diff --git a/.github/actions/build_and_test_ya/action.yml b/.github/actions/build_and_test_ya/action.yml index 9dd86a4820ea..e142a282b8bd 100644 --- a/.github/actions/build_and_test_ya/action.yml +++ b/.github/actions/build_and_test_ya/action.yml @@ -51,12 +51,37 @@ inputs: vars: type: string default: "" + custom_branch_name: + description: "Custom branch name required when workflow branch != checkout branch" + type: string + required: false defaults: run: shell: bash runs: using: "composite" steps: + - name: Prepare folder prefix + id: prepare_prefix + shell: bash + run: | + # Check if custom_branch_name is set and not empty + if [ -n "${{ inputs.custom_branch_name }}" ]; then + # Extract and sanitize custom_branch_name + CUSTOM_BRANCH_NAME="${{ inputs.custom_branch_name }}" + # Replace all unsupported characters with hyphens + SANITIZED_NAME="${CUSTOM_BRANCH_NAME//[^a-zA-Z0-9-]/-}" + # Optionally limit the length to, say, 50 characters + SANITIZED_NAME="${SANITIZED_NAME:0:50}" + # Assign the sanitized name to the folder_prefix + FOLDER_PREFIX="ya-${SANITIZED_NAME}-" + else + # If the branch name is not provided, use a default prefix + FOLDER_PREFIX='ya-' + fi + # Output the folder_prefix for use in subsequent steps + echo "folder_prefix=${FOLDER_PREFIX}" >> $GITHUB_ENV + - name: Prepare s3cmd uses: ./.github/actions/s3cmd with: @@ -64,7 +89,7 @@ runs: s3_endpoint: ${{ fromJSON( inputs.vars ).AWS_ENDPOINT }} s3_key_id: ${{ fromJSON( inputs.secs ).AWS_KEY_ID }} s3_key_secret: ${{ fromJSON( inputs.secs ).AWS_KEY_VALUE }} - folder_prefix: ya- + folder_prefix: ${{ env.folder_prefix }} build_preset: ${{ inputs.build_preset }} - name: Run build and tests @@ -88,3 +113,4 @@ runs: bazel_remote_password: ${{ fromJSON( inputs.secs ).REMOTE_CACHE_PASSWORD || '' }} put_build_results_to_cache: ${{ inputs.put_build_results_to_cache }} test_retry_count: ${{ inputs.test_retry_count }} + custom_branch_name: ${{ inputs.custom_branch_name }} diff --git a/.github/actions/test_ya/action.yml b/.github/actions/test_ya/action.yml index 97b574459858..c41fdbbc01be 100644 --- a/.github/actions/test_ya/action.yml +++ b/.github/actions/test_ya/action.yml @@ -60,6 +60,11 @@ inputs: type: string default: "" description: "how many times to retry failed tests" + custom_branch_name: + description: "Custom branch name required when workflow branch != checkout branch" + type: string + required: false + outputs: success: value: ${{ steps.build.outputs.status }} @@ -271,8 +276,18 @@ runs: --cache-size 2TB --force-build-depends ) + echo "inputs.custom_branch_name = ${{ inputs.custom_branch_name }}" + echo "GITHUB_REF_NAME = $GITHUB_REF_NAME" + + if [ -z "${{ inputs.custom_branch_name }}" ]; then + BRANCH_NAME="${GITHUB_REF_NAME}" + else + BRANCH_NAME="${{ inputs.custom_branch_name }}" + fi + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + echo "BRANCH_NAME is set to $BRANCH_NAME" - TESTMO_BRANCH_TAG="$GITHUB_REF_NAME" + TESTMO_BRANCH_TAG="$BRANCH_NAME" TESTMO_ARCH="${{ runner.arch == 'X64' && 'x86-64' || runner.arch == 'ARM64' && 'arm64' || 'unknown' }}" TESTMO_PR_NUMBER=${{ github.event.number }} @@ -453,6 +468,7 @@ runs: --public_dir "$PUBLIC_DIR" \ --public_dir_url "$PUBLIC_DIR_URL" \ --build_preset "$BUILD_PRESET" \ + --branch "$BRANCH_NAME" \ --status_report_file statusrep.txt \ --is_retry $IS_RETRY \ --is_last_retry $IS_LAST_RETRY \ @@ -470,7 +486,7 @@ runs: # upload tests results to YDB ydb_upload_run_name="${TESTMO_RUN_NAME// /"_"}" - result=`.github/scripts/analytics/upload_tests_results.py --test-results-file ${CURRENT_JUNIT_XML_PATH} --run-timestamp $(date +%s) --commit $(git rev-parse HEAD) --build-type ${BUILD_PRESET} --pull $ydb_upload_run_name --job-name "${{ github.workflow }}" --job-id "${{ github.run_id }}" --branch ${GITHUB_REF_NAME}` + result=`.github/scripts/analytics/upload_tests_results.py --test-results-file ${CURRENT_JUNIT_XML_PATH} --run-timestamp $(date +%s) --commit $(git rev-parse HEAD) --build-type ${BUILD_PRESET} --pull $ydb_upload_run_name --job-name "${{ github.workflow }}" --job-id "${{ github.run_id }}" --branch "${BRANCH_NAME}"` if [ ${{ inputs.testman_token }} ]; then # finish testme session @@ -573,7 +589,7 @@ runs: echo file ${file_to_check} NOT changed else echo file ${file_to_check} changed - .github/scripts/tests/get_muted_tests.py --output_folder "$PUBLIC_DIR/mute_info/" get_mute_diff --base_sha $ORIGINAL_HEAD~1 --head_sha $ORIGINAL_HEAD --job-id "${{ github.run_id }}" --branch "${GITHUB_REF_NAME}" + .github/scripts/tests/get_muted_tests.py --output_folder "$PUBLIC_DIR/mute_info/" get_mute_diff --base_sha $ORIGINAL_HEAD~1 --head_sha $ORIGINAL_HEAD --job-id "${{ github.run_id }}" --branch "${BRANCH_NAME}" FILE_PATH=$PUBLIC_DIR/mute_info/2_new_muted_tests.txt SEPARATOR="" if [ -f "$FILE_PATH" ]; then @@ -633,7 +649,7 @@ runs: run: | set -x export build_preset="${{ inputs.build_preset }}" - export branch_to_compare="$GITHUB_REF_NAME" + export branch_to_compare="$BRANCH_NAME" export yellow_treshold=102400 export red_treshold=2097152 export commit_git_sha="$(git rev-parse HEAD)" diff --git a/.github/actions/update_changelog/update_changelog.py b/.github/actions/update_changelog/update_changelog.py index bdfeb69ad5c0..7ae60214c4e9 100644 --- a/.github/actions/update_changelog/update_changelog.py +++ b/.github/actions/update_changelog/update_changelog.py @@ -57,7 +57,7 @@ def to_file(changelog_path, changelog): for category, items in changelog[UNRELEASED].items(): if(len(changelog[UNRELEASED][category]) == 0): continue - file.write(f"{CATEGORY_PREFIX}{category}\n") + file.write(f"{CATEGORY_PREFIX}{category}\n\n") for id, body in items.items(): file.write(f"{ITEM_PREFIX}{id}:{body.strip()}\n") file.write("\n") @@ -69,7 +69,7 @@ def to_file(changelog_path, changelog): for category, items in categories.items(): if(len(changelog[version][category]) == 0): continue - file.write(f"{CATEGORY_PREFIX}{category}\n") + file.write(f"{CATEGORY_PREFIX}{category}\n\n") for id, body in items.items(): file.write(f"{ITEM_PREFIX}{id}:{body.strip()}\n") file.write("\n") @@ -83,7 +83,7 @@ def extract_changelog_category(description): return None def extract_pr_number(changelog_entry): - match = re.search(r"#(\d+)", changelog_entry) + match = re.search(r"\* (\d+)", changelog_entry) if match: return int(match.group(1)) return None @@ -136,14 +136,17 @@ def update_changelog(changelog_path, pr_data): to_file(changelog_path, changelog) def run_command(command): + print(f"Executing command: {command}") try: result = subprocess.run(command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output = result.stdout.decode().strip() + print(f"Command output: {output}") + return output except subprocess.CalledProcessError as e: print(f"::error::Command failed with exit code {e.returncode}: {e.stderr.decode()}") print(f"::error::Command: {e.cmd}") print(f"::error::Output: {e.stdout.decode()}") sys.exit(1) - return result.stdout.decode().strip() def branch_exists(branch_name): result = subprocess.run(["git", "ls-remote", "--heads", "origin", branch_name], capture_output=True, text=True) @@ -169,7 +172,7 @@ def fetch_user_details(username): response.raise_for_status() return response.json() -if __name__ == "__main__": +def main(): if len(sys.argv) != 5: print("Usage: update_changelog.py ") sys.exit(1) @@ -178,6 +181,13 @@ def fetch_user_details(username): changelog_path = sys.argv[2] base_branch = sys.argv[3] suffix = sys.argv[4] + + # Fetch latest changes + run_command("git fetch origin") + # Check out existing branch + run_command(f"git checkout {base_branch}") + # Make sure it's up to date + run_command(f"git pull origin {base_branch}") try: with open(pr_data_file, 'r') as file: @@ -187,6 +197,10 @@ def fetch_user_details(username): sys.exit(1) pr_data = [] + if not pr_ids: + print("::notice::No PR IDs found in the provided file.") + return + for pr in pr_ids: try: pr_details = fetch_pr_details(pr["id"]) @@ -203,7 +217,7 @@ def fetch_user_details(username): except Exception as e: print(f"::error::Failed to fetch PR details for PR #{pr['id']}: {e}") sys.exit(1) - + update_changelog(changelog_path, pr_data) base_branch_name = f"changelog/{base_branch}-{suffix}" @@ -212,13 +226,18 @@ def fetch_user_details(username): while branch_exists(branch_name): branch_name = f"{base_branch_name}-{index}" index += 1 + run_command(f"git checkout -b {branch_name}") run_command(f"git add {changelog_path}") run_command(f"git commit -m \"Update CHANGELOG.md for {suffix}\"") run_command(f"git push origin {branch_name}") - pr_title = f"Update CHANGELOG.md for {suffix}" + pr_title = f"Update CHANGELOG.md for {base_branch}:{suffix}" pr_body = f"This PR updates the CHANGELOG.md file for {suffix}." pr_create_command = f"gh pr create --title \"{pr_title}\" --body \"{pr_body}\" --base {base_branch} --head {branch_name}" pr_url = run_command(pr_create_command) # run_command(f"gh pr edit {pr_url} --add-assignee galnat") # TODO: Make assignee customizable + + +if __name__ == "__main__": + main() diff --git a/.github/config/muted_ya.txt b/.github/config/muted_ya.txt index 4a86e11680b7..f43771c43956 100644 --- a/.github/config/muted_ya.txt +++ b/.github/config/muted_ya.txt @@ -16,7 +16,12 @@ ydb/core/keyvalue/ut_trace TKeyValueTracingTest.ReadHuge ydb/core/keyvalue/ut_trace TKeyValueTracingTest.ReadSmall ydb/core/keyvalue/ut_trace TKeyValueTracingTest.WriteHuge ydb/core/keyvalue/ut_trace TKeyValueTracingTest.WriteSmall +ydb/core/kqp/ut/batch_operations KqpBatchUpdate.Large_3 +ydb/core/kqp/ut/batch_operations [*/*] chunk chunk ydb/core/kqp/ut/cost KqpCost.OlapWriteRow +ydb/core/kqp/ut/federated_query/s3 KqpFederatedQuery.ExecuteScriptWithLargeFile +ydb/core/kqp/ut/federated_query/s3 KqpFederatedQuery.ExecuteScriptWithThinFile +ydb/core/kqp/ut/federated_query/s3 sole chunk chunk ydb/core/kqp/ut/olap KqpDecimalColumnShard.TestAggregation ydb/core/kqp/ut/olap KqpDecimalColumnShard.TestFilterCompare ydb/core/kqp/ut/olap KqpOlapIndexes.IndexesInBS @@ -30,29 +35,21 @@ ydb/core/kqp/ut/olap KqpOlapWrite.TierDraftsGCWithRestart ydb/core/kqp/ut/olap [*/*] chunk chunk ydb/core/kqp/ut/query KqpAnalyze.AnalyzeTable+ColumnStore ydb/core/kqp/ut/query KqpAnalyze.AnalyzeTable-ColumnStore -ydb/core/kqp/ut/query KqpLimits.TooBigColumn+useSink ydb/core/kqp/ut/query KqpStats.SysViewClientLost ydb/core/kqp/ut/scheme KqpOlapScheme.TenThousandColumns ydb/core/kqp/ut/scheme KqpScheme.AlterAsyncReplication ydb/core/kqp/ut/scheme [*/*] chunk chunk ydb/core/kqp/ut/service [*/*] chunk chunk ydb/core/kqp/ut/tx KqpSinkTx.OlapInvalidateOnError -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TConflictReadWriteOlap -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TConflictReadWriteOltp -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TConflictReadWriteOltpNoSink -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TConflictWriteOlap -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TConflictWriteOltp -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TConflictWriteOltpNoSink -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TReadOnlyOltp -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TReadOnlyOltpNoSink -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TSimpleOltp -ydb/core/kqp/ut/tx KqpSnapshotIsolation.TSimpleOltpNoSink ydb/core/kqp/ut/yql KqpScripting.StreamExecuteYqlScriptScanOperationTmeoutBruteForce ydb/core/mind/hive/ut TStorageBalanceTest.TestScenario2 +ydb/core/persqueue/ut/ut_with_sdk TopicAutoscaling.PartitionSplit_DistributedTxCommit_CheckOffsetCommitForDifferentCases_SplitedTopic +ydb/core/quoter/ut QuoterWithKesusTest.KesusRecreation ydb/core/quoter/ut QuoterWithKesusTest.PrefetchCoefficient ydb/core/statistics/aggregator/ut AnalyzeColumnshard.AnalyzeRebootColumnShard -ydb/core/tablet_flat/ut DataCleanup.CleanupDataWithFollowers ydb/core/tx/datashard/ut_incremental_backup IncrementalBackup.ComplexRestoreBackupCollection+WithIncremental +ydb/core/tx/schemeshard/ut_export_reboots_s3 TExportToS3WithRebootsTests.CancelShouldSucceedOnManyTables +ydb/core/tx/schemeshard/ut_export_reboots_s3 TExportToS3WithRebootsTests.ShouldSucceedOnManyTables ydb/core/tx/schemeshard/ut_login_large TSchemeShardLoginLargeTest.RemoveLogin_Many ydb/core/tx/schemeshard/ut_move_reboots TSchemeShardMoveRebootsTest.WithData ydb/core/tx/schemeshard/ut_move_reboots TSchemeShardMoveRebootsTest.WithDataAndPersistentPartitionStats @@ -62,7 +59,6 @@ ydb/library/actors/interconnect/ut_huge_cluster HugeCluster.AllToAll ydb/library/actors/interconnect/ut_huge_cluster sole chunk chunk ydb/library/yaml_config/ut_transform test_transform.py.TestYamlConfigTransformations.test_basic[args1-dump_ds_init] ydb/library/yql/dq/opt/ut sole chunk chunk -ydb/public/sdk/cpp/src/client/topic/ut [*/*] chunk chunk ydb/services/ydb/sdk_sessions_pool_ut YdbSdkSessionsPool.StressTestSync1 ydb/services/ydb/sdk_sessions_pool_ut YdbSdkSessionsPool.StressTestSync10 ydb/services/ydb/sdk_sessions_ut YdbSdkSessions.TestSdkFreeSessionAfterBadSessionQueryService @@ -84,8 +80,6 @@ ydb/tests/fq/yds test_select_limit_db_id.py.TestSelectLimitWithDbId.test_select_ ydb/tests/fq/yds test_yds_bindings.py.TestBindings.test_yds_insert[v1] ydb/tests/functional/compatibility test_compatibility.py.TestCompatibility.test_simple ydb/tests/functional/compatibility test_followers.py.TestFollowersCompatibility.test_followers_compatability -ydb/tests/functional/compatibility test_stress.py.TestStress.test_kv[last_stable-row] -ydb/tests/functional/compatibility test_stress.py.TestStress.test_kv[mixed-row] ydb/tests/functional/compatibility test_stress.py.TestStress.test_log[last_stable-row] ydb/tests/functional/compatibility test_stress.py.TestStress.test_log[mixed-row] ydb/tests/functional/compatibility test_stress.py.TestStress.test_tpch1[current-row] @@ -94,18 +88,11 @@ ydb/tests/functional/compatibility test_stress.py.TestStress.test_tpch1[mixed-ro ydb/tests/functional/hive test_drain.py.TestHive.test_drain_on_stop ydb/tests/functional/rename [test_rename.py */*] chunk chunk ydb/tests/functional/serializable sole chunk chunk -ydb/tests/functional/serializable test.py.test_local ydb/tests/functional/serverless test_serverless.py.test_database_with_disk_quotas[enable_alter_database_create_hive_first--false] ydb/tests/functional/serverless test_serverless.py.test_database_with_disk_quotas[enable_alter_database_create_hive_first--true] ydb/tests/functional/suite_tests [test_sql_logic.py */*] chunk chunk ydb/tests/functional/suite_tests test_postgres.py.TestPGSQL.test_sql_suite[plan-jointest/join2.test] -ydb/tests/functional/suite_tests test_postgres.py.TestPGSQL.test_sql_suite[plan-select.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select1-1.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select2-1.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select2-3.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select2-4.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select3-9.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[results-select3-13.test] +ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[results-select2-1.test] ydb/tests/functional/tenants test_dynamic_tenants.py.test_create_and_drop_the_same_tenant2[enable_alter_database_create_hive_first--false] ydb/tests/functional/tenants test_dynamic_tenants.py.test_create_and_drop_the_same_tenant2[enable_alter_database_create_hive_first--true] ydb/tests/functional/tenants test_tenants.py.TestTenants.test_create_drop_create_table3[enable_alter_database_create_hive_first--false] @@ -119,16 +106,17 @@ ydb/tests/functional/tpc/large sole chunk chunk ydb/tests/functional/tpc/large test_tpcds.py.TestTpcdsS1.test_tpcds[10] ydb/tests/functional/tpc/large test_tpcds.py.TestTpcdsS1.test_tpcds[11] ydb/tests/functional/tpc/large test_tpcds.py.TestTpcdsS1.test_tpcds[12] -ydb/tests/functional/tpc/large test_tpcds.py.TestTpcdsS1.test_tpcds[36] -ydb/tests/functional/tpc/large test_tpcds.py.TestTpcdsS1.test_tpcds[67] -ydb/tests/functional/tpc/large test_tpcds.py.TestTpcdsS1.test_tpcds[86] ydb/tests/functional/tpc/large test_tpcds.py.TestTpcdsS1.test_tpcds[9] -ydb/tests/functional/tpc/large test_tpch_spilling.py.TestTpchSpillingS10.test_tpch[7] ydb/tests/olap sole chunk chunk +ydb/tests/olap test_log_scenario.py.TestLogScenario.test +ydb/tests/olap test_log_scenario.py.TestLogScenario.test[1051200] +ydb/tests/olap test_log_scenario.py.TestLogScenario.test[180] ydb/tests/olap test_quota_exhaustion.py.TestYdbWorkload.test_delete -ydb/tests/olap/data_quotas test_quota_exhaustion.py.TestYdbWorkload.test_duplicates ydb/tests/olap/column_family/compression alter_compression.py.TestAlterCompression.test_all_supported_compression ydb/tests/olap/column_family/compression sole chunk chunk +ydb/tests/olap/data_quotas [*/*] chunk chunk +ydb/tests/olap/data_quotas test_quota_exhaustion.py.TestYdbWorkload.test +ydb/tests/olap/data_quotas test_quota_exhaustion.py.TestYdbWorkload.test_duplicates ydb/tests/olap/oom overlapping_portions.py.TestOverlappingPortions.test ydb/tests/olap/scenario sole chunk chunk ydb/tests/olap/scenario test_alter_compression.py.TestAlterCompression.test[alter_compression] @@ -139,7 +127,6 @@ ydb/tests/olap/ttl_tiering [data_migration_when_alter_ttl.py] chunk chunk ydb/tests/olap/ttl_tiering [ttl_delete_s3.py] chunk chunk ydb/tests/olap/ttl_tiering data_migration_when_alter_ttl.py.TestDataMigrationWhenAlterTtl.test ydb/tests/olap/ttl_tiering sole chunk chunk -ydb/tests/olap/ttl_tiering ttl_delete_s3.py.TestDeleteS3Ttl.test_data_unchanged_after_ttl_change ydb/tests/olap/ttl_tiering ttl_delete_s3.py.TestDeleteS3Ttl.test_delete_s3_tiering ydb/tests/olap/ttl_tiering ttl_delete_s3.py.TestDeleteS3Ttl.test_ttl_delete ydb/tests/postgres_integrations/go-libpq [docker_wrapper_test.py] chunk chunk @@ -225,4 +212,5 @@ ydb/tests/sql/large test_workload_manager.py.TestWorkloadManager.test_resource_p ydb/tests/sql/large test_workload_manager.py.TestWorkloadManager.test_resource_pool_queue_size_limit ydb/tests/stress/log/tests test_workload.py.TestYdbLogWorkload.test[column] ydb/tests/stress/log/tests test_workload.py.TestYdbLogWorkload.test[row] +ydb/tests/stress/mixedpy test_mixed.py.TestYdbMixedWorkload.test[column] ydb/tools/stress_tool/ut TDeviceTestTool.PDiskTestLogWrite diff --git a/.github/scripts/analytics/data_mart_delete_table.py b/.github/scripts/analytics/data_mart_delete_table.py new file mode 100644 index 000000000000..76121b3fc523 --- /dev/null +++ b/.github/scripts/analytics/data_mart_delete_table.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +import argparse +import ydb +import configparser +import os + +# Load configuration +dir = os.path.dirname(__file__) +config = configparser.ConfigParser() +config_file_path = f"{dir}/../../config/ydb_qa_db.ini" +config.read(config_file_path) + +DATABASE_ENDPOINT = config["QA_DB"]["DATABASE_ENDPOINT"] +DATABASE_PATH = config["QA_DB"]["DATABASE_PATH"] + +def parse_args(): + parser = argparse.ArgumentParser(description="Delete a YDB table") + parser.add_argument("--table_path", required=True, help="Table path and name to delete") + + return parser.parse_args() + +def check_table_exists(session, table_path): + """Check if table exists""" + try: + session.describe_table(table_path) + return True + except ydb.SchemeError: + return False + +def delete_table(session, table_path): + """Delete the specified table.""" + try: + session.drop_table(table_path) + print(f"Table '{table_path}' successfully deleted.") + return True + except ydb.Error as e: + print(f"Error deleting table: {e}") + return False + +def main(): + args = parse_args() + + if "CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS" not in os.environ: + print("Error: Env variable CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS is missing, skipping") + return 1 + else: + os.environ["YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS"] = os.environ[ + "CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS" + ] + + table_path = args.table_path + full_table_path = f'{DATABASE_PATH}/{table_path}' + + print(f"Connecting to YDB to delete table {full_table_path}") + + with ydb.Driver( + endpoint=DATABASE_ENDPOINT, + database=DATABASE_PATH, + credentials=ydb.credentials_from_env_variables() + ) as driver: + # Wait until driver is ready + driver.wait(timeout=10, fail_fast=True) + + with ydb.SessionPool(driver) as pool: + # Проверяем существование таблицы + def check_and_delete(session): + exists = check_table_exists(session, full_table_path) + if exists: + return delete_table(session, full_table_path) + else: + print(f"Table '{full_table_path}' does not exist.") + return False + + result = pool.retry_operation_sync(check_and_delete) + + if result: + print(f"Table {full_table_path} has been deleted successfully.") + return 0 + else: + print(f"No table was deleted.") + return 1 + +if __name__ == "__main__": + exit_code = main() + exit(exit_code) diff --git a/.github/scripts/analytics/data_mart_executor.py b/.github/scripts/analytics/data_mart_executor.py index 00116e8cff93..2f88ac849cbc 100755 --- a/.github/scripts/analytics/data_mart_executor.py +++ b/.github/scripts/analytics/data_mart_executor.py @@ -145,7 +145,7 @@ def main(): ] table_path = args.table_path - batch_size = 50000 + batch_size = 1000 # Read SQL query from file sql_query_path = os.path.join(repo_path, args.query_path) diff --git a/.github/scripts/analytics/data_mart_queries/perfomance_olap_mart.sql b/.github/scripts/analytics/data_mart_queries/perfomance_olap_mart.sql index 960cace5add0..12630831db3b 100644 --- a/.github/scripts/analytics/data_mart_queries/perfomance_olap_mart.sql +++ b/.github/scripts/analytics/data_mart_queries/perfomance_olap_mart.sql @@ -1,318 +1,178 @@ -select +$start_timestamp = (CurrentUtcDate() - 30 * Interval("P1D")); - Db , +$all_suites = ( + SELECT + Suite, Test + FROM ( + SELECT + Suite, + ListSort(AGG_LIST_DISTINCT(Test)) AS Tests + FROM `perfomance/olap/tests_results` + WHERE Timestamp >= $start_timestamp + GROUP BY Suite + ) + FLATTEN LIST BY Tests AS Test +); + +$launch_times = ( + SELECT + launch_times_raw.*, + all_suites.* + FROM ( + SELECT + Db, + Branch, + Version, + LunchId, + CAST(Min(RunId / 1000UL) AS Timestamp) AS Run_start_timestamp, + ROW_NUMBER() OVER (PARTITION BY Db, Version ORDER BY Min(RunId) ASC) AS Run_number_in_version, + ROW_NUMBER() OVER (PARTITION BY Db, Branch ORDER BY Min(RunId) DESC) AS Run_number_in_branch_desc + FROM `perfomance/olap/tests_results` + WHERE Timestamp >= $start_timestamp + GROUP BY + Db, + Unicode::SplitToList(JSON_VALUE(Info, "$.cluster.version"), '.')[0] As Branch, + JSON_VALUE(Info, "$.cluster.version") AS Version, + JSON_VALUE(Info, "$.ci_launch_id") AS LunchId + ) AS launch_times_raw + CROSS JOIN $all_suites AS all_suites +); + +$all_tests_raw = + SELECT + tests_results.*, + JSON_VALUE(Info, "$.report_url") AS Report, + JSON_VALUE(tests_results.Info, "$.cluster.version") AS Version_n, + JSON_VALUE(tests_results.Info, "$.ci_launch_id") AS LunchId_n, + CAST(JSON_VALUE(Stats, '$.DiffsCount') AS INT) AS diff_response, + IF(Success > 0, MeanDuration / 1000) AS YdbSumMeans, + IF(Success > 0, MaxDuration / 1000) AS YdbSumMax, + IF(Success > 0, MinDuration / 1000) AS YdbSumMin, + CAST(RunId / 1000UL AS Timestamp) AS RunTs, + IF (JSON_VALUE(Stats, "$.errors.other") = "true", + "red", + IF (JSON_VALUE(Stats, "$.errors.timeout") = "true", + "blue", + IF (JSON_VALUE(Stats, "$.errors.warning") = "true", + "yellow", + "green" + ) + ) + ) AS Color + FROM `perfomance/olap/tests_results` AS tests_results + WHERE Timestamp >= $start_timestamp; + +SELECT + Db, Suite, Test, - Next_Run_start_timestamp , Run_start_timestamp, Run_number_in_version, Run_number_in_branch_desc, - MaxDuration , - MeanDuration , - MedianDuration , - MinDuration , - YdbSumMax , - YdbSumMeans , - YdbSumMin , + MaxDuration, + MeanDuration, + MedianDuration, + MinDuration, + YdbSumMax, + YdbSumMeans, + YdbSumMin, Version, Branch, - diff_response , + diff_response, Timestamp, - COALESCE(Success ,0) as Success , - max(Kind) OVER (PARTITION by Db , Run_start_timestamp, Suite) as Kind, - max(Report) OVER (PARTITION by Db , Run_start_timestamp, Suite) as Report, - max(RunId) OVER (PARTITION by Db , Run_start_timestamp, Suite) as RunId, - max(RunTs) OVER (PARTITION by Db , Run_start_timestamp, Suite) as RunTs, + COALESCE(Success,0) AS Success, + max(Kind) OVER (PARTITION by Db, Run_start_timestamp, Suite) AS Kind, + max(Report) OVER (PARTITION by Db, Run_start_timestamp, Suite) AS Report, + max(RunId) OVER (PARTITION by Db, Run_start_timestamp, Suite) AS RunId, + max(RunTs) OVER (PARTITION by Db, Run_start_timestamp, Suite) AS RunTs, YdbSumMeans IS NULL AS errors, - max(Report) OVER (PARTITION by Db , Run_start_timestamp, Suite) IS NULL AS Suite_not_runned, + max(Report) OVER (PARTITION by Db, Run_start_timestamp, Suite) IS NULL AS Suite_not_runned, Color - from ( - -SELECT - null_template.Db AS Db, --only from null_template - COALESCE(real_data.Kind, null_template.Kind) AS Kind, - COALESCE(real_data.MaxDuration, null_template.MaxDuration) AS MaxDuration, - COALESCE(real_data.MeanDuration, null_template.MeanDuration) AS MeanDuration, - COALESCE(real_data.MedianDuration, null_template.MedianDuration) AS MedianDuration, - COALESCE(real_data.MinDuration, null_template.MinDuration) AS MinDuration, - null_template.Next_Run_start_timestamp AS Next_Run_start_timestamp, --only from null_template - COALESCE(real_data.Report, null_template.Report) AS Report, - COALESCE(real_data.Branch, null_template.Branch) AS Branch, - COALESCE(real_data.RunId, null_template.RunId) AS RunId, - COALESCE(real_data.RunTs, null_template.RunTs) AS RunTs, - null_template.Run_number_in_version AS Run_number_in_version, --only from null_template - null_template.Run_start_timestamp AS Run_start_timestamp, --only from null_template - COALESCE(real_data.Run_number_in_branch_desc, null_template.Run_number_in_branch_desc) AS Run_number_in_branch_desc, - COALESCE(real_data.Success, null_template.Success) AS Success, - null_template.Suite AS Suite, --only from null_template - null_template.Test AS Test, --only from null_template - COALESCE(real_data.Timestamp, null_template.Timestamp) AS Timestamp, - COALESCE(real_data.Version, null_template.Version) AS Version, - COALESCE(real_data.YdbSumMax, null_template.YdbSumMax) AS YdbSumMax, - COALESCE(real_data.YdbSumMeans, null_template.YdbSumMeans) AS YdbSumMeans, - COALESCE(real_data.YdbSumMin, null_template.YdbSumMin) AS YdbSumMin, - COALESCE(real_data.diff_response, null_template.diff_response) AS diff_response, - COALESCE(real_data.Color, null_template.Color) AS Color, - FROM ( - SELECT - all_tests.*, - launch_times.* - FROM ( - SELECT - launch_times.*, - all_suites.* - FROM ( - SELECT DISTINCT - Db, - Version, - Branch, - Run_start_timestamp, - Run_number_in_version, - Next_Run_start_timestamp, - ROW_NUMBER() OVER (PARTITION BY Db, Branch ORDER BY Run_start_timestamp DESC) AS Run_number_in_branch_desc - FROM ( - SELECT - Db, - Version, - Run_start_timestamp, - Next_Run_start_timestamp, - ROW_NUMBER() OVER (PARTITION BY t1.Db, t1.Version ORDER BY t1.Run_start_timestamp ASC) AS Run_number_in_version, - Unicode::SplitToList(Version, '.')[0] AS Branch - FROM ( - SELECT - runs.Db AS Db, - runs.Version AS Version, - run_start.Run_start_timestamp AS Run_start_timestamp, - run_start.Next_Run_start_timestamp AS Next_Run_start_timestamp - FROM ( - SELECT DISTINCT - Db, - Timestamp, - JSON_VALUE(Info, "$.cluster.version") AS Version, - CAST(RunId / 1000 AS Timestamp) AS RunTs - FROM `perfomance/olap/tests_results` - WHere Timestamp >= CurrentUtcDate() - 30*Interval("P1D") - ) AS runs - LEFT JOIN ( - SELECT - Db, - JSON_VALUE(Info, "$.cluster.version") AS Version, - Timestamp AS Run_start_timestamp, - LEAD(Timestamp) OVER (PARTITION BY Db, JSON_VALUE(Info, "$.cluster.version") ORDER BY Timestamp) AS Next_Run_start_timestamp - FROM `perfomance/olap/tests_results` - WHERE Suite = 'Clickbench' AND Test = '_Verification' - And Timestamp >= CurrentUtcDate() - 30*Interval("P1D") - ORDER BY Db, Run_start_timestamp DESC, Version - ) AS run_start - ON runs.Db = run_start.Db AND runs.Version = run_start.Version - WHERE ( - (runs.Timestamp >= run_start.Run_start_timestamp AND runs.Timestamp < run_start.Next_Run_start_timestamp) OR - (runs.Timestamp >= run_start.Run_start_timestamp AND run_start.Next_Run_start_timestamp IS NULL) - ) - ) AS t1 - GROUP BY Db, Version, Run_start_timestamp, Next_Run_start_timestamp - ) AS run_start - GROUP BY Db, Branch, Version, Run_start_timestamp, Run_number_in_version, Next_Run_start_timestamp - ) AS launch_times - CROSS JOIN ( - SELECT - Suite, Test - FROM ( - SELECT - Suite, - ListSort(AGG_LIST_DISTINCT(Test)) AS Tests - FROM `perfomance/olap/tests_results` - WHere Timestamp >= CurrentUtcDate() - 30*Interval("P1D") - GROUP BY Suite - ORDER BY Suite - ) - FLATTEN LIST BY Tests AS Test - ORDER BY Suite, Test - ) AS all_suites - ) AS launch_times - LEFT JOIN ( - SELECT - all_tests.*, - JSON_VALUE(Info, "$.report_url") AS Report, - JSON_VALUE(all_tests.Info, "$.cluster.version") AS Version_n, - CAST(JSON_VALUE(Stats, '$.DiffsCount') AS INT) AS diff_response, - IF(Success > 0, MeanDuration / 1000) AS YdbSumMeans, - IF(Success > 0, MaxDuration / 1000) AS YdbSumMax, - IF(Success > 0, MinDuration / 1000) AS YdbSumMin, - CAST(RunId / 1000 AS Timestamp) AS RunTs, - IF (JSON_VALUE(Stats, "$.errors.other") = "true", - "red", - IF (JSON_VALUE(Stats, "$.errors.timeout") = "true", - "blue", - IF (JSON_VALUE(Stats, "$.errors.warning") = "true", - "yellow", - "green" - ) - ) - ) as Color - FROM `perfomance/olap/tests_results` AS all_tests - Where JSON_VALUE(all_tests.Info, "$.cluster.version") is Null --and Test != '_Verification' - and Timestamp >= CurrentUtcDate() - 30*Interval("P1D") - ) AS all_tests - ON all_tests.Db = launch_times.Db - AND all_tests.Suite = launch_times.Suite - AND all_tests.Test = launch_times.Test - -- WHERE ( all_tests.Version_n is Null) - - - ORDER BY Run_start_timestamp DESC, Db, launch_times.Version, RunId -) AS null_template -Full OUTER join -(SELECT - real_data.Db AS Db, - real_data.Kind AS Kind, - real_data.MaxDuration AS MaxDuration, - real_data.MeanDuration AS MeanDuration, - real_data.MedianDuration AS MedianDuration, - real_data.MinDuration AS MinDuration, - real_data.Next_Run_start_timestamp AS Next_Run_start_timestamp, - real_data.Report AS Report, - real_data.Branch AS Branch, - real_data.RunId AS RunId, - real_data.RunTs AS RunTs, - real_data.Run_number_in_version AS Run_number_in_version, - real_data.Run_start_timestamp AS Run_start_timestamp, - real_data.Run_number_in_branch_desc AS Run_number_in_branch_desc, - --real_data.Stats AS Stats, - real_data.Success AS Success, - real_data.Suite AS Suite, - real_data.Test AS Test, - real_data.Timestamp AS Timestamp, - real_data.Version AS Version, - real_data.YdbSumMax AS YdbSumMax, - real_data.YdbSumMeans AS YdbSumMeans, - real_data.YdbSumMin AS YdbSumMin, - real_data.diff_response AS diff_response, - real_data.Color AS Color, - + SELECT + null_template.Db AS Db, --only from null_template + COALESCE(real_data.Kind, null_template.Kind) AS Kind, + COALESCE(real_data.MaxDuration, null_template.MaxDuration) AS MaxDuration, + COALESCE(real_data.MeanDuration, null_template.MeanDuration) AS MeanDuration, + COALESCE(real_data.MedianDuration, null_template.MedianDuration) AS MedianDuration, + COALESCE(real_data.MinDuration, null_template.MinDuration) AS MinDuration, + COALESCE(real_data.Report, null_template.Report) AS Report, + COALESCE(real_data.Branch, null_template.Branch) AS Branch, + COALESCE(real_data.RunId, null_template.RunId) AS RunId, + COALESCE(real_data.RunTs, null_template.RunTs) AS RunTs, + null_template.Run_number_in_version AS Run_number_in_version, --only from null_template + null_template.Run_start_timestamp AS Run_start_timestamp, --only from null_template + COALESCE(real_data.Run_number_in_branch_desc, null_template.Run_number_in_branch_desc) AS Run_number_in_branch_desc, + COALESCE(real_data.Success, null_template.Success) AS Success, + null_template.Suite AS Suite, --only from null_template + null_template.Test AS Test, --only from null_template + COALESCE(real_data.Timestamp, null_template.Timestamp) AS Timestamp, + COALESCE(real_data.Version, null_template.Version) AS Version, + COALESCE(real_data.YdbSumMax, null_template.YdbSumMax) AS YdbSumMax, + COALESCE(real_data.YdbSumMeans, null_template.YdbSumMeans) AS YdbSumMeans, + COALESCE(real_data.YdbSumMin, null_template.YdbSumMin) AS YdbSumMin, + COALESCE(real_data.diff_response, null_template.diff_response) AS diff_response, + COALESCE(real_data.Color, null_template.Color) AS Color, FROM ( SELECT all_tests.*, - launch_times.*, - - FROM ( - SELECT - launch_times.*, - all_suites.* - FROM ( - SELECT DISTINCT - Db, - Version, - Branch, - Run_start_timestamp, - Run_number_in_version, - Next_Run_start_timestamp, - ROW_NUMBER() OVER (PARTITION BY Db, Branch ORDER BY Run_start_timestamp DESC) AS Run_number_in_branch_desc - FROM ( - SELECT - Db, - Version, - Run_start_timestamp, - Next_Run_start_timestamp, - ROW_NUMBER() OVER (PARTITION BY t1.Db, t1.Version ORDER BY t1.Run_start_timestamp ASC) AS Run_number_in_version, - Unicode::SplitToList(Version, '.')[0] AS Branch - FROM ( - SELECT - runs.Db AS Db, - runs.Version AS Version, - run_start.Run_start_timestamp AS Run_start_timestamp, - run_start.Next_Run_start_timestamp AS Next_Run_start_timestamp - FROM ( - SELECT DISTINCT - Db, - Timestamp, - JSON_VALUE(Info, "$.cluster.version") AS Version, - CAST(RunId / 1000 AS Timestamp) AS RunTs - FROM `perfomance/olap/tests_results` - WHere Timestamp >= CurrentUtcDate() - 30*Interval("P1D") - ) AS runs - LEFT JOIN ( - SELECT - Db, - JSON_VALUE(Info, "$.cluster.version") AS Version, - Timestamp AS Run_start_timestamp, - LEAD(Timestamp) OVER (PARTITION BY Db, JSON_VALUE(Info, "$.cluster.version") ORDER BY Timestamp) AS Next_Run_start_timestamp - FROM `perfomance/olap/tests_results` - WHERE Suite = 'Clickbench' AND Test = '_Verification' - And Timestamp >= CurrentUtcDate() - 30*Interval("P1D") - ORDER BY Db, Run_start_timestamp DESC, Version - ) AS run_start - ON runs.Db = run_start.Db AND runs.Version = run_start.Version - WHERE ( - (runs.Timestamp >= run_start.Run_start_timestamp AND runs.Timestamp < run_start.Next_Run_start_timestamp) OR - (runs.Timestamp >= run_start.Run_start_timestamp AND run_start.Next_Run_start_timestamp IS NULL) - ) - ) AS t1 - GROUP BY Db, Version, Run_start_timestamp, Next_Run_start_timestamp - ) AS run_start - GROUP BY Db, Branch, Version, Run_start_timestamp, Run_number_in_version, Next_Run_start_timestamp - ) AS launch_times - CROSS JOIN ( - SELECT - Suite, Test - FROM ( - SELECT - Suite, - ListSort(AGG_LIST_DISTINCT(Test)) AS Tests - FROM `perfomance/olap/tests_results` - WHere Timestamp >= CurrentUtcDate() - 30*Interval("P1D") - GROUP BY Suite - ORDER BY Suite - - ) - FLATTEN LIST BY Tests AS Test - ORDER BY Suite, Test - ) AS all_suites - ) AS launch_times + launch_times.* + FROM $launch_times AS launch_times LEFT JOIN ( - SELECT - all_tests.*, - JSON_VALUE(Info, "$.report_url") AS Report, - JSON_VALUE(all_tests.Info, "$.cluster.version") AS Version_n, - CAST(JSON_VALUE(Stats, '$.DiffsCount') AS INT) AS diff_response, - IF(Success > 0, MeanDuration / 1000) AS YdbSumMeans, - IF(Success > 0, MaxDuration / 1000) AS YdbSumMax, - IF(Success > 0, MinDuration / 1000) AS YdbSumMin, - CAST(RunId / 1000 AS Timestamp) AS RunTs, - IF (JSON_VALUE(Stats, "$.errors.other") = "true", - "red", - IF (JSON_VALUE(Stats, "$.errors.timeout") = "true", - "blue", - IF (JSON_VALUE(Stats, "$.errors.warning") = "true", - "yellow", - "green" - ) - ) - ) as Color - FROM `perfomance/olap/tests_results` AS all_tests - WHere Timestamp >= CurrentUtcDate() - 30*Interval("P1D") + SELECT + * + FROM $all_tests_raw AS all_tests_raw + WHERE JSON_VALUE(all_tests_raw.Info, "$.cluster.version") is NULL ) AS all_tests ON all_tests.Db = launch_times.Db AND all_tests.Suite = launch_times.Suite AND all_tests.Test = launch_times.Test - AND all_tests.Version_n = launch_times.Version - WHERE ( - (all_tests.Timestamp >= launch_times.Run_start_timestamp AND all_tests.Timestamp < launch_times.Next_Run_start_timestamp) OR - (all_tests.Timestamp >= launch_times.Run_start_timestamp AND launch_times.Next_Run_start_timestamp IS NULL) - OR all_tests.RunId IS NULL - - ) - - ORDER BY Run_start_timestamp DESC, Db, Version, RunId + -- WHERE ( all_tests.Version_n is NULL) + ) AS null_template + FULL OUTER JOIN ( + SELECT + real_data.Db AS Db, + real_data.Kind AS Kind, + real_data.MaxDuration AS MaxDuration, + real_data.MeanDuration AS MeanDuration, + real_data.MedianDuration AS MedianDuration, + real_data.MinDuration AS MinDuration, + real_data.Report AS Report, + real_data.Branch AS Branch, + real_data.RunId AS RunId, + real_data.RunTs AS RunTs, + real_data.Run_number_in_version AS Run_number_in_version, + real_data.Run_start_timestamp AS Run_start_timestamp, + real_data.Run_number_in_branch_desc AS Run_number_in_branch_desc, + --real_data.Stats AS Stats, + real_data.Success AS Success, + real_data.Suite AS Suite, + real_data.Test AS Test, + real_data.Timestamp AS Timestamp, + real_data.Version AS Version, + real_data.YdbSumMax AS YdbSumMax, + real_data.YdbSumMeans AS YdbSumMeans, + real_data.YdbSumMin AS YdbSumMin, + real_data.diff_response AS diff_response, + real_data.Color AS Color, + FROM ( + SELECT + all_tests.*, + launch_times.*, + FROM $launch_times AS launch_times + LEFT JOIN $all_tests_raw AS all_tests + ON all_tests.Db = launch_times.Db + AND all_tests.Suite = launch_times.Suite + AND all_tests.Test = launch_times.Test + AND all_tests.Version_n = launch_times.Version + WHERE ( + all_tests.LunchId_n == launch_times.LunchId + OR all_tests.RunId IS NULL + ) + ) AS real_data ) AS real_data -) as real_data - -on null_template.Db = real_data.Db -and null_template.Run_start_timestamp = real_data.Run_start_timestamp -and null_template.Suite = real_data.Suite -and null_template.Test = real_data.Test + ON null_template.Db = real_data.Db + AND null_template.Run_start_timestamp = real_data.Run_start_timestamp + AND null_template.Suite = real_data.Suite + AND null_template.Test = real_data.Test ) - - - diff --git a/.github/scripts/analytics/data_mart_queries/test_history_fast_mart.sql b/.github/scripts/analytics/data_mart_queries/test_history_fast_mart.sql new file mode 100644 index 000000000000..8245527f3368 --- /dev/null +++ b/.github/scripts/analytics/data_mart_queries/test_history_fast_mart.sql @@ -0,0 +1,25 @@ +SELECT + build_type, + job_name, + job_id, + commit, + branch, + pull, + run_timestamp, + test_id, + suite_folder, + test_name, + cast(suite_folder || '/' || test_name as UTF8) as full_name, + duration, + status, + cast(String::ReplaceAll(status_description, ';;', '\n')as Utf8) as status_description , + owners + FROM `test_results/test_runs_column` as all_data + WHERE + run_timestamp >= CurrentUtcDate() - Interval("P1D") + and String::Contains(test_name, '.flake8') = FALSE + and (CASE + WHEN String::Contains(test_name, 'chunk chunk') OR String::Contains(test_name, 'chunk+chunk') THEN TRUE + ELSE FALSE + END) = FALSE + and (branch = 'main' or branch like 'stable-%') diff --git a/.github/scripts/analytics/data_mart_queries/test_history_mart.sql b/.github/scripts/analytics/data_mart_queries/test_history_mart.sql new file mode 100644 index 000000000000..83f5e67d8abb --- /dev/null +++ b/.github/scripts/analytics/data_mart_queries/test_history_mart.sql @@ -0,0 +1,34 @@ +SELECT + build_type , + job_name, + job_id, + commit, + branch, + pull, + run_timestamp, + test_id, + suite_folder, + test_name, + cast(suite_folder || '/' || test_name as UTF8) as full_name, + duration, + status, + String::ReplaceAll(status_description, ';;', '\n') as status_description, + owners, + String::ReplaceAll(owners, 'TEAM:@ydb-platform/', '') as owner_team, + String::SplitToList(pull,'_A')[0] as pull_raw, + cast(COALESCE(String::SplitToList(pull,'_A')[1],"1") as Uint16) as attempt, + (cast(pull as String) || '_' || SUBSTRING(cast(commit as String), 1, 8)) as pull_commit, + CASE + WHEN String::Contains(test_name, 'chunk chunk') OR String::Contains(test_name, 'chunk+chunk') THEN TRUE + ELSE FALSE + END as with_cunks + +FROM `test_results/test_runs_column` + +WHERE + run_timestamp >= CurrentUtcDate() - 1*Interval("P1D") + and String::Contains(test_name, '.flake8') = FALSE + and (CASE + WHEN String::Contains(test_name, 'chunk chunk') OR String::Contains(test_name, 'chunk+chunk') THEN TRUE + ELSE FALSE + END) = FALSE diff --git a/.github/scripts/analytics/data_mart_queries/test_monitor_mart.sql b/.github/scripts/analytics/data_mart_queries/test_monitor_mart.sql index ebf1793f8364..4383be240345 100644 --- a/.github/scripts/analytics/data_mart_queries/test_monitor_mart.sql +++ b/.github/scripts/analytics/data_mart_queries/test_monitor_mart.sql @@ -36,10 +36,9 @@ SELECT END as is_muted_or_skipped FROM `test_results/analytics/tests_monitor` WHERE date_window >= CurrentUtcDate() - 30 * Interval("P1D") -and branch = 'main' +and ( branch = 'main' or branch like 'stable-%') and is_test_chunk = 0 and (CASE WHEN is_muted = 1 OR (state = 'Skipped' AND days_in_state > 14) THEN TRUE ELSE FALSE END ) = TRUE - diff --git a/.github/scripts/analytics/data_mart_queries/test_results_mart.sql b/.github/scripts/analytics/data_mart_queries/test_results_mart.sql deleted file mode 100644 index 3e7c3d31619c..000000000000 --- a/.github/scripts/analytics/data_mart_queries/test_results_mart.sql +++ /dev/null @@ -1,35 +0,0 @@ -SELECT - build_type , - job_name, - job_id, - commit, - branch, - pull, - run_timestamp, - test_id, - suite_folder, - test_name, - cast(suite_folder || '/' || test_name as UTF8) as full_name, - duration, - status, - String::ReplaceAll(status_description, ';;', '\n') as status_description, - owners, - String::ReplaceAll(owners, 'TEAM:@ydb-platform/', '') as owner_team, - String::SplitToList(pull,'_A')[0] as pull_raw, - cast(COALESCE(String::SplitToList(pull,'_A')[1],"1") as Uint16) as attempt, - (cast(pull as String) || '_' || SUBSTRING(cast(commit as String), 1, 8)) as pull_commit, - CASE - WHEN String::Contains(test_name, 'chunk chunk') OR String::Contains(test_name, 'chunk+chunk') THEN TRUE - ELSE FALSE - END as with_cunks - -FROM `test_results/test_runs_column` - -WHERE - run_timestamp >= CurrentUtcDate() - 6*Interval("P1D") - and build_type = 'relwithdebinfo' - and String::Contains(test_name, '.flake8') = FALSE - and (CASE - WHEN String::Contains(test_name, 'chunk chunk') OR String::Contains(test_name, 'chunk+chunk') THEN TRUE - ELSE FALSE - END) = FALSE diff --git a/.github/scripts/analytics/data_mart_ttl_analog.py b/.github/scripts/analytics/data_mart_ttl_analog.py new file mode 100644 index 000000000000..9d80406ca0c2 --- /dev/null +++ b/.github/scripts/analytics/data_mart_ttl_analog.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +import argparse +import ydb +import configparser +import os +import time + +# Load configuration +dir = os.path.dirname(__file__) +config = configparser.ConfigParser() +config_file_path = f"{dir}/../../config/ydb_qa_db.ini" +config.read(config_file_path) + +DATABASE_ENDPOINT = config["QA_DB"]["DATABASE_ENDPOINT"] +DATABASE_PATH = config["QA_DB"]["DATABASE_PATH"] + +def parse_args(): + parser = argparse.ArgumentParser(description="Delete old records from YDB table") + parser.add_argument("--table-path", required=True, help="Table path and name") + parser.add_argument("--timestamp-field", required=True, help="Name of the timestamp field") + parser.add_argument("--delete-interval", required=True, help="Interval to delete records older than, in ISO 8601 format (https://en.wikipedia.org/wiki/ISO_8601#Durations) without 'P'") + + return parser.parse_args() + +def delete_old_records(session, full_table_path, timestamp_field, delete_interval): + """Delete records older than the specified interval.""" + # First, count the number of records that will be deleted + count_query = f""" + SELECT COUNT(*) as count + FROM `{full_table_path}` + WHERE `{timestamp_field}` < CurrentUtcDate() - Interval("P{delete_interval}") + """ + + print(f"Counting records to delete...") + result_sets = session.transaction().execute(count_query) + row_count = result_sets[0].rows[0].count + + if row_count == 0: + print("No records to delete.") + return 0 + + print(f"Found {row_count} records older than {delete_interval}.") + + # Now perform the delete operation + delete_query = f""" + DELETE FROM `{full_table_path}` + WHERE `{timestamp_field}` < CurrentUtcDate() - Interval("P{delete_interval}") + """ + + print(f"Executing DELETE query: {delete_query}") + start_time = time.time() + session.transaction().execute(delete_query, commit_tx=True) + end_time = time.time() + + print(f"Deleted {row_count} records in {end_time - start_time:.2f} seconds.") + return row_count + +def main(): + args = parse_args() + + if "CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS" not in os.environ: + print("Error: Env variable CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS is missing, skipping") + return 1 + else: + os.environ["YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS"] = os.environ[ + "CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS" + ] + + table_path = args.table_path + full_table_path = f'{DATABASE_PATH}/{table_path}' + timestamp_field = args.timestamp_field + delete_interval = args.delete_interval + + print(f"Connecting to YDB to delete records from {full_table_path}") + print(f"Will delete records where {timestamp_field} < CurrentUtcDate() - Interval(\"P{delete_interval}\")") + + with ydb.Driver( + endpoint=DATABASE_ENDPOINT, + database=DATABASE_PATH, + credentials=ydb.credentials_from_env_variables() + ) as driver: + # Wait until driver is ready + driver.wait(timeout=10, fail_fast=True) + + with ydb.SessionPool(driver) as pool: + try: + def transaction_delete(session): + return delete_old_records(session, full_table_path, timestamp_field, delete_interval) + + deleted_count = pool.retry_operation_sync(transaction_delete) + + print(f"Successfully deleted old records from {full_table_path}") + print(f"Total records deleted: {deleted_count}") + return 0 + except ydb.Error as e: + print(f"Error deleting records: {e}") + return 1 + +if __name__ == "__main__": + exit_code = main() + exit(exit_code) diff --git a/.github/scripts/analytics/flaky_tests_history.py b/.github/scripts/analytics/flaky_tests_history.py index d1c1c637af45..29b55d1dc11d 100755 --- a/.github/scripts/analytics/flaky_tests_history.py +++ b/.github/scripts/analytics/flaky_tests_history.py @@ -78,8 +78,8 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('--days-window', default=1, type=int, help='how many days back we collecting history') - parser.add_argument('--build_type',choices=['relwithdebinfo', 'release-asan'], default='relwithdebinfo', type=str, help='build : relwithdebinfo or release-asan') - parser.add_argument('--branch', default='main',choices=['main'], type=str, help='branch') + parser.add_argument('--build_type', default='relwithdebinfo', type=str, help='build types') + parser.add_argument('--branch', default='main', type=str, help='branch') args, unknown = parser.parse_known_args() history_for_n_day = args.days_window @@ -203,6 +203,9 @@ def main(): and job_name in ( 'Nightly-run', 'Regression-run', + 'Regression-run_Large', + 'Regression-run_Small_and_Medium', + 'Regression-run_compatibility', 'Regression-whitelist-run', 'Postcommit_relwithdebinfo', 'Postcommit_asan' diff --git a/.github/scripts/analytics/flaky_tests_history_n_runs.py b/.github/scripts/analytics/flaky_tests_history_n_runs.py index 1c4787a45c59..c35046374e25 100755 --- a/.github/scripts/analytics/flaky_tests_history_n_runs.py +++ b/.github/scripts/analytics/flaky_tests_history_n_runs.py @@ -203,6 +203,9 @@ def main(): and job_name in ( 'Nightly-run', 'Regression-run', + 'Regression-run_Large', + 'Regression-run_Small_and_Medium', + 'Regression-run_compatibility', 'Regression-whitelist-run', 'Postcommit_relwithdebinfo', 'Postcommit_asan' @@ -227,6 +230,9 @@ def main(): and job_name in ( 'Nightly-run', 'Regression-run', + 'Regression-run_Large', + 'Regression-run_Small_and_Medium', + 'Regression-run_compatibility', 'Regression-whitelist-run', 'Postcommit_relwithdebinfo', 'Postcommit_asan' diff --git a/.github/scripts/analytics/test_history_fast.py b/.github/scripts/analytics/test_history_fast.py index cf14a3836370..7dc78b484f16 100755 --- a/.github/scripts/analytics/test_history_fast.py +++ b/.github/scripts/analytics/test_history_fast.py @@ -19,6 +19,17 @@ def drop_table(session, table_path): session.execute_scheme(f"DROP TABLE IF EXISTS `{table_path}`;") +def check_table_exists(session, table_path): + """Check if table exists""" + try: + session.describe_table(table_path) + print(f"Table '{table_path}' already exists.") + return True + except ydb.SchemeError: + print(f"Table '{table_path}' does not exist.") + return False + + def create_test_history_fast_table(session, table_path): print(f"> Creating table: '{table_path}'") session.execute_scheme(f""" @@ -38,7 +49,7 @@ def create_test_history_fast_table(session, table_path): `status` Utf8, `status_description` Utf8, `owners` Utf8, - PRIMARY KEY (`full_name`, `run_timestamp`, `job_name`, `branch`, `build_type`, test_id) + PRIMARY KEY (`run_timestamp`, `full_name`, `job_name`, `branch`, `build_type`, test_id) ) PARTITION BY HASH(run_timestamp) WITH ( @@ -74,7 +85,7 @@ def bulk_upsert(table_client, table_path, rows): def get_missed_data_for_upload(driver): results = [] query = f""" - SELECT + SELECT build_type, job_name, job_id, @@ -96,8 +107,14 @@ def get_missed_data_for_upload(driver): ) as fast_data_missed ON all_data.run_timestamp = fast_data_missed.run_timestamp WHERE - all_data.run_timestamp >= CurrentUtcDate() - 6*Interval("P1D") AND - fast_data_missed.run_timestamp is NULL + all_data.run_timestamp >= CurrentUtcDate() - 6*Interval("P1D") + and String::Contains(all_data.test_name, '.flake8') = FALSE + and (CASE + WHEN String::Contains(all_data.test_name, 'chunk chunk') OR String::Contains(all_data.test_name, 'chunk+chunk') THEN TRUE + ELSE FALSE + END) = FALSE + and (all_data.branch = 'main' or all_data.branch like 'stable-%') + and fast_data_missed.run_timestamp is NULL """ scan_query = ydb.ScanQuery(query, {}) @@ -127,7 +144,8 @@ def main(): ] table_path = "test_results/analytics/test_history_fast" - batch_size = 50000 + full_table_path = f'{DATABASE_PATH}/{table_path}' + batch_size = 1000 with ydb.Driver( endpoint=DATABASE_ENDPOINT, @@ -136,13 +154,24 @@ def main(): ) as driver: driver.wait(timeout=10, fail_fast=True) with ydb.SessionPool(driver) as pool: + # Проверяем существование таблицы и создаем её если нужно + def check_and_create_table(session): + exists = check_table_exists(session, full_table_path) + if not exists: + create_test_history_fast_table(session, full_table_path) + return True + return exists + + pool.retry_operation_sync(check_and_create_table) + + # Продолжаем с основной логикой скрипта prepared_for_upload_rows = get_missed_data_for_upload(driver) print(f'Preparing to upsert: {len(prepared_for_upload_rows)} rows') if prepared_for_upload_rows: for start in range(0, len(prepared_for_upload_rows), batch_size): batch_rows_for_upload = prepared_for_upload_rows[start:start + batch_size] print(f'upserting: {start}-{start + len(batch_rows_for_upload)}/{len(prepared_for_upload_rows)} rows') - bulk_upsert(driver.table_client, f'{DATABASE_PATH}/{table_path}', batch_rows_for_upload) + bulk_upsert(driver.table_client, full_table_path, batch_rows_for_upload) print('Tests uploaded') else: print('Nothing to upload') diff --git a/.github/scripts/analytics/tests_monitor.py b/.github/scripts/analytics/tests_monitor.py index 89c2489ad3ab..fc23a4c0ed6d 100755 --- a/.github/scripts/analytics/tests_monitor.py +++ b/.github/scripts/analytics/tests_monitor.py @@ -283,12 +283,12 @@ def main(): parser.add_argument('--days-window', default=1, type=int, help='how many days back we collecting history') parser.add_argument( '--build_type', - choices=['relwithdebinfo', 'release-asan'], + choices=['relwithdebinfo', 'release-asan', 'release-tsan', 'release-msan'], default='relwithdebinfo', type=str, - help='build : relwithdebinfo or release-asan', + help='build type', ) - parser.add_argument('--branch', default='main', choices=['main'], type=str, help='branch') + parser.add_argument('--branch', default='main', type=str, help='branch') parser.add_argument( '--concurent', @@ -325,7 +325,7 @@ def main(): tc_settings = ydb.TableClientSettings().with_native_date_in_result_sets(enabled=False) table_client = ydb.TableClient(driver, tc_settings) base_date = datetime.datetime(1970, 1, 1) - default_start_date = datetime.date(2024, 11, 1) + default_start_date = datetime.date(2025, 2, 1) today = datetime.date.today() table_path = f'test_results/analytics/tests_monitor' diff --git a/.github/scripts/analytics/upload_testowners.py b/.github/scripts/analytics/upload_testowners.py index 05cae9b04f06..ed20ffcbf03b 100755 --- a/.github/scripts/analytics/upload_testowners.py +++ b/.github/scripts/analytics/upload_testowners.py @@ -1,11 +1,8 @@ #!/usr/bin/env python3 -import argparse import configparser -import datetime import os import posixpath -import traceback import time import ydb from collections import Counter @@ -95,6 +92,9 @@ def main(): and job_name in ( 'Nightly-run', 'Regression-run', + 'Regression-run_Large', + 'Regression-run_Small_and_Medium', + 'Regression-run_compatibility', 'Regression-whitelist-run', 'Postcommit_relwithdebinfo', 'Postcommit_asan' diff --git a/.github/scripts/tests/create_new_muted_ya.py b/.github/scripts/tests/create_new_muted_ya.py index 8642a93398d7..e2aae4931d9f 100755 --- a/.github/scripts/tests/create_new_muted_ya.py +++ b/.github/scripts/tests/create_new_muted_ya.py @@ -28,8 +28,8 @@ DATABASE_PATH = config["QA_DB"]["DATABASE_PATH"] -def execute_query(driver): - query_string = ''' +def execute_query(driver, branch='main', build_type='relwithdebinfo'): + query_string = f''' SELECT * from ( SELECT data.*, CASE WHEN new_flaky.full_name IS NOT NULL THEN True ELSE False END AS new_flaky_today, @@ -101,7 +101,7 @@ def execute_query(driver): and data.build_type = deleted.build_type and data.branch = deleted.branch ) - where date_window = CurrentUtcDate() and branch = 'main' + where date_window = CurrentUtcDate() and branch = '{branch}' and build_type = '{build_type}' ''' @@ -178,8 +178,8 @@ def apply_and_add_mutes(all_tests, output_path, mute_check): for test in all_tests if test.get('days_in_state') >= 1 and test.get('flaky_today') - and (test.get('pass_count') + test.get('fail_count')) >= 3 - and test.get('fail_count') > 2 + and (test.get('pass_count') + test.get('fail_count')) >= 2 + and test.get('fail_count') >= 2 and test.get('fail_count')/(test.get('pass_count') + test.get('fail_count')) > 0.2 # <=80% success rate ) flaky_tests = sorted(flaky_tests) @@ -191,8 +191,8 @@ def apply_and_add_mutes(all_tests, output_path, mute_check): for test in all_tests if test.get('days_in_state') >= 1 and test.get('flaky_today') - and (test.get('pass_count') + test.get('fail_count')) >= 3 - and test.get('fail_count') > 2 + and (test.get('pass_count') + test.get('fail_count')) >=2 + and test.get('fail_count') >= 2 and test.get('fail_count')/(test.get('pass_count') + test.get('fail_count')) > 0.2 # <=80% success rate ) ## тесты может запускаться 1 раз в день. если за последние 7 дней набирается трешход то мьютим @@ -356,9 +356,9 @@ def create_mute_issues(all_tests, file_path): print(f"Writing results to {file_path}") with open(file_path, 'w') as f: - f.write("```\n") + f.write("\n") f.write("\n".join(results)) - f.write("\n```") + f.write("\n") with open(os.environ['GITHUB_OUTPUT'], 'a') as gh_out: gh_out.write(f"created_issues_file={file_path}") @@ -389,7 +389,7 @@ def mute_worker(args): ) as driver: driver.wait(timeout=10, fail_fast=True) - all_tests = execute_query(driver) + all_tests = execute_query(driver, args.branch) if args.mode == 'update_muted_ya': output_path = args.output_folder os.makedirs(output_path, exist_ok=True) @@ -407,6 +407,7 @@ def mute_worker(args): update_muted_ya_parser = subparsers.add_parser('update_muted_ya', help='create new muted_ya') update_muted_ya_parser.add_argument('--output_folder', default=repo_path, required=False, help='Output folder.') + update_muted_ya_parser.add_argument('--branch', default='main', help='Branch to get history') create_issues_parser = subparsers.add_parser( 'create_issues', @@ -415,7 +416,8 @@ def mute_worker(args): create_issues_parser.add_argument( '--file_path', default=f'{repo_path}/mute_update/flaky.txt', required=False, help='file path' ) + create_issues_parser.add_argument('--branch', default='main', help='Branch to get history') args = parser.parse_args() - mute_worker(args) \ No newline at end of file + mute_worker(args) diff --git a/.github/scripts/tests/generate-summary.py b/.github/scripts/tests/generate-summary.py index 5fd6f20588b8..239f24e4e2eb 100755 --- a/.github/scripts/tests/generate-summary.py +++ b/.github/scripts/tests/generate-summary.py @@ -230,7 +230,7 @@ def render_pm(value, url, diff=None): return text -def render_testlist_html(rows, fn, build_preset): +def render_testlist_html(rows, fn, build_preset, branch): TEMPLATES_PATH = os.path.join(os.path.dirname(__file__), "templates") env = Environment(loader=FileSystemLoader(TEMPLATES_PATH), undefined=StrictUndefined) @@ -273,7 +273,7 @@ def render_testlist_html(rows, fn, build_preset): tests_names_for_history.append(test.full_name) try: - history = get_test_history(tests_names_for_history, last_n_runs, build_preset) + history = get_test_history(tests_names_for_history, last_n_runs, build_preset, branch) except Exception: print(traceback.format_exc()) @@ -308,7 +308,9 @@ def render_testlist_html(rows, fn, build_preset): tests=status_test, has_any_log=has_any_log, history=history, - build_preset=buid_preset_params + build_preset=build_preset, + buid_preset_params=buid_preset_params, + branch=branch ) with open(fn, "w") as fp: @@ -345,7 +347,7 @@ def get_codeowners_for_tests(codeowners_file_path, tests_data): tests_data_with_owners.append(test) -def gen_summary(public_dir, public_dir_url, paths, is_retry: bool, build_preset): +def gen_summary(public_dir, public_dir_url, paths, is_retry: bool, build_preset, branch): summary = TestSummary(is_retry=is_retry) for title, html_fn, path in paths: @@ -359,7 +361,7 @@ def gen_summary(public_dir, public_dir_url, paths, is_retry: bool, build_preset) html_fn = os.path.relpath(html_fn, public_dir) report_url = f"{public_dir_url}/{html_fn}" - render_testlist_html(summary_line.tests, os.path.join(public_dir, html_fn),build_preset) + render_testlist_html(summary_line.tests, os.path.join(public_dir, html_fn),build_preset, branch) summary_line.add_report(html_fn, report_url) summary.add_line(summary_line) @@ -418,6 +420,7 @@ def main(): parser.add_argument("--public_dir_url", required=True) parser.add_argument("--summary_links", required=True) parser.add_argument('--build_preset', default="default-linux-x86-64-relwithdebinfo", required=False) + parser.add_argument('--branch', default="main", required=False) parser.add_argument('--status_report_file', required=False) parser.add_argument('--is_retry', required=True, type=int) parser.add_argument('--is_last_retry', required=True, type=int) @@ -434,7 +437,13 @@ def main(): paths = iter(args.args) title_path = list(zip(paths, paths, paths)) - summary = gen_summary(args.public_dir, args.public_dir_url, title_path, is_retry=bool(args.is_retry),build_preset=args.build_preset) + summary = gen_summary(args.public_dir, + args.public_dir_url, + title_path, + is_retry=bool(args.is_retry), + build_preset=args.build_preset, + branch=args.branch + ) write_summary(summary) if summary.is_failed and not args.is_test_result_ignored: diff --git a/.github/scripts/tests/get_muted_tests.py b/.github/scripts/tests/get_muted_tests.py index ff28a7f831aa..ce523706d99d 100755 --- a/.github/scripts/tests/get_muted_tests.py +++ b/.github/scripts/tests/get_muted_tests.py @@ -187,7 +187,7 @@ def mute_applier(args): for test in all_tests: testsuite = to_str(test['suite_folder']) testcase = to_str(test['test_name']) - test['branch'] = 'main' + test['branch'] = args.branch test['is_muted'] = int(mute_check(testsuite, testcase)) upload_muted_tests(all_tests) diff --git a/.github/scripts/tests/get_test_history.py b/.github/scripts/tests/get_test_history.py index 06d4c323725e..a3b2e32146b8 100644 --- a/.github/scripts/tests/get_test_history.py +++ b/.github/scripts/tests/get_test_history.py @@ -16,7 +16,7 @@ DATABASE_PATH = config["QA_DB"]["DATABASE_PATH"] -def get_test_history(test_names_array, last_n_runs_of_test_amount, build_type): +def get_test_history(test_names_array, last_n_runs_of_test_amount, build_type, branch): if "CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS" not in os.environ: print( "Error: Env variable CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS is missing, skipping" @@ -48,33 +48,64 @@ def get_test_history(test_names_array, last_n_runs_of_test_amount, build_type): DECLARE $test_names AS List; DECLARE $rn_max AS Int32; DECLARE $build_type AS Utf8; - - $test_names=[{','.join("'{0}'".format(x) for x in test_names_batch)}]; + DECLARE $branch AS Utf8; + + $test_names = [{','.join("'{0}'".format(x) for x in test_names_batch)}]; $rn_max = {last_n_runs_of_test_amount}; $build_type = '{build_type}'; + $branch = '{branch}'; - $tests=( + -- Оптимизированный запрос с учетом особенностей YDB + $filtered_tests = ( SELECT - suite_folder ||'/' || test_name as full_name,test_name,build_type, commit, branch, run_timestamp, status, status_description, + suite_folder || '/' || test_name AS full_name, + test_name, + build_type, + commit, + branch, + run_timestamp, + status, + status_description, + job_id, + job_name, ROW_NUMBER() OVER (PARTITION BY test_name ORDER BY run_timestamp DESC) AS rn FROM - `test_results/test_runs_column` - where job_name in ( - 'Nightly-run', - 'Regression-run', - 'Regression-whitelist-run', - 'Postcommit_relwithdebinfo', - 'Postcommit_asan' - ) - and build_type = $build_type - and suite_folder ||'/' || test_name in $test_names - and status != 'skipped' + `test_results/test_runs_column` AS t + WHERE + t.build_type = $build_type + AND t.branch = $branch + AND t.job_name IN ( + 'Nightly-run', + 'Regression-run', + 'Regression-whitelist-run', + 'Postcommit_relwithdebinfo', + 'Postcommit_asan' + ) + AND t.status != 'skipped' + AND suite_folder || '/' || test_name IN $test_names ); - select full_name,test_name,build_type, commit, branch, run_timestamp, status, status_description,rn - from $tests - WHERE rn <= $rn_max - ORDER BY test_name, run_timestamp; + -- Финальный запрос с ограничением по количеству запусков + SELECT + full_name, + test_name, + build_type, + commit, + branch, + run_timestamp, + status, + status_description, + job_id, + job_name, + rn + FROM + $filtered_tests + WHERE + rn <= $rn_max + ORDER BY + test_name, + run_timestamp; + """ query = ydb.ScanQuery(history_query, {}) it = driver.table_client.scan_query(query) @@ -92,10 +123,13 @@ def get_test_history(test_names_array, last_n_runs_of_test_amount, build_type): results[row["full_name"].decode("utf-8")] = {} results[row["full_name"].decode("utf-8")][row["run_timestamp"]] = { + "branch": row["branch"], "status": row["status"], "commit": row["commit"], "datetime": datetime.datetime.fromtimestamp(int(row["run_timestamp"] / 1000000)).strftime("%H:%m %B %d %Y"), - "status_description": row["status_description"], + "status_description": row["status_description"].replace(';;','\n'), + "job_id": row["job_id"], + "job_name": row["job_name"] } end_time = time.time() print( @@ -104,4 +138,4 @@ def get_test_history(test_names_array, last_n_runs_of_test_amount, build_type): if __name__ == "__main__": - get_test_history(test_names_array, last_n_runs_of_test_amount, build_type) + get_test_history(test_names_array, last_n_runs_of_test_amount, build_type, branch) diff --git a/.github/scripts/tests/templates/summary.html b/.github/scripts/tests/templates/summary.html index a595d1b7e233..e21a31e54b65 100644 --- a/.github/scripts/tests/templates/summary.html +++ b/.github/scripts/tests/templates/summary.html @@ -321,6 +321,60 @@ overflow: auto; } + /* Стили для модального окна */ + #errorModal { + display: none; + position: fixed; + z-index: 1000; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0,0,0,0.5); + } + + .modal-content { + background-color: #fefefe; + margin: 5% auto; + padding: 20px; + border: 1px solid #888; + width: 80%; + border-radius: 5px; + max-height: 80vh; + overflow-y: auto; + } + + .close-modal { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; + cursor: pointer; + } + + .modal-header { + margin-bottom: 15px; + padding-bottom: 10px; + border-bottom: 1px solid #eee; + font-size: smaller; + } + + .modal-info { + font-size: small; + margin-bottom: 15px; + line-height: 1.5; + } + + .modal-info-item { + margin-bottom: 5px; + } + + .modal-info-label { + font-weight: bold; + display: inline-block; + width: 80px; + } ") - -produces - - Hello, ! - -but the contextual autoescaping in html/template - - import "html/template" - ... - t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) - err = t.ExecuteTemplate(out, "T", "") - -produces safe, escaped HTML output - - Hello, <script>alert('you have been pwned')</script>! - -# Contexts - -This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing -functions to each simple action pipeline, so given the excerpt - - {{.}} - -At parse time each {{.}} is overwritten to add escaping functions as necessary. -In this case it becomes - - {{. | htmlescaper}} - -where urlescaper, attrescaper, and htmlescaper are aliases for internal escaping -functions. - -For these internal escaping functions, if an action pipeline evaluates to -a nil interface value, it is treated as though it were an empty string. - -# Namespaced and data- attributes - -Attributes with a namespace are treated as if they had no namespace. -Given the excerpt - - - -At parse time the attribute will be treated as if it were just "href". -So at parse time the template becomes: - - - -Similarly to attributes with namespaces, attributes with a "data-" prefix are -treated as if they had no "data-" prefix. So given - - - -At parse time this becomes - - - -If an attribute has both a namespace and a "data-" prefix, only the namespace -will be removed when determining the context. For example - - - -This is handled as if "my:data-href" was just "data-href" and not "href" as -it would be if the "data-" prefix were to be ignored too. Thus at parse -time this becomes just - - - -As a special case, attributes with the namespace "xmlns" are always treated -as containing URLs. Given the excerpts - - - - - -At parse time they become: - - - - - -# Errors - -See the documentation of ErrorCode for details. - -# A fuller picture - -The rest of this package comment may be skipped on first reading; it includes -details necessary to understand escaping contexts and error messages. Most users -will not need to understand these details. - -# Contexts - -Assuming {{.}} is `O'Reilly: How are you?`, the table below shows -how {{.}} appears when used in the context to the left. - - Context {{.}} After - {{.}} O'Reilly: How are <i>you</i>? - O'Reilly: How are you? - O'Reilly: How are %3ci%3eyou%3c/i%3e? - O'Reilly%3a%20How%20are%3ci%3e...%3f - O\x27Reilly: How are \x3ci\x3eyou...? - "O\x27Reilly: How are \x3ci\x3eyou...?" - O\x27Reilly: How are \x3ci\x3eyou...\x3f - -If used in an unsafe context, then the value might be filtered out: - - Context {{.}} After - #ZgotmplZ - -since "O'Reilly:" is not an allowed protocol like "http:". - -If {{.}} is the innocuous word, `left`, then it can appear more widely, - - Context {{.}} After - {{.}} left - left - left - left - left - left - left - left - left - -Non-string values can be used in JavaScript contexts. -If {{.}} is - - struct{A,B string}{ "foo", "bar" } - -in the escaped template - - - -then the template output is - - - -See package json to understand how non-string content is marshaled for -embedding in JavaScript contexts. - -# Typed Strings - -By default, this package assumes that all pipelines produce a plain text string. -It adds escaping pipeline stages necessary to correctly and safely embed that -plain text string in the appropriate context. - -When a data value is not plain text, you can make sure it is not over-escaped -by marking it with its type. - -Types HTML, JS, URL, and others from content.go can carry safe content that is -exempted from escaping. - -The template - - Hello, {{.}}! - -can be invoked with - - tmpl.Execute(out, template.HTML(`World`)) - -to produce - - Hello, World! - -instead of the - - Hello, <b>World<b>! - -that would have been produced if {{.}} was a regular string. - -# Security Model - -https://rawgit.com/mikesamuel/sanitized-jquery-templates/trunk/safetemplate.html#problem_definition defines "safe" as used by this package. - -This package assumes that template authors are trusted, that Execute's data -parameter is not, and seeks to preserve the properties below in the face -of untrusted data: - -Structure Preservation Property: -"... when a template author writes an HTML tag in a safe templating language, -the browser will interpret the corresponding portion of the output as a tag -regardless of the values of untrusted data, and similarly for other structures -such as attribute boundaries and JS and CSS string boundaries." - -Code Effect Property: -"... only code specified by the template author should run as a result of -injecting the template output into a page and all code specified by the -template author should run as a result of the same." - -Least Surprise Property: -"A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who -knows that contextual autoescaping happens should be able to look at a {{.}} -and correctly infer what sanitization happens." - -As a consequence of the Least Surprise Property, template actions within an -ECMAScript 6 template literal are disabled by default. -Handling string interpolation within these literals is rather complex resulting -in no clear safe way to support it. -To re-enable template actions within ECMAScript 6 template literals, use the -GODEBUG=jstmpllitinterp=1 environment variable. -*/ -package template diff --git a/contrib/go/_std_1.22/src/html/template/js.go b/contrib/go/_std_1.22/src/html/template/js.go deleted file mode 100644 index d911ada26d3d..000000000000 --- a/contrib/go/_std_1.22/src/html/template/js.go +++ /dev/null @@ -1,485 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "bytes" - "encoding/json" - "fmt" - "reflect" - "strings" - "unicode/utf8" -) - -// jsWhitespace contains all of the JS whitespace characters, as defined -// by the \s character class. -// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Character_classes. -const jsWhitespace = "\f\n\r\t\v\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff" - -// nextJSCtx returns the context that determines whether a slash after the -// given run of tokens starts a regular expression instead of a division -// operator: / or /=. -// -// This assumes that the token run does not include any string tokens, comment -// tokens, regular expression literal tokens, or division operators. -// -// This fails on some valid but nonsensical JavaScript programs like -// "x = ++/foo/i" which is quite different than "x++/foo/i", but is not known to -// fail on any known useful programs. It is based on the draft -// JavaScript 2.0 lexical grammar and requires one token of lookbehind: -// https://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html -func nextJSCtx(s []byte, preceding jsCtx) jsCtx { - // Trim all JS whitespace characters - s = bytes.TrimRight(s, jsWhitespace) - if len(s) == 0 { - return preceding - } - - // All cases below are in the single-byte UTF-8 group. - switch c, n := s[len(s)-1], len(s); c { - case '+', '-': - // ++ and -- are not regexp preceders, but + and - are whether - // they are used as infix or prefix operators. - start := n - 1 - // Count the number of adjacent dashes or pluses. - for start > 0 && s[start-1] == c { - start-- - } - if (n-start)&1 == 1 { - // Reached for trailing minus signs since "---" is the - // same as "-- -". - return jsCtxRegexp - } - return jsCtxDivOp - case '.': - // Handle "42." - if n != 1 && '0' <= s[n-2] && s[n-2] <= '9' { - return jsCtxDivOp - } - return jsCtxRegexp - // Suffixes for all punctuators from section 7.7 of the language spec - // that only end binary operators not handled above. - case ',', '<', '>', '=', '*', '%', '&', '|', '^', '?': - return jsCtxRegexp - // Suffixes for all punctuators from section 7.7 of the language spec - // that are prefix operators not handled above. - case '!', '~': - return jsCtxRegexp - // Matches all the punctuators from section 7.7 of the language spec - // that are open brackets not handled above. - case '(', '[': - return jsCtxRegexp - // Matches all the punctuators from section 7.7 of the language spec - // that precede expression starts. - case ':', ';', '{': - return jsCtxRegexp - // CAVEAT: the close punctuators ('}', ']', ')') precede div ops and - // are handled in the default except for '}' which can precede a - // division op as in - // ({ valueOf: function () { return 42 } } / 2 - // which is valid, but, in practice, developers don't divide object - // literals, so our heuristic works well for code like - // function () { ... } /foo/.test(x) && sideEffect(); - // The ')' punctuator can precede a regular expression as in - // if (b) /foo/.test(x) && ... - // but this is much less likely than - // (a + b) / c - case '}': - return jsCtxRegexp - default: - // Look for an IdentifierName and see if it is a keyword that - // can precede a regular expression. - j := n - for j > 0 && isJSIdentPart(rune(s[j-1])) { - j-- - } - if regexpPrecederKeywords[string(s[j:])] { - return jsCtxRegexp - } - } - // Otherwise is a punctuator not listed above, or - // a string which precedes a div op, or an identifier - // which precedes a div op. - return jsCtxDivOp -} - -// regexpPrecederKeywords is a set of reserved JS keywords that can precede a -// regular expression in JS source. -var regexpPrecederKeywords = map[string]bool{ - "break": true, - "case": true, - "continue": true, - "delete": true, - "do": true, - "else": true, - "finally": true, - "in": true, - "instanceof": true, - "return": true, - "throw": true, - "try": true, - "typeof": true, - "void": true, -} - -var jsonMarshalType = reflect.TypeFor[json.Marshaler]() - -// indirectToJSONMarshaler returns the value, after dereferencing as many times -// as necessary to reach the base type (or nil) or an implementation of json.Marshal. -func indirectToJSONMarshaler(a any) any { - // text/template now supports passing untyped nil as a func call - // argument, so we must support it. Otherwise we'd panic below, as one - // cannot call the Type or Interface methods on an invalid - // reflect.Value. See golang.org/issue/18716. - if a == nil { - return nil - } - - v := reflect.ValueOf(a) - for !v.Type().Implements(jsonMarshalType) && v.Kind() == reflect.Pointer && !v.IsNil() { - v = v.Elem() - } - return v.Interface() -} - -// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has -// neither side-effects nor free variables outside (NaN, Infinity). -func jsValEscaper(args ...any) string { - var a any - if len(args) == 1 { - a = indirectToJSONMarshaler(args[0]) - switch t := a.(type) { - case JS: - return string(t) - case JSStr: - // TODO: normalize quotes. - return `"` + string(t) + `"` - case json.Marshaler: - // Do not treat as a Stringer. - case fmt.Stringer: - a = t.String() - } - } else { - for i, arg := range args { - args[i] = indirectToJSONMarshaler(arg) - } - a = fmt.Sprint(args...) - } - // TODO: detect cycles before calling Marshal which loops infinitely on - // cyclic data. This may be an unacceptable DoS risk. - b, err := json.Marshal(a) - if err != nil { - // While the standard JSON marshaller does not include user controlled - // information in the error message, if a type has a MarshalJSON method, - // the content of the error message is not guaranteed. Since we insert - // the error into the template, as part of a comment, we attempt to - // prevent the error from either terminating the comment, or the script - // block itself. - // - // In particular we: - // * replace "*/" comment end tokens with "* /", which does not - // terminate the comment - // * replace "", "", or " element, -// or in an HTML5 event handler attribute such as onclick. -func jsStrEscaper(args ...any) string { - s, t := stringify(args...) - if t == contentTypeJSStr { - return replace(s, jsStrNormReplacementTable) - } - return replace(s, jsStrReplacementTable) -} - -func jsTmplLitEscaper(args ...any) string { - s, _ := stringify(args...) - return replace(s, jsBqStrReplacementTable) -} - -// jsRegexpEscaper behaves like jsStrEscaper but escapes regular expression -// specials so the result is treated literally when included in a regular -// expression literal. /foo{{.X}}bar/ matches the string "foo" followed by -// the literal text of {{.X}} followed by the string "bar". -func jsRegexpEscaper(args ...any) string { - s, _ := stringify(args...) - s = replace(s, jsRegexpReplacementTable) - if s == "" { - // /{{.X}}/ should not produce a line comment when .X == "". - return "(?:)" - } - return s -} - -// replace replaces each rune r of s with replacementTable[r], provided that -// r < len(replacementTable). If replacementTable[r] is the empty string then -// no replacement is made. -// It also replaces runes U+2028 and U+2029 with the raw strings `\u2028` and -// `\u2029`. -func replace(s string, replacementTable []string) string { - var b strings.Builder - r, w, written := rune(0), 0, 0 - for i := 0; i < len(s); i += w { - // See comment in htmlEscaper. - r, w = utf8.DecodeRuneInString(s[i:]) - var repl string - switch { - case int(r) < len(lowUnicodeReplacementTable): - repl = lowUnicodeReplacementTable[r] - case int(r) < len(replacementTable) && replacementTable[r] != "": - repl = replacementTable[r] - case r == '\u2028': - repl = `\u2028` - case r == '\u2029': - repl = `\u2029` - default: - continue - } - if written == 0 { - b.Grow(len(s)) - } - b.WriteString(s[written:i]) - b.WriteString(repl) - written = i + w - } - if written == 0 { - return s - } - b.WriteString(s[written:]) - return b.String() -} - -var lowUnicodeReplacementTable = []string{ - 0: `\u0000`, 1: `\u0001`, 2: `\u0002`, 3: `\u0003`, 4: `\u0004`, 5: `\u0005`, 6: `\u0006`, - '\a': `\u0007`, - '\b': `\u0008`, - '\t': `\t`, - '\n': `\n`, - '\v': `\u000b`, // "\v" == "v" on IE 6. - '\f': `\f`, - '\r': `\r`, - 0xe: `\u000e`, 0xf: `\u000f`, 0x10: `\u0010`, 0x11: `\u0011`, 0x12: `\u0012`, 0x13: `\u0013`, - 0x14: `\u0014`, 0x15: `\u0015`, 0x16: `\u0016`, 0x17: `\u0017`, 0x18: `\u0018`, 0x19: `\u0019`, - 0x1a: `\u001a`, 0x1b: `\u001b`, 0x1c: `\u001c`, 0x1d: `\u001d`, 0x1e: `\u001e`, 0x1f: `\u001f`, -} - -var jsStrReplacementTable = []string{ - 0: `\u0000`, - '\t': `\t`, - '\n': `\n`, - '\v': `\u000b`, // "\v" == "v" on IE 6. - '\f': `\f`, - '\r': `\r`, - // Encode HTML specials as hex so the output can be embedded - // in HTML attributes without further encoding. - '"': `\u0022`, - '`': `\u0060`, - '&': `\u0026`, - '\'': `\u0027`, - '+': `\u002b`, - '/': `\/`, - '<': `\u003c`, - '>': `\u003e`, - '\\': `\\`, -} - -// jsBqStrReplacementTable is like jsStrReplacementTable except it also contains -// the special characters for JS template literals: $, {, and }. -var jsBqStrReplacementTable = []string{ - 0: `\u0000`, - '\t': `\t`, - '\n': `\n`, - '\v': `\u000b`, // "\v" == "v" on IE 6. - '\f': `\f`, - '\r': `\r`, - // Encode HTML specials as hex so the output can be embedded - // in HTML attributes without further encoding. - '"': `\u0022`, - '`': `\u0060`, - '&': `\u0026`, - '\'': `\u0027`, - '+': `\u002b`, - '/': `\/`, - '<': `\u003c`, - '>': `\u003e`, - '\\': `\\`, - '$': `\u0024`, - '{': `\u007b`, - '}': `\u007d`, -} - -// jsStrNormReplacementTable is like jsStrReplacementTable but does not -// overencode existing escapes since this table has no entry for `\`. -var jsStrNormReplacementTable = []string{ - 0: `\u0000`, - '\t': `\t`, - '\n': `\n`, - '\v': `\u000b`, // "\v" == "v" on IE 6. - '\f': `\f`, - '\r': `\r`, - // Encode HTML specials as hex so the output can be embedded - // in HTML attributes without further encoding. - '"': `\u0022`, - '&': `\u0026`, - '\'': `\u0027`, - '`': `\u0060`, - '+': `\u002b`, - '/': `\/`, - '<': `\u003c`, - '>': `\u003e`, -} -var jsRegexpReplacementTable = []string{ - 0: `\u0000`, - '\t': `\t`, - '\n': `\n`, - '\v': `\u000b`, // "\v" == "v" on IE 6. - '\f': `\f`, - '\r': `\r`, - // Encode HTML specials as hex so the output can be embedded - // in HTML attributes without further encoding. - '"': `\u0022`, - '$': `\$`, - '&': `\u0026`, - '\'': `\u0027`, - '(': `\(`, - ')': `\)`, - '*': `\*`, - '+': `\u002b`, - '-': `\-`, - '.': `\.`, - '/': `\/`, - '<': `\u003c`, - '>': `\u003e`, - '?': `\?`, - '[': `\[`, - '\\': `\\`, - ']': `\]`, - '^': `\^`, - '{': `\{`, - '|': `\|`, - '}': `\}`, -} - -// isJSIdentPart reports whether the given rune is a JS identifier part. -// It does not handle all the non-Latin letters, joiners, and combining marks, -// but it does handle every codepoint that can occur in a numeric literal or -// a keyword. -func isJSIdentPart(r rune) bool { - switch { - case r == '$': - return true - case '0' <= r && r <= '9': - return true - case 'A' <= r && r <= 'Z': - return true - case r == '_': - return true - case 'a' <= r && r <= 'z': - return true - } - return false -} - -// isJSType reports whether the given MIME type should be considered JavaScript. -// -// It is used to determine whether a script tag with a type attribute is a javascript container. -func isJSType(mimeType string) bool { - // per - // https://www.w3.org/TR/html5/scripting-1.html#attr-script-type - // https://tools.ietf.org/html/rfc7231#section-3.1.1 - // https://tools.ietf.org/html/rfc4329#section-3 - // https://www.ietf.org/rfc/rfc4627.txt - // discard parameters - mimeType, _, _ = strings.Cut(mimeType, ";") - mimeType = strings.ToLower(mimeType) - mimeType = strings.TrimSpace(mimeType) - switch mimeType { - case - "application/ecmascript", - "application/javascript", - "application/json", - "application/ld+json", - "application/x-ecmascript", - "application/x-javascript", - "module", - "text/ecmascript", - "text/javascript", - "text/javascript1.0", - "text/javascript1.1", - "text/javascript1.2", - "text/javascript1.3", - "text/javascript1.4", - "text/javascript1.5", - "text/jscript", - "text/livescript", - "text/x-ecmascript", - "text/x-javascript": - return true - default: - return false - } -} diff --git a/contrib/go/_std_1.22/src/html/template/template.go b/contrib/go/_std_1.22/src/html/template/template.go deleted file mode 100644 index 30b64dff0408..000000000000 --- a/contrib/go/_std_1.22/src/html/template/template.go +++ /dev/null @@ -1,530 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "fmt" - "io" - "io/fs" - "os" - "path" - "path/filepath" - "sync" - "text/template" - "text/template/parse" -) - -// Template is a specialized Template from "text/template" that produces a safe -// HTML document fragment. -type Template struct { - // Sticky error if escaping fails, or escapeOK if succeeded. - escapeErr error - // We could embed the text/template field, but it's safer not to because - // we need to keep our version of the name space and the underlying - // template's in sync. - text *template.Template - // The underlying template's parse tree, updated to be HTML-safe. - Tree *parse.Tree - *nameSpace // common to all associated templates -} - -// escapeOK is a sentinel value used to indicate valid escaping. -var escapeOK = fmt.Errorf("template escaped correctly") - -// nameSpace is the data structure shared by all templates in an association. -type nameSpace struct { - mu sync.Mutex - set map[string]*Template - escaped bool - esc escaper -} - -// Templates returns a slice of the templates associated with t, including t -// itself. -func (t *Template) Templates() []*Template { - ns := t.nameSpace - ns.mu.Lock() - defer ns.mu.Unlock() - // Return a slice so we don't expose the map. - m := make([]*Template, 0, len(ns.set)) - for _, v := range ns.set { - m = append(m, v) - } - return m -} - -// Option sets options for the template. Options are described by -// strings, either a simple string or "key=value". There can be at -// most one equals sign in an option string. If the option string -// is unrecognized or otherwise invalid, Option panics. -// -// Known options: -// -// missingkey: Control the behavior during execution if a map is -// indexed with a key that is not present in the map. -// -// "missingkey=default" or "missingkey=invalid" -// The default behavior: Do nothing and continue execution. -// If printed, the result of the index operation is the string -// "". -// "missingkey=zero" -// The operation returns the zero value for the map type's element. -// "missingkey=error" -// Execution stops immediately with an error. -func (t *Template) Option(opt ...string) *Template { - t.text.Option(opt...) - return t -} - -// checkCanParse checks whether it is OK to parse templates. -// If not, it returns an error. -func (t *Template) checkCanParse() error { - if t == nil { - return nil - } - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - if t.nameSpace.escaped { - return fmt.Errorf("html/template: cannot Parse after Execute") - } - return nil -} - -// escape escapes all associated templates. -func (t *Template) escape() error { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - t.nameSpace.escaped = true - if t.escapeErr == nil { - if t.Tree == nil { - return fmt.Errorf("template: %q is an incomplete or empty template", t.Name()) - } - if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil { - return err - } - } else if t.escapeErr != escapeOK { - return t.escapeErr - } - return nil -} - -// Execute applies a parsed template to the specified data object, -// writing the output to wr. -// If an error occurs executing the template or writing its output, -// execution stops, but partial results may already have been written to -// the output writer. -// A template may be executed safely in parallel, although if parallel -// executions share a Writer the output may be interleaved. -func (t *Template) Execute(wr io.Writer, data any) error { - if err := t.escape(); err != nil { - return err - } - return t.text.Execute(wr, data) -} - -// ExecuteTemplate applies the template associated with t that has the given -// name to the specified data object and writes the output to wr. -// If an error occurs executing the template or writing its output, -// execution stops, but partial results may already have been written to -// the output writer. -// A template may be executed safely in parallel, although if parallel -// executions share a Writer the output may be interleaved. -func (t *Template) ExecuteTemplate(wr io.Writer, name string, data any) error { - tmpl, err := t.lookupAndEscapeTemplate(name) - if err != nil { - return err - } - return tmpl.text.Execute(wr, data) -} - -// lookupAndEscapeTemplate guarantees that the template with the given name -// is escaped, or returns an error if it cannot be. It returns the named -// template. -func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - t.nameSpace.escaped = true - tmpl = t.set[name] - if tmpl == nil { - return nil, fmt.Errorf("html/template: %q is undefined", name) - } - if tmpl.escapeErr != nil && tmpl.escapeErr != escapeOK { - return nil, tmpl.escapeErr - } - if tmpl.text.Tree == nil || tmpl.text.Root == nil { - return nil, fmt.Errorf("html/template: %q is an incomplete template", name) - } - if t.text.Lookup(name) == nil { - panic("html/template internal error: template escaping out of sync") - } - if tmpl.escapeErr == nil { - err = escapeTemplate(tmpl, tmpl.text.Root, name) - } - return tmpl, err -} - -// DefinedTemplates returns a string listing the defined templates, -// prefixed by the string "; defined templates are: ". If there are none, -// it returns the empty string. Used to generate an error message. -func (t *Template) DefinedTemplates() string { - return t.text.DefinedTemplates() -} - -// Parse parses text as a template body for t. -// Named template definitions ({{define ...}} or {{block ...}} statements) in text -// define additional templates associated with t and are removed from the -// definition of t itself. -// -// Templates can be redefined in successive calls to Parse, -// before the first use of Execute on t or any associated template. -// A template definition with a body containing only white space and comments -// is considered empty and will not replace an existing template's body. -// This allows using Parse to add new named template definitions without -// overwriting the main template body. -func (t *Template) Parse(text string) (*Template, error) { - if err := t.checkCanParse(); err != nil { - return nil, err - } - - ret, err := t.text.Parse(text) - if err != nil { - return nil, err - } - - // In general, all the named templates might have changed underfoot. - // Regardless, some new ones may have been defined. - // The template.Template set has been updated; update ours. - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - for _, v := range ret.Templates() { - name := v.Name() - tmpl := t.set[name] - if tmpl == nil { - tmpl = t.new(name) - } - tmpl.text = v - tmpl.Tree = v.Tree - } - return t, nil -} - -// AddParseTree creates a new template with the name and parse tree -// and associates it with t. -// -// It returns an error if t or any associated template has already been executed. -func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { - if err := t.checkCanParse(); err != nil { - return nil, err - } - - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - text, err := t.text.AddParseTree(name, tree) - if err != nil { - return nil, err - } - ret := &Template{ - nil, - text, - text.Tree, - t.nameSpace, - } - t.set[name] = ret - return ret, nil -} - -// Clone returns a duplicate of the template, including all associated -// templates. The actual representation is not copied, but the name space of -// associated templates is, so further calls to Parse in the copy will add -// templates to the copy but not to the original. Clone can be used to prepare -// common templates and use them with variant definitions for other templates -// by adding the variants after the clone is made. -// -// It returns an error if t has already been executed. -func (t *Template) Clone() (*Template, error) { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - if t.escapeErr != nil { - return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) - } - textClone, err := t.text.Clone() - if err != nil { - return nil, err - } - ns := &nameSpace{set: make(map[string]*Template)} - ns.esc = makeEscaper(ns) - ret := &Template{ - nil, - textClone, - textClone.Tree, - ns, - } - ret.set[ret.Name()] = ret - for _, x := range textClone.Templates() { - name := x.Name() - src := t.set[name] - if src == nil || src.escapeErr != nil { - return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) - } - x.Tree = x.Tree.Copy() - ret.set[name] = &Template{ - nil, - x, - x.Tree, - ret.nameSpace, - } - } - // Return the template associated with the name of this template. - return ret.set[ret.Name()], nil -} - -// New allocates a new HTML template with the given name. -func New(name string) *Template { - ns := &nameSpace{set: make(map[string]*Template)} - ns.esc = makeEscaper(ns) - tmpl := &Template{ - nil, - template.New(name), - nil, - ns, - } - tmpl.set[name] = tmpl - return tmpl -} - -// New allocates a new HTML template associated with the given one -// and with the same delimiters. The association, which is transitive, -// allows one template to invoke another with a {{template}} action. -// -// If a template with the given name already exists, the new HTML template -// will replace it. The existing template will be reset and disassociated with -// t. -func (t *Template) New(name string) *Template { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - return t.new(name) -} - -// new is the implementation of New, without the lock. -func (t *Template) new(name string) *Template { - tmpl := &Template{ - nil, - t.text.New(name), - nil, - t.nameSpace, - } - if existing, ok := tmpl.set[name]; ok { - emptyTmpl := New(existing.Name()) - *existing = *emptyTmpl - } - tmpl.set[name] = tmpl - return tmpl -} - -// Name returns the name of the template. -func (t *Template) Name() string { - return t.text.Name() -} - -type FuncMap = template.FuncMap - -// Funcs adds the elements of the argument map to the template's function map. -// It must be called before the template is parsed. -// It panics if a value in the map is not a function with appropriate return -// type. However, it is legal to overwrite elements of the map. The return -// value is the template, so calls can be chained. -func (t *Template) Funcs(funcMap FuncMap) *Template { - t.text.Funcs(template.FuncMap(funcMap)) - return t -} - -// Delims sets the action delimiters to the specified strings, to be used in -// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template -// definitions will inherit the settings. An empty delimiter stands for the -// corresponding default: {{ or }}. -// The return value is the template, so calls can be chained. -func (t *Template) Delims(left, right string) *Template { - t.text.Delims(left, right) - return t -} - -// Lookup returns the template with the given name that is associated with t, -// or nil if there is no such template. -func (t *Template) Lookup(name string) *Template { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - return t.set[name] -} - -// Must is a helper that wraps a call to a function returning (*Template, error) -// and panics if the error is non-nil. It is intended for use in variable initializations -// such as -// -// var t = template.Must(template.New("name").Parse("html")) -func Must(t *Template, err error) *Template { - if err != nil { - panic(err) - } - return t -} - -// ParseFiles creates a new Template and parses the template definitions from -// the named files. The returned template's name will have the (base) name and -// (parsed) contents of the first file. There must be at least one file. -// If an error occurs, parsing stops and the returned *Template is nil. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template -// named "foo", while "a/foo" is unavailable. -func ParseFiles(filenames ...string) (*Template, error) { - return parseFiles(nil, readFileOS, filenames...) -} - -// ParseFiles parses the named files and associates the resulting templates with -// t. If an error occurs, parsing stops and the returned template is nil; -// otherwise it is t. There must be at least one file. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -// -// ParseFiles returns an error if t or any associated template has already been executed. -func (t *Template) ParseFiles(filenames ...string) (*Template, error) { - return parseFiles(t, readFileOS, filenames...) -} - -// parseFiles is the helper for the method and function. If the argument -// template is nil, it is created from the first file. -func parseFiles(t *Template, readFile func(string) (string, []byte, error), filenames ...string) (*Template, error) { - if err := t.checkCanParse(); err != nil { - return nil, err - } - - if len(filenames) == 0 { - // Not really a problem, but be consistent. - return nil, fmt.Errorf("html/template: no files named in call to ParseFiles") - } - for _, filename := range filenames { - name, b, err := readFile(filename) - if err != nil { - return nil, err - } - s := string(b) - // First template becomes return value if not already defined, - // and we use that one for subsequent New calls to associate - // all the templates together. Also, if this file has the same name - // as t, this file becomes the contents of t, so - // t, err := New(name).Funcs(xxx).ParseFiles(name) - // works. Otherwise we create a new template associated with t. - var tmpl *Template - if t == nil { - t = New(name) - } - if name == t.Name() { - tmpl = t - } else { - tmpl = t.New(name) - } - _, err = tmpl.Parse(s) - if err != nil { - return nil, err - } - } - return t, nil -} - -// ParseGlob creates a new Template and parses the template definitions from -// the files identified by the pattern. The files are matched according to the -// semantics of filepath.Match, and the pattern must match at least one file. -// The returned template will have the (base) name and (parsed) contents of the -// first file matched by the pattern. ParseGlob is equivalent to calling -// ParseFiles with the list of files matched by the pattern. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -func ParseGlob(pattern string) (*Template, error) { - return parseGlob(nil, pattern) -} - -// ParseGlob parses the template definitions in the files identified by the -// pattern and associates the resulting templates with t. The files are matched -// according to the semantics of filepath.Match, and the pattern must match at -// least one file. ParseGlob is equivalent to calling t.ParseFiles with the -// list of files matched by the pattern. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -// -// ParseGlob returns an error if t or any associated template has already been executed. -func (t *Template) ParseGlob(pattern string) (*Template, error) { - return parseGlob(t, pattern) -} - -// parseGlob is the implementation of the function and method ParseGlob. -func parseGlob(t *Template, pattern string) (*Template, error) { - if err := t.checkCanParse(); err != nil { - return nil, err - } - filenames, err := filepath.Glob(pattern) - if err != nil { - return nil, err - } - if len(filenames) == 0 { - return nil, fmt.Errorf("html/template: pattern matches no files: %#q", pattern) - } - return parseFiles(t, readFileOS, filenames...) -} - -// IsTrue reports whether the value is 'true', in the sense of not the zero of its type, -// and whether the value has a meaningful truth value. This is the definition of -// truth used by if and other such actions. -func IsTrue(val any) (truth, ok bool) { - return template.IsTrue(val) -} - -// ParseFS is like ParseFiles or ParseGlob but reads from the file system fs -// instead of the host operating system's file system. -// It accepts a list of glob patterns. -// (Note that most file names serve as glob patterns matching only themselves.) -func ParseFS(fs fs.FS, patterns ...string) (*Template, error) { - return parseFS(nil, fs, patterns) -} - -// ParseFS is like ParseFiles or ParseGlob but reads from the file system fs -// instead of the host operating system's file system. -// It accepts a list of glob patterns. -// (Note that most file names serve as glob patterns matching only themselves.) -func (t *Template) ParseFS(fs fs.FS, patterns ...string) (*Template, error) { - return parseFS(t, fs, patterns) -} - -func parseFS(t *Template, fsys fs.FS, patterns []string) (*Template, error) { - var filenames []string - for _, pattern := range patterns { - list, err := fs.Glob(fsys, pattern) - if err != nil { - return nil, err - } - if len(list) == 0 { - return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) - } - filenames = append(filenames, list...) - } - return parseFiles(t, readFileFS(fsys), filenames...) -} - -func readFileOS(file string) (name string, b []byte, err error) { - name = filepath.Base(file) - b, err = os.ReadFile(file) - return -} - -func readFileFS(fsys fs.FS) func(string) (string, []byte, error) { - return func(file string) (name string, b []byte, err error) { - name = path.Base(file) - b, err = fs.ReadFile(fsys, file) - return - } -} diff --git a/contrib/go/_std_1.22/src/internal/abi/map.go b/contrib/go/_std_1.22/src/internal/abi/map.go deleted file mode 100644 index ad054e7d7779..000000000000 --- a/contrib/go/_std_1.22/src/internal/abi/map.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package abi - -// Map constants common to several packages -// runtime/runtime-gdb.py:MapTypePrinter contains its own copy -const ( - MapBucketCountBits = 3 // log2 of number of elements in a bucket. - MapBucketCount = 1 << MapBucketCountBits - MapMaxKeyBytes = 128 // Must fit in a uint8. - MapMaxElemBytes = 128 // Must fit in a uint8. -) - -// ZeroValSize is the size in bytes of runtime.zeroVal. -const ZeroValSize = 1024 diff --git a/contrib/go/_std_1.22/src/internal/abi/symtab.go b/contrib/go/_std_1.22/src/internal/abi/symtab.go deleted file mode 100644 index ce1b65015519..000000000000 --- a/contrib/go/_std_1.22/src/internal/abi/symtab.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package abi - -// A FuncFlag records bits about a function, passed to the runtime. -type FuncFlag uint8 - -const ( - // FuncFlagTopFrame indicates a function that appears at the top of its stack. - // The traceback routine stop at such a function and consider that a - // successful, complete traversal of the stack. - // Examples of TopFrame functions include goexit, which appears - // at the top of a user goroutine stack, and mstart, which appears - // at the top of a system goroutine stack. - FuncFlagTopFrame FuncFlag = 1 << iota - - // FuncFlagSPWrite indicates a function that writes an arbitrary value to SP - // (any write other than adding or subtracting a constant amount). - // The traceback routines cannot encode such changes into the - // pcsp tables, so the function traceback cannot safely unwind past - // SPWrite functions. Stopping at an SPWrite function is considered - // to be an incomplete unwinding of the stack. In certain contexts - // (in particular garbage collector stack scans) that is a fatal error. - FuncFlagSPWrite - - // FuncFlagAsm indicates that a function was implemented in assembly. - FuncFlagAsm -) - -// A FuncID identifies particular functions that need to be treated -// specially by the runtime. -// Note that in some situations involving plugins, there may be multiple -// copies of a particular special runtime function. -type FuncID uint8 - -const ( - // If you add a FuncID, you probably also want to add an entry to the map in - // ../../cmd/internal/objabi/funcid.go - - FuncIDNormal FuncID = iota // not a special function - FuncID_abort - FuncID_asmcgocall - FuncID_asyncPreempt - FuncID_cgocallback - FuncID_corostart - FuncID_debugCallV2 - FuncID_gcBgMarkWorker - FuncID_goexit - FuncID_gogo - FuncID_gopanic - FuncID_handleAsyncEvent - FuncID_mcall - FuncID_morestack - FuncID_mstart - FuncID_panicwrap - FuncID_rt0_go - FuncID_runfinq - FuncID_runtime_main - FuncID_sigpanic - FuncID_systemstack - FuncID_systemstack_switch - FuncIDWrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.) -) - -// ArgsSizeUnknown is set in Func.argsize to mark all functions -// whose argument size is unknown (C vararg functions, and -// assembly code without an explicit specification). -// This value is generated by the compiler, assembler, or linker. -const ArgsSizeUnknown = -0x80000000 - -// IDs for PCDATA and FUNCDATA tables in Go binaries. -// -// These must agree with ../../../runtime/funcdata.h. -const ( - PCDATA_UnsafePoint = 0 - PCDATA_StackMapIndex = 1 - PCDATA_InlTreeIndex = 2 - PCDATA_ArgLiveIndex = 3 - - FUNCDATA_ArgsPointerMaps = 0 - FUNCDATA_LocalsPointerMaps = 1 - FUNCDATA_StackObjects = 2 - FUNCDATA_InlTree = 3 - FUNCDATA_OpenCodedDeferInfo = 4 - FUNCDATA_ArgInfo = 5 - FUNCDATA_ArgLiveInfo = 6 - FUNCDATA_WrapInfo = 7 -) - -// Special values for the PCDATA_UnsafePoint table. -const ( - UnsafePointSafe = -1 // Safe for async preemption - UnsafePointUnsafe = -2 // Unsafe for async preemption - - // UnsafePointRestart1(2) apply on a sequence of instructions, within - // which if an async preemption happens, we should back off the PC - // to the start of the sequence when resuming. - // We need two so we can distinguish the start/end of the sequence - // in case that two sequences are next to each other. - UnsafePointRestart1 = -3 - UnsafePointRestart2 = -4 - - // Like UnsafePointRestart1, but back to function entry if async preempted. - UnsafePointRestartAtEntry = -5 -) diff --git a/contrib/go/_std_1.22/src/internal/abi/type.go b/contrib/go/_std_1.22/src/internal/abi/type.go deleted file mode 100644 index 659fb7bffd32..000000000000 --- a/contrib/go/_std_1.22/src/internal/abi/type.go +++ /dev/null @@ -1,718 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package abi - -import ( - "unsafe" -) - -// Type is the runtime representation of a Go type. -// -// Be careful about accessing this type at build time, as the version -// of this type in the compiler/linker may not have the same layout -// as the version in the target binary, due to pointer width -// differences and any experiments. Use cmd/compile/internal/rttype -// or the functions in compiletype.go to access this type instead. -// (TODO: this admonition applies to every type in this package. -// Put it in some shared location?) -type Type struct { - Size_ uintptr - PtrBytes uintptr // number of (prefix) bytes in the type that can contain pointers - Hash uint32 // hash of type; avoids computation in hash tables - TFlag TFlag // extra type information flags - Align_ uint8 // alignment of variable with this type - FieldAlign_ uint8 // alignment of struct field with this type - Kind_ uint8 // enumeration for C - // function for comparing objects of this type - // (ptr to object A, ptr to object B) -> ==? - Equal func(unsafe.Pointer, unsafe.Pointer) bool - // GCData stores the GC type data for the garbage collector. - // If the KindGCProg bit is set in kind, GCData is a GC program. - // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. - GCData *byte - Str NameOff // string form - PtrToThis TypeOff // type for pointer to this type, may be zero -} - -// A Kind represents the specific kind of type that a Type represents. -// The zero Kind is not a valid kind. -type Kind uint - -const ( - Invalid Kind = iota - Bool - Int - Int8 - Int16 - Int32 - Int64 - Uint - Uint8 - Uint16 - Uint32 - Uint64 - Uintptr - Float32 - Float64 - Complex64 - Complex128 - Array - Chan - Func - Interface - Map - Pointer - Slice - String - Struct - UnsafePointer -) - -const ( - // TODO (khr, drchase) why aren't these in TFlag? Investigate, fix if possible. - KindDirectIface = 1 << 5 - KindGCProg = 1 << 6 // Type.gc points to GC program - KindMask = (1 << 5) - 1 -) - -// TFlag is used by a Type to signal what extra type information is -// available in the memory directly following the Type value. -type TFlag uint8 - -const ( - // TFlagUncommon means that there is a data with a type, UncommonType, - // just beyond the shared-per-type common data. That is, the data - // for struct types will store their UncommonType at one offset, the - // data for interface types will store their UncommonType at a different - // offset. UncommonType is always accessed via a pointer that is computed - // using trust-us-we-are-the-implementors pointer arithmetic. - // - // For example, if t.Kind() == Struct and t.tflag&TFlagUncommon != 0, - // then t has UncommonType data and it can be accessed as: - // - // type structTypeUncommon struct { - // structType - // u UncommonType - // } - // u := &(*structTypeUncommon)(unsafe.Pointer(t)).u - TFlagUncommon TFlag = 1 << 0 - - // TFlagExtraStar means the name in the str field has an - // extraneous '*' prefix. This is because for most types T in - // a program, the type *T also exists and reusing the str data - // saves binary size. - TFlagExtraStar TFlag = 1 << 1 - - // TFlagNamed means the type has a name. - TFlagNamed TFlag = 1 << 2 - - // TFlagRegularMemory means that equal and hash functions can treat - // this type as a single region of t.size bytes. - TFlagRegularMemory TFlag = 1 << 3 - - // TFlagUnrolledBitmap marks special types that are unrolled-bitmap - // versions of types with GC programs. - // These types need to be deallocated when the underlying object - // is freed. - TFlagUnrolledBitmap TFlag = 1 << 4 -) - -// NameOff is the offset to a name from moduledata.types. See resolveNameOff in runtime. -type NameOff int32 - -// TypeOff is the offset to a type from moduledata.types. See resolveTypeOff in runtime. -type TypeOff int32 - -// TextOff is an offset from the top of a text section. See (rtype).textOff in runtime. -type TextOff int32 - -// String returns the name of k. -func (k Kind) String() string { - if int(k) < len(kindNames) { - return kindNames[k] - } - return kindNames[0] -} - -var kindNames = []string{ - Invalid: "invalid", - Bool: "bool", - Int: "int", - Int8: "int8", - Int16: "int16", - Int32: "int32", - Int64: "int64", - Uint: "uint", - Uint8: "uint8", - Uint16: "uint16", - Uint32: "uint32", - Uint64: "uint64", - Uintptr: "uintptr", - Float32: "float32", - Float64: "float64", - Complex64: "complex64", - Complex128: "complex128", - Array: "array", - Chan: "chan", - Func: "func", - Interface: "interface", - Map: "map", - Pointer: "ptr", - Slice: "slice", - String: "string", - Struct: "struct", - UnsafePointer: "unsafe.Pointer", -} - -func (t *Type) Kind() Kind { return Kind(t.Kind_ & KindMask) } - -func (t *Type) HasName() bool { - return t.TFlag&TFlagNamed != 0 -} - -func (t *Type) Pointers() bool { return t.PtrBytes != 0 } - -// IfaceIndir reports whether t is stored indirectly in an interface value. -func (t *Type) IfaceIndir() bool { - return t.Kind_&KindDirectIface == 0 -} - -// isDirectIface reports whether t is stored directly in an interface value. -func (t *Type) IsDirectIface() bool { - return t.Kind_&KindDirectIface != 0 -} - -func (t *Type) GcSlice(begin, end uintptr) []byte { - return unsafe.Slice(t.GCData, int(end))[begin:] -} - -// Method on non-interface type -type Method struct { - Name NameOff // name of method - Mtyp TypeOff // method type (without receiver) - Ifn TextOff // fn used in interface call (one-word receiver) - Tfn TextOff // fn used for normal method call -} - -// UncommonType is present only for defined types or types with methods -// (if T is a defined type, the uncommonTypes for T and *T have methods). -// Using a pointer to this struct reduces the overall size required -// to describe a non-defined type with no methods. -type UncommonType struct { - PkgPath NameOff // import path; empty for built-in types like int, string - Mcount uint16 // number of methods - Xcount uint16 // number of exported methods - Moff uint32 // offset from this uncommontype to [mcount]Method - _ uint32 // unused -} - -func (t *UncommonType) Methods() []Method { - if t.Mcount == 0 { - return nil - } - return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.mcount > 0"))[:t.Mcount:t.Mcount] -} - -func (t *UncommonType) ExportedMethods() []Method { - if t.Xcount == 0 { - return nil - } - return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.xcount > 0"))[:t.Xcount:t.Xcount] -} - -// addChecked returns p+x. -// -// The whySafe string is ignored, so that the function still inlines -// as efficiently as p+x, but all call sites should use the string to -// record why the addition is safe, which is to say why the addition -// does not cause x to advance to the very end of p's allocation -// and therefore point incorrectly at the next block in memory. -func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { - return unsafe.Pointer(uintptr(p) + x) -} - -// Imethod represents a method on an interface type -type Imethod struct { - Name NameOff // name of method - Typ TypeOff // .(*FuncType) underneath -} - -// ArrayType represents a fixed array type. -type ArrayType struct { - Type - Elem *Type // array element type - Slice *Type // slice type - Len uintptr -} - -// Len returns the length of t if t is an array type, otherwise 0 -func (t *Type) Len() int { - if t.Kind() == Array { - return int((*ArrayType)(unsafe.Pointer(t)).Len) - } - return 0 -} - -func (t *Type) Common() *Type { - return t -} - -type ChanDir int - -const ( - RecvDir ChanDir = 1 << iota // <-chan - SendDir // chan<- - BothDir = RecvDir | SendDir // chan - InvalidDir ChanDir = 0 -) - -// ChanType represents a channel type -type ChanType struct { - Type - Elem *Type - Dir ChanDir -} - -type structTypeUncommon struct { - StructType - u UncommonType -} - -// ChanDir returns the direction of t if t is a channel type, otherwise InvalidDir (0). -func (t *Type) ChanDir() ChanDir { - if t.Kind() == Chan { - ch := (*ChanType)(unsafe.Pointer(t)) - return ch.Dir - } - return InvalidDir -} - -// Uncommon returns a pointer to T's "uncommon" data if there is any, otherwise nil -func (t *Type) Uncommon() *UncommonType { - if t.TFlag&TFlagUncommon == 0 { - return nil - } - switch t.Kind() { - case Struct: - return &(*structTypeUncommon)(unsafe.Pointer(t)).u - case Pointer: - type u struct { - PtrType - u UncommonType - } - return &(*u)(unsafe.Pointer(t)).u - case Func: - type u struct { - FuncType - u UncommonType - } - return &(*u)(unsafe.Pointer(t)).u - case Slice: - type u struct { - SliceType - u UncommonType - } - return &(*u)(unsafe.Pointer(t)).u - case Array: - type u struct { - ArrayType - u UncommonType - } - return &(*u)(unsafe.Pointer(t)).u - case Chan: - type u struct { - ChanType - u UncommonType - } - return &(*u)(unsafe.Pointer(t)).u - case Map: - type u struct { - MapType - u UncommonType - } - return &(*u)(unsafe.Pointer(t)).u - case Interface: - type u struct { - InterfaceType - u UncommonType - } - return &(*u)(unsafe.Pointer(t)).u - default: - type u struct { - Type - u UncommonType - } - return &(*u)(unsafe.Pointer(t)).u - } -} - -// Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil. -func (t *Type) Elem() *Type { - switch t.Kind() { - case Array: - tt := (*ArrayType)(unsafe.Pointer(t)) - return tt.Elem - case Chan: - tt := (*ChanType)(unsafe.Pointer(t)) - return tt.Elem - case Map: - tt := (*MapType)(unsafe.Pointer(t)) - return tt.Elem - case Pointer: - tt := (*PtrType)(unsafe.Pointer(t)) - return tt.Elem - case Slice: - tt := (*SliceType)(unsafe.Pointer(t)) - return tt.Elem - } - return nil -} - -// StructType returns t cast to a *StructType, or nil if its tag does not match. -func (t *Type) StructType() *StructType { - if t.Kind() != Struct { - return nil - } - return (*StructType)(unsafe.Pointer(t)) -} - -// MapType returns t cast to a *MapType, or nil if its tag does not match. -func (t *Type) MapType() *MapType { - if t.Kind() != Map { - return nil - } - return (*MapType)(unsafe.Pointer(t)) -} - -// ArrayType returns t cast to a *ArrayType, or nil if its tag does not match. -func (t *Type) ArrayType() *ArrayType { - if t.Kind() != Array { - return nil - } - return (*ArrayType)(unsafe.Pointer(t)) -} - -// FuncType returns t cast to a *FuncType, or nil if its tag does not match. -func (t *Type) FuncType() *FuncType { - if t.Kind() != Func { - return nil - } - return (*FuncType)(unsafe.Pointer(t)) -} - -// InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match. -func (t *Type) InterfaceType() *InterfaceType { - if t.Kind() != Interface { - return nil - } - return (*InterfaceType)(unsafe.Pointer(t)) -} - -// Size returns the size of data with type t. -func (t *Type) Size() uintptr { return t.Size_ } - -// Align returns the alignment of data with type t. -func (t *Type) Align() int { return int(t.Align_) } - -func (t *Type) FieldAlign() int { return int(t.FieldAlign_) } - -type InterfaceType struct { - Type - PkgPath Name // import path - Methods []Imethod // sorted by hash -} - -func (t *Type) ExportedMethods() []Method { - ut := t.Uncommon() - if ut == nil { - return nil - } - return ut.ExportedMethods() -} - -func (t *Type) NumMethod() int { - if t.Kind() == Interface { - tt := (*InterfaceType)(unsafe.Pointer(t)) - return tt.NumMethod() - } - return len(t.ExportedMethods()) -} - -// NumMethod returns the number of interface methods in the type's method set. -func (t *InterfaceType) NumMethod() int { return len(t.Methods) } - -type MapType struct { - Type - Key *Type - Elem *Type - Bucket *Type // internal type representing a hash bucket - // function for hashing keys (ptr to key, seed) -> hash - Hasher func(unsafe.Pointer, uintptr) uintptr - KeySize uint8 // size of key slot - ValueSize uint8 // size of elem slot - BucketSize uint16 // size of bucket - Flags uint32 -} - -// Note: flag values must match those used in the TMAP case -// in ../cmd/compile/internal/reflectdata/reflect.go:writeType. -func (mt *MapType) IndirectKey() bool { // store ptr to key instead of key itself - return mt.Flags&1 != 0 -} -func (mt *MapType) IndirectElem() bool { // store ptr to elem instead of elem itself - return mt.Flags&2 != 0 -} -func (mt *MapType) ReflexiveKey() bool { // true if k==k for all keys - return mt.Flags&4 != 0 -} -func (mt *MapType) NeedKeyUpdate() bool { // true if we need to update key on an overwrite - return mt.Flags&8 != 0 -} -func (mt *MapType) HashMightPanic() bool { // true if hash function might panic - return mt.Flags&16 != 0 -} - -func (t *Type) Key() *Type { - if t.Kind() == Map { - return (*MapType)(unsafe.Pointer(t)).Key - } - return nil -} - -type SliceType struct { - Type - Elem *Type // slice element type -} - -// funcType represents a function type. -// -// A *Type for each in and out parameter is stored in an array that -// directly follows the funcType (and possibly its uncommonType). So -// a function type with one method, one input, and one output is: -// -// struct { -// funcType -// uncommonType -// [2]*rtype // [0] is in, [1] is out -// } -type FuncType struct { - Type - InCount uint16 - OutCount uint16 // top bit is set if last input parameter is ... -} - -func (t *FuncType) In(i int) *Type { - return t.InSlice()[i] -} - -func (t *FuncType) NumIn() int { - return int(t.InCount) -} - -func (t *FuncType) NumOut() int { - return int(t.OutCount & (1<<15 - 1)) -} - -func (t *FuncType) Out(i int) *Type { - return (t.OutSlice()[i]) -} - -func (t *FuncType) InSlice() []*Type { - uadd := unsafe.Sizeof(*t) - if t.TFlag&TFlagUncommon != 0 { - uadd += unsafe.Sizeof(UncommonType{}) - } - if t.InCount == 0 { - return nil - } - return (*[1 << 16]*Type)(addChecked(unsafe.Pointer(t), uadd, "t.inCount > 0"))[:t.InCount:t.InCount] -} -func (t *FuncType) OutSlice() []*Type { - outCount := uint16(t.NumOut()) - if outCount == 0 { - return nil - } - uadd := unsafe.Sizeof(*t) - if t.TFlag&TFlagUncommon != 0 { - uadd += unsafe.Sizeof(UncommonType{}) - } - return (*[1 << 17]*Type)(addChecked(unsafe.Pointer(t), uadd, "outCount > 0"))[t.InCount : t.InCount+outCount : t.InCount+outCount] -} - -func (t *FuncType) IsVariadic() bool { - return t.OutCount&(1<<15) != 0 -} - -type PtrType struct { - Type - Elem *Type // pointer element (pointed at) type -} - -type StructField struct { - Name Name // name is always non-empty - Typ *Type // type of field - Offset uintptr // byte offset of field -} - -func (f *StructField) Embedded() bool { - return f.Name.IsEmbedded() -} - -type StructType struct { - Type - PkgPath Name - Fields []StructField -} - -// Name is an encoded type Name with optional extra data. -// -// The first byte is a bit field containing: -// -// 1<<0 the name is exported -// 1<<1 tag data follows the name -// 1<<2 pkgPath nameOff follows the name and tag -// 1<<3 the name is of an embedded (a.k.a. anonymous) field -// -// Following that, there is a varint-encoded length of the name, -// followed by the name itself. -// -// If tag data is present, it also has a varint-encoded length -// followed by the tag itself. -// -// If the import path follows, then 4 bytes at the end of -// the data form a nameOff. The import path is only set for concrete -// methods that are defined in a different package than their type. -// -// If a name starts with "*", then the exported bit represents -// whether the pointed to type is exported. -// -// Note: this encoding must match here and in: -// cmd/compile/internal/reflectdata/reflect.go -// cmd/link/internal/ld/decodesym.go - -type Name struct { - Bytes *byte -} - -// DataChecked does pointer arithmetic on n's Bytes, and that arithmetic is asserted to -// be safe for the reason in whySafe (which can appear in a backtrace, etc.) -func (n Name) DataChecked(off int, whySafe string) *byte { - return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), whySafe)) -} - -// Data does pointer arithmetic on n's Bytes, and that arithmetic is asserted to -// be safe because the runtime made the call (other packages use DataChecked) -func (n Name) Data(off int) *byte { - return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), "the runtime doesn't need to give you a reason")) -} - -// IsExported returns "is n exported?" -func (n Name) IsExported() bool { - return (*n.Bytes)&(1<<0) != 0 -} - -// HasTag returns true iff there is tag data following this name -func (n Name) HasTag() bool { - return (*n.Bytes)&(1<<1) != 0 -} - -// IsEmbedded returns true iff n is embedded (an anonymous field). -func (n Name) IsEmbedded() bool { - return (*n.Bytes)&(1<<3) != 0 -} - -// ReadVarint parses a varint as encoded by encoding/binary. -// It returns the number of encoded bytes and the encoded value. -func (n Name) ReadVarint(off int) (int, int) { - v := 0 - for i := 0; ; i++ { - x := *n.DataChecked(off+i, "read varint") - v += int(x&0x7f) << (7 * i) - if x&0x80 == 0 { - return i + 1, v - } - } -} - -// IsBlank indicates whether n is "_". -func (n Name) IsBlank() bool { - if n.Bytes == nil { - return false - } - _, l := n.ReadVarint(1) - return l == 1 && *n.Data(2) == '_' -} - -// writeVarint writes n to buf in varint form. Returns the -// number of bytes written. n must be nonnegative. -// Writes at most 10 bytes. -func writeVarint(buf []byte, n int) int { - for i := 0; ; i++ { - b := byte(n & 0x7f) - n >>= 7 - if n == 0 { - buf[i] = b - return i + 1 - } - buf[i] = b | 0x80 - } -} - -// Name returns the tag string for n, or empty if there is none. -func (n Name) Name() string { - if n.Bytes == nil { - return "" - } - i, l := n.ReadVarint(1) - return unsafe.String(n.DataChecked(1+i, "non-empty string"), l) -} - -// Tag returns the tag string for n, or empty if there is none. -func (n Name) Tag() string { - if !n.HasTag() { - return "" - } - i, l := n.ReadVarint(1) - i2, l2 := n.ReadVarint(1 + i + l) - return unsafe.String(n.DataChecked(1+i+l+i2, "non-empty string"), l2) -} - -func NewName(n, tag string, exported, embedded bool) Name { - if len(n) >= 1<<29 { - panic("abi.NewName: name too long: " + n[:1024] + "...") - } - if len(tag) >= 1<<29 { - panic("abi.NewName: tag too long: " + tag[:1024] + "...") - } - var nameLen [10]byte - var tagLen [10]byte - nameLenLen := writeVarint(nameLen[:], len(n)) - tagLenLen := writeVarint(tagLen[:], len(tag)) - - var bits byte - l := 1 + nameLenLen + len(n) - if exported { - bits |= 1 << 0 - } - if len(tag) > 0 { - l += tagLenLen + len(tag) - bits |= 1 << 1 - } - if embedded { - bits |= 1 << 3 - } - - b := make([]byte, l) - b[0] = bits - copy(b[1:], nameLen[:nameLenLen]) - copy(b[1+nameLenLen:], n) - if len(tag) > 0 { - tb := b[1+nameLenLen+len(n):] - copy(tb, tagLen[:tagLenLen]) - copy(tb[tagLenLen:], tag) - } - - return Name{Bytes: &b[0]} -} diff --git a/contrib/go/_std_1.22/src/internal/abi/ya.make b/contrib/go/_std_1.22/src/internal/abi/ya.make deleted file mode 100644 index 62a84b9fc36e..000000000000 --- a/contrib/go/_std_1.22/src/internal/abi/ya.make +++ /dev/null @@ -1,31 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - abi.go - abi_arm64.go - abi_test.s - compiletype.go - funcpc.go - map.go - stack.go - stub.s - switch.go - symtab.go - type.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - abi.go - abi_amd64.go - abi_test.s - compiletype.go - funcpc.go - map.go - stack.go - stub.s - switch.go - symtab.go - type.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/buildcfg/cfg.go b/contrib/go/_std_1.22/src/internal/buildcfg/cfg.go deleted file mode 100644 index 8b97a653d773..000000000000 --- a/contrib/go/_std_1.22/src/internal/buildcfg/cfg.go +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package buildcfg provides access to the build configuration -// described by the current environment. It is for use by build tools -// such as cmd/go or cmd/compile and for setting up go/build's Default context. -// -// Note that it does NOT provide access to the build configuration used to -// build the currently-running binary. For that, use runtime.GOOS etc -// as well as internal/goexperiment. -package buildcfg - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - "strconv" - "strings" -) - -var ( - GOROOT = runtime.GOROOT() // cached for efficiency - GOARCH = envOr("GOARCH", defaultGOARCH) - GOOS = envOr("GOOS", defaultGOOS) - GO386 = envOr("GO386", defaultGO386) - GOAMD64 = goamd64() - GOARM = goarm() - GOMIPS = gomips() - GOMIPS64 = gomips64() - GOPPC64 = goppc64() - GOWASM = gowasm() - ToolTags = toolTags() - GO_LDSO = defaultGO_LDSO - Version = version -) - -// Error is one of the errors found (if any) in the build configuration. -var Error error - -// Check exits the program with a fatal error if Error is non-nil. -func Check() { - if Error != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), Error) - os.Exit(2) - } -} - -func envOr(key, value string) string { - if x := os.Getenv(key); x != "" { - return x - } - return value -} - -func goamd64() int { - switch v := envOr("GOAMD64", defaultGOAMD64); v { - case "v1": - return 1 - case "v2": - return 2 - case "v3": - return 3 - case "v4": - return 4 - } - Error = fmt.Errorf("invalid GOAMD64: must be v1, v2, v3, v4") - return int(defaultGOAMD64[len("v")] - '0') -} - -type goarmFeatures struct { - Version int - SoftFloat bool -} - -func (g goarmFeatures) String() string { - armStr := strconv.Itoa(g.Version) - if g.SoftFloat { - armStr += ",softfloat" - } else { - armStr += ",hardfloat" - } - return armStr -} - -func goarm() (g goarmFeatures) { - const ( - softFloatOpt = ",softfloat" - hardFloatOpt = ",hardfloat" - ) - def := defaultGOARM - if GOOS == "android" && GOARCH == "arm" { - // Android arm devices always support GOARM=7. - def = "7" - } - v := envOr("GOARM", def) - - floatSpecified := false - if strings.HasSuffix(v, softFloatOpt) { - g.SoftFloat = true - floatSpecified = true - v = v[:len(v)-len(softFloatOpt)] - } - if strings.HasSuffix(v, hardFloatOpt) { - floatSpecified = true - v = v[:len(v)-len(hardFloatOpt)] - } - - switch v { - case "5": - g.Version = 5 - case "6": - g.Version = 6 - case "7": - g.Version = 7 - default: - Error = fmt.Errorf("invalid GOARM: must start with 5, 6, or 7, and may optionally end in either %q or %q", hardFloatOpt, softFloatOpt) - g.Version = int(def[0] - '0') - } - - // 5 defaults to softfloat. 6 and 7 default to hardfloat. - if !floatSpecified && g.Version == 5 { - g.SoftFloat = true - } - return -} - -func gomips() string { - switch v := envOr("GOMIPS", defaultGOMIPS); v { - case "hardfloat", "softfloat": - return v - } - Error = fmt.Errorf("invalid GOMIPS: must be hardfloat, softfloat") - return defaultGOMIPS -} - -func gomips64() string { - switch v := envOr("GOMIPS64", defaultGOMIPS64); v { - case "hardfloat", "softfloat": - return v - } - Error = fmt.Errorf("invalid GOMIPS64: must be hardfloat, softfloat") - return defaultGOMIPS64 -} - -func goppc64() int { - switch v := envOr("GOPPC64", defaultGOPPC64); v { - case "power8": - return 8 - case "power9": - return 9 - case "power10": - return 10 - } - Error = fmt.Errorf("invalid GOPPC64: must be power8, power9, power10") - return int(defaultGOPPC64[len("power")] - '0') -} - -type gowasmFeatures struct { - SatConv bool - SignExt bool -} - -func (f gowasmFeatures) String() string { - var flags []string - if f.SatConv { - flags = append(flags, "satconv") - } - if f.SignExt { - flags = append(flags, "signext") - } - return strings.Join(flags, ",") -} - -func gowasm() (f gowasmFeatures) { - for _, opt := range strings.Split(envOr("GOWASM", ""), ",") { - switch opt { - case "satconv": - f.SatConv = true - case "signext": - f.SignExt = true - case "": - // ignore - default: - Error = fmt.Errorf("invalid GOWASM: no such feature %q", opt) - } - } - return -} - -func Getgoextlinkenabled() string { - return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED) -} - -func toolTags() []string { - tags := experimentTags() - tags = append(tags, gogoarchTags()...) - return tags -} - -func experimentTags() []string { - var list []string - // For each experiment that has been enabled in the toolchain, define a - // build tag with the same name but prefixed by "goexperiment." which can be - // used for compiling alternative files for the experiment. This allows - // changes for the experiment, like extra struct fields in the runtime, - // without affecting the base non-experiment code at all. - for _, exp := range Experiment.Enabled() { - list = append(list, "goexperiment."+exp) - } - return list -} - -// GOGOARCH returns the name and value of the GO$GOARCH setting. -// For example, if GOARCH is "amd64" it might return "GOAMD64", "v2". -func GOGOARCH() (name, value string) { - switch GOARCH { - case "386": - return "GO386", GO386 - case "amd64": - return "GOAMD64", fmt.Sprintf("v%d", GOAMD64) - case "arm": - return "GOARM", GOARM.String() - case "mips", "mipsle": - return "GOMIPS", GOMIPS - case "mips64", "mips64le": - return "GOMIPS64", GOMIPS64 - case "ppc64", "ppc64le": - return "GOPPC64", fmt.Sprintf("power%d", GOPPC64) - case "wasm": - return "GOWASM", GOWASM.String() - } - return "", "" -} - -func gogoarchTags() []string { - switch GOARCH { - case "386": - return []string{GOARCH + "." + GO386} - case "amd64": - var list []string - for i := 1; i <= GOAMD64; i++ { - list = append(list, fmt.Sprintf("%s.v%d", GOARCH, i)) - } - return list - case "arm": - var list []string - for i := 5; i <= GOARM.Version; i++ { - list = append(list, fmt.Sprintf("%s.%d", GOARCH, i)) - } - return list - case "mips", "mipsle": - return []string{GOARCH + "." + GOMIPS} - case "mips64", "mips64le": - return []string{GOARCH + "." + GOMIPS64} - case "ppc64", "ppc64le": - var list []string - for i := 8; i <= GOPPC64; i++ { - list = append(list, fmt.Sprintf("%s.power%d", GOARCH, i)) - } - return list - case "wasm": - var list []string - if GOWASM.SatConv { - list = append(list, GOARCH+".satconv") - } - if GOWASM.SignExt { - list = append(list, GOARCH+".signext") - } - return list - } - return nil -} diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_generic.go b/contrib/go/_std_1.22/src/internal/bytealg/compare_generic.go deleted file mode 100644 index b04e2750611b..000000000000 --- a/contrib/go/_std_1.22/src/internal/bytealg/compare_generic.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !386 && !amd64 && !s390x && !arm && !arm64 && !loong64 && !ppc64 && !ppc64le && !mips && !mipsle && !wasm && !mips64 && !mips64le && !riscv64 - -package bytealg - -import _ "unsafe" // for go:linkname - -func Compare(a, b []byte) int { - l := len(a) - if len(b) < l { - l = len(b) - } - if l == 0 || &a[0] == &b[0] { - goto samebytes - } - for i := 0; i < l; i++ { - c1, c2 := a[i], b[i] - if c1 < c2 { - return -1 - } - if c1 > c2 { - return +1 - } - } -samebytes: - if len(a) < len(b) { - return -1 - } - if len(a) > len(b) { - return +1 - } - return 0 -} - -//go:linkname runtime_cmpstring runtime.cmpstring -func runtime_cmpstring(a, b string) int { - l := len(a) - if len(b) < l { - l = len(b) - } - for i := 0; i < l; i++ { - c1, c2 := a[i], b[i] - if c1 < c2 { - return -1 - } - if c1 > c2 { - return +1 - } - } - if len(a) < len(b) { - return -1 - } - if len(a) > len(b) { - return +1 - } - return 0 -} diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_loong64.s b/contrib/go/_std_1.22/src/internal/bytealg/equal_loong64.s deleted file mode 100644 index a3ad5c1b35b6..000000000000 --- a/contrib/go/_std_1.22/src/internal/bytealg/equal_loong64.s +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go_asm.h" -#include "textflag.h" - -#define REGCTXT R29 - -// memequal(a, b unsafe.Pointer, size uintptr) bool -TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25 -#ifndef GOEXPERIMENT_regabiargs - MOVV a+0(FP), R4 - MOVV b+8(FP), R5 - MOVV size+16(FP), R6 -#endif - BEQ R4, R5, eq - ADDV R4, R6, R7 - PCALIGN $16 -loop: - BNE R4, R7, test - MOVV $1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R4, ret+24(FP) -#endif - RET -test: - MOVBU (R4), R9 - ADDV $1, R4 - MOVBU (R5), R10 - ADDV $1, R5 - BEQ R9, R10, loop - - MOVB R0, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R0, ret+24(FP) -#endif - RET -eq: - MOVV $1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R4, ret+24(FP) -#endif - RET - -// memequal_varlen(a, b unsafe.Pointer) bool -TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 -#ifndef GOEXPERIMENT_regabiargs - MOVV a+0(FP), R4 - MOVV b+8(FP), R5 -#endif - BEQ R4, R5, eq - MOVV 8(REGCTXT), R6 // compiler stores size at offset 8 in the closure - MOVV R4, 8(R3) - MOVV R5, 16(R3) - MOVV R6, 24(R3) - JAL runtime·memequal(SB) - MOVBU 32(R3), R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R4, ret+16(FP) -#endif - RET -eq: - MOVV $1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R4, ret+16(FP) -#endif - RET diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_loong64.s b/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_loong64.s deleted file mode 100644 index 03e066097312..000000000000 --- a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_loong64.s +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go_asm.h" -#include "textflag.h" - -TEXT ·IndexByte(SB),NOSPLIT,$0-40 -#ifndef GOEXPERIMENT_regabiargs - MOVV b_base+0(FP), R4 - MOVV b_len+8(FP), R5 - MOVBU c+24(FP), R7 // byte to find -#endif - // R4 = b_base - // R5 = b_len - // R6 = b_cap (unused) - // R7 = byte to find - AND $0xff, R7 - MOVV R4, R6 // store base for later - ADDV R4, R5 // end - ADDV $-1, R4 - - PCALIGN $16 -loop: - ADDV $1, R4 - BEQ R4, R5, notfound - MOVBU (R4), R8 - BNE R7, R8, loop - - SUBV R6, R4 // remove base -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, ret+32(FP) -#endif - RET - -notfound: - MOVV $-1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, ret+32(FP) -#endif - RET - -TEXT ·IndexByteString(SB),NOSPLIT,$0-32 -#ifndef GOEXPERIMENT_regabiargs - MOVV s_base+0(FP), R4 - MOVV s_len+8(FP), R5 - MOVBU c+16(FP), R6 // byte to find -#endif - // R4 = s_base - // R5 = s_len - // R6 = byte to find - MOVV R4, R7 // store base for later - ADDV R4, R5 // end - ADDV $-1, R4 - - PCALIGN $16 -loop: - ADDV $1, R4 - BEQ R4, R5, notfound - MOVBU (R4), R8 - BNE R6, R8, loop - - SUBV R7, R4 // remove base -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, ret+24(FP) -#endif - RET - -notfound: - MOVV $-1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, ret+24(FP) -#endif - RET diff --git a/contrib/go/_std_1.22/src/internal/bytealg/ya.make b/contrib/go/_std_1.22/src/internal/bytealg/ya.make deleted file mode 100644 index 522d0c3728bf..000000000000 --- a/contrib/go/_std_1.22/src/internal/bytealg/ya.make +++ /dev/null @@ -1,37 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - bytealg.go - compare_arm64.s - compare_native.go - count_arm64.s - count_native.go - equal_arm64.s - equal_generic.go - equal_native.go - index_arm64.go - index_arm64.s - index_native.go - indexbyte_arm64.s - indexbyte_native.go - lastindexbyte_generic.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - bytealg.go - compare_amd64.s - compare_native.go - count_amd64.s - count_native.go - equal_amd64.s - equal_generic.go - equal_native.go - index_amd64.go - index_amd64.s - index_native.go - indexbyte_amd64.s - indexbyte_native.go - lastindexbyte_generic.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8.go b/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8.go deleted file mode 100644 index ce55c07d058a..000000000000 --- a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package chacha8rand implements a pseudorandom generator -// based on ChaCha8. It is used by both runtime and math/rand/v2 -// and must have no dependencies. -package chacha8rand - -const ( - ctrInc = 4 // increment counter by 4 between block calls - ctrMax = 16 // reseed when counter reaches 16 - chunk = 32 // each chunk produced by block is 32 uint64s - reseed = 4 // reseed with 4 words -) - -// block is the chacha8rand block function. -func block(seed *[4]uint64, blocks *[32]uint64, counter uint32) - -// A State holds the state for a single random generator. -// It must be used from one goroutine at a time. -// If used by multiple goroutines at a time, the goroutines -// may see the same random values, but the code will not -// crash or cause out-of-bounds memory accesses. -type State struct { - buf [32]uint64 - seed [4]uint64 - i uint32 - n uint32 - c uint32 -} - -// Next returns the next random value, along with a boolean -// indicating whether one was available. -// If one is not available, the caller should call Refill -// and then repeat the call to Next. -// -// Next is //go:nosplit to allow its use in the runtime -// with per-m data without holding the per-m lock. -//go:nosplit -func (s *State) Next() (uint64, bool) { - i := s.i - if i >= s.n { - return 0, false - } - s.i = i + 1 - return s.buf[i&31], true // i&31 eliminates bounds check -} - -// Init seeds the State with the given seed value. -func (s *State) Init(seed [32]byte) { - s.Init64([4]uint64{ - leUint64(seed[0*8:]), - leUint64(seed[1*8:]), - leUint64(seed[2*8:]), - leUint64(seed[3*8:]), - }) -} - -// Init64 seeds the state with the given seed value. -func (s *State) Init64(seed [4]uint64) { - s.seed = seed - block(&s.seed, &s.buf, 0) - s.c = 0 - s.i = 0 - s.n = chunk -} - -// Refill refills the state with more random values. -// After a call to Refill, an immediate call to Next will succeed -// (unless multiple goroutines are incorrectly sharing a state). -func (s *State) Refill() { - s.c += ctrInc - if s.c == ctrMax { - // Reseed with generated uint64s for forward secrecy. - // Normally this is done immediately after computing a block, - // but we do it immediately before computing the next block, - // to allow a much smaller serialized state (just the seed plus offset). - // This gives a delayed benefit for the forward secrecy - // (you can reconstruct the recent past given a memory dump), - // which we deem acceptable in exchange for the reduced size. - s.seed[0] = s.buf[len(s.buf)-reseed+0] - s.seed[1] = s.buf[len(s.buf)-reseed+1] - s.seed[2] = s.buf[len(s.buf)-reseed+2] - s.seed[3] = s.buf[len(s.buf)-reseed+3] - s.c = 0 - } - block(&s.seed, &s.buf, s.c) - s.i = 0 - s.n = uint32(len(s.buf)) - if s.c == ctrMax-ctrInc { - s.n = uint32(len(s.buf)) - reseed - } -} - -// Reseed reseeds the state with new random values. -// After a call to Reseed, any previously returned random values -// have been erased from the memory of the state and cannot be -// recovered. -func (s *State) Reseed() { - var seed [4]uint64 - for i := range seed { - for { - x, ok := s.Next() - if ok { - seed[i] = x - break - } - s.Refill() - } - } - s.Init64(seed) -} - -// Marshal marshals the state into a byte slice. -// Marshal and Unmarshal are functions, not methods, -// so that they will not be linked into the runtime -// when it uses the State struct, since the runtime -// does not need these. -func Marshal(s *State) []byte { - data := make([]byte, 6*8) - copy(data, "chacha8:") - used := (s.c/ctrInc)*chunk + s.i - bePutUint64(data[1*8:], uint64(used)) - for i, seed := range s.seed { - lePutUint64(data[(2+i)*8:], seed) - } - return data -} - -type errUnmarshalChaCha8 struct{} - -func (*errUnmarshalChaCha8) Error() string { - return "invalid ChaCha8 encoding" -} - -// Unmarshal unmarshals the state from a byte slice. -func Unmarshal(s *State, data []byte) error { - if len(data) != 6*8 || string(data[:8]) != "chacha8:" { - return new(errUnmarshalChaCha8) - } - used := beUint64(data[1*8:]) - if used > (ctrMax/ctrInc)*chunk-reseed { - return new(errUnmarshalChaCha8) - } - for i := range s.seed { - s.seed[i] = leUint64(data[(2+i)*8:]) - } - s.c = ctrInc * (uint32(used) / chunk) - block(&s.seed, &s.buf, s.c) - s.i = uint32(used) % chunk - s.n = chunk - if s.c == ctrMax-ctrInc { - s.n = chunk - reseed - } - return nil -} - -// binary.bigEndian.Uint64, copied to avoid dependency -func beUint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 -} - -// binary.bigEndian.PutUint64, copied to avoid dependency -func bePutUint64(b []byte, v uint64) { - _ = b[7] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 56) - b[1] = byte(v >> 48) - b[2] = byte(v >> 40) - b[3] = byte(v >> 32) - b[4] = byte(v >> 24) - b[5] = byte(v >> 16) - b[6] = byte(v >> 8) - b[7] = byte(v) -} - -// binary.littleEndian.Uint64, copied to avoid dependency -func leUint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 -} - -// binary.littleEndian.PutUint64, copied to avoid dependency -func lePutUint64(b []byte, v uint64) { - _ = b[7] // early bounds check to guarantee safety of writes below - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) - b[4] = byte(v >> 32) - b[5] = byte(v >> 40) - b[6] = byte(v >> 48) - b[7] = byte(v >> 56) -} diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/ya.make b/contrib/go/_std_1.22/src/internal/chacha8rand/ya.make deleted file mode 100644 index c70335c29003..000000000000 --- a/contrib/go/_std_1.22/src/internal/chacha8rand/ya.make +++ /dev/null @@ -1,15 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - chacha8.go - chacha8_arm64.s - chacha8_generic.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - chacha8.go - chacha8_amd64.s - chacha8_generic.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/coverage/rtcov/rtcov.go b/contrib/go/_std_1.22/src/internal/coverage/rtcov/rtcov.go deleted file mode 100644 index bbb93acced7d..000000000000 --- a/contrib/go/_std_1.22/src/internal/coverage/rtcov/rtcov.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rtcov - -// This package contains types whose structure is shared between -// the runtime package and the "runtime/coverage" package. - -// CovMetaBlob is a container for holding the meta-data symbol (an -// RODATA variable) for an instrumented Go package. Here "p" points to -// the symbol itself, "len" is the length of the sym in bytes, and -// "hash" is an md5sum for the sym computed by the compiler. When -// the init function for a coverage-instrumented package executes, it -// will make a call into the runtime which will create a covMetaBlob -// object for the package and chain it onto a global list. -type CovMetaBlob struct { - P *byte - Len uint32 - Hash [16]byte - PkgPath string - PkgID int - CounterMode uint8 // coverage.CounterMode - CounterGranularity uint8 // coverage.CounterGranularity -} - -// CovCounterBlob is a container for encapsulating a counter section -// (BSS variable) for an instrumented Go module. Here "counters" -// points to the counter payload and "len" is the number of uint32 -// entries in the section. -type CovCounterBlob struct { - Counters *uint32 - Len uint64 -} diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu.go b/contrib/go/_std_1.22/src/internal/cpu/cpu.go deleted file mode 100644 index d794e53ceeef..000000000000 --- a/contrib/go/_std_1.22/src/internal/cpu/cpu.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package cpu implements processor feature detection -// used by the Go standard library. -package cpu - -// DebugOptions is set to true by the runtime if the OS supports reading -// GODEBUG early in runtime startup. -// This should not be changed after it is initialized. -var DebugOptions bool - -// CacheLinePad is used to pad structs to avoid false sharing. -type CacheLinePad struct{ _ [CacheLinePadSize]byte } - -// CacheLineSize is the CPU's assumed cache line size. -// There is currently no runtime detection of the real cache line size -// so we use the constant per GOARCH CacheLinePadSize as an approximation. -var CacheLineSize uintptr = CacheLinePadSize - -// The booleans in X86 contain the correspondingly named cpuid feature bit. -// HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers -// in addition to the cpuid feature bit being set. -// The struct is padded to avoid false sharing. -var X86 struct { - _ CacheLinePad - HasAES bool - HasADX bool - HasAVX bool - HasAVX2 bool - HasAVX512F bool - HasAVX512BW bool - HasAVX512VL bool - HasBMI1 bool - HasBMI2 bool - HasERMS bool - HasFMA bool - HasOSXSAVE bool - HasPCLMULQDQ bool - HasPOPCNT bool - HasRDTSCP bool - HasSHA bool - HasSSE3 bool - HasSSSE3 bool - HasSSE41 bool - HasSSE42 bool - _ CacheLinePad -} - -// The booleans in ARM contain the correspondingly named cpu feature bit. -// The struct is padded to avoid false sharing. -var ARM struct { - _ CacheLinePad - HasVFPv4 bool - HasIDIVA bool - HasV7Atomics bool - _ CacheLinePad -} - -// The booleans in ARM64 contain the correspondingly named cpu feature bit. -// The struct is padded to avoid false sharing. -var ARM64 struct { - _ CacheLinePad - HasAES bool - HasPMULL bool - HasSHA1 bool - HasSHA2 bool - HasSHA512 bool - HasCRC32 bool - HasATOMICS bool - HasCPUID bool - IsNeoverse bool - _ CacheLinePad -} - -var MIPS64X struct { - _ CacheLinePad - HasMSA bool // MIPS SIMD architecture - _ CacheLinePad -} - -// For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00, -// since there are no optional categories. There are some exceptions that also -// require kernel support to work (darn, scv), so there are feature bits for -// those as well. The minimum processor requirement is POWER8 (ISA 2.07). -// The struct is padded to avoid false sharing. -var PPC64 struct { - _ CacheLinePad - HasDARN bool // Hardware random number generator (requires kernel enablement) - HasSCV bool // Syscall vectored (requires kernel enablement) - IsPOWER8 bool // ISA v2.07 (POWER8) - IsPOWER9 bool // ISA v3.00 (POWER9) - IsPOWER10 bool // ISA v3.1 (POWER10) - _ CacheLinePad -} - -var S390X struct { - _ CacheLinePad - HasZARCH bool // z architecture mode is active [mandatory] - HasSTFLE bool // store facility list extended [mandatory] - HasLDISP bool // long (20-bit) displacements [mandatory] - HasEIMM bool // 32-bit immediates [mandatory] - HasDFP bool // decimal floating point - HasETF3EH bool // ETF-3 enhanced - HasMSA bool // message security assist (CPACF) - HasAES bool // KM-AES{128,192,256} functions - HasAESCBC bool // KMC-AES{128,192,256} functions - HasAESCTR bool // KMCTR-AES{128,192,256} functions - HasAESGCM bool // KMA-GCM-AES{128,192,256} functions - HasGHASH bool // KIMD-GHASH function - HasSHA1 bool // K{I,L}MD-SHA-1 functions - HasSHA256 bool // K{I,L}MD-SHA-256 functions - HasSHA512 bool // K{I,L}MD-SHA-512 functions - HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions - HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. - HasVXE bool // vector-enhancements facility 1 - HasKDSA bool // elliptic curve functions - HasECDSA bool // NIST curves - HasEDDSA bool // Edwards curves - _ CacheLinePad -} - -// Initialize examines the processor and sets the relevant variables above. -// This is called by the runtime package early in program initialization, -// before normal init functions are run. env is set by runtime if the OS supports -// cpu feature options in GODEBUG. -func Initialize(env string) { - doinit() - processOptions(env) -} - -// options contains the cpu debug options that can be used in GODEBUG. -// Options are arch dependent and are added by the arch specific doinit functions. -// Features that are mandatory for the specific GOARCH should not be added to options -// (e.g. SSE2 on amd64). -var options []option - -// Option names should be lower case. e.g. avx instead of AVX. -type option struct { - Name string - Feature *bool - Specified bool // whether feature value was specified in GODEBUG - Enable bool // whether feature should be enabled -} - -// processOptions enables or disables CPU feature values based on the parsed env string. -// The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2... -// where feature names is one of the architecture specific list stored in the -// cpu packages options variable and values are either 'on' or 'off'. -// If env contains cpu.all=off then all cpu features referenced through the options -// variable are disabled. Other feature names and values result in warning messages. -func processOptions(env string) { -field: - for env != "" { - field := "" - i := indexByte(env, ',') - if i < 0 { - field, env = env, "" - } else { - field, env = env[:i], env[i+1:] - } - if len(field) < 4 || field[:4] != "cpu." { - continue - } - i = indexByte(field, '=') - if i < 0 { - print("GODEBUG: no value specified for \"", field, "\"\n") - continue - } - key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" - - var enable bool - switch value { - case "on": - enable = true - case "off": - enable = false - default: - print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n") - continue field - } - - if key == "all" { - for i := range options { - options[i].Specified = true - options[i].Enable = enable - } - continue field - } - - for i := range options { - if options[i].Name == key { - options[i].Specified = true - options[i].Enable = enable - continue field - } - } - - print("GODEBUG: unknown cpu feature \"", key, "\"\n") - } - - for _, o := range options { - if !o.Specified { - continue - } - - if o.Enable && !*o.Feature { - print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n") - continue - } - - *o.Feature = o.Enable - } -} - -// indexByte returns the index of the first instance of c in s, -// or -1 if c is not present in s. -// indexByte is semantically the same as [strings.IndexByte]. -// We copy this function because "internal/cpu" should not have external dependencies. -func indexByte(s string, c byte) int { - for i := 0; i < len(s); i++ { - if s[i] == c { - return i - } - } - return -1 -} diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_darwin.go b/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_darwin.go deleted file mode 100644 index 60beadddbb1d..000000000000 --- a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_darwin.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build arm64 && darwin && !ios - -package cpu - -func osInit() { - ARM64.HasATOMICS = sysctlEnabled([]byte("hw.optional.armv8_1_atomics\x00")) - ARM64.HasCRC32 = sysctlEnabled([]byte("hw.optional.armv8_crc32\x00")) - ARM64.HasSHA512 = sysctlEnabled([]byte("hw.optional.armv8_2_sha512\x00")) - - // There are no hw.optional sysctl values for the below features on Mac OS 11.0 - // to detect their supported state dynamically. Assume the CPU features that - // Apple Silicon M1 supports to be available as a minimal set of features - // to all Go programs running on darwin/arm64. - ARM64.HasAES = true - ARM64.HasPMULL = true - ARM64.HasSHA1 = true - ARM64.HasSHA2 = true -} - -//go:noescape -func getsysctlbyname(name []byte) (int32, int32) - -func sysctlEnabled(name []byte) bool { - ret, value := getsysctlbyname(name) - if ret < 0 { - return false - } - return value > 0 -} diff --git a/contrib/go/_std_1.22/src/internal/cpu/ya.make b/contrib/go/_std_1.22/src/internal/cpu/ya.make deleted file mode 100644 index b9d0c3e3a331..000000000000 --- a/contrib/go/_std_1.22/src/internal/cpu/ya.make +++ /dev/null @@ -1,29 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - cpu.go - cpu.s - cpu_arm64.go - cpu_arm64.s - cpu_arm64_darwin.go - cpu_no_name.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - cpu.go - cpu.s - cpu_x86.go - cpu_x86.s - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - cpu.go - cpu.s - cpu_arm64.go - cpu_arm64.s - cpu_arm64_hwcap.go - cpu_arm64_linux.go - cpu_no_name.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/fmtsort/sort.go b/contrib/go/_std_1.22/src/internal/fmtsort/sort.go deleted file mode 100644 index 278a89bd75d4..000000000000 --- a/contrib/go/_std_1.22/src/internal/fmtsort/sort.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package fmtsort provides a general stable ordering mechanism -// for maps, on behalf of the fmt and text/template packages. -// It is not guaranteed to be efficient and works only for types -// that are valid map keys. -package fmtsort - -import ( - "reflect" - "sort" -) - -// Note: Throughout this package we avoid calling reflect.Value.Interface as -// it is not always legal to do so and it's easier to avoid the issue than to face it. - -// SortedMap represents a map's keys and values. The keys and values are -// aligned in index order: Value[i] is the value in the map corresponding to Key[i]. -type SortedMap struct { - Key []reflect.Value - Value []reflect.Value -} - -func (o *SortedMap) Len() int { return len(o.Key) } -func (o *SortedMap) Less(i, j int) bool { return compare(o.Key[i], o.Key[j]) < 0 } -func (o *SortedMap) Swap(i, j int) { - o.Key[i], o.Key[j] = o.Key[j], o.Key[i] - o.Value[i], o.Value[j] = o.Value[j], o.Value[i] -} - -// Sort accepts a map and returns a SortedMap that has the same keys and -// values but in a stable sorted order according to the keys, modulo issues -// raised by unorderable key values such as NaNs. -// -// The ordering rules are more general than with Go's < operator: -// -// - when applicable, nil compares low -// - ints, floats, and strings order by < -// - NaN compares less than non-NaN floats -// - bool compares false before true -// - complex compares real, then imag -// - pointers compare by machine address -// - channel values compare by machine address -// - structs compare each field in turn -// - arrays compare each element in turn. -// Otherwise identical arrays compare by length. -// - interface values compare first by reflect.Type describing the concrete type -// and then by concrete value as described in the previous rules. -func Sort(mapValue reflect.Value) *SortedMap { - if mapValue.Type().Kind() != reflect.Map { - return nil - } - // Note: this code is arranged to not panic even in the presence - // of a concurrent map update. The runtime is responsible for - // yelling loudly if that happens. See issue 33275. - n := mapValue.Len() - key := make([]reflect.Value, 0, n) - value := make([]reflect.Value, 0, n) - iter := mapValue.MapRange() - for iter.Next() { - key = append(key, iter.Key()) - value = append(value, iter.Value()) - } - sorted := &SortedMap{ - Key: key, - Value: value, - } - sort.Stable(sorted) - return sorted -} - -// compare compares two values of the same type. It returns -1, 0, 1 -// according to whether a > b (1), a == b (0), or a < b (-1). -// If the types differ, it returns -1. -// See the comment on Sort for the comparison rules. -func compare(aVal, bVal reflect.Value) int { - aType, bType := aVal.Type(), bVal.Type() - if aType != bType { - return -1 // No good answer possible, but don't return 0: they're not equal. - } - switch aVal.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - a, b := aVal.Int(), bVal.Int() - switch { - case a < b: - return -1 - case a > b: - return 1 - default: - return 0 - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - a, b := aVal.Uint(), bVal.Uint() - switch { - case a < b: - return -1 - case a > b: - return 1 - default: - return 0 - } - case reflect.String: - a, b := aVal.String(), bVal.String() - switch { - case a < b: - return -1 - case a > b: - return 1 - default: - return 0 - } - case reflect.Float32, reflect.Float64: - return floatCompare(aVal.Float(), bVal.Float()) - case reflect.Complex64, reflect.Complex128: - a, b := aVal.Complex(), bVal.Complex() - if c := floatCompare(real(a), real(b)); c != 0 { - return c - } - return floatCompare(imag(a), imag(b)) - case reflect.Bool: - a, b := aVal.Bool(), bVal.Bool() - switch { - case a == b: - return 0 - case a: - return 1 - default: - return -1 - } - case reflect.Pointer, reflect.UnsafePointer: - a, b := aVal.Pointer(), bVal.Pointer() - switch { - case a < b: - return -1 - case a > b: - return 1 - default: - return 0 - } - case reflect.Chan: - if c, ok := nilCompare(aVal, bVal); ok { - return c - } - ap, bp := aVal.Pointer(), bVal.Pointer() - switch { - case ap < bp: - return -1 - case ap > bp: - return 1 - default: - return 0 - } - case reflect.Struct: - for i := 0; i < aVal.NumField(); i++ { - if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 { - return c - } - } - return 0 - case reflect.Array: - for i := 0; i < aVal.Len(); i++ { - if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 { - return c - } - } - return 0 - case reflect.Interface: - if c, ok := nilCompare(aVal, bVal); ok { - return c - } - c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type())) - if c != 0 { - return c - } - return compare(aVal.Elem(), bVal.Elem()) - default: - // Certain types cannot appear as keys (maps, funcs, slices), but be explicit. - panic("bad type in compare: " + aType.String()) - } -} - -// nilCompare checks whether either value is nil. If not, the boolean is false. -// If either value is nil, the boolean is true and the integer is the comparison -// value. The comparison is defined to be 0 if both are nil, otherwise the one -// nil value compares low. Both arguments must represent a chan, func, -// interface, map, pointer, or slice. -func nilCompare(aVal, bVal reflect.Value) (int, bool) { - if aVal.IsNil() { - if bVal.IsNil() { - return 0, true - } - return -1, true - } - if bVal.IsNil() { - return 1, true - } - return 0, false -} - -// floatCompare compares two floating-point values. NaNs compare low. -func floatCompare(a, b float64) int { - switch { - case isNaN(a): - return -1 // No good answer if b is a NaN so don't bother checking. - case isNaN(b): - return 1 - case a < b: - return -1 - case a > b: - return 1 - } - return 0 -} - -func isNaN(a float64) bool { - return a != a -} diff --git a/contrib/go/_std_1.22/src/internal/goarch/ya.make b/contrib/go/_std_1.22/src/internal/goarch/ya.make deleted file mode 100644 index 53ba46790f9e..000000000000 --- a/contrib/go/_std_1.22/src/internal/goarch/ya.make +++ /dev/null @@ -1,15 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - goarch.go - goarch_arm64.go - zgoarch_arm64.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - goarch.go - goarch_amd64.go - zgoarch_amd64.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_off.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_off.go deleted file mode 100644 index 72c702f9e706..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_off.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.allocheaders - -package goexperiment - -const AllocHeaders = false -const AllocHeadersInt = 0 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_on.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_on.go deleted file mode 100644 index f9f2965fe2e4..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_on.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.allocheaders - -package goexperiment - -const AllocHeaders = true -const AllocHeadersInt = 1 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_off.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_off.go deleted file mode 100644 index 2f9c8269d891..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_off.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.exectracer2 -// +build !goexperiment.exectracer2 - -package goexperiment - -const ExecTracer2 = false -const ExecTracer2Int = 0 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_on.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_on.go deleted file mode 100644 index f94a29247fac..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_on.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.exectracer2 -// +build goexperiment.exectracer2 - -package goexperiment - -const ExecTracer2 = true -const ExecTracer2Int = 1 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_off.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_off.go deleted file mode 100644 index 142be47d963d..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_off.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.pagetrace - -package goexperiment - -const PageTrace = false -const PageTraceInt = 0 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_on.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_on.go deleted file mode 100644 index f3b161478901..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_on.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.pagetrace - -package goexperiment - -const PageTrace = true -const PageTraceInt = 1 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/ya.make b/contrib/go/_std_1.22/src/internal/goexperiment/ya.make deleted file mode 100644 index 1c716226c606..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/ya.make +++ /dev/null @@ -1,24 +0,0 @@ -GO_LIBRARY() -IF (TRUE) - SRCS( - exp_allocheaders_off.go - exp_arenas_off.go - exp_boringcrypto_off.go - exp_cacheprog_off.go - exp_cgocheck2_off.go - exp_coverageredesign_off.go - exp_exectracer2_off.go - exp_fieldtrack_off.go - exp_heapminimum512kib_off.go - exp_loopvar_off.go - exp_newinliner_off.go - exp_pagetrace_off.go - exp_preemptibleloops_off.go - exp_rangefunc_off.go - exp_regabiargs_off.go - exp_regabiwrappers_off.go - exp_staticlockranking_off.go - flags.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/goos/ya.make b/contrib/go/_std_1.22/src/internal/goos/ya.make deleted file mode 100644 index 703feb1fbe86..000000000000 --- a/contrib/go/_std_1.22/src/internal/goos/ya.make +++ /dev/null @@ -1,21 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - goos.go - unix.go - zgoos_darwin.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - goos.go - unix.go - zgoos_linux.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - goos.go - nonunix.go - zgoos_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/intern/intern.go b/contrib/go/_std_1.22/src/internal/intern/intern.go deleted file mode 100644 index 2f97c2e66942..000000000000 --- a/contrib/go/_std_1.22/src/internal/intern/intern.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package intern lets you make smaller comparable values by boxing -// a larger comparable value (such as a 16 byte string header) down -// into a globally unique 8 byte pointer. -// -// The globally unique pointers are garbage collected with weak -// references and finalizers. This package hides that. -package intern - -import ( - "internal/godebug" - "runtime" - "sync" - "unsafe" -) - -// A Value pointer is the handle to an underlying comparable value. -// See func Get for how Value pointers may be used. -type Value struct { - _ [0]func() // prevent people from accidentally using value type as comparable - cmpVal any - // resurrected is guarded by mu (for all instances of Value). - // It is set true whenever v is synthesized from a uintptr. - resurrected bool -} - -// Get returns the comparable value passed to the Get func -// that returned v. -func (v *Value) Get() any { return v.cmpVal } - -// key is a key in our global value map. -// It contains type-specialized fields to avoid allocations -// when converting common types to empty interfaces. -type key struct { - s string - cmpVal any - // isString reports whether key contains a string. - // Without it, the zero value of key is ambiguous. - isString bool -} - -// keyFor returns a key to use with cmpVal. -func keyFor(cmpVal any) key { - if s, ok := cmpVal.(string); ok { - return key{s: s, isString: true} - } - return key{cmpVal: cmpVal} -} - -// Value returns a *Value built from k. -func (k key) Value() *Value { - if k.isString { - return &Value{cmpVal: k.s} - } - return &Value{cmpVal: k.cmpVal} -} - -var ( - // mu guards valMap, a weakref map of *Value by underlying value. - // It also guards the resurrected field of all *Values. - mu sync.Mutex - valMap = map[key]uintptr{} // to uintptr(*Value) - valSafe = safeMap() // non-nil in safe+leaky mode -) - -var intern = godebug.New("#intern") - -// safeMap returns a non-nil map if we're in safe-but-leaky mode, -// as controlled by GODEBUG=intern=leaky -func safeMap() map[key]*Value { - if intern.Value() == "leaky" { - return map[key]*Value{} - } - return nil -} - -// Get returns a pointer representing the comparable value cmpVal. -// -// The returned pointer will be the same for Get(v) and Get(v2) -// if and only if v == v2, and can be used as a map key. -func Get(cmpVal any) *Value { - return get(keyFor(cmpVal)) -} - -// GetByString is identical to Get, except that it is specialized for strings. -// This avoids an allocation from putting a string into an interface{} -// to pass as an argument to Get. -func GetByString(s string) *Value { - return get(key{s: s, isString: true}) -} - -// We play unsafe games that violate Go's rules (and assume a non-moving -// collector). So we quiet Go here. -// See the comment below Get for more implementation details. -// -//go:nocheckptr -func get(k key) *Value { - mu.Lock() - defer mu.Unlock() - - var v *Value - if valSafe != nil { - v = valSafe[k] - } else if addr, ok := valMap[k]; ok { - v = (*Value)(unsafe.Pointer(addr)) - v.resurrected = true - } - if v != nil { - return v - } - v = k.Value() - if valSafe != nil { - valSafe[k] = v - } else { - // SetFinalizer before uintptr conversion (theoretical concern; - // see https://github.com/go4org/intern/issues/13) - runtime.SetFinalizer(v, finalize) - valMap[k] = uintptr(unsafe.Pointer(v)) - } - return v -} - -func finalize(v *Value) { - mu.Lock() - defer mu.Unlock() - if v.resurrected { - // We lost the race. Somebody resurrected it while we - // were about to finalize it. Try again next round. - v.resurrected = false - runtime.SetFinalizer(v, finalize) - return - } - delete(valMap, keyFor(v.cmpVal)) -} - -// Interning is simple if you don't require that unused values be -// garbage collectable. But we do require that; we don't want to be -// DOS vector. We do this by using a uintptr to hide the pointer from -// the garbage collector, and using a finalizer to eliminate the -// pointer when no other code is using it. -// -// The obvious implementation of this is to use a -// map[interface{}]uintptr-of-*interface{}, and set up a finalizer to -// delete from the map. Unfortunately, this is racy. Because pointers -// are being created in violation of Go's unsafety rules, it's -// possible to create a pointer to a value concurrently with the GC -// concluding that the value can be collected. There are other races -// that break the equality invariant as well, but the use-after-free -// will cause a runtime crash. -// -// To make this work, the finalizer needs to know that no references -// have been unsafely created since the finalizer was set up. To do -// this, values carry a "resurrected" sentinel, which gets set -// whenever a pointer is unsafely created. If the finalizer encounters -// the sentinel, it clears the sentinel and delays collection for one -// additional GC cycle, by re-installing itself as finalizer. This -// ensures that the unsafely created pointer is visible to the GC, and -// will correctly prevent collection. -// -// This technique does mean that interned values that get reused take -// at least 3 GC cycles to fully collect (1 to clear the sentinel, 1 -// to clean up the unsafe map, 1 to be actually deleted). -// -// @ianlancetaylor commented in -// https://github.com/golang/go/issues/41303#issuecomment-717401656 -// that it is possible to implement weak references in terms of -// finalizers without unsafe. Unfortunately, the approach he outlined -// does not work here, for two reasons. First, there is no way to -// construct a strong pointer out of a weak pointer; our map stores -// weak pointers, but we must return strong pointers to callers. -// Second, and more fundamentally, we must return not just _a_ strong -// pointer to callers, but _the same_ strong pointer to callers. In -// order to return _the same_ strong pointer to callers, we must track -// it, which is exactly what we cannot do with strong pointers. -// -// See https://github.com/inetaf/netaddr/issues/53 for more -// discussion, and https://github.com/go4org/intern/issues/2 for an -// illustration of the subtleties at play. diff --git a/contrib/go/_std_1.22/src/internal/intern/ya.make b/contrib/go/_std_1.22/src/internal/intern/ya.make deleted file mode 100644 index 2aa90abdbac8..000000000000 --- a/contrib/go/_std_1.22/src/internal/intern/ya.make +++ /dev/null @@ -1,7 +0,0 @@ -GO_LIBRARY() -IF (TRUE) - SRCS( - intern.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_fsync_darwin.go b/contrib/go/_std_1.22/src/internal/poll/fd_fsync_darwin.go deleted file mode 100644 index 731b7fd5bd65..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/fd_fsync_darwin.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package poll - -import ( - "internal/syscall/unix" - "syscall" -) - -// Fsync invokes SYS_FCNTL with SYS_FULLFSYNC because -// on OS X, SYS_FSYNC doesn't fully flush contents to disk. -// See Issue #26650 as well as the man page for fsync on OS X. -func (fd *FD) Fsync() error { - if err := fd.incref(); err != nil { - return err - } - defer fd.decref() - return ignoringEINTR(func() error { - _, err := unix.Fcntl(fd.Sysfd, syscall.F_FULLFSYNC, 0) - return err - }) -} diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_windows.go b/contrib/go/_std_1.22/src/internal/poll/fd_windows.go deleted file mode 100644 index 2095a6aa2927..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/fd_windows.go +++ /dev/null @@ -1,1331 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package poll - -import ( - "errors" - "internal/race" - "internal/syscall/windows" - "io" - "sync" - "syscall" - "unicode/utf16" - "unicode/utf8" - "unsafe" -) - -var ( - initErr error - ioSync uint64 -) - -// This package uses the SetFileCompletionNotificationModes Windows -// API to skip calling GetQueuedCompletionStatus if an IO operation -// completes synchronously. There is a known bug where -// SetFileCompletionNotificationModes crashes on some systems (see -// https://support.microsoft.com/kb/2568167 for details). - -var useSetFileCompletionNotificationModes bool // determines is SetFileCompletionNotificationModes is present and safe to use - -// checkSetFileCompletionNotificationModes verifies that -// SetFileCompletionNotificationModes Windows API is present -// on the system and is safe to use. -// See https://support.microsoft.com/kb/2568167 for details. -func checkSetFileCompletionNotificationModes() { - err := syscall.LoadSetFileCompletionNotificationModes() - if err != nil { - return - } - protos := [2]int32{syscall.IPPROTO_TCP, 0} - var buf [32]syscall.WSAProtocolInfo - len := uint32(unsafe.Sizeof(buf)) - n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len) - if err != nil { - return - } - for i := int32(0); i < n; i++ { - if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 { - return - } - } - useSetFileCompletionNotificationModes = true -} - -func init() { - var d syscall.WSAData - e := syscall.WSAStartup(uint32(0x202), &d) - if e != nil { - initErr = e - } - checkSetFileCompletionNotificationModes() -} - -// operation contains superset of data necessary to perform all async IO. -type operation struct { - // Used by IOCP interface, it must be first field - // of the struct, as our code rely on it. - o syscall.Overlapped - - // fields used by runtime.netpoll - runtimeCtx uintptr - mode int32 - errno int32 - qty uint32 - - // fields used only by net package - fd *FD - buf syscall.WSABuf - msg windows.WSAMsg - sa syscall.Sockaddr - rsa *syscall.RawSockaddrAny - rsan int32 - handle syscall.Handle - flags uint32 - bufs []syscall.WSABuf -} - -func (o *operation) InitBuf(buf []byte) { - o.buf.Len = uint32(len(buf)) - o.buf.Buf = nil - if len(buf) != 0 { - o.buf.Buf = &buf[0] - } -} - -func (o *operation) InitBufs(buf *[][]byte) { - if o.bufs == nil { - o.bufs = make([]syscall.WSABuf, 0, len(*buf)) - } else { - o.bufs = o.bufs[:0] - } - for _, b := range *buf { - if len(b) == 0 { - o.bufs = append(o.bufs, syscall.WSABuf{}) - continue - } - for len(b) > maxRW { - o.bufs = append(o.bufs, syscall.WSABuf{Len: maxRW, Buf: &b[0]}) - b = b[maxRW:] - } - if len(b) > 0 { - o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: &b[0]}) - } - } -} - -// ClearBufs clears all pointers to Buffers parameter captured -// by InitBufs, so it can be released by garbage collector. -func (o *operation) ClearBufs() { - for i := range o.bufs { - o.bufs[i].Buf = nil - } - o.bufs = o.bufs[:0] -} - -func (o *operation) InitMsg(p []byte, oob []byte) { - o.InitBuf(p) - o.msg.Buffers = &o.buf - o.msg.BufferCount = 1 - - o.msg.Name = nil - o.msg.Namelen = 0 - - o.msg.Flags = 0 - o.msg.Control.Len = uint32(len(oob)) - o.msg.Control.Buf = nil - if len(oob) != 0 { - o.msg.Control.Buf = &oob[0] - } -} - -// execIO executes a single IO operation o. It submits and cancels -// IO in the current thread for systems where Windows CancelIoEx API -// is available. Alternatively, it passes the request onto -// runtime netpoll and waits for completion or cancels request. -func execIO(o *operation, submit func(o *operation) error) (int, error) { - if o.fd.pd.runtimeCtx == 0 { - return 0, errors.New("internal error: polling on unsupported descriptor type") - } - - fd := o.fd - // Notify runtime netpoll about starting IO. - err := fd.pd.prepare(int(o.mode), fd.isFile) - if err != nil { - return 0, err - } - // Start IO. - err = submit(o) - switch err { - case nil: - // IO completed immediately - if o.fd.skipSyncNotif { - // No completion message will follow, so return immediately. - return int(o.qty), nil - } - // Need to get our completion message anyway. - case syscall.ERROR_IO_PENDING: - // IO started, and we have to wait for its completion. - err = nil - default: - return 0, err - } - // Wait for our request to complete. - err = fd.pd.wait(int(o.mode), fd.isFile) - if err == nil { - // All is good. Extract our IO results and return. - if o.errno != 0 { - err = syscall.Errno(o.errno) - // More data available. Return back the size of received data. - if err == syscall.ERROR_MORE_DATA || err == windows.WSAEMSGSIZE { - return int(o.qty), err - } - return 0, err - } - return int(o.qty), nil - } - // IO is interrupted by "close" or "timeout" - netpollErr := err - switch netpollErr { - case ErrNetClosing, ErrFileClosing, ErrDeadlineExceeded: - // will deal with those. - default: - panic("unexpected runtime.netpoll error: " + netpollErr.Error()) - } - // Cancel our request. - err = syscall.CancelIoEx(fd.Sysfd, &o.o) - // Assuming ERROR_NOT_FOUND is returned, if IO is completed. - if err != nil && err != syscall.ERROR_NOT_FOUND { - // TODO(brainman): maybe do something else, but panic. - panic(err) - } - // Wait for cancellation to complete. - fd.pd.waitCanceled(int(o.mode)) - if o.errno != 0 { - err = syscall.Errno(o.errno) - if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled - err = netpollErr - } - return 0, err - } - // We issued a cancellation request. But, it seems, IO operation succeeded - // before the cancellation request run. We need to treat the IO operation as - // succeeded (the bytes are actually sent/recv from network). - return int(o.qty), nil -} - -// FD is a file descriptor. The net and os packages embed this type in -// a larger type representing a network connection or OS file. -type FD struct { - // Lock sysfd and serialize access to Read and Write methods. - fdmu fdMutex - - // System file descriptor. Immutable until Close. - Sysfd syscall.Handle - - // Read operation. - rop operation - // Write operation. - wop operation - - // I/O poller. - pd pollDesc - - // Used to implement pread/pwrite. - l sync.Mutex - - // For console I/O. - lastbits []byte // first few bytes of the last incomplete rune in last write - readuint16 []uint16 // buffer to hold uint16s obtained with ReadConsole - readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8 - readbyteOffset int // readbyte[readOffset:] is yet to be consumed with file.Read - - // Semaphore signaled when file is closed. - csema uint32 - - skipSyncNotif bool - - // Whether this is a streaming descriptor, as opposed to a - // packet-based descriptor like a UDP socket. - IsStream bool - - // Whether a zero byte read indicates EOF. This is false for a - // message based socket connection. - ZeroReadIsEOF bool - - // Whether this is a file rather than a network socket. - isFile bool - - // The kind of this file. - kind fileKind -} - -// fileKind describes the kind of file. -type fileKind byte - -const ( - kindNet fileKind = iota - kindFile - kindConsole - kindPipe -) - -// logInitFD is set by tests to enable file descriptor initialization logging. -var logInitFD func(net string, fd *FD, err error) - -// Init initializes the FD. The Sysfd field should already be set. -// This can be called multiple times on a single FD. -// The net argument is a network name from the net package (e.g., "tcp"), -// or "file" or "console" or "dir". -// Set pollable to true if fd should be managed by runtime netpoll. -func (fd *FD) Init(net string, pollable bool) (string, error) { - if initErr != nil { - return "", initErr - } - - switch net { - case "file", "dir": - fd.kind = kindFile - case "console": - fd.kind = kindConsole - case "pipe": - fd.kind = kindPipe - case "tcp", "tcp4", "tcp6", - "udp", "udp4", "udp6", - "ip", "ip4", "ip6", - "unix", "unixgram", "unixpacket": - fd.kind = kindNet - default: - return "", errors.New("internal error: unknown network type " + net) - } - fd.isFile = fd.kind != kindNet - - var err error - if pollable { - // Only call init for a network socket. - // This means that we don't add files to the runtime poller. - // Adding files to the runtime poller can confuse matters - // if the user is doing their own overlapped I/O. - // See issue #21172. - // - // In general the code below avoids calling the execIO - // function for non-network sockets. If some method does - // somehow call execIO, then execIO, and therefore the - // calling method, will return an error, because - // fd.pd.runtimeCtx will be 0. - err = fd.pd.init(fd) - } - if logInitFD != nil { - logInitFD(net, fd, err) - } - if err != nil { - return "", err - } - if pollable && useSetFileCompletionNotificationModes { - // We do not use events, so we can skip them always. - flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE) - switch net { - case "tcp", "tcp4", "tcp6", - "udp", "udp4", "udp6": - flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS - } - err := syscall.SetFileCompletionNotificationModes(fd.Sysfd, flags) - if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 { - fd.skipSyncNotif = true - } - } - // Disable SIO_UDP_CONNRESET behavior. - // http://support.microsoft.com/kb/263823 - switch net { - case "udp", "udp4", "udp6": - ret := uint32(0) - flag := uint32(0) - size := uint32(unsafe.Sizeof(flag)) - err := syscall.WSAIoctl(fd.Sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) - if err != nil { - return "wsaioctl", err - } - } - fd.rop.mode = 'r' - fd.wop.mode = 'w' - fd.rop.fd = fd - fd.wop.fd = fd - fd.rop.runtimeCtx = fd.pd.runtimeCtx - fd.wop.runtimeCtx = fd.pd.runtimeCtx - return "", nil -} - -func (fd *FD) destroy() error { - if fd.Sysfd == syscall.InvalidHandle { - return syscall.EINVAL - } - // Poller may want to unregister fd in readiness notification mechanism, - // so this must be executed before fd.CloseFunc. - fd.pd.close() - var err error - switch fd.kind { - case kindNet: - // The net package uses the CloseFunc variable for testing. - err = CloseFunc(fd.Sysfd) - default: - err = syscall.CloseHandle(fd.Sysfd) - } - fd.Sysfd = syscall.InvalidHandle - runtime_Semrelease(&fd.csema) - return err -} - -// Close closes the FD. The underlying file descriptor is closed by -// the destroy method when there are no remaining references. -func (fd *FD) Close() error { - if !fd.fdmu.increfAndClose() { - return errClosing(fd.isFile) - } - if fd.kind == kindPipe { - syscall.CancelIoEx(fd.Sysfd, nil) - } - // unblock pending reader and writer - fd.pd.evict() - err := fd.decref() - // Wait until the descriptor is closed. If this was the only - // reference, it is already closed. - runtime_Semacquire(&fd.csema) - return err -} - -// Windows ReadFile and WSARecv use DWORD (uint32) parameter to pass buffer length. -// This prevents us reading blocks larger than 4GB. -// See golang.org/issue/26923. -const maxRW = 1 << 30 // 1GB is large enough and keeps subsequent reads aligned - -// Read implements io.Reader. -func (fd *FD) Read(buf []byte) (int, error) { - if err := fd.readLock(); err != nil { - return 0, err - } - defer fd.readUnlock() - - if len(buf) > maxRW { - buf = buf[:maxRW] - } - - var n int - var err error - if fd.isFile { - fd.l.Lock() - defer fd.l.Unlock() - switch fd.kind { - case kindConsole: - n, err = fd.readConsole(buf) - default: - n, err = syscall.Read(fd.Sysfd, buf) - if fd.kind == kindPipe && err == syscall.ERROR_OPERATION_ABORTED { - // Close uses CancelIoEx to interrupt concurrent I/O for pipes. - // If the fd is a pipe and the Read was interrupted by CancelIoEx, - // we assume it is interrupted by Close. - err = ErrFileClosing - } - } - if err != nil { - n = 0 - } - } else { - o := &fd.rop - o.InitBuf(buf) - n, err = execIO(o, func(o *operation) error { - return syscall.WSARecv(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil) - }) - if race.Enabled { - race.Acquire(unsafe.Pointer(&ioSync)) - } - } - if len(buf) != 0 { - err = fd.eofError(n, err) - } - return n, err -} - -var ReadConsole = syscall.ReadConsole // changed for testing - -// readConsole reads utf16 characters from console File, -// encodes them into utf8 and stores them in buffer b. -// It returns the number of utf8 bytes read and an error, if any. -func (fd *FD) readConsole(b []byte) (int, error) { - if len(b) == 0 { - return 0, nil - } - - if fd.readuint16 == nil { - // Note: syscall.ReadConsole fails for very large buffers. - // The limit is somewhere around (but not exactly) 16384. - // Stay well below. - fd.readuint16 = make([]uint16, 0, 10000) - fd.readbyte = make([]byte, 0, 4*cap(fd.readuint16)) - } - - for fd.readbyteOffset >= len(fd.readbyte) { - n := cap(fd.readuint16) - len(fd.readuint16) - if n > len(b) { - n = len(b) - } - var nw uint32 - err := ReadConsole(fd.Sysfd, &fd.readuint16[:len(fd.readuint16)+1][len(fd.readuint16)], uint32(n), &nw, nil) - if err != nil { - return 0, err - } - uint16s := fd.readuint16[:len(fd.readuint16)+int(nw)] - fd.readuint16 = fd.readuint16[:0] - buf := fd.readbyte[:0] - for i := 0; i < len(uint16s); i++ { - r := rune(uint16s[i]) - if utf16.IsSurrogate(r) { - if i+1 == len(uint16s) { - if nw > 0 { - // Save half surrogate pair for next time. - fd.readuint16 = fd.readuint16[:1] - fd.readuint16[0] = uint16(r) - break - } - r = utf8.RuneError - } else { - r = utf16.DecodeRune(r, rune(uint16s[i+1])) - if r != utf8.RuneError { - i++ - } - } - } - buf = utf8.AppendRune(buf, r) - } - fd.readbyte = buf - fd.readbyteOffset = 0 - if nw == 0 { - break - } - } - - src := fd.readbyte[fd.readbyteOffset:] - var i int - for i = 0; i < len(src) && i < len(b); i++ { - x := src[i] - if x == 0x1A { // Ctrl-Z - if i == 0 { - fd.readbyteOffset++ - } - break - } - b[i] = x - } - fd.readbyteOffset += i - return i, nil -} - -// Pread emulates the Unix pread system call. -func (fd *FD) Pread(b []byte, off int64) (int, error) { - if fd.kind == kindPipe { - // Pread does not work with pipes - return 0, syscall.ESPIPE - } - // Call incref, not readLock, because since pread specifies the - // offset it is independent from other reads. - if err := fd.incref(); err != nil { - return 0, err - } - defer fd.decref() - - if len(b) > maxRW { - b = b[:maxRW] - } - - fd.l.Lock() - defer fd.l.Unlock() - curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent) - if e != nil { - return 0, e - } - defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart) - o := syscall.Overlapped{ - OffsetHigh: uint32(off >> 32), - Offset: uint32(off), - } - var done uint32 - e = syscall.ReadFile(fd.Sysfd, b, &done, &o) - if e != nil { - done = 0 - if e == syscall.ERROR_HANDLE_EOF { - e = io.EOF - } - } - if len(b) != 0 { - e = fd.eofError(int(done), e) - } - return int(done), e -} - -// ReadFrom wraps the recvfrom network call. -func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) { - if len(buf) == 0 { - return 0, nil, nil - } - if len(buf) > maxRW { - buf = buf[:maxRW] - } - if err := fd.readLock(); err != nil { - return 0, nil, err - } - defer fd.readUnlock() - o := &fd.rop - o.InitBuf(buf) - n, err := execIO(o, func(o *operation) error { - if o.rsa == nil { - o.rsa = new(syscall.RawSockaddrAny) - } - o.rsan = int32(unsafe.Sizeof(*o.rsa)) - return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) - }) - err = fd.eofError(n, err) - if err != nil { - return n, nil, err - } - sa, _ := o.rsa.Sockaddr() - return n, sa, nil -} - -// ReadFromInet4 wraps the recvfrom network call for IPv4. -func (fd *FD) ReadFromInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error) { - if len(buf) == 0 { - return 0, nil - } - if len(buf) > maxRW { - buf = buf[:maxRW] - } - if err := fd.readLock(); err != nil { - return 0, err - } - defer fd.readUnlock() - o := &fd.rop - o.InitBuf(buf) - n, err := execIO(o, func(o *operation) error { - if o.rsa == nil { - o.rsa = new(syscall.RawSockaddrAny) - } - o.rsan = int32(unsafe.Sizeof(*o.rsa)) - return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) - }) - err = fd.eofError(n, err) - if err != nil { - return n, err - } - rawToSockaddrInet4(o.rsa, sa4) - return n, err -} - -// ReadFromInet6 wraps the recvfrom network call for IPv6. -func (fd *FD) ReadFromInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error) { - if len(buf) == 0 { - return 0, nil - } - if len(buf) > maxRW { - buf = buf[:maxRW] - } - if err := fd.readLock(); err != nil { - return 0, err - } - defer fd.readUnlock() - o := &fd.rop - o.InitBuf(buf) - n, err := execIO(o, func(o *operation) error { - if o.rsa == nil { - o.rsa = new(syscall.RawSockaddrAny) - } - o.rsan = int32(unsafe.Sizeof(*o.rsa)) - return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) - }) - err = fd.eofError(n, err) - if err != nil { - return n, err - } - rawToSockaddrInet6(o.rsa, sa6) - return n, err -} - -// Write implements io.Writer. -func (fd *FD) Write(buf []byte) (int, error) { - if err := fd.writeLock(); err != nil { - return 0, err - } - defer fd.writeUnlock() - if fd.isFile { - fd.l.Lock() - defer fd.l.Unlock() - } - - ntotal := 0 - for len(buf) > 0 { - b := buf - if len(b) > maxRW { - b = b[:maxRW] - } - var n int - var err error - if fd.isFile { - switch fd.kind { - case kindConsole: - n, err = fd.writeConsole(b) - default: - n, err = syscall.Write(fd.Sysfd, b) - if fd.kind == kindPipe && err == syscall.ERROR_OPERATION_ABORTED { - // Close uses CancelIoEx to interrupt concurrent I/O for pipes. - // If the fd is a pipe and the Write was interrupted by CancelIoEx, - // we assume it is interrupted by Close. - err = ErrFileClosing - } - } - if err != nil { - n = 0 - } - } else { - if race.Enabled { - race.ReleaseMerge(unsafe.Pointer(&ioSync)) - } - o := &fd.wop - o.InitBuf(b) - n, err = execIO(o, func(o *operation) error { - return syscall.WSASend(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil) - }) - } - ntotal += n - if err != nil { - return ntotal, err - } - buf = buf[n:] - } - return ntotal, nil -} - -// writeConsole writes len(b) bytes to the console File. -// It returns the number of bytes written and an error, if any. -func (fd *FD) writeConsole(b []byte) (int, error) { - n := len(b) - runes := make([]rune, 0, 256) - if len(fd.lastbits) > 0 { - b = append(fd.lastbits, b...) - fd.lastbits = nil - - } - for len(b) >= utf8.UTFMax || utf8.FullRune(b) { - r, l := utf8.DecodeRune(b) - runes = append(runes, r) - b = b[l:] - } - if len(b) > 0 { - fd.lastbits = make([]byte, len(b)) - copy(fd.lastbits, b) - } - // syscall.WriteConsole seems to fail, if given large buffer. - // So limit the buffer to 16000 characters. This number was - // discovered by experimenting with syscall.WriteConsole. - const maxWrite = 16000 - for len(runes) > 0 { - m := len(runes) - if m > maxWrite { - m = maxWrite - } - chunk := runes[:m] - runes = runes[m:] - uint16s := utf16.Encode(chunk) - for len(uint16s) > 0 { - var written uint32 - err := syscall.WriteConsole(fd.Sysfd, &uint16s[0], uint32(len(uint16s)), &written, nil) - if err != nil { - return 0, err - } - uint16s = uint16s[written:] - } - } - return n, nil -} - -// Pwrite emulates the Unix pwrite system call. -func (fd *FD) Pwrite(buf []byte, off int64) (int, error) { - if fd.kind == kindPipe { - // Pwrite does not work with pipes - return 0, syscall.ESPIPE - } - // Call incref, not writeLock, because since pwrite specifies the - // offset it is independent from other writes. - if err := fd.incref(); err != nil { - return 0, err - } - defer fd.decref() - - fd.l.Lock() - defer fd.l.Unlock() - curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent) - if e != nil { - return 0, e - } - defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart) - - ntotal := 0 - for len(buf) > 0 { - b := buf - if len(b) > maxRW { - b = b[:maxRW] - } - var n uint32 - o := syscall.Overlapped{ - OffsetHigh: uint32(off >> 32), - Offset: uint32(off), - } - e = syscall.WriteFile(fd.Sysfd, b, &n, &o) - ntotal += int(n) - if e != nil { - return ntotal, e - } - buf = buf[n:] - off += int64(n) - } - return ntotal, nil -} - -// Writev emulates the Unix writev system call. -func (fd *FD) Writev(buf *[][]byte) (int64, error) { - if len(*buf) == 0 { - return 0, nil - } - if err := fd.writeLock(); err != nil { - return 0, err - } - defer fd.writeUnlock() - if race.Enabled { - race.ReleaseMerge(unsafe.Pointer(&ioSync)) - } - o := &fd.wop - o.InitBufs(buf) - n, err := execIO(o, func(o *operation) error { - return syscall.WSASend(o.fd.Sysfd, &o.bufs[0], uint32(len(o.bufs)), &o.qty, 0, &o.o, nil) - }) - o.ClearBufs() - TestHookDidWritev(n) - consume(buf, int64(n)) - return int64(n), err -} - -// WriteTo wraps the sendto network call. -func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) { - if err := fd.writeLock(); err != nil { - return 0, err - } - defer fd.writeUnlock() - - if len(buf) == 0 { - // handle zero-byte payload - o := &fd.wop - o.InitBuf(buf) - o.sa = sa - n, err := execIO(o, func(o *operation) error { - return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil) - }) - return n, err - } - - ntotal := 0 - for len(buf) > 0 { - b := buf - if len(b) > maxRW { - b = b[:maxRW] - } - o := &fd.wop - o.InitBuf(b) - o.sa = sa - n, err := execIO(o, func(o *operation) error { - return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil) - }) - ntotal += int(n) - if err != nil { - return ntotal, err - } - buf = buf[n:] - } - return ntotal, nil -} - -// WriteToInet4 is WriteTo, specialized for syscall.SockaddrInet4. -func (fd *FD) WriteToInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error) { - if err := fd.writeLock(); err != nil { - return 0, err - } - defer fd.writeUnlock() - - if len(buf) == 0 { - // handle zero-byte payload - o := &fd.wop - o.InitBuf(buf) - n, err := execIO(o, func(o *operation) error { - return windows.WSASendtoInet4(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa4, &o.o, nil) - }) - return n, err - } - - ntotal := 0 - for len(buf) > 0 { - b := buf - if len(b) > maxRW { - b = b[:maxRW] - } - o := &fd.wop - o.InitBuf(b) - n, err := execIO(o, func(o *operation) error { - return windows.WSASendtoInet4(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa4, &o.o, nil) - }) - ntotal += int(n) - if err != nil { - return ntotal, err - } - buf = buf[n:] - } - return ntotal, nil -} - -// WriteToInet6 is WriteTo, specialized for syscall.SockaddrInet6. -func (fd *FD) WriteToInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error) { - if err := fd.writeLock(); err != nil { - return 0, err - } - defer fd.writeUnlock() - - if len(buf) == 0 { - // handle zero-byte payload - o := &fd.wop - o.InitBuf(buf) - n, err := execIO(o, func(o *operation) error { - return windows.WSASendtoInet6(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa6, &o.o, nil) - }) - return n, err - } - - ntotal := 0 - for len(buf) > 0 { - b := buf - if len(b) > maxRW { - b = b[:maxRW] - } - o := &fd.wop - o.InitBuf(b) - n, err := execIO(o, func(o *operation) error { - return windows.WSASendtoInet6(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa6, &o.o, nil) - }) - ntotal += int(n) - if err != nil { - return ntotal, err - } - buf = buf[n:] - } - return ntotal, nil -} - -// Call ConnectEx. This doesn't need any locking, since it is only -// called when the descriptor is first created. This is here rather -// than in the net package so that it can use fd.wop. -func (fd *FD) ConnectEx(ra syscall.Sockaddr) error { - o := &fd.wop - o.sa = ra - _, err := execIO(o, func(o *operation) error { - return ConnectExFunc(o.fd.Sysfd, o.sa, nil, 0, nil, &o.o) - }) - return err -} - -func (fd *FD) acceptOne(s syscall.Handle, rawsa []syscall.RawSockaddrAny, o *operation) (string, error) { - // Submit accept request. - o.handle = s - o.rsan = int32(unsafe.Sizeof(rawsa[0])) - _, err := execIO(o, func(o *operation) error { - return AcceptFunc(o.fd.Sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o) - }) - if err != nil { - CloseFunc(s) - return "acceptex", err - } - - // Inherit properties of the listening socket. - err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.Sysfd)), int32(unsafe.Sizeof(fd.Sysfd))) - if err != nil { - CloseFunc(s) - return "setsockopt", err - } - - return "", nil -} - -// Accept handles accepting a socket. The sysSocket parameter is used -// to allocate the net socket. -func (fd *FD) Accept(sysSocket func() (syscall.Handle, error)) (syscall.Handle, []syscall.RawSockaddrAny, uint32, string, error) { - if err := fd.readLock(); err != nil { - return syscall.InvalidHandle, nil, 0, "", err - } - defer fd.readUnlock() - - o := &fd.rop - var rawsa [2]syscall.RawSockaddrAny - for { - s, err := sysSocket() - if err != nil { - return syscall.InvalidHandle, nil, 0, "", err - } - - errcall, err := fd.acceptOne(s, rawsa[:], o) - if err == nil { - return s, rawsa[:], uint32(o.rsan), "", nil - } - - // Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is - // returned here. These happen if connection reset is received - // before AcceptEx could complete. These errors relate to new - // connection, not to AcceptEx, so ignore broken connection and - // try AcceptEx again for more connections. - errno, ok := err.(syscall.Errno) - if !ok { - return syscall.InvalidHandle, nil, 0, errcall, err - } - switch errno { - case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET: - // ignore these and try again - default: - return syscall.InvalidHandle, nil, 0, errcall, err - } - } -} - -// Seek wraps syscall.Seek. -func (fd *FD) Seek(offset int64, whence int) (int64, error) { - if fd.kind == kindPipe { - return 0, syscall.ESPIPE - } - if err := fd.incref(); err != nil { - return 0, err - } - defer fd.decref() - - fd.l.Lock() - defer fd.l.Unlock() - - return syscall.Seek(fd.Sysfd, offset, whence) -} - -// Fchmod updates syscall.ByHandleFileInformation.Fileattributes when needed. -func (fd *FD) Fchmod(mode uint32) error { - if err := fd.incref(); err != nil { - return err - } - defer fd.decref() - - var d syscall.ByHandleFileInformation - if err := syscall.GetFileInformationByHandle(fd.Sysfd, &d); err != nil { - return err - } - attrs := d.FileAttributes - if mode&syscall.S_IWRITE != 0 { - attrs &^= syscall.FILE_ATTRIBUTE_READONLY - } else { - attrs |= syscall.FILE_ATTRIBUTE_READONLY - } - if attrs == d.FileAttributes { - return nil - } - - var du windows.FILE_BASIC_INFO - du.FileAttributes = attrs - return windows.SetFileInformationByHandle(fd.Sysfd, windows.FileBasicInfo, unsafe.Pointer(&du), uint32(unsafe.Sizeof(du))) -} - -// Fchdir wraps syscall.Fchdir. -func (fd *FD) Fchdir() error { - if err := fd.incref(); err != nil { - return err - } - defer fd.decref() - return syscall.Fchdir(fd.Sysfd) -} - -// GetFileType wraps syscall.GetFileType. -func (fd *FD) GetFileType() (uint32, error) { - if err := fd.incref(); err != nil { - return 0, err - } - defer fd.decref() - return syscall.GetFileType(fd.Sysfd) -} - -// GetFileInformationByHandle wraps GetFileInformationByHandle. -func (fd *FD) GetFileInformationByHandle(data *syscall.ByHandleFileInformation) error { - if err := fd.incref(); err != nil { - return err - } - defer fd.decref() - return syscall.GetFileInformationByHandle(fd.Sysfd, data) -} - -// RawRead invokes the user-defined function f for a read operation. -func (fd *FD) RawRead(f func(uintptr) bool) error { - if err := fd.readLock(); err != nil { - return err - } - defer fd.readUnlock() - for { - if f(uintptr(fd.Sysfd)) { - return nil - } - - // Use a zero-byte read as a way to get notified when this - // socket is readable. h/t https://stackoverflow.com/a/42019668/332798 - o := &fd.rop - o.InitBuf(nil) - if !fd.IsStream { - o.flags |= windows.MSG_PEEK - } - _, err := execIO(o, func(o *operation) error { - return syscall.WSARecv(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil) - }) - if err == windows.WSAEMSGSIZE { - // expected with a 0-byte peek, ignore. - } else if err != nil { - return err - } - } -} - -// RawWrite invokes the user-defined function f for a write operation. -func (fd *FD) RawWrite(f func(uintptr) bool) error { - if err := fd.writeLock(); err != nil { - return err - } - defer fd.writeUnlock() - - if f(uintptr(fd.Sysfd)) { - return nil - } - - // TODO(tmm1): find a way to detect socket writability - return syscall.EWINDOWS -} - -func sockaddrInet4ToRaw(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet4) int32 { - *rsa = syscall.RawSockaddrAny{} - raw := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa)) - raw.Family = syscall.AF_INET - p := (*[2]byte)(unsafe.Pointer(&raw.Port)) - p[0] = byte(sa.Port >> 8) - p[1] = byte(sa.Port) - raw.Addr = sa.Addr - return int32(unsafe.Sizeof(*raw)) -} - -func sockaddrInet6ToRaw(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet6) int32 { - *rsa = syscall.RawSockaddrAny{} - raw := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa)) - raw.Family = syscall.AF_INET6 - p := (*[2]byte)(unsafe.Pointer(&raw.Port)) - p[0] = byte(sa.Port >> 8) - p[1] = byte(sa.Port) - raw.Scope_id = sa.ZoneId - raw.Addr = sa.Addr - return int32(unsafe.Sizeof(*raw)) -} - -func rawToSockaddrInet4(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet4) { - pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa)) - p := (*[2]byte)(unsafe.Pointer(&pp.Port)) - sa.Port = int(p[0])<<8 + int(p[1]) - sa.Addr = pp.Addr -} - -func rawToSockaddrInet6(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet6) { - pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa)) - p := (*[2]byte)(unsafe.Pointer(&pp.Port)) - sa.Port = int(p[0])<<8 + int(p[1]) - sa.ZoneId = pp.Scope_id - sa.Addr = pp.Addr -} - -func sockaddrToRaw(rsa *syscall.RawSockaddrAny, sa syscall.Sockaddr) (int32, error) { - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - sz := sockaddrInet4ToRaw(rsa, sa) - return sz, nil - case *syscall.SockaddrInet6: - sz := sockaddrInet6ToRaw(rsa, sa) - return sz, nil - default: - return 0, syscall.EWINDOWS - } -} - -// ReadMsg wraps the WSARecvMsg network call. -func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.Sockaddr, error) { - if err := fd.readLock(); err != nil { - return 0, 0, 0, nil, err - } - defer fd.readUnlock() - - if len(p) > maxRW { - p = p[:maxRW] - } - - o := &fd.rop - o.InitMsg(p, oob) - if o.rsa == nil { - o.rsa = new(syscall.RawSockaddrAny) - } - o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) - o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa)) - o.msg.Flags = uint32(flags) - n, err := execIO(o, func(o *operation) error { - return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil) - }) - err = fd.eofError(n, err) - var sa syscall.Sockaddr - if err == nil { - sa, err = o.rsa.Sockaddr() - } - return n, int(o.msg.Control.Len), int(o.msg.Flags), sa, err -} - -// ReadMsgInet4 is ReadMsg, but specialized to return a syscall.SockaddrInet4. -func (fd *FD) ReadMsgInet4(p []byte, oob []byte, flags int, sa4 *syscall.SockaddrInet4) (int, int, int, error) { - if err := fd.readLock(); err != nil { - return 0, 0, 0, err - } - defer fd.readUnlock() - - if len(p) > maxRW { - p = p[:maxRW] - } - - o := &fd.rop - o.InitMsg(p, oob) - if o.rsa == nil { - o.rsa = new(syscall.RawSockaddrAny) - } - o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) - o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa)) - o.msg.Flags = uint32(flags) - n, err := execIO(o, func(o *operation) error { - return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil) - }) - err = fd.eofError(n, err) - if err == nil { - rawToSockaddrInet4(o.rsa, sa4) - } - return n, int(o.msg.Control.Len), int(o.msg.Flags), err -} - -// ReadMsgInet6 is ReadMsg, but specialized to return a syscall.SockaddrInet6. -func (fd *FD) ReadMsgInet6(p []byte, oob []byte, flags int, sa6 *syscall.SockaddrInet6) (int, int, int, error) { - if err := fd.readLock(); err != nil { - return 0, 0, 0, err - } - defer fd.readUnlock() - - if len(p) > maxRW { - p = p[:maxRW] - } - - o := &fd.rop - o.InitMsg(p, oob) - if o.rsa == nil { - o.rsa = new(syscall.RawSockaddrAny) - } - o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) - o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa)) - o.msg.Flags = uint32(flags) - n, err := execIO(o, func(o *operation) error { - return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil) - }) - err = fd.eofError(n, err) - if err == nil { - rawToSockaddrInet6(o.rsa, sa6) - } - return n, int(o.msg.Control.Len), int(o.msg.Flags), err -} - -// WriteMsg wraps the WSASendMsg network call. -func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) { - if len(p) > maxRW { - return 0, 0, errors.New("packet is too large (only 1GB is allowed)") - } - - if err := fd.writeLock(); err != nil { - return 0, 0, err - } - defer fd.writeUnlock() - - o := &fd.wop - o.InitMsg(p, oob) - if sa != nil { - if o.rsa == nil { - o.rsa = new(syscall.RawSockaddrAny) - } - len, err := sockaddrToRaw(o.rsa, sa) - if err != nil { - return 0, 0, err - } - o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) - o.msg.Namelen = len - } - n, err := execIO(o, func(o *operation) error { - return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil) - }) - return n, int(o.msg.Control.Len), err -} - -// WriteMsgInet4 is WriteMsg specialized for syscall.SockaddrInet4. -func (fd *FD) WriteMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (int, int, error) { - if len(p) > maxRW { - return 0, 0, errors.New("packet is too large (only 1GB is allowed)") - } - - if err := fd.writeLock(); err != nil { - return 0, 0, err - } - defer fd.writeUnlock() - - o := &fd.wop - o.InitMsg(p, oob) - if o.rsa == nil { - o.rsa = new(syscall.RawSockaddrAny) - } - len := sockaddrInet4ToRaw(o.rsa, sa) - o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) - o.msg.Namelen = len - n, err := execIO(o, func(o *operation) error { - return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil) - }) - return n, int(o.msg.Control.Len), err -} - -// WriteMsgInet6 is WriteMsg specialized for syscall.SockaddrInet6. -func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (int, int, error) { - if len(p) > maxRW { - return 0, 0, errors.New("packet is too large (only 1GB is allowed)") - } - - if err := fd.writeLock(); err != nil { - return 0, 0, err - } - defer fd.writeUnlock() - - o := &fd.wop - o.InitMsg(p, oob) - if o.rsa == nil { - o.rsa = new(syscall.RawSockaddrAny) - } - len := sockaddrInet6ToRaw(o.rsa, sa) - o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) - o.msg.Namelen = len - n, err := execIO(o, func(o *operation) error { - return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil) - }) - return n, int(o.msg.Control.Len), err -} diff --git a/contrib/go/_std_1.22/src/internal/poll/sendfile_bsd.go b/contrib/go/_std_1.22/src/internal/poll/sendfile_bsd.go deleted file mode 100644 index 0f55cad73dc3..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/sendfile_bsd.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin || dragonfly || freebsd - -package poll - -import "syscall" - -// maxSendfileSize is the largest chunk size we ask the kernel to copy -// at a time. -const maxSendfileSize int = 4 << 20 - -// SendFile wraps the sendfile system call. -func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error, bool) { - if err := dstFD.writeLock(); err != nil { - return 0, err, false - } - defer dstFD.writeUnlock() - if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { - return 0, err, false - } - - dst := dstFD.Sysfd - var ( - written int64 - err error - handled = true - ) - for remain > 0 { - n := maxSendfileSize - if int64(n) > remain { - n = int(remain) - } - pos1 := pos - n, err1 := syscall.Sendfile(dst, src, &pos1, n) - if n > 0 { - pos += int64(n) - written += int64(n) - remain -= int64(n) - } else if n == 0 && err1 == nil { - break - } - if err1 == syscall.EINTR { - continue - } - if err1 == syscall.EAGAIN { - if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil { - continue - } - } - if err1 != nil { - // This includes syscall.ENOSYS (no kernel - // support) and syscall.EINVAL (fd types which - // don't implement sendfile) - err = err1 - handled = false - break - } - } - return written, err, handled -} diff --git a/contrib/go/_std_1.22/src/internal/poll/sendfile_linux.go b/contrib/go/_std_1.22/src/internal/poll/sendfile_linux.go deleted file mode 100644 index cc31969a43f9..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/sendfile_linux.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package poll - -import "syscall" - -// maxSendfileSize is the largest chunk size we ask the kernel to copy -// at a time. -const maxSendfileSize int = 4 << 20 - -// SendFile wraps the sendfile system call. -func SendFile(dstFD *FD, src int, remain int64) (int64, error, bool) { - if err := dstFD.writeLock(); err != nil { - return 0, err, false - } - defer dstFD.writeUnlock() - if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { - return 0, err, false - } - - dst := dstFD.Sysfd - var ( - written int64 - err error - handled = true - ) - for remain > 0 { - n := maxSendfileSize - if int64(n) > remain { - n = int(remain) - } - n, err1 := syscall.Sendfile(dst, src, nil, n) - if n > 0 { - written += int64(n) - remain -= int64(n) - } else if n == 0 && err1 == nil { - break - } - if err1 == syscall.EINTR { - continue - } - if err1 == syscall.EAGAIN { - if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil { - continue - } - } - if err1 != nil { - // This includes syscall.ENOSYS (no kernel - // support) and syscall.EINVAL (fd types which - // don't implement sendfile) - err = err1 - handled = false - break - } - } - return written, err, handled -} diff --git a/contrib/go/_std_1.22/src/internal/poll/sendfile_solaris.go b/contrib/go/_std_1.22/src/internal/poll/sendfile_solaris.go deleted file mode 100644 index f9f685c64a64..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/sendfile_solaris.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package poll - -import "syscall" - -// Not strictly needed, but very helpful for debugging, see issue #10221. -// -//go:cgo_import_dynamic _ _ "libsendfile.so" -//go:cgo_import_dynamic _ _ "libsocket.so" - -// maxSendfileSize is the largest chunk size we ask the kernel to copy -// at a time. -const maxSendfileSize int = 4 << 20 - -// SendFile wraps the sendfile system call. -func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error, bool) { - if err := dstFD.writeLock(); err != nil { - return 0, err, false - } - defer dstFD.writeUnlock() - if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { - return 0, err, false - } - - dst := dstFD.Sysfd - var ( - written int64 - err error - handled = true - ) - for remain > 0 { - n := maxSendfileSize - if int64(n) > remain { - n = int(remain) - } - pos1 := pos - n, err1 := syscall.Sendfile(dst, src, &pos1, n) - if err1 == syscall.EAGAIN || err1 == syscall.EINTR { - // partial write may have occurred - n = int(pos1 - pos) - } - if n > 0 { - pos += int64(n) - written += int64(n) - remain -= int64(n) - } else if n == 0 && err1 == nil { - break - } - if err1 == syscall.EAGAIN { - if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil { - continue - } - } - if err1 == syscall.EINTR { - continue - } - if err1 != nil { - // This includes syscall.ENOSYS (no kernel - // support) and syscall.EINVAL (fd types which - // don't implement sendfile) - err = err1 - handled = false - break - } - } - return written, err, handled -} diff --git a/contrib/go/_std_1.22/src/internal/poll/sendfile_windows.go b/contrib/go/_std_1.22/src/internal/poll/sendfile_windows.go deleted file mode 100644 index 8c3353bc6ffa..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/sendfile_windows.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package poll - -import ( - "io" - "syscall" -) - -// SendFile wraps the TransmitFile call. -func SendFile(fd *FD, src syscall.Handle, n int64) (written int64, err error) { - if fd.kind == kindPipe { - // TransmitFile does not work with pipes - return 0, syscall.ESPIPE - } - if ft, _ := syscall.GetFileType(src); ft == syscall.FILE_TYPE_PIPE { - return 0, syscall.ESPIPE - } - - if err := fd.writeLock(); err != nil { - return 0, err - } - defer fd.writeUnlock() - - o := &fd.wop - o.handle = src - - // TODO(brainman): skip calling syscall.Seek if OS allows it - curpos, err := syscall.Seek(o.handle, 0, io.SeekCurrent) - if err != nil { - return 0, err - } - - if n <= 0 { // We don't know the size of the file so infer it. - // Find the number of bytes offset from curpos until the end of the file. - n, err = syscall.Seek(o.handle, -curpos, io.SeekEnd) - if err != nil { - return - } - // Now seek back to the original position. - if _, err = syscall.Seek(o.handle, curpos, io.SeekStart); err != nil { - return - } - } - - // TransmitFile can be invoked in one call with at most - // 2,147,483,646 bytes: the maximum value for a 32-bit integer minus 1. - // See https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile - const maxChunkSizePerCall = int64(0x7fffffff - 1) - - for n > 0 { - chunkSize := maxChunkSizePerCall - if chunkSize > n { - chunkSize = n - } - - o.qty = uint32(chunkSize) - o.o.Offset = uint32(curpos) - o.o.OffsetHigh = uint32(curpos >> 32) - - nw, err := execIO(o, func(o *operation) error { - return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND) - }) - if err != nil { - return written, err - } - - curpos += int64(nw) - - // Some versions of Windows (Windows 10 1803) do not set - // file position after TransmitFile completes. - // So just use Seek to set file position. - if _, err = syscall.Seek(o.handle, curpos, io.SeekStart); err != nil { - return written, err - } - - n -= int64(nw) - written += int64(nw) - } - - return -} diff --git a/contrib/go/_std_1.22/src/internal/poll/sock_cloexec.go b/contrib/go/_std_1.22/src/internal/poll/sock_cloexec.go deleted file mode 100644 index 361c11bc57c3..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/sock_cloexec.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file implements accept for platforms that provide a fast path for -// setting SetNonblock and CloseOnExec. - -//go:build dragonfly || freebsd || (linux && !arm) || netbsd || openbsd || solaris - -package poll - -import "syscall" - -// Wrapper around the accept system call that marks the returned file -// descriptor as nonblocking and close-on-exec. -func accept(s int) (int, syscall.Sockaddr, string, error) { - ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) - // TODO: We can remove the fallback on Linux and *BSD, - // as currently supported versions all support accept4 - // with SOCK_CLOEXEC, but Solaris does not. See issue #59359. - switch err { - case nil: - return ns, sa, "", nil - default: // errors other than the ones listed - return -1, sa, "accept4", err - case syscall.ENOSYS: // syscall missing - case syscall.EINVAL: // some Linux use this instead of ENOSYS - case syscall.EACCES: // some Linux use this instead of ENOSYS - case syscall.EFAULT: // some Linux use this instead of ENOSYS - } - - // See ../syscall/exec_unix.go for description of ForkLock. - // It is probably okay to hold the lock across syscall.Accept - // because we have put fd.sysfd into non-blocking mode. - // However, a call to the File method will put it back into - // blocking mode. We can't take that risk, so no use of ForkLock here. - ns, sa, err = AcceptFunc(s) - if err == nil { - syscall.CloseOnExec(ns) - } - if err != nil { - return -1, nil, "accept", err - } - if err = syscall.SetNonblock(ns, true); err != nil { - CloseFunc(ns) - return -1, nil, "setnonblock", err - } - return ns, sa, "", nil -} diff --git a/contrib/go/_std_1.22/src/internal/poll/splice_linux.go b/contrib/go/_std_1.22/src/internal/poll/splice_linux.go deleted file mode 100644 index 72cca34fe4ae..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/splice_linux.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package poll - -import ( - "internal/syscall/unix" - "runtime" - "sync" - "syscall" - "unsafe" -) - -const ( - // spliceNonblock doesn't make the splice itself necessarily nonblocking - // (because the actual file descriptors that are spliced from/to may block - // unless they have the O_NONBLOCK flag set), but it makes the splice pipe - // operations nonblocking. - spliceNonblock = 0x2 - - // maxSpliceSize is the maximum amount of data Splice asks - // the kernel to move in a single call to splice(2). - // We use 1MB as Splice writes data through a pipe, and 1MB is the default maximum pipe buffer size, - // which is determined by /proc/sys/fs/pipe-max-size. - maxSpliceSize = 1 << 20 -) - -// Splice transfers at most remain bytes of data from src to dst, using the -// splice system call to minimize copies of data from and to userspace. -// -// Splice gets a pipe buffer from the pool or creates a new one if needed, to serve as a buffer for the data transfer. -// src and dst must both be stream-oriented sockets. -// -// If err != nil, sc is the system call which caused the error. -func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, err error) { - p, sc, err := getPipe() - if err != nil { - return 0, false, sc, err - } - defer putPipe(p) - var inPipe, n int - for err == nil && remain > 0 { - max := maxSpliceSize - if int64(max) > remain { - max = int(remain) - } - inPipe, err = spliceDrain(p.wfd, src, max) - // The operation is considered handled if splice returns no - // error, or an error other than EINVAL. An EINVAL means the - // kernel does not support splice for the socket type of src. - // The failed syscall does not consume any data so it is safe - // to fall back to a generic copy. - // - // spliceDrain should never return EAGAIN, so if err != nil, - // Splice cannot continue. - // - // If inPipe == 0 && err == nil, src is at EOF, and the - // transfer is complete. - handled = handled || (err != syscall.EINVAL) - if err != nil || inPipe == 0 { - break - } - p.data += inPipe - - n, err = splicePump(dst, p.rfd, inPipe) - if n > 0 { - written += int64(n) - remain -= int64(n) - p.data -= n - } - } - if err != nil { - return written, handled, "splice", err - } - return written, true, "", nil -} - -// spliceDrain moves data from a socket to a pipe. -// -// Invariant: when entering spliceDrain, the pipe is empty. It is either in its -// initial state, or splicePump has emptied it previously. -// -// Given this, spliceDrain can reasonably assume that the pipe is ready for -// writing, so if splice returns EAGAIN, it must be because the socket is not -// ready for reading. -// -// If spliceDrain returns (0, nil), src is at EOF. -func spliceDrain(pipefd int, sock *FD, max int) (int, error) { - if err := sock.readLock(); err != nil { - return 0, err - } - defer sock.readUnlock() - if err := sock.pd.prepareRead(sock.isFile); err != nil { - return 0, err - } - for { - // In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here, - // because it could return EAGAIN ceaselessly when the write end of the pipe is full, - // but this shouldn't be a concern here, since the pipe buffer must be sufficient for - // this data transmission on the basis of the workflow in Splice. - n, err := splice(pipefd, sock.Sysfd, max, spliceNonblock) - if err == syscall.EINTR { - continue - } - if err != syscall.EAGAIN { - return n, err - } - if sock.pd.pollable() { - if err := sock.pd.waitRead(sock.isFile); err != nil { - return n, err - } - } - } -} - -// splicePump moves all the buffered data from a pipe to a socket. -// -// Invariant: when entering splicePump, there are exactly inPipe -// bytes of data in the pipe, from a previous call to spliceDrain. -// -// By analogy to the condition from spliceDrain, splicePump -// only needs to poll the socket for readiness, if splice returns -// EAGAIN. -// -// If splicePump cannot move all the data in a single call to -// splice(2), it loops over the buffered data until it has written -// all of it to the socket. This behavior is similar to the Write -// step of an io.Copy in userspace. -func splicePump(sock *FD, pipefd int, inPipe int) (int, error) { - if err := sock.writeLock(); err != nil { - return 0, err - } - defer sock.writeUnlock() - if err := sock.pd.prepareWrite(sock.isFile); err != nil { - return 0, err - } - written := 0 - for inPipe > 0 { - // In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here, - // because it could return EAGAIN ceaselessly when the read end of the pipe is empty, - // but this shouldn't be a concern here, since the pipe buffer must contain inPipe size of - // data on the basis of the workflow in Splice. - n, err := splice(sock.Sysfd, pipefd, inPipe, spliceNonblock) - if err == syscall.EINTR { - continue - } - // Here, the condition n == 0 && err == nil should never be - // observed, since Splice controls the write side of the pipe. - if n > 0 { - inPipe -= n - written += n - continue - } - if err != syscall.EAGAIN { - return written, err - } - if sock.pd.pollable() { - if err := sock.pd.waitWrite(sock.isFile); err != nil { - return written, err - } - } - } - return written, nil -} - -// splice wraps the splice system call. Since the current implementation -// only uses splice on sockets and pipes, the offset arguments are unused. -// splice returns int instead of int64, because callers never ask it to -// move more data in a single call than can fit in an int32. -func splice(out int, in int, max int, flags int) (int, error) { - n, err := syscall.Splice(in, nil, out, nil, max, flags) - return int(n), err -} - -type splicePipeFields struct { - rfd int - wfd int - data int -} - -type splicePipe struct { - splicePipeFields - - // We want to use a finalizer, so ensure that the size is - // large enough to not use the tiny allocator. - _ [24 - unsafe.Sizeof(splicePipeFields{})%24]byte -} - -// splicePipePool caches pipes to avoid high-frequency construction and destruction of pipe buffers. -// The garbage collector will free all pipes in the sync.Pool periodically, thus we need to set up -// a finalizer for each pipe to close its file descriptors before the actual GC. -var splicePipePool = sync.Pool{New: newPoolPipe} - -func newPoolPipe() any { - // Discard the error which occurred during the creation of pipe buffer, - // redirecting the data transmission to the conventional way utilizing read() + write() as a fallback. - p := newPipe() - if p == nil { - return nil - } - runtime.SetFinalizer(p, destroyPipe) - return p -} - -// getPipe tries to acquire a pipe buffer from the pool or create a new one with newPipe() if it gets nil from the cache. -// -// Note that it may fail to create a new pipe buffer by newPipe(), in which case getPipe() will return a generic error -// and system call name splice in a string as the indication. -func getPipe() (*splicePipe, string, error) { - v := splicePipePool.Get() - if v == nil { - return nil, "splice", syscall.EINVAL - } - return v.(*splicePipe), "", nil -} - -func putPipe(p *splicePipe) { - // If there is still data left in the pipe, - // then close and discard it instead of putting it back into the pool. - if p.data != 0 { - runtime.SetFinalizer(p, nil) - destroyPipe(p) - return - } - splicePipePool.Put(p) -} - -// newPipe sets up a pipe for a splice operation. -func newPipe() *splicePipe { - var fds [2]int - if err := syscall.Pipe2(fds[:], syscall.O_CLOEXEC|syscall.O_NONBLOCK); err != nil { - return nil - } - - // Splice will loop writing maxSpliceSize bytes from the source to the pipe, - // and then write those bytes from the pipe to the destination. - // Set the pipe buffer size to maxSpliceSize to optimize that. - // Ignore errors here, as a smaller buffer size will work, - // although it will require more system calls. - unix.Fcntl(fds[0], syscall.F_SETPIPE_SZ, maxSpliceSize) - - return &splicePipe{splicePipeFields: splicePipeFields{rfd: fds[0], wfd: fds[1]}} -} - -// destroyPipe destroys a pipe. -func destroyPipe(p *splicePipe) { - CloseFunc(p.rfd) - CloseFunc(p.wfd) -} diff --git a/contrib/go/_std_1.22/src/internal/poll/strconv.go b/contrib/go/_std_1.22/src/internal/poll/strconv.go deleted file mode 100644 index 2b052fa1747f..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/strconv.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build plan9 - -package poll - -// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in -// suffix. -func stringsHasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix -} diff --git a/contrib/go/_std_1.22/src/internal/poll/ya.make b/contrib/go/_std_1.22/src/internal/poll/ya.make deleted file mode 100644 index 175eda755a51..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/ya.make +++ /dev/null @@ -1,63 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - errno_unix.go - fd.go - fd_fsync_darwin.go - fd_mutex.go - fd_opendir_darwin.go - fd_poll_runtime.go - fd_posix.go - fd_unix.go - fd_unixjs.go - fd_writev_libc.go - hook_unix.go - iovec_unix.go - sendfile_bsd.go - sockopt.go - sockopt_unix.go - sockoptip.go - sys_cloexec.go - writev.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - copy_file_range_linux.go - errno_unix.go - fd.go - fd_fsync_posix.go - fd_mutex.go - fd_poll_runtime.go - fd_posix.go - fd_unix.go - fd_unixjs.go - fd_writev_unix.go - hook_cloexec.go - hook_unix.go - iovec_unix.go - sendfile_linux.go - sock_cloexec.go - sockopt.go - sockopt_linux.go - sockopt_unix.go - sockoptip.go - splice_linux.go - writev.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - errno_windows.go - fd.go - fd_fsync_windows.go - fd_mutex.go - fd_poll_runtime.go - fd_posix.go - fd_windows.go - hook_windows.go - sendfile_windows.go - sockopt.go - sockopt_windows.go - sockoptip.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/race/ya.make b/contrib/go/_std_1.22/src/internal/race/ya.make deleted file mode 100644 index 3e33723a5ec0..000000000000 --- a/contrib/go/_std_1.22/src/internal/race/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race.go - ) -ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - norace.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/swapper.go b/contrib/go/_std_1.22/src/internal/reflectlite/swapper.go deleted file mode 100644 index ac17d9bbc465..000000000000 --- a/contrib/go/_std_1.22/src/internal/reflectlite/swapper.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package reflectlite - -import ( - "internal/goarch" - "internal/unsafeheader" - "unsafe" -) - -// Swapper returns a function that swaps the elements in the provided -// slice. -// -// Swapper panics if the provided interface is not a slice. -func Swapper(slice any) func(i, j int) { - v := ValueOf(slice) - if v.Kind() != Slice { - panic(&ValueError{Method: "Swapper", Kind: v.Kind()}) - } - // Fast path for slices of size 0 and 1. Nothing to swap. - switch v.Len() { - case 0: - return func(i, j int) { panic("reflect: slice index out of range") } - case 1: - return func(i, j int) { - if i != 0 || j != 0 { - panic("reflect: slice index out of range") - } - } - } - - typ := v.Type().Elem().common() - size := typ.Size() - hasPtr := typ.PtrBytes != 0 - - // Some common & small cases, without using memmove: - if hasPtr { - if size == goarch.PtrSize { - ps := *(*[]unsafe.Pointer)(v.ptr) - return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } - } - if typ.Kind() == String { - ss := *(*[]string)(v.ptr) - return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] } - } - } else { - switch size { - case 8: - is := *(*[]int64)(v.ptr) - return func(i, j int) { is[i], is[j] = is[j], is[i] } - case 4: - is := *(*[]int32)(v.ptr) - return func(i, j int) { is[i], is[j] = is[j], is[i] } - case 2: - is := *(*[]int16)(v.ptr) - return func(i, j int) { is[i], is[j] = is[j], is[i] } - case 1: - is := *(*[]int8)(v.ptr) - return func(i, j int) { is[i], is[j] = is[j], is[i] } - } - } - - s := (*unsafeheader.Slice)(v.ptr) - tmp := unsafe_New(typ) // swap scratch space - - return func(i, j int) { - if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) { - panic("reflect: slice index out of range") - } - val1 := arrayAt(s.Data, i, size, "i < s.Len") - val2 := arrayAt(s.Data, j, size, "j < s.Len") - typedmemmove(typ, tmp, val1) - typedmemmove(typ, val1, val2) - typedmemmove(typ, val2, tmp) - } -} diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/type.go b/contrib/go/_std_1.22/src/internal/reflectlite/type.go deleted file mode 100644 index e585d24f538c..000000000000 --- a/contrib/go/_std_1.22/src/internal/reflectlite/type.go +++ /dev/null @@ -1,665 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package reflectlite implements lightweight version of reflect, not using -// any package except for "runtime", "unsafe", and "internal/abi" -package reflectlite - -import ( - "internal/abi" - "unsafe" -) - -// Type is the representation of a Go type. -// -// Not all methods apply to all kinds of types. Restrictions, -// if any, are noted in the documentation for each method. -// Use the Kind method to find out the kind of type before -// calling kind-specific methods. Calling a method -// inappropriate to the kind of type causes a run-time panic. -// -// Type values are comparable, such as with the == operator, -// so they can be used as map keys. -// Two Type values are equal if they represent identical types. -type Type interface { - // Methods applicable to all types. - - // Name returns the type's name within its package for a defined type. - // For other (non-defined) types it returns the empty string. - Name() string - - // PkgPath returns a defined type's package path, that is, the import path - // that uniquely identifies the package, such as "encoding/base64". - // If the type was predeclared (string, error) or not defined (*T, struct{}, - // []int, or A where A is an alias for a non-defined type), the package path - // will be the empty string. - PkgPath() string - - // Size returns the number of bytes needed to store - // a value of the given type; it is analogous to unsafe.Sizeof. - Size() uintptr - - // Kind returns the specific kind of this type. - Kind() Kind - - // Implements reports whether the type implements the interface type u. - Implements(u Type) bool - - // AssignableTo reports whether a value of the type is assignable to type u. - AssignableTo(u Type) bool - - // Comparable reports whether values of this type are comparable. - Comparable() bool - - // String returns a string representation of the type. - // The string representation may use shortened package names - // (e.g., base64 instead of "encoding/base64") and is not - // guaranteed to be unique among types. To test for type identity, - // compare the Types directly. - String() string - - // Elem returns a type's element type. - // It panics if the type's Kind is not Ptr. - Elem() Type - - common() *abi.Type - uncommon() *uncommonType -} - -/* - * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go). - * A few are known to ../runtime/type.go to convey to debuggers. - * They are also known to ../runtime/type.go. - */ - -// A Kind represents the specific kind of type that a Type represents. -// The zero Kind is not a valid kind. -type Kind = abi.Kind - -const Ptr = abi.Pointer - -const ( - // Import-and-export these constants as necessary - Interface = abi.Interface - Slice = abi.Slice - String = abi.String - Struct = abi.Struct -) - -type nameOff = abi.NameOff -type typeOff = abi.TypeOff -type textOff = abi.TextOff - -type rtype struct { - *abi.Type -} - -// uncommonType is present only for defined types or types with methods -// (if T is a defined type, the uncommonTypes for T and *T have methods). -// Using a pointer to this struct reduces the overall size required -// to describe a non-defined type with no methods. -type uncommonType = abi.UncommonType - -// arrayType represents a fixed array type. -type arrayType = abi.ArrayType - -// chanType represents a channel type. -type chanType = abi.ChanType - -type funcType = abi.FuncType - -type interfaceType = abi.InterfaceType - -// mapType represents a map type. -type mapType struct { - rtype - Key *abi.Type // map key type - Elem *abi.Type // map element (value) type - Bucket *abi.Type // internal bucket structure - // function for hashing keys (ptr to key, seed) -> hash - Hasher func(unsafe.Pointer, uintptr) uintptr - KeySize uint8 // size of key slot - ValueSize uint8 // size of value slot - BucketSize uint16 // size of bucket - Flags uint32 -} - -// ptrType represents a pointer type. -type ptrType = abi.PtrType - -// sliceType represents a slice type. -type sliceType = abi.SliceType - -// structType represents a struct type. -type structType = abi.StructType - -// name is an encoded type name with optional extra data. -// -// The first byte is a bit field containing: -// -// 1<<0 the name is exported -// 1<<1 tag data follows the name -// 1<<2 pkgPath nameOff follows the name and tag -// -// The next two bytes are the data length: -// -// l := uint16(data[1])<<8 | uint16(data[2]) -// -// Bytes [3:3+l] are the string data. -// -// If tag data follows then bytes 3+l and 3+l+1 are the tag length, -// with the data following. -// -// If the import path follows, then 4 bytes at the end of -// the data form a nameOff. The import path is only set for concrete -// methods that are defined in a different package than their type. -// -// If a name starts with "*", then the exported bit represents -// whether the pointed to type is exported. -type name struct { - bytes *byte -} - -func (n name) data(off int, whySafe string) *byte { - return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off), whySafe)) -} - -func (n name) isExported() bool { - return (*n.bytes)&(1<<0) != 0 -} - -func (n name) hasTag() bool { - return (*n.bytes)&(1<<1) != 0 -} - -func (n name) embedded() bool { - return (*n.bytes)&(1<<3) != 0 -} - -// readVarint parses a varint as encoded by encoding/binary. -// It returns the number of encoded bytes and the encoded value. -func (n name) readVarint(off int) (int, int) { - v := 0 - for i := 0; ; i++ { - x := *n.data(off+i, "read varint") - v += int(x&0x7f) << (7 * i) - if x&0x80 == 0 { - return i + 1, v - } - } -} - -func (n name) name() string { - if n.bytes == nil { - return "" - } - i, l := n.readVarint(1) - return unsafe.String(n.data(1+i, "non-empty string"), l) -} - -func (n name) tag() string { - if !n.hasTag() { - return "" - } - i, l := n.readVarint(1) - i2, l2 := n.readVarint(1 + i + l) - return unsafe.String(n.data(1+i+l+i2, "non-empty string"), l2) -} - -func pkgPath(n abi.Name) string { - if n.Bytes == nil || *n.DataChecked(0, "name flag field")&(1<<2) == 0 { - return "" - } - i, l := n.ReadVarint(1) - off := 1 + i + l - if n.HasTag() { - i2, l2 := n.ReadVarint(off) - off += i2 + l2 - } - var nameOff int32 - // Note that this field may not be aligned in memory, - // so we cannot use a direct int32 assignment here. - copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.DataChecked(off, "name offset field")))[:]) - pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n.Bytes), nameOff))} - return pkgPathName.name() -} - -/* - * The compiler knows the exact layout of all the data structures above. - * The compiler does not know about the data structures and methods below. - */ - -// resolveNameOff resolves a name offset from a base pointer. -// The (*rtype).nameOff method is a convenience wrapper for this function. -// Implemented in the runtime package. -// -//go:noescape -func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer - -// resolveTypeOff resolves an *rtype offset from a base type. -// The (*rtype).typeOff method is a convenience wrapper for this function. -// Implemented in the runtime package. -// -//go:noescape -func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer - -func (t rtype) nameOff(off nameOff) abi.Name { - return abi.Name{Bytes: (*byte)(resolveNameOff(unsafe.Pointer(t.Type), int32(off)))} -} - -func (t rtype) typeOff(off typeOff) *abi.Type { - return (*abi.Type)(resolveTypeOff(unsafe.Pointer(t.Type), int32(off))) -} - -func (t rtype) uncommon() *uncommonType { - return t.Uncommon() -} - -func (t rtype) String() string { - s := t.nameOff(t.Str).Name() - if t.TFlag&abi.TFlagExtraStar != 0 { - return s[1:] - } - return s -} - -func (t rtype) common() *abi.Type { return t.Type } - -func (t rtype) exportedMethods() []abi.Method { - ut := t.uncommon() - if ut == nil { - return nil - } - return ut.ExportedMethods() -} - -func (t rtype) NumMethod() int { - tt := t.Type.InterfaceType() - if tt != nil { - return tt.NumMethod() - } - return len(t.exportedMethods()) -} - -func (t rtype) PkgPath() string { - if t.TFlag&abi.TFlagNamed == 0 { - return "" - } - ut := t.uncommon() - if ut == nil { - return "" - } - return t.nameOff(ut.PkgPath).Name() -} - -func (t rtype) Name() string { - if !t.HasName() { - return "" - } - s := t.String() - i := len(s) - 1 - sqBrackets := 0 - for i >= 0 && (s[i] != '.' || sqBrackets != 0) { - switch s[i] { - case ']': - sqBrackets++ - case '[': - sqBrackets-- - } - i-- - } - return s[i+1:] -} - -func toRType(t *abi.Type) rtype { - return rtype{t} -} - -func elem(t *abi.Type) *abi.Type { - et := t.Elem() - if et != nil { - return et - } - panic("reflect: Elem of invalid type " + toRType(t).String()) -} - -func (t rtype) Elem() Type { - return toType(elem(t.common())) -} - -func (t rtype) In(i int) Type { - tt := t.Type.FuncType() - if tt == nil { - panic("reflect: In of non-func type") - } - return toType(tt.InSlice()[i]) -} - -func (t rtype) Key() Type { - tt := t.Type.MapType() - if tt == nil { - panic("reflect: Key of non-map type") - } - return toType(tt.Key) -} - -func (t rtype) Len() int { - tt := t.Type.ArrayType() - if tt == nil { - panic("reflect: Len of non-array type") - } - return int(tt.Len) -} - -func (t rtype) NumField() int { - tt := t.Type.StructType() - if tt == nil { - panic("reflect: NumField of non-struct type") - } - return len(tt.Fields) -} - -func (t rtype) NumIn() int { - tt := t.Type.FuncType() - if tt == nil { - panic("reflect: NumIn of non-func type") - } - return int(tt.InCount) -} - -func (t rtype) NumOut() int { - tt := t.Type.FuncType() - if tt == nil { - panic("reflect: NumOut of non-func type") - } - return tt.NumOut() -} - -func (t rtype) Out(i int) Type { - tt := t.Type.FuncType() - if tt == nil { - panic("reflect: Out of non-func type") - } - return toType(tt.OutSlice()[i]) -} - -// add returns p+x. -// -// The whySafe string is ignored, so that the function still inlines -// as efficiently as p+x, but all call sites should use the string to -// record why the addition is safe, which is to say why the addition -// does not cause x to advance to the very end of p's allocation -// and therefore point incorrectly at the next block in memory. -func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { - return unsafe.Pointer(uintptr(p) + x) -} - -// TypeOf returns the reflection Type that represents the dynamic type of i. -// If i is a nil interface value, TypeOf returns nil. -func TypeOf(i any) Type { - eface := *(*emptyInterface)(unsafe.Pointer(&i)) - // Noescape so this doesn't make i to escape. See the comment - // at Value.typ for why this is safe. - return toType((*abi.Type)(noescape(unsafe.Pointer(eface.typ)))) -} - -func (t rtype) Implements(u Type) bool { - if u == nil { - panic("reflect: nil type passed to Type.Implements") - } - if u.Kind() != Interface { - panic("reflect: non-interface type passed to Type.Implements") - } - return implements(u.common(), t.common()) -} - -func (t rtype) AssignableTo(u Type) bool { - if u == nil { - panic("reflect: nil type passed to Type.AssignableTo") - } - uu := u.common() - tt := t.common() - return directlyAssignable(uu, tt) || implements(uu, tt) -} - -func (t rtype) Comparable() bool { - return t.Equal != nil -} - -// implements reports whether the type V implements the interface type T. -func implements(T, V *abi.Type) bool { - t := T.InterfaceType() - if t == nil { - return false - } - if len(t.Methods) == 0 { - return true - } - rT := toRType(T) - rV := toRType(V) - - // The same algorithm applies in both cases, but the - // method tables for an interface type and a concrete type - // are different, so the code is duplicated. - // In both cases the algorithm is a linear scan over the two - // lists - T's methods and V's methods - simultaneously. - // Since method tables are stored in a unique sorted order - // (alphabetical, with no duplicate method names), the scan - // through V's methods must hit a match for each of T's - // methods along the way, or else V does not implement T. - // This lets us run the scan in overall linear time instead of - // the quadratic time a naive search would require. - // See also ../runtime/iface.go. - if V.Kind() == Interface { - v := (*interfaceType)(unsafe.Pointer(V)) - i := 0 - for j := 0; j < len(v.Methods); j++ { - tm := &t.Methods[i] - tmName := rT.nameOff(tm.Name) - vm := &v.Methods[j] - vmName := rV.nameOff(vm.Name) - if vmName.Name() == tmName.Name() && rV.typeOff(vm.Typ) == rT.typeOff(tm.Typ) { - if !tmName.IsExported() { - tmPkgPath := pkgPath(tmName) - if tmPkgPath == "" { - tmPkgPath = t.PkgPath.Name() - } - vmPkgPath := pkgPath(vmName) - if vmPkgPath == "" { - vmPkgPath = v.PkgPath.Name() - } - if tmPkgPath != vmPkgPath { - continue - } - } - if i++; i >= len(t.Methods) { - return true - } - } - } - return false - } - - v := V.Uncommon() - if v == nil { - return false - } - i := 0 - vmethods := v.Methods() - for j := 0; j < int(v.Mcount); j++ { - tm := &t.Methods[i] - tmName := rT.nameOff(tm.Name) - vm := vmethods[j] - vmName := rV.nameOff(vm.Name) - if vmName.Name() == tmName.Name() && rV.typeOff(vm.Mtyp) == rT.typeOff(tm.Typ) { - if !tmName.IsExported() { - tmPkgPath := pkgPath(tmName) - if tmPkgPath == "" { - tmPkgPath = t.PkgPath.Name() - } - vmPkgPath := pkgPath(vmName) - if vmPkgPath == "" { - vmPkgPath = rV.nameOff(v.PkgPath).Name() - } - if tmPkgPath != vmPkgPath { - continue - } - } - if i++; i >= len(t.Methods) { - return true - } - } - } - return false -} - -// directlyAssignable reports whether a value x of type V can be directly -// assigned (using memmove) to a value of type T. -// https://golang.org/doc/go_spec.html#Assignability -// Ignoring the interface rules (implemented elsewhere) -// and the ideal constant rules (no ideal constants at run time). -func directlyAssignable(T, V *abi.Type) bool { - // x's type V is identical to T? - if T == V { - return true - } - - // Otherwise at least one of T and V must not be defined - // and they must have the same kind. - if T.HasName() && V.HasName() || T.Kind() != V.Kind() { - return false - } - - // x's type T and V must have identical underlying types. - return haveIdenticalUnderlyingType(T, V, true) -} - -func haveIdenticalType(T, V *abi.Type, cmpTags bool) bool { - if cmpTags { - return T == V - } - - if toRType(T).Name() != toRType(V).Name() || T.Kind() != V.Kind() { - return false - } - - return haveIdenticalUnderlyingType(T, V, false) -} - -func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool { - if T == V { - return true - } - - kind := T.Kind() - if kind != V.Kind() { - return false - } - - // Non-composite types of equal kind have same underlying type - // (the predefined instance of the type). - if abi.Bool <= kind && kind <= abi.Complex128 || kind == abi.String || kind == abi.UnsafePointer { - return true - } - - // Composite types. - switch kind { - case abi.Array: - return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) - - case abi.Chan: - // Special case: - // x is a bidirectional channel value, T is a channel type, - // and x's type V and T have identical element types. - if V.ChanDir() == abi.BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) { - return true - } - - // Otherwise continue test for identical underlying type. - return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) - - case abi.Func: - t := (*funcType)(unsafe.Pointer(T)) - v := (*funcType)(unsafe.Pointer(V)) - if t.OutCount != v.OutCount || t.InCount != v.InCount { - return false - } - for i := 0; i < t.NumIn(); i++ { - if !haveIdenticalType(t.In(i), v.In(i), cmpTags) { - return false - } - } - for i := 0; i < t.NumOut(); i++ { - if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) { - return false - } - } - return true - - case Interface: - t := (*interfaceType)(unsafe.Pointer(T)) - v := (*interfaceType)(unsafe.Pointer(V)) - if len(t.Methods) == 0 && len(v.Methods) == 0 { - return true - } - // Might have the same methods but still - // need a run time conversion. - return false - - case abi.Map: - return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) - - case Ptr, abi.Slice: - return haveIdenticalType(T.Elem(), V.Elem(), cmpTags) - - case abi.Struct: - t := (*structType)(unsafe.Pointer(T)) - v := (*structType)(unsafe.Pointer(V)) - if len(t.Fields) != len(v.Fields) { - return false - } - if t.PkgPath.Name() != v.PkgPath.Name() { - return false - } - for i := range t.Fields { - tf := &t.Fields[i] - vf := &v.Fields[i] - if tf.Name.Name() != vf.Name.Name() { - return false - } - if !haveIdenticalType(tf.Typ, vf.Typ, cmpTags) { - return false - } - if cmpTags && tf.Name.Tag() != vf.Name.Tag() { - return false - } - if tf.Offset != vf.Offset { - return false - } - if tf.Embedded() != vf.Embedded() { - return false - } - } - return true - } - - return false -} - -// toType converts from a *rtype to a Type that can be returned -// to the client of package reflect. In gc, the only concern is that -// a nil *rtype must be replaced by a nil Type, but in gccgo this -// function takes care of ensuring that multiple *rtype for the same -// type are coalesced into a single Type. -func toType(t *abi.Type) Type { - if t == nil { - return nil - } - return toRType(t) -} - -// ifaceIndir reports whether t is stored indirectly in an interface value. -func ifaceIndir(t *abi.Type) bool { - return t.Kind_&abi.KindDirectIface == 0 -} diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/value.go b/contrib/go/_std_1.22/src/internal/reflectlite/value.go deleted file mode 100644 index c47e5ea12b3c..000000000000 --- a/contrib/go/_std_1.22/src/internal/reflectlite/value.go +++ /dev/null @@ -1,493 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package reflectlite - -import ( - "internal/abi" - "internal/goarch" - "internal/unsafeheader" - "runtime" - "unsafe" -) - -// Value is the reflection interface to a Go value. -// -// Not all methods apply to all kinds of values. Restrictions, -// if any, are noted in the documentation for each method. -// Use the Kind method to find out the kind of value before -// calling kind-specific methods. Calling a method -// inappropriate to the kind of type causes a run time panic. -// -// The zero Value represents no value. -// Its IsValid method returns false, its Kind method returns Invalid, -// its String method returns "", and all other methods panic. -// Most functions and methods never return an invalid value. -// If one does, its documentation states the conditions explicitly. -// -// A Value can be used concurrently by multiple goroutines provided that -// the underlying Go value can be used concurrently for the equivalent -// direct operations. -// -// To compare two Values, compare the results of the Interface method. -// Using == on two Values does not compare the underlying values -// they represent. -type Value struct { - // typ_ holds the type of the value represented by a Value. - // Access using the typ method to avoid escape of v. - typ_ *abi.Type - - // Pointer-valued data or, if flagIndir is set, pointer to data. - // Valid when either flagIndir is set or typ.pointers() is true. - ptr unsafe.Pointer - - // flag holds metadata about the value. - // The lowest bits are flag bits: - // - flagStickyRO: obtained via unexported not embedded field, so read-only - // - flagEmbedRO: obtained via unexported embedded field, so read-only - // - flagIndir: val holds a pointer to the data - // - flagAddr: v.CanAddr is true (implies flagIndir) - // Value cannot represent method values. - // The next five bits give the Kind of the value. - // This repeats typ.Kind() except for method values. - // The remaining 23+ bits give a method number for method values. - // If flag.kind() != Func, code can assume that flagMethod is unset. - // If ifaceIndir(typ), code can assume that flagIndir is set. - flag - - // A method value represents a curried method invocation - // like r.Read for some receiver r. The typ+val+flag bits describe - // the receiver r, but the flag's Kind bits say Func (methods are - // functions), and the top bits of the flag give the method number - // in r's type's method table. -} - -type flag uintptr - -const ( - flagKindWidth = 5 // there are 27 kinds - flagKindMask flag = 1<= len, -// because then the result will point outside the array. -// whySafe must explain why i < len. (Passing "i < len" is fine; -// the benefit is to surface this assumption at the call site.) -func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer { - return add(p, uintptr(i)*eltSize, "i < len") -} - -func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) - -// typedmemmove copies a value of type t to dst from src. -// -//go:noescape -func typedmemmove(t *abi.Type, dst, src unsafe.Pointer) - -// Dummy annotation marking that the value x escapes, -// for use in cases where the reflect code is so clever that -// the compiler cannot follow. -func escapes(x any) { - if dummy.b { - dummy.x = x - } -} - -var dummy struct { - b bool - x any -} - -//go:nosplit -func noescape(p unsafe.Pointer) unsafe.Pointer { - x := uintptr(p) - return unsafe.Pointer(x ^ 0) -} diff --git a/contrib/go/_std_1.22/src/internal/safefilepath/path.go b/contrib/go/_std_1.22/src/internal/safefilepath/path.go deleted file mode 100644 index 0f0a270c3034..000000000000 --- a/contrib/go/_std_1.22/src/internal/safefilepath/path.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package safefilepath manipulates operating-system file paths. -package safefilepath - -import ( - "errors" -) - -var errInvalidPath = errors.New("invalid path") - -// FromFS converts a slash-separated path into an operating-system path. -// -// FromFS returns an error if the path cannot be represented by the operating -// system. For example, paths containing '\' and ':' characters are rejected -// on Windows. -func FromFS(path string) (string, error) { - return fromFS(path) -} diff --git a/contrib/go/_std_1.22/src/internal/safefilepath/path_other.go b/contrib/go/_std_1.22/src/internal/safefilepath/path_other.go deleted file mode 100644 index 974e7751a290..000000000000 --- a/contrib/go/_std_1.22/src/internal/safefilepath/path_other.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !windows - -package safefilepath - -import "runtime" - -func fromFS(path string) (string, error) { - if runtime.GOOS == "plan9" { - if len(path) > 0 && path[0] == '#' { - return "", errInvalidPath - } - } - for i := range path { - if path[i] == 0 { - return "", errInvalidPath - } - } - return path, nil -} diff --git a/contrib/go/_std_1.22/src/internal/safefilepath/path_windows.go b/contrib/go/_std_1.22/src/internal/safefilepath/path_windows.go deleted file mode 100644 index 7cfd6ce2eac2..000000000000 --- a/contrib/go/_std_1.22/src/internal/safefilepath/path_windows.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package safefilepath - -import ( - "syscall" - "unicode/utf8" -) - -func fromFS(path string) (string, error) { - if !utf8.ValidString(path) { - return "", errInvalidPath - } - for len(path) > 1 && path[0] == '/' && path[1] == '/' { - path = path[1:] - } - containsSlash := false - for p := path; p != ""; { - // Find the next path element. - i := 0 - for i < len(p) && p[i] != '/' { - switch p[i] { - case 0, '\\', ':': - return "", errInvalidPath - } - i++ - } - part := p[:i] - if i < len(p) { - containsSlash = true - p = p[i+1:] - } else { - p = "" - } - if IsReservedName(part) { - return "", errInvalidPath - } - } - if containsSlash { - // We can't depend on strings, so substitute \ for / manually. - buf := []byte(path) - for i, b := range buf { - if b == '/' { - buf[i] = '\\' - } - } - path = string(buf) - } - return path, nil -} - -// IsReservedName reports if name is a Windows reserved device name. -// It does not detect names with an extension, which are also reserved on some Windows versions. -// -// For details, search for PRN in -// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. -func IsReservedName(name string) bool { - // Device names can have arbitrary trailing characters following a dot or colon. - base := name - for i := 0; i < len(base); i++ { - switch base[i] { - case ':', '.': - base = base[:i] - } - } - // Trailing spaces in the last path element are ignored. - for len(base) > 0 && base[len(base)-1] == ' ' { - base = base[:len(base)-1] - } - if !isReservedBaseName(base) { - return false - } - if len(base) == len(name) { - return true - } - // The path element is a reserved name with an extension. - // Some Windows versions consider this a reserved name, - // while others do not. Use FullPath to see if the name is - // reserved. - if p, _ := syscall.FullPath(name); len(p) >= 4 && p[:4] == `\\.\` { - return true - } - return false -} - -func isReservedBaseName(name string) bool { - if len(name) == 3 { - switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { - case "CON", "PRN", "AUX", "NUL": - return true - } - } - if len(name) >= 4 { - switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { - case "COM", "LPT": - if len(name) == 4 && '1' <= name[3] && name[3] <= '9' { - return true - } - // Superscript ¹, ², and ³ are considered numbers as well. - switch name[3:] { - case "\u00b2", "\u00b3", "\u00b9": - return true - } - return false - } - } - - // Passing CONIN$ or CONOUT$ to CreateFile opens a console handle. - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#consoles - // - // While CONIN$ and CONOUT$ aren't documented as being files, - // they behave the same as CON. For example, ./CONIN$ also opens the console input. - if len(name) == 6 && name[5] == '$' && equalFold(name, "CONIN$") { - return true - } - if len(name) == 7 && name[6] == '$' && equalFold(name, "CONOUT$") { - return true - } - return false -} - -func equalFold(a, b string) bool { - if len(a) != len(b) { - return false - } - for i := 0; i < len(a); i++ { - if toUpper(a[i]) != toUpper(b[i]) { - return false - } - } - return true -} - -func toUpper(c byte) byte { - if 'a' <= c && c <= 'z' { - return c - ('a' - 'A') - } - return c -} diff --git a/contrib/go/_std_1.22/src/internal/safefilepath/ya.make b/contrib/go/_std_1.22/src/internal/safefilepath/ya.make deleted file mode 100644 index 9b77c8250297..000000000000 --- a/contrib/go/_std_1.22/src/internal/safefilepath/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - path.go - path_other.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - path.go - path_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/syscall/execenv/ya.make b/contrib/go/_std_1.22/src/internal/syscall/execenv/ya.make deleted file mode 100644 index 523cb40ae2e6..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/execenv/ya.make +++ /dev/null @@ -1,11 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - execenv_default.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - execenv_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_solaris.go b/contrib/go/_std_1.22/src/internal/syscall/unix/at_solaris.go deleted file mode 100644 index 4ab224d670b9..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/at_solaris.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unix - -import "syscall" - -// Implemented as sysvicall6 in runtime/syscall_solaris.go. -func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) - -//go:cgo_import_dynamic libc_fstatat fstatat "libc.so" -//go:cgo_import_dynamic libc_openat openat "libc.so" -//go:cgo_import_dynamic libc_unlinkat unlinkat "libc.so" - -const ( - AT_REMOVEDIR = 0x1 - AT_SYMLINK_NOFOLLOW = 0x1000 - - UTIME_OMIT = -0x2 -) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_darwin.go b/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_darwin.go deleted file mode 100644 index 208ff34d038e..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_darwin.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unix - -const AT_REMOVEDIR = 0x80 -const AT_SYMLINK_NOFOLLOW = 0x0020 - -const UTIME_OMIT = -0x2 diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_dragonfly.go b/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_dragonfly.go deleted file mode 100644 index 9ac1f919f147..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_dragonfly.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unix - -import "syscall" - -const unlinkatTrap uintptr = syscall.SYS_UNLINKAT -const openatTrap uintptr = syscall.SYS_OPENAT -const fstatatTrap uintptr = syscall.SYS_FSTATAT - -const ( - AT_EACCESS = 0x4 - AT_FDCWD = 0xfffafdcd - AT_REMOVEDIR = 0x2 - AT_SYMLINK_NOFOLLOW = 0x1 - - UTIME_OMIT = -0x1 -) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_openbsd.go b/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_openbsd.go deleted file mode 100644 index fd389477ec33..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_openbsd.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unix - -import "syscall" - -const unlinkatTrap uintptr = syscall.SYS_UNLINKAT -const openatTrap uintptr = syscall.SYS_OPENAT -const fstatatTrap uintptr = syscall.SYS_FSTATAT - -const AT_REMOVEDIR = 0x08 -const AT_SYMLINK_NOFOLLOW = 0x02 - -const UTIME_OMIT = -0x1 diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/constants.go b/contrib/go/_std_1.22/src/internal/syscall/unix/constants.go deleted file mode 100644 index e3245897055c..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/constants.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix - -package unix - -const ( - R_OK = 0x4 - W_OK = 0x2 - X_OK = 0x1 -) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.go b/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.go deleted file mode 100644 index 834099ffed64..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && !ios - -package unix - -import ( - "internal/abi" - "unsafe" -) - -//go:cgo_import_dynamic libc_getentropy getentropy "/usr/lib/libSystem.B.dylib" - -func libc_getentropy_trampoline() - -// GetEntropy calls the macOS getentropy system call. -func GetEntropy(p []byte) error { - _, _, errno := syscall_syscall(abi.FuncPCABI0(libc_getentropy_trampoline), - uintptr(unsafe.Pointer(&p[0])), - uintptr(len(p)), - 0) - if errno != 0 { - return errno - } - return nil -} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.s b/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.s deleted file mode 100644 index f41e0fe97b09..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.s +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && !ios - -#include "textflag.h" - -TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0; JMP libc_getentropy(SB) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/pidfd_linux.go b/contrib/go/_std_1.22/src/internal/syscall/unix/pidfd_linux.go deleted file mode 100644 index 02cfaa062cae..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/pidfd_linux.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unix - -import "syscall" - -func PidFDSendSignal(pidfd uintptr, s syscall.Signal) error { - _, _, errno := syscall.Syscall(pidfdSendSignalTrap, pidfd, uintptr(s), 0) - if errno != 0 { - return errno - } - return nil -} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/ya.make b/contrib/go/_std_1.22/src/internal/syscall/unix/ya.make deleted file mode 100644 index a8f44da8e800..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/ya.make +++ /dev/null @@ -1,60 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - asm_darwin.s - at_libc2.go - at_sysnum_darwin.go - constants.go - eaccess_other.go - fcntl_unix.go - getentropy_darwin.go - getentropy_darwin.s - kernel_version_other.go - net.go - net_darwin.go - nonblocking_unix.go - pty_darwin.go - user_darwin.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - at.go - at_fstatat.go - at_sysnum_fstatat_linux.go - at_sysnum_linux.go - constants.go - copy_file_range_linux.go - eaccess_linux.go - fcntl_unix.go - getrandom.go - getrandom_linux.go - kernel_version_linux.go - net.go - nonblocking_unix.go - pidfd_linux.go - sysnum_linux_generic.go - ) -ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - at.go - at_fstatat.go - at_sysnum_linux.go - at_sysnum_newfstatat_linux.go - constants.go - copy_file_range_linux.go - eaccess_linux.go - fcntl_unix.go - getrandom.go - getrandom_linux.go - kernel_version_linux.go - net.go - nonblocking_unix.go - pidfd_linux.go - sysnum_linux_amd64.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - kernel_version_other.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/net_windows.go b/contrib/go/_std_1.22/src/internal/syscall/windows/net_windows.go deleted file mode 100644 index 42c600c1447d..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/net_windows.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package windows - -import ( - "sync" - "syscall" - _ "unsafe" -) - -//go:linkname WSASendtoInet4 syscall.wsaSendtoInet4 -//go:noescape -func WSASendtoInet4(s syscall.Handle, bufs *syscall.WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *syscall.SockaddrInet4, overlapped *syscall.Overlapped, croutine *byte) (err error) - -//go:linkname WSASendtoInet6 syscall.wsaSendtoInet6 -//go:noescape -func WSASendtoInet6(s syscall.Handle, bufs *syscall.WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *syscall.SockaddrInet6, overlapped *syscall.Overlapped, croutine *byte) (err error) - -const ( - SIO_TCP_INITIAL_RTO = syscall.IOC_IN | syscall.IOC_VENDOR | 17 - TCP_INITIAL_RTO_UNSPECIFIED_RTT = ^uint16(0) - TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS = ^uint8(1) -) - -type TCP_INITIAL_RTO_PARAMETERS struct { - Rtt uint16 - MaxSynRetransmissions uint8 -} - -var Support_TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS = sync.OnceValue(func() bool { - var maj, min, build uint32 - rtlGetNtVersionNumbers(&maj, &min, &build) - return maj >= 10 && build&0xffff >= 16299 -}) - -//go:linkname rtlGetNtVersionNumbers syscall.rtlGetNtVersionNumbers -//go:noescape -func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/syscall_windows.go b/contrib/go/_std_1.22/src/internal/syscall/windows/syscall_windows.go deleted file mode 100644 index d10e30cb6825..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/syscall_windows.go +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package windows - -import ( - "sync" - "syscall" - "unsafe" -) - -// UTF16PtrToString is like UTF16ToString, but takes *uint16 -// as a parameter instead of []uint16. -func UTF16PtrToString(p *uint16) string { - if p == nil { - return "" - } - end := unsafe.Pointer(p) - n := 0 - for *(*uint16)(end) != 0 { - end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p)) - n++ - } - return syscall.UTF16ToString(unsafe.Slice(p, n)) -} - -const ( - ERROR_BAD_LENGTH syscall.Errno = 24 - ERROR_SHARING_VIOLATION syscall.Errno = 32 - ERROR_LOCK_VIOLATION syscall.Errno = 33 - ERROR_NOT_SUPPORTED syscall.Errno = 50 - ERROR_CALL_NOT_IMPLEMENTED syscall.Errno = 120 - ERROR_INVALID_NAME syscall.Errno = 123 - ERROR_LOCK_FAILED syscall.Errno = 167 - ERROR_NO_UNICODE_TRANSLATION syscall.Errno = 1113 -) - -const GAA_FLAG_INCLUDE_PREFIX = 0x00000010 - -const ( - IF_TYPE_OTHER = 1 - IF_TYPE_ETHERNET_CSMACD = 6 - IF_TYPE_ISO88025_TOKENRING = 9 - IF_TYPE_PPP = 23 - IF_TYPE_SOFTWARE_LOOPBACK = 24 - IF_TYPE_ATM = 37 - IF_TYPE_IEEE80211 = 71 - IF_TYPE_TUNNEL = 131 - IF_TYPE_IEEE1394 = 144 -) - -type SocketAddress struct { - Sockaddr *syscall.RawSockaddrAny - SockaddrLength int32 -} - -type IpAdapterUnicastAddress struct { - Length uint32 - Flags uint32 - Next *IpAdapterUnicastAddress - Address SocketAddress - PrefixOrigin int32 - SuffixOrigin int32 - DadState int32 - ValidLifetime uint32 - PreferredLifetime uint32 - LeaseLifetime uint32 - OnLinkPrefixLength uint8 -} - -type IpAdapterAnycastAddress struct { - Length uint32 - Flags uint32 - Next *IpAdapterAnycastAddress - Address SocketAddress -} - -type IpAdapterMulticastAddress struct { - Length uint32 - Flags uint32 - Next *IpAdapterMulticastAddress - Address SocketAddress -} - -type IpAdapterDnsServerAdapter struct { - Length uint32 - Reserved uint32 - Next *IpAdapterDnsServerAdapter - Address SocketAddress -} - -type IpAdapterPrefix struct { - Length uint32 - Flags uint32 - Next *IpAdapterPrefix - Address SocketAddress - PrefixLength uint32 -} - -type IpAdapterAddresses struct { - Length uint32 - IfIndex uint32 - Next *IpAdapterAddresses - AdapterName *byte - FirstUnicastAddress *IpAdapterUnicastAddress - FirstAnycastAddress *IpAdapterAnycastAddress - FirstMulticastAddress *IpAdapterMulticastAddress - FirstDnsServerAddress *IpAdapterDnsServerAdapter - DnsSuffix *uint16 - Description *uint16 - FriendlyName *uint16 - PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte - PhysicalAddressLength uint32 - Flags uint32 - Mtu uint32 - IfType uint32 - OperStatus uint32 - Ipv6IfIndex uint32 - ZoneIndices [16]uint32 - FirstPrefix *IpAdapterPrefix - /* more fields might be present here. */ -} - -type SecurityAttributes struct { - Length uint16 - SecurityDescriptor uintptr - InheritHandle bool -} - -type FILE_BASIC_INFO struct { - CreationTime int64 - LastAccessTime int64 - LastWriteTime int64 - ChangedTime int64 - FileAttributes uint32 - - // Pad out to 8-byte alignment. - // - // Without this padding, TestChmod fails due to an argument validation error - // in SetFileInformationByHandle on windows/386. - // - // https://learn.microsoft.com/en-us/cpp/build/reference/zp-struct-member-alignment?view=msvc-170 - // says that “The C/C++ headers in the Windows SDK assume the platform's - // default alignment is used.” What we see here is padding rather than - // alignment, but maybe it is related. - _ uint32 -} - -const ( - IfOperStatusUp = 1 - IfOperStatusDown = 2 - IfOperStatusTesting = 3 - IfOperStatusUnknown = 4 - IfOperStatusDormant = 5 - IfOperStatusNotPresent = 6 - IfOperStatusLowerLayerDown = 7 -) - -//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses -//sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW -//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW -//sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW -//sys SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf unsafe.Pointer, bufsize uint32) (err error) = kernel32.SetFileInformationByHandle -//sys VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQuery -//sys GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPath2W - -const ( - // flags for CreateToolhelp32Snapshot - TH32CS_SNAPMODULE = 0x08 - TH32CS_SNAPMODULE32 = 0x10 -) - -const MAX_MODULE_NAME32 = 255 - -type ModuleEntry32 struct { - Size uint32 - ModuleID uint32 - ProcessID uint32 - GlblcntUsage uint32 - ProccntUsage uint32 - ModBaseAddr uintptr - ModBaseSize uint32 - ModuleHandle syscall.Handle - Module [MAX_MODULE_NAME32 + 1]uint16 - ExePath [syscall.MAX_PATH]uint16 -} - -const SizeofModuleEntry32 = unsafe.Sizeof(ModuleEntry32{}) - -//sys Module32First(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW -//sys Module32Next(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32NextW - -const ( - WSA_FLAG_OVERLAPPED = 0x01 - WSA_FLAG_NO_HANDLE_INHERIT = 0x80 - - WSAEMSGSIZE syscall.Errno = 10040 - - MSG_PEEK = 0x2 - MSG_TRUNC = 0x0100 - MSG_CTRUNC = 0x0200 - - socket_error = uintptr(^uint32(0)) -) - -var WSAID_WSASENDMSG = syscall.GUID{ - Data1: 0xa441e712, - Data2: 0x754f, - Data3: 0x43ca, - Data4: [8]byte{0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d}, -} - -var WSAID_WSARECVMSG = syscall.GUID{ - Data1: 0xf689d7c8, - Data2: 0x6f1f, - Data3: 0x436b, - Data4: [8]byte{0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22}, -} - -var sendRecvMsgFunc struct { - once sync.Once - sendAddr uintptr - recvAddr uintptr - err error -} - -type WSAMsg struct { - Name syscall.Pointer - Namelen int32 - Buffers *syscall.WSABuf - BufferCount uint32 - Control syscall.WSABuf - Flags uint32 -} - -//sys WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = ws2_32.WSASocketW - -func loadWSASendRecvMsg() error { - sendRecvMsgFunc.once.Do(func() { - var s syscall.Handle - s, sendRecvMsgFunc.err = syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) - if sendRecvMsgFunc.err != nil { - return - } - defer syscall.CloseHandle(s) - var n uint32 - sendRecvMsgFunc.err = syscall.WSAIoctl(s, - syscall.SIO_GET_EXTENSION_FUNCTION_POINTER, - (*byte)(unsafe.Pointer(&WSAID_WSARECVMSG)), - uint32(unsafe.Sizeof(WSAID_WSARECVMSG)), - (*byte)(unsafe.Pointer(&sendRecvMsgFunc.recvAddr)), - uint32(unsafe.Sizeof(sendRecvMsgFunc.recvAddr)), - &n, nil, 0) - if sendRecvMsgFunc.err != nil { - return - } - sendRecvMsgFunc.err = syscall.WSAIoctl(s, - syscall.SIO_GET_EXTENSION_FUNCTION_POINTER, - (*byte)(unsafe.Pointer(&WSAID_WSASENDMSG)), - uint32(unsafe.Sizeof(WSAID_WSASENDMSG)), - (*byte)(unsafe.Pointer(&sendRecvMsgFunc.sendAddr)), - uint32(unsafe.Sizeof(sendRecvMsgFunc.sendAddr)), - &n, nil, 0) - }) - return sendRecvMsgFunc.err -} - -func WSASendMsg(fd syscall.Handle, msg *WSAMsg, flags uint32, bytesSent *uint32, overlapped *syscall.Overlapped, croutine *byte) error { - err := loadWSASendRecvMsg() - if err != nil { - return err - } - r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.sendAddr, 6, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(flags), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) - if r1 == socket_error { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return err -} - -func WSARecvMsg(fd syscall.Handle, msg *WSAMsg, bytesReceived *uint32, overlapped *syscall.Overlapped, croutine *byte) error { - err := loadWSASendRecvMsg() - if err != nil { - return err - } - r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.recvAddr, 5, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(bytesReceived)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0) - if r1 == socket_error { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return err -} - -const ( - ComputerNameNetBIOS = 0 - ComputerNameDnsHostname = 1 - ComputerNameDnsDomain = 2 - ComputerNameDnsFullyQualified = 3 - ComputerNamePhysicalNetBIOS = 4 - ComputerNamePhysicalDnsHostname = 5 - ComputerNamePhysicalDnsDomain = 6 - ComputerNamePhysicalDnsFullyQualified = 7 - ComputerNameMax = 8 - - MOVEFILE_REPLACE_EXISTING = 0x1 - MOVEFILE_COPY_ALLOWED = 0x2 - MOVEFILE_DELAY_UNTIL_REBOOT = 0x4 - MOVEFILE_WRITE_THROUGH = 0x8 - MOVEFILE_CREATE_HARDLINK = 0x10 - MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 -) - -func Rename(oldpath, newpath string) error { - from, err := syscall.UTF16PtrFromString(oldpath) - if err != nil { - return err - } - to, err := syscall.UTF16PtrFromString(newpath) - if err != nil { - return err - } - return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) -} - -//sys LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) = kernel32.LockFileEx -//sys UnlockFileEx(file syscall.Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) = kernel32.UnlockFileEx - -const ( - LOCKFILE_FAIL_IMMEDIATELY = 0x00000001 - LOCKFILE_EXCLUSIVE_LOCK = 0x00000002 -) - -const MB_ERR_INVALID_CHARS = 8 - -//sys GetACP() (acp uint32) = kernel32.GetACP -//sys GetConsoleCP() (ccp uint32) = kernel32.GetConsoleCP -//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar -//sys GetCurrentThread() (pseudoHandle syscall.Handle, err error) = kernel32.GetCurrentThread - -// Constants from lmshare.h -const ( - STYPE_DISKTREE = 0x00 - STYPE_TEMPORARY = 0x40000000 -) - -type SHARE_INFO_2 struct { - Netname *uint16 - Type uint32 - Remark *uint16 - Permissions uint32 - MaxUses uint32 - CurrentUses uint32 - Path *uint16 - Passwd *uint16 -} - -//sys NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) = netapi32.NetShareAdd -//sys NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) = netapi32.NetShareDel - -const ( - FILE_NAME_NORMALIZED = 0x0 - FILE_NAME_OPENED = 0x8 - - VOLUME_NAME_DOS = 0x0 - VOLUME_NAME_GUID = 0x1 - VOLUME_NAME_NONE = 0x4 - VOLUME_NAME_NT = 0x2 -) - -//sys GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) = kernel32.GetFinalPathNameByHandleW - -func ErrorLoadingGetTempPath2() error { - return procGetTempPath2W.Find() -} - -//sys CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock -//sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock -//sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW - -//sys ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng - -type FILE_ID_BOTH_DIR_INFO struct { - NextEntryOffset uint32 - FileIndex uint32 - CreationTime syscall.Filetime - LastAccessTime syscall.Filetime - LastWriteTime syscall.Filetime - ChangeTime syscall.Filetime - EndOfFile uint64 - AllocationSize uint64 - FileAttributes uint32 - FileNameLength uint32 - EaSize uint32 - ShortNameLength uint32 - ShortName [12]uint16 - FileID uint64 - FileName [1]uint16 -} - -type FILE_FULL_DIR_INFO struct { - NextEntryOffset uint32 - FileIndex uint32 - CreationTime syscall.Filetime - LastAccessTime syscall.Filetime - LastWriteTime syscall.Filetime - ChangeTime syscall.Filetime - EndOfFile uint64 - AllocationSize uint64 - FileAttributes uint32 - FileNameLength uint32 - EaSize uint32 - FileName [1]uint16 -} - -//sys GetVolumeInformationByHandle(file syscall.Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) = GetVolumeInformationByHandleW -//sys GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) = GetVolumeNameForVolumeMountPointW - -//sys RtlLookupFunctionEntry(pc uintptr, baseAddress *uintptr, table *byte) (ret uintptr) = kernel32.RtlLookupFunctionEntry -//sys RtlVirtualUnwind(handlerType uint32, baseAddress uintptr, pc uintptr, entry uintptr, ctxt uintptr, data *uintptr, frame *uintptr, ctxptrs *byte) (ret uintptr) = kernel32.RtlVirtualUnwind - -type SERVICE_STATUS struct { - ServiceType uint32 - CurrentState uint32 - ControlsAccepted uint32 - Win32ExitCode uint32 - ServiceSpecificExitCode uint32 - CheckPoint uint32 - WaitHint uint32 -} - -const ( - SERVICE_RUNNING = 4 - SERVICE_QUERY_STATUS = 4 -) - -//sys OpenService(mgr syscall.Handle, serviceName *uint16, access uint32) (handle syscall.Handle, err error) = advapi32.OpenServiceW -//sys QueryServiceStatus(hService syscall.Handle, lpServiceStatus *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus -//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle syscall.Handle, err error) [failretval==0] = advapi32.OpenSCManagerW diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/ya.make b/contrib/go/_std_1.22/src/internal/syscall/windows/ya.make deleted file mode 100644 index e1b38ff2f290..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/ya.make +++ /dev/null @@ -1,14 +0,0 @@ -GO_LIBRARY() -IF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - memory_windows.go - net_windows.go - psapi_windows.go - reparse_windows.go - security_windows.go - symlink_windows.go - syscall_windows.go - zsyscall_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/zsyscall_windows.go b/contrib/go/_std_1.22/src/internal/syscall/windows/zsyscall_windows.go deleted file mode 100644 index 931f157cf166..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/zsyscall_windows.go +++ /dev/null @@ -1,436 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package windows - -import ( - "internal/syscall/windows/sysdll" - "syscall" - "unsafe" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) - errERROR_EINVAL error = syscall.EINVAL -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -func errnoErr(e syscall.Errno) error { - switch e { - case 0: - return errERROR_EINVAL - case errnoERROR_IO_PENDING: - return errERROR_IO_PENDING - } - // TODO: add more here, after collecting data on the common - // error values see on Windows. (perhaps when running - // all.bat?) - return e -} - -var ( - modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) - modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll")) - modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) - modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) - modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) - modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) - moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) - modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) - - procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") - procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") - procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") - procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") - procOpenSCManagerW = modadvapi32.NewProc("OpenSCManagerW") - procOpenServiceW = modadvapi32.NewProc("OpenServiceW") - procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") - procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") - procRevertToSelf = modadvapi32.NewProc("RevertToSelf") - procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") - procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng") - procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") - procCreateEventW = modkernel32.NewProc("CreateEventW") - procGetACP = modkernel32.NewProc("GetACP") - procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") - procGetConsoleCP = modkernel32.NewProc("GetConsoleCP") - procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") - procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx") - procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW") - procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") - procGetTempPath2W = modkernel32.NewProc("GetTempPath2W") - procGetVolumeInformationByHandleW = modkernel32.NewProc("GetVolumeInformationByHandleW") - procGetVolumeNameForVolumeMountPointW = modkernel32.NewProc("GetVolumeNameForVolumeMountPointW") - procLockFileEx = modkernel32.NewProc("LockFileEx") - procModule32FirstW = modkernel32.NewProc("Module32FirstW") - procModule32NextW = modkernel32.NewProc("Module32NextW") - procMoveFileExW = modkernel32.NewProc("MoveFileExW") - procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar") - procRtlLookupFunctionEntry = modkernel32.NewProc("RtlLookupFunctionEntry") - procRtlVirtualUnwind = modkernel32.NewProc("RtlVirtualUnwind") - procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle") - procUnlockFileEx = modkernel32.NewProc("UnlockFileEx") - procVirtualQuery = modkernel32.NewProc("VirtualQuery") - procNetShareAdd = modnetapi32.NewProc("NetShareAdd") - procNetShareDel = modnetapi32.NewProc("NetShareDel") - procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups") - procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") - procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock") - procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock") - procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW") - procWSASocketW = modws2_32.NewProc("WSASocketW") -) - -func adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) { - var _p0 uint32 - if disableAllPrivileges { - _p0 = 1 - } - r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen))) - ret = uint32(r0) - if true { - err = errnoErr(e1) - } - return -} - -func DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) { - r1, _, e1 := syscall.Syscall6(procDuplicateTokenEx.Addr(), 6, uintptr(hExistingToken), uintptr(dwDesiredAccess), uintptr(unsafe.Pointer(lpTokenAttributes)), uintptr(impersonationLevel), uintptr(tokenType), uintptr(unsafe.Pointer(phNewToken))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func ImpersonateSelf(impersonationlevel uint32) (err error) { - r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) { - r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemname)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(access)) - handle = syscall.Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func OpenService(mgr syscall.Handle, serviceName *uint16, access uint32) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall(procOpenServiceW.Addr(), 3, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(access)) - handle = syscall.Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) { - var _p0 uint32 - if openasself { - _p0 = 1 - } - r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(h), uintptr(access), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func QueryServiceStatus(hService syscall.Handle, lpServiceStatus *SERVICE_STATUS) (err error) { - r1, _, e1 := syscall.Syscall(procQueryServiceStatus.Addr(), 2, uintptr(hService), uintptr(unsafe.Pointer(lpServiceStatus)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func RevertToSelf() (err error) { - r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation uintptr, tokenInformationLength uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetTokenInformation.Addr(), 4, uintptr(tokenHandle), uintptr(tokenInformationClass), uintptr(tokenInformation), uintptr(tokenInformationLength), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func ProcessPrng(buf []byte) (err error) { - var _p0 *byte - if len(buf) > 0 { - _p0 = &buf[0] - } - r1, _, e1 := syscall.Syscall(procProcessPrng.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { - r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) - if r0 != 0 { - errcode = syscall.Errno(r0) - } - return -} - -func CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttrs)), uintptr(manualReset), uintptr(initialState), uintptr(unsafe.Pointer(name)), 0, 0) - handle = syscall.Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func GetACP() (acp uint32) { - r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0) - acp = uint32(r0) - return -} - -func GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nameformat), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetConsoleCP() (ccp uint32) { - r0, _, _ := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0) - ccp = uint32(r0) - return -} - -func GetCurrentThread() (pseudoHandle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) - pseudoHandle = syscall.Handle(r0) - if pseudoHandle == 0 { - err = errnoErr(e1) - } - return -} - -func GetFileInformationByHandleEx(handle syscall.Handle, class uint32, info *byte, bufsize uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(handle), uintptr(class), uintptr(unsafe.Pointer(info)), uintptr(bufsize), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetModuleFileNameW.Addr(), 3, uintptr(module), uintptr(unsafe.Pointer(fn)), uintptr(len)) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetTempPath2W.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetVolumeInformationByHandle(file syscall.Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procGetVolumeInformationByHandleW.Addr(), 8, uintptr(file), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetVolumeNameForVolumeMountPointW.Addr(), 3, uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferlength)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) { - r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(file), uintptr(flags), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func Module32First(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procModule32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func Module32Next(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procModule32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) { - r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar)) - nwrite = int32(r0) - if nwrite == 0 { - err = errnoErr(e1) - } - return -} - -func RtlLookupFunctionEntry(pc uintptr, baseAddress *uintptr, table *byte) (ret uintptr) { - r0, _, _ := syscall.Syscall(procRtlLookupFunctionEntry.Addr(), 3, uintptr(pc), uintptr(unsafe.Pointer(baseAddress)), uintptr(unsafe.Pointer(table))) - ret = uintptr(r0) - return -} - -func RtlVirtualUnwind(handlerType uint32, baseAddress uintptr, pc uintptr, entry uintptr, ctxt uintptr, data *uintptr, frame *uintptr, ctxptrs *byte) (ret uintptr) { - r0, _, _ := syscall.Syscall9(procRtlVirtualUnwind.Addr(), 8, uintptr(handlerType), uintptr(baseAddress), uintptr(pc), uintptr(entry), uintptr(ctxt), uintptr(unsafe.Pointer(data)), uintptr(unsafe.Pointer(frame)), uintptr(unsafe.Pointer(ctxptrs)), 0) - ret = uintptr(r0) - return -} - -func SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf unsafe.Pointer, bufsize uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(handle), uintptr(fileInformationClass), uintptr(buf), uintptr(bufsize), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func UnlockFileEx(file syscall.Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) { - r1, _, e1 := syscall.Syscall6(procUnlockFileEx.Addr(), 5, uintptr(file), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procVirtualQuery.Addr(), 3, uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) { - r0, _, _ := syscall.Syscall6(procNetShareAdd.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(parmErr)), 0, 0) - if r0 != 0 { - neterr = syscall.Errno(r0) - } - return -} - -func NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) { - r0, _, _ := syscall.Syscall(procNetShareDel.Addr(), 3, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(netName)), uintptr(reserved)) - if r0 != 0 { - neterr = syscall.Errno(r0) - } - return -} - -func NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, flags uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32) (neterr error) { - r0, _, _ := syscall.Syscall9(procNetUserGetLocalGroups.Addr(), 8, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(flags), uintptr(unsafe.Pointer(buf)), uintptr(prefMaxLen), uintptr(unsafe.Pointer(entriesRead)), uintptr(unsafe.Pointer(totalEntries)), 0) - if r0 != 0 { - neterr = syscall.Errno(r0) - } - return -} - -func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(memCounters)), uintptr(cb)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) { - var _p0 uint32 - if inheritExisting { - _p0 = 1 - } - r1, _, e1 := syscall.Syscall(procCreateEnvironmentBlock.Addr(), 3, uintptr(unsafe.Pointer(block)), uintptr(token), uintptr(_p0)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func DestroyEnvironmentBlock(block *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procDestroyEnvironmentBlock.Addr(), 1, uintptr(unsafe.Pointer(block)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetProfilesDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protinfo)), uintptr(group), uintptr(flags)) - handle = syscall.Handle(r0) - if handle == syscall.InvalidHandle { - err = errnoErr(e1) - } - return -} diff --git a/contrib/go/_std_1.22/src/log/slog/doc.go b/contrib/go/_std_1.22/src/log/slog/doc.go deleted file mode 100644 index 001559326b3e..000000000000 --- a/contrib/go/_std_1.22/src/log/slog/doc.go +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package slog provides structured logging, -in which log records include a message, -a severity level, and various other attributes -expressed as key-value pairs. - -It defines a type, [Logger], -which provides several methods (such as [Logger.Info] and [Logger.Error]) -for reporting events of interest. - -Each Logger is associated with a [Handler]. -A Logger output method creates a [Record] from the method arguments -and passes it to the Handler, which decides how to handle it. -There is a default Logger accessible through top-level functions -(such as [Info] and [Error]) that call the corresponding Logger methods. - -A log record consists of a time, a level, a message, and a set of key-value -pairs, where the keys are strings and the values may be of any type. -As an example, - - slog.Info("hello", "count", 3) - -creates a record containing the time of the call, -a level of Info, the message "hello", and a single -pair with key "count" and value 3. - -The [Info] top-level function calls the [Logger.Info] method on the default Logger. -In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. -Besides these convenience methods for common levels, -there is also a [Logger.Log] method which takes the level as an argument. -Each of these methods has a corresponding top-level function that uses the -default logger. - -The default handler formats the log record's message, time, level, and attributes -as a string and passes it to the [log] package. - - 2022/11/08 15:28:26 INFO hello count=3 - -For more control over the output format, create a logger with a different handler. -This statement uses [New] to create a new logger with a [TextHandler] -that writes structured records in text form to standard error: - - logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) - -[TextHandler] output is a sequence of key=value pairs, easily and unambiguously -parsed by machine. This statement: - - logger.Info("hello", "count", 3) - -produces this output: - - time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 - -The package also provides [JSONHandler], whose output is line-delimited JSON: - - logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - logger.Info("hello", "count", 3) - -produces this output: - - {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} - -Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. -There are options for setting the minimum level (see Levels, below), -displaying the source file and line of the log call, and -modifying attributes before they are logged. - -Setting a logger as the default with - - slog.SetDefault(logger) - -will cause the top-level functions like [Info] to use it. -[SetDefault] also updates the default logger used by the [log] package, -so that existing applications that use [log.Printf] and related functions -will send log records to the logger's handler without needing to be rewritten. - -Some attributes are common to many log calls. -For example, you may wish to include the URL or trace identifier of a server request -with all log events arising from the request. -Rather than repeat the attribute with every log call, you can use [Logger.With] -to construct a new Logger containing the attributes: - - logger2 := logger.With("url", r.URL) - -The arguments to With are the same key-value pairs used in [Logger.Info]. -The result is a new Logger with the same handler as the original, but additional -attributes that will appear in the output of every call. - -# Levels - -A [Level] is an integer representing the importance or severity of a log event. -The higher the level, the more severe the event. -This package defines constants for the most common levels, -but any int can be used as a level. - -In an application, you may wish to log messages only at a certain level or greater. -One common configuration is to log messages at Info or higher levels, -suppressing debug logging until it is needed. -The built-in handlers can be configured with the minimum level to output by -setting [HandlerOptions.Level]. -The program's `main` function typically does this. -The default value is LevelInfo. - -Setting the [HandlerOptions.Level] field to a [Level] value -fixes the handler's minimum level throughout its lifetime. -Setting it to a [LevelVar] allows the level to be varied dynamically. -A LevelVar holds a Level and is safe to read or write from multiple -goroutines. -To vary the level dynamically for an entire program, first initialize -a global LevelVar: - - var programLevel = new(slog.LevelVar) // Info by default - -Then use the LevelVar to construct a handler, and make it the default: - - h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) - slog.SetDefault(slog.New(h)) - -Now the program can change its logging level with a single statement: - - programLevel.Set(slog.LevelDebug) - -# Groups - -Attributes can be collected into groups. -A group has a name that is used to qualify the names of its attributes. -How this qualification is displayed depends on the handler. -[TextHandler] separates the group and attribute names with a dot. -[JSONHandler] treats each group as a separate JSON object, with the group name as the key. - -Use [Group] to create a Group attribute from a name and a list of key-value pairs: - - slog.Group("request", - "method", r.Method, - "url", r.URL) - -TextHandler would display this group as - - request.method=GET request.url=http://example.com - -JSONHandler would display it as - - "request":{"method":"GET","url":"http://example.com"} - -Use [Logger.WithGroup] to qualify all of a Logger's output -with a group name. Calling WithGroup on a Logger results in a -new Logger with the same Handler as the original, but with all -its attributes qualified by the group name. - -This can help prevent duplicate attribute keys in large systems, -where subsystems might use the same keys. -Pass each subsystem a different Logger with its own group name so that -potential duplicates are qualified: - - logger := slog.Default().With("id", systemID) - parserLogger := logger.WithGroup("parser") - parseInput(input, parserLogger) - -When parseInput logs with parserLogger, its keys will be qualified with "parser", -so even if it uses the common key "id", the log line will have distinct keys. - -# Contexts - -Some handlers may wish to include information from the [context.Context] that is -available at the call site. One example of such information -is the identifier for the current span when tracing is enabled. - -The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first -argument, as do their corresponding top-level functions. - -Although the convenience methods on Logger (Info and so on) and the -corresponding top-level functions do not take a context, the alternatives ending -in "Context" do. For example, - - slog.InfoContext(ctx, "message") - -It is recommended to pass a context to an output method if one is available. - -# Attrs and Values - -An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as -alternating keys and values. The statement - - slog.Info("hello", slog.Int("count", 3)) - -behaves the same as - - slog.Info("hello", "count", 3) - -There are convenience constructors for [Attr] such as [Int], [String], and [Bool] -for common types, as well as the function [Any] for constructing Attrs of any -type. - -The value part of an Attr is a type called [Value]. -Like an [any], a Value can hold any Go value, -but it can represent typical values, including all numbers and strings, -without an allocation. - -For the most efficient log output, use [Logger.LogAttrs]. -It is similar to [Logger.Log] but accepts only Attrs, not alternating -keys and values; this allows it, too, to avoid allocation. - -The call - - logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) - -is the most efficient way to achieve the same output as - - slog.InfoContext(ctx, "hello", "count", 3) - -# Customizing a type's logging behavior - -If a type implements the [LogValuer] interface, the [Value] returned from its LogValue -method is used for logging. You can use this to control how values of the type -appear in logs. For example, you can redact secret information like passwords, -or gather a struct's fields in a Group. See the examples under [LogValuer] for -details. - -A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] -method handles these cases carefully, avoiding infinite loops and unbounded recursion. -Handler authors and others may wish to use [Value.Resolve] instead of calling LogValue directly. - -# Wrapping output methods - -The logger functions use reflection over the call stack to find the file name -and line number of the logging call within the application. This can produce -incorrect source information for functions that wrap slog. For instance, if you -define this function in file mylog.go: - - func Infof(logger *slog.Logger, format string, args ...any) { - logger.Info(fmt.Sprintf(format, args...)) - } - -and you call it like this in main.go: - - Infof(slog.Default(), "hello, %s", "world") - -then slog will report the source file as mylog.go, not main.go. - -A correct implementation of Infof will obtain the source location -(pc) and pass it to NewRecord. -The Infof function in the package-level example called "wrapping" -demonstrates how to do this. - -# Working with Records - -Sometimes a Handler will need to modify a Record -before passing it on to another Handler or backend. -A Record contains a mixture of simple public fields (e.g. Time, Level, Message) -and hidden fields that refer to state (such as attributes) indirectly. This -means that modifying a simple copy of a Record (e.g. by calling -[Record.Add] or [Record.AddAttrs] to add attributes) -may have unexpected effects on the original. -Before modifying a Record, use [Record.Clone] to -create a copy that shares no state with the original, -or create a new Record with [NewRecord] -and build up its Attrs by traversing the old ones with [Record.Attrs]. - -# Performance considerations - -If profiling your application demonstrates that logging is taking significant time, -the following suggestions may help. - -If many log lines have a common attribute, use [Logger.With] to create a Logger with -that attribute. The built-in handlers will format that attribute only once, at the -call to [Logger.With]. The [Handler] interface is designed to allow that optimization, -and a well-written Handler should take advantage of it. - -The arguments to a log call are always evaluated, even if the log event is discarded. -If possible, defer computation so that it happens only if the value is actually logged. -For example, consider the call - - slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily - -The URL.String method will be called even if the logger discards Info-level events. -Instead, pass the URL directly: - - slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed - -The built-in [TextHandler] will call its String method, but only -if the log event is enabled. -Avoiding the call to String also preserves the structure of the underlying value. -For example [JSONHandler] emits the components of the parsed URL as a JSON object. -If you want to avoid eagerly paying the cost of the String call -without causing the handler to potentially inspect the structure of the value, -wrap the value in a fmt.Stringer implementation that hides its Marshal methods. - -You can also use the [LogValuer] interface to avoid unnecessary work in disabled log -calls. Say you need to log some expensive value: - - slog.Debug("frobbing", "value", computeExpensiveValue(arg)) - -Even if this line is disabled, computeExpensiveValue will be called. -To avoid that, define a type implementing LogValuer: - - type expensive struct { arg int } - - func (e expensive) LogValue() slog.Value { - return slog.AnyValue(computeExpensiveValue(e.arg)) - } - -Then use a value of that type in log calls: - - slog.Debug("frobbing", "value", expensive{arg}) - -Now computeExpensiveValue will only be called when the line is enabled. - -The built-in handlers acquire a lock before calling [io.Writer.Write] -to ensure that each record is written in one piece. User-defined -handlers are responsible for their own locking. - -# Writing a handler - -For a guide to writing a custom handler, see https://golang.org/s/slog-handler-guide. -*/ -package slog diff --git a/contrib/go/_std_1.22/src/log/slog/internal/buffer/buffer.go b/contrib/go/_std_1.22/src/log/slog/internal/buffer/buffer.go deleted file mode 100644 index 310ec37d4a12..000000000000 --- a/contrib/go/_std_1.22/src/log/slog/internal/buffer/buffer.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package buffer provides a pool-allocated byte buffer. -package buffer - -import "sync" - -// buffer adapted from go/src/fmt/print.go -type Buffer []byte - -// Having an initial size gives a dramatic speedup. -var bufPool = sync.Pool{ - New: func() any { - b := make([]byte, 0, 1024) - return (*Buffer)(&b) - }, -} - -func New() *Buffer { - return bufPool.Get().(*Buffer) -} - -func (b *Buffer) Free() { - // To reduce peak allocation, return only smaller buffers to the pool. - const maxBufferSize = 16 << 10 - if cap(*b) <= maxBufferSize { - *b = (*b)[:0] - bufPool.Put(b) - } -} - -func (b *Buffer) Reset() { - b.SetLen(0) -} - -func (b *Buffer) Write(p []byte) (int, error) { - *b = append(*b, p...) - return len(p), nil -} - -func (b *Buffer) WriteString(s string) (int, error) { - *b = append(*b, s...) - return len(s), nil -} - -func (b *Buffer) WriteByte(c byte) error { - *b = append(*b, c) - return nil -} - -func (b *Buffer) String() string { - return string(*b) -} - -func (b *Buffer) Len() int { - return len(*b) -} - -func (b *Buffer) SetLen(n int) { - *b = (*b)[:n] -} diff --git a/contrib/go/_std_1.22/src/log/slog/value.go b/contrib/go/_std_1.22/src/log/slog/value.go deleted file mode 100644 index d278d9b92355..000000000000 --- a/contrib/go/_std_1.22/src/log/slog/value.go +++ /dev/null @@ -1,520 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slog - -import ( - "fmt" - "math" - "runtime" - "slices" - "strconv" - "strings" - "time" - "unsafe" -) - -// A Value can represent any Go value, but unlike type any, -// it can represent most small values without an allocation. -// The zero Value corresponds to nil. -type Value struct { - _ [0]func() // disallow == - // num holds the value for Kinds Int64, Uint64, Float64, Bool and Duration, - // the string length for KindString, and nanoseconds since the epoch for KindTime. - num uint64 - // If any is of type Kind, then the value is in num as described above. - // If any is of type *time.Location, then the Kind is Time and time.Time value - // can be constructed from the Unix nanos in num and the location (monotonic time - // is not preserved). - // If any is of type stringptr, then the Kind is String and the string value - // consists of the length in num and the pointer in any. - // Otherwise, the Kind is Any and any is the value. - // (This implies that Attrs cannot store values of type Kind, *time.Location - // or stringptr.) - any any -} - -type ( - stringptr *byte // used in Value.any when the Value is a string - groupptr *Attr // used in Value.any when the Value is a []Attr -) - -// Kind is the kind of a [Value]. -type Kind int - -// The following list is sorted alphabetically, but it's also important that -// KindAny is 0 so that a zero Value represents nil. - -const ( - KindAny Kind = iota - KindBool - KindDuration - KindFloat64 - KindInt64 - KindString - KindTime - KindUint64 - KindGroup - KindLogValuer -) - -var kindStrings = []string{ - "Any", - "Bool", - "Duration", - "Float64", - "Int64", - "String", - "Time", - "Uint64", - "Group", - "LogValuer", -} - -func (k Kind) String() string { - if k >= 0 && int(k) < len(kindStrings) { - return kindStrings[k] - } - return "" -} - -// Unexported version of Kind, just so we can store Kinds in Values. -// (No user-provided value has this type.) -type kind Kind - -// Kind returns v's Kind. -func (v Value) Kind() Kind { - switch x := v.any.(type) { - case Kind: - return x - case stringptr: - return KindString - case timeLocation: - return KindTime - case groupptr: - return KindGroup - case LogValuer: - return KindLogValuer - case kind: // a kind is just a wrapper for a Kind - return KindAny - default: - return KindAny - } -} - -//////////////// Constructors - -// StringValue returns a new [Value] for a string. -func StringValue(value string) Value { - return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))} -} - -// IntValue returns a [Value] for an int. -func IntValue(v int) Value { - return Int64Value(int64(v)) -} - -// Int64Value returns a [Value] for an int64. -func Int64Value(v int64) Value { - return Value{num: uint64(v), any: KindInt64} -} - -// Uint64Value returns a [Value] for a uint64. -func Uint64Value(v uint64) Value { - return Value{num: v, any: KindUint64} -} - -// Float64Value returns a [Value] for a floating-point number. -func Float64Value(v float64) Value { - return Value{num: math.Float64bits(v), any: KindFloat64} -} - -// BoolValue returns a [Value] for a bool. -func BoolValue(v bool) Value { - u := uint64(0) - if v { - u = 1 - } - return Value{num: u, any: KindBool} -} - -// Unexported version of *time.Location, just so we can store *time.Locations in -// Values. (No user-provided value has this type.) -type timeLocation *time.Location - -// TimeValue returns a [Value] for a [time.Time]. -// It discards the monotonic portion. -func TimeValue(v time.Time) Value { - if v.IsZero() { - // UnixNano on the zero time is undefined, so represent the zero time - // with a nil *time.Location instead. time.Time.Location method never - // returns nil, so a Value with any == timeLocation(nil) cannot be - // mistaken for any other Value, time.Time or otherwise. - return Value{any: timeLocation(nil)} - } - return Value{num: uint64(v.UnixNano()), any: timeLocation(v.Location())} -} - -// DurationValue returns a [Value] for a [time.Duration]. -func DurationValue(v time.Duration) Value { - return Value{num: uint64(v.Nanoseconds()), any: KindDuration} -} - -// GroupValue returns a new [Value] for a list of Attrs. -// The caller must not subsequently mutate the argument slice. -func GroupValue(as ...Attr) Value { - // Remove empty groups. - // It is simpler overall to do this at construction than - // to check each Group recursively for emptiness. - if n := countEmptyGroups(as); n > 0 { - as2 := make([]Attr, 0, len(as)-n) - for _, a := range as { - if !a.Value.isEmptyGroup() { - as2 = append(as2, a) - } - } - as = as2 - } - return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))} -} - -// countEmptyGroups returns the number of empty group values in its argument. -func countEmptyGroups(as []Attr) int { - n := 0 - for _, a := range as { - if a.Value.isEmptyGroup() { - n++ - } - } - return n -} - -// AnyValue returns a [Value] for the supplied value. -// -// If the supplied value is of type Value, it is returned -// unmodified. -// -// Given a value of one of Go's predeclared string, bool, or -// (non-complex) numeric types, AnyValue returns a Value of kind -// [KindString], [KindBool], [KindUint64], [KindInt64], or [KindFloat64]. -// The width of the original numeric type is not preserved. -// -// Given a [time.Time] or [time.Duration] value, AnyValue returns a Value of kind -// [KindTime] or [KindDuration]. The monotonic time is not preserved. -// -// For nil, or values of all other types, including named types whose -// underlying type is numeric, AnyValue returns a value of kind [KindAny]. -func AnyValue(v any) Value { - switch v := v.(type) { - case string: - return StringValue(v) - case int: - return Int64Value(int64(v)) - case uint: - return Uint64Value(uint64(v)) - case int64: - return Int64Value(v) - case uint64: - return Uint64Value(v) - case bool: - return BoolValue(v) - case time.Duration: - return DurationValue(v) - case time.Time: - return TimeValue(v) - case uint8: - return Uint64Value(uint64(v)) - case uint16: - return Uint64Value(uint64(v)) - case uint32: - return Uint64Value(uint64(v)) - case uintptr: - return Uint64Value(uint64(v)) - case int8: - return Int64Value(int64(v)) - case int16: - return Int64Value(int64(v)) - case int32: - return Int64Value(int64(v)) - case float64: - return Float64Value(v) - case float32: - return Float64Value(float64(v)) - case []Attr: - return GroupValue(v...) - case Kind: - return Value{any: kind(v)} - case Value: - return v - default: - return Value{any: v} - } -} - -//////////////// Accessors - -// Any returns v's value as an any. -func (v Value) Any() any { - switch v.Kind() { - case KindAny: - if k, ok := v.any.(kind); ok { - return Kind(k) - } - return v.any - case KindLogValuer: - return v.any - case KindGroup: - return v.group() - case KindInt64: - return int64(v.num) - case KindUint64: - return v.num - case KindFloat64: - return v.float() - case KindString: - return v.str() - case KindBool: - return v.bool() - case KindDuration: - return v.duration() - case KindTime: - return v.time() - default: - panic(fmt.Sprintf("bad kind: %s", v.Kind())) - } -} - -// String returns Value's value as a string, formatted like [fmt.Sprint]. Unlike -// the methods Int64, Float64, and so on, which panic if v is of the -// wrong kind, String never panics. -func (v Value) String() string { - if sp, ok := v.any.(stringptr); ok { - return unsafe.String(sp, v.num) - } - var buf []byte - return string(v.append(buf)) -} - -func (v Value) str() string { - return unsafe.String(v.any.(stringptr), v.num) -} - -// Int64 returns v's value as an int64. It panics -// if v is not a signed integer. -func (v Value) Int64() int64 { - if g, w := v.Kind(), KindInt64; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - return int64(v.num) -} - -// Uint64 returns v's value as a uint64. It panics -// if v is not an unsigned integer. -func (v Value) Uint64() uint64 { - if g, w := v.Kind(), KindUint64; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - return v.num -} - -// Bool returns v's value as a bool. It panics -// if v is not a bool. -func (v Value) Bool() bool { - if g, w := v.Kind(), KindBool; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - return v.bool() -} - -func (v Value) bool() bool { - return v.num == 1 -} - -// Duration returns v's value as a [time.Duration]. It panics -// if v is not a time.Duration. -func (v Value) Duration() time.Duration { - if g, w := v.Kind(), KindDuration; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - - return v.duration() -} - -func (v Value) duration() time.Duration { - return time.Duration(int64(v.num)) -} - -// Float64 returns v's value as a float64. It panics -// if v is not a float64. -func (v Value) Float64() float64 { - if g, w := v.Kind(), KindFloat64; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - - return v.float() -} - -func (v Value) float() float64 { - return math.Float64frombits(v.num) -} - -// Time returns v's value as a [time.Time]. It panics -// if v is not a time.Time. -func (v Value) Time() time.Time { - if g, w := v.Kind(), KindTime; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - return v.time() -} - -func (v Value) time() time.Time { - loc := v.any.(timeLocation) - if loc == nil { - return time.Time{} - } - return time.Unix(0, int64(v.num)).In(loc) -} - -// LogValuer returns v's value as a LogValuer. It panics -// if v is not a LogValuer. -func (v Value) LogValuer() LogValuer { - return v.any.(LogValuer) -} - -// Group returns v's value as a []Attr. -// It panics if v's [Kind] is not [KindGroup]. -func (v Value) Group() []Attr { - if sp, ok := v.any.(groupptr); ok { - return unsafe.Slice((*Attr)(sp), v.num) - } - panic("Group: bad kind") -} - -func (v Value) group() []Attr { - return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num) -} - -//////////////// Other - -// Equal reports whether v and w represent the same Go value. -func (v Value) Equal(w Value) bool { - k1 := v.Kind() - k2 := w.Kind() - if k1 != k2 { - return false - } - switch k1 { - case KindInt64, KindUint64, KindBool, KindDuration: - return v.num == w.num - case KindString: - return v.str() == w.str() - case KindFloat64: - return v.float() == w.float() - case KindTime: - return v.time().Equal(w.time()) - case KindAny, KindLogValuer: - return v.any == w.any // may panic if non-comparable - case KindGroup: - return slices.EqualFunc(v.group(), w.group(), Attr.Equal) - default: - panic(fmt.Sprintf("bad kind: %s", k1)) - } -} - -// isEmptyGroup reports whether v is a group that has no attributes. -func (v Value) isEmptyGroup() bool { - if v.Kind() != KindGroup { - return false - } - // We do not need to recursively examine the group's Attrs for emptiness, - // because GroupValue removed them when the group was constructed, and - // groups are immutable. - return len(v.group()) == 0 -} - -// append appends a text representation of v to dst. -// v is formatted as with fmt.Sprint. -func (v Value) append(dst []byte) []byte { - switch v.Kind() { - case KindString: - return append(dst, v.str()...) - case KindInt64: - return strconv.AppendInt(dst, int64(v.num), 10) - case KindUint64: - return strconv.AppendUint(dst, v.num, 10) - case KindFloat64: - return strconv.AppendFloat(dst, v.float(), 'g', -1, 64) - case KindBool: - return strconv.AppendBool(dst, v.bool()) - case KindDuration: - return append(dst, v.duration().String()...) - case KindTime: - return append(dst, v.time().String()...) - case KindGroup: - return fmt.Append(dst, v.group()) - case KindAny, KindLogValuer: - return fmt.Append(dst, v.any) - default: - panic(fmt.Sprintf("bad kind: %s", v.Kind())) - } -} - -// A LogValuer is any Go value that can convert itself into a Value for logging. -// -// This mechanism may be used to defer expensive operations until they are -// needed, or to expand a single value into a sequence of components. -type LogValuer interface { - LogValue() Value -} - -const maxLogValues = 100 - -// Resolve repeatedly calls LogValue on v while it implements [LogValuer], -// and returns the result. -// If v resolves to a group, the group's attributes' values are not recursively -// resolved. -// If the number of LogValue calls exceeds a threshold, a Value containing an -// error is returned. -// Resolve's return value is guaranteed not to be of Kind [KindLogValuer]. -func (v Value) Resolve() (rv Value) { - orig := v - defer func() { - if r := recover(); r != nil { - rv = AnyValue(fmt.Errorf("LogValue panicked\n%s", stack(3, 5))) - } - }() - - for i := 0; i < maxLogValues; i++ { - if v.Kind() != KindLogValuer { - return v - } - v = v.LogValuer().LogValue() - } - err := fmt.Errorf("LogValue called too many times on Value of type %T", orig.Any()) - return AnyValue(err) -} - -func stack(skip, nFrames int) string { - pcs := make([]uintptr, nFrames+1) - n := runtime.Callers(skip+1, pcs) - if n == 0 { - return "(no stack)" - } - frames := runtime.CallersFrames(pcs[:n]) - var b strings.Builder - i := 0 - for { - frame, more := frames.Next() - fmt.Fprintf(&b, "called from %s (%s:%d)\n", frame.Function, frame.File, frame.Line) - if !more { - break - } - i++ - if i >= nFrames { - fmt.Fprintf(&b, "(rest of stack elided)\n") - break - } - } - return b.String() -} diff --git a/contrib/go/_std_1.22/src/log/syslog/ya.make b/contrib/go/_std_1.22/src/log/syslog/ya.make deleted file mode 100644 index a0bf92b6113f..000000000000 --- a/contrib/go/_std_1.22/src/log/syslog/ya.make +++ /dev/null @@ -1,15 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - syslog.go - syslog_unix.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/math/big/arith_decl.go b/contrib/go/_std_1.22/src/math/big/arith_decl.go deleted file mode 100644 index f14f8d6794ee..000000000000 --- a/contrib/go/_std_1.22/src/math/big/arith_decl.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !math_big_pure_go - -package big - -// implemented in arith_$GOARCH.s - -//go:noescape -func addVV(z, x, y []Word) (c Word) - -//go:noescape -func subVV(z, x, y []Word) (c Word) - -//go:noescape -func addVW(z, x []Word, y Word) (c Word) - -//go:noescape -func subVW(z, x []Word, y Word) (c Word) - -//go:noescape -func shlVU(z, x []Word, s uint) (c Word) - -//go:noescape -func shrVU(z, x []Word, s uint) (c Word) - -//go:noescape -func mulAddVWW(z, x []Word, y, r Word) (c Word) - -//go:noescape -func addMulVVW(z, x []Word, y Word) (c Word) diff --git a/contrib/go/_std_1.22/src/math/big/nat.go b/contrib/go/_std_1.22/src/math/big/nat.go deleted file mode 100644 index ecb7d363d4fb..000000000000 --- a/contrib/go/_std_1.22/src/math/big/nat.go +++ /dev/null @@ -1,1422 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file implements unsigned multi-precision integers (natural -// numbers). They are the building blocks for the implementation -// of signed integers, rationals, and floating-point numbers. -// -// Caution: This implementation relies on the function "alias" -// which assumes that (nat) slice capacities are never -// changed (no 3-operand slice expressions). If that -// changes, alias needs to be updated for correctness. - -package big - -import ( - "encoding/binary" - "math/bits" - "math/rand" - "sync" -) - -// An unsigned integer x of the form -// -// x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0] -// -// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n, -// with the digits x[i] as the slice elements. -// -// A number is normalized if the slice contains no leading 0 digits. -// During arithmetic operations, denormalized values may occur but are -// always normalized before returning the final result. The normalized -// representation of 0 is the empty or nil slice (length = 0). -type nat []Word - -var ( - natOne = nat{1} - natTwo = nat{2} - natFive = nat{5} - natTen = nat{10} -) - -func (z nat) String() string { - return "0x" + string(z.itoa(false, 16)) -} - -func (z nat) clear() { - for i := range z { - z[i] = 0 - } -} - -func (z nat) norm() nat { - i := len(z) - for i > 0 && z[i-1] == 0 { - i-- - } - return z[0:i] -} - -func (z nat) make(n int) nat { - if n <= cap(z) { - return z[:n] // reuse z - } - if n == 1 { - // Most nats start small and stay that way; don't over-allocate. - return make(nat, 1) - } - // Choosing a good value for e has significant performance impact - // because it increases the chance that a value can be reused. - const e = 4 // extra capacity - return make(nat, n, n+e) -} - -func (z nat) setWord(x Word) nat { - if x == 0 { - return z[:0] - } - z = z.make(1) - z[0] = x - return z -} - -func (z nat) setUint64(x uint64) nat { - // single-word value - if w := Word(x); uint64(w) == x { - return z.setWord(w) - } - // 2-word value - z = z.make(2) - z[1] = Word(x >> 32) - z[0] = Word(x) - return z -} - -func (z nat) set(x nat) nat { - z = z.make(len(x)) - copy(z, x) - return z -} - -func (z nat) add(x, y nat) nat { - m := len(x) - n := len(y) - - switch { - case m < n: - return z.add(y, x) - case m == 0: - // n == 0 because m >= n; result is 0 - return z[:0] - case n == 0: - // result is x - return z.set(x) - } - // m > 0 - - z = z.make(m + 1) - c := addVV(z[0:n], x, y) - if m > n { - c = addVW(z[n:m], x[n:], c) - } - z[m] = c - - return z.norm() -} - -func (z nat) sub(x, y nat) nat { - m := len(x) - n := len(y) - - switch { - case m < n: - panic("underflow") - case m == 0: - // n == 0 because m >= n; result is 0 - return z[:0] - case n == 0: - // result is x - return z.set(x) - } - // m > 0 - - z = z.make(m) - c := subVV(z[0:n], x, y) - if m > n { - c = subVW(z[n:], x[n:], c) - } - if c != 0 { - panic("underflow") - } - - return z.norm() -} - -func (x nat) cmp(y nat) (r int) { - m := len(x) - n := len(y) - if m != n || m == 0 { - switch { - case m < n: - r = -1 - case m > n: - r = 1 - } - return - } - - i := m - 1 - for i > 0 && x[i] == y[i] { - i-- - } - - switch { - case x[i] < y[i]: - r = -1 - case x[i] > y[i]: - r = 1 - } - return -} - -func (z nat) mulAddWW(x nat, y, r Word) nat { - m := len(x) - if m == 0 || y == 0 { - return z.setWord(r) // result is r - } - // m > 0 - - z = z.make(m + 1) - z[m] = mulAddVWW(z[0:m], x, y, r) - - return z.norm() -} - -// basicMul multiplies x and y and leaves the result in z. -// The (non-normalized) result is placed in z[0 : len(x) + len(y)]. -func basicMul(z, x, y nat) { - z[0 : len(x)+len(y)].clear() // initialize z - for i, d := range y { - if d != 0 { - z[len(x)+i] = addMulVVW(z[i:i+len(x)], x, d) - } - } -} - -// montgomery computes z mod m = x*y*2**(-n*_W) mod m, -// assuming k = -1/m mod 2**_W. -// z is used for storing the result which is returned; -// z must not alias x, y or m. -// See Gueron, "Efficient Software Implementations of Modular Exponentiation". -// https://eprint.iacr.org/2011/239.pdf -// In the terminology of that paper, this is an "Almost Montgomery Multiplication": -// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result -// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m. -func (z nat) montgomery(x, y, m nat, k Word, n int) nat { - // This code assumes x, y, m are all the same length, n. - // (required by addMulVVW and the for loop). - // It also assumes that x, y are already reduced mod m, - // or else the result will not be properly reduced. - if len(x) != n || len(y) != n || len(m) != n { - panic("math/big: mismatched montgomery number lengths") - } - z = z.make(n * 2) - z.clear() - var c Word - for i := 0; i < n; i++ { - d := y[i] - c2 := addMulVVW(z[i:n+i], x, d) - t := z[i] * k - c3 := addMulVVW(z[i:n+i], m, t) - cx := c + c2 - cy := cx + c3 - z[n+i] = cy - if cx < c2 || cy < c3 { - c = 1 - } else { - c = 0 - } - } - if c != 0 { - subVV(z[:n], z[n:], m) - } else { - copy(z[:n], z[n:]) - } - return z[:n] -} - -// Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks. -// Factored out for readability - do not use outside karatsuba. -func karatsubaAdd(z, x nat, n int) { - if c := addVV(z[0:n], z, x); c != 0 { - addVW(z[n:n+n>>1], z[n:], c) - } -} - -// Like karatsubaAdd, but does subtract. -func karatsubaSub(z, x nat, n int) { - if c := subVV(z[0:n], z, x); c != 0 { - subVW(z[n:n+n>>1], z[n:], c) - } -} - -// Operands that are shorter than karatsubaThreshold are multiplied using -// "grade school" multiplication; for longer operands the Karatsuba algorithm -// is used. -var karatsubaThreshold = 40 // computed by calibrate_test.go - -// karatsuba multiplies x and y and leaves the result in z. -// Both x and y must have the same length n and n must be a -// power of 2. The result vector z must have len(z) >= 6*n. -// The (non-normalized) result is placed in z[0 : 2*n]. -func karatsuba(z, x, y nat) { - n := len(y) - - // Switch to basic multiplication if numbers are odd or small. - // (n is always even if karatsubaThreshold is even, but be - // conservative) - if n&1 != 0 || n < karatsubaThreshold || n < 2 { - basicMul(z, x, y) - return - } - // n&1 == 0 && n >= karatsubaThreshold && n >= 2 - - // Karatsuba multiplication is based on the observation that - // for two numbers x and y with: - // - // x = x1*b + x0 - // y = y1*b + y0 - // - // the product x*y can be obtained with 3 products z2, z1, z0 - // instead of 4: - // - // x*y = x1*y1*b*b + (x1*y0 + x0*y1)*b + x0*y0 - // = z2*b*b + z1*b + z0 - // - // with: - // - // xd = x1 - x0 - // yd = y0 - y1 - // - // z1 = xd*yd + z2 + z0 - // = (x1-x0)*(y0 - y1) + z2 + z0 - // = x1*y0 - x1*y1 - x0*y0 + x0*y1 + z2 + z0 - // = x1*y0 - z2 - z0 + x0*y1 + z2 + z0 - // = x1*y0 + x0*y1 - - // split x, y into "digits" - n2 := n >> 1 // n2 >= 1 - x1, x0 := x[n2:], x[0:n2] // x = x1*b + y0 - y1, y0 := y[n2:], y[0:n2] // y = y1*b + y0 - - // z is used for the result and temporary storage: - // - // 6*n 5*n 4*n 3*n 2*n 1*n 0*n - // z = [z2 copy|z0 copy| xd*yd | yd:xd | x1*y1 | x0*y0 ] - // - // For each recursive call of karatsuba, an unused slice of - // z is passed in that has (at least) half the length of the - // caller's z. - - // compute z0 and z2 with the result "in place" in z - karatsuba(z, x0, y0) // z0 = x0*y0 - karatsuba(z[n:], x1, y1) // z2 = x1*y1 - - // compute xd (or the negative value if underflow occurs) - s := 1 // sign of product xd*yd - xd := z[2*n : 2*n+n2] - if subVV(xd, x1, x0) != 0 { // x1-x0 - s = -s - subVV(xd, x0, x1) // x0-x1 - } - - // compute yd (or the negative value if underflow occurs) - yd := z[2*n+n2 : 3*n] - if subVV(yd, y0, y1) != 0 { // y0-y1 - s = -s - subVV(yd, y1, y0) // y1-y0 - } - - // p = (x1-x0)*(y0-y1) == x1*y0 - x1*y1 - x0*y0 + x0*y1 for s > 0 - // p = (x0-x1)*(y0-y1) == x0*y0 - x0*y1 - x1*y0 + x1*y1 for s < 0 - p := z[n*3:] - karatsuba(p, xd, yd) - - // save original z2:z0 - // (ok to use upper half of z since we're done recurring) - r := z[n*4:] - copy(r, z[:n*2]) - - // add up all partial products - // - // 2*n n 0 - // z = [ z2 | z0 ] - // + [ z0 ] - // + [ z2 ] - // + [ p ] - // - karatsubaAdd(z[n2:], r, n) - karatsubaAdd(z[n2:], r[n:], n) - if s > 0 { - karatsubaAdd(z[n2:], p, n) - } else { - karatsubaSub(z[n2:], p, n) - } -} - -// alias reports whether x and y share the same base array. -// -// Note: alias assumes that the capacity of underlying arrays -// is never changed for nat values; i.e. that there are -// no 3-operand slice expressions in this code (or worse, -// reflect-based operations to the same effect). -func alias(x, y nat) bool { - return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1] -} - -// addAt implements z += x<<(_W*i); z must be long enough. -// (we don't use nat.add because we need z to stay the same -// slice, and we don't need to normalize z after each addition) -func addAt(z, x nat, i int) { - if n := len(x); n > 0 { - if c := addVV(z[i:i+n], z[i:], x); c != 0 { - j := i + n - if j < len(z) { - addVW(z[j:], z[j:], c) - } - } - } -} - -// karatsubaLen computes an approximation to the maximum k <= n such that -// k = p<= 0. Thus, the -// result is the largest number that can be divided repeatedly by 2 before -// becoming about the value of threshold. -func karatsubaLen(n, threshold int) int { - i := uint(0) - for n > threshold { - n >>= 1 - i++ - } - return n << i -} - -func (z nat) mul(x, y nat) nat { - m := len(x) - n := len(y) - - switch { - case m < n: - return z.mul(y, x) - case m == 0 || n == 0: - return z[:0] - case n == 1: - return z.mulAddWW(x, y[0], 0) - } - // m >= n > 1 - - // determine if z can be reused - if alias(z, x) || alias(z, y) { - z = nil // z is an alias for x or y - cannot reuse - } - - // use basic multiplication if the numbers are small - if n < karatsubaThreshold { - z = z.make(m + n) - basicMul(z, x, y) - return z.norm() - } - // m >= n && n >= karatsubaThreshold && n >= 2 - - // determine Karatsuba length k such that - // - // x = xh*b + x0 (0 <= x0 < b) - // y = yh*b + y0 (0 <= y0 < b) - // b = 1<<(_W*k) ("base" of digits xi, yi) - // - k := karatsubaLen(n, karatsubaThreshold) - // k <= n - - // multiply x0 and y0 via Karatsuba - x0 := x[0:k] // x0 is not normalized - y0 := y[0:k] // y0 is not normalized - z = z.make(max(6*k, m+n)) // enough space for karatsuba of x0*y0 and full result of x*y - karatsuba(z, x0, y0) - z = z[0 : m+n] // z has final length but may be incomplete - z[2*k:].clear() // upper portion of z is garbage (and 2*k <= m+n since k <= n <= m) - - // If xh != 0 or yh != 0, add the missing terms to z. For - // - // xh = xi*b^i + ... + x2*b^2 + x1*b (0 <= xi < b) - // yh = y1*b (0 <= y1 < b) - // - // the missing terms are - // - // x0*y1*b and xi*y0*b^i, xi*y1*b^(i+1) for i > 0 - // - // since all the yi for i > 1 are 0 by choice of k: If any of them - // were > 0, then yh >= b^2 and thus y >= b^2. Then k' = k*2 would - // be a larger valid threshold contradicting the assumption about k. - // - if k < n || m != n { - tp := getNat(3 * k) - t := *tp - - // add x0*y1*b - x0 := x0.norm() - y1 := y[k:] // y1 is normalized because y is - t = t.mul(x0, y1) // update t so we don't lose t's underlying array - addAt(z, t, k) - - // add xi*y0< k { - xi = xi[:k] - } - xi = xi.norm() - t = t.mul(xi, y0) - addAt(z, t, i) - t = t.mul(xi, y1) - addAt(z, t, i+k) - } - - putNat(tp) - } - - return z.norm() -} - -// basicSqr sets z = x*x and is asymptotically faster than basicMul -// by about a factor of 2, but slower for small arguments due to overhead. -// Requirements: len(x) > 0, len(z) == 2*len(x) -// The (non-normalized) result is placed in z. -func basicSqr(z, x nat) { - n := len(x) - tp := getNat(2 * n) - t := *tp // temporary variable to hold the products - t.clear() - z[1], z[0] = mulWW(x[0], x[0]) // the initial square - for i := 1; i < n; i++ { - d := x[i] - // z collects the squares x[i] * x[i] - z[2*i+1], z[2*i] = mulWW(d, d) - // t collects the products x[i] * x[j] where j < i - t[2*i] = addMulVVW(t[i:2*i], x[0:i], d) - } - t[2*n-1] = shlVU(t[1:2*n-1], t[1:2*n-1], 1) // double the j < i products - addVV(z, z, t) // combine the result - putNat(tp) -} - -// karatsubaSqr squares x and leaves the result in z. -// len(x) must be a power of 2 and len(z) >= 6*len(x). -// The (non-normalized) result is placed in z[0 : 2*len(x)]. -// -// The algorithm and the layout of z are the same as for karatsuba. -func karatsubaSqr(z, x nat) { - n := len(x) - - if n&1 != 0 || n < karatsubaSqrThreshold || n < 2 { - basicSqr(z[:2*n], x) - return - } - - n2 := n >> 1 - x1, x0 := x[n2:], x[0:n2] - - karatsubaSqr(z, x0) - karatsubaSqr(z[n:], x1) - - // s = sign(xd*yd) == -1 for xd != 0; s == 1 for xd == 0 - xd := z[2*n : 2*n+n2] - if subVV(xd, x1, x0) != 0 { - subVV(xd, x0, x1) - } - - p := z[n*3:] - karatsubaSqr(p, xd) - - r := z[n*4:] - copy(r, z[:n*2]) - - karatsubaAdd(z[n2:], r, n) - karatsubaAdd(z[n2:], r[n:], n) - karatsubaSub(z[n2:], p, n) // s == -1 for p != 0; s == 1 for p == 0 -} - -// Operands that are shorter than basicSqrThreshold are squared using -// "grade school" multiplication; for operands longer than karatsubaSqrThreshold -// we use the Karatsuba algorithm optimized for x == y. -var basicSqrThreshold = 20 // computed by calibrate_test.go -var karatsubaSqrThreshold = 260 // computed by calibrate_test.go - -// z = x*x -func (z nat) sqr(x nat) nat { - n := len(x) - switch { - case n == 0: - return z[:0] - case n == 1: - d := x[0] - z = z.make(2) - z[1], z[0] = mulWW(d, d) - return z.norm() - } - - if alias(z, x) { - z = nil // z is an alias for x - cannot reuse - } - - if n < basicSqrThreshold { - z = z.make(2 * n) - basicMul(z, x, x) - return z.norm() - } - if n < karatsubaSqrThreshold { - z = z.make(2 * n) - basicSqr(z, x) - return z.norm() - } - - // Use Karatsuba multiplication optimized for x == y. - // The algorithm and layout of z are the same as for mul. - - // z = (x1*b + x0)^2 = x1^2*b^2 + 2*x1*x0*b + x0^2 - - k := karatsubaLen(n, karatsubaSqrThreshold) - - x0 := x[0:k] - z = z.make(max(6*k, 2*n)) - karatsubaSqr(z, x0) // z = x0^2 - z = z[0 : 2*n] - z[2*k:].clear() - - if k < n { - tp := getNat(2 * k) - t := *tp - x0 := x0.norm() - x1 := x[k:] - t = t.mul(x0, x1) - addAt(z, t, k) - addAt(z, t, k) // z = 2*x1*x0*b + x0^2 - t = t.sqr(x1) - addAt(z, t, 2*k) // z = x1^2*b^2 + 2*x1*x0*b + x0^2 - putNat(tp) - } - - return z.norm() -} - -// mulRange computes the product of all the unsigned integers in the -// range [a, b] inclusively. If a > b (empty range), the result is 1. -func (z nat) mulRange(a, b uint64) nat { - switch { - case a == 0: - // cut long ranges short (optimization) - return z.setUint64(0) - case a > b: - return z.setUint64(1) - case a == b: - return z.setUint64(a) - case a+1 == b: - return z.mul(nat(nil).setUint64(a), nat(nil).setUint64(b)) - } - m := a + (b-a)/2 // avoid overflow - return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b)) -} - -// getNat returns a *nat of len n. The contents may not be zero. -// The pool holds *nat to avoid allocation when converting to interface{}. -func getNat(n int) *nat { - var z *nat - if v := natPool.Get(); v != nil { - z = v.(*nat) - } - if z == nil { - z = new(nat) - } - *z = z.make(n) - if n > 0 { - (*z)[0] = 0xfedcb // break code expecting zero - } - return z -} - -func putNat(x *nat) { - natPool.Put(x) -} - -var natPool sync.Pool - -// bitLen returns the length of x in bits. -// Unlike most methods, it works even if x is not normalized. -func (x nat) bitLen() int { - // This function is used in cryptographic operations. It must not leak - // anything but the Int's sign and bit size through side-channels. Any - // changes must be reviewed by a security expert. - if i := len(x) - 1; i >= 0 { - // bits.Len uses a lookup table for the low-order bits on some - // architectures. Neutralize any input-dependent behavior by setting all - // bits after the first one bit. - top := uint(x[i]) - top |= top >> 1 - top |= top >> 2 - top |= top >> 4 - top |= top >> 8 - top |= top >> 16 - top |= top >> 16 >> 16 // ">> 32" doesn't compile on 32-bit architectures - return i*_W + bits.Len(top) - } - return 0 -} - -// trailingZeroBits returns the number of consecutive least significant zero -// bits of x. -func (x nat) trailingZeroBits() uint { - if len(x) == 0 { - return 0 - } - var i uint - for x[i] == 0 { - i++ - } - // x[i] != 0 - return i*_W + uint(bits.TrailingZeros(uint(x[i]))) -} - -// isPow2 returns i, true when x == 2**i and 0, false otherwise. -func (x nat) isPow2() (uint, bool) { - var i uint - for x[i] == 0 { - i++ - } - if i == uint(len(x))-1 && x[i]&(x[i]-1) == 0 { - return i*_W + uint(bits.TrailingZeros(uint(x[i]))), true - } - return 0, false -} - -func same(x, y nat) bool { - return len(x) == len(y) && len(x) > 0 && &x[0] == &y[0] -} - -// z = x << s -func (z nat) shl(x nat, s uint) nat { - if s == 0 { - if same(z, x) { - return z - } - if !alias(z, x) { - return z.set(x) - } - } - - m := len(x) - if m == 0 { - return z[:0] - } - // m > 0 - - n := m + int(s/_W) - z = z.make(n + 1) - z[n] = shlVU(z[n-m:n], x, s%_W) - z[0 : n-m].clear() - - return z.norm() -} - -// z = x >> s -func (z nat) shr(x nat, s uint) nat { - if s == 0 { - if same(z, x) { - return z - } - if !alias(z, x) { - return z.set(x) - } - } - - m := len(x) - n := m - int(s/_W) - if n <= 0 { - return z[:0] - } - // n > 0 - - z = z.make(n) - shrVU(z, x[m-n:], s%_W) - - return z.norm() -} - -func (z nat) setBit(x nat, i uint, b uint) nat { - j := int(i / _W) - m := Word(1) << (i % _W) - n := len(x) - switch b { - case 0: - z = z.make(n) - copy(z, x) - if j >= n { - // no need to grow - return z - } - z[j] &^= m - return z.norm() - case 1: - if j >= n { - z = z.make(j + 1) - z[n:].clear() - } else { - z = z.make(n) - } - copy(z, x) - z[j] |= m - // no need to normalize - return z - } - panic("set bit is not 0 or 1") -} - -// bit returns the value of the i'th bit, with lsb == bit 0. -func (x nat) bit(i uint) uint { - j := i / _W - if j >= uint(len(x)) { - return 0 - } - // 0 <= j < len(x) - return uint(x[j] >> (i % _W) & 1) -} - -// sticky returns 1 if there's a 1 bit within the -// i least significant bits, otherwise it returns 0. -func (x nat) sticky(i uint) uint { - j := i / _W - if j >= uint(len(x)) { - if len(x) == 0 { - return 0 - } - return 1 - } - // 0 <= j < len(x) - for _, x := range x[:j] { - if x != 0 { - return 1 - } - } - if x[j]<<(_W-i%_W) != 0 { - return 1 - } - return 0 -} - -func (z nat) and(x, y nat) nat { - m := len(x) - n := len(y) - if m > n { - m = n - } - // m <= n - - z = z.make(m) - for i := 0; i < m; i++ { - z[i] = x[i] & y[i] - } - - return z.norm() -} - -// trunc returns z = x mod 2ⁿ. -func (z nat) trunc(x nat, n uint) nat { - w := (n + _W - 1) / _W - if uint(len(x)) < w { - return z.set(x) - } - z = z.make(int(w)) - copy(z, x) - if n%_W != 0 { - z[len(z)-1] &= 1<<(n%_W) - 1 - } - return z.norm() -} - -func (z nat) andNot(x, y nat) nat { - m := len(x) - n := len(y) - if n > m { - n = m - } - // m >= n - - z = z.make(m) - for i := 0; i < n; i++ { - z[i] = x[i] &^ y[i] - } - copy(z[n:m], x[n:m]) - - return z.norm() -} - -func (z nat) or(x, y nat) nat { - m := len(x) - n := len(y) - s := x - if m < n { - n, m = m, n - s = y - } - // m >= n - - z = z.make(m) - for i := 0; i < n; i++ { - z[i] = x[i] | y[i] - } - copy(z[n:m], s[n:m]) - - return z.norm() -} - -func (z nat) xor(x, y nat) nat { - m := len(x) - n := len(y) - s := x - if m < n { - n, m = m, n - s = y - } - // m >= n - - z = z.make(m) - for i := 0; i < n; i++ { - z[i] = x[i] ^ y[i] - } - copy(z[n:m], s[n:m]) - - return z.norm() -} - -// random creates a random integer in [0..limit), using the space in z if -// possible. n is the bit length of limit. -func (z nat) random(rand *rand.Rand, limit nat, n int) nat { - if alias(z, limit) { - z = nil // z is an alias for limit - cannot reuse - } - z = z.make(len(limit)) - - bitLengthOfMSW := uint(n % _W) - if bitLengthOfMSW == 0 { - bitLengthOfMSW = _W - } - mask := Word((1 << bitLengthOfMSW) - 1) - - for { - switch _W { - case 32: - for i := range z { - z[i] = Word(rand.Uint32()) - } - case 64: - for i := range z { - z[i] = Word(rand.Uint32()) | Word(rand.Uint32())<<32 - } - default: - panic("unknown word size") - } - z[len(limit)-1] &= mask - if z.cmp(limit) < 0 { - break - } - } - - return z.norm() -} - -// If m != 0 (i.e., len(m) != 0), expNN sets z to x**y mod m; -// otherwise it sets z to x**y. The result is the value of z. -func (z nat) expNN(x, y, m nat, slow bool) nat { - if alias(z, x) || alias(z, y) { - // We cannot allow in-place modification of x or y. - z = nil - } - - // x**y mod 1 == 0 - if len(m) == 1 && m[0] == 1 { - return z.setWord(0) - } - // m == 0 || m > 1 - - // x**0 == 1 - if len(y) == 0 { - return z.setWord(1) - } - // y > 0 - - // 0**y = 0 - if len(x) == 0 { - return z.setWord(0) - } - // x > 0 - - // 1**y = 1 - if len(x) == 1 && x[0] == 1 { - return z.setWord(1) - } - // x > 1 - - // x**1 == x - if len(y) == 1 && y[0] == 1 { - if len(m) != 0 { - return z.rem(x, m) - } - return z.set(x) - } - // y > 1 - - if len(m) != 0 { - // We likely end up being as long as the modulus. - z = z.make(len(m)) - - // If the exponent is large, we use the Montgomery method for odd values, - // and a 4-bit, windowed exponentiation for powers of two, - // and a CRT-decomposed Montgomery method for the remaining values - // (even values times non-trivial odd values, which decompose into one - // instance of each of the first two cases). - if len(y) > 1 && !slow { - if m[0]&1 == 1 { - return z.expNNMontgomery(x, y, m) - } - if logM, ok := m.isPow2(); ok { - return z.expNNWindowed(x, y, logM) - } - return z.expNNMontgomeryEven(x, y, m) - } - } - - z = z.set(x) - v := y[len(y)-1] // v > 0 because y is normalized and y > 0 - shift := nlz(v) + 1 - v <<= shift - var q nat - - const mask = 1 << (_W - 1) - - // We walk through the bits of the exponent one by one. Each time we - // see a bit, we square, thus doubling the power. If the bit is a one, - // we also multiply by x, thus adding one to the power. - - w := _W - int(shift) - // zz and r are used to avoid allocating in mul and div as - // otherwise the arguments would alias. - var zz, r nat - for j := 0; j < w; j++ { - zz = zz.sqr(z) - zz, z = z, zz - - if v&mask != 0 { - zz = zz.mul(z, x) - zz, z = z, zz - } - - if len(m) != 0 { - zz, r = zz.div(r, z, m) - zz, r, q, z = q, z, zz, r - } - - v <<= 1 - } - - for i := len(y) - 2; i >= 0; i-- { - v = y[i] - - for j := 0; j < _W; j++ { - zz = zz.sqr(z) - zz, z = z, zz - - if v&mask != 0 { - zz = zz.mul(z, x) - zz, z = z, zz - } - - if len(m) != 0 { - zz, r = zz.div(r, z, m) - zz, r, q, z = q, z, zz, r - } - - v <<= 1 - } - } - - return z.norm() -} - -// expNNMontgomeryEven calculates x**y mod m where m = m1 × m2 for m1 = 2ⁿ and m2 odd. -// It uses two recursive calls to expNN for x**y mod m1 and x**y mod m2 -// and then uses the Chinese Remainder Theorem to combine the results. -// The recursive call using m1 will use expNNWindowed, -// while the recursive call using m2 will use expNNMontgomery. -// For more details, see Ç. K. Koç, “Montgomery Reduction with Even Modulus”, -// IEE Proceedings: Computers and Digital Techniques, 141(5) 314-316, September 1994. -// http://www.people.vcu.edu/~jwang3/CMSC691/j34monex.pdf -func (z nat) expNNMontgomeryEven(x, y, m nat) nat { - // Split m = m₁ × m₂ where m₁ = 2ⁿ - n := m.trailingZeroBits() - m1 := nat(nil).shl(natOne, n) - m2 := nat(nil).shr(m, n) - - // We want z = x**y mod m. - // z₁ = x**y mod m1 = (x**y mod m) mod m1 = z mod m1 - // z₂ = x**y mod m2 = (x**y mod m) mod m2 = z mod m2 - // (We are using the math/big convention for names here, - // where the computation is z = x**y mod m, so its parts are z1 and z2. - // The paper is computing x = a**e mod n; it refers to these as x2 and z1.) - z1 := nat(nil).expNN(x, y, m1, false) - z2 := nat(nil).expNN(x, y, m2, false) - - // Reconstruct z from z₁, z₂ using CRT, using algorithm from paper, - // which uses only a single modInverse (and an easy one at that). - // p = (z₁ - z₂) × m₂⁻¹ (mod m₁) - // z = z₂ + p × m₂ - // The final addition is in range because: - // z = z₂ + p × m₂ - // ≤ z₂ + (m₁-1) × m₂ - // < m₂ + (m₁-1) × m₂ - // = m₁ × m₂ - // = m. - z = z.set(z2) - - // Compute (z₁ - z₂) mod m1 [m1 == 2**n] into z1. - z1 = z1.subMod2N(z1, z2, n) - - // Reuse z2 for p = (z₁ - z₂) [in z1] * m2⁻¹ (mod m₁ [= 2ⁿ]). - m2inv := nat(nil).modInverse(m2, m1) - z2 = z2.mul(z1, m2inv) - z2 = z2.trunc(z2, n) - - // Reuse z1 for p * m2. - z = z.add(z, z1.mul(z2, m2)) - - return z -} - -// expNNWindowed calculates x**y mod m using a fixed, 4-bit window, -// where m = 2**logM. -func (z nat) expNNWindowed(x, y nat, logM uint) nat { - if len(y) <= 1 { - panic("big: misuse of expNNWindowed") - } - if x[0]&1 == 0 { - // len(y) > 1, so y > logM. - // x is even, so x**y is a multiple of 2**y which is a multiple of 2**logM. - return z.setWord(0) - } - if logM == 1 { - return z.setWord(1) - } - - // zz is used to avoid allocating in mul as otherwise - // the arguments would alias. - w := int((logM + _W - 1) / _W) - zzp := getNat(w) - zz := *zzp - - const n = 4 - // powers[i] contains x^i. - var powers [1 << n]*nat - for i := range powers { - powers[i] = getNat(w) - } - *powers[0] = powers[0].set(natOne) - *powers[1] = powers[1].trunc(x, logM) - for i := 2; i < 1< mtop { - i = mtop - } - advance := false - z = z.setWord(1) - for ; i >= 0; i-- { - yi := y[i] - if i == mtop { - yi &= mmask - } - for j := 0; j < _W; j += n { - if advance { - // Account for use of 4 bits in previous iteration. - // Unrolled loop for significant performance - // gain. Use go test -bench=".*" in crypto/rsa - // to check performance before making changes. - zz = zz.sqr(z) - zz, z = z, zz - z = z.trunc(z, logM) - - zz = zz.sqr(z) - zz, z = z, zz - z = z.trunc(z, logM) - - zz = zz.sqr(z) - zz, z = z, zz - z = z.trunc(z, logM) - - zz = zz.sqr(z) - zz, z = z, zz - z = z.trunc(z, logM) - } - - zz = zz.mul(z, *powers[yi>>(_W-n)]) - zz, z = z, zz - z = z.trunc(z, logM) - - yi <<= n - advance = true - } - } - - *zzp = zz - putNat(zzp) - for i := range powers { - putNat(powers[i]) - } - - return z.norm() -} - -// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window. -// Uses Montgomery representation. -func (z nat) expNNMontgomery(x, y, m nat) nat { - numWords := len(m) - - // We want the lengths of x and m to be equal. - // It is OK if x >= m as long as len(x) == len(m). - if len(x) > numWords { - _, x = nat(nil).div(nil, x, m) - // Note: now len(x) <= numWords, not guaranteed ==. - } - if len(x) < numWords { - rr := make(nat, numWords) - copy(rr, x) - x = rr - } - - // Ideally the precomputations would be performed outside, and reused - // k0 = -m**-1 mod 2**_W. Algorithm from: Dumas, J.G. "On Newton–Raphson - // Iteration for Multiplicative Inverses Modulo Prime Powers". - k0 := 2 - m[0] - t := m[0] - 1 - for i := 1; i < _W; i <<= 1 { - t *= t - k0 *= (t + 1) - } - k0 = -k0 - - // RR = 2**(2*_W*len(m)) mod m - RR := nat(nil).setWord(1) - zz := nat(nil).shl(RR, uint(2*numWords*_W)) - _, RR = nat(nil).div(RR, zz, m) - if len(RR) < numWords { - zz = zz.make(numWords) - copy(zz, RR) - RR = zz - } - // one = 1, with equal length to that of m - one := make(nat, numWords) - one[0] = 1 - - const n = 4 - // powers[i] contains x^i - var powers [1 << n]nat - powers[0] = powers[0].montgomery(one, RR, m, k0, numWords) - powers[1] = powers[1].montgomery(x, RR, m, k0, numWords) - for i := 2; i < 1<= 0; i-- { - yi := y[i] - for j := 0; j < _W; j += n { - if i != len(y)-1 || j != 0 { - zz = zz.montgomery(z, z, m, k0, numWords) - z = z.montgomery(zz, zz, m, k0, numWords) - zz = zz.montgomery(z, z, m, k0, numWords) - z = z.montgomery(zz, zz, m, k0, numWords) - } - zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords) - z, zz = zz, z - yi <<= n - } - } - // convert to regular number - zz = zz.montgomery(z, one, m, k0, numWords) - - // One last reduction, just in case. - // See golang.org/issue/13907. - if zz.cmp(m) >= 0 { - // Common case is m has high bit set; in that case, - // since zz is the same length as m, there can be just - // one multiple of m to remove. Just subtract. - // We think that the subtract should be sufficient in general, - // so do that unconditionally, but double-check, - // in case our beliefs are wrong. - // The div is not expected to be reached. - zz = zz.sub(zz, m) - if zz.cmp(m) >= 0 { - _, zz = nat(nil).div(nil, zz, m) - } - } - - return zz.norm() -} - -// bytes writes the value of z into buf using big-endian encoding. -// The value of z is encoded in the slice buf[i:]. If the value of z -// cannot be represented in buf, bytes panics. The number i of unused -// bytes at the beginning of buf is returned as result. -func (z nat) bytes(buf []byte) (i int) { - // This function is used in cryptographic operations. It must not leak - // anything but the Int's sign and bit size through side-channels. Any - // changes must be reviewed by a security expert. - i = len(buf) - for _, d := range z { - for j := 0; j < _S; j++ { - i-- - if i >= 0 { - buf[i] = byte(d) - } else if byte(d) != 0 { - panic("math/big: buffer too small to fit value") - } - d >>= 8 - } - } - - if i < 0 { - i = 0 - } - for i < len(buf) && buf[i] == 0 { - i++ - } - - return -} - -// bigEndianWord returns the contents of buf interpreted as a big-endian encoded Word value. -func bigEndianWord(buf []byte) Word { - if _W == 64 { - return Word(binary.BigEndian.Uint64(buf)) - } - return Word(binary.BigEndian.Uint32(buf)) -} - -// setBytes interprets buf as the bytes of a big-endian unsigned -// integer, sets z to that value, and returns z. -func (z nat) setBytes(buf []byte) nat { - z = z.make((len(buf) + _S - 1) / _S) - - i := len(buf) - for k := 0; i >= _S; k++ { - z[k] = bigEndianWord(buf[i-_S : i]) - i -= _S - } - if i > 0 { - var d Word - for s := uint(0); i > 0; s += 8 { - d |= Word(buf[i-1]) << s - i-- - } - z[len(z)-1] = d - } - - return z.norm() -} - -// sqrt sets z = ⌊√x⌋ -func (z nat) sqrt(x nat) nat { - if x.cmp(natOne) <= 0 { - return z.set(x) - } - if alias(z, x) { - z = nil - } - - // Start with value known to be too large and repeat "z = ⌊(z + ⌊x/z⌋)/2⌋" until it stops getting smaller. - // See Brent and Zimmermann, Modern Computer Arithmetic, Algorithm 1.13 (SqrtInt). - // https://members.loria.fr/PZimmermann/mca/pub226.html - // If x is one less than a perfect square, the sequence oscillates between the correct z and z+1; - // otherwise it converges to the correct z and stays there. - var z1, z2 nat - z1 = z - z1 = z1.setUint64(1) - z1 = z1.shl(z1, uint(x.bitLen()+1)/2) // must be ≥ √x - for n := 0; ; n++ { - z2, _ = z2.div(nil, x, z1) - z2 = z2.add(z2, z1) - z2 = z2.shr(z2, 1) - if z2.cmp(z1) >= 0 { - // z1 is answer. - // Figure out whether z1 or z2 is currently aliased to z by looking at loop count. - if n&1 == 0 { - return z1 - } - return z.set(z1) - } - z1, z2 = z2, z1 - } -} - -// subMod2N returns z = (x - y) mod 2ⁿ. -func (z nat) subMod2N(x, y nat, n uint) nat { - if uint(x.bitLen()) > n { - if alias(z, x) { - // ok to overwrite x in place - x = x.trunc(x, n) - } else { - x = nat(nil).trunc(x, n) - } - } - if uint(y.bitLen()) > n { - if alias(z, y) { - // ok to overwrite y in place - y = y.trunc(y, n) - } else { - y = nat(nil).trunc(y, n) - } - } - if x.cmp(y) >= 0 { - return z.sub(x, y) - } - // x - y < 0; x - y mod 2ⁿ = x - y + 2ⁿ = 2ⁿ - (y - x) = 1 + 2ⁿ-1 - (y - x) = 1 + ^(y - x). - z = z.sub(y, x) - for uint(len(z))*_W < n { - z = append(z, 0) - } - for i := range z { - z[i] = ^z[i] - } - z = z.trunc(z, n) - return z.add(z, natOne) -} diff --git a/contrib/go/_std_1.22/src/math/big/ya.make b/contrib/go/_std_1.22/src/math/big/ya.make deleted file mode 100644 index 02c6a9f230ec..000000000000 --- a/contrib/go/_std_1.22/src/math/big/ya.make +++ /dev/null @@ -1,54 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - accuracy_string.go - arith.go - arith_arm64.s - arith_decl.go - decimal.go - doc.go - float.go - floatconv.go - floatmarsh.go - ftoa.go - int.go - intconv.go - intmarsh.go - nat.go - natconv.go - natdiv.go - prime.go - rat.go - ratconv.go - ratmarsh.go - roundingmode_string.go - sqrt.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - accuracy_string.go - arith.go - arith_amd64.go - arith_amd64.s - arith_decl.go - decimal.go - doc.go - float.go - floatconv.go - floatmarsh.go - ftoa.go - int.go - intconv.go - intmarsh.go - nat.go - natconv.go - natdiv.go - prime.go - rat.go - ratconv.go - ratmarsh.go - roundingmode_string.go - sqrt.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/math/rand/rand.go b/contrib/go/_std_1.22/src/math/rand/rand.go deleted file mode 100644 index a8ed9c0cb7cf..000000000000 --- a/contrib/go/_std_1.22/src/math/rand/rand.go +++ /dev/null @@ -1,547 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package rand implements pseudo-random number generators suitable for tasks -// such as simulation, but it should not be used for security-sensitive work. -// -// Random numbers are generated by a [Source], usually wrapped in a [Rand]. -// Both types should be used by a single goroutine at a time: sharing among -// multiple goroutines requires some kind of synchronization. -// -// Top-level functions, such as [Float64] and [Int], -// are safe for concurrent use by multiple goroutines. -// -// This package's outputs might be easily predictable regardless of how it's -// seeded. For random numbers suitable for security-sensitive work, see the -// crypto/rand package. -package rand - -import ( - "internal/godebug" - "sync" - "sync/atomic" - _ "unsafe" // for go:linkname -) - -// A Source represents a source of uniformly-distributed -// pseudo-random int64 values in the range [0, 1<<63). -// -// A Source is not safe for concurrent use by multiple goroutines. -type Source interface { - Int63() int64 - Seed(seed int64) -} - -// A Source64 is a [Source] that can also generate -// uniformly-distributed pseudo-random uint64 values in -// the range [0, 1<<64) directly. -// If a [Rand] r's underlying [Source] s implements Source64, -// then r.Uint64 returns the result of one call to s.Uint64 -// instead of making two calls to s.Int63. -type Source64 interface { - Source - Uint64() uint64 -} - -// NewSource returns a new pseudo-random [Source] seeded with the given value. -// Unlike the default [Source] used by top-level functions, this source is not -// safe for concurrent use by multiple goroutines. -// The returned [Source] implements [Source64]. -func NewSource(seed int64) Source { - return newSource(seed) -} - -func newSource(seed int64) *rngSource { - var rng rngSource - rng.Seed(seed) - return &rng -} - -// A Rand is a source of random numbers. -type Rand struct { - src Source - s64 Source64 // non-nil if src is source64 - - // readVal contains remainder of 63-bit integer used for bytes - // generation during most recent Read call. - // It is saved so next Read call can start where the previous - // one finished. - readVal int64 - // readPos indicates the number of low-order bytes of readVal - // that are still valid. - readPos int8 -} - -// New returns a new [Rand] that uses random values from src -// to generate other random values. -func New(src Source) *Rand { - s64, _ := src.(Source64) - return &Rand{src: src, s64: s64} -} - -// Seed uses the provided seed value to initialize the generator to a deterministic state. -// Seed should not be called concurrently with any other [Rand] method. -func (r *Rand) Seed(seed int64) { - if lk, ok := r.src.(*lockedSource); ok { - lk.seedPos(seed, &r.readPos) - return - } - - r.src.Seed(seed) - r.readPos = 0 -} - -// Int63 returns a non-negative pseudo-random 63-bit integer as an int64. -func (r *Rand) Int63() int64 { return r.src.Int63() } - -// Uint32 returns a pseudo-random 32-bit value as a uint32. -func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) } - -// Uint64 returns a pseudo-random 64-bit value as a uint64. -func (r *Rand) Uint64() uint64 { - if r.s64 != nil { - return r.s64.Uint64() - } - return uint64(r.Int63())>>31 | uint64(r.Int63())<<32 -} - -// Int31 returns a non-negative pseudo-random 31-bit integer as an int32. -func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) } - -// Int returns a non-negative pseudo-random int. -func (r *Rand) Int() int { - u := uint(r.Int63()) - return int(u << 1 >> 1) // clear sign bit if int == int32 -} - -// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n). -// It panics if n <= 0. -func (r *Rand) Int63n(n int64) int64 { - if n <= 0 { - panic("invalid argument to Int63n") - } - if n&(n-1) == 0 { // n is power of two, can mask - return r.Int63() & (n - 1) - } - max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) - v := r.Int63() - for v > max { - v = r.Int63() - } - return v % n -} - -// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). -// It panics if n <= 0. -func (r *Rand) Int31n(n int32) int32 { - if n <= 0 { - panic("invalid argument to Int31n") - } - if n&(n-1) == 0 { // n is power of two, can mask - return r.Int31() & (n - 1) - } - max := int32((1 << 31) - 1 - (1<<31)%uint32(n)) - v := r.Int31() - for v > max { - v = r.Int31() - } - return v % n -} - -// int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). -// n must be > 0, but int31n does not check this; the caller must ensure it. -// int31n exists because Int31n is inefficient, but Go 1 compatibility -// requires that the stream of values produced by math/rand remain unchanged. -// int31n can thus only be used internally, by newly introduced APIs. -// -// For implementation details, see: -// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction -// https://lemire.me/blog/2016/06/30/fast-random-shuffling -func (r *Rand) int31n(n int32) int32 { - v := r.Uint32() - prod := uint64(v) * uint64(n) - low := uint32(prod) - if low < uint32(n) { - thresh := uint32(-n) % uint32(n) - for low < thresh { - v = r.Uint32() - prod = uint64(v) * uint64(n) - low = uint32(prod) - } - } - return int32(prod >> 32) -} - -// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n). -// It panics if n <= 0. -func (r *Rand) Intn(n int) int { - if n <= 0 { - panic("invalid argument to Intn") - } - if n <= 1<<31-1 { - return int(r.Int31n(int32(n))) - } - return int(r.Int63n(int64(n))) -} - -// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0). -func (r *Rand) Float64() float64 { - // A clearer, simpler implementation would be: - // return float64(r.Int63n(1<<53)) / (1<<53) - // However, Go 1 shipped with - // return float64(r.Int63()) / (1 << 63) - // and we want to preserve that value stream. - // - // There is one bug in the value stream: r.Int63() may be so close - // to 1<<63 that the division rounds up to 1.0, and we've guaranteed - // that the result is always less than 1.0. - // - // We tried to fix this by mapping 1.0 back to 0.0, but since float64 - // values near 0 are much denser than near 1, mapping 1 to 0 caused - // a theoretically significant overshoot in the probability of returning 0. - // Instead of that, if we round up to 1, just try again. - // Getting 1 only happens 1/2⁵³ of the time, so most clients - // will not observe it anyway. -again: - f := float64(r.Int63()) / (1 << 63) - if f == 1 { - goto again // resample; this branch is taken O(never) - } - return f -} - -// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0). -func (r *Rand) Float32() float32 { - // Same rationale as in Float64: we want to preserve the Go 1 value - // stream except we want to fix it not to return 1.0 - // This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64). -again: - f := float32(r.Float64()) - if f == 1 { - goto again // resample; this branch is taken O(very rarely) - } - return f -} - -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers -// in the half-open interval [0,n). -func (r *Rand) Perm(n int) []int { - m := make([]int, n) - // In the following loop, the iteration when i=0 always swaps m[0] with m[0]. - // A change to remove this useless iteration is to assign 1 to i in the init - // statement. But Perm also effects r. Making this change will affect - // the final state of r. So this change can't be made for compatibility - // reasons for Go 1. - for i := 0; i < n; i++ { - j := r.Intn(i + 1) - m[i] = m[j] - m[j] = i - } - return m -} - -// Shuffle pseudo-randomizes the order of elements. -// n is the number of elements. Shuffle panics if n < 0. -// swap swaps the elements with indexes i and j. -func (r *Rand) Shuffle(n int, swap func(i, j int)) { - if n < 0 { - panic("invalid argument to Shuffle") - } - - // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle - // Shuffle really ought not be called with n that doesn't fit in 32 bits. - // Not only will it take a very long time, but with 2³¹! possible permutations, - // there's no way that any PRNG can have a big enough internal state to - // generate even a minuscule percentage of the possible permutations. - // Nevertheless, the right API signature accepts an int n, so handle it as best we can. - i := n - 1 - for ; i > 1<<31-1-1; i-- { - j := int(r.Int63n(int64(i + 1))) - swap(i, j) - } - for ; i > 0; i-- { - j := int(r.int31n(int32(i + 1))) - swap(i, j) - } -} - -// Read generates len(p) random bytes and writes them into p. It -// always returns len(p) and a nil error. -// Read should not be called concurrently with any other Rand method. -func (r *Rand) Read(p []byte) (n int, err error) { - switch src := r.src.(type) { - case *lockedSource: - return src.read(p, &r.readVal, &r.readPos) - case *runtimeSource: - return src.read(p, &r.readVal, &r.readPos) - } - return read(p, r.src, &r.readVal, &r.readPos) -} - -func read(p []byte, src Source, readVal *int64, readPos *int8) (n int, err error) { - pos := *readPos - val := *readVal - rng, _ := src.(*rngSource) - for n = 0; n < len(p); n++ { - if pos == 0 { - if rng != nil { - val = rng.Int63() - } else { - val = src.Int63() - } - pos = 7 - } - p[n] = byte(val) - val >>= 8 - pos-- - } - *readPos = pos - *readVal = val - return -} - -/* - * Top-level convenience functions - */ - -// globalRandGenerator is the source of random numbers for the top-level -// convenience functions. When possible it uses the runtime fastrand64 -// function to avoid locking. This is not possible if the user called Seed, -// either explicitly or implicitly via GODEBUG=randautoseed=0. -var globalRandGenerator atomic.Pointer[Rand] - -var randautoseed = godebug.New("randautoseed") - -// globalRand returns the generator to use for the top-level convenience -// functions. -func globalRand() *Rand { - if r := globalRandGenerator.Load(); r != nil { - return r - } - - // This is the first call. Initialize based on GODEBUG. - var r *Rand - if randautoseed.Value() == "0" { - randautoseed.IncNonDefault() - r = New(new(lockedSource)) - r.Seed(1) - } else { - r = &Rand{ - src: &runtimeSource{}, - s64: &runtimeSource{}, - } - } - - if !globalRandGenerator.CompareAndSwap(nil, r) { - // Two different goroutines called some top-level - // function at the same time. While the results in - // that case are unpredictable, if we just use r here, - // and we are using a seed, we will most likely return - // the same value for both calls. That doesn't seem ideal. - // Just use the first one to get in. - return globalRandGenerator.Load() - } - - return r -} - -//go:linkname runtime_rand runtime.rand -func runtime_rand() uint64 - -// runtimeSource is an implementation of Source64 that uses the runtime -// fastrand functions. -type runtimeSource struct { - // The mutex is used to avoid race conditions in Read. - mu sync.Mutex -} - -func (*runtimeSource) Int63() int64 { - return int64(runtime_rand() & rngMask) -} - -func (*runtimeSource) Seed(int64) { - panic("internal error: call to runtimeSource.Seed") -} - -func (*runtimeSource) Uint64() uint64 { - return runtime_rand() -} - -func (fs *runtimeSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) { - fs.mu.Lock() - n, err = read(p, fs, readVal, readPos) - fs.mu.Unlock() - return -} - -// Seed uses the provided seed value to initialize the default Source to a -// deterministic state. Seed values that have the same remainder when -// divided by 2³¹-1 generate the same pseudo-random sequence. -// Seed, unlike the [Rand.Seed] method, is safe for concurrent use. -// -// If Seed is not called, the generator is seeded randomly at program startup. -// -// Prior to Go 1.20, the generator was seeded like Seed(1) at program startup. -// To force the old behavior, call Seed(1) at program startup. -// Alternately, set GODEBUG=randautoseed=0 in the environment -// before making any calls to functions in this package. -// -// Deprecated: As of Go 1.20 there is no reason to call Seed with -// a random value. Programs that call Seed with a known value to get -// a specific sequence of results should use New(NewSource(seed)) to -// obtain a local random generator. -func Seed(seed int64) { - orig := globalRandGenerator.Load() - - // If we are already using a lockedSource, we can just re-seed it. - if orig != nil { - if _, ok := orig.src.(*lockedSource); ok { - orig.Seed(seed) - return - } - } - - // Otherwise either - // 1) orig == nil, which is the normal case when Seed is the first - // top-level function to be called, or - // 2) orig is already a runtimeSource, in which case we need to change - // to a lockedSource. - // Either way we do the same thing. - - r := New(new(lockedSource)) - r.Seed(seed) - - if !globalRandGenerator.CompareAndSwap(orig, r) { - // Something changed underfoot. Retry to be safe. - Seed(seed) - } -} - -// Int63 returns a non-negative pseudo-random 63-bit integer as an int64 -// from the default [Source]. -func Int63() int64 { return globalRand().Int63() } - -// Uint32 returns a pseudo-random 32-bit value as a uint32 -// from the default [Source]. -func Uint32() uint32 { return globalRand().Uint32() } - -// Uint64 returns a pseudo-random 64-bit value as a uint64 -// from the default [Source]. -func Uint64() uint64 { return globalRand().Uint64() } - -// Int31 returns a non-negative pseudo-random 31-bit integer as an int32 -// from the default [Source]. -func Int31() int32 { return globalRand().Int31() } - -// Int returns a non-negative pseudo-random int from the default [Source]. -func Int() int { return globalRand().Int() } - -// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n) -// from the default [Source]. -// It panics if n <= 0. -func Int63n(n int64) int64 { return globalRand().Int63n(n) } - -// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n) -// from the default [Source]. -// It panics if n <= 0. -func Int31n(n int32) int32 { return globalRand().Int31n(n) } - -// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n) -// from the default [Source]. -// It panics if n <= 0. -func Intn(n int) int { return globalRand().Intn(n) } - -// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0) -// from the default [Source]. -func Float64() float64 { return globalRand().Float64() } - -// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0) -// from the default [Source]. -func Float32() float32 { return globalRand().Float32() } - -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers -// in the half-open interval [0,n) from the default [Source]. -func Perm(n int) []int { return globalRand().Perm(n) } - -// Shuffle pseudo-randomizes the order of elements using the default [Source]. -// n is the number of elements. Shuffle panics if n < 0. -// swap swaps the elements with indexes i and j. -func Shuffle(n int, swap func(i, j int)) { globalRand().Shuffle(n, swap) } - -// Read generates len(p) random bytes from the default [Source] and -// writes them into p. It always returns len(p) and a nil error. -// Read, unlike the [Rand.Read] method, is safe for concurrent use. -// -// Deprecated: For almost all use cases, [crypto/rand.Read] is more appropriate. -func Read(p []byte) (n int, err error) { return globalRand().Read(p) } - -// NormFloat64 returns a normally distributed float64 in the range -// [-[math.MaxFloat64], +[math.MaxFloat64]] with -// standard normal distribution (mean = 0, stddev = 1) -// from the default [Source]. -// To produce a different normal distribution, callers can -// adjust the output using: -// -// sample = NormFloat64() * desiredStdDev + desiredMean -func NormFloat64() float64 { return globalRand().NormFloat64() } - -// ExpFloat64 returns an exponentially distributed float64 in the range -// (0, +[math.MaxFloat64]] with an exponential distribution whose rate parameter -// (lambda) is 1 and whose mean is 1/lambda (1) from the default [Source]. -// To produce a distribution with a different rate parameter, -// callers can adjust the output using: -// -// sample = ExpFloat64() / desiredRateParameter -func ExpFloat64() float64 { return globalRand().ExpFloat64() } - -type lockedSource struct { - lk sync.Mutex - s *rngSource -} - -func (r *lockedSource) Int63() (n int64) { - r.lk.Lock() - n = r.s.Int63() - r.lk.Unlock() - return -} - -func (r *lockedSource) Uint64() (n uint64) { - r.lk.Lock() - n = r.s.Uint64() - r.lk.Unlock() - return -} - -func (r *lockedSource) Seed(seed int64) { - r.lk.Lock() - r.seed(seed) - r.lk.Unlock() -} - -// seedPos implements Seed for a lockedSource without a race condition. -func (r *lockedSource) seedPos(seed int64, readPos *int8) { - r.lk.Lock() - r.seed(seed) - *readPos = 0 - r.lk.Unlock() -} - -// seed seeds the underlying source. -// The caller must have locked r.lk. -func (r *lockedSource) seed(seed int64) { - if r.s == nil { - r.s = newSource(seed) - } else { - r.s.Seed(seed) - } -} - -// read implements Read for a lockedSource without a race condition. -func (r *lockedSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) { - r.lk.Lock() - n, err = read(p, r.s, readVal, readPos) - r.lk.Unlock() - return -} diff --git a/contrib/go/_std_1.22/src/math/rand/v2/chacha8.go b/contrib/go/_std_1.22/src/math/rand/v2/chacha8.go deleted file mode 100644 index 6b9aa7278250..000000000000 --- a/contrib/go/_std_1.22/src/math/rand/v2/chacha8.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rand - -import "internal/chacha8rand" - -// A ChaCha8 is a ChaCha8-based cryptographically strong -// random number generator. -type ChaCha8 struct { - state chacha8rand.State -} - -// NewChaCha8 returns a new ChaCha8 seeded with the given seed. -func NewChaCha8(seed [32]byte) *ChaCha8 { - c := new(ChaCha8) - c.state.Init(seed) - return c -} - -// Seed resets the ChaCha8 to behave the same way as NewChaCha8(seed). -func (c *ChaCha8) Seed(seed [32]byte) { - c.state.Init(seed) -} - -// Uint64 returns a uniformly distributed random uint64 value. -func (c *ChaCha8) Uint64() uint64 { - for { - x, ok := c.state.Next() - if ok { - return x - } - c.state.Refill() - } -} - -// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. -func (c *ChaCha8) UnmarshalBinary(data []byte) error { - return chacha8rand.Unmarshal(&c.state, data) -} - -// MarshalBinary implements the encoding.BinaryMarshaler interface. -func (c *ChaCha8) MarshalBinary() ([]byte, error) { - return chacha8rand.Marshal(&c.state), nil -} diff --git a/contrib/go/_std_1.22/src/math/rand/v2/rand.go b/contrib/go/_std_1.22/src/math/rand/v2/rand.go deleted file mode 100644 index f490408472ba..000000000000 --- a/contrib/go/_std_1.22/src/math/rand/v2/rand.go +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package rand implements pseudo-random number generators suitable for tasks -// such as simulation, but it should not be used for security-sensitive work. -// -// Random numbers are generated by a [Source], usually wrapped in a [Rand]. -// Both types should be used by a single goroutine at a time: sharing among -// multiple goroutines requires some kind of synchronization. -// -// Top-level functions, such as [Float64] and [Int], -// are safe for concurrent use by multiple goroutines. -// -// This package's outputs might be easily predictable regardless of how it's -// seeded. For random numbers suitable for security-sensitive work, see the -// crypto/rand package. -package rand - -import ( - "math/bits" - _ "unsafe" // for go:linkname -) - -// A Source is a source of uniformly-distributed -// pseudo-random uint64 values in the range [0, 1<<64). -// -// A Source is not safe for concurrent use by multiple goroutines. -type Source interface { - Uint64() uint64 -} - -// A Rand is a source of random numbers. -type Rand struct { - src Source -} - -// New returns a new Rand that uses random values from src -// to generate other random values. -func New(src Source) *Rand { - return &Rand{src: src} -} - -// Int64 returns a non-negative pseudo-random 63-bit integer as an int64. -func (r *Rand) Int64() int64 { return int64(r.src.Uint64() &^ (1 << 63)) } - -// Uint32 returns a pseudo-random 32-bit value as a uint32. -func (r *Rand) Uint32() uint32 { return uint32(r.src.Uint64() >> 32) } - -// Uint64 returns a pseudo-random 64-bit value as a uint64. -func (r *Rand) Uint64() uint64 { return r.src.Uint64() } - -// Int32 returns a non-negative pseudo-random 31-bit integer as an int32. -func (r *Rand) Int32() int32 { return int32(r.src.Uint64() >> 33) } - -// Int returns a non-negative pseudo-random int. -func (r *Rand) Int() int { return int(uint(r.src.Uint64()) << 1 >> 1) } - -// Int64N returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n). -// It panics if n <= 0. -func (r *Rand) Int64N(n int64) int64 { - if n <= 0 { - panic("invalid argument to Int64N") - } - return int64(r.uint64n(uint64(n))) -} - -// Uint64N returns, as a uint64, a non-negative pseudo-random number in the half-open interval [0,n). -// It panics if n == 0. -func (r *Rand) Uint64N(n uint64) uint64 { - if n == 0 { - panic("invalid argument to Uint64N") - } - return r.uint64n(n) -} - -// uint64n is the no-bounds-checks version of Uint64N. -func (r *Rand) uint64n(n uint64) uint64 { - if is32bit && uint64(uint32(n)) == n { - return uint64(r.uint32n(uint32(n))) - } - if n&(n-1) == 0 { // n is power of two, can mask - return r.Uint64() & (n - 1) - } - - // Suppose we have a uint64 x uniform in the range [0,2⁶⁴) - // and want to reduce it to the range [0,n) preserving exact uniformity. - // We can simulate a scaling arbitrary precision x * (n/2⁶⁴) by - // the high bits of a double-width multiply of x*n, meaning (x*n)/2⁶⁴. - // Since there are 2⁶⁴ possible inputs x and only n possible outputs, - // the output is necessarily biased if n does not divide 2⁶⁴. - // In general (x*n)/2⁶⁴ = k for x*n in [k*2⁶⁴,(k+1)*2⁶⁴). - // There are either floor(2⁶⁴/n) or ceil(2⁶⁴/n) possible products - // in that range, depending on k. - // But suppose we reject the sample and try again when - // x*n is in [k*2⁶⁴, k*2⁶⁴+(2⁶⁴%n)), meaning rejecting fewer than n possible - // outcomes out of the 2⁶⁴. - // Now there are exactly floor(2⁶⁴/n) possible ways to produce - // each output value k, so we've restored uniformity. - // To get valid uint64 math, 2⁶⁴ % n = (2⁶⁴ - n) % n = -n % n, - // so the direct implementation of this algorithm would be: - // - // hi, lo := bits.Mul64(r.Uint64(), n) - // thresh := -n % n - // for lo < thresh { - // hi, lo = bits.Mul64(r.Uint64(), n) - // } - // - // That still leaves an expensive 64-bit division that we would rather avoid. - // We know that thresh < n, and n is usually much less than 2⁶⁴, so we can - // avoid the last four lines unless lo < n. - // - // See also: - // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction - // https://lemire.me/blog/2016/06/30/fast-random-shuffling - hi, lo := bits.Mul64(r.Uint64(), n) - if lo < n { - thresh := -n % n - for lo < thresh { - hi, lo = bits.Mul64(r.Uint64(), n) - } - } - return hi -} - -// uint32n is an identical computation to uint64n -// but optimized for 32-bit systems. -func (r *Rand) uint32n(n uint32) uint32 { - if n&(n-1) == 0 { // n is power of two, can mask - return uint32(r.Uint64()) & (n - 1) - } - // On 64-bit systems we still use the uint64 code below because - // the probability of a random uint64 lo being < a uint32 n is near zero, - // meaning the unbiasing loop almost never runs. - // On 32-bit systems, here we need to implement that same logic in 32-bit math, - // both to preserve the exact output sequence observed on 64-bit machines - // and to preserve the optimization that the unbiasing loop almost never runs. - // - // We want to compute - // hi, lo := bits.Mul64(r.Uint64(), n) - // In terms of 32-bit halves, this is: - // x1:x0 := r.Uint64() - // 0:hi, lo1:lo0 := bits.Mul64(x1:x0, 0:n) - // Writing out the multiplication in terms of bits.Mul32 allows - // using direct hardware instructions and avoiding - // the computations involving these zeros. - x := r.Uint64() - lo1a, lo0 := bits.Mul32(uint32(x), n) - hi, lo1b := bits.Mul32(uint32(x>>32), n) - lo1, c := bits.Add32(lo1a, lo1b, 0) - hi += c - if lo1 == 0 && lo0 < uint32(n) { - n64 := uint64(n) - thresh := uint32(-n64 % n64) - for lo1 == 0 && lo0 < thresh { - x := r.Uint64() - lo1a, lo0 = bits.Mul32(uint32(x), n) - hi, lo1b = bits.Mul32(uint32(x>>32), n) - lo1, c = bits.Add32(lo1a, lo1b, 0) - hi += c - } - } - return hi -} - -// Int32N returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). -// It panics if n <= 0. -func (r *Rand) Int32N(n int32) int32 { - if n <= 0 { - panic("invalid argument to Int32N") - } - return int32(r.uint64n(uint64(n))) -} - -// Uint32N returns, as a uint32, a non-negative pseudo-random number in the half-open interval [0,n). -// It panics if n == 0. -func (r *Rand) Uint32N(n uint32) uint32 { - if n == 0 { - panic("invalid argument to Uint32N") - } - return uint32(r.uint64n(uint64(n))) -} - -const is32bit = ^uint(0)>>32 == 0 - -// IntN returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n). -// It panics if n <= 0. -func (r *Rand) IntN(n int) int { - if n <= 0 { - panic("invalid argument to IntN") - } - return int(r.uint64n(uint64(n))) -} - -// UintN returns, as a uint, a non-negative pseudo-random number in the half-open interval [0,n). -// It panics if n == 0. -func (r *Rand) UintN(n uint) uint { - if n == 0 { - panic("invalid argument to UintN") - } - return uint(r.uint64n(uint64(n))) -} - -// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0). -func (r *Rand) Float64() float64 { - // There are exactly 1<<53 float64s in [0,1). Use Intn(1<<53) / (1<<53). - return float64(r.Uint64()<<11>>11) / (1 << 53) -} - -// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0). -func (r *Rand) Float32() float32 { - // There are exactly 1<<24 float32s in [0,1). Use Intn(1<<24) / (1<<24). - return float32(r.Uint32()<<8>>8) / (1 << 24) -} - -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers -// in the half-open interval [0,n). -func (r *Rand) Perm(n int) []int { - p := make([]int, n) - for i := range p { - p[i] = i - } - r.Shuffle(len(p), func(i, j int) { p[i], p[j] = p[j], p[i] }) - return p -} - -// Shuffle pseudo-randomizes the order of elements. -// n is the number of elements. Shuffle panics if n < 0. -// swap swaps the elements with indexes i and j. -func (r *Rand) Shuffle(n int, swap func(i, j int)) { - if n < 0 { - panic("invalid argument to Shuffle") - } - - // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle - // Shuffle really ought not be called with n that doesn't fit in 32 bits. - // Not only will it take a very long time, but with 2³¹! possible permutations, - // there's no way that any PRNG can have a big enough internal state to - // generate even a minuscule percentage of the possible permutations. - // Nevertheless, the right API signature accepts an int n, so handle it as best we can. - for i := n - 1; i > 0; i-- { - j := int(r.uint64n(uint64(i + 1))) - swap(i, j) - } -} - -/* - * Top-level convenience functions - */ - -// globalRand is the source of random numbers for the top-level -// convenience functions. -var globalRand = &Rand{src: &runtimeSource{}} - -//go:linkname runtime_rand runtime.rand -func runtime_rand() uint64 - -// runtimeSource is a Source that uses the runtime fastrand functions. -type runtimeSource struct{} - -func (*runtimeSource) Uint64() uint64 { - return runtime_rand() -} - -// Int64 returns a non-negative pseudo-random 63-bit integer as an int64 -// from the default Source. -func Int64() int64 { return globalRand.Int64() } - -// Uint32 returns a pseudo-random 32-bit value as a uint32 -// from the default Source. -func Uint32() uint32 { return globalRand.Uint32() } - -// Uint64N returns, as a uint64, a pseudo-random number in the half-open interval [0,n) -// from the default Source. -// It panics if n <= 0. -func Uint64N(n uint64) uint64 { return globalRand.Uint64N(n) } - -// Uint32N returns, as a uint32, a pseudo-random number in the half-open interval [0,n) -// from the default Source. -// It panics if n <= 0. -func Uint32N(n uint32) uint32 { return globalRand.Uint32N(n) } - -// Uint64 returns a pseudo-random 64-bit value as a uint64 -// from the default Source. -func Uint64() uint64 { return globalRand.Uint64() } - -// Int32 returns a non-negative pseudo-random 31-bit integer as an int32 -// from the default Source. -func Int32() int32 { return globalRand.Int32() } - -// Int returns a non-negative pseudo-random int from the default Source. -func Int() int { return globalRand.Int() } - -// Int64N returns, as an int64, a pseudo-random number in the half-open interval [0,n) -// from the default Source. -// It panics if n <= 0. -func Int64N(n int64) int64 { return globalRand.Int64N(n) } - -// Int32N returns, as an int32, a pseudo-random number in the half-open interval [0,n) -// from the default Source. -// It panics if n <= 0. -func Int32N(n int32) int32 { return globalRand.Int32N(n) } - -// IntN returns, as an int, a pseudo-random number in the half-open interval [0,n) -// from the default Source. -// It panics if n <= 0. -func IntN(n int) int { return globalRand.IntN(n) } - -// UintN returns, as a uint, a pseudo-random number in the half-open interval [0,n) -// from the default Source. -// It panics if n <= 0. -func UintN(n uint) uint { return globalRand.UintN(n) } - -// N returns a pseudo-random number in the half-open interval [0,n) from the default Source. -// The type parameter Int can be any integer type. -// It panics if n <= 0. -func N[Int intType](n Int) Int { - if n <= 0 { - panic("invalid argument to N") - } - return Int(globalRand.uint64n(uint64(n))) -} - -type intType interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr -} - -// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0) -// from the default Source. -func Float64() float64 { return globalRand.Float64() } - -// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0) -// from the default Source. -func Float32() float32 { return globalRand.Float32() } - -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers -// in the half-open interval [0,n) from the default Source. -func Perm(n int) []int { return globalRand.Perm(n) } - -// Shuffle pseudo-randomizes the order of elements using the default Source. -// n is the number of elements. Shuffle panics if n < 0. -// swap swaps the elements with indexes i and j. -func Shuffle(n int, swap func(i, j int)) { globalRand.Shuffle(n, swap) } - -// NormFloat64 returns a normally distributed float64 in the range -// [-math.MaxFloat64, +math.MaxFloat64] with -// standard normal distribution (mean = 0, stddev = 1) -// from the default Source. -// To produce a different normal distribution, callers can -// adjust the output using: -// -// sample = NormFloat64() * desiredStdDev + desiredMean -func NormFloat64() float64 { return globalRand.NormFloat64() } - -// ExpFloat64 returns an exponentially distributed float64 in the range -// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter -// (lambda) is 1 and whose mean is 1/lambda (1) from the default Source. -// To produce a distribution with a different rate parameter, -// callers can adjust the output using: -// -// sample = ExpFloat64() / desiredRateParameter -func ExpFloat64() float64 { return globalRand.ExpFloat64() } diff --git a/contrib/go/_std_1.22/src/math/rand/v2/ya.make b/contrib/go/_std_1.22/src/math/rand/v2/ya.make deleted file mode 100644 index 709d17ea4d94..000000000000 --- a/contrib/go/_std_1.22/src/math/rand/v2/ya.make +++ /dev/null @@ -1,14 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (TRUE) - SRCS( - chacha8.go - exp.go - normal.go - pcg.go - rand.go - zipf.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/math/unsafe.go b/contrib/go/_std_1.22/src/math/unsafe.go deleted file mode 100644 index e59f50ca62e5..000000000000 --- a/contrib/go/_std_1.22/src/math/unsafe.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import "unsafe" - -// Float32bits returns the IEEE 754 binary representation of f, -// with the sign bit of f and the result in the same bit position. -// Float32bits(Float32frombits(x)) == x. -func Float32bits(f float32) uint32 { return *(*uint32)(unsafe.Pointer(&f)) } - -// Float32frombits returns the floating-point number corresponding -// to the IEEE 754 binary representation b, with the sign bit of b -// and the result in the same bit position. -// Float32frombits(Float32bits(x)) == x. -func Float32frombits(b uint32) float32 { return *(*float32)(unsafe.Pointer(&b)) } - -// Float64bits returns the IEEE 754 binary representation of f, -// with the sign bit of f and the result in the same bit position, -// and Float64bits(Float64frombits(x)) == x. -func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) } - -// Float64frombits returns the floating-point number corresponding -// to the IEEE 754 binary representation b, with the sign bit of b -// and the result in the same bit position. -// Float64frombits(Float64bits(x)) == x. -func Float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) } diff --git a/contrib/go/_std_1.22/src/math/ya.make b/contrib/go/_std_1.22/src/math/ya.make deleted file mode 100644 index daf65b084a79..000000000000 --- a/contrib/go/_std_1.22/src/math/ya.make +++ /dev/null @@ -1,125 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - abs.go - acosh.go - asin.go - asinh.go - atan.go - atan2.go - atanh.go - bits.go - cbrt.go - const.go - copysign.go - dim.go - dim_arm64.s - dim_asm.go - erf.go - erfinv.go - exp.go - exp2_asm.go - exp_arm64.s - exp_asm.go - expm1.go - floor.go - floor_arm64.s - floor_asm.go - fma.go - frexp.go - gamma.go - hypot.go - hypot_noasm.go - j0.go - j1.go - jn.go - ldexp.go - lgamma.go - log.go - log10.go - log1p.go - log_stub.go - logb.go - mod.go - modf.go - modf_arm64.s - modf_asm.go - nextafter.go - pow.go - pow10.go - remainder.go - signbit.go - sin.go - sincos.go - sinh.go - sqrt.go - stubs.go - tan.go - tanh.go - trig_reduce.go - unsafe.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - abs.go - acosh.go - asin.go - asinh.go - atan.go - atan2.go - atanh.go - bits.go - cbrt.go - const.go - copysign.go - dim.go - dim_amd64.s - dim_asm.go - erf.go - erfinv.go - exp.go - exp2_noasm.go - exp_amd64.go - exp_amd64.s - exp_asm.go - expm1.go - floor.go - floor_amd64.s - floor_asm.go - fma.go - frexp.go - gamma.go - hypot.go - hypot_amd64.s - hypot_asm.go - j0.go - j1.go - jn.go - ldexp.go - lgamma.go - log.go - log10.go - log1p.go - log_amd64.s - log_asm.go - logb.go - mod.go - modf.go - modf_noasm.go - nextafter.go - pow.go - pow10.go - remainder.go - signbit.go - sin.go - sincos.go - sinh.go - sqrt.go - stubs.go - tan.go - tanh.go - trig_reduce.go - unsafe.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/mime/multipart/writer.go b/contrib/go/_std_1.22/src/mime/multipart/writer.go deleted file mode 100644 index d1ff151a7d1d..000000000000 --- a/contrib/go/_std_1.22/src/mime/multipart/writer.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package multipart - -import ( - "bytes" - "crypto/rand" - "errors" - "fmt" - "io" - "net/textproto" - "sort" - "strings" -) - -// A Writer generates multipart messages. -type Writer struct { - w io.Writer - boundary string - lastpart *part -} - -// NewWriter returns a new multipart Writer with a random boundary, -// writing to w. -func NewWriter(w io.Writer) *Writer { - return &Writer{ - w: w, - boundary: randomBoundary(), - } -} - -// Boundary returns the Writer's boundary. -func (w *Writer) Boundary() string { - return w.boundary -} - -// SetBoundary overrides the Writer's default randomly-generated -// boundary separator with an explicit value. -// -// SetBoundary must be called before any parts are created, may only -// contain certain ASCII characters, and must be non-empty and -// at most 70 bytes long. -func (w *Writer) SetBoundary(boundary string) error { - if w.lastpart != nil { - return errors.New("mime: SetBoundary called after write") - } - // rfc2046#section-5.1.1 - if len(boundary) < 1 || len(boundary) > 70 { - return errors.New("mime: invalid boundary length") - } - end := len(boundary) - 1 - for i, b := range boundary { - if 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' { - continue - } - switch b { - case '\'', '(', ')', '+', '_', ',', '-', '.', '/', ':', '=', '?': - continue - case ' ': - if i != end { - continue - } - } - return errors.New("mime: invalid boundary character") - } - w.boundary = boundary - return nil -} - -// FormDataContentType returns the Content-Type for an HTTP -// multipart/form-data with this Writer's Boundary. -func (w *Writer) FormDataContentType() string { - b := w.boundary - // We must quote the boundary if it contains any of the - // tspecials characters defined by RFC 2045, or space. - if strings.ContainsAny(b, `()<>@,;:\"/[]?= `) { - b = `"` + b + `"` - } - return "multipart/form-data; boundary=" + b -} - -func randomBoundary() string { - var buf [30]byte - _, err := io.ReadFull(rand.Reader, buf[:]) - if err != nil { - panic(err) - } - return fmt.Sprintf("%x", buf[:]) -} - -// CreatePart creates a new multipart section with the provided -// header. The body of the part should be written to the returned -// Writer. After calling CreatePart, any previous part may no longer -// be written to. -func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) { - if w.lastpart != nil { - if err := w.lastpart.close(); err != nil { - return nil, err - } - } - var b bytes.Buffer - if w.lastpart != nil { - fmt.Fprintf(&b, "\r\n--%s\r\n", w.boundary) - } else { - fmt.Fprintf(&b, "--%s\r\n", w.boundary) - } - - keys := make([]string, 0, len(header)) - for k := range header { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - for _, v := range header[k] { - fmt.Fprintf(&b, "%s: %s\r\n", k, v) - } - } - fmt.Fprintf(&b, "\r\n") - _, err := io.Copy(w.w, &b) - if err != nil { - return nil, err - } - p := &part{ - mw: w, - } - w.lastpart = p - return p, nil -} - -var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") - -func escapeQuotes(s string) string { - return quoteEscaper.Replace(s) -} - -// CreateFormFile is a convenience wrapper around CreatePart. It creates -// a new form-data header with the provided field name and file name. -func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) { - h := make(textproto.MIMEHeader) - h.Set("Content-Disposition", - fmt.Sprintf(`form-data; name="%s"; filename="%s"`, - escapeQuotes(fieldname), escapeQuotes(filename))) - h.Set("Content-Type", "application/octet-stream") - return w.CreatePart(h) -} - -// CreateFormField calls CreatePart with a header using the -// given field name. -func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) { - h := make(textproto.MIMEHeader) - h.Set("Content-Disposition", - fmt.Sprintf(`form-data; name="%s"`, escapeQuotes(fieldname))) - return w.CreatePart(h) -} - -// WriteField calls CreateFormField and then writes the given value. -func (w *Writer) WriteField(fieldname, value string) error { - p, err := w.CreateFormField(fieldname) - if err != nil { - return err - } - _, err = p.Write([]byte(value)) - return err -} - -// Close finishes the multipart message and writes the trailing -// boundary end line to the output. -func (w *Writer) Close() error { - if w.lastpart != nil { - if err := w.lastpart.close(); err != nil { - return err - } - w.lastpart = nil - } - _, err := fmt.Fprintf(w.w, "\r\n--%s--\r\n", w.boundary) - return err -} - -type part struct { - mw *Writer - closed bool - we error // last error that occurred writing -} - -func (p *part) close() error { - p.closed = true - return p.we -} - -func (p *part) Write(d []byte) (n int, err error) { - if p.closed { - return 0, errors.New("multipart: can't write to finished part") - } - n, err = p.mw.w.Write(d) - if err != nil { - p.we = err - } - return -} diff --git a/contrib/go/_std_1.22/src/mime/quotedprintable/writer.go b/contrib/go/_std_1.22/src/mime/quotedprintable/writer.go deleted file mode 100644 index 16ea0bf7d622..000000000000 --- a/contrib/go/_std_1.22/src/mime/quotedprintable/writer.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package quotedprintable - -import "io" - -const lineMaxLen = 76 - -// A Writer is a quoted-printable writer that implements io.WriteCloser. -type Writer struct { - // Binary mode treats the writer's input as pure binary and processes end of - // line bytes as binary data. - Binary bool - - w io.Writer - i int - line [78]byte - cr bool -} - -// NewWriter returns a new Writer that writes to w. -func NewWriter(w io.Writer) *Writer { - return &Writer{w: w} -} - -// Write encodes p using quoted-printable encoding and writes it to the -// underlying io.Writer. It limits line length to 76 characters. The encoded -// bytes are not necessarily flushed until the Writer is closed. -func (w *Writer) Write(p []byte) (n int, err error) { - for i, b := range p { - switch { - // Simple writes are done in batch. - case b >= '!' && b <= '~' && b != '=': - continue - case isWhitespace(b) || !w.Binary && (b == '\n' || b == '\r'): - continue - } - - if i > n { - if err := w.write(p[n:i]); err != nil { - return n, err - } - n = i - } - - if err := w.encode(b); err != nil { - return n, err - } - n++ - } - - if n == len(p) { - return n, nil - } - - if err := w.write(p[n:]); err != nil { - return n, err - } - - return len(p), nil -} - -// Close closes the Writer, flushing any unwritten data to the underlying -// io.Writer, but does not close the underlying io.Writer. -func (w *Writer) Close() error { - if err := w.checkLastByte(); err != nil { - return err - } - - return w.flush() -} - -// write limits text encoded in quoted-printable to 76 characters per line. -func (w *Writer) write(p []byte) error { - for _, b := range p { - if b == '\n' || b == '\r' { - // If the previous byte was \r, the CRLF has already been inserted. - if w.cr && b == '\n' { - w.cr = false - continue - } - - if b == '\r' { - w.cr = true - } - - if err := w.checkLastByte(); err != nil { - return err - } - if err := w.insertCRLF(); err != nil { - return err - } - continue - } - - if w.i == lineMaxLen-1 { - if err := w.insertSoftLineBreak(); err != nil { - return err - } - } - - w.line[w.i] = b - w.i++ - w.cr = false - } - - return nil -} - -func (w *Writer) encode(b byte) error { - if lineMaxLen-1-w.i < 3 { - if err := w.insertSoftLineBreak(); err != nil { - return err - } - } - - w.line[w.i] = '=' - w.line[w.i+1] = upperhex[b>>4] - w.line[w.i+2] = upperhex[b&0x0f] - w.i += 3 - - return nil -} - -const upperhex = "0123456789ABCDEF" - -// checkLastByte encodes the last buffered byte if it is a space or a tab. -func (w *Writer) checkLastByte() error { - if w.i == 0 { - return nil - } - - b := w.line[w.i-1] - if isWhitespace(b) { - w.i-- - if err := w.encode(b); err != nil { - return err - } - } - - return nil -} - -func (w *Writer) insertSoftLineBreak() error { - w.line[w.i] = '=' - w.i++ - - return w.insertCRLF() -} - -func (w *Writer) insertCRLF() error { - w.line[w.i] = '\r' - w.line[w.i+1] = '\n' - w.i += 2 - - return w.flush() -} - -func (w *Writer) flush() error { - if _, err := w.w.Write(w.line[:w.i]); err != nil { - return err - } - - w.i = 0 - return nil -} - -func isWhitespace(b byte) bool { - return b == ' ' || b == '\t' -} diff --git a/contrib/go/_std_1.22/src/mime/type.go b/contrib/go/_std_1.22/src/mime/type.go deleted file mode 100644 index 465ecf0d599c..000000000000 --- a/contrib/go/_std_1.22/src/mime/type.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package mime implements parts of the MIME spec. -package mime - -import ( - "fmt" - "sort" - "strings" - "sync" -) - -var ( - mimeTypes sync.Map // map[string]string; ".Z" => "application/x-compress" - mimeTypesLower sync.Map // map[string]string; ".z" => "application/x-compress" - - // extensions maps from MIME type to list of lowercase file - // extensions: "image/jpeg" => [".jpg", ".jpeg"] - extensionsMu sync.Mutex // Guards stores (but not loads) on extensions. - extensions sync.Map // map[string][]string; slice values are append-only. -) - -func clearSyncMap(m *sync.Map) { - m.Range(func(k, _ any) bool { - m.Delete(k) - return true - }) -} - -// setMimeTypes is used by initMime's non-test path, and by tests. -func setMimeTypes(lowerExt, mixExt map[string]string) { - clearSyncMap(&mimeTypes) - clearSyncMap(&mimeTypesLower) - clearSyncMap(&extensions) - - for k, v := range lowerExt { - mimeTypesLower.Store(k, v) - } - for k, v := range mixExt { - mimeTypes.Store(k, v) - } - - extensionsMu.Lock() - defer extensionsMu.Unlock() - for k, v := range lowerExt { - justType, _, err := ParseMediaType(v) - if err != nil { - panic(err) - } - var exts []string - if ei, ok := extensions.Load(justType); ok { - exts = ei.([]string) - } - extensions.Store(justType, append(exts, k)) - } -} - -var builtinTypesLower = map[string]string{ - ".avif": "image/avif", - ".css": "text/css; charset=utf-8", - ".gif": "image/gif", - ".htm": "text/html; charset=utf-8", - ".html": "text/html; charset=utf-8", - ".jpeg": "image/jpeg", - ".jpg": "image/jpeg", - ".js": "text/javascript; charset=utf-8", - ".json": "application/json", - ".mjs": "text/javascript; charset=utf-8", - ".pdf": "application/pdf", - ".png": "image/png", - ".svg": "image/svg+xml", - ".wasm": "application/wasm", - ".webp": "image/webp", - ".xml": "text/xml; charset=utf-8", -} - -var once sync.Once // guards initMime - -var testInitMime, osInitMime func() - -func initMime() { - if fn := testInitMime; fn != nil { - fn() - } else { - setMimeTypes(builtinTypesLower, builtinTypesLower) - osInitMime() - } -} - -// TypeByExtension returns the MIME type associated with the file extension ext. -// The extension ext should begin with a leading dot, as in ".html". -// When ext has no associated type, TypeByExtension returns "". -// -// Extensions are looked up first case-sensitively, then case-insensitively. -// -// The built-in table is small but on unix it is augmented by the local -// system's MIME-info database or mime.types file(s) if available under one or -// more of these names: -// -// /usr/local/share/mime/globs2 -// /usr/share/mime/globs2 -// /etc/mime.types -// /etc/apache2/mime.types -// /etc/apache/mime.types -// -// On Windows, MIME types are extracted from the registry. -// -// Text types have the charset parameter set to "utf-8" by default. -func TypeByExtension(ext string) string { - once.Do(initMime) - - // Case-sensitive lookup. - if v, ok := mimeTypes.Load(ext); ok { - return v.(string) - } - - // Case-insensitive lookup. - // Optimistically assume a short ASCII extension and be - // allocation-free in that case. - var buf [10]byte - lower := buf[:0] - const utf8RuneSelf = 0x80 // from utf8 package, but not importing it. - for i := 0; i < len(ext); i++ { - c := ext[i] - if c >= utf8RuneSelf { - // Slow path. - si, _ := mimeTypesLower.Load(strings.ToLower(ext)) - s, _ := si.(string) - return s - } - if 'A' <= c && c <= 'Z' { - lower = append(lower, c+('a'-'A')) - } else { - lower = append(lower, c) - } - } - si, _ := mimeTypesLower.Load(string(lower)) - s, _ := si.(string) - return s -} - -// ExtensionsByType returns the extensions known to be associated with the MIME -// type typ. The returned extensions will each begin with a leading dot, as in -// ".html". When typ has no associated extensions, ExtensionsByType returns an -// nil slice. -func ExtensionsByType(typ string) ([]string, error) { - justType, _, err := ParseMediaType(typ) - if err != nil { - return nil, err - } - - once.Do(initMime) - s, ok := extensions.Load(justType) - if !ok { - return nil, nil - } - ret := append([]string(nil), s.([]string)...) - sort.Strings(ret) - return ret, nil -} - -// AddExtensionType sets the MIME type associated with -// the extension ext to typ. The extension should begin with -// a leading dot, as in ".html". -func AddExtensionType(ext, typ string) error { - if !strings.HasPrefix(ext, ".") { - return fmt.Errorf("mime: extension %q missing leading dot", ext) - } - once.Do(initMime) - return setExtensionType(ext, typ) -} - -func setExtensionType(extension, mimeType string) error { - justType, param, err := ParseMediaType(mimeType) - if err != nil { - return err - } - if strings.HasPrefix(mimeType, "text/") && param["charset"] == "" { - param["charset"] = "utf-8" - mimeType = FormatMediaType(mimeType, param) - } - extLower := strings.ToLower(extension) - - mimeTypes.Store(extension, mimeType) - mimeTypesLower.Store(extLower, mimeType) - - extensionsMu.Lock() - defer extensionsMu.Unlock() - var exts []string - if ei, ok := extensions.Load(justType); ok { - exts = ei.([]string) - } - for _, v := range exts { - if v == extLower { - return nil - } - } - extensions.Store(justType, append(exts, extLower)) - return nil -} diff --git a/contrib/go/_std_1.22/src/mime/ya.make b/contrib/go/_std_1.22/src/mime/ya.make deleted file mode 100644 index ef970c93b897..000000000000 --- a/contrib/go/_std_1.22/src/mime/ya.make +++ /dev/null @@ -1,19 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - encodedword.go - grammar.go - mediatype.go - type.go - type_unix.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - encodedword.go - grammar.go - mediatype.go - type.go - type_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_darwin.go b/contrib/go/_std_1.22/src/net/cgo_unix_cgo_darwin.go deleted file mode 100644 index 40d5e426f25c..000000000000 --- a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_darwin.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !netgo && cgo && darwin - -package net - -/* -#include -*/ -import "C" - -import ( - "internal/syscall/unix" - "unsafe" -) - -// This will cause a compile error when the size of -// unix.ResState is too small. -type _ [unsafe.Sizeof(unix.ResState{}) - unsafe.Sizeof(C.struct___res_state{})]byte diff --git a/contrib/go/_std_1.22/src/net/dnsconfig.go b/contrib/go/_std_1.22/src/net/dnsconfig.go deleted file mode 100644 index c86a70be5afd..000000000000 --- a/contrib/go/_std_1.22/src/net/dnsconfig.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "os" - "sync/atomic" - "time" -) - -var ( - defaultNS = []string{"127.0.0.1:53", "[::1]:53"} - getHostname = os.Hostname // variable for testing -) - -type dnsConfig struct { - servers []string // server addresses (in host:port form) to use - search []string // rooted suffixes to append to local name - ndots int // number of dots in name to trigger absolute lookup - timeout time.Duration // wait before giving up on a query, including retries - attempts int // lost packets before giving up on server - rotate bool // round robin among servers - unknownOpt bool // anything unknown was encountered - lookup []string // OpenBSD top-level database "lookup" order - err error // any error that occurs during open of resolv.conf - mtime time.Time // time of resolv.conf modification - soffset uint32 // used by serverOffset - singleRequest bool // use sequential A and AAAA queries instead of parallel queries - useTCP bool // force usage of TCP for DNS resolutions - trustAD bool // add AD flag to queries - noReload bool // do not check for config file updates -} - -// serverOffset returns an offset that can be used to determine -// indices of servers in c.servers when making queries. -// When the rotate option is enabled, this offset increases. -// Otherwise it is always 0. -func (c *dnsConfig) serverOffset() uint32 { - if c.rotate { - return atomic.AddUint32(&c.soffset, 1) - 1 // return 0 to start - } - return 0 -} diff --git a/contrib/go/_std_1.22/src/net/dnsconfig_windows.go b/contrib/go/_std_1.22/src/net/dnsconfig_windows.go deleted file mode 100644 index f3d242366ae2..000000000000 --- a/contrib/go/_std_1.22/src/net/dnsconfig_windows.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "internal/syscall/windows" - "syscall" - "time" -) - -func dnsReadConfig(ignoredFilename string) (conf *dnsConfig) { - conf = &dnsConfig{ - ndots: 1, - timeout: 5 * time.Second, - attempts: 2, - } - defer func() { - if len(conf.servers) == 0 { - conf.servers = defaultNS - } - }() - aas, err := adapterAddresses() - if err != nil { - return - } - // TODO(bradfitz): this just collects all the DNS servers on all - // the interfaces in some random order. It should order it by - // default route, or only use the default route(s) instead. - // In practice, however, it mostly works. - for _, aa := range aas { - for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next { - // Only take interfaces whose OperStatus is IfOperStatusUp(0x01) into DNS configs. - if aa.OperStatus != windows.IfOperStatusUp { - continue - } - sa, err := dns.Address.Sockaddr.Sockaddr() - if err != nil { - continue - } - var ip IP - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - ip = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) - case *syscall.SockaddrInet6: - ip = make(IP, IPv6len) - copy(ip, sa.Addr[:]) - if ip[0] == 0xfe && ip[1] == 0xc0 { - // Ignore these fec0/10 ones. Windows seems to - // populate them as defaults on its misc rando - // interfaces. - continue - } - default: - // Unexpected type. - continue - } - conf.servers = append(conf.servers, JoinHostPort(ip.String(), "53")) - } - } - return conf -} diff --git a/contrib/go/_std_1.22/src/net/fd_windows.go b/contrib/go/_std_1.22/src/net/fd_windows.go deleted file mode 100644 index 45a10cf1eb01..000000000000 --- a/contrib/go/_std_1.22/src/net/fd_windows.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "context" - "internal/poll" - "internal/syscall/windows" - "os" - "runtime" - "syscall" - "unsafe" -) - -const ( - readSyscallName = "wsarecv" - readFromSyscallName = "wsarecvfrom" - readMsgSyscallName = "wsarecvmsg" - writeSyscallName = "wsasend" - writeToSyscallName = "wsasendto" - writeMsgSyscallName = "wsasendmsg" -) - -// canUseConnectEx reports whether we can use the ConnectEx Windows API call -// for the given network type. -func canUseConnectEx(net string) bool { - switch net { - case "tcp", "tcp4", "tcp6": - return true - } - // ConnectEx windows API does not support connectionless sockets. - return false -} - -func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) { - ret := &netFD{ - pfd: poll.FD{ - Sysfd: sysfd, - IsStream: sotype == syscall.SOCK_STREAM, - ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW, - }, - family: family, - sotype: sotype, - net: net, - } - return ret, nil -} - -func (fd *netFD) init() error { - errcall, err := fd.pfd.Init(fd.net, true) - if errcall != "" { - err = wrapSyscallError(errcall, err) - } - return err -} - -// Always returns nil for connected peer address result. -func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (syscall.Sockaddr, error) { - // Do not need to call fd.writeLock here, - // because fd is not yet accessible to user, - // so no concurrent operations are possible. - if err := fd.init(); err != nil { - return nil, err - } - - if ctx.Done() != nil { - // Propagate the Context's deadline and cancellation. - // If the context is already done, or if it has a nonzero deadline, - // ensure that that is applied before the call to ConnectEx begins - // so that we don't return spurious connections. - defer fd.pfd.SetWriteDeadline(noDeadline) - - if ctx.Err() != nil { - fd.pfd.SetWriteDeadline(aLongTimeAgo) - } else { - if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { - fd.pfd.SetWriteDeadline(deadline) - } - - done := make(chan struct{}) - stop := context.AfterFunc(ctx, func() { - // Force the runtime's poller to immediately give - // up waiting for writability. - fd.pfd.SetWriteDeadline(aLongTimeAgo) - close(done) - }) - defer func() { - if !stop() { - // Wait for the call to SetWriteDeadline to complete so that we can - // reset the deadline if everything else succeeded. - <-done - } - }() - } - } - - if !canUseConnectEx(fd.net) { - err := connectFunc(fd.pfd.Sysfd, ra) - return nil, os.NewSyscallError("connect", err) - } - // ConnectEx windows API requires an unconnected, previously bound socket. - if la == nil { - switch ra.(type) { - case *syscall.SockaddrInet4: - la = &syscall.SockaddrInet4{} - case *syscall.SockaddrInet6: - la = &syscall.SockaddrInet6{} - default: - panic("unexpected type in connect") - } - if err := syscall.Bind(fd.pfd.Sysfd, la); err != nil { - return nil, os.NewSyscallError("bind", err) - } - } - - var isloopback bool - switch ra := ra.(type) { - case *syscall.SockaddrInet4: - isloopback = ra.Addr[0] == 127 - case *syscall.SockaddrInet6: - isloopback = ra.Addr == [16]byte(IPv6loopback) - default: - panic("unexpected type in connect") - } - if isloopback { - // This makes ConnectEx() fails faster if the target port on the localhost - // is not reachable, instead of waiting for 2s. - params := windows.TCP_INITIAL_RTO_PARAMETERS{ - Rtt: windows.TCP_INITIAL_RTO_UNSPECIFIED_RTT, // use the default or overridden by the Administrator - MaxSynRetransmissions: 1, // minimum possible value before Windows 10.0.16299 - } - if windows.Support_TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS() { - // In Windows 10.0.16299 TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS makes ConnectEx() fails instantly. - params.MaxSynRetransmissions = windows.TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS - } - var out uint32 - // Don't abort the connection if WSAIoctl fails, as it is only an optimization. - // If it fails reliably, we expect TestDialClosedPortFailFast to detect it. - _ = fd.pfd.WSAIoctl(windows.SIO_TCP_INITIAL_RTO, (*byte)(unsafe.Pointer(¶ms)), uint32(unsafe.Sizeof(params)), nil, 0, &out, nil, 0) - } - - // Call ConnectEx API. - if err := fd.pfd.ConnectEx(ra); err != nil { - select { - case <-ctx.Done(): - return nil, mapErr(ctx.Err()) - default: - if _, ok := err.(syscall.Errno); ok { - err = os.NewSyscallError("connectex", err) - } - return nil, err - } - } - // Refresh socket properties. - return nil, os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.pfd.Sysfd)), int32(unsafe.Sizeof(fd.pfd.Sysfd)))) -} - -func (c *conn) writeBuffers(v *Buffers) (int64, error) { - if !c.ok() { - return 0, syscall.EINVAL - } - n, err := c.fd.writeBuffers(v) - if err != nil { - return n, &OpError{Op: "wsasend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} - } - return n, nil -} - -func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) { - n, err := fd.pfd.Writev((*[][]byte)(buf)) - runtime.KeepAlive(fd) - return n, wrapSyscallError("wsasend", err) -} - -func (fd *netFD) accept() (*netFD, error) { - s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) { - return sysSocket(fd.family, fd.sotype, 0) - }) - - if err != nil { - if errcall != "" { - err = wrapSyscallError(errcall, err) - } - return nil, err - } - - // Associate our new socket with IOCP. - netfd, err := newFD(s, fd.family, fd.sotype, fd.net) - if err != nil { - poll.CloseFunc(s) - return nil, err - } - if err := netfd.init(); err != nil { - fd.Close() - return nil, err - } - - // Get local and peer addr out of AcceptEx buffer. - var lrsa, rrsa *syscall.RawSockaddrAny - var llen, rlen int32 - syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])), - 0, rsan, rsan, &lrsa, &llen, &rrsa, &rlen) - lsa, _ := lrsa.Sockaddr() - rsa, _ := rrsa.Sockaddr() - - netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) - return netfd, nil -} - -// Unimplemented functions. - -func (fd *netFD) dup() (*os.File, error) { - // TODO: Implement this - return nil, syscall.EWINDOWS -} diff --git a/contrib/go/_std_1.22/src/net/file_plan9.go b/contrib/go/_std_1.22/src/net/file_plan9.go deleted file mode 100644 index 64aabf93ee54..000000000000 --- a/contrib/go/_std_1.22/src/net/file_plan9.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "errors" - "io" - "os" - "syscall" -) - -func (fd *netFD) status(ln int) (string, error) { - if !fd.ok() { - return "", syscall.EINVAL - } - - status, err := os.Open(fd.dir + "/status") - if err != nil { - return "", err - } - defer status.Close() - buf := make([]byte, ln) - n, err := io.ReadFull(status, buf[:]) - if err != nil { - return "", err - } - return string(buf[:n]), nil -} - -func newFileFD(f *os.File) (net *netFD, err error) { - var ctl *os.File - close := func(fd int) { - if err != nil { - syscall.Close(fd) - } - } - - path, err := syscall.Fd2path(int(f.Fd())) - if err != nil { - return nil, os.NewSyscallError("fd2path", err) - } - comp := splitAtBytes(path, "/") - n := len(comp) - if n < 3 || comp[0][0:3] != "net" { - return nil, syscall.EPLAN9 - } - - name := comp[2] - switch file := comp[n-1]; file { - case "ctl", "clone": - fd, err := syscall.Dup(int(f.Fd()), -1) - if err != nil { - return nil, os.NewSyscallError("dup", err) - } - defer close(fd) - - dir := netdir + "/" + comp[n-2] - ctl = os.NewFile(uintptr(fd), dir+"/"+file) - ctl.Seek(0, io.SeekStart) - var buf [16]byte - n, err := ctl.Read(buf[:]) - if err != nil { - return nil, err - } - name = string(buf[:n]) - default: - if len(comp) < 4 { - return nil, errors.New("could not find control file for connection") - } - dir := netdir + "/" + comp[1] + "/" + name - ctl, err = os.OpenFile(dir+"/ctl", os.O_RDWR, 0) - if err != nil { - return nil, err - } - defer close(int(ctl.Fd())) - } - dir := netdir + "/" + comp[1] + "/" + name - laddr, err := readPlan9Addr(comp[1], dir+"/local") - if err != nil { - return nil, err - } - return newFD(comp[1], name, nil, ctl, nil, laddr, nil) -} - -func fileConn(f *os.File) (Conn, error) { - fd, err := newFileFD(f) - if err != nil { - return nil, err - } - if !fd.ok() { - return nil, syscall.EINVAL - } - - fd.data, err = os.OpenFile(fd.dir+"/data", os.O_RDWR, 0) - if err != nil { - return nil, err - } - - switch fd.laddr.(type) { - case *TCPAddr: - return newTCPConn(fd, defaultTCPKeepAlive, testHookSetKeepAlive), nil - case *UDPAddr: - return newUDPConn(fd), nil - } - return nil, syscall.EPLAN9 -} - -func fileListener(f *os.File) (Listener, error) { - fd, err := newFileFD(f) - if err != nil { - return nil, err - } - switch fd.laddr.(type) { - case *TCPAddr: - default: - return nil, syscall.EPLAN9 - } - - // check that file corresponds to a listener - s, err := fd.status(len("Listen")) - if err != nil { - return nil, err - } - if s != "Listen" { - return nil, errors.New("file does not represent a listener") - } - - return &TCPListener{fd: fd}, nil -} - -func filePacketConn(f *os.File) (PacketConn, error) { - return nil, syscall.EPLAN9 -} diff --git a/contrib/go/_std_1.22/src/net/file_unix.go b/contrib/go/_std_1.22/src/net/file_unix.go deleted file mode 100644 index 8b9fc38916f7..000000000000 --- a/contrib/go/_std_1.22/src/net/file_unix.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix - -package net - -import ( - "internal/poll" - "os" - "syscall" -) - -func dupSocket(f *os.File) (int, error) { - s, call, err := poll.DupCloseOnExec(int(f.Fd())) - if err != nil { - if call != "" { - err = os.NewSyscallError(call, err) - } - return -1, err - } - if err := syscall.SetNonblock(s, true); err != nil { - poll.CloseFunc(s) - return -1, os.NewSyscallError("setnonblock", err) - } - return s, nil -} - -func newFileFD(f *os.File) (*netFD, error) { - s, err := dupSocket(f) - if err != nil { - return nil, err - } - family := syscall.AF_UNSPEC - sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE) - if err != nil { - poll.CloseFunc(s) - return nil, os.NewSyscallError("getsockopt", err) - } - lsa, _ := syscall.Getsockname(s) - rsa, _ := syscall.Getpeername(s) - switch lsa.(type) { - case *syscall.SockaddrInet4: - family = syscall.AF_INET - case *syscall.SockaddrInet6: - family = syscall.AF_INET6 - case *syscall.SockaddrUnix: - family = syscall.AF_UNIX - default: - poll.CloseFunc(s) - return nil, syscall.EPROTONOSUPPORT - } - fd, err := newFD(s, family, sotype, "") - if err != nil { - poll.CloseFunc(s) - return nil, err - } - laddr := fd.addrFunc()(lsa) - raddr := fd.addrFunc()(rsa) - fd.net = laddr.Network() - if err := fd.init(); err != nil { - fd.Close() - return nil, err - } - fd.setAddr(laddr, raddr) - return fd, nil -} - -func fileConn(f *os.File) (Conn, error) { - fd, err := newFileFD(f) - if err != nil { - return nil, err - } - switch fd.laddr.(type) { - case *TCPAddr: - return newTCPConn(fd, defaultTCPKeepAlive, testHookSetKeepAlive), nil - case *UDPAddr: - return newUDPConn(fd), nil - case *IPAddr: - return newIPConn(fd), nil - case *UnixAddr: - return newUnixConn(fd), nil - } - fd.Close() - return nil, syscall.EINVAL -} - -func fileListener(f *os.File) (Listener, error) { - fd, err := newFileFD(f) - if err != nil { - return nil, err - } - switch laddr := fd.laddr.(type) { - case *TCPAddr: - return &TCPListener{fd: fd}, nil - case *UnixAddr: - return &UnixListener{fd: fd, path: laddr.Name, unlink: false}, nil - } - fd.Close() - return nil, syscall.EINVAL -} - -func filePacketConn(f *os.File) (PacketConn, error) { - fd, err := newFileFD(f) - if err != nil { - return nil, err - } - switch fd.laddr.(type) { - case *UDPAddr: - return newUDPConn(fd), nil - case *IPAddr: - return newIPConn(fd), nil - case *UnixAddr: - return newUnixConn(fd), nil - } - fd.Close() - return nil, syscall.EINVAL -} diff --git a/contrib/go/_std_1.22/src/net/http/clone.go b/contrib/go/_std_1.22/src/net/http/clone.go deleted file mode 100644 index 3a3375bff716..000000000000 --- a/contrib/go/_std_1.22/src/net/http/clone.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package http - -import ( - "mime/multipart" - "net/textproto" - "net/url" -) - -func cloneURLValues(v url.Values) url.Values { - if v == nil { - return nil - } - // http.Header and url.Values have the same representation, so temporarily - // treat it like http.Header, which does have a clone: - return url.Values(Header(v).Clone()) -} - -func cloneURL(u *url.URL) *url.URL { - if u == nil { - return nil - } - u2 := new(url.URL) - *u2 = *u - if u.User != nil { - u2.User = new(url.Userinfo) - *u2.User = *u.User - } - return u2 -} - -func cloneMultipartForm(f *multipart.Form) *multipart.Form { - if f == nil { - return nil - } - f2 := &multipart.Form{ - Value: (map[string][]string)(Header(f.Value).Clone()), - } - if f.File != nil { - m := make(map[string][]*multipart.FileHeader) - for k, vv := range f.File { - vv2 := make([]*multipart.FileHeader, len(vv)) - for i, v := range vv { - vv2[i] = cloneMultipartFileHeader(v) - } - m[k] = vv2 - } - f2.File = m - } - return f2 -} - -func cloneMultipartFileHeader(fh *multipart.FileHeader) *multipart.FileHeader { - if fh == nil { - return nil - } - fh2 := new(multipart.FileHeader) - *fh2 = *fh - fh2.Header = textproto.MIMEHeader(Header(fh.Header).Clone()) - return fh2 -} - -// cloneOrMakeHeader invokes Header.Clone but if the -// result is nil, it'll instead make and return a non-nil Header. -func cloneOrMakeHeader(hdr Header) Header { - clone := hdr.Clone() - if clone == nil { - clone = make(Header) - } - return clone -} diff --git a/contrib/go/_std_1.22/src/net/http/cookie.go b/contrib/go/_std_1.22/src/net/http/cookie.go deleted file mode 100644 index c22897f3f99e..000000000000 --- a/contrib/go/_std_1.22/src/net/http/cookie.go +++ /dev/null @@ -1,468 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package http - -import ( - "errors" - "fmt" - "log" - "net" - "net/http/internal/ascii" - "net/textproto" - "strconv" - "strings" - "time" -) - -// A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an -// HTTP response or the Cookie header of an HTTP request. -// -// See https://tools.ietf.org/html/rfc6265 for details. -type Cookie struct { - Name string - Value string - - Path string // optional - Domain string // optional - Expires time.Time // optional - RawExpires string // for reading cookies only - - // MaxAge=0 means no 'Max-Age' attribute specified. - // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' - // MaxAge>0 means Max-Age attribute present and given in seconds - MaxAge int - Secure bool - HttpOnly bool - SameSite SameSite - Raw string - Unparsed []string // Raw text of unparsed attribute-value pairs -} - -// SameSite allows a server to define a cookie attribute making it impossible for -// the browser to send this cookie along with cross-site requests. The main -// goal is to mitigate the risk of cross-origin information leakage, and provide -// some protection against cross-site request forgery attacks. -// -// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details. -type SameSite int - -const ( - SameSiteDefaultMode SameSite = iota + 1 - SameSiteLaxMode - SameSiteStrictMode - SameSiteNoneMode -) - -// readSetCookies parses all "Set-Cookie" values from -// the header h and returns the successfully parsed Cookies. -func readSetCookies(h Header) []*Cookie { - cookieCount := len(h["Set-Cookie"]) - if cookieCount == 0 { - return []*Cookie{} - } - cookies := make([]*Cookie, 0, cookieCount) - for _, line := range h["Set-Cookie"] { - parts := strings.Split(textproto.TrimString(line), ";") - if len(parts) == 1 && parts[0] == "" { - continue - } - parts[0] = textproto.TrimString(parts[0]) - name, value, ok := strings.Cut(parts[0], "=") - if !ok { - continue - } - name = textproto.TrimString(name) - if !isCookieNameValid(name) { - continue - } - value, ok = parseCookieValue(value, true) - if !ok { - continue - } - c := &Cookie{ - Name: name, - Value: value, - Raw: line, - } - for i := 1; i < len(parts); i++ { - parts[i] = textproto.TrimString(parts[i]) - if len(parts[i]) == 0 { - continue - } - - attr, val, _ := strings.Cut(parts[i], "=") - lowerAttr, isASCII := ascii.ToLower(attr) - if !isASCII { - continue - } - val, ok = parseCookieValue(val, false) - if !ok { - c.Unparsed = append(c.Unparsed, parts[i]) - continue - } - - switch lowerAttr { - case "samesite": - lowerVal, ascii := ascii.ToLower(val) - if !ascii { - c.SameSite = SameSiteDefaultMode - continue - } - switch lowerVal { - case "lax": - c.SameSite = SameSiteLaxMode - case "strict": - c.SameSite = SameSiteStrictMode - case "none": - c.SameSite = SameSiteNoneMode - default: - c.SameSite = SameSiteDefaultMode - } - continue - case "secure": - c.Secure = true - continue - case "httponly": - c.HttpOnly = true - continue - case "domain": - c.Domain = val - continue - case "max-age": - secs, err := strconv.Atoi(val) - if err != nil || secs != 0 && val[0] == '0' { - break - } - if secs <= 0 { - secs = -1 - } - c.MaxAge = secs - continue - case "expires": - c.RawExpires = val - exptime, err := time.Parse(time.RFC1123, val) - if err != nil { - exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val) - if err != nil { - c.Expires = time.Time{} - break - } - } - c.Expires = exptime.UTC() - continue - case "path": - c.Path = val - continue - } - c.Unparsed = append(c.Unparsed, parts[i]) - } - cookies = append(cookies, c) - } - return cookies -} - -// SetCookie adds a Set-Cookie header to the provided [ResponseWriter]'s headers. -// The provided cookie must have a valid Name. Invalid cookies may be -// silently dropped. -func SetCookie(w ResponseWriter, cookie *Cookie) { - if v := cookie.String(); v != "" { - w.Header().Add("Set-Cookie", v) - } -} - -// String returns the serialization of the cookie for use in a [Cookie] -// header (if only Name and Value are set) or a Set-Cookie response -// header (if other fields are set). -// If c is nil or c.Name is invalid, the empty string is returned. -func (c *Cookie) String() string { - if c == nil || !isCookieNameValid(c.Name) { - return "" - } - // extraCookieLength derived from typical length of cookie attributes - // see RFC 6265 Sec 4.1. - const extraCookieLength = 110 - var b strings.Builder - b.Grow(len(c.Name) + len(c.Value) + len(c.Domain) + len(c.Path) + extraCookieLength) - b.WriteString(c.Name) - b.WriteRune('=') - b.WriteString(sanitizeCookieValue(c.Value)) - - if len(c.Path) > 0 { - b.WriteString("; Path=") - b.WriteString(sanitizeCookiePath(c.Path)) - } - if len(c.Domain) > 0 { - if validCookieDomain(c.Domain) { - // A c.Domain containing illegal characters is not - // sanitized but simply dropped which turns the cookie - // into a host-only cookie. A leading dot is okay - // but won't be sent. - d := c.Domain - if d[0] == '.' { - d = d[1:] - } - b.WriteString("; Domain=") - b.WriteString(d) - } else { - log.Printf("net/http: invalid Cookie.Domain %q; dropping domain attribute", c.Domain) - } - } - var buf [len(TimeFormat)]byte - if validCookieExpires(c.Expires) { - b.WriteString("; Expires=") - b.Write(c.Expires.UTC().AppendFormat(buf[:0], TimeFormat)) - } - if c.MaxAge > 0 { - b.WriteString("; Max-Age=") - b.Write(strconv.AppendInt(buf[:0], int64(c.MaxAge), 10)) - } else if c.MaxAge < 0 { - b.WriteString("; Max-Age=0") - } - if c.HttpOnly { - b.WriteString("; HttpOnly") - } - if c.Secure { - b.WriteString("; Secure") - } - switch c.SameSite { - case SameSiteDefaultMode: - // Skip, default mode is obtained by not emitting the attribute. - case SameSiteNoneMode: - b.WriteString("; SameSite=None") - case SameSiteLaxMode: - b.WriteString("; SameSite=Lax") - case SameSiteStrictMode: - b.WriteString("; SameSite=Strict") - } - return b.String() -} - -// Valid reports whether the cookie is valid. -func (c *Cookie) Valid() error { - if c == nil { - return errors.New("http: nil Cookie") - } - if !isCookieNameValid(c.Name) { - return errors.New("http: invalid Cookie.Name") - } - if !c.Expires.IsZero() && !validCookieExpires(c.Expires) { - return errors.New("http: invalid Cookie.Expires") - } - for i := 0; i < len(c.Value); i++ { - if !validCookieValueByte(c.Value[i]) { - return fmt.Errorf("http: invalid byte %q in Cookie.Value", c.Value[i]) - } - } - if len(c.Path) > 0 { - for i := 0; i < len(c.Path); i++ { - if !validCookiePathByte(c.Path[i]) { - return fmt.Errorf("http: invalid byte %q in Cookie.Path", c.Path[i]) - } - } - } - if len(c.Domain) > 0 { - if !validCookieDomain(c.Domain) { - return errors.New("http: invalid Cookie.Domain") - } - } - return nil -} - -// readCookies parses all "Cookie" values from the header h and -// returns the successfully parsed Cookies. -// -// if filter isn't empty, only cookies of that name are returned. -func readCookies(h Header, filter string) []*Cookie { - lines := h["Cookie"] - if len(lines) == 0 { - return []*Cookie{} - } - - cookies := make([]*Cookie, 0, len(lines)+strings.Count(lines[0], ";")) - for _, line := range lines { - line = textproto.TrimString(line) - - var part string - for len(line) > 0 { // continue since we have rest - part, line, _ = strings.Cut(line, ";") - part = textproto.TrimString(part) - if part == "" { - continue - } - name, val, _ := strings.Cut(part, "=") - name = textproto.TrimString(name) - if !isCookieNameValid(name) { - continue - } - if filter != "" && filter != name { - continue - } - val, ok := parseCookieValue(val, true) - if !ok { - continue - } - cookies = append(cookies, &Cookie{Name: name, Value: val}) - } - } - return cookies -} - -// validCookieDomain reports whether v is a valid cookie domain-value. -func validCookieDomain(v string) bool { - if isCookieDomainName(v) { - return true - } - if net.ParseIP(v) != nil && !strings.Contains(v, ":") { - return true - } - return false -} - -// validCookieExpires reports whether v is a valid cookie expires-value. -func validCookieExpires(t time.Time) bool { - // IETF RFC 6265 Section 5.1.1.5, the year must not be less than 1601 - return t.Year() >= 1601 -} - -// isCookieDomainName reports whether s is a valid domain name or a valid -// domain name with a leading dot '.'. It is almost a direct copy of -// package net's isDomainName. -func isCookieDomainName(s string) bool { - if len(s) == 0 { - return false - } - if len(s) > 255 { - return false - } - - if s[0] == '.' { - // A cookie a domain attribute may start with a leading dot. - s = s[1:] - } - last := byte('.') - ok := false // Ok once we've seen a letter. - partlen := 0 - for i := 0; i < len(s); i++ { - c := s[i] - switch { - default: - return false - case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': - // No '_' allowed here (in contrast to package net). - ok = true - partlen++ - case '0' <= c && c <= '9': - // fine - partlen++ - case c == '-': - // Byte before dash cannot be dot. - if last == '.' { - return false - } - partlen++ - case c == '.': - // Byte before dot cannot be dot, dash. - if last == '.' || last == '-' { - return false - } - if partlen > 63 || partlen == 0 { - return false - } - partlen = 0 - } - last = c - } - if last == '-' || partlen > 63 { - return false - } - - return ok -} - -var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-") - -func sanitizeCookieName(n string) string { - return cookieNameSanitizer.Replace(n) -} - -// sanitizeCookieValue produces a suitable cookie-value from v. -// https://tools.ietf.org/html/rfc6265#section-4.1.1 -// -// cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) -// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E -// ; US-ASCII characters excluding CTLs, -// ; whitespace DQUOTE, comma, semicolon, -// ; and backslash -// -// We loosen this as spaces and commas are common in cookie values -// but we produce a quoted cookie-value if and only if v contains -// commas or spaces. -// See https://golang.org/issue/7243 for the discussion. -func sanitizeCookieValue(v string) string { - v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v) - if len(v) == 0 { - return v - } - if strings.ContainsAny(v, " ,") { - return `"` + v + `"` - } - return v -} - -func validCookieValueByte(b byte) bool { - return 0x20 <= b && b < 0x7f && b != '"' && b != ';' && b != '\\' -} - -// path-av = "Path=" path-value -// path-value = -func sanitizeCookiePath(v string) string { - return sanitizeOrWarn("Cookie.Path", validCookiePathByte, v) -} - -func validCookiePathByte(b byte) bool { - return 0x20 <= b && b < 0x7f && b != ';' -} - -func sanitizeOrWarn(fieldName string, valid func(byte) bool, v string) string { - ok := true - for i := 0; i < len(v); i++ { - if valid(v[i]) { - continue - } - log.Printf("net/http: invalid byte %q in %s; dropping invalid bytes", v[i], fieldName) - ok = false - break - } - if ok { - return v - } - buf := make([]byte, 0, len(v)) - for i := 0; i < len(v); i++ { - if b := v[i]; valid(b) { - buf = append(buf, b) - } - } - return string(buf) -} - -func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) { - // Strip the quotes, if present. - if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' { - raw = raw[1 : len(raw)-1] - } - for i := 0; i < len(raw); i++ { - if !validCookieValueByte(raw[i]) { - return "", false - } - } - return raw, true -} - -func isCookieNameValid(raw string) bool { - if raw == "" { - return false - } - return strings.IndexFunc(raw, isNotToken) < 0 -} diff --git a/contrib/go/_std_1.22/src/net/http/httptest/server.go b/contrib/go/_std_1.22/src/net/http/httptest/server.go deleted file mode 100644 index 5095b438ec94..000000000000 --- a/contrib/go/_std_1.22/src/net/http/httptest/server.go +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Implementation of Server - -package httptest - -import ( - "crypto/tls" - "crypto/x509" - "flag" - "fmt" - "log" - "net" - "net/http" - "net/http/internal/testcert" - "os" - "strings" - "sync" - "time" -) - -// A Server is an HTTP server listening on a system-chosen port on the -// local loopback interface, for use in end-to-end HTTP tests. -type Server struct { - URL string // base URL of form http://ipaddr:port with no trailing slash - Listener net.Listener - - // EnableHTTP2 controls whether HTTP/2 is enabled - // on the server. It must be set between calling - // NewUnstartedServer and calling Server.StartTLS. - EnableHTTP2 bool - - // TLS is the optional TLS configuration, populated with a new config - // after TLS is started. If set on an unstarted server before StartTLS - // is called, existing fields are copied into the new config. - TLS *tls.Config - - // Config may be changed after calling NewUnstartedServer and - // before Start or StartTLS. - Config *http.Server - - // certificate is a parsed version of the TLS config certificate, if present. - certificate *x509.Certificate - - // wg counts the number of outstanding HTTP requests on this server. - // Close blocks until all requests are finished. - wg sync.WaitGroup - - mu sync.Mutex // guards closed and conns - closed bool - conns map[net.Conn]http.ConnState // except terminal states - - // client is configured for use with the server. - // Its transport is automatically closed when Close is called. - client *http.Client -} - -func newLocalListener() net.Listener { - if serveFlag != "" { - l, err := net.Listen("tcp", serveFlag) - if err != nil { - panic(fmt.Sprintf("httptest: failed to listen on %v: %v", serveFlag, err)) - } - return l - } - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - if l, err = net.Listen("tcp6", "[::1]:0"); err != nil { - panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err)) - } - } - return l -} - -// When debugging a particular http server-based test, -// this flag lets you run -// -// go test -run='^BrokenTest$' -httptest.serve=127.0.0.1:8000 -// -// to start the broken server so you can interact with it manually. -// We only register this flag if it looks like the caller knows about it -// and is trying to use it as we don't want to pollute flags and this -// isn't really part of our API. Don't depend on this. -var serveFlag string - -func init() { - if strSliceContainsPrefix(os.Args, "-httptest.serve=") || strSliceContainsPrefix(os.Args, "--httptest.serve=") { - flag.StringVar(&serveFlag, "httptest.serve", "", "if non-empty, httptest.NewServer serves on this address and blocks.") - } -} - -func strSliceContainsPrefix(v []string, pre string) bool { - for _, s := range v { - if strings.HasPrefix(s, pre) { - return true - } - } - return false -} - -// NewServer starts and returns a new [Server]. -// The caller should call Close when finished, to shut it down. -func NewServer(handler http.Handler) *Server { - ts := NewUnstartedServer(handler) - ts.Start() - return ts -} - -// NewUnstartedServer returns a new [Server] but doesn't start it. -// -// After changing its configuration, the caller should call Start or -// StartTLS. -// -// The caller should call Close when finished, to shut it down. -func NewUnstartedServer(handler http.Handler) *Server { - return &Server{ - Listener: newLocalListener(), - Config: &http.Server{Handler: handler}, - } -} - -// Start starts a server from NewUnstartedServer. -func (s *Server) Start() { - if s.URL != "" { - panic("Server already started") - } - if s.client == nil { - s.client = &http.Client{Transport: &http.Transport{}} - } - s.URL = "http://" + s.Listener.Addr().String() - s.wrap() - s.goServe() - if serveFlag != "" { - fmt.Fprintln(os.Stderr, "httptest: serving on", s.URL) - select {} - } -} - -// StartTLS starts TLS on a server from NewUnstartedServer. -func (s *Server) StartTLS() { - if s.URL != "" { - panic("Server already started") - } - if s.client == nil { - s.client = &http.Client{} - } - cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey) - if err != nil { - panic(fmt.Sprintf("httptest: NewTLSServer: %v", err)) - } - - existingConfig := s.TLS - if existingConfig != nil { - s.TLS = existingConfig.Clone() - } else { - s.TLS = new(tls.Config) - } - if s.TLS.NextProtos == nil { - nextProtos := []string{"http/1.1"} - if s.EnableHTTP2 { - nextProtos = []string{"h2"} - } - s.TLS.NextProtos = nextProtos - } - if len(s.TLS.Certificates) == 0 { - s.TLS.Certificates = []tls.Certificate{cert} - } - s.certificate, err = x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0]) - if err != nil { - panic(fmt.Sprintf("httptest: NewTLSServer: %v", err)) - } - certpool := x509.NewCertPool() - certpool.AddCert(s.certificate) - s.client.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: certpool, - }, - ForceAttemptHTTP2: s.EnableHTTP2, - } - s.Listener = tls.NewListener(s.Listener, s.TLS) - s.URL = "https://" + s.Listener.Addr().String() - s.wrap() - s.goServe() -} - -// NewTLSServer starts and returns a new [Server] using TLS. -// The caller should call Close when finished, to shut it down. -func NewTLSServer(handler http.Handler) *Server { - ts := NewUnstartedServer(handler) - ts.StartTLS() - return ts -} - -type closeIdleTransport interface { - CloseIdleConnections() -} - -// Close shuts down the server and blocks until all outstanding -// requests on this server have completed. -func (s *Server) Close() { - s.mu.Lock() - if !s.closed { - s.closed = true - s.Listener.Close() - s.Config.SetKeepAlivesEnabled(false) - for c, st := range s.conns { - // Force-close any idle connections (those between - // requests) and new connections (those which connected - // but never sent a request). StateNew connections are - // super rare and have only been seen (in - // previously-flaky tests) in the case of - // socket-late-binding races from the http Client - // dialing this server and then getting an idle - // connection before the dial completed. There is thus - // a connected connection in StateNew with no - // associated Request. We only close StateIdle and - // StateNew because they're not doing anything. It's - // possible StateNew is about to do something in a few - // milliseconds, but a previous CL to check again in a - // few milliseconds wasn't liked (early versions of - // https://golang.org/cl/15151) so now we just - // forcefully close StateNew. The docs for Server.Close say - // we wait for "outstanding requests", so we don't close things - // in StateActive. - if st == http.StateIdle || st == http.StateNew { - s.closeConn(c) - } - } - // If this server doesn't shut down in 5 seconds, tell the user why. - t := time.AfterFunc(5*time.Second, s.logCloseHangDebugInfo) - defer t.Stop() - } - s.mu.Unlock() - - // Not part of httptest.Server's correctness, but assume most - // users of httptest.Server will be using the standard - // transport, so help them out and close any idle connections for them. - if t, ok := http.DefaultTransport.(closeIdleTransport); ok { - t.CloseIdleConnections() - } - - // Also close the client idle connections. - if s.client != nil { - if t, ok := s.client.Transport.(closeIdleTransport); ok { - t.CloseIdleConnections() - } - } - - s.wg.Wait() -} - -func (s *Server) logCloseHangDebugInfo() { - s.mu.Lock() - defer s.mu.Unlock() - var buf strings.Builder - buf.WriteString("httptest.Server blocked in Close after 5 seconds, waiting for connections:\n") - for c, st := range s.conns { - fmt.Fprintf(&buf, " %T %p %v in state %v\n", c, c, c.RemoteAddr(), st) - } - log.Print(buf.String()) -} - -// CloseClientConnections closes any open HTTP connections to the test Server. -func (s *Server) CloseClientConnections() { - s.mu.Lock() - nconn := len(s.conns) - ch := make(chan struct{}, nconn) - for c := range s.conns { - go s.closeConnChan(c, ch) - } - s.mu.Unlock() - - // Wait for outstanding closes to finish. - // - // Out of paranoia for making a late change in Go 1.6, we - // bound how long this can wait, since golang.org/issue/14291 - // isn't fully understood yet. At least this should only be used - // in tests. - timer := time.NewTimer(5 * time.Second) - defer timer.Stop() - for i := 0; i < nconn; i++ { - select { - case <-ch: - case <-timer.C: - // Too slow. Give up. - return - } - } -} - -// Certificate returns the certificate used by the server, or nil if -// the server doesn't use TLS. -func (s *Server) Certificate() *x509.Certificate { - return s.certificate -} - -// Client returns an HTTP client configured for making requests to the server. -// It is configured to trust the server's TLS test certificate and will -// close its idle connections on [Server.Close]. -func (s *Server) Client() *http.Client { - return s.client -} - -func (s *Server) goServe() { - s.wg.Add(1) - go func() { - defer s.wg.Done() - s.Config.Serve(s.Listener) - }() -} - -// wrap installs the connection state-tracking hook to know which -// connections are idle. -func (s *Server) wrap() { - oldHook := s.Config.ConnState - s.Config.ConnState = func(c net.Conn, cs http.ConnState) { - s.mu.Lock() - defer s.mu.Unlock() - - switch cs { - case http.StateNew: - if _, exists := s.conns[c]; exists { - panic("invalid state transition") - } - if s.conns == nil { - s.conns = make(map[net.Conn]http.ConnState) - } - // Add c to the set of tracked conns and increment it to the - // waitgroup. - s.wg.Add(1) - s.conns[c] = cs - if s.closed { - // Probably just a socket-late-binding dial from - // the default transport that lost the race (and - // thus this connection is now idle and will - // never be used). - s.closeConn(c) - } - case http.StateActive: - if oldState, ok := s.conns[c]; ok { - if oldState != http.StateNew && oldState != http.StateIdle { - panic("invalid state transition") - } - s.conns[c] = cs - } - case http.StateIdle: - if oldState, ok := s.conns[c]; ok { - if oldState != http.StateActive { - panic("invalid state transition") - } - s.conns[c] = cs - } - if s.closed { - s.closeConn(c) - } - case http.StateHijacked, http.StateClosed: - // Remove c from the set of tracked conns and decrement it from the - // waitgroup, unless it was previously removed. - if _, ok := s.conns[c]; ok { - delete(s.conns, c) - // Keep Close from returning until the user's ConnState hook - // (if any) finishes. - defer s.wg.Done() - } - } - if oldHook != nil { - oldHook(c, cs) - } - } -} - -// closeConn closes c. -// s.mu must be held. -func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) } - -// closeConnChan is like closeConn, but takes an optional channel to receive a value -// when the goroutine closing c is done. -func (s *Server) closeConnChan(c net.Conn, done chan<- struct{}) { - c.Close() - if done != nil { - done <- struct{}{} - } -} diff --git a/contrib/go/_std_1.22/src/net/http/internal/testcert/testcert.go b/contrib/go/_std_1.22/src/net/http/internal/testcert/testcert.go deleted file mode 100644 index d510e791d617..000000000000 --- a/contrib/go/_std_1.22/src/net/http/internal/testcert/testcert.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package testcert contains a test-only localhost certificate. -package testcert - -import "strings" - -// LocalhostCert is a PEM-encoded TLS cert with SAN IPs -// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT. -// generated from src/crypto/tls: -// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h -var LocalhostCert = []byte(`-----BEGIN CERTIFICATE----- -MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS -MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw -MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r -bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U -aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P -YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk -POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu -h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE -AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv -bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI -5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv -cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2 -+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B -grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK -5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/ -WkBKOclmOV2xlTVuPw== ------END CERTIFICATE-----`) - -// LocalhostKey is the private key for LocalhostCert. -var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi -4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS -gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW -URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX -AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy -VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK -x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk -lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL -dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89 -EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq -XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki -6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O -3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s -uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ -Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ -w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo -+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP -OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA -brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv -m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y -LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN -/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN -s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ -Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0 -xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/ -ZboOWVe3icTy64BT3OQhmg== ------END RSA TESTING KEY-----`)) - -func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } diff --git a/contrib/go/_std_1.22/src/net/http/pprof/pprof.go b/contrib/go/_std_1.22/src/net/http/pprof/pprof.go deleted file mode 100644 index bc48f1183413..000000000000 --- a/contrib/go/_std_1.22/src/net/http/pprof/pprof.go +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package pprof serves via its HTTP server runtime profiling data -// in the format expected by the pprof visualization tool. -// -// The package is typically only imported for the side effect of -// registering its HTTP handlers. -// The handled paths all begin with /debug/pprof/. -// -// To use pprof, link this package into your program: -// -// import _ "net/http/pprof" -// -// If your application is not already running an http server, you -// need to start one. Add "net/http" and "log" to your imports and -// the following code to your main function: -// -// go func() { -// log.Println(http.ListenAndServe("localhost:6060", nil)) -// }() -// -// By default, all the profiles listed in [runtime/pprof.Profile] are -// available (via [Handler]), in addition to the [Cmdline], [Profile], [Symbol], -// and [Trace] profiles defined in this package. -// If you are not using DefaultServeMux, you will have to register handlers -// with the mux you are using. -// -// # Parameters -// -// Parameters can be passed via GET query params: -// -// - debug=N (all profiles): response format: N = 0: binary (default), N > 0: plaintext -// - gc=N (heap profile): N > 0: run a garbage collection cycle before profiling -// - seconds=N (allocs, block, goroutine, heap, mutex, threadcreate profiles): return a delta profile -// - seconds=N (cpu (profile), trace profiles): profile for the given duration -// -// # Usage examples -// -// Use the pprof tool to look at the heap profile: -// -// go tool pprof http://localhost:6060/debug/pprof/heap -// -// Or to look at a 30-second CPU profile: -// -// go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30 -// -// Or to look at the goroutine blocking profile, after calling -// [runtime.SetBlockProfileRate] in your program: -// -// go tool pprof http://localhost:6060/debug/pprof/block -// -// Or to look at the holders of contended mutexes, after calling -// [runtime.SetMutexProfileFraction] in your program: -// -// go tool pprof http://localhost:6060/debug/pprof/mutex -// -// The package also exports a handler that serves execution trace data -// for the "go tool trace" command. To collect a 5-second execution trace: -// -// curl -o trace.out http://localhost:6060/debug/pprof/trace?seconds=5 -// go tool trace trace.out -// -// To view all available profiles, open http://localhost:6060/debug/pprof/ -// in your browser. -// -// For a study of the facility in action, visit -// https://blog.golang.org/2011/06/profiling-go-programs.html. -package pprof - -import ( - "bufio" - "bytes" - "context" - "fmt" - "html" - "internal/profile" - "io" - "log" - "net/http" - "net/url" - "os" - "runtime" - "runtime/pprof" - "runtime/trace" - "sort" - "strconv" - "strings" - "time" -) - -func init() { - http.HandleFunc("/debug/pprof/", Index) - http.HandleFunc("/debug/pprof/cmdline", Cmdline) - http.HandleFunc("/debug/pprof/profile", Profile) - http.HandleFunc("/debug/pprof/symbol", Symbol) - http.HandleFunc("/debug/pprof/trace", Trace) -} - -// Cmdline responds with the running program's -// command line, with arguments separated by NUL bytes. -// The package initialization registers it as /debug/pprof/cmdline. -func Cmdline(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Content-Type-Options", "nosniff") - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - fmt.Fprint(w, strings.Join(os.Args, "\x00")) -} - -func sleep(r *http.Request, d time.Duration) { - select { - case <-time.After(d): - case <-r.Context().Done(): - } -} - -func durationExceedsWriteTimeout(r *http.Request, seconds float64) bool { - srv, ok := r.Context().Value(http.ServerContextKey).(*http.Server) - return ok && srv.WriteTimeout != 0 && seconds >= srv.WriteTimeout.Seconds() -} - -func serveError(w http.ResponseWriter, status int, txt string) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("X-Go-Pprof", "1") - w.Header().Del("Content-Disposition") - w.WriteHeader(status) - fmt.Fprintln(w, txt) -} - -// Profile responds with the pprof-formatted cpu profile. -// Profiling lasts for duration specified in seconds GET parameter, or for 30 seconds if not specified. -// The package initialization registers it as /debug/pprof/profile. -func Profile(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Content-Type-Options", "nosniff") - sec, err := strconv.ParseInt(r.FormValue("seconds"), 10, 64) - if sec <= 0 || err != nil { - sec = 30 - } - - if durationExceedsWriteTimeout(r, float64(sec)) { - serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout") - return - } - - // Set Content Type assuming StartCPUProfile will work, - // because if it does it starts writing. - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Disposition", `attachment; filename="profile"`) - if err := pprof.StartCPUProfile(w); err != nil { - // StartCPUProfile failed, so no writes yet. - serveError(w, http.StatusInternalServerError, - fmt.Sprintf("Could not enable CPU profiling: %s", err)) - return - } - sleep(r, time.Duration(sec)*time.Second) - pprof.StopCPUProfile() -} - -// Trace responds with the execution trace in binary form. -// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified. -// The package initialization registers it as /debug/pprof/trace. -func Trace(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Content-Type-Options", "nosniff") - sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64) - if sec <= 0 || err != nil { - sec = 1 - } - - if durationExceedsWriteTimeout(r, sec) { - serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout") - return - } - - // Set Content Type assuming trace.Start will work, - // because if it does it starts writing. - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Disposition", `attachment; filename="trace"`) - if err := trace.Start(w); err != nil { - // trace.Start failed, so no writes yet. - serveError(w, http.StatusInternalServerError, - fmt.Sprintf("Could not enable tracing: %s", err)) - return - } - sleep(r, time.Duration(sec*float64(time.Second))) - trace.Stop() -} - -// Symbol looks up the program counters listed in the request, -// responding with a table mapping program counters to function names. -// The package initialization registers it as /debug/pprof/symbol. -func Symbol(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Content-Type-Options", "nosniff") - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - - // We have to read the whole POST body before - // writing any output. Buffer the output here. - var buf bytes.Buffer - - // We don't know how many symbols we have, but we - // do have symbol information. Pprof only cares whether - // this number is 0 (no symbols available) or > 0. - fmt.Fprintf(&buf, "num_symbols: 1\n") - - var b *bufio.Reader - if r.Method == "POST" { - b = bufio.NewReader(r.Body) - } else { - b = bufio.NewReader(strings.NewReader(r.URL.RawQuery)) - } - - for { - word, err := b.ReadSlice('+') - if err == nil { - word = word[0 : len(word)-1] // trim + - } - pc, _ := strconv.ParseUint(string(word), 0, 64) - if pc != 0 { - f := runtime.FuncForPC(uintptr(pc)) - if f != nil { - fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name()) - } - } - - // Wait until here to check for err; the last - // symbol will have an err because it doesn't end in +. - if err != nil { - if err != io.EOF { - fmt.Fprintf(&buf, "reading request: %v\n", err) - } - break - } - } - - w.Write(buf.Bytes()) -} - -// Handler returns an HTTP handler that serves the named profile. -// Available profiles can be found in [runtime/pprof.Profile]. -func Handler(name string) http.Handler { - return handler(name) -} - -type handler string - -func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Content-Type-Options", "nosniff") - p := pprof.Lookup(string(name)) - if p == nil { - serveError(w, http.StatusNotFound, "Unknown profile") - return - } - if sec := r.FormValue("seconds"); sec != "" { - name.serveDeltaProfile(w, r, p, sec) - return - } - gc, _ := strconv.Atoi(r.FormValue("gc")) - if name == "heap" && gc > 0 { - runtime.GC() - } - debug, _ := strconv.Atoi(r.FormValue("debug")) - if debug != 0 { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - } else { - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name)) - } - p.WriteTo(w, debug) -} - -func (name handler) serveDeltaProfile(w http.ResponseWriter, r *http.Request, p *pprof.Profile, secStr string) { - sec, err := strconv.ParseInt(secStr, 10, 64) - if err != nil || sec <= 0 { - serveError(w, http.StatusBadRequest, `invalid value for "seconds" - must be a positive integer`) - return - } - if !profileSupportsDelta[name] { - serveError(w, http.StatusBadRequest, `"seconds" parameter is not supported for this profile type`) - return - } - // 'name' should be a key in profileSupportsDelta. - if durationExceedsWriteTimeout(r, float64(sec)) { - serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout") - return - } - debug, _ := strconv.Atoi(r.FormValue("debug")) - if debug != 0 { - serveError(w, http.StatusBadRequest, "seconds and debug params are incompatible") - return - } - p0, err := collectProfile(p) - if err != nil { - serveError(w, http.StatusInternalServerError, "failed to collect profile") - return - } - - t := time.NewTimer(time.Duration(sec) * time.Second) - defer t.Stop() - - select { - case <-r.Context().Done(): - err := r.Context().Err() - if err == context.DeadlineExceeded { - serveError(w, http.StatusRequestTimeout, err.Error()) - } else { // TODO: what's a good status code for canceled requests? 400? - serveError(w, http.StatusInternalServerError, err.Error()) - } - return - case <-t.C: - } - - p1, err := collectProfile(p) - if err != nil { - serveError(w, http.StatusInternalServerError, "failed to collect profile") - return - } - ts := p1.TimeNanos - dur := p1.TimeNanos - p0.TimeNanos - - p0.Scale(-1) - - p1, err = profile.Merge([]*profile.Profile{p0, p1}) - if err != nil { - serveError(w, http.StatusInternalServerError, "failed to compute delta") - return - } - - p1.TimeNanos = ts // set since we don't know what profile.Merge set for TimeNanos. - p1.DurationNanos = dur - - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s-delta"`, name)) - p1.Write(w) -} - -func collectProfile(p *pprof.Profile) (*profile.Profile, error) { - var buf bytes.Buffer - if err := p.WriteTo(&buf, 0); err != nil { - return nil, err - } - ts := time.Now().UnixNano() - p0, err := profile.Parse(&buf) - if err != nil { - return nil, err - } - p0.TimeNanos = ts - return p0, nil -} - -var profileSupportsDelta = map[handler]bool{ - "allocs": true, - "block": true, - "goroutine": true, - "heap": true, - "mutex": true, - "threadcreate": true, -} - -var profileDescriptions = map[string]string{ - "allocs": "A sampling of all past memory allocations", - "block": "Stack traces that led to blocking on synchronization primitives", - "cmdline": "The command line invocation of the current program", - "goroutine": "Stack traces of all current goroutines. Use debug=2 as a query parameter to export in the same format as an unrecovered panic.", - "heap": "A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.", - "mutex": "Stack traces of holders of contended mutexes", - "profile": "CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile.", - "threadcreate": "Stack traces that led to the creation of new OS threads", - "trace": "A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.", -} - -type profileEntry struct { - Name string - Href string - Desc string - Count int -} - -// Index responds with the pprof-formatted profile named by the request. -// For example, "/debug/pprof/heap" serves the "heap" profile. -// Index responds to a request for "/debug/pprof/" with an HTML page -// listing the available profiles. -func Index(w http.ResponseWriter, r *http.Request) { - if name, found := strings.CutPrefix(r.URL.Path, "/debug/pprof/"); found { - if name != "" { - handler(name).ServeHTTP(w, r) - return - } - } - - w.Header().Set("X-Content-Type-Options", "nosniff") - w.Header().Set("Content-Type", "text/html; charset=utf-8") - - var profiles []profileEntry - for _, p := range pprof.Profiles() { - profiles = append(profiles, profileEntry{ - Name: p.Name(), - Href: p.Name(), - Desc: profileDescriptions[p.Name()], - Count: p.Count(), - }) - } - - // Adding other profiles exposed from within this package - for _, p := range []string{"cmdline", "profile", "trace"} { - profiles = append(profiles, profileEntry{ - Name: p, - Href: p, - Desc: profileDescriptions[p], - }) - } - - sort.Slice(profiles, func(i, j int) bool { - return profiles[i].Name < profiles[j].Name - }) - - if err := indexTmplExecute(w, profiles); err != nil { - log.Print(err) - } -} - -func indexTmplExecute(w io.Writer, profiles []profileEntry) error { - var b bytes.Buffer - b.WriteString(` - -/debug/pprof/ - - - -/debug/pprof/ -
-

Set debug=1 as a query parameter to export in legacy text format

-
-Types of profiles available: - - -`) - - for _, profile := range profiles { - link := &url.URL{Path: profile.Href, RawQuery: "debug=1"} - fmt.Fprintf(&b, "\n", profile.Count, link, html.EscapeString(profile.Name)) - } - - b.WriteString(`
CountProfile
%d%s
-
full goroutine stack dump -
-

-Profile Descriptions: -

    -`) - for _, profile := range profiles { - fmt.Fprintf(&b, "
  • %s:
    %s
  • \n", html.EscapeString(profile.Name), html.EscapeString(profile.Desc)) - } - b.WriteString(`
-

- -`) - - _, err := w.Write(b.Bytes()) - return err -} diff --git a/contrib/go/_std_1.22/src/net/http/roundtrip.go b/contrib/go/_std_1.22/src/net/http/roundtrip.go deleted file mode 100644 index 08c270179afb..000000000000 --- a/contrib/go/_std_1.22/src/net/http/roundtrip.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !js - -package http - -// RoundTrip implements the [RoundTripper] interface. -// -// For higher-level HTTP client support (such as handling of cookies -// and redirects), see [Get], [Post], and the [Client] type. -// -// Like the RoundTripper interface, the error types returned -// by RoundTrip are unspecified. -func (t *Transport) RoundTrip(req *Request) (*Response, error) { - return t.roundTrip(req) -} diff --git a/contrib/go/_std_1.22/src/net/http/server.go b/contrib/go/_std_1.22/src/net/http/server.go deleted file mode 100644 index 23a603a83dd7..000000000000 --- a/contrib/go/_std_1.22/src/net/http/server.go +++ /dev/null @@ -1,3848 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// HTTP server. See RFC 7230 through 7235. - -package http - -import ( - "bufio" - "bytes" - "context" - "crypto/tls" - "errors" - "fmt" - "internal/godebug" - "io" - "log" - "math/rand" - "net" - "net/textproto" - "net/url" - urlpkg "net/url" - "path" - "runtime" - "sort" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - - "golang.org/x/net/http/httpguts" -) - -// Errors used by the HTTP server. -var ( - // ErrBodyNotAllowed is returned by ResponseWriter.Write calls - // when the HTTP method or response code does not permit a - // body. - ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body") - - // ErrHijacked is returned by ResponseWriter.Write calls when - // the underlying connection has been hijacked using the - // Hijacker interface. A zero-byte write on a hijacked - // connection will return ErrHijacked without any other side - // effects. - ErrHijacked = errors.New("http: connection has been hijacked") - - // ErrContentLength is returned by ResponseWriter.Write calls - // when a Handler set a Content-Length response header with a - // declared size and then attempted to write more bytes than - // declared. - ErrContentLength = errors.New("http: wrote more than the declared Content-Length") - - // Deprecated: ErrWriteAfterFlush is no longer returned by - // anything in the net/http package. Callers should not - // compare errors against this variable. - ErrWriteAfterFlush = errors.New("unused") -) - -// A Handler responds to an HTTP request. -// -// [Handler.ServeHTTP] should write reply headers and data to the [ResponseWriter] -// and then return. Returning signals that the request is finished; it -// is not valid to use the [ResponseWriter] or read from the -// [Request.Body] after or concurrently with the completion of the -// ServeHTTP call. -// -// Depending on the HTTP client software, HTTP protocol version, and -// any intermediaries between the client and the Go server, it may not -// be possible to read from the [Request.Body] after writing to the -// [ResponseWriter]. Cautious handlers should read the [Request.Body] -// first, and then reply. -// -// Except for reading the body, handlers should not modify the -// provided Request. -// -// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes -// that the effect of the panic was isolated to the active request. -// It recovers the panic, logs a stack trace to the server error log, -// and either closes the network connection or sends an HTTP/2 -// RST_STREAM, depending on the HTTP protocol. To abort a handler so -// the client sees an interrupted response but the server doesn't log -// an error, panic with the value [ErrAbortHandler]. -type Handler interface { - ServeHTTP(ResponseWriter, *Request) -} - -// A ResponseWriter interface is used by an HTTP handler to -// construct an HTTP response. -// -// A ResponseWriter may not be used after [Handler.ServeHTTP] has returned. -type ResponseWriter interface { - // Header returns the header map that will be sent by - // [ResponseWriter.WriteHeader]. The [Header] map also is the mechanism with which - // [Handler] implementations can set HTTP trailers. - // - // Changing the header map after a call to [ResponseWriter.WriteHeader] (or - // [ResponseWriter.Write]) has no effect unless the HTTP status code was of the - // 1xx class or the modified headers are trailers. - // - // There are two ways to set Trailers. The preferred way is to - // predeclare in the headers which trailers you will later - // send by setting the "Trailer" header to the names of the - // trailer keys which will come later. In this case, those - // keys of the Header map are treated as if they were - // trailers. See the example. The second way, for trailer - // keys not known to the [Handler] until after the first [ResponseWriter.Write], - // is to prefix the [Header] map keys with the [TrailerPrefix] - // constant value. - // - // To suppress automatic response headers (such as "Date"), set - // their value to nil. - Header() Header - - // Write writes the data to the connection as part of an HTTP reply. - // - // If [ResponseWriter.WriteHeader] has not yet been called, Write calls - // WriteHeader(http.StatusOK) before writing the data. If the Header - // does not contain a Content-Type line, Write adds a Content-Type set - // to the result of passing the initial 512 bytes of written data to - // [DetectContentType]. Additionally, if the total size of all written - // data is under a few KB and there are no Flush calls, the - // Content-Length header is added automatically. - // - // Depending on the HTTP protocol version and the client, calling - // Write or WriteHeader may prevent future reads on the - // Request.Body. For HTTP/1.x requests, handlers should read any - // needed request body data before writing the response. Once the - // headers have been flushed (due to either an explicit Flusher.Flush - // call or writing enough data to trigger a flush), the request body - // may be unavailable. For HTTP/2 requests, the Go HTTP server permits - // handlers to continue to read the request body while concurrently - // writing the response. However, such behavior may not be supported - // by all HTTP/2 clients. Handlers should read before writing if - // possible to maximize compatibility. - Write([]byte) (int, error) - - // WriteHeader sends an HTTP response header with the provided - // status code. - // - // If WriteHeader is not called explicitly, the first call to Write - // will trigger an implicit WriteHeader(http.StatusOK). - // Thus explicit calls to WriteHeader are mainly used to - // send error codes or 1xx informational responses. - // - // The provided code must be a valid HTTP 1xx-5xx status code. - // Any number of 1xx headers may be written, followed by at most - // one 2xx-5xx header. 1xx headers are sent immediately, but 2xx-5xx - // headers may be buffered. Use the Flusher interface to send - // buffered data. The header map is cleared when 2xx-5xx headers are - // sent, but not with 1xx headers. - // - // The server will automatically send a 100 (Continue) header - // on the first read from the request body if the request has - // an "Expect: 100-continue" header. - WriteHeader(statusCode int) -} - -// The Flusher interface is implemented by ResponseWriters that allow -// an HTTP handler to flush buffered data to the client. -// -// The default HTTP/1.x and HTTP/2 [ResponseWriter] implementations -// support [Flusher], but ResponseWriter wrappers may not. Handlers -// should always test for this ability at runtime. -// -// Note that even for ResponseWriters that support Flush, -// if the client is connected through an HTTP proxy, -// the buffered data may not reach the client until the response -// completes. -type Flusher interface { - // Flush sends any buffered data to the client. - Flush() -} - -// The Hijacker interface is implemented by ResponseWriters that allow -// an HTTP handler to take over the connection. -// -// The default [ResponseWriter] for HTTP/1.x connections supports -// Hijacker, but HTTP/2 connections intentionally do not. -// ResponseWriter wrappers may also not support Hijacker. Handlers -// should always test for this ability at runtime. -type Hijacker interface { - // Hijack lets the caller take over the connection. - // After a call to Hijack the HTTP server library - // will not do anything else with the connection. - // - // It becomes the caller's responsibility to manage - // and close the connection. - // - // The returned net.Conn may have read or write deadlines - // already set, depending on the configuration of the - // Server. It is the caller's responsibility to set - // or clear those deadlines as needed. - // - // The returned bufio.Reader may contain unprocessed buffered - // data from the client. - // - // After a call to Hijack, the original Request.Body must not - // be used. The original Request's Context remains valid and - // is not canceled until the Request's ServeHTTP method - // returns. - Hijack() (net.Conn, *bufio.ReadWriter, error) -} - -// The CloseNotifier interface is implemented by ResponseWriters which -// allow detecting when the underlying connection has gone away. -// -// This mechanism can be used to cancel long operations on the server -// if the client has disconnected before the response is ready. -// -// Deprecated: the CloseNotifier interface predates Go's context package. -// New code should use [Request.Context] instead. -type CloseNotifier interface { - // CloseNotify returns a channel that receives at most a - // single value (true) when the client connection has gone - // away. - // - // CloseNotify may wait to notify until Request.Body has been - // fully read. - // - // After the Handler has returned, there is no guarantee - // that the channel receives a value. - // - // If the protocol is HTTP/1.1 and CloseNotify is called while - // processing an idempotent request (such a GET) while - // HTTP/1.1 pipelining is in use, the arrival of a subsequent - // pipelined request may cause a value to be sent on the - // returned channel. In practice HTTP/1.1 pipelining is not - // enabled in browsers and not seen often in the wild. If this - // is a problem, use HTTP/2 or only use CloseNotify on methods - // such as POST. - CloseNotify() <-chan bool -} - -var ( - // ServerContextKey is a context key. It can be used in HTTP - // handlers with Context.Value to access the server that - // started the handler. The associated value will be of - // type *Server. - ServerContextKey = &contextKey{"http-server"} - - // LocalAddrContextKey is a context key. It can be used in - // HTTP handlers with Context.Value to access the local - // address the connection arrived on. - // The associated value will be of type net.Addr. - LocalAddrContextKey = &contextKey{"local-addr"} -) - -// A conn represents the server side of an HTTP connection. -type conn struct { - // server is the server on which the connection arrived. - // Immutable; never nil. - server *Server - - // cancelCtx cancels the connection-level context. - cancelCtx context.CancelFunc - - // rwc is the underlying network connection. - // This is never wrapped by other types and is the value given out - // to CloseNotifier callers. It is usually of type *net.TCPConn or - // *tls.Conn. - rwc net.Conn - - // remoteAddr is rwc.RemoteAddr().String(). It is not populated synchronously - // inside the Listener's Accept goroutine, as some implementations block. - // It is populated immediately inside the (*conn).serve goroutine. - // This is the value of a Handler's (*Request).RemoteAddr. - remoteAddr string - - // tlsState is the TLS connection state when using TLS. - // nil means not TLS. - tlsState *tls.ConnectionState - - // werr is set to the first write error to rwc. - // It is set via checkConnErrorWriter{w}, where bufw writes. - werr error - - // r is bufr's read source. It's a wrapper around rwc that provides - // io.LimitedReader-style limiting (while reading request headers) - // and functionality to support CloseNotifier. See *connReader docs. - r *connReader - - // bufr reads from r. - bufr *bufio.Reader - - // bufw writes to checkConnErrorWriter{c}, which populates werr on error. - bufw *bufio.Writer - - // lastMethod is the method of the most recent request - // on this connection, if any. - lastMethod string - - curReq atomic.Pointer[response] // (which has a Request in it) - - curState atomic.Uint64 // packed (unixtime<<8|uint8(ConnState)) - - // mu guards hijackedv - mu sync.Mutex - - // hijackedv is whether this connection has been hijacked - // by a Handler with the Hijacker interface. - // It is guarded by mu. - hijackedv bool -} - -func (c *conn) hijacked() bool { - c.mu.Lock() - defer c.mu.Unlock() - return c.hijackedv -} - -// c.mu must be held. -func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) { - if c.hijackedv { - return nil, nil, ErrHijacked - } - c.r.abortPendingRead() - - c.hijackedv = true - rwc = c.rwc - rwc.SetDeadline(time.Time{}) - - buf = bufio.NewReadWriter(c.bufr, bufio.NewWriter(rwc)) - if c.r.hasByte { - if _, err := c.bufr.Peek(c.bufr.Buffered() + 1); err != nil { - return nil, nil, fmt.Errorf("unexpected Peek failure reading buffered byte: %v", err) - } - } - c.setState(rwc, StateHijacked, runHooks) - return -} - -// This should be >= 512 bytes for DetectContentType, -// but otherwise it's somewhat arbitrary. -const bufferBeforeChunkingSize = 2048 - -// chunkWriter writes to a response's conn buffer, and is the writer -// wrapped by the response.w buffered writer. -// -// chunkWriter also is responsible for finalizing the Header, including -// conditionally setting the Content-Type and setting a Content-Length -// in cases where the handler's final output is smaller than the buffer -// size. It also conditionally adds chunk headers, when in chunking mode. -// -// See the comment above (*response).Write for the entire write flow. -type chunkWriter struct { - res *response - - // header is either nil or a deep clone of res.handlerHeader - // at the time of res.writeHeader, if res.writeHeader is - // called and extra buffering is being done to calculate - // Content-Type and/or Content-Length. - header Header - - // wroteHeader tells whether the header's been written to "the - // wire" (or rather: w.conn.buf). this is unlike - // (*response).wroteHeader, which tells only whether it was - // logically written. - wroteHeader bool - - // set by the writeHeader method: - chunking bool // using chunked transfer encoding for reply body -} - -var ( - crlf = []byte("\r\n") - colonSpace = []byte(": ") -) - -func (cw *chunkWriter) Write(p []byte) (n int, err error) { - if !cw.wroteHeader { - cw.writeHeader(p) - } - if cw.res.req.Method == "HEAD" { - // Eat writes. - return len(p), nil - } - if cw.chunking { - _, err = fmt.Fprintf(cw.res.conn.bufw, "%x\r\n", len(p)) - if err != nil { - cw.res.conn.rwc.Close() - return - } - } - n, err = cw.res.conn.bufw.Write(p) - if cw.chunking && err == nil { - _, err = cw.res.conn.bufw.Write(crlf) - } - if err != nil { - cw.res.conn.rwc.Close() - } - return -} - -func (cw *chunkWriter) flush() error { - if !cw.wroteHeader { - cw.writeHeader(nil) - } - return cw.res.conn.bufw.Flush() -} - -func (cw *chunkWriter) close() { - if !cw.wroteHeader { - cw.writeHeader(nil) - } - if cw.chunking { - bw := cw.res.conn.bufw // conn's bufio writer - // zero chunk to mark EOF - bw.WriteString("0\r\n") - if trailers := cw.res.finalTrailers(); trailers != nil { - trailers.Write(bw) // the writer handles noting errors - } - // final blank line after the trailers (whether - // present or not) - bw.WriteString("\r\n") - } -} - -// A response represents the server side of an HTTP response. -type response struct { - conn *conn - req *Request // request for this response - reqBody io.ReadCloser - cancelCtx context.CancelFunc // when ServeHTTP exits - wroteHeader bool // a non-1xx header has been (logically) written - wroteContinue bool // 100 Continue response was written - wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive" - wantsClose bool // HTTP request has Connection "close" - - // canWriteContinue is an atomic boolean that says whether or - // not a 100 Continue header can be written to the - // connection. - // writeContinueMu must be held while writing the header. - // These two fields together synchronize the body reader (the - // expectContinueReader, which wants to write 100 Continue) - // against the main writer. - canWriteContinue atomic.Bool - writeContinueMu sync.Mutex - - w *bufio.Writer // buffers output in chunks to chunkWriter - cw chunkWriter - - // handlerHeader is the Header that Handlers get access to, - // which may be retained and mutated even after WriteHeader. - // handlerHeader is copied into cw.header at WriteHeader - // time, and privately mutated thereafter. - handlerHeader Header - calledHeader bool // handler accessed handlerHeader via Header - - written int64 // number of bytes written in body - contentLength int64 // explicitly-declared Content-Length; or -1 - status int // status code passed to WriteHeader - - // close connection after this reply. set on request and - // updated after response from handler if there's a - // "Connection: keep-alive" response header and a - // Content-Length. - closeAfterReply bool - - // When fullDuplex is false (the default), we consume any remaining - // request body before starting to write a response. - fullDuplex bool - - // requestBodyLimitHit is set by requestTooLarge when - // maxBytesReader hits its max size. It is checked in - // WriteHeader, to make sure we don't consume the - // remaining request body to try to advance to the next HTTP - // request. Instead, when this is set, we stop reading - // subsequent requests on this connection and stop reading - // input from it. - requestBodyLimitHit bool - - // trailers are the headers to be sent after the handler - // finishes writing the body. This field is initialized from - // the Trailer response header when the response header is - // written. - trailers []string - - handlerDone atomic.Bool // set true when the handler exits - - // Buffers for Date, Content-Length, and status code - dateBuf [len(TimeFormat)]byte - clenBuf [10]byte - statusBuf [3]byte - - // closeNotifyCh is the channel returned by CloseNotify. - // TODO(bradfitz): this is currently (for Go 1.8) always - // non-nil. Make this lazily-created again as it used to be? - closeNotifyCh chan bool - didCloseNotify atomic.Bool // atomic (only false->true winner should send) -} - -func (c *response) SetReadDeadline(deadline time.Time) error { - return c.conn.rwc.SetReadDeadline(deadline) -} - -func (c *response) SetWriteDeadline(deadline time.Time) error { - return c.conn.rwc.SetWriteDeadline(deadline) -} - -func (c *response) EnableFullDuplex() error { - c.fullDuplex = true - return nil -} - -// TrailerPrefix is a magic prefix for [ResponseWriter.Header] map keys -// that, if present, signals that the map entry is actually for -// the response trailers, and not the response headers. The prefix -// is stripped after the ServeHTTP call finishes and the values are -// sent in the trailers. -// -// This mechanism is intended only for trailers that are not known -// prior to the headers being written. If the set of trailers is fixed -// or known before the header is written, the normal Go trailers mechanism -// is preferred: -// -// https://pkg.go.dev/net/http#ResponseWriter -// https://pkg.go.dev/net/http#example-ResponseWriter-Trailers -const TrailerPrefix = "Trailer:" - -// finalTrailers is called after the Handler exits and returns a non-nil -// value if the Handler set any trailers. -func (w *response) finalTrailers() Header { - var t Header - for k, vv := range w.handlerHeader { - if kk, found := strings.CutPrefix(k, TrailerPrefix); found { - if t == nil { - t = make(Header) - } - t[kk] = vv - } - } - for _, k := range w.trailers { - if t == nil { - t = make(Header) - } - for _, v := range w.handlerHeader[k] { - t.Add(k, v) - } - } - return t -} - -// declareTrailer is called for each Trailer header when the -// response header is written. It notes that a header will need to be -// written in the trailers at the end of the response. -func (w *response) declareTrailer(k string) { - k = CanonicalHeaderKey(k) - if !httpguts.ValidTrailerHeader(k) { - // Forbidden by RFC 7230, section 4.1.2 - return - } - w.trailers = append(w.trailers, k) -} - -// requestTooLarge is called by maxBytesReader when too much input has -// been read from the client. -func (w *response) requestTooLarge() { - w.closeAfterReply = true - w.requestBodyLimitHit = true - if !w.wroteHeader { - w.Header().Set("Connection", "close") - } -} - -// writerOnly hides an io.Writer value's optional ReadFrom method -// from io.Copy. -type writerOnly struct { - io.Writer -} - -// ReadFrom is here to optimize copying from an [*os.File] regular file -// to a [*net.TCPConn] with sendfile, or from a supported src type such -// as a *net.TCPConn on Linux with splice. -func (w *response) ReadFrom(src io.Reader) (n int64, err error) { - buf := getCopyBuf() - defer putCopyBuf(buf) - - // Our underlying w.conn.rwc is usually a *TCPConn (with its - // own ReadFrom method). If not, just fall back to the normal - // copy method. - rf, ok := w.conn.rwc.(io.ReaderFrom) - if !ok { - return io.CopyBuffer(writerOnly{w}, src, buf) - } - - // Copy the first sniffLen bytes before switching to ReadFrom. - // This ensures we don't start writing the response before the - // source is available (see golang.org/issue/5660) and provides - // enough bytes to perform Content-Type sniffing when required. - if !w.cw.wroteHeader { - n0, err := io.CopyBuffer(writerOnly{w}, io.LimitReader(src, sniffLen), buf) - n += n0 - if err != nil || n0 < sniffLen { - return n, err - } - } - - w.w.Flush() // get rid of any previous writes - w.cw.flush() // make sure Header is written; flush data to rwc - - // Now that cw has been flushed, its chunking field is guaranteed initialized. - if !w.cw.chunking && w.bodyAllowed() { - n0, err := rf.ReadFrom(src) - n += n0 - w.written += n0 - return n, err - } - - n0, err := io.CopyBuffer(writerOnly{w}, src, buf) - n += n0 - return n, err -} - -// debugServerConnections controls whether all server connections are wrapped -// with a verbose logging wrapper. -const debugServerConnections = false - -// Create new connection from rwc. -func (srv *Server) newConn(rwc net.Conn) *conn { - c := &conn{ - server: srv, - rwc: rwc, - } - if debugServerConnections { - c.rwc = newLoggingConn("server", c.rwc) - } - return c -} - -type readResult struct { - _ incomparable - n int - err error - b byte // byte read, if n == 1 -} - -// connReader is the io.Reader wrapper used by *conn. It combines a -// selectively-activated io.LimitedReader (to bound request header -// read sizes) with support for selectively keeping an io.Reader.Read -// call blocked in a background goroutine to wait for activity and -// trigger a CloseNotifier channel. -type connReader struct { - conn *conn - - mu sync.Mutex // guards following - hasByte bool - byteBuf [1]byte - cond *sync.Cond - inRead bool - aborted bool // set true before conn.rwc deadline is set to past - remain int64 // bytes remaining -} - -func (cr *connReader) lock() { - cr.mu.Lock() - if cr.cond == nil { - cr.cond = sync.NewCond(&cr.mu) - } -} - -func (cr *connReader) unlock() { cr.mu.Unlock() } - -func (cr *connReader) startBackgroundRead() { - cr.lock() - defer cr.unlock() - if cr.inRead { - panic("invalid concurrent Body.Read call") - } - if cr.hasByte { - return - } - cr.inRead = true - cr.conn.rwc.SetReadDeadline(time.Time{}) - go cr.backgroundRead() -} - -func (cr *connReader) backgroundRead() { - n, err := cr.conn.rwc.Read(cr.byteBuf[:]) - cr.lock() - if n == 1 { - cr.hasByte = true - // We were past the end of the previous request's body already - // (since we wouldn't be in a background read otherwise), so - // this is a pipelined HTTP request. Prior to Go 1.11 we used to - // send on the CloseNotify channel and cancel the context here, - // but the behavior was documented as only "may", and we only - // did that because that's how CloseNotify accidentally behaved - // in very early Go releases prior to context support. Once we - // added context support, people used a Handler's - // Request.Context() and passed it along. Having that context - // cancel on pipelined HTTP requests caused problems. - // Fortunately, almost nothing uses HTTP/1.x pipelining. - // Unfortunately, apt-get does, or sometimes does. - // New Go 1.11 behavior: don't fire CloseNotify or cancel - // contexts on pipelined requests. Shouldn't affect people, but - // fixes cases like Issue 23921. This does mean that a client - // closing their TCP connection after sending a pipelined - // request won't cancel the context, but we'll catch that on any - // write failure (in checkConnErrorWriter.Write). - // If the server never writes, yes, there are still contrived - // server & client behaviors where this fails to ever cancel the - // context, but that's kinda why HTTP/1.x pipelining died - // anyway. - } - if ne, ok := err.(net.Error); ok && cr.aborted && ne.Timeout() { - // Ignore this error. It's the expected error from - // another goroutine calling abortPendingRead. - } else if err != nil { - cr.handleReadError(err) - } - cr.aborted = false - cr.inRead = false - cr.unlock() - cr.cond.Broadcast() -} - -func (cr *connReader) abortPendingRead() { - cr.lock() - defer cr.unlock() - if !cr.inRead { - return - } - cr.aborted = true - cr.conn.rwc.SetReadDeadline(aLongTimeAgo) - for cr.inRead { - cr.cond.Wait() - } - cr.conn.rwc.SetReadDeadline(time.Time{}) -} - -func (cr *connReader) setReadLimit(remain int64) { cr.remain = remain } -func (cr *connReader) setInfiniteReadLimit() { cr.remain = maxInt64 } -func (cr *connReader) hitReadLimit() bool { return cr.remain <= 0 } - -// handleReadError is called whenever a Read from the client returns a -// non-nil error. -// -// The provided non-nil err is almost always io.EOF or a "use of -// closed network connection". In any case, the error is not -// particularly interesting, except perhaps for debugging during -// development. Any error means the connection is dead and we should -// down its context. -// -// It may be called from multiple goroutines. -func (cr *connReader) handleReadError(_ error) { - cr.conn.cancelCtx() - cr.closeNotify() -} - -// may be called from multiple goroutines. -func (cr *connReader) closeNotify() { - res := cr.conn.curReq.Load() - if res != nil && !res.didCloseNotify.Swap(true) { - res.closeNotifyCh <- true - } -} - -func (cr *connReader) Read(p []byte) (n int, err error) { - cr.lock() - if cr.inRead { - cr.unlock() - if cr.conn.hijacked() { - panic("invalid Body.Read call. After hijacked, the original Request must not be used") - } - panic("invalid concurrent Body.Read call") - } - if cr.hitReadLimit() { - cr.unlock() - return 0, io.EOF - } - if len(p) == 0 { - cr.unlock() - return 0, nil - } - if int64(len(p)) > cr.remain { - p = p[:cr.remain] - } - if cr.hasByte { - p[0] = cr.byteBuf[0] - cr.hasByte = false - cr.unlock() - return 1, nil - } - cr.inRead = true - cr.unlock() - n, err = cr.conn.rwc.Read(p) - - cr.lock() - cr.inRead = false - if err != nil { - cr.handleReadError(err) - } - cr.remain -= int64(n) - cr.unlock() - - cr.cond.Broadcast() - return n, err -} - -var ( - bufioReaderPool sync.Pool - bufioWriter2kPool sync.Pool - bufioWriter4kPool sync.Pool -) - -const copyBufPoolSize = 32 * 1024 - -var copyBufPool = sync.Pool{New: func() any { return new([copyBufPoolSize]byte) }} - -func getCopyBuf() []byte { - return copyBufPool.Get().(*[copyBufPoolSize]byte)[:] -} -func putCopyBuf(b []byte) { - if len(b) != copyBufPoolSize { - panic("trying to put back buffer of the wrong size in the copyBufPool") - } - copyBufPool.Put((*[copyBufPoolSize]byte)(b)) -} - -func bufioWriterPool(size int) *sync.Pool { - switch size { - case 2 << 10: - return &bufioWriter2kPool - case 4 << 10: - return &bufioWriter4kPool - } - return nil -} - -func newBufioReader(r io.Reader) *bufio.Reader { - if v := bufioReaderPool.Get(); v != nil { - br := v.(*bufio.Reader) - br.Reset(r) - return br - } - // Note: if this reader size is ever changed, update - // TestHandlerBodyClose's assumptions. - return bufio.NewReader(r) -} - -func putBufioReader(br *bufio.Reader) { - br.Reset(nil) - bufioReaderPool.Put(br) -} - -func newBufioWriterSize(w io.Writer, size int) *bufio.Writer { - pool := bufioWriterPool(size) - if pool != nil { - if v := pool.Get(); v != nil { - bw := v.(*bufio.Writer) - bw.Reset(w) - return bw - } - } - return bufio.NewWriterSize(w, size) -} - -func putBufioWriter(bw *bufio.Writer) { - bw.Reset(nil) - if pool := bufioWriterPool(bw.Available()); pool != nil { - pool.Put(bw) - } -} - -// DefaultMaxHeaderBytes is the maximum permitted size of the headers -// in an HTTP request. -// This can be overridden by setting [Server.MaxHeaderBytes]. -const DefaultMaxHeaderBytes = 1 << 20 // 1 MB - -func (srv *Server) maxHeaderBytes() int { - if srv.MaxHeaderBytes > 0 { - return srv.MaxHeaderBytes - } - return DefaultMaxHeaderBytes -} - -func (srv *Server) initialReadLimitSize() int64 { - return int64(srv.maxHeaderBytes()) + 4096 // bufio slop -} - -// tlsHandshakeTimeout returns the time limit permitted for the TLS -// handshake, or zero for unlimited. -// -// It returns the minimum of any positive ReadHeaderTimeout, -// ReadTimeout, or WriteTimeout. -func (srv *Server) tlsHandshakeTimeout() time.Duration { - var ret time.Duration - for _, v := range [...]time.Duration{ - srv.ReadHeaderTimeout, - srv.ReadTimeout, - srv.WriteTimeout, - } { - if v <= 0 { - continue - } - if ret == 0 || v < ret { - ret = v - } - } - return ret -} - -// wrapper around io.ReadCloser which on first read, sends an -// HTTP/1.1 100 Continue header -type expectContinueReader struct { - resp *response - readCloser io.ReadCloser - closed atomic.Bool - sawEOF atomic.Bool -} - -func (ecr *expectContinueReader) Read(p []byte) (n int, err error) { - if ecr.closed.Load() { - return 0, ErrBodyReadAfterClose - } - w := ecr.resp - if !w.wroteContinue && w.canWriteContinue.Load() && !w.conn.hijacked() { - w.wroteContinue = true - w.writeContinueMu.Lock() - if w.canWriteContinue.Load() { - w.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n") - w.conn.bufw.Flush() - w.canWriteContinue.Store(false) - } - w.writeContinueMu.Unlock() - } - n, err = ecr.readCloser.Read(p) - if err == io.EOF { - ecr.sawEOF.Store(true) - } - return -} - -func (ecr *expectContinueReader) Close() error { - ecr.closed.Store(true) - return ecr.readCloser.Close() -} - -// TimeFormat is the time format to use when generating times in HTTP -// headers. It is like [time.RFC1123] but hard-codes GMT as the time -// zone. The time being formatted must be in UTC for Format to -// generate the correct format. -// -// For parsing this time format, see [ParseTime]. -const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" - -// appendTime is a non-allocating version of []byte(t.UTC().Format(TimeFormat)) -func appendTime(b []byte, t time.Time) []byte { - const days = "SunMonTueWedThuFriSat" - const months = "JanFebMarAprMayJunJulAugSepOctNovDec" - - t = t.UTC() - yy, mm, dd := t.Date() - hh, mn, ss := t.Clock() - day := days[3*t.Weekday():] - mon := months[3*(mm-1):] - - return append(b, - day[0], day[1], day[2], ',', ' ', - byte('0'+dd/10), byte('0'+dd%10), ' ', - mon[0], mon[1], mon[2], ' ', - byte('0'+yy/1000), byte('0'+(yy/100)%10), byte('0'+(yy/10)%10), byte('0'+yy%10), ' ', - byte('0'+hh/10), byte('0'+hh%10), ':', - byte('0'+mn/10), byte('0'+mn%10), ':', - byte('0'+ss/10), byte('0'+ss%10), ' ', - 'G', 'M', 'T') -} - -var errTooLarge = errors.New("http: request too large") - -// Read next request from connection. -func (c *conn) readRequest(ctx context.Context) (w *response, err error) { - if c.hijacked() { - return nil, ErrHijacked - } - - var ( - wholeReqDeadline time.Time // or zero if none - hdrDeadline time.Time // or zero if none - ) - t0 := time.Now() - if d := c.server.readHeaderTimeout(); d > 0 { - hdrDeadline = t0.Add(d) - } - if d := c.server.ReadTimeout; d > 0 { - wholeReqDeadline = t0.Add(d) - } - c.rwc.SetReadDeadline(hdrDeadline) - if d := c.server.WriteTimeout; d > 0 { - defer func() { - c.rwc.SetWriteDeadline(time.Now().Add(d)) - }() - } - - c.r.setReadLimit(c.server.initialReadLimitSize()) - if c.lastMethod == "POST" { - // RFC 7230 section 3 tolerance for old buggy clients. - peek, _ := c.bufr.Peek(4) // ReadRequest will get err below - c.bufr.Discard(numLeadingCRorLF(peek)) - } - req, err := readRequest(c.bufr) - if err != nil { - if c.r.hitReadLimit() { - return nil, errTooLarge - } - return nil, err - } - - if !http1ServerSupportsRequest(req) { - return nil, statusError{StatusHTTPVersionNotSupported, "unsupported protocol version"} - } - - c.lastMethod = req.Method - c.r.setInfiniteReadLimit() - - hosts, haveHost := req.Header["Host"] - isH2Upgrade := req.isH2Upgrade() - if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade && req.Method != "CONNECT" { - return nil, badRequestError("missing required Host header") - } - if len(hosts) == 1 && !httpguts.ValidHostHeader(hosts[0]) { - return nil, badRequestError("malformed Host header") - } - for k, vv := range req.Header { - if !httpguts.ValidHeaderFieldName(k) { - return nil, badRequestError("invalid header name") - } - for _, v := range vv { - if !httpguts.ValidHeaderFieldValue(v) { - return nil, badRequestError("invalid header value") - } - } - } - delete(req.Header, "Host") - - ctx, cancelCtx := context.WithCancel(ctx) - req.ctx = ctx - req.RemoteAddr = c.remoteAddr - req.TLS = c.tlsState - if body, ok := req.Body.(*body); ok { - body.doEarlyClose = true - } - - // Adjust the read deadline if necessary. - if !hdrDeadline.Equal(wholeReqDeadline) { - c.rwc.SetReadDeadline(wholeReqDeadline) - } - - w = &response{ - conn: c, - cancelCtx: cancelCtx, - req: req, - reqBody: req.Body, - handlerHeader: make(Header), - contentLength: -1, - closeNotifyCh: make(chan bool, 1), - - // We populate these ahead of time so we're not - // reading from req.Header after their Handler starts - // and maybe mutates it (Issue 14940) - wants10KeepAlive: req.wantsHttp10KeepAlive(), - wantsClose: req.wantsClose(), - } - if isH2Upgrade { - w.closeAfterReply = true - } - w.cw.res = w - w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize) - return w, nil -} - -// http1ServerSupportsRequest reports whether Go's HTTP/1.x server -// supports the given request. -func http1ServerSupportsRequest(req *Request) bool { - if req.ProtoMajor == 1 { - return true - } - // Accept "PRI * HTTP/2.0" upgrade requests, so Handlers can - // wire up their own HTTP/2 upgrades. - if req.ProtoMajor == 2 && req.ProtoMinor == 0 && - req.Method == "PRI" && req.RequestURI == "*" { - return true - } - // Reject HTTP/0.x, and all other HTTP/2+ requests (which - // aren't encoded in ASCII anyway). - return false -} - -func (w *response) Header() Header { - if w.cw.header == nil && w.wroteHeader && !w.cw.wroteHeader { - // Accessing the header between logically writing it - // and physically writing it means we need to allocate - // a clone to snapshot the logically written state. - w.cw.header = w.handlerHeader.Clone() - } - w.calledHeader = true - return w.handlerHeader -} - -// maxPostHandlerReadBytes is the max number of Request.Body bytes not -// consumed by a handler that the server will read from the client -// in order to keep a connection alive. If there are more bytes than -// this then the server to be paranoid instead sends a "Connection: -// close" response. -// -// This number is approximately what a typical machine's TCP buffer -// size is anyway. (if we have the bytes on the machine, we might as -// well read them) -const maxPostHandlerReadBytes = 256 << 10 - -func checkWriteHeaderCode(code int) { - // Issue 22880: require valid WriteHeader status codes. - // For now we only enforce that it's three digits. - // In the future we might block things over 599 (600 and above aren't defined - // at https://httpwg.org/specs/rfc7231.html#status.codes). - // But for now any three digits. - // - // We used to send "HTTP/1.1 000 0" on the wire in responses but there's - // no equivalent bogus thing we can realistically send in HTTP/2, - // so we'll consistently panic instead and help people find their bugs - // early. (We can't return an error from WriteHeader even if we wanted to.) - if code < 100 || code > 999 { - panic(fmt.Sprintf("invalid WriteHeader code %v", code)) - } -} - -// relevantCaller searches the call stack for the first function outside of net/http. -// The purpose of this function is to provide more helpful error messages. -func relevantCaller() runtime.Frame { - pc := make([]uintptr, 16) - n := runtime.Callers(1, pc) - frames := runtime.CallersFrames(pc[:n]) - var frame runtime.Frame - for { - frame, more := frames.Next() - if !strings.HasPrefix(frame.Function, "net/http.") { - return frame - } - if !more { - break - } - } - return frame -} - -func (w *response) WriteHeader(code int) { - if w.conn.hijacked() { - caller := relevantCaller() - w.conn.server.logf("http: response.WriteHeader on hijacked connection from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line) - return - } - if w.wroteHeader { - caller := relevantCaller() - w.conn.server.logf("http: superfluous response.WriteHeader call from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line) - return - } - checkWriteHeaderCode(code) - - // Handle informational headers. - // - // We shouldn't send any further headers after 101 Switching Protocols, - // so it takes the non-informational path. - if code >= 100 && code <= 199 && code != StatusSwitchingProtocols { - // Prevent a potential race with an automatically-sent 100 Continue triggered by Request.Body.Read() - if code == 100 && w.canWriteContinue.Load() { - w.writeContinueMu.Lock() - w.canWriteContinue.Store(false) - w.writeContinueMu.Unlock() - } - - writeStatusLine(w.conn.bufw, w.req.ProtoAtLeast(1, 1), code, w.statusBuf[:]) - - // Per RFC 8297 we must not clear the current header map - w.handlerHeader.WriteSubset(w.conn.bufw, excludedHeadersNoBody) - w.conn.bufw.Write(crlf) - w.conn.bufw.Flush() - - return - } - - w.wroteHeader = true - w.status = code - - if w.calledHeader && w.cw.header == nil { - w.cw.header = w.handlerHeader.Clone() - } - - if cl := w.handlerHeader.get("Content-Length"); cl != "" { - v, err := strconv.ParseInt(cl, 10, 64) - if err == nil && v >= 0 { - w.contentLength = v - } else { - w.conn.server.logf("http: invalid Content-Length of %q", cl) - w.handlerHeader.Del("Content-Length") - } - } -} - -// extraHeader is the set of headers sometimes added by chunkWriter.writeHeader. -// This type is used to avoid extra allocations from cloning and/or populating -// the response Header map and all its 1-element slices. -type extraHeader struct { - contentType string - connection string - transferEncoding string - date []byte // written if not nil - contentLength []byte // written if not nil -} - -// Sorted the same as extraHeader.Write's loop. -var extraHeaderKeys = [][]byte{ - []byte("Content-Type"), - []byte("Connection"), - []byte("Transfer-Encoding"), -} - -var ( - headerContentLength = []byte("Content-Length: ") - headerDate = []byte("Date: ") -) - -// Write writes the headers described in h to w. -// -// This method has a value receiver, despite the somewhat large size -// of h, because it prevents an allocation. The escape analysis isn't -// smart enough to realize this function doesn't mutate h. -func (h extraHeader) Write(w *bufio.Writer) { - if h.date != nil { - w.Write(headerDate) - w.Write(h.date) - w.Write(crlf) - } - if h.contentLength != nil { - w.Write(headerContentLength) - w.Write(h.contentLength) - w.Write(crlf) - } - for i, v := range []string{h.contentType, h.connection, h.transferEncoding} { - if v != "" { - w.Write(extraHeaderKeys[i]) - w.Write(colonSpace) - w.WriteString(v) - w.Write(crlf) - } - } -} - -// writeHeader finalizes the header sent to the client and writes it -// to cw.res.conn.bufw. -// -// p is not written by writeHeader, but is the first chunk of the body -// that will be written. It is sniffed for a Content-Type if none is -// set explicitly. It's also used to set the Content-Length, if the -// total body size was small and the handler has already finished -// running. -func (cw *chunkWriter) writeHeader(p []byte) { - if cw.wroteHeader { - return - } - cw.wroteHeader = true - - w := cw.res - keepAlivesEnabled := w.conn.server.doKeepAlives() - isHEAD := w.req.Method == "HEAD" - - // header is written out to w.conn.buf below. Depending on the - // state of the handler, we either own the map or not. If we - // don't own it, the exclude map is created lazily for - // WriteSubset to remove headers. The setHeader struct holds - // headers we need to add. - header := cw.header - owned := header != nil - if !owned { - header = w.handlerHeader - } - var excludeHeader map[string]bool - delHeader := func(key string) { - if owned { - header.Del(key) - return - } - if _, ok := header[key]; !ok { - return - } - if excludeHeader == nil { - excludeHeader = make(map[string]bool) - } - excludeHeader[key] = true - } - var setHeader extraHeader - - // Don't write out the fake "Trailer:foo" keys. See TrailerPrefix. - trailers := false - for k := range cw.header { - if strings.HasPrefix(k, TrailerPrefix) { - if excludeHeader == nil { - excludeHeader = make(map[string]bool) - } - excludeHeader[k] = true - trailers = true - } - } - for _, v := range cw.header["Trailer"] { - trailers = true - foreachHeaderElement(v, cw.res.declareTrailer) - } - - te := header.get("Transfer-Encoding") - hasTE := te != "" - - // If the handler is done but never sent a Content-Length - // response header and this is our first (and last) write, set - // it, even to zero. This helps HTTP/1.0 clients keep their - // "keep-alive" connections alive. - // Exceptions: 304/204/1xx responses never get Content-Length, and if - // it was a HEAD request, we don't know the difference between - // 0 actual bytes and 0 bytes because the handler noticed it - // was a HEAD request and chose not to write anything. So for - // HEAD, the handler should either write the Content-Length or - // write non-zero bytes. If it's actually 0 bytes and the - // handler never looked at the Request.Method, we just don't - // send a Content-Length header. - // Further, we don't send an automatic Content-Length if they - // set a Transfer-Encoding, because they're generally incompatible. - if w.handlerDone.Load() && !trailers && !hasTE && bodyAllowedForStatus(w.status) && !header.has("Content-Length") && (!isHEAD || len(p) > 0) { - w.contentLength = int64(len(p)) - setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10) - } - - // If this was an HTTP/1.0 request with keep-alive and we sent a - // Content-Length back, we can make this a keep-alive response ... - if w.wants10KeepAlive && keepAlivesEnabled { - sentLength := header.get("Content-Length") != "" - if sentLength && header.get("Connection") == "keep-alive" { - w.closeAfterReply = false - } - } - - // Check for an explicit (and valid) Content-Length header. - hasCL := w.contentLength != -1 - - if w.wants10KeepAlive && (isHEAD || hasCL || !bodyAllowedForStatus(w.status)) { - _, connectionHeaderSet := header["Connection"] - if !connectionHeaderSet { - setHeader.connection = "keep-alive" - } - } else if !w.req.ProtoAtLeast(1, 1) || w.wantsClose { - w.closeAfterReply = true - } - - if header.get("Connection") == "close" || !keepAlivesEnabled { - w.closeAfterReply = true - } - - // If the client wanted a 100-continue but we never sent it to - // them (or, more strictly: we never finished reading their - // request body), don't reuse this connection. - // - // This behavior was first added on the theory that we don't know - // if the next bytes on the wire are going to be the remainder of - // the request body or the subsequent request (see issue 11549), - // but that's not correct: If we keep using the connection, - // the client is required to send the request body whether we - // asked for it or not. - // - // We probably do want to skip reusing the connection in most cases, - // however. If the client is offering a large request body that we - // don't intend to use, then it's better to close the connection - // than to read the body. For now, assume that if we're sending - // headers, the handler is done reading the body and we should - // drop the connection if we haven't seen EOF. - if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF.Load() { - w.closeAfterReply = true - } - - // We do this by default because there are a number of clients that - // send a full request before starting to read the response, and they - // can deadlock if we start writing the response with unconsumed body - // remaining. See Issue 15527 for some history. - // - // If full duplex mode has been enabled with ResponseController.EnableFullDuplex, - // then leave the request body alone. - if w.req.ContentLength != 0 && !w.closeAfterReply && !w.fullDuplex { - var discard, tooBig bool - - switch bdy := w.req.Body.(type) { - case *expectContinueReader: - if bdy.resp.wroteContinue { - discard = true - } - case *body: - bdy.mu.Lock() - switch { - case bdy.closed: - if !bdy.sawEOF { - // Body was closed in handler with non-EOF error. - w.closeAfterReply = true - } - case bdy.unreadDataSizeLocked() >= maxPostHandlerReadBytes: - tooBig = true - default: - discard = true - } - bdy.mu.Unlock() - default: - discard = true - } - - if discard { - _, err := io.CopyN(io.Discard, w.reqBody, maxPostHandlerReadBytes+1) - switch err { - case nil: - // There must be even more data left over. - tooBig = true - case ErrBodyReadAfterClose: - // Body was already consumed and closed. - case io.EOF: - // The remaining body was just consumed, close it. - err = w.reqBody.Close() - if err != nil { - w.closeAfterReply = true - } - default: - // Some other kind of error occurred, like a read timeout, or - // corrupt chunked encoding. In any case, whatever remains - // on the wire must not be parsed as another HTTP request. - w.closeAfterReply = true - } - } - - if tooBig { - w.requestTooLarge() - delHeader("Connection") - setHeader.connection = "close" - } - } - - code := w.status - if bodyAllowedForStatus(code) { - // If no content type, apply sniffing algorithm to body. - _, haveType := header["Content-Type"] - - // If the Content-Encoding was set and is non-blank, - // we shouldn't sniff the body. See Issue 31753. - ce := header.Get("Content-Encoding") - hasCE := len(ce) > 0 - if !hasCE && !haveType && !hasTE && len(p) > 0 { - setHeader.contentType = DetectContentType(p) - } - } else { - for _, k := range suppressedHeaders(code) { - delHeader(k) - } - } - - if !header.has("Date") { - setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now()) - } - - if hasCL && hasTE && te != "identity" { - // TODO: return an error if WriteHeader gets a return parameter - // For now just ignore the Content-Length. - w.conn.server.logf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d", - te, w.contentLength) - delHeader("Content-Length") - hasCL = false - } - - if w.req.Method == "HEAD" || !bodyAllowedForStatus(code) || code == StatusNoContent { - // Response has no body. - delHeader("Transfer-Encoding") - } else if hasCL { - // Content-Length has been provided, so no chunking is to be done. - delHeader("Transfer-Encoding") - } else if w.req.ProtoAtLeast(1, 1) { - // HTTP/1.1 or greater: Transfer-Encoding has been set to identity, and no - // content-length has been provided. The connection must be closed after the - // reply is written, and no chunking is to be done. This is the setup - // recommended in the Server-Sent Events candidate recommendation 11, - // section 8. - if hasTE && te == "identity" { - cw.chunking = false - w.closeAfterReply = true - delHeader("Transfer-Encoding") - } else { - // HTTP/1.1 or greater: use chunked transfer encoding - // to avoid closing the connection at EOF. - cw.chunking = true - setHeader.transferEncoding = "chunked" - if hasTE && te == "chunked" { - // We will send the chunked Transfer-Encoding header later. - delHeader("Transfer-Encoding") - } - } - } else { - // HTTP version < 1.1: cannot do chunked transfer - // encoding and we don't know the Content-Length so - // signal EOF by closing connection. - w.closeAfterReply = true - delHeader("Transfer-Encoding") // in case already set - } - - // Cannot use Content-Length with non-identity Transfer-Encoding. - if cw.chunking { - delHeader("Content-Length") - } - if !w.req.ProtoAtLeast(1, 0) { - return - } - - // Only override the Connection header if it is not a successful - // protocol switch response and if KeepAlives are not enabled. - // See https://golang.org/issue/36381. - delConnectionHeader := w.closeAfterReply && - (!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) && - !isProtocolSwitchResponse(w.status, header) - if delConnectionHeader { - delHeader("Connection") - if w.req.ProtoAtLeast(1, 1) { - setHeader.connection = "close" - } - } - - writeStatusLine(w.conn.bufw, w.req.ProtoAtLeast(1, 1), code, w.statusBuf[:]) - cw.header.WriteSubset(w.conn.bufw, excludeHeader) - setHeader.Write(w.conn.bufw) - w.conn.bufw.Write(crlf) -} - -// foreachHeaderElement splits v according to the "#rule" construction -// in RFC 7230 section 7 and calls fn for each non-empty element. -func foreachHeaderElement(v string, fn func(string)) { - v = textproto.TrimString(v) - if v == "" { - return - } - if !strings.Contains(v, ",") { - fn(v) - return - } - for _, f := range strings.Split(v, ",") { - if f = textproto.TrimString(f); f != "" { - fn(f) - } - } -} - -// writeStatusLine writes an HTTP/1.x Status-Line (RFC 7230 Section 3.1.2) -// to bw. is11 is whether the HTTP request is HTTP/1.1. false means HTTP/1.0. -// code is the response status code. -// scratch is an optional scratch buffer. If it has at least capacity 3, it's used. -func writeStatusLine(bw *bufio.Writer, is11 bool, code int, scratch []byte) { - if is11 { - bw.WriteString("HTTP/1.1 ") - } else { - bw.WriteString("HTTP/1.0 ") - } - if text := StatusText(code); text != "" { - bw.Write(strconv.AppendInt(scratch[:0], int64(code), 10)) - bw.WriteByte(' ') - bw.WriteString(text) - bw.WriteString("\r\n") - } else { - // don't worry about performance - fmt.Fprintf(bw, "%03d status code %d\r\n", code, code) - } -} - -// bodyAllowed reports whether a Write is allowed for this response type. -// It's illegal to call this before the header has been flushed. -func (w *response) bodyAllowed() bool { - if !w.wroteHeader { - panic("") - } - return bodyAllowedForStatus(w.status) -} - -// The Life Of A Write is like this: -// -// Handler starts. No header has been sent. The handler can either -// write a header, or just start writing. Writing before sending a header -// sends an implicitly empty 200 OK header. -// -// If the handler didn't declare a Content-Length up front, we either -// go into chunking mode or, if the handler finishes running before -// the chunking buffer size, we compute a Content-Length and send that -// in the header instead. -// -// Likewise, if the handler didn't set a Content-Type, we sniff that -// from the initial chunk of output. -// -// The Writers are wired together like: -// -// 1. *response (the ResponseWriter) -> -// 2. (*response).w, a [*bufio.Writer] of bufferBeforeChunkingSize bytes -> -// 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type) -// and which writes the chunk headers, if needed -> -// 4. conn.bufw, a *bufio.Writer of default (4kB) bytes, writing to -> -// 5. checkConnErrorWriter{c}, which notes any non-nil error on Write -// and populates c.werr with it if so, but otherwise writes to -> -// 6. the rwc, the [net.Conn]. -// -// TODO(bradfitz): short-circuit some of the buffering when the -// initial header contains both a Content-Type and Content-Length. -// Also short-circuit in (1) when the header's been sent and not in -// chunking mode, writing directly to (4) instead, if (2) has no -// buffered data. More generally, we could short-circuit from (1) to -// (3) even in chunking mode if the write size from (1) is over some -// threshold and nothing is in (2). The answer might be mostly making -// bufferBeforeChunkingSize smaller and having bufio's fast-paths deal -// with this instead. -func (w *response) Write(data []byte) (n int, err error) { - return w.write(len(data), data, "") -} - -func (w *response) WriteString(data string) (n int, err error) { - return w.write(len(data), nil, data) -} - -// either dataB or dataS is non-zero. -func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) { - if w.conn.hijacked() { - if lenData > 0 { - caller := relevantCaller() - w.conn.server.logf("http: response.Write on hijacked connection from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line) - } - return 0, ErrHijacked - } - - if w.canWriteContinue.Load() { - // Body reader wants to write 100 Continue but hasn't yet. - // Tell it not to. The store must be done while holding the lock - // because the lock makes sure that there is not an active write - // this very moment. - w.writeContinueMu.Lock() - w.canWriteContinue.Store(false) - w.writeContinueMu.Unlock() - } - - if !w.wroteHeader { - w.WriteHeader(StatusOK) - } - if lenData == 0 { - return 0, nil - } - if !w.bodyAllowed() { - return 0, ErrBodyNotAllowed - } - - w.written += int64(lenData) // ignoring errors, for errorKludge - if w.contentLength != -1 && w.written > w.contentLength { - return 0, ErrContentLength - } - if dataB != nil { - return w.w.Write(dataB) - } else { - return w.w.WriteString(dataS) - } -} - -func (w *response) finishRequest() { - w.handlerDone.Store(true) - - if !w.wroteHeader { - w.WriteHeader(StatusOK) - } - - w.w.Flush() - putBufioWriter(w.w) - w.cw.close() - w.conn.bufw.Flush() - - w.conn.r.abortPendingRead() - - // Close the body (regardless of w.closeAfterReply) so we can - // re-use its bufio.Reader later safely. - w.reqBody.Close() - - if w.req.MultipartForm != nil { - w.req.MultipartForm.RemoveAll() - } -} - -// shouldReuseConnection reports whether the underlying TCP connection can be reused. -// It must only be called after the handler is done executing. -func (w *response) shouldReuseConnection() bool { - if w.closeAfterReply { - // The request or something set while executing the - // handler indicated we shouldn't reuse this - // connection. - return false - } - - if w.req.Method != "HEAD" && w.contentLength != -1 && w.bodyAllowed() && w.contentLength != w.written { - // Did not write enough. Avoid getting out of sync. - return false - } - - // There was some error writing to the underlying connection - // during the request, so don't re-use this conn. - if w.conn.werr != nil { - return false - } - - if w.closedRequestBodyEarly() { - return false - } - - return true -} - -func (w *response) closedRequestBodyEarly() bool { - body, ok := w.req.Body.(*body) - return ok && body.didEarlyClose() -} - -func (w *response) Flush() { - w.FlushError() -} - -func (w *response) FlushError() error { - if !w.wroteHeader { - w.WriteHeader(StatusOK) - } - err := w.w.Flush() - e2 := w.cw.flush() - if err == nil { - err = e2 - } - return err -} - -func (c *conn) finalFlush() { - if c.bufr != nil { - // Steal the bufio.Reader (~4KB worth of memory) and its associated - // reader for a future connection. - putBufioReader(c.bufr) - c.bufr = nil - } - - if c.bufw != nil { - c.bufw.Flush() - // Steal the bufio.Writer (~4KB worth of memory) and its associated - // writer for a future connection. - putBufioWriter(c.bufw) - c.bufw = nil - } -} - -// Close the connection. -func (c *conn) close() { - c.finalFlush() - c.rwc.Close() -} - -// rstAvoidanceDelay is the amount of time we sleep after closing the -// write side of a TCP connection before closing the entire socket. -// By sleeping, we increase the chances that the client sees our FIN -// and processes its final data before they process the subsequent RST -// from closing a connection with known unread data. -// This RST seems to occur mostly on BSD systems. (And Windows?) -// This timeout is somewhat arbitrary (~latency around the planet), -// and may be modified by tests. -// -// TODO(bcmills): This should arguably be a server configuration parameter, -// not a hard-coded value. -var rstAvoidanceDelay = 500 * time.Millisecond - -type closeWriter interface { - CloseWrite() error -} - -var _ closeWriter = (*net.TCPConn)(nil) - -// closeWriteAndWait flushes any outstanding data and sends a FIN packet (if -// client is connected via TCP), signaling that we're done. We then -// pause for a bit, hoping the client processes it before any -// subsequent RST. -// -// See https://golang.org/issue/3595 -func (c *conn) closeWriteAndWait() { - c.finalFlush() - if tcp, ok := c.rwc.(closeWriter); ok { - tcp.CloseWrite() - } - - // When we return from closeWriteAndWait, the caller will fully close the - // connection. If client is still writing to the connection, this will cause - // the write to fail with ECONNRESET or similar. Unfortunately, many TCP - // implementations will also drop unread packets from the client's read buffer - // when a write fails, causing our final response to be truncated away too. - // - // As a result, https://www.rfc-editor.org/rfc/rfc7230#section-6.6 recommends - // that “[t]he server … continues to read from the connection until it - // receives a corresponding close by the client, or until the server is - // reasonably certain that its own TCP stack has received the client's - // acknowledgement of the packet(s) containing the server's last response.” - // - // Unfortunately, we have no straightforward way to be “reasonably certain” - // that we have received the client's ACK, and at any rate we don't want to - // allow a misbehaving client to soak up server connections indefinitely by - // withholding an ACK, nor do we want to go through the complexity or overhead - // of using low-level APIs to figure out when a TCP round-trip has completed. - // - // Instead, we declare that we are “reasonably certain” that we received the - // ACK if maxRSTAvoidanceDelay has elapsed. - time.Sleep(rstAvoidanceDelay) -} - -// validNextProto reports whether the proto is a valid ALPN protocol name. -// Everything is valid except the empty string and built-in protocol types, -// so that those can't be overridden with alternate implementations. -func validNextProto(proto string) bool { - switch proto { - case "", "http/1.1", "http/1.0": - return false - } - return true -} - -const ( - runHooks = true - skipHooks = false -) - -func (c *conn) setState(nc net.Conn, state ConnState, runHook bool) { - srv := c.server - switch state { - case StateNew: - srv.trackConn(c, true) - case StateHijacked, StateClosed: - srv.trackConn(c, false) - } - if state > 0xff || state < 0 { - panic("internal error") - } - packedState := uint64(time.Now().Unix()<<8) | uint64(state) - c.curState.Store(packedState) - if !runHook { - return - } - if hook := srv.ConnState; hook != nil { - hook(nc, state) - } -} - -func (c *conn) getState() (state ConnState, unixSec int64) { - packedState := c.curState.Load() - return ConnState(packedState & 0xff), int64(packedState >> 8) -} - -// badRequestError is a literal string (used by in the server in HTML, -// unescaped) to tell the user why their request was bad. It should -// be plain text without user info or other embedded errors. -func badRequestError(e string) error { return statusError{StatusBadRequest, e} } - -// statusError is an error used to respond to a request with an HTTP status. -// The text should be plain text without user info or other embedded errors. -type statusError struct { - code int - text string -} - -func (e statusError) Error() string { return StatusText(e.code) + ": " + e.text } - -// ErrAbortHandler is a sentinel panic value to abort a handler. -// While any panic from ServeHTTP aborts the response to the client, -// panicking with ErrAbortHandler also suppresses logging of a stack -// trace to the server's error log. -var ErrAbortHandler = errors.New("net/http: abort Handler") - -// isCommonNetReadError reports whether err is a common error -// encountered during reading a request off the network when the -// client has gone away or had its read fail somehow. This is used to -// determine which logs are interesting enough to log about. -func isCommonNetReadError(err error) bool { - if err == io.EOF { - return true - } - if neterr, ok := err.(net.Error); ok && neterr.Timeout() { - return true - } - if oe, ok := err.(*net.OpError); ok && oe.Op == "read" { - return true - } - return false -} - -// Serve a new connection. -func (c *conn) serve(ctx context.Context) { - if ra := c.rwc.RemoteAddr(); ra != nil { - c.remoteAddr = ra.String() - } - ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr()) - var inFlightResponse *response - defer func() { - if err := recover(); err != nil && err != ErrAbortHandler { - const size = 64 << 10 - buf := make([]byte, size) - buf = buf[:runtime.Stack(buf, false)] - c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf) - } - if inFlightResponse != nil { - inFlightResponse.cancelCtx() - } - if !c.hijacked() { - if inFlightResponse != nil { - inFlightResponse.conn.r.abortPendingRead() - inFlightResponse.reqBody.Close() - } - c.close() - c.setState(c.rwc, StateClosed, runHooks) - } - }() - - if tlsConn, ok := c.rwc.(*tls.Conn); ok { - tlsTO := c.server.tlsHandshakeTimeout() - if tlsTO > 0 { - dl := time.Now().Add(tlsTO) - c.rwc.SetReadDeadline(dl) - c.rwc.SetWriteDeadline(dl) - } - if err := tlsConn.HandshakeContext(ctx); err != nil { - // If the handshake failed due to the client not speaking - // TLS, assume they're speaking plaintext HTTP and write a - // 400 response on the TLS conn's underlying net.Conn. - if re, ok := err.(tls.RecordHeaderError); ok && re.Conn != nil && tlsRecordHeaderLooksLikeHTTP(re.RecordHeader) { - io.WriteString(re.Conn, "HTTP/1.0 400 Bad Request\r\n\r\nClient sent an HTTP request to an HTTPS server.\n") - re.Conn.Close() - return - } - c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err) - return - } - // Restore Conn-level deadlines. - if tlsTO > 0 { - c.rwc.SetReadDeadline(time.Time{}) - c.rwc.SetWriteDeadline(time.Time{}) - } - c.tlsState = new(tls.ConnectionState) - *c.tlsState = tlsConn.ConnectionState() - if proto := c.tlsState.NegotiatedProtocol; validNextProto(proto) { - if fn := c.server.TLSNextProto[proto]; fn != nil { - h := initALPNRequest{ctx, tlsConn, serverHandler{c.server}} - // Mark freshly created HTTP/2 as active and prevent any server state hooks - // from being run on these connections. This prevents closeIdleConns from - // closing such connections. See issue https://golang.org/issue/39776. - c.setState(c.rwc, StateActive, skipHooks) - fn(c.server, tlsConn, h) - } - return - } - } - - // HTTP/1.x from here on. - - ctx, cancelCtx := context.WithCancel(ctx) - c.cancelCtx = cancelCtx - defer cancelCtx() - - c.r = &connReader{conn: c} - c.bufr = newBufioReader(c.r) - c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) - - for { - w, err := c.readRequest(ctx) - if c.r.remain != c.server.initialReadLimitSize() { - // If we read any bytes off the wire, we're active. - c.setState(c.rwc, StateActive, runHooks) - } - if err != nil { - const errorHeaders = "\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: close\r\n\r\n" - - switch { - case err == errTooLarge: - // Their HTTP client may or may not be - // able to read this if we're - // responding to them and hanging up - // while they're still writing their - // request. Undefined behavior. - const publicErr = "431 Request Header Fields Too Large" - fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr) - c.closeWriteAndWait() - return - - case isUnsupportedTEError(err): - // Respond as per RFC 7230 Section 3.3.1 which says, - // A server that receives a request message with a - // transfer coding it does not understand SHOULD - // respond with 501 (Unimplemented). - code := StatusNotImplemented - - // We purposefully aren't echoing back the transfer-encoding's value, - // so as to mitigate the risk of cross side scripting by an attacker. - fmt.Fprintf(c.rwc, "HTTP/1.1 %d %s%sUnsupported transfer encoding", code, StatusText(code), errorHeaders) - return - - case isCommonNetReadError(err): - return // don't reply - - default: - if v, ok := err.(statusError); ok { - fmt.Fprintf(c.rwc, "HTTP/1.1 %d %s: %s%s%d %s: %s", v.code, StatusText(v.code), v.text, errorHeaders, v.code, StatusText(v.code), v.text) - return - } - const publicErr = "400 Bad Request" - fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr) - return - } - } - - // Expect 100 Continue support - req := w.req - if req.expectsContinue() { - if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 { - // Wrap the Body reader with one that replies on the connection - req.Body = &expectContinueReader{readCloser: req.Body, resp: w} - w.canWriteContinue.Store(true) - } - } else if req.Header.get("Expect") != "" { - w.sendExpectationFailed() - return - } - - c.curReq.Store(w) - - if requestBodyRemains(req.Body) { - registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead) - } else { - w.conn.r.startBackgroundRead() - } - - // HTTP cannot have multiple simultaneous active requests.[*] - // Until the server replies to this request, it can't read another, - // so we might as well run the handler in this goroutine. - // [*] Not strictly true: HTTP pipelining. We could let them all process - // in parallel even if their responses need to be serialized. - // But we're not going to implement HTTP pipelining because it - // was never deployed in the wild and the answer is HTTP/2. - inFlightResponse = w - serverHandler{c.server}.ServeHTTP(w, w.req) - inFlightResponse = nil - w.cancelCtx() - if c.hijacked() { - return - } - w.finishRequest() - c.rwc.SetWriteDeadline(time.Time{}) - if !w.shouldReuseConnection() { - if w.requestBodyLimitHit || w.closedRequestBodyEarly() { - c.closeWriteAndWait() - } - return - } - c.setState(c.rwc, StateIdle, runHooks) - c.curReq.Store(nil) - - if !w.conn.server.doKeepAlives() { - // We're in shutdown mode. We might've replied - // to the user without "Connection: close" and - // they might think they can send another - // request, but such is life with HTTP/1.1. - return - } - - if d := c.server.idleTimeout(); d != 0 { - c.rwc.SetReadDeadline(time.Now().Add(d)) - } else { - c.rwc.SetReadDeadline(time.Time{}) - } - - // Wait for the connection to become readable again before trying to - // read the next request. This prevents a ReadHeaderTimeout or - // ReadTimeout from starting until the first bytes of the next request - // have been received. - if _, err := c.bufr.Peek(4); err != nil { - return - } - - c.rwc.SetReadDeadline(time.Time{}) - } -} - -func (w *response) sendExpectationFailed() { - // TODO(bradfitz): let ServeHTTP handlers handle - // requests with non-standard expectation[s]? Seems - // theoretical at best, and doesn't fit into the - // current ServeHTTP model anyway. We'd need to - // make the ResponseWriter an optional - // "ExpectReplier" interface or something. - // - // For now we'll just obey RFC 7231 5.1.1 which says - // "A server that receives an Expect field-value other - // than 100-continue MAY respond with a 417 (Expectation - // Failed) status code to indicate that the unexpected - // expectation cannot be met." - w.Header().Set("Connection", "close") - w.WriteHeader(StatusExpectationFailed) - w.finishRequest() -} - -// Hijack implements the [Hijacker.Hijack] method. Our response is both a [ResponseWriter] -// and a [Hijacker]. -func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) { - if w.handlerDone.Load() { - panic("net/http: Hijack called after ServeHTTP finished") - } - if w.wroteHeader { - w.cw.flush() - } - - c := w.conn - c.mu.Lock() - defer c.mu.Unlock() - - // Release the bufioWriter that writes to the chunk writer, it is not - // used after a connection has been hijacked. - rwc, buf, err = c.hijackLocked() - if err == nil { - putBufioWriter(w.w) - w.w = nil - } - return rwc, buf, err -} - -func (w *response) CloseNotify() <-chan bool { - if w.handlerDone.Load() { - panic("net/http: CloseNotify called after ServeHTTP finished") - } - return w.closeNotifyCh -} - -func registerOnHitEOF(rc io.ReadCloser, fn func()) { - switch v := rc.(type) { - case *expectContinueReader: - registerOnHitEOF(v.readCloser, fn) - case *body: - v.registerOnHitEOF(fn) - default: - panic("unexpected type " + fmt.Sprintf("%T", rc)) - } -} - -// requestBodyRemains reports whether future calls to Read -// on rc might yield more data. -func requestBodyRemains(rc io.ReadCloser) bool { - if rc == NoBody { - return false - } - switch v := rc.(type) { - case *expectContinueReader: - return requestBodyRemains(v.readCloser) - case *body: - return v.bodyRemains() - default: - panic("unexpected type " + fmt.Sprintf("%T", rc)) - } -} - -// The HandlerFunc type is an adapter to allow the use of -// ordinary functions as HTTP handlers. If f is a function -// with the appropriate signature, HandlerFunc(f) is a -// [Handler] that calls f. -type HandlerFunc func(ResponseWriter, *Request) - -// ServeHTTP calls f(w, r). -func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { - f(w, r) -} - -// Helper handlers - -// Error replies to the request with the specified error message and HTTP code. -// It does not otherwise end the request; the caller should ensure no further -// writes are done to w. -// The error message should be plain text. -func Error(w ResponseWriter, error string, code int) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("X-Content-Type-Options", "nosniff") - w.WriteHeader(code) - fmt.Fprintln(w, error) -} - -// NotFound replies to the request with an HTTP 404 not found error. -func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) } - -// NotFoundHandler returns a simple request handler -// that replies to each request with a “404 page not found” reply. -func NotFoundHandler() Handler { return HandlerFunc(NotFound) } - -// StripPrefix returns a handler that serves HTTP requests by removing the -// given prefix from the request URL's Path (and RawPath if set) and invoking -// the handler h. StripPrefix handles a request for a path that doesn't begin -// with prefix by replying with an HTTP 404 not found error. The prefix must -// match exactly: if the prefix in the request contains escaped characters -// the reply is also an HTTP 404 not found error. -func StripPrefix(prefix string, h Handler) Handler { - if prefix == "" { - return h - } - return HandlerFunc(func(w ResponseWriter, r *Request) { - p := strings.TrimPrefix(r.URL.Path, prefix) - rp := strings.TrimPrefix(r.URL.RawPath, prefix) - if len(p) < len(r.URL.Path) && (r.URL.RawPath == "" || len(rp) < len(r.URL.RawPath)) { - r2 := new(Request) - *r2 = *r - r2.URL = new(url.URL) - *r2.URL = *r.URL - r2.URL.Path = p - r2.URL.RawPath = rp - h.ServeHTTP(w, r2) - } else { - NotFound(w, r) - } - }) -} - -// Redirect replies to the request with a redirect to url, -// which may be a path relative to the request path. -// -// The provided code should be in the 3xx range and is usually -// [StatusMovedPermanently], [StatusFound] or [StatusSeeOther]. -// -// If the Content-Type header has not been set, [Redirect] sets it -// to "text/html; charset=utf-8" and writes a small HTML body. -// Setting the Content-Type header to any value, including nil, -// disables that behavior. -func Redirect(w ResponseWriter, r *Request, url string, code int) { - if u, err := urlpkg.Parse(url); err == nil { - // If url was relative, make its path absolute by - // combining with request path. - // The client would probably do this for us, - // but doing it ourselves is more reliable. - // See RFC 7231, section 7.1.2 - if u.Scheme == "" && u.Host == "" { - oldpath := r.URL.Path - if oldpath == "" { // should not happen, but avoid a crash if it does - oldpath = "/" - } - - // no leading http://server - if url == "" || url[0] != '/' { - // make relative path absolute - olddir, _ := path.Split(oldpath) - url = olddir + url - } - - var query string - if i := strings.Index(url, "?"); i != -1 { - url, query = url[:i], url[i:] - } - - // clean up but preserve trailing slash - trailing := strings.HasSuffix(url, "/") - url = path.Clean(url) - if trailing && !strings.HasSuffix(url, "/") { - url += "/" - } - url += query - } - } - - h := w.Header() - - // RFC 7231 notes that a short HTML body is usually included in - // the response because older user agents may not understand 301/307. - // Do it only if the request didn't already have a Content-Type header. - _, hadCT := h["Content-Type"] - - h.Set("Location", hexEscapeNonASCII(url)) - if !hadCT && (r.Method == "GET" || r.Method == "HEAD") { - h.Set("Content-Type", "text/html; charset=utf-8") - } - w.WriteHeader(code) - - // Shouldn't send the body for POST or HEAD; that leaves GET. - if !hadCT && r.Method == "GET" { - body := "" + StatusText(code) + ".\n" - fmt.Fprintln(w, body) - } -} - -var htmlReplacer = strings.NewReplacer( - "&", "&", - "<", "<", - ">", ">", - // """ is shorter than """. - `"`, """, - // "'" is shorter than "'" and apos was not in HTML until HTML5. - "'", "'", -) - -func htmlEscape(s string) string { - return htmlReplacer.Replace(s) -} - -// Redirect to a fixed URL -type redirectHandler struct { - url string - code int -} - -func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) { - Redirect(w, r, rh.url, rh.code) -} - -// RedirectHandler returns a request handler that redirects -// each request it receives to the given url using the given -// status code. -// -// The provided code should be in the 3xx range and is usually -// [StatusMovedPermanently], [StatusFound] or [StatusSeeOther]. -func RedirectHandler(url string, code int) Handler { - return &redirectHandler{url, code} -} - -// ServeMux is an HTTP request multiplexer. -// It matches the URL of each incoming request against a list of registered -// patterns and calls the handler for the pattern that -// most closely matches the URL. -// -// # Patterns -// -// Patterns can match the method, host and path of a request. -// Some examples: -// -// - "/index.html" matches the path "/index.html" for any host and method. -// - "GET /static/" matches a GET request whose path begins with "/static/". -// - "example.com/" matches any request to the host "example.com". -// - "example.com/{$}" matches requests with host "example.com" and path "/". -// - "/b/{bucket}/o/{objectname...}" matches paths whose first segment is "b" -// and whose third segment is "o". The name "bucket" denotes the second -// segment and "objectname" denotes the remainder of the path. -// -// In general, a pattern looks like -// -// [METHOD ][HOST]/[PATH] -// -// All three parts are optional; "/" is a valid pattern. -// If METHOD is present, it must be followed by a single space. -// -// Literal (that is, non-wildcard) parts of a pattern match -// the corresponding parts of a request case-sensitively. -// -// A pattern with no method matches every method. A pattern -// with the method GET matches both GET and HEAD requests. -// Otherwise, the method must match exactly. -// -// A pattern with no host matches every host. -// A pattern with a host matches URLs on that host only. -// -// A path can include wildcard segments of the form {NAME} or {NAME...}. -// For example, "/b/{bucket}/o/{objectname...}". -// The wildcard name must be a valid Go identifier. -// Wildcards must be full path segments: they must be preceded by a slash and followed by -// either a slash or the end of the string. -// For example, "/b_{bucket}" is not a valid pattern. -// -// Normally a wildcard matches only a single path segment, -// ending at the next literal slash (not %2F) in the request URL. -// But if the "..." is present, then the wildcard matches the remainder of the URL path, including slashes. -// (Therefore it is invalid for a "..." wildcard to appear anywhere but at the end of a pattern.) -// The match for a wildcard can be obtained by calling [Request.PathValue] with the wildcard's name. -// A trailing slash in a path acts as an anonymous "..." wildcard. -// -// The special wildcard {$} matches only the end of the URL. -// For example, the pattern "/{$}" matches only the path "/", -// whereas the pattern "/" matches every path. -// -// For matching, both pattern paths and incoming request paths are unescaped segment by segment. -// So, for example, the path "/a%2Fb/100%25" is treated as having two segments, "a/b" and "100%". -// The pattern "/a%2fb/" matches it, but the pattern "/a/b/" does not. -// -// # Precedence -// -// If two or more patterns match a request, then the most specific pattern takes precedence. -// A pattern P1 is more specific than P2 if P1 matches a strict subset of P2’s requests; -// that is, if P2 matches all the requests of P1 and more. -// If neither is more specific, then the patterns conflict. -// There is one exception to this rule, for backwards compatibility: -// if two patterns would otherwise conflict and one has a host while the other does not, -// then the pattern with the host takes precedence. -// If a pattern passed [ServeMux.Handle] or [ServeMux.HandleFunc] conflicts with -// another pattern that is already registered, those functions panic. -// -// As an example of the general rule, "/images/thumbnails/" is more specific than "/images/", -// so both can be registered. -// The former matches paths beginning with "/images/thumbnails/" -// and the latter will match any other path in the "/images/" subtree. -// -// As another example, consider the patterns "GET /" and "/index.html": -// both match a GET request for "/index.html", but the former pattern -// matches all other GET and HEAD requests, while the latter matches any -// request for "/index.html" that uses a different method. -// The patterns conflict. -// -// # Trailing-slash redirection -// -// Consider a [ServeMux] with a handler for a subtree, registered using a trailing slash or "..." wildcard. -// If the ServeMux receives a request for the subtree root without a trailing slash, -// it redirects the request by adding the trailing slash. -// This behavior can be overridden with a separate registration for the path without -// the trailing slash or "..." wildcard. For example, registering "/images/" causes ServeMux -// to redirect a request for "/images" to "/images/", unless "/images" has -// been registered separately. -// -// # Request sanitizing -// -// ServeMux also takes care of sanitizing the URL request path and the Host -// header, stripping the port number and redirecting any request containing . or -// .. segments or repeated slashes to an equivalent, cleaner URL. -// -// # Compatibility -// -// The pattern syntax and matching behavior of ServeMux changed significantly -// in Go 1.22. To restore the old behavior, set the GODEBUG environment variable -// to "httpmuxgo121=1". This setting is read once, at program startup; changes -// during execution will be ignored. -// -// The backwards-incompatible changes include: -// - Wildcards are just ordinary literal path segments in 1.21. -// For example, the pattern "/{x}" will match only that path in 1.21, -// but will match any one-segment path in 1.22. -// - In 1.21, no pattern was rejected, unless it was empty or conflicted with an existing pattern. -// In 1.22, syntactically invalid patterns will cause [ServeMux.Handle] and [ServeMux.HandleFunc] to panic. -// For example, in 1.21, the patterns "/{" and "/a{x}" match themselves, -// but in 1.22 they are invalid and will cause a panic when registered. -// - In 1.22, each segment of a pattern is unescaped; this was not done in 1.21. -// For example, in 1.22 the pattern "/%61" matches the path "/a" ("%61" being the URL escape sequence for "a"), -// but in 1.21 it would match only the path "/%2561" (where "%25" is the escape for the percent sign). -// - When matching patterns to paths, in 1.22 each segment of the path is unescaped; in 1.21, the entire path is unescaped. -// This change mostly affects how paths with %2F escapes adjacent to slashes are treated. -// See https://go.dev/issue/21955 for details. -type ServeMux struct { - mu sync.RWMutex - tree routingNode - index routingIndex - patterns []*pattern // TODO(jba): remove if possible - mux121 serveMux121 // used only when GODEBUG=httpmuxgo121=1 -} - -// NewServeMux allocates and returns a new [ServeMux]. -func NewServeMux() *ServeMux { - return &ServeMux{} -} - -// DefaultServeMux is the default [ServeMux] used by [Serve]. -var DefaultServeMux = &defaultServeMux - -var defaultServeMux ServeMux - -// cleanPath returns the canonical path for p, eliminating . and .. elements. -func cleanPath(p string) string { - if p == "" { - return "/" - } - if p[0] != '/' { - p = "/" + p - } - np := path.Clean(p) - // path.Clean removes trailing slash except for root; - // put the trailing slash back if necessary. - if p[len(p)-1] == '/' && np != "/" { - // Fast path for common case of p being the string we want: - if len(p) == len(np)+1 && strings.HasPrefix(p, np) { - np = p - } else { - np += "/" - } - } - return np -} - -// stripHostPort returns h without any trailing ":". -func stripHostPort(h string) string { - // If no port on host, return unchanged - if !strings.Contains(h, ":") { - return h - } - host, _, err := net.SplitHostPort(h) - if err != nil { - return h // on error, return unchanged - } - return host -} - -// Handler returns the handler to use for the given request, -// consulting r.Method, r.Host, and r.URL.Path. It always returns -// a non-nil handler. If the path is not in its canonical form, the -// handler will be an internally-generated handler that redirects -// to the canonical path. If the host contains a port, it is ignored -// when matching handlers. -// -// The path and host are used unchanged for CONNECT requests. -// -// Handler also returns the registered pattern that matches the -// request or, in the case of internally-generated redirects, -// the path that will match after following the redirect. -// -// If there is no registered handler that applies to the request, -// Handler returns a “page not found” handler and an empty pattern. -func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { - if use121 { - return mux.mux121.findHandler(r) - } - h, p, _, _ := mux.findHandler(r) - return h, p -} - -// findHandler finds a handler for a request. -// If there is a matching handler, it returns it and the pattern that matched. -// Otherwise it returns a Redirect or NotFound handler with the path that would match -// after the redirect. -func (mux *ServeMux) findHandler(r *Request) (h Handler, patStr string, _ *pattern, matches []string) { - var n *routingNode - host := r.URL.Host - escapedPath := r.URL.EscapedPath() - path := escapedPath - // CONNECT requests are not canonicalized. - if r.Method == "CONNECT" { - // If r.URL.Path is /tree and its handler is not registered, - // the /tree -> /tree/ redirect applies to CONNECT requests - // but the path canonicalization does not. - _, _, u := mux.matchOrRedirect(host, r.Method, path, r.URL) - if u != nil { - return RedirectHandler(u.String(), StatusMovedPermanently), u.Path, nil, nil - } - // Redo the match, this time with r.Host instead of r.URL.Host. - // Pass a nil URL to skip the trailing-slash redirect logic. - n, matches, _ = mux.matchOrRedirect(r.Host, r.Method, path, nil) - } else { - // All other requests have any port stripped and path cleaned - // before passing to mux.handler. - host = stripHostPort(r.Host) - path = cleanPath(path) - - // If the given path is /tree and its handler is not registered, - // redirect for /tree/. - var u *url.URL - n, matches, u = mux.matchOrRedirect(host, r.Method, path, r.URL) - if u != nil { - return RedirectHandler(u.String(), StatusMovedPermanently), u.Path, nil, nil - } - if path != escapedPath { - // Redirect to cleaned path. - patStr := "" - if n != nil { - patStr = n.pattern.String() - } - u := &url.URL{Path: path, RawQuery: r.URL.RawQuery} - return RedirectHandler(u.String(), StatusMovedPermanently), patStr, nil, nil - } - } - if n == nil { - // We didn't find a match with the request method. To distinguish between - // Not Found and Method Not Allowed, see if there is another pattern that - // matches except for the method. - allowedMethods := mux.matchingMethods(host, path) - if len(allowedMethods) > 0 { - return HandlerFunc(func(w ResponseWriter, r *Request) { - w.Header().Set("Allow", strings.Join(allowedMethods, ", ")) - Error(w, StatusText(StatusMethodNotAllowed), StatusMethodNotAllowed) - }), "", nil, nil - } - return NotFoundHandler(), "", nil, nil - } - return n.handler, n.pattern.String(), n.pattern, matches -} - -// matchOrRedirect looks up a node in the tree that matches the host, method and path. -// -// If the url argument is non-nil, handler also deals with trailing-slash -// redirection: when a path doesn't match exactly, the match is tried again -// after appending "/" to the path. If that second match succeeds, the last -// return value is the URL to redirect to. -func (mux *ServeMux) matchOrRedirect(host, method, path string, u *url.URL) (_ *routingNode, matches []string, redirectTo *url.URL) { - mux.mu.RLock() - defer mux.mu.RUnlock() - - n, matches := mux.tree.match(host, method, path) - // If we have an exact match, or we were asked not to try trailing-slash redirection, - // then we're done. - if !exactMatch(n, path) && u != nil { - // If there is an exact match with a trailing slash, then redirect. - path += "/" - n2, _ := mux.tree.match(host, method, path) - if exactMatch(n2, path) { - return nil, nil, &url.URL{Path: cleanPath(u.Path) + "/", RawQuery: u.RawQuery} - } - } - return n, matches, nil -} - -// exactMatch reports whether the node's pattern exactly matches the path. -// As a special case, if the node is nil, exactMatch return false. -// -// Before wildcards were introduced, it was clear that an exact match meant -// that the pattern and path were the same string. The only other possibility -// was that a trailing-slash pattern, like "/", matched a path longer than -// it, like "/a". -// -// With wildcards, we define an inexact match as any one where a multi wildcard -// matches a non-empty string. All other matches are exact. -// For example, these are all exact matches: -// -// pattern path -// /a /a -// /{x} /a -// /a/{$} /a/ -// /a/ /a/ -// -// The last case has a multi wildcard (implicitly), but the match is exact because -// the wildcard matches the empty string. -// -// Examples of matches that are not exact: -// -// pattern path -// / /a -// /a/{x...} /a/b -func exactMatch(n *routingNode, path string) bool { - if n == nil { - return false - } - // We can't directly implement the definition (empty match for multi - // wildcard) because we don't record a match for anonymous multis. - - // If there is no multi, the match is exact. - if !n.pattern.lastSegment().multi { - return true - } - - // If the path doesn't end in a trailing slash, then the multi match - // is non-empty. - if len(path) > 0 && path[len(path)-1] != '/' { - return false - } - // Only patterns ending in {$} or a multi wildcard can - // match a path with a trailing slash. - // For the match to be exact, the number of pattern - // segments should be the same as the number of slashes in the path. - // E.g. "/a/b/{$}" and "/a/b/{...}" exactly match "/a/b/", but "/a/" does not. - return len(n.pattern.segments) == strings.Count(path, "/") -} - -// matchingMethods return a sorted list of all methods that would match with the given host and path. -func (mux *ServeMux) matchingMethods(host, path string) []string { - // Hold the read lock for the entire method so that the two matches are done - // on the same set of registered patterns. - mux.mu.RLock() - defer mux.mu.RUnlock() - ms := map[string]bool{} - mux.tree.matchingMethods(host, path, ms) - // matchOrRedirect will try appending a trailing slash if there is no match. - mux.tree.matchingMethods(host, path+"/", ms) - methods := mapKeys(ms) - sort.Strings(methods) - return methods -} - -// TODO(jba): replace with maps.Keys when it is defined. -func mapKeys[K comparable, V any](m map[K]V) []K { - var ks []K - for k := range m { - ks = append(ks, k) - } - return ks -} - -// ServeHTTP dispatches the request to the handler whose -// pattern most closely matches the request URL. -func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { - if r.RequestURI == "*" { - if r.ProtoAtLeast(1, 1) { - w.Header().Set("Connection", "close") - } - w.WriteHeader(StatusBadRequest) - return - } - var h Handler - if use121 { - h, _ = mux.mux121.findHandler(r) - } else { - h, _, r.pat, r.matches = mux.findHandler(r) - } - h.ServeHTTP(w, r) -} - -// The four functions below all call ServeMux.register so that callerLocation -// always refers to user code. - -// Handle registers the handler for the given pattern. -// If the given pattern conflicts, with one that is already registered, Handle -// panics. -func (mux *ServeMux) Handle(pattern string, handler Handler) { - if use121 { - mux.mux121.handle(pattern, handler) - } else { - mux.register(pattern, handler) - } -} - -// HandleFunc registers the handler function for the given pattern. -// If the given pattern conflicts, with one that is already registered, HandleFunc -// panics. -func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { - if use121 { - mux.mux121.handleFunc(pattern, handler) - } else { - mux.register(pattern, HandlerFunc(handler)) - } -} - -// Handle registers the handler for the given pattern in [DefaultServeMux]. -// The documentation for [ServeMux] explains how patterns are matched. -func Handle(pattern string, handler Handler) { - if use121 { - DefaultServeMux.mux121.handle(pattern, handler) - } else { - DefaultServeMux.register(pattern, handler) - } -} - -// HandleFunc registers the handler function for the given pattern in [DefaultServeMux]. -// The documentation for [ServeMux] explains how patterns are matched. -func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { - if use121 { - DefaultServeMux.mux121.handleFunc(pattern, handler) - } else { - DefaultServeMux.register(pattern, HandlerFunc(handler)) - } -} - -func (mux *ServeMux) register(pattern string, handler Handler) { - if err := mux.registerErr(pattern, handler); err != nil { - panic(err) - } -} - -func (mux *ServeMux) registerErr(patstr string, handler Handler) error { - if patstr == "" { - return errors.New("http: invalid pattern") - } - if handler == nil { - return errors.New("http: nil handler") - } - if f, ok := handler.(HandlerFunc); ok && f == nil { - return errors.New("http: nil handler") - } - - pat, err := parsePattern(patstr) - if err != nil { - return fmt.Errorf("parsing %q: %w", patstr, err) - } - - // Get the caller's location, for better conflict error messages. - // Skip register and whatever calls it. - _, file, line, ok := runtime.Caller(3) - if !ok { - pat.loc = "unknown location" - } else { - pat.loc = fmt.Sprintf("%s:%d", file, line) - } - - mux.mu.Lock() - defer mux.mu.Unlock() - // Check for conflict. - if err := mux.index.possiblyConflictingPatterns(pat, func(pat2 *pattern) error { - if pat.conflictsWith(pat2) { - d := describeConflict(pat, pat2) - return fmt.Errorf("pattern %q (registered at %s) conflicts with pattern %q (registered at %s):\n%s", - pat, pat.loc, pat2, pat2.loc, d) - } - return nil - }); err != nil { - return err - } - mux.tree.addPattern(pat, handler) - mux.index.addPattern(pat) - mux.patterns = append(mux.patterns, pat) - return nil -} - -// Serve accepts incoming HTTP connections on the listener l, -// creating a new service goroutine for each. The service goroutines -// read requests and then call handler to reply to them. -// -// The handler is typically nil, in which case [DefaultServeMux] is used. -// -// HTTP/2 support is only enabled if the Listener returns [*tls.Conn] -// connections and they were configured with "h2" in the TLS -// Config.NextProtos. -// -// Serve always returns a non-nil error. -func Serve(l net.Listener, handler Handler) error { - srv := &Server{Handler: handler} - return srv.Serve(l) -} - -// ServeTLS accepts incoming HTTPS connections on the listener l, -// creating a new service goroutine for each. The service goroutines -// read requests and then call handler to reply to them. -// -// The handler is typically nil, in which case [DefaultServeMux] is used. -// -// Additionally, files containing a certificate and matching private key -// for the server must be provided. If the certificate is signed by a -// certificate authority, the certFile should be the concatenation -// of the server's certificate, any intermediates, and the CA's certificate. -// -// ServeTLS always returns a non-nil error. -func ServeTLS(l net.Listener, handler Handler, certFile, keyFile string) error { - srv := &Server{Handler: handler} - return srv.ServeTLS(l, certFile, keyFile) -} - -// A Server defines parameters for running an HTTP server. -// The zero value for Server is a valid configuration. -type Server struct { - // Addr optionally specifies the TCP address for the server to listen on, - // in the form "host:port". If empty, ":http" (port 80) is used. - // The service names are defined in RFC 6335 and assigned by IANA. - // See net.Dial for details of the address format. - Addr string - - Handler Handler // handler to invoke, http.DefaultServeMux if nil - - // DisableGeneralOptionsHandler, if true, passes "OPTIONS *" requests to the Handler, - // otherwise responds with 200 OK and Content-Length: 0. - DisableGeneralOptionsHandler bool - - // TLSConfig optionally provides a TLS configuration for use - // by ServeTLS and ListenAndServeTLS. Note that this value is - // cloned by ServeTLS and ListenAndServeTLS, so it's not - // possible to modify the configuration with methods like - // tls.Config.SetSessionTicketKeys. To use - // SetSessionTicketKeys, use Server.Serve with a TLS Listener - // instead. - TLSConfig *tls.Config - - // ReadTimeout is the maximum duration for reading the entire - // request, including the body. A zero or negative value means - // there will be no timeout. - // - // Because ReadTimeout does not let Handlers make per-request - // decisions on each request body's acceptable deadline or - // upload rate, most users will prefer to use - // ReadHeaderTimeout. It is valid to use them both. - ReadTimeout time.Duration - - // ReadHeaderTimeout is the amount of time allowed to read - // request headers. The connection's read deadline is reset - // after reading the headers and the Handler can decide what - // is considered too slow for the body. If ReadHeaderTimeout - // is zero, the value of ReadTimeout is used. If both are - // zero, there is no timeout. - ReadHeaderTimeout time.Duration - - // WriteTimeout is the maximum duration before timing out - // writes of the response. It is reset whenever a new - // request's header is read. Like ReadTimeout, it does not - // let Handlers make decisions on a per-request basis. - // A zero or negative value means there will be no timeout. - WriteTimeout time.Duration - - // IdleTimeout is the maximum amount of time to wait for the - // next request when keep-alives are enabled. If IdleTimeout - // is zero, the value of ReadTimeout is used. If both are - // zero, there is no timeout. - IdleTimeout time.Duration - - // MaxHeaderBytes controls the maximum number of bytes the - // server will read parsing the request header's keys and - // values, including the request line. It does not limit the - // size of the request body. - // If zero, DefaultMaxHeaderBytes is used. - MaxHeaderBytes int - - // TLSNextProto optionally specifies a function to take over - // ownership of the provided TLS connection when an ALPN - // protocol upgrade has occurred. The map key is the protocol - // name negotiated. The Handler argument should be used to - // handle HTTP requests and will initialize the Request's TLS - // and RemoteAddr if not already set. The connection is - // automatically closed when the function returns. - // If TLSNextProto is not nil, HTTP/2 support is not enabled - // automatically. - TLSNextProto map[string]func(*Server, *tls.Conn, Handler) - - // ConnState specifies an optional callback function that is - // called when a client connection changes state. See the - // ConnState type and associated constants for details. - ConnState func(net.Conn, ConnState) - - // ErrorLog specifies an optional logger for errors accepting - // connections, unexpected behavior from handlers, and - // underlying FileSystem errors. - // If nil, logging is done via the log package's standard logger. - ErrorLog *log.Logger - - // BaseContext optionally specifies a function that returns - // the base context for incoming requests on this server. - // The provided Listener is the specific Listener that's - // about to start accepting requests. - // If BaseContext is nil, the default is context.Background(). - // If non-nil, it must return a non-nil context. - BaseContext func(net.Listener) context.Context - - // ConnContext optionally specifies a function that modifies - // the context used for a new connection c. The provided ctx - // is derived from the base context and has a ServerContextKey - // value. - ConnContext func(ctx context.Context, c net.Conn) context.Context - - inShutdown atomic.Bool // true when server is in shutdown - - disableKeepAlives atomic.Bool - nextProtoOnce sync.Once // guards setupHTTP2_* init - nextProtoErr error // result of http2.ConfigureServer if used - - mu sync.Mutex - listeners map[*net.Listener]struct{} - activeConn map[*conn]struct{} - onShutdown []func() - - listenerGroup sync.WaitGroup -} - -// Close immediately closes all active net.Listeners and any -// connections in state [StateNew], [StateActive], or [StateIdle]. For a -// graceful shutdown, use [Server.Shutdown]. -// -// Close does not attempt to close (and does not even know about) -// any hijacked connections, such as WebSockets. -// -// Close returns any error returned from closing the [Server]'s -// underlying Listener(s). -func (srv *Server) Close() error { - srv.inShutdown.Store(true) - srv.mu.Lock() - defer srv.mu.Unlock() - err := srv.closeListenersLocked() - - // Unlock srv.mu while waiting for listenerGroup. - // The group Add and Done calls are made with srv.mu held, - // to avoid adding a new listener in the window between - // us setting inShutdown above and waiting here. - srv.mu.Unlock() - srv.listenerGroup.Wait() - srv.mu.Lock() - - for c := range srv.activeConn { - c.rwc.Close() - delete(srv.activeConn, c) - } - return err -} - -// shutdownPollIntervalMax is the max polling interval when checking -// quiescence during Server.Shutdown. Polling starts with a small -// interval and backs off to the max. -// Ideally we could find a solution that doesn't involve polling, -// but which also doesn't have a high runtime cost (and doesn't -// involve any contentious mutexes), but that is left as an -// exercise for the reader. -const shutdownPollIntervalMax = 500 * time.Millisecond - -// Shutdown gracefully shuts down the server without interrupting any -// active connections. Shutdown works by first closing all open -// listeners, then closing all idle connections, and then waiting -// indefinitely for connections to return to idle and then shut down. -// If the provided context expires before the shutdown is complete, -// Shutdown returns the context's error, otherwise it returns any -// error returned from closing the [Server]'s underlying Listener(s). -// -// When Shutdown is called, [Serve], [ListenAndServe], and -// [ListenAndServeTLS] immediately return [ErrServerClosed]. Make sure the -// program doesn't exit and waits instead for Shutdown to return. -// -// Shutdown does not attempt to close nor wait for hijacked -// connections such as WebSockets. The caller of Shutdown should -// separately notify such long-lived connections of shutdown and wait -// for them to close, if desired. See [Server.RegisterOnShutdown] for a way to -// register shutdown notification functions. -// -// Once Shutdown has been called on a server, it may not be reused; -// future calls to methods such as Serve will return ErrServerClosed. -func (srv *Server) Shutdown(ctx context.Context) error { - srv.inShutdown.Store(true) - - srv.mu.Lock() - lnerr := srv.closeListenersLocked() - for _, f := range srv.onShutdown { - go f() - } - srv.mu.Unlock() - srv.listenerGroup.Wait() - - pollIntervalBase := time.Millisecond - nextPollInterval := func() time.Duration { - // Add 10% jitter. - interval := pollIntervalBase + time.Duration(rand.Intn(int(pollIntervalBase/10))) - // Double and clamp for next time. - pollIntervalBase *= 2 - if pollIntervalBase > shutdownPollIntervalMax { - pollIntervalBase = shutdownPollIntervalMax - } - return interval - } - - timer := time.NewTimer(nextPollInterval()) - defer timer.Stop() - for { - if srv.closeIdleConns() { - return lnerr - } - select { - case <-ctx.Done(): - return ctx.Err() - case <-timer.C: - timer.Reset(nextPollInterval()) - } - } -} - -// RegisterOnShutdown registers a function to call on [Server.Shutdown]. -// This can be used to gracefully shutdown connections that have -// undergone ALPN protocol upgrade or that have been hijacked. -// This function should start protocol-specific graceful shutdown, -// but should not wait for shutdown to complete. -func (srv *Server) RegisterOnShutdown(f func()) { - srv.mu.Lock() - srv.onShutdown = append(srv.onShutdown, f) - srv.mu.Unlock() -} - -// closeIdleConns closes all idle connections and reports whether the -// server is quiescent. -func (s *Server) closeIdleConns() bool { - s.mu.Lock() - defer s.mu.Unlock() - quiescent := true - for c := range s.activeConn { - st, unixSec := c.getState() - // Issue 22682: treat StateNew connections as if - // they're idle if we haven't read the first request's - // header in over 5 seconds. - if st == StateNew && unixSec < time.Now().Unix()-5 { - st = StateIdle - } - if st != StateIdle || unixSec == 0 { - // Assume unixSec == 0 means it's a very new - // connection, without state set yet. - quiescent = false - continue - } - c.rwc.Close() - delete(s.activeConn, c) - } - return quiescent -} - -func (s *Server) closeListenersLocked() error { - var err error - for ln := range s.listeners { - if cerr := (*ln).Close(); cerr != nil && err == nil { - err = cerr - } - } - return err -} - -// A ConnState represents the state of a client connection to a server. -// It's used by the optional [Server.ConnState] hook. -type ConnState int - -const ( - // StateNew represents a new connection that is expected to - // send a request immediately. Connections begin at this - // state and then transition to either StateActive or - // StateClosed. - StateNew ConnState = iota - - // StateActive represents a connection that has read 1 or more - // bytes of a request. The Server.ConnState hook for - // StateActive fires before the request has entered a handler - // and doesn't fire again until the request has been - // handled. After the request is handled, the state - // transitions to StateClosed, StateHijacked, or StateIdle. - // For HTTP/2, StateActive fires on the transition from zero - // to one active request, and only transitions away once all - // active requests are complete. That means that ConnState - // cannot be used to do per-request work; ConnState only notes - // the overall state of the connection. - StateActive - - // StateIdle represents a connection that has finished - // handling a request and is in the keep-alive state, waiting - // for a new request. Connections transition from StateIdle - // to either StateActive or StateClosed. - StateIdle - - // StateHijacked represents a hijacked connection. - // This is a terminal state. It does not transition to StateClosed. - StateHijacked - - // StateClosed represents a closed connection. - // This is a terminal state. Hijacked connections do not - // transition to StateClosed. - StateClosed -) - -var stateName = map[ConnState]string{ - StateNew: "new", - StateActive: "active", - StateIdle: "idle", - StateHijacked: "hijacked", - StateClosed: "closed", -} - -func (c ConnState) String() string { - return stateName[c] -} - -// serverHandler delegates to either the server's Handler or -// DefaultServeMux and also handles "OPTIONS *" requests. -type serverHandler struct { - srv *Server -} - -func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { - handler := sh.srv.Handler - if handler == nil { - handler = DefaultServeMux - } - if !sh.srv.DisableGeneralOptionsHandler && req.RequestURI == "*" && req.Method == "OPTIONS" { - handler = globalOptionsHandler{} - } - - handler.ServeHTTP(rw, req) -} - -// AllowQuerySemicolons returns a handler that serves requests by converting any -// unescaped semicolons in the URL query to ampersands, and invoking the handler h. -// -// This restores the pre-Go 1.17 behavior of splitting query parameters on both -// semicolons and ampersands. (See golang.org/issue/25192). Note that this -// behavior doesn't match that of many proxies, and the mismatch can lead to -// security issues. -// -// AllowQuerySemicolons should be invoked before [Request.ParseForm] is called. -func AllowQuerySemicolons(h Handler) Handler { - return HandlerFunc(func(w ResponseWriter, r *Request) { - if strings.Contains(r.URL.RawQuery, ";") { - r2 := new(Request) - *r2 = *r - r2.URL = new(url.URL) - *r2.URL = *r.URL - r2.URL.RawQuery = strings.ReplaceAll(r.URL.RawQuery, ";", "&") - h.ServeHTTP(w, r2) - } else { - h.ServeHTTP(w, r) - } - }) -} - -// ListenAndServe listens on the TCP network address srv.Addr and then -// calls [Serve] to handle requests on incoming connections. -// Accepted connections are configured to enable TCP keep-alives. -// -// If srv.Addr is blank, ":http" is used. -// -// ListenAndServe always returns a non-nil error. After [Server.Shutdown] or [Server.Close], -// the returned error is [ErrServerClosed]. -func (srv *Server) ListenAndServe() error { - if srv.shuttingDown() { - return ErrServerClosed - } - addr := srv.Addr - if addr == "" { - addr = ":http" - } - ln, err := net.Listen("tcp", addr) - if err != nil { - return err - } - return srv.Serve(ln) -} - -var testHookServerServe func(*Server, net.Listener) // used if non-nil - -// shouldConfigureHTTP2ForServe reports whether Server.Serve should configure -// automatic HTTP/2. (which sets up the srv.TLSNextProto map) -func (srv *Server) shouldConfigureHTTP2ForServe() bool { - if srv.TLSConfig == nil { - // Compatibility with Go 1.6: - // If there's no TLSConfig, it's possible that the user just - // didn't set it on the http.Server, but did pass it to - // tls.NewListener and passed that listener to Serve. - // So we should configure HTTP/2 (to set up srv.TLSNextProto) - // in case the listener returns an "h2" *tls.Conn. - return true - } - // The user specified a TLSConfig on their http.Server. - // In this, case, only configure HTTP/2 if their tls.Config - // explicitly mentions "h2". Otherwise http2.ConfigureServer - // would modify the tls.Config to add it, but they probably already - // passed this tls.Config to tls.NewListener. And if they did, - // it's too late anyway to fix it. It would only be potentially racy. - // See Issue 15908. - return strSliceContains(srv.TLSConfig.NextProtos, http2NextProtoTLS) -} - -// ErrServerClosed is returned by the [Server.Serve], [ServeTLS], [ListenAndServe], -// and [ListenAndServeTLS] methods after a call to [Server.Shutdown] or [Server.Close]. -var ErrServerClosed = errors.New("http: Server closed") - -// Serve accepts incoming connections on the Listener l, creating a -// new service goroutine for each. The service goroutines read requests and -// then call srv.Handler to reply to them. -// -// HTTP/2 support is only enabled if the Listener returns [*tls.Conn] -// connections and they were configured with "h2" in the TLS -// Config.NextProtos. -// -// Serve always returns a non-nil error and closes l. -// After [Server.Shutdown] or [Server.Close], the returned error is [ErrServerClosed]. -func (srv *Server) Serve(l net.Listener) error { - if fn := testHookServerServe; fn != nil { - fn(srv, l) // call hook with unwrapped listener - } - - origListener := l - l = &onceCloseListener{Listener: l} - defer l.Close() - - if err := srv.setupHTTP2_Serve(); err != nil { - return err - } - - if !srv.trackListener(&l, true) { - return ErrServerClosed - } - defer srv.trackListener(&l, false) - - baseCtx := context.Background() - if srv.BaseContext != nil { - baseCtx = srv.BaseContext(origListener) - if baseCtx == nil { - panic("BaseContext returned a nil context") - } - } - - var tempDelay time.Duration // how long to sleep on accept failure - - ctx := context.WithValue(baseCtx, ServerContextKey, srv) - for { - rw, err := l.Accept() - if err != nil { - if srv.shuttingDown() { - return ErrServerClosed - } - if ne, ok := err.(net.Error); ok && ne.Temporary() { - if tempDelay == 0 { - tempDelay = 5 * time.Millisecond - } else { - tempDelay *= 2 - } - if max := 1 * time.Second; tempDelay > max { - tempDelay = max - } - srv.logf("http: Accept error: %v; retrying in %v", err, tempDelay) - time.Sleep(tempDelay) - continue - } - return err - } - connCtx := ctx - if cc := srv.ConnContext; cc != nil { - connCtx = cc(connCtx, rw) - if connCtx == nil { - panic("ConnContext returned nil") - } - } - tempDelay = 0 - c := srv.newConn(rw) - c.setState(c.rwc, StateNew, runHooks) // before Serve can return - go c.serve(connCtx) - } -} - -// ServeTLS accepts incoming connections on the Listener l, creating a -// new service goroutine for each. The service goroutines perform TLS -// setup and then read requests, calling srv.Handler to reply to them. -// -// Files containing a certificate and matching private key for the -// server must be provided if neither the [Server]'s -// TLSConfig.Certificates nor TLSConfig.GetCertificate are populated. -// If the certificate is signed by a certificate authority, the -// certFile should be the concatenation of the server's certificate, -// any intermediates, and the CA's certificate. -// -// ServeTLS always returns a non-nil error. After [Server.Shutdown] or [Server.Close], the -// returned error is [ErrServerClosed]. -func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error { - // Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig - // before we clone it and create the TLS Listener. - if err := srv.setupHTTP2_ServeTLS(); err != nil { - return err - } - - config := cloneTLSConfig(srv.TLSConfig) - if !strSliceContains(config.NextProtos, "http/1.1") { - config.NextProtos = append(config.NextProtos, "http/1.1") - } - - configHasCert := len(config.Certificates) > 0 || config.GetCertificate != nil - if !configHasCert || certFile != "" || keyFile != "" { - var err error - config.Certificates = make([]tls.Certificate, 1) - config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) - if err != nil { - return err - } - } - - tlsListener := tls.NewListener(l, config) - return srv.Serve(tlsListener) -} - -// trackListener adds or removes a net.Listener to the set of tracked -// listeners. -// -// We store a pointer to interface in the map set, in case the -// net.Listener is not comparable. This is safe because we only call -// trackListener via Serve and can track+defer untrack the same -// pointer to local variable there. We never need to compare a -// Listener from another caller. -// -// It reports whether the server is still up (not Shutdown or Closed). -func (s *Server) trackListener(ln *net.Listener, add bool) bool { - s.mu.Lock() - defer s.mu.Unlock() - if s.listeners == nil { - s.listeners = make(map[*net.Listener]struct{}) - } - if add { - if s.shuttingDown() { - return false - } - s.listeners[ln] = struct{}{} - s.listenerGroup.Add(1) - } else { - delete(s.listeners, ln) - s.listenerGroup.Done() - } - return true -} - -func (s *Server) trackConn(c *conn, add bool) { - s.mu.Lock() - defer s.mu.Unlock() - if s.activeConn == nil { - s.activeConn = make(map[*conn]struct{}) - } - if add { - s.activeConn[c] = struct{}{} - } else { - delete(s.activeConn, c) - } -} - -func (s *Server) idleTimeout() time.Duration { - if s.IdleTimeout != 0 { - return s.IdleTimeout - } - return s.ReadTimeout -} - -func (s *Server) readHeaderTimeout() time.Duration { - if s.ReadHeaderTimeout != 0 { - return s.ReadHeaderTimeout - } - return s.ReadTimeout -} - -func (s *Server) doKeepAlives() bool { - return !s.disableKeepAlives.Load() && !s.shuttingDown() -} - -func (s *Server) shuttingDown() bool { - return s.inShutdown.Load() -} - -// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled. -// By default, keep-alives are always enabled. Only very -// resource-constrained environments or servers in the process of -// shutting down should disable them. -func (srv *Server) SetKeepAlivesEnabled(v bool) { - if v { - srv.disableKeepAlives.Store(false) - return - } - srv.disableKeepAlives.Store(true) - - // Close idle HTTP/1 conns: - srv.closeIdleConns() - - // TODO: Issue 26303: close HTTP/2 conns as soon as they become idle. -} - -func (s *Server) logf(format string, args ...any) { - if s.ErrorLog != nil { - s.ErrorLog.Printf(format, args...) - } else { - log.Printf(format, args...) - } -} - -// logf prints to the ErrorLog of the *Server associated with request r -// via ServerContextKey. If there's no associated server, or if ErrorLog -// is nil, logging is done via the log package's standard logger. -func logf(r *Request, format string, args ...any) { - s, _ := r.Context().Value(ServerContextKey).(*Server) - if s != nil && s.ErrorLog != nil { - s.ErrorLog.Printf(format, args...) - } else { - log.Printf(format, args...) - } -} - -// ListenAndServe listens on the TCP network address addr and then calls -// [Serve] with handler to handle requests on incoming connections. -// Accepted connections are configured to enable TCP keep-alives. -// -// The handler is typically nil, in which case [DefaultServeMux] is used. -// -// ListenAndServe always returns a non-nil error. -func ListenAndServe(addr string, handler Handler) error { - server := &Server{Addr: addr, Handler: handler} - return server.ListenAndServe() -} - -// ListenAndServeTLS acts identically to [ListenAndServe], except that it -// expects HTTPS connections. Additionally, files containing a certificate and -// matching private key for the server must be provided. If the certificate -// is signed by a certificate authority, the certFile should be the concatenation -// of the server's certificate, any intermediates, and the CA's certificate. -func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error { - server := &Server{Addr: addr, Handler: handler} - return server.ListenAndServeTLS(certFile, keyFile) -} - -// ListenAndServeTLS listens on the TCP network address srv.Addr and -// then calls [ServeTLS] to handle requests on incoming TLS connections. -// Accepted connections are configured to enable TCP keep-alives. -// -// Filenames containing a certificate and matching private key for the -// server must be provided if neither the [Server]'s TLSConfig.Certificates -// nor TLSConfig.GetCertificate are populated. If the certificate is -// signed by a certificate authority, the certFile should be the -// concatenation of the server's certificate, any intermediates, and -// the CA's certificate. -// -// If srv.Addr is blank, ":https" is used. -// -// ListenAndServeTLS always returns a non-nil error. After [Server.Shutdown] or -// [Server.Close], the returned error is [ErrServerClosed]. -func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { - if srv.shuttingDown() { - return ErrServerClosed - } - addr := srv.Addr - if addr == "" { - addr = ":https" - } - - ln, err := net.Listen("tcp", addr) - if err != nil { - return err - } - - defer ln.Close() - - return srv.ServeTLS(ln, certFile, keyFile) -} - -// setupHTTP2_ServeTLS conditionally configures HTTP/2 on -// srv and reports whether there was an error setting it up. If it is -// not configured for policy reasons, nil is returned. -func (srv *Server) setupHTTP2_ServeTLS() error { - srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults) - return srv.nextProtoErr -} - -// setupHTTP2_Serve is called from (*Server).Serve and conditionally -// configures HTTP/2 on srv using a more conservative policy than -// setupHTTP2_ServeTLS because Serve is called after tls.Listen, -// and may be called concurrently. See shouldConfigureHTTP2ForServe. -// -// The tests named TestTransportAutomaticHTTP2* and -// TestConcurrentServerServe in server_test.go demonstrate some -// of the supported use cases and motivations. -func (srv *Server) setupHTTP2_Serve() error { - srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults_Serve) - return srv.nextProtoErr -} - -func (srv *Server) onceSetNextProtoDefaults_Serve() { - if srv.shouldConfigureHTTP2ForServe() { - srv.onceSetNextProtoDefaults() - } -} - -var http2server = godebug.New("http2server") - -// onceSetNextProtoDefaults configures HTTP/2, if the user hasn't -// configured otherwise. (by setting srv.TLSNextProto non-nil) -// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2_*). -func (srv *Server) onceSetNextProtoDefaults() { - if omitBundledHTTP2 { - return - } - if http2server.Value() == "0" { - http2server.IncNonDefault() - return - } - // Enable HTTP/2 by default if the user hasn't otherwise - // configured their TLSNextProto map. - if srv.TLSNextProto == nil { - conf := &http2Server{ - NewWriteScheduler: func() http2WriteScheduler { return http2NewPriorityWriteScheduler(nil) }, - } - srv.nextProtoErr = http2ConfigureServer(srv, conf) - } -} - -// TimeoutHandler returns a [Handler] that runs h with the given time limit. -// -// The new Handler calls h.ServeHTTP to handle each request, but if a -// call runs for longer than its time limit, the handler responds with -// a 503 Service Unavailable error and the given message in its body. -// (If msg is empty, a suitable default message will be sent.) -// After such a timeout, writes by h to its [ResponseWriter] will return -// [ErrHandlerTimeout]. -// -// TimeoutHandler supports the [Pusher] interface but does not support -// the [Hijacker] or [Flusher] interfaces. -func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler { - return &timeoutHandler{ - handler: h, - body: msg, - dt: dt, - } -} - -// ErrHandlerTimeout is returned on [ResponseWriter] Write calls -// in handlers which have timed out. -var ErrHandlerTimeout = errors.New("http: Handler timeout") - -type timeoutHandler struct { - handler Handler - body string - dt time.Duration - - // When set, no context will be created and this context will - // be used instead. - testContext context.Context -} - -func (h *timeoutHandler) errorBody() string { - if h.body != "" { - return h.body - } - return "Timeout

Timeout

" -} - -func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { - ctx := h.testContext - if ctx == nil { - var cancelCtx context.CancelFunc - ctx, cancelCtx = context.WithTimeout(r.Context(), h.dt) - defer cancelCtx() - } - r = r.WithContext(ctx) - done := make(chan struct{}) - tw := &timeoutWriter{ - w: w, - h: make(Header), - req: r, - } - panicChan := make(chan any, 1) - go func() { - defer func() { - if p := recover(); p != nil { - panicChan <- p - } - }() - h.handler.ServeHTTP(tw, r) - close(done) - }() - select { - case p := <-panicChan: - panic(p) - case <-done: - tw.mu.Lock() - defer tw.mu.Unlock() - dst := w.Header() - for k, vv := range tw.h { - dst[k] = vv - } - if !tw.wroteHeader { - tw.code = StatusOK - } - w.WriteHeader(tw.code) - w.Write(tw.wbuf.Bytes()) - case <-ctx.Done(): - tw.mu.Lock() - defer tw.mu.Unlock() - switch err := ctx.Err(); err { - case context.DeadlineExceeded: - w.WriteHeader(StatusServiceUnavailable) - io.WriteString(w, h.errorBody()) - tw.err = ErrHandlerTimeout - default: - w.WriteHeader(StatusServiceUnavailable) - tw.err = err - } - } -} - -type timeoutWriter struct { - w ResponseWriter - h Header - wbuf bytes.Buffer - req *Request - - mu sync.Mutex - err error - wroteHeader bool - code int -} - -var _ Pusher = (*timeoutWriter)(nil) - -// Push implements the [Pusher] interface. -func (tw *timeoutWriter) Push(target string, opts *PushOptions) error { - if pusher, ok := tw.w.(Pusher); ok { - return pusher.Push(target, opts) - } - return ErrNotSupported -} - -func (tw *timeoutWriter) Header() Header { return tw.h } - -func (tw *timeoutWriter) Write(p []byte) (int, error) { - tw.mu.Lock() - defer tw.mu.Unlock() - if tw.err != nil { - return 0, tw.err - } - if !tw.wroteHeader { - tw.writeHeaderLocked(StatusOK) - } - return tw.wbuf.Write(p) -} - -func (tw *timeoutWriter) writeHeaderLocked(code int) { - checkWriteHeaderCode(code) - - switch { - case tw.err != nil: - return - case tw.wroteHeader: - if tw.req != nil { - caller := relevantCaller() - logf(tw.req, "http: superfluous response.WriteHeader call from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line) - } - default: - tw.wroteHeader = true - tw.code = code - } -} - -func (tw *timeoutWriter) WriteHeader(code int) { - tw.mu.Lock() - defer tw.mu.Unlock() - tw.writeHeaderLocked(code) -} - -// onceCloseListener wraps a net.Listener, protecting it from -// multiple Close calls. -type onceCloseListener struct { - net.Listener - once sync.Once - closeErr error -} - -func (oc *onceCloseListener) Close() error { - oc.once.Do(oc.close) - return oc.closeErr -} - -func (oc *onceCloseListener) close() { oc.closeErr = oc.Listener.Close() } - -// globalOptionsHandler responds to "OPTIONS *" requests. -type globalOptionsHandler struct{} - -func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) { - w.Header().Set("Content-Length", "0") - if r.ContentLength != 0 { - // Read up to 4KB of OPTIONS body (as mentioned in the - // spec as being reserved for future use), but anything - // over that is considered a waste of server resources - // (or an attack) and we abort and close the connection, - // courtesy of MaxBytesReader's EOF behavior. - mb := MaxBytesReader(w, r.Body, 4<<10) - io.Copy(io.Discard, mb) - } -} - -// initALPNRequest is an HTTP handler that initializes certain -// uninitialized fields in its *Request. Such partially-initialized -// Requests come from ALPN protocol handlers. -type initALPNRequest struct { - ctx context.Context - c *tls.Conn - h serverHandler -} - -// BaseContext is an exported but unadvertised [http.Handler] method -// recognized by x/net/http2 to pass down a context; the TLSNextProto -// API predates context support so we shoehorn through the only -// interface we have available. -func (h initALPNRequest) BaseContext() context.Context { return h.ctx } - -func (h initALPNRequest) ServeHTTP(rw ResponseWriter, req *Request) { - if req.TLS == nil { - req.TLS = &tls.ConnectionState{} - *req.TLS = h.c.ConnectionState() - } - if req.Body == nil { - req.Body = NoBody - } - if req.RemoteAddr == "" { - req.RemoteAddr = h.c.RemoteAddr().String() - } - h.h.ServeHTTP(rw, req) -} - -// loggingConn is used for debugging. -type loggingConn struct { - name string - net.Conn -} - -var ( - uniqNameMu sync.Mutex - uniqNameNext = make(map[string]int) -) - -func newLoggingConn(baseName string, c net.Conn) net.Conn { - uniqNameMu.Lock() - defer uniqNameMu.Unlock() - uniqNameNext[baseName]++ - return &loggingConn{ - name: fmt.Sprintf("%s-%d", baseName, uniqNameNext[baseName]), - Conn: c, - } -} - -func (c *loggingConn) Write(p []byte) (n int, err error) { - log.Printf("%s.Write(%d) = ....", c.name, len(p)) - n, err = c.Conn.Write(p) - log.Printf("%s.Write(%d) = %d, %v", c.name, len(p), n, err) - return -} - -func (c *loggingConn) Read(p []byte) (n int, err error) { - log.Printf("%s.Read(%d) = ....", c.name, len(p)) - n, err = c.Conn.Read(p) - log.Printf("%s.Read(%d) = %d, %v", c.name, len(p), n, err) - return -} - -func (c *loggingConn) Close() (err error) { - log.Printf("%s.Close() = ...", c.name) - err = c.Conn.Close() - log.Printf("%s.Close() = %v", c.name, err) - return -} - -// checkConnErrorWriter writes to c.rwc and records any write errors to c.werr. -// It only contains one field (and a pointer field at that), so it -// fits in an interface value without an extra allocation. -type checkConnErrorWriter struct { - c *conn -} - -func (w checkConnErrorWriter) Write(p []byte) (n int, err error) { - n, err = w.c.rwc.Write(p) - if err != nil && w.c.werr == nil { - w.c.werr = err - w.c.cancelCtx() - } - return -} - -func numLeadingCRorLF(v []byte) (n int) { - for _, b := range v { - if b == '\r' || b == '\n' { - n++ - continue - } - break - } - return -} - -func strSliceContains(ss []string, s string) bool { - for _, v := range ss { - if v == s { - return true - } - } - return false -} - -// tlsRecordHeaderLooksLikeHTTP reports whether a TLS record header -// looks like it might've been a misdirected plaintext HTTP request. -func tlsRecordHeaderLooksLikeHTTP(hdr [5]byte) bool { - switch string(hdr[:]) { - case "GET /", "HEAD ", "POST ", "PUT /", "OPTIO": - return true - } - return false -} - -// MaxBytesHandler returns a [Handler] that runs h with its [ResponseWriter] and [Request.Body] wrapped by a MaxBytesReader. -func MaxBytesHandler(h Handler, n int64) Handler { - return HandlerFunc(func(w ResponseWriter, r *Request) { - r2 := *r - r2.Body = MaxBytesReader(w, r.Body, n) - h.ServeHTTP(w, &r2) - }) -} diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/ya.make b/contrib/go/_std_1.22/src/net/internal/socktest/ya.make deleted file mode 100644 index b83fe4f8d545..000000000000 --- a/contrib/go/_std_1.22/src/net/internal/socktest/ya.make +++ /dev/null @@ -1,27 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - switch.go - switch_posix.go - switch_unix.go - sys_unix.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - switch.go - switch_posix.go - switch_unix.go - sys_cloexec.go - sys_unix.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - switch.go - switch_posix.go - switch_windows.go - sys_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/net/lookup.go b/contrib/go/_std_1.22/src/net/lookup.go deleted file mode 100644 index 3ec266078609..000000000000 --- a/contrib/go/_std_1.22/src/net/lookup.go +++ /dev/null @@ -1,920 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "context" - "errors" - "internal/nettrace" - "internal/singleflight" - "net/netip" - "sync" - - "golang.org/x/net/dns/dnsmessage" -) - -// protocols contains minimal mappings between internet protocol -// names and numbers for platforms that don't have a complete list of -// protocol numbers. -// -// See https://www.iana.org/assignments/protocol-numbers -// -// On Unix, this map is augmented by readProtocols via lookupProtocol. -var protocols = map[string]int{ - "icmp": 1, - "igmp": 2, - "tcp": 6, - "udp": 17, - "ipv6-icmp": 58, -} - -// services contains minimal mappings between services names and port -// numbers for platforms that don't have a complete list of port numbers. -// -// See https://www.iana.org/assignments/service-names-port-numbers -// -// On Unix, this map is augmented by readServices via goLookupPort. -var services = map[string]map[string]int{ - "udp": { - "domain": 53, - }, - "tcp": { - "ftp": 21, - "ftps": 990, - "gopher": 70, // ʕ◔ϖ◔ʔ - "http": 80, - "https": 443, - "imap2": 143, - "imap3": 220, - "imaps": 993, - "pop3": 110, - "pop3s": 995, - "smtp": 25, - "submissions": 465, - "ssh": 22, - "telnet": 23, - }, -} - -// dnsWaitGroup can be used by tests to wait for all DNS goroutines to -// complete. This avoids races on the test hooks. -var dnsWaitGroup sync.WaitGroup - -const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow - -func lookupProtocolMap(name string) (int, error) { - var lowerProtocol [maxProtoLength]byte - n := copy(lowerProtocol[:], name) - lowerASCIIBytes(lowerProtocol[:n]) - proto, found := protocols[string(lowerProtocol[:n])] - if !found || n != len(name) { - return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name} - } - return proto, nil -} - -// maxPortBufSize is the longest reasonable name of a service -// (non-numeric port). -// Currently the longest known IANA-unregistered name is -// "mobility-header", so we use that length, plus some slop in case -// something longer is added in the future. -const maxPortBufSize = len("mobility-header") + 10 - -func lookupPortMap(network, service string) (port int, error error) { - switch network { - case "ip": // no hints - if p, err := lookupPortMapWithNetwork("tcp", "ip", service); err == nil { - return p, nil - } - return lookupPortMapWithNetwork("udp", "ip", service) - case "tcp", "tcp4", "tcp6": - return lookupPortMapWithNetwork("tcp", "tcp", service) - case "udp", "udp4", "udp6": - return lookupPortMapWithNetwork("udp", "udp", service) - } - return 0, &DNSError{Err: "unknown network", Name: network + "/" + service} -} - -func lookupPortMapWithNetwork(network, errNetwork, service string) (port int, error error) { - if m, ok := services[network]; ok { - var lowerService [maxPortBufSize]byte - n := copy(lowerService[:], service) - lowerASCIIBytes(lowerService[:n]) - if port, ok := m[string(lowerService[:n])]; ok && n == len(service) { - return port, nil - } - return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true} - } - return 0, &DNSError{Err: "unknown network", Name: errNetwork + "/" + service} -} - -// ipVersion returns the provided network's IP version: '4', '6' or 0 -// if network does not end in a '4' or '6' byte. -func ipVersion(network string) byte { - if network == "" { - return 0 - } - n := network[len(network)-1] - if n != '4' && n != '6' { - n = 0 - } - return n -} - -// DefaultResolver is the resolver used by the package-level Lookup -// functions and by Dialers without a specified Resolver. -var DefaultResolver = &Resolver{} - -// A Resolver looks up names and numbers. -// -// A nil *Resolver is equivalent to a zero Resolver. -type Resolver struct { - // PreferGo controls whether Go's built-in DNS resolver is preferred - // on platforms where it's available. It is equivalent to setting - // GODEBUG=netdns=go, but scoped to just this resolver. - PreferGo bool - - // StrictErrors controls the behavior of temporary errors - // (including timeout, socket errors, and SERVFAIL) when using - // Go's built-in resolver. For a query composed of multiple - // sub-queries (such as an A+AAAA address lookup, or walking the - // DNS search list), this option causes such errors to abort the - // whole query instead of returning a partial result. This is - // not enabled by default because it may affect compatibility - // with resolvers that process AAAA queries incorrectly. - StrictErrors bool - - // Dial optionally specifies an alternate dialer for use by - // Go's built-in DNS resolver to make TCP and UDP connections - // to DNS services. The host in the address parameter will - // always be a literal IP address and not a host name, and the - // port in the address parameter will be a literal port number - // and not a service name. - // If the Conn returned is also a PacketConn, sent and received DNS - // messages must adhere to RFC 1035 section 4.2.1, "UDP usage". - // Otherwise, DNS messages transmitted over Conn must adhere - // to RFC 7766 section 5, "Transport Protocol Selection". - // If nil, the default dialer is used. - Dial func(ctx context.Context, network, address string) (Conn, error) - - // lookupGroup merges LookupIPAddr calls together for lookups for the same - // host. The lookupGroup key is the LookupIPAddr.host argument. - // The return values are ([]IPAddr, error). - lookupGroup singleflight.Group - - // TODO(bradfitz): optional interface impl override hook - // TODO(bradfitz): Timeout time.Duration? -} - -func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo } -func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors } - -func (r *Resolver) getLookupGroup() *singleflight.Group { - if r == nil { - return &DefaultResolver.lookupGroup - } - return &r.lookupGroup -} - -// LookupHost looks up the given host using the local resolver. -// It returns a slice of that host's addresses. -// -// LookupHost uses [context.Background] internally; to specify the context, use -// [Resolver.LookupHost]. -func LookupHost(host string) (addrs []string, err error) { - return DefaultResolver.LookupHost(context.Background(), host) -} - -// LookupHost looks up the given host using the local resolver. -// It returns a slice of that host's addresses. -func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) { - // Make sure that no matter what we do later, host=="" is rejected. - if host == "" { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} - } - if _, err := netip.ParseAddr(host); err == nil { - return []string{host}, nil - } - return r.lookupHost(ctx, host) -} - -// LookupIP looks up host using the local resolver. -// It returns a slice of that host's IPv4 and IPv6 addresses. -func LookupIP(host string) ([]IP, error) { - addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host) - if err != nil { - return nil, err - } - ips := make([]IP, len(addrs)) - for i, ia := range addrs { - ips[i] = ia.IP - } - return ips, nil -} - -// LookupIPAddr looks up host using the local resolver. -// It returns a slice of that host's IPv4 and IPv6 addresses. -func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) { - return r.lookupIPAddr(ctx, "ip", host) -} - -// LookupIP looks up host for the given network using the local resolver. -// It returns a slice of that host's IP addresses of the type specified by -// network. -// network must be one of "ip", "ip4" or "ip6". -func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) { - afnet, _, err := parseNetwork(ctx, network, false) - if err != nil { - return nil, err - } - switch afnet { - case "ip", "ip4", "ip6": - default: - return nil, UnknownNetworkError(network) - } - - if host == "" { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} - } - addrs, err := r.internetAddrList(ctx, afnet, host) - if err != nil { - return nil, err - } - - ips := make([]IP, 0, len(addrs)) - for _, addr := range addrs { - ips = append(ips, addr.(*IPAddr).IP) - } - return ips, nil -} - -// LookupNetIP looks up host using the local resolver. -// It returns a slice of that host's IP addresses of the type specified by -// network. -// The network must be one of "ip", "ip4" or "ip6". -func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) { - // TODO(bradfitz): make this efficient, making the internal net package - // type throughout be netip.Addr and only converting to the net.IP slice - // version at the edge. But for now (2021-10-20), this is a wrapper around - // the old way. - ips, err := r.LookupIP(ctx, network, host) - if err != nil { - return nil, err - } - ret := make([]netip.Addr, 0, len(ips)) - for _, ip := range ips { - if a, ok := netip.AddrFromSlice(ip); ok { - ret = append(ret, a) - } - } - return ret, nil -} - -// onlyValuesCtx is a context that uses an underlying context -// for value lookup if the underlying context hasn't yet expired. -type onlyValuesCtx struct { - context.Context - lookupValues context.Context -} - -var _ context.Context = (*onlyValuesCtx)(nil) - -// Value performs a lookup if the original context hasn't expired. -func (ovc *onlyValuesCtx) Value(key any) any { - select { - case <-ovc.lookupValues.Done(): - return nil - default: - return ovc.lookupValues.Value(key) - } -} - -// withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx -// for its values, otherwise it is never canceled and has no deadline. -// If the lookup context expires, any looked up values will return nil. -// See Issue 28600. -func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context { - return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx} -} - -// lookupIPAddr looks up host using the local resolver and particular network. -// It returns a slice of that host's IPv4 and IPv6 addresses. -func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) { - // Make sure that no matter what we do later, host=="" is rejected. - if host == "" { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} - } - if ip, err := netip.ParseAddr(host); err == nil { - return []IPAddr{{IP: IP(ip.AsSlice()).To16(), Zone: ip.Zone()}}, nil - } - trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) - if trace != nil && trace.DNSStart != nil { - trace.DNSStart(host) - } - // The underlying resolver func is lookupIP by default but it - // can be overridden by tests. This is needed by net/http, so it - // uses a context key instead of unexported variables. - resolverFunc := r.lookupIP - if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil { - resolverFunc = alt - } - - // We don't want a cancellation of ctx to affect the - // lookupGroup operation. Otherwise if our context gets - // canceled it might cause an error to be returned to a lookup - // using a completely different context. However we need to preserve - // only the values in context. See Issue 28600. - lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx)) - - lookupKey := network + "\000" + host - dnsWaitGroup.Add(1) - ch := r.getLookupGroup().DoChan(lookupKey, func() (any, error) { - return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host) - }) - - dnsWaitGroupDone := func(ch <-chan singleflight.Result, cancelFn context.CancelFunc) { - <-ch - dnsWaitGroup.Done() - cancelFn() - } - select { - case <-ctx.Done(): - // Our context was canceled. If we are the only - // goroutine looking up this key, then drop the key - // from the lookupGroup and cancel the lookup. - // If there are other goroutines looking up this key, - // let the lookup continue uncanceled, and let later - // lookups with the same key share the result. - // See issues 8602, 20703, 22724. - if r.getLookupGroup().ForgetUnshared(lookupKey) { - lookupGroupCancel() - go dnsWaitGroupDone(ch, func() {}) - } else { - go dnsWaitGroupDone(ch, lookupGroupCancel) - } - ctxErr := ctx.Err() - err := &DNSError{ - Err: mapErr(ctxErr).Error(), - Name: host, - IsTimeout: ctxErr == context.DeadlineExceeded, - } - if trace != nil && trace.DNSDone != nil { - trace.DNSDone(nil, false, err) - } - return nil, err - case r := <-ch: - dnsWaitGroup.Done() - lookupGroupCancel() - err := r.Err - if err != nil { - if _, ok := err.(*DNSError); !ok { - isTimeout := false - if err == context.DeadlineExceeded { - isTimeout = true - } else if terr, ok := err.(timeout); ok { - isTimeout = terr.Timeout() - } - err = &DNSError{ - Err: err.Error(), - Name: host, - IsTimeout: isTimeout, - } - } - } - if trace != nil && trace.DNSDone != nil { - addrs, _ := r.Val.([]IPAddr) - trace.DNSDone(ipAddrsEface(addrs), r.Shared, err) - } - return lookupIPReturn(r.Val, err, r.Shared) - } -} - -// lookupIPReturn turns the return values from singleflight.Do into -// the return values from LookupIP. -func lookupIPReturn(addrsi any, err error, shared bool) ([]IPAddr, error) { - if err != nil { - return nil, err - } - addrs := addrsi.([]IPAddr) - if shared { - clone := make([]IPAddr, len(addrs)) - copy(clone, addrs) - addrs = clone - } - return addrs, nil -} - -// ipAddrsEface returns an empty interface slice of addrs. -func ipAddrsEface(addrs []IPAddr) []any { - s := make([]any, len(addrs)) - for i, v := range addrs { - s[i] = v - } - return s -} - -// LookupPort looks up the port for the given network and service. -// -// LookupPort uses [context.Background] internally; to specify the context, use -// [Resolver.LookupPort]. -func LookupPort(network, service string) (port int, err error) { - return DefaultResolver.LookupPort(context.Background(), network, service) -} - -// LookupPort looks up the port for the given network and service. -// -// The network must be one of "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6" or "ip". -func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) { - port, needsLookup := parsePort(service) - if needsLookup { - switch network { - case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip": - case "": // a hint wildcard for Go 1.0 undocumented behavior - network = "ip" - default: - return 0, &AddrError{Err: "unknown network", Addr: network} - } - port, err = r.lookupPort(ctx, network, service) - if err != nil { - return 0, err - } - } - if 0 > port || port > 65535 { - return 0, &AddrError{Err: "invalid port", Addr: service} - } - return port, nil -} - -// LookupCNAME returns the canonical name for the given host. -// Callers that do not care about the canonical name can call -// [LookupHost] or [LookupIP] directly; both take care of resolving -// the canonical name as part of the lookup. -// -// A canonical name is the final name after following zero -// or more CNAME records. -// LookupCNAME does not return an error if host does not -// contain DNS "CNAME" records, as long as host resolves to -// address records. -// -// The returned canonical name is validated to be a properly -// formatted presentation-format domain name. -// -// LookupCNAME uses [context.Background] internally; to specify the context, use -// [Resolver.LookupCNAME]. -func LookupCNAME(host string) (cname string, err error) { - return DefaultResolver.LookupCNAME(context.Background(), host) -} - -// LookupCNAME returns the canonical name for the given host. -// Callers that do not care about the canonical name can call -// [LookupHost] or [LookupIP] directly; both take care of resolving -// the canonical name as part of the lookup. -// -// A canonical name is the final name after following zero -// or more CNAME records. -// LookupCNAME does not return an error if host does not -// contain DNS "CNAME" records, as long as host resolves to -// address records. -// -// The returned canonical name is validated to be a properly -// formatted presentation-format domain name. -func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { - cname, err := r.lookupCNAME(ctx, host) - if err != nil { - return "", err - } - if !isDomainName(cname) { - return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host} - } - return cname, nil -} - -// LookupSRV tries to resolve an [SRV] query of the given service, -// protocol, and domain name. The proto is "tcp" or "udp". -// The returned records are sorted by priority and randomized -// by weight within a priority. -// -// LookupSRV constructs the DNS name to look up following RFC 2782. -// That is, it looks up _service._proto.name. To accommodate services -// publishing SRV records under non-standard names, if both service -// and proto are empty strings, LookupSRV looks up name directly. -// -// The returned service names are validated to be properly -// formatted presentation-format domain names. If the response contains -// invalid names, those records are filtered out and an error -// will be returned alongside the remaining results, if any. -func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { - return DefaultResolver.LookupSRV(context.Background(), service, proto, name) -} - -// LookupSRV tries to resolve an [SRV] query of the given service, -// protocol, and domain name. The proto is "tcp" or "udp". -// The returned records are sorted by priority and randomized -// by weight within a priority. -// -// LookupSRV constructs the DNS name to look up following RFC 2782. -// That is, it looks up _service._proto.name. To accommodate services -// publishing SRV records under non-standard names, if both service -// and proto are empty strings, LookupSRV looks up name directly. -// -// The returned service names are validated to be properly -// formatted presentation-format domain names. If the response contains -// invalid names, those records are filtered out and an error -// will be returned alongside the remaining results, if any. -func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { - cname, addrs, err := r.lookupSRV(ctx, service, proto, name) - if err != nil { - return "", nil, err - } - if cname != "" && !isDomainName(cname) { - return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} - } - filteredAddrs := make([]*SRV, 0, len(addrs)) - for _, addr := range addrs { - if addr == nil { - continue - } - if !isDomainName(addr.Target) { - continue - } - filteredAddrs = append(filteredAddrs, addr) - } - if len(addrs) != len(filteredAddrs) { - return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} - } - return cname, filteredAddrs, nil -} - -// LookupMX returns the DNS MX records for the given domain name sorted by preference. -// -// The returned mail server names are validated to be properly -// formatted presentation-format domain names. If the response contains -// invalid names, those records are filtered out and an error -// will be returned alongside the remaining results, if any. -// -// LookupMX uses [context.Background] internally; to specify the context, use -// [Resolver.LookupMX]. -func LookupMX(name string) ([]*MX, error) { - return DefaultResolver.LookupMX(context.Background(), name) -} - -// LookupMX returns the DNS MX records for the given domain name sorted by preference. -// -// The returned mail server names are validated to be properly -// formatted presentation-format domain names. If the response contains -// invalid names, those records are filtered out and an error -// will be returned alongside the remaining results, if any. -func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { - records, err := r.lookupMX(ctx, name) - if err != nil { - return nil, err - } - filteredMX := make([]*MX, 0, len(records)) - for _, mx := range records { - if mx == nil { - continue - } - if !isDomainName(mx.Host) { - continue - } - filteredMX = append(filteredMX, mx) - } - if len(records) != len(filteredMX) { - return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} - } - return filteredMX, nil -} - -// LookupNS returns the DNS NS records for the given domain name. -// -// The returned name server names are validated to be properly -// formatted presentation-format domain names. If the response contains -// invalid names, those records are filtered out and an error -// will be returned alongside the remaining results, if any. -// -// LookupNS uses [context.Background] internally; to specify the context, use -// [Resolver.LookupNS]. -func LookupNS(name string) ([]*NS, error) { - return DefaultResolver.LookupNS(context.Background(), name) -} - -// LookupNS returns the DNS NS records for the given domain name. -// -// The returned name server names are validated to be properly -// formatted presentation-format domain names. If the response contains -// invalid names, those records are filtered out and an error -// will be returned alongside the remaining results, if any. -func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { - records, err := r.lookupNS(ctx, name) - if err != nil { - return nil, err - } - filteredNS := make([]*NS, 0, len(records)) - for _, ns := range records { - if ns == nil { - continue - } - if !isDomainName(ns.Host) { - continue - } - filteredNS = append(filteredNS, ns) - } - if len(records) != len(filteredNS) { - return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} - } - return filteredNS, nil -} - -// LookupTXT returns the DNS TXT records for the given domain name. -// -// LookupTXT uses [context.Background] internally; to specify the context, use -// [Resolver.LookupTXT]. -func LookupTXT(name string) ([]string, error) { - return DefaultResolver.lookupTXT(context.Background(), name) -} - -// LookupTXT returns the DNS TXT records for the given domain name. -func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) { - return r.lookupTXT(ctx, name) -} - -// LookupAddr performs a reverse lookup for the given address, returning a list -// of names mapping to that address. -// -// The returned names are validated to be properly formatted presentation-format -// domain names. If the response contains invalid names, those records are filtered -// out and an error will be returned alongside the remaining results, if any. -// -// When using the host C library resolver, at most one result will be -// returned. To bypass the host resolver, use a custom [Resolver]. -// -// LookupAddr uses [context.Background] internally; to specify the context, use -// [Resolver.LookupAddr]. -func LookupAddr(addr string) (names []string, err error) { - return DefaultResolver.LookupAddr(context.Background(), addr) -} - -// LookupAddr performs a reverse lookup for the given address, returning a list -// of names mapping to that address. -// -// The returned names are validated to be properly formatted presentation-format -// domain names. If the response contains invalid names, those records are filtered -// out and an error will be returned alongside the remaining results, if any. -func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { - names, err := r.lookupAddr(ctx, addr) - if err != nil { - return nil, err - } - filteredNames := make([]string, 0, len(names)) - for _, name := range names { - if isDomainName(name) { - filteredNames = append(filteredNames, name) - } - } - if len(names) != len(filteredNames) { - return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr} - } - return filteredNames, nil -} - -// errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup... -// method receives DNS records which contain invalid DNS names. This may be returned alongside -// results which have had the malformed records filtered out. -var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names" - -// dial makes a new connection to the provided server (which must be -// an IP address) with the provided network type, using either r.Dial -// (if both r and r.Dial are non-nil) or else Dialer.DialContext. -func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) { - // Calling Dial here is scary -- we have to be sure not to - // dial a name that will require a DNS lookup, or Dial will - // call back here to translate it. The DNS config parser has - // already checked that all the cfg.servers are IP - // addresses, which Dial will use without a DNS lookup. - var c Conn - var err error - if r != nil && r.Dial != nil { - c, err = r.Dial(ctx, network, server) - } else { - var d Dialer - c, err = d.DialContext(ctx, network, server) - } - if err != nil { - return nil, mapErr(err) - } - return c, nil -} - -// goLookupSRV returns the SRV records for a target name, built either -// from its component service ("sip"), protocol ("tcp"), and name -// ("example.com."), or from name directly (if service and proto are -// both empty). -// -// In either case, the returned target name ("_sip._tcp.example.com.") -// is also returned on success. -// -// The records are sorted by weight. -func (r *Resolver) goLookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*SRV, err error) { - if service == "" && proto == "" { - target = name - } else { - target = "_" + service + "._" + proto + "." + name - } - p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV, nil) - if err != nil { - return "", nil, err - } - var cname dnsmessage.Name - for { - h, err := p.AnswerHeader() - if err == dnsmessage.ErrSectionDone { - break - } - if err != nil { - return "", nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - if h.Type != dnsmessage.TypeSRV { - if err := p.SkipAnswer(); err != nil { - return "", nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - continue - } - if cname.Length == 0 && h.Name.Length != 0 { - cname = h.Name - } - srv, err := p.SRVResource() - if err != nil { - return "", nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight}) - } - byPriorityWeight(srvs).sort() - return cname.String(), srvs, nil -} - -// goLookupMX returns the MX records for name. -func (r *Resolver) goLookupMX(ctx context.Context, name string) ([]*MX, error) { - p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX, nil) - if err != nil { - return nil, err - } - var mxs []*MX - for { - h, err := p.AnswerHeader() - if err == dnsmessage.ErrSectionDone { - break - } - if err != nil { - return nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - if h.Type != dnsmessage.TypeMX { - if err := p.SkipAnswer(); err != nil { - return nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - continue - } - mx, err := p.MXResource() - if err != nil { - return nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref}) - - } - byPref(mxs).sort() - return mxs, nil -} - -// goLookupNS returns the NS records for name. -func (r *Resolver) goLookupNS(ctx context.Context, name string) ([]*NS, error) { - p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS, nil) - if err != nil { - return nil, err - } - var nss []*NS - for { - h, err := p.AnswerHeader() - if err == dnsmessage.ErrSectionDone { - break - } - if err != nil { - return nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - if h.Type != dnsmessage.TypeNS { - if err := p.SkipAnswer(); err != nil { - return nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - continue - } - ns, err := p.NSResource() - if err != nil { - return nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - nss = append(nss, &NS{Host: ns.NS.String()}) - } - return nss, nil -} - -// goLookupTXT returns the TXT records from name. -func (r *Resolver) goLookupTXT(ctx context.Context, name string) ([]string, error) { - p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT, nil) - if err != nil { - return nil, err - } - var txts []string - for { - h, err := p.AnswerHeader() - if err == dnsmessage.ErrSectionDone { - break - } - if err != nil { - return nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - if h.Type != dnsmessage.TypeTXT { - if err := p.SkipAnswer(); err != nil { - return nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - continue - } - txt, err := p.TXTResource() - if err != nil { - return nil, &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } - } - // Multiple strings in one TXT record need to be - // concatenated without separator to be consistent - // with previous Go resolver. - n := 0 - for _, s := range txt.TXT { - n += len(s) - } - txtJoin := make([]byte, 0, n) - for _, s := range txt.TXT { - txtJoin = append(txtJoin, s...) - } - if len(txts) == 0 { - txts = make([]string, 0, 1) - } - txts = append(txts, string(txtJoin)) - } - return txts, nil -} - -func parseCNAMEFromResources(resources []dnsmessage.Resource) (string, error) { - if len(resources) == 0 { - return "", errors.New("no CNAME record received") - } - c, ok := resources[0].Body.(*dnsmessage.CNAMEResource) - if !ok { - return "", errors.New("could not parse CNAME record") - } - return c.CNAME.String(), nil -} diff --git a/contrib/go/_std_1.22/src/net/mail/message.go b/contrib/go/_std_1.22/src/net/mail/message.go deleted file mode 100644 index fc2a9e46f811..000000000000 --- a/contrib/go/_std_1.22/src/net/mail/message.go +++ /dev/null @@ -1,915 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package mail implements parsing of mail messages. - -For the most part, this package follows the syntax as specified by RFC 5322 and -extended by RFC 6532. -Notable divergences: - - Obsolete address formats are not parsed, including addresses with - embedded route information. - - The full range of spacing (the CFWS syntax element) is not supported, - such as breaking addresses across lines. - - No unicode normalization is performed. - - The special characters ()[]:;@\, are allowed to appear unquoted in names. - - A leading From line is permitted, as in mbox format (RFC 4155). -*/ -package mail - -import ( - "bufio" - "errors" - "fmt" - "io" - "log" - "mime" - "net/textproto" - "strings" - "sync" - "time" - "unicode/utf8" -) - -var debug = debugT(false) - -type debugT bool - -func (d debugT) Printf(format string, args ...any) { - if d { - log.Printf(format, args...) - } -} - -// A Message represents a parsed mail message. -type Message struct { - Header Header - Body io.Reader -} - -// ReadMessage reads a message from r. -// The headers are parsed, and the body of the message will be available -// for reading from msg.Body. -func ReadMessage(r io.Reader) (msg *Message, err error) { - tp := textproto.NewReader(bufio.NewReader(r)) - - hdr, err := readHeader(tp) - if err != nil && (err != io.EOF || len(hdr) == 0) { - return nil, err - } - - return &Message{ - Header: Header(hdr), - Body: tp.R, - }, nil -} - -// readHeader reads the message headers from r. -// This is like textproto.ReadMIMEHeader, but doesn't validate. -// The fix for issue #53188 tightened up net/textproto to enforce -// restrictions of RFC 7230. -// This package implements RFC 5322, which does not have those restrictions. -// This function copies the relevant code from net/textproto, -// simplified for RFC 5322. -func readHeader(r *textproto.Reader) (map[string][]string, error) { - m := make(map[string][]string) - - // The first line cannot start with a leading space. - if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { - line, err := r.ReadLine() - if err != nil { - return m, err - } - return m, errors.New("malformed initial line: " + line) - } - - for { - kv, err := r.ReadContinuedLine() - if kv == "" { - return m, err - } - - // Key ends at first colon. - k, v, ok := strings.Cut(kv, ":") - if !ok { - return m, errors.New("malformed header line: " + kv) - } - key := textproto.CanonicalMIMEHeaderKey(k) - - // Permit empty key, because that is what we did in the past. - if key == "" { - continue - } - - // Skip initial spaces in value. - value := strings.TrimLeft(v, " \t") - - m[key] = append(m[key], value) - - if err != nil { - return m, err - } - } -} - -// Layouts suitable for passing to time.Parse. -// These are tried in order. -var ( - dateLayoutsBuildOnce sync.Once - dateLayouts []string -) - -func buildDateLayouts() { - // Generate layouts based on RFC 5322, section 3.3. - - dows := [...]string{"", "Mon, "} // day-of-week - days := [...]string{"2", "02"} // day = 1*2DIGIT - years := [...]string{"2006", "06"} // year = 4*DIGIT / 2*DIGIT - seconds := [...]string{":05", ""} // second - // "-0700 (MST)" is not in RFC 5322, but is common. - zones := [...]string{"-0700", "MST", "UT"} // zone = (("+" / "-") 4DIGIT) / "UT" / "GMT" / ... - - for _, dow := range dows { - for _, day := range days { - for _, year := range years { - for _, second := range seconds { - for _, zone := range zones { - s := dow + day + " Jan " + year + " 15:04" + second + " " + zone - dateLayouts = append(dateLayouts, s) - } - } - } - } - } -} - -// ParseDate parses an RFC 5322 date string. -func ParseDate(date string) (time.Time, error) { - dateLayoutsBuildOnce.Do(buildDateLayouts) - // CR and LF must match and are tolerated anywhere in the date field. - date = strings.ReplaceAll(date, "\r\n", "") - if strings.Contains(date, "\r") { - return time.Time{}, errors.New("mail: header has a CR without LF") - } - // Re-using some addrParser methods which support obsolete text, i.e. non-printable ASCII - p := addrParser{date, nil} - p.skipSpace() - - // RFC 5322: zone = (FWS ( "+" / "-" ) 4DIGIT) / obs-zone - // zone length is always 5 chars unless obsolete (obs-zone) - if ind := strings.IndexAny(p.s, "+-"); ind != -1 && len(p.s) >= ind+5 { - date = p.s[:ind+5] - p.s = p.s[ind+5:] - } else { - ind := strings.Index(p.s, "T") - if ind == 0 { - // In this case we have the following date formats: - // * Thu, 20 Nov 1997 09:55:06 MDT - // * Thu, 20 Nov 1997 09:55:06 MDT (MDT) - // * Thu, 20 Nov 1997 09:55:06 MDT (This comment) - ind = strings.Index(p.s[1:], "T") - if ind != -1 { - ind++ - } - } - - if ind != -1 && len(p.s) >= ind+5 { - // The last letter T of the obsolete time zone is checked when no standard time zone is found. - // If T is misplaced, the date to parse is garbage. - date = p.s[:ind+1] - p.s = p.s[ind+1:] - } - } - if !p.skipCFWS() { - return time.Time{}, errors.New("mail: misformatted parenthetical comment") - } - for _, layout := range dateLayouts { - t, err := time.Parse(layout, date) - if err == nil { - return t, nil - } - } - return time.Time{}, errors.New("mail: header could not be parsed") -} - -// A Header represents the key-value pairs in a mail message header. -type Header map[string][]string - -// Get gets the first value associated with the given key. -// It is case insensitive; CanonicalMIMEHeaderKey is used -// to canonicalize the provided key. -// If there are no values associated with the key, Get returns "". -// To access multiple values of a key, or to use non-canonical keys, -// access the map directly. -func (h Header) Get(key string) string { - return textproto.MIMEHeader(h).Get(key) -} - -var ErrHeaderNotPresent = errors.New("mail: header not in message") - -// Date parses the Date header field. -func (h Header) Date() (time.Time, error) { - hdr := h.Get("Date") - if hdr == "" { - return time.Time{}, ErrHeaderNotPresent - } - return ParseDate(hdr) -} - -// AddressList parses the named header field as a list of addresses. -func (h Header) AddressList(key string) ([]*Address, error) { - hdr := h.Get(key) - if hdr == "" { - return nil, ErrHeaderNotPresent - } - return ParseAddressList(hdr) -} - -// Address represents a single mail address. -// An address such as "Barry Gibbs " is represented -// as Address{Name: "Barry Gibbs", Address: "bg@example.com"}. -type Address struct { - Name string // Proper name; may be empty. - Address string // user@domain -} - -// ParseAddress parses a single RFC 5322 address, e.g. "Barry Gibbs " -func ParseAddress(address string) (*Address, error) { - return (&addrParser{s: address}).parseSingleAddress() -} - -// ParseAddressList parses the given string as a list of addresses. -func ParseAddressList(list string) ([]*Address, error) { - return (&addrParser{s: list}).parseAddressList() -} - -// An AddressParser is an RFC 5322 address parser. -type AddressParser struct { - // WordDecoder optionally specifies a decoder for RFC 2047 encoded-words. - WordDecoder *mime.WordDecoder -} - -// Parse parses a single RFC 5322 address of the -// form "Gogh Fir " or "foo@example.com". -func (p *AddressParser) Parse(address string) (*Address, error) { - return (&addrParser{s: address, dec: p.WordDecoder}).parseSingleAddress() -} - -// ParseList parses the given string as a list of comma-separated addresses -// of the form "Gogh Fir " or "foo@example.com". -func (p *AddressParser) ParseList(list string) ([]*Address, error) { - return (&addrParser{s: list, dec: p.WordDecoder}).parseAddressList() -} - -// String formats the address as a valid RFC 5322 address. -// If the address's name contains non-ASCII characters -// the name will be rendered according to RFC 2047. -func (a *Address) String() string { - // Format address local@domain - at := strings.LastIndex(a.Address, "@") - var local, domain string - if at < 0 { - // This is a malformed address ("@" is required in addr-spec); - // treat the whole address as local-part. - local = a.Address - } else { - local, domain = a.Address[:at], a.Address[at+1:] - } - - // Add quotes if needed - quoteLocal := false - for i, r := range local { - if isAtext(r, false) { - continue - } - if r == '.' { - // Dots are okay if they are surrounded by atext. - // We only need to check that the previous byte is - // not a dot, and this isn't the end of the string. - if i > 0 && local[i-1] != '.' && i < len(local)-1 { - continue - } - } - quoteLocal = true - break - } - if quoteLocal { - local = quoteString(local) - - } - - s := "<" + local + "@" + domain + ">" - - if a.Name == "" { - return s - } - - // If every character is printable ASCII, quoting is simple. - allPrintable := true - for _, r := range a.Name { - // isWSP here should actually be isFWS, - // but we don't support folding yet. - if !isVchar(r) && !isWSP(r) || isMultibyte(r) { - allPrintable = false - break - } - } - if allPrintable { - return quoteString(a.Name) + " " + s - } - - // Text in an encoded-word in a display-name must not contain certain - // characters like quotes or parentheses (see RFC 2047 section 5.3). - // When this is the case encode the name using base64 encoding. - if strings.ContainsAny(a.Name, "\"#$%&'(),.:;<>@[]^`{|}~") { - return mime.BEncoding.Encode("utf-8", a.Name) + " " + s - } - return mime.QEncoding.Encode("utf-8", a.Name) + " " + s -} - -type addrParser struct { - s string - dec *mime.WordDecoder // may be nil -} - -func (p *addrParser) parseAddressList() ([]*Address, error) { - var list []*Address - for { - p.skipSpace() - - // allow skipping empty entries (RFC5322 obs-addr-list) - if p.consume(',') { - continue - } - - addrs, err := p.parseAddress(true) - if err != nil { - return nil, err - } - list = append(list, addrs...) - - if !p.skipCFWS() { - return nil, errors.New("mail: misformatted parenthetical comment") - } - if p.empty() { - break - } - if p.peek() != ',' { - return nil, errors.New("mail: expected comma") - } - - // Skip empty entries for obs-addr-list. - for p.consume(',') { - p.skipSpace() - } - if p.empty() { - break - } - } - return list, nil -} - -func (p *addrParser) parseSingleAddress() (*Address, error) { - addrs, err := p.parseAddress(true) - if err != nil { - return nil, err - } - if !p.skipCFWS() { - return nil, errors.New("mail: misformatted parenthetical comment") - } - if !p.empty() { - return nil, fmt.Errorf("mail: expected single address, got %q", p.s) - } - if len(addrs) == 0 { - return nil, errors.New("mail: empty group") - } - if len(addrs) > 1 { - return nil, errors.New("mail: group with multiple addresses") - } - return addrs[0], nil -} - -// parseAddress parses a single RFC 5322 address at the start of p. -func (p *addrParser) parseAddress(handleGroup bool) ([]*Address, error) { - debug.Printf("parseAddress: %q", p.s) - p.skipSpace() - if p.empty() { - return nil, errors.New("mail: no address") - } - - // address = mailbox / group - // mailbox = name-addr / addr-spec - // group = display-name ":" [group-list] ";" [CFWS] - - // addr-spec has a more restricted grammar than name-addr, - // so try parsing it first, and fallback to name-addr. - // TODO(dsymonds): Is this really correct? - spec, err := p.consumeAddrSpec() - if err == nil { - var displayName string - p.skipSpace() - if !p.empty() && p.peek() == '(' { - displayName, err = p.consumeDisplayNameComment() - if err != nil { - return nil, err - } - } - - return []*Address{{ - Name: displayName, - Address: spec, - }}, err - } - debug.Printf("parseAddress: not an addr-spec: %v", err) - debug.Printf("parseAddress: state is now %q", p.s) - - // display-name - var displayName string - if p.peek() != '<' { - displayName, err = p.consumePhrase() - if err != nil { - return nil, err - } - } - debug.Printf("parseAddress: displayName=%q", displayName) - - p.skipSpace() - if handleGroup { - if p.consume(':') { - return p.consumeGroupList() - } - } - // angle-addr = "<" addr-spec ">" - if !p.consume('<') { - atext := true - for _, r := range displayName { - if !isAtext(r, true) { - atext = false - break - } - } - if atext { - // The input is like "foo.bar"; it's possible the input - // meant to be "foo.bar@domain", or "foo.bar <...>". - return nil, errors.New("mail: missing '@' or angle-addr") - } - // The input is like "Full Name", which couldn't possibly be a - // valid email address if followed by "@domain"; the input - // likely meant to be "Full Name <...>". - return nil, errors.New("mail: no angle-addr") - } - spec, err = p.consumeAddrSpec() - if err != nil { - return nil, err - } - if !p.consume('>') { - return nil, errors.New("mail: unclosed angle-addr") - } - debug.Printf("parseAddress: spec=%q", spec) - - return []*Address{{ - Name: displayName, - Address: spec, - }}, nil -} - -func (p *addrParser) consumeGroupList() ([]*Address, error) { - var group []*Address - // handle empty group. - p.skipSpace() - if p.consume(';') { - if !p.skipCFWS() { - return nil, errors.New("mail: misformatted parenthetical comment") - } - return group, nil - } - - for { - p.skipSpace() - // embedded groups not allowed. - addrs, err := p.parseAddress(false) - if err != nil { - return nil, err - } - group = append(group, addrs...) - - if !p.skipCFWS() { - return nil, errors.New("mail: misformatted parenthetical comment") - } - if p.consume(';') { - if !p.skipCFWS() { - return nil, errors.New("mail: misformatted parenthetical comment") - } - break - } - if !p.consume(',') { - return nil, errors.New("mail: expected comma") - } - } - return group, nil -} - -// consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p. -func (p *addrParser) consumeAddrSpec() (spec string, err error) { - debug.Printf("consumeAddrSpec: %q", p.s) - - orig := *p - defer func() { - if err != nil { - *p = orig - } - }() - - // local-part = dot-atom / quoted-string - var localPart string - p.skipSpace() - if p.empty() { - return "", errors.New("mail: no addr-spec") - } - if p.peek() == '"' { - // quoted-string - debug.Printf("consumeAddrSpec: parsing quoted-string") - localPart, err = p.consumeQuotedString() - if localPart == "" { - err = errors.New("mail: empty quoted string in addr-spec") - } - } else { - // dot-atom - debug.Printf("consumeAddrSpec: parsing dot-atom") - localPart, err = p.consumeAtom(true, false) - } - if err != nil { - debug.Printf("consumeAddrSpec: failed: %v", err) - return "", err - } - - if !p.consume('@') { - return "", errors.New("mail: missing @ in addr-spec") - } - - // domain = dot-atom / domain-literal - var domain string - p.skipSpace() - if p.empty() { - return "", errors.New("mail: no domain in addr-spec") - } - // TODO(dsymonds): Handle domain-literal - domain, err = p.consumeAtom(true, false) - if err != nil { - return "", err - } - - return localPart + "@" + domain, nil -} - -// consumePhrase parses the RFC 5322 phrase at the start of p. -func (p *addrParser) consumePhrase() (phrase string, err error) { - debug.Printf("consumePhrase: [%s]", p.s) - // phrase = 1*word - var words []string - var isPrevEncoded bool - for { - // obs-phrase allows CFWS after one word - if len(words) > 0 { - if !p.skipCFWS() { - return "", errors.New("mail: misformatted parenthetical comment") - } - } - // word = atom / quoted-string - var word string - p.skipSpace() - if p.empty() { - break - } - isEncoded := false - if p.peek() == '"' { - // quoted-string - word, err = p.consumeQuotedString() - } else { - // atom - // We actually parse dot-atom here to be more permissive - // than what RFC 5322 specifies. - word, err = p.consumeAtom(true, true) - if err == nil { - word, isEncoded, err = p.decodeRFC2047Word(word) - } - } - - if err != nil { - break - } - debug.Printf("consumePhrase: consumed %q", word) - if isPrevEncoded && isEncoded { - words[len(words)-1] += word - } else { - words = append(words, word) - } - isPrevEncoded = isEncoded - } - // Ignore any error if we got at least one word. - if err != nil && len(words) == 0 { - debug.Printf("consumePhrase: hit err: %v", err) - return "", fmt.Errorf("mail: missing word in phrase: %v", err) - } - phrase = strings.Join(words, " ") - return phrase, nil -} - -// consumeQuotedString parses the quoted string at the start of p. -func (p *addrParser) consumeQuotedString() (qs string, err error) { - // Assume first byte is '"'. - i := 1 - qsb := make([]rune, 0, 10) - - escaped := false - -Loop: - for { - r, size := utf8.DecodeRuneInString(p.s[i:]) - - switch { - case size == 0: - return "", errors.New("mail: unclosed quoted-string") - - case size == 1 && r == utf8.RuneError: - return "", fmt.Errorf("mail: invalid utf-8 in quoted-string: %q", p.s) - - case escaped: - // quoted-pair = ("\" (VCHAR / WSP)) - - if !isVchar(r) && !isWSP(r) { - return "", fmt.Errorf("mail: bad character in quoted-string: %q", r) - } - - qsb = append(qsb, r) - escaped = false - - case isQtext(r) || isWSP(r): - // qtext (printable US-ASCII excluding " and \), or - // FWS (almost; we're ignoring CRLF) - qsb = append(qsb, r) - - case r == '"': - break Loop - - case r == '\\': - escaped = true - - default: - return "", fmt.Errorf("mail: bad character in quoted-string: %q", r) - - } - - i += size - } - p.s = p.s[i+1:] - return string(qsb), nil -} - -// consumeAtom parses an RFC 5322 atom at the start of p. -// If dot is true, consumeAtom parses an RFC 5322 dot-atom instead. -// If permissive is true, consumeAtom will not fail on: -// - leading/trailing/double dots in the atom (see golang.org/issue/4938) -func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) { - i := 0 - -Loop: - for { - r, size := utf8.DecodeRuneInString(p.s[i:]) - switch { - case size == 1 && r == utf8.RuneError: - return "", fmt.Errorf("mail: invalid utf-8 in address: %q", p.s) - - case size == 0 || !isAtext(r, dot): - break Loop - - default: - i += size - - } - } - - if i == 0 { - return "", errors.New("mail: invalid string") - } - atom, p.s = p.s[:i], p.s[i:] - if !permissive { - if strings.HasPrefix(atom, ".") { - return "", errors.New("mail: leading dot in atom") - } - if strings.Contains(atom, "..") { - return "", errors.New("mail: double dot in atom") - } - if strings.HasSuffix(atom, ".") { - return "", errors.New("mail: trailing dot in atom") - } - } - return atom, nil -} - -func (p *addrParser) consumeDisplayNameComment() (string, error) { - if !p.consume('(') { - return "", errors.New("mail: comment does not start with (") - } - comment, ok := p.consumeComment() - if !ok { - return "", errors.New("mail: misformatted parenthetical comment") - } - - // TODO(stapelberg): parse quoted-string within comment - words := strings.FieldsFunc(comment, func(r rune) bool { return r == ' ' || r == '\t' }) - for idx, word := range words { - decoded, isEncoded, err := p.decodeRFC2047Word(word) - if err != nil { - return "", err - } - if isEncoded { - words[idx] = decoded - } - } - - return strings.Join(words, " "), nil -} - -func (p *addrParser) consume(c byte) bool { - if p.empty() || p.peek() != c { - return false - } - p.s = p.s[1:] - return true -} - -// skipSpace skips the leading space and tab characters. -func (p *addrParser) skipSpace() { - p.s = strings.TrimLeft(p.s, " \t") -} - -func (p *addrParser) peek() byte { - return p.s[0] -} - -func (p *addrParser) empty() bool { - return p.len() == 0 -} - -func (p *addrParser) len() int { - return len(p.s) -} - -// skipCFWS skips CFWS as defined in RFC5322. -func (p *addrParser) skipCFWS() bool { - p.skipSpace() - - for { - if !p.consume('(') { - break - } - - if _, ok := p.consumeComment(); !ok { - return false - } - - p.skipSpace() - } - - return true -} - -func (p *addrParser) consumeComment() (string, bool) { - // '(' already consumed. - depth := 1 - - var comment string - for { - if p.empty() || depth == 0 { - break - } - - if p.peek() == '\\' && p.len() > 1 { - p.s = p.s[1:] - } else if p.peek() == '(' { - depth++ - } else if p.peek() == ')' { - depth-- - } - if depth > 0 { - comment += p.s[:1] - } - p.s = p.s[1:] - } - - return comment, depth == 0 -} - -func (p *addrParser) decodeRFC2047Word(s string) (word string, isEncoded bool, err error) { - dec := p.dec - if dec == nil { - dec = &rfc2047Decoder - } - - // Substitute our own CharsetReader function so that we can tell - // whether an error from the Decode method was due to the - // CharsetReader (meaning the charset is invalid). - // We used to look for the charsetError type in the error result, - // but that behaves badly with CharsetReaders other than the - // one in rfc2047Decoder. - adec := *dec - charsetReaderError := false - adec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { - if dec.CharsetReader == nil { - charsetReaderError = true - return nil, charsetError(charset) - } - r, err := dec.CharsetReader(charset, input) - if err != nil { - charsetReaderError = true - } - return r, err - } - word, err = adec.Decode(s) - if err == nil { - return word, true, nil - } - - // If the error came from the character set reader - // (meaning the character set itself is invalid - // but the decoding worked fine until then), - // return the original text and the error, - // with isEncoded=true. - if charsetReaderError { - return s, true, err - } - - // Ignore invalid RFC 2047 encoded-word errors. - return s, false, nil -} - -var rfc2047Decoder = mime.WordDecoder{ - CharsetReader: func(charset string, input io.Reader) (io.Reader, error) { - return nil, charsetError(charset) - }, -} - -type charsetError string - -func (e charsetError) Error() string { - return fmt.Sprintf("charset not supported: %q", string(e)) -} - -// isAtext reports whether r is an RFC 5322 atext character. -// If dot is true, period is included. -func isAtext(r rune, dot bool) bool { - switch r { - case '.': - return dot - - // RFC 5322 3.2.3. specials - case '(', ')', '<', '>', '[', ']', ':', ';', '@', '\\', ',', '"': // RFC 5322 3.2.3. specials - return false - } - return isVchar(r) -} - -// isQtext reports whether r is an RFC 5322 qtext character. -func isQtext(r rune) bool { - // Printable US-ASCII, excluding backslash or quote. - if r == '\\' || r == '"' { - return false - } - return isVchar(r) -} - -// quoteString renders a string as an RFC 5322 quoted-string. -func quoteString(s string) string { - var b strings.Builder - b.WriteByte('"') - for _, r := range s { - if isQtext(r) || isWSP(r) { - b.WriteRune(r) - } else if isVchar(r) { - b.WriteByte('\\') - b.WriteRune(r) - } - } - b.WriteByte('"') - return b.String() -} - -// isVchar reports whether r is an RFC 5322 VCHAR character. -func isVchar(r rune) bool { - // Visible (printing) characters. - return '!' <= r && r <= '~' || isMultibyte(r) -} - -// isMultibyte reports whether r is a multi-byte UTF-8 character -// as supported by RFC 6532. -func isMultibyte(r rune) bool { - return r >= utf8.RuneSelf -} - -// isWSP reports whether r is a WSP (white space). -// WSP is a space or horizontal tab (RFC 5234 Appendix B). -func isWSP(r rune) bool { - return r == ' ' || r == '\t' -} diff --git a/contrib/go/_std_1.22/src/net/netip/leaf_alts.go b/contrib/go/_std_1.22/src/net/netip/leaf_alts.go deleted file mode 100644 index d887bed62733..000000000000 --- a/contrib/go/_std_1.22/src/net/netip/leaf_alts.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Stuff that exists in std, but we can't use due to being a dependency -// of net, for go/build deps_test policy reasons. - -package netip - -func beUint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 -} - -func bePutUint64(b []byte, v uint64) { - _ = b[7] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 56) - b[1] = byte(v >> 48) - b[2] = byte(v >> 40) - b[3] = byte(v >> 32) - b[4] = byte(v >> 24) - b[5] = byte(v >> 16) - b[6] = byte(v >> 8) - b[7] = byte(v) -} - -func bePutUint32(b []byte, v uint32) { - _ = b[3] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 24) - b[1] = byte(v >> 16) - b[2] = byte(v >> 8) - b[3] = byte(v) -} - -func leUint16(b []byte) uint16 { - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint16(b[0]) | uint16(b[1])<<8 -} - -func lePutUint16(b []byte, v uint16) { - _ = b[1] // early bounds check to guarantee safety of writes below - b[0] = byte(v) - b[1] = byte(v >> 8) -} diff --git a/contrib/go/_std_1.22/src/net/netip/ya.make b/contrib/go/_std_1.22/src/net/netip/ya.make deleted file mode 100644 index 644b119e6d34..000000000000 --- a/contrib/go/_std_1.22/src/net/netip/ya.make +++ /dev/null @@ -1,9 +0,0 @@ -GO_LIBRARY() -IF (TRUE) - SRCS( - leaf_alts.go - netip.go - uint128.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/net/parse.go b/contrib/go/_std_1.22/src/net/parse.go deleted file mode 100644 index 29dffad43cf4..000000000000 --- a/contrib/go/_std_1.22/src/net/parse.go +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Simple file i/o and string manipulation, to avoid -// depending on strconv and bufio and strings. - -package net - -import ( - "internal/bytealg" - "io" - "os" - "time" -) - -type file struct { - file *os.File - data []byte - atEOF bool -} - -func (f *file) close() { f.file.Close() } - -func (f *file) getLineFromData() (s string, ok bool) { - data := f.data - i := 0 - for i = 0; i < len(data); i++ { - if data[i] == '\n' { - s = string(data[0:i]) - ok = true - // move data - i++ - n := len(data) - i - copy(data[0:], data[i:]) - f.data = data[0:n] - return - } - } - if f.atEOF && len(f.data) > 0 { - // EOF, return all we have - s = string(data) - f.data = f.data[0:0] - ok = true - } - return -} - -func (f *file) readLine() (s string, ok bool) { - if s, ok = f.getLineFromData(); ok { - return - } - if len(f.data) < cap(f.data) { - ln := len(f.data) - n, err := io.ReadFull(f.file, f.data[ln:cap(f.data)]) - if n >= 0 { - f.data = f.data[0 : ln+n] - } - if err == io.EOF || err == io.ErrUnexpectedEOF { - f.atEOF = true - } - } - s, ok = f.getLineFromData() - return -} - -func (f *file) stat() (mtime time.Time, size int64, err error) { - st, err := f.file.Stat() - if err != nil { - return time.Time{}, 0, err - } - return st.ModTime(), st.Size(), nil -} - -func open(name string) (*file, error) { - fd, err := os.Open(name) - if err != nil { - return nil, err - } - return &file{fd, make([]byte, 0, 64*1024), false}, nil -} - -func stat(name string) (mtime time.Time, size int64, err error) { - st, err := os.Stat(name) - if err != nil { - return time.Time{}, 0, err - } - return st.ModTime(), st.Size(), nil -} - -// Count occurrences in s of any bytes in t. -func countAnyByte(s string, t string) int { - n := 0 - for i := 0; i < len(s); i++ { - if bytealg.IndexByteString(t, s[i]) >= 0 { - n++ - } - } - return n -} - -// Split s at any bytes in t. -func splitAtBytes(s string, t string) []string { - a := make([]string, 1+countAnyByte(s, t)) - n := 0 - last := 0 - for i := 0; i < len(s); i++ { - if bytealg.IndexByteString(t, s[i]) >= 0 { - if last < i { - a[n] = s[last:i] - n++ - } - last = i + 1 - } - } - if last < len(s) { - a[n] = s[last:] - n++ - } - return a[0:n] -} - -func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") } - -// Bigger than we need, not too big to worry about overflow -const big = 0xFFFFFF - -// Decimal to integer. -// Returns number, characters consumed, success. -func dtoi(s string) (n int, i int, ok bool) { - n = 0 - for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { - n = n*10 + int(s[i]-'0') - if n >= big { - return big, i, false - } - } - if i == 0 { - return 0, 0, false - } - return n, i, true -} - -// Hexadecimal to integer. -// Returns number, characters consumed, success. -func xtoi(s string) (n int, i int, ok bool) { - n = 0 - for i = 0; i < len(s); i++ { - if '0' <= s[i] && s[i] <= '9' { - n *= 16 - n += int(s[i] - '0') - } else if 'a' <= s[i] && s[i] <= 'f' { - n *= 16 - n += int(s[i]-'a') + 10 - } else if 'A' <= s[i] && s[i] <= 'F' { - n *= 16 - n += int(s[i]-'A') + 10 - } else { - break - } - if n >= big { - return 0, i, false - } - } - if i == 0 { - return 0, i, false - } - return n, i, true -} - -// xtoi2 converts the next two hex digits of s into a byte. -// If s is longer than 2 bytes then the third byte must be e. -// If the first two bytes of s are not hex digits or the third byte -// does not match e, false is returned. -func xtoi2(s string, e byte) (byte, bool) { - if len(s) > 2 && s[2] != e { - return 0, false - } - n, ei, ok := xtoi(s[:2]) - return byte(n), ok && ei == 2 -} - -// hasUpperCase tells whether the given string contains at least one upper-case. -func hasUpperCase(s string) bool { - for i := range s { - if 'A' <= s[i] && s[i] <= 'Z' { - return true - } - } - return false -} - -// lowerASCIIBytes makes x ASCII lowercase in-place. -func lowerASCIIBytes(x []byte) { - for i, b := range x { - if 'A' <= b && b <= 'Z' { - x[i] += 'a' - 'A' - } - } -} - -// lowerASCII returns the ASCII lowercase version of b. -func lowerASCII(b byte) byte { - if 'A' <= b && b <= 'Z' { - return b + ('a' - 'A') - } - return b -} - -// trimSpace returns x without any leading or trailing ASCII whitespace. -func trimSpace(x string) string { - for len(x) > 0 && isSpace(x[0]) { - x = x[1:] - } - for len(x) > 0 && isSpace(x[len(x)-1]) { - x = x[:len(x)-1] - } - return x -} - -// isSpace reports whether b is an ASCII space character. -func isSpace(b byte) bool { - return b == ' ' || b == '\t' || b == '\n' || b == '\r' -} - -// removeComment returns line, removing any '#' byte and any following -// bytes. -func removeComment(line string) string { - if i := bytealg.IndexByteString(line, '#'); i != -1 { - return line[:i] - } - return line -} - -// foreachField runs fn on each non-empty run of non-space bytes in x. -// It returns the first non-nil error returned by fn. -func foreachField(x string, fn func(field string) error) error { - x = trimSpace(x) - for len(x) > 0 { - sp := bytealg.IndexByteString(x, ' ') - if sp == -1 { - return fn(x) - } - if field := trimSpace(x[:sp]); len(field) > 0 { - if err := fn(field); err != nil { - return err - } - } - x = trimSpace(x[sp+1:]) - } - return nil -} - -// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in -// suffix. -func stringsHasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix -} - -// stringsHasSuffixFold reports whether s ends in suffix, -// ASCII-case-insensitively. -func stringsHasSuffixFold(s, suffix string) bool { - return len(s) >= len(suffix) && stringsEqualFold(s[len(s)-len(suffix):], suffix) -} - -// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix. -func stringsHasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[:len(prefix)] == prefix -} - -// stringsEqualFold is strings.EqualFold, ASCII only. It reports whether s and t -// are equal, ASCII-case-insensitively. -func stringsEqualFold(s, t string) bool { - if len(s) != len(t) { - return false - } - for i := 0; i < len(s); i++ { - if lowerASCII(s[i]) != lowerASCII(t[i]) { - return false - } - } - return true -} diff --git a/contrib/go/_std_1.22/src/net/rpc/debug.go b/contrib/go/_std_1.22/src/net/rpc/debug.go deleted file mode 100644 index 9e499fd984de..000000000000 --- a/contrib/go/_std_1.22/src/net/rpc/debug.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rpc - -/* - Some HTML presented at http://machine:port/debug/rpc - Lists services, their methods, and some statistics, still rudimentary. -*/ - -import ( - "fmt" - "html/template" - "net/http" - "sort" -) - -const debugText = ` - - Services - {{range .}} -
- Service {{.Name}} -
- - - {{range .Method}} - - - - - {{end}} -
MethodCalls
{{.Name}}({{.Type.ArgType}}, {{.Type.ReplyType}}) error{{.Type.NumCalls}}
- {{end}} - - ` - -var debug = template.Must(template.New("RPC debug").Parse(debugText)) - -// If set, print log statements for internal and I/O errors. -var debugLog = false - -type debugMethod struct { - Type *methodType - Name string -} - -type methodArray []debugMethod - -type debugService struct { - Service *service - Name string - Method methodArray -} - -type serviceArray []debugService - -func (s serviceArray) Len() int { return len(s) } -func (s serviceArray) Less(i, j int) bool { return s[i].Name < s[j].Name } -func (s serviceArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func (m methodArray) Len() int { return len(m) } -func (m methodArray) Less(i, j int) bool { return m[i].Name < m[j].Name } -func (m methodArray) Swap(i, j int) { m[i], m[j] = m[j], m[i] } - -type debugHTTP struct { - *Server -} - -// Runs at /debug/rpc -func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) { - // Build a sorted version of the data. - var services serviceArray - server.serviceMap.Range(func(snamei, svci any) bool { - svc := svci.(*service) - ds := debugService{svc, snamei.(string), make(methodArray, 0, len(svc.method))} - for mname, method := range svc.method { - ds.Method = append(ds.Method, debugMethod{method, mname}) - } - sort.Sort(ds.Method) - services = append(services, ds) - return true - }) - sort.Sort(services) - err := debug.Execute(w, services) - if err != nil { - fmt.Fprintln(w, "rpc: error executing template:", err.Error()) - } -} diff --git a/contrib/go/_std_1.22/src/net/sendfile_linux.go b/contrib/go/_std_1.22/src/net/sendfile_linux.go deleted file mode 100644 index 9a7d0058032f..000000000000 --- a/contrib/go/_std_1.22/src/net/sendfile_linux.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "internal/poll" - "io" - "os" -) - -// sendFile copies the contents of r to c using the sendfile -// system call to minimize copies. -// -// if handled == true, sendFile returns the number (potentially zero) of bytes -// copied and any non-EOF error. -// -// if handled == false, sendFile performed no work. -func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { - var remain int64 = 1<<63 - 1 // by default, copy until EOF - - lr, ok := r.(*io.LimitedReader) - if ok { - remain, r = lr.N, lr.R - if remain <= 0 { - return 0, nil, true - } - } - f, ok := r.(*os.File) - if !ok { - return 0, nil, false - } - - sc, err := f.SyscallConn() - if err != nil { - return 0, nil, false - } - - var werr error - err = sc.Read(func(fd uintptr) bool { - written, werr, handled = poll.SendFile(&c.pfd, int(fd), remain) - return true - }) - if err == nil { - err = werr - } - - if lr != nil { - lr.N = remain - written - } - return written, wrapSyscallError("sendfile", err), handled -} diff --git a/contrib/go/_std_1.22/src/net/sendfile_stub.go b/contrib/go/_std_1.22/src/net/sendfile_stub.go deleted file mode 100644 index a4fdd99ffec2..000000000000 --- a/contrib/go/_std_1.22/src/net/sendfile_stub.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build aix || js || netbsd || openbsd || ios || wasip1 - -package net - -import "io" - -func sendFile(c *netFD, r io.Reader) (n int64, err error, handled bool) { - return 0, nil, false -} diff --git a/contrib/go/_std_1.22/src/net/sendfile_windows.go b/contrib/go/_std_1.22/src/net/sendfile_windows.go deleted file mode 100644 index 59b1b0d5c1dd..000000000000 --- a/contrib/go/_std_1.22/src/net/sendfile_windows.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "internal/poll" - "io" - "os" - "syscall" -) - -// sendFile copies the contents of r to c using the TransmitFile -// system call to minimize copies. -// -// if handled == true, sendFile returns the number of bytes copied and any -// non-EOF error. -// -// if handled == false, sendFile performed no work. -func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) { - var n int64 = 0 // by default, copy until EOF. - - lr, ok := r.(*io.LimitedReader) - if ok { - n, r = lr.N, lr.R - if n <= 0 { - return 0, nil, true - } - } - - f, ok := r.(*os.File) - if !ok { - return 0, nil, false - } - - written, err = poll.SendFile(&fd.pfd, syscall.Handle(f.Fd()), n) - if err != nil { - err = wrapSyscallError("transmitfile", err) - } - - // If any byte was copied, regardless of any error - // encountered mid-way, handled must be set to true. - handled = written > 0 - - return -} diff --git a/contrib/go/_std_1.22/src/net/sock_cloexec.go b/contrib/go/_std_1.22/src/net/sock_cloexec.go deleted file mode 100644 index 9eeb89746b9e..000000000000 --- a/contrib/go/_std_1.22/src/net/sock_cloexec.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file implements sysSocket for platforms that provide a fast path for -// setting SetNonblock and CloseOnExec. - -//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris - -package net - -import ( - "internal/poll" - "os" - "syscall" -) - -// Wrapper around the socket system call that marks the returned file -// descriptor as nonblocking and close-on-exec. -func sysSocket(family, sotype, proto int) (int, error) { - s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto) - // TODO: We can remove the fallback on Linux and *BSD, - // as currently supported versions all support accept4 - // with SOCK_CLOEXEC, but Solaris does not. See issue #59359. - switch err { - case nil: - return s, nil - default: - return -1, os.NewSyscallError("socket", err) - case syscall.EPROTONOSUPPORT, syscall.EINVAL: - } - - // See ../syscall/exec_unix.go for description of ForkLock. - syscall.ForkLock.RLock() - s, err = socketFunc(family, sotype, proto) - if err == nil { - syscall.CloseOnExec(s) - } - syscall.ForkLock.RUnlock() - if err != nil { - return -1, os.NewSyscallError("socket", err) - } - if err = syscall.SetNonblock(s, true); err != nil { - poll.CloseFunc(s) - return -1, os.NewSyscallError("setnonblock", err) - } - return s, nil -} diff --git a/contrib/go/_std_1.22/src/net/splice_linux.go b/contrib/go/_std_1.22/src/net/splice_linux.go deleted file mode 100644 index bdafcb59ab84..000000000000 --- a/contrib/go/_std_1.22/src/net/splice_linux.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "internal/poll" - "io" -) - -// spliceFrom transfers data from r to c using the splice system call to minimize -// copies from and to userspace. c must be a TCP connection. -// Currently, spliceFrom is only enabled if r is a TCP or a stream-oriented Unix connection. -// -// If spliceFrom returns handled == false, it has performed no work. -func spliceFrom(c *netFD, r io.Reader) (written int64, err error, handled bool) { - var remain int64 = 1<<63 - 1 // by default, copy until EOF - lr, ok := r.(*io.LimitedReader) - if ok { - remain, r = lr.N, lr.R - if remain <= 0 { - return 0, nil, true - } - } - - var s *netFD - switch v := r.(type) { - case *TCPConn: - s = v.fd - case tcpConnWithoutWriteTo: - s = v.fd - case *UnixConn: - if v.fd.net != "unix" { - return 0, nil, false - } - s = v.fd - default: - return 0, nil, false - } - - written, handled, sc, err := poll.Splice(&c.pfd, &s.pfd, remain) - if lr != nil { - lr.N -= written - } - return written, wrapSyscallError(sc, err), handled -} - -// spliceTo transfers data from c to w using the splice system call to minimize -// copies from and to userspace. c must be a TCP connection. -// Currently, spliceTo is only enabled if w is a stream-oriented Unix connection. -// -// If spliceTo returns handled == false, it has performed no work. -func spliceTo(w io.Writer, c *netFD) (written int64, err error, handled bool) { - uc, ok := w.(*UnixConn) - if !ok || uc.fd.net != "unix" { - return - } - - written, handled, sc, err := poll.Splice(&uc.fd.pfd, &c.pfd, 1<<63-1) - return written, wrapSyscallError(sc, err), handled -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_darwin.go b/contrib/go/_std_1.22/src/net/tcpsockopt_darwin.go deleted file mode 100644 index 53c6756e33e0..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_darwin.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "runtime" - "syscall" - "time" -) - -// syscall.TCP_KEEPINTVL is missing on some darwin architectures. -const sysTCP_KEEPINTVL = 0x101 - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects seconds so round to next highest second. - secs := int(roundDurationUp(d, time.Second)) - if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs); err != nil { - return wrapSyscallError("setsockopt", err) - } - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_dragonfly.go b/contrib/go/_std_1.22/src/net/tcpsockopt_dragonfly.go deleted file mode 100644 index b473c02b6867..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_dragonfly.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "runtime" - "syscall" - "time" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects milliseconds so round to next highest - // millisecond. - msecs := int(roundDurationUp(d, time.Millisecond)) - if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs); err != nil { - return wrapSyscallError("setsockopt", err) - } - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_openbsd.go b/contrib/go/_std_1.22/src/net/tcpsockopt_openbsd.go deleted file mode 100644 index 10e1bef3e5aa..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_openbsd.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "syscall" - "time" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // OpenBSD has no user-settable per-socket TCP keepalive - // options. - return syscall.ENOPROTOOPT -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_plan9.go b/contrib/go/_std_1.22/src/net/tcpsockopt_plan9.go deleted file mode 100644 index 264359dcf3da..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_plan9.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TCP socket options for plan9 - -package net - -import ( - "internal/itoa" - "syscall" - "time" -) - -func setNoDelay(fd *netFD, noDelay bool) error { - return syscall.EPLAN9 -} - -// Set keep alive period. -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - cmd := "keepalive " + itoa.Itoa(int(d/time.Millisecond)) - _, e := fd.ctl.WriteAt([]byte(cmd), 0) - return e -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_solaris.go b/contrib/go/_std_1.22/src/net/tcpsockopt_solaris.go deleted file mode 100644 index f15e589dc058..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_solaris.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "runtime" - "syscall" - "time" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects milliseconds so round to next highest - // millisecond. - msecs := int(roundDurationUp(d, time.Millisecond)) - - // Normally we'd do - // syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs) - // here, but we can't because Solaris does not have TCP_KEEPINTVL. - // Solaris has TCP_KEEPALIVE_ABORT_THRESHOLD, but it's not the same - // thing, it refers to the total time until aborting (not between - // probes), and it uses an exponential backoff algorithm instead of - // waiting the same time between probes. We can't hope for the best - // and do it anyway, like on Darwin, because Solaris might eventually - // allocate a constant with a different meaning for the value of - // TCP_KEEPINTVL on illumos. - - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_stub.go b/contrib/go/_std_1.22/src/net/tcpsockopt_stub.go deleted file mode 100644 index cef07cd6484e..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_stub.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build js || wasip1 - -package net - -import ( - "syscall" - "time" -) - -func setNoDelay(fd *netFD, noDelay bool) error { - return syscall.ENOPROTOOPT -} - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - return syscall.ENOPROTOOPT -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_unix.go b/contrib/go/_std_1.22/src/net/tcpsockopt_unix.go deleted file mode 100644 index bdcdc4023983..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_unix.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build aix || freebsd || linux || netbsd - -package net - -import ( - "runtime" - "syscall" - "time" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects seconds so round to next highest second. - secs := int(roundDurationUp(d, time.Second)) - if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil { - return wrapSyscallError("setsockopt", err) - } - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_windows.go b/contrib/go/_std_1.22/src/net/tcpsockopt_windows.go deleted file mode 100644 index 4a0b09465eea..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_windows.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "os" - "runtime" - "syscall" - "time" - "unsafe" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects milliseconds so round to next highest - // millisecond. - msecs := uint32(roundDurationUp(d, time.Millisecond)) - ka := syscall.TCPKeepalive{ - OnOff: 1, - Time: msecs, - Interval: msecs, - } - ret := uint32(0) - size := uint32(unsafe.Sizeof(ka)) - err := fd.pfd.WSAIoctl(syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0) - runtime.KeepAlive(fd) - return os.NewSyscallError("wsaioctl", err) -} diff --git a/contrib/go/_std_1.22/src/net/textproto/reader.go b/contrib/go/_std_1.22/src/net/textproto/reader.go deleted file mode 100644 index 793021101b30..000000000000 --- a/contrib/go/_std_1.22/src/net/textproto/reader.go +++ /dev/null @@ -1,840 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package textproto - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "io" - "math" - "strconv" - "strings" - "sync" -) - -// TODO: This should be a distinguishable error (ErrMessageTooLarge) -// to allow mime/multipart to detect it. -var errMessageTooLarge = errors.New("message too large") - -// A Reader implements convenience methods for reading requests -// or responses from a text protocol network connection. -type Reader struct { - R *bufio.Reader - dot *dotReader - buf []byte // a re-usable buffer for readContinuedLineSlice -} - -// NewReader returns a new [Reader] reading from r. -// -// To avoid denial of service attacks, the provided [bufio.Reader] -// should be reading from an [io.LimitReader] or similar Reader to bound -// the size of responses. -func NewReader(r *bufio.Reader) *Reader { - return &Reader{R: r} -} - -// ReadLine reads a single line from r, -// eliding the final \n or \r\n from the returned string. -func (r *Reader) ReadLine() (string, error) { - line, err := r.readLineSlice(-1) - return string(line), err -} - -// ReadLineBytes is like [Reader.ReadLine] but returns a []byte instead of a string. -func (r *Reader) ReadLineBytes() ([]byte, error) { - line, err := r.readLineSlice(-1) - if line != nil { - line = bytes.Clone(line) - } - return line, err -} - -// readLineSlice reads a single line from r, -// up to lim bytes long (or unlimited if lim is less than 0), -// eliding the final \r or \r\n from the returned string. -func (r *Reader) readLineSlice(lim int64) ([]byte, error) { - r.closeDot() - var line []byte - for { - l, more, err := r.R.ReadLine() - if err != nil { - return nil, err - } - if lim >= 0 && int64(len(line))+int64(len(l)) > lim { - return nil, errMessageTooLarge - } - // Avoid the copy if the first call produced a full line. - if line == nil && !more { - return l, nil - } - line = append(line, l...) - if !more { - break - } - } - return line, nil -} - -// ReadContinuedLine reads a possibly continued line from r, -// eliding the final trailing ASCII white space. -// Lines after the first are considered continuations if they -// begin with a space or tab character. In the returned data, -// continuation lines are separated from the previous line -// only by a single space: the newline and leading white space -// are removed. -// -// For example, consider this input: -// -// Line 1 -// continued... -// Line 2 -// -// The first call to ReadContinuedLine will return "Line 1 continued..." -// and the second will return "Line 2". -// -// Empty lines are never continued. -func (r *Reader) ReadContinuedLine() (string, error) { - line, err := r.readContinuedLineSlice(-1, noValidation) - return string(line), err -} - -// trim returns s with leading and trailing spaces and tabs removed. -// It does not assume Unicode or UTF-8. -func trim(s []byte) []byte { - i := 0 - for i < len(s) && (s[i] == ' ' || s[i] == '\t') { - i++ - } - n := len(s) - for n > i && (s[n-1] == ' ' || s[n-1] == '\t') { - n-- - } - return s[i:n] -} - -// ReadContinuedLineBytes is like [Reader.ReadContinuedLine] but -// returns a []byte instead of a string. -func (r *Reader) ReadContinuedLineBytes() ([]byte, error) { - line, err := r.readContinuedLineSlice(-1, noValidation) - if line != nil { - line = bytes.Clone(line) - } - return line, err -} - -// readContinuedLineSlice reads continued lines from the reader buffer, -// returning a byte slice with all lines. The validateFirstLine function -// is run on the first read line, and if it returns an error then this -// error is returned from readContinuedLineSlice. -// It reads up to lim bytes of data (or unlimited if lim is less than 0). -func (r *Reader) readContinuedLineSlice(lim int64, validateFirstLine func([]byte) error) ([]byte, error) { - if validateFirstLine == nil { - return nil, fmt.Errorf("missing validateFirstLine func") - } - - // Read the first line. - line, err := r.readLineSlice(lim) - if err != nil { - return nil, err - } - if len(line) == 0 { // blank line - no continuation - return line, nil - } - - if err := validateFirstLine(line); err != nil { - return nil, err - } - - // Optimistically assume that we have started to buffer the next line - // and it starts with an ASCII letter (the next header key), or a blank - // line, so we can avoid copying that buffered data around in memory - // and skipping over non-existent whitespace. - if r.R.Buffered() > 1 { - peek, _ := r.R.Peek(2) - if len(peek) > 0 && (isASCIILetter(peek[0]) || peek[0] == '\n') || - len(peek) == 2 && peek[0] == '\r' && peek[1] == '\n' { - return trim(line), nil - } - } - - // ReadByte or the next readLineSlice will flush the read buffer; - // copy the slice into buf. - r.buf = append(r.buf[:0], trim(line)...) - - if lim < 0 { - lim = math.MaxInt64 - } - lim -= int64(len(r.buf)) - - // Read continuation lines. - for r.skipSpace() > 0 { - r.buf = append(r.buf, ' ') - if int64(len(r.buf)) >= lim { - return nil, errMessageTooLarge - } - line, err := r.readLineSlice(lim - int64(len(r.buf))) - if err != nil { - break - } - r.buf = append(r.buf, trim(line)...) - } - return r.buf, nil -} - -// skipSpace skips R over all spaces and returns the number of bytes skipped. -func (r *Reader) skipSpace() int { - n := 0 - for { - c, err := r.R.ReadByte() - if err != nil { - // Bufio will keep err until next read. - break - } - if c != ' ' && c != '\t' { - r.R.UnreadByte() - break - } - n++ - } - return n -} - -func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err error) { - line, err := r.ReadLine() - if err != nil { - return - } - return parseCodeLine(line, expectCode) -} - -func parseCodeLine(line string, expectCode int) (code int, continued bool, message string, err error) { - if len(line) < 4 || line[3] != ' ' && line[3] != '-' { - err = ProtocolError("short response: " + line) - return - } - continued = line[3] == '-' - code, err = strconv.Atoi(line[0:3]) - if err != nil || code < 100 { - err = ProtocolError("invalid response code: " + line) - return - } - message = line[4:] - if 1 <= expectCode && expectCode < 10 && code/100 != expectCode || - 10 <= expectCode && expectCode < 100 && code/10 != expectCode || - 100 <= expectCode && expectCode < 1000 && code != expectCode { - err = &Error{code, message} - } - return -} - -// ReadCodeLine reads a response code line of the form -// -// code message -// -// where code is a three-digit status code and the message -// extends to the rest of the line. An example of such a line is: -// -// 220 plan9.bell-labs.com ESMTP -// -// If the prefix of the status does not match the digits in expectCode, -// ReadCodeLine returns with err set to &Error{code, message}. -// For example, if expectCode is 31, an error will be returned if -// the status is not in the range [310,319]. -// -// If the response is multi-line, ReadCodeLine returns an error. -// -// An expectCode <= 0 disables the check of the status code. -func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err error) { - code, continued, message, err := r.readCodeLine(expectCode) - if err == nil && continued { - err = ProtocolError("unexpected multi-line response: " + message) - } - return -} - -// ReadResponse reads a multi-line response of the form: -// -// code-message line 1 -// code-message line 2 -// ... -// code message line n -// -// where code is a three-digit status code. The first line starts with the -// code and a hyphen. The response is terminated by a line that starts -// with the same code followed by a space. Each line in message is -// separated by a newline (\n). -// -// See page 36 of RFC 959 (https://www.ietf.org/rfc/rfc959.txt) for -// details of another form of response accepted: -// -// code-message line 1 -// message line 2 -// ... -// code message line n -// -// If the prefix of the status does not match the digits in expectCode, -// ReadResponse returns with err set to &Error{code, message}. -// For example, if expectCode is 31, an error will be returned if -// the status is not in the range [310,319]. -// -// An expectCode <= 0 disables the check of the status code. -func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error) { - code, continued, message, err := r.readCodeLine(expectCode) - multi := continued - for continued { - line, err := r.ReadLine() - if err != nil { - return 0, "", err - } - - var code2 int - var moreMessage string - code2, continued, moreMessage, err = parseCodeLine(line, 0) - if err != nil || code2 != code { - message += "\n" + strings.TrimRight(line, "\r\n") - continued = true - continue - } - message += "\n" + moreMessage - } - if err != nil && multi && message != "" { - // replace one line error message with all lines (full message) - err = &Error{code, message} - } - return -} - -// DotReader returns a new [Reader] that satisfies Reads using the -// decoded text of a dot-encoded block read from r. -// The returned Reader is only valid until the next call -// to a method on r. -// -// Dot encoding is a common framing used for data blocks -// in text protocols such as SMTP. The data consists of a sequence -// of lines, each of which ends in "\r\n". The sequence itself -// ends at a line containing just a dot: ".\r\n". Lines beginning -// with a dot are escaped with an additional dot to avoid -// looking like the end of the sequence. -// -// The decoded form returned by the Reader's Read method -// rewrites the "\r\n" line endings into the simpler "\n", -// removes leading dot escapes if present, and stops with error [io.EOF] -// after consuming (and discarding) the end-of-sequence line. -func (r *Reader) DotReader() io.Reader { - r.closeDot() - r.dot = &dotReader{r: r} - return r.dot -} - -type dotReader struct { - r *Reader - state int -} - -// Read satisfies reads by decoding dot-encoded data read from d.r. -func (d *dotReader) Read(b []byte) (n int, err error) { - // Run data through a simple state machine to - // elide leading dots, rewrite trailing \r\n into \n, - // and detect ending .\r\n line. - const ( - stateBeginLine = iota // beginning of line; initial state; must be zero - stateDot // read . at beginning of line - stateDotCR // read .\r at beginning of line - stateCR // read \r (possibly at end of line) - stateData // reading data in middle of line - stateEOF // reached .\r\n end marker line - ) - br := d.r.R - for n < len(b) && d.state != stateEOF { - var c byte - c, err = br.ReadByte() - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - break - } - switch d.state { - case stateBeginLine: - if c == '.' { - d.state = stateDot - continue - } - if c == '\r' { - d.state = stateCR - continue - } - d.state = stateData - - case stateDot: - if c == '\r' { - d.state = stateDotCR - continue - } - if c == '\n' { - d.state = stateEOF - continue - } - d.state = stateData - - case stateDotCR: - if c == '\n' { - d.state = stateEOF - continue - } - // Not part of .\r\n. - // Consume leading dot and emit saved \r. - br.UnreadByte() - c = '\r' - d.state = stateData - - case stateCR: - if c == '\n' { - d.state = stateBeginLine - break - } - // Not part of \r\n. Emit saved \r - br.UnreadByte() - c = '\r' - d.state = stateData - - case stateData: - if c == '\r' { - d.state = stateCR - continue - } - if c == '\n' { - d.state = stateBeginLine - } - } - b[n] = c - n++ - } - if err == nil && d.state == stateEOF { - err = io.EOF - } - if err != nil && d.r.dot == d { - d.r.dot = nil - } - return -} - -// closeDot drains the current DotReader if any, -// making sure that it reads until the ending dot line. -func (r *Reader) closeDot() { - if r.dot == nil { - return - } - buf := make([]byte, 128) - for r.dot != nil { - // When Read reaches EOF or an error, - // it will set r.dot == nil. - r.dot.Read(buf) - } -} - -// ReadDotBytes reads a dot-encoding and returns the decoded data. -// -// See the documentation for the [Reader.DotReader] method for details about dot-encoding. -func (r *Reader) ReadDotBytes() ([]byte, error) { - return io.ReadAll(r.DotReader()) -} - -// ReadDotLines reads a dot-encoding and returns a slice -// containing the decoded lines, with the final \r\n or \n elided from each. -// -// See the documentation for the [Reader.DotReader] method for details about dot-encoding. -func (r *Reader) ReadDotLines() ([]string, error) { - // We could use ReadDotBytes and then Split it, - // but reading a line at a time avoids needing a - // large contiguous block of memory and is simpler. - var v []string - var err error - for { - var line string - line, err = r.ReadLine() - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - break - } - - // Dot by itself marks end; otherwise cut one dot. - if len(line) > 0 && line[0] == '.' { - if len(line) == 1 { - break - } - line = line[1:] - } - v = append(v, line) - } - return v, err -} - -var colon = []byte(":") - -// ReadMIMEHeader reads a MIME-style header from r. -// The header is a sequence of possibly continued Key: Value lines -// ending in a blank line. -// The returned map m maps [CanonicalMIMEHeaderKey](key) to a -// sequence of values in the same order encountered in the input. -// -// For example, consider this input: -// -// My-Key: Value 1 -// Long-Key: Even -// Longer Value -// My-Key: Value 2 -// -// Given that input, ReadMIMEHeader returns the map: -// -// map[string][]string{ -// "My-Key": {"Value 1", "Value 2"}, -// "Long-Key": {"Even Longer Value"}, -// } -func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { - return readMIMEHeader(r, math.MaxInt64, math.MaxInt64) -} - -// readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. -// It is called by the mime/multipart package. -func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) { - // Avoid lots of small slice allocations later by allocating one - // large one ahead of time which we'll cut up into smaller - // slices. If this isn't big enough later, we allocate small ones. - var strs []string - hint := r.upcomingHeaderKeys() - if hint > 0 { - if hint > 1000 { - hint = 1000 // set a cap to avoid overallocation - } - strs = make([]string, hint) - } - - m := make(MIMEHeader, hint) - - // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. - // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large - // MIMEHeaders average about 200 bytes per entry. - maxMemory -= 400 - const mapEntryOverhead = 200 - - // The first line cannot start with a leading space. - if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { - const errorLimit = 80 // arbitrary limit on how much of the line we'll quote - line, err := r.readLineSlice(errorLimit) - if err != nil { - return m, err - } - return m, ProtocolError("malformed MIME header initial line: " + string(line)) - } - - for { - kv, err := r.readContinuedLineSlice(maxMemory, mustHaveFieldNameColon) - if len(kv) == 0 { - return m, err - } - - // Key ends at first colon. - k, v, ok := bytes.Cut(kv, colon) - if !ok { - return m, ProtocolError("malformed MIME header line: " + string(kv)) - } - key, ok := canonicalMIMEHeaderKey(k) - if !ok { - return m, ProtocolError("malformed MIME header line: " + string(kv)) - } - for _, c := range v { - if !validHeaderValueByte(c) { - return m, ProtocolError("malformed MIME header line: " + string(kv)) - } - } - - // As per RFC 7230 field-name is a token, tokens consist of one or more chars. - // We could return a ProtocolError here, but better to be liberal in what we - // accept, so if we get an empty key, skip it. - if key == "" { - continue - } - - maxHeaders-- - if maxHeaders < 0 { - return nil, errMessageTooLarge - } - - // Skip initial spaces in value. - value := string(bytes.TrimLeft(v, " \t")) - - vv := m[key] - if vv == nil { - maxMemory -= int64(len(key)) - maxMemory -= mapEntryOverhead - } - maxMemory -= int64(len(value)) - if maxMemory < 0 { - return m, errMessageTooLarge - } - if vv == nil && len(strs) > 0 { - // More than likely this will be a single-element key. - // Most headers aren't multi-valued. - // Set the capacity on strs[0] to 1, so any future append - // won't extend the slice into the other strings. - vv, strs = strs[:1:1], strs[1:] - vv[0] = value - m[key] = vv - } else { - m[key] = append(vv, value) - } - - if err != nil { - return m, err - } - } -} - -// noValidation is a no-op validation func for readContinuedLineSlice -// that permits any lines. -func noValidation(_ []byte) error { return nil } - -// mustHaveFieldNameColon ensures that, per RFC 7230, the -// field-name is on a single line, so the first line must -// contain a colon. -func mustHaveFieldNameColon(line []byte) error { - if bytes.IndexByte(line, ':') < 0 { - return ProtocolError(fmt.Sprintf("malformed MIME header: missing colon: %q", line)) - } - return nil -} - -var nl = []byte("\n") - -// upcomingHeaderKeys returns an approximation of the number of keys -// that will be in this header. If it gets confused, it returns 0. -func (r *Reader) upcomingHeaderKeys() (n int) { - // Try to determine the 'hint' size. - r.R.Peek(1) // force a buffer load if empty - s := r.R.Buffered() - if s == 0 { - return - } - peek, _ := r.R.Peek(s) - for len(peek) > 0 && n < 1000 { - var line []byte - line, peek, _ = bytes.Cut(peek, nl) - if len(line) == 0 || (len(line) == 1 && line[0] == '\r') { - // Blank line separating headers from the body. - break - } - if line[0] == ' ' || line[0] == '\t' { - // Folded continuation of the previous line. - continue - } - n++ - } - return n -} - -// CanonicalMIMEHeaderKey returns the canonical format of the -// MIME header key s. The canonicalization converts the first -// letter and any letter following a hyphen to upper case; -// the rest are converted to lowercase. For example, the -// canonical key for "accept-encoding" is "Accept-Encoding". -// MIME header keys are assumed to be ASCII only. -// If s contains a space or invalid header field bytes, it is -// returned without modifications. -func CanonicalMIMEHeaderKey(s string) string { - // Quick check for canonical encoding. - upper := true - for i := 0; i < len(s); i++ { - c := s[i] - if !validHeaderFieldByte(c) { - return s - } - if upper && 'a' <= c && c <= 'z' { - s, _ = canonicalMIMEHeaderKey([]byte(s)) - return s - } - if !upper && 'A' <= c && c <= 'Z' { - s, _ = canonicalMIMEHeaderKey([]byte(s)) - return s - } - upper = c == '-' - } - return s -} - -const toLower = 'a' - 'A' - -// validHeaderFieldByte reports whether c is a valid byte in a header -// field name. RFC 7230 says: -// -// header-field = field-name ":" OWS field-value OWS -// field-name = token -// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / -// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA -// token = 1*tchar -func validHeaderFieldByte(c byte) bool { - // mask is a 128-bit bitmap with 1s for allowed bytes, - // so that the byte c can be tested with a shift and an and. - // If c >= 128, then 1<>64)) != 0 -} - -// validHeaderValueByte reports whether c is a valid byte in a header -// field value. RFC 7230 says: -// -// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] -// field-vchar = VCHAR / obs-text -// obs-text = %x80-FF -// -// RFC 5234 says: -// -// HTAB = %x09 -// SP = %x20 -// VCHAR = %x21-7E -func validHeaderValueByte(c byte) bool { - // mask is a 128-bit bitmap with 1s for allowed bytes, - // so that the byte c can be tested with a shift and an and. - // If c >= 128, then 1<>64)) == 0 -} - -// canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is -// allowed to mutate the provided byte slice before returning the -// string. -// -// For invalid inputs (if a contains spaces or non-token bytes), a -// is unchanged and a string copy is returned. -// -// ok is true if the header key contains only valid characters and spaces. -// ReadMIMEHeader accepts header keys containing spaces, but does not -// canonicalize them. -func canonicalMIMEHeaderKey(a []byte) (_ string, ok bool) { - // See if a looks like a header key. If not, return it unchanged. - noCanon := false - for _, c := range a { - if validHeaderFieldByte(c) { - continue - } - // Don't canonicalize. - if c == ' ' { - // We accept invalid headers with a space before the - // colon, but must not canonicalize them. - // See https://go.dev/issue/34540. - noCanon = true - continue - } - return string(a), false - } - if noCanon { - return string(a), true - } - - upper := true - for i, c := range a { - // Canonicalize: first letter upper case - // and upper case after each dash. - // (Host, User-Agent, If-Modified-Since). - // MIME headers are ASCII only, so no Unicode issues. - if upper && 'a' <= c && c <= 'z' { - c -= toLower - } else if !upper && 'A' <= c && c <= 'Z' { - c += toLower - } - a[i] = c - upper = c == '-' // for next time - } - commonHeaderOnce.Do(initCommonHeader) - // The compiler recognizes m[string(byteSlice)] as a special - // case, so a copy of a's bytes into a new string does not - // happen in this map lookup: - if v := commonHeader[string(a)]; v != "" { - return v, true - } - return string(a), true -} - -// commonHeader interns common header strings. -var commonHeader map[string]string - -var commonHeaderOnce sync.Once - -func initCommonHeader() { - commonHeader = make(map[string]string) - for _, v := range []string{ - "Accept", - "Accept-Charset", - "Accept-Encoding", - "Accept-Language", - "Accept-Ranges", - "Cache-Control", - "Cc", - "Connection", - "Content-Id", - "Content-Language", - "Content-Length", - "Content-Transfer-Encoding", - "Content-Type", - "Cookie", - "Date", - "Dkim-Signature", - "Etag", - "Expires", - "From", - "Host", - "If-Modified-Since", - "If-None-Match", - "In-Reply-To", - "Last-Modified", - "Location", - "Message-Id", - "Mime-Version", - "Pragma", - "Received", - "Return-Path", - "Server", - "Set-Cookie", - "Subject", - "To", - "User-Agent", - "Via", - "X-Forwarded-For", - "X-Imforwards", - "X-Powered-By", - } { - commonHeader[v] = v - } -} diff --git a/contrib/go/_std_1.22/src/net/ya.make b/contrib/go/_std_1.22/src/net/ya.make deleted file mode 100644 index a6cdbd8d6caf..000000000000 --- a/contrib/go/_std_1.22/src/net/ya.make +++ /dev/null @@ -1,325 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED) - SRCS( - addrselect.go - cgo_darwin.go - cgo_unix.go - cgo_unix_syscall.go - conf.go - dial.go - dnsclient.go - dnsclient_unix.go - dnsconfig.go - dnsconfig_unix.go - error_posix.go - error_unix.go - fd_posix.go - fd_unix.go - file.go - file_unix.go - hook.go - hook_unix.go - hosts.go - interface.go - interface_bsd.go - interface_darwin.go - ip.go - iprawsock.go - iprawsock_posix.go - ipsock.go - ipsock_posix.go - lookup.go - lookup_unix.go - mac.go - mptcpsock_stub.go - net.go - netcgo_off.go - netgo_off.go - nss.go - parse.go - pipe.go - port.go - port_unix.go - rawconn.go - rlimit_unix.go - sendfile_unix_alt.go - sock_bsd.go - sock_posix.go - sockaddr_posix.go - sockopt_bsd.go - sockopt_posix.go - sockoptip_bsdvar.go - sockoptip_posix.go - splice_stub.go - sys_cloexec.go - tcpsock.go - tcpsock_posix.go - tcpsockopt_darwin.go - tcpsockopt_posix.go - udpsock.go - udpsock_posix.go - unixsock.go - unixsock_posix.go - unixsock_readmsg_cloexec.go - writev_unix.go - ) - -IF (CGO_ENABLED) - CGO_SRCS( - cgo_unix_cgo_darwin.go - ) -ENDIF() -ELSEIF (OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - addrselect.go - cgo_darwin.go - cgo_unix.go - cgo_unix_syscall.go - conf.go - dial.go - dnsclient.go - dnsclient_unix.go - dnsconfig.go - dnsconfig_unix.go - error_posix.go - error_unix.go - fd_posix.go - fd_unix.go - file.go - file_unix.go - hook.go - hook_unix.go - hosts.go - interface.go - interface_bsd.go - interface_darwin.go - ip.go - iprawsock.go - iprawsock_posix.go - ipsock.go - ipsock_posix.go - lookup.go - lookup_unix.go - mac.go - mptcpsock_stub.go - net.go - netcgo_off.go - netgo_off.go - nss.go - parse.go - pipe.go - port.go - port_unix.go - rawconn.go - rlimit_unix.go - sendfile_unix_alt.go - sock_bsd.go - sock_posix.go - sockaddr_posix.go - sockopt_bsd.go - sockopt_posix.go - sockoptip_bsdvar.go - sockoptip_posix.go - splice_stub.go - sys_cloexec.go - tcpsock.go - tcpsock_posix.go - tcpsockopt_darwin.go - tcpsockopt_posix.go - udpsock.go - udpsock_posix.go - unixsock.go - unixsock_posix.go - unixsock_readmsg_cloexec.go - writev_unix.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED) - SRCS( - addrselect.go - cgo_unix.go - conf.go - dial.go - dnsclient.go - dnsclient_unix.go - dnsconfig.go - dnsconfig_unix.go - error_posix.go - error_unix.go - fd_posix.go - fd_unix.go - file.go - file_unix.go - hook.go - hook_unix.go - hosts.go - interface.go - interface_linux.go - ip.go - iprawsock.go - iprawsock_posix.go - ipsock.go - ipsock_posix.go - lookup.go - lookup_unix.go - mac.go - mptcpsock_linux.go - net.go - netcgo_off.go - netgo_off.go - nss.go - parse.go - pipe.go - port.go - port_unix.go - rawconn.go - rlimit_unix.go - sendfile_linux.go - sock_cloexec.go - sock_linux.go - sock_posix.go - sockaddr_posix.go - sockopt_linux.go - sockopt_posix.go - sockoptip_linux.go - sockoptip_posix.go - splice_linux.go - tcpsock.go - tcpsock_posix.go - tcpsockopt_posix.go - tcpsockopt_unix.go - udpsock.go - udpsock_posix.go - unixsock.go - unixsock_posix.go - unixsock_readmsg_cmsg_cloexec.go - writev_unix.go - ) - -IF (CGO_ENABLED) - CGO_SRCS( - cgo_linux.go - cgo_resnew.go - cgo_socknew.go - cgo_unix_cgo.go - cgo_unix_cgo_res.go - ) -ENDIF() -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - addrselect.go - cgo_stub.go - conf.go - dial.go - dnsclient.go - dnsclient_unix.go - dnsconfig.go - dnsconfig_unix.go - error_posix.go - error_unix.go - fd_posix.go - fd_unix.go - file.go - file_unix.go - hook.go - hook_unix.go - hosts.go - interface.go - interface_linux.go - ip.go - iprawsock.go - iprawsock_posix.go - ipsock.go - ipsock_posix.go - lookup.go - lookup_unix.go - mac.go - mptcpsock_linux.go - net.go - netcgo_off.go - netgo_off.go - nss.go - parse.go - pipe.go - port.go - port_unix.go - rawconn.go - rlimit_unix.go - sendfile_linux.go - sock_cloexec.go - sock_linux.go - sock_posix.go - sockaddr_posix.go - sockopt_linux.go - sockopt_posix.go - sockoptip_linux.go - sockoptip_posix.go - splice_linux.go - tcpsock.go - tcpsock_posix.go - tcpsockopt_posix.go - tcpsockopt_unix.go - udpsock.go - udpsock_posix.go - unixsock.go - unixsock_posix.go - unixsock_readmsg_cmsg_cloexec.go - writev_unix.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - addrselect.go - conf.go - dial.go - dnsclient.go - dnsclient_unix.go - dnsconfig.go - dnsconfig_windows.go - error_posix.go - error_windows.go - fd_posix.go - fd_windows.go - file.go - file_windows.go - hook.go - hook_windows.go - hosts.go - interface.go - interface_windows.go - ip.go - iprawsock.go - iprawsock_posix.go - ipsock.go - ipsock_posix.go - lookup.go - lookup_windows.go - mac.go - mptcpsock_stub.go - net.go - netcgo_off.go - netgo_off.go - nss.go - parse.go - pipe.go - port.go - rawconn.go - sendfile_windows.go - sock_posix.go - sock_windows.go - sockaddr_posix.go - sockopt_posix.go - sockopt_windows.go - sockoptip_posix.go - sockoptip_windows.go - splice_stub.go - tcpsock.go - tcpsock_posix.go - tcpsockopt_posix.go - tcpsockopt_windows.go - udpsock.go - udpsock_posix.go - unixsock.go - unixsock_posix.go - unixsock_readmsg_other.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/os/dir.go b/contrib/go/_std_1.22/src/os/dir.go deleted file mode 100644 index 5306bcb3ba7c..000000000000 --- a/contrib/go/_std_1.22/src/os/dir.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "io/fs" - "sort" -) - -type readdirMode int - -const ( - readdirName readdirMode = iota - readdirDirEntry - readdirFileInfo -) - -// Readdir reads the contents of the directory associated with file and -// returns a slice of up to n FileInfo values, as would be returned -// by Lstat, in directory order. Subsequent calls on the same file will yield -// further FileInfos. -// -// If n > 0, Readdir returns at most n FileInfo structures. In this case, if -// Readdir returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. -// -// If n <= 0, Readdir returns all the FileInfo from the directory in -// a single slice. In this case, if Readdir succeeds (reads all -// the way to the end of the directory), it returns the slice and a -// nil error. If it encounters an error before the end of the -// directory, Readdir returns the FileInfo read until that point -// and a non-nil error. -// -// Most clients are better served by the more efficient ReadDir method. -func (f *File) Readdir(n int) ([]FileInfo, error) { - if f == nil { - return nil, ErrInvalid - } - _, _, infos, err := f.readdir(n, readdirFileInfo) - if infos == nil { - // Readdir has historically always returned a non-nil empty slice, never nil, - // even on error (except misuse with nil receiver above). - // Keep it that way to avoid breaking overly sensitive callers. - infos = []FileInfo{} - } - return infos, err -} - -// Readdirnames reads the contents of the directory associated with file -// and returns a slice of up to n names of files in the directory, -// in directory order. Subsequent calls on the same file will yield -// further names. -// -// If n > 0, Readdirnames returns at most n names. In this case, if -// Readdirnames returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. -// -// If n <= 0, Readdirnames returns all the names from the directory in -// a single slice. In this case, if Readdirnames succeeds (reads all -// the way to the end of the directory), it returns the slice and a -// nil error. If it encounters an error before the end of the -// directory, Readdirnames returns the names read until that point and -// a non-nil error. -func (f *File) Readdirnames(n int) (names []string, err error) { - if f == nil { - return nil, ErrInvalid - } - names, _, _, err = f.readdir(n, readdirName) - if names == nil { - // Readdirnames has historically always returned a non-nil empty slice, never nil, - // even on error (except misuse with nil receiver above). - // Keep it that way to avoid breaking overly sensitive callers. - names = []string{} - } - return names, err -} - -// A DirEntry is an entry read from a directory -// (using the ReadDir function or a File's ReadDir method). -type DirEntry = fs.DirEntry - -// ReadDir reads the contents of the directory associated with the file f -// and returns a slice of DirEntry values in directory order. -// Subsequent calls on the same file will yield later DirEntry records in the directory. -// -// If n > 0, ReadDir returns at most n DirEntry records. -// In this case, if ReadDir returns an empty slice, it will return an error explaining why. -// At the end of a directory, the error is io.EOF. -// -// If n <= 0, ReadDir returns all the DirEntry records remaining in the directory. -// When it succeeds, it returns a nil error (not io.EOF). -func (f *File) ReadDir(n int) ([]DirEntry, error) { - if f == nil { - return nil, ErrInvalid - } - _, dirents, _, err := f.readdir(n, readdirDirEntry) - if dirents == nil { - // Match Readdir and Readdirnames: don't return nil slices. - dirents = []DirEntry{} - } - return dirents, err -} - -// testingForceReadDirLstat forces ReadDir to call Lstat, for testing that code path. -// This can be difficult to provoke on some Unix systems otherwise. -var testingForceReadDirLstat bool - -// ReadDir reads the named directory, -// returning all its directory entries sorted by filename. -// If an error occurs reading the directory, -// ReadDir returns the entries it was able to read before the error, -// along with the error. -func ReadDir(name string) ([]DirEntry, error) { - f, err := Open(name) - if err != nil { - return nil, err - } - defer f.Close() - - dirs, err := f.ReadDir(-1) - sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() }) - return dirs, err -} diff --git a/contrib/go/_std_1.22/src/os/dir_plan9.go b/contrib/go/_std_1.22/src/os/dir_plan9.go deleted file mode 100644 index 6ea5940e71df..000000000000 --- a/contrib/go/_std_1.22/src/os/dir_plan9.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "io" - "io/fs" - "syscall" -) - -func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { - // If this file has no dirinfo, create one. - if file.dirinfo == nil { - file.dirinfo = new(dirInfo) - } - d := file.dirinfo - size := n - if size <= 0 { - size = 100 - n = -1 - } - for n != 0 { - // Refill the buffer if necessary. - if d.bufp >= d.nbuf { - nb, err := file.Read(d.buf[:]) - - // Update the buffer state before checking for errors. - d.bufp, d.nbuf = 0, nb - - if err != nil { - if err == io.EOF { - break - } - return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: err} - } - if nb < syscall.STATFIXLEN { - return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: syscall.ErrShortStat} - } - } - - // Get a record from the buffer. - b := d.buf[d.bufp:] - m := int(uint16(b[0])|uint16(b[1])<<8) + 2 - if m < syscall.STATFIXLEN { - return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: syscall.ErrShortStat} - } - - dir, err := syscall.UnmarshalDir(b[:m]) - if err != nil { - return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: err} - } - - if mode == readdirName { - names = append(names, dir.Name) - } else { - f := fileInfoFromStat(dir) - if mode == readdirDirEntry { - dirents = append(dirents, dirEntry{f}) - } else { - infos = append(infos, f) - } - } - d.bufp += m - n-- - } - - if n > 0 && len(names)+len(dirents)+len(infos) == 0 { - return nil, nil, nil, io.EOF - } - return names, dirents, infos, nil -} - -type dirEntry struct { - fs *fileStat -} - -func (de dirEntry) Name() string { return de.fs.Name() } -func (de dirEntry) IsDir() bool { return de.fs.IsDir() } -func (de dirEntry) Type() FileMode { return de.fs.Mode().Type() } -func (de dirEntry) Info() (FileInfo, error) { return de.fs, nil } - -func (de dirEntry) String() string { - return fs.FormatDirEntry(de) -} diff --git a/contrib/go/_std_1.22/src/os/dir_windows.go b/contrib/go/_std_1.22/src/os/dir_windows.go deleted file mode 100644 index 4485dffdb184..000000000000 --- a/contrib/go/_std_1.22/src/os/dir_windows.go +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "internal/syscall/windows" - "io" - "io/fs" - "runtime" - "sync" - "syscall" - "unsafe" -) - -// Auxiliary information if the File describes a directory -type dirInfo struct { - // buf is a slice pointer so the slice header - // does not escape to the heap when returning - // buf to dirBufPool. - buf *[]byte // buffer for directory I/O - bufp int // location of next record in buf - vol uint32 - class uint32 // type of entries in buf - path string // absolute directory path, empty if the file system supports FILE_ID_BOTH_DIR_INFO -} - -const ( - // dirBufSize is the size of the dirInfo buffer. - // The buffer must be big enough to hold at least a single entry. - // The filename alone can be 512 bytes (MAX_PATH*2), and the fixed part of - // the FILE_ID_BOTH_DIR_INFO structure is 105 bytes, so dirBufSize - // should not be set below 1024 bytes (512+105+safety buffer). - // Windows 8.1 and earlier only works with buffer sizes up to 64 kB. - dirBufSize = 64 * 1024 // 64kB -) - -var dirBufPool = sync.Pool{ - New: func() any { - // The buffer must be at least a block long. - buf := make([]byte, dirBufSize) - return &buf - }, -} - -func (d *dirInfo) close() { - if d.buf != nil { - dirBufPool.Put(d.buf) - d.buf = nil - } -} - -// allowReadDirFileID indicates whether File.readdir should try to use FILE_ID_BOTH_DIR_INFO -// if the underlying file system supports it. -// Useful for testing purposes. -var allowReadDirFileID = true - -func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { - // If this file has no dirinfo, create one. - if file.dirinfo == nil { - // vol is used by os.SameFile. - // It is safe to query it once and reuse the value. - // Hard links are not allowed to reference files in other volumes. - // Junctions and symbolic links can reference files and directories in other volumes, - // but the reparse point should still live in the parent volume. - var vol, flags uint32 - err = windows.GetVolumeInformationByHandle(file.pfd.Sysfd, nil, 0, &vol, nil, &flags, nil, 0) - runtime.KeepAlive(file) - if err != nil { - err = &PathError{Op: "readdir", Path: file.name, Err: err} - return - } - file.dirinfo = new(dirInfo) - file.dirinfo.buf = dirBufPool.Get().(*[]byte) - file.dirinfo.vol = vol - if allowReadDirFileID && flags&windows.FILE_SUPPORTS_OPEN_BY_FILE_ID != 0 { - file.dirinfo.class = windows.FileIdBothDirectoryRestartInfo - } else { - file.dirinfo.class = windows.FileFullDirectoryRestartInfo - // Set the directory path for use by os.SameFile, as it is possible that - // the file system supports retrieving the file ID using GetFileInformationByHandle. - file.dirinfo.path = file.name - if !isAbs(file.dirinfo.path) { - // If the path is relative, we need to convert it to an absolute path - // in case the current directory changes between this call and a - // call to os.SameFile. - file.dirinfo.path, err = syscall.FullPath(file.dirinfo.path) - if err != nil { - err = &PathError{Op: "readdir", Path: file.name, Err: err} - return - } - } - } - } - d := file.dirinfo - wantAll := n <= 0 - if wantAll { - n = -1 - } - for n != 0 { - // Refill the buffer if necessary - if d.bufp == 0 { - err = windows.GetFileInformationByHandleEx(file.pfd.Sysfd, d.class, (*byte)(unsafe.Pointer(&(*d.buf)[0])), uint32(len(*d.buf))) - runtime.KeepAlive(file) - if err != nil { - if err == syscall.ERROR_NO_MORE_FILES { - break - } - if err == syscall.ERROR_FILE_NOT_FOUND && - (d.class == windows.FileIdBothDirectoryRestartInfo || d.class == windows.FileFullDirectoryRestartInfo) { - // GetFileInformationByHandleEx doesn't document the return error codes when the info class is FileIdBothDirectoryRestartInfo, - // but MS-FSA 2.1.5.6.3 [1] specifies that the underlying file system driver should return STATUS_NO_SUCH_FILE when - // reading an empty root directory, which is mapped to ERROR_FILE_NOT_FOUND by Windows. - // Note that some file system drivers may never return this error code, as the spec allows to return the "." and ".." - // entries in such cases, making the directory appear non-empty. - // The chances of false positive are very low, as we know that the directory exists, else GetVolumeInformationByHandle - // would have failed, and that the handle is still valid, as we haven't closed it. - // See go.dev/issue/61159. - // [1] https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fsa/fa8194e0-53ec-413b-8315-e8fa85396fd8 - break - } - if s, _ := file.Stat(); s != nil && !s.IsDir() { - err = &PathError{Op: "readdir", Path: file.name, Err: syscall.ENOTDIR} - } else { - err = &PathError{Op: "GetFileInformationByHandleEx", Path: file.name, Err: err} - } - return - } - if d.class == windows.FileIdBothDirectoryRestartInfo { - d.class = windows.FileIdBothDirectoryInfo - } else if d.class == windows.FileFullDirectoryRestartInfo { - d.class = windows.FileFullDirectoryInfo - } - } - // Drain the buffer - var islast bool - for n != 0 && !islast { - var nextEntryOffset uint32 - var nameslice []uint16 - entry := unsafe.Pointer(&(*d.buf)[d.bufp]) - if d.class == windows.FileIdBothDirectoryInfo { - info := (*windows.FILE_ID_BOTH_DIR_INFO)(entry) - nextEntryOffset = info.NextEntryOffset - nameslice = unsafe.Slice(&info.FileName[0], info.FileNameLength/2) - } else { - info := (*windows.FILE_FULL_DIR_INFO)(entry) - nextEntryOffset = info.NextEntryOffset - nameslice = unsafe.Slice(&info.FileName[0], info.FileNameLength/2) - } - d.bufp += int(nextEntryOffset) - islast = nextEntryOffset == 0 - if islast { - d.bufp = 0 - } - if (len(nameslice) == 1 && nameslice[0] == '.') || - (len(nameslice) == 2 && nameslice[0] == '.' && nameslice[1] == '.') { - // Ignore "." and ".." and avoid allocating a string for them. - continue - } - name := syscall.UTF16ToString(nameslice) - if mode == readdirName { - names = append(names, name) - } else { - var f *fileStat - if d.class == windows.FileIdBothDirectoryInfo { - f = newFileStatFromFileIDBothDirInfo((*windows.FILE_ID_BOTH_DIR_INFO)(entry)) - } else { - f = newFileStatFromFileFullDirInfo((*windows.FILE_FULL_DIR_INFO)(entry)) - // Defer appending the entry name to the parent directory path until - // it is really needed, to avoid allocating a string that may not be used. - // It is currently only used in os.SameFile. - f.appendNameToPath = true - f.path = d.path - } - f.name = name - f.vol = d.vol - if mode == readdirDirEntry { - dirents = append(dirents, dirEntry{f}) - } else { - infos = append(infos, f) - } - } - n-- - } - } - if !wantAll && len(names)+len(dirents)+len(infos) == 0 { - return nil, nil, nil, io.EOF - } - return names, dirents, infos, nil -} - -type dirEntry struct { - fs *fileStat -} - -func (de dirEntry) Name() string { return de.fs.Name() } -func (de dirEntry) IsDir() bool { return de.fs.IsDir() } -func (de dirEntry) Type() FileMode { return de.fs.Mode().Type() } -func (de dirEntry) Info() (FileInfo, error) { return de.fs, nil } - -func (de dirEntry) String() string { - return fs.FormatDirEntry(de) -} diff --git a/contrib/go/_std_1.22/src/os/endian_big.go b/contrib/go/_std_1.22/src/os/endian_big.go deleted file mode 100644 index 0375e533726e..000000000000 --- a/contrib/go/_std_1.22/src/os/endian_big.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -//go:build ppc64 || s390x || mips || mips64 - -package os - -const isBigEndian = true diff --git a/contrib/go/_std_1.22/src/os/endian_little.go b/contrib/go/_std_1.22/src/os/endian_little.go deleted file mode 100644 index a7cf1cdda8e4..000000000000 --- a/contrib/go/_std_1.22/src/os/endian_little.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -//go:build 386 || amd64 || arm || arm64 || loong64 || ppc64le || mips64le || mipsle || riscv64 || wasm - -package os - -const isBigEndian = false diff --git a/contrib/go/_std_1.22/src/os/error.go b/contrib/go/_std_1.22/src/os/error.go deleted file mode 100644 index 62ede9ded3bc..000000000000 --- a/contrib/go/_std_1.22/src/os/error.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "internal/poll" - "io/fs" -) - -// Portable analogs of some common system call errors. -// -// Errors returned from this package may be tested against these errors -// with errors.Is. -var ( - // ErrInvalid indicates an invalid argument. - // Methods on File will return this error when the receiver is nil. - ErrInvalid = fs.ErrInvalid // "invalid argument" - - ErrPermission = fs.ErrPermission // "permission denied" - ErrExist = fs.ErrExist // "file already exists" - ErrNotExist = fs.ErrNotExist // "file does not exist" - ErrClosed = fs.ErrClosed // "file already closed" - - ErrNoDeadline = errNoDeadline() // "file type does not support deadline" - ErrDeadlineExceeded = errDeadlineExceeded() // "i/o timeout" -) - -func errNoDeadline() error { return poll.ErrNoDeadline } - -// errDeadlineExceeded returns the value for os.ErrDeadlineExceeded. -// This error comes from the internal/poll package, which is also -// used by package net. Doing it this way ensures that the net -// package will return os.ErrDeadlineExceeded for an exceeded deadline, -// as documented by net.Conn.SetDeadline, without requiring any extra -// work in the net package and without requiring the internal/poll -// package to import os (which it can't, because that would be circular). -func errDeadlineExceeded() error { return poll.ErrDeadlineExceeded } - -type timeout interface { - Timeout() bool -} - -// PathError records an error and the operation and file path that caused it. -type PathError = fs.PathError - -// SyscallError records an error from a specific system call. -type SyscallError struct { - Syscall string - Err error -} - -func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() } - -func (e *SyscallError) Unwrap() error { return e.Err } - -// Timeout reports whether this error represents a timeout. -func (e *SyscallError) Timeout() bool { - t, ok := e.Err.(timeout) - return ok && t.Timeout() -} - -// NewSyscallError returns, as an error, a new SyscallError -// with the given system call name and error details. -// As a convenience, if err is nil, NewSyscallError returns nil. -func NewSyscallError(syscall string, err error) error { - if err == nil { - return nil - } - return &SyscallError{syscall, err} -} - -// IsExist returns a boolean indicating whether the error is known to report -// that a file or directory already exists. It is satisfied by ErrExist as -// well as some syscall errors. -// -// This function predates errors.Is. It only supports errors returned by -// the os package. New code should use errors.Is(err, fs.ErrExist). -func IsExist(err error) bool { - return underlyingErrorIs(err, ErrExist) -} - -// IsNotExist returns a boolean indicating whether the error is known to -// report that a file or directory does not exist. It is satisfied by -// ErrNotExist as well as some syscall errors. -// -// This function predates errors.Is. It only supports errors returned by -// the os package. New code should use errors.Is(err, fs.ErrNotExist). -func IsNotExist(err error) bool { - return underlyingErrorIs(err, ErrNotExist) -} - -// IsPermission returns a boolean indicating whether the error is known to -// report that permission is denied. It is satisfied by ErrPermission as well -// as some syscall errors. -// -// This function predates errors.Is. It only supports errors returned by -// the os package. New code should use errors.Is(err, fs.ErrPermission). -func IsPermission(err error) bool { - return underlyingErrorIs(err, ErrPermission) -} - -// IsTimeout returns a boolean indicating whether the error is known -// to report that a timeout occurred. -// -// This function predates errors.Is, and the notion of whether an -// error indicates a timeout can be ambiguous. For example, the Unix -// error EWOULDBLOCK sometimes indicates a timeout and sometimes does not. -// New code should use errors.Is with a value appropriate to the call -// returning the error, such as os.ErrDeadlineExceeded. -func IsTimeout(err error) bool { - terr, ok := underlyingError(err).(timeout) - return ok && terr.Timeout() -} - -func underlyingErrorIs(err, target error) bool { - // Note that this function is not errors.Is: - // underlyingError only unwraps the specific error-wrapping types - // that it historically did, not all errors implementing Unwrap(). - err = underlyingError(err) - if err == target { - return true - } - // To preserve prior behavior, only examine syscall errors. - e, ok := err.(syscallErrorType) - return ok && e.Is(target) -} - -// underlyingError returns the underlying error for known os error types. -func underlyingError(err error) error { - switch err := err.(type) { - case *PathError: - return err.Err - case *LinkError: - return err.Err - case *SyscallError: - return err.Err - } - return err -} diff --git a/contrib/go/_std_1.22/src/os/error_posix.go b/contrib/go/_std_1.22/src/os/error_posix.go deleted file mode 100644 index b159c036c110..000000000000 --- a/contrib/go/_std_1.22/src/os/error_posix.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix || (js && wasm) || wasip1 || windows - -package os - -import "syscall" - -// wrapSyscallError takes an error and a syscall name. If the error is -// a syscall.Errno, it wraps it in an os.SyscallError using the syscall name. -func wrapSyscallError(name string, err error) error { - if _, ok := err.(syscall.Errno); ok { - err = NewSyscallError(name, err) - } - return err -} diff --git a/contrib/go/_std_1.22/src/os/exec.go b/contrib/go/_std_1.22/src/os/exec.go deleted file mode 100644 index ed5a75c4d13f..000000000000 --- a/contrib/go/_std_1.22/src/os/exec.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "errors" - "internal/testlog" - "runtime" - "sync" - "sync/atomic" - "syscall" - "time" -) - -// ErrProcessDone indicates a Process has finished. -var ErrProcessDone = errors.New("os: process already finished") - -// Process stores the information about a process created by StartProcess. -type Process struct { - Pid int - handle uintptr // handle is accessed atomically on Windows - isdone atomic.Bool // process has been successfully waited on - sigMu sync.RWMutex // avoid race between wait and signal -} - -func newProcess(pid int, handle uintptr) *Process { - p := &Process{Pid: pid, handle: handle} - runtime.SetFinalizer(p, (*Process).Release) - return p -} - -func (p *Process) setDone() { - p.isdone.Store(true) -} - -func (p *Process) done() bool { - return p.isdone.Load() -} - -// ProcAttr holds the attributes that will be applied to a new process -// started by StartProcess. -type ProcAttr struct { - // If Dir is non-empty, the child changes into the directory before - // creating the process. - Dir string - // If Env is non-nil, it gives the environment variables for the - // new process in the form returned by Environ. - // If it is nil, the result of Environ will be used. - Env []string - // Files specifies the open files inherited by the new process. The - // first three entries correspond to standard input, standard output, and - // standard error. An implementation may support additional entries, - // depending on the underlying operating system. A nil entry corresponds - // to that file being closed when the process starts. - // On Unix systems, StartProcess will change these File values - // to blocking mode, which means that SetDeadline will stop working - // and calling Close will not interrupt a Read or Write. - Files []*File - - // Operating system-specific process creation attributes. - // Note that setting this field means that your program - // may not execute properly or even compile on some - // operating systems. - Sys *syscall.SysProcAttr -} - -// A Signal represents an operating system signal. -// The usual underlying implementation is operating system-dependent: -// on Unix it is syscall.Signal. -type Signal interface { - String() string - Signal() // to distinguish from other Stringers -} - -// Getpid returns the process id of the caller. -func Getpid() int { return syscall.Getpid() } - -// Getppid returns the process id of the caller's parent. -func Getppid() int { return syscall.Getppid() } - -// FindProcess looks for a running process by its pid. -// -// The Process it returns can be used to obtain information -// about the underlying operating system process. -// -// On Unix systems, FindProcess always succeeds and returns a Process -// for the given pid, regardless of whether the process exists. To test whether -// the process actually exists, see whether p.Signal(syscall.Signal(0)) reports -// an error. -func FindProcess(pid int) (*Process, error) { - return findProcess(pid) -} - -// StartProcess starts a new process with the program, arguments and attributes -// specified by name, argv and attr. The argv slice will become os.Args in the -// new process, so it normally starts with the program name. -// -// If the calling goroutine has locked the operating system thread -// with runtime.LockOSThread and modified any inheritable OS-level -// thread state (for example, Linux or Plan 9 name spaces), the new -// process will inherit the caller's thread state. -// -// StartProcess is a low-level interface. The os/exec package provides -// higher-level interfaces. -// -// If there is an error, it will be of type *PathError. -func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) { - testlog.Open(name) - return startProcess(name, argv, attr) -} - -// Release releases any resources associated with the Process p, -// rendering it unusable in the future. -// Release only needs to be called if Wait is not. -func (p *Process) Release() error { - return p.release() -} - -// Kill causes the Process to exit immediately. Kill does not wait until -// the Process has actually exited. This only kills the Process itself, -// not any other processes it may have started. -func (p *Process) Kill() error { - return p.kill() -} - -// Wait waits for the Process to exit, and then returns a -// ProcessState describing its status and an error, if any. -// Wait releases any resources associated with the Process. -// On most operating systems, the Process must be a child -// of the current process or an error will be returned. -func (p *Process) Wait() (*ProcessState, error) { - return p.wait() -} - -// Signal sends a signal to the Process. -// Sending Interrupt on Windows is not implemented. -func (p *Process) Signal(sig Signal) error { - return p.signal(sig) -} - -// UserTime returns the user CPU time of the exited process and its children. -func (p *ProcessState) UserTime() time.Duration { - return p.userTime() -} - -// SystemTime returns the system CPU time of the exited process and its children. -func (p *ProcessState) SystemTime() time.Duration { - return p.systemTime() -} - -// Exited reports whether the program has exited. -// On Unix systems this reports true if the program exited due to calling exit, -// but false if the program terminated due to a signal. -func (p *ProcessState) Exited() bool { - return p.exited() -} - -// Success reports whether the program exited successfully, -// such as with exit status 0 on Unix. -func (p *ProcessState) Success() bool { - return p.success() -} - -// Sys returns system-dependent exit information about -// the process. Convert it to the appropriate underlying -// type, such as syscall.WaitStatus on Unix, to access its contents. -func (p *ProcessState) Sys() any { - return p.sys() -} - -// SysUsage returns system-dependent resource usage information about -// the exited process. Convert it to the appropriate underlying -// type, such as *syscall.Rusage on Unix, to access its contents. -// (On Unix, *syscall.Rusage matches struct rusage as defined in the -// getrusage(2) manual page.) -func (p *ProcessState) SysUsage() any { - return p.sysUsage() -} diff --git a/contrib/go/_std_1.22/src/os/exec/exec.go b/contrib/go/_std_1.22/src/os/exec/exec.go deleted file mode 100644 index a52b75f69cde..000000000000 --- a/contrib/go/_std_1.22/src/os/exec/exec.go +++ /dev/null @@ -1,1307 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package exec runs external commands. It wraps os.StartProcess to make it -// easier to remap stdin and stdout, connect I/O with pipes, and do other -// adjustments. -// -// Unlike the "system" library call from C and other languages, the -// os/exec package intentionally does not invoke the system shell and -// does not expand any glob patterns or handle other expansions, -// pipelines, or redirections typically done by shells. The package -// behaves more like C's "exec" family of functions. To expand glob -// patterns, either call the shell directly, taking care to escape any -// dangerous input, or use the path/filepath package's Glob function. -// To expand environment variables, use package os's ExpandEnv. -// -// Note that the examples in this package assume a Unix system. -// They may not run on Windows, and they do not run in the Go Playground -// used by golang.org and godoc.org. -// -// # Executables in the current directory -// -// The functions Command and LookPath look for a program -// in the directories listed in the current path, following the -// conventions of the host operating system. -// Operating systems have for decades included the current -// directory in this search, sometimes implicitly and sometimes -// configured explicitly that way by default. -// Modern practice is that including the current directory -// is usually unexpected and often leads to security problems. -// -// To avoid those security problems, as of Go 1.19, this package will not resolve a program -// using an implicit or explicit path entry relative to the current directory. -// That is, if you run exec.LookPath("go"), it will not successfully return -// ./go on Unix nor .\go.exe on Windows, no matter how the path is configured. -// Instead, if the usual path algorithms would result in that answer, -// these functions return an error err satisfying errors.Is(err, ErrDot). -// -// For example, consider these two program snippets: -// -// path, err := exec.LookPath("prog") -// if err != nil { -// log.Fatal(err) -// } -// use(path) -// -// and -// -// cmd := exec.Command("prog") -// if err := cmd.Run(); err != nil { -// log.Fatal(err) -// } -// -// These will not find and run ./prog or .\prog.exe, -// no matter how the current path is configured. -// -// Code that always wants to run a program from the current directory -// can be rewritten to say "./prog" instead of "prog". -// -// Code that insists on including results from relative path entries -// can instead override the error using an errors.Is check: -// -// path, err := exec.LookPath("prog") -// if errors.Is(err, exec.ErrDot) { -// err = nil -// } -// if err != nil { -// log.Fatal(err) -// } -// use(path) -// -// and -// -// cmd := exec.Command("prog") -// if errors.Is(cmd.Err, exec.ErrDot) { -// cmd.Err = nil -// } -// if err := cmd.Run(); err != nil { -// log.Fatal(err) -// } -// -// Setting the environment variable GODEBUG=execerrdot=0 -// disables generation of ErrDot entirely, temporarily restoring the pre-Go 1.19 -// behavior for programs that are unable to apply more targeted fixes. -// A future version of Go may remove support for this variable. -// -// Before adding such overrides, make sure you understand the -// security implications of doing so. -// See https://go.dev/blog/path-security for more information. -package exec - -import ( - "bytes" - "context" - "errors" - "internal/godebug" - "internal/syscall/execenv" - "io" - "os" - "path/filepath" - "runtime" - "strconv" - "strings" - "syscall" - "time" -) - -// Error is returned by LookPath when it fails to classify a file as an -// executable. -type Error struct { - // Name is the file name for which the error occurred. - Name string - // Err is the underlying error. - Err error -} - -func (e *Error) Error() string { - return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error() -} - -func (e *Error) Unwrap() error { return e.Err } - -// ErrWaitDelay is returned by (*Cmd).Wait if the process exits with a -// successful status code but its output pipes are not closed before the -// command's WaitDelay expires. -var ErrWaitDelay = errors.New("exec: WaitDelay expired before I/O complete") - -// wrappedError wraps an error without relying on fmt.Errorf. -type wrappedError struct { - prefix string - err error -} - -func (w wrappedError) Error() string { - return w.prefix + ": " + w.err.Error() -} - -func (w wrappedError) Unwrap() error { - return w.err -} - -// Cmd represents an external command being prepared or run. -// -// A Cmd cannot be reused after calling its Run, Output or CombinedOutput -// methods. -type Cmd struct { - // Path is the path of the command to run. - // - // This is the only field that must be set to a non-zero - // value. If Path is relative, it is evaluated relative - // to Dir. - Path string - - // Args holds command line arguments, including the command as Args[0]. - // If the Args field is empty or nil, Run uses {Path}. - // - // In typical use, both Path and Args are set by calling Command. - Args []string - - // Env specifies the environment of the process. - // Each entry is of the form "key=value". - // If Env is nil, the new process uses the current process's - // environment. - // If Env contains duplicate environment keys, only the last - // value in the slice for each duplicate key is used. - // As a special case on Windows, SYSTEMROOT is always added if - // missing and not explicitly set to the empty string. - Env []string - - // Dir specifies the working directory of the command. - // If Dir is the empty string, Run runs the command in the - // calling process's current directory. - Dir string - - // Stdin specifies the process's standard input. - // - // If Stdin is nil, the process reads from the null device (os.DevNull). - // - // If Stdin is an *os.File, the process's standard input is connected - // directly to that file. - // - // Otherwise, during the execution of the command a separate - // goroutine reads from Stdin and delivers that data to the command - // over a pipe. In this case, Wait does not complete until the goroutine - // stops copying, either because it has reached the end of Stdin - // (EOF or a read error), or because writing to the pipe returned an error, - // or because a nonzero WaitDelay was set and expired. - Stdin io.Reader - - // Stdout and Stderr specify the process's standard output and error. - // - // If either is nil, Run connects the corresponding file descriptor - // to the null device (os.DevNull). - // - // If either is an *os.File, the corresponding output from the process - // is connected directly to that file. - // - // Otherwise, during the execution of the command a separate goroutine - // reads from the process over a pipe and delivers that data to the - // corresponding Writer. In this case, Wait does not complete until the - // goroutine reaches EOF or encounters an error or a nonzero WaitDelay - // expires. - // - // If Stdout and Stderr are the same writer, and have a type that can - // be compared with ==, at most one goroutine at a time will call Write. - Stdout io.Writer - Stderr io.Writer - - // ExtraFiles specifies additional open files to be inherited by the - // new process. It does not include standard input, standard output, or - // standard error. If non-nil, entry i becomes file descriptor 3+i. - // - // ExtraFiles is not supported on Windows. - ExtraFiles []*os.File - - // SysProcAttr holds optional, operating system-specific attributes. - // Run passes it to os.StartProcess as the os.ProcAttr's Sys field. - SysProcAttr *syscall.SysProcAttr - - // Process is the underlying process, once started. - Process *os.Process - - // ProcessState contains information about an exited process. - // If the process was started successfully, Wait or Run will - // populate its ProcessState when the command completes. - ProcessState *os.ProcessState - - // ctx is the context passed to CommandContext, if any. - ctx context.Context - - Err error // LookPath error, if any. - - // If Cancel is non-nil, the command must have been created with - // CommandContext and Cancel will be called when the command's - // Context is done. By default, CommandContext sets Cancel to - // call the Kill method on the command's Process. - // - // Typically a custom Cancel will send a signal to the command's - // Process, but it may instead take other actions to initiate cancellation, - // such as closing a stdin or stdout pipe or sending a shutdown request on a - // network socket. - // - // If the command exits with a success status after Cancel is - // called, and Cancel does not return an error equivalent to - // os.ErrProcessDone, then Wait and similar methods will return a non-nil - // error: either an error wrapping the one returned by Cancel, - // or the error from the Context. - // (If the command exits with a non-success status, or Cancel - // returns an error that wraps os.ErrProcessDone, Wait and similar methods - // continue to return the command's usual exit status.) - // - // If Cancel is set to nil, nothing will happen immediately when the command's - // Context is done, but a nonzero WaitDelay will still take effect. That may - // be useful, for example, to work around deadlocks in commands that do not - // support shutdown signals but are expected to always finish quickly. - // - // Cancel will not be called if Start returns a non-nil error. - Cancel func() error - - // If WaitDelay is non-zero, it bounds the time spent waiting on two sources - // of unexpected delay in Wait: a child process that fails to exit after the - // associated Context is canceled, and a child process that exits but leaves - // its I/O pipes unclosed. - // - // The WaitDelay timer starts when either the associated Context is done or a - // call to Wait observes that the child process has exited, whichever occurs - // first. When the delay has elapsed, the command shuts down the child process - // and/or its I/O pipes. - // - // If the child process has failed to exit — perhaps because it ignored or - // failed to receive a shutdown signal from a Cancel function, or because no - // Cancel function was set — then it will be terminated using os.Process.Kill. - // - // Then, if the I/O pipes communicating with the child process are still open, - // those pipes are closed in order to unblock any goroutines currently blocked - // on Read or Write calls. - // - // If pipes are closed due to WaitDelay, no Cancel call has occurred, - // and the command has otherwise exited with a successful status, Wait and - // similar methods will return ErrWaitDelay instead of nil. - // - // If WaitDelay is zero (the default), I/O pipes will be read until EOF, - // which might not occur until orphaned subprocesses of the command have - // also closed their descriptors for the pipes. - WaitDelay time.Duration - - // childIOFiles holds closers for any of the child process's - // stdin, stdout, and/or stderr files that were opened by the Cmd itself - // (not supplied by the caller). These should be closed as soon as they - // are inherited by the child process. - childIOFiles []io.Closer - - // parentIOPipes holds closers for the parent's end of any pipes - // connected to the child's stdin, stdout, and/or stderr streams - // that were opened by the Cmd itself (not supplied by the caller). - // These should be closed after Wait sees the command and copying - // goroutines exit, or after WaitDelay has expired. - parentIOPipes []io.Closer - - // goroutine holds a set of closures to execute to copy data - // to and/or from the command's I/O pipes. - goroutine []func() error - - // If goroutineErr is non-nil, it receives the first error from a copying - // goroutine once all such goroutines have completed. - // goroutineErr is set to nil once its error has been received. - goroutineErr <-chan error - - // If ctxResult is non-nil, it receives the result of watchCtx exactly once. - ctxResult <-chan ctxResult - - // The stack saved when the Command was created, if GODEBUG contains - // execwait=2. Used for debugging leaks. - createdByStack []byte - - // For a security release long ago, we created x/sys/execabs, - // which manipulated the unexported lookPathErr error field - // in this struct. For Go 1.19 we exported the field as Err error, - // above, but we have to keep lookPathErr around for use by - // old programs building against new toolchains. - // The String and Start methods look for an error in lookPathErr - // in preference to Err, to preserve the errors that execabs sets. - // - // In general we don't guarantee misuse of reflect like this, - // but the misuse of reflect was by us, the best of various bad - // options to fix the security problem, and people depend on - // those old copies of execabs continuing to work. - // The result is that we have to leave this variable around for the - // rest of time, a compatibility scar. - // - // See https://go.dev/blog/path-security - // and https://go.dev/issue/43724 for more context. - lookPathErr error - - // cachedLookExtensions caches the result of calling lookExtensions. - // This is only used on Windows. - cachedLookExtensions string -} - -// A ctxResult reports the result of watching the Context associated with a -// running command (and sending corresponding signals if needed). -type ctxResult struct { - err error - - // If timer is non-nil, it expires after WaitDelay has elapsed after - // the Context is done. - // - // (If timer is nil, that means that the Context was not done before the - // command completed, or no WaitDelay was set, or the WaitDelay already - // expired and its effect was already applied.) - timer *time.Timer -} - -var execwait = godebug.New("#execwait") -var execerrdot = godebug.New("execerrdot") - -// Command returns the Cmd struct to execute the named program with -// the given arguments. -// -// It sets only the Path and Args in the returned structure. -// -// If name contains no path separators, Command uses LookPath to -// resolve name to a complete path if possible. Otherwise it uses name -// directly as Path. -// -// The returned Cmd's Args field is constructed from the command name -// followed by the elements of arg, so arg should not include the -// command name itself. For example, Command("echo", "hello"). -// Args[0] is always name, not the possibly resolved Path. -// -// On Windows, processes receive the whole command line as a single string -// and do their own parsing. Command combines and quotes Args into a command -// line string with an algorithm compatible with applications using -// CommandLineToArgvW (which is the most common way). Notable exceptions are -// msiexec.exe and cmd.exe (and thus, all batch files), which have a different -// unquoting algorithm. In these or other similar cases, you can do the -// quoting yourself and provide the full command line in SysProcAttr.CmdLine, -// leaving Args empty. -func Command(name string, arg ...string) *Cmd { - cmd := &Cmd{ - Path: name, - Args: append([]string{name}, arg...), - } - - if v := execwait.Value(); v != "" { - if v == "2" { - // Obtain the caller stack. (This is equivalent to runtime/debug.Stack, - // copied to avoid importing the whole package.) - stack := make([]byte, 1024) - for { - n := runtime.Stack(stack, false) - if n < len(stack) { - stack = stack[:n] - break - } - stack = make([]byte, 2*len(stack)) - } - - if i := bytes.Index(stack, []byte("\nos/exec.Command(")); i >= 0 { - stack = stack[i+1:] - } - cmd.createdByStack = stack - } - - runtime.SetFinalizer(cmd, func(c *Cmd) { - if c.Process != nil && c.ProcessState == nil { - debugHint := "" - if c.createdByStack == nil { - debugHint = " (set GODEBUG=execwait=2 to capture stacks for debugging)" - } else { - os.Stderr.WriteString("GODEBUG=execwait=2 detected a leaked exec.Cmd created by:\n") - os.Stderr.Write(c.createdByStack) - os.Stderr.WriteString("\n") - debugHint = "" - } - panic("exec: Cmd started a Process but leaked without a call to Wait" + debugHint) - } - }) - } - - if filepath.Base(name) == name { - lp, err := LookPath(name) - if lp != "" { - // Update cmd.Path even if err is non-nil. - // If err is ErrDot (especially on Windows), lp may include a resolved - // extension (like .exe or .bat) that should be preserved. - cmd.Path = lp - } - if err != nil { - cmd.Err = err - } - } else if runtime.GOOS == "windows" && filepath.IsAbs(name) { - // We may need to add a filename extension from PATHEXT - // or verify an extension that is already present. - // Since the path is absolute, its extension should be unambiguous - // and independent of cmd.Dir, and we can go ahead and cache the lookup now. - // - // Note that we cannot add an extension here for relative paths, because - // cmd.Dir may be set after we return from this function and that may cause - // the command to resolve to a different extension. - lp, err := lookExtensions(name, "") - cmd.cachedLookExtensions = lp - if err != nil { - cmd.Err = err - } - } - return cmd -} - -// CommandContext is like Command but includes a context. -// -// The provided context is used to interrupt the process -// (by calling cmd.Cancel or os.Process.Kill) -// if the context becomes done before the command completes on its own. -// -// CommandContext sets the command's Cancel function to invoke the Kill method -// on its Process, and leaves its WaitDelay unset. The caller may change the -// cancellation behavior by modifying those fields before starting the command. -func CommandContext(ctx context.Context, name string, arg ...string) *Cmd { - if ctx == nil { - panic("nil Context") - } - cmd := Command(name, arg...) - cmd.ctx = ctx - cmd.Cancel = func() error { - return cmd.Process.Kill() - } - return cmd -} - -// String returns a human-readable description of c. -// It is intended only for debugging. -// In particular, it is not suitable for use as input to a shell. -// The output of String may vary across Go releases. -func (c *Cmd) String() string { - if c.Err != nil || c.lookPathErr != nil { - // failed to resolve path; report the original requested path (plus args) - return strings.Join(c.Args, " ") - } - // report the exact executable path (plus args) - b := new(strings.Builder) - b.WriteString(c.Path) - for _, a := range c.Args[1:] { - b.WriteByte(' ') - b.WriteString(a) - } - return b.String() -} - -// interfaceEqual protects against panics from doing equality tests on -// two interfaces with non-comparable underlying types. -func interfaceEqual(a, b any) bool { - defer func() { - recover() - }() - return a == b -} - -func (c *Cmd) argv() []string { - if len(c.Args) > 0 { - return c.Args - } - return []string{c.Path} -} - -func (c *Cmd) childStdin() (*os.File, error) { - if c.Stdin == nil { - f, err := os.Open(os.DevNull) - if err != nil { - return nil, err - } - c.childIOFiles = append(c.childIOFiles, f) - return f, nil - } - - if f, ok := c.Stdin.(*os.File); ok { - return f, nil - } - - pr, pw, err := os.Pipe() - if err != nil { - return nil, err - } - - c.childIOFiles = append(c.childIOFiles, pr) - c.parentIOPipes = append(c.parentIOPipes, pw) - c.goroutine = append(c.goroutine, func() error { - _, err := io.Copy(pw, c.Stdin) - if skipStdinCopyError(err) { - err = nil - } - if err1 := pw.Close(); err == nil { - err = err1 - } - return err - }) - return pr, nil -} - -func (c *Cmd) childStdout() (*os.File, error) { - return c.writerDescriptor(c.Stdout) -} - -func (c *Cmd) childStderr(childStdout *os.File) (*os.File, error) { - if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) { - return childStdout, nil - } - return c.writerDescriptor(c.Stderr) -} - -// writerDescriptor returns an os.File to which the child process -// can write to send data to w. -// -// If w is nil, writerDescriptor returns a File that writes to os.DevNull. -func (c *Cmd) writerDescriptor(w io.Writer) (*os.File, error) { - if w == nil { - f, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0) - if err != nil { - return nil, err - } - c.childIOFiles = append(c.childIOFiles, f) - return f, nil - } - - if f, ok := w.(*os.File); ok { - return f, nil - } - - pr, pw, err := os.Pipe() - if err != nil { - return nil, err - } - - c.childIOFiles = append(c.childIOFiles, pw) - c.parentIOPipes = append(c.parentIOPipes, pr) - c.goroutine = append(c.goroutine, func() error { - _, err := io.Copy(w, pr) - pr.Close() // in case io.Copy stopped due to write error - return err - }) - return pw, nil -} - -func closeDescriptors(closers []io.Closer) { - for _, fd := range closers { - fd.Close() - } -} - -// Run starts the specified command and waits for it to complete. -// -// The returned error is nil if the command runs, has no problems -// copying stdin, stdout, and stderr, and exits with a zero exit -// status. -// -// If the command starts but does not complete successfully, the error is of -// type *ExitError. Other error types may be returned for other situations. -// -// If the calling goroutine has locked the operating system thread -// with runtime.LockOSThread and modified any inheritable OS-level -// thread state (for example, Linux or Plan 9 name spaces), the new -// process will inherit the caller's thread state. -func (c *Cmd) Run() error { - if err := c.Start(); err != nil { - return err - } - return c.Wait() -} - -// Start starts the specified command but does not wait for it to complete. -// -// If Start returns successfully, the c.Process field will be set. -// -// After a successful call to Start the Wait method must be called in -// order to release associated system resources. -func (c *Cmd) Start() error { - // Check for doubled Start calls before we defer failure cleanup. If the prior - // call to Start succeeded, we don't want to spuriously close its pipes. - if c.Process != nil { - return errors.New("exec: already started") - } - - started := false - defer func() { - closeDescriptors(c.childIOFiles) - c.childIOFiles = nil - - if !started { - closeDescriptors(c.parentIOPipes) - c.parentIOPipes = nil - } - }() - - if c.Path == "" && c.Err == nil && c.lookPathErr == nil { - c.Err = errors.New("exec: no command") - } - if c.Err != nil || c.lookPathErr != nil { - if c.lookPathErr != nil { - return c.lookPathErr - } - return c.Err - } - lp := c.Path - if c.cachedLookExtensions != "" { - lp = c.cachedLookExtensions - } - if runtime.GOOS == "windows" && c.cachedLookExtensions == "" { - // If c.Path is relative, we had to wait until now - // to resolve it in case c.Dir was changed. - // (If it is absolute, we already resolved its extension in Command - // and shouldn't need to do so again.) - // - // Unfortunately, we cannot write the result back to c.Path because programs - // may assume that they can call Start concurrently with reading the path. - // (It is safe and non-racy to do so on Unix platforms, and users might not - // test with the race detector on all platforms; - // see https://go.dev/issue/62596.) - // - // So we will pass the fully resolved path to os.StartProcess, but leave - // c.Path as is: missing a bit of logging information seems less harmful - // than triggering a surprising data race, and if the user really cares - // about that bit of logging they can always use LookPath to resolve it. - var err error - lp, err = lookExtensions(c.Path, c.Dir) - if err != nil { - return err - } - } - if c.Cancel != nil && c.ctx == nil { - return errors.New("exec: command with a non-nil Cancel was not created with CommandContext") - } - if c.ctx != nil { - select { - case <-c.ctx.Done(): - return c.ctx.Err() - default: - } - } - - childFiles := make([]*os.File, 0, 3+len(c.ExtraFiles)) - stdin, err := c.childStdin() - if err != nil { - return err - } - childFiles = append(childFiles, stdin) - stdout, err := c.childStdout() - if err != nil { - return err - } - childFiles = append(childFiles, stdout) - stderr, err := c.childStderr(stdout) - if err != nil { - return err - } - childFiles = append(childFiles, stderr) - childFiles = append(childFiles, c.ExtraFiles...) - - env, err := c.environ() - if err != nil { - return err - } - - c.Process, err = os.StartProcess(lp, c.argv(), &os.ProcAttr{ - Dir: c.Dir, - Files: childFiles, - Env: env, - Sys: c.SysProcAttr, - }) - if err != nil { - return err - } - started = true - - // Don't allocate the goroutineErr channel unless there are goroutines to start. - if len(c.goroutine) > 0 { - goroutineErr := make(chan error, 1) - c.goroutineErr = goroutineErr - - type goroutineStatus struct { - running int - firstErr error - } - statusc := make(chan goroutineStatus, 1) - statusc <- goroutineStatus{running: len(c.goroutine)} - for _, fn := range c.goroutine { - go func(fn func() error) { - err := fn() - - status := <-statusc - if status.firstErr == nil { - status.firstErr = err - } - status.running-- - if status.running == 0 { - goroutineErr <- status.firstErr - } else { - statusc <- status - } - }(fn) - } - c.goroutine = nil // Allow the goroutines' closures to be GC'd when they complete. - } - - // If we have anything to do when the command's Context expires, - // start a goroutine to watch for cancellation. - // - // (Even if the command was created by CommandContext, a helper library may - // have explicitly set its Cancel field back to nil, indicating that it should - // be allowed to continue running after cancellation after all.) - if (c.Cancel != nil || c.WaitDelay != 0) && c.ctx != nil && c.ctx.Done() != nil { - resultc := make(chan ctxResult) - c.ctxResult = resultc - go c.watchCtx(resultc) - } - - return nil -} - -// watchCtx watches c.ctx until it is able to send a result to resultc. -// -// If c.ctx is done before a result can be sent, watchCtx calls c.Cancel, -// and/or kills cmd.Process it after c.WaitDelay has elapsed. -// -// watchCtx manipulates c.goroutineErr, so its result must be received before -// c.awaitGoroutines is called. -func (c *Cmd) watchCtx(resultc chan<- ctxResult) { - select { - case resultc <- ctxResult{}: - return - case <-c.ctx.Done(): - } - - var err error - if c.Cancel != nil { - if interruptErr := c.Cancel(); interruptErr == nil { - // We appear to have successfully interrupted the command, so any - // program behavior from this point may be due to ctx even if the - // command exits with code 0. - err = c.ctx.Err() - } else if errors.Is(interruptErr, os.ErrProcessDone) { - // The process already finished: we just didn't notice it yet. - // (Perhaps c.Wait hadn't been called, or perhaps it happened to race with - // c.ctx being cancelled.) Don't inject a needless error. - } else { - err = wrappedError{ - prefix: "exec: canceling Cmd", - err: interruptErr, - } - } - } - if c.WaitDelay == 0 { - resultc <- ctxResult{err: err} - return - } - - timer := time.NewTimer(c.WaitDelay) - select { - case resultc <- ctxResult{err: err, timer: timer}: - // c.Process.Wait returned and we've handed the timer off to c.Wait. - // It will take care of goroutine shutdown from here. - return - case <-timer.C: - } - - killed := false - if killErr := c.Process.Kill(); killErr == nil { - // We appear to have killed the process. c.Process.Wait should return a - // non-nil error to c.Wait unless the Kill signal races with a successful - // exit, and if that does happen we shouldn't report a spurious error, - // so don't set err to anything here. - killed = true - } else if !errors.Is(killErr, os.ErrProcessDone) { - err = wrappedError{ - prefix: "exec: killing Cmd", - err: killErr, - } - } - - if c.goroutineErr != nil { - select { - case goroutineErr := <-c.goroutineErr: - // Forward goroutineErr only if we don't have reason to believe it was - // caused by a call to Cancel or Kill above. - if err == nil && !killed { - err = goroutineErr - } - default: - // Close the child process's I/O pipes, in case it abandoned some - // subprocess that inherited them and is still holding them open - // (see https://go.dev/issue/23019). - // - // We close the goroutine pipes only after we have sent any signals we're - // going to send to the process (via Signal or Kill above): if we send - // SIGKILL to the process, we would prefer for it to die of SIGKILL, not - // SIGPIPE. (However, this may still cause any orphaned subprocesses to - // terminate with SIGPIPE.) - closeDescriptors(c.parentIOPipes) - // Wait for the copying goroutines to finish, but report ErrWaitDelay for - // the error: any other error here could result from closing the pipes. - _ = <-c.goroutineErr - if err == nil { - err = ErrWaitDelay - } - } - - // Since we have already received the only result from c.goroutineErr, - // set it to nil to prevent awaitGoroutines from blocking on it. - c.goroutineErr = nil - } - - resultc <- ctxResult{err: err} -} - -// An ExitError reports an unsuccessful exit by a command. -type ExitError struct { - *os.ProcessState - - // Stderr holds a subset of the standard error output from the - // Cmd.Output method if standard error was not otherwise being - // collected. - // - // If the error output is long, Stderr may contain only a prefix - // and suffix of the output, with the middle replaced with - // text about the number of omitted bytes. - // - // Stderr is provided for debugging, for inclusion in error messages. - // Users with other needs should redirect Cmd.Stderr as needed. - Stderr []byte -} - -func (e *ExitError) Error() string { - return e.ProcessState.String() -} - -// Wait waits for the command to exit and waits for any copying to -// stdin or copying from stdout or stderr to complete. -// -// The command must have been started by Start. -// -// The returned error is nil if the command runs, has no problems -// copying stdin, stdout, and stderr, and exits with a zero exit -// status. -// -// If the command fails to run or doesn't complete successfully, the -// error is of type *ExitError. Other error types may be -// returned for I/O problems. -// -// If any of c.Stdin, c.Stdout or c.Stderr are not an *os.File, Wait also waits -// for the respective I/O loop copying to or from the process to complete. -// -// Wait releases any resources associated with the Cmd. -func (c *Cmd) Wait() error { - if c.Process == nil { - return errors.New("exec: not started") - } - if c.ProcessState != nil { - return errors.New("exec: Wait was already called") - } - - state, err := c.Process.Wait() - if err == nil && !state.Success() { - err = &ExitError{ProcessState: state} - } - c.ProcessState = state - - var timer *time.Timer - if c.ctxResult != nil { - watch := <-c.ctxResult - timer = watch.timer - // If c.Process.Wait returned an error, prefer that. - // Otherwise, report any error from the watchCtx goroutine, - // such as a Context cancellation or a WaitDelay overrun. - if err == nil && watch.err != nil { - err = watch.err - } - } - - if goroutineErr := c.awaitGoroutines(timer); err == nil { - // Report an error from the copying goroutines only if the program otherwise - // exited normally on its own. Otherwise, the copying error may be due to the - // abnormal termination. - err = goroutineErr - } - closeDescriptors(c.parentIOPipes) - c.parentIOPipes = nil - - return err -} - -// awaitGoroutines waits for the results of the goroutines copying data to or -// from the command's I/O pipes. -// -// If c.WaitDelay elapses before the goroutines complete, awaitGoroutines -// forcibly closes their pipes and returns ErrWaitDelay. -// -// If timer is non-nil, it must send to timer.C at the end of c.WaitDelay. -func (c *Cmd) awaitGoroutines(timer *time.Timer) error { - defer func() { - if timer != nil { - timer.Stop() - } - c.goroutineErr = nil - }() - - if c.goroutineErr == nil { - return nil // No running goroutines to await. - } - - if timer == nil { - if c.WaitDelay == 0 { - return <-c.goroutineErr - } - - select { - case err := <-c.goroutineErr: - // Avoid the overhead of starting a timer. - return err - default: - } - - // No existing timer was started: either there is no Context associated with - // the command, or c.Process.Wait completed before the Context was done. - timer = time.NewTimer(c.WaitDelay) - } - - select { - case <-timer.C: - closeDescriptors(c.parentIOPipes) - // Wait for the copying goroutines to finish, but ignore any error - // (since it was probably caused by closing the pipes). - _ = <-c.goroutineErr - return ErrWaitDelay - - case err := <-c.goroutineErr: - return err - } -} - -// Output runs the command and returns its standard output. -// Any returned error will usually be of type *ExitError. -// If c.Stderr was nil, Output populates ExitError.Stderr. -func (c *Cmd) Output() ([]byte, error) { - if c.Stdout != nil { - return nil, errors.New("exec: Stdout already set") - } - var stdout bytes.Buffer - c.Stdout = &stdout - - captureErr := c.Stderr == nil - if captureErr { - c.Stderr = &prefixSuffixSaver{N: 32 << 10} - } - - err := c.Run() - if err != nil && captureErr { - if ee, ok := err.(*ExitError); ok { - ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes() - } - } - return stdout.Bytes(), err -} - -// CombinedOutput runs the command and returns its combined standard -// output and standard error. -func (c *Cmd) CombinedOutput() ([]byte, error) { - if c.Stdout != nil { - return nil, errors.New("exec: Stdout already set") - } - if c.Stderr != nil { - return nil, errors.New("exec: Stderr already set") - } - var b bytes.Buffer - c.Stdout = &b - c.Stderr = &b - err := c.Run() - return b.Bytes(), err -} - -// StdinPipe returns a pipe that will be connected to the command's -// standard input when the command starts. -// The pipe will be closed automatically after Wait sees the command exit. -// A caller need only call Close to force the pipe to close sooner. -// For example, if the command being run will not exit until standard input -// is closed, the caller must close the pipe. -func (c *Cmd) StdinPipe() (io.WriteCloser, error) { - if c.Stdin != nil { - return nil, errors.New("exec: Stdin already set") - } - if c.Process != nil { - return nil, errors.New("exec: StdinPipe after process started") - } - pr, pw, err := os.Pipe() - if err != nil { - return nil, err - } - c.Stdin = pr - c.childIOFiles = append(c.childIOFiles, pr) - c.parentIOPipes = append(c.parentIOPipes, pw) - return pw, nil -} - -// StdoutPipe returns a pipe that will be connected to the command's -// standard output when the command starts. -// -// Wait will close the pipe after seeing the command exit, so most callers -// need not close the pipe themselves. It is thus incorrect to call Wait -// before all reads from the pipe have completed. -// For the same reason, it is incorrect to call Run when using StdoutPipe. -// See the example for idiomatic usage. -func (c *Cmd) StdoutPipe() (io.ReadCloser, error) { - if c.Stdout != nil { - return nil, errors.New("exec: Stdout already set") - } - if c.Process != nil { - return nil, errors.New("exec: StdoutPipe after process started") - } - pr, pw, err := os.Pipe() - if err != nil { - return nil, err - } - c.Stdout = pw - c.childIOFiles = append(c.childIOFiles, pw) - c.parentIOPipes = append(c.parentIOPipes, pr) - return pr, nil -} - -// StderrPipe returns a pipe that will be connected to the command's -// standard error when the command starts. -// -// Wait will close the pipe after seeing the command exit, so most callers -// need not close the pipe themselves. It is thus incorrect to call Wait -// before all reads from the pipe have completed. -// For the same reason, it is incorrect to use Run when using StderrPipe. -// See the StdoutPipe example for idiomatic usage. -func (c *Cmd) StderrPipe() (io.ReadCloser, error) { - if c.Stderr != nil { - return nil, errors.New("exec: Stderr already set") - } - if c.Process != nil { - return nil, errors.New("exec: StderrPipe after process started") - } - pr, pw, err := os.Pipe() - if err != nil { - return nil, err - } - c.Stderr = pw - c.childIOFiles = append(c.childIOFiles, pw) - c.parentIOPipes = append(c.parentIOPipes, pr) - return pr, nil -} - -// prefixSuffixSaver is an io.Writer which retains the first N bytes -// and the last N bytes written to it. The Bytes() methods reconstructs -// it with a pretty error message. -type prefixSuffixSaver struct { - N int // max size of prefix or suffix - prefix []byte - suffix []byte // ring buffer once len(suffix) == N - suffixOff int // offset to write into suffix - skipped int64 - - // TODO(bradfitz): we could keep one large []byte and use part of it for - // the prefix, reserve space for the '... Omitting N bytes ...' message, - // then the ring buffer suffix, and just rearrange the ring buffer - // suffix when Bytes() is called, but it doesn't seem worth it for - // now just for error messages. It's only ~64KB anyway. -} - -func (w *prefixSuffixSaver) Write(p []byte) (n int, err error) { - lenp := len(p) - p = w.fill(&w.prefix, p) - - // Only keep the last w.N bytes of suffix data. - if overage := len(p) - w.N; overage > 0 { - p = p[overage:] - w.skipped += int64(overage) - } - p = w.fill(&w.suffix, p) - - // w.suffix is full now if p is non-empty. Overwrite it in a circle. - for len(p) > 0 { // 0, 1, or 2 iterations. - n := copy(w.suffix[w.suffixOff:], p) - p = p[n:] - w.skipped += int64(n) - w.suffixOff += n - if w.suffixOff == w.N { - w.suffixOff = 0 - } - } - return lenp, nil -} - -// fill appends up to len(p) bytes of p to *dst, such that *dst does not -// grow larger than w.N. It returns the un-appended suffix of p. -func (w *prefixSuffixSaver) fill(dst *[]byte, p []byte) (pRemain []byte) { - if remain := w.N - len(*dst); remain > 0 { - add := min(len(p), remain) - *dst = append(*dst, p[:add]...) - p = p[add:] - } - return p -} - -func (w *prefixSuffixSaver) Bytes() []byte { - if w.suffix == nil { - return w.prefix - } - if w.skipped == 0 { - return append(w.prefix, w.suffix...) - } - var buf bytes.Buffer - buf.Grow(len(w.prefix) + len(w.suffix) + 50) - buf.Write(w.prefix) - buf.WriteString("\n... omitting ") - buf.WriteString(strconv.FormatInt(w.skipped, 10)) - buf.WriteString(" bytes ...\n") - buf.Write(w.suffix[w.suffixOff:]) - buf.Write(w.suffix[:w.suffixOff]) - return buf.Bytes() -} - -// environ returns a best-effort copy of the environment in which the command -// would be run as it is currently configured. If an error occurs in computing -// the environment, it is returned alongside the best-effort copy. -func (c *Cmd) environ() ([]string, error) { - var err error - - env := c.Env - if env == nil { - env, err = execenv.Default(c.SysProcAttr) - if err != nil { - env = os.Environ() - // Note that the non-nil err is preserved despite env being overridden. - } - - if c.Dir != "" { - switch runtime.GOOS { - case "windows", "plan9": - // Windows and Plan 9 do not use the PWD variable, so we don't need to - // keep it accurate. - default: - // On POSIX platforms, PWD represents “an absolute pathname of the - // current working directory.” Since we are changing the working - // directory for the command, we should also update PWD to reflect that. - // - // Unfortunately, we didn't always do that, so (as proposed in - // https://go.dev/issue/50599) to avoid unintended collateral damage we - // only implicitly update PWD when Env is nil. That way, we're much - // less likely to override an intentional change to the variable. - if pwd, absErr := filepath.Abs(c.Dir); absErr == nil { - env = append(env, "PWD="+pwd) - } else if err == nil { - err = absErr - } - } - } - } - - env, dedupErr := dedupEnv(env) - if err == nil { - err = dedupErr - } - return addCriticalEnv(env), err -} - -// Environ returns a copy of the environment in which the command would be run -// as it is currently configured. -func (c *Cmd) Environ() []string { - // Intentionally ignore errors: environ returns a best-effort environment no matter what. - env, _ := c.environ() - return env -} - -// dedupEnv returns a copy of env with any duplicates removed, in favor of -// later values. -// Items not of the normal environment "key=value" form are preserved unchanged. -// Except on Plan 9, items containing NUL characters are removed, and -// an error is returned along with the remaining values. -func dedupEnv(env []string) ([]string, error) { - return dedupEnvCase(runtime.GOOS == "windows", runtime.GOOS == "plan9", env) -} - -// dedupEnvCase is dedupEnv with a case option for testing. -// If caseInsensitive is true, the case of keys is ignored. -// If nulOK is false, items containing NUL characters are allowed. -func dedupEnvCase(caseInsensitive, nulOK bool, env []string) ([]string, error) { - // Construct the output in reverse order, to preserve the - // last occurrence of each key. - var err error - out := make([]string, 0, len(env)) - saw := make(map[string]bool, len(env)) - for n := len(env); n > 0; n-- { - kv := env[n-1] - - // Reject NUL in environment variables to prevent security issues (#56284); - // except on Plan 9, which uses NUL as os.PathListSeparator (#56544). - if !nulOK && strings.IndexByte(kv, 0) != -1 { - err = errors.New("exec: environment variable contains NUL") - continue - } - - i := strings.Index(kv, "=") - if i == 0 { - // We observe in practice keys with a single leading "=" on Windows. - // TODO(#49886): Should we consume only the first leading "=" as part - // of the key, or parse through arbitrarily many of them until a non-"="? - i = strings.Index(kv[1:], "=") + 1 - } - if i < 0 { - if kv != "" { - // The entry is not of the form "key=value" (as it is required to be). - // Leave it as-is for now. - // TODO(#52436): should we strip or reject these bogus entries? - out = append(out, kv) - } - continue - } - k := kv[:i] - if caseInsensitive { - k = strings.ToLower(k) - } - if saw[k] { - continue - } - - saw[k] = true - out = append(out, kv) - } - - // Now reverse the slice to restore the original order. - for i := 0; i < len(out)/2; i++ { - j := len(out) - i - 1 - out[i], out[j] = out[j], out[i] - } - - return out, err -} - -// addCriticalEnv adds any critical environment variables that are required -// (or at least almost always required) on the operating system. -// Currently this is only used for Windows. -func addCriticalEnv(env []string) []string { - if runtime.GOOS != "windows" { - return env - } - for _, kv := range env { - k, _, ok := strings.Cut(kv, "=") - if !ok { - continue - } - if strings.EqualFold(k, "SYSTEMROOT") { - // We already have it. - return env - } - } - return append(env, "SYSTEMROOT="+os.Getenv("SYSTEMROOT")) -} - -// ErrDot indicates that a path lookup resolved to an executable -// in the current directory due to ‘.’ being in the path, either -// implicitly or explicitly. See the package documentation for details. -// -// Note that functions in this package do not return ErrDot directly. -// Code should use errors.Is(err, ErrDot), not err == ErrDot, -// to test whether a returned error err is due to this condition. -var ErrDot = errors.New("cannot run executable found relative to current directory") diff --git a/contrib/go/_std_1.22/src/os/exec/internal/fdtest/ya.make b/contrib/go/_std_1.22/src/os/exec/internal/fdtest/ya.make deleted file mode 100644 index 0bc55ff0acb7..000000000000 --- a/contrib/go/_std_1.22/src/os/exec/internal/fdtest/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - exists_unix.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - exists_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/os/exec/ya.make b/contrib/go/_std_1.22/src/os/exec/ya.make deleted file mode 100644 index 4cdcd7c290a1..000000000000 --- a/contrib/go/_std_1.22/src/os/exec/ya.make +++ /dev/null @@ -1,17 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - exec.go - exec_unix.go - lp_unix.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - exec.go - exec_windows.go - lp_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/os/exec_plan9.go b/contrib/go/_std_1.22/src/os/exec_plan9.go deleted file mode 100644 index 69714ff79830..000000000000 --- a/contrib/go/_std_1.22/src/os/exec_plan9.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "internal/itoa" - "runtime" - "syscall" - "time" -) - -// The only signal values guaranteed to be present in the os package -// on all systems are Interrupt (send the process an interrupt) and -// Kill (force the process to exit). Interrupt is not implemented on -// Windows; using it with os.Process.Signal will return an error. -var ( - Interrupt Signal = syscall.Note("interrupt") - Kill Signal = syscall.Note("kill") -) - -func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { - sysattr := &syscall.ProcAttr{ - Dir: attr.Dir, - Env: attr.Env, - Sys: attr.Sys, - } - - sysattr.Files = make([]uintptr, 0, len(attr.Files)) - for _, f := range attr.Files { - sysattr.Files = append(sysattr.Files, f.Fd()) - } - - pid, h, e := syscall.StartProcess(name, argv, sysattr) - if e != nil { - return nil, &PathError{Op: "fork/exec", Path: name, Err: e} - } - - return newProcess(pid, h), nil -} - -func (p *Process) writeProcFile(file string, data string) error { - f, e := OpenFile("/proc/"+itoa.Itoa(p.Pid)+"/"+file, O_WRONLY, 0) - if e != nil { - return e - } - defer f.Close() - _, e = f.Write([]byte(data)) - return e -} - -func (p *Process) signal(sig Signal) error { - if p.done() { - return ErrProcessDone - } - if e := p.writeProcFile("note", sig.String()); e != nil { - return NewSyscallError("signal", e) - } - return nil -} - -func (p *Process) kill() error { - return p.signal(Kill) -} - -func (p *Process) wait() (ps *ProcessState, err error) { - var waitmsg syscall.Waitmsg - - if p.Pid == -1 { - return nil, ErrInvalid - } - err = syscall.WaitProcess(p.Pid, &waitmsg) - if err != nil { - return nil, NewSyscallError("wait", err) - } - - p.setDone() - ps = &ProcessState{ - pid: waitmsg.Pid, - status: &waitmsg, - } - return ps, nil -} - -func (p *Process) release() error { - // NOOP for Plan 9. - p.Pid = -1 - // no need for a finalizer anymore - runtime.SetFinalizer(p, nil) - return nil -} - -func findProcess(pid int) (p *Process, err error) { - // NOOP for Plan 9. - return newProcess(pid, 0), nil -} - -// ProcessState stores information about a process, as reported by Wait. -type ProcessState struct { - pid int // The process's id. - status *syscall.Waitmsg // System-dependent status info. -} - -// Pid returns the process id of the exited process. -func (p *ProcessState) Pid() int { - return p.pid -} - -func (p *ProcessState) exited() bool { - return p.status.Exited() -} - -func (p *ProcessState) success() bool { - return p.status.ExitStatus() == 0 -} - -func (p *ProcessState) sys() any { - return p.status -} - -func (p *ProcessState) sysUsage() any { - return p.status -} - -func (p *ProcessState) userTime() time.Duration { - return time.Duration(p.status.Time[0]) * time.Millisecond -} - -func (p *ProcessState) systemTime() time.Duration { - return time.Duration(p.status.Time[1]) * time.Millisecond -} - -func (p *ProcessState) String() string { - if p == nil { - return "" - } - return "exit status: " + p.status.Msg -} - -// ExitCode returns the exit code of the exited process, or -1 -// if the process hasn't exited or was terminated by a signal. -func (p *ProcessState) ExitCode() int { - // return -1 if the process hasn't started. - if p == nil { - return -1 - } - return p.status.ExitStatus() -} diff --git a/contrib/go/_std_1.22/src/os/exec_unix.go b/contrib/go/_std_1.22/src/os/exec_unix.go deleted file mode 100644 index 36b320df1894..000000000000 --- a/contrib/go/_std_1.22/src/os/exec_unix.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix || (js && wasm) || wasip1 - -package os - -import ( - "errors" - "runtime" - "syscall" - "time" -) - -func (p *Process) wait() (ps *ProcessState, err error) { - if p.Pid == -1 { - return nil, syscall.EINVAL - } - - // If we can block until Wait4 will succeed immediately, do so. - ready, err := p.blockUntilWaitable() - if err != nil { - return nil, err - } - if ready { - // Mark the process done now, before the call to Wait4, - // so that Process.signal will not send a signal. - p.setDone() - // Acquire a write lock on sigMu to wait for any - // active call to the signal method to complete. - p.sigMu.Lock() - p.sigMu.Unlock() - } - - var ( - status syscall.WaitStatus - rusage syscall.Rusage - pid1 int - e error - ) - for { - pid1, e = syscall.Wait4(p.Pid, &status, 0, &rusage) - if e != syscall.EINTR { - break - } - } - if e != nil { - return nil, NewSyscallError("wait", e) - } - p.setDone() - ps = &ProcessState{ - pid: pid1, - status: status, - rusage: &rusage, - } - return ps, nil -} - -func (p *Process) signal(sig Signal) error { - if p.Pid == -1 { - return errors.New("os: process already released") - } - if p.Pid == 0 { - return errors.New("os: process not initialized") - } - p.sigMu.RLock() - defer p.sigMu.RUnlock() - if p.done() { - return ErrProcessDone - } - s, ok := sig.(syscall.Signal) - if !ok { - return errors.New("os: unsupported signal type") - } - if e := syscall.Kill(p.Pid, s); e != nil { - if e == syscall.ESRCH { - return ErrProcessDone - } - return e - } - return nil -} - -func (p *Process) release() error { - // NOOP for unix. - p.Pid = -1 - // no need for a finalizer anymore - runtime.SetFinalizer(p, nil) - return nil -} - -func findProcess(pid int) (p *Process, err error) { - // NOOP for unix. - return newProcess(pid, 0), nil -} - -func (p *ProcessState) userTime() time.Duration { - return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond -} - -func (p *ProcessState) systemTime() time.Duration { - return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond -} diff --git a/contrib/go/_std_1.22/src/os/executable_procfs.go b/contrib/go/_std_1.22/src/os/executable_procfs.go deleted file mode 100644 index 94e674e36486..000000000000 --- a/contrib/go/_std_1.22/src/os/executable_procfs.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux || netbsd - -package os - -import ( - "errors" - "runtime" -) - -func executable() (string, error) { - var procfn string - switch runtime.GOOS { - default: - return "", errors.New("Executable not implemented for " + runtime.GOOS) - case "linux", "android": - procfn = "/proc/self/exe" - case "netbsd": - procfn = "/proc/curproc/exe" - } - path, err := Readlink(procfn) - - // When the executable has been deleted then Readlink returns a - // path appended with " (deleted)". - return stringsTrimSuffix(path, " (deleted)"), err -} - -// stringsTrimSuffix is the same as strings.TrimSuffix. -func stringsTrimSuffix(s, suffix string) string { - if len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix { - return s[:len(s)-len(suffix)] - } - return s -} diff --git a/contrib/go/_std_1.22/src/os/file_plan9.go b/contrib/go/_std_1.22/src/os/file_plan9.go deleted file mode 100644 index c0ee6b33f9f9..000000000000 --- a/contrib/go/_std_1.22/src/os/file_plan9.go +++ /dev/null @@ -1,618 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "internal/bytealg" - "internal/poll" - "io" - "runtime" - "syscall" - "time" -) - -// fixLongPath is a noop on non-Windows platforms. -func fixLongPath(path string) string { - return path -} - -// file is the real representation of *File. -// The extra level of indirection ensures that no clients of os -// can overwrite this data, which could cause the finalizer -// to close the wrong file descriptor. -type file struct { - fdmu poll.FDMutex - fd int - name string - dirinfo *dirInfo // nil unless directory being read - appendMode bool // whether file is opened for appending -} - -// Fd returns the integer Plan 9 file descriptor referencing the open file. -// If f is closed, the file descriptor becomes invalid. -// If f is garbage collected, a finalizer may close the file descriptor, -// making it invalid; see runtime.SetFinalizer for more information on when -// a finalizer might be run. On Unix systems this will cause the SetDeadline -// methods to stop working. -// -// As an alternative, see the f.SyscallConn method. -func (f *File) Fd() uintptr { - if f == nil { - return ^(uintptr(0)) - } - return uintptr(f.fd) -} - -// NewFile returns a new File with the given file descriptor and -// name. The returned value will be nil if fd is not a valid file -// descriptor. -func NewFile(fd uintptr, name string) *File { - fdi := int(fd) - if fdi < 0 { - return nil - } - f := &File{&file{fd: fdi, name: name}} - runtime.SetFinalizer(f.file, (*file).close) - return f -} - -// Auxiliary information if the File describes a directory -type dirInfo struct { - buf [syscall.STATMAX]byte // buffer for directory I/O - nbuf int // length of buf; return value from Read - bufp int // location of next record in buf. -} - -func epipecheck(file *File, e error) { -} - -// DevNull is the name of the operating system's “null device.” -// On Unix-like systems, it is "/dev/null"; on Windows, "NUL". -const DevNull = "/dev/null" - -// syscallMode returns the syscall-specific mode bits from Go's portable mode bits. -func syscallMode(i FileMode) (o uint32) { - o |= uint32(i.Perm()) - if i&ModeAppend != 0 { - o |= syscall.DMAPPEND - } - if i&ModeExclusive != 0 { - o |= syscall.DMEXCL - } - if i&ModeTemporary != 0 { - o |= syscall.DMTMP - } - return -} - -// openFileNolog is the Plan 9 implementation of OpenFile. -func openFileNolog(name string, flag int, perm FileMode) (*File, error) { - var ( - fd int - e error - create bool - excl bool - trunc bool - append bool - ) - - if flag&O_CREATE == O_CREATE { - flag = flag & ^O_CREATE - create = true - } - if flag&O_EXCL == O_EXCL { - excl = true - } - if flag&O_TRUNC == O_TRUNC { - trunc = true - } - // O_APPEND is emulated on Plan 9 - if flag&O_APPEND == O_APPEND { - flag = flag &^ O_APPEND - append = true - } - - if (create && trunc) || excl { - fd, e = syscall.Create(name, flag, syscallMode(perm)) - } else { - fd, e = syscall.Open(name, flag) - if IsNotExist(e) && create { - fd, e = syscall.Create(name, flag, syscallMode(perm)) - if e != nil { - return nil, &PathError{Op: "create", Path: name, Err: e} - } - } - } - - if e != nil { - return nil, &PathError{Op: "open", Path: name, Err: e} - } - - if append { - if _, e = syscall.Seek(fd, 0, io.SeekEnd); e != nil { - return nil, &PathError{Op: "seek", Path: name, Err: e} - } - } - - return NewFile(uintptr(fd), name), nil -} - -// Close closes the File, rendering it unusable for I/O. -// On files that support SetDeadline, any pending I/O operations will -// be canceled and return immediately with an ErrClosed error. -// Close will return an error if it has already been called. -func (f *File) Close() error { - if f == nil { - return ErrInvalid - } - return f.file.close() -} - -func (file *file) close() error { - if !file.fdmu.IncrefAndClose() { - return &PathError{Op: "close", Path: file.name, Err: ErrClosed} - } - - // At this point we should cancel any pending I/O. - // How do we do that on Plan 9? - - err := file.decref() - - // no need for a finalizer anymore - runtime.SetFinalizer(file, nil) - return err -} - -// destroy actually closes the descriptor. This is called when -// there are no remaining references, by the decref, readUnlock, -// and writeUnlock methods. -func (file *file) destroy() error { - var err error - if e := syscall.Close(file.fd); e != nil { - err = &PathError{Op: "close", Path: file.name, Err: e} - } - return err -} - -// Stat returns the FileInfo structure describing file. -// If there is an error, it will be of type *PathError. -func (f *File) Stat() (FileInfo, error) { - if f == nil { - return nil, ErrInvalid - } - d, err := dirstat(f) - if err != nil { - return nil, err - } - return fileInfoFromStat(d), nil -} - -// Truncate changes the size of the file. -// It does not change the I/O offset. -// If there is an error, it will be of type *PathError. -func (f *File) Truncate(size int64) error { - if f == nil { - return ErrInvalid - } - - var d syscall.Dir - d.Null() - d.Length = size - - var buf [syscall.STATFIXLEN]byte - n, err := d.Marshal(buf[:]) - if err != nil { - return &PathError{Op: "truncate", Path: f.name, Err: err} - } - - if err := f.incref("truncate"); err != nil { - return err - } - defer f.decref() - - if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { - return &PathError{Op: "truncate", Path: f.name, Err: err} - } - return nil -} - -const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm) - -func (f *File) chmod(mode FileMode) error { - if f == nil { - return ErrInvalid - } - var d syscall.Dir - - odir, e := dirstat(f) - if e != nil { - return &PathError{Op: "chmod", Path: f.name, Err: e} - } - d.Null() - d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask - - var buf [syscall.STATFIXLEN]byte - n, err := d.Marshal(buf[:]) - if err != nil { - return &PathError{Op: "chmod", Path: f.name, Err: err} - } - - if err := f.incref("chmod"); err != nil { - return err - } - defer f.decref() - - if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { - return &PathError{Op: "chmod", Path: f.name, Err: err} - } - return nil -} - -// Sync commits the current contents of the file to stable storage. -// Typically, this means flushing the file system's in-memory copy -// of recently written data to disk. -func (f *File) Sync() error { - if f == nil { - return ErrInvalid - } - var d syscall.Dir - d.Null() - - var buf [syscall.STATFIXLEN]byte - n, err := d.Marshal(buf[:]) - if err != nil { - return &PathError{Op: "sync", Path: f.name, Err: err} - } - - if err := f.incref("sync"); err != nil { - return err - } - defer f.decref() - - if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { - return &PathError{Op: "sync", Path: f.name, Err: err} - } - return nil -} - -// read reads up to len(b) bytes from the File. -// It returns the number of bytes read and an error, if any. -func (f *File) read(b []byte) (n int, err error) { - if err := f.readLock(); err != nil { - return 0, err - } - defer f.readUnlock() - n, e := fixCount(syscall.Read(f.fd, b)) - if n == 0 && len(b) > 0 && e == nil { - return 0, io.EOF - } - return n, e -} - -// pread reads len(b) bytes from the File starting at byte offset off. -// It returns the number of bytes read and the error, if any. -// EOF is signaled by a zero count with err set to nil. -func (f *File) pread(b []byte, off int64) (n int, err error) { - if err := f.readLock(); err != nil { - return 0, err - } - defer f.readUnlock() - n, e := fixCount(syscall.Pread(f.fd, b, off)) - if n == 0 && len(b) > 0 && e == nil { - return 0, io.EOF - } - return n, e -} - -// write writes len(b) bytes to the File. -// It returns the number of bytes written and an error, if any. -// Since Plan 9 preserves message boundaries, never allow -// a zero-byte write. -func (f *File) write(b []byte) (n int, err error) { - if err := f.writeLock(); err != nil { - return 0, err - } - defer f.writeUnlock() - if len(b) == 0 { - return 0, nil - } - return fixCount(syscall.Write(f.fd, b)) -} - -// pwrite writes len(b) bytes to the File starting at byte offset off. -// It returns the number of bytes written and an error, if any. -// Since Plan 9 preserves message boundaries, never allow -// a zero-byte write. -func (f *File) pwrite(b []byte, off int64) (n int, err error) { - if err := f.writeLock(); err != nil { - return 0, err - } - defer f.writeUnlock() - if len(b) == 0 { - return 0, nil - } - return fixCount(syscall.Pwrite(f.fd, b, off)) -} - -// seek sets the offset for the next Read or Write on file to offset, interpreted -// according to whence: 0 means relative to the origin of the file, 1 means -// relative to the current offset, and 2 means relative to the end. -// It returns the new offset and an error, if any. -func (f *File) seek(offset int64, whence int) (ret int64, err error) { - if err := f.incref(""); err != nil { - return 0, err - } - defer f.decref() - if f.dirinfo != nil { - // Free cached dirinfo, so we allocate a new one if we - // access this file as a directory again. See #35767 and #37161. - f.dirinfo = nil - } - return syscall.Seek(f.fd, offset, whence) -} - -// Truncate changes the size of the named file. -// If the file is a symbolic link, it changes the size of the link's target. -// If there is an error, it will be of type *PathError. -func Truncate(name string, size int64) error { - var d syscall.Dir - - d.Null() - d.Length = size - - var buf [syscall.STATFIXLEN]byte - n, err := d.Marshal(buf[:]) - if err != nil { - return &PathError{Op: "truncate", Path: name, Err: err} - } - if err = syscall.Wstat(name, buf[:n]); err != nil { - return &PathError{Op: "truncate", Path: name, Err: err} - } - return nil -} - -// Remove removes the named file or directory. -// If there is an error, it will be of type *PathError. -func Remove(name string) error { - if e := syscall.Remove(name); e != nil { - return &PathError{Op: "remove", Path: name, Err: e} - } - return nil -} - -// hasPrefix from the strings package. -func hasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[0:len(prefix)] == prefix -} - -func rename(oldname, newname string) error { - dirname := oldname[:bytealg.LastIndexByteString(oldname, '/')+1] - if hasPrefix(newname, dirname) { - newname = newname[len(dirname):] - } else { - return &LinkError{"rename", oldname, newname, ErrInvalid} - } - - // If newname still contains slashes after removing the oldname - // prefix, the rename is cross-directory and must be rejected. - if bytealg.LastIndexByteString(newname, '/') >= 0 { - return &LinkError{"rename", oldname, newname, ErrInvalid} - } - - var d syscall.Dir - - d.Null() - d.Name = newname - - buf := make([]byte, syscall.STATFIXLEN+len(d.Name)) - n, err := d.Marshal(buf[:]) - if err != nil { - return &LinkError{"rename", oldname, newname, err} - } - - // If newname already exists and is not a directory, rename replaces it. - f, err := Stat(dirname + newname) - if err == nil && !f.IsDir() { - Remove(dirname + newname) - } - - if err = syscall.Wstat(oldname, buf[:n]); err != nil { - return &LinkError{"rename", oldname, newname, err} - } - return nil -} - -// See docs in file.go:Chmod. -func chmod(name string, mode FileMode) error { - var d syscall.Dir - - odir, e := dirstat(name) - if e != nil { - return &PathError{Op: "chmod", Path: name, Err: e} - } - d.Null() - d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask - - var buf [syscall.STATFIXLEN]byte - n, err := d.Marshal(buf[:]) - if err != nil { - return &PathError{Op: "chmod", Path: name, Err: err} - } - if err = syscall.Wstat(name, buf[:n]); err != nil { - return &PathError{Op: "chmod", Path: name, Err: err} - } - return nil -} - -// Chtimes changes the access and modification times of the named -// file, similar to the Unix utime() or utimes() functions. -// A zero time.Time value will leave the corresponding file time unchanged. -// -// The underlying filesystem may truncate or round the values to a -// less precise time unit. -// If there is an error, it will be of type *PathError. -func Chtimes(name string, atime time.Time, mtime time.Time) error { - var d syscall.Dir - - d.Null() - d.Atime = uint32(atime.Unix()) - d.Mtime = uint32(mtime.Unix()) - if atime.IsZero() { - d.Atime = 0xFFFFFFFF - } - if mtime.IsZero() { - d.Mtime = 0xFFFFFFFF - } - - var buf [syscall.STATFIXLEN]byte - n, err := d.Marshal(buf[:]) - if err != nil { - return &PathError{Op: "chtimes", Path: name, Err: err} - } - if err = syscall.Wstat(name, buf[:n]); err != nil { - return &PathError{Op: "chtimes", Path: name, Err: err} - } - return nil -} - -// Pipe returns a connected pair of Files; reads from r return bytes -// written to w. It returns the files and an error, if any. -func Pipe() (r *File, w *File, err error) { - var p [2]int - - if e := syscall.Pipe(p[0:]); e != nil { - return nil, nil, NewSyscallError("pipe", e) - } - - return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil -} - -// not supported on Plan 9 - -// Link creates newname as a hard link to the oldname file. -// If there is an error, it will be of type *LinkError. -func Link(oldname, newname string) error { - return &LinkError{"link", oldname, newname, syscall.EPLAN9} -} - -// Symlink creates newname as a symbolic link to oldname. -// On Windows, a symlink to a non-existent oldname creates a file symlink; -// if oldname is later created as a directory the symlink will not work. -// If there is an error, it will be of type *LinkError. -func Symlink(oldname, newname string) error { - return &LinkError{"symlink", oldname, newname, syscall.EPLAN9} -} - -func readlink(name string) (string, error) { - return "", &PathError{Op: "readlink", Path: name, Err: syscall.EPLAN9} -} - -// Chown changes the numeric uid and gid of the named file. -// If the file is a symbolic link, it changes the uid and gid of the link's target. -// A uid or gid of -1 means to not change that value. -// If there is an error, it will be of type *PathError. -// -// On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or -// EPLAN9 error, wrapped in *PathError. -func Chown(name string, uid, gid int) error { - return &PathError{Op: "chown", Path: name, Err: syscall.EPLAN9} -} - -// Lchown changes the numeric uid and gid of the named file. -// If the file is a symbolic link, it changes the uid and gid of the link itself. -// If there is an error, it will be of type *PathError. -func Lchown(name string, uid, gid int) error { - return &PathError{Op: "lchown", Path: name, Err: syscall.EPLAN9} -} - -// Chown changes the numeric uid and gid of the named file. -// If there is an error, it will be of type *PathError. -func (f *File) Chown(uid, gid int) error { - if f == nil { - return ErrInvalid - } - return &PathError{Op: "chown", Path: f.name, Err: syscall.EPLAN9} -} - -func tempDir() string { - dir := Getenv("TMPDIR") - if dir == "" { - dir = "/tmp" - } - return dir -} - -// Chdir changes the current working directory to the file, -// which must be a directory. -// If there is an error, it will be of type *PathError. -func (f *File) Chdir() error { - if err := f.incref("chdir"); err != nil { - return err - } - defer f.decref() - if e := syscall.Fchdir(f.fd); e != nil { - return &PathError{Op: "chdir", Path: f.name, Err: e} - } - return nil -} - -// setDeadline sets the read and write deadline. -func (f *File) setDeadline(time.Time) error { - if err := f.checkValid("SetDeadline"); err != nil { - return err - } - return poll.ErrNoDeadline -} - -// setReadDeadline sets the read deadline. -func (f *File) setReadDeadline(time.Time) error { - if err := f.checkValid("SetReadDeadline"); err != nil { - return err - } - return poll.ErrNoDeadline -} - -// setWriteDeadline sets the write deadline. -func (f *File) setWriteDeadline(time.Time) error { - if err := f.checkValid("SetWriteDeadline"); err != nil { - return err - } - return poll.ErrNoDeadline -} - -// checkValid checks whether f is valid for use, but does not prepare -// to actually use it. If f is not ready checkValid returns an appropriate -// error, perhaps incorporating the operation name op. -func (f *File) checkValid(op string) error { - if f == nil { - return ErrInvalid - } - if err := f.incref(op); err != nil { - return err - } - return f.decref() -} - -type rawConn struct{} - -func (c *rawConn) Control(f func(uintptr)) error { - return syscall.EPLAN9 -} - -func (c *rawConn) Read(f func(uintptr) bool) error { - return syscall.EPLAN9 -} - -func (c *rawConn) Write(f func(uintptr) bool) error { - return syscall.EPLAN9 -} - -func newRawConn(file *File) (*rawConn, error) { - return nil, syscall.EPLAN9 -} - -func ignoringEINTR(fn func() error) error { - return fn() -} diff --git a/contrib/go/_std_1.22/src/os/file_unix.go b/contrib/go/_std_1.22/src/os/file_unix.go deleted file mode 100644 index 649ec3ebb591..000000000000 --- a/contrib/go/_std_1.22/src/os/file_unix.go +++ /dev/null @@ -1,495 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix || (js && wasm) || wasip1 - -package os - -import ( - "internal/poll" - "internal/syscall/unix" - "io/fs" - "runtime" - "syscall" - _ "unsafe" // for go:linkname -) - -const _UTIME_OMIT = unix.UTIME_OMIT - -// fixLongPath is a noop on non-Windows platforms. -func fixLongPath(path string) string { - return path -} - -func rename(oldname, newname string) error { - fi, err := Lstat(newname) - if err == nil && fi.IsDir() { - // There are two independent errors this function can return: - // one for a bad oldname, and one for a bad newname. - // At this point we've determined the newname is bad. - // But just in case oldname is also bad, prioritize returning - // the oldname error because that's what we did historically. - // However, if the old name and new name are not the same, yet - // they refer to the same file, it implies a case-only - // rename on a case-insensitive filesystem, which is ok. - if ofi, err := Lstat(oldname); err != nil { - if pe, ok := err.(*PathError); ok { - err = pe.Err - } - return &LinkError{"rename", oldname, newname, err} - } else if newname == oldname || !SameFile(fi, ofi) { - return &LinkError{"rename", oldname, newname, syscall.EEXIST} - } - } - err = ignoringEINTR(func() error { - return syscall.Rename(oldname, newname) - }) - if err != nil { - return &LinkError{"rename", oldname, newname, err} - } - return nil -} - -// file is the real representation of *File. -// The extra level of indirection ensures that no clients of os -// can overwrite this data, which could cause the finalizer -// to close the wrong file descriptor. -type file struct { - pfd poll.FD - name string - dirinfo *dirInfo // nil unless directory being read - nonblock bool // whether we set nonblocking mode - stdoutOrErr bool // whether this is stdout or stderr - appendMode bool // whether file is opened for appending -} - -// Fd returns the integer Unix file descriptor referencing the open file. -// If f is closed, the file descriptor becomes invalid. -// If f is garbage collected, a finalizer may close the file descriptor, -// making it invalid; see runtime.SetFinalizer for more information on when -// a finalizer might be run. On Unix systems this will cause the SetDeadline -// methods to stop working. -// Because file descriptors can be reused, the returned file descriptor may -// only be closed through the Close method of f, or by its finalizer during -// garbage collection. Otherwise, during garbage collection the finalizer -// may close an unrelated file descriptor with the same (reused) number. -// -// As an alternative, see the f.SyscallConn method. -func (f *File) Fd() uintptr { - if f == nil { - return ^(uintptr(0)) - } - - // If we put the file descriptor into nonblocking mode, - // then set it to blocking mode before we return it, - // because historically we have always returned a descriptor - // opened in blocking mode. The File will continue to work, - // but any blocking operation will tie up a thread. - if f.nonblock { - f.pfd.SetBlocking() - } - - return uintptr(f.pfd.Sysfd) -} - -// NewFile returns a new File with the given file descriptor and -// name. The returned value will be nil if fd is not a valid file -// descriptor. On Unix systems, if the file descriptor is in -// non-blocking mode, NewFile will attempt to return a pollable File -// (one for which the SetDeadline methods work). -// -// After passing it to NewFile, fd may become invalid under the same -// conditions described in the comments of the Fd method, and the same -// constraints apply. -func NewFile(fd uintptr, name string) *File { - fdi := int(fd) - if fdi < 0 { - return nil - } - - kind := kindNewFile - appendMode := false - if flags, err := unix.Fcntl(fdi, syscall.F_GETFL, 0); err == nil { - if unix.HasNonblockFlag(flags) { - kind = kindNonBlock - } - appendMode = flags&syscall.O_APPEND != 0 - } - f := newFile(fdi, name, kind) - f.appendMode = appendMode - return f -} - -// net_newUnixFile is a hidden entry point called by net.conn.File. -// This is used so that a nonblocking network connection will become -// blocking if code calls the Fd method. We don't want that for direct -// calls to NewFile: passing a nonblocking descriptor to NewFile should -// remain nonblocking if you get it back using Fd. But for net.conn.File -// the call to NewFile is hidden from the user. Historically in that case -// the Fd method has returned a blocking descriptor, and we want to -// retain that behavior because existing code expects it and depends on it. -// -//go:linkname net_newUnixFile net.newUnixFile -func net_newUnixFile(fd int, name string) *File { - if fd < 0 { - panic("invalid FD") - } - - f := newFile(fd, name, kindNonBlock) - f.nonblock = true // tell Fd to return blocking descriptor - return f -} - -// newFileKind describes the kind of file to newFile. -type newFileKind int - -const ( - // kindNewFile means that the descriptor was passed to us via NewFile. - kindNewFile newFileKind = iota - // kindOpenFile means that the descriptor was opened using - // Open, Create, or OpenFile (without O_NONBLOCK). - kindOpenFile - // kindPipe means that the descriptor was opened using Pipe. - kindPipe - // kindNonBlock means that the descriptor is already in - // non-blocking mode. - kindNonBlock - // kindNoPoll means that we should not put the descriptor into - // non-blocking mode, because we know it is not a pipe or FIFO. - // Used by openDirAt for directories. - kindNoPoll -) - -// newFile is like NewFile, but if called from OpenFile or Pipe -// (as passed in the kind parameter) it tries to add the file to -// the runtime poller. -func newFile(fd int, name string, kind newFileKind) *File { - f := &File{&file{ - pfd: poll.FD{ - Sysfd: fd, - IsStream: true, - ZeroReadIsEOF: true, - }, - name: name, - stdoutOrErr: fd == 1 || fd == 2, - }} - - pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock - - // If the caller passed a non-blocking filedes (kindNonBlock), - // we assume they know what they are doing so we allow it to be - // used with kqueue. - if kind == kindOpenFile { - switch runtime.GOOS { - case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd": - var st syscall.Stat_t - err := ignoringEINTR(func() error { - return syscall.Fstat(fd, &st) - }) - typ := st.Mode & syscall.S_IFMT - // Don't try to use kqueue with regular files on *BSDs. - // On FreeBSD a regular file is always - // reported as ready for writing. - // On Dragonfly, NetBSD and OpenBSD the fd is signaled - // only once as ready (both read and write). - // Issue 19093. - // Also don't add directories to the netpoller. - if err == nil && (typ == syscall.S_IFREG || typ == syscall.S_IFDIR) { - pollable = false - } - - // In addition to the behavior described above for regular files, - // on Darwin, kqueue does not work properly with fifos: - // closing the last writer does not cause a kqueue event - // for any readers. See issue #24164. - if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && typ == syscall.S_IFIFO { - pollable = false - } - } - } - - clearNonBlock := false - if pollable { - if kind == kindNonBlock { - // The descriptor is already in non-blocking mode. - // We only set f.nonblock if we put the file into - // non-blocking mode. - } else if err := syscall.SetNonblock(fd, true); err == nil { - f.nonblock = true - clearNonBlock = true - } else { - pollable = false - } - } - - // An error here indicates a failure to register - // with the netpoll system. That can happen for - // a file descriptor that is not supported by - // epoll/kqueue; for example, disk files on - // Linux systems. We assume that any real error - // will show up in later I/O. - // We do restore the blocking behavior if it was set by us. - if pollErr := f.pfd.Init("file", pollable); pollErr != nil && clearNonBlock { - if err := syscall.SetNonblock(fd, false); err == nil { - f.nonblock = false - } - } - - runtime.SetFinalizer(f.file, (*file).close) - return f -} - -func sigpipe() // implemented in package runtime - -// epipecheck raises SIGPIPE if we get an EPIPE error on standard -// output or standard error. See the SIGPIPE docs in os/signal, and -// issue 11845. -func epipecheck(file *File, e error) { - if e == syscall.EPIPE && file.stdoutOrErr { - sigpipe() - } -} - -// DevNull is the name of the operating system's “null device.” -// On Unix-like systems, it is "/dev/null"; on Windows, "NUL". -const DevNull = "/dev/null" - -// openFileNolog is the Unix implementation of OpenFile. -// Changes here should be reflected in openDirAt, if relevant. -func openFileNolog(name string, flag int, perm FileMode) (*File, error) { - setSticky := false - if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 { - if _, err := Stat(name); IsNotExist(err) { - setSticky = true - } - } - - var r int - var s poll.SysFile - for { - var e error - r, s, e = open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) - if e == nil { - break - } - - // We have to check EINTR here, per issues 11180 and 39237. - if e == syscall.EINTR { - continue - } - - return nil, &PathError{Op: "open", Path: name, Err: e} - } - - // open(2) itself won't handle the sticky bit on *BSD and Solaris - if setSticky { - setStickyBit(name) - } - - // There's a race here with fork/exec, which we are - // content to live with. See ../syscall/exec_unix.go. - if !supportsCloseOnExec { - syscall.CloseOnExec(r) - } - - kind := kindOpenFile - if unix.HasNonblockFlag(flag) { - kind = kindNonBlock - } - - f := newFile(r, name, kind) - f.pfd.SysFile = s - return f, nil -} - -func (file *file) close() error { - if file == nil { - return syscall.EINVAL - } - if file.dirinfo != nil { - file.dirinfo.close() - file.dirinfo = nil - } - var err error - if e := file.pfd.Close(); e != nil { - if e == poll.ErrFileClosing { - e = ErrClosed - } - err = &PathError{Op: "close", Path: file.name, Err: e} - } - - // no need for a finalizer anymore - runtime.SetFinalizer(file, nil) - return err -} - -// seek sets the offset for the next Read or Write on file to offset, interpreted -// according to whence: 0 means relative to the origin of the file, 1 means -// relative to the current offset, and 2 means relative to the end. -// It returns the new offset and an error, if any. -func (f *File) seek(offset int64, whence int) (ret int64, err error) { - if f.dirinfo != nil { - // Free cached dirinfo, so we allocate a new one if we - // access this file as a directory again. See #35767 and #37161. - f.dirinfo.close() - f.dirinfo = nil - } - ret, err = f.pfd.Seek(offset, whence) - runtime.KeepAlive(f) - return ret, err -} - -// Truncate changes the size of the named file. -// If the file is a symbolic link, it changes the size of the link's target. -// If there is an error, it will be of type *PathError. -func Truncate(name string, size int64) error { - e := ignoringEINTR(func() error { - return syscall.Truncate(name, size) - }) - if e != nil { - return &PathError{Op: "truncate", Path: name, Err: e} - } - return nil -} - -// Remove removes the named file or (empty) directory. -// If there is an error, it will be of type *PathError. -func Remove(name string) error { - // System call interface forces us to know - // whether name is a file or directory. - // Try both: it is cheaper on average than - // doing a Stat plus the right one. - e := ignoringEINTR(func() error { - return syscall.Unlink(name) - }) - if e == nil { - return nil - } - e1 := ignoringEINTR(func() error { - return syscall.Rmdir(name) - }) - if e1 == nil { - return nil - } - - // Both failed: figure out which error to return. - // OS X and Linux differ on whether unlink(dir) - // returns EISDIR, so can't use that. However, - // both agree that rmdir(file) returns ENOTDIR, - // so we can use that to decide which error is real. - // Rmdir might also return ENOTDIR if given a bad - // file path, like /etc/passwd/foo, but in that case, - // both errors will be ENOTDIR, so it's okay to - // use the error from unlink. - if e1 != syscall.ENOTDIR { - e = e1 - } - return &PathError{Op: "remove", Path: name, Err: e} -} - -func tempDir() string { - dir := Getenv("TMPDIR") - if dir == "" { - if runtime.GOOS == "android" { - dir = "/data/local/tmp" - } else { - dir = "/tmp" - } - } - return dir -} - -// Link creates newname as a hard link to the oldname file. -// If there is an error, it will be of type *LinkError. -func Link(oldname, newname string) error { - e := ignoringEINTR(func() error { - return syscall.Link(oldname, newname) - }) - if e != nil { - return &LinkError{"link", oldname, newname, e} - } - return nil -} - -// Symlink creates newname as a symbolic link to oldname. -// On Windows, a symlink to a non-existent oldname creates a file symlink; -// if oldname is later created as a directory the symlink will not work. -// If there is an error, it will be of type *LinkError. -func Symlink(oldname, newname string) error { - e := ignoringEINTR(func() error { - return syscall.Symlink(oldname, newname) - }) - if e != nil { - return &LinkError{"symlink", oldname, newname, e} - } - return nil -} - -func readlink(name string) (string, error) { - for len := 128; ; len *= 2 { - b := make([]byte, len) - var ( - n int - e error - ) - for { - n, e = fixCount(syscall.Readlink(name, b)) - if e != syscall.EINTR { - break - } - } - // buffer too small - if (runtime.GOOS == "aix" || runtime.GOOS == "wasip1") && e == syscall.ERANGE { - continue - } - if e != nil { - return "", &PathError{Op: "readlink", Path: name, Err: e} - } - if n < len { - return string(b[0:n]), nil - } - } -} - -type unixDirent struct { - parent string - name string - typ FileMode - info FileInfo -} - -func (d *unixDirent) Name() string { return d.name } -func (d *unixDirent) IsDir() bool { return d.typ.IsDir() } -func (d *unixDirent) Type() FileMode { return d.typ } - -func (d *unixDirent) Info() (FileInfo, error) { - if d.info != nil { - return d.info, nil - } - return lstat(d.parent + "/" + d.name) -} - -func (d *unixDirent) String() string { - return fs.FormatDirEntry(d) -} - -func newUnixDirent(parent, name string, typ FileMode) (DirEntry, error) { - ude := &unixDirent{ - parent: parent, - name: name, - typ: typ, - } - if typ != ^FileMode(0) && !testingForceReadDirLstat { - return ude, nil - } - - info, err := lstat(parent + "/" + name) - if err != nil { - return nil, err - } - - ude.typ = info.Mode().Type() - ude.info = info - return ude, nil -} diff --git a/contrib/go/_std_1.22/src/os/path.go b/contrib/go/_std_1.22/src/os/path.go deleted file mode 100644 index 6ac4cbe20f78..000000000000 --- a/contrib/go/_std_1.22/src/os/path.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "syscall" -) - -// MkdirAll creates a directory named path, -// along with any necessary parents, and returns nil, -// or else returns an error. -// The permission bits perm (before umask) are used for all -// directories that MkdirAll creates. -// If path is already a directory, MkdirAll does nothing -// and returns nil. -func MkdirAll(path string, perm FileMode) error { - // Fast path: if we can tell whether path is a directory or file, stop with success or error. - dir, err := Stat(path) - if err == nil { - if dir.IsDir() { - return nil - } - return &PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} - } - - // Slow path: make sure parent exists and then call Mkdir for path. - - // Extract the parent folder from path by first removing any trailing - // path separator and then scanning backward until finding a path - // separator or reaching the beginning of the string. - i := len(path) - 1 - for i >= 0 && IsPathSeparator(path[i]) { - i-- - } - for i >= 0 && !IsPathSeparator(path[i]) { - i-- - } - if i < 0 { - i = 0 - } - - // If there is a parent directory, and it is not the volume name, - // recurse to ensure parent directory exists. - if parent := path[:i]; len(parent) > len(volumeName(path)) { - err = MkdirAll(parent, perm) - if err != nil { - return err - } - } - - // Parent now exists; invoke Mkdir and use its result. - err = Mkdir(path, perm) - if err != nil { - // Handle arguments like "foo/." by - // double-checking that directory doesn't exist. - dir, err1 := Lstat(path) - if err1 == nil && dir.IsDir() { - return nil - } - return err - } - return nil -} - -// RemoveAll removes path and any children it contains. -// It removes everything it can but returns the first error -// it encounters. If the path does not exist, RemoveAll -// returns nil (no error). -// If there is an error, it will be of type *PathError. -func RemoveAll(path string) error { - return removeAll(path) -} - -// endsWithDot reports whether the final component of path is ".". -func endsWithDot(path string) bool { - if path == "." { - return true - } - if len(path) >= 2 && path[len(path)-1] == '.' && IsPathSeparator(path[len(path)-2]) { - return true - } - return false -} diff --git a/contrib/go/_std_1.22/src/os/path_plan9.go b/contrib/go/_std_1.22/src/os/path_plan9.go deleted file mode 100644 index f1c9dbc048c1..000000000000 --- a/contrib/go/_std_1.22/src/os/path_plan9.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -const ( - PathSeparator = '/' // OS-specific path separator - PathListSeparator = '\000' // OS-specific path list separator -) - -// IsPathSeparator reports whether c is a directory separator character. -func IsPathSeparator(c uint8) bool { - return PathSeparator == c -} - -func volumeName(p string) string { - return "" -} diff --git a/contrib/go/_std_1.22/src/os/path_unix.go b/contrib/go/_std_1.22/src/os/path_unix.go deleted file mode 100644 index 1c80fa91f8be..000000000000 --- a/contrib/go/_std_1.22/src/os/path_unix.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix || (js && wasm) || wasip1 - -package os - -const ( - PathSeparator = '/' // OS-specific path separator - PathListSeparator = ':' // OS-specific path list separator -) - -// IsPathSeparator reports whether c is a directory separator character. -func IsPathSeparator(c uint8) bool { - return PathSeparator == c -} - -// basename removes trailing slashes and the leading directory name from path name. -func basename(name string) string { - i := len(name) - 1 - // Remove trailing slashes - for ; i > 0 && name[i] == '/'; i-- { - name = name[:i] - } - // Remove leading directory name - for i--; i >= 0; i-- { - if name[i] == '/' { - name = name[i+1:] - break - } - } - - return name -} - -// splitPath returns the base name and parent directory. -func splitPath(path string) (string, string) { - // if no better parent is found, the path is relative from "here" - dirname := "." - - // Remove all but one leading slash. - for len(path) > 1 && path[0] == '/' && path[1] == '/' { - path = path[1:] - } - - i := len(path) - 1 - - // Remove trailing slashes. - for ; i > 0 && path[i] == '/'; i-- { - path = path[:i] - } - - // if no slashes in path, base is path - basename := path - - // Remove leading directory path - for i--; i >= 0; i-- { - if path[i] == '/' { - if i == 0 { - dirname = path[:1] - } else { - dirname = path[:i] - } - basename = path[i+1:] - break - } - } - - return dirname, basename -} - -func volumeName(p string) string { - return "" -} diff --git a/contrib/go/_std_1.22/src/os/path_windows.go b/contrib/go/_std_1.22/src/os/path_windows.go deleted file mode 100644 index 052202514825..000000000000 --- a/contrib/go/_std_1.22/src/os/path_windows.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -const ( - PathSeparator = '\\' // OS-specific path separator - PathListSeparator = ';' // OS-specific path list separator -) - -// IsPathSeparator reports whether c is a directory separator character. -func IsPathSeparator(c uint8) bool { - // NOTE: Windows accepts / as path separator. - return c == '\\' || c == '/' -} - -// basename removes trailing slashes and the leading -// directory name and drive letter from path name. -func basename(name string) string { - // Remove drive letter - if len(name) == 2 && name[1] == ':' { - name = "." - } else if len(name) > 2 && name[1] == ':' { - name = name[2:] - } - i := len(name) - 1 - // Remove trailing slashes - for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- { - name = name[:i] - } - // Remove leading directory name - for i--; i >= 0; i-- { - if name[i] == '/' || name[i] == '\\' { - name = name[i+1:] - break - } - } - return name -} - -func isAbs(path string) (b bool) { - v := volumeName(path) - if v == "" { - return false - } - path = path[len(v):] - if path == "" { - return false - } - return IsPathSeparator(path[0]) -} - -func volumeName(path string) (v string) { - if len(path) < 2 { - return "" - } - // with drive letter - c := path[0] - if path[1] == ':' && - ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' || - 'A' <= c && c <= 'Z') { - return path[:2] - } - // is it UNC - if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) && - !IsPathSeparator(path[2]) && path[2] != '.' { - // first, leading `\\` and next shouldn't be `\`. its server name. - for n := 3; n < l-1; n++ { - // second, next '\' shouldn't be repeated. - if IsPathSeparator(path[n]) { - n++ - // third, following something characters. its share name. - if !IsPathSeparator(path[n]) { - if path[n] == '.' { - break - } - for ; n < l; n++ { - if IsPathSeparator(path[n]) { - break - } - } - return path[:n] - } - break - } - } - } - return "" -} - -func fromSlash(path string) string { - // Replace each '/' with '\\' if present - var pathbuf []byte - var lastSlash int - for i, b := range path { - if b == '/' { - if pathbuf == nil { - pathbuf = make([]byte, len(path)) - } - copy(pathbuf[lastSlash:], path[lastSlash:i]) - pathbuf[i] = '\\' - lastSlash = i + 1 - } - } - if pathbuf == nil { - return path - } - - copy(pathbuf[lastSlash:], path[lastSlash:]) - return string(pathbuf) -} - -func dirname(path string) string { - vol := volumeName(path) - i := len(path) - 1 - for i >= len(vol) && !IsPathSeparator(path[i]) { - i-- - } - dir := path[len(vol) : i+1] - last := len(dir) - 1 - if last > 0 && IsPathSeparator(dir[last]) { - dir = dir[:last] - } - if dir == "" { - dir = "." - } - return vol + dir -} - -// This is set via go:linkname on runtime.canUseLongPaths, and is true when the OS -// supports opting into proper long path handling without the need for fixups. -var canUseLongPaths bool - -// fixLongPath returns the extended-length (\\?\-prefixed) form of -// path when needed, in order to avoid the default 260 character file -// path limit imposed by Windows. If path is not easily converted to -// the extended-length form (for example, if path is a relative path -// or contains .. elements), or is short enough, fixLongPath returns -// path unmodified. -// -// See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation -func fixLongPath(path string) string { - if canUseLongPaths { - return path - } - // Do nothing (and don't allocate) if the path is "short". - // Empirically (at least on the Windows Server 2013 builder), - // the kernel is arbitrarily okay with < 248 bytes. That - // matches what the docs above say: - // "When using an API to create a directory, the specified - // path cannot be so long that you cannot append an 8.3 file - // name (that is, the directory name cannot exceed MAX_PATH - // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248. - // - // The MSDN docs appear to say that a normal path that is 248 bytes long - // will work; empirically the path must be less then 248 bytes long. - if len(path) < 248 { - // Don't fix. (This is how Go 1.7 and earlier worked, - // not automatically generating the \\?\ form) - return path - } - - // The extended form begins with \\?\, as in - // \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt. - // The extended form disables evaluation of . and .. path - // elements and disables the interpretation of / as equivalent - // to \. The conversion here rewrites / to \ and elides - // . elements as well as trailing or duplicate separators. For - // simplicity it avoids the conversion entirely for relative - // paths or paths containing .. elements. For now, - // \\server\share paths are not converted to - // \\?\UNC\server\share paths because the rules for doing so - // are less well-specified. - if len(path) >= 2 && path[:2] == `\\` { - // Don't canonicalize UNC paths. - return path - } - if !isAbs(path) { - // Relative path - return path - } - - const prefix = `\\?` - - pathbuf := make([]byte, len(prefix)+len(path)+len(`\`)) - copy(pathbuf, prefix) - n := len(path) - r, w := 0, len(prefix) - for r < n { - switch { - case IsPathSeparator(path[r]): - // empty block - r++ - case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])): - // /./ - r++ - case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])): - // /../ is currently unhandled - return path - default: - pathbuf[w] = '\\' - w++ - for ; r < n && !IsPathSeparator(path[r]); r++ { - pathbuf[w] = path[r] - w++ - } - } - } - // A drive's root directory needs a trailing \ - if w == len(`\\?\c:`) { - pathbuf[w] = '\\' - w++ - } - return string(pathbuf[:w]) -} diff --git a/contrib/go/_std_1.22/src/os/proc.go b/contrib/go/_std_1.22/src/os/proc.go deleted file mode 100644 index 3aae5680eea5..000000000000 --- a/contrib/go/_std_1.22/src/os/proc.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Process etc. - -package os - -import ( - "internal/testlog" - "runtime" - "syscall" -) - -// Args hold the command-line arguments, starting with the program name. -var Args []string - -func init() { - if runtime.GOOS == "windows" { - // Initialized in exec_windows.go. - return - } - Args = runtime_args() -} - -func runtime_args() []string // in package runtime - -// Getuid returns the numeric user id of the caller. -// -// On Windows, it returns -1. -func Getuid() int { return syscall.Getuid() } - -// Geteuid returns the numeric effective user id of the caller. -// -// On Windows, it returns -1. -func Geteuid() int { return syscall.Geteuid() } - -// Getgid returns the numeric group id of the caller. -// -// On Windows, it returns -1. -func Getgid() int { return syscall.Getgid() } - -// Getegid returns the numeric effective group id of the caller. -// -// On Windows, it returns -1. -func Getegid() int { return syscall.Getegid() } - -// Getgroups returns a list of the numeric ids of groups that the caller belongs to. -// -// On Windows, it returns syscall.EWINDOWS. See the os/user package -// for a possible alternative. -func Getgroups() ([]int, error) { - gids, e := syscall.Getgroups() - return gids, NewSyscallError("getgroups", e) -} - -// Exit causes the current program to exit with the given status code. -// Conventionally, code zero indicates success, non-zero an error. -// The program terminates immediately; deferred functions are not run. -// -// For portability, the status code should be in the range [0, 125]. -func Exit(code int) { - if code == 0 && testlog.PanicOnExit0() { - // We were told to panic on calls to os.Exit(0). - // This is used to fail tests that make an early - // unexpected call to os.Exit(0). - panic("unexpected call to os.Exit(0) during test") - } - - // Inform the runtime that os.Exit is being called. If -race is - // enabled, this will give race detector a chance to fail the - // program (racy programs do not have the right to finish - // successfully). If coverage is enabled, then this call will - // enable us to write out a coverage data file. - runtime_beforeExit(code) - - syscall.Exit(code) -} - -func runtime_beforeExit(exitCode int) // implemented in runtime diff --git a/contrib/go/_std_1.22/src/os/signal/doc.go b/contrib/go/_std_1.22/src/os/signal/doc.go deleted file mode 100644 index a2a7525ef0ae..000000000000 --- a/contrib/go/_std_1.22/src/os/signal/doc.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package signal implements access to incoming signals. - -Signals are primarily used on Unix-like systems. For the use of this -package on Windows and Plan 9, see below. - -# Types of signals - -The signals SIGKILL and SIGSTOP may not be caught by a program, and -therefore cannot be affected by this package. - -Synchronous signals are signals triggered by errors in program -execution: SIGBUS, SIGFPE, and SIGSEGV. These are only considered -synchronous when caused by program execution, not when sent using -[os.Process.Kill] or the kill program or some similar mechanism. In -general, except as discussed below, Go programs will convert a -synchronous signal into a run-time panic. - -The remaining signals are asynchronous signals. They are not -triggered by program errors, but are instead sent from the kernel or -from some other program. - -Of the asynchronous signals, the SIGHUP signal is sent when a program -loses its controlling terminal. The SIGINT signal is sent when the -user at the controlling terminal presses the interrupt character, -which by default is ^C (Control-C). The SIGQUIT signal is sent when -the user at the controlling terminal presses the quit character, which -by default is ^\ (Control-Backslash). In general you can cause a -program to simply exit by pressing ^C, and you can cause it to exit -with a stack dump by pressing ^\. - -# Default behavior of signals in Go programs - -By default, a synchronous signal is converted into a run-time panic. A -SIGHUP, SIGINT, or SIGTERM signal causes the program to exit. A -SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGSTKFLT, SIGEMT, or SIGSYS signal -causes the program to exit with a stack dump. A SIGTSTP, SIGTTIN, or -SIGTTOU signal gets the system default behavior (these signals are -used by the shell for job control). The SIGPROF signal is handled -directly by the Go runtime to implement runtime.CPUProfile. Other -signals will be caught but no action will be taken. - -If the Go program is started with either SIGHUP or SIGINT ignored -(signal handler set to SIG_IGN), they will remain ignored. - -If the Go program is started with a non-empty signal mask, that will -generally be honored. However, some signals are explicitly unblocked: -the synchronous signals, SIGILL, SIGTRAP, SIGSTKFLT, SIGCHLD, SIGPROF, -and, on Linux, signals 32 (SIGCANCEL) and 33 (SIGSETXID) -(SIGCANCEL and SIGSETXID are used internally by glibc). Subprocesses -started by [os.Exec], or by [os/exec], will inherit the -modified signal mask. - -# Changing the behavior of signals in Go programs - -The functions in this package allow a program to change the way Go -programs handle signals. - -Notify disables the default behavior for a given set of asynchronous -signals and instead delivers them over one or more registered -channels. Specifically, it applies to the signals SIGHUP, SIGINT, -SIGQUIT, SIGABRT, and SIGTERM. It also applies to the job control -signals SIGTSTP, SIGTTIN, and SIGTTOU, in which case the system -default behavior does not occur. It also applies to some signals that -otherwise cause no action: SIGUSR1, SIGUSR2, SIGPIPE, SIGALRM, -SIGCHLD, SIGCONT, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGWINCH, -SIGIO, SIGPWR, SIGSYS, SIGINFO, SIGTHR, SIGWAITING, SIGLWP, SIGFREEZE, -SIGTHAW, SIGLOST, SIGXRES, SIGJVM1, SIGJVM2, and any real time signals -used on the system. Note that not all of these signals are available -on all systems. - -If the program was started with SIGHUP or SIGINT ignored, and Notify -is called for either signal, a signal handler will be installed for -that signal and it will no longer be ignored. If, later, Reset or -Ignore is called for that signal, or Stop is called on all channels -passed to Notify for that signal, the signal will once again be -ignored. Reset will restore the system default behavior for the -signal, while Ignore will cause the system to ignore the signal -entirely. - -If the program is started with a non-empty signal mask, some signals -will be explicitly unblocked as described above. If Notify is called -for a blocked signal, it will be unblocked. If, later, Reset is -called for that signal, or Stop is called on all channels passed to -Notify for that signal, the signal will once again be blocked. - -# SIGPIPE - -When a Go program writes to a broken pipe, the kernel will raise a -SIGPIPE signal. - -If the program has not called Notify to receive SIGPIPE signals, then -the behavior depends on the file descriptor number. A write to a -broken pipe on file descriptors 1 or 2 (standard output or standard -error) will cause the program to exit with a SIGPIPE signal. A write -to a broken pipe on some other file descriptor will take no action on -the SIGPIPE signal, and the write will fail with an EPIPE error. - -If the program has called Notify to receive SIGPIPE signals, the file -descriptor number does not matter. The SIGPIPE signal will be -delivered to the Notify channel, and the write will fail with an EPIPE -error. - -This means that, by default, command line programs will behave like -typical Unix command line programs, while other programs will not -crash with SIGPIPE when writing to a closed network connection. - -# Go programs that use cgo or SWIG - -In a Go program that includes non-Go code, typically C/C++ code -accessed using cgo or SWIG, Go's startup code normally runs first. It -configures the signal handlers as expected by the Go runtime, before -the non-Go startup code runs. If the non-Go startup code wishes to -install its own signal handlers, it must take certain steps to keep Go -working well. This section documents those steps and the overall -effect changes to signal handler settings by the non-Go code can have -on Go programs. In rare cases, the non-Go code may run before the Go -code, in which case the next section also applies. - -If the non-Go code called by the Go program does not change any signal -handlers or masks, then the behavior is the same as for a pure Go -program. - -If the non-Go code installs any signal handlers, it must use the -SA_ONSTACK flag with sigaction. Failing to do so is likely to cause -the program to crash if the signal is received. Go programs routinely -run with a limited stack, and therefore set up an alternate signal -stack. - -If the non-Go code installs a signal handler for any of the -synchronous signals (SIGBUS, SIGFPE, SIGSEGV), then it should record -the existing Go signal handler. If those signals occur while -executing Go code, it should invoke the Go signal handler (whether the -signal occurs while executing Go code can be determined by looking at -the PC passed to the signal handler). Otherwise some Go run-time -panics will not occur as expected. - -If the non-Go code installs a signal handler for any of the -asynchronous signals, it may invoke the Go signal handler or not as it -chooses. Naturally, if it does not invoke the Go signal handler, the -Go behavior described above will not occur. This can be an issue with -the SIGPROF signal in particular. - -The non-Go code should not change the signal mask on any threads -created by the Go runtime. If the non-Go code starts new threads of -its own, it may set the signal mask as it pleases. - -If the non-Go code starts a new thread, changes the signal mask, and -then invokes a Go function in that thread, the Go runtime will -automatically unblock certain signals: the synchronous signals, -SIGILL, SIGTRAP, SIGSTKFLT, SIGCHLD, SIGPROF, SIGCANCEL, and -SIGSETXID. When the Go function returns, the non-Go signal mask will -be restored. - -If the Go signal handler is invoked on a non-Go thread not running Go -code, the handler generally forwards the signal to the non-Go code, as -follows. If the signal is SIGPROF, the Go handler does -nothing. Otherwise, the Go handler removes itself, unblocks the -signal, and raises it again, to invoke any non-Go handler or default -system handler. If the program does not exit, the Go handler then -reinstalls itself and continues execution of the program. - -If a SIGPIPE signal is received, the Go program will invoke the -special handling described above if the SIGPIPE is received on a Go -thread. If the SIGPIPE is received on a non-Go thread the signal will -be forwarded to the non-Go handler, if any; if there is none the -default system handler will cause the program to terminate. - -# Non-Go programs that call Go code - -When Go code is built with options like -buildmode=c-shared, it will -be run as part of an existing non-Go program. The non-Go code may -have already installed signal handlers when the Go code starts (that -may also happen in unusual cases when using cgo or SWIG; in that case, -the discussion here applies). For -buildmode=c-archive the Go runtime -will initialize signals at global constructor time. For --buildmode=c-shared the Go runtime will initialize signals when the -shared library is loaded. - -If the Go runtime sees an existing signal handler for the SIGCANCEL or -SIGSETXID signals (which are used only on Linux), it will turn on -the SA_ONSTACK flag and otherwise keep the signal handler. - -For the synchronous signals and SIGPIPE, the Go runtime will install a -signal handler. It will save any existing signal handler. If a -synchronous signal arrives while executing non-Go code, the Go runtime -will invoke the existing signal handler instead of the Go signal -handler. - -Go code built with -buildmode=c-archive or -buildmode=c-shared will -not install any other signal handlers by default. If there is an -existing signal handler, the Go runtime will turn on the SA_ONSTACK -flag and otherwise keep the signal handler. If Notify is called for an -asynchronous signal, a Go signal handler will be installed for that -signal. If, later, Reset is called for that signal, the original -handling for that signal will be reinstalled, restoring the non-Go -signal handler if any. - -Go code built without -buildmode=c-archive or -buildmode=c-shared will -install a signal handler for the asynchronous signals listed above, -and save any existing signal handler. If a signal is delivered to a -non-Go thread, it will act as described above, except that if there is -an existing non-Go signal handler, that handler will be installed -before raising the signal. - -# Windows - -On Windows a ^C (Control-C) or ^BREAK (Control-Break) normally cause -the program to exit. If Notify is called for [os.Interrupt], ^C or ^BREAK -will cause [os.Interrupt] to be sent on the channel, and the program will -not exit. If Reset is called, or Stop is called on all channels passed -to Notify, then the default behavior will be restored. - -Additionally, if Notify is called, and Windows sends CTRL_CLOSE_EVENT, -CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT to the process, Notify will -return syscall.SIGTERM. Unlike Control-C and Control-Break, Notify does -not change process behavior when either CTRL_CLOSE_EVENT, -CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT is received - the process will -still get terminated unless it exits. But receiving syscall.SIGTERM will -give the process an opportunity to clean up before termination. - -# Plan 9 - -On Plan 9, signals have type syscall.Note, which is a string. Calling -Notify with a syscall.Note will cause that value to be sent on the -channel when that string is posted as a note. -*/ -package signal diff --git a/contrib/go/_std_1.22/src/os/types.go b/contrib/go/_std_1.22/src/os/types.go deleted file mode 100644 index d8edd98b68d7..000000000000 --- a/contrib/go/_std_1.22/src/os/types.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "io/fs" - "syscall" -) - -// Getpagesize returns the underlying system's memory page size. -func Getpagesize() int { return syscall.Getpagesize() } - -// File represents an open file descriptor. -type File struct { - *file // os specific -} - -// A FileInfo describes a file and is returned by Stat and Lstat. -type FileInfo = fs.FileInfo - -// A FileMode represents a file's mode and permission bits. -// The bits have the same definition on all systems, so that -// information about files can be moved from one system -// to another portably. Not all bits apply to all systems. -// The only required bit is ModeDir for directories. -type FileMode = fs.FileMode - -// The defined file mode bits are the most significant bits of the FileMode. -// The nine least-significant bits are the standard Unix rwxrwxrwx permissions. -// The values of these bits should be considered part of the public API and -// may be used in wire protocols or disk representations: they must not be -// changed, although new bits might be added. -const ( - // The single letters are the abbreviations - // used by the String method's formatting. - ModeDir = fs.ModeDir // d: is a directory - ModeAppend = fs.ModeAppend // a: append-only - ModeExclusive = fs.ModeExclusive // l: exclusive use - ModeTemporary = fs.ModeTemporary // T: temporary file; Plan 9 only - ModeSymlink = fs.ModeSymlink // L: symbolic link - ModeDevice = fs.ModeDevice // D: device file - ModeNamedPipe = fs.ModeNamedPipe // p: named pipe (FIFO) - ModeSocket = fs.ModeSocket // S: Unix domain socket - ModeSetuid = fs.ModeSetuid // u: setuid - ModeSetgid = fs.ModeSetgid // g: setgid - ModeCharDevice = fs.ModeCharDevice // c: Unix character device, when ModeDevice is set - ModeSticky = fs.ModeSticky // t: sticky - ModeIrregular = fs.ModeIrregular // ?: non-regular file; nothing else is known about this file - - // Mask for the type bits. For regular files, none will be set. - ModeType = fs.ModeType - - ModePerm = fs.ModePerm // Unix permission bits, 0o777 -) - -func (fs *fileStat) Name() string { return fs.name } -func (fs *fileStat) IsDir() bool { return fs.Mode().IsDir() } - -// SameFile reports whether fi1 and fi2 describe the same file. -// For example, on Unix this means that the device and inode fields -// of the two underlying structures are identical; on other systems -// the decision may be based on the path names. -// SameFile only applies to results returned by this package's Stat. -// It returns false in other cases. -func SameFile(fi1, fi2 FileInfo) bool { - fs1, ok1 := fi1.(*fileStat) - fs2, ok2 := fi2.(*fileStat) - if !ok1 || !ok2 { - return false - } - return sameFile(fs1, fs2) -} diff --git a/contrib/go/_std_1.22/src/os/types_windows.go b/contrib/go/_std_1.22/src/os/types_windows.go deleted file mode 100644 index 6b9fef6c123f..000000000000 --- a/contrib/go/_std_1.22/src/os/types_windows.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "internal/syscall/windows" - "sync" - "syscall" - "time" - "unsafe" -) - -// A fileStat is the implementation of FileInfo returned by Stat and Lstat. -type fileStat struct { - name string - - // from ByHandleFileInformation, Win32FileAttributeData, Win32finddata, and GetFileInformationByHandleEx - FileAttributes uint32 - CreationTime syscall.Filetime - LastAccessTime syscall.Filetime - LastWriteTime syscall.Filetime - FileSizeHigh uint32 - FileSizeLow uint32 - - // from Win32finddata and GetFileInformationByHandleEx - ReparseTag uint32 - - // what syscall.GetFileType returns - filetype uint32 - - // used to implement SameFile - sync.Mutex - path string - vol uint32 - idxhi uint32 - idxlo uint32 - appendNameToPath bool -} - -// newFileStatFromGetFileInformationByHandle calls GetFileInformationByHandle -// to gather all required information about the file handle h. -func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (fs *fileStat, err error) { - var d syscall.ByHandleFileInformation - err = syscall.GetFileInformationByHandle(h, &d) - if err != nil { - return nil, &PathError{Op: "GetFileInformationByHandle", Path: path, Err: err} - } - - var ti windows.FILE_ATTRIBUTE_TAG_INFO - err = windows.GetFileInformationByHandleEx(h, windows.FileAttributeTagInfo, (*byte)(unsafe.Pointer(&ti)), uint32(unsafe.Sizeof(ti))) - if err != nil { - if errno, ok := err.(syscall.Errno); ok && errno == windows.ERROR_INVALID_PARAMETER { - // It appears calling GetFileInformationByHandleEx with - // FILE_ATTRIBUTE_TAG_INFO fails on FAT file system with - // ERROR_INVALID_PARAMETER. Clear ti.ReparseTag in that - // instance to indicate no symlinks are possible. - ti.ReparseTag = 0 - } else { - return nil, &PathError{Op: "GetFileInformationByHandleEx", Path: path, Err: err} - } - } - - return &fileStat{ - name: basename(path), - FileAttributes: d.FileAttributes, - CreationTime: d.CreationTime, - LastAccessTime: d.LastAccessTime, - LastWriteTime: d.LastWriteTime, - FileSizeHigh: d.FileSizeHigh, - FileSizeLow: d.FileSizeLow, - vol: d.VolumeSerialNumber, - idxhi: d.FileIndexHigh, - idxlo: d.FileIndexLow, - ReparseTag: ti.ReparseTag, - // fileStat.path is used by os.SameFile to decide if it needs - // to fetch vol, idxhi and idxlo. But these are already set, - // so set fileStat.path to "" to prevent os.SameFile doing it again. - }, nil -} - -// newFileStatFromFileIDBothDirInfo copies all required information -// from windows.FILE_ID_BOTH_DIR_INFO d into the newly created fileStat. -func newFileStatFromFileIDBothDirInfo(d *windows.FILE_ID_BOTH_DIR_INFO) *fileStat { - // The FILE_ID_BOTH_DIR_INFO MSDN documentations isn't completely correct. - // FileAttributes can contain any file attributes that is currently set on the file, - // not just the ones documented. - // EaSize contains the reparse tag if the file is a reparse point. - return &fileStat{ - FileAttributes: d.FileAttributes, - CreationTime: d.CreationTime, - LastAccessTime: d.LastAccessTime, - LastWriteTime: d.LastWriteTime, - FileSizeHigh: uint32(d.EndOfFile >> 32), - FileSizeLow: uint32(d.EndOfFile), - ReparseTag: d.EaSize, - idxhi: uint32(d.FileID >> 32), - idxlo: uint32(d.FileID), - } -} - -// newFileStatFromFileFullDirInfo copies all required information -// from windows.FILE_FULL_DIR_INFO d into the newly created fileStat. -func newFileStatFromFileFullDirInfo(d *windows.FILE_FULL_DIR_INFO) *fileStat { - return &fileStat{ - FileAttributes: d.FileAttributes, - CreationTime: d.CreationTime, - LastAccessTime: d.LastAccessTime, - LastWriteTime: d.LastWriteTime, - FileSizeHigh: uint32(d.EndOfFile >> 32), - FileSizeLow: uint32(d.EndOfFile), - ReparseTag: d.EaSize, - } -} - -// newFileStatFromWin32finddata copies all required information -// from syscall.Win32finddata d into the newly created fileStat. -func newFileStatFromWin32finddata(d *syscall.Win32finddata) *fileStat { - fs := &fileStat{ - FileAttributes: d.FileAttributes, - CreationTime: d.CreationTime, - LastAccessTime: d.LastAccessTime, - LastWriteTime: d.LastWriteTime, - FileSizeHigh: d.FileSizeHigh, - FileSizeLow: d.FileSizeLow, - } - if d.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { - // Per https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataw: - // “If the dwFileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT - // attribute, this member specifies the reparse point tag. Otherwise, this - // value is undefined and should not be used.” - fs.ReparseTag = d.Reserved0 - } - return fs -} - -// isReparseTagNameSurrogate determines whether a tag's associated -// reparse point is a surrogate for another named entity (for example, a mounted folder). -// -// See https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-isreparsetagnamesurrogate -// and https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-point-tags. -func (fs *fileStat) isReparseTagNameSurrogate() bool { - // True for IO_REPARSE_TAG_SYMLINK and IO_REPARSE_TAG_MOUNT_POINT. - return fs.ReparseTag&0x20000000 != 0 -} - -func (fs *fileStat) isSymlink() bool { - // As of https://go.dev/cl/86556, we treat MOUNT_POINT reparse points as - // symlinks because otherwise certain directory junction tests in the - // path/filepath package would fail. - // - // However, - // https://learn.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions - // seems to suggest that directory junctions should be treated like hard - // links, not symlinks. - // - // TODO(bcmills): Get more input from Microsoft on what the behavior ought to - // be for MOUNT_POINT reparse points. - - return fs.ReparseTag == syscall.IO_REPARSE_TAG_SYMLINK || - fs.ReparseTag == windows.IO_REPARSE_TAG_MOUNT_POINT -} - -func (fs *fileStat) Size() int64 { - return int64(fs.FileSizeHigh)<<32 + int64(fs.FileSizeLow) -} - -func (fs *fileStat) Mode() (m FileMode) { - if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 { - m |= 0444 - } else { - m |= 0666 - } - if fs.isSymlink() { - return m | ModeSymlink - } - if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { - m |= ModeDir | 0111 - } - switch fs.filetype { - case syscall.FILE_TYPE_PIPE: - m |= ModeNamedPipe - case syscall.FILE_TYPE_CHAR: - m |= ModeDevice | ModeCharDevice - } - if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 && m&ModeType == 0 { - if fs.ReparseTag == windows.IO_REPARSE_TAG_DEDUP { - // If the Data Deduplication service is enabled on Windows Server, its - // Optimization job may convert regular files to IO_REPARSE_TAG_DEDUP - // whenever that job runs. - // - // However, DEDUP reparse points remain similar in most respects to - // regular files: they continue to support random-access reads and writes - // of persistent data, and they shouldn't add unexpected latency or - // unavailability in the way that a network filesystem might. - // - // Go programs may use ModeIrregular to filter out unusual files (such as - // raw device files on Linux, POSIX FIFO special files, and so on), so - // to avoid files changing unpredictably from regular to irregular we will - // consider DEDUP files to be close enough to regular to treat as such. - } else { - m |= ModeIrregular - } - } - return m -} - -func (fs *fileStat) ModTime() time.Time { - return time.Unix(0, fs.LastWriteTime.Nanoseconds()) -} - -// Sys returns syscall.Win32FileAttributeData for file fs. -func (fs *fileStat) Sys() any { - return &syscall.Win32FileAttributeData{ - FileAttributes: fs.FileAttributes, - CreationTime: fs.CreationTime, - LastAccessTime: fs.LastAccessTime, - LastWriteTime: fs.LastWriteTime, - FileSizeHigh: fs.FileSizeHigh, - FileSizeLow: fs.FileSizeLow, - } -} - -func (fs *fileStat) loadFileId() error { - fs.Lock() - defer fs.Unlock() - if fs.path == "" { - // already done - return nil - } - var path string - if fs.appendNameToPath { - path = fixLongPath(fs.path + `\` + fs.name) - } else { - path = fs.path - } - pathp, err := syscall.UTF16PtrFromString(path) - if err != nil { - return err - } - - // Per https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-points-and-file-operations, - // “Applications that use the CreateFile function should specify the - // FILE_FLAG_OPEN_REPARSE_POINT flag when opening the file if it is a reparse - // point.” - // - // And per https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew, - // “If the file is not a reparse point, then this flag is ignored.” - // - // So we set FILE_FLAG_OPEN_REPARSE_POINT unconditionally, since we want - // information about the reparse point itself. - // - // If the file is a symlink, the symlink target should have already been - // resolved when the fileStat was created, so we don't need to worry about - // resolving symlink reparse points again here. - attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS | syscall.FILE_FLAG_OPEN_REPARSE_POINT) - - h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0) - if err != nil { - return err - } - defer syscall.CloseHandle(h) - var i syscall.ByHandleFileInformation - err = syscall.GetFileInformationByHandle(h, &i) - if err != nil { - return err - } - fs.path = "" - fs.vol = i.VolumeSerialNumber - fs.idxhi = i.FileIndexHigh - fs.idxlo = i.FileIndexLow - return nil -} - -// saveInfoFromPath saves full path of the file to be used by os.SameFile later, -// and set name from path. -func (fs *fileStat) saveInfoFromPath(path string) error { - fs.path = path - if !isAbs(fs.path) { - var err error - fs.path, err = syscall.FullPath(fs.path) - if err != nil { - return &PathError{Op: "FullPath", Path: path, Err: err} - } - } - fs.name = basename(path) - return nil -} - -func sameFile(fs1, fs2 *fileStat) bool { - e := fs1.loadFileId() - if e != nil { - return false - } - e = fs2.loadFileId() - if e != nil { - return false - } - return fs1.vol == fs2.vol && fs1.idxhi == fs2.idxhi && fs1.idxlo == fs2.idxlo -} - -// For testing. -func atime(fi FileInfo) time.Time { - return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) -} diff --git a/contrib/go/_std_1.22/src/os/user/lookup.go b/contrib/go/_std_1.22/src/os/user/lookup.go deleted file mode 100644 index ed33d0c7cd17..000000000000 --- a/contrib/go/_std_1.22/src/os/user/lookup.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package user - -import "sync" - -const ( - userFile = "/etc/passwd" - groupFile = "/etc/group" -) - -var colon = []byte{':'} - -// Current returns the current user. -// -// The first call will cache the current user information. -// Subsequent calls will return the cached value and will not reflect -// changes to the current user. -func Current() (*User, error) { - cache.Do(func() { cache.u, cache.err = current() }) - if cache.err != nil { - return nil, cache.err - } - u := *cache.u // copy - return &u, nil -} - -// cache of the current user -var cache struct { - sync.Once - u *User - err error -} - -// Lookup looks up a user by username. If the user cannot be found, the -// returned error is of type UnknownUserError. -func Lookup(username string) (*User, error) { - if u, err := Current(); err == nil && u.Username == username { - return u, err - } - return lookupUser(username) -} - -// LookupId looks up a user by userid. If the user cannot be found, the -// returned error is of type UnknownUserIdError. -func LookupId(uid string) (*User, error) { - if u, err := Current(); err == nil && u.Uid == uid { - return u, err - } - return lookupUserId(uid) -} - -// LookupGroup looks up a group by name. If the group cannot be found, the -// returned error is of type UnknownGroupError. -func LookupGroup(name string) (*Group, error) { - return lookupGroup(name) -} - -// LookupGroupId looks up a group by groupid. If the group cannot be found, the -// returned error is of type UnknownGroupIdError. -func LookupGroupId(gid string) (*Group, error) { - return lookupGroupId(gid) -} - -// GroupIds returns the list of group IDs that the user is a member of. -func (u *User) GroupIds() ([]string, error) { - return listGroups(u) -} diff --git a/contrib/go/_std_1.22/src/os/user/ya.make b/contrib/go/_std_1.22/src/os/user/ya.make deleted file mode 100644 index 9e0e9f8f2ae4..000000000000 --- a/contrib/go/_std_1.22/src/os/user/ya.make +++ /dev/null @@ -1,42 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - cgo_listgroups_unix.go - cgo_lookup_syscall.go - cgo_lookup_unix.go - getgrouplist_syscall.go - lookup.go - user.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED) - SRCS( - cgo_listgroups_unix.go - cgo_lookup_unix.go - lookup.go - user.go - ) - -IF (CGO_ENABLED) - CGO_SRCS( - cgo_lookup_cgo.go - getgrouplist_unix.go - ) -ENDIF() -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - listgroups_unix.go - lookup.go - lookup_stubs.go - lookup_unix.go - user.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - lookup.go - lookup_windows.go - user.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/os/ya.make b/contrib/go/_std_1.22/src/os/ya.make deleted file mode 100644 index 8911bf552df5..000000000000 --- a/contrib/go/_std_1.22/src/os/ya.make +++ /dev/null @@ -1,113 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - dir.go - dir_darwin.go - endian_little.go - env.go - error.go - error_errno.go - error_posix.go - exec.go - exec_posix.go - exec_unix.go - executable.go - executable_darwin.go - file.go - file_open_unix.go - file_posix.go - file_unix.go - getwd.go - path.go - path_unix.go - pipe_unix.go - proc.go - rawconn.go - removeall_at.go - stat.go - stat_darwin.go - stat_unix.go - sticky_bsd.go - sys.go - sys_bsd.go - sys_unix.go - tempfile.go - types.go - types_unix.go - wait_unimp.go - zero_copy_stub.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - dir.go - dir_unix.go - dirent_linux.go - endian_little.go - env.go - error.go - error_errno.go - error_posix.go - exec.go - exec_posix.go - exec_unix.go - executable.go - executable_procfs.go - file.go - file_open_unix.go - file_posix.go - file_unix.go - getwd.go - path.go - path_unix.go - pipe2_unix.go - proc.go - rawconn.go - removeall_at.go - stat.go - stat_linux.go - stat_unix.go - sticky_notbsd.go - sys.go - sys_linux.go - sys_unix.go - tempfile.go - types.go - types_unix.go - wait_waitid.go - zero_copy_linux.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - dir.go - dir_windows.go - endian_little.go - env.go - error.go - error_errno.go - error_posix.go - exec.go - exec_posix.go - exec_windows.go - executable.go - executable_windows.go - file.go - file_posix.go - file_windows.go - getwd.go - path.go - path_windows.go - proc.go - rawconn.go - removeall_noat.go - stat.go - stat_windows.go - sticky_notbsd.go - sys.go - sys_windows.go - tempfile.go - types.go - types_windows.go - zero_copy_stub.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/path/filepath/path.go b/contrib/go/_std_1.22/src/path/filepath/path.go deleted file mode 100644 index 2af0f5b04cfc..000000000000 --- a/contrib/go/_std_1.22/src/path/filepath/path.go +++ /dev/null @@ -1,639 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package filepath implements utility routines for manipulating filename paths -// in a way compatible with the target operating system-defined file paths. -// -// The filepath package uses either forward slashes or backslashes, -// depending on the operating system. To process paths such as URLs -// that always use forward slashes regardless of the operating -// system, see the [path] package. -package filepath - -import ( - "errors" - "io/fs" - "os" - "slices" - "sort" - "strings" -) - -// A lazybuf is a lazily constructed path buffer. -// It supports append, reading previously appended bytes, -// and retrieving the final string. It does not allocate a buffer -// to hold the output until that output diverges from s. -type lazybuf struct { - path string - buf []byte - w int - volAndPath string - volLen int -} - -func (b *lazybuf) index(i int) byte { - if b.buf != nil { - return b.buf[i] - } - return b.path[i] -} - -func (b *lazybuf) append(c byte) { - if b.buf == nil { - if b.w < len(b.path) && b.path[b.w] == c { - b.w++ - return - } - b.buf = make([]byte, len(b.path)) - copy(b.buf, b.path[:b.w]) - } - b.buf[b.w] = c - b.w++ -} - -func (b *lazybuf) prepend(prefix ...byte) { - b.buf = slices.Insert(b.buf, 0, prefix...) - b.w += len(prefix) -} - -func (b *lazybuf) string() string { - if b.buf == nil { - return b.volAndPath[:b.volLen+b.w] - } - return b.volAndPath[:b.volLen] + string(b.buf[:b.w]) -} - -const ( - Separator = os.PathSeparator - ListSeparator = os.PathListSeparator -) - -// Clean returns the shortest path name equivalent to path -// by purely lexical processing. It applies the following rules -// iteratively until no further processing can be done: -// -// 1. Replace multiple [Separator] elements with a single one. -// 2. Eliminate each . path name element (the current directory). -// 3. Eliminate each inner .. path name element (the parent directory) -// along with the non-.. element that precedes it. -// 4. Eliminate .. elements that begin a rooted path: -// that is, replace "/.." by "/" at the beginning of a path, -// assuming Separator is '/'. -// -// The returned path ends in a slash only if it represents a root directory, -// such as "/" on Unix or `C:\` on Windows. -// -// Finally, any occurrences of slash are replaced by Separator. -// -// If the result of this process is an empty string, Clean -// returns the string ".". -// -// On Windows, Clean does not modify the volume name other than to replace -// occurrences of "/" with `\`. -// For example, Clean("//host/share/../x") returns `\\host\share\x`. -// -// See also Rob Pike, “Lexical File Names in Plan 9 or -// Getting Dot-Dot Right,” -// https://9p.io/sys/doc/lexnames.html -func Clean(path string) string { - originalPath := path - volLen := volumeNameLen(path) - path = path[volLen:] - if path == "" { - if volLen > 1 && os.IsPathSeparator(originalPath[0]) && os.IsPathSeparator(originalPath[1]) { - // should be UNC - return FromSlash(originalPath) - } - return originalPath + "." - } - rooted := os.IsPathSeparator(path[0]) - - // Invariants: - // reading from path; r is index of next byte to process. - // writing to buf; w is index of next byte to write. - // dotdot is index in buf where .. must stop, either because - // it is the leading slash or it is a leading ../../.. prefix. - n := len(path) - out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen} - r, dotdot := 0, 0 - if rooted { - out.append(Separator) - r, dotdot = 1, 1 - } - - for r < n { - switch { - case os.IsPathSeparator(path[r]): - // empty path element - r++ - case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): - // . element - r++ - case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): - // .. element: remove to last separator - r += 2 - switch { - case out.w > dotdot: - // can backtrack - out.w-- - for out.w > dotdot && !os.IsPathSeparator(out.index(out.w)) { - out.w-- - } - case !rooted: - // cannot backtrack, but not rooted, so append .. element. - if out.w > 0 { - out.append(Separator) - } - out.append('.') - out.append('.') - dotdot = out.w - } - default: - // real path element. - // add slash if needed - if rooted && out.w != 1 || !rooted && out.w != 0 { - out.append(Separator) - } - // copy element - for ; r < n && !os.IsPathSeparator(path[r]); r++ { - out.append(path[r]) - } - } - } - - // Turn empty string into "." - if out.w == 0 { - out.append('.') - } - - postClean(&out) // avoid creating absolute paths on Windows - return FromSlash(out.string()) -} - -// IsLocal reports whether path, using lexical analysis only, has all of these properties: -// -// - is within the subtree rooted at the directory in which path is evaluated -// - is not an absolute path -// - is not empty -// - on Windows, is not a reserved name such as "NUL" -// -// If IsLocal(path) returns true, then -// Join(base, path) will always produce a path contained within base and -// Clean(path) will always produce an unrooted path with no ".." path elements. -// -// IsLocal is a purely lexical operation. -// In particular, it does not account for the effect of any symbolic links -// that may exist in the filesystem. -func IsLocal(path string) bool { - return isLocal(path) -} - -func unixIsLocal(path string) bool { - if IsAbs(path) || path == "" { - return false - } - hasDots := false - for p := path; p != ""; { - var part string - part, p, _ = strings.Cut(p, "/") - if part == "." || part == ".." { - hasDots = true - break - } - } - if hasDots { - path = Clean(path) - } - if path == ".." || strings.HasPrefix(path, "../") { - return false - } - return true -} - -// ToSlash returns the result of replacing each separator character -// in path with a slash ('/') character. Multiple separators are -// replaced by multiple slashes. -func ToSlash(path string) string { - if Separator == '/' { - return path - } - return strings.ReplaceAll(path, string(Separator), "/") -} - -// FromSlash returns the result of replacing each slash ('/') character -// in path with a separator character. Multiple slashes are replaced -// by multiple separators. -func FromSlash(path string) string { - if Separator == '/' { - return path - } - return strings.ReplaceAll(path, "/", string(Separator)) -} - -// SplitList splits a list of paths joined by the OS-specific [ListSeparator], -// usually found in PATH or GOPATH environment variables. -// Unlike strings.Split, SplitList returns an empty slice when passed an empty -// string. -func SplitList(path string) []string { - return splitList(path) -} - -// Split splits path immediately following the final [Separator], -// separating it into a directory and file name component. -// If there is no Separator in path, Split returns an empty dir -// and file set to path. -// The returned values have the property that path = dir+file. -func Split(path string) (dir, file string) { - vol := VolumeName(path) - i := len(path) - 1 - for i >= len(vol) && !os.IsPathSeparator(path[i]) { - i-- - } - return path[:i+1], path[i+1:] -} - -// Join joins any number of path elements into a single path, -// separating them with an OS specific [Separator]. Empty elements -// are ignored. The result is Cleaned. However, if the argument -// list is empty or all its elements are empty, Join returns -// an empty string. -// On Windows, the result will only be a UNC path if the first -// non-empty element is a UNC path. -func Join(elem ...string) string { - return join(elem) -} - -// Ext returns the file name extension used by path. -// The extension is the suffix beginning at the final dot -// in the final element of path; it is empty if there is -// no dot. -func Ext(path string) string { - for i := len(path) - 1; i >= 0 && !os.IsPathSeparator(path[i]); i-- { - if path[i] == '.' { - return path[i:] - } - } - return "" -} - -// EvalSymlinks returns the path name after the evaluation of any symbolic -// links. -// If path is relative the result will be relative to the current directory, -// unless one of the components is an absolute symbolic link. -// EvalSymlinks calls [Clean] on the result. -func EvalSymlinks(path string) (string, error) { - return evalSymlinks(path) -} - -// Abs returns an absolute representation of path. -// If the path is not absolute it will be joined with the current -// working directory to turn it into an absolute path. The absolute -// path name for a given file is not guaranteed to be unique. -// Abs calls [Clean] on the result. -func Abs(path string) (string, error) { - return abs(path) -} - -func unixAbs(path string) (string, error) { - if IsAbs(path) { - return Clean(path), nil - } - wd, err := os.Getwd() - if err != nil { - return "", err - } - return Join(wd, path), nil -} - -// Rel returns a relative path that is lexically equivalent to targpath when -// joined to basepath with an intervening separator. That is, -// [Join](basepath, Rel(basepath, targpath)) is equivalent to targpath itself. -// On success, the returned path will always be relative to basepath, -// even if basepath and targpath share no elements. -// An error is returned if targpath can't be made relative to basepath or if -// knowing the current working directory would be necessary to compute it. -// Rel calls [Clean] on the result. -func Rel(basepath, targpath string) (string, error) { - baseVol := VolumeName(basepath) - targVol := VolumeName(targpath) - base := Clean(basepath) - targ := Clean(targpath) - if sameWord(targ, base) { - return ".", nil - } - base = base[len(baseVol):] - targ = targ[len(targVol):] - if base == "." { - base = "" - } else if base == "" && volumeNameLen(baseVol) > 2 /* isUNC */ { - // Treat any targetpath matching `\\host\share` basepath as absolute path. - base = string(Separator) - } - - // Can't use IsAbs - `\a` and `a` are both relative in Windows. - baseSlashed := len(base) > 0 && base[0] == Separator - targSlashed := len(targ) > 0 && targ[0] == Separator - if baseSlashed != targSlashed || !sameWord(baseVol, targVol) { - return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) - } - // Position base[b0:bi] and targ[t0:ti] at the first differing elements. - bl := len(base) - tl := len(targ) - var b0, bi, t0, ti int - for { - for bi < bl && base[bi] != Separator { - bi++ - } - for ti < tl && targ[ti] != Separator { - ti++ - } - if !sameWord(targ[t0:ti], base[b0:bi]) { - break - } - if bi < bl { - bi++ - } - if ti < tl { - ti++ - } - b0 = bi - t0 = ti - } - if base[b0:bi] == ".." { - return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) - } - if b0 != bl { - // Base elements left. Must go up before going down. - seps := strings.Count(base[b0:bl], string(Separator)) - size := 2 + seps*3 - if tl != t0 { - size += 1 + tl - t0 - } - buf := make([]byte, size) - n := copy(buf, "..") - for i := 0; i < seps; i++ { - buf[n] = Separator - copy(buf[n+1:], "..") - n += 3 - } - if t0 != tl { - buf[n] = Separator - copy(buf[n+1:], targ[t0:]) - } - return string(buf), nil - } - return targ[t0:], nil -} - -// SkipDir is used as a return value from [WalkFunc] to indicate that -// the directory named in the call is to be skipped. It is not returned -// as an error by any function. -var SkipDir error = fs.SkipDir - -// SkipAll is used as a return value from [WalkFunc] to indicate that -// all remaining files and directories are to be skipped. It is not returned -// as an error by any function. -var SkipAll error = fs.SkipAll - -// WalkFunc is the type of the function called by [Walk] to visit each -// file or directory. -// -// The path argument contains the argument to Walk as a prefix. -// That is, if Walk is called with root argument "dir" and finds a file -// named "a" in that directory, the walk function will be called with -// argument "dir/a". -// -// The directory and file are joined with Join, which may clean the -// directory name: if Walk is called with the root argument "x/../dir" -// and finds a file named "a" in that directory, the walk function will -// be called with argument "dir/a", not "x/../dir/a". -// -// The info argument is the fs.FileInfo for the named path. -// -// The error result returned by the function controls how Walk continues. -// If the function returns the special value [SkipDir], Walk skips the -// current directory (path if info.IsDir() is true, otherwise path's -// parent directory). If the function returns the special value [SkipAll], -// Walk skips all remaining files and directories. Otherwise, if the function -// returns a non-nil error, Walk stops entirely and returns that error. -// -// The err argument reports an error related to path, signaling that Walk -// will not walk into that directory. The function can decide how to -// handle that error; as described earlier, returning the error will -// cause Walk to stop walking the entire tree. -// -// Walk calls the function with a non-nil err argument in two cases. -// -// First, if an [os.Lstat] on the root directory or any directory or file -// in the tree fails, Walk calls the function with path set to that -// directory or file's path, info set to nil, and err set to the error -// from os.Lstat. -// -// Second, if a directory's Readdirnames method fails, Walk calls the -// function with path set to the directory's path, info, set to an -// [fs.FileInfo] describing the directory, and err set to the error from -// Readdirnames. -type WalkFunc func(path string, info fs.FileInfo, err error) error - -var lstat = os.Lstat // for testing - -// walkDir recursively descends path, calling walkDirFn. -func walkDir(path string, d fs.DirEntry, walkDirFn fs.WalkDirFunc) error { - if err := walkDirFn(path, d, nil); err != nil || !d.IsDir() { - if err == SkipDir && d.IsDir() { - // Successfully skipped directory. - err = nil - } - return err - } - - dirs, err := os.ReadDir(path) - if err != nil { - // Second call, to report ReadDir error. - err = walkDirFn(path, d, err) - if err != nil { - if err == SkipDir && d.IsDir() { - err = nil - } - return err - } - } - - for _, d1 := range dirs { - path1 := Join(path, d1.Name()) - if err := walkDir(path1, d1, walkDirFn); err != nil { - if err == SkipDir { - break - } - return err - } - } - return nil -} - -// walk recursively descends path, calling walkFn. -func walk(path string, info fs.FileInfo, walkFn WalkFunc) error { - if !info.IsDir() { - return walkFn(path, info, nil) - } - - names, err := readDirNames(path) - err1 := walkFn(path, info, err) - // If err != nil, walk can't walk into this directory. - // err1 != nil means walkFn want walk to skip this directory or stop walking. - // Therefore, if one of err and err1 isn't nil, walk will return. - if err != nil || err1 != nil { - // The caller's behavior is controlled by the return value, which is decided - // by walkFn. walkFn may ignore err and return nil. - // If walkFn returns SkipDir or SkipAll, it will be handled by the caller. - // So walk should return whatever walkFn returns. - return err1 - } - - for _, name := range names { - filename := Join(path, name) - fileInfo, err := lstat(filename) - if err != nil { - if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir { - return err - } - } else { - err = walk(filename, fileInfo, walkFn) - if err != nil { - if !fileInfo.IsDir() || err != SkipDir { - return err - } - } - } - } - return nil -} - -// WalkDir walks the file tree rooted at root, calling fn for each file or -// directory in the tree, including root. -// -// All errors that arise visiting files and directories are filtered by fn: -// see the [fs.WalkDirFunc] documentation for details. -// -// The files are walked in lexical order, which makes the output deterministic -// but requires WalkDir to read an entire directory into memory before proceeding -// to walk that directory. -// -// WalkDir does not follow symbolic links. -// -// WalkDir calls fn with paths that use the separator character appropriate -// for the operating system. This is unlike [io/fs.WalkDir], which always -// uses slash separated paths. -func WalkDir(root string, fn fs.WalkDirFunc) error { - info, err := os.Lstat(root) - if err != nil { - err = fn(root, nil, err) - } else { - err = walkDir(root, fs.FileInfoToDirEntry(info), fn) - } - if err == SkipDir || err == SkipAll { - return nil - } - return err -} - -// Walk walks the file tree rooted at root, calling fn for each file or -// directory in the tree, including root. -// -// All errors that arise visiting files and directories are filtered by fn: -// see the [WalkFunc] documentation for details. -// -// The files are walked in lexical order, which makes the output deterministic -// but requires Walk to read an entire directory into memory before proceeding -// to walk that directory. -// -// Walk does not follow symbolic links. -// -// Walk is less efficient than [WalkDir], introduced in Go 1.16, -// which avoids calling os.Lstat on every visited file or directory. -func Walk(root string, fn WalkFunc) error { - info, err := os.Lstat(root) - if err != nil { - err = fn(root, nil, err) - } else { - err = walk(root, info, fn) - } - if err == SkipDir || err == SkipAll { - return nil - } - return err -} - -// readDirNames reads the directory named by dirname and returns -// a sorted list of directory entry names. -func readDirNames(dirname string) ([]string, error) { - f, err := os.Open(dirname) - if err != nil { - return nil, err - } - names, err := f.Readdirnames(-1) - f.Close() - if err != nil { - return nil, err - } - sort.Strings(names) - return names, nil -} - -// Base returns the last element of path. -// Trailing path separators are removed before extracting the last element. -// If the path is empty, Base returns ".". -// If the path consists entirely of separators, Base returns a single separator. -func Base(path string) string { - if path == "" { - return "." - } - // Strip trailing slashes. - for len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) { - path = path[0 : len(path)-1] - } - // Throw away volume name - path = path[len(VolumeName(path)):] - // Find the last element - i := len(path) - 1 - for i >= 0 && !os.IsPathSeparator(path[i]) { - i-- - } - if i >= 0 { - path = path[i+1:] - } - // If empty now, it had only slashes. - if path == "" { - return string(Separator) - } - return path -} - -// Dir returns all but the last element of path, typically the path's directory. -// After dropping the final element, Dir calls [Clean] on the path and trailing -// slashes are removed. -// If the path is empty, Dir returns ".". -// If the path consists entirely of separators, Dir returns a single separator. -// The returned path does not end in a separator unless it is the root directory. -func Dir(path string) string { - vol := VolumeName(path) - i := len(path) - 1 - for i >= len(vol) && !os.IsPathSeparator(path[i]) { - i-- - } - dir := Clean(path[len(vol) : i+1]) - if dir == "." && len(vol) > 2 { - // must be UNC - return vol - } - return vol + dir -} - -// VolumeName returns leading volume name. -// Given "C:\foo\bar" it returns "C:" on Windows. -// Given "\\host\share\foo" it returns "\\host\share". -// On other platforms it returns "". -func VolumeName(path string) string { - return FromSlash(path[:volumeNameLen(path)]) -} diff --git a/contrib/go/_std_1.22/src/path/filepath/path_plan9.go b/contrib/go/_std_1.22/src/path/filepath/path_plan9.go deleted file mode 100644 index 453206aee3e0..000000000000 --- a/contrib/go/_std_1.22/src/path/filepath/path_plan9.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath - -import "strings" - -func isLocal(path string) bool { - return unixIsLocal(path) -} - -// IsAbs reports whether the path is absolute. -func IsAbs(path string) bool { - return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") -} - -// volumeNameLen returns length of the leading volume name on Windows. -// It returns 0 elsewhere. -func volumeNameLen(path string) int { - return 0 -} - -// HasPrefix exists for historical compatibility and should not be used. -// -// Deprecated: HasPrefix does not respect path boundaries and -// does not ignore case when required. -func HasPrefix(p, prefix string) bool { - return strings.HasPrefix(p, prefix) -} - -func splitList(path string) []string { - if path == "" { - return []string{} - } - return strings.Split(path, string(ListSeparator)) -} - -func abs(path string) (string, error) { - return unixAbs(path) -} - -func join(elem []string) string { - // If there's a bug here, fix the logic in ./path_unix.go too. - for i, e := range elem { - if e != "" { - return Clean(strings.Join(elem[i:], string(Separator))) - } - } - return "" -} - -func sameWord(a, b string) bool { - return a == b -} diff --git a/contrib/go/_std_1.22/src/path/filepath/path_unix.go b/contrib/go/_std_1.22/src/path/filepath/path_unix.go deleted file mode 100644 index 57e621743434..000000000000 --- a/contrib/go/_std_1.22/src/path/filepath/path_unix.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix || (js && wasm) || wasip1 - -package filepath - -import "strings" - -func isLocal(path string) bool { - return unixIsLocal(path) -} - -// IsAbs reports whether the path is absolute. -func IsAbs(path string) bool { - return strings.HasPrefix(path, "/") -} - -// volumeNameLen returns length of the leading volume name on Windows. -// It returns 0 elsewhere. -func volumeNameLen(path string) int { - return 0 -} - -// HasPrefix exists for historical compatibility and should not be used. -// -// Deprecated: HasPrefix does not respect path boundaries and -// does not ignore case when required. -func HasPrefix(p, prefix string) bool { - return strings.HasPrefix(p, prefix) -} - -func splitList(path string) []string { - if path == "" { - return []string{} - } - return strings.Split(path, string(ListSeparator)) -} - -func abs(path string) (string, error) { - return unixAbs(path) -} - -func join(elem []string) string { - // If there's a bug here, fix the logic in ./path_plan9.go too. - for i, e := range elem { - if e != "" { - return Clean(strings.Join(elem[i:], string(Separator))) - } - } - return "" -} - -func sameWord(a, b string) bool { - return a == b -} diff --git a/contrib/go/_std_1.22/src/path/filepath/path_windows.go b/contrib/go/_std_1.22/src/path/filepath/path_windows.go deleted file mode 100644 index eacab0e5ced6..000000000000 --- a/contrib/go/_std_1.22/src/path/filepath/path_windows.go +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath - -import ( - "internal/safefilepath" - "os" - "strings" - "syscall" -) - -func isSlash(c uint8) bool { - return c == '\\' || c == '/' -} - -func toUpper(c byte) byte { - if 'a' <= c && c <= 'z' { - return c - ('a' - 'A') - } - return c -} - -func isLocal(path string) bool { - if path == "" { - return false - } - if isSlash(path[0]) { - // Path rooted in the current drive. - return false - } - if strings.IndexByte(path, ':') >= 0 { - // Colons are only valid when marking a drive letter ("C:foo"). - // Rejecting any path with a colon is conservative but safe. - return false - } - hasDots := false // contains . or .. path elements - for p := path; p != ""; { - var part string - part, p, _ = cutPath(p) - if part == "." || part == ".." { - hasDots = true - } - if safefilepath.IsReservedName(part) { - return false - } - } - if hasDots { - path = Clean(path) - } - if path == ".." || strings.HasPrefix(path, `..\`) { - return false - } - return true -} - -// IsAbs reports whether the path is absolute. -func IsAbs(path string) (b bool) { - l := volumeNameLen(path) - if l == 0 { - return false - } - // If the volume name starts with a double slash, this is an absolute path. - if isSlash(path[0]) && isSlash(path[1]) { - return true - } - path = path[l:] - if path == "" { - return false - } - return isSlash(path[0]) -} - -// volumeNameLen returns length of the leading volume name on Windows. -// It returns 0 elsewhere. -// -// See: -// https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats -// https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html -func volumeNameLen(path string) int { - switch { - case len(path) >= 2 && path[1] == ':': - // Path starts with a drive letter. - // - // Not all Windows functions necessarily enforce the requirement that - // drive letters be in the set A-Z, and we don't try to here. - // - // We don't handle the case of a path starting with a non-ASCII character, - // in which case the "drive letter" might be multiple bytes long. - return 2 - - case len(path) == 0 || !isSlash(path[0]): - // Path does not have a volume component. - return 0 - - case pathHasPrefixFold(path, `\\.\UNC`): - // We're going to treat the UNC host and share as part of the volume - // prefix for historical reasons, but this isn't really principled; - // Windows's own GetFullPathName will happily remove the first - // component of the path in this space, converting - // \\.\unc\a\b\..\c into \\.\unc\a\c. - return uncLen(path, len(`\\.\UNC\`)) - - case pathHasPrefixFold(path, `\\.`) || - pathHasPrefixFold(path, `\\?`) || pathHasPrefixFold(path, `\??`): - // Path starts with \\.\, and is a Local Device path; or - // path starts with \\?\ or \??\ and is a Root Local Device path. - // - // We treat the next component after the \\.\ prefix as - // part of the volume name, which means Clean(`\\?\c:\`) - // won't remove the trailing \. (See #64028.) - if len(path) == 3 { - return 3 // exactly \\. - } - _, rest, ok := cutPath(path[4:]) - if !ok { - return len(path) - } - return len(path) - len(rest) - 1 - - case len(path) >= 2 && isSlash(path[1]): - // Path starts with \\, and is a UNC path. - return uncLen(path, 2) - } - return 0 -} - -// pathHasPrefixFold tests whether the path s begins with prefix, -// ignoring case and treating all path separators as equivalent. -// If s is longer than prefix, then s[len(prefix)] must be a path separator. -func pathHasPrefixFold(s, prefix string) bool { - if len(s) < len(prefix) { - return false - } - for i := 0; i < len(prefix); i++ { - if isSlash(prefix[i]) { - if !isSlash(s[i]) { - return false - } - } else if toUpper(prefix[i]) != toUpper(s[i]) { - return false - } - } - if len(s) > len(prefix) && !isSlash(s[len(prefix)]) { - return false - } - return true -} - -// uncLen returns the length of the volume prefix of a UNC path. -// prefixLen is the prefix prior to the start of the UNC host; -// for example, for "//host/share", the prefixLen is len("//")==2. -func uncLen(path string, prefixLen int) int { - count := 0 - for i := prefixLen; i < len(path); i++ { - if isSlash(path[i]) { - count++ - if count == 2 { - return i - } - } - } - return len(path) -} - -// cutPath slices path around the first path separator. -func cutPath(path string) (before, after string, found bool) { - for i := range path { - if isSlash(path[i]) { - return path[:i], path[i+1:], true - } - } - return path, "", false -} - -// HasPrefix exists for historical compatibility and should not be used. -// -// Deprecated: HasPrefix does not respect path boundaries and -// does not ignore case when required. -func HasPrefix(p, prefix string) bool { - if strings.HasPrefix(p, prefix) { - return true - } - return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix)) -} - -func splitList(path string) []string { - // The same implementation is used in LookPath in os/exec; - // consider changing os/exec when changing this. - - if path == "" { - return []string{} - } - - // Split path, respecting but preserving quotes. - list := []string{} - start := 0 - quo := false - for i := 0; i < len(path); i++ { - switch c := path[i]; { - case c == '"': - quo = !quo - case c == ListSeparator && !quo: - list = append(list, path[start:i]) - start = i + 1 - } - } - list = append(list, path[start:]) - - // Remove quotes. - for i, s := range list { - list[i] = strings.ReplaceAll(s, `"`, ``) - } - - return list -} - -func abs(path string) (string, error) { - if path == "" { - // syscall.FullPath returns an error on empty path, because it's not a valid path. - // To implement Abs behavior of returning working directory on empty string input, - // special-case empty path by changing it to "." path. See golang.org/issue/24441. - path = "." - } - fullPath, err := syscall.FullPath(path) - if err != nil { - return "", err - } - return Clean(fullPath), nil -} - -func join(elem []string) string { - var b strings.Builder - var lastChar byte - for _, e := range elem { - switch { - case b.Len() == 0: - // Add the first non-empty path element unchanged. - case isSlash(lastChar): - // If the path ends in a slash, strip any leading slashes from the next - // path element to avoid creating a UNC path (any path starting with "\\") - // from non-UNC elements. - // - // The correct behavior for Join when the first element is an incomplete UNC - // path (for example, "\\") is underspecified. We currently join subsequent - // elements so Join("\\", "host", "share") produces "\\host\share". - for len(e) > 0 && isSlash(e[0]) { - e = e[1:] - } - // If the path is \ and the next path element is ??, - // add an extra .\ to create \.\?? rather than \??\ - // (a Root Local Device path). - if b.Len() == 1 && pathHasPrefixFold(e, "??") { - b.WriteString(`.\`) - } - case lastChar == ':': - // If the path ends in a colon, keep the path relative to the current directory - // on a drive and don't add a separator. Preserve leading slashes in the next - // path element, which may make the path absolute. - // - // Join(`C:`, `f`) = `C:f` - // Join(`C:`, `\f`) = `C:\f` - default: - // In all other cases, add a separator between elements. - b.WriteByte('\\') - lastChar = '\\' - } - if len(e) > 0 { - b.WriteString(e) - lastChar = e[len(e)-1] - } - } - if b.Len() == 0 { - return "" - } - return Clean(b.String()) -} - -// joinNonEmpty is like join, but it assumes that the first element is non-empty. -func joinNonEmpty(elem []string) string { - if len(elem[0]) == 2 && elem[0][1] == ':' { - // First element is drive letter without terminating slash. - // Keep path relative to current directory on that drive. - // Skip empty elements. - i := 1 - for ; i < len(elem); i++ { - if elem[i] != "" { - break - } - } - return Clean(elem[0] + strings.Join(elem[i:], string(Separator))) - } - // The following logic prevents Join from inadvertently creating a - // UNC path on Windows. Unless the first element is a UNC path, Join - // shouldn't create a UNC path. See golang.org/issue/9167. - p := Clean(strings.Join(elem, string(Separator))) - if !isUNC(p) { - return p - } - // p == UNC only allowed when the first element is a UNC path. - head := Clean(elem[0]) - if isUNC(head) { - return p - } - // head + tail == UNC, but joining two non-UNC paths should not result - // in a UNC path. Undo creation of UNC path. - tail := Clean(strings.Join(elem[1:], string(Separator))) - if head[len(head)-1] == Separator { - return head + tail - } - return head + string(Separator) + tail -} - -// isUNC reports whether path is a UNC path. -func isUNC(path string) bool { - return len(path) > 1 && isSlash(path[0]) && isSlash(path[1]) -} - -func sameWord(a, b string) bool { - return strings.EqualFold(a, b) -} - -// postClean adjusts the results of Clean to avoid turning a relative path -// into an absolute or rooted one. -func postClean(out *lazybuf) { - if out.volLen != 0 || out.buf == nil { - return - } - // If a ':' appears in the path element at the start of a path, - // insert a .\ at the beginning to avoid converting relative paths - // like a/../c: into c:. - for _, c := range out.buf { - if os.IsPathSeparator(c) { - break - } - if c == ':' { - out.prepend('.', Separator) - return - } - } - // If a path begins with \??\, insert a \. at the beginning - // to avoid converting paths like \a\..\??\c:\x into \??\c:\x - // (equivalent to c:\x). - if len(out.buf) >= 3 && os.IsPathSeparator(out.buf[0]) && out.buf[1] == '?' && out.buf[2] == '?' { - out.prepend(Separator, '.') - } -} diff --git a/contrib/go/_std_1.22/src/path/filepath/ya.make b/contrib/go/_std_1.22/src/path/filepath/ya.make deleted file mode 100644 index 40919fc1b05e..000000000000 --- a/contrib/go/_std_1.22/src/path/filepath/ya.make +++ /dev/null @@ -1,20 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - match.go - path.go - path_nonwindows.go - path_unix.go - symlink.go - symlink_unix.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - match.go - path.go - path_windows.go - symlink.go - symlink_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/reflect/arena.go b/contrib/go/_std_1.22/src/reflect/arena.go deleted file mode 100644 index cac1a1da5eaa..000000000000 --- a/contrib/go/_std_1.22/src/reflect/arena.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.arenas - -package reflect - -import "arena" - -// ArenaNew returns a Value representing a pointer to a new zero value for the -// specified type, allocating storage for it in the provided arena. That is, -// the returned Value's Type is PointerTo(typ). -func ArenaNew(a *arena.Arena, typ Type) Value { - return ValueOf(arena_New(a, PointerTo(typ))) -} - -func arena_New(a *arena.Arena, typ any) any diff --git a/contrib/go/_std_1.22/src/reflect/asm_loong64.s b/contrib/go/_std_1.22/src/reflect/asm_loong64.s deleted file mode 100644 index 520f0afdd516..000000000000 --- a/contrib/go/_std_1.22/src/reflect/asm_loong64.s +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "textflag.h" -#include "funcdata.h" - -#define REGCTXT R29 - -// The frames of each of the two functions below contain two locals, at offsets -// that are known to the runtime. -// -// The first local is a bool called retValid with a whole pointer-word reserved -// for it on the stack. The purpose of this word is so that the runtime knows -// whether the stack-allocated return space contains valid values for stack -// scanning. -// -// The second local is an abi.RegArgs value whose offset is also known to the -// runtime, so that a stack map for it can be constructed, since it contains -// pointers visible to the GC. -#define LOCAL_RETVALID 40 -#define LOCAL_REGARGS 48 - -// The frame size of the functions below is -// 32 (args of callReflect) + 8 (bool + padding) + 392 (abi.RegArgs) = 432. - -// makeFuncStub is the code half of the function returned by MakeFunc. -// See the comment on the declaration of makeFuncStub in makefunc.go -// for more details. -// No arg size here, runtime pulls arg map out of the func value. -TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$432 - NO_LOCAL_POINTERS - ADDV $LOCAL_REGARGS, R3, R25 // spillArgs using R25 - JAL runtime·spillArgs(SB) - MOVV REGCTXT, 32(R3) // save REGCTXT > args of moveMakeFuncArgPtrs < LOCAL_REGARGS - -#ifdef GOEXPERIMENT_regabiargs - MOVV REGCTXT, R4 - MOVV R25, R5 -#else - MOVV REGCTXT, 8(R3) - MOVV R25, 16(R3) -#endif - JAL ·moveMakeFuncArgPtrs(SB) - MOVV 32(R3), REGCTXT // restore REGCTXT - - MOVV REGCTXT, 8(R3) - MOVV $argframe+0(FP), R20 - MOVV R20, 16(R3) - MOVV R0, LOCAL_RETVALID(R3) - ADDV $LOCAL_RETVALID, R3, R20 - MOVV R20, 24(R3) - ADDV $LOCAL_REGARGS, R3, R20 - MOVV R20, 32(R3) - JAL ·callReflect(SB) - ADDV $LOCAL_REGARGS, R3, R25 //unspillArgs using R25 - JAL runtime·unspillArgs(SB) - RET - -// methodValueCall is the code half of the function returned by makeMethodValue. -// See the comment on the declaration of methodValueCall in makefunc.go -// for more details. -// No arg size here; runtime pulls arg map out of the func value. -TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$432 - NO_LOCAL_POINTERS - ADDV $LOCAL_REGARGS, R3, R25 // spillArgs using R25 - JAL runtime·spillArgs(SB) - MOVV REGCTXT, 32(R3) // save REGCTXT > args of moveMakeFuncArgPtrs < LOCAL_REGARGS -#ifdef GOEXPERIMENT_regabiargs - MOVV REGCTXT, R4 - MOVV R25, R5 -#else - MOVV REGCTXT, 8(R3) - MOVV R25, 16(R3) -#endif - JAL ·moveMakeFuncArgPtrs(SB) - MOVV 32(R3), REGCTXT // restore REGCTXT - MOVV REGCTXT, 8(R3) - MOVV $argframe+0(FP), R20 - MOVV R20, 16(R3) - MOVB R0, LOCAL_RETVALID(R3) - ADDV $LOCAL_RETVALID, R3, R20 - MOVV R20, 24(R3) - ADDV $LOCAL_REGARGS, R3, R20 - MOVV R20, 32(R3) // frame size to 32+SP as callreflect args) - JAL ·callMethod(SB) - ADDV $LOCAL_REGARGS, R3, R25 // unspillArgs using R25 - JAL runtime·unspillArgs(SB) - RET diff --git a/contrib/go/_std_1.22/src/reflect/swapper.go b/contrib/go/_std_1.22/src/reflect/swapper.go deleted file mode 100644 index 1e8f4ed16364..000000000000 --- a/contrib/go/_std_1.22/src/reflect/swapper.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package reflect - -import ( - "internal/abi" - "internal/goarch" - "internal/unsafeheader" - "unsafe" -) - -// Swapper returns a function that swaps the elements in the provided -// slice. -// -// Swapper panics if the provided interface is not a slice. -func Swapper(slice any) func(i, j int) { - v := ValueOf(slice) - if v.Kind() != Slice { - panic(&ValueError{Method: "Swapper", Kind: v.Kind()}) - } - // Fast path for slices of size 0 and 1. Nothing to swap. - switch v.Len() { - case 0: - return func(i, j int) { panic("reflect: slice index out of range") } - case 1: - return func(i, j int) { - if i != 0 || j != 0 { - panic("reflect: slice index out of range") - } - } - } - - typ := v.Type().Elem().common() - size := typ.Size() - hasPtr := typ.PtrBytes != 0 - - // Some common & small cases, without using memmove: - if hasPtr { - if size == goarch.PtrSize { - ps := *(*[]unsafe.Pointer)(v.ptr) - return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } - } - if typ.Kind() == abi.String { - ss := *(*[]string)(v.ptr) - return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] } - } - } else { - switch size { - case 8: - is := *(*[]int64)(v.ptr) - return func(i, j int) { is[i], is[j] = is[j], is[i] } - case 4: - is := *(*[]int32)(v.ptr) - return func(i, j int) { is[i], is[j] = is[j], is[i] } - case 2: - is := *(*[]int16)(v.ptr) - return func(i, j int) { is[i], is[j] = is[j], is[i] } - case 1: - is := *(*[]int8)(v.ptr) - return func(i, j int) { is[i], is[j] = is[j], is[i] } - } - } - - s := (*unsafeheader.Slice)(v.ptr) - tmp := unsafe_New(typ) // swap scratch space - - return func(i, j int) { - if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) { - panic("reflect: slice index out of range") - } - val1 := arrayAt(s.Data, i, size, "i < s.Len") - val2 := arrayAt(s.Data, j, size, "j < s.Len") - typedmemmove(typ, tmp, val1) - typedmemmove(typ, val1, val2) - typedmemmove(typ, val2, tmp) - } -} diff --git a/contrib/go/_std_1.22/src/reflect/type.go b/contrib/go/_std_1.22/src/reflect/type.go deleted file mode 100644 index 89c501553023..000000000000 --- a/contrib/go/_std_1.22/src/reflect/type.go +++ /dev/null @@ -1,2885 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package reflect implements run-time reflection, allowing a program to -// manipulate objects with arbitrary types. The typical use is to take a value -// with static type interface{} and extract its dynamic type information by -// calling TypeOf, which returns a Type. -// -// A call to ValueOf returns a Value representing the run-time data. -// Zero takes a Type and returns a Value representing a zero value -// for that type. -// -// See "The Laws of Reflection" for an introduction to reflection in Go: -// https://golang.org/doc/articles/laws_of_reflection.html -package reflect - -import ( - "internal/abi" - "internal/goarch" - "strconv" - "sync" - "unicode" - "unicode/utf8" - "unsafe" -) - -// Type is the representation of a Go type. -// -// Not all methods apply to all kinds of types. Restrictions, -// if any, are noted in the documentation for each method. -// Use the Kind method to find out the kind of type before -// calling kind-specific methods. Calling a method -// inappropriate to the kind of type causes a run-time panic. -// -// Type values are comparable, such as with the == operator, -// so they can be used as map keys. -// Two Type values are equal if they represent identical types. -type Type interface { - // Methods applicable to all types. - - // Align returns the alignment in bytes of a value of - // this type when allocated in memory. - Align() int - - // FieldAlign returns the alignment in bytes of a value of - // this type when used as a field in a struct. - FieldAlign() int - - // Method returns the i'th method in the type's method set. - // It panics if i is not in the range [0, NumMethod()). - // - // For a non-interface type T or *T, the returned Method's Type and Func - // fields describe a function whose first argument is the receiver, - // and only exported methods are accessible. - // - // For an interface type, the returned Method's Type field gives the - // method signature, without a receiver, and the Func field is nil. - // - // Methods are sorted in lexicographic order. - Method(int) Method - - // MethodByName returns the method with that name in the type's - // method set and a boolean indicating if the method was found. - // - // For a non-interface type T or *T, the returned Method's Type and Func - // fields describe a function whose first argument is the receiver. - // - // For an interface type, the returned Method's Type field gives the - // method signature, without a receiver, and the Func field is nil. - MethodByName(string) (Method, bool) - - // NumMethod returns the number of methods accessible using Method. - // - // For a non-interface type, it returns the number of exported methods. - // - // For an interface type, it returns the number of exported and unexported methods. - NumMethod() int - - // Name returns the type's name within its package for a defined type. - // For other (non-defined) types it returns the empty string. - Name() string - - // PkgPath returns a defined type's package path, that is, the import path - // that uniquely identifies the package, such as "encoding/base64". - // If the type was predeclared (string, error) or not defined (*T, struct{}, - // []int, or A where A is an alias for a non-defined type), the package path - // will be the empty string. - PkgPath() string - - // Size returns the number of bytes needed to store - // a value of the given type; it is analogous to unsafe.Sizeof. - Size() uintptr - - // String returns a string representation of the type. - // The string representation may use shortened package names - // (e.g., base64 instead of "encoding/base64") and is not - // guaranteed to be unique among types. To test for type identity, - // compare the Types directly. - String() string - - // Kind returns the specific kind of this type. - Kind() Kind - - // Implements reports whether the type implements the interface type u. - Implements(u Type) bool - - // AssignableTo reports whether a value of the type is assignable to type u. - AssignableTo(u Type) bool - - // ConvertibleTo reports whether a value of the type is convertible to type u. - // Even if ConvertibleTo returns true, the conversion may still panic. - // For example, a slice of type []T is convertible to *[N]T, - // but the conversion will panic if its length is less than N. - ConvertibleTo(u Type) bool - - // Comparable reports whether values of this type are comparable. - // Even if Comparable returns true, the comparison may still panic. - // For example, values of interface type are comparable, - // but the comparison will panic if their dynamic type is not comparable. - Comparable() bool - - // Methods applicable only to some types, depending on Kind. - // The methods allowed for each kind are: - // - // Int*, Uint*, Float*, Complex*: Bits - // Array: Elem, Len - // Chan: ChanDir, Elem - // Func: In, NumIn, Out, NumOut, IsVariadic. - // Map: Key, Elem - // Pointer: Elem - // Slice: Elem - // Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField - - // Bits returns the size of the type in bits. - // It panics if the type's Kind is not one of the - // sized or unsized Int, Uint, Float, or Complex kinds. - Bits() int - - // ChanDir returns a channel type's direction. - // It panics if the type's Kind is not Chan. - ChanDir() ChanDir - - // IsVariadic reports whether a function type's final input parameter - // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's - // implicit actual type []T. - // - // For concreteness, if t represents func(x int, y ... float64), then - // - // t.NumIn() == 2 - // t.In(0) is the reflect.Type for "int" - // t.In(1) is the reflect.Type for "[]float64" - // t.IsVariadic() == true - // - // IsVariadic panics if the type's Kind is not Func. - IsVariadic() bool - - // Elem returns a type's element type. - // It panics if the type's Kind is not Array, Chan, Map, Pointer, or Slice. - Elem() Type - - // Field returns a struct type's i'th field. - // It panics if the type's Kind is not Struct. - // It panics if i is not in the range [0, NumField()). - Field(i int) StructField - - // FieldByIndex returns the nested field corresponding - // to the index sequence. It is equivalent to calling Field - // successively for each index i. - // It panics if the type's Kind is not Struct. - FieldByIndex(index []int) StructField - - // FieldByName returns the struct field with the given name - // and a boolean indicating if the field was found. - // If the returned field is promoted from an embedded struct, - // then Offset in the returned StructField is the offset in - // the embedded struct. - FieldByName(name string) (StructField, bool) - - // FieldByNameFunc returns the struct field with a name - // that satisfies the match function and a boolean indicating if - // the field was found. - // - // FieldByNameFunc considers the fields in the struct itself - // and then the fields in any embedded structs, in breadth first order, - // stopping at the shallowest nesting depth containing one or more - // fields satisfying the match function. If multiple fields at that depth - // satisfy the match function, they cancel each other - // and FieldByNameFunc returns no match. - // This behavior mirrors Go's handling of name lookup in - // structs containing embedded fields. - // - // If the returned field is promoted from an embedded struct, - // then Offset in the returned StructField is the offset in - // the embedded struct. - FieldByNameFunc(match func(string) bool) (StructField, bool) - - // In returns the type of a function type's i'th input parameter. - // It panics if the type's Kind is not Func. - // It panics if i is not in the range [0, NumIn()). - In(i int) Type - - // Key returns a map type's key type. - // It panics if the type's Kind is not Map. - Key() Type - - // Len returns an array type's length. - // It panics if the type's Kind is not Array. - Len() int - - // NumField returns a struct type's field count. - // It panics if the type's Kind is not Struct. - NumField() int - - // NumIn returns a function type's input parameter count. - // It panics if the type's Kind is not Func. - NumIn() int - - // NumOut returns a function type's output parameter count. - // It panics if the type's Kind is not Func. - NumOut() int - - // Out returns the type of a function type's i'th output parameter. - // It panics if the type's Kind is not Func. - // It panics if i is not in the range [0, NumOut()). - Out(i int) Type - - common() *abi.Type - uncommon() *uncommonType -} - -// BUG(rsc): FieldByName and related functions consider struct field names to be equal -// if the names are equal, even if they are unexported names originating -// in different packages. The practical effect of this is that the result of -// t.FieldByName("x") is not well defined if the struct type t contains -// multiple fields named x (embedded from different packages). -// FieldByName may return one of the fields named x or may report that there are none. -// See https://golang.org/issue/4876 for more details. - -/* - * These data structures are known to the compiler (../cmd/compile/internal/reflectdata/reflect.go). - * A few are known to ../runtime/type.go to convey to debuggers. - * They are also known to ../runtime/type.go. - */ - -// A Kind represents the specific kind of type that a [Type] represents. -// The zero Kind is not a valid kind. -type Kind uint - -const ( - Invalid Kind = iota - Bool - Int - Int8 - Int16 - Int32 - Int64 - Uint - Uint8 - Uint16 - Uint32 - Uint64 - Uintptr - Float32 - Float64 - Complex64 - Complex128 - Array - Chan - Func - Interface - Map - Pointer - Slice - String - Struct - UnsafePointer -) - -// Ptr is the old name for the [Pointer] kind. -const Ptr = Pointer - -// uncommonType is present only for defined types or types with methods -// (if T is a defined type, the uncommonTypes for T and *T have methods). -// Using a pointer to this struct reduces the overall size required -// to describe a non-defined type with no methods. -type uncommonType = abi.UncommonType - -// Embed this type to get common/uncommon -type common struct { - abi.Type -} - -// rtype is the common implementation of most values. -// It is embedded in other struct types. -type rtype struct { - t abi.Type -} - -func (t *rtype) common() *abi.Type { - return &t.t -} - -func (t *rtype) uncommon() *abi.UncommonType { - return t.t.Uncommon() -} - -type aNameOff = abi.NameOff -type aTypeOff = abi.TypeOff -type aTextOff = abi.TextOff - -// ChanDir represents a channel type's direction. -type ChanDir int - -const ( - RecvDir ChanDir = 1 << iota // <-chan - SendDir // chan<- - BothDir = RecvDir | SendDir // chan -) - -// arrayType represents a fixed array type. -type arrayType = abi.ArrayType - -// chanType represents a channel type. -type chanType = abi.ChanType - -// funcType represents a function type. -// -// A *rtype for each in and out parameter is stored in an array that -// directly follows the funcType (and possibly its uncommonType). So -// a function type with one method, one input, and one output is: -// -// struct { -// funcType -// uncommonType -// [2]*rtype // [0] is in, [1] is out -// } -type funcType = abi.FuncType - -// interfaceType represents an interface type. -type interfaceType struct { - abi.InterfaceType // can embed directly because not a public type. -} - -func (t *interfaceType) nameOff(off aNameOff) abi.Name { - return toRType(&t.Type).nameOff(off) -} - -func nameOffFor(t *abi.Type, off aNameOff) abi.Name { - return toRType(t).nameOff(off) -} - -func typeOffFor(t *abi.Type, off aTypeOff) *abi.Type { - return toRType(t).typeOff(off) -} - -func (t *interfaceType) typeOff(off aTypeOff) *abi.Type { - return toRType(&t.Type).typeOff(off) -} - -func (t *interfaceType) common() *abi.Type { - return &t.Type -} - -func (t *interfaceType) uncommon() *abi.UncommonType { - return t.Uncommon() -} - -// mapType represents a map type. -type mapType struct { - abi.MapType -} - -// ptrType represents a pointer type. -type ptrType struct { - abi.PtrType -} - -// sliceType represents a slice type. -type sliceType struct { - abi.SliceType -} - -// Struct field -type structField = abi.StructField - -// structType represents a struct type. -type structType struct { - abi.StructType -} - -func pkgPath(n abi.Name) string { - if n.Bytes == nil || *n.DataChecked(0, "name flag field")&(1<<2) == 0 { - return "" - } - i, l := n.ReadVarint(1) - off := 1 + i + l - if n.HasTag() { - i2, l2 := n.ReadVarint(off) - off += i2 + l2 - } - var nameOff int32 - // Note that this field may not be aligned in memory, - // so we cannot use a direct int32 assignment here. - copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.DataChecked(off, "name offset field")))[:]) - pkgPathName := abi.Name{Bytes: (*byte)(resolveTypeOff(unsafe.Pointer(n.Bytes), nameOff))} - return pkgPathName.Name() -} - -func newName(n, tag string, exported, embedded bool) abi.Name { - return abi.NewName(n, tag, exported, embedded) -} - -/* - * The compiler knows the exact layout of all the data structures above. - * The compiler does not know about the data structures and methods below. - */ - -// Method represents a single method. -type Method struct { - // Name is the method name. - Name string - - // PkgPath is the package path that qualifies a lower case (unexported) - // method name. It is empty for upper case (exported) method names. - // The combination of PkgPath and Name uniquely identifies a method - // in a method set. - // See https://golang.org/ref/spec#Uniqueness_of_identifiers - PkgPath string - - Type Type // method type - Func Value // func with receiver as first argument - Index int // index for Type.Method -} - -// IsExported reports whether the method is exported. -func (m Method) IsExported() bool { - return m.PkgPath == "" -} - -const ( - kindDirectIface = 1 << 5 - kindGCProg = 1 << 6 // Type.gc points to GC program - kindMask = (1 << 5) - 1 -) - -// String returns the name of k. -func (k Kind) String() string { - if uint(k) < uint(len(kindNames)) { - return kindNames[uint(k)] - } - return "kind" + strconv.Itoa(int(k)) -} - -var kindNames = []string{ - Invalid: "invalid", - Bool: "bool", - Int: "int", - Int8: "int8", - Int16: "int16", - Int32: "int32", - Int64: "int64", - Uint: "uint", - Uint8: "uint8", - Uint16: "uint16", - Uint32: "uint32", - Uint64: "uint64", - Uintptr: "uintptr", - Float32: "float32", - Float64: "float64", - Complex64: "complex64", - Complex128: "complex128", - Array: "array", - Chan: "chan", - Func: "func", - Interface: "interface", - Map: "map", - Pointer: "ptr", - Slice: "slice", - String: "string", - Struct: "struct", - UnsafePointer: "unsafe.Pointer", -} - -// resolveNameOff resolves a name offset from a base pointer. -// The (*rtype).nameOff method is a convenience wrapper for this function. -// Implemented in the runtime package. -// -//go:noescape -func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer - -// resolveTypeOff resolves an *rtype offset from a base type. -// The (*rtype).typeOff method is a convenience wrapper for this function. -// Implemented in the runtime package. -// -//go:noescape -func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer - -// resolveTextOff resolves a function pointer offset from a base type. -// The (*rtype).textOff method is a convenience wrapper for this function. -// Implemented in the runtime package. -// -//go:noescape -func resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer - -// addReflectOff adds a pointer to the reflection lookup map in the runtime. -// It returns a new ID that can be used as a typeOff or textOff, and will -// be resolved correctly. Implemented in the runtime package. -// -//go:noescape -func addReflectOff(ptr unsafe.Pointer) int32 - -// resolveReflectName adds a name to the reflection lookup map in the runtime. -// It returns a new nameOff that can be used to refer to the pointer. -func resolveReflectName(n abi.Name) aNameOff { - return aNameOff(addReflectOff(unsafe.Pointer(n.Bytes))) -} - -// resolveReflectType adds a *rtype to the reflection lookup map in the runtime. -// It returns a new typeOff that can be used to refer to the pointer. -func resolveReflectType(t *abi.Type) aTypeOff { - return aTypeOff(addReflectOff(unsafe.Pointer(t))) -} - -// resolveReflectText adds a function pointer to the reflection lookup map in -// the runtime. It returns a new textOff that can be used to refer to the -// pointer. -func resolveReflectText(ptr unsafe.Pointer) aTextOff { - return aTextOff(addReflectOff(ptr)) -} - -func (t *rtype) nameOff(off aNameOff) abi.Name { - return abi.Name{Bytes: (*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))} -} - -func (t *rtype) typeOff(off aTypeOff) *abi.Type { - return (*abi.Type)(resolveTypeOff(unsafe.Pointer(t), int32(off))) -} - -func (t *rtype) textOff(off aTextOff) unsafe.Pointer { - return resolveTextOff(unsafe.Pointer(t), int32(off)) -} - -func textOffFor(t *abi.Type, off aTextOff) unsafe.Pointer { - return toRType(t).textOff(off) -} - -func (t *rtype) String() string { - s := t.nameOff(t.t.Str).Name() - if t.t.TFlag&abi.TFlagExtraStar != 0 { - return s[1:] - } - return s -} - -func (t *rtype) Size() uintptr { return t.t.Size() } - -func (t *rtype) Bits() int { - if t == nil { - panic("reflect: Bits of nil Type") - } - k := t.Kind() - if k < Int || k > Complex128 { - panic("reflect: Bits of non-arithmetic Type " + t.String()) - } - return int(t.t.Size_) * 8 -} - -func (t *rtype) Align() int { return t.t.Align() } - -func (t *rtype) FieldAlign() int { return t.t.FieldAlign() } - -func (t *rtype) Kind() Kind { return Kind(t.t.Kind()) } - -func (t *rtype) exportedMethods() []abi.Method { - ut := t.uncommon() - if ut == nil { - return nil - } - return ut.ExportedMethods() -} - -func (t *rtype) NumMethod() int { - if t.Kind() == Interface { - tt := (*interfaceType)(unsafe.Pointer(t)) - return tt.NumMethod() - } - return len(t.exportedMethods()) -} - -func (t *rtype) Method(i int) (m Method) { - if t.Kind() == Interface { - tt := (*interfaceType)(unsafe.Pointer(t)) - return tt.Method(i) - } - methods := t.exportedMethods() - if i < 0 || i >= len(methods) { - panic("reflect: Method index out of range") - } - p := methods[i] - pname := t.nameOff(p.Name) - m.Name = pname.Name() - fl := flag(Func) - mtyp := t.typeOff(p.Mtyp) - ft := (*funcType)(unsafe.Pointer(mtyp)) - in := make([]Type, 0, 1+ft.NumIn()) - in = append(in, t) - for _, arg := range ft.InSlice() { - in = append(in, toRType(arg)) - } - out := make([]Type, 0, ft.NumOut()) - for _, ret := range ft.OutSlice() { - out = append(out, toRType(ret)) - } - mt := FuncOf(in, out, ft.IsVariadic()) - m.Type = mt - tfn := t.textOff(p.Tfn) - fn := unsafe.Pointer(&tfn) - m.Func = Value{&mt.(*rtype).t, fn, fl} - - m.Index = i - return m -} - -func (t *rtype) MethodByName(name string) (m Method, ok bool) { - if t.Kind() == Interface { - tt := (*interfaceType)(unsafe.Pointer(t)) - return tt.MethodByName(name) - } - ut := t.uncommon() - if ut == nil { - return Method{}, false - } - - methods := ut.ExportedMethods() - - // We are looking for the first index i where the string becomes >= s. - // This is a copy of sort.Search, with f(h) replaced by (t.nameOff(methods[h].name).name() >= name). - i, j := 0, len(methods) - for i < j { - h := int(uint(i+j) >> 1) // avoid overflow when computing h - // i ≤ h < j - if !(t.nameOff(methods[h].Name).Name() >= name) { - i = h + 1 // preserves f(i-1) == false - } else { - j = h // preserves f(j) == true - } - } - // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. - if i < len(methods) && name == t.nameOff(methods[i].Name).Name() { - return t.Method(i), true - } - - return Method{}, false -} - -func (t *rtype) PkgPath() string { - if t.t.TFlag&abi.TFlagNamed == 0 { - return "" - } - ut := t.uncommon() - if ut == nil { - return "" - } - return t.nameOff(ut.PkgPath).Name() -} - -func pkgPathFor(t *abi.Type) string { - return toRType(t).PkgPath() -} - -func (t *rtype) Name() string { - if !t.t.HasName() { - return "" - } - s := t.String() - i := len(s) - 1 - sqBrackets := 0 - for i >= 0 && (s[i] != '.' || sqBrackets != 0) { - switch s[i] { - case ']': - sqBrackets++ - case '[': - sqBrackets-- - } - i-- - } - return s[i+1:] -} - -func nameFor(t *abi.Type) string { - return toRType(t).Name() -} - -func (t *rtype) ChanDir() ChanDir { - if t.Kind() != Chan { - panic("reflect: ChanDir of non-chan type " + t.String()) - } - tt := (*abi.ChanType)(unsafe.Pointer(t)) - return ChanDir(tt.Dir) -} - -func toRType(t *abi.Type) *rtype { - return (*rtype)(unsafe.Pointer(t)) -} - -func elem(t *abi.Type) *abi.Type { - et := t.Elem() - if et != nil { - return et - } - panic("reflect: Elem of invalid type " + stringFor(t)) -} - -func (t *rtype) Elem() Type { - return toType(elem(t.common())) -} - -func (t *rtype) Field(i int) StructField { - if t.Kind() != Struct { - panic("reflect: Field of non-struct type " + t.String()) - } - tt := (*structType)(unsafe.Pointer(t)) - return tt.Field(i) -} - -func (t *rtype) FieldByIndex(index []int) StructField { - if t.Kind() != Struct { - panic("reflect: FieldByIndex of non-struct type " + t.String()) - } - tt := (*structType)(unsafe.Pointer(t)) - return tt.FieldByIndex(index) -} - -func (t *rtype) FieldByName(name string) (StructField, bool) { - if t.Kind() != Struct { - panic("reflect: FieldByName of non-struct type " + t.String()) - } - tt := (*structType)(unsafe.Pointer(t)) - return tt.FieldByName(name) -} - -func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) { - if t.Kind() != Struct { - panic("reflect: FieldByNameFunc of non-struct type " + t.String()) - } - tt := (*structType)(unsafe.Pointer(t)) - return tt.FieldByNameFunc(match) -} - -func (t *rtype) Key() Type { - if t.Kind() != Map { - panic("reflect: Key of non-map type " + t.String()) - } - tt := (*mapType)(unsafe.Pointer(t)) - return toType(tt.Key) -} - -func (t *rtype) Len() int { - if t.Kind() != Array { - panic("reflect: Len of non-array type " + t.String()) - } - tt := (*arrayType)(unsafe.Pointer(t)) - return int(tt.Len) -} - -func (t *rtype) NumField() int { - if t.Kind() != Struct { - panic("reflect: NumField of non-struct type " + t.String()) - } - tt := (*structType)(unsafe.Pointer(t)) - return len(tt.Fields) -} - -func (t *rtype) In(i int) Type { - if t.Kind() != Func { - panic("reflect: In of non-func type " + t.String()) - } - tt := (*abi.FuncType)(unsafe.Pointer(t)) - return toType(tt.InSlice()[i]) -} - -func (t *rtype) NumIn() int { - if t.Kind() != Func { - panic("reflect: NumIn of non-func type " + t.String()) - } - tt := (*abi.FuncType)(unsafe.Pointer(t)) - return tt.NumIn() -} - -func (t *rtype) NumOut() int { - if t.Kind() != Func { - panic("reflect: NumOut of non-func type " + t.String()) - } - tt := (*abi.FuncType)(unsafe.Pointer(t)) - return tt.NumOut() -} - -func (t *rtype) Out(i int) Type { - if t.Kind() != Func { - panic("reflect: Out of non-func type " + t.String()) - } - tt := (*abi.FuncType)(unsafe.Pointer(t)) - return toType(tt.OutSlice()[i]) -} - -func (t *rtype) IsVariadic() bool { - if t.Kind() != Func { - panic("reflect: IsVariadic of non-func type " + t.String()) - } - tt := (*abi.FuncType)(unsafe.Pointer(t)) - return tt.IsVariadic() -} - -// add returns p+x. -// -// The whySafe string is ignored, so that the function still inlines -// as efficiently as p+x, but all call sites should use the string to -// record why the addition is safe, which is to say why the addition -// does not cause x to advance to the very end of p's allocation -// and therefore point incorrectly at the next block in memory. -func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { - return unsafe.Pointer(uintptr(p) + x) -} - -func (d ChanDir) String() string { - switch d { - case SendDir: - return "chan<-" - case RecvDir: - return "<-chan" - case BothDir: - return "chan" - } - return "ChanDir" + strconv.Itoa(int(d)) -} - -// Method returns the i'th method in the type's method set. -func (t *interfaceType) Method(i int) (m Method) { - if i < 0 || i >= len(t.Methods) { - return - } - p := &t.Methods[i] - pname := t.nameOff(p.Name) - m.Name = pname.Name() - if !pname.IsExported() { - m.PkgPath = pkgPath(pname) - if m.PkgPath == "" { - m.PkgPath = t.PkgPath.Name() - } - } - m.Type = toType(t.typeOff(p.Typ)) - m.Index = i - return -} - -// NumMethod returns the number of interface methods in the type's method set. -func (t *interfaceType) NumMethod() int { return len(t.Methods) } - -// MethodByName method with the given name in the type's method set. -func (t *interfaceType) MethodByName(name string) (m Method, ok bool) { - if t == nil { - return - } - var p *abi.Imethod - for i := range t.Methods { - p = &t.Methods[i] - if t.nameOff(p.Name).Name() == name { - return t.Method(i), true - } - } - return -} - -// A StructField describes a single field in a struct. -type StructField struct { - // Name is the field name. - Name string - - // PkgPath is the package path that qualifies a lower case (unexported) - // field name. It is empty for upper case (exported) field names. - // See https://golang.org/ref/spec#Uniqueness_of_identifiers - PkgPath string - - Type Type // field type - Tag StructTag // field tag string - Offset uintptr // offset within struct, in bytes - Index []int // index sequence for Type.FieldByIndex - Anonymous bool // is an embedded field -} - -// IsExported reports whether the field is exported. -func (f StructField) IsExported() bool { - return f.PkgPath == "" -} - -// A StructTag is the tag string in a struct field. -// -// By convention, tag strings are a concatenation of -// optionally space-separated key:"value" pairs. -// Each key is a non-empty string consisting of non-control -// characters other than space (U+0020 ' '), quote (U+0022 '"'), -// and colon (U+003A ':'). Each value is quoted using U+0022 '"' -// characters and Go string literal syntax. -type StructTag string - -// Get returns the value associated with key in the tag string. -// If there is no such key in the tag, Get returns the empty string. -// If the tag does not have the conventional format, the value -// returned by Get is unspecified. To determine whether a tag is -// explicitly set to the empty string, use Lookup. -func (tag StructTag) Get(key string) string { - v, _ := tag.Lookup(key) - return v -} - -// Lookup returns the value associated with key in the tag string. -// If the key is present in the tag the value (which may be empty) -// is returned. Otherwise the returned value will be the empty string. -// The ok return value reports whether the value was explicitly set in -// the tag string. If the tag does not have the conventional format, -// the value returned by Lookup is unspecified. -func (tag StructTag) Lookup(key string) (value string, ok bool) { - // When modifying this code, also update the validateStructTag code - // in cmd/vet/structtag.go. - - for tag != "" { - // Skip leading space. - i := 0 - for i < len(tag) && tag[i] == ' ' { - i++ - } - tag = tag[i:] - if tag == "" { - break - } - - // Scan to colon. A space, a quote or a control character is a syntax error. - // Strictly speaking, control chars include the range [0x7f, 0x9f], not just - // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters - // as it is simpler to inspect the tag's bytes than the tag's runes. - i = 0 - for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { - i++ - } - if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { - break - } - name := string(tag[:i]) - tag = tag[i+1:] - - // Scan quoted string to find value. - i = 1 - for i < len(tag) && tag[i] != '"' { - if tag[i] == '\\' { - i++ - } - i++ - } - if i >= len(tag) { - break - } - qvalue := string(tag[:i+1]) - tag = tag[i+1:] - - if key == name { - value, err := strconv.Unquote(qvalue) - if err != nil { - break - } - return value, true - } - } - return "", false -} - -// Field returns the i'th struct field. -func (t *structType) Field(i int) (f StructField) { - if i < 0 || i >= len(t.Fields) { - panic("reflect: Field index out of bounds") - } - p := &t.Fields[i] - f.Type = toType(p.Typ) - f.Name = p.Name.Name() - f.Anonymous = p.Embedded() - if !p.Name.IsExported() { - f.PkgPath = t.PkgPath.Name() - } - if tag := p.Name.Tag(); tag != "" { - f.Tag = StructTag(tag) - } - f.Offset = p.Offset - - // NOTE(rsc): This is the only allocation in the interface - // presented by a reflect.Type. It would be nice to avoid, - // at least in the common cases, but we need to make sure - // that misbehaving clients of reflect cannot affect other - // uses of reflect. One possibility is CL 5371098, but we - // postponed that ugliness until there is a demonstrated - // need for the performance. This is issue 2320. - f.Index = []int{i} - return -} - -// TODO(gri): Should there be an error/bool indicator if the index -// is wrong for FieldByIndex? - -// FieldByIndex returns the nested field corresponding to index. -func (t *structType) FieldByIndex(index []int) (f StructField) { - f.Type = toType(&t.Type) - for i, x := range index { - if i > 0 { - ft := f.Type - if ft.Kind() == Pointer && ft.Elem().Kind() == Struct { - ft = ft.Elem() - } - f.Type = ft - } - f = f.Type.Field(x) - } - return -} - -// A fieldScan represents an item on the fieldByNameFunc scan work list. -type fieldScan struct { - typ *structType - index []int -} - -// FieldByNameFunc returns the struct field with a name that satisfies the -// match function and a boolean to indicate if the field was found. -func (t *structType) FieldByNameFunc(match func(string) bool) (result StructField, ok bool) { - // This uses the same condition that the Go language does: there must be a unique instance - // of the match at a given depth level. If there are multiple instances of a match at the - // same depth, they annihilate each other and inhibit any possible match at a lower level. - // The algorithm is breadth first search, one depth level at a time. - - // The current and next slices are work queues: - // current lists the fields to visit on this depth level, - // and next lists the fields on the next lower level. - current := []fieldScan{} - next := []fieldScan{{typ: t}} - - // nextCount records the number of times an embedded type has been - // encountered and considered for queueing in the 'next' slice. - // We only queue the first one, but we increment the count on each. - // If a struct type T can be reached more than once at a given depth level, - // then it annihilates itself and need not be considered at all when we - // process that next depth level. - var nextCount map[*structType]int - - // visited records the structs that have been considered already. - // Embedded pointer fields can create cycles in the graph of - // reachable embedded types; visited avoids following those cycles. - // It also avoids duplicated effort: if we didn't find the field in an - // embedded type T at level 2, we won't find it in one at level 4 either. - visited := map[*structType]bool{} - - for len(next) > 0 { - current, next = next, current[:0] - count := nextCount - nextCount = nil - - // Process all the fields at this depth, now listed in 'current'. - // The loop queues embedded fields found in 'next', for processing during the next - // iteration. The multiplicity of the 'current' field counts is recorded - // in 'count'; the multiplicity of the 'next' field counts is recorded in 'nextCount'. - for _, scan := range current { - t := scan.typ - if visited[t] { - // We've looked through this type before, at a higher level. - // That higher level would shadow the lower level we're now at, - // so this one can't be useful to us. Ignore it. - continue - } - visited[t] = true - for i := range t.Fields { - f := &t.Fields[i] - // Find name and (for embedded field) type for field f. - fname := f.Name.Name() - var ntyp *abi.Type - if f.Embedded() { - // Embedded field of type T or *T. - ntyp = f.Typ - if ntyp.Kind() == abi.Pointer { - ntyp = ntyp.Elem() - } - } - - // Does it match? - if match(fname) { - // Potential match - if count[t] > 1 || ok { - // Name appeared multiple times at this level: annihilate. - return StructField{}, false - } - result = t.Field(i) - result.Index = nil - result.Index = append(result.Index, scan.index...) - result.Index = append(result.Index, i) - ok = true - continue - } - - // Queue embedded struct fields for processing with next level, - // but only if we haven't seen a match yet at this level and only - // if the embedded types haven't already been queued. - if ok || ntyp == nil || ntyp.Kind() != abi.Struct { - continue - } - styp := (*structType)(unsafe.Pointer(ntyp)) - if nextCount[styp] > 0 { - nextCount[styp] = 2 // exact multiple doesn't matter - continue - } - if nextCount == nil { - nextCount = map[*structType]int{} - } - nextCount[styp] = 1 - if count[t] > 1 { - nextCount[styp] = 2 // exact multiple doesn't matter - } - var index []int - index = append(index, scan.index...) - index = append(index, i) - next = append(next, fieldScan{styp, index}) - } - } - if ok { - break - } - } - return -} - -// FieldByName returns the struct field with the given name -// and a boolean to indicate if the field was found. -func (t *structType) FieldByName(name string) (f StructField, present bool) { - // Quick check for top-level name, or struct without embedded fields. - hasEmbeds := false - if name != "" { - for i := range t.Fields { - tf := &t.Fields[i] - if tf.Name.Name() == name { - return t.Field(i), true - } - if tf.Embedded() { - hasEmbeds = true - } - } - } - if !hasEmbeds { - return - } - return t.FieldByNameFunc(func(s string) bool { return s == name }) -} - -// TypeOf returns the reflection [Type] that represents the dynamic type of i. -// If i is a nil interface value, TypeOf returns nil. -func TypeOf(i any) Type { - eface := *(*emptyInterface)(unsafe.Pointer(&i)) - // Noescape so this doesn't make i to escape. See the comment - // at Value.typ for why this is safe. - return toType((*abi.Type)(noescape(unsafe.Pointer(eface.typ)))) -} - -// rtypeOf directly extracts the *rtype of the provided value. -func rtypeOf(i any) *abi.Type { - eface := *(*emptyInterface)(unsafe.Pointer(&i)) - return eface.typ -} - -// ptrMap is the cache for PointerTo. -var ptrMap sync.Map // map[*rtype]*ptrType - -// PtrTo returns the pointer type with element t. -// For example, if t represents type Foo, PtrTo(t) represents *Foo. -// -// PtrTo is the old spelling of [PointerTo]. -// The two functions behave identically. -// -// Deprecated: Superseded by [PointerTo]. -func PtrTo(t Type) Type { return PointerTo(t) } - -// PointerTo returns the pointer type with element t. -// For example, if t represents type Foo, PointerTo(t) represents *Foo. -func PointerTo(t Type) Type { - return toRType(t.(*rtype).ptrTo()) -} - -func (t *rtype) ptrTo() *abi.Type { - at := &t.t - if at.PtrToThis != 0 { - return t.typeOff(at.PtrToThis) - } - - // Check the cache. - if pi, ok := ptrMap.Load(t); ok { - return &pi.(*ptrType).Type - } - - // Look in known types. - s := "*" + t.String() - for _, tt := range typesByString(s) { - p := (*ptrType)(unsafe.Pointer(tt)) - if p.Elem != &t.t { - continue - } - pi, _ := ptrMap.LoadOrStore(t, p) - return &pi.(*ptrType).Type - } - - // Create a new ptrType starting with the description - // of an *unsafe.Pointer. - var iptr any = (*unsafe.Pointer)(nil) - prototype := *(**ptrType)(unsafe.Pointer(&iptr)) - pp := *prototype - - pp.Str = resolveReflectName(newName(s, "", false, false)) - pp.PtrToThis = 0 - - // For the type structures linked into the binary, the - // compiler provides a good hash of the string. - // Create a good hash for the new string by using - // the FNV-1 hash's mixing function to combine the - // old hash and the new "*". - pp.Hash = fnv1(t.t.Hash, '*') - - pp.Elem = at - - pi, _ := ptrMap.LoadOrStore(t, &pp) - return &pi.(*ptrType).Type -} - -func ptrTo(t *abi.Type) *abi.Type { - return toRType(t).ptrTo() -} - -// fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function. -func fnv1(x uint32, list ...byte) uint32 { - for _, b := range list { - x = x*16777619 ^ uint32(b) - } - return x -} - -func (t *rtype) Implements(u Type) bool { - if u == nil { - panic("reflect: nil type passed to Type.Implements") - } - if u.Kind() != Interface { - panic("reflect: non-interface type passed to Type.Implements") - } - return implements(u.common(), t.common()) -} - -func (t *rtype) AssignableTo(u Type) bool { - if u == nil { - panic("reflect: nil type passed to Type.AssignableTo") - } - uu := u.common() - return directlyAssignable(uu, t.common()) || implements(uu, t.common()) -} - -func (t *rtype) ConvertibleTo(u Type) bool { - if u == nil { - panic("reflect: nil type passed to Type.ConvertibleTo") - } - return convertOp(u.common(), t.common()) != nil -} - -func (t *rtype) Comparable() bool { - return t.t.Equal != nil -} - -// implements reports whether the type V implements the interface type T. -func implements(T, V *abi.Type) bool { - if T.Kind() != abi.Interface { - return false - } - t := (*interfaceType)(unsafe.Pointer(T)) - if len(t.Methods) == 0 { - return true - } - - // The same algorithm applies in both cases, but the - // method tables for an interface type and a concrete type - // are different, so the code is duplicated. - // In both cases the algorithm is a linear scan over the two - // lists - T's methods and V's methods - simultaneously. - // Since method tables are stored in a unique sorted order - // (alphabetical, with no duplicate method names), the scan - // through V's methods must hit a match for each of T's - // methods along the way, or else V does not implement T. - // This lets us run the scan in overall linear time instead of - // the quadratic time a naive search would require. - // See also ../runtime/iface.go. - if V.Kind() == abi.Interface { - v := (*interfaceType)(unsafe.Pointer(V)) - i := 0 - for j := 0; j < len(v.Methods); j++ { - tm := &t.Methods[i] - tmName := t.nameOff(tm.Name) - vm := &v.Methods[j] - vmName := nameOffFor(V, vm.Name) - if vmName.Name() == tmName.Name() && typeOffFor(V, vm.Typ) == t.typeOff(tm.Typ) { - if !tmName.IsExported() { - tmPkgPath := pkgPath(tmName) - if tmPkgPath == "" { - tmPkgPath = t.PkgPath.Name() - } - vmPkgPath := pkgPath(vmName) - if vmPkgPath == "" { - vmPkgPath = v.PkgPath.Name() - } - if tmPkgPath != vmPkgPath { - continue - } - } - if i++; i >= len(t.Methods) { - return true - } - } - } - return false - } - - v := V.Uncommon() - if v == nil { - return false - } - i := 0 - vmethods := v.Methods() - for j := 0; j < int(v.Mcount); j++ { - tm := &t.Methods[i] - tmName := t.nameOff(tm.Name) - vm := vmethods[j] - vmName := nameOffFor(V, vm.Name) - if vmName.Name() == tmName.Name() && typeOffFor(V, vm.Mtyp) == t.typeOff(tm.Typ) { - if !tmName.IsExported() { - tmPkgPath := pkgPath(tmName) - if tmPkgPath == "" { - tmPkgPath = t.PkgPath.Name() - } - vmPkgPath := pkgPath(vmName) - if vmPkgPath == "" { - vmPkgPath = nameOffFor(V, v.PkgPath).Name() - } - if tmPkgPath != vmPkgPath { - continue - } - } - if i++; i >= len(t.Methods) { - return true - } - } - } - return false -} - -// specialChannelAssignability reports whether a value x of channel type V -// can be directly assigned (using memmove) to another channel type T. -// https://golang.org/doc/go_spec.html#Assignability -// T and V must be both of Chan kind. -func specialChannelAssignability(T, V *abi.Type) bool { - // Special case: - // x is a bidirectional channel value, T is a channel type, - // x's type V and T have identical element types, - // and at least one of V or T is not a defined type. - return V.ChanDir() == abi.BothDir && (nameFor(T) == "" || nameFor(V) == "") && haveIdenticalType(T.Elem(), V.Elem(), true) -} - -// directlyAssignable reports whether a value x of type V can be directly -// assigned (using memmove) to a value of type T. -// https://golang.org/doc/go_spec.html#Assignability -// Ignoring the interface rules (implemented elsewhere) -// and the ideal constant rules (no ideal constants at run time). -func directlyAssignable(T, V *abi.Type) bool { - // x's type V is identical to T? - if T == V { - return true - } - - // Otherwise at least one of T and V must not be defined - // and they must have the same kind. - if T.HasName() && V.HasName() || T.Kind() != V.Kind() { - return false - } - - if T.Kind() == abi.Chan && specialChannelAssignability(T, V) { - return true - } - - // x's type T and V must have identical underlying types. - return haveIdenticalUnderlyingType(T, V, true) -} - -func haveIdenticalType(T, V *abi.Type, cmpTags bool) bool { - if cmpTags { - return T == V - } - - if nameFor(T) != nameFor(V) || T.Kind() != V.Kind() || pkgPathFor(T) != pkgPathFor(V) { - return false - } - - return haveIdenticalUnderlyingType(T, V, false) -} - -func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool { - if T == V { - return true - } - - kind := Kind(T.Kind()) - if kind != Kind(V.Kind()) { - return false - } - - // Non-composite types of equal kind have same underlying type - // (the predefined instance of the type). - if Bool <= kind && kind <= Complex128 || kind == String || kind == UnsafePointer { - return true - } - - // Composite types. - switch kind { - case Array: - return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) - - case Chan: - return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) - - case Func: - t := (*funcType)(unsafe.Pointer(T)) - v := (*funcType)(unsafe.Pointer(V)) - if t.OutCount != v.OutCount || t.InCount != v.InCount { - return false - } - for i := 0; i < t.NumIn(); i++ { - if !haveIdenticalType(t.In(i), v.In(i), cmpTags) { - return false - } - } - for i := 0; i < t.NumOut(); i++ { - if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) { - return false - } - } - return true - - case Interface: - t := (*interfaceType)(unsafe.Pointer(T)) - v := (*interfaceType)(unsafe.Pointer(V)) - if len(t.Methods) == 0 && len(v.Methods) == 0 { - return true - } - // Might have the same methods but still - // need a run time conversion. - return false - - case Map: - return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) - - case Pointer, Slice: - return haveIdenticalType(T.Elem(), V.Elem(), cmpTags) - - case Struct: - t := (*structType)(unsafe.Pointer(T)) - v := (*structType)(unsafe.Pointer(V)) - if len(t.Fields) != len(v.Fields) { - return false - } - if t.PkgPath.Name() != v.PkgPath.Name() { - return false - } - for i := range t.Fields { - tf := &t.Fields[i] - vf := &v.Fields[i] - if tf.Name.Name() != vf.Name.Name() { - return false - } - if !haveIdenticalType(tf.Typ, vf.Typ, cmpTags) { - return false - } - if cmpTags && tf.Name.Tag() != vf.Name.Tag() { - return false - } - if tf.Offset != vf.Offset { - return false - } - if tf.Embedded() != vf.Embedded() { - return false - } - } - return true - } - - return false -} - -// typelinks is implemented in package runtime. -// It returns a slice of the sections in each module, -// and a slice of *rtype offsets in each module. -// -// The types in each module are sorted by string. That is, the first -// two linked types of the first module are: -// -// d0 := sections[0] -// t1 := (*rtype)(add(d0, offset[0][0])) -// t2 := (*rtype)(add(d0, offset[0][1])) -// -// and -// -// t1.String() < t2.String() -// -// Note that strings are not unique identifiers for types: -// there can be more than one with a given string. -// Only types we might want to look up are included: -// pointers, channels, maps, slices, and arrays. -func typelinks() (sections []unsafe.Pointer, offset [][]int32) - -func rtypeOff(section unsafe.Pointer, off int32) *abi.Type { - return (*abi.Type)(add(section, uintptr(off), "sizeof(rtype) > 0")) -} - -// typesByString returns the subslice of typelinks() whose elements have -// the given string representation. -// It may be empty (no known types with that string) or may have -// multiple elements (multiple types with that string). -func typesByString(s string) []*abi.Type { - sections, offset := typelinks() - var ret []*abi.Type - - for offsI, offs := range offset { - section := sections[offsI] - - // We are looking for the first index i where the string becomes >= s. - // This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s). - i, j := 0, len(offs) - for i < j { - h := int(uint(i+j) >> 1) // avoid overflow when computing h - // i ≤ h < j - if !(stringFor(rtypeOff(section, offs[h])) >= s) { - i = h + 1 // preserves f(i-1) == false - } else { - j = h // preserves f(j) == true - } - } - // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. - - // Having found the first, linear scan forward to find the last. - // We could do a second binary search, but the caller is going - // to do a linear scan anyway. - for j := i; j < len(offs); j++ { - typ := rtypeOff(section, offs[j]) - if stringFor(typ) != s { - break - } - ret = append(ret, typ) - } - } - return ret -} - -// The lookupCache caches ArrayOf, ChanOf, MapOf and SliceOf lookups. -var lookupCache sync.Map // map[cacheKey]*rtype - -// A cacheKey is the key for use in the lookupCache. -// Four values describe any of the types we are looking for: -// type kind, one or two subtypes, and an extra integer. -type cacheKey struct { - kind Kind - t1 *abi.Type - t2 *abi.Type - extra uintptr -} - -// The funcLookupCache caches FuncOf lookups. -// FuncOf does not share the common lookupCache since cacheKey is not -// sufficient to represent functions unambiguously. -var funcLookupCache struct { - sync.Mutex // Guards stores (but not loads) on m. - - // m is a map[uint32][]*rtype keyed by the hash calculated in FuncOf. - // Elements of m are append-only and thus safe for concurrent reading. - m sync.Map -} - -// ChanOf returns the channel type with the given direction and element type. -// For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int. -// -// The gc runtime imposes a limit of 64 kB on channel element types. -// If t's size is equal to or exceeds this limit, ChanOf panics. -func ChanOf(dir ChanDir, t Type) Type { - typ := t.common() - - // Look in cache. - ckey := cacheKey{Chan, typ, nil, uintptr(dir)} - if ch, ok := lookupCache.Load(ckey); ok { - return ch.(*rtype) - } - - // This restriction is imposed by the gc compiler and the runtime. - if typ.Size_ >= 1<<16 { - panic("reflect.ChanOf: element size too large") - } - - // Look in known types. - var s string - switch dir { - default: - panic("reflect.ChanOf: invalid dir") - case SendDir: - s = "chan<- " + stringFor(typ) - case RecvDir: - s = "<-chan " + stringFor(typ) - case BothDir: - typeStr := stringFor(typ) - if typeStr[0] == '<' { - // typ is recv chan, need parentheses as "<-" associates with leftmost - // chan possible, see: - // * https://golang.org/ref/spec#Channel_types - // * https://github.com/golang/go/issues/39897 - s = "chan (" + typeStr + ")" - } else { - s = "chan " + typeStr - } - } - for _, tt := range typesByString(s) { - ch := (*chanType)(unsafe.Pointer(tt)) - if ch.Elem == typ && ch.Dir == abi.ChanDir(dir) { - ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt)) - return ti.(Type) - } - } - - // Make a channel type. - var ichan any = (chan unsafe.Pointer)(nil) - prototype := *(**chanType)(unsafe.Pointer(&ichan)) - ch := *prototype - ch.TFlag = abi.TFlagRegularMemory - ch.Dir = abi.ChanDir(dir) - ch.Str = resolveReflectName(newName(s, "", false, false)) - ch.Hash = fnv1(typ.Hash, 'c', byte(dir)) - ch.Elem = typ - - ti, _ := lookupCache.LoadOrStore(ckey, toRType(&ch.Type)) - return ti.(Type) -} - -// MapOf returns the map type with the given key and element types. -// For example, if k represents int and e represents string, -// MapOf(k, e) represents map[int]string. -// -// If the key type is not a valid map key type (that is, if it does -// not implement Go's == operator), MapOf panics. -func MapOf(key, elem Type) Type { - ktyp := key.common() - etyp := elem.common() - - if ktyp.Equal == nil { - panic("reflect.MapOf: invalid key type " + stringFor(ktyp)) - } - - // Look in cache. - ckey := cacheKey{Map, ktyp, etyp, 0} - if mt, ok := lookupCache.Load(ckey); ok { - return mt.(Type) - } - - // Look in known types. - s := "map[" + stringFor(ktyp) + "]" + stringFor(etyp) - for _, tt := range typesByString(s) { - mt := (*mapType)(unsafe.Pointer(tt)) - if mt.Key == ktyp && mt.Elem == etyp { - ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt)) - return ti.(Type) - } - } - - // Make a map type. - // Note: flag values must match those used in the TMAP case - // in ../cmd/compile/internal/reflectdata/reflect.go:writeType. - var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil) - mt := **(**mapType)(unsafe.Pointer(&imap)) - mt.Str = resolveReflectName(newName(s, "", false, false)) - mt.TFlag = 0 - mt.Hash = fnv1(etyp.Hash, 'm', byte(ktyp.Hash>>24), byte(ktyp.Hash>>16), byte(ktyp.Hash>>8), byte(ktyp.Hash)) - mt.Key = ktyp - mt.Elem = etyp - mt.Bucket = bucketOf(ktyp, etyp) - mt.Hasher = func(p unsafe.Pointer, seed uintptr) uintptr { - return typehash(ktyp, p, seed) - } - mt.Flags = 0 - if ktyp.Size_ > maxKeySize { - mt.KeySize = uint8(goarch.PtrSize) - mt.Flags |= 1 // indirect key - } else { - mt.KeySize = uint8(ktyp.Size_) - } - if etyp.Size_ > maxValSize { - mt.ValueSize = uint8(goarch.PtrSize) - mt.Flags |= 2 // indirect value - } else { - mt.MapType.ValueSize = uint8(etyp.Size_) - } - mt.MapType.BucketSize = uint16(mt.Bucket.Size_) - if isReflexive(ktyp) { - mt.Flags |= 4 - } - if needKeyUpdate(ktyp) { - mt.Flags |= 8 - } - if hashMightPanic(ktyp) { - mt.Flags |= 16 - } - mt.PtrToThis = 0 - - ti, _ := lookupCache.LoadOrStore(ckey, toRType(&mt.Type)) - return ti.(Type) -} - -var funcTypes []Type -var funcTypesMutex sync.Mutex - -func initFuncTypes(n int) Type { - funcTypesMutex.Lock() - defer funcTypesMutex.Unlock() - if n >= len(funcTypes) { - newFuncTypes := make([]Type, n+1) - copy(newFuncTypes, funcTypes) - funcTypes = newFuncTypes - } - if funcTypes[n] != nil { - return funcTypes[n] - } - - funcTypes[n] = StructOf([]StructField{ - { - Name: "FuncType", - Type: TypeOf(funcType{}), - }, - { - Name: "Args", - Type: ArrayOf(n, TypeOf(&rtype{})), - }, - }) - return funcTypes[n] -} - -// FuncOf returns the function type with the given argument and result types. -// For example if k represents int and e represents string, -// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string. -// -// The variadic argument controls whether the function is variadic. FuncOf -// panics if the in[len(in)-1] does not represent a slice and variadic is -// true. -func FuncOf(in, out []Type, variadic bool) Type { - if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) { - panic("reflect.FuncOf: last arg of variadic func must be slice") - } - - // Make a func type. - var ifunc any = (func())(nil) - prototype := *(**funcType)(unsafe.Pointer(&ifunc)) - n := len(in) + len(out) - - if n > 128 { - panic("reflect.FuncOf: too many arguments") - } - - o := New(initFuncTypes(n)).Elem() - ft := (*funcType)(unsafe.Pointer(o.Field(0).Addr().Pointer())) - args := unsafe.Slice((**rtype)(unsafe.Pointer(o.Field(1).Addr().Pointer())), n)[0:0:n] - *ft = *prototype - - // Build a hash and minimally populate ft. - var hash uint32 - for _, in := range in { - t := in.(*rtype) - args = append(args, t) - hash = fnv1(hash, byte(t.t.Hash>>24), byte(t.t.Hash>>16), byte(t.t.Hash>>8), byte(t.t.Hash)) - } - if variadic { - hash = fnv1(hash, 'v') - } - hash = fnv1(hash, '.') - for _, out := range out { - t := out.(*rtype) - args = append(args, t) - hash = fnv1(hash, byte(t.t.Hash>>24), byte(t.t.Hash>>16), byte(t.t.Hash>>8), byte(t.t.Hash)) - } - - ft.TFlag = 0 - ft.Hash = hash - ft.InCount = uint16(len(in)) - ft.OutCount = uint16(len(out)) - if variadic { - ft.OutCount |= 1 << 15 - } - - // Look in cache. - if ts, ok := funcLookupCache.m.Load(hash); ok { - for _, t := range ts.([]*abi.Type) { - if haveIdenticalUnderlyingType(&ft.Type, t, true) { - return toRType(t) - } - } - } - - // Not in cache, lock and retry. - funcLookupCache.Lock() - defer funcLookupCache.Unlock() - if ts, ok := funcLookupCache.m.Load(hash); ok { - for _, t := range ts.([]*abi.Type) { - if haveIdenticalUnderlyingType(&ft.Type, t, true) { - return toRType(t) - } - } - } - - addToCache := func(tt *abi.Type) Type { - var rts []*abi.Type - if rti, ok := funcLookupCache.m.Load(hash); ok { - rts = rti.([]*abi.Type) - } - funcLookupCache.m.Store(hash, append(rts, tt)) - return toType(tt) - } - - // Look in known types for the same string representation. - str := funcStr(ft) - for _, tt := range typesByString(str) { - if haveIdenticalUnderlyingType(&ft.Type, tt, true) { - return addToCache(tt) - } - } - - // Populate the remaining fields of ft and store in cache. - ft.Str = resolveReflectName(newName(str, "", false, false)) - ft.PtrToThis = 0 - return addToCache(&ft.Type) -} -func stringFor(t *abi.Type) string { - return toRType(t).String() -} - -// funcStr builds a string representation of a funcType. -func funcStr(ft *funcType) string { - repr := make([]byte, 0, 64) - repr = append(repr, "func("...) - for i, t := range ft.InSlice() { - if i > 0 { - repr = append(repr, ", "...) - } - if ft.IsVariadic() && i == int(ft.InCount)-1 { - repr = append(repr, "..."...) - repr = append(repr, stringFor((*sliceType)(unsafe.Pointer(t)).Elem)...) - } else { - repr = append(repr, stringFor(t)...) - } - } - repr = append(repr, ')') - out := ft.OutSlice() - if len(out) == 1 { - repr = append(repr, ' ') - } else if len(out) > 1 { - repr = append(repr, " ("...) - } - for i, t := range out { - if i > 0 { - repr = append(repr, ", "...) - } - repr = append(repr, stringFor(t)...) - } - if len(out) > 1 { - repr = append(repr, ')') - } - return string(repr) -} - -// isReflexive reports whether the == operation on the type is reflexive. -// That is, x == x for all values x of type t. -func isReflexive(t *abi.Type) bool { - switch Kind(t.Kind()) { - case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, String, UnsafePointer: - return true - case Float32, Float64, Complex64, Complex128, Interface: - return false - case Array: - tt := (*arrayType)(unsafe.Pointer(t)) - return isReflexive(tt.Elem) - case Struct: - tt := (*structType)(unsafe.Pointer(t)) - for _, f := range tt.Fields { - if !isReflexive(f.Typ) { - return false - } - } - return true - default: - // Func, Map, Slice, Invalid - panic("isReflexive called on non-key type " + stringFor(t)) - } -} - -// needKeyUpdate reports whether map overwrites require the key to be copied. -func needKeyUpdate(t *abi.Type) bool { - switch Kind(t.Kind()) { - case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, UnsafePointer: - return false - case Float32, Float64, Complex64, Complex128, Interface, String: - // Float keys can be updated from +0 to -0. - // String keys can be updated to use a smaller backing store. - // Interfaces might have floats or strings in them. - return true - case Array: - tt := (*arrayType)(unsafe.Pointer(t)) - return needKeyUpdate(tt.Elem) - case Struct: - tt := (*structType)(unsafe.Pointer(t)) - for _, f := range tt.Fields { - if needKeyUpdate(f.Typ) { - return true - } - } - return false - default: - // Func, Map, Slice, Invalid - panic("needKeyUpdate called on non-key type " + stringFor(t)) - } -} - -// hashMightPanic reports whether the hash of a map key of type t might panic. -func hashMightPanic(t *abi.Type) bool { - switch Kind(t.Kind()) { - case Interface: - return true - case Array: - tt := (*arrayType)(unsafe.Pointer(t)) - return hashMightPanic(tt.Elem) - case Struct: - tt := (*structType)(unsafe.Pointer(t)) - for _, f := range tt.Fields { - if hashMightPanic(f.Typ) { - return true - } - } - return false - default: - return false - } -} - -// Make sure these routines stay in sync with ../runtime/map.go! -// These types exist only for GC, so we only fill out GC relevant info. -// Currently, that's just size and the GC program. We also fill in string -// for possible debugging use. -const ( - bucketSize uintptr = abi.MapBucketCount - maxKeySize uintptr = abi.MapMaxKeyBytes - maxValSize uintptr = abi.MapMaxElemBytes -) - -func bucketOf(ktyp, etyp *abi.Type) *abi.Type { - if ktyp.Size_ > maxKeySize { - ktyp = ptrTo(ktyp) - } - if etyp.Size_ > maxValSize { - etyp = ptrTo(etyp) - } - - // Prepare GC data if any. - // A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+ptrSize bytes, - // or 2064 bytes, or 258 pointer-size words, or 33 bytes of pointer bitmap. - // Note that since the key and value are known to be <= 128 bytes, - // they're guaranteed to have bitmaps instead of GC programs. - var gcdata *byte - var ptrdata uintptr - - size := bucketSize*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize - if size&uintptr(ktyp.Align_-1) != 0 || size&uintptr(etyp.Align_-1) != 0 { - panic("reflect: bad size computation in MapOf") - } - - if ktyp.PtrBytes != 0 || etyp.PtrBytes != 0 { - nptr := (bucketSize*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize) / goarch.PtrSize - n := (nptr + 7) / 8 - - // Runtime needs pointer masks to be a multiple of uintptr in size. - n = (n + goarch.PtrSize - 1) &^ (goarch.PtrSize - 1) - mask := make([]byte, n) - base := bucketSize / goarch.PtrSize - - if ktyp.PtrBytes != 0 { - emitGCMask(mask, base, ktyp, bucketSize) - } - base += bucketSize * ktyp.Size_ / goarch.PtrSize - - if etyp.PtrBytes != 0 { - emitGCMask(mask, base, etyp, bucketSize) - } - base += bucketSize * etyp.Size_ / goarch.PtrSize - - word := base - mask[word/8] |= 1 << (word % 8) - gcdata = &mask[0] - ptrdata = (word + 1) * goarch.PtrSize - - // overflow word must be last - if ptrdata != size { - panic("reflect: bad layout computation in MapOf") - } - } - - b := &abi.Type{ - Align_: goarch.PtrSize, - Size_: size, - Kind_: uint8(Struct), - PtrBytes: ptrdata, - GCData: gcdata, - } - s := "bucket(" + stringFor(ktyp) + "," + stringFor(etyp) + ")" - b.Str = resolveReflectName(newName(s, "", false, false)) - return b -} - -func (t *rtype) gcSlice(begin, end uintptr) []byte { - return (*[1 << 30]byte)(unsafe.Pointer(t.t.GCData))[begin:end:end] -} - -// emitGCMask writes the GC mask for [n]typ into out, starting at bit -// offset base. -func emitGCMask(out []byte, base uintptr, typ *abi.Type, n uintptr) { - if typ.Kind_&kindGCProg != 0 { - panic("reflect: unexpected GC program") - } - ptrs := typ.PtrBytes / goarch.PtrSize - words := typ.Size_ / goarch.PtrSize - mask := typ.GcSlice(0, (ptrs+7)/8) - for j := uintptr(0); j < ptrs; j++ { - if (mask[j/8]>>(j%8))&1 != 0 { - for i := uintptr(0); i < n; i++ { - k := base + i*words + j - out[k/8] |= 1 << (k % 8) - } - } - } -} - -// appendGCProg appends the GC program for the first ptrdata bytes of -// typ to dst and returns the extended slice. -func appendGCProg(dst []byte, typ *abi.Type) []byte { - if typ.Kind_&kindGCProg != 0 { - // Element has GC program; emit one element. - n := uintptr(*(*uint32)(unsafe.Pointer(typ.GCData))) - prog := typ.GcSlice(4, 4+n-1) - return append(dst, prog...) - } - - // Element is small with pointer mask; use as literal bits. - ptrs := typ.PtrBytes / goarch.PtrSize - mask := typ.GcSlice(0, (ptrs+7)/8) - - // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). - for ; ptrs > 120; ptrs -= 120 { - dst = append(dst, 120) - dst = append(dst, mask[:15]...) - mask = mask[15:] - } - - dst = append(dst, byte(ptrs)) - dst = append(dst, mask...) - return dst -} - -// SliceOf returns the slice type with element type t. -// For example, if t represents int, SliceOf(t) represents []int. -func SliceOf(t Type) Type { - typ := t.common() - - // Look in cache. - ckey := cacheKey{Slice, typ, nil, 0} - if slice, ok := lookupCache.Load(ckey); ok { - return slice.(Type) - } - - // Look in known types. - s := "[]" + stringFor(typ) - for _, tt := range typesByString(s) { - slice := (*sliceType)(unsafe.Pointer(tt)) - if slice.Elem == typ { - ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt)) - return ti.(Type) - } - } - - // Make a slice type. - var islice any = ([]unsafe.Pointer)(nil) - prototype := *(**sliceType)(unsafe.Pointer(&islice)) - slice := *prototype - slice.TFlag = 0 - slice.Str = resolveReflectName(newName(s, "", false, false)) - slice.Hash = fnv1(typ.Hash, '[') - slice.Elem = typ - slice.PtrToThis = 0 - - ti, _ := lookupCache.LoadOrStore(ckey, toRType(&slice.Type)) - return ti.(Type) -} - -// The structLookupCache caches StructOf lookups. -// StructOf does not share the common lookupCache since we need to pin -// the memory associated with *structTypeFixedN. -var structLookupCache struct { - sync.Mutex // Guards stores (but not loads) on m. - - // m is a map[uint32][]Type keyed by the hash calculated in StructOf. - // Elements in m are append-only and thus safe for concurrent reading. - m sync.Map -} - -type structTypeUncommon struct { - structType - u uncommonType -} - -// isLetter reports whether a given 'rune' is classified as a Letter. -func isLetter(ch rune) bool { - return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch) -} - -// isValidFieldName checks if a string is a valid (struct) field name or not. -// -// According to the language spec, a field name should be an identifier. -// -// identifier = letter { letter | unicode_digit } . -// letter = unicode_letter | "_" . -func isValidFieldName(fieldName string) bool { - for i, c := range fieldName { - if i == 0 && !isLetter(c) { - return false - } - - if !(isLetter(c) || unicode.IsDigit(c)) { - return false - } - } - - return len(fieldName) > 0 -} - -// StructOf returns the struct type containing fields. -// The Offset and Index fields are ignored and computed as they would be -// by the compiler. -// -// StructOf currently does not support promoted methods of embedded fields -// and panics if passed unexported StructFields. -func StructOf(fields []StructField) Type { - var ( - hash = fnv1(0, []byte("struct {")...) - size uintptr - typalign uint8 - comparable = true - methods []abi.Method - - fs = make([]structField, len(fields)) - repr = make([]byte, 0, 64) - fset = map[string]struct{}{} // fields' names - - hasGCProg = false // records whether a struct-field type has a GCProg - ) - - lastzero := uintptr(0) - repr = append(repr, "struct {"...) - pkgpath := "" - for i, field := range fields { - if field.Name == "" { - panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name") - } - if !isValidFieldName(field.Name) { - panic("reflect.StructOf: field " + strconv.Itoa(i) + " has invalid name") - } - if field.Type == nil { - panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type") - } - f, fpkgpath := runtimeStructField(field) - ft := f.Typ - if ft.Kind_&kindGCProg != 0 { - hasGCProg = true - } - if fpkgpath != "" { - if pkgpath == "" { - pkgpath = fpkgpath - } else if pkgpath != fpkgpath { - panic("reflect.Struct: fields with different PkgPath " + pkgpath + " and " + fpkgpath) - } - } - - // Update string and hash - name := f.Name.Name() - hash = fnv1(hash, []byte(name)...) - repr = append(repr, (" " + name)...) - if f.Embedded() { - // Embedded field - if f.Typ.Kind() == abi.Pointer { - // Embedded ** and *interface{} are illegal - elem := ft.Elem() - if k := elem.Kind(); k == abi.Pointer || k == abi.Interface { - panic("reflect.StructOf: illegal embedded field type " + stringFor(ft)) - } - } - - switch Kind(f.Typ.Kind()) { - case Interface: - ift := (*interfaceType)(unsafe.Pointer(ft)) - for _, m := range ift.Methods { - if pkgPath(ift.nameOff(m.Name)) != "" { - // TODO(sbinet). Issue 15924. - panic("reflect: embedded interface with unexported method(s) not implemented") - } - - fnStub := resolveReflectText(unsafe.Pointer(abi.FuncPCABIInternal(embeddedIfaceMethStub))) - methods = append(methods, abi.Method{ - Name: resolveReflectName(ift.nameOff(m.Name)), - Mtyp: resolveReflectType(ift.typeOff(m.Typ)), - Ifn: fnStub, - Tfn: fnStub, - }) - } - case Pointer: - ptr := (*ptrType)(unsafe.Pointer(ft)) - if unt := ptr.Uncommon(); unt != nil { - if i > 0 && unt.Mcount > 0 { - // Issue 15924. - panic("reflect: embedded type with methods not implemented if type is not first field") - } - if len(fields) > 1 { - panic("reflect: embedded type with methods not implemented if there is more than one field") - } - for _, m := range unt.Methods() { - mname := nameOffFor(ft, m.Name) - if pkgPath(mname) != "" { - // TODO(sbinet). - // Issue 15924. - panic("reflect: embedded interface with unexported method(s) not implemented") - } - methods = append(methods, abi.Method{ - Name: resolveReflectName(mname), - Mtyp: resolveReflectType(typeOffFor(ft, m.Mtyp)), - Ifn: resolveReflectText(textOffFor(ft, m.Ifn)), - Tfn: resolveReflectText(textOffFor(ft, m.Tfn)), - }) - } - } - if unt := ptr.Elem.Uncommon(); unt != nil { - for _, m := range unt.Methods() { - mname := nameOffFor(ft, m.Name) - if pkgPath(mname) != "" { - // TODO(sbinet) - // Issue 15924. - panic("reflect: embedded interface with unexported method(s) not implemented") - } - methods = append(methods, abi.Method{ - Name: resolveReflectName(mname), - Mtyp: resolveReflectType(typeOffFor(ptr.Elem, m.Mtyp)), - Ifn: resolveReflectText(textOffFor(ptr.Elem, m.Ifn)), - Tfn: resolveReflectText(textOffFor(ptr.Elem, m.Tfn)), - }) - } - } - default: - if unt := ft.Uncommon(); unt != nil { - if i > 0 && unt.Mcount > 0 { - // Issue 15924. - panic("reflect: embedded type with methods not implemented if type is not first field") - } - if len(fields) > 1 && ft.Kind_&kindDirectIface != 0 { - panic("reflect: embedded type with methods not implemented for non-pointer type") - } - for _, m := range unt.Methods() { - mname := nameOffFor(ft, m.Name) - if pkgPath(mname) != "" { - // TODO(sbinet) - // Issue 15924. - panic("reflect: embedded interface with unexported method(s) not implemented") - } - methods = append(methods, abi.Method{ - Name: resolveReflectName(mname), - Mtyp: resolveReflectType(typeOffFor(ft, m.Mtyp)), - Ifn: resolveReflectText(textOffFor(ft, m.Ifn)), - Tfn: resolveReflectText(textOffFor(ft, m.Tfn)), - }) - - } - } - } - } - if _, dup := fset[name]; dup && name != "_" { - panic("reflect.StructOf: duplicate field " + name) - } - fset[name] = struct{}{} - - hash = fnv1(hash, byte(ft.Hash>>24), byte(ft.Hash>>16), byte(ft.Hash>>8), byte(ft.Hash)) - - repr = append(repr, (" " + stringFor(ft))...) - if f.Name.HasTag() { - hash = fnv1(hash, []byte(f.Name.Tag())...) - repr = append(repr, (" " + strconv.Quote(f.Name.Tag()))...) - } - if i < len(fields)-1 { - repr = append(repr, ';') - } - - comparable = comparable && (ft.Equal != nil) - - offset := align(size, uintptr(ft.Align_)) - if offset < size { - panic("reflect.StructOf: struct size would exceed virtual address space") - } - if ft.Align_ > typalign { - typalign = ft.Align_ - } - size = offset + ft.Size_ - if size < offset { - panic("reflect.StructOf: struct size would exceed virtual address space") - } - f.Offset = offset - - if ft.Size_ == 0 { - lastzero = size - } - - fs[i] = f - } - - if size > 0 && lastzero == size { - // This is a non-zero sized struct that ends in a - // zero-sized field. We add an extra byte of padding, - // to ensure that taking the address of the final - // zero-sized field can't manufacture a pointer to the - // next object in the heap. See issue 9401. - size++ - if size == 0 { - panic("reflect.StructOf: struct size would exceed virtual address space") - } - } - - var typ *structType - var ut *uncommonType - - if len(methods) == 0 { - t := new(structTypeUncommon) - typ = &t.structType - ut = &t.u - } else { - // A *rtype representing a struct is followed directly in memory by an - // array of method objects representing the methods attached to the - // struct. To get the same layout for a run time generated type, we - // need an array directly following the uncommonType memory. - // A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN. - tt := New(StructOf([]StructField{ - {Name: "S", Type: TypeOf(structType{})}, - {Name: "U", Type: TypeOf(uncommonType{})}, - {Name: "M", Type: ArrayOf(len(methods), TypeOf(methods[0]))}, - })) - - typ = (*structType)(tt.Elem().Field(0).Addr().UnsafePointer()) - ut = (*uncommonType)(tt.Elem().Field(1).Addr().UnsafePointer()) - - copy(tt.Elem().Field(2).Slice(0, len(methods)).Interface().([]abi.Method), methods) - } - // TODO(sbinet): Once we allow embedding multiple types, - // methods will need to be sorted like the compiler does. - // TODO(sbinet): Once we allow non-exported methods, we will - // need to compute xcount as the number of exported methods. - ut.Mcount = uint16(len(methods)) - ut.Xcount = ut.Mcount - ut.Moff = uint32(unsafe.Sizeof(uncommonType{})) - - if len(fs) > 0 { - repr = append(repr, ' ') - } - repr = append(repr, '}') - hash = fnv1(hash, '}') - str := string(repr) - - // Round the size up to be a multiple of the alignment. - s := align(size, uintptr(typalign)) - if s < size { - panic("reflect.StructOf: struct size would exceed virtual address space") - } - size = s - - // Make the struct type. - var istruct any = struct{}{} - prototype := *(**structType)(unsafe.Pointer(&istruct)) - *typ = *prototype - typ.Fields = fs - if pkgpath != "" { - typ.PkgPath = newName(pkgpath, "", false, false) - } - - // Look in cache. - if ts, ok := structLookupCache.m.Load(hash); ok { - for _, st := range ts.([]Type) { - t := st.common() - if haveIdenticalUnderlyingType(&typ.Type, t, true) { - return toType(t) - } - } - } - - // Not in cache, lock and retry. - structLookupCache.Lock() - defer structLookupCache.Unlock() - if ts, ok := structLookupCache.m.Load(hash); ok { - for _, st := range ts.([]Type) { - t := st.common() - if haveIdenticalUnderlyingType(&typ.Type, t, true) { - return toType(t) - } - } - } - - addToCache := func(t Type) Type { - var ts []Type - if ti, ok := structLookupCache.m.Load(hash); ok { - ts = ti.([]Type) - } - structLookupCache.m.Store(hash, append(ts, t)) - return t - } - - // Look in known types. - for _, t := range typesByString(str) { - if haveIdenticalUnderlyingType(&typ.Type, t, true) { - // even if 't' wasn't a structType with methods, we should be ok - // as the 'u uncommonType' field won't be accessed except when - // tflag&abi.TFlagUncommon is set. - return addToCache(toType(t)) - } - } - - typ.Str = resolveReflectName(newName(str, "", false, false)) - typ.TFlag = 0 // TODO: set tflagRegularMemory - typ.Hash = hash - typ.Size_ = size - typ.PtrBytes = typeptrdata(&typ.Type) - typ.Align_ = typalign - typ.FieldAlign_ = typalign - typ.PtrToThis = 0 - if len(methods) > 0 { - typ.TFlag |= abi.TFlagUncommon - } - - if hasGCProg { - lastPtrField := 0 - for i, ft := range fs { - if ft.Typ.Pointers() { - lastPtrField = i - } - } - prog := []byte{0, 0, 0, 0} // will be length of prog - var off uintptr - for i, ft := range fs { - if i > lastPtrField { - // gcprog should not include anything for any field after - // the last field that contains pointer data - break - } - if !ft.Typ.Pointers() { - // Ignore pointerless fields. - continue - } - // Pad to start of this field with zeros. - if ft.Offset > off { - n := (ft.Offset - off) / goarch.PtrSize - prog = append(prog, 0x01, 0x00) // emit a 0 bit - if n > 1 { - prog = append(prog, 0x81) // repeat previous bit - prog = appendVarint(prog, n-1) // n-1 times - } - off = ft.Offset - } - - prog = appendGCProg(prog, ft.Typ) - off += ft.Typ.PtrBytes - } - prog = append(prog, 0) - *(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4) - typ.Kind_ |= kindGCProg - typ.GCData = &prog[0] - } else { - typ.Kind_ &^= kindGCProg - bv := new(bitVector) - addTypeBits(bv, 0, &typ.Type) - if len(bv.data) > 0 { - typ.GCData = &bv.data[0] - } - } - typ.Equal = nil - if comparable { - typ.Equal = func(p, q unsafe.Pointer) bool { - for _, ft := range typ.Fields { - pi := add(p, ft.Offset, "&x.field safe") - qi := add(q, ft.Offset, "&x.field safe") - if !ft.Typ.Equal(pi, qi) { - return false - } - } - return true - } - } - - switch { - case len(fs) == 1 && !ifaceIndir(fs[0].Typ): - // structs of 1 direct iface type can be direct - typ.Kind_ |= kindDirectIface - default: - typ.Kind_ &^= kindDirectIface - } - - return addToCache(toType(&typ.Type)) -} - -func embeddedIfaceMethStub() { - panic("reflect: StructOf does not support methods of embedded interfaces") -} - -// runtimeStructField takes a StructField value passed to StructOf and -// returns both the corresponding internal representation, of type -// structField, and the pkgpath value to use for this field. -func runtimeStructField(field StructField) (structField, string) { - if field.Anonymous && field.PkgPath != "" { - panic("reflect.StructOf: field \"" + field.Name + "\" is anonymous but has PkgPath set") - } - - if field.IsExported() { - // Best-effort check for misuse. - // Since this field will be treated as exported, not much harm done if Unicode lowercase slips through. - c := field.Name[0] - if 'a' <= c && c <= 'z' || c == '_' { - panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath") - } - } - - resolveReflectType(field.Type.common()) // install in runtime - f := structField{ - Name: newName(field.Name, string(field.Tag), field.IsExported(), field.Anonymous), - Typ: field.Type.common(), - Offset: 0, - } - return f, field.PkgPath -} - -// typeptrdata returns the length in bytes of the prefix of t -// containing pointer data. Anything after this offset is scalar data. -// keep in sync with ../cmd/compile/internal/reflectdata/reflect.go -func typeptrdata(t *abi.Type) uintptr { - switch t.Kind() { - case abi.Struct: - st := (*structType)(unsafe.Pointer(t)) - // find the last field that has pointers. - field := -1 - for i := range st.Fields { - ft := st.Fields[i].Typ - if ft.Pointers() { - field = i - } - } - if field == -1 { - return 0 - } - f := st.Fields[field] - return f.Offset + f.Typ.PtrBytes - - default: - panic("reflect.typeptrdata: unexpected type, " + stringFor(t)) - } -} - -// See cmd/compile/internal/reflectdata/reflect.go for derivation of constant. -const maxPtrmaskBytes = 2048 - -// ArrayOf returns the array type with the given length and element type. -// For example, if t represents int, ArrayOf(5, t) represents [5]int. -// -// If the resulting type would be larger than the available address space, -// ArrayOf panics. -func ArrayOf(length int, elem Type) Type { - if length < 0 { - panic("reflect: negative length passed to ArrayOf") - } - - typ := elem.common() - - // Look in cache. - ckey := cacheKey{Array, typ, nil, uintptr(length)} - if array, ok := lookupCache.Load(ckey); ok { - return array.(Type) - } - - // Look in known types. - s := "[" + strconv.Itoa(length) + "]" + stringFor(typ) - for _, tt := range typesByString(s) { - array := (*arrayType)(unsafe.Pointer(tt)) - if array.Elem == typ { - ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt)) - return ti.(Type) - } - } - - // Make an array type. - var iarray any = [1]unsafe.Pointer{} - prototype := *(**arrayType)(unsafe.Pointer(&iarray)) - array := *prototype - array.TFlag = typ.TFlag & abi.TFlagRegularMemory - array.Str = resolveReflectName(newName(s, "", false, false)) - array.Hash = fnv1(typ.Hash, '[') - for n := uint32(length); n > 0; n >>= 8 { - array.Hash = fnv1(array.Hash, byte(n)) - } - array.Hash = fnv1(array.Hash, ']') - array.Elem = typ - array.PtrToThis = 0 - if typ.Size_ > 0 { - max := ^uintptr(0) / typ.Size_ - if uintptr(length) > max { - panic("reflect.ArrayOf: array size would exceed virtual address space") - } - } - array.Size_ = typ.Size_ * uintptr(length) - if length > 0 && typ.PtrBytes != 0 { - array.PtrBytes = typ.Size_*uintptr(length-1) + typ.PtrBytes - } - array.Align_ = typ.Align_ - array.FieldAlign_ = typ.FieldAlign_ - array.Len = uintptr(length) - array.Slice = &(SliceOf(elem).(*rtype).t) - - switch { - case typ.PtrBytes == 0 || array.Size_ == 0: - // No pointers. - array.GCData = nil - array.PtrBytes = 0 - - case length == 1: - // In memory, 1-element array looks just like the element. - array.Kind_ |= typ.Kind_ & kindGCProg - array.GCData = typ.GCData - array.PtrBytes = typ.PtrBytes - - case typ.Kind_&kindGCProg == 0 && array.Size_ <= maxPtrmaskBytes*8*goarch.PtrSize: - // Element is small with pointer mask; array is still small. - // Create direct pointer mask by turning each 1 bit in elem - // into length 1 bits in larger mask. - n := (array.PtrBytes/goarch.PtrSize + 7) / 8 - // Runtime needs pointer masks to be a multiple of uintptr in size. - n = (n + goarch.PtrSize - 1) &^ (goarch.PtrSize - 1) - mask := make([]byte, n) - emitGCMask(mask, 0, typ, array.Len) - array.GCData = &mask[0] - - default: - // Create program that emits one element - // and then repeats to make the array. - prog := []byte{0, 0, 0, 0} // will be length of prog - prog = appendGCProg(prog, typ) - // Pad from ptrdata to size. - elemPtrs := typ.PtrBytes / goarch.PtrSize - elemWords := typ.Size_ / goarch.PtrSize - if elemPtrs < elemWords { - // Emit literal 0 bit, then repeat as needed. - prog = append(prog, 0x01, 0x00) - if elemPtrs+1 < elemWords { - prog = append(prog, 0x81) - prog = appendVarint(prog, elemWords-elemPtrs-1) - } - } - // Repeat length-1 times. - if elemWords < 0x80 { - prog = append(prog, byte(elemWords|0x80)) - } else { - prog = append(prog, 0x80) - prog = appendVarint(prog, elemWords) - } - prog = appendVarint(prog, uintptr(length)-1) - prog = append(prog, 0) - *(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4) - array.Kind_ |= kindGCProg - array.GCData = &prog[0] - array.PtrBytes = array.Size_ // overestimate but ok; must match program - } - - etyp := typ - esize := etyp.Size() - - array.Equal = nil - if eequal := etyp.Equal; eequal != nil { - array.Equal = func(p, q unsafe.Pointer) bool { - for i := 0; i < length; i++ { - pi := arrayAt(p, i, esize, "i < length") - qi := arrayAt(q, i, esize, "i < length") - if !eequal(pi, qi) { - return false - } - - } - return true - } - } - - switch { - case length == 1 && !ifaceIndir(typ): - // array of 1 direct iface type can be direct - array.Kind_ |= kindDirectIface - default: - array.Kind_ &^= kindDirectIface - } - - ti, _ := lookupCache.LoadOrStore(ckey, toRType(&array.Type)) - return ti.(Type) -} - -func appendVarint(x []byte, v uintptr) []byte { - for ; v >= 0x80; v >>= 7 { - x = append(x, byte(v|0x80)) - } - x = append(x, byte(v)) - return x -} - -// toType converts from a *rtype to a Type that can be returned -// to the client of package reflect. In gc, the only concern is that -// a nil *rtype must be replaced by a nil Type, but in gccgo this -// function takes care of ensuring that multiple *rtype for the same -// type are coalesced into a single Type. -func toType(t *abi.Type) Type { - if t == nil { - return nil - } - return toRType(t) -} - -type layoutKey struct { - ftyp *funcType // function signature - rcvr *abi.Type // receiver type, or nil if none -} - -type layoutType struct { - t *abi.Type - framePool *sync.Pool - abid abiDesc -} - -var layoutCache sync.Map // map[layoutKey]layoutType - -// funcLayout computes a struct type representing the layout of the -// stack-assigned function arguments and return values for the function -// type t. -// If rcvr != nil, rcvr specifies the type of the receiver. -// The returned type exists only for GC, so we only fill out GC relevant info. -// Currently, that's just size and the GC program. We also fill in -// the name for possible debugging use. -func funcLayout(t *funcType, rcvr *abi.Type) (frametype *abi.Type, framePool *sync.Pool, abid abiDesc) { - if t.Kind() != abi.Func { - panic("reflect: funcLayout of non-func type " + stringFor(&t.Type)) - } - if rcvr != nil && rcvr.Kind() == abi.Interface { - panic("reflect: funcLayout with interface receiver " + stringFor(rcvr)) - } - k := layoutKey{t, rcvr} - if lti, ok := layoutCache.Load(k); ok { - lt := lti.(layoutType) - return lt.t, lt.framePool, lt.abid - } - - // Compute the ABI layout. - abid = newAbiDesc(t, rcvr) - - // build dummy rtype holding gc program - x := &abi.Type{ - Align_: goarch.PtrSize, - // Don't add spill space here; it's only necessary in - // reflectcall's frame, not in the allocated frame. - // TODO(mknyszek): Remove this comment when register - // spill space in the frame is no longer required. - Size_: align(abid.retOffset+abid.ret.stackBytes, goarch.PtrSize), - PtrBytes: uintptr(abid.stackPtrs.n) * goarch.PtrSize, - } - if abid.stackPtrs.n > 0 { - x.GCData = &abid.stackPtrs.data[0] - } - - var s string - if rcvr != nil { - s = "methodargs(" + stringFor(rcvr) + ")(" + stringFor(&t.Type) + ")" - } else { - s = "funcargs(" + stringFor(&t.Type) + ")" - } - x.Str = resolveReflectName(newName(s, "", false, false)) - - // cache result for future callers - framePool = &sync.Pool{New: func() any { - return unsafe_New(x) - }} - lti, _ := layoutCache.LoadOrStore(k, layoutType{ - t: x, - framePool: framePool, - abid: abid, - }) - lt := lti.(layoutType) - return lt.t, lt.framePool, lt.abid -} - -// ifaceIndir reports whether t is stored indirectly in an interface value. -func ifaceIndir(t *abi.Type) bool { - return t.Kind_&kindDirectIface == 0 -} - -// Note: this type must agree with runtime.bitvector. -type bitVector struct { - n uint32 // number of bits - data []byte -} - -// append a bit to the bitmap. -func (bv *bitVector) append(bit uint8) { - if bv.n%(8*goarch.PtrSize) == 0 { - // Runtime needs pointer masks to be a multiple of uintptr in size. - // Since reflect passes bv.data directly to the runtime as a pointer mask, - // we append a full uintptr of zeros at a time. - for i := 0; i < goarch.PtrSize; i++ { - bv.data = append(bv.data, 0) - } - } - bv.data[bv.n/8] |= bit << (bv.n % 8) - bv.n++ -} - -func addTypeBits(bv *bitVector, offset uintptr, t *abi.Type) { - if t.PtrBytes == 0 { - return - } - - switch Kind(t.Kind_ & kindMask) { - case Chan, Func, Map, Pointer, Slice, String, UnsafePointer: - // 1 pointer at start of representation - for bv.n < uint32(offset/uintptr(goarch.PtrSize)) { - bv.append(0) - } - bv.append(1) - - case Interface: - // 2 pointers - for bv.n < uint32(offset/uintptr(goarch.PtrSize)) { - bv.append(0) - } - bv.append(1) - bv.append(1) - - case Array: - // repeat inner type - tt := (*arrayType)(unsafe.Pointer(t)) - for i := 0; i < int(tt.Len); i++ { - addTypeBits(bv, offset+uintptr(i)*tt.Elem.Size_, tt.Elem) - } - - case Struct: - // apply fields - tt := (*structType)(unsafe.Pointer(t)) - for i := range tt.Fields { - f := &tt.Fields[i] - addTypeBits(bv, offset+f.Offset, f.Typ) - } - } -} - -// TypeFor returns the [Type] that represents the type argument T. -func TypeFor[T any]() Type { - return TypeOf((*T)(nil)).Elem() -} diff --git a/contrib/go/_std_1.22/src/reflect/value.go b/contrib/go/_std_1.22/src/reflect/value.go deleted file mode 100644 index 06f22f742813..000000000000 --- a/contrib/go/_std_1.22/src/reflect/value.go +++ /dev/null @@ -1,4011 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package reflect - -import ( - "errors" - "internal/abi" - "internal/goarch" - "internal/itoa" - "internal/unsafeheader" - "math" - "runtime" - "unsafe" -) - -// Value is the reflection interface to a Go value. -// -// Not all methods apply to all kinds of values. Restrictions, -// if any, are noted in the documentation for each method. -// Use the Kind method to find out the kind of value before -// calling kind-specific methods. Calling a method -// inappropriate to the kind of type causes a run time panic. -// -// The zero Value represents no value. -// Its IsValid method returns false, its Kind method returns Invalid, -// its String method returns "", and all other methods panic. -// Most functions and methods never return an invalid value. -// If one does, its documentation states the conditions explicitly. -// -// A Value can be used concurrently by multiple goroutines provided that -// the underlying Go value can be used concurrently for the equivalent -// direct operations. -// -// To compare two Values, compare the results of the Interface method. -// Using == on two Values does not compare the underlying values -// they represent. -type Value struct { - // typ_ holds the type of the value represented by a Value. - // Access using the typ method to avoid escape of v. - typ_ *abi.Type - - // Pointer-valued data or, if flagIndir is set, pointer to data. - // Valid when either flagIndir is set or typ.pointers() is true. - ptr unsafe.Pointer - - // flag holds metadata about the value. - // - // The lowest five bits give the Kind of the value, mirroring typ.Kind(). - // - // The next set of bits are flag bits: - // - flagStickyRO: obtained via unexported not embedded field, so read-only - // - flagEmbedRO: obtained via unexported embedded field, so read-only - // - flagIndir: val holds a pointer to the data - // - flagAddr: v.CanAddr is true (implies flagIndir and ptr is non-nil) - // - flagMethod: v is a method value. - // If ifaceIndir(typ), code can assume that flagIndir is set. - // - // The remaining 22+ bits give a method number for method values. - // If flag.kind() != Func, code can assume that flagMethod is unset. - flag - - // A method value represents a curried method invocation - // like r.Read for some receiver r. The typ+val+flag bits describe - // the receiver r, but the flag's Kind bits say Func (methods are - // functions), and the top bits of the flag give the method number - // in r's type's method table. -} - -type flag uintptr - -const ( - flagKindWidth = 5 // there are 27 kinds - flagKindMask flag = 1< len(prefix) && name[:len(prefix)] == prefix { - methodName := name[len(prefix):] - if len(methodName) > 0 && 'A' <= methodName[0] && methodName[0] <= 'Z' { - return name - } - } - } - return "unknown method" -} - -// emptyInterface is the header for an interface{} value. -type emptyInterface struct { - typ *abi.Type - word unsafe.Pointer -} - -// nonEmptyInterface is the header for an interface value with methods. -type nonEmptyInterface struct { - // see ../runtime/iface.go:/Itab - itab *struct { - ityp *abi.Type // static interface type - typ *abi.Type // dynamic concrete type - hash uint32 // copy of typ.hash - _ [4]byte - fun [100000]unsafe.Pointer // method table - } - word unsafe.Pointer -} - -// mustBe panics if f's kind is not expected. -// Making this a method on flag instead of on Value -// (and embedding flag in Value) means that we can write -// the very clear v.mustBe(Bool) and have it compile into -// v.flag.mustBe(Bool), which will only bother to copy the -// single important word for the receiver. -func (f flag) mustBe(expected Kind) { - // TODO(mvdan): use f.kind() again once mid-stack inlining gets better - if Kind(f&flagKindMask) != expected { - panic(&ValueError{valueMethodName(), f.kind()}) - } -} - -// mustBeExported panics if f records that the value was obtained using -// an unexported field. -func (f flag) mustBeExported() { - if f == 0 || f&flagRO != 0 { - f.mustBeExportedSlow() - } -} - -func (f flag) mustBeExportedSlow() { - if f == 0 { - panic(&ValueError{valueMethodName(), Invalid}) - } - if f&flagRO != 0 { - panic("reflect: " + valueMethodName() + " using value obtained using unexported field") - } -} - -// mustBeAssignable panics if f records that the value is not assignable, -// which is to say that either it was obtained using an unexported field -// or it is not addressable. -func (f flag) mustBeAssignable() { - if f&flagRO != 0 || f&flagAddr == 0 { - f.mustBeAssignableSlow() - } -} - -func (f flag) mustBeAssignableSlow() { - if f == 0 { - panic(&ValueError{valueMethodName(), Invalid}) - } - // Assignable if addressable and not read-only. - if f&flagRO != 0 { - panic("reflect: " + valueMethodName() + " using value obtained using unexported field") - } - if f&flagAddr == 0 { - panic("reflect: " + valueMethodName() + " using unaddressable value") - } -} - -// Addr returns a pointer value representing the address of v. -// It panics if [Value.CanAddr] returns false. -// Addr is typically used to obtain a pointer to a struct field -// or slice element in order to call a method that requires a -// pointer receiver. -func (v Value) Addr() Value { - if v.flag&flagAddr == 0 { - panic("reflect.Value.Addr of unaddressable value") - } - // Preserve flagRO instead of using v.flag.ro() so that - // v.Addr().Elem() is equivalent to v (#32772) - fl := v.flag & flagRO - return Value{ptrTo(v.typ()), v.ptr, fl | flag(Pointer)} -} - -// Bool returns v's underlying value. -// It panics if v's kind is not [Bool]. -func (v Value) Bool() bool { - // panicNotBool is split out to keep Bool inlineable. - if v.kind() != Bool { - v.panicNotBool() - } - return *(*bool)(v.ptr) -} - -func (v Value) panicNotBool() { - v.mustBe(Bool) -} - -var bytesType = rtypeOf(([]byte)(nil)) - -// Bytes returns v's underlying value. -// It panics if v's underlying value is not a slice of bytes or -// an addressable array of bytes. -func (v Value) Bytes() []byte { - // bytesSlow is split out to keep Bytes inlineable for unnamed []byte. - if v.typ_ == bytesType { // ok to use v.typ_ directly as comparison doesn't cause escape - return *(*[]byte)(v.ptr) - } - return v.bytesSlow() -} - -func (v Value) bytesSlow() []byte { - switch v.kind() { - case Slice: - if v.typ().Elem().Kind() != abi.Uint8 { - panic("reflect.Value.Bytes of non-byte slice") - } - // Slice is always bigger than a word; assume flagIndir. - return *(*[]byte)(v.ptr) - case Array: - if v.typ().Elem().Kind() != abi.Uint8 { - panic("reflect.Value.Bytes of non-byte array") - } - if !v.CanAddr() { - panic("reflect.Value.Bytes of unaddressable byte array") - } - p := (*byte)(v.ptr) - n := int((*arrayType)(unsafe.Pointer(v.typ())).Len) - return unsafe.Slice(p, n) - } - panic(&ValueError{"reflect.Value.Bytes", v.kind()}) -} - -// runes returns v's underlying value. -// It panics if v's underlying value is not a slice of runes (int32s). -func (v Value) runes() []rune { - v.mustBe(Slice) - if v.typ().Elem().Kind() != abi.Int32 { - panic("reflect.Value.Bytes of non-rune slice") - } - // Slice is always bigger than a word; assume flagIndir. - return *(*[]rune)(v.ptr) -} - -// CanAddr reports whether the value's address can be obtained with [Value.Addr]. -// Such values are called addressable. A value is addressable if it is -// an element of a slice, an element of an addressable array, -// a field of an addressable struct, or the result of dereferencing a pointer. -// If CanAddr returns false, calling [Value.Addr] will panic. -func (v Value) CanAddr() bool { - return v.flag&flagAddr != 0 -} - -// CanSet reports whether the value of v can be changed. -// A [Value] can be changed only if it is addressable and was not -// obtained by the use of unexported struct fields. -// If CanSet returns false, calling [Value.Set] or any type-specific -// setter (e.g., [Value.SetBool], [Value.SetInt]) will panic. -func (v Value) CanSet() bool { - return v.flag&(flagAddr|flagRO) == flagAddr -} - -// Call calls the function v with the input arguments in. -// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]). -// Call panics if v's Kind is not [Func]. -// It returns the output results as Values. -// As in Go, each input argument must be assignable to the -// type of the function's corresponding input parameter. -// If v is a variadic function, Call creates the variadic slice parameter -// itself, copying in the corresponding values. -func (v Value) Call(in []Value) []Value { - v.mustBe(Func) - v.mustBeExported() - return v.call("Call", in) -} - -// CallSlice calls the variadic function v with the input arguments in, -// assigning the slice in[len(in)-1] to v's final variadic argument. -// For example, if len(in) == 3, v.CallSlice(in) represents the Go call v(in[0], in[1], in[2]...). -// CallSlice panics if v's Kind is not [Func] or if v is not variadic. -// It returns the output results as Values. -// As in Go, each input argument must be assignable to the -// type of the function's corresponding input parameter. -func (v Value) CallSlice(in []Value) []Value { - v.mustBe(Func) - v.mustBeExported() - return v.call("CallSlice", in) -} - -var callGC bool // for testing; see TestCallMethodJump and TestCallArgLive - -const debugReflectCall = false - -func (v Value) call(op string, in []Value) []Value { - // Get function pointer, type. - t := (*funcType)(unsafe.Pointer(v.typ())) - var ( - fn unsafe.Pointer - rcvr Value - rcvrtype *abi.Type - ) - if v.flag&flagMethod != 0 { - rcvr = v - rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift) - } else if v.flag&flagIndir != 0 { - fn = *(*unsafe.Pointer)(v.ptr) - } else { - fn = v.ptr - } - - if fn == nil { - panic("reflect.Value.Call: call of nil function") - } - - isSlice := op == "CallSlice" - n := t.NumIn() - isVariadic := t.IsVariadic() - if isSlice { - if !isVariadic { - panic("reflect: CallSlice of non-variadic function") - } - if len(in) < n { - panic("reflect: CallSlice with too few input arguments") - } - if len(in) > n { - panic("reflect: CallSlice with too many input arguments") - } - } else { - if isVariadic { - n-- - } - if len(in) < n { - panic("reflect: Call with too few input arguments") - } - if !isVariadic && len(in) > n { - panic("reflect: Call with too many input arguments") - } - } - for _, x := range in { - if x.Kind() == Invalid { - panic("reflect: " + op + " using zero Value argument") - } - } - for i := 0; i < n; i++ { - if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(toRType(targ)) { - panic("reflect: " + op + " using " + xt.String() + " as type " + stringFor(targ)) - } - } - if !isSlice && isVariadic { - // prepare slice for remaining values - m := len(in) - n - slice := MakeSlice(toRType(t.In(n)), m, m) - elem := toRType(t.In(n)).Elem() // FIXME cast to slice type and Elem() - for i := 0; i < m; i++ { - x := in[n+i] - if xt := x.Type(); !xt.AssignableTo(elem) { - panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op) - } - slice.Index(i).Set(x) - } - origIn := in - in = make([]Value, n+1) - copy(in[:n], origIn) - in[n] = slice - } - - nin := len(in) - if nin != t.NumIn() { - panic("reflect.Value.Call: wrong argument count") - } - nout := t.NumOut() - - // Register argument space. - var regArgs abi.RegArgs - - // Compute frame type. - frametype, framePool, abid := funcLayout(t, rcvrtype) - - // Allocate a chunk of memory for frame if needed. - var stackArgs unsafe.Pointer - if frametype.Size() != 0 { - if nout == 0 { - stackArgs = framePool.Get().(unsafe.Pointer) - } else { - // Can't use pool if the function has return values. - // We will leak pointer to args in ret, so its lifetime is not scoped. - stackArgs = unsafe_New(frametype) - } - } - frameSize := frametype.Size() - - if debugReflectCall { - println("reflect.call", stringFor(&t.Type)) - abid.dump() - } - - // Copy inputs into args. - - // Handle receiver. - inStart := 0 - if rcvrtype != nil { - // Guaranteed to only be one word in size, - // so it will only take up exactly 1 abiStep (either - // in a register or on the stack). - switch st := abid.call.steps[0]; st.kind { - case abiStepStack: - storeRcvr(rcvr, stackArgs) - case abiStepPointer: - storeRcvr(rcvr, unsafe.Pointer(®Args.Ptrs[st.ireg])) - fallthrough - case abiStepIntReg: - storeRcvr(rcvr, unsafe.Pointer(®Args.Ints[st.ireg])) - case abiStepFloatReg: - storeRcvr(rcvr, unsafe.Pointer(®Args.Floats[st.freg])) - default: - panic("unknown ABI parameter kind") - } - inStart = 1 - } - - // Handle arguments. - for i, v := range in { - v.mustBeExported() - targ := toRType(t.In(i)) - // TODO(mknyszek): Figure out if it's possible to get some - // scratch space for this assignment check. Previously, it - // was possible to use space in the argument frame. - v = v.assignTo("reflect.Value.Call", &targ.t, nil) - stepsLoop: - for _, st := range abid.call.stepsForValue(i + inStart) { - switch st.kind { - case abiStepStack: - // Copy values to the "stack." - addr := add(stackArgs, st.stkOff, "precomputed stack arg offset") - if v.flag&flagIndir != 0 { - typedmemmove(&targ.t, addr, v.ptr) - } else { - *(*unsafe.Pointer)(addr) = v.ptr - } - // There's only one step for a stack-allocated value. - break stepsLoop - case abiStepIntReg, abiStepPointer: - // Copy values to "integer registers." - if v.flag&flagIndir != 0 { - offset := add(v.ptr, st.offset, "precomputed value offset") - if st.kind == abiStepPointer { - // Duplicate this pointer in the pointer area of the - // register space. Otherwise, there's the potential for - // this to be the last reference to v.ptr. - regArgs.Ptrs[st.ireg] = *(*unsafe.Pointer)(offset) - } - intToReg(®Args, st.ireg, st.size, offset) - } else { - if st.kind == abiStepPointer { - // See the comment in abiStepPointer case above. - regArgs.Ptrs[st.ireg] = v.ptr - } - regArgs.Ints[st.ireg] = uintptr(v.ptr) - } - case abiStepFloatReg: - // Copy values to "float registers." - if v.flag&flagIndir == 0 { - panic("attempted to copy pointer to FP register") - } - offset := add(v.ptr, st.offset, "precomputed value offset") - floatToReg(®Args, st.freg, st.size, offset) - default: - panic("unknown ABI part kind") - } - } - } - // TODO(mknyszek): Remove this when we no longer have - // caller reserved spill space. - frameSize = align(frameSize, goarch.PtrSize) - frameSize += abid.spill - - // Mark pointers in registers for the return path. - regArgs.ReturnIsPtr = abid.outRegPtrs - - if debugReflectCall { - regArgs.Dump() - } - - // For testing; see TestCallArgLive. - if callGC { - runtime.GC() - } - - // Call. - call(frametype, fn, stackArgs, uint32(frametype.Size()), uint32(abid.retOffset), uint32(frameSize), ®Args) - - // For testing; see TestCallMethodJump. - if callGC { - runtime.GC() - } - - var ret []Value - if nout == 0 { - if stackArgs != nil { - typedmemclr(frametype, stackArgs) - framePool.Put(stackArgs) - } - } else { - if stackArgs != nil { - // Zero the now unused input area of args, - // because the Values returned by this function contain pointers to the args object, - // and will thus keep the args object alive indefinitely. - typedmemclrpartial(frametype, stackArgs, 0, abid.retOffset) - } - - // Wrap Values around return values in args. - ret = make([]Value, nout) - for i := 0; i < nout; i++ { - tv := t.Out(i) - if tv.Size() == 0 { - // For zero-sized return value, args+off may point to the next object. - // In this case, return the zero value instead. - ret[i] = Zero(toRType(tv)) - continue - } - steps := abid.ret.stepsForValue(i) - if st := steps[0]; st.kind == abiStepStack { - // This value is on the stack. If part of a value is stack - // allocated, the entire value is according to the ABI. So - // just make an indirection into the allocated frame. - fl := flagIndir | flag(tv.Kind()) - ret[i] = Value{tv, add(stackArgs, st.stkOff, "tv.Size() != 0"), fl} - // Note: this does introduce false sharing between results - - // if any result is live, they are all live. - // (And the space for the args is live as well, but as we've - // cleared that space it isn't as big a deal.) - continue - } - - // Handle pointers passed in registers. - if !ifaceIndir(tv) { - // Pointer-valued data gets put directly - // into v.ptr. - if steps[0].kind != abiStepPointer { - print("kind=", steps[0].kind, ", type=", stringFor(tv), "\n") - panic("mismatch between ABI description and types") - } - ret[i] = Value{tv, regArgs.Ptrs[steps[0].ireg], flag(tv.Kind())} - continue - } - - // All that's left is values passed in registers that we need to - // create space for and copy values back into. - // - // TODO(mknyszek): We make a new allocation for each register-allocated - // value, but previously we could always point into the heap-allocated - // stack frame. This is a regression that could be fixed by adding - // additional space to the allocated stack frame and storing the - // register-allocated return values into the allocated stack frame and - // referring there in the resulting Value. - s := unsafe_New(tv) - for _, st := range steps { - switch st.kind { - case abiStepIntReg: - offset := add(s, st.offset, "precomputed value offset") - intFromReg(®Args, st.ireg, st.size, offset) - case abiStepPointer: - s := add(s, st.offset, "precomputed value offset") - *((*unsafe.Pointer)(s)) = regArgs.Ptrs[st.ireg] - case abiStepFloatReg: - offset := add(s, st.offset, "precomputed value offset") - floatFromReg(®Args, st.freg, st.size, offset) - case abiStepStack: - panic("register-based return value has stack component") - default: - panic("unknown ABI part kind") - } - } - ret[i] = Value{tv, s, flagIndir | flag(tv.Kind())} - } - } - - return ret -} - -// callReflect is the call implementation used by a function -// returned by MakeFunc. In many ways it is the opposite of the -// method Value.call above. The method above converts a call using Values -// into a call of a function with a concrete argument frame, while -// callReflect converts a call of a function with a concrete argument -// frame into a call using Values. -// It is in this file so that it can be next to the call method above. -// The remainder of the MakeFunc implementation is in makefunc.go. -// -// NOTE: This function must be marked as a "wrapper" in the generated code, -// so that the linker can make it work correctly for panic and recover. -// The gc compilers know to do that for the name "reflect.callReflect". -// -// ctxt is the "closure" generated by MakeFunc. -// frame is a pointer to the arguments to that closure on the stack. -// retValid points to a boolean which should be set when the results -// section of frame is set. -// -// regs contains the argument values passed in registers and will contain -// the values returned from ctxt.fn in registers. -func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool, regs *abi.RegArgs) { - if callGC { - // Call GC upon entry during testing. - // Getting our stack scanned here is the biggest hazard, because - // our caller (makeFuncStub) could have failed to place the last - // pointer to a value in regs' pointer space, in which case it - // won't be visible to the GC. - runtime.GC() - } - ftyp := ctxt.ftyp - f := ctxt.fn - - _, _, abid := funcLayout(ftyp, nil) - - // Copy arguments into Values. - ptr := frame - in := make([]Value, 0, int(ftyp.InCount)) - for i, typ := range ftyp.InSlice() { - if typ.Size() == 0 { - in = append(in, Zero(toRType(typ))) - continue - } - v := Value{typ, nil, flag(typ.Kind())} - steps := abid.call.stepsForValue(i) - if st := steps[0]; st.kind == abiStepStack { - if ifaceIndir(typ) { - // value cannot be inlined in interface data. - // Must make a copy, because f might keep a reference to it, - // and we cannot let f keep a reference to the stack frame - // after this function returns, not even a read-only reference. - v.ptr = unsafe_New(typ) - if typ.Size() > 0 { - typedmemmove(typ, v.ptr, add(ptr, st.stkOff, "typ.size > 0")) - } - v.flag |= flagIndir - } else { - v.ptr = *(*unsafe.Pointer)(add(ptr, st.stkOff, "1-ptr")) - } - } else { - if ifaceIndir(typ) { - // All that's left is values passed in registers that we need to - // create space for the values. - v.flag |= flagIndir - v.ptr = unsafe_New(typ) - for _, st := range steps { - switch st.kind { - case abiStepIntReg: - offset := add(v.ptr, st.offset, "precomputed value offset") - intFromReg(regs, st.ireg, st.size, offset) - case abiStepPointer: - s := add(v.ptr, st.offset, "precomputed value offset") - *((*unsafe.Pointer)(s)) = regs.Ptrs[st.ireg] - case abiStepFloatReg: - offset := add(v.ptr, st.offset, "precomputed value offset") - floatFromReg(regs, st.freg, st.size, offset) - case abiStepStack: - panic("register-based return value has stack component") - default: - panic("unknown ABI part kind") - } - } - } else { - // Pointer-valued data gets put directly - // into v.ptr. - if steps[0].kind != abiStepPointer { - print("kind=", steps[0].kind, ", type=", stringFor(typ), "\n") - panic("mismatch between ABI description and types") - } - v.ptr = regs.Ptrs[steps[0].ireg] - } - } - in = append(in, v) - } - - // Call underlying function. - out := f(in) - numOut := ftyp.NumOut() - if len(out) != numOut { - panic("reflect: wrong return count from function created by MakeFunc") - } - - // Copy results back into argument frame and register space. - if numOut > 0 { - for i, typ := range ftyp.OutSlice() { - v := out[i] - if v.typ() == nil { - panic("reflect: function created by MakeFunc using " + funcName(f) + - " returned zero Value") - } - if v.flag&flagRO != 0 { - panic("reflect: function created by MakeFunc using " + funcName(f) + - " returned value obtained from unexported field") - } - if typ.Size() == 0 { - continue - } - - // Convert v to type typ if v is assignable to a variable - // of type t in the language spec. - // See issue 28761. - // - // - // TODO(mknyszek): In the switch to the register ABI we lost - // the scratch space here for the register cases (and - // temporarily for all the cases). - // - // If/when this happens, take note of the following: - // - // We must clear the destination before calling assignTo, - // in case assignTo writes (with memory barriers) to the - // target location used as scratch space. See issue 39541. - v = v.assignTo("reflect.MakeFunc", typ, nil) - stepsLoop: - for _, st := range abid.ret.stepsForValue(i) { - switch st.kind { - case abiStepStack: - // Copy values to the "stack." - addr := add(ptr, st.stkOff, "precomputed stack arg offset") - // Do not use write barriers. The stack space used - // for this call is not adequately zeroed, and we - // are careful to keep the arguments alive until we - // return to makeFuncStub's caller. - if v.flag&flagIndir != 0 { - memmove(addr, v.ptr, st.size) - } else { - // This case must be a pointer type. - *(*uintptr)(addr) = uintptr(v.ptr) - } - // There's only one step for a stack-allocated value. - break stepsLoop - case abiStepIntReg, abiStepPointer: - // Copy values to "integer registers." - if v.flag&flagIndir != 0 { - offset := add(v.ptr, st.offset, "precomputed value offset") - intToReg(regs, st.ireg, st.size, offset) - } else { - // Only populate the Ints space on the return path. - // This is safe because out is kept alive until the - // end of this function, and the return path through - // makeFuncStub has no preemption, so these pointers - // are always visible to the GC. - regs.Ints[st.ireg] = uintptr(v.ptr) - } - case abiStepFloatReg: - // Copy values to "float registers." - if v.flag&flagIndir == 0 { - panic("attempted to copy pointer to FP register") - } - offset := add(v.ptr, st.offset, "precomputed value offset") - floatToReg(regs, st.freg, st.size, offset) - default: - panic("unknown ABI part kind") - } - } - } - } - - // Announce that the return values are valid. - // After this point the runtime can depend on the return values being valid. - *retValid = true - - // We have to make sure that the out slice lives at least until - // the runtime knows the return values are valid. Otherwise, the - // return values might not be scanned by anyone during a GC. - // (out would be dead, and the return slots not yet alive.) - runtime.KeepAlive(out) - - // runtime.getArgInfo expects to be able to find ctxt on the - // stack when it finds our caller, makeFuncStub. Make sure it - // doesn't get garbage collected. - runtime.KeepAlive(ctxt) -} - -// methodReceiver returns information about the receiver -// described by v. The Value v may or may not have the -// flagMethod bit set, so the kind cached in v.flag should -// not be used. -// The return value rcvrtype gives the method's actual receiver type. -// The return value t gives the method type signature (without the receiver). -// The return value fn is a pointer to the method code. -func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *abi.Type, t *funcType, fn unsafe.Pointer) { - i := methodIndex - if v.typ().Kind() == abi.Interface { - tt := (*interfaceType)(unsafe.Pointer(v.typ())) - if uint(i) >= uint(len(tt.Methods)) { - panic("reflect: internal error: invalid method index") - } - m := &tt.Methods[i] - if !tt.nameOff(m.Name).IsExported() { - panic("reflect: " + op + " of unexported method") - } - iface := (*nonEmptyInterface)(v.ptr) - if iface.itab == nil { - panic("reflect: " + op + " of method on nil interface value") - } - rcvrtype = iface.itab.typ - fn = unsafe.Pointer(&iface.itab.fun[i]) - t = (*funcType)(unsafe.Pointer(tt.typeOff(m.Typ))) - } else { - rcvrtype = v.typ() - ms := v.typ().ExportedMethods() - if uint(i) >= uint(len(ms)) { - panic("reflect: internal error: invalid method index") - } - m := ms[i] - if !nameOffFor(v.typ(), m.Name).IsExported() { - panic("reflect: " + op + " of unexported method") - } - ifn := textOffFor(v.typ(), m.Ifn) - fn = unsafe.Pointer(&ifn) - t = (*funcType)(unsafe.Pointer(typeOffFor(v.typ(), m.Mtyp))) - } - return -} - -// v is a method receiver. Store at p the word which is used to -// encode that receiver at the start of the argument list. -// Reflect uses the "interface" calling convention for -// methods, which always uses one word to record the receiver. -func storeRcvr(v Value, p unsafe.Pointer) { - t := v.typ() - if t.Kind() == abi.Interface { - // the interface data word becomes the receiver word - iface := (*nonEmptyInterface)(v.ptr) - *(*unsafe.Pointer)(p) = iface.word - } else if v.flag&flagIndir != 0 && !ifaceIndir(t) { - *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr) - } else { - *(*unsafe.Pointer)(p) = v.ptr - } -} - -// align returns the result of rounding x up to a multiple of n. -// n must be a power of two. -func align(x, n uintptr) uintptr { - return (x + n - 1) &^ (n - 1) -} - -// callMethod is the call implementation used by a function returned -// by makeMethodValue (used by v.Method(i).Interface()). -// It is a streamlined version of the usual reflect call: the caller has -// already laid out the argument frame for us, so we don't have -// to deal with individual Values for each argument. -// It is in this file so that it can be next to the two similar functions above. -// The remainder of the makeMethodValue implementation is in makefunc.go. -// -// NOTE: This function must be marked as a "wrapper" in the generated code, -// so that the linker can make it work correctly for panic and recover. -// The gc compilers know to do that for the name "reflect.callMethod". -// -// ctxt is the "closure" generated by makeVethodValue. -// frame is a pointer to the arguments to that closure on the stack. -// retValid points to a boolean which should be set when the results -// section of frame is set. -// -// regs contains the argument values passed in registers and will contain -// the values returned from ctxt.fn in registers. -func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *abi.RegArgs) { - rcvr := ctxt.rcvr - rcvrType, valueFuncType, methodFn := methodReceiver("call", rcvr, ctxt.method) - - // There are two ABIs at play here. - // - // methodValueCall was invoked with the ABI assuming there was no - // receiver ("value ABI") and that's what frame and regs are holding. - // - // Meanwhile, we need to actually call the method with a receiver, which - // has its own ABI ("method ABI"). Everything that follows is a translation - // between the two. - _, _, valueABI := funcLayout(valueFuncType, nil) - valueFrame, valueRegs := frame, regs - methodFrameType, methodFramePool, methodABI := funcLayout(valueFuncType, rcvrType) - - // Make a new frame that is one word bigger so we can store the receiver. - // This space is used for both arguments and return values. - methodFrame := methodFramePool.Get().(unsafe.Pointer) - var methodRegs abi.RegArgs - - // Deal with the receiver. It's guaranteed to only be one word in size. - switch st := methodABI.call.steps[0]; st.kind { - case abiStepStack: - // Only copy the receiver to the stack if the ABI says so. - // Otherwise, it'll be in a register already. - storeRcvr(rcvr, methodFrame) - case abiStepPointer: - // Put the receiver in a register. - storeRcvr(rcvr, unsafe.Pointer(&methodRegs.Ptrs[st.ireg])) - fallthrough - case abiStepIntReg: - storeRcvr(rcvr, unsafe.Pointer(&methodRegs.Ints[st.ireg])) - case abiStepFloatReg: - storeRcvr(rcvr, unsafe.Pointer(&methodRegs.Floats[st.freg])) - default: - panic("unknown ABI parameter kind") - } - - // Translate the rest of the arguments. - for i, t := range valueFuncType.InSlice() { - valueSteps := valueABI.call.stepsForValue(i) - methodSteps := methodABI.call.stepsForValue(i + 1) - - // Zero-sized types are trivial: nothing to do. - if len(valueSteps) == 0 { - if len(methodSteps) != 0 { - panic("method ABI and value ABI do not align") - } - continue - } - - // There are four cases to handle in translating each - // argument: - // 1. Stack -> stack translation. - // 2. Stack -> registers translation. - // 3. Registers -> stack translation. - // 4. Registers -> registers translation. - - // If the value ABI passes the value on the stack, - // then the method ABI does too, because it has strictly - // fewer arguments. Simply copy between the two. - if vStep := valueSteps[0]; vStep.kind == abiStepStack { - mStep := methodSteps[0] - // Handle stack -> stack translation. - if mStep.kind == abiStepStack { - if vStep.size != mStep.size { - panic("method ABI and value ABI do not align") - } - typedmemmove(t, - add(methodFrame, mStep.stkOff, "precomputed stack offset"), - add(valueFrame, vStep.stkOff, "precomputed stack offset")) - continue - } - // Handle stack -> register translation. - for _, mStep := range methodSteps { - from := add(valueFrame, vStep.stkOff+mStep.offset, "precomputed stack offset") - switch mStep.kind { - case abiStepPointer: - // Do the pointer copy directly so we get a write barrier. - methodRegs.Ptrs[mStep.ireg] = *(*unsafe.Pointer)(from) - fallthrough // We need to make sure this ends up in Ints, too. - case abiStepIntReg: - intToReg(&methodRegs, mStep.ireg, mStep.size, from) - case abiStepFloatReg: - floatToReg(&methodRegs, mStep.freg, mStep.size, from) - default: - panic("unexpected method step") - } - } - continue - } - // Handle register -> stack translation. - if mStep := methodSteps[0]; mStep.kind == abiStepStack { - for _, vStep := range valueSteps { - to := add(methodFrame, mStep.stkOff+vStep.offset, "precomputed stack offset") - switch vStep.kind { - case abiStepPointer: - // Do the pointer copy directly so we get a write barrier. - *(*unsafe.Pointer)(to) = valueRegs.Ptrs[vStep.ireg] - case abiStepIntReg: - intFromReg(valueRegs, vStep.ireg, vStep.size, to) - case abiStepFloatReg: - floatFromReg(valueRegs, vStep.freg, vStep.size, to) - default: - panic("unexpected value step") - } - } - continue - } - // Handle register -> register translation. - if len(valueSteps) != len(methodSteps) { - // Because it's the same type for the value, and it's assigned - // to registers both times, it should always take up the same - // number of registers for each ABI. - panic("method ABI and value ABI don't align") - } - for i, vStep := range valueSteps { - mStep := methodSteps[i] - if mStep.kind != vStep.kind { - panic("method ABI and value ABI don't align") - } - switch vStep.kind { - case abiStepPointer: - // Copy this too, so we get a write barrier. - methodRegs.Ptrs[mStep.ireg] = valueRegs.Ptrs[vStep.ireg] - fallthrough - case abiStepIntReg: - methodRegs.Ints[mStep.ireg] = valueRegs.Ints[vStep.ireg] - case abiStepFloatReg: - methodRegs.Floats[mStep.freg] = valueRegs.Floats[vStep.freg] - default: - panic("unexpected value step") - } - } - } - - methodFrameSize := methodFrameType.Size() - // TODO(mknyszek): Remove this when we no longer have - // caller reserved spill space. - methodFrameSize = align(methodFrameSize, goarch.PtrSize) - methodFrameSize += methodABI.spill - - // Mark pointers in registers for the return path. - methodRegs.ReturnIsPtr = methodABI.outRegPtrs - - // Call. - // Call copies the arguments from scratch to the stack, calls fn, - // and then copies the results back into scratch. - call(methodFrameType, methodFn, methodFrame, uint32(methodFrameType.Size()), uint32(methodABI.retOffset), uint32(methodFrameSize), &methodRegs) - - // Copy return values. - // - // This is somewhat simpler because both ABIs have an identical - // return value ABI (the types are identical). As a result, register - // results can simply be copied over. Stack-allocated values are laid - // out the same, but are at different offsets from the start of the frame - // Ignore any changes to args. - // Avoid constructing out-of-bounds pointers if there are no return values. - // because the arguments may be laid out differently. - if valueRegs != nil { - *valueRegs = methodRegs - } - if retSize := methodFrameType.Size() - methodABI.retOffset; retSize > 0 { - valueRet := add(valueFrame, valueABI.retOffset, "valueFrame's size > retOffset") - methodRet := add(methodFrame, methodABI.retOffset, "methodFrame's size > retOffset") - // This copies to the stack. Write barriers are not needed. - memmove(valueRet, methodRet, retSize) - } - - // Tell the runtime it can now depend on the return values - // being properly initialized. - *retValid = true - - // Clear the scratch space and put it back in the pool. - // This must happen after the statement above, so that the return - // values will always be scanned by someone. - typedmemclr(methodFrameType, methodFrame) - methodFramePool.Put(methodFrame) - - // See the comment in callReflect. - runtime.KeepAlive(ctxt) - - // Keep valueRegs alive because it may hold live pointer results. - // The caller (methodValueCall) has it as a stack object, which is only - // scanned when there is a reference to it. - runtime.KeepAlive(valueRegs) -} - -// funcName returns the name of f, for use in error messages. -func funcName(f func([]Value) []Value) string { - pc := *(*uintptr)(unsafe.Pointer(&f)) - rf := runtime.FuncForPC(pc) - if rf != nil { - return rf.Name() - } - return "closure" -} - -// Cap returns v's capacity. -// It panics if v's Kind is not [Array], [Chan], [Slice] or pointer to [Array]. -func (v Value) Cap() int { - // capNonSlice is split out to keep Cap inlineable for slice kinds. - if v.kind() == Slice { - return (*unsafeheader.Slice)(v.ptr).Cap - } - return v.capNonSlice() -} - -func (v Value) capNonSlice() int { - k := v.kind() - switch k { - case Array: - return v.typ().Len() - case Chan: - return chancap(v.pointer()) - case Ptr: - if v.typ().Elem().Kind() == abi.Array { - return v.typ().Elem().Len() - } - panic("reflect: call of reflect.Value.Cap on ptr to non-array Value") - } - panic(&ValueError{"reflect.Value.Cap", v.kind()}) -} - -// Close closes the channel v. -// It panics if v's Kind is not [Chan] or -// v is a receive-only channel. -func (v Value) Close() { - v.mustBe(Chan) - v.mustBeExported() - tt := (*chanType)(unsafe.Pointer(v.typ())) - if ChanDir(tt.Dir)&SendDir == 0 { - panic("reflect: close of receive-only channel") - } - - chanclose(v.pointer()) -} - -// CanComplex reports whether [Value.Complex] can be used without panicking. -func (v Value) CanComplex() bool { - switch v.kind() { - case Complex64, Complex128: - return true - default: - return false - } -} - -// Complex returns v's underlying value, as a complex128. -// It panics if v's Kind is not [Complex64] or [Complex128] -func (v Value) Complex() complex128 { - k := v.kind() - switch k { - case Complex64: - return complex128(*(*complex64)(v.ptr)) - case Complex128: - return *(*complex128)(v.ptr) - } - panic(&ValueError{"reflect.Value.Complex", v.kind()}) -} - -// Elem returns the value that the interface v contains -// or that the pointer v points to. -// It panics if v's Kind is not [Interface] or [Pointer]. -// It returns the zero Value if v is nil. -func (v Value) Elem() Value { - k := v.kind() - switch k { - case Interface: - var eface any - if v.typ().NumMethod() == 0 { - eface = *(*any)(v.ptr) - } else { - eface = (any)(*(*interface { - M() - })(v.ptr)) - } - x := unpackEface(eface) - if x.flag != 0 { - x.flag |= v.flag.ro() - } - return x - case Pointer: - ptr := v.ptr - if v.flag&flagIndir != 0 { - if ifaceIndir(v.typ()) { - // This is a pointer to a not-in-heap object. ptr points to a uintptr - // in the heap. That uintptr is the address of a not-in-heap object. - // In general, pointers to not-in-heap objects can be total junk. - // But Elem() is asking to dereference it, so the user has asserted - // that at least it is a valid pointer (not just an integer stored in - // a pointer slot). So let's check, to make sure that it isn't a pointer - // that the runtime will crash on if it sees it during GC or write barriers. - // Since it is a not-in-heap pointer, all pointers to the heap are - // forbidden! That makes the test pretty easy. - // See issue 48399. - if !verifyNotInHeapPtr(*(*uintptr)(ptr)) { - panic("reflect: reflect.Value.Elem on an invalid notinheap pointer") - } - } - ptr = *(*unsafe.Pointer)(ptr) - } - // The returned value's address is v's value. - if ptr == nil { - return Value{} - } - tt := (*ptrType)(unsafe.Pointer(v.typ())) - typ := tt.Elem - fl := v.flag&flagRO | flagIndir | flagAddr - fl |= flag(typ.Kind()) - return Value{typ, ptr, fl} - } - panic(&ValueError{"reflect.Value.Elem", v.kind()}) -} - -// Field returns the i'th field of the struct v. -// It panics if v's Kind is not [Struct] or i is out of range. -func (v Value) Field(i int) Value { - if v.kind() != Struct { - panic(&ValueError{"reflect.Value.Field", v.kind()}) - } - tt := (*structType)(unsafe.Pointer(v.typ())) - if uint(i) >= uint(len(tt.Fields)) { - panic("reflect: Field index out of range") - } - field := &tt.Fields[i] - typ := field.Typ - - // Inherit permission bits from v, but clear flagEmbedRO. - fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind()) - // Using an unexported field forces flagRO. - if !field.Name.IsExported() { - if field.Embedded() { - fl |= flagEmbedRO - } else { - fl |= flagStickyRO - } - } - // Either flagIndir is set and v.ptr points at struct, - // or flagIndir is not set and v.ptr is the actual struct data. - // In the former case, we want v.ptr + offset. - // In the latter case, we must have field.offset = 0, - // so v.ptr + field.offset is still the correct address. - ptr := add(v.ptr, field.Offset, "same as non-reflect &v.field") - return Value{typ, ptr, fl} -} - -// FieldByIndex returns the nested field corresponding to index. -// It panics if evaluation requires stepping through a nil -// pointer or a field that is not a struct. -func (v Value) FieldByIndex(index []int) Value { - if len(index) == 1 { - return v.Field(index[0]) - } - v.mustBe(Struct) - for i, x := range index { - if i > 0 { - if v.Kind() == Pointer && v.typ().Elem().Kind() == abi.Struct { - if v.IsNil() { - panic("reflect: indirection through nil pointer to embedded struct") - } - v = v.Elem() - } - } - v = v.Field(x) - } - return v -} - -// FieldByIndexErr returns the nested field corresponding to index. -// It returns an error if evaluation requires stepping through a nil -// pointer, but panics if it must step through a field that -// is not a struct. -func (v Value) FieldByIndexErr(index []int) (Value, error) { - if len(index) == 1 { - return v.Field(index[0]), nil - } - v.mustBe(Struct) - for i, x := range index { - if i > 0 { - if v.Kind() == Ptr && v.typ().Elem().Kind() == abi.Struct { - if v.IsNil() { - return Value{}, errors.New("reflect: indirection through nil pointer to embedded struct field " + nameFor(v.typ().Elem())) - } - v = v.Elem() - } - } - v = v.Field(x) - } - return v, nil -} - -// FieldByName returns the struct field with the given name. -// It returns the zero Value if no field was found. -// It panics if v's Kind is not [Struct]. -func (v Value) FieldByName(name string) Value { - v.mustBe(Struct) - if f, ok := toRType(v.typ()).FieldByName(name); ok { - return v.FieldByIndex(f.Index) - } - return Value{} -} - -// FieldByNameFunc returns the struct field with a name -// that satisfies the match function. -// It panics if v's Kind is not [Struct]. -// It returns the zero Value if no field was found. -func (v Value) FieldByNameFunc(match func(string) bool) Value { - if f, ok := toRType(v.typ()).FieldByNameFunc(match); ok { - return v.FieldByIndex(f.Index) - } - return Value{} -} - -// CanFloat reports whether [Value.Float] can be used without panicking. -func (v Value) CanFloat() bool { - switch v.kind() { - case Float32, Float64: - return true - default: - return false - } -} - -// Float returns v's underlying value, as a float64. -// It panics if v's Kind is not [Float32] or [Float64] -func (v Value) Float() float64 { - k := v.kind() - switch k { - case Float32: - return float64(*(*float32)(v.ptr)) - case Float64: - return *(*float64)(v.ptr) - } - panic(&ValueError{"reflect.Value.Float", v.kind()}) -} - -var uint8Type = rtypeOf(uint8(0)) - -// Index returns v's i'th element. -// It panics if v's Kind is not [Array], [Slice], or [String] or i is out of range. -func (v Value) Index(i int) Value { - switch v.kind() { - case Array: - tt := (*arrayType)(unsafe.Pointer(v.typ())) - if uint(i) >= uint(tt.Len) { - panic("reflect: array index out of range") - } - typ := tt.Elem - offset := uintptr(i) * typ.Size() - - // Either flagIndir is set and v.ptr points at array, - // or flagIndir is not set and v.ptr is the actual array data. - // In the former case, we want v.ptr + offset. - // In the latter case, we must be doing Index(0), so offset = 0, - // so v.ptr + offset is still the correct address. - val := add(v.ptr, offset, "same as &v[i], i < tt.len") - fl := v.flag&(flagIndir|flagAddr) | v.flag.ro() | flag(typ.Kind()) // bits same as overall array - return Value{typ, val, fl} - - case Slice: - // Element flag same as Elem of Pointer. - // Addressable, indirect, possibly read-only. - s := (*unsafeheader.Slice)(v.ptr) - if uint(i) >= uint(s.Len) { - panic("reflect: slice index out of range") - } - tt := (*sliceType)(unsafe.Pointer(v.typ())) - typ := tt.Elem - val := arrayAt(s.Data, i, typ.Size(), "i < s.Len") - fl := flagAddr | flagIndir | v.flag.ro() | flag(typ.Kind()) - return Value{typ, val, fl} - - case String: - s := (*unsafeheader.String)(v.ptr) - if uint(i) >= uint(s.Len) { - panic("reflect: string index out of range") - } - p := arrayAt(s.Data, i, 1, "i < s.Len") - fl := v.flag.ro() | flag(Uint8) | flagIndir - return Value{uint8Type, p, fl} - } - panic(&ValueError{"reflect.Value.Index", v.kind()}) -} - -// CanInt reports whether Int can be used without panicking. -func (v Value) CanInt() bool { - switch v.kind() { - case Int, Int8, Int16, Int32, Int64: - return true - default: - return false - } -} - -// Int returns v's underlying value, as an int64. -// It panics if v's Kind is not [Int], [Int8], [Int16], [Int32], or [Int64]. -func (v Value) Int() int64 { - k := v.kind() - p := v.ptr - switch k { - case Int: - return int64(*(*int)(p)) - case Int8: - return int64(*(*int8)(p)) - case Int16: - return int64(*(*int16)(p)) - case Int32: - return int64(*(*int32)(p)) - case Int64: - return *(*int64)(p) - } - panic(&ValueError{"reflect.Value.Int", v.kind()}) -} - -// CanInterface reports whether [Value.Interface] can be used without panicking. -func (v Value) CanInterface() bool { - if v.flag == 0 { - panic(&ValueError{"reflect.Value.CanInterface", Invalid}) - } - return v.flag&flagRO == 0 -} - -// Interface returns v's current value as an interface{}. -// It is equivalent to: -// -// var i interface{} = (v's underlying value) -// -// It panics if the Value was obtained by accessing -// unexported struct fields. -func (v Value) Interface() (i any) { - return valueInterface(v, true) -} - -func valueInterface(v Value, safe bool) any { - if v.flag == 0 { - panic(&ValueError{"reflect.Value.Interface", Invalid}) - } - if safe && v.flag&flagRO != 0 { - // Do not allow access to unexported values via Interface, - // because they might be pointers that should not be - // writable or methods or function that should not be callable. - panic("reflect.Value.Interface: cannot return value obtained from unexported field or method") - } - if v.flag&flagMethod != 0 { - v = makeMethodValue("Interface", v) - } - - if v.kind() == Interface { - // Special case: return the element inside the interface. - // Empty interface has one layout, all interfaces with - // methods have a second layout. - if v.NumMethod() == 0 { - return *(*any)(v.ptr) - } - return *(*interface { - M() - })(v.ptr) - } - - // TODO: pass safe to packEface so we don't need to copy if safe==true? - return packEface(v) -} - -// InterfaceData returns a pair of unspecified uintptr values. -// It panics if v's Kind is not Interface. -// -// In earlier versions of Go, this function returned the interface's -// value as a uintptr pair. As of Go 1.4, the implementation of -// interface values precludes any defined use of InterfaceData. -// -// Deprecated: The memory representation of interface values is not -// compatible with InterfaceData. -func (v Value) InterfaceData() [2]uintptr { - v.mustBe(Interface) - // The compiler loses track as it converts to uintptr. Force escape. - escapes(v.ptr) - // We treat this as a read operation, so we allow - // it even for unexported data, because the caller - // has to import "unsafe" to turn it into something - // that can be abused. - // Interface value is always bigger than a word; assume flagIndir. - return *(*[2]uintptr)(v.ptr) -} - -// IsNil reports whether its argument v is nil. The argument must be -// a chan, func, interface, map, pointer, or slice value; if it is -// not, IsNil panics. Note that IsNil is not always equivalent to a -// regular comparison with nil in Go. For example, if v was created -// by calling ValueOf with an uninitialized interface variable i, -// i==nil will be true but v.IsNil will panic as v will be the zero -// Value. -func (v Value) IsNil() bool { - k := v.kind() - switch k { - case Chan, Func, Map, Pointer, UnsafePointer: - if v.flag&flagMethod != 0 { - return false - } - ptr := v.ptr - if v.flag&flagIndir != 0 { - ptr = *(*unsafe.Pointer)(ptr) - } - return ptr == nil - case Interface, Slice: - // Both interface and slice are nil if first word is 0. - // Both are always bigger than a word; assume flagIndir. - return *(*unsafe.Pointer)(v.ptr) == nil - } - panic(&ValueError{"reflect.Value.IsNil", v.kind()}) -} - -// IsValid reports whether v represents a value. -// It returns false if v is the zero Value. -// If IsValid returns false, all other methods except String panic. -// Most functions and methods never return an invalid Value. -// If one does, its documentation states the conditions explicitly. -func (v Value) IsValid() bool { - return v.flag != 0 -} - -// IsZero reports whether v is the zero value for its type. -// It panics if the argument is invalid. -func (v Value) IsZero() bool { - switch v.kind() { - case Bool: - return !v.Bool() - case Int, Int8, Int16, Int32, Int64: - return v.Int() == 0 - case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return v.Uint() == 0 - case Float32, Float64: - return v.Float() == 0 - case Complex64, Complex128: - return v.Complex() == 0 - case Array: - if v.flag&flagIndir == 0 { - return v.ptr == nil - } - typ := (*abi.ArrayType)(unsafe.Pointer(v.typ())) - // If the type is comparable, then compare directly with zero. - if typ.Equal != nil && typ.Size() <= abi.ZeroValSize { - // v.ptr doesn't escape, as Equal functions are compiler generated - // and never escape. The escape analysis doesn't know, as it is a - // function pointer call. - return typ.Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0])) - } - if typ.TFlag&abi.TFlagRegularMemory != 0 { - // For some types where the zero value is a value where all bits of this type are 0 - // optimize it. - return isZero(unsafe.Slice(((*byte)(v.ptr)), typ.Size())) - } - n := int(typ.Len) - for i := 0; i < n; i++ { - if !v.Index(i).IsZero() { - return false - } - } - return true - case Chan, Func, Interface, Map, Pointer, Slice, UnsafePointer: - return v.IsNil() - case String: - return v.Len() == 0 - case Struct: - if v.flag&flagIndir == 0 { - return v.ptr == nil - } - typ := (*abi.StructType)(unsafe.Pointer(v.typ())) - // If the type is comparable, then compare directly with zero. - if typ.Equal != nil && typ.Size() <= abi.ZeroValSize { - // See noescape justification above. - return typ.Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0])) - } - if typ.TFlag&abi.TFlagRegularMemory != 0 { - // For some types where the zero value is a value where all bits of this type are 0 - // optimize it. - return isZero(unsafe.Slice(((*byte)(v.ptr)), typ.Size())) - } - - n := v.NumField() - for i := 0; i < n; i++ { - if !v.Field(i).IsZero() && v.Type().Field(i).Name != "_" { - return false - } - } - return true - default: - // This should never happen, but will act as a safeguard for later, - // as a default value doesn't makes sense here. - panic(&ValueError{"reflect.Value.IsZero", v.Kind()}) - } -} - -// isZero For all zeros, performance is not as good as -// return bytealg.Count(b, byte(0)) == len(b) -func isZero(b []byte) bool { - if len(b) == 0 { - return true - } - const n = 32 - // Align memory addresses to 8 bytes. - for uintptr(unsafe.Pointer(&b[0]))%8 != 0 { - if b[0] != 0 { - return false - } - b = b[1:] - if len(b) == 0 { - return true - } - } - for len(b)%8 != 0 { - if b[len(b)-1] != 0 { - return false - } - b = b[:len(b)-1] - } - if len(b) == 0 { - return true - } - w := unsafe.Slice((*uint64)(unsafe.Pointer(&b[0])), len(b)/8) - for len(w)%n != 0 { - if w[0] != 0 { - return false - } - w = w[1:] - } - for len(w) >= n { - if w[0] != 0 || w[1] != 0 || w[2] != 0 || w[3] != 0 || - w[4] != 0 || w[5] != 0 || w[6] != 0 || w[7] != 0 || - w[8] != 0 || w[9] != 0 || w[10] != 0 || w[11] != 0 || - w[12] != 0 || w[13] != 0 || w[14] != 0 || w[15] != 0 || - w[16] != 0 || w[17] != 0 || w[18] != 0 || w[19] != 0 || - w[20] != 0 || w[21] != 0 || w[22] != 0 || w[23] != 0 || - w[24] != 0 || w[25] != 0 || w[26] != 0 || w[27] != 0 || - w[28] != 0 || w[29] != 0 || w[30] != 0 || w[31] != 0 { - return false - } - w = w[n:] - } - return true -} - -// SetZero sets v to be the zero value of v's type. -// It panics if [Value.CanSet] returns false. -func (v Value) SetZero() { - v.mustBeAssignable() - switch v.kind() { - case Bool: - *(*bool)(v.ptr) = false - case Int: - *(*int)(v.ptr) = 0 - case Int8: - *(*int8)(v.ptr) = 0 - case Int16: - *(*int16)(v.ptr) = 0 - case Int32: - *(*int32)(v.ptr) = 0 - case Int64: - *(*int64)(v.ptr) = 0 - case Uint: - *(*uint)(v.ptr) = 0 - case Uint8: - *(*uint8)(v.ptr) = 0 - case Uint16: - *(*uint16)(v.ptr) = 0 - case Uint32: - *(*uint32)(v.ptr) = 0 - case Uint64: - *(*uint64)(v.ptr) = 0 - case Uintptr: - *(*uintptr)(v.ptr) = 0 - case Float32: - *(*float32)(v.ptr) = 0 - case Float64: - *(*float64)(v.ptr) = 0 - case Complex64: - *(*complex64)(v.ptr) = 0 - case Complex128: - *(*complex128)(v.ptr) = 0 - case String: - *(*string)(v.ptr) = "" - case Slice: - *(*unsafeheader.Slice)(v.ptr) = unsafeheader.Slice{} - case Interface: - *(*emptyInterface)(v.ptr) = emptyInterface{} - case Chan, Func, Map, Pointer, UnsafePointer: - *(*unsafe.Pointer)(v.ptr) = nil - case Array, Struct: - typedmemclr(v.typ(), v.ptr) - default: - // This should never happen, but will act as a safeguard for later, - // as a default value doesn't makes sense here. - panic(&ValueError{"reflect.Value.SetZero", v.Kind()}) - } -} - -// Kind returns v's Kind. -// If v is the zero Value ([Value.IsValid] returns false), Kind returns Invalid. -func (v Value) Kind() Kind { - return v.kind() -} - -// Len returns v's length. -// It panics if v's Kind is not [Array], [Chan], [Map], [Slice], [String], or pointer to [Array]. -func (v Value) Len() int { - // lenNonSlice is split out to keep Len inlineable for slice kinds. - if v.kind() == Slice { - return (*unsafeheader.Slice)(v.ptr).Len - } - return v.lenNonSlice() -} - -func (v Value) lenNonSlice() int { - switch k := v.kind(); k { - case Array: - tt := (*arrayType)(unsafe.Pointer(v.typ())) - return int(tt.Len) - case Chan: - return chanlen(v.pointer()) - case Map: - return maplen(v.pointer()) - case String: - // String is bigger than a word; assume flagIndir. - return (*unsafeheader.String)(v.ptr).Len - case Ptr: - if v.typ().Elem().Kind() == abi.Array { - return v.typ().Elem().Len() - } - panic("reflect: call of reflect.Value.Len on ptr to non-array Value") - } - panic(&ValueError{"reflect.Value.Len", v.kind()}) -} - -var stringType = rtypeOf("") - -// MapIndex returns the value associated with key in the map v. -// It panics if v's Kind is not [Map]. -// It returns the zero Value if key is not found in the map or if v represents a nil map. -// As in Go, the key's value must be assignable to the map's key type. -func (v Value) MapIndex(key Value) Value { - v.mustBe(Map) - tt := (*mapType)(unsafe.Pointer(v.typ())) - - // Do not require key to be exported, so that DeepEqual - // and other programs can use all the keys returned by - // MapKeys as arguments to MapIndex. If either the map - // or the key is unexported, though, the result will be - // considered unexported. This is consistent with the - // behavior for structs, which allow read but not write - // of unexported fields. - - var e unsafe.Pointer - if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= maxValSize { - k := *(*string)(key.ptr) - e = mapaccess_faststr(v.typ(), v.pointer(), k) - } else { - key = key.assignTo("reflect.Value.MapIndex", tt.Key, nil) - var k unsafe.Pointer - if key.flag&flagIndir != 0 { - k = key.ptr - } else { - k = unsafe.Pointer(&key.ptr) - } - e = mapaccess(v.typ(), v.pointer(), k) - } - if e == nil { - return Value{} - } - typ := tt.Elem - fl := (v.flag | key.flag).ro() - fl |= flag(typ.Kind()) - return copyVal(typ, fl, e) -} - -// MapKeys returns a slice containing all the keys present in the map, -// in unspecified order. -// It panics if v's Kind is not [Map]. -// It returns an empty slice if v represents a nil map. -func (v Value) MapKeys() []Value { - v.mustBe(Map) - tt := (*mapType)(unsafe.Pointer(v.typ())) - keyType := tt.Key - - fl := v.flag.ro() | flag(keyType.Kind()) - - m := v.pointer() - mlen := int(0) - if m != nil { - mlen = maplen(m) - } - var it hiter - mapiterinit(v.typ(), m, &it) - a := make([]Value, mlen) - var i int - for i = 0; i < len(a); i++ { - key := mapiterkey(&it) - if key == nil { - // Someone deleted an entry from the map since we - // called maplen above. It's a data race, but nothing - // we can do about it. - break - } - a[i] = copyVal(keyType, fl, key) - mapiternext(&it) - } - return a[:i] -} - -// hiter's structure matches runtime.hiter's structure. -// Having a clone here allows us to embed a map iterator -// inside type MapIter so that MapIters can be re-used -// without doing any allocations. -type hiter struct { - key unsafe.Pointer - elem unsafe.Pointer - t unsafe.Pointer - h unsafe.Pointer - buckets unsafe.Pointer - bptr unsafe.Pointer - overflow *[]unsafe.Pointer - oldoverflow *[]unsafe.Pointer - startBucket uintptr - offset uint8 - wrapped bool - B uint8 - i uint8 - bucket uintptr - checkBucket uintptr -} - -func (h *hiter) initialized() bool { - return h.t != nil -} - -// A MapIter is an iterator for ranging over a map. -// See [Value.MapRange]. -type MapIter struct { - m Value - hiter hiter -} - -// Key returns the key of iter's current map entry. -func (iter *MapIter) Key() Value { - if !iter.hiter.initialized() { - panic("MapIter.Key called before Next") - } - iterkey := mapiterkey(&iter.hiter) - if iterkey == nil { - panic("MapIter.Key called on exhausted iterator") - } - - t := (*mapType)(unsafe.Pointer(iter.m.typ())) - ktype := t.Key - return copyVal(ktype, iter.m.flag.ro()|flag(ktype.Kind()), iterkey) -} - -// SetIterKey assigns to v the key of iter's current map entry. -// It is equivalent to v.Set(iter.Key()), but it avoids allocating a new Value. -// As in Go, the key must be assignable to v's type and -// must not be derived from an unexported field. -func (v Value) SetIterKey(iter *MapIter) { - if !iter.hiter.initialized() { - panic("reflect: Value.SetIterKey called before Next") - } - iterkey := mapiterkey(&iter.hiter) - if iterkey == nil { - panic("reflect: Value.SetIterKey called on exhausted iterator") - } - - v.mustBeAssignable() - var target unsafe.Pointer - if v.kind() == Interface { - target = v.ptr - } - - t := (*mapType)(unsafe.Pointer(iter.m.typ())) - ktype := t.Key - - iter.m.mustBeExported() // do not let unexported m leak - key := Value{ktype, iterkey, iter.m.flag | flag(ktype.Kind()) | flagIndir} - key = key.assignTo("reflect.MapIter.SetKey", v.typ(), target) - typedmemmove(v.typ(), v.ptr, key.ptr) -} - -// Value returns the value of iter's current map entry. -func (iter *MapIter) Value() Value { - if !iter.hiter.initialized() { - panic("MapIter.Value called before Next") - } - iterelem := mapiterelem(&iter.hiter) - if iterelem == nil { - panic("MapIter.Value called on exhausted iterator") - } - - t := (*mapType)(unsafe.Pointer(iter.m.typ())) - vtype := t.Elem - return copyVal(vtype, iter.m.flag.ro()|flag(vtype.Kind()), iterelem) -} - -// SetIterValue assigns to v the value of iter's current map entry. -// It is equivalent to v.Set(iter.Value()), but it avoids allocating a new Value. -// As in Go, the value must be assignable to v's type and -// must not be derived from an unexported field. -func (v Value) SetIterValue(iter *MapIter) { - if !iter.hiter.initialized() { - panic("reflect: Value.SetIterValue called before Next") - } - iterelem := mapiterelem(&iter.hiter) - if iterelem == nil { - panic("reflect: Value.SetIterValue called on exhausted iterator") - } - - v.mustBeAssignable() - var target unsafe.Pointer - if v.kind() == Interface { - target = v.ptr - } - - t := (*mapType)(unsafe.Pointer(iter.m.typ())) - vtype := t.Elem - - iter.m.mustBeExported() // do not let unexported m leak - elem := Value{vtype, iterelem, iter.m.flag | flag(vtype.Kind()) | flagIndir} - elem = elem.assignTo("reflect.MapIter.SetValue", v.typ(), target) - typedmemmove(v.typ(), v.ptr, elem.ptr) -} - -// Next advances the map iterator and reports whether there is another -// entry. It returns false when iter is exhausted; subsequent -// calls to [MapIter.Key], [MapIter.Value], or [MapIter.Next] will panic. -func (iter *MapIter) Next() bool { - if !iter.m.IsValid() { - panic("MapIter.Next called on an iterator that does not have an associated map Value") - } - if !iter.hiter.initialized() { - mapiterinit(iter.m.typ(), iter.m.pointer(), &iter.hiter) - } else { - if mapiterkey(&iter.hiter) == nil { - panic("MapIter.Next called on exhausted iterator") - } - mapiternext(&iter.hiter) - } - return mapiterkey(&iter.hiter) != nil -} - -// Reset modifies iter to iterate over v. -// It panics if v's Kind is not [Map] and v is not the zero Value. -// Reset(Value{}) causes iter to not to refer to any map, -// which may allow the previously iterated-over map to be garbage collected. -func (iter *MapIter) Reset(v Value) { - if v.IsValid() { - v.mustBe(Map) - } - iter.m = v - iter.hiter = hiter{} -} - -// MapRange returns a range iterator for a map. -// It panics if v's Kind is not [Map]. -// -// Call [MapIter.Next] to advance the iterator, and [MapIter.Key]/[MapIter.Value] to access each entry. -// [MapIter.Next] returns false when the iterator is exhausted. -// MapRange follows the same iteration semantics as a range statement. -// -// Example: -// -// iter := reflect.ValueOf(m).MapRange() -// for iter.Next() { -// k := iter.Key() -// v := iter.Value() -// ... -// } -func (v Value) MapRange() *MapIter { - // This is inlinable to take advantage of "function outlining". - // The allocation of MapIter can be stack allocated if the caller - // does not allow it to escape. - // See https://blog.filippo.io/efficient-go-apis-with-the-inliner/ - if v.kind() != Map { - v.panicNotMap() - } - return &MapIter{m: v} -} - -// Force slow panicking path not inlined, so it won't add to the -// inlining budget of the caller. -// TODO: undo when the inliner is no longer bottom-up only. -// -//go:noinline -func (f flag) panicNotMap() { - f.mustBe(Map) -} - -// copyVal returns a Value containing the map key or value at ptr, -// allocating a new variable as needed. -func copyVal(typ *abi.Type, fl flag, ptr unsafe.Pointer) Value { - if typ.IfaceIndir() { - // Copy result so future changes to the map - // won't change the underlying value. - c := unsafe_New(typ) - typedmemmove(typ, c, ptr) - return Value{typ, c, fl | flagIndir} - } - return Value{typ, *(*unsafe.Pointer)(ptr), fl} -} - -// Method returns a function value corresponding to v's i'th method. -// The arguments to a Call on the returned function should not include -// a receiver; the returned function will always use v as the receiver. -// Method panics if i is out of range or if v is a nil interface value. -func (v Value) Method(i int) Value { - if v.typ() == nil { - panic(&ValueError{"reflect.Value.Method", Invalid}) - } - if v.flag&flagMethod != 0 || uint(i) >= uint(toRType(v.typ()).NumMethod()) { - panic("reflect: Method index out of range") - } - if v.typ().Kind() == abi.Interface && v.IsNil() { - panic("reflect: Method on nil interface value") - } - fl := v.flag.ro() | (v.flag & flagIndir) - fl |= flag(Func) - fl |= flag(i)<> (64 - bitSize) - return x != trunc - } - panic(&ValueError{"reflect.Value.OverflowInt", v.kind()}) -} - -// OverflowUint reports whether the uint64 x cannot be represented by v's type. -// It panics if v's Kind is not [Uint], [Uintptr], [Uint8], [Uint16], [Uint32], or [Uint64]. -func (v Value) OverflowUint(x uint64) bool { - k := v.kind() - switch k { - case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64: - bitSize := v.typ_.Size() * 8 // ok to use v.typ_ directly as Size doesn't escape - trunc := (x << (64 - bitSize)) >> (64 - bitSize) - return x != trunc - } - panic(&ValueError{"reflect.Value.OverflowUint", v.kind()}) -} - -//go:nocheckptr -// This prevents inlining Value.Pointer when -d=checkptr is enabled, -// which ensures cmd/compile can recognize unsafe.Pointer(v.Pointer()) -// and make an exception. - -// Pointer returns v's value as a uintptr. -// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], or [UnsafePointer]. -// -// If v's Kind is [Func], the returned pointer is an underlying -// code pointer, but not necessarily enough to identify a -// single function uniquely. The only guarantee is that the -// result is zero if and only if v is a nil func Value. -// -// If v's Kind is [Slice], the returned pointer is to the first -// element of the slice. If the slice is nil the returned value -// is 0. If the slice is empty but non-nil the return value is non-zero. -// -// It's preferred to use uintptr(Value.UnsafePointer()) to get the equivalent result. -func (v Value) Pointer() uintptr { - // The compiler loses track as it converts to uintptr. Force escape. - escapes(v.ptr) - - k := v.kind() - switch k { - case Pointer: - if v.typ().PtrBytes == 0 { - val := *(*uintptr)(v.ptr) - // Since it is a not-in-heap pointer, all pointers to the heap are - // forbidden! See comment in Value.Elem and issue #48399. - if !verifyNotInHeapPtr(val) { - panic("reflect: reflect.Value.Pointer on an invalid notinheap pointer") - } - return val - } - fallthrough - case Chan, Map, UnsafePointer: - return uintptr(v.pointer()) - case Func: - if v.flag&flagMethod != 0 { - // As the doc comment says, the returned pointer is an - // underlying code pointer but not necessarily enough to - // identify a single function uniquely. All method expressions - // created via reflect have the same underlying code pointer, - // so their Pointers are equal. The function used here must - // match the one used in makeMethodValue. - return methodValueCallCodePtr() - } - p := v.pointer() - // Non-nil func value points at data block. - // First word of data block is actual code. - if p != nil { - p = *(*unsafe.Pointer)(p) - } - return uintptr(p) - - case Slice: - return uintptr((*unsafeheader.Slice)(v.ptr).Data) - } - panic(&ValueError{"reflect.Value.Pointer", v.kind()}) -} - -// Recv receives and returns a value from the channel v. -// It panics if v's Kind is not [Chan]. -// The receive blocks until a value is ready. -// The boolean value ok is true if the value x corresponds to a send -// on the channel, false if it is a zero value received because the channel is closed. -func (v Value) Recv() (x Value, ok bool) { - v.mustBe(Chan) - v.mustBeExported() - return v.recv(false) -} - -// internal recv, possibly non-blocking (nb). -// v is known to be a channel. -func (v Value) recv(nb bool) (val Value, ok bool) { - tt := (*chanType)(unsafe.Pointer(v.typ())) - if ChanDir(tt.Dir)&RecvDir == 0 { - panic("reflect: recv on send-only channel") - } - t := tt.Elem - val = Value{t, nil, flag(t.Kind())} - var p unsafe.Pointer - if ifaceIndir(t) { - p = unsafe_New(t) - val.ptr = p - val.flag |= flagIndir - } else { - p = unsafe.Pointer(&val.ptr) - } - selected, ok := chanrecv(v.pointer(), nb, p) - if !selected { - val = Value{} - } - return -} - -// Send sends x on the channel v. -// It panics if v's kind is not [Chan] or if x's type is not the same type as v's element type. -// As in Go, x's value must be assignable to the channel's element type. -func (v Value) Send(x Value) { - v.mustBe(Chan) - v.mustBeExported() - v.send(x, false) -} - -// internal send, possibly non-blocking. -// v is known to be a channel. -func (v Value) send(x Value, nb bool) (selected bool) { - tt := (*chanType)(unsafe.Pointer(v.typ())) - if ChanDir(tt.Dir)&SendDir == 0 { - panic("reflect: send on recv-only channel") - } - x.mustBeExported() - x = x.assignTo("reflect.Value.Send", tt.Elem, nil) - var p unsafe.Pointer - if x.flag&flagIndir != 0 { - p = x.ptr - } else { - p = unsafe.Pointer(&x.ptr) - } - return chansend(v.pointer(), p, nb) -} - -// Set assigns x to the value v. -// It panics if [Value.CanSet] returns false. -// As in Go, x's value must be assignable to v's type and -// must not be derived from an unexported field. -func (v Value) Set(x Value) { - v.mustBeAssignable() - x.mustBeExported() // do not let unexported x leak - var target unsafe.Pointer - if v.kind() == Interface { - target = v.ptr - } - x = x.assignTo("reflect.Set", v.typ(), target) - if x.flag&flagIndir != 0 { - if x.ptr == unsafe.Pointer(&zeroVal[0]) { - typedmemclr(v.typ(), v.ptr) - } else { - typedmemmove(v.typ(), v.ptr, x.ptr) - } - } else { - *(*unsafe.Pointer)(v.ptr) = x.ptr - } -} - -// SetBool sets v's underlying value. -// It panics if v's Kind is not [Bool] or if [Value.CanSet] returns false. -func (v Value) SetBool(x bool) { - v.mustBeAssignable() - v.mustBe(Bool) - *(*bool)(v.ptr) = x -} - -// SetBytes sets v's underlying value. -// It panics if v's underlying value is not a slice of bytes. -func (v Value) SetBytes(x []byte) { - v.mustBeAssignable() - v.mustBe(Slice) - if toRType(v.typ()).Elem().Kind() != Uint8 { // TODO add Elem method, fix mustBe(Slice) to return slice. - panic("reflect.Value.SetBytes of non-byte slice") - } - *(*[]byte)(v.ptr) = x -} - -// setRunes sets v's underlying value. -// It panics if v's underlying value is not a slice of runes (int32s). -func (v Value) setRunes(x []rune) { - v.mustBeAssignable() - v.mustBe(Slice) - if v.typ().Elem().Kind() != abi.Int32 { - panic("reflect.Value.setRunes of non-rune slice") - } - *(*[]rune)(v.ptr) = x -} - -// SetComplex sets v's underlying value to x. -// It panics if v's Kind is not [Complex64] or [Complex128], or if [Value.CanSet] returns false. -func (v Value) SetComplex(x complex128) { - v.mustBeAssignable() - switch k := v.kind(); k { - default: - panic(&ValueError{"reflect.Value.SetComplex", v.kind()}) - case Complex64: - *(*complex64)(v.ptr) = complex64(x) - case Complex128: - *(*complex128)(v.ptr) = x - } -} - -// SetFloat sets v's underlying value to x. -// It panics if v's Kind is not [Float32] or [Float64], or if [Value.CanSet] returns false. -func (v Value) SetFloat(x float64) { - v.mustBeAssignable() - switch k := v.kind(); k { - default: - panic(&ValueError{"reflect.Value.SetFloat", v.kind()}) - case Float32: - *(*float32)(v.ptr) = float32(x) - case Float64: - *(*float64)(v.ptr) = x - } -} - -// SetInt sets v's underlying value to x. -// It panics if v's Kind is not [Int], [Int8], [Int16], [Int32], or [Int64], or if [Value.CanSet] returns false. -func (v Value) SetInt(x int64) { - v.mustBeAssignable() - switch k := v.kind(); k { - default: - panic(&ValueError{"reflect.Value.SetInt", v.kind()}) - case Int: - *(*int)(v.ptr) = int(x) - case Int8: - *(*int8)(v.ptr) = int8(x) - case Int16: - *(*int16)(v.ptr) = int16(x) - case Int32: - *(*int32)(v.ptr) = int32(x) - case Int64: - *(*int64)(v.ptr) = x - } -} - -// SetLen sets v's length to n. -// It panics if v's Kind is not [Slice] or if n is negative or -// greater than the capacity of the slice. -func (v Value) SetLen(n int) { - v.mustBeAssignable() - v.mustBe(Slice) - s := (*unsafeheader.Slice)(v.ptr) - if uint(n) > uint(s.Cap) { - panic("reflect: slice length out of range in SetLen") - } - s.Len = n -} - -// SetCap sets v's capacity to n. -// It panics if v's Kind is not [Slice] or if n is smaller than the length or -// greater than the capacity of the slice. -func (v Value) SetCap(n int) { - v.mustBeAssignable() - v.mustBe(Slice) - s := (*unsafeheader.Slice)(v.ptr) - if n < s.Len || n > s.Cap { - panic("reflect: slice capacity out of range in SetCap") - } - s.Cap = n -} - -// SetMapIndex sets the element associated with key in the map v to elem. -// It panics if v's Kind is not [Map]. -// If elem is the zero Value, SetMapIndex deletes the key from the map. -// Otherwise if v holds a nil map, SetMapIndex will panic. -// As in Go, key's elem must be assignable to the map's key type, -// and elem's value must be assignable to the map's elem type. -func (v Value) SetMapIndex(key, elem Value) { - v.mustBe(Map) - v.mustBeExported() - key.mustBeExported() - tt := (*mapType)(unsafe.Pointer(v.typ())) - - if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= maxValSize { - k := *(*string)(key.ptr) - if elem.typ() == nil { - mapdelete_faststr(v.typ(), v.pointer(), k) - return - } - elem.mustBeExported() - elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil) - var e unsafe.Pointer - if elem.flag&flagIndir != 0 { - e = elem.ptr - } else { - e = unsafe.Pointer(&elem.ptr) - } - mapassign_faststr(v.typ(), v.pointer(), k, e) - return - } - - key = key.assignTo("reflect.Value.SetMapIndex", tt.Key, nil) - var k unsafe.Pointer - if key.flag&flagIndir != 0 { - k = key.ptr - } else { - k = unsafe.Pointer(&key.ptr) - } - if elem.typ() == nil { - mapdelete(v.typ(), v.pointer(), k) - return - } - elem.mustBeExported() - elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil) - var e unsafe.Pointer - if elem.flag&flagIndir != 0 { - e = elem.ptr - } else { - e = unsafe.Pointer(&elem.ptr) - } - mapassign(v.typ(), v.pointer(), k, e) -} - -// SetUint sets v's underlying value to x. -// It panics if v's Kind is not [Uint], [Uintptr], [Uint8], [Uint16], [Uint32], or [Uint64], or if [Value.CanSet] returns false. -func (v Value) SetUint(x uint64) { - v.mustBeAssignable() - switch k := v.kind(); k { - default: - panic(&ValueError{"reflect.Value.SetUint", v.kind()}) - case Uint: - *(*uint)(v.ptr) = uint(x) - case Uint8: - *(*uint8)(v.ptr) = uint8(x) - case Uint16: - *(*uint16)(v.ptr) = uint16(x) - case Uint32: - *(*uint32)(v.ptr) = uint32(x) - case Uint64: - *(*uint64)(v.ptr) = x - case Uintptr: - *(*uintptr)(v.ptr) = uintptr(x) - } -} - -// SetPointer sets the [unsafe.Pointer] value v to x. -// It panics if v's Kind is not UnsafePointer. -func (v Value) SetPointer(x unsafe.Pointer) { - v.mustBeAssignable() - v.mustBe(UnsafePointer) - *(*unsafe.Pointer)(v.ptr) = x -} - -// SetString sets v's underlying value to x. -// It panics if v's Kind is not [String] or if [Value.CanSet] returns false. -func (v Value) SetString(x string) { - v.mustBeAssignable() - v.mustBe(String) - *(*string)(v.ptr) = x -} - -// Slice returns v[i:j]. -// It panics if v's Kind is not [Array], [Slice] or [String], or if v is an unaddressable array, -// or if the indexes are out of bounds. -func (v Value) Slice(i, j int) Value { - var ( - cap int - typ *sliceType - base unsafe.Pointer - ) - switch kind := v.kind(); kind { - default: - panic(&ValueError{"reflect.Value.Slice", v.kind()}) - - case Array: - if v.flag&flagAddr == 0 { - panic("reflect.Value.Slice: slice of unaddressable array") - } - tt := (*arrayType)(unsafe.Pointer(v.typ())) - cap = int(tt.Len) - typ = (*sliceType)(unsafe.Pointer(tt.Slice)) - base = v.ptr - - case Slice: - typ = (*sliceType)(unsafe.Pointer(v.typ())) - s := (*unsafeheader.Slice)(v.ptr) - base = s.Data - cap = s.Cap - - case String: - s := (*unsafeheader.String)(v.ptr) - if i < 0 || j < i || j > s.Len { - panic("reflect.Value.Slice: string slice index out of bounds") - } - var t unsafeheader.String - if i < s.Len { - t = unsafeheader.String{Data: arrayAt(s.Data, i, 1, "i < s.Len"), Len: j - i} - } - return Value{v.typ(), unsafe.Pointer(&t), v.flag} - } - - if i < 0 || j < i || j > cap { - panic("reflect.Value.Slice: slice index out of bounds") - } - - // Declare slice so that gc can see the base pointer in it. - var x []unsafe.Pointer - - // Reinterpret as *unsafeheader.Slice to edit. - s := (*unsafeheader.Slice)(unsafe.Pointer(&x)) - s.Len = j - i - s.Cap = cap - i - if cap-i > 0 { - s.Data = arrayAt(base, i, typ.Elem.Size(), "i < cap") - } else { - // do not advance pointer, to avoid pointing beyond end of slice - s.Data = base - } - - fl := v.flag.ro() | flagIndir | flag(Slice) - return Value{typ.Common(), unsafe.Pointer(&x), fl} -} - -// Slice3 is the 3-index form of the slice operation: it returns v[i:j:k]. -// It panics if v's Kind is not [Array] or [Slice], or if v is an unaddressable array, -// or if the indexes are out of bounds. -func (v Value) Slice3(i, j, k int) Value { - var ( - cap int - typ *sliceType - base unsafe.Pointer - ) - switch kind := v.kind(); kind { - default: - panic(&ValueError{"reflect.Value.Slice3", v.kind()}) - - case Array: - if v.flag&flagAddr == 0 { - panic("reflect.Value.Slice3: slice of unaddressable array") - } - tt := (*arrayType)(unsafe.Pointer(v.typ())) - cap = int(tt.Len) - typ = (*sliceType)(unsafe.Pointer(tt.Slice)) - base = v.ptr - - case Slice: - typ = (*sliceType)(unsafe.Pointer(v.typ())) - s := (*unsafeheader.Slice)(v.ptr) - base = s.Data - cap = s.Cap - } - - if i < 0 || j < i || k < j || k > cap { - panic("reflect.Value.Slice3: slice index out of bounds") - } - - // Declare slice so that the garbage collector - // can see the base pointer in it. - var x []unsafe.Pointer - - // Reinterpret as *unsafeheader.Slice to edit. - s := (*unsafeheader.Slice)(unsafe.Pointer(&x)) - s.Len = j - i - s.Cap = k - i - if k-i > 0 { - s.Data = arrayAt(base, i, typ.Elem.Size(), "i < k <= cap") - } else { - // do not advance pointer, to avoid pointing beyond end of slice - s.Data = base - } - - fl := v.flag.ro() | flagIndir | flag(Slice) - return Value{typ.Common(), unsafe.Pointer(&x), fl} -} - -// String returns the string v's underlying value, as a string. -// String is a special case because of Go's String method convention. -// Unlike the other getters, it does not panic if v's Kind is not [String]. -// Instead, it returns a string of the form "" where T is v's type. -// The fmt package treats Values specially. It does not call their String -// method implicitly but instead prints the concrete values they hold. -func (v Value) String() string { - // stringNonString is split out to keep String inlineable for string kinds. - if v.kind() == String { - return *(*string)(v.ptr) - } - return v.stringNonString() -} - -func (v Value) stringNonString() string { - if v.kind() == Invalid { - return "" - } - // If you call String on a reflect.Value of other type, it's better to - // print something than to panic. Useful in debugging. - return "<" + v.Type().String() + " Value>" -} - -// TryRecv attempts to receive a value from the channel v but will not block. -// It panics if v's Kind is not [Chan]. -// If the receive delivers a value, x is the transferred value and ok is true. -// If the receive cannot finish without blocking, x is the zero Value and ok is false. -// If the channel is closed, x is the zero value for the channel's element type and ok is false. -func (v Value) TryRecv() (x Value, ok bool) { - v.mustBe(Chan) - v.mustBeExported() - return v.recv(true) -} - -// TrySend attempts to send x on the channel v but will not block. -// It panics if v's Kind is not [Chan]. -// It reports whether the value was sent. -// As in Go, x's value must be assignable to the channel's element type. -func (v Value) TrySend(x Value) bool { - v.mustBe(Chan) - v.mustBeExported() - return v.send(x, true) -} - -// Type returns v's type. -func (v Value) Type() Type { - if v.flag != 0 && v.flag&flagMethod == 0 { - return (*rtype)(noescape(unsafe.Pointer(v.typ_))) // inline of toRType(v.typ()), for own inlining in inline test - } - return v.typeSlow() -} - -func (v Value) typeSlow() Type { - if v.flag == 0 { - panic(&ValueError{"reflect.Value.Type", Invalid}) - } - - typ := v.typ() - if v.flag&flagMethod == 0 { - return toRType(v.typ()) - } - - // Method value. - // v.typ describes the receiver, not the method type. - i := int(v.flag) >> flagMethodShift - if v.typ().Kind() == abi.Interface { - // Method on interface. - tt := (*interfaceType)(unsafe.Pointer(typ)) - if uint(i) >= uint(len(tt.Methods)) { - panic("reflect: internal error: invalid method index") - } - m := &tt.Methods[i] - return toRType(typeOffFor(typ, m.Typ)) - } - // Method on concrete type. - ms := typ.ExportedMethods() - if uint(i) >= uint(len(ms)) { - panic("reflect: internal error: invalid method index") - } - m := ms[i] - return toRType(typeOffFor(typ, m.Mtyp)) -} - -// CanUint reports whether [Value.Uint] can be used without panicking. -func (v Value) CanUint() bool { - switch v.kind() { - case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return true - default: - return false - } -} - -// Uint returns v's underlying value, as a uint64. -// It panics if v's Kind is not [Uint], [Uintptr], [Uint8], [Uint16], [Uint32], or [Uint64]. -func (v Value) Uint() uint64 { - k := v.kind() - p := v.ptr - switch k { - case Uint: - return uint64(*(*uint)(p)) - case Uint8: - return uint64(*(*uint8)(p)) - case Uint16: - return uint64(*(*uint16)(p)) - case Uint32: - return uint64(*(*uint32)(p)) - case Uint64: - return *(*uint64)(p) - case Uintptr: - return uint64(*(*uintptr)(p)) - } - panic(&ValueError{"reflect.Value.Uint", v.kind()}) -} - -//go:nocheckptr -// This prevents inlining Value.UnsafeAddr when -d=checkptr is enabled, -// which ensures cmd/compile can recognize unsafe.Pointer(v.UnsafeAddr()) -// and make an exception. - -// UnsafeAddr returns a pointer to v's data, as a uintptr. -// It panics if v is not addressable. -// -// It's preferred to use uintptr(Value.Addr().UnsafePointer()) to get the equivalent result. -func (v Value) UnsafeAddr() uintptr { - if v.typ() == nil { - panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid}) - } - if v.flag&flagAddr == 0 { - panic("reflect.Value.UnsafeAddr of unaddressable value") - } - // The compiler loses track as it converts to uintptr. Force escape. - escapes(v.ptr) - return uintptr(v.ptr) -} - -// UnsafePointer returns v's value as a [unsafe.Pointer]. -// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], or [UnsafePointer]. -// -// If v's Kind is [Func], the returned pointer is an underlying -// code pointer, but not necessarily enough to identify a -// single function uniquely. The only guarantee is that the -// result is zero if and only if v is a nil func Value. -// -// If v's Kind is [Slice], the returned pointer is to the first -// element of the slice. If the slice is nil the returned value -// is nil. If the slice is empty but non-nil the return value is non-nil. -func (v Value) UnsafePointer() unsafe.Pointer { - k := v.kind() - switch k { - case Pointer: - if v.typ().PtrBytes == 0 { - // Since it is a not-in-heap pointer, all pointers to the heap are - // forbidden! See comment in Value.Elem and issue #48399. - if !verifyNotInHeapPtr(*(*uintptr)(v.ptr)) { - panic("reflect: reflect.Value.UnsafePointer on an invalid notinheap pointer") - } - return *(*unsafe.Pointer)(v.ptr) - } - fallthrough - case Chan, Map, UnsafePointer: - return v.pointer() - case Func: - if v.flag&flagMethod != 0 { - // As the doc comment says, the returned pointer is an - // underlying code pointer but not necessarily enough to - // identify a single function uniquely. All method expressions - // created via reflect have the same underlying code pointer, - // so their Pointers are equal. The function used here must - // match the one used in makeMethodValue. - code := methodValueCallCodePtr() - return *(*unsafe.Pointer)(unsafe.Pointer(&code)) - } - p := v.pointer() - // Non-nil func value points at data block. - // First word of data block is actual code. - if p != nil { - p = *(*unsafe.Pointer)(p) - } - return p - - case Slice: - return (*unsafeheader.Slice)(v.ptr).Data - } - panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()}) -} - -// StringHeader is the runtime representation of a string. -// It cannot be used safely or portably and its representation may -// change in a later release. -// Moreover, the Data field is not sufficient to guarantee the data -// it references will not be garbage collected, so programs must keep -// a separate, correctly typed pointer to the underlying data. -// -// Deprecated: Use unsafe.String or unsafe.StringData instead. -type StringHeader struct { - Data uintptr - Len int -} - -// SliceHeader is the runtime representation of a slice. -// It cannot be used safely or portably and its representation may -// change in a later release. -// Moreover, the Data field is not sufficient to guarantee the data -// it references will not be garbage collected, so programs must keep -// a separate, correctly typed pointer to the underlying data. -// -// Deprecated: Use unsafe.Slice or unsafe.SliceData instead. -type SliceHeader struct { - Data uintptr - Len int - Cap int -} - -func typesMustMatch(what string, t1, t2 Type) { - if t1 != t2 { - panic(what + ": " + t1.String() + " != " + t2.String()) - } -} - -// arrayAt returns the i-th element of p, -// an array whose elements are eltSize bytes wide. -// The array pointed at by p must have at least i+1 elements: -// it is invalid (but impossible to check here) to pass i >= len, -// because then the result will point outside the array. -// whySafe must explain why i < len. (Passing "i < len" is fine; -// the benefit is to surface this assumption at the call site.) -func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer { - return add(p, uintptr(i)*eltSize, "i < len") -} - -// Grow increases the slice's capacity, if necessary, to guarantee space for -// another n elements. After Grow(n), at least n elements can be appended -// to the slice without another allocation. -// -// It panics if v's Kind is not a [Slice] or if n is negative or too large to -// allocate the memory. -func (v Value) Grow(n int) { - v.mustBeAssignable() - v.mustBe(Slice) - v.grow(n) -} - -// grow is identical to Grow but does not check for assignability. -func (v Value) grow(n int) { - p := (*unsafeheader.Slice)(v.ptr) - switch { - case n < 0: - panic("reflect.Value.Grow: negative len") - case p.Len+n < 0: - panic("reflect.Value.Grow: slice overflow") - case p.Len+n > p.Cap: - t := v.typ().Elem() - *p = growslice(t, *p, n) - } -} - -// extendSlice extends a slice by n elements. -// -// Unlike Value.grow, which modifies the slice in place and -// does not change the length of the slice in place, -// extendSlice returns a new slice value with the length -// incremented by the number of specified elements. -func (v Value) extendSlice(n int) Value { - v.mustBeExported() - v.mustBe(Slice) - - // Shallow copy the slice header to avoid mutating the source slice. - sh := *(*unsafeheader.Slice)(v.ptr) - s := &sh - v.ptr = unsafe.Pointer(s) - v.flag = flagIndir | flag(Slice) // equivalent flag to MakeSlice - - v.grow(n) // fine to treat as assignable since we allocate a new slice header - s.Len += n - return v -} - -// Clear clears the contents of a map or zeros the contents of a slice. -// -// It panics if v's Kind is not [Map] or [Slice]. -func (v Value) Clear() { - switch v.Kind() { - case Slice: - sh := *(*unsafeheader.Slice)(v.ptr) - st := (*sliceType)(unsafe.Pointer(v.typ())) - typedarrayclear(st.Elem, sh.Data, sh.Len) - case Map: - mapclear(v.typ(), v.pointer()) - default: - panic(&ValueError{"reflect.Value.Clear", v.Kind()}) - } -} - -// Append appends the values x to a slice s and returns the resulting slice. -// As in Go, each x's value must be assignable to the slice's element type. -func Append(s Value, x ...Value) Value { - s.mustBe(Slice) - n := s.Len() - s = s.extendSlice(len(x)) - for i, v := range x { - s.Index(n + i).Set(v) - } - return s -} - -// AppendSlice appends a slice t to a slice s and returns the resulting slice. -// The slices s and t must have the same element type. -func AppendSlice(s, t Value) Value { - s.mustBe(Slice) - t.mustBe(Slice) - typesMustMatch("reflect.AppendSlice", s.Type().Elem(), t.Type().Elem()) - ns := s.Len() - nt := t.Len() - s = s.extendSlice(nt) - Copy(s.Slice(ns, ns+nt), t) - return s -} - -// Copy copies the contents of src into dst until either -// dst has been filled or src has been exhausted. -// It returns the number of elements copied. -// Dst and src each must have kind [Slice] or [Array], and -// dst and src must have the same element type. -// -// As a special case, src can have kind [String] if the element type of dst is kind [Uint8]. -func Copy(dst, src Value) int { - dk := dst.kind() - if dk != Array && dk != Slice { - panic(&ValueError{"reflect.Copy", dk}) - } - if dk == Array { - dst.mustBeAssignable() - } - dst.mustBeExported() - - sk := src.kind() - var stringCopy bool - if sk != Array && sk != Slice { - stringCopy = sk == String && dst.typ().Elem().Kind() == abi.Uint8 - if !stringCopy { - panic(&ValueError{"reflect.Copy", sk}) - } - } - src.mustBeExported() - - de := dst.typ().Elem() - if !stringCopy { - se := src.typ().Elem() - typesMustMatch("reflect.Copy", toType(de), toType(se)) - } - - var ds, ss unsafeheader.Slice - if dk == Array { - ds.Data = dst.ptr - ds.Len = dst.Len() - ds.Cap = ds.Len - } else { - ds = *(*unsafeheader.Slice)(dst.ptr) - } - if sk == Array { - ss.Data = src.ptr - ss.Len = src.Len() - ss.Cap = ss.Len - } else if sk == Slice { - ss = *(*unsafeheader.Slice)(src.ptr) - } else { - sh := *(*unsafeheader.String)(src.ptr) - ss.Data = sh.Data - ss.Len = sh.Len - ss.Cap = sh.Len - } - - return typedslicecopy(de.Common(), ds, ss) -} - -// A runtimeSelect is a single case passed to rselect. -// This must match ../runtime/select.go:/runtimeSelect -type runtimeSelect struct { - dir SelectDir // SelectSend, SelectRecv or SelectDefault - typ *rtype // channel type - ch unsafe.Pointer // channel - val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir) -} - -// rselect runs a select. It returns the index of the chosen case. -// If the case was a receive, val is filled in with the received value. -// The conventional OK bool indicates whether the receive corresponds -// to a sent value. -// -// rselect generally doesn't escape the runtimeSelect slice, except -// that for the send case the value to send needs to escape. We don't -// have a way to represent that in the function signature. So we handle -// that with a forced escape in function Select. -// -//go:noescape -func rselect([]runtimeSelect) (chosen int, recvOK bool) - -// A SelectDir describes the communication direction of a select case. -type SelectDir int - -// NOTE: These values must match ../runtime/select.go:/selectDir. - -const ( - _ SelectDir = iota - SelectSend // case Chan <- Send - SelectRecv // case <-Chan: - SelectDefault // default -) - -// A SelectCase describes a single case in a select operation. -// The kind of case depends on Dir, the communication direction. -// -// If Dir is SelectDefault, the case represents a default case. -// Chan and Send must be zero Values. -// -// If Dir is SelectSend, the case represents a send operation. -// Normally Chan's underlying value must be a channel, and Send's underlying value must be -// assignable to the channel's element type. As a special case, if Chan is a zero Value, -// then the case is ignored, and the field Send will also be ignored and may be either zero -// or non-zero. -// -// If Dir is SelectRecv, the case represents a receive operation. -// Normally Chan's underlying value must be a channel and Send must be a zero Value. -// If Chan is a zero Value, then the case is ignored, but Send must still be a zero Value. -// When a receive operation is selected, the received Value is returned by Select. -type SelectCase struct { - Dir SelectDir // direction of case - Chan Value // channel to use (for send or receive) - Send Value // value to send (for send) -} - -// Select executes a select operation described by the list of cases. -// Like the Go select statement, it blocks until at least one of the cases -// can proceed, makes a uniform pseudo-random choice, -// and then executes that case. It returns the index of the chosen case -// and, if that case was a receive operation, the value received and a -// boolean indicating whether the value corresponds to a send on the channel -// (as opposed to a zero value received because the channel is closed). -// Select supports a maximum of 65536 cases. -func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { - if len(cases) > 65536 { - panic("reflect.Select: too many cases (max 65536)") - } - // NOTE: Do not trust that caller is not modifying cases data underfoot. - // The range is safe because the caller cannot modify our copy of the len - // and each iteration makes its own copy of the value c. - var runcases []runtimeSelect - if len(cases) > 4 { - // Slice is heap allocated due to runtime dependent capacity. - runcases = make([]runtimeSelect, len(cases)) - } else { - // Slice can be stack allocated due to constant capacity. - runcases = make([]runtimeSelect, len(cases), 4) - } - - haveDefault := false - for i, c := range cases { - rc := &runcases[i] - rc.dir = c.Dir - switch c.Dir { - default: - panic("reflect.Select: invalid Dir") - - case SelectDefault: // default - if haveDefault { - panic("reflect.Select: multiple default cases") - } - haveDefault = true - if c.Chan.IsValid() { - panic("reflect.Select: default case has Chan value") - } - if c.Send.IsValid() { - panic("reflect.Select: default case has Send value") - } - - case SelectSend: - ch := c.Chan - if !ch.IsValid() { - break - } - ch.mustBe(Chan) - ch.mustBeExported() - tt := (*chanType)(unsafe.Pointer(ch.typ())) - if ChanDir(tt.Dir)&SendDir == 0 { - panic("reflect.Select: SendDir case using recv-only channel") - } - rc.ch = ch.pointer() - rc.typ = toRType(&tt.Type) - v := c.Send - if !v.IsValid() { - panic("reflect.Select: SendDir case missing Send value") - } - v.mustBeExported() - v = v.assignTo("reflect.Select", tt.Elem, nil) - if v.flag&flagIndir != 0 { - rc.val = v.ptr - } else { - rc.val = unsafe.Pointer(&v.ptr) - } - // The value to send needs to escape. See the comment at rselect for - // why we need forced escape. - escapes(rc.val) - - case SelectRecv: - if c.Send.IsValid() { - panic("reflect.Select: RecvDir case has Send value") - } - ch := c.Chan - if !ch.IsValid() { - break - } - ch.mustBe(Chan) - ch.mustBeExported() - tt := (*chanType)(unsafe.Pointer(ch.typ())) - if ChanDir(tt.Dir)&RecvDir == 0 { - panic("reflect.Select: RecvDir case using send-only channel") - } - rc.ch = ch.pointer() - rc.typ = toRType(&tt.Type) - rc.val = unsafe_New(tt.Elem) - } - } - - chosen, recvOK = rselect(runcases) - if runcases[chosen].dir == SelectRecv { - tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ)) - t := tt.Elem - p := runcases[chosen].val - fl := flag(t.Kind()) - if t.IfaceIndir() { - recv = Value{t, p, fl | flagIndir} - } else { - recv = Value{t, *(*unsafe.Pointer)(p), fl} - } - } - return chosen, recv, recvOK -} - -/* - * constructors - */ - -// implemented in package runtime - -//go:noescape -func unsafe_New(*abi.Type) unsafe.Pointer - -//go:noescape -func unsafe_NewArray(*abi.Type, int) unsafe.Pointer - -// MakeSlice creates a new zero-initialized slice value -// for the specified slice type, length, and capacity. -func MakeSlice(typ Type, len, cap int) Value { - if typ.Kind() != Slice { - panic("reflect.MakeSlice of non-slice type") - } - if len < 0 { - panic("reflect.MakeSlice: negative len") - } - if cap < 0 { - panic("reflect.MakeSlice: negative cap") - } - if len > cap { - panic("reflect.MakeSlice: len > cap") - } - - s := unsafeheader.Slice{Data: unsafe_NewArray(&(typ.Elem().(*rtype).t), cap), Len: len, Cap: cap} - return Value{&typ.(*rtype).t, unsafe.Pointer(&s), flagIndir | flag(Slice)} -} - -// MakeChan creates a new channel with the specified type and buffer size. -func MakeChan(typ Type, buffer int) Value { - if typ.Kind() != Chan { - panic("reflect.MakeChan of non-chan type") - } - if buffer < 0 { - panic("reflect.MakeChan: negative buffer size") - } - if typ.ChanDir() != BothDir { - panic("reflect.MakeChan: unidirectional channel type") - } - t := typ.common() - ch := makechan(t, buffer) - return Value{t, ch, flag(Chan)} -} - -// MakeMap creates a new map with the specified type. -func MakeMap(typ Type) Value { - return MakeMapWithSize(typ, 0) -} - -// MakeMapWithSize creates a new map with the specified type -// and initial space for approximately n elements. -func MakeMapWithSize(typ Type, n int) Value { - if typ.Kind() != Map { - panic("reflect.MakeMapWithSize of non-map type") - } - t := typ.common() - m := makemap(t, n) - return Value{t, m, flag(Map)} -} - -// Indirect returns the value that v points to. -// If v is a nil pointer, Indirect returns a zero Value. -// If v is not a pointer, Indirect returns v. -func Indirect(v Value) Value { - if v.Kind() != Pointer { - return v - } - return v.Elem() -} - -// ValueOf returns a new Value initialized to the concrete value -// stored in the interface i. ValueOf(nil) returns the zero Value. -func ValueOf(i any) Value { - if i == nil { - return Value{} - } - return unpackEface(i) -} - -// Zero returns a Value representing the zero value for the specified type. -// The result is different from the zero value of the Value struct, -// which represents no value at all. -// For example, Zero(TypeOf(42)) returns a Value with Kind [Int] and value 0. -// The returned value is neither addressable nor settable. -func Zero(typ Type) Value { - if typ == nil { - panic("reflect: Zero(nil)") - } - t := &typ.(*rtype).t - fl := flag(t.Kind()) - if t.IfaceIndir() { - var p unsafe.Pointer - if t.Size() <= abi.ZeroValSize { - p = unsafe.Pointer(&zeroVal[0]) - } else { - p = unsafe_New(t) - } - return Value{t, p, fl | flagIndir} - } - return Value{t, nil, fl} -} - -//go:linkname zeroVal runtime.zeroVal -var zeroVal [abi.ZeroValSize]byte - -// New returns a Value representing a pointer to a new zero value -// for the specified type. That is, the returned Value's Type is PointerTo(typ). -func New(typ Type) Value { - if typ == nil { - panic("reflect: New(nil)") - } - t := &typ.(*rtype).t - pt := ptrTo(t) - if ifaceIndir(pt) { - // This is a pointer to a not-in-heap type. - panic("reflect: New of type that may not be allocated in heap (possibly undefined cgo C type)") - } - ptr := unsafe_New(t) - fl := flag(Pointer) - return Value{pt, ptr, fl} -} - -// NewAt returns a Value representing a pointer to a value of the -// specified type, using p as that pointer. -func NewAt(typ Type, p unsafe.Pointer) Value { - fl := flag(Pointer) - t := typ.(*rtype) - return Value{t.ptrTo(), p, fl} -} - -// assignTo returns a value v that can be assigned directly to dst. -// It panics if v is not assignable to dst. -// For a conversion to an interface type, target, if not nil, -// is a suggested scratch space to use. -// target must be initialized memory (or nil). -func (v Value) assignTo(context string, dst *abi.Type, target unsafe.Pointer) Value { - if v.flag&flagMethod != 0 { - v = makeMethodValue(context, v) - } - - switch { - case directlyAssignable(dst, v.typ()): - // Overwrite type so that they match. - // Same memory layout, so no harm done. - fl := v.flag&(flagAddr|flagIndir) | v.flag.ro() - fl |= flag(dst.Kind()) - return Value{dst, v.ptr, fl} - - case implements(dst, v.typ()): - if v.Kind() == Interface && v.IsNil() { - // A nil ReadWriter passed to nil Reader is OK, - // but using ifaceE2I below will panic. - // Avoid the panic by returning a nil dst (e.g., Reader) explicitly. - return Value{dst, nil, flag(Interface)} - } - x := valueInterface(v, false) - if target == nil { - target = unsafe_New(dst) - } - if dst.NumMethod() == 0 { - *(*any)(target) = x - } else { - ifaceE2I(dst, x, target) - } - return Value{dst, target, flagIndir | flag(Interface)} - } - - // Failed. - panic(context + ": value of type " + stringFor(v.typ()) + " is not assignable to type " + stringFor(dst)) -} - -// Convert returns the value v converted to type t. -// If the usual Go conversion rules do not allow conversion -// of the value v to type t, or if converting v to type t panics, Convert panics. -func (v Value) Convert(t Type) Value { - if v.flag&flagMethod != 0 { - v = makeMethodValue("Convert", v) - } - op := convertOp(t.common(), v.typ()) - if op == nil { - panic("reflect.Value.Convert: value of type " + stringFor(v.typ()) + " cannot be converted to type " + t.String()) - } - return op(v, t) -} - -// CanConvert reports whether the value v can be converted to type t. -// If v.CanConvert(t) returns true then v.Convert(t) will not panic. -func (v Value) CanConvert(t Type) bool { - vt := v.Type() - if !vt.ConvertibleTo(t) { - return false - } - // Converting from slice to array or to pointer-to-array can panic - // depending on the value. - switch { - case vt.Kind() == Slice && t.Kind() == Array: - if t.Len() > v.Len() { - return false - } - case vt.Kind() == Slice && t.Kind() == Pointer && t.Elem().Kind() == Array: - n := t.Elem().Len() - if n > v.Len() { - return false - } - } - return true -} - -// Comparable reports whether the value v is comparable. -// If the type of v is an interface, this checks the dynamic type. -// If this reports true then v.Interface() == x will not panic for any x, -// nor will v.Equal(u) for any Value u. -func (v Value) Comparable() bool { - k := v.Kind() - switch k { - case Invalid: - return false - - case Array: - switch v.Type().Elem().Kind() { - case Interface, Array, Struct: - for i := 0; i < v.Type().Len(); i++ { - if !v.Index(i).Comparable() { - return false - } - } - return true - } - return v.Type().Comparable() - - case Interface: - return v.Elem().Comparable() - - case Struct: - for i := 0; i < v.NumField(); i++ { - if !v.Field(i).Comparable() { - return false - } - } - return true - - default: - return v.Type().Comparable() - } -} - -// Equal reports true if v is equal to u. -// For two invalid values, Equal will report true. -// For an interface value, Equal will compare the value within the interface. -// Otherwise, If the values have different types, Equal will report false. -// Otherwise, for arrays and structs Equal will compare each element in order, -// and report false if it finds non-equal elements. -// During all comparisons, if values of the same type are compared, -// and the type is not comparable, Equal will panic. -func (v Value) Equal(u Value) bool { - if v.Kind() == Interface { - v = v.Elem() - } - if u.Kind() == Interface { - u = u.Elem() - } - - if !v.IsValid() || !u.IsValid() { - return v.IsValid() == u.IsValid() - } - - if v.Kind() != u.Kind() || v.Type() != u.Type() { - return false - } - - // Handle each Kind directly rather than calling valueInterface - // to avoid allocating. - switch v.Kind() { - default: - panic("reflect.Value.Equal: invalid Kind") - case Bool: - return v.Bool() == u.Bool() - case Int, Int8, Int16, Int32, Int64: - return v.Int() == u.Int() - case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return v.Uint() == u.Uint() - case Float32, Float64: - return v.Float() == u.Float() - case Complex64, Complex128: - return v.Complex() == u.Complex() - case String: - return v.String() == u.String() - case Chan, Pointer, UnsafePointer: - return v.Pointer() == u.Pointer() - case Array: - // u and v have the same type so they have the same length - vl := v.Len() - if vl == 0 { - // panic on [0]func() - if !v.Type().Elem().Comparable() { - break - } - return true - } - for i := 0; i < vl; i++ { - if !v.Index(i).Equal(u.Index(i)) { - return false - } - } - return true - case Struct: - // u and v have the same type so they have the same fields - nf := v.NumField() - for i := 0; i < nf; i++ { - if !v.Field(i).Equal(u.Field(i)) { - return false - } - } - return true - case Func, Map, Slice: - break - } - panic("reflect.Value.Equal: values of type " + v.Type().String() + " are not comparable") -} - -// convertOp returns the function to convert a value of type src -// to a value of type dst. If the conversion is illegal, convertOp returns nil. -func convertOp(dst, src *abi.Type) func(Value, Type) Value { - switch Kind(src.Kind()) { - case Int, Int8, Int16, Int32, Int64: - switch Kind(dst.Kind()) { - case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return cvtInt - case Float32, Float64: - return cvtIntFloat - case String: - return cvtIntString - } - - case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - switch Kind(dst.Kind()) { - case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return cvtUint - case Float32, Float64: - return cvtUintFloat - case String: - return cvtUintString - } - - case Float32, Float64: - switch Kind(dst.Kind()) { - case Int, Int8, Int16, Int32, Int64: - return cvtFloatInt - case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return cvtFloatUint - case Float32, Float64: - return cvtFloat - } - - case Complex64, Complex128: - switch Kind(dst.Kind()) { - case Complex64, Complex128: - return cvtComplex - } - - case String: - if dst.Kind() == abi.Slice && pkgPathFor(dst.Elem()) == "" { - switch Kind(dst.Elem().Kind()) { - case Uint8: - return cvtStringBytes - case Int32: - return cvtStringRunes - } - } - - case Slice: - if dst.Kind() == abi.String && pkgPathFor(src.Elem()) == "" { - switch Kind(src.Elem().Kind()) { - case Uint8: - return cvtBytesString - case Int32: - return cvtRunesString - } - } - // "x is a slice, T is a pointer-to-array type, - // and the slice and array types have identical element types." - if dst.Kind() == abi.Pointer && dst.Elem().Kind() == abi.Array && src.Elem() == dst.Elem().Elem() { - return cvtSliceArrayPtr - } - // "x is a slice, T is an array type, - // and the slice and array types have identical element types." - if dst.Kind() == abi.Array && src.Elem() == dst.Elem() { - return cvtSliceArray - } - - case Chan: - if dst.Kind() == abi.Chan && specialChannelAssignability(dst, src) { - return cvtDirect - } - } - - // dst and src have same underlying type. - if haveIdenticalUnderlyingType(dst, src, false) { - return cvtDirect - } - - // dst and src are non-defined pointer types with same underlying base type. - if dst.Kind() == abi.Pointer && nameFor(dst) == "" && - src.Kind() == abi.Pointer && nameFor(src) == "" && - haveIdenticalUnderlyingType(elem(dst), elem(src), false) { - return cvtDirect - } - - if implements(dst, src) { - if src.Kind() == abi.Interface { - return cvtI2I - } - return cvtT2I - } - - return nil -} - -// makeInt returns a Value of type t equal to bits (possibly truncated), -// where t is a signed or unsigned int type. -func makeInt(f flag, bits uint64, t Type) Value { - typ := t.common() - ptr := unsafe_New(typ) - switch typ.Size() { - case 1: - *(*uint8)(ptr) = uint8(bits) - case 2: - *(*uint16)(ptr) = uint16(bits) - case 4: - *(*uint32)(ptr) = uint32(bits) - case 8: - *(*uint64)(ptr) = bits - } - return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} -} - -// makeFloat returns a Value of type t equal to v (possibly truncated to float32), -// where t is a float32 or float64 type. -func makeFloat(f flag, v float64, t Type) Value { - typ := t.common() - ptr := unsafe_New(typ) - switch typ.Size() { - case 4: - *(*float32)(ptr) = float32(v) - case 8: - *(*float64)(ptr) = v - } - return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} -} - -// makeFloat32 returns a Value of type t equal to v, where t is a float32 type. -func makeFloat32(f flag, v float32, t Type) Value { - typ := t.common() - ptr := unsafe_New(typ) - *(*float32)(ptr) = v - return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} -} - -// makeComplex returns a Value of type t equal to v (possibly truncated to complex64), -// where t is a complex64 or complex128 type. -func makeComplex(f flag, v complex128, t Type) Value { - typ := t.common() - ptr := unsafe_New(typ) - switch typ.Size() { - case 8: - *(*complex64)(ptr) = complex64(v) - case 16: - *(*complex128)(ptr) = v - } - return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} -} - -func makeString(f flag, v string, t Type) Value { - ret := New(t).Elem() - ret.SetString(v) - ret.flag = ret.flag&^flagAddr | f - return ret -} - -func makeBytes(f flag, v []byte, t Type) Value { - ret := New(t).Elem() - ret.SetBytes(v) - ret.flag = ret.flag&^flagAddr | f - return ret -} - -func makeRunes(f flag, v []rune, t Type) Value { - ret := New(t).Elem() - ret.setRunes(v) - ret.flag = ret.flag&^flagAddr | f - return ret -} - -// These conversion functions are returned by convertOp -// for classes of conversions. For example, the first function, cvtInt, -// takes any value v of signed int type and returns the value converted -// to type t, where t is any signed or unsigned int type. - -// convertOp: intXX -> [u]intXX -func cvtInt(v Value, t Type) Value { - return makeInt(v.flag.ro(), uint64(v.Int()), t) -} - -// convertOp: uintXX -> [u]intXX -func cvtUint(v Value, t Type) Value { - return makeInt(v.flag.ro(), v.Uint(), t) -} - -// convertOp: floatXX -> intXX -func cvtFloatInt(v Value, t Type) Value { - return makeInt(v.flag.ro(), uint64(int64(v.Float())), t) -} - -// convertOp: floatXX -> uintXX -func cvtFloatUint(v Value, t Type) Value { - return makeInt(v.flag.ro(), uint64(v.Float()), t) -} - -// convertOp: intXX -> floatXX -func cvtIntFloat(v Value, t Type) Value { - return makeFloat(v.flag.ro(), float64(v.Int()), t) -} - -// convertOp: uintXX -> floatXX -func cvtUintFloat(v Value, t Type) Value { - return makeFloat(v.flag.ro(), float64(v.Uint()), t) -} - -// convertOp: floatXX -> floatXX -func cvtFloat(v Value, t Type) Value { - if v.Type().Kind() == Float32 && t.Kind() == Float32 { - // Don't do any conversion if both types have underlying type float32. - // This avoids converting to float64 and back, which will - // convert a signaling NaN to a quiet NaN. See issue 36400. - return makeFloat32(v.flag.ro(), *(*float32)(v.ptr), t) - } - return makeFloat(v.flag.ro(), v.Float(), t) -} - -// convertOp: complexXX -> complexXX -func cvtComplex(v Value, t Type) Value { - return makeComplex(v.flag.ro(), v.Complex(), t) -} - -// convertOp: intXX -> string -func cvtIntString(v Value, t Type) Value { - s := "\uFFFD" - if x := v.Int(); int64(rune(x)) == x { - s = string(rune(x)) - } - return makeString(v.flag.ro(), s, t) -} - -// convertOp: uintXX -> string -func cvtUintString(v Value, t Type) Value { - s := "\uFFFD" - if x := v.Uint(); uint64(rune(x)) == x { - s = string(rune(x)) - } - return makeString(v.flag.ro(), s, t) -} - -// convertOp: []byte -> string -func cvtBytesString(v Value, t Type) Value { - return makeString(v.flag.ro(), string(v.Bytes()), t) -} - -// convertOp: string -> []byte -func cvtStringBytes(v Value, t Type) Value { - return makeBytes(v.flag.ro(), []byte(v.String()), t) -} - -// convertOp: []rune -> string -func cvtRunesString(v Value, t Type) Value { - return makeString(v.flag.ro(), string(v.runes()), t) -} - -// convertOp: string -> []rune -func cvtStringRunes(v Value, t Type) Value { - return makeRunes(v.flag.ro(), []rune(v.String()), t) -} - -// convertOp: []T -> *[N]T -func cvtSliceArrayPtr(v Value, t Type) Value { - n := t.Elem().Len() - if n > v.Len() { - panic("reflect: cannot convert slice with length " + itoa.Itoa(v.Len()) + " to pointer to array with length " + itoa.Itoa(n)) - } - h := (*unsafeheader.Slice)(v.ptr) - return Value{t.common(), h.Data, v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Pointer)} -} - -// convertOp: []T -> [N]T -func cvtSliceArray(v Value, t Type) Value { - n := t.Len() - if n > v.Len() { - panic("reflect: cannot convert slice with length " + itoa.Itoa(v.Len()) + " to array with length " + itoa.Itoa(n)) - } - h := (*unsafeheader.Slice)(v.ptr) - typ := t.common() - ptr := h.Data - c := unsafe_New(typ) - typedmemmove(typ, c, ptr) - ptr = c - - return Value{typ, ptr, v.flag&^(flagAddr|flagKindMask) | flag(Array)} -} - -// convertOp: direct copy -func cvtDirect(v Value, typ Type) Value { - f := v.flag - t := typ.common() - ptr := v.ptr - if f&flagAddr != 0 { - // indirect, mutable word - make a copy - c := unsafe_New(t) - typedmemmove(t, c, ptr) - ptr = c - f &^= flagAddr - } - return Value{t, ptr, v.flag.ro() | f} // v.flag.ro()|f == f? -} - -// convertOp: concrete -> interface -func cvtT2I(v Value, typ Type) Value { - target := unsafe_New(typ.common()) - x := valueInterface(v, false) - if typ.NumMethod() == 0 { - *(*any)(target) = x - } else { - ifaceE2I(typ.common(), x, target) - } - return Value{typ.common(), target, v.flag.ro() | flagIndir | flag(Interface)} -} - -// convertOp: interface -> interface -func cvtI2I(v Value, typ Type) Value { - if v.IsNil() { - ret := Zero(typ) - ret.flag |= v.flag.ro() - return ret - } - return cvtT2I(v.Elem(), typ) -} - -// implemented in ../runtime -// -//go:noescape -func chancap(ch unsafe.Pointer) int - -//go:noescape -func chanclose(ch unsafe.Pointer) - -//go:noescape -func chanlen(ch unsafe.Pointer) int - -// Note: some of the noescape annotations below are technically a lie, -// but safe in the context of this package. Functions like chansend0 -// and mapassign0 don't escape the referent, but may escape anything -// the referent points to (they do shallow copies of the referent). -// We add a 0 to their names and wrap them in functions with the -// proper escape behavior. - -//go:noescape -func chanrecv(ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool) - -//go:noescape -func chansend0(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool - -func chansend(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool { - contentEscapes(val) - return chansend0(ch, val, nb) -} - -func makechan(typ *abi.Type, size int) (ch unsafe.Pointer) -func makemap(t *abi.Type, cap int) (m unsafe.Pointer) - -//go:noescape -func mapaccess(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer) - -//go:noescape -func mapaccess_faststr(t *abi.Type, m unsafe.Pointer, key string) (val unsafe.Pointer) - -//go:noescape -func mapassign0(t *abi.Type, m unsafe.Pointer, key, val unsafe.Pointer) - -func mapassign(t *abi.Type, m unsafe.Pointer, key, val unsafe.Pointer) { - contentEscapes(key) - contentEscapes(val) - mapassign0(t, m, key, val) -} - -//go:noescape -func mapassign_faststr0(t *abi.Type, m unsafe.Pointer, key string, val unsafe.Pointer) - -func mapassign_faststr(t *abi.Type, m unsafe.Pointer, key string, val unsafe.Pointer) { - contentEscapes((*unsafeheader.String)(unsafe.Pointer(&key)).Data) - contentEscapes(val) - mapassign_faststr0(t, m, key, val) -} - -//go:noescape -func mapdelete(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) - -//go:noescape -func mapdelete_faststr(t *abi.Type, m unsafe.Pointer, key string) - -//go:noescape -func mapiterinit(t *abi.Type, m unsafe.Pointer, it *hiter) - -//go:noescape -func mapiterkey(it *hiter) (key unsafe.Pointer) - -//go:noescape -func mapiterelem(it *hiter) (elem unsafe.Pointer) - -//go:noescape -func mapiternext(it *hiter) - -//go:noescape -func maplen(m unsafe.Pointer) int - -func mapclear(t *abi.Type, m unsafe.Pointer) - -// call calls fn with "stackArgsSize" bytes of stack arguments laid out -// at stackArgs and register arguments laid out in regArgs. frameSize is -// the total amount of stack space that will be reserved by call, so this -// should include enough space to spill register arguments to the stack in -// case of preemption. -// -// After fn returns, call copies stackArgsSize-stackRetOffset result bytes -// back into stackArgs+stackRetOffset before returning, for any return -// values passed on the stack. Register-based return values will be found -// in the same regArgs structure. -// -// regArgs must also be prepared with an appropriate ReturnIsPtr bitmap -// indicating which registers will contain pointer-valued return values. The -// purpose of this bitmap is to keep pointers visible to the GC between -// returning from reflectcall and actually using them. -// -// If copying result bytes back from the stack, the caller must pass the -// argument frame type as stackArgsType, so that call can execute appropriate -// write barriers during the copy. -// -// Arguments passed through to call do not escape. The type is used only in a -// very limited callee of call, the stackArgs are copied, and regArgs is only -// used in the call frame. -// -//go:noescape -//go:linkname call runtime.reflectcall -func call(stackArgsType *abi.Type, f, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) - -func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) - -// memmove copies size bytes to dst from src. No write barriers are used. -// -//go:noescape -func memmove(dst, src unsafe.Pointer, size uintptr) - -// typedmemmove copies a value of type t to dst from src. -// -//go:noescape -func typedmemmove(t *abi.Type, dst, src unsafe.Pointer) - -// typedmemclr zeros the value at ptr of type t. -// -//go:noescape -func typedmemclr(t *abi.Type, ptr unsafe.Pointer) - -// typedmemclrpartial is like typedmemclr but assumes that -// dst points off bytes into the value and only clears size bytes. -// -//go:noescape -func typedmemclrpartial(t *abi.Type, ptr unsafe.Pointer, off, size uintptr) - -// typedslicecopy copies a slice of elemType values from src to dst, -// returning the number of elements copied. -// -//go:noescape -func typedslicecopy(t *abi.Type, dst, src unsafeheader.Slice) int - -// typedarrayclear zeroes the value at ptr of an array of elemType, -// only clears len elem. -// -//go:noescape -func typedarrayclear(elemType *abi.Type, ptr unsafe.Pointer, len int) - -//go:noescape -func typehash(t *abi.Type, p unsafe.Pointer, h uintptr) uintptr - -func verifyNotInHeapPtr(p uintptr) bool - -//go:noescape -func growslice(t *abi.Type, old unsafeheader.Slice, num int) unsafeheader.Slice - -// Dummy annotation marking that the value x escapes, -// for use in cases where the reflect code is so clever that -// the compiler cannot follow. -func escapes(x any) { - if dummy.b { - dummy.x = x - } -} - -var dummy struct { - b bool - x any -} - -// Dummy annotation marking that the content of value x -// escapes (i.e. modeling roughly heap=*x), -// for use in cases where the reflect code is so clever that -// the compiler cannot follow. -func contentEscapes(x unsafe.Pointer) { - if dummy.b { - escapes(*(*any)(x)) // the dereference may not always be safe, but never executed - } -} - -//go:nosplit -func noescape(p unsafe.Pointer) unsafe.Pointer { - x := uintptr(p) - return unsafe.Pointer(x ^ 0) -} diff --git a/contrib/go/_std_1.22/src/reflect/ya.make b/contrib/go/_std_1.22/src/reflect/ya.make deleted file mode 100644 index 49ccadde8e51..000000000000 --- a/contrib/go/_std_1.22/src/reflect/ya.make +++ /dev/null @@ -1,27 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - abi.go - asm_arm64.s - deepequal.go - float32reg_generic.go - makefunc.go - swapper.go - type.go - value.go - visiblefields.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - abi.go - asm_amd64.s - deepequal.go - float32reg_generic.go - makefunc.go - swapper.go - type.go - value.go - visiblefields.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/regexp/regexp.go b/contrib/go/_std_1.22/src/regexp/regexp.go deleted file mode 100644 index 462f235b1bb1..000000000000 --- a/contrib/go/_std_1.22/src/regexp/regexp.go +++ /dev/null @@ -1,1304 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package regexp implements regular expression search. -// -// The syntax of the regular expressions accepted is the same -// general syntax used by Perl, Python, and other languages. -// More precisely, it is the syntax accepted by RE2 and described at -// https://golang.org/s/re2syntax, except for \C. -// For an overview of the syntax, see the [regexp/syntax] package. -// -// The regexp implementation provided by this package is -// guaranteed to run in time linear in the size of the input. -// (This is a property not guaranteed by most open source -// implementations of regular expressions.) For more information -// about this property, see -// -// https://swtch.com/~rsc/regexp/regexp1.html -// -// or any book about automata theory. -// -// All characters are UTF-8-encoded code points. -// Following [utf8.DecodeRune], each byte of an invalid UTF-8 sequence -// is treated as if it encoded utf8.RuneError (U+FFFD). -// -// There are 16 methods of [Regexp] that match a regular expression and identify -// the matched text. Their names are matched by this regular expression: -// -// Find(All)?(String)?(Submatch)?(Index)? -// -// If 'All' is present, the routine matches successive non-overlapping -// matches of the entire expression. Empty matches abutting a preceding -// match are ignored. The return value is a slice containing the successive -// return values of the corresponding non-'All' routine. These routines take -// an extra integer argument, n. If n >= 0, the function returns at most n -// matches/submatches; otherwise, it returns all of them. -// -// If 'String' is present, the argument is a string; otherwise it is a slice -// of bytes; return values are adjusted as appropriate. -// -// If 'Submatch' is present, the return value is a slice identifying the -// successive submatches of the expression. Submatches are matches of -// parenthesized subexpressions (also known as capturing groups) within the -// regular expression, numbered from left to right in order of opening -// parenthesis. Submatch 0 is the match of the entire expression, submatch 1 is -// the match of the first parenthesized subexpression, and so on. -// -// If 'Index' is present, matches and submatches are identified by byte index -// pairs within the input string: result[2*n:2*n+2] identifies the indexes of -// the nth submatch. The pair for n==0 identifies the match of the entire -// expression. If 'Index' is not present, the match is identified by the text -// of the match/submatch. If an index is negative or text is nil, it means that -// subexpression did not match any string in the input. For 'String' versions -// an empty string means either no match or an empty match. -// -// There is also a subset of the methods that can be applied to text read -// from a RuneReader: -// -// MatchReader, FindReaderIndex, FindReaderSubmatchIndex -// -// This set may grow. Note that regular expression matches may need to -// examine text beyond the text returned by a match, so the methods that -// match text from a RuneReader may read arbitrarily far into the input -// before returning. -// -// (There are a few other methods that do not match this pattern.) -package regexp - -import ( - "bytes" - "io" - "regexp/syntax" - "strconv" - "strings" - "sync" - "unicode" - "unicode/utf8" -) - -// Regexp is the representation of a compiled regular expression. -// A Regexp is safe for concurrent use by multiple goroutines, -// except for configuration methods, such as [Regexp.Longest]. -type Regexp struct { - expr string // as passed to Compile - prog *syntax.Prog // compiled program - onepass *onePassProg // onepass program or nil - numSubexp int - maxBitStateLen int - subexpNames []string - prefix string // required prefix in unanchored matches - prefixBytes []byte // prefix, as a []byte - prefixRune rune // first rune in prefix - prefixEnd uint32 // pc for last rune in prefix - mpool int // pool for machines - matchcap int // size of recorded match lengths - prefixComplete bool // prefix is the entire regexp - cond syntax.EmptyOp // empty-width conditions required at start of match - minInputLen int // minimum length of the input in bytes - - // This field can be modified by the Longest method, - // but it is otherwise read-only. - longest bool // whether regexp prefers leftmost-longest match -} - -// String returns the source text used to compile the regular expression. -func (re *Regexp) String() string { - return re.expr -} - -// Copy returns a new [Regexp] object copied from re. -// Calling [Regexp.Longest] on one copy does not affect another. -// -// Deprecated: In earlier releases, when using a [Regexp] in multiple goroutines, -// giving each goroutine its own copy helped to avoid lock contention. -// As of Go 1.12, using Copy is no longer necessary to avoid lock contention. -// Copy may still be appropriate if the reason for its use is to make -// two copies with different [Regexp.Longest] settings. -func (re *Regexp) Copy() *Regexp { - re2 := *re - return &re2 -} - -// Compile parses a regular expression and returns, if successful, -// a [Regexp] object that can be used to match against text. -// -// When matching against text, the regexp returns a match that -// begins as early as possible in the input (leftmost), and among those -// it chooses the one that a backtracking search would have found first. -// This so-called leftmost-first matching is the same semantics -// that Perl, Python, and other implementations use, although this -// package implements it without the expense of backtracking. -// For POSIX leftmost-longest matching, see [CompilePOSIX]. -func Compile(expr string) (*Regexp, error) { - return compile(expr, syntax.Perl, false) -} - -// CompilePOSIX is like [Compile] but restricts the regular expression -// to POSIX ERE (egrep) syntax and changes the match semantics to -// leftmost-longest. -// -// That is, when matching against text, the regexp returns a match that -// begins as early as possible in the input (leftmost), and among those -// it chooses a match that is as long as possible. -// This so-called leftmost-longest matching is the same semantics -// that early regular expression implementations used and that POSIX -// specifies. -// -// However, there can be multiple leftmost-longest matches, with different -// submatch choices, and here this package diverges from POSIX. -// Among the possible leftmost-longest matches, this package chooses -// the one that a backtracking search would have found first, while POSIX -// specifies that the match be chosen to maximize the length of the first -// subexpression, then the second, and so on from left to right. -// The POSIX rule is computationally prohibitive and not even well-defined. -// See https://swtch.com/~rsc/regexp/regexp2.html#posix for details. -func CompilePOSIX(expr string) (*Regexp, error) { - return compile(expr, syntax.POSIX, true) -} - -// Longest makes future searches prefer the leftmost-longest match. -// That is, when matching against text, the regexp returns a match that -// begins as early as possible in the input (leftmost), and among those -// it chooses a match that is as long as possible. -// This method modifies the [Regexp] and may not be called concurrently -// with any other methods. -func (re *Regexp) Longest() { - re.longest = true -} - -func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) { - re, err := syntax.Parse(expr, mode) - if err != nil { - return nil, err - } - maxCap := re.MaxCap() - capNames := re.CapNames() - - re = re.Simplify() - prog, err := syntax.Compile(re) - if err != nil { - return nil, err - } - matchcap := prog.NumCap - if matchcap < 2 { - matchcap = 2 - } - regexp := &Regexp{ - expr: expr, - prog: prog, - onepass: compileOnePass(prog), - numSubexp: maxCap, - subexpNames: capNames, - cond: prog.StartCond(), - longest: longest, - matchcap: matchcap, - minInputLen: minInputLen(re), - } - if regexp.onepass == nil { - regexp.prefix, regexp.prefixComplete = prog.Prefix() - regexp.maxBitStateLen = maxBitStateLen(prog) - } else { - regexp.prefix, regexp.prefixComplete, regexp.prefixEnd = onePassPrefix(prog) - } - if regexp.prefix != "" { - // TODO(rsc): Remove this allocation by adding - // IndexString to package bytes. - regexp.prefixBytes = []byte(regexp.prefix) - regexp.prefixRune, _ = utf8.DecodeRuneInString(regexp.prefix) - } - - n := len(prog.Inst) - i := 0 - for matchSize[i] != 0 && matchSize[i] < n { - i++ - } - regexp.mpool = i - - return regexp, nil -} - -// Pools of *machine for use during (*Regexp).doExecute, -// split up by the size of the execution queues. -// matchPool[i] machines have queue size matchSize[i]. -// On a 64-bit system each queue entry is 16 bytes, -// so matchPool[0] has 16*2*128 = 4kB queues, etc. -// The final matchPool is a catch-all for very large queues. -var ( - matchSize = [...]int{128, 512, 2048, 16384, 0} - matchPool [len(matchSize)]sync.Pool -) - -// get returns a machine to use for matching re. -// It uses the re's machine cache if possible, to avoid -// unnecessary allocation. -func (re *Regexp) get() *machine { - m, ok := matchPool[re.mpool].Get().(*machine) - if !ok { - m = new(machine) - } - m.re = re - m.p = re.prog - if cap(m.matchcap) < re.matchcap { - m.matchcap = make([]int, re.matchcap) - for _, t := range m.pool { - t.cap = make([]int, re.matchcap) - } - } - - // Allocate queues if needed. - // Or reallocate, for "large" match pool. - n := matchSize[re.mpool] - if n == 0 { // large pool - n = len(re.prog.Inst) - } - if len(m.q0.sparse) < n { - m.q0 = queue{make([]uint32, n), make([]entry, 0, n)} - m.q1 = queue{make([]uint32, n), make([]entry, 0, n)} - } - return m -} - -// put returns a machine to the correct machine pool. -func (re *Regexp) put(m *machine) { - m.re = nil - m.p = nil - m.inputs.clear() - matchPool[re.mpool].Put(m) -} - -// minInputLen walks the regexp to find the minimum length of any matchable input. -func minInputLen(re *syntax.Regexp) int { - switch re.Op { - default: - return 0 - case syntax.OpAnyChar, syntax.OpAnyCharNotNL, syntax.OpCharClass: - return 1 - case syntax.OpLiteral: - l := 0 - for _, r := range re.Rune { - if r == utf8.RuneError { - l++ - } else { - l += utf8.RuneLen(r) - } - } - return l - case syntax.OpCapture, syntax.OpPlus: - return minInputLen(re.Sub[0]) - case syntax.OpRepeat: - return re.Min * minInputLen(re.Sub[0]) - case syntax.OpConcat: - l := 0 - for _, sub := range re.Sub { - l += minInputLen(sub) - } - return l - case syntax.OpAlternate: - l := minInputLen(re.Sub[0]) - var lnext int - for _, sub := range re.Sub[1:] { - lnext = minInputLen(sub) - if lnext < l { - l = lnext - } - } - return l - } -} - -// MustCompile is like [Compile] but panics if the expression cannot be parsed. -// It simplifies safe initialization of global variables holding compiled regular -// expressions. -func MustCompile(str string) *Regexp { - regexp, err := Compile(str) - if err != nil { - panic(`regexp: Compile(` + quote(str) + `): ` + err.Error()) - } - return regexp -} - -// MustCompilePOSIX is like [CompilePOSIX] but panics if the expression cannot be parsed. -// It simplifies safe initialization of global variables holding compiled regular -// expressions. -func MustCompilePOSIX(str string) *Regexp { - regexp, err := CompilePOSIX(str) - if err != nil { - panic(`regexp: CompilePOSIX(` + quote(str) + `): ` + err.Error()) - } - return regexp -} - -func quote(s string) string { - if strconv.CanBackquote(s) { - return "`" + s + "`" - } - return strconv.Quote(s) -} - -// NumSubexp returns the number of parenthesized subexpressions in this [Regexp]. -func (re *Regexp) NumSubexp() int { - return re.numSubexp -} - -// SubexpNames returns the names of the parenthesized subexpressions -// in this [Regexp]. The name for the first sub-expression is names[1], -// so that if m is a match slice, the name for m[i] is SubexpNames()[i]. -// Since the Regexp as a whole cannot be named, names[0] is always -// the empty string. The slice should not be modified. -func (re *Regexp) SubexpNames() []string { - return re.subexpNames -} - -// SubexpIndex returns the index of the first subexpression with the given name, -// or -1 if there is no subexpression with that name. -// -// Note that multiple subexpressions can be written using the same name, as in -// (?Pa+)(?Pb+), which declares two subexpressions named "bob". -// In this case, SubexpIndex returns the index of the leftmost such subexpression -// in the regular expression. -func (re *Regexp) SubexpIndex(name string) int { - if name != "" { - for i, s := range re.subexpNames { - if name == s { - return i - } - } - } - return -1 -} - -const endOfText rune = -1 - -// input abstracts different representations of the input text. It provides -// one-character lookahead. -type input interface { - step(pos int) (r rune, width int) // advance one rune - canCheckPrefix() bool // can we look ahead without losing info? - hasPrefix(re *Regexp) bool - index(re *Regexp, pos int) int - context(pos int) lazyFlag -} - -// inputString scans a string. -type inputString struct { - str string -} - -func (i *inputString) step(pos int) (rune, int) { - if pos < len(i.str) { - c := i.str[pos] - if c < utf8.RuneSelf { - return rune(c), 1 - } - return utf8.DecodeRuneInString(i.str[pos:]) - } - return endOfText, 0 -} - -func (i *inputString) canCheckPrefix() bool { - return true -} - -func (i *inputString) hasPrefix(re *Regexp) bool { - return strings.HasPrefix(i.str, re.prefix) -} - -func (i *inputString) index(re *Regexp, pos int) int { - return strings.Index(i.str[pos:], re.prefix) -} - -func (i *inputString) context(pos int) lazyFlag { - r1, r2 := endOfText, endOfText - // 0 < pos && pos <= len(i.str) - if uint(pos-1) < uint(len(i.str)) { - r1 = rune(i.str[pos-1]) - if r1 >= utf8.RuneSelf { - r1, _ = utf8.DecodeLastRuneInString(i.str[:pos]) - } - } - // 0 <= pos && pos < len(i.str) - if uint(pos) < uint(len(i.str)) { - r2 = rune(i.str[pos]) - if r2 >= utf8.RuneSelf { - r2, _ = utf8.DecodeRuneInString(i.str[pos:]) - } - } - return newLazyFlag(r1, r2) -} - -// inputBytes scans a byte slice. -type inputBytes struct { - str []byte -} - -func (i *inputBytes) step(pos int) (rune, int) { - if pos < len(i.str) { - c := i.str[pos] - if c < utf8.RuneSelf { - return rune(c), 1 - } - return utf8.DecodeRune(i.str[pos:]) - } - return endOfText, 0 -} - -func (i *inputBytes) canCheckPrefix() bool { - return true -} - -func (i *inputBytes) hasPrefix(re *Regexp) bool { - return bytes.HasPrefix(i.str, re.prefixBytes) -} - -func (i *inputBytes) index(re *Regexp, pos int) int { - return bytes.Index(i.str[pos:], re.prefixBytes) -} - -func (i *inputBytes) context(pos int) lazyFlag { - r1, r2 := endOfText, endOfText - // 0 < pos && pos <= len(i.str) - if uint(pos-1) < uint(len(i.str)) { - r1 = rune(i.str[pos-1]) - if r1 >= utf8.RuneSelf { - r1, _ = utf8.DecodeLastRune(i.str[:pos]) - } - } - // 0 <= pos && pos < len(i.str) - if uint(pos) < uint(len(i.str)) { - r2 = rune(i.str[pos]) - if r2 >= utf8.RuneSelf { - r2, _ = utf8.DecodeRune(i.str[pos:]) - } - } - return newLazyFlag(r1, r2) -} - -// inputReader scans a RuneReader. -type inputReader struct { - r io.RuneReader - atEOT bool - pos int -} - -func (i *inputReader) step(pos int) (rune, int) { - if !i.atEOT && pos != i.pos { - return endOfText, 0 - - } - r, w, err := i.r.ReadRune() - if err != nil { - i.atEOT = true - return endOfText, 0 - } - i.pos += w - return r, w -} - -func (i *inputReader) canCheckPrefix() bool { - return false -} - -func (i *inputReader) hasPrefix(re *Regexp) bool { - return false -} - -func (i *inputReader) index(re *Regexp, pos int) int { - return -1 -} - -func (i *inputReader) context(pos int) lazyFlag { - return 0 // not used -} - -// LiteralPrefix returns a literal string that must begin any match -// of the regular expression re. It returns the boolean true if the -// literal string comprises the entire regular expression. -func (re *Regexp) LiteralPrefix() (prefix string, complete bool) { - return re.prefix, re.prefixComplete -} - -// MatchReader reports whether the text returned by the [io.RuneReader] -// contains any match of the regular expression re. -func (re *Regexp) MatchReader(r io.RuneReader) bool { - return re.doMatch(r, nil, "") -} - -// MatchString reports whether the string s -// contains any match of the regular expression re. -func (re *Regexp) MatchString(s string) bool { - return re.doMatch(nil, nil, s) -} - -// Match reports whether the byte slice b -// contains any match of the regular expression re. -func (re *Regexp) Match(b []byte) bool { - return re.doMatch(nil, b, "") -} - -// MatchReader reports whether the text returned by the RuneReader -// contains any match of the regular expression pattern. -// More complicated queries need to use [Compile] and the full [Regexp] interface. -func MatchReader(pattern string, r io.RuneReader) (matched bool, err error) { - re, err := Compile(pattern) - if err != nil { - return false, err - } - return re.MatchReader(r), nil -} - -// MatchString reports whether the string s -// contains any match of the regular expression pattern. -// More complicated queries need to use [Compile] and the full [Regexp] interface. -func MatchString(pattern string, s string) (matched bool, err error) { - re, err := Compile(pattern) - if err != nil { - return false, err - } - return re.MatchString(s), nil -} - -// Match reports whether the byte slice b -// contains any match of the regular expression pattern. -// More complicated queries need to use [Compile] and the full [Regexp] interface. -func Match(pattern string, b []byte) (matched bool, err error) { - re, err := Compile(pattern) - if err != nil { - return false, err - } - return re.Match(b), nil -} - -// ReplaceAllString returns a copy of src, replacing matches of the [Regexp] -// with the replacement string repl. -// Inside repl, $ signs are interpreted as in [Regexp.Expand]. -func (re *Regexp) ReplaceAllString(src, repl string) string { - n := 2 - if strings.Contains(repl, "$") { - n = 2 * (re.numSubexp + 1) - } - b := re.replaceAll(nil, src, n, func(dst []byte, match []int) []byte { - return re.expand(dst, repl, nil, src, match) - }) - return string(b) -} - -// ReplaceAllLiteralString returns a copy of src, replacing matches of the [Regexp] -// with the replacement string repl. The replacement repl is substituted directly, -// without using [Regexp.Expand]. -func (re *Regexp) ReplaceAllLiteralString(src, repl string) string { - return string(re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte { - return append(dst, repl...) - })) -} - -// ReplaceAllStringFunc returns a copy of src in which all matches of the -// [Regexp] have been replaced by the return value of function repl applied -// to the matched substring. The replacement returned by repl is substituted -// directly, without using [Regexp.Expand]. -func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string { - b := re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte { - return append(dst, repl(src[match[0]:match[1]])...) - }) - return string(b) -} - -func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst []byte, m []int) []byte) []byte { - lastMatchEnd := 0 // end position of the most recent match - searchPos := 0 // position where we next look for a match - var buf []byte - var endPos int - if bsrc != nil { - endPos = len(bsrc) - } else { - endPos = len(src) - } - if nmatch > re.prog.NumCap { - nmatch = re.prog.NumCap - } - - var dstCap [2]int - for searchPos <= endPos { - a := re.doExecute(nil, bsrc, src, searchPos, nmatch, dstCap[:0]) - if len(a) == 0 { - break // no more matches - } - - // Copy the unmatched characters before this match. - if bsrc != nil { - buf = append(buf, bsrc[lastMatchEnd:a[0]]...) - } else { - buf = append(buf, src[lastMatchEnd:a[0]]...) - } - - // Now insert a copy of the replacement string, but not for a - // match of the empty string immediately after another match. - // (Otherwise, we get double replacement for patterns that - // match both empty and nonempty strings.) - if a[1] > lastMatchEnd || a[0] == 0 { - buf = repl(buf, a) - } - lastMatchEnd = a[1] - - // Advance past this match; always advance at least one character. - var width int - if bsrc != nil { - _, width = utf8.DecodeRune(bsrc[searchPos:]) - } else { - _, width = utf8.DecodeRuneInString(src[searchPos:]) - } - if searchPos+width > a[1] { - searchPos += width - } else if searchPos+1 > a[1] { - // This clause is only needed at the end of the input - // string. In that case, DecodeRuneInString returns width=0. - searchPos++ - } else { - searchPos = a[1] - } - } - - // Copy the unmatched characters after the last match. - if bsrc != nil { - buf = append(buf, bsrc[lastMatchEnd:]...) - } else { - buf = append(buf, src[lastMatchEnd:]...) - } - - return buf -} - -// ReplaceAll returns a copy of src, replacing matches of the [Regexp] -// with the replacement text repl. -// Inside repl, $ signs are interpreted as in [Regexp.Expand]. -func (re *Regexp) ReplaceAll(src, repl []byte) []byte { - n := 2 - if bytes.IndexByte(repl, '$') >= 0 { - n = 2 * (re.numSubexp + 1) - } - srepl := "" - b := re.replaceAll(src, "", n, func(dst []byte, match []int) []byte { - if len(srepl) != len(repl) { - srepl = string(repl) - } - return re.expand(dst, srepl, src, "", match) - }) - return b -} - -// ReplaceAllLiteral returns a copy of src, replacing matches of the [Regexp] -// with the replacement bytes repl. The replacement repl is substituted directly, -// without using [Regexp.Expand]. -func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte { - return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte { - return append(dst, repl...) - }) -} - -// ReplaceAllFunc returns a copy of src in which all matches of the -// [Regexp] have been replaced by the return value of function repl applied -// to the matched byte slice. The replacement returned by repl is substituted -// directly, without using [Regexp.Expand]. -func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte { - return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte { - return append(dst, repl(src[match[0]:match[1]])...) - }) -} - -// Bitmap used by func special to check whether a character needs to be escaped. -var specialBytes [16]byte - -// special reports whether byte b needs to be escaped by QuoteMeta. -func special(b byte) bool { - return b < utf8.RuneSelf && specialBytes[b%16]&(1<<(b/16)) != 0 -} - -func init() { - for _, b := range []byte(`\.+*?()|[]{}^$`) { - specialBytes[b%16] |= 1 << (b / 16) - } -} - -// QuoteMeta returns a string that escapes all regular expression metacharacters -// inside the argument text; the returned string is a regular expression matching -// the literal text. -func QuoteMeta(s string) string { - // A byte loop is correct because all metacharacters are ASCII. - var i int - for i = 0; i < len(s); i++ { - if special(s[i]) { - break - } - } - // No meta characters found, so return original string. - if i >= len(s) { - return s - } - - b := make([]byte, 2*len(s)-i) - copy(b, s[:i]) - j := i - for ; i < len(s); i++ { - if special(s[i]) { - b[j] = '\\' - j++ - } - b[j] = s[i] - j++ - } - return string(b[:j]) -} - -// The number of capture values in the program may correspond -// to fewer capturing expressions than are in the regexp. -// For example, "(a){0}" turns into an empty program, so the -// maximum capture in the program is 0 but we need to return -// an expression for \1. Pad appends -1s to the slice a as needed. -func (re *Regexp) pad(a []int) []int { - if a == nil { - // No match. - return nil - } - n := (1 + re.numSubexp) * 2 - for len(a) < n { - a = append(a, -1) - } - return a -} - -// allMatches calls deliver at most n times -// with the location of successive matches in the input text. -// The input text is b if non-nil, otherwise s. -func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) { - var end int - if b == nil { - end = len(s) - } else { - end = len(b) - } - - for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; { - matches := re.doExecute(nil, b, s, pos, re.prog.NumCap, nil) - if len(matches) == 0 { - break - } - - accept := true - if matches[1] == pos { - // We've found an empty match. - if matches[0] == prevMatchEnd { - // We don't allow an empty match right - // after a previous match, so ignore it. - accept = false - } - var width int - if b == nil { - is := inputString{str: s} - _, width = is.step(pos) - } else { - ib := inputBytes{str: b} - _, width = ib.step(pos) - } - if width > 0 { - pos += width - } else { - pos = end + 1 - } - } else { - pos = matches[1] - } - prevMatchEnd = matches[1] - - if accept { - deliver(re.pad(matches)) - i++ - } - } -} - -// Find returns a slice holding the text of the leftmost match in b of the regular expression. -// A return value of nil indicates no match. -func (re *Regexp) Find(b []byte) []byte { - var dstCap [2]int - a := re.doExecute(nil, b, "", 0, 2, dstCap[:0]) - if a == nil { - return nil - } - return b[a[0]:a[1]:a[1]] -} - -// FindIndex returns a two-element slice of integers defining the location of -// the leftmost match in b of the regular expression. The match itself is at -// b[loc[0]:loc[1]]. -// A return value of nil indicates no match. -func (re *Regexp) FindIndex(b []byte) (loc []int) { - a := re.doExecute(nil, b, "", 0, 2, nil) - if a == nil { - return nil - } - return a[0:2] -} - -// FindString returns a string holding the text of the leftmost match in s of the regular -// expression. If there is no match, the return value is an empty string, -// but it will also be empty if the regular expression successfully matches -// an empty string. Use [Regexp.FindStringIndex] or [Regexp.FindStringSubmatch] if it is -// necessary to distinguish these cases. -func (re *Regexp) FindString(s string) string { - var dstCap [2]int - a := re.doExecute(nil, nil, s, 0, 2, dstCap[:0]) - if a == nil { - return "" - } - return s[a[0]:a[1]] -} - -// FindStringIndex returns a two-element slice of integers defining the -// location of the leftmost match in s of the regular expression. The match -// itself is at s[loc[0]:loc[1]]. -// A return value of nil indicates no match. -func (re *Regexp) FindStringIndex(s string) (loc []int) { - a := re.doExecute(nil, nil, s, 0, 2, nil) - if a == nil { - return nil - } - return a[0:2] -} - -// FindReaderIndex returns a two-element slice of integers defining the -// location of the leftmost match of the regular expression in text read from -// the [io.RuneReader]. The match text was found in the input stream at -// byte offset loc[0] through loc[1]-1. -// A return value of nil indicates no match. -func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int) { - a := re.doExecute(r, nil, "", 0, 2, nil) - if a == nil { - return nil - } - return a[0:2] -} - -// FindSubmatch returns a slice of slices holding the text of the leftmost -// match of the regular expression in b and the matches, if any, of its -// subexpressions, as defined by the 'Submatch' descriptions in the package -// comment. -// A return value of nil indicates no match. -func (re *Regexp) FindSubmatch(b []byte) [][]byte { - var dstCap [4]int - a := re.doExecute(nil, b, "", 0, re.prog.NumCap, dstCap[:0]) - if a == nil { - return nil - } - ret := make([][]byte, 1+re.numSubexp) - for i := range ret { - if 2*i < len(a) && a[2*i] >= 0 { - ret[i] = b[a[2*i]:a[2*i+1]:a[2*i+1]] - } - } - return ret -} - -// Expand appends template to dst and returns the result; during the -// append, Expand replaces variables in the template with corresponding -// matches drawn from src. The match slice should have been returned by -// [Regexp.FindSubmatchIndex]. -// -// In the template, a variable is denoted by a substring of the form -// $name or ${name}, where name is a non-empty sequence of letters, -// digits, and underscores. A purely numeric name like $1 refers to -// the submatch with the corresponding index; other names refer to -// capturing parentheses named with the (?P...) syntax. A -// reference to an out of range or unmatched index or a name that is not -// present in the regular expression is replaced with an empty slice. -// -// In the $name form, name is taken to be as long as possible: $1x is -// equivalent to ${1x}, not ${1}x, and, $10 is equivalent to ${10}, not ${1}0. -// -// To insert a literal $ in the output, use $$ in the template. -func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte { - return re.expand(dst, string(template), src, "", match) -} - -// ExpandString is like [Regexp.Expand] but the template and source are strings. -// It appends to and returns a byte slice in order to give the calling -// code control over allocation. -func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte { - return re.expand(dst, template, nil, src, match) -} - -func (re *Regexp) expand(dst []byte, template string, bsrc []byte, src string, match []int) []byte { - for len(template) > 0 { - before, after, ok := strings.Cut(template, "$") - if !ok { - break - } - dst = append(dst, before...) - template = after - if template != "" && template[0] == '$' { - // Treat $$ as $. - dst = append(dst, '$') - template = template[1:] - continue - } - name, num, rest, ok := extract(template) - if !ok { - // Malformed; treat $ as raw text. - dst = append(dst, '$') - continue - } - template = rest - if num >= 0 { - if 2*num+1 < len(match) && match[2*num] >= 0 { - if bsrc != nil { - dst = append(dst, bsrc[match[2*num]:match[2*num+1]]...) - } else { - dst = append(dst, src[match[2*num]:match[2*num+1]]...) - } - } - } else { - for i, namei := range re.subexpNames { - if name == namei && 2*i+1 < len(match) && match[2*i] >= 0 { - if bsrc != nil { - dst = append(dst, bsrc[match[2*i]:match[2*i+1]]...) - } else { - dst = append(dst, src[match[2*i]:match[2*i+1]]...) - } - break - } - } - } - } - dst = append(dst, template...) - return dst -} - -// extract returns the name from a leading "name" or "{name}" in str. -// (The $ has already been removed by the caller.) -// If it is a number, extract returns num set to that number; otherwise num = -1. -func extract(str string) (name string, num int, rest string, ok bool) { - if str == "" { - return - } - brace := false - if str[0] == '{' { - brace = true - str = str[1:] - } - i := 0 - for i < len(str) { - rune, size := utf8.DecodeRuneInString(str[i:]) - if !unicode.IsLetter(rune) && !unicode.IsDigit(rune) && rune != '_' { - break - } - i += size - } - if i == 0 { - // empty name is not okay - return - } - name = str[:i] - if brace { - if i >= len(str) || str[i] != '}' { - // missing closing brace - return - } - i++ - } - - // Parse number. - num = 0 - for i := 0; i < len(name); i++ { - if name[i] < '0' || '9' < name[i] || num >= 1e8 { - num = -1 - break - } - num = num*10 + int(name[i]) - '0' - } - // Disallow leading zeros. - if name[0] == '0' && len(name) > 1 { - num = -1 - } - - rest = str[i:] - ok = true - return -} - -// FindSubmatchIndex returns a slice holding the index pairs identifying the -// leftmost match of the regular expression in b and the matches, if any, of -// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions -// in the package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindSubmatchIndex(b []byte) []int { - return re.pad(re.doExecute(nil, b, "", 0, re.prog.NumCap, nil)) -} - -// FindStringSubmatch returns a slice of strings holding the text of the -// leftmost match of the regular expression in s and the matches, if any, of -// its subexpressions, as defined by the 'Submatch' description in the -// package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindStringSubmatch(s string) []string { - var dstCap [4]int - a := re.doExecute(nil, nil, s, 0, re.prog.NumCap, dstCap[:0]) - if a == nil { - return nil - } - ret := make([]string, 1+re.numSubexp) - for i := range ret { - if 2*i < len(a) && a[2*i] >= 0 { - ret[i] = s[a[2*i]:a[2*i+1]] - } - } - return ret -} - -// FindStringSubmatchIndex returns a slice holding the index pairs -// identifying the leftmost match of the regular expression in s and the -// matches, if any, of its subexpressions, as defined by the 'Submatch' and -// 'Index' descriptions in the package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindStringSubmatchIndex(s string) []int { - return re.pad(re.doExecute(nil, nil, s, 0, re.prog.NumCap, nil)) -} - -// FindReaderSubmatchIndex returns a slice holding the index pairs -// identifying the leftmost match of the regular expression of text read by -// the [io.RuneReader], and the matches, if any, of its subexpressions, as defined -// by the 'Submatch' and 'Index' descriptions in the package comment. A -// return value of nil indicates no match. -func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int { - return re.pad(re.doExecute(r, nil, "", 0, re.prog.NumCap, nil)) -} - -const startSize = 10 // The size at which to start a slice in the 'All' routines. - -// FindAll is the 'All' version of Find; it returns a slice of all successive -// matches of the expression, as defined by the 'All' description in the -// package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindAll(b []byte, n int) [][]byte { - if n < 0 { - n = len(b) + 1 - } - var result [][]byte - re.allMatches("", b, n, func(match []int) { - if result == nil { - result = make([][]byte, 0, startSize) - } - result = append(result, b[match[0]:match[1]:match[1]]) - }) - return result -} - -// FindAllIndex is the 'All' version of [Regexp.FindIndex]; it returns a slice of all -// successive matches of the expression, as defined by the 'All' description -// in the package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindAllIndex(b []byte, n int) [][]int { - if n < 0 { - n = len(b) + 1 - } - var result [][]int - re.allMatches("", b, n, func(match []int) { - if result == nil { - result = make([][]int, 0, startSize) - } - result = append(result, match[0:2]) - }) - return result -} - -// FindAllString is the 'All' version of [Regexp.FindString]; it returns a slice of all -// successive matches of the expression, as defined by the 'All' description -// in the package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindAllString(s string, n int) []string { - if n < 0 { - n = len(s) + 1 - } - var result []string - re.allMatches(s, nil, n, func(match []int) { - if result == nil { - result = make([]string, 0, startSize) - } - result = append(result, s[match[0]:match[1]]) - }) - return result -} - -// FindAllStringIndex is the 'All' version of [Regexp.FindStringIndex]; it returns a -// slice of all successive matches of the expression, as defined by the 'All' -// description in the package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindAllStringIndex(s string, n int) [][]int { - if n < 0 { - n = len(s) + 1 - } - var result [][]int - re.allMatches(s, nil, n, func(match []int) { - if result == nil { - result = make([][]int, 0, startSize) - } - result = append(result, match[0:2]) - }) - return result -} - -// FindAllSubmatch is the 'All' version of [Regexp.FindSubmatch]; it returns a slice -// of all successive matches of the expression, as defined by the 'All' -// description in the package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte { - if n < 0 { - n = len(b) + 1 - } - var result [][][]byte - re.allMatches("", b, n, func(match []int) { - if result == nil { - result = make([][][]byte, 0, startSize) - } - slice := make([][]byte, len(match)/2) - for j := range slice { - if match[2*j] >= 0 { - slice[j] = b[match[2*j]:match[2*j+1]:match[2*j+1]] - } - } - result = append(result, slice) - }) - return result -} - -// FindAllSubmatchIndex is the 'All' version of [Regexp.FindSubmatchIndex]; it returns -// a slice of all successive matches of the expression, as defined by the -// 'All' description in the package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int { - if n < 0 { - n = len(b) + 1 - } - var result [][]int - re.allMatches("", b, n, func(match []int) { - if result == nil { - result = make([][]int, 0, startSize) - } - result = append(result, match) - }) - return result -} - -// FindAllStringSubmatch is the 'All' version of [Regexp.FindStringSubmatch]; it -// returns a slice of all successive matches of the expression, as defined by -// the 'All' description in the package comment. -// A return value of nil indicates no match. -func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string { - if n < 0 { - n = len(s) + 1 - } - var result [][]string - re.allMatches(s, nil, n, func(match []int) { - if result == nil { - result = make([][]string, 0, startSize) - } - slice := make([]string, len(match)/2) - for j := range slice { - if match[2*j] >= 0 { - slice[j] = s[match[2*j]:match[2*j+1]] - } - } - result = append(result, slice) - }) - return result -} - -// FindAllStringSubmatchIndex is the 'All' version of -// [Regexp.FindStringSubmatchIndex]; it returns a slice of all successive matches of -// the expression, as defined by the 'All' description in the package -// comment. -// A return value of nil indicates no match. -func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int { - if n < 0 { - n = len(s) + 1 - } - var result [][]int - re.allMatches(s, nil, n, func(match []int) { - if result == nil { - result = make([][]int, 0, startSize) - } - result = append(result, match) - }) - return result -} - -// Split slices s into substrings separated by the expression and returns a slice of -// the substrings between those expression matches. -// -// The slice returned by this method consists of all the substrings of s -// not contained in the slice returned by [Regexp.FindAllString]. When called on an expression -// that contains no metacharacters, it is equivalent to [strings.SplitN]. -// -// Example: -// -// s := regexp.MustCompile("a*").Split("abaabaccadaaae", 5) -// // s: ["", "b", "b", "c", "cadaaae"] -// -// The count determines the number of substrings to return: -// -// n > 0: at most n substrings; the last substring will be the unsplit remainder. -// n == 0: the result is nil (zero substrings) -// n < 0: all substrings -func (re *Regexp) Split(s string, n int) []string { - - if n == 0 { - return nil - } - - if len(re.expr) > 0 && len(s) == 0 { - return []string{""} - } - - matches := re.FindAllStringIndex(s, n) - strings := make([]string, 0, len(matches)) - - beg := 0 - end := 0 - for _, match := range matches { - if n > 0 && len(strings) >= n-1 { - break - } - - end = match[0] - if match[1] != 0 { - strings = append(strings, s[beg:end]) - } - beg = match[1] - } - - if end != len(s) { - strings = append(strings, s[beg:]) - } - - return strings -} - -// MarshalText implements [encoding.TextMarshaler]. The output -// matches that of calling the [Regexp.String] method. -// -// Note that the output is lossy in some cases: This method does not indicate -// POSIX regular expressions (i.e. those compiled by calling [CompilePOSIX]), or -// those for which the [Regexp.Longest] method has been called. -func (re *Regexp) MarshalText() ([]byte, error) { - return []byte(re.String()), nil -} - -// UnmarshalText implements [encoding.TextUnmarshaler] by calling -// [Compile] on the encoded value. -func (re *Regexp) UnmarshalText(text []byte) error { - newRE, err := Compile(string(text)) - if err != nil { - return err - } - *re = *newRE - return nil -} diff --git a/contrib/go/_std_1.22/src/regexp/syntax/doc.go b/contrib/go/_std_1.22/src/regexp/syntax/doc.go deleted file mode 100644 index eb8a971c7348..000000000000 --- a/contrib/go/_std_1.22/src/regexp/syntax/doc.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// DO NOT EDIT. This file is generated by mksyntaxgo from the RE2 distribution. - -/* -Package syntax parses regular expressions into parse trees and compiles -parse trees into programs. Most clients of regular expressions will use the -facilities of package regexp (such as Compile and Match) instead of this package. - -# Syntax - -The regular expression syntax understood by this package when parsing with the Perl flag is as follows. -Parts of the syntax can be disabled by passing alternate flags to Parse. - -Single characters: - - . any character, possibly including newline (flag s=true) - [xyz] character class - [^xyz] negated character class - \d Perl character class - \D negated Perl character class - [[:alpha:]] ASCII character class - [[:^alpha:]] negated ASCII character class - \pN Unicode character class (one-letter name) - \p{Greek} Unicode character class - \PN negated Unicode character class (one-letter name) - \P{Greek} negated Unicode character class - -Composites: - - xy x followed by y - x|y x or y (prefer x) - -Repetitions: - - x* zero or more x, prefer more - x+ one or more x, prefer more - x? zero or one x, prefer one - x{n,m} n or n+1 or ... or m x, prefer more - x{n,} n or more x, prefer more - x{n} exactly n x - x*? zero or more x, prefer fewer - x+? one or more x, prefer fewer - x?? zero or one x, prefer zero - x{n,m}? n or n+1 or ... or m x, prefer fewer - x{n,}? n or more x, prefer fewer - x{n}? exactly n x - -Implementation restriction: The counting forms x{n,m}, x{n,}, and x{n} -reject forms that create a minimum or maximum repetition count above 1000. -Unlimited repetitions are not subject to this restriction. - -Grouping: - - (re) numbered capturing group (submatch) - (?Pre) named & numbered capturing group (submatch) - (?re) named & numbered capturing group (submatch) - (?:re) non-capturing group - (?flags) set flags within current group; non-capturing - (?flags:re) set flags during re; non-capturing - - Flag syntax is xyz (set) or -xyz (clear) or xy-z (set xy, clear z). The flags are: - - i case-insensitive (default false) - m multi-line mode: ^ and $ match begin/end line in addition to begin/end text (default false) - s let . match \n (default false) - U ungreedy: swap meaning of x* and x*?, x+ and x+?, etc (default false) - -Empty strings: - - ^ at beginning of text or line (flag m=true) - $ at end of text (like \z not \Z) or line (flag m=true) - \A at beginning of text - \b at ASCII word boundary (\w on one side and \W, \A, or \z on the other) - \B not at ASCII word boundary - \z at end of text - -Escape sequences: - - \a bell (== \007) - \f form feed (== \014) - \t horizontal tab (== \011) - \n newline (== \012) - \r carriage return (== \015) - \v vertical tab character (== \013) - \* literal *, for any punctuation character * - \123 octal character code (up to three digits) - \x7F hex character code (exactly two digits) - \x{10FFFF} hex character code - \Q...\E literal text ... even if ... has punctuation - -Character class elements: - - x single character - A-Z character range (inclusive) - \d Perl character class - [:foo:] ASCII character class foo - \p{Foo} Unicode character class Foo - \pF Unicode character class F (one-letter name) - -Named character classes as character class elements: - - [\d] digits (== \d) - [^\d] not digits (== \D) - [\D] not digits (== \D) - [^\D] not not digits (== \d) - [[:name:]] named ASCII class inside character class (== [:name:]) - [^[:name:]] named ASCII class inside negated character class (== [:^name:]) - [\p{Name}] named Unicode property inside character class (== \p{Name}) - [^\p{Name}] named Unicode property inside negated character class (== \P{Name}) - -Perl character classes (all ASCII-only): - - \d digits (== [0-9]) - \D not digits (== [^0-9]) - \s whitespace (== [\t\n\f\r ]) - \S not whitespace (== [^\t\n\f\r ]) - \w word characters (== [0-9A-Za-z_]) - \W not word characters (== [^0-9A-Za-z_]) - -ASCII character classes: - - [[:alnum:]] alphanumeric (== [0-9A-Za-z]) - [[:alpha:]] alphabetic (== [A-Za-z]) - [[:ascii:]] ASCII (== [\x00-\x7F]) - [[:blank:]] blank (== [\t ]) - [[:cntrl:]] control (== [\x00-\x1F\x7F]) - [[:digit:]] digits (== [0-9]) - [[:graph:]] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]) - [[:lower:]] lower case (== [a-z]) - [[:print:]] printable (== [ -~] == [ [:graph:]]) - [[:punct:]] punctuation (== [!-/:-@[-`{-~]) - [[:space:]] whitespace (== [\t\n\v\f\r ]) - [[:upper:]] upper case (== [A-Z]) - [[:word:]] word characters (== [0-9A-Za-z_]) - [[:xdigit:]] hex digit (== [0-9A-Fa-f]) - -Unicode character classes are those in unicode.Categories and unicode.Scripts. -*/ -package syntax diff --git a/contrib/go/_std_1.22/src/regexp/syntax/parse.go b/contrib/go/_std_1.22/src/regexp/syntax/parse.go deleted file mode 100644 index 6a11b53fb180..000000000000 --- a/contrib/go/_std_1.22/src/regexp/syntax/parse.go +++ /dev/null @@ -1,2138 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syntax - -import ( - "sort" - "strings" - "unicode" - "unicode/utf8" -) - -// An Error describes a failure to parse a regular expression -// and gives the offending expression. -type Error struct { - Code ErrorCode - Expr string -} - -func (e *Error) Error() string { - return "error parsing regexp: " + e.Code.String() + ": `" + e.Expr + "`" -} - -// An ErrorCode describes a failure to parse a regular expression. -type ErrorCode string - -const ( - // Unexpected error - ErrInternalError ErrorCode = "regexp/syntax: internal error" - - // Parse errors - ErrInvalidCharClass ErrorCode = "invalid character class" - ErrInvalidCharRange ErrorCode = "invalid character class range" - ErrInvalidEscape ErrorCode = "invalid escape sequence" - ErrInvalidNamedCapture ErrorCode = "invalid named capture" - ErrInvalidPerlOp ErrorCode = "invalid or unsupported Perl syntax" - ErrInvalidRepeatOp ErrorCode = "invalid nested repetition operator" - ErrInvalidRepeatSize ErrorCode = "invalid repeat count" - ErrInvalidUTF8 ErrorCode = "invalid UTF-8" - ErrMissingBracket ErrorCode = "missing closing ]" - ErrMissingParen ErrorCode = "missing closing )" - ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator" - ErrTrailingBackslash ErrorCode = "trailing backslash at end of expression" - ErrUnexpectedParen ErrorCode = "unexpected )" - ErrNestingDepth ErrorCode = "expression nests too deeply" - ErrLarge ErrorCode = "expression too large" -) - -func (e ErrorCode) String() string { - return string(e) -} - -// Flags control the behavior of the parser and record information about regexp context. -type Flags uint16 - -const ( - FoldCase Flags = 1 << iota // case-insensitive match - Literal // treat pattern as literal string - ClassNL // allow character classes like [^a-z] and [[:space:]] to match newline - DotNL // allow . to match newline - OneLine // treat ^ and $ as only matching at beginning and end of text - NonGreedy // make repetition operators default to non-greedy - PerlX // allow Perl extensions - UnicodeGroups // allow \p{Han}, \P{Han} for Unicode group and negation - WasDollar // regexp OpEndText was $, not \z - Simple // regexp contains no counted repetition - - MatchNL = ClassNL | DotNL - - Perl = ClassNL | OneLine | PerlX | UnicodeGroups // as close to Perl as possible - POSIX Flags = 0 // POSIX syntax -) - -// Pseudo-ops for parsing stack. -const ( - opLeftParen = opPseudo + iota - opVerticalBar -) - -// maxHeight is the maximum height of a regexp parse tree. -// It is somewhat arbitrarily chosen, but the idea is to be large enough -// that no one will actually hit in real use but at the same time small enough -// that recursion on the Regexp tree will not hit the 1GB Go stack limit. -// The maximum amount of stack for a single recursive frame is probably -// closer to 1kB, so this could potentially be raised, but it seems unlikely -// that people have regexps nested even this deeply. -// We ran a test on Google's C++ code base and turned up only -// a single use case with depth > 100; it had depth 128. -// Using depth 1000 should be plenty of margin. -// As an optimization, we don't even bother calculating heights -// until we've allocated at least maxHeight Regexp structures. -const maxHeight = 1000 - -// maxSize is the maximum size of a compiled regexp in Insts. -// It too is somewhat arbitrarily chosen, but the idea is to be large enough -// to allow significant regexps while at the same time small enough that -// the compiled form will not take up too much memory. -// 128 MB is enough for a 3.3 million Inst structures, which roughly -// corresponds to a 3.3 MB regexp. -const ( - maxSize = 128 << 20 / instSize - instSize = 5 * 8 // byte, 2 uint32, slice is 5 64-bit words -) - -// maxRunes is the maximum number of runes allowed in a regexp tree -// counting the runes in all the nodes. -// Ignoring character classes p.numRunes is always less than the length of the regexp. -// Character classes can make it much larger: each \pL adds 1292 runes. -// 128 MB is enough for 32M runes, which is over 26k \pL instances. -// Note that repetitions do not make copies of the rune slices, -// so \pL{1000} is only one rune slice, not 1000. -// We could keep a cache of character classes we've seen, -// so that all the \pL we see use the same rune list, -// but that doesn't remove the problem entirely: -// consider something like [\pL01234][\pL01235][\pL01236]...[\pL^&*()]. -// And because the Rune slice is exposed directly in the Regexp, -// there is not an opportunity to change the representation to allow -// partial sharing between different character classes. -// So the limit is the best we can do. -const ( - maxRunes = 128 << 20 / runeSize - runeSize = 4 // rune is int32 -) - -type parser struct { - flags Flags // parse mode flags - stack []*Regexp // stack of parsed expressions - free *Regexp - numCap int // number of capturing groups seen - wholeRegexp string - tmpClass []rune // temporary char class work space - numRegexp int // number of regexps allocated - numRunes int // number of runes in char classes - repeats int64 // product of all repetitions seen - height map[*Regexp]int // regexp height, for height limit check - size map[*Regexp]int64 // regexp compiled size, for size limit check -} - -func (p *parser) newRegexp(op Op) *Regexp { - re := p.free - if re != nil { - p.free = re.Sub0[0] - *re = Regexp{} - } else { - re = new(Regexp) - p.numRegexp++ - } - re.Op = op - return re -} - -func (p *parser) reuse(re *Regexp) { - if p.height != nil { - delete(p.height, re) - } - re.Sub0[0] = p.free - p.free = re -} - -func (p *parser) checkLimits(re *Regexp) { - if p.numRunes > maxRunes { - panic(ErrLarge) - } - p.checkSize(re) - p.checkHeight(re) -} - -func (p *parser) checkSize(re *Regexp) { - if p.size == nil { - // We haven't started tracking size yet. - // Do a relatively cheap check to see if we need to start. - // Maintain the product of all the repeats we've seen - // and don't track if the total number of regexp nodes - // we've seen times the repeat product is in budget. - if p.repeats == 0 { - p.repeats = 1 - } - if re.Op == OpRepeat { - n := re.Max - if n == -1 { - n = re.Min - } - if n <= 0 { - n = 1 - } - if int64(n) > maxSize/p.repeats { - p.repeats = maxSize - } else { - p.repeats *= int64(n) - } - } - if int64(p.numRegexp) < maxSize/p.repeats { - return - } - - // We need to start tracking size. - // Make the map and belatedly populate it - // with info about everything we've constructed so far. - p.size = make(map[*Regexp]int64) - for _, re := range p.stack { - p.checkSize(re) - } - } - - if p.calcSize(re, true) > maxSize { - panic(ErrLarge) - } -} - -func (p *parser) calcSize(re *Regexp, force bool) int64 { - if !force { - if size, ok := p.size[re]; ok { - return size - } - } - - var size int64 - switch re.Op { - case OpLiteral: - size = int64(len(re.Rune)) - case OpCapture, OpStar: - // star can be 1+ or 2+; assume 2 pessimistically - size = 2 + p.calcSize(re.Sub[0], false) - case OpPlus, OpQuest: - size = 1 + p.calcSize(re.Sub[0], false) - case OpConcat: - for _, sub := range re.Sub { - size += p.calcSize(sub, false) - } - case OpAlternate: - for _, sub := range re.Sub { - size += p.calcSize(sub, false) - } - if len(re.Sub) > 1 { - size += int64(len(re.Sub)) - 1 - } - case OpRepeat: - sub := p.calcSize(re.Sub[0], false) - if re.Max == -1 { - if re.Min == 0 { - size = 2 + sub // x* - } else { - size = 1 + int64(re.Min)*sub // xxx+ - } - break - } - // x{2,5} = xx(x(x(x)?)?)? - size = int64(re.Max)*sub + int64(re.Max-re.Min) - } - - if size < 1 { - size = 1 - } - p.size[re] = size - return size -} - -func (p *parser) checkHeight(re *Regexp) { - if p.numRegexp < maxHeight { - return - } - if p.height == nil { - p.height = make(map[*Regexp]int) - for _, re := range p.stack { - p.checkHeight(re) - } - } - if p.calcHeight(re, true) > maxHeight { - panic(ErrNestingDepth) - } -} - -func (p *parser) calcHeight(re *Regexp, force bool) int { - if !force { - if h, ok := p.height[re]; ok { - return h - } - } - h := 1 - for _, sub := range re.Sub { - hsub := p.calcHeight(sub, false) - if h < 1+hsub { - h = 1 + hsub - } - } - p.height[re] = h - return h -} - -// Parse stack manipulation. - -// push pushes the regexp re onto the parse stack and returns the regexp. -func (p *parser) push(re *Regexp) *Regexp { - p.numRunes += len(re.Rune) - if re.Op == OpCharClass && len(re.Rune) == 2 && re.Rune[0] == re.Rune[1] { - // Single rune. - if p.maybeConcat(re.Rune[0], p.flags&^FoldCase) { - return nil - } - re.Op = OpLiteral - re.Rune = re.Rune[:1] - re.Flags = p.flags &^ FoldCase - } else if re.Op == OpCharClass && len(re.Rune) == 4 && - re.Rune[0] == re.Rune[1] && re.Rune[2] == re.Rune[3] && - unicode.SimpleFold(re.Rune[0]) == re.Rune[2] && - unicode.SimpleFold(re.Rune[2]) == re.Rune[0] || - re.Op == OpCharClass && len(re.Rune) == 2 && - re.Rune[0]+1 == re.Rune[1] && - unicode.SimpleFold(re.Rune[0]) == re.Rune[1] && - unicode.SimpleFold(re.Rune[1]) == re.Rune[0] { - // Case-insensitive rune like [Aa] or [Δδ]. - if p.maybeConcat(re.Rune[0], p.flags|FoldCase) { - return nil - } - - // Rewrite as (case-insensitive) literal. - re.Op = OpLiteral - re.Rune = re.Rune[:1] - re.Flags = p.flags | FoldCase - } else { - // Incremental concatenation. - p.maybeConcat(-1, 0) - } - - p.stack = append(p.stack, re) - p.checkLimits(re) - return re -} - -// maybeConcat implements incremental concatenation -// of literal runes into string nodes. The parser calls this -// before each push, so only the top fragment of the stack -// might need processing. Since this is called before a push, -// the topmost literal is no longer subject to operators like * -// (Otherwise ab* would turn into (ab)*.) -// If r >= 0 and there's a node left over, maybeConcat uses it -// to push r with the given flags. -// maybeConcat reports whether r was pushed. -func (p *parser) maybeConcat(r rune, flags Flags) bool { - n := len(p.stack) - if n < 2 { - return false - } - - re1 := p.stack[n-1] - re2 := p.stack[n-2] - if re1.Op != OpLiteral || re2.Op != OpLiteral || re1.Flags&FoldCase != re2.Flags&FoldCase { - return false - } - - // Push re1 into re2. - re2.Rune = append(re2.Rune, re1.Rune...) - - // Reuse re1 if possible. - if r >= 0 { - re1.Rune = re1.Rune0[:1] - re1.Rune[0] = r - re1.Flags = flags - return true - } - - p.stack = p.stack[:n-1] - p.reuse(re1) - return false // did not push r -} - -// literal pushes a literal regexp for the rune r on the stack. -func (p *parser) literal(r rune) { - re := p.newRegexp(OpLiteral) - re.Flags = p.flags - if p.flags&FoldCase != 0 { - r = minFoldRune(r) - } - re.Rune0[0] = r - re.Rune = re.Rune0[:1] - p.push(re) -} - -// minFoldRune returns the minimum rune fold-equivalent to r. -func minFoldRune(r rune) rune { - if r < minFold || r > maxFold { - return r - } - m := r - r0 := r - for r = unicode.SimpleFold(r); r != r0; r = unicode.SimpleFold(r) { - m = min(m, r) - } - return m -} - -// op pushes a regexp with the given op onto the stack -// and returns that regexp. -func (p *parser) op(op Op) *Regexp { - re := p.newRegexp(op) - re.Flags = p.flags - return p.push(re) -} - -// repeat replaces the top stack element with itself repeated according to op, min, max. -// before is the regexp suffix starting at the repetition operator. -// after is the regexp suffix following after the repetition operator. -// repeat returns an updated 'after' and an error, if any. -func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (string, error) { - flags := p.flags - if p.flags&PerlX != 0 { - if len(after) > 0 && after[0] == '?' { - after = after[1:] - flags ^= NonGreedy - } - if lastRepeat != "" { - // In Perl it is not allowed to stack repetition operators: - // a** is a syntax error, not a doubled star, and a++ means - // something else entirely, which we don't support! - return "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(after)]} - } - } - n := len(p.stack) - if n == 0 { - return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]} - } - sub := p.stack[n-1] - if sub.Op >= opPseudo { - return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]} - } - - re := p.newRegexp(op) - re.Min = min - re.Max = max - re.Flags = flags - re.Sub = re.Sub0[:1] - re.Sub[0] = sub - p.stack[n-1] = re - p.checkLimits(re) - - if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) { - return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} - } - - return after, nil -} - -// repeatIsValid reports whether the repetition re is valid. -// Valid means that the combination of the top-level repetition -// and any inner repetitions does not exceed n copies of the -// innermost thing. -// This function rewalks the regexp tree and is called for every repetition, -// so we have to worry about inducing quadratic behavior in the parser. -// We avoid this by only calling repeatIsValid when min or max >= 2. -// In that case the depth of any >= 2 nesting can only get to 9 without -// triggering a parse error, so each subtree can only be rewalked 9 times. -func repeatIsValid(re *Regexp, n int) bool { - if re.Op == OpRepeat { - m := re.Max - if m == 0 { - return true - } - if m < 0 { - m = re.Min - } - if m > n { - return false - } - if m > 0 { - n /= m - } - } - for _, sub := range re.Sub { - if !repeatIsValid(sub, n) { - return false - } - } - return true -} - -// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation. -func (p *parser) concat() *Regexp { - p.maybeConcat(-1, 0) - - // Scan down to find pseudo-operator | or (. - i := len(p.stack) - for i > 0 && p.stack[i-1].Op < opPseudo { - i-- - } - subs := p.stack[i:] - p.stack = p.stack[:i] - - // Empty concatenation is special case. - if len(subs) == 0 { - return p.push(p.newRegexp(OpEmptyMatch)) - } - - return p.push(p.collapse(subs, OpConcat)) -} - -// alternate replaces the top of the stack (above the topmost '(') with its alternation. -func (p *parser) alternate() *Regexp { - // Scan down to find pseudo-operator (. - // There are no | above (. - i := len(p.stack) - for i > 0 && p.stack[i-1].Op < opPseudo { - i-- - } - subs := p.stack[i:] - p.stack = p.stack[:i] - - // Make sure top class is clean. - // All the others already are (see swapVerticalBar). - if len(subs) > 0 { - cleanAlt(subs[len(subs)-1]) - } - - // Empty alternate is special case - // (shouldn't happen but easy to handle). - if len(subs) == 0 { - return p.push(p.newRegexp(OpNoMatch)) - } - - return p.push(p.collapse(subs, OpAlternate)) -} - -// cleanAlt cleans re for eventual inclusion in an alternation. -func cleanAlt(re *Regexp) { - switch re.Op { - case OpCharClass: - re.Rune = cleanClass(&re.Rune) - if len(re.Rune) == 2 && re.Rune[0] == 0 && re.Rune[1] == unicode.MaxRune { - re.Rune = nil - re.Op = OpAnyChar - return - } - if len(re.Rune) == 4 && re.Rune[0] == 0 && re.Rune[1] == '\n'-1 && re.Rune[2] == '\n'+1 && re.Rune[3] == unicode.MaxRune { - re.Rune = nil - re.Op = OpAnyCharNotNL - return - } - if cap(re.Rune)-len(re.Rune) > 100 { - // re.Rune will not grow any more. - // Make a copy or inline to reclaim storage. - re.Rune = append(re.Rune0[:0], re.Rune...) - } - } -} - -// collapse returns the result of applying op to sub. -// If sub contains op nodes, they all get hoisted up -// so that there is never a concat of a concat or an -// alternate of an alternate. -func (p *parser) collapse(subs []*Regexp, op Op) *Regexp { - if len(subs) == 1 { - return subs[0] - } - re := p.newRegexp(op) - re.Sub = re.Sub0[:0] - for _, sub := range subs { - if sub.Op == op { - re.Sub = append(re.Sub, sub.Sub...) - p.reuse(sub) - } else { - re.Sub = append(re.Sub, sub) - } - } - if op == OpAlternate { - re.Sub = p.factor(re.Sub) - if len(re.Sub) == 1 { - old := re - re = re.Sub[0] - p.reuse(old) - } - } - return re -} - -// factor factors common prefixes from the alternation list sub. -// It returns a replacement list that reuses the same storage and -// frees (passes to p.reuse) any removed *Regexps. -// -// For example, -// -// ABC|ABD|AEF|BCX|BCY -// -// simplifies by literal prefix extraction to -// -// A(B(C|D)|EF)|BC(X|Y) -// -// which simplifies by character class introduction to -// -// A(B[CD]|EF)|BC[XY] -func (p *parser) factor(sub []*Regexp) []*Regexp { - if len(sub) < 2 { - return sub - } - - // Round 1: Factor out common literal prefixes. - var str []rune - var strflags Flags - start := 0 - out := sub[:0] - for i := 0; i <= len(sub); i++ { - // Invariant: the Regexps that were in sub[0:start] have been - // used or marked for reuse, and the slice space has been reused - // for out (len(out) <= start). - // - // Invariant: sub[start:i] consists of regexps that all begin - // with str as modified by strflags. - var istr []rune - var iflags Flags - if i < len(sub) { - istr, iflags = p.leadingString(sub[i]) - if iflags == strflags { - same := 0 - for same < len(str) && same < len(istr) && str[same] == istr[same] { - same++ - } - if same > 0 { - // Matches at least one rune in current range. - // Keep going around. - str = str[:same] - continue - } - } - } - - // Found end of a run with common leading literal string: - // sub[start:i] all begin with str[0:len(str)], but sub[i] - // does not even begin with str[0]. - // - // Factor out common string and append factored expression to out. - if i == start { - // Nothing to do - run of length 0. - } else if i == start+1 { - // Just one: don't bother factoring. - out = append(out, sub[start]) - } else { - // Construct factored form: prefix(suffix1|suffix2|...) - prefix := p.newRegexp(OpLiteral) - prefix.Flags = strflags - prefix.Rune = append(prefix.Rune[:0], str...) - - for j := start; j < i; j++ { - sub[j] = p.removeLeadingString(sub[j], len(str)) - p.checkLimits(sub[j]) - } - suffix := p.collapse(sub[start:i], OpAlternate) // recurse - - re := p.newRegexp(OpConcat) - re.Sub = append(re.Sub[:0], prefix, suffix) - out = append(out, re) - } - - // Prepare for next iteration. - start = i - str = istr - strflags = iflags - } - sub = out - - // Round 2: Factor out common simple prefixes, - // just the first piece of each concatenation. - // This will be good enough a lot of the time. - // - // Complex subexpressions (e.g. involving quantifiers) - // are not safe to factor because that collapses their - // distinct paths through the automaton, which affects - // correctness in some cases. - start = 0 - out = sub[:0] - var first *Regexp - for i := 0; i <= len(sub); i++ { - // Invariant: the Regexps that were in sub[0:start] have been - // used or marked for reuse, and the slice space has been reused - // for out (len(out) <= start). - // - // Invariant: sub[start:i] consists of regexps that all begin with ifirst. - var ifirst *Regexp - if i < len(sub) { - ifirst = p.leadingRegexp(sub[i]) - if first != nil && first.Equal(ifirst) && - // first must be a character class OR a fixed repeat of a character class. - (isCharClass(first) || (first.Op == OpRepeat && first.Min == first.Max && isCharClass(first.Sub[0]))) { - continue - } - } - - // Found end of a run with common leading regexp: - // sub[start:i] all begin with first but sub[i] does not. - // - // Factor out common regexp and append factored expression to out. - if i == start { - // Nothing to do - run of length 0. - } else if i == start+1 { - // Just one: don't bother factoring. - out = append(out, sub[start]) - } else { - // Construct factored form: prefix(suffix1|suffix2|...) - prefix := first - for j := start; j < i; j++ { - reuse := j != start // prefix came from sub[start] - sub[j] = p.removeLeadingRegexp(sub[j], reuse) - p.checkLimits(sub[j]) - } - suffix := p.collapse(sub[start:i], OpAlternate) // recurse - - re := p.newRegexp(OpConcat) - re.Sub = append(re.Sub[:0], prefix, suffix) - out = append(out, re) - } - - // Prepare for next iteration. - start = i - first = ifirst - } - sub = out - - // Round 3: Collapse runs of single literals into character classes. - start = 0 - out = sub[:0] - for i := 0; i <= len(sub); i++ { - // Invariant: the Regexps that were in sub[0:start] have been - // used or marked for reuse, and the slice space has been reused - // for out (len(out) <= start). - // - // Invariant: sub[start:i] consists of regexps that are either - // literal runes or character classes. - if i < len(sub) && isCharClass(sub[i]) { - continue - } - - // sub[i] is not a char or char class; - // emit char class for sub[start:i]... - if i == start { - // Nothing to do - run of length 0. - } else if i == start+1 { - out = append(out, sub[start]) - } else { - // Make new char class. - // Start with most complex regexp in sub[start]. - max := start - for j := start + 1; j < i; j++ { - if sub[max].Op < sub[j].Op || sub[max].Op == sub[j].Op && len(sub[max].Rune) < len(sub[j].Rune) { - max = j - } - } - sub[start], sub[max] = sub[max], sub[start] - - for j := start + 1; j < i; j++ { - mergeCharClass(sub[start], sub[j]) - p.reuse(sub[j]) - } - cleanAlt(sub[start]) - out = append(out, sub[start]) - } - - // ... and then emit sub[i]. - if i < len(sub) { - out = append(out, sub[i]) - } - start = i + 1 - } - sub = out - - // Round 4: Collapse runs of empty matches into a single empty match. - start = 0 - out = sub[:0] - for i := range sub { - if i+1 < len(sub) && sub[i].Op == OpEmptyMatch && sub[i+1].Op == OpEmptyMatch { - continue - } - out = append(out, sub[i]) - } - sub = out - - return sub -} - -// leadingString returns the leading literal string that re begins with. -// The string refers to storage in re or its children. -func (p *parser) leadingString(re *Regexp) ([]rune, Flags) { - if re.Op == OpConcat && len(re.Sub) > 0 { - re = re.Sub[0] - } - if re.Op != OpLiteral { - return nil, 0 - } - return re.Rune, re.Flags & FoldCase -} - -// removeLeadingString removes the first n leading runes -// from the beginning of re. It returns the replacement for re. -func (p *parser) removeLeadingString(re *Regexp, n int) *Regexp { - if re.Op == OpConcat && len(re.Sub) > 0 { - // Removing a leading string in a concatenation - // might simplify the concatenation. - sub := re.Sub[0] - sub = p.removeLeadingString(sub, n) - re.Sub[0] = sub - if sub.Op == OpEmptyMatch { - p.reuse(sub) - switch len(re.Sub) { - case 0, 1: - // Impossible but handle. - re.Op = OpEmptyMatch - re.Sub = nil - case 2: - old := re - re = re.Sub[1] - p.reuse(old) - default: - copy(re.Sub, re.Sub[1:]) - re.Sub = re.Sub[:len(re.Sub)-1] - } - } - return re - } - - if re.Op == OpLiteral { - re.Rune = re.Rune[:copy(re.Rune, re.Rune[n:])] - if len(re.Rune) == 0 { - re.Op = OpEmptyMatch - } - } - return re -} - -// leadingRegexp returns the leading regexp that re begins with. -// The regexp refers to storage in re or its children. -func (p *parser) leadingRegexp(re *Regexp) *Regexp { - if re.Op == OpEmptyMatch { - return nil - } - if re.Op == OpConcat && len(re.Sub) > 0 { - sub := re.Sub[0] - if sub.Op == OpEmptyMatch { - return nil - } - return sub - } - return re -} - -// removeLeadingRegexp removes the leading regexp in re. -// It returns the replacement for re. -// If reuse is true, it passes the removed regexp (if no longer needed) to p.reuse. -func (p *parser) removeLeadingRegexp(re *Regexp, reuse bool) *Regexp { - if re.Op == OpConcat && len(re.Sub) > 0 { - if reuse { - p.reuse(re.Sub[0]) - } - re.Sub = re.Sub[:copy(re.Sub, re.Sub[1:])] - switch len(re.Sub) { - case 0: - re.Op = OpEmptyMatch - re.Sub = nil - case 1: - old := re - re = re.Sub[0] - p.reuse(old) - } - return re - } - if reuse { - p.reuse(re) - } - return p.newRegexp(OpEmptyMatch) -} - -func literalRegexp(s string, flags Flags) *Regexp { - re := &Regexp{Op: OpLiteral} - re.Flags = flags - re.Rune = re.Rune0[:0] // use local storage for small strings - for _, c := range s { - if len(re.Rune) >= cap(re.Rune) { - // string is too long to fit in Rune0. let Go handle it - re.Rune = []rune(s) - break - } - re.Rune = append(re.Rune, c) - } - return re -} - -// Parsing. - -// Parse parses a regular expression string s, controlled by the specified -// Flags, and returns a regular expression parse tree. The syntax is -// described in the top-level comment. -func Parse(s string, flags Flags) (*Regexp, error) { - return parse(s, flags) -} - -func parse(s string, flags Flags) (_ *Regexp, err error) { - defer func() { - switch r := recover(); r { - default: - panic(r) - case nil: - // ok - case ErrLarge: // too big - err = &Error{Code: ErrLarge, Expr: s} - case ErrNestingDepth: - err = &Error{Code: ErrNestingDepth, Expr: s} - } - }() - - if flags&Literal != 0 { - // Trivial parser for literal string. - if err := checkUTF8(s); err != nil { - return nil, err - } - return literalRegexp(s, flags), nil - } - - // Otherwise, must do real work. - var ( - p parser - c rune - op Op - lastRepeat string - ) - p.flags = flags - p.wholeRegexp = s - t := s - for t != "" { - repeat := "" - BigSwitch: - switch t[0] { - default: - if c, t, err = nextRune(t); err != nil { - return nil, err - } - p.literal(c) - - case '(': - if p.flags&PerlX != 0 && len(t) >= 2 && t[1] == '?' { - // Flag changes and non-capturing groups. - if t, err = p.parsePerlFlags(t); err != nil { - return nil, err - } - break - } - p.numCap++ - p.op(opLeftParen).Cap = p.numCap - t = t[1:] - case '|': - if err = p.parseVerticalBar(); err != nil { - return nil, err - } - t = t[1:] - case ')': - if err = p.parseRightParen(); err != nil { - return nil, err - } - t = t[1:] - case '^': - if p.flags&OneLine != 0 { - p.op(OpBeginText) - } else { - p.op(OpBeginLine) - } - t = t[1:] - case '$': - if p.flags&OneLine != 0 { - p.op(OpEndText).Flags |= WasDollar - } else { - p.op(OpEndLine) - } - t = t[1:] - case '.': - if p.flags&DotNL != 0 { - p.op(OpAnyChar) - } else { - p.op(OpAnyCharNotNL) - } - t = t[1:] - case '[': - if t, err = p.parseClass(t); err != nil { - return nil, err - } - case '*', '+', '?': - before := t - switch t[0] { - case '*': - op = OpStar - case '+': - op = OpPlus - case '?': - op = OpQuest - } - after := t[1:] - if after, err = p.repeat(op, 0, 0, before, after, lastRepeat); err != nil { - return nil, err - } - repeat = before - t = after - case '{': - op = OpRepeat - before := t - min, max, after, ok := p.parseRepeat(t) - if !ok { - // If the repeat cannot be parsed, { is a literal. - p.literal('{') - t = t[1:] - break - } - if min < 0 || min > 1000 || max > 1000 || max >= 0 && min > max { - // Numbers were too big, or max is present and min > max. - return nil, &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} - } - if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil { - return nil, err - } - repeat = before - t = after - case '\\': - if p.flags&PerlX != 0 && len(t) >= 2 { - switch t[1] { - case 'A': - p.op(OpBeginText) - t = t[2:] - break BigSwitch - case 'b': - p.op(OpWordBoundary) - t = t[2:] - break BigSwitch - case 'B': - p.op(OpNoWordBoundary) - t = t[2:] - break BigSwitch - case 'C': - // any byte; not supported - return nil, &Error{ErrInvalidEscape, t[:2]} - case 'Q': - // \Q ... \E: the ... is always literals - var lit string - lit, t, _ = strings.Cut(t[2:], `\E`) - for lit != "" { - c, rest, err := nextRune(lit) - if err != nil { - return nil, err - } - p.literal(c) - lit = rest - } - break BigSwitch - case 'z': - p.op(OpEndText) - t = t[2:] - break BigSwitch - } - } - - re := p.newRegexp(OpCharClass) - re.Flags = p.flags - - // Look for Unicode character group like \p{Han} - if len(t) >= 2 && (t[1] == 'p' || t[1] == 'P') { - r, rest, err := p.parseUnicodeClass(t, re.Rune0[:0]) - if err != nil { - return nil, err - } - if r != nil { - re.Rune = r - t = rest - p.push(re) - break BigSwitch - } - } - - // Perl character class escape. - if r, rest := p.parsePerlClassEscape(t, re.Rune0[:0]); r != nil { - re.Rune = r - t = rest - p.push(re) - break BigSwitch - } - p.reuse(re) - - // Ordinary single-character escape. - if c, t, err = p.parseEscape(t); err != nil { - return nil, err - } - p.literal(c) - } - lastRepeat = repeat - } - - p.concat() - if p.swapVerticalBar() { - // pop vertical bar - p.stack = p.stack[:len(p.stack)-1] - } - p.alternate() - - n := len(p.stack) - if n != 1 { - return nil, &Error{ErrMissingParen, s} - } - return p.stack[0], nil -} - -// parseRepeat parses {min} (max=min) or {min,} (max=-1) or {min,max}. -// If s is not of that form, it returns ok == false. -// If s has the right form but the values are too big, it returns min == -1, ok == true. -func (p *parser) parseRepeat(s string) (min, max int, rest string, ok bool) { - if s == "" || s[0] != '{' { - return - } - s = s[1:] - var ok1 bool - if min, s, ok1 = p.parseInt(s); !ok1 { - return - } - if s == "" { - return - } - if s[0] != ',' { - max = min - } else { - s = s[1:] - if s == "" { - return - } - if s[0] == '}' { - max = -1 - } else if max, s, ok1 = p.parseInt(s); !ok1 { - return - } else if max < 0 { - // parseInt found too big a number - min = -1 - } - } - if s == "" || s[0] != '}' { - return - } - rest = s[1:] - ok = true - return -} - -// parsePerlFlags parses a Perl flag setting or non-capturing group or both, -// like (?i) or (?: or (?i:. It removes the prefix from s and updates the parse state. -// The caller must have ensured that s begins with "(?". -func (p *parser) parsePerlFlags(s string) (rest string, err error) { - t := s - - // Check for named captures, first introduced in Python's regexp library. - // As usual, there are three slightly different syntaxes: - // - // (?Pexpr) the original, introduced by Python - // (?expr) the .NET alteration, adopted by Perl 5.10 - // (?'name'expr) another .NET alteration, adopted by Perl 5.10 - // - // Perl 5.10 gave in and implemented the Python version too, - // but they claim that the last two are the preferred forms. - // PCRE and languages based on it (specifically, PHP and Ruby) - // support all three as well. EcmaScript 4 uses only the Python form. - // - // In both the open source world (via Code Search) and the - // Google source tree, (?Pname) and (?name) are the - // dominant forms of named captures and both are supported. - startsWithP := len(t) > 4 && t[2] == 'P' && t[3] == '<' - startsWithName := len(t) > 3 && t[2] == '<' - - if startsWithP || startsWithName { - // position of expr start - exprStartPos := 4 - if startsWithName { - exprStartPos = 3 - } - - // Pull out name. - end := strings.IndexRune(t, '>') - if end < 0 { - if err = checkUTF8(t); err != nil { - return "", err - } - return "", &Error{ErrInvalidNamedCapture, s} - } - - capture := t[:end+1] // "(?P" or "(?" - name := t[exprStartPos:end] // "name" - if err = checkUTF8(name); err != nil { - return "", err - } - if !isValidCaptureName(name) { - return "", &Error{ErrInvalidNamedCapture, capture} - } - - // Like ordinary capture, but named. - p.numCap++ - re := p.op(opLeftParen) - re.Cap = p.numCap - re.Name = name - return t[end+1:], nil - } - - // Non-capturing group. Might also twiddle Perl flags. - var c rune - t = t[2:] // skip (? - flags := p.flags - sign := +1 - sawFlag := false -Loop: - for t != "" { - if c, t, err = nextRune(t); err != nil { - return "", err - } - switch c { - default: - break Loop - - // Flags. - case 'i': - flags |= FoldCase - sawFlag = true - case 'm': - flags &^= OneLine - sawFlag = true - case 's': - flags |= DotNL - sawFlag = true - case 'U': - flags |= NonGreedy - sawFlag = true - - // Switch to negation. - case '-': - if sign < 0 { - break Loop - } - sign = -1 - // Invert flags so that | above turn into &^ and vice versa. - // We'll invert flags again before using it below. - flags = ^flags - sawFlag = false - - // End of flags, starting group or not. - case ':', ')': - if sign < 0 { - if !sawFlag { - break Loop - } - flags = ^flags - } - if c == ':' { - // Open new group - p.op(opLeftParen) - } - p.flags = flags - return t, nil - } - } - - return "", &Error{ErrInvalidPerlOp, s[:len(s)-len(t)]} -} - -// isValidCaptureName reports whether name -// is a valid capture name: [A-Za-z0-9_]+. -// PCRE limits names to 32 bytes. -// Python rejects names starting with digits. -// We don't enforce either of those. -func isValidCaptureName(name string) bool { - if name == "" { - return false - } - for _, c := range name { - if c != '_' && !isalnum(c) { - return false - } - } - return true -} - -// parseInt parses a decimal integer. -func (p *parser) parseInt(s string) (n int, rest string, ok bool) { - if s == "" || s[0] < '0' || '9' < s[0] { - return - } - // Disallow leading zeros. - if len(s) >= 2 && s[0] == '0' && '0' <= s[1] && s[1] <= '9' { - return - } - t := s - for s != "" && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - rest = s - ok = true - // Have digits, compute value. - t = t[:len(t)-len(s)] - for i := 0; i < len(t); i++ { - // Avoid overflow. - if n >= 1e8 { - n = -1 - break - } - n = n*10 + int(t[i]) - '0' - } - return -} - -// can this be represented as a character class? -// single-rune literal string, char class, ., and .|\n. -func isCharClass(re *Regexp) bool { - return re.Op == OpLiteral && len(re.Rune) == 1 || - re.Op == OpCharClass || - re.Op == OpAnyCharNotNL || - re.Op == OpAnyChar -} - -// does re match r? -func matchRune(re *Regexp, r rune) bool { - switch re.Op { - case OpLiteral: - return len(re.Rune) == 1 && re.Rune[0] == r - case OpCharClass: - for i := 0; i < len(re.Rune); i += 2 { - if re.Rune[i] <= r && r <= re.Rune[i+1] { - return true - } - } - return false - case OpAnyCharNotNL: - return r != '\n' - case OpAnyChar: - return true - } - return false -} - -// parseVerticalBar handles a | in the input. -func (p *parser) parseVerticalBar() error { - p.concat() - - // The concatenation we just parsed is on top of the stack. - // If it sits above an opVerticalBar, swap it below - // (things below an opVerticalBar become an alternation). - // Otherwise, push a new vertical bar. - if !p.swapVerticalBar() { - p.op(opVerticalBar) - } - - return nil -} - -// mergeCharClass makes dst = dst|src. -// The caller must ensure that dst.Op >= src.Op, -// to reduce the amount of copying. -func mergeCharClass(dst, src *Regexp) { - switch dst.Op { - case OpAnyChar: - // src doesn't add anything. - case OpAnyCharNotNL: - // src might add \n - if matchRune(src, '\n') { - dst.Op = OpAnyChar - } - case OpCharClass: - // src is simpler, so either literal or char class - if src.Op == OpLiteral { - dst.Rune = appendLiteral(dst.Rune, src.Rune[0], src.Flags) - } else { - dst.Rune = appendClass(dst.Rune, src.Rune) - } - case OpLiteral: - // both literal - if src.Rune[0] == dst.Rune[0] && src.Flags == dst.Flags { - break - } - dst.Op = OpCharClass - dst.Rune = appendLiteral(dst.Rune[:0], dst.Rune[0], dst.Flags) - dst.Rune = appendLiteral(dst.Rune, src.Rune[0], src.Flags) - } -} - -// If the top of the stack is an element followed by an opVerticalBar -// swapVerticalBar swaps the two and returns true. -// Otherwise it returns false. -func (p *parser) swapVerticalBar() bool { - // If above and below vertical bar are literal or char class, - // can merge into a single char class. - n := len(p.stack) - if n >= 3 && p.stack[n-2].Op == opVerticalBar && isCharClass(p.stack[n-1]) && isCharClass(p.stack[n-3]) { - re1 := p.stack[n-1] - re3 := p.stack[n-3] - // Make re3 the more complex of the two. - if re1.Op > re3.Op { - re1, re3 = re3, re1 - p.stack[n-3] = re3 - } - mergeCharClass(re3, re1) - p.reuse(re1) - p.stack = p.stack[:n-1] - return true - } - - if n >= 2 { - re1 := p.stack[n-1] - re2 := p.stack[n-2] - if re2.Op == opVerticalBar { - if n >= 3 { - // Now out of reach. - // Clean opportunistically. - cleanAlt(p.stack[n-3]) - } - p.stack[n-2] = re1 - p.stack[n-1] = re2 - return true - } - } - return false -} - -// parseRightParen handles a ) in the input. -func (p *parser) parseRightParen() error { - p.concat() - if p.swapVerticalBar() { - // pop vertical bar - p.stack = p.stack[:len(p.stack)-1] - } - p.alternate() - - n := len(p.stack) - if n < 2 { - return &Error{ErrUnexpectedParen, p.wholeRegexp} - } - re1 := p.stack[n-1] - re2 := p.stack[n-2] - p.stack = p.stack[:n-2] - if re2.Op != opLeftParen { - return &Error{ErrUnexpectedParen, p.wholeRegexp} - } - // Restore flags at time of paren. - p.flags = re2.Flags - if re2.Cap == 0 { - // Just for grouping. - p.push(re1) - } else { - re2.Op = OpCapture - re2.Sub = re2.Sub0[:1] - re2.Sub[0] = re1 - p.push(re2) - } - return nil -} - -// parseEscape parses an escape sequence at the beginning of s -// and returns the rune. -func (p *parser) parseEscape(s string) (r rune, rest string, err error) { - t := s[1:] - if t == "" { - return 0, "", &Error{ErrTrailingBackslash, ""} - } - c, t, err := nextRune(t) - if err != nil { - return 0, "", err - } - -Switch: - switch c { - default: - if c < utf8.RuneSelf && !isalnum(c) { - // Escaped non-word characters are always themselves. - // PCRE is not quite so rigorous: it accepts things like - // \q, but we don't. We once rejected \_, but too many - // programs and people insist on using it, so allow \_. - return c, t, nil - } - - // Octal escapes. - case '1', '2', '3', '4', '5', '6', '7': - // Single non-zero digit is a backreference; not supported - if t == "" || t[0] < '0' || t[0] > '7' { - break - } - fallthrough - case '0': - // Consume up to three octal digits; already have one. - r = c - '0' - for i := 1; i < 3; i++ { - if t == "" || t[0] < '0' || t[0] > '7' { - break - } - r = r*8 + rune(t[0]) - '0' - t = t[1:] - } - return r, t, nil - - // Hexadecimal escapes. - case 'x': - if t == "" { - break - } - if c, t, err = nextRune(t); err != nil { - return 0, "", err - } - if c == '{' { - // Any number of digits in braces. - // Perl accepts any text at all; it ignores all text - // after the first non-hex digit. We require only hex digits, - // and at least one. - nhex := 0 - r = 0 - for { - if t == "" { - break Switch - } - if c, t, err = nextRune(t); err != nil { - return 0, "", err - } - if c == '}' { - break - } - v := unhex(c) - if v < 0 { - break Switch - } - r = r*16 + v - if r > unicode.MaxRune { - break Switch - } - nhex++ - } - if nhex == 0 { - break Switch - } - return r, t, nil - } - - // Easy case: two hex digits. - x := unhex(c) - if c, t, err = nextRune(t); err != nil { - return 0, "", err - } - y := unhex(c) - if x < 0 || y < 0 { - break - } - return x*16 + y, t, nil - - // C escapes. There is no case 'b', to avoid misparsing - // the Perl word-boundary \b as the C backspace \b - // when in POSIX mode. In Perl, /\b/ means word-boundary - // but /[\b]/ means backspace. We don't support that. - // If you want a backspace, embed a literal backspace - // character or use \x08. - case 'a': - return '\a', t, err - case 'f': - return '\f', t, err - case 'n': - return '\n', t, err - case 'r': - return '\r', t, err - case 't': - return '\t', t, err - case 'v': - return '\v', t, err - } - return 0, "", &Error{ErrInvalidEscape, s[:len(s)-len(t)]} -} - -// parseClassChar parses a character class character at the beginning of s -// and returns it. -func (p *parser) parseClassChar(s, wholeClass string) (r rune, rest string, err error) { - if s == "" { - return 0, "", &Error{Code: ErrMissingBracket, Expr: wholeClass} - } - - // Allow regular escape sequences even though - // many need not be escaped in this context. - if s[0] == '\\' { - return p.parseEscape(s) - } - - return nextRune(s) -} - -type charGroup struct { - sign int - class []rune -} - -// parsePerlClassEscape parses a leading Perl character class escape like \d -// from the beginning of s. If one is present, it appends the characters to r -// and returns the new slice r and the remainder of the string. -func (p *parser) parsePerlClassEscape(s string, r []rune) (out []rune, rest string) { - if p.flags&PerlX == 0 || len(s) < 2 || s[0] != '\\' { - return - } - g := perlGroup[s[0:2]] - if g.sign == 0 { - return - } - return p.appendGroup(r, g), s[2:] -} - -// parseNamedClass parses a leading POSIX named character class like [:alnum:] -// from the beginning of s. If one is present, it appends the characters to r -// and returns the new slice r and the remainder of the string. -func (p *parser) parseNamedClass(s string, r []rune) (out []rune, rest string, err error) { - if len(s) < 2 || s[0] != '[' || s[1] != ':' { - return - } - - i := strings.Index(s[2:], ":]") - if i < 0 { - return - } - i += 2 - name, s := s[0:i+2], s[i+2:] - g := posixGroup[name] - if g.sign == 0 { - return nil, "", &Error{ErrInvalidCharRange, name} - } - return p.appendGroup(r, g), s, nil -} - -func (p *parser) appendGroup(r []rune, g charGroup) []rune { - if p.flags&FoldCase == 0 { - if g.sign < 0 { - r = appendNegatedClass(r, g.class) - } else { - r = appendClass(r, g.class) - } - } else { - tmp := p.tmpClass[:0] - tmp = appendFoldedClass(tmp, g.class) - p.tmpClass = tmp - tmp = cleanClass(&p.tmpClass) - if g.sign < 0 { - r = appendNegatedClass(r, tmp) - } else { - r = appendClass(r, tmp) - } - } - return r -} - -var anyTable = &unicode.RangeTable{ - R16: []unicode.Range16{{Lo: 0, Hi: 1<<16 - 1, Stride: 1}}, - R32: []unicode.Range32{{Lo: 1 << 16, Hi: unicode.MaxRune, Stride: 1}}, -} - -// unicodeTable returns the unicode.RangeTable identified by name -// and the table of additional fold-equivalent code points. -func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) { - // Special case: "Any" means any. - if name == "Any" { - return anyTable, anyTable - } - if t := unicode.Categories[name]; t != nil { - return t, unicode.FoldCategory[name] - } - if t := unicode.Scripts[name]; t != nil { - return t, unicode.FoldScript[name] - } - return nil, nil -} - -// parseUnicodeClass parses a leading Unicode character class like \p{Han} -// from the beginning of s. If one is present, it appends the characters to r -// and returns the new slice r and the remainder of the string. -func (p *parser) parseUnicodeClass(s string, r []rune) (out []rune, rest string, err error) { - if p.flags&UnicodeGroups == 0 || len(s) < 2 || s[0] != '\\' || s[1] != 'p' && s[1] != 'P' { - return - } - - // Committed to parse or return error. - sign := +1 - if s[1] == 'P' { - sign = -1 - } - t := s[2:] - c, t, err := nextRune(t) - if err != nil { - return - } - var seq, name string - if c != '{' { - // Single-letter name. - seq = s[:len(s)-len(t)] - name = seq[2:] - } else { - // Name is in braces. - end := strings.IndexRune(s, '}') - if end < 0 { - if err = checkUTF8(s); err != nil { - return - } - return nil, "", &Error{ErrInvalidCharRange, s} - } - seq, t = s[:end+1], s[end+1:] - name = s[3:end] - if err = checkUTF8(name); err != nil { - return - } - } - - // Group can have leading negation too. \p{^Han} == \P{Han}, \P{^Han} == \p{Han}. - if name != "" && name[0] == '^' { - sign = -sign - name = name[1:] - } - - tab, fold := unicodeTable(name) - if tab == nil { - return nil, "", &Error{ErrInvalidCharRange, seq} - } - - if p.flags&FoldCase == 0 || fold == nil { - if sign > 0 { - r = appendTable(r, tab) - } else { - r = appendNegatedTable(r, tab) - } - } else { - // Merge and clean tab and fold in a temporary buffer. - // This is necessary for the negative case and just tidy - // for the positive case. - tmp := p.tmpClass[:0] - tmp = appendTable(tmp, tab) - tmp = appendTable(tmp, fold) - p.tmpClass = tmp - tmp = cleanClass(&p.tmpClass) - if sign > 0 { - r = appendClass(r, tmp) - } else { - r = appendNegatedClass(r, tmp) - } - } - return r, t, nil -} - -// parseClass parses a character class at the beginning of s -// and pushes it onto the parse stack. -func (p *parser) parseClass(s string) (rest string, err error) { - t := s[1:] // chop [ - re := p.newRegexp(OpCharClass) - re.Flags = p.flags - re.Rune = re.Rune0[:0] - - sign := +1 - if t != "" && t[0] == '^' { - sign = -1 - t = t[1:] - - // If character class does not match \n, add it here, - // so that negation later will do the right thing. - if p.flags&ClassNL == 0 { - re.Rune = append(re.Rune, '\n', '\n') - } - } - - class := re.Rune - first := true // ] and - are okay as first char in class - for t == "" || t[0] != ']' || first { - // POSIX: - is only okay unescaped as first or last in class. - // Perl: - is okay anywhere. - if t != "" && t[0] == '-' && p.flags&PerlX == 0 && !first && (len(t) == 1 || t[1] != ']') { - _, size := utf8.DecodeRuneInString(t[1:]) - return "", &Error{Code: ErrInvalidCharRange, Expr: t[:1+size]} - } - first = false - - // Look for POSIX [:alnum:] etc. - if len(t) > 2 && t[0] == '[' && t[1] == ':' { - nclass, nt, err := p.parseNamedClass(t, class) - if err != nil { - return "", err - } - if nclass != nil { - class, t = nclass, nt - continue - } - } - - // Look for Unicode character group like \p{Han}. - nclass, nt, err := p.parseUnicodeClass(t, class) - if err != nil { - return "", err - } - if nclass != nil { - class, t = nclass, nt - continue - } - - // Look for Perl character class symbols (extension). - if nclass, nt := p.parsePerlClassEscape(t, class); nclass != nil { - class, t = nclass, nt - continue - } - - // Single character or simple range. - rng := t - var lo, hi rune - if lo, t, err = p.parseClassChar(t, s); err != nil { - return "", err - } - hi = lo - // [a-] means (a|-) so check for final ]. - if len(t) >= 2 && t[0] == '-' && t[1] != ']' { - t = t[1:] - if hi, t, err = p.parseClassChar(t, s); err != nil { - return "", err - } - if hi < lo { - rng = rng[:len(rng)-len(t)] - return "", &Error{Code: ErrInvalidCharRange, Expr: rng} - } - } - if p.flags&FoldCase == 0 { - class = appendRange(class, lo, hi) - } else { - class = appendFoldedRange(class, lo, hi) - } - } - t = t[1:] // chop ] - - // Use &re.Rune instead of &class to avoid allocation. - re.Rune = class - class = cleanClass(&re.Rune) - if sign < 0 { - class = negateClass(class) - } - re.Rune = class - p.push(re) - return t, nil -} - -// cleanClass sorts the ranges (pairs of elements of r), -// merges them, and eliminates duplicates. -func cleanClass(rp *[]rune) []rune { - - // Sort by lo increasing, hi decreasing to break ties. - sort.Sort(ranges{rp}) - - r := *rp - if len(r) < 2 { - return r - } - - // Merge abutting, overlapping. - w := 2 // write index - for i := 2; i < len(r); i += 2 { - lo, hi := r[i], r[i+1] - if lo <= r[w-1]+1 { - // merge with previous range - if hi > r[w-1] { - r[w-1] = hi - } - continue - } - // new disjoint range - r[w] = lo - r[w+1] = hi - w += 2 - } - - return r[:w] -} - -// inCharClass reports whether r is in the class. -// It assumes the class has been cleaned by cleanClass. -func inCharClass(r rune, class []rune) bool { - _, ok := sort.Find(len(class)/2, func(i int) int { - lo, hi := class[2*i], class[2*i+1] - if r > hi { - return +1 - } - if r < lo { - return -1 - } - return 0 - }) - return ok -} - -// appendLiteral returns the result of appending the literal x to the class r. -func appendLiteral(r []rune, x rune, flags Flags) []rune { - if flags&FoldCase != 0 { - return appendFoldedRange(r, x, x) - } - return appendRange(r, x, x) -} - -// appendRange returns the result of appending the range lo-hi to the class r. -func appendRange(r []rune, lo, hi rune) []rune { - // Expand last range or next to last range if it overlaps or abuts. - // Checking two ranges helps when appending case-folded - // alphabets, so that one range can be expanding A-Z and the - // other expanding a-z. - n := len(r) - for i := 2; i <= 4; i += 2 { // twice, using i=2, i=4 - if n >= i { - rlo, rhi := r[n-i], r[n-i+1] - if lo <= rhi+1 && rlo <= hi+1 { - if lo < rlo { - r[n-i] = lo - } - if hi > rhi { - r[n-i+1] = hi - } - return r - } - } - } - - return append(r, lo, hi) -} - -const ( - // minimum and maximum runes involved in folding. - // checked during test. - minFold = 0x0041 - maxFold = 0x1e943 -) - -// appendFoldedRange returns the result of appending the range lo-hi -// and its case folding-equivalent runes to the class r. -func appendFoldedRange(r []rune, lo, hi rune) []rune { - // Optimizations. - if lo <= minFold && hi >= maxFold { - // Range is full: folding can't add more. - return appendRange(r, lo, hi) - } - if hi < minFold || lo > maxFold { - // Range is outside folding possibilities. - return appendRange(r, lo, hi) - } - if lo < minFold { - // [lo, minFold-1] needs no folding. - r = appendRange(r, lo, minFold-1) - lo = minFold - } - if hi > maxFold { - // [maxFold+1, hi] needs no folding. - r = appendRange(r, maxFold+1, hi) - hi = maxFold - } - - // Brute force. Depend on appendRange to coalesce ranges on the fly. - for c := lo; c <= hi; c++ { - r = appendRange(r, c, c) - f := unicode.SimpleFold(c) - for f != c { - r = appendRange(r, f, f) - f = unicode.SimpleFold(f) - } - } - return r -} - -// appendClass returns the result of appending the class x to the class r. -// It assume x is clean. -func appendClass(r []rune, x []rune) []rune { - for i := 0; i < len(x); i += 2 { - r = appendRange(r, x[i], x[i+1]) - } - return r -} - -// appendFoldedClass returns the result of appending the case folding of the class x to the class r. -func appendFoldedClass(r []rune, x []rune) []rune { - for i := 0; i < len(x); i += 2 { - r = appendFoldedRange(r, x[i], x[i+1]) - } - return r -} - -// appendNegatedClass returns the result of appending the negation of the class x to the class r. -// It assumes x is clean. -func appendNegatedClass(r []rune, x []rune) []rune { - nextLo := '\u0000' - for i := 0; i < len(x); i += 2 { - lo, hi := x[i], x[i+1] - if nextLo <= lo-1 { - r = appendRange(r, nextLo, lo-1) - } - nextLo = hi + 1 - } - if nextLo <= unicode.MaxRune { - r = appendRange(r, nextLo, unicode.MaxRune) - } - return r -} - -// appendTable returns the result of appending x to the class r. -func appendTable(r []rune, x *unicode.RangeTable) []rune { - for _, xr := range x.R16 { - lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride) - if stride == 1 { - r = appendRange(r, lo, hi) - continue - } - for c := lo; c <= hi; c += stride { - r = appendRange(r, c, c) - } - } - for _, xr := range x.R32 { - lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride) - if stride == 1 { - r = appendRange(r, lo, hi) - continue - } - for c := lo; c <= hi; c += stride { - r = appendRange(r, c, c) - } - } - return r -} - -// appendNegatedTable returns the result of appending the negation of x to the class r. -func appendNegatedTable(r []rune, x *unicode.RangeTable) []rune { - nextLo := '\u0000' // lo end of next class to add - for _, xr := range x.R16 { - lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride) - if stride == 1 { - if nextLo <= lo-1 { - r = appendRange(r, nextLo, lo-1) - } - nextLo = hi + 1 - continue - } - for c := lo; c <= hi; c += stride { - if nextLo <= c-1 { - r = appendRange(r, nextLo, c-1) - } - nextLo = c + 1 - } - } - for _, xr := range x.R32 { - lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride) - if stride == 1 { - if nextLo <= lo-1 { - r = appendRange(r, nextLo, lo-1) - } - nextLo = hi + 1 - continue - } - for c := lo; c <= hi; c += stride { - if nextLo <= c-1 { - r = appendRange(r, nextLo, c-1) - } - nextLo = c + 1 - } - } - if nextLo <= unicode.MaxRune { - r = appendRange(r, nextLo, unicode.MaxRune) - } - return r -} - -// negateClass overwrites r and returns r's negation. -// It assumes the class r is already clean. -func negateClass(r []rune) []rune { - nextLo := '\u0000' // lo end of next class to add - w := 0 // write index - for i := 0; i < len(r); i += 2 { - lo, hi := r[i], r[i+1] - if nextLo <= lo-1 { - r[w] = nextLo - r[w+1] = lo - 1 - w += 2 - } - nextLo = hi + 1 - } - r = r[:w] - if nextLo <= unicode.MaxRune { - // It's possible for the negation to have one more - // range - this one - than the original class, so use append. - r = append(r, nextLo, unicode.MaxRune) - } - return r -} - -// ranges implements sort.Interface on a []rune. -// The choice of receiver type definition is strange -// but avoids an allocation since we already have -// a *[]rune. -type ranges struct { - p *[]rune -} - -func (ra ranges) Less(i, j int) bool { - p := *ra.p - i *= 2 - j *= 2 - return p[i] < p[j] || p[i] == p[j] && p[i+1] > p[j+1] -} - -func (ra ranges) Len() int { - return len(*ra.p) / 2 -} - -func (ra ranges) Swap(i, j int) { - p := *ra.p - i *= 2 - j *= 2 - p[i], p[i+1], p[j], p[j+1] = p[j], p[j+1], p[i], p[i+1] -} - -func checkUTF8(s string) error { - for s != "" { - rune, size := utf8.DecodeRuneInString(s) - if rune == utf8.RuneError && size == 1 { - return &Error{Code: ErrInvalidUTF8, Expr: s} - } - s = s[size:] - } - return nil -} - -func nextRune(s string) (c rune, t string, err error) { - c, size := utf8.DecodeRuneInString(s) - if c == utf8.RuneError && size == 1 { - return 0, "", &Error{Code: ErrInvalidUTF8, Expr: s} - } - return c, s[size:], nil -} - -func isalnum(c rune) bool { - return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' -} - -func unhex(c rune) rune { - if '0' <= c && c <= '9' { - return c - '0' - } - if 'a' <= c && c <= 'f' { - return c - 'a' + 10 - } - if 'A' <= c && c <= 'F' { - return c - 'A' + 10 - } - return -1 -} diff --git a/contrib/go/_std_1.22/src/regexp/syntax/regexp.go b/contrib/go/_std_1.22/src/regexp/syntax/regexp.go deleted file mode 100644 index 4fa7d0e2f833..000000000000 --- a/contrib/go/_std_1.22/src/regexp/syntax/regexp.go +++ /dev/null @@ -1,477 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syntax - -// Note to implementers: -// In this package, re is always a *Regexp and r is always a rune. - -import ( - "strconv" - "strings" - "unicode" -) - -// A Regexp is a node in a regular expression syntax tree. -type Regexp struct { - Op Op // operator - Flags Flags - Sub []*Regexp // subexpressions, if any - Sub0 [1]*Regexp // storage for short Sub - Rune []rune // matched runes, for OpLiteral, OpCharClass - Rune0 [2]rune // storage for short Rune - Min, Max int // min, max for OpRepeat - Cap int // capturing index, for OpCapture - Name string // capturing name, for OpCapture -} - -//go:generate stringer -type Op -trimprefix Op - -// An Op is a single regular expression operator. -type Op uint8 - -// Operators are listed in precedence order, tightest binding to weakest. -// Character class operators are listed simplest to most complex -// (OpLiteral, OpCharClass, OpAnyCharNotNL, OpAnyChar). - -const ( - OpNoMatch Op = 1 + iota // matches no strings - OpEmptyMatch // matches empty string - OpLiteral // matches Runes sequence - OpCharClass // matches Runes interpreted as range pair list - OpAnyCharNotNL // matches any character except newline - OpAnyChar // matches any character - OpBeginLine // matches empty string at beginning of line - OpEndLine // matches empty string at end of line - OpBeginText // matches empty string at beginning of text - OpEndText // matches empty string at end of text - OpWordBoundary // matches word boundary `\b` - OpNoWordBoundary // matches word non-boundary `\B` - OpCapture // capturing subexpression with index Cap, optional name Name - OpStar // matches Sub[0] zero or more times - OpPlus // matches Sub[0] one or more times - OpQuest // matches Sub[0] zero or one times - OpRepeat // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit) - OpConcat // matches concatenation of Subs - OpAlternate // matches alternation of Subs -) - -const opPseudo Op = 128 // where pseudo-ops start - -// Equal reports whether x and y have identical structure. -func (x *Regexp) Equal(y *Regexp) bool { - if x == nil || y == nil { - return x == y - } - if x.Op != y.Op { - return false - } - switch x.Op { - case OpEndText: - // The parse flags remember whether this is \z or \Z. - if x.Flags&WasDollar != y.Flags&WasDollar { - return false - } - - case OpLiteral, OpCharClass: - if len(x.Rune) != len(y.Rune) { - return false - } - for i, r := range x.Rune { - if r != y.Rune[i] { - return false - } - } - - case OpAlternate, OpConcat: - if len(x.Sub) != len(y.Sub) { - return false - } - for i, sub := range x.Sub { - if !sub.Equal(y.Sub[i]) { - return false - } - } - - case OpStar, OpPlus, OpQuest: - if x.Flags&NonGreedy != y.Flags&NonGreedy || !x.Sub[0].Equal(y.Sub[0]) { - return false - } - - case OpRepeat: - if x.Flags&NonGreedy != y.Flags&NonGreedy || x.Min != y.Min || x.Max != y.Max || !x.Sub[0].Equal(y.Sub[0]) { - return false - } - - case OpCapture: - if x.Cap != y.Cap || x.Name != y.Name || !x.Sub[0].Equal(y.Sub[0]) { - return false - } - } - return true -} - -// printFlags is a bit set indicating which flags (including non-capturing parens) to print around a regexp. -type printFlags uint8 - -const ( - flagI printFlags = 1 << iota // (?i: - flagM // (?m: - flagS // (?s: - flagOff // ) - flagPrec // (?: ) - negShift = 5 // flagI<") - case OpNoMatch: - b.WriteString(`[^\x00-\x{10FFFF}]`) - case OpEmptyMatch: - b.WriteString(`(?:)`) - case OpLiteral: - for _, r := range re.Rune { - escape(b, r, false) - } - case OpCharClass: - if len(re.Rune)%2 != 0 { - b.WriteString(`[invalid char class]`) - break - } - b.WriteRune('[') - if len(re.Rune) == 0 { - b.WriteString(`^\x00-\x{10FFFF}`) - } else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune && len(re.Rune) > 2 { - // Contains 0 and MaxRune. Probably a negated class. - // Print the gaps. - b.WriteRune('^') - for i := 1; i < len(re.Rune)-1; i += 2 { - lo, hi := re.Rune[i]+1, re.Rune[i+1]-1 - escape(b, lo, lo == '-') - if lo != hi { - if hi != lo+1 { - b.WriteRune('-') - } - escape(b, hi, hi == '-') - } - } - } else { - for i := 0; i < len(re.Rune); i += 2 { - lo, hi := re.Rune[i], re.Rune[i+1] - escape(b, lo, lo == '-') - if lo != hi { - if hi != lo+1 { - b.WriteRune('-') - } - escape(b, hi, hi == '-') - } - } - } - b.WriteRune(']') - case OpAnyCharNotNL, OpAnyChar: - b.WriteString(`.`) - case OpBeginLine: - b.WriteString(`^`) - case OpEndLine: - b.WriteString(`$`) - case OpBeginText: - b.WriteString(`\A`) - case OpEndText: - if re.Flags&WasDollar != 0 { - b.WriteString(`$`) - } else { - b.WriteString(`\z`) - } - case OpWordBoundary: - b.WriteString(`\b`) - case OpNoWordBoundary: - b.WriteString(`\B`) - case OpCapture: - if re.Name != "" { - b.WriteString(`(?P<`) - b.WriteString(re.Name) - b.WriteRune('>') - } else { - b.WriteRune('(') - } - if re.Sub[0].Op != OpEmptyMatch { - writeRegexp(b, re.Sub[0], flags[re.Sub[0]], flags) - } - b.WriteRune(')') - case OpStar, OpPlus, OpQuest, OpRepeat: - p := printFlags(0) - sub := re.Sub[0] - if sub.Op > OpCapture || sub.Op == OpLiteral && len(sub.Rune) > 1 { - p = flagPrec - } - writeRegexp(b, sub, p, flags) - - switch re.Op { - case OpStar: - b.WriteRune('*') - case OpPlus: - b.WriteRune('+') - case OpQuest: - b.WriteRune('?') - case OpRepeat: - b.WriteRune('{') - b.WriteString(strconv.Itoa(re.Min)) - if re.Max != re.Min { - b.WriteRune(',') - if re.Max >= 0 { - b.WriteString(strconv.Itoa(re.Max)) - } - } - b.WriteRune('}') - } - if re.Flags&NonGreedy != 0 { - b.WriteRune('?') - } - case OpConcat: - for _, sub := range re.Sub { - p := printFlags(0) - if sub.Op == OpAlternate { - p = flagPrec - } - writeRegexp(b, sub, p, flags) - } - case OpAlternate: - for i, sub := range re.Sub { - if i > 0 { - b.WriteRune('|') - } - writeRegexp(b, sub, 0, flags) - } - } -} - -func (re *Regexp) String() string { - var b strings.Builder - var flags map[*Regexp]printFlags - must, cant := calcFlags(re, &flags) - must |= (cant &^ flagI) << negShift - if must != 0 { - must |= flagOff - } - writeRegexp(&b, re, must, flags) - return b.String() -} - -const meta = `\.+*?()|[]{}^$` - -func escape(b *strings.Builder, r rune, force bool) { - if unicode.IsPrint(r) { - if strings.ContainsRune(meta, r) || force { - b.WriteRune('\\') - } - b.WriteRune(r) - return - } - - switch r { - case '\a': - b.WriteString(`\a`) - case '\f': - b.WriteString(`\f`) - case '\n': - b.WriteString(`\n`) - case '\r': - b.WriteString(`\r`) - case '\t': - b.WriteString(`\t`) - case '\v': - b.WriteString(`\v`) - default: - if r < 0x100 { - b.WriteString(`\x`) - s := strconv.FormatInt(int64(r), 16) - if len(s) == 1 { - b.WriteRune('0') - } - b.WriteString(s) - break - } - b.WriteString(`\x{`) - b.WriteString(strconv.FormatInt(int64(r), 16)) - b.WriteString(`}`) - } -} - -// MaxCap walks the regexp to find the maximum capture index. -func (re *Regexp) MaxCap() int { - m := 0 - if re.Op == OpCapture { - m = re.Cap - } - for _, sub := range re.Sub { - if n := sub.MaxCap(); m < n { - m = n - } - } - return m -} - -// CapNames walks the regexp to find the names of capturing groups. -func (re *Regexp) CapNames() []string { - names := make([]string, re.MaxCap()+1) - re.capNames(names) - return names -} - -func (re *Regexp) capNames(names []string) { - if re.Op == OpCapture { - names[re.Cap] = re.Name - } - for _, sub := range re.Sub { - sub.capNames(names) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/arena.go b/contrib/go/_std_1.22/src/runtime/arena.go deleted file mode 100644 index e943817ceeab..000000000000 --- a/contrib/go/_std_1.22/src/runtime/arena.go +++ /dev/null @@ -1,935 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Implementation of (safe) user arenas. -// -// This file contains the implementation of user arenas wherein Go values can -// be manually allocated and freed in bulk. The act of manually freeing memory, -// potentially before a GC cycle, means that a garbage collection cycle can be -// delayed, improving efficiency by reducing GC cycle frequency. There are other -// potential efficiency benefits, such as improved locality and access to a more -// efficient allocation strategy. -// -// What makes the arenas here safe is that once they are freed, accessing the -// arena's memory will cause an explicit program fault, and the arena's address -// space will not be reused until no more pointers into it are found. There's one -// exception to this: if an arena allocated memory that isn't exhausted, it's placed -// back into a pool for reuse. This means that a crash is not always guaranteed. -// -// While this may seem unsafe, it still prevents memory corruption, and is in fact -// necessary in order to make new(T) a valid implementation of arenas. Such a property -// is desirable to allow for a trivial implementation. (It also avoids complexities -// that arise from synchronization with the GC when trying to set the arena chunks to -// fault while the GC is active.) -// -// The implementation works in layers. At the bottom, arenas are managed in chunks. -// Each chunk must be a multiple of the heap arena size, or the heap arena size must -// be divisible by the arena chunks. The address space for each chunk, and each -// corresponding heapArena for that address space, are eternally reserved for use as -// arena chunks. That is, they can never be used for the general heap. Each chunk -// is also represented by a single mspan, and is modeled as a single large heap -// allocation. It must be, because each chunk contains ordinary Go values that may -// point into the heap, so it must be scanned just like any other object. Any -// pointer into a chunk will therefore always cause the whole chunk to be scanned -// while its corresponding arena is still live. -// -// Chunks may be allocated either from new memory mapped by the OS on our behalf, -// or by reusing old freed chunks. When chunks are freed, their underlying memory -// is returned to the OS, set to fault on access, and may not be reused until the -// program doesn't point into the chunk anymore (the code refers to this state as -// "quarantined"), a property checked by the GC. -// -// The sweeper handles moving chunks out of this quarantine state to be ready for -// reuse. When the chunk is placed into the quarantine state, its corresponding -// span is marked as noscan so that the GC doesn't try to scan memory that would -// cause a fault. -// -// At the next layer are the user arenas themselves. They consist of a single -// active chunk which new Go values are bump-allocated into and a list of chunks -// that were exhausted when allocating into the arena. Once the arena is freed, -// it frees all full chunks it references, and places the active one onto a reuse -// list for a future arena to use. Each arena keeps its list of referenced chunks -// explicitly live until it is freed. Each user arena also maps to an object which -// has a finalizer attached that ensures the arena's chunks are all freed even if -// the arena itself is never explicitly freed. -// -// Pointer-ful memory is bump-allocated from low addresses to high addresses in each -// chunk, while pointer-free memory is bump-allocated from high address to low -// addresses. The reason for this is to take advantage of a GC optimization wherein -// the GC will stop scanning an object when there are no more pointers in it, which -// also allows us to elide clearing the heap bitmap for pointer-free Go values -// allocated into arenas. -// -// Note that arenas are not safe to use concurrently. -// -// In summary, there are 2 resources: arenas, and arena chunks. They exist in the -// following lifecycle: -// -// (1) A new arena is created via newArena. -// (2) Chunks are allocated to hold memory allocated into the arena with new or slice. -// (a) Chunks are first allocated from the reuse list of partially-used chunks. -// (b) If there are no such chunks, then chunks on the ready list are taken. -// (c) Failing all the above, memory for a new chunk is mapped. -// (3) The arena is freed, or all references to it are dropped, triggering its finalizer. -// (a) If the GC is not active, exhausted chunks are set to fault and placed on a -// quarantine list. -// (b) If the GC is active, exhausted chunks are placed on a fault list and will -// go through step (a) at a later point in time. -// (c) Any remaining partially-used chunk is placed on a reuse list. -// (4) Once no more pointers are found into quarantined arena chunks, the sweeper -// takes these chunks out of quarantine and places them on the ready list. - -package runtime - -import ( - "internal/goarch" - "internal/goexperiment" - "runtime/internal/atomic" - "runtime/internal/math" - "unsafe" -) - -// Functions starting with arena_ are meant to be exported to downstream users -// of arenas. They should wrap these functions in a higher-lever API. -// -// The underlying arena and its resources are managed through an opaque unsafe.Pointer. - -// arena_newArena is a wrapper around newUserArena. -// -//go:linkname arena_newArena arena.runtime_arena_newArena -func arena_newArena() unsafe.Pointer { - return unsafe.Pointer(newUserArena()) -} - -// arena_arena_New is a wrapper around (*userArena).new, except that typ -// is an any (must be a *_type, still) and typ must be a type descriptor -// for a pointer to the type to actually be allocated, i.e. pass a *T -// to allocate a T. This is necessary because this function returns a *T. -// -//go:linkname arena_arena_New arena.runtime_arena_arena_New -func arena_arena_New(arena unsafe.Pointer, typ any) any { - t := (*_type)(efaceOf(&typ).data) - if t.Kind_&kindMask != kindPtr { - throw("arena_New: non-pointer type") - } - te := (*ptrtype)(unsafe.Pointer(t)).Elem - x := ((*userArena)(arena)).new(te) - var result any - e := efaceOf(&result) - e._type = t - e.data = x - return result -} - -// arena_arena_Slice is a wrapper around (*userArena).slice. -// -//go:linkname arena_arena_Slice arena.runtime_arena_arena_Slice -func arena_arena_Slice(arena unsafe.Pointer, slice any, cap int) { - ((*userArena)(arena)).slice(slice, cap) -} - -// arena_arena_Free is a wrapper around (*userArena).free. -// -//go:linkname arena_arena_Free arena.runtime_arena_arena_Free -func arena_arena_Free(arena unsafe.Pointer) { - ((*userArena)(arena)).free() -} - -// arena_heapify takes a value that lives in an arena and makes a copy -// of it on the heap. Values that don't live in an arena are returned unmodified. -// -//go:linkname arena_heapify arena.runtime_arena_heapify -func arena_heapify(s any) any { - var v unsafe.Pointer - e := efaceOf(&s) - t := e._type - switch t.Kind_ & kindMask { - case kindString: - v = stringStructOf((*string)(e.data)).str - case kindSlice: - v = (*slice)(e.data).array - case kindPtr: - v = e.data - default: - panic("arena: Clone only supports pointers, slices, and strings") - } - span := spanOf(uintptr(v)) - if span == nil || !span.isUserArenaChunk { - // Not stored in a user arena chunk. - return s - } - // Heap-allocate storage for a copy. - var x any - switch t.Kind_ & kindMask { - case kindString: - s1 := s.(string) - s2, b := rawstring(len(s1)) - copy(b, s1) - x = s2 - case kindSlice: - len := (*slice)(e.data).len - et := (*slicetype)(unsafe.Pointer(t)).Elem - sl := new(slice) - *sl = slice{makeslicecopy(et, len, len, (*slice)(e.data).array), len, len} - xe := efaceOf(&x) - xe._type = t - xe.data = unsafe.Pointer(sl) - case kindPtr: - et := (*ptrtype)(unsafe.Pointer(t)).Elem - e2 := newobject(et) - typedmemmove(et, e2, e.data) - xe := efaceOf(&x) - xe._type = t - xe.data = e2 - } - return x -} - -const ( - // userArenaChunkBytes is the size of a user arena chunk. - userArenaChunkBytesMax = 8 << 20 - userArenaChunkBytes = uintptr(int64(userArenaChunkBytesMax-heapArenaBytes)&(int64(userArenaChunkBytesMax-heapArenaBytes)>>63) + heapArenaBytes) // min(userArenaChunkBytesMax, heapArenaBytes) - - // userArenaChunkPages is the number of pages a user arena chunk uses. - userArenaChunkPages = userArenaChunkBytes / pageSize - - // userArenaChunkMaxAllocBytes is the maximum size of an object that can - // be allocated from an arena. This number is chosen to cap worst-case - // fragmentation of user arenas to 25%. Larger allocations are redirected - // to the heap. - userArenaChunkMaxAllocBytes = userArenaChunkBytes / 4 -) - -func init() { - if userArenaChunkPages*pageSize != userArenaChunkBytes { - throw("user arena chunk size is not a multiple of the page size") - } - if userArenaChunkBytes%physPageSize != 0 { - throw("user arena chunk size is not a multiple of the physical page size") - } - if userArenaChunkBytes < heapArenaBytes { - if heapArenaBytes%userArenaChunkBytes != 0 { - throw("user arena chunk size is smaller than a heap arena, but doesn't divide it") - } - } else { - if userArenaChunkBytes%heapArenaBytes != 0 { - throw("user arena chunks size is larger than a heap arena, but not a multiple") - } - } - lockInit(&userArenaState.lock, lockRankUserArenaState) -} - -// userArenaChunkReserveBytes returns the amount of additional bytes to reserve for -// heap metadata. -func userArenaChunkReserveBytes() uintptr { - if goexperiment.AllocHeaders { - // In the allocation headers experiment, we reserve the end of the chunk for - // a pointer/scalar bitmap. We also reserve space for a dummy _type that - // refers to the bitmap. The PtrBytes field of the dummy _type indicates how - // many of those bits are valid. - return userArenaChunkBytes/goarch.PtrSize/8 + unsafe.Sizeof(_type{}) - } - return 0 -} - -type userArena struct { - // full is a list of full chunks that have not enough free memory left, and - // that we'll free once this user arena is freed. - // - // Can't use mSpanList here because it's not-in-heap. - fullList *mspan - - // active is the user arena chunk we're currently allocating into. - active *mspan - - // refs is a set of references to the arena chunks so that they're kept alive. - // - // The last reference in the list always refers to active, while the rest of - // them correspond to fullList. Specifically, the head of fullList is the - // second-to-last one, fullList.next is the third-to-last, and so on. - // - // In other words, every time a new chunk becomes active, its appended to this - // list. - refs []unsafe.Pointer - - // defunct is true if free has been called on this arena. - // - // This is just a best-effort way to discover a concurrent allocation - // and free. Also used to detect a double-free. - defunct atomic.Bool -} - -// newUserArena creates a new userArena ready to be used. -func newUserArena() *userArena { - a := new(userArena) - SetFinalizer(a, func(a *userArena) { - // If arena handle is dropped without being freed, then call - // free on the arena, so the arena chunks are never reclaimed - // by the garbage collector. - a.free() - }) - a.refill() - return a -} - -// new allocates a new object of the provided type into the arena, and returns -// its pointer. -// -// This operation is not safe to call concurrently with other operations on the -// same arena. -func (a *userArena) new(typ *_type) unsafe.Pointer { - return a.alloc(typ, -1) -} - -// slice allocates a new slice backing store. slice must be a pointer to a slice -// (i.e. *[]T), because userArenaSlice will update the slice directly. -// -// cap determines the capacity of the slice backing store and must be non-negative. -// -// This operation is not safe to call concurrently with other operations on the -// same arena. -func (a *userArena) slice(sl any, cap int) { - if cap < 0 { - panic("userArena.slice: negative cap") - } - i := efaceOf(&sl) - typ := i._type - if typ.Kind_&kindMask != kindPtr { - panic("slice result of non-ptr type") - } - typ = (*ptrtype)(unsafe.Pointer(typ)).Elem - if typ.Kind_&kindMask != kindSlice { - panic("slice of non-ptr-to-slice type") - } - typ = (*slicetype)(unsafe.Pointer(typ)).Elem - // t is now the element type of the slice we want to allocate. - - *((*slice)(i.data)) = slice{a.alloc(typ, cap), cap, cap} -} - -// free returns the userArena's chunks back to mheap and marks it as defunct. -// -// Must be called at most once for any given arena. -// -// This operation is not safe to call concurrently with other operations on the -// same arena. -func (a *userArena) free() { - // Check for a double-free. - if a.defunct.Load() { - panic("arena double free") - } - - // Mark ourselves as defunct. - a.defunct.Store(true) - SetFinalizer(a, nil) - - // Free all the full arenas. - // - // The refs on this list are in reverse order from the second-to-last. - s := a.fullList - i := len(a.refs) - 2 - for s != nil { - a.fullList = s.next - s.next = nil - freeUserArenaChunk(s, a.refs[i]) - s = a.fullList - i-- - } - if a.fullList != nil || i >= 0 { - // There's still something left on the full list, or we - // failed to actually iterate over the entire refs list. - throw("full list doesn't match refs list in length") - } - - // Put the active chunk onto the reuse list. - // - // Note that active's reference is always the last reference in refs. - s = a.active - if s != nil { - if raceenabled || msanenabled || asanenabled { - // Don't reuse arenas with sanitizers enabled. We want to catch - // any use-after-free errors aggressively. - freeUserArenaChunk(s, a.refs[len(a.refs)-1]) - } else { - lock(&userArenaState.lock) - userArenaState.reuse = append(userArenaState.reuse, liveUserArenaChunk{s, a.refs[len(a.refs)-1]}) - unlock(&userArenaState.lock) - } - } - // nil out a.active so that a race with freeing will more likely cause a crash. - a.active = nil - a.refs = nil -} - -// alloc reserves space in the current chunk or calls refill and reserves space -// in a new chunk. If cap is negative, the type will be taken literally, otherwise -// it will be considered as an element type for a slice backing store with capacity -// cap. -func (a *userArena) alloc(typ *_type, cap int) unsafe.Pointer { - s := a.active - var x unsafe.Pointer - for { - x = s.userArenaNextFree(typ, cap) - if x != nil { - break - } - s = a.refill() - } - return x -} - -// refill inserts the current arena chunk onto the full list and obtains a new -// one, either from the partial list or allocating a new one, both from mheap. -func (a *userArena) refill() *mspan { - // If there's an active chunk, assume it's full. - s := a.active - if s != nil { - if s.userArenaChunkFree.size() > userArenaChunkMaxAllocBytes { - // It's difficult to tell when we're actually out of memory - // in a chunk because the allocation that failed may still leave - // some free space available. However, that amount of free space - // should never exceed the maximum allocation size. - throw("wasted too much memory in an arena chunk") - } - s.next = a.fullList - a.fullList = s - a.active = nil - s = nil - } - var x unsafe.Pointer - - // Check the partially-used list. - lock(&userArenaState.lock) - if len(userArenaState.reuse) > 0 { - // Pick off the last arena chunk from the list. - n := len(userArenaState.reuse) - 1 - x = userArenaState.reuse[n].x - s = userArenaState.reuse[n].mspan - userArenaState.reuse[n].x = nil - userArenaState.reuse[n].mspan = nil - userArenaState.reuse = userArenaState.reuse[:n] - } - unlock(&userArenaState.lock) - if s == nil { - // Allocate a new one. - x, s = newUserArenaChunk() - if s == nil { - throw("out of memory") - } - } - a.refs = append(a.refs, x) - a.active = s - return s -} - -type liveUserArenaChunk struct { - *mspan // Must represent a user arena chunk. - - // Reference to mspan.base() to keep the chunk alive. - x unsafe.Pointer -} - -var userArenaState struct { - lock mutex - - // reuse contains a list of partially-used and already-live - // user arena chunks that can be quickly reused for another - // arena. - // - // Protected by lock. - reuse []liveUserArenaChunk - - // fault contains full user arena chunks that need to be faulted. - // - // Protected by lock. - fault []liveUserArenaChunk -} - -// userArenaNextFree reserves space in the user arena for an item of the specified -// type. If cap is not -1, this is for an array of cap elements of type t. -func (s *mspan) userArenaNextFree(typ *_type, cap int) unsafe.Pointer { - size := typ.Size_ - if cap > 0 { - if size > ^uintptr(0)/uintptr(cap) { - // Overflow. - throw("out of memory") - } - size *= uintptr(cap) - } - if size == 0 || cap == 0 { - return unsafe.Pointer(&zerobase) - } - if size > userArenaChunkMaxAllocBytes { - // Redirect allocations that don't fit into a chunk well directly - // from the heap. - if cap >= 0 { - return newarray(typ, cap) - } - return newobject(typ) - } - - // Prevent preemption as we set up the space for a new object. - // - // Act like we're allocating. - mp := acquirem() - if mp.mallocing != 0 { - throw("malloc deadlock") - } - if mp.gsignal == getg() { - throw("malloc during signal") - } - mp.mallocing = 1 - - var ptr unsafe.Pointer - if typ.PtrBytes == 0 { - // Allocate pointer-less objects from the tail end of the chunk. - v, ok := s.userArenaChunkFree.takeFromBack(size, typ.Align_) - if ok { - ptr = unsafe.Pointer(v) - } - } else { - v, ok := s.userArenaChunkFree.takeFromFront(size, typ.Align_) - if ok { - ptr = unsafe.Pointer(v) - } - } - if ptr == nil { - // Failed to allocate. - mp.mallocing = 0 - releasem(mp) - return nil - } - if s.needzero != 0 { - throw("arena chunk needs zeroing, but should already be zeroed") - } - // Set up heap bitmap and do extra accounting. - if typ.PtrBytes != 0 { - if cap >= 0 { - userArenaHeapBitsSetSliceType(typ, cap, ptr, s) - } else { - userArenaHeapBitsSetType(typ, ptr, s) - } - c := getMCache(mp) - if c == nil { - throw("mallocgc called without a P or outside bootstrapping") - } - if cap > 0 { - c.scanAlloc += size - (typ.Size_ - typ.PtrBytes) - } else { - c.scanAlloc += typ.PtrBytes - } - } - - // Ensure that the stores above that initialize x to - // type-safe memory and set the heap bits occur before - // the caller can make ptr observable to the garbage - // collector. Otherwise, on weakly ordered machines, - // the garbage collector could follow a pointer to x, - // but see uninitialized memory or stale heap bits. - publicationBarrier() - - mp.mallocing = 0 - releasem(mp) - - return ptr -} - -// userArenaHeapBitsSetSliceType is the equivalent of heapBitsSetType but for -// Go slice backing store values allocated in a user arena chunk. It sets up the -// heap bitmap for n consecutive values with type typ allocated at address ptr. -func userArenaHeapBitsSetSliceType(typ *_type, n int, ptr unsafe.Pointer, s *mspan) { - mem, overflow := math.MulUintptr(typ.Size_, uintptr(n)) - if overflow || n < 0 || mem > maxAlloc { - panic(plainError("runtime: allocation size out of range")) - } - for i := 0; i < n; i++ { - userArenaHeapBitsSetType(typ, add(ptr, uintptr(i)*typ.Size_), s) - } -} - -// newUserArenaChunk allocates a user arena chunk, which maps to a single -// heap arena and single span. Returns a pointer to the base of the chunk -// (this is really important: we need to keep the chunk alive) and the span. -func newUserArenaChunk() (unsafe.Pointer, *mspan) { - if gcphase == _GCmarktermination { - throw("newUserArenaChunk called with gcphase == _GCmarktermination") - } - - // Deduct assist credit. Because user arena chunks are modeled as one - // giant heap object which counts toward heapLive, we're obligated to - // assist the GC proportionally (and it's worth noting that the arena - // does represent additional work for the GC, but we also have no idea - // what that looks like until we actually allocate things into the - // arena). - deductAssistCredit(userArenaChunkBytes) - - // Set mp.mallocing to keep from being preempted by GC. - mp := acquirem() - if mp.mallocing != 0 { - throw("malloc deadlock") - } - if mp.gsignal == getg() { - throw("malloc during signal") - } - mp.mallocing = 1 - - // Allocate a new user arena. - var span *mspan - systemstack(func() { - span = mheap_.allocUserArenaChunk() - }) - if span == nil { - throw("out of memory") - } - x := unsafe.Pointer(span.base()) - - // Allocate black during GC. - // All slots hold nil so no scanning is needed. - // This may be racing with GC so do it atomically if there can be - // a race marking the bit. - if gcphase != _GCoff { - gcmarknewobject(span, span.base()) - } - - if raceenabled { - // TODO(mknyszek): Track individual objects. - racemalloc(unsafe.Pointer(span.base()), span.elemsize) - } - - if msanenabled { - // TODO(mknyszek): Track individual objects. - msanmalloc(unsafe.Pointer(span.base()), span.elemsize) - } - - if asanenabled { - // TODO(mknyszek): Track individual objects. - rzSize := computeRZlog(span.elemsize) - span.elemsize -= rzSize - if goexperiment.AllocHeaders { - span.largeType.Size_ = span.elemsize - } - rzStart := span.base() + span.elemsize - span.userArenaChunkFree = makeAddrRange(span.base(), rzStart) - asanpoison(unsafe.Pointer(rzStart), span.limit-rzStart) - asanunpoison(unsafe.Pointer(span.base()), span.elemsize) - } - - if rate := MemProfileRate; rate > 0 { - c := getMCache(mp) - if c == nil { - throw("newUserArenaChunk called without a P or outside bootstrapping") - } - // Note cache c only valid while m acquired; see #47302 - if rate != 1 && userArenaChunkBytes < c.nextSample { - c.nextSample -= userArenaChunkBytes - } else { - profilealloc(mp, unsafe.Pointer(span.base()), userArenaChunkBytes) - } - } - mp.mallocing = 0 - releasem(mp) - - // Again, because this chunk counts toward heapLive, potentially trigger a GC. - if t := (gcTrigger{kind: gcTriggerHeap}); t.test() { - gcStart(t) - } - - if debug.malloc { - if debug.allocfreetrace != 0 { - tracealloc(unsafe.Pointer(span.base()), userArenaChunkBytes, nil) - } - - if inittrace.active && inittrace.id == getg().goid { - // Init functions are executed sequentially in a single goroutine. - inittrace.bytes += uint64(userArenaChunkBytes) - } - } - - // Double-check it's aligned to the physical page size. Based on the current - // implementation this is trivially true, but it need not be in the future. - // However, if it's not aligned to the physical page size then we can't properly - // set it to fault later. - if uintptr(x)%physPageSize != 0 { - throw("user arena chunk is not aligned to the physical page size") - } - - return x, span -} - -// isUnusedUserArenaChunk indicates that the arena chunk has been set to fault -// and doesn't contain any scannable memory anymore. However, it might still be -// mSpanInUse as it sits on the quarantine list, since it needs to be swept. -// -// This is not safe to execute unless the caller has ownership of the mspan or -// the world is stopped (preemption is prevented while the relevant state changes). -// -// This is really only meant to be used by accounting tests in the runtime to -// distinguish when a span shouldn't be counted (since mSpanInUse might not be -// enough). -func (s *mspan) isUnusedUserArenaChunk() bool { - return s.isUserArenaChunk && s.spanclass == makeSpanClass(0, true) -} - -// setUserArenaChunkToFault sets the address space for the user arena chunk to fault -// and releases any underlying memory resources. -// -// Must be in a non-preemptible state to ensure the consistency of statistics -// exported to MemStats. -func (s *mspan) setUserArenaChunkToFault() { - if !s.isUserArenaChunk { - throw("invalid span in heapArena for user arena") - } - if s.npages*pageSize != userArenaChunkBytes { - throw("span on userArena.faultList has invalid size") - } - - // Update the span class to be noscan. What we want to happen is that - // any pointer into the span keeps it from getting recycled, so we want - // the mark bit to get set, but we're about to set the address space to fault, - // so we have to prevent the GC from scanning this memory. - // - // It's OK to set it here because (1) a GC isn't in progress, so the scanning code - // won't make a bad decision, (2) we're currently non-preemptible and in the runtime, - // so a GC is blocked from starting. We might race with sweeping, which could - // put it on the "wrong" sweep list, but really don't care because the chunk is - // treated as a large object span and there's no meaningful difference between scan - // and noscan large objects in the sweeper. The STW at the start of the GC acts as a - // barrier for this update. - s.spanclass = makeSpanClass(0, true) - - // Actually set the arena chunk to fault, so we'll get dangling pointer errors. - // sysFault currently uses a method on each OS that forces it to evacuate all - // memory backing the chunk. - sysFault(unsafe.Pointer(s.base()), s.npages*pageSize) - - // Everything on the list is counted as in-use, however sysFault transitions to - // Reserved, not Prepared, so we skip updating heapFree or heapReleased and just - // remove the memory from the total altogether; it's just address space now. - gcController.heapInUse.add(-int64(s.npages * pageSize)) - - // Count this as a free of an object right now as opposed to when - // the span gets off the quarantine list. The main reason is so that the - // amount of bytes allocated doesn't exceed how much is counted as - // "mapped ready," which could cause a deadlock in the pacer. - gcController.totalFree.Add(int64(s.elemsize)) - - // Update consistent stats to match. - // - // We're non-preemptible, so it's safe to update consistent stats (our P - // won't change out from under us). - stats := memstats.heapStats.acquire() - atomic.Xaddint64(&stats.committed, -int64(s.npages*pageSize)) - atomic.Xaddint64(&stats.inHeap, -int64(s.npages*pageSize)) - atomic.Xadd64(&stats.largeFreeCount, 1) - atomic.Xadd64(&stats.largeFree, int64(s.elemsize)) - memstats.heapStats.release() - - // This counts as a free, so update heapLive. - gcController.update(-int64(s.elemsize), 0) - - // Mark it as free for the race detector. - if raceenabled { - racefree(unsafe.Pointer(s.base()), s.elemsize) - } - - systemstack(func() { - // Add the user arena to the quarantine list. - lock(&mheap_.lock) - mheap_.userArena.quarantineList.insert(s) - unlock(&mheap_.lock) - }) -} - -// inUserArenaChunk returns true if p points to a user arena chunk. -func inUserArenaChunk(p uintptr) bool { - s := spanOf(p) - if s == nil { - return false - } - return s.isUserArenaChunk -} - -// freeUserArenaChunk releases the user arena represented by s back to the runtime. -// -// x must be a live pointer within s. -// -// The runtime will set the user arena to fault once it's safe (the GC is no longer running) -// and then once the user arena is no longer referenced by the application, will allow it to -// be reused. -func freeUserArenaChunk(s *mspan, x unsafe.Pointer) { - if !s.isUserArenaChunk { - throw("span is not for a user arena") - } - if s.npages*pageSize != userArenaChunkBytes { - throw("invalid user arena span size") - } - - // Mark the region as free to various santizers immediately instead - // of handling them at sweep time. - if raceenabled { - racefree(unsafe.Pointer(s.base()), s.elemsize) - } - if msanenabled { - msanfree(unsafe.Pointer(s.base()), s.elemsize) - } - if asanenabled { - asanpoison(unsafe.Pointer(s.base()), s.elemsize) - } - - // Make ourselves non-preemptible as we manipulate state and statistics. - // - // Also required by setUserArenaChunksToFault. - mp := acquirem() - - // We can only set user arenas to fault if we're in the _GCoff phase. - if gcphase == _GCoff { - lock(&userArenaState.lock) - faultList := userArenaState.fault - userArenaState.fault = nil - unlock(&userArenaState.lock) - - s.setUserArenaChunkToFault() - for _, lc := range faultList { - lc.mspan.setUserArenaChunkToFault() - } - - // Until the chunks are set to fault, keep them alive via the fault list. - KeepAlive(x) - KeepAlive(faultList) - } else { - // Put the user arena on the fault list. - lock(&userArenaState.lock) - userArenaState.fault = append(userArenaState.fault, liveUserArenaChunk{s, x}) - unlock(&userArenaState.lock) - } - releasem(mp) -} - -// allocUserArenaChunk attempts to reuse a free user arena chunk represented -// as a span. -// -// Must be in a non-preemptible state to ensure the consistency of statistics -// exported to MemStats. -// -// Acquires the heap lock. Must run on the system stack for that reason. -// -//go:systemstack -func (h *mheap) allocUserArenaChunk() *mspan { - var s *mspan - var base uintptr - - // First check the free list. - lock(&h.lock) - if !h.userArena.readyList.isEmpty() { - s = h.userArena.readyList.first - h.userArena.readyList.remove(s) - base = s.base() - } else { - // Free list was empty, so allocate a new arena. - hintList := &h.userArena.arenaHints - if raceenabled { - // In race mode just use the regular heap hints. We might fragment - // the address space, but the race detector requires that the heap - // is mapped contiguously. - hintList = &h.arenaHints - } - v, size := h.sysAlloc(userArenaChunkBytes, hintList, false) - if size%userArenaChunkBytes != 0 { - throw("sysAlloc size is not divisible by userArenaChunkBytes") - } - if size > userArenaChunkBytes { - // We got more than we asked for. This can happen if - // heapArenaSize > userArenaChunkSize, or if sysAlloc just returns - // some extra as a result of trying to find an aligned region. - // - // Divide it up and put it on the ready list. - for i := userArenaChunkBytes; i < size; i += userArenaChunkBytes { - s := h.allocMSpanLocked() - s.init(uintptr(v)+i, userArenaChunkPages) - h.userArena.readyList.insertBack(s) - } - size = userArenaChunkBytes - } - base = uintptr(v) - if base == 0 { - // Out of memory. - unlock(&h.lock) - return nil - } - s = h.allocMSpanLocked() - } - unlock(&h.lock) - - // sysAlloc returns Reserved address space, and any span we're - // reusing is set to fault (so, also Reserved), so transition - // it to Prepared and then Ready. - // - // Unlike (*mheap).grow, just map in everything that we - // asked for. We're likely going to use it all. - sysMap(unsafe.Pointer(base), userArenaChunkBytes, &gcController.heapReleased) - sysUsed(unsafe.Pointer(base), userArenaChunkBytes, userArenaChunkBytes) - - // Model the user arena as a heap span for a large object. - spc := makeSpanClass(0, false) - h.initSpan(s, spanAllocHeap, spc, base, userArenaChunkPages) - s.isUserArenaChunk = true - s.elemsize -= userArenaChunkReserveBytes() - s.limit = s.base() + s.elemsize - s.freeindex = 1 - s.allocCount = 1 - - // Account for this new arena chunk memory. - gcController.heapInUse.add(int64(userArenaChunkBytes)) - gcController.heapReleased.add(-int64(userArenaChunkBytes)) - - stats := memstats.heapStats.acquire() - atomic.Xaddint64(&stats.inHeap, int64(userArenaChunkBytes)) - atomic.Xaddint64(&stats.committed, int64(userArenaChunkBytes)) - - // Model the arena as a single large malloc. - atomic.Xadd64(&stats.largeAlloc, int64(s.elemsize)) - atomic.Xadd64(&stats.largeAllocCount, 1) - memstats.heapStats.release() - - // Count the alloc in inconsistent, internal stats. - gcController.totalAlloc.Add(int64(s.elemsize)) - - // Update heapLive. - gcController.update(int64(s.elemsize), 0) - - // This must clear the entire heap bitmap so that it's safe - // to allocate noscan data without writing anything out. - s.initHeapBits(true) - - // Clear the span preemptively. It's an arena chunk, so let's assume - // everything is going to be used. - // - // This also seems to make a massive difference as to whether or - // not Linux decides to back this memory with transparent huge - // pages. There's latency involved in this zeroing, but the hugepage - // gains are almost always worth it. Note: it's important that we - // clear even if it's freshly mapped and we know there's no point - // to zeroing as *that* is the critical signal to use huge pages. - memclrNoHeapPointers(unsafe.Pointer(s.base()), s.elemsize) - s.needzero = 0 - - s.freeIndexForScan = 1 - - // Set up the range for allocation. - s.userArenaChunkFree = makeAddrRange(base, base+s.elemsize) - - // Put the large span in the mcentral swept list so that it's - // visible to the background sweeper. - h.central[spc].mcentral.fullSwept(h.sweepgen).push(s) - - if goexperiment.AllocHeaders { - // Set up an allocation header. Avoid write barriers here because this type - // is not a real type, and it exists in an invalid location. - *(*uintptr)(unsafe.Pointer(&s.largeType)) = uintptr(unsafe.Pointer(s.limit)) - *(*uintptr)(unsafe.Pointer(&s.largeType.GCData)) = s.limit + unsafe.Sizeof(_type{}) - s.largeType.PtrBytes = 0 - s.largeType.Size_ = s.elemsize - } - return s -} diff --git a/contrib/go/_std_1.22/src/runtime/asan.go b/contrib/go/_std_1.22/src/runtime/asan.go deleted file mode 100644 index 25b83277e6d7..000000000000 --- a/contrib/go/_std_1.22/src/runtime/asan.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build asan - -package runtime - -import ( - "unsafe" -) - -// Public address sanitizer API. -func ASanRead(addr unsafe.Pointer, len int) { - sp := getcallersp() - pc := getcallerpc() - doasanread(addr, uintptr(len), sp, pc) -} - -func ASanWrite(addr unsafe.Pointer, len int) { - sp := getcallersp() - pc := getcallerpc() - doasanwrite(addr, uintptr(len), sp, pc) -} - -// Private interface for the runtime. -const asanenabled = true - -// asan{read,write} are nosplit because they may be called between -// fork and exec, when the stack must not grow. See issue #50391. - -//go:nosplit -func asanread(addr unsafe.Pointer, sz uintptr) { - sp := getcallersp() - pc := getcallerpc() - doasanread(addr, sz, sp, pc) -} - -//go:nosplit -func asanwrite(addr unsafe.Pointer, sz uintptr) { - sp := getcallersp() - pc := getcallerpc() - doasanwrite(addr, sz, sp, pc) -} - -//go:noescape -func doasanread(addr unsafe.Pointer, sz, sp, pc uintptr) - -//go:noescape -func doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr) - -//go:noescape -func asanunpoison(addr unsafe.Pointer, sz uintptr) - -//go:noescape -func asanpoison(addr unsafe.Pointer, sz uintptr) - -//go:noescape -func asanregisterglobals(addr unsafe.Pointer, n uintptr) - -// These are called from asan_GOARCH.s -// -//go:cgo_import_static __asan_read_go -//go:cgo_import_static __asan_write_go -//go:cgo_import_static __asan_unpoison_go -//go:cgo_import_static __asan_poison_go -//go:cgo_import_static __asan_register_globals_go diff --git a/contrib/go/_std_1.22/src/runtime/asm.s b/contrib/go/_std_1.22/src/runtime/asm.s deleted file mode 100644 index 24cd0c95db64..000000000000 --- a/contrib/go/_std_1.22/src/runtime/asm.s +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "textflag.h" - -#ifndef GOARCH_amd64 -TEXT ·sigpanic0(SB),NOSPLIT,$0-0 - JMP ·sigpanic(SB) -#endif - -// See map.go comment on the need for this routine. -TEXT ·mapinitnoop(SB),NOSPLIT,$0-0 - RET - -#ifndef GOARCH_amd64 -#ifndef GOARCH_arm64 -#ifndef GOARCH_mips64 -#ifndef GOARCH_mips64le -#ifndef GOARCH_ppc64 -#ifndef GOARCH_ppc64le -#ifndef GOARCH_riscv64 -#ifndef GOARCH_wasm -// stub to appease shared build mode. -TEXT ·switchToCrashStack0(SB),NOSPLIT,$0-0 - UNDEF -#endif -#endif -#endif -#endif -#endif -#endif -#endif -#endif diff --git a/contrib/go/_std_1.22/src/runtime/asm_amd64.s b/contrib/go/_std_1.22/src/runtime/asm_amd64.s deleted file mode 100644 index 1071d270c1b8..000000000000 --- a/contrib/go/_std_1.22/src/runtime/asm_amd64.s +++ /dev/null @@ -1,2138 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go_asm.h" -#include "go_tls.h" -#include "funcdata.h" -#include "textflag.h" -#include "cgo/abi_amd64.h" - -// _rt0_amd64 is common startup code for most amd64 systems when using -// internal linking. This is the entry point for the program from the -// kernel for an ordinary -buildmode=exe program. The stack holds the -// number of arguments and the C-style argv. -TEXT _rt0_amd64(SB),NOSPLIT,$-8 - MOVQ 0(SP), DI // argc - LEAQ 8(SP), SI // argv - JMP runtime·rt0_go(SB) - -// main is common startup code for most amd64 systems when using -// external linking. The C startup code will call the symbol "main" -// passing argc and argv in the usual C ABI registers DI and SI. -TEXT main(SB),NOSPLIT,$-8 - JMP runtime·rt0_go(SB) - -// _rt0_amd64_lib is common startup code for most amd64 systems when -// using -buildmode=c-archive or -buildmode=c-shared. The linker will -// arrange to invoke this function as a global constructor (for -// c-archive) or when the shared library is loaded (for c-shared). -// We expect argc and argv to be passed in the usual C ABI registers -// DI and SI. -TEXT _rt0_amd64_lib(SB),NOSPLIT|NOFRAME,$0 - // Transition from C ABI to Go ABI. - PUSH_REGS_HOST_TO_ABI0() - - MOVQ DI, _rt0_amd64_lib_argc<>(SB) - MOVQ SI, _rt0_amd64_lib_argv<>(SB) - - // Synchronous initialization. - CALL runtime·libpreinit(SB) - - // Create a new thread to finish Go runtime initialization. - MOVQ _cgo_sys_thread_create(SB), AX - TESTQ AX, AX - JZ nocgo - - // We're calling back to C. - // Align stack per ELF ABI requirements. - MOVQ SP, BX // Callee-save in C ABI - ANDQ $~15, SP - MOVQ $_rt0_amd64_lib_go(SB), DI - MOVQ $0, SI - CALL AX - MOVQ BX, SP - JMP restore - -nocgo: - ADJSP $16 - MOVQ $0x800000, 0(SP) // stacksize - MOVQ $_rt0_amd64_lib_go(SB), AX - MOVQ AX, 8(SP) // fn - CALL runtime·newosproc0(SB) - ADJSP $-16 - -restore: - POP_REGS_HOST_TO_ABI0() - RET - -// _rt0_amd64_lib_go initializes the Go runtime. -// This is started in a separate thread by _rt0_amd64_lib. -TEXT _rt0_amd64_lib_go(SB),NOSPLIT,$0 - MOVQ _rt0_amd64_lib_argc<>(SB), DI - MOVQ _rt0_amd64_lib_argv<>(SB), SI - JMP runtime·rt0_go(SB) - -DATA _rt0_amd64_lib_argc<>(SB)/8, $0 -GLOBL _rt0_amd64_lib_argc<>(SB),NOPTR, $8 -DATA _rt0_amd64_lib_argv<>(SB)/8, $0 -GLOBL _rt0_amd64_lib_argv<>(SB),NOPTR, $8 - -#ifdef GOAMD64_v2 -DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v2 microarchitecture support.\n" -#endif - -#ifdef GOAMD64_v3 -DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v3 microarchitecture support.\n" -#endif - -#ifdef GOAMD64_v4 -DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v4 microarchitecture support.\n" -#endif - -GLOBL bad_cpu_msg<>(SB), RODATA, $84 - -// Define a list of AMD64 microarchitecture level features -// https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels - - // SSE3 SSSE3 CMPXCHNG16 SSE4.1 SSE4.2 POPCNT -#define V2_FEATURES_CX (1 << 0 | 1 << 9 | 1 << 13 | 1 << 19 | 1 << 20 | 1 << 23) - // LAHF/SAHF -#define V2_EXT_FEATURES_CX (1 << 0) - // FMA MOVBE OSXSAVE AVX F16C -#define V3_FEATURES_CX (V2_FEATURES_CX | 1 << 12 | 1 << 22 | 1 << 27 | 1 << 28 | 1 << 29) - // ABM (FOR LZNCT) -#define V3_EXT_FEATURES_CX (V2_EXT_FEATURES_CX | 1 << 5) - // BMI1 AVX2 BMI2 -#define V3_EXT_FEATURES_BX (1 << 3 | 1 << 5 | 1 << 8) - // XMM YMM -#define V3_OS_SUPPORT_AX (1 << 1 | 1 << 2) - -#define V4_FEATURES_CX V3_FEATURES_CX - -#define V4_EXT_FEATURES_CX V3_EXT_FEATURES_CX - // AVX512F AVX512DQ AVX512CD AVX512BW AVX512VL -#define V4_EXT_FEATURES_BX (V3_EXT_FEATURES_BX | 1 << 16 | 1 << 17 | 1 << 28 | 1 << 30 | 1 << 31) - // OPMASK ZMM -#define V4_OS_SUPPORT_AX (V3_OS_SUPPORT_AX | 1 << 5 | (1 << 6 | 1 << 7)) - -#ifdef GOAMD64_v2 -#define NEED_MAX_CPUID 0x80000001 -#define NEED_FEATURES_CX V2_FEATURES_CX -#define NEED_EXT_FEATURES_CX V2_EXT_FEATURES_CX -#endif - -#ifdef GOAMD64_v3 -#define NEED_MAX_CPUID 0x80000001 -#define NEED_FEATURES_CX V3_FEATURES_CX -#define NEED_EXT_FEATURES_CX V3_EXT_FEATURES_CX -#define NEED_EXT_FEATURES_BX V3_EXT_FEATURES_BX -#define NEED_OS_SUPPORT_AX V3_OS_SUPPORT_AX -#endif - -#ifdef GOAMD64_v4 -#define NEED_MAX_CPUID 0x80000001 -#define NEED_FEATURES_CX V4_FEATURES_CX -#define NEED_EXT_FEATURES_CX V4_EXT_FEATURES_CX -#define NEED_EXT_FEATURES_BX V4_EXT_FEATURES_BX - -// Darwin requires a different approach to check AVX512 support, see CL 285572. -#ifdef GOOS_darwin -#define NEED_OS_SUPPORT_AX V3_OS_SUPPORT_AX -// These values are from: -// https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/osfmk/i386/cpu_capabilities.h -#define commpage64_base_address 0x00007fffffe00000 -#define commpage64_cpu_capabilities64 (commpage64_base_address+0x010) -#define commpage64_version (commpage64_base_address+0x01E) -#define AVX512F 0x0000004000000000 -#define AVX512CD 0x0000008000000000 -#define AVX512DQ 0x0000010000000000 -#define AVX512BW 0x0000020000000000 -#define AVX512VL 0x0000100000000000 -#define NEED_DARWIN_SUPPORT (AVX512F | AVX512DQ | AVX512CD | AVX512BW | AVX512VL) -#else -#define NEED_OS_SUPPORT_AX V4_OS_SUPPORT_AX -#endif - -#endif - -TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 - // copy arguments forward on an even stack - MOVQ DI, AX // argc - MOVQ SI, BX // argv - SUBQ $(5*8), SP // 3args 2auto - ANDQ $~15, SP - MOVQ AX, 24(SP) - MOVQ BX, 32(SP) - - // create istack out of the given (operating system) stack. - // _cgo_init may update stackguard. - MOVQ $runtime·g0(SB), DI - LEAQ (-64*1024)(SP), BX - MOVQ BX, g_stackguard0(DI) - MOVQ BX, g_stackguard1(DI) - MOVQ BX, (g_stack+stack_lo)(DI) - MOVQ SP, (g_stack+stack_hi)(DI) - - // find out information about the processor we're on - MOVL $0, AX - CPUID - CMPL AX, $0 - JE nocpuinfo - - CMPL BX, $0x756E6547 // "Genu" - JNE notintel - CMPL DX, $0x49656E69 // "ineI" - JNE notintel - CMPL CX, $0x6C65746E // "ntel" - JNE notintel - MOVB $1, runtime·isIntel(SB) - -notintel: - // Load EAX=1 cpuid flags - MOVL $1, AX - CPUID - MOVL AX, runtime·processorVersionInfo(SB) - -nocpuinfo: - // if there is an _cgo_init, call it. - MOVQ _cgo_init(SB), AX - TESTQ AX, AX - JZ needtls - // arg 1: g0, already in DI - MOVQ $setg_gcc<>(SB), SI // arg 2: setg_gcc - MOVQ $0, DX // arg 3, 4: not used when using platform's TLS - MOVQ $0, CX -#ifdef GOOS_android - MOVQ $runtime·tls_g(SB), DX // arg 3: &tls_g - // arg 4: TLS base, stored in slot 0 (Android's TLS_SLOT_SELF). - // Compensate for tls_g (+16). - MOVQ -16(TLS), CX -#endif -#ifdef GOOS_windows - MOVQ $runtime·tls_g(SB), DX // arg 3: &tls_g - // Adjust for the Win64 calling convention. - MOVQ CX, R9 // arg 4 - MOVQ DX, R8 // arg 3 - MOVQ SI, DX // arg 2 - MOVQ DI, CX // arg 1 -#endif - CALL AX - - // update stackguard after _cgo_init - MOVQ $runtime·g0(SB), CX - MOVQ (g_stack+stack_lo)(CX), AX - ADDQ $const_stackGuard, AX - MOVQ AX, g_stackguard0(CX) - MOVQ AX, g_stackguard1(CX) - -#ifndef GOOS_windows - JMP ok -#endif -needtls: -#ifdef GOOS_plan9 - // skip TLS setup on Plan 9 - JMP ok -#endif -#ifdef GOOS_solaris - // skip TLS setup on Solaris - JMP ok -#endif -#ifdef GOOS_illumos - // skip TLS setup on illumos - JMP ok -#endif -#ifdef GOOS_darwin - // skip TLS setup on Darwin - JMP ok -#endif -#ifdef GOOS_openbsd - // skip TLS setup on OpenBSD - JMP ok -#endif - -#ifdef GOOS_windows - CALL runtime·wintls(SB) -#endif - - LEAQ runtime·m0+m_tls(SB), DI - CALL runtime·settls(SB) - - // store through it, to make sure it works - get_tls(BX) - MOVQ $0x123, g(BX) - MOVQ runtime·m0+m_tls(SB), AX - CMPQ AX, $0x123 - JEQ 2(PC) - CALL runtime·abort(SB) -ok: - // set the per-goroutine and per-mach "registers" - get_tls(BX) - LEAQ runtime·g0(SB), CX - MOVQ CX, g(BX) - LEAQ runtime·m0(SB), AX - - // save m->g0 = g0 - MOVQ CX, m_g0(AX) - // save m0 to g0->m - MOVQ AX, g_m(CX) - - CLD // convention is D is always left cleared - - // Check GOAMD64 requirements - // We need to do this after setting up TLS, so that - // we can report an error if there is a failure. See issue 49586. -#ifdef NEED_FEATURES_CX - MOVL $0, AX - CPUID - CMPL AX, $0 - JE bad_cpu - MOVL $1, AX - CPUID - ANDL $NEED_FEATURES_CX, CX - CMPL CX, $NEED_FEATURES_CX - JNE bad_cpu -#endif - -#ifdef NEED_MAX_CPUID - MOVL $0x80000000, AX - CPUID - CMPL AX, $NEED_MAX_CPUID - JL bad_cpu -#endif - -#ifdef NEED_EXT_FEATURES_BX - MOVL $7, AX - MOVL $0, CX - CPUID - ANDL $NEED_EXT_FEATURES_BX, BX - CMPL BX, $NEED_EXT_FEATURES_BX - JNE bad_cpu -#endif - -#ifdef NEED_EXT_FEATURES_CX - MOVL $0x80000001, AX - CPUID - ANDL $NEED_EXT_FEATURES_CX, CX - CMPL CX, $NEED_EXT_FEATURES_CX - JNE bad_cpu -#endif - -#ifdef NEED_OS_SUPPORT_AX - XORL CX, CX - XGETBV - ANDL $NEED_OS_SUPPORT_AX, AX - CMPL AX, $NEED_OS_SUPPORT_AX - JNE bad_cpu -#endif - -#ifdef NEED_DARWIN_SUPPORT - MOVQ $commpage64_version, BX - CMPW (BX), $13 // cpu_capabilities64 undefined in versions < 13 - JL bad_cpu - MOVQ $commpage64_cpu_capabilities64, BX - MOVQ (BX), BX - MOVQ $NEED_DARWIN_SUPPORT, CX - ANDQ CX, BX - CMPQ BX, CX - JNE bad_cpu -#endif - - CALL runtime·check(SB) - - MOVL 24(SP), AX // copy argc - MOVL AX, 0(SP) - MOVQ 32(SP), AX // copy argv - MOVQ AX, 8(SP) - CALL runtime·args(SB) - CALL runtime·osinit(SB) - CALL runtime·schedinit(SB) - - // create a new goroutine to start program - MOVQ $runtime·mainPC(SB), AX // entry - PUSHQ AX - CALL runtime·newproc(SB) - POPQ AX - - // start this M - CALL runtime·mstart(SB) - - CALL runtime·abort(SB) // mstart should never return - RET - -bad_cpu: // show that the program requires a certain microarchitecture level. - MOVQ $2, 0(SP) - MOVQ $bad_cpu_msg<>(SB), AX - MOVQ AX, 8(SP) - MOVQ $84, 16(SP) - CALL runtime·write(SB) - MOVQ $1, 0(SP) - CALL runtime·exit(SB) - CALL runtime·abort(SB) - RET - - // Prevent dead-code elimination of debugCallV2, which is - // intended to be called by debuggers. - MOVQ $runtime·debugCallV2(SB), AX - RET - -// mainPC is a function value for runtime.main, to be passed to newproc. -// The reference to runtime.main is made via ABIInternal, since the -// actual function (not the ABI0 wrapper) is needed by newproc. -DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) -GLOBL runtime·mainPC(SB),RODATA,$8 - -TEXT runtime·breakpoint(SB),NOSPLIT,$0-0 - BYTE $0xcc - RET - -TEXT runtime·asminit(SB),NOSPLIT,$0-0 - // No per-thread init. - RET - -TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME|NOFRAME,$0 - CALL runtime·mstart0(SB) - RET // not reached - -/* - * go-routine - */ - -// func gogo(buf *gobuf) -// restore state from Gobuf; longjmp -TEXT runtime·gogo(SB), NOSPLIT, $0-8 - MOVQ buf+0(FP), BX // gobuf - MOVQ gobuf_g(BX), DX - MOVQ 0(DX), CX // make sure g != nil - JMP gogo<>(SB) - -TEXT gogo<>(SB), NOSPLIT, $0 - get_tls(CX) - MOVQ DX, g(CX) - MOVQ DX, R14 // set the g register - MOVQ gobuf_sp(BX), SP // restore SP - MOVQ gobuf_ret(BX), AX - MOVQ gobuf_ctxt(BX), DX - MOVQ gobuf_bp(BX), BP - MOVQ $0, gobuf_sp(BX) // clear to help garbage collector - MOVQ $0, gobuf_ret(BX) - MOVQ $0, gobuf_ctxt(BX) - MOVQ $0, gobuf_bp(BX) - MOVQ gobuf_pc(BX), BX - JMP BX - -// func mcall(fn func(*g)) -// Switch to m->g0's stack, call fn(g). -// Fn must never return. It should gogo(&g->sched) -// to keep running g. -TEXT runtime·mcall(SB), NOSPLIT, $0-8 - MOVQ AX, DX // DX = fn - - // Save state in g->sched. The caller's SP and PC are restored by gogo to - // resume execution in the caller's frame (implicit return). The caller's BP - // is also restored to support frame pointer unwinding. - MOVQ SP, BX // hide (SP) reads from vet - MOVQ 8(BX), BX // caller's PC - MOVQ BX, (g_sched+gobuf_pc)(R14) - LEAQ fn+0(FP), BX // caller's SP - MOVQ BX, (g_sched+gobuf_sp)(R14) - // Get the caller's frame pointer by dereferencing BP. Storing BP as it is - // can cause a frame pointer cycle, see CL 476235. - MOVQ (BP), BX // caller's BP - MOVQ BX, (g_sched+gobuf_bp)(R14) - - // switch to m->g0 & its stack, call fn - MOVQ g_m(R14), BX - MOVQ m_g0(BX), SI // SI = g.m.g0 - CMPQ SI, R14 // if g == m->g0 call badmcall - JNE goodm - JMP runtime·badmcall(SB) -goodm: - MOVQ R14, AX // AX (and arg 0) = g - MOVQ SI, R14 // g = g.m.g0 - get_tls(CX) // Set G in TLS - MOVQ R14, g(CX) - MOVQ (g_sched+gobuf_sp)(R14), SP // sp = g0.sched.sp - PUSHQ AX // open up space for fn's arg spill slot - MOVQ 0(DX), R12 - CALL R12 // fn(g) - POPQ AX - JMP runtime·badmcall2(SB) - RET - -// systemstack_switch is a dummy routine that systemstack leaves at the bottom -// of the G stack. We need to distinguish the routine that -// lives at the bottom of the G stack from the one that lives -// at the top of the system stack because the one at the top of -// the system stack terminates the stack walk (see topofstack()). -// The frame layout needs to match systemstack -// so that it can pretend to be systemstack_switch. -TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 - UNDEF - // Make sure this function is not leaf, - // so the frame is saved. - CALL runtime·abort(SB) - RET - -// func systemstack(fn func()) -TEXT runtime·systemstack(SB), NOSPLIT, $0-8 - MOVQ fn+0(FP), DI // DI = fn - get_tls(CX) - MOVQ g(CX), AX // AX = g - MOVQ g_m(AX), BX // BX = m - - CMPQ AX, m_gsignal(BX) - JEQ noswitch - - MOVQ m_g0(BX), DX // DX = g0 - CMPQ AX, DX - JEQ noswitch - - CMPQ AX, m_curg(BX) - JNE bad - - // Switch stacks. - // The original frame pointer is stored in BP, - // which is useful for stack unwinding. - // Save our state in g->sched. Pretend to - // be systemstack_switch if the G stack is scanned. - CALL gosave_systemstack_switch<>(SB) - - // switch to g0 - MOVQ DX, g(CX) - MOVQ DX, R14 // set the g register - MOVQ (g_sched+gobuf_sp)(DX), SP - - // call target function - MOVQ DI, DX - MOVQ 0(DI), DI - CALL DI - - // switch back to g - get_tls(CX) - MOVQ g(CX), AX - MOVQ g_m(AX), BX - MOVQ m_curg(BX), AX - MOVQ AX, g(CX) - MOVQ (g_sched+gobuf_sp)(AX), SP - MOVQ (g_sched+gobuf_bp)(AX), BP - MOVQ $0, (g_sched+gobuf_sp)(AX) - MOVQ $0, (g_sched+gobuf_bp)(AX) - RET - -noswitch: - // already on m stack; tail call the function - // Using a tail call here cleans up tracebacks since we won't stop - // at an intermediate systemstack. - MOVQ DI, DX - MOVQ 0(DI), DI - // The function epilogue is not called on a tail call. - // Pop BP from the stack to simulate it. - POPQ BP - JMP DI - -bad: - // Bad: g is not gsignal, not g0, not curg. What is it? - MOVQ $runtime·badsystemstack(SB), AX - CALL AX - INT $3 - -// func switchToCrashStack0(fn func()) -TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 - MOVQ g_m(R14), BX // curm - - // set g to gcrash - LEAQ runtime·gcrash(SB), R14 // g = &gcrash - MOVQ BX, g_m(R14) // g.m = curm - MOVQ R14, m_g0(BX) // curm.g0 = g - get_tls(CX) - MOVQ R14, g(CX) - - // switch to crashstack - MOVQ (g_stack+stack_hi)(R14), BX - SUBQ $(4*8), BX - MOVQ BX, SP - - // call target function - MOVQ AX, DX - MOVQ 0(AX), AX - CALL AX - - // should never return - CALL runtime·abort(SB) - UNDEF - -/* - * support for morestack - */ - -// Called during function prolog when more stack is needed. -// -// The traceback routines see morestack on a g0 as being -// the top of a stack (for example, morestack calling newstack -// calling the scheduler calling newm calling gc), so we must -// record an argument size. For that purpose, it has no arguments. -TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 - // Cannot grow scheduler stack (m->g0). - get_tls(CX) - MOVQ g(CX), DI // DI = g - MOVQ g_m(DI), BX // BX = m - - // Set g->sched to context in f. - MOVQ 0(SP), AX // f's PC - MOVQ AX, (g_sched+gobuf_pc)(DI) - LEAQ 8(SP), AX // f's SP - MOVQ AX, (g_sched+gobuf_sp)(DI) - MOVQ BP, (g_sched+gobuf_bp)(DI) - MOVQ DX, (g_sched+gobuf_ctxt)(DI) - - MOVQ m_g0(BX), SI // SI = m.g0 - CMPQ DI, SI - JNE 3(PC) - CALL runtime·badmorestackg0(SB) - CALL runtime·abort(SB) - - // Cannot grow signal stack (m->gsignal). - MOVQ m_gsignal(BX), SI - CMPQ DI, SI - JNE 3(PC) - CALL runtime·badmorestackgsignal(SB) - CALL runtime·abort(SB) - - // Called from f. - // Set m->morebuf to f's caller. - NOP SP // tell vet SP changed - stop checking offsets - MOVQ 8(SP), AX // f's caller's PC - MOVQ AX, (m_morebuf+gobuf_pc)(BX) - LEAQ 16(SP), AX // f's caller's SP - MOVQ AX, (m_morebuf+gobuf_sp)(BX) - MOVQ DI, (m_morebuf+gobuf_g)(BX) - - // Call newstack on m->g0's stack. - MOVQ m_g0(BX), BX - MOVQ BX, g(CX) - MOVQ (g_sched+gobuf_sp)(BX), SP - MOVQ (g_sched+gobuf_bp)(BX), BP - CALL runtime·newstack(SB) - CALL runtime·abort(SB) // crash if newstack returns - RET - -// morestack but not preserving ctxt. -TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack(SB) - -// spillArgs stores return values from registers to a *internal/abi.RegArgs in R12. -TEXT ·spillArgs(SB),NOSPLIT,$0-0 - MOVQ AX, 0(R12) - MOVQ BX, 8(R12) - MOVQ CX, 16(R12) - MOVQ DI, 24(R12) - MOVQ SI, 32(R12) - MOVQ R8, 40(R12) - MOVQ R9, 48(R12) - MOVQ R10, 56(R12) - MOVQ R11, 64(R12) - MOVQ X0, 72(R12) - MOVQ X1, 80(R12) - MOVQ X2, 88(R12) - MOVQ X3, 96(R12) - MOVQ X4, 104(R12) - MOVQ X5, 112(R12) - MOVQ X6, 120(R12) - MOVQ X7, 128(R12) - MOVQ X8, 136(R12) - MOVQ X9, 144(R12) - MOVQ X10, 152(R12) - MOVQ X11, 160(R12) - MOVQ X12, 168(R12) - MOVQ X13, 176(R12) - MOVQ X14, 184(R12) - RET - -// unspillArgs loads args into registers from a *internal/abi.RegArgs in R12. -TEXT ·unspillArgs(SB),NOSPLIT,$0-0 - MOVQ 0(R12), AX - MOVQ 8(R12), BX - MOVQ 16(R12), CX - MOVQ 24(R12), DI - MOVQ 32(R12), SI - MOVQ 40(R12), R8 - MOVQ 48(R12), R9 - MOVQ 56(R12), R10 - MOVQ 64(R12), R11 - MOVQ 72(R12), X0 - MOVQ 80(R12), X1 - MOVQ 88(R12), X2 - MOVQ 96(R12), X3 - MOVQ 104(R12), X4 - MOVQ 112(R12), X5 - MOVQ 120(R12), X6 - MOVQ 128(R12), X7 - MOVQ 136(R12), X8 - MOVQ 144(R12), X9 - MOVQ 152(R12), X10 - MOVQ 160(R12), X11 - MOVQ 168(R12), X12 - MOVQ 176(R12), X13 - MOVQ 184(R12), X14 - RET - -// reflectcall: call a function with the given argument list -// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). -// we don't have variable-sized frames, so we use a small number -// of constant-sized-frame functions to encode a few bits of size in the pc. -// Caution: ugly multiline assembly macros in your future! - -#define DISPATCH(NAME,MAXSIZE) \ - CMPQ CX, $MAXSIZE; \ - JA 3(PC); \ - MOVQ $NAME(SB), AX; \ - JMP AX -// Note: can't just "JMP NAME(SB)" - bad inlining results. - -TEXT ·reflectcall(SB), NOSPLIT, $0-48 - MOVLQZX frameSize+32(FP), CX - DISPATCH(runtime·call16, 16) - DISPATCH(runtime·call32, 32) - DISPATCH(runtime·call64, 64) - DISPATCH(runtime·call128, 128) - DISPATCH(runtime·call256, 256) - DISPATCH(runtime·call512, 512) - DISPATCH(runtime·call1024, 1024) - DISPATCH(runtime·call2048, 2048) - DISPATCH(runtime·call4096, 4096) - DISPATCH(runtime·call8192, 8192) - DISPATCH(runtime·call16384, 16384) - DISPATCH(runtime·call32768, 32768) - DISPATCH(runtime·call65536, 65536) - DISPATCH(runtime·call131072, 131072) - DISPATCH(runtime·call262144, 262144) - DISPATCH(runtime·call524288, 524288) - DISPATCH(runtime·call1048576, 1048576) - DISPATCH(runtime·call2097152, 2097152) - DISPATCH(runtime·call4194304, 4194304) - DISPATCH(runtime·call8388608, 8388608) - DISPATCH(runtime·call16777216, 16777216) - DISPATCH(runtime·call33554432, 33554432) - DISPATCH(runtime·call67108864, 67108864) - DISPATCH(runtime·call134217728, 134217728) - DISPATCH(runtime·call268435456, 268435456) - DISPATCH(runtime·call536870912, 536870912) - DISPATCH(runtime·call1073741824, 1073741824) - MOVQ $runtime·badreflectcall(SB), AX - JMP AX - -#define CALLFN(NAME,MAXSIZE) \ -TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ - NO_LOCAL_POINTERS; \ - /* copy arguments to stack */ \ - MOVQ stackArgs+16(FP), SI; \ - MOVLQZX stackArgsSize+24(FP), CX; \ - MOVQ SP, DI; \ - REP;MOVSB; \ - /* set up argument registers */ \ - MOVQ regArgs+40(FP), R12; \ - CALL ·unspillArgs(SB); \ - /* call function */ \ - MOVQ f+8(FP), DX; \ - PCDATA $PCDATA_StackMapIndex, $0; \ - MOVQ (DX), R12; \ - CALL R12; \ - /* copy register return values back */ \ - MOVQ regArgs+40(FP), R12; \ - CALL ·spillArgs(SB); \ - MOVLQZX stackArgsSize+24(FP), CX; \ - MOVLQZX stackRetOffset+28(FP), BX; \ - MOVQ stackArgs+16(FP), DI; \ - MOVQ stackArgsType+0(FP), DX; \ - MOVQ SP, SI; \ - ADDQ BX, DI; \ - ADDQ BX, SI; \ - SUBQ BX, CX; \ - CALL callRet<>(SB); \ - RET - -// callRet copies return values back at the end of call*. This is a -// separate function so it can allocate stack space for the arguments -// to reflectcallmove. It does not follow the Go ABI; it expects its -// arguments in registers. -TEXT callRet<>(SB), NOSPLIT, $40-0 - NO_LOCAL_POINTERS - MOVQ DX, 0(SP) - MOVQ DI, 8(SP) - MOVQ SI, 16(SP) - MOVQ CX, 24(SP) - MOVQ R12, 32(SP) - CALL runtime·reflectcallmove(SB) - RET - -CALLFN(·call16, 16) -CALLFN(·call32, 32) -CALLFN(·call64, 64) -CALLFN(·call128, 128) -CALLFN(·call256, 256) -CALLFN(·call512, 512) -CALLFN(·call1024, 1024) -CALLFN(·call2048, 2048) -CALLFN(·call4096, 4096) -CALLFN(·call8192, 8192) -CALLFN(·call16384, 16384) -CALLFN(·call32768, 32768) -CALLFN(·call65536, 65536) -CALLFN(·call131072, 131072) -CALLFN(·call262144, 262144) -CALLFN(·call524288, 524288) -CALLFN(·call1048576, 1048576) -CALLFN(·call2097152, 2097152) -CALLFN(·call4194304, 4194304) -CALLFN(·call8388608, 8388608) -CALLFN(·call16777216, 16777216) -CALLFN(·call33554432, 33554432) -CALLFN(·call67108864, 67108864) -CALLFN(·call134217728, 134217728) -CALLFN(·call268435456, 268435456) -CALLFN(·call536870912, 536870912) -CALLFN(·call1073741824, 1073741824) - -TEXT runtime·procyield(SB),NOSPLIT,$0-0 - MOVL cycles+0(FP), AX -again: - PAUSE - SUBL $1, AX - JNZ again - RET - - -TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 - // Stores are already ordered on x86, so this is just a - // compile barrier. - RET - -// Save state of caller into g->sched, -// but using fake PC from systemstack_switch. -// Must only be called from functions with frame pointer -// and without locals ($0) or else unwinding from -// systemstack_switch is incorrect. -// Smashes R9. -TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 - // Take systemstack_switch PC and add 8 bytes to skip - // the prologue. The final location does not matter - // as long as we are between the prologue and the epilogue. - MOVQ $runtime·systemstack_switch+8(SB), R9 - MOVQ R9, (g_sched+gobuf_pc)(R14) - LEAQ 8(SP), R9 - MOVQ R9, (g_sched+gobuf_sp)(R14) - MOVQ $0, (g_sched+gobuf_ret)(R14) - MOVQ BP, (g_sched+gobuf_bp)(R14) - // Assert ctxt is zero. See func save. - MOVQ (g_sched+gobuf_ctxt)(R14), R9 - TESTQ R9, R9 - JZ 2(PC) - CALL runtime·abort(SB) - RET - -// func asmcgocall_no_g(fn, arg unsafe.Pointer) -// Call fn(arg) aligned appropriately for the gcc ABI. -// Called on a system stack, and there may be no g yet (during needm). -TEXT ·asmcgocall_no_g(SB),NOSPLIT,$32-16 - MOVQ fn+0(FP), AX - MOVQ arg+8(FP), BX - MOVQ SP, DX - ANDQ $~15, SP // alignment - MOVQ DX, 8(SP) - MOVQ BX, DI // DI = first argument in AMD64 ABI - MOVQ BX, CX // CX = first argument in Win64 - CALL AX - MOVQ 8(SP), DX - MOVQ DX, SP - RET - -// asmcgocall_landingpad calls AX with BX as argument. -// Must be called on the system stack. -TEXT ·asmcgocall_landingpad(SB),NOSPLIT,$0-0 -#ifdef GOOS_windows - // Make sure we have enough room for 4 stack-backed fast-call - // registers as per Windows amd64 calling convention. - ADJSP $32 - // On Windows, asmcgocall_landingpad acts as landing pad for exceptions - // thrown in the cgo call. Exceptions that reach this function will be - // handled by runtime.sehtramp thanks to the SEH metadata added - // by the compiler. - // Note that runtime.sehtramp can't be attached directly to asmcgocall - // because its initial stack pointer can be outside the system stack bounds, - // and Windows stops the stack unwinding without calling the exception handler - // when it reaches that point. - MOVQ BX, CX // CX = first argument in Win64 - CALL AX - // The exception handler is not called if the next instruction is part of - // the epilogue, which includes the RET instruction, so we need to add a NOP here. - BYTE $0x90 - ADJSP $-32 - RET -#endif - // Tail call AX on non-Windows, as the extra stack frame is not needed. - MOVQ BX, DI // DI = first argument in AMD64 ABI - JMP AX - -// func asmcgocall(fn, arg unsafe.Pointer) int32 -// Call fn(arg) on the scheduler stack, -// aligned appropriately for the gcc ABI. -// See cgocall.go for more details. -TEXT ·asmcgocall(SB),NOSPLIT,$0-20 - MOVQ fn+0(FP), AX - MOVQ arg+8(FP), BX - - MOVQ SP, DX - - // Figure out if we need to switch to m->g0 stack. - // We get called to create new OS threads too, and those - // come in on the m->g0 stack already. Or we might already - // be on the m->gsignal stack. - get_tls(CX) - MOVQ g(CX), DI - CMPQ DI, $0 - JEQ nosave - MOVQ g_m(DI), R8 - MOVQ m_gsignal(R8), SI - CMPQ DI, SI - JEQ nosave - MOVQ m_g0(R8), SI - CMPQ DI, SI - JEQ nosave - - // Switch to system stack. - // The original frame pointer is stored in BP, - // which is useful for stack unwinding. - CALL gosave_systemstack_switch<>(SB) - MOVQ SI, g(CX) - MOVQ (g_sched+gobuf_sp)(SI), SP - - // Now on a scheduling stack (a pthread-created stack). - SUBQ $16, SP - ANDQ $~15, SP // alignment for gcc ABI - MOVQ DI, 8(SP) // save g - MOVQ (g_stack+stack_hi)(DI), DI - SUBQ DX, DI - MOVQ DI, 0(SP) // save depth in stack (can't just save SP, as stack might be copied during a callback) - CALL runtime·asmcgocall_landingpad(SB) - - // Restore registers, g, stack pointer. - get_tls(CX) - MOVQ 8(SP), DI - MOVQ (g_stack+stack_hi)(DI), SI - SUBQ 0(SP), SI - MOVQ DI, g(CX) - MOVQ SI, SP - - MOVL AX, ret+16(FP) - RET - -nosave: - // Running on a system stack, perhaps even without a g. - // Having no g can happen during thread creation or thread teardown - // (see needm/dropm on Solaris, for example). - // This code is like the above sequence but without saving/restoring g - // and without worrying about the stack moving out from under us - // (because we're on a system stack, not a goroutine stack). - // The above code could be used directly if already on a system stack, - // but then the only path through this code would be a rare case on Solaris. - // Using this code for all "already on system stack" calls exercises it more, - // which should help keep it correct. - SUBQ $16, SP - ANDQ $~15, SP - MOVQ $0, 8(SP) // where above code stores g, in case someone looks during debugging - MOVQ DX, 0(SP) // save original stack pointer - CALL runtime·asmcgocall_landingpad(SB) - MOVQ 0(SP), SI // restore original stack pointer - MOVQ SI, SP - MOVL AX, ret+16(FP) - RET - -#ifdef GOOS_windows -// Dummy TLS that's used on Windows so that we don't crash trying -// to restore the G register in needm. needm and its callees are -// very careful never to actually use the G, the TLS just can't be -// unset since we're in Go code. -GLOBL zeroTLS<>(SB),RODATA,$const_tlsSize -#endif - -// func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) -// See cgocall.go for more details. -TEXT ·cgocallback(SB),NOSPLIT,$24-24 - NO_LOCAL_POINTERS - - // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. - // It is used to dropm while thread is exiting. - MOVQ fn+0(FP), AX - CMPQ AX, $0 - JNE loadg - // Restore the g from frame. - get_tls(CX) - MOVQ frame+8(FP), BX - MOVQ BX, g(CX) - JMP dropm - -loadg: - // If g is nil, Go did not create the current thread, - // or if this thread never called into Go on pthread platforms. - // Call needm to obtain one m for temporary use. - // In this case, we're running on the thread stack, so there's - // lots of space, but the linker doesn't know. Hide the call from - // the linker analysis by using an indirect call through AX. - get_tls(CX) -#ifdef GOOS_windows - MOVL $0, BX - CMPQ CX, $0 - JEQ 2(PC) -#endif - MOVQ g(CX), BX - CMPQ BX, $0 - JEQ needm - MOVQ g_m(BX), BX - MOVQ BX, savedm-8(SP) // saved copy of oldm - JMP havem -needm: -#ifdef GOOS_windows - // Set up a dummy TLS value. needm is careful not to use it, - // but it needs to be there to prevent autogenerated code from - // crashing when it loads from it. - // We don't need to clear it or anything later because needm - // will set up TLS properly. - MOVQ $zeroTLS<>(SB), DI - CALL runtime·settls(SB) -#endif - // On some platforms (Windows) we cannot call needm through - // an ABI wrapper because there's no TLS set up, and the ABI - // wrapper will try to restore the G register (R14) from TLS. - // Clear X15 because Go expects it and we're not calling - // through a wrapper, but otherwise avoid setting the G - // register in the wrapper and call needm directly. It - // takes no arguments and doesn't return any values so - // there's no need to handle that. Clear R14 so that there's - // a bad value in there, in case needm tries to use it. - XORPS X15, X15 - XORQ R14, R14 - MOVQ $runtime·needAndBindM(SB), AX - CALL AX - MOVQ $0, savedm-8(SP) - get_tls(CX) - MOVQ g(CX), BX - MOVQ g_m(BX), BX - - // Set m->sched.sp = SP, so that if a panic happens - // during the function we are about to execute, it will - // have a valid SP to run on the g0 stack. - // The next few lines (after the havem label) - // will save this SP onto the stack and then write - // the same SP back to m->sched.sp. That seems redundant, - // but if an unrecovered panic happens, unwindm will - // restore the g->sched.sp from the stack location - // and then systemstack will try to use it. If we don't set it here, - // that restored SP will be uninitialized (typically 0) and - // will not be usable. - MOVQ m_g0(BX), SI - MOVQ SP, (g_sched+gobuf_sp)(SI) - -havem: - // Now there's a valid m, and we're running on its m->g0. - // Save current m->g0->sched.sp on stack and then set it to SP. - // Save current sp in m->g0->sched.sp in preparation for - // switch back to m->curg stack. - // NOTE: unwindm knows that the saved g->sched.sp is at 0(SP). - MOVQ m_g0(BX), SI - MOVQ (g_sched+gobuf_sp)(SI), AX - MOVQ AX, 0(SP) - MOVQ SP, (g_sched+gobuf_sp)(SI) - - // Switch to m->curg stack and call runtime.cgocallbackg. - // Because we are taking over the execution of m->curg - // but *not* resuming what had been running, we need to - // save that information (m->curg->sched) so we can restore it. - // We can restore m->curg->sched.sp easily, because calling - // runtime.cgocallbackg leaves SP unchanged upon return. - // To save m->curg->sched.pc, we push it onto the curg stack and - // open a frame the same size as cgocallback's g0 frame. - // Once we switch to the curg stack, the pushed PC will appear - // to be the return PC of cgocallback, so that the traceback - // will seamlessly trace back into the earlier calls. - MOVQ m_curg(BX), SI - MOVQ SI, g(CX) - MOVQ (g_sched+gobuf_sp)(SI), DI // prepare stack as DI - MOVQ (g_sched+gobuf_pc)(SI), BX - MOVQ BX, -8(DI) // "push" return PC on the g stack - // Gather our arguments into registers. - MOVQ fn+0(FP), BX - MOVQ frame+8(FP), CX - MOVQ ctxt+16(FP), DX - // Compute the size of the frame, including return PC and, if - // GOEXPERIMENT=framepointer, the saved base pointer - LEAQ fn+0(FP), AX - SUBQ SP, AX // AX is our actual frame size - SUBQ AX, DI // Allocate the same frame size on the g stack - MOVQ DI, SP - - MOVQ BX, 0(SP) - MOVQ CX, 8(SP) - MOVQ DX, 16(SP) - MOVQ $runtime·cgocallbackg(SB), AX - CALL AX // indirect call to bypass nosplit check. We're on a different stack now. - - // Compute the size of the frame again. FP and SP have - // completely different values here than they did above, - // but only their difference matters. - LEAQ fn+0(FP), AX - SUBQ SP, AX - - // Restore g->sched (== m->curg->sched) from saved values. - get_tls(CX) - MOVQ g(CX), SI - MOVQ SP, DI - ADDQ AX, DI - MOVQ -8(DI), BX - MOVQ BX, (g_sched+gobuf_pc)(SI) - MOVQ DI, (g_sched+gobuf_sp)(SI) - - // Switch back to m->g0's stack and restore m->g0->sched.sp. - // (Unlike m->curg, the g0 goroutine never uses sched.pc, - // so we do not have to restore it.) - MOVQ g(CX), BX - MOVQ g_m(BX), BX - MOVQ m_g0(BX), SI - MOVQ SI, g(CX) - MOVQ (g_sched+gobuf_sp)(SI), SP - MOVQ 0(SP), AX - MOVQ AX, (g_sched+gobuf_sp)(SI) - - // If the m on entry was nil, we called needm above to borrow an m, - // 1. for the duration of the call on non-pthread platforms, - // 2. or the duration of the C thread alive on pthread platforms. - // If the m on entry wasn't nil, - // 1. the thread might be a Go thread, - // 2. or it wasn't the first call from a C thread on pthread platforms, - // since then we skip dropm to reuse the m in the first call. - MOVQ savedm-8(SP), BX - CMPQ BX, $0 - JNE done - - // Skip dropm to reuse it in the next call, when a pthread key has been created. - MOVQ _cgo_pthread_key_created(SB), AX - // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. - CMPQ AX, $0 - JEQ dropm - CMPQ (AX), $0 - JNE done - -dropm: - MOVQ $runtime·dropm(SB), AX - CALL AX -#ifdef GOOS_windows - // We need to clear the TLS pointer in case the next - // thread that comes into Go tries to reuse that space - // but uses the same M. - XORQ DI, DI - CALL runtime·settls(SB) -#endif -done: - - // Done! - RET - -// func setg(gg *g) -// set g. for use by needm. -TEXT runtime·setg(SB), NOSPLIT, $0-8 - MOVQ gg+0(FP), BX - get_tls(CX) - MOVQ BX, g(CX) - RET - -// void setg_gcc(G*); set g called from gcc. -TEXT setg_gcc<>(SB),NOSPLIT,$0 - get_tls(AX) - MOVQ DI, g(AX) - MOVQ DI, R14 // set the g register - RET - -TEXT runtime·abort(SB),NOSPLIT,$0-0 - INT $3 -loop: - JMP loop - -// check that SP is in range [g->stack.lo, g->stack.hi) -TEXT runtime·stackcheck(SB), NOSPLIT|NOFRAME, $0-0 - get_tls(CX) - MOVQ g(CX), AX - CMPQ (g_stack+stack_hi)(AX), SP - JHI 2(PC) - CALL runtime·abort(SB) - CMPQ SP, (g_stack+stack_lo)(AX) - JHI 2(PC) - CALL runtime·abort(SB) - RET - -// func cputicks() int64 -TEXT runtime·cputicks(SB),NOSPLIT,$0-0 - CMPB internal∕cpu·X86+const_offsetX86HasRDTSCP(SB), $1 - JNE fences - // Instruction stream serializing RDTSCP is supported. - // RDTSCP is supported by Intel Nehalem (2008) and - // AMD K8 Rev. F (2006) and newer. - RDTSCP -done: - SHLQ $32, DX - ADDQ DX, AX - MOVQ AX, ret+0(FP) - RET -fences: - // MFENCE is instruction stream serializing and flushes the - // store buffers on AMD. The serialization semantics of LFENCE on AMD - // are dependent on MSR C001_1029 and CPU generation. - // LFENCE on Intel does wait for all previous instructions to have executed. - // Intel recommends MFENCE;LFENCE in its manuals before RDTSC to have all - // previous instructions executed and all previous loads and stores to globally visible. - // Using MFENCE;LFENCE here aligns the serializing properties without - // runtime detection of CPU manufacturer. - MFENCE - LFENCE - RDTSC - JMP done - -// func memhash(p unsafe.Pointer, h, s uintptr) uintptr -// hash function using AES hardware instructions -TEXT runtime·memhash(SB),NOSPLIT,$0-32 - // AX = ptr to data - // BX = seed - // CX = size - CMPB runtime·useAeshash(SB), $0 - JEQ noaes - JMP aeshashbody<>(SB) -noaes: - JMP runtime·memhashFallback(SB) - -// func strhash(p unsafe.Pointer, h uintptr) uintptr -TEXT runtime·strhash(SB),NOSPLIT,$0-24 - // AX = ptr to string struct - // BX = seed - CMPB runtime·useAeshash(SB), $0 - JEQ noaes - MOVQ 8(AX), CX // length of string - MOVQ (AX), AX // string data - JMP aeshashbody<>(SB) -noaes: - JMP runtime·strhashFallback(SB) - -// AX: data -// BX: hash seed -// CX: length -// At return: AX = return value -TEXT aeshashbody<>(SB),NOSPLIT,$0-0 - // Fill an SSE register with our seeds. - MOVQ BX, X0 // 64 bits of per-table hash seed - PINSRW $4, CX, X0 // 16 bits of length - PSHUFHW $0, X0, X0 // repeat length 4 times total - MOVO X0, X1 // save unscrambled seed - PXOR runtime·aeskeysched(SB), X0 // xor in per-process seed - AESENC X0, X0 // scramble seed - - CMPQ CX, $16 - JB aes0to15 - JE aes16 - CMPQ CX, $32 - JBE aes17to32 - CMPQ CX, $64 - JBE aes33to64 - CMPQ CX, $128 - JBE aes65to128 - JMP aes129plus - -aes0to15: - TESTQ CX, CX - JE aes0 - - ADDQ $16, AX - TESTW $0xff0, AX - JE endofpage - - // 16 bytes loaded at this address won't cross - // a page boundary, so we can load it directly. - MOVOU -16(AX), X1 - ADDQ CX, CX - MOVQ $masks<>(SB), AX - PAND (AX)(CX*8), X1 -final1: - PXOR X0, X1 // xor data with seed - AESENC X1, X1 // scramble combo 3 times - AESENC X1, X1 - AESENC X1, X1 - MOVQ X1, AX // return X1 - RET - -endofpage: - // address ends in 1111xxxx. Might be up against - // a page boundary, so load ending at last byte. - // Then shift bytes down using pshufb. - MOVOU -32(AX)(CX*1), X1 - ADDQ CX, CX - MOVQ $shifts<>(SB), AX - PSHUFB (AX)(CX*8), X1 - JMP final1 - -aes0: - // Return scrambled input seed - AESENC X0, X0 - MOVQ X0, AX // return X0 - RET - -aes16: - MOVOU (AX), X1 - JMP final1 - -aes17to32: - // make second starting seed - PXOR runtime·aeskeysched+16(SB), X1 - AESENC X1, X1 - - // load data to be hashed - MOVOU (AX), X2 - MOVOU -16(AX)(CX*1), X3 - - // xor with seed - PXOR X0, X2 - PXOR X1, X3 - - // scramble 3 times - AESENC X2, X2 - AESENC X3, X3 - AESENC X2, X2 - AESENC X3, X3 - AESENC X2, X2 - AESENC X3, X3 - - // combine results - PXOR X3, X2 - MOVQ X2, AX // return X2 - RET - -aes33to64: - // make 3 more starting seeds - MOVO X1, X2 - MOVO X1, X3 - PXOR runtime·aeskeysched+16(SB), X1 - PXOR runtime·aeskeysched+32(SB), X2 - PXOR runtime·aeskeysched+48(SB), X3 - AESENC X1, X1 - AESENC X2, X2 - AESENC X3, X3 - - MOVOU (AX), X4 - MOVOU 16(AX), X5 - MOVOU -32(AX)(CX*1), X6 - MOVOU -16(AX)(CX*1), X7 - - PXOR X0, X4 - PXOR X1, X5 - PXOR X2, X6 - PXOR X3, X7 - - AESENC X4, X4 - AESENC X5, X5 - AESENC X6, X6 - AESENC X7, X7 - - AESENC X4, X4 - AESENC X5, X5 - AESENC X6, X6 - AESENC X7, X7 - - AESENC X4, X4 - AESENC X5, X5 - AESENC X6, X6 - AESENC X7, X7 - - PXOR X6, X4 - PXOR X7, X5 - PXOR X5, X4 - MOVQ X4, AX // return X4 - RET - -aes65to128: - // make 7 more starting seeds - MOVO X1, X2 - MOVO X1, X3 - MOVO X1, X4 - MOVO X1, X5 - MOVO X1, X6 - MOVO X1, X7 - PXOR runtime·aeskeysched+16(SB), X1 - PXOR runtime·aeskeysched+32(SB), X2 - PXOR runtime·aeskeysched+48(SB), X3 - PXOR runtime·aeskeysched+64(SB), X4 - PXOR runtime·aeskeysched+80(SB), X5 - PXOR runtime·aeskeysched+96(SB), X6 - PXOR runtime·aeskeysched+112(SB), X7 - AESENC X1, X1 - AESENC X2, X2 - AESENC X3, X3 - AESENC X4, X4 - AESENC X5, X5 - AESENC X6, X6 - AESENC X7, X7 - - // load data - MOVOU (AX), X8 - MOVOU 16(AX), X9 - MOVOU 32(AX), X10 - MOVOU 48(AX), X11 - MOVOU -64(AX)(CX*1), X12 - MOVOU -48(AX)(CX*1), X13 - MOVOU -32(AX)(CX*1), X14 - MOVOU -16(AX)(CX*1), X15 - - // xor with seed - PXOR X0, X8 - PXOR X1, X9 - PXOR X2, X10 - PXOR X3, X11 - PXOR X4, X12 - PXOR X5, X13 - PXOR X6, X14 - PXOR X7, X15 - - // scramble 3 times - AESENC X8, X8 - AESENC X9, X9 - AESENC X10, X10 - AESENC X11, X11 - AESENC X12, X12 - AESENC X13, X13 - AESENC X14, X14 - AESENC X15, X15 - - AESENC X8, X8 - AESENC X9, X9 - AESENC X10, X10 - AESENC X11, X11 - AESENC X12, X12 - AESENC X13, X13 - AESENC X14, X14 - AESENC X15, X15 - - AESENC X8, X8 - AESENC X9, X9 - AESENC X10, X10 - AESENC X11, X11 - AESENC X12, X12 - AESENC X13, X13 - AESENC X14, X14 - AESENC X15, X15 - - // combine results - PXOR X12, X8 - PXOR X13, X9 - PXOR X14, X10 - PXOR X15, X11 - PXOR X10, X8 - PXOR X11, X9 - PXOR X9, X8 - // X15 must be zero on return - PXOR X15, X15 - MOVQ X8, AX // return X8 - RET - -aes129plus: - // make 7 more starting seeds - MOVO X1, X2 - MOVO X1, X3 - MOVO X1, X4 - MOVO X1, X5 - MOVO X1, X6 - MOVO X1, X7 - PXOR runtime·aeskeysched+16(SB), X1 - PXOR runtime·aeskeysched+32(SB), X2 - PXOR runtime·aeskeysched+48(SB), X3 - PXOR runtime·aeskeysched+64(SB), X4 - PXOR runtime·aeskeysched+80(SB), X5 - PXOR runtime·aeskeysched+96(SB), X6 - PXOR runtime·aeskeysched+112(SB), X7 - AESENC X1, X1 - AESENC X2, X2 - AESENC X3, X3 - AESENC X4, X4 - AESENC X5, X5 - AESENC X6, X6 - AESENC X7, X7 - - // start with last (possibly overlapping) block - MOVOU -128(AX)(CX*1), X8 - MOVOU -112(AX)(CX*1), X9 - MOVOU -96(AX)(CX*1), X10 - MOVOU -80(AX)(CX*1), X11 - MOVOU -64(AX)(CX*1), X12 - MOVOU -48(AX)(CX*1), X13 - MOVOU -32(AX)(CX*1), X14 - MOVOU -16(AX)(CX*1), X15 - - // xor in seed - PXOR X0, X8 - PXOR X1, X9 - PXOR X2, X10 - PXOR X3, X11 - PXOR X4, X12 - PXOR X5, X13 - PXOR X6, X14 - PXOR X7, X15 - - // compute number of remaining 128-byte blocks - DECQ CX - SHRQ $7, CX - - PCALIGN $16 -aesloop: - // scramble state - AESENC X8, X8 - AESENC X9, X9 - AESENC X10, X10 - AESENC X11, X11 - AESENC X12, X12 - AESENC X13, X13 - AESENC X14, X14 - AESENC X15, X15 - - // scramble state, xor in a block - MOVOU (AX), X0 - MOVOU 16(AX), X1 - MOVOU 32(AX), X2 - MOVOU 48(AX), X3 - AESENC X0, X8 - AESENC X1, X9 - AESENC X2, X10 - AESENC X3, X11 - MOVOU 64(AX), X4 - MOVOU 80(AX), X5 - MOVOU 96(AX), X6 - MOVOU 112(AX), X7 - AESENC X4, X12 - AESENC X5, X13 - AESENC X6, X14 - AESENC X7, X15 - - ADDQ $128, AX - DECQ CX - JNE aesloop - - // 3 more scrambles to finish - AESENC X8, X8 - AESENC X9, X9 - AESENC X10, X10 - AESENC X11, X11 - AESENC X12, X12 - AESENC X13, X13 - AESENC X14, X14 - AESENC X15, X15 - AESENC X8, X8 - AESENC X9, X9 - AESENC X10, X10 - AESENC X11, X11 - AESENC X12, X12 - AESENC X13, X13 - AESENC X14, X14 - AESENC X15, X15 - AESENC X8, X8 - AESENC X9, X9 - AESENC X10, X10 - AESENC X11, X11 - AESENC X12, X12 - AESENC X13, X13 - AESENC X14, X14 - AESENC X15, X15 - - PXOR X12, X8 - PXOR X13, X9 - PXOR X14, X10 - PXOR X15, X11 - PXOR X10, X8 - PXOR X11, X9 - PXOR X9, X8 - // X15 must be zero on return - PXOR X15, X15 - MOVQ X8, AX // return X8 - RET - -// func memhash32(p unsafe.Pointer, h uintptr) uintptr -// ABIInternal for performance. -TEXT runtime·memhash32(SB),NOSPLIT,$0-24 - // AX = ptr to data - // BX = seed - CMPB runtime·useAeshash(SB), $0 - JEQ noaes - MOVQ BX, X0 // X0 = seed - PINSRD $2, (AX), X0 // data - AESENC runtime·aeskeysched+0(SB), X0 - AESENC runtime·aeskeysched+16(SB), X0 - AESENC runtime·aeskeysched+32(SB), X0 - MOVQ X0, AX // return X0 - RET -noaes: - JMP runtime·memhash32Fallback(SB) - -// func memhash64(p unsafe.Pointer, h uintptr) uintptr -// ABIInternal for performance. -TEXT runtime·memhash64(SB),NOSPLIT,$0-24 - // AX = ptr to data - // BX = seed - CMPB runtime·useAeshash(SB), $0 - JEQ noaes - MOVQ BX, X0 // X0 = seed - PINSRQ $1, (AX), X0 // data - AESENC runtime·aeskeysched+0(SB), X0 - AESENC runtime·aeskeysched+16(SB), X0 - AESENC runtime·aeskeysched+32(SB), X0 - MOVQ X0, AX // return X0 - RET -noaes: - JMP runtime·memhash64Fallback(SB) - -// simple mask to get rid of data in the high part of the register. -DATA masks<>+0x00(SB)/8, $0x0000000000000000 -DATA masks<>+0x08(SB)/8, $0x0000000000000000 -DATA masks<>+0x10(SB)/8, $0x00000000000000ff -DATA masks<>+0x18(SB)/8, $0x0000000000000000 -DATA masks<>+0x20(SB)/8, $0x000000000000ffff -DATA masks<>+0x28(SB)/8, $0x0000000000000000 -DATA masks<>+0x30(SB)/8, $0x0000000000ffffff -DATA masks<>+0x38(SB)/8, $0x0000000000000000 -DATA masks<>+0x40(SB)/8, $0x00000000ffffffff -DATA masks<>+0x48(SB)/8, $0x0000000000000000 -DATA masks<>+0x50(SB)/8, $0x000000ffffffffff -DATA masks<>+0x58(SB)/8, $0x0000000000000000 -DATA masks<>+0x60(SB)/8, $0x0000ffffffffffff -DATA masks<>+0x68(SB)/8, $0x0000000000000000 -DATA masks<>+0x70(SB)/8, $0x00ffffffffffffff -DATA masks<>+0x78(SB)/8, $0x0000000000000000 -DATA masks<>+0x80(SB)/8, $0xffffffffffffffff -DATA masks<>+0x88(SB)/8, $0x0000000000000000 -DATA masks<>+0x90(SB)/8, $0xffffffffffffffff -DATA masks<>+0x98(SB)/8, $0x00000000000000ff -DATA masks<>+0xa0(SB)/8, $0xffffffffffffffff -DATA masks<>+0xa8(SB)/8, $0x000000000000ffff -DATA masks<>+0xb0(SB)/8, $0xffffffffffffffff -DATA masks<>+0xb8(SB)/8, $0x0000000000ffffff -DATA masks<>+0xc0(SB)/8, $0xffffffffffffffff -DATA masks<>+0xc8(SB)/8, $0x00000000ffffffff -DATA masks<>+0xd0(SB)/8, $0xffffffffffffffff -DATA masks<>+0xd8(SB)/8, $0x000000ffffffffff -DATA masks<>+0xe0(SB)/8, $0xffffffffffffffff -DATA masks<>+0xe8(SB)/8, $0x0000ffffffffffff -DATA masks<>+0xf0(SB)/8, $0xffffffffffffffff -DATA masks<>+0xf8(SB)/8, $0x00ffffffffffffff -GLOBL masks<>(SB),RODATA,$256 - -// func checkASM() bool -TEXT ·checkASM(SB),NOSPLIT,$0-1 - // check that masks<>(SB) and shifts<>(SB) are aligned to 16-byte - MOVQ $masks<>(SB), AX - MOVQ $shifts<>(SB), BX - ORQ BX, AX - TESTQ $15, AX - SETEQ ret+0(FP) - RET - -// these are arguments to pshufb. They move data down from -// the high bytes of the register to the low bytes of the register. -// index is how many bytes to move. -DATA shifts<>+0x00(SB)/8, $0x0000000000000000 -DATA shifts<>+0x08(SB)/8, $0x0000000000000000 -DATA shifts<>+0x10(SB)/8, $0xffffffffffffff0f -DATA shifts<>+0x18(SB)/8, $0xffffffffffffffff -DATA shifts<>+0x20(SB)/8, $0xffffffffffff0f0e -DATA shifts<>+0x28(SB)/8, $0xffffffffffffffff -DATA shifts<>+0x30(SB)/8, $0xffffffffff0f0e0d -DATA shifts<>+0x38(SB)/8, $0xffffffffffffffff -DATA shifts<>+0x40(SB)/8, $0xffffffff0f0e0d0c -DATA shifts<>+0x48(SB)/8, $0xffffffffffffffff -DATA shifts<>+0x50(SB)/8, $0xffffff0f0e0d0c0b -DATA shifts<>+0x58(SB)/8, $0xffffffffffffffff -DATA shifts<>+0x60(SB)/8, $0xffff0f0e0d0c0b0a -DATA shifts<>+0x68(SB)/8, $0xffffffffffffffff -DATA shifts<>+0x70(SB)/8, $0xff0f0e0d0c0b0a09 -DATA shifts<>+0x78(SB)/8, $0xffffffffffffffff -DATA shifts<>+0x80(SB)/8, $0x0f0e0d0c0b0a0908 -DATA shifts<>+0x88(SB)/8, $0xffffffffffffffff -DATA shifts<>+0x90(SB)/8, $0x0e0d0c0b0a090807 -DATA shifts<>+0x98(SB)/8, $0xffffffffffffff0f -DATA shifts<>+0xa0(SB)/8, $0x0d0c0b0a09080706 -DATA shifts<>+0xa8(SB)/8, $0xffffffffffff0f0e -DATA shifts<>+0xb0(SB)/8, $0x0c0b0a0908070605 -DATA shifts<>+0xb8(SB)/8, $0xffffffffff0f0e0d -DATA shifts<>+0xc0(SB)/8, $0x0b0a090807060504 -DATA shifts<>+0xc8(SB)/8, $0xffffffff0f0e0d0c -DATA shifts<>+0xd0(SB)/8, $0x0a09080706050403 -DATA shifts<>+0xd8(SB)/8, $0xffffff0f0e0d0c0b -DATA shifts<>+0xe0(SB)/8, $0x0908070605040302 -DATA shifts<>+0xe8(SB)/8, $0xffff0f0e0d0c0b0a -DATA shifts<>+0xf0(SB)/8, $0x0807060504030201 -DATA shifts<>+0xf8(SB)/8, $0xff0f0e0d0c0b0a09 -GLOBL shifts<>(SB),RODATA,$256 - -TEXT runtime·return0(SB), NOSPLIT, $0 - MOVL $0, AX - RET - - -// Called from cgo wrappers, this function returns g->m->curg.stack.hi. -// Must obey the gcc calling convention. -TEXT _cgo_topofstack(SB),NOSPLIT,$0 - get_tls(CX) - MOVQ g(CX), AX - MOVQ g_m(AX), AX - MOVQ m_curg(AX), AX - MOVQ (g_stack+stack_hi)(AX), AX - RET - -// The top-most function running on a goroutine -// returns to goexit+PCQuantum. -TEXT runtime·goexit(SB),NOSPLIT|TOPFRAME|NOFRAME,$0-0 - BYTE $0x90 // NOP - CALL runtime·goexit1(SB) // does not return - // traceback from goexit1 must hit code range of goexit - BYTE $0x90 // NOP - -// This is called from .init_array and follows the platform, not Go, ABI. -TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 - PUSHQ R15 // The access to global variables below implicitly uses R15, which is callee-save - MOVQ runtime·lastmoduledatap(SB), AX - MOVQ DI, moduledata_next(AX) - MOVQ DI, runtime·lastmoduledatap(SB) - POPQ R15 - RET - -// Initialize special registers then jump to sigpanic. -// This function is injected from the signal handler for panicking -// signals. It is quite painful to set X15 in the signal context, -// so we do it here. -TEXT ·sigpanic0(SB),NOSPLIT,$0-0 - get_tls(R14) - MOVQ g(R14), R14 -#ifndef GOOS_plan9 - XORPS X15, X15 -#endif - JMP ·sigpanic(SB) - -// gcWriteBarrier informs the GC about heap pointer writes. -// -// gcWriteBarrier returns space in a write barrier buffer which -// should be filled in by the caller. -// gcWriteBarrier does NOT follow the Go ABI. It accepts the -// number of bytes of buffer needed in R11, and returns a pointer -// to the buffer space in R11. -// It clobbers FLAGS. It does not clobber any general-purpose registers, -// but may clobber others (e.g., SSE registers). -// Typical use would be, when doing *(CX+88) = AX -// CMPL $0, runtime.writeBarrier(SB) -// JEQ dowrite -// CALL runtime.gcBatchBarrier2(SB) -// MOVQ AX, (R11) -// MOVQ 88(CX), DX -// MOVQ DX, 8(R11) -// dowrite: -// MOVQ AX, 88(CX) -TEXT gcWriteBarrier<>(SB),NOSPLIT,$112 - // Save the registers clobbered by the fast path. This is slightly - // faster than having the caller spill these. - MOVQ R12, 96(SP) - MOVQ R13, 104(SP) -retry: - // TODO: Consider passing g.m.p in as an argument so they can be shared - // across a sequence of write barriers. - MOVQ g_m(R14), R13 - MOVQ m_p(R13), R13 - // Get current buffer write position. - MOVQ (p_wbBuf+wbBuf_next)(R13), R12 // original next position - ADDQ R11, R12 // new next position - // Is the buffer full? - CMPQ R12, (p_wbBuf+wbBuf_end)(R13) - JA flush - // Commit to the larger buffer. - MOVQ R12, (p_wbBuf+wbBuf_next)(R13) - // Make return value (the original next position) - SUBQ R11, R12 - MOVQ R12, R11 - // Restore registers. - MOVQ 96(SP), R12 - MOVQ 104(SP), R13 - RET - -flush: - // Save all general purpose registers since these could be - // clobbered by wbBufFlush and were not saved by the caller. - // It is possible for wbBufFlush to clobber other registers - // (e.g., SSE registers), but the compiler takes care of saving - // those in the caller if necessary. This strikes a balance - // with registers that are likely to be used. - // - // We don't have type information for these, but all code under - // here is NOSPLIT, so nothing will observe these. - // - // TODO: We could strike a different balance; e.g., saving X0 - // and not saving GP registers that are less likely to be used. - MOVQ DI, 0(SP) - MOVQ AX, 8(SP) - MOVQ BX, 16(SP) - MOVQ CX, 24(SP) - MOVQ DX, 32(SP) - // DI already saved - MOVQ SI, 40(SP) - MOVQ BP, 48(SP) - MOVQ R8, 56(SP) - MOVQ R9, 64(SP) - MOVQ R10, 72(SP) - MOVQ R11, 80(SP) - // R12 already saved - // R13 already saved - // R14 is g - MOVQ R15, 88(SP) - - CALL runtime·wbBufFlush(SB) - - MOVQ 0(SP), DI - MOVQ 8(SP), AX - MOVQ 16(SP), BX - MOVQ 24(SP), CX - MOVQ 32(SP), DX - MOVQ 40(SP), SI - MOVQ 48(SP), BP - MOVQ 56(SP), R8 - MOVQ 64(SP), R9 - MOVQ 72(SP), R10 - MOVQ 80(SP), R11 - MOVQ 88(SP), R15 - JMP retry - -TEXT runtime·gcWriteBarrier1(SB),NOSPLIT|NOFRAME,$0 - MOVL $8, R11 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier2(SB),NOSPLIT|NOFRAME,$0 - MOVL $16, R11 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier3(SB),NOSPLIT|NOFRAME,$0 - MOVL $24, R11 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier4(SB),NOSPLIT|NOFRAME,$0 - MOVL $32, R11 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier5(SB),NOSPLIT|NOFRAME,$0 - MOVL $40, R11 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier6(SB),NOSPLIT|NOFRAME,$0 - MOVL $48, R11 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier7(SB),NOSPLIT|NOFRAME,$0 - MOVL $56, R11 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier8(SB),NOSPLIT|NOFRAME,$0 - MOVL $64, R11 - JMP gcWriteBarrier<>(SB) - -DATA debugCallFrameTooLarge<>+0x00(SB)/20, $"call frame too large" -GLOBL debugCallFrameTooLarge<>(SB), RODATA, $20 // Size duplicated below - -// debugCallV2 is the entry point for debugger-injected function -// calls on running goroutines. It informs the runtime that a -// debug call has been injected and creates a call frame for the -// debugger to fill in. -// -// To inject a function call, a debugger should: -// 1. Check that the goroutine is in state _Grunning and that -// there are at least 256 bytes free on the stack. -// 2. Push the current PC on the stack (updating SP). -// 3. Write the desired argument frame size at SP-16 (using the SP -// after step 2). -// 4. Save all machine registers (including flags and XMM registers) -// so they can be restored later by the debugger. -// 5. Set the PC to debugCallV2 and resume execution. -// -// If the goroutine is in state _Grunnable, then it's not generally -// safe to inject a call because it may return out via other runtime -// operations. Instead, the debugger should unwind the stack to find -// the return to non-runtime code, add a temporary breakpoint there, -// and inject the call once that breakpoint is hit. -// -// If the goroutine is in any other state, it's not safe to inject a call. -// -// This function communicates back to the debugger by setting R12 and -// invoking INT3 to raise a breakpoint signal. See the comments in the -// implementation for the protocol the debugger is expected to -// follow. InjectDebugCall in the runtime tests demonstrates this protocol. -// -// The debugger must ensure that any pointers passed to the function -// obey escape analysis requirements. Specifically, it must not pass -// a stack pointer to an escaping argument. debugCallV2 cannot check -// this invariant. -// -// This is ABIInternal because Go code injects its PC directly into new -// goroutine stacks. -TEXT runtime·debugCallV2(SB),NOSPLIT,$152-0 - // Save all registers that may contain pointers so they can be - // conservatively scanned. - // - // We can't do anything that might clobber any of these - // registers before this. - MOVQ R15, r15-(14*8+8)(SP) - MOVQ R14, r14-(13*8+8)(SP) - MOVQ R13, r13-(12*8+8)(SP) - MOVQ R12, r12-(11*8+8)(SP) - MOVQ R11, r11-(10*8+8)(SP) - MOVQ R10, r10-(9*8+8)(SP) - MOVQ R9, r9-(8*8+8)(SP) - MOVQ R8, r8-(7*8+8)(SP) - MOVQ DI, di-(6*8+8)(SP) - MOVQ SI, si-(5*8+8)(SP) - MOVQ BP, bp-(4*8+8)(SP) - MOVQ BX, bx-(3*8+8)(SP) - MOVQ DX, dx-(2*8+8)(SP) - // Save the frame size before we clobber it. Either of the last - // saves could clobber this depending on whether there's a saved BP. - MOVQ frameSize-24(FP), DX // aka -16(RSP) before prologue - MOVQ CX, cx-(1*8+8)(SP) - MOVQ AX, ax-(0*8+8)(SP) - - // Save the argument frame size. - MOVQ DX, frameSize-128(SP) - - // Perform a safe-point check. - MOVQ retpc-8(FP), AX // Caller's PC - MOVQ AX, 0(SP) - CALL runtime·debugCallCheck(SB) - MOVQ 8(SP), AX - TESTQ AX, AX - JZ good - // The safety check failed. Put the reason string at the top - // of the stack. - MOVQ AX, 0(SP) - MOVQ 16(SP), AX - MOVQ AX, 8(SP) - // Set R12 to 8 and invoke INT3. The debugger should get the - // reason a call can't be injected from the top of the stack - // and resume execution. - MOVQ $8, R12 - BYTE $0xcc - JMP restore - -good: - // Registers are saved and it's safe to make a call. - // Open up a call frame, moving the stack if necessary. - // - // Once the frame is allocated, this will set R12 to 0 and - // invoke INT3. The debugger should write the argument - // frame for the call at SP, set up argument registers, push - // the trapping PC on the stack, set the PC to the function to - // call, set RDX to point to the closure (if a closure call), - // and resume execution. - // - // If the function returns, this will set R12 to 1 and invoke - // INT3. The debugger can then inspect any return value saved - // on the stack at SP and in registers and resume execution again. - // - // If the function panics, this will set R12 to 2 and invoke INT3. - // The interface{} value of the panic will be at SP. The debugger - // can inspect the panic value and resume execution again. -#define DEBUG_CALL_DISPATCH(NAME,MAXSIZE) \ - CMPQ AX, $MAXSIZE; \ - JA 5(PC); \ - MOVQ $NAME(SB), AX; \ - MOVQ AX, 0(SP); \ - CALL runtime·debugCallWrap(SB); \ - JMP restore - - MOVQ frameSize-128(SP), AX - DEBUG_CALL_DISPATCH(debugCall32<>, 32) - DEBUG_CALL_DISPATCH(debugCall64<>, 64) - DEBUG_CALL_DISPATCH(debugCall128<>, 128) - DEBUG_CALL_DISPATCH(debugCall256<>, 256) - DEBUG_CALL_DISPATCH(debugCall512<>, 512) - DEBUG_CALL_DISPATCH(debugCall1024<>, 1024) - DEBUG_CALL_DISPATCH(debugCall2048<>, 2048) - DEBUG_CALL_DISPATCH(debugCall4096<>, 4096) - DEBUG_CALL_DISPATCH(debugCall8192<>, 8192) - DEBUG_CALL_DISPATCH(debugCall16384<>, 16384) - DEBUG_CALL_DISPATCH(debugCall32768<>, 32768) - DEBUG_CALL_DISPATCH(debugCall65536<>, 65536) - // The frame size is too large. Report the error. - MOVQ $debugCallFrameTooLarge<>(SB), AX - MOVQ AX, 0(SP) - MOVQ $20, 8(SP) // length of debugCallFrameTooLarge string - MOVQ $8, R12 - BYTE $0xcc - JMP restore - -restore: - // Calls and failures resume here. - // - // Set R12 to 16 and invoke INT3. The debugger should restore - // all registers except RIP and RSP and resume execution. - MOVQ $16, R12 - BYTE $0xcc - // We must not modify flags after this point. - - // Restore pointer-containing registers, which may have been - // modified from the debugger's copy by stack copying. - MOVQ ax-(0*8+8)(SP), AX - MOVQ cx-(1*8+8)(SP), CX - MOVQ dx-(2*8+8)(SP), DX - MOVQ bx-(3*8+8)(SP), BX - MOVQ bp-(4*8+8)(SP), BP - MOVQ si-(5*8+8)(SP), SI - MOVQ di-(6*8+8)(SP), DI - MOVQ r8-(7*8+8)(SP), R8 - MOVQ r9-(8*8+8)(SP), R9 - MOVQ r10-(9*8+8)(SP), R10 - MOVQ r11-(10*8+8)(SP), R11 - MOVQ r12-(11*8+8)(SP), R12 - MOVQ r13-(12*8+8)(SP), R13 - MOVQ r14-(13*8+8)(SP), R14 - MOVQ r15-(14*8+8)(SP), R15 - - RET - -// runtime.debugCallCheck assumes that functions defined with the -// DEBUG_CALL_FN macro are safe points to inject calls. -#define DEBUG_CALL_FN(NAME,MAXSIZE) \ -TEXT NAME(SB),WRAPPER,$MAXSIZE-0; \ - NO_LOCAL_POINTERS; \ - MOVQ $0, R12; \ - BYTE $0xcc; \ - MOVQ $1, R12; \ - BYTE $0xcc; \ - RET -DEBUG_CALL_FN(debugCall32<>, 32) -DEBUG_CALL_FN(debugCall64<>, 64) -DEBUG_CALL_FN(debugCall128<>, 128) -DEBUG_CALL_FN(debugCall256<>, 256) -DEBUG_CALL_FN(debugCall512<>, 512) -DEBUG_CALL_FN(debugCall1024<>, 1024) -DEBUG_CALL_FN(debugCall2048<>, 2048) -DEBUG_CALL_FN(debugCall4096<>, 4096) -DEBUG_CALL_FN(debugCall8192<>, 8192) -DEBUG_CALL_FN(debugCall16384<>, 16384) -DEBUG_CALL_FN(debugCall32768<>, 32768) -DEBUG_CALL_FN(debugCall65536<>, 65536) - -// func debugCallPanicked(val interface{}) -TEXT runtime·debugCallPanicked(SB),NOSPLIT,$16-16 - // Copy the panic value to the top of stack. - MOVQ val_type+0(FP), AX - MOVQ AX, 0(SP) - MOVQ val_data+8(FP), AX - MOVQ AX, 8(SP) - MOVQ $2, R12 - BYTE $0xcc - RET - -// Note: these functions use a special calling convention to save generated code space. -// Arguments are passed in registers, but the space for those arguments are allocated -// in the caller's stack frame. These stubs write the args into that stack space and -// then tail call to the corresponding runtime handler. -// The tail call makes these stubs disappear in backtraces. -// Defined as ABIInternal since they do not use the stack-based Go ABI. -TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 - MOVQ CX, BX - JMP runtime·goPanicIndex(SB) -TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 - MOVQ CX, BX - JMP runtime·goPanicIndexU(SB) -TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 - MOVQ CX, AX - MOVQ DX, BX - JMP runtime·goPanicSliceAlen(SB) -TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 - MOVQ CX, AX - MOVQ DX, BX - JMP runtime·goPanicSliceAlenU(SB) -TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 - MOVQ CX, AX - MOVQ DX, BX - JMP runtime·goPanicSliceAcap(SB) -TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 - MOVQ CX, AX - MOVQ DX, BX - JMP runtime·goPanicSliceAcapU(SB) -TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 - MOVQ CX, BX - JMP runtime·goPanicSliceB(SB) -TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 - MOVQ CX, BX - JMP runtime·goPanicSliceBU(SB) -TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 - MOVQ DX, AX - JMP runtime·goPanicSlice3Alen(SB) -TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 - MOVQ DX, AX - JMP runtime·goPanicSlice3AlenU(SB) -TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 - MOVQ DX, AX - JMP runtime·goPanicSlice3Acap(SB) -TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 - MOVQ DX, AX - JMP runtime·goPanicSlice3AcapU(SB) -TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 - MOVQ CX, AX - MOVQ DX, BX - JMP runtime·goPanicSlice3B(SB) -TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 - MOVQ CX, AX - MOVQ DX, BX - JMP runtime·goPanicSlice3BU(SB) -TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 - MOVQ CX, BX - JMP runtime·goPanicSlice3C(SB) -TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 - MOVQ CX, BX - JMP runtime·goPanicSlice3CU(SB) -TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 - MOVQ DX, AX - JMP runtime·goPanicSliceConvert(SB) - -#ifdef GOOS_android -// Use the free TLS_SLOT_APP slot #2 on Android Q. -// Earlier androids are set up in gcc_android.c. -DATA runtime·tls_g+0(SB)/8, $16 -GLOBL runtime·tls_g+0(SB), NOPTR, $8 -#endif -#ifdef GOOS_windows -GLOBL runtime·tls_g+0(SB), NOPTR, $8 -#endif - -// The compiler and assembler's -spectre=ret mode rewrites -// all indirect CALL AX / JMP AX instructions to be -// CALL retpolineAX / JMP retpolineAX. -// See https://support.google.com/faqs/answer/7625886. -#define RETPOLINE(reg) \ - /* CALL setup */ BYTE $0xE8; BYTE $(2+2); BYTE $0; BYTE $0; BYTE $0; \ - /* nospec: */ \ - /* PAUSE */ BYTE $0xF3; BYTE $0x90; \ - /* JMP nospec */ BYTE $0xEB; BYTE $-(2+2); \ - /* setup: */ \ - /* MOVQ AX, 0(SP) */ BYTE $0x48|((reg&8)>>1); BYTE $0x89; \ - BYTE $0x04|((reg&7)<<3); BYTE $0x24; \ - /* RET */ BYTE $0xC3 - -TEXT runtime·retpolineAX(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(0) -TEXT runtime·retpolineCX(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(1) -TEXT runtime·retpolineDX(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(2) -TEXT runtime·retpolineBX(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(3) -/* SP is 4, can't happen / magic encodings */ -TEXT runtime·retpolineBP(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(5) -TEXT runtime·retpolineSI(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(6) -TEXT runtime·retpolineDI(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(7) -TEXT runtime·retpolineR8(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(8) -TEXT runtime·retpolineR9(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(9) -TEXT runtime·retpolineR10(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(10) -TEXT runtime·retpolineR11(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(11) -TEXT runtime·retpolineR12(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(12) -TEXT runtime·retpolineR13(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(13) -TEXT runtime·retpolineR14(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(14) -TEXT runtime·retpolineR15(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(15) - -TEXT ·getfp(SB),NOSPLIT|NOFRAME,$0 - MOVQ BP, AX - RET diff --git a/contrib/go/_std_1.22/src/runtime/asm_arm64.s b/contrib/go/_std_1.22/src/runtime/asm_arm64.s deleted file mode 100644 index 6d77b08a1b90..000000000000 --- a/contrib/go/_std_1.22/src/runtime/asm_arm64.s +++ /dev/null @@ -1,1598 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go_asm.h" -#include "go_tls.h" -#include "tls_arm64.h" -#include "funcdata.h" -#include "textflag.h" - -TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 - // SP = stack; R0 = argc; R1 = argv - - SUB $32, RSP - MOVW R0, 8(RSP) // argc - MOVD R1, 16(RSP) // argv - -#ifdef TLS_darwin - // Initialize TLS. - MOVD ZR, g // clear g, make sure it's not junk. - SUB $32, RSP - MRS_TPIDR_R0 - AND $~7, R0 - MOVD R0, 16(RSP) // arg2: TLS base - MOVD $runtime·tls_g(SB), R2 - MOVD R2, 8(RSP) // arg1: &tlsg - BL ·tlsinit(SB) - ADD $32, RSP -#endif - - // create istack out of the given (operating system) stack. - // _cgo_init may update stackguard. - MOVD $runtime·g0(SB), g - MOVD RSP, R7 - MOVD $(-64*1024)(R7), R0 - MOVD R0, g_stackguard0(g) - MOVD R0, g_stackguard1(g) - MOVD R0, (g_stack+stack_lo)(g) - MOVD R7, (g_stack+stack_hi)(g) - - // if there is a _cgo_init, call it using the gcc ABI. - MOVD _cgo_init(SB), R12 - CBZ R12, nocgo - -#ifdef GOOS_android - MRS_TPIDR_R0 // load TLS base pointer - MOVD R0, R3 // arg 3: TLS base pointer - MOVD $runtime·tls_g(SB), R2 // arg 2: &tls_g -#else - MOVD $0, R2 // arg 2: not used when using platform's TLS -#endif - MOVD $setg_gcc<>(SB), R1 // arg 1: setg - MOVD g, R0 // arg 0: G - SUB $16, RSP // reserve 16 bytes for sp-8 where fp may be saved. - BL (R12) - ADD $16, RSP - -nocgo: - BL runtime·save_g(SB) - // update stackguard after _cgo_init - MOVD (g_stack+stack_lo)(g), R0 - ADD $const_stackGuard, R0 - MOVD R0, g_stackguard0(g) - MOVD R0, g_stackguard1(g) - - // set the per-goroutine and per-mach "registers" - MOVD $runtime·m0(SB), R0 - - // save m->g0 = g0 - MOVD g, m_g0(R0) - // save m0 to g0->m - MOVD R0, g_m(g) - - BL runtime·check(SB) - -#ifdef GOOS_windows - BL runtime·wintls(SB) -#endif - - MOVW 8(RSP), R0 // copy argc - MOVW R0, -8(RSP) - MOVD 16(RSP), R0 // copy argv - MOVD R0, 0(RSP) - BL runtime·args(SB) - BL runtime·osinit(SB) - BL runtime·schedinit(SB) - - // create a new goroutine to start program - MOVD $runtime·mainPC(SB), R0 // entry - SUB $16, RSP - MOVD R0, 8(RSP) // arg - MOVD $0, 0(RSP) // dummy LR - BL runtime·newproc(SB) - ADD $16, RSP - - // start this M - BL runtime·mstart(SB) - - // Prevent dead-code elimination of debugCallV2, which is - // intended to be called by debuggers. - MOVD $runtime·debugCallV2(SB), R0 - - MOVD $0, R0 - MOVD R0, (R0) // boom - UNDEF - -DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) -GLOBL runtime·mainPC(SB),RODATA,$8 - -// Windows ARM64 needs an immediate 0xf000 argument. -// See go.dev/issues/53837. -#define BREAK \ -#ifdef GOOS_windows \ - BRK $0xf000 \ -#else \ - BRK \ -#endif \ - - -TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0 - BREAK - RET - -TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0 - RET - -TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 - BL runtime·mstart0(SB) - RET // not reached - -/* - * go-routine - */ - -// void gogo(Gobuf*) -// restore state from Gobuf; longjmp -TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8 - MOVD buf+0(FP), R5 - MOVD gobuf_g(R5), R6 - MOVD 0(R6), R4 // make sure g != nil - B gogo<>(SB) - -TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 - MOVD R6, g - BL runtime·save_g(SB) - - MOVD gobuf_sp(R5), R0 - MOVD R0, RSP - MOVD gobuf_bp(R5), R29 - MOVD gobuf_lr(R5), LR - MOVD gobuf_ret(R5), R0 - MOVD gobuf_ctxt(R5), R26 - MOVD $0, gobuf_sp(R5) - MOVD $0, gobuf_bp(R5) - MOVD $0, gobuf_ret(R5) - MOVD $0, gobuf_lr(R5) - MOVD $0, gobuf_ctxt(R5) - CMP ZR, ZR // set condition codes for == test, needed by stack split - MOVD gobuf_pc(R5), R6 - B (R6) - -// void mcall(fn func(*g)) -// Switch to m->g0's stack, call fn(g). -// Fn must never return. It should gogo(&g->sched) -// to keep running g. -TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 - MOVD R0, R26 // context - - // Save caller state in g->sched - MOVD RSP, R0 - MOVD R0, (g_sched+gobuf_sp)(g) - MOVD R29, (g_sched+gobuf_bp)(g) - MOVD LR, (g_sched+gobuf_pc)(g) - MOVD $0, (g_sched+gobuf_lr)(g) - - // Switch to m->g0 & its stack, call fn. - MOVD g, R3 - MOVD g_m(g), R8 - MOVD m_g0(R8), g - BL runtime·save_g(SB) - CMP g, R3 - BNE 2(PC) - B runtime·badmcall(SB) - - MOVD (g_sched+gobuf_sp)(g), R0 - MOVD R0, RSP // sp = m->g0->sched.sp - MOVD (g_sched+gobuf_bp)(g), R29 - MOVD R3, R0 // arg = g - MOVD $0, -16(RSP) // dummy LR - SUB $16, RSP - MOVD 0(R26), R4 // code pointer - BL (R4) - B runtime·badmcall2(SB) - -// systemstack_switch is a dummy routine that systemstack leaves at the bottom -// of the G stack. We need to distinguish the routine that -// lives at the bottom of the G stack from the one that lives -// at the top of the system stack because the one at the top of -// the system stack terminates the stack walk (see topofstack()). -TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 - UNDEF - BL (LR) // make sure this function is not leaf - RET - -// func systemstack(fn func()) -TEXT runtime·systemstack(SB), NOSPLIT, $0-8 - MOVD fn+0(FP), R3 // R3 = fn - MOVD R3, R26 // context - MOVD g_m(g), R4 // R4 = m - - MOVD m_gsignal(R4), R5 // R5 = gsignal - CMP g, R5 - BEQ noswitch - - MOVD m_g0(R4), R5 // R5 = g0 - CMP g, R5 - BEQ noswitch - - MOVD m_curg(R4), R6 - CMP g, R6 - BEQ switch - - // Bad: g is not gsignal, not g0, not curg. What is it? - // Hide call from linker nosplit analysis. - MOVD $runtime·badsystemstack(SB), R3 - BL (R3) - B runtime·abort(SB) - -switch: - // save our state in g->sched. Pretend to - // be systemstack_switch if the G stack is scanned. - BL gosave_systemstack_switch<>(SB) - - // switch to g0 - MOVD R5, g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R3 - MOVD R3, RSP - MOVD (g_sched+gobuf_bp)(g), R29 - - // call target function - MOVD 0(R26), R3 // code pointer - BL (R3) - - // switch back to g - MOVD g_m(g), R3 - MOVD m_curg(R3), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R0 - MOVD R0, RSP - MOVD (g_sched+gobuf_bp)(g), R29 - MOVD $0, (g_sched+gobuf_sp)(g) - MOVD $0, (g_sched+gobuf_bp)(g) - RET - -noswitch: - // already on m stack, just call directly - // Using a tail call here cleans up tracebacks since we won't stop - // at an intermediate systemstack. - MOVD 0(R26), R3 // code pointer - MOVD.P 16(RSP), R30 // restore LR - SUB $8, RSP, R29 // restore FP - B (R3) - -// func switchToCrashStack0(fn func()) -TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 - MOVD R0, R26 // context register - MOVD g_m(g), R1 // curm - - // set g to gcrash - MOVD $runtime·gcrash(SB), g // g = &gcrash - BL runtime·save_g(SB) // clobbers R0 - MOVD R1, g_m(g) // g.m = curm - MOVD g, m_g0(R1) // curm.g0 = g - - // switch to crashstack - MOVD (g_stack+stack_hi)(g), R1 - SUB $(4*8), R1 - MOVD R1, RSP - - // call target function - MOVD 0(R26), R0 - CALL (R0) - - // should never return - CALL runtime·abort(SB) - UNDEF - -/* - * support for morestack - */ - -// Called during function prolog when more stack is needed. -// Caller has already loaded: -// R3 prolog's LR (R30) -// -// The traceback routines see morestack on a g0 as being -// the top of a stack (for example, morestack calling newstack -// calling the scheduler calling newm calling gc), so we must -// record an argument size. For that purpose, it has no arguments. -TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 - // Cannot grow scheduler stack (m->g0). - MOVD g_m(g), R8 - MOVD m_g0(R8), R4 - - // Called from f. - // Set g->sched to context in f - MOVD RSP, R0 - MOVD R0, (g_sched+gobuf_sp)(g) - MOVD R29, (g_sched+gobuf_bp)(g) - MOVD LR, (g_sched+gobuf_pc)(g) - MOVD R3, (g_sched+gobuf_lr)(g) - MOVD R26, (g_sched+gobuf_ctxt)(g) - - CMP g, R4 - BNE 3(PC) - BL runtime·badmorestackg0(SB) - B runtime·abort(SB) - - // Cannot grow signal stack (m->gsignal). - MOVD m_gsignal(R8), R4 - CMP g, R4 - BNE 3(PC) - BL runtime·badmorestackgsignal(SB) - B runtime·abort(SB) - - // Called from f. - // Set m->morebuf to f's callers. - MOVD R3, (m_morebuf+gobuf_pc)(R8) // f's caller's PC - MOVD RSP, R0 - MOVD R0, (m_morebuf+gobuf_sp)(R8) // f's caller's RSP - MOVD g, (m_morebuf+gobuf_g)(R8) - - // Call newstack on m->g0's stack. - MOVD m_g0(R8), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R0 - MOVD R0, RSP - MOVD (g_sched+gobuf_bp)(g), R29 - MOVD.W $0, -16(RSP) // create a call frame on g0 (saved LR; keep 16-aligned) - BL runtime·newstack(SB) - - // Not reached, but make sure the return PC from the call to newstack - // is still in this function, and not the beginning of the next. - UNDEF - -TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 - // Force SPWRITE. This function doesn't actually write SP, - // but it is called with a special calling convention where - // the caller doesn't save LR on stack but passes it as a - // register (R3), and the unwinder currently doesn't understand. - // Make it SPWRITE to stop unwinding. (See issue 54332) - MOVD RSP, RSP - - MOVW $0, R26 - B runtime·morestack(SB) - -// spillArgs stores return values from registers to a *internal/abi.RegArgs in R20. -TEXT ·spillArgs(SB),NOSPLIT,$0-0 - STP (R0, R1), (0*8)(R20) - STP (R2, R3), (2*8)(R20) - STP (R4, R5), (4*8)(R20) - STP (R6, R7), (6*8)(R20) - STP (R8, R9), (8*8)(R20) - STP (R10, R11), (10*8)(R20) - STP (R12, R13), (12*8)(R20) - STP (R14, R15), (14*8)(R20) - FSTPD (F0, F1), (16*8)(R20) - FSTPD (F2, F3), (18*8)(R20) - FSTPD (F4, F5), (20*8)(R20) - FSTPD (F6, F7), (22*8)(R20) - FSTPD (F8, F9), (24*8)(R20) - FSTPD (F10, F11), (26*8)(R20) - FSTPD (F12, F13), (28*8)(R20) - FSTPD (F14, F15), (30*8)(R20) - RET - -// unspillArgs loads args into registers from a *internal/abi.RegArgs in R20. -TEXT ·unspillArgs(SB),NOSPLIT,$0-0 - LDP (0*8)(R20), (R0, R1) - LDP (2*8)(R20), (R2, R3) - LDP (4*8)(R20), (R4, R5) - LDP (6*8)(R20), (R6, R7) - LDP (8*8)(R20), (R8, R9) - LDP (10*8)(R20), (R10, R11) - LDP (12*8)(R20), (R12, R13) - LDP (14*8)(R20), (R14, R15) - FLDPD (16*8)(R20), (F0, F1) - FLDPD (18*8)(R20), (F2, F3) - FLDPD (20*8)(R20), (F4, F5) - FLDPD (22*8)(R20), (F6, F7) - FLDPD (24*8)(R20), (F8, F9) - FLDPD (26*8)(R20), (F10, F11) - FLDPD (28*8)(R20), (F12, F13) - FLDPD (30*8)(R20), (F14, F15) - RET - -// reflectcall: call a function with the given argument list -// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). -// we don't have variable-sized frames, so we use a small number -// of constant-sized-frame functions to encode a few bits of size in the pc. -// Caution: ugly multiline assembly macros in your future! - -#define DISPATCH(NAME,MAXSIZE) \ - MOVD $MAXSIZE, R27; \ - CMP R27, R16; \ - BGT 3(PC); \ - MOVD $NAME(SB), R27; \ - B (R27) -// Note: can't just "B NAME(SB)" - bad inlining results. - -TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-48 - MOVWU frameSize+32(FP), R16 - DISPATCH(runtime·call16, 16) - DISPATCH(runtime·call32, 32) - DISPATCH(runtime·call64, 64) - DISPATCH(runtime·call128, 128) - DISPATCH(runtime·call256, 256) - DISPATCH(runtime·call512, 512) - DISPATCH(runtime·call1024, 1024) - DISPATCH(runtime·call2048, 2048) - DISPATCH(runtime·call4096, 4096) - DISPATCH(runtime·call8192, 8192) - DISPATCH(runtime·call16384, 16384) - DISPATCH(runtime·call32768, 32768) - DISPATCH(runtime·call65536, 65536) - DISPATCH(runtime·call131072, 131072) - DISPATCH(runtime·call262144, 262144) - DISPATCH(runtime·call524288, 524288) - DISPATCH(runtime·call1048576, 1048576) - DISPATCH(runtime·call2097152, 2097152) - DISPATCH(runtime·call4194304, 4194304) - DISPATCH(runtime·call8388608, 8388608) - DISPATCH(runtime·call16777216, 16777216) - DISPATCH(runtime·call33554432, 33554432) - DISPATCH(runtime·call67108864, 67108864) - DISPATCH(runtime·call134217728, 134217728) - DISPATCH(runtime·call268435456, 268435456) - DISPATCH(runtime·call536870912, 536870912) - DISPATCH(runtime·call1073741824, 1073741824) - MOVD $runtime·badreflectcall(SB), R0 - B (R0) - -#define CALLFN(NAME,MAXSIZE) \ -TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ - NO_LOCAL_POINTERS; \ - /* copy arguments to stack */ \ - MOVD stackArgs+16(FP), R3; \ - MOVWU stackArgsSize+24(FP), R4; \ - ADD $8, RSP, R5; \ - BIC $0xf, R4, R6; \ - CBZ R6, 6(PC); \ - /* if R6=(argsize&~15) != 0 */ \ - ADD R6, R5, R6; \ - /* copy 16 bytes a time */ \ - LDP.P 16(R3), (R7, R8); \ - STP.P (R7, R8), 16(R5); \ - CMP R5, R6; \ - BNE -3(PC); \ - AND $0xf, R4, R6; \ - CBZ R6, 6(PC); \ - /* if R6=(argsize&15) != 0 */ \ - ADD R6, R5, R6; \ - /* copy 1 byte a time for the rest */ \ - MOVBU.P 1(R3), R7; \ - MOVBU.P R7, 1(R5); \ - CMP R5, R6; \ - BNE -3(PC); \ - /* set up argument registers */ \ - MOVD regArgs+40(FP), R20; \ - CALL ·unspillArgs(SB); \ - /* call function */ \ - MOVD f+8(FP), R26; \ - MOVD (R26), R20; \ - PCDATA $PCDATA_StackMapIndex, $0; \ - BL (R20); \ - /* copy return values back */ \ - MOVD regArgs+40(FP), R20; \ - CALL ·spillArgs(SB); \ - MOVD stackArgsType+0(FP), R7; \ - MOVD stackArgs+16(FP), R3; \ - MOVWU stackArgsSize+24(FP), R4; \ - MOVWU stackRetOffset+28(FP), R6; \ - ADD $8, RSP, R5; \ - ADD R6, R5; \ - ADD R6, R3; \ - SUB R6, R4; \ - BL callRet<>(SB); \ - RET - -// callRet copies return values back at the end of call*. This is a -// separate function so it can allocate stack space for the arguments -// to reflectcallmove. It does not follow the Go ABI; it expects its -// arguments in registers. -TEXT callRet<>(SB), NOSPLIT, $48-0 - NO_LOCAL_POINTERS - STP (R7, R3), 8(RSP) - STP (R5, R4), 24(RSP) - MOVD R20, 40(RSP) - BL runtime·reflectcallmove(SB) - RET - -CALLFN(·call16, 16) -CALLFN(·call32, 32) -CALLFN(·call64, 64) -CALLFN(·call128, 128) -CALLFN(·call256, 256) -CALLFN(·call512, 512) -CALLFN(·call1024, 1024) -CALLFN(·call2048, 2048) -CALLFN(·call4096, 4096) -CALLFN(·call8192, 8192) -CALLFN(·call16384, 16384) -CALLFN(·call32768, 32768) -CALLFN(·call65536, 65536) -CALLFN(·call131072, 131072) -CALLFN(·call262144, 262144) -CALLFN(·call524288, 524288) -CALLFN(·call1048576, 1048576) -CALLFN(·call2097152, 2097152) -CALLFN(·call4194304, 4194304) -CALLFN(·call8388608, 8388608) -CALLFN(·call16777216, 16777216) -CALLFN(·call33554432, 33554432) -CALLFN(·call67108864, 67108864) -CALLFN(·call134217728, 134217728) -CALLFN(·call268435456, 268435456) -CALLFN(·call536870912, 536870912) -CALLFN(·call1073741824, 1073741824) - -// func memhash32(p unsafe.Pointer, h uintptr) uintptr -TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 - MOVB runtime·useAeshash(SB), R10 - CBZ R10, noaes - MOVD $runtime·aeskeysched+0(SB), R3 - - VEOR V0.B16, V0.B16, V0.B16 - VLD1 (R3), [V2.B16] - VLD1 (R0), V0.S[1] - VMOV R1, V0.S[0] - - AESE V2.B16, V0.B16 - AESMC V0.B16, V0.B16 - AESE V2.B16, V0.B16 - AESMC V0.B16, V0.B16 - AESE V2.B16, V0.B16 - - VMOV V0.D[0], R0 - RET -noaes: - B runtime·memhash32Fallback(SB) - -// func memhash64(p unsafe.Pointer, h uintptr) uintptr -TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 - MOVB runtime·useAeshash(SB), R10 - CBZ R10, noaes - MOVD $runtime·aeskeysched+0(SB), R3 - - VEOR V0.B16, V0.B16, V0.B16 - VLD1 (R3), [V2.B16] - VLD1 (R0), V0.D[1] - VMOV R1, V0.D[0] - - AESE V2.B16, V0.B16 - AESMC V0.B16, V0.B16 - AESE V2.B16, V0.B16 - AESMC V0.B16, V0.B16 - AESE V2.B16, V0.B16 - - VMOV V0.D[0], R0 - RET -noaes: - B runtime·memhash64Fallback(SB) - -// func memhash(p unsafe.Pointer, h, size uintptr) uintptr -TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 - MOVB runtime·useAeshash(SB), R10 - CBZ R10, noaes - B aeshashbody<>(SB) -noaes: - B runtime·memhashFallback(SB) - -// func strhash(p unsafe.Pointer, h uintptr) uintptr -TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 - MOVB runtime·useAeshash(SB), R10 - CBZ R10, noaes - LDP (R0), (R0, R2) // string data / length - B aeshashbody<>(SB) -noaes: - B runtime·strhashFallback(SB) - -// R0: data -// R1: seed data -// R2: length -// At return, R0 = return value -TEXT aeshashbody<>(SB),NOSPLIT|NOFRAME,$0 - VEOR V30.B16, V30.B16, V30.B16 - VMOV R1, V30.D[0] - VMOV R2, V30.D[1] // load length into seed - - MOVD $runtime·aeskeysched+0(SB), R4 - VLD1.P 16(R4), [V0.B16] - AESE V30.B16, V0.B16 - AESMC V0.B16, V0.B16 - CMP $16, R2 - BLO aes0to15 - BEQ aes16 - CMP $32, R2 - BLS aes17to32 - CMP $64, R2 - BLS aes33to64 - CMP $128, R2 - BLS aes65to128 - B aes129plus - -aes0to15: - CBZ R2, aes0 - VEOR V2.B16, V2.B16, V2.B16 - TBZ $3, R2, less_than_8 - VLD1.P 8(R0), V2.D[0] - -less_than_8: - TBZ $2, R2, less_than_4 - VLD1.P 4(R0), V2.S[2] - -less_than_4: - TBZ $1, R2, less_than_2 - VLD1.P 2(R0), V2.H[6] - -less_than_2: - TBZ $0, R2, done - VLD1 (R0), V2.B[14] -done: - AESE V0.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V0.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V0.B16, V2.B16 - AESMC V2.B16, V2.B16 - - VMOV V2.D[0], R0 - RET - -aes0: - VMOV V0.D[0], R0 - RET - -aes16: - VLD1 (R0), [V2.B16] - B done - -aes17to32: - // make second seed - VLD1 (R4), [V1.B16] - AESE V30.B16, V1.B16 - AESMC V1.B16, V1.B16 - SUB $16, R2, R10 - VLD1.P (R0)(R10), [V2.B16] - VLD1 (R0), [V3.B16] - - AESE V0.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V1.B16, V3.B16 - AESMC V3.B16, V3.B16 - - AESE V0.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V1.B16, V3.B16 - AESMC V3.B16, V3.B16 - - AESE V0.B16, V2.B16 - AESE V1.B16, V3.B16 - - VEOR V3.B16, V2.B16, V2.B16 - - VMOV V2.D[0], R0 - RET - -aes33to64: - VLD1 (R4), [V1.B16, V2.B16, V3.B16] - AESE V30.B16, V1.B16 - AESMC V1.B16, V1.B16 - AESE V30.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V30.B16, V3.B16 - AESMC V3.B16, V3.B16 - SUB $32, R2, R10 - - VLD1.P (R0)(R10), [V4.B16, V5.B16] - VLD1 (R0), [V6.B16, V7.B16] - - AESE V0.B16, V4.B16 - AESMC V4.B16, V4.B16 - AESE V1.B16, V5.B16 - AESMC V5.B16, V5.B16 - AESE V2.B16, V6.B16 - AESMC V6.B16, V6.B16 - AESE V3.B16, V7.B16 - AESMC V7.B16, V7.B16 - - AESE V0.B16, V4.B16 - AESMC V4.B16, V4.B16 - AESE V1.B16, V5.B16 - AESMC V5.B16, V5.B16 - AESE V2.B16, V6.B16 - AESMC V6.B16, V6.B16 - AESE V3.B16, V7.B16 - AESMC V7.B16, V7.B16 - - AESE V0.B16, V4.B16 - AESE V1.B16, V5.B16 - AESE V2.B16, V6.B16 - AESE V3.B16, V7.B16 - - VEOR V6.B16, V4.B16, V4.B16 - VEOR V7.B16, V5.B16, V5.B16 - VEOR V5.B16, V4.B16, V4.B16 - - VMOV V4.D[0], R0 - RET - -aes65to128: - VLD1.P 64(R4), [V1.B16, V2.B16, V3.B16, V4.B16] - VLD1 (R4), [V5.B16, V6.B16, V7.B16] - AESE V30.B16, V1.B16 - AESMC V1.B16, V1.B16 - AESE V30.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V30.B16, V3.B16 - AESMC V3.B16, V3.B16 - AESE V30.B16, V4.B16 - AESMC V4.B16, V4.B16 - AESE V30.B16, V5.B16 - AESMC V5.B16, V5.B16 - AESE V30.B16, V6.B16 - AESMC V6.B16, V6.B16 - AESE V30.B16, V7.B16 - AESMC V7.B16, V7.B16 - - SUB $64, R2, R10 - VLD1.P (R0)(R10), [V8.B16, V9.B16, V10.B16, V11.B16] - VLD1 (R0), [V12.B16, V13.B16, V14.B16, V15.B16] - AESE V0.B16, V8.B16 - AESMC V8.B16, V8.B16 - AESE V1.B16, V9.B16 - AESMC V9.B16, V9.B16 - AESE V2.B16, V10.B16 - AESMC V10.B16, V10.B16 - AESE V3.B16, V11.B16 - AESMC V11.B16, V11.B16 - AESE V4.B16, V12.B16 - AESMC V12.B16, V12.B16 - AESE V5.B16, V13.B16 - AESMC V13.B16, V13.B16 - AESE V6.B16, V14.B16 - AESMC V14.B16, V14.B16 - AESE V7.B16, V15.B16 - AESMC V15.B16, V15.B16 - - AESE V0.B16, V8.B16 - AESMC V8.B16, V8.B16 - AESE V1.B16, V9.B16 - AESMC V9.B16, V9.B16 - AESE V2.B16, V10.B16 - AESMC V10.B16, V10.B16 - AESE V3.B16, V11.B16 - AESMC V11.B16, V11.B16 - AESE V4.B16, V12.B16 - AESMC V12.B16, V12.B16 - AESE V5.B16, V13.B16 - AESMC V13.B16, V13.B16 - AESE V6.B16, V14.B16 - AESMC V14.B16, V14.B16 - AESE V7.B16, V15.B16 - AESMC V15.B16, V15.B16 - - AESE V0.B16, V8.B16 - AESE V1.B16, V9.B16 - AESE V2.B16, V10.B16 - AESE V3.B16, V11.B16 - AESE V4.B16, V12.B16 - AESE V5.B16, V13.B16 - AESE V6.B16, V14.B16 - AESE V7.B16, V15.B16 - - VEOR V12.B16, V8.B16, V8.B16 - VEOR V13.B16, V9.B16, V9.B16 - VEOR V14.B16, V10.B16, V10.B16 - VEOR V15.B16, V11.B16, V11.B16 - VEOR V10.B16, V8.B16, V8.B16 - VEOR V11.B16, V9.B16, V9.B16 - VEOR V9.B16, V8.B16, V8.B16 - - VMOV V8.D[0], R0 - RET - -aes129plus: - PRFM (R0), PLDL1KEEP - VLD1.P 64(R4), [V1.B16, V2.B16, V3.B16, V4.B16] - VLD1 (R4), [V5.B16, V6.B16, V7.B16] - AESE V30.B16, V1.B16 - AESMC V1.B16, V1.B16 - AESE V30.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V30.B16, V3.B16 - AESMC V3.B16, V3.B16 - AESE V30.B16, V4.B16 - AESMC V4.B16, V4.B16 - AESE V30.B16, V5.B16 - AESMC V5.B16, V5.B16 - AESE V30.B16, V6.B16 - AESMC V6.B16, V6.B16 - AESE V30.B16, V7.B16 - AESMC V7.B16, V7.B16 - ADD R0, R2, R10 - SUB $128, R10, R10 - VLD1.P 64(R10), [V8.B16, V9.B16, V10.B16, V11.B16] - VLD1 (R10), [V12.B16, V13.B16, V14.B16, V15.B16] - SUB $1, R2, R2 - LSR $7, R2, R2 - -aesloop: - AESE V8.B16, V0.B16 - AESMC V0.B16, V0.B16 - AESE V9.B16, V1.B16 - AESMC V1.B16, V1.B16 - AESE V10.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V11.B16, V3.B16 - AESMC V3.B16, V3.B16 - AESE V12.B16, V4.B16 - AESMC V4.B16, V4.B16 - AESE V13.B16, V5.B16 - AESMC V5.B16, V5.B16 - AESE V14.B16, V6.B16 - AESMC V6.B16, V6.B16 - AESE V15.B16, V7.B16 - AESMC V7.B16, V7.B16 - - VLD1.P 64(R0), [V8.B16, V9.B16, V10.B16, V11.B16] - AESE V8.B16, V0.B16 - AESMC V0.B16, V0.B16 - AESE V9.B16, V1.B16 - AESMC V1.B16, V1.B16 - AESE V10.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V11.B16, V3.B16 - AESMC V3.B16, V3.B16 - - VLD1.P 64(R0), [V12.B16, V13.B16, V14.B16, V15.B16] - AESE V12.B16, V4.B16 - AESMC V4.B16, V4.B16 - AESE V13.B16, V5.B16 - AESMC V5.B16, V5.B16 - AESE V14.B16, V6.B16 - AESMC V6.B16, V6.B16 - AESE V15.B16, V7.B16 - AESMC V7.B16, V7.B16 - SUB $1, R2, R2 - CBNZ R2, aesloop - - AESE V8.B16, V0.B16 - AESMC V0.B16, V0.B16 - AESE V9.B16, V1.B16 - AESMC V1.B16, V1.B16 - AESE V10.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V11.B16, V3.B16 - AESMC V3.B16, V3.B16 - AESE V12.B16, V4.B16 - AESMC V4.B16, V4.B16 - AESE V13.B16, V5.B16 - AESMC V5.B16, V5.B16 - AESE V14.B16, V6.B16 - AESMC V6.B16, V6.B16 - AESE V15.B16, V7.B16 - AESMC V7.B16, V7.B16 - - AESE V8.B16, V0.B16 - AESMC V0.B16, V0.B16 - AESE V9.B16, V1.B16 - AESMC V1.B16, V1.B16 - AESE V10.B16, V2.B16 - AESMC V2.B16, V2.B16 - AESE V11.B16, V3.B16 - AESMC V3.B16, V3.B16 - AESE V12.B16, V4.B16 - AESMC V4.B16, V4.B16 - AESE V13.B16, V5.B16 - AESMC V5.B16, V5.B16 - AESE V14.B16, V6.B16 - AESMC V6.B16, V6.B16 - AESE V15.B16, V7.B16 - AESMC V7.B16, V7.B16 - - AESE V8.B16, V0.B16 - AESE V9.B16, V1.B16 - AESE V10.B16, V2.B16 - AESE V11.B16, V3.B16 - AESE V12.B16, V4.B16 - AESE V13.B16, V5.B16 - AESE V14.B16, V6.B16 - AESE V15.B16, V7.B16 - - VEOR V0.B16, V1.B16, V0.B16 - VEOR V2.B16, V3.B16, V2.B16 - VEOR V4.B16, V5.B16, V4.B16 - VEOR V6.B16, V7.B16, V6.B16 - VEOR V0.B16, V2.B16, V0.B16 - VEOR V4.B16, V6.B16, V4.B16 - VEOR V4.B16, V0.B16, V0.B16 - - VMOV V0.D[0], R0 - RET - -TEXT runtime·procyield(SB),NOSPLIT,$0-0 - MOVWU cycles+0(FP), R0 -again: - YIELD - SUBW $1, R0 - CBNZ R0, again - RET - -// Save state of caller into g->sched, -// but using fake PC from systemstack_switch. -// Must only be called from functions with no locals ($0) -// or else unwinding from systemstack_switch is incorrect. -// Smashes R0. -TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 - MOVD $runtime·systemstack_switch(SB), R0 - ADD $8, R0 // get past prologue - MOVD R0, (g_sched+gobuf_pc)(g) - MOVD RSP, R0 - MOVD R0, (g_sched+gobuf_sp)(g) - MOVD R29, (g_sched+gobuf_bp)(g) - MOVD $0, (g_sched+gobuf_lr)(g) - MOVD $0, (g_sched+gobuf_ret)(g) - // Assert ctxt is zero. See func save. - MOVD (g_sched+gobuf_ctxt)(g), R0 - CBZ R0, 2(PC) - CALL runtime·abort(SB) - RET - -// func asmcgocall_no_g(fn, arg unsafe.Pointer) -// Call fn(arg) aligned appropriately for the gcc ABI. -// Called on a system stack, and there may be no g yet (during needm). -TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16 - MOVD fn+0(FP), R1 - MOVD arg+8(FP), R0 - SUB $16, RSP // skip over saved frame pointer below RSP - BL (R1) - ADD $16, RSP // skip over saved frame pointer below RSP - RET - -// func asmcgocall(fn, arg unsafe.Pointer) int32 -// Call fn(arg) on the scheduler stack, -// aligned appropriately for the gcc ABI. -// See cgocall.go for more details. -TEXT ·asmcgocall(SB),NOSPLIT,$0-20 - MOVD fn+0(FP), R1 - MOVD arg+8(FP), R0 - - MOVD RSP, R2 // save original stack pointer - CBZ g, nosave - MOVD g, R4 - - // Figure out if we need to switch to m->g0 stack. - // We get called to create new OS threads too, and those - // come in on the m->g0 stack already. Or we might already - // be on the m->gsignal stack. - MOVD g_m(g), R8 - MOVD m_gsignal(R8), R3 - CMP R3, g - BEQ nosave - MOVD m_g0(R8), R3 - CMP R3, g - BEQ nosave - - // Switch to system stack. - MOVD R0, R9 // gosave_systemstack_switch<> and save_g might clobber R0 - BL gosave_systemstack_switch<>(SB) - MOVD R3, g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R0 - MOVD R0, RSP - MOVD (g_sched+gobuf_bp)(g), R29 - MOVD R9, R0 - - // Now on a scheduling stack (a pthread-created stack). - // Save room for two of our pointers /*, plus 32 bytes of callee - // save area that lives on the caller stack. */ - MOVD RSP, R13 - SUB $16, R13 - MOVD R13, RSP - MOVD R4, 0(RSP) // save old g on stack - MOVD (g_stack+stack_hi)(R4), R4 - SUB R2, R4 - MOVD R4, 8(RSP) // save depth in old g stack (can't just save SP, as stack might be copied during a callback) - BL (R1) - MOVD R0, R9 - - // Restore g, stack pointer. R0 is errno, so don't touch it - MOVD 0(RSP), g - BL runtime·save_g(SB) - MOVD (g_stack+stack_hi)(g), R5 - MOVD 8(RSP), R6 - SUB R6, R5 - MOVD R9, R0 - MOVD R5, RSP - - MOVW R0, ret+16(FP) - RET - -nosave: - // Running on a system stack, perhaps even without a g. - // Having no g can happen during thread creation or thread teardown - // (see needm/dropm on Solaris, for example). - // This code is like the above sequence but without saving/restoring g - // and without worrying about the stack moving out from under us - // (because we're on a system stack, not a goroutine stack). - // The above code could be used directly if already on a system stack, - // but then the only path through this code would be a rare case on Solaris. - // Using this code for all "already on system stack" calls exercises it more, - // which should help keep it correct. - MOVD RSP, R13 - SUB $16, R13 - MOVD R13, RSP - MOVD $0, R4 - MOVD R4, 0(RSP) // Where above code stores g, in case someone looks during debugging. - MOVD R2, 8(RSP) // Save original stack pointer. - BL (R1) - // Restore stack pointer. - MOVD 8(RSP), R2 - MOVD R2, RSP - MOVD R0, ret+16(FP) - RET - -// cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) -// See cgocall.go for more details. -TEXT ·cgocallback(SB),NOSPLIT,$24-24 - NO_LOCAL_POINTERS - - // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. - // It is used to dropm while thread is exiting. - MOVD fn+0(FP), R1 - CBNZ R1, loadg - // Restore the g from frame. - MOVD frame+8(FP), g - B dropm - -loadg: - // Load g from thread-local storage. - BL runtime·load_g(SB) - - // If g is nil, Go did not create the current thread, - // or if this thread never called into Go on pthread platforms. - // Call needm to obtain one for temporary use. - // In this case, we're running on the thread stack, so there's - // lots of space, but the linker doesn't know. Hide the call from - // the linker analysis by using an indirect call. - CBZ g, needm - - MOVD g_m(g), R8 - MOVD R8, savedm-8(SP) - B havem - -needm: - MOVD g, savedm-8(SP) // g is zero, so is m. - MOVD $runtime·needAndBindM(SB), R0 - BL (R0) - - // Set m->g0->sched.sp = SP, so that if a panic happens - // during the function we are about to execute, it will - // have a valid SP to run on the g0 stack. - // The next few lines (after the havem label) - // will save this SP onto the stack and then write - // the same SP back to m->sched.sp. That seems redundant, - // but if an unrecovered panic happens, unwindm will - // restore the g->sched.sp from the stack location - // and then systemstack will try to use it. If we don't set it here, - // that restored SP will be uninitialized (typically 0) and - // will not be usable. - MOVD g_m(g), R8 - MOVD m_g0(R8), R3 - MOVD RSP, R0 - MOVD R0, (g_sched+gobuf_sp)(R3) - MOVD R29, (g_sched+gobuf_bp)(R3) - -havem: - // Now there's a valid m, and we're running on its m->g0. - // Save current m->g0->sched.sp on stack and then set it to SP. - // Save current sp in m->g0->sched.sp in preparation for - // switch back to m->curg stack. - // NOTE: unwindm knows that the saved g->sched.sp is at 16(RSP) aka savedsp-16(SP). - // Beware that the frame size is actually 32+16. - MOVD m_g0(R8), R3 - MOVD (g_sched+gobuf_sp)(R3), R4 - MOVD R4, savedsp-16(SP) - MOVD RSP, R0 - MOVD R0, (g_sched+gobuf_sp)(R3) - - // Switch to m->curg stack and call runtime.cgocallbackg. - // Because we are taking over the execution of m->curg - // but *not* resuming what had been running, we need to - // save that information (m->curg->sched) so we can restore it. - // We can restore m->curg->sched.sp easily, because calling - // runtime.cgocallbackg leaves SP unchanged upon return. - // To save m->curg->sched.pc, we push it onto the curg stack and - // open a frame the same size as cgocallback's g0 frame. - // Once we switch to the curg stack, the pushed PC will appear - // to be the return PC of cgocallback, so that the traceback - // will seamlessly trace back into the earlier calls. - MOVD m_curg(R8), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 - MOVD (g_sched+gobuf_pc)(g), R5 - MOVD R5, -48(R4) - MOVD (g_sched+gobuf_bp)(g), R5 - MOVD R5, -56(R4) - // Gather our arguments into registers. - MOVD fn+0(FP), R1 - MOVD frame+8(FP), R2 - MOVD ctxt+16(FP), R3 - MOVD $-48(R4), R0 // maintain 16-byte SP alignment - MOVD R0, RSP // switch stack - MOVD R1, 8(RSP) - MOVD R2, 16(RSP) - MOVD R3, 24(RSP) - MOVD $runtime·cgocallbackg(SB), R0 - CALL (R0) // indirect call to bypass nosplit check. We're on a different stack now. - - // Restore g->sched (== m->curg->sched) from saved values. - MOVD 0(RSP), R5 - MOVD R5, (g_sched+gobuf_pc)(g) - MOVD RSP, R4 - ADD $48, R4, R4 - MOVD R4, (g_sched+gobuf_sp)(g) - - // Switch back to m->g0's stack and restore m->g0->sched.sp. - // (Unlike m->curg, the g0 goroutine never uses sched.pc, - // so we do not have to restore it.) - MOVD g_m(g), R8 - MOVD m_g0(R8), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R0 - MOVD R0, RSP - MOVD savedsp-16(SP), R4 - MOVD R4, (g_sched+gobuf_sp)(g) - - // If the m on entry was nil, we called needm above to borrow an m, - // 1. for the duration of the call on non-pthread platforms, - // 2. or the duration of the C thread alive on pthread platforms. - // If the m on entry wasn't nil, - // 1. the thread might be a Go thread, - // 2. or it wasn't the first call from a C thread on pthread platforms, - // since then we skip dropm to reuse the m in the first call. - MOVD savedm-8(SP), R6 - CBNZ R6, droppedm - - // Skip dropm to reuse it in the next call, when a pthread key has been created. - MOVD _cgo_pthread_key_created(SB), R6 - // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. - CBZ R6, dropm - MOVD (R6), R6 - CBNZ R6, droppedm - -dropm: - MOVD $runtime·dropm(SB), R0 - BL (R0) -droppedm: - - // Done! - RET - -// Called from cgo wrappers, this function returns g->m->curg.stack.hi. -// Must obey the gcc calling convention. -TEXT _cgo_topofstack(SB),NOSPLIT,$24 - // g (R28) and REGTMP (R27) might be clobbered by load_g. They - // are callee-save in the gcc calling convention, so save them. - MOVD R27, savedR27-8(SP) - MOVD g, saveG-16(SP) - - BL runtime·load_g(SB) - MOVD g_m(g), R0 - MOVD m_curg(R0), R0 - MOVD (g_stack+stack_hi)(R0), R0 - - MOVD saveG-16(SP), g - MOVD savedR28-8(SP), R27 - RET - -// void setg(G*); set g. for use by needm. -TEXT runtime·setg(SB), NOSPLIT, $0-8 - MOVD gg+0(FP), g - // This only happens if iscgo, so jump straight to save_g - BL runtime·save_g(SB) - RET - -// void setg_gcc(G*); set g called from gcc -TEXT setg_gcc<>(SB),NOSPLIT,$8 - MOVD R0, g - MOVD R27, savedR27-8(SP) - BL runtime·save_g(SB) - MOVD savedR27-8(SP), R27 - RET - -TEXT runtime·emptyfunc(SB),0,$0-0 - RET - -TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 - MOVD ZR, R0 - MOVD (R0), R0 - UNDEF - -TEXT runtime·return0(SB), NOSPLIT, $0 - MOVW $0, R0 - RET - -// The top-most function running on a goroutine -// returns to goexit+PCQuantum. -TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 - MOVD R0, R0 // NOP - BL runtime·goexit1(SB) // does not return - -// This is called from .init_array and follows the platform, not Go, ABI. -TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 - SUB $0x10, RSP - MOVD R27, 8(RSP) // The access to global variables below implicitly uses R27, which is callee-save - MOVD runtime·lastmoduledatap(SB), R1 - MOVD R0, moduledata_next(R1) - MOVD R0, runtime·lastmoduledatap(SB) - MOVD 8(RSP), R27 - ADD $0x10, RSP - RET - -TEXT ·checkASM(SB),NOSPLIT,$0-1 - MOVW $1, R3 - MOVB R3, ret+0(FP) - RET - -// gcWriteBarrier informs the GC about heap pointer writes. -// -// gcWriteBarrier does NOT follow the Go ABI. It accepts the -// number of bytes of buffer needed in R25, and returns a pointer -// to the buffer space in R25. -// It clobbers condition codes. -// It does not clobber any general-purpose registers except R27, -// but may clobber others (e.g., floating point registers) -// The act of CALLing gcWriteBarrier will clobber R30 (LR). -TEXT gcWriteBarrier<>(SB),NOSPLIT,$200 - // Save the registers clobbered by the fast path. - STP (R0, R1), 184(RSP) -retry: - MOVD g_m(g), R0 - MOVD m_p(R0), R0 - MOVD (p_wbBuf+wbBuf_next)(R0), R1 - MOVD (p_wbBuf+wbBuf_end)(R0), R27 - // Increment wbBuf.next position. - ADD R25, R1 - // Is the buffer full? - CMP R27, R1 - BHI flush - // Commit to the larger buffer. - MOVD R1, (p_wbBuf+wbBuf_next)(R0) - // Make return value (the original next position) - SUB R25, R1, R25 - // Restore registers. - LDP 184(RSP), (R0, R1) - RET - -flush: - // Save all general purpose registers since these could be - // clobbered by wbBufFlush and were not saved by the caller. - // R0 and R1 already saved - STP (R2, R3), 1*8(RSP) - STP (R4, R5), 3*8(RSP) - STP (R6, R7), 5*8(RSP) - STP (R8, R9), 7*8(RSP) - STP (R10, R11), 9*8(RSP) - STP (R12, R13), 11*8(RSP) - STP (R14, R15), 13*8(RSP) - // R16, R17 may be clobbered by linker trampoline - // R18 is unused. - STP (R19, R20), 15*8(RSP) - STP (R21, R22), 17*8(RSP) - STP (R23, R24), 19*8(RSP) - STP (R25, R26), 21*8(RSP) - // R27 is temp register. - // R28 is g. - // R29 is frame pointer (unused). - // R30 is LR, which was saved by the prologue. - // R31 is SP. - - CALL runtime·wbBufFlush(SB) - LDP 1*8(RSP), (R2, R3) - LDP 3*8(RSP), (R4, R5) - LDP 5*8(RSP), (R6, R7) - LDP 7*8(RSP), (R8, R9) - LDP 9*8(RSP), (R10, R11) - LDP 11*8(RSP), (R12, R13) - LDP 13*8(RSP), (R14, R15) - LDP 15*8(RSP), (R19, R20) - LDP 17*8(RSP), (R21, R22) - LDP 19*8(RSP), (R23, R24) - LDP 21*8(RSP), (R25, R26) - JMP retry - -TEXT runtime·gcWriteBarrier1(SB),NOSPLIT,$0 - MOVD $8, R25 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier2(SB),NOSPLIT,$0 - MOVD $16, R25 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier3(SB),NOSPLIT,$0 - MOVD $24, R25 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier4(SB),NOSPLIT,$0 - MOVD $32, R25 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier5(SB),NOSPLIT,$0 - MOVD $40, R25 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier6(SB),NOSPLIT,$0 - MOVD $48, R25 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier7(SB),NOSPLIT,$0 - MOVD $56, R25 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier8(SB),NOSPLIT,$0 - MOVD $64, R25 - JMP gcWriteBarrier<>(SB) - -DATA debugCallFrameTooLarge<>+0x00(SB)/20, $"call frame too large" -GLOBL debugCallFrameTooLarge<>(SB), RODATA, $20 // Size duplicated below - -// debugCallV2 is the entry point for debugger-injected function -// calls on running goroutines. It informs the runtime that a -// debug call has been injected and creates a call frame for the -// debugger to fill in. -// -// To inject a function call, a debugger should: -// 1. Check that the goroutine is in state _Grunning and that -// there are at least 288 bytes free on the stack. -// 2. Set SP as SP-16. -// 3. Store the current LR in (SP) (using the SP after step 2). -// 4. Store the current PC in the LR register. -// 5. Write the desired argument frame size at SP-16 -// 6. Save all machine registers (including flags and fpsimd registers) -// so they can be restored later by the debugger. -// 7. Set the PC to debugCallV2 and resume execution. -// -// If the goroutine is in state _Grunnable, then it's not generally -// safe to inject a call because it may return out via other runtime -// operations. Instead, the debugger should unwind the stack to find -// the return to non-runtime code, add a temporary breakpoint there, -// and inject the call once that breakpoint is hit. -// -// If the goroutine is in any other state, it's not safe to inject a call. -// -// This function communicates back to the debugger by setting R20 and -// invoking BRK to raise a breakpoint signal. Note that the signal PC of -// the signal triggered by the BRK instruction is the PC where the signal -// is trapped, not the next PC, so to resume execution, the debugger needs -// to set the signal PC to PC+4. See the comments in the implementation for -// the protocol the debugger is expected to follow. InjectDebugCall in the -// runtime tests demonstrates this protocol. -// -// The debugger must ensure that any pointers passed to the function -// obey escape analysis requirements. Specifically, it must not pass -// a stack pointer to an escaping argument. debugCallV2 cannot check -// this invariant. -// -// This is ABIInternal because Go code injects its PC directly into new -// goroutine stacks. -TEXT runtime·debugCallV2(SB),NOSPLIT|NOFRAME,$0-0 - STP (R29, R30), -280(RSP) - SUB $272, RSP, RSP - SUB $8, RSP, R29 - // Save all registers that may contain pointers so they can be - // conservatively scanned. - // - // We can't do anything that might clobber any of these - // registers before this. - STP (R27, g), (30*8)(RSP) - STP (R25, R26), (28*8)(RSP) - STP (R23, R24), (26*8)(RSP) - STP (R21, R22), (24*8)(RSP) - STP (R19, R20), (22*8)(RSP) - STP (R16, R17), (20*8)(RSP) - STP (R14, R15), (18*8)(RSP) - STP (R12, R13), (16*8)(RSP) - STP (R10, R11), (14*8)(RSP) - STP (R8, R9), (12*8)(RSP) - STP (R6, R7), (10*8)(RSP) - STP (R4, R5), (8*8)(RSP) - STP (R2, R3), (6*8)(RSP) - STP (R0, R1), (4*8)(RSP) - - // Perform a safe-point check. - MOVD R30, 8(RSP) // Caller's PC - CALL runtime·debugCallCheck(SB) - MOVD 16(RSP), R0 - CBZ R0, good - - // The safety check failed. Put the reason string at the top - // of the stack. - MOVD R0, 8(RSP) - MOVD 24(RSP), R0 - MOVD R0, 16(RSP) - - // Set R20 to 8 and invoke BRK. The debugger should get the - // reason a call can't be injected from SP+8 and resume execution. - MOVD $8, R20 - BREAK - JMP restore - -good: - // Registers are saved and it's safe to make a call. - // Open up a call frame, moving the stack if necessary. - // - // Once the frame is allocated, this will set R20 to 0 and - // invoke BRK. The debugger should write the argument - // frame for the call at SP+8, set up argument registers, - // set the LR as the signal PC + 4, set the PC to the function - // to call, set R26 to point to the closure (if a closure call), - // and resume execution. - // - // If the function returns, this will set R20 to 1 and invoke - // BRK. The debugger can then inspect any return value saved - // on the stack at SP+8 and in registers. To resume execution, - // the debugger should restore the LR from (SP). - // - // If the function panics, this will set R20 to 2 and invoke BRK. - // The interface{} value of the panic will be at SP+8. The debugger - // can inspect the panic value and resume execution again. -#define DEBUG_CALL_DISPATCH(NAME,MAXSIZE) \ - CMP $MAXSIZE, R0; \ - BGT 5(PC); \ - MOVD $NAME(SB), R0; \ - MOVD R0, 8(RSP); \ - CALL runtime·debugCallWrap(SB); \ - JMP restore - - MOVD 256(RSP), R0 // the argument frame size - DEBUG_CALL_DISPATCH(debugCall32<>, 32) - DEBUG_CALL_DISPATCH(debugCall64<>, 64) - DEBUG_CALL_DISPATCH(debugCall128<>, 128) - DEBUG_CALL_DISPATCH(debugCall256<>, 256) - DEBUG_CALL_DISPATCH(debugCall512<>, 512) - DEBUG_CALL_DISPATCH(debugCall1024<>, 1024) - DEBUG_CALL_DISPATCH(debugCall2048<>, 2048) - DEBUG_CALL_DISPATCH(debugCall4096<>, 4096) - DEBUG_CALL_DISPATCH(debugCall8192<>, 8192) - DEBUG_CALL_DISPATCH(debugCall16384<>, 16384) - DEBUG_CALL_DISPATCH(debugCall32768<>, 32768) - DEBUG_CALL_DISPATCH(debugCall65536<>, 65536) - // The frame size is too large. Report the error. - MOVD $debugCallFrameTooLarge<>(SB), R0 - MOVD R0, 8(RSP) - MOVD $20, R0 - MOVD R0, 16(RSP) // length of debugCallFrameTooLarge string - MOVD $8, R20 - BREAK - JMP restore - -restore: - // Calls and failures resume here. - // - // Set R20 to 16 and invoke BRK. The debugger should restore - // all registers except for PC and RSP and resume execution. - MOVD $16, R20 - BREAK - // We must not modify flags after this point. - - // Restore pointer-containing registers, which may have been - // modified from the debugger's copy by stack copying. - LDP (30*8)(RSP), (R27, g) - LDP (28*8)(RSP), (R25, R26) - LDP (26*8)(RSP), (R23, R24) - LDP (24*8)(RSP), (R21, R22) - LDP (22*8)(RSP), (R19, R20) - LDP (20*8)(RSP), (R16, R17) - LDP (18*8)(RSP), (R14, R15) - LDP (16*8)(RSP), (R12, R13) - LDP (14*8)(RSP), (R10, R11) - LDP (12*8)(RSP), (R8, R9) - LDP (10*8)(RSP), (R6, R7) - LDP (8*8)(RSP), (R4, R5) - LDP (6*8)(RSP), (R2, R3) - LDP (4*8)(RSP), (R0, R1) - - LDP -8(RSP), (R29, R27) - ADD $288, RSP, RSP // Add 16 more bytes, see saveSigContext - MOVD -16(RSP), R30 // restore old lr - JMP (R27) - -// runtime.debugCallCheck assumes that functions defined with the -// DEBUG_CALL_FN macro are safe points to inject calls. -#define DEBUG_CALL_FN(NAME,MAXSIZE) \ -TEXT NAME(SB),WRAPPER,$MAXSIZE-0; \ - NO_LOCAL_POINTERS; \ - MOVD $0, R20; \ - BREAK; \ - MOVD $1, R20; \ - BREAK; \ - RET -DEBUG_CALL_FN(debugCall32<>, 32) -DEBUG_CALL_FN(debugCall64<>, 64) -DEBUG_CALL_FN(debugCall128<>, 128) -DEBUG_CALL_FN(debugCall256<>, 256) -DEBUG_CALL_FN(debugCall512<>, 512) -DEBUG_CALL_FN(debugCall1024<>, 1024) -DEBUG_CALL_FN(debugCall2048<>, 2048) -DEBUG_CALL_FN(debugCall4096<>, 4096) -DEBUG_CALL_FN(debugCall8192<>, 8192) -DEBUG_CALL_FN(debugCall16384<>, 16384) -DEBUG_CALL_FN(debugCall32768<>, 32768) -DEBUG_CALL_FN(debugCall65536<>, 65536) - -// func debugCallPanicked(val interface{}) -TEXT runtime·debugCallPanicked(SB),NOSPLIT,$16-16 - // Copy the panic value to the top of stack at SP+8. - MOVD val_type+0(FP), R0 - MOVD R0, 8(RSP) - MOVD val_data+8(FP), R0 - MOVD R0, 16(RSP) - MOVD $2, R20 - BREAK - RET - -// Note: these functions use a special calling convention to save generated code space. -// Arguments are passed in registers, but the space for those arguments are allocated -// in the caller's stack frame. These stubs write the args into that stack space and -// then tail call to the corresponding runtime handler. -// The tail call makes these stubs disappear in backtraces. -// -// Defined as ABIInternal since the compiler generates ABIInternal -// calls to it directly and it does not use the stack-based Go ABI. -TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 - JMP runtime·goPanicIndex(SB) -TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 - JMP runtime·goPanicIndexU(SB) -TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 - MOVD R1, R0 - MOVD R2, R1 - JMP runtime·goPanicSliceAlen(SB) -TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 - MOVD R1, R0 - MOVD R2, R1 - JMP runtime·goPanicSliceAlenU(SB) -TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 - MOVD R1, R0 - MOVD R2, R1 - JMP runtime·goPanicSliceAcap(SB) -TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 - MOVD R1, R0 - MOVD R2, R1 - JMP runtime·goPanicSliceAcapU(SB) -TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 - JMP runtime·goPanicSliceB(SB) -TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 - JMP runtime·goPanicSliceBU(SB) -TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 - MOVD R2, R0 - MOVD R3, R1 - JMP runtime·goPanicSlice3Alen(SB) -TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 - MOVD R2, R0 - MOVD R3, R1 - JMP runtime·goPanicSlice3AlenU(SB) -TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 - MOVD R2, R0 - MOVD R3, R1 - JMP runtime·goPanicSlice3Acap(SB) -TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 - MOVD R2, R0 - MOVD R3, R1 - JMP runtime·goPanicSlice3AcapU(SB) -TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 - MOVD R1, R0 - MOVD R2, R1 - JMP runtime·goPanicSlice3B(SB) -TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 - MOVD R1, R0 - MOVD R2, R1 - JMP runtime·goPanicSlice3BU(SB) -TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 - JMP runtime·goPanicSlice3C(SB) -TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 - JMP runtime·goPanicSlice3CU(SB) -TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 - MOVD R2, R0 - MOVD R3, R1 - JMP runtime·goPanicSliceConvert(SB) - -TEXT ·getfp(SB),NOSPLIT|NOFRAME,$0 - MOVD R29, R0 - RET diff --git a/contrib/go/_std_1.22/src/runtime/asm_loong64.s b/contrib/go/_std_1.22/src/runtime/asm_loong64.s deleted file mode 100644 index 586bd23ed478..000000000000 --- a/contrib/go/_std_1.22/src/runtime/asm_loong64.s +++ /dev/null @@ -1,1032 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go_asm.h" -#include "go_tls.h" -#include "funcdata.h" -#include "textflag.h" - -#define REGCTXT R29 - -TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 - // R3 = stack; R4 = argc; R5 = argv - - ADDV $-24, R3 - MOVW R4, 8(R3) // argc - MOVV R5, 16(R3) // argv - - // create istack out of the given (operating system) stack. - // _cgo_init may update stackguard. - MOVV $runtime·g0(SB), g - MOVV $(-64*1024), R30 - ADDV R30, R3, R19 - MOVV R19, g_stackguard0(g) - MOVV R19, g_stackguard1(g) - MOVV R19, (g_stack+stack_lo)(g) - MOVV R3, (g_stack+stack_hi)(g) - - // if there is a _cgo_init, call it using the gcc ABI. - MOVV _cgo_init(SB), R25 - BEQ R25, nocgo - - MOVV R0, R7 // arg 3: not used - MOVV R0, R6 // arg 2: not used - MOVV $setg_gcc<>(SB), R5 // arg 1: setg - MOVV g, R4 // arg 0: G - JAL (R25) - -nocgo: - // update stackguard after _cgo_init - MOVV (g_stack+stack_lo)(g), R19 - ADDV $const_stackGuard, R19 - MOVV R19, g_stackguard0(g) - MOVV R19, g_stackguard1(g) - - // set the per-goroutine and per-mach "registers" - MOVV $runtime·m0(SB), R19 - - // save m->g0 = g0 - MOVV g, m_g0(R19) - // save m0 to g0->m - MOVV R19, g_m(g) - - JAL runtime·check(SB) - - // args are already prepared - JAL runtime·args(SB) - JAL runtime·osinit(SB) - JAL runtime·schedinit(SB) - - // create a new goroutine to start program - MOVV $runtime·mainPC(SB), R19 // entry - ADDV $-16, R3 - MOVV R19, 8(R3) - MOVV R0, 0(R3) - JAL runtime·newproc(SB) - ADDV $16, R3 - - // start this M - JAL runtime·mstart(SB) - - MOVV R0, 1(R0) - RET - -DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) -GLOBL runtime·mainPC(SB),RODATA,$8 - -TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0 - BREAK - RET - -TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0 - RET - -TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 - JAL runtime·mstart0(SB) - RET // not reached - -// func cputicks() int64 -TEXT runtime·cputicks(SB),NOSPLIT,$0-8 - RDTIMED R0, R4 - MOVV R4, ret+0(FP) - RET - -/* - * go-routine - */ - -// void gogo(Gobuf*) -// restore state from Gobuf; longjmp -TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8 - MOVV buf+0(FP), R4 - MOVV gobuf_g(R4), R5 - MOVV 0(R5), R0 // make sure g != nil - JMP gogo<>(SB) - -TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 - MOVV R5, g - JAL runtime·save_g(SB) - - MOVV gobuf_sp(R4), R3 - MOVV gobuf_lr(R4), R1 - MOVV gobuf_ret(R4), R19 - MOVV gobuf_ctxt(R4), REGCTXT - MOVV R0, gobuf_sp(R4) - MOVV R0, gobuf_ret(R4) - MOVV R0, gobuf_lr(R4) - MOVV R0, gobuf_ctxt(R4) - MOVV gobuf_pc(R4), R6 - JMP (R6) - -// void mcall(fn func(*g)) -// Switch to m->g0's stack, call fn(g). -// Fn must never return. It should gogo(&g->sched) -// to keep running g. -TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 -#ifdef GOEXPERIMENT_regabiargs - MOVV R4, REGCTXT -#else - MOVV fn+0(FP), REGCTXT -#endif - - // Save caller state in g->sched - MOVV R3, (g_sched+gobuf_sp)(g) - MOVV R1, (g_sched+gobuf_pc)(g) - MOVV R0, (g_sched+gobuf_lr)(g) - - // Switch to m->g0 & its stack, call fn. - MOVV g, R4 // arg = g - MOVV g_m(g), R20 - MOVV m_g0(R20), g - JAL runtime·save_g(SB) - BNE g, R4, 2(PC) - JMP runtime·badmcall(SB) - MOVV 0(REGCTXT), R20 // code pointer - MOVV (g_sched+gobuf_sp)(g), R3 // sp = m->g0->sched.sp - ADDV $-16, R3 - MOVV R4, 8(R3) - MOVV R0, 0(R3) - JAL (R20) - JMP runtime·badmcall2(SB) - -// systemstack_switch is a dummy routine that systemstack leaves at the bottom -// of the G stack. We need to distinguish the routine that -// lives at the bottom of the G stack from the one that lives -// at the top of the system stack because the one at the top of -// the system stack terminates the stack walk (see topofstack()). -TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 - UNDEF - JAL (R1) // make sure this function is not leaf - RET - -// func systemstack(fn func()) -TEXT runtime·systemstack(SB), NOSPLIT, $0-8 - MOVV fn+0(FP), R19 // R19 = fn - MOVV R19, REGCTXT // context - MOVV g_m(g), R4 // R4 = m - - MOVV m_gsignal(R4), R5 // R5 = gsignal - BEQ g, R5, noswitch - - MOVV m_g0(R4), R5 // R5 = g0 - BEQ g, R5, noswitch - - MOVV m_curg(R4), R6 - BEQ g, R6, switch - - // Bad: g is not gsignal, not g0, not curg. What is it? - // Hide call from linker nosplit analysis. - MOVV $runtime·badsystemstack(SB), R7 - JAL (R7) - JAL runtime·abort(SB) - -switch: - // save our state in g->sched. Pretend to - // be systemstack_switch if the G stack is scanned. - JAL gosave_systemstack_switch<>(SB) - - // switch to g0 - MOVV R5, g - JAL runtime·save_g(SB) - MOVV (g_sched+gobuf_sp)(g), R19 - MOVV R19, R3 - - // call target function - MOVV 0(REGCTXT), R6 // code pointer - JAL (R6) - - // switch back to g - MOVV g_m(g), R4 - MOVV m_curg(R4), g - JAL runtime·save_g(SB) - MOVV (g_sched+gobuf_sp)(g), R3 - MOVV R0, (g_sched+gobuf_sp)(g) - RET - -noswitch: - // already on m stack, just call directly - // Using a tail call here cleans up tracebacks since we won't stop - // at an intermediate systemstack. - MOVV 0(REGCTXT), R4 // code pointer - MOVV 0(R3), R1 // restore LR - ADDV $8, R3 - JMP (R4) - -/* - * support for morestack - */ - -// Called during function prolog when more stack is needed. -// Caller has already loaded: -// loong64: R31: LR -// -// The traceback routines see morestack on a g0 as being -// the top of a stack (for example, morestack calling newstack -// calling the scheduler calling newm calling gc), so we must -// record an argument size. For that purpose, it has no arguments. -TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 - // Cannot grow scheduler stack (m->g0). - MOVV g_m(g), R7 - MOVV m_g0(R7), R8 - BNE g, R8, 3(PC) - JAL runtime·badmorestackg0(SB) - JAL runtime·abort(SB) - - // Cannot grow signal stack (m->gsignal). - MOVV m_gsignal(R7), R8 - BNE g, R8, 3(PC) - JAL runtime·badmorestackgsignal(SB) - JAL runtime·abort(SB) - - // Called from f. - // Set g->sched to context in f. - MOVV R3, (g_sched+gobuf_sp)(g) - MOVV R1, (g_sched+gobuf_pc)(g) - MOVV R31, (g_sched+gobuf_lr)(g) - MOVV REGCTXT, (g_sched+gobuf_ctxt)(g) - - // Called from f. - // Set m->morebuf to f's caller. - MOVV R31, (m_morebuf+gobuf_pc)(R7) // f's caller's PC - MOVV R3, (m_morebuf+gobuf_sp)(R7) // f's caller's SP - MOVV g, (m_morebuf+gobuf_g)(R7) - - // Call newstack on m->g0's stack. - MOVV m_g0(R7), g - JAL runtime·save_g(SB) - MOVV (g_sched+gobuf_sp)(g), R3 - // Create a stack frame on g0 to call newstack. - MOVV R0, -8(R3) // Zero saved LR in frame - ADDV $-8, R3 - JAL runtime·newstack(SB) - - // Not reached, but make sure the return PC from the call to newstack - // is still in this function, and not the beginning of the next. - UNDEF - -TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 - // Force SPWRITE. This function doesn't actually write SP, - // but it is called with a special calling convention where - // the caller doesn't save LR on stack but passes it as a - // register (R5), and the unwinder currently doesn't understand. - // Make it SPWRITE to stop unwinding. (See issue 54332) - MOVV R3, R3 - - MOVV R0, REGCTXT - JMP runtime·morestack(SB) - -// reflectcall: call a function with the given argument list -// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). -// we don't have variable-sized frames, so we use a small number -// of constant-sized-frame functions to encode a few bits of size in the pc. -// Caution: ugly multiline assembly macros in your future! - -#define DISPATCH(NAME,MAXSIZE) \ - MOVV $MAXSIZE, R30; \ - SGTU R19, R30, R30; \ - BNE R30, 3(PC); \ - MOVV $NAME(SB), R4; \ - JMP (R4) -// Note: can't just "BR NAME(SB)" - bad inlining results. - -TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-48 - MOVWU frameSize+32(FP), R19 - DISPATCH(runtime·call32, 32) - DISPATCH(runtime·call64, 64) - DISPATCH(runtime·call128, 128) - DISPATCH(runtime·call256, 256) - DISPATCH(runtime·call512, 512) - DISPATCH(runtime·call1024, 1024) - DISPATCH(runtime·call2048, 2048) - DISPATCH(runtime·call4096, 4096) - DISPATCH(runtime·call8192, 8192) - DISPATCH(runtime·call16384, 16384) - DISPATCH(runtime·call32768, 32768) - DISPATCH(runtime·call65536, 65536) - DISPATCH(runtime·call131072, 131072) - DISPATCH(runtime·call262144, 262144) - DISPATCH(runtime·call524288, 524288) - DISPATCH(runtime·call1048576, 1048576) - DISPATCH(runtime·call2097152, 2097152) - DISPATCH(runtime·call4194304, 4194304) - DISPATCH(runtime·call8388608, 8388608) - DISPATCH(runtime·call16777216, 16777216) - DISPATCH(runtime·call33554432, 33554432) - DISPATCH(runtime·call67108864, 67108864) - DISPATCH(runtime·call134217728, 134217728) - DISPATCH(runtime·call268435456, 268435456) - DISPATCH(runtime·call536870912, 536870912) - DISPATCH(runtime·call1073741824, 1073741824) - MOVV $runtime·badreflectcall(SB), R4 - JMP (R4) - -#define CALLFN(NAME,MAXSIZE) \ -TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ - NO_LOCAL_POINTERS; \ - /* copy arguments to stack */ \ - MOVV arg+16(FP), R4; \ - MOVWU argsize+24(FP), R5; \ - MOVV R3, R12; \ - ADDV $8, R12; \ - ADDV R12, R5; \ - BEQ R12, R5, 6(PC); \ - MOVBU (R4), R6; \ - ADDV $1, R4; \ - MOVBU R6, (R12); \ - ADDV $1, R12; \ - JMP -5(PC); \ - /* set up argument registers */ \ - MOVV regArgs+40(FP), R25; \ - JAL ·unspillArgs(SB); \ - /* call function */ \ - MOVV f+8(FP), REGCTXT; \ - MOVV (REGCTXT), R25; \ - PCDATA $PCDATA_StackMapIndex, $0; \ - JAL (R25); \ - /* copy return values back */ \ - MOVV regArgs+40(FP), R25; \ - JAL ·spillArgs(SB); \ - MOVV argtype+0(FP), R7; \ - MOVV arg+16(FP), R4; \ - MOVWU n+24(FP), R5; \ - MOVWU retoffset+28(FP), R6; \ - ADDV $8, R3, R12; \ - ADDV R6, R12; \ - ADDV R6, R4; \ - SUBVU R6, R5; \ - JAL callRet<>(SB); \ - RET - -// callRet copies return values back at the end of call*. This is a -// separate function so it can allocate stack space for the arguments -// to reflectcallmove. It does not follow the Go ABI; it expects its -// arguments in registers. -TEXT callRet<>(SB), NOSPLIT, $40-0 - NO_LOCAL_POINTERS - MOVV R7, 8(R3) - MOVV R4, 16(R3) - MOVV R12, 24(R3) - MOVV R5, 32(R3) - MOVV R25, 40(R3) - JAL runtime·reflectcallmove(SB) - RET - -CALLFN(·call16, 16) -CALLFN(·call32, 32) -CALLFN(·call64, 64) -CALLFN(·call128, 128) -CALLFN(·call256, 256) -CALLFN(·call512, 512) -CALLFN(·call1024, 1024) -CALLFN(·call2048, 2048) -CALLFN(·call4096, 4096) -CALLFN(·call8192, 8192) -CALLFN(·call16384, 16384) -CALLFN(·call32768, 32768) -CALLFN(·call65536, 65536) -CALLFN(·call131072, 131072) -CALLFN(·call262144, 262144) -CALLFN(·call524288, 524288) -CALLFN(·call1048576, 1048576) -CALLFN(·call2097152, 2097152) -CALLFN(·call4194304, 4194304) -CALLFN(·call8388608, 8388608) -CALLFN(·call16777216, 16777216) -CALLFN(·call33554432, 33554432) -CALLFN(·call67108864, 67108864) -CALLFN(·call134217728, 134217728) -CALLFN(·call268435456, 268435456) -CALLFN(·call536870912, 536870912) -CALLFN(·call1073741824, 1073741824) - -TEXT runtime·procyield(SB),NOSPLIT,$0-0 - RET - -// Save state of caller into g->sched. -// but using fake PC from systemstack_switch. -// Must only be called from functions with no locals ($0) -// or else unwinding from systemstack_switch is incorrect. -// Smashes R19. -TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 - MOVV $runtime·systemstack_switch(SB), R19 - ADDV $8, R19 - MOVV R19, (g_sched+gobuf_pc)(g) - MOVV R3, (g_sched+gobuf_sp)(g) - MOVV R0, (g_sched+gobuf_lr)(g) - MOVV R0, (g_sched+gobuf_ret)(g) - // Assert ctxt is zero. See func save. - MOVV (g_sched+gobuf_ctxt)(g), R19 - BEQ R19, 2(PC) - JAL runtime·abort(SB) - RET - -// func asmcgocall(fn, arg unsafe.Pointer) int32 -// Call fn(arg) on the scheduler stack, -// aligned appropriately for the gcc ABI. -// See cgocall.go for more details. -TEXT ·asmcgocall(SB),NOSPLIT,$0-20 - MOVV fn+0(FP), R25 - MOVV arg+8(FP), R4 - - MOVV R3, R12 // save original stack pointer - MOVV g, R13 - - // Figure out if we need to switch to m->g0 stack. - // We get called to create new OS threads too, and those - // come in on the m->g0 stack already. - MOVV g_m(g), R5 - MOVV m_gsignal(R5), R6 - BEQ R6, g, g0 - MOVV m_g0(R5), R6 - BEQ R6, g, g0 - - JAL gosave_systemstack_switch<>(SB) - MOVV R6, g - JAL runtime·save_g(SB) - MOVV (g_sched+gobuf_sp)(g), R3 - - // Now on a scheduling stack (a pthread-created stack). -g0: - // Save room for two of our pointers. - ADDV $-16, R3 - MOVV R13, 0(R3) // save old g on stack - MOVV (g_stack+stack_hi)(R13), R13 - SUBVU R12, R13 - MOVV R13, 8(R3) // save depth in old g stack (can't just save SP, as stack might be copied during a callback) - JAL (R25) - - // Restore g, stack pointer. R4 is return value. - MOVV 0(R3), g - JAL runtime·save_g(SB) - MOVV (g_stack+stack_hi)(g), R5 - MOVV 8(R3), R6 - SUBVU R6, R5 - MOVV R5, R3 - - MOVW R4, ret+16(FP) - RET - -// func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) -// See cgocall.go for more details. -TEXT ·cgocallback(SB),NOSPLIT,$24-24 - NO_LOCAL_POINTERS - - // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. - // It is used to dropm while thread is exiting. - MOVV fn+0(FP), R5 - BNE R5, loadg - // Restore the g from frame. - MOVV frame+8(FP), g - JMP dropm - -loadg: - // Load m and g from thread-local storage. - MOVB runtime·iscgo(SB), R19 - BEQ R19, nocgo - JAL runtime·load_g(SB) -nocgo: - - // If g is nil, Go did not create the current thread, - // or if this thread never called into Go on pthread platforms. - // Call needm to obtain one for temporary use. - // In this case, we're running on the thread stack, so there's - // lots of space, but the linker doesn't know. Hide the call from - // the linker analysis by using an indirect call. - BEQ g, needm - - MOVV g_m(g), R12 - MOVV R12, savedm-8(SP) - JMP havem - -needm: - MOVV g, savedm-8(SP) // g is zero, so is m. - MOVV $runtime·needAndBindM(SB), R4 - JAL (R4) - - // Set m->sched.sp = SP, so that if a panic happens - // during the function we are about to execute, it will - // have a valid SP to run on the g0 stack. - // The next few lines (after the havem label) - // will save this SP onto the stack and then write - // the same SP back to m->sched.sp. That seems redundant, - // but if an unrecovered panic happens, unwindm will - // restore the g->sched.sp from the stack location - // and then systemstack will try to use it. If we don't set it here, - // that restored SP will be uninitialized (typically 0) and - // will not be usable. - MOVV g_m(g), R12 - MOVV m_g0(R12), R19 - MOVV R3, (g_sched+gobuf_sp)(R19) - -havem: - // Now there's a valid m, and we're running on its m->g0. - // Save current m->g0->sched.sp on stack and then set it to SP. - // Save current sp in m->g0->sched.sp in preparation for - // switch back to m->curg stack. - // NOTE: unwindm knows that the saved g->sched.sp is at 8(R29) aka savedsp-16(SP). - MOVV m_g0(R12), R19 - MOVV (g_sched+gobuf_sp)(R19), R13 - MOVV R13, savedsp-24(SP) // must match frame size - MOVV R3, (g_sched+gobuf_sp)(R19) - - // Switch to m->curg stack and call runtime.cgocallbackg. - // Because we are taking over the execution of m->curg - // but *not* resuming what had been running, we need to - // save that information (m->curg->sched) so we can restore it. - // We can restore m->curg->sched.sp easily, because calling - // runtime.cgocallbackg leaves SP unchanged upon return. - // To save m->curg->sched.pc, we push it onto the stack. - // This has the added benefit that it looks to the traceback - // routine like cgocallbackg is going to return to that - // PC (because the frame we allocate below has the same - // size as cgocallback_gofunc's frame declared above) - // so that the traceback will seamlessly trace back into - // the earlier calls. - MOVV m_curg(R12), g - JAL runtime·save_g(SB) - MOVV (g_sched+gobuf_sp)(g), R13 // prepare stack as R13 - MOVV (g_sched+gobuf_pc)(g), R4 - MOVV R4, -(24+8)(R13) // "saved LR"; must match frame size - MOVV fn+0(FP), R5 - MOVV frame+8(FP), R6 - MOVV ctxt+16(FP), R7 - MOVV $-(24+8)(R13), R3 - MOVV R5, 8(R3) - MOVV R6, 16(R3) - MOVV R7, 24(R3) - JAL runtime·cgocallbackg(SB) - - // Restore g->sched (== m->curg->sched) from saved values. - MOVV 0(R3), R4 - MOVV R4, (g_sched+gobuf_pc)(g) - MOVV $(24+8)(R3), R13 // must match frame size - MOVV R13, (g_sched+gobuf_sp)(g) - - // Switch back to m->g0's stack and restore m->g0->sched.sp. - // (Unlike m->curg, the g0 goroutine never uses sched.pc, - // so we do not have to restore it.) - MOVV g_m(g), R12 - MOVV m_g0(R12), g - JAL runtime·save_g(SB) - MOVV (g_sched+gobuf_sp)(g), R3 - MOVV savedsp-24(SP), R13 // must match frame size - MOVV R13, (g_sched+gobuf_sp)(g) - - // If the m on entry was nil, we called needm above to borrow an m, - // 1. for the duration of the call on non-pthread platforms, - // 2. or the duration of the C thread alive on pthread platforms. - // If the m on entry wasn't nil, - // 1. the thread might be a Go thread, - // 2. or it wasn't the first call from a C thread on pthread platforms, - // since then we skip dropm to resue the m in the first call. - MOVV savedm-8(SP), R12 - BNE R12, droppedm - - // Skip dropm to reuse it in the next call, when a pthread key has been created. - MOVV _cgo_pthread_key_created(SB), R12 - // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. - BEQ R12, dropm - MOVV (R12), R12 - BNE R12, droppedm - -dropm: - MOVV $runtime·dropm(SB), R4 - JAL (R4) -droppedm: - - // Done! - RET - -// void setg(G*); set g. for use by needm. -TEXT runtime·setg(SB), NOSPLIT, $0-8 - MOVV gg+0(FP), g - // This only happens if iscgo, so jump straight to save_g - JAL runtime·save_g(SB) - RET - -// void setg_gcc(G*); set g called from gcc with g in R19 -TEXT setg_gcc<>(SB),NOSPLIT,$0-0 - MOVV R19, g - JAL runtime·save_g(SB) - RET - -TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 - MOVW (R0), R0 - UNDEF - -// AES hashing not implemented for loong64 -TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 - JMP runtime·memhashFallback(SB) -TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 - JMP runtime·strhashFallback(SB) -TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 - JMP runtime·memhash32Fallback(SB) -TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 - JMP runtime·memhash64Fallback(SB) - -TEXT runtime·return0(SB), NOSPLIT, $0 - MOVW $0, R19 - RET - -// Called from cgo wrappers, this function returns g->m->curg.stack.hi. -// Must obey the gcc calling convention. -TEXT _cgo_topofstack(SB),NOSPLIT,$16 - // g (R22) and REGTMP (R30) might be clobbered by load_g. They - // are callee-save in the gcc calling convention, so save them. - MOVV R30, savedREGTMP-16(SP) - MOVV g, savedG-8(SP) - - JAL runtime·load_g(SB) - MOVV g_m(g), R19 - MOVV m_curg(R19), R19 - MOVV (g_stack+stack_hi)(R19), R4 // return value in R4 - - MOVV savedG-8(SP), g - MOVV savedREGTMP-16(SP), R30 - RET - -// The top-most function running on a goroutine -// returns to goexit+PCQuantum. -TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 - NOOP - JAL runtime·goexit1(SB) // does not return - // traceback from goexit1 must hit code range of goexit - NOOP - -// This is called from .init_array and follows the platform, not Go, ABI. -TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 - ADDV $-0x10, R3 - MOVV R30, 8(R3) // The access to global variables below implicitly uses R30, which is callee-save - MOVV runtime·lastmoduledatap(SB), R12 - MOVV R4, moduledata_next(R12) - MOVV R4, runtime·lastmoduledatap(SB) - MOVV 8(R3), R30 - ADDV $0x10, R3 - RET - -TEXT ·checkASM(SB),NOSPLIT,$0-1 - MOVW $1, R19 - MOVB R19, ret+0(FP) - RET - -#ifdef GOEXPERIMENT_regabiargs -// spillArgs stores return values from registers to a *internal/abi.RegArgs in R25. -TEXT ·spillArgs(SB),NOSPLIT,$0-0 - MOVV R4, (0*8)(R25) - MOVV R5, (1*8)(R25) - MOVV R6, (2*8)(R25) - MOVV R7, (3*8)(R25) - MOVV R8, (4*8)(R25) - MOVV R9, (5*8)(R25) - MOVV R10, (6*8)(R25) - MOVV R11, (7*8)(R25) - MOVV R12, (8*8)(R25) - MOVV R13, (9*8)(R25) - MOVV R14, (10*8)(R25) - MOVV R15, (11*8)(R25) - MOVV R16, (12*8)(R25) - MOVV R17, (13*8)(R25) - MOVV R18, (14*8)(R25) - MOVV R19, (15*8)(R25) - MOVD F0, (16*8)(R25) - MOVD F1, (17*8)(R25) - MOVD F2, (18*8)(R25) - MOVD F3, (19*8)(R25) - MOVD F4, (20*8)(R25) - MOVD F5, (21*8)(R25) - MOVD F6, (22*8)(R25) - MOVD F7, (23*8)(R25) - MOVD F8, (24*8)(R25) - MOVD F9, (25*8)(R25) - MOVD F10, (26*8)(R25) - MOVD F11, (27*8)(R25) - MOVD F12, (28*8)(R25) - MOVD F13, (29*8)(R25) - MOVD F14, (30*8)(R25) - MOVD F15, (31*8)(R25) - RET - -// unspillArgs loads args into registers from a *internal/abi.RegArgs in R25. -TEXT ·unspillArgs(SB),NOSPLIT,$0-0 - MOVV (0*8)(R25), R4 - MOVV (1*8)(R25), R5 - MOVV (2*8)(R25), R6 - MOVV (3*8)(R25), R7 - MOVV (4*8)(R25), R8 - MOVV (5*8)(R25), R9 - MOVV (6*8)(R25), R10 - MOVV (7*8)(R25), R11 - MOVV (8*8)(R25), R12 - MOVV (9*8)(R25), R13 - MOVV (10*8)(R25), R14 - MOVV (11*8)(R25), R15 - MOVV (12*8)(R25), R16 - MOVV (13*8)(R25), R17 - MOVV (14*8)(R25), R18 - MOVV (15*8)(R25), R19 - MOVD (16*8)(R25), F0 - MOVD (17*8)(R25), F1 - MOVD (18*8)(R25), F2 - MOVD (19*8)(R25), F3 - MOVD (20*8)(R25), F4 - MOVD (21*8)(R25), F5 - MOVD (22*8)(R25), F6 - MOVD (23*8)(R25), F7 - MOVD (24*8)(R25), F8 - MOVD (25*8)(R25), F9 - MOVD (26*8)(R25), F10 - MOVD (27*8)(R25), F11 - MOVD (28*8)(R25), F12 - MOVD (29*8)(R25), F13 - MOVD (30*8)(R25), F14 - MOVD (31*8)(R25), F15 - RET -#else -TEXT ·spillArgs(SB),NOSPLIT,$0-0 - RET - -TEXT ·unspillArgs(SB),NOSPLIT,$0-0 - RET -#endif - -// gcWriteBarrier informs the GC about heap pointer writes. -// -// gcWriteBarrier does NOT follow the Go ABI. It accepts the -// number of bytes of buffer needed in R29, and returns a pointer -// to the buffer space in R29. -// It clobbers R30 (the linker temp register). -// The act of CALLing gcWriteBarrier will clobber R1 (LR). -// It does not clobber any other general-purpose registers, -// but may clobber others (e.g., floating point registers). -TEXT gcWriteBarrier<>(SB),NOSPLIT,$216 - // Save the registers clobbered by the fast path. - MOVV R19, 208(R3) - MOVV R13, 216(R3) -retry: - MOVV g_m(g), R19 - MOVV m_p(R19), R19 - MOVV (p_wbBuf+wbBuf_next)(R19), R13 - MOVV (p_wbBuf+wbBuf_end)(R19), R30 // R30 is linker temp register - // Increment wbBuf.next position. - ADDV R29, R13 - // Is the buffer full? - BLTU R30, R13, flush - // Commit to the larger buffer. - MOVV R13, (p_wbBuf+wbBuf_next)(R19) - // Make return value (the original next position) - SUBV R29, R13, R29 - // Restore registers. - MOVV 208(R3), R19 - MOVV 216(R3), R13 - RET - -flush: - // Save all general purpose registers since these could be - // clobbered by wbBufFlush and were not saved by the caller. - MOVV R27, 8(R3) - MOVV R28, 16(R3) - // R1 is LR, which was saved by the prologue. - MOVV R2, 24(R3) - // R3 is SP. - MOVV R4, 32(R3) - MOVV R5, 40(R3) - MOVV R6, 48(R3) - MOVV R7, 56(R3) - MOVV R8, 64(R3) - MOVV R9, 72(R3) - MOVV R10, 80(R3) - MOVV R11, 88(R3) - MOVV R12, 96(R3) - // R13 already saved - MOVV R14, 104(R3) - MOVV R15, 112(R3) - MOVV R16, 120(R3) - MOVV R17, 128(R3) - MOVV R18, 136(R3) - // R19 already saved - MOVV R20, 144(R3) - MOVV R21, 152(R3) - // R22 is g. - MOVV R23, 160(R3) - MOVV R24, 168(R3) - MOVV R25, 176(R3) - MOVV R26, 184(R3) - // R27 already saved - // R28 already saved. - MOVV R29, 192(R3) - // R30 is tmp register. - MOVV R31, 200(R3) - - CALL runtime·wbBufFlush(SB) - - MOVV 8(R3), R27 - MOVV 16(R3), R28 - MOVV 24(R3), R2 - MOVV 32(R3), R4 - MOVV 40(R3), R5 - MOVV 48(R3), R6 - MOVV 56(R3), R7 - MOVV 64(R3), R8 - MOVV 72(R3), R9 - MOVV 80(R3), R10 - MOVV 88(R3), R11 - MOVV 96(R3), R12 - MOVV 104(R3), R14 - MOVV 112(R3), R15 - MOVV 120(R3), R16 - MOVV 128(R3), R17 - MOVV 136(R3), R18 - MOVV 144(R3), R20 - MOVV 152(R3), R21 - MOVV 160(R3), R23 - MOVV 168(R3), R24 - MOVV 176(R3), R25 - MOVV 184(R3), R26 - MOVV 192(R3), R29 - MOVV 200(R3), R31 - JMP retry - -TEXT runtime·gcWriteBarrier1(SB),NOSPLIT,$0 - MOVV $8, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier2(SB),NOSPLIT,$0 - MOVV $16, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier3(SB),NOSPLIT,$0 - MOVV $24, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier4(SB),NOSPLIT,$0 - MOVV $32, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier5(SB),NOSPLIT,$0 - MOVV $40, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier6(SB),NOSPLIT,$0 - MOVV $48, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier7(SB),NOSPLIT,$0 - MOVV $56, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier8(SB),NOSPLIT,$0 - MOVV $64, R29 - JMP gcWriteBarrier<>(SB) - -// Note: these functions use a special calling convention to save generated code space. -// Arguments are passed in registers, but the space for those arguments are allocated -// in the caller's stack frame. These stubs write the args into that stack space and -// then tail call to the corresponding runtime handler. -// The tail call makes these stubs disappear in backtraces. -TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R20, R4 - MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif - JMP runtime·goPanicIndex(SB) -TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R20, R4 - MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif - JMP runtime·goPanicIndexU(SB) -TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R21, R4 - MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif - JMP runtime·goPanicSliceAlen(SB) -TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R21, R4 - MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif - JMP runtime·goPanicSliceAlenU(SB) -TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R21, R4 - MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif - JMP runtime·goPanicSliceAcap(SB) -TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R21, R4 - MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif - JMP runtime·goPanicSliceAcapU(SB) -TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R20, R4 - MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif - JMP runtime·goPanicSliceB(SB) -TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R20, R4 - MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif - JMP runtime·goPanicSliceBU(SB) -TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R23, R4 - MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif - JMP runtime·goPanicSlice3Alen(SB) -TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R23, R4 - MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif - JMP runtime·goPanicSlice3AlenU(SB) -TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R23, R4 - MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif - JMP runtime·goPanicSlice3Acap(SB) -TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R23, R4 - MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif - JMP runtime·goPanicSlice3AcapU(SB) -TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R21, R4 - MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif - JMP runtime·goPanicSlice3B(SB) -TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R21, R4 - MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif - JMP runtime·goPanicSlice3BU(SB) -TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R20, R4 - MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif - JMP runtime·goPanicSlice3C(SB) -TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R20, R4 - MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif - JMP runtime·goPanicSlice3CU(SB) -TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs - MOVV R23, R4 - MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif - JMP runtime·goPanicSliceConvert(SB) diff --git a/contrib/go/_std_1.22/src/runtime/asm_ppc64x.s b/contrib/go/_std_1.22/src/runtime/asm_ppc64x.s deleted file mode 100644 index ff9b736430cc..000000000000 --- a/contrib/go/_std_1.22/src/runtime/asm_ppc64x.s +++ /dev/null @@ -1,1618 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build ppc64 || ppc64le - -#include "go_asm.h" -#include "go_tls.h" -#include "funcdata.h" -#include "textflag.h" -#include "asm_ppc64x.h" - -#ifdef GOOS_aix -#define cgoCalleeStackSize 48 -#else -#define cgoCalleeStackSize 32 -#endif - -TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 - // R1 = stack; R3 = argc; R4 = argv; R13 = C TLS base pointer - - // initialize essential registers - BL runtime·reginit(SB) - - SUB $(FIXED_FRAME+16), R1 - MOVD R2, 24(R1) // stash the TOC pointer away again now we've created a new frame - MOVW R3, FIXED_FRAME+0(R1) // argc - MOVD R4, FIXED_FRAME+8(R1) // argv - - // create istack out of the given (operating system) stack. - // _cgo_init may update stackguard. - MOVD $runtime·g0(SB), g - BL runtime·save_g(SB) - MOVD $(-64*1024), R31 - ADD R31, R1, R3 - MOVD R3, g_stackguard0(g) - MOVD R3, g_stackguard1(g) - MOVD R3, (g_stack+stack_lo)(g) - MOVD R1, (g_stack+stack_hi)(g) - - // If there is a _cgo_init, call it using the gcc ABI. - MOVD _cgo_init(SB), R12 - CMP R0, R12 - BEQ nocgo - -#ifdef GO_PPC64X_HAS_FUNCDESC - // Load the real entry address from the first slot of the function descriptor. - MOVD 8(R12), R2 - MOVD (R12), R12 -#endif - MOVD R12, CTR // r12 = "global function entry point" - MOVD R13, R5 // arg 2: TLS base pointer - MOVD $setg_gcc<>(SB), R4 // arg 1: setg - MOVD g, R3 // arg 0: G - // C functions expect 32 (48 for AIX) bytes of space on caller - // stack frame and a 16-byte aligned R1 - MOVD R1, R14 // save current stack - SUB $cgoCalleeStackSize, R1 // reserve the callee area - RLDCR $0, R1, $~15, R1 // 16-byte align - BL (CTR) // may clobber R0, R3-R12 - MOVD R14, R1 // restore stack -#ifndef GOOS_aix - MOVD 24(R1), R2 -#endif - XOR R0, R0 // fix R0 - -nocgo: - // update stackguard after _cgo_init - MOVD (g_stack+stack_lo)(g), R3 - ADD $const_stackGuard, R3 - MOVD R3, g_stackguard0(g) - MOVD R3, g_stackguard1(g) - - // set the per-goroutine and per-mach "registers" - MOVD $runtime·m0(SB), R3 - - // save m->g0 = g0 - MOVD g, m_g0(R3) - // save m0 to g0->m - MOVD R3, g_m(g) - - BL runtime·check(SB) - - // args are already prepared - BL runtime·args(SB) - BL runtime·osinit(SB) - BL runtime·schedinit(SB) - - // create a new goroutine to start program - MOVD $runtime·mainPC(SB), R3 // entry - MOVDU R3, -8(R1) - MOVDU R0, -8(R1) - MOVDU R0, -8(R1) - MOVDU R0, -8(R1) - MOVDU R0, -8(R1) - BL runtime·newproc(SB) - ADD $(8+FIXED_FRAME), R1 - - // start this M - BL runtime·mstart(SB) - // Prevent dead-code elimination of debugCallV2, which is - // intended to be called by debuggers. -#ifdef GOARCH_ppc64le - MOVD $runtime·debugCallV2(SB), R31 -#endif - MOVD R0, 0(R0) - RET - -DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) -GLOBL runtime·mainPC(SB),RODATA,$8 - -TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0 - TW $31, R0, R0 - RET - -TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0 - RET - -// Any changes must be reflected to runtime/cgo/gcc_aix_ppc64.S:.crosscall_ppc64 -TEXT _cgo_reginit(SB),NOSPLIT|NOFRAME,$0-0 - // crosscall_ppc64 and crosscall2 need to reginit, but can't - // get at the 'runtime.reginit' symbol. - BR runtime·reginit(SB) - -TEXT runtime·reginit(SB),NOSPLIT|NOFRAME,$0-0 - // set R0 to zero, it's expected by the toolchain - XOR R0, R0 - RET - -TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 - BL runtime·mstart0(SB) - RET // not reached - -/* - * go-routine - */ - -// void gogo(Gobuf*) -// restore state from Gobuf; longjmp -TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8 - MOVD buf+0(FP), R5 - MOVD gobuf_g(R5), R6 - MOVD 0(R6), R4 // make sure g != nil - BR gogo<>(SB) - -TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 - MOVD R6, g - BL runtime·save_g(SB) - - MOVD gobuf_sp(R5), R1 - MOVD gobuf_lr(R5), R31 -#ifndef GOOS_aix - MOVD 24(R1), R2 // restore R2 -#endif - MOVD R31, LR - MOVD gobuf_ret(R5), R3 - MOVD gobuf_ctxt(R5), R11 - MOVD R0, gobuf_sp(R5) - MOVD R0, gobuf_ret(R5) - MOVD R0, gobuf_lr(R5) - MOVD R0, gobuf_ctxt(R5) - CMP R0, R0 // set condition codes for == test, needed by stack split - MOVD gobuf_pc(R5), R12 - MOVD R12, CTR - BR (CTR) - -// void mcall(fn func(*g)) -// Switch to m->g0's stack, call fn(g). -// Fn must never return. It should gogo(&g->sched) -// to keep running g. -TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 - // Save caller state in g->sched - // R11 should be safe across save_g?? - MOVD R3, R11 - MOVD R1, (g_sched+gobuf_sp)(g) - MOVD LR, R31 - MOVD R31, (g_sched+gobuf_pc)(g) - MOVD R0, (g_sched+gobuf_lr)(g) - - // Switch to m->g0 & its stack, call fn. - MOVD g, R3 - MOVD g_m(g), R8 - MOVD m_g0(R8), g - BL runtime·save_g(SB) - CMP g, R3 - BNE 2(PC) - BR runtime·badmcall(SB) - MOVD 0(R11), R12 // code pointer - MOVD R12, CTR - MOVD (g_sched+gobuf_sp)(g), R1 // sp = m->g0->sched.sp - // Don't need to do anything special for regabiargs here - // R3 is g; stack is set anyway - MOVDU R3, -8(R1) - MOVDU R0, -8(R1) - MOVDU R0, -8(R1) - MOVDU R0, -8(R1) - MOVDU R0, -8(R1) - BL (CTR) - MOVD 24(R1), R2 - BR runtime·badmcall2(SB) - -// systemstack_switch is a dummy routine that systemstack leaves at the bottom -// of the G stack. We need to distinguish the routine that -// lives at the bottom of the G stack from the one that lives -// at the top of the system stack because the one at the top of -// the system stack terminates the stack walk (see topofstack()). -TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 - // We have several undefs here so that 16 bytes past - // $runtime·systemstack_switch lies within them whether or not the - // instructions that derive r2 from r12 are there. - UNDEF - UNDEF - UNDEF - BL (LR) // make sure this function is not leaf - RET - -// func systemstack(fn func()) -TEXT runtime·systemstack(SB), NOSPLIT, $0-8 - MOVD fn+0(FP), R3 // R3 = fn - MOVD R3, R11 // context - MOVD g_m(g), R4 // R4 = m - - MOVD m_gsignal(R4), R5 // R5 = gsignal - CMP g, R5 - BEQ noswitch - - MOVD m_g0(R4), R5 // R5 = g0 - CMP g, R5 - BEQ noswitch - - MOVD m_curg(R4), R6 - CMP g, R6 - BEQ switch - - // Bad: g is not gsignal, not g0, not curg. What is it? - // Hide call from linker nosplit analysis. - MOVD $runtime·badsystemstack(SB), R12 - MOVD R12, CTR - BL (CTR) - BL runtime·abort(SB) - -switch: - // save our state in g->sched. Pretend to - // be systemstack_switch if the G stack is scanned. - BL gosave_systemstack_switch<>(SB) - - // switch to g0 - MOVD R5, g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R1 - - // call target function - MOVD 0(R11), R12 // code pointer - MOVD R12, CTR - BL (CTR) - - // restore TOC pointer. It seems unlikely that we will use systemstack - // to call a function defined in another module, but the results of - // doing so would be so confusing that it's worth doing this. - MOVD g_m(g), R3 - MOVD m_curg(R3), g - MOVD (g_sched+gobuf_sp)(g), R3 -#ifndef GOOS_aix - MOVD 24(R3), R2 -#endif - // switch back to g - MOVD g_m(g), R3 - MOVD m_curg(R3), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R1 - MOVD R0, (g_sched+gobuf_sp)(g) - RET - -noswitch: - // already on m stack, just call directly - // On other arches we do a tail call here, but it appears to be - // impossible to tail call a function pointer in shared mode on - // ppc64 because the caller is responsible for restoring the TOC. - MOVD 0(R11), R12 // code pointer - MOVD R12, CTR - BL (CTR) -#ifndef GOOS_aix - MOVD 24(R1), R2 -#endif - RET - -// func switchToCrashStack0(fn func()) -TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 - MOVD R3, R11 // context register - MOVD g_m(g), R3 // curm - - // set g to gcrash - MOVD $runtime·gcrash(SB), g // g = &gcrash - CALL runtime·save_g(SB) // clobbers R31 - MOVD R3, g_m(g) // g.m = curm - MOVD g, m_g0(R3) // curm.g0 = g - - // switch to crashstack - MOVD (g_stack+stack_hi)(g), R3 - SUB $(4*8), R3 - MOVD R3, R1 - - // call target function - MOVD 0(R11), R12 // code pointer - MOVD R12, CTR - BL (CTR) - - // should never return - CALL runtime·abort(SB) - UNDEF - -/* - * support for morestack - */ - -// Called during function prolog when more stack is needed. -// Caller has already loaded: -// R3: framesize, R4: argsize, R5: LR -// -// The traceback routines see morestack on a g0 as being -// the top of a stack (for example, morestack calling newstack -// calling the scheduler calling newm calling gc), so we must -// record an argument size. For that purpose, it has no arguments. -TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 - // Called from f. - // Set g->sched to context in f. - MOVD R1, (g_sched+gobuf_sp)(g) - MOVD LR, R8 - MOVD R8, (g_sched+gobuf_pc)(g) - MOVD R5, (g_sched+gobuf_lr)(g) - MOVD R11, (g_sched+gobuf_ctxt)(g) - - // Cannot grow scheduler stack (m->g0). - MOVD g_m(g), R7 - MOVD m_g0(R7), R8 - CMP g, R8 - BNE 3(PC) - BL runtime·badmorestackg0(SB) - BL runtime·abort(SB) - - // Cannot grow signal stack (m->gsignal). - MOVD m_gsignal(R7), R8 - CMP g, R8 - BNE 3(PC) - BL runtime·badmorestackgsignal(SB) - BL runtime·abort(SB) - - // Called from f. - // Set m->morebuf to f's caller. - MOVD R5, (m_morebuf+gobuf_pc)(R7) // f's caller's PC - MOVD R1, (m_morebuf+gobuf_sp)(R7) // f's caller's SP - MOVD g, (m_morebuf+gobuf_g)(R7) - - // Call newstack on m->g0's stack. - MOVD m_g0(R7), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R1 - MOVDU R0, -(FIXED_FRAME+0)(R1) // create a call frame on g0 - BL runtime·newstack(SB) - - // Not reached, but make sure the return PC from the call to newstack - // is still in this function, and not the beginning of the next. - UNDEF - -TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 - // Force SPWRITE. This function doesn't actually write SP, - // but it is called with a special calling convention where - // the caller doesn't save LR on stack but passes it as a - // register (R5), and the unwinder currently doesn't understand. - // Make it SPWRITE to stop unwinding. (See issue 54332) - // Use OR R0, R1 instead of MOVD R1, R1 as the MOVD instruction - // has a special affect on Power8,9,10 by lowering the thread - // priority and causing a slowdown in execution time - - OR R0, R1 - MOVD R0, R11 - BR runtime·morestack(SB) - -// reflectcall: call a function with the given argument list -// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). -// we don't have variable-sized frames, so we use a small number -// of constant-sized-frame functions to encode a few bits of size in the pc. -// Caution: ugly multiline assembly macros in your future! - -#define DISPATCH(NAME,MAXSIZE) \ - MOVD $MAXSIZE, R31; \ - CMP R3, R31; \ - BGT 4(PC); \ - MOVD $NAME(SB), R12; \ - MOVD R12, CTR; \ - BR (CTR) -// Note: can't just "BR NAME(SB)" - bad inlining results. - -TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-48 - MOVWZ frameSize+32(FP), R3 - DISPATCH(runtime·call16, 16) - DISPATCH(runtime·call32, 32) - DISPATCH(runtime·call64, 64) - DISPATCH(runtime·call128, 128) - DISPATCH(runtime·call256, 256) - DISPATCH(runtime·call512, 512) - DISPATCH(runtime·call1024, 1024) - DISPATCH(runtime·call2048, 2048) - DISPATCH(runtime·call4096, 4096) - DISPATCH(runtime·call8192, 8192) - DISPATCH(runtime·call16384, 16384) - DISPATCH(runtime·call32768, 32768) - DISPATCH(runtime·call65536, 65536) - DISPATCH(runtime·call131072, 131072) - DISPATCH(runtime·call262144, 262144) - DISPATCH(runtime·call524288, 524288) - DISPATCH(runtime·call1048576, 1048576) - DISPATCH(runtime·call2097152, 2097152) - DISPATCH(runtime·call4194304, 4194304) - DISPATCH(runtime·call8388608, 8388608) - DISPATCH(runtime·call16777216, 16777216) - DISPATCH(runtime·call33554432, 33554432) - DISPATCH(runtime·call67108864, 67108864) - DISPATCH(runtime·call134217728, 134217728) - DISPATCH(runtime·call268435456, 268435456) - DISPATCH(runtime·call536870912, 536870912) - DISPATCH(runtime·call1073741824, 1073741824) - MOVD $runtime·badreflectcall(SB), R12 - MOVD R12, CTR - BR (CTR) - -#define CALLFN(NAME,MAXSIZE) \ -TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ - NO_LOCAL_POINTERS; \ - /* copy arguments to stack */ \ - MOVD stackArgs+16(FP), R3; \ - MOVWZ stackArgsSize+24(FP), R4; \ - MOVD R1, R5; \ - CMP R4, $8; \ - BLT tailsetup; \ - /* copy 8 at a time if possible */ \ - ADD $(FIXED_FRAME-8), R5; \ - SUB $8, R3; \ -top: \ - MOVDU 8(R3), R7; \ - MOVDU R7, 8(R5); \ - SUB $8, R4; \ - CMP R4, $8; \ - BGE top; \ - /* handle remaining bytes */ \ - CMP $0, R4; \ - BEQ callfn; \ - ADD $7, R3; \ - ADD $7, R5; \ - BR tail; \ -tailsetup: \ - CMP $0, R4; \ - BEQ callfn; \ - ADD $(FIXED_FRAME-1), R5; \ - SUB $1, R3; \ -tail: \ - MOVBU 1(R3), R6; \ - MOVBU R6, 1(R5); \ - SUB $1, R4; \ - CMP $0, R4; \ - BGT tail; \ -callfn: \ - /* call function */ \ - MOVD f+8(FP), R11; \ -#ifdef GOOS_aix \ - /* AIX won't trigger a SIGSEGV if R11 = nil */ \ - /* So it manually triggers it */ \ - CMP R0, R11 \ - BNE 2(PC) \ - MOVD R0, 0(R0) \ -#endif \ - MOVD regArgs+40(FP), R20; \ - BL runtime·unspillArgs(SB); \ - MOVD (R11), R12; \ - MOVD R12, CTR; \ - PCDATA $PCDATA_StackMapIndex, $0; \ - BL (CTR); \ -#ifndef GOOS_aix \ - MOVD 24(R1), R2; \ -#endif \ - /* copy return values back */ \ - MOVD regArgs+40(FP), R20; \ - BL runtime·spillArgs(SB); \ - MOVD stackArgsType+0(FP), R7; \ - MOVD stackArgs+16(FP), R3; \ - MOVWZ stackArgsSize+24(FP), R4; \ - MOVWZ stackRetOffset+28(FP), R6; \ - ADD $FIXED_FRAME, R1, R5; \ - ADD R6, R5; \ - ADD R6, R3; \ - SUB R6, R4; \ - BL callRet<>(SB); \ - RET - -// callRet copies return values back at the end of call*. This is a -// separate function so it can allocate stack space for the arguments -// to reflectcallmove. It does not follow the Go ABI; it expects its -// arguments in registers. -TEXT callRet<>(SB), NOSPLIT, $40-0 - NO_LOCAL_POINTERS - MOVD R7, FIXED_FRAME+0(R1) - MOVD R3, FIXED_FRAME+8(R1) - MOVD R5, FIXED_FRAME+16(R1) - MOVD R4, FIXED_FRAME+24(R1) - MOVD R20, FIXED_FRAME+32(R1) - BL runtime·reflectcallmove(SB) - RET - -CALLFN(·call16, 16) -CALLFN(·call32, 32) -CALLFN(·call64, 64) -CALLFN(·call128, 128) -CALLFN(·call256, 256) -CALLFN(·call512, 512) -CALLFN(·call1024, 1024) -CALLFN(·call2048, 2048) -CALLFN(·call4096, 4096) -CALLFN(·call8192, 8192) -CALLFN(·call16384, 16384) -CALLFN(·call32768, 32768) -CALLFN(·call65536, 65536) -CALLFN(·call131072, 131072) -CALLFN(·call262144, 262144) -CALLFN(·call524288, 524288) -CALLFN(·call1048576, 1048576) -CALLFN(·call2097152, 2097152) -CALLFN(·call4194304, 4194304) -CALLFN(·call8388608, 8388608) -CALLFN(·call16777216, 16777216) -CALLFN(·call33554432, 33554432) -CALLFN(·call67108864, 67108864) -CALLFN(·call134217728, 134217728) -CALLFN(·call268435456, 268435456) -CALLFN(·call536870912, 536870912) -CALLFN(·call1073741824, 1073741824) - -TEXT runtime·procyield(SB),NOSPLIT|NOFRAME,$0-4 - MOVW cycles+0(FP), R7 - // POWER does not have a pause/yield instruction equivalent. - // Instead, we can lower the program priority by setting the - // Program Priority Register prior to the wait loop and set it - // back to default afterwards. On Linux, the default priority is - // medium-low. For details, see page 837 of the ISA 3.0. - OR R1, R1, R1 // Set PPR priority to low -again: - SUB $1, R7 - CMP $0, R7 - BNE again - OR R6, R6, R6 // Set PPR priority back to medium-low - RET - -// Save state of caller into g->sched, -// but using fake PC from systemstack_switch. -// Must only be called from functions with no locals ($0) -// or else unwinding from systemstack_switch is incorrect. -// Smashes R31. -TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 - MOVD $runtime·systemstack_switch(SB), R31 - ADD $16, R31 // get past prologue (including r2-setting instructions when they're there) - MOVD R31, (g_sched+gobuf_pc)(g) - MOVD R1, (g_sched+gobuf_sp)(g) - MOVD R0, (g_sched+gobuf_lr)(g) - MOVD R0, (g_sched+gobuf_ret)(g) - // Assert ctxt is zero. See func save. - MOVD (g_sched+gobuf_ctxt)(g), R31 - CMP R0, R31 - BEQ 2(PC) - BL runtime·abort(SB) - RET - -#ifdef GOOS_aix -#define asmcgocallSaveOffset cgoCalleeStackSize + 8 -#else -#define asmcgocallSaveOffset cgoCalleeStackSize -#endif - -// func asmcgocall_no_g(fn, arg unsafe.Pointer) -// Call fn(arg) aligned appropriately for the gcc ABI. -// Called on a system stack, and there may be no g yet (during needm). -TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16 - MOVD fn+0(FP), R3 - MOVD arg+8(FP), R4 - - MOVD R1, R15 - SUB $(asmcgocallSaveOffset+8), R1 - RLDCR $0, R1, $~15, R1 // 16-byte alignment for gcc ABI - MOVD R15, asmcgocallSaveOffset(R1) - - MOVD R0, 0(R1) // clear back chain pointer (TODO can we give it real back trace information?) - - // This is a "global call", so put the global entry point in r12 - MOVD R3, R12 - -#ifdef GO_PPC64X_HAS_FUNCDESC - // Load the real entry address from the first slot of the function descriptor. - MOVD 8(R12), R2 - MOVD (R12), R12 -#endif - MOVD R12, CTR - MOVD R4, R3 // arg in r3 - BL (CTR) - - // C code can clobber R0, so set it back to 0. F27-F31 are - // callee save, so we don't need to recover those. - XOR R0, R0 - - MOVD asmcgocallSaveOffset(R1), R1 // Restore stack pointer. -#ifndef GOOS_aix - MOVD 24(R1), R2 -#endif - - RET - -// func asmcgocall(fn, arg unsafe.Pointer) int32 -// Call fn(arg) on the scheduler stack, -// aligned appropriately for the gcc ABI. -// See cgocall.go for more details. -TEXT ·asmcgocall(SB),NOSPLIT,$0-20 - MOVD fn+0(FP), R3 - MOVD arg+8(FP), R4 - - MOVD R1, R7 // save original stack pointer - CMP $0, g - BEQ nosave - MOVD g, R5 - - // Figure out if we need to switch to m->g0 stack. - // We get called to create new OS threads too, and those - // come in on the m->g0 stack already. Or we might already - // be on the m->gsignal stack. - MOVD g_m(g), R8 - MOVD m_gsignal(R8), R6 - CMP R6, g - BEQ nosave - MOVD m_g0(R8), R6 - CMP R6, g - BEQ nosave - - BL gosave_systemstack_switch<>(SB) - MOVD R6, g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R1 - - // Now on a scheduling stack (a pthread-created stack). -#ifdef GOOS_aix - // Create a fake LR to improve backtrace. - MOVD $runtime·asmcgocall(SB), R6 - MOVD R6, 16(R1) - // AIX also saves one argument on the stack. - SUB $8, R1 -#endif - // Save room for two of our pointers, plus the callee - // save area that lives on the caller stack. - SUB $(asmcgocallSaveOffset+16), R1 - RLDCR $0, R1, $~15, R1 // 16-byte alignment for gcc ABI - MOVD R5, (asmcgocallSaveOffset+8)(R1) // save old g on stack - MOVD (g_stack+stack_hi)(R5), R5 - SUB R7, R5 - MOVD R5, asmcgocallSaveOffset(R1) // save depth in old g stack (can't just save SP, as stack might be copied during a callback) -#ifdef GOOS_aix - MOVD R7, 0(R1) // Save frame pointer to allow manual backtrace with gdb -#else - MOVD R0, 0(R1) // clear back chain pointer (TODO can we give it real back trace information?) -#endif - // This is a "global call", so put the global entry point in r12 - MOVD R3, R12 - -#ifdef GO_PPC64X_HAS_FUNCDESC - // Load the real entry address from the first slot of the function descriptor. - MOVD 8(R12), R2 - MOVD (R12), R12 -#endif - MOVD R12, CTR - MOVD R4, R3 // arg in r3 - BL (CTR) - - // Reinitialise zero value register. - XOR R0, R0 - - // Restore g, stack pointer, toc pointer. - // R3 is errno, so don't touch it - MOVD (asmcgocallSaveOffset+8)(R1), g - MOVD (g_stack+stack_hi)(g), R5 - MOVD asmcgocallSaveOffset(R1), R6 - SUB R6, R5 -#ifndef GOOS_aix - MOVD 24(R5), R2 -#endif - MOVD R5, R1 - BL runtime·save_g(SB) - - MOVW R3, ret+16(FP) - RET - -nosave: - // Running on a system stack, perhaps even without a g. - // Having no g can happen during thread creation or thread teardown. - // This code is like the above sequence but without saving/restoring g - // and without worrying about the stack moving out from under us - // (because we're on a system stack, not a goroutine stack). - // The above code could be used directly if already on a system stack, - // but then the only path through this code would be a rare case. - // Using this code for all "already on system stack" calls exercises it more, - // which should help keep it correct. - - SUB $(asmcgocallSaveOffset+8), R1 - RLDCR $0, R1, $~15, R1 // 16-byte alignment for gcc ABI - MOVD R7, asmcgocallSaveOffset(R1) // Save original stack pointer. - - MOVD R3, R12 // fn -#ifdef GO_PPC64X_HAS_FUNCDESC - // Load the real entry address from the first slot of the function descriptor. - MOVD 8(R12), R2 - MOVD (R12), R12 -#endif - MOVD R12, CTR - MOVD R4, R3 // arg - BL (CTR) - - // Reinitialise zero value register. - XOR R0, R0 - - MOVD asmcgocallSaveOffset(R1), R1 // Restore stack pointer. -#ifndef GOOS_aix - MOVD 24(R1), R2 -#endif - MOVW R3, ret+16(FP) - RET - -// func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) -// See cgocall.go for more details. -TEXT ·cgocallback(SB),NOSPLIT,$24-24 - NO_LOCAL_POINTERS - - // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. - // It is used to dropm while thread is exiting. - MOVD fn+0(FP), R5 - CMP R5, $0 - BNE loadg - // Restore the g from frame. - MOVD frame+8(FP), g - BR dropm - -loadg: - // Load m and g from thread-local storage. -#ifndef GOOS_openbsd - MOVBZ runtime·iscgo(SB), R3 - CMP R3, $0 - BEQ nocgo -#endif - BL runtime·load_g(SB) -nocgo: - - // If g is nil, Go did not create the current thread, - // or if this thread never called into Go on pthread platforms. - // Call needm to obtain one for temporary use. - // In this case, we're running on the thread stack, so there's - // lots of space, but the linker doesn't know. Hide the call from - // the linker analysis by using an indirect call. - CMP g, $0 - BEQ needm - - MOVD g_m(g), R8 - MOVD R8, savedm-8(SP) - BR havem - -needm: - MOVD g, savedm-8(SP) // g is zero, so is m. - MOVD $runtime·needAndBindM(SB), R12 - MOVD R12, CTR - BL (CTR) - - // Set m->sched.sp = SP, so that if a panic happens - // during the function we are about to execute, it will - // have a valid SP to run on the g0 stack. - // The next few lines (after the havem label) - // will save this SP onto the stack and then write - // the same SP back to m->sched.sp. That seems redundant, - // but if an unrecovered panic happens, unwindm will - // restore the g->sched.sp from the stack location - // and then systemstack will try to use it. If we don't set it here, - // that restored SP will be uninitialized (typically 0) and - // will not be usable. - MOVD g_m(g), R8 - MOVD m_g0(R8), R3 - MOVD R1, (g_sched+gobuf_sp)(R3) - -havem: - // Now there's a valid m, and we're running on its m->g0. - // Save current m->g0->sched.sp on stack and then set it to SP. - // Save current sp in m->g0->sched.sp in preparation for - // switch back to m->curg stack. - // NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP). - MOVD m_g0(R8), R3 - MOVD (g_sched+gobuf_sp)(R3), R4 - MOVD R4, savedsp-24(SP) // must match frame size - MOVD R1, (g_sched+gobuf_sp)(R3) - - // Switch to m->curg stack and call runtime.cgocallbackg. - // Because we are taking over the execution of m->curg - // but *not* resuming what had been running, we need to - // save that information (m->curg->sched) so we can restore it. - // We can restore m->curg->sched.sp easily, because calling - // runtime.cgocallbackg leaves SP unchanged upon return. - // To save m->curg->sched.pc, we push it onto the curg stack and - // open a frame the same size as cgocallback's g0 frame. - // Once we switch to the curg stack, the pushed PC will appear - // to be the return PC of cgocallback, so that the traceback - // will seamlessly trace back into the earlier calls. - MOVD m_curg(R8), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 - MOVD (g_sched+gobuf_pc)(g), R5 - MOVD R5, -(24+FIXED_FRAME)(R4) // "saved LR"; must match frame size - // Gather our arguments into registers. - MOVD fn+0(FP), R5 - MOVD frame+8(FP), R6 - MOVD ctxt+16(FP), R7 - MOVD $-(24+FIXED_FRAME)(R4), R1 // switch stack; must match frame size - MOVD R5, FIXED_FRAME+0(R1) - MOVD R6, FIXED_FRAME+8(R1) - MOVD R7, FIXED_FRAME+16(R1) - - MOVD $runtime·cgocallbackg(SB), R12 - MOVD R12, CTR - CALL (CTR) // indirect call to bypass nosplit check. We're on a different stack now. - - // Restore g->sched (== m->curg->sched) from saved values. - MOVD 0(R1), R5 - MOVD R5, (g_sched+gobuf_pc)(g) - MOVD $(24+FIXED_FRAME)(R1), R4 // must match frame size - MOVD R4, (g_sched+gobuf_sp)(g) - - // Switch back to m->g0's stack and restore m->g0->sched.sp. - // (Unlike m->curg, the g0 goroutine never uses sched.pc, - // so we do not have to restore it.) - MOVD g_m(g), R8 - MOVD m_g0(R8), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R1 - MOVD savedsp-24(SP), R4 // must match frame size - MOVD R4, (g_sched+gobuf_sp)(g) - - // If the m on entry was nil, we called needm above to borrow an m, - // 1. for the duration of the call on non-pthread platforms, - // 2. or the duration of the C thread alive on pthread platforms. - // If the m on entry wasn't nil, - // 1. the thread might be a Go thread, - // 2. or it wasn't the first call from a C thread on pthread platforms, - // since then we skip dropm to reuse the m in the first call. - MOVD savedm-8(SP), R6 - CMP R6, $0 - BNE droppedm - - // Skip dropm to reuse it in the next call, when a pthread key has been created. - MOVD _cgo_pthread_key_created(SB), R6 - // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. - CMP R6, $0 - BEQ dropm - MOVD (R6), R6 - CMP R6, $0 - BNE droppedm - -dropm: - MOVD $runtime·dropm(SB), R12 - MOVD R12, CTR - BL (CTR) -droppedm: - - // Done! - RET - -// void setg(G*); set g. for use by needm. -TEXT runtime·setg(SB), NOSPLIT, $0-8 - MOVD gg+0(FP), g - // This only happens if iscgo, so jump straight to save_g - BL runtime·save_g(SB) - RET - -#ifdef GO_PPC64X_HAS_FUNCDESC -DEFINE_PPC64X_FUNCDESC(setg_gcc<>, _setg_gcc<>) -TEXT _setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 -#else -TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 -#endif - // The standard prologue clobbers R31, which is callee-save in - // the C ABI, so we have to use $-8-0 and save LR ourselves. - MOVD LR, R4 - // Also save g and R31, since they're callee-save in C ABI - MOVD R31, R5 - MOVD g, R6 - - MOVD R3, g - BL runtime·save_g(SB) - - MOVD R6, g - MOVD R5, R31 - MOVD R4, LR - RET - -TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 - MOVW (R0), R0 - UNDEF - -#define TBR 268 - -// int64 runtime·cputicks(void) -TEXT runtime·cputicks(SB),NOSPLIT,$0-8 - MOVD SPR(TBR), R3 - MOVD R3, ret+0(FP) - RET - -// spillArgs stores return values from registers to a *internal/abi.RegArgs in R20. -TEXT runtime·spillArgs(SB),NOSPLIT,$0-0 - MOVD R3, 0(R20) - MOVD R4, 8(R20) - MOVD R5, 16(R20) - MOVD R6, 24(R20) - MOVD R7, 32(R20) - MOVD R8, 40(R20) - MOVD R9, 48(R20) - MOVD R10, 56(R20) - MOVD R14, 64(R20) - MOVD R15, 72(R20) - MOVD R16, 80(R20) - MOVD R17, 88(R20) - FMOVD F1, 96(R20) - FMOVD F2, 104(R20) - FMOVD F3, 112(R20) - FMOVD F4, 120(R20) - FMOVD F5, 128(R20) - FMOVD F6, 136(R20) - FMOVD F7, 144(R20) - FMOVD F8, 152(R20) - FMOVD F9, 160(R20) - FMOVD F10, 168(R20) - FMOVD F11, 176(R20) - FMOVD F12, 184(R20) - RET - -// unspillArgs loads args into registers from a *internal/abi.RegArgs in R20. -TEXT runtime·unspillArgs(SB),NOSPLIT,$0-0 - MOVD 0(R20), R3 - MOVD 8(R20), R4 - MOVD 16(R20), R5 - MOVD 24(R20), R6 - MOVD 32(R20), R7 - MOVD 40(R20), R8 - MOVD 48(R20), R9 - MOVD 56(R20), R10 - MOVD 64(R20), R14 - MOVD 72(R20), R15 - MOVD 80(R20), R16 - MOVD 88(R20), R17 - FMOVD 96(R20), F1 - FMOVD 104(R20), F2 - FMOVD 112(R20), F3 - FMOVD 120(R20), F4 - FMOVD 128(R20), F5 - FMOVD 136(R20), F6 - FMOVD 144(R20), F7 - FMOVD 152(R20), F8 - FMOVD 160(R20), F9 - FMOVD 168(R20), F10 - FMOVD 176(R20), F11 - FMOVD 184(R20), F12 - RET - -// AES hashing not implemented for ppc64 -TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 - JMP runtime·memhashFallback(SB) -TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 - JMP runtime·strhashFallback(SB) -TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 - JMP runtime·memhash32Fallback(SB) -TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 - JMP runtime·memhash64Fallback(SB) - -TEXT runtime·return0(SB), NOSPLIT, $0 - MOVW $0, R3 - RET - -// Called from cgo wrappers, this function returns g->m->curg.stack.hi. -// Must obey the gcc calling convention. -#ifdef GOOS_aix -// On AIX, _cgo_topofstack is defined in runtime/cgo, because it must -// be a longcall in order to prevent trampolines from ld. -TEXT __cgo_topofstack(SB),NOSPLIT|NOFRAME,$0 -#else -TEXT _cgo_topofstack(SB),NOSPLIT|NOFRAME,$0 -#endif - // g (R30) and R31 are callee-save in the C ABI, so save them - MOVD g, R4 - MOVD R31, R5 - MOVD LR, R6 - - BL runtime·load_g(SB) // clobbers g (R30), R31 - MOVD g_m(g), R3 - MOVD m_curg(R3), R3 - MOVD (g_stack+stack_hi)(R3), R3 - - MOVD R4, g - MOVD R5, R31 - MOVD R6, LR - RET - -// The top-most function running on a goroutine -// returns to goexit+PCQuantum. -// -// When dynamically linking Go, it can be returned to from a function -// implemented in a different module and so needs to reload the TOC pointer -// from the stack (although this function declares that it does not set up x-a -// frame, newproc1 does in fact allocate one for goexit and saves the TOC -// pointer in the correct place). -// goexit+_PCQuantum is halfway through the usual global entry point prologue -// that derives r2 from r12 which is a bit silly, but not harmful. -TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 - MOVD 24(R1), R2 - BL runtime·goexit1(SB) // does not return - // traceback from goexit1 must hit code range of goexit - MOVD R0, R0 // NOP - -// prepGoExitFrame saves the current TOC pointer (i.e. the TOC pointer for the -// module containing runtime) to the frame that goexit will execute in when -// the goroutine exits. It's implemented in assembly mainly because that's the -// easiest way to get access to R2. -TEXT runtime·prepGoExitFrame(SB),NOSPLIT,$0-8 - MOVD sp+0(FP), R3 - MOVD R2, 24(R3) - RET - -TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0 - ADD $-8, R1 - MOVD R31, 0(R1) - MOVD runtime·lastmoduledatap(SB), R4 - MOVD R3, moduledata_next(R4) - MOVD R3, runtime·lastmoduledatap(SB) - MOVD 0(R1), R31 - ADD $8, R1 - RET - -TEXT ·checkASM(SB),NOSPLIT,$0-1 - MOVW $1, R3 - MOVB R3, ret+0(FP) - RET - -// gcWriteBarrier informs the GC about heap pointer writes. -// -// gcWriteBarrier does NOT follow the Go ABI. It accepts the -// number of bytes of buffer needed in R29, and returns a pointer -// to the buffer space in R29. -// It clobbers condition codes. -// It does not clobber R0 through R17 (except special registers), -// but may clobber any other register, *including* R31. -TEXT gcWriteBarrier<>(SB),NOSPLIT,$120 - // The standard prologue clobbers R31. - // We use R18, R19, and R31 as scratch registers. -retry: - MOVD g_m(g), R18 - MOVD m_p(R18), R18 - MOVD (p_wbBuf+wbBuf_next)(R18), R19 - MOVD (p_wbBuf+wbBuf_end)(R18), R31 - // Increment wbBuf.next position. - ADD R29, R19 - // Is the buffer full? - CMPU R31, R19 - BLT flush - // Commit to the larger buffer. - MOVD R19, (p_wbBuf+wbBuf_next)(R18) - // Make return value (the original next position) - SUB R29, R19, R29 - RET - -flush: - // Save registers R0 through R15 since these were not saved by the caller. - // We don't save all registers on ppc64 because it takes too much space. - MOVD R20, (FIXED_FRAME+0)(R1) - MOVD R21, (FIXED_FRAME+8)(R1) - // R0 is always 0, so no need to spill. - // R1 is SP. - // R2 is SB. - MOVD R3, (FIXED_FRAME+16)(R1) - MOVD R4, (FIXED_FRAME+24)(R1) - MOVD R5, (FIXED_FRAME+32)(R1) - MOVD R6, (FIXED_FRAME+40)(R1) - MOVD R7, (FIXED_FRAME+48)(R1) - MOVD R8, (FIXED_FRAME+56)(R1) - MOVD R9, (FIXED_FRAME+64)(R1) - MOVD R10, (FIXED_FRAME+72)(R1) - // R11, R12 may be clobbered by external-linker-inserted trampoline - // R13 is REGTLS - MOVD R14, (FIXED_FRAME+80)(R1) - MOVD R15, (FIXED_FRAME+88)(R1) - MOVD R16, (FIXED_FRAME+96)(R1) - MOVD R17, (FIXED_FRAME+104)(R1) - MOVD R29, (FIXED_FRAME+112)(R1) - - CALL runtime·wbBufFlush(SB) - - MOVD (FIXED_FRAME+0)(R1), R20 - MOVD (FIXED_FRAME+8)(R1), R21 - MOVD (FIXED_FRAME+16)(R1), R3 - MOVD (FIXED_FRAME+24)(R1), R4 - MOVD (FIXED_FRAME+32)(R1), R5 - MOVD (FIXED_FRAME+40)(R1), R6 - MOVD (FIXED_FRAME+48)(R1), R7 - MOVD (FIXED_FRAME+56)(R1), R8 - MOVD (FIXED_FRAME+64)(R1), R9 - MOVD (FIXED_FRAME+72)(R1), R10 - MOVD (FIXED_FRAME+80)(R1), R14 - MOVD (FIXED_FRAME+88)(R1), R15 - MOVD (FIXED_FRAME+96)(R1), R16 - MOVD (FIXED_FRAME+104)(R1), R17 - MOVD (FIXED_FRAME+112)(R1), R29 - JMP retry - -TEXT runtime·gcWriteBarrier1(SB),NOSPLIT,$0 - MOVD $8, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier2(SB),NOSPLIT,$0 - MOVD $16, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier3(SB),NOSPLIT,$0 - MOVD $24, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier4(SB),NOSPLIT,$0 - MOVD $32, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier5(SB),NOSPLIT,$0 - MOVD $40, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier6(SB),NOSPLIT,$0 - MOVD $48, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier7(SB),NOSPLIT,$0 - MOVD $56, R29 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier8(SB),NOSPLIT,$0 - MOVD $64, R29 - JMP gcWriteBarrier<>(SB) - -DATA debugCallFrameTooLarge<>+0x00(SB)/20, $"call frame too large" -GLOBL debugCallFrameTooLarge<>(SB), RODATA, $20 // Size duplicated below - -// debugCallV2 is the entry point for debugger-injected function -// calls on running goroutines. It informs the runtime that a -// debug call has been injected and creates a call frame for the -// debugger to fill in. -// -// To inject a function call, a debugger should: -// 1. Check that the goroutine is in state _Grunning and that -// there are at least 320 bytes free on the stack. -// 2. Set SP as SP-32. -// 3. Store the current LR in (SP) (using the SP after step 2). -// 4. Store the current PC in the LR register. -// 5. Write the desired argument frame size at SP-32 -// 6. Save all machine registers (including flags and floating point registers) -// so they can be restored later by the debugger. -// 7. Set the PC to debugCallV2 and resume execution. -// -// If the goroutine is in state _Grunnable, then it's not generally -// safe to inject a call because it may return out via other runtime -// operations. Instead, the debugger should unwind the stack to find -// the return to non-runtime code, add a temporary breakpoint there, -// and inject the call once that breakpoint is hit. -// -// If the goroutine is in any other state, it's not safe to inject a call. -// -// This function communicates back to the debugger by setting R20 and -// invoking TW to raise a breakpoint signal. Note that the signal PC of -// the signal triggered by the TW instruction is the PC where the signal -// is trapped, not the next PC, so to resume execution, the debugger needs -// to set the signal PC to PC+4. See the comments in the implementation for -// the protocol the debugger is expected to follow. InjectDebugCall in the -// runtime tests demonstrates this protocol. -// The debugger must ensure that any pointers passed to the function -// obey escape analysis requirements. Specifically, it must not pass -// a stack pointer to an escaping argument. debugCallV2 cannot check -// this invariant. -// -// This is ABIInternal because Go code injects its PC directly into new -// goroutine stacks. -#ifdef GOARCH_ppc64le -TEXT runtime·debugCallV2(SB), NOSPLIT|NOFRAME, $0-0 - // save scratch register R31 first - MOVD R31, -184(R1) - MOVD 0(R1), R31 - // save caller LR - MOVD R31, -304(R1) - MOVD -32(R1), R31 - // save argument frame size - MOVD R31, -192(R1) - MOVD LR, R31 - MOVD R31, -320(R1) - ADD $-320, R1 - // save all registers that can contain pointers - // and the CR register - MOVW CR, R31 - MOVD R31, 8(R1) - MOVD R2, 24(R1) - MOVD R3, 56(R1) - MOVD R4, 64(R1) - MOVD R5, 72(R1) - MOVD R6, 80(R1) - MOVD R7, 88(R1) - MOVD R8, 96(R1) - MOVD R9, 104(R1) - MOVD R10, 112(R1) - MOVD R11, 120(R1) - MOVD R12, 144(R1) - MOVD R13, 152(R1) - MOVD R14, 160(R1) - MOVD R15, 168(R1) - MOVD R16, 176(R1) - MOVD R17, 184(R1) - MOVD R18, 192(R1) - MOVD R19, 200(R1) - MOVD R20, 208(R1) - MOVD R21, 216(R1) - MOVD R22, 224(R1) - MOVD R23, 232(R1) - MOVD R24, 240(R1) - MOVD R25, 248(R1) - MOVD R26, 256(R1) - MOVD R27, 264(R1) - MOVD R28, 272(R1) - MOVD R29, 280(R1) - MOVD g, 288(R1) - MOVD LR, R31 - MOVD R31, 32(R1) - CALL runtime·debugCallCheck(SB) - MOVD 40(R1), R22 - XOR R0, R0 - CMP R22, R0 - BEQ good - MOVD 48(R1), R22 - MOVD $8, R20 - TW $31, R0, R0 - - BR restore - -good: -#define DEBUG_CALL_DISPATCH(NAME,MAXSIZE) \ - MOVD $MAXSIZE, R23; \ - CMP R26, R23; \ - BGT 5(PC); \ - MOVD $NAME(SB), R26; \ - MOVD R26, 32(R1); \ - CALL runtime·debugCallWrap(SB); \ - BR restore - - // the argument frame size - MOVD 128(R1), R26 - - DEBUG_CALL_DISPATCH(debugCall32<>, 32) - DEBUG_CALL_DISPATCH(debugCall64<>, 64) - DEBUG_CALL_DISPATCH(debugCall128<>, 128) - DEBUG_CALL_DISPATCH(debugCall256<>, 256) - DEBUG_CALL_DISPATCH(debugCall512<>, 512) - DEBUG_CALL_DISPATCH(debugCall1024<>, 1024) - DEBUG_CALL_DISPATCH(debugCall2048<>, 2048) - DEBUG_CALL_DISPATCH(debugCall4096<>, 4096) - DEBUG_CALL_DISPATCH(debugCall8192<>, 8192) - DEBUG_CALL_DISPATCH(debugCall16384<>, 16384) - DEBUG_CALL_DISPATCH(debugCall32768<>, 32768) - DEBUG_CALL_DISPATCH(debugCall65536<>, 65536) - // The frame size is too large. Report the error. - MOVD $debugCallFrameTooLarge<>(SB), R22 - MOVD R22, 32(R1) - MOVD $20, R22 - // length of debugCallFrameTooLarge string - MOVD R22, 40(R1) - MOVD $8, R20 - TW $31, R0, R0 - BR restore -restore: - MOVD $16, R20 - TW $31, R0, R0 - // restore all registers that can contain - // pointers including CR - MOVD 8(R1), R31 - MOVW R31, CR - MOVD 24(R1), R2 - MOVD 56(R1), R3 - MOVD 64(R1), R4 - MOVD 72(R1), R5 - MOVD 80(R1), R6 - MOVD 88(R1), R7 - MOVD 96(R1), R8 - MOVD 104(R1), R9 - MOVD 112(R1), R10 - MOVD 120(R1), R11 - MOVD 144(R1), R12 - MOVD 152(R1), R13 - MOVD 160(R1), R14 - MOVD 168(R1), R15 - MOVD 176(R1), R16 - MOVD 184(R1), R17 - MOVD 192(R1), R18 - MOVD 200(R1), R19 - MOVD 208(R1), R20 - MOVD 216(R1), R21 - MOVD 224(R1), R22 - MOVD 232(R1), R23 - MOVD 240(R1), R24 - MOVD 248(R1), R25 - MOVD 256(R1), R26 - MOVD 264(R1), R27 - MOVD 272(R1), R28 - MOVD 280(R1), R29 - MOVD 288(R1), g - MOVD 16(R1), R31 - // restore old LR - MOVD R31, LR - // restore caller PC - MOVD 0(R1), CTR - MOVD 136(R1), R31 - // Add 32 bytes more to compensate for SP change in saveSigContext - ADD $352, R1 - JMP (CTR) -#endif -#define DEBUG_CALL_FN(NAME,MAXSIZE) \ -TEXT NAME(SB),WRAPPER,$MAXSIZE-0; \ - NO_LOCAL_POINTERS; \ - MOVD $0, R20; \ - TW $31, R0, R0 \ - MOVD $1, R20; \ - TW $31, R0, R0 \ - RET -DEBUG_CALL_FN(debugCall32<>, 32) -DEBUG_CALL_FN(debugCall64<>, 64) -DEBUG_CALL_FN(debugCall128<>, 128) -DEBUG_CALL_FN(debugCall256<>, 256) -DEBUG_CALL_FN(debugCall512<>, 512) -DEBUG_CALL_FN(debugCall1024<>, 1024) -DEBUG_CALL_FN(debugCall2048<>, 2048) -DEBUG_CALL_FN(debugCall4096<>, 4096) -DEBUG_CALL_FN(debugCall8192<>, 8192) -DEBUG_CALL_FN(debugCall16384<>, 16384) -DEBUG_CALL_FN(debugCall32768<>, 32768) -DEBUG_CALL_FN(debugCall65536<>, 65536) - -#ifdef GOARCH_ppc64le -// func debugCallPanicked(val interface{}) -TEXT runtime·debugCallPanicked(SB),NOSPLIT,$32-16 - // Copy the panic value to the top of stack at SP+32. - MOVD val_type+0(FP), R31 - MOVD R31, 32(R1) - MOVD val_data+8(FP), R31 - MOVD R31, 40(R1) - MOVD $2, R20 - TW $31, R0, R0 - RET -#endif -// Note: these functions use a special calling convention to save generated code space. -// Arguments are passed in registers, but the space for those arguments are allocated -// in the caller's stack frame. These stubs write the args into that stack space and -// then tail call to the corresponding runtime handler. -// The tail call makes these stubs disappear in backtraces. -TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 - JMP runtime·goPanicIndex(SB) -TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 - JMP runtime·goPanicIndexU(SB) -TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 - MOVD R4, R3 - MOVD R5, R4 - JMP runtime·goPanicSliceAlen(SB) -TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 - MOVD R4, R3 - MOVD R5, R4 - JMP runtime·goPanicSliceAlenU(SB) -TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 - MOVD R4, R3 - MOVD R5, R4 - JMP runtime·goPanicSliceAcap(SB) -TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 - MOVD R4, R3 - MOVD R5, R4 - JMP runtime·goPanicSliceAcapU(SB) -TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 - JMP runtime·goPanicSliceB(SB) -TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 - JMP runtime·goPanicSliceBU(SB) -TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 - MOVD R5, R3 - MOVD R6, R4 - JMP runtime·goPanicSlice3Alen(SB) -TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 - MOVD R5, R3 - MOVD R6, R4 - JMP runtime·goPanicSlice3AlenU(SB) -TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 - MOVD R5, R3 - MOVD R6, R4 - JMP runtime·goPanicSlice3Acap(SB) -TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 - MOVD R5, R3 - MOVD R6, R4 - JMP runtime·goPanicSlice3AcapU(SB) -TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 - MOVD R4, R3 - MOVD R5, R4 - JMP runtime·goPanicSlice3B(SB) -TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 - MOVD R4, R3 - MOVD R5, R4 - JMP runtime·goPanicSlice3BU(SB) -TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 - JMP runtime·goPanicSlice3C(SB) -TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 - JMP runtime·goPanicSlice3CU(SB) -TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 - MOVD R5, R3 - MOVD R6, R4 - JMP runtime·goPanicSliceConvert(SB) - -// These functions are used when internal linking cgo with external -// objects compiled with the -Os on gcc. They reduce prologue/epilogue -// size by deferring preservation of callee-save registers to a shared -// function. These are defined in PPC64 ELFv2 2.3.3 (but also present -// in ELFv1) -// -// These appear unused, but the linker will redirect calls to functions -// like _savegpr0_14 or _restgpr1_14 to runtime.elf_savegpr0 or -// runtime.elf_restgpr1 with an appropriate offset based on the number -// register operations required when linking external objects which -// make these calls. For GPR/FPR saves, the minimum register value is -// 14, for VR it is 20. -// -// These are only used when linking such cgo code internally. Note, R12 -// and R0 may be used in different ways than regular ELF compliant -// functions. -TEXT runtime·elf_savegpr0(SB),NOSPLIT|NOFRAME,$0 - // R0 holds the LR of the caller's caller, R1 holds save location - MOVD R14, -144(R1) - MOVD R15, -136(R1) - MOVD R16, -128(R1) - MOVD R17, -120(R1) - MOVD R18, -112(R1) - MOVD R19, -104(R1) - MOVD R20, -96(R1) - MOVD R21, -88(R1) - MOVD R22, -80(R1) - MOVD R23, -72(R1) - MOVD R24, -64(R1) - MOVD R25, -56(R1) - MOVD R26, -48(R1) - MOVD R27, -40(R1) - MOVD R28, -32(R1) - MOVD R29, -24(R1) - MOVD g, -16(R1) - MOVD R31, -8(R1) - MOVD R0, 16(R1) - RET -TEXT runtime·elf_restgpr0(SB),NOSPLIT|NOFRAME,$0 - // R1 holds save location. This returns to the LR saved on stack (bypassing the caller) - MOVD -144(R1), R14 - MOVD -136(R1), R15 - MOVD -128(R1), R16 - MOVD -120(R1), R17 - MOVD -112(R1), R18 - MOVD -104(R1), R19 - MOVD -96(R1), R20 - MOVD -88(R1), R21 - MOVD -80(R1), R22 - MOVD -72(R1), R23 - MOVD -64(R1), R24 - MOVD -56(R1), R25 - MOVD -48(R1), R26 - MOVD -40(R1), R27 - MOVD -32(R1), R28 - MOVD -24(R1), R29 - MOVD -16(R1), g - MOVD -8(R1), R31 - MOVD 16(R1), R0 // Load and return to saved LR - MOVD R0, LR - RET -TEXT runtime·elf_savegpr1(SB),NOSPLIT|NOFRAME,$0 - // R12 holds the save location - MOVD R14, -144(R12) - MOVD R15, -136(R12) - MOVD R16, -128(R12) - MOVD R17, -120(R12) - MOVD R18, -112(R12) - MOVD R19, -104(R12) - MOVD R20, -96(R12) - MOVD R21, -88(R12) - MOVD R22, -80(R12) - MOVD R23, -72(R12) - MOVD R24, -64(R12) - MOVD R25, -56(R12) - MOVD R26, -48(R12) - MOVD R27, -40(R12) - MOVD R28, -32(R12) - MOVD R29, -24(R12) - MOVD g, -16(R12) - MOVD R31, -8(R12) - RET -TEXT runtime·elf_restgpr1(SB),NOSPLIT|NOFRAME,$0 - // R12 holds the save location - MOVD -144(R12), R14 - MOVD -136(R12), R15 - MOVD -128(R12), R16 - MOVD -120(R12), R17 - MOVD -112(R12), R18 - MOVD -104(R12), R19 - MOVD -96(R12), R20 - MOVD -88(R12), R21 - MOVD -80(R12), R22 - MOVD -72(R12), R23 - MOVD -64(R12), R24 - MOVD -56(R12), R25 - MOVD -48(R12), R26 - MOVD -40(R12), R27 - MOVD -32(R12), R28 - MOVD -24(R12), R29 - MOVD -16(R12), g - MOVD -8(R12), R31 - RET -TEXT runtime·elf_savefpr(SB),NOSPLIT|NOFRAME,$0 - // R0 holds the LR of the caller's caller, R1 holds save location - FMOVD F14, -144(R1) - FMOVD F15, -136(R1) - FMOVD F16, -128(R1) - FMOVD F17, -120(R1) - FMOVD F18, -112(R1) - FMOVD F19, -104(R1) - FMOVD F20, -96(R1) - FMOVD F21, -88(R1) - FMOVD F22, -80(R1) - FMOVD F23, -72(R1) - FMOVD F24, -64(R1) - FMOVD F25, -56(R1) - FMOVD F26, -48(R1) - FMOVD F27, -40(R1) - FMOVD F28, -32(R1) - FMOVD F29, -24(R1) - FMOVD F30, -16(R1) - FMOVD F31, -8(R1) - MOVD R0, 16(R1) - RET -TEXT runtime·elf_restfpr(SB),NOSPLIT|NOFRAME,$0 - // R1 holds save location. This returns to the LR saved on stack (bypassing the caller) - FMOVD -144(R1), F14 - FMOVD -136(R1), F15 - FMOVD -128(R1), F16 - FMOVD -120(R1), F17 - FMOVD -112(R1), F18 - FMOVD -104(R1), F19 - FMOVD -96(R1), F20 - FMOVD -88(R1), F21 - FMOVD -80(R1), F22 - FMOVD -72(R1), F23 - FMOVD -64(R1), F24 - FMOVD -56(R1), F25 - FMOVD -48(R1), F26 - FMOVD -40(R1), F27 - FMOVD -32(R1), F28 - FMOVD -24(R1), F29 - FMOVD -16(R1), F30 - FMOVD -8(R1), F31 - MOVD 16(R1), R0 // Load and return to saved LR - MOVD R0, LR - RET -TEXT runtime·elf_savevr(SB),NOSPLIT|NOFRAME,$0 - // R0 holds the save location, R12 is clobbered - MOVD $-192, R12 - STVX V20, (R0+R12) - MOVD $-176, R12 - STVX V21, (R0+R12) - MOVD $-160, R12 - STVX V22, (R0+R12) - MOVD $-144, R12 - STVX V23, (R0+R12) - MOVD $-128, R12 - STVX V24, (R0+R12) - MOVD $-112, R12 - STVX V25, (R0+R12) - MOVD $-96, R12 - STVX V26, (R0+R12) - MOVD $-80, R12 - STVX V27, (R0+R12) - MOVD $-64, R12 - STVX V28, (R0+R12) - MOVD $-48, R12 - STVX V29, (R0+R12) - MOVD $-32, R12 - STVX V30, (R0+R12) - MOVD $-16, R12 - STVX V31, (R0+R12) - RET -TEXT runtime·elf_restvr(SB),NOSPLIT|NOFRAME,$0 - // R0 holds the save location, R12 is clobbered - MOVD $-192, R12 - LVX (R0+R12), V20 - MOVD $-176, R12 - LVX (R0+R12), V21 - MOVD $-160, R12 - LVX (R0+R12), V22 - MOVD $-144, R12 - LVX (R0+R12), V23 - MOVD $-128, R12 - LVX (R0+R12), V24 - MOVD $-112, R12 - LVX (R0+R12), V25 - MOVD $-96, R12 - LVX (R0+R12), V26 - MOVD $-80, R12 - LVX (R0+R12), V27 - MOVD $-64, R12 - LVX (R0+R12), V28 - MOVD $-48, R12 - LVX (R0+R12), V29 - MOVD $-32, R12 - LVX (R0+R12), V30 - MOVD $-16, R12 - LVX (R0+R12), V31 - RET diff --git a/contrib/go/_std_1.22/src/runtime/asm_s390x.s b/contrib/go/_std_1.22/src/runtime/asm_s390x.s deleted file mode 100644 index a8e1424bf181..000000000000 --- a/contrib/go/_std_1.22/src/runtime/asm_s390x.s +++ /dev/null @@ -1,951 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go_asm.h" -#include "go_tls.h" -#include "funcdata.h" -#include "textflag.h" - -// _rt0_s390x_lib is common startup code for s390x systems when -// using -buildmode=c-archive or -buildmode=c-shared. The linker will -// arrange to invoke this function as a global constructor (for -// c-archive) or when the shared library is loaded (for c-shared). -// We expect argc and argv to be passed in the usual C ABI registers -// R2 and R3. -TEXT _rt0_s390x_lib(SB), NOSPLIT|NOFRAME, $0 - STMG R6, R15, 48(R15) - MOVD R2, _rt0_s390x_lib_argc<>(SB) - MOVD R3, _rt0_s390x_lib_argv<>(SB) - - // Save R6-R15 in the register save area of the calling function. - STMG R6, R15, 48(R15) - - // Allocate 80 bytes on the stack. - MOVD $-80(R15), R15 - - // Save F8-F15 in our stack frame. - FMOVD F8, 16(R15) - FMOVD F9, 24(R15) - FMOVD F10, 32(R15) - FMOVD F11, 40(R15) - FMOVD F12, 48(R15) - FMOVD F13, 56(R15) - FMOVD F14, 64(R15) - FMOVD F15, 72(R15) - - // Synchronous initialization. - MOVD $runtime·libpreinit(SB), R1 - BL R1 - - // Create a new thread to finish Go runtime initialization. - MOVD _cgo_sys_thread_create(SB), R1 - CMP R1, $0 - BEQ nocgo - MOVD $_rt0_s390x_lib_go(SB), R2 - MOVD $0, R3 - BL R1 - BR restore - -nocgo: - MOVD $0x800000, R1 // stacksize - MOVD R1, 0(R15) - MOVD $_rt0_s390x_lib_go(SB), R1 - MOVD R1, 8(R15) // fn - MOVD $runtime·newosproc(SB), R1 - BL R1 - -restore: - // Restore F8-F15 from our stack frame. - FMOVD 16(R15), F8 - FMOVD 24(R15), F9 - FMOVD 32(R15), F10 - FMOVD 40(R15), F11 - FMOVD 48(R15), F12 - FMOVD 56(R15), F13 - FMOVD 64(R15), F14 - FMOVD 72(R15), F15 - MOVD $80(R15), R15 - - // Restore R6-R15. - LMG 48(R15), R6, R15 - RET - -// _rt0_s390x_lib_go initializes the Go runtime. -// This is started in a separate thread by _rt0_s390x_lib. -TEXT _rt0_s390x_lib_go(SB), NOSPLIT|NOFRAME, $0 - MOVD _rt0_s390x_lib_argc<>(SB), R2 - MOVD _rt0_s390x_lib_argv<>(SB), R3 - MOVD $runtime·rt0_go(SB), R1 - BR R1 - -DATA _rt0_s390x_lib_argc<>(SB)/8, $0 -GLOBL _rt0_s390x_lib_argc<>(SB), NOPTR, $8 -DATA _rt0_s90x_lib_argv<>(SB)/8, $0 -GLOBL _rt0_s390x_lib_argv<>(SB), NOPTR, $8 - -TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 - // R2 = argc; R3 = argv; R11 = temp; R13 = g; R15 = stack pointer - // C TLS base pointer in AR0:AR1 - - // initialize essential registers - XOR R0, R0 - - SUB $24, R15 - MOVW R2, 8(R15) // argc - MOVD R3, 16(R15) // argv - - // create istack out of the given (operating system) stack. - // _cgo_init may update stackguard. - MOVD $runtime·g0(SB), g - MOVD R15, R11 - SUB $(64*1024), R11 - MOVD R11, g_stackguard0(g) - MOVD R11, g_stackguard1(g) - MOVD R11, (g_stack+stack_lo)(g) - MOVD R15, (g_stack+stack_hi)(g) - - // if there is a _cgo_init, call it using the gcc ABI. - MOVD _cgo_init(SB), R11 - CMPBEQ R11, $0, nocgo - MOVW AR0, R4 // (AR0 << 32 | AR1) is the TLS base pointer; MOVD is translated to EAR - SLD $32, R4, R4 - MOVW AR1, R4 // arg 2: TLS base pointer - MOVD $setg_gcc<>(SB), R3 // arg 1: setg - MOVD g, R2 // arg 0: G - // C functions expect 160 bytes of space on caller stack frame - // and an 8-byte aligned stack pointer - MOVD R15, R9 // save current stack (R9 is preserved in the Linux ABI) - SUB $160, R15 // reserve 160 bytes - MOVD $~7, R6 - AND R6, R15 // 8-byte align - BL R11 // this call clobbers volatile registers according to Linux ABI (R0-R5, R14) - MOVD R9, R15 // restore stack - XOR R0, R0 // zero R0 - -nocgo: - // update stackguard after _cgo_init - MOVD (g_stack+stack_lo)(g), R2 - ADD $const_stackGuard, R2 - MOVD R2, g_stackguard0(g) - MOVD R2, g_stackguard1(g) - - // set the per-goroutine and per-mach "registers" - MOVD $runtime·m0(SB), R2 - - // save m->g0 = g0 - MOVD g, m_g0(R2) - // save m0 to g0->m - MOVD R2, g_m(g) - - BL runtime·check(SB) - - // argc/argv are already prepared on stack - BL runtime·args(SB) - BL runtime·checkS390xCPU(SB) - BL runtime·osinit(SB) - BL runtime·schedinit(SB) - - // create a new goroutine to start program - MOVD $runtime·mainPC(SB), R2 // entry - SUB $16, R15 - MOVD R2, 8(R15) - MOVD $0, 0(R15) - BL runtime·newproc(SB) - ADD $16, R15 - - // start this M - BL runtime·mstart(SB) - - MOVD $0, 1(R0) - RET - -DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) -GLOBL runtime·mainPC(SB),RODATA,$8 - -TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0 - BRRK - RET - -TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0 - RET - -TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 - CALL runtime·mstart0(SB) - RET // not reached - -/* - * go-routine - */ - -// void gogo(Gobuf*) -// restore state from Gobuf; longjmp -TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8 - MOVD buf+0(FP), R5 - MOVD gobuf_g(R5), R6 - MOVD 0(R6), R7 // make sure g != nil - BR gogo<>(SB) - -TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 - MOVD R6, g - BL runtime·save_g(SB) - - MOVD 0(g), R4 - MOVD gobuf_sp(R5), R15 - MOVD gobuf_lr(R5), LR - MOVD gobuf_ret(R5), R3 - MOVD gobuf_ctxt(R5), R12 - MOVD $0, gobuf_sp(R5) - MOVD $0, gobuf_ret(R5) - MOVD $0, gobuf_lr(R5) - MOVD $0, gobuf_ctxt(R5) - CMP R0, R0 // set condition codes for == test, needed by stack split - MOVD gobuf_pc(R5), R6 - BR (R6) - -// void mcall(fn func(*g)) -// Switch to m->g0's stack, call fn(g). -// Fn must never return. It should gogo(&g->sched) -// to keep running g. -TEXT runtime·mcall(SB), NOSPLIT, $-8-8 - // Save caller state in g->sched - MOVD R15, (g_sched+gobuf_sp)(g) - MOVD LR, (g_sched+gobuf_pc)(g) - MOVD $0, (g_sched+gobuf_lr)(g) - - // Switch to m->g0 & its stack, call fn. - MOVD g, R3 - MOVD g_m(g), R8 - MOVD m_g0(R8), g - BL runtime·save_g(SB) - CMP g, R3 - BNE 2(PC) - BR runtime·badmcall(SB) - MOVD fn+0(FP), R12 // context - MOVD 0(R12), R4 // code pointer - MOVD (g_sched+gobuf_sp)(g), R15 // sp = m->g0->sched.sp - SUB $16, R15 - MOVD R3, 8(R15) - MOVD $0, 0(R15) - BL (R4) - BR runtime·badmcall2(SB) - -// systemstack_switch is a dummy routine that systemstack leaves at the bottom -// of the G stack. We need to distinguish the routine that -// lives at the bottom of the G stack from the one that lives -// at the top of the system stack because the one at the top of -// the system stack terminates the stack walk (see topofstack()). -TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 - UNDEF - BL (LR) // make sure this function is not leaf - RET - -// func systemstack(fn func()) -TEXT runtime·systemstack(SB), NOSPLIT, $0-8 - MOVD fn+0(FP), R3 // R3 = fn - MOVD R3, R12 // context - MOVD g_m(g), R4 // R4 = m - - MOVD m_gsignal(R4), R5 // R5 = gsignal - CMPBEQ g, R5, noswitch - - MOVD m_g0(R4), R5 // R5 = g0 - CMPBEQ g, R5, noswitch - - MOVD m_curg(R4), R6 - CMPBEQ g, R6, switch - - // Bad: g is not gsignal, not g0, not curg. What is it? - // Hide call from linker nosplit analysis. - MOVD $runtime·badsystemstack(SB), R3 - BL (R3) - BL runtime·abort(SB) - -switch: - // save our state in g->sched. Pretend to - // be systemstack_switch if the G stack is scanned. - BL gosave_systemstack_switch<>(SB) - - // switch to g0 - MOVD R5, g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R15 - - // call target function - MOVD 0(R12), R3 // code pointer - BL (R3) - - // switch back to g - MOVD g_m(g), R3 - MOVD m_curg(R3), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R15 - MOVD $0, (g_sched+gobuf_sp)(g) - RET - -noswitch: - // already on m stack, just call directly - // Using a tail call here cleans up tracebacks since we won't stop - // at an intermediate systemstack. - MOVD 0(R12), R3 // code pointer - MOVD 0(R15), LR // restore LR - ADD $8, R15 - BR (R3) - -/* - * support for morestack - */ - -// Called during function prolog when more stack is needed. -// Caller has already loaded: -// R3: framesize, R4: argsize, R5: LR -// -// The traceback routines see morestack on a g0 as being -// the top of a stack (for example, morestack calling newstack -// calling the scheduler calling newm calling gc), so we must -// record an argument size. For that purpose, it has no arguments. -TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 - // Cannot grow scheduler stack (m->g0). - MOVD g_m(g), R7 - MOVD m_g0(R7), R8 - CMPBNE g, R8, 3(PC) - BL runtime·badmorestackg0(SB) - BL runtime·abort(SB) - - // Cannot grow signal stack (m->gsignal). - MOVD m_gsignal(R7), R8 - CMP g, R8 - BNE 3(PC) - BL runtime·badmorestackgsignal(SB) - BL runtime·abort(SB) - - // Called from f. - // Set g->sched to context in f. - MOVD R15, (g_sched+gobuf_sp)(g) - MOVD LR, R8 - MOVD R8, (g_sched+gobuf_pc)(g) - MOVD R5, (g_sched+gobuf_lr)(g) - MOVD R12, (g_sched+gobuf_ctxt)(g) - - // Called from f. - // Set m->morebuf to f's caller. - MOVD R5, (m_morebuf+gobuf_pc)(R7) // f's caller's PC - MOVD R15, (m_morebuf+gobuf_sp)(R7) // f's caller's SP - MOVD g, (m_morebuf+gobuf_g)(R7) - - // Call newstack on m->g0's stack. - MOVD m_g0(R7), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R15 - // Create a stack frame on g0 to call newstack. - MOVD $0, -8(R15) // Zero saved LR in frame - SUB $8, R15 - BL runtime·newstack(SB) - - // Not reached, but make sure the return PC from the call to newstack - // is still in this function, and not the beginning of the next. - UNDEF - -TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 - // Force SPWRITE. This function doesn't actually write SP, - // but it is called with a special calling convention where - // the caller doesn't save LR on stack but passes it as a - // register (R5), and the unwinder currently doesn't understand. - // Make it SPWRITE to stop unwinding. (See issue 54332) - MOVD R15, R15 - - MOVD $0, R12 - BR runtime·morestack(SB) - -// reflectcall: call a function with the given argument list -// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). -// we don't have variable-sized frames, so we use a small number -// of constant-sized-frame functions to encode a few bits of size in the pc. -// Caution: ugly multiline assembly macros in your future! - -#define DISPATCH(NAME,MAXSIZE) \ - MOVD $MAXSIZE, R4; \ - CMP R3, R4; \ - BGT 3(PC); \ - MOVD $NAME(SB), R5; \ - BR (R5) -// Note: can't just "BR NAME(SB)" - bad inlining results. - -TEXT ·reflectcall(SB), NOSPLIT, $-8-48 - MOVWZ frameSize+32(FP), R3 - DISPATCH(runtime·call16, 16) - DISPATCH(runtime·call32, 32) - DISPATCH(runtime·call64, 64) - DISPATCH(runtime·call128, 128) - DISPATCH(runtime·call256, 256) - DISPATCH(runtime·call512, 512) - DISPATCH(runtime·call1024, 1024) - DISPATCH(runtime·call2048, 2048) - DISPATCH(runtime·call4096, 4096) - DISPATCH(runtime·call8192, 8192) - DISPATCH(runtime·call16384, 16384) - DISPATCH(runtime·call32768, 32768) - DISPATCH(runtime·call65536, 65536) - DISPATCH(runtime·call131072, 131072) - DISPATCH(runtime·call262144, 262144) - DISPATCH(runtime·call524288, 524288) - DISPATCH(runtime·call1048576, 1048576) - DISPATCH(runtime·call2097152, 2097152) - DISPATCH(runtime·call4194304, 4194304) - DISPATCH(runtime·call8388608, 8388608) - DISPATCH(runtime·call16777216, 16777216) - DISPATCH(runtime·call33554432, 33554432) - DISPATCH(runtime·call67108864, 67108864) - DISPATCH(runtime·call134217728, 134217728) - DISPATCH(runtime·call268435456, 268435456) - DISPATCH(runtime·call536870912, 536870912) - DISPATCH(runtime·call1073741824, 1073741824) - MOVD $runtime·badreflectcall(SB), R5 - BR (R5) - -#define CALLFN(NAME,MAXSIZE) \ -TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ - NO_LOCAL_POINTERS; \ - /* copy arguments to stack */ \ - MOVD stackArgs+16(FP), R4; \ - MOVWZ stackArgsSize+24(FP), R5; \ - MOVD $stack-MAXSIZE(SP), R6; \ -loopArgs: /* copy 256 bytes at a time */ \ - CMP R5, $256; \ - BLT tailArgs; \ - SUB $256, R5; \ - MVC $256, 0(R4), 0(R6); \ - MOVD $256(R4), R4; \ - MOVD $256(R6), R6; \ - BR loopArgs; \ -tailArgs: /* copy remaining bytes */ \ - CMP R5, $0; \ - BEQ callFunction; \ - SUB $1, R5; \ - EXRL $callfnMVC<>(SB), R5; \ -callFunction: \ - MOVD f+8(FP), R12; \ - MOVD (R12), R8; \ - PCDATA $PCDATA_StackMapIndex, $0; \ - BL (R8); \ - /* copy return values back */ \ - MOVD stackArgsType+0(FP), R7; \ - MOVD stackArgs+16(FP), R6; \ - MOVWZ stackArgsSize+24(FP), R5; \ - MOVD $stack-MAXSIZE(SP), R4; \ - MOVWZ stackRetOffset+28(FP), R1; \ - ADD R1, R4; \ - ADD R1, R6; \ - SUB R1, R5; \ - BL callRet<>(SB); \ - RET - -// callRet copies return values back at the end of call*. This is a -// separate function so it can allocate stack space for the arguments -// to reflectcallmove. It does not follow the Go ABI; it expects its -// arguments in registers. -TEXT callRet<>(SB), NOSPLIT, $40-0 - MOVD R7, 8(R15) - MOVD R6, 16(R15) - MOVD R4, 24(R15) - MOVD R5, 32(R15) - MOVD $0, 40(R15) - BL runtime·reflectcallmove(SB) - RET - -CALLFN(·call16, 16) -CALLFN(·call32, 32) -CALLFN(·call64, 64) -CALLFN(·call128, 128) -CALLFN(·call256, 256) -CALLFN(·call512, 512) -CALLFN(·call1024, 1024) -CALLFN(·call2048, 2048) -CALLFN(·call4096, 4096) -CALLFN(·call8192, 8192) -CALLFN(·call16384, 16384) -CALLFN(·call32768, 32768) -CALLFN(·call65536, 65536) -CALLFN(·call131072, 131072) -CALLFN(·call262144, 262144) -CALLFN(·call524288, 524288) -CALLFN(·call1048576, 1048576) -CALLFN(·call2097152, 2097152) -CALLFN(·call4194304, 4194304) -CALLFN(·call8388608, 8388608) -CALLFN(·call16777216, 16777216) -CALLFN(·call33554432, 33554432) -CALLFN(·call67108864, 67108864) -CALLFN(·call134217728, 134217728) -CALLFN(·call268435456, 268435456) -CALLFN(·call536870912, 536870912) -CALLFN(·call1073741824, 1073741824) - -// Not a function: target for EXRL (execute relative long) instruction. -TEXT callfnMVC<>(SB),NOSPLIT|NOFRAME,$0-0 - MVC $1, 0(R4), 0(R6) - -TEXT runtime·procyield(SB),NOSPLIT,$0-0 - RET - -// Save state of caller into g->sched, -// but using fake PC from systemstack_switch. -// Must only be called from functions with no locals ($0) -// or else unwinding from systemstack_switch is incorrect. -// Smashes R1. -TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 - MOVD $runtime·systemstack_switch(SB), R1 - ADD $16, R1 // get past prologue - MOVD R1, (g_sched+gobuf_pc)(g) - MOVD R15, (g_sched+gobuf_sp)(g) - MOVD $0, (g_sched+gobuf_lr)(g) - MOVD $0, (g_sched+gobuf_ret)(g) - // Assert ctxt is zero. See func save. - MOVD (g_sched+gobuf_ctxt)(g), R1 - CMPBEQ R1, $0, 2(PC) - BL runtime·abort(SB) - RET - -// func asmcgocall(fn, arg unsafe.Pointer) int32 -// Call fn(arg) on the scheduler stack, -// aligned appropriately for the gcc ABI. -// See cgocall.go for more details. -TEXT ·asmcgocall(SB),NOSPLIT,$0-20 - // R2 = argc; R3 = argv; R11 = temp; R13 = g; R15 = stack pointer - // C TLS base pointer in AR0:AR1 - MOVD fn+0(FP), R3 - MOVD arg+8(FP), R4 - - MOVD R15, R2 // save original stack pointer - MOVD g, R5 - - // Figure out if we need to switch to m->g0 stack. - // We get called to create new OS threads too, and those - // come in on the m->g0 stack already. Or we might already - // be on the m->gsignal stack. - MOVD g_m(g), R6 - MOVD m_gsignal(R6), R7 - CMPBEQ R7, g, g0 - MOVD m_g0(R6), R7 - CMPBEQ R7, g, g0 - BL gosave_systemstack_switch<>(SB) - MOVD R7, g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R15 - - // Now on a scheduling stack (a pthread-created stack). -g0: - // Save room for two of our pointers, plus 160 bytes of callee - // save area that lives on the caller stack. - SUB $176, R15 - MOVD $~7, R6 - AND R6, R15 // 8-byte alignment for gcc ABI - MOVD R5, 168(R15) // save old g on stack - MOVD (g_stack+stack_hi)(R5), R5 - SUB R2, R5 - MOVD R5, 160(R15) // save depth in old g stack (can't just save SP, as stack might be copied during a callback) - MOVD $0, 0(R15) // clear back chain pointer (TODO can we give it real back trace information?) - MOVD R4, R2 // arg in R2 - BL R3 // can clobber: R0-R5, R14, F0-F3, F5, F7-F15 - - XOR R0, R0 // set R0 back to 0. - // Restore g, stack pointer. - MOVD 168(R15), g - BL runtime·save_g(SB) - MOVD (g_stack+stack_hi)(g), R5 - MOVD 160(R15), R6 - SUB R6, R5 - MOVD R5, R15 - - MOVW R2, ret+16(FP) - RET - -// cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) -// See cgocall.go for more details. -TEXT ·cgocallback(SB),NOSPLIT,$24-24 - NO_LOCAL_POINTERS - - // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. - // It is used to dropm while thread is exiting. - MOVD fn+0(FP), R1 - CMPBNE R1, $0, loadg - // Restore the g from frame. - MOVD frame+8(FP), g - BR dropm - -loadg: - // Load m and g from thread-local storage. - MOVB runtime·iscgo(SB), R3 - CMPBEQ R3, $0, nocgo - BL runtime·load_g(SB) - -nocgo: - // If g is nil, Go did not create the current thread, - // or if this thread never called into Go on pthread platforms. - // Call needm to obtain one for temporary use. - // In this case, we're running on the thread stack, so there's - // lots of space, but the linker doesn't know. Hide the call from - // the linker analysis by using an indirect call. - CMPBEQ g, $0, needm - - MOVD g_m(g), R8 - MOVD R8, savedm-8(SP) - BR havem - -needm: - MOVD g, savedm-8(SP) // g is zero, so is m. - MOVD $runtime·needAndBindM(SB), R3 - BL (R3) - - // Set m->sched.sp = SP, so that if a panic happens - // during the function we are about to execute, it will - // have a valid SP to run on the g0 stack. - // The next few lines (after the havem label) - // will save this SP onto the stack and then write - // the same SP back to m->sched.sp. That seems redundant, - // but if an unrecovered panic happens, unwindm will - // restore the g->sched.sp from the stack location - // and then systemstack will try to use it. If we don't set it here, - // that restored SP will be uninitialized (typically 0) and - // will not be usable. - MOVD g_m(g), R8 - MOVD m_g0(R8), R3 - MOVD R15, (g_sched+gobuf_sp)(R3) - -havem: - // Now there's a valid m, and we're running on its m->g0. - // Save current m->g0->sched.sp on stack and then set it to SP. - // Save current sp in m->g0->sched.sp in preparation for - // switch back to m->curg stack. - // NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP). - MOVD m_g0(R8), R3 - MOVD (g_sched+gobuf_sp)(R3), R4 - MOVD R4, savedsp-24(SP) // must match frame size - MOVD R15, (g_sched+gobuf_sp)(R3) - - // Switch to m->curg stack and call runtime.cgocallbackg. - // Because we are taking over the execution of m->curg - // but *not* resuming what had been running, we need to - // save that information (m->curg->sched) so we can restore it. - // We can restore m->curg->sched.sp easily, because calling - // runtime.cgocallbackg leaves SP unchanged upon return. - // To save m->curg->sched.pc, we push it onto the curg stack and - // open a frame the same size as cgocallback's g0 frame. - // Once we switch to the curg stack, the pushed PC will appear - // to be the return PC of cgocallback, so that the traceback - // will seamlessly trace back into the earlier calls. - MOVD m_curg(R8), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 - MOVD (g_sched+gobuf_pc)(g), R5 - MOVD R5, -(24+8)(R4) // "saved LR"; must match frame size - // Gather our arguments into registers. - MOVD fn+0(FP), R1 - MOVD frame+8(FP), R2 - MOVD ctxt+16(FP), R3 - MOVD $-(24+8)(R4), R15 // switch stack; must match frame size - MOVD R1, 8(R15) - MOVD R2, 16(R15) - MOVD R3, 24(R15) - BL runtime·cgocallbackg(SB) - - // Restore g->sched (== m->curg->sched) from saved values. - MOVD 0(R15), R5 - MOVD R5, (g_sched+gobuf_pc)(g) - MOVD $(24+8)(R15), R4 // must match frame size - MOVD R4, (g_sched+gobuf_sp)(g) - - // Switch back to m->g0's stack and restore m->g0->sched.sp. - // (Unlike m->curg, the g0 goroutine never uses sched.pc, - // so we do not have to restore it.) - MOVD g_m(g), R8 - MOVD m_g0(R8), g - BL runtime·save_g(SB) - MOVD (g_sched+gobuf_sp)(g), R15 - MOVD savedsp-24(SP), R4 // must match frame size - MOVD R4, (g_sched+gobuf_sp)(g) - - // If the m on entry was nil, we called needm above to borrow an m, - // 1. for the duration of the call on non-pthread platforms, - // 2. or the duration of the C thread alive on pthread platforms. - // If the m on entry wasn't nil, - // 1. the thread might be a Go thread, - // 2. or it wasn't the first call from a C thread on pthread platforms, - // since then we skip dropm to reuse the m in the first call. - MOVD savedm-8(SP), R6 - CMPBNE R6, $0, droppedm - - // Skip dropm to reuse it in the next call, when a pthread key has been created. - MOVD _cgo_pthread_key_created(SB), R6 - // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. - CMPBEQ R6, $0, dropm - MOVD (R6), R6 - CMPBNE R6, $0, droppedm - -dropm: - MOVD $runtime·dropm(SB), R3 - BL (R3) -droppedm: - - // Done! - RET - -// void setg(G*); set g. for use by needm. -TEXT runtime·setg(SB), NOSPLIT, $0-8 - MOVD gg+0(FP), g - // This only happens if iscgo, so jump straight to save_g - BL runtime·save_g(SB) - RET - -// void setg_gcc(G*); set g in C TLS. -// Must obey the gcc calling convention. -TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 - // The standard prologue clobbers LR (R14), which is callee-save in - // the C ABI, so we have to use NOFRAME and save LR ourselves. - MOVD LR, R1 - // Also save g, R10, and R11 since they're callee-save in C ABI - MOVD R10, R3 - MOVD g, R4 - MOVD R11, R5 - - MOVD R2, g - BL runtime·save_g(SB) - - MOVD R5, R11 - MOVD R4, g - MOVD R3, R10 - MOVD R1, LR - RET - -TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 - MOVW (R0), R0 - UNDEF - -// int64 runtime·cputicks(void) -TEXT runtime·cputicks(SB),NOSPLIT,$0-8 - // The TOD clock on s390 counts from the year 1900 in ~250ps intervals. - // This means that since about 1972 the msb has been set, making the - // result of a call to STORE CLOCK (stck) a negative number. - // We clear the msb to make it positive. - STCK ret+0(FP) // serialises before and after call - MOVD ret+0(FP), R3 // R3 will wrap to 0 in the year 2043 - SLD $1, R3 - SRD $1, R3 - MOVD R3, ret+0(FP) - RET - -// AES hashing not implemented for s390x -TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 - JMP runtime·memhashFallback(SB) -TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 - JMP runtime·strhashFallback(SB) -TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 - JMP runtime·memhash32Fallback(SB) -TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 - JMP runtime·memhash64Fallback(SB) - -TEXT runtime·return0(SB), NOSPLIT, $0 - MOVW $0, R3 - RET - -// Called from cgo wrappers, this function returns g->m->curg.stack.hi. -// Must obey the gcc calling convention. -TEXT _cgo_topofstack(SB),NOSPLIT|NOFRAME,$0 - // g (R13), R10, R11 and LR (R14) are callee-save in the C ABI, so save them - MOVD g, R1 - MOVD R10, R3 - MOVD LR, R4 - MOVD R11, R5 - - BL runtime·load_g(SB) // clobbers g (R13), R10, R11 - MOVD g_m(g), R2 - MOVD m_curg(R2), R2 - MOVD (g_stack+stack_hi)(R2), R2 - - MOVD R1, g - MOVD R3, R10 - MOVD R4, LR - MOVD R5, R11 - RET - -// The top-most function running on a goroutine -// returns to goexit+PCQuantum. -TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 - BYTE $0x07; BYTE $0x00; // 2-byte nop - BL runtime·goexit1(SB) // does not return - // traceback from goexit1 must hit code range of goexit - BYTE $0x07; BYTE $0x00; // 2-byte nop - -TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 - // Stores are already ordered on s390x, so this is just a - // compile barrier. - RET - -// This is called from .init_array and follows the platform, not Go, ABI. -// We are overly conservative. We could only save the registers we use. -// However, since this function is only called once per loaded module -// performance is unimportant. -TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0 - // Save R6-R15 in the register save area of the calling function. - // Don't bother saving F8-F15 as we aren't doing any calls. - STMG R6, R15, 48(R15) - - // append the argument (passed in R2, as per the ELF ABI) to the - // moduledata linked list. - MOVD runtime·lastmoduledatap(SB), R1 - MOVD R2, moduledata_next(R1) - MOVD R2, runtime·lastmoduledatap(SB) - - // Restore R6-R15. - LMG 48(R15), R6, R15 - RET - -TEXT ·checkASM(SB),NOSPLIT,$0-1 - MOVB $1, ret+0(FP) - RET - -// gcWriteBarrier informs the GC about heap pointer writes. -// -// gcWriteBarrier does NOT follow the Go ABI. It accepts the -// number of bytes of buffer needed in R9, and returns a pointer -// to the buffer space in R9. -// It clobbers R10 (the temp register) and R1 (used by PLT stub). -// It does not clobber any other general-purpose registers, -// but may clobber others (e.g., floating point registers). -TEXT gcWriteBarrier<>(SB),NOSPLIT,$96 - // Save the registers clobbered by the fast path. - MOVD R4, 96(R15) -retry: - MOVD g_m(g), R1 - MOVD m_p(R1), R1 - // Increment wbBuf.next position. - MOVD R9, R4 - ADD (p_wbBuf+wbBuf_next)(R1), R4 - // Is the buffer full? - MOVD (p_wbBuf+wbBuf_end)(R1), R10 - CMPUBGT R4, R10, flush - // Commit to the larger buffer. - MOVD R4, (p_wbBuf+wbBuf_next)(R1) - // Make return value (the original next position) - SUB R9, R4, R9 - // Restore registers. - MOVD 96(R15), R4 - RET - -flush: - // Save all general purpose registers since these could be - // clobbered by wbBufFlush and were not saved by the caller. - STMG R2, R3, 8(R15) - MOVD R0, 24(R15) - // R1 already saved. - // R4 already saved. - STMG R5, R12, 32(R15) // save R5 - R12 - // R13 is g. - // R14 is LR. - // R15 is SP. - - CALL runtime·wbBufFlush(SB) - - LMG 8(R15), R2, R3 // restore R2 - R3 - MOVD 24(R15), R0 // restore R0 - LMG 32(R15), R5, R12 // restore R5 - R12 - JMP retry - -TEXT runtime·gcWriteBarrier1(SB),NOSPLIT,$0 - MOVD $8, R9 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier2(SB),NOSPLIT,$0 - MOVD $16, R9 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier3(SB),NOSPLIT,$0 - MOVD $24, R9 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier4(SB),NOSPLIT,$0 - MOVD $32, R9 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier5(SB),NOSPLIT,$0 - MOVD $40, R9 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier6(SB),NOSPLIT,$0 - MOVD $48, R9 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier7(SB),NOSPLIT,$0 - MOVD $56, R9 - JMP gcWriteBarrier<>(SB) -TEXT runtime·gcWriteBarrier8(SB),NOSPLIT,$0 - MOVD $64, R9 - JMP gcWriteBarrier<>(SB) - -// Note: these functions use a special calling convention to save generated code space. -// Arguments are passed in registers, but the space for those arguments are allocated -// in the caller's stack frame. These stubs write the args into that stack space and -// then tail call to the corresponding runtime handler. -// The tail call makes these stubs disappear in backtraces. -TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 - MOVD R0, x+0(FP) - MOVD R1, y+8(FP) - JMP runtime·goPanicIndex(SB) -TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 - MOVD R0, x+0(FP) - MOVD R1, y+8(FP) - JMP runtime·goPanicIndexU(SB) -TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 - MOVD R1, x+0(FP) - MOVD R2, y+8(FP) - JMP runtime·goPanicSliceAlen(SB) -TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 - MOVD R1, x+0(FP) - MOVD R2, y+8(FP) - JMP runtime·goPanicSliceAlenU(SB) -TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 - MOVD R1, x+0(FP) - MOVD R2, y+8(FP) - JMP runtime·goPanicSliceAcap(SB) -TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 - MOVD R1, x+0(FP) - MOVD R2, y+8(FP) - JMP runtime·goPanicSliceAcapU(SB) -TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 - MOVD R0, x+0(FP) - MOVD R1, y+8(FP) - JMP runtime·goPanicSliceB(SB) -TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 - MOVD R0, x+0(FP) - MOVD R1, y+8(FP) - JMP runtime·goPanicSliceBU(SB) -TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 - MOVD R2, x+0(FP) - MOVD R3, y+8(FP) - JMP runtime·goPanicSlice3Alen(SB) -TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 - MOVD R2, x+0(FP) - MOVD R3, y+8(FP) - JMP runtime·goPanicSlice3AlenU(SB) -TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 - MOVD R2, x+0(FP) - MOVD R3, y+8(FP) - JMP runtime·goPanicSlice3Acap(SB) -TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 - MOVD R2, x+0(FP) - MOVD R3, y+8(FP) - JMP runtime·goPanicSlice3AcapU(SB) -TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 - MOVD R1, x+0(FP) - MOVD R2, y+8(FP) - JMP runtime·goPanicSlice3B(SB) -TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 - MOVD R1, x+0(FP) - MOVD R2, y+8(FP) - JMP runtime·goPanicSlice3BU(SB) -TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 - MOVD R0, x+0(FP) - MOVD R1, y+8(FP) - JMP runtime·goPanicSlice3C(SB) -TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 - MOVD R0, x+0(FP) - MOVD R1, y+8(FP) - JMP runtime·goPanicSlice3CU(SB) -TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 - MOVD R2, x+0(FP) - MOVD R3, y+8(FP) - JMP runtime·goPanicSliceConvert(SB) diff --git a/contrib/go/_std_1.22/src/runtime/cgo.go b/contrib/go/_std_1.22/src/runtime/cgo.go deleted file mode 100644 index 40c8c748d3e5..000000000000 --- a/contrib/go/_std_1.22/src/runtime/cgo.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -//go:cgo_export_static main - -// Filled in by runtime/cgo when linked into binary. - -//go:linkname _cgo_init _cgo_init -//go:linkname _cgo_thread_start _cgo_thread_start -//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create -//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done -//go:linkname _cgo_callers _cgo_callers -//go:linkname _cgo_set_context_function _cgo_set_context_function -//go:linkname _cgo_yield _cgo_yield -//go:linkname _cgo_pthread_key_created _cgo_pthread_key_created -//go:linkname _cgo_bindm _cgo_bindm -//go:linkname _cgo_getstackbound _cgo_getstackbound - -var ( - _cgo_init unsafe.Pointer - _cgo_thread_start unsafe.Pointer - _cgo_sys_thread_create unsafe.Pointer - _cgo_notify_runtime_init_done unsafe.Pointer - _cgo_callers unsafe.Pointer - _cgo_set_context_function unsafe.Pointer - _cgo_yield unsafe.Pointer - _cgo_pthread_key_created unsafe.Pointer - _cgo_bindm unsafe.Pointer - _cgo_getstackbound unsafe.Pointer -) - -// iscgo is set to true by the runtime/cgo package -var iscgo bool - -// set_crosscall2 is set by the runtime/cgo package -var set_crosscall2 func() - -// cgoHasExtraM is set on startup when an extra M is created for cgo. -// The extra M must be created before any C/C++ code calls cgocallback. -var cgoHasExtraM bool - -// cgoUse is called by cgo-generated code (using go:linkname to get at -// an unexported name). The calls serve two purposes: -// 1) they are opaque to escape analysis, so the argument is considered to -// escape to the heap. -// 2) they keep the argument alive until the call site; the call is emitted after -// the end of the (presumed) use of the argument by C. -// cgoUse should not actually be called (see cgoAlwaysFalse). -func cgoUse(any) { throw("cgoUse should not be called") } - -// cgoAlwaysFalse is a boolean value that is always false. -// The cgo-generated code says if cgoAlwaysFalse { cgoUse(p) }. -// The compiler cannot see that cgoAlwaysFalse is always false, -// so it emits the test and keeps the call, giving the desired -// escape analysis result. The test is cheaper than the call. -var cgoAlwaysFalse bool - -var cgo_yield = &_cgo_yield - -func cgoNoCallback(v bool) { - g := getg() - if g.nocgocallback && v { - panic("runtime: unexpected setting cgoNoCallback") - } - g.nocgocallback = v -} diff --git a/contrib/go/_std_1.22/src/runtime/cgo/cgo.go b/contrib/go/_std_1.22/src/runtime/cgo/cgo.go deleted file mode 100644 index 1e3a50291838..000000000000 --- a/contrib/go/_std_1.22/src/runtime/cgo/cgo.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package cgo contains runtime support for code generated -by the cgo tool. See the documentation for the cgo command -for details on using cgo. -*/ -package cgo - -/* - -#cgo darwin,!arm64 LDFLAGS: -lpthread -#cgo darwin,arm64 LDFLAGS: -framework CoreFoundation -#cgo dragonfly LDFLAGS: -lpthread -#cgo freebsd LDFLAGS: -lpthread -#cgo android LDFLAGS: -llog -#cgo !android,linux LDFLAGS: -lpthread -#cgo netbsd LDFLAGS: -lpthread -#cgo openbsd LDFLAGS: -lpthread -#cgo aix LDFLAGS: -Wl,-berok -#cgo solaris LDFLAGS: -lxnet -#cgo solaris LDFLAGS: -lsocket - -// Use -fno-stack-protector to avoid problems locating the -// proper support functions. See issues #52919, #54313, #58385. -#cgo CFLAGS: -Wall -Werror -fno-stack-protector - -#cgo solaris CPPFLAGS: -D_POSIX_PTHREAD_SEMANTICS - -*/ -import "C" - -import "runtime/internal/sys" - -// Incomplete is used specifically for the semantics of incomplete C types. -type Incomplete struct { - _ sys.NotInHeap -} diff --git a/contrib/go/_std_1.22/src/runtime/cgo/ya.make b/contrib/go/_std_1.22/src/runtime/cgo/ya.make deleted file mode 100644 index 095be326f76f..000000000000 --- a/contrib/go/_std_1.22/src/runtime/cgo/ya.make +++ /dev/null @@ -1,127 +0,0 @@ -IF (CGO_ENABLED) - GO_LIBRARY() - - PEERDIR( - library/cpp/sanitizer/include - ) - - NO_COMPILER_WARNINGS() - - SRCS( - abi_loong64.h - abi_ppc64x.h - callbacks.go - CGO_EXPORT gcc_context.c - CGO_EXPORT gcc_util.c - handle.go - iscgo.go - libcgo.h - libcgo_unix.h - ) - - CGO_SRCS( - cgo.go - ) - - IF (ARCH_ARM64) - SRCS( - abi_arm64.h - asm_arm64.s - gcc_arm64.S - ) - ENDIF() - - IF (ARCH_X86_64) - SRCS( - abi_amd64.h - asm_amd64.s - gcc_amd64.S - ) - ENDIF() - - IF (OS_DARWIN) - SRCS( - callbacks_traceback.go - CGO_EXPORT gcc_libinit.c - CGO_EXPORT gcc_setenv.c - CGO_EXPORT gcc_stack_darwin.c - CGO_EXPORT gcc_traceback.c - setenv.go - ) - - IF (ARCH_ARM64) - CGO_LDFLAGS( - -framework - CoreFoundation - ) - - SRCS( - CGO_EXPORT gcc_darwin_arm64.c - ) - ENDIF() - - IF (ARCH_X86_64) - CGO_LDFLAGS( - -lpthread - ) - - SRCS( - CGO_EXPORT gcc_darwin_amd64.c - ) - ENDIF() - ENDIF() - - IF (OS_LINUX) - CGO_LDFLAGS(-lpthread -ldl -lresolv) - - SRCS( - callbacks_traceback.go - CGO_EXPORT gcc_fatalf.c - CGO_EXPORT gcc_libinit.c - CGO_EXPORT gcc_mmap.c - CGO_EXPORT gcc_setenv.c - CGO_EXPORT gcc_sigaction.c - CGO_EXPORT gcc_stack_unix.c - CGO_EXPORT gcc_traceback.c - linux.go - CGO_EXPORT linux_syscall.c - mmap.go - setenv.go - sigaction.go - ) - - IF (ARCH_ARM64) - SRCS( - CGO_EXPORT gcc_linux_arm64.c - ) - ENDIF() - - IF (ARCH_X86_64) - SRCS( - CGO_EXPORT gcc_linux_amd64.c - ) - ENDIF() - ENDIF() - - IF (OS_WINDOWS) - SRCS( - CGO_EXPORT gcc_libinit_windows.c - CGO_EXPORT gcc_stack_windows.c - libcgo_windows.h - ) - - IF (ARCH_ARM64) - SRCS( - CGO_EXPORT gcc_windows_arm64.c - ) - ENDIF() - - IF (ARCH_X86_64) - SRCS( - CGO_EXPORT gcc_windows_amd64.c - ) - ENDIF() - ENDIF() - - END() -ENDIF() diff --git a/contrib/go/_std_1.22/src/runtime/chan.go b/contrib/go/_std_1.22/src/runtime/chan.go deleted file mode 100644 index ff9e2a9155af..000000000000 --- a/contrib/go/_std_1.22/src/runtime/chan.go +++ /dev/null @@ -1,851 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// This file contains the implementation of Go channels. - -// Invariants: -// At least one of c.sendq and c.recvq is empty, -// except for the case of an unbuffered channel with a single goroutine -// blocked on it for both sending and receiving using a select statement, -// in which case the length of c.sendq and c.recvq is limited only by the -// size of the select statement. -// -// For buffered channels, also: -// c.qcount > 0 implies that c.recvq is empty. -// c.qcount < c.dataqsiz implies that c.sendq is empty. - -import ( - "internal/abi" - "runtime/internal/atomic" - "runtime/internal/math" - "unsafe" -) - -const ( - maxAlign = 8 - hchanSize = unsafe.Sizeof(hchan{}) + uintptr(-int(unsafe.Sizeof(hchan{}))&(maxAlign-1)) - debugChan = false -) - -type hchan struct { - qcount uint // total data in the queue - dataqsiz uint // size of the circular queue - buf unsafe.Pointer // points to an array of dataqsiz elements - elemsize uint16 - closed uint32 - elemtype *_type // element type - sendx uint // send index - recvx uint // receive index - recvq waitq // list of recv waiters - sendq waitq // list of send waiters - - // lock protects all fields in hchan, as well as several - // fields in sudogs blocked on this channel. - // - // Do not change another G's status while holding this lock - // (in particular, do not ready a G), as this can deadlock - // with stack shrinking. - lock mutex -} - -type waitq struct { - first *sudog - last *sudog -} - -//go:linkname reflect_makechan reflect.makechan -func reflect_makechan(t *chantype, size int) *hchan { - return makechan(t, size) -} - -func makechan64(t *chantype, size int64) *hchan { - if int64(int(size)) != size { - panic(plainError("makechan: size out of range")) - } - - return makechan(t, int(size)) -} - -func makechan(t *chantype, size int) *hchan { - elem := t.Elem - - // compiler checks this but be safe. - if elem.Size_ >= 1<<16 { - throw("makechan: invalid channel element type") - } - if hchanSize%maxAlign != 0 || elem.Align_ > maxAlign { - throw("makechan: bad alignment") - } - - mem, overflow := math.MulUintptr(elem.Size_, uintptr(size)) - if overflow || mem > maxAlloc-hchanSize || size < 0 { - panic(plainError("makechan: size out of range")) - } - - // Hchan does not contain pointers interesting for GC when elements stored in buf do not contain pointers. - // buf points into the same allocation, elemtype is persistent. - // SudoG's are referenced from their owning thread so they can't be collected. - // TODO(dvyukov,rlh): Rethink when collector can move allocated objects. - var c *hchan - switch { - case mem == 0: - // Queue or element size is zero. - c = (*hchan)(mallocgc(hchanSize, nil, true)) - // Race detector uses this location for synchronization. - c.buf = c.raceaddr() - case elem.PtrBytes == 0: - // Elements do not contain pointers. - // Allocate hchan and buf in one call. - c = (*hchan)(mallocgc(hchanSize+mem, nil, true)) - c.buf = add(unsafe.Pointer(c), hchanSize) - default: - // Elements contain pointers. - c = new(hchan) - c.buf = mallocgc(mem, elem, true) - } - - c.elemsize = uint16(elem.Size_) - c.elemtype = elem - c.dataqsiz = uint(size) - lockInit(&c.lock, lockRankHchan) - - if debugChan { - print("makechan: chan=", c, "; elemsize=", elem.Size_, "; dataqsiz=", size, "\n") - } - return c -} - -// chanbuf(c, i) is pointer to the i'th slot in the buffer. -func chanbuf(c *hchan, i uint) unsafe.Pointer { - return add(c.buf, uintptr(i)*uintptr(c.elemsize)) -} - -// full reports whether a send on c would block (that is, the channel is full). -// It uses a single word-sized read of mutable state, so although -// the answer is instantaneously true, the correct answer may have changed -// by the time the calling function receives the return value. -func full(c *hchan) bool { - // c.dataqsiz is immutable (never written after the channel is created) - // so it is safe to read at any time during channel operation. - if c.dataqsiz == 0 { - // Assumes that a pointer read is relaxed-atomic. - return c.recvq.first == nil - } - // Assumes that a uint read is relaxed-atomic. - return c.qcount == c.dataqsiz -} - -// entry point for c <- x from compiled code. -// -//go:nosplit -func chansend1(c *hchan, elem unsafe.Pointer) { - chansend(c, elem, true, getcallerpc()) -} - -/* - * generic single channel send/recv - * If block is not nil, - * then the protocol will not - * sleep but return if it could - * not complete. - * - * sleep can wake up with g.param == nil - * when a channel involved in the sleep has - * been closed. it is easiest to loop and re-run - * the operation; we'll see that it's now closed. - */ -func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { - if c == nil { - if !block { - return false - } - gopark(nil, nil, waitReasonChanSendNilChan, traceBlockForever, 2) - throw("unreachable") - } - - if debugChan { - print("chansend: chan=", c, "\n") - } - - if raceenabled { - racereadpc(c.raceaddr(), callerpc, abi.FuncPCABIInternal(chansend)) - } - - // Fast path: check for failed non-blocking operation without acquiring the lock. - // - // After observing that the channel is not closed, we observe that the channel is - // not ready for sending. Each of these observations is a single word-sized read - // (first c.closed and second full()). - // Because a closed channel cannot transition from 'ready for sending' to - // 'not ready for sending', even if the channel is closed between the two observations, - // they imply a moment between the two when the channel was both not yet closed - // and not ready for sending. We behave as if we observed the channel at that moment, - // and report that the send cannot proceed. - // - // It is okay if the reads are reordered here: if we observe that the channel is not - // ready for sending and then observe that it is not closed, that implies that the - // channel wasn't closed during the first observation. However, nothing here - // guarantees forward progress. We rely on the side effects of lock release in - // chanrecv() and closechan() to update this thread's view of c.closed and full(). - if !block && c.closed == 0 && full(c) { - return false - } - - var t0 int64 - if blockprofilerate > 0 { - t0 = cputicks() - } - - lock(&c.lock) - - if c.closed != 0 { - unlock(&c.lock) - panic(plainError("send on closed channel")) - } - - if sg := c.recvq.dequeue(); sg != nil { - // Found a waiting receiver. We pass the value we want to send - // directly to the receiver, bypassing the channel buffer (if any). - send(c, sg, ep, func() { unlock(&c.lock) }, 3) - return true - } - - if c.qcount < c.dataqsiz { - // Space is available in the channel buffer. Enqueue the element to send. - qp := chanbuf(c, c.sendx) - if raceenabled { - racenotify(c, c.sendx, nil) - } - typedmemmove(c.elemtype, qp, ep) - c.sendx++ - if c.sendx == c.dataqsiz { - c.sendx = 0 - } - c.qcount++ - unlock(&c.lock) - return true - } - - if !block { - unlock(&c.lock) - return false - } - - // Block on the channel. Some receiver will complete our operation for us. - gp := getg() - mysg := acquireSudog() - mysg.releasetime = 0 - if t0 != 0 { - mysg.releasetime = -1 - } - // No stack splits between assigning elem and enqueuing mysg - // on gp.waiting where copystack can find it. - mysg.elem = ep - mysg.waitlink = nil - mysg.g = gp - mysg.isSelect = false - mysg.c = c - gp.waiting = mysg - gp.param = nil - c.sendq.enqueue(mysg) - // Signal to anyone trying to shrink our stack that we're about - // to park on a channel. The window between when this G's status - // changes and when we set gp.activeStackChans is not safe for - // stack shrinking. - gp.parkingOnChan.Store(true) - gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceBlockChanSend, 2) - // Ensure the value being sent is kept alive until the - // receiver copies it out. The sudog has a pointer to the - // stack object, but sudogs aren't considered as roots of the - // stack tracer. - KeepAlive(ep) - - // someone woke us up. - if mysg != gp.waiting { - throw("G waiting list is corrupted") - } - gp.waiting = nil - gp.activeStackChans = false - closed := !mysg.success - gp.param = nil - if mysg.releasetime > 0 { - blockevent(mysg.releasetime-t0, 2) - } - mysg.c = nil - releaseSudog(mysg) - if closed { - if c.closed == 0 { - throw("chansend: spurious wakeup") - } - panic(plainError("send on closed channel")) - } - return true -} - -// send processes a send operation on an empty channel c. -// The value ep sent by the sender is copied to the receiver sg. -// The receiver is then woken up to go on its merry way. -// Channel c must be empty and locked. send unlocks c with unlockf. -// sg must already be dequeued from c. -// ep must be non-nil and point to the heap or the caller's stack. -func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) { - if raceenabled { - if c.dataqsiz == 0 { - racesync(c, sg) - } else { - // Pretend we go through the buffer, even though - // we copy directly. Note that we need to increment - // the head/tail locations only when raceenabled. - racenotify(c, c.recvx, nil) - racenotify(c, c.recvx, sg) - c.recvx++ - if c.recvx == c.dataqsiz { - c.recvx = 0 - } - c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz - } - } - if sg.elem != nil { - sendDirect(c.elemtype, sg, ep) - sg.elem = nil - } - gp := sg.g - unlockf() - gp.param = unsafe.Pointer(sg) - sg.success = true - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp, skip+1) -} - -// Sends and receives on unbuffered or empty-buffered channels are the -// only operations where one running goroutine writes to the stack of -// another running goroutine. The GC assumes that stack writes only -// happen when the goroutine is running and are only done by that -// goroutine. Using a write barrier is sufficient to make up for -// violating that assumption, but the write barrier has to work. -// typedmemmove will call bulkBarrierPreWrite, but the target bytes -// are not in the heap, so that will not help. We arrange to call -// memmove and typeBitsBulkBarrier instead. - -func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) { - // src is on our stack, dst is a slot on another stack. - - // Once we read sg.elem out of sg, it will no longer - // be updated if the destination's stack gets copied (shrunk). - // So make sure that no preemption points can happen between read & use. - dst := sg.elem - typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.Size_) - // No need for cgo write barrier checks because dst is always - // Go memory. - memmove(dst, src, t.Size_) -} - -func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) { - // dst is on our stack or the heap, src is on another stack. - // The channel is locked, so src will not move during this - // operation. - src := sg.elem - typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.Size_) - memmove(dst, src, t.Size_) -} - -func closechan(c *hchan) { - if c == nil { - panic(plainError("close of nil channel")) - } - - lock(&c.lock) - if c.closed != 0 { - unlock(&c.lock) - panic(plainError("close of closed channel")) - } - - if raceenabled { - callerpc := getcallerpc() - racewritepc(c.raceaddr(), callerpc, abi.FuncPCABIInternal(closechan)) - racerelease(c.raceaddr()) - } - - c.closed = 1 - - var glist gList - - // release all readers - for { - sg := c.recvq.dequeue() - if sg == nil { - break - } - if sg.elem != nil { - typedmemclr(c.elemtype, sg.elem) - sg.elem = nil - } - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - gp := sg.g - gp.param = unsafe.Pointer(sg) - sg.success = false - if raceenabled { - raceacquireg(gp, c.raceaddr()) - } - glist.push(gp) - } - - // release all writers (they will panic) - for { - sg := c.sendq.dequeue() - if sg == nil { - break - } - sg.elem = nil - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - gp := sg.g - gp.param = unsafe.Pointer(sg) - sg.success = false - if raceenabled { - raceacquireg(gp, c.raceaddr()) - } - glist.push(gp) - } - unlock(&c.lock) - - // Ready all Gs now that we've dropped the channel lock. - for !glist.empty() { - gp := glist.pop() - gp.schedlink = 0 - goready(gp, 3) - } -} - -// empty reports whether a read from c would block (that is, the channel is -// empty). It uses a single atomic read of mutable state. -func empty(c *hchan) bool { - // c.dataqsiz is immutable. - if c.dataqsiz == 0 { - return atomic.Loadp(unsafe.Pointer(&c.sendq.first)) == nil - } - return atomic.Loaduint(&c.qcount) == 0 -} - -// entry points for <- c from compiled code. -// -//go:nosplit -func chanrecv1(c *hchan, elem unsafe.Pointer) { - chanrecv(c, elem, true) -} - -//go:nosplit -func chanrecv2(c *hchan, elem unsafe.Pointer) (received bool) { - _, received = chanrecv(c, elem, true) - return -} - -// chanrecv receives on channel c and writes the received data to ep. -// ep may be nil, in which case received data is ignored. -// If block == false and no elements are available, returns (false, false). -// Otherwise, if c is closed, zeros *ep and returns (true, false). -// Otherwise, fills in *ep with an element and returns (true, true). -// A non-nil ep must point to the heap or the caller's stack. -func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) { - // raceenabled: don't need to check ep, as it is always on the stack - // or is new memory allocated by reflect. - - if debugChan { - print("chanrecv: chan=", c, "\n") - } - - if c == nil { - if !block { - return - } - gopark(nil, nil, waitReasonChanReceiveNilChan, traceBlockForever, 2) - throw("unreachable") - } - - // Fast path: check for failed non-blocking operation without acquiring the lock. - if !block && empty(c) { - // After observing that the channel is not ready for receiving, we observe whether the - // channel is closed. - // - // Reordering of these checks could lead to incorrect behavior when racing with a close. - // For example, if the channel was open and not empty, was closed, and then drained, - // reordered reads could incorrectly indicate "open and empty". To prevent reordering, - // we use atomic loads for both checks, and rely on emptying and closing to happen in - // separate critical sections under the same lock. This assumption fails when closing - // an unbuffered channel with a blocked send, but that is an error condition anyway. - if atomic.Load(&c.closed) == 0 { - // Because a channel cannot be reopened, the later observation of the channel - // being not closed implies that it was also not closed at the moment of the - // first observation. We behave as if we observed the channel at that moment - // and report that the receive cannot proceed. - return - } - // The channel is irreversibly closed. Re-check whether the channel has any pending data - // to receive, which could have arrived between the empty and closed checks above. - // Sequential consistency is also required here, when racing with such a send. - if empty(c) { - // The channel is irreversibly closed and empty. - if raceenabled { - raceacquire(c.raceaddr()) - } - if ep != nil { - typedmemclr(c.elemtype, ep) - } - return true, false - } - } - - var t0 int64 - if blockprofilerate > 0 { - t0 = cputicks() - } - - lock(&c.lock) - - if c.closed != 0 { - if c.qcount == 0 { - if raceenabled { - raceacquire(c.raceaddr()) - } - unlock(&c.lock) - if ep != nil { - typedmemclr(c.elemtype, ep) - } - return true, false - } - // The channel has been closed, but the channel's buffer have data. - } else { - // Just found waiting sender with not closed. - if sg := c.sendq.dequeue(); sg != nil { - // Found a waiting sender. If buffer is size 0, receive value - // directly from sender. Otherwise, receive from head of queue - // and add sender's value to the tail of the queue (both map to - // the same buffer slot because the queue is full). - recv(c, sg, ep, func() { unlock(&c.lock) }, 3) - return true, true - } - } - - if c.qcount > 0 { - // Receive directly from queue - qp := chanbuf(c, c.recvx) - if raceenabled { - racenotify(c, c.recvx, nil) - } - if ep != nil { - typedmemmove(c.elemtype, ep, qp) - } - typedmemclr(c.elemtype, qp) - c.recvx++ - if c.recvx == c.dataqsiz { - c.recvx = 0 - } - c.qcount-- - unlock(&c.lock) - return true, true - } - - if !block { - unlock(&c.lock) - return false, false - } - - // no sender available: block on this channel. - gp := getg() - mysg := acquireSudog() - mysg.releasetime = 0 - if t0 != 0 { - mysg.releasetime = -1 - } - // No stack splits between assigning elem and enqueuing mysg - // on gp.waiting where copystack can find it. - mysg.elem = ep - mysg.waitlink = nil - gp.waiting = mysg - mysg.g = gp - mysg.isSelect = false - mysg.c = c - gp.param = nil - c.recvq.enqueue(mysg) - // Signal to anyone trying to shrink our stack that we're about - // to park on a channel. The window between when this G's status - // changes and when we set gp.activeStackChans is not safe for - // stack shrinking. - gp.parkingOnChan.Store(true) - gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanReceive, traceBlockChanRecv, 2) - - // someone woke us up - if mysg != gp.waiting { - throw("G waiting list is corrupted") - } - gp.waiting = nil - gp.activeStackChans = false - if mysg.releasetime > 0 { - blockevent(mysg.releasetime-t0, 2) - } - success := mysg.success - gp.param = nil - mysg.c = nil - releaseSudog(mysg) - return true, success -} - -// recv processes a receive operation on a full channel c. -// There are 2 parts: -// 1. The value sent by the sender sg is put into the channel -// and the sender is woken up to go on its merry way. -// 2. The value received by the receiver (the current G) is -// written to ep. -// -// For synchronous channels, both values are the same. -// For asynchronous channels, the receiver gets its data from -// the channel buffer and the sender's data is put in the -// channel buffer. -// Channel c must be full and locked. recv unlocks c with unlockf. -// sg must already be dequeued from c. -// A non-nil ep must point to the heap or the caller's stack. -func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) { - if c.dataqsiz == 0 { - if raceenabled { - racesync(c, sg) - } - if ep != nil { - // copy data from sender - recvDirect(c.elemtype, sg, ep) - } - } else { - // Queue is full. Take the item at the - // head of the queue. Make the sender enqueue - // its item at the tail of the queue. Since the - // queue is full, those are both the same slot. - qp := chanbuf(c, c.recvx) - if raceenabled { - racenotify(c, c.recvx, nil) - racenotify(c, c.recvx, sg) - } - // copy data from queue to receiver - if ep != nil { - typedmemmove(c.elemtype, ep, qp) - } - // copy data from sender to queue - typedmemmove(c.elemtype, qp, sg.elem) - c.recvx++ - if c.recvx == c.dataqsiz { - c.recvx = 0 - } - c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz - } - sg.elem = nil - gp := sg.g - unlockf() - gp.param = unsafe.Pointer(sg) - sg.success = true - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp, skip+1) -} - -func chanparkcommit(gp *g, chanLock unsafe.Pointer) bool { - // There are unlocked sudogs that point into gp's stack. Stack - // copying must lock the channels of those sudogs. - // Set activeStackChans here instead of before we try parking - // because we could self-deadlock in stack growth on the - // channel lock. - gp.activeStackChans = true - // Mark that it's safe for stack shrinking to occur now, - // because any thread acquiring this G's stack for shrinking - // is guaranteed to observe activeStackChans after this store. - gp.parkingOnChan.Store(false) - // Make sure we unlock after setting activeStackChans and - // unsetting parkingOnChan. The moment we unlock chanLock - // we risk gp getting readied by a channel operation and - // so gp could continue running before everything before - // the unlock is visible (even to gp itself). - unlock((*mutex)(chanLock)) - return true -} - -// compiler implements -// -// select { -// case c <- v: -// ... foo -// default: -// ... bar -// } -// -// as -// -// if selectnbsend(c, v) { -// ... foo -// } else { -// ... bar -// } -func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) { - return chansend(c, elem, false, getcallerpc()) -} - -// compiler implements -// -// select { -// case v, ok = <-c: -// ... foo -// default: -// ... bar -// } -// -// as -// -// if selected, ok = selectnbrecv(&v, c); selected { -// ... foo -// } else { -// ... bar -// } -func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected, received bool) { - return chanrecv(c, elem, false) -} - -//go:linkname reflect_chansend reflect.chansend0 -func reflect_chansend(c *hchan, elem unsafe.Pointer, nb bool) (selected bool) { - return chansend(c, elem, !nb, getcallerpc()) -} - -//go:linkname reflect_chanrecv reflect.chanrecv -func reflect_chanrecv(c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) { - return chanrecv(c, elem, !nb) -} - -//go:linkname reflect_chanlen reflect.chanlen -func reflect_chanlen(c *hchan) int { - if c == nil { - return 0 - } - return int(c.qcount) -} - -//go:linkname reflectlite_chanlen internal/reflectlite.chanlen -func reflectlite_chanlen(c *hchan) int { - if c == nil { - return 0 - } - return int(c.qcount) -} - -//go:linkname reflect_chancap reflect.chancap -func reflect_chancap(c *hchan) int { - if c == nil { - return 0 - } - return int(c.dataqsiz) -} - -//go:linkname reflect_chanclose reflect.chanclose -func reflect_chanclose(c *hchan) { - closechan(c) -} - -func (q *waitq) enqueue(sgp *sudog) { - sgp.next = nil - x := q.last - if x == nil { - sgp.prev = nil - q.first = sgp - q.last = sgp - return - } - sgp.prev = x - x.next = sgp - q.last = sgp -} - -func (q *waitq) dequeue() *sudog { - for { - sgp := q.first - if sgp == nil { - return nil - } - y := sgp.next - if y == nil { - q.first = nil - q.last = nil - } else { - y.prev = nil - q.first = y - sgp.next = nil // mark as removed (see dequeueSudoG) - } - - // if a goroutine was put on this queue because of a - // select, there is a small window between the goroutine - // being woken up by a different case and it grabbing the - // channel locks. Once it has the lock - // it removes itself from the queue, so we won't see it after that. - // We use a flag in the G struct to tell us when someone - // else has won the race to signal this goroutine but the goroutine - // hasn't removed itself from the queue yet. - if sgp.isSelect && !sgp.g.selectDone.CompareAndSwap(0, 1) { - continue - } - - return sgp - } -} - -func (c *hchan) raceaddr() unsafe.Pointer { - // Treat read-like and write-like operations on the channel to - // happen at this address. Avoid using the address of qcount - // or dataqsiz, because the len() and cap() builtins read - // those addresses, and we don't want them racing with - // operations like close(). - return unsafe.Pointer(&c.buf) -} - -func racesync(c *hchan, sg *sudog) { - racerelease(chanbuf(c, 0)) - raceacquireg(sg.g, chanbuf(c, 0)) - racereleaseg(sg.g, chanbuf(c, 0)) - raceacquire(chanbuf(c, 0)) -} - -// Notify the race detector of a send or receive involving buffer entry idx -// and a channel c or its communicating partner sg. -// This function handles the special case of c.elemsize==0. -func racenotify(c *hchan, idx uint, sg *sudog) { - // We could have passed the unsafe.Pointer corresponding to entry idx - // instead of idx itself. However, in a future version of this function, - // we can use idx to better handle the case of elemsize==0. - // A future improvement to the detector is to call TSan with c and idx: - // this way, Go will continue to not allocating buffer entries for channels - // of elemsize==0, yet the race detector can be made to handle multiple - // sync objects underneath the hood (one sync object per idx) - qp := chanbuf(c, idx) - // When elemsize==0, we don't allocate a full buffer for the channel. - // Instead of individual buffer entries, the race detector uses the - // c.buf as the only buffer entry. This simplification prevents us from - // following the memory model's happens-before rules (rules that are - // implemented in racereleaseacquire). Instead, we accumulate happens-before - // information in the synchronization object associated with c.buf. - if c.elemsize == 0 { - if sg == nil { - raceacquire(qp) - racerelease(qp) - } else { - raceacquireg(sg.g, qp) - racereleaseg(sg.g, qp) - } - } else { - if sg == nil { - racereleaseacquire(qp) - } else { - racereleaseacquireg(sg.g, qp) - } - } -} diff --git a/contrib/go/_std_1.22/src/runtime/coro.go b/contrib/go/_std_1.22/src/runtime/coro.go deleted file mode 100644 index 0d6666e343b5..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coro.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -// A coro represents extra concurrency without extra parallelism, -// as would be needed for a coroutine implementation. -// The coro does not represent a specific coroutine, only the ability -// to do coroutine-style control transfers. -// It can be thought of as like a special channel that always has -// a goroutine blocked on it. If another goroutine calls coroswitch(c), -// the caller becomes the goroutine blocked in c, and the goroutine -// formerly blocked in c starts running. -// These switches continue until a call to coroexit(c), -// which ends the use of the coro by releasing the blocked -// goroutine in c and exiting the current goroutine. -// -// Coros are heap allocated and garbage collected, so that user code -// can hold a pointer to a coro without causing potential dangling -// pointer errors. -type coro struct { - gp guintptr - f func(*coro) -} - -//go:linkname newcoro - -// newcoro creates a new coro containing a -// goroutine blocked waiting to run f -// and returns that coro. -func newcoro(f func(*coro)) *coro { - c := new(coro) - c.f = f - pc := getcallerpc() - gp := getg() - systemstack(func() { - start := corostart - startfv := *(**funcval)(unsafe.Pointer(&start)) - gp = newproc1(startfv, gp, pc) - }) - gp.coroarg = c - gp.waitreason = waitReasonCoroutine - casgstatus(gp, _Grunnable, _Gwaiting) - c.gp.set(gp) - return c -} - -//go:linkname corostart - -// corostart is the entry func for a new coroutine. -// It runs the coroutine user function f passed to corostart -// and then calls coroexit to remove the extra concurrency. -func corostart() { - gp := getg() - c := gp.coroarg - gp.coroarg = nil - - c.f(c) - coroexit(c) -} - -// coroexit is like coroswitch but closes the coro -// and exits the current goroutine -func coroexit(c *coro) { - gp := getg() - gp.coroarg = c - gp.coroexit = true - mcall(coroswitch_m) -} - -//go:linkname coroswitch - -// coroswitch switches to the goroutine blocked on c -// and then blocks the current goroutine on c. -func coroswitch(c *coro) { - gp := getg() - gp.coroarg = c - mcall(coroswitch_m) -} - -// coroswitch_m is the implementation of coroswitch -// that runs on the m stack. -// -// Note: Coroutine switches are expected to happen at -// an order of magnitude (or more) higher frequency -// than regular goroutine switches, so this path is heavily -// optimized to remove unnecessary work. -// The fast path here is three CAS: the one at the top on gp.atomicstatus, -// the one in the middle to choose the next g, -// and the one at the bottom on gnext.atomicstatus. -// It is important not to add more atomic operations or other -// expensive operations to the fast path. -func coroswitch_m(gp *g) { - // TODO(rsc,mknyszek): add tracing support in a lightweight manner. - // Probably the tracer will need a global bool (set and cleared during STW) - // that this code can check to decide whether to use trace.gen.Load(); - // we do not want to do the atomic load all the time, especially when - // tracer use is relatively rare. - c := gp.coroarg - gp.coroarg = nil - exit := gp.coroexit - gp.coroexit = false - mp := gp.m - - if exit { - gdestroy(gp) - gp = nil - } else { - // If we can CAS ourselves directly from running to waiting, so do, - // keeping the control transfer as lightweight as possible. - gp.waitreason = waitReasonCoroutine - if !gp.atomicstatus.CompareAndSwap(_Grunning, _Gwaiting) { - // The CAS failed: use casgstatus, which will take care of - // coordinating with the garbage collector about the state change. - casgstatus(gp, _Grunning, _Gwaiting) - } - - // Clear gp.m. - setMNoWB(&gp.m, nil) - } - - // The goroutine stored in c is the one to run next. - // Swap it with ourselves. - var gnext *g - for { - // Note: this is a racy load, but it will eventually - // get the right value, and if it gets the wrong value, - // the c.gp.cas will fail, so no harm done other than - // a wasted loop iteration. - // The cas will also sync c.gp's - // memory enough that the next iteration of the racy load - // should see the correct value. - // We are avoiding the atomic load to keep this path - // as lightweight as absolutely possible. - // (The atomic load is free on x86 but not free elsewhere.) - next := c.gp - if next.ptr() == nil { - throw("coroswitch on exited coro") - } - var self guintptr - self.set(gp) - if c.gp.cas(next, self) { - gnext = next.ptr() - break - } - } - - // Start running next, without heavy scheduling machinery. - // Set mp.curg and gnext.m and then update scheduling state - // directly if possible. - setGNoWB(&mp.curg, gnext) - setMNoWB(&gnext.m, mp) - if !gnext.atomicstatus.CompareAndSwap(_Gwaiting, _Grunning) { - // The CAS failed: use casgstatus, which will take care of - // coordinating with the garbage collector about the state change. - casgstatus(gnext, _Gwaiting, _Grunnable) - casgstatus(gnext, _Grunnable, _Grunning) - } - - // Switch to gnext. Does not return. - gogo(&gnext.sched) -} diff --git a/contrib/go/_std_1.22/src/runtime/coverage/apis.go b/contrib/go/_std_1.22/src/runtime/coverage/apis.go deleted file mode 100644 index 15ba04a86f9c..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/apis.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package coverage - -import ( - "fmt" - "internal/coverage" - "io" - "sync/atomic" - "unsafe" -) - -// WriteMetaDir writes a coverage meta-data file for the currently -// running program to the directory specified in 'dir'. An error will -// be returned if the operation can't be completed successfully (for -// example, if the currently running program was not built with -// "-cover", or if the directory does not exist). -func WriteMetaDir(dir string) error { - if !finalHashComputed { - return fmt.Errorf("error: no meta-data available (binary not built with -cover?)") - } - return emitMetaDataToDirectory(dir, getCovMetaList()) -} - -// WriteMeta writes the meta-data content (the payload that would -// normally be emitted to a meta-data file) for the currently running -// program to the writer 'w'. An error will be returned if the -// operation can't be completed successfully (for example, if the -// currently running program was not built with "-cover", or if a -// write fails). -func WriteMeta(w io.Writer) error { - if w == nil { - return fmt.Errorf("error: nil writer in WriteMeta") - } - if !finalHashComputed { - return fmt.Errorf("error: no meta-data available (binary not built with -cover?)") - } - ml := getCovMetaList() - return writeMetaData(w, ml, cmode, cgran, finalHash) -} - -// WriteCountersDir writes a coverage counter-data file for the -// currently running program to the directory specified in 'dir'. An -// error will be returned if the operation can't be completed -// successfully (for example, if the currently running program was not -// built with "-cover", or if the directory does not exist). The -// counter data written will be a snapshot taken at the point of the -// call. -func WriteCountersDir(dir string) error { - if cmode != coverage.CtrModeAtomic { - return fmt.Errorf("WriteCountersDir invoked for program built with -covermode=%s (please use -covermode=atomic)", cmode.String()) - } - return emitCounterDataToDirectory(dir) -} - -// WriteCounters writes coverage counter-data content for the -// currently running program to the writer 'w'. An error will be -// returned if the operation can't be completed successfully (for -// example, if the currently running program was not built with -// "-cover", or if a write fails). The counter data written will be a -// snapshot taken at the point of the invocation. -func WriteCounters(w io.Writer) error { - if w == nil { - return fmt.Errorf("error: nil writer in WriteCounters") - } - if cmode != coverage.CtrModeAtomic { - return fmt.Errorf("WriteCounters invoked for program built with -covermode=%s (please use -covermode=atomic)", cmode.String()) - } - // Ask the runtime for the list of coverage counter symbols. - cl := getCovCounterList() - if len(cl) == 0 { - return fmt.Errorf("program not built with -cover") - } - if !finalHashComputed { - return fmt.Errorf("meta-data not written yet, unable to write counter data") - } - - pm := getCovPkgMap() - s := &emitState{ - counterlist: cl, - pkgmap: pm, - } - return s.emitCounterDataToWriter(w) -} - -// ClearCounters clears/resets all coverage counter variables in the -// currently running program. It returns an error if the program in -// question was not built with the "-cover" flag. Clearing of coverage -// counters is also not supported for programs not using atomic -// counter mode (see more detailed comments below for the rationale -// here). -func ClearCounters() error { - cl := getCovCounterList() - if len(cl) == 0 { - return fmt.Errorf("program not built with -cover") - } - if cmode != coverage.CtrModeAtomic { - return fmt.Errorf("ClearCounters invoked for program built with -covermode=%s (please use -covermode=atomic)", cmode.String()) - } - - // Implementation note: this function would be faster and simpler - // if we could just zero out the entire counter array, but for the - // moment we go through and zero out just the slots in the array - // corresponding to the counter values. We do this to avoid the - // following bad scenario: suppose that a user builds their Go - // program with "-cover", and that program has a function (call it - // main.XYZ) that invokes ClearCounters: - // - // func XYZ() { - // ... do some stuff ... - // coverage.ClearCounters() - // if someCondition { <<--- HERE - // ... - // } - // } - // - // At the point where ClearCounters executes, main.XYZ has not yet - // finished running, thus as soon as the call returns the line - // marked "HERE" above will trigger the writing of a non-zero - // value into main.XYZ's counter slab. However since we've just - // finished clearing the entire counter segment, we will have lost - // the values in the prolog portion of main.XYZ's counter slab - // (nctrs, pkgid, funcid). This means that later on at the end of - // program execution as we walk through the entire counter array - // for the program looking for executed functions, we'll zoom past - // main.XYZ's prolog (which was zero'd) and hit the non-zero - // counter value corresponding to the "HERE" block, which will - // then be interpreted as the start of another live function. - // Things will go downhill from there. - // - // This same scenario is also a potential risk if the program is - // running on an architecture that permits reordering of - // writes/stores, since the inconsistency described above could - // arise here. Example scenario: - // - // func ABC() { - // ... // prolog - // if alwaysTrue() { - // XYZ() // counter update here - // } - // } - // - // In the instrumented version of ABC, the prolog of the function - // will contain a series of stores to the initial portion of the - // counter array to write number-of-counters, pkgid, funcid. Later - // in the function there is also a store to increment a counter - // for the block containing the call to XYZ(). If the CPU is - // allowed to reorder stores and decides to issue the XYZ store - // before the prolog stores, this could be observable as an - // inconsistency similar to the one above. Hence the requirement - // for atomic counter mode: according to package atomic docs, - // "...operations that happen in a specific order on one thread, - // will always be observed to happen in exactly that order by - // another thread". Thus we can be sure that there will be no - // inconsistency when reading the counter array from the thread - // running ClearCounters. - - for _, c := range cl { - sd := unsafe.Slice((*atomic.Uint32)(unsafe.Pointer(c.Counters)), int(c.Len)) - for i := 0; i < len(sd); i++ { - // Skip ahead until the next non-zero value. - sdi := sd[i].Load() - if sdi == 0 { - continue - } - // We found a function that was executed; clear its counters. - nCtrs := sdi - for j := 0; j < int(nCtrs); j++ { - sd[i+coverage.FirstCtrOffset+j].Store(0) - } - // Move to next function. - i += coverage.FirstCtrOffset + int(nCtrs) - 1 - } - } - return nil -} diff --git a/contrib/go/_std_1.22/src/runtime/coverage/dummy.s b/contrib/go/_std_1.22/src/runtime/coverage/dummy.s deleted file mode 100644 index 75928593a0b4..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/dummy.s +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The runtime package uses //go:linkname to push a few functions into this -// package but we still need a .s file so the Go tool does not pass -complete -// to 'go tool compile' so the latter does not complain about Go functions -// with no bodies. diff --git a/contrib/go/_std_1.22/src/runtime/coverage/emit.go b/contrib/go/_std_1.22/src/runtime/coverage/emit.go deleted file mode 100644 index 6fe04daea8d0..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/emit.go +++ /dev/null @@ -1,609 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package coverage - -import ( - "crypto/md5" - "fmt" - "internal/coverage" - "internal/coverage/encodecounter" - "internal/coverage/encodemeta" - "internal/coverage/rtcov" - "io" - "os" - "path/filepath" - "runtime" - "strconv" - "sync/atomic" - "time" - "unsafe" -) - -// This file contains functions that support the writing of data files -// emitted at the end of code coverage testing runs, from instrumented -// executables. - -// getCovMetaList returns a list of meta-data blobs registered -// for the currently executing instrumented program. It is defined in the -// runtime. -func getCovMetaList() []rtcov.CovMetaBlob - -// getCovCounterList returns a list of counter-data blobs registered -// for the currently executing instrumented program. It is defined in the -// runtime. -func getCovCounterList() []rtcov.CovCounterBlob - -// getCovPkgMap returns a map storing the remapped package IDs for -// hard-coded runtime packages (see internal/coverage/pkgid.go for -// more on why hard-coded package IDs are needed). This function -// is defined in the runtime. -func getCovPkgMap() map[int]int - -// emitState holds useful state information during the emit process. -// -// When an instrumented program finishes execution and starts the -// process of writing out coverage data, it's possible that an -// existing meta-data file already exists in the output directory. In -// this case openOutputFiles() below will leave the 'mf' field below -// as nil. If a new meta-data file is needed, field 'mfname' will be -// the final desired path of the meta file, 'mftmp' will be a -// temporary file, and 'mf' will be an open os.File pointer for -// 'mftmp'. The meta-data file payload will be written to 'mf', the -// temp file will be then closed and renamed (from 'mftmp' to -// 'mfname'), so as to insure that the meta-data file is created -// atomically; we want this so that things work smoothly in cases -// where there are several instances of a given instrumented program -// all terminating at the same time and trying to create meta-data -// files simultaneously. -// -// For counter data files there is less chance of a collision, hence -// the openOutputFiles() stores the counter data file in 'cfname' and -// then places the *io.File into 'cf'. -type emitState struct { - mfname string // path of final meta-data output file - mftmp string // path to meta-data temp file (if needed) - mf *os.File // open os.File for meta-data temp file - cfname string // path of final counter data file - cftmp string // path to counter data temp file - cf *os.File // open os.File for counter data file - outdir string // output directory - - // List of meta-data symbols obtained from the runtime - metalist []rtcov.CovMetaBlob - - // List of counter-data symbols obtained from the runtime - counterlist []rtcov.CovCounterBlob - - // Table to use for remapping hard-coded pkg ids. - pkgmap map[int]int - - // emit debug trace output - debug bool -} - -var ( - // finalHash is computed at init time from the list of meta-data - // symbols registered during init. It is used both for writing the - // meta-data file and counter-data files. - finalHash [16]byte - // Set to true when we've computed finalHash + finalMetaLen. - finalHashComputed bool - // Total meta-data length. - finalMetaLen uint64 - // Records whether we've already attempted to write meta-data. - metaDataEmitAttempted bool - // Counter mode for this instrumented program run. - cmode coverage.CounterMode - // Counter granularity for this instrumented program run. - cgran coverage.CounterGranularity - // Cached value of GOCOVERDIR environment variable. - goCoverDir string - // Copy of os.Args made at init time, converted into map format. - capturedOsArgs map[string]string - // Flag used in tests to signal that coverage data already written. - covProfileAlreadyEmitted bool -) - -// fileType is used to select between counter-data files and -// meta-data files. -type fileType int - -const ( - noFile = 1 << iota - metaDataFile - counterDataFile -) - -// emitMetaData emits the meta-data output file for this coverage run. -// This entry point is intended to be invoked by the compiler from -// an instrumented program's main package init func. -func emitMetaData() { - if covProfileAlreadyEmitted { - return - } - ml, err := prepareForMetaEmit() - if err != nil { - fmt.Fprintf(os.Stderr, "error: coverage meta-data prep failed: %v\n", err) - if os.Getenv("GOCOVERDEBUG") != "" { - panic("meta-data write failure") - } - } - if len(ml) == 0 { - fmt.Fprintf(os.Stderr, "program not built with -cover\n") - return - } - - goCoverDir = os.Getenv("GOCOVERDIR") - if goCoverDir == "" { - fmt.Fprintf(os.Stderr, "warning: GOCOVERDIR not set, no coverage data emitted\n") - return - } - - if err := emitMetaDataToDirectory(goCoverDir, ml); err != nil { - fmt.Fprintf(os.Stderr, "error: coverage meta-data emit failed: %v\n", err) - if os.Getenv("GOCOVERDEBUG") != "" { - panic("meta-data write failure") - } - } -} - -func modeClash(m coverage.CounterMode) bool { - if m == coverage.CtrModeRegOnly || m == coverage.CtrModeTestMain { - return false - } - if cmode == coverage.CtrModeInvalid { - cmode = m - return false - } - return cmode != m -} - -func granClash(g coverage.CounterGranularity) bool { - if cgran == coverage.CtrGranularityInvalid { - cgran = g - return false - } - return cgran != g -} - -// prepareForMetaEmit performs preparatory steps needed prior to -// emitting a meta-data file, notably computing a final hash of -// all meta-data blobs and capturing os args. -func prepareForMetaEmit() ([]rtcov.CovMetaBlob, error) { - // Ask the runtime for the list of coverage meta-data symbols. - ml := getCovMetaList() - - // In the normal case (go build -o prog.exe ... ; ./prog.exe) - // len(ml) will always be non-zero, but we check here since at - // some point this function will be reachable via user-callable - // APIs (for example, to write out coverage data from a server - // program that doesn't ever call os.Exit). - if len(ml) == 0 { - return nil, nil - } - - s := &emitState{ - metalist: ml, - debug: os.Getenv("GOCOVERDEBUG") != "", - } - - // Capture os.Args() now so as to avoid issues if args - // are rewritten during program execution. - capturedOsArgs = captureOsArgs() - - if s.debug { - fmt.Fprintf(os.Stderr, "=+= GOCOVERDIR is %s\n", os.Getenv("GOCOVERDIR")) - fmt.Fprintf(os.Stderr, "=+= contents of covmetalist:\n") - for k, b := range ml { - fmt.Fprintf(os.Stderr, "=+= slot: %d path: %s ", k, b.PkgPath) - if b.PkgID != -1 { - fmt.Fprintf(os.Stderr, " hcid: %d", b.PkgID) - } - fmt.Fprintf(os.Stderr, "\n") - } - pm := getCovPkgMap() - fmt.Fprintf(os.Stderr, "=+= remap table:\n") - for from, to := range pm { - fmt.Fprintf(os.Stderr, "=+= from %d to %d\n", - uint32(from), uint32(to)) - } - } - - h := md5.New() - tlen := uint64(unsafe.Sizeof(coverage.MetaFileHeader{})) - for _, entry := range ml { - if _, err := h.Write(entry.Hash[:]); err != nil { - return nil, err - } - tlen += uint64(entry.Len) - ecm := coverage.CounterMode(entry.CounterMode) - if modeClash(ecm) { - return nil, fmt.Errorf("coverage counter mode clash: package %s uses mode=%d, but package %s uses mode=%s\n", ml[0].PkgPath, cmode, entry.PkgPath, ecm) - } - ecg := coverage.CounterGranularity(entry.CounterGranularity) - if granClash(ecg) { - return nil, fmt.Errorf("coverage counter granularity clash: package %s uses gran=%d, but package %s uses gran=%s\n", ml[0].PkgPath, cgran, entry.PkgPath, ecg) - } - } - - // Hash mode and granularity as well. - h.Write([]byte(cmode.String())) - h.Write([]byte(cgran.String())) - - // Compute final digest. - fh := h.Sum(nil) - copy(finalHash[:], fh) - finalHashComputed = true - finalMetaLen = tlen - - return ml, nil -} - -// emitMetaDataToDirectory emits the meta-data output file to the specified -// directory, returning an error if something went wrong. -func emitMetaDataToDirectory(outdir string, ml []rtcov.CovMetaBlob) error { - ml, err := prepareForMetaEmit() - if err != nil { - return err - } - if len(ml) == 0 { - return nil - } - - metaDataEmitAttempted = true - - s := &emitState{ - metalist: ml, - debug: os.Getenv("GOCOVERDEBUG") != "", - outdir: outdir, - } - - // Open output files. - if err := s.openOutputFiles(finalHash, finalMetaLen, metaDataFile); err != nil { - return err - } - - // Emit meta-data file only if needed (may already be present). - if s.needMetaDataFile() { - if err := s.emitMetaDataFile(finalHash, finalMetaLen); err != nil { - return err - } - } - return nil -} - -// emitCounterData emits the counter data output file for this coverage run. -// This entry point is intended to be invoked by the runtime when an -// instrumented program is terminating or calling os.Exit(). -func emitCounterData() { - if goCoverDir == "" || !finalHashComputed || covProfileAlreadyEmitted { - return - } - if err := emitCounterDataToDirectory(goCoverDir); err != nil { - fmt.Fprintf(os.Stderr, "error: coverage counter data emit failed: %v\n", err) - if os.Getenv("GOCOVERDEBUG") != "" { - panic("counter-data write failure") - } - } -} - -// emitCounterDataToDirectory emits the counter-data output file for this coverage run. -func emitCounterDataToDirectory(outdir string) error { - // Ask the runtime for the list of coverage counter symbols. - cl := getCovCounterList() - if len(cl) == 0 { - // no work to do here. - return nil - } - - if !finalHashComputed { - return fmt.Errorf("error: meta-data not available (binary not built with -cover?)") - } - - // Ask the runtime for the list of coverage counter symbols. - pm := getCovPkgMap() - s := &emitState{ - counterlist: cl, - pkgmap: pm, - outdir: outdir, - debug: os.Getenv("GOCOVERDEBUG") != "", - } - - // Open output file. - if err := s.openOutputFiles(finalHash, finalMetaLen, counterDataFile); err != nil { - return err - } - if s.cf == nil { - return fmt.Errorf("counter data output file open failed (no additional info") - } - - // Emit counter data file. - if err := s.emitCounterDataFile(finalHash, s.cf); err != nil { - return err - } - if err := s.cf.Close(); err != nil { - return fmt.Errorf("closing counter data file: %v", err) - } - - // Counter file has now been closed. Rename the temp to the - // final desired path. - if err := os.Rename(s.cftmp, s.cfname); err != nil { - return fmt.Errorf("writing %s: rename from %s failed: %v\n", s.cfname, s.cftmp, err) - } - - return nil -} - -// emitCounterDataToWriter emits counter data for this coverage run to an io.Writer. -func (s *emitState) emitCounterDataToWriter(w io.Writer) error { - if err := s.emitCounterDataFile(finalHash, w); err != nil { - return err - } - return nil -} - -// openMetaFile determines whether we need to emit a meta-data output -// file, or whether we can reuse the existing file in the coverage out -// dir. It updates mfname/mftmp/mf fields in 's', returning an error -// if something went wrong. See the comment on the emitState type -// definition above for more on how file opening is managed. -func (s *emitState) openMetaFile(metaHash [16]byte, metaLen uint64) error { - - // Open meta-outfile for reading to see if it exists. - fn := fmt.Sprintf("%s.%x", coverage.MetaFilePref, metaHash) - s.mfname = filepath.Join(s.outdir, fn) - fi, err := os.Stat(s.mfname) - if err != nil || fi.Size() != int64(metaLen) { - // We need a new meta-file. - tname := "tmp." + fn + strconv.FormatInt(time.Now().UnixNano(), 10) - s.mftmp = filepath.Join(s.outdir, tname) - s.mf, err = os.Create(s.mftmp) - if err != nil { - return fmt.Errorf("creating meta-data file %s: %v", s.mftmp, err) - } - } - return nil -} - -// openCounterFile opens an output file for the counter data portion -// of a test coverage run. If updates the 'cfname' and 'cf' fields in -// 's', returning an error if something went wrong. -func (s *emitState) openCounterFile(metaHash [16]byte) error { - processID := os.Getpid() - fn := fmt.Sprintf(coverage.CounterFileTempl, coverage.CounterFilePref, metaHash, processID, time.Now().UnixNano()) - s.cfname = filepath.Join(s.outdir, fn) - s.cftmp = filepath.Join(s.outdir, "tmp."+fn) - var err error - s.cf, err = os.Create(s.cftmp) - if err != nil { - return fmt.Errorf("creating counter data file %s: %v", s.cftmp, err) - } - return nil -} - -// openOutputFiles opens output files in preparation for emitting -// coverage data. In the case of the meta-data file, openOutputFiles -// may determine that we can reuse an existing meta-data file in the -// outdir, in which case it will leave the 'mf' field in the state -// struct as nil. If a new meta-file is needed, the field 'mfname' -// will be the final desired path of the meta file, 'mftmp' will be a -// temporary file, and 'mf' will be an open os.File pointer for -// 'mftmp'. The idea is that the client/caller will write content into -// 'mf', close it, and then rename 'mftmp' to 'mfname'. This function -// also opens the counter data output file, setting 'cf' and 'cfname' -// in the state struct. -func (s *emitState) openOutputFiles(metaHash [16]byte, metaLen uint64, which fileType) error { - fi, err := os.Stat(s.outdir) - if err != nil { - return fmt.Errorf("output directory %q inaccessible (err: %v); no coverage data written", s.outdir, err) - } - if !fi.IsDir() { - return fmt.Errorf("output directory %q not a directory; no coverage data written", s.outdir) - } - - if (which & metaDataFile) != 0 { - if err := s.openMetaFile(metaHash, metaLen); err != nil { - return err - } - } - if (which & counterDataFile) != 0 { - if err := s.openCounterFile(metaHash); err != nil { - return err - } - } - return nil -} - -// emitMetaDataFile emits coverage meta-data to a previously opened -// temporary file (s.mftmp), then renames the generated file to the -// final path (s.mfname). -func (s *emitState) emitMetaDataFile(finalHash [16]byte, tlen uint64) error { - if err := writeMetaData(s.mf, s.metalist, cmode, cgran, finalHash); err != nil { - return fmt.Errorf("writing %s: %v\n", s.mftmp, err) - } - if err := s.mf.Close(); err != nil { - return fmt.Errorf("closing meta data temp file: %v", err) - } - - // Temp file has now been flushed and closed. Rename the temp to the - // final desired path. - if err := os.Rename(s.mftmp, s.mfname); err != nil { - return fmt.Errorf("writing %s: rename from %s failed: %v\n", s.mfname, s.mftmp, err) - } - - return nil -} - -// needMetaDataFile returns TRUE if we need to emit a meta-data file -// for this program run. It should be used only after -// openOutputFiles() has been invoked. -func (s *emitState) needMetaDataFile() bool { - return s.mf != nil -} - -func writeMetaData(w io.Writer, metalist []rtcov.CovMetaBlob, cmode coverage.CounterMode, gran coverage.CounterGranularity, finalHash [16]byte) error { - mfw := encodemeta.NewCoverageMetaFileWriter("", w) - - var blobs [][]byte - for _, e := range metalist { - sd := unsafe.Slice(e.P, int(e.Len)) - blobs = append(blobs, sd) - } - return mfw.Write(finalHash, blobs, cmode, gran) -} - -func (s *emitState) VisitFuncs(f encodecounter.CounterVisitorFn) error { - var tcounters []uint32 - - rdCounters := func(actrs []atomic.Uint32, ctrs []uint32) []uint32 { - ctrs = ctrs[:0] - for i := range actrs { - ctrs = append(ctrs, actrs[i].Load()) - } - return ctrs - } - - dpkg := uint32(0) - for _, c := range s.counterlist { - sd := unsafe.Slice((*atomic.Uint32)(unsafe.Pointer(c.Counters)), int(c.Len)) - for i := 0; i < len(sd); i++ { - // Skip ahead until the next non-zero value. - sdi := sd[i].Load() - if sdi == 0 { - continue - } - - // We found a function that was executed. - nCtrs := sd[i+coverage.NumCtrsOffset].Load() - pkgId := sd[i+coverage.PkgIdOffset].Load() - funcId := sd[i+coverage.FuncIdOffset].Load() - cst := i + coverage.FirstCtrOffset - counters := sd[cst : cst+int(nCtrs)] - - // Check to make sure that we have at least one live - // counter. See the implementation note in ClearCoverageCounters - // for a description of why this is needed. - isLive := false - for i := 0; i < len(counters); i++ { - if counters[i].Load() != 0 { - isLive = true - break - } - } - if !isLive { - // Skip this function. - i += coverage.FirstCtrOffset + int(nCtrs) - 1 - continue - } - - if s.debug { - if pkgId != dpkg { - dpkg = pkgId - fmt.Fprintf(os.Stderr, "\n=+= %d: pk=%d visit live fcn", - i, pkgId) - } - fmt.Fprintf(os.Stderr, " {i=%d F%d NC%d}", i, funcId, nCtrs) - } - - // Vet and/or fix up package ID. A package ID of zero - // indicates that there is some new package X that is a - // runtime dependency, and this package has code that - // executes before its corresponding init package runs. - // This is a fatal error that we should only see during - // Go development (e.g. tip). - ipk := int32(pkgId) - if ipk == 0 { - fmt.Fprintf(os.Stderr, "\n") - reportErrorInHardcodedList(int32(i), ipk, funcId, nCtrs) - } else if ipk < 0 { - if newId, ok := s.pkgmap[int(ipk)]; ok { - pkgId = uint32(newId) - } else { - fmt.Fprintf(os.Stderr, "\n") - reportErrorInHardcodedList(int32(i), ipk, funcId, nCtrs) - } - } else { - // The package ID value stored in the counter array - // has 1 added to it (so as to preclude the - // possibility of a zero value ; see - // runtime.addCovMeta), so subtract off 1 here to form - // the real package ID. - pkgId-- - } - - tcounters = rdCounters(counters, tcounters) - if err := f(pkgId, funcId, tcounters); err != nil { - return err - } - - // Skip over this function. - i += coverage.FirstCtrOffset + int(nCtrs) - 1 - } - if s.debug { - fmt.Fprintf(os.Stderr, "\n") - } - } - return nil -} - -// captureOsArgs converts os.Args() into the format we use to store -// this info in the counter data file (counter data file "args" -// section is a generic key-value collection). See the 'args' section -// in internal/coverage/defs.go for more info. The args map -// is also used to capture GOOS + GOARCH values as well. -func captureOsArgs() map[string]string { - m := make(map[string]string) - m["argc"] = strconv.Itoa(len(os.Args)) - for k, a := range os.Args { - m[fmt.Sprintf("argv%d", k)] = a - } - m["GOOS"] = runtime.GOOS - m["GOARCH"] = runtime.GOARCH - return m -} - -// emitCounterDataFile emits the counter data portion of a -// coverage output file (to the file 's.cf'). -func (s *emitState) emitCounterDataFile(finalHash [16]byte, w io.Writer) error { - cfw := encodecounter.NewCoverageDataWriter(w, coverage.CtrULeb128) - if err := cfw.Write(finalHash, capturedOsArgs, s); err != nil { - return err - } - return nil -} - -// markProfileEmitted signals the runtime/coverage machinery that -// coverage data output files have already been written out, and there -// is no need to take any additional action at exit time. This -// function is called (via linknamed reference) from the -// coverage-related boilerplate code in _testmain.go emitted for go -// unit tests. -func markProfileEmitted(val bool) { - covProfileAlreadyEmitted = val -} - -func reportErrorInHardcodedList(slot, pkgID int32, fnID, nCtrs uint32) { - metaList := getCovMetaList() - pkgMap := getCovPkgMap() - - println("internal error in coverage meta-data tracking:") - println("encountered bad pkgID:", pkgID, " at slot:", slot, - " fnID:", fnID, " numCtrs:", nCtrs) - println("list of hard-coded runtime package IDs needs revising.") - println("[see the comment on the 'rtPkgs' var in ") - println(" /src/internal/coverage/pkid.go]") - println("registered list:") - for k, b := range metaList { - print("slot: ", k, " path='", b.PkgPath, "' ") - if b.PkgID != -1 { - print(" hard-coded id: ", b.PkgID) - } - println("") - } - println("remap table:") - for from, to := range pkgMap { - println("from ", from, " to ", to) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/coverage/hooks.go b/contrib/go/_std_1.22/src/runtime/coverage/hooks.go deleted file mode 100644 index a9fbf9d7dd18..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/hooks.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package coverage - -import _ "unsafe" - -// initHook is invoked from the main package "init" routine in -// programs built with "-cover". This function is intended to be -// called only by the compiler. -// -// If 'istest' is false, it indicates we're building a regular program -// ("go build -cover ..."), in which case we immediately try to write -// out the meta-data file, and register emitCounterData as an exit -// hook. -// -// If 'istest' is true (indicating that the program in question is a -// Go test binary), then we tentatively queue up both emitMetaData and -// emitCounterData as exit hooks. In the normal case (e.g. regular "go -// test -cover" run) the testmain.go boilerplate will run at the end -// of the test, write out the coverage percentage, and then invoke -// markProfileEmitted() to indicate that no more work needs to be -// done. If however that call is never made, this is a sign that the -// test binary is being used as a replacement binary for the tool -// being tested, hence we do want to run exit hooks when the program -// terminates. -func initHook(istest bool) { - // Note: hooks are run in reverse registration order, so - // register the counter data hook before the meta-data hook - // (in the case where two hooks are needed). - runOnNonZeroExit := true - runtime_addExitHook(emitCounterData, runOnNonZeroExit) - if istest { - runtime_addExitHook(emitMetaData, runOnNonZeroExit) - } else { - emitMetaData() - } -} - -//go:linkname runtime_addExitHook runtime.addExitHook -func runtime_addExitHook(f func(), runOnNonZeroExit bool) diff --git a/contrib/go/_std_1.22/src/runtime/coverage/testsupport.go b/contrib/go/_std_1.22/src/runtime/coverage/testsupport.go deleted file mode 100644 index f169580618a5..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/testsupport.go +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package coverage - -import ( - "encoding/json" - "fmt" - "internal/coverage" - "internal/coverage/calloc" - "internal/coverage/cformat" - "internal/coverage/cmerge" - "internal/coverage/decodecounter" - "internal/coverage/decodemeta" - "internal/coverage/pods" - "io" - "os" - "path/filepath" - "runtime/internal/atomic" - "strings" - "unsafe" -) - -// processCoverTestDir is called (via a linknamed reference) from -// testmain code when "go test -cover" is in effect. It is not -// intended to be used other than internally by the Go command's -// generated code. -func processCoverTestDir(dir string, cfile string, cm string, cpkg string) error { - return processCoverTestDirInternal(dir, cfile, cm, cpkg, os.Stdout) -} - -// processCoverTestDirInternal is an io.Writer version of processCoverTestDir, -// exposed for unit testing. -func processCoverTestDirInternal(dir string, cfile string, cm string, cpkg string, w io.Writer) error { - cmode := coverage.ParseCounterMode(cm) - if cmode == coverage.CtrModeInvalid { - return fmt.Errorf("invalid counter mode %q", cm) - } - - // Emit meta-data and counter data. - ml := getCovMetaList() - if len(ml) == 0 { - // This corresponds to the case where we have a package that - // contains test code but no functions (which is fine). In this - // case there is no need to emit anything. - } else { - if err := emitMetaDataToDirectory(dir, ml); err != nil { - return err - } - if err := emitCounterDataToDirectory(dir); err != nil { - return err - } - } - - // Collect pods from test run. For the majority of cases we would - // expect to see a single pod here, but allow for multiple pods in - // case the test harness is doing extra work to collect data files - // from builds that it kicks off as part of the testing. - podlist, err := pods.CollectPods([]string{dir}, false) - if err != nil { - return fmt.Errorf("reading from %s: %v", dir, err) - } - - // Open text output file if appropriate. - var tf *os.File - var tfClosed bool - if cfile != "" { - var err error - tf, err = os.Create(cfile) - if err != nil { - return fmt.Errorf("internal error: opening coverage data output file %q: %v", cfile, err) - } - defer func() { - if !tfClosed { - tfClosed = true - tf.Close() - } - }() - } - - // Read/process the pods. - ts := &tstate{ - cm: &cmerge.Merger{}, - cf: cformat.NewFormatter(cmode), - cmode: cmode, - } - // Generate the expected hash string based on the final meta-data - // hash for this test, then look only for pods that refer to that - // hash (just in case there are multiple instrumented executables - // in play). See issue #57924 for more on this. - hashstring := fmt.Sprintf("%x", finalHash) - importpaths := make(map[string]struct{}) - for _, p := range podlist { - if !strings.Contains(p.MetaFile, hashstring) { - continue - } - if err := ts.processPod(p, importpaths); err != nil { - return err - } - } - - metafilespath := filepath.Join(dir, coverage.MetaFilesFileName) - if _, err := os.Stat(metafilespath); err == nil { - if err := ts.readAuxMetaFiles(metafilespath, importpaths); err != nil { - return err - } - } - - // Emit percent. - if err := ts.cf.EmitPercent(w, cpkg, true, true); err != nil { - return err - } - - // Emit text output. - if tf != nil { - if err := ts.cf.EmitTextual(tf); err != nil { - return err - } - tfClosed = true - if err := tf.Close(); err != nil { - return fmt.Errorf("closing %s: %v", cfile, err) - } - } - - return nil -} - -type tstate struct { - calloc.BatchCounterAlloc - cm *cmerge.Merger - cf *cformat.Formatter - cmode coverage.CounterMode -} - -// processPod reads coverage counter data for a specific pod. -func (ts *tstate) processPod(p pods.Pod, importpaths map[string]struct{}) error { - // Open meta-data file - f, err := os.Open(p.MetaFile) - if err != nil { - return fmt.Errorf("unable to open meta-data file %s: %v", p.MetaFile, err) - } - defer func() { - f.Close() - }() - var mfr *decodemeta.CoverageMetaFileReader - mfr, err = decodemeta.NewCoverageMetaFileReader(f, nil) - if err != nil { - return fmt.Errorf("error reading meta-data file %s: %v", p.MetaFile, err) - } - newmode := mfr.CounterMode() - if newmode != ts.cmode { - return fmt.Errorf("internal error: counter mode clash: %q from test harness, %q from data file %s", ts.cmode.String(), newmode.String(), p.MetaFile) - } - newgran := mfr.CounterGranularity() - if err := ts.cm.SetModeAndGranularity(p.MetaFile, cmode, newgran); err != nil { - return err - } - - // A map to store counter data, indexed by pkgid/fnid tuple. - pmm := make(map[pkfunc][]uint32) - - // Helper to read a single counter data file. - readcdf := func(cdf string) error { - cf, err := os.Open(cdf) - if err != nil { - return fmt.Errorf("opening counter data file %s: %s", cdf, err) - } - defer cf.Close() - var cdr *decodecounter.CounterDataReader - cdr, err = decodecounter.NewCounterDataReader(cdf, cf) - if err != nil { - return fmt.Errorf("reading counter data file %s: %s", cdf, err) - } - var data decodecounter.FuncPayload - for { - ok, err := cdr.NextFunc(&data) - if err != nil { - return fmt.Errorf("reading counter data file %s: %v", cdf, err) - } - if !ok { - break - } - - // NB: sanity check on pkg and func IDs? - key := pkfunc{pk: data.PkgIdx, fcn: data.FuncIdx} - if prev, found := pmm[key]; found { - // Note: no overflow reporting here. - if err, _ := ts.cm.MergeCounters(data.Counters, prev); err != nil { - return fmt.Errorf("processing counter data file %s: %v", cdf, err) - } - } - c := ts.AllocateCounters(len(data.Counters)) - copy(c, data.Counters) - pmm[key] = c - } - return nil - } - - // Read counter data files. - for _, cdf := range p.CounterDataFiles { - if err := readcdf(cdf); err != nil { - return err - } - } - - // Visit meta-data file. - np := uint32(mfr.NumPackages()) - payload := []byte{} - for pkIdx := uint32(0); pkIdx < np; pkIdx++ { - var pd *decodemeta.CoverageMetaDataDecoder - pd, payload, err = mfr.GetPackageDecoder(pkIdx, payload) - if err != nil { - return fmt.Errorf("reading pkg %d from meta-file %s: %s", pkIdx, p.MetaFile, err) - } - ts.cf.SetPackage(pd.PackagePath()) - importpaths[pd.PackagePath()] = struct{}{} - var fd coverage.FuncDesc - nf := pd.NumFuncs() - for fnIdx := uint32(0); fnIdx < nf; fnIdx++ { - if err := pd.ReadFunc(fnIdx, &fd); err != nil { - return fmt.Errorf("reading meta-data file %s: %v", - p.MetaFile, err) - } - key := pkfunc{pk: pkIdx, fcn: fnIdx} - counters, haveCounters := pmm[key] - for i := 0; i < len(fd.Units); i++ { - u := fd.Units[i] - // Skip units with non-zero parent (no way to represent - // these in the existing format). - if u.Parent != 0 { - continue - } - count := uint32(0) - if haveCounters { - count = counters[i] - } - ts.cf.AddUnit(fd.Srcfile, fd.Funcname, fd.Lit, u, count) - } - } - } - return nil -} - -type pkfunc struct { - pk, fcn uint32 -} - -func (ts *tstate) readAuxMetaFiles(metafiles string, importpaths map[string]struct{}) error { - // Unmarshall the information on available aux metafiles into - // a MetaFileCollection struct. - var mfc coverage.MetaFileCollection - data, err := os.ReadFile(metafiles) - if err != nil { - return fmt.Errorf("error reading auxmetafiles file %q: %v", metafiles, err) - } - if err := json.Unmarshal(data, &mfc); err != nil { - return fmt.Errorf("error reading auxmetafiles file %q: %v", metafiles, err) - } - - // Walk through each available aux meta-file. If we've already - // seen the package path in question during the walk of the - // "regular" meta-data file, then we can skip the package, - // otherwise construct a dummy pod with the single meta-data file - // (no counters) and invoke processPod on it. - for i := range mfc.ImportPaths { - p := mfc.ImportPaths[i] - if _, ok := importpaths[p]; ok { - continue - } - var pod pods.Pod - pod.MetaFile = mfc.MetaFileFragments[i] - if err := ts.processPod(pod, importpaths); err != nil { - return err - } - } - return nil -} - -// snapshot returns a snapshot of coverage percentage at a moment of -// time within a running test, so as to support the testing.Coverage() -// function. This version doesn't examine coverage meta-data, so the -// result it returns will be less accurate (more "slop") due to the -// fact that we don't look at the meta data to see how many statements -// are associated with each counter. -func snapshot() float64 { - cl := getCovCounterList() - if len(cl) == 0 { - // no work to do here. - return 0.0 - } - - tot := uint64(0) - totExec := uint64(0) - for _, c := range cl { - sd := unsafe.Slice((*atomic.Uint32)(unsafe.Pointer(c.Counters)), c.Len) - tot += uint64(len(sd)) - for i := 0; i < len(sd); i++ { - // Skip ahead until the next non-zero value. - if sd[i].Load() == 0 { - continue - } - // We found a function that was executed. - nCtrs := sd[i+coverage.NumCtrsOffset].Load() - cst := i + coverage.FirstCtrOffset - - if cst+int(nCtrs) > len(sd) { - break - } - counters := sd[cst : cst+int(nCtrs)] - for i := range counters { - if counters[i].Load() != 0 { - totExec++ - } - } - i += coverage.FirstCtrOffset + int(nCtrs) - 1 - } - } - if tot == 0 { - return 0.0 - } - return float64(totExec) / float64(tot) -} diff --git a/contrib/go/_std_1.22/src/runtime/coverage/ya.make b/contrib/go/_std_1.22/src/runtime/coverage/ya.make deleted file mode 100644 index f62e9cabccdc..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (TRUE) - SRCS( - apis.go - dummy.s - emit.go - hooks.go - testsupport.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/runtime/covermeta.go b/contrib/go/_std_1.22/src/runtime/covermeta.go deleted file mode 100644 index 54ef42ae1ff4..000000000000 --- a/contrib/go/_std_1.22/src/runtime/covermeta.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/coverage/rtcov" - "unsafe" -) - -// covMeta is the top-level container for bits of state related to -// code coverage meta-data in the runtime. -var covMeta struct { - // metaList contains the list of currently registered meta-data - // blobs for the running program. - metaList []rtcov.CovMetaBlob - - // pkgMap records mappings from hard-coded package IDs to - // slots in the covMetaList above. - pkgMap map[int]int - - // Set to true if we discover a package mapping glitch. - hardCodedListNeedsUpdating bool -} - -// addCovMeta is invoked during package "init" functions by the -// compiler when compiling for coverage instrumentation; here 'p' is a -// meta-data blob of length 'dlen' for the package in question, 'hash' -// is a compiler-computed md5.sum for the blob, 'pkpath' is the -// package path, 'pkid' is the hard-coded ID that the compiler is -// using for the package (or -1 if the compiler doesn't think a -// hard-coded ID is needed), and 'cmode'/'cgran' are the coverage -// counter mode and granularity requested by the user. Return value is -// the ID for the package for use by the package code itself. -func addCovMeta(p unsafe.Pointer, dlen uint32, hash [16]byte, pkpath string, pkid int, cmode uint8, cgran uint8) uint32 { - slot := len(covMeta.metaList) - covMeta.metaList = append(covMeta.metaList, - rtcov.CovMetaBlob{ - P: (*byte)(p), - Len: dlen, - Hash: hash, - PkgPath: pkpath, - PkgID: pkid, - CounterMode: cmode, - CounterGranularity: cgran, - }) - if pkid != -1 { - if covMeta.pkgMap == nil { - covMeta.pkgMap = make(map[int]int) - } - if _, ok := covMeta.pkgMap[pkid]; ok { - throw("runtime.addCovMeta: coverage package map collision") - } - // Record the real slot (position on meta-list) for this - // package; we'll use the map to fix things up later on. - covMeta.pkgMap[pkid] = slot - } - - // ID zero is reserved as invalid. - return uint32(slot + 1) -} - -//go:linkname runtime_coverage_getCovMetaList runtime/coverage.getCovMetaList -func runtime_coverage_getCovMetaList() []rtcov.CovMetaBlob { - return covMeta.metaList -} - -//go:linkname runtime_coverage_getCovPkgMap runtime/coverage.getCovPkgMap -func runtime_coverage_getCovPkgMap() map[int]int { - return covMeta.pkgMap -} diff --git a/contrib/go/_std_1.22/src/runtime/debug.go b/contrib/go/_std_1.22/src/runtime/debug.go deleted file mode 100644 index 3233ce8ee737..000000000000 --- a/contrib/go/_std_1.22/src/runtime/debug.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "runtime/internal/atomic" - "unsafe" -) - -// GOMAXPROCS sets the maximum number of CPUs that can be executing -// simultaneously and returns the previous setting. It defaults to -// the value of [runtime.NumCPU]. If n < 1, it does not change the current setting. -// This call will go away when the scheduler improves. -func GOMAXPROCS(n int) int { - if GOARCH == "wasm" && n > 1 { - n = 1 // WebAssembly has no threads yet, so only one CPU is possible. - } - - lock(&sched.lock) - ret := int(gomaxprocs) - unlock(&sched.lock) - if n <= 0 || n == ret { - return ret - } - - stw := stopTheWorldGC(stwGOMAXPROCS) - - // newprocs will be processed by startTheWorld - newprocs = int32(n) - - startTheWorldGC(stw) - return ret -} - -// NumCPU returns the number of logical CPUs usable by the current process. -// -// The set of available CPUs is checked by querying the operating system -// at process startup. Changes to operating system CPU allocation after -// process startup are not reflected. -func NumCPU() int { - return int(ncpu) -} - -// NumCgoCall returns the number of cgo calls made by the current process. -func NumCgoCall() int64 { - var n = int64(atomic.Load64(&ncgocall)) - for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { - n += int64(mp.ncgocall) - } - return n -} - -func totalMutexWaitTimeNanos() int64 { - total := sched.totalMutexWaitTime.Load() - - total += sched.totalRuntimeLockWaitTime.Load() - for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { - total += mp.mLockProfile.waitTime.Load() - } - - return total -} - -// NumGoroutine returns the number of goroutines that currently exist. -func NumGoroutine() int { - return int(gcount()) -} - -//go:linkname debug_modinfo runtime/debug.modinfo -func debug_modinfo() string { - return modinfo -} - -// mayMoreStackPreempt is a maymorestack hook that forces a preemption -// at every possible cooperative preemption point. -// -// This is valuable to apply to the runtime, which can be sensitive to -// preemption points. To apply this to all preemption points in the -// runtime and runtime-like code, use the following in bash or zsh: -// -// X=(-{gc,asm}flags={runtime/...,reflect,sync}=-d=maymorestack=runtime.mayMoreStackPreempt) GOFLAGS=${X[@]} -// -// This must be deeply nosplit because it is called from a function -// prologue before the stack is set up and because the compiler will -// call it from any splittable prologue (leading to infinite -// recursion). -// -// Ideally it should also use very little stack because the linker -// doesn't currently account for this in nosplit stack depth checking. -// -// Ensure mayMoreStackPreempt can be called for all ABIs. -// -//go:nosplit -//go:linkname mayMoreStackPreempt -func mayMoreStackPreempt() { - // Don't do anything on the g0 or gsignal stack. - gp := getg() - if gp == gp.m.g0 || gp == gp.m.gsignal { - return - } - // Force a preemption, unless the stack is already poisoned. - if gp.stackguard0 < stackPoisonMin { - gp.stackguard0 = stackPreempt - } -} - -// mayMoreStackMove is a maymorestack hook that forces stack movement -// at every possible point. -// -// See mayMoreStackPreempt. -// -//go:nosplit -//go:linkname mayMoreStackMove -func mayMoreStackMove() { - // Don't do anything on the g0 or gsignal stack. - gp := getg() - if gp == gp.m.g0 || gp == gp.m.gsignal { - return - } - // Force stack movement, unless the stack is already poisoned. - if gp.stackguard0 < stackPoisonMin { - gp.stackguard0 = stackForceMove - } -} diff --git a/contrib/go/_std_1.22/src/runtime/debug/stack.go b/contrib/go/_std_1.22/src/runtime/debug/stack.go deleted file mode 100644 index 3999840d3c8e..000000000000 --- a/contrib/go/_std_1.22/src/runtime/debug/stack.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package debug contains facilities for programs to debug themselves while -// they are running. -package debug - -import ( - "os" - "runtime" -) - -// PrintStack prints to standard error the stack trace returned by runtime.Stack. -func PrintStack() { - os.Stderr.Write(Stack()) -} - -// Stack returns a formatted stack trace of the goroutine that calls it. -// It calls [runtime.Stack] with a large enough buffer to capture the entire trace. -func Stack() []byte { - buf := make([]byte, 1024) - for { - n := runtime.Stack(buf, false) - if n < len(buf) { - return buf[:n] - } - buf = make([]byte, 2*len(buf)) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/env_posix.go b/contrib/go/_std_1.22/src/runtime/env_posix.go deleted file mode 100644 index 0eb4f0d7a3b8..000000000000 --- a/contrib/go/_std_1.22/src/runtime/env_posix.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func gogetenv(key string) string { - env := environ() - if env == nil { - throw("getenv before env init") - } - for _, s := range env { - if len(s) > len(key) && s[len(key)] == '=' && envKeyEqual(s[:len(key)], key) { - return s[len(key)+1:] - } - } - return "" -} - -// envKeyEqual reports whether a == b, with ASCII-only case insensitivity -// on Windows. The two strings must have the same length. -func envKeyEqual(a, b string) bool { - if GOOS == "windows" { // case insensitive - for i := 0; i < len(a); i++ { - ca, cb := a[i], b[i] - if ca == cb || lowerASCII(ca) == lowerASCII(cb) { - continue - } - return false - } - return true - } - return a == b -} - -func lowerASCII(c byte) byte { - if 'A' <= c && c <= 'Z' { - return c + ('a' - 'A') - } - return c -} - -var _cgo_setenv unsafe.Pointer // pointer to C function -var _cgo_unsetenv unsafe.Pointer // pointer to C function - -// Update the C environment if cgo is loaded. -func setenv_c(k string, v string) { - if _cgo_setenv == nil { - return - } - arg := [2]unsafe.Pointer{cstring(k), cstring(v)} - asmcgocall(_cgo_setenv, unsafe.Pointer(&arg)) -} - -// Update the C environment if cgo is loaded. -func unsetenv_c(k string) { - if _cgo_unsetenv == nil { - return - } - arg := [1]unsafe.Pointer{cstring(k)} - asmcgocall(_cgo_unsetenv, unsafe.Pointer(&arg)) -} - -func cstring(s string) unsafe.Pointer { - p := make([]byte, len(s)+1) - copy(p, s) - return unsafe.Pointer(&p[0]) -} diff --git a/contrib/go/_std_1.22/src/runtime/error.go b/contrib/go/_std_1.22/src/runtime/error.go deleted file mode 100644 index b507f25e185d..000000000000 --- a/contrib/go/_std_1.22/src/runtime/error.go +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "internal/bytealg" - -// The Error interface identifies a run time error. -type Error interface { - error - - // RuntimeError is a no-op function but - // serves to distinguish types that are run time - // errors from ordinary errors: a type is a - // run time error if it has a RuntimeError method. - RuntimeError() -} - -// A TypeAssertionError explains a failed type assertion. -type TypeAssertionError struct { - _interface *_type - concrete *_type - asserted *_type - missingMethod string // one method needed by Interface, missing from Concrete -} - -func (*TypeAssertionError) RuntimeError() {} - -func (e *TypeAssertionError) Error() string { - inter := "interface" - if e._interface != nil { - inter = toRType(e._interface).string() - } - as := toRType(e.asserted).string() - if e.concrete == nil { - return "interface conversion: " + inter + " is nil, not " + as - } - cs := toRType(e.concrete).string() - if e.missingMethod == "" { - msg := "interface conversion: " + inter + " is " + cs + ", not " + as - if cs == as { - // provide slightly clearer error message - if toRType(e.concrete).pkgpath() != toRType(e.asserted).pkgpath() { - msg += " (types from different packages)" - } else { - msg += " (types from different scopes)" - } - } - return msg - } - return "interface conversion: " + cs + " is not " + as + - ": missing method " + e.missingMethod -} - -// itoa converts val to a decimal representation. The result is -// written somewhere within buf and the location of the result is returned. -// buf must be at least 20 bytes. -// -//go:nosplit -func itoa(buf []byte, val uint64) []byte { - i := len(buf) - 1 - for val >= 10 { - buf[i] = byte(val%10 + '0') - i-- - val /= 10 - } - buf[i] = byte(val + '0') - return buf[i:] -} - -// An errorString represents a runtime error described by a single string. -type errorString string - -func (e errorString) RuntimeError() {} - -func (e errorString) Error() string { - return "runtime error: " + string(e) -} - -type errorAddressString struct { - msg string // error message - addr uintptr // memory address where the error occurred -} - -func (e errorAddressString) RuntimeError() {} - -func (e errorAddressString) Error() string { - return "runtime error: " + e.msg -} - -// Addr returns the memory address where a fault occurred. -// The address provided is best-effort. -// The veracity of the result may depend on the platform. -// Errors providing this method will only be returned as -// a result of using [runtime/debug.SetPanicOnFault]. -func (e errorAddressString) Addr() uintptr { - return e.addr -} - -// plainError represents a runtime error described a string without -// the prefix "runtime error: " after invoking errorString.Error(). -// See Issue #14965. -type plainError string - -func (e plainError) RuntimeError() {} - -func (e plainError) Error() string { - return string(e) -} - -// A boundsError represents an indexing or slicing operation gone wrong. -type boundsError struct { - x int64 - y int - // Values in an index or slice expression can be signed or unsigned. - // That means we'd need 65 bits to encode all possible indexes, from -2^63 to 2^64-1. - // Instead, we keep track of whether x should be interpreted as signed or unsigned. - // y is known to be nonnegative and to fit in an int. - signed bool - code boundsErrorCode -} - -type boundsErrorCode uint8 - -const ( - boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed - - boundsSliceAlen // s[?:x], 0 <= x <= len(s) failed - boundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed - boundsSliceB // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen) - - boundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed - boundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed - boundsSlice3B // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen) - boundsSlice3C // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen) - - boundsConvert // (*[x]T)(s), 0 <= x <= len(s) failed - // Note: in the above, len(s) and cap(s) are stored in y -) - -// boundsErrorFmts provide error text for various out-of-bounds panics. -// Note: if you change these strings, you should adjust the size of the buffer -// in boundsError.Error below as well. -var boundsErrorFmts = [...]string{ - boundsIndex: "index out of range [%x] with length %y", - boundsSliceAlen: "slice bounds out of range [:%x] with length %y", - boundsSliceAcap: "slice bounds out of range [:%x] with capacity %y", - boundsSliceB: "slice bounds out of range [%x:%y]", - boundsSlice3Alen: "slice bounds out of range [::%x] with length %y", - boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y", - boundsSlice3B: "slice bounds out of range [:%x:%y]", - boundsSlice3C: "slice bounds out of range [%x:%y:]", - boundsConvert: "cannot convert slice with length %y to array or pointer to array with length %x", -} - -// boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y. -var boundsNegErrorFmts = [...]string{ - boundsIndex: "index out of range [%x]", - boundsSliceAlen: "slice bounds out of range [:%x]", - boundsSliceAcap: "slice bounds out of range [:%x]", - boundsSliceB: "slice bounds out of range [%x:]", - boundsSlice3Alen: "slice bounds out of range [::%x]", - boundsSlice3Acap: "slice bounds out of range [::%x]", - boundsSlice3B: "slice bounds out of range [:%x:]", - boundsSlice3C: "slice bounds out of range [%x::]", -} - -func (e boundsError) RuntimeError() {} - -func appendIntStr(b []byte, v int64, signed bool) []byte { - if signed && v < 0 { - b = append(b, '-') - v = -v - } - var buf [20]byte - b = append(b, itoa(buf[:], uint64(v))...) - return b -} - -func (e boundsError) Error() string { - fmt := boundsErrorFmts[e.code] - if e.signed && e.x < 0 { - fmt = boundsNegErrorFmts[e.code] - } - // max message length is 99: "runtime error: slice bounds out of range [::%x] with capacity %y" - // x can be at most 20 characters. y can be at most 19. - b := make([]byte, 0, 100) - b = append(b, "runtime error: "...) - for i := 0; i < len(fmt); i++ { - c := fmt[i] - if c != '%' { - b = append(b, c) - continue - } - i++ - switch fmt[i] { - case 'x': - b = appendIntStr(b, e.x, e.signed) - case 'y': - b = appendIntStr(b, int64(e.y), true) - } - } - return string(b) -} - -type stringer interface { - String() string -} - -// printany prints an argument passed to panic. -// If panic is called with a value that has a String or Error method, -// it has already been converted into a string by preprintpanics. -func printany(i any) { - switch v := i.(type) { - case nil: - print("nil") - case bool: - print(v) - case int: - print(v) - case int8: - print(v) - case int16: - print(v) - case int32: - print(v) - case int64: - print(v) - case uint: - print(v) - case uint8: - print(v) - case uint16: - print(v) - case uint32: - print(v) - case uint64: - print(v) - case uintptr: - print(v) - case float32: - print(v) - case float64: - print(v) - case complex64: - print(v) - case complex128: - print(v) - case string: - print(v) - default: - printanycustomtype(i) - } -} - -func printanycustomtype(i any) { - eface := efaceOf(&i) - typestring := toRType(eface._type).string() - - switch eface._type.Kind_ { - case kindString: - print(typestring, `("`, *(*string)(eface.data), `")`) - case kindBool: - print(typestring, "(", *(*bool)(eface.data), ")") - case kindInt: - print(typestring, "(", *(*int)(eface.data), ")") - case kindInt8: - print(typestring, "(", *(*int8)(eface.data), ")") - case kindInt16: - print(typestring, "(", *(*int16)(eface.data), ")") - case kindInt32: - print(typestring, "(", *(*int32)(eface.data), ")") - case kindInt64: - print(typestring, "(", *(*int64)(eface.data), ")") - case kindUint: - print(typestring, "(", *(*uint)(eface.data), ")") - case kindUint8: - print(typestring, "(", *(*uint8)(eface.data), ")") - case kindUint16: - print(typestring, "(", *(*uint16)(eface.data), ")") - case kindUint32: - print(typestring, "(", *(*uint32)(eface.data), ")") - case kindUint64: - print(typestring, "(", *(*uint64)(eface.data), ")") - case kindUintptr: - print(typestring, "(", *(*uintptr)(eface.data), ")") - case kindFloat32: - print(typestring, "(", *(*float32)(eface.data), ")") - case kindFloat64: - print(typestring, "(", *(*float64)(eface.data), ")") - case kindComplex64: - print(typestring, *(*complex64)(eface.data)) - case kindComplex128: - print(typestring, *(*complex128)(eface.data)) - default: - print("(", typestring, ") ", eface.data) - } -} - -// panicwrap generates a panic for a call to a wrapped value method -// with a nil pointer receiver. -// -// It is called from the generated wrapper code. -func panicwrap() { - pc := getcallerpc() - name := funcNameForPrint(funcname(findfunc(pc))) - // name is something like "main.(*T).F". - // We want to extract pkg ("main"), typ ("T"), and meth ("F"). - // Do it by finding the parens. - i := bytealg.IndexByteString(name, '(') - if i < 0 { - throw("panicwrap: no ( in " + name) - } - pkg := name[:i-1] - if i+2 >= len(name) || name[i-1:i+2] != ".(*" { - throw("panicwrap: unexpected string after package name: " + name) - } - name = name[i+2:] - i = bytealg.IndexByteString(name, ')') - if i < 0 { - throw("panicwrap: no ) in " + name) - } - if i+2 >= len(name) || name[i:i+2] != ")." { - throw("panicwrap: unexpected string after type name: " + name) - } - typ := name[:i] - meth := name[i+2:] - panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")) -} diff --git a/contrib/go/_std_1.22/src/runtime/exithook.go b/contrib/go/_std_1.22/src/runtime/exithook.go deleted file mode 100644 index 65b426b383f8..000000000000 --- a/contrib/go/_std_1.22/src/runtime/exithook.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// addExitHook registers the specified function 'f' to be run at -// program termination (e.g. when someone invokes os.Exit(), or when -// main.main returns). Hooks are run in reverse order of registration: -// first hook added is the last one run. -// -// CAREFUL: the expectation is that addExitHook should only be called -// from a safe context (e.g. not an error/panic path or signal -// handler, preemption enabled, allocation allowed, write barriers -// allowed, etc), and that the exit function 'f' will be invoked under -// similar circumstances. That is the say, we are expecting that 'f' -// uses normal / high-level Go code as opposed to one of the more -// restricted dialects used for the trickier parts of the runtime. -func addExitHook(f func(), runOnNonZeroExit bool) { - exitHooks.hooks = append(exitHooks.hooks, exitHook{f: f, runOnNonZeroExit: runOnNonZeroExit}) -} - -// exitHook stores a function to be run on program exit, registered -// by the utility runtime.addExitHook. -type exitHook struct { - f func() // func to run - runOnNonZeroExit bool // whether to run on non-zero exit code -} - -// exitHooks stores state related to hook functions registered to -// run when program execution terminates. -var exitHooks struct { - hooks []exitHook - runningExitHooks bool -} - -// runExitHooks runs any registered exit hook functions (funcs -// previously registered using runtime.addExitHook). Here 'exitCode' -// is the status code being passed to os.Exit, or zero if the program -// is terminating normally without calling os.Exit. -func runExitHooks(exitCode int) { - if exitHooks.runningExitHooks { - throw("internal error: exit hook invoked exit") - } - exitHooks.runningExitHooks = true - - runExitHook := func(f func()) (caughtPanic bool) { - defer func() { - if x := recover(); x != nil { - caughtPanic = true - } - }() - f() - return - } - - finishPageTrace() - for i := range exitHooks.hooks { - h := exitHooks.hooks[len(exitHooks.hooks)-i-1] - if exitCode != 0 && !h.runOnNonZeroExit { - continue - } - if caughtPanic := runExitHook(h.f); caughtPanic { - throw("internal error: exit hook invoked panic") - } - } - exitHooks.hooks = nil - exitHooks.runningExitHooks = false -} diff --git a/contrib/go/_std_1.22/src/runtime/iface.go b/contrib/go/_std_1.22/src/runtime/iface.go deleted file mode 100644 index bad49a346e86..000000000000 --- a/contrib/go/_std_1.22/src/runtime/iface.go +++ /dev/null @@ -1,686 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -const itabInitSize = 512 - -var ( - itabLock mutex // lock for accessing itab table - itabTable = &itabTableInit // pointer to current table - itabTableInit = itabTableType{size: itabInitSize} // starter table -) - -// Note: change the formula in the mallocgc call in itabAdd if you change these fields. -type itabTableType struct { - size uintptr // length of entries array. Always a power of 2. - count uintptr // current number of filled entries. - entries [itabInitSize]*itab // really [size] large -} - -func itabHashFunc(inter *interfacetype, typ *_type) uintptr { - // compiler has provided some good hash codes for us. - return uintptr(inter.Type.Hash ^ typ.Hash) -} - -func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { - if len(inter.Methods) == 0 { - throw("internal error - misuse of itab") - } - - // easy case - if typ.TFlag&abi.TFlagUncommon == 0 { - if canfail { - return nil - } - name := toRType(&inter.Type).nameOff(inter.Methods[0].Name) - panic(&TypeAssertionError{nil, typ, &inter.Type, name.Name()}) - } - - var m *itab - - // First, look in the existing table to see if we can find the itab we need. - // This is by far the most common case, so do it without locks. - // Use atomic to ensure we see any previous writes done by the thread - // that updates the itabTable field (with atomic.Storep in itabAdd). - t := (*itabTableType)(atomic.Loadp(unsafe.Pointer(&itabTable))) - if m = t.find(inter, typ); m != nil { - goto finish - } - - // Not found. Grab the lock and try again. - lock(&itabLock) - if m = itabTable.find(inter, typ); m != nil { - unlock(&itabLock) - goto finish - } - - // Entry doesn't exist yet. Make a new entry & add it. - m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.Methods)-1)*goarch.PtrSize, 0, &memstats.other_sys)) - m.inter = inter - m._type = typ - // The hash is used in type switches. However, compiler statically generates itab's - // for all interface/type pairs used in switches (which are added to itabTable - // in itabsinit). The dynamically-generated itab's never participate in type switches, - // and thus the hash is irrelevant. - // Note: m.hash is _not_ the hash used for the runtime itabTable hash table. - m.hash = 0 - m.init() - itabAdd(m) - unlock(&itabLock) -finish: - if m.fun[0] != 0 { - return m - } - if canfail { - return nil - } - // this can only happen if the conversion - // was already done once using the , ok form - // and we have a cached negative result. - // The cached result doesn't record which - // interface function was missing, so initialize - // the itab again to get the missing function name. - panic(&TypeAssertionError{concrete: typ, asserted: &inter.Type, missingMethod: m.init()}) -} - -// find finds the given interface/type pair in t. -// Returns nil if the given interface/type pair isn't present. -func (t *itabTableType) find(inter *interfacetype, typ *_type) *itab { - // Implemented using quadratic probing. - // Probe sequence is h(i) = h0 + i*(i+1)/2 mod 2^k. - // We're guaranteed to hit all table entries using this probe sequence. - mask := t.size - 1 - h := itabHashFunc(inter, typ) & mask - for i := uintptr(1); ; i++ { - p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) - // Use atomic read here so if we see m != nil, we also see - // the initializations of the fields of m. - // m := *p - m := (*itab)(atomic.Loadp(unsafe.Pointer(p))) - if m == nil { - return nil - } - if m.inter == inter && m._type == typ { - return m - } - h += i - h &= mask - } -} - -// itabAdd adds the given itab to the itab hash table. -// itabLock must be held. -func itabAdd(m *itab) { - // Bugs can lead to calling this while mallocing is set, - // typically because this is called while panicking. - // Crash reliably, rather than only when we need to grow - // the hash table. - if getg().m.mallocing != 0 { - throw("malloc deadlock") - } - - t := itabTable - if t.count >= 3*(t.size/4) { // 75% load factor - // Grow hash table. - // t2 = new(itabTableType) + some additional entries - // We lie and tell malloc we want pointer-free memory because - // all the pointed-to values are not in the heap. - t2 := (*itabTableType)(mallocgc((2+2*t.size)*goarch.PtrSize, nil, true)) - t2.size = t.size * 2 - - // Copy over entries. - // Note: while copying, other threads may look for an itab and - // fail to find it. That's ok, they will then try to get the itab lock - // and as a consequence wait until this copying is complete. - iterate_itabs(t2.add) - if t2.count != t.count { - throw("mismatched count during itab table copy") - } - // Publish new hash table. Use an atomic write: see comment in getitab. - atomicstorep(unsafe.Pointer(&itabTable), unsafe.Pointer(t2)) - // Adopt the new table as our own. - t = itabTable - // Note: the old table can be GC'ed here. - } - t.add(m) -} - -// add adds the given itab to itab table t. -// itabLock must be held. -func (t *itabTableType) add(m *itab) { - // See comment in find about the probe sequence. - // Insert new itab in the first empty spot in the probe sequence. - mask := t.size - 1 - h := itabHashFunc(m.inter, m._type) & mask - for i := uintptr(1); ; i++ { - p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) - m2 := *p - if m2 == m { - // A given itab may be used in more than one module - // and thanks to the way global symbol resolution works, the - // pointed-to itab may already have been inserted into the - // global 'hash'. - return - } - if m2 == nil { - // Use atomic write here so if a reader sees m, it also - // sees the correctly initialized fields of m. - // NoWB is ok because m is not in heap memory. - // *p = m - atomic.StorepNoWB(unsafe.Pointer(p), unsafe.Pointer(m)) - t.count++ - return - } - h += i - h &= mask - } -} - -// init fills in the m.fun array with all the code pointers for -// the m.inter/m._type pair. If the type does not implement the interface, -// it sets m.fun[0] to 0 and returns the name of an interface function that is missing. -// It is ok to call this multiple times on the same m, even concurrently. -func (m *itab) init() string { - inter := m.inter - typ := m._type - x := typ.Uncommon() - - // both inter and typ have method sorted by name, - // and interface names are unique, - // so can iterate over both in lock step; - // the loop is O(ni+nt) not O(ni*nt). - ni := len(inter.Methods) - nt := int(x.Mcount) - xmhdr := (*[1 << 16]abi.Method)(add(unsafe.Pointer(x), uintptr(x.Moff)))[:nt:nt] - j := 0 - methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.fun[0]))[:ni:ni] - var fun0 unsafe.Pointer -imethods: - for k := 0; k < ni; k++ { - i := &inter.Methods[k] - itype := toRType(&inter.Type).typeOff(i.Typ) - name := toRType(&inter.Type).nameOff(i.Name) - iname := name.Name() - ipkg := pkgPath(name) - if ipkg == "" { - ipkg = inter.PkgPath.Name() - } - for ; j < nt; j++ { - t := &xmhdr[j] - rtyp := toRType(typ) - tname := rtyp.nameOff(t.Name) - if rtyp.typeOff(t.Mtyp) == itype && tname.Name() == iname { - pkgPath := pkgPath(tname) - if pkgPath == "" { - pkgPath = rtyp.nameOff(x.PkgPath).Name() - } - if tname.IsExported() || pkgPath == ipkg { - ifn := rtyp.textOff(t.Ifn) - if k == 0 { - fun0 = ifn // we'll set m.fun[0] at the end - } else { - methods[k] = ifn - } - continue imethods - } - } - } - // didn't find method - m.fun[0] = 0 - return iname - } - m.fun[0] = uintptr(fun0) - return "" -} - -func itabsinit() { - lockInit(&itabLock, lockRankItab) - lock(&itabLock) - for _, md := range activeModules() { - for _, i := range md.itablinks { - itabAdd(i) - } - } - unlock(&itabLock) -} - -// panicdottypeE is called when doing an e.(T) conversion and the conversion fails. -// have = the dynamic type we have. -// want = the static type we're trying to convert to. -// iface = the static type we're converting from. -func panicdottypeE(have, want, iface *_type) { - panic(&TypeAssertionError{iface, have, want, ""}) -} - -// panicdottypeI is called when doing an i.(T) conversion and the conversion fails. -// Same args as panicdottypeE, but "have" is the dynamic itab we have. -func panicdottypeI(have *itab, want, iface *_type) { - var t *_type - if have != nil { - t = have._type - } - panicdottypeE(t, want, iface) -} - -// panicnildottype is called when doing an i.(T) conversion and the interface i is nil. -// want = the static type we're trying to convert to. -func panicnildottype(want *_type) { - panic(&TypeAssertionError{nil, nil, want, ""}) - // TODO: Add the static type we're converting from as well. - // It might generate a better error message. - // Just to match other nil conversion errors, we don't for now. -} - -// The specialized convTx routines need a type descriptor to use when calling mallocgc. -// We don't need the type to be exact, just to have the correct size, alignment, and pointer-ness. -// However, when debugging, it'd be nice to have some indication in mallocgc where the types came from, -// so we use named types here. -// We then construct interface values of these types, -// and then extract the type word to use as needed. -type ( - uint16InterfacePtr uint16 - uint32InterfacePtr uint32 - uint64InterfacePtr uint64 - stringInterfacePtr string - sliceInterfacePtr []byte -) - -var ( - uint16Eface any = uint16InterfacePtr(0) - uint32Eface any = uint32InterfacePtr(0) - uint64Eface any = uint64InterfacePtr(0) - stringEface any = stringInterfacePtr("") - sliceEface any = sliceInterfacePtr(nil) - - uint16Type *_type = efaceOf(&uint16Eface)._type - uint32Type *_type = efaceOf(&uint32Eface)._type - uint64Type *_type = efaceOf(&uint64Eface)._type - stringType *_type = efaceOf(&stringEface)._type - sliceType *_type = efaceOf(&sliceEface)._type -) - -// The conv and assert functions below do very similar things. -// The convXXX functions are guaranteed by the compiler to succeed. -// The assertXXX functions may fail (either panicking or returning false, -// depending on whether they are 1-result or 2-result). -// The convXXX functions succeed on a nil input, whereas the assertXXX -// functions fail on a nil input. - -// convT converts a value of type t, which is pointed to by v, to a pointer that can -// be used as the second word of an interface value. -func convT(t *_type, v unsafe.Pointer) unsafe.Pointer { - if raceenabled { - raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convT)) - } - if msanenabled { - msanread(v, t.Size_) - } - if asanenabled { - asanread(v, t.Size_) - } - x := mallocgc(t.Size_, t, true) - typedmemmove(t, x, v) - return x -} -func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer { - // TODO: maybe take size instead of type? - if raceenabled { - raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convTnoptr)) - } - if msanenabled { - msanread(v, t.Size_) - } - if asanenabled { - asanread(v, t.Size_) - } - - x := mallocgc(t.Size_, t, false) - memmove(x, v, t.Size_) - return x -} - -func convT16(val uint16) (x unsafe.Pointer) { - if val < uint16(len(staticuint64s)) { - x = unsafe.Pointer(&staticuint64s[val]) - if goarch.BigEndian { - x = add(x, 6) - } - } else { - x = mallocgc(2, uint16Type, false) - *(*uint16)(x) = val - } - return -} - -func convT32(val uint32) (x unsafe.Pointer) { - if val < uint32(len(staticuint64s)) { - x = unsafe.Pointer(&staticuint64s[val]) - if goarch.BigEndian { - x = add(x, 4) - } - } else { - x = mallocgc(4, uint32Type, false) - *(*uint32)(x) = val - } - return -} - -func convT64(val uint64) (x unsafe.Pointer) { - if val < uint64(len(staticuint64s)) { - x = unsafe.Pointer(&staticuint64s[val]) - } else { - x = mallocgc(8, uint64Type, false) - *(*uint64)(x) = val - } - return -} - -func convTstring(val string) (x unsafe.Pointer) { - if val == "" { - x = unsafe.Pointer(&zeroVal[0]) - } else { - x = mallocgc(unsafe.Sizeof(val), stringType, true) - *(*string)(x) = val - } - return -} - -func convTslice(val []byte) (x unsafe.Pointer) { - // Note: this must work for any element type, not just byte. - if (*slice)(unsafe.Pointer(&val)).array == nil { - x = unsafe.Pointer(&zeroVal[0]) - } else { - x = mallocgc(unsafe.Sizeof(val), sliceType, true) - *(*[]byte)(x) = val - } - return -} - -func assertE2I(inter *interfacetype, t *_type) *itab { - if t == nil { - // explicit conversions require non-nil interface value. - panic(&TypeAssertionError{nil, nil, &inter.Type, ""}) - } - return getitab(inter, t, false) -} - -func assertE2I2(inter *interfacetype, t *_type) *itab { - if t == nil { - return nil - } - return getitab(inter, t, true) -} - -// typeAssert builds an itab for the concrete type t and the -// interface type s.Inter. If the conversion is not possible it -// panics if s.CanFail is false and returns nil if s.CanFail is true. -func typeAssert(s *abi.TypeAssert, t *_type) *itab { - var tab *itab - if t == nil { - if !s.CanFail { - panic(&TypeAssertionError{nil, nil, &s.Inter.Type, ""}) - } - } else { - tab = getitab(s.Inter, t, s.CanFail) - } - - if !abi.UseInterfaceSwitchCache(GOARCH) { - return tab - } - - // Maybe update the cache, so the next time the generated code - // doesn't need to call into the runtime. - if cheaprand()&1023 != 0 { - // Only bother updating the cache ~1 in 1000 times. - return tab - } - // Load the current cache. - oldC := (*abi.TypeAssertCache)(atomic.Loadp(unsafe.Pointer(&s.Cache))) - - if cheaprand()&uint32(oldC.Mask) != 0 { - // As cache gets larger, choose to update it less often - // so we can amortize the cost of building a new cache. - return tab - } - - // Make a new cache. - newC := buildTypeAssertCache(oldC, t, tab) - - // Update cache. Use compare-and-swap so if multiple threads - // are fighting to update the cache, at least one of their - // updates will stick. - atomic_casPointer((*unsafe.Pointer)(unsafe.Pointer(&s.Cache)), unsafe.Pointer(oldC), unsafe.Pointer(newC)) - - return tab -} - -func buildTypeAssertCache(oldC *abi.TypeAssertCache, typ *_type, tab *itab) *abi.TypeAssertCache { - oldEntries := unsafe.Slice(&oldC.Entries[0], oldC.Mask+1) - - // Count the number of entries we need. - n := 1 - for _, e := range oldEntries { - if e.Typ != 0 { - n++ - } - } - - // Figure out how big a table we need. - // We need at least one more slot than the number of entries - // so that we are guaranteed an empty slot (for termination). - newN := n * 2 // make it at most 50% full - newN = 1 << sys.Len64(uint64(newN-1)) // round up to a power of 2 - - // Allocate the new table. - newSize := unsafe.Sizeof(abi.TypeAssertCache{}) + uintptr(newN-1)*unsafe.Sizeof(abi.TypeAssertCacheEntry{}) - newC := (*abi.TypeAssertCache)(mallocgc(newSize, nil, true)) - newC.Mask = uintptr(newN - 1) - newEntries := unsafe.Slice(&newC.Entries[0], newN) - - // Fill the new table. - addEntry := func(typ *_type, tab *itab) { - h := int(typ.Hash) & (newN - 1) - for { - if newEntries[h].Typ == 0 { - newEntries[h].Typ = uintptr(unsafe.Pointer(typ)) - newEntries[h].Itab = uintptr(unsafe.Pointer(tab)) - return - } - h = (h + 1) & (newN - 1) - } - } - for _, e := range oldEntries { - if e.Typ != 0 { - addEntry((*_type)(unsafe.Pointer(e.Typ)), (*itab)(unsafe.Pointer(e.Itab))) - } - } - addEntry(typ, tab) - - return newC -} - -// Empty type assert cache. Contains one entry with a nil Typ (which -// causes a cache lookup to fail immediately.) -var emptyTypeAssertCache = abi.TypeAssertCache{Mask: 0} - -// interfaceSwitch compares t against the list of cases in s. -// If t matches case i, interfaceSwitch returns the case index i and -// an itab for the pair . -// If there is no match, return N,nil, where N is the number -// of cases. -func interfaceSwitch(s *abi.InterfaceSwitch, t *_type) (int, *itab) { - cases := unsafe.Slice(&s.Cases[0], s.NCases) - - // Results if we don't find a match. - case_ := len(cases) - var tab *itab - - // Look through each case in order. - for i, c := range cases { - tab = getitab(c, t, true) - if tab != nil { - case_ = i - break - } - } - - if !abi.UseInterfaceSwitchCache(GOARCH) { - return case_, tab - } - - // Maybe update the cache, so the next time the generated code - // doesn't need to call into the runtime. - if cheaprand()&1023 != 0 { - // Only bother updating the cache ~1 in 1000 times. - // This ensures we don't waste memory on switches, or - // switch arguments, that only happen a few times. - return case_, tab - } - // Load the current cache. - oldC := (*abi.InterfaceSwitchCache)(atomic.Loadp(unsafe.Pointer(&s.Cache))) - - if cheaprand()&uint32(oldC.Mask) != 0 { - // As cache gets larger, choose to update it less often - // so we can amortize the cost of building a new cache - // (that cost is linear in oldc.Mask). - return case_, tab - } - - // Make a new cache. - newC := buildInterfaceSwitchCache(oldC, t, case_, tab) - - // Update cache. Use compare-and-swap so if multiple threads - // are fighting to update the cache, at least one of their - // updates will stick. - atomic_casPointer((*unsafe.Pointer)(unsafe.Pointer(&s.Cache)), unsafe.Pointer(oldC), unsafe.Pointer(newC)) - - return case_, tab -} - -// buildInterfaceSwitchCache constructs an interface switch cache -// containing all the entries from oldC plus the new entry -// (typ,case_,tab). -func buildInterfaceSwitchCache(oldC *abi.InterfaceSwitchCache, typ *_type, case_ int, tab *itab) *abi.InterfaceSwitchCache { - oldEntries := unsafe.Slice(&oldC.Entries[0], oldC.Mask+1) - - // Count the number of entries we need. - n := 1 - for _, e := range oldEntries { - if e.Typ != 0 { - n++ - } - } - - // Figure out how big a table we need. - // We need at least one more slot than the number of entries - // so that we are guaranteed an empty slot (for termination). - newN := n * 2 // make it at most 50% full - newN = 1 << sys.Len64(uint64(newN-1)) // round up to a power of 2 - - // Allocate the new table. - newSize := unsafe.Sizeof(abi.InterfaceSwitchCache{}) + uintptr(newN-1)*unsafe.Sizeof(abi.InterfaceSwitchCacheEntry{}) - newC := (*abi.InterfaceSwitchCache)(mallocgc(newSize, nil, true)) - newC.Mask = uintptr(newN - 1) - newEntries := unsafe.Slice(&newC.Entries[0], newN) - - // Fill the new table. - addEntry := func(typ *_type, case_ int, tab *itab) { - h := int(typ.Hash) & (newN - 1) - for { - if newEntries[h].Typ == 0 { - newEntries[h].Typ = uintptr(unsafe.Pointer(typ)) - newEntries[h].Case = case_ - newEntries[h].Itab = uintptr(unsafe.Pointer(tab)) - return - } - h = (h + 1) & (newN - 1) - } - } - for _, e := range oldEntries { - if e.Typ != 0 { - addEntry((*_type)(unsafe.Pointer(e.Typ)), e.Case, (*itab)(unsafe.Pointer(e.Itab))) - } - } - addEntry(typ, case_, tab) - - return newC -} - -// Empty interface switch cache. Contains one entry with a nil Typ (which -// causes a cache lookup to fail immediately.) -var emptyInterfaceSwitchCache = abi.InterfaceSwitchCache{Mask: 0} - -//go:linkname reflect_ifaceE2I reflect.ifaceE2I -func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { - *dst = iface{assertE2I(inter, e._type), e.data} -} - -//go:linkname reflectlite_ifaceE2I internal/reflectlite.ifaceE2I -func reflectlite_ifaceE2I(inter *interfacetype, e eface, dst *iface) { - *dst = iface{assertE2I(inter, e._type), e.data} -} - -func iterate_itabs(fn func(*itab)) { - // Note: only runs during stop the world or with itabLock held, - // so no other locks/atomics needed. - t := itabTable - for i := uintptr(0); i < t.size; i++ { - m := *(**itab)(add(unsafe.Pointer(&t.entries), i*goarch.PtrSize)) - if m != nil { - fn(m) - } - } -} - -// staticuint64s is used to avoid allocating in convTx for small integer values. -var staticuint64s = [...]uint64{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -} - -// The linker redirects a reference of a method that it determined -// unreachable to a reference to this function, so it will throw if -// ever called. -func unreachableMethod() { - throw("unreachable method called. linker bug?") -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/ya.make b/contrib/go/_std_1.22/src/runtime/internal/atomic/ya.make deleted file mode 100644 index 03e5cd519bb0..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/ya.make +++ /dev/null @@ -1,23 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - atomic_arm64.go - atomic_arm64.s - doc.go - stubs.go - types.go - types_64bit.go - unaligned.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - atomic_amd64.go - atomic_amd64.s - doc.go - stubs.go - types.go - types_64bit.go - unaligned.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/ya.make b/contrib/go/_std_1.22/src/runtime/internal/sys/ya.make deleted file mode 100644 index 53c753ca322e..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/sys/ya.make +++ /dev/null @@ -1,21 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) - SRCS( - consts.go - consts_race.go - intrinsics.go - nih.go - sys.go - zversion.go - ) -ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - consts.go - consts_norace.go - intrinsics.go - nih.go - sys.go - zversion.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_loong64.s b/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_loong64.s deleted file mode 100644 index 11c5bc2468d5..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_loong64.s +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "textflag.h" - -// func Syscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr) -// -// We need to convert to the syscall ABI. -// -// arg | ABIInternal | Syscall -// --------------------------- -// num | R4 | R11 -// a1 | R5 | R4 -// a2 | R6 | R5 -// a3 | R7 | R6 -// a4 | R8 | R7 -// a5 | R9 | R8 -// a6 | R10 | R9 -// -// r1 | R4 | R4 -// r2 | R5 | R5 -// err | R6 | part of R4 -TEXT ·Syscall6(SB),NOSPLIT,$0-80 -#ifdef GOEXPERIMENT_regabiargs - MOVV R4, R11 // syscall entry - MOVV R5, R4 - MOVV R6, R5 - MOVV R7, R6 - MOVV R8, R7 - MOVV R9, R8 - MOVV R10, R9 -#else - MOVV num+0(FP), R11 // syscall entry - MOVV a1+8(FP), R4 - MOVV a2+16(FP), R5 - MOVV a3+24(FP), R6 - MOVV a4+32(FP), R7 - MOVV a5+40(FP), R8 - MOVV a6+48(FP), R9 -#endif - SYSCALL -#ifdef GOEXPERIMENT_regabiargs - MOVV R0, R5 // r2 is not used. Always set to 0. - MOVW $-4096, R12 - BGEU R12, R4, ok - SUBVU R4, R0, R6 // errno - MOVV $-1, R4 // r1 -#else - MOVW $-4096, R12 - BGEU R12, R4, ok - MOVV $-1, R12 - MOVV R12, r1+56(FP) - MOVV R0, r2+64(FP) - SUBVU R4, R0, R4 - MOVV R4, errno+72(FP) -#endif - RET -ok: -#ifdef GOEXPERIMENT_regabiargs - // r1 already in R4 - MOVV R0, R6 // errno -#else - MOVV R4, r1+56(FP) - MOVV R0, r2+64(FP) // r2 is not used. Always set to 0. - MOVV R0, errno+72(FP) -#endif - RET diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_386.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_386.go deleted file mode 100644 index dc723a60b244..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_386.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -const ( - SYS_FCNTL = 55 - SYS_EPOLL_CTL = 255 - SYS_EPOLL_PWAIT = 319 - SYS_EPOLL_CREATE1 = 329 - SYS_EPOLL_PWAIT2 = 441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - Data [8]byte // to match amd64 -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_amd64.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_amd64.go deleted file mode 100644 index 886eb5bda250..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_amd64.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -const ( - SYS_FCNTL = 72 - SYS_EPOLL_CTL = 233 - SYS_EPOLL_PWAIT = 281 - SYS_EPOLL_CREATE1 = 291 - SYS_EPOLL_PWAIT2 = 441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - Data [8]byte // unaligned uintptr -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm.go deleted file mode 100644 index 8f812a2f68b5..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -const ( - SYS_FCNTL = 55 - SYS_EPOLL_CTL = 251 - SYS_EPOLL_PWAIT = 346 - SYS_EPOLL_CREATE1 = 357 - SYS_EPOLL_PWAIT2 = 441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - _pad uint32 - Data [8]byte // to match amd64 -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm64.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm64.go deleted file mode 100644 index 48e11b0c512f..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm64.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -const ( - SYS_EPOLL_CREATE1 = 20 - SYS_EPOLL_CTL = 21 - SYS_EPOLL_PWAIT = 22 - SYS_FCNTL = 25 - SYS_EPOLL_PWAIT2 = 441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - _pad uint32 - Data [8]byte // to match amd64 -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_loong64.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_loong64.go deleted file mode 100644 index b78ef818614c..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_loong64.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -const ( - SYS_EPOLL_CREATE1 = 20 - SYS_EPOLL_CTL = 21 - SYS_EPOLL_PWAIT = 22 - SYS_FCNTL = 25 - SYS_EPOLL_PWAIT2 = 441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - pad_cgo_0 [4]byte - Data [8]byte // unaligned uintptr -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mips64x.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mips64x.go deleted file mode 100644 index 92b49ca969cb..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mips64x.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux && (mips64 || mips64le) - -package syscall - -const ( - SYS_FCNTL = 5070 - SYS_EPOLL_CTL = 5208 - SYS_EPOLL_PWAIT = 5272 - SYS_EPOLL_CREATE1 = 5285 - SYS_EPOLL_PWAIT2 = 5441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - pad_cgo_0 [4]byte - Data [8]byte // unaligned uintptr -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mipsx.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mipsx.go deleted file mode 100644 index e28d09c7f135..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mipsx.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux && (mips || mipsle) - -package syscall - -const ( - SYS_FCNTL = 4055 - SYS_EPOLL_CTL = 4249 - SYS_EPOLL_PWAIT = 4313 - SYS_EPOLL_CREATE1 = 4326 - SYS_EPOLL_PWAIT2 = 4441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - pad_cgo_0 [4]byte - Data uint64 -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_ppc64x.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_ppc64x.go deleted file mode 100644 index a74483eb6d71..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_ppc64x.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux && (ppc64 || ppc64le) - -package syscall - -const ( - SYS_FCNTL = 55 - SYS_EPOLL_CTL = 237 - SYS_EPOLL_PWAIT = 303 - SYS_EPOLL_CREATE1 = 315 - SYS_EPOLL_PWAIT2 = 441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - pad_cgo_0 [4]byte - Data [8]byte // unaligned uintptr -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_riscv64.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_riscv64.go deleted file mode 100644 index b78ef818614c..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_riscv64.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -const ( - SYS_EPOLL_CREATE1 = 20 - SYS_EPOLL_CTL = 21 - SYS_EPOLL_PWAIT = 22 - SYS_FCNTL = 25 - SYS_EPOLL_PWAIT2 = 441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - pad_cgo_0 [4]byte - Data [8]byte // unaligned uintptr -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_s390x.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_s390x.go deleted file mode 100644 index a7bb1ba66d66..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_s390x.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -const ( - SYS_FCNTL = 55 - SYS_EPOLL_CTL = 250 - SYS_EPOLL_PWAIT = 312 - SYS_EPOLL_CREATE1 = 327 - SYS_EPOLL_PWAIT2 = 441 - - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 -) - -type EpollEvent struct { - Events uint32 - pad_cgo_0 [4]byte - Data [8]byte // unaligned uintptr -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/syscall_linux.go b/contrib/go/_std_1.22/src/runtime/internal/syscall/syscall_linux.go deleted file mode 100644 index 7209634edb3f..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/syscall_linux.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package syscall provides the syscall primitives required for the runtime. -package syscall - -import ( - "unsafe" -) - -// TODO(https://go.dev/issue/51087): This package is incomplete and currently -// only contains very minimal support for Linux. - -// Syscall6 calls system call number 'num' with arguments a1-6. -func Syscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr) - -// syscall_RawSyscall6 is a push linkname to export Syscall6 as -// syscall.RawSyscall6. -// -// //go:uintptrkeepalive because the uintptr argument may be converted pointers -// that need to be kept alive in the caller (this is implied for Syscall6 since -// it has no body). -// -// //go:nosplit because stack copying does not account for uintptrkeepalive, so -// the stack must not grow. Stack copying cannot blindly assume that all -// uintptr arguments are pointers, because some values may look like pointers, -// but not really be pointers, and adjusting their value would break the call. -// -// This is a separate wrapper because we can't export one function as two -// names. The assembly implementations name themselves Syscall6 would not be -// affected by a linkname. -// -//go:uintptrkeepalive -//go:nosplit -//go:linkname syscall_RawSyscall6 syscall.RawSyscall6 -func syscall_RawSyscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr) { - return Syscall6(num, a1, a2, a3, a4, a5, a6) -} - -func EpollCreate1(flags int32) (fd int32, errno uintptr) { - r1, _, e := Syscall6(SYS_EPOLL_CREATE1, uintptr(flags), 0, 0, 0, 0, 0) - return int32(r1), e -} - -var _zero uintptr - -func EpollWait(epfd int32, events []EpollEvent, maxev, waitms int32) (n int32, errno uintptr) { - var ev unsafe.Pointer - if len(events) > 0 { - ev = unsafe.Pointer(&events[0]) - } else { - ev = unsafe.Pointer(&_zero) - } - r1, _, e := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(ev), uintptr(maxev), uintptr(waitms), 0, 0) - return int32(r1), e -} - -func EpollCtl(epfd, op, fd int32, event *EpollEvent) (errno uintptr) { - _, _, e := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0) - return e -} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/ya.make b/contrib/go/_std_1.22/src/runtime/internal/syscall/ya.make deleted file mode 100644 index 87ade4449e61..000000000000 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/ya.make +++ /dev/null @@ -1,15 +0,0 @@ -GO_LIBRARY() -IF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - asm_linux_arm64.s - defs_linux_arm64.go - syscall_linux.go - ) -ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - asm_linux_amd64.s - defs_linux_amd64.go - syscall_linux.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/runtime/lockrank.go b/contrib/go/_std_1.22/src/runtime/lockrank.go deleted file mode 100644 index b27e6c560615..000000000000 --- a/contrib/go/_std_1.22/src/runtime/lockrank.go +++ /dev/null @@ -1,212 +0,0 @@ -// Code generated by mklockrank.go; DO NOT EDIT. - -package runtime - -type lockRank int - -// Constants representing the ranks of all non-leaf runtime locks, in rank order. -// Locks with lower rank must be taken before locks with higher rank, -// in addition to satisfying the partial order in lockPartialOrder. -// A few ranks allow self-cycles, which are specified in lockPartialOrder. -const ( - lockRankUnknown lockRank = iota - - lockRankSysmon - lockRankScavenge - lockRankForcegc - lockRankDefer - lockRankSweepWaiters - lockRankAssistQueue - lockRankSweep - lockRankTestR - lockRankTestW - lockRankAllocmW - lockRankExecW - lockRankCpuprof - lockRankPollDesc - lockRankWakeableSleep - // SCHED - lockRankAllocmR - lockRankExecR - lockRankSched - lockRankAllg - lockRankAllp - lockRankTimers - lockRankNetpollInit - lockRankHchan - lockRankNotifyList - lockRankSudog - lockRankRoot - lockRankItab - lockRankReflectOffs - lockRankUserArenaState - // TRACEGLOBAL - lockRankTraceBuf - lockRankTraceStrings - // MALLOC - lockRankFin - lockRankSpanSetSpine - lockRankMspanSpecial - // MPROF - lockRankGcBitsArenas - lockRankProfInsert - lockRankProfBlock - lockRankProfMemActive - lockRankProfMemFuture - // STACKGROW - lockRankGscan - lockRankStackpool - lockRankStackLarge - lockRankHchanLeaf - // WB - lockRankWbufSpans - lockRankMheap - lockRankMheapSpecial - lockRankGlobalAlloc - // TRACE - lockRankTrace - lockRankTraceStackTab - lockRankPanic - lockRankDeadlock - lockRankRaceFini - lockRankAllocmRInternal - lockRankExecRInternal - lockRankTestRInternal -) - -// lockRankLeafRank is the rank of lock that does not have a declared rank, -// and hence is a leaf lock. -const lockRankLeafRank lockRank = 1000 - -// lockNames gives the names associated with each of the above ranks. -var lockNames = []string{ - lockRankSysmon: "sysmon", - lockRankScavenge: "scavenge", - lockRankForcegc: "forcegc", - lockRankDefer: "defer", - lockRankSweepWaiters: "sweepWaiters", - lockRankAssistQueue: "assistQueue", - lockRankSweep: "sweep", - lockRankTestR: "testR", - lockRankTestW: "testW", - lockRankAllocmW: "allocmW", - lockRankExecW: "execW", - lockRankCpuprof: "cpuprof", - lockRankPollDesc: "pollDesc", - lockRankWakeableSleep: "wakeableSleep", - lockRankAllocmR: "allocmR", - lockRankExecR: "execR", - lockRankSched: "sched", - lockRankAllg: "allg", - lockRankAllp: "allp", - lockRankTimers: "timers", - lockRankNetpollInit: "netpollInit", - lockRankHchan: "hchan", - lockRankNotifyList: "notifyList", - lockRankSudog: "sudog", - lockRankRoot: "root", - lockRankItab: "itab", - lockRankReflectOffs: "reflectOffs", - lockRankUserArenaState: "userArenaState", - lockRankTraceBuf: "traceBuf", - lockRankTraceStrings: "traceStrings", - lockRankFin: "fin", - lockRankSpanSetSpine: "spanSetSpine", - lockRankMspanSpecial: "mspanSpecial", - lockRankGcBitsArenas: "gcBitsArenas", - lockRankProfInsert: "profInsert", - lockRankProfBlock: "profBlock", - lockRankProfMemActive: "profMemActive", - lockRankProfMemFuture: "profMemFuture", - lockRankGscan: "gscan", - lockRankStackpool: "stackpool", - lockRankStackLarge: "stackLarge", - lockRankHchanLeaf: "hchanLeaf", - lockRankWbufSpans: "wbufSpans", - lockRankMheap: "mheap", - lockRankMheapSpecial: "mheapSpecial", - lockRankGlobalAlloc: "globalAlloc", - lockRankTrace: "trace", - lockRankTraceStackTab: "traceStackTab", - lockRankPanic: "panic", - lockRankDeadlock: "deadlock", - lockRankRaceFini: "raceFini", - lockRankAllocmRInternal: "allocmRInternal", - lockRankExecRInternal: "execRInternal", - lockRankTestRInternal: "testRInternal", -} - -func (rank lockRank) String() string { - if rank == 0 { - return "UNKNOWN" - } - if rank == lockRankLeafRank { - return "LEAF" - } - if rank < 0 || int(rank) >= len(lockNames) { - return "BAD RANK" - } - return lockNames[rank] -} - -// lockPartialOrder is the transitive closure of the lock rank graph. -// An entry for rank X lists all of the ranks that can already be held -// when rank X is acquired. -// -// Lock ranks that allow self-cycles list themselves. -var lockPartialOrder [][]lockRank = [][]lockRank{ - lockRankSysmon: {}, - lockRankScavenge: {lockRankSysmon}, - lockRankForcegc: {lockRankSysmon}, - lockRankDefer: {}, - lockRankSweepWaiters: {}, - lockRankAssistQueue: {}, - lockRankSweep: {}, - lockRankTestR: {}, - lockRankTestW: {}, - lockRankAllocmW: {}, - lockRankExecW: {}, - lockRankCpuprof: {}, - lockRankPollDesc: {}, - lockRankWakeableSleep: {}, - lockRankAllocmR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep}, - lockRankExecR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep}, - lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR}, - lockRankAllg: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched}, - lockRankAllp: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched}, - lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllp, lockRankTimers}, - lockRankNetpollInit: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllp, lockRankTimers}, - lockRankHchan: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankWakeableSleep, lockRankHchan}, - lockRankNotifyList: {}, - lockRankSudog: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList}, - lockRankRoot: {}, - lockRankItab: {}, - lockRankReflectOffs: {lockRankItab}, - lockRankUserArenaState: {}, - lockRankTraceBuf: {lockRankSysmon, lockRankScavenge}, - lockRankTraceStrings: {lockRankSysmon, lockRankScavenge, lockRankTraceBuf}, - lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial}, - lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive}, - lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture}, - lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf}, - lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans}, - lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, - lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial}, - lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, - lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace}, - lockRankPanic: {}, - lockRankDeadlock: {lockRankPanic, lockRankDeadlock}, - lockRankRaceFini: {lockRankPanic}, - lockRankAllocmRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankAllocmW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR}, - lockRankExecRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankExecR}, - lockRankTestRInternal: {lockRankTestR, lockRankTestW}, -} diff --git a/contrib/go/_std_1.22/src/runtime/map.go b/contrib/go/_std_1.22/src/runtime/map.go deleted file mode 100644 index cd3f838fa19c..000000000000 --- a/contrib/go/_std_1.22/src/runtime/map.go +++ /dev/null @@ -1,1732 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// This file contains the implementation of Go's map type. -// -// A map is just a hash table. The data is arranged -// into an array of buckets. Each bucket contains up to -// 8 key/elem pairs. The low-order bits of the hash are -// used to select a bucket. Each bucket contains a few -// high-order bits of each hash to distinguish the entries -// within a single bucket. -// -// If more than 8 keys hash to a bucket, we chain on -// extra buckets. -// -// When the hashtable grows, we allocate a new array -// of buckets twice as big. Buckets are incrementally -// copied from the old bucket array to the new bucket array. -// -// Map iterators walk through the array of buckets and -// return the keys in walk order (bucket #, then overflow -// chain order, then bucket index). To maintain iteration -// semantics, we never move keys within their bucket (if -// we did, keys might be returned 0 or 2 times). When -// growing the table, iterators remain iterating through the -// old table and must check the new table if the bucket -// they are iterating through has been moved ("evacuated") -// to the new table. - -// Picking loadFactor: too large and we have lots of overflow -// buckets, too small and we waste a lot of space. I wrote -// a simple program to check some stats for different loads: -// (64-bit, 8 byte keys and elems) -// loadFactor %overflow bytes/entry hitprobe missprobe -// 4.00 2.13 20.77 3.00 4.00 -// 4.50 4.05 17.30 3.25 4.50 -// 5.00 6.85 14.77 3.50 5.00 -// 5.50 10.55 12.94 3.75 5.50 -// 6.00 15.27 11.67 4.00 6.00 -// 6.50 20.90 10.79 4.25 6.50 -// 7.00 27.14 10.15 4.50 7.00 -// 7.50 34.03 9.73 4.75 7.50 -// 8.00 41.10 9.40 5.00 8.00 -// -// %overflow = percentage of buckets which have an overflow bucket -// bytes/entry = overhead bytes used per key/elem pair -// hitprobe = # of entries to check when looking up a present key -// missprobe = # of entries to check when looking up an absent key -// -// Keep in mind this data is for maximally loaded tables, i.e. just -// before the table grows. Typical tables will be somewhat less loaded. - -import ( - "internal/abi" - "internal/goarch" - "runtime/internal/atomic" - "runtime/internal/math" - "unsafe" -) - -const ( - // Maximum number of key/elem pairs a bucket can hold. - bucketCntBits = abi.MapBucketCountBits - bucketCnt = abi.MapBucketCount - - // Maximum average load of a bucket that triggers growth is bucketCnt*13/16 (about 80% full) - // Because of minimum alignment rules, bucketCnt is known to be at least 8. - // Represent as loadFactorNum/loadFactorDen, to allow integer math. - loadFactorDen = 2 - loadFactorNum = loadFactorDen * bucketCnt * 13 / 16 - - // Maximum key or elem size to keep inline (instead of mallocing per element). - // Must fit in a uint8. - // Fast versions cannot handle big elems - the cutoff size for - // fast versions in cmd/compile/internal/gc/walk.go must be at most this elem. - maxKeySize = abi.MapMaxKeyBytes - maxElemSize = abi.MapMaxElemBytes - - // data offset should be the size of the bmap struct, but needs to be - // aligned correctly. For amd64p32 this means 64-bit alignment - // even though pointers are 32 bit. - dataOffset = unsafe.Offsetof(struct { - b bmap - v int64 - }{}.v) - - // Possible tophash values. We reserve a few possibilities for special marks. - // Each bucket (including its overflow buckets, if any) will have either all or none of its - // entries in the evacuated* states (except during the evacuate() method, which only happens - // during map writes and thus no one else can observe the map during that time). - emptyRest = 0 // this cell is empty, and there are no more non-empty cells at higher indexes or overflows. - emptyOne = 1 // this cell is empty - evacuatedX = 2 // key/elem is valid. Entry has been evacuated to first half of larger table. - evacuatedY = 3 // same as above, but evacuated to second half of larger table. - evacuatedEmpty = 4 // cell is empty, bucket is evacuated. - minTopHash = 5 // minimum tophash for a normal filled cell. - - // flags - iterator = 1 // there may be an iterator using buckets - oldIterator = 2 // there may be an iterator using oldbuckets - hashWriting = 4 // a goroutine is writing to the map - sameSizeGrow = 8 // the current map growth is to a new map of the same size - - // sentinel bucket ID for iterator checks - noCheck = 1<<(8*goarch.PtrSize) - 1 -) - -// isEmpty reports whether the given tophash array entry represents an empty bucket entry. -func isEmpty(x uint8) bool { - return x <= emptyOne -} - -// A header for a Go map. -type hmap struct { - // Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go. - // Make sure this stays in sync with the compiler's definition. - count int // # live cells == size of map. Must be first (used by len() builtin) - flags uint8 - B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items) - noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details - hash0 uint32 // hash seed - - buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. - oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing - nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated) - - extra *mapextra // optional fields -} - -// mapextra holds fields that are not present on all maps. -type mapextra struct { - // If both key and elem do not contain pointers and are inline, then we mark bucket - // type as containing no pointers. This avoids scanning such maps. - // However, bmap.overflow is a pointer. In order to keep overflow buckets - // alive, we store pointers to all overflow buckets in hmap.extra.overflow and hmap.extra.oldoverflow. - // overflow and oldoverflow are only used if key and elem do not contain pointers. - // overflow contains overflow buckets for hmap.buckets. - // oldoverflow contains overflow buckets for hmap.oldbuckets. - // The indirection allows to store a pointer to the slice in hiter. - overflow *[]*bmap - oldoverflow *[]*bmap - - // nextOverflow holds a pointer to a free overflow bucket. - nextOverflow *bmap -} - -// A bucket for a Go map. -type bmap struct { - // tophash generally contains the top byte of the hash value - // for each key in this bucket. If tophash[0] < minTopHash, - // tophash[0] is a bucket evacuation state instead. - tophash [bucketCnt]uint8 - // Followed by bucketCnt keys and then bucketCnt elems. - // NOTE: packing all the keys together and then all the elems together makes the - // code a bit more complicated than alternating key/elem/key/elem/... but it allows - // us to eliminate padding which would be needed for, e.g., map[int64]int8. - // Followed by an overflow pointer. -} - -// A hash iteration structure. -// If you modify hiter, also change cmd/compile/internal/reflectdata/reflect.go -// and reflect/value.go to match the layout of this structure. -type hiter struct { - key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/compile/internal/walk/range.go). - elem unsafe.Pointer // Must be in second position (see cmd/compile/internal/walk/range.go). - t *maptype - h *hmap - buckets unsafe.Pointer // bucket ptr at hash_iter initialization time - bptr *bmap // current bucket - overflow *[]*bmap // keeps overflow buckets of hmap.buckets alive - oldoverflow *[]*bmap // keeps overflow buckets of hmap.oldbuckets alive - startBucket uintptr // bucket iteration started at - offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1) - wrapped bool // already wrapped around from end of bucket array to beginning - B uint8 - i uint8 - bucket uintptr - checkBucket uintptr -} - -// bucketShift returns 1<> (goarch.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - return top -} - -func evacuated(b *bmap) bool { - h := b.tophash[0] - return h > emptyOne && h < minTopHash -} - -func (b *bmap) overflow(t *maptype) *bmap { - return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.BucketSize)-goarch.PtrSize)) -} - -func (b *bmap) setoverflow(t *maptype, ovf *bmap) { - *(**bmap)(add(unsafe.Pointer(b), uintptr(t.BucketSize)-goarch.PtrSize)) = ovf -} - -func (b *bmap) keys() unsafe.Pointer { - return add(unsafe.Pointer(b), dataOffset) -} - -// incrnoverflow increments h.noverflow. -// noverflow counts the number of overflow buckets. -// This is used to trigger same-size map growth. -// See also tooManyOverflowBuckets. -// To keep hmap small, noverflow is a uint16. -// When there are few buckets, noverflow is an exact count. -// When there are many buckets, noverflow is an approximate count. -func (h *hmap) incrnoverflow() { - // We trigger same-size map growth if there are - // as many overflow buckets as buckets. - // We need to be able to count to 1< maxAlloc { - hint = 0 - } - - // initialize Hmap - if h == nil { - h = new(hmap) - } - h.hash0 = uint32(rand()) - - // Find the size parameter B which will hold the requested # of elements. - // For hint < 0 overLoadFactor returns false since hint < bucketCnt. - B := uint8(0) - for overLoadFactor(hint, B) { - B++ - } - h.B = B - - // allocate initial hash table - // if B == 0, the buckets field is allocated lazily later (in mapassign) - // If hint is large zeroing this memory could take a while. - if h.B != 0 { - var nextOverflow *bmap - h.buckets, nextOverflow = makeBucketArray(t, h.B, nil) - if nextOverflow != nil { - h.extra = new(mapextra) - h.extra.nextOverflow = nextOverflow - } - } - - return h -} - -// makeBucketArray initializes a backing array for map buckets. -// 1<= 4 { - // Add on the estimated number of overflow buckets - // required to insert the median number of elements - // used with this value of b. - nbuckets += bucketShift(b - 4) - sz := t.Bucket.Size_ * nbuckets - up := roundupsize(sz, t.Bucket.PtrBytes == 0) - if up != sz { - nbuckets = up / t.Bucket.Size_ - } - } - - if dirtyalloc == nil { - buckets = newarray(t.Bucket, int(nbuckets)) - } else { - // dirtyalloc was previously generated by - // the above newarray(t.Bucket, int(nbuckets)) - // but may not be empty. - buckets = dirtyalloc - size := t.Bucket.Size_ * nbuckets - if t.Bucket.PtrBytes != 0 { - memclrHasPointers(buckets, size) - } else { - memclrNoHeapPointers(buckets, size) - } - } - - if base != nbuckets { - // We preallocated some overflow buckets. - // To keep the overhead of tracking these overflow buckets to a minimum, - // we use the convention that if a preallocated overflow bucket's overflow - // pointer is nil, then there are more available by bumping the pointer. - // We need a safe non-nil pointer for the last overflow bucket; just use buckets. - nextOverflow = (*bmap)(add(buckets, base*uintptr(t.BucketSize))) - last := (*bmap)(add(buckets, (nbuckets-1)*uintptr(t.BucketSize))) - last.setoverflow(t, (*bmap)(buckets)) - } - return buckets, nextOverflow -} - -// mapaccess1 returns a pointer to h[key]. Never returns nil, instead -// it will return a reference to the zero object for the elem type if -// the key is not in the map. -// NOTE: The returned pointer may keep the whole map live, so don't -// hold onto it for very long. -func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { - if raceenabled && h != nil { - callerpc := getcallerpc() - pc := abi.FuncPCABIInternal(mapaccess1) - racereadpc(unsafe.Pointer(h), callerpc, pc) - raceReadObjectPC(t.Key, key, callerpc, pc) - } - if msanenabled && h != nil { - msanread(key, t.Key.Size_) - } - if asanenabled && h != nil { - asanread(key, t.Key.Size_) - } - if h == nil || h.count == 0 { - if err := mapKeyError(t, key); err != nil { - panic(err) // see issue 23734 - } - return unsafe.Pointer(&zeroVal[0]) - } - if h.flags&hashWriting != 0 { - fatal("concurrent map read and map write") - } - hash := t.Hasher(key, uintptr(h.hash0)) - m := bucketMask(h.B) - b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.BucketSize))) - if c := h.oldbuckets; c != nil { - if !h.sameSizeGrow() { - // There used to be half as many buckets; mask down one more power of two. - m >>= 1 - } - oldb := (*bmap)(add(c, (hash&m)*uintptr(t.BucketSize))) - if !evacuated(oldb) { - b = oldb - } - } - top := tophash(hash) -bucketloop: - for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - if b.tophash[i] == emptyRest { - break bucketloop - } - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) - if t.IndirectKey() { - k = *((*unsafe.Pointer)(k)) - } - if t.Key.Equal(key, k) { - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) - if t.IndirectElem() { - e = *((*unsafe.Pointer)(e)) - } - return e - } - } - } - return unsafe.Pointer(&zeroVal[0]) -} - -func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) { - if raceenabled && h != nil { - callerpc := getcallerpc() - pc := abi.FuncPCABIInternal(mapaccess2) - racereadpc(unsafe.Pointer(h), callerpc, pc) - raceReadObjectPC(t.Key, key, callerpc, pc) - } - if msanenabled && h != nil { - msanread(key, t.Key.Size_) - } - if asanenabled && h != nil { - asanread(key, t.Key.Size_) - } - if h == nil || h.count == 0 { - if err := mapKeyError(t, key); err != nil { - panic(err) // see issue 23734 - } - return unsafe.Pointer(&zeroVal[0]), false - } - if h.flags&hashWriting != 0 { - fatal("concurrent map read and map write") - } - hash := t.Hasher(key, uintptr(h.hash0)) - m := bucketMask(h.B) - b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.BucketSize))) - if c := h.oldbuckets; c != nil { - if !h.sameSizeGrow() { - // There used to be half as many buckets; mask down one more power of two. - m >>= 1 - } - oldb := (*bmap)(add(c, (hash&m)*uintptr(t.BucketSize))) - if !evacuated(oldb) { - b = oldb - } - } - top := tophash(hash) -bucketloop: - for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - if b.tophash[i] == emptyRest { - break bucketloop - } - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) - if t.IndirectKey() { - k = *((*unsafe.Pointer)(k)) - } - if t.Key.Equal(key, k) { - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) - if t.IndirectElem() { - e = *((*unsafe.Pointer)(e)) - } - return e, true - } - } - } - return unsafe.Pointer(&zeroVal[0]), false -} - -// returns both key and elem. Used by map iterator. -func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe.Pointer) { - if h == nil || h.count == 0 { - return nil, nil - } - hash := t.Hasher(key, uintptr(h.hash0)) - m := bucketMask(h.B) - b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.BucketSize))) - if c := h.oldbuckets; c != nil { - if !h.sameSizeGrow() { - // There used to be half as many buckets; mask down one more power of two. - m >>= 1 - } - oldb := (*bmap)(add(c, (hash&m)*uintptr(t.BucketSize))) - if !evacuated(oldb) { - b = oldb - } - } - top := tophash(hash) -bucketloop: - for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - if b.tophash[i] == emptyRest { - break bucketloop - } - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) - if t.IndirectKey() { - k = *((*unsafe.Pointer)(k)) - } - if t.Key.Equal(key, k) { - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) - if t.IndirectElem() { - e = *((*unsafe.Pointer)(e)) - } - return k, e - } - } - } - return nil, nil -} - -func mapaccess1_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) unsafe.Pointer { - e := mapaccess1(t, h, key) - if e == unsafe.Pointer(&zeroVal[0]) { - return zero - } - return e -} - -func mapaccess2_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) (unsafe.Pointer, bool) { - e := mapaccess1(t, h, key) - if e == unsafe.Pointer(&zeroVal[0]) { - return zero, false - } - return e, true -} - -// Like mapaccess, but allocates a slot for the key if it is not present in the map. -func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { - if h == nil { - panic(plainError("assignment to entry in nil map")) - } - if raceenabled { - callerpc := getcallerpc() - pc := abi.FuncPCABIInternal(mapassign) - racewritepc(unsafe.Pointer(h), callerpc, pc) - raceReadObjectPC(t.Key, key, callerpc, pc) - } - if msanenabled { - msanread(key, t.Key.Size_) - } - if asanenabled { - asanread(key, t.Key.Size_) - } - if h.flags&hashWriting != 0 { - fatal("concurrent map writes") - } - hash := t.Hasher(key, uintptr(h.hash0)) - - // Set hashWriting after calling t.hasher, since t.hasher may panic, - // in which case we have not actually done a write. - h.flags ^= hashWriting - - if h.buckets == nil { - h.buckets = newobject(t.Bucket) // newarray(t.Bucket, 1) - } - -again: - bucket := hash & bucketMask(h.B) - if h.growing() { - growWork(t, h, bucket) - } - b := (*bmap)(add(h.buckets, bucket*uintptr(t.BucketSize))) - top := tophash(hash) - - var inserti *uint8 - var insertk unsafe.Pointer - var elem unsafe.Pointer -bucketloop: - for { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - if isEmpty(b.tophash[i]) && inserti == nil { - inserti = &b.tophash[i] - insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) - elem = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) - } - if b.tophash[i] == emptyRest { - break bucketloop - } - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) - if t.IndirectKey() { - k = *((*unsafe.Pointer)(k)) - } - if !t.Key.Equal(key, k) { - continue - } - // already have a mapping for key. Update it. - if t.NeedKeyUpdate() { - typedmemmove(t.Key, k, key) - } - elem = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) - goto done - } - ovf := b.overflow(t) - if ovf == nil { - break - } - b = ovf - } - - // Did not find mapping for key. Allocate new cell & add entry. - - // If we hit the max load factor or we have too many overflow buckets, - // and we're not already in the middle of growing, start growing. - if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { - hashGrow(t, h) - goto again // Growing the table invalidates everything, so try again - } - - if inserti == nil { - // The current bucket and all the overflow buckets connected to it are full, allocate a new one. - newb := h.newoverflow(t, b) - inserti = &newb.tophash[0] - insertk = add(unsafe.Pointer(newb), dataOffset) - elem = add(insertk, bucketCnt*uintptr(t.KeySize)) - } - - // store new key/elem at insert position - if t.IndirectKey() { - kmem := newobject(t.Key) - *(*unsafe.Pointer)(insertk) = kmem - insertk = kmem - } - if t.IndirectElem() { - vmem := newobject(t.Elem) - *(*unsafe.Pointer)(elem) = vmem - } - typedmemmove(t.Key, insertk, key) - *inserti = top - h.count++ - -done: - if h.flags&hashWriting == 0 { - fatal("concurrent map writes") - } - h.flags &^= hashWriting - if t.IndirectElem() { - elem = *((*unsafe.Pointer)(elem)) - } - return elem -} - -func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { - if raceenabled && h != nil { - callerpc := getcallerpc() - pc := abi.FuncPCABIInternal(mapdelete) - racewritepc(unsafe.Pointer(h), callerpc, pc) - raceReadObjectPC(t.Key, key, callerpc, pc) - } - if msanenabled && h != nil { - msanread(key, t.Key.Size_) - } - if asanenabled && h != nil { - asanread(key, t.Key.Size_) - } - if h == nil || h.count == 0 { - if err := mapKeyError(t, key); err != nil { - panic(err) // see issue 23734 - } - return - } - if h.flags&hashWriting != 0 { - fatal("concurrent map writes") - } - - hash := t.Hasher(key, uintptr(h.hash0)) - - // Set hashWriting after calling t.hasher, since t.hasher may panic, - // in which case we have not actually done a write (delete). - h.flags ^= hashWriting - - bucket := hash & bucketMask(h.B) - if h.growing() { - growWork(t, h, bucket) - } - b := (*bmap)(add(h.buckets, bucket*uintptr(t.BucketSize))) - bOrig := b - top := tophash(hash) -search: - for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - if b.tophash[i] == emptyRest { - break search - } - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) - k2 := k - if t.IndirectKey() { - k2 = *((*unsafe.Pointer)(k2)) - } - if !t.Key.Equal(key, k2) { - continue - } - // Only clear key if there are pointers in it. - if t.IndirectKey() { - *(*unsafe.Pointer)(k) = nil - } else if t.Key.PtrBytes != 0 { - memclrHasPointers(k, t.Key.Size_) - } - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) - if t.IndirectElem() { - *(*unsafe.Pointer)(e) = nil - } else if t.Elem.PtrBytes != 0 { - memclrHasPointers(e, t.Elem.Size_) - } else { - memclrNoHeapPointers(e, t.Elem.Size_) - } - b.tophash[i] = emptyOne - // If the bucket now ends in a bunch of emptyOne states, - // change those to emptyRest states. - // It would be nice to make this a separate function, but - // for loops are not currently inlineable. - if i == bucketCnt-1 { - if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { - goto notLast - } - } else { - if b.tophash[i+1] != emptyRest { - goto notLast - } - } - for { - b.tophash[i] = emptyRest - if i == 0 { - if b == bOrig { - break // beginning of initial bucket, we're done. - } - // Find previous bucket, continue at its last entry. - c := b - for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { - } - i = bucketCnt - 1 - } else { - i-- - } - if b.tophash[i] != emptyOne { - break - } - } - notLast: - h.count-- - // Reset the hash seed to make it more difficult for attackers to - // repeatedly trigger hash collisions. See issue 25237. - if h.count == 0 { - h.hash0 = uint32(rand()) - } - break search - } - } - - if h.flags&hashWriting == 0 { - fatal("concurrent map writes") - } - h.flags &^= hashWriting -} - -// mapiterinit initializes the hiter struct used for ranging over maps. -// The hiter struct pointed to by 'it' is allocated on the stack -// by the compilers order pass or on the heap by reflect_mapiterinit. -// Both need to have zeroed hiter since the struct contains pointers. -func mapiterinit(t *maptype, h *hmap, it *hiter) { - if raceenabled && h != nil { - callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapiterinit)) - } - - it.t = t - if h == nil || h.count == 0 { - return - } - - if unsafe.Sizeof(hiter{})/goarch.PtrSize != 12 { - throw("hash_iter size incorrect") // see cmd/compile/internal/reflectdata/reflect.go - } - it.h = h - - // grab snapshot of bucket state - it.B = h.B - it.buckets = h.buckets - if t.Bucket.PtrBytes == 0 { - // Allocate the current slice and remember pointers to both current and old. - // This preserves all relevant overflow buckets alive even if - // the table grows and/or overflow buckets are added to the table - // while we are iterating. - h.createOverflow() - it.overflow = h.extra.overflow - it.oldoverflow = h.extra.oldoverflow - } - - // decide where to start - r := uintptr(rand()) - it.startBucket = r & bucketMask(h.B) - it.offset = uint8(r >> h.B & (bucketCnt - 1)) - - // iterator state - it.bucket = it.startBucket - - // Remember we have an iterator. - // Can run concurrently with another mapiterinit(). - if old := h.flags; old&(iterator|oldIterator) != iterator|oldIterator { - atomic.Or8(&h.flags, iterator|oldIterator) - } - - mapiternext(it) -} - -func mapiternext(it *hiter) { - h := it.h - if raceenabled { - callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapiternext)) - } - if h.flags&hashWriting != 0 { - fatal("concurrent map iteration and map write") - } - t := it.t - bucket := it.bucket - b := it.bptr - i := it.i - checkBucket := it.checkBucket - -next: - if b == nil { - if bucket == it.startBucket && it.wrapped { - // end of iteration - it.key = nil - it.elem = nil - return - } - if h.growing() && it.B == h.B { - // Iterator was started in the middle of a grow, and the grow isn't done yet. - // If the bucket we're looking at hasn't been filled in yet (i.e. the old - // bucket hasn't been evacuated) then we need to iterate through the old - // bucket and only return the ones that will be migrated to this bucket. - oldbucket := bucket & it.h.oldbucketmask() - b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.BucketSize))) - if !evacuated(b) { - checkBucket = bucket - } else { - b = (*bmap)(add(it.buckets, bucket*uintptr(t.BucketSize))) - checkBucket = noCheck - } - } else { - b = (*bmap)(add(it.buckets, bucket*uintptr(t.BucketSize))) - checkBucket = noCheck - } - bucket++ - if bucket == bucketShift(it.B) { - bucket = 0 - it.wrapped = true - } - i = 0 - } - for ; i < bucketCnt; i++ { - offi := (i + it.offset) & (bucketCnt - 1) - if isEmpty(b.tophash[offi]) || b.tophash[offi] == evacuatedEmpty { - // TODO: emptyRest is hard to use here, as we start iterating - // in the middle of a bucket. It's feasible, just tricky. - continue - } - k := add(unsafe.Pointer(b), dataOffset+uintptr(offi)*uintptr(t.KeySize)) - if t.IndirectKey() { - k = *((*unsafe.Pointer)(k)) - } - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+uintptr(offi)*uintptr(t.ValueSize)) - if checkBucket != noCheck && !h.sameSizeGrow() { - // Special case: iterator was started during a grow to a larger size - // and the grow is not done yet. We're working on a bucket whose - // oldbucket has not been evacuated yet. Or at least, it wasn't - // evacuated when we started the bucket. So we're iterating - // through the oldbucket, skipping any keys that will go - // to the other new bucket (each oldbucket expands to two - // buckets during a grow). - if t.ReflexiveKey() || t.Key.Equal(k, k) { - // If the item in the oldbucket is not destined for - // the current new bucket in the iteration, skip it. - hash := t.Hasher(k, uintptr(h.hash0)) - if hash&bucketMask(it.B) != checkBucket { - continue - } - } else { - // Hash isn't repeatable if k != k (NaNs). We need a - // repeatable and randomish choice of which direction - // to send NaNs during evacuation. We'll use the low - // bit of tophash to decide which way NaNs go. - // NOTE: this case is why we need two evacuate tophash - // values, evacuatedX and evacuatedY, that differ in - // their low bit. - if checkBucket>>(it.B-1) != uintptr(b.tophash[offi]&1) { - continue - } - } - } - if (b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY) || - !(t.ReflexiveKey() || t.Key.Equal(k, k)) { - // This is the golden data, we can return it. - // OR - // key!=key, so the entry can't be deleted or updated, so we can just return it. - // That's lucky for us because when key!=key we can't look it up successfully. - it.key = k - if t.IndirectElem() { - e = *((*unsafe.Pointer)(e)) - } - it.elem = e - } else { - // The hash table has grown since the iterator was started. - // The golden data for this key is now somewhere else. - // Check the current hash table for the data. - // This code handles the case where the key - // has been deleted, updated, or deleted and reinserted. - // NOTE: we need to regrab the key as it has potentially been - // updated to an equal() but not identical key (e.g. +0.0 vs -0.0). - rk, re := mapaccessK(t, h, k) - if rk == nil { - continue // key has been deleted - } - it.key = rk - it.elem = re - } - it.bucket = bucket - if it.bptr != b { // avoid unnecessary write barrier; see issue 14921 - it.bptr = b - } - it.i = i + 1 - it.checkBucket = checkBucket - return - } - b = b.overflow(t) - i = 0 - goto next -} - -// mapclear deletes all keys from a map. -func mapclear(t *maptype, h *hmap) { - if raceenabled && h != nil { - callerpc := getcallerpc() - pc := abi.FuncPCABIInternal(mapclear) - racewritepc(unsafe.Pointer(h), callerpc, pc) - } - - if h == nil || h.count == 0 { - return - } - - if h.flags&hashWriting != 0 { - fatal("concurrent map writes") - } - - h.flags ^= hashWriting - - // Mark buckets empty, so existing iterators can be terminated, see issue #59411. - markBucketsEmpty := func(bucket unsafe.Pointer, mask uintptr) { - for i := uintptr(0); i <= mask; i++ { - b := (*bmap)(add(bucket, i*uintptr(t.BucketSize))) - for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { - b.tophash[i] = emptyRest - } - } - } - } - markBucketsEmpty(h.buckets, bucketMask(h.B)) - if oldBuckets := h.oldbuckets; oldBuckets != nil { - markBucketsEmpty(oldBuckets, h.oldbucketmask()) - } - - h.flags &^= sameSizeGrow - h.oldbuckets = nil - h.nevacuate = 0 - h.noverflow = 0 - h.count = 0 - - // Reset the hash seed to make it more difficult for attackers to - // repeatedly trigger hash collisions. See issue 25237. - h.hash0 = uint32(rand()) - - // Keep the mapextra allocation but clear any extra information. - if h.extra != nil { - *h.extra = mapextra{} - } - - // makeBucketArray clears the memory pointed to by h.buckets - // and recovers any overflow buckets by generating them - // as if h.buckets was newly alloced. - _, nextOverflow := makeBucketArray(t, h.B, h.buckets) - if nextOverflow != nil { - // If overflow buckets are created then h.extra - // will have been allocated during initial bucket creation. - h.extra.nextOverflow = nextOverflow - } - - if h.flags&hashWriting == 0 { - fatal("concurrent map writes") - } - h.flags &^= hashWriting -} - -func hashGrow(t *maptype, h *hmap) { - // If we've hit the load factor, get bigger. - // Otherwise, there are too many overflow buckets, - // so keep the same number of buckets and "grow" laterally. - bigger := uint8(1) - if !overLoadFactor(h.count+1, h.B) { - bigger = 0 - h.flags |= sameSizeGrow - } - oldbuckets := h.buckets - newbuckets, nextOverflow := makeBucketArray(t, h.B+bigger, nil) - - flags := h.flags &^ (iterator | oldIterator) - if h.flags&iterator != 0 { - flags |= oldIterator - } - // commit the grow (atomic wrt gc) - h.B += bigger - h.flags = flags - h.oldbuckets = oldbuckets - h.buckets = newbuckets - h.nevacuate = 0 - h.noverflow = 0 - - if h.extra != nil && h.extra.overflow != nil { - // Promote current overflow buckets to the old generation. - if h.extra.oldoverflow != nil { - throw("oldoverflow is not nil") - } - h.extra.oldoverflow = h.extra.overflow - h.extra.overflow = nil - } - if nextOverflow != nil { - if h.extra == nil { - h.extra = new(mapextra) - } - h.extra.nextOverflow = nextOverflow - } - - // the actual copying of the hash table data is done incrementally - // by growWork() and evacuate(). -} - -// overLoadFactor reports whether count items placed in 1< bucketCnt && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen) -} - -// tooManyOverflowBuckets reports whether noverflow buckets is too many for a map with 1< 15 { - B = 15 - } - // The compiler doesn't see here that B < 16; mask B to generate shorter shift code. - return noverflow >= uint16(1)<<(B&15) -} - -// growing reports whether h is growing. The growth may be to the same size or bigger. -func (h *hmap) growing() bool { - return h.oldbuckets != nil -} - -// sameSizeGrow reports whether the current growth is to a map of the same size. -func (h *hmap) sameSizeGrow() bool { - return h.flags&sameSizeGrow != 0 -} - -// noldbuckets calculates the number of buckets prior to the current map growth. -func (h *hmap) noldbuckets() uintptr { - oldB := h.B - if !h.sameSizeGrow() { - oldB-- - } - return bucketShift(oldB) -} - -// oldbucketmask provides a mask that can be applied to calculate n % noldbuckets(). -func (h *hmap) oldbucketmask() uintptr { - return h.noldbuckets() - 1 -} - -func growWork(t *maptype, h *hmap, bucket uintptr) { - // make sure we evacuate the oldbucket corresponding - // to the bucket we're about to use - evacuate(t, h, bucket&h.oldbucketmask()) - - // evacuate one more oldbucket to make progress on growing - if h.growing() { - evacuate(t, h, h.nevacuate) - } -} - -func bucketEvacuated(t *maptype, h *hmap, bucket uintptr) bool { - b := (*bmap)(add(h.oldbuckets, bucket*uintptr(t.BucketSize))) - return evacuated(b) -} - -// evacDst is an evacuation destination. -type evacDst struct { - b *bmap // current destination bucket - i int // key/elem index into b - k unsafe.Pointer // pointer to current key storage - e unsafe.Pointer // pointer to current elem storage -} - -func evacuate(t *maptype, h *hmap, oldbucket uintptr) { - b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.BucketSize))) - newbit := h.noldbuckets() - if !evacuated(b) { - // TODO: reuse overflow buckets instead of using new ones, if there - // is no iterator using the old buckets. (If !oldIterator.) - - // xy contains the x and y (low and high) evacuation destinations. - var xy [2]evacDst - x := &xy[0] - x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.BucketSize))) - x.k = add(unsafe.Pointer(x.b), dataOffset) - x.e = add(x.k, bucketCnt*uintptr(t.KeySize)) - - if !h.sameSizeGrow() { - // Only calculate y pointers if we're growing bigger. - // Otherwise GC can see bad pointers. - y := &xy[1] - y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.BucketSize))) - y.k = add(unsafe.Pointer(y.b), dataOffset) - y.e = add(y.k, bucketCnt*uintptr(t.KeySize)) - } - - for ; b != nil; b = b.overflow(t) { - k := add(unsafe.Pointer(b), dataOffset) - e := add(k, bucketCnt*uintptr(t.KeySize)) - for i := 0; i < bucketCnt; i, k, e = i+1, add(k, uintptr(t.KeySize)), add(e, uintptr(t.ValueSize)) { - top := b.tophash[i] - if isEmpty(top) { - b.tophash[i] = evacuatedEmpty - continue - } - if top < minTopHash { - throw("bad map state") - } - k2 := k - if t.IndirectKey() { - k2 = *((*unsafe.Pointer)(k2)) - } - var useY uint8 - if !h.sameSizeGrow() { - // Compute hash to make our evacuation decision (whether we need - // to send this key/elem to bucket x or bucket y). - hash := t.Hasher(k2, uintptr(h.hash0)) - if h.flags&iterator != 0 && !t.ReflexiveKey() && !t.Key.Equal(k2, k2) { - // If key != key (NaNs), then the hash could be (and probably - // will be) entirely different from the old hash. Moreover, - // it isn't reproducible. Reproducibility is required in the - // presence of iterators, as our evacuation decision must - // match whatever decision the iterator made. - // Fortunately, we have the freedom to send these keys either - // way. Also, tophash is meaningless for these kinds of keys. - // We let the low bit of tophash drive the evacuation decision. - // We recompute a new random tophash for the next level so - // these keys will get evenly distributed across all buckets - // after multiple grows. - useY = top & 1 - top = tophash(hash) - } else { - if hash&newbit != 0 { - useY = 1 - } - } - } - - if evacuatedX+1 != evacuatedY || evacuatedX^1 != evacuatedY { - throw("bad evacuatedN") - } - - b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY - dst := &xy[useY] // evacuation destination - - if dst.i == bucketCnt { - dst.b = h.newoverflow(t, dst.b) - dst.i = 0 - dst.k = add(unsafe.Pointer(dst.b), dataOffset) - dst.e = add(dst.k, bucketCnt*uintptr(t.KeySize)) - } - dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check - if t.IndirectKey() { - *(*unsafe.Pointer)(dst.k) = k2 // copy pointer - } else { - typedmemmove(t.Key, dst.k, k) // copy elem - } - if t.IndirectElem() { - *(*unsafe.Pointer)(dst.e) = *(*unsafe.Pointer)(e) - } else { - typedmemmove(t.Elem, dst.e, e) - } - dst.i++ - // These updates might push these pointers past the end of the - // key or elem arrays. That's ok, as we have the overflow pointer - // at the end of the bucket to protect against pointing past the - // end of the bucket. - dst.k = add(dst.k, uintptr(t.KeySize)) - dst.e = add(dst.e, uintptr(t.ValueSize)) - } - } - // Unlink the overflow buckets & clear key/elem to help GC. - if h.flags&oldIterator == 0 && t.Bucket.PtrBytes != 0 { - b := add(h.oldbuckets, oldbucket*uintptr(t.BucketSize)) - // Preserve b.tophash because the evacuation - // state is maintained there. - ptr := add(b, dataOffset) - n := uintptr(t.BucketSize) - dataOffset - memclrHasPointers(ptr, n) - } - } - - if oldbucket == h.nevacuate { - advanceEvacuationMark(h, t, newbit) - } -} - -func advanceEvacuationMark(h *hmap, t *maptype, newbit uintptr) { - h.nevacuate++ - // Experiments suggest that 1024 is overkill by at least an order of magnitude. - // Put it in there as a safeguard anyway, to ensure O(1) behavior. - stop := h.nevacuate + 1024 - if stop > newbit { - stop = newbit - } - for h.nevacuate != stop && bucketEvacuated(t, h, h.nevacuate) { - h.nevacuate++ - } - if h.nevacuate == newbit { // newbit == # of oldbuckets - // Growing is all done. Free old main bucket array. - h.oldbuckets = nil - // Can discard old overflow buckets as well. - // If they are still referenced by an iterator, - // then the iterator holds a pointers to the slice. - if h.extra != nil { - h.extra.oldoverflow = nil - } - h.flags &^= sameSizeGrow - } -} - -// Reflect stubs. Called from ../reflect/asm_*.s - -//go:linkname reflect_makemap reflect.makemap -func reflect_makemap(t *maptype, cap int) *hmap { - // Check invariants and reflects math. - if t.Key.Equal == nil { - throw("runtime.reflect_makemap: unsupported map key type") - } - if t.Key.Size_ > maxKeySize && (!t.IndirectKey() || t.KeySize != uint8(goarch.PtrSize)) || - t.Key.Size_ <= maxKeySize && (t.IndirectKey() || t.KeySize != uint8(t.Key.Size_)) { - throw("key size wrong") - } - if t.Elem.Size_ > maxElemSize && (!t.IndirectElem() || t.ValueSize != uint8(goarch.PtrSize)) || - t.Elem.Size_ <= maxElemSize && (t.IndirectElem() || t.ValueSize != uint8(t.Elem.Size_)) { - throw("elem size wrong") - } - if t.Key.Align_ > bucketCnt { - throw("key align too big") - } - if t.Elem.Align_ > bucketCnt { - throw("elem align too big") - } - if t.Key.Size_%uintptr(t.Key.Align_) != 0 { - throw("key size not a multiple of key align") - } - if t.Elem.Size_%uintptr(t.Elem.Align_) != 0 { - throw("elem size not a multiple of elem align") - } - if bucketCnt < 8 { - throw("bucketsize too small for proper alignment") - } - if dataOffset%uintptr(t.Key.Align_) != 0 { - throw("need padding in bucket (key)") - } - if dataOffset%uintptr(t.Elem.Align_) != 0 { - throw("need padding in bucket (elem)") - } - - return makemap(t, cap, nil) -} - -//go:linkname reflect_mapaccess reflect.mapaccess -func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { - elem, ok := mapaccess2(t, h, key) - if !ok { - // reflect wants nil for a missing element - elem = nil - } - return elem -} - -//go:linkname reflect_mapaccess_faststr reflect.mapaccess_faststr -func reflect_mapaccess_faststr(t *maptype, h *hmap, key string) unsafe.Pointer { - elem, ok := mapaccess2_faststr(t, h, key) - if !ok { - // reflect wants nil for a missing element - elem = nil - } - return elem -} - -//go:linkname reflect_mapassign reflect.mapassign0 -func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, elem unsafe.Pointer) { - p := mapassign(t, h, key) - typedmemmove(t.Elem, p, elem) -} - -//go:linkname reflect_mapassign_faststr reflect.mapassign_faststr0 -func reflect_mapassign_faststr(t *maptype, h *hmap, key string, elem unsafe.Pointer) { - p := mapassign_faststr(t, h, key) - typedmemmove(t.Elem, p, elem) -} - -//go:linkname reflect_mapdelete reflect.mapdelete -func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { - mapdelete(t, h, key) -} - -//go:linkname reflect_mapdelete_faststr reflect.mapdelete_faststr -func reflect_mapdelete_faststr(t *maptype, h *hmap, key string) { - mapdelete_faststr(t, h, key) -} - -//go:linkname reflect_mapiterinit reflect.mapiterinit -func reflect_mapiterinit(t *maptype, h *hmap, it *hiter) { - mapiterinit(t, h, it) -} - -//go:linkname reflect_mapiternext reflect.mapiternext -func reflect_mapiternext(it *hiter) { - mapiternext(it) -} - -//go:linkname reflect_mapiterkey reflect.mapiterkey -func reflect_mapiterkey(it *hiter) unsafe.Pointer { - return it.key -} - -//go:linkname reflect_mapiterelem reflect.mapiterelem -func reflect_mapiterelem(it *hiter) unsafe.Pointer { - return it.elem -} - -//go:linkname reflect_maplen reflect.maplen -func reflect_maplen(h *hmap) int { - if h == nil { - return 0 - } - if raceenabled { - callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(reflect_maplen)) - } - return h.count -} - -//go:linkname reflect_mapclear reflect.mapclear -func reflect_mapclear(t *maptype, h *hmap) { - mapclear(t, h) -} - -//go:linkname reflectlite_maplen internal/reflectlite.maplen -func reflectlite_maplen(h *hmap) int { - if h == nil { - return 0 - } - if raceenabled { - callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(reflect_maplen)) - } - return h.count -} - -var zeroVal [abi.ZeroValSize]byte - -// mapinitnoop is a no-op function known the Go linker; if a given global -// map (of the right size) is determined to be dead, the linker will -// rewrite the relocation (from the package init func) from the outlined -// map init function to this symbol. Defined in assembly so as to avoid -// complications with instrumentation (coverage, etc). -func mapinitnoop() - -// mapclone for implementing maps.Clone -// -//go:linkname mapclone maps.clone -func mapclone(m any) any { - e := efaceOf(&m) - e.data = unsafe.Pointer(mapclone2((*maptype)(unsafe.Pointer(e._type)), (*hmap)(e.data))) - return m -} - -// moveToBmap moves a bucket from src to dst. It returns the destination bucket or new destination bucket if it overflows -// and the pos that the next key/value will be written, if pos == bucketCnt means needs to written in overflow bucket. -func moveToBmap(t *maptype, h *hmap, dst *bmap, pos int, src *bmap) (*bmap, int) { - for i := 0; i < bucketCnt; i++ { - if isEmpty(src.tophash[i]) { - continue - } - - for ; pos < bucketCnt; pos++ { - if isEmpty(dst.tophash[pos]) { - break - } - } - - if pos == bucketCnt { - dst = h.newoverflow(t, dst) - pos = 0 - } - - srcK := add(unsafe.Pointer(src), dataOffset+uintptr(i)*uintptr(t.KeySize)) - srcEle := add(unsafe.Pointer(src), dataOffset+bucketCnt*uintptr(t.KeySize)+uintptr(i)*uintptr(t.ValueSize)) - dstK := add(unsafe.Pointer(dst), dataOffset+uintptr(pos)*uintptr(t.KeySize)) - dstEle := add(unsafe.Pointer(dst), dataOffset+bucketCnt*uintptr(t.KeySize)+uintptr(pos)*uintptr(t.ValueSize)) - - dst.tophash[pos] = src.tophash[i] - if t.IndirectKey() { - srcK = *(*unsafe.Pointer)(srcK) - if t.NeedKeyUpdate() { - kStore := newobject(t.Key) - typedmemmove(t.Key, kStore, srcK) - srcK = kStore - } - // Note: if NeedKeyUpdate is false, then the memory - // used to store the key is immutable, so we can share - // it between the original map and its clone. - *(*unsafe.Pointer)(dstK) = srcK - } else { - typedmemmove(t.Key, dstK, srcK) - } - if t.IndirectElem() { - srcEle = *(*unsafe.Pointer)(srcEle) - eStore := newobject(t.Elem) - typedmemmove(t.Elem, eStore, srcEle) - *(*unsafe.Pointer)(dstEle) = eStore - } else { - typedmemmove(t.Elem, dstEle, srcEle) - } - pos++ - h.count++ - } - return dst, pos -} - -func mapclone2(t *maptype, src *hmap) *hmap { - dst := makemap(t, src.count, nil) - dst.hash0 = src.hash0 - dst.nevacuate = 0 - //flags do not need to be copied here, just like a new map has no flags. - - if src.count == 0 { - return dst - } - - if src.flags&hashWriting != 0 { - fatal("concurrent map clone and map write") - } - - if src.B == 0 && !(t.IndirectKey() && t.NeedKeyUpdate()) && !t.IndirectElem() { - // Quick copy for small maps. - dst.buckets = newobject(t.Bucket) - dst.count = src.count - typedmemmove(t.Bucket, dst.buckets, src.buckets) - return dst - } - - if dst.B == 0 { - dst.buckets = newobject(t.Bucket) - } - dstArraySize := int(bucketShift(dst.B)) - srcArraySize := int(bucketShift(src.B)) - for i := 0; i < dstArraySize; i++ { - dstBmap := (*bmap)(add(dst.buckets, uintptr(i*int(t.BucketSize)))) - pos := 0 - for j := 0; j < srcArraySize; j += dstArraySize { - srcBmap := (*bmap)(add(src.buckets, uintptr((i+j)*int(t.BucketSize)))) - for srcBmap != nil { - dstBmap, pos = moveToBmap(t, dst, dstBmap, pos, srcBmap) - srcBmap = srcBmap.overflow(t) - } - } - } - - if src.oldbuckets == nil { - return dst - } - - oldB := src.B - srcOldbuckets := src.oldbuckets - if !src.sameSizeGrow() { - oldB-- - } - oldSrcArraySize := int(bucketShift(oldB)) - - for i := 0; i < oldSrcArraySize; i++ { - srcBmap := (*bmap)(add(srcOldbuckets, uintptr(i*int(t.BucketSize)))) - if evacuated(srcBmap) { - continue - } - - if oldB >= dst.B { // main bucket bits in dst is less than oldB bits in src - dstBmap := (*bmap)(add(dst.buckets, (uintptr(i)&bucketMask(dst.B))*uintptr(t.BucketSize))) - for dstBmap.overflow(t) != nil { - dstBmap = dstBmap.overflow(t) - } - pos := 0 - for srcBmap != nil { - dstBmap, pos = moveToBmap(t, dst, dstBmap, pos, srcBmap) - srcBmap = srcBmap.overflow(t) - } - continue - } - - // oldB < dst.B, so a single source bucket may go to multiple destination buckets. - // Process entries one at a time. - for srcBmap != nil { - // move from oldBlucket to new bucket - for i := uintptr(0); i < bucketCnt; i++ { - if isEmpty(srcBmap.tophash[i]) { - continue - } - - if src.flags&hashWriting != 0 { - fatal("concurrent map clone and map write") - } - - srcK := add(unsafe.Pointer(srcBmap), dataOffset+i*uintptr(t.KeySize)) - if t.IndirectKey() { - srcK = *((*unsafe.Pointer)(srcK)) - } - - srcEle := add(unsafe.Pointer(srcBmap), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) - if t.IndirectElem() { - srcEle = *((*unsafe.Pointer)(srcEle)) - } - dstEle := mapassign(t, dst, srcK) - typedmemmove(t.Elem, dstEle, srcEle) - } - srcBmap = srcBmap.overflow(t) - } - } - return dst -} - -// keys for implementing maps.keys -// -//go:linkname keys maps.keys -func keys(m any, p unsafe.Pointer) { - e := efaceOf(&m) - t := (*maptype)(unsafe.Pointer(e._type)) - h := (*hmap)(e.data) - - if h == nil || h.count == 0 { - return - } - s := (*slice)(p) - r := int(rand()) - offset := uint8(r >> h.B & (bucketCnt - 1)) - if h.B == 0 { - copyKeys(t, h, (*bmap)(h.buckets), s, offset) - return - } - arraySize := int(bucketShift(h.B)) - buckets := h.buckets - for i := 0; i < arraySize; i++ { - bucket := (i + r) & (arraySize - 1) - b := (*bmap)(add(buckets, uintptr(bucket)*uintptr(t.BucketSize))) - copyKeys(t, h, b, s, offset) - } - - if h.growing() { - oldArraySize := int(h.noldbuckets()) - for i := 0; i < oldArraySize; i++ { - bucket := (i + r) & (oldArraySize - 1) - b := (*bmap)(add(h.oldbuckets, uintptr(bucket)*uintptr(t.BucketSize))) - if evacuated(b) { - continue - } - copyKeys(t, h, b, s, offset) - } - } - return -} - -func copyKeys(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) { - for b != nil { - for i := uintptr(0); i < bucketCnt; i++ { - offi := (i + uintptr(offset)) & (bucketCnt - 1) - if isEmpty(b.tophash[offi]) { - continue - } - if h.flags&hashWriting != 0 { - fatal("concurrent map read and map write") - } - k := add(unsafe.Pointer(b), dataOffset+offi*uintptr(t.KeySize)) - if t.IndirectKey() { - k = *((*unsafe.Pointer)(k)) - } - if s.len >= s.cap { - fatal("concurrent map read and map write") - } - typedmemmove(t.Key, add(s.array, uintptr(s.len)*uintptr(t.Key.Size())), k) - s.len++ - } - b = b.overflow(t) - } -} - -// values for implementing maps.values -// -//go:linkname values maps.values -func values(m any, p unsafe.Pointer) { - e := efaceOf(&m) - t := (*maptype)(unsafe.Pointer(e._type)) - h := (*hmap)(e.data) - if h == nil || h.count == 0 { - return - } - s := (*slice)(p) - r := int(rand()) - offset := uint8(r >> h.B & (bucketCnt - 1)) - if h.B == 0 { - copyValues(t, h, (*bmap)(h.buckets), s, offset) - return - } - arraySize := int(bucketShift(h.B)) - buckets := h.buckets - for i := 0; i < arraySize; i++ { - bucket := (i + r) & (arraySize - 1) - b := (*bmap)(add(buckets, uintptr(bucket)*uintptr(t.BucketSize))) - copyValues(t, h, b, s, offset) - } - - if h.growing() { - oldArraySize := int(h.noldbuckets()) - for i := 0; i < oldArraySize; i++ { - bucket := (i + r) & (oldArraySize - 1) - b := (*bmap)(add(h.oldbuckets, uintptr(bucket)*uintptr(t.BucketSize))) - if evacuated(b) { - continue - } - copyValues(t, h, b, s, offset) - } - } - return -} - -func copyValues(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) { - for b != nil { - for i := uintptr(0); i < bucketCnt; i++ { - offi := (i + uintptr(offset)) & (bucketCnt - 1) - if isEmpty(b.tophash[offi]) { - continue - } - - if h.flags&hashWriting != 0 { - fatal("concurrent map read and map write") - } - - ele := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+offi*uintptr(t.ValueSize)) - if t.IndirectElem() { - ele = *((*unsafe.Pointer)(ele)) - } - if s.len >= s.cap { - fatal("concurrent map read and map write") - } - typedmemmove(t.Elem, add(s.array, uintptr(s.len)*uintptr(t.Elem.Size())), ele) - s.len++ - } - b = b.overflow(t) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/mbitmap.go b/contrib/go/_std_1.22/src/runtime/mbitmap.go deleted file mode 100644 index cdd1c5fc3b5b..000000000000 --- a/contrib/go/_std_1.22/src/runtime/mbitmap.go +++ /dev/null @@ -1,775 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/goarch" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -// addb returns the byte pointer p+n. -// -//go:nowritebarrier -//go:nosplit -func addb(p *byte, n uintptr) *byte { - // Note: wrote out full expression instead of calling add(p, n) - // to reduce the number of temporaries generated by the - // compiler for this trivial expression during inlining. - return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + n)) -} - -// subtractb returns the byte pointer p-n. -// -//go:nowritebarrier -//go:nosplit -func subtractb(p *byte, n uintptr) *byte { - // Note: wrote out full expression instead of calling add(p, -n) - // to reduce the number of temporaries generated by the - // compiler for this trivial expression during inlining. - return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - n)) -} - -// add1 returns the byte pointer p+1. -// -//go:nowritebarrier -//go:nosplit -func add1(p *byte) *byte { - // Note: wrote out full expression instead of calling addb(p, 1) - // to reduce the number of temporaries generated by the - // compiler for this trivial expression during inlining. - return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1)) -} - -// subtract1 returns the byte pointer p-1. -// -// nosplit because it is used during write barriers and must not be preempted. -// -//go:nowritebarrier -//go:nosplit -func subtract1(p *byte) *byte { - // Note: wrote out full expression instead of calling subtractb(p, 1) - // to reduce the number of temporaries generated by the - // compiler for this trivial expression during inlining. - return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - 1)) -} - -// markBits provides access to the mark bit for an object in the heap. -// bytep points to the byte holding the mark bit. -// mask is a byte with a single bit set that can be &ed with *bytep -// to see if the bit has been set. -// *m.byte&m.mask != 0 indicates the mark bit is set. -// index can be used along with span information to generate -// the address of the object in the heap. -// We maintain one set of mark bits for allocation and one for -// marking purposes. -type markBits struct { - bytep *uint8 - mask uint8 - index uintptr -} - -//go:nosplit -func (s *mspan) allocBitsForIndex(allocBitIndex uintptr) markBits { - bytep, mask := s.allocBits.bitp(allocBitIndex) - return markBits{bytep, mask, allocBitIndex} -} - -// refillAllocCache takes 8 bytes s.allocBits starting at whichByte -// and negates them so that ctz (count trailing zeros) instructions -// can be used. It then places these 8 bytes into the cached 64 bit -// s.allocCache. -func (s *mspan) refillAllocCache(whichByte uint16) { - bytes := (*[8]uint8)(unsafe.Pointer(s.allocBits.bytep(uintptr(whichByte)))) - aCache := uint64(0) - aCache |= uint64(bytes[0]) - aCache |= uint64(bytes[1]) << (1 * 8) - aCache |= uint64(bytes[2]) << (2 * 8) - aCache |= uint64(bytes[3]) << (3 * 8) - aCache |= uint64(bytes[4]) << (4 * 8) - aCache |= uint64(bytes[5]) << (5 * 8) - aCache |= uint64(bytes[6]) << (6 * 8) - aCache |= uint64(bytes[7]) << (7 * 8) - s.allocCache = ^aCache -} - -// nextFreeIndex returns the index of the next free object in s at -// or after s.freeindex. -// There are hardware instructions that can be used to make this -// faster if profiling warrants it. -func (s *mspan) nextFreeIndex() uint16 { - sfreeindex := s.freeindex - snelems := s.nelems - if sfreeindex == snelems { - return sfreeindex - } - if sfreeindex > snelems { - throw("s.freeindex > s.nelems") - } - - aCache := s.allocCache - - bitIndex := sys.TrailingZeros64(aCache) - for bitIndex == 64 { - // Move index to start of next cached bits. - sfreeindex = (sfreeindex + 64) &^ (64 - 1) - if sfreeindex >= snelems { - s.freeindex = snelems - return snelems - } - whichByte := sfreeindex / 8 - // Refill s.allocCache with the next 64 alloc bits. - s.refillAllocCache(whichByte) - aCache = s.allocCache - bitIndex = sys.TrailingZeros64(aCache) - // nothing available in cached bits - // grab the next 8 bytes and try again. - } - result := sfreeindex + uint16(bitIndex) - if result >= snelems { - s.freeindex = snelems - return snelems - } - - s.allocCache >>= uint(bitIndex + 1) - sfreeindex = result + 1 - - if sfreeindex%64 == 0 && sfreeindex != snelems { - // We just incremented s.freeindex so it isn't 0. - // As each 1 in s.allocCache was encountered and used for allocation - // it was shifted away. At this point s.allocCache contains all 0s. - // Refill s.allocCache so that it corresponds - // to the bits at s.allocBits starting at s.freeindex. - whichByte := sfreeindex / 8 - s.refillAllocCache(whichByte) - } - s.freeindex = sfreeindex - return result -} - -// isFree reports whether the index'th object in s is unallocated. -// -// The caller must ensure s.state is mSpanInUse, and there must have -// been no preemption points since ensuring this (which could allow a -// GC transition, which would allow the state to change). -func (s *mspan) isFree(index uintptr) bool { - if index < uintptr(s.freeIndexForScan) { - return false - } - bytep, mask := s.allocBits.bitp(index) - return *bytep&mask == 0 -} - -// divideByElemSize returns n/s.elemsize. -// n must be within [0, s.npages*_PageSize), -// or may be exactly s.npages*_PageSize -// if s.elemsize is from sizeclasses.go. -// -// nosplit, because it is called by objIndex, which is nosplit -// -//go:nosplit -func (s *mspan) divideByElemSize(n uintptr) uintptr { - const doubleCheck = false - - // See explanation in mksizeclasses.go's computeDivMagic. - q := uintptr((uint64(n) * uint64(s.divMul)) >> 32) - - if doubleCheck && q != n/s.elemsize { - println(n, "/", s.elemsize, "should be", n/s.elemsize, "but got", q) - throw("bad magic division") - } - return q -} - -// nosplit, because it is called by other nosplit code like findObject -// -//go:nosplit -func (s *mspan) objIndex(p uintptr) uintptr { - return s.divideByElemSize(p - s.base()) -} - -func markBitsForAddr(p uintptr) markBits { - s := spanOf(p) - objIndex := s.objIndex(p) - return s.markBitsForIndex(objIndex) -} - -func (s *mspan) markBitsForIndex(objIndex uintptr) markBits { - bytep, mask := s.gcmarkBits.bitp(objIndex) - return markBits{bytep, mask, objIndex} -} - -func (s *mspan) markBitsForBase() markBits { - return markBits{&s.gcmarkBits.x, uint8(1), 0} -} - -// isMarked reports whether mark bit m is set. -func (m markBits) isMarked() bool { - return *m.bytep&m.mask != 0 -} - -// setMarked sets the marked bit in the markbits, atomically. -func (m markBits) setMarked() { - // Might be racing with other updates, so use atomic update always. - // We used to be clever here and use a non-atomic update in certain - // cases, but it's not worth the risk. - atomic.Or8(m.bytep, m.mask) -} - -// setMarkedNonAtomic sets the marked bit in the markbits, non-atomically. -func (m markBits) setMarkedNonAtomic() { - *m.bytep |= m.mask -} - -// clearMarked clears the marked bit in the markbits, atomically. -func (m markBits) clearMarked() { - // Might be racing with other updates, so use atomic update always. - // We used to be clever here and use a non-atomic update in certain - // cases, but it's not worth the risk. - atomic.And8(m.bytep, ^m.mask) -} - -// markBitsForSpan returns the markBits for the span base address base. -func markBitsForSpan(base uintptr) (mbits markBits) { - mbits = markBitsForAddr(base) - if mbits.mask != 1 { - throw("markBitsForSpan: unaligned start") - } - return mbits -} - -// advance advances the markBits to the next object in the span. -func (m *markBits) advance() { - if m.mask == 1<<7 { - m.bytep = (*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(m.bytep)) + 1)) - m.mask = 1 - } else { - m.mask = m.mask << 1 - } - m.index++ -} - -// clobberdeadPtr is a special value that is used by the compiler to -// clobber dead stack slots, when -clobberdead flag is set. -const clobberdeadPtr = uintptr(0xdeaddead | 0xdeaddead<<((^uintptr(0)>>63)*32)) - -// badPointer throws bad pointer in heap panic. -func badPointer(s *mspan, p, refBase, refOff uintptr) { - // Typically this indicates an incorrect use - // of unsafe or cgo to store a bad pointer in - // the Go heap. It may also indicate a runtime - // bug. - // - // TODO(austin): We could be more aggressive - // and detect pointers to unallocated objects - // in allocated spans. - printlock() - print("runtime: pointer ", hex(p)) - if s != nil { - state := s.state.get() - if state != mSpanInUse { - print(" to unallocated span") - } else { - print(" to unused region of span") - } - print(" span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", state) - } - print("\n") - if refBase != 0 { - print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n") - gcDumpObject("object", refBase, refOff) - } - getg().m.traceback = 2 - throw("found bad pointer in Go heap (incorrect use of unsafe or cgo?)") -} - -// findObject returns the base address for the heap object containing -// the address p, the object's span, and the index of the object in s. -// If p does not point into a heap object, it returns base == 0. -// -// If p points is an invalid heap pointer and debug.invalidptr != 0, -// findObject panics. -// -// refBase and refOff optionally give the base address of the object -// in which the pointer p was found and the byte offset at which it -// was found. These are used for error reporting. -// -// It is nosplit so it is safe for p to be a pointer to the current goroutine's stack. -// Since p is a uintptr, it would not be adjusted if the stack were to move. -// -//go:nosplit -func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex uintptr) { - s = spanOf(p) - // If s is nil, the virtual address has never been part of the heap. - // This pointer may be to some mmap'd region, so we allow it. - if s == nil { - if (GOARCH == "amd64" || GOARCH == "arm64") && p == clobberdeadPtr && debug.invalidptr != 0 { - // Crash if clobberdeadPtr is seen. Only on AMD64 and ARM64 for now, - // as they are the only platform where compiler's clobberdead mode is - // implemented. On these platforms clobberdeadPtr cannot be a valid address. - badPointer(s, p, refBase, refOff) - } - return - } - // If p is a bad pointer, it may not be in s's bounds. - // - // Check s.state to synchronize with span initialization - // before checking other fields. See also spanOfHeap. - if state := s.state.get(); state != mSpanInUse || p < s.base() || p >= s.limit { - // Pointers into stacks are also ok, the runtime manages these explicitly. - if state == mSpanManual { - return - } - // The following ensures that we are rigorous about what data - // structures hold valid pointers. - if debug.invalidptr != 0 { - badPointer(s, p, refBase, refOff) - } - return - } - - objIndex = s.objIndex(p) - base = s.base() + objIndex*s.elemsize - return -} - -// reflect_verifyNotInHeapPtr reports whether converting the not-in-heap pointer into a unsafe.Pointer is ok. -// -//go:linkname reflect_verifyNotInHeapPtr reflect.verifyNotInHeapPtr -func reflect_verifyNotInHeapPtr(p uintptr) bool { - // Conversion to a pointer is ok as long as findObject above does not call badPointer. - // Since we're already promised that p doesn't point into the heap, just disallow heap - // pointers and the special clobbered pointer. - return spanOf(p) == nil && p != clobberdeadPtr -} - -const ptrBits = 8 * goarch.PtrSize - -// bulkBarrierBitmap executes write barriers for copying from [src, -// src+size) to [dst, dst+size) using a 1-bit pointer bitmap. src is -// assumed to start maskOffset bytes into the data covered by the -// bitmap in bits (which may not be a multiple of 8). -// -// This is used by bulkBarrierPreWrite for writes to data and BSS. -// -//go:nosplit -func bulkBarrierBitmap(dst, src, size, maskOffset uintptr, bits *uint8) { - word := maskOffset / goarch.PtrSize - bits = addb(bits, word/8) - mask := uint8(1) << (word % 8) - - buf := &getg().m.p.ptr().wbBuf - for i := uintptr(0); i < size; i += goarch.PtrSize { - if mask == 0 { - bits = addb(bits, 1) - if *bits == 0 { - // Skip 8 words. - i += 7 * goarch.PtrSize - continue - } - mask = 1 - } - if *bits&mask != 0 { - dstx := (*uintptr)(unsafe.Pointer(dst + i)) - if src == 0 { - p := buf.get1() - p[0] = *dstx - } else { - srcx := (*uintptr)(unsafe.Pointer(src + i)) - p := buf.get2() - p[0] = *dstx - p[1] = *srcx - } - } - mask <<= 1 - } -} - -// typeBitsBulkBarrier executes a write barrier for every -// pointer that would be copied from [src, src+size) to [dst, -// dst+size) by a memmove using the type bitmap to locate those -// pointer slots. -// -// The type typ must correspond exactly to [src, src+size) and [dst, dst+size). -// dst, src, and size must be pointer-aligned. -// The type typ must have a plain bitmap, not a GC program. -// The only use of this function is in channel sends, and the -// 64 kB channel element limit takes care of this for us. -// -// Must not be preempted because it typically runs right before memmove, -// and the GC must observe them as an atomic action. -// -// Callers must perform cgo checks if goexperiment.CgoCheck2. -// -//go:nosplit -func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) { - if typ == nil { - throw("runtime: typeBitsBulkBarrier without type") - } - if typ.Size_ != size { - println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " of size ", typ.Size_, " but memory size", size) - throw("runtime: invalid typeBitsBulkBarrier") - } - if typ.Kind_&kindGCProg != 0 { - println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " with GC prog") - throw("runtime: invalid typeBitsBulkBarrier") - } - if !writeBarrier.enabled { - return - } - ptrmask := typ.GCData - buf := &getg().m.p.ptr().wbBuf - var bits uint32 - for i := uintptr(0); i < typ.PtrBytes; i += goarch.PtrSize { - if i&(goarch.PtrSize*8-1) == 0 { - bits = uint32(*ptrmask) - ptrmask = addb(ptrmask, 1) - } else { - bits = bits >> 1 - } - if bits&1 != 0 { - dstx := (*uintptr)(unsafe.Pointer(dst + i)) - srcx := (*uintptr)(unsafe.Pointer(src + i)) - p := buf.get2() - p[0] = *dstx - p[1] = *srcx - } - } -} - -// countAlloc returns the number of objects allocated in span s by -// scanning the mark bitmap. -func (s *mspan) countAlloc() int { - count := 0 - bytes := divRoundUp(uintptr(s.nelems), 8) - // Iterate over each 8-byte chunk and count allocations - // with an intrinsic. Note that newMarkBits guarantees that - // gcmarkBits will be 8-byte aligned, so we don't have to - // worry about edge cases, irrelevant bits will simply be zero. - for i := uintptr(0); i < bytes; i += 8 { - // Extract 64 bits from the byte pointer and get a OnesCount. - // Note that the unsafe cast here doesn't preserve endianness, - // but that's OK. We only care about how many bits are 1, not - // about the order we discover them in. - mrkBits := *(*uint64)(unsafe.Pointer(s.gcmarkBits.bytep(i))) - count += sys.OnesCount64(mrkBits) - } - return count -} - -// Read the bytes starting at the aligned pointer p into a uintptr. -// Read is little-endian. -func readUintptr(p *byte) uintptr { - x := *(*uintptr)(unsafe.Pointer(p)) - if goarch.BigEndian { - if goarch.PtrSize == 8 { - return uintptr(sys.Bswap64(uint64(x))) - } - return uintptr(sys.Bswap32(uint32(x))) - } - return x -} - -var debugPtrmask struct { - lock mutex - data *byte -} - -// progToPointerMask returns the 1-bit pointer mask output by the GC program prog. -// size the size of the region described by prog, in bytes. -// The resulting bitvector will have no more than size/goarch.PtrSize bits. -func progToPointerMask(prog *byte, size uintptr) bitvector { - n := (size/goarch.PtrSize + 7) / 8 - x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1] - x[len(x)-1] = 0xa1 // overflow check sentinel - n = runGCProg(prog, &x[0]) - if x[len(x)-1] != 0xa1 { - throw("progToPointerMask: overflow") - } - return bitvector{int32(n), &x[0]} -} - -// Packed GC pointer bitmaps, aka GC programs. -// -// For large types containing arrays, the type information has a -// natural repetition that can be encoded to save space in the -// binary and in the memory representation of the type information. -// -// The encoding is a simple Lempel-Ziv style bytecode machine -// with the following instructions: -// -// 00000000: stop -// 0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes -// 10000000 n c: repeat the previous n bits c times; n, c are varints -// 1nnnnnnn c: repeat the previous n bits c times; c is a varint - -// runGCProg returns the number of 1-bit entries written to memory. -func runGCProg(prog, dst *byte) uintptr { - dstStart := dst - - // Bits waiting to be written to memory. - var bits uintptr - var nbits uintptr - - p := prog -Run: - for { - // Flush accumulated full bytes. - // The rest of the loop assumes that nbits <= 7. - for ; nbits >= 8; nbits -= 8 { - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - } - - // Process one instruction. - inst := uintptr(*p) - p = add1(p) - n := inst & 0x7F - if inst&0x80 == 0 { - // Literal bits; n == 0 means end of program. - if n == 0 { - // Program is over. - break Run - } - nbyte := n / 8 - for i := uintptr(0); i < nbyte; i++ { - bits |= uintptr(*p) << nbits - p = add1(p) - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - } - if n %= 8; n > 0 { - bits |= uintptr(*p) << nbits - p = add1(p) - nbits += n - } - continue Run - } - - // Repeat. If n == 0, it is encoded in a varint in the next bytes. - if n == 0 { - for off := uint(0); ; off += 7 { - x := uintptr(*p) - p = add1(p) - n |= (x & 0x7F) << off - if x&0x80 == 0 { - break - } - } - } - - // Count is encoded in a varint in the next bytes. - c := uintptr(0) - for off := uint(0); ; off += 7 { - x := uintptr(*p) - p = add1(p) - c |= (x & 0x7F) << off - if x&0x80 == 0 { - break - } - } - c *= n // now total number of bits to copy - - // If the number of bits being repeated is small, load them - // into a register and use that register for the entire loop - // instead of repeatedly reading from memory. - // Handling fewer than 8 bits here makes the general loop simpler. - // The cutoff is goarch.PtrSize*8 - 7 to guarantee that when we add - // the pattern to a bit buffer holding at most 7 bits (a partial byte) - // it will not overflow. - src := dst - const maxBits = goarch.PtrSize*8 - 7 - if n <= maxBits { - // Start with bits in output buffer. - pattern := bits - npattern := nbits - - // If we need more bits, fetch them from memory. - src = subtract1(src) - for npattern < n { - pattern <<= 8 - pattern |= uintptr(*src) - src = subtract1(src) - npattern += 8 - } - - // We started with the whole bit output buffer, - // and then we loaded bits from whole bytes. - // Either way, we might now have too many instead of too few. - // Discard the extra. - if npattern > n { - pattern >>= npattern - n - npattern = n - } - - // Replicate pattern to at most maxBits. - if npattern == 1 { - // One bit being repeated. - // If the bit is 1, make the pattern all 1s. - // If the bit is 0, the pattern is already all 0s, - // but we can claim that the number of bits - // in the word is equal to the number we need (c), - // because right shift of bits will zero fill. - if pattern == 1 { - pattern = 1<8 bits, there will be full bytes to flush - // on each iteration. - for ; c >= npattern; c -= npattern { - bits |= pattern << nbits - nbits += npattern - for nbits >= 8 { - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - nbits -= 8 - } - } - - // Add final fragment to bit buffer. - if c > 0 { - pattern &= 1< nbits because n > maxBits and nbits <= 7 - // Leading src fragment. - src = subtractb(src, (off+7)/8) - if frag := off & 7; frag != 0 { - bits |= uintptr(*src) >> (8 - frag) << nbits - src = add1(src) - nbits += frag - c -= frag - } - // Main loop: load one byte, write another. - // The bits are rotating through the bit buffer. - for i := c / 8; i > 0; i-- { - bits |= uintptr(*src) << nbits - src = add1(src) - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - } - // Final src fragment. - if c %= 8; c > 0 { - bits |= (uintptr(*src) & (1< 0; nbits -= 8 { - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - } - return totalBits -} - -// materializeGCProg allocates space for the (1-bit) pointer bitmask -// for an object of size ptrdata. Then it fills that space with the -// pointer bitmask specified by the program prog. -// The bitmask starts at s.startAddr. -// The result must be deallocated with dematerializeGCProg. -func materializeGCProg(ptrdata uintptr, prog *byte) *mspan { - // Each word of ptrdata needs one bit in the bitmap. - bitmapBytes := divRoundUp(ptrdata, 8*goarch.PtrSize) - // Compute the number of pages needed for bitmapBytes. - pages := divRoundUp(bitmapBytes, pageSize) - s := mheap_.allocManual(pages, spanAllocPtrScalarBits) - runGCProg(addb(prog, 4), (*byte)(unsafe.Pointer(s.startAddr))) - return s -} -func dematerializeGCProg(s *mspan) { - mheap_.freeManual(s, spanAllocPtrScalarBits) -} - -func dumpGCProg(p *byte) { - nptr := 0 - for { - x := *p - p = add1(p) - if x == 0 { - print("\t", nptr, " end\n") - break - } - if x&0x80 == 0 { - print("\t", nptr, " lit ", x, ":") - n := int(x+7) / 8 - for i := 0; i < n; i++ { - print(" ", hex(*p)) - p = add1(p) - } - print("\n") - nptr += int(x) - } else { - nbit := int(x &^ 0x80) - if nbit == 0 { - for nb := uint(0); ; nb += 7 { - x := *p - p = add1(p) - nbit |= int(x&0x7f) << nb - if x&0x80 == 0 { - break - } - } - } - count := 0 - for nb := uint(0); ; nb += 7 { - x := *p - p = add1(p) - count |= int(x&0x7f) << nb - if x&0x80 == 0 { - break - } - } - print("\t", nptr, " repeat ", nbit, " × ", count, "\n") - nptr += nbit * count - } - } -} - -// Testing. - -// reflect_gcbits returns the GC type info for x, for testing. -// The result is the bitmap entries (0 or 1), one entry per byte. -// -//go:linkname reflect_gcbits reflect.gcbits -func reflect_gcbits(x any) []byte { - return getgcmask(x) -} diff --git a/contrib/go/_std_1.22/src/runtime/mbitmap_allocheaders.go b/contrib/go/_std_1.22/src/runtime/mbitmap_allocheaders.go deleted file mode 100644 index 1ec055352e78..000000000000 --- a/contrib/go/_std_1.22/src/runtime/mbitmap_allocheaders.go +++ /dev/null @@ -1,1376 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.allocheaders - -// Garbage collector: type and heap bitmaps. -// -// Stack, data, and bss bitmaps -// -// Stack frames and global variables in the data and bss sections are -// described by bitmaps with 1 bit per pointer-sized word. A "1" bit -// means the word is a live pointer to be visited by the GC (referred to -// as "pointer"). A "0" bit means the word should be ignored by GC -// (referred to as "scalar", though it could be a dead pointer value). -// -// Heap bitmaps -// -// The heap bitmap comprises 1 bit for each pointer-sized word in the heap, -// recording whether a pointer is stored in that word or not. This bitmap -// is stored at the end of a span for small objects and is unrolled at -// runtime from type metadata for all larger objects. Objects without -// pointers have neither a bitmap nor associated type metadata. -// -// Bits in all cases correspond to words in little-endian order. -// -// For small objects, if s is the mspan for the span starting at "start", -// then s.heapBits() returns a slice containing the bitmap for the whole span. -// That is, s.heapBits()[0] holds the goarch.PtrSize*8 bits for the first -// goarch.PtrSize*8 words from "start" through "start+63*ptrSize" in the span. -// On a related note, small objects are always small enough that their bitmap -// fits in goarch.PtrSize*8 bits, so writing out bitmap data takes two bitmap -// writes at most (because object boundaries don't generally lie on -// s.heapBits()[i] boundaries). -// -// For larger objects, if t is the type for the object starting at "start", -// within some span whose mspan is s, then the bitmap at t.GCData is "tiled" -// from "start" through "start+s.elemsize". -// Specifically, the first bit of t.GCData corresponds to the word at "start", -// the second to the word after "start", and so on up to t.PtrBytes. At t.PtrBytes, -// we skip to "start+t.Size_" and begin again from there. This process is -// repeated until we hit "start+s.elemsize". -// This tiling algorithm supports array data, since the type always refers to -// the element type of the array. Single objects are considered the same as -// single-element arrays. -// The tiling algorithm may scan data past the end of the compiler-recognized -// object, but any unused data within the allocation slot (i.e. within s.elemsize) -// is zeroed, so the GC just observes nil pointers. -// Note that this "tiled" bitmap isn't stored anywhere; it is generated on-the-fly. -// -// For objects without their own span, the type metadata is stored in the first -// word before the object at the beginning of the allocation slot. For objects -// with their own span, the type metadata is stored in the mspan. -// -// The bitmap for small unallocated objects in scannable spans is not maintained -// (can be junk). - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "runtime/internal/sys" - "unsafe" -) - -const ( - // A malloc header is functionally a single type pointer, but - // we need to use 8 here to ensure 8-byte alignment of allocations - // on 32-bit platforms. It's wasteful, but a lot of code relies on - // 8-byte alignment for 8-byte atomics. - mallocHeaderSize = 8 - - // The minimum object size that has a malloc header, exclusive. - // - // The size of this value controls overheads from the malloc header. - // The minimum size is bound by writeHeapBitsSmall, which assumes that the - // pointer bitmap for objects of a size smaller than this doesn't cross - // more than one pointer-word boundary. This sets an upper-bound on this - // value at the number of bits in a uintptr, multiplied by the pointer - // size in bytes. - // - // We choose a value here that has a natural cutover point in terms of memory - // overheads. This value just happens to be the maximum possible value this - // can be. - // - // A span with heap bits in it will have 128 bytes of heap bits on 64-bit - // platforms, and 256 bytes of heap bits on 32-bit platforms. The first size - // class where malloc headers match this overhead for 64-bit platforms is - // 512 bytes (8 KiB / 512 bytes * 8 bytes-per-header = 128 bytes of overhead). - // On 32-bit platforms, this same point is the 256 byte size class - // (8 KiB / 256 bytes * 8 bytes-per-header = 256 bytes of overhead). - // - // Guaranteed to be exactly at a size class boundary. The reason this value is - // an exclusive minimum is subtle. Suppose we're allocating a 504-byte object - // and its rounded up to 512 bytes for the size class. If minSizeForMallocHeader - // is 512 and an inclusive minimum, then a comparison against minSizeForMallocHeader - // by the two values would produce different results. In other words, the comparison - // would not be invariant to size-class rounding. Eschewing this property means a - // more complex check or possibly storing additional state to determine whether a - // span has malloc headers. - minSizeForMallocHeader = goarch.PtrSize * ptrBits -) - -// heapBitsInSpan returns true if the size of an object implies its ptr/scalar -// data is stored at the end of the span, and is accessible via span.heapBits. -// -// Note: this works for both rounded-up sizes (span.elemsize) and unrounded -// type sizes because minSizeForMallocHeader is guaranteed to be at a size -// class boundary. -// -//go:nosplit -func heapBitsInSpan(userSize uintptr) bool { - // N.B. minSizeForMallocHeader is an exclusive minimum so that this function is - // invariant under size-class rounding on its input. - return userSize <= minSizeForMallocHeader -} - -// heapArenaPtrScalar contains the per-heapArena pointer/scalar metadata for the GC. -type heapArenaPtrScalar struct { - // N.B. This is no longer necessary with allocation headers. -} - -// typePointers is an iterator over the pointers in a heap object. -// -// Iteration through this type implements the tiling algorithm described at the -// top of this file. -type typePointers struct { - // elem is the address of the current array element of type typ being iterated over. - // Objects that are not arrays are treated as single-element arrays, in which case - // this value does not change. - elem uintptr - - // addr is the address the iterator is currently working from and describes - // the address of the first word referenced by mask. - addr uintptr - - // mask is a bitmask where each bit corresponds to pointer-words after addr. - // Bit 0 is the pointer-word at addr, Bit 1 is the next word, and so on. - // If a bit is 1, then there is a pointer at that word. - // nextFast and next mask out bits in this mask as their pointers are processed. - mask uintptr - - // typ is a pointer to the type information for the heap object's type. - // This may be nil if the object is in a span where heapBitsInSpan(span.elemsize) is true. - typ *_type -} - -// typePointersOf returns an iterator over all heap pointers in the range [addr, addr+size). -// -// addr and addr+size must be in the range [span.base(), span.limit). -// -// Note: addr+size must be passed as the limit argument to the iterator's next method on -// each iteration. This slightly awkward API is to allow typePointers to be destructured -// by the compiler. -// -// nosplit because it is used during write barriers and must not be preempted. -// -//go:nosplit -func (span *mspan) typePointersOf(addr, size uintptr) typePointers { - base := span.objBase(addr) - tp := span.typePointersOfUnchecked(base) - if base == addr && size == span.elemsize { - return tp - } - return tp.fastForward(addr-tp.addr, addr+size) -} - -// typePointersOfUnchecked is like typePointersOf, but assumes addr is the base -// of an allocation slot in a span (the start of the object if no header, the -// header otherwise). It returns an iterator that generates all pointers -// in the range [addr, addr+span.elemsize). -// -// nosplit because it is used during write barriers and must not be preempted. -// -//go:nosplit -func (span *mspan) typePointersOfUnchecked(addr uintptr) typePointers { - const doubleCheck = false - if doubleCheck && span.objBase(addr) != addr { - print("runtime: addr=", addr, " base=", span.objBase(addr), "\n") - throw("typePointersOfUnchecked consisting of non-base-address for object") - } - - spc := span.spanclass - if spc.noscan() { - return typePointers{} - } - if heapBitsInSpan(span.elemsize) { - // Handle header-less objects. - return typePointers{elem: addr, addr: addr, mask: span.heapBitsSmallForAddr(addr)} - } - - // All of these objects have a header. - var typ *_type - if spc.sizeclass() != 0 { - // Pull the allocation header from the first word of the object. - typ = *(**_type)(unsafe.Pointer(addr)) - addr += mallocHeaderSize - } else { - typ = span.largeType - } - gcdata := typ.GCData - return typePointers{elem: addr, addr: addr, mask: readUintptr(gcdata), typ: typ} -} - -// typePointersOfType is like typePointersOf, but assumes addr points to one or more -// contiguous instances of the provided type. The provided type must not be nil and -// it must not have its type metadata encoded as a gcprog. -// -// It returns an iterator that tiles typ.GCData starting from addr. It's the caller's -// responsibility to limit iteration. -// -// nosplit because its callers are nosplit and require all their callees to be nosplit. -// -//go:nosplit -func (span *mspan) typePointersOfType(typ *abi.Type, addr uintptr) typePointers { - const doubleCheck = false - if doubleCheck && (typ == nil || typ.Kind_&kindGCProg != 0) { - throw("bad type passed to typePointersOfType") - } - if span.spanclass.noscan() { - return typePointers{} - } - // Since we have the type, pretend we have a header. - gcdata := typ.GCData - return typePointers{elem: addr, addr: addr, mask: readUintptr(gcdata), typ: typ} -} - -// nextFast is the fast path of next. nextFast is written to be inlineable and, -// as the name implies, fast. -// -// Callers that are performance-critical should iterate using the following -// pattern: -// -// for { -// var addr uintptr -// if tp, addr = tp.nextFast(); addr == 0 { -// if tp, addr = tp.next(limit); addr == 0 { -// break -// } -// } -// // Use addr. -// ... -// } -// -// nosplit because it is used during write barriers and must not be preempted. -// -//go:nosplit -func (tp typePointers) nextFast() (typePointers, uintptr) { - // TESTQ/JEQ - if tp.mask == 0 { - return tp, 0 - } - // BSFQ - var i int - if goarch.PtrSize == 8 { - i = sys.TrailingZeros64(uint64(tp.mask)) - } else { - i = sys.TrailingZeros32(uint32(tp.mask)) - } - // BTCQ - tp.mask ^= uintptr(1) << (i & (ptrBits - 1)) - // LEAQ (XX)(XX*8) - return tp, tp.addr + uintptr(i)*goarch.PtrSize -} - -// next advances the pointers iterator, returning the updated iterator and -// the address of the next pointer. -// -// limit must be the same each time it is passed to next. -// -// nosplit because it is used during write barriers and must not be preempted. -// -//go:nosplit -func (tp typePointers) next(limit uintptr) (typePointers, uintptr) { - for { - if tp.mask != 0 { - return tp.nextFast() - } - - // Stop if we don't actually have type information. - if tp.typ == nil { - return typePointers{}, 0 - } - - // Advance to the next element if necessary. - if tp.addr+goarch.PtrSize*ptrBits >= tp.elem+tp.typ.PtrBytes { - tp.elem += tp.typ.Size_ - tp.addr = tp.elem - } else { - tp.addr += ptrBits * goarch.PtrSize - } - - // Check if we've exceeded the limit with the last update. - if tp.addr >= limit { - return typePointers{}, 0 - } - - // Grab more bits and try again. - tp.mask = readUintptr(addb(tp.typ.GCData, (tp.addr-tp.elem)/goarch.PtrSize/8)) - if tp.addr+goarch.PtrSize*ptrBits > limit { - bits := (tp.addr + goarch.PtrSize*ptrBits - limit) / goarch.PtrSize - tp.mask &^= ((1 << (bits)) - 1) << (ptrBits - bits) - } - } -} - -// fastForward moves the iterator forward by n bytes. n must be a multiple -// of goarch.PtrSize. limit must be the same limit passed to next for this -// iterator. -// -// nosplit because it is used during write barriers and must not be preempted. -// -//go:nosplit -func (tp typePointers) fastForward(n, limit uintptr) typePointers { - // Basic bounds check. - target := tp.addr + n - if target >= limit { - return typePointers{} - } - if tp.typ == nil { - // Handle small objects. - // Clear any bits before the target address. - tp.mask &^= (1 << ((target - tp.addr) / goarch.PtrSize)) - 1 - // Clear any bits past the limit. - if tp.addr+goarch.PtrSize*ptrBits > limit { - bits := (tp.addr + goarch.PtrSize*ptrBits - limit) / goarch.PtrSize - tp.mask &^= ((1 << (bits)) - 1) << (ptrBits - bits) - } - return tp - } - - // Move up elem and addr. - // Offsets within an element are always at a ptrBits*goarch.PtrSize boundary. - if n >= tp.typ.Size_ { - // elem needs to be moved to the element containing - // tp.addr + n. - oldelem := tp.elem - tp.elem += (tp.addr - tp.elem + n) / tp.typ.Size_ * tp.typ.Size_ - tp.addr = tp.elem + alignDown(n-(tp.elem-oldelem), ptrBits*goarch.PtrSize) - } else { - tp.addr += alignDown(n, ptrBits*goarch.PtrSize) - } - - if tp.addr-tp.elem >= tp.typ.PtrBytes { - // We're starting in the non-pointer area of an array. - // Move up to the next element. - tp.elem += tp.typ.Size_ - tp.addr = tp.elem - tp.mask = readUintptr(tp.typ.GCData) - - // We may have exceeded the limit after this. Bail just like next does. - if tp.addr >= limit { - return typePointers{} - } - } else { - // Grab the mask, but then clear any bits before the target address and any - // bits over the limit. - tp.mask = readUintptr(addb(tp.typ.GCData, (tp.addr-tp.elem)/goarch.PtrSize/8)) - tp.mask &^= (1 << ((target - tp.addr) / goarch.PtrSize)) - 1 - } - if tp.addr+goarch.PtrSize*ptrBits > limit { - bits := (tp.addr + goarch.PtrSize*ptrBits - limit) / goarch.PtrSize - tp.mask &^= ((1 << (bits)) - 1) << (ptrBits - bits) - } - return tp -} - -// objBase returns the base pointer for the object containing addr in span. -// -// Assumes that addr points into a valid part of span (span.base() <= addr < span.limit). -// -//go:nosplit -func (span *mspan) objBase(addr uintptr) uintptr { - return span.base() + span.objIndex(addr)*span.elemsize -} - -// bulkBarrierPreWrite executes a write barrier -// for every pointer slot in the memory range [src, src+size), -// using pointer/scalar information from [dst, dst+size). -// This executes the write barriers necessary before a memmove. -// src, dst, and size must be pointer-aligned. -// The range [dst, dst+size) must lie within a single object. -// It does not perform the actual writes. -// -// As a special case, src == 0 indicates that this is being used for a -// memclr. bulkBarrierPreWrite will pass 0 for the src of each write -// barrier. -// -// Callers should call bulkBarrierPreWrite immediately before -// calling memmove(dst, src, size). This function is marked nosplit -// to avoid being preempted; the GC must not stop the goroutine -// between the memmove and the execution of the barriers. -// The caller is also responsible for cgo pointer checks if this -// may be writing Go pointers into non-Go memory. -// -// Pointer data is not maintained for allocations containing -// no pointers at all; any caller of bulkBarrierPreWrite must first -// make sure the underlying allocation contains pointers, usually -// by checking typ.PtrBytes. -// -// The typ argument is the type of the space at src and dst (and the -// element type if src and dst refer to arrays) and it is optional. -// If typ is nil, the barrier will still behave as expected and typ -// is used purely as an optimization. However, it must be used with -// care. -// -// If typ is not nil, then src and dst must point to one or more values -// of type typ. The caller must ensure that the ranges [src, src+size) -// and [dst, dst+size) refer to one or more whole values of type src and -// dst (leaving off the pointerless tail of the space is OK). If this -// precondition is not followed, this function will fail to scan the -// right pointers. -// -// When in doubt, pass nil for typ. That is safe and will always work. -// -// Callers must perform cgo checks if goexperiment.CgoCheck2. -// -//go:nosplit -func bulkBarrierPreWrite(dst, src, size uintptr, typ *abi.Type) { - if (dst|src|size)&(goarch.PtrSize-1) != 0 { - throw("bulkBarrierPreWrite: unaligned arguments") - } - if !writeBarrier.enabled { - return - } - s := spanOf(dst) - if s == nil { - // If dst is a global, use the data or BSS bitmaps to - // execute write barriers. - for _, datap := range activeModules() { - if datap.data <= dst && dst < datap.edata { - bulkBarrierBitmap(dst, src, size, dst-datap.data, datap.gcdatamask.bytedata) - return - } - } - for _, datap := range activeModules() { - if datap.bss <= dst && dst < datap.ebss { - bulkBarrierBitmap(dst, src, size, dst-datap.bss, datap.gcbssmask.bytedata) - return - } - } - return - } else if s.state.get() != mSpanInUse || dst < s.base() || s.limit <= dst { - // dst was heap memory at some point, but isn't now. - // It can't be a global. It must be either our stack, - // or in the case of direct channel sends, it could be - // another stack. Either way, no need for barriers. - // This will also catch if dst is in a freed span, - // though that should never have. - return - } - buf := &getg().m.p.ptr().wbBuf - - // Double-check that the bitmaps generated in the two possible paths match. - const doubleCheck = false - if doubleCheck { - doubleCheckTypePointersOfType(s, typ, dst, size) - } - - var tp typePointers - if typ != nil && typ.Kind_&kindGCProg == 0 { - tp = s.typePointersOfType(typ, dst) - } else { - tp = s.typePointersOf(dst, size) - } - if src == 0 { - for { - var addr uintptr - if tp, addr = tp.next(dst + size); addr == 0 { - break - } - dstx := (*uintptr)(unsafe.Pointer(addr)) - p := buf.get1() - p[0] = *dstx - } - } else { - for { - var addr uintptr - if tp, addr = tp.next(dst + size); addr == 0 { - break - } - dstx := (*uintptr)(unsafe.Pointer(addr)) - srcx := (*uintptr)(unsafe.Pointer(src + (addr - dst))) - p := buf.get2() - p[0] = *dstx - p[1] = *srcx - } - } -} - -// bulkBarrierPreWriteSrcOnly is like bulkBarrierPreWrite but -// does not execute write barriers for [dst, dst+size). -// -// In addition to the requirements of bulkBarrierPreWrite -// callers need to ensure [dst, dst+size) is zeroed. -// -// This is used for special cases where e.g. dst was just -// created and zeroed with malloc. -// -// The type of the space can be provided purely as an optimization. -// See bulkBarrierPreWrite's comment for more details -- use this -// optimization with great care. -// -//go:nosplit -func bulkBarrierPreWriteSrcOnly(dst, src, size uintptr, typ *abi.Type) { - if (dst|src|size)&(goarch.PtrSize-1) != 0 { - throw("bulkBarrierPreWrite: unaligned arguments") - } - if !writeBarrier.enabled { - return - } - buf := &getg().m.p.ptr().wbBuf - s := spanOf(dst) - - // Double-check that the bitmaps generated in the two possible paths match. - const doubleCheck = false - if doubleCheck { - doubleCheckTypePointersOfType(s, typ, dst, size) - } - - var tp typePointers - if typ != nil && typ.Kind_&kindGCProg == 0 { - tp = s.typePointersOfType(typ, dst) - } else { - tp = s.typePointersOf(dst, size) - } - for { - var addr uintptr - if tp, addr = tp.next(dst + size); addr == 0 { - break - } - srcx := (*uintptr)(unsafe.Pointer(addr - dst + src)) - p := buf.get1() - p[0] = *srcx - } -} - -// initHeapBits initializes the heap bitmap for a span. -// -// TODO(mknyszek): This should set the heap bits for single pointer -// allocations eagerly to avoid calling heapSetType at allocation time, -// just to write one bit. -func (s *mspan) initHeapBits(forceClear bool) { - if (!s.spanclass.noscan() && heapBitsInSpan(s.elemsize)) || s.isUserArenaChunk { - b := s.heapBits() - for i := range b { - b[i] = 0 - } - } -} - -// bswapIfBigEndian swaps the byte order of the uintptr on goarch.BigEndian platforms, -// and leaves it alone elsewhere. -func bswapIfBigEndian(x uintptr) uintptr { - if goarch.BigEndian { - if goarch.PtrSize == 8 { - return uintptr(sys.Bswap64(uint64(x))) - } - return uintptr(sys.Bswap32(uint32(x))) - } - return x -} - -type writeUserArenaHeapBits struct { - offset uintptr // offset in span that the low bit of mask represents the pointer state of. - mask uintptr // some pointer bits starting at the address addr. - valid uintptr // number of bits in buf that are valid (including low) - low uintptr // number of low-order bits to not overwrite -} - -func (s *mspan) writeUserArenaHeapBits(addr uintptr) (h writeUserArenaHeapBits) { - offset := addr - s.base() - - // We start writing bits maybe in the middle of a heap bitmap word. - // Remember how many bits into the word we started, so we can be sure - // not to overwrite the previous bits. - h.low = offset / goarch.PtrSize % ptrBits - - // round down to heap word that starts the bitmap word. - h.offset = offset - h.low*goarch.PtrSize - - // We don't have any bits yet. - h.mask = 0 - h.valid = h.low - - return -} - -// write appends the pointerness of the next valid pointer slots -// using the low valid bits of bits. 1=pointer, 0=scalar. -func (h writeUserArenaHeapBits) write(s *mspan, bits, valid uintptr) writeUserArenaHeapBits { - if h.valid+valid <= ptrBits { - // Fast path - just accumulate the bits. - h.mask |= bits << h.valid - h.valid += valid - return h - } - // Too many bits to fit in this word. Write the current word - // out and move on to the next word. - - data := h.mask | bits<> (ptrBits - h.valid) // leftover for next word - h.valid += valid - ptrBits // have h.valid+valid bits, writing ptrBits of them - - // Flush mask to the memory bitmap. - idx := h.offset / (ptrBits * goarch.PtrSize) - m := uintptr(1)< ptrBits { - h = h.write(s, 0, ptrBits) - words -= ptrBits - } - return h.write(s, 0, words) -} - -// Flush the bits that have been written, and add zeros as needed -// to cover the full object [addr, addr+size). -func (h writeUserArenaHeapBits) flush(s *mspan, addr, size uintptr) { - offset := addr - s.base() - - // zeros counts the number of bits needed to represent the object minus the - // number of bits we've already written. This is the number of 0 bits - // that need to be added. - zeros := (offset+size-h.offset)/goarch.PtrSize - h.valid - - // Add zero bits up to the bitmap word boundary - if zeros > 0 { - z := ptrBits - h.valid - if z > zeros { - z = zeros - } - h.valid += z - zeros -= z - } - - // Find word in bitmap that we're going to write. - bitmap := s.heapBits() - idx := h.offset / (ptrBits * goarch.PtrSize) - - // Write remaining bits. - if h.valid != h.low { - m := uintptr(1)< minSizeForMallocHeader { - throw("heapBits called for span class that should have a malloc header") - } - } - // Find the bitmap at the end of the span. - // - // Nearly every span with heap bits is exactly one page in size. Arenas are the only exception. - if span.npages == 1 { - // This will be inlined and constant-folded down. - return heapBitsSlice(span.base(), pageSize) - } - return heapBitsSlice(span.base(), span.npages*pageSize) -} - -// Helper for constructing a slice for the span's heap bits. -// -//go:nosplit -func heapBitsSlice(spanBase, spanSize uintptr) []uintptr { - bitmapSize := spanSize / goarch.PtrSize / 8 - elems := int(bitmapSize / goarch.PtrSize) - var sl notInHeapSlice - sl = notInHeapSlice{(*notInHeap)(unsafe.Pointer(spanBase + spanSize - bitmapSize)), elems, elems} - return *(*[]uintptr)(unsafe.Pointer(&sl)) -} - -// heapBitsSmallForAddr loads the heap bits for the object stored at addr from span.heapBits. -// -// addr must be the base pointer of an object in the span. heapBitsInSpan(span.elemsize) -// must be true. -// -//go:nosplit -func (span *mspan) heapBitsSmallForAddr(addr uintptr) uintptr { - spanSize := span.npages * pageSize - bitmapSize := spanSize / goarch.PtrSize / 8 - hbits := (*byte)(unsafe.Pointer(span.base() + spanSize - bitmapSize)) - - // These objects are always small enough that their bitmaps - // fit in a single word, so just load the word or two we need. - // - // Mirrors mspan.writeHeapBitsSmall. - // - // We should be using heapBits(), but unfortunately it introduces - // both bounds checks panics and throw which causes us to exceed - // the nosplit limit in quite a few cases. - i := (addr - span.base()) / goarch.PtrSize / ptrBits - j := (addr - span.base()) / goarch.PtrSize % ptrBits - bits := span.elemsize / goarch.PtrSize - word0 := (*uintptr)(unsafe.Pointer(addb(hbits, goarch.PtrSize*(i+0)))) - word1 := (*uintptr)(unsafe.Pointer(addb(hbits, goarch.PtrSize*(i+1)))) - - var read uintptr - if j+bits > ptrBits { - // Two reads. - bits0 := ptrBits - j - bits1 := bits - bits0 - read = *word0 >> j - read |= (*word1 & ((1 << bits1) - 1)) << bits0 - } else { - // One read. - read = (*word0 >> j) & ((1 << bits) - 1) - } - return read -} - -// writeHeapBitsSmall writes the heap bits for small objects whose ptr/scalar data is -// stored as a bitmap at the end of the span. -// -// Assumes dataSize is <= ptrBits*goarch.PtrSize. x must be a pointer into the span. -// heapBitsInSpan(dataSize) must be true. dataSize must be >= typ.Size_. -// -//go:nosplit -func (span *mspan) writeHeapBitsSmall(x, dataSize uintptr, typ *_type) (scanSize uintptr) { - // The objects here are always really small, so a single load is sufficient. - src0 := readUintptr(typ.GCData) - - // Create repetitions of the bitmap if we have a small array. - bits := span.elemsize / goarch.PtrSize - scanSize = typ.PtrBytes - src := src0 - switch typ.Size_ { - case goarch.PtrSize: - src = (1 << (dataSize / goarch.PtrSize)) - 1 - default: - for i := typ.Size_; i < dataSize; i += typ.Size_ { - src |= src0 << (i / goarch.PtrSize) - scanSize += typ.Size_ - } - } - - // Since we're never writing more than one uintptr's worth of bits, we're either going - // to do one or two writes. - dst := span.heapBits() - o := (x - span.base()) / goarch.PtrSize - i := o / ptrBits - j := o % ptrBits - if j+bits > ptrBits { - // Two writes. - bits0 := ptrBits - j - bits1 := bits - bits0 - dst[i+0] = dst[i+0]&(^uintptr(0)>>bits0) | (src << j) - dst[i+1] = dst[i+1]&^((1<> bits0) - } else { - // One write. - dst[i] = (dst[i] &^ (((1 << bits) - 1) << j)) | (src << j) - } - - const doubleCheck = false - if doubleCheck { - srcRead := span.heapBitsSmallForAddr(x) - if srcRead != src { - print("runtime: x=", hex(x), " i=", i, " j=", j, " bits=", bits, "\n") - print("runtime: dataSize=", dataSize, " typ.Size_=", typ.Size_, " typ.PtrBytes=", typ.PtrBytes, "\n") - print("runtime: src0=", hex(src0), " src=", hex(src), " srcRead=", hex(srcRead), "\n") - throw("bad pointer bits written for small object") - } - } - return -} - -// For !goexperiment.AllocHeaders. -func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { -} - -// heapSetType records that the new allocation [x, x+size) -// holds in [x, x+dataSize) one or more values of type typ. -// (The number of values is given by dataSize / typ.Size.) -// If dataSize < size, the fragment [x+dataSize, x+size) is -// recorded as non-pointer data. -// It is known that the type has pointers somewhere; -// malloc does not call heapSetType when there are no pointers. -// -// There can be read-write races between heapSetType and things -// that read the heap metadata like scanobject. However, since -// heapSetType is only used for objects that have not yet been -// made reachable, readers will ignore bits being modified by this -// function. This does mean this function cannot transiently modify -// shared memory that belongs to neighboring objects. Also, on weakly-ordered -// machines, callers must execute a store/store (publication) barrier -// between calling this function and making the object reachable. -func heapSetType(x, dataSize uintptr, typ *_type, header **_type, span *mspan) (scanSize uintptr) { - const doubleCheck = false - - gctyp := typ - if header == nil { - if doubleCheck && (!heapBitsInSpan(dataSize) || !heapBitsInSpan(span.elemsize)) { - throw("tried to write heap bits, but no heap bits in span") - } - // Handle the case where we have no malloc header. - scanSize = span.writeHeapBitsSmall(x, dataSize, typ) - } else { - if typ.Kind_&kindGCProg != 0 { - // Allocate space to unroll the gcprog. This space will consist of - // a dummy _type value and the unrolled gcprog. The dummy _type will - // refer to the bitmap, and the mspan will refer to the dummy _type. - if span.spanclass.sizeclass() != 0 { - throw("GCProg for type that isn't large") - } - spaceNeeded := alignUp(unsafe.Sizeof(_type{}), goarch.PtrSize) - heapBitsOff := spaceNeeded - spaceNeeded += alignUp(typ.PtrBytes/goarch.PtrSize/8, goarch.PtrSize) - npages := alignUp(spaceNeeded, pageSize) / pageSize - var progSpan *mspan - systemstack(func() { - progSpan = mheap_.allocManual(npages, spanAllocPtrScalarBits) - memclrNoHeapPointers(unsafe.Pointer(progSpan.base()), progSpan.npages*pageSize) - }) - // Write a dummy _type in the new space. - // - // We only need to write size, PtrBytes, and GCData, since that's all - // the GC cares about. - gctyp = (*_type)(unsafe.Pointer(progSpan.base())) - gctyp.Size_ = typ.Size_ - gctyp.PtrBytes = typ.PtrBytes - gctyp.GCData = (*byte)(add(unsafe.Pointer(progSpan.base()), heapBitsOff)) - gctyp.TFlag = abi.TFlagUnrolledBitmap - - // Expand the GC program into space reserved at the end of the new span. - runGCProg(addb(typ.GCData, 4), gctyp.GCData) - } - - // Write out the header. - *header = gctyp - scanSize = span.elemsize - } - - if doubleCheck { - doubleCheckHeapPointers(x, dataSize, gctyp, header, span) - - // To exercise the less common path more often, generate - // a random interior pointer and make sure iterating from - // that point works correctly too. - maxIterBytes := span.elemsize - if header == nil { - maxIterBytes = dataSize - } - off := alignUp(uintptr(cheaprand())%dataSize, goarch.PtrSize) - size := dataSize - off - if size == 0 { - off -= goarch.PtrSize - size += goarch.PtrSize - } - interior := x + off - size -= alignDown(uintptr(cheaprand())%size, goarch.PtrSize) - if size == 0 { - size = goarch.PtrSize - } - // Round up the type to the size of the type. - size = (size + gctyp.Size_ - 1) / gctyp.Size_ * gctyp.Size_ - if interior+size > x+maxIterBytes { - size = x + maxIterBytes - interior - } - doubleCheckHeapPointersInterior(x, interior, size, dataSize, gctyp, header, span) - } - return -} - -func doubleCheckHeapPointers(x, dataSize uintptr, typ *_type, header **_type, span *mspan) { - // Check that scanning the full object works. - tp := span.typePointersOfUnchecked(span.objBase(x)) - maxIterBytes := span.elemsize - if header == nil { - maxIterBytes = dataSize - } - bad := false - for i := uintptr(0); i < maxIterBytes; i += goarch.PtrSize { - // Compute the pointer bit we want at offset i. - want := false - if i < span.elemsize { - off := i % typ.Size_ - if off < typ.PtrBytes { - j := off / goarch.PtrSize - want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 - } - } - if want { - var addr uintptr - tp, addr = tp.next(x + span.elemsize) - if addr == 0 { - println("runtime: found bad iterator") - } - if addr != x+i { - print("runtime: addr=", hex(addr), " x+i=", hex(x+i), "\n") - bad = true - } - } - } - if !bad { - var addr uintptr - tp, addr = tp.next(x + span.elemsize) - if addr == 0 { - return - } - println("runtime: extra pointer:", hex(addr)) - } - print("runtime: hasHeader=", header != nil, " typ.Size_=", typ.Size_, " hasGCProg=", typ.Kind_&kindGCProg != 0, "\n") - print("runtime: x=", hex(x), " dataSize=", dataSize, " elemsize=", span.elemsize, "\n") - print("runtime: typ=", unsafe.Pointer(typ), " typ.PtrBytes=", typ.PtrBytes, "\n") - print("runtime: limit=", hex(x+span.elemsize), "\n") - tp = span.typePointersOfUnchecked(x) - dumpTypePointers(tp) - for { - var addr uintptr - if tp, addr = tp.next(x + span.elemsize); addr == 0 { - println("runtime: would've stopped here") - dumpTypePointers(tp) - break - } - print("runtime: addr=", hex(addr), "\n") - dumpTypePointers(tp) - } - throw("heapSetType: pointer entry not correct") -} - -func doubleCheckHeapPointersInterior(x, interior, size, dataSize uintptr, typ *_type, header **_type, span *mspan) { - bad := false - if interior < x { - print("runtime: interior=", hex(interior), " x=", hex(x), "\n") - throw("found bad interior pointer") - } - off := interior - x - tp := span.typePointersOf(interior, size) - for i := off; i < off+size; i += goarch.PtrSize { - // Compute the pointer bit we want at offset i. - want := false - if i < span.elemsize { - off := i % typ.Size_ - if off < typ.PtrBytes { - j := off / goarch.PtrSize - want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 - } - } - if want { - var addr uintptr - tp, addr = tp.next(interior + size) - if addr == 0 { - println("runtime: found bad iterator") - bad = true - } - if addr != x+i { - print("runtime: addr=", hex(addr), " x+i=", hex(x+i), "\n") - bad = true - } - } - } - if !bad { - var addr uintptr - tp, addr = tp.next(interior + size) - if addr == 0 { - return - } - println("runtime: extra pointer:", hex(addr)) - } - print("runtime: hasHeader=", header != nil, " typ.Size_=", typ.Size_, "\n") - print("runtime: x=", hex(x), " dataSize=", dataSize, " elemsize=", span.elemsize, " interior=", hex(interior), " size=", size, "\n") - print("runtime: limit=", hex(interior+size), "\n") - tp = span.typePointersOf(interior, size) - dumpTypePointers(tp) - for { - var addr uintptr - if tp, addr = tp.next(interior + size); addr == 0 { - println("runtime: would've stopped here") - dumpTypePointers(tp) - break - } - print("runtime: addr=", hex(addr), "\n") - dumpTypePointers(tp) - } - - print("runtime: want: ") - for i := off; i < off+size; i += goarch.PtrSize { - // Compute the pointer bit we want at offset i. - want := false - if i < dataSize { - off := i % typ.Size_ - if off < typ.PtrBytes { - j := off / goarch.PtrSize - want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 - } - } - if want { - print("1") - } else { - print("0") - } - } - println() - - throw("heapSetType: pointer entry not correct") -} - -//go:nosplit -func doubleCheckTypePointersOfType(s *mspan, typ *_type, addr, size uintptr) { - if typ == nil || typ.Kind_&kindGCProg != 0 { - return - } - if typ.Kind_&kindMask == kindInterface { - // Interfaces are unfortunately inconsistently handled - // when it comes to the type pointer, so it's easy to - // produce a lot of false positives here. - return - } - tp0 := s.typePointersOfType(typ, addr) - tp1 := s.typePointersOf(addr, size) - failed := false - for { - var addr0, addr1 uintptr - tp0, addr0 = tp0.next(addr + size) - tp1, addr1 = tp1.next(addr + size) - if addr0 != addr1 { - failed = true - break - } - if addr0 == 0 { - break - } - } - if failed { - tp0 := s.typePointersOfType(typ, addr) - tp1 := s.typePointersOf(addr, size) - print("runtime: addr=", hex(addr), " size=", size, "\n") - print("runtime: type=", toRType(typ).string(), "\n") - dumpTypePointers(tp0) - dumpTypePointers(tp1) - for { - var addr0, addr1 uintptr - tp0, addr0 = tp0.next(addr + size) - tp1, addr1 = tp1.next(addr + size) - print("runtime: ", hex(addr0), " ", hex(addr1), "\n") - if addr0 == 0 && addr1 == 0 { - break - } - } - throw("mismatch between typePointersOfType and typePointersOf") - } -} - -func dumpTypePointers(tp typePointers) { - print("runtime: tp.elem=", hex(tp.elem), " tp.typ=", unsafe.Pointer(tp.typ), "\n") - print("runtime: tp.addr=", hex(tp.addr), " tp.mask=") - for i := uintptr(0); i < ptrBits; i++ { - if tp.mask&(uintptr(1)<> (off % 8)) & 1 - } - return - } - - // bss - if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss { - bitmap := datap.gcbssmask.bytedata - n := et.Size_ - mask = make([]byte, n/goarch.PtrSize) - for i := uintptr(0); i < n; i += goarch.PtrSize { - off := (uintptr(p) + i - datap.bss) / goarch.PtrSize - mask[i/goarch.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 - } - return - } - } - - // heap - if base, s, _ := findObject(uintptr(p), 0, 0); base != 0 { - if s.spanclass.noscan() { - return nil - } - limit := base + s.elemsize - - // Move the base up to the iterator's start, because - // we want to hide evidence of a malloc header from the - // caller. - tp := s.typePointersOfUnchecked(base) - base = tp.addr - - // Unroll the full bitmap the GC would actually observe. - maskFromHeap := make([]byte, (limit-base)/goarch.PtrSize) - for { - var addr uintptr - if tp, addr = tp.next(limit); addr == 0 { - break - } - maskFromHeap[(addr-base)/goarch.PtrSize] = 1 - } - - // Double-check that every part of the ptr/scalar we're not - // showing the caller is zeroed. This keeps us honest that - // that information is actually irrelevant. - for i := limit; i < s.elemsize; i++ { - if *(*byte)(unsafe.Pointer(i)) != 0 { - throw("found non-zeroed tail of allocation") - } - } - - // Callers (and a check we're about to run) expects this mask - // to end at the last pointer. - for len(maskFromHeap) > 0 && maskFromHeap[len(maskFromHeap)-1] == 0 { - maskFromHeap = maskFromHeap[:len(maskFromHeap)-1] - } - - if et.Kind_&kindGCProg == 0 { - // Unroll again, but this time from the type information. - maskFromType := make([]byte, (limit-base)/goarch.PtrSize) - tp = s.typePointersOfType(et, base) - for { - var addr uintptr - if tp, addr = tp.next(limit); addr == 0 { - break - } - maskFromType[(addr-base)/goarch.PtrSize] = 1 - } - - // Validate that the prefix of maskFromType is equal to - // maskFromHeap. maskFromType may contain more pointers than - // maskFromHeap produces because maskFromHeap may be able to - // get exact type information for certain classes of objects. - // With maskFromType, we're always just tiling the type bitmap - // through to the elemsize. - // - // It's OK if maskFromType has pointers in elemsize that extend - // past the actual populated space; we checked above that all - // that space is zeroed, so just the GC will just see nil pointers. - differs := false - for i := range maskFromHeap { - if maskFromHeap[i] != maskFromType[i] { - differs = true - break - } - } - - if differs { - print("runtime: heap mask=") - for _, b := range maskFromHeap { - print(b) - } - println() - print("runtime: type mask=") - for _, b := range maskFromType { - print(b) - } - println() - print("runtime: type=", toRType(et).string(), "\n") - throw("found two different masks from two different methods") - } - } - - // Select the heap mask to return. We may not have a type mask. - mask = maskFromHeap - - // Make sure we keep ep alive. We may have stopped referencing - // ep's data pointer sometime before this point and it's possible - // for that memory to get freed. - KeepAlive(ep) - return - } - - // stack - if gp := getg(); gp.m.curg.stack.lo <= uintptr(p) && uintptr(p) < gp.m.curg.stack.hi { - found := false - var u unwinder - for u.initAt(gp.m.curg.sched.pc, gp.m.curg.sched.sp, 0, gp.m.curg, 0); u.valid(); u.next() { - if u.frame.sp <= uintptr(p) && uintptr(p) < u.frame.varp { - found = true - break - } - } - if found { - locals, _, _ := u.frame.getStackMap(false) - if locals.n == 0 { - return - } - size := uintptr(locals.n) * goarch.PtrSize - n := (*ptrtype)(unsafe.Pointer(t)).Elem.Size_ - mask = make([]byte, n/goarch.PtrSize) - for i := uintptr(0); i < n; i += goarch.PtrSize { - off := (uintptr(p) + i - u.frame.varp + size) / goarch.PtrSize - mask[i/goarch.PtrSize] = locals.ptrbit(off) - } - } - return - } - - // otherwise, not something the GC knows about. - // possibly read-only data, like malloc(0). - // must not have pointers - return -} - -// userArenaHeapBitsSetType is the equivalent of heapSetType but for -// non-slice-backing-store Go values allocated in a user arena chunk. It -// sets up the type metadata for the value with type typ allocated at address ptr. -// base is the base address of the arena chunk. -func userArenaHeapBitsSetType(typ *_type, ptr unsafe.Pointer, s *mspan) { - base := s.base() - h := s.writeUserArenaHeapBits(uintptr(ptr)) - - p := typ.GCData // start of 1-bit pointer mask (or GC program) - var gcProgBits uintptr - if typ.Kind_&kindGCProg != 0 { - // Expand gc program, using the object itself for storage. - gcProgBits = runGCProg(addb(p, 4), (*byte)(ptr)) - p = (*byte)(ptr) - } - nb := typ.PtrBytes / goarch.PtrSize - - for i := uintptr(0); i < nb; i += ptrBits { - k := nb - i - if k > ptrBits { - k = ptrBits - } - // N.B. On big endian platforms we byte swap the data that we - // read from GCData, which is always stored in little-endian order - // by the compiler. writeUserArenaHeapBits handles data in - // a platform-ordered way for efficiency, but stores back the - // data in little endian order, since we expose the bitmap through - // a dummy type. - h = h.write(s, readUintptr(addb(p, i/8)), k) - } - // Note: we call pad here to ensure we emit explicit 0 bits - // for the pointerless tail of the object. This ensures that - // there's only a single noMorePtrs mark for the next object - // to clear. We don't need to do this to clear stale noMorePtrs - // markers from previous uses because arena chunk pointer bitmaps - // are always fully cleared when reused. - h = h.pad(s, typ.Size_-typ.PtrBytes) - h.flush(s, uintptr(ptr), typ.Size_) - - if typ.Kind_&kindGCProg != 0 { - // Zero out temporary ptrmask buffer inside object. - memclrNoHeapPointers(ptr, (gcProgBits+7)/8) - } - - // Update the PtrBytes value in the type information. After this - // point, the GC will observe the new bitmap. - s.largeType.PtrBytes = uintptr(ptr) - base + typ.PtrBytes - - // Double-check that the bitmap was written out correctly. - const doubleCheck = false - if doubleCheck { - doubleCheckHeapPointersInterior(uintptr(ptr), uintptr(ptr), typ.Size_, typ.Size_, typ, &s.largeType, s) - } -} - -// For !goexperiment.AllocHeaders, to pass TestIntendedInlining. -func writeHeapBitsForAddr() { - panic("not implemented") -} - -// For !goexperiment.AllocHeaders. -type heapBits struct { -} - -// For !goexperiment.AllocHeaders. -// -//go:nosplit -func heapBitsForAddr(addr, size uintptr) heapBits { - panic("not implemented") -} - -// For !goexperiment.AllocHeaders. -// -//go:nosplit -func (h heapBits) next() (heapBits, uintptr) { - panic("not implemented") -} - -// For !goexperiment.AllocHeaders. -// -//go:nosplit -func (h heapBits) nextFast() (heapBits, uintptr) { - panic("not implemented") -} diff --git a/contrib/go/_std_1.22/src/runtime/mbitmap_noallocheaders.go b/contrib/go/_std_1.22/src/runtime/mbitmap_noallocheaders.go deleted file mode 100644 index 383993aa1ef7..000000000000 --- a/contrib/go/_std_1.22/src/runtime/mbitmap_noallocheaders.go +++ /dev/null @@ -1,938 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !goexperiment.allocheaders - -// Garbage collector: type and heap bitmaps. -// -// Stack, data, and bss bitmaps -// -// Stack frames and global variables in the data and bss sections are -// described by bitmaps with 1 bit per pointer-sized word. A "1" bit -// means the word is a live pointer to be visited by the GC (referred to -// as "pointer"). A "0" bit means the word should be ignored by GC -// (referred to as "scalar", though it could be a dead pointer value). -// -// Heap bitmap -// -// The heap bitmap comprises 1 bit for each pointer-sized word in the heap, -// recording whether a pointer is stored in that word or not. This bitmap -// is stored in the heapArena metadata backing each heap arena. -// That is, if ha is the heapArena for the arena starting at "start", -// then ha.bitmap[0] holds the 64 bits for the 64 words "start" -// through start+63*ptrSize, ha.bitmap[1] holds the entries for -// start+64*ptrSize through start+127*ptrSize, and so on. -// Bits correspond to words in little-endian order. ha.bitmap[0]&1 represents -// the word at "start", ha.bitmap[0]>>1&1 represents the word at start+8, etc. -// (For 32-bit platforms, s/64/32/.) -// -// We also keep a noMorePtrs bitmap which allows us to stop scanning -// the heap bitmap early in certain situations. If ha.noMorePtrs[i]>>j&1 -// is 1, then the object containing the last word described by ha.bitmap[8*i+j] -// has no more pointers beyond those described by ha.bitmap[8*i+j]. -// If ha.noMorePtrs[i]>>j&1 is set, the entries in ha.bitmap[8*i+j+1] and -// beyond must all be zero until the start of the next object. -// -// The bitmap for noscan spans is set to all zero at span allocation time. -// -// The bitmap for unallocated objects in scannable spans is not maintained -// (can be junk). - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "runtime/internal/sys" - "unsafe" -) - -const ( - // For compatibility with the allocheaders GOEXPERIMENT. - mallocHeaderSize = 0 - minSizeForMallocHeader = ^uintptr(0) -) - -// For compatibility with the allocheaders GOEXPERIMENT. -// -//go:nosplit -func heapBitsInSpan(_ uintptr) bool { - return false -} - -// heapArenaPtrScalar contains the per-heapArena pointer/scalar metadata for the GC. -type heapArenaPtrScalar struct { - // bitmap stores the pointer/scalar bitmap for the words in - // this arena. See mbitmap.go for a description. - // This array uses 1 bit per word of heap, or 1.6% of the heap size (for 64-bit). - bitmap [heapArenaBitmapWords]uintptr - - // If the ith bit of noMorePtrs is true, then there are no more - // pointers for the object containing the word described by the - // high bit of bitmap[i]. - // In that case, bitmap[i+1], ... must be zero until the start - // of the next object. - // We never operate on these entries using bit-parallel techniques, - // so it is ok if they are small. Also, they can't be bigger than - // uint16 because at that size a single noMorePtrs entry - // represents 8K of memory, the minimum size of a span. Any larger - // and we'd have to worry about concurrent updates. - // This array uses 1 bit per word of bitmap, or .024% of the heap size (for 64-bit). - noMorePtrs [heapArenaBitmapWords / 8]uint8 -} - -// heapBits provides access to the bitmap bits for a single heap word. -// The methods on heapBits take value receivers so that the compiler -// can more easily inline calls to those methods and registerize the -// struct fields independently. -type heapBits struct { - // heapBits will report on pointers in the range [addr,addr+size). - // The low bit of mask contains the pointerness of the word at addr - // (assuming valid>0). - addr, size uintptr - - // The next few pointer bits representing words starting at addr. - // Those bits already returned by next() are zeroed. - mask uintptr - // Number of bits in mask that are valid. mask is always less than 1<> off - valid := ptrBits - off - - // Process depending on where the object ends. - nptr := size / goarch.PtrSize - if nptr < valid { - // Bits for this object end before the end of this bitmap word. - // Squash bits for the following objects. - mask &= 1<<(nptr&(ptrBits-1)) - 1 - valid = nptr - } else if nptr == valid { - // Bits for this object end at exactly the end of this bitmap word. - // All good. - } else { - // Bits for this object extend into the next bitmap word. See if there - // may be any pointers recorded there. - if uintptr(ha.noMorePtrs[idx/8])>>(idx%8)&1 != 0 { - // No more pointers in this object after this bitmap word. - // Update size so we know not to look there. - size = valid * goarch.PtrSize - } - } - - return heapBits{addr: addr, size: size, mask: mask, valid: valid} -} - -// Returns the (absolute) address of the next known pointer and -// a heapBits iterator representing any remaining pointers. -// If there are no more pointers, returns address 0. -// Note that next does not modify h. The caller must record the result. -// -// nosplit because it is used during write barriers and must not be preempted. -// -//go:nosplit -func (h heapBits) next() (heapBits, uintptr) { - for { - if h.mask != 0 { - var i int - if goarch.PtrSize == 8 { - i = sys.TrailingZeros64(uint64(h.mask)) - } else { - i = sys.TrailingZeros32(uint32(h.mask)) - } - h.mask ^= uintptr(1) << (i & (ptrBits - 1)) - return h, h.addr + uintptr(i)*goarch.PtrSize - } - - // Skip words that we've already processed. - h.addr += h.valid * goarch.PtrSize - h.size -= h.valid * goarch.PtrSize - if h.size == 0 { - return h, 0 // no more pointers - } - - // Grab more bits and try again. - h = heapBitsForAddr(h.addr, h.size) - } -} - -// nextFast is like next, but can return 0 even when there are more pointers -// to be found. Callers should call next if nextFast returns 0 as its second -// return value. -// -// if addr, h = h.nextFast(); addr == 0 { -// if addr, h = h.next(); addr == 0 { -// ... no more pointers ... -// } -// } -// ... process pointer at addr ... -// -// nextFast is designed to be inlineable. -// -//go:nosplit -func (h heapBits) nextFast() (heapBits, uintptr) { - // TESTQ/JEQ - if h.mask == 0 { - return h, 0 - } - // BSFQ - var i int - if goarch.PtrSize == 8 { - i = sys.TrailingZeros64(uint64(h.mask)) - } else { - i = sys.TrailingZeros32(uint32(h.mask)) - } - // BTCQ - h.mask ^= uintptr(1) << (i & (ptrBits - 1)) - // LEAQ (XX)(XX*8) - return h, h.addr + uintptr(i)*goarch.PtrSize -} - -// bulkBarrierPreWrite executes a write barrier -// for every pointer slot in the memory range [src, src+size), -// using pointer/scalar information from [dst, dst+size). -// This executes the write barriers necessary before a memmove. -// src, dst, and size must be pointer-aligned. -// The range [dst, dst+size) must lie within a single object. -// It does not perform the actual writes. -// -// As a special case, src == 0 indicates that this is being used for a -// memclr. bulkBarrierPreWrite will pass 0 for the src of each write -// barrier. -// -// Callers should call bulkBarrierPreWrite immediately before -// calling memmove(dst, src, size). This function is marked nosplit -// to avoid being preempted; the GC must not stop the goroutine -// between the memmove and the execution of the barriers. -// The caller is also responsible for cgo pointer checks if this -// may be writing Go pointers into non-Go memory. -// -// The pointer bitmap is not maintained for allocations containing -// no pointers at all; any caller of bulkBarrierPreWrite must first -// make sure the underlying allocation contains pointers, usually -// by checking typ.PtrBytes. -// -// The type of the space can be provided purely as an optimization, -// however it is not used with GOEXPERIMENT=noallocheaders. -// -// Callers must perform cgo checks if goexperiment.CgoCheck2. -// -//go:nosplit -func bulkBarrierPreWrite(dst, src, size uintptr, _ *abi.Type) { - if (dst|src|size)&(goarch.PtrSize-1) != 0 { - throw("bulkBarrierPreWrite: unaligned arguments") - } - if !writeBarrier.enabled { - return - } - if s := spanOf(dst); s == nil { - // If dst is a global, use the data or BSS bitmaps to - // execute write barriers. - for _, datap := range activeModules() { - if datap.data <= dst && dst < datap.edata { - bulkBarrierBitmap(dst, src, size, dst-datap.data, datap.gcdatamask.bytedata) - return - } - } - for _, datap := range activeModules() { - if datap.bss <= dst && dst < datap.ebss { - bulkBarrierBitmap(dst, src, size, dst-datap.bss, datap.gcbssmask.bytedata) - return - } - } - return - } else if s.state.get() != mSpanInUse || dst < s.base() || s.limit <= dst { - // dst was heap memory at some point, but isn't now. - // It can't be a global. It must be either our stack, - // or in the case of direct channel sends, it could be - // another stack. Either way, no need for barriers. - // This will also catch if dst is in a freed span, - // though that should never have. - return - } - - buf := &getg().m.p.ptr().wbBuf - h := heapBitsForAddr(dst, size) - if src == 0 { - for { - var addr uintptr - if h, addr = h.next(); addr == 0 { - break - } - dstx := (*uintptr)(unsafe.Pointer(addr)) - p := buf.get1() - p[0] = *dstx - } - } else { - for { - var addr uintptr - if h, addr = h.next(); addr == 0 { - break - } - dstx := (*uintptr)(unsafe.Pointer(addr)) - srcx := (*uintptr)(unsafe.Pointer(src + (addr - dst))) - p := buf.get2() - p[0] = *dstx - p[1] = *srcx - } - } -} - -// bulkBarrierPreWriteSrcOnly is like bulkBarrierPreWrite but -// does not execute write barriers for [dst, dst+size). -// -// In addition to the requirements of bulkBarrierPreWrite -// callers need to ensure [dst, dst+size) is zeroed. -// -// This is used for special cases where e.g. dst was just -// created and zeroed with malloc. -// -// The type of the space can be provided purely as an optimization, -// however it is not used with GOEXPERIMENT=noallocheaders. -// -//go:nosplit -func bulkBarrierPreWriteSrcOnly(dst, src, size uintptr, _ *abi.Type) { - if (dst|src|size)&(goarch.PtrSize-1) != 0 { - throw("bulkBarrierPreWrite: unaligned arguments") - } - if !writeBarrier.enabled { - return - } - buf := &getg().m.p.ptr().wbBuf - h := heapBitsForAddr(dst, size) - for { - var addr uintptr - if h, addr = h.next(); addr == 0 { - break - } - srcx := (*uintptr)(unsafe.Pointer(addr - dst + src)) - p := buf.get1() - p[0] = *srcx - } -} - -// initHeapBits initializes the heap bitmap for a span. -// If this is a span of single pointer allocations, it initializes all -// words to pointer. If force is true, clears all bits. -func (s *mspan) initHeapBits(forceClear bool) { - if forceClear || s.spanclass.noscan() { - // Set all the pointer bits to zero. We do this once - // when the span is allocated so we don't have to do it - // for each object allocation. - base := s.base() - size := s.npages * pageSize - h := writeHeapBitsForAddr(base) - h.flush(base, size) - return - } - isPtrs := goarch.PtrSize == 8 && s.elemsize == goarch.PtrSize - if !isPtrs { - return // nothing to do - } - h := writeHeapBitsForAddr(s.base()) - size := s.npages * pageSize - nptrs := size / goarch.PtrSize - for i := uintptr(0); i < nptrs; i += ptrBits { - h = h.write(^uintptr(0), ptrBits) - } - h.flush(s.base(), size) -} - -type writeHeapBits struct { - addr uintptr // address that the low bit of mask represents the pointer state of. - mask uintptr // some pointer bits starting at the address addr. - valid uintptr // number of bits in buf that are valid (including low) - low uintptr // number of low-order bits to not overwrite -} - -func writeHeapBitsForAddr(addr uintptr) (h writeHeapBits) { - // We start writing bits maybe in the middle of a heap bitmap word. - // Remember how many bits into the word we started, so we can be sure - // not to overwrite the previous bits. - h.low = addr / goarch.PtrSize % ptrBits - - // round down to heap word that starts the bitmap word. - h.addr = addr - h.low*goarch.PtrSize - - // We don't have any bits yet. - h.mask = 0 - h.valid = h.low - - return -} - -// write appends the pointerness of the next valid pointer slots -// using the low valid bits of bits. 1=pointer, 0=scalar. -func (h writeHeapBits) write(bits, valid uintptr) writeHeapBits { - if h.valid+valid <= ptrBits { - // Fast path - just accumulate the bits. - h.mask |= bits << h.valid - h.valid += valid - return h - } - // Too many bits to fit in this word. Write the current word - // out and move on to the next word. - - data := h.mask | bits<> (ptrBits - h.valid) // leftover for next word - h.valid += valid - ptrBits // have h.valid+valid bits, writing ptrBits of them - - // Flush mask to the memory bitmap. - // TODO: figure out how to cache arena lookup. - ai := arenaIndex(h.addr) - ha := mheap_.arenas[ai.l1()][ai.l2()] - idx := h.addr / (ptrBits * goarch.PtrSize) % heapArenaBitmapWords - m := uintptr(1)< ptrBits { - h = h.write(0, ptrBits) - words -= ptrBits - } - return h.write(0, words) -} - -// Flush the bits that have been written, and add zeros as needed -// to cover the full object [addr, addr+size). -func (h writeHeapBits) flush(addr, size uintptr) { - // zeros counts the number of bits needed to represent the object minus the - // number of bits we've already written. This is the number of 0 bits - // that need to be added. - zeros := (addr+size-h.addr)/goarch.PtrSize - h.valid - - // Add zero bits up to the bitmap word boundary - if zeros > 0 { - z := ptrBits - h.valid - if z > zeros { - z = zeros - } - h.valid += z - zeros -= z - } - - // Find word in bitmap that we're going to write. - ai := arenaIndex(h.addr) - ha := mheap_.arenas[ai.l1()][ai.l2()] - idx := h.addr / (ptrBits * goarch.PtrSize) % heapArenaBitmapWords - - // Write remaining bits. - if h.valid != h.low { - m := uintptr(1)< 8 { - h = h.write(uintptr(*p), 8) - p = add1(p) - j -= 8 - } - h = h.write(uintptr(*p), j) - - if i+typ.Size_ == dataSize { - break // no padding after last element - } - - // Pad with zeros to the start of the next element. - h = h.pad(typ.Size_ - n*goarch.PtrSize) - } - - h.flush(x, size) - - // Erase the expanded GC program. - memclrNoHeapPointers(unsafe.Pointer(obj), (n+7)/8) - return - } - - // Note about sizes: - // - // typ.Size is the number of words in the object, - // and typ.PtrBytes is the number of words in the prefix - // of the object that contains pointers. That is, the final - // typ.Size - typ.PtrBytes words contain no pointers. - // This allows optimization of a common pattern where - // an object has a small header followed by a large scalar - // buffer. If we know the pointers are over, we don't have - // to scan the buffer's heap bitmap at all. - // The 1-bit ptrmasks are sized to contain only bits for - // the typ.PtrBytes prefix, zero padded out to a full byte - // of bitmap. If there is more room in the allocated object, - // that space is pointerless. The noMorePtrs bitmap will prevent - // scanning large pointerless tails of an object. - // - // Replicated copies are not as nice: if there is an array of - // objects with scalar tails, all but the last tail does have to - // be initialized, because there is no way to say "skip forward". - - ptrs := typ.PtrBytes / goarch.PtrSize - if typ.Size_ == dataSize { // Single element - if ptrs <= ptrBits { // Single small element - m := readUintptr(typ.GCData) - h = h.write(m, ptrs) - } else { // Single large element - p := typ.GCData - for { - h = h.write(readUintptr(p), ptrBits) - p = addb(p, ptrBits/8) - ptrs -= ptrBits - if ptrs <= ptrBits { - break - } - } - m := readUintptr(p) - h = h.write(m, ptrs) - } - } else { // Repeated element - words := typ.Size_ / goarch.PtrSize // total words, including scalar tail - if words <= ptrBits { // Repeated small element - n := dataSize / typ.Size_ - m := readUintptr(typ.GCData) - // Make larger unit to repeat - for words <= ptrBits/2 { - if n&1 != 0 { - h = h.write(m, words) - } - n /= 2 - m |= m << words - ptrs += words - words *= 2 - if n == 1 { - break - } - } - for n > 1 { - h = h.write(m, words) - n-- - } - h = h.write(m, ptrs) - } else { // Repeated large element - for i := uintptr(0); true; i += typ.Size_ { - p := typ.GCData - j := ptrs - for j > ptrBits { - h = h.write(readUintptr(p), ptrBits) - p = addb(p, ptrBits/8) - j -= ptrBits - } - m := readUintptr(p) - h = h.write(m, j) - if i+typ.Size_ == dataSize { - break // don't need the trailing nonptr bits on the last element. - } - // Pad with zeros to the start of the next element. - h = h.pad(typ.Size_ - typ.PtrBytes) - } - } - } - h.flush(x, size) - - if doubleCheck { - h := heapBitsForAddr(x, size) - for i := uintptr(0); i < size; i += goarch.PtrSize { - // Compute the pointer bit we want at offset i. - want := false - if i < dataSize { - off := i % typ.Size_ - if off < typ.PtrBytes { - j := off / goarch.PtrSize - want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 - } - } - if want { - var addr uintptr - h, addr = h.next() - if addr != x+i { - throw("heapBitsSetType: pointer entry not correct") - } - } - } - if _, addr := h.next(); addr != 0 { - throw("heapBitsSetType: extra pointer") - } - } -} - -// For goexperiment.AllocHeaders -func heapSetType(x, dataSize uintptr, typ *_type, header **_type, span *mspan) (scanSize uintptr) { - return 0 -} - -// Testing. - -// Returns GC type info for the pointer stored in ep for testing. -// If ep points to the stack, only static live information will be returned -// (i.e. not for objects which are only dynamically live stack objects). -func getgcmask(ep any) (mask []byte) { - e := *efaceOf(&ep) - p := e.data - t := e._type - // data or bss - for _, datap := range activeModules() { - // data - if datap.data <= uintptr(p) && uintptr(p) < datap.edata { - bitmap := datap.gcdatamask.bytedata - n := (*ptrtype)(unsafe.Pointer(t)).Elem.Size_ - mask = make([]byte, n/goarch.PtrSize) - for i := uintptr(0); i < n; i += goarch.PtrSize { - off := (uintptr(p) + i - datap.data) / goarch.PtrSize - mask[i/goarch.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 - } - return - } - - // bss - if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss { - bitmap := datap.gcbssmask.bytedata - n := (*ptrtype)(unsafe.Pointer(t)).Elem.Size_ - mask = make([]byte, n/goarch.PtrSize) - for i := uintptr(0); i < n; i += goarch.PtrSize { - off := (uintptr(p) + i - datap.bss) / goarch.PtrSize - mask[i/goarch.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 - } - return - } - } - - // heap - if base, s, _ := findObject(uintptr(p), 0, 0); base != 0 { - if s.spanclass.noscan() { - return nil - } - n := s.elemsize - hbits := heapBitsForAddr(base, n) - mask = make([]byte, n/goarch.PtrSize) - for { - var addr uintptr - if hbits, addr = hbits.next(); addr == 0 { - break - } - mask[(addr-base)/goarch.PtrSize] = 1 - } - // Callers expect this mask to end at the last pointer. - for len(mask) > 0 && mask[len(mask)-1] == 0 { - mask = mask[:len(mask)-1] - } - - // Make sure we keep ep alive. We may have stopped referencing - // ep's data pointer sometime before this point and it's possible - // for that memory to get freed. - KeepAlive(ep) - return - } - - // stack - if gp := getg(); gp.m.curg.stack.lo <= uintptr(p) && uintptr(p) < gp.m.curg.stack.hi { - found := false - var u unwinder - for u.initAt(gp.m.curg.sched.pc, gp.m.curg.sched.sp, 0, gp.m.curg, 0); u.valid(); u.next() { - if u.frame.sp <= uintptr(p) && uintptr(p) < u.frame.varp { - found = true - break - } - } - if found { - locals, _, _ := u.frame.getStackMap(false) - if locals.n == 0 { - return - } - size := uintptr(locals.n) * goarch.PtrSize - n := (*ptrtype)(unsafe.Pointer(t)).Elem.Size_ - mask = make([]byte, n/goarch.PtrSize) - for i := uintptr(0); i < n; i += goarch.PtrSize { - off := (uintptr(p) + i - u.frame.varp + size) / goarch.PtrSize - mask[i/goarch.PtrSize] = locals.ptrbit(off) - } - } - return - } - - // otherwise, not something the GC knows about. - // possibly read-only data, like malloc(0). - // must not have pointers - return -} - -// userArenaHeapBitsSetType is the equivalent of heapBitsSetType but for -// non-slice-backing-store Go values allocated in a user arena chunk. It -// sets up the heap bitmap for the value with type typ allocated at address ptr. -// base is the base address of the arena chunk. -func userArenaHeapBitsSetType(typ *_type, ptr unsafe.Pointer, s *mspan) { - base := s.base() - h := writeHeapBitsForAddr(uintptr(ptr)) - - // Our last allocation might have ended right at a noMorePtrs mark, - // which we would not have erased. We need to erase that mark here, - // because we're going to start adding new heap bitmap bits. - // We only need to clear one mark, because below we make sure to - // pad out the bits with zeroes and only write one noMorePtrs bit - // for each new object. - // (This is only necessary at noMorePtrs boundaries, as noMorePtrs - // marks within an object allocated with newAt will be erased by - // the normal writeHeapBitsForAddr mechanism.) - // - // Note that we skip this if this is the first allocation in the - // arena because there's definitely no previous noMorePtrs mark - // (in fact, we *must* do this, because we're going to try to back - // up a pointer to fix this up). - if uintptr(ptr)%(8*goarch.PtrSize*goarch.PtrSize) == 0 && uintptr(ptr) != base { - // Back up one pointer and rewrite that pointer. That will - // cause the writeHeapBits implementation to clear the - // noMorePtrs bit we need to clear. - r := heapBitsForAddr(uintptr(ptr)-goarch.PtrSize, goarch.PtrSize) - _, p := r.next() - b := uintptr(0) - if p == uintptr(ptr)-goarch.PtrSize { - b = 1 - } - h = writeHeapBitsForAddr(uintptr(ptr) - goarch.PtrSize) - h = h.write(b, 1) - } - - p := typ.GCData // start of 1-bit pointer mask (or GC program) - var gcProgBits uintptr - if typ.Kind_&kindGCProg != 0 { - // Expand gc program, using the object itself for storage. - gcProgBits = runGCProg(addb(p, 4), (*byte)(ptr)) - p = (*byte)(ptr) - } - nb := typ.PtrBytes / goarch.PtrSize - - for i := uintptr(0); i < nb; i += ptrBits { - k := nb - i - if k > ptrBits { - k = ptrBits - } - h = h.write(readUintptr(addb(p, i/8)), k) - } - // Note: we call pad here to ensure we emit explicit 0 bits - // for the pointerless tail of the object. This ensures that - // there's only a single noMorePtrs mark for the next object - // to clear. We don't need to do this to clear stale noMorePtrs - // markers from previous uses because arena chunk pointer bitmaps - // are always fully cleared when reused. - h = h.pad(typ.Size_ - typ.PtrBytes) - h.flush(uintptr(ptr), typ.Size_) - - if typ.Kind_&kindGCProg != 0 { - // Zero out temporary ptrmask buffer inside object. - memclrNoHeapPointers(ptr, (gcProgBits+7)/8) - } - - // Double-check that the bitmap was written out correctly. - // - // Derived from heapBitsSetType. - const doubleCheck = false - if doubleCheck { - size := typ.Size_ - x := uintptr(ptr) - h := heapBitsForAddr(x, size) - for i := uintptr(0); i < size; i += goarch.PtrSize { - // Compute the pointer bit we want at offset i. - want := false - off := i % typ.Size_ - if off < typ.PtrBytes { - j := off / goarch.PtrSize - want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 - } - if want { - var addr uintptr - h, addr = h.next() - if addr != x+i { - throw("userArenaHeapBitsSetType: pointer entry not correct") - } - } - } - if _, addr := h.next(); addr != 0 { - throw("userArenaHeapBitsSetType: extra pointer") - } - } -} - -// For goexperiment.AllocHeaders. -type typePointers struct { - addr uintptr -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (span *mspan) typePointersOf(addr, size uintptr) typePointers { - panic("not implemented") -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (span *mspan) typePointersOfUnchecked(addr uintptr) typePointers { - panic("not implemented") -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (tp typePointers) nextFast() (typePointers, uintptr) { - panic("not implemented") -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (tp typePointers) next(limit uintptr) (typePointers, uintptr) { - panic("not implemented") -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (tp typePointers) fastForward(n, limit uintptr) typePointers { - panic("not implemented") -} - -// For goexperiment.AllocHeaders, to pass TestIntendedInlining. -func (s *mspan) writeUserArenaHeapBits() { - panic("not implemented") -} - -// For goexperiment.AllocHeaders, to pass TestIntendedInlining. -func heapBitsSlice() { - panic("not implemented") -} diff --git a/contrib/go/_std_1.22/src/runtime/metrics/doc.go b/contrib/go/_std_1.22/src/runtime/metrics/doc.go deleted file mode 100644 index 85f256d65a29..000000000000 --- a/contrib/go/_std_1.22/src/runtime/metrics/doc.go +++ /dev/null @@ -1,466 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Note: run 'go generate' (which will run 'go test -generate') to update the "Supported metrics" list. -//go:generate go test -run=Docs -generate - -/* -Package metrics provides a stable interface to access implementation-defined -metrics exported by the Go runtime. This package is similar to existing functions -like [runtime.ReadMemStats] and [runtime/debug.ReadGCStats], but significantly more general. - -The set of metrics defined by this package may evolve as the runtime itself -evolves, and also enables variation across Go implementations, whose relevant -metric sets may not intersect. - -# Interface - -Metrics are designated by a string key, rather than, for example, a field name in -a struct. The full list of supported metrics is always available in the slice of -Descriptions returned by [All]. Each [Description] also includes useful information -about the metric. - -Thus, users of this API are encouraged to sample supported metrics defined by the -slice returned by All to remain compatible across Go versions. Of course, situations -arise where reading specific metrics is critical. For these cases, users are -encouraged to use build tags, and although metrics may be deprecated and removed, -users should consider this to be an exceptional and rare event, coinciding with a -very large change in a particular Go implementation. - -Each metric key also has a "kind" (see [ValueKind]) that describes the format of the -metric's value. -In the interest of not breaking users of this package, the "kind" for a given metric -is guaranteed not to change. If it must change, then a new metric will be introduced -with a new key and a new "kind." - -# Metric key format - -As mentioned earlier, metric keys are strings. Their format is simple and well-defined, -designed to be both human and machine readable. It is split into two components, -separated by a colon: a rooted path and a unit. The choice to include the unit in -the key is motivated by compatibility: if a metric's unit changes, its semantics likely -did also, and a new key should be introduced. - -For more details on the precise definition of the metric key's path and unit formats, see -the documentation of the Name field of the Description struct. - -# A note about floats - -This package supports metrics whose values have a floating-point representation. In -order to improve ease-of-use, this package promises to never produce the following -classes of floating-point values: NaN, infinity. - -# Supported metrics - -Below is the full list of supported metrics, ordered lexicographically. - - /cgo/go-to-c-calls:calls - Count of calls made from Go to C by the current process. - - /cpu/classes/gc/mark/assist:cpu-seconds - Estimated total CPU time goroutines spent performing GC - tasks to assist the GC and prevent it from falling behind the - application. This metric is an overestimate, and not directly - comparable to system CPU time measurements. Compare only with - other /cpu/classes metrics. - - /cpu/classes/gc/mark/dedicated:cpu-seconds - Estimated total CPU time spent performing GC tasks on processors - (as defined by GOMAXPROCS) dedicated to those tasks. This metric - is an overestimate, and not directly comparable to system CPU - time measurements. Compare only with other /cpu/classes metrics. - - /cpu/classes/gc/mark/idle:cpu-seconds - Estimated total CPU time spent performing GC tasks on spare CPU - resources that the Go scheduler could not otherwise find a use - for. This should be subtracted from the total GC CPU time to - obtain a measure of compulsory GC CPU time. This metric is an - overestimate, and not directly comparable to system CPU time - measurements. Compare only with other /cpu/classes metrics. - - /cpu/classes/gc/pause:cpu-seconds - Estimated total CPU time spent with the application paused by - the GC. Even if only one thread is running during the pause, - this is computed as GOMAXPROCS times the pause latency because - nothing else can be executing. This is the exact sum of samples - in /sched/pauses/total/gc:seconds if each sample is multiplied - by GOMAXPROCS at the time it is taken. This metric is an - overestimate, and not directly comparable to system CPU time - measurements. Compare only with other /cpu/classes metrics. - - /cpu/classes/gc/total:cpu-seconds - Estimated total CPU time spent performing GC tasks. This metric - is an overestimate, and not directly comparable to system CPU - time measurements. Compare only with other /cpu/classes metrics. - Sum of all metrics in /cpu/classes/gc. - - /cpu/classes/idle:cpu-seconds - Estimated total available CPU time not spent executing - any Go or Go runtime code. In other words, the part of - /cpu/classes/total:cpu-seconds that was unused. This metric is - an overestimate, and not directly comparable to system CPU time - measurements. Compare only with other /cpu/classes metrics. - - /cpu/classes/scavenge/assist:cpu-seconds - Estimated total CPU time spent returning unused memory to the - underlying platform in response eagerly in response to memory - pressure. This metric is an overestimate, and not directly - comparable to system CPU time measurements. Compare only with - other /cpu/classes metrics. - - /cpu/classes/scavenge/background:cpu-seconds - Estimated total CPU time spent performing background tasks to - return unused memory to the underlying platform. This metric is - an overestimate, and not directly comparable to system CPU time - measurements. Compare only with other /cpu/classes metrics. - - /cpu/classes/scavenge/total:cpu-seconds - Estimated total CPU time spent performing tasks that return - unused memory to the underlying platform. This metric is an - overestimate, and not directly comparable to system CPU time - measurements. Compare only with other /cpu/classes metrics. - Sum of all metrics in /cpu/classes/scavenge. - - /cpu/classes/total:cpu-seconds - Estimated total available CPU time for user Go code or the Go - runtime, as defined by GOMAXPROCS. In other words, GOMAXPROCS - integrated over the wall-clock duration this process has been - executing for. This metric is an overestimate, and not directly - comparable to system CPU time measurements. Compare only with - other /cpu/classes metrics. Sum of all metrics in /cpu/classes. - - /cpu/classes/user:cpu-seconds - Estimated total CPU time spent running user Go code. This may - also include some small amount of time spent in the Go runtime. - This metric is an overestimate, and not directly comparable - to system CPU time measurements. Compare only with other - /cpu/classes metrics. - - /gc/cycles/automatic:gc-cycles - Count of completed GC cycles generated by the Go runtime. - - /gc/cycles/forced:gc-cycles - Count of completed GC cycles forced by the application. - - /gc/cycles/total:gc-cycles - Count of all completed GC cycles. - - /gc/gogc:percent - Heap size target percentage configured by the user, otherwise - 100. This value is set by the GOGC environment variable, and the - runtime/debug.SetGCPercent function. - - /gc/gomemlimit:bytes - Go runtime memory limit configured by the user, otherwise - math.MaxInt64. This value is set by the GOMEMLIMIT environment - variable, and the runtime/debug.SetMemoryLimit function. - - /gc/heap/allocs-by-size:bytes - Distribution of heap allocations by approximate size. - Bucket counts increase monotonically. Note that this does not - include tiny objects as defined by /gc/heap/tiny/allocs:objects, - only tiny blocks. - - /gc/heap/allocs:bytes - Cumulative sum of memory allocated to the heap by the - application. - - /gc/heap/allocs:objects - Cumulative count of heap allocations triggered by the - application. Note that this does not include tiny objects as - defined by /gc/heap/tiny/allocs:objects, only tiny blocks. - - /gc/heap/frees-by-size:bytes - Distribution of freed heap allocations by approximate size. - Bucket counts increase monotonically. Note that this does not - include tiny objects as defined by /gc/heap/tiny/allocs:objects, - only tiny blocks. - - /gc/heap/frees:bytes - Cumulative sum of heap memory freed by the garbage collector. - - /gc/heap/frees:objects - Cumulative count of heap allocations whose storage was freed - by the garbage collector. Note that this does not include tiny - objects as defined by /gc/heap/tiny/allocs:objects, only tiny - blocks. - - /gc/heap/goal:bytes - Heap size target for the end of the GC cycle. - - /gc/heap/live:bytes - Heap memory occupied by live objects that were marked by the - previous GC. - - /gc/heap/objects:objects - Number of objects, live or unswept, occupying heap memory. - - /gc/heap/tiny/allocs:objects - Count of small allocations that are packed together into blocks. - These allocations are counted separately from other allocations - because each individual allocation is not tracked by the - runtime, only their block. Each block is already accounted for - in allocs-by-size and frees-by-size. - - /gc/limiter/last-enabled:gc-cycle - GC cycle the last time the GC CPU limiter was enabled. - This metric is useful for diagnosing the root cause of an - out-of-memory error, because the limiter trades memory for CPU - time when the GC's CPU time gets too high. This is most likely - to occur with use of SetMemoryLimit. The first GC cycle is cycle - 1, so a value of 0 indicates that it was never enabled. - - /gc/pauses:seconds - Deprecated. Prefer the identical /sched/pauses/total/gc:seconds. - - /gc/scan/globals:bytes - The total amount of global variable space that is scannable. - - /gc/scan/heap:bytes - The total amount of heap space that is scannable. - - /gc/scan/stack:bytes - The number of bytes of stack that were scanned last GC cycle. - - /gc/scan/total:bytes - The total amount space that is scannable. Sum of all metrics in - /gc/scan. - - /gc/stack/starting-size:bytes - The stack size of new goroutines. - - /godebug/non-default-behavior/execerrdot:events - The number of non-default behaviors executed by the os/exec - package due to a non-default GODEBUG=execerrdot=... setting. - - /godebug/non-default-behavior/gocachehash:events - The number of non-default behaviors executed by the cmd/go - package due to a non-default GODEBUG=gocachehash=... setting. - - /godebug/non-default-behavior/gocachetest:events - The number of non-default behaviors executed by the cmd/go - package due to a non-default GODEBUG=gocachetest=... setting. - - /godebug/non-default-behavior/gocacheverify:events - The number of non-default behaviors executed by the cmd/go - package due to a non-default GODEBUG=gocacheverify=... setting. - - /godebug/non-default-behavior/gotypesalias:events - The number of non-default behaviors executed by the go/types - package due to a non-default GODEBUG=gotypesalias=... setting. - - /godebug/non-default-behavior/http2client:events - The number of non-default behaviors executed by the net/http - package due to a non-default GODEBUG=http2client=... setting. - - /godebug/non-default-behavior/http2server:events - The number of non-default behaviors executed by the net/http - package due to a non-default GODEBUG=http2server=... setting. - - /godebug/non-default-behavior/httplaxcontentlength:events - The number of non-default behaviors executed by the net/http - package due to a non-default GODEBUG=httplaxcontentlength=... - setting. - - /godebug/non-default-behavior/httpmuxgo121:events - The number of non-default behaviors executed by the net/http - package due to a non-default GODEBUG=httpmuxgo121=... setting. - - /godebug/non-default-behavior/installgoroot:events - The number of non-default behaviors executed by the go/build - package due to a non-default GODEBUG=installgoroot=... setting. - - /godebug/non-default-behavior/jstmpllitinterp:events - The number of non-default behaviors executed by - the html/template package due to a non-default - GODEBUG=jstmpllitinterp=... setting. - - /godebug/non-default-behavior/multipartmaxheaders:events - The number of non-default behaviors executed by - the mime/multipart package due to a non-default - GODEBUG=multipartmaxheaders=... setting. - - /godebug/non-default-behavior/multipartmaxparts:events - The number of non-default behaviors executed by - the mime/multipart package due to a non-default - GODEBUG=multipartmaxparts=... setting. - - /godebug/non-default-behavior/multipathtcp:events - The number of non-default behaviors executed by the net package - due to a non-default GODEBUG=multipathtcp=... setting. - - /godebug/non-default-behavior/netedns0:events - The number of non-default behaviors executed by the net package - due to a non-default GODEBUG=netedns0=... setting. - - /godebug/non-default-behavior/panicnil:events - The number of non-default behaviors executed by the runtime - package due to a non-default GODEBUG=panicnil=... setting. - - /godebug/non-default-behavior/randautoseed:events - The number of non-default behaviors executed by the math/rand - package due to a non-default GODEBUG=randautoseed=... setting. - - /godebug/non-default-behavior/tarinsecurepath:events - The number of non-default behaviors executed by the archive/tar - package due to a non-default GODEBUG=tarinsecurepath=... - setting. - - /godebug/non-default-behavior/tls10server:events - The number of non-default behaviors executed by the crypto/tls - package due to a non-default GODEBUG=tls10server=... setting. - - /godebug/non-default-behavior/tlsmaxrsasize:events - The number of non-default behaviors executed by the crypto/tls - package due to a non-default GODEBUG=tlsmaxrsasize=... setting. - - /godebug/non-default-behavior/tlsrsakex:events - The number of non-default behaviors executed by the crypto/tls - package due to a non-default GODEBUG=tlsrsakex=... setting. - - /godebug/non-default-behavior/tlsunsafeekm:events - The number of non-default behaviors executed by the crypto/tls - package due to a non-default GODEBUG=tlsunsafeekm=... setting. - - /godebug/non-default-behavior/x509sha1:events - The number of non-default behaviors executed by the crypto/x509 - package due to a non-default GODEBUG=x509sha1=... setting. - - /godebug/non-default-behavior/x509usefallbackroots:events - The number of non-default behaviors executed by the crypto/x509 - package due to a non-default GODEBUG=x509usefallbackroots=... - setting. - - /godebug/non-default-behavior/x509usepolicies:events - The number of non-default behaviors executed by the crypto/x509 - package due to a non-default GODEBUG=x509usepolicies=... - setting. - - /godebug/non-default-behavior/zipinsecurepath:events - The number of non-default behaviors executed by the archive/zip - package due to a non-default GODEBUG=zipinsecurepath=... - setting. - - /memory/classes/heap/free:bytes - Memory that is completely free and eligible to be returned to - the underlying system, but has not been. This metric is the - runtime's estimate of free address space that is backed by - physical memory. - - /memory/classes/heap/objects:bytes - Memory occupied by live objects and dead objects that have not - yet been marked free by the garbage collector. - - /memory/classes/heap/released:bytes - Memory that is completely free and has been returned to the - underlying system. This metric is the runtime's estimate of free - address space that is still mapped into the process, but is not - backed by physical memory. - - /memory/classes/heap/stacks:bytes - Memory allocated from the heap that is reserved for stack space, - whether or not it is currently in-use. Currently, this - represents all stack memory for goroutines. It also includes all - OS thread stacks in non-cgo programs. Note that stacks may be - allocated differently in the future, and this may change. - - /memory/classes/heap/unused:bytes - Memory that is reserved for heap objects but is not currently - used to hold heap objects. - - /memory/classes/metadata/mcache/free:bytes - Memory that is reserved for runtime mcache structures, but not - in-use. - - /memory/classes/metadata/mcache/inuse:bytes - Memory that is occupied by runtime mcache structures that are - currently being used. - - /memory/classes/metadata/mspan/free:bytes - Memory that is reserved for runtime mspan structures, but not - in-use. - - /memory/classes/metadata/mspan/inuse:bytes - Memory that is occupied by runtime mspan structures that are - currently being used. - - /memory/classes/metadata/other:bytes - Memory that is reserved for or used to hold runtime metadata. - - /memory/classes/os-stacks:bytes - Stack memory allocated by the underlying operating system. - In non-cgo programs this metric is currently zero. This may - change in the future.In cgo programs this metric includes - OS thread stacks allocated directly from the OS. Currently, - this only accounts for one stack in c-shared and c-archive build - modes, and other sources of stacks from the OS are not measured. - This too may change in the future. - - /memory/classes/other:bytes - Memory used by execution trace buffers, structures for debugging - the runtime, finalizer and profiler specials, and more. - - /memory/classes/profiling/buckets:bytes - Memory that is used by the stack trace hash map used for - profiling. - - /memory/classes/total:bytes - All memory mapped by the Go runtime into the current process - as read-write. Note that this does not include memory mapped - by code called via cgo or via the syscall package. Sum of all - metrics in /memory/classes. - - /sched/gomaxprocs:threads - The current runtime.GOMAXPROCS setting, or the number of - operating system threads that can execute user-level Go code - simultaneously. - - /sched/goroutines:goroutines - Count of live goroutines. - - /sched/latencies:seconds - Distribution of the time goroutines have spent in the scheduler - in a runnable state before actually running. Bucket counts - increase monotonically. - - /sched/pauses/stopping/gc:seconds - Distribution of individual GC-related stop-the-world stopping - latencies. This is the time it takes from deciding to stop the - world until all Ps are stopped. This is a subset of the total - GC-related stop-the-world time (/sched/pauses/total/gc:seconds). - During this time, some threads may be executing. Bucket counts - increase monotonically. - - /sched/pauses/stopping/other:seconds - Distribution of individual non-GC-related stop-the-world - stopping latencies. This is the time it takes from deciding - to stop the world until all Ps are stopped. This is a - subset of the total non-GC-related stop-the-world time - (/sched/pauses/total/other:seconds). During this time, some - threads may be executing. Bucket counts increase monotonically. - - /sched/pauses/total/gc:seconds - Distribution of individual GC-related stop-the-world pause - latencies. This is the time from deciding to stop the world - until the world is started again. Some of this time is spent - getting all threads to stop (this is measured directly in - /sched/pauses/stopping/gc:seconds), during which some threads - may still be running. Bucket counts increase monotonically. - - /sched/pauses/total/other:seconds - Distribution of individual non-GC-related stop-the-world - pause latencies. This is the time from deciding to stop the - world until the world is started again. Some of this time - is spent getting all threads to stop (measured directly in - /sched/pauses/stopping/other:seconds). Bucket counts increase - monotonically. - - /sync/mutex/wait/total:seconds - Approximate cumulative time goroutines have spent blocked on a - sync.Mutex, sync.RWMutex, or runtime-internal lock. This metric - is useful for identifying global changes in lock contention. - Collect a mutex or block profile using the runtime/pprof package - for more detailed contention data. -*/ -package metrics diff --git a/contrib/go/_std_1.22/src/runtime/msan.go b/contrib/go/_std_1.22/src/runtime/msan.go deleted file mode 100644 index 5e2aae1bd161..000000000000 --- a/contrib/go/_std_1.22/src/runtime/msan.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build msan - -package runtime - -import ( - "unsafe" -) - -// Public memory sanitizer API. - -func MSanRead(addr unsafe.Pointer, len int) { - msanread(addr, uintptr(len)) -} - -func MSanWrite(addr unsafe.Pointer, len int) { - msanwrite(addr, uintptr(len)) -} - -// Private interface for the runtime. -const msanenabled = true - -// If we are running on the system stack, the C program may have -// marked part of that stack as uninitialized. We don't instrument -// the runtime, but operations like a slice copy can call msanread -// anyhow for values on the stack. Just ignore msanread when running -// on the system stack. The other msan functions are fine. -// -//go:nosplit -func msanread(addr unsafe.Pointer, sz uintptr) { - gp := getg() - if gp == nil || gp.m == nil || gp == gp.m.g0 || gp == gp.m.gsignal { - return - } - domsanread(addr, sz) -} - -//go:noescape -func domsanread(addr unsafe.Pointer, sz uintptr) - -//go:noescape -func msanwrite(addr unsafe.Pointer, sz uintptr) - -//go:noescape -func msanmalloc(addr unsafe.Pointer, sz uintptr) - -//go:noescape -func msanfree(addr unsafe.Pointer, sz uintptr) - -//go:noescape -func msanmove(dst, src unsafe.Pointer, sz uintptr) - -// These are called from msan_GOARCH.s -// -//go:cgo_import_static __msan_read_go -//go:cgo_import_static __msan_write_go -//go:cgo_import_static __msan_malloc_go -//go:cgo_import_static __msan_free_go -//go:cgo_import_static __msan_memmove diff --git a/contrib/go/_std_1.22/src/runtime/msize_allocheaders.go b/contrib/go/_std_1.22/src/runtime/msize_allocheaders.go deleted file mode 100644 index 6873ec66d9dd..000000000000 --- a/contrib/go/_std_1.22/src/runtime/msize_allocheaders.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.allocheaders - -// Malloc small size classes. -// -// See malloc.go for overview. -// See also mksizeclasses.go for how we decide what size classes to use. - -package runtime - -// Returns size of the memory block that mallocgc will allocate if you ask for the size, -// minus any inline space for metadata. -func roundupsize(size uintptr, noscan bool) (reqSize uintptr) { - reqSize = size - if reqSize <= maxSmallSize-mallocHeaderSize { - // Small object. - if !noscan && reqSize > minSizeForMallocHeader { // !noscan && !heapBitsInSpan(reqSize) - reqSize += mallocHeaderSize - } - // (reqSize - size) is either mallocHeaderSize or 0. We need to subtract mallocHeaderSize - // from the result if we have one, since mallocgc will add it back in. - if reqSize <= smallSizeMax-8 { - return uintptr(class_to_size[size_to_class8[divRoundUp(reqSize, smallSizeDiv)]]) - (reqSize - size) - } - return uintptr(class_to_size[size_to_class128[divRoundUp(reqSize-smallSizeMax, largeSizeDiv)]]) - (reqSize - size) - } - // Large object. Align reqSize up to the next page. Check for overflow. - reqSize += pageSize - 1 - if reqSize < size { - return size - } - return reqSize &^ (pageSize - 1) -} diff --git a/contrib/go/_std_1.22/src/runtime/msize_noallocheaders.go b/contrib/go/_std_1.22/src/runtime/msize_noallocheaders.go deleted file mode 100644 index d89e0d6cbe89..000000000000 --- a/contrib/go/_std_1.22/src/runtime/msize_noallocheaders.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !goexperiment.allocheaders - -// Malloc small size classes. -// -// See malloc.go for overview. -// See also mksizeclasses.go for how we decide what size classes to use. - -package runtime - -// Returns size of the memory block that mallocgc will allocate if you ask for the size. -// -// The noscan argument is purely for compatibility with goexperiment.AllocHeaders. -func roundupsize(size uintptr, noscan bool) uintptr { - if size < _MaxSmallSize { - if size <= smallSizeMax-8 { - return uintptr(class_to_size[size_to_class8[divRoundUp(size, smallSizeDiv)]]) - } else { - return uintptr(class_to_size[size_to_class128[divRoundUp(size-smallSizeMax, largeSizeDiv)]]) - } - } - if size+_PageSize < size { - return size - } - return alignUp(size, _PageSize) -} diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_epoll.go b/contrib/go/_std_1.22/src/runtime/netpoll_epoll.go deleted file mode 100644 index cda19fbc2787..000000000000 --- a/contrib/go/_std_1.22/src/runtime/netpoll_epoll.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux - -package runtime - -import ( - "runtime/internal/atomic" - "runtime/internal/syscall" - "unsafe" -) - -var ( - epfd int32 = -1 // epoll descriptor - - netpollBreakRd, netpollBreakWr uintptr // for netpollBreak - - netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak -) - -func netpollinit() { - var errno uintptr - epfd, errno = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC) - if errno != 0 { - println("runtime: epollcreate failed with", errno) - throw("runtime: netpollinit failed") - } - r, w, errpipe := nonblockingPipe() - if errpipe != 0 { - println("runtime: pipe failed with", -errpipe) - throw("runtime: pipe failed") - } - ev := syscall.EpollEvent{ - Events: syscall.EPOLLIN, - } - *(**uintptr)(unsafe.Pointer(&ev.Data)) = &netpollBreakRd - errno = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, r, &ev) - if errno != 0 { - println("runtime: epollctl failed with", errno) - throw("runtime: epollctl failed") - } - netpollBreakRd = uintptr(r) - netpollBreakWr = uintptr(w) -} - -func netpollIsPollDescriptor(fd uintptr) bool { - return fd == uintptr(epfd) || fd == netpollBreakRd || fd == netpollBreakWr -} - -func netpollopen(fd uintptr, pd *pollDesc) uintptr { - var ev syscall.EpollEvent - ev.Events = syscall.EPOLLIN | syscall.EPOLLOUT | syscall.EPOLLRDHUP | syscall.EPOLLET - tp := taggedPointerPack(unsafe.Pointer(pd), pd.fdseq.Load()) - *(*taggedPointer)(unsafe.Pointer(&ev.Data)) = tp - return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, int32(fd), &ev) -} - -func netpollclose(fd uintptr) uintptr { - var ev syscall.EpollEvent - return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, int32(fd), &ev) -} - -func netpollarm(pd *pollDesc, mode int) { - throw("runtime: unused") -} - -// netpollBreak interrupts an epollwait. -func netpollBreak() { - // Failing to cas indicates there is an in-flight wakeup, so we're done here. - if !netpollWakeSig.CompareAndSwap(0, 1) { - return - } - - for { - var b byte - n := write(netpollBreakWr, unsafe.Pointer(&b), 1) - if n == 1 { - break - } - if n == -_EINTR { - continue - } - if n == -_EAGAIN { - return - } - println("runtime: netpollBreak write failed with", -n) - throw("runtime: netpollBreak write failed") - } -} - -// netpoll checks for ready network connections. -// Returns list of goroutines that become runnable. -// delay < 0: blocks indefinitely -// delay == 0: does not block, just polls -// delay > 0: block for up to that many nanoseconds -func netpoll(delay int64) (gList, int32) { - if epfd == -1 { - return gList{}, 0 - } - var waitms int32 - if delay < 0 { - waitms = -1 - } else if delay == 0 { - waitms = 0 - } else if delay < 1e6 { - waitms = 1 - } else if delay < 1e15 { - waitms = int32(delay / 1e6) - } else { - // An arbitrary cap on how long to wait for a timer. - // 1e9 ms == ~11.5 days. - waitms = 1e9 - } - var events [128]syscall.EpollEvent -retry: - n, errno := syscall.EpollWait(epfd, events[:], int32(len(events)), waitms) - if errno != 0 { - if errno != _EINTR { - println("runtime: epollwait on fd", epfd, "failed with", errno) - throw("runtime: netpoll failed") - } - // If a timed sleep was interrupted, just return to - // recalculate how long we should sleep now. - if waitms > 0 { - return gList{}, 0 - } - goto retry - } - var toRun gList - delta := int32(0) - for i := int32(0); i < n; i++ { - ev := events[i] - if ev.Events == 0 { - continue - } - - if *(**uintptr)(unsafe.Pointer(&ev.Data)) == &netpollBreakRd { - if ev.Events != syscall.EPOLLIN { - println("runtime: netpoll: break fd ready for", ev.Events) - throw("runtime: netpoll: break fd ready for something unexpected") - } - if delay != 0 { - // netpollBreak could be picked up by a - // nonblocking poll. Only read the byte - // if blocking. - var tmp [16]byte - read(int32(netpollBreakRd), noescape(unsafe.Pointer(&tmp[0])), int32(len(tmp))) - netpollWakeSig.Store(0) - } - continue - } - - var mode int32 - if ev.Events&(syscall.EPOLLIN|syscall.EPOLLRDHUP|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 { - mode += 'r' - } - if ev.Events&(syscall.EPOLLOUT|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 { - mode += 'w' - } - if mode != 0 { - tp := *(*taggedPointer)(unsafe.Pointer(&ev.Data)) - pd := (*pollDesc)(tp.pointer()) - tag := tp.tag() - if pd.fdseq.Load() == tag { - pd.setEventErr(ev.Events == syscall.EPOLLERR, tag) - delta += netpollready(&toRun, pd, mode) - } - } - } - return toRun, delta -} diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_windows.go b/contrib/go/_std_1.22/src/runtime/netpoll_windows.go deleted file mode 100644 index 484a9e85b2d6..000000000000 --- a/contrib/go/_std_1.22/src/runtime/netpoll_windows.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "runtime/internal/atomic" - "unsafe" -) - -const _DWORD_MAX = 0xffffffff - -const _INVALID_HANDLE_VALUE = ^uintptr(0) - -// net_op must be the same as beginning of internal/poll.operation. -// Keep these in sync. -type net_op struct { - // used by windows - o overlapped - // used by netpoll - pd *pollDesc - mode int32 - errno int32 - qty uint32 -} - -type overlappedEntry struct { - key *pollDesc - op *net_op // In reality it's *overlapped, but we cast it to *net_op anyway. - internal uintptr - qty uint32 -} - -var ( - iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle - - netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak -) - -func netpollinit() { - iocphandle = stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX) - if iocphandle == 0 { - println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")") - throw("runtime: netpollinit failed") - } -} - -func netpollIsPollDescriptor(fd uintptr) bool { - return fd == iocphandle -} - -func netpollopen(fd uintptr, pd *pollDesc) int32 { - // TODO(iant): Consider using taggedPointer on 64-bit systems. - if stdcall4(_CreateIoCompletionPort, fd, iocphandle, uintptr(unsafe.Pointer(pd)), 0) == 0 { - return int32(getlasterror()) - } - return 0 -} - -func netpollclose(fd uintptr) int32 { - // nothing to do - return 0 -} - -func netpollarm(pd *pollDesc, mode int) { - throw("runtime: unused") -} - -func netpollBreak() { - // Failing to cas indicates there is an in-flight wakeup, so we're done here. - if !netpollWakeSig.CompareAndSwap(0, 1) { - return - } - - if stdcall4(_PostQueuedCompletionStatus, iocphandle, 0, 0, 0) == 0 { - println("runtime: netpoll: PostQueuedCompletionStatus failed (errno=", getlasterror(), ")") - throw("runtime: netpoll: PostQueuedCompletionStatus failed") - } -} - -// netpoll checks for ready network connections. -// Returns list of goroutines that become runnable. -// delay < 0: blocks indefinitely -// delay == 0: does not block, just polls -// delay > 0: block for up to that many nanoseconds -func netpoll(delay int64) (gList, int32) { - var entries [64]overlappedEntry - var wait, qty, flags, n, i uint32 - var errno int32 - var op *net_op - var toRun gList - - mp := getg().m - - if iocphandle == _INVALID_HANDLE_VALUE { - return gList{}, 0 - } - if delay < 0 { - wait = _INFINITE - } else if delay == 0 { - wait = 0 - } else if delay < 1e6 { - wait = 1 - } else if delay < 1e15 { - wait = uint32(delay / 1e6) - } else { - // An arbitrary cap on how long to wait for a timer. - // 1e9 ms == ~11.5 days. - wait = 1e9 - } - - n = uint32(len(entries) / int(gomaxprocs)) - if n < 8 { - n = 8 - } - if delay != 0 { - mp.blocked = true - } - if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 { - mp.blocked = false - errno = int32(getlasterror()) - if errno == _WAIT_TIMEOUT { - return gList{}, 0 - } - println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")") - throw("runtime: netpoll failed") - } - mp.blocked = false - delta := int32(0) - for i = 0; i < n; i++ { - op = entries[i].op - if op != nil && op.pd == entries[i].key { - errno = 0 - qty = 0 - if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { - errno = int32(getlasterror()) - } - delta += handlecompletion(&toRun, op, errno, qty) - } else { - netpollWakeSig.Store(0) - if delay == 0 { - // Forward the notification to the - // blocked poller. - netpollBreak() - } - } - } - return toRun, delta -} - -func handlecompletion(toRun *gList, op *net_op, errno int32, qty uint32) int32 { - mode := op.mode - if mode != 'r' && mode != 'w' { - println("runtime: GetQueuedCompletionStatusEx returned invalid mode=", mode) - throw("runtime: netpoll failed") - } - op.errno = errno - op.qty = qty - return netpollready(toRun, op.pd, mode) -} diff --git a/contrib/go/_std_1.22/src/runtime/os_unix_nonlinux.go b/contrib/go/_std_1.22/src/runtime/os_unix_nonlinux.go deleted file mode 100644 index b98753b8fe12..000000000000 --- a/contrib/go/_std_1.22/src/runtime/os_unix_nonlinux.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix && !linux - -package runtime - -// sigFromUser reports whether the signal was sent because of a call -// to kill. -// -//go:nosplit -func (c *sigctxt) sigFromUser() bool { - return c.sigcode() == _SI_USER -} diff --git a/contrib/go/_std_1.22/src/runtime/pagetrace_off.go b/contrib/go/_std_1.22/src/runtime/pagetrace_off.go deleted file mode 100644 index 10b44d40ced3..000000000000 --- a/contrib/go/_std_1.22/src/runtime/pagetrace_off.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !goexperiment.pagetrace - -package runtime - -//go:systemstack -func pageTraceAlloc(pp *p, now int64, base, npages uintptr) { -} - -//go:systemstack -func pageTraceFree(pp *p, now int64, base, npages uintptr) { -} - -//go:systemstack -func pageTraceScav(pp *p, now int64, base, npages uintptr) { -} - -type pageTraceBuf struct { -} - -func initPageTrace(env string) { -} - -func finishPageTrace() { -} diff --git a/contrib/go/_std_1.22/src/runtime/pagetrace_on.go b/contrib/go/_std_1.22/src/runtime/pagetrace_on.go deleted file mode 100644 index f82521caadd6..000000000000 --- a/contrib/go/_std_1.22/src/runtime/pagetrace_on.go +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.pagetrace - -// Page tracer. -// -// This file contains an implementation of page trace instrumentation for tracking -// the way the Go runtime manages pages of memory. The trace may be enabled at program -// startup with the GODEBUG option pagetrace. -// -// Each page trace event is either 8 or 16 bytes wide. The first -// 8 bytes follow this format for non-sync events: -// -// [16 timestamp delta][35 base address][10 npages][1 isLarge][2 pageTraceEventType] -// -// If the "large" bit is set then the event is 16 bytes wide with the second 8 byte word -// containing the full npages value (the npages bitfield is 0). -// -// The base address's bottom pageShift bits are always zero hence why we can pack other -// data in there. We ignore the top 16 bits, assuming a 48 bit address space for the -// heap. -// -// The timestamp delta is computed from the difference between the current nanotime -// timestamp and the last sync event's timestamp. The bottom pageTraceTimeLostBits of -// this delta is removed and only the next pageTraceTimeDeltaBits are kept. -// -// A sync event is emitted at the beginning of each trace buffer and whenever the -// timestamp delta would not fit in an event. -// -// Sync events have the following structure: -// -// [61 timestamp or P ID][1 isPID][2 pageTraceSyncEvent] -// -// In essence, the "large" bit repurposed to indicate whether it's a timestamp or a P ID -// (these are typically uint32). Note that we only have 61 bits for the 64-bit timestamp, -// but like for the delta we drop the bottom pageTraceTimeLostBits here as well. - -package runtime - -import ( - "runtime/internal/sys" - "unsafe" -) - -// pageTraceAlloc records a page trace allocation event. -// pp may be nil. Call only if debug.pagetracefd != 0. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func pageTraceAlloc(pp *p, now int64, base, npages uintptr) { - if pageTrace.enabled { - if now == 0 { - now = nanotime() - } - pageTraceEmit(pp, now, base, npages, pageTraceAllocEvent) - } -} - -// pageTraceFree records a page trace free event. -// pp may be nil. Call only if debug.pagetracefd != 0. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func pageTraceFree(pp *p, now int64, base, npages uintptr) { - if pageTrace.enabled { - if now == 0 { - now = nanotime() - } - pageTraceEmit(pp, now, base, npages, pageTraceFreeEvent) - } -} - -// pageTraceScav records a page trace scavenge event. -// pp may be nil. Call only if debug.pagetracefd != 0. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func pageTraceScav(pp *p, now int64, base, npages uintptr) { - if pageTrace.enabled { - if now == 0 { - now = nanotime() - } - pageTraceEmit(pp, now, base, npages, pageTraceScavEvent) - } -} - -// pageTraceEventType is a page trace event type. -type pageTraceEventType uint8 - -const ( - pageTraceSyncEvent pageTraceEventType = iota // Timestamp emission. - pageTraceAllocEvent // Allocation of pages. - pageTraceFreeEvent // Freeing pages. - pageTraceScavEvent // Scavenging pages. -) - -// pageTraceEmit emits a page trace event. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func pageTraceEmit(pp *p, now int64, base, npages uintptr, typ pageTraceEventType) { - // Get a buffer. - var tbp *pageTraceBuf - pid := int32(-1) - if pp == nil { - // We have no P, so take the global buffer. - lock(&pageTrace.lock) - tbp = &pageTrace.buf - } else { - tbp = &pp.pageTraceBuf - pid = pp.id - } - - // Initialize the buffer if necessary. - tb := *tbp - if tb.buf == nil { - tb.buf = (*pageTraceEvents)(sysAlloc(pageTraceBufSize, &memstats.other_sys)) - tb = tb.writePid(pid) - } - - // Handle timestamp and emit a sync event if necessary. - if now < tb.timeBase { - now = tb.timeBase - } - if now-tb.timeBase >= pageTraceTimeMaxDelta { - tb.timeBase = now - tb = tb.writeSync(pid) - } - - // Emit the event. - tb = tb.writeEvent(pid, now, base, npages, typ) - - // Write back the buffer. - *tbp = tb - if pp == nil { - unlock(&pageTrace.lock) - } -} - -const ( - pageTraceBufSize = 32 << 10 - - // These constants describe the per-event timestamp delta encoding. - pageTraceTimeLostBits = 7 // How many bits of precision we lose in the delta. - pageTraceTimeDeltaBits = 16 // Size of the delta in bits. - pageTraceTimeMaxDelta = 1 << (pageTraceTimeLostBits + pageTraceTimeDeltaBits) -) - -// pageTraceEvents is the low-level buffer containing the trace data. -type pageTraceEvents struct { - _ sys.NotInHeap - events [pageTraceBufSize / 8]uint64 -} - -// pageTraceBuf is a wrapper around pageTraceEvents that knows how to write events -// to the buffer. It tracks state necessary to do so. -type pageTraceBuf struct { - buf *pageTraceEvents - len int // How many events have been written so far. - timeBase int64 // The current timestamp base from which deltas are produced. - finished bool // Whether this trace buf should no longer flush anything out. -} - -// writePid writes a P ID event indicating which P we're running on. -// -// Assumes there's always space in the buffer since this is only called at the -// beginning of a new buffer. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func (tb pageTraceBuf) writePid(pid int32) pageTraceBuf { - e := uint64(int64(pid))<<3 | 0b100 | uint64(pageTraceSyncEvent) - tb.buf.events[tb.len] = e - tb.len++ - return tb -} - -// writeSync writes a sync event, which is just a timestamp. Handles flushing. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func (tb pageTraceBuf) writeSync(pid int32) pageTraceBuf { - if tb.len+1 > len(tb.buf.events) { - // N.B. flush will writeSync again. - return tb.flush(pid, tb.timeBase) - } - e := ((uint64(tb.timeBase) >> pageTraceTimeLostBits) << 3) | uint64(pageTraceSyncEvent) - tb.buf.events[tb.len] = e - tb.len++ - return tb -} - -// writeEvent handles writing all non-sync and non-pid events. Handles flushing if necessary. -// -// pid indicates the P we're currently running on. Necessary in case we need to flush. -// now is the current nanotime timestamp. -// base is the base address of whatever group of pages this event is happening to. -// npages is the length of the group of pages this event is happening to. -// typ is the event that's happening to these pages. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func (tb pageTraceBuf) writeEvent(pid int32, now int64, base, npages uintptr, typ pageTraceEventType) pageTraceBuf { - large := 0 - np := npages - if npages >= 1024 { - large = 1 - np = 0 - } - if tb.len+1+large > len(tb.buf.events) { - tb = tb.flush(pid, now) - } - if base%pageSize != 0 { - throw("base address not page aligned") - } - e := uint64(base) - // The pageShift low-order bits are zero. - e |= uint64(typ) // 2 bits - e |= uint64(large) << 2 // 1 bit - e |= uint64(np) << 3 // 10 bits - // Write the timestamp delta in the upper pageTraceTimeDeltaBits. - e |= uint64((now-tb.timeBase)>>pageTraceTimeLostBits) << (64 - pageTraceTimeDeltaBits) - tb.buf.events[tb.len] = e - if large != 0 { - // npages doesn't fit in 10 bits, so write an additional word with that data. - tb.buf.events[tb.len+1] = uint64(npages) - } - tb.len += 1 + large - return tb -} - -// flush writes out the contents of the buffer to pageTrace.fd and resets the buffer. -// It then writes out a P ID event and the first sync event for the new buffer. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func (tb pageTraceBuf) flush(pid int32, now int64) pageTraceBuf { - if !tb.finished { - lock(&pageTrace.fdLock) - writeFull(uintptr(pageTrace.fd), (*byte)(unsafe.Pointer(&tb.buf.events[0])), tb.len*8) - unlock(&pageTrace.fdLock) - } - tb.len = 0 - tb.timeBase = now - return tb.writePid(pid).writeSync(pid) -} - -var pageTrace struct { - // enabled indicates whether tracing is enabled. If true, fd >= 0. - // - // Safe to read without synchronization because it's only set once - // at program initialization. - enabled bool - - // buf is the page trace buffer used if there is no P. - // - // lock protects buf. - lock mutex - buf pageTraceBuf - - // fdLock protects writing to fd. - // - // fd is the file to write the page trace to. - fdLock mutex - fd int32 -} - -// initPageTrace initializes the page tracing infrastructure from GODEBUG. -// -// env must be the value of the GODEBUG environment variable. -func initPageTrace(env string) { - var value string - for env != "" { - elt, rest := env, "" - for i := 0; i < len(env); i++ { - if env[i] == ',' { - elt, rest = env[:i], env[i+1:] - break - } - } - env = rest - if hasPrefix(elt, "pagetrace=") { - value = elt[len("pagetrace="):] - break - } - } - pageTrace.fd = -1 - if canCreateFile && value != "" { - var tmp [4096]byte - if len(value) != 0 && len(value) < 4096 { - copy(tmp[:], value) - pageTrace.fd = create(&tmp[0], 0o664) - } - } - pageTrace.enabled = pageTrace.fd >= 0 -} - -// finishPageTrace flushes all P's trace buffers and disables page tracing. -func finishPageTrace() { - if !pageTrace.enabled { - return - } - // Grab worldsema as we're about to execute a ragged barrier. - semacquire(&worldsema) - systemstack(func() { - // Disable tracing. This isn't strictly necessary and it's best-effort. - pageTrace.enabled = false - - // Execute a ragged barrier, flushing each trace buffer. - forEachP(waitReasonPageTraceFlush, func(pp *p) { - if pp.pageTraceBuf.buf != nil { - pp.pageTraceBuf = pp.pageTraceBuf.flush(pp.id, nanotime()) - } - pp.pageTraceBuf.finished = true - }) - - // Write the global have-no-P buffer. - lock(&pageTrace.lock) - if pageTrace.buf.buf != nil { - pageTrace.buf = pageTrace.buf.flush(-1, nanotime()) - } - pageTrace.buf.finished = true - unlock(&pageTrace.lock) - - // Safely close the file as nothing else should be allowed to write to the fd. - lock(&pageTrace.fdLock) - closefd(pageTrace.fd) - pageTrace.fd = -1 - unlock(&pageTrace.fdLock) - }) - semrelease(&worldsema) -} - -// writeFull ensures that a complete write of bn bytes from b is made to fd. -func writeFull(fd uintptr, b *byte, bn int) { - for bn > 0 { - n := write(fd, unsafe.Pointer(b), int32(bn)) - if n == -_EINTR || n == -_EAGAIN { - continue - } - if n < 0 { - print("errno=", -n, "\n") - throw("writeBytes: bad write") - } - bn -= int(n) - b = addb(b, uintptr(n)) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pprof.go b/contrib/go/_std_1.22/src/runtime/pprof/pprof.go deleted file mode 100644 index a4dcf3350826..000000000000 --- a/contrib/go/_std_1.22/src/runtime/pprof/pprof.go +++ /dev/null @@ -1,950 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package pprof writes runtime profiling data in the format expected -// by the pprof visualization tool. -// -// # Profiling a Go program -// -// The first step to profiling a Go program is to enable profiling. -// Support for profiling benchmarks built with the standard testing -// package is built into go test. For example, the following command -// runs benchmarks in the current directory and writes the CPU and -// memory profiles to cpu.prof and mem.prof: -// -// go test -cpuprofile cpu.prof -memprofile mem.prof -bench . -// -// To add equivalent profiling support to a standalone program, add -// code like the following to your main function: -// -// var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") -// var memprofile = flag.String("memprofile", "", "write memory profile to `file`") -// -// func main() { -// flag.Parse() -// if *cpuprofile != "" { -// f, err := os.Create(*cpuprofile) -// if err != nil { -// log.Fatal("could not create CPU profile: ", err) -// } -// defer f.Close() // error handling omitted for example -// if err := pprof.StartCPUProfile(f); err != nil { -// log.Fatal("could not start CPU profile: ", err) -// } -// defer pprof.StopCPUProfile() -// } -// -// // ... rest of the program ... -// -// if *memprofile != "" { -// f, err := os.Create(*memprofile) -// if err != nil { -// log.Fatal("could not create memory profile: ", err) -// } -// defer f.Close() // error handling omitted for example -// runtime.GC() // get up-to-date statistics -// if err := pprof.WriteHeapProfile(f); err != nil { -// log.Fatal("could not write memory profile: ", err) -// } -// } -// } -// -// There is also a standard HTTP interface to profiling data. Adding -// the following line will install handlers under the /debug/pprof/ -// URL to download live profiles: -// -// import _ "net/http/pprof" -// -// See the net/http/pprof package for more details. -// -// Profiles can then be visualized with the pprof tool: -// -// go tool pprof cpu.prof -// -// There are many commands available from the pprof command line. -// Commonly used commands include "top", which prints a summary of the -// top program hot-spots, and "web", which opens an interactive graph -// of hot-spots and their call graphs. Use "help" for information on -// all pprof commands. -// -// For more information about pprof, see -// https://github.com/google/pprof/blob/main/doc/README.md. -package pprof - -import ( - "bufio" - "fmt" - "internal/abi" - "io" - "runtime" - "sort" - "strings" - "sync" - "text/tabwriter" - "time" - "unsafe" -) - -// BUG(rsc): Profiles are only as good as the kernel support used to generate them. -// See https://golang.org/issue/13841 for details about known problems. - -// A Profile is a collection of stack traces showing the call sequences -// that led to instances of a particular event, such as allocation. -// Packages can create and maintain their own profiles; the most common -// use is for tracking resources that must be explicitly closed, such as files -// or network connections. -// -// A Profile's methods can be called from multiple goroutines simultaneously. -// -// Each Profile has a unique name. A few profiles are predefined: -// -// goroutine - stack traces of all current goroutines -// heap - a sampling of memory allocations of live objects -// allocs - a sampling of all past memory allocations -// threadcreate - stack traces that led to the creation of new OS threads -// block - stack traces that led to blocking on synchronization primitives -// mutex - stack traces of holders of contended mutexes -// -// These predefined profiles maintain themselves and panic on an explicit -// [Profile.Add] or [Profile.Remove] method call. -// -// The CPU profile is not available as a Profile. It has a special API, -// the [StartCPUProfile] and [StopCPUProfile] functions, because it streams -// output to a writer during profiling. -// -// # Heap profile -// -// The heap profile reports statistics as of the most recently completed -// garbage collection; it elides more recent allocation to avoid skewing -// the profile away from live data and toward garbage. -// If there has been no garbage collection at all, the heap profile reports -// all known allocations. This exception helps mainly in programs running -// without garbage collection enabled, usually for debugging purposes. -// -// The heap profile tracks both the allocation sites for all live objects in -// the application memory and for all objects allocated since the program start. -// Pprof's -inuse_space, -inuse_objects, -alloc_space, and -alloc_objects -// flags select which to display, defaulting to -inuse_space (live objects, -// scaled by size). -// -// # Allocs profile -// -// The allocs profile is the same as the heap profile but changes the default -// pprof display to -alloc_space, the total number of bytes allocated since -// the program began (including garbage-collected bytes). -// -// # Block profile -// -// The block profile tracks time spent blocked on synchronization primitives, -// such as [sync.Mutex], [sync.RWMutex], [sync.WaitGroup], [sync.Cond], and -// channel send/receive/select. -// -// Stack traces correspond to the location that blocked (for example, -// [sync.Mutex.Lock]). -// -// Sample values correspond to cumulative time spent blocked at that stack -// trace, subject to time-based sampling specified by -// [runtime.SetBlockProfileRate]. -// -// # Mutex profile -// -// The mutex profile tracks contention on mutexes, such as [sync.Mutex], -// [sync.RWMutex], and runtime-internal locks. -// -// Stack traces correspond to the end of the critical section causing -// contention. For example, a lock held for a long time while other goroutines -// are waiting to acquire the lock will report contention when the lock is -// finally unlocked (that is, at [sync.Mutex.Unlock]). -// -// Sample values correspond to the approximate cumulative time other goroutines -// spent blocked waiting for the lock, subject to event-based sampling -// specified by [runtime.SetMutexProfileFraction]. For example, if a caller -// holds a lock for 1s while 5 other goroutines are waiting for the entire -// second to acquire the lock, its unlock call stack will report 5s of -// contention. -// -// Runtime-internal locks are always reported at the location -// "runtime._LostContendedRuntimeLock". More detailed stack traces for -// runtime-internal locks can be obtained by setting -// `GODEBUG=runtimecontentionstacks=1` (see package [runtime] docs for -// caveats). -type Profile struct { - name string - mu sync.Mutex - m map[any][]uintptr - count func() int - write func(io.Writer, int) error -} - -// profiles records all registered profiles. -var profiles struct { - mu sync.Mutex - m map[string]*Profile -} - -var goroutineProfile = &Profile{ - name: "goroutine", - count: countGoroutine, - write: writeGoroutine, -} - -var threadcreateProfile = &Profile{ - name: "threadcreate", - count: countThreadCreate, - write: writeThreadCreate, -} - -var heapProfile = &Profile{ - name: "heap", - count: countHeap, - write: writeHeap, -} - -var allocsProfile = &Profile{ - name: "allocs", - count: countHeap, // identical to heap profile - write: writeAlloc, -} - -var blockProfile = &Profile{ - name: "block", - count: countBlock, - write: writeBlock, -} - -var mutexProfile = &Profile{ - name: "mutex", - count: countMutex, - write: writeMutex, -} - -func lockProfiles() { - profiles.mu.Lock() - if profiles.m == nil { - // Initial built-in profiles. - profiles.m = map[string]*Profile{ - "goroutine": goroutineProfile, - "threadcreate": threadcreateProfile, - "heap": heapProfile, - "allocs": allocsProfile, - "block": blockProfile, - "mutex": mutexProfile, - } - } -} - -func unlockProfiles() { - profiles.mu.Unlock() -} - -// NewProfile creates a new profile with the given name. -// If a profile with that name already exists, NewProfile panics. -// The convention is to use a 'import/path.' prefix to create -// separate name spaces for each package. -// For compatibility with various tools that read pprof data, -// profile names should not contain spaces. -func NewProfile(name string) *Profile { - lockProfiles() - defer unlockProfiles() - if name == "" { - panic("pprof: NewProfile with empty name") - } - if profiles.m[name] != nil { - panic("pprof: NewProfile name already in use: " + name) - } - p := &Profile{ - name: name, - m: map[any][]uintptr{}, - } - profiles.m[name] = p - return p -} - -// Lookup returns the profile with the given name, or nil if no such profile exists. -func Lookup(name string) *Profile { - lockProfiles() - defer unlockProfiles() - return profiles.m[name] -} - -// Profiles returns a slice of all the known profiles, sorted by name. -func Profiles() []*Profile { - lockProfiles() - defer unlockProfiles() - - all := make([]*Profile, 0, len(profiles.m)) - for _, p := range profiles.m { - all = append(all, p) - } - - sort.Slice(all, func(i, j int) bool { return all[i].name < all[j].name }) - return all -} - -// Name returns this profile's name, which can be passed to [Lookup] to reobtain the profile. -func (p *Profile) Name() string { - return p.name -} - -// Count returns the number of execution stacks currently in the profile. -func (p *Profile) Count() int { - p.mu.Lock() - defer p.mu.Unlock() - if p.count != nil { - return p.count() - } - return len(p.m) -} - -// Add adds the current execution stack to the profile, associated with value. -// Add stores value in an internal map, so value must be suitable for use as -// a map key and will not be garbage collected until the corresponding -// call to [Profile.Remove]. Add panics if the profile already contains a stack for value. -// -// The skip parameter has the same meaning as [runtime.Caller]'s skip -// and controls where the stack trace begins. Passing skip=0 begins the -// trace in the function calling Add. For example, given this -// execution stack: -// -// Add -// called from rpc.NewClient -// called from mypkg.Run -// called from main.main -// -// Passing skip=0 begins the stack trace at the call to Add inside rpc.NewClient. -// Passing skip=1 begins the stack trace at the call to NewClient inside mypkg.Run. -func (p *Profile) Add(value any, skip int) { - if p.name == "" { - panic("pprof: use of uninitialized Profile") - } - if p.write != nil { - panic("pprof: Add called on built-in Profile " + p.name) - } - - stk := make([]uintptr, 32) - n := runtime.Callers(skip+1, stk[:]) - stk = stk[:n] - if len(stk) == 0 { - // The value for skip is too large, and there's no stack trace to record. - stk = []uintptr{abi.FuncPCABIInternal(lostProfileEvent)} - } - - p.mu.Lock() - defer p.mu.Unlock() - if p.m[value] != nil { - panic("pprof: Profile.Add of duplicate value") - } - p.m[value] = stk -} - -// Remove removes the execution stack associated with value from the profile. -// It is a no-op if the value is not in the profile. -func (p *Profile) Remove(value any) { - p.mu.Lock() - defer p.mu.Unlock() - delete(p.m, value) -} - -// WriteTo writes a pprof-formatted snapshot of the profile to w. -// If a write to w returns an error, WriteTo returns that error. -// Otherwise, WriteTo returns nil. -// -// The debug parameter enables additional output. -// Passing debug=0 writes the gzip-compressed protocol buffer described -// in https://github.com/google/pprof/tree/master/proto#overview. -// Passing debug=1 writes the legacy text format with comments -// translating addresses to function names and line numbers, so that a -// programmer can read the profile without tools. -// -// The predefined profiles may assign meaning to other debug values; -// for example, when printing the "goroutine" profile, debug=2 means to -// print the goroutine stacks in the same form that a Go program uses -// when dying due to an unrecovered panic. -func (p *Profile) WriteTo(w io.Writer, debug int) error { - if p.name == "" { - panic("pprof: use of zero Profile") - } - if p.write != nil { - return p.write(w, debug) - } - - // Obtain consistent snapshot under lock; then process without lock. - p.mu.Lock() - all := make([][]uintptr, 0, len(p.m)) - for _, stk := range p.m { - all = append(all, stk) - } - p.mu.Unlock() - - // Map order is non-deterministic; make output deterministic. - sort.Slice(all, func(i, j int) bool { - t, u := all[i], all[j] - for k := 0; k < len(t) && k < len(u); k++ { - if t[k] != u[k] { - return t[k] < u[k] - } - } - return len(t) < len(u) - }) - - return printCountProfile(w, debug, p.name, stackProfile(all)) -} - -type stackProfile [][]uintptr - -func (x stackProfile) Len() int { return len(x) } -func (x stackProfile) Stack(i int) []uintptr { return x[i] } -func (x stackProfile) Label(i int) *labelMap { return nil } - -// A countProfile is a set of stack traces to be printed as counts -// grouped by stack trace. There are multiple implementations: -// all that matters is that we can find out how many traces there are -// and obtain each trace in turn. -type countProfile interface { - Len() int - Stack(i int) []uintptr - Label(i int) *labelMap -} - -// printCountCycleProfile outputs block profile records (for block or mutex profiles) -// as the pprof-proto format output. Translations from cycle count to time duration -// are done because The proto expects count and time (nanoseconds) instead of count -// and the number of cycles for block, contention profiles. -func printCountCycleProfile(w io.Writer, countName, cycleName string, records []runtime.BlockProfileRecord) error { - // Output profile in protobuf form. - b := newProfileBuilder(w) - b.pbValueType(tagProfile_PeriodType, countName, "count") - b.pb.int64Opt(tagProfile_Period, 1) - b.pbValueType(tagProfile_SampleType, countName, "count") - b.pbValueType(tagProfile_SampleType, cycleName, "nanoseconds") - - cpuGHz := float64(runtime_cyclesPerSecond()) / 1e9 - - values := []int64{0, 0} - var locs []uint64 - for _, r := range records { - values[0] = r.Count - values[1] = int64(float64(r.Cycles) / cpuGHz) - // For count profiles, all stack addresses are - // return PCs, which is what appendLocsForStack expects. - locs = b.appendLocsForStack(locs[:0], r.Stack()) - b.pbSample(values, locs, nil) - } - b.build() - return nil -} - -// printCountProfile prints a countProfile at the specified debug level. -// The profile will be in compressed proto format unless debug is nonzero. -func printCountProfile(w io.Writer, debug int, name string, p countProfile) error { - // Build count of each stack. - var buf strings.Builder - key := func(stk []uintptr, lbls *labelMap) string { - buf.Reset() - fmt.Fprintf(&buf, "@") - for _, pc := range stk { - fmt.Fprintf(&buf, " %#x", pc) - } - if lbls != nil { - buf.WriteString("\n# labels: ") - buf.WriteString(lbls.String()) - } - return buf.String() - } - count := map[string]int{} - index := map[string]int{} - var keys []string - n := p.Len() - for i := 0; i < n; i++ { - k := key(p.Stack(i), p.Label(i)) - if count[k] == 0 { - index[k] = i - keys = append(keys, k) - } - count[k]++ - } - - sort.Sort(&keysByCount{keys, count}) - - if debug > 0 { - // Print debug profile in legacy format - tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) - fmt.Fprintf(tw, "%s profile: total %d\n", name, p.Len()) - for _, k := range keys { - fmt.Fprintf(tw, "%d %s\n", count[k], k) - printStackRecord(tw, p.Stack(index[k]), false) - } - return tw.Flush() - } - - // Output profile in protobuf form. - b := newProfileBuilder(w) - b.pbValueType(tagProfile_PeriodType, name, "count") - b.pb.int64Opt(tagProfile_Period, 1) - b.pbValueType(tagProfile_SampleType, name, "count") - - values := []int64{0} - var locs []uint64 - for _, k := range keys { - values[0] = int64(count[k]) - // For count profiles, all stack addresses are - // return PCs, which is what appendLocsForStack expects. - locs = b.appendLocsForStack(locs[:0], p.Stack(index[k])) - idx := index[k] - var labels func() - if p.Label(idx) != nil { - labels = func() { - for k, v := range *p.Label(idx) { - b.pbLabel(tagSample_Label, k, v, 0) - } - } - } - b.pbSample(values, locs, labels) - } - b.build() - return nil -} - -// keysByCount sorts keys with higher counts first, breaking ties by key string order. -type keysByCount struct { - keys []string - count map[string]int -} - -func (x *keysByCount) Len() int { return len(x.keys) } -func (x *keysByCount) Swap(i, j int) { x.keys[i], x.keys[j] = x.keys[j], x.keys[i] } -func (x *keysByCount) Less(i, j int) bool { - ki, kj := x.keys[i], x.keys[j] - ci, cj := x.count[ki], x.count[kj] - if ci != cj { - return ci > cj - } - return ki < kj -} - -// printStackRecord prints the function + source line information -// for a single stack trace. -func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) { - show := allFrames - frames := runtime.CallersFrames(stk) - for { - frame, more := frames.Next() - name := frame.Function - if name == "" { - show = true - fmt.Fprintf(w, "#\t%#x\n", frame.PC) - } else if name != "runtime.goexit" && (show || !strings.HasPrefix(name, "runtime.")) { - // Hide runtime.goexit and any runtime functions at the beginning. - // This is useful mainly for allocation traces. - show = true - fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", frame.PC, name, frame.PC-frame.Entry, frame.File, frame.Line) - } - if !more { - break - } - } - if !show { - // We didn't print anything; do it again, - // and this time include runtime functions. - printStackRecord(w, stk, true) - return - } - fmt.Fprintf(w, "\n") -} - -// Interface to system profiles. - -// WriteHeapProfile is shorthand for [Lookup]("heap").WriteTo(w, 0). -// It is preserved for backwards compatibility. -func WriteHeapProfile(w io.Writer) error { - return writeHeap(w, 0) -} - -// countHeap returns the number of records in the heap profile. -func countHeap() int { - n, _ := runtime.MemProfile(nil, true) - return n -} - -// writeHeap writes the current runtime heap profile to w. -func writeHeap(w io.Writer, debug int) error { - return writeHeapInternal(w, debug, "") -} - -// writeAlloc writes the current runtime heap profile to w -// with the total allocation space as the default sample type. -func writeAlloc(w io.Writer, debug int) error { - return writeHeapInternal(w, debug, "alloc_space") -} - -func writeHeapInternal(w io.Writer, debug int, defaultSampleType string) error { - var memStats *runtime.MemStats - if debug != 0 { - // Read mem stats first, so that our other allocations - // do not appear in the statistics. - memStats = new(runtime.MemStats) - runtime.ReadMemStats(memStats) - } - - // Find out how many records there are (MemProfile(nil, true)), - // allocate that many records, and get the data. - // There's a race—more records might be added between - // the two calls—so allocate a few extra records for safety - // and also try again if we're very unlucky. - // The loop should only execute one iteration in the common case. - var p []runtime.MemProfileRecord - n, ok := runtime.MemProfile(nil, true) - for { - // Allocate room for a slightly bigger profile, - // in case a few more entries have been added - // since the call to MemProfile. - p = make([]runtime.MemProfileRecord, n+50) - n, ok = runtime.MemProfile(p, true) - if ok { - p = p[0:n] - break - } - // Profile grew; try again. - } - - if debug == 0 { - return writeHeapProto(w, p, int64(runtime.MemProfileRate), defaultSampleType) - } - - sort.Slice(p, func(i, j int) bool { return p[i].InUseBytes() > p[j].InUseBytes() }) - - b := bufio.NewWriter(w) - tw := tabwriter.NewWriter(b, 1, 8, 1, '\t', 0) - w = tw - - var total runtime.MemProfileRecord - for i := range p { - r := &p[i] - total.AllocBytes += r.AllocBytes - total.AllocObjects += r.AllocObjects - total.FreeBytes += r.FreeBytes - total.FreeObjects += r.FreeObjects - } - - // Technically the rate is MemProfileRate not 2*MemProfileRate, - // but early versions of the C++ heap profiler reported 2*MemProfileRate, - // so that's what pprof has come to expect. - rate := 2 * runtime.MemProfileRate - - // pprof reads a profile with alloc == inuse as being a "2-column" profile - // (objects and bytes, not distinguishing alloc from inuse), - // but then such a profile can't be merged using pprof *.prof with - // other 4-column profiles where alloc != inuse. - // The easiest way to avoid this bug is to adjust allocBytes so it's never == inuseBytes. - // pprof doesn't use these header values anymore except for checking equality. - inUseBytes := total.InUseBytes() - allocBytes := total.AllocBytes - if inUseBytes == allocBytes { - allocBytes++ - } - - fmt.Fprintf(w, "heap profile: %d: %d [%d: %d] @ heap/%d\n", - total.InUseObjects(), inUseBytes, - total.AllocObjects, allocBytes, - rate) - - for i := range p { - r := &p[i] - fmt.Fprintf(w, "%d: %d [%d: %d] @", - r.InUseObjects(), r.InUseBytes(), - r.AllocObjects, r.AllocBytes) - for _, pc := range r.Stack() { - fmt.Fprintf(w, " %#x", pc) - } - fmt.Fprintf(w, "\n") - printStackRecord(w, r.Stack(), false) - } - - // Print memstats information too. - // Pprof will ignore, but useful for people - s := memStats - fmt.Fprintf(w, "\n# runtime.MemStats\n") - fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc) - fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc) - fmt.Fprintf(w, "# Sys = %d\n", s.Sys) - fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups) - fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs) - fmt.Fprintf(w, "# Frees = %d\n", s.Frees) - - fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc) - fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys) - fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle) - fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse) - fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased) - fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects) - - fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys) - fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys) - fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys) - fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys) - fmt.Fprintf(w, "# GCSys = %d\n", s.GCSys) - fmt.Fprintf(w, "# OtherSys = %d\n", s.OtherSys) - - fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC) - fmt.Fprintf(w, "# LastGC = %d\n", s.LastGC) - fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs) - fmt.Fprintf(w, "# PauseEnd = %d\n", s.PauseEnd) - fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC) - fmt.Fprintf(w, "# NumForcedGC = %d\n", s.NumForcedGC) - fmt.Fprintf(w, "# GCCPUFraction = %v\n", s.GCCPUFraction) - fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC) - - // Also flush out MaxRSS on supported platforms. - addMaxRSS(w) - - tw.Flush() - return b.Flush() -} - -// countThreadCreate returns the size of the current ThreadCreateProfile. -func countThreadCreate() int { - n, _ := runtime.ThreadCreateProfile(nil) - return n -} - -// writeThreadCreate writes the current runtime ThreadCreateProfile to w. -func writeThreadCreate(w io.Writer, debug int) error { - // Until https://golang.org/issues/6104 is addressed, wrap - // ThreadCreateProfile because there's no point in tracking labels when we - // don't get any stack-traces. - return writeRuntimeProfile(w, debug, "threadcreate", func(p []runtime.StackRecord, _ []unsafe.Pointer) (n int, ok bool) { - return runtime.ThreadCreateProfile(p) - }) -} - -// countGoroutine returns the number of goroutines. -func countGoroutine() int { - return runtime.NumGoroutine() -} - -// runtime_goroutineProfileWithLabels is defined in runtime/mprof.go -func runtime_goroutineProfileWithLabels(p []runtime.StackRecord, labels []unsafe.Pointer) (n int, ok bool) - -// writeGoroutine writes the current runtime GoroutineProfile to w. -func writeGoroutine(w io.Writer, debug int) error { - if debug >= 2 { - return writeGoroutineStacks(w) - } - return writeRuntimeProfile(w, debug, "goroutine", runtime_goroutineProfileWithLabels) -} - -func writeGoroutineStacks(w io.Writer) error { - // We don't know how big the buffer needs to be to collect - // all the goroutines. Start with 1 MB and try a few times, doubling each time. - // Give up and use a truncated trace if 64 MB is not enough. - buf := make([]byte, 1<<20) - for i := 0; ; i++ { - n := runtime.Stack(buf, true) - if n < len(buf) { - buf = buf[:n] - break - } - if len(buf) >= 64<<20 { - // Filled 64 MB - stop there. - break - } - buf = make([]byte, 2*len(buf)) - } - _, err := w.Write(buf) - return err -} - -func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runtime.StackRecord, []unsafe.Pointer) (int, bool)) error { - // Find out how many records there are (fetch(nil)), - // allocate that many records, and get the data. - // There's a race—more records might be added between - // the two calls—so allocate a few extra records for safety - // and also try again if we're very unlucky. - // The loop should only execute one iteration in the common case. - var p []runtime.StackRecord - var labels []unsafe.Pointer - n, ok := fetch(nil, nil) - for { - // Allocate room for a slightly bigger profile, - // in case a few more entries have been added - // since the call to ThreadProfile. - p = make([]runtime.StackRecord, n+10) - labels = make([]unsafe.Pointer, n+10) - n, ok = fetch(p, labels) - if ok { - p = p[0:n] - break - } - // Profile grew; try again. - } - - return printCountProfile(w, debug, name, &runtimeProfile{p, labels}) -} - -type runtimeProfile struct { - stk []runtime.StackRecord - labels []unsafe.Pointer -} - -func (p *runtimeProfile) Len() int { return len(p.stk) } -func (p *runtimeProfile) Stack(i int) []uintptr { return p.stk[i].Stack() } -func (p *runtimeProfile) Label(i int) *labelMap { return (*labelMap)(p.labels[i]) } - -var cpu struct { - sync.Mutex - profiling bool - done chan bool -} - -// StartCPUProfile enables CPU profiling for the current process. -// While profiling, the profile will be buffered and written to w. -// StartCPUProfile returns an error if profiling is already enabled. -// -// On Unix-like systems, StartCPUProfile does not work by default for -// Go code built with -buildmode=c-archive or -buildmode=c-shared. -// StartCPUProfile relies on the SIGPROF signal, but that signal will -// be delivered to the main program's SIGPROF signal handler (if any) -// not to the one used by Go. To make it work, call [os/signal.Notify] -// for [syscall.SIGPROF], but note that doing so may break any profiling -// being done by the main program. -func StartCPUProfile(w io.Writer) error { - // The runtime routines allow a variable profiling rate, - // but in practice operating systems cannot trigger signals - // at more than about 500 Hz, and our processing of the - // signal is not cheap (mostly getting the stack trace). - // 100 Hz is a reasonable choice: it is frequent enough to - // produce useful data, rare enough not to bog down the - // system, and a nice round number to make it easy to - // convert sample counts to seconds. Instead of requiring - // each client to specify the frequency, we hard code it. - const hz = 100 - - cpu.Lock() - defer cpu.Unlock() - if cpu.done == nil { - cpu.done = make(chan bool) - } - // Double-check. - if cpu.profiling { - return fmt.Errorf("cpu profiling already in use") - } - cpu.profiling = true - runtime.SetCPUProfileRate(hz) - go profileWriter(w) - return nil -} - -// readProfile, provided by the runtime, returns the next chunk of -// binary CPU profiling stack trace data, blocking until data is available. -// If profiling is turned off and all the profile data accumulated while it was -// on has been returned, readProfile returns eof=true. -// The caller must save the returned data and tags before calling readProfile again. -func readProfile() (data []uint64, tags []unsafe.Pointer, eof bool) - -func profileWriter(w io.Writer) { - b := newProfileBuilder(w) - var err error - for { - time.Sleep(100 * time.Millisecond) - data, tags, eof := readProfile() - if e := b.addCPUData(data, tags); e != nil && err == nil { - err = e - } - if eof { - break - } - } - if err != nil { - // The runtime should never produce an invalid or truncated profile. - // It drops records that can't fit into its log buffers. - panic("runtime/pprof: converting profile: " + err.Error()) - } - b.build() - cpu.done <- true -} - -// StopCPUProfile stops the current CPU profile, if any. -// StopCPUProfile only returns after all the writes for the -// profile have completed. -func StopCPUProfile() { - cpu.Lock() - defer cpu.Unlock() - - if !cpu.profiling { - return - } - cpu.profiling = false - runtime.SetCPUProfileRate(0) - <-cpu.done -} - -// countBlock returns the number of records in the blocking profile. -func countBlock() int { - n, _ := runtime.BlockProfile(nil) - return n -} - -// countMutex returns the number of records in the mutex profile. -func countMutex() int { - n, _ := runtime.MutexProfile(nil) - return n -} - -// writeBlock writes the current blocking profile to w. -func writeBlock(w io.Writer, debug int) error { - return writeProfileInternal(w, debug, "contention", runtime.BlockProfile) -} - -// writeMutex writes the current mutex profile to w. -func writeMutex(w io.Writer, debug int) error { - return writeProfileInternal(w, debug, "mutex", runtime.MutexProfile) -} - -// writeProfileInternal writes the current blocking or mutex profile depending on the passed parameters. -func writeProfileInternal(w io.Writer, debug int, name string, runtimeProfile func([]runtime.BlockProfileRecord) (int, bool)) error { - var p []runtime.BlockProfileRecord - n, ok := runtimeProfile(nil) - for { - p = make([]runtime.BlockProfileRecord, n+50) - n, ok = runtimeProfile(p) - if ok { - p = p[:n] - break - } - } - - sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles }) - - if debug <= 0 { - return printCountCycleProfile(w, "contentions", "delay", p) - } - - b := bufio.NewWriter(w) - tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) - w = tw - - fmt.Fprintf(w, "--- %v:\n", name) - fmt.Fprintf(w, "cycles/second=%v\n", runtime_cyclesPerSecond()) - if name == "mutex" { - fmt.Fprintf(w, "sampling period=%d\n", runtime.SetMutexProfileFraction(-1)) - } - for i := range p { - r := &p[i] - fmt.Fprintf(w, "%v %v @", r.Cycles, r.Count) - for _, pc := range r.Stack() { - fmt.Fprintf(w, " %#x", pc) - } - fmt.Fprint(w, "\n") - if debug > 0 { - printStackRecord(w, r.Stack(), true) - } - } - - if tw != nil { - tw.Flush() - } - return b.Flush() -} - -func runtime_cyclesPerSecond() int64 diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pprof_norusage.go b/contrib/go/_std_1.22/src/runtime/pprof/pprof_norusage.go deleted file mode 100644 index 8de38086c716..000000000000 --- a/contrib/go/_std_1.22/src/runtime/pprof/pprof_norusage.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows - -package pprof - -import ( - "io" -) - -// Stub call for platforms that don't support rusage. -func addMaxRSS(w io.Writer) { -} diff --git a/contrib/go/_std_1.22/src/runtime/pprof/ya.make b/contrib/go/_std_1.22/src/runtime/pprof/ya.make deleted file mode 100644 index 6849450c60c0..000000000000 --- a/contrib/go/_std_1.22/src/runtime/pprof/ya.make +++ /dev/null @@ -1,65 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - defs_darwin_arm64.go - elf.go - label.go - map.go - pe.go - pprof.go - pprof_rusage.go - proto.go - proto_darwin.go - protobuf.go - protomem.go - runtime.go - vminfo_darwin.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - defs_darwin_amd64.go - elf.go - label.go - map.go - pe.go - pprof.go - pprof_rusage.go - proto.go - proto_darwin.go - protobuf.go - protomem.go - runtime.go - vminfo_darwin.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - elf.go - label.go - map.go - pe.go - pprof.go - pprof_rusage.go - proto.go - proto_other.go - protobuf.go - protomem.go - runtime.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - elf.go - label.go - map.go - pe.go - pprof.go - pprof_windows.go - proto.go - proto_windows.go - protobuf.go - protomem.go - runtime.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/runtime/proc.go b/contrib/go/_std_1.22/src/runtime/proc.go deleted file mode 100644 index 061673150f5d..000000000000 --- a/contrib/go/_std_1.22/src/runtime/proc.go +++ /dev/null @@ -1,7198 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/abi" - "internal/cpu" - "internal/goarch" - "internal/goexperiment" - "internal/goos" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -// set using cmd/go/internal/modload.ModInfoProg -var modinfo string - -// Goroutine scheduler -// The scheduler's job is to distribute ready-to-run goroutines over worker threads. -// -// The main concepts are: -// G - goroutine. -// M - worker thread, or machine. -// P - processor, a resource that is required to execute Go code. -// M must have an associated P to execute Go code, however it can be -// blocked or in a syscall w/o an associated P. -// -// Design doc at https://golang.org/s/go11sched. - -// Worker thread parking/unparking. -// We need to balance between keeping enough running worker threads to utilize -// available hardware parallelism and parking excessive running worker threads -// to conserve CPU resources and power. This is not simple for two reasons: -// (1) scheduler state is intentionally distributed (in particular, per-P work -// queues), so it is not possible to compute global predicates on fast paths; -// (2) for optimal thread management we would need to know the future (don't park -// a worker thread when a new goroutine will be readied in near future). -// -// Three rejected approaches that would work badly: -// 1. Centralize all scheduler state (would inhibit scalability). -// 2. Direct goroutine handoff. That is, when we ready a new goroutine and there -// is a spare P, unpark a thread and handoff it the thread and the goroutine. -// This would lead to thread state thrashing, as the thread that readied the -// goroutine can be out of work the very next moment, we will need to park it. -// Also, it would destroy locality of computation as we want to preserve -// dependent goroutines on the same thread; and introduce additional latency. -// 3. Unpark an additional thread whenever we ready a goroutine and there is an -// idle P, but don't do handoff. This would lead to excessive thread parking/ -// unparking as the additional threads will instantly park without discovering -// any work to do. -// -// The current approach: -// -// This approach applies to three primary sources of potential work: readying a -// goroutine, new/modified-earlier timers, and idle-priority GC. See below for -// additional details. -// -// We unpark an additional thread when we submit work if (this is wakep()): -// 1. There is an idle P, and -// 2. There are no "spinning" worker threads. -// -// A worker thread is considered spinning if it is out of local work and did -// not find work in the global run queue or netpoller; the spinning state is -// denoted in m.spinning and in sched.nmspinning. Threads unparked this way are -// also considered spinning; we don't do goroutine handoff so such threads are -// out of work initially. Spinning threads spin on looking for work in per-P -// run queues and timer heaps or from the GC before parking. If a spinning -// thread finds work it takes itself out of the spinning state and proceeds to -// execution. If it does not find work it takes itself out of the spinning -// state and then parks. -// -// If there is at least one spinning thread (sched.nmspinning>1), we don't -// unpark new threads when submitting work. To compensate for that, if the last -// spinning thread finds work and stops spinning, it must unpark a new spinning -// thread. This approach smooths out unjustified spikes of thread unparking, -// but at the same time guarantees eventual maximal CPU parallelism -// utilization. -// -// The main implementation complication is that we need to be very careful -// during spinning->non-spinning thread transition. This transition can race -// with submission of new work, and either one part or another needs to unpark -// another worker thread. If they both fail to do that, we can end up with -// semi-persistent CPU underutilization. -// -// The general pattern for submission is: -// 1. Submit work to the local or global run queue, timer heap, or GC state. -// 2. #StoreLoad-style memory barrier. -// 3. Check sched.nmspinning. -// -// The general pattern for spinning->non-spinning transition is: -// 1. Decrement nmspinning. -// 2. #StoreLoad-style memory barrier. -// 3. Check all per-P work queues and GC for new work. -// -// Note that all this complexity does not apply to global run queue as we are -// not sloppy about thread unparking when submitting to global queue. Also see -// comments for nmspinning manipulation. -// -// How these different sources of work behave varies, though it doesn't affect -// the synchronization approach: -// * Ready goroutine: this is an obvious source of work; the goroutine is -// immediately ready and must run on some thread eventually. -// * New/modified-earlier timer: The current timer implementation (see time.go) -// uses netpoll in a thread with no work available to wait for the soonest -// timer. If there is no thread waiting, we want a new spinning thread to go -// wait. -// * Idle-priority GC: The GC wakes a stopped idle thread to contribute to -// background GC work (note: currently disabled per golang.org/issue/19112). -// Also see golang.org/issue/44313, as this should be extended to all GC -// workers. - -var ( - m0 m - g0 g - mcache0 *mcache - raceprocctx0 uintptr - raceFiniLock mutex -) - -// This slice records the initializing tasks that need to be -// done to start up the runtime. It is built by the linker. -var runtime_inittasks []*initTask - -// main_init_done is a signal used by cgocallbackg that initialization -// has been completed. It is made before _cgo_notify_runtime_init_done, -// so all cgo calls can rely on it existing. When main_init is complete, -// it is closed, meaning cgocallbackg can reliably receive from it. -var main_init_done chan bool - -//go:linkname main_main main.main -func main_main() - -// mainStarted indicates that the main M has started. -var mainStarted bool - -// runtimeInitTime is the nanotime() at which the runtime started. -var runtimeInitTime int64 - -// Value to use for signal mask for newly created M's. -var initSigmask sigset - -// The main goroutine. -func main() { - mp := getg().m - - // Racectx of m0->g0 is used only as the parent of the main goroutine. - // It must not be used for anything else. - mp.g0.racectx = 0 - - // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. - // Using decimal instead of binary GB and MB because - // they look nicer in the stack overflow failure message. - if goarch.PtrSize == 8 { - maxstacksize = 1000000000 - } else { - maxstacksize = 250000000 - } - - // An upper limit for max stack size. Used to avoid random crashes - // after calling SetMaxStack and trying to allocate a stack that is too big, - // since stackalloc works with 32-bit sizes. - maxstackceiling = 2 * maxstacksize - - // Allow newproc to start new Ms. - mainStarted = true - - if GOARCH != "wasm" { // no threads on wasm yet, so no sysmon - systemstack(func() { - newm(sysmon, nil, -1) - }) - } - - // Lock the main goroutine onto this, the main OS thread, - // during initialization. Most programs won't care, but a few - // do require certain calls to be made by the main thread. - // Those can arrange for main.main to run in the main thread - // by calling runtime.LockOSThread during initialization - // to preserve the lock. - lockOSThread() - - if mp != &m0 { - throw("runtime.main not on m0") - } - - // Record when the world started. - // Must be before doInit for tracing init. - runtimeInitTime = nanotime() - if runtimeInitTime == 0 { - throw("nanotime returning zero") - } - - if debug.inittrace != 0 { - inittrace.id = getg().goid - inittrace.active = true - } - - doInit(runtime_inittasks) // Must be before defer. - - // Defer unlock so that runtime.Goexit during init does the unlock too. - needUnlock := true - defer func() { - if needUnlock { - unlockOSThread() - } - }() - - gcenable() - - main_init_done = make(chan bool) - if iscgo { - if _cgo_pthread_key_created == nil { - throw("_cgo_pthread_key_created missing") - } - - if _cgo_thread_start == nil { - throw("_cgo_thread_start missing") - } - if GOOS != "windows" { - if _cgo_setenv == nil { - throw("_cgo_setenv missing") - } - if _cgo_unsetenv == nil { - throw("_cgo_unsetenv missing") - } - } - if _cgo_notify_runtime_init_done == nil { - throw("_cgo_notify_runtime_init_done missing") - } - - // Set the x_crosscall2_ptr C function pointer variable point to crosscall2. - if set_crosscall2 == nil { - throw("set_crosscall2 missing") - } - set_crosscall2() - - // Start the template thread in case we enter Go from - // a C-created thread and need to create a new thread. - startTemplateThread() - cgocall(_cgo_notify_runtime_init_done, nil) - } - - // Run the initializing tasks. Depending on build mode this - // list can arrive a few different ways, but it will always - // contain the init tasks computed by the linker for all the - // packages in the program (excluding those added at runtime - // by package plugin). Run through the modules in dependency - // order (the order they are initialized by the dynamic - // loader, i.e. they are added to the moduledata linked list). - for m := &firstmoduledata; m != nil; m = m.next { - doInit(m.inittasks) - } - - // Disable init tracing after main init done to avoid overhead - // of collecting statistics in malloc and newproc - inittrace.active = false - - close(main_init_done) - - needUnlock = false - unlockOSThread() - - if isarchive || islibrary { - // A program compiled with -buildmode=c-archive or c-shared - // has a main, but it is not executed. - return - } - fn := main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime - fn() - if raceenabled { - runExitHooks(0) // run hooks now, since racefini does not return - racefini() - } - - // Make racy client program work: if panicking on - // another goroutine at the same time as main returns, - // let the other goroutine finish printing the panic trace. - // Once it does, it will exit. See issues 3934 and 20018. - if runningPanicDefers.Load() != 0 { - // Running deferred functions should not take long. - for c := 0; c < 1000; c++ { - if runningPanicDefers.Load() == 0 { - break - } - Gosched() - } - } - if panicking.Load() != 0 { - gopark(nil, nil, waitReasonPanicWait, traceBlockForever, 1) - } - runExitHooks(0) - - exit(0) - for { - var x *int32 - *x = 0 - } -} - -// os_beforeExit is called from os.Exit(0). -// -//go:linkname os_beforeExit os.runtime_beforeExit -func os_beforeExit(exitCode int) { - runExitHooks(exitCode) - if exitCode == 0 && raceenabled { - racefini() - } -} - -// start forcegc helper goroutine -func init() { - go forcegchelper() -} - -func forcegchelper() { - forcegc.g = getg() - lockInit(&forcegc.lock, lockRankForcegc) - for { - lock(&forcegc.lock) - if forcegc.idle.Load() { - throw("forcegc: phase error") - } - forcegc.idle.Store(true) - goparkunlock(&forcegc.lock, waitReasonForceGCIdle, traceBlockSystemGoroutine, 1) - // this goroutine is explicitly resumed by sysmon - if debug.gctrace > 0 { - println("GC forced") - } - // Time-triggered, fully concurrent. - gcStart(gcTrigger{kind: gcTriggerTime, now: nanotime()}) - } -} - -// Gosched yields the processor, allowing other goroutines to run. It does not -// suspend the current goroutine, so execution resumes automatically. -// -//go:nosplit -func Gosched() { - checkTimeouts() - mcall(gosched_m) -} - -// goschedguarded yields the processor like gosched, but also checks -// for forbidden states and opts out of the yield in those cases. -// -//go:nosplit -func goschedguarded() { - mcall(goschedguarded_m) -} - -// goschedIfBusy yields the processor like gosched, but only does so if -// there are no idle Ps or if we're on the only P and there's nothing in -// the run queue. In both cases, there is freely available idle time. -// -//go:nosplit -func goschedIfBusy() { - gp := getg() - // Call gosched if gp.preempt is set; we may be in a tight loop that - // doesn't otherwise yield. - if !gp.preempt && sched.npidle.Load() > 0 { - return - } - mcall(gosched_m) -} - -// Puts the current goroutine into a waiting state and calls unlockf on the -// system stack. -// -// If unlockf returns false, the goroutine is resumed. -// -// unlockf must not access this G's stack, as it may be moved between -// the call to gopark and the call to unlockf. -// -// Note that because unlockf is called after putting the G into a waiting -// state, the G may have already been readied by the time unlockf is called -// unless there is external synchronization preventing the G from being -// readied. If unlockf returns false, it must guarantee that the G cannot be -// externally readied. -// -// Reason explains why the goroutine has been parked. It is displayed in stack -// traces and heap dumps. Reasons should be unique and descriptive. Do not -// re-use reasons, add new ones. -func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceReason traceBlockReason, traceskip int) { - if reason != waitReasonSleep { - checkTimeouts() // timeouts may expire while two goroutines keep the scheduler busy - } - mp := acquirem() - gp := mp.curg - status := readgstatus(gp) - if status != _Grunning && status != _Gscanrunning { - throw("gopark: bad g status") - } - mp.waitlock = lock - mp.waitunlockf = unlockf - gp.waitreason = reason - mp.waitTraceBlockReason = traceReason - mp.waitTraceSkip = traceskip - releasem(mp) - // can't do anything that might move the G between Ms here. - mcall(park_m) -} - -// Puts the current goroutine into a waiting state and unlocks the lock. -// The goroutine can be made runnable again by calling goready(gp). -func goparkunlock(lock *mutex, reason waitReason, traceReason traceBlockReason, traceskip int) { - gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceReason, traceskip) -} - -func goready(gp *g, traceskip int) { - systemstack(func() { - ready(gp, traceskip, true) - }) -} - -//go:nosplit -func acquireSudog() *sudog { - // Delicate dance: the semaphore implementation calls - // acquireSudog, acquireSudog calls new(sudog), - // new calls malloc, malloc can call the garbage collector, - // and the garbage collector calls the semaphore implementation - // in stopTheWorld. - // Break the cycle by doing acquirem/releasem around new(sudog). - // The acquirem/releasem increments m.locks during new(sudog), - // which keeps the garbage collector from being invoked. - mp := acquirem() - pp := mp.p.ptr() - if len(pp.sudogcache) == 0 { - lock(&sched.sudoglock) - // First, try to grab a batch from central cache. - for len(pp.sudogcache) < cap(pp.sudogcache)/2 && sched.sudogcache != nil { - s := sched.sudogcache - sched.sudogcache = s.next - s.next = nil - pp.sudogcache = append(pp.sudogcache, s) - } - unlock(&sched.sudoglock) - // If the central cache is empty, allocate a new one. - if len(pp.sudogcache) == 0 { - pp.sudogcache = append(pp.sudogcache, new(sudog)) - } - } - n := len(pp.sudogcache) - s := pp.sudogcache[n-1] - pp.sudogcache[n-1] = nil - pp.sudogcache = pp.sudogcache[:n-1] - if s.elem != nil { - throw("acquireSudog: found s.elem != nil in cache") - } - releasem(mp) - return s -} - -//go:nosplit -func releaseSudog(s *sudog) { - if s.elem != nil { - throw("runtime: sudog with non-nil elem") - } - if s.isSelect { - throw("runtime: sudog with non-false isSelect") - } - if s.next != nil { - throw("runtime: sudog with non-nil next") - } - if s.prev != nil { - throw("runtime: sudog with non-nil prev") - } - if s.waitlink != nil { - throw("runtime: sudog with non-nil waitlink") - } - if s.c != nil { - throw("runtime: sudog with non-nil c") - } - gp := getg() - if gp.param != nil { - throw("runtime: releaseSudog with non-nil gp.param") - } - mp := acquirem() // avoid rescheduling to another P - pp := mp.p.ptr() - if len(pp.sudogcache) == cap(pp.sudogcache) { - // Transfer half of local cache to the central cache. - var first, last *sudog - for len(pp.sudogcache) > cap(pp.sudogcache)/2 { - n := len(pp.sudogcache) - p := pp.sudogcache[n-1] - pp.sudogcache[n-1] = nil - pp.sudogcache = pp.sudogcache[:n-1] - if first == nil { - first = p - } else { - last.next = p - } - last = p - } - lock(&sched.sudoglock) - last.next = sched.sudogcache - sched.sudogcache = first - unlock(&sched.sudoglock) - } - pp.sudogcache = append(pp.sudogcache, s) - releasem(mp) -} - -// called from assembly. -func badmcall(fn func(*g)) { - throw("runtime: mcall called on m->g0 stack") -} - -func badmcall2(fn func(*g)) { - throw("runtime: mcall function returned") -} - -func badreflectcall() { - panic(plainError("arg size to reflect.call more than 1GB")) -} - -//go:nosplit -//go:nowritebarrierrec -func badmorestackg0() { - if !crashStackImplemented { - writeErrStr("fatal: morestack on g0\n") - return - } - - g := getg() - switchToCrashStack(func() { - print("runtime: morestack on g0, stack [", hex(g.stack.lo), " ", hex(g.stack.hi), "], sp=", hex(g.sched.sp), ", called from\n") - g.m.traceback = 2 // include pc and sp in stack trace - traceback1(g.sched.pc, g.sched.sp, g.sched.lr, g, 0) - print("\n") - - throw("morestack on g0") - }) -} - -//go:nosplit -//go:nowritebarrierrec -func badmorestackgsignal() { - writeErrStr("fatal: morestack on gsignal\n") -} - -//go:nosplit -func badctxt() { - throw("ctxt != 0") -} - -// gcrash is a fake g that can be used when crashing due to bad -// stack conditions. -var gcrash g - -var crashingG atomic.Pointer[g] - -// Switch to crashstack and call fn, with special handling of -// concurrent and recursive cases. -// -// Nosplit as it is called in a bad stack condition (we know -// morestack would fail). -// -//go:nosplit -//go:nowritebarrierrec -func switchToCrashStack(fn func()) { - me := getg() - if crashingG.CompareAndSwapNoWB(nil, me) { - switchToCrashStack0(fn) // should never return - abort() - } - if crashingG.Load() == me { - // recursive crashing. too bad. - writeErrStr("fatal: recursive switchToCrashStack\n") - abort() - } - // Another g is crashing. Give it some time, hopefully it will finish traceback. - usleep_no_g(100) - writeErrStr("fatal: concurrent switchToCrashStack\n") - abort() -} - -// Disable crash stack on Windows for now. Apparently, throwing an exception -// on a non-system-allocated crash stack causes EXCEPTION_STACK_OVERFLOW and -// hangs the process (see issue 63938). -const crashStackImplemented = (GOARCH == "amd64" || GOARCH == "arm64" || GOARCH == "mips64" || GOARCH == "mips64le" || GOARCH == "ppc64" || GOARCH == "ppc64le" || GOARCH == "riscv64" || GOARCH == "wasm") && GOOS != "windows" - -//go:noescape -func switchToCrashStack0(fn func()) // in assembly - -func lockedOSThread() bool { - gp := getg() - return gp.lockedm != 0 && gp.m.lockedg != 0 -} - -var ( - // allgs contains all Gs ever created (including dead Gs), and thus - // never shrinks. - // - // Access via the slice is protected by allglock or stop-the-world. - // Readers that cannot take the lock may (carefully!) use the atomic - // variables below. - allglock mutex - allgs []*g - - // allglen and allgptr are atomic variables that contain len(allgs) and - // &allgs[0] respectively. Proper ordering depends on totally-ordered - // loads and stores. Writes are protected by allglock. - // - // allgptr is updated before allglen. Readers should read allglen - // before allgptr to ensure that allglen is always <= len(allgptr). New - // Gs appended during the race can be missed. For a consistent view of - // all Gs, allglock must be held. - // - // allgptr copies should always be stored as a concrete type or - // unsafe.Pointer, not uintptr, to ensure that GC can still reach it - // even if it points to a stale array. - allglen uintptr - allgptr **g -) - -func allgadd(gp *g) { - if readgstatus(gp) == _Gidle { - throw("allgadd: bad status Gidle") - } - - lock(&allglock) - allgs = append(allgs, gp) - if &allgs[0] != allgptr { - atomicstorep(unsafe.Pointer(&allgptr), unsafe.Pointer(&allgs[0])) - } - atomic.Storeuintptr(&allglen, uintptr(len(allgs))) - unlock(&allglock) -} - -// allGsSnapshot returns a snapshot of the slice of all Gs. -// -// The world must be stopped or allglock must be held. -func allGsSnapshot() []*g { - assertWorldStoppedOrLockHeld(&allglock) - - // Because the world is stopped or allglock is held, allgadd - // cannot happen concurrently with this. allgs grows - // monotonically and existing entries never change, so we can - // simply return a copy of the slice header. For added safety, - // we trim everything past len because that can still change. - return allgs[:len(allgs):len(allgs)] -} - -// atomicAllG returns &allgs[0] and len(allgs) for use with atomicAllGIndex. -func atomicAllG() (**g, uintptr) { - length := atomic.Loaduintptr(&allglen) - ptr := (**g)(atomic.Loadp(unsafe.Pointer(&allgptr))) - return ptr, length -} - -// atomicAllGIndex returns ptr[i] with the allgptr returned from atomicAllG. -func atomicAllGIndex(ptr **g, i uintptr) *g { - return *(**g)(add(unsafe.Pointer(ptr), i*goarch.PtrSize)) -} - -// forEachG calls fn on every G from allgs. -// -// forEachG takes a lock to exclude concurrent addition of new Gs. -func forEachG(fn func(gp *g)) { - lock(&allglock) - for _, gp := range allgs { - fn(gp) - } - unlock(&allglock) -} - -// forEachGRace calls fn on every G from allgs. -// -// forEachGRace avoids locking, but does not exclude addition of new Gs during -// execution, which may be missed. -func forEachGRace(fn func(gp *g)) { - ptr, length := atomicAllG() - for i := uintptr(0); i < length; i++ { - gp := atomicAllGIndex(ptr, i) - fn(gp) - } - return -} - -const ( - // Number of goroutine ids to grab from sched.goidgen to local per-P cache at once. - // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number. - _GoidCacheBatch = 16 -) - -// cpuinit sets up CPU feature flags and calls internal/cpu.Initialize. env should be the complete -// value of the GODEBUG environment variable. -func cpuinit(env string) { - switch GOOS { - case "aix", "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "illumos", "solaris", "linux": - cpu.DebugOptions = true - } - cpu.Initialize(env) - - // Support cpu feature variables are used in code generated by the compiler - // to guard execution of instructions that can not be assumed to be always supported. - switch GOARCH { - case "386", "amd64": - x86HasPOPCNT = cpu.X86.HasPOPCNT - x86HasSSE41 = cpu.X86.HasSSE41 - x86HasFMA = cpu.X86.HasFMA - - case "arm": - armHasVFPv4 = cpu.ARM.HasVFPv4 - - case "arm64": - arm64HasATOMICS = cpu.ARM64.HasATOMICS - } -} - -// getGodebugEarly extracts the environment variable GODEBUG from the environment on -// Unix-like operating systems and returns it. This function exists to extract GODEBUG -// early before much of the runtime is initialized. -func getGodebugEarly() string { - const prefix = "GODEBUG=" - var env string - switch GOOS { - case "aix", "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "illumos", "solaris", "linux": - // Similar to goenv_unix but extracts the environment value for - // GODEBUG directly. - // TODO(moehrmann): remove when general goenvs() can be called before cpuinit() - n := int32(0) - for argv_index(argv, argc+1+n) != nil { - n++ - } - - for i := int32(0); i < n; i++ { - p := argv_index(argv, argc+1+i) - s := unsafe.String(p, findnull(p)) - - if hasPrefix(s, prefix) { - env = gostring(p)[len(prefix):] - break - } - } - } - return env -} - -// The bootstrap sequence is: -// -// call osinit -// call schedinit -// make & queue new G -// call runtime·mstart -// -// The new G calls runtime·main. -func schedinit() { - lockInit(&sched.lock, lockRankSched) - lockInit(&sched.sysmonlock, lockRankSysmon) - lockInit(&sched.deferlock, lockRankDefer) - lockInit(&sched.sudoglock, lockRankSudog) - lockInit(&deadlock, lockRankDeadlock) - lockInit(&paniclk, lockRankPanic) - lockInit(&allglock, lockRankAllg) - lockInit(&allpLock, lockRankAllp) - lockInit(&reflectOffs.lock, lockRankReflectOffs) - lockInit(&finlock, lockRankFin) - lockInit(&cpuprof.lock, lockRankCpuprof) - allocmLock.init(lockRankAllocmR, lockRankAllocmRInternal, lockRankAllocmW) - execLock.init(lockRankExecR, lockRankExecRInternal, lockRankExecW) - traceLockInit() - // Enforce that this lock is always a leaf lock. - // All of this lock's critical sections should be - // extremely short. - lockInit(&memstats.heapStats.noPLock, lockRankLeafRank) - - // raceinit must be the first call to race detector. - // In particular, it must be done before mallocinit below calls racemapshadow. - gp := getg() - if raceenabled { - gp.racectx, raceprocctx0 = raceinit() - } - - sched.maxmcount = 10000 - - // The world starts stopped. - worldStopped() - - ticks.init() // run as early as possible - moduledataverify() - stackinit() - mallocinit() - godebug := getGodebugEarly() - initPageTrace(godebug) // must run after mallocinit but before anything allocates - cpuinit(godebug) // must run before alginit - randinit() // must run before alginit, mcommoninit - alginit() // maps, hash, rand must not be used before this call - mcommoninit(gp.m, -1) - modulesinit() // provides activeModules - typelinksinit() // uses maps, activeModules - itabsinit() // uses activeModules - stkobjinit() // must run before GC starts - - sigsave(&gp.m.sigmask) - initSigmask = gp.m.sigmask - - goargs() - goenvs() - secure() - checkfds() - parsedebugvars() - gcinit() - - // Allocate stack space that can be used when crashing due to bad stack - // conditions, e.g. morestack on g0. - gcrash.stack = stackalloc(16384) - gcrash.stackguard0 = gcrash.stack.lo + 1000 - gcrash.stackguard1 = gcrash.stack.lo + 1000 - - // if disableMemoryProfiling is set, update MemProfileRate to 0 to turn off memprofile. - // Note: parsedebugvars may update MemProfileRate, but when disableMemoryProfiling is - // set to true by the linker, it means that nothing is consuming the profile, it is - // safe to set MemProfileRate to 0. - if disableMemoryProfiling { - MemProfileRate = 0 - } - - lock(&sched.lock) - sched.lastpoll.Store(nanotime()) - procs := ncpu - if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 { - procs = n - } - if procresize(procs) != nil { - throw("unknown runnable goroutine during bootstrap") - } - unlock(&sched.lock) - - // World is effectively started now, as P's can run. - worldStarted() - - if buildVersion == "" { - // Condition should never trigger. This code just serves - // to ensure runtime·buildVersion is kept in the resulting binary. - buildVersion = "unknown" - } - if len(modinfo) == 1 { - // Condition should never trigger. This code just serves - // to ensure runtime·modinfo is kept in the resulting binary. - modinfo = "" - } -} - -func dumpgstatus(gp *g) { - thisg := getg() - print("runtime: gp: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n") - print("runtime: getg: g=", thisg, ", goid=", thisg.goid, ", g->atomicstatus=", readgstatus(thisg), "\n") -} - -// sched.lock must be held. -func checkmcount() { - assertLockHeld(&sched.lock) - - // Exclude extra M's, which are used for cgocallback from threads - // created in C. - // - // The purpose of the SetMaxThreads limit is to avoid accidental fork - // bomb from something like millions of goroutines blocking on system - // calls, causing the runtime to create millions of threads. By - // definition, this isn't a problem for threads created in C, so we - // exclude them from the limit. See https://go.dev/issue/60004. - count := mcount() - int32(extraMInUse.Load()) - int32(extraMLength.Load()) - if count > sched.maxmcount { - print("runtime: program exceeds ", sched.maxmcount, "-thread limit\n") - throw("thread exhaustion") - } -} - -// mReserveID returns the next ID to use for a new m. This new m is immediately -// considered 'running' by checkdead. -// -// sched.lock must be held. -func mReserveID() int64 { - assertLockHeld(&sched.lock) - - if sched.mnext+1 < sched.mnext { - throw("runtime: thread ID overflow") - } - id := sched.mnext - sched.mnext++ - checkmcount() - return id -} - -// Pre-allocated ID may be passed as 'id', or omitted by passing -1. -func mcommoninit(mp *m, id int64) { - gp := getg() - - // g0 stack won't make sense for user (and is not necessary unwindable). - if gp != gp.m.g0 { - callers(1, mp.createstack[:]) - } - - lock(&sched.lock) - - if id >= 0 { - mp.id = id - } else { - mp.id = mReserveID() - } - - mrandinit(mp) - - mpreinit(mp) - if mp.gsignal != nil { - mp.gsignal.stackguard1 = mp.gsignal.stack.lo + stackGuard - } - - // Add to allm so garbage collector doesn't free g->m - // when it is just in a register or thread-local storage. - mp.alllink = allm - - // NumCgoCall() and others iterate over allm w/o schedlock, - // so we need to publish it safely. - atomicstorep(unsafe.Pointer(&allm), unsafe.Pointer(mp)) - unlock(&sched.lock) - - // Allocate memory to hold a cgo traceback if the cgo call crashes. - if iscgo || GOOS == "solaris" || GOOS == "illumos" || GOOS == "windows" { - mp.cgoCallers = new(cgoCallers) - } -} - -func (mp *m) becomeSpinning() { - mp.spinning = true - sched.nmspinning.Add(1) - sched.needspinning.Store(0) -} - -func (mp *m) hasCgoOnStack() bool { - return mp.ncgo > 0 || mp.isextra -} - -const ( - // osHasLowResTimer indicates that the platform's internal timer system has a low resolution, - // typically on the order of 1 ms or more. - osHasLowResTimer = GOOS == "windows" || GOOS == "openbsd" || GOOS == "netbsd" - - // osHasLowResClockInt is osHasLowResClock but in integer form, so it can be used to create - // constants conditionally. - osHasLowResClockInt = goos.IsWindows - - // osHasLowResClock indicates that timestamps produced by nanotime on the platform have a - // low resolution, typically on the order of 1 ms or more. - osHasLowResClock = osHasLowResClockInt > 0 -) - -// Mark gp ready to run. -func ready(gp *g, traceskip int, next bool) { - status := readgstatus(gp) - - // Mark runnable. - mp := acquirem() // disable preemption because it can be holding p in a local var - if status&^_Gscan != _Gwaiting { - dumpgstatus(gp) - throw("bad g->status in ready") - } - - // status is Gwaiting or Gscanwaiting, make Grunnable and put on runq - trace := traceAcquire() - casgstatus(gp, _Gwaiting, _Grunnable) - if trace.ok() { - trace.GoUnpark(gp, traceskip) - traceRelease(trace) - } - runqput(mp.p.ptr(), gp, next) - wakep() - releasem(mp) -} - -// freezeStopWait is a large value that freezetheworld sets -// sched.stopwait to in order to request that all Gs permanently stop. -const freezeStopWait = 0x7fffffff - -// freezing is set to non-zero if the runtime is trying to freeze the -// world. -var freezing atomic.Bool - -// Similar to stopTheWorld but best-effort and can be called several times. -// There is no reverse operation, used during crashing. -// This function must not lock any mutexes. -func freezetheworld() { - freezing.Store(true) - if debug.dontfreezetheworld > 0 { - // Don't prempt Ps to stop goroutines. That will perturb - // scheduler state, making debugging more difficult. Instead, - // allow goroutines to continue execution. - // - // fatalpanic will tracebackothers to trace all goroutines. It - // is unsafe to trace a running goroutine, so tracebackothers - // will skip running goroutines. That is OK and expected, we - // expect users of dontfreezetheworld to use core files anyway. - // - // However, allowing the scheduler to continue running free - // introduces a race: a goroutine may be stopped when - // tracebackothers checks its status, and then start running - // later when we are in the middle of traceback, potentially - // causing a crash. - // - // To mitigate this, when an M naturally enters the scheduler, - // schedule checks if freezing is set and if so stops - // execution. This guarantees that while Gs can transition from - // running to stopped, they can never transition from stopped - // to running. - // - // The sleep here allows racing Ms that missed freezing and are - // about to run a G to complete the transition to running - // before we start traceback. - usleep(1000) - return - } - - // stopwait and preemption requests can be lost - // due to races with concurrently executing threads, - // so try several times - for i := 0; i < 5; i++ { - // this should tell the scheduler to not start any new goroutines - sched.stopwait = freezeStopWait - sched.gcwaiting.Store(true) - // this should stop running goroutines - if !preemptall() { - break // no running goroutines - } - usleep(1000) - } - // to be sure - usleep(1000) - preemptall() - usleep(1000) -} - -// All reads and writes of g's status go through readgstatus, casgstatus -// castogscanstatus, casfrom_Gscanstatus. -// -//go:nosplit -func readgstatus(gp *g) uint32 { - return gp.atomicstatus.Load() -} - -// The Gscanstatuses are acting like locks and this releases them. -// If it proves to be a performance hit we should be able to make these -// simple atomic stores but for now we are going to throw if -// we see an inconsistent state. -func casfrom_Gscanstatus(gp *g, oldval, newval uint32) { - success := false - - // Check that transition is valid. - switch oldval { - default: - print("runtime: casfrom_Gscanstatus bad oldval gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n") - dumpgstatus(gp) - throw("casfrom_Gscanstatus:top gp->status is not in scan state") - case _Gscanrunnable, - _Gscanwaiting, - _Gscanrunning, - _Gscansyscall, - _Gscanpreempted: - if newval == oldval&^_Gscan { - success = gp.atomicstatus.CompareAndSwap(oldval, newval) - } - } - if !success { - print("runtime: casfrom_Gscanstatus failed gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n") - dumpgstatus(gp) - throw("casfrom_Gscanstatus: gp->status is not in scan state") - } - releaseLockRank(lockRankGscan) -} - -// This will return false if the gp is not in the expected status and the cas fails. -// This acts like a lock acquire while the casfromgstatus acts like a lock release. -func castogscanstatus(gp *g, oldval, newval uint32) bool { - switch oldval { - case _Grunnable, - _Grunning, - _Gwaiting, - _Gsyscall: - if newval == oldval|_Gscan { - r := gp.atomicstatus.CompareAndSwap(oldval, newval) - if r { - acquireLockRank(lockRankGscan) - } - return r - - } - } - print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n") - throw("castogscanstatus") - panic("not reached") -} - -// casgstatusAlwaysTrack is a debug flag that causes casgstatus to always track -// various latencies on every transition instead of sampling them. -var casgstatusAlwaysTrack = false - -// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus -// and casfrom_Gscanstatus instead. -// casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that -// put it in the Gscan state is finished. -// -//go:nosplit -func casgstatus(gp *g, oldval, newval uint32) { - if (oldval&_Gscan != 0) || (newval&_Gscan != 0) || oldval == newval { - systemstack(func() { - print("runtime: casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n") - throw("casgstatus: bad incoming values") - }) - } - - acquireLockRank(lockRankGscan) - releaseLockRank(lockRankGscan) - - // See https://golang.org/cl/21503 for justification of the yield delay. - const yieldDelay = 5 * 1000 - var nextYield int64 - - // loop if gp->atomicstatus is in a scan state giving - // GC time to finish and change the state to oldval. - for i := 0; !gp.atomicstatus.CompareAndSwap(oldval, newval); i++ { - if oldval == _Gwaiting && gp.atomicstatus.Load() == _Grunnable { - throw("casgstatus: waiting for Gwaiting but is Grunnable") - } - if i == 0 { - nextYield = nanotime() + yieldDelay - } - if nanotime() < nextYield { - for x := 0; x < 10 && gp.atomicstatus.Load() != oldval; x++ { - procyield(1) - } - } else { - osyield() - nextYield = nanotime() + yieldDelay/2 - } - } - - if oldval == _Grunning { - // Track every gTrackingPeriod time a goroutine transitions out of running. - if casgstatusAlwaysTrack || gp.trackingSeq%gTrackingPeriod == 0 { - gp.tracking = true - } - gp.trackingSeq++ - } - if !gp.tracking { - return - } - - // Handle various kinds of tracking. - // - // Currently: - // - Time spent in runnable. - // - Time spent blocked on a sync.Mutex or sync.RWMutex. - switch oldval { - case _Grunnable: - // We transitioned out of runnable, so measure how much - // time we spent in this state and add it to - // runnableTime. - now := nanotime() - gp.runnableTime += now - gp.trackingStamp - gp.trackingStamp = 0 - case _Gwaiting: - if !gp.waitreason.isMutexWait() { - // Not blocking on a lock. - break - } - // Blocking on a lock, measure it. Note that because we're - // sampling, we have to multiply by our sampling period to get - // a more representative estimate of the absolute value. - // gTrackingPeriod also represents an accurate sampling period - // because we can only enter this state from _Grunning. - now := nanotime() - sched.totalMutexWaitTime.Add((now - gp.trackingStamp) * gTrackingPeriod) - gp.trackingStamp = 0 - } - switch newval { - case _Gwaiting: - if !gp.waitreason.isMutexWait() { - // Not blocking on a lock. - break - } - // Blocking on a lock. Write down the timestamp. - now := nanotime() - gp.trackingStamp = now - case _Grunnable: - // We just transitioned into runnable, so record what - // time that happened. - now := nanotime() - gp.trackingStamp = now - case _Grunning: - // We're transitioning into running, so turn off - // tracking and record how much time we spent in - // runnable. - gp.tracking = false - sched.timeToRun.record(gp.runnableTime) - gp.runnableTime = 0 - } -} - -// casGToWaiting transitions gp from old to _Gwaiting, and sets the wait reason. -// -// Use this over casgstatus when possible to ensure that a waitreason is set. -func casGToWaiting(gp *g, old uint32, reason waitReason) { - // Set the wait reason before calling casgstatus, because casgstatus will use it. - gp.waitreason = reason - casgstatus(gp, old, _Gwaiting) -} - -// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable. -// Returns old status. Cannot call casgstatus directly, because we are racing with an -// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus, -// it might have become Grunnable by the time we get to the cas. If we called casgstatus, -// it would loop waiting for the status to go back to Gwaiting, which it never will. -// -//go:nosplit -func casgcopystack(gp *g) uint32 { - for { - oldstatus := readgstatus(gp) &^ _Gscan - if oldstatus != _Gwaiting && oldstatus != _Grunnable { - throw("copystack: bad status, not Gwaiting or Grunnable") - } - if gp.atomicstatus.CompareAndSwap(oldstatus, _Gcopystack) { - return oldstatus - } - } -} - -// casGToPreemptScan transitions gp from _Grunning to _Gscan|_Gpreempted. -// -// TODO(austin): This is the only status operation that both changes -// the status and locks the _Gscan bit. Rethink this. -func casGToPreemptScan(gp *g, old, new uint32) { - if old != _Grunning || new != _Gscan|_Gpreempted { - throw("bad g transition") - } - acquireLockRank(lockRankGscan) - for !gp.atomicstatus.CompareAndSwap(_Grunning, _Gscan|_Gpreempted) { - } -} - -// casGFromPreempted attempts to transition gp from _Gpreempted to -// _Gwaiting. If successful, the caller is responsible for -// re-scheduling gp. -func casGFromPreempted(gp *g, old, new uint32) bool { - if old != _Gpreempted || new != _Gwaiting { - throw("bad g transition") - } - gp.waitreason = waitReasonPreempted - return gp.atomicstatus.CompareAndSwap(_Gpreempted, _Gwaiting) -} - -// stwReason is an enumeration of reasons the world is stopping. -type stwReason uint8 - -// Reasons to stop-the-world. -// -// Avoid reusing reasons and add new ones instead. -const ( - stwUnknown stwReason = iota // "unknown" - stwGCMarkTerm // "GC mark termination" - stwGCSweepTerm // "GC sweep termination" - stwWriteHeapDump // "write heap dump" - stwGoroutineProfile // "goroutine profile" - stwGoroutineProfileCleanup // "goroutine profile cleanup" - stwAllGoroutinesStack // "all goroutines stack trace" - stwReadMemStats // "read mem stats" - stwAllThreadsSyscall // "AllThreadsSyscall" - stwGOMAXPROCS // "GOMAXPROCS" - stwStartTrace // "start trace" - stwStopTrace // "stop trace" - stwForTestCountPagesInUse // "CountPagesInUse (test)" - stwForTestReadMetricsSlow // "ReadMetricsSlow (test)" - stwForTestReadMemStatsSlow // "ReadMemStatsSlow (test)" - stwForTestPageCachePagesLeaked // "PageCachePagesLeaked (test)" - stwForTestResetDebugLog // "ResetDebugLog (test)" -) - -func (r stwReason) String() string { - return stwReasonStrings[r] -} - -func (r stwReason) isGC() bool { - return r == stwGCMarkTerm || r == stwGCSweepTerm -} - -// If you add to this list, also add it to src/internal/trace/parser.go. -// If you change the values of any of the stw* constants, bump the trace -// version number and make a copy of this. -var stwReasonStrings = [...]string{ - stwUnknown: "unknown", - stwGCMarkTerm: "GC mark termination", - stwGCSweepTerm: "GC sweep termination", - stwWriteHeapDump: "write heap dump", - stwGoroutineProfile: "goroutine profile", - stwGoroutineProfileCleanup: "goroutine profile cleanup", - stwAllGoroutinesStack: "all goroutines stack trace", - stwReadMemStats: "read mem stats", - stwAllThreadsSyscall: "AllThreadsSyscall", - stwGOMAXPROCS: "GOMAXPROCS", - stwStartTrace: "start trace", - stwStopTrace: "stop trace", - stwForTestCountPagesInUse: "CountPagesInUse (test)", - stwForTestReadMetricsSlow: "ReadMetricsSlow (test)", - stwForTestReadMemStatsSlow: "ReadMemStatsSlow (test)", - stwForTestPageCachePagesLeaked: "PageCachePagesLeaked (test)", - stwForTestResetDebugLog: "ResetDebugLog (test)", -} - -// worldStop provides context from the stop-the-world required by the -// start-the-world. -type worldStop struct { - reason stwReason - start int64 -} - -// Temporary variable for stopTheWorld, when it can't write to the stack. -// -// Protected by worldsema. -var stopTheWorldContext worldStop - -// stopTheWorld stops all P's from executing goroutines, interrupting -// all goroutines at GC safe points and records reason as the reason -// for the stop. On return, only the current goroutine's P is running. -// stopTheWorld must not be called from a system stack and the caller -// must not hold worldsema. The caller must call startTheWorld when -// other P's should resume execution. -// -// stopTheWorld is safe for multiple goroutines to call at the -// same time. Each will execute its own stop, and the stops will -// be serialized. -// -// This is also used by routines that do stack dumps. If the system is -// in panic or being exited, this may not reliably stop all -// goroutines. -// -// Returns the STW context. When starting the world, this context must be -// passed to startTheWorld. -func stopTheWorld(reason stwReason) worldStop { - semacquire(&worldsema) - gp := getg() - gp.m.preemptoff = reason.String() - systemstack(func() { - // Mark the goroutine which called stopTheWorld preemptible so its - // stack may be scanned. - // This lets a mark worker scan us while we try to stop the world - // since otherwise we could get in a mutual preemption deadlock. - // We must not modify anything on the G stack because a stack shrink - // may occur. A stack shrink is otherwise OK though because in order - // to return from this function (and to leave the system stack) we - // must have preempted all goroutines, including any attempting - // to scan our stack, in which case, any stack shrinking will - // have already completed by the time we exit. - // - // N.B. The execution tracer is not aware of this status - // transition and handles it specially based on the - // wait reason. - casGToWaiting(gp, _Grunning, waitReasonStoppingTheWorld) - stopTheWorldContext = stopTheWorldWithSema(reason) // avoid write to stack - casgstatus(gp, _Gwaiting, _Grunning) - }) - return stopTheWorldContext -} - -// startTheWorld undoes the effects of stopTheWorld. -// -// w must be the worldStop returned by stopTheWorld. -func startTheWorld(w worldStop) { - systemstack(func() { startTheWorldWithSema(0, w) }) - - // worldsema must be held over startTheWorldWithSema to ensure - // gomaxprocs cannot change while worldsema is held. - // - // Release worldsema with direct handoff to the next waiter, but - // acquirem so that semrelease1 doesn't try to yield our time. - // - // Otherwise if e.g. ReadMemStats is being called in a loop, - // it might stomp on other attempts to stop the world, such as - // for starting or ending GC. The operation this blocks is - // so heavy-weight that we should just try to be as fair as - // possible here. - // - // We don't want to just allow us to get preempted between now - // and releasing the semaphore because then we keep everyone - // (including, for example, GCs) waiting longer. - mp := acquirem() - mp.preemptoff = "" - semrelease1(&worldsema, true, 0) - releasem(mp) -} - -// stopTheWorldGC has the same effect as stopTheWorld, but blocks -// until the GC is not running. It also blocks a GC from starting -// until startTheWorldGC is called. -func stopTheWorldGC(reason stwReason) worldStop { - semacquire(&gcsema) - return stopTheWorld(reason) -} - -// startTheWorldGC undoes the effects of stopTheWorldGC. -// -// w must be the worldStop returned by stopTheWorld. -func startTheWorldGC(w worldStop) { - startTheWorld(w) - semrelease(&gcsema) -} - -// Holding worldsema grants an M the right to try to stop the world. -var worldsema uint32 = 1 - -// Holding gcsema grants the M the right to block a GC, and blocks -// until the current GC is done. In particular, it prevents gomaxprocs -// from changing concurrently. -// -// TODO(mknyszek): Once gomaxprocs and the execution tracer can handle -// being changed/enabled during a GC, remove this. -var gcsema uint32 = 1 - -// stopTheWorldWithSema is the core implementation of stopTheWorld. -// The caller is responsible for acquiring worldsema and disabling -// preemption first and then should stopTheWorldWithSema on the system -// stack: -// -// semacquire(&worldsema, 0) -// m.preemptoff = "reason" -// var stw worldStop -// systemstack(func() { -// stw = stopTheWorldWithSema(reason) -// }) -// -// When finished, the caller must either call startTheWorld or undo -// these three operations separately: -// -// m.preemptoff = "" -// systemstack(func() { -// now = startTheWorldWithSema(stw) -// }) -// semrelease(&worldsema) -// -// It is allowed to acquire worldsema once and then execute multiple -// startTheWorldWithSema/stopTheWorldWithSema pairs. -// Other P's are able to execute between successive calls to -// startTheWorldWithSema and stopTheWorldWithSema. -// Holding worldsema causes any other goroutines invoking -// stopTheWorld to block. -// -// Returns the STW context. When starting the world, this context must be -// passed to startTheWorldWithSema. -func stopTheWorldWithSema(reason stwReason) worldStop { - trace := traceAcquire() - if trace.ok() { - trace.STWStart(reason) - traceRelease(trace) - } - gp := getg() - - // If we hold a lock, then we won't be able to stop another M - // that is blocked trying to acquire the lock. - if gp.m.locks > 0 { - throw("stopTheWorld: holding locks") - } - - lock(&sched.lock) - start := nanotime() // exclude time waiting for sched.lock from start and total time metrics. - sched.stopwait = gomaxprocs - sched.gcwaiting.Store(true) - preemptall() - // stop current P - gp.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic. - sched.stopwait-- - // try to retake all P's in Psyscall status - trace = traceAcquire() - for _, pp := range allp { - s := pp.status - if s == _Psyscall && atomic.Cas(&pp.status, s, _Pgcstop) { - if trace.ok() { - trace.GoSysBlock(pp) - trace.ProcSteal(pp, false) - } - pp.syscalltick++ - sched.stopwait-- - } - } - if trace.ok() { - traceRelease(trace) - } - - // stop idle P's - now := nanotime() - for { - pp, _ := pidleget(now) - if pp == nil { - break - } - pp.status = _Pgcstop - sched.stopwait-- - } - wait := sched.stopwait > 0 - unlock(&sched.lock) - - // wait for remaining P's to stop voluntarily - if wait { - for { - // wait for 100us, then try to re-preempt in case of any races - if notetsleep(&sched.stopnote, 100*1000) { - noteclear(&sched.stopnote) - break - } - preemptall() - } - } - - startTime := nanotime() - start - if reason.isGC() { - sched.stwStoppingTimeGC.record(startTime) - } else { - sched.stwStoppingTimeOther.record(startTime) - } - - // sanity checks - bad := "" - if sched.stopwait != 0 { - bad = "stopTheWorld: not stopped (stopwait != 0)" - } else { - for _, pp := range allp { - if pp.status != _Pgcstop { - bad = "stopTheWorld: not stopped (status != _Pgcstop)" - } - } - } - if freezing.Load() { - // Some other thread is panicking. This can cause the - // sanity checks above to fail if the panic happens in - // the signal handler on a stopped thread. Either way, - // we should halt this thread. - lock(&deadlock) - lock(&deadlock) - } - if bad != "" { - throw(bad) - } - - worldStopped() - - return worldStop{reason: reason, start: start} -} - -// reason is the same STW reason passed to stopTheWorld. start is the start -// time returned by stopTheWorld. -// -// now is the current time; prefer to pass 0 to capture a fresh timestamp. -// -// stattTheWorldWithSema returns now. -func startTheWorldWithSema(now int64, w worldStop) int64 { - assertWorldStopped() - - mp := acquirem() // disable preemption because it can be holding p in a local var - if netpollinited() { - list, delta := netpoll(0) // non-blocking - injectglist(&list) - netpollAdjustWaiters(delta) - } - lock(&sched.lock) - - procs := gomaxprocs - if newprocs != 0 { - procs = newprocs - newprocs = 0 - } - p1 := procresize(procs) - sched.gcwaiting.Store(false) - if sched.sysmonwait.Load() { - sched.sysmonwait.Store(false) - notewakeup(&sched.sysmonnote) - } - unlock(&sched.lock) - - worldStarted() - - for p1 != nil { - p := p1 - p1 = p1.link.ptr() - if p.m != 0 { - mp := p.m.ptr() - p.m = 0 - if mp.nextp != 0 { - throw("startTheWorld: inconsistent mp->nextp") - } - mp.nextp.set(p) - notewakeup(&mp.park) - } else { - // Start M to run P. Do not start another M below. - newm(nil, p, -1) - } - } - - // Capture start-the-world time before doing clean-up tasks. - if now == 0 { - now = nanotime() - } - totalTime := now - w.start - if w.reason.isGC() { - sched.stwTotalTimeGC.record(totalTime) - } else { - sched.stwTotalTimeOther.record(totalTime) - } - trace := traceAcquire() - if trace.ok() { - trace.STWDone() - traceRelease(trace) - } - - // Wakeup an additional proc in case we have excessive runnable goroutines - // in local queues or in the global queue. If we don't, the proc will park itself. - // If we have lots of excessive work, resetspinning will unpark additional procs as necessary. - wakep() - - releasem(mp) - - return now -} - -// usesLibcall indicates whether this runtime performs system calls -// via libcall. -func usesLibcall() bool { - switch GOOS { - case "aix", "darwin", "illumos", "ios", "solaris", "windows": - return true - case "openbsd": - return GOARCH != "mips64" - } - return false -} - -// mStackIsSystemAllocated indicates whether this runtime starts on a -// system-allocated stack. -func mStackIsSystemAllocated() bool { - switch GOOS { - case "aix", "darwin", "plan9", "illumos", "ios", "solaris", "windows": - return true - case "openbsd": - return GOARCH != "mips64" - } - return false -} - -// mstart is the entry-point for new Ms. -// It is written in assembly, uses ABI0, is marked TOPFRAME, and calls mstart0. -func mstart() - -// mstart0 is the Go entry-point for new Ms. -// This must not split the stack because we may not even have stack -// bounds set up yet. -// -// May run during STW (because it doesn't have a P yet), so write -// barriers are not allowed. -// -//go:nosplit -//go:nowritebarrierrec -func mstart0() { - gp := getg() - - osStack := gp.stack.lo == 0 - if osStack { - // Initialize stack bounds from system stack. - // Cgo may have left stack size in stack.hi. - // minit may update the stack bounds. - // - // Note: these bounds may not be very accurate. - // We set hi to &size, but there are things above - // it. The 1024 is supposed to compensate this, - // but is somewhat arbitrary. - size := gp.stack.hi - if size == 0 { - size = 16384 * sys.StackGuardMultiplier - } - gp.stack.hi = uintptr(noescape(unsafe.Pointer(&size))) - gp.stack.lo = gp.stack.hi - size + 1024 - } - // Initialize stack guard so that we can start calling regular - // Go code. - gp.stackguard0 = gp.stack.lo + stackGuard - // This is the g0, so we can also call go:systemstack - // functions, which check stackguard1. - gp.stackguard1 = gp.stackguard0 - mstart1() - - // Exit this thread. - if mStackIsSystemAllocated() { - // Windows, Solaris, illumos, Darwin, AIX and Plan 9 always system-allocate - // the stack, but put it in gp.stack before mstart, - // so the logic above hasn't set osStack yet. - osStack = true - } - mexit(osStack) -} - -// The go:noinline is to guarantee the getcallerpc/getcallersp below are safe, -// so that we can set up g0.sched to return to the call of mstart1 above. -// -//go:noinline -func mstart1() { - gp := getg() - - if gp != gp.m.g0 { - throw("bad runtime·mstart") - } - - // Set up m.g0.sched as a label returning to just - // after the mstart1 call in mstart0 above, for use by goexit0 and mcall. - // We're never coming back to mstart1 after we call schedule, - // so other calls can reuse the current frame. - // And goexit0 does a gogo that needs to return from mstart1 - // and let mstart0 exit the thread. - gp.sched.g = guintptr(unsafe.Pointer(gp)) - gp.sched.pc = getcallerpc() - gp.sched.sp = getcallersp() - - asminit() - minit() - - // Install signal handlers; after minit so that minit can - // prepare the thread to be able to handle the signals. - if gp.m == &m0 { - mstartm0() - } - - if fn := gp.m.mstartfn; fn != nil { - fn() - } - - if gp.m != &m0 { - acquirep(gp.m.nextp.ptr()) - gp.m.nextp = 0 - } - schedule() -} - -// mstartm0 implements part of mstart1 that only runs on the m0. -// -// Write barriers are allowed here because we know the GC can't be -// running yet, so they'll be no-ops. -// -//go:yeswritebarrierrec -func mstartm0() { - // Create an extra M for callbacks on threads not created by Go. - // An extra M is also needed on Windows for callbacks created by - // syscall.NewCallback. See issue #6751 for details. - if (iscgo || GOOS == "windows") && !cgoHasExtraM { - cgoHasExtraM = true - newextram() - } - initsig(false) -} - -// mPark causes a thread to park itself, returning once woken. -// -//go:nosplit -func mPark() { - gp := getg() - notesleep(&gp.m.park) - noteclear(&gp.m.park) -} - -// mexit tears down and exits the current thread. -// -// Don't call this directly to exit the thread, since it must run at -// the top of the thread stack. Instead, use gogo(&gp.m.g0.sched) to -// unwind the stack to the point that exits the thread. -// -// It is entered with m.p != nil, so write barriers are allowed. It -// will release the P before exiting. -// -//go:yeswritebarrierrec -func mexit(osStack bool) { - mp := getg().m - - if mp == &m0 { - // This is the main thread. Just wedge it. - // - // On Linux, exiting the main thread puts the process - // into a non-waitable zombie state. On Plan 9, - // exiting the main thread unblocks wait even though - // other threads are still running. On Solaris we can - // neither exitThread nor return from mstart. Other - // bad things probably happen on other platforms. - // - // We could try to clean up this M more before wedging - // it, but that complicates signal handling. - handoffp(releasep()) - lock(&sched.lock) - sched.nmfreed++ - checkdead() - unlock(&sched.lock) - mPark() - throw("locked m0 woke up") - } - - sigblock(true) - unminit() - - // Free the gsignal stack. - if mp.gsignal != nil { - stackfree(mp.gsignal.stack) - // On some platforms, when calling into VDSO (e.g. nanotime) - // we store our g on the gsignal stack, if there is one. - // Now the stack is freed, unlink it from the m, so we - // won't write to it when calling VDSO code. - mp.gsignal = nil - } - - // Remove m from allm. - lock(&sched.lock) - for pprev := &allm; *pprev != nil; pprev = &(*pprev).alllink { - if *pprev == mp { - *pprev = mp.alllink - goto found - } - } - throw("m not found in allm") -found: - // Events must not be traced after this point. - - // Delay reaping m until it's done with the stack. - // - // Put mp on the free list, though it will not be reaped while freeWait - // is freeMWait. mp is no longer reachable via allm, so even if it is - // on an OS stack, we must keep a reference to mp alive so that the GC - // doesn't free mp while we are still using it. - // - // Note that the free list must not be linked through alllink because - // some functions walk allm without locking, so may be using alllink. - // - // N.B. It's important that the M appears on the free list simultaneously - // with it being removed so that the tracer can find it. - mp.freeWait.Store(freeMWait) - mp.freelink = sched.freem - sched.freem = mp - unlock(&sched.lock) - - atomic.Xadd64(&ncgocall, int64(mp.ncgocall)) - sched.totalRuntimeLockWaitTime.Add(mp.mLockProfile.waitTime.Load()) - - // Release the P. - handoffp(releasep()) - // After this point we must not have write barriers. - - // Invoke the deadlock detector. This must happen after - // handoffp because it may have started a new M to take our - // P's work. - lock(&sched.lock) - sched.nmfreed++ - checkdead() - unlock(&sched.lock) - - if GOOS == "darwin" || GOOS == "ios" { - // Make sure pendingPreemptSignals is correct when an M exits. - // For #41702. - if mp.signalPending.Load() != 0 { - pendingPreemptSignals.Add(-1) - } - } - - // Destroy all allocated resources. After this is called, we may no - // longer take any locks. - mdestroy(mp) - - if osStack { - // No more uses of mp, so it is safe to drop the reference. - mp.freeWait.Store(freeMRef) - - // Return from mstart and let the system thread - // library free the g0 stack and terminate the thread. - return - } - - // mstart is the thread's entry point, so there's nothing to - // return to. Exit the thread directly. exitThread will clear - // m.freeWait when it's done with the stack and the m can be - // reaped. - exitThread(&mp.freeWait) -} - -// forEachP calls fn(p) for every P p when p reaches a GC safe point. -// If a P is currently executing code, this will bring the P to a GC -// safe point and execute fn on that P. If the P is not executing code -// (it is idle or in a syscall), this will call fn(p) directly while -// preventing the P from exiting its state. This does not ensure that -// fn will run on every CPU executing Go code, but it acts as a global -// memory barrier. GC uses this as a "ragged barrier." -// -// The caller must hold worldsema. fn must not refer to any -// part of the current goroutine's stack, since the GC may move it. -func forEachP(reason waitReason, fn func(*p)) { - systemstack(func() { - gp := getg().m.curg - // Mark the user stack as preemptible so that it may be scanned. - // Otherwise, our attempt to force all P's to a safepoint could - // result in a deadlock as we attempt to preempt a worker that's - // trying to preempt us (e.g. for a stack scan). - // - // N.B. The execution tracer is not aware of this status - // transition and handles it specially based on the - // wait reason. - casGToWaiting(gp, _Grunning, reason) - forEachPInternal(fn) - casgstatus(gp, _Gwaiting, _Grunning) - }) -} - -// forEachPInternal calls fn(p) for every P p when p reaches a GC safe point. -// It is the internal implementation of forEachP. -// -// The caller must hold worldsema and either must ensure that a GC is not -// running (otherwise this may deadlock with the GC trying to preempt this P) -// or it must leave its goroutine in a preemptible state before it switches -// to the systemstack. Due to these restrictions, prefer forEachP when possible. -// -//go:systemstack -func forEachPInternal(fn func(*p)) { - mp := acquirem() - pp := getg().m.p.ptr() - - lock(&sched.lock) - if sched.safePointWait != 0 { - throw("forEachP: sched.safePointWait != 0") - } - sched.safePointWait = gomaxprocs - 1 - sched.safePointFn = fn - - // Ask all Ps to run the safe point function. - for _, p2 := range allp { - if p2 != pp { - atomic.Store(&p2.runSafePointFn, 1) - } - } - preemptall() - - // Any P entering _Pidle or _Psyscall from now on will observe - // p.runSafePointFn == 1 and will call runSafePointFn when - // changing its status to _Pidle/_Psyscall. - - // Run safe point function for all idle Ps. sched.pidle will - // not change because we hold sched.lock. - for p := sched.pidle.ptr(); p != nil; p = p.link.ptr() { - if atomic.Cas(&p.runSafePointFn, 1, 0) { - fn(p) - sched.safePointWait-- - } - } - - wait := sched.safePointWait > 0 - unlock(&sched.lock) - - // Run fn for the current P. - fn(pp) - - // Force Ps currently in _Psyscall into _Pidle and hand them - // off to induce safe point function execution. - for _, p2 := range allp { - s := p2.status - - // We need to be fine-grained about tracing here, since handoffp - // might call into the tracer, and the tracer is non-reentrant. - trace := traceAcquire() - if s == _Psyscall && p2.runSafePointFn == 1 && atomic.Cas(&p2.status, s, _Pidle) { - if trace.ok() { - // It's important that we traceRelease before we call handoffp, which may also traceAcquire. - trace.GoSysBlock(p2) - trace.ProcSteal(p2, false) - traceRelease(trace) - } - p2.syscalltick++ - handoffp(p2) - } else if trace.ok() { - traceRelease(trace) - } - } - - // Wait for remaining Ps to run fn. - if wait { - for { - // Wait for 100us, then try to re-preempt in - // case of any races. - // - // Requires system stack. - if notetsleep(&sched.safePointNote, 100*1000) { - noteclear(&sched.safePointNote) - break - } - preemptall() - } - } - if sched.safePointWait != 0 { - throw("forEachP: not done") - } - for _, p2 := range allp { - if p2.runSafePointFn != 0 { - throw("forEachP: P did not run fn") - } - } - - lock(&sched.lock) - sched.safePointFn = nil - unlock(&sched.lock) - releasem(mp) -} - -// runSafePointFn runs the safe point function, if any, for this P. -// This should be called like -// -// if getg().m.p.runSafePointFn != 0 { -// runSafePointFn() -// } -// -// runSafePointFn must be checked on any transition in to _Pidle or -// _Psyscall to avoid a race where forEachP sees that the P is running -// just before the P goes into _Pidle/_Psyscall and neither forEachP -// nor the P run the safe-point function. -func runSafePointFn() { - p := getg().m.p.ptr() - // Resolve the race between forEachP running the safe-point - // function on this P's behalf and this P running the - // safe-point function directly. - if !atomic.Cas(&p.runSafePointFn, 1, 0) { - return - } - sched.safePointFn(p) - lock(&sched.lock) - sched.safePointWait-- - if sched.safePointWait == 0 { - notewakeup(&sched.safePointNote) - } - unlock(&sched.lock) -} - -// When running with cgo, we call _cgo_thread_start -// to start threads for us so that we can play nicely with -// foreign code. -var cgoThreadStart unsafe.Pointer - -type cgothreadstart struct { - g guintptr - tls *uint64 - fn unsafe.Pointer -} - -// Allocate a new m unassociated with any thread. -// Can use p for allocation context if needed. -// fn is recorded as the new m's m.mstartfn. -// id is optional pre-allocated m ID. Omit by passing -1. -// -// This function is allowed to have write barriers even if the caller -// isn't because it borrows pp. -// -//go:yeswritebarrierrec -func allocm(pp *p, fn func(), id int64) *m { - allocmLock.rlock() - - // The caller owns pp, but we may borrow (i.e., acquirep) it. We must - // disable preemption to ensure it is not stolen, which would make the - // caller lose ownership. - acquirem() - - gp := getg() - if gp.m.p == 0 { - acquirep(pp) // temporarily borrow p for mallocs in this function - } - - // Release the free M list. We need to do this somewhere and - // this may free up a stack we can use. - if sched.freem != nil { - lock(&sched.lock) - var newList *m - for freem := sched.freem; freem != nil; { - // Wait for freeWait to indicate that freem's stack is unused. - wait := freem.freeWait.Load() - if wait == freeMWait { - next := freem.freelink - freem.freelink = newList - newList = freem - freem = next - continue - } - // Drop any remaining trace resources. - // Ms can continue to emit events all the way until wait != freeMWait, - // so it's only safe to call traceThreadDestroy at this point. - if traceEnabled() || traceShuttingDown() { - traceThreadDestroy(freem) - } - // Free the stack if needed. For freeMRef, there is - // nothing to do except drop freem from the sched.freem - // list. - if wait == freeMStack { - // stackfree must be on the system stack, but allocm is - // reachable off the system stack transitively from - // startm. - systemstack(func() { - stackfree(freem.g0.stack) - }) - } - freem = freem.freelink - } - sched.freem = newList - unlock(&sched.lock) - } - - mp := new(m) - mp.mstartfn = fn - mcommoninit(mp, id) - - // In case of cgo or Solaris or illumos or Darwin, pthread_create will make us a stack. - // Windows and Plan 9 will layout sched stack on OS stack. - if iscgo || mStackIsSystemAllocated() { - mp.g0 = malg(-1) - } else { - mp.g0 = malg(16384 * sys.StackGuardMultiplier) - } - mp.g0.m = mp - - if pp == gp.m.p.ptr() { - releasep() - } - - releasem(gp.m) - allocmLock.runlock() - return mp -} - -// needm is called when a cgo callback happens on a -// thread without an m (a thread not created by Go). -// In this case, needm is expected to find an m to use -// and return with m, g initialized correctly. -// Since m and g are not set now (likely nil, but see below) -// needm is limited in what routines it can call. In particular -// it can only call nosplit functions (textflag 7) and cannot -// do any scheduling that requires an m. -// -// In order to avoid needing heavy lifting here, we adopt -// the following strategy: there is a stack of available m's -// that can be stolen. Using compare-and-swap -// to pop from the stack has ABA races, so we simulate -// a lock by doing an exchange (via Casuintptr) to steal the stack -// head and replace the top pointer with MLOCKED (1). -// This serves as a simple spin lock that we can use even -// without an m. The thread that locks the stack in this way -// unlocks the stack by storing a valid stack head pointer. -// -// In order to make sure that there is always an m structure -// available to be stolen, we maintain the invariant that there -// is always one more than needed. At the beginning of the -// program (if cgo is in use) the list is seeded with a single m. -// If needm finds that it has taken the last m off the list, its job -// is - once it has installed its own m so that it can do things like -// allocate memory - to create a spare m and put it on the list. -// -// Each of these extra m's also has a g0 and a curg that are -// pressed into service as the scheduling stack and current -// goroutine for the duration of the cgo callback. -// -// It calls dropm to put the m back on the list, -// 1. when the callback is done with the m in non-pthread platforms, -// 2. or when the C thread exiting on pthread platforms. -// -// The signal argument indicates whether we're called from a signal -// handler. -// -//go:nosplit -func needm(signal bool) { - if (iscgo || GOOS == "windows") && !cgoHasExtraM { - // Can happen if C/C++ code calls Go from a global ctor. - // Can also happen on Windows if a global ctor uses a - // callback created by syscall.NewCallback. See issue #6751 - // for details. - // - // Can not throw, because scheduler is not initialized yet. - writeErrStr("fatal error: cgo callback before cgo call\n") - exit(1) - } - - // Save and block signals before getting an M. - // The signal handler may call needm itself, - // and we must avoid a deadlock. Also, once g is installed, - // any incoming signals will try to execute, - // but we won't have the sigaltstack settings and other data - // set up appropriately until the end of minit, which will - // unblock the signals. This is the same dance as when - // starting a new m to run Go code via newosproc. - var sigmask sigset - sigsave(&sigmask) - sigblock(false) - - // getExtraM is safe here because of the invariant above, - // that the extra list always contains or will soon contain - // at least one m. - mp, last := getExtraM() - - // Set needextram when we've just emptied the list, - // so that the eventual call into cgocallbackg will - // allocate a new m for the extra list. We delay the - // allocation until then so that it can be done - // after exitsyscall makes sure it is okay to be - // running at all (that is, there's no garbage collection - // running right now). - mp.needextram = last - - // Store the original signal mask for use by minit. - mp.sigmask = sigmask - - // Install TLS on some platforms (previously setg - // would do this if necessary). - osSetupTLS(mp) - - // Install g (= m->g0) and set the stack bounds - // to match the current stack. - setg(mp.g0) - sp := getcallersp() - callbackUpdateSystemStack(mp, sp, signal) - - // Should mark we are already in Go now. - // Otherwise, we may call needm again when we get a signal, before cgocallbackg1, - // which means the extram list may be empty, that will cause a deadlock. - mp.isExtraInC = false - - // Initialize this thread to use the m. - asminit() - minit() - - // Emit a trace event for this dead -> syscall transition, - // but only in the new tracer and only if we're not in a signal handler. - // - // N.B. the tracer can run on a bare M just fine, we just have - // to make sure to do this before setg(nil) and unminit. - var trace traceLocker - if goexperiment.ExecTracer2 && !signal { - trace = traceAcquire() - } - - // mp.curg is now a real goroutine. - casgstatus(mp.curg, _Gdead, _Gsyscall) - sched.ngsys.Add(-1) - - if goexperiment.ExecTracer2 && !signal { - if trace.ok() { - trace.GoCreateSyscall(mp.curg) - traceRelease(trace) - } - } - mp.isExtraInSig = signal -} - -// Acquire an extra m and bind it to the C thread when a pthread key has been created. -// -//go:nosplit -func needAndBindM() { - needm(false) - - if _cgo_pthread_key_created != nil && *(*uintptr)(_cgo_pthread_key_created) != 0 { - cgoBindM() - } -} - -// newextram allocates m's and puts them on the extra list. -// It is called with a working local m, so that it can do things -// like call schedlock and allocate. -func newextram() { - c := extraMWaiters.Swap(0) - if c > 0 { - for i := uint32(0); i < c; i++ { - oneNewExtraM() - } - } else if extraMLength.Load() == 0 { - // Make sure there is at least one extra M. - oneNewExtraM() - } -} - -// oneNewExtraM allocates an m and puts it on the extra list. -func oneNewExtraM() { - // Create extra goroutine locked to extra m. - // The goroutine is the context in which the cgo callback will run. - // The sched.pc will never be returned to, but setting it to - // goexit makes clear to the traceback routines where - // the goroutine stack ends. - mp := allocm(nil, nil, -1) - gp := malg(4096) - gp.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum - gp.sched.sp = gp.stack.hi - gp.sched.sp -= 4 * goarch.PtrSize // extra space in case of reads slightly beyond frame - gp.sched.lr = 0 - gp.sched.g = guintptr(unsafe.Pointer(gp)) - gp.syscallpc = gp.sched.pc - gp.syscallsp = gp.sched.sp - gp.stktopsp = gp.sched.sp - // malg returns status as _Gidle. Change to _Gdead before - // adding to allg where GC can see it. We use _Gdead to hide - // this from tracebacks and stack scans since it isn't a - // "real" goroutine until needm grabs it. - casgstatus(gp, _Gidle, _Gdead) - gp.m = mp - mp.curg = gp - mp.isextra = true - // mark we are in C by default. - mp.isExtraInC = true - mp.lockedInt++ - mp.lockedg.set(gp) - gp.lockedm.set(mp) - gp.goid = sched.goidgen.Add(1) - if raceenabled { - gp.racectx = racegostart(abi.FuncPCABIInternal(newextram) + sys.PCQuantum) - } - trace := traceAcquire() - if trace.ok() { - trace.OneNewExtraM(gp) - traceRelease(trace) - } - // put on allg for garbage collector - allgadd(gp) - - // gp is now on the allg list, but we don't want it to be - // counted by gcount. It would be more "proper" to increment - // sched.ngfree, but that requires locking. Incrementing ngsys - // has the same effect. - sched.ngsys.Add(1) - - // Add m to the extra list. - addExtraM(mp) -} - -// dropm puts the current m back onto the extra list. -// -// 1. On systems without pthreads, like Windows -// dropm is called when a cgo callback has called needm but is now -// done with the callback and returning back into the non-Go thread. -// -// The main expense here is the call to signalstack to release the -// m's signal stack, and then the call to needm on the next callback -// from this thread. It is tempting to try to save the m for next time, -// which would eliminate both these costs, but there might not be -// a next time: the current thread (which Go does not control) might exit. -// If we saved the m for that thread, there would be an m leak each time -// such a thread exited. Instead, we acquire and release an m on each -// call. These should typically not be scheduling operations, just a few -// atomics, so the cost should be small. -// -// 2. On systems with pthreads -// dropm is called while a non-Go thread is exiting. -// We allocate a pthread per-thread variable using pthread_key_create, -// to register a thread-exit-time destructor. -// And store the g into a thread-specific value associated with the pthread key, -// when first return back to C. -// So that the destructor would invoke dropm while the non-Go thread is exiting. -// This is much faster since it avoids expensive signal-related syscalls. -// -// This always runs without a P, so //go:nowritebarrierrec is required. -// -// This may run with a different stack than was recorded in g0 (there is no -// call to callbackUpdateSystemStack prior to dropm), so this must be -// //go:nosplit to avoid the stack bounds check. -// -//go:nowritebarrierrec -//go:nosplit -func dropm() { - // Clear m and g, and return m to the extra list. - // After the call to setg we can only call nosplit functions - // with no pointer manipulation. - mp := getg().m - - // Emit a trace event for this syscall -> dead transition, - // but only in the new tracer. - // - // N.B. the tracer can run on a bare M just fine, we just have - // to make sure to do this before setg(nil) and unminit. - var trace traceLocker - if goexperiment.ExecTracer2 && !mp.isExtraInSig { - trace = traceAcquire() - } - - // Return mp.curg to dead state. - casgstatus(mp.curg, _Gsyscall, _Gdead) - mp.curg.preemptStop = false - sched.ngsys.Add(1) - - if goexperiment.ExecTracer2 && !mp.isExtraInSig { - if trace.ok() { - trace.GoDestroySyscall() - traceRelease(trace) - } - } - - if goexperiment.ExecTracer2 { - // Trash syscalltick so that it doesn't line up with mp.old.syscalltick anymore. - // - // In the new tracer, we model needm and dropm and a goroutine being created and - // destroyed respectively. The m then might get reused with a different procid but - // still with a reference to oldp, and still with the same syscalltick. The next - // time a G is "created" in needm, it'll return and quietly reacquire its P from a - // different m with a different procid, which will confuse the trace parser. By - // trashing syscalltick, we ensure that it'll appear as if we lost the P to the - // tracer parser and that we just reacquired it. - // - // Trash the value by decrementing because that gets us as far away from the value - // the syscall exit code expects as possible. Setting to zero is risky because - // syscalltick could already be zero (and in fact, is initialized to zero). - mp.syscalltick-- - } - - // Reset trace state unconditionally. This goroutine is being 'destroyed' - // from the perspective of the tracer. - mp.curg.trace.reset() - - // Flush all the M's buffers. This is necessary because the M might - // be used on a different thread with a different procid, so we have - // to make sure we don't write into the same buffer. - // - // N.B. traceThreadDestroy is a no-op in the old tracer, so avoid the - // unnecessary acquire/release of the lock. - if goexperiment.ExecTracer2 && (traceEnabled() || traceShuttingDown()) { - // Acquire sched.lock across thread destruction. One of the invariants of the tracer - // is that a thread cannot disappear from the tracer's view (allm or freem) without - // it noticing, so it requires that sched.lock be held over traceThreadDestroy. - // - // This isn't strictly necessary in this case, because this thread never leaves allm, - // but the critical section is short and dropm is rare on pthread platforms, so just - // take the lock and play it safe. traceThreadDestroy also asserts that the lock is held. - lock(&sched.lock) - traceThreadDestroy(mp) - unlock(&sched.lock) - } - mp.isExtraInSig = false - - // Block signals before unminit. - // Unminit unregisters the signal handling stack (but needs g on some systems). - // Setg(nil) clears g, which is the signal handler's cue not to run Go handlers. - // It's important not to try to handle a signal between those two steps. - sigmask := mp.sigmask - sigblock(false) - unminit() - - setg(nil) - - // Clear g0 stack bounds to ensure that needm always refreshes the - // bounds when reusing this M. - g0 := mp.g0 - g0.stack.hi = 0 - g0.stack.lo = 0 - g0.stackguard0 = 0 - g0.stackguard1 = 0 - - putExtraM(mp) - - msigrestore(sigmask) -} - -// bindm store the g0 of the current m into a thread-specific value. -// -// We allocate a pthread per-thread variable using pthread_key_create, -// to register a thread-exit-time destructor. -// We are here setting the thread-specific value of the pthread key, to enable the destructor. -// So that the pthread_key_destructor would dropm while the C thread is exiting. -// -// And the saved g will be used in pthread_key_destructor, -// since the g stored in the TLS by Go might be cleared in some platforms, -// before the destructor invoked, so, we restore g by the stored g, before dropm. -// -// We store g0 instead of m, to make the assembly code simpler, -// since we need to restore g0 in runtime.cgocallback. -// -// On systems without pthreads, like Windows, bindm shouldn't be used. -// -// NOTE: this always runs without a P, so, nowritebarrierrec required. -// -//go:nosplit -//go:nowritebarrierrec -func cgoBindM() { - if GOOS == "windows" || GOOS == "plan9" { - fatal("bindm in unexpected GOOS") - } - g := getg() - if g.m.g0 != g { - fatal("the current g is not g0") - } - if _cgo_bindm != nil { - asmcgocall(_cgo_bindm, unsafe.Pointer(g)) - } -} - -// A helper function for EnsureDropM. -func getm() uintptr { - return uintptr(unsafe.Pointer(getg().m)) -} - -var ( - // Locking linked list of extra M's, via mp.schedlink. Must be accessed - // only via lockextra/unlockextra. - // - // Can't be atomic.Pointer[m] because we use an invalid pointer as a - // "locked" sentinel value. M's on this list remain visible to the GC - // because their mp.curg is on allgs. - extraM atomic.Uintptr - // Number of M's in the extraM list. - extraMLength atomic.Uint32 - // Number of waiters in lockextra. - extraMWaiters atomic.Uint32 - - // Number of extra M's in use by threads. - extraMInUse atomic.Uint32 -) - -// lockextra locks the extra list and returns the list head. -// The caller must unlock the list by storing a new list head -// to extram. If nilokay is true, then lockextra will -// return a nil list head if that's what it finds. If nilokay is false, -// lockextra will keep waiting until the list head is no longer nil. -// -//go:nosplit -func lockextra(nilokay bool) *m { - const locked = 1 - - incr := false - for { - old := extraM.Load() - if old == locked { - osyield_no_g() - continue - } - if old == 0 && !nilokay { - if !incr { - // Add 1 to the number of threads - // waiting for an M. - // This is cleared by newextram. - extraMWaiters.Add(1) - incr = true - } - usleep_no_g(1) - continue - } - if extraM.CompareAndSwap(old, locked) { - return (*m)(unsafe.Pointer(old)) - } - osyield_no_g() - continue - } -} - -//go:nosplit -func unlockextra(mp *m, delta int32) { - extraMLength.Add(delta) - extraM.Store(uintptr(unsafe.Pointer(mp))) -} - -// Return an M from the extra M list. Returns last == true if the list becomes -// empty because of this call. -// -// Spins waiting for an extra M, so caller must ensure that the list always -// contains or will soon contain at least one M. -// -//go:nosplit -func getExtraM() (mp *m, last bool) { - mp = lockextra(false) - extraMInUse.Add(1) - unlockextra(mp.schedlink.ptr(), -1) - return mp, mp.schedlink.ptr() == nil -} - -// Returns an extra M back to the list. mp must be from getExtraM. Newly -// allocated M's should use addExtraM. -// -//go:nosplit -func putExtraM(mp *m) { - extraMInUse.Add(-1) - addExtraM(mp) -} - -// Adds a newly allocated M to the extra M list. -// -//go:nosplit -func addExtraM(mp *m) { - mnext := lockextra(true) - mp.schedlink.set(mnext) - unlockextra(mp, 1) -} - -var ( - // allocmLock is locked for read when creating new Ms in allocm and their - // addition to allm. Thus acquiring this lock for write blocks the - // creation of new Ms. - allocmLock rwmutex - - // execLock serializes exec and clone to avoid bugs or unspecified - // behaviour around exec'ing while creating/destroying threads. See - // issue #19546. - execLock rwmutex -) - -// These errors are reported (via writeErrStr) by some OS-specific -// versions of newosproc and newosproc0. -const ( - failthreadcreate = "runtime: failed to create new OS thread\n" - failallocatestack = "runtime: failed to allocate stack for the new OS thread\n" -) - -// newmHandoff contains a list of m structures that need new OS threads. -// This is used by newm in situations where newm itself can't safely -// start an OS thread. -var newmHandoff struct { - lock mutex - - // newm points to a list of M structures that need new OS - // threads. The list is linked through m.schedlink. - newm muintptr - - // waiting indicates that wake needs to be notified when an m - // is put on the list. - waiting bool - wake note - - // haveTemplateThread indicates that the templateThread has - // been started. This is not protected by lock. Use cas to set - // to 1. - haveTemplateThread uint32 -} - -// Create a new m. It will start off with a call to fn, or else the scheduler. -// fn needs to be static and not a heap allocated closure. -// May run with m.p==nil, so write barriers are not allowed. -// -// id is optional pre-allocated m ID. Omit by passing -1. -// -//go:nowritebarrierrec -func newm(fn func(), pp *p, id int64) { - // allocm adds a new M to allm, but they do not start until created by - // the OS in newm1 or the template thread. - // - // doAllThreadsSyscall requires that every M in allm will eventually - // start and be signal-able, even with a STW. - // - // Disable preemption here until we start the thread to ensure that - // newm is not preempted between allocm and starting the new thread, - // ensuring that anything added to allm is guaranteed to eventually - // start. - acquirem() - - mp := allocm(pp, fn, id) - mp.nextp.set(pp) - mp.sigmask = initSigmask - if gp := getg(); gp != nil && gp.m != nil && (gp.m.lockedExt != 0 || gp.m.incgo) && GOOS != "plan9" { - // We're on a locked M or a thread that may have been - // started by C. The kernel state of this thread may - // be strange (the user may have locked it for that - // purpose). We don't want to clone that into another - // thread. Instead, ask a known-good thread to create - // the thread for us. - // - // This is disabled on Plan 9. See golang.org/issue/22227. - // - // TODO: This may be unnecessary on Windows, which - // doesn't model thread creation off fork. - lock(&newmHandoff.lock) - if newmHandoff.haveTemplateThread == 0 { - throw("on a locked thread with no template thread") - } - mp.schedlink = newmHandoff.newm - newmHandoff.newm.set(mp) - if newmHandoff.waiting { - newmHandoff.waiting = false - notewakeup(&newmHandoff.wake) - } - unlock(&newmHandoff.lock) - // The M has not started yet, but the template thread does not - // participate in STW, so it will always process queued Ms and - // it is safe to releasem. - releasem(getg().m) - return - } - newm1(mp) - releasem(getg().m) -} - -func newm1(mp *m) { - if iscgo { - var ts cgothreadstart - if _cgo_thread_start == nil { - throw("_cgo_thread_start missing") - } - ts.g.set(mp.g0) - ts.tls = (*uint64)(unsafe.Pointer(&mp.tls[0])) - ts.fn = unsafe.Pointer(abi.FuncPCABI0(mstart)) - if msanenabled { - msanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts)) - } - if asanenabled { - asanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts)) - } - execLock.rlock() // Prevent process clone. - asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts)) - execLock.runlock() - return - } - execLock.rlock() // Prevent process clone. - newosproc(mp) - execLock.runlock() -} - -// startTemplateThread starts the template thread if it is not already -// running. -// -// The calling thread must itself be in a known-good state. -func startTemplateThread() { - if GOARCH == "wasm" { // no threads on wasm yet - return - } - - // Disable preemption to guarantee that the template thread will be - // created before a park once haveTemplateThread is set. - mp := acquirem() - if !atomic.Cas(&newmHandoff.haveTemplateThread, 0, 1) { - releasem(mp) - return - } - newm(templateThread, nil, -1) - releasem(mp) -} - -// templateThread is a thread in a known-good state that exists solely -// to start new threads in known-good states when the calling thread -// may not be in a good state. -// -// Many programs never need this, so templateThread is started lazily -// when we first enter a state that might lead to running on a thread -// in an unknown state. -// -// templateThread runs on an M without a P, so it must not have write -// barriers. -// -//go:nowritebarrierrec -func templateThread() { - lock(&sched.lock) - sched.nmsys++ - checkdead() - unlock(&sched.lock) - - for { - lock(&newmHandoff.lock) - for newmHandoff.newm != 0 { - newm := newmHandoff.newm.ptr() - newmHandoff.newm = 0 - unlock(&newmHandoff.lock) - for newm != nil { - next := newm.schedlink.ptr() - newm.schedlink = 0 - newm1(newm) - newm = next - } - lock(&newmHandoff.lock) - } - newmHandoff.waiting = true - noteclear(&newmHandoff.wake) - unlock(&newmHandoff.lock) - notesleep(&newmHandoff.wake) - } -} - -// Stops execution of the current m until new work is available. -// Returns with acquired P. -func stopm() { - gp := getg() - - if gp.m.locks != 0 { - throw("stopm holding locks") - } - if gp.m.p != 0 { - throw("stopm holding p") - } - if gp.m.spinning { - throw("stopm spinning") - } - - lock(&sched.lock) - mput(gp.m) - unlock(&sched.lock) - mPark() - acquirep(gp.m.nextp.ptr()) - gp.m.nextp = 0 -} - -func mspinning() { - // startm's caller incremented nmspinning. Set the new M's spinning. - getg().m.spinning = true -} - -// Schedules some M to run the p (creates an M if necessary). -// If p==nil, tries to get an idle P, if no idle P's does nothing. -// May run with m.p==nil, so write barriers are not allowed. -// If spinning is set, the caller has incremented nmspinning and must provide a -// P. startm will set m.spinning in the newly started M. -// -// Callers passing a non-nil P must call from a non-preemptible context. See -// comment on acquirem below. -// -// Argument lockheld indicates whether the caller already acquired the -// scheduler lock. Callers holding the lock when making the call must pass -// true. The lock might be temporarily dropped, but will be reacquired before -// returning. -// -// Must not have write barriers because this may be called without a P. -// -//go:nowritebarrierrec -func startm(pp *p, spinning, lockheld bool) { - // Disable preemption. - // - // Every owned P must have an owner that will eventually stop it in the - // event of a GC stop request. startm takes transient ownership of a P - // (either from argument or pidleget below) and transfers ownership to - // a started M, which will be responsible for performing the stop. - // - // Preemption must be disabled during this transient ownership, - // otherwise the P this is running on may enter GC stop while still - // holding the transient P, leaving that P in limbo and deadlocking the - // STW. - // - // Callers passing a non-nil P must already be in non-preemptible - // context, otherwise such preemption could occur on function entry to - // startm. Callers passing a nil P may be preemptible, so we must - // disable preemption before acquiring a P from pidleget below. - mp := acquirem() - if !lockheld { - lock(&sched.lock) - } - if pp == nil { - if spinning { - // TODO(prattmic): All remaining calls to this function - // with _p_ == nil could be cleaned up to find a P - // before calling startm. - throw("startm: P required for spinning=true") - } - pp, _ = pidleget(0) - if pp == nil { - if !lockheld { - unlock(&sched.lock) - } - releasem(mp) - return - } - } - nmp := mget() - if nmp == nil { - // No M is available, we must drop sched.lock and call newm. - // However, we already own a P to assign to the M. - // - // Once sched.lock is released, another G (e.g., in a syscall), - // could find no idle P while checkdead finds a runnable G but - // no running M's because this new M hasn't started yet, thus - // throwing in an apparent deadlock. - // This apparent deadlock is possible when startm is called - // from sysmon, which doesn't count as a running M. - // - // Avoid this situation by pre-allocating the ID for the new M, - // thus marking it as 'running' before we drop sched.lock. This - // new M will eventually run the scheduler to execute any - // queued G's. - id := mReserveID() - unlock(&sched.lock) - - var fn func() - if spinning { - // The caller incremented nmspinning, so set m.spinning in the new M. - fn = mspinning - } - newm(fn, pp, id) - - if lockheld { - lock(&sched.lock) - } - // Ownership transfer of pp committed by start in newm. - // Preemption is now safe. - releasem(mp) - return - } - if !lockheld { - unlock(&sched.lock) - } - if nmp.spinning { - throw("startm: m is spinning") - } - if nmp.nextp != 0 { - throw("startm: m has p") - } - if spinning && !runqempty(pp) { - throw("startm: p has runnable gs") - } - // The caller incremented nmspinning, so set m.spinning in the new M. - nmp.spinning = spinning - nmp.nextp.set(pp) - notewakeup(&nmp.park) - // Ownership transfer of pp committed by wakeup. Preemption is now - // safe. - releasem(mp) -} - -// Hands off P from syscall or locked M. -// Always runs without a P, so write barriers are not allowed. -// -//go:nowritebarrierrec -func handoffp(pp *p) { - // handoffp must start an M in any situation where - // findrunnable would return a G to run on pp. - - // if it has local work, start it straight away - if !runqempty(pp) || sched.runqsize != 0 { - startm(pp, false, false) - return - } - // if there's trace work to do, start it straight away - if (traceEnabled() || traceShuttingDown()) && traceReaderAvailable() != nil { - startm(pp, false, false) - return - } - // if it has GC work, start it straight away - if gcBlackenEnabled != 0 && gcMarkWorkAvailable(pp) { - startm(pp, false, false) - return - } - // no local work, check that there are no spinning/idle M's, - // otherwise our help is not required - if sched.nmspinning.Load()+sched.npidle.Load() == 0 && sched.nmspinning.CompareAndSwap(0, 1) { // TODO: fast atomic - sched.needspinning.Store(0) - startm(pp, true, false) - return - } - lock(&sched.lock) - if sched.gcwaiting.Load() { - pp.status = _Pgcstop - sched.stopwait-- - if sched.stopwait == 0 { - notewakeup(&sched.stopnote) - } - unlock(&sched.lock) - return - } - if pp.runSafePointFn != 0 && atomic.Cas(&pp.runSafePointFn, 1, 0) { - sched.safePointFn(pp) - sched.safePointWait-- - if sched.safePointWait == 0 { - notewakeup(&sched.safePointNote) - } - } - if sched.runqsize != 0 { - unlock(&sched.lock) - startm(pp, false, false) - return - } - // If this is the last running P and nobody is polling network, - // need to wakeup another M to poll network. - if sched.npidle.Load() == gomaxprocs-1 && sched.lastpoll.Load() != 0 { - unlock(&sched.lock) - startm(pp, false, false) - return - } - - // The scheduler lock cannot be held when calling wakeNetPoller below - // because wakeNetPoller may call wakep which may call startm. - when := nobarrierWakeTime(pp) - pidleput(pp, 0) - unlock(&sched.lock) - - if when != 0 { - wakeNetPoller(when) - } -} - -// Tries to add one more P to execute G's. -// Called when a G is made runnable (newproc, ready). -// Must be called with a P. -func wakep() { - // Be conservative about spinning threads, only start one if none exist - // already. - if sched.nmspinning.Load() != 0 || !sched.nmspinning.CompareAndSwap(0, 1) { - return - } - - // Disable preemption until ownership of pp transfers to the next M in - // startm. Otherwise preemption here would leave pp stuck waiting to - // enter _Pgcstop. - // - // See preemption comment on acquirem in startm for more details. - mp := acquirem() - - var pp *p - lock(&sched.lock) - pp, _ = pidlegetSpinning(0) - if pp == nil { - if sched.nmspinning.Add(-1) < 0 { - throw("wakep: negative nmspinning") - } - unlock(&sched.lock) - releasem(mp) - return - } - // Since we always have a P, the race in the "No M is available" - // comment in startm doesn't apply during the small window between the - // unlock here and lock in startm. A checkdead in between will always - // see at least one running M (ours). - unlock(&sched.lock) - - startm(pp, true, false) - - releasem(mp) -} - -// Stops execution of the current m that is locked to a g until the g is runnable again. -// Returns with acquired P. -func stoplockedm() { - gp := getg() - - if gp.m.lockedg == 0 || gp.m.lockedg.ptr().lockedm.ptr() != gp.m { - throw("stoplockedm: inconsistent locking") - } - if gp.m.p != 0 { - // Schedule another M to run this p. - pp := releasep() - handoffp(pp) - } - incidlelocked(1) - // Wait until another thread schedules lockedg again. - mPark() - status := readgstatus(gp.m.lockedg.ptr()) - if status&^_Gscan != _Grunnable { - print("runtime:stoplockedm: lockedg (atomicstatus=", status, ") is not Grunnable or Gscanrunnable\n") - dumpgstatus(gp.m.lockedg.ptr()) - throw("stoplockedm: not runnable") - } - acquirep(gp.m.nextp.ptr()) - gp.m.nextp = 0 -} - -// Schedules the locked m to run the locked gp. -// May run during STW, so write barriers are not allowed. -// -//go:nowritebarrierrec -func startlockedm(gp *g) { - mp := gp.lockedm.ptr() - if mp == getg().m { - throw("startlockedm: locked to me") - } - if mp.nextp != 0 { - throw("startlockedm: m has p") - } - // directly handoff current P to the locked m - incidlelocked(-1) - pp := releasep() - mp.nextp.set(pp) - notewakeup(&mp.park) - stopm() -} - -// Stops the current m for stopTheWorld. -// Returns when the world is restarted. -func gcstopm() { - gp := getg() - - if !sched.gcwaiting.Load() { - throw("gcstopm: not waiting for gc") - } - if gp.m.spinning { - gp.m.spinning = false - // OK to just drop nmspinning here, - // startTheWorld will unpark threads as necessary. - if sched.nmspinning.Add(-1) < 0 { - throw("gcstopm: negative nmspinning") - } - } - pp := releasep() - lock(&sched.lock) - pp.status = _Pgcstop - sched.stopwait-- - if sched.stopwait == 0 { - notewakeup(&sched.stopnote) - } - unlock(&sched.lock) - stopm() -} - -// Schedules gp to run on the current M. -// If inheritTime is true, gp inherits the remaining time in the -// current time slice. Otherwise, it starts a new time slice. -// Never returns. -// -// Write barriers are allowed because this is called immediately after -// acquiring a P in several places. -// -//go:yeswritebarrierrec -func execute(gp *g, inheritTime bool) { - mp := getg().m - - if goroutineProfile.active { - // Make sure that gp has had its stack written out to the goroutine - // profile, exactly as it was when the goroutine profiler first stopped - // the world. - tryRecordGoroutineProfile(gp, osyield) - } - - // Assign gp.m before entering _Grunning so running Gs have an - // M. - mp.curg = gp - gp.m = mp - casgstatus(gp, _Grunnable, _Grunning) - gp.waitsince = 0 - gp.preempt = false - gp.stackguard0 = gp.stack.lo + stackGuard - if !inheritTime { - mp.p.ptr().schedtick++ - } - - // Check whether the profiler needs to be turned on or off. - hz := sched.profilehz - if mp.profilehz != hz { - setThreadCPUProfiler(hz) - } - - trace := traceAcquire() - if trace.ok() { - // GoSysExit has to happen when we have a P, but before GoStart. - // So we emit it here. - if !goexperiment.ExecTracer2 && gp.syscallsp != 0 { - trace.GoSysExit(true) - } - trace.GoStart() - traceRelease(trace) - } - - gogo(&gp.sched) -} - -// Finds a runnable goroutine to execute. -// Tries to steal from other P's, get g from local or global queue, poll network. -// tryWakeP indicates that the returned goroutine is not normal (GC worker, trace -// reader) so the caller should try to wake a P. -func findRunnable() (gp *g, inheritTime, tryWakeP bool) { - mp := getg().m - - // The conditions here and in handoffp must agree: if - // findrunnable would return a G to run, handoffp must start - // an M. - -top: - pp := mp.p.ptr() - if sched.gcwaiting.Load() { - gcstopm() - goto top - } - if pp.runSafePointFn != 0 { - runSafePointFn() - } - - // now and pollUntil are saved for work stealing later, - // which may steal timers. It's important that between now - // and then, nothing blocks, so these numbers remain mostly - // relevant. - now, pollUntil, _ := checkTimers(pp, 0) - - // Try to schedule the trace reader. - if traceEnabled() || traceShuttingDown() { - gp := traceReader() - if gp != nil { - trace := traceAcquire() - casgstatus(gp, _Gwaiting, _Grunnable) - if trace.ok() { - trace.GoUnpark(gp, 0) - traceRelease(trace) - } - return gp, false, true - } - } - - // Try to schedule a GC worker. - if gcBlackenEnabled != 0 { - gp, tnow := gcController.findRunnableGCWorker(pp, now) - if gp != nil { - return gp, false, true - } - now = tnow - } - - // Check the global runnable queue once in a while to ensure fairness. - // Otherwise two goroutines can completely occupy the local runqueue - // by constantly respawning each other. - if pp.schedtick%61 == 0 && sched.runqsize > 0 { - lock(&sched.lock) - gp := globrunqget(pp, 1) - unlock(&sched.lock) - if gp != nil { - return gp, false, false - } - } - - // Wake up the finalizer G. - if fingStatus.Load()&(fingWait|fingWake) == fingWait|fingWake { - if gp := wakefing(); gp != nil { - ready(gp, 0, true) - } - } - if *cgo_yield != nil { - asmcgocall(*cgo_yield, nil) - } - - // local runq - if gp, inheritTime := runqget(pp); gp != nil { - return gp, inheritTime, false - } - - // global runq - if sched.runqsize != 0 { - lock(&sched.lock) - gp := globrunqget(pp, 0) - unlock(&sched.lock) - if gp != nil { - return gp, false, false - } - } - - // Poll network. - // This netpoll is only an optimization before we resort to stealing. - // We can safely skip it if there are no waiters or a thread is blocked - // in netpoll already. If there is any kind of logical race with that - // blocked thread (e.g. it has already returned from netpoll, but does - // not set lastpoll yet), this thread will do blocking netpoll below - // anyway. - if netpollinited() && netpollAnyWaiters() && sched.lastpoll.Load() != 0 { - if list, delta := netpoll(0); !list.empty() { // non-blocking - gp := list.pop() - injectglist(&list) - netpollAdjustWaiters(delta) - trace := traceAcquire() - casgstatus(gp, _Gwaiting, _Grunnable) - if trace.ok() { - trace.GoUnpark(gp, 0) - traceRelease(trace) - } - return gp, false, false - } - } - - // Spinning Ms: steal work from other Ps. - // - // Limit the number of spinning Ms to half the number of busy Ps. - // This is necessary to prevent excessive CPU consumption when - // GOMAXPROCS>>1 but the program parallelism is low. - if mp.spinning || 2*sched.nmspinning.Load() < gomaxprocs-sched.npidle.Load() { - if !mp.spinning { - mp.becomeSpinning() - } - - gp, inheritTime, tnow, w, newWork := stealWork(now) - if gp != nil { - // Successfully stole. - return gp, inheritTime, false - } - if newWork { - // There may be new timer or GC work; restart to - // discover. - goto top - } - - now = tnow - if w != 0 && (pollUntil == 0 || w < pollUntil) { - // Earlier timer to wait for. - pollUntil = w - } - } - - // We have nothing to do. - // - // If we're in the GC mark phase, can safely scan and blacken objects, - // and have work to do, run idle-time marking rather than give up the P. - if gcBlackenEnabled != 0 && gcMarkWorkAvailable(pp) && gcController.addIdleMarkWorker() { - node := (*gcBgMarkWorkerNode)(gcBgMarkWorkerPool.pop()) - if node != nil { - pp.gcMarkWorkerMode = gcMarkWorkerIdleMode - gp := node.gp.ptr() - - trace := traceAcquire() - casgstatus(gp, _Gwaiting, _Grunnable) - if trace.ok() { - trace.GoUnpark(gp, 0) - traceRelease(trace) - } - return gp, false, false - } - gcController.removeIdleMarkWorker() - } - - // wasm only: - // If a callback returned and no other goroutine is awake, - // then wake event handler goroutine which pauses execution - // until a callback was triggered. - gp, otherReady := beforeIdle(now, pollUntil) - if gp != nil { - trace := traceAcquire() - casgstatus(gp, _Gwaiting, _Grunnable) - if trace.ok() { - trace.GoUnpark(gp, 0) - traceRelease(trace) - } - return gp, false, false - } - if otherReady { - goto top - } - - // Before we drop our P, make a snapshot of the allp slice, - // which can change underfoot once we no longer block - // safe-points. We don't need to snapshot the contents because - // everything up to cap(allp) is immutable. - allpSnapshot := allp - // Also snapshot masks. Value changes are OK, but we can't allow - // len to change out from under us. - idlepMaskSnapshot := idlepMask - timerpMaskSnapshot := timerpMask - - // return P and block - lock(&sched.lock) - if sched.gcwaiting.Load() || pp.runSafePointFn != 0 { - unlock(&sched.lock) - goto top - } - if sched.runqsize != 0 { - gp := globrunqget(pp, 0) - unlock(&sched.lock) - return gp, false, false - } - if !mp.spinning && sched.needspinning.Load() == 1 { - // See "Delicate dance" comment below. - mp.becomeSpinning() - unlock(&sched.lock) - goto top - } - if releasep() != pp { - throw("findrunnable: wrong p") - } - now = pidleput(pp, now) - unlock(&sched.lock) - - // Delicate dance: thread transitions from spinning to non-spinning - // state, potentially concurrently with submission of new work. We must - // drop nmspinning first and then check all sources again (with - // #StoreLoad memory barrier in between). If we do it the other way - // around, another thread can submit work after we've checked all - // sources but before we drop nmspinning; as a result nobody will - // unpark a thread to run the work. - // - // This applies to the following sources of work: - // - // * Goroutines added to the global or a per-P run queue. - // * New/modified-earlier timers on a per-P timer heap. - // * Idle-priority GC work (barring golang.org/issue/19112). - // - // If we discover new work below, we need to restore m.spinning as a - // signal for resetspinning to unpark a new worker thread (because - // there can be more than one starving goroutine). - // - // However, if after discovering new work we also observe no idle Ps - // (either here or in resetspinning), we have a problem. We may be - // racing with a non-spinning M in the block above, having found no - // work and preparing to release its P and park. Allowing that P to go - // idle will result in loss of work conservation (idle P while there is - // runnable work). This could result in complete deadlock in the - // unlikely event that we discover new work (from netpoll) right as we - // are racing with _all_ other Ps going idle. - // - // We use sched.needspinning to synchronize with non-spinning Ms going - // idle. If needspinning is set when they are about to drop their P, - // they abort the drop and instead become a new spinning M on our - // behalf. If we are not racing and the system is truly fully loaded - // then no spinning threads are required, and the next thread to - // naturally become spinning will clear the flag. - // - // Also see "Worker thread parking/unparking" comment at the top of the - // file. - wasSpinning := mp.spinning - if mp.spinning { - mp.spinning = false - if sched.nmspinning.Add(-1) < 0 { - throw("findrunnable: negative nmspinning") - } - - // Note the for correctness, only the last M transitioning from - // spinning to non-spinning must perform these rechecks to - // ensure no missed work. However, the runtime has some cases - // of transient increments of nmspinning that are decremented - // without going through this path, so we must be conservative - // and perform the check on all spinning Ms. - // - // See https://go.dev/issue/43997. - - // Check global and P runqueues again. - - lock(&sched.lock) - if sched.runqsize != 0 { - pp, _ := pidlegetSpinning(0) - if pp != nil { - gp := globrunqget(pp, 0) - if gp == nil { - throw("global runq empty with non-zero runqsize") - } - unlock(&sched.lock) - acquirep(pp) - mp.becomeSpinning() - return gp, false, false - } - } - unlock(&sched.lock) - - pp := checkRunqsNoP(allpSnapshot, idlepMaskSnapshot) - if pp != nil { - acquirep(pp) - mp.becomeSpinning() - goto top - } - - // Check for idle-priority GC work again. - pp, gp := checkIdleGCNoP() - if pp != nil { - acquirep(pp) - mp.becomeSpinning() - - // Run the idle worker. - pp.gcMarkWorkerMode = gcMarkWorkerIdleMode - trace := traceAcquire() - casgstatus(gp, _Gwaiting, _Grunnable) - if trace.ok() { - trace.GoUnpark(gp, 0) - traceRelease(trace) - } - return gp, false, false - } - - // Finally, check for timer creation or expiry concurrently with - // transitioning from spinning to non-spinning. - // - // Note that we cannot use checkTimers here because it calls - // adjusttimers which may need to allocate memory, and that isn't - // allowed when we don't have an active P. - pollUntil = checkTimersNoP(allpSnapshot, timerpMaskSnapshot, pollUntil) - } - - // Poll network until next timer. - if netpollinited() && (netpollAnyWaiters() || pollUntil != 0) && sched.lastpoll.Swap(0) != 0 { - sched.pollUntil.Store(pollUntil) - if mp.p != 0 { - throw("findrunnable: netpoll with p") - } - if mp.spinning { - throw("findrunnable: netpoll with spinning") - } - delay := int64(-1) - if pollUntil != 0 { - if now == 0 { - now = nanotime() - } - delay = pollUntil - now - if delay < 0 { - delay = 0 - } - } - if faketime != 0 { - // When using fake time, just poll. - delay = 0 - } - list, delta := netpoll(delay) // block until new work is available - // Refresh now again, after potentially blocking. - now = nanotime() - sched.pollUntil.Store(0) - sched.lastpoll.Store(now) - if faketime != 0 && list.empty() { - // Using fake time and nothing is ready; stop M. - // When all M's stop, checkdead will call timejump. - stopm() - goto top - } - lock(&sched.lock) - pp, _ := pidleget(now) - unlock(&sched.lock) - if pp == nil { - injectglist(&list) - netpollAdjustWaiters(delta) - } else { - acquirep(pp) - if !list.empty() { - gp := list.pop() - injectglist(&list) - netpollAdjustWaiters(delta) - trace := traceAcquire() - casgstatus(gp, _Gwaiting, _Grunnable) - if trace.ok() { - trace.GoUnpark(gp, 0) - traceRelease(trace) - } - return gp, false, false - } - if wasSpinning { - mp.becomeSpinning() - } - goto top - } - } else if pollUntil != 0 && netpollinited() { - pollerPollUntil := sched.pollUntil.Load() - if pollerPollUntil == 0 || pollerPollUntil > pollUntil { - netpollBreak() - } - } - stopm() - goto top -} - -// pollWork reports whether there is non-background work this P could -// be doing. This is a fairly lightweight check to be used for -// background work loops, like idle GC. It checks a subset of the -// conditions checked by the actual scheduler. -func pollWork() bool { - if sched.runqsize != 0 { - return true - } - p := getg().m.p.ptr() - if !runqempty(p) { - return true - } - if netpollinited() && netpollAnyWaiters() && sched.lastpoll.Load() != 0 { - if list, delta := netpoll(0); !list.empty() { - injectglist(&list) - netpollAdjustWaiters(delta) - return true - } - } - return false -} - -// stealWork attempts to steal a runnable goroutine or timer from any P. -// -// If newWork is true, new work may have been readied. -// -// If now is not 0 it is the current time. stealWork returns the passed time or -// the current time if now was passed as 0. -func stealWork(now int64) (gp *g, inheritTime bool, rnow, pollUntil int64, newWork bool) { - pp := getg().m.p.ptr() - - ranTimer := false - - const stealTries = 4 - for i := 0; i < stealTries; i++ { - stealTimersOrRunNextG := i == stealTries-1 - - for enum := stealOrder.start(cheaprand()); !enum.done(); enum.next() { - if sched.gcwaiting.Load() { - // GC work may be available. - return nil, false, now, pollUntil, true - } - p2 := allp[enum.position()] - if pp == p2 { - continue - } - - // Steal timers from p2. This call to checkTimers is the only place - // where we might hold a lock on a different P's timers. We do this - // once on the last pass before checking runnext because stealing - // from the other P's runnext should be the last resort, so if there - // are timers to steal do that first. - // - // We only check timers on one of the stealing iterations because - // the time stored in now doesn't change in this loop and checking - // the timers for each P more than once with the same value of now - // is probably a waste of time. - // - // timerpMask tells us whether the P may have timers at all. If it - // can't, no need to check at all. - if stealTimersOrRunNextG && timerpMask.read(enum.position()) { - tnow, w, ran := checkTimers(p2, now) - now = tnow - if w != 0 && (pollUntil == 0 || w < pollUntil) { - pollUntil = w - } - if ran { - // Running the timers may have - // made an arbitrary number of G's - // ready and added them to this P's - // local run queue. That invalidates - // the assumption of runqsteal - // that it always has room to add - // stolen G's. So check now if there - // is a local G to run. - if gp, inheritTime := runqget(pp); gp != nil { - return gp, inheritTime, now, pollUntil, ranTimer - } - ranTimer = true - } - } - - // Don't bother to attempt to steal if p2 is idle. - if !idlepMask.read(enum.position()) { - if gp := runqsteal(pp, p2, stealTimersOrRunNextG); gp != nil { - return gp, false, now, pollUntil, ranTimer - } - } - } - } - - // No goroutines found to steal. Regardless, running a timer may have - // made some goroutine ready that we missed. Indicate the next timer to - // wait for. - return nil, false, now, pollUntil, ranTimer -} - -// Check all Ps for a runnable G to steal. -// -// On entry we have no P. If a G is available to steal and a P is available, -// the P is returned which the caller should acquire and attempt to steal the -// work to. -func checkRunqsNoP(allpSnapshot []*p, idlepMaskSnapshot pMask) *p { - for id, p2 := range allpSnapshot { - if !idlepMaskSnapshot.read(uint32(id)) && !runqempty(p2) { - lock(&sched.lock) - pp, _ := pidlegetSpinning(0) - if pp == nil { - // Can't get a P, don't bother checking remaining Ps. - unlock(&sched.lock) - return nil - } - unlock(&sched.lock) - return pp - } - } - - // No work available. - return nil -} - -// Check all Ps for a timer expiring sooner than pollUntil. -// -// Returns updated pollUntil value. -func checkTimersNoP(allpSnapshot []*p, timerpMaskSnapshot pMask, pollUntil int64) int64 { - for id, p2 := range allpSnapshot { - if timerpMaskSnapshot.read(uint32(id)) { - w := nobarrierWakeTime(p2) - if w != 0 && (pollUntil == 0 || w < pollUntil) { - pollUntil = w - } - } - } - - return pollUntil -} - -// Check for idle-priority GC, without a P on entry. -// -// If some GC work, a P, and a worker G are all available, the P and G will be -// returned. The returned P has not been wired yet. -func checkIdleGCNoP() (*p, *g) { - // N.B. Since we have no P, gcBlackenEnabled may change at any time; we - // must check again after acquiring a P. As an optimization, we also check - // if an idle mark worker is needed at all. This is OK here, because if we - // observe that one isn't needed, at least one is currently running. Even if - // it stops running, its own journey into the scheduler should schedule it - // again, if need be (at which point, this check will pass, if relevant). - if atomic.Load(&gcBlackenEnabled) == 0 || !gcController.needIdleMarkWorker() { - return nil, nil - } - if !gcMarkWorkAvailable(nil) { - return nil, nil - } - - // Work is available; we can start an idle GC worker only if there is - // an available P and available worker G. - // - // We can attempt to acquire these in either order, though both have - // synchronization concerns (see below). Workers are almost always - // available (see comment in findRunnableGCWorker for the one case - // there may be none). Since we're slightly less likely to find a P, - // check for that first. - // - // Synchronization: note that we must hold sched.lock until we are - // committed to keeping it. Otherwise we cannot put the unnecessary P - // back in sched.pidle without performing the full set of idle - // transition checks. - // - // If we were to check gcBgMarkWorkerPool first, we must somehow handle - // the assumption in gcControllerState.findRunnableGCWorker that an - // empty gcBgMarkWorkerPool is only possible if gcMarkDone is running. - lock(&sched.lock) - pp, now := pidlegetSpinning(0) - if pp == nil { - unlock(&sched.lock) - return nil, nil - } - - // Now that we own a P, gcBlackenEnabled can't change (as it requires STW). - if gcBlackenEnabled == 0 || !gcController.addIdleMarkWorker() { - pidleput(pp, now) - unlock(&sched.lock) - return nil, nil - } - - node := (*gcBgMarkWorkerNode)(gcBgMarkWorkerPool.pop()) - if node == nil { - pidleput(pp, now) - unlock(&sched.lock) - gcController.removeIdleMarkWorker() - return nil, nil - } - - unlock(&sched.lock) - - return pp, node.gp.ptr() -} - -// wakeNetPoller wakes up the thread sleeping in the network poller if it isn't -// going to wake up before the when argument; or it wakes an idle P to service -// timers and the network poller if there isn't one already. -func wakeNetPoller(when int64) { - if sched.lastpoll.Load() == 0 { - // In findrunnable we ensure that when polling the pollUntil - // field is either zero or the time to which the current - // poll is expected to run. This can have a spurious wakeup - // but should never miss a wakeup. - pollerPollUntil := sched.pollUntil.Load() - if pollerPollUntil == 0 || pollerPollUntil > when { - netpollBreak() - } - } else { - // There are no threads in the network poller, try to get - // one there so it can handle new timers. - if GOOS != "plan9" { // Temporary workaround - see issue #42303. - wakep() - } - } -} - -func resetspinning() { - gp := getg() - if !gp.m.spinning { - throw("resetspinning: not a spinning m") - } - gp.m.spinning = false - nmspinning := sched.nmspinning.Add(-1) - if nmspinning < 0 { - throw("findrunnable: negative nmspinning") - } - // M wakeup policy is deliberately somewhat conservative, so check if we - // need to wakeup another P here. See "Worker thread parking/unparking" - // comment at the top of the file for details. - wakep() -} - -// injectglist adds each runnable G on the list to some run queue, -// and clears glist. If there is no current P, they are added to the -// global queue, and up to npidle M's are started to run them. -// Otherwise, for each idle P, this adds a G to the global queue -// and starts an M. Any remaining G's are added to the current P's -// local run queue. -// This may temporarily acquire sched.lock. -// Can run concurrently with GC. -func injectglist(glist *gList) { - if glist.empty() { - return - } - trace := traceAcquire() - if trace.ok() { - for gp := glist.head.ptr(); gp != nil; gp = gp.schedlink.ptr() { - trace.GoUnpark(gp, 0) - } - traceRelease(trace) - } - - // Mark all the goroutines as runnable before we put them - // on the run queues. - head := glist.head.ptr() - var tail *g - qsize := 0 - for gp := head; gp != nil; gp = gp.schedlink.ptr() { - tail = gp - qsize++ - casgstatus(gp, _Gwaiting, _Grunnable) - } - - // Turn the gList into a gQueue. - var q gQueue - q.head.set(head) - q.tail.set(tail) - *glist = gList{} - - startIdle := func(n int) { - for i := 0; i < n; i++ { - mp := acquirem() // See comment in startm. - lock(&sched.lock) - - pp, _ := pidlegetSpinning(0) - if pp == nil { - unlock(&sched.lock) - releasem(mp) - break - } - - startm(pp, false, true) - unlock(&sched.lock) - releasem(mp) - } - } - - pp := getg().m.p.ptr() - if pp == nil { - lock(&sched.lock) - globrunqputbatch(&q, int32(qsize)) - unlock(&sched.lock) - startIdle(qsize) - return - } - - npidle := int(sched.npidle.Load()) - var globq gQueue - var n int - for n = 0; n < npidle && !q.empty(); n++ { - g := q.pop() - globq.pushBack(g) - } - if n > 0 { - lock(&sched.lock) - globrunqputbatch(&globq, int32(n)) - unlock(&sched.lock) - startIdle(n) - qsize -= n - } - - if !q.empty() { - runqputbatch(pp, &q, qsize) - } -} - -// One round of scheduler: find a runnable goroutine and execute it. -// Never returns. -func schedule() { - mp := getg().m - - if mp.locks != 0 { - throw("schedule: holding locks") - } - - if mp.lockedg != 0 { - stoplockedm() - execute(mp.lockedg.ptr(), false) // Never returns. - } - - // We should not schedule away from a g that is executing a cgo call, - // since the cgo call is using the m's g0 stack. - if mp.incgo { - throw("schedule: in cgo") - } - -top: - pp := mp.p.ptr() - pp.preempt = false - - // Safety check: if we are spinning, the run queue should be empty. - // Check this before calling checkTimers, as that might call - // goready to put a ready goroutine on the local run queue. - if mp.spinning && (pp.runnext != 0 || pp.runqhead != pp.runqtail) { - throw("schedule: spinning with local work") - } - - gp, inheritTime, tryWakeP := findRunnable() // blocks until work is available - - if debug.dontfreezetheworld > 0 && freezing.Load() { - // See comment in freezetheworld. We don't want to perturb - // scheduler state, so we didn't gcstopm in findRunnable, but - // also don't want to allow new goroutines to run. - // - // Deadlock here rather than in the findRunnable loop so if - // findRunnable is stuck in a loop we don't perturb that - // either. - lock(&deadlock) - lock(&deadlock) - } - - // This thread is going to run a goroutine and is not spinning anymore, - // so if it was marked as spinning we need to reset it now and potentially - // start a new spinning M. - if mp.spinning { - resetspinning() - } - - if sched.disable.user && !schedEnabled(gp) { - // Scheduling of this goroutine is disabled. Put it on - // the list of pending runnable goroutines for when we - // re-enable user scheduling and look again. - lock(&sched.lock) - if schedEnabled(gp) { - // Something re-enabled scheduling while we - // were acquiring the lock. - unlock(&sched.lock) - } else { - sched.disable.runnable.pushBack(gp) - sched.disable.n++ - unlock(&sched.lock) - goto top - } - } - - // If about to schedule a not-normal goroutine (a GCworker or tracereader), - // wake a P if there is one. - if tryWakeP { - wakep() - } - if gp.lockedm != 0 { - // Hands off own p to the locked m, - // then blocks waiting for a new p. - startlockedm(gp) - goto top - } - - execute(gp, inheritTime) -} - -// dropg removes the association between m and the current goroutine m->curg (gp for short). -// Typically a caller sets gp's status away from Grunning and then -// immediately calls dropg to finish the job. The caller is also responsible -// for arranging that gp will be restarted using ready at an -// appropriate time. After calling dropg and arranging for gp to be -// readied later, the caller can do other work but eventually should -// call schedule to restart the scheduling of goroutines on this m. -func dropg() { - gp := getg() - - setMNoWB(&gp.m.curg.m, nil) - setGNoWB(&gp.m.curg, nil) -} - -// checkTimers runs any timers for the P that are ready. -// If now is not 0 it is the current time. -// It returns the passed time or the current time if now was passed as 0. -// and the time when the next timer should run or 0 if there is no next timer, -// and reports whether it ran any timers. -// If the time when the next timer should run is not 0, -// it is always larger than the returned time. -// We pass now in and out to avoid extra calls of nanotime. -// -//go:yeswritebarrierrec -func checkTimers(pp *p, now int64) (rnow, pollUntil int64, ran bool) { - // If it's not yet time for the first timer, or the first adjusted - // timer, then there is nothing to do. - next := pp.timer0When.Load() - nextAdj := pp.timerModifiedEarliest.Load() - if next == 0 || (nextAdj != 0 && nextAdj < next) { - next = nextAdj - } - - if next == 0 { - // No timers to run or adjust. - return now, 0, false - } - - if now == 0 { - now = nanotime() - } - if now < next { - // Next timer is not ready to run, but keep going - // if we would clear deleted timers. - // This corresponds to the condition below where - // we decide whether to call clearDeletedTimers. - if pp != getg().m.p.ptr() || int(pp.deletedTimers.Load()) <= int(pp.numTimers.Load()/4) { - return now, next, false - } - } - - lock(&pp.timersLock) - - if len(pp.timers) > 0 { - adjusttimers(pp, now) - for len(pp.timers) > 0 { - // Note that runtimer may temporarily unlock - // pp.timersLock. - if tw := runtimer(pp, now); tw != 0 { - if tw > 0 { - pollUntil = tw - } - break - } - ran = true - } - } - - // If this is the local P, and there are a lot of deleted timers, - // clear them out. We only do this for the local P to reduce - // lock contention on timersLock. - if pp == getg().m.p.ptr() && int(pp.deletedTimers.Load()) > len(pp.timers)/4 { - clearDeletedTimers(pp) - } - - unlock(&pp.timersLock) - - return now, pollUntil, ran -} - -func parkunlock_c(gp *g, lock unsafe.Pointer) bool { - unlock((*mutex)(lock)) - return true -} - -// park continuation on g0. -func park_m(gp *g) { - mp := getg().m - - trace := traceAcquire() - - // N.B. Not using casGToWaiting here because the waitreason is - // set by park_m's caller. - casgstatus(gp, _Grunning, _Gwaiting) - if trace.ok() { - trace.GoPark(mp.waitTraceBlockReason, mp.waitTraceSkip) - traceRelease(trace) - } - - dropg() - - if fn := mp.waitunlockf; fn != nil { - ok := fn(gp, mp.waitlock) - mp.waitunlockf = nil - mp.waitlock = nil - if !ok { - trace := traceAcquire() - casgstatus(gp, _Gwaiting, _Grunnable) - if trace.ok() { - trace.GoUnpark(gp, 2) - traceRelease(trace) - } - execute(gp, true) // Schedule it back, never returns. - } - } - schedule() -} - -func goschedImpl(gp *g, preempted bool) { - trace := traceAcquire() - status := readgstatus(gp) - if status&^_Gscan != _Grunning { - dumpgstatus(gp) - throw("bad g status") - } - casgstatus(gp, _Grunning, _Grunnable) - if trace.ok() { - if preempted { - trace.GoPreempt() - } else { - trace.GoSched() - } - traceRelease(trace) - } - - dropg() - lock(&sched.lock) - globrunqput(gp) - unlock(&sched.lock) - - if mainStarted { - wakep() - } - - schedule() -} - -// Gosched continuation on g0. -func gosched_m(gp *g) { - goschedImpl(gp, false) -} - -// goschedguarded is a forbidden-states-avoided version of gosched_m. -func goschedguarded_m(gp *g) { - if !canPreemptM(gp.m) { - gogo(&gp.sched) // never return - } - goschedImpl(gp, false) -} - -func gopreempt_m(gp *g) { - goschedImpl(gp, true) -} - -// preemptPark parks gp and puts it in _Gpreempted. -// -//go:systemstack -func preemptPark(gp *g) { - status := readgstatus(gp) - if status&^_Gscan != _Grunning { - dumpgstatus(gp) - throw("bad g status") - } - - if gp.asyncSafePoint { - // Double-check that async preemption does not - // happen in SPWRITE assembly functions. - // isAsyncSafePoint must exclude this case. - f := findfunc(gp.sched.pc) - if !f.valid() { - throw("preempt at unknown pc") - } - if f.flag&abi.FuncFlagSPWrite != 0 { - println("runtime: unexpected SPWRITE function", funcname(f), "in async preempt") - throw("preempt SPWRITE") - } - } - - // Transition from _Grunning to _Gscan|_Gpreempted. We can't - // be in _Grunning when we dropg because then we'd be running - // without an M, but the moment we're in _Gpreempted, - // something could claim this G before we've fully cleaned it - // up. Hence, we set the scan bit to lock down further - // transitions until we can dropg. - casGToPreemptScan(gp, _Grunning, _Gscan|_Gpreempted) - dropg() - - // Be careful about how we trace this next event. The ordering - // is subtle. - // - // The moment we CAS into _Gpreempted, suspendG could CAS to - // _Gwaiting, do its work, and ready the goroutine. All of - // this could happen before we even get the chance to emit - // an event. The end result is that the events could appear - // out of order, and the tracer generally assumes the scheduler - // takes care of the ordering between GoPark and GoUnpark. - // - // The answer here is simple: emit the event while we still hold - // the _Gscan bit on the goroutine. We still need to traceAcquire - // and traceRelease across the CAS because the tracer could be - // what's calling suspendG in the first place, and we want the - // CAS and event emission to appear atomic to the tracer. - trace := traceAcquire() - if trace.ok() { - trace.GoPark(traceBlockPreempted, 0) - } - casfrom_Gscanstatus(gp, _Gscan|_Gpreempted, _Gpreempted) - if trace.ok() { - traceRelease(trace) - } - schedule() -} - -// goyield is like Gosched, but it: -// - emits a GoPreempt trace event instead of a GoSched trace event -// - puts the current G on the runq of the current P instead of the globrunq -func goyield() { - checkTimeouts() - mcall(goyield_m) -} - -func goyield_m(gp *g) { - trace := traceAcquire() - pp := gp.m.p.ptr() - casgstatus(gp, _Grunning, _Grunnable) - if trace.ok() { - trace.GoPreempt() - traceRelease(trace) - } - dropg() - runqput(pp, gp, false) - schedule() -} - -// Finishes execution of the current goroutine. -func goexit1() { - if raceenabled { - racegoend() - } - trace := traceAcquire() - if trace.ok() { - trace.GoEnd() - traceRelease(trace) - } - mcall(goexit0) -} - -// goexit continuation on g0. -func goexit0(gp *g) { - gdestroy(gp) - schedule() -} - -func gdestroy(gp *g) { - mp := getg().m - pp := mp.p.ptr() - - casgstatus(gp, _Grunning, _Gdead) - gcController.addScannableStack(pp, -int64(gp.stack.hi-gp.stack.lo)) - if isSystemGoroutine(gp, false) { - sched.ngsys.Add(-1) - } - gp.m = nil - locked := gp.lockedm != 0 - gp.lockedm = 0 - mp.lockedg = 0 - gp.preemptStop = false - gp.paniconfault = false - gp._defer = nil // should be true already but just in case. - gp._panic = nil // non-nil for Goexit during panic. points at stack-allocated data. - gp.writebuf = nil - gp.waitreason = waitReasonZero - gp.param = nil - gp.labels = nil - gp.timer = nil - - if gcBlackenEnabled != 0 && gp.gcAssistBytes > 0 { - // Flush assist credit to the global pool. This gives - // better information to pacing if the application is - // rapidly creating an exiting goroutines. - assistWorkPerByte := gcController.assistWorkPerByte.Load() - scanCredit := int64(assistWorkPerByte * float64(gp.gcAssistBytes)) - gcController.bgScanCredit.Add(scanCredit) - gp.gcAssistBytes = 0 - } - - dropg() - - if GOARCH == "wasm" { // no threads yet on wasm - gfput(pp, gp) - return - } - - if mp.lockedInt != 0 { - print("invalid m->lockedInt = ", mp.lockedInt, "\n") - throw("internal lockOSThread error") - } - gfput(pp, gp) - if locked { - // The goroutine may have locked this thread because - // it put it in an unusual kernel state. Kill it - // rather than returning it to the thread pool. - - // Return to mstart, which will release the P and exit - // the thread. - if GOOS != "plan9" { // See golang.org/issue/22227. - gogo(&mp.g0.sched) - } else { - // Clear lockedExt on plan9 since we may end up re-using - // this thread. - mp.lockedExt = 0 - } - } -} - -// save updates getg().sched to refer to pc and sp so that a following -// gogo will restore pc and sp. -// -// save must not have write barriers because invoking a write barrier -// can clobber getg().sched. -// -//go:nosplit -//go:nowritebarrierrec -func save(pc, sp uintptr) { - gp := getg() - - if gp == gp.m.g0 || gp == gp.m.gsignal { - // m.g0.sched is special and must describe the context - // for exiting the thread. mstart1 writes to it directly. - // m.gsignal.sched should not be used at all. - // This check makes sure save calls do not accidentally - // run in contexts where they'd write to system g's. - throw("save on system g not allowed") - } - - gp.sched.pc = pc - gp.sched.sp = sp - gp.sched.lr = 0 - gp.sched.ret = 0 - // We need to ensure ctxt is zero, but can't have a write - // barrier here. However, it should always already be zero. - // Assert that. - if gp.sched.ctxt != nil { - badctxt() - } -} - -// The goroutine g is about to enter a system call. -// Record that it's not using the cpu anymore. -// This is called only from the go syscall library and cgocall, -// not from the low-level system calls used by the runtime. -// -// Entersyscall cannot split the stack: the save must -// make g->sched refer to the caller's stack segment, because -// entersyscall is going to return immediately after. -// -// Nothing entersyscall calls can split the stack either. -// We cannot safely move the stack during an active call to syscall, -// because we do not know which of the uintptr arguments are -// really pointers (back into the stack). -// In practice, this means that we make the fast path run through -// entersyscall doing no-split things, and the slow path has to use systemstack -// to run bigger things on the system stack. -// -// reentersyscall is the entry point used by cgo callbacks, where explicitly -// saved SP and PC are restored. This is needed when exitsyscall will be called -// from a function further up in the call stack than the parent, as g->syscallsp -// must always point to a valid stack frame. entersyscall below is the normal -// entry point for syscalls, which obtains the SP and PC from the caller. -// -// Syscall tracing (old tracer): -// At the start of a syscall we emit traceGoSysCall to capture the stack trace. -// If the syscall does not block, that is it, we do not emit any other events. -// If the syscall blocks (that is, P is retaken), retaker emits traceGoSysBlock; -// when syscall returns we emit traceGoSysExit and when the goroutine starts running -// (potentially instantly, if exitsyscallfast returns true) we emit traceGoStart. -// To ensure that traceGoSysExit is emitted strictly after traceGoSysBlock, -// we remember current value of syscalltick in m (gp.m.syscalltick = gp.m.p.ptr().syscalltick), -// whoever emits traceGoSysBlock increments p.syscalltick afterwards; -// and we wait for the increment before emitting traceGoSysExit. -// Note that the increment is done even if tracing is not enabled, -// because tracing can be enabled in the middle of syscall. We don't want the wait to hang. -// -//go:nosplit -func reentersyscall(pc, sp uintptr) { - trace := traceAcquire() - gp := getg() - - // Disable preemption because during this function g is in Gsyscall status, - // but can have inconsistent g->sched, do not let GC observe it. - gp.m.locks++ - - // Entersyscall must not call any function that might split/grow the stack. - // (See details in comment above.) - // Catch calls that might, by replacing the stack guard with something that - // will trip any stack check and leaving a flag to tell newstack to die. - gp.stackguard0 = stackPreempt - gp.throwsplit = true - - // Leave SP around for GC and traceback. - save(pc, sp) - gp.syscallsp = sp - gp.syscallpc = pc - casgstatus(gp, _Grunning, _Gsyscall) - if staticLockRanking { - // When doing static lock ranking casgstatus can call - // systemstack which clobbers g.sched. - save(pc, sp) - } - if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp { - systemstack(func() { - print("entersyscall inconsistent ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") - throw("entersyscall") - }) - } - - if trace.ok() { - systemstack(func() { - trace.GoSysCall() - traceRelease(trace) - }) - // systemstack itself clobbers g.sched.{pc,sp} and we might - // need them later when the G is genuinely blocked in a - // syscall - save(pc, sp) - } - - if sched.sysmonwait.Load() { - systemstack(entersyscall_sysmon) - save(pc, sp) - } - - if gp.m.p.ptr().runSafePointFn != 0 { - // runSafePointFn may stack split if run on this stack - systemstack(runSafePointFn) - save(pc, sp) - } - - gp.m.syscalltick = gp.m.p.ptr().syscalltick - pp := gp.m.p.ptr() - pp.m = 0 - gp.m.oldp.set(pp) - gp.m.p = 0 - atomic.Store(&pp.status, _Psyscall) - if sched.gcwaiting.Load() { - systemstack(entersyscall_gcwait) - save(pc, sp) - } - - gp.m.locks-- -} - -// Standard syscall entry used by the go syscall library and normal cgo calls. -// -// This is exported via linkname to assembly in the syscall package and x/sys. -// -//go:nosplit -//go:linkname entersyscall -func entersyscall() { - reentersyscall(getcallerpc(), getcallersp()) -} - -func entersyscall_sysmon() { - lock(&sched.lock) - if sched.sysmonwait.Load() { - sched.sysmonwait.Store(false) - notewakeup(&sched.sysmonnote) - } - unlock(&sched.lock) -} - -func entersyscall_gcwait() { - gp := getg() - pp := gp.m.oldp.ptr() - - lock(&sched.lock) - trace := traceAcquire() - if sched.stopwait > 0 && atomic.Cas(&pp.status, _Psyscall, _Pgcstop) { - if trace.ok() { - if goexperiment.ExecTracer2 { - // This is a steal in the new tracer. While it's very likely - // that we were the ones to put this P into _Psyscall, between - // then and now it's totally possible it had been stolen and - // then put back into _Psyscall for us to acquire here. In such - // case ProcStop would be incorrect. - // - // TODO(mknyszek): Consider emitting a ProcStop instead when - // gp.m.syscalltick == pp.syscalltick, since then we know we never - // lost the P. - trace.ProcSteal(pp, true) - } else { - trace.GoSysBlock(pp) - trace.ProcStop(pp) - } - traceRelease(trace) - } - pp.syscalltick++ - if sched.stopwait--; sched.stopwait == 0 { - notewakeup(&sched.stopnote) - } - } else if trace.ok() { - traceRelease(trace) - } - unlock(&sched.lock) -} - -// The same as entersyscall(), but with a hint that the syscall is blocking. -// -//go:nosplit -func entersyscallblock() { - gp := getg() - - gp.m.locks++ // see comment in entersyscall - gp.throwsplit = true - gp.stackguard0 = stackPreempt // see comment in entersyscall - gp.m.syscalltick = gp.m.p.ptr().syscalltick - gp.m.p.ptr().syscalltick++ - - // Leave SP around for GC and traceback. - pc := getcallerpc() - sp := getcallersp() - save(pc, sp) - gp.syscallsp = gp.sched.sp - gp.syscallpc = gp.sched.pc - if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp { - sp1 := sp - sp2 := gp.sched.sp - sp3 := gp.syscallsp - systemstack(func() { - print("entersyscallblock inconsistent ", hex(sp1), " ", hex(sp2), " ", hex(sp3), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") - throw("entersyscallblock") - }) - } - casgstatus(gp, _Grunning, _Gsyscall) - if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp { - systemstack(func() { - print("entersyscallblock inconsistent ", hex(sp), " ", hex(gp.sched.sp), " ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") - throw("entersyscallblock") - }) - } - - systemstack(entersyscallblock_handoff) - - // Resave for traceback during blocked call. - save(getcallerpc(), getcallersp()) - - gp.m.locks-- -} - -func entersyscallblock_handoff() { - trace := traceAcquire() - if trace.ok() { - trace.GoSysCall() - trace.GoSysBlock(getg().m.p.ptr()) - traceRelease(trace) - } - handoffp(releasep()) -} - -// The goroutine g exited its system call. -// Arrange for it to run on a cpu again. -// This is called only from the go syscall library, not -// from the low-level system calls used by the runtime. -// -// Write barriers are not allowed because our P may have been stolen. -// -// This is exported via linkname to assembly in the syscall package. -// -//go:nosplit -//go:nowritebarrierrec -//go:linkname exitsyscall -func exitsyscall() { - gp := getg() - - gp.m.locks++ // see comment in entersyscall - if getcallersp() > gp.syscallsp { - throw("exitsyscall: syscall frame is no longer valid") - } - - gp.waitsince = 0 - oldp := gp.m.oldp.ptr() - gp.m.oldp = 0 - if exitsyscallfast(oldp) { - // When exitsyscallfast returns success, we have a P so can now use - // write barriers - if goroutineProfile.active { - // Make sure that gp has had its stack written out to the goroutine - // profile, exactly as it was when the goroutine profiler first - // stopped the world. - systemstack(func() { - tryRecordGoroutineProfileWB(gp) - }) - } - trace := traceAcquire() - if trace.ok() { - lostP := oldp != gp.m.p.ptr() || gp.m.syscalltick != gp.m.p.ptr().syscalltick - systemstack(func() { - if goexperiment.ExecTracer2 { - // Write out syscall exit eagerly in the experiment. - // - // It's important that we write this *after* we know whether we - // lost our P or not (determined by exitsyscallfast). - trace.GoSysExit(lostP) - } - if lostP { - // We lost the P at some point, even though we got it back here. - // Trace that we're starting again, because there was a traceGoSysBlock - // call somewhere in exitsyscallfast (indicating that this goroutine - // had blocked) and we're about to start running again. - trace.GoStart() - } - }) - } - // There's a cpu for us, so we can run. - gp.m.p.ptr().syscalltick++ - // We need to cas the status and scan before resuming... - casgstatus(gp, _Gsyscall, _Grunning) - if trace.ok() { - traceRelease(trace) - } - - // Garbage collector isn't running (since we are), - // so okay to clear syscallsp. - gp.syscallsp = 0 - gp.m.locks-- - if gp.preempt { - // restore the preemption request in case we've cleared it in newstack - gp.stackguard0 = stackPreempt - } else { - // otherwise restore the real stackGuard, we've spoiled it in entersyscall/entersyscallblock - gp.stackguard0 = gp.stack.lo + stackGuard - } - gp.throwsplit = false - - if sched.disable.user && !schedEnabled(gp) { - // Scheduling of this goroutine is disabled. - Gosched() - } - - return - } - - if !goexperiment.ExecTracer2 { - // In the old tracer, because we don't have a P we can't - // actually record the true time we exited the syscall. - // Record it. - trace := traceAcquire() - if trace.ok() { - trace.RecordSyscallExitedTime(gp, oldp) - traceRelease(trace) - } - } - - gp.m.locks-- - - // Call the scheduler. - mcall(exitsyscall0) - - // Scheduler returned, so we're allowed to run now. - // Delete the syscallsp information that we left for - // the garbage collector during the system call. - // Must wait until now because until gosched returns - // we don't know for sure that the garbage collector - // is not running. - gp.syscallsp = 0 - gp.m.p.ptr().syscalltick++ - gp.throwsplit = false -} - -//go:nosplit -func exitsyscallfast(oldp *p) bool { - gp := getg() - - // Freezetheworld sets stopwait but does not retake P's. - if sched.stopwait == freezeStopWait { - return false - } - - // Try to re-acquire the last P. - trace := traceAcquire() - if oldp != nil && oldp.status == _Psyscall && atomic.Cas(&oldp.status, _Psyscall, _Pidle) { - // There's a cpu for us, so we can run. - wirep(oldp) - exitsyscallfast_reacquired(trace) - if trace.ok() { - traceRelease(trace) - } - return true - } - if trace.ok() { - traceRelease(trace) - } - - // Try to get any other idle P. - if sched.pidle != 0 { - var ok bool - systemstack(func() { - ok = exitsyscallfast_pidle() - if ok && !goexperiment.ExecTracer2 { - trace := traceAcquire() - if trace.ok() { - if oldp != nil { - // Wait till traceGoSysBlock event is emitted. - // This ensures consistency of the trace (the goroutine is started after it is blocked). - for oldp.syscalltick == gp.m.syscalltick { - osyield() - } - } - // In the experiment, we write this in exitsyscall. - // Don't write it here unless the experiment is off. - trace.GoSysExit(true) - traceRelease(trace) - } - } - }) - if ok { - return true - } - } - return false -} - -// exitsyscallfast_reacquired is the exitsyscall path on which this G -// has successfully reacquired the P it was running on before the -// syscall. -// -//go:nosplit -func exitsyscallfast_reacquired(trace traceLocker) { - gp := getg() - if gp.m.syscalltick != gp.m.p.ptr().syscalltick { - if trace.ok() { - // The p was retaken and then enter into syscall again (since gp.m.syscalltick has changed). - // traceGoSysBlock for this syscall was already emitted, - // but here we effectively retake the p from the new syscall running on the same p. - systemstack(func() { - if goexperiment.ExecTracer2 { - // In the experiment, we're stealing the P. It's treated - // as if it temporarily stopped running. Then, start running. - trace.ProcSteal(gp.m.p.ptr(), true) - trace.ProcStart() - } else { - // Denote blocking of the new syscall. - trace.GoSysBlock(gp.m.p.ptr()) - // Denote completion of the current syscall. - trace.GoSysExit(true) - } - }) - } - gp.m.p.ptr().syscalltick++ - } -} - -func exitsyscallfast_pidle() bool { - lock(&sched.lock) - pp, _ := pidleget(0) - if pp != nil && sched.sysmonwait.Load() { - sched.sysmonwait.Store(false) - notewakeup(&sched.sysmonnote) - } - unlock(&sched.lock) - if pp != nil { - acquirep(pp) - return true - } - return false -} - -// exitsyscall slow path on g0. -// Failed to acquire P, enqueue gp as runnable. -// -// Called via mcall, so gp is the calling g from this M. -// -//go:nowritebarrierrec -func exitsyscall0(gp *g) { - var trace traceLocker - if goexperiment.ExecTracer2 { - traceExitingSyscall() - trace = traceAcquire() - } - casgstatus(gp, _Gsyscall, _Grunnable) - if goexperiment.ExecTracer2 { - traceExitedSyscall() - if trace.ok() { - // Write out syscall exit eagerly in the experiment. - // - // It's important that we write this *after* we know whether we - // lost our P or not (determined by exitsyscallfast). - trace.GoSysExit(true) - traceRelease(trace) - } - } - dropg() - lock(&sched.lock) - var pp *p - if schedEnabled(gp) { - pp, _ = pidleget(0) - } - var locked bool - if pp == nil { - globrunqput(gp) - - // Below, we stoplockedm if gp is locked. globrunqput releases - // ownership of gp, so we must check if gp is locked prior to - // committing the release by unlocking sched.lock, otherwise we - // could race with another M transitioning gp from unlocked to - // locked. - locked = gp.lockedm != 0 - } else if sched.sysmonwait.Load() { - sched.sysmonwait.Store(false) - notewakeup(&sched.sysmonnote) - } - unlock(&sched.lock) - if pp != nil { - acquirep(pp) - execute(gp, false) // Never returns. - } - if locked { - // Wait until another thread schedules gp and so m again. - // - // N.B. lockedm must be this M, as this g was running on this M - // before entersyscall. - stoplockedm() - execute(gp, false) // Never returns. - } - stopm() - schedule() // Never returns. -} - -// Called from syscall package before fork. -// -//go:linkname syscall_runtime_BeforeFork syscall.runtime_BeforeFork -//go:nosplit -func syscall_runtime_BeforeFork() { - gp := getg().m.curg - - // Block signals during a fork, so that the child does not run - // a signal handler before exec if a signal is sent to the process - // group. See issue #18600. - gp.m.locks++ - sigsave(&gp.m.sigmask) - sigblock(false) - - // This function is called before fork in syscall package. - // Code between fork and exec must not allocate memory nor even try to grow stack. - // Here we spoil g.stackguard0 to reliably detect any attempts to grow stack. - // runtime_AfterFork will undo this in parent process, but not in child. - gp.stackguard0 = stackFork -} - -// Called from syscall package after fork in parent. -// -//go:linkname syscall_runtime_AfterFork syscall.runtime_AfterFork -//go:nosplit -func syscall_runtime_AfterFork() { - gp := getg().m.curg - - // See the comments in beforefork. - gp.stackguard0 = gp.stack.lo + stackGuard - - msigrestore(gp.m.sigmask) - - gp.m.locks-- -} - -// inForkedChild is true while manipulating signals in the child process. -// This is used to avoid calling libc functions in case we are using vfork. -var inForkedChild bool - -// Called from syscall package after fork in child. -// It resets non-sigignored signals to the default handler, and -// restores the signal mask in preparation for the exec. -// -// Because this might be called during a vfork, and therefore may be -// temporarily sharing address space with the parent process, this must -// not change any global variables or calling into C code that may do so. -// -//go:linkname syscall_runtime_AfterForkInChild syscall.runtime_AfterForkInChild -//go:nosplit -//go:nowritebarrierrec -func syscall_runtime_AfterForkInChild() { - // It's OK to change the global variable inForkedChild here - // because we are going to change it back. There is no race here, - // because if we are sharing address space with the parent process, - // then the parent process can not be running concurrently. - inForkedChild = true - - clearSignalHandlers() - - // When we are the child we are the only thread running, - // so we know that nothing else has changed gp.m.sigmask. - msigrestore(getg().m.sigmask) - - inForkedChild = false -} - -// pendingPreemptSignals is the number of preemption signals -// that have been sent but not received. This is only used on Darwin. -// For #41702. -var pendingPreemptSignals atomic.Int32 - -// Called from syscall package before Exec. -// -//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec -func syscall_runtime_BeforeExec() { - // Prevent thread creation during exec. - execLock.lock() - - // On Darwin, wait for all pending preemption signals to - // be received. See issue #41702. - if GOOS == "darwin" || GOOS == "ios" { - for pendingPreemptSignals.Load() > 0 { - osyield() - } - } -} - -// Called from syscall package after Exec. -// -//go:linkname syscall_runtime_AfterExec syscall.runtime_AfterExec -func syscall_runtime_AfterExec() { - execLock.unlock() -} - -// Allocate a new g, with a stack big enough for stacksize bytes. -func malg(stacksize int32) *g { - newg := new(g) - if stacksize >= 0 { - stacksize = round2(stackSystem + stacksize) - systemstack(func() { - newg.stack = stackalloc(uint32(stacksize)) - }) - newg.stackguard0 = newg.stack.lo + stackGuard - newg.stackguard1 = ^uintptr(0) - // Clear the bottom word of the stack. We record g - // there on gsignal stack during VDSO on ARM and ARM64. - *(*uintptr)(unsafe.Pointer(newg.stack.lo)) = 0 - } - return newg -} - -// Create a new g running fn. -// Put it on the queue of g's waiting to run. -// The compiler turns a go statement into a call to this. -func newproc(fn *funcval) { - gp := getg() - pc := getcallerpc() - systemstack(func() { - newg := newproc1(fn, gp, pc) - - pp := getg().m.p.ptr() - runqput(pp, newg, true) - - if mainStarted { - wakep() - } - }) -} - -// Create a new g in state _Grunnable, starting at fn. callerpc is the -// address of the go statement that created this. The caller is responsible -// for adding the new g to the scheduler. -func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g { - if fn == nil { - fatal("go of nil func value") - } - - mp := acquirem() // disable preemption because we hold M and P in local vars. - pp := mp.p.ptr() - newg := gfget(pp) - if newg == nil { - newg = malg(stackMin) - casgstatus(newg, _Gidle, _Gdead) - allgadd(newg) // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack. - } - if newg.stack.hi == 0 { - throw("newproc1: newg missing stack") - } - - if readgstatus(newg) != _Gdead { - throw("newproc1: new g is not Gdead") - } - - totalSize := uintptr(4*goarch.PtrSize + sys.MinFrameSize) // extra space in case of reads slightly beyond frame - totalSize = alignUp(totalSize, sys.StackAlign) - sp := newg.stack.hi - totalSize - if usesLR { - // caller's LR - *(*uintptr)(unsafe.Pointer(sp)) = 0 - prepGoExitFrame(sp) - } - if GOARCH == "arm64" { - // caller's FP - *(*uintptr)(unsafe.Pointer(sp - goarch.PtrSize)) = 0 - } - - memclrNoHeapPointers(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched)) - newg.sched.sp = sp - newg.stktopsp = sp - newg.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum // +PCQuantum so that previous instruction is in same function - newg.sched.g = guintptr(unsafe.Pointer(newg)) - gostartcallfn(&newg.sched, fn) - newg.parentGoid = callergp.goid - newg.gopc = callerpc - newg.ancestors = saveAncestors(callergp) - newg.startpc = fn.fn - if isSystemGoroutine(newg, false) { - sched.ngsys.Add(1) - } else { - // Only user goroutines inherit pprof labels. - if mp.curg != nil { - newg.labels = mp.curg.labels - } - if goroutineProfile.active { - // A concurrent goroutine profile is running. It should include - // exactly the set of goroutines that were alive when the goroutine - // profiler first stopped the world. That does not include newg, so - // mark it as not needing a profile before transitioning it from - // _Gdead. - newg.goroutineProfiled.Store(goroutineProfileSatisfied) - } - } - // Track initial transition? - newg.trackingSeq = uint8(cheaprand()) - if newg.trackingSeq%gTrackingPeriod == 0 { - newg.tracking = true - } - gcController.addScannableStack(pp, int64(newg.stack.hi-newg.stack.lo)) - - // Get a goid and switch to runnable. Make all this atomic to the tracer. - trace := traceAcquire() - casgstatus(newg, _Gdead, _Grunnable) - if pp.goidcache == pp.goidcacheend { - // Sched.goidgen is the last allocated id, - // this batch must be [sched.goidgen+1, sched.goidgen+GoidCacheBatch]. - // At startup sched.goidgen=0, so main goroutine receives goid=1. - pp.goidcache = sched.goidgen.Add(_GoidCacheBatch) - pp.goidcache -= _GoidCacheBatch - 1 - pp.goidcacheend = pp.goidcache + _GoidCacheBatch - } - newg.goid = pp.goidcache - pp.goidcache++ - newg.trace.reset() - if trace.ok() { - trace.GoCreate(newg, newg.startpc) - traceRelease(trace) - } - - // Set up race context. - if raceenabled { - newg.racectx = racegostart(callerpc) - newg.raceignore = 0 - if newg.labels != nil { - // See note in proflabel.go on labelSync's role in synchronizing - // with the reads in the signal handler. - racereleasemergeg(newg, unsafe.Pointer(&labelSync)) - } - } - releasem(mp) - - return newg -} - -// saveAncestors copies previous ancestors of the given caller g and -// includes info for the current caller into a new set of tracebacks for -// a g being created. -func saveAncestors(callergp *g) *[]ancestorInfo { - // Copy all prior info, except for the root goroutine (goid 0). - if debug.tracebackancestors <= 0 || callergp.goid == 0 { - return nil - } - var callerAncestors []ancestorInfo - if callergp.ancestors != nil { - callerAncestors = *callergp.ancestors - } - n := int32(len(callerAncestors)) + 1 - if n > debug.tracebackancestors { - n = debug.tracebackancestors - } - ancestors := make([]ancestorInfo, n) - copy(ancestors[1:], callerAncestors) - - var pcs [tracebackInnerFrames]uintptr - npcs := gcallers(callergp, 0, pcs[:]) - ipcs := make([]uintptr, npcs) - copy(ipcs, pcs[:]) - ancestors[0] = ancestorInfo{ - pcs: ipcs, - goid: callergp.goid, - gopc: callergp.gopc, - } - - ancestorsp := new([]ancestorInfo) - *ancestorsp = ancestors - return ancestorsp -} - -// Put on gfree list. -// If local list is too long, transfer a batch to the global list. -func gfput(pp *p, gp *g) { - if readgstatus(gp) != _Gdead { - throw("gfput: bad status (not Gdead)") - } - - stksize := gp.stack.hi - gp.stack.lo - - if stksize != uintptr(startingStackSize) { - // non-standard stack size - free it. - stackfree(gp.stack) - gp.stack.lo = 0 - gp.stack.hi = 0 - gp.stackguard0 = 0 - } - - pp.gFree.push(gp) - pp.gFree.n++ - if pp.gFree.n >= 64 { - var ( - inc int32 - stackQ gQueue - noStackQ gQueue - ) - for pp.gFree.n >= 32 { - gp := pp.gFree.pop() - pp.gFree.n-- - if gp.stack.lo == 0 { - noStackQ.push(gp) - } else { - stackQ.push(gp) - } - inc++ - } - lock(&sched.gFree.lock) - sched.gFree.noStack.pushAll(noStackQ) - sched.gFree.stack.pushAll(stackQ) - sched.gFree.n += inc - unlock(&sched.gFree.lock) - } -} - -// Get from gfree list. -// If local list is empty, grab a batch from global list. -func gfget(pp *p) *g { -retry: - if pp.gFree.empty() && (!sched.gFree.stack.empty() || !sched.gFree.noStack.empty()) { - lock(&sched.gFree.lock) - // Move a batch of free Gs to the P. - for pp.gFree.n < 32 { - // Prefer Gs with stacks. - gp := sched.gFree.stack.pop() - if gp == nil { - gp = sched.gFree.noStack.pop() - if gp == nil { - break - } - } - sched.gFree.n-- - pp.gFree.push(gp) - pp.gFree.n++ - } - unlock(&sched.gFree.lock) - goto retry - } - gp := pp.gFree.pop() - if gp == nil { - return nil - } - pp.gFree.n-- - if gp.stack.lo != 0 && gp.stack.hi-gp.stack.lo != uintptr(startingStackSize) { - // Deallocate old stack. We kept it in gfput because it was the - // right size when the goroutine was put on the free list, but - // the right size has changed since then. - systemstack(func() { - stackfree(gp.stack) - gp.stack.lo = 0 - gp.stack.hi = 0 - gp.stackguard0 = 0 - }) - } - if gp.stack.lo == 0 { - // Stack was deallocated in gfput or just above. Allocate a new one. - systemstack(func() { - gp.stack = stackalloc(startingStackSize) - }) - gp.stackguard0 = gp.stack.lo + stackGuard - } else { - if raceenabled { - racemalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo) - } - if msanenabled { - msanmalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo) - } - if asanenabled { - asanunpoison(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo) - } - } - return gp -} - -// Purge all cached G's from gfree list to the global list. -func gfpurge(pp *p) { - var ( - inc int32 - stackQ gQueue - noStackQ gQueue - ) - for !pp.gFree.empty() { - gp := pp.gFree.pop() - pp.gFree.n-- - if gp.stack.lo == 0 { - noStackQ.push(gp) - } else { - stackQ.push(gp) - } - inc++ - } - lock(&sched.gFree.lock) - sched.gFree.noStack.pushAll(noStackQ) - sched.gFree.stack.pushAll(stackQ) - sched.gFree.n += inc - unlock(&sched.gFree.lock) -} - -// Breakpoint executes a breakpoint trap. -func Breakpoint() { - breakpoint() -} - -// dolockOSThread is called by LockOSThread and lockOSThread below -// after they modify m.locked. Do not allow preemption during this call, -// or else the m might be different in this function than in the caller. -// -//go:nosplit -func dolockOSThread() { - if GOARCH == "wasm" { - return // no threads on wasm yet - } - gp := getg() - gp.m.lockedg.set(gp) - gp.lockedm.set(gp.m) -} - -// LockOSThread wires the calling goroutine to its current operating system thread. -// The calling goroutine will always execute in that thread, -// and no other goroutine will execute in it, -// until the calling goroutine has made as many calls to -// [UnlockOSThread] as to LockOSThread. -// If the calling goroutine exits without unlocking the thread, -// the thread will be terminated. -// -// All init functions are run on the startup thread. Calling LockOSThread -// from an init function will cause the main function to be invoked on -// that thread. -// -// A goroutine should call LockOSThread before calling OS services or -// non-Go library functions that depend on per-thread state. -// -//go:nosplit -func LockOSThread() { - if atomic.Load(&newmHandoff.haveTemplateThread) == 0 && GOOS != "plan9" { - // If we need to start a new thread from the locked - // thread, we need the template thread. Start it now - // while we're in a known-good state. - startTemplateThread() - } - gp := getg() - gp.m.lockedExt++ - if gp.m.lockedExt == 0 { - gp.m.lockedExt-- - panic("LockOSThread nesting overflow") - } - dolockOSThread() -} - -//go:nosplit -func lockOSThread() { - getg().m.lockedInt++ - dolockOSThread() -} - -// dounlockOSThread is called by UnlockOSThread and unlockOSThread below -// after they update m->locked. Do not allow preemption during this call, -// or else the m might be in different in this function than in the caller. -// -//go:nosplit -func dounlockOSThread() { - if GOARCH == "wasm" { - return // no threads on wasm yet - } - gp := getg() - if gp.m.lockedInt != 0 || gp.m.lockedExt != 0 { - return - } - gp.m.lockedg = 0 - gp.lockedm = 0 -} - -// UnlockOSThread undoes an earlier call to LockOSThread. -// If this drops the number of active LockOSThread calls on the -// calling goroutine to zero, it unwires the calling goroutine from -// its fixed operating system thread. -// If there are no active LockOSThread calls, this is a no-op. -// -// Before calling UnlockOSThread, the caller must ensure that the OS -// thread is suitable for running other goroutines. If the caller made -// any permanent changes to the state of the thread that would affect -// other goroutines, it should not call this function and thus leave -// the goroutine locked to the OS thread until the goroutine (and -// hence the thread) exits. -// -//go:nosplit -func UnlockOSThread() { - gp := getg() - if gp.m.lockedExt == 0 { - return - } - gp.m.lockedExt-- - dounlockOSThread() -} - -//go:nosplit -func unlockOSThread() { - gp := getg() - if gp.m.lockedInt == 0 { - systemstack(badunlockosthread) - } - gp.m.lockedInt-- - dounlockOSThread() -} - -func badunlockosthread() { - throw("runtime: internal error: misuse of lockOSThread/unlockOSThread") -} - -func gcount() int32 { - n := int32(atomic.Loaduintptr(&allglen)) - sched.gFree.n - sched.ngsys.Load() - for _, pp := range allp { - n -= pp.gFree.n - } - - // All these variables can be changed concurrently, so the result can be inconsistent. - // But at least the current goroutine is running. - if n < 1 { - n = 1 - } - return n -} - -func mcount() int32 { - return int32(sched.mnext - sched.nmfreed) -} - -var prof struct { - signalLock atomic.Uint32 - - // Must hold signalLock to write. Reads may be lock-free, but - // signalLock should be taken to synchronize with changes. - hz atomic.Int32 -} - -func _System() { _System() } -func _ExternalCode() { _ExternalCode() } -func _LostExternalCode() { _LostExternalCode() } -func _GC() { _GC() } -func _LostSIGPROFDuringAtomic64() { _LostSIGPROFDuringAtomic64() } -func _LostContendedRuntimeLock() { _LostContendedRuntimeLock() } -func _VDSO() { _VDSO() } - -// Called if we receive a SIGPROF signal. -// Called by the signal handler, may run during STW. -// -//go:nowritebarrierrec -func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { - if prof.hz.Load() == 0 { - return - } - - // If mp.profilehz is 0, then profiling is not enabled for this thread. - // We must check this to avoid a deadlock between setcpuprofilerate - // and the call to cpuprof.add, below. - if mp != nil && mp.profilehz == 0 { - return - } - - // On mips{,le}/arm, 64bit atomics are emulated with spinlocks, in - // runtime/internal/atomic. If SIGPROF arrives while the program is inside - // the critical section, it creates a deadlock (when writing the sample). - // As a workaround, create a counter of SIGPROFs while in critical section - // to store the count, and pass it to sigprof.add() later when SIGPROF is - // received from somewhere else (with _LostSIGPROFDuringAtomic64 as pc). - if GOARCH == "mips" || GOARCH == "mipsle" || GOARCH == "arm" { - if f := findfunc(pc); f.valid() { - if hasPrefix(funcname(f), "runtime/internal/atomic") { - cpuprof.lostAtomic++ - return - } - } - if GOARCH == "arm" && goarm < 7 && GOOS == "linux" && pc&0xffff0000 == 0xffff0000 { - // runtime/internal/atomic functions call into kernel - // helpers on arm < 7. See - // runtime/internal/atomic/sys_linux_arm.s. - cpuprof.lostAtomic++ - return - } - } - - // Profiling runs concurrently with GC, so it must not allocate. - // Set a trap in case the code does allocate. - // Note that on windows, one thread takes profiles of all the - // other threads, so mp is usually not getg().m. - // In fact mp may not even be stopped. - // See golang.org/issue/17165. - getg().m.mallocing++ - - var u unwinder - var stk [maxCPUProfStack]uintptr - n := 0 - if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 { - cgoOff := 0 - // Check cgoCallersUse to make sure that we are not - // interrupting other code that is fiddling with - // cgoCallers. We are running in a signal handler - // with all signals blocked, so we don't have to worry - // about any other code interrupting us. - if mp.cgoCallersUse.Load() == 0 && mp.cgoCallers != nil && mp.cgoCallers[0] != 0 { - for cgoOff < len(mp.cgoCallers) && mp.cgoCallers[cgoOff] != 0 { - cgoOff++ - } - n += copy(stk[:], mp.cgoCallers[:cgoOff]) - mp.cgoCallers[0] = 0 - } - - // Collect Go stack that leads to the cgo call. - u.initAt(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, unwindSilentErrors) - } else if usesLibcall() && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 { - // Libcall, i.e. runtime syscall on windows. - // Collect Go stack that leads to the call. - u.initAt(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), unwindSilentErrors) - } else if mp != nil && mp.vdsoSP != 0 { - // VDSO call, e.g. nanotime1 on Linux. - // Collect Go stack that leads to the call. - u.initAt(mp.vdsoPC, mp.vdsoSP, 0, gp, unwindSilentErrors|unwindJumpStack) - } else { - u.initAt(pc, sp, lr, gp, unwindSilentErrors|unwindTrap|unwindJumpStack) - } - n += tracebackPCs(&u, 0, stk[n:]) - - if n <= 0 { - // Normal traceback is impossible or has failed. - // Account it against abstract "System" or "GC". - n = 2 - if inVDSOPage(pc) { - pc = abi.FuncPCABIInternal(_VDSO) + sys.PCQuantum - } else if pc > firstmoduledata.etext { - // "ExternalCode" is better than "etext". - pc = abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum - } - stk[0] = pc - if mp.preemptoff != "" { - stk[1] = abi.FuncPCABIInternal(_GC) + sys.PCQuantum - } else { - stk[1] = abi.FuncPCABIInternal(_System) + sys.PCQuantum - } - } - - if prof.hz.Load() != 0 { - // Note: it can happen on Windows that we interrupted a system thread - // with no g, so gp could nil. The other nil checks are done out of - // caution, but not expected to be nil in practice. - var tagPtr *unsafe.Pointer - if gp != nil && gp.m != nil && gp.m.curg != nil { - tagPtr = &gp.m.curg.labels - } - cpuprof.add(tagPtr, stk[:n]) - - gprof := gp - var mp *m - var pp *p - if gp != nil && gp.m != nil { - if gp.m.curg != nil { - gprof = gp.m.curg - } - mp = gp.m - pp = gp.m.p.ptr() - } - traceCPUSample(gprof, mp, pp, stk[:n]) - } - getg().m.mallocing-- -} - -// setcpuprofilerate sets the CPU profiling rate to hz times per second. -// If hz <= 0, setcpuprofilerate turns off CPU profiling. -func setcpuprofilerate(hz int32) { - // Force sane arguments. - if hz < 0 { - hz = 0 - } - - // Disable preemption, otherwise we can be rescheduled to another thread - // that has profiling enabled. - gp := getg() - gp.m.locks++ - - // Stop profiler on this thread so that it is safe to lock prof. - // if a profiling signal came in while we had prof locked, - // it would deadlock. - setThreadCPUProfiler(0) - - for !prof.signalLock.CompareAndSwap(0, 1) { - osyield() - } - if prof.hz.Load() != hz { - setProcessCPUProfiler(hz) - prof.hz.Store(hz) - } - prof.signalLock.Store(0) - - lock(&sched.lock) - sched.profilehz = hz - unlock(&sched.lock) - - if hz != 0 { - setThreadCPUProfiler(hz) - } - - gp.m.locks-- -} - -// init initializes pp, which may be a freshly allocated p or a -// previously destroyed p, and transitions it to status _Pgcstop. -func (pp *p) init(id int32) { - pp.id = id - pp.status = _Pgcstop - pp.sudogcache = pp.sudogbuf[:0] - pp.deferpool = pp.deferpoolbuf[:0] - pp.wbBuf.reset() - if pp.mcache == nil { - if id == 0 { - if mcache0 == nil { - throw("missing mcache?") - } - // Use the bootstrap mcache0. Only one P will get - // mcache0: the one with ID 0. - pp.mcache = mcache0 - } else { - pp.mcache = allocmcache() - } - } - if raceenabled && pp.raceprocctx == 0 { - if id == 0 { - pp.raceprocctx = raceprocctx0 - raceprocctx0 = 0 // bootstrap - } else { - pp.raceprocctx = raceproccreate() - } - } - lockInit(&pp.timersLock, lockRankTimers) - - // This P may get timers when it starts running. Set the mask here - // since the P may not go through pidleget (notably P 0 on startup). - timerpMask.set(id) - // Similarly, we may not go through pidleget before this P starts - // running if it is P 0 on startup. - idlepMask.clear(id) -} - -// destroy releases all of the resources associated with pp and -// transitions it to status _Pdead. -// -// sched.lock must be held and the world must be stopped. -func (pp *p) destroy() { - assertLockHeld(&sched.lock) - assertWorldStopped() - - // Move all runnable goroutines to the global queue - for pp.runqhead != pp.runqtail { - // Pop from tail of local queue - pp.runqtail-- - gp := pp.runq[pp.runqtail%uint32(len(pp.runq))].ptr() - // Push onto head of global queue - globrunqputhead(gp) - } - if pp.runnext != 0 { - globrunqputhead(pp.runnext.ptr()) - pp.runnext = 0 - } - if len(pp.timers) > 0 { - plocal := getg().m.p.ptr() - // The world is stopped, but we acquire timersLock to - // protect against sysmon calling timeSleepUntil. - // This is the only case where we hold the timersLock of - // more than one P, so there are no deadlock concerns. - lock(&plocal.timersLock) - lock(&pp.timersLock) - moveTimers(plocal, pp.timers) - pp.timers = nil - pp.numTimers.Store(0) - pp.deletedTimers.Store(0) - pp.timer0When.Store(0) - unlock(&pp.timersLock) - unlock(&plocal.timersLock) - } - // Flush p's write barrier buffer. - if gcphase != _GCoff { - wbBufFlush1(pp) - pp.gcw.dispose() - } - for i := range pp.sudogbuf { - pp.sudogbuf[i] = nil - } - pp.sudogcache = pp.sudogbuf[:0] - pp.pinnerCache = nil - for j := range pp.deferpoolbuf { - pp.deferpoolbuf[j] = nil - } - pp.deferpool = pp.deferpoolbuf[:0] - systemstack(func() { - for i := 0; i < pp.mspancache.len; i++ { - // Safe to call since the world is stopped. - mheap_.spanalloc.free(unsafe.Pointer(pp.mspancache.buf[i])) - } - pp.mspancache.len = 0 - lock(&mheap_.lock) - pp.pcache.flush(&mheap_.pages) - unlock(&mheap_.lock) - }) - freemcache(pp.mcache) - pp.mcache = nil - gfpurge(pp) - traceProcFree(pp) - if raceenabled { - if pp.timerRaceCtx != 0 { - // The race detector code uses a callback to fetch - // the proc context, so arrange for that callback - // to see the right thing. - // This hack only works because we are the only - // thread running. - mp := getg().m - phold := mp.p.ptr() - mp.p.set(pp) - - racectxend(pp.timerRaceCtx) - pp.timerRaceCtx = 0 - - mp.p.set(phold) - } - raceprocdestroy(pp.raceprocctx) - pp.raceprocctx = 0 - } - pp.gcAssistTime = 0 - pp.status = _Pdead -} - -// Change number of processors. -// -// sched.lock must be held, and the world must be stopped. -// -// gcworkbufs must not be being modified by either the GC or the write barrier -// code, so the GC must not be running if the number of Ps actually changes. -// -// Returns list of Ps with local work, they need to be scheduled by the caller. -func procresize(nprocs int32) *p { - assertLockHeld(&sched.lock) - assertWorldStopped() - - old := gomaxprocs - if old < 0 || nprocs <= 0 { - throw("procresize: invalid arg") - } - trace := traceAcquire() - if trace.ok() { - trace.Gomaxprocs(nprocs) - traceRelease(trace) - } - - // update statistics - now := nanotime() - if sched.procresizetime != 0 { - sched.totaltime += int64(old) * (now - sched.procresizetime) - } - sched.procresizetime = now - - maskWords := (nprocs + 31) / 32 - - // Grow allp if necessary. - if nprocs > int32(len(allp)) { - // Synchronize with retake, which could be running - // concurrently since it doesn't run on a P. - lock(&allpLock) - if nprocs <= int32(cap(allp)) { - allp = allp[:nprocs] - } else { - nallp := make([]*p, nprocs) - // Copy everything up to allp's cap so we - // never lose old allocated Ps. - copy(nallp, allp[:cap(allp)]) - allp = nallp - } - - if maskWords <= int32(cap(idlepMask)) { - idlepMask = idlepMask[:maskWords] - timerpMask = timerpMask[:maskWords] - } else { - nidlepMask := make([]uint32, maskWords) - // No need to copy beyond len, old Ps are irrelevant. - copy(nidlepMask, idlepMask) - idlepMask = nidlepMask - - ntimerpMask := make([]uint32, maskWords) - copy(ntimerpMask, timerpMask) - timerpMask = ntimerpMask - } - unlock(&allpLock) - } - - // initialize new P's - for i := old; i < nprocs; i++ { - pp := allp[i] - if pp == nil { - pp = new(p) - } - pp.init(i) - atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp)) - } - - gp := getg() - if gp.m.p != 0 && gp.m.p.ptr().id < nprocs { - // continue to use the current P - gp.m.p.ptr().status = _Prunning - gp.m.p.ptr().mcache.prepareForSweep() - } else { - // release the current P and acquire allp[0]. - // - // We must do this before destroying our current P - // because p.destroy itself has write barriers, so we - // need to do that from a valid P. - if gp.m.p != 0 { - trace := traceAcquire() - if trace.ok() { - // Pretend that we were descheduled - // and then scheduled again to keep - // the trace sane. - trace.GoSched() - trace.ProcStop(gp.m.p.ptr()) - traceRelease(trace) - } - gp.m.p.ptr().m = 0 - } - gp.m.p = 0 - pp := allp[0] - pp.m = 0 - pp.status = _Pidle - acquirep(pp) - trace := traceAcquire() - if trace.ok() { - trace.GoStart() - traceRelease(trace) - } - } - - // g.m.p is now set, so we no longer need mcache0 for bootstrapping. - mcache0 = nil - - // release resources from unused P's - for i := nprocs; i < old; i++ { - pp := allp[i] - pp.destroy() - // can't free P itself because it can be referenced by an M in syscall - } - - // Trim allp. - if int32(len(allp)) != nprocs { - lock(&allpLock) - allp = allp[:nprocs] - idlepMask = idlepMask[:maskWords] - timerpMask = timerpMask[:maskWords] - unlock(&allpLock) - } - - var runnablePs *p - for i := nprocs - 1; i >= 0; i-- { - pp := allp[i] - if gp.m.p.ptr() == pp { - continue - } - pp.status = _Pidle - if runqempty(pp) { - pidleput(pp, now) - } else { - pp.m.set(mget()) - pp.link.set(runnablePs) - runnablePs = pp - } - } - stealOrder.reset(uint32(nprocs)) - var int32p *int32 = &gomaxprocs // make compiler check that gomaxprocs is an int32 - atomic.Store((*uint32)(unsafe.Pointer(int32p)), uint32(nprocs)) - if old != nprocs { - // Notify the limiter that the amount of procs has changed. - gcCPULimiter.resetCapacity(now, nprocs) - } - return runnablePs -} - -// Associate p and the current m. -// -// This function is allowed to have write barriers even if the caller -// isn't because it immediately acquires pp. -// -//go:yeswritebarrierrec -func acquirep(pp *p) { - // Do the part that isn't allowed to have write barriers. - wirep(pp) - - // Have p; write barriers now allowed. - - // Perform deferred mcache flush before this P can allocate - // from a potentially stale mcache. - pp.mcache.prepareForSweep() - - trace := traceAcquire() - if trace.ok() { - trace.ProcStart() - traceRelease(trace) - } -} - -// wirep is the first step of acquirep, which actually associates the -// current M to pp. This is broken out so we can disallow write -// barriers for this part, since we don't yet have a P. -// -//go:nowritebarrierrec -//go:nosplit -func wirep(pp *p) { - gp := getg() - - if gp.m.p != 0 { - // Call on the systemstack to avoid a nosplit overflow build failure - // on some platforms when built with -N -l. See #64113. - systemstack(func() { - throw("wirep: already in go") - }) - } - if pp.m != 0 || pp.status != _Pidle { - // Call on the systemstack to avoid a nosplit overflow build failure - // on some platforms when built with -N -l. See #64113. - systemstack(func() { - id := int64(0) - if pp.m != 0 { - id = pp.m.ptr().id - } - print("wirep: p->m=", pp.m, "(", id, ") p->status=", pp.status, "\n") - throw("wirep: invalid p state") - }) - } - gp.m.p.set(pp) - pp.m.set(gp.m) - pp.status = _Prunning -} - -// Disassociate p and the current m. -func releasep() *p { - trace := traceAcquire() - if trace.ok() { - trace.ProcStop(getg().m.p.ptr()) - traceRelease(trace) - } - return releasepNoTrace() -} - -// Disassociate p and the current m without tracing an event. -func releasepNoTrace() *p { - gp := getg() - - if gp.m.p == 0 { - throw("releasep: invalid arg") - } - pp := gp.m.p.ptr() - if pp.m.ptr() != gp.m || pp.status != _Prunning { - print("releasep: m=", gp.m, " m->p=", gp.m.p.ptr(), " p->m=", hex(pp.m), " p->status=", pp.status, "\n") - throw("releasep: invalid p state") - } - gp.m.p = 0 - pp.m = 0 - pp.status = _Pidle - return pp -} - -func incidlelocked(v int32) { - lock(&sched.lock) - sched.nmidlelocked += v - if v > 0 { - checkdead() - } - unlock(&sched.lock) -} - -// Check for deadlock situation. -// The check is based on number of running M's, if 0 -> deadlock. -// sched.lock must be held. -func checkdead() { - assertLockHeld(&sched.lock) - - // For -buildmode=c-shared or -buildmode=c-archive it's OK if - // there are no running goroutines. The calling program is - // assumed to be running. - if islibrary || isarchive { - return - } - - // If we are dying because of a signal caught on an already idle thread, - // freezetheworld will cause all running threads to block. - // And runtime will essentially enter into deadlock state, - // except that there is a thread that will call exit soon. - if panicking.Load() > 0 { - return - } - - // If we are not running under cgo, but we have an extra M then account - // for it. (It is possible to have an extra M on Windows without cgo to - // accommodate callbacks created by syscall.NewCallback. See issue #6751 - // for details.) - var run0 int32 - if !iscgo && cgoHasExtraM && extraMLength.Load() > 0 { - run0 = 1 - } - - run := mcount() - sched.nmidle - sched.nmidlelocked - sched.nmsys - if run > run0 { - return - } - if run < 0 { - print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", mcount(), " nmsys=", sched.nmsys, "\n") - unlock(&sched.lock) - throw("checkdead: inconsistent counts") - } - - grunning := 0 - forEachG(func(gp *g) { - if isSystemGoroutine(gp, false) { - return - } - s := readgstatus(gp) - switch s &^ _Gscan { - case _Gwaiting, - _Gpreempted: - grunning++ - case _Grunnable, - _Grunning, - _Gsyscall: - print("runtime: checkdead: find g ", gp.goid, " in status ", s, "\n") - unlock(&sched.lock) - throw("checkdead: runnable g") - } - }) - if grunning == 0 { // possible if main goroutine calls runtime·Goexit() - unlock(&sched.lock) // unlock so that GODEBUG=scheddetail=1 doesn't hang - fatal("no goroutines (main called runtime.Goexit) - deadlock!") - } - - // Maybe jump time forward for playground. - if faketime != 0 { - if when := timeSleepUntil(); when < maxWhen { - faketime = when - - // Start an M to steal the timer. - pp, _ := pidleget(faketime) - if pp == nil { - // There should always be a free P since - // nothing is running. - unlock(&sched.lock) - throw("checkdead: no p for timer") - } - mp := mget() - if mp == nil { - // There should always be a free M since - // nothing is running. - unlock(&sched.lock) - throw("checkdead: no m for timer") - } - // M must be spinning to steal. We set this to be - // explicit, but since this is the only M it would - // become spinning on its own anyways. - sched.nmspinning.Add(1) - mp.spinning = true - mp.nextp.set(pp) - notewakeup(&mp.park) - return - } - } - - // There are no goroutines running, so we can look at the P's. - for _, pp := range allp { - if len(pp.timers) > 0 { - return - } - } - - unlock(&sched.lock) // unlock so that GODEBUG=scheddetail=1 doesn't hang - fatal("all goroutines are asleep - deadlock!") -} - -// forcegcperiod is the maximum time in nanoseconds between garbage -// collections. If we go this long without a garbage collection, one -// is forced to run. -// -// This is a variable for testing purposes. It normally doesn't change. -var forcegcperiod int64 = 2 * 60 * 1e9 - -// needSysmonWorkaround is true if the workaround for -// golang.org/issue/42515 is needed on NetBSD. -var needSysmonWorkaround bool = false - -// Always runs without a P, so write barriers are not allowed. -// -//go:nowritebarrierrec -func sysmon() { - lock(&sched.lock) - sched.nmsys++ - checkdead() - unlock(&sched.lock) - - lasttrace := int64(0) - idle := 0 // how many cycles in succession we had not wokeup somebody - delay := uint32(0) - - for { - if idle == 0 { // start with 20us sleep... - delay = 20 - } else if idle > 50 { // start doubling the sleep after 1ms... - delay *= 2 - } - if delay > 10*1000 { // up to 10ms - delay = 10 * 1000 - } - usleep(delay) - - // sysmon should not enter deep sleep if schedtrace is enabled so that - // it can print that information at the right time. - // - // It should also not enter deep sleep if there are any active P's so - // that it can retake P's from syscalls, preempt long running G's, and - // poll the network if all P's are busy for long stretches. - // - // It should wakeup from deep sleep if any P's become active either due - // to exiting a syscall or waking up due to a timer expiring so that it - // can resume performing those duties. If it wakes from a syscall it - // resets idle and delay as a bet that since it had retaken a P from a - // syscall before, it may need to do it again shortly after the - // application starts work again. It does not reset idle when waking - // from a timer to avoid adding system load to applications that spend - // most of their time sleeping. - now := nanotime() - if debug.schedtrace <= 0 && (sched.gcwaiting.Load() || sched.npidle.Load() == gomaxprocs) { - lock(&sched.lock) - if sched.gcwaiting.Load() || sched.npidle.Load() == gomaxprocs { - syscallWake := false - next := timeSleepUntil() - if next > now { - sched.sysmonwait.Store(true) - unlock(&sched.lock) - // Make wake-up period small enough - // for the sampling to be correct. - sleep := forcegcperiod / 2 - if next-now < sleep { - sleep = next - now - } - shouldRelax := sleep >= osRelaxMinNS - if shouldRelax { - osRelax(true) - } - syscallWake = notetsleep(&sched.sysmonnote, sleep) - if shouldRelax { - osRelax(false) - } - lock(&sched.lock) - sched.sysmonwait.Store(false) - noteclear(&sched.sysmonnote) - } - if syscallWake { - idle = 0 - delay = 20 - } - } - unlock(&sched.lock) - } - - lock(&sched.sysmonlock) - // Update now in case we blocked on sysmonnote or spent a long time - // blocked on schedlock or sysmonlock above. - now = nanotime() - - // trigger libc interceptors if needed - if *cgo_yield != nil { - asmcgocall(*cgo_yield, nil) - } - // poll network if not polled for more than 10ms - lastpoll := sched.lastpoll.Load() - if netpollinited() && lastpoll != 0 && lastpoll+10*1000*1000 < now { - sched.lastpoll.CompareAndSwap(lastpoll, now) - list, delta := netpoll(0) // non-blocking - returns list of goroutines - if !list.empty() { - // Need to decrement number of idle locked M's - // (pretending that one more is running) before injectglist. - // Otherwise it can lead to the following situation: - // injectglist grabs all P's but before it starts M's to run the P's, - // another M returns from syscall, finishes running its G, - // observes that there is no work to do and no other running M's - // and reports deadlock. - incidlelocked(-1) - injectglist(&list) - incidlelocked(1) - netpollAdjustWaiters(delta) - } - } - if GOOS == "netbsd" && needSysmonWorkaround { - // netpoll is responsible for waiting for timer - // expiration, so we typically don't have to worry - // about starting an M to service timers. (Note that - // sleep for timeSleepUntil above simply ensures sysmon - // starts running again when that timer expiration may - // cause Go code to run again). - // - // However, netbsd has a kernel bug that sometimes - // misses netpollBreak wake-ups, which can lead to - // unbounded delays servicing timers. If we detect this - // overrun, then startm to get something to handle the - // timer. - // - // See issue 42515 and - // https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50094. - if next := timeSleepUntil(); next < now { - startm(nil, false, false) - } - } - if scavenger.sysmonWake.Load() != 0 { - // Kick the scavenger awake if someone requested it. - scavenger.wake() - } - // retake P's blocked in syscalls - // and preempt long running G's - if retake(now) != 0 { - idle = 0 - } else { - idle++ - } - // check if we need to force a GC - if t := (gcTrigger{kind: gcTriggerTime, now: now}); t.test() && forcegc.idle.Load() { - lock(&forcegc.lock) - forcegc.idle.Store(false) - var list gList - list.push(forcegc.g) - injectglist(&list) - unlock(&forcegc.lock) - } - if debug.schedtrace > 0 && lasttrace+int64(debug.schedtrace)*1000000 <= now { - lasttrace = now - schedtrace(debug.scheddetail > 0) - } - unlock(&sched.sysmonlock) - } -} - -type sysmontick struct { - schedtick uint32 - schedwhen int64 - syscalltick uint32 - syscallwhen int64 -} - -// forcePreemptNS is the time slice given to a G before it is -// preempted. -const forcePreemptNS = 10 * 1000 * 1000 // 10ms - -func retake(now int64) uint32 { - n := 0 - // Prevent allp slice changes. This lock will be completely - // uncontended unless we're already stopping the world. - lock(&allpLock) - // We can't use a range loop over allp because we may - // temporarily drop the allpLock. Hence, we need to re-fetch - // allp each time around the loop. - for i := 0; i < len(allp); i++ { - pp := allp[i] - if pp == nil { - // This can happen if procresize has grown - // allp but not yet created new Ps. - continue - } - pd := &pp.sysmontick - s := pp.status - sysretake := false - if s == _Prunning || s == _Psyscall { - // Preempt G if it's running for too long. - t := int64(pp.schedtick) - if int64(pd.schedtick) != t { - pd.schedtick = uint32(t) - pd.schedwhen = now - } else if pd.schedwhen+forcePreemptNS <= now { - preemptone(pp) - // In case of syscall, preemptone() doesn't - // work, because there is no M wired to P. - sysretake = true - } - } - if s == _Psyscall { - // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us). - t := int64(pp.syscalltick) - if !sysretake && int64(pd.syscalltick) != t { - pd.syscalltick = uint32(t) - pd.syscallwhen = now - continue - } - // On the one hand we don't want to retake Ps if there is no other work to do, - // but on the other hand we want to retake them eventually - // because they can prevent the sysmon thread from deep sleep. - if runqempty(pp) && sched.nmspinning.Load()+sched.npidle.Load() > 0 && pd.syscallwhen+10*1000*1000 > now { - continue - } - // Drop allpLock so we can take sched.lock. - unlock(&allpLock) - // Need to decrement number of idle locked M's - // (pretending that one more is running) before the CAS. - // Otherwise the M from which we retake can exit the syscall, - // increment nmidle and report deadlock. - incidlelocked(-1) - trace := traceAcquire() - if atomic.Cas(&pp.status, s, _Pidle) { - if trace.ok() { - trace.GoSysBlock(pp) - trace.ProcSteal(pp, false) - traceRelease(trace) - } - n++ - pp.syscalltick++ - handoffp(pp) - } else if trace.ok() { - traceRelease(trace) - } - incidlelocked(1) - lock(&allpLock) - } - } - unlock(&allpLock) - return uint32(n) -} - -// Tell all goroutines that they have been preempted and they should stop. -// This function is purely best-effort. It can fail to inform a goroutine if a -// processor just started running it. -// No locks need to be held. -// Returns true if preemption request was issued to at least one goroutine. -func preemptall() bool { - res := false - for _, pp := range allp { - if pp.status != _Prunning { - continue - } - if preemptone(pp) { - res = true - } - } - return res -} - -// Tell the goroutine running on processor P to stop. -// This function is purely best-effort. It can incorrectly fail to inform the -// goroutine. It can inform the wrong goroutine. Even if it informs the -// correct goroutine, that goroutine might ignore the request if it is -// simultaneously executing newstack. -// No lock needs to be held. -// Returns true if preemption request was issued. -// The actual preemption will happen at some point in the future -// and will be indicated by the gp->status no longer being -// Grunning -func preemptone(pp *p) bool { - mp := pp.m.ptr() - if mp == nil || mp == getg().m { - return false - } - gp := mp.curg - if gp == nil || gp == mp.g0 { - return false - } - - gp.preempt = true - - // Every call in a goroutine checks for stack overflow by - // comparing the current stack pointer to gp->stackguard0. - // Setting gp->stackguard0 to StackPreempt folds - // preemption into the normal stack overflow check. - gp.stackguard0 = stackPreempt - - // Request an async preemption of this P. - if preemptMSupported && debug.asyncpreemptoff == 0 { - pp.preempt = true - preemptM(mp) - } - - return true -} - -var starttime int64 - -func schedtrace(detailed bool) { - now := nanotime() - if starttime == 0 { - starttime = now - } - - lock(&sched.lock) - print("SCHED ", (now-starttime)/1e6, "ms: gomaxprocs=", gomaxprocs, " idleprocs=", sched.npidle.Load(), " threads=", mcount(), " spinningthreads=", sched.nmspinning.Load(), " needspinning=", sched.needspinning.Load(), " idlethreads=", sched.nmidle, " runqueue=", sched.runqsize) - if detailed { - print(" gcwaiting=", sched.gcwaiting.Load(), " nmidlelocked=", sched.nmidlelocked, " stopwait=", sched.stopwait, " sysmonwait=", sched.sysmonwait.Load(), "\n") - } - // We must be careful while reading data from P's, M's and G's. - // Even if we hold schedlock, most data can be changed concurrently. - // E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil. - for i, pp := range allp { - mp := pp.m.ptr() - h := atomic.Load(&pp.runqhead) - t := atomic.Load(&pp.runqtail) - if detailed { - print(" P", i, ": status=", pp.status, " schedtick=", pp.schedtick, " syscalltick=", pp.syscalltick, " m=") - if mp != nil { - print(mp.id) - } else { - print("nil") - } - print(" runqsize=", t-h, " gfreecnt=", pp.gFree.n, " timerslen=", len(pp.timers), "\n") - } else { - // In non-detailed mode format lengths of per-P run queues as: - // [len1 len2 len3 len4] - print(" ") - if i == 0 { - print("[") - } - print(t - h) - if i == len(allp)-1 { - print("]\n") - } - } - } - - if !detailed { - unlock(&sched.lock) - return - } - - for mp := allm; mp != nil; mp = mp.alllink { - pp := mp.p.ptr() - print(" M", mp.id, ": p=") - if pp != nil { - print(pp.id) - } else { - print("nil") - } - print(" curg=") - if mp.curg != nil { - print(mp.curg.goid) - } else { - print("nil") - } - print(" mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, " locks=", mp.locks, " dying=", mp.dying, " spinning=", mp.spinning, " blocked=", mp.blocked, " lockedg=") - if lockedg := mp.lockedg.ptr(); lockedg != nil { - print(lockedg.goid) - } else { - print("nil") - } - print("\n") - } - - forEachG(func(gp *g) { - print(" G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason.String(), ") m=") - if gp.m != nil { - print(gp.m.id) - } else { - print("nil") - } - print(" lockedm=") - if lockedm := gp.lockedm.ptr(); lockedm != nil { - print(lockedm.id) - } else { - print("nil") - } - print("\n") - }) - unlock(&sched.lock) -} - -// schedEnableUser enables or disables the scheduling of user -// goroutines. -// -// This does not stop already running user goroutines, so the caller -// should first stop the world when disabling user goroutines. -func schedEnableUser(enable bool) { - lock(&sched.lock) - if sched.disable.user == !enable { - unlock(&sched.lock) - return - } - sched.disable.user = !enable - if enable { - n := sched.disable.n - sched.disable.n = 0 - globrunqputbatch(&sched.disable.runnable, n) - unlock(&sched.lock) - for ; n != 0 && sched.npidle.Load() != 0; n-- { - startm(nil, false, false) - } - } else { - unlock(&sched.lock) - } -} - -// schedEnabled reports whether gp should be scheduled. It returns -// false is scheduling of gp is disabled. -// -// sched.lock must be held. -func schedEnabled(gp *g) bool { - assertLockHeld(&sched.lock) - - if sched.disable.user { - return isSystemGoroutine(gp, true) - } - return true -} - -// Put mp on midle list. -// sched.lock must be held. -// May run during STW, so write barriers are not allowed. -// -//go:nowritebarrierrec -func mput(mp *m) { - assertLockHeld(&sched.lock) - - mp.schedlink = sched.midle - sched.midle.set(mp) - sched.nmidle++ - checkdead() -} - -// Try to get an m from midle list. -// sched.lock must be held. -// May run during STW, so write barriers are not allowed. -// -//go:nowritebarrierrec -func mget() *m { - assertLockHeld(&sched.lock) - - mp := sched.midle.ptr() - if mp != nil { - sched.midle = mp.schedlink - sched.nmidle-- - } - return mp -} - -// Put gp on the global runnable queue. -// sched.lock must be held. -// May run during STW, so write barriers are not allowed. -// -//go:nowritebarrierrec -func globrunqput(gp *g) { - assertLockHeld(&sched.lock) - - sched.runq.pushBack(gp) - sched.runqsize++ -} - -// Put gp at the head of the global runnable queue. -// sched.lock must be held. -// May run during STW, so write barriers are not allowed. -// -//go:nowritebarrierrec -func globrunqputhead(gp *g) { - assertLockHeld(&sched.lock) - - sched.runq.push(gp) - sched.runqsize++ -} - -// Put a batch of runnable goroutines on the global runnable queue. -// This clears *batch. -// sched.lock must be held. -// May run during STW, so write barriers are not allowed. -// -//go:nowritebarrierrec -func globrunqputbatch(batch *gQueue, n int32) { - assertLockHeld(&sched.lock) - - sched.runq.pushBackAll(*batch) - sched.runqsize += n - *batch = gQueue{} -} - -// Try get a batch of G's from the global runnable queue. -// sched.lock must be held. -func globrunqget(pp *p, max int32) *g { - assertLockHeld(&sched.lock) - - if sched.runqsize == 0 { - return nil - } - - n := sched.runqsize/gomaxprocs + 1 - if n > sched.runqsize { - n = sched.runqsize - } - if max > 0 && n > max { - n = max - } - if n > int32(len(pp.runq))/2 { - n = int32(len(pp.runq)) / 2 - } - - sched.runqsize -= n - - gp := sched.runq.pop() - n-- - for ; n > 0; n-- { - gp1 := sched.runq.pop() - runqput(pp, gp1, false) - } - return gp -} - -// pMask is an atomic bitstring with one bit per P. -type pMask []uint32 - -// read returns true if P id's bit is set. -func (p pMask) read(id uint32) bool { - word := id / 32 - mask := uint32(1) << (id % 32) - return (atomic.Load(&p[word]) & mask) != 0 -} - -// set sets P id's bit. -func (p pMask) set(id int32) { - word := id / 32 - mask := uint32(1) << (id % 32) - atomic.Or(&p[word], mask) -} - -// clear clears P id's bit. -func (p pMask) clear(id int32) { - word := id / 32 - mask := uint32(1) << (id % 32) - atomic.And(&p[word], ^mask) -} - -// updateTimerPMask clears pp's timer mask if it has no timers on its heap. -// -// Ideally, the timer mask would be kept immediately consistent on any timer -// operations. Unfortunately, updating a shared global data structure in the -// timer hot path adds too much overhead in applications frequently switching -// between no timers and some timers. -// -// As a compromise, the timer mask is updated only on pidleget / pidleput. A -// running P (returned by pidleget) may add a timer at any time, so its mask -// must be set. An idle P (passed to pidleput) cannot add new timers while -// idle, so if it has no timers at that time, its mask may be cleared. -// -// Thus, we get the following effects on timer-stealing in findrunnable: -// -// - Idle Ps with no timers when they go idle are never checked in findrunnable -// (for work- or timer-stealing; this is the ideal case). -// - Running Ps must always be checked. -// - Idle Ps whose timers are stolen must continue to be checked until they run -// again, even after timer expiration. -// -// When the P starts running again, the mask should be set, as a timer may be -// added at any time. -// -// TODO(prattmic): Additional targeted updates may improve the above cases. -// e.g., updating the mask when stealing a timer. -func updateTimerPMask(pp *p) { - if pp.numTimers.Load() > 0 { - return - } - - // Looks like there are no timers, however another P may transiently - // decrement numTimers when handling a timerModified timer in - // checkTimers. We must take timersLock to serialize with these changes. - lock(&pp.timersLock) - if pp.numTimers.Load() == 0 { - timerpMask.clear(pp.id) - } - unlock(&pp.timersLock) -} - -// pidleput puts p on the _Pidle list. now must be a relatively recent call -// to nanotime or zero. Returns now or the current time if now was zero. -// -// This releases ownership of p. Once sched.lock is released it is no longer -// safe to use p. -// -// sched.lock must be held. -// -// May run during STW, so write barriers are not allowed. -// -//go:nowritebarrierrec -func pidleput(pp *p, now int64) int64 { - assertLockHeld(&sched.lock) - - if !runqempty(pp) { - throw("pidleput: P has non-empty run queue") - } - if now == 0 { - now = nanotime() - } - updateTimerPMask(pp) // clear if there are no timers. - idlepMask.set(pp.id) - pp.link = sched.pidle - sched.pidle.set(pp) - sched.npidle.Add(1) - if !pp.limiterEvent.start(limiterEventIdle, now) { - throw("must be able to track idle limiter event") - } - return now -} - -// pidleget tries to get a p from the _Pidle list, acquiring ownership. -// -// sched.lock must be held. -// -// May run during STW, so write barriers are not allowed. -// -//go:nowritebarrierrec -func pidleget(now int64) (*p, int64) { - assertLockHeld(&sched.lock) - - pp := sched.pidle.ptr() - if pp != nil { - // Timer may get added at any time now. - if now == 0 { - now = nanotime() - } - timerpMask.set(pp.id) - idlepMask.clear(pp.id) - sched.pidle = pp.link - sched.npidle.Add(-1) - pp.limiterEvent.stop(limiterEventIdle, now) - } - return pp, now -} - -// pidlegetSpinning tries to get a p from the _Pidle list, acquiring ownership. -// This is called by spinning Ms (or callers than need a spinning M) that have -// found work. If no P is available, this must synchronized with non-spinning -// Ms that may be preparing to drop their P without discovering this work. -// -// sched.lock must be held. -// -// May run during STW, so write barriers are not allowed. -// -//go:nowritebarrierrec -func pidlegetSpinning(now int64) (*p, int64) { - assertLockHeld(&sched.lock) - - pp, now := pidleget(now) - if pp == nil { - // See "Delicate dance" comment in findrunnable. We found work - // that we cannot take, we must synchronize with non-spinning - // Ms that may be preparing to drop their P. - sched.needspinning.Store(1) - return nil, now - } - - return pp, now -} - -// runqempty reports whether pp has no Gs on its local run queue. -// It never returns true spuriously. -func runqempty(pp *p) bool { - // Defend against a race where 1) pp has G1 in runqnext but runqhead == runqtail, - // 2) runqput on pp kicks G1 to the runq, 3) runqget on pp empties runqnext. - // Simply observing that runqhead == runqtail and then observing that runqnext == nil - // does not mean the queue is empty. - for { - head := atomic.Load(&pp.runqhead) - tail := atomic.Load(&pp.runqtail) - runnext := atomic.Loaduintptr((*uintptr)(unsafe.Pointer(&pp.runnext))) - if tail == atomic.Load(&pp.runqtail) { - return head == tail && runnext == 0 - } - } -} - -// To shake out latent assumptions about scheduling order, -// we introduce some randomness into scheduling decisions -// when running with the race detector. -// The need for this was made obvious by changing the -// (deterministic) scheduling order in Go 1.5 and breaking -// many poorly-written tests. -// With the randomness here, as long as the tests pass -// consistently with -race, they shouldn't have latent scheduling -// assumptions. -const randomizeScheduler = raceenabled - -// runqput tries to put g on the local runnable queue. -// If next is false, runqput adds g to the tail of the runnable queue. -// If next is true, runqput puts g in the pp.runnext slot. -// If the run queue is full, runnext puts g on the global queue. -// Executed only by the owner P. -func runqput(pp *p, gp *g, next bool) { - if randomizeScheduler && next && randn(2) == 0 { - next = false - } - - if next { - retryNext: - oldnext := pp.runnext - if !pp.runnext.cas(oldnext, guintptr(unsafe.Pointer(gp))) { - goto retryNext - } - if oldnext == 0 { - return - } - // Kick the old runnext out to the regular run queue. - gp = oldnext.ptr() - } - -retry: - h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with consumers - t := pp.runqtail - if t-h < uint32(len(pp.runq)) { - pp.runq[t%uint32(len(pp.runq))].set(gp) - atomic.StoreRel(&pp.runqtail, t+1) // store-release, makes the item available for consumption - return - } - if runqputslow(pp, gp, h, t) { - return - } - // the queue is not full, now the put above must succeed - goto retry -} - -// Put g and a batch of work from local runnable queue on global queue. -// Executed only by the owner P. -func runqputslow(pp *p, gp *g, h, t uint32) bool { - var batch [len(pp.runq)/2 + 1]*g - - // First, grab a batch from local queue. - n := t - h - n = n / 2 - if n != uint32(len(pp.runq)/2) { - throw("runqputslow: queue is not full") - } - for i := uint32(0); i < n; i++ { - batch[i] = pp.runq[(h+i)%uint32(len(pp.runq))].ptr() - } - if !atomic.CasRel(&pp.runqhead, h, h+n) { // cas-release, commits consume - return false - } - batch[n] = gp - - if randomizeScheduler { - for i := uint32(1); i <= n; i++ { - j := cheaprandn(i + 1) - batch[i], batch[j] = batch[j], batch[i] - } - } - - // Link the goroutines. - for i := uint32(0); i < n; i++ { - batch[i].schedlink.set(batch[i+1]) - } - var q gQueue - q.head.set(batch[0]) - q.tail.set(batch[n]) - - // Now put the batch on global queue. - lock(&sched.lock) - globrunqputbatch(&q, int32(n+1)) - unlock(&sched.lock) - return true -} - -// runqputbatch tries to put all the G's on q on the local runnable queue. -// If the queue is full, they are put on the global queue; in that case -// this will temporarily acquire the scheduler lock. -// Executed only by the owner P. -func runqputbatch(pp *p, q *gQueue, qsize int) { - h := atomic.LoadAcq(&pp.runqhead) - t := pp.runqtail - n := uint32(0) - for !q.empty() && t-h < uint32(len(pp.runq)) { - gp := q.pop() - pp.runq[t%uint32(len(pp.runq))].set(gp) - t++ - n++ - } - qsize -= int(n) - - if randomizeScheduler { - off := func(o uint32) uint32 { - return (pp.runqtail + o) % uint32(len(pp.runq)) - } - for i := uint32(1); i < n; i++ { - j := cheaprandn(i + 1) - pp.runq[off(i)], pp.runq[off(j)] = pp.runq[off(j)], pp.runq[off(i)] - } - } - - atomic.StoreRel(&pp.runqtail, t) - if !q.empty() { - lock(&sched.lock) - globrunqputbatch(q, int32(qsize)) - unlock(&sched.lock) - } -} - -// Get g from local runnable queue. -// If inheritTime is true, gp should inherit the remaining time in the -// current time slice. Otherwise, it should start a new time slice. -// Executed only by the owner P. -func runqget(pp *p) (gp *g, inheritTime bool) { - // If there's a runnext, it's the next G to run. - next := pp.runnext - // If the runnext is non-0 and the CAS fails, it could only have been stolen by another P, - // because other Ps can race to set runnext to 0, but only the current P can set it to non-0. - // Hence, there's no need to retry this CAS if it fails. - if next != 0 && pp.runnext.cas(next, 0) { - return next.ptr(), true - } - - for { - h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with other consumers - t := pp.runqtail - if t == h { - return nil, false - } - gp := pp.runq[h%uint32(len(pp.runq))].ptr() - if atomic.CasRel(&pp.runqhead, h, h+1) { // cas-release, commits consume - return gp, false - } - } -} - -// runqdrain drains the local runnable queue of pp and returns all goroutines in it. -// Executed only by the owner P. -func runqdrain(pp *p) (drainQ gQueue, n uint32) { - oldNext := pp.runnext - if oldNext != 0 && pp.runnext.cas(oldNext, 0) { - drainQ.pushBack(oldNext.ptr()) - n++ - } - -retry: - h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with other consumers - t := pp.runqtail - qn := t - h - if qn == 0 { - return - } - if qn > uint32(len(pp.runq)) { // read inconsistent h and t - goto retry - } - - if !atomic.CasRel(&pp.runqhead, h, h+qn) { // cas-release, commits consume - goto retry - } - - // We've inverted the order in which it gets G's from the local P's runnable queue - // and then advances the head pointer because we don't want to mess up the statuses of G's - // while runqdrain() and runqsteal() are running in parallel. - // Thus we should advance the head pointer before draining the local P into a gQueue, - // so that we can update any gp.schedlink only after we take the full ownership of G, - // meanwhile, other P's can't access to all G's in local P's runnable queue and steal them. - // See https://groups.google.com/g/golang-dev/c/0pTKxEKhHSc/m/6Q85QjdVBQAJ for more details. - for i := uint32(0); i < qn; i++ { - gp := pp.runq[(h+i)%uint32(len(pp.runq))].ptr() - drainQ.pushBack(gp) - n++ - } - return -} - -// Grabs a batch of goroutines from pp's runnable queue into batch. -// Batch is a ring buffer starting at batchHead. -// Returns number of grabbed goroutines. -// Can be executed by any P. -func runqgrab(pp *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool) uint32 { - for { - h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with other consumers - t := atomic.LoadAcq(&pp.runqtail) // load-acquire, synchronize with the producer - n := t - h - n = n - n/2 - if n == 0 { - if stealRunNextG { - // Try to steal from pp.runnext. - if next := pp.runnext; next != 0 { - if pp.status == _Prunning { - // Sleep to ensure that pp isn't about to run the g - // we are about to steal. - // The important use case here is when the g running - // on pp ready()s another g and then almost - // immediately blocks. Instead of stealing runnext - // in this window, back off to give pp a chance to - // schedule runnext. This will avoid thrashing gs - // between different Ps. - // A sync chan send/recv takes ~50ns as of time of - // writing, so 3us gives ~50x overshoot. - if !osHasLowResTimer { - usleep(3) - } else { - // On some platforms system timer granularity is - // 1-15ms, which is way too much for this - // optimization. So just yield. - osyield() - } - } - if !pp.runnext.cas(next, 0) { - continue - } - batch[batchHead%uint32(len(batch))] = next - return 1 - } - } - return 0 - } - if n > uint32(len(pp.runq)/2) { // read inconsistent h and t - continue - } - for i := uint32(0); i < n; i++ { - g := pp.runq[(h+i)%uint32(len(pp.runq))] - batch[(batchHead+i)%uint32(len(batch))] = g - } - if atomic.CasRel(&pp.runqhead, h, h+n) { // cas-release, commits consume - return n - } - } -} - -// Steal half of elements from local runnable queue of p2 -// and put onto local runnable queue of p. -// Returns one of the stolen elements (or nil if failed). -func runqsteal(pp, p2 *p, stealRunNextG bool) *g { - t := pp.runqtail - n := runqgrab(p2, &pp.runq, t, stealRunNextG) - if n == 0 { - return nil - } - n-- - gp := pp.runq[(t+n)%uint32(len(pp.runq))].ptr() - if n == 0 { - return gp - } - h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with consumers - if t-h+n >= uint32(len(pp.runq)) { - throw("runqsteal: runq overflow") - } - atomic.StoreRel(&pp.runqtail, t+n) // store-release, makes the item available for consumption - return gp -} - -// A gQueue is a dequeue of Gs linked through g.schedlink. A G can only -// be on one gQueue or gList at a time. -type gQueue struct { - head guintptr - tail guintptr -} - -// empty reports whether q is empty. -func (q *gQueue) empty() bool { - return q.head == 0 -} - -// push adds gp to the head of q. -func (q *gQueue) push(gp *g) { - gp.schedlink = q.head - q.head.set(gp) - if q.tail == 0 { - q.tail.set(gp) - } -} - -// pushBack adds gp to the tail of q. -func (q *gQueue) pushBack(gp *g) { - gp.schedlink = 0 - if q.tail != 0 { - q.tail.ptr().schedlink.set(gp) - } else { - q.head.set(gp) - } - q.tail.set(gp) -} - -// pushBackAll adds all Gs in q2 to the tail of q. After this q2 must -// not be used. -func (q *gQueue) pushBackAll(q2 gQueue) { - if q2.tail == 0 { - return - } - q2.tail.ptr().schedlink = 0 - if q.tail != 0 { - q.tail.ptr().schedlink = q2.head - } else { - q.head = q2.head - } - q.tail = q2.tail -} - -// pop removes and returns the head of queue q. It returns nil if -// q is empty. -func (q *gQueue) pop() *g { - gp := q.head.ptr() - if gp != nil { - q.head = gp.schedlink - if q.head == 0 { - q.tail = 0 - } - } - return gp -} - -// popList takes all Gs in q and returns them as a gList. -func (q *gQueue) popList() gList { - stack := gList{q.head} - *q = gQueue{} - return stack -} - -// A gList is a list of Gs linked through g.schedlink. A G can only be -// on one gQueue or gList at a time. -type gList struct { - head guintptr -} - -// empty reports whether l is empty. -func (l *gList) empty() bool { - return l.head == 0 -} - -// push adds gp to the head of l. -func (l *gList) push(gp *g) { - gp.schedlink = l.head - l.head.set(gp) -} - -// pushAll prepends all Gs in q to l. -func (l *gList) pushAll(q gQueue) { - if !q.empty() { - q.tail.ptr().schedlink = l.head - l.head = q.head - } -} - -// pop removes and returns the head of l. If l is empty, it returns nil. -func (l *gList) pop() *g { - gp := l.head.ptr() - if gp != nil { - l.head = gp.schedlink - } - return gp -} - -//go:linkname setMaxThreads runtime/debug.setMaxThreads -func setMaxThreads(in int) (out int) { - lock(&sched.lock) - out = int(sched.maxmcount) - if in > 0x7fffffff { // MaxInt32 - sched.maxmcount = 0x7fffffff - } else { - sched.maxmcount = int32(in) - } - checkmcount() - unlock(&sched.lock) - return -} - -//go:nosplit -func procPin() int { - gp := getg() - mp := gp.m - - mp.locks++ - return int(mp.p.ptr().id) -} - -//go:nosplit -func procUnpin() { - gp := getg() - gp.m.locks-- -} - -//go:linkname sync_runtime_procPin sync.runtime_procPin -//go:nosplit -func sync_runtime_procPin() int { - return procPin() -} - -//go:linkname sync_runtime_procUnpin sync.runtime_procUnpin -//go:nosplit -func sync_runtime_procUnpin() { - procUnpin() -} - -//go:linkname sync_atomic_runtime_procPin sync/atomic.runtime_procPin -//go:nosplit -func sync_atomic_runtime_procPin() int { - return procPin() -} - -//go:linkname sync_atomic_runtime_procUnpin sync/atomic.runtime_procUnpin -//go:nosplit -func sync_atomic_runtime_procUnpin() { - procUnpin() -} - -// Active spinning for sync.Mutex. -// -//go:linkname sync_runtime_canSpin sync.runtime_canSpin -//go:nosplit -func sync_runtime_canSpin(i int) bool { - // sync.Mutex is cooperative, so we are conservative with spinning. - // Spin only few times and only if running on a multicore machine and - // GOMAXPROCS>1 and there is at least one other running P and local runq is empty. - // As opposed to runtime mutex we don't do passive spinning here, - // because there can be work on global runq or on other Ps. - if i >= active_spin || ncpu <= 1 || gomaxprocs <= sched.npidle.Load()+sched.nmspinning.Load()+1 { - return false - } - if p := getg().m.p.ptr(); !runqempty(p) { - return false - } - return true -} - -//go:linkname sync_runtime_doSpin sync.runtime_doSpin -//go:nosplit -func sync_runtime_doSpin() { - procyield(active_spin_cnt) -} - -var stealOrder randomOrder - -// randomOrder/randomEnum are helper types for randomized work stealing. -// They allow to enumerate all Ps in different pseudo-random orders without repetitions. -// The algorithm is based on the fact that if we have X such that X and GOMAXPROCS -// are coprime, then a sequences of (i + X) % GOMAXPROCS gives the required enumeration. -type randomOrder struct { - count uint32 - coprimes []uint32 -} - -type randomEnum struct { - i uint32 - count uint32 - pos uint32 - inc uint32 -} - -func (ord *randomOrder) reset(count uint32) { - ord.count = count - ord.coprimes = ord.coprimes[:0] - for i := uint32(1); i <= count; i++ { - if gcd(i, count) == 1 { - ord.coprimes = append(ord.coprimes, i) - } - } -} - -func (ord *randomOrder) start(i uint32) randomEnum { - return randomEnum{ - count: ord.count, - pos: i % ord.count, - inc: ord.coprimes[i/ord.count%uint32(len(ord.coprimes))], - } -} - -func (enum *randomEnum) done() bool { - return enum.i == enum.count -} - -func (enum *randomEnum) next() { - enum.i++ - enum.pos = (enum.pos + enum.inc) % enum.count -} - -func (enum *randomEnum) position() uint32 { - return enum.pos -} - -func gcd(a, b uint32) uint32 { - for b != 0 { - a, b = b, a%b - } - return a -} - -// An initTask represents the set of initializations that need to be done for a package. -// Keep in sync with ../../test/noinit.go:initTask -type initTask struct { - state uint32 // 0 = uninitialized, 1 = in progress, 2 = done - nfns uint32 - // followed by nfns pcs, uintptr sized, one per init function to run -} - -// inittrace stores statistics for init functions which are -// updated by malloc and newproc when active is true. -var inittrace tracestat - -type tracestat struct { - active bool // init tracing activation status - id uint64 // init goroutine id - allocs uint64 // heap allocations - bytes uint64 // heap allocated bytes -} - -func doInit(ts []*initTask) { - for _, t := range ts { - doInit1(t) - } -} - -func doInit1(t *initTask) { - switch t.state { - case 2: // fully initialized - return - case 1: // initialization in progress - throw("recursive call during initialization - linker skew") - default: // not initialized yet - t.state = 1 // initialization in progress - - var ( - start int64 - before tracestat - ) - - if inittrace.active { - start = nanotime() - // Load stats non-atomically since tracinit is updated only by this init goroutine. - before = inittrace - } - - if t.nfns == 0 { - // We should have pruned all of these in the linker. - throw("inittask with no functions") - } - - firstFunc := add(unsafe.Pointer(t), 8) - for i := uint32(0); i < t.nfns; i++ { - p := add(firstFunc, uintptr(i)*goarch.PtrSize) - f := *(*func())(unsafe.Pointer(&p)) - f() - } - - if inittrace.active { - end := nanotime() - // Load stats non-atomically since tracinit is updated only by this init goroutine. - after := inittrace - - f := *(*func())(unsafe.Pointer(&firstFunc)) - pkg := funcpkgpath(findfunc(abi.FuncPCABIInternal(f))) - - var sbuf [24]byte - print("init ", pkg, " @") - print(string(fmtNSAsMS(sbuf[:], uint64(start-runtimeInitTime))), " ms, ") - print(string(fmtNSAsMS(sbuf[:], uint64(end-start))), " ms clock, ") - print(string(itoa(sbuf[:], after.bytes-before.bytes)), " bytes, ") - print(string(itoa(sbuf[:], after.allocs-before.allocs)), " allocs") - print("\n") - } - - t.state = 2 // initialization done - } -} diff --git a/contrib/go/_std_1.22/src/runtime/proflabel.go b/contrib/go/_std_1.22/src/runtime/proflabel.go deleted file mode 100644 index b2a161729eff..000000000000 --- a/contrib/go/_std_1.22/src/runtime/proflabel.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -var labelSync uintptr - -//go:linkname runtime_setProfLabel runtime/pprof.runtime_setProfLabel -func runtime_setProfLabel(labels unsafe.Pointer) { - // Introduce race edge for read-back via profile. - // This would more properly use &getg().labels as the sync address, - // but we do the read in a signal handler and can't call the race runtime then. - // - // This uses racereleasemerge rather than just racerelease so - // the acquire in profBuf.read synchronizes with *all* prior - // setProfLabel operations, not just the most recent one. This - // is important because profBuf.read will observe different - // labels set by different setProfLabel operations on - // different goroutines, so it needs to synchronize with all - // of them (this wouldn't be an issue if we could synchronize - // on &getg().labels since we would synchronize with each - // most-recent labels write separately.) - // - // racereleasemerge is like a full read-modify-write on - // labelSync, rather than just a store-release, so it carries - // a dependency on the previous racereleasemerge, which - // ultimately carries forward to the acquire in profBuf.read. - if raceenabled { - racereleasemerge(unsafe.Pointer(&labelSync)) - } - getg().labels = labels -} - -//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel -func runtime_getProfLabel() unsafe.Pointer { - return getg().labels -} diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/ya.make b/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/ya.make deleted file mode 100644 index b02d72616d65..000000000000 --- a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/ya.make +++ /dev/null @@ -1,28 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - race_darwin.syso - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race_darwin.syso - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - race_linux.syso - ) -ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race_linux.syso - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race_windows.syso - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/ya.make b/contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/ya.make deleted file mode 100644 index b3aeb5efea4f..000000000000 --- a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/ya.make +++ /dev/null @@ -1,9 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - race_linux.syso - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/runtime/race/ya.make b/contrib/go/_std_1.22/src/runtime/race/ya.make deleted file mode 100644 index db88477cb141..000000000000 --- a/contrib/go/_std_1.22/src/runtime/race/ya.make +++ /dev/null @@ -1,54 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race_darwin_arm64.go - race_darwin_arm64.syso - ) -ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race_darwin_arm64.syso - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race_darwin_amd64.go - race_v1_amd64.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race_v1_amd64.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED) - SRCS( - doc.go - race_linux_arm64.syso - ) - -IF (CGO_ENABLED) - CGO_SRCS( - race.go - ) -ENDIF() -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race_linux_arm64.syso - ) -ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED) - SRCS( - doc.go - race_v1_amd64.go - ) - -IF (CGO_ENABLED) - CGO_SRCS( - race.go - ) -ENDIF() -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/runtime/rand.go b/contrib/go/_std_1.22/src/runtime/rand.go deleted file mode 100644 index 10cd116fadea..000000000000 --- a/contrib/go/_std_1.22/src/runtime/rand.go +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Random number generation - -package runtime - -import ( - "internal/chacha8rand" - "internal/goarch" - "runtime/internal/math" - "unsafe" - _ "unsafe" // for go:linkname -) - -// OS-specific startup can set startupRand if the OS passes -// random data to the process at startup time. -// For example Linux passes 16 bytes in the auxv vector. -var startupRand []byte - -// globalRand holds the global random state. -// It is only used at startup and for creating new m's. -// Otherwise the per-m random state should be used -// by calling goodrand. -var globalRand struct { - lock mutex - seed [32]byte - state chacha8rand.State - init bool -} - -var readRandomFailed bool - -// randinit initializes the global random state. -// It must be called before any use of grand. -func randinit() { - lock(&globalRand.lock) - if globalRand.init { - fatal("randinit twice") - } - - seed := &globalRand.seed - if startupRand != nil { - for i, c := range startupRand { - seed[i%len(seed)] ^= c - } - clear(startupRand) - startupRand = nil - } else { - if readRandom(seed[:]) != len(seed) { - // readRandom should never fail, but if it does we'd rather - // not make Go binaries completely unusable, so make up - // some random data based on the current time. - readRandomFailed = true - readTimeRandom(seed[:]) - } - } - globalRand.state.Init(*seed) - clear(seed[:]) - globalRand.init = true - unlock(&globalRand.lock) -} - -// readTimeRandom stretches any entropy in the current time -// into entropy the length of r and XORs it into r. -// This is a fallback for when readRandom does not read -// the full requested amount. -// Whatever entropy r already contained is preserved. -func readTimeRandom(r []byte) { - // Inspired by wyrand. - // An earlier version of this code used getg().m.procid as well, - // but note that this is called so early in startup that procid - // is not initialized yet. - v := uint64(nanotime()) - for len(r) > 0 { - v ^= 0xa0761d6478bd642f - v *= 0xe7037ed1a0b428db - size := 8 - if len(r) < 8 { - size = len(r) - } - for i := 0; i < size; i++ { - r[i] ^= byte(v >> (8 * i)) - } - r = r[size:] - v = v>>32 | v<<32 - } -} - -// bootstrapRand returns a random uint64 from the global random generator. -func bootstrapRand() uint64 { - lock(&globalRand.lock) - if !globalRand.init { - fatal("randinit missed") - } - for { - if x, ok := globalRand.state.Next(); ok { - unlock(&globalRand.lock) - return x - } - globalRand.state.Refill() - } -} - -// bootstrapRandReseed reseeds the bootstrap random number generator, -// clearing from memory any trace of previously returned random numbers. -func bootstrapRandReseed() { - lock(&globalRand.lock) - if !globalRand.init { - fatal("randinit missed") - } - globalRand.state.Reseed() - unlock(&globalRand.lock) -} - -// rand32 is uint32(rand()), called from compiler-generated code. -//go:nosplit -func rand32() uint32 { - return uint32(rand()) -} - -// rand returns a random uint64 from the per-m chacha8 state. -// Do not change signature: used via linkname from other packages. -//go:nosplit -//go:linkname rand -func rand() uint64 { - // Note: We avoid acquirem here so that in the fast path - // there is just a getg, an inlined c.Next, and a return. - // The performance difference on a 16-core AMD is - // 3.7ns/call this way versus 4.3ns/call with acquirem (+16%). - mp := getg().m - c := &mp.chacha8 - for { - // Note: c.Next is marked nosplit, - // so we don't need to use mp.locks - // on the fast path, which is that the - // first attempt succeeds. - x, ok := c.Next() - if ok { - return x - } - mp.locks++ // hold m even though c.Refill may do stack split checks - c.Refill() - mp.locks-- - } -} - -// mrandinit initializes the random state of an m. -func mrandinit(mp *m) { - var seed [4]uint64 - for i := range seed { - seed[i] = bootstrapRand() - } - bootstrapRandReseed() // erase key we just extracted - mp.chacha8.Init64(seed) - mp.cheaprand = rand() -} - -// randn is like rand() % n but faster. -// Do not change signature: used via linkname from other packages. -//go:nosplit -//go:linkname randn -func randn(n uint32) uint32 { - // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ - return uint32((uint64(uint32(rand())) * uint64(n)) >> 32) -} - -// cheaprand is a non-cryptographic-quality 32-bit random generator -// suitable for calling at very high frequency (such as during scheduling decisions) -// and at sensitive moments in the runtime (such as during stack unwinding). -// it is "cheap" in the sense of both expense and quality. -// -// cheaprand must not be exported to other packages: -// the rule is that other packages using runtime-provided -// randomness must always use rand. -//go:nosplit -func cheaprand() uint32 { - mp := getg().m - // Implement wyrand: https://github.com/wangyi-fudan/wyhash - // Only the platform that math.Mul64 can be lowered - // by the compiler should be in this list. - if goarch.IsAmd64|goarch.IsArm64|goarch.IsPpc64| - goarch.IsPpc64le|goarch.IsMips64|goarch.IsMips64le| - goarch.IsS390x|goarch.IsRiscv64|goarch.IsLoong64 == 1 { - mp.cheaprand += 0xa0761d6478bd642f - hi, lo := math.Mul64(mp.cheaprand, mp.cheaprand^0xe7037ed1a0b428db) - return uint32(hi ^ lo) - } - - // Implement xorshift64+: 2 32-bit xorshift sequences added together. - // Shift triplet [17,7,16] was calculated as indicated in Marsaglia's - // Xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf - // This generator passes the SmallCrush suite, part of TestU01 framework: - // http://simul.iro.umontreal.ca/testu01/tu01.html - t := (*[2]uint32)(unsafe.Pointer(&mp.cheaprand)) - s1, s0 := t[0], t[1] - s1 ^= s1 << 17 - s1 = s1 ^ s0 ^ s1>>7 ^ s0>>16 - t[0], t[1] = s0, s1 - return s0 + s1 -} - -// cheaprand64 is a non-cryptographic-quality 63-bit random generator -// suitable for calling at very high frequency (such as during sampling decisions). -// it is "cheap" in the sense of both expense and quality. -// -// cheaprand64 must not be exported to other packages: -// the rule is that other packages using runtime-provided -// randomness must always use rand. -//go:nosplit -func cheaprand64() int64 { - return int64(cheaprand())<<31 ^ int64(cheaprand()) -} - -// cheaprandn is like cheaprand() % n but faster. -// -// cheaprandn must not be exported to other packages: -// the rule is that other packages using runtime-provided -// randomness must always use randn. -//go:nosplit -func cheaprandn(n uint32) uint32 { - // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ - return uint32((uint64(cheaprand()) * uint64(n)) >> 32) -} - -// Too much legacy code has go:linkname references -// to runtime.fastrand and friends, so keep these around for now. -// Code should migrate to math/rand/v2.Uint64, -// which is just as fast, but that's only available in Go 1.22+. -// It would be reasonable to remove these in Go 1.24. -// Do not call these from package runtime. - -//go:linkname legacy_fastrand runtime.fastrand -func legacy_fastrand() uint32 { - return uint32(rand()) -} - -//go:linkname legacy_fastrandn runtime.fastrandn -func legacy_fastrandn(n uint32) uint32 { - return randn(n) -} - -//go:linkname legacy_fastrand64 runtime.fastrand64 -func legacy_fastrand64() uint64 { - return rand() -} diff --git a/contrib/go/_std_1.22/src/runtime/rt0_aix_ppc64.s b/contrib/go/_std_1.22/src/runtime/rt0_aix_ppc64.s deleted file mode 100644 index 1670a809862a..000000000000 --- a/contrib/go/_std_1.22/src/runtime/rt0_aix_ppc64.s +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "textflag.h" -#include "asm_ppc64x.h" - -// _rt0_ppc64_aix is a function descriptor of the entrypoint function -// __start. This name is needed by cmd/link. -DEFINE_PPC64X_FUNCDESC(_rt0_ppc64_aix, __start<>) - -// The starting function must return in the loader to -// initialise some libraries, especially libthread which -// creates the main thread and adds the TLS in R13 -// R19 contains a function descriptor to the loader function -// which needs to be called. -// This code is similar to the __start function in C -TEXT __start<>(SB),NOSPLIT,$-8 - XOR R0, R0 - MOVD $libc___n_pthreads(SB), R4 - MOVD 0(R4), R4 - MOVD $libc___mod_init(SB), R5 - MOVD 0(R5), R5 - MOVD 0(R19), R0 - MOVD R2, 40(R1) - MOVD 8(R19), R2 - MOVD R18, R3 - MOVD R0, CTR - BL (CTR) // Return to AIX loader - - // Launch rt0_go - MOVD 40(R1), R2 - MOVD R14, R3 // argc - MOVD R15, R4 // argv - BL _main(SB) - - -DEFINE_PPC64X_FUNCDESC(main, _main) -TEXT _main(SB),NOSPLIT,$-8 - MOVD $runtime·rt0_go(SB), R12 - MOVD R12, CTR - BR (CTR) - - -TEXT _rt0_ppc64_aix_lib(SB),NOSPLIT,$-8 - // Start with standard C stack frame layout and linkage. - MOVD LR, R0 - MOVD R0, 16(R1) // Save LR in caller's frame. - MOVW CR, R0 // Save CR in caller's frame - MOVD R0, 8(R1) - - MOVDU R1, -344(R1) // Allocate frame. - - // Preserve callee-save registers. - MOVD R14, 48(R1) - MOVD R15, 56(R1) - MOVD R16, 64(R1) - MOVD R17, 72(R1) - MOVD R18, 80(R1) - MOVD R19, 88(R1) - MOVD R20, 96(R1) - MOVD R21,104(R1) - MOVD R22, 112(R1) - MOVD R23, 120(R1) - MOVD R24, 128(R1) - MOVD R25, 136(R1) - MOVD R26, 144(R1) - MOVD R27, 152(R1) - MOVD R28, 160(R1) - MOVD R29, 168(R1) - MOVD g, 176(R1) // R30 - MOVD R31, 184(R1) - FMOVD F14, 192(R1) - FMOVD F15, 200(R1) - FMOVD F16, 208(R1) - FMOVD F17, 216(R1) - FMOVD F18, 224(R1) - FMOVD F19, 232(R1) - FMOVD F20, 240(R1) - FMOVD F21, 248(R1) - FMOVD F22, 256(R1) - FMOVD F23, 264(R1) - FMOVD F24, 272(R1) - FMOVD F25, 280(R1) - FMOVD F26, 288(R1) - FMOVD F27, 296(R1) - FMOVD F28, 304(R1) - FMOVD F29, 312(R1) - FMOVD F30, 320(R1) - FMOVD F31, 328(R1) - - // Synchronous initialization. - MOVD $runtime·reginit(SB), R12 - MOVD R12, CTR - BL (CTR) - - MOVBZ runtime·isarchive(SB), R3 // Check buildmode = c-archive - CMP $0, R3 - BEQ done - - MOVD R14, _rt0_ppc64_aix_lib_argc<>(SB) - MOVD R15, _rt0_ppc64_aix_lib_argv<>(SB) - - MOVD $runtime·libpreinit(SB), R12 - MOVD R12, CTR - BL (CTR) - - // Create a new thread to do the runtime initialization and return. - MOVD _cgo_sys_thread_create(SB), R12 - CMP $0, R12 - BEQ nocgo - MOVD $_rt0_ppc64_aix_lib_go(SB), R3 - MOVD $0, R4 - MOVD R2, 40(R1) - MOVD 8(R12), R2 - MOVD (R12), R12 - MOVD R12, CTR - BL (CTR) - MOVD 40(R1), R2 - BR done - -nocgo: - MOVD $0x800000, R12 // stacksize = 8192KB - MOVD R12, 8(R1) - MOVD $_rt0_ppc64_aix_lib_go(SB), R12 - MOVD R12, 16(R1) - MOVD $runtime·newosproc0(SB),R12 - MOVD R12, CTR - BL (CTR) - -done: - // Restore saved registers. - MOVD 48(R1), R14 - MOVD 56(R1), R15 - MOVD 64(R1), R16 - MOVD 72(R1), R17 - MOVD 80(R1), R18 - MOVD 88(R1), R19 - MOVD 96(R1), R20 - MOVD 104(R1), R21 - MOVD 112(R1), R22 - MOVD 120(R1), R23 - MOVD 128(R1), R24 - MOVD 136(R1), R25 - MOVD 144(R1), R26 - MOVD 152(R1), R27 - MOVD 160(R1), R28 - MOVD 168(R1), R29 - MOVD 176(R1), g // R30 - MOVD 184(R1), R31 - FMOVD 196(R1), F14 - FMOVD 200(R1), F15 - FMOVD 208(R1), F16 - FMOVD 216(R1), F17 - FMOVD 224(R1), F18 - FMOVD 232(R1), F19 - FMOVD 240(R1), F20 - FMOVD 248(R1), F21 - FMOVD 256(R1), F22 - FMOVD 264(R1), F23 - FMOVD 272(R1), F24 - FMOVD 280(R1), F25 - FMOVD 288(R1), F26 - FMOVD 296(R1), F27 - FMOVD 304(R1), F28 - FMOVD 312(R1), F29 - FMOVD 320(R1), F30 - FMOVD 328(R1), F31 - - ADD $344, R1 - - MOVD 8(R1), R0 - MOVFL R0, $0xff - MOVD 16(R1), R0 - MOVD R0, LR - RET - -DEFINE_PPC64X_FUNCDESC(_rt0_ppc64_aix_lib_go, __rt0_ppc64_aix_lib_go) - -TEXT __rt0_ppc64_aix_lib_go(SB),NOSPLIT,$0 - MOVD _rt0_ppc64_aix_lib_argc<>(SB), R3 - MOVD _rt0_ppc64_aix_lib_argv<>(SB), R4 - MOVD $runtime·rt0_go(SB), R12 - MOVD R12, CTR - BR (CTR) - -DATA _rt0_ppc64_aix_lib_argc<>(SB)/8, $0 -GLOBL _rt0_ppc64_aix_lib_argc<>(SB),NOPTR, $8 -DATA _rt0_ppc64_aix_lib_argv<>(SB)/8, $0 -GLOBL _rt0_ppc64_aix_lib_argv<>(SB),NOPTR, $8 diff --git a/contrib/go/_std_1.22/src/runtime/runtime.go b/contrib/go/_std_1.22/src/runtime/runtime.go deleted file mode 100644 index c70a76e40905..000000000000 --- a/contrib/go/_std_1.22/src/runtime/runtime.go +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "runtime/internal/atomic" - "unsafe" -) - -//go:generate go run wincallback.go -//go:generate go run mkduff.go -//go:generate go run mkfastlog2table.go -//go:generate go run mklockrank.go -o lockrank.go - -var ticks ticksType - -type ticksType struct { - // lock protects access to start* and val. - lock mutex - startTicks int64 - startTime int64 - val atomic.Int64 -} - -// init initializes ticks to maximize the chance that we have a good ticksPerSecond reference. -// -// Must not run concurrently with ticksPerSecond. -func (t *ticksType) init() { - lock(&ticks.lock) - t.startTime = nanotime() - t.startTicks = cputicks() - unlock(&ticks.lock) -} - -// minTimeForTicksPerSecond is the minimum elapsed time we require to consider our ticksPerSecond -// measurement to be of decent enough quality for profiling. -// -// There's a linear relationship here between minimum time and error from the true value. -// The error from the true ticks-per-second in a linux/amd64 VM seems to be: -// - 1 ms -> ~0.02% error -// - 5 ms -> ~0.004% error -// - 10 ms -> ~0.002% error -// - 50 ms -> ~0.0003% error -// - 100 ms -> ~0.0001% error -// -// We're willing to take 0.004% error here, because ticksPerSecond is intended to be used for -// converting durations, not timestamps. Durations are usually going to be much larger, and so -// the tiny error doesn't matter. The error is definitely going to be a problem when trying to -// use this for timestamps, as it'll make those timestamps much less likely to line up. -const minTimeForTicksPerSecond = 5_000_000*(1-osHasLowResClockInt) + 100_000_000*osHasLowResClockInt - -// ticksPerSecond returns a conversion rate between the cputicks clock and the nanotime clock. -// -// Note: Clocks are hard. Using this as an actual conversion rate for timestamps is ill-advised -// and should be avoided when possible. Use only for durations, where a tiny error term isn't going -// to make a meaningful difference in even a 1ms duration. If an accurate timestamp is needed, -// use nanotime instead. (The entire Windows platform is a broad exception to this rule, where nanotime -// produces timestamps on such a coarse granularity that the error from this conversion is actually -// preferable.) -// -// The strategy for computing the conversion rate is to write down nanotime and cputicks as -// early in process startup as possible. From then, we just need to wait until we get values -// from nanotime that we can use (some platforms have a really coarse system time granularity). -// We require some amount of time to pass to ensure that the conversion rate is fairly accurate -// in aggregate. But because we compute this rate lazily, there's a pretty good chance a decent -// amount of time has passed by the time we get here. -// -// Must be called from a normal goroutine context (running regular goroutine with a P). -// -// Called by runtime/pprof in addition to runtime code. -// -// TODO(mknyszek): This doesn't account for things like CPU frequency scaling. Consider -// a more sophisticated and general approach in the future. -func ticksPerSecond() int64 { - // Get the conversion rate if we've already computed it. - r := ticks.val.Load() - if r != 0 { - return r - } - - // Compute the conversion rate. - for { - lock(&ticks.lock) - r = ticks.val.Load() - if r != 0 { - unlock(&ticks.lock) - return r - } - - // Grab the current time in both clocks. - nowTime := nanotime() - nowTicks := cputicks() - - // See if we can use these times. - if nowTicks > ticks.startTicks && nowTime-ticks.startTime > minTimeForTicksPerSecond { - // Perform the calculation with floats. We don't want to risk overflow. - r = int64(float64(nowTicks-ticks.startTicks) * 1e9 / float64(nowTime-ticks.startTime)) - if r == 0 { - // Zero is both a sentinel value and it would be bad if callers used this as - // a divisor. We tried out best, so just make it 1. - r++ - } - ticks.val.Store(r) - unlock(&ticks.lock) - break - } - unlock(&ticks.lock) - - // Sleep in one millisecond increments until we have a reliable time. - timeSleep(1_000_000) - } - return r -} - -var envs []string -var argslice []string - -//go:linkname syscall_runtime_envs syscall.runtime_envs -func syscall_runtime_envs() []string { return append([]string{}, envs...) } - -//go:linkname syscall_Getpagesize syscall.Getpagesize -func syscall_Getpagesize() int { return int(physPageSize) } - -//go:linkname os_runtime_args os.runtime_args -func os_runtime_args() []string { return append([]string{}, argslice...) } - -//go:linkname syscall_Exit syscall.Exit -//go:nosplit -func syscall_Exit(code int) { - exit(int32(code)) -} - -var godebugDefault string -var godebugUpdate atomic.Pointer[func(string, string)] -var godebugEnv atomic.Pointer[string] // set by parsedebugvars -var godebugNewIncNonDefault atomic.Pointer[func(string) func()] - -//go:linkname godebug_setUpdate internal/godebug.setUpdate -func godebug_setUpdate(update func(string, string)) { - p := new(func(string, string)) - *p = update - godebugUpdate.Store(p) - godebugNotify(false) -} - -//go:linkname godebug_setNewIncNonDefault internal/godebug.setNewIncNonDefault -func godebug_setNewIncNonDefault(newIncNonDefault func(string) func()) { - p := new(func(string) func()) - *p = newIncNonDefault - godebugNewIncNonDefault.Store(p) -} - -// A godebugInc provides access to internal/godebug's IncNonDefault function -// for a given GODEBUG setting. -// Calls before internal/godebug registers itself are dropped on the floor. -type godebugInc struct { - name string - inc atomic.Pointer[func()] -} - -func (g *godebugInc) IncNonDefault() { - inc := g.inc.Load() - if inc == nil { - newInc := godebugNewIncNonDefault.Load() - if newInc == nil { - return - } - inc = new(func()) - *inc = (*newInc)(g.name) - if raceenabled { - racereleasemerge(unsafe.Pointer(&g.inc)) - } - if !g.inc.CompareAndSwap(nil, inc) { - inc = g.inc.Load() - } - } - if raceenabled { - raceacquire(unsafe.Pointer(&g.inc)) - } - (*inc)() -} - -func godebugNotify(envChanged bool) { - update := godebugUpdate.Load() - var env string - if p := godebugEnv.Load(); p != nil { - env = *p - } - if envChanged { - reparsedebugvars(env) - } - if update != nil { - (*update)(godebugDefault, env) - } -} - -//go:linkname syscall_runtimeSetenv syscall.runtimeSetenv -func syscall_runtimeSetenv(key, value string) { - setenv_c(key, value) - if key == "GODEBUG" { - p := new(string) - *p = value - godebugEnv.Store(p) - godebugNotify(true) - } -} - -//go:linkname syscall_runtimeUnsetenv syscall.runtimeUnsetenv -func syscall_runtimeUnsetenv(key string) { - unsetenv_c(key) - if key == "GODEBUG" { - godebugEnv.Store(nil) - godebugNotify(true) - } -} - -// writeErrStr writes a string to descriptor 2. -// -//go:nosplit -func writeErrStr(s string) { - write(2, unsafe.Pointer(unsafe.StringData(s)), int32(len(s))) -} - -// auxv is populated on relevant platforms but defined here for all platforms -// so x/sys/cpu can assume the getAuxv symbol exists without keeping its list -// of auxv-using GOOS build tags in sync. -// -// It contains an even number of elements, (tag, value) pairs. -var auxv []uintptr - -func getAuxv() []uintptr { return auxv } // accessed from x/sys/cpu; see issue 57336 diff --git a/contrib/go/_std_1.22/src/runtime/rwmutex.go b/contrib/go/_std_1.22/src/runtime/rwmutex.go deleted file mode 100644 index 34d8f675c179..000000000000 --- a/contrib/go/_std_1.22/src/runtime/rwmutex.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "runtime/internal/atomic" -) - -// This is a copy of sync/rwmutex.go rewritten to work in the runtime. - -// A rwmutex is a reader/writer mutual exclusion lock. -// The lock can be held by an arbitrary number of readers or a single writer. -// This is a variant of sync.RWMutex, for the runtime package. -// Like mutex, rwmutex blocks the calling M. -// It does not interact with the goroutine scheduler. -type rwmutex struct { - rLock mutex // protects readers, readerPass, writer - readers muintptr // list of pending readers - readerPass uint32 // number of pending readers to skip readers list - - wLock mutex // serializes writers - writer muintptr // pending writer waiting for completing readers - - readerCount atomic.Int32 // number of pending readers - readerWait atomic.Int32 // number of departing readers - - readRank lockRank // semantic lock rank for read locking -} - -// Lock ranking an rwmutex has two aspects: -// -// Semantic ranking: this rwmutex represents some higher level lock that -// protects some resource (e.g., allocmLock protects creation of new Ms). The -// read and write locks of that resource need to be represented in the lock -// rank. -// -// Internal ranking: as an implementation detail, rwmutex uses two mutexes: -// rLock and wLock. These have lock order requirements: wLock must be locked -// before rLock. This also needs to be represented in the lock rank. -// -// Semantic ranking is represented by acquiring readRank during read lock and -// writeRank during write lock. -// -// wLock is held for the duration of a write lock, so it uses writeRank -// directly, both for semantic and internal ranking. rLock is only held -// temporarily inside the rlock/lock methods, so it uses readRankInternal to -// represent internal ranking. Semantic ranking is represented by a separate -// acquire of readRank for the duration of a read lock. -// -// The lock ranking must document this ordering: -// - readRankInternal is a leaf lock. -// - readRank is taken before readRankInternal. -// - writeRank is taken before readRankInternal. -// - readRank is placed in the lock order wherever a read lock of this rwmutex -// belongs. -// - writeRank is placed in the lock order wherever a write lock of this -// rwmutex belongs. -func (rw *rwmutex) init(readRank, readRankInternal, writeRank lockRank) { - rw.readRank = readRank - - lockInit(&rw.rLock, readRankInternal) - lockInit(&rw.wLock, writeRank) -} - -const rwmutexMaxReaders = 1 << 30 - -// rlock locks rw for reading. -func (rw *rwmutex) rlock() { - // The reader must not be allowed to lose its P or else other - // things blocking on the lock may consume all of the Ps and - // deadlock (issue #20903). Alternatively, we could drop the P - // while sleeping. - acquirem() - - acquireLockRank(rw.readRank) - lockWithRankMayAcquire(&rw.rLock, getLockRank(&rw.rLock)) - - if rw.readerCount.Add(1) < 0 { - // A writer is pending. Park on the reader queue. - systemstack(func() { - lock(&rw.rLock) - if rw.readerPass > 0 { - // Writer finished. - rw.readerPass -= 1 - unlock(&rw.rLock) - } else { - // Queue this reader to be woken by - // the writer. - m := getg().m - m.schedlink = rw.readers - rw.readers.set(m) - unlock(&rw.rLock) - notesleep(&m.park) - noteclear(&m.park) - } - }) - } -} - -// runlock undoes a single rlock call on rw. -func (rw *rwmutex) runlock() { - if r := rw.readerCount.Add(-1); r < 0 { - if r+1 == 0 || r+1 == -rwmutexMaxReaders { - throw("runlock of unlocked rwmutex") - } - // A writer is pending. - if rw.readerWait.Add(-1) == 0 { - // The last reader unblocks the writer. - lock(&rw.rLock) - w := rw.writer.ptr() - if w != nil { - notewakeup(&w.park) - } - unlock(&rw.rLock) - } - } - releaseLockRank(rw.readRank) - releasem(getg().m) -} - -// lock locks rw for writing. -func (rw *rwmutex) lock() { - // Resolve competition with other writers and stick to our P. - lock(&rw.wLock) - m := getg().m - // Announce that there is a pending writer. - r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders - // Wait for any active readers to complete. - lock(&rw.rLock) - if r != 0 && rw.readerWait.Add(r) != 0 { - // Wait for reader to wake us up. - systemstack(func() { - rw.writer.set(m) - unlock(&rw.rLock) - notesleep(&m.park) - noteclear(&m.park) - }) - } else { - unlock(&rw.rLock) - } -} - -// unlock unlocks rw for writing. -func (rw *rwmutex) unlock() { - // Announce to readers that there is no active writer. - r := rw.readerCount.Add(rwmutexMaxReaders) - if r >= rwmutexMaxReaders { - throw("unlock of unlocked rwmutex") - } - // Unblock blocked readers. - lock(&rw.rLock) - for rw.readers.ptr() != nil { - reader := rw.readers.ptr() - rw.readers = reader.schedlink - reader.schedlink.set(nil) - notewakeup(&reader.park) - r -= 1 - } - // If r > 0, there are pending readers that aren't on the - // queue. Tell them to skip waiting. - rw.readerPass += uint32(r) - unlock(&rw.rLock) - // Allow other writers to proceed. - unlock(&rw.wLock) -} diff --git a/contrib/go/_std_1.22/src/runtime/slice.go b/contrib/go/_std_1.22/src/runtime/slice.go deleted file mode 100644 index eb628bb1694c..000000000000 --- a/contrib/go/_std_1.22/src/runtime/slice.go +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "runtime/internal/math" - "runtime/internal/sys" - "unsafe" -) - -type slice struct { - array unsafe.Pointer - len int - cap int -} - -// A notInHeapSlice is a slice backed by runtime/internal/sys.NotInHeap memory. -type notInHeapSlice struct { - array *notInHeap - len int - cap int -} - -func panicmakeslicelen() { - panic(errorString("makeslice: len out of range")) -} - -func panicmakeslicecap() { - panic(errorString("makeslice: cap out of range")) -} - -// makeslicecopy allocates a slice of "tolen" elements of type "et", -// then copies "fromlen" elements of type "et" into that new allocation from "from". -func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer { - var tomem, copymem uintptr - if uintptr(tolen) > uintptr(fromlen) { - var overflow bool - tomem, overflow = math.MulUintptr(et.Size_, uintptr(tolen)) - if overflow || tomem > maxAlloc || tolen < 0 { - panicmakeslicelen() - } - copymem = et.Size_ * uintptr(fromlen) - } else { - // fromlen is a known good length providing and equal or greater than tolen, - // thereby making tolen a good slice length too as from and to slices have the - // same element width. - tomem = et.Size_ * uintptr(tolen) - copymem = tomem - } - - var to unsafe.Pointer - if et.PtrBytes == 0 { - to = mallocgc(tomem, nil, false) - if copymem < tomem { - memclrNoHeapPointers(add(to, copymem), tomem-copymem) - } - } else { - // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. - to = mallocgc(tomem, et, true) - if copymem > 0 && writeBarrier.enabled { - // Only shade the pointers in old.array since we know the destination slice to - // only contains nil pointers because it has been cleared during alloc. - // - // It's safe to pass a type to this function as an optimization because - // from and to only ever refer to memory representing whole values of - // type et. See the comment on bulkBarrierPreWrite. - bulkBarrierPreWriteSrcOnly(uintptr(to), uintptr(from), copymem, et) - } - } - - if raceenabled { - callerpc := getcallerpc() - pc := abi.FuncPCABIInternal(makeslicecopy) - racereadrangepc(from, copymem, callerpc, pc) - } - if msanenabled { - msanread(from, copymem) - } - if asanenabled { - asanread(from, copymem) - } - - memmove(to, from, copymem) - - return to -} - -func makeslice(et *_type, len, cap int) unsafe.Pointer { - mem, overflow := math.MulUintptr(et.Size_, uintptr(cap)) - if overflow || mem > maxAlloc || len < 0 || len > cap { - // NOTE: Produce a 'len out of range' error instead of a - // 'cap out of range' error when someone does make([]T, bignumber). - // 'cap out of range' is true too, but since the cap is only being - // supplied implicitly, saying len is clearer. - // See golang.org/issue/4085. - mem, overflow := math.MulUintptr(et.Size_, uintptr(len)) - if overflow || mem > maxAlloc || len < 0 { - panicmakeslicelen() - } - panicmakeslicecap() - } - - return mallocgc(mem, et, true) -} - -func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer { - len := int(len64) - if int64(len) != len64 { - panicmakeslicelen() - } - - cap := int(cap64) - if int64(cap) != cap64 { - panicmakeslicecap() - } - - return makeslice(et, len, cap) -} - -// growslice allocates new backing store for a slice. -// -// arguments: -// -// oldPtr = pointer to the slice's backing array -// newLen = new length (= oldLen + num) -// oldCap = original slice's capacity. -// num = number of elements being added -// et = element type -// -// return values: -// -// newPtr = pointer to the new backing store -// newLen = same value as the argument -// newCap = capacity of the new backing store -// -// Requires that uint(newLen) > uint(oldCap). -// Assumes the original slice length is newLen - num -// -// A new backing store is allocated with space for at least newLen elements. -// Existing entries [0, oldLen) are copied over to the new backing store. -// Added entries [oldLen, newLen) are not initialized by growslice -// (although for pointer-containing element types, they are zeroed). They -// must be initialized by the caller. -// Trailing entries [newLen, newCap) are zeroed. -// -// growslice's odd calling convention makes the generated code that calls -// this function simpler. In particular, it accepts and returns the -// new length so that the old length is not live (does not need to be -// spilled/restored) and the new length is returned (also does not need -// to be spilled/restored). -func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice { - oldLen := newLen - num - if raceenabled { - callerpc := getcallerpc() - racereadrangepc(oldPtr, uintptr(oldLen*int(et.Size_)), callerpc, abi.FuncPCABIInternal(growslice)) - } - if msanenabled { - msanread(oldPtr, uintptr(oldLen*int(et.Size_))) - } - if asanenabled { - asanread(oldPtr, uintptr(oldLen*int(et.Size_))) - } - - if newLen < 0 { - panic(errorString("growslice: len out of range")) - } - - if et.Size_ == 0 { - // append should not create a slice with nil pointer but non-zero len. - // We assume that append doesn't need to preserve oldPtr in this case. - return slice{unsafe.Pointer(&zerobase), newLen, newLen} - } - - newcap := nextslicecap(newLen, oldCap) - - var overflow bool - var lenmem, newlenmem, capmem uintptr - // Specialize for common values of et.Size. - // For 1 we don't need any division/multiplication. - // For goarch.PtrSize, compiler will optimize division/multiplication into a shift by a constant. - // For powers of 2, use a variable shift. - noscan := et.PtrBytes == 0 - switch { - case et.Size_ == 1: - lenmem = uintptr(oldLen) - newlenmem = uintptr(newLen) - capmem = roundupsize(uintptr(newcap), noscan) - overflow = uintptr(newcap) > maxAlloc - newcap = int(capmem) - case et.Size_ == goarch.PtrSize: - lenmem = uintptr(oldLen) * goarch.PtrSize - newlenmem = uintptr(newLen) * goarch.PtrSize - capmem = roundupsize(uintptr(newcap)*goarch.PtrSize, noscan) - overflow = uintptr(newcap) > maxAlloc/goarch.PtrSize - newcap = int(capmem / goarch.PtrSize) - case isPowerOfTwo(et.Size_): - var shift uintptr - if goarch.PtrSize == 8 { - // Mask shift for better code generation. - shift = uintptr(sys.TrailingZeros64(uint64(et.Size_))) & 63 - } else { - shift = uintptr(sys.TrailingZeros32(uint32(et.Size_))) & 31 - } - lenmem = uintptr(oldLen) << shift - newlenmem = uintptr(newLen) << shift - capmem = roundupsize(uintptr(newcap)< (maxAlloc >> shift) - newcap = int(capmem >> shift) - capmem = uintptr(newcap) << shift - default: - lenmem = uintptr(oldLen) * et.Size_ - newlenmem = uintptr(newLen) * et.Size_ - capmem, overflow = math.MulUintptr(et.Size_, uintptr(newcap)) - capmem = roundupsize(capmem, noscan) - newcap = int(capmem / et.Size_) - capmem = uintptr(newcap) * et.Size_ - } - - // The check of overflow in addition to capmem > maxAlloc is needed - // to prevent an overflow which can be used to trigger a segfault - // on 32bit architectures with this example program: - // - // type T [1<<27 + 1]int64 - // - // var d T - // var s []T - // - // func main() { - // s = append(s, d, d, d, d) - // print(len(s), "\n") - // } - if overflow || capmem > maxAlloc { - panic(errorString("growslice: len out of range")) - } - - var p unsafe.Pointer - if et.PtrBytes == 0 { - p = mallocgc(capmem, nil, false) - // The append() that calls growslice is going to overwrite from oldLen to newLen. - // Only clear the part that will not be overwritten. - // The reflect_growslice() that calls growslice will manually clear - // the region not cleared here. - memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem) - } else { - // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. - p = mallocgc(capmem, et, true) - if lenmem > 0 && writeBarrier.enabled { - // Only shade the pointers in oldPtr since we know the destination slice p - // only contains nil pointers because it has been cleared during alloc. - // - // It's safe to pass a type to this function as an optimization because - // from and to only ever refer to memory representing whole values of - // type et. See the comment on bulkBarrierPreWrite. - bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(oldPtr), lenmem-et.Size_+et.PtrBytes, et) - } - } - memmove(p, oldPtr, lenmem) - - return slice{p, newLen, newcap} -} - -// nextslicecap computes the next appropriate slice length. -func nextslicecap(newLen, oldCap int) int { - newcap := oldCap - doublecap := newcap + newcap - if newLen > doublecap { - return newLen - } - - const threshold = 256 - if oldCap < threshold { - return doublecap - } - for { - // Transition from growing 2x for small slices - // to growing 1.25x for large slices. This formula - // gives a smooth-ish transition between the two. - newcap += (newcap + 3*threshold) >> 2 - - // We need to check `newcap >= newLen` and whether `newcap` overflowed. - // newLen is guaranteed to be larger than zero, hence - // when newcap overflows then `uint(newcap) > uint(newLen)`. - // This allows to check for both with the same comparison. - if uint(newcap) >= uint(newLen) { - break - } - } - - // Set newcap to the requested cap when - // the newcap calculation overflowed. - if newcap <= 0 { - return newLen - } - return newcap -} - -//go:linkname reflect_growslice reflect.growslice -func reflect_growslice(et *_type, old slice, num int) slice { - // Semantically equivalent to slices.Grow, except that the caller - // is responsible for ensuring that old.len+num > old.cap. - num -= old.cap - old.len // preserve memory of old[old.len:old.cap] - new := growslice(old.array, old.cap+num, old.cap, num, et) - // growslice does not zero out new[old.cap:new.len] since it assumes that - // the memory will be overwritten by an append() that called growslice. - // Since the caller of reflect_growslice is not append(), - // zero out this region before returning the slice to the reflect package. - if et.PtrBytes == 0 { - oldcapmem := uintptr(old.cap) * et.Size_ - newlenmem := uintptr(new.len) * et.Size_ - memclrNoHeapPointers(add(new.array, oldcapmem), newlenmem-oldcapmem) - } - new.len = old.len // preserve the old length - return new -} - -func isPowerOfTwo(x uintptr) bool { - return x&(x-1) == 0 -} - -// slicecopy is used to copy from a string or slice of pointerless elements into a slice. -func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int { - if fromLen == 0 || toLen == 0 { - return 0 - } - - n := fromLen - if toLen < n { - n = toLen - } - - if width == 0 { - return n - } - - size := uintptr(n) * width - if raceenabled { - callerpc := getcallerpc() - pc := abi.FuncPCABIInternal(slicecopy) - racereadrangepc(fromPtr, size, callerpc, pc) - racewriterangepc(toPtr, size, callerpc, pc) - } - if msanenabled { - msanread(fromPtr, size) - msanwrite(toPtr, size) - } - if asanenabled { - asanread(fromPtr, size) - asanwrite(toPtr, size) - } - - if size == 1 { // common case worth about 2x to do here - // TODO: is this still worth it with new memmove impl? - *(*byte)(toPtr) = *(*byte)(fromPtr) // known to be a byte pointer - } else { - memmove(toPtr, fromPtr, size) - } - return n -} - -//go:linkname bytealg_MakeNoZero internal/bytealg.MakeNoZero -func bytealg_MakeNoZero(len int) []byte { - if uintptr(len) > maxAlloc { - panicmakeslicelen() - } - return unsafe.Slice((*byte)(mallocgc(uintptr(len), nil, false)), len) -} diff --git a/contrib/go/_std_1.22/src/runtime/stack.go b/contrib/go/_std_1.22/src/runtime/stack.go deleted file mode 100644 index 61cd0a0fddd6..000000000000 --- a/contrib/go/_std_1.22/src/runtime/stack.go +++ /dev/null @@ -1,1343 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/abi" - "internal/cpu" - "internal/goarch" - "internal/goos" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -/* -Stack layout parameters. -Included both by runtime (compiled via 6c) and linkers (compiled via gcc). - -The per-goroutine g->stackguard is set to point StackGuard bytes -above the bottom of the stack. Each function compares its stack -pointer against g->stackguard to check for overflow. To cut one -instruction from the check sequence for functions with tiny frames, -the stack is allowed to protrude StackSmall bytes below the stack -guard. Functions with large frames don't bother with the check and -always call morestack. The sequences are (for amd64, others are -similar): - - guard = g->stackguard - frame = function's stack frame size - argsize = size of function arguments (call + return) - - stack frame size <= StackSmall: - CMPQ guard, SP - JHI 3(PC) - MOVQ m->morearg, $(argsize << 32) - CALL morestack(SB) - - stack frame size > StackSmall but < StackBig - LEAQ (frame-StackSmall)(SP), R0 - CMPQ guard, R0 - JHI 3(PC) - MOVQ m->morearg, $(argsize << 32) - CALL morestack(SB) - - stack frame size >= StackBig: - MOVQ m->morearg, $((argsize << 32) | frame) - CALL morestack(SB) - -The bottom StackGuard - StackSmall bytes are important: there has -to be enough room to execute functions that refuse to check for -stack overflow, either because they need to be adjacent to the -actual caller's frame (deferproc) or because they handle the imminent -stack overflow (morestack). - -For example, deferproc might call malloc, which does one of the -above checks (without allocating a full frame), which might trigger -a call to morestack. This sequence needs to fit in the bottom -section of the stack. On amd64, morestack's frame is 40 bytes, and -deferproc's frame is 56 bytes. That fits well within the -StackGuard - StackSmall bytes at the bottom. -The linkers explore all possible call traces involving non-splitting -functions to make sure that this limit cannot be violated. -*/ - -const ( - // stackSystem is a number of additional bytes to add - // to each stack below the usual guard area for OS-specific - // purposes like signal handling. Used on Windows, Plan 9, - // and iOS because they do not use a separate stack. - stackSystem = goos.IsWindows*512*goarch.PtrSize + goos.IsPlan9*512 + goos.IsIos*goarch.IsArm64*1024 - - // The minimum size of stack used by Go code - stackMin = 2048 - - // The minimum stack size to allocate. - // The hackery here rounds fixedStack0 up to a power of 2. - fixedStack0 = stackMin + stackSystem - fixedStack1 = fixedStack0 - 1 - fixedStack2 = fixedStack1 | (fixedStack1 >> 1) - fixedStack3 = fixedStack2 | (fixedStack2 >> 2) - fixedStack4 = fixedStack3 | (fixedStack3 >> 4) - fixedStack5 = fixedStack4 | (fixedStack4 >> 8) - fixedStack6 = fixedStack5 | (fixedStack5 >> 16) - fixedStack = fixedStack6 + 1 - - // stackNosplit is the maximum number of bytes that a chain of NOSPLIT - // functions can use. - // This arithmetic must match that in cmd/internal/objabi/stack.go:StackNosplit. - stackNosplit = abi.StackNosplitBase * sys.StackGuardMultiplier - - // The stack guard is a pointer this many bytes above the - // bottom of the stack. - // - // The guard leaves enough room for a stackNosplit chain of NOSPLIT calls - // plus one stackSmall frame plus stackSystem bytes for the OS. - // This arithmetic must match that in cmd/internal/objabi/stack.go:StackLimit. - stackGuard = stackNosplit + stackSystem + abi.StackSmall -) - -const ( - // stackDebug == 0: no logging - // == 1: logging of per-stack operations - // == 2: logging of per-frame operations - // == 3: logging of per-word updates - // == 4: logging of per-word reads - stackDebug = 0 - stackFromSystem = 0 // allocate stacks from system memory instead of the heap - stackFaultOnFree = 0 // old stacks are mapped noaccess to detect use after free - stackNoCache = 0 // disable per-P small stack caches - - // check the BP links during traceback. - debugCheckBP = false -) - -var ( - stackPoisonCopy = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy -) - -const ( - uintptrMask = 1<<(8*goarch.PtrSize) - 1 - - // The values below can be stored to g.stackguard0 to force - // the next stack check to fail. - // These are all larger than any real SP. - - // Goroutine preemption request. - // 0xfffffade in hex. - stackPreempt = uintptrMask & -1314 - - // Thread is forking. Causes a split stack check failure. - // 0xfffffb2e in hex. - stackFork = uintptrMask & -1234 - - // Force a stack movement. Used for debugging. - // 0xfffffeed in hex. - stackForceMove = uintptrMask & -275 - - // stackPoisonMin is the lowest allowed stack poison value. - stackPoisonMin = uintptrMask & -4096 -) - -// Global pool of spans that have free stacks. -// Stacks are assigned an order according to size. -// -// order = log_2(size/FixedStack) -// -// There is a free list for each order. -var stackpool [_NumStackOrders]struct { - item stackpoolItem - _ [(cpu.CacheLinePadSize - unsafe.Sizeof(stackpoolItem{})%cpu.CacheLinePadSize) % cpu.CacheLinePadSize]byte -} - -type stackpoolItem struct { - _ sys.NotInHeap - mu mutex - span mSpanList -} - -// Global pool of large stack spans. -var stackLarge struct { - lock mutex - free [heapAddrBits - pageShift]mSpanList // free lists by log_2(s.npages) -} - -func stackinit() { - if _StackCacheSize&_PageMask != 0 { - throw("cache size must be a multiple of page size") - } - for i := range stackpool { - stackpool[i].item.span.init() - lockInit(&stackpool[i].item.mu, lockRankStackpool) - } - for i := range stackLarge.free { - stackLarge.free[i].init() - lockInit(&stackLarge.lock, lockRankStackLarge) - } -} - -// stacklog2 returns ⌊log_2(n)⌋. -func stacklog2(n uintptr) int { - log2 := 0 - for n > 1 { - n >>= 1 - log2++ - } - return log2 -} - -// Allocates a stack from the free pool. Must be called with -// stackpool[order].item.mu held. -func stackpoolalloc(order uint8) gclinkptr { - list := &stackpool[order].item.span - s := list.first - lockWithRankMayAcquire(&mheap_.lock, lockRankMheap) - if s == nil { - // no free stacks. Allocate another span worth. - s = mheap_.allocManual(_StackCacheSize>>_PageShift, spanAllocStack) - if s == nil { - throw("out of memory") - } - if s.allocCount != 0 { - throw("bad allocCount") - } - if s.manualFreeList.ptr() != nil { - throw("bad manualFreeList") - } - osStackAlloc(s) - s.elemsize = fixedStack << order - for i := uintptr(0); i < _StackCacheSize; i += s.elemsize { - x := gclinkptr(s.base() + i) - x.ptr().next = s.manualFreeList - s.manualFreeList = x - } - list.insert(s) - } - x := s.manualFreeList - if x.ptr() == nil { - throw("span has no free stacks") - } - s.manualFreeList = x.ptr().next - s.allocCount++ - if s.manualFreeList.ptr() == nil { - // all stacks in s are allocated. - list.remove(s) - } - return x -} - -// Adds stack x to the free pool. Must be called with stackpool[order].item.mu held. -func stackpoolfree(x gclinkptr, order uint8) { - s := spanOfUnchecked(uintptr(x)) - if s.state.get() != mSpanManual { - throw("freeing stack not in a stack span") - } - if s.manualFreeList.ptr() == nil { - // s will now have a free stack - stackpool[order].item.span.insert(s) - } - x.ptr().next = s.manualFreeList - s.manualFreeList = x - s.allocCount-- - if gcphase == _GCoff && s.allocCount == 0 { - // Span is completely free. Return it to the heap - // immediately if we're sweeping. - // - // If GC is active, we delay the free until the end of - // GC to avoid the following type of situation: - // - // 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer - // 2) The stack that pointer points to is copied - // 3) The old stack is freed - // 4) The containing span is marked free - // 5) GC attempts to mark the SudoG.elem pointer. The - // marking fails because the pointer looks like a - // pointer into a free span. - // - // By not freeing, we prevent step #4 until GC is done. - stackpool[order].item.span.remove(s) - s.manualFreeList = 0 - osStackFree(s) - mheap_.freeManual(s, spanAllocStack) - } -} - -// stackcacherefill/stackcacherelease implement a global pool of stack segments. -// The pool is required to prevent unlimited growth of per-thread caches. -// -//go:systemstack -func stackcacherefill(c *mcache, order uint8) { - if stackDebug >= 1 { - print("stackcacherefill order=", order, "\n") - } - - // Grab some stacks from the global cache. - // Grab half of the allowed capacity (to prevent thrashing). - var list gclinkptr - var size uintptr - lock(&stackpool[order].item.mu) - for size < _StackCacheSize/2 { - x := stackpoolalloc(order) - x.ptr().next = list - list = x - size += fixedStack << order - } - unlock(&stackpool[order].item.mu) - c.stackcache[order].list = list - c.stackcache[order].size = size -} - -//go:systemstack -func stackcacherelease(c *mcache, order uint8) { - if stackDebug >= 1 { - print("stackcacherelease order=", order, "\n") - } - x := c.stackcache[order].list - size := c.stackcache[order].size - lock(&stackpool[order].item.mu) - for size > _StackCacheSize/2 { - y := x.ptr().next - stackpoolfree(x, order) - x = y - size -= fixedStack << order - } - unlock(&stackpool[order].item.mu) - c.stackcache[order].list = x - c.stackcache[order].size = size -} - -//go:systemstack -func stackcache_clear(c *mcache) { - if stackDebug >= 1 { - print("stackcache clear\n") - } - for order := uint8(0); order < _NumStackOrders; order++ { - lock(&stackpool[order].item.mu) - x := c.stackcache[order].list - for x.ptr() != nil { - y := x.ptr().next - stackpoolfree(x, order) - x = y - } - c.stackcache[order].list = 0 - c.stackcache[order].size = 0 - unlock(&stackpool[order].item.mu) - } -} - -// stackalloc allocates an n byte stack. -// -// stackalloc must run on the system stack because it uses per-P -// resources and must not split the stack. -// -//go:systemstack -func stackalloc(n uint32) stack { - // Stackalloc must be called on scheduler stack, so that we - // never try to grow the stack during the code that stackalloc runs. - // Doing so would cause a deadlock (issue 1547). - thisg := getg() - if thisg != thisg.m.g0 { - throw("stackalloc not on scheduler stack") - } - if n&(n-1) != 0 { - throw("stack size not a power of 2") - } - if stackDebug >= 1 { - print("stackalloc ", n, "\n") - } - - if debug.efence != 0 || stackFromSystem != 0 { - n = uint32(alignUp(uintptr(n), physPageSize)) - v := sysAlloc(uintptr(n), &memstats.stacks_sys) - if v == nil { - throw("out of memory (stackalloc)") - } - return stack{uintptr(v), uintptr(v) + uintptr(n)} - } - - // Small stacks are allocated with a fixed-size free-list allocator. - // If we need a stack of a bigger size, we fall back on allocating - // a dedicated span. - var v unsafe.Pointer - if n < fixedStack<<_NumStackOrders && n < _StackCacheSize { - order := uint8(0) - n2 := n - for n2 > fixedStack { - order++ - n2 >>= 1 - } - var x gclinkptr - if stackNoCache != 0 || thisg.m.p == 0 || thisg.m.preemptoff != "" { - // thisg.m.p == 0 can happen in the guts of exitsyscall - // or procresize. Just get a stack from the global pool. - // Also don't touch stackcache during gc - // as it's flushed concurrently. - lock(&stackpool[order].item.mu) - x = stackpoolalloc(order) - unlock(&stackpool[order].item.mu) - } else { - c := thisg.m.p.ptr().mcache - x = c.stackcache[order].list - if x.ptr() == nil { - stackcacherefill(c, order) - x = c.stackcache[order].list - } - c.stackcache[order].list = x.ptr().next - c.stackcache[order].size -= uintptr(n) - } - v = unsafe.Pointer(x) - } else { - var s *mspan - npage := uintptr(n) >> _PageShift - log2npage := stacklog2(npage) - - // Try to get a stack from the large stack cache. - lock(&stackLarge.lock) - if !stackLarge.free[log2npage].isEmpty() { - s = stackLarge.free[log2npage].first - stackLarge.free[log2npage].remove(s) - } - unlock(&stackLarge.lock) - - lockWithRankMayAcquire(&mheap_.lock, lockRankMheap) - - if s == nil { - // Allocate a new stack from the heap. - s = mheap_.allocManual(npage, spanAllocStack) - if s == nil { - throw("out of memory") - } - osStackAlloc(s) - s.elemsize = uintptr(n) - } - v = unsafe.Pointer(s.base()) - } - - if raceenabled { - racemalloc(v, uintptr(n)) - } - if msanenabled { - msanmalloc(v, uintptr(n)) - } - if asanenabled { - asanunpoison(v, uintptr(n)) - } - if stackDebug >= 1 { - print(" allocated ", v, "\n") - } - return stack{uintptr(v), uintptr(v) + uintptr(n)} -} - -// stackfree frees an n byte stack allocation at stk. -// -// stackfree must run on the system stack because it uses per-P -// resources and must not split the stack. -// -//go:systemstack -func stackfree(stk stack) { - gp := getg() - v := unsafe.Pointer(stk.lo) - n := stk.hi - stk.lo - if n&(n-1) != 0 { - throw("stack not a power of 2") - } - if stk.lo+n < stk.hi { - throw("bad stack size") - } - if stackDebug >= 1 { - println("stackfree", v, n) - memclrNoHeapPointers(v, n) // for testing, clobber stack data - } - if debug.efence != 0 || stackFromSystem != 0 { - if debug.efence != 0 || stackFaultOnFree != 0 { - sysFault(v, n) - } else { - sysFree(v, n, &memstats.stacks_sys) - } - return - } - if msanenabled { - msanfree(v, n) - } - if asanenabled { - asanpoison(v, n) - } - if n < fixedStack<<_NumStackOrders && n < _StackCacheSize { - order := uint8(0) - n2 := n - for n2 > fixedStack { - order++ - n2 >>= 1 - } - x := gclinkptr(v) - if stackNoCache != 0 || gp.m.p == 0 || gp.m.preemptoff != "" { - lock(&stackpool[order].item.mu) - stackpoolfree(x, order) - unlock(&stackpool[order].item.mu) - } else { - c := gp.m.p.ptr().mcache - if c.stackcache[order].size >= _StackCacheSize { - stackcacherelease(c, order) - } - x.ptr().next = c.stackcache[order].list - c.stackcache[order].list = x - c.stackcache[order].size += n - } - } else { - s := spanOfUnchecked(uintptr(v)) - if s.state.get() != mSpanManual { - println(hex(s.base()), v) - throw("bad span state") - } - if gcphase == _GCoff { - // Free the stack immediately if we're - // sweeping. - osStackFree(s) - mheap_.freeManual(s, spanAllocStack) - } else { - // If the GC is running, we can't return a - // stack span to the heap because it could be - // reused as a heap span, and this state - // change would race with GC. Add it to the - // large stack cache instead. - log2npage := stacklog2(s.npages) - lock(&stackLarge.lock) - stackLarge.free[log2npage].insert(s) - unlock(&stackLarge.lock) - } - } -} - -var maxstacksize uintptr = 1 << 20 // enough until runtime.main sets it for real - -var maxstackceiling = maxstacksize - -var ptrnames = []string{ - 0: "scalar", - 1: "ptr", -} - -// Stack frame layout -// -// (x86) -// +------------------+ -// | args from caller | -// +------------------+ <- frame->argp -// | return address | -// +------------------+ -// | caller's BP (*) | (*) if framepointer_enabled && varp > sp -// +------------------+ <- frame->varp -// | locals | -// +------------------+ -// | args to callee | -// +------------------+ <- frame->sp -// -// (arm) -// +------------------+ -// | args from caller | -// +------------------+ <- frame->argp -// | caller's retaddr | -// +------------------+ -// | caller's FP (*) | (*) on ARM64, if framepointer_enabled && varp > sp -// +------------------+ <- frame->varp -// | locals | -// +------------------+ -// | args to callee | -// +------------------+ -// | return address | -// +------------------+ <- frame->sp -// -// varp > sp means that the function has a frame; -// varp == sp means frameless function. - -type adjustinfo struct { - old stack - delta uintptr // ptr distance from old to new stack (newbase - oldbase) - - // sghi is the highest sudog.elem on the stack. - sghi uintptr -} - -// adjustpointer checks whether *vpp is in the old stack described by adjinfo. -// If so, it rewrites *vpp to point into the new stack. -func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) { - pp := (*uintptr)(vpp) - p := *pp - if stackDebug >= 4 { - print(" ", pp, ":", hex(p), "\n") - } - if adjinfo.old.lo <= p && p < adjinfo.old.hi { - *pp = p + adjinfo.delta - if stackDebug >= 3 { - print(" adjust ptr ", pp, ":", hex(p), " -> ", hex(*pp), "\n") - } - } -} - -// Information from the compiler about the layout of stack frames. -// Note: this type must agree with reflect.bitVector. -type bitvector struct { - n int32 // # of bits - bytedata *uint8 -} - -// ptrbit returns the i'th bit in bv. -// ptrbit is less efficient than iterating directly over bitvector bits, -// and should only be used in non-performance-critical code. -// See adjustpointers for an example of a high-efficiency walk of a bitvector. -func (bv *bitvector) ptrbit(i uintptr) uint8 { - b := *(addb(bv.bytedata, i/8)) - return (b >> (i % 8)) & 1 -} - -// bv describes the memory starting at address scanp. -// Adjust any pointers contained therein. -func adjustpointers(scanp unsafe.Pointer, bv *bitvector, adjinfo *adjustinfo, f funcInfo) { - minp := adjinfo.old.lo - maxp := adjinfo.old.hi - delta := adjinfo.delta - num := uintptr(bv.n) - // If this frame might contain channel receive slots, use CAS - // to adjust pointers. If the slot hasn't been received into - // yet, it may contain stack pointers and a concurrent send - // could race with adjusting those pointers. (The sent value - // itself can never contain stack pointers.) - useCAS := uintptr(scanp) < adjinfo.sghi - for i := uintptr(0); i < num; i += 8 { - if stackDebug >= 4 { - for j := uintptr(0); j < 8; j++ { - print(" ", add(scanp, (i+j)*goarch.PtrSize), ":", ptrnames[bv.ptrbit(i+j)], ":", hex(*(*uintptr)(add(scanp, (i+j)*goarch.PtrSize))), " # ", i, " ", *addb(bv.bytedata, i/8), "\n") - } - } - b := *(addb(bv.bytedata, i/8)) - for b != 0 { - j := uintptr(sys.TrailingZeros8(b)) - b &= b - 1 - pp := (*uintptr)(add(scanp, (i+j)*goarch.PtrSize)) - retry: - p := *pp - if f.valid() && 0 < p && p < minLegalPointer && debug.invalidptr != 0 { - // Looks like a junk value in a pointer slot. - // Live analysis wrong? - getg().m.traceback = 2 - print("runtime: bad pointer in frame ", funcname(f), " at ", pp, ": ", hex(p), "\n") - throw("invalid pointer found on stack") - } - if minp <= p && p < maxp { - if stackDebug >= 3 { - print("adjust ptr ", hex(p), " ", funcname(f), "\n") - } - if useCAS { - ppu := (*unsafe.Pointer)(unsafe.Pointer(pp)) - if !atomic.Casp1(ppu, unsafe.Pointer(p), unsafe.Pointer(p+delta)) { - goto retry - } - } else { - *pp = p + delta - } - } - } - } -} - -// Note: the argument/return area is adjusted by the callee. -func adjustframe(frame *stkframe, adjinfo *adjustinfo) { - if frame.continpc == 0 { - // Frame is dead. - return - } - f := frame.fn - if stackDebug >= 2 { - print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n") - } - - // Adjust saved frame pointer if there is one. - if (goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.ARM64) && frame.argp-frame.varp == 2*goarch.PtrSize { - if stackDebug >= 3 { - print(" saved bp\n") - } - if debugCheckBP { - // Frame pointers should always point to the next higher frame on - // the Go stack (or be nil, for the top frame on the stack). - bp := *(*uintptr)(unsafe.Pointer(frame.varp)) - if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) { - println("runtime: found invalid frame pointer") - print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n") - throw("bad frame pointer") - } - } - // On AMD64, this is the caller's frame pointer saved in the current - // frame. - // On ARM64, this is the frame pointer of the caller's caller saved - // by the caller in its frame (one word below its SP). - adjustpointer(adjinfo, unsafe.Pointer(frame.varp)) - } - - locals, args, objs := frame.getStackMap(true) - - // Adjust local variables if stack frame has been allocated. - if locals.n > 0 { - size := uintptr(locals.n) * goarch.PtrSize - adjustpointers(unsafe.Pointer(frame.varp-size), &locals, adjinfo, f) - } - - // Adjust arguments. - if args.n > 0 { - if stackDebug >= 3 { - print(" args\n") - } - adjustpointers(unsafe.Pointer(frame.argp), &args, adjinfo, funcInfo{}) - } - - // Adjust pointers in all stack objects (whether they are live or not). - // See comments in mgcmark.go:scanframeworker. - if frame.varp != 0 { - for i := range objs { - obj := &objs[i] - off := obj.off - base := frame.varp // locals base pointer - if off >= 0 { - base = frame.argp // arguments and return values base pointer - } - p := base + uintptr(off) - if p < frame.sp { - // Object hasn't been allocated in the frame yet. - // (Happens when the stack bounds check fails and - // we call into morestack.) - continue - } - ptrdata := obj.ptrdata() - gcdata := obj.gcdata() - var s *mspan - if obj.useGCProg() { - // See comments in mgcmark.go:scanstack - s = materializeGCProg(ptrdata, gcdata) - gcdata = (*byte)(unsafe.Pointer(s.startAddr)) - } - for i := uintptr(0); i < ptrdata; i += goarch.PtrSize { - if *addb(gcdata, i/(8*goarch.PtrSize))>>(i/goarch.PtrSize&7)&1 != 0 { - adjustpointer(adjinfo, unsafe.Pointer(p+i)) - } - } - if s != nil { - dematerializeGCProg(s) - } - } - } -} - -func adjustctxt(gp *g, adjinfo *adjustinfo) { - adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.ctxt)) - if !framepointer_enabled { - return - } - if debugCheckBP { - bp := gp.sched.bp - if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) { - println("runtime: found invalid top frame pointer") - print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n") - throw("bad top frame pointer") - } - } - oldfp := gp.sched.bp - adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.bp)) - if GOARCH == "arm64" { - // On ARM64, the frame pointer is saved one word *below* the SP, - // which is not copied or adjusted in any frame. Do it explicitly - // here. - if oldfp == gp.sched.sp-goarch.PtrSize { - memmove(unsafe.Pointer(gp.sched.bp), unsafe.Pointer(oldfp), goarch.PtrSize) - adjustpointer(adjinfo, unsafe.Pointer(gp.sched.bp)) - } - } -} - -func adjustdefers(gp *g, adjinfo *adjustinfo) { - // Adjust pointers in the Defer structs. - // We need to do this first because we need to adjust the - // defer.link fields so we always work on the new stack. - adjustpointer(adjinfo, unsafe.Pointer(&gp._defer)) - for d := gp._defer; d != nil; d = d.link { - adjustpointer(adjinfo, unsafe.Pointer(&d.fn)) - adjustpointer(adjinfo, unsafe.Pointer(&d.sp)) - adjustpointer(adjinfo, unsafe.Pointer(&d.link)) - } -} - -func adjustpanics(gp *g, adjinfo *adjustinfo) { - // Panics are on stack and already adjusted. - // Update pointer to head of list in G. - adjustpointer(adjinfo, unsafe.Pointer(&gp._panic)) -} - -func adjustsudogs(gp *g, adjinfo *adjustinfo) { - // the data elements pointed to by a SudoG structure - // might be in the stack. - for s := gp.waiting; s != nil; s = s.waitlink { - adjustpointer(adjinfo, unsafe.Pointer(&s.elem)) - } -} - -func fillstack(stk stack, b byte) { - for p := stk.lo; p < stk.hi; p++ { - *(*byte)(unsafe.Pointer(p)) = b - } -} - -func findsghi(gp *g, stk stack) uintptr { - var sghi uintptr - for sg := gp.waiting; sg != nil; sg = sg.waitlink { - p := uintptr(sg.elem) + uintptr(sg.c.elemsize) - if stk.lo <= p && p < stk.hi && p > sghi { - sghi = p - } - } - return sghi -} - -// syncadjustsudogs adjusts gp's sudogs and copies the part of gp's -// stack they refer to while synchronizing with concurrent channel -// operations. It returns the number of bytes of stack copied. -func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr { - if gp.waiting == nil { - return 0 - } - - // Lock channels to prevent concurrent send/receive. - var lastc *hchan - for sg := gp.waiting; sg != nil; sg = sg.waitlink { - if sg.c != lastc { - // There is a ranking cycle here between gscan bit and - // hchan locks. Normally, we only allow acquiring hchan - // locks and then getting a gscan bit. In this case, we - // already have the gscan bit. We allow acquiring hchan - // locks here as a special case, since a deadlock can't - // happen because the G involved must already be - // suspended. So, we get a special hchan lock rank here - // that is lower than gscan, but doesn't allow acquiring - // any other locks other than hchan. - lockWithRank(&sg.c.lock, lockRankHchanLeaf) - } - lastc = sg.c - } - - // Adjust sudogs. - adjustsudogs(gp, adjinfo) - - // Copy the part of the stack the sudogs point in to - // while holding the lock to prevent races on - // send/receive slots. - var sgsize uintptr - if adjinfo.sghi != 0 { - oldBot := adjinfo.old.hi - used - newBot := oldBot + adjinfo.delta - sgsize = adjinfo.sghi - oldBot - memmove(unsafe.Pointer(newBot), unsafe.Pointer(oldBot), sgsize) - } - - // Unlock channels. - lastc = nil - for sg := gp.waiting; sg != nil; sg = sg.waitlink { - if sg.c != lastc { - unlock(&sg.c.lock) - } - lastc = sg.c - } - - return sgsize -} - -// Copies gp's stack to a new stack of a different size. -// Caller must have changed gp status to Gcopystack. -func copystack(gp *g, newsize uintptr) { - if gp.syscallsp != 0 { - throw("stack growth not allowed in system call") - } - old := gp.stack - if old.lo == 0 { - throw("nil stackbase") - } - used := old.hi - gp.sched.sp - // Add just the difference to gcController.addScannableStack. - // g0 stacks never move, so this will never account for them. - // It's also fine if we have no P, addScannableStack can deal with - // that case. - gcController.addScannableStack(getg().m.p.ptr(), int64(newsize)-int64(old.hi-old.lo)) - - // allocate new stack - new := stackalloc(uint32(newsize)) - if stackPoisonCopy != 0 { - fillstack(new, 0xfd) - } - if stackDebug >= 1 { - print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]", " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n") - } - - // Compute adjustment. - var adjinfo adjustinfo - adjinfo.old = old - adjinfo.delta = new.hi - old.hi - - // Adjust sudogs, synchronizing with channel ops if necessary. - ncopy := used - if !gp.activeStackChans { - if newsize < old.hi-old.lo && gp.parkingOnChan.Load() { - // It's not safe for someone to shrink this stack while we're actively - // parking on a channel, but it is safe to grow since we do that - // ourselves and explicitly don't want to synchronize with channels - // since we could self-deadlock. - throw("racy sudog adjustment due to parking on channel") - } - adjustsudogs(gp, &adjinfo) - } else { - // sudogs may be pointing in to the stack and gp has - // released channel locks, so other goroutines could - // be writing to gp's stack. Find the highest such - // pointer so we can handle everything there and below - // carefully. (This shouldn't be far from the bottom - // of the stack, so there's little cost in handling - // everything below it carefully.) - adjinfo.sghi = findsghi(gp, old) - - // Synchronize with channel ops and copy the part of - // the stack they may interact with. - ncopy -= syncadjustsudogs(gp, used, &adjinfo) - } - - // Copy the stack (or the rest of it) to the new location - memmove(unsafe.Pointer(new.hi-ncopy), unsafe.Pointer(old.hi-ncopy), ncopy) - - // Adjust remaining structures that have pointers into stacks. - // We have to do most of these before we traceback the new - // stack because gentraceback uses them. - adjustctxt(gp, &adjinfo) - adjustdefers(gp, &adjinfo) - adjustpanics(gp, &adjinfo) - if adjinfo.sghi != 0 { - adjinfo.sghi += adjinfo.delta - } - - // Swap out old stack for new one - gp.stack = new - gp.stackguard0 = new.lo + stackGuard // NOTE: might clobber a preempt request - gp.sched.sp = new.hi - used - gp.stktopsp += adjinfo.delta - - // Adjust pointers in the new stack. - var u unwinder - for u.init(gp, 0); u.valid(); u.next() { - adjustframe(&u.frame, &adjinfo) - } - - // free old stack - if stackPoisonCopy != 0 { - fillstack(old, 0xfc) - } - stackfree(old) -} - -// round x up to a power of 2. -func round2(x int32) int32 { - s := uint(0) - for 1<atomicstatus will be Grunning or Gscanrunning upon entry. -// If the scheduler is trying to stop this g, then it will set preemptStop. -// -// This must be nowritebarrierrec because it can be called as part of -// stack growth from other nowritebarrierrec functions, but the -// compiler doesn't check this. -// -//go:nowritebarrierrec -func newstack() { - thisg := getg() - // TODO: double check all gp. shouldn't be getg(). - if thisg.m.morebuf.g.ptr().stackguard0 == stackFork { - throw("stack growth after fork") - } - if thisg.m.morebuf.g.ptr() != thisg.m.curg { - print("runtime: newstack called from g=", hex(thisg.m.morebuf.g), "\n"+"\tm=", thisg.m, " m->curg=", thisg.m.curg, " m->g0=", thisg.m.g0, " m->gsignal=", thisg.m.gsignal, "\n") - morebuf := thisg.m.morebuf - traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g.ptr()) - throw("runtime: wrong goroutine in newstack") - } - - gp := thisg.m.curg - - if thisg.m.curg.throwsplit { - // Update syscallsp, syscallpc in case traceback uses them. - morebuf := thisg.m.morebuf - gp.syscallsp = morebuf.sp - gp.syscallpc = morebuf.pc - pcname, pcoff := "(unknown)", uintptr(0) - f := findfunc(gp.sched.pc) - if f.valid() { - pcname = funcname(f) - pcoff = gp.sched.pc - f.entry() - } - print("runtime: newstack at ", pcname, "+", hex(pcoff), - " sp=", hex(gp.sched.sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n", - "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n", - "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n") - - thisg.m.traceback = 2 // Include runtime frames - traceback(morebuf.pc, morebuf.sp, morebuf.lr, gp) - throw("runtime: stack split at bad time") - } - - morebuf := thisg.m.morebuf - thisg.m.morebuf.pc = 0 - thisg.m.morebuf.lr = 0 - thisg.m.morebuf.sp = 0 - thisg.m.morebuf.g = 0 - - // NOTE: stackguard0 may change underfoot, if another thread - // is about to try to preempt gp. Read it just once and use that same - // value now and below. - stackguard0 := atomic.Loaduintptr(&gp.stackguard0) - - // Be conservative about where we preempt. - // We are interested in preempting user Go code, not runtime code. - // If we're holding locks, mallocing, or preemption is disabled, don't - // preempt. - // This check is very early in newstack so that even the status change - // from Grunning to Gwaiting and back doesn't happen in this case. - // That status change by itself can be viewed as a small preemption, - // because the GC might change Gwaiting to Gscanwaiting, and then - // this goroutine has to wait for the GC to finish before continuing. - // If the GC is in some way dependent on this goroutine (for example, - // it needs a lock held by the goroutine), that small preemption turns - // into a real deadlock. - preempt := stackguard0 == stackPreempt - if preempt { - if !canPreemptM(thisg.m) { - // Let the goroutine keep running for now. - // gp->preempt is set, so it will be preempted next time. - gp.stackguard0 = gp.stack.lo + stackGuard - gogo(&gp.sched) // never return - } - } - - if gp.stack.lo == 0 { - throw("missing stack in newstack") - } - sp := gp.sched.sp - if goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.I386 || goarch.ArchFamily == goarch.WASM { - // The call to morestack cost a word. - sp -= goarch.PtrSize - } - if stackDebug >= 1 || sp < gp.stack.lo { - print("runtime: newstack sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n", - "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n", - "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n") - } - if sp < gp.stack.lo { - print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->status=", hex(readgstatus(gp)), "\n ") - print("runtime: split stack overflow: ", hex(sp), " < ", hex(gp.stack.lo), "\n") - throw("runtime: split stack overflow") - } - - if preempt { - if gp == thisg.m.g0 { - throw("runtime: preempt g0") - } - if thisg.m.p == 0 && thisg.m.locks == 0 { - throw("runtime: g is running but p is not") - } - - if gp.preemptShrink { - // We're at a synchronous safe point now, so - // do the pending stack shrink. - gp.preemptShrink = false - shrinkstack(gp) - } - - if gp.preemptStop { - preemptPark(gp) // never returns - } - - // Act like goroutine called runtime.Gosched. - gopreempt_m(gp) // never return - } - - // Allocate a bigger segment and move the stack. - oldsize := gp.stack.hi - gp.stack.lo - newsize := oldsize * 2 - - // Make sure we grow at least as much as needed to fit the new frame. - // (This is just an optimization - the caller of morestack will - // recheck the bounds on return.) - if f := findfunc(gp.sched.pc); f.valid() { - max := uintptr(funcMaxSPDelta(f)) - needed := max + stackGuard - used := gp.stack.hi - gp.sched.sp - for newsize-used < needed { - newsize *= 2 - } - } - - if stackguard0 == stackForceMove { - // Forced stack movement used for debugging. - // Don't double the stack (or we may quickly run out - // if this is done repeatedly). - newsize = oldsize - } - - if newsize > maxstacksize || newsize > maxstackceiling { - if maxstacksize < maxstackceiling { - print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n") - } else { - print("runtime: goroutine stack exceeds ", maxstackceiling, "-byte limit\n") - } - print("runtime: sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n") - throw("stack overflow") - } - - // The goroutine must be executing in order to call newstack, - // so it must be Grunning (or Gscanrunning). - casgstatus(gp, _Grunning, _Gcopystack) - - // The concurrent GC will not scan the stack while we are doing the copy since - // the gp is in a Gcopystack status. - copystack(gp, newsize) - if stackDebug >= 1 { - print("stack grow done\n") - } - casgstatus(gp, _Gcopystack, _Grunning) - gogo(&gp.sched) -} - -//go:nosplit -func nilfunc() { - *(*uint8)(nil) = 0 -} - -// adjust Gobuf as if it executed a call to fn -// and then stopped before the first instruction in fn. -func gostartcallfn(gobuf *gobuf, fv *funcval) { - var fn unsafe.Pointer - if fv != nil { - fn = unsafe.Pointer(fv.fn) - } else { - fn = unsafe.Pointer(abi.FuncPCABIInternal(nilfunc)) - } - gostartcall(gobuf, fn, unsafe.Pointer(fv)) -} - -// isShrinkStackSafe returns whether it's safe to attempt to shrink -// gp's stack. Shrinking the stack is only safe when we have precise -// pointer maps for all frames on the stack. -func isShrinkStackSafe(gp *g) bool { - // We can't copy the stack if we're in a syscall. - // The syscall might have pointers into the stack and - // often we don't have precise pointer maps for the innermost - // frames. - // - // We also can't copy the stack if we're at an asynchronous - // safe-point because we don't have precise pointer maps for - // all frames. - // - // We also can't *shrink* the stack in the window between the - // goroutine calling gopark to park on a channel and - // gp.activeStackChans being set. - return gp.syscallsp == 0 && !gp.asyncSafePoint && !gp.parkingOnChan.Load() -} - -// Maybe shrink the stack being used by gp. -// -// gp must be stopped and we must own its stack. It may be in -// _Grunning, but only if this is our own user G. -func shrinkstack(gp *g) { - if gp.stack.lo == 0 { - throw("missing stack in shrinkstack") - } - if s := readgstatus(gp); s&_Gscan == 0 { - // We don't own the stack via _Gscan. We could still - // own it if this is our own user G and we're on the - // system stack. - if !(gp == getg().m.curg && getg() != getg().m.curg && s == _Grunning) { - // We don't own the stack. - throw("bad status in shrinkstack") - } - } - if !isShrinkStackSafe(gp) { - throw("shrinkstack at bad time") - } - // Check for self-shrinks while in a libcall. These may have - // pointers into the stack disguised as uintptrs, but these - // code paths should all be nosplit. - if gp == getg().m.curg && gp.m.libcallsp != 0 { - throw("shrinking stack in libcall") - } - - if debug.gcshrinkstackoff > 0 { - return - } - f := findfunc(gp.startpc) - if f.valid() && f.funcID == abi.FuncID_gcBgMarkWorker { - // We're not allowed to shrink the gcBgMarkWorker - // stack (see gcBgMarkWorker for explanation). - return - } - - oldsize := gp.stack.hi - gp.stack.lo - newsize := oldsize / 2 - // Don't shrink the allocation below the minimum-sized stack - // allocation. - if newsize < fixedStack { - return - } - // Compute how much of the stack is currently in use and only - // shrink the stack if gp is using less than a quarter of its - // current stack. The currently used stack includes everything - // down to the SP plus the stack guard space that ensures - // there's room for nosplit functions. - avail := gp.stack.hi - gp.stack.lo - if used := gp.stack.hi - gp.sched.sp + stackNosplit; used >= avail/4 { - return - } - - if stackDebug > 0 { - print("shrinking stack ", oldsize, "->", newsize, "\n") - } - - copystack(gp, newsize) -} - -// freeStackSpans frees unused stack spans at the end of GC. -func freeStackSpans() { - // Scan stack pools for empty stack spans. - for order := range stackpool { - lock(&stackpool[order].item.mu) - list := &stackpool[order].item.span - for s := list.first; s != nil; { - next := s.next - if s.allocCount == 0 { - list.remove(s) - s.manualFreeList = 0 - osStackFree(s) - mheap_.freeManual(s, spanAllocStack) - } - s = next - } - unlock(&stackpool[order].item.mu) - } - - // Free large stack spans. - lock(&stackLarge.lock) - for i := range stackLarge.free { - for s := stackLarge.free[i].first; s != nil; { - next := s.next - stackLarge.free[i].remove(s) - osStackFree(s) - mheap_.freeManual(s, spanAllocStack) - s = next - } - } - unlock(&stackLarge.lock) -} - -// A stackObjectRecord is generated by the compiler for each stack object in a stack frame. -// This record must match the generator code in cmd/compile/internal/liveness/plive.go:emitStackObjects. -type stackObjectRecord struct { - // offset in frame - // if negative, offset from varp - // if non-negative, offset from argp - off int32 - size int32 - _ptrdata int32 // ptrdata, or -ptrdata is GC prog is used - gcdataoff uint32 // offset to gcdata from moduledata.rodata -} - -func (r *stackObjectRecord) useGCProg() bool { - return r._ptrdata < 0 -} - -func (r *stackObjectRecord) ptrdata() uintptr { - x := r._ptrdata - if x < 0 { - return uintptr(-x) - } - return uintptr(x) -} - -// gcdata returns pointer map or GC prog of the type. -func (r *stackObjectRecord) gcdata() *byte { - ptr := uintptr(unsafe.Pointer(r)) - var mod *moduledata - for datap := &firstmoduledata; datap != nil; datap = datap.next { - if datap.gofunc <= ptr && ptr < datap.end { - mod = datap - break - } - } - // If you get a panic here due to a nil mod, - // you may have made a copy of a stackObjectRecord. - // You must use the original pointer. - res := mod.rodata + uintptr(r.gcdataoff) - return (*byte)(unsafe.Pointer(res)) -} - -// This is exported as ABI0 via linkname so obj can call it. -// -//go:nosplit -//go:linkname morestackc -func morestackc() { - throw("attempt to execute system stack code on user stack") -} - -// startingStackSize is the amount of stack that new goroutines start with. -// It is a power of 2, and between _FixedStack and maxstacksize, inclusive. -// startingStackSize is updated every GC by tracking the average size of -// stacks scanned during the GC. -var startingStackSize uint32 = fixedStack - -func gcComputeStartingStackSize() { - if debug.adaptivestackstart == 0 { - return - } - // For details, see the design doc at - // https://docs.google.com/document/d/1YDlGIdVTPnmUiTAavlZxBI1d9pwGQgZT7IKFKlIXohQ/edit?usp=sharing - // The basic algorithm is to track the average size of stacks - // and start goroutines with stack equal to that average size. - // Starting at the average size uses at most 2x the space that - // an ideal algorithm would have used. - // This is just a heuristic to avoid excessive stack growth work - // early in a goroutine's lifetime. See issue 18138. Stacks that - // are allocated too small can still grow, and stacks allocated - // too large can still shrink. - var scannedStackSize uint64 - var scannedStacks uint64 - for _, p := range allp { - scannedStackSize += p.scannedStackSize - scannedStacks += p.scannedStacks - // Reset for next time - p.scannedStackSize = 0 - p.scannedStacks = 0 - } - if scannedStacks == 0 { - startingStackSize = fixedStack - return - } - avg := scannedStackSize/scannedStacks + stackGuard - // Note: we add stackGuard to ensure that a goroutine that - // uses the average space will not trigger a growth. - if avg > uint64(maxstacksize) { - avg = uint64(maxstacksize) - } - if avg < fixedStack { - avg = fixedStack - } - // Note: maxstacksize fits in 30 bits, so avg also does. - startingStackSize = uint32(round2(int32(avg))) -} diff --git a/contrib/go/_std_1.22/src/runtime/symtab.go b/contrib/go/_std_1.22/src/runtime/symtab.go deleted file mode 100644 index edf800f5198e..000000000000 --- a/contrib/go/_std_1.22/src/runtime/symtab.go +++ /dev/null @@ -1,1160 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -// Frames may be used to get function/file/line information for a -// slice of PC values returned by [Callers]. -type Frames struct { - // callers is a slice of PCs that have not yet been expanded to frames. - callers []uintptr - - // frames is a slice of Frames that have yet to be returned. - frames []Frame - frameStore [2]Frame -} - -// Frame is the information returned by [Frames] for each call frame. -type Frame struct { - // PC is the program counter for the location in this frame. - // For a frame that calls another frame, this will be the - // program counter of a call instruction. Because of inlining, - // multiple frames may have the same PC value, but different - // symbolic information. - PC uintptr - - // Func is the Func value of this call frame. This may be nil - // for non-Go code or fully inlined functions. - Func *Func - - // Function is the package path-qualified function name of - // this call frame. If non-empty, this string uniquely - // identifies a single function in the program. - // This may be the empty string if not known. - // If Func is not nil then Function == Func.Name(). - Function string - - // File and Line are the file name and line number of the - // location in this frame. For non-leaf frames, this will be - // the location of a call. These may be the empty string and - // zero, respectively, if not known. - File string - Line int - - // startLine is the line number of the beginning of the function in - // this frame. Specifically, it is the line number of the func keyword - // for Go functions. Note that //line directives can change the - // filename and/or line number arbitrarily within a function, meaning - // that the Line - startLine offset is not always meaningful. - // - // This may be zero if not known. - startLine int - - // Entry point program counter for the function; may be zero - // if not known. If Func is not nil then Entry == - // Func.Entry(). - Entry uintptr - - // The runtime's internal view of the function. This field - // is set (funcInfo.valid() returns true) only for Go functions, - // not for C functions. - funcInfo funcInfo -} - -// CallersFrames takes a slice of PC values returned by [Callers] and -// prepares to return function/file/line information. -// Do not change the slice until you are done with the [Frames]. -func CallersFrames(callers []uintptr) *Frames { - f := &Frames{callers: callers} - f.frames = f.frameStore[:0] - return f -} - -// Next returns a [Frame] representing the next call frame in the slice -// of PC values. If it has already returned all call frames, Next -// returns a zero [Frame]. -// -// The more result indicates whether the next call to Next will return -// a valid [Frame]. It does not necessarily indicate whether this call -// returned one. -// -// See the [Frames] example for idiomatic usage. -func (ci *Frames) Next() (frame Frame, more bool) { - for len(ci.frames) < 2 { - // Find the next frame. - // We need to look for 2 frames so we know what - // to return for the "more" result. - if len(ci.callers) == 0 { - break - } - pc := ci.callers[0] - ci.callers = ci.callers[1:] - funcInfo := findfunc(pc) - if !funcInfo.valid() { - if cgoSymbolizer != nil { - // Pre-expand cgo frames. We could do this - // incrementally, too, but there's no way to - // avoid allocation in this case anyway. - ci.frames = append(ci.frames, expandCgoFrames(pc)...) - } - continue - } - f := funcInfo._Func() - entry := f.Entry() - if pc > entry { - // We store the pc of the start of the instruction following - // the instruction in question (the call or the inline mark). - // This is done for historical reasons, and to make FuncForPC - // work correctly for entries in the result of runtime.Callers. - pc-- - } - // It's important that interpret pc non-strictly as cgoTraceback may - // have added bogus PCs with a valid funcInfo but invalid PCDATA. - u, uf := newInlineUnwinder(funcInfo, pc) - sf := u.srcFunc(uf) - if u.isInlined(uf) { - // Note: entry is not modified. It always refers to a real frame, not an inlined one. - // File/line from funcline1 below are already correct. - f = nil - } - ci.frames = append(ci.frames, Frame{ - PC: pc, - Func: f, - Function: funcNameForPrint(sf.name()), - Entry: entry, - startLine: int(sf.startLine), - funcInfo: funcInfo, - // Note: File,Line set below - }) - } - - // Pop one frame from the frame list. Keep the rest. - // Avoid allocation in the common case, which is 1 or 2 frames. - switch len(ci.frames) { - case 0: // In the rare case when there are no frames at all, we return Frame{}. - return - case 1: - frame = ci.frames[0] - ci.frames = ci.frameStore[:0] - case 2: - frame = ci.frames[0] - ci.frameStore[0] = ci.frames[1] - ci.frames = ci.frameStore[:1] - default: - frame = ci.frames[0] - ci.frames = ci.frames[1:] - } - more = len(ci.frames) > 0 - if frame.funcInfo.valid() { - // Compute file/line just before we need to return it, - // as it can be expensive. This avoids computing file/line - // for the Frame we find but don't return. See issue 32093. - file, line := funcline1(frame.funcInfo, frame.PC, false) - frame.File, frame.Line = file, int(line) - } - return -} - -// runtime_FrameStartLine returns the start line of the function in a Frame. -// -//go:linkname runtime_FrameStartLine runtime/pprof.runtime_FrameStartLine -func runtime_FrameStartLine(f *Frame) int { - return f.startLine -} - -// runtime_FrameSymbolName returns the full symbol name of the function in a Frame. -// For generic functions this differs from f.Function in that this doesn't replace -// the shape name to "...". -// -//go:linkname runtime_FrameSymbolName runtime/pprof.runtime_FrameSymbolName -func runtime_FrameSymbolName(f *Frame) string { - if !f.funcInfo.valid() { - return f.Function - } - u, uf := newInlineUnwinder(f.funcInfo, f.PC) - sf := u.srcFunc(uf) - return sf.name() -} - -// runtime_expandFinalInlineFrame expands the final pc in stk to include all -// "callers" if pc is inline. -// -//go:linkname runtime_expandFinalInlineFrame runtime/pprof.runtime_expandFinalInlineFrame -func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr { - // TODO: It would be more efficient to report only physical PCs to pprof and - // just expand the whole stack. - if len(stk) == 0 { - return stk - } - pc := stk[len(stk)-1] - tracepc := pc - 1 - - f := findfunc(tracepc) - if !f.valid() { - // Not a Go function. - return stk - } - - u, uf := newInlineUnwinder(f, tracepc) - if !u.isInlined(uf) { - // Nothing inline at tracepc. - return stk - } - - // Treat the previous func as normal. We haven't actually checked, but - // since this pc was included in the stack, we know it shouldn't be - // elided. - calleeID := abi.FuncIDNormal - - // Remove pc from stk; we'll re-add it below. - stk = stk[:len(stk)-1] - - for ; uf.valid(); uf = u.next(uf) { - funcID := u.srcFunc(uf).funcID - if funcID == abi.FuncIDWrapper && elideWrapperCalling(calleeID) { - // ignore wrappers - } else { - stk = append(stk, uf.pc+1) - } - calleeID = funcID - } - - return stk -} - -// expandCgoFrames expands frame information for pc, known to be -// a non-Go function, using the cgoSymbolizer hook. expandCgoFrames -// returns nil if pc could not be expanded. -func expandCgoFrames(pc uintptr) []Frame { - arg := cgoSymbolizerArg{pc: pc} - callCgoSymbolizer(&arg) - - if arg.file == nil && arg.funcName == nil { - // No useful information from symbolizer. - return nil - } - - var frames []Frame - for { - frames = append(frames, Frame{ - PC: pc, - Func: nil, - Function: gostring(arg.funcName), - File: gostring(arg.file), - Line: int(arg.lineno), - Entry: arg.entry, - // funcInfo is zero, which implies !funcInfo.valid(). - // That ensures that we use the File/Line info given here. - }) - if arg.more == 0 { - break - } - callCgoSymbolizer(&arg) - } - - // No more frames for this PC. Tell the symbolizer we are done. - // We don't try to maintain a single cgoSymbolizerArg for the - // whole use of Frames, because there would be no good way to tell - // the symbolizer when we are done. - arg.pc = 0 - callCgoSymbolizer(&arg) - - return frames -} - -// NOTE: Func does not expose the actual unexported fields, because we return *Func -// values to users, and we want to keep them from being able to overwrite the data -// with (say) *f = Func{}. -// All code operating on a *Func must call raw() to get the *_func -// or funcInfo() to get the funcInfo instead. - -// A Func represents a Go function in the running binary. -type Func struct { - opaque struct{} // unexported field to disallow conversions -} - -func (f *Func) raw() *_func { - return (*_func)(unsafe.Pointer(f)) -} - -func (f *Func) funcInfo() funcInfo { - return f.raw().funcInfo() -} - -func (f *_func) funcInfo() funcInfo { - // Find the module containing fn. fn is located in the pclntable. - // The unsafe.Pointer to uintptr conversions and arithmetic - // are safe because we are working with module addresses. - ptr := uintptr(unsafe.Pointer(f)) - var mod *moduledata - for datap := &firstmoduledata; datap != nil; datap = datap.next { - if len(datap.pclntable) == 0 { - continue - } - base := uintptr(unsafe.Pointer(&datap.pclntable[0])) - if base <= ptr && ptr < base+uintptr(len(datap.pclntable)) { - mod = datap - break - } - } - return funcInfo{f, mod} -} - -// pcHeader holds data used by the pclntab lookups. -type pcHeader struct { - magic uint32 // 0xFFFFFFF1 - pad1, pad2 uint8 // 0,0 - minLC uint8 // min instruction size - ptrSize uint8 // size of a ptr in bytes - nfunc int // number of functions in the module - nfiles uint // number of entries in the file tab - textStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text - funcnameOffset uintptr // offset to the funcnametab variable from pcHeader - cuOffset uintptr // offset to the cutab variable from pcHeader - filetabOffset uintptr // offset to the filetab variable from pcHeader - pctabOffset uintptr // offset to the pctab variable from pcHeader - pclnOffset uintptr // offset to the pclntab variable from pcHeader -} - -// moduledata records information about the layout of the executable -// image. It is written by the linker. Any changes here must be -// matched changes to the code in cmd/link/internal/ld/symtab.go:symtab. -// moduledata is stored in statically allocated non-pointer memory; -// none of the pointers here are visible to the garbage collector. -type moduledata struct { - sys.NotInHeap // Only in static data - - pcHeader *pcHeader - funcnametab []byte - cutab []uint32 - filetab []byte - pctab []byte - pclntable []byte - ftab []functab - findfunctab uintptr - minpc, maxpc uintptr - - text, etext uintptr - noptrdata, enoptrdata uintptr - data, edata uintptr - bss, ebss uintptr - noptrbss, enoptrbss uintptr - covctrs, ecovctrs uintptr - end, gcdata, gcbss uintptr - types, etypes uintptr - rodata uintptr - gofunc uintptr // go.func.* - - textsectmap []textsect - typelinks []int32 // offsets from types - itablinks []*itab - - ptab []ptabEntry - - pluginpath string - pkghashes []modulehash - - // This slice records the initializing tasks that need to be - // done to start up the program. It is built by the linker. - inittasks []*initTask - - modulename string - modulehashes []modulehash - - hasmain uint8 // 1 if module contains the main function, 0 otherwise - - gcdatamask, gcbssmask bitvector - - typemap map[typeOff]*_type // offset to *_rtype in previous module - - bad bool // module failed to load and should be ignored - - next *moduledata -} - -// A modulehash is used to compare the ABI of a new module or a -// package in a new module with the loaded program. -// -// For each shared library a module links against, the linker creates an entry in the -// moduledata.modulehashes slice containing the name of the module, the abi hash seen -// at link time and a pointer to the runtime abi hash. These are checked in -// moduledataverify1 below. -// -// For each loaded plugin, the pkghashes slice has a modulehash of the -// newly loaded package that can be used to check the plugin's version of -// a package against any previously loaded version of the package. -// This is done in plugin.lastmoduleinit. -type modulehash struct { - modulename string - linktimehash string - runtimehash *string -} - -// pinnedTypemaps are the map[typeOff]*_type from the moduledata objects. -// -// These typemap objects are allocated at run time on the heap, but the -// only direct reference to them is in the moduledata, created by the -// linker and marked SNOPTRDATA so it is ignored by the GC. -// -// To make sure the map isn't collected, we keep a second reference here. -var pinnedTypemaps []map[typeOff]*_type - -var firstmoduledata moduledata // linker symbol -var lastmoduledatap *moduledata // linker symbol -var modulesSlice *[]*moduledata // see activeModules - -// activeModules returns a slice of active modules. -// -// A module is active once its gcdatamask and gcbssmask have been -// assembled and it is usable by the GC. -// -// This is nosplit/nowritebarrier because it is called by the -// cgo pointer checking code. -// -//go:nosplit -//go:nowritebarrier -func activeModules() []*moduledata { - p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice))) - if p == nil { - return nil - } - return *p -} - -// modulesinit creates the active modules slice out of all loaded modules. -// -// When a module is first loaded by the dynamic linker, an .init_array -// function (written by cmd/link) is invoked to call addmoduledata, -// appending to the module to the linked list that starts with -// firstmoduledata. -// -// There are two times this can happen in the lifecycle of a Go -// program. First, if compiled with -linkshared, a number of modules -// built with -buildmode=shared can be loaded at program initialization. -// Second, a Go program can load a module while running that was built -// with -buildmode=plugin. -// -// After loading, this function is called which initializes the -// moduledata so it is usable by the GC and creates a new activeModules -// list. -// -// Only one goroutine may call modulesinit at a time. -func modulesinit() { - modules := new([]*moduledata) - for md := &firstmoduledata; md != nil; md = md.next { - if md.bad { - continue - } - *modules = append(*modules, md) - if md.gcdatamask == (bitvector{}) { - scanDataSize := md.edata - md.data - md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), scanDataSize) - scanBSSSize := md.ebss - md.bss - md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), scanBSSSize) - gcController.addGlobals(int64(scanDataSize + scanBSSSize)) - } - } - - // Modules appear in the moduledata linked list in the order they are - // loaded by the dynamic loader, with one exception: the - // firstmoduledata itself the module that contains the runtime. This - // is not always the first module (when using -buildmode=shared, it - // is typically libstd.so, the second module). The order matters for - // typelinksinit, so we swap the first module with whatever module - // contains the main function. - // - // See Issue #18729. - for i, md := range *modules { - if md.hasmain != 0 { - (*modules)[0] = md - (*modules)[i] = &firstmoduledata - break - } - } - - atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules)) -} - -type functab struct { - entryoff uint32 // relative to runtime.text - funcoff uint32 -} - -// Mapping information for secondary text sections - -type textsect struct { - vaddr uintptr // prelinked section vaddr - end uintptr // vaddr + section length - baseaddr uintptr // relocated section address -} - -const minfunc = 16 // minimum function size -const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table - -// findfuncbucket is an array of these structures. -// Each bucket represents 4096 bytes of the text segment. -// Each subbucket represents 256 bytes of the text segment. -// To find a function given a pc, locate the bucket and subbucket for -// that pc. Add together the idx and subbucket value to obtain a -// function index. Then scan the functab array starting at that -// index to find the target function. -// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead. -type findfuncbucket struct { - idx uint32 - subbuckets [16]byte -} - -func moduledataverify() { - for datap := &firstmoduledata; datap != nil; datap = datap.next { - moduledataverify1(datap) - } -} - -const debugPcln = false - -func moduledataverify1(datap *moduledata) { - // Check that the pclntab's format is valid. - hdr := datap.pcHeader - if hdr.magic != 0xfffffff1 || hdr.pad1 != 0 || hdr.pad2 != 0 || - hdr.minLC != sys.PCQuantum || hdr.ptrSize != goarch.PtrSize || hdr.textStart != datap.text { - println("runtime: pcHeader: magic=", hex(hdr.magic), "pad1=", hdr.pad1, "pad2=", hdr.pad2, - "minLC=", hdr.minLC, "ptrSize=", hdr.ptrSize, "pcHeader.textStart=", hex(hdr.textStart), - "text=", hex(datap.text), "pluginpath=", datap.pluginpath) - throw("invalid function symbol table") - } - - // ftab is lookup table for function by program counter. - nftab := len(datap.ftab) - 1 - for i := 0; i < nftab; i++ { - // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function. - if datap.ftab[i].entryoff > datap.ftab[i+1].entryoff { - f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap} - f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap} - f2name := "end" - if i+1 < nftab { - f2name = funcname(f2) - } - println("function symbol table not sorted by PC offset:", hex(datap.ftab[i].entryoff), funcname(f1), ">", hex(datap.ftab[i+1].entryoff), f2name, ", plugin:", datap.pluginpath) - for j := 0; j <= i; j++ { - println("\t", hex(datap.ftab[j].entryoff), funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap})) - } - if GOOS == "aix" && isarchive { - println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive") - } - throw("invalid runtime symbol table") - } - } - - min := datap.textAddr(datap.ftab[0].entryoff) - max := datap.textAddr(datap.ftab[nftab].entryoff) - if datap.minpc != min || datap.maxpc != max { - println("minpc=", hex(datap.minpc), "min=", hex(min), "maxpc=", hex(datap.maxpc), "max=", hex(max)) - throw("minpc or maxpc invalid") - } - - for _, modulehash := range datap.modulehashes { - if modulehash.linktimehash != *modulehash.runtimehash { - println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename) - throw("abi mismatch") - } - } -} - -// textAddr returns md.text + off, with special handling for multiple text sections. -// off is a (virtual) offset computed at internal linking time, -// before the external linker adjusts the sections' base addresses. -// -// The text, or instruction stream is generated as one large buffer. -// The off (offset) for a function is its offset within this buffer. -// If the total text size gets too large, there can be issues on platforms like ppc64 -// if the target of calls are too far for the call instruction. -// To resolve the large text issue, the text is split into multiple text sections -// to allow the linker to generate long calls when necessary. -// When this happens, the vaddr for each text section is set to its offset within the text. -// Each function's offset is compared against the section vaddrs and ends to determine the containing section. -// Then the section relative offset is added to the section's -// relocated baseaddr to compute the function address. -// -// It is nosplit because it is part of the findfunc implementation. -// -//go:nosplit -func (md *moduledata) textAddr(off32 uint32) uintptr { - off := uintptr(off32) - res := md.text + off - if len(md.textsectmap) > 1 { - for i, sect := range md.textsectmap { - // For the last section, include the end address (etext), as it is included in the functab. - if off >= sect.vaddr && off < sect.end || (i == len(md.textsectmap)-1 && off == sect.end) { - res = sect.baseaddr + off - sect.vaddr - break - } - } - if res > md.etext && GOARCH != "wasm" { // on wasm, functions do not live in the same address space as the linear memory - println("runtime: textAddr", hex(res), "out of range", hex(md.text), "-", hex(md.etext)) - throw("runtime: text offset out of range") - } - } - return res -} - -// textOff is the opposite of textAddr. It converts a PC to a (virtual) offset -// to md.text, and returns if the PC is in any Go text section. -// -// It is nosplit because it is part of the findfunc implementation. -// -//go:nosplit -func (md *moduledata) textOff(pc uintptr) (uint32, bool) { - res := uint32(pc - md.text) - if len(md.textsectmap) > 1 { - for i, sect := range md.textsectmap { - if sect.baseaddr > pc { - // pc is not in any section. - return 0, false - } - end := sect.baseaddr + (sect.end - sect.vaddr) - // For the last section, include the end address (etext), as it is included in the functab. - if i == len(md.textsectmap)-1 { - end++ - } - if pc < end { - res = uint32(pc - sect.baseaddr + sect.vaddr) - break - } - } - } - return res, true -} - -// funcName returns the string at nameOff in the function name table. -func (md *moduledata) funcName(nameOff int32) string { - if nameOff == 0 { - return "" - } - return gostringnocopy(&md.funcnametab[nameOff]) -} - -// FuncForPC returns a *[Func] describing the function that contains the -// given program counter address, or else nil. -// -// If pc represents multiple functions because of inlining, it returns -// the *Func describing the innermost function, but with an entry of -// the outermost function. -func FuncForPC(pc uintptr) *Func { - f := findfunc(pc) - if !f.valid() { - return nil - } - // This must interpret PC non-strictly so bad PCs (those between functions) don't crash the runtime. - // We just report the preceding function in that situation. See issue 29735. - // TODO: Perhaps we should report no function at all in that case. - // The runtime currently doesn't have function end info, alas. - u, uf := newInlineUnwinder(f, pc) - if !u.isInlined(uf) { - return f._Func() - } - sf := u.srcFunc(uf) - file, line := u.fileLine(uf) - fi := &funcinl{ - ones: ^uint32(0), - entry: f.entry(), // entry of the real (the outermost) function. - name: sf.name(), - file: file, - line: int32(line), - startLine: sf.startLine, - } - return (*Func)(unsafe.Pointer(fi)) -} - -// Name returns the name of the function. -func (f *Func) Name() string { - if f == nil { - return "" - } - fn := f.raw() - if fn.isInlined() { // inlined version - fi := (*funcinl)(unsafe.Pointer(fn)) - return funcNameForPrint(fi.name) - } - return funcNameForPrint(funcname(f.funcInfo())) -} - -// Entry returns the entry address of the function. -func (f *Func) Entry() uintptr { - fn := f.raw() - if fn.isInlined() { // inlined version - fi := (*funcinl)(unsafe.Pointer(fn)) - return fi.entry - } - return fn.funcInfo().entry() -} - -// FileLine returns the file name and line number of the -// source code corresponding to the program counter pc. -// The result will not be accurate if pc is not a program -// counter within f. -func (f *Func) FileLine(pc uintptr) (file string, line int) { - fn := f.raw() - if fn.isInlined() { // inlined version - fi := (*funcinl)(unsafe.Pointer(fn)) - return fi.file, int(fi.line) - } - // Pass strict=false here, because anyone can call this function, - // and they might just be wrong about targetpc belonging to f. - file, line32 := funcline1(f.funcInfo(), pc, false) - return file, int(line32) -} - -// startLine returns the starting line number of the function. i.e., the line -// number of the func keyword. -func (f *Func) startLine() int32 { - fn := f.raw() - if fn.isInlined() { // inlined version - fi := (*funcinl)(unsafe.Pointer(fn)) - return fi.startLine - } - return fn.funcInfo().startLine -} - -// findmoduledatap looks up the moduledata for a PC. -// -// It is nosplit because it's part of the isgoexception -// implementation. -// -//go:nosplit -func findmoduledatap(pc uintptr) *moduledata { - for datap := &firstmoduledata; datap != nil; datap = datap.next { - if datap.minpc <= pc && pc < datap.maxpc { - return datap - } - } - return nil -} - -type funcInfo struct { - *_func - datap *moduledata -} - -func (f funcInfo) valid() bool { - return f._func != nil -} - -func (f funcInfo) _Func() *Func { - return (*Func)(unsafe.Pointer(f._func)) -} - -// isInlined reports whether f should be re-interpreted as a *funcinl. -func (f *_func) isInlined() bool { - return f.entryOff == ^uint32(0) // see comment for funcinl.ones -} - -// entry returns the entry PC for f. -func (f funcInfo) entry() uintptr { - return f.datap.textAddr(f.entryOff) -} - -// findfunc looks up function metadata for a PC. -// -// It is nosplit because it's part of the isgoexception -// implementation. -// -//go:nosplit -func findfunc(pc uintptr) funcInfo { - datap := findmoduledatap(pc) - if datap == nil { - return funcInfo{} - } - const nsub = uintptr(len(findfuncbucket{}.subbuckets)) - - pcOff, ok := datap.textOff(pc) - if !ok { - return funcInfo{} - } - - x := uintptr(pcOff) + datap.text - datap.minpc // TODO: are datap.text and datap.minpc always equal? - b := x / pcbucketsize - i := x % pcbucketsize / (pcbucketsize / nsub) - - ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{}))) - idx := ffb.idx + uint32(ffb.subbuckets[i]) - - // Find the ftab entry. - for datap.ftab[idx+1].entryoff <= pcOff { - idx++ - } - - funcoff := datap.ftab[idx].funcoff - return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap} -} - -// A srcFunc represents a logical function in the source code. This may -// correspond to an actual symbol in the binary text, or it may correspond to a -// source function that has been inlined. -type srcFunc struct { - datap *moduledata - nameOff int32 - startLine int32 - funcID abi.FuncID -} - -func (f funcInfo) srcFunc() srcFunc { - if !f.valid() { - return srcFunc{} - } - return srcFunc{f.datap, f.nameOff, f.startLine, f.funcID} -} - -func (s srcFunc) name() string { - if s.datap == nil { - return "" - } - return s.datap.funcName(s.nameOff) -} - -type pcvalueCache struct { - entries [2][8]pcvalueCacheEnt - inUse int -} - -type pcvalueCacheEnt struct { - // targetpc and off together are the key of this cache entry. - targetpc uintptr - off uint32 - - val int32 // The value of this entry. - valPC uintptr // The PC at which val starts -} - -// pcvalueCacheKey returns the outermost index in a pcvalueCache to use for targetpc. -// It must be very cheap to calculate. -// For now, align to goarch.PtrSize and reduce mod the number of entries. -// In practice, this appears to be fairly randomly and evenly distributed. -func pcvalueCacheKey(targetpc uintptr) uintptr { - return (targetpc / goarch.PtrSize) % uintptr(len(pcvalueCache{}.entries)) -} - -// Returns the PCData value, and the PC where this value starts. -func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uintptr) { - // If true, when we get a cache hit, still look up the data and make sure it - // matches the cached contents. - const debugCheckCache = false - - if off == 0 { - return -1, 0 - } - - // Check the cache. This speeds up walks of deep stacks, which - // tend to have the same recursive functions over and over, - // or repetitive stacks between goroutines. - var checkVal int32 - var checkPC uintptr - ck := pcvalueCacheKey(targetpc) - { - mp := acquirem() - cache := &mp.pcvalueCache - // The cache can be used by the signal handler on this M. Avoid - // re-entrant use of the cache. The signal handler can also write inUse, - // but will always restore its value, so we can use a regular increment - // even if we get signaled in the middle of it. - cache.inUse++ - if cache.inUse == 1 { - for i := range cache.entries[ck] { - // We check off first because we're more - // likely to have multiple entries with - // different offsets for the same targetpc - // than the other way around, so we'll usually - // fail in the first clause. - ent := &cache.entries[ck][i] - if ent.off == off && ent.targetpc == targetpc { - val, pc := ent.val, ent.valPC - if debugCheckCache { - checkVal, checkPC = ent.val, ent.valPC - break - } else { - cache.inUse-- - releasem(mp) - return val, pc - } - } - } - } else if debugCheckCache && (cache.inUse < 1 || cache.inUse > 2) { - // Catch accounting errors or deeply reentrant use. In principle - // "inUse" should never exceed 2. - throw("cache.inUse out of range") - } - cache.inUse-- - releasem(mp) - } - - if !f.valid() { - if strict && panicking.Load() == 0 { - println("runtime: no module data for", hex(f.entry())) - throw("no module data") - } - return -1, 0 - } - datap := f.datap - p := datap.pctab[off:] - pc := f.entry() - prevpc := pc - val := int32(-1) - for { - var ok bool - p, ok = step(p, &pc, &val, pc == f.entry()) - if !ok { - break - } - if targetpc < pc { - // Replace a random entry in the cache. Random - // replacement prevents a performance cliff if - // a recursive stack's cycle is slightly - // larger than the cache. - // Put the new element at the beginning, - // since it is the most likely to be newly used. - if debugCheckCache && checkPC != 0 { - if checkVal != val || checkPC != prevpc { - print("runtime: table value ", val, "@", prevpc, " != cache value ", checkVal, "@", checkPC, " at PC ", targetpc, " off ", off, "\n") - throw("bad pcvalue cache") - } - } else { - mp := acquirem() - cache := &mp.pcvalueCache - cache.inUse++ - if cache.inUse == 1 { - e := &cache.entries[ck] - ci := cheaprandn(uint32(len(cache.entries[ck]))) - e[ci] = e[0] - e[0] = pcvalueCacheEnt{ - targetpc: targetpc, - off: off, - val: val, - valPC: prevpc, - } - } - cache.inUse-- - releasem(mp) - } - - return val, prevpc - } - prevpc = pc - } - - // If there was a table, it should have covered all program counters. - // If not, something is wrong. - if panicking.Load() != 0 || !strict { - return -1, 0 - } - - print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n") - - p = datap.pctab[off:] - pc = f.entry() - val = -1 - for { - var ok bool - p, ok = step(p, &pc, &val, pc == f.entry()) - if !ok { - break - } - print("\tvalue=", val, " until pc=", hex(pc), "\n") - } - - throw("invalid runtime symbol table") - return -1, 0 -} - -func funcname(f funcInfo) string { - if !f.valid() { - return "" - } - return f.datap.funcName(f.nameOff) -} - -func funcpkgpath(f funcInfo) string { - name := funcNameForPrint(funcname(f)) - i := len(name) - 1 - for ; i > 0; i-- { - if name[i] == '/' { - break - } - } - for ; i < len(name); i++ { - if name[i] == '.' { - break - } - } - return name[:i] -} - -func funcfile(f funcInfo, fileno int32) string { - datap := f.datap - if !f.valid() { - return "?" - } - // Make sure the cu index and file offset are valid - if fileoff := datap.cutab[f.cuOffset+uint32(fileno)]; fileoff != ^uint32(0) { - return gostringnocopy(&datap.filetab[fileoff]) - } - // pcln section is corrupt. - return "?" -} - -func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) { - datap := f.datap - if !f.valid() { - return "?", 0 - } - fileno, _ := pcvalue(f, f.pcfile, targetpc, strict) - line, _ = pcvalue(f, f.pcln, targetpc, strict) - if fileno == -1 || line == -1 || int(fileno) >= len(datap.filetab) { - // print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n") - return "?", 0 - } - file = funcfile(f, fileno) - return -} - -func funcline(f funcInfo, targetpc uintptr) (file string, line int32) { - return funcline1(f, targetpc, true) -} - -func funcspdelta(f funcInfo, targetpc uintptr) int32 { - x, _ := pcvalue(f, f.pcsp, targetpc, true) - if debugPcln && x&(goarch.PtrSize-1) != 0 { - print("invalid spdelta ", funcname(f), " ", hex(f.entry()), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n") - throw("bad spdelta") - } - return x -} - -// funcMaxSPDelta returns the maximum spdelta at any point in f. -func funcMaxSPDelta(f funcInfo) int32 { - datap := f.datap - p := datap.pctab[f.pcsp:] - pc := f.entry() - val := int32(-1) - most := int32(0) - for { - var ok bool - p, ok = step(p, &pc, &val, pc == f.entry()) - if !ok { - return most - } - most = max(most, val) - } -} - -func pcdatastart(f funcInfo, table uint32) uint32 { - return *(*uint32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4)) -} - -func pcdatavalue(f funcInfo, table uint32, targetpc uintptr) int32 { - if table >= f.npcdata { - return -1 - } - r, _ := pcvalue(f, pcdatastart(f, table), targetpc, true) - return r -} - -func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, strict bool) int32 { - if table >= f.npcdata { - return -1 - } - r, _ := pcvalue(f, pcdatastart(f, table), targetpc, strict) - return r -} - -// Like pcdatavalue, but also return the start PC of this PCData value. -func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) { - if table >= f.npcdata { - return -1, 0 - } - return pcvalue(f, pcdatastart(f, table), targetpc, true) -} - -// funcdata returns a pointer to the ith funcdata for f. -// funcdata should be kept in sync with cmd/link:writeFuncs. -func funcdata(f funcInfo, i uint8) unsafe.Pointer { - if i < 0 || i >= f.nfuncdata { - return nil - } - base := f.datap.gofunc // load gofunc address early so that we calculate during cache misses - p := uintptr(unsafe.Pointer(&f.nfuncdata)) + unsafe.Sizeof(f.nfuncdata) + uintptr(f.npcdata)*4 + uintptr(i)*4 - off := *(*uint32)(unsafe.Pointer(p)) - // Return off == ^uint32(0) ? 0 : f.datap.gofunc + uintptr(off), but without branches. - // The compiler calculates mask on most architectures using conditional assignment. - var mask uintptr - if off == ^uint32(0) { - mask = 1 - } - mask-- - raw := base + uintptr(off) - return unsafe.Pointer(raw & mask) -} - -// step advances to the next pc, value pair in the encoded table. -func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) { - // For both uvdelta and pcdelta, the common case (~70%) - // is that they are a single byte. If so, avoid calling readvarint. - uvdelta := uint32(p[0]) - if uvdelta == 0 && !first { - return nil, false - } - n := uint32(1) - if uvdelta&0x80 != 0 { - n, uvdelta = readvarint(p) - } - *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1)) - p = p[n:] - - pcdelta := uint32(p[0]) - n = 1 - if pcdelta&0x80 != 0 { - n, pcdelta = readvarint(p) - } - p = p[n:] - *pc += uintptr(pcdelta * sys.PCQuantum) - return p, true -} - -// readvarint reads a varint from p. -func readvarint(p []byte) (read uint32, val uint32) { - var v, shift, n uint32 - for { - b := p[n] - n++ - v |= uint32(b&0x7F) << (shift & 31) - if b&0x80 == 0 { - break - } - shift += 7 - } - return n, v -} - -type stackmap struct { - n int32 // number of bitmaps - nbit int32 // number of bits in each bitmap - bytedata [1]byte // bitmaps, each starting on a byte boundary -} - -//go:nowritebarrier -func stackmapdata(stkmap *stackmap, n int32) bitvector { - // Check this invariant only when stackDebug is on at all. - // The invariant is already checked by many of stackmapdata's callers, - // and disabling it by default allows stackmapdata to be inlined. - if stackDebug > 0 && (n < 0 || n >= stkmap.n) { - throw("stackmapdata: index out of range") - } - return bitvector{stkmap.nbit, addb(&stkmap.bytedata[0], uintptr(n*((stkmap.nbit+7)>>3)))} -} diff --git a/contrib/go/_std_1.22/src/runtime/syscall_windows.go b/contrib/go/_std_1.22/src/runtime/syscall_windows.go deleted file mode 100644 index ba88e93d7dc9..000000000000 --- a/contrib/go/_std_1.22/src/runtime/syscall_windows.go +++ /dev/null @@ -1,546 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "unsafe" -) - -// cbs stores all registered Go callbacks. -var cbs struct { - lock mutex // use cbsLock / cbsUnlock for race instrumentation. - ctxt [cb_max]winCallback - index map[winCallbackKey]int - n int -} - -func cbsLock() { - lock(&cbs.lock) - // compileCallback is used by goenvs prior to completion of schedinit. - // raceacquire involves a racecallback to get the proc, which is not - // safe prior to scheduler initialization. Thus avoid instrumentation - // until then. - if raceenabled && mainStarted { - raceacquire(unsafe.Pointer(&cbs.lock)) - } -} - -func cbsUnlock() { - if raceenabled && mainStarted { - racerelease(unsafe.Pointer(&cbs.lock)) - } - unlock(&cbs.lock) -} - -// winCallback records information about a registered Go callback. -type winCallback struct { - fn *funcval // Go function - retPop uintptr // For 386 cdecl, how many bytes to pop on return - abiMap abiDesc -} - -// abiPartKind is the action an abiPart should take. -type abiPartKind int - -const ( - abiPartBad abiPartKind = iota - abiPartStack // Move a value from memory to the stack. - abiPartReg // Move a value from memory to a register. -) - -// abiPart encodes a step in translating between calling ABIs. -type abiPart struct { - kind abiPartKind - srcStackOffset uintptr - dstStackOffset uintptr // used if kind == abiPartStack - dstRegister int // used if kind == abiPartReg - len uintptr -} - -func (a *abiPart) tryMerge(b abiPart) bool { - if a.kind != abiPartStack || b.kind != abiPartStack { - return false - } - if a.srcStackOffset+a.len == b.srcStackOffset && a.dstStackOffset+a.len == b.dstStackOffset { - a.len += b.len - return true - } - return false -} - -// abiDesc specifies how to translate from a C frame to a Go -// frame. This does not specify how to translate back because -// the result is always a uintptr. If the C ABI is fastcall, -// this assumes the four fastcall registers were first spilled -// to the shadow space. -type abiDesc struct { - parts []abiPart - - srcStackSize uintptr // stdcall/fastcall stack space tracking - dstStackSize uintptr // Go stack space used - dstSpill uintptr // Extra stack space for argument spill slots - dstRegisters int // Go ABI int argument registers used - - // retOffset is the offset of the uintptr-sized result in the Go - // frame. - retOffset uintptr -} - -func (p *abiDesc) assignArg(t *_type) { - if t.Size_ > goarch.PtrSize { - // We don't support this right now. In - // stdcall/cdecl, 64-bit ints and doubles are - // passed as two words (little endian); and - // structs are pushed on the stack. In - // fastcall, arguments larger than the word - // size are passed by reference. On arm, - // 8-byte aligned arguments round up to the - // next even register and can be split across - // registers and the stack. - panic("compileCallback: argument size is larger than uintptr") - } - if k := t.Kind_ & kindMask; GOARCH != "386" && (k == kindFloat32 || k == kindFloat64) { - // In fastcall, floating-point arguments in - // the first four positions are passed in - // floating-point registers, which we don't - // currently spill. arm passes floating-point - // arguments in VFP registers, which we also - // don't support. - // So basically we only support 386. - panic("compileCallback: float arguments not supported") - } - - if t.Size_ == 0 { - // The Go ABI aligns for zero-sized types. - p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_)) - return - } - - // In the C ABI, we're already on a word boundary. - // Also, sub-word-sized fastcall register arguments - // are stored to the least-significant bytes of the - // argument word and all supported Windows - // architectures are little endian, so srcStackOffset - // is already pointing to the right place for smaller - // arguments. The same is true on arm. - - oldParts := p.parts - if p.tryRegAssignArg(t, 0) { - // Account for spill space. - // - // TODO(mknyszek): Remove this when we no longer have - // caller reserved spill space. - p.dstSpill = alignUp(p.dstSpill, uintptr(t.Align_)) - p.dstSpill += t.Size_ - } else { - // Register assignment failed. - // Undo the work and stack assign. - p.parts = oldParts - - // The Go ABI aligns arguments. - p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_)) - - // Copy just the size of the argument. Note that this - // could be a small by-value struct, but C and Go - // struct layouts are compatible, so we can copy these - // directly, too. - part := abiPart{ - kind: abiPartStack, - srcStackOffset: p.srcStackSize, - dstStackOffset: p.dstStackSize, - len: t.Size_, - } - // Add this step to the adapter. - if len(p.parts) == 0 || !p.parts[len(p.parts)-1].tryMerge(part) { - p.parts = append(p.parts, part) - } - // The Go ABI packs arguments. - p.dstStackSize += t.Size_ - } - - // cdecl, stdcall, fastcall, and arm pad arguments to word size. - // TODO(rsc): On arm and arm64 do we need to skip the caller's saved LR? - p.srcStackSize += goarch.PtrSize -} - -// tryRegAssignArg tries to register-assign a value of type t. -// If this type is nested in an aggregate type, then offset is the -// offset of this type within its parent type. -// Assumes t.size <= goarch.PtrSize and t.size != 0. -// -// Returns whether the assignment succeeded. -func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool { - switch k := t.Kind_ & kindMask; k { - case kindBool, kindInt, kindInt8, kindInt16, kindInt32, kindUint, kindUint8, kindUint16, kindUint32, kindUintptr, kindPtr, kindUnsafePointer: - // Assign a register for all these types. - return p.assignReg(t.Size_, offset) - case kindInt64, kindUint64: - // Only register-assign if the registers are big enough. - if goarch.PtrSize == 8 { - return p.assignReg(t.Size_, offset) - } - case kindArray: - at := (*arraytype)(unsafe.Pointer(t)) - if at.Len == 1 { - return p.tryRegAssignArg(at.Elem, offset) // TODO fix when runtime is fully commoned up w/ abi.Type - } - case kindStruct: - st := (*structtype)(unsafe.Pointer(t)) - for i := range st.Fields { - f := &st.Fields[i] - if !p.tryRegAssignArg(f.Typ, offset+f.Offset) { - return false - } - } - return true - } - // Pointer-sized types such as maps and channels are currently - // not supported. - panic("compileCallback: type " + toRType(t).string() + " is currently not supported for use in system callbacks") -} - -// assignReg attempts to assign a single register for an -// argument with the given size, at the given offset into the -// value in the C ABI space. -// -// Returns whether the assignment was successful. -func (p *abiDesc) assignReg(size, offset uintptr) bool { - if p.dstRegisters >= intArgRegs { - return false - } - p.parts = append(p.parts, abiPart{ - kind: abiPartReg, - srcStackOffset: p.srcStackSize + offset, - dstRegister: p.dstRegisters, - len: size, - }) - p.dstRegisters++ - return true -} - -type winCallbackKey struct { - fn *funcval - cdecl bool -} - -func callbackasm() - -// callbackasmAddr returns address of runtime.callbackasm -// function adjusted by i. -// On x86 and amd64, runtime.callbackasm is a series of CALL instructions, -// and we want callback to arrive at -// correspondent call instruction instead of start of -// runtime.callbackasm. -// On ARM, runtime.callbackasm is a series of mov and branch instructions. -// R12 is loaded with the callback index. Each entry is two instructions, -// hence 8 bytes. -func callbackasmAddr(i int) uintptr { - var entrySize int - switch GOARCH { - default: - panic("unsupported architecture") - case "386", "amd64": - entrySize = 5 - case "arm", "arm64": - // On ARM and ARM64, each entry is a MOV instruction - // followed by a branch instruction - entrySize = 8 - } - return abi.FuncPCABI0(callbackasm) + uintptr(i*entrySize) -} - -const callbackMaxFrame = 64 * goarch.PtrSize - -// compileCallback converts a Go function fn into a C function pointer -// that can be passed to Windows APIs. -// -// On 386, if cdecl is true, the returned C function will use the -// cdecl calling convention; otherwise, it will use stdcall. On amd64, -// it always uses fastcall. On arm, it always uses the ARM convention. -// -//go:linkname compileCallback syscall.compileCallback -func compileCallback(fn eface, cdecl bool) (code uintptr) { - if GOARCH != "386" { - // cdecl is only meaningful on 386. - cdecl = false - } - - if fn._type == nil || (fn._type.Kind_&kindMask) != kindFunc { - panic("compileCallback: expected function with one uintptr-sized result") - } - ft := (*functype)(unsafe.Pointer(fn._type)) - - // Check arguments and construct ABI translation. - var abiMap abiDesc - for _, t := range ft.InSlice() { - abiMap.assignArg(t) - } - // The Go ABI aligns the result to the word size. src is - // already aligned. - abiMap.dstStackSize = alignUp(abiMap.dstStackSize, goarch.PtrSize) - abiMap.retOffset = abiMap.dstStackSize - - if len(ft.OutSlice()) != 1 { - panic("compileCallback: expected function with one uintptr-sized result") - } - if ft.OutSlice()[0].Size_ != goarch.PtrSize { - panic("compileCallback: expected function with one uintptr-sized result") - } - if k := ft.OutSlice()[0].Kind_ & kindMask; k == kindFloat32 || k == kindFloat64 { - // In cdecl and stdcall, float results are returned in - // ST(0). In fastcall, they're returned in XMM0. - // Either way, it's not AX. - panic("compileCallback: float results not supported") - } - if intArgRegs == 0 { - // Make room for the uintptr-sized result. - // If there are argument registers, the return value will - // be passed in the first register. - abiMap.dstStackSize += goarch.PtrSize - } - - // TODO(mknyszek): Remove dstSpill from this calculation when we no longer have - // caller reserved spill space. - frameSize := alignUp(abiMap.dstStackSize, goarch.PtrSize) - frameSize += abiMap.dstSpill - if frameSize > callbackMaxFrame { - panic("compileCallback: function argument frame too large") - } - - // For cdecl, the callee is responsible for popping its - // arguments from the C stack. - var retPop uintptr - if cdecl { - retPop = abiMap.srcStackSize - } - - key := winCallbackKey{(*funcval)(fn.data), cdecl} - - cbsLock() - - // Check if this callback is already registered. - if n, ok := cbs.index[key]; ok { - cbsUnlock() - return callbackasmAddr(n) - } - - // Register the callback. - if cbs.index == nil { - cbs.index = make(map[winCallbackKey]int) - } - n := cbs.n - if n >= len(cbs.ctxt) { - cbsUnlock() - throw("too many callback functions") - } - c := winCallback{key.fn, retPop, abiMap} - cbs.ctxt[n] = c - cbs.index[key] = n - cbs.n++ - - cbsUnlock() - return callbackasmAddr(n) -} - -type callbackArgs struct { - index uintptr - // args points to the argument block. - // - // For cdecl and stdcall, all arguments are on the stack. - // - // For fastcall, the trampoline spills register arguments to - // the reserved spill slots below the stack arguments, - // resulting in a layout equivalent to stdcall. - // - // For arm, the trampoline stores the register arguments just - // below the stack arguments, so again we can treat it as one - // big stack arguments frame. - args unsafe.Pointer - // Below are out-args from callbackWrap - result uintptr - retPop uintptr // For 386 cdecl, how many bytes to pop on return -} - -// callbackWrap is called by callbackasm to invoke a registered C callback. -func callbackWrap(a *callbackArgs) { - c := cbs.ctxt[a.index] - a.retPop = c.retPop - - // Convert from C to Go ABI. - var regs abi.RegArgs - var frame [callbackMaxFrame]byte - goArgs := unsafe.Pointer(&frame) - for _, part := range c.abiMap.parts { - switch part.kind { - case abiPartStack: - memmove(add(goArgs, part.dstStackOffset), add(a.args, part.srcStackOffset), part.len) - case abiPartReg: - goReg := unsafe.Pointer(®s.Ints[part.dstRegister]) - memmove(goReg, add(a.args, part.srcStackOffset), part.len) - default: - panic("bad ABI description") - } - } - - // TODO(mknyszek): Remove this when we no longer have - // caller reserved spill space. - frameSize := alignUp(c.abiMap.dstStackSize, goarch.PtrSize) - frameSize += c.abiMap.dstSpill - - // Even though this is copying back results, we can pass a nil - // type because those results must not require write barriers. - reflectcall(nil, unsafe.Pointer(c.fn), noescape(goArgs), uint32(c.abiMap.dstStackSize), uint32(c.abiMap.retOffset), uint32(frameSize), ®s) - - // Extract the result. - // - // There's always exactly one return value, one pointer in size. - // If it's on the stack, then we will have reserved space for it - // at the end of the frame, otherwise it was passed in a register. - if c.abiMap.dstStackSize != c.abiMap.retOffset { - a.result = *(*uintptr)(unsafe.Pointer(&frame[c.abiMap.retOffset])) - } else { - var zero int - // On architectures with no registers, Ints[0] would be a compile error, - // so we use a dynamic index. These architectures will never take this - // branch, so this won't cause a runtime panic. - a.result = regs.Ints[zero] - } -} - -const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 - -//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary -//go:nosplit -//go:cgo_unsafe_args -func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) { - lockOSThread() - c := &getg().m.syscall - c.fn = getLoadLibraryEx() - c.n = 3 - args := struct { - lpFileName *uint16 - hFile uintptr // always 0 - flags uint32 - }{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32} - c.args = uintptr(noescape(unsafe.Pointer(&args))) - - cgocall(asmstdcallAddr, unsafe.Pointer(c)) - KeepAlive(filename) - handle = c.r1 - if handle == 0 { - err = c.err - } - unlockOSThread() // not defer'd after the lockOSThread above to save stack frame size. - return -} - -//go:linkname syscall_loadlibrary syscall.loadlibrary -//go:nosplit -//go:cgo_unsafe_args -func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { - lockOSThread() - defer unlockOSThread() - c := &getg().m.syscall - c.fn = getLoadLibrary() - c.n = 1 - c.args = uintptr(noescape(unsafe.Pointer(&filename))) - cgocall(asmstdcallAddr, unsafe.Pointer(c)) - KeepAlive(filename) - handle = c.r1 - if handle == 0 { - err = c.err - } - return -} - -//go:linkname syscall_getprocaddress syscall.getprocaddress -//go:nosplit -//go:cgo_unsafe_args -func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) { - lockOSThread() - defer unlockOSThread() - c := &getg().m.syscall - c.fn = getGetProcAddress() - c.n = 2 - c.args = uintptr(noescape(unsafe.Pointer(&handle))) - cgocall(asmstdcallAddr, unsafe.Pointer(c)) - KeepAlive(procname) - outhandle = c.r1 - if outhandle == 0 { - err = c.err - } - return -} - -//go:linkname syscall_Syscall syscall.Syscall -//go:nosplit -func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3) -} - -//go:linkname syscall_Syscall6 syscall.Syscall6 -//go:nosplit -func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6) -} - -//go:linkname syscall_Syscall9 syscall.Syscall9 -//go:nosplit -func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9) -} - -//go:linkname syscall_Syscall12 syscall.Syscall12 -//go:nosplit -func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) -} - -//go:linkname syscall_Syscall15 syscall.Syscall15 -//go:nosplit -func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) -} - -//go:linkname syscall_Syscall18 syscall.Syscall18 -//go:nosplit -func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) -} - -// maxArgs should be divisible by 2, as Windows stack -// must be kept 16-byte aligned on syscall entry. -// -// Although it only permits maximum 42 parameters, it -// is arguably large enough. -const maxArgs = 42 - -//go:linkname syscall_SyscallN syscall.SyscallN -//go:nosplit -func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) { - nargs := len(args) - - // asmstdcall expects it can access the first 4 arguments - // to load them into registers. - var tmp [4]uintptr - switch { - case nargs < 4: - copy(tmp[:], args) - args = tmp[:] - case nargs > maxArgs: - panic("runtime: SyscallN has too many arguments") - } - - lockOSThread() - defer unlockOSThread() - c := &getg().m.syscall - c.fn = trap - c.n = uintptr(nargs) - c.args = uintptr(noescape(unsafe.Pointer(&args[0]))) - cgocall(asmstdcallAddr, unsafe.Pointer(c)) - return c.r1, c.r2, c.err -} diff --git a/contrib/go/_std_1.22/src/runtime/time.go b/contrib/go/_std_1.22/src/runtime/time.go deleted file mode 100644 index 8ed1e45fc9d8..000000000000 --- a/contrib/go/_std_1.22/src/runtime/time.go +++ /dev/null @@ -1,1144 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Time-related runtime and pieces of package time. - -package runtime - -import ( - "internal/abi" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -// Package time knows the layout of this structure. -// If this struct changes, adjust ../time/sleep.go:/runtimeTimer. -type timer struct { - // If this timer is on a heap, which P's heap it is on. - // puintptr rather than *p to match uintptr in the versions - // of this struct defined in other packages. - pp puintptr - - // Timer wakes up at when, and then at when+period, ... (period > 0 only) - // each time calling f(arg, now) in the timer goroutine, so f must be - // a well-behaved function and not block. - // - // when must be positive on an active timer. - when int64 - period int64 - f func(any, uintptr) - arg any - seq uintptr - - // What to set the when field to in timerModifiedXX status. - nextwhen int64 - - // The status field holds one of the values below. - status atomic.Uint32 -} - -// Code outside this file has to be careful in using a timer value. -// -// The pp, status, and nextwhen fields may only be used by code in this file. -// -// Code that creates a new timer value can set the when, period, f, -// arg, and seq fields. -// A new timer value may be passed to addtimer (called by time.startTimer). -// After doing that no fields may be touched. -// -// An active timer (one that has been passed to addtimer) may be -// passed to deltimer (time.stopTimer), after which it is no longer an -// active timer. It is an inactive timer. -// In an inactive timer the period, f, arg, and seq fields may be modified, -// but not the when field. -// It's OK to just drop an inactive timer and let the GC collect it. -// It's not OK to pass an inactive timer to addtimer. -// Only newly allocated timer values may be passed to addtimer. -// -// An active timer may be passed to modtimer. No fields may be touched. -// It remains an active timer. -// -// An inactive timer may be passed to resettimer to turn into an -// active timer with an updated when field. -// It's OK to pass a newly allocated timer value to resettimer. -// -// Timer operations are addtimer, deltimer, modtimer, resettimer, -// cleantimers, adjusttimers, and runtimer. -// -// We don't permit calling addtimer/deltimer/modtimer/resettimer simultaneously, -// but adjusttimers and runtimer can be called at the same time as any of those. -// -// Active timers live in heaps attached to P, in the timers field. -// Inactive timers live there too temporarily, until they are removed. -// -// addtimer: -// timerNoStatus -> timerWaiting -// anything else -> panic: invalid value -// deltimer: -// timerWaiting -> timerModifying -> timerDeleted -// timerModifiedEarlier -> timerModifying -> timerDeleted -// timerModifiedLater -> timerModifying -> timerDeleted -// timerNoStatus -> do nothing -// timerDeleted -> do nothing -// timerRemoving -> do nothing -// timerRemoved -> do nothing -// timerRunning -> wait until status changes -// timerMoving -> wait until status changes -// timerModifying -> wait until status changes -// modtimer: -// timerWaiting -> timerModifying -> timerModifiedXX -// timerModifiedXX -> timerModifying -> timerModifiedYY -// timerNoStatus -> timerModifying -> timerWaiting -// timerRemoved -> timerModifying -> timerWaiting -// timerDeleted -> timerModifying -> timerModifiedXX -// timerRunning -> wait until status changes -// timerMoving -> wait until status changes -// timerRemoving -> wait until status changes -// timerModifying -> wait until status changes -// cleantimers (looks in P's timer heap): -// timerDeleted -> timerRemoving -> timerRemoved -// timerModifiedXX -> timerMoving -> timerWaiting -// adjusttimers (looks in P's timer heap): -// timerDeleted -> timerRemoving -> timerRemoved -// timerModifiedXX -> timerMoving -> timerWaiting -// runtimer (looks in P's timer heap): -// timerNoStatus -> panic: uninitialized timer -// timerWaiting -> timerWaiting or -// timerWaiting -> timerRunning -> timerNoStatus or -// timerWaiting -> timerRunning -> timerWaiting -// timerModifying -> wait until status changes -// timerModifiedXX -> timerMoving -> timerWaiting -// timerDeleted -> timerRemoving -> timerRemoved -// timerRunning -> panic: concurrent runtimer calls -// timerRemoved -> panic: inconsistent timer heap -// timerRemoving -> panic: inconsistent timer heap -// timerMoving -> panic: inconsistent timer heap - -// Values for the timer status field. -const ( - // Timer has no status set yet. - timerNoStatus = iota - - // Waiting for timer to fire. - // The timer is in some P's heap. - timerWaiting - - // Running the timer function. - // A timer will only have this status briefly. - timerRunning - - // The timer is deleted and should be removed. - // It should not be run, but it is still in some P's heap. - timerDeleted - - // The timer is being removed. - // The timer will only have this status briefly. - timerRemoving - - // The timer has been stopped. - // It is not in any P's heap. - timerRemoved - - // The timer is being modified. - // The timer will only have this status briefly. - timerModifying - - // The timer has been modified to an earlier time. - // The new when value is in the nextwhen field. - // The timer is in some P's heap, possibly in the wrong place. - timerModifiedEarlier - - // The timer has been modified to the same or a later time. - // The new when value is in the nextwhen field. - // The timer is in some P's heap, possibly in the wrong place. - timerModifiedLater - - // The timer has been modified and is being moved. - // The timer will only have this status briefly. - timerMoving -) - -// maxWhen is the maximum value for timer's when field. -const maxWhen = 1<<63 - 1 - -// verifyTimers can be set to true to add debugging checks that the -// timer heaps are valid. -const verifyTimers = false - -// Package time APIs. -// Godoc uses the comments in package time, not these. - -// time.now is implemented in assembly. - -// timeSleep puts the current goroutine to sleep for at least ns nanoseconds. -// -//go:linkname timeSleep time.Sleep -func timeSleep(ns int64) { - if ns <= 0 { - return - } - - gp := getg() - t := gp.timer - if t == nil { - t = new(timer) - gp.timer = t - } - t.f = goroutineReady - t.arg = gp - t.nextwhen = nanotime() + ns - if t.nextwhen < 0 { // check for overflow. - t.nextwhen = maxWhen - } - gopark(resetForSleep, unsafe.Pointer(t), waitReasonSleep, traceBlockSleep, 1) -} - -// resetForSleep is called after the goroutine is parked for timeSleep. -// We can't call resettimer in timeSleep itself because if this is a short -// sleep and there are many goroutines then the P can wind up running the -// timer function, goroutineReady, before the goroutine has been parked. -func resetForSleep(gp *g, ut unsafe.Pointer) bool { - t := (*timer)(ut) - resettimer(t, t.nextwhen) - return true -} - -// startTimer adds t to the timer heap. -// -//go:linkname startTimer time.startTimer -func startTimer(t *timer) { - if raceenabled { - racerelease(unsafe.Pointer(t)) - } - addtimer(t) -} - -// stopTimer stops a timer. -// It reports whether t was stopped before being run. -// -//go:linkname stopTimer time.stopTimer -func stopTimer(t *timer) bool { - return deltimer(t) -} - -// resetTimer resets an inactive timer, adding it to the heap. -// -// Reports whether the timer was modified before it was run. -// -//go:linkname resetTimer time.resetTimer -func resetTimer(t *timer, when int64) bool { - if raceenabled { - racerelease(unsafe.Pointer(t)) - } - return resettimer(t, when) -} - -// modTimer modifies an existing timer. -// -//go:linkname modTimer time.modTimer -func modTimer(t *timer, when, period int64, f func(any, uintptr), arg any, seq uintptr) { - modtimer(t, when, period, f, arg, seq) -} - -// Go runtime. - -// Ready the goroutine arg. -func goroutineReady(arg any, seq uintptr) { - goready(arg.(*g), 0) -} - -// Note: this changes some unsynchronized operations to synchronized operations -// addtimer adds a timer to the current P. -// This should only be called with a newly created timer. -// That avoids the risk of changing the when field of a timer in some P's heap, -// which could cause the heap to become unsorted. -func addtimer(t *timer) { - // when must be positive. A negative value will cause runtimer to - // overflow during its delta calculation and never expire other runtime - // timers. Zero will cause checkTimers to fail to notice the timer. - if t.when <= 0 { - throw("timer when must be positive") - } - if t.period < 0 { - throw("timer period must be non-negative") - } - if t.status.Load() != timerNoStatus { - throw("addtimer called with initialized timer") - } - t.status.Store(timerWaiting) - - when := t.when - - // Disable preemption while using pp to avoid changing another P's heap. - mp := acquirem() - - pp := getg().m.p.ptr() - lock(&pp.timersLock) - cleantimers(pp) - doaddtimer(pp, t) - unlock(&pp.timersLock) - - wakeNetPoller(when) - - releasem(mp) -} - -// doaddtimer adds t to the current P's heap. -// The caller must have locked the timers for pp. -func doaddtimer(pp *p, t *timer) { - // Timers rely on the network poller, so make sure the poller - // has started. - if netpollInited.Load() == 0 { - netpollGenericInit() - } - - if t.pp != 0 { - throw("doaddtimer: P already set in timer") - } - t.pp.set(pp) - i := len(pp.timers) - pp.timers = append(pp.timers, t) - siftupTimer(pp.timers, i) - if t == pp.timers[0] { - pp.timer0When.Store(t.when) - } - pp.numTimers.Add(1) -} - -// deltimer deletes the timer t. It may be on some other P, so we can't -// actually remove it from the timers heap. We can only mark it as deleted. -// It will be removed in due course by the P whose heap it is on. -// Reports whether the timer was removed before it was run. -func deltimer(t *timer) bool { - for { - switch s := t.status.Load(); s { - case timerWaiting, timerModifiedLater: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp := acquirem() - if t.status.CompareAndSwap(s, timerModifying) { - // Must fetch t.pp before changing status, - // as cleantimers in another goroutine - // can clear t.pp of a timerDeleted timer. - tpp := t.pp.ptr() - if !t.status.CompareAndSwap(timerModifying, timerDeleted) { - badTimer() - } - releasem(mp) - tpp.deletedTimers.Add(1) - // Timer was not yet run. - return true - } else { - releasem(mp) - } - case timerModifiedEarlier: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp := acquirem() - if t.status.CompareAndSwap(s, timerModifying) { - // Must fetch t.pp before setting status - // to timerDeleted. - tpp := t.pp.ptr() - if !t.status.CompareAndSwap(timerModifying, timerDeleted) { - badTimer() - } - releasem(mp) - tpp.deletedTimers.Add(1) - // Timer was not yet run. - return true - } else { - releasem(mp) - } - case timerDeleted, timerRemoving, timerRemoved: - // Timer was already run. - return false - case timerRunning, timerMoving: - // The timer is being run or moved, by a different P. - // Wait for it to complete. - osyield() - case timerNoStatus: - // Removing timer that was never added or - // has already been run. Also see issue 21874. - return false - case timerModifying: - // Simultaneous calls to deltimer and modtimer. - // Wait for the other call to complete. - osyield() - default: - badTimer() - } - } -} - -// dodeltimer removes timer i from the current P's heap. -// We are locked on the P when this is called. -// It returns the smallest changed index in pp.timers. -// The caller must have locked the timers for pp. -func dodeltimer(pp *p, i int) int { - if t := pp.timers[i]; t.pp.ptr() != pp { - throw("dodeltimer: wrong P") - } else { - t.pp = 0 - } - last := len(pp.timers) - 1 - if i != last { - pp.timers[i] = pp.timers[last] - } - pp.timers[last] = nil - pp.timers = pp.timers[:last] - smallestChanged := i - if i != last { - // Moving to i may have moved the last timer to a new parent, - // so sift up to preserve the heap guarantee. - smallestChanged = siftupTimer(pp.timers, i) - siftdownTimer(pp.timers, i) - } - if i == 0 { - updateTimer0When(pp) - } - n := pp.numTimers.Add(-1) - if n == 0 { - // If there are no timers, then clearly none are modified. - pp.timerModifiedEarliest.Store(0) - } - return smallestChanged -} - -// dodeltimer0 removes timer 0 from the current P's heap. -// We are locked on the P when this is called. -// It reports whether it saw no problems due to races. -// The caller must have locked the timers for pp. -func dodeltimer0(pp *p) { - if t := pp.timers[0]; t.pp.ptr() != pp { - throw("dodeltimer0: wrong P") - } else { - t.pp = 0 - } - last := len(pp.timers) - 1 - if last > 0 { - pp.timers[0] = pp.timers[last] - } - pp.timers[last] = nil - pp.timers = pp.timers[:last] - if last > 0 { - siftdownTimer(pp.timers, 0) - } - updateTimer0When(pp) - n := pp.numTimers.Add(-1) - if n == 0 { - // If there are no timers, then clearly none are modified. - pp.timerModifiedEarliest.Store(0) - } -} - -// modtimer modifies an existing timer. -// This is called by the netpoll code or time.Ticker.Reset or time.Timer.Reset. -// Reports whether the timer was modified before it was run. -func modtimer(t *timer, when, period int64, f func(any, uintptr), arg any, seq uintptr) bool { - if when <= 0 { - throw("timer when must be positive") - } - if period < 0 { - throw("timer period must be non-negative") - } - - status := uint32(timerNoStatus) - wasRemoved := false - var pending bool - var mp *m -loop: - for { - switch status = t.status.Load(); status { - case timerWaiting, timerModifiedEarlier, timerModifiedLater: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp = acquirem() - if t.status.CompareAndSwap(status, timerModifying) { - pending = true // timer not yet run - break loop - } - releasem(mp) - case timerNoStatus, timerRemoved: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp = acquirem() - - // Timer was already run and t is no longer in a heap. - // Act like addtimer. - if t.status.CompareAndSwap(status, timerModifying) { - wasRemoved = true - pending = false // timer already run or stopped - break loop - } - releasem(mp) - case timerDeleted: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp = acquirem() - if t.status.CompareAndSwap(status, timerModifying) { - t.pp.ptr().deletedTimers.Add(-1) - pending = false // timer already stopped - break loop - } - releasem(mp) - case timerRunning, timerRemoving, timerMoving: - // The timer is being run or moved, by a different P. - // Wait for it to complete. - osyield() - case timerModifying: - // Multiple simultaneous calls to modtimer. - // Wait for the other call to complete. - osyield() - default: - badTimer() - } - } - - t.period = period - t.f = f - t.arg = arg - t.seq = seq - - if wasRemoved { - t.when = when - pp := getg().m.p.ptr() - lock(&pp.timersLock) - doaddtimer(pp, t) - unlock(&pp.timersLock) - if !t.status.CompareAndSwap(timerModifying, timerWaiting) { - badTimer() - } - releasem(mp) - wakeNetPoller(when) - } else { - // The timer is in some other P's heap, so we can't change - // the when field. If we did, the other P's heap would - // be out of order. So we put the new when value in the - // nextwhen field, and let the other P set the when field - // when it is prepared to resort the heap. - t.nextwhen = when - - newStatus := uint32(timerModifiedLater) - if when < t.when { - newStatus = timerModifiedEarlier - } - - tpp := t.pp.ptr() - - if newStatus == timerModifiedEarlier { - updateTimerModifiedEarliest(tpp, when) - } - - // Set the new status of the timer. - if !t.status.CompareAndSwap(timerModifying, newStatus) { - badTimer() - } - releasem(mp) - - // If the new status is earlier, wake up the poller. - if newStatus == timerModifiedEarlier { - wakeNetPoller(when) - } - } - - return pending -} - -// resettimer resets the time when a timer should fire. -// If used for an inactive timer, the timer will become active. -// This should be called instead of addtimer if the timer value has been, -// or may have been, used previously. -// Reports whether the timer was modified before it was run. -func resettimer(t *timer, when int64) bool { - return modtimer(t, when, t.period, t.f, t.arg, t.seq) -} - -// cleantimers cleans up the head of the timer queue. This speeds up -// programs that create and delete timers; leaving them in the heap -// slows down addtimer. Reports whether no timer problems were found. -// The caller must have locked the timers for pp. -func cleantimers(pp *p) { - gp := getg() - for { - if len(pp.timers) == 0 { - return - } - - // This loop can theoretically run for a while, and because - // it is holding timersLock it cannot be preempted. - // If someone is trying to preempt us, just return. - // We can clean the timers later. - if gp.preemptStop { - return - } - - t := pp.timers[0] - if t.pp.ptr() != pp { - throw("cleantimers: bad p") - } - switch s := t.status.Load(); s { - case timerDeleted: - if !t.status.CompareAndSwap(s, timerRemoving) { - continue - } - dodeltimer0(pp) - if !t.status.CompareAndSwap(timerRemoving, timerRemoved) { - badTimer() - } - pp.deletedTimers.Add(-1) - case timerModifiedEarlier, timerModifiedLater: - if !t.status.CompareAndSwap(s, timerMoving) { - continue - } - // Now we can change the when field. - t.when = t.nextwhen - // Move t to the right position. - dodeltimer0(pp) - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - default: - // Head of timers does not need adjustment. - return - } - } -} - -// moveTimers moves a slice of timers to pp. The slice has been taken -// from a different P. -// This is currently called when the world is stopped, but the caller -// is expected to have locked the timers for pp. -func moveTimers(pp *p, timers []*timer) { - for _, t := range timers { - loop: - for { - switch s := t.status.Load(); s { - case timerWaiting: - if !t.status.CompareAndSwap(s, timerMoving) { - continue - } - t.pp = 0 - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - break loop - case timerModifiedEarlier, timerModifiedLater: - if !t.status.CompareAndSwap(s, timerMoving) { - continue - } - t.when = t.nextwhen - t.pp = 0 - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - break loop - case timerDeleted: - if !t.status.CompareAndSwap(s, timerRemoved) { - continue - } - t.pp = 0 - // We no longer need this timer in the heap. - break loop - case timerModifying: - // Loop until the modification is complete. - osyield() - case timerNoStatus, timerRemoved: - // We should not see these status values in a timers heap. - badTimer() - case timerRunning, timerRemoving, timerMoving: - // Some other P thinks it owns this timer, - // which should not happen. - badTimer() - default: - badTimer() - } - } - } -} - -// adjusttimers looks through the timers in the current P's heap for -// any timers that have been modified to run earlier, and puts them in -// the correct place in the heap. While looking for those timers, -// it also moves timers that have been modified to run later, -// and removes deleted timers. The caller must have locked the timers for pp. -func adjusttimers(pp *p, now int64) { - // If we haven't yet reached the time of the first timerModifiedEarlier - // timer, don't do anything. This speeds up programs that adjust - // a lot of timers back and forth if the timers rarely expire. - // We'll postpone looking through all the adjusted timers until - // one would actually expire. - first := pp.timerModifiedEarliest.Load() - if first == 0 || first > now { - if verifyTimers { - verifyTimerHeap(pp) - } - return - } - - // We are going to clear all timerModifiedEarlier timers. - pp.timerModifiedEarliest.Store(0) - - var moved []*timer - for i := 0; i < len(pp.timers); i++ { - t := pp.timers[i] - if t.pp.ptr() != pp { - throw("adjusttimers: bad p") - } - switch s := t.status.Load(); s { - case timerDeleted: - if t.status.CompareAndSwap(s, timerRemoving) { - changed := dodeltimer(pp, i) - if !t.status.CompareAndSwap(timerRemoving, timerRemoved) { - badTimer() - } - pp.deletedTimers.Add(-1) - // Go back to the earliest changed heap entry. - // "- 1" because the loop will add 1. - i = changed - 1 - } - case timerModifiedEarlier, timerModifiedLater: - if t.status.CompareAndSwap(s, timerMoving) { - // Now we can change the when field. - t.when = t.nextwhen - // Take t off the heap, and hold onto it. - // We don't add it back yet because the - // heap manipulation could cause our - // loop to skip some other timer. - changed := dodeltimer(pp, i) - moved = append(moved, t) - // Go back to the earliest changed heap entry. - // "- 1" because the loop will add 1. - i = changed - 1 - } - case timerNoStatus, timerRunning, timerRemoving, timerRemoved, timerMoving: - badTimer() - case timerWaiting: - // OK, nothing to do. - case timerModifying: - // Check again after modification is complete. - osyield() - i-- - default: - badTimer() - } - } - - if len(moved) > 0 { - addAdjustedTimers(pp, moved) - } - - if verifyTimers { - verifyTimerHeap(pp) - } -} - -// addAdjustedTimers adds any timers we adjusted in adjusttimers -// back to the timer heap. -func addAdjustedTimers(pp *p, moved []*timer) { - for _, t := range moved { - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - } -} - -// nobarrierWakeTime looks at P's timers and returns the time when we -// should wake up the netpoller. It returns 0 if there are no timers. -// This function is invoked when dropping a P, and must run without -// any write barriers. -// -//go:nowritebarrierrec -func nobarrierWakeTime(pp *p) int64 { - next := pp.timer0When.Load() - nextAdj := pp.timerModifiedEarliest.Load() - if next == 0 || (nextAdj != 0 && nextAdj < next) { - next = nextAdj - } - return next -} - -// runtimer examines the first timer in timers. If it is ready based on now, -// it runs the timer and removes or updates it. -// Returns 0 if it ran a timer, -1 if there are no more timers, or the time -// when the first timer should run. -// The caller must have locked the timers for pp. -// If a timer is run, this will temporarily unlock the timers. -// -//go:systemstack -func runtimer(pp *p, now int64) int64 { - for { - t := pp.timers[0] - if t.pp.ptr() != pp { - throw("runtimer: bad p") - } - switch s := t.status.Load(); s { - case timerWaiting: - if t.when > now { - // Not ready to run. - return t.when - } - - if !t.status.CompareAndSwap(s, timerRunning) { - continue - } - // Note that runOneTimer may temporarily unlock - // pp.timersLock. - runOneTimer(pp, t, now) - return 0 - - case timerDeleted: - if !t.status.CompareAndSwap(s, timerRemoving) { - continue - } - dodeltimer0(pp) - if !t.status.CompareAndSwap(timerRemoving, timerRemoved) { - badTimer() - } - pp.deletedTimers.Add(-1) - if len(pp.timers) == 0 { - return -1 - } - - case timerModifiedEarlier, timerModifiedLater: - if !t.status.CompareAndSwap(s, timerMoving) { - continue - } - t.when = t.nextwhen - dodeltimer0(pp) - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - - case timerModifying: - // Wait for modification to complete. - osyield() - - case timerNoStatus, timerRemoved: - // Should not see a new or inactive timer on the heap. - badTimer() - case timerRunning, timerRemoving, timerMoving: - // These should only be set when timers are locked, - // and we didn't do it. - badTimer() - default: - badTimer() - } - } -} - -// runOneTimer runs a single timer. -// The caller must have locked the timers for pp. -// This will temporarily unlock the timers while running the timer function. -// -//go:systemstack -func runOneTimer(pp *p, t *timer, now int64) { - if raceenabled { - ppcur := getg().m.p.ptr() - if ppcur.timerRaceCtx == 0 { - ppcur.timerRaceCtx = racegostart(abi.FuncPCABIInternal(runtimer) + sys.PCQuantum) - } - raceacquirectx(ppcur.timerRaceCtx, unsafe.Pointer(t)) - } - - f := t.f - arg := t.arg - seq := t.seq - - if t.period > 0 { - // Leave in heap but adjust next time to fire. - delta := t.when - now - t.when += t.period * (1 + -delta/t.period) - if t.when < 0 { // check for overflow. - t.when = maxWhen - } - siftdownTimer(pp.timers, 0) - if !t.status.CompareAndSwap(timerRunning, timerWaiting) { - badTimer() - } - updateTimer0When(pp) - } else { - // Remove from heap. - dodeltimer0(pp) - if !t.status.CompareAndSwap(timerRunning, timerNoStatus) { - badTimer() - } - } - - if raceenabled { - // Temporarily use the current P's racectx for g0. - gp := getg() - if gp.racectx != 0 { - throw("runOneTimer: unexpected racectx") - } - gp.racectx = gp.m.p.ptr().timerRaceCtx - } - - unlock(&pp.timersLock) - - f(arg, seq) - - lock(&pp.timersLock) - - if raceenabled { - gp := getg() - gp.racectx = 0 - } -} - -// clearDeletedTimers removes all deleted timers from the P's timer heap. -// This is used to avoid clogging up the heap if the program -// starts a lot of long-running timers and then stops them. -// For example, this can happen via context.WithTimeout. -// -// This is the only function that walks through the entire timer heap, -// other than moveTimers which only runs when the world is stopped. -// -// The caller must have locked the timers for pp. -func clearDeletedTimers(pp *p) { - // We are going to clear all timerModifiedEarlier timers. - // Do this now in case new ones show up while we are looping. - pp.timerModifiedEarliest.Store(0) - - cdel := int32(0) - to := 0 - changedHeap := false - timers := pp.timers -nextTimer: - for _, t := range timers { - for { - switch s := t.status.Load(); s { - case timerWaiting: - if changedHeap { - timers[to] = t - siftupTimer(timers, to) - } - to++ - continue nextTimer - case timerModifiedEarlier, timerModifiedLater: - if t.status.CompareAndSwap(s, timerMoving) { - t.when = t.nextwhen - timers[to] = t - siftupTimer(timers, to) - to++ - changedHeap = true - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - continue nextTimer - } - case timerDeleted: - if t.status.CompareAndSwap(s, timerRemoving) { - t.pp = 0 - cdel++ - if !t.status.CompareAndSwap(timerRemoving, timerRemoved) { - badTimer() - } - changedHeap = true - continue nextTimer - } - case timerModifying: - // Loop until modification complete. - osyield() - case timerNoStatus, timerRemoved: - // We should not see these status values in a timer heap. - badTimer() - case timerRunning, timerRemoving, timerMoving: - // Some other P thinks it owns this timer, - // which should not happen. - badTimer() - default: - badTimer() - } - } - } - - // Set remaining slots in timers slice to nil, - // so that the timer values can be garbage collected. - for i := to; i < len(timers); i++ { - timers[i] = nil - } - - pp.deletedTimers.Add(-cdel) - pp.numTimers.Add(-cdel) - - timers = timers[:to] - pp.timers = timers - updateTimer0When(pp) - - if verifyTimers { - verifyTimerHeap(pp) - } -} - -// verifyTimerHeap verifies that the timer heap is in a valid state. -// This is only for debugging, and is only called if verifyTimers is true. -// The caller must have locked the timers. -func verifyTimerHeap(pp *p) { - for i, t := range pp.timers { - if i == 0 { - // First timer has no parent. - continue - } - - // The heap is 4-ary. See siftupTimer and siftdownTimer. - p := (i - 1) / 4 - if t.when < pp.timers[p].when { - print("bad timer heap at ", i, ": ", p, ": ", pp.timers[p].when, ", ", i, ": ", t.when, "\n") - throw("bad timer heap") - } - } - if numTimers := int(pp.numTimers.Load()); len(pp.timers) != numTimers { - println("timer heap len", len(pp.timers), "!= numTimers", numTimers) - throw("bad timer heap len") - } -} - -// updateTimer0When sets the P's timer0When field. -// The caller must have locked the timers for pp. -func updateTimer0When(pp *p) { - if len(pp.timers) == 0 { - pp.timer0When.Store(0) - } else { - pp.timer0When.Store(pp.timers[0].when) - } -} - -// updateTimerModifiedEarliest updates the recorded nextwhen field of the -// earlier timerModifiedEarier value. -// The timers for pp will not be locked. -func updateTimerModifiedEarliest(pp *p, nextwhen int64) { - for { - old := pp.timerModifiedEarliest.Load() - if old != 0 && old < nextwhen { - return - } - - if pp.timerModifiedEarliest.CompareAndSwap(old, nextwhen) { - return - } - } -} - -// timeSleepUntil returns the time when the next timer should fire. Returns -// maxWhen if there are no timers. -// This is only called by sysmon and checkdead. -func timeSleepUntil() int64 { - next := int64(maxWhen) - - // Prevent allp slice changes. This is like retake. - lock(&allpLock) - for _, pp := range allp { - if pp == nil { - // This can happen if procresize has grown - // allp but not yet created new Ps. - continue - } - - w := pp.timer0When.Load() - if w != 0 && w < next { - next = w - } - - w = pp.timerModifiedEarliest.Load() - if w != 0 && w < next { - next = w - } - } - unlock(&allpLock) - - return next -} - -// Heap maintenance algorithms. -// These algorithms check for slice index errors manually. -// Slice index error can happen if the program is using racy -// access to timers. We don't want to panic here, because -// it will cause the program to crash with a mysterious -// "panic holding locks" message. Instead, we panic while not -// holding a lock. - -// siftupTimer puts the timer at position i in the right place -// in the heap by moving it up toward the top of the heap. -// It returns the smallest changed index. -func siftupTimer(t []*timer, i int) int { - if i >= len(t) { - badTimer() - } - when := t[i].when - if when <= 0 { - badTimer() - } - tmp := t[i] - for i > 0 { - p := (i - 1) / 4 // parent - if when >= t[p].when { - break - } - t[i] = t[p] - i = p - } - if tmp != t[i] { - t[i] = tmp - } - return i -} - -// siftdownTimer puts the timer at position i in the right place -// in the heap by moving it down toward the bottom of the heap. -func siftdownTimer(t []*timer, i int) { - n := len(t) - if i >= n { - badTimer() - } - when := t[i].when - if when <= 0 { - badTimer() - } - tmp := t[i] - for { - c := i*4 + 1 // left child - c3 := c + 2 // mid child - if c >= n { - break - } - w := t[c].when - if c+1 < n && t[c+1].when < w { - w = t[c+1].when - c++ - } - if c3 < n { - w3 := t[c3].when - if c3+1 < n && t[c3+1].when < w3 { - w3 = t[c3+1].when - c3++ - } - if w3 < w { - w = w3 - c = c3 - } - } - if w >= when { - break - } - t[i] = t[c] - i = c - } - if tmp != t[i] { - t[i] = tmp - } -} - -// badTimer is called if the timer data structures have been corrupted, -// presumably due to racy use by the program. We panic here rather than -// panicking due to invalid slice access while holding locks. -// See issue #25686. -func badTimer() { - throw("timer data corruption") -} diff --git a/contrib/go/_std_1.22/src/runtime/time_nofake.go b/contrib/go/_std_1.22/src/runtime/time_nofake.go deleted file mode 100644 index 70a2102b22e8..000000000000 --- a/contrib/go/_std_1.22/src/runtime/time_nofake.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !faketime - -package runtime - -import "unsafe" - -// faketime is the simulated time in nanoseconds since 1970 for the -// playground. -// -// Zero means not to use faketime. -var faketime int64 - -//go:nosplit -func nanotime() int64 { - return nanotime1() -} - -var overrideWrite func(fd uintptr, p unsafe.Pointer, n int32) int32 - -// write must be nosplit on Windows (see write1) -// -//go:nosplit -func write(fd uintptr, p unsafe.Pointer, n int32) int32 { - if overrideWrite != nil { - return overrideWrite(fd, noescape(p), n) - } - return write1(fd, p, n) -} diff --git a/contrib/go/_std_1.22/src/runtime/timestub.go b/contrib/go/_std_1.22/src/runtime/timestub.go deleted file mode 100644 index 1d2926b43dc3..000000000000 --- a/contrib/go/_std_1.22/src/runtime/timestub.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Declarations for operating systems implementing time.now -// indirectly, in terms of walltime and nanotime assembly. - -//go:build !faketime && !windows && !(linux && amd64) - -package runtime - -import _ "unsafe" // for go:linkname - -//go:linkname time_now time.now -func time_now() (sec int64, nsec int32, mono int64) { - sec, nsec = walltime() - return sec, nsec, nanotime() -} diff --git a/contrib/go/_std_1.22/src/runtime/trace.go b/contrib/go/_std_1.22/src/runtime/trace.go deleted file mode 100644 index a9cfa22337e1..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace.go +++ /dev/null @@ -1,1925 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !goexperiment.exectracer2 - -// Go execution tracer. -// The tracer captures a wide range of execution events like goroutine -// creation/blocking/unblocking, syscall enter/exit/block, GC-related events, -// changes of heap size, processor start/stop, etc and writes them to a buffer -// in a compact form. A precise nanosecond-precision timestamp and a stack -// trace is captured for most events. -// See https://golang.org/s/go15trace for more info. - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "internal/goos" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -// Event types in the trace, args are given in square brackets. -const ( - traceEvNone = 0 // unused - traceEvBatch = 1 // start of per-P batch of events [pid, timestamp] - traceEvFrequency = 2 // contains tracer timer frequency [frequency (ticks per second)] - traceEvStack = 3 // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}] - traceEvGomaxprocs = 4 // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id] - traceEvProcStart = 5 // start of P [timestamp, thread id] - traceEvProcStop = 6 // stop of P [timestamp] - traceEvGCStart = 7 // GC start [timestamp, seq, stack id] - traceEvGCDone = 8 // GC done [timestamp] - traceEvSTWStart = 9 // STW start [timestamp, kind] - traceEvSTWDone = 10 // STW done [timestamp] - traceEvGCSweepStart = 11 // GC sweep start [timestamp, stack id] - traceEvGCSweepDone = 12 // GC sweep done [timestamp, swept, reclaimed] - traceEvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id] - traceEvGoStart = 14 // goroutine starts running [timestamp, goroutine id, seq] - traceEvGoEnd = 15 // goroutine ends [timestamp] - traceEvGoStop = 16 // goroutine stops (like in select{}) [timestamp, stack] - traceEvGoSched = 17 // goroutine calls Gosched [timestamp, stack] - traceEvGoPreempt = 18 // goroutine is preempted [timestamp, stack] - traceEvGoSleep = 19 // goroutine calls Sleep [timestamp, stack] - traceEvGoBlock = 20 // goroutine blocks [timestamp, stack] - traceEvGoUnblock = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack] - traceEvGoBlockSend = 22 // goroutine blocks on chan send [timestamp, stack] - traceEvGoBlockRecv = 23 // goroutine blocks on chan recv [timestamp, stack] - traceEvGoBlockSelect = 24 // goroutine blocks on select [timestamp, stack] - traceEvGoBlockSync = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack] - traceEvGoBlockCond = 26 // goroutine blocks on Cond [timestamp, stack] - traceEvGoBlockNet = 27 // goroutine blocks on network [timestamp, stack] - traceEvGoSysCall = 28 // syscall enter [timestamp, stack] - traceEvGoSysExit = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp] - traceEvGoSysBlock = 30 // syscall blocks [timestamp] - traceEvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id] - traceEvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id] - traceEvHeapAlloc = 33 // gcController.heapLive change [timestamp, heap_alloc] - traceEvHeapGoal = 34 // gcController.heapGoal() (formerly next_gc) change [timestamp, heap goal in bytes] - traceEvTimerGoroutine = 35 // not currently used; previously denoted timer goroutine [timer goroutine id] - traceEvFutileWakeup = 36 // not currently used; denotes that the previous wakeup of this goroutine was futile [timestamp] - traceEvString = 37 // string dictionary entry [ID, length, string] - traceEvGoStartLocal = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id] - traceEvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack] - traceEvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp] - traceEvGoStartLabel = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id] - traceEvGoBlockGC = 42 // goroutine blocks on GC assist [timestamp, stack] - traceEvGCMarkAssistStart = 43 // GC mark assist start [timestamp, stack] - traceEvGCMarkAssistDone = 44 // GC mark assist done [timestamp] - traceEvUserTaskCreate = 45 // trace.NewTask [timestamp, internal task id, internal parent task id, name string, stack] - traceEvUserTaskEnd = 46 // end of a task [timestamp, internal task id, stack] - traceEvUserRegion = 47 // trace.WithRegion [timestamp, internal task id, mode(0:start, 1:end), name string, stack] - traceEvUserLog = 48 // trace.Log [timestamp, internal task id, key string id, stack, value string] - traceEvCPUSample = 49 // CPU profiling sample [timestamp, real timestamp, real P id (-1 when absent), goroutine id, stack] - traceEvCount = 50 - // Byte is used but only 6 bits are available for event type. - // The remaining 2 bits are used to specify the number of arguments. - // That means, the max event type value is 63. -) - -// traceBlockReason is an enumeration of reasons a goroutine might block. -// This is the interface the rest of the runtime uses to tell the -// tracer why a goroutine blocked. The tracer then propagates this information -// into the trace however it sees fit. -// -// Note that traceBlockReasons should not be compared, since reasons that are -// distinct by name may *not* be distinct by value. -type traceBlockReason uint8 - -// For maximal efficiency, just map the trace block reason directly to a trace -// event. -const ( - traceBlockGeneric traceBlockReason = traceEvGoBlock - traceBlockForever = traceEvGoStop - traceBlockNet = traceEvGoBlockNet - traceBlockSelect = traceEvGoBlockSelect - traceBlockCondWait = traceEvGoBlockCond - traceBlockSync = traceEvGoBlockSync - traceBlockChanSend = traceEvGoBlockSend - traceBlockChanRecv = traceEvGoBlockRecv - traceBlockGCMarkAssist = traceEvGoBlockGC - traceBlockGCSweep = traceEvGoBlock - traceBlockSystemGoroutine = traceEvGoBlock - traceBlockPreempted = traceEvGoBlock - traceBlockDebugCall = traceEvGoBlock - traceBlockUntilGCEnds = traceEvGoBlock - traceBlockSleep = traceEvGoSleep -) - -const ( - // Timestamps in trace are cputicks/traceTickDiv. - // This makes absolute values of timestamp diffs smaller, - // and so they are encoded in less number of bytes. - // 64 on x86 is somewhat arbitrary (one tick is ~20ns on a 3GHz machine). - // The suggested increment frequency for PowerPC's time base register is - // 512 MHz according to Power ISA v2.07 section 6.2, so we use 16 on ppc64 - // and ppc64le. - traceTimeDiv = 16 + 48*(goarch.Is386|goarch.IsAmd64) - // Maximum number of PCs in a single stack trace. - // Since events contain only stack id rather than whole stack trace, - // we can allow quite large values here. - traceStackSize = 128 - // Identifier of a fake P that is used when we trace without a real P. - traceGlobProc = -1 - // Maximum number of bytes to encode uint64 in base-128. - traceBytesPerNumber = 10 - // Shift of the number of arguments in the first event byte. - traceArgCountShift = 6 -) - -// trace is global tracing context. -var trace struct { - // trace.lock must only be acquired on the system stack where - // stack splits cannot happen while it is held. - lock mutex // protects the following members - enabled bool // when set runtime traces events - shutdown bool // set when we are waiting for trace reader to finish after setting enabled to false - headerWritten bool // whether ReadTrace has emitted trace header - footerWritten bool // whether ReadTrace has emitted trace footer - shutdownSema uint32 // used to wait for ReadTrace completion - seqStart uint64 // sequence number when tracing was started - startTicks int64 // cputicks when tracing was started - endTicks int64 // cputicks when tracing was stopped - startNanotime int64 // nanotime when tracing was started - endNanotime int64 // nanotime when tracing was stopped - startTime traceTime // traceClockNow when tracing started - endTime traceTime // traceClockNow when tracing stopped - seqGC uint64 // GC start/done sequencer - reading traceBufPtr // buffer currently handed off to user - empty traceBufPtr // stack of empty buffers - fullHead traceBufPtr // queue of full buffers - fullTail traceBufPtr - stackTab traceStackTable // maps stack traces to unique ids - // cpuLogRead accepts CPU profile samples from the signal handler where - // they're generated. It uses a two-word header to hold the IDs of the P and - // G (respectively) that were active at the time of the sample. Because - // profBuf uses a record with all zeros in its header to indicate overflow, - // we make sure to make the P field always non-zero: The ID of a real P will - // start at bit 1, and bit 0 will be set. Samples that arrive while no P is - // running (such as near syscalls) will set the first header field to 0b10. - // This careful handling of the first header field allows us to store ID of - // the active G directly in the second field, even though that will be 0 - // when sampling g0. - cpuLogRead *profBuf - // cpuLogBuf is a trace buffer to hold events corresponding to CPU profile - // samples, which arrive out of band and not directly connected to a - // specific P. - cpuLogBuf traceBufPtr - - reader atomic.Pointer[g] // goroutine that called ReadTrace, or nil - - signalLock atomic.Uint32 // protects use of the following member, only usable in signal handlers - cpuLogWrite *profBuf // copy of cpuLogRead for use in signal handlers, set without signalLock - - // Dictionary for traceEvString. - // - // TODO: central lock to access the map is not ideal. - // option: pre-assign ids to all user annotation region names and tags - // option: per-P cache - // option: sync.Map like data structure - stringsLock mutex - strings map[string]uint64 - stringSeq uint64 - - // markWorkerLabels maps gcMarkWorkerMode to string ID. - markWorkerLabels [len(gcMarkWorkerModeStrings)]uint64 - - bufLock mutex // protects buf - buf traceBufPtr // global trace buffer, used when running without a p -} - -// gTraceState is per-G state for the tracer. -type gTraceState struct { - sysExitTime traceTime // timestamp when syscall has returned - tracedSyscallEnter bool // syscall or cgo was entered while trace was enabled or StartTrace has emitted EvGoInSyscall about this goroutine - seq uint64 // trace event sequencer - lastP puintptr // last P emitted an event for this goroutine -} - -// Unused; for compatibility with the new tracer. -func (s *gTraceState) reset() {} - -// mTraceState is per-M state for the tracer. -type mTraceState struct { - startingTrace bool // this M is in TraceStart, potentially before traceEnabled is true - tracedSTWStart bool // this M traced a STW start, so it should trace an end -} - -// pTraceState is per-P state for the tracer. -type pTraceState struct { - buf traceBufPtr - - // inSweep indicates the sweep events should be traced. - // This is used to defer the sweep start event until a span - // has actually been swept. - inSweep bool - - // swept and reclaimed track the number of bytes swept and reclaimed - // by sweeping in the current sweep loop (while inSweep was true). - swept, reclaimed uintptr -} - -// traceLockInit initializes global trace locks. -func traceLockInit() { - lockInit(&trace.bufLock, lockRankTraceBuf) - lockInit(&trace.stringsLock, lockRankTraceStrings) - lockInit(&trace.lock, lockRankTrace) - lockInit(&trace.stackTab.lock, lockRankTraceStackTab) -} - -// traceBufHeader is per-P tracing buffer. -type traceBufHeader struct { - link traceBufPtr // in trace.empty/full - lastTime traceTime // when we wrote the last event - pos int // next write offset in arr - stk [traceStackSize]uintptr // scratch buffer for traceback -} - -// traceBuf is per-P tracing buffer. -type traceBuf struct { - _ sys.NotInHeap - traceBufHeader - arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf -} - -// traceBufPtr is a *traceBuf that is not traced by the garbage -// collector and doesn't have write barriers. traceBufs are not -// allocated from the GC'd heap, so this is safe, and are often -// manipulated in contexts where write barriers are not allowed, so -// this is necessary. -// -// TODO: Since traceBuf is now embedded runtime/internal/sys.NotInHeap, this isn't necessary. -type traceBufPtr uintptr - -func (tp traceBufPtr) ptr() *traceBuf { return (*traceBuf)(unsafe.Pointer(tp)) } -func (tp *traceBufPtr) set(b *traceBuf) { *tp = traceBufPtr(unsafe.Pointer(b)) } -func traceBufPtrOf(b *traceBuf) traceBufPtr { - return traceBufPtr(unsafe.Pointer(b)) -} - -// traceEnabled returns true if the trace is currently enabled. -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func traceEnabled() bool { - return trace.enabled -} - -// traceShuttingDown returns true if the trace is currently shutting down. -// -//go:nosplit -func traceShuttingDown() bool { - return trace.shutdown -} - -// traceLocker represents an M writing trace events. While a traceLocker value -// is valid, the tracer observes all operations on the G/M/P or trace events being -// written as happening atomically. -// -// This doesn't do much for the current tracer, because the current tracer doesn't -// need atomicity around non-trace runtime operations. All the state it needs it -// collects carefully during a STW. -type traceLocker struct { - enabled bool -} - -// traceAcquire prepares this M for writing one or more trace events. -// -// This exists for compatibility with the upcoming new tracer; it doesn't do much -// in the current tracer. -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func traceAcquire() traceLocker { - if !traceEnabled() { - return traceLocker{false} - } - return traceLocker{true} -} - -// ok returns true if the traceLocker is valid (i.e. tracing is enabled). -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func (tl traceLocker) ok() bool { - return tl.enabled -} - -// traceRelease indicates that this M is done writing trace events. -// -// This exists for compatibility with the upcoming new tracer; it doesn't do anything -// in the current tracer. -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func traceRelease(tl traceLocker) { -} - -// StartTrace enables tracing for the current process. -// While tracing, the data will be buffered and available via [ReadTrace]. -// StartTrace returns an error if tracing is already enabled. -// Most clients should use the [runtime/trace] package or the [testing] package's -// -test.trace flag instead of calling StartTrace directly. -func StartTrace() error { - // Stop the world so that we can take a consistent snapshot - // of all goroutines at the beginning of the trace. - // Do not stop the world during GC so we ensure we always see - // a consistent view of GC-related events (e.g. a start is always - // paired with an end). - stw := stopTheWorldGC(stwStartTrace) - - // Prevent sysmon from running any code that could generate events. - lock(&sched.sysmonlock) - - // We are in stop-the-world, but syscalls can finish and write to trace concurrently. - // Exitsyscall could check trace.enabled long before and then suddenly wake up - // and decide to write to trace at a random point in time. - // However, such syscall will use the global trace.buf buffer, because we've - // acquired all p's by doing stop-the-world. So this protects us from such races. - lock(&trace.bufLock) - - if trace.enabled || trace.shutdown { - unlock(&trace.bufLock) - unlock(&sched.sysmonlock) - startTheWorldGC(stw) - return errorString("tracing is already enabled") - } - - // Can't set trace.enabled yet. While the world is stopped, exitsyscall could - // already emit a delayed event (see exitTicks in exitsyscall) if we set trace.enabled here. - // That would lead to an inconsistent trace: - // - either GoSysExit appears before EvGoInSyscall, - // - or GoSysExit appears for a goroutine for which we don't emit EvGoInSyscall below. - // To instruct traceEvent that it must not ignore events below, we set trace.startingTrace. - // trace.enabled is set afterwards once we have emitted all preliminary events. - mp := getg().m - mp.trace.startingTrace = true - - // Obtain current stack ID to use in all traceEvGoCreate events below. - stkBuf := make([]uintptr, traceStackSize) - stackID := traceStackID(mp, stkBuf, 2) - - profBuf := newProfBuf(2, profBufWordCount, profBufTagCount) // after the timestamp, header is [pp.id, gp.goid] - trace.cpuLogRead = profBuf - - // We must not acquire trace.signalLock outside of a signal handler: a - // profiling signal may arrive at any time and try to acquire it, leading to - // deadlock. Because we can't use that lock to protect updates to - // trace.cpuLogWrite (only use of the structure it references), reads and - // writes of the pointer must be atomic. (And although this field is never - // the sole pointer to the profBuf value, it's best to allow a write barrier - // here.) - atomicstorep(unsafe.Pointer(&trace.cpuLogWrite), unsafe.Pointer(profBuf)) - - // World is stopped, no need to lock. - forEachGRace(func(gp *g) { - status := readgstatus(gp) - if status != _Gdead { - gp.trace.seq = 0 - gp.trace.lastP = getg().m.p - // +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum. - id := trace.stackTab.put([]uintptr{logicalStackSentinel, startPCforTrace(gp.startpc) + sys.PCQuantum}) - traceEvent(traceEvGoCreate, -1, gp.goid, uint64(id), stackID) - } - if status == _Gwaiting { - // traceEvGoWaiting is implied to have seq=1. - gp.trace.seq++ - traceEvent(traceEvGoWaiting, -1, gp.goid) - } - if status == _Gsyscall { - gp.trace.seq++ - gp.trace.tracedSyscallEnter = true - traceEvent(traceEvGoInSyscall, -1, gp.goid) - } else if status == _Gdead && gp.m != nil && gp.m.isextra { - // Trigger two trace events for the dead g in the extra m, - // since the next event of the g will be traceEvGoSysExit in exitsyscall, - // while calling from C thread to Go. - gp.trace.seq = 0 - gp.trace.lastP = getg().m.p - // +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum. - id := trace.stackTab.put([]uintptr{logicalStackSentinel, startPCforTrace(0) + sys.PCQuantum}) // no start pc - traceEvent(traceEvGoCreate, -1, gp.goid, uint64(id), stackID) - gp.trace.seq++ - gp.trace.tracedSyscallEnter = true - traceEvent(traceEvGoInSyscall, -1, gp.goid) - } else { - // We need to explicitly clear the flag. A previous trace might have ended with a goroutine - // not emitting a GoSysExit and clearing the flag, leaving it in a stale state. Clearing - // it here makes it unambiguous to any goroutine exiting a syscall racing with us that - // no EvGoInSyscall event was emitted for it. (It's not racy to set this flag here, because - // it'll only get checked when the goroutine runs again, which will be after the world starts - // again.) - gp.trace.tracedSyscallEnter = false - } - }) - // Use a dummy traceLocker. The trace isn't enabled yet, but we can still write events. - tl := traceLocker{} - tl.ProcStart() - tl.GoStart() - // Note: startTicks needs to be set after we emit traceEvGoInSyscall events. - // If we do it the other way around, it is possible that exitsyscall will - // query sysExitTime after startTicks but before traceEvGoInSyscall timestamp. - // It will lead to a false conclusion that cputicks is broken. - trace.startTime = traceClockNow() - trace.startTicks = cputicks() - trace.startNanotime = nanotime() - trace.headerWritten = false - trace.footerWritten = false - - // string to id mapping - // 0 : reserved for an empty string - // remaining: other strings registered by traceString - trace.stringSeq = 0 - trace.strings = make(map[string]uint64) - - trace.seqGC = 0 - mp.trace.startingTrace = false - trace.enabled = true - - // Register runtime goroutine labels. - _, pid, bufp := traceAcquireBuffer() - for i, label := range gcMarkWorkerModeStrings[:] { - trace.markWorkerLabels[i], bufp = traceString(bufp, pid, label) - } - traceReleaseBuffer(mp, pid) - - unlock(&trace.bufLock) - - unlock(&sched.sysmonlock) - - // Record the current state of HeapGoal to avoid information loss in trace. - // - // Use the same dummy trace locker. The trace can't end until after we start - // the world, and we can safely trace from here. - tl.HeapGoal() - - startTheWorldGC(stw) - return nil -} - -// StopTrace stops tracing, if it was previously enabled. -// StopTrace only returns after all the reads for the trace have completed. -func StopTrace() { - // Stop the world so that we can collect the trace buffers from all p's below, - // and also to avoid races with traceEvent. - stw := stopTheWorldGC(stwStopTrace) - - // See the comment in StartTrace. - lock(&sched.sysmonlock) - - // See the comment in StartTrace. - lock(&trace.bufLock) - - if !trace.enabled { - unlock(&trace.bufLock) - unlock(&sched.sysmonlock) - startTheWorldGC(stw) - return - } - - // Trace GoSched for us, and use a dummy locker. The world is stopped - // and we control whether the trace is enabled, so this is safe. - tl := traceLocker{} - tl.GoSched() - - atomicstorep(unsafe.Pointer(&trace.cpuLogWrite), nil) - trace.cpuLogRead.close() - traceReadCPU() - - // Loop over all allocated Ps because dead Ps may still have - // trace buffers. - for _, p := range allp[:cap(allp)] { - buf := p.trace.buf - if buf != 0 { - traceFullQueue(buf) - p.trace.buf = 0 - } - } - if trace.buf != 0 { - buf := trace.buf - trace.buf = 0 - if buf.ptr().pos != 0 { - traceFullQueue(buf) - } - } - if trace.cpuLogBuf != 0 { - buf := trace.cpuLogBuf - trace.cpuLogBuf = 0 - if buf.ptr().pos != 0 { - traceFullQueue(buf) - } - } - - // Wait for startNanotime != endNanotime. On Windows the default interval between - // system clock ticks is typically between 1 and 15 milliseconds, which may not - // have passed since the trace started. Without nanotime moving forward, trace - // tooling has no way of identifying how much real time each cputicks time deltas - // represent. - for { - trace.endTime = traceClockNow() - trace.endTicks = cputicks() - trace.endNanotime = nanotime() - - if trace.endNanotime != trace.startNanotime || faketime != 0 { - break - } - osyield() - } - - trace.enabled = false - trace.shutdown = true - unlock(&trace.bufLock) - - unlock(&sched.sysmonlock) - - startTheWorldGC(stw) - - // The world is started but we've set trace.shutdown, so new tracing can't start. - // Wait for the trace reader to flush pending buffers and stop. - semacquire(&trace.shutdownSema) - if raceenabled { - raceacquire(unsafe.Pointer(&trace.shutdownSema)) - } - - systemstack(func() { - // The lock protects us from races with StartTrace/StopTrace because they do stop-the-world. - lock(&trace.lock) - for _, p := range allp[:cap(allp)] { - if p.trace.buf != 0 { - throw("trace: non-empty trace buffer in proc") - } - } - if trace.buf != 0 { - throw("trace: non-empty global trace buffer") - } - if trace.fullHead != 0 || trace.fullTail != 0 { - throw("trace: non-empty full trace buffer") - } - if trace.reading != 0 || trace.reader.Load() != nil { - throw("trace: reading after shutdown") - } - for trace.empty != 0 { - buf := trace.empty - trace.empty = buf.ptr().link - sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf.ptr()), &memstats.other_sys) - } - trace.strings = nil - trace.shutdown = false - trace.cpuLogRead = nil - unlock(&trace.lock) - }) -} - -// ReadTrace returns the next chunk of binary tracing data, blocking until data -// is available. If tracing is turned off and all the data accumulated while it -// was on has been returned, ReadTrace returns nil. The caller must copy the -// returned data before calling ReadTrace again. -// ReadTrace must be called from one goroutine at a time. -func ReadTrace() []byte { -top: - var buf []byte - var park bool - systemstack(func() { - buf, park = readTrace0() - }) - if park { - gopark(func(gp *g, _ unsafe.Pointer) bool { - if !trace.reader.CompareAndSwapNoWB(nil, gp) { - // We're racing with another reader. - // Wake up and handle this case. - return false - } - - if g2 := traceReader(); gp == g2 { - // New data arrived between unlocking - // and the CAS and we won the wake-up - // race, so wake up directly. - return false - } else if g2 != nil { - printlock() - println("runtime: got trace reader", g2, g2.goid) - throw("unexpected trace reader") - } - - return true - }, nil, waitReasonTraceReaderBlocked, traceBlockSystemGoroutine, 2) - goto top - } - - return buf -} - -// readTrace0 is ReadTrace's continuation on g0. This must run on the -// system stack because it acquires trace.lock. -// -//go:systemstack -func readTrace0() (buf []byte, park bool) { - if raceenabled { - // g0 doesn't have a race context. Borrow the user G's. - if getg().racectx != 0 { - throw("expected racectx == 0") - } - getg().racectx = getg().m.curg.racectx - // (This defer should get open-coded, which is safe on - // the system stack.) - defer func() { getg().racectx = 0 }() - } - - // Optimistically look for CPU profile samples. This may write new stack - // records, and may write new tracing buffers. This must be done with the - // trace lock not held. footerWritten and shutdown are safe to access - // here. They are only mutated by this goroutine or during a STW. - if !trace.footerWritten && !trace.shutdown { - traceReadCPU() - } - - // This function must not allocate while holding trace.lock: - // allocation can call heap allocate, which will try to emit a trace - // event while holding heap lock. - lock(&trace.lock) - - if trace.reader.Load() != nil { - // More than one goroutine reads trace. This is bad. - // But we rather do not crash the program because of tracing, - // because tracing can be enabled at runtime on prod servers. - unlock(&trace.lock) - println("runtime: ReadTrace called from multiple goroutines simultaneously") - return nil, false - } - // Recycle the old buffer. - if buf := trace.reading; buf != 0 { - buf.ptr().link = trace.empty - trace.empty = buf - trace.reading = 0 - } - // Write trace header. - if !trace.headerWritten { - trace.headerWritten = true - unlock(&trace.lock) - return []byte("go 1.21 trace\x00\x00\x00"), false - } - // Wait for new data. - if trace.fullHead == 0 && !trace.shutdown { - // We don't simply use a note because the scheduler - // executes this goroutine directly when it wakes up - // (also a note would consume an M). - unlock(&trace.lock) - return nil, true - } -newFull: - assertLockHeld(&trace.lock) - // Write a buffer. - if trace.fullHead != 0 { - buf := traceFullDequeue() - trace.reading = buf - unlock(&trace.lock) - return buf.ptr().arr[:buf.ptr().pos], false - } - - // Write footer with timer frequency. - if !trace.footerWritten { - trace.footerWritten = true - freq := (float64(trace.endTicks-trace.startTicks) / traceTimeDiv) / (float64(trace.endNanotime-trace.startNanotime) / 1e9) - if freq <= 0 { - throw("trace: ReadTrace got invalid frequency") - } - unlock(&trace.lock) - - // Write frequency event. - bufp := traceFlush(0, 0) - buf := bufp.ptr() - buf.byte(traceEvFrequency | 0< 0, write current stack id as the last argument (skipping skip top frames). -// If skip = 0, this event type should contain a stack, but we don't want -// to collect and remember it for this particular call. -func traceEvent(ev byte, skip int, args ...uint64) { - mp, pid, bufp := traceAcquireBuffer() - // Double-check trace.enabled now that we've done m.locks++ and acquired bufLock. - // This protects from races between traceEvent and StartTrace/StopTrace. - - // The caller checked that trace.enabled == true, but trace.enabled might have been - // turned off between the check and now. Check again. traceLockBuffer did mp.locks++, - // StopTrace does stopTheWorld, and stopTheWorld waits for mp.locks to go back to zero, - // so if we see trace.enabled == true now, we know it's true for the rest of the function. - // Exitsyscall can run even during stopTheWorld. The race with StartTrace/StopTrace - // during tracing in exitsyscall is resolved by locking trace.bufLock in traceLockBuffer. - // - // Note trace_userTaskCreate runs the same check. - if !trace.enabled && !mp.trace.startingTrace { - traceReleaseBuffer(mp, pid) - return - } - - if skip > 0 { - if getg() == mp.curg { - skip++ // +1 because stack is captured in traceEventLocked. - } - } - traceEventLocked(0, mp, pid, bufp, ev, 0, skip, args...) - traceReleaseBuffer(mp, pid) -} - -// traceEventLocked writes a single event of type ev to the trace buffer bufp, -// flushing the buffer if necessary. pid is the id of the current P, or -// traceGlobProc if we're tracing without a real P. -// -// Preemption is disabled, and if running without a real P the global tracing -// buffer is locked. -// -// Events types that do not include a stack set skip to -1. Event types that -// include a stack may explicitly reference a stackID from the trace.stackTab -// (obtained by an earlier call to traceStackID). Without an explicit stackID, -// this function will automatically capture the stack of the goroutine currently -// running on mp, skipping skip top frames or, if skip is 0, writing out an -// empty stack record. -// -// It records the event's args to the traceBuf, and also makes an effort to -// reserve extraBytes bytes of additional space immediately following the event, -// in the same traceBuf. -func traceEventLocked(extraBytes int, mp *m, pid int32, bufp *traceBufPtr, ev byte, stackID uint32, skip int, args ...uint64) { - buf := bufp.ptr() - // TODO: test on non-zero extraBytes param. - maxSize := 2 + 5*traceBytesPerNumber + extraBytes // event type, length, sequence, timestamp, stack id and two add params - if buf == nil || len(buf.arr)-buf.pos < maxSize { - systemstack(func() { - buf = traceFlush(traceBufPtrOf(buf), pid).ptr() - }) - bufp.set(buf) - } - - ts := traceClockNow() - if ts <= buf.lastTime { - ts = buf.lastTime + 1 - } - tsDiff := uint64(ts - buf.lastTime) - buf.lastTime = ts - narg := byte(len(args)) - if stackID != 0 || skip >= 0 { - narg++ - } - // We have only 2 bits for number of arguments. - // If number is >= 3, then the event type is followed by event length in bytes. - if narg > 3 { - narg = 3 - } - startPos := buf.pos - buf.byte(ev | narg< 0 { - buf.varint(traceStackID(mp, buf.stk[:], skip)) - } - evSize := buf.pos - startPos - if evSize > maxSize { - throw("invalid length of trace event") - } - if lenp != nil { - // Fill in actual length. - *lenp = byte(evSize - 2) - } -} - -// traceCPUSample writes a CPU profile sample stack to the execution tracer's -// profiling buffer. It is called from a signal handler, so is limited in what -// it can do. -func traceCPUSample(gp *g, _ *m, pp *p, stk []uintptr) { - if !traceEnabled() { - // Tracing is usually turned off; don't spend time acquiring the signal - // lock unless it's active. - return - } - - // Match the clock used in traceEventLocked - now := traceClockNow() - // The "header" here is the ID of the P that was running the profiled code, - // followed by the ID of the goroutine. (For normal CPU profiling, it's - // usually the number of samples with the given stack.) Near syscalls, pp - // may be nil. Reporting goid of 0 is fine for either g0 or a nil gp. - var hdr [2]uint64 - if pp != nil { - // Overflow records in profBuf have all header values set to zero. Make - // sure that real headers have at least one bit set. - hdr[0] = uint64(pp.id)<<1 | 0b1 - } else { - hdr[0] = 0b10 - } - if gp != nil { - hdr[1] = gp.goid - } - - // Allow only one writer at a time - for !trace.signalLock.CompareAndSwap(0, 1) { - // TODO: Is it safe to osyield here? https://go.dev/issue/52672 - osyield() - } - - if log := (*profBuf)(atomic.Loadp(unsafe.Pointer(&trace.cpuLogWrite))); log != nil { - // Note: we don't pass a tag pointer here (how should profiling tags - // interact with the execution tracer?), but if we did we'd need to be - // careful about write barriers. See the long comment in profBuf.write. - log.write(nil, int64(now), hdr[:], stk) - } - - trace.signalLock.Store(0) -} - -func traceReadCPU() { - bufp := &trace.cpuLogBuf - - for { - data, tags, _ := trace.cpuLogRead.read(profBufNonBlocking) - if len(data) == 0 { - break - } - for len(data) > 0 { - if len(data) < 4 || data[0] > uint64(len(data)) { - break // truncated profile - } - if data[0] < 4 || tags != nil && len(tags) < 1 { - break // malformed profile - } - if len(tags) < 1 { - break // mismatched profile records and tags - } - timestamp := data[1] - ppid := data[2] >> 1 - if hasP := (data[2] & 0b1) != 0; !hasP { - ppid = ^uint64(0) - } - goid := data[3] - stk := data[4:data[0]] - empty := len(stk) == 1 && data[2] == 0 && data[3] == 0 - data = data[data[0]:] - // No support here for reporting goroutine tags at the moment; if - // that information is to be part of the execution trace, we'd - // probably want to see when the tags are applied and when they - // change, instead of only seeing them when we get a CPU sample. - tags = tags[1:] - - if empty { - // Looks like an overflow record from the profBuf. Not much to - // do here, we only want to report full records. - // - // TODO: should we start a goroutine to drain the profBuf, - // rather than relying on a high-enough volume of tracing events - // to keep ReadTrace busy? https://go.dev/issue/52674 - continue - } - - buf := bufp.ptr() - if buf == nil { - systemstack(func() { - *bufp = traceFlush(*bufp, 0) - }) - buf = bufp.ptr() - } - nstk := 1 - buf.stk[0] = logicalStackSentinel - for ; nstk < len(buf.stk) && nstk-1 < len(stk); nstk++ { - buf.stk[nstk] = uintptr(stk[nstk-1]) - } - stackID := trace.stackTab.put(buf.stk[:nstk]) - - traceEventLocked(0, nil, 0, bufp, traceEvCPUSample, stackID, 1, timestamp, ppid, goid) - } - } -} - -// logicalStackSentinel is a sentinel value at pcBuf[0] signifying that -// pcBuf[1:] holds a logical stack requiring no further processing. Any other -// value at pcBuf[0] represents a skip value to apply to the physical stack in -// pcBuf[1:] after inline expansion. -const logicalStackSentinel = ^uintptr(0) - -// traceStackID captures a stack trace into pcBuf, registers it in the trace -// stack table, and returns its unique ID. pcBuf should have a length equal to -// traceStackSize. skip controls the number of leaf frames to omit in order to -// hide tracer internals from stack traces, see CL 5523. -func traceStackID(mp *m, pcBuf []uintptr, skip int) uint64 { - gp := getg() - curgp := mp.curg - nstk := 1 - if tracefpunwindoff() || mp.hasCgoOnStack() { - // Slow path: Unwind using default unwinder. Used when frame pointer - // unwinding is unavailable or disabled (tracefpunwindoff), or might - // produce incomplete results or crashes (hasCgoOnStack). Note that no - // cgo callback related crashes have been observed yet. The main - // motivation is to take advantage of a potentially registered cgo - // symbolizer. - pcBuf[0] = logicalStackSentinel - if curgp == gp { - nstk += callers(skip+1, pcBuf[1:]) - } else if curgp != nil { - nstk += gcallers(curgp, skip, pcBuf[1:]) - } - } else { - // Fast path: Unwind using frame pointers. - pcBuf[0] = uintptr(skip) - if curgp == gp { - nstk += fpTracebackPCs(unsafe.Pointer(getfp()), pcBuf[1:]) - } else if curgp != nil { - // We're called on the g0 stack through mcall(fn) or systemstack(fn). To - // behave like gcallers above, we start unwinding from sched.bp, which - // points to the caller frame of the leaf frame on g's stack. The return - // address of the leaf frame is stored in sched.pc, which we manually - // capture here. - pcBuf[1] = curgp.sched.pc - nstk += 1 + fpTracebackPCs(unsafe.Pointer(curgp.sched.bp), pcBuf[2:]) - } - } - if nstk > 0 { - nstk-- // skip runtime.goexit - } - if nstk > 0 && curgp.goid == 1 { - nstk-- // skip runtime.main - } - id := trace.stackTab.put(pcBuf[:nstk]) - return uint64(id) -} - -// tracefpunwindoff returns true if frame pointer unwinding for the tracer is -// disabled via GODEBUG or not supported by the architecture. -// TODO(#60254): support frame pointer unwinding on plan9/amd64. -func tracefpunwindoff() bool { - return debug.tracefpunwindoff != 0 || (goarch.ArchFamily != goarch.AMD64 && goarch.ArchFamily != goarch.ARM64) || goos.IsPlan9 == 1 -} - -// fpTracebackPCs populates pcBuf with the return addresses for each frame and -// returns the number of PCs written to pcBuf. The returned PCs correspond to -// "physical frames" rather than "logical frames"; that is if A is inlined into -// B, this will return a PC for only B. -func fpTracebackPCs(fp unsafe.Pointer, pcBuf []uintptr) (i int) { - for i = 0; i < len(pcBuf) && fp != nil; i++ { - // return addr sits one word above the frame pointer - pcBuf[i] = *(*uintptr)(unsafe.Pointer(uintptr(fp) + goarch.PtrSize)) - // follow the frame pointer to the next one - fp = unsafe.Pointer(*(*uintptr)(fp)) - } - return i -} - -// traceAcquireBuffer returns trace buffer to use and, if necessary, locks it. -func traceAcquireBuffer() (mp *m, pid int32, bufp *traceBufPtr) { - // Any time we acquire a buffer, we may end up flushing it, - // but flushes are rare. Record the lock edge even if it - // doesn't happen this time. - lockRankMayTraceFlush() - - mp = acquirem() - if p := mp.p.ptr(); p != nil { - return mp, p.id, &p.trace.buf - } - lock(&trace.bufLock) - return mp, traceGlobProc, &trace.buf -} - -// traceReleaseBuffer releases a buffer previously acquired with traceAcquireBuffer. -func traceReleaseBuffer(mp *m, pid int32) { - if pid == traceGlobProc { - unlock(&trace.bufLock) - } - releasem(mp) -} - -// lockRankMayTraceFlush records the lock ranking effects of a -// potential call to traceFlush. -func lockRankMayTraceFlush() { - lockWithRankMayAcquire(&trace.lock, getLockRank(&trace.lock)) -} - -// traceFlush puts buf onto stack of full buffers and returns an empty buffer. -// -// This must run on the system stack because it acquires trace.lock. -// -//go:systemstack -func traceFlush(buf traceBufPtr, pid int32) traceBufPtr { - lock(&trace.lock) - if buf != 0 { - traceFullQueue(buf) - } - if trace.empty != 0 { - buf = trace.empty - trace.empty = buf.ptr().link - } else { - buf = traceBufPtr(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys)) - if buf == 0 { - throw("trace: out of memory") - } - } - bufp := buf.ptr() - bufp.link.set(nil) - bufp.pos = 0 - - // initialize the buffer for a new batch - ts := traceClockNow() - if ts <= bufp.lastTime { - ts = bufp.lastTime + 1 - } - bufp.lastTime = ts - bufp.byte(traceEvBatch | 1<= 0x80; v >>= 7 { - buf.arr[pos] = 0x80 | byte(v) - pos++ - } - buf.arr[pos] = byte(v) - pos++ - buf.pos = pos -} - -// varintAt writes varint v at byte position pos in buf. This always -// consumes traceBytesPerNumber bytes. This is intended for when the -// caller needs to reserve space for a varint but can't populate it -// until later. -func (buf *traceBuf) varintAt(pos int, v uint64) { - for i := 0; i < traceBytesPerNumber; i++ { - if i < traceBytesPerNumber-1 { - buf.arr[pos] = 0x80 | byte(v) - } else { - buf.arr[pos] = byte(v) - } - v >>= 7 - pos++ - } -} - -// byte appends v to buf. -func (buf *traceBuf) byte(v byte) { - buf.arr[buf.pos] = v - buf.pos++ -} - -// traceStackTable maps stack traces (arrays of PC's) to unique uint32 ids. -// It is lock-free for reading. -type traceStackTable struct { - lock mutex // Must be acquired on the system stack - seq uint32 - mem traceAlloc - tab [1 << 13]traceStackPtr -} - -// traceStack is a single stack in traceStackTable. -type traceStack struct { - link traceStackPtr - hash uintptr - id uint32 - n int - stk [0]uintptr // real type [n]uintptr -} - -type traceStackPtr uintptr - -func (tp traceStackPtr) ptr() *traceStack { return (*traceStack)(unsafe.Pointer(tp)) } - -// stack returns slice of PCs. -func (ts *traceStack) stack() []uintptr { - return (*[traceStackSize]uintptr)(unsafe.Pointer(&ts.stk))[:ts.n] -} - -// put returns a unique id for the stack trace pcs and caches it in the table, -// if it sees the trace for the first time. -func (tab *traceStackTable) put(pcs []uintptr) uint32 { - if len(pcs) == 0 { - return 0 - } - hash := memhash(unsafe.Pointer(&pcs[0]), 0, uintptr(len(pcs))*unsafe.Sizeof(pcs[0])) - // First, search the hashtable w/o the mutex. - if id := tab.find(pcs, hash); id != 0 { - return id - } - // Now, double check under the mutex. - // Switch to the system stack so we can acquire tab.lock - var id uint32 - systemstack(func() { - lock(&tab.lock) - if id = tab.find(pcs, hash); id != 0 { - unlock(&tab.lock) - return - } - // Create new record. - tab.seq++ - stk := tab.newStack(len(pcs)) - stk.hash = hash - stk.id = tab.seq - id = stk.id - stk.n = len(pcs) - stkpc := stk.stack() - copy(stkpc, pcs) - part := int(hash % uintptr(len(tab.tab))) - stk.link = tab.tab[part] - atomicstorep(unsafe.Pointer(&tab.tab[part]), unsafe.Pointer(stk)) - unlock(&tab.lock) - }) - return id -} - -// find checks if the stack trace pcs is already present in the table. -func (tab *traceStackTable) find(pcs []uintptr, hash uintptr) uint32 { - part := int(hash % uintptr(len(tab.tab))) -Search: - for stk := tab.tab[part].ptr(); stk != nil; stk = stk.link.ptr() { - if stk.hash == hash && stk.n == len(pcs) { - for i, stkpc := range stk.stack() { - if stkpc != pcs[i] { - continue Search - } - } - return stk.id - } - } - return 0 -} - -// newStack allocates a new stack of size n. -func (tab *traceStackTable) newStack(n int) *traceStack { - return (*traceStack)(tab.mem.alloc(unsafe.Sizeof(traceStack{}) + uintptr(n)*goarch.PtrSize)) -} - -// traceFrames returns the frames corresponding to pcs. It may -// allocate and may emit trace events. -func traceFrames(bufp traceBufPtr, pcs []uintptr) ([]traceFrame, traceBufPtr) { - frames := make([]traceFrame, 0, len(pcs)) - ci := CallersFrames(pcs) - for { - var frame traceFrame - f, more := ci.Next() - frame, bufp = traceFrameForPC(bufp, 0, f) - frames = append(frames, frame) - if !more { - return frames, bufp - } - } -} - -// dump writes all previously cached stacks to trace buffers, -// releases all memory and resets state. -// -// This must run on the system stack because it calls traceFlush. -// -//go:systemstack -func (tab *traceStackTable) dump(bufp traceBufPtr) traceBufPtr { - for i := range tab.tab { - stk := tab.tab[i].ptr() - for ; stk != nil; stk = stk.link.ptr() { - var frames []traceFrame - frames, bufp = traceFrames(bufp, fpunwindExpand(stk.stack())) - - // Estimate the size of this record. This - // bound is pretty loose, but avoids counting - // lots of varint sizes. - maxSize := 1 + traceBytesPerNumber + (2+4*len(frames))*traceBytesPerNumber - // Make sure we have enough buffer space. - if buf := bufp.ptr(); len(buf.arr)-buf.pos < maxSize { - bufp = traceFlush(bufp, 0) - } - - // Emit header, with space reserved for length. - buf := bufp.ptr() - buf.byte(traceEvStack | 3< 0 && pcBuf[0] == logicalStackSentinel { - // pcBuf contains logical rather than inlined frames, skip has already been - // applied, just return it without the sentinel value in pcBuf[0]. - return pcBuf[1:] - } - - var ( - lastFuncID = abi.FuncIDNormal - newPCBuf = make([]uintptr, 0, traceStackSize) - skip = pcBuf[0] - // skipOrAdd skips or appends retPC to newPCBuf and returns true if more - // pcs can be added. - skipOrAdd = func(retPC uintptr) bool { - if skip > 0 { - skip-- - } else { - newPCBuf = append(newPCBuf, retPC) - } - return len(newPCBuf) < cap(newPCBuf) - } - ) - -outer: - for _, retPC := range pcBuf[1:] { - callPC := retPC - 1 - fi := findfunc(callPC) - if !fi.valid() { - // There is no funcInfo if callPC belongs to a C function. In this case - // we still keep the pc, but don't attempt to expand inlined frames. - if more := skipOrAdd(retPC); !more { - break outer - } - continue - } - - u, uf := newInlineUnwinder(fi, callPC) - for ; uf.valid(); uf = u.next(uf) { - sf := u.srcFunc(uf) - if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(lastFuncID) { - // ignore wrappers - } else if more := skipOrAdd(uf.pc + 1); !more { - break outer - } - lastFuncID = sf.funcID - } - } - return newPCBuf -} - -type traceFrame struct { - PC uintptr - funcID uint64 - fileID uint64 - line uint64 -} - -// traceFrameForPC records the frame information. -// It may allocate memory. -func traceFrameForPC(buf traceBufPtr, pid int32, f Frame) (traceFrame, traceBufPtr) { - bufp := &buf - var frame traceFrame - frame.PC = f.PC - - fn := f.Function - const maxLen = 1 << 10 - if len(fn) > maxLen { - fn = fn[len(fn)-maxLen:] - } - frame.funcID, bufp = traceString(bufp, pid, fn) - frame.line = uint64(f.Line) - file := f.File - if len(file) > maxLen { - file = file[len(file)-maxLen:] - } - frame.fileID, bufp = traceString(bufp, pid, file) - return frame, (*bufp) -} - -// traceAlloc is a non-thread-safe region allocator. -// It holds a linked list of traceAllocBlock. -type traceAlloc struct { - head traceAllocBlockPtr - off uintptr -} - -// traceAllocBlock is a block in traceAlloc. -// -// traceAllocBlock is allocated from non-GC'd memory, so it must not -// contain heap pointers. Writes to pointers to traceAllocBlocks do -// not need write barriers. -type traceAllocBlock struct { - _ sys.NotInHeap - next traceAllocBlockPtr - data [64<<10 - goarch.PtrSize]byte -} - -// TODO: Since traceAllocBlock is now embedded runtime/internal/sys.NotInHeap, this isn't necessary. -type traceAllocBlockPtr uintptr - -func (p traceAllocBlockPtr) ptr() *traceAllocBlock { return (*traceAllocBlock)(unsafe.Pointer(p)) } -func (p *traceAllocBlockPtr) set(x *traceAllocBlock) { *p = traceAllocBlockPtr(unsafe.Pointer(x)) } - -// alloc allocates n-byte block. -func (a *traceAlloc) alloc(n uintptr) unsafe.Pointer { - n = alignUp(n, goarch.PtrSize) - if a.head == 0 || a.off+n > uintptr(len(a.head.ptr().data)) { - if n > uintptr(len(a.head.ptr().data)) { - throw("trace: alloc too large") - } - block := (*traceAllocBlock)(sysAlloc(unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys)) - if block == nil { - throw("trace: out of memory") - } - block.next.set(a.head.ptr()) - a.head.set(block) - a.off = 0 - } - p := &a.head.ptr().data[a.off] - a.off += n - return unsafe.Pointer(p) -} - -// drop frees all previously allocated memory and resets the allocator. -func (a *traceAlloc) drop() { - for a.head != 0 { - block := a.head.ptr() - a.head.set(block.next.ptr()) - sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys) - } -} - -// The following functions write specific events to trace. - -func (_ traceLocker) Gomaxprocs(procs int32) { - traceEvent(traceEvGomaxprocs, 1, uint64(procs)) -} - -func (_ traceLocker) ProcStart() { - traceEvent(traceEvProcStart, -1, uint64(getg().m.id)) -} - -func (_ traceLocker) ProcStop(pp *p) { - // Sysmon and stopTheWorld can stop Ps blocked in syscalls, - // to handle this we temporary employ the P. - mp := acquirem() - oldp := mp.p - mp.p.set(pp) - traceEvent(traceEvProcStop, -1) - mp.p = oldp - releasem(mp) -} - -func (_ traceLocker) GCStart() { - traceEvent(traceEvGCStart, 3, trace.seqGC) - trace.seqGC++ -} - -func (_ traceLocker) GCDone() { - traceEvent(traceEvGCDone, -1) -} - -func (_ traceLocker) STWStart(reason stwReason) { - // Don't trace if this STW is for trace start/stop, since traceEnabled - // switches during a STW. - if reason == stwStartTrace || reason == stwStopTrace { - return - } - getg().m.trace.tracedSTWStart = true - traceEvent(traceEvSTWStart, -1, uint64(reason)) -} - -func (_ traceLocker) STWDone() { - mp := getg().m - if !mp.trace.tracedSTWStart { - return - } - mp.trace.tracedSTWStart = false - traceEvent(traceEvSTWDone, -1) -} - -// traceGCSweepStart prepares to trace a sweep loop. This does not -// emit any events until traceGCSweepSpan is called. -// -// traceGCSweepStart must be paired with traceGCSweepDone and there -// must be no preemption points between these two calls. -func (_ traceLocker) GCSweepStart() { - // Delay the actual GCSweepStart event until the first span - // sweep. If we don't sweep anything, don't emit any events. - pp := getg().m.p.ptr() - if pp.trace.inSweep { - throw("double traceGCSweepStart") - } - pp.trace.inSweep, pp.trace.swept, pp.trace.reclaimed = true, 0, 0 -} - -// traceGCSweepSpan traces the sweep of a single page. -// -// This may be called outside a traceGCSweepStart/traceGCSweepDone -// pair; however, it will not emit any trace events in this case. -func (_ traceLocker) GCSweepSpan(bytesSwept uintptr) { - pp := getg().m.p.ptr() - if pp.trace.inSweep { - if pp.trace.swept == 0 { - traceEvent(traceEvGCSweepStart, 1) - } - pp.trace.swept += bytesSwept - } -} - -func (_ traceLocker) GCSweepDone() { - pp := getg().m.p.ptr() - if !pp.trace.inSweep { - throw("missing traceGCSweepStart") - } - if pp.trace.swept != 0 { - traceEvent(traceEvGCSweepDone, -1, uint64(pp.trace.swept), uint64(pp.trace.reclaimed)) - } - pp.trace.inSweep = false -} - -func (_ traceLocker) GCMarkAssistStart() { - traceEvent(traceEvGCMarkAssistStart, 1) -} - -func (_ traceLocker) GCMarkAssistDone() { - traceEvent(traceEvGCMarkAssistDone, -1) -} - -func (_ traceLocker) GoCreate(newg *g, pc uintptr) { - newg.trace.seq = 0 - newg.trace.lastP = getg().m.p - // +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum. - id := trace.stackTab.put([]uintptr{logicalStackSentinel, startPCforTrace(pc) + sys.PCQuantum}) - traceEvent(traceEvGoCreate, 2, newg.goid, uint64(id)) -} - -func (_ traceLocker) GoStart() { - gp := getg().m.curg - pp := gp.m.p - gp.trace.seq++ - if pp.ptr().gcMarkWorkerMode != gcMarkWorkerNotWorker { - traceEvent(traceEvGoStartLabel, -1, gp.goid, gp.trace.seq, trace.markWorkerLabels[pp.ptr().gcMarkWorkerMode]) - } else if gp.trace.lastP == pp { - traceEvent(traceEvGoStartLocal, -1, gp.goid) - } else { - gp.trace.lastP = pp - traceEvent(traceEvGoStart, -1, gp.goid, gp.trace.seq) - } -} - -func (_ traceLocker) GoEnd() { - traceEvent(traceEvGoEnd, -1) -} - -func (_ traceLocker) GoSched() { - gp := getg() - gp.trace.lastP = gp.m.p - traceEvent(traceEvGoSched, 1) -} - -func (_ traceLocker) GoPreempt() { - gp := getg() - gp.trace.lastP = gp.m.p - traceEvent(traceEvGoPreempt, 1) -} - -func (_ traceLocker) GoPark(reason traceBlockReason, skip int) { - // Convert the block reason directly to a trace event type. - // See traceBlockReason for more information. - traceEvent(byte(reason), skip) -} - -func (_ traceLocker) GoUnpark(gp *g, skip int) { - pp := getg().m.p - gp.trace.seq++ - if gp.trace.lastP == pp { - traceEvent(traceEvGoUnblockLocal, skip, gp.goid) - } else { - gp.trace.lastP = pp - traceEvent(traceEvGoUnblock, skip, gp.goid, gp.trace.seq) - } -} - -func (_ traceLocker) GoSysCall() { - var skip int - switch { - case tracefpunwindoff(): - // Unwind by skipping 1 frame relative to gp.syscallsp which is captured 3 - // frames above this frame. For frame pointer unwinding we produce the same - // results by hard coding the number of frames in between our caller and the - // actual syscall, see cases below. - // TODO(felixge): Implement gp.syscallbp to avoid this workaround? - skip = 1 - case GOOS == "solaris" || GOOS == "illumos": - // These platforms don't use a libc_read_trampoline. - skip = 3 - default: - // Skip the extra trampoline frame used on most systems. - skip = 4 - } - getg().m.curg.trace.tracedSyscallEnter = true - traceEvent(traceEvGoSysCall, skip) -} - -func (_ traceLocker) GoSysExit(lostP bool) { - if !lostP { - throw("lostP must always be true in the old tracer for GoSysExit") - } - gp := getg().m.curg - if !gp.trace.tracedSyscallEnter { - // There was no syscall entry traced for us at all, so there's definitely - // no EvGoSysBlock or EvGoInSyscall before us, which EvGoSysExit requires. - return - } - gp.trace.tracedSyscallEnter = false - ts := gp.trace.sysExitTime - if ts != 0 && ts < trace.startTime { - // There is a race between the code that initializes sysExitTimes - // (in exitsyscall, which runs without a P, and therefore is not - // stopped with the rest of the world) and the code that initializes - // a new trace. The recorded sysExitTime must therefore be treated - // as "best effort". If they are valid for this trace, then great, - // use them for greater accuracy. But if they're not valid for this - // trace, assume that the trace was started after the actual syscall - // exit (but before we actually managed to start the goroutine, - // aka right now), and assign a fresh time stamp to keep the log consistent. - ts = 0 - } - gp.trace.sysExitTime = 0 - gp.trace.seq++ - gp.trace.lastP = gp.m.p - traceEvent(traceEvGoSysExit, -1, gp.goid, gp.trace.seq, uint64(ts)) -} - -// nosplit because it's called from exitsyscall without a P. -// -//go:nosplit -func (_ traceLocker) RecordSyscallExitedTime(gp *g, oldp *p) { - // Wait till traceGoSysBlock event is emitted. - // This ensures consistency of the trace (the goroutine is started after it is blocked). - for oldp != nil && oldp.syscalltick == gp.m.syscalltick { - osyield() - } - // We can't trace syscall exit right now because we don't have a P. - // Tracing code can invoke write barriers that cannot run without a P. - // So instead we remember the syscall exit time and emit the event - // in execute when we have a P. - gp.trace.sysExitTime = traceClockNow() -} - -func (_ traceLocker) GoSysBlock(pp *p) { - // Sysmon and stopTheWorld can declare syscalls running on remote Ps as blocked, - // to handle this we temporary employ the P. - mp := acquirem() - oldp := mp.p - mp.p.set(pp) - traceEvent(traceEvGoSysBlock, -1) - mp.p = oldp - releasem(mp) -} - -func (t traceLocker) ProcSteal(pp *p, forMe bool) { - t.ProcStop(pp) -} - -func (_ traceLocker) HeapAlloc(live uint64) { - traceEvent(traceEvHeapAlloc, -1, live) -} - -func (_ traceLocker) HeapGoal() { - heapGoal := gcController.heapGoal() - if heapGoal == ^uint64(0) { - // Heap-based triggering is disabled. - traceEvent(traceEvHeapGoal, -1, 0) - } else { - traceEvent(traceEvHeapGoal, -1, heapGoal) - } -} - -// To access runtime functions from runtime/trace. -// See runtime/trace/annotation.go - -//go:linkname trace_userTaskCreate runtime/trace.userTaskCreate -func trace_userTaskCreate(id, parentID uint64, taskType string) { - if !trace.enabled { - return - } - - // Same as in traceEvent. - mp, pid, bufp := traceAcquireBuffer() - if !trace.enabled && !mp.trace.startingTrace { - traceReleaseBuffer(mp, pid) - return - } - - typeStringID, bufp := traceString(bufp, pid, taskType) - traceEventLocked(0, mp, pid, bufp, traceEvUserTaskCreate, 0, 3, id, parentID, typeStringID) - traceReleaseBuffer(mp, pid) -} - -//go:linkname trace_userTaskEnd runtime/trace.userTaskEnd -func trace_userTaskEnd(id uint64) { - traceEvent(traceEvUserTaskEnd, 2, id) -} - -//go:linkname trace_userRegion runtime/trace.userRegion -func trace_userRegion(id, mode uint64, name string) { - if !trace.enabled { - return - } - - mp, pid, bufp := traceAcquireBuffer() - if !trace.enabled && !mp.trace.startingTrace { - traceReleaseBuffer(mp, pid) - return - } - - nameStringID, bufp := traceString(bufp, pid, name) - traceEventLocked(0, mp, pid, bufp, traceEvUserRegion, 0, 3, id, mode, nameStringID) - traceReleaseBuffer(mp, pid) -} - -//go:linkname trace_userLog runtime/trace.userLog -func trace_userLog(id uint64, category, message string) { - if !trace.enabled { - return - } - - mp, pid, bufp := traceAcquireBuffer() - if !trace.enabled && !mp.trace.startingTrace { - traceReleaseBuffer(mp, pid) - return - } - - categoryID, bufp := traceString(bufp, pid, category) - - // The log message is recorded after all of the normal trace event - // arguments, including the task, category, and stack IDs. We must ask - // traceEventLocked to reserve extra space for the length of the message - // and the message itself. - extraSpace := traceBytesPerNumber + len(message) - traceEventLocked(extraSpace, mp, pid, bufp, traceEvUserLog, 0, 3, id, categoryID) - buf := bufp.ptr() - - // double-check the message and its length can fit. - // Otherwise, truncate the message. - slen := len(message) - if room := len(buf.arr) - buf.pos; room < slen+traceBytesPerNumber { - slen = room - } - buf.varint(uint64(slen)) - buf.pos += copy(buf.arr[buf.pos:], message[:slen]) - - traceReleaseBuffer(mp, pid) -} - -// the start PC of a goroutine for tracing purposes. If pc is a wrapper, -// it returns the PC of the wrapped function. Otherwise it returns pc. -func startPCforTrace(pc uintptr) uintptr { - f := findfunc(pc) - if !f.valid() { - return pc // may happen for locked g in extra M since its pc is 0. - } - w := funcdata(f, abi.FUNCDATA_WrapInfo) - if w == nil { - return pc // not a wrapper - } - return f.datap.textAddr(*(*uint32)(w)) -} - -// OneNewExtraM registers the fact that a new extra M was created with -// the tracer. This matters if the M (which has an attached G) is used while -// the trace is still active because if it is, we need the fact that it exists -// to show up in the final trace. -func (tl traceLocker) OneNewExtraM(gp *g) { - // Trigger two trace events for the locked g in the extra m, - // since the next event of the g will be traceEvGoSysExit in exitsyscall, - // while calling from C thread to Go. - tl.GoCreate(gp, 0) // no start pc - gp.trace.seq++ - traceEvent(traceEvGoInSyscall, -1, gp.goid) -} - -// Used only in the new tracer. -func (tl traceLocker) GoCreateSyscall(gp *g) { -} - -// Used only in the new tracer. -func (tl traceLocker) GoDestroySyscall() { -} - -// traceTime represents a timestamp for the trace. -type traceTime uint64 - -// traceClockNow returns a monotonic timestamp. The clock this function gets -// the timestamp from is specific to tracing, and shouldn't be mixed with other -// clock sources. -// -// nosplit because it's called from exitsyscall, which is nosplit. -// -//go:nosplit -func traceClockNow() traceTime { - return traceTime(cputicks() / traceTimeDiv) -} - -func traceExitingSyscall() { -} - -func traceExitedSyscall() { -} - -// Not used in the old tracer. Defined for compatibility. -const defaultTraceAdvancePeriod = 0 diff --git a/contrib/go/_std_1.22/src/runtime/trace2.go b/contrib/go/_std_1.22/src/runtime/trace2.go deleted file mode 100644 index 673205dda8a4..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2.go +++ /dev/null @@ -1,1001 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Go execution tracer. -// The tracer captures a wide range of execution events like goroutine -// creation/blocking/unblocking, syscall enter/exit/block, GC-related events, -// changes of heap size, processor start/stop, etc and writes them to a buffer -// in a compact form. A precise nanosecond-precision timestamp and a stack -// trace is captured for most events. -// -// Tracer invariants (to keep the synchronization making sense): -// - An m that has a trace buffer must be on either the allm or sched.freem lists. -// - Any trace buffer mutation must either be happening in traceAdvance or between -// a traceAcquire and a subsequent traceRelease. -// - traceAdvance cannot return until the previous generation's buffers are all flushed. -// -// See https://go.dev/issue/60773 for a link to the full design. - -package runtime - -import ( - "runtime/internal/atomic" - "unsafe" -) - -// Trace state. - -// trace is global tracing context. -var trace struct { - // trace.lock must only be acquired on the system stack where - // stack splits cannot happen while it is held. - lock mutex - - // Trace buffer management. - // - // First we check the empty list for any free buffers. If not, buffers - // are allocated directly from the OS. Once they're filled up and/or - // flushed, they end up on the full queue for trace.gen%2. - // - // The trace reader takes buffers off the full list one-by-one and - // places them into reading until they're finished being read from. - // Then they're placed onto the empty list. - // - // Protected by trace.lock. - reading *traceBuf // buffer currently handed off to user - empty *traceBuf // stack of empty buffers - full [2]traceBufQueue - workAvailable atomic.Bool - - // State for the trace reader goroutine. - // - // Protected by trace.lock. - readerGen atomic.Uintptr // the generation the reader is currently reading for - flushedGen atomic.Uintptr // the last completed generation - headerWritten bool // whether ReadTrace has emitted trace header - - // doneSema is used to synchronize the reader and traceAdvance. Specifically, - // it notifies traceAdvance that the reader is done with a generation. - // Both semaphores are 0 by default (so, acquires block). traceAdvance - // attempts to acquire for gen%2 after flushing the last buffers for gen. - // Meanwhile the reader releases the sema for gen%2 when it has finished - // processing gen. - doneSema [2]uint32 - - // Trace data tables for deduplicating data going into the trace. - // There are 2 of each: one for gen%2, one for 1-gen%2. - stackTab [2]traceStackTable // maps stack traces to unique ids - stringTab [2]traceStringTable // maps strings to unique ids - - // cpuLogRead accepts CPU profile samples from the signal handler where - // they're generated. There are two profBufs here: one for gen%2, one for - // 1-gen%2. These profBufs use a three-word header to hold the IDs of the P, G, - // and M (respectively) that were active at the time of the sample. Because - // profBuf uses a record with all zeros in its header to indicate overflow, - // we make sure to make the P field always non-zero: The ID of a real P will - // start at bit 1, and bit 0 will be set. Samples that arrive while no P is - // running (such as near syscalls) will set the first header field to 0b10. - // This careful handling of the first header field allows us to store ID of - // the active G directly in the second field, even though that will be 0 - // when sampling g0. - // - // Initialization and teardown of these fields is protected by traceAdvanceSema. - cpuLogRead [2]*profBuf - signalLock atomic.Uint32 // protects use of the following member, only usable in signal handlers - cpuLogWrite [2]atomic.Pointer[profBuf] // copy of cpuLogRead for use in signal handlers, set without signalLock - cpuSleep *wakeableSleep - cpuLogDone <-chan struct{} - cpuBuf [2]*traceBuf - - reader atomic.Pointer[g] // goroutine that called ReadTrace, or nil - - // Fast mappings from enumerations to string IDs that are prepopulated - // in the trace. - markWorkerLabels [2][len(gcMarkWorkerModeStrings)]traceArg - goStopReasons [2][len(traceGoStopReasonStrings)]traceArg - goBlockReasons [2][len(traceBlockReasonStrings)]traceArg - - // Trace generation counter. - gen atomic.Uintptr - lastNonZeroGen uintptr // last non-zero value of gen - - // shutdown is set when we are waiting for trace reader to finish after setting gen to 0 - // - // Writes protected by trace.lock. - shutdown atomic.Bool - - // Number of goroutines in syscall exiting slow path. - exitingSyscall atomic.Int32 - - // seqGC is the sequence counter for GC begin/end. - // - // Mutated only during stop-the-world. - seqGC uint64 -} - -// Trace public API. - -var ( - traceAdvanceSema uint32 = 1 - traceShutdownSema uint32 = 1 -) - -// StartTrace enables tracing for the current process. -// While tracing, the data will be buffered and available via [ReadTrace]. -// StartTrace returns an error if tracing is already enabled. -// Most clients should use the [runtime/trace] package or the [testing] package's -// -test.trace flag instead of calling StartTrace directly. -func StartTrace() error { - if traceEnabled() || traceShuttingDown() { - return errorString("tracing is already enabled") - } - // Block until cleanup of the last trace is done. - semacquire(&traceShutdownSema) - semrelease(&traceShutdownSema) - - // Hold traceAdvanceSema across trace start, since we'll want it on - // the other side of tracing being enabled globally. - semacquire(&traceAdvanceSema) - - // Initialize CPU profile -> trace ingestion. - traceInitReadCPU() - - // Compute the first generation for this StartTrace. - // - // Note: we start from the last non-zero generation rather than 1 so we - // can avoid resetting all the arrays indexed by gen%2 or gen%3. There's - // more than one of each per m, p, and goroutine. - firstGen := traceNextGen(trace.lastNonZeroGen) - - // Reset GC sequencer. - trace.seqGC = 1 - - // Reset trace reader state. - trace.headerWritten = false - trace.readerGen.Store(firstGen) - trace.flushedGen.Store(0) - - // Register some basic strings in the string tables. - traceRegisterLabelsAndReasons(firstGen) - - // Stop the world. - // - // The purpose of stopping the world is to make sure that no goroutine is in a - // context where it could emit an event by bringing all goroutines to a safe point - // with no opportunity to transition. - // - // The exception to this rule are goroutines that are concurrently exiting a syscall. - // Those will all be forced into the syscalling slow path, and we'll just make sure - // that we don't observe any goroutines in that critical section before starting - // the world again. - // - // A good follow-up question to this is why stopping the world is necessary at all - // given that we have traceAcquire and traceRelease. Unfortunately, those only help - // us when tracing is already active (for performance, so when tracing is off the - // tracing seqlock is left untouched). The main issue here is subtle: we're going to - // want to obtain a correct starting status for each goroutine, but there are windows - // of time in which we could read and emit an incorrect status. Specifically: - // - // trace := traceAcquire() - // // <----> problem window - // casgstatus(gp, _Gwaiting, _Grunnable) - // if trace.ok() { - // trace.GoUnpark(gp, 2) - // traceRelease(trace) - // } - // - // More precisely, if we readgstatus for a gp while another goroutine is in the problem - // window and that goroutine didn't observe that tracing had begun, then we might write - // a GoStatus(GoWaiting) event for that goroutine, but it won't trace an event marking - // the transition from GoWaiting to GoRunnable. The trace will then be broken, because - // future events will be emitted assuming the tracer sees GoRunnable. - // - // In short, what we really need here is to make sure that the next time *any goroutine* - // hits a traceAcquire, it sees that the trace is enabled. - // - // Note also that stopping the world is necessary to make sure sweep-related events are - // coherent. Since the world is stopped and sweeps are non-preemptible, we can never start - // the world and see an unpaired sweep 'end' event. Other parts of the tracer rely on this. - stw := stopTheWorld(stwStartTrace) - - // Prevent sysmon from running any code that could generate events. - lock(&sched.sysmonlock) - - // Reset mSyscallID on all Ps while we have them stationary and the trace is disabled. - for _, pp := range allp { - pp.trace.mSyscallID = -1 - } - - // Start tracing. - // - // After this executes, other Ms may start creating trace buffers and emitting - // data into them. - trace.gen.Store(firstGen) - - // Wait for exitingSyscall to drain. - // - // It may not monotonically decrease to zero, but in the limit it will always become - // zero because the world is stopped and there are no available Ps for syscall-exited - // goroutines to run on. - // - // Because we set gen before checking this, and because exitingSyscall is always incremented - // *after* traceAcquire (which checks gen), we can be certain that when exitingSyscall is zero - // that any goroutine that goes to exit a syscall from then on *must* observe the new gen. - // - // The critical section on each goroutine here is going to be quite short, so the likelihood - // that we observe a zero value is high. - for trace.exitingSyscall.Load() != 0 { - osyield() - } - - // Record some initial pieces of information. - // - // N.B. This will also emit a status event for this goroutine. - tl := traceAcquire() - tl.Gomaxprocs(gomaxprocs) // Get this as early in the trace as possible. See comment in traceAdvance. - tl.STWStart(stwStartTrace) // We didn't trace this above, so trace it now. - - // Record the fact that a GC is active, if applicable. - if gcphase == _GCmark || gcphase == _GCmarktermination { - tl.GCActive() - } - - // Record the heap goal so we have it at the very beginning of the trace. - tl.HeapGoal() - - // Make sure a ProcStatus is emitted for every P, while we're here. - for _, pp := range allp { - tl.writer().writeProcStatusForP(pp, pp == tl.mp.p.ptr()).end() - } - traceRelease(tl) - - unlock(&sched.sysmonlock) - startTheWorld(stw) - - traceStartReadCPU() - traceAdvancer.start() - - semrelease(&traceAdvanceSema) - return nil -} - -// StopTrace stops tracing, if it was previously enabled. -// StopTrace only returns after all the reads for the trace have completed. -func StopTrace() { - traceAdvance(true) -} - -// traceAdvance moves tracing to the next generation, and cleans up the current generation, -// ensuring that it's flushed out before returning. If stopTrace is true, it disables tracing -// altogether instead of advancing to the next generation. -// -// traceAdvanceSema must not be held. -func traceAdvance(stopTrace bool) { - semacquire(&traceAdvanceSema) - - // Get the gen that we're advancing from. In this function we don't really care much - // about the generation we're advancing _into_ since we'll do all the cleanup in this - // generation for the next advancement. - gen := trace.gen.Load() - if gen == 0 { - // We may end up here traceAdvance is called concurrently with StopTrace. - semrelease(&traceAdvanceSema) - return - } - - // Write an EvFrequency event for this generation. - // - // N.B. This may block for quite a while to get a good frequency estimate, so make sure we do - // this here and not e.g. on the trace reader. - traceFrequency(gen) - - // Collect all the untraced Gs. - type untracedG struct { - gp *g - goid uint64 - mid int64 - status uint32 - waitreason waitReason - inMarkAssist bool - } - var untracedGs []untracedG - forEachGRace(func(gp *g) { - // Make absolutely sure all Gs are ready for the next - // generation. We need to do this even for dead Gs because - // they may come alive with a new identity, and its status - // traced bookkeeping might end up being stale. - // We may miss totally new goroutines, but they'll always - // have clean bookkeeping. - gp.trace.readyNextGen(gen) - // If the status was traced, nothing else to do. - if gp.trace.statusWasTraced(gen) { - return - } - // Scribble down information about this goroutine. - ug := untracedG{gp: gp, mid: -1} - systemstack(func() { - me := getg().m.curg - // We don't have to handle this G status transition because we - // already eliminated ourselves from consideration above. - casGToWaiting(me, _Grunning, waitReasonTraceGoroutineStatus) - // We need to suspend and take ownership of the G to safely read its - // goid. Note that we can't actually emit the event at this point - // because we might stop the G in a window where it's unsafe to write - // events based on the G's status. We need the global trace buffer flush - // coming up to make sure we're not racing with the G. - // - // It should be very unlikely that we try to preempt a running G here. - // The only situation that we might is that we're racing with a G - // that's running for the first time in this generation. Therefore, - // this should be relatively fast. - s := suspendG(gp) - if !s.dead { - ug.goid = s.g.goid - if s.g.m != nil { - ug.mid = int64(s.g.m.procid) - } - ug.status = readgstatus(s.g) &^ _Gscan - ug.waitreason = s.g.waitreason - ug.inMarkAssist = s.g.inMarkAssist - } - resumeG(s) - casgstatus(me, _Gwaiting, _Grunning) - }) - if ug.goid != 0 { - untracedGs = append(untracedGs, ug) - } - }) - - if !stopTrace { - // Re-register runtime goroutine labels and stop/block reasons. - traceRegisterLabelsAndReasons(traceNextGen(gen)) - } - - // Now that we've done some of the heavy stuff, prevent the world from stopping. - // This is necessary to ensure the consistency of the STW events. If we're feeling - // adventurous we could lift this restriction and add a STWActive event, but the - // cost of maintaining this consistency is low. We're not going to hold this semaphore - // for very long and most STW periods are very short. - // Once we hold worldsema, prevent preemption as well so we're not interrupted partway - // through this. We want to get this done as soon as possible. - semacquire(&worldsema) - mp := acquirem() - - // Advance the generation or stop the trace. - trace.lastNonZeroGen = gen - if stopTrace { - systemstack(func() { - // Ordering is important here. Set shutdown first, then disable tracing, - // so that conditions like (traceEnabled() || traceShuttingDown()) have - // no opportunity to be false. Hold the trace lock so this update appears - // atomic to the trace reader. - lock(&trace.lock) - trace.shutdown.Store(true) - trace.gen.Store(0) - unlock(&trace.lock) - }) - } else { - trace.gen.Store(traceNextGen(gen)) - } - - // Emit a ProcsChange event so we have one on record for each generation. - // Let's emit it as soon as possible so that downstream tools can rely on the value - // being there fairly soon in a generation. - // - // It's important that we do this before allowing stop-the-worlds again, - // because the procs count could change. - if !stopTrace { - tl := traceAcquire() - tl.Gomaxprocs(gomaxprocs) - traceRelease(tl) - } - - // Emit a GCActive event in the new generation if necessary. - // - // It's important that we do this before allowing stop-the-worlds again, - // because that could emit global GC-related events. - if !stopTrace && (gcphase == _GCmark || gcphase == _GCmarktermination) { - tl := traceAcquire() - tl.GCActive() - traceRelease(tl) - } - - // Preemption is OK again after this. If the world stops or whatever it's fine. - // We're just cleaning up the last generation after this point. - // - // We also don't care if the GC starts again after this for the same reasons. - releasem(mp) - semrelease(&worldsema) - - // Snapshot allm and freem. - // - // Snapshotting after the generation counter update is sufficient. - // Because an m must be on either allm or sched.freem if it has an active trace - // buffer, new threads added to allm after this point must necessarily observe - // the new generation number (sched.lock acts as a barrier). - // - // Threads that exit before this point and are on neither list explicitly - // flush their own buffers in traceThreadDestroy. - // - // Snapshotting freem is necessary because Ms can continue to emit events - // while they're still on that list. Removal from sched.freem is serialized with - // this snapshot, so either we'll capture an m on sched.freem and race with - // the removal to flush its buffers (resolved by traceThreadDestroy acquiring - // the thread's seqlock, which one of us must win, so at least its old gen buffer - // will be flushed in time for the new generation) or it will have flushed its - // buffers before we snapshotted it to begin with. - lock(&sched.lock) - mToFlush := allm - for mp := mToFlush; mp != nil; mp = mp.alllink { - mp.trace.link = mp.alllink - } - for mp := sched.freem; mp != nil; mp = mp.freelink { - mp.trace.link = mToFlush - mToFlush = mp - } - unlock(&sched.lock) - - // Iterate over our snapshot, flushing every buffer until we're done. - // - // Because trace writers read the generation while the seqlock is - // held, we can be certain that when there are no writers there are - // also no stale generation values left. Therefore, it's safe to flush - // any buffers that remain in that generation's slot. - const debugDeadlock = false - systemstack(func() { - // Track iterations for some rudimentary deadlock detection. - i := 0 - detectedDeadlock := false - - for mToFlush != nil { - prev := &mToFlush - for mp := *prev; mp != nil; { - if mp.trace.seqlock.Load()%2 != 0 { - // The M is writing. Come back to it later. - prev = &mp.trace.link - mp = mp.trace.link - continue - } - // Flush the trace buffer. - // - // trace.lock needed for traceBufFlush, but also to synchronize - // with traceThreadDestroy, which flushes both buffers unconditionally. - lock(&trace.lock) - bufp := &mp.trace.buf[gen%2] - if *bufp != nil { - traceBufFlush(*bufp, gen) - *bufp = nil - } - unlock(&trace.lock) - - // Remove the m from the flush list. - *prev = mp.trace.link - mp.trace.link = nil - mp = *prev - } - // Yield only if we're going to be going around the loop again. - if mToFlush != nil { - osyield() - } - - if debugDeadlock { - // Try to detect a deadlock. We probably shouldn't loop here - // this many times. - if i > 100000 && !detectedDeadlock { - detectedDeadlock = true - println("runtime: failing to flush") - for mp := mToFlush; mp != nil; mp = mp.trace.link { - print("runtime: m=", mp.id, "\n") - } - } - i++ - } - } - }) - - // At this point, the old generation is fully flushed minus stack and string - // tables, CPU samples, and goroutines that haven't run at all during the last - // generation. - - // Check to see if any Gs still haven't had events written out for them. - statusWriter := unsafeTraceWriter(gen, nil) - for _, ug := range untracedGs { - if ug.gp.trace.statusWasTraced(gen) { - // It was traced, we don't need to do anything. - continue - } - // It still wasn't traced. Because we ensured all Ms stopped writing trace - // events to the last generation, that must mean the G never had its status - // traced in gen between when we recorded it and now. If that's true, the goid - // and status we recorded then is exactly what we want right now. - status := goStatusToTraceGoStatus(ug.status, ug.waitreason) - statusWriter = statusWriter.writeGoStatus(ug.goid, ug.mid, status, ug.inMarkAssist) - } - statusWriter.flush().end() - - // Read everything out of the last gen's CPU profile buffer. - traceReadCPU(gen) - - systemstack(func() { - // Flush CPU samples, stacks, and strings for the last generation. This is safe, - // because we're now certain no M is writing to the last generation. - // - // Ordering is important here. traceCPUFlush may generate new stacks and dumping - // stacks may generate new strings. - traceCPUFlush(gen) - trace.stackTab[gen%2].dump(gen) - trace.stringTab[gen%2].reset(gen) - - // That's it. This generation is done producing buffers. - lock(&trace.lock) - trace.flushedGen.Store(gen) - unlock(&trace.lock) - }) - - if stopTrace { - semacquire(&traceShutdownSema) - - // Finish off CPU profile reading. - traceStopReadCPU() - } else { - // Go over each P and emit a status event for it if necessary. - // - // We do this at the beginning of the new generation instead of the - // end like we do for goroutines because forEachP doesn't give us a - // hook to skip Ps that have already been traced. Since we have to - // preempt all Ps anyway, might as well stay consistent with StartTrace - // which does this during the STW. - semacquire(&worldsema) - forEachP(waitReasonTraceProcStatus, func(pp *p) { - tl := traceAcquire() - if !pp.trace.statusWasTraced(tl.gen) { - tl.writer().writeProcStatusForP(pp, false).end() - } - traceRelease(tl) - }) - // Perform status reset on dead Ps because they just appear as idle. - // - // Holding worldsema prevents allp from changing. - // - // TODO(mknyszek): Consider explicitly emitting ProcCreate and ProcDestroy - // events to indicate whether a P exists, rather than just making its - // existence implicit. - for _, pp := range allp[len(allp):cap(allp)] { - pp.trace.readyNextGen(traceNextGen(gen)) - } - semrelease(&worldsema) - } - - // Block until the trace reader has finished processing the last generation. - semacquire(&trace.doneSema[gen%2]) - if raceenabled { - raceacquire(unsafe.Pointer(&trace.doneSema[gen%2])) - } - - // Double-check that things look as we expect after advancing and perform some - // final cleanup if the trace has fully stopped. - systemstack(func() { - lock(&trace.lock) - if !trace.full[gen%2].empty() { - throw("trace: non-empty full trace buffer for done generation") - } - if stopTrace { - if !trace.full[1-(gen%2)].empty() { - throw("trace: non-empty full trace buffer for next generation") - } - if trace.reading != nil || trace.reader.Load() != nil { - throw("trace: reading after shutdown") - } - // Free all the empty buffers. - for trace.empty != nil { - buf := trace.empty - trace.empty = buf.link - sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf), &memstats.other_sys) - } - // Clear trace.shutdown and other flags. - trace.headerWritten = false - trace.shutdown.Store(false) - } - unlock(&trace.lock) - }) - - if stopTrace { - // Clear the sweep state on every P for the next time tracing is enabled. - // - // It may be stale in the next trace because we may have ended tracing in - // the middle of a sweep on a P. - // - // It's fine not to call forEachP here because tracing is disabled and we - // know at this point that nothing is calling into the tracer, but we do - // need to look at dead Ps too just because GOMAXPROCS could have been called - // at any point since we stopped tracing, and we have to ensure there's no - // bad state on dead Ps too. Prevent a STW and a concurrent GOMAXPROCS that - // might mutate allp by making ourselves briefly non-preemptible. - mp := acquirem() - for _, pp := range allp[:cap(allp)] { - pp.trace.inSweep = false - pp.trace.maySweep = false - pp.trace.swept = 0 - pp.trace.reclaimed = 0 - } - releasem(mp) - } - - // Release the advance semaphore. If stopTrace is true we're still holding onto - // traceShutdownSema. - // - // Do a direct handoff. Don't let one caller of traceAdvance starve - // other calls to traceAdvance. - semrelease1(&traceAdvanceSema, true, 0) - - if stopTrace { - // Stop the traceAdvancer. We can't be holding traceAdvanceSema here because - // we'll deadlock (we're blocked on the advancer goroutine exiting, but it - // may be currently trying to acquire traceAdvanceSema). - traceAdvancer.stop() - semrelease(&traceShutdownSema) - } -} - -func traceNextGen(gen uintptr) uintptr { - if gen == ^uintptr(0) { - // gen is used both %2 and %3 and we want both patterns to continue when we loop around. - // ^uint32(0) and ^uint64(0) are both odd and multiples of 3. Therefore the next generation - // we want is even and one more than a multiple of 3. The smallest such number is 4. - return 4 - } - return gen + 1 -} - -// traceRegisterLabelsAndReasons re-registers mark worker labels and -// goroutine stop/block reasons in the string table for the provided -// generation. Note: the provided generation must not have started yet. -func traceRegisterLabelsAndReasons(gen uintptr) { - for i, label := range gcMarkWorkerModeStrings[:] { - trace.markWorkerLabels[gen%2][i] = traceArg(trace.stringTab[gen%2].put(gen, label)) - } - for i, str := range traceBlockReasonStrings[:] { - trace.goBlockReasons[gen%2][i] = traceArg(trace.stringTab[gen%2].put(gen, str)) - } - for i, str := range traceGoStopReasonStrings[:] { - trace.goStopReasons[gen%2][i] = traceArg(trace.stringTab[gen%2].put(gen, str)) - } -} - -// ReadTrace returns the next chunk of binary tracing data, blocking until data -// is available. If tracing is turned off and all the data accumulated while it -// was on has been returned, ReadTrace returns nil. The caller must copy the -// returned data before calling ReadTrace again. -// ReadTrace must be called from one goroutine at a time. -func ReadTrace() []byte { -top: - var buf []byte - var park bool - systemstack(func() { - buf, park = readTrace0() - }) - if park { - gopark(func(gp *g, _ unsafe.Pointer) bool { - if !trace.reader.CompareAndSwapNoWB(nil, gp) { - // We're racing with another reader. - // Wake up and handle this case. - return false - } - - if g2 := traceReader(); gp == g2 { - // New data arrived between unlocking - // and the CAS and we won the wake-up - // race, so wake up directly. - return false - } else if g2 != nil { - printlock() - println("runtime: got trace reader", g2, g2.goid) - throw("unexpected trace reader") - } - - return true - }, nil, waitReasonTraceReaderBlocked, traceBlockSystemGoroutine, 2) - goto top - } - - return buf -} - -// readTrace0 is ReadTrace's continuation on g0. This must run on the -// system stack because it acquires trace.lock. -// -//go:systemstack -func readTrace0() (buf []byte, park bool) { - if raceenabled { - // g0 doesn't have a race context. Borrow the user G's. - if getg().racectx != 0 { - throw("expected racectx == 0") - } - getg().racectx = getg().m.curg.racectx - // (This defer should get open-coded, which is safe on - // the system stack.) - defer func() { getg().racectx = 0 }() - } - - // This function must not allocate while holding trace.lock: - // allocation can call heap allocate, which will try to emit a trace - // event while holding heap lock. - lock(&trace.lock) - - if trace.reader.Load() != nil { - // More than one goroutine reads trace. This is bad. - // But we rather do not crash the program because of tracing, - // because tracing can be enabled at runtime on prod servers. - unlock(&trace.lock) - println("runtime: ReadTrace called from multiple goroutines simultaneously") - return nil, false - } - // Recycle the old buffer. - if buf := trace.reading; buf != nil { - buf.link = trace.empty - trace.empty = buf - trace.reading = nil - } - // Write trace header. - if !trace.headerWritten { - trace.headerWritten = true - unlock(&trace.lock) - return []byte("go 1.22 trace\x00\x00\x00"), false - } - - // Read the next buffer. - - if trace.readerGen.Load() == 0 { - trace.readerGen.Store(1) - } - var gen uintptr - for { - assertLockHeld(&trace.lock) - gen = trace.readerGen.Load() - - // Check to see if we need to block for more data in this generation - // or if we need to move our generation forward. - if !trace.full[gen%2].empty() { - break - } - // Most of the time readerGen is one generation ahead of flushedGen, as the - // current generation is being read from. Then, once the last buffer is flushed - // into readerGen, flushedGen will rise to meet it. At this point, the tracer - // is waiting on the reader to finish flushing the last generation so that it - // can continue to advance. - if trace.flushedGen.Load() == gen { - if trace.shutdown.Load() { - unlock(&trace.lock) - - // Wake up anyone waiting for us to be done with this generation. - // - // Do this after reading trace.shutdown, because the thread we're - // waking up is going to clear trace.shutdown. - if raceenabled { - // Model synchronization on trace.doneSema, which te race - // detector does not see. This is required to avoid false - // race reports on writer passed to trace.Start. - racerelease(unsafe.Pointer(&trace.doneSema[gen%2])) - } - semrelease(&trace.doneSema[gen%2]) - - // We're shutting down, and the last generation is fully - // read. We're done. - return nil, false - } - // The previous gen has had all of its buffers flushed, and - // there's nothing else for us to read. Advance the generation - // we're reading from and try again. - trace.readerGen.Store(trace.gen.Load()) - unlock(&trace.lock) - - // Wake up anyone waiting for us to be done with this generation. - // - // Do this after reading gen to make sure we can't have the trace - // advance until we've read it. - if raceenabled { - // See comment above in the shutdown case. - racerelease(unsafe.Pointer(&trace.doneSema[gen%2])) - } - semrelease(&trace.doneSema[gen%2]) - - // Reacquire the lock and go back to the top of the loop. - lock(&trace.lock) - continue - } - // Wait for new data. - // - // We don't simply use a note because the scheduler - // executes this goroutine directly when it wakes up - // (also a note would consume an M). - // - // Before we drop the lock, clear the workAvailable flag. Work can - // only be queued with trace.lock held, so this is at least true until - // we drop the lock. - trace.workAvailable.Store(false) - unlock(&trace.lock) - return nil, true - } - // Pull a buffer. - tbuf := trace.full[gen%2].pop() - trace.reading = tbuf - unlock(&trace.lock) - return tbuf.arr[:tbuf.pos], false -} - -// traceReader returns the trace reader that should be woken up, if any. -// Callers should first check (traceEnabled() || traceShuttingDown()). -// -// This must run on the system stack because it acquires trace.lock. -// -//go:systemstack -func traceReader() *g { - gp := traceReaderAvailable() - if gp == nil || !trace.reader.CompareAndSwapNoWB(gp, nil) { - return nil - } - return gp -} - -// traceReaderAvailable returns the trace reader if it is not currently -// scheduled and should be. Callers should first check that -// (traceEnabled() || traceShuttingDown()) is true. -func traceReaderAvailable() *g { - // There are three conditions under which we definitely want to schedule - // the reader: - // - The reader is lagging behind in finishing off the last generation. - // In this case, trace buffers could even be empty, but the trace - // advancer will be waiting on the reader, so we have to make sure - // to schedule the reader ASAP. - // - The reader has pending work to process for it's reader generation - // (assuming readerGen is not lagging behind). Note that we also want - // to be careful *not* to schedule the reader if there's no work to do. - // - The trace is shutting down. The trace stopper blocks on the reader - // to finish, much like trace advancement. - // - // We also want to be careful not to schedule the reader if there's no - // reason to. - if trace.flushedGen.Load() == trace.readerGen.Load() || trace.workAvailable.Load() || trace.shutdown.Load() { - return trace.reader.Load() - } - return nil -} - -// Trace advancer goroutine. -var traceAdvancer traceAdvancerState - -type traceAdvancerState struct { - timer *wakeableSleep - done chan struct{} -} - -// start starts a new traceAdvancer. -func (s *traceAdvancerState) start() { - // Start a goroutine to periodically advance the trace generation. - s.done = make(chan struct{}) - s.timer = newWakeableSleep() - go func() { - for traceEnabled() { - // Set a timer to wake us up - s.timer.sleep(int64(debug.traceadvanceperiod)) - - // Try to advance the trace. - traceAdvance(false) - } - s.done <- struct{}{} - }() -} - -// stop stops a traceAdvancer and blocks until it exits. -func (s *traceAdvancerState) stop() { - s.timer.wake() - <-s.done - close(s.done) - s.timer.close() -} - -// traceAdvancePeriod is the approximate period between -// new generations. -const defaultTraceAdvancePeriod = 1e9 // 1 second. - -// wakeableSleep manages a wakeable goroutine sleep. -// -// Users of this type must call init before first use and -// close to free up resources. Once close is called, init -// must be called before another use. -type wakeableSleep struct { - timer *timer - - // lock protects access to wakeup, but not send/recv on it. - lock mutex - wakeup chan struct{} -} - -// newWakeableSleep initializes a new wakeableSleep and returns it. -func newWakeableSleep() *wakeableSleep { - s := new(wakeableSleep) - lockInit(&s.lock, lockRankWakeableSleep) - s.wakeup = make(chan struct{}, 1) - s.timer = new(timer) - s.timer.arg = s - s.timer.f = func(s any, _ uintptr) { - s.(*wakeableSleep).wake() - } - return s -} - -// sleep sleeps for the provided duration in nanoseconds or until -// another goroutine calls wake. -// -// Must not be called by more than one goroutine at a time and -// must not be called concurrently with close. -func (s *wakeableSleep) sleep(ns int64) { - resetTimer(s.timer, nanotime()+ns) - lock(&s.lock) - if raceenabled { - raceacquire(unsafe.Pointer(&s.lock)) - } - wakeup := s.wakeup - if raceenabled { - racerelease(unsafe.Pointer(&s.lock)) - } - unlock(&s.lock) - <-wakeup - stopTimer(s.timer) -} - -// wake awakens any goroutine sleeping on the timer. -// -// Safe for concurrent use with all other methods. -func (s *wakeableSleep) wake() { - // Grab the wakeup channel, which may be nil if we're - // racing with close. - lock(&s.lock) - if raceenabled { - raceacquire(unsafe.Pointer(&s.lock)) - } - if s.wakeup != nil { - // Non-blocking send. - // - // Others may also write to this channel and we don't - // want to block on the receiver waking up. This also - // effectively batches together wakeup notifications. - select { - case s.wakeup <- struct{}{}: - default: - } - } - if raceenabled { - racerelease(unsafe.Pointer(&s.lock)) - } - unlock(&s.lock) -} - -// close wakes any goroutine sleeping on the timer and prevents -// further sleeping on it. -// -// Once close is called, the wakeableSleep must no longer be used. -// -// It must only be called once no goroutine is sleeping on the -// timer *and* nothing else will call wake concurrently. -func (s *wakeableSleep) close() { - // Set wakeup to nil so that a late timer ends up being a no-op. - lock(&s.lock) - if raceenabled { - raceacquire(unsafe.Pointer(&s.lock)) - } - wakeup := s.wakeup - s.wakeup = nil - - // Close the channel. - close(wakeup) - - if raceenabled { - racerelease(unsafe.Pointer(&s.lock)) - } - unlock(&s.lock) - return -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2buf.go b/contrib/go/_std_1.22/src/runtime/trace2buf.go deleted file mode 100644 index 54de5e1df613..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2buf.go +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Trace buffer management. - -package runtime - -import ( - "runtime/internal/sys" - "unsafe" -) - -// Maximum number of bytes required to encode uint64 in base-128. -const traceBytesPerNumber = 10 - -// traceWriter is the interface for writing all trace data. -// -// This type is passed around as a value, and all of its methods return -// a new traceWriter. This allows for chaining together calls in a fluent-style -// API. This is partly stylistic, and very slightly for performance, since -// the compiler can destructure this value and pass it between calls as -// just regular arguments. However, this style is not load-bearing, and -// we can change it if it's deemed too error-prone. -type traceWriter struct { - traceLocker - *traceBuf -} - -// write returns an a traceWriter that writes into the current M's stream. -func (tl traceLocker) writer() traceWriter { - return traceWriter{traceLocker: tl, traceBuf: tl.mp.trace.buf[tl.gen%2]} -} - -// unsafeTraceWriter produces a traceWriter that doesn't lock the trace. -// -// It should only be used in contexts where either: -// - Another traceLocker is held. -// - trace.gen is prevented from advancing. -// -// buf may be nil. -func unsafeTraceWriter(gen uintptr, buf *traceBuf) traceWriter { - return traceWriter{traceLocker: traceLocker{gen: gen}, traceBuf: buf} -} - -// end writes the buffer back into the m. -func (w traceWriter) end() { - if w.mp == nil { - // Tolerate a nil mp. It makes code that creates traceWriters directly - // less error-prone. - return - } - w.mp.trace.buf[w.gen%2] = w.traceBuf -} - -// ensure makes sure that at least maxSize bytes are available to write. -// -// Returns whether the buffer was flushed. -func (w traceWriter) ensure(maxSize int) (traceWriter, bool) { - refill := w.traceBuf == nil || !w.available(maxSize) - if refill { - w = w.refill() - } - return w, refill -} - -// flush puts w.traceBuf on the queue of full buffers. -func (w traceWriter) flush() traceWriter { - systemstack(func() { - lock(&trace.lock) - if w.traceBuf != nil { - traceBufFlush(w.traceBuf, w.gen) - } - unlock(&trace.lock) - }) - w.traceBuf = nil - return w -} - -// refill puts w.traceBuf on the queue of full buffers and refresh's w's buffer. -func (w traceWriter) refill() traceWriter { - systemstack(func() { - lock(&trace.lock) - if w.traceBuf != nil { - traceBufFlush(w.traceBuf, w.gen) - } - if trace.empty != nil { - w.traceBuf = trace.empty - trace.empty = w.traceBuf.link - unlock(&trace.lock) - } else { - unlock(&trace.lock) - w.traceBuf = (*traceBuf)(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys)) - if w.traceBuf == nil { - throw("trace: out of memory") - } - } - }) - // Initialize the buffer. - ts := traceClockNow() - if ts <= w.traceBuf.lastTime { - ts = w.traceBuf.lastTime + 1 - } - w.traceBuf.lastTime = ts - w.traceBuf.link = nil - w.traceBuf.pos = 0 - - // Tolerate a nil mp. - mID := ^uint64(0) - if w.mp != nil { - mID = uint64(w.mp.procid) - } - - // Write the buffer's header. - w.byte(byte(traceEvEventBatch)) - w.varint(uint64(w.gen)) - w.varint(uint64(mID)) - w.varint(uint64(ts)) - w.traceBuf.lenPos = w.varintReserve() - return w -} - -// traceBufQueue is a FIFO of traceBufs. -type traceBufQueue struct { - head, tail *traceBuf -} - -// push queues buf into queue of buffers. -func (q *traceBufQueue) push(buf *traceBuf) { - buf.link = nil - if q.head == nil { - q.head = buf - } else { - q.tail.link = buf - } - q.tail = buf -} - -// pop dequeues from the queue of buffers. -func (q *traceBufQueue) pop() *traceBuf { - buf := q.head - if buf == nil { - return nil - } - q.head = buf.link - if q.head == nil { - q.tail = nil - } - buf.link = nil - return buf -} - -func (q *traceBufQueue) empty() bool { - return q.head == nil -} - -// traceBufHeader is per-P tracing buffer. -type traceBufHeader struct { - link *traceBuf // in trace.empty/full - lastTime traceTime // when we wrote the last event - pos int // next write offset in arr - lenPos int // position of batch length value -} - -// traceBuf is per-M tracing buffer. -// -// TODO(mknyszek): Rename traceBuf to traceBatch, since they map 1:1 with event batches. -type traceBuf struct { - _ sys.NotInHeap - traceBufHeader - arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf -} - -// byte appends v to buf. -func (buf *traceBuf) byte(v byte) { - buf.arr[buf.pos] = v - buf.pos++ -} - -// varint appends v to buf in little-endian-base-128 encoding. -func (buf *traceBuf) varint(v uint64) { - pos := buf.pos - arr := buf.arr[pos : pos+traceBytesPerNumber] - for i := range arr { - if v < 0x80 { - pos += i + 1 - arr[i] = byte(v) - break - } - arr[i] = 0x80 | byte(v) - v >>= 7 - } - buf.pos = pos -} - -// varintReserve reserves enough space in buf to hold any varint. -// -// Space reserved this way can be filled in with the varintAt method. -func (buf *traceBuf) varintReserve() int { - p := buf.pos - buf.pos += traceBytesPerNumber - return p -} - -// stringData appends s's data directly to buf. -func (buf *traceBuf) stringData(s string) { - buf.pos += copy(buf.arr[buf.pos:], s) -} - -func (buf *traceBuf) available(size int) bool { - return len(buf.arr)-buf.pos >= size -} - -// varintAt writes varint v at byte position pos in buf. This always -// consumes traceBytesPerNumber bytes. This is intended for when the caller -// needs to reserve space for a varint but can't populate it until later. -// Use varintReserve to reserve this space. -func (buf *traceBuf) varintAt(pos int, v uint64) { - for i := 0; i < traceBytesPerNumber; i++ { - if i < traceBytesPerNumber-1 { - buf.arr[pos] = 0x80 | byte(v) - } else { - buf.arr[pos] = byte(v) - } - v >>= 7 - pos++ - } - if v != 0 { - throw("v could not fit in traceBytesPerNumber") - } -} - -// traceBufFlush flushes a trace buffer. -// -// Must run on the system stack because trace.lock must be held. -// -//go:systemstack -func traceBufFlush(buf *traceBuf, gen uintptr) { - assertLockHeld(&trace.lock) - - // Write out the non-header length of the batch in the header. - // - // Note: the length of the header is not included to make it easier - // to calculate this value when deserializing and reserializing the - // trace. Varints can have additional padding of zero bits that is - // quite difficult to preserve, and if we include the header we - // force serializers to do more work. Nothing else actually needs - // padding. - buf.varintAt(buf.lenPos, uint64(buf.pos-(buf.lenPos+traceBytesPerNumber))) - trace.full[gen%2].push(buf) - - // Notify the scheduler that there's work available and that the trace - // reader should be scheduled. - if !trace.workAvailable.Load() { - trace.workAvailable.Store(true) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2cpu.go b/contrib/go/_std_1.22/src/runtime/trace2cpu.go deleted file mode 100644 index 4635662c08d5..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2cpu.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// CPU profile -> trace - -package runtime - -// traceInitReadCPU initializes CPU profile -> tracer state for tracing. -// -// Returns a profBuf for reading from. -func traceInitReadCPU() { - if traceEnabled() { - throw("traceInitReadCPU called with trace enabled") - } - // Create new profBuf for CPU samples that will be emitted as events. - // Format: after the timestamp, header is [pp.id, gp.goid, mp.procid]. - trace.cpuLogRead[0] = newProfBuf(3, profBufWordCount, profBufTagCount) - trace.cpuLogRead[1] = newProfBuf(3, profBufWordCount, profBufTagCount) - // We must not acquire trace.signalLock outside of a signal handler: a - // profiling signal may arrive at any time and try to acquire it, leading to - // deadlock. Because we can't use that lock to protect updates to - // trace.cpuLogWrite (only use of the structure it references), reads and - // writes of the pointer must be atomic. (And although this field is never - // the sole pointer to the profBuf value, it's best to allow a write barrier - // here.) - trace.cpuLogWrite[0].Store(trace.cpuLogRead[0]) - trace.cpuLogWrite[1].Store(trace.cpuLogRead[1]) -} - -// traceStartReadCPU creates a goroutine to start reading CPU profile -// data into an active trace. -// -// traceAdvanceSema must be held. -func traceStartReadCPU() { - if !traceEnabled() { - throw("traceStartReadCPU called with trace disabled") - } - // Spin up the logger goroutine. - trace.cpuSleep = newWakeableSleep() - done := make(chan struct{}, 1) - go func() { - for traceEnabled() { - // Sleep here because traceReadCPU is non-blocking. This mirrors - // how the runtime/pprof package obtains CPU profile data. - // - // We can't do a blocking read here because Darwin can't do a - // wakeup from a signal handler, so all CPU profiling is just - // non-blocking. See #61768 for more details. - // - // Like the runtime/pprof package, even if that bug didn't exist - // we would still want to do a goroutine-level sleep in between - // reads to avoid frequent wakeups. - trace.cpuSleep.sleep(100_000_000) - - tl := traceAcquire() - if !tl.ok() { - // Tracing disabled. - break - } - keepGoing := traceReadCPU(tl.gen) - traceRelease(tl) - if !keepGoing { - break - } - } - done <- struct{}{} - }() - trace.cpuLogDone = done -} - -// traceStopReadCPU blocks until the trace CPU reading goroutine exits. -// -// traceAdvanceSema must be held, and tracing must be disabled. -func traceStopReadCPU() { - if traceEnabled() { - throw("traceStopReadCPU called with trace enabled") - } - - // Once we close the profbuf, we'll be in one of two situations: - // - The logger goroutine has already exited because it observed - // that the trace is disabled. - // - The logger goroutine is asleep. - // - // Wake the goroutine so it can observe that their the buffer is - // closed an exit. - trace.cpuLogWrite[0].Store(nil) - trace.cpuLogWrite[1].Store(nil) - trace.cpuLogRead[0].close() - trace.cpuLogRead[1].close() - trace.cpuSleep.wake() - - // Wait until the logger goroutine exits. - <-trace.cpuLogDone - - // Clear state for the next trace. - trace.cpuLogDone = nil - trace.cpuLogRead[0] = nil - trace.cpuLogRead[1] = nil - trace.cpuSleep.close() -} - -// traceReadCPU attempts to read from the provided profBuf[gen%2] and write -// into the trace. Returns true if there might be more to read or false -// if the profBuf is closed or the caller should otherwise stop reading. -// -// The caller is responsible for ensuring that gen does not change. Either -// the caller must be in a traceAcquire/traceRelease block, or must be calling -// with traceAdvanceSema held. -// -// No more than one goroutine may be in traceReadCPU for the same -// profBuf at a time. -// -// Must not run on the system stack because profBuf.read performs race -// operations. -func traceReadCPU(gen uintptr) bool { - var pcBuf [traceStackSize]uintptr - - data, tags, eof := trace.cpuLogRead[gen%2].read(profBufNonBlocking) - for len(data) > 0 { - if len(data) < 4 || data[0] > uint64(len(data)) { - break // truncated profile - } - if data[0] < 4 || tags != nil && len(tags) < 1 { - break // malformed profile - } - if len(tags) < 1 { - break // mismatched profile records and tags - } - - // Deserialize the data in the profile buffer. - recordLen := data[0] - timestamp := data[1] - ppid := data[2] >> 1 - if hasP := (data[2] & 0b1) != 0; !hasP { - ppid = ^uint64(0) - } - goid := data[3] - mpid := data[4] - stk := data[5:recordLen] - - // Overflow records always have their headers contain - // all zeroes. - isOverflowRecord := len(stk) == 1 && data[2] == 0 && data[3] == 0 && data[4] == 0 - - // Move the data iterator forward. - data = data[recordLen:] - // No support here for reporting goroutine tags at the moment; if - // that information is to be part of the execution trace, we'd - // probably want to see when the tags are applied and when they - // change, instead of only seeing them when we get a CPU sample. - tags = tags[1:] - - if isOverflowRecord { - // Looks like an overflow record from the profBuf. Not much to - // do here, we only want to report full records. - continue - } - - // Construct the stack for insertion to the stack table. - nstk := 1 - pcBuf[0] = logicalStackSentinel - for ; nstk < len(pcBuf) && nstk-1 < len(stk); nstk++ { - pcBuf[nstk] = uintptr(stk[nstk-1]) - } - - // Write out a trace event. - w := unsafeTraceWriter(gen, trace.cpuBuf[gen%2]) - - // Ensure we have a place to write to. - var flushed bool - w, flushed = w.ensure(2 + 5*traceBytesPerNumber /* traceEvCPUSamples + traceEvCPUSample + timestamp + g + m + p + stack ID */) - if flushed { - // Annotate the batch as containing strings. - w.byte(byte(traceEvCPUSamples)) - } - - // Add the stack to the table. - stackID := trace.stackTab[gen%2].put(pcBuf[:nstk]) - - // Write out the CPU sample. - w.byte(byte(traceEvCPUSample)) - w.varint(timestamp) - w.varint(mpid) - w.varint(ppid) - w.varint(goid) - w.varint(stackID) - - trace.cpuBuf[gen%2] = w.traceBuf - } - return !eof -} - -// traceCPUFlush flushes trace.cpuBuf[gen%2]. The caller must be certain that gen -// has completed and that there are no more writers to it. -// -// Must run on the systemstack because it flushes buffers and acquires trace.lock -// to do so. -// -//go:systemstack -func traceCPUFlush(gen uintptr) { - // Flush any remaining trace buffers containing CPU samples. - if buf := trace.cpuBuf[gen%2]; buf != nil { - lock(&trace.lock) - traceBufFlush(buf, gen) - unlock(&trace.lock) - trace.cpuBuf[gen%2] = nil - } -} - -// traceCPUSample writes a CPU profile sample stack to the execution tracer's -// profiling buffer. It is called from a signal handler, so is limited in what -// it can do. mp must be the thread that is currently stopped in a signal. -func traceCPUSample(gp *g, mp *m, pp *p, stk []uintptr) { - if !traceEnabled() { - // Tracing is usually turned off; don't spend time acquiring the signal - // lock unless it's active. - return - } - if mp == nil { - // Drop samples that don't have an identifiable thread. We can't render - // this in any useful way anyway. - return - } - - // We're going to conditionally write to one of two buffers based on the - // generation. To make sure we write to the correct one, we need to make - // sure this thread's trace seqlock is held. If it already is, then we're - // in the tracer and we can just take advantage of that. If it isn't, then - // we need to acquire it and read the generation. - locked := false - if mp.trace.seqlock.Load()%2 == 0 { - mp.trace.seqlock.Add(1) - locked = true - } - gen := trace.gen.Load() - if gen == 0 { - // Tracing is disabled, as it turns out. Release the seqlock if necessary - // and exit. - if locked { - mp.trace.seqlock.Add(1) - } - return - } - - now := traceClockNow() - // The "header" here is the ID of the M that was running the profiled code, - // followed by the IDs of the P and goroutine. (For normal CPU profiling, it's - // usually the number of samples with the given stack.) Near syscalls, pp - // may be nil. Reporting goid of 0 is fine for either g0 or a nil gp. - var hdr [3]uint64 - if pp != nil { - // Overflow records in profBuf have all header values set to zero. Make - // sure that real headers have at least one bit set. - hdr[0] = uint64(pp.id)<<1 | 0b1 - } else { - hdr[0] = 0b10 - } - if gp != nil { - hdr[1] = gp.goid - } - if mp != nil { - hdr[2] = uint64(mp.procid) - } - - // Allow only one writer at a time - for !trace.signalLock.CompareAndSwap(0, 1) { - // TODO: Is it safe to osyield here? https://go.dev/issue/52672 - osyield() - } - - if log := trace.cpuLogWrite[gen%2].Load(); log != nil { - // Note: we don't pass a tag pointer here (how should profiling tags - // interact with the execution tracer?), but if we did we'd need to be - // careful about write barriers. See the long comment in profBuf.write. - log.write(nil, int64(now), hdr[:], stk) - } - - trace.signalLock.Store(0) - - // Release the seqlock if we acquired it earlier. - if locked { - mp.trace.seqlock.Add(1) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2event.go b/contrib/go/_std_1.22/src/runtime/trace2event.go deleted file mode 100644 index 1f2a9f754be1..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2event.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Trace event writing API for trace2runtime.go. - -package runtime - -import ( - "runtime/internal/sys" -) - -// Event types in the trace, args are given in square brackets. -// -// Naming scheme: -// - Time range event pairs have suffixes "Begin" and "End". -// - "Start", "Stop", "Create", "Destroy", "Block", "Unblock" -// are suffixes reserved for scheduling resources. -// -// NOTE: If you add an event type, make sure you also update all -// tables in this file! -type traceEv uint8 - -const ( - traceEvNone traceEv = iota // unused - - // Structural events. - traceEvEventBatch // start of per-M batch of events [generation, M ID, timestamp, batch length] - traceEvStacks // start of a section of the stack table [...traceEvStack] - traceEvStack // stack table entry [ID, ...{PC, func string ID, file string ID, line #}] - traceEvStrings // start of a section of the string dictionary [...traceEvString] - traceEvString // string dictionary entry [ID, length, string] - traceEvCPUSamples // start of a section of CPU samples [...traceEvCPUSample] - traceEvCPUSample // CPU profiling sample [timestamp, M ID, P ID, goroutine ID, stack ID] - traceEvFrequency // timestamp units per sec [freq] - - // Procs. - traceEvProcsChange // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack ID] - traceEvProcStart // start of P [timestamp, P ID, P seq] - traceEvProcStop // stop of P [timestamp] - traceEvProcSteal // P was stolen [timestamp, P ID, P seq, M ID] - traceEvProcStatus // P status at the start of a generation [timestamp, P ID, status] - - // Goroutines. - traceEvGoCreate // goroutine creation [timestamp, new goroutine ID, new stack ID, stack ID] - traceEvGoCreateSyscall // goroutine appears in syscall (cgo callback) [timestamp, new goroutine ID] - traceEvGoStart // goroutine starts running [timestamp, goroutine ID, goroutine seq] - traceEvGoDestroy // goroutine ends [timestamp] - traceEvGoDestroySyscall // goroutine ends in syscall (cgo callback) [timestamp] - traceEvGoStop // goroutine yields its time, but is runnable [timestamp, reason, stack ID] - traceEvGoBlock // goroutine blocks [timestamp, reason, stack ID] - traceEvGoUnblock // goroutine is unblocked [timestamp, goroutine ID, goroutine seq, stack ID] - traceEvGoSyscallBegin // syscall enter [timestamp, P seq, stack ID] - traceEvGoSyscallEnd // syscall exit [timestamp] - traceEvGoSyscallEndBlocked // syscall exit and it blocked at some point [timestamp] - traceEvGoStatus // goroutine status at the start of a generation [timestamp, goroutine ID, M ID, status] - - // STW. - traceEvSTWBegin // STW start [timestamp, kind] - traceEvSTWEnd // STW done [timestamp] - - // GC events. - traceEvGCActive // GC active [timestamp, seq] - traceEvGCBegin // GC start [timestamp, seq, stack ID] - traceEvGCEnd // GC done [timestamp, seq] - traceEvGCSweepActive // GC sweep active [timestamp, P ID] - traceEvGCSweepBegin // GC sweep start [timestamp, stack ID] - traceEvGCSweepEnd // GC sweep done [timestamp, swept bytes, reclaimed bytes] - traceEvGCMarkAssistActive // GC mark assist active [timestamp, goroutine ID] - traceEvGCMarkAssistBegin // GC mark assist start [timestamp, stack ID] - traceEvGCMarkAssistEnd // GC mark assist done [timestamp] - traceEvHeapAlloc // gcController.heapLive change [timestamp, heap alloc in bytes] - traceEvHeapGoal // gcController.heapGoal() change [timestamp, heap goal in bytes] - - // Annotations. - traceEvGoLabel // apply string label to current running goroutine [timestamp, label string ID] - traceEvUserTaskBegin // trace.NewTask [timestamp, internal task ID, internal parent task ID, name string ID, stack ID] - traceEvUserTaskEnd // end of a task [timestamp, internal task ID, stack ID] - traceEvUserRegionBegin // trace.{Start,With}Region [timestamp, internal task ID, name string ID, stack ID] - traceEvUserRegionEnd // trace.{End,With}Region [timestamp, internal task ID, name string ID, stack ID] - traceEvUserLog // trace.Log [timestamp, internal task ID, key string ID, stack, value string ID] -) - -// traceArg is a simple wrapper type to help ensure that arguments passed -// to traces are well-formed. -type traceArg uint64 - -// traceEventWriter is the high-level API for writing trace events. -// -// See the comment on traceWriter about style for more details as to why -// this type and its methods are structured the way they are. -type traceEventWriter struct { - w traceWriter -} - -// eventWriter creates a new traceEventWriter. It is the main entrypoint for writing trace events. -// -// Before creating the event writer, this method will emit a status for the current goroutine -// or proc if it exists, and if it hasn't had its status emitted yet. goStatus and procStatus indicate -// what the status of goroutine or P should be immediately *before* the events that are about to -// be written using the eventWriter (if they exist). No status will be written if there's no active -// goroutine or P. -// -// Callers can elect to pass a constant value here if the status is clear (e.g. a goroutine must have -// been Runnable before a GoStart). Otherwise, callers can query the status of either the goroutine -// or P and pass the appropriate status. -// -// In this case, the default status should be traceGoBad or traceProcBad to help identify bugs sooner. -func (tl traceLocker) eventWriter(goStatus traceGoStatus, procStatus traceProcStatus) traceEventWriter { - w := tl.writer() - if pp := tl.mp.p.ptr(); pp != nil && !pp.trace.statusWasTraced(tl.gen) && pp.trace.acquireStatus(tl.gen) { - w = w.writeProcStatus(uint64(pp.id), procStatus, pp.trace.inSweep) - } - if gp := tl.mp.curg; gp != nil && !gp.trace.statusWasTraced(tl.gen) && gp.trace.acquireStatus(tl.gen) { - w = w.writeGoStatus(uint64(gp.goid), int64(tl.mp.procid), goStatus, gp.inMarkAssist) - } - return traceEventWriter{w} -} - -// commit writes out a trace event and calls end. It's a helper to make the -// common case of writing out a single event less error-prone. -func (e traceEventWriter) commit(ev traceEv, args ...traceArg) { - e = e.write(ev, args...) - e.end() -} - -// write writes an event into the trace. -func (e traceEventWriter) write(ev traceEv, args ...traceArg) traceEventWriter { - e.w = e.w.event(ev, args...) - return e -} - -// end finishes writing to the trace. The traceEventWriter must not be used after this call. -func (e traceEventWriter) end() { - e.w.end() -} - -// traceEventWrite is the part of traceEvent that actually writes the event. -func (w traceWriter) event(ev traceEv, args ...traceArg) traceWriter { - // Make sure we have room. - w, _ = w.ensure(1 + (len(args)+1)*traceBytesPerNumber) - - // Compute the timestamp diff that we'll put in the trace. - ts := traceClockNow() - if ts <= w.traceBuf.lastTime { - ts = w.traceBuf.lastTime + 1 - } - tsDiff := uint64(ts - w.traceBuf.lastTime) - w.traceBuf.lastTime = ts - - // Write out event. - w.byte(byte(ev)) - w.varint(tsDiff) - for _, arg := range args { - w.varint(uint64(arg)) - } - return w -} - -// stack takes a stack trace skipping the provided number of frames. -// It then returns a traceArg representing that stack which may be -// passed to write. -func (tl traceLocker) stack(skip int) traceArg { - return traceArg(traceStack(skip, tl.mp, tl.gen)) -} - -// startPC takes a start PC for a goroutine and produces a unique -// stack ID for it. -// -// It then returns a traceArg representing that stack which may be -// passed to write. -func (tl traceLocker) startPC(pc uintptr) traceArg { - // +PCQuantum because makeTraceFrame expects return PCs and subtracts PCQuantum. - return traceArg(trace.stackTab[tl.gen%2].put([]uintptr{ - logicalStackSentinel, - startPCForTrace(pc) + sys.PCQuantum, - })) -} - -// string returns a traceArg representing s which may be passed to write. -// The string is assumed to be relatively short and popular, so it may be -// stored for a while in the string dictionary. -func (tl traceLocker) string(s string) traceArg { - return traceArg(trace.stringTab[tl.gen%2].put(tl.gen, s)) -} - -// uniqueString returns a traceArg representing s which may be passed to write. -// The string is assumed to be unique or long, so it will be written out to -// the trace eagerly. -func (tl traceLocker) uniqueString(s string) traceArg { - return traceArg(trace.stringTab[tl.gen%2].emit(tl.gen, s)) -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2map.go b/contrib/go/_std_1.22/src/runtime/trace2map.go deleted file mode 100644 index 195ec0bbe729..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2map.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Simple hash table for tracing. Provides a mapping -// between variable-length data and a unique ID. Subsequent -// puts of the same data will return the same ID. -// -// Uses a region-based allocation scheme and assumes that the -// table doesn't ever grow very big. -// -// This is definitely not a general-purpose hash table! It avoids -// doing any high-level Go operations so it's safe to use even in -// sensitive contexts. - -package runtime - -import ( - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -type traceMap struct { - lock mutex // Must be acquired on the system stack - seq atomic.Uint64 - mem traceRegionAlloc - tab [1 << 13]atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap) -} - -type traceMapNode struct { - _ sys.NotInHeap - link atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap) - hash uintptr - id uint64 - data []byte -} - -// next is a type-safe wrapper around link. -func (n *traceMapNode) next() *traceMapNode { - return (*traceMapNode)(n.link.Load()) -} - -// stealID steals an ID from the table, ensuring that it will not -// appear in the table anymore. -func (tab *traceMap) stealID() uint64 { - return tab.seq.Add(1) -} - -// put inserts the data into the table. -// -// It's always safe to noescape data because its bytes are always copied. -// -// Returns a unique ID for the data and whether this is the first time -// the data has been added to the map. -func (tab *traceMap) put(data unsafe.Pointer, size uintptr) (uint64, bool) { - if size == 0 { - return 0, false - } - hash := memhash(data, 0, size) - // First, search the hashtable w/o the mutex. - if id := tab.find(data, size, hash); id != 0 { - return id, false - } - // Now, double check under the mutex. - // Switch to the system stack so we can acquire tab.lock - var id uint64 - var added bool - systemstack(func() { - lock(&tab.lock) - if id = tab.find(data, size, hash); id != 0 { - unlock(&tab.lock) - return - } - // Create new record. - id = tab.seq.Add(1) - vd := tab.newTraceMapNode(data, size, hash, id) - - // Insert it into the table. - // - // Update the link first, since the node isn't published yet. - // Then, store the node in the table as the new first node - // for the bucket. - part := int(hash % uintptr(len(tab.tab))) - vd.link.StoreNoWB(tab.tab[part].Load()) - tab.tab[part].StoreNoWB(unsafe.Pointer(vd)) - unlock(&tab.lock) - - added = true - }) - return id, added -} - -// find looks up data in the table, assuming hash is a hash of data. -// -// Returns 0 if the data is not found, and the unique ID for it if it is. -func (tab *traceMap) find(data unsafe.Pointer, size, hash uintptr) uint64 { - part := int(hash % uintptr(len(tab.tab))) - for vd := tab.bucket(part); vd != nil; vd = vd.next() { - // Synchronization not necessary. Once published to the table, these - // values are immutable. - if vd.hash == hash && uintptr(len(vd.data)) == size { - if memequal(unsafe.Pointer(&vd.data[0]), data, size) { - return vd.id - } - } - } - return 0 -} - -// bucket is a type-safe wrapper for looking up a value in tab.tab. -func (tab *traceMap) bucket(part int) *traceMapNode { - return (*traceMapNode)(tab.tab[part].Load()) -} - -func (tab *traceMap) newTraceMapNode(data unsafe.Pointer, size, hash uintptr, id uint64) *traceMapNode { - // Create data array. - sl := notInHeapSlice{ - array: tab.mem.alloc(size), - len: int(size), - cap: int(size), - } - memmove(unsafe.Pointer(sl.array), data, size) - - // Create metadata structure. - meta := (*traceMapNode)(unsafe.Pointer(tab.mem.alloc(unsafe.Sizeof(traceMapNode{})))) - *(*notInHeapSlice)(unsafe.Pointer(&meta.data)) = sl - meta.id = id - meta.hash = hash - return meta -} - -// reset drops all allocated memory from the table and resets it. -// -// tab.lock must be held. Must run on the system stack because of this. -// -//go:systemstack -func (tab *traceMap) reset() { - assertLockHeld(&tab.lock) - tab.mem.drop() - tab.seq.Store(0) - // Clear table without write barriers. The table consists entirely - // of notinheap pointers, so this is fine. - // - // Write barriers may theoretically call into the tracer and acquire - // the lock again, and this lock ordering is expressed in the static - // lock ranking checker. - memclrNoHeapPointers(unsafe.Pointer(&tab.tab), unsafe.Sizeof(tab.tab)) -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2region.go b/contrib/go/_std_1.22/src/runtime/trace2region.go deleted file mode 100644 index b514d127b592..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2region.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Simple not-in-heap bump-pointer traceRegion allocator. - -package runtime - -import ( - "internal/goarch" - "runtime/internal/sys" - "unsafe" -) - -// traceRegionAlloc is a non-thread-safe region allocator. -// It holds a linked list of traceRegionAllocBlock. -type traceRegionAlloc struct { - head *traceRegionAllocBlock - off uintptr -} - -// traceRegionAllocBlock is a block in traceRegionAlloc. -// -// traceRegionAllocBlock is allocated from non-GC'd memory, so it must not -// contain heap pointers. Writes to pointers to traceRegionAllocBlocks do -// not need write barriers. -type traceRegionAllocBlock struct { - _ sys.NotInHeap - next *traceRegionAllocBlock - data [64<<10 - goarch.PtrSize]byte -} - -// alloc allocates n-byte block. -func (a *traceRegionAlloc) alloc(n uintptr) *notInHeap { - n = alignUp(n, goarch.PtrSize) - if a.head == nil || a.off+n > uintptr(len(a.head.data)) { - if n > uintptr(len(a.head.data)) { - throw("traceRegion: alloc too large") - } - block := (*traceRegionAllocBlock)(sysAlloc(unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys)) - if block == nil { - throw("traceRegion: out of memory") - } - block.next = a.head - a.head = block - a.off = 0 - } - p := &a.head.data[a.off] - a.off += n - return (*notInHeap)(unsafe.Pointer(p)) -} - -// drop frees all previously allocated memory and resets the allocator. -func (a *traceRegionAlloc) drop() { - for a.head != nil { - block := a.head - a.head = block.next - sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2runtime.go b/contrib/go/_std_1.22/src/runtime/trace2runtime.go deleted file mode 100644 index 512e53907e60..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2runtime.go +++ /dev/null @@ -1,704 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Runtime -> tracer API. - -package runtime - -import ( - "runtime/internal/atomic" - _ "unsafe" // for go:linkname -) - -// gTraceState is per-G state for the tracer. -type gTraceState struct { - traceSchedResourceState -} - -// reset resets the gTraceState for a new goroutine. -func (s *gTraceState) reset() { - s.seq = [2]uint64{} - // N.B. s.statusTraced is managed and cleared separately. -} - -// mTraceState is per-M state for the tracer. -type mTraceState struct { - seqlock atomic.Uintptr // seqlock indicating that this M is writing to a trace buffer. - buf [2]*traceBuf // Per-M traceBuf for writing. Indexed by trace.gen%2. - link *m // Snapshot of alllink or freelink. -} - -// pTraceState is per-P state for the tracer. -type pTraceState struct { - traceSchedResourceState - - // mSyscallID is the ID of the M this was bound to before entering a syscall. - mSyscallID int64 - - // maySweep indicates the sweep events should be traced. - // This is used to defer the sweep start event until a span - // has actually been swept. - maySweep bool - - // inSweep indicates that at least one sweep event has been traced. - inSweep bool - - // swept and reclaimed track the number of bytes swept and reclaimed - // by sweeping in the current sweep loop (while maySweep was true). - swept, reclaimed uintptr -} - -// traceLockInit initializes global trace locks. -func traceLockInit() { - // Sharing a lock rank here is fine because they should never be accessed - // together. If they are, we want to find out immediately. - lockInit(&trace.stringTab[0].lock, lockRankTraceStrings) - lockInit(&trace.stringTab[0].tab.lock, lockRankTraceStrings) - lockInit(&trace.stringTab[1].lock, lockRankTraceStrings) - lockInit(&trace.stringTab[1].tab.lock, lockRankTraceStrings) - lockInit(&trace.stackTab[0].tab.lock, lockRankTraceStackTab) - lockInit(&trace.stackTab[1].tab.lock, lockRankTraceStackTab) - lockInit(&trace.lock, lockRankTrace) -} - -// lockRankMayTraceFlush records the lock ranking effects of a -// potential call to traceFlush. -// -// nosplit because traceAcquire is nosplit. -// -//go:nosplit -func lockRankMayTraceFlush() { - lockWithRankMayAcquire(&trace.lock, getLockRank(&trace.lock)) -} - -// traceBlockReason is an enumeration of reasons a goroutine might block. -// This is the interface the rest of the runtime uses to tell the -// tracer why a goroutine blocked. The tracer then propagates this information -// into the trace however it sees fit. -// -// Note that traceBlockReasons should not be compared, since reasons that are -// distinct by name may *not* be distinct by value. -type traceBlockReason uint8 - -const ( - traceBlockGeneric traceBlockReason = iota - traceBlockForever - traceBlockNet - traceBlockSelect - traceBlockCondWait - traceBlockSync - traceBlockChanSend - traceBlockChanRecv - traceBlockGCMarkAssist - traceBlockGCSweep - traceBlockSystemGoroutine - traceBlockPreempted - traceBlockDebugCall - traceBlockUntilGCEnds - traceBlockSleep -) - -var traceBlockReasonStrings = [...]string{ - traceBlockGeneric: "unspecified", - traceBlockForever: "forever", - traceBlockNet: "network", - traceBlockSelect: "select", - traceBlockCondWait: "sync.(*Cond).Wait", - traceBlockSync: "sync", - traceBlockChanSend: "chan send", - traceBlockChanRecv: "chan receive", - traceBlockGCMarkAssist: "GC mark assist wait for work", - traceBlockGCSweep: "GC background sweeper wait", - traceBlockSystemGoroutine: "system goroutine wait", - traceBlockPreempted: "preempted", - traceBlockDebugCall: "wait for debug call", - traceBlockUntilGCEnds: "wait until GC ends", - traceBlockSleep: "sleep", -} - -// traceGoStopReason is an enumeration of reasons a goroutine might yield. -// -// Note that traceGoStopReasons should not be compared, since reasons that are -// distinct by name may *not* be distinct by value. -type traceGoStopReason uint8 - -const ( - traceGoStopGeneric traceGoStopReason = iota - traceGoStopGoSched - traceGoStopPreempted -) - -var traceGoStopReasonStrings = [...]string{ - traceGoStopGeneric: "unspecified", - traceGoStopGoSched: "runtime.Gosched", - traceGoStopPreempted: "preempted", -} - -// traceEnabled returns true if the trace is currently enabled. -// -//go:nosplit -func traceEnabled() bool { - return trace.gen.Load() != 0 -} - -// traceShuttingDown returns true if the trace is currently shutting down. -func traceShuttingDown() bool { - return trace.shutdown.Load() -} - -// traceLocker represents an M writing trace events. While a traceLocker value -// is valid, the tracer observes all operations on the G/M/P or trace events being -// written as happening atomically. -type traceLocker struct { - mp *m - gen uintptr -} - -// debugTraceReentrancy checks if the trace is reentrant. -// -// This is optional because throwing in a function makes it instantly -// not inlineable, and we want traceAcquire to be inlineable for -// low overhead when the trace is disabled. -const debugTraceReentrancy = false - -// traceAcquire prepares this M for writing one or more trace events. -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func traceAcquire() traceLocker { - if !traceEnabled() { - return traceLocker{} - } - return traceAcquireEnabled() -} - -// traceAcquireEnabled is the traceEnabled path for traceAcquire. It's explicitly -// broken out to make traceAcquire inlineable to keep the overhead of the tracer -// when it's disabled low. -// -// nosplit because it's called by traceAcquire, which is nosplit. -// -//go:nosplit -func traceAcquireEnabled() traceLocker { - // Any time we acquire a traceLocker, we may flush a trace buffer. But - // buffer flushes are rare. Record the lock edge even if it doesn't happen - // this time. - lockRankMayTraceFlush() - - // Prevent preemption. - mp := acquirem() - - // Acquire the trace seqlock. This prevents traceAdvance from moving forward - // until all Ms are observed to be outside of their seqlock critical section. - // - // Note: The seqlock is mutated here and also in traceCPUSample. If you update - // usage of the seqlock here, make sure to also look at what traceCPUSample is - // doing. - seq := mp.trace.seqlock.Add(1) - if debugTraceReentrancy && seq%2 != 1 { - throw("bad use of trace.seqlock or tracer is reentrant") - } - - // N.B. This load of gen appears redundant with the one in traceEnabled. - // However, it's very important that the gen we use for writing to the trace - // is acquired under a traceLocker so traceAdvance can make sure no stale - // gen values are being used. - // - // Because we're doing this load again, it also means that the trace - // might end up being disabled when we load it. In that case we need to undo - // what we did and bail. - gen := trace.gen.Load() - if gen == 0 { - mp.trace.seqlock.Add(1) - releasem(mp) - return traceLocker{} - } - return traceLocker{mp, gen} -} - -// ok returns true if the traceLocker is valid (i.e. tracing is enabled). -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func (tl traceLocker) ok() bool { - return tl.gen != 0 -} - -// traceRelease indicates that this M is done writing trace events. -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func traceRelease(tl traceLocker) { - seq := tl.mp.trace.seqlock.Add(1) - if debugTraceReentrancy && seq%2 != 0 { - print("runtime: seq=", seq, "\n") - throw("bad use of trace.seqlock") - } - releasem(tl.mp) -} - -// traceExitingSyscall marks a goroutine as exiting the syscall slow path. -// -// Must be paired with a traceExitedSyscall call. -func traceExitingSyscall() { - trace.exitingSyscall.Add(1) -} - -// traceExitedSyscall marks a goroutine as having exited the syscall slow path. -func traceExitedSyscall() { - trace.exitingSyscall.Add(-1) -} - -// Gomaxprocs emits a ProcsChange event. -func (tl traceLocker) Gomaxprocs(procs int32) { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvProcsChange, traceArg(procs), tl.stack(1)) -} - -// ProcStart traces a ProcStart event. -// -// Must be called with a valid P. -func (tl traceLocker) ProcStart() { - pp := tl.mp.p.ptr() - // Procs are typically started within the scheduler when there is no user goroutine. If there is a user goroutine, - // it must be in _Gsyscall because the only time a goroutine is allowed to have its Proc moved around from under it - // is during a syscall. - tl.eventWriter(traceGoSyscall, traceProcIdle).commit(traceEvProcStart, traceArg(pp.id), pp.trace.nextSeq(tl.gen)) -} - -// ProcStop traces a ProcStop event. -func (tl traceLocker) ProcStop(pp *p) { - // The only time a goroutine is allowed to have its Proc moved around - // from under it is during a syscall. - tl.eventWriter(traceGoSyscall, traceProcRunning).commit(traceEvProcStop) -} - -// GCActive traces a GCActive event. -// -// Must be emitted by an actively running goroutine on an active P. This restriction can be changed -// easily and only depends on where it's currently called. -func (tl traceLocker) GCActive() { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCActive, traceArg(trace.seqGC)) - // N.B. Only one GC can be running at a time, so this is naturally - // serialized by the caller. - trace.seqGC++ -} - -// GCStart traces a GCBegin event. -// -// Must be emitted by an actively running goroutine on an active P. This restriction can be changed -// easily and only depends on where it's currently called. -func (tl traceLocker) GCStart() { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCBegin, traceArg(trace.seqGC), tl.stack(3)) - // N.B. Only one GC can be running at a time, so this is naturally - // serialized by the caller. - trace.seqGC++ -} - -// GCDone traces a GCEnd event. -// -// Must be emitted by an actively running goroutine on an active P. This restriction can be changed -// easily and only depends on where it's currently called. -func (tl traceLocker) GCDone() { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCEnd, traceArg(trace.seqGC)) - // N.B. Only one GC can be running at a time, so this is naturally - // serialized by the caller. - trace.seqGC++ -} - -// STWStart traces a STWBegin event. -func (tl traceLocker) STWStart(reason stwReason) { - // Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the - // runtime's state tracking, but it's more accurate and doesn't result in any loss of information. - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSTWBegin, tl.string(reason.String()), tl.stack(2)) -} - -// STWDone traces a STWEnd event. -func (tl traceLocker) STWDone() { - // Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the - // runtime's state tracking, but it's more accurate and doesn't result in any loss of information. - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSTWEnd) -} - -// GCSweepStart prepares to trace a sweep loop. This does not -// emit any events until traceGCSweepSpan is called. -// -// GCSweepStart must be paired with traceGCSweepDone and there -// must be no preemption points between these two calls. -// -// Must be called with a valid P. -func (tl traceLocker) GCSweepStart() { - // Delay the actual GCSweepBegin event until the first span - // sweep. If we don't sweep anything, don't emit any events. - pp := tl.mp.p.ptr() - if pp.trace.maySweep { - throw("double traceGCSweepStart") - } - pp.trace.maySweep, pp.trace.swept, pp.trace.reclaimed = true, 0, 0 -} - -// GCSweepSpan traces the sweep of a single span. If this is -// the first span swept since traceGCSweepStart was called, this -// will emit a GCSweepBegin event. -// -// This may be called outside a traceGCSweepStart/traceGCSweepDone -// pair; however, it will not emit any trace events in this case. -// -// Must be called with a valid P. -func (tl traceLocker) GCSweepSpan(bytesSwept uintptr) { - pp := tl.mp.p.ptr() - if pp.trace.maySweep { - if pp.trace.swept == 0 { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCSweepBegin, tl.stack(1)) - pp.trace.inSweep = true - } - pp.trace.swept += bytesSwept - } -} - -// GCSweepDone finishes tracing a sweep loop. If any memory was -// swept (i.e. traceGCSweepSpan emitted an event) then this will emit -// a GCSweepEnd event. -// -// Must be called with a valid P. -func (tl traceLocker) GCSweepDone() { - pp := tl.mp.p.ptr() - if !pp.trace.maySweep { - throw("missing traceGCSweepStart") - } - if pp.trace.inSweep { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCSweepEnd, traceArg(pp.trace.swept), traceArg(pp.trace.reclaimed)) - pp.trace.inSweep = false - } - pp.trace.maySweep = false -} - -// GCMarkAssistStart emits a MarkAssistBegin event. -func (tl traceLocker) GCMarkAssistStart() { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCMarkAssistBegin, tl.stack(1)) -} - -// GCMarkAssistDone emits a MarkAssistEnd event. -func (tl traceLocker) GCMarkAssistDone() { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCMarkAssistEnd) -} - -// GoCreate emits a GoCreate event. -func (tl traceLocker) GoCreate(newg *g, pc uintptr) { - newg.trace.setStatusTraced(tl.gen) - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoCreate, traceArg(newg.goid), tl.startPC(pc), tl.stack(2)) -} - -// GoStart emits a GoStart event. -// -// Must be called with a valid P. -func (tl traceLocker) GoStart() { - gp := getg().m.curg - pp := gp.m.p - w := tl.eventWriter(traceGoRunnable, traceProcRunning) - w = w.write(traceEvGoStart, traceArg(gp.goid), gp.trace.nextSeq(tl.gen)) - if pp.ptr().gcMarkWorkerMode != gcMarkWorkerNotWorker { - w = w.write(traceEvGoLabel, trace.markWorkerLabels[tl.gen%2][pp.ptr().gcMarkWorkerMode]) - } - w.end() -} - -// GoEnd emits a GoDestroy event. -// -// TODO(mknyszek): Rename this to GoDestroy. -func (tl traceLocker) GoEnd() { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoDestroy) -} - -// GoSched emits a GoStop event with a GoSched reason. -func (tl traceLocker) GoSched() { - tl.GoStop(traceGoStopGoSched) -} - -// GoPreempt emits a GoStop event with a GoPreempted reason. -func (tl traceLocker) GoPreempt() { - tl.GoStop(traceGoStopPreempted) -} - -// GoStop emits a GoStop event with the provided reason. -func (tl traceLocker) GoStop(reason traceGoStopReason) { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoStop, traceArg(trace.goStopReasons[tl.gen%2][reason]), tl.stack(1)) -} - -// GoPark emits a GoBlock event with the provided reason. -// -// TODO(mknyszek): Replace traceBlockReason with waitReason. It's silly -// that we have both, and waitReason is way more descriptive. -func (tl traceLocker) GoPark(reason traceBlockReason, skip int) { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoBlock, traceArg(trace.goBlockReasons[tl.gen%2][reason]), tl.stack(skip)) -} - -// GoUnpark emits a GoUnblock event. -func (tl traceLocker) GoUnpark(gp *g, skip int) { - // Emit a GoWaiting status if necessary for the unblocked goroutine. - w := tl.eventWriter(traceGoRunning, traceProcRunning) - if !gp.trace.statusWasTraced(tl.gen) && gp.trace.acquireStatus(tl.gen) { - // Careful: don't use the event writer. We never want status or in-progress events - // to trigger more in-progress events. - w.w = w.w.writeGoStatus(gp.goid, -1, traceGoWaiting, gp.inMarkAssist) - } - w.commit(traceEvGoUnblock, traceArg(gp.goid), gp.trace.nextSeq(tl.gen), tl.stack(skip)) -} - -// GoSysCall emits a GoSyscallBegin event. -// -// Must be called with a valid P. -func (tl traceLocker) GoSysCall() { - var skip int - switch { - case tracefpunwindoff(): - // Unwind by skipping 1 frame relative to gp.syscallsp which is captured 3 - // results by hard coding the number of frames in between our caller and the - // actual syscall, see cases below. - // TODO(felixge): Implement gp.syscallbp to avoid this workaround? - skip = 1 - case GOOS == "solaris" || GOOS == "illumos": - // These platforms don't use a libc_read_trampoline. - skip = 3 - default: - // Skip the extra trampoline frame used on most systems. - skip = 4 - } - // Scribble down the M that the P is currently attached to. - pp := tl.mp.p.ptr() - pp.trace.mSyscallID = int64(tl.mp.procid) - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoSyscallBegin, pp.trace.nextSeq(tl.gen), tl.stack(skip)) -} - -// GoSysExit emits a GoSyscallEnd event, possibly along with a GoSyscallBlocked event -// if lostP is true. -// -// lostP must be true in all cases that a goroutine loses its P during a syscall. -// This means it's not sufficient to check if it has no P. In particular, it needs to be -// true in the following cases: -// - The goroutine lost its P, it ran some other code, and then got it back. It's now running with that P. -// - The goroutine lost its P and was unable to reacquire it, and is now running without a P. -// - The goroutine lost its P and acquired a different one, and is now running with that P. -func (tl traceLocker) GoSysExit(lostP bool) { - ev := traceEvGoSyscallEnd - procStatus := traceProcSyscall // Procs implicitly enter traceProcSyscall on GoSyscallBegin. - if lostP { - ev = traceEvGoSyscallEndBlocked - procStatus = traceProcRunning // If a G has a P when emitting this event, it reacquired a P and is indeed running. - } else { - tl.mp.p.ptr().trace.mSyscallID = -1 - } - tl.eventWriter(traceGoSyscall, procStatus).commit(ev) -} - -// ProcSteal indicates that our current M stole a P from another M. -// -// inSyscall indicates that we're stealing the P from a syscall context. -// -// The caller must have ownership of pp. -func (tl traceLocker) ProcSteal(pp *p, inSyscall bool) { - // Grab the M ID we stole from. - mStolenFrom := pp.trace.mSyscallID - pp.trace.mSyscallID = -1 - - // The status of the proc and goroutine, if we need to emit one here, is not evident from the - // context of just emitting this event alone. There are two cases. Either we're trying to steal - // the P just to get its attention (e.g. STW or sysmon retake) or we're trying to steal a P for - // ourselves specifically to keep running. The two contexts look different, but can be summarized - // fairly succinctly. In the former, we're a regular running goroutine and proc, if we have either. - // In the latter, we're a goroutine in a syscall. - goStatus := traceGoRunning - procStatus := traceProcRunning - if inSyscall { - goStatus = traceGoSyscall - procStatus = traceProcSyscallAbandoned - } - w := tl.eventWriter(goStatus, procStatus) - - // Emit the status of the P we're stealing. We may have *just* done this when creating the event - // writer but it's not guaranteed, even if inSyscall is true. Although it might seem like from a - // syscall context we're always stealing a P for ourselves, we may have not wired it up yet (so - // it wouldn't be visible to eventWriter) or we may not even intend to wire it up to ourselves - // at all (e.g. entersyscall_gcwait). - if !pp.trace.statusWasTraced(tl.gen) && pp.trace.acquireStatus(tl.gen) { - // Careful: don't use the event writer. We never want status or in-progress events - // to trigger more in-progress events. - w.w = w.w.writeProcStatus(uint64(pp.id), traceProcSyscallAbandoned, pp.trace.inSweep) - } - w.commit(traceEvProcSteal, traceArg(pp.id), pp.trace.nextSeq(tl.gen), traceArg(mStolenFrom)) -} - -// GoSysBlock is a no-op in the new tracer. -func (tl traceLocker) GoSysBlock(pp *p) { -} - -// HeapAlloc emits a HeapAlloc event. -func (tl traceLocker) HeapAlloc(live uint64) { - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapAlloc, traceArg(live)) -} - -// HeapGoal reads the current heap goal and emits a HeapGoal event. -func (tl traceLocker) HeapGoal() { - heapGoal := gcController.heapGoal() - if heapGoal == ^uint64(0) { - // Heap-based triggering is disabled. - heapGoal = 0 - } - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapGoal, traceArg(heapGoal)) -} - -// OneNewExtraM is a no-op in the new tracer. This is worth keeping around though because -// it's a good place to insert a thread-level event about the new extra M. -func (tl traceLocker) OneNewExtraM(_ *g) { -} - -// GoCreateSyscall indicates that a goroutine has transitioned from dead to GoSyscall. -// -// Unlike GoCreate, the caller must be running on gp. -// -// This occurs when C code calls into Go. On pthread platforms it occurs only when -// a C thread calls into Go code for the first time. -func (tl traceLocker) GoCreateSyscall(gp *g) { - // N.B. We should never trace a status for this goroutine (which we're currently running on), - // since we want this to appear like goroutine creation. - gp.trace.setStatusTraced(tl.gen) - tl.eventWriter(traceGoBad, traceProcBad).commit(traceEvGoCreateSyscall, traceArg(gp.goid)) -} - -// GoDestroySyscall indicates that a goroutine has transitioned from GoSyscall to dead. -// -// Must not have a P. -// -// This occurs when Go code returns back to C. On pthread platforms it occurs only when -// the C thread is destroyed. -func (tl traceLocker) GoDestroySyscall() { - // N.B. If we trace a status here, we must never have a P, and we must be on a goroutine - // that is in the syscall state. - tl.eventWriter(traceGoSyscall, traceProcBad).commit(traceEvGoDestroySyscall) -} - -// To access runtime functions from runtime/trace. -// See runtime/trace/annotation.go - -// trace_userTaskCreate emits a UserTaskCreate event. -// -//go:linkname trace_userTaskCreate runtime/trace.userTaskCreate -func trace_userTaskCreate(id, parentID uint64, taskType string) { - tl := traceAcquire() - if !tl.ok() { - // Need to do this check because the caller won't have it. - return - } - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserTaskBegin, traceArg(id), traceArg(parentID), tl.string(taskType), tl.stack(3)) - traceRelease(tl) -} - -// trace_userTaskEnd emits a UserTaskEnd event. -// -//go:linkname trace_userTaskEnd runtime/trace.userTaskEnd -func trace_userTaskEnd(id uint64) { - tl := traceAcquire() - if !tl.ok() { - // Need to do this check because the caller won't have it. - return - } - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserTaskEnd, traceArg(id), tl.stack(2)) - traceRelease(tl) -} - -// trace_userTaskEnd emits a UserRegionBegin or UserRegionEnd event, -// depending on mode (0 == Begin, 1 == End). -// -// TODO(mknyszek): Just make this two functions. -// -//go:linkname trace_userRegion runtime/trace.userRegion -func trace_userRegion(id, mode uint64, name string) { - tl := traceAcquire() - if !tl.ok() { - // Need to do this check because the caller won't have it. - return - } - var ev traceEv - switch mode { - case 0: - ev = traceEvUserRegionBegin - case 1: - ev = traceEvUserRegionEnd - default: - return - } - tl.eventWriter(traceGoRunning, traceProcRunning).commit(ev, traceArg(id), tl.string(name), tl.stack(3)) - traceRelease(tl) -} - -// trace_userTaskEnd emits a UserRegionBegin or UserRegionEnd event. -// -//go:linkname trace_userLog runtime/trace.userLog -func trace_userLog(id uint64, category, message string) { - tl := traceAcquire() - if !tl.ok() { - // Need to do this check because the caller won't have it. - return - } - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserLog, traceArg(id), tl.string(category), tl.uniqueString(message), tl.stack(3)) - traceRelease(tl) -} - -// traceProcFree is called when a P is destroyed. -// -// This must run on the system stack to match the old tracer. -// -//go:systemstack -func traceProcFree(_ *p) { -} - -// traceThreadDestroy is called when a thread is removed from -// sched.freem. -// -// mp must not be able to emit trace events anymore. -// -// sched.lock must be held to synchronize with traceAdvance. -func traceThreadDestroy(mp *m) { - assertLockHeld(&sched.lock) - - // Flush all outstanding buffers to maintain the invariant - // that an M only has active buffers while on sched.freem - // or allm. - // - // Perform a traceAcquire/traceRelease on behalf of mp to - // synchronize with the tracer trying to flush our buffer - // as well. - seq := mp.trace.seqlock.Add(1) - if debugTraceReentrancy && seq%2 != 1 { - throw("bad use of trace.seqlock or tracer is reentrant") - } - systemstack(func() { - lock(&trace.lock) - for i := range mp.trace.buf { - if mp.trace.buf[i] != nil { - // N.B. traceBufFlush accepts a generation, but it - // really just cares about gen%2. - traceBufFlush(mp.trace.buf[i], uintptr(i)) - mp.trace.buf[i] = nil - } - } - unlock(&trace.lock) - }) - seq1 := mp.trace.seqlock.Add(1) - if seq1 != seq+1 { - print("runtime: seq1=", seq1, "\n") - throw("bad use of trace.seqlock") - } -} - -// Not used in the new tracer; solely for compatibility with the old tracer. -// nosplit because it's called from exitsyscall without a P. -// -//go:nosplit -func (_ traceLocker) RecordSyscallExitedTime(_ *g, _ *p) { -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2stack.go b/contrib/go/_std_1.22/src/runtime/trace2stack.go deleted file mode 100644 index af6638fa8f08..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2stack.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Trace stack table and acquisition. - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "unsafe" -) - -const ( - // Maximum number of PCs in a single stack trace. - // Since events contain only stack id rather than whole stack trace, - // we can allow quite large values here. - traceStackSize = 128 - - // logicalStackSentinel is a sentinel value at pcBuf[0] signifying that - // pcBuf[1:] holds a logical stack requiring no further processing. Any other - // value at pcBuf[0] represents a skip value to apply to the physical stack in - // pcBuf[1:] after inline expansion. - logicalStackSentinel = ^uintptr(0) -) - -// traceStack captures a stack trace and registers it in the trace stack table. -// It then returns its unique ID. -// -// skip controls the number of leaf frames to omit in order to hide tracer internals -// from stack traces, see CL 5523. -// -// Avoid calling this function directly. gen needs to be the current generation -// that this stack trace is being written out for, which needs to be synchronized with -// generations moving forward. Prefer traceEventWriter.stack. -func traceStack(skip int, mp *m, gen uintptr) uint64 { - var pcBuf [traceStackSize]uintptr - - gp := getg() - curgp := gp.m.curg - nstk := 1 - if tracefpunwindoff() || mp.hasCgoOnStack() { - // Slow path: Unwind using default unwinder. Used when frame pointer - // unwinding is unavailable or disabled (tracefpunwindoff), or might - // produce incomplete results or crashes (hasCgoOnStack). Note that no - // cgo callback related crashes have been observed yet. The main - // motivation is to take advantage of a potentially registered cgo - // symbolizer. - pcBuf[0] = logicalStackSentinel - if curgp == gp { - nstk += callers(skip+1, pcBuf[1:]) - } else if curgp != nil { - nstk += gcallers(curgp, skip, pcBuf[1:]) - } - } else { - // Fast path: Unwind using frame pointers. - pcBuf[0] = uintptr(skip) - if curgp == gp { - nstk += fpTracebackPCs(unsafe.Pointer(getfp()), pcBuf[1:]) - } else if curgp != nil { - // We're called on the g0 stack through mcall(fn) or systemstack(fn). To - // behave like gcallers above, we start unwinding from sched.bp, which - // points to the caller frame of the leaf frame on g's stack. The return - // address of the leaf frame is stored in sched.pc, which we manually - // capture here. - pcBuf[1] = curgp.sched.pc - nstk += 1 + fpTracebackPCs(unsafe.Pointer(curgp.sched.bp), pcBuf[2:]) - } - } - if nstk > 0 { - nstk-- // skip runtime.goexit - } - if nstk > 0 && curgp.goid == 1 { - nstk-- // skip runtime.main - } - id := trace.stackTab[gen%2].put(pcBuf[:nstk]) - return id -} - -// traceStackTable maps stack traces (arrays of PC's) to unique uint32 ids. -// It is lock-free for reading. -type traceStackTable struct { - tab traceMap -} - -// put returns a unique id for the stack trace pcs and caches it in the table, -// if it sees the trace for the first time. -func (t *traceStackTable) put(pcs []uintptr) uint64 { - if len(pcs) == 0 { - return 0 - } - id, _ := t.tab.put(noescape(unsafe.Pointer(&pcs[0])), uintptr(len(pcs))*unsafe.Sizeof(uintptr(0))) - return id -} - -// dump writes all previously cached stacks to trace buffers, -// releases all memory and resets state. It must only be called once the caller -// can guarantee that there are no more writers to the table. -// -// This must run on the system stack because it flushes buffers and thus -// may acquire trace.lock. -// -//go:systemstack -func (t *traceStackTable) dump(gen uintptr) { - w := unsafeTraceWriter(gen, nil) - - // Iterate over the table. - // - // Do not acquire t.tab.lock. There's a conceptual lock cycle between acquiring this lock - // here and allocation-related locks. Specifically, this lock may be acquired when an event - // is emitted in allocation paths. Simultaneously, we might allocate here with the lock held, - // creating a cycle. In practice, this cycle is never exercised. Because the table is only - // dumped once there are no more writers, it's not possible for the cycle to occur. However - // the lockrank mode is not sophisticated enough to identify this, and if it's not possible - // for that cycle to happen, then it's also not possible for this to race with writers to - // the table. - for i := range t.tab.tab { - stk := t.tab.bucket(i) - for ; stk != nil; stk = stk.next() { - stack := unsafe.Slice((*uintptr)(unsafe.Pointer(&stk.data[0])), uintptr(len(stk.data))/unsafe.Sizeof(uintptr(0))) - - // N.B. This might allocate, but that's OK because we're not writing to the M's buffer, - // but one we're about to create (with ensure). - frames := makeTraceFrames(gen, fpunwindExpand(stack)) - - // Returns the maximum number of bytes required to hold the encoded stack, given that - // it contains N frames. - maxBytes := 1 + (2+4*len(frames))*traceBytesPerNumber - - // Estimate the size of this record. This - // bound is pretty loose, but avoids counting - // lots of varint sizes. - // - // Add 1 because we might also write traceEvStacks. - var flushed bool - w, flushed = w.ensure(1 + maxBytes) - if flushed { - w.byte(byte(traceEvStacks)) - } - - // Emit stack event. - w.byte(byte(traceEvStack)) - w.varint(uint64(stk.id)) - w.varint(uint64(len(frames))) - for _, frame := range frames { - w.varint(uint64(frame.PC)) - w.varint(frame.funcID) - w.varint(frame.fileID) - w.varint(frame.line) - } - } - } - // Still, hold the lock over reset. The callee expects it, even though it's - // not strictly necessary. - lock(&t.tab.lock) - t.tab.reset() - unlock(&t.tab.lock) - - w.flush().end() -} - -// makeTraceFrames returns the frames corresponding to pcs. It may -// allocate and may emit trace events. -func makeTraceFrames(gen uintptr, pcs []uintptr) []traceFrame { - frames := make([]traceFrame, 0, len(pcs)) - ci := CallersFrames(pcs) - for { - f, more := ci.Next() - frames = append(frames, makeTraceFrame(gen, f)) - if !more { - return frames - } - } -} - -type traceFrame struct { - PC uintptr - funcID uint64 - fileID uint64 - line uint64 -} - -// makeTraceFrame sets up a traceFrame for a frame. -func makeTraceFrame(gen uintptr, f Frame) traceFrame { - var frame traceFrame - frame.PC = f.PC - - fn := f.Function - const maxLen = 1 << 10 - if len(fn) > maxLen { - fn = fn[len(fn)-maxLen:] - } - frame.funcID = trace.stringTab[gen%2].put(gen, fn) - frame.line = uint64(f.Line) - file := f.File - if len(file) > maxLen { - file = file[len(file)-maxLen:] - } - frame.fileID = trace.stringTab[gen%2].put(gen, file) - return frame -} - -// tracefpunwindoff returns true if frame pointer unwinding for the tracer is -// disabled via GODEBUG or not supported by the architecture. -func tracefpunwindoff() bool { - return debug.tracefpunwindoff != 0 || (goarch.ArchFamily != goarch.AMD64 && goarch.ArchFamily != goarch.ARM64) -} - -// fpTracebackPCs populates pcBuf with the return addresses for each frame and -// returns the number of PCs written to pcBuf. The returned PCs correspond to -// "physical frames" rather than "logical frames"; that is if A is inlined into -// B, this will return a PC for only B. -func fpTracebackPCs(fp unsafe.Pointer, pcBuf []uintptr) (i int) { - for i = 0; i < len(pcBuf) && fp != nil; i++ { - // return addr sits one word above the frame pointer - pcBuf[i] = *(*uintptr)(unsafe.Pointer(uintptr(fp) + goarch.PtrSize)) - // follow the frame pointer to the next one - fp = unsafe.Pointer(*(*uintptr)(fp)) - } - return i -} - -// fpunwindExpand checks if pcBuf contains logical frames (which include inlined -// frames) or physical frames (produced by frame pointer unwinding) using a -// sentinel value in pcBuf[0]. Logical frames are simply returned without the -// sentinel. Physical frames are turned into logical frames via inline unwinding -// and by applying the skip value that's stored in pcBuf[0]. -func fpunwindExpand(pcBuf []uintptr) []uintptr { - if len(pcBuf) > 0 && pcBuf[0] == logicalStackSentinel { - // pcBuf contains logical rather than inlined frames, skip has already been - // applied, just return it without the sentinel value in pcBuf[0]. - return pcBuf[1:] - } - - var ( - lastFuncID = abi.FuncIDNormal - newPCBuf = make([]uintptr, 0, traceStackSize) - skip = pcBuf[0] - // skipOrAdd skips or appends retPC to newPCBuf and returns true if more - // pcs can be added. - skipOrAdd = func(retPC uintptr) bool { - if skip > 0 { - skip-- - } else { - newPCBuf = append(newPCBuf, retPC) - } - return len(newPCBuf) < cap(newPCBuf) - } - ) - -outer: - for _, retPC := range pcBuf[1:] { - callPC := retPC - 1 - fi := findfunc(callPC) - if !fi.valid() { - // There is no funcInfo if callPC belongs to a C function. In this case - // we still keep the pc, but don't attempt to expand inlined frames. - if more := skipOrAdd(retPC); !more { - break outer - } - continue - } - - u, uf := newInlineUnwinder(fi, callPC) - for ; uf.valid(); uf = u.next(uf) { - sf := u.srcFunc(uf) - if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(lastFuncID) { - // ignore wrappers - } else if more := skipOrAdd(uf.pc + 1); !more { - break outer - } - lastFuncID = sf.funcID - } - } - return newPCBuf -} - -// startPCForTrace returns the start PC of a goroutine for tracing purposes. -// If pc is a wrapper, it returns the PC of the wrapped function. Otherwise it -// returns pc. -func startPCForTrace(pc uintptr) uintptr { - f := findfunc(pc) - if !f.valid() { - return pc // may happen for locked g in extra M since its pc is 0. - } - w := funcdata(f, abi.FUNCDATA_WrapInfo) - if w == nil { - return pc // not a wrapper - } - return f.datap.textAddr(*(*uint32)(w)) -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2status.go b/contrib/go/_std_1.22/src/runtime/trace2status.go deleted file mode 100644 index 5016e086560a..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2status.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Trace goroutine and P status management. - -package runtime - -import "runtime/internal/atomic" - -// traceGoStatus is the status of a goroutine. -// -// They correspond directly to the various goroutine -// statuses. -type traceGoStatus uint8 - -const ( - traceGoBad traceGoStatus = iota - traceGoRunnable - traceGoRunning - traceGoSyscall - traceGoWaiting -) - -// traceProcStatus is the status of a P. -// -// They mostly correspond to the various P statuses. -type traceProcStatus uint8 - -const ( - traceProcBad traceProcStatus = iota - traceProcRunning - traceProcIdle - traceProcSyscall - - // traceProcSyscallAbandoned is a special case of - // traceProcSyscall. It's used in the very specific case - // where the first a P is mentioned in a generation is - // part of a ProcSteal event. If that's the first time - // it's mentioned, then there's no GoSyscallBegin to - // connect the P stealing back to at that point. This - // special state indicates this to the parser, so it - // doesn't try to find a GoSyscallEndBlocked that - // corresponds with the ProcSteal. - traceProcSyscallAbandoned -) - -// writeGoStatus emits a GoStatus event as well as any active ranges on the goroutine. -func (w traceWriter) writeGoStatus(goid uint64, mid int64, status traceGoStatus, markAssist bool) traceWriter { - // The status should never be bad. Some invariant must have been violated. - if status == traceGoBad { - print("runtime: goid=", goid, "\n") - throw("attempted to trace a bad status for a goroutine") - } - - // Trace the status. - w = w.event(traceEvGoStatus, traceArg(goid), traceArg(uint64(mid)), traceArg(status)) - - // Trace any special ranges that are in-progress. - if markAssist { - w = w.event(traceEvGCMarkAssistActive, traceArg(goid)) - } - return w -} - -// writeProcStatusForP emits a ProcStatus event for the provided p based on its status. -// -// The caller must fully own pp and it must be prevented from transitioning (e.g. this can be -// called by a forEachP callback or from a STW). -func (w traceWriter) writeProcStatusForP(pp *p, inSTW bool) traceWriter { - if !pp.trace.acquireStatus(w.gen) { - return w - } - var status traceProcStatus - switch pp.status { - case _Pidle, _Pgcstop: - status = traceProcIdle - if pp.status == _Pgcstop && inSTW { - // N.B. a P that is running and currently has the world stopped will be - // in _Pgcstop, but we model it as running in the tracer. - status = traceProcRunning - } - case _Prunning: - status = traceProcRunning - // There's a short window wherein the goroutine may have entered _Gsyscall - // but it still owns the P (it's not in _Psyscall yet). The goroutine entering - // _Gsyscall is the tracer's signal that the P its bound to is also in a syscall, - // so we need to emit a status that matches. See #64318. - if w.mp.p.ptr() == pp && w.mp.curg != nil && readgstatus(w.mp.curg)&^_Gscan == _Gsyscall { - status = traceProcSyscall - } - case _Psyscall: - status = traceProcSyscall - default: - throw("attempt to trace invalid or unsupported P status") - } - w = w.writeProcStatus(uint64(pp.id), status, pp.trace.inSweep) - return w -} - -// writeProcStatus emits a ProcStatus event with all the provided information. -// -// The caller must have taken ownership of a P's status writing, and the P must be -// prevented from transitioning. -func (w traceWriter) writeProcStatus(pid uint64, status traceProcStatus, inSweep bool) traceWriter { - // The status should never be bad. Some invariant must have been violated. - if status == traceProcBad { - print("runtime: pid=", pid, "\n") - throw("attempted to trace a bad status for a proc") - } - - // Trace the status. - w = w.event(traceEvProcStatus, traceArg(pid), traceArg(status)) - - // Trace any special ranges that are in-progress. - if inSweep { - w = w.event(traceEvGCSweepActive, traceArg(pid)) - } - return w -} - -// goStatusToTraceGoStatus translates the internal status to tracGoStatus. -// -// status must not be _Gdead or any status whose name has the suffix "_unused." -func goStatusToTraceGoStatus(status uint32, wr waitReason) traceGoStatus { - // N.B. Ignore the _Gscan bit. We don't model it in the tracer. - var tgs traceGoStatus - switch status &^ _Gscan { - case _Grunnable: - tgs = traceGoRunnable - case _Grunning, _Gcopystack: - tgs = traceGoRunning - case _Gsyscall: - tgs = traceGoSyscall - case _Gwaiting, _Gpreempted: - // There are a number of cases where a G might end up in - // _Gwaiting but it's actually running in a non-preemptive - // state but needs to present itself as preempted to the - // garbage collector. In these cases, we're not going to - // emit an event, and we want these goroutines to appear in - // the final trace as if they're running, not blocked. - tgs = traceGoWaiting - if status == _Gwaiting && - wr == waitReasonStoppingTheWorld || - wr == waitReasonGCMarkTermination || - wr == waitReasonGarbageCollection || - wr == waitReasonTraceProcStatus || - wr == waitReasonPageTraceFlush || - wr == waitReasonGCWorkerActive { - tgs = traceGoRunning - } - case _Gdead: - throw("tried to trace dead goroutine") - default: - throw("tried to trace goroutine with invalid or unsupported status") - } - return tgs -} - -// traceSchedResourceState is shared state for scheduling resources (i.e. fields common to -// both Gs and Ps). -type traceSchedResourceState struct { - // statusTraced indicates whether a status event was traced for this resource - // a particular generation. - // - // There are 3 of these because when transitioning across generations, traceAdvance - // needs to be able to reliably observe whether a status was traced for the previous - // generation, while we need to clear the value for the next generation. - statusTraced [3]atomic.Uint32 - - // seq is the sequence counter for this scheduling resource's events. - // The purpose of the sequence counter is to establish a partial order between - // events that don't obviously happen serially (same M) in the stream ofevents. - // - // There are two of these so that we can reset the counter on each generation. - // This saves space in the resulting trace by keeping the counter small and allows - // GoStatus and GoCreate events to omit a sequence number (implicitly 0). - seq [2]uint64 -} - -// acquireStatus acquires the right to emit a Status event for the scheduling resource. -func (r *traceSchedResourceState) acquireStatus(gen uintptr) bool { - if !r.statusTraced[gen%3].CompareAndSwap(0, 1) { - return false - } - r.readyNextGen(gen) - return true -} - -// readyNextGen readies r for the generation following gen. -func (r *traceSchedResourceState) readyNextGen(gen uintptr) { - nextGen := traceNextGen(gen) - r.seq[nextGen%2] = 0 - r.statusTraced[nextGen%3].Store(0) -} - -// statusWasTraced returns true if the sched resource's status was already acquired for tracing. -func (r *traceSchedResourceState) statusWasTraced(gen uintptr) bool { - return r.statusTraced[gen%3].Load() != 0 -} - -// setStatusTraced indicates that the resource's status was already traced, for example -// when a goroutine is created. -func (r *traceSchedResourceState) setStatusTraced(gen uintptr) { - r.statusTraced[gen%3].Store(1) -} - -// nextSeq returns the next sequence number for the resource. -func (r *traceSchedResourceState) nextSeq(gen uintptr) traceArg { - r.seq[gen%2]++ - return traceArg(r.seq[gen%2]) -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2string.go b/contrib/go/_std_1.22/src/runtime/trace2string.go deleted file mode 100644 index cbb0ecfb3743..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2string.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Trace string management. - -package runtime - -// Trace strings. - -const maxTraceStringLen = 1024 - -// traceStringTable is map of string -> unique ID that also manages -// writing strings out into the trace. -type traceStringTable struct { - // lock protects buf. - lock mutex - buf *traceBuf // string batches to write out to the trace. - - // tab is a mapping of string -> unique ID. - tab traceMap -} - -// put adds a string to the table, emits it, and returns a unique ID for it. -func (t *traceStringTable) put(gen uintptr, s string) uint64 { - // Put the string in the table. - ss := stringStructOf(&s) - id, added := t.tab.put(ss.str, uintptr(ss.len)) - if added { - // Write the string to the buffer. - systemstack(func() { - t.writeString(gen, id, s) - }) - } - return id -} - -// emit emits a string and creates an ID for it, but doesn't add it to the table. Returns the ID. -func (t *traceStringTable) emit(gen uintptr, s string) uint64 { - // Grab an ID and write the string to the buffer. - id := t.tab.stealID() - systemstack(func() { - t.writeString(gen, id, s) - }) - return id -} - -// writeString writes the string to t.buf. -// -// Must run on the systemstack because it may flush buffers and thus could acquire trace.lock. -// -//go:systemstack -func (t *traceStringTable) writeString(gen uintptr, id uint64, s string) { - // Truncate the string if necessary. - if len(s) > maxTraceStringLen { - s = s[:maxTraceStringLen] - } - - lock(&t.lock) - w := unsafeTraceWriter(gen, t.buf) - - // Ensure we have a place to write to. - var flushed bool - w, flushed = w.ensure(2 + 2*traceBytesPerNumber + len(s) /* traceEvStrings + traceEvString + ID + len + string data */) - if flushed { - // Annotate the batch as containing strings. - w.byte(byte(traceEvStrings)) - } - - // Write out the string. - w.byte(byte(traceEvString)) - w.varint(id) - w.varint(uint64(len(s))) - w.stringData(s) - - // Store back buf if it was updated during ensure. - t.buf = w.traceBuf - unlock(&t.lock) -} - -// reset clears the string table and flushes any buffers it has. -// -// Must be called only once the caller is certain nothing else will be -// added to this table. -// -// Because it flushes buffers, this may acquire trace.lock and thus -// must run on the systemstack. -// -//go:systemstack -func (t *traceStringTable) reset(gen uintptr) { - if t.buf != nil { - lock(&trace.lock) - traceBufFlush(t.buf, gen) - unlock(&trace.lock) - t.buf = nil - } - - // Reset the table. - lock(&t.tab.lock) - t.tab.reset() - unlock(&t.tab.lock) -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2time.go b/contrib/go/_std_1.22/src/runtime/trace2time.go deleted file mode 100644 index 7a7a53e7d8d5..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2time.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Trace time and clock. - -package runtime - -import "internal/goarch" - -// Timestamps in trace are produced through either nanotime or cputicks -// and divided by traceTimeDiv. nanotime is used everywhere except on -// platforms where osHasLowResClock is true, because the system clock -// isn't granular enough to get useful information out of a trace in -// many cases. -// -// This makes absolute values of timestamp diffs smaller, and so they are -// encoded in fewer bytes. -// -// The target resolution in all cases is 64 nanoseconds. -// This is based on the fact that fundamentally the execution tracer won't emit -// events more frequently than roughly every 200 ns or so, because that's roughly -// how long it takes to call through the scheduler. -// We could be more aggressive and bump this up to 128 ns while still getting -// useful data, but the extra bit doesn't save us that much and the headroom is -// nice to have. -// -// Hitting this target resolution is easy in the nanotime case: just pick a -// division of 64. In the cputicks case it's a bit more complex. -// -// For x86, on a 3 GHz machine, we'd want to divide by 3*64 to hit our target. -// To keep the division operation efficient, we round that up to 4*64, or 256. -// Given what cputicks represents, we use this on all other platforms except -// for PowerPC. -// The suggested increment frequency for PowerPC's time base register is -// 512 MHz according to Power ISA v2.07 section 6.2, so we use 32 on ppc64 -// and ppc64le. -const traceTimeDiv = (1-osHasLowResClockInt)*64 + osHasLowResClockInt*(256-224*(goarch.IsPpc64|goarch.IsPpc64le)) - -// traceTime represents a timestamp for the trace. -type traceTime uint64 - -// traceClockNow returns a monotonic timestamp. The clock this function gets -// the timestamp from is specific to tracing, and shouldn't be mixed with other -// clock sources. -// -// nosplit because it's called from exitsyscall, which is nosplit. -// -//go:nosplit -func traceClockNow() traceTime { - if osHasLowResClock { - return traceTime(cputicks() / traceTimeDiv) - } - return traceTime(nanotime() / traceTimeDiv) -} - -// traceClockUnitsPerSecond estimates the number of trace clock units per -// second that elapse. -func traceClockUnitsPerSecond() uint64 { - if osHasLowResClock { - // We're using cputicks as our clock, so we need a real estimate. - return uint64(ticksPerSecond() / traceTimeDiv) - } - // Our clock is nanotime, so it's just the constant time division. - // (trace clock units / nanoseconds) * (1e9 nanoseconds / 1 second) - return uint64(1.0 / float64(traceTimeDiv) * 1e9) -} - -// traceFrequency writes a batch with a single EvFrequency event. -// -// freq is the number of trace clock units per second. -func traceFrequency(gen uintptr) { - w := unsafeTraceWriter(gen, nil) - - // Ensure we have a place to write to. - w, _ = w.ensure(1 + traceBytesPerNumber /* traceEvFrequency + frequency */) - - // Write out the string. - w.byte(byte(traceEvFrequency)) - w.varint(traceClockUnitsPerSecond()) - - // Immediately flush the buffer. - systemstack(func() { - lock(&trace.lock) - traceBufFlush(w.traceBuf, gen) - unlock(&trace.lock) - }) -} diff --git a/contrib/go/_std_1.22/src/runtime/type.go b/contrib/go/_std_1.22/src/runtime/type.go deleted file mode 100644 index 1150a53208c3..000000000000 --- a/contrib/go/_std_1.22/src/runtime/type.go +++ /dev/null @@ -1,469 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Runtime type representation. - -package runtime - -import ( - "internal/abi" - "unsafe" -) - -type nameOff = abi.NameOff -type typeOff = abi.TypeOff -type textOff = abi.TextOff - -type _type = abi.Type - -// rtype is a wrapper that allows us to define additional methods. -type rtype struct { - *abi.Type // embedding is okay here (unlike reflect) because none of this is public -} - -func (t rtype) string() string { - s := t.nameOff(t.Str).Name() - if t.TFlag&abi.TFlagExtraStar != 0 { - return s[1:] - } - return s -} - -func (t rtype) uncommon() *uncommontype { - return t.Uncommon() -} - -func (t rtype) name() string { - if t.TFlag&abi.TFlagNamed == 0 { - return "" - } - s := t.string() - i := len(s) - 1 - sqBrackets := 0 - for i >= 0 && (s[i] != '.' || sqBrackets != 0) { - switch s[i] { - case ']': - sqBrackets++ - case '[': - sqBrackets-- - } - i-- - } - return s[i+1:] -} - -// pkgpath returns the path of the package where t was defined, if -// available. This is not the same as the reflect package's PkgPath -// method, in that it returns the package path for struct and interface -// types, not just named types. -func (t rtype) pkgpath() string { - if u := t.uncommon(); u != nil { - return t.nameOff(u.PkgPath).Name() - } - switch t.Kind_ & kindMask { - case kindStruct: - st := (*structtype)(unsafe.Pointer(t.Type)) - return st.PkgPath.Name() - case kindInterface: - it := (*interfacetype)(unsafe.Pointer(t.Type)) - return it.PkgPath.Name() - } - return "" -} - -// reflectOffs holds type offsets defined at run time by the reflect package. -// -// When a type is defined at run time, its *rtype data lives on the heap. -// There are a wide range of possible addresses the heap may use, that -// may not be representable as a 32-bit offset. Moreover the GC may -// one day start moving heap memory, in which case there is no stable -// offset that can be defined. -// -// To provide stable offsets, we add pin *rtype objects in a global map -// and treat the offset as an identifier. We use negative offsets that -// do not overlap with any compile-time module offsets. -// -// Entries are created by reflect.addReflectOff. -var reflectOffs struct { - lock mutex - next int32 - m map[int32]unsafe.Pointer - minv map[unsafe.Pointer]int32 -} - -func reflectOffsLock() { - lock(&reflectOffs.lock) - if raceenabled { - raceacquire(unsafe.Pointer(&reflectOffs.lock)) - } -} - -func reflectOffsUnlock() { - if raceenabled { - racerelease(unsafe.Pointer(&reflectOffs.lock)) - } - unlock(&reflectOffs.lock) -} - -func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { - if off == 0 { - return name{} - } - base := uintptr(ptrInModule) - for md := &firstmoduledata; md != nil; md = md.next { - if base >= md.types && base < md.etypes { - res := md.types + uintptr(off) - if res > md.etypes { - println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) - throw("runtime: name offset out of range") - } - return name{Bytes: (*byte)(unsafe.Pointer(res))} - } - } - - // No module found. see if it is a run time name. - reflectOffsLock() - res, found := reflectOffs.m[int32(off)] - reflectOffsUnlock() - if !found { - println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:") - for next := &firstmoduledata; next != nil; next = next.next { - println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) - } - throw("runtime: name offset base pointer out of range") - } - return name{Bytes: (*byte)(res)} -} - -func (t rtype) nameOff(off nameOff) name { - return resolveNameOff(unsafe.Pointer(t.Type), off) -} - -func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type { - if off == 0 || off == -1 { - // -1 is the sentinel value for unreachable code. - // See cmd/link/internal/ld/data.go:relocsym. - return nil - } - base := uintptr(ptrInModule) - var md *moduledata - for next := &firstmoduledata; next != nil; next = next.next { - if base >= next.types && base < next.etypes { - md = next - break - } - } - if md == nil { - reflectOffsLock() - res := reflectOffs.m[int32(off)] - reflectOffsUnlock() - if res == nil { - println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:") - for next := &firstmoduledata; next != nil; next = next.next { - println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) - } - throw("runtime: type offset base pointer out of range") - } - return (*_type)(res) - } - if t := md.typemap[off]; t != nil { - return t - } - res := md.types + uintptr(off) - if res > md.etypes { - println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) - throw("runtime: type offset out of range") - } - return (*_type)(unsafe.Pointer(res)) -} - -func (t rtype) typeOff(off typeOff) *_type { - return resolveTypeOff(unsafe.Pointer(t.Type), off) -} - -func (t rtype) textOff(off textOff) unsafe.Pointer { - if off == -1 { - // -1 is the sentinel value for unreachable code. - // See cmd/link/internal/ld/data.go:relocsym. - return unsafe.Pointer(abi.FuncPCABIInternal(unreachableMethod)) - } - base := uintptr(unsafe.Pointer(t.Type)) - var md *moduledata - for next := &firstmoduledata; next != nil; next = next.next { - if base >= next.types && base < next.etypes { - md = next - break - } - } - if md == nil { - reflectOffsLock() - res := reflectOffs.m[int32(off)] - reflectOffsUnlock() - if res == nil { - println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:") - for next := &firstmoduledata; next != nil; next = next.next { - println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) - } - throw("runtime: text offset base pointer out of range") - } - return res - } - res := md.textAddr(uint32(off)) - return unsafe.Pointer(res) -} - -type uncommontype = abi.UncommonType - -type interfacetype = abi.InterfaceType - -type maptype = abi.MapType - -type arraytype = abi.ArrayType - -type chantype = abi.ChanType - -type slicetype = abi.SliceType - -type functype = abi.FuncType - -type ptrtype = abi.PtrType - -type name = abi.Name - -type structtype = abi.StructType - -func pkgPath(n name) string { - if n.Bytes == nil || *n.Data(0)&(1<<2) == 0 { - return "" - } - i, l := n.ReadVarint(1) - off := 1 + i + l - if *n.Data(0)&(1<<1) != 0 { - i2, l2 := n.ReadVarint(off) - off += i2 + l2 - } - var nameOff nameOff - copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.Data(off)))[:]) - pkgPathName := resolveNameOff(unsafe.Pointer(n.Bytes), nameOff) - return pkgPathName.Name() -} - -// typelinksinit scans the types from extra modules and builds the -// moduledata typemap used to de-duplicate type pointers. -func typelinksinit() { - if firstmoduledata.next == nil { - return - } - typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks)) - - modules := activeModules() - prev := modules[0] - for _, md := range modules[1:] { - // Collect types from the previous module into typehash. - collect: - for _, tl := range prev.typelinks { - var t *_type - if prev.typemap == nil { - t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl))) - } else { - t = prev.typemap[typeOff(tl)] - } - // Add to typehash if not seen before. - tlist := typehash[t.Hash] - for _, tcur := range tlist { - if tcur == t { - continue collect - } - } - typehash[t.Hash] = append(tlist, t) - } - - if md.typemap == nil { - // If any of this module's typelinks match a type from a - // prior module, prefer that prior type by adding the offset - // to this module's typemap. - tm := make(map[typeOff]*_type, len(md.typelinks)) - pinnedTypemaps = append(pinnedTypemaps, tm) - md.typemap = tm - for _, tl := range md.typelinks { - t := (*_type)(unsafe.Pointer(md.types + uintptr(tl))) - for _, candidate := range typehash[t.Hash] { - seen := map[_typePair]struct{}{} - if typesEqual(t, candidate, seen) { - t = candidate - break - } - } - md.typemap[typeOff(tl)] = t - } - } - - prev = md - } -} - -type _typePair struct { - t1 *_type - t2 *_type -} - -func toRType(t *abi.Type) rtype { - return rtype{t} -} - -// typesEqual reports whether two types are equal. -// -// Everywhere in the runtime and reflect packages, it is assumed that -// there is exactly one *_type per Go type, so that pointer equality -// can be used to test if types are equal. There is one place that -// breaks this assumption: buildmode=shared. In this case a type can -// appear as two different pieces of memory. This is hidden from the -// runtime and reflect package by the per-module typemap built in -// typelinksinit. It uses typesEqual to map types from later modules -// back into earlier ones. -// -// Only typelinksinit needs this function. -func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool { - tp := _typePair{t, v} - if _, ok := seen[tp]; ok { - return true - } - - // mark these types as seen, and thus equivalent which prevents an infinite loop if - // the two types are identical, but recursively defined and loaded from - // different modules - seen[tp] = struct{}{} - - if t == v { - return true - } - kind := t.Kind_ & kindMask - if kind != v.Kind_&kindMask { - return false - } - rt, rv := toRType(t), toRType(v) - if rt.string() != rv.string() { - return false - } - ut := t.Uncommon() - uv := v.Uncommon() - if ut != nil || uv != nil { - if ut == nil || uv == nil { - return false - } - pkgpatht := rt.nameOff(ut.PkgPath).Name() - pkgpathv := rv.nameOff(uv.PkgPath).Name() - if pkgpatht != pkgpathv { - return false - } - } - if kindBool <= kind && kind <= kindComplex128 { - return true - } - switch kind { - case kindString, kindUnsafePointer: - return true - case kindArray: - at := (*arraytype)(unsafe.Pointer(t)) - av := (*arraytype)(unsafe.Pointer(v)) - return typesEqual(at.Elem, av.Elem, seen) && at.Len == av.Len - case kindChan: - ct := (*chantype)(unsafe.Pointer(t)) - cv := (*chantype)(unsafe.Pointer(v)) - return ct.Dir == cv.Dir && typesEqual(ct.Elem, cv.Elem, seen) - case kindFunc: - ft := (*functype)(unsafe.Pointer(t)) - fv := (*functype)(unsafe.Pointer(v)) - if ft.OutCount != fv.OutCount || ft.InCount != fv.InCount { - return false - } - tin, vin := ft.InSlice(), fv.InSlice() - for i := 0; i < len(tin); i++ { - if !typesEqual(tin[i], vin[i], seen) { - return false - } - } - tout, vout := ft.OutSlice(), fv.OutSlice() - for i := 0; i < len(tout); i++ { - if !typesEqual(tout[i], vout[i], seen) { - return false - } - } - return true - case kindInterface: - it := (*interfacetype)(unsafe.Pointer(t)) - iv := (*interfacetype)(unsafe.Pointer(v)) - if it.PkgPath.Name() != iv.PkgPath.Name() { - return false - } - if len(it.Methods) != len(iv.Methods) { - return false - } - for i := range it.Methods { - tm := &it.Methods[i] - vm := &iv.Methods[i] - // Note the mhdr array can be relocated from - // another module. See #17724. - tname := resolveNameOff(unsafe.Pointer(tm), tm.Name) - vname := resolveNameOff(unsafe.Pointer(vm), vm.Name) - if tname.Name() != vname.Name() { - return false - } - if pkgPath(tname) != pkgPath(vname) { - return false - } - tityp := resolveTypeOff(unsafe.Pointer(tm), tm.Typ) - vityp := resolveTypeOff(unsafe.Pointer(vm), vm.Typ) - if !typesEqual(tityp, vityp, seen) { - return false - } - } - return true - case kindMap: - mt := (*maptype)(unsafe.Pointer(t)) - mv := (*maptype)(unsafe.Pointer(v)) - return typesEqual(mt.Key, mv.Key, seen) && typesEqual(mt.Elem, mv.Elem, seen) - case kindPtr: - pt := (*ptrtype)(unsafe.Pointer(t)) - pv := (*ptrtype)(unsafe.Pointer(v)) - return typesEqual(pt.Elem, pv.Elem, seen) - case kindSlice: - st := (*slicetype)(unsafe.Pointer(t)) - sv := (*slicetype)(unsafe.Pointer(v)) - return typesEqual(st.Elem, sv.Elem, seen) - case kindStruct: - st := (*structtype)(unsafe.Pointer(t)) - sv := (*structtype)(unsafe.Pointer(v)) - if len(st.Fields) != len(sv.Fields) { - return false - } - if st.PkgPath.Name() != sv.PkgPath.Name() { - return false - } - for i := range st.Fields { - tf := &st.Fields[i] - vf := &sv.Fields[i] - if tf.Name.Name() != vf.Name.Name() { - return false - } - if !typesEqual(tf.Typ, vf.Typ, seen) { - return false - } - if tf.Name.Tag() != vf.Name.Tag() { - return false - } - if tf.Offset != vf.Offset { - return false - } - if tf.Name.IsEmbedded() != vf.Name.IsEmbedded() { - return false - } - } - return true - default: - println("runtime: impossible type kind", kind) - throw("runtime: impossible type kind") - return false - } -} diff --git a/contrib/go/_std_1.22/src/runtime/typekind.go b/contrib/go/_std_1.22/src/runtime/typekind.go deleted file mode 100644 index bd2dec94c40d..000000000000 --- a/contrib/go/_std_1.22/src/runtime/typekind.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -const ( - kindBool = 1 + iota - kindInt - kindInt8 - kindInt16 - kindInt32 - kindInt64 - kindUint - kindUint8 - kindUint16 - kindUint32 - kindUint64 - kindUintptr - kindFloat32 - kindFloat64 - kindComplex64 - kindComplex128 - kindArray - kindChan - kindFunc - kindInterface - kindMap - kindPtr - kindSlice - kindString - kindStruct - kindUnsafePointer - - kindDirectIface = 1 << 5 - kindGCProg = 1 << 6 - kindMask = (1 << 5) - 1 -) - -// isDirectIface reports whether t is stored directly in an interface value. -func isDirectIface(t *_type) bool { - return t.Kind_&kindDirectIface != 0 -} diff --git a/contrib/go/_std_1.22/src/runtime/unsafe.go b/contrib/go/_std_1.22/src/runtime/unsafe.go deleted file mode 100644 index 6675264f5977..000000000000 --- a/contrib/go/_std_1.22/src/runtime/unsafe.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "runtime/internal/math" - "unsafe" -) - -func unsafestring(ptr unsafe.Pointer, len int) { - if len < 0 { - panicunsafestringlen() - } - - if uintptr(len) > -uintptr(ptr) { - if ptr == nil { - panicunsafestringnilptr() - } - panicunsafestringlen() - } -} - -// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeString -func unsafestring64(ptr unsafe.Pointer, len64 int64) { - len := int(len64) - if int64(len) != len64 { - panicunsafestringlen() - } - unsafestring(ptr, len) -} - -func unsafestringcheckptr(ptr unsafe.Pointer, len64 int64) { - unsafestring64(ptr, len64) - - // Check that underlying array doesn't straddle multiple heap objects. - // unsafestring64 has already checked for overflow. - if checkptrStraddles(ptr, uintptr(len64)) { - throw("checkptr: unsafe.String result straddles multiple allocations") - } -} - -func panicunsafestringlen() { - panic(errorString("unsafe.String: len out of range")) -} - -func panicunsafestringnilptr() { - panic(errorString("unsafe.String: ptr is nil and len is not zero")) -} - -// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice -func unsafeslice(et *_type, ptr unsafe.Pointer, len int) { - if len < 0 { - panicunsafeslicelen1(getcallerpc()) - } - - if et.Size_ == 0 { - if ptr == nil && len > 0 { - panicunsafeslicenilptr1(getcallerpc()) - } - } - - mem, overflow := math.MulUintptr(et.Size_, uintptr(len)) - if overflow || mem > -uintptr(ptr) { - if ptr == nil { - panicunsafeslicenilptr1(getcallerpc()) - } - panicunsafeslicelen1(getcallerpc()) - } -} - -// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice -func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) { - len := int(len64) - if int64(len) != len64 { - panicunsafeslicelen1(getcallerpc()) - } - unsafeslice(et, ptr, len) -} - -func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) { - unsafeslice64(et, ptr, len64) - - // Check that underlying array doesn't straddle multiple heap objects. - // unsafeslice64 has already checked for overflow. - if checkptrStraddles(ptr, uintptr(len64)*et.Size_) { - throw("checkptr: unsafe.Slice result straddles multiple allocations") - } -} - -func panicunsafeslicelen() { - // This is called only from compiler-generated code, so we can get the - // source of the panic. - panicunsafeslicelen1(getcallerpc()) -} - -//go:yeswritebarrierrec -func panicunsafeslicelen1(pc uintptr) { - panicCheck1(pc, "unsafe.Slice: len out of range") - panic(errorString("unsafe.Slice: len out of range")) -} - -func panicunsafeslicenilptr() { - // This is called only from compiler-generated code, so we can get the - // source of the panic. - panicunsafeslicenilptr1(getcallerpc()) -} - -//go:yeswritebarrierrec -func panicunsafeslicenilptr1(pc uintptr) { - panicCheck1(pc, "unsafe.Slice: ptr is nil and len is not zero") - panic(errorString("unsafe.Slice: ptr is nil and len is not zero")) -} diff --git a/contrib/go/_std_1.22/src/runtime/ya.make b/contrib/go/_std_1.22/src/runtime/ya.make deleted file mode 100644 index 4405653b1781..000000000000 --- a/contrib/go/_std_1.22/src/runtime/ya.make +++ /dev/null @@ -1,1587 +0,0 @@ -GO_LIBRARY() - -IF(SANITIZER_TYPE == "memory") - SRCS(msan.go msan_${GO_HOST_ARCH}.s) -ELSE() - SRCS(msan0.go) -ENDIF() - -IF(SANITIZER_TYPE == "address") - SRCS(asan.go asan_${GO_HOST_ARCH}.s) -ELSE() - SRCS(asan0.go) -ENDIF() - -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_arm64.s - atomic_arm64.s - atomic_pointer.go - cgo.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_arm64.go - cpuprof.go - create_file_unix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_darwin_arm64.go - duff_arm64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_unix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_sema.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_darwin.go - memclr_arm64.s - memmove_arm64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - nbpipe_pipe.go - netpoll.go - netpoll_kqueue.go - nonwindows_stub.go - os_darwin.go - os_darwin_arm64.go - os_nonopenbsd.go - os_unix.go - os_unix_nonlinux.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_arm64.s - preempt_nonwindows.go - print.go - proc.go - profbuf.go - proflabel.go - race.go - race_arm64.s - rand.go - rdebug.go - retry.go - rt0_darwin_arm64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_issetugid.go - security_unix.go - select.go - sema.go - signal_arm64.go - signal_darwin.go - signal_darwin_arm64.go - signal_unix.go - sigqueue.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs_arm64.go - stubs_nonlinux.go - symtab.go - symtabinl.go - sys_arm64.go - sys_darwin.go - sys_darwin_arm64.go - sys_darwin_arm64.s - sys_libc.go - sys_nonppc64x.go - tagptr.go - tagptr_64bit.go - test_stubs.go - time.go - time_nofake.go - timestub.go - tls_arm64.s - tls_stub.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_in_none.go - write_err.go - ) -ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_arm64.s - atomic_arm64.s - atomic_pointer.go - cgo.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_arm64.go - cpuprof.go - create_file_unix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_darwin_arm64.go - duff_arm64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_unix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_sema.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_darwin.go - memclr_arm64.s - memmove_arm64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - nbpipe_pipe.go - netpoll.go - netpoll_kqueue.go - nonwindows_stub.go - os_darwin.go - os_darwin_arm64.go - os_nonopenbsd.go - os_unix.go - os_unix_nonlinux.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_arm64.s - preempt_nonwindows.go - print.go - proc.go - profbuf.go - proflabel.go - race0.go - rand.go - rdebug.go - retry.go - rt0_darwin_arm64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_issetugid.go - security_unix.go - select.go - sema.go - signal_arm64.go - signal_darwin.go - signal_darwin_arm64.go - signal_unix.go - sigqueue.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs_arm64.go - stubs_nonlinux.go - symtab.go - symtabinl.go - sys_arm64.go - sys_darwin.go - sys_darwin_arm64.go - sys_darwin_arm64.s - sys_libc.go - sys_nonppc64x.go - tagptr.go - tagptr_64bit.go - test_stubs.go - time.go - time_nofake.go - timestub.go - tls_arm64.s - tls_stub.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_in_none.go - write_err.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_amd64.s - atomic_pointer.go - cgo.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_amd64.go - cpuprof.go - cputicks.go - create_file_unix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_darwin_amd64.go - duff_amd64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_unix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_sema.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_darwin.go - memclr_amd64.s - memmove_amd64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - nbpipe_pipe.go - netpoll.go - netpoll_kqueue.go - nonwindows_stub.go - os_darwin.go - os_nonopenbsd.go - os_unix.go - os_unix_nonlinux.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_amd64.s - preempt_nonwindows.go - print.go - proc.go - profbuf.go - proflabel.go - race.go - race_amd64.s - rand.go - rdebug.go - retry.go - rt0_darwin_amd64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_issetugid.go - security_unix.go - select.go - sema.go - signal_amd64.go - signal_darwin.go - signal_darwin_amd64.go - signal_unix.go - sigqueue.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs_amd64.go - stubs_nonlinux.go - symtab.go - symtabinl.go - sys_darwin.go - sys_darwin_amd64.s - sys_libc.go - sys_nonppc64x.go - sys_x86.go - tagptr.go - tagptr_64bit.go - test_amd64.go - test_amd64.s - time.go - time_nofake.go - timestub.go - tls_stub.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_in_none.go - write_err.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_amd64.s - atomic_pointer.go - cgo.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_amd64.go - cpuprof.go - cputicks.go - create_file_unix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_darwin_amd64.go - duff_amd64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_unix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_sema.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_darwin.go - memclr_amd64.s - memmove_amd64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - nbpipe_pipe.go - netpoll.go - netpoll_kqueue.go - nonwindows_stub.go - os_darwin.go - os_nonopenbsd.go - os_unix.go - os_unix_nonlinux.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_amd64.s - preempt_nonwindows.go - print.go - proc.go - profbuf.go - proflabel.go - race0.go - rand.go - rdebug.go - retry.go - rt0_darwin_amd64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_issetugid.go - security_unix.go - select.go - sema.go - signal_amd64.go - signal_darwin.go - signal_darwin_amd64.go - signal_unix.go - sigqueue.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs_amd64.go - stubs_nonlinux.go - symtab.go - symtabinl.go - sys_darwin.go - sys_darwin_amd64.s - sys_libc.go - sys_nonppc64x.go - sys_x86.go - tagptr.go - tagptr_64bit.go - test_amd64.go - test_amd64.s - time.go - time_nofake.go - timestub.go - tls_stub.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_in_none.go - write_err.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_arm64.s - atomic_arm64.s - atomic_pointer.go - cgo.go - cgo_mmap.go - cgo_sigaction.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_arm64.go - cpuprof.go - create_file_unix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_linux_arm64.go - duff_arm64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_unix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_futex.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_linux.go - memclr_arm64.s - memmove_arm64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - nbpipe_pipe2.go - netpoll.go - netpoll_epoll.go - nonwindows_stub.go - os_linux.go - os_linux_arm64.go - os_linux_generic.go - os_nonopenbsd.go - os_unix.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_arm64.s - preempt_nonwindows.go - print.go - proc.go - profbuf.go - proflabel.go - race.go - race_arm64.s - rand.go - rdebug.go - retry.go - rt0_linux_arm64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_linux.go - security_unix.go - select.go - sema.go - signal_arm64.go - signal_linux_arm64.go - signal_unix.go - sigqueue.go - sigqueue_note.go - sigtab_linux_generic.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs2.go - stubs3.go - stubs_arm64.go - stubs_linux.go - symtab.go - symtabinl.go - sys_arm64.go - sys_linux_arm64.s - sys_nonppc64x.go - tagptr.go - tagptr_64bit.go - test_stubs.go - time.go - time_nofake.go - timestub.go - timestub2.go - tls_arm64.s - tls_stub.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_elf64.go - vdso_linux.go - vdso_linux_arm64.go - write_err.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_arm64.s - atomic_arm64.s - atomic_pointer.go - cgo.go - cgo_mmap.go - cgo_sigaction.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_arm64.go - cpuprof.go - create_file_unix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_linux_arm64.go - duff_arm64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_unix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_futex.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_linux.go - memclr_arm64.s - memmove_arm64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - nbpipe_pipe2.go - netpoll.go - netpoll_epoll.go - nonwindows_stub.go - os_linux.go - os_linux_arm64.go - os_linux_generic.go - os_nonopenbsd.go - os_unix.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_arm64.s - preempt_nonwindows.go - print.go - proc.go - profbuf.go - proflabel.go - race0.go - rand.go - rdebug.go - retry.go - rt0_linux_arm64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_linux.go - security_unix.go - select.go - sema.go - signal_arm64.go - signal_linux_arm64.go - signal_unix.go - sigqueue.go - sigqueue_note.go - sigtab_linux_generic.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs2.go - stubs3.go - stubs_arm64.go - stubs_linux.go - symtab.go - symtabinl.go - sys_arm64.go - sys_linux_arm64.s - sys_nonppc64x.go - tagptr.go - tagptr_64bit.go - test_stubs.go - time.go - time_nofake.go - timestub.go - timestub2.go - tls_arm64.s - tls_stub.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_elf64.go - vdso_linux.go - vdso_linux_arm64.go - write_err.go - ) -ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_amd64.s - atomic_pointer.go - cgo.go - cgo_mmap.go - cgo_sigaction.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_amd64.go - cpuprof.go - cputicks.go - create_file_unix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_linux_amd64.go - duff_amd64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_unix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_futex.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_linux.go - memclr_amd64.s - memmove_amd64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - nbpipe_pipe2.go - netpoll.go - netpoll_epoll.go - nonwindows_stub.go - os_linux.go - os_linux_generic.go - os_linux_noauxv.go - os_linux_x86.go - os_nonopenbsd.go - os_unix.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_amd64.s - preempt_nonwindows.go - print.go - proc.go - profbuf.go - proflabel.go - race.go - race_amd64.s - rand.go - rdebug.go - retry.go - rt0_linux_amd64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_linux.go - security_unix.go - select.go - sema.go - signal_amd64.go - signal_linux_amd64.go - signal_unix.go - sigqueue.go - sigqueue_note.go - sigtab_linux_generic.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs2.go - stubs3.go - stubs_amd64.go - stubs_linux.go - symtab.go - symtabinl.go - sys_linux_amd64.s - sys_nonppc64x.go - sys_x86.go - tagptr.go - tagptr_64bit.go - test_amd64.go - test_amd64.s - time.go - time_linux_amd64.s - time_nofake.go - timeasm.go - tls_stub.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_elf64.go - vdso_linux.go - vdso_linux_amd64.go - write_err.go - ) -ELSEIF (OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_amd64.s - atomic_pointer.go - cgo.go - cgo_mmap.go - cgo_sigaction.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_amd64.go - cpuprof.go - cputicks.go - create_file_unix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_linux_amd64.go - duff_amd64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_unix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_futex.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_linux.go - memclr_amd64.s - memmove_amd64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - nbpipe_pipe2.go - netpoll.go - netpoll_epoll.go - nonwindows_stub.go - os_linux.go - os_linux_generic.go - os_linux_noauxv.go - os_linux_x86.go - os_nonopenbsd.go - os_unix.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_amd64.s - preempt_nonwindows.go - print.go - proc.go - profbuf.go - proflabel.go - race0.go - rand.go - rdebug.go - retry.go - rt0_linux_amd64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_linux.go - security_unix.go - select.go - sema.go - signal_amd64.go - signal_linux_amd64.go - signal_unix.go - sigqueue.go - sigqueue_note.go - sigtab_linux_generic.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs2.go - stubs3.go - stubs_amd64.go - stubs_linux.go - symtab.go - symtabinl.go - sys_linux_amd64.s - sys_nonppc64x.go - sys_x86.go - tagptr.go - tagptr_64bit.go - test_amd64.go - test_amd64.s - time.go - time_linux_amd64.s - time_nofake.go - timeasm.go - tls_stub.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_elf64.go - vdso_linux.go - vdso_linux_amd64.go - write_err.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_amd64.s - atomic_pointer.go - auxv_none.go - cgo.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_amd64.go - cpuprof.go - cputicks.go - create_file_nounix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_windows.go - defs_windows_amd64.go - duff_amd64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_nonunix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_sema.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_windows.go - memclr_amd64.s - memmove_amd64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - netpoll.go - netpoll_windows.go - os_nonopenbsd.go - os_windows.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_amd64.s - print.go - proc.go - profbuf.go - proflabel.go - race.go - race_amd64.s - rand.go - rdebug.go - rt0_windows_amd64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_nonunix.go - select.go - sema.go - signal_windows.go - sigqueue.go - sigqueue_note.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs3.go - stubs_amd64.go - stubs_nonlinux.go - symtab.go - symtabinl.go - sys_nonppc64x.go - sys_windows_amd64.s - sys_x86.go - syscall_windows.go - tagptr.go - tagptr_64bit.go - test_amd64.go - test_amd64.s - time.go - time_nofake.go - time_windows_amd64.s - timeasm.go - tls_windows_amd64.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_in_none.go - write_err.go - zcallback_windows.go - zcallback_windows.s - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - alg.go - arena.go - asm.s - asm_amd64.s - atomic_pointer.go - auxv_none.go - cgo.go - cgocall.go - cgocallback.go - cgocheck.go - chan.go - checkptr.go - compiler.go - complex.go - coro.go - covercounter.go - covermeta.go - cpuflags.go - cpuflags_amd64.go - cpuprof.go - cputicks.go - create_file_nounix.go - debug.go - debugcall.go - debuglog.go - debuglog_off.go - defs_windows.go - defs_windows_amd64.go - duff_amd64.s - env_posix.go - error.go - exithook.go - extern.go - fastlog2.go - fastlog2table.go - fds_nonunix.go - float.go - hash64.go - heapdump.go - histogram.go - iface.go - lfstack.go - lock_sema.go - lockrank.go - lockrank_off.go - malloc.go - map.go - map_fast32.go - map_fast64.go - map_faststr.go - mbarrier.go - mbitmap.go - mbitmap_noallocheaders.go - mcache.go - mcentral.go - mcheckmark.go - mem.go - mem_windows.go - memclr_amd64.s - memmove_amd64.s - metrics.go - mfinal.go - mfixalloc.go - mgc.go - mgclimit.go - mgcmark.go - mgcpacer.go - mgcscavenge.go - mgcstack.go - mgcsweep.go - mgcwork.go - mheap.go - minmax.go - mpagealloc.go - mpagealloc_64bit.go - mpagecache.go - mpallocbits.go - mprof.go - mranges.go - msize_noallocheaders.go - mspanset.go - mstats.go - mwbbuf.go - netpoll.go - netpoll_windows.go - os_nonopenbsd.go - os_windows.go - pagetrace_off.go - panic.go - pinner.go - plugin.go - preempt.go - preempt_amd64.s - print.go - proc.go - profbuf.go - proflabel.go - race0.go - rand.go - rdebug.go - rt0_windows_amd64.s - runtime.go - runtime1.go - runtime2.go - runtime_boring.go - rwmutex.go - security_nonunix.go - select.go - sema.go - signal_windows.go - sigqueue.go - sigqueue_note.go - sizeclasses.go - slice.go - softfloat64.go - stack.go - stkframe.go - string.go - stubs.go - stubs3.go - stubs_amd64.go - stubs_nonlinux.go - symtab.go - symtabinl.go - sys_nonppc64x.go - sys_windows_amd64.s - sys_x86.go - syscall_windows.go - tagptr.go - tagptr_64bit.go - test_amd64.go - test_amd64.s - time.go - time_nofake.go - time_windows_amd64.s - timeasm.go - tls_windows_amd64.go - trace.go - traceback.go - type.go - typekind.go - unsafe.go - utf8.go - vdso_in_none.go - write_err.go - zcallback_windows.go - zcallback_windows.s - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/slices/sort.go b/contrib/go/_std_1.22/src/slices/sort.go deleted file mode 100644 index d5e998ce1e2c..000000000000 --- a/contrib/go/_std_1.22/src/slices/sort.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -generic - -package slices - -import ( - "cmp" - "math/bits" -) - -// Sort sorts a slice of any ordered type in ascending order. -// When sorting floating-point numbers, NaNs are ordered before other values. -func Sort[S ~[]E, E cmp.Ordered](x S) { - n := len(x) - pdqsortOrdered(x, 0, n, bits.Len(uint(n))) -} - -// SortFunc sorts the slice x in ascending order as determined by the cmp -// function. This sort is not guaranteed to be stable. -// cmp(a, b) should return a negative number when a < b, a positive number when -// a > b and zero when a == b. -// -// SortFunc requires that cmp is a strict weak ordering. -// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. -func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { - n := len(x) - pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp) -} - -// SortStableFunc sorts the slice x while keeping the original order of equal -// elements, using cmp to compare elements in the same way as [SortFunc]. -func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { - stableCmpFunc(x, len(x), cmp) -} - -// IsSorted reports whether x is sorted in ascending order. -func IsSorted[S ~[]E, E cmp.Ordered](x S) bool { - for i := len(x) - 1; i > 0; i-- { - if cmp.Less(x[i], x[i-1]) { - return false - } - } - return true -} - -// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the -// comparison function as defined by [SortFunc]. -func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool { - for i := len(x) - 1; i > 0; i-- { - if cmp(x[i], x[i-1]) < 0 { - return false - } - } - return true -} - -// Min returns the minimal value in x. It panics if x is empty. -// For floating-point numbers, Min propagates NaNs (any NaN value in x -// forces the output to be NaN). -func Min[S ~[]E, E cmp.Ordered](x S) E { - if len(x) < 1 { - panic("slices.Min: empty list") - } - m := x[0] - for i := 1; i < len(x); i++ { - m = min(m, x[i]) - } - return m -} - -// MinFunc returns the minimal value in x, using cmp to compare elements. -// It panics if x is empty. If there is more than one minimal element -// according to the cmp function, MinFunc returns the first one. -func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E { - if len(x) < 1 { - panic("slices.MinFunc: empty list") - } - m := x[0] - for i := 1; i < len(x); i++ { - if cmp(x[i], m) < 0 { - m = x[i] - } - } - return m -} - -// Max returns the maximal value in x. It panics if x is empty. -// For floating-point E, Max propagates NaNs (any NaN value in x -// forces the output to be NaN). -func Max[S ~[]E, E cmp.Ordered](x S) E { - if len(x) < 1 { - panic("slices.Max: empty list") - } - m := x[0] - for i := 1; i < len(x); i++ { - m = max(m, x[i]) - } - return m -} - -// MaxFunc returns the maximal value in x, using cmp to compare elements. -// It panics if x is empty. If there is more than one maximal element -// according to the cmp function, MaxFunc returns the first one. -func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E { - if len(x) < 1 { - panic("slices.MaxFunc: empty list") - } - m := x[0] - for i := 1; i < len(x); i++ { - if cmp(x[i], m) > 0 { - m = x[i] - } - } - return m -} - -// BinarySearch searches for target in a sorted slice and returns the position -// where target is found, or the position where target would appear in the -// sort order; it also returns a bool saying whether the target is really found -// in the slice. The slice must be sorted in increasing order. -func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) { - // Inlining is faster than calling BinarySearchFunc with a lambda. - n := len(x) - // Define x[-1] < target and x[n] >= target. - // Invariant: x[i-1] < target, x[j] >= target. - i, j := 0, n - for i < j { - h := int(uint(i+j) >> 1) // avoid overflow when computing h - // i ≤ h < j - if cmp.Less(x[h], target) { - i = h + 1 // preserves x[i-1] < target - } else { - j = h // preserves x[j] >= target - } - } - // i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i. - return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target))) -} - -// BinarySearchFunc works like [BinarySearch], but uses a custom comparison -// function. The slice must be sorted in increasing order, where "increasing" -// is defined by cmp. cmp should return 0 if the slice element matches -// the target, a negative number if the slice element precedes the target, -// or a positive number if the slice element follows the target. -// cmp must implement the same ordering as the slice, such that if -// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice. -func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) { - n := len(x) - // Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 . - // Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0. - i, j := 0, n - for i < j { - h := int(uint(i+j) >> 1) // avoid overflow when computing h - // i ≤ h < j - if cmp(x[h], target) < 0 { - i = h + 1 // preserves cmp(x[i - 1], target) < 0 - } else { - j = h // preserves cmp(x[j], target) >= 0 - } - } - // i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i. - return i, i < n && cmp(x[i], target) == 0 -} - -type sortedHint int // hint for pdqsort when choosing the pivot - -const ( - unknownHint sortedHint = iota - increasingHint - decreasingHint -) - -// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf -type xorshift uint64 - -func (r *xorshift) Next() uint64 { - *r ^= *r << 13 - *r ^= *r >> 17 - *r ^= *r << 5 - return uint64(*r) -} - -func nextPowerOfTwo(length int) uint { - return 1 << bits.Len(uint(length)) -} - -// isNaN reports whether x is a NaN without requiring the math package. -// This will always return false if T is not floating-point. -func isNaN[T cmp.Ordered](x T) bool { - return x != x -} diff --git a/contrib/go/_std_1.22/src/slices/ya.make b/contrib/go/_std_1.22/src/slices/ya.make deleted file mode 100644 index 4d251376d86f..000000000000 --- a/contrib/go/_std_1.22/src/slices/ya.make +++ /dev/null @@ -1,10 +0,0 @@ -GO_LIBRARY() -IF (TRUE) - SRCS( - slices.go - sort.go - zsortanyfunc.go - zsortordered.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/strconv/doc.go b/contrib/go/_std_1.22/src/strconv/doc.go deleted file mode 100644 index fa20f902d0a2..000000000000 --- a/contrib/go/_std_1.22/src/strconv/doc.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package strconv implements conversions to and from string representations -// of basic data types. -// -// # Numeric Conversions -// -// The most common numeric conversions are Atoi (string to int) and Itoa (int to string). -// -// i, err := strconv.Atoi("-42") -// s := strconv.Itoa(-42) -// -// These assume decimal and the Go int type. -// -// [ParseBool], [ParseFloat], [ParseInt], and [ParseUint] convert strings to values: -// -// b, err := strconv.ParseBool("true") -// f, err := strconv.ParseFloat("3.1415", 64) -// i, err := strconv.ParseInt("-42", 10, 64) -// u, err := strconv.ParseUint("42", 10, 64) -// -// The parse functions return the widest type (float64, int64, and uint64), -// but if the size argument specifies a narrower width the result can be -// converted to that narrower type without data loss: -// -// s := "2147483647" // biggest int32 -// i64, err := strconv.ParseInt(s, 10, 32) -// ... -// i := int32(i64) -// -// [FormatBool], [FormatFloat], [FormatInt], and [FormatUint] convert values to strings: -// -// s := strconv.FormatBool(true) -// s := strconv.FormatFloat(3.1415, 'E', -1, 64) -// s := strconv.FormatInt(-42, 16) -// s := strconv.FormatUint(42, 16) -// -// [AppendBool], [AppendFloat], [AppendInt], and [AppendUint] are similar but -// append the formatted value to a destination slice. -// -// # String Conversions -// -// [Quote] and [QuoteToASCII] convert strings to quoted Go string literals. -// The latter guarantees that the result is an ASCII string, by escaping -// any non-ASCII Unicode with \u: -// -// q := strconv.Quote("Hello, 世界") -// q := strconv.QuoteToASCII("Hello, 世界") -// -// [QuoteRune] and [QuoteRuneToASCII] are similar but accept runes and -// return quoted Go rune literals. -// -// [Unquote] and [UnquoteChar] unquote Go string and rune literals. -package strconv diff --git a/contrib/go/_std_1.22/src/strings/clone.go b/contrib/go/_std_1.22/src/strings/clone.go deleted file mode 100644 index d14df11d4979..000000000000 --- a/contrib/go/_std_1.22/src/strings/clone.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package strings - -import ( - "unsafe" -) - -// Clone returns a fresh copy of s. -// It guarantees to make a copy of s into a new allocation, -// which can be important when retaining only a small substring -// of a much larger string. Using Clone can help such programs -// use less memory. Of course, since using Clone makes a copy, -// overuse of Clone can make programs use more memory. -// Clone should typically be used only rarely, and only when -// profiling indicates that it is needed. -// For strings of length zero the string "" will be returned -// and no allocation is made. -func Clone(s string) string { - if len(s) == 0 { - return "" - } - b := make([]byte, len(s)) - copy(b, s) - return unsafe.String(&b[0], len(b)) -} diff --git a/contrib/go/_std_1.22/src/strings/compare.go b/contrib/go/_std_1.22/src/strings/compare.go deleted file mode 100644 index 2bd4a243db2f..000000000000 --- a/contrib/go/_std_1.22/src/strings/compare.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package strings - -// Compare returns an integer comparing two strings lexicographically. -// The result will be 0 if a == b, -1 if a < b, and +1 if a > b. -// -// Compare is included only for symmetry with package bytes. -// It is usually clearer and always faster to use the built-in -// string comparison operators ==, <, >, and so on. -func Compare(a, b string) int { - // NOTE(rsc): This function does NOT call the runtime cmpstring function, - // because we do not want to provide any performance justification for - // using strings.Compare. Basically no one should use strings.Compare. - // As the comment above says, it is here only for symmetry with package bytes. - // If performance is important, the compiler should be changed to recognize - // the pattern so that all code doing three-way comparisons, not just code - // using strings.Compare, can benefit. - if a == b { - return 0 - } - if a < b { - return -1 - } - return +1 -} diff --git a/contrib/go/_std_1.22/src/strings/strings.go b/contrib/go/_std_1.22/src/strings/strings.go deleted file mode 100644 index f3f0723721f6..000000000000 --- a/contrib/go/_std_1.22/src/strings/strings.go +++ /dev/null @@ -1,1300 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package strings implements simple functions to manipulate UTF-8 encoded strings. -// -// For information about UTF-8 strings in Go, see https://blog.golang.org/strings. -package strings - -import ( - "internal/bytealg" - "unicode" - "unicode/utf8" -) - -const maxInt = int(^uint(0) >> 1) - -// explode splits s into a slice of UTF-8 strings, -// one string per Unicode character up to a maximum of n (n < 0 means no limit). -// Invalid UTF-8 bytes are sliced individually. -func explode(s string, n int) []string { - l := utf8.RuneCountInString(s) - if n < 0 || n > l { - n = l - } - a := make([]string, n) - for i := 0; i < n-1; i++ { - _, size := utf8.DecodeRuneInString(s) - a[i] = s[:size] - s = s[size:] - } - if n > 0 { - a[n-1] = s - } - return a -} - -// Count counts the number of non-overlapping instances of substr in s. -// If substr is an empty string, Count returns 1 + the number of Unicode code points in s. -func Count(s, substr string) int { - // special case - if len(substr) == 0 { - return utf8.RuneCountInString(s) + 1 - } - if len(substr) == 1 { - return bytealg.CountString(s, substr[0]) - } - n := 0 - for { - i := Index(s, substr) - if i == -1 { - return n - } - n++ - s = s[i+len(substr):] - } -} - -// Contains reports whether substr is within s. -func Contains(s, substr string) bool { - return Index(s, substr) >= 0 -} - -// ContainsAny reports whether any Unicode code points in chars are within s. -func ContainsAny(s, chars string) bool { - return IndexAny(s, chars) >= 0 -} - -// ContainsRune reports whether the Unicode code point r is within s. -func ContainsRune(s string, r rune) bool { - return IndexRune(s, r) >= 0 -} - -// ContainsFunc reports whether any Unicode code points r within s satisfy f(r). -func ContainsFunc(s string, f func(rune) bool) bool { - return IndexFunc(s, f) >= 0 -} - -// LastIndex returns the index of the last instance of substr in s, or -1 if substr is not present in s. -func LastIndex(s, substr string) int { - n := len(substr) - switch { - case n == 0: - return len(s) - case n == 1: - return bytealg.LastIndexByteString(s, substr[0]) - case n == len(s): - if substr == s { - return 0 - } - return -1 - case n > len(s): - return -1 - } - // Rabin-Karp search from the end of the string - hashss, pow := bytealg.HashStrRev(substr) - last := len(s) - n - var h uint32 - for i := len(s) - 1; i >= last; i-- { - h = h*bytealg.PrimeRK + uint32(s[i]) - } - if h == hashss && s[last:] == substr { - return last - } - for i := last - 1; i >= 0; i-- { - h *= bytealg.PrimeRK - h += uint32(s[i]) - h -= pow * uint32(s[i+n]) - if h == hashss && s[i:i+n] == substr { - return i - } - } - return -1 -} - -// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s. -func IndexByte(s string, c byte) int { - return bytealg.IndexByteString(s, c) -} - -// IndexRune returns the index of the first instance of the Unicode code point -// r, or -1 if rune is not present in s. -// If r is utf8.RuneError, it returns the first instance of any -// invalid UTF-8 byte sequence. -func IndexRune(s string, r rune) int { - switch { - case 0 <= r && r < utf8.RuneSelf: - return IndexByte(s, byte(r)) - case r == utf8.RuneError: - for i, r := range s { - if r == utf8.RuneError { - return i - } - } - return -1 - case !utf8.ValidRune(r): - return -1 - default: - return Index(s, string(r)) - } -} - -// IndexAny returns the index of the first instance of any Unicode code point -// from chars in s, or -1 if no Unicode code point from chars is present in s. -func IndexAny(s, chars string) int { - if chars == "" { - // Avoid scanning all of s. - return -1 - } - if len(chars) == 1 { - // Avoid scanning all of s. - r := rune(chars[0]) - if r >= utf8.RuneSelf { - r = utf8.RuneError - } - return IndexRune(s, r) - } - if len(s) > 8 { - if as, isASCII := makeASCIISet(chars); isASCII { - for i := 0; i < len(s); i++ { - if as.contains(s[i]) { - return i - } - } - return -1 - } - } - for i, c := range s { - if IndexRune(chars, c) >= 0 { - return i - } - } - return -1 -} - -// LastIndexAny returns the index of the last instance of any Unicode code -// point from chars in s, or -1 if no Unicode code point from chars is -// present in s. -func LastIndexAny(s, chars string) int { - if chars == "" { - // Avoid scanning all of s. - return -1 - } - if len(s) == 1 { - rc := rune(s[0]) - if rc >= utf8.RuneSelf { - rc = utf8.RuneError - } - if IndexRune(chars, rc) >= 0 { - return 0 - } - return -1 - } - if len(s) > 8 { - if as, isASCII := makeASCIISet(chars); isASCII { - for i := len(s) - 1; i >= 0; i-- { - if as.contains(s[i]) { - return i - } - } - return -1 - } - } - if len(chars) == 1 { - rc := rune(chars[0]) - if rc >= utf8.RuneSelf { - rc = utf8.RuneError - } - for i := len(s); i > 0; { - r, size := utf8.DecodeLastRuneInString(s[:i]) - i -= size - if rc == r { - return i - } - } - return -1 - } - for i := len(s); i > 0; { - r, size := utf8.DecodeLastRuneInString(s[:i]) - i -= size - if IndexRune(chars, r) >= 0 { - return i - } - } - return -1 -} - -// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s. -func LastIndexByte(s string, c byte) int { - return bytealg.LastIndexByteString(s, c) -} - -// Generic split: splits after each instance of sep, -// including sepSave bytes of sep in the subarrays. -func genSplit(s, sep string, sepSave, n int) []string { - if n == 0 { - return nil - } - if sep == "" { - return explode(s, n) - } - if n < 0 { - n = Count(s, sep) + 1 - } - - if n > len(s)+1 { - n = len(s) + 1 - } - a := make([]string, n) - n-- - i := 0 - for i < n { - m := Index(s, sep) - if m < 0 { - break - } - a[i] = s[:m+sepSave] - s = s[m+len(sep):] - i++ - } - a[i] = s - return a[:i+1] -} - -// SplitN slices s into substrings separated by sep and returns a slice of -// the substrings between those separators. -// -// The count determines the number of substrings to return: -// -// n > 0: at most n substrings; the last substring will be the unsplit remainder. -// n == 0: the result is nil (zero substrings) -// n < 0: all substrings -// -// Edge cases for s and sep (for example, empty strings) are handled -// as described in the documentation for [Split]. -// -// To split around the first instance of a separator, see Cut. -func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) } - -// SplitAfterN slices s into substrings after each instance of sep and -// returns a slice of those substrings. -// -// The count determines the number of substrings to return: -// -// n > 0: at most n substrings; the last substring will be the unsplit remainder. -// n == 0: the result is nil (zero substrings) -// n < 0: all substrings -// -// Edge cases for s and sep (for example, empty strings) are handled -// as described in the documentation for SplitAfter. -func SplitAfterN(s, sep string, n int) []string { - return genSplit(s, sep, len(sep), n) -} - -// Split slices s into all substrings separated by sep and returns a slice of -// the substrings between those separators. -// -// If s does not contain sep and sep is not empty, Split returns a -// slice of length 1 whose only element is s. -// -// If sep is empty, Split splits after each UTF-8 sequence. If both s -// and sep are empty, Split returns an empty slice. -// -// It is equivalent to [SplitN] with a count of -1. -// -// To split around the first instance of a separator, see Cut. -func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) } - -// SplitAfter slices s into all substrings after each instance of sep and -// returns a slice of those substrings. -// -// If s does not contain sep and sep is not empty, SplitAfter returns -// a slice of length 1 whose only element is s. -// -// If sep is empty, SplitAfter splits after each UTF-8 sequence. If -// both s and sep are empty, SplitAfter returns an empty slice. -// -// It is equivalent to [SplitAfterN] with a count of -1. -func SplitAfter(s, sep string) []string { - return genSplit(s, sep, len(sep), -1) -} - -var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1} - -// Fields splits the string s around each instance of one or more consecutive white space -// characters, as defined by unicode.IsSpace, returning a slice of substrings of s or an -// empty slice if s contains only white space. -func Fields(s string) []string { - // First count the fields. - // This is an exact count if s is ASCII, otherwise it is an approximation. - n := 0 - wasSpace := 1 - // setBits is used to track which bits are set in the bytes of s. - setBits := uint8(0) - for i := 0; i < len(s); i++ { - r := s[i] - setBits |= r - isSpace := int(asciiSpace[r]) - n += wasSpace & ^isSpace - wasSpace = isSpace - } - - if setBits >= utf8.RuneSelf { - // Some runes in the input string are not ASCII. - return FieldsFunc(s, unicode.IsSpace) - } - // ASCII fast path - a := make([]string, n) - na := 0 - fieldStart := 0 - i := 0 - // Skip spaces in the front of the input. - for i < len(s) && asciiSpace[s[i]] != 0 { - i++ - } - fieldStart = i - for i < len(s) { - if asciiSpace[s[i]] == 0 { - i++ - continue - } - a[na] = s[fieldStart:i] - na++ - i++ - // Skip spaces in between fields. - for i < len(s) && asciiSpace[s[i]] != 0 { - i++ - } - fieldStart = i - } - if fieldStart < len(s) { // Last field might end at EOF. - a[na] = s[fieldStart:] - } - return a -} - -// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c) -// and returns an array of slices of s. If all code points in s satisfy f(c) or the -// string is empty, an empty slice is returned. -// -// FieldsFunc makes no guarantees about the order in which it calls f(c) -// and assumes that f always returns the same value for a given c. -func FieldsFunc(s string, f func(rune) bool) []string { - // A span is used to record a slice of s of the form s[start:end]. - // The start index is inclusive and the end index is exclusive. - type span struct { - start int - end int - } - spans := make([]span, 0, 32) - - // Find the field start and end indices. - // Doing this in a separate pass (rather than slicing the string s - // and collecting the result substrings right away) is significantly - // more efficient, possibly due to cache effects. - start := -1 // valid span start if >= 0 - for end, rune := range s { - if f(rune) { - if start >= 0 { - spans = append(spans, span{start, end}) - // Set start to a negative value. - // Note: using -1 here consistently and reproducibly - // slows down this code by a several percent on amd64. - start = ^start - } - } else { - if start < 0 { - start = end - } - } - } - - // Last field might end at EOF. - if start >= 0 { - spans = append(spans, span{start, len(s)}) - } - - // Create strings from recorded field indices. - a := make([]string, len(spans)) - for i, span := range spans { - a[i] = s[span.start:span.end] - } - - return a -} - -// Join concatenates the elements of its first argument to create a single string. The separator -// string sep is placed between elements in the resulting string. -func Join(elems []string, sep string) string { - switch len(elems) { - case 0: - return "" - case 1: - return elems[0] - } - - var n int - if len(sep) > 0 { - if len(sep) >= maxInt/(len(elems)-1) { - panic("strings: Join output length overflow") - } - n += len(sep) * (len(elems) - 1) - } - for _, elem := range elems { - if len(elem) > maxInt-n { - panic("strings: Join output length overflow") - } - n += len(elem) - } - - var b Builder - b.Grow(n) - b.WriteString(elems[0]) - for _, s := range elems[1:] { - b.WriteString(sep) - b.WriteString(s) - } - return b.String() -} - -// HasPrefix reports whether the string s begins with prefix. -func HasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[0:len(prefix)] == prefix -} - -// HasSuffix reports whether the string s ends with suffix. -func HasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix -} - -// Map returns a copy of the string s with all its characters modified -// according to the mapping function. If mapping returns a negative value, the character is -// dropped from the string with no replacement. -func Map(mapping func(rune) rune, s string) string { - // In the worst case, the string can grow when mapped, making - // things unpleasant. But it's so rare we barge in assuming it's - // fine. It could also shrink but that falls out naturally. - - // The output buffer b is initialized on demand, the first - // time a character differs. - var b Builder - - for i, c := range s { - r := mapping(c) - if r == c && c != utf8.RuneError { - continue - } - - var width int - if c == utf8.RuneError { - c, width = utf8.DecodeRuneInString(s[i:]) - if width != 1 && r == c { - continue - } - } else { - width = utf8.RuneLen(c) - } - - b.Grow(len(s) + utf8.UTFMax) - b.WriteString(s[:i]) - if r >= 0 { - b.WriteRune(r) - } - - s = s[i+width:] - break - } - - // Fast path for unchanged input - if b.Cap() == 0 { // didn't call b.Grow above - return s - } - - for _, c := range s { - r := mapping(c) - - if r >= 0 { - // common case - // Due to inlining, it is more performant to determine if WriteByte should be - // invoked rather than always call WriteRune - if r < utf8.RuneSelf { - b.WriteByte(byte(r)) - } else { - // r is not an ASCII rune. - b.WriteRune(r) - } - } - } - - return b.String() -} - -// Repeat returns a new string consisting of count copies of the string s. -// -// It panics if count is negative or if the result of (len(s) * count) -// overflows. -func Repeat(s string, count int) string { - switch count { - case 0: - return "" - case 1: - return s - } - - // Since we cannot return an error on overflow, - // we should panic if the repeat will generate an overflow. - // See golang.org/issue/16237. - if count < 0 { - panic("strings: negative Repeat count") - } - if len(s) >= maxInt/count { - panic("strings: Repeat output length overflow") - } - n := len(s) * count - - if len(s) == 0 { - return "" - } - - // Past a certain chunk size it is counterproductive to use - // larger chunks as the source of the write, as when the source - // is too large we are basically just thrashing the CPU D-cache. - // So if the result length is larger than an empirically-found - // limit (8KB), we stop growing the source string once the limit - // is reached and keep reusing the same source string - that - // should therefore be always resident in the L1 cache - until we - // have completed the construction of the result. - // This yields significant speedups (up to +100%) in cases where - // the result length is large (roughly, over L2 cache size). - const chunkLimit = 8 * 1024 - chunkMax := n - if n > chunkLimit { - chunkMax = chunkLimit / len(s) * len(s) - if chunkMax == 0 { - chunkMax = len(s) - } - } - - var b Builder - b.Grow(n) - b.WriteString(s) - for b.Len() < n { - chunk := n - b.Len() - if chunk > b.Len() { - chunk = b.Len() - } - if chunk > chunkMax { - chunk = chunkMax - } - b.WriteString(b.String()[:chunk]) - } - return b.String() -} - -// ToUpper returns s with all Unicode letters mapped to their upper case. -func ToUpper(s string) string { - isASCII, hasLower := true, false - for i := 0; i < len(s); i++ { - c := s[i] - if c >= utf8.RuneSelf { - isASCII = false - break - } - hasLower = hasLower || ('a' <= c && c <= 'z') - } - - if isASCII { // optimize for ASCII-only strings. - if !hasLower { - return s - } - var ( - b Builder - pos int - ) - b.Grow(len(s)) - for i := 0; i < len(s); i++ { - c := s[i] - if 'a' <= c && c <= 'z' { - c -= 'a' - 'A' - if pos < i { - b.WriteString(s[pos:i]) - } - b.WriteByte(c) - pos = i + 1 - } - } - if pos < len(s) { - b.WriteString(s[pos:]) - } - return b.String() - } - return Map(unicode.ToUpper, s) -} - -// ToLower returns s with all Unicode letters mapped to their lower case. -func ToLower(s string) string { - isASCII, hasUpper := true, false - for i := 0; i < len(s); i++ { - c := s[i] - if c >= utf8.RuneSelf { - isASCII = false - break - } - hasUpper = hasUpper || ('A' <= c && c <= 'Z') - } - - if isASCII { // optimize for ASCII-only strings. - if !hasUpper { - return s - } - var ( - b Builder - pos int - ) - b.Grow(len(s)) - for i := 0; i < len(s); i++ { - c := s[i] - if 'A' <= c && c <= 'Z' { - c += 'a' - 'A' - if pos < i { - b.WriteString(s[pos:i]) - } - b.WriteByte(c) - pos = i + 1 - } - } - if pos < len(s) { - b.WriteString(s[pos:]) - } - return b.String() - } - return Map(unicode.ToLower, s) -} - -// ToTitle returns a copy of the string s with all Unicode letters mapped to -// their Unicode title case. -func ToTitle(s string) string { return Map(unicode.ToTitle, s) } - -// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their -// upper case using the case mapping specified by c. -func ToUpperSpecial(c unicode.SpecialCase, s string) string { - return Map(c.ToUpper, s) -} - -// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their -// lower case using the case mapping specified by c. -func ToLowerSpecial(c unicode.SpecialCase, s string) string { - return Map(c.ToLower, s) -} - -// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their -// Unicode title case, giving priority to the special casing rules. -func ToTitleSpecial(c unicode.SpecialCase, s string) string { - return Map(c.ToTitle, s) -} - -// ToValidUTF8 returns a copy of the string s with each run of invalid UTF-8 byte sequences -// replaced by the replacement string, which may be empty. -func ToValidUTF8(s, replacement string) string { - var b Builder - - for i, c := range s { - if c != utf8.RuneError { - continue - } - - _, wid := utf8.DecodeRuneInString(s[i:]) - if wid == 1 { - b.Grow(len(s) + len(replacement)) - b.WriteString(s[:i]) - s = s[i:] - break - } - } - - // Fast path for unchanged input - if b.Cap() == 0 { // didn't call b.Grow above - return s - } - - invalid := false // previous byte was from an invalid UTF-8 sequence - for i := 0; i < len(s); { - c := s[i] - if c < utf8.RuneSelf { - i++ - invalid = false - b.WriteByte(c) - continue - } - _, wid := utf8.DecodeRuneInString(s[i:]) - if wid == 1 { - i++ - if !invalid { - invalid = true - b.WriteString(replacement) - } - continue - } - invalid = false - b.WriteString(s[i : i+wid]) - i += wid - } - - return b.String() -} - -// isSeparator reports whether the rune could mark a word boundary. -// TODO: update when package unicode captures more of the properties. -func isSeparator(r rune) bool { - // ASCII alphanumerics and underscore are not separators - if r <= 0x7F { - switch { - case '0' <= r && r <= '9': - return false - case 'a' <= r && r <= 'z': - return false - case 'A' <= r && r <= 'Z': - return false - case r == '_': - return false - } - return true - } - // Letters and digits are not separators - if unicode.IsLetter(r) || unicode.IsDigit(r) { - return false - } - // Otherwise, all we can do for now is treat spaces as separators. - return unicode.IsSpace(r) -} - -// Title returns a copy of the string s with all Unicode letters that begin words -// mapped to their Unicode title case. -// -// Deprecated: The rule Title uses for word boundaries does not handle Unicode -// punctuation properly. Use golang.org/x/text/cases instead. -func Title(s string) string { - // Use a closure here to remember state. - // Hackish but effective. Depends on Map scanning in order and calling - // the closure once per rune. - prev := ' ' - return Map( - func(r rune) rune { - if isSeparator(prev) { - prev = r - return unicode.ToTitle(r) - } - prev = r - return r - }, - s) -} - -// TrimLeftFunc returns a slice of the string s with all leading -// Unicode code points c satisfying f(c) removed. -func TrimLeftFunc(s string, f func(rune) bool) string { - i := indexFunc(s, f, false) - if i == -1 { - return "" - } - return s[i:] -} - -// TrimRightFunc returns a slice of the string s with all trailing -// Unicode code points c satisfying f(c) removed. -func TrimRightFunc(s string, f func(rune) bool) string { - i := lastIndexFunc(s, f, false) - if i >= 0 && s[i] >= utf8.RuneSelf { - _, wid := utf8.DecodeRuneInString(s[i:]) - i += wid - } else { - i++ - } - return s[0:i] -} - -// TrimFunc returns a slice of the string s with all leading -// and trailing Unicode code points c satisfying f(c) removed. -func TrimFunc(s string, f func(rune) bool) string { - return TrimRightFunc(TrimLeftFunc(s, f), f) -} - -// IndexFunc returns the index into s of the first Unicode -// code point satisfying f(c), or -1 if none do. -func IndexFunc(s string, f func(rune) bool) int { - return indexFunc(s, f, true) -} - -// LastIndexFunc returns the index into s of the last -// Unicode code point satisfying f(c), or -1 if none do. -func LastIndexFunc(s string, f func(rune) bool) int { - return lastIndexFunc(s, f, true) -} - -// indexFunc is the same as IndexFunc except that if -// truth==false, the sense of the predicate function is -// inverted. -func indexFunc(s string, f func(rune) bool, truth bool) int { - for i, r := range s { - if f(r) == truth { - return i - } - } - return -1 -} - -// lastIndexFunc is the same as LastIndexFunc except that if -// truth==false, the sense of the predicate function is -// inverted. -func lastIndexFunc(s string, f func(rune) bool, truth bool) int { - for i := len(s); i > 0; { - r, size := utf8.DecodeLastRuneInString(s[0:i]) - i -= size - if f(r) == truth { - return i - } - } - return -1 -} - -// asciiSet is a 32-byte value, where each bit represents the presence of a -// given ASCII character in the set. The 128-bits of the lower 16 bytes, -// starting with the least-significant bit of the lowest word to the -// most-significant bit of the highest word, map to the full range of all -// 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed, -// ensuring that any non-ASCII character will be reported as not in the set. -// This allocates a total of 32 bytes even though the upper half -// is unused to avoid bounds checks in asciiSet.contains. -type asciiSet [8]uint32 - -// makeASCIISet creates a set of ASCII characters and reports whether all -// characters in chars are ASCII. -func makeASCIISet(chars string) (as asciiSet, ok bool) { - for i := 0; i < len(chars); i++ { - c := chars[i] - if c >= utf8.RuneSelf { - return as, false - } - as[c/32] |= 1 << (c % 32) - } - return as, true -} - -// contains reports whether c is inside the set. -func (as *asciiSet) contains(c byte) bool { - return (as[c/32] & (1 << (c % 32))) != 0 -} - -// Trim returns a slice of the string s with all leading and -// trailing Unicode code points contained in cutset removed. -func Trim(s, cutset string) string { - if s == "" || cutset == "" { - return s - } - if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { - return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0]) - } - if as, ok := makeASCIISet(cutset); ok { - return trimLeftASCII(trimRightASCII(s, &as), &as) - } - return trimLeftUnicode(trimRightUnicode(s, cutset), cutset) -} - -// TrimLeft returns a slice of the string s with all leading -// Unicode code points contained in cutset removed. -// -// To remove a prefix, use [TrimPrefix] instead. -func TrimLeft(s, cutset string) string { - if s == "" || cutset == "" { - return s - } - if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { - return trimLeftByte(s, cutset[0]) - } - if as, ok := makeASCIISet(cutset); ok { - return trimLeftASCII(s, &as) - } - return trimLeftUnicode(s, cutset) -} - -func trimLeftByte(s string, c byte) string { - for len(s) > 0 && s[0] == c { - s = s[1:] - } - return s -} - -func trimLeftASCII(s string, as *asciiSet) string { - for len(s) > 0 { - if !as.contains(s[0]) { - break - } - s = s[1:] - } - return s -} - -func trimLeftUnicode(s, cutset string) string { - for len(s) > 0 { - r, n := rune(s[0]), 1 - if r >= utf8.RuneSelf { - r, n = utf8.DecodeRuneInString(s) - } - if !ContainsRune(cutset, r) { - break - } - s = s[n:] - } - return s -} - -// TrimRight returns a slice of the string s, with all trailing -// Unicode code points contained in cutset removed. -// -// To remove a suffix, use [TrimSuffix] instead. -func TrimRight(s, cutset string) string { - if s == "" || cutset == "" { - return s - } - if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { - return trimRightByte(s, cutset[0]) - } - if as, ok := makeASCIISet(cutset); ok { - return trimRightASCII(s, &as) - } - return trimRightUnicode(s, cutset) -} - -func trimRightByte(s string, c byte) string { - for len(s) > 0 && s[len(s)-1] == c { - s = s[:len(s)-1] - } - return s -} - -func trimRightASCII(s string, as *asciiSet) string { - for len(s) > 0 { - if !as.contains(s[len(s)-1]) { - break - } - s = s[:len(s)-1] - } - return s -} - -func trimRightUnicode(s, cutset string) string { - for len(s) > 0 { - r, n := rune(s[len(s)-1]), 1 - if r >= utf8.RuneSelf { - r, n = utf8.DecodeLastRuneInString(s) - } - if !ContainsRune(cutset, r) { - break - } - s = s[:len(s)-n] - } - return s -} - -// TrimSpace returns a slice of the string s, with all leading -// and trailing white space removed, as defined by Unicode. -func TrimSpace(s string) string { - // Fast path for ASCII: look for the first ASCII non-space byte - start := 0 - for ; start < len(s); start++ { - c := s[start] - if c >= utf8.RuneSelf { - // If we run into a non-ASCII byte, fall back to the - // slower unicode-aware method on the remaining bytes - return TrimFunc(s[start:], unicode.IsSpace) - } - if asciiSpace[c] == 0 { - break - } - } - - // Now look for the first ASCII non-space byte from the end - stop := len(s) - for ; stop > start; stop-- { - c := s[stop-1] - if c >= utf8.RuneSelf { - // start has been already trimmed above, should trim end only - return TrimRightFunc(s[start:stop], unicode.IsSpace) - } - if asciiSpace[c] == 0 { - break - } - } - - // At this point s[start:stop] starts and ends with an ASCII - // non-space bytes, so we're done. Non-ASCII cases have already - // been handled above. - return s[start:stop] -} - -// TrimPrefix returns s without the provided leading prefix string. -// If s doesn't start with prefix, s is returned unchanged. -func TrimPrefix(s, prefix string) string { - if HasPrefix(s, prefix) { - return s[len(prefix):] - } - return s -} - -// TrimSuffix returns s without the provided trailing suffix string. -// If s doesn't end with suffix, s is returned unchanged. -func TrimSuffix(s, suffix string) string { - if HasSuffix(s, suffix) { - return s[:len(s)-len(suffix)] - } - return s -} - -// Replace returns a copy of the string s with the first n -// non-overlapping instances of old replaced by new. -// If old is empty, it matches at the beginning of the string -// and after each UTF-8 sequence, yielding up to k+1 replacements -// for a k-rune string. -// If n < 0, there is no limit on the number of replacements. -func Replace(s, old, new string, n int) string { - if old == new || n == 0 { - return s // avoid allocation - } - - // Compute number of replacements. - if m := Count(s, old); m == 0 { - return s // avoid allocation - } else if n < 0 || m < n { - n = m - } - - // Apply replacements to buffer. - var b Builder - b.Grow(len(s) + n*(len(new)-len(old))) - start := 0 - for i := 0; i < n; i++ { - j := start - if len(old) == 0 { - if i > 0 { - _, wid := utf8.DecodeRuneInString(s[start:]) - j += wid - } - } else { - j += Index(s[start:], old) - } - b.WriteString(s[start:j]) - b.WriteString(new) - start = j + len(old) - } - b.WriteString(s[start:]) - return b.String() -} - -// ReplaceAll returns a copy of the string s with all -// non-overlapping instances of old replaced by new. -// If old is empty, it matches at the beginning of the string -// and after each UTF-8 sequence, yielding up to k+1 replacements -// for a k-rune string. -func ReplaceAll(s, old, new string) string { - return Replace(s, old, new, -1) -} - -// EqualFold reports whether s and t, interpreted as UTF-8 strings, -// are equal under simple Unicode case-folding, which is a more general -// form of case-insensitivity. -func EqualFold(s, t string) bool { - // ASCII fast path - i := 0 - for ; i < len(s) && i < len(t); i++ { - sr := s[i] - tr := t[i] - if sr|tr >= utf8.RuneSelf { - goto hasUnicode - } - - // Easy case. - if tr == sr { - continue - } - - // Make sr < tr to simplify what follows. - if tr < sr { - tr, sr = sr, tr - } - // ASCII only, sr/tr must be upper/lower case - if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' { - continue - } - return false - } - // Check if we've exhausted both strings. - return len(s) == len(t) - -hasUnicode: - s = s[i:] - t = t[i:] - for _, sr := range s { - // If t is exhausted the strings are not equal. - if len(t) == 0 { - return false - } - - // Extract first rune from second string. - var tr rune - if t[0] < utf8.RuneSelf { - tr, t = rune(t[0]), t[1:] - } else { - r, size := utf8.DecodeRuneInString(t) - tr, t = r, t[size:] - } - - // If they match, keep going; if not, return false. - - // Easy case. - if tr == sr { - continue - } - - // Make sr < tr to simplify what follows. - if tr < sr { - tr, sr = sr, tr - } - // Fast check for ASCII. - if tr < utf8.RuneSelf { - // ASCII only, sr/tr must be upper/lower case - if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' { - continue - } - return false - } - - // General case. SimpleFold(x) returns the next equivalent rune > x - // or wraps around to smaller values. - r := unicode.SimpleFold(sr) - for r != sr && r < tr { - r = unicode.SimpleFold(r) - } - if r == tr { - continue - } - return false - } - - // First string is empty, so check if the second one is also empty. - return len(t) == 0 -} - -// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s. -func Index(s, substr string) int { - n := len(substr) - switch { - case n == 0: - return 0 - case n == 1: - return IndexByte(s, substr[0]) - case n == len(s): - if substr == s { - return 0 - } - return -1 - case n > len(s): - return -1 - case n <= bytealg.MaxLen: - // Use brute force when s and substr both are small - if len(s) <= bytealg.MaxBruteForce { - return bytealg.IndexString(s, substr) - } - c0 := substr[0] - c1 := substr[1] - i := 0 - t := len(s) - n + 1 - fails := 0 - for i < t { - if s[i] != c0 { - // IndexByte is faster than bytealg.IndexString, so use it as long as - // we're not getting lots of false positives. - o := IndexByte(s[i+1:t], c0) - if o < 0 { - return -1 - } - i += o + 1 - } - if s[i+1] == c1 && s[i:i+n] == substr { - return i - } - fails++ - i++ - // Switch to bytealg.IndexString when IndexByte produces too many false positives. - if fails > bytealg.Cutover(i) { - r := bytealg.IndexString(s[i:], substr) - if r >= 0 { - return r + i - } - return -1 - } - } - return -1 - } - c0 := substr[0] - c1 := substr[1] - i := 0 - t := len(s) - n + 1 - fails := 0 - for i < t { - if s[i] != c0 { - o := IndexByte(s[i+1:t], c0) - if o < 0 { - return -1 - } - i += o + 1 - } - if s[i+1] == c1 && s[i:i+n] == substr { - return i - } - i++ - fails++ - if fails >= 4+i>>4 && i < t { - // See comment in ../bytes/bytes.go. - j := bytealg.IndexRabinKarp(s[i:], substr) - if j < 0 { - return -1 - } - return i + j - } - } - return -1 -} - -// Cut slices s around the first instance of sep, -// returning the text before and after sep. -// The found result reports whether sep appears in s. -// If sep does not appear in s, cut returns s, "", false. -func Cut(s, sep string) (before, after string, found bool) { - if i := Index(s, sep); i >= 0 { - return s[:i], s[i+len(sep):], true - } - return s, "", false -} - -// CutPrefix returns s without the provided leading prefix string -// and reports whether it found the prefix. -// If s doesn't start with prefix, CutPrefix returns s, false. -// If prefix is the empty string, CutPrefix returns s, true. -func CutPrefix(s, prefix string) (after string, found bool) { - if !HasPrefix(s, prefix) { - return s, false - } - return s[len(prefix):], true -} - -// CutSuffix returns s without the provided ending suffix string -// and reports whether it found the suffix. -// If s doesn't end with suffix, CutSuffix returns s, false. -// If suffix is the empty string, CutSuffix returns s, true. -func CutSuffix(s, suffix string) (before string, found bool) { - if !HasSuffix(s, suffix) { - return s, false - } - return s[:len(s)-len(suffix)], true -} diff --git a/contrib/go/_std_1.22/src/sync/atomic/asm.s b/contrib/go/_std_1.22/src/sync/atomic/asm.s deleted file mode 100644 index 2022304665ef..000000000000 --- a/contrib/go/_std_1.22/src/sync/atomic/asm.s +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !race - -#include "textflag.h" - -TEXT ·SwapInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchg(SB) - -TEXT ·SwapUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchg(SB) - -TEXT ·SwapInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchg64(SB) - -TEXT ·SwapUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchg64(SB) - -TEXT ·SwapUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchguintptr(SB) - -TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Cas(SB) - -TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Cas(SB) - -TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Casuintptr(SB) - -TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Cas64(SB) - -TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Cas64(SB) - -TEXT ·AddInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadd(SB) - -TEXT ·AddUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadd(SB) - -TEXT ·AddUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadduintptr(SB) - -TEXT ·AddInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadd64(SB) - -TEXT ·AddUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadd64(SB) - -TEXT ·LoadInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Load(SB) - -TEXT ·LoadUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Load(SB) - -TEXT ·LoadInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Load64(SB) - -TEXT ·LoadUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Load64(SB) - -TEXT ·LoadUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Loaduintptr(SB) - -TEXT ·LoadPointer(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Loadp(SB) - -TEXT ·StoreInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Store(SB) - -TEXT ·StoreUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Store(SB) - -TEXT ·StoreInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Store64(SB) - -TEXT ·StoreUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Store64(SB) - -TEXT ·StoreUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Storeuintptr(SB) diff --git a/contrib/go/_std_1.22/src/sync/atomic/doc.go b/contrib/go/_std_1.22/src/sync/atomic/doc.go deleted file mode 100644 index c22d1159affa..000000000000 --- a/contrib/go/_std_1.22/src/sync/atomic/doc.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package atomic provides low-level atomic memory primitives -// useful for implementing synchronization algorithms. -// -// These functions require great care to be used correctly. -// Except for special, low-level applications, synchronization is better -// done with channels or the facilities of the [sync] package. -// Share memory by communicating; -// don't communicate by sharing memory. -// -// The swap operation, implemented by the SwapT functions, is the atomic -// equivalent of: -// -// old = *addr -// *addr = new -// return old -// -// The compare-and-swap operation, implemented by the CompareAndSwapT -// functions, is the atomic equivalent of: -// -// if *addr == old { -// *addr = new -// return true -// } -// return false -// -// The add operation, implemented by the AddT functions, is the atomic -// equivalent of: -// -// *addr += delta -// return *addr -// -// The load and store operations, implemented by the LoadT and StoreT -// functions, are the atomic equivalents of "return *addr" and -// "*addr = val". -// -// In the terminology of the Go memory model, if the effect of -// an atomic operation A is observed by atomic operation B, -// then A “synchronizes before” B. -// Additionally, all the atomic operations executed in a program -// behave as though executed in some sequentially consistent order. -// This definition provides the same semantics as -// C++'s sequentially consistent atomics and Java's volatile variables. -package atomic - -import ( - "unsafe" -) - -// BUG(rsc): On 386, the 64-bit functions use instructions unavailable before the Pentium MMX. -// -// On non-Linux ARM, the 64-bit functions use instructions unavailable before the ARMv6k core. -// -// On ARM, 386, and 32-bit MIPS, it is the caller's responsibility to arrange -// for 64-bit alignment of 64-bit words accessed atomically via the primitive -// atomic functions (types [Int64] and [Uint64] are automatically aligned). -// The first word in an allocated struct, array, or slice; in a global -// variable; or in a local variable (because the subject of all atomic operations -// will escape to the heap) can be relied upon to be 64-bit aligned. - -// SwapInt32 atomically stores new into *addr and returns the previous *addr value. -// Consider using the more ergonomic and less error-prone [Int32.Swap] instead. -func SwapInt32(addr *int32, new int32) (old int32) - -// SwapInt64 atomically stores new into *addr and returns the previous *addr value. -// Consider using the more ergonomic and less error-prone [Int64.Swap] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func SwapInt64(addr *int64, new int64) (old int64) - -// SwapUint32 atomically stores new into *addr and returns the previous *addr value. -// Consider using the more ergonomic and less error-prone [Uint32.Swap] instead. -func SwapUint32(addr *uint32, new uint32) (old uint32) - -// SwapUint64 atomically stores new into *addr and returns the previous *addr value. -// Consider using the more ergonomic and less error-prone [Uint64.Swap] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func SwapUint64(addr *uint64, new uint64) (old uint64) - -// SwapUintptr atomically stores new into *addr and returns the previous *addr value. -// Consider using the more ergonomic and less error-prone [Uintptr.Swap] instead. -func SwapUintptr(addr *uintptr, new uintptr) (old uintptr) - -// SwapPointer atomically stores new into *addr and returns the previous *addr value. -// Consider using the more ergonomic and less error-prone [Pointer.Swap] instead. -func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer) - -// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value. -// Consider using the more ergonomic and less error-prone [Int32.CompareAndSwap] instead. -func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool) - -// CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value. -// Consider using the more ergonomic and less error-prone [Int64.CompareAndSwap] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool) - -// CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value. -// Consider using the more ergonomic and less error-prone [Uint32.CompareAndSwap] instead. -func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool) - -// CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value. -// Consider using the more ergonomic and less error-prone [Uint64.CompareAndSwap] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool) - -// CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value. -// Consider using the more ergonomic and less error-prone [Uintptr.CompareAndSwap] instead. -func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool) - -// CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value. -// Consider using the more ergonomic and less error-prone [Pointer.CompareAndSwap] instead. -func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool) - -// AddInt32 atomically adds delta to *addr and returns the new value. -// Consider using the more ergonomic and less error-prone [Int32.Add] instead. -func AddInt32(addr *int32, delta int32) (new int32) - -// AddUint32 atomically adds delta to *addr and returns the new value. -// To subtract a signed positive constant value c from x, do AddUint32(&x, ^uint32(c-1)). -// In particular, to decrement x, do AddUint32(&x, ^uint32(0)). -// Consider using the more ergonomic and less error-prone [Uint32.Add] instead. -func AddUint32(addr *uint32, delta uint32) (new uint32) - -// AddInt64 atomically adds delta to *addr and returns the new value. -// Consider using the more ergonomic and less error-prone [Int64.Add] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func AddInt64(addr *int64, delta int64) (new int64) - -// AddUint64 atomically adds delta to *addr and returns the new value. -// To subtract a signed positive constant value c from x, do AddUint64(&x, ^uint64(c-1)). -// In particular, to decrement x, do AddUint64(&x, ^uint64(0)). -// Consider using the more ergonomic and less error-prone [Uint64.Add] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func AddUint64(addr *uint64, delta uint64) (new uint64) - -// AddUintptr atomically adds delta to *addr and returns the new value. -// Consider using the more ergonomic and less error-prone [Uintptr.Add] instead. -func AddUintptr(addr *uintptr, delta uintptr) (new uintptr) - -// LoadInt32 atomically loads *addr. -// Consider using the more ergonomic and less error-prone [Int32.Load] instead. -func LoadInt32(addr *int32) (val int32) - -// LoadInt64 atomically loads *addr. -// Consider using the more ergonomic and less error-prone [Int64.Load] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func LoadInt64(addr *int64) (val int64) - -// LoadUint32 atomically loads *addr. -// Consider using the more ergonomic and less error-prone [Uint32.Load] instead. -func LoadUint32(addr *uint32) (val uint32) - -// LoadUint64 atomically loads *addr. -// Consider using the more ergonomic and less error-prone [Uint64.Load] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func LoadUint64(addr *uint64) (val uint64) - -// LoadUintptr atomically loads *addr. -// Consider using the more ergonomic and less error-prone [Uintptr.Load] instead. -func LoadUintptr(addr *uintptr) (val uintptr) - -// LoadPointer atomically loads *addr. -// Consider using the more ergonomic and less error-prone [Pointer.Load] instead. -func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) - -// StoreInt32 atomically stores val into *addr. -// Consider using the more ergonomic and less error-prone [Int32.Store] instead. -func StoreInt32(addr *int32, val int32) - -// StoreInt64 atomically stores val into *addr. -// Consider using the more ergonomic and less error-prone [Int64.Store] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func StoreInt64(addr *int64, val int64) - -// StoreUint32 atomically stores val into *addr. -// Consider using the more ergonomic and less error-prone [Uint32.Store] instead. -func StoreUint32(addr *uint32, val uint32) - -// StoreUint64 atomically stores val into *addr. -// Consider using the more ergonomic and less error-prone [Uint64.Store] instead -// (particularly if you target 32-bit platforms; see the bugs section). -func StoreUint64(addr *uint64, val uint64) - -// StoreUintptr atomically stores val into *addr. -// Consider using the more ergonomic and less error-prone [Uintptr.Store] instead. -func StoreUintptr(addr *uintptr, val uintptr) - -// StorePointer atomically stores val into *addr. -// Consider using the more ergonomic and less error-prone [Pointer.Store] instead. -func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer) diff --git a/contrib/go/_std_1.22/src/sync/atomic/type.go b/contrib/go/_std_1.22/src/sync/atomic/type.go deleted file mode 100644 index 179fa93092be..000000000000 --- a/contrib/go/_std_1.22/src/sync/atomic/type.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package atomic - -import "unsafe" - -// A Bool is an atomic boolean value. -// The zero value is false. -type Bool struct { - _ noCopy - v uint32 -} - -// Load atomically loads and returns the value stored in x. -func (x *Bool) Load() bool { return LoadUint32(&x.v) != 0 } - -// Store atomically stores val into x. -func (x *Bool) Store(val bool) { StoreUint32(&x.v, b32(val)) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Bool) Swap(new bool) (old bool) { return SwapUint32(&x.v, b32(new)) != 0 } - -// CompareAndSwap executes the compare-and-swap operation for the boolean value x. -func (x *Bool) CompareAndSwap(old, new bool) (swapped bool) { - return CompareAndSwapUint32(&x.v, b32(old), b32(new)) -} - -// b32 returns a uint32 0 or 1 representing b. -func b32(b bool) uint32 { - if b { - return 1 - } - return 0 -} - -// For testing *Pointer[T]'s methods can be inlined. -// Keep in sync with cmd/compile/internal/test/inl_test.go:TestIntendedInlining. -var _ = &Pointer[int]{} - -// A Pointer is an atomic pointer of type *T. The zero value is a nil *T. -type Pointer[T any] struct { - // Mention *T in a field to disallow conversion between Pointer types. - // See go.dev/issue/56603 for more details. - // Use *T, not T, to avoid spurious recursive type definition errors. - _ [0]*T - - _ noCopy - v unsafe.Pointer -} - -// Load atomically loads and returns the value stored in x. -func (x *Pointer[T]) Load() *T { return (*T)(LoadPointer(&x.v)) } - -// Store atomically stores val into x. -func (x *Pointer[T]) Store(val *T) { StorePointer(&x.v, unsafe.Pointer(val)) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Pointer[T]) Swap(new *T) (old *T) { return (*T)(SwapPointer(&x.v, unsafe.Pointer(new))) } - -// CompareAndSwap executes the compare-and-swap operation for x. -func (x *Pointer[T]) CompareAndSwap(old, new *T) (swapped bool) { - return CompareAndSwapPointer(&x.v, unsafe.Pointer(old), unsafe.Pointer(new)) -} - -// An Int32 is an atomic int32. The zero value is zero. -type Int32 struct { - _ noCopy - v int32 -} - -// Load atomically loads and returns the value stored in x. -func (x *Int32) Load() int32 { return LoadInt32(&x.v) } - -// Store atomically stores val into x. -func (x *Int32) Store(val int32) { StoreInt32(&x.v, val) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Int32) Swap(new int32) (old int32) { return SwapInt32(&x.v, new) } - -// CompareAndSwap executes the compare-and-swap operation for x. -func (x *Int32) CompareAndSwap(old, new int32) (swapped bool) { - return CompareAndSwapInt32(&x.v, old, new) -} - -// Add atomically adds delta to x and returns the new value. -func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) } - -// An Int64 is an atomic int64. The zero value is zero. -type Int64 struct { - _ noCopy - _ align64 - v int64 -} - -// Load atomically loads and returns the value stored in x. -func (x *Int64) Load() int64 { return LoadInt64(&x.v) } - -// Store atomically stores val into x. -func (x *Int64) Store(val int64) { StoreInt64(&x.v, val) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Int64) Swap(new int64) (old int64) { return SwapInt64(&x.v, new) } - -// CompareAndSwap executes the compare-and-swap operation for x. -func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) { - return CompareAndSwapInt64(&x.v, old, new) -} - -// Add atomically adds delta to x and returns the new value. -func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) } - -// A Uint32 is an atomic uint32. The zero value is zero. -type Uint32 struct { - _ noCopy - v uint32 -} - -// Load atomically loads and returns the value stored in x. -func (x *Uint32) Load() uint32 { return LoadUint32(&x.v) } - -// Store atomically stores val into x. -func (x *Uint32) Store(val uint32) { StoreUint32(&x.v, val) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Uint32) Swap(new uint32) (old uint32) { return SwapUint32(&x.v, new) } - -// CompareAndSwap executes the compare-and-swap operation for x. -func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) { - return CompareAndSwapUint32(&x.v, old, new) -} - -// Add atomically adds delta to x and returns the new value. -func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) } - -// A Uint64 is an atomic uint64. The zero value is zero. -type Uint64 struct { - _ noCopy - _ align64 - v uint64 -} - -// Load atomically loads and returns the value stored in x. -func (x *Uint64) Load() uint64 { return LoadUint64(&x.v) } - -// Store atomically stores val into x. -func (x *Uint64) Store(val uint64) { StoreUint64(&x.v, val) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Uint64) Swap(new uint64) (old uint64) { return SwapUint64(&x.v, new) } - -// CompareAndSwap executes the compare-and-swap operation for x. -func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) { - return CompareAndSwapUint64(&x.v, old, new) -} - -// Add atomically adds delta to x and returns the new value. -func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) } - -// A Uintptr is an atomic uintptr. The zero value is zero. -type Uintptr struct { - _ noCopy - v uintptr -} - -// Load atomically loads and returns the value stored in x. -func (x *Uintptr) Load() uintptr { return LoadUintptr(&x.v) } - -// Store atomically stores val into x. -func (x *Uintptr) Store(val uintptr) { StoreUintptr(&x.v, val) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Uintptr) Swap(new uintptr) (old uintptr) { return SwapUintptr(&x.v, new) } - -// CompareAndSwap executes the compare-and-swap operation for x. -func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool) { - return CompareAndSwapUintptr(&x.v, old, new) -} - -// Add atomically adds delta to x and returns the new value. -func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) } - -// noCopy may be added to structs which must not be copied -// after the first use. -// -// See https://golang.org/issues/8005#issuecomment-190753527 -// for details. -// -// Note that it must not be embedded, due to the Lock and Unlock methods. -type noCopy struct{} - -// Lock is a no-op used by -copylocks checker from `go vet`. -func (*noCopy) Lock() {} -func (*noCopy) Unlock() {} - -// align64 may be added to structs that must be 64-bit aligned. -// This struct is recognized by a special case in the compiler -// and will not work if copied to any other package. -type align64 struct{} diff --git a/contrib/go/_std_1.22/src/sync/atomic/value.go b/contrib/go/_std_1.22/src/sync/atomic/value.go deleted file mode 100644 index a57b08a6b877..000000000000 --- a/contrib/go/_std_1.22/src/sync/atomic/value.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package atomic - -import ( - "unsafe" -) - -// A Value provides an atomic load and store of a consistently typed value. -// The zero value for a Value returns nil from Load. -// Once Store has been called, a Value must not be copied. -// -// A Value must not be copied after first use. -type Value struct { - v any -} - -// efaceWords is interface{} internal representation. -type efaceWords struct { - typ unsafe.Pointer - data unsafe.Pointer -} - -// Load returns the value set by the most recent Store. -// It returns nil if there has been no call to Store for this Value. -func (v *Value) Load() (val any) { - vp := (*efaceWords)(unsafe.Pointer(v)) - typ := LoadPointer(&vp.typ) - if typ == nil || typ == unsafe.Pointer(&firstStoreInProgress) { - // First store not yet completed. - return nil - } - data := LoadPointer(&vp.data) - vlp := (*efaceWords)(unsafe.Pointer(&val)) - vlp.typ = typ - vlp.data = data - return -} - -var firstStoreInProgress byte - -// Store sets the value of the Value v to val. -// All calls to Store for a given Value must use values of the same concrete type. -// Store of an inconsistent type panics, as does Store(nil). -func (v *Value) Store(val any) { - if val == nil { - panic("sync/atomic: store of nil value into Value") - } - vp := (*efaceWords)(unsafe.Pointer(v)) - vlp := (*efaceWords)(unsafe.Pointer(&val)) - for { - typ := LoadPointer(&vp.typ) - if typ == nil { - // Attempt to start first store. - // Disable preemption so that other goroutines can use - // active spin wait to wait for completion. - runtime_procPin() - if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { - runtime_procUnpin() - continue - } - // Complete first store. - StorePointer(&vp.data, vlp.data) - StorePointer(&vp.typ, vlp.typ) - runtime_procUnpin() - return - } - if typ == unsafe.Pointer(&firstStoreInProgress) { - // First store in progress. Wait. - // Since we disable preemption around the first store, - // we can wait with active spinning. - continue - } - // First store completed. Check type and overwrite data. - if typ != vlp.typ { - panic("sync/atomic: store of inconsistently typed value into Value") - } - StorePointer(&vp.data, vlp.data) - return - } -} - -// Swap stores new into Value and returns the previous value. It returns nil if -// the Value is empty. -// -// All calls to Swap for a given Value must use values of the same concrete -// type. Swap of an inconsistent type panics, as does Swap(nil). -func (v *Value) Swap(new any) (old any) { - if new == nil { - panic("sync/atomic: swap of nil value into Value") - } - vp := (*efaceWords)(unsafe.Pointer(v)) - np := (*efaceWords)(unsafe.Pointer(&new)) - for { - typ := LoadPointer(&vp.typ) - if typ == nil { - // Attempt to start first store. - // Disable preemption so that other goroutines can use - // active spin wait to wait for completion; and so that - // GC does not see the fake type accidentally. - runtime_procPin() - if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { - runtime_procUnpin() - continue - } - // Complete first store. - StorePointer(&vp.data, np.data) - StorePointer(&vp.typ, np.typ) - runtime_procUnpin() - return nil - } - if typ == unsafe.Pointer(&firstStoreInProgress) { - // First store in progress. Wait. - // Since we disable preemption around the first store, - // we can wait with active spinning. - continue - } - // First store completed. Check type and overwrite data. - if typ != np.typ { - panic("sync/atomic: swap of inconsistently typed value into Value") - } - op := (*efaceWords)(unsafe.Pointer(&old)) - op.typ, op.data = np.typ, SwapPointer(&vp.data, np.data) - return old - } -} - -// CompareAndSwap executes the compare-and-swap operation for the Value. -// -// All calls to CompareAndSwap for a given Value must use values of the same -// concrete type. CompareAndSwap of an inconsistent type panics, as does -// CompareAndSwap(old, nil). -func (v *Value) CompareAndSwap(old, new any) (swapped bool) { - if new == nil { - panic("sync/atomic: compare and swap of nil value into Value") - } - vp := (*efaceWords)(unsafe.Pointer(v)) - np := (*efaceWords)(unsafe.Pointer(&new)) - op := (*efaceWords)(unsafe.Pointer(&old)) - if op.typ != nil && np.typ != op.typ { - panic("sync/atomic: compare and swap of inconsistently typed values") - } - for { - typ := LoadPointer(&vp.typ) - if typ == nil { - if old != nil { - return false - } - // Attempt to start first store. - // Disable preemption so that other goroutines can use - // active spin wait to wait for completion; and so that - // GC does not see the fake type accidentally. - runtime_procPin() - if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { - runtime_procUnpin() - continue - } - // Complete first store. - StorePointer(&vp.data, np.data) - StorePointer(&vp.typ, np.typ) - runtime_procUnpin() - return true - } - if typ == unsafe.Pointer(&firstStoreInProgress) { - // First store in progress. Wait. - // Since we disable preemption around the first store, - // we can wait with active spinning. - continue - } - // First store completed. Check type and overwrite data. - if typ != np.typ { - panic("sync/atomic: compare and swap of inconsistently typed value into Value") - } - // Compare old and current via runtime equality check. - // This allows value types to be compared, something - // not offered by the package functions. - // CompareAndSwapPointer below only ensures vp.data - // has not changed since LoadPointer. - data := LoadPointer(&vp.data) - var i any - (*efaceWords)(unsafe.Pointer(&i)).typ = typ - (*efaceWords)(unsafe.Pointer(&i)).data = data - if i != old { - return false - } - return CompareAndSwapPointer(&vp.data, data, np.data) - } -} - -// Disable/enable preemption, implemented in runtime. -func runtime_procPin() int -func runtime_procUnpin() diff --git a/contrib/go/_std_1.22/src/sync/atomic/ya.make b/contrib/go/_std_1.22/src/sync/atomic/ya.make deleted file mode 100644 index 7e14d468ad29..000000000000 --- a/contrib/go/_std_1.22/src/sync/atomic/ya.make +++ /dev/null @@ -1,17 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) - SRCS( - doc.go - race.s - type.go - value.go - ) -ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - asm.s - doc.go - type.go - value.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/sync/map.go b/contrib/go/_std_1.22/src/sync/map.go deleted file mode 100644 index 7a9eebdce39d..000000000000 --- a/contrib/go/_std_1.22/src/sync/map.go +++ /dev/null @@ -1,516 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sync - -import ( - "sync/atomic" -) - -// Map is like a Go map[any]any but is safe for concurrent use -// by multiple goroutines without additional locking or coordination. -// Loads, stores, and deletes run in amortized constant time. -// -// The Map type is specialized. Most code should use a plain Go map instead, -// with separate locking or coordination, for better type safety and to make it -// easier to maintain other invariants along with the map content. -// -// The Map type is optimized for two common use cases: (1) when the entry for a given -// key is only ever written once but read many times, as in caches that only grow, -// or (2) when multiple goroutines read, write, and overwrite entries for disjoint -// sets of keys. In these two cases, use of a Map may significantly reduce lock -// contention compared to a Go map paired with a separate Mutex or RWMutex. -// -// The zero Map is empty and ready for use. A Map must not be copied after first use. -// -// In the terminology of the Go memory model, Map arranges that a write operation -// “synchronizes before” any read operation that observes the effect of the write, where -// read and write operations are defined as follows. -// Load, LoadAndDelete, LoadOrStore, Swap, CompareAndSwap, and CompareAndDelete -// are read operations; Delete, LoadAndDelete, Store, and Swap are write operations; -// LoadOrStore is a write operation when it returns loaded set to false; -// CompareAndSwap is a write operation when it returns swapped set to true; -// and CompareAndDelete is a write operation when it returns deleted set to true. -type Map struct { - mu Mutex - - // read contains the portion of the map's contents that are safe for - // concurrent access (with or without mu held). - // - // The read field itself is always safe to load, but must only be stored with - // mu held. - // - // Entries stored in read may be updated concurrently without mu, but updating - // a previously-expunged entry requires that the entry be copied to the dirty - // map and unexpunged with mu held. - read atomic.Pointer[readOnly] - - // dirty contains the portion of the map's contents that require mu to be - // held. To ensure that the dirty map can be promoted to the read map quickly, - // it also includes all of the non-expunged entries in the read map. - // - // Expunged entries are not stored in the dirty map. An expunged entry in the - // clean map must be unexpunged and added to the dirty map before a new value - // can be stored to it. - // - // If the dirty map is nil, the next write to the map will initialize it by - // making a shallow copy of the clean map, omitting stale entries. - dirty map[any]*entry - - // misses counts the number of loads since the read map was last updated that - // needed to lock mu to determine whether the key was present. - // - // Once enough misses have occurred to cover the cost of copying the dirty - // map, the dirty map will be promoted to the read map (in the unamended - // state) and the next store to the map will make a new dirty copy. - misses int -} - -// readOnly is an immutable struct stored atomically in the Map.read field. -type readOnly struct { - m map[any]*entry - amended bool // true if the dirty map contains some key not in m. -} - -// expunged is an arbitrary pointer that marks entries which have been deleted -// from the dirty map. -var expunged = new(any) - -// An entry is a slot in the map corresponding to a particular key. -type entry struct { - // p points to the interface{} value stored for the entry. - // - // If p == nil, the entry has been deleted, and either m.dirty == nil or - // m.dirty[key] is e. - // - // If p == expunged, the entry has been deleted, m.dirty != nil, and the entry - // is missing from m.dirty. - // - // Otherwise, the entry is valid and recorded in m.read.m[key] and, if m.dirty - // != nil, in m.dirty[key]. - // - // An entry can be deleted by atomic replacement with nil: when m.dirty is - // next created, it will atomically replace nil with expunged and leave - // m.dirty[key] unset. - // - // An entry's associated value can be updated by atomic replacement, provided - // p != expunged. If p == expunged, an entry's associated value can be updated - // only after first setting m.dirty[key] = e so that lookups using the dirty - // map find the entry. - p atomic.Pointer[any] -} - -func newEntry(i any) *entry { - e := &entry{} - e.p.Store(&i) - return e -} - -func (m *Map) loadReadOnly() readOnly { - if p := m.read.Load(); p != nil { - return *p - } - return readOnly{} -} - -// Load returns the value stored in the map for a key, or nil if no -// value is present. -// The ok result indicates whether value was found in the map. -func (m *Map) Load(key any) (value any, ok bool) { - read := m.loadReadOnly() - e, ok := read.m[key] - if !ok && read.amended { - m.mu.Lock() - // Avoid reporting a spurious miss if m.dirty got promoted while we were - // blocked on m.mu. (If further loads of the same key will not miss, it's - // not worth copying the dirty map for this key.) - read = m.loadReadOnly() - e, ok = read.m[key] - if !ok && read.amended { - e, ok = m.dirty[key] - // Regardless of whether the entry was present, record a miss: this key - // will take the slow path until the dirty map is promoted to the read - // map. - m.missLocked() - } - m.mu.Unlock() - } - if !ok { - return nil, false - } - return e.load() -} - -func (e *entry) load() (value any, ok bool) { - p := e.p.Load() - if p == nil || p == expunged { - return nil, false - } - return *p, true -} - -// Store sets the value for a key. -func (m *Map) Store(key, value any) { - _, _ = m.Swap(key, value) -} - -// tryCompareAndSwap compare the entry with the given old value and swaps -// it with a new value if the entry is equal to the old value, and the entry -// has not been expunged. -// -// If the entry is expunged, tryCompareAndSwap returns false and leaves -// the entry unchanged. -func (e *entry) tryCompareAndSwap(old, new any) bool { - p := e.p.Load() - if p == nil || p == expunged || *p != old { - return false - } - - // Copy the interface after the first load to make this method more amenable - // to escape analysis: if the comparison fails from the start, we shouldn't - // bother heap-allocating an interface value to store. - nc := new - for { - if e.p.CompareAndSwap(p, &nc) { - return true - } - p = e.p.Load() - if p == nil || p == expunged || *p != old { - return false - } - } -} - -// unexpungeLocked ensures that the entry is not marked as expunged. -// -// If the entry was previously expunged, it must be added to the dirty map -// before m.mu is unlocked. -func (e *entry) unexpungeLocked() (wasExpunged bool) { - return e.p.CompareAndSwap(expunged, nil) -} - -// swapLocked unconditionally swaps a value into the entry. -// -// The entry must be known not to be expunged. -func (e *entry) swapLocked(i *any) *any { - return e.p.Swap(i) -} - -// LoadOrStore returns the existing value for the key if present. -// Otherwise, it stores and returns the given value. -// The loaded result is true if the value was loaded, false if stored. -func (m *Map) LoadOrStore(key, value any) (actual any, loaded bool) { - // Avoid locking if it's a clean hit. - read := m.loadReadOnly() - if e, ok := read.m[key]; ok { - actual, loaded, ok := e.tryLoadOrStore(value) - if ok { - return actual, loaded - } - } - - m.mu.Lock() - read = m.loadReadOnly() - if e, ok := read.m[key]; ok { - if e.unexpungeLocked() { - m.dirty[key] = e - } - actual, loaded, _ = e.tryLoadOrStore(value) - } else if e, ok := m.dirty[key]; ok { - actual, loaded, _ = e.tryLoadOrStore(value) - m.missLocked() - } else { - if !read.amended { - // We're adding the first new key to the dirty map. - // Make sure it is allocated and mark the read-only map as incomplete. - m.dirtyLocked() - m.read.Store(&readOnly{m: read.m, amended: true}) - } - m.dirty[key] = newEntry(value) - actual, loaded = value, false - } - m.mu.Unlock() - - return actual, loaded -} - -// tryLoadOrStore atomically loads or stores a value if the entry is not -// expunged. -// -// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and -// returns with ok==false. -func (e *entry) tryLoadOrStore(i any) (actual any, loaded, ok bool) { - p := e.p.Load() - if p == expunged { - return nil, false, false - } - if p != nil { - return *p, true, true - } - - // Copy the interface after the first load to make this method more amenable - // to escape analysis: if we hit the "load" path or the entry is expunged, we - // shouldn't bother heap-allocating. - ic := i - for { - if e.p.CompareAndSwap(nil, &ic) { - return i, false, true - } - p = e.p.Load() - if p == expunged { - return nil, false, false - } - if p != nil { - return *p, true, true - } - } -} - -// LoadAndDelete deletes the value for a key, returning the previous value if any. -// The loaded result reports whether the key was present. -func (m *Map) LoadAndDelete(key any) (value any, loaded bool) { - read := m.loadReadOnly() - e, ok := read.m[key] - if !ok && read.amended { - m.mu.Lock() - read = m.loadReadOnly() - e, ok = read.m[key] - if !ok && read.amended { - e, ok = m.dirty[key] - delete(m.dirty, key) - // Regardless of whether the entry was present, record a miss: this key - // will take the slow path until the dirty map is promoted to the read - // map. - m.missLocked() - } - m.mu.Unlock() - } - if ok { - return e.delete() - } - return nil, false -} - -// Delete deletes the value for a key. -func (m *Map) Delete(key any) { - m.LoadAndDelete(key) -} - -func (e *entry) delete() (value any, ok bool) { - for { - p := e.p.Load() - if p == nil || p == expunged { - return nil, false - } - if e.p.CompareAndSwap(p, nil) { - return *p, true - } - } -} - -// trySwap swaps a value if the entry has not been expunged. -// -// If the entry is expunged, trySwap returns false and leaves the entry -// unchanged. -func (e *entry) trySwap(i *any) (*any, bool) { - for { - p := e.p.Load() - if p == expunged { - return nil, false - } - if e.p.CompareAndSwap(p, i) { - return p, true - } - } -} - -// Swap swaps the value for a key and returns the previous value if any. -// The loaded result reports whether the key was present. -func (m *Map) Swap(key, value any) (previous any, loaded bool) { - read := m.loadReadOnly() - if e, ok := read.m[key]; ok { - if v, ok := e.trySwap(&value); ok { - if v == nil { - return nil, false - } - return *v, true - } - } - - m.mu.Lock() - read = m.loadReadOnly() - if e, ok := read.m[key]; ok { - if e.unexpungeLocked() { - // The entry was previously expunged, which implies that there is a - // non-nil dirty map and this entry is not in it. - m.dirty[key] = e - } - if v := e.swapLocked(&value); v != nil { - loaded = true - previous = *v - } - } else if e, ok := m.dirty[key]; ok { - if v := e.swapLocked(&value); v != nil { - loaded = true - previous = *v - } - } else { - if !read.amended { - // We're adding the first new key to the dirty map. - // Make sure it is allocated and mark the read-only map as incomplete. - m.dirtyLocked() - m.read.Store(&readOnly{m: read.m, amended: true}) - } - m.dirty[key] = newEntry(value) - } - m.mu.Unlock() - return previous, loaded -} - -// CompareAndSwap swaps the old and new values for key -// if the value stored in the map is equal to old. -// The old value must be of a comparable type. -func (m *Map) CompareAndSwap(key, old, new any) bool { - read := m.loadReadOnly() - if e, ok := read.m[key]; ok { - return e.tryCompareAndSwap(old, new) - } else if !read.amended { - return false // No existing value for key. - } - - m.mu.Lock() - defer m.mu.Unlock() - read = m.loadReadOnly() - swapped := false - if e, ok := read.m[key]; ok { - swapped = e.tryCompareAndSwap(old, new) - } else if e, ok := m.dirty[key]; ok { - swapped = e.tryCompareAndSwap(old, new) - // We needed to lock mu in order to load the entry for key, - // and the operation didn't change the set of keys in the map - // (so it would be made more efficient by promoting the dirty - // map to read-only). - // Count it as a miss so that we will eventually switch to the - // more efficient steady state. - m.missLocked() - } - return swapped -} - -// CompareAndDelete deletes the entry for key if its value is equal to old. -// The old value must be of a comparable type. -// -// If there is no current value for key in the map, CompareAndDelete -// returns false (even if the old value is the nil interface value). -func (m *Map) CompareAndDelete(key, old any) (deleted bool) { - read := m.loadReadOnly() - e, ok := read.m[key] - if !ok && read.amended { - m.mu.Lock() - read = m.loadReadOnly() - e, ok = read.m[key] - if !ok && read.amended { - e, ok = m.dirty[key] - // Don't delete key from m.dirty: we still need to do the “compare” part - // of the operation. The entry will eventually be expunged when the - // dirty map is promoted to the read map. - // - // Regardless of whether the entry was present, record a miss: this key - // will take the slow path until the dirty map is promoted to the read - // map. - m.missLocked() - } - m.mu.Unlock() - } - for ok { - p := e.p.Load() - if p == nil || p == expunged || *p != old { - return false - } - if e.p.CompareAndSwap(p, nil) { - return true - } - } - return false -} - -// Range calls f sequentially for each key and value present in the map. -// If f returns false, range stops the iteration. -// -// Range does not necessarily correspond to any consistent snapshot of the Map's -// contents: no key will be visited more than once, but if the value for any key -// is stored or deleted concurrently (including by f), Range may reflect any -// mapping for that key from any point during the Range call. Range does not -// block other methods on the receiver; even f itself may call any method on m. -// -// Range may be O(N) with the number of elements in the map even if f returns -// false after a constant number of calls. -func (m *Map) Range(f func(key, value any) bool) { - // We need to be able to iterate over all of the keys that were already - // present at the start of the call to Range. - // If read.amended is false, then read.m satisfies that property without - // requiring us to hold m.mu for a long time. - read := m.loadReadOnly() - if read.amended { - // m.dirty contains keys not in read.m. Fortunately, Range is already O(N) - // (assuming the caller does not break out early), so a call to Range - // amortizes an entire copy of the map: we can promote the dirty copy - // immediately! - m.mu.Lock() - read = m.loadReadOnly() - if read.amended { - read = readOnly{m: m.dirty} - copyRead := read - m.read.Store(©Read) - m.dirty = nil - m.misses = 0 - } - m.mu.Unlock() - } - - for k, e := range read.m { - v, ok := e.load() - if !ok { - continue - } - if !f(k, v) { - break - } - } -} - -func (m *Map) missLocked() { - m.misses++ - if m.misses < len(m.dirty) { - return - } - m.read.Store(&readOnly{m: m.dirty}) - m.dirty = nil - m.misses = 0 -} - -func (m *Map) dirtyLocked() { - if m.dirty != nil { - return - } - - read := m.loadReadOnly() - m.dirty = make(map[any]*entry, len(read.m)) - for k, e := range read.m { - if !e.tryExpungeLocked() { - m.dirty[k] = e - } - } -} - -func (e *entry) tryExpungeLocked() (isExpunged bool) { - p := e.p.Load() - for p == nil { - if e.p.CompareAndSwap(nil, expunged) { - return true - } - p = e.p.Load() - } - return p == expunged -} diff --git a/contrib/go/_std_1.22/src/sync/rwmutex.go b/contrib/go/_std_1.22/src/sync/rwmutex.go deleted file mode 100644 index f445b66fd7b0..000000000000 --- a/contrib/go/_std_1.22/src/sync/rwmutex.go +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sync - -import ( - "internal/race" - "sync/atomic" - "unsafe" -) - -// There is a modified copy of this file in runtime/rwmutex.go. -// If you make any changes here, see if you should make them there. - -// A RWMutex is a reader/writer mutual exclusion lock. -// The lock can be held by an arbitrary number of readers or a single writer. -// The zero value for a RWMutex is an unlocked mutex. -// -// A RWMutex must not be copied after first use. -// -// If any goroutine calls Lock while the lock is already held by -// one or more readers, concurrent calls to RLock will block until -// the writer has acquired (and released) the lock, to ensure that -// the lock eventually becomes available to the writer. -// Note that this prohibits recursive read-locking. -// -// In the terminology of the Go memory model, -// the n'th call to Unlock “synchronizes before” the m'th call to Lock -// for any n < m, just as for Mutex. -// For any call to RLock, there exists an n such that -// the n'th call to Unlock “synchronizes before” that call to RLock, -// and the corresponding call to RUnlock “synchronizes before” -// the n+1'th call to Lock. -type RWMutex struct { - w Mutex // held if there are pending writers - writerSem uint32 // semaphore for writers to wait for completing readers - readerSem uint32 // semaphore for readers to wait for completing writers - readerCount atomic.Int32 // number of pending readers - readerWait atomic.Int32 // number of departing readers -} - -const rwmutexMaxReaders = 1 << 30 - -// Happens-before relationships are indicated to the race detector via: -// - Unlock -> Lock: readerSem -// - Unlock -> RLock: readerSem -// - RUnlock -> Lock: writerSem -// -// The methods below temporarily disable handling of race synchronization -// events in order to provide the more precise model above to the race -// detector. -// -// For example, atomic.AddInt32 in RLock should not appear to provide -// acquire-release semantics, which would incorrectly synchronize racing -// readers, thus potentially missing races. - -// RLock locks rw for reading. -// -// It should not be used for recursive read locking; a blocked Lock -// call excludes new readers from acquiring the lock. See the -// documentation on the RWMutex type. -func (rw *RWMutex) RLock() { - if race.Enabled { - _ = rw.w.state - race.Disable() - } - if rw.readerCount.Add(1) < 0 { - // A writer is pending, wait for it. - runtime_SemacquireRWMutexR(&rw.readerSem, false, 0) - } - if race.Enabled { - race.Enable() - race.Acquire(unsafe.Pointer(&rw.readerSem)) - } -} - -// TryRLock tries to lock rw for reading and reports whether it succeeded. -// -// Note that while correct uses of TryRLock do exist, they are rare, -// and use of TryRLock is often a sign of a deeper problem -// in a particular use of mutexes. -func (rw *RWMutex) TryRLock() bool { - if race.Enabled { - _ = rw.w.state - race.Disable() - } - for { - c := rw.readerCount.Load() - if c < 0 { - if race.Enabled { - race.Enable() - } - return false - } - if rw.readerCount.CompareAndSwap(c, c+1) { - if race.Enabled { - race.Enable() - race.Acquire(unsafe.Pointer(&rw.readerSem)) - } - return true - } - } -} - -// RUnlock undoes a single RLock call; -// it does not affect other simultaneous readers. -// It is a run-time error if rw is not locked for reading -// on entry to RUnlock. -func (rw *RWMutex) RUnlock() { - if race.Enabled { - _ = rw.w.state - race.ReleaseMerge(unsafe.Pointer(&rw.writerSem)) - race.Disable() - } - if r := rw.readerCount.Add(-1); r < 0 { - // Outlined slow-path to allow the fast-path to be inlined - rw.rUnlockSlow(r) - } - if race.Enabled { - race.Enable() - } -} - -func (rw *RWMutex) rUnlockSlow(r int32) { - if r+1 == 0 || r+1 == -rwmutexMaxReaders { - race.Enable() - fatal("sync: RUnlock of unlocked RWMutex") - } - // A writer is pending. - if rw.readerWait.Add(-1) == 0 { - // The last reader unblocks the writer. - runtime_Semrelease(&rw.writerSem, false, 1) - } -} - -// Lock locks rw for writing. -// If the lock is already locked for reading or writing, -// Lock blocks until the lock is available. -func (rw *RWMutex) Lock() { - if race.Enabled { - _ = rw.w.state - race.Disable() - } - // First, resolve competition with other writers. - rw.w.Lock() - // Announce to readers there is a pending writer. - r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders - // Wait for active readers. - if r != 0 && rw.readerWait.Add(r) != 0 { - runtime_SemacquireRWMutex(&rw.writerSem, false, 0) - } - if race.Enabled { - race.Enable() - race.Acquire(unsafe.Pointer(&rw.readerSem)) - race.Acquire(unsafe.Pointer(&rw.writerSem)) - } -} - -// TryLock tries to lock rw for writing and reports whether it succeeded. -// -// Note that while correct uses of TryLock do exist, they are rare, -// and use of TryLock is often a sign of a deeper problem -// in a particular use of mutexes. -func (rw *RWMutex) TryLock() bool { - if race.Enabled { - _ = rw.w.state - race.Disable() - } - if !rw.w.TryLock() { - if race.Enabled { - race.Enable() - } - return false - } - if !rw.readerCount.CompareAndSwap(0, -rwmutexMaxReaders) { - rw.w.Unlock() - if race.Enabled { - race.Enable() - } - return false - } - if race.Enabled { - race.Enable() - race.Acquire(unsafe.Pointer(&rw.readerSem)) - race.Acquire(unsafe.Pointer(&rw.writerSem)) - } - return true -} - -// Unlock unlocks rw for writing. It is a run-time error if rw is -// not locked for writing on entry to Unlock. -// -// As with Mutexes, a locked RWMutex is not associated with a particular -// goroutine. One goroutine may RLock (Lock) a RWMutex and then -// arrange for another goroutine to RUnlock (Unlock) it. -func (rw *RWMutex) Unlock() { - if race.Enabled { - _ = rw.w.state - race.Release(unsafe.Pointer(&rw.readerSem)) - race.Disable() - } - - // Announce to readers there is no active writer. - r := rw.readerCount.Add(rwmutexMaxReaders) - if r >= rwmutexMaxReaders { - race.Enable() - fatal("sync: Unlock of unlocked RWMutex") - } - // Unblock blocked readers, if any. - for i := 0; i < int(r); i++ { - runtime_Semrelease(&rw.readerSem, false, 0) - } - // Allow other writers to proceed. - rw.w.Unlock() - if race.Enabled { - race.Enable() - } -} - -// syscall_hasWaitingReaders reports whether any goroutine is waiting -// to acquire a read lock on rw. This exists because syscall.ForkLock -// is an RWMutex, and we can't change that without breaking compatibility. -// We don't need or want RWMutex semantics for ForkLock, and we use -// this private API to avoid having to change the type of ForkLock. -// For more details see the syscall package. -// -//go:linkname syscall_hasWaitingReaders syscall.hasWaitingReaders -func syscall_hasWaitingReaders(rw *RWMutex) bool { - r := rw.readerCount.Load() - return r < 0 && r+rwmutexMaxReaders > 0 -} - -// RLocker returns a Locker interface that implements -// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock. -func (rw *RWMutex) RLocker() Locker { - return (*rlocker)(rw) -} - -type rlocker RWMutex - -func (r *rlocker) Lock() { (*RWMutex)(r).RLock() } -func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() } diff --git a/contrib/go/_std_1.22/src/syscall/asan.go b/contrib/go/_std_1.22/src/syscall/asan.go deleted file mode 100644 index eff30781e4d9..000000000000 --- a/contrib/go/_std_1.22/src/syscall/asan.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build asan - -package syscall - -import ( - "runtime" - "unsafe" -) - -const asanenabled = true - -func asanRead(addr unsafe.Pointer, len int) { - runtime.ASanRead(addr, len) -} - -func asanWrite(addr unsafe.Pointer, len int) { - runtime.ASanWrite(addr, len) -} diff --git a/contrib/go/_std_1.22/src/syscall/asan0.go b/contrib/go/_std_1.22/src/syscall/asan0.go deleted file mode 100644 index 08bc44dea1c6..000000000000 --- a/contrib/go/_std_1.22/src/syscall/asan0.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !asan - -package syscall - -import ( - "unsafe" -) - -const asanenabled = false - -func asanRead(addr unsafe.Pointer, len int) { -} - -func asanWrite(addr unsafe.Pointer, len int) { -} diff --git a/contrib/go/_std_1.22/src/syscall/dir_plan9.go b/contrib/go/_std_1.22/src/syscall/dir_plan9.go deleted file mode 100644 index 1667cbc02f49..000000000000 --- a/contrib/go/_std_1.22/src/syscall/dir_plan9.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Plan 9 directory marshaling. See intro(5). - -package syscall - -import "errors" - -var ( - ErrShortStat = errors.New("stat buffer too short") - ErrBadStat = errors.New("malformed stat buffer") - ErrBadName = errors.New("bad character in file name") -) - -// A Qid represents a 9P server's unique identification for a file. -type Qid struct { - Path uint64 // the file server's unique identification for the file - Vers uint32 // version number for given Path - Type uint8 // the type of the file (syscall.QTDIR for example) -} - -// A Dir contains the metadata for a file. -type Dir struct { - // system-modified data - Type uint16 // server type - Dev uint32 // server subtype - - // file data - Qid Qid // unique id from server - Mode uint32 // permissions - Atime uint32 // last read time - Mtime uint32 // last write time - Length int64 // file length - Name string // last element of path - Uid string // owner name - Gid string // group name - Muid string // last modifier name -} - -var nullDir = Dir{ - Type: ^uint16(0), - Dev: ^uint32(0), - Qid: Qid{ - Path: ^uint64(0), - Vers: ^uint32(0), - Type: ^uint8(0), - }, - Mode: ^uint32(0), - Atime: ^uint32(0), - Mtime: ^uint32(0), - Length: ^int64(0), -} - -// Null assigns special "don't touch" values to members of d to -// avoid modifying them during syscall.Wstat. -func (d *Dir) Null() { *d = nullDir } - -// Marshal encodes a 9P stat message corresponding to d into b -// -// If there isn't enough space in b for a stat message, ErrShortStat is returned. -func (d *Dir) Marshal(b []byte) (n int, err error) { - n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid) - if n > len(b) { - return n, ErrShortStat - } - - for _, c := range d.Name { - if c == '/' { - return n, ErrBadName - } - } - - b = pbit16(b, uint16(n)-2) - b = pbit16(b, d.Type) - b = pbit32(b, d.Dev) - b = pbit8(b, d.Qid.Type) - b = pbit32(b, d.Qid.Vers) - b = pbit64(b, d.Qid.Path) - b = pbit32(b, d.Mode) - b = pbit32(b, d.Atime) - b = pbit32(b, d.Mtime) - b = pbit64(b, uint64(d.Length)) - b = pstring(b, d.Name) - b = pstring(b, d.Uid) - b = pstring(b, d.Gid) - b = pstring(b, d.Muid) - - return n, nil -} - -// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir. -// -// If b is too small to hold a valid stat message, ErrShortStat is returned. -// -// If the stat message itself is invalid, ErrBadStat is returned. -func UnmarshalDir(b []byte) (*Dir, error) { - if len(b) < STATFIXLEN { - return nil, ErrShortStat - } - size, buf := gbit16(b) - if len(b) != int(size)+2 { - return nil, ErrBadStat - } - b = buf - - var d Dir - d.Type, b = gbit16(b) - d.Dev, b = gbit32(b) - d.Qid.Type, b = gbit8(b) - d.Qid.Vers, b = gbit32(b) - d.Qid.Path, b = gbit64(b) - d.Mode, b = gbit32(b) - d.Atime, b = gbit32(b) - d.Mtime, b = gbit32(b) - - n, b := gbit64(b) - d.Length = int64(n) - - var ok bool - if d.Name, b, ok = gstring(b); !ok { - return nil, ErrBadStat - } - if d.Uid, b, ok = gstring(b); !ok { - return nil, ErrBadStat - } - if d.Gid, b, ok = gstring(b); !ok { - return nil, ErrBadStat - } - if d.Muid, b, ok = gstring(b); !ok { - return nil, ErrBadStat - } - - return &d, nil -} - -// pbit8 copies the 8-bit number v to b and returns the remaining slice of b. -func pbit8(b []byte, v uint8) []byte { - b[0] = byte(v) - return b[1:] -} - -// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b. -func pbit16(b []byte, v uint16) []byte { - b[0] = byte(v) - b[1] = byte(v >> 8) - return b[2:] -} - -// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b. -func pbit32(b []byte, v uint32) []byte { - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) - return b[4:] -} - -// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b. -func pbit64(b []byte, v uint64) []byte { - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) - b[4] = byte(v >> 32) - b[5] = byte(v >> 40) - b[6] = byte(v >> 48) - b[7] = byte(v >> 56) - return b[8:] -} - -// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and -// returning the remaining slice of b.. -func pstring(b []byte, s string) []byte { - b = pbit16(b, uint16(len(s))) - n := copy(b, s) - return b[n:] -} - -// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b. -func gbit8(b []byte) (uint8, []byte) { - return uint8(b[0]), b[1:] -} - -// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b. -// -//go:nosplit -func gbit16(b []byte) (uint16, []byte) { - return uint16(b[0]) | uint16(b[1])<<8, b[2:] -} - -// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b. -func gbit32(b []byte) (uint32, []byte) { - return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:] -} - -// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b. -func gbit64(b []byte) (uint64, []byte) { - lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24 - return uint64(lo) | uint64(hi)<<32, b[8:] -} - -// gstring reads a string from b, prefixed with a 16-bit length in little-endian order. -// It returns the string with the remaining slice of b and a boolean. If the length is -// greater than the number of bytes in b, the boolean will be false. -func gstring(b []byte) (string, []byte, bool) { - n, b := gbit16(b) - if int(n) > len(b) { - return "", b, false - } - return string(b[:n]), b[n:], true -} diff --git a/contrib/go/_std_1.22/src/syscall/dirent.go b/contrib/go/_std_1.22/src/syscall/dirent.go deleted file mode 100644 index 1a0f1eec11bf..000000000000 --- a/contrib/go/_std_1.22/src/syscall/dirent.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix || (js && wasm) || wasip1 - -package syscall - -import ( - "runtime" - "unsafe" -) - -// readInt returns the size-bytes unsigned integer in native byte order at offset off. -func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { - if len(b) < int(off+size) { - return 0, false - } - if isBigEndian { - return readIntBE(b[off:], size), true - } - return readIntLE(b[off:], size), true -} - -func readIntBE(b []byte, size uintptr) uint64 { - switch size { - case 1: - return uint64(b[0]) - case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[1]) | uint64(b[0])<<8 - case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 - case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 - default: - panic("syscall: readInt with unsupported size") - } -} - -func readIntLE(b []byte, size uintptr) uint64 { - switch size { - case 1: - return uint64(b[0]) - case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 - case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 - case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 - default: - panic("syscall: readInt with unsupported size") - } -} - -// ParseDirent parses up to max directory entries in buf, -// appending the names to names. It returns the number of -// bytes consumed from buf, the number of entries added -// to names, and the new names slice. -func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { - origlen := len(buf) - count = 0 - for max != 0 && len(buf) > 0 { - reclen, ok := direntReclen(buf) - if !ok || reclen > uint64(len(buf)) { - return origlen, count, names - } - rec := buf[:reclen] - buf = buf[reclen:] - ino, ok := direntIno(rec) - if !ok { - break - } - // See src/os/dir_unix.go for the reason why this condition is - // excluded on wasip1. - if ino == 0 && runtime.GOOS != "wasip1" { // File absent in directory. - continue - } - const namoff = uint64(unsafe.Offsetof(Dirent{}.Name)) - namlen, ok := direntNamlen(rec) - if !ok || namoff+namlen > uint64(len(rec)) { - break - } - name := rec[namoff : namoff+namlen] - for i, c := range name { - if c == 0 { - name = name[:i] - break - } - } - // Check for useless names before allocating a string. - if string(name) == "." || string(name) == ".." { - continue - } - max-- - count++ - names = append(names, string(name)) - } - return origlen - len(buf), count, names -} diff --git a/contrib/go/_std_1.22/src/syscall/endian_big.go b/contrib/go/_std_1.22/src/syscall/endian_big.go deleted file mode 100644 index 8e3874eb8630..000000000000 --- a/contrib/go/_std_1.22/src/syscall/endian_big.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -//go:build ppc64 || s390x || mips || mips64 - -package syscall - -const isBigEndian = true diff --git a/contrib/go/_std_1.22/src/syscall/endian_little.go b/contrib/go/_std_1.22/src/syscall/endian_little.go deleted file mode 100644 index f5fcb58db4e4..000000000000 --- a/contrib/go/_std_1.22/src/syscall/endian_little.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -//go:build 386 || amd64 || arm || arm64 || loong64 || ppc64le || mips64le || mipsle || riscv64 || wasm - -package syscall - -const isBigEndian = false diff --git a/contrib/go/_std_1.22/src/syscall/exec_linux.go b/contrib/go/_std_1.22/src/syscall/exec_linux.go deleted file mode 100644 index e6d6343ed889..000000000000 --- a/contrib/go/_std_1.22/src/syscall/exec_linux.go +++ /dev/null @@ -1,733 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux - -package syscall - -import ( - "internal/itoa" - "runtime" - "unsafe" -) - -// Linux unshare/clone/clone2/clone3 flags, architecture-independent, -// copied from linux/sched.h. -const ( - CLONE_VM = 0x00000100 // set if VM shared between processes - CLONE_FS = 0x00000200 // set if fs info shared between processes - CLONE_FILES = 0x00000400 // set if open files shared between processes - CLONE_SIGHAND = 0x00000800 // set if signal handlers and blocked signals shared - CLONE_PIDFD = 0x00001000 // set if a pidfd should be placed in parent - CLONE_PTRACE = 0x00002000 // set if we want to let tracing continue on the child too - CLONE_VFORK = 0x00004000 // set if the parent wants the child to wake it up on mm_release - CLONE_PARENT = 0x00008000 // set if we want to have the same parent as the cloner - CLONE_THREAD = 0x00010000 // Same thread group? - CLONE_NEWNS = 0x00020000 // New mount namespace group - CLONE_SYSVSEM = 0x00040000 // share system V SEM_UNDO semantics - CLONE_SETTLS = 0x00080000 // create a new TLS for the child - CLONE_PARENT_SETTID = 0x00100000 // set the TID in the parent - CLONE_CHILD_CLEARTID = 0x00200000 // clear the TID in the child - CLONE_DETACHED = 0x00400000 // Unused, ignored - CLONE_UNTRACED = 0x00800000 // set if the tracing process can't force CLONE_PTRACE on this clone - CLONE_CHILD_SETTID = 0x01000000 // set the TID in the child - CLONE_NEWCGROUP = 0x02000000 // New cgroup namespace - CLONE_NEWUTS = 0x04000000 // New utsname namespace - CLONE_NEWIPC = 0x08000000 // New ipc namespace - CLONE_NEWUSER = 0x10000000 // New user namespace - CLONE_NEWPID = 0x20000000 // New pid namespace - CLONE_NEWNET = 0x40000000 // New network namespace - CLONE_IO = 0x80000000 // Clone io context - - // Flags for the clone3() syscall. - - CLONE_CLEAR_SIGHAND = 0x100000000 // Clear any signal handler and reset to SIG_DFL. - CLONE_INTO_CGROUP = 0x200000000 // Clone into a specific cgroup given the right permissions. - - // Cloning flags intersect with CSIGNAL so can be used with unshare and clone3 - // syscalls only: - - CLONE_NEWTIME = 0x00000080 // New time namespace -) - -// SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux. -// See user_namespaces(7). -type SysProcIDMap struct { - ContainerID int // Container ID. - HostID int // Host ID. - Size int // Size. -} - -type SysProcAttr struct { - Chroot string // Chroot. - Credential *Credential // Credential. - // Ptrace tells the child to call ptrace(PTRACE_TRACEME). - // Call runtime.LockOSThread before starting a process with this set, - // and don't call UnlockOSThread until done with PtraceSyscall calls. - Ptrace bool - Setsid bool // Create session. - // Setpgid sets the process group ID of the child to Pgid, - // or, if Pgid == 0, to the new child's process ID. - Setpgid bool - // Setctty sets the controlling terminal of the child to - // file descriptor Ctty. Ctty must be a descriptor number - // in the child process: an index into ProcAttr.Files. - // This is only meaningful if Setsid is true. - Setctty bool - Noctty bool // Detach fd 0 from controlling terminal. - Ctty int // Controlling TTY fd. - // Foreground places the child process group in the foreground. - // This implies Setpgid. The Ctty field must be set to - // the descriptor of the controlling TTY. - // Unlike Setctty, in this case Ctty must be a descriptor - // number in the parent process. - Foreground bool - Pgid int // Child's process group ID if Setpgid. - // Pdeathsig, if non-zero, is a signal that the kernel will send to - // the child process when the creating thread dies. Note that the signal - // is sent on thread termination, which may happen before process termination. - // There are more details at https://go.dev/issue/27505. - Pdeathsig Signal - Cloneflags uintptr // Flags for clone calls. - Unshareflags uintptr // Flags for unshare calls. - UidMappings []SysProcIDMap // User ID mappings for user namespaces. - GidMappings []SysProcIDMap // Group ID mappings for user namespaces. - // GidMappingsEnableSetgroups enabling setgroups syscall. - // If false, then setgroups syscall will be disabled for the child process. - // This parameter is no-op if GidMappings == nil. Otherwise for unprivileged - // users this should be set to false for mappings work. - GidMappingsEnableSetgroups bool - AmbientCaps []uintptr // Ambient capabilities. - UseCgroupFD bool // Whether to make use of the CgroupFD field. - CgroupFD int // File descriptor of a cgroup to put the new process into. - // PidFD, if not nil, is used to store the pidfd of a child, if the - // functionality is supported by the kernel, or -1. Note *PidFD is - // changed only if the process starts successfully. - PidFD *int -} - -var ( - none = [...]byte{'n', 'o', 'n', 'e', 0} - slash = [...]byte{'/', 0} - - forceClone3 = false // Used by unit tests only. -) - -// Implemented in runtime package. -func runtime_BeforeFork() -func runtime_AfterFork() -func runtime_AfterForkInChild() - -// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. -// If a dup or exec fails, write the errno error to pipe. -// (Pipe is close-on-exec so if exec succeeds, it will be closed.) -// In the child, this function must not acquire any locks, because -// they might have been locked at the time of the fork. This means -// no rescheduling, no malloc calls, and no new stack segments. -// For the same reason compiler does not race instrument it. -// The calls to RawSyscall are okay because they are assembly -// functions that do not grow the stack. -// -//go:norace -func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { - // Set up and fork. This returns immediately in the parent or - // if there's an error. - upid, pidfd, err, mapPipe, locked := forkAndExecInChild1(argv0, argv, envv, chroot, dir, attr, sys, pipe) - if locked { - runtime_AfterFork() - } - if err != 0 { - return 0, err - } - - // parent; return PID - pid = int(upid) - if sys.PidFD != nil { - *sys.PidFD = int(pidfd) - } - - if sys.UidMappings != nil || sys.GidMappings != nil { - Close(mapPipe[0]) - var err2 Errno - // uid/gid mappings will be written after fork and unshare(2) for user - // namespaces. - if sys.Unshareflags&CLONE_NEWUSER == 0 { - if err := writeUidGidMappings(pid, sys); err != nil { - err2 = err.(Errno) - } - } - RawSyscall(SYS_WRITE, uintptr(mapPipe[1]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) - Close(mapPipe[1]) - } - - return pid, 0 -} - -const _LINUX_CAPABILITY_VERSION_3 = 0x20080522 - -type capHeader struct { - version uint32 - pid int32 -} - -type capData struct { - effective uint32 - permitted uint32 - inheritable uint32 -} -type caps struct { - hdr capHeader - data [2]capData -} - -// See CAP_TO_INDEX in linux/capability.h: -func capToIndex(cap uintptr) uintptr { return cap >> 5 } - -// See CAP_TO_MASK in linux/capability.h: -func capToMask(cap uintptr) uint32 { return 1 << uint(cap&31) } - -// cloneArgs holds arguments for clone3 Linux syscall. -type cloneArgs struct { - flags uint64 // Flags bit mask - pidFD uint64 // Where to store PID file descriptor (int *) - childTID uint64 // Where to store child TID, in child's memory (pid_t *) - parentTID uint64 // Where to store child TID, in parent's memory (pid_t *) - exitSignal uint64 // Signal to deliver to parent on child termination - stack uint64 // Pointer to lowest byte of stack - stackSize uint64 // Size of stack - tls uint64 // Location of new TLS - setTID uint64 // Pointer to a pid_t array (since Linux 5.5) - setTIDSize uint64 // Number of elements in set_tid (since Linux 5.5) - cgroup uint64 // File descriptor for target cgroup of child (since Linux 5.7) -} - -// forkAndExecInChild1 implements the body of forkAndExecInChild up to -// the parent's post-fork path. This is a separate function so we can -// separate the child's and parent's stack frames if we're using -// vfork. -// -// This is go:noinline because the point is to keep the stack frames -// of this and forkAndExecInChild separate. -// -//go:noinline -//go:norace -//go:nocheckptr -func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid uintptr, pidfd int32, err1 Errno, mapPipe [2]int, locked bool) { - // Defined in linux/prctl.h starting with Linux 4.3. - const ( - PR_CAP_AMBIENT = 0x2f - PR_CAP_AMBIENT_RAISE = 0x2 - ) - - // vfork requires that the child not touch any of the parent's - // active stack frames. Hence, the child does all post-fork - // processing in this stack frame and never returns, while the - // parent returns immediately from this frame and does all - // post-fork processing in the outer frame. - // - // Declare all variables at top in case any - // declarations require heap allocation (e.g., err2). - // ":=" should not be used to declare any variable after - // the call to runtime_BeforeFork. - // - // NOTE(bcmills): The allocation behavior described in the above comment - // seems to lack a corresponding test, and it may be rendered invalid - // by an otherwise-correct change in the compiler. - var ( - err2 Errno - nextfd int - i int - caps caps - fd1, flags uintptr - puid, psetgroups, pgid []byte - uidmap, setgroups, gidmap []byte - clone3 *cloneArgs - pgrp int32 - dirfd int - cred *Credential - ngroups, groups uintptr - c uintptr - ) - pidfd = -1 - - rlim := origRlimitNofile.Load() - - if sys.UidMappings != nil { - puid = []byte("/proc/self/uid_map\000") - uidmap = formatIDMappings(sys.UidMappings) - } - - if sys.GidMappings != nil { - psetgroups = []byte("/proc/self/setgroups\000") - pgid = []byte("/proc/self/gid_map\000") - - if sys.GidMappingsEnableSetgroups { - setgroups = []byte("allow\000") - } else { - setgroups = []byte("deny\000") - } - gidmap = formatIDMappings(sys.GidMappings) - } - - // Record parent PID so child can test if it has died. - ppid, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0) - - // Guard against side effects of shuffling fds below. - // Make sure that nextfd is beyond any currently open files so - // that we can't run the risk of overwriting any of them. - fd := make([]int, len(attr.Files)) - nextfd = len(attr.Files) - for i, ufd := range attr.Files { - if nextfd < int(ufd) { - nextfd = int(ufd) - } - fd[i] = int(ufd) - } - nextfd++ - - // Allocate another pipe for parent to child communication for - // synchronizing writing of User ID/Group ID mappings. - if sys.UidMappings != nil || sys.GidMappings != nil { - if err := forkExecPipe(mapPipe[:]); err != nil { - err1 = err.(Errno) - return - } - } - - flags = sys.Cloneflags - if sys.Cloneflags&CLONE_NEWUSER == 0 && sys.Unshareflags&CLONE_NEWUSER == 0 { - flags |= CLONE_VFORK | CLONE_VM - } - if sys.PidFD != nil { - flags |= CLONE_PIDFD - } - // Whether to use clone3. - if sys.UseCgroupFD || flags&CLONE_NEWTIME != 0 || forceClone3 { - clone3 = &cloneArgs{ - flags: uint64(flags), - exitSignal: uint64(SIGCHLD), - } - if sys.UseCgroupFD { - clone3.flags |= CLONE_INTO_CGROUP - clone3.cgroup = uint64(sys.CgroupFD) - } - if sys.PidFD != nil { - clone3.pidFD = uint64(uintptr(unsafe.Pointer(&pidfd))) - } - } - - // About to call fork. - // No more allocation or calls of non-assembly functions. - runtime_BeforeFork() - locked = true - if clone3 != nil { - pid, err1 = rawVforkSyscall(_SYS_clone3, uintptr(unsafe.Pointer(clone3)), unsafe.Sizeof(*clone3), 0) - } else { - flags |= uintptr(SIGCHLD) - if runtime.GOARCH == "s390x" { - // On Linux/s390, the first two arguments of clone(2) are swapped. - pid, err1 = rawVforkSyscall(SYS_CLONE, 0, flags, uintptr(unsafe.Pointer(&pidfd))) - } else { - pid, err1 = rawVforkSyscall(SYS_CLONE, flags, 0, uintptr(unsafe.Pointer(&pidfd))) - } - } - if err1 != 0 || pid != 0 { - // If we're in the parent, we must return immediately - // so we're not in the same stack frame as the child. - // This can at most use the return PC, which the child - // will not modify, and the results of - // rawVforkSyscall, which must have been written after - // the child was replaced. - return - } - - // Fork succeeded, now in child. - - // Enable the "keep capabilities" flag to set ambient capabilities later. - if len(sys.AmbientCaps) > 0 { - _, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_KEEPCAPS, 1, 0, 0, 0, 0) - if err1 != 0 { - goto childerror - } - } - - // Wait for User ID/Group ID mappings to be written. - if sys.UidMappings != nil || sys.GidMappings != nil { - if _, _, err1 = RawSyscall(SYS_CLOSE, uintptr(mapPipe[1]), 0, 0); err1 != 0 { - goto childerror - } - pid, _, err1 = RawSyscall(SYS_READ, uintptr(mapPipe[0]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) - if err1 != 0 { - goto childerror - } - if pid != unsafe.Sizeof(err2) { - err1 = EINVAL - goto childerror - } - if err2 != 0 { - err1 = err2 - goto childerror - } - } - - // Session ID - if sys.Setsid { - _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0) - if err1 != 0 { - goto childerror - } - } - - // Set process group - if sys.Setpgid || sys.Foreground { - // Place child in process group. - _, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0) - if err1 != 0 { - goto childerror - } - } - - if sys.Foreground { - pgrp = int32(sys.Pgid) - if pgrp == 0 { - pid, _ = rawSyscallNoError(SYS_GETPID, 0, 0, 0) - - pgrp = int32(pid) - } - - // Place process group in foreground. - _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp))) - if err1 != 0 { - goto childerror - } - } - - // Restore the signal mask. We do this after TIOCSPGRP to avoid - // having the kernel send a SIGTTOU signal to the process group. - runtime_AfterForkInChild() - - // Unshare - if sys.Unshareflags != 0 { - _, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshareflags, 0, 0) - if err1 != 0 { - goto childerror - } - - if sys.Unshareflags&CLONE_NEWUSER != 0 && sys.GidMappings != nil { - dirfd = int(_AT_FDCWD) - if fd1, _, err1 = RawSyscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(&psetgroups[0])), uintptr(O_WRONLY), 0, 0, 0); err1 != 0 { - goto childerror - } - pid, _, err1 = RawSyscall(SYS_WRITE, fd1, uintptr(unsafe.Pointer(&setgroups[0])), uintptr(len(setgroups))) - if err1 != 0 { - goto childerror - } - if _, _, err1 = RawSyscall(SYS_CLOSE, fd1, 0, 0); err1 != 0 { - goto childerror - } - - if fd1, _, err1 = RawSyscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(&pgid[0])), uintptr(O_WRONLY), 0, 0, 0); err1 != 0 { - goto childerror - } - pid, _, err1 = RawSyscall(SYS_WRITE, fd1, uintptr(unsafe.Pointer(&gidmap[0])), uintptr(len(gidmap))) - if err1 != 0 { - goto childerror - } - if _, _, err1 = RawSyscall(SYS_CLOSE, fd1, 0, 0); err1 != 0 { - goto childerror - } - } - - if sys.Unshareflags&CLONE_NEWUSER != 0 && sys.UidMappings != nil { - dirfd = int(_AT_FDCWD) - if fd1, _, err1 = RawSyscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(&puid[0])), uintptr(O_WRONLY), 0, 0, 0); err1 != 0 { - goto childerror - } - pid, _, err1 = RawSyscall(SYS_WRITE, fd1, uintptr(unsafe.Pointer(&uidmap[0])), uintptr(len(uidmap))) - if err1 != 0 { - goto childerror - } - if _, _, err1 = RawSyscall(SYS_CLOSE, fd1, 0, 0); err1 != 0 { - goto childerror - } - } - - // The unshare system call in Linux doesn't unshare mount points - // mounted with --shared. Systemd mounts / with --shared. For a - // long discussion of the pros and cons of this see debian bug 739593. - // The Go model of unsharing is more like Plan 9, where you ask - // to unshare and the namespaces are unconditionally unshared. - // To make this model work we must further mark / as MS_PRIVATE. - // This is what the standard unshare command does. - if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS { - _, _, err1 = RawSyscall6(SYS_MOUNT, uintptr(unsafe.Pointer(&none[0])), uintptr(unsafe.Pointer(&slash[0])), 0, MS_REC|MS_PRIVATE, 0, 0) - if err1 != 0 { - goto childerror - } - } - } - - // Chroot - if chroot != nil { - _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0) - if err1 != 0 { - goto childerror - } - } - - // User and groups - if cred = sys.Credential; cred != nil { - ngroups = uintptr(len(cred.Groups)) - groups = uintptr(0) - if ngroups > 0 { - groups = uintptr(unsafe.Pointer(&cred.Groups[0])) - } - if !(sys.GidMappings != nil && !sys.GidMappingsEnableSetgroups && ngroups == 0) && !cred.NoSetGroups { - _, _, err1 = RawSyscall(_SYS_setgroups, ngroups, groups, 0) - if err1 != 0 { - goto childerror - } - } - _, _, err1 = RawSyscall(sys_SETGID, uintptr(cred.Gid), 0, 0) - if err1 != 0 { - goto childerror - } - _, _, err1 = RawSyscall(sys_SETUID, uintptr(cred.Uid), 0, 0) - if err1 != 0 { - goto childerror - } - } - - if len(sys.AmbientCaps) != 0 { - // Ambient capabilities were added in the 4.3 kernel, - // so it is safe to always use _LINUX_CAPABILITY_VERSION_3. - caps.hdr.version = _LINUX_CAPABILITY_VERSION_3 - - if _, _, err1 = RawSyscall(SYS_CAPGET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); err1 != 0 { - goto childerror - } - - for _, c = range sys.AmbientCaps { - // Add the c capability to the permitted and inheritable capability mask, - // otherwise we will not be able to add it to the ambient capability mask. - caps.data[capToIndex(c)].permitted |= capToMask(c) - caps.data[capToIndex(c)].inheritable |= capToMask(c) - } - - if _, _, err1 = RawSyscall(SYS_CAPSET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); err1 != 0 { - goto childerror - } - - for _, c = range sys.AmbientCaps { - _, _, err1 = RawSyscall6(SYS_PRCTL, PR_CAP_AMBIENT, uintptr(PR_CAP_AMBIENT_RAISE), c, 0, 0, 0) - if err1 != 0 { - goto childerror - } - } - } - - // Chdir - if dir != nil { - _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0) - if err1 != 0 { - goto childerror - } - } - - // Parent death signal - if sys.Pdeathsig != 0 { - _, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0) - if err1 != 0 { - goto childerror - } - - // Signal self if parent is already dead. This might cause a - // duplicate signal in rare cases, but it won't matter when - // using SIGKILL. - pid, _ = rawSyscallNoError(SYS_GETPPID, 0, 0, 0) - if pid != ppid { - pid, _ = rawSyscallNoError(SYS_GETPID, 0, 0, 0) - _, _, err1 = RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0) - if err1 != 0 { - goto childerror - } - } - } - - // Pass 1: look for fd[i] < i and move those up above len(fd) - // so that pass 2 won't stomp on an fd it needs later. - if pipe < nextfd { - _, _, err1 = RawSyscall(SYS_DUP3, uintptr(pipe), uintptr(nextfd), O_CLOEXEC) - if err1 != 0 { - goto childerror - } - pipe = nextfd - nextfd++ - } - for i = 0; i < len(fd); i++ { - if fd[i] >= 0 && fd[i] < i { - if nextfd == pipe { // don't stomp on pipe - nextfd++ - } - _, _, err1 = RawSyscall(SYS_DUP3, uintptr(fd[i]), uintptr(nextfd), O_CLOEXEC) - if err1 != 0 { - goto childerror - } - fd[i] = nextfd - nextfd++ - } - } - - // Pass 2: dup fd[i] down onto i. - for i = 0; i < len(fd); i++ { - if fd[i] == -1 { - RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) - continue - } - if fd[i] == i { - // dup2(i, i) won't clear close-on-exec flag on Linux, - // probably not elsewhere either. - _, _, err1 = RawSyscall(fcntl64Syscall, uintptr(fd[i]), F_SETFD, 0) - if err1 != 0 { - goto childerror - } - continue - } - // The new fd is created NOT close-on-exec, - // which is exactly what we want. - _, _, err1 = RawSyscall(SYS_DUP3, uintptr(fd[i]), uintptr(i), 0) - if err1 != 0 { - goto childerror - } - } - - // By convention, we don't close-on-exec the fds we are - // started with, so if len(fd) < 3, close 0, 1, 2 as needed. - // Programs that know they inherit fds >= 3 will need - // to set them close-on-exec. - for i = len(fd); i < 3; i++ { - RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) - } - - // Detach fd 0 from tty - if sys.Noctty { - _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0) - if err1 != 0 { - goto childerror - } - } - - // Set the controlling TTY to Ctty - if sys.Setctty { - _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 1) - if err1 != 0 { - goto childerror - } - } - - // Restore original rlimit. - if rlim != nil { - rawSetrlimit(RLIMIT_NOFILE, rlim) - } - - // Enable tracing if requested. - // Do this right before exec so that we don't unnecessarily trace the runtime - // setting up after the fork. See issue #21428. - if sys.Ptrace { - _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0) - if err1 != 0 { - goto childerror - } - } - - // Time to exec. - _, _, err1 = RawSyscall(SYS_EXECVE, - uintptr(unsafe.Pointer(argv0)), - uintptr(unsafe.Pointer(&argv[0])), - uintptr(unsafe.Pointer(&envv[0]))) - -childerror: - // send error code on pipe - RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) - for { - RawSyscall(SYS_EXIT, 253, 0, 0) - } -} - -func formatIDMappings(idMap []SysProcIDMap) []byte { - var data []byte - for _, im := range idMap { - data = append(data, itoa.Itoa(im.ContainerID)+" "+itoa.Itoa(im.HostID)+" "+itoa.Itoa(im.Size)+"\n"...) - } - return data -} - -// writeIDMappings writes the user namespace User ID or Group ID mappings to the specified path. -func writeIDMappings(path string, idMap []SysProcIDMap) error { - fd, err := Open(path, O_RDWR, 0) - if err != nil { - return err - } - - if _, err := Write(fd, formatIDMappings(idMap)); err != nil { - Close(fd) - return err - } - - if err := Close(fd); err != nil { - return err - } - - return nil -} - -// writeSetgroups writes to /proc/PID/setgroups "deny" if enable is false -// and "allow" if enable is true. -// This is needed since kernel 3.19, because you can't write gid_map without -// disabling setgroups() system call. -func writeSetgroups(pid int, enable bool) error { - sgf := "/proc/" + itoa.Itoa(pid) + "/setgroups" - fd, err := Open(sgf, O_RDWR, 0) - if err != nil { - return err - } - - var data []byte - if enable { - data = []byte("allow") - } else { - data = []byte("deny") - } - - if _, err := Write(fd, data); err != nil { - Close(fd) - return err - } - - return Close(fd) -} - -// writeUidGidMappings writes User ID and Group ID mappings for user namespaces -// for a process and it is called from the parent process. -func writeUidGidMappings(pid int, sys *SysProcAttr) error { - if sys.UidMappings != nil { - uidf := "/proc/" + itoa.Itoa(pid) + "/uid_map" - if err := writeIDMappings(uidf, sys.UidMappings); err != nil { - return err - } - } - - if sys.GidMappings != nil { - // If the kernel is too old to support /proc/PID/setgroups, writeSetGroups will return ENOENT; this is OK. - if err := writeSetgroups(pid, sys.GidMappingsEnableSetgroups); err != nil && err != ENOENT { - return err - } - gidf := "/proc/" + itoa.Itoa(pid) + "/gid_map" - if err := writeIDMappings(gidf, sys.GidMappings); err != nil { - return err - } - } - - return nil -} diff --git a/contrib/go/_std_1.22/src/syscall/exec_plan9.go b/contrib/go/_std_1.22/src/syscall/exec_plan9.go deleted file mode 100644 index 8762237825c7..000000000000 --- a/contrib/go/_std_1.22/src/syscall/exec_plan9.go +++ /dev/null @@ -1,611 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Fork, exec, wait, etc. - -package syscall - -import ( - "internal/itoa" - "runtime" - "sync" - "unsafe" -) - -// ForkLock is not used on plan9. -var ForkLock sync.RWMutex - -// gstringb reads a non-empty string from b, prefixed with a 16-bit length in little-endian order. -// It returns the string as a byte slice, or nil if b is too short to contain the length or -// the full string. -// -//go:nosplit -func gstringb(b []byte) []byte { - if len(b) < 2 { - return nil - } - n, b := gbit16(b) - if int(n) > len(b) { - return nil - } - return b[:n] -} - -// Offset of the name field in a 9P directory entry - see UnmarshalDir() in dir_plan9.go -const nameOffset = 39 - -// gdirname returns the first filename from a buffer of directory entries, -// and a slice containing the remaining directory entries. -// If the buffer doesn't start with a valid directory entry, the returned name is nil. -// -//go:nosplit -func gdirname(buf []byte) (name []byte, rest []byte) { - if len(buf) < 2 { - return - } - size, buf := gbit16(buf) - if size < STATFIXLEN || int(size) > len(buf) { - return - } - name = gstringb(buf[nameOffset:size]) - rest = buf[size:] - return -} - -// StringSlicePtr converts a slice of strings to a slice of pointers -// to NUL-terminated byte arrays. If any string contains a NUL byte -// this function panics instead of returning an error. -// -// Deprecated: Use SlicePtrFromStrings instead. -func StringSlicePtr(ss []string) []*byte { - bb := make([]*byte, len(ss)+1) - for i := 0; i < len(ss); i++ { - bb[i] = StringBytePtr(ss[i]) - } - bb[len(ss)] = nil - return bb -} - -// SlicePtrFromStrings converts a slice of strings to a slice of -// pointers to NUL-terminated byte arrays. If any string contains -// a NUL byte, it returns (nil, EINVAL). -func SlicePtrFromStrings(ss []string) ([]*byte, error) { - var err error - bb := make([]*byte, len(ss)+1) - for i := 0; i < len(ss); i++ { - bb[i], err = BytePtrFromString(ss[i]) - if err != nil { - return nil, err - } - } - bb[len(ss)] = nil - return bb, nil -} - -// readdirnames returns the names of files inside the directory represented by dirfd. -func readdirnames(dirfd int) (names []string, err error) { - names = make([]string, 0, 100) - var buf [STATMAX]byte - - for { - n, e := Read(dirfd, buf[:]) - if e != nil { - return nil, e - } - if n == 0 { - break - } - for b := buf[:n]; len(b) > 0; { - var s []byte - s, b = gdirname(b) - if s == nil { - return nil, ErrBadStat - } - names = append(names, string(s)) - } - } - return -} - -// name of the directory containing names and control files for all open file descriptors -var dupdev, _ = BytePtrFromString("#d") - -// forkAndExecInChild forks the process, calling dup onto 0..len(fd) -// and finally invoking exec(argv0, argvv, envv) in the child. -// If a dup or exec fails, it writes the error string to pipe. -// (The pipe write end is close-on-exec so if exec succeeds, it will be closed.) -// -// In the child, this function must not acquire any locks, because -// they might have been locked at the time of the fork. This means -// no rescheduling, no malloc calls, and no new stack segments. -// The calls to RawSyscall are okay because they are assembly -// functions that do not grow the stack. -// -//go:norace -func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, pipe int, rflag int) (pid int, err error) { - // Declare all variables at top in case any - // declarations require heap allocation (e.g., errbuf). - var ( - r1 uintptr - nextfd int - i int - clearenv int - envfd int - errbuf [ERRMAX]byte - statbuf [STATMAX]byte - dupdevfd int - n int - b []byte - ) - - // Guard against side effects of shuffling fds below. - // Make sure that nextfd is beyond any currently open files so - // that we can't run the risk of overwriting any of them. - fd := make([]int, len(attr.Files)) - nextfd = len(attr.Files) - for i, ufd := range attr.Files { - if nextfd < int(ufd) { - nextfd = int(ufd) - } - fd[i] = int(ufd) - } - nextfd++ - - if envv != nil { - clearenv = RFCENVG - } - - // About to call fork. - // No more allocation or calls of non-assembly functions. - r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv|rflag), 0, 0) - - if r1 != 0 { - if int32(r1) == -1 { - return 0, NewError(errstr()) - } - // parent; return PID - return int(r1), nil - } - - // Fork succeeded, now in child. - - // Close fds we don't need. - r1, _, _ = RawSyscall(SYS_OPEN, uintptr(unsafe.Pointer(dupdev)), uintptr(O_RDONLY), 0) - dupdevfd = int(r1) - if dupdevfd == -1 { - goto childerror - } -dirloop: - for { - r1, _, _ = RawSyscall6(SYS_PREAD, uintptr(dupdevfd), uintptr(unsafe.Pointer(&statbuf[0])), uintptr(len(statbuf)), ^uintptr(0), ^uintptr(0), 0) - n = int(r1) - switch n { - case -1: - goto childerror - case 0: - break dirloop - } - for b = statbuf[:n]; len(b) > 0; { - var s []byte - s, b = gdirname(b) - if s == nil { - copy(errbuf[:], ErrBadStat.Error()) - goto childerror1 - } - if s[len(s)-1] == 'l' { - // control file for descriptor is named ctl - continue - } - closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd) - } - } - RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0) - - // Write new environment variables. - if envv != nil { - for i = 0; i < len(envv); i++ { - r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666)) - - if int32(r1) == -1 { - goto childerror - } - - envfd = int(r1) - - r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintptr(unsafe.Pointer(envv[i].value)), uintptr(envv[i].nvalue), - ^uintptr(0), ^uintptr(0), 0) - - if int32(r1) == -1 || int(r1) != envv[i].nvalue { - goto childerror - } - - r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0) - - if int32(r1) == -1 { - goto childerror - } - } - } - - // Chdir - if dir != nil { - r1, _, _ = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0) - if int32(r1) == -1 { - goto childerror - } - } - - // Pass 1: look for fd[i] < i and move those up above len(fd) - // so that pass 2 won't stomp on an fd it needs later. - if pipe < nextfd { - r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0) - if int32(r1) == -1 { - goto childerror - } - pipe = nextfd - nextfd++ - } - for i = 0; i < len(fd); i++ { - if fd[i] >= 0 && fd[i] < i { - if nextfd == pipe { // don't stomp on pipe - nextfd++ - } - r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(nextfd), 0) - if int32(r1) == -1 { - goto childerror - } - - fd[i] = nextfd - nextfd++ - } - } - - // Pass 2: dup fd[i] down onto i. - for i = 0; i < len(fd); i++ { - if fd[i] == -1 { - RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) - continue - } - if fd[i] == i { - continue - } - r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(i), 0) - if int32(r1) == -1 { - goto childerror - } - } - - // Pass 3: close fd[i] if it was moved in the previous pass. - for i = 0; i < len(fd); i++ { - if fd[i] >= len(fd) { - RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0) - } - } - - // Time to exec. - r1, _, _ = RawSyscall(SYS_EXEC, - uintptr(unsafe.Pointer(argv0)), - uintptr(unsafe.Pointer(&argv[0])), 0) - -childerror: - // send error string on pipe - RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0) -childerror1: - errbuf[len(errbuf)-1] = 0 - i = 0 - for i < len(errbuf) && errbuf[i] != 0 { - i++ - } - - RawSyscall6(SYS_PWRITE, uintptr(pipe), uintptr(unsafe.Pointer(&errbuf[0])), uintptr(i), - ^uintptr(0), ^uintptr(0), 0) - - for { - RawSyscall(SYS_EXITS, 0, 0, 0) - } -} - -// close the numbered file descriptor, unless it is fd1, fd2, or a member of fds. -// -//go:nosplit -func closeFdExcept(n int, fd1 int, fd2 int, fds []int) { - if n == fd1 || n == fd2 { - return - } - for _, fd := range fds { - if n == fd { - return - } - } - RawSyscall(SYS_CLOSE, uintptr(n), 0, 0) -} - -func cexecPipe(p []int) error { - e := Pipe(p) - if e != nil { - return e - } - - fd, e := Open("#d/"+itoa.Itoa(p[1]), O_RDWR|O_CLOEXEC) - if e != nil { - Close(p[0]) - Close(p[1]) - return e - } - - Close(p[1]) - p[1] = fd - return nil -} - -type envItem struct { - name *byte - value *byte - nvalue int -} - -type ProcAttr struct { - Dir string // Current working directory. - Env []string // Environment. - Files []uintptr // File descriptors. - Sys *SysProcAttr -} - -type SysProcAttr struct { - Rfork int // additional flags to pass to rfork -} - -var zeroProcAttr ProcAttr -var zeroSysProcAttr SysProcAttr - -func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { - var ( - p [2]int - n int - errbuf [ERRMAX]byte - wmsg Waitmsg - ) - - if attr == nil { - attr = &zeroProcAttr - } - sys := attr.Sys - if sys == nil { - sys = &zeroSysProcAttr - } - - p[0] = -1 - p[1] = -1 - - // Convert args to C form. - argv0p, err := BytePtrFromString(argv0) - if err != nil { - return 0, err - } - argvp, err := SlicePtrFromStrings(argv) - if err != nil { - return 0, err - } - - destDir := attr.Dir - if destDir == "" { - wdmu.Lock() - destDir = wdStr - wdmu.Unlock() - } - var dir *byte - if destDir != "" { - dir, err = BytePtrFromString(destDir) - if err != nil { - return 0, err - } - } - var envvParsed []envItem - if attr.Env != nil { - envvParsed = make([]envItem, 0, len(attr.Env)) - for _, v := range attr.Env { - i := 0 - for i < len(v) && v[i] != '=' { - i++ - } - - envname, err := BytePtrFromString("/env/" + v[:i]) - if err != nil { - return 0, err - } - envvalue := make([]byte, len(v)-i) - copy(envvalue, v[i+1:]) - envvParsed = append(envvParsed, envItem{envname, &envvalue[0], len(v) - i}) - } - } - - // Allocate child status pipe close on exec. - e := cexecPipe(p[:]) - - if e != nil { - return 0, e - } - - // Kick off child. - pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, p[1], sys.Rfork) - - if err != nil { - if p[0] >= 0 { - Close(p[0]) - Close(p[1]) - } - return 0, err - } - - // Read child error status from pipe. - Close(p[1]) - n, err = Read(p[0], errbuf[:]) - Close(p[0]) - - if err != nil || n != 0 { - if n > 0 { - err = NewError(string(errbuf[:n])) - } else if err == nil { - err = NewError("failed to read exec status") - } - - // Child failed; wait for it to exit, to make sure - // the zombies don't accumulate. - for wmsg.Pid != pid { - Await(&wmsg) - } - return 0, err - } - - // Read got EOF, so pipe closed on exec, so exec succeeded. - return pid, nil -} - -type waitErr struct { - Waitmsg - err error -} - -var procs struct { - sync.Mutex - waits map[int]chan *waitErr -} - -// startProcess starts a new goroutine, tied to the OS -// thread, which runs the process and subsequently waits -// for it to finish, communicating the process stats back -// to any goroutines that may have been waiting on it. -// -// Such a dedicated goroutine is needed because on -// Plan 9, only the parent thread can wait for a child, -// whereas goroutines tend to jump OS threads (e.g., -// between starting a process and running Wait(), the -// goroutine may have been rescheduled). -func startProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { - type forkRet struct { - pid int - err error - } - - forkc := make(chan forkRet, 1) - go func() { - runtime.LockOSThread() - var ret forkRet - - ret.pid, ret.err = forkExec(argv0, argv, attr) - // If fork fails there is nothing to wait for. - if ret.err != nil || ret.pid == 0 { - forkc <- ret - return - } - - waitc := make(chan *waitErr, 1) - - // Mark that the process is running. - procs.Lock() - if procs.waits == nil { - procs.waits = make(map[int]chan *waitErr) - } - procs.waits[ret.pid] = waitc - procs.Unlock() - - forkc <- ret - - var w waitErr - for w.err == nil && w.Pid != ret.pid { - w.err = Await(&w.Waitmsg) - } - waitc <- &w - close(waitc) - }() - ret := <-forkc - return ret.pid, ret.err -} - -// Combination of fork and exec, careful to be thread safe. -func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { - return startProcess(argv0, argv, attr) -} - -// StartProcess wraps ForkExec for package os. -func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { - pid, err = startProcess(argv0, argv, attr) - return pid, 0, err -} - -// Ordinary exec. -func Exec(argv0 string, argv []string, envv []string) (err error) { - if envv != nil { - r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0) - if int32(r1) == -1 { - return NewError(errstr()) - } - - for _, v := range envv { - i := 0 - for i < len(v) && v[i] != '=' { - i++ - } - - fd, e := Create("/env/"+v[:i], O_WRONLY, 0666) - if e != nil { - return e - } - - _, e = Write(fd, []byte(v[i+1:])) - if e != nil { - Close(fd) - return e - } - Close(fd) - } - } - - argv0p, err := BytePtrFromString(argv0) - if err != nil { - return err - } - argvp, err := SlicePtrFromStrings(argv) - if err != nil { - return err - } - _, _, e1 := Syscall(SYS_EXEC, - uintptr(unsafe.Pointer(argv0p)), - uintptr(unsafe.Pointer(&argvp[0])), - 0) - - return e1 -} - -// WaitProcess waits until the pid of a -// running process is found in the queue of -// wait messages. It is used in conjunction -// with ForkExec/StartProcess to wait for a -// running process to exit. -func WaitProcess(pid int, w *Waitmsg) (err error) { - procs.Lock() - ch := procs.waits[pid] - procs.Unlock() - - var wmsg *waitErr - if ch != nil { - wmsg = <-ch - procs.Lock() - if procs.waits[pid] == ch { - delete(procs.waits, pid) - } - procs.Unlock() - } - if wmsg == nil { - // ch was missing or ch is closed - return NewError("process not found") - } - if wmsg.err != nil { - return wmsg.err - } - if w != nil { - *w = wmsg.Waitmsg - } - return nil -} diff --git a/contrib/go/_std_1.22/src/syscall/exec_unix.go b/contrib/go/_std_1.22/src/syscall/exec_unix.go deleted file mode 100644 index 469b6601982d..000000000000 --- a/contrib/go/_std_1.22/src/syscall/exec_unix.go +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix - -// Fork, exec, wait, etc. - -package syscall - -import ( - errorspkg "errors" - "internal/bytealg" - "runtime" - "sync" - "unsafe" -) - -// ForkLock is used to synchronize creation of new file descriptors -// with fork. -// -// We want the child in a fork/exec sequence to inherit only the -// file descriptors we intend. To do that, we mark all file -// descriptors close-on-exec and then, in the child, explicitly -// unmark the ones we want the exec'ed program to keep. -// Unix doesn't make this easy: there is, in general, no way to -// allocate a new file descriptor close-on-exec. Instead you -// have to allocate the descriptor and then mark it close-on-exec. -// If a fork happens between those two events, the child's exec -// will inherit an unwanted file descriptor. -// -// This lock solves that race: the create new fd/mark close-on-exec -// operation is done holding ForkLock for reading, and the fork itself -// is done holding ForkLock for writing. At least, that's the idea. -// There are some complications. -// -// Some system calls that create new file descriptors can block -// for arbitrarily long times: open on a hung NFS server or named -// pipe, accept on a socket, and so on. We can't reasonably grab -// the lock across those operations. -// -// It is worse to inherit some file descriptors than others. -// If a non-malicious child accidentally inherits an open ordinary file, -// that's not a big deal. On the other hand, if a long-lived child -// accidentally inherits the write end of a pipe, then the reader -// of that pipe will not see EOF until that child exits, potentially -// causing the parent program to hang. This is a common problem -// in threaded C programs that use popen. -// -// Luckily, the file descriptors that are most important not to -// inherit are not the ones that can take an arbitrarily long time -// to create: pipe returns instantly, and the net package uses -// non-blocking I/O to accept on a listening socket. -// The rules for which file descriptor-creating operations use the -// ForkLock are as follows: -// -// - Pipe. Use pipe2 if available. Otherwise, does not block, -// so use ForkLock. -// - Socket. Use SOCK_CLOEXEC if available. Otherwise, does not -// block, so use ForkLock. -// - Open. Use O_CLOEXEC if available. Otherwise, may block, -// so live with the race. -// - Dup. Use F_DUPFD_CLOEXEC or dup3 if available. Otherwise, -// does not block, so use ForkLock. -var ForkLock sync.RWMutex - -// StringSlicePtr converts a slice of strings to a slice of pointers -// to NUL-terminated byte arrays. If any string contains a NUL byte -// this function panics instead of returning an error. -// -// Deprecated: Use SlicePtrFromStrings instead. -func StringSlicePtr(ss []string) []*byte { - bb := make([]*byte, len(ss)+1) - for i := 0; i < len(ss); i++ { - bb[i] = StringBytePtr(ss[i]) - } - bb[len(ss)] = nil - return bb -} - -// SlicePtrFromStrings converts a slice of strings to a slice of -// pointers to NUL-terminated byte arrays. If any string contains -// a NUL byte, it returns (nil, EINVAL). -func SlicePtrFromStrings(ss []string) ([]*byte, error) { - n := 0 - for _, s := range ss { - if bytealg.IndexByteString(s, 0) != -1 { - return nil, EINVAL - } - n += len(s) + 1 // +1 for NUL - } - bb := make([]*byte, len(ss)+1) - b := make([]byte, n) - n = 0 - for i, s := range ss { - bb[i] = &b[n] - copy(b[n:], s) - n += len(s) + 1 - } - return bb, nil -} - -func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) } - -func SetNonblock(fd int, nonblocking bool) (err error) { - flag, err := fcntl(fd, F_GETFL, 0) - if err != nil { - return err - } - if (flag&O_NONBLOCK != 0) == nonblocking { - return nil - } - if nonblocking { - flag |= O_NONBLOCK - } else { - flag &^= O_NONBLOCK - } - _, err = fcntl(fd, F_SETFL, flag) - return err -} - -// Credential holds user and group identities to be assumed -// by a child process started by StartProcess. -type Credential struct { - Uid uint32 // User ID. - Gid uint32 // Group ID. - Groups []uint32 // Supplementary group IDs. - NoSetGroups bool // If true, don't set supplementary groups -} - -// ProcAttr holds attributes that will be applied to a new process started -// by StartProcess. -type ProcAttr struct { - Dir string // Current working directory. - Env []string // Environment. - Files []uintptr // File descriptors. - Sys *SysProcAttr -} - -var zeroProcAttr ProcAttr -var zeroSysProcAttr SysProcAttr - -func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { - var p [2]int - var n int - var err1 Errno - var wstatus WaitStatus - - if attr == nil { - attr = &zeroProcAttr - } - sys := attr.Sys - if sys == nil { - sys = &zeroSysProcAttr - } - - // Convert args to C form. - argv0p, err := BytePtrFromString(argv0) - if err != nil { - return 0, err - } - argvp, err := SlicePtrFromStrings(argv) - if err != nil { - return 0, err - } - envvp, err := SlicePtrFromStrings(attr.Env) - if err != nil { - return 0, err - } - - if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv) > 0 && len(argv[0]) > len(argv0) { - argvp[0] = argv0p - } - - var chroot *byte - if sys.Chroot != "" { - chroot, err = BytePtrFromString(sys.Chroot) - if err != nil { - return 0, err - } - } - var dir *byte - if attr.Dir != "" { - dir, err = BytePtrFromString(attr.Dir) - if err != nil { - return 0, err - } - } - - // Both Setctty and Foreground use the Ctty field, - // but they give it slightly different meanings. - if sys.Setctty && sys.Foreground { - return 0, errorspkg.New("both Setctty and Foreground set in SysProcAttr") - } - if sys.Setctty && sys.Ctty >= len(attr.Files) { - return 0, errorspkg.New("Setctty set but Ctty not valid in child") - } - - acquireForkLock() - - // Allocate child status pipe close on exec. - if err = forkExecPipe(p[:]); err != nil { - releaseForkLock() - return 0, err - } - - // Kick off child. - pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1]) - if err1 != 0 { - Close(p[0]) - Close(p[1]) - releaseForkLock() - return 0, Errno(err1) - } - releaseForkLock() - - // Read child error status from pipe. - Close(p[1]) - for { - n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1))) - if err != EINTR { - break - } - } - Close(p[0]) - if err != nil || n != 0 { - if n == int(unsafe.Sizeof(err1)) { - err = Errno(err1) - } - if err == nil { - err = EPIPE - } - - // Child failed; wait for it to exit, to make sure - // the zombies don't accumulate. - _, err1 := Wait4(pid, &wstatus, 0, nil) - for err1 == EINTR { - _, err1 = Wait4(pid, &wstatus, 0, nil) - } - return 0, err - } - - // Read got EOF, so pipe closed on exec, so exec succeeded. - return pid, nil -} - -// Combination of fork and exec, careful to be thread safe. -func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { - return forkExec(argv0, argv, attr) -} - -// StartProcess wraps ForkExec for package os. -func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { - pid, err = forkExec(argv0, argv, attr) - return pid, 0, err -} - -// Implemented in runtime package. -func runtime_BeforeExec() -func runtime_AfterExec() - -// execveLibc is non-nil on OS using libc syscall, set to execve in exec_libc.go; this -// avoids a build dependency for other platforms. -var execveLibc func(path uintptr, argv uintptr, envp uintptr) Errno -var execveDarwin func(path *byte, argv **byte, envp **byte) error -var execveOpenBSD func(path *byte, argv **byte, envp **byte) error - -// Exec invokes the execve(2) system call. -func Exec(argv0 string, argv []string, envv []string) (err error) { - argv0p, err := BytePtrFromString(argv0) - if err != nil { - return err - } - argvp, err := SlicePtrFromStrings(argv) - if err != nil { - return err - } - envvp, err := SlicePtrFromStrings(envv) - if err != nil { - return err - } - runtime_BeforeExec() - - rlim := origRlimitNofile.Load() - if rlim != nil { - Setrlimit(RLIMIT_NOFILE, rlim) - } - - var err1 error - if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "aix" { - // RawSyscall should never be used on Solaris, illumos, or AIX. - err1 = execveLibc( - uintptr(unsafe.Pointer(argv0p)), - uintptr(unsafe.Pointer(&argvp[0])), - uintptr(unsafe.Pointer(&envvp[0]))) - } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { - // Similarly on Darwin. - err1 = execveDarwin(argv0p, &argvp[0], &envvp[0]) - } else if runtime.GOOS == "openbsd" && runtime.GOARCH != "mips64" { - // Similarly on OpenBSD. - err1 = execveOpenBSD(argv0p, &argvp[0], &envvp[0]) - } else { - _, _, err1 = RawSyscall(SYS_EXECVE, - uintptr(unsafe.Pointer(argv0p)), - uintptr(unsafe.Pointer(&argvp[0])), - uintptr(unsafe.Pointer(&envvp[0]))) - } - runtime_AfterExec() - return err1 -} diff --git a/contrib/go/_std_1.22/src/syscall/js/js.go b/contrib/go/_std_1.22/src/syscall/js/js.go deleted file mode 100644 index f7e32eb366db..000000000000 --- a/contrib/go/_std_1.22/src/syscall/js/js.go +++ /dev/null @@ -1,600 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build js && wasm - -// Package js gives access to the WebAssembly host environment when using the js/wasm architecture. -// Its API is based on JavaScript semantics. -// -// This package is EXPERIMENTAL. Its current scope is only to allow tests to run, but not yet to provide a -// comprehensive API for users. It is exempt from the Go compatibility promise. -package js - -import ( - "runtime" - "unsafe" -) - -// ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly. -// -// The JavaScript value "undefined" is represented by the value 0. -// A JavaScript number (64-bit float, except 0 and NaN) is represented by its IEEE 754 binary representation. -// All other values are represented as an IEEE 754 binary representation of NaN with bits 0-31 used as -// an ID and bits 32-34 used to differentiate between string, symbol, function and object. -type ref uint64 - -// nanHead are the upper 32 bits of a ref which are set if the value is not encoded as an IEEE 754 number (see above). -const nanHead = 0x7FF80000 - -// Value represents a JavaScript value. The zero value is the JavaScript value "undefined". -// Values can be checked for equality with the Equal method. -type Value struct { - _ [0]func() // uncomparable; to make == not compile - ref ref // identifies a JavaScript value, see ref type - gcPtr *ref // used to trigger the finalizer when the Value is not referenced any more -} - -const ( - // the type flags need to be in sync with wasm_exec.js - typeFlagNone = iota - typeFlagObject - typeFlagString - typeFlagSymbol - typeFlagFunction -) - -func makeValue(r ref) Value { - var gcPtr *ref - typeFlag := (r >> 32) & 7 - if (r>>32)&nanHead == nanHead && typeFlag != typeFlagNone { - gcPtr = new(ref) - *gcPtr = r - runtime.SetFinalizer(gcPtr, func(p *ref) { - finalizeRef(*p) - }) - } - - return Value{ref: r, gcPtr: gcPtr} -} - -//go:wasmimport gojs syscall/js.finalizeRef -func finalizeRef(r ref) - -func predefValue(id uint32, typeFlag byte) Value { - return Value{ref: (nanHead|ref(typeFlag))<<32 | ref(id)} -} - -func floatValue(f float64) Value { - if f == 0 { - return valueZero - } - if f != f { - return valueNaN - } - return Value{ref: *(*ref)(unsafe.Pointer(&f))} -} - -// Error wraps a JavaScript error. -type Error struct { - // Value is the underlying JavaScript error value. - Value -} - -// Error implements the error interface. -func (e Error) Error() string { - return "JavaScript error: " + e.Get("message").String() -} - -var ( - valueUndefined = Value{ref: 0} - valueNaN = predefValue(0, typeFlagNone) - valueZero = predefValue(1, typeFlagNone) - valueNull = predefValue(2, typeFlagNone) - valueTrue = predefValue(3, typeFlagNone) - valueFalse = predefValue(4, typeFlagNone) - valueGlobal = predefValue(5, typeFlagObject) - jsGo = predefValue(6, typeFlagObject) // instance of the Go class in JavaScript - - objectConstructor = valueGlobal.Get("Object") - arrayConstructor = valueGlobal.Get("Array") -) - -// Equal reports whether v and w are equal according to JavaScript's === operator. -func (v Value) Equal(w Value) bool { - return v.ref == w.ref && v.ref != valueNaN.ref -} - -// Undefined returns the JavaScript value "undefined". -func Undefined() Value { - return valueUndefined -} - -// IsUndefined reports whether v is the JavaScript value "undefined". -func (v Value) IsUndefined() bool { - return v.ref == valueUndefined.ref -} - -// Null returns the JavaScript value "null". -func Null() Value { - return valueNull -} - -// IsNull reports whether v is the JavaScript value "null". -func (v Value) IsNull() bool { - return v.ref == valueNull.ref -} - -// IsNaN reports whether v is the JavaScript value "NaN". -func (v Value) IsNaN() bool { - return v.ref == valueNaN.ref -} - -// Global returns the JavaScript global object, usually "window" or "global". -func Global() Value { - return valueGlobal -} - -// ValueOf returns x as a JavaScript value: -// -// | Go | JavaScript | -// | ---------------------- | ---------------------- | -// | js.Value | [its value] | -// | js.Func | function | -// | nil | null | -// | bool | boolean | -// | integers and floats | number | -// | string | string | -// | []interface{} | new array | -// | map[string]interface{} | new object | -// -// Panics if x is not one of the expected types. -func ValueOf(x any) Value { - switch x := x.(type) { - case Value: - return x - case Func: - return x.Value - case nil: - return valueNull - case bool: - if x { - return valueTrue - } else { - return valueFalse - } - case int: - return floatValue(float64(x)) - case int8: - return floatValue(float64(x)) - case int16: - return floatValue(float64(x)) - case int32: - return floatValue(float64(x)) - case int64: - return floatValue(float64(x)) - case uint: - return floatValue(float64(x)) - case uint8: - return floatValue(float64(x)) - case uint16: - return floatValue(float64(x)) - case uint32: - return floatValue(float64(x)) - case uint64: - return floatValue(float64(x)) - case uintptr: - return floatValue(float64(x)) - case unsafe.Pointer: - return floatValue(float64(uintptr(x))) - case float32: - return floatValue(float64(x)) - case float64: - return floatValue(x) - case string: - return makeValue(stringVal(x)) - case []any: - a := arrayConstructor.New(len(x)) - for i, s := range x { - a.SetIndex(i, s) - } - return a - case map[string]any: - o := objectConstructor.New() - for k, v := range x { - o.Set(k, v) - } - return o - default: - panic("ValueOf: invalid value") - } -} - -//go:wasmimport gojs syscall/js.stringVal -func stringVal(x string) ref - -// Type represents the JavaScript type of a Value. -type Type int - -const ( - TypeUndefined Type = iota - TypeNull - TypeBoolean - TypeNumber - TypeString - TypeSymbol - TypeObject - TypeFunction -) - -func (t Type) String() string { - switch t { - case TypeUndefined: - return "undefined" - case TypeNull: - return "null" - case TypeBoolean: - return "boolean" - case TypeNumber: - return "number" - case TypeString: - return "string" - case TypeSymbol: - return "symbol" - case TypeObject: - return "object" - case TypeFunction: - return "function" - default: - panic("bad type") - } -} - -func (t Type) isObject() bool { - return t == TypeObject || t == TypeFunction -} - -// Type returns the JavaScript type of the value v. It is similar to JavaScript's typeof operator, -// except that it returns TypeNull instead of TypeObject for null. -func (v Value) Type() Type { - switch v.ref { - case valueUndefined.ref: - return TypeUndefined - case valueNull.ref: - return TypeNull - case valueTrue.ref, valueFalse.ref: - return TypeBoolean - } - if v.isNumber() { - return TypeNumber - } - typeFlag := (v.ref >> 32) & 7 - switch typeFlag { - case typeFlagObject: - return TypeObject - case typeFlagString: - return TypeString - case typeFlagSymbol: - return TypeSymbol - case typeFlagFunction: - return TypeFunction - default: - panic("bad type flag") - } -} - -// Get returns the JavaScript property p of value v. -// It panics if v is not a JavaScript object. -func (v Value) Get(p string) Value { - if vType := v.Type(); !vType.isObject() { - panic(&ValueError{"Value.Get", vType}) - } - r := makeValue(valueGet(v.ref, p)) - runtime.KeepAlive(v) - return r -} - -//go:wasmimport gojs syscall/js.valueGet -func valueGet(v ref, p string) ref - -// Set sets the JavaScript property p of value v to ValueOf(x). -// It panics if v is not a JavaScript object. -func (v Value) Set(p string, x any) { - if vType := v.Type(); !vType.isObject() { - panic(&ValueError{"Value.Set", vType}) - } - xv := ValueOf(x) - valueSet(v.ref, p, xv.ref) - runtime.KeepAlive(v) - runtime.KeepAlive(xv) -} - -//go:wasmimport gojs syscall/js.valueSet -func valueSet(v ref, p string, x ref) - -// Delete deletes the JavaScript property p of value v. -// It panics if v is not a JavaScript object. -func (v Value) Delete(p string) { - if vType := v.Type(); !vType.isObject() { - panic(&ValueError{"Value.Delete", vType}) - } - valueDelete(v.ref, p) - runtime.KeepAlive(v) -} - -//go:wasmimport gojs syscall/js.valueDelete -func valueDelete(v ref, p string) - -// Index returns JavaScript index i of value v. -// It panics if v is not a JavaScript object. -func (v Value) Index(i int) Value { - if vType := v.Type(); !vType.isObject() { - panic(&ValueError{"Value.Index", vType}) - } - r := makeValue(valueIndex(v.ref, i)) - runtime.KeepAlive(v) - return r -} - -//go:wasmimport gojs syscall/js.valueIndex -func valueIndex(v ref, i int) ref - -// SetIndex sets the JavaScript index i of value v to ValueOf(x). -// It panics if v is not a JavaScript object. -func (v Value) SetIndex(i int, x any) { - if vType := v.Type(); !vType.isObject() { - panic(&ValueError{"Value.SetIndex", vType}) - } - xv := ValueOf(x) - valueSetIndex(v.ref, i, xv.ref) - runtime.KeepAlive(v) - runtime.KeepAlive(xv) -} - -//go:wasmimport gojs syscall/js.valueSetIndex -func valueSetIndex(v ref, i int, x ref) - -func makeArgs(args []any) ([]Value, []ref) { - argVals := make([]Value, len(args)) - argRefs := make([]ref, len(args)) - for i, arg := range args { - v := ValueOf(arg) - argVals[i] = v - argRefs[i] = v.ref - } - return argVals, argRefs -} - -// Length returns the JavaScript property "length" of v. -// It panics if v is not a JavaScript object. -func (v Value) Length() int { - if vType := v.Type(); !vType.isObject() { - panic(&ValueError{"Value.SetIndex", vType}) - } - r := valueLength(v.ref) - runtime.KeepAlive(v) - return r -} - -//go:wasmimport gojs syscall/js.valueLength -func valueLength(v ref) int - -// Call does a JavaScript call to the method m of value v with the given arguments. -// It panics if v has no method m. -// The arguments get mapped to JavaScript values according to the ValueOf function. -func (v Value) Call(m string, args ...any) Value { - argVals, argRefs := makeArgs(args) - res, ok := valueCall(v.ref, m, argRefs) - runtime.KeepAlive(v) - runtime.KeepAlive(argVals) - if !ok { - if vType := v.Type(); !vType.isObject() { // check here to avoid overhead in success case - panic(&ValueError{"Value.Call", vType}) - } - if propType := v.Get(m).Type(); propType != TypeFunction { - panic("syscall/js: Value.Call: property " + m + " is not a function, got " + propType.String()) - } - panic(Error{makeValue(res)}) - } - return makeValue(res) -} - -//go:wasmimport gojs syscall/js.valueCall -//go:nosplit -func valueCall(v ref, m string, args []ref) (ref, bool) - -// Invoke does a JavaScript call of the value v with the given arguments. -// It panics if v is not a JavaScript function. -// The arguments get mapped to JavaScript values according to the ValueOf function. -func (v Value) Invoke(args ...any) Value { - argVals, argRefs := makeArgs(args) - res, ok := valueInvoke(v.ref, argRefs) - runtime.KeepAlive(v) - runtime.KeepAlive(argVals) - if !ok { - if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case - panic(&ValueError{"Value.Invoke", vType}) - } - panic(Error{makeValue(res)}) - } - return makeValue(res) -} - -//go:wasmimport gojs syscall/js.valueInvoke -func valueInvoke(v ref, args []ref) (ref, bool) - -// New uses JavaScript's "new" operator with value v as constructor and the given arguments. -// It panics if v is not a JavaScript function. -// The arguments get mapped to JavaScript values according to the ValueOf function. -func (v Value) New(args ...any) Value { - argVals, argRefs := makeArgs(args) - res, ok := valueNew(v.ref, argRefs) - runtime.KeepAlive(v) - runtime.KeepAlive(argVals) - if !ok { - if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case - panic(&ValueError{"Value.Invoke", vType}) - } - panic(Error{makeValue(res)}) - } - return makeValue(res) -} - -//go:wasmimport gojs syscall/js.valueNew -func valueNew(v ref, args []ref) (ref, bool) - -func (v Value) isNumber() bool { - return v.ref == valueZero.ref || - v.ref == valueNaN.ref || - (v.ref != valueUndefined.ref && (v.ref>>32)&nanHead != nanHead) -} - -func (v Value) float(method string) float64 { - if !v.isNumber() { - panic(&ValueError{method, v.Type()}) - } - if v.ref == valueZero.ref { - return 0 - } - return *(*float64)(unsafe.Pointer(&v.ref)) -} - -// Float returns the value v as a float64. -// It panics if v is not a JavaScript number. -func (v Value) Float() float64 { - return v.float("Value.Float") -} - -// Int returns the value v truncated to an int. -// It panics if v is not a JavaScript number. -func (v Value) Int() int { - return int(v.float("Value.Int")) -} - -// Bool returns the value v as a bool. -// It panics if v is not a JavaScript boolean. -func (v Value) Bool() bool { - switch v.ref { - case valueTrue.ref: - return true - case valueFalse.ref: - return false - default: - panic(&ValueError{"Value.Bool", v.Type()}) - } -} - -// Truthy returns the JavaScript "truthiness" of the value v. In JavaScript, -// false, 0, "", null, undefined, and NaN are "falsy", and everything else is -// "truthy". See https://developer.mozilla.org/en-US/docs/Glossary/Truthy. -func (v Value) Truthy() bool { - switch v.Type() { - case TypeUndefined, TypeNull: - return false - case TypeBoolean: - return v.Bool() - case TypeNumber: - return v.ref != valueNaN.ref && v.ref != valueZero.ref - case TypeString: - return v.String() != "" - case TypeSymbol, TypeFunction, TypeObject: - return true - default: - panic("bad type") - } -} - -// String returns the value v as a string. -// String is a special case because of Go's String method convention. Unlike the other getters, -// it does not panic if v's Type is not TypeString. Instead, it returns a string of the form "" -// or "" where T is v's type and V is a string representation of v's value. -func (v Value) String() string { - switch v.Type() { - case TypeString: - return jsString(v) - case TypeUndefined: - return "" - case TypeNull: - return "" - case TypeBoolean: - return "" - case TypeNumber: - return "" - case TypeSymbol: - return "" - case TypeObject: - return "" - case TypeFunction: - return "" - default: - panic("bad type") - } -} - -func jsString(v Value) string { - str, length := valuePrepareString(v.ref) - runtime.KeepAlive(v) - b := make([]byte, length) - valueLoadString(str, b) - finalizeRef(str) - return string(b) -} - -//go:wasmimport gojs syscall/js.valuePrepareString -func valuePrepareString(v ref) (ref, int) - -//go:wasmimport gojs syscall/js.valueLoadString -func valueLoadString(v ref, b []byte) - -// InstanceOf reports whether v is an instance of type t according to JavaScript's instanceof operator. -func (v Value) InstanceOf(t Value) bool { - r := valueInstanceOf(v.ref, t.ref) - runtime.KeepAlive(v) - runtime.KeepAlive(t) - return r -} - -//go:wasmimport gojs syscall/js.valueInstanceOf -func valueInstanceOf(v ref, t ref) bool - -// A ValueError occurs when a Value method is invoked on -// a Value that does not support it. Such cases are documented -// in the description of each method. -type ValueError struct { - Method string - Type Type -} - -func (e *ValueError) Error() string { - return "syscall/js: call of " + e.Method + " on " + e.Type.String() -} - -// CopyBytesToGo copies bytes from src to dst. -// It panics if src is not a Uint8Array or Uint8ClampedArray. -// It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. -func CopyBytesToGo(dst []byte, src Value) int { - n, ok := copyBytesToGo(dst, src.ref) - runtime.KeepAlive(src) - if !ok { - panic("syscall/js: CopyBytesToGo: expected src to be a Uint8Array or Uint8ClampedArray") - } - return n -} - -//go:wasmimport gojs syscall/js.copyBytesToGo -func copyBytesToGo(dst []byte, src ref) (int, bool) - -// CopyBytesToJS copies bytes from src to dst. -// It panics if dst is not a Uint8Array or Uint8ClampedArray. -// It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. -func CopyBytesToJS(dst Value, src []byte) int { - n, ok := copyBytesToJS(dst.ref, src) - runtime.KeepAlive(dst) - if !ok { - panic("syscall/js: CopyBytesToJS: expected dst to be a Uint8Array or Uint8ClampedArray") - } - return n -} - -//go:wasmimport gojs syscall/js.copyBytesToJS -func copyBytesToJS(dst ref, src []byte) (int, bool) diff --git a/contrib/go/_std_1.22/src/syscall/msan.go b/contrib/go/_std_1.22/src/syscall/msan.go deleted file mode 100644 index 89c580799fc8..000000000000 --- a/contrib/go/_std_1.22/src/syscall/msan.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build msan - -package syscall - -import ( - "runtime" - "unsafe" -) - -const msanenabled = true - -func msanRead(addr unsafe.Pointer, len int) { - runtime.MSanRead(addr, len) -} - -func msanWrite(addr unsafe.Pointer, len int) { - runtime.MSanWrite(addr, len) -} diff --git a/contrib/go/_std_1.22/src/syscall/msan0.go b/contrib/go/_std_1.22/src/syscall/msan0.go deleted file mode 100644 index fba8a5f716ed..000000000000 --- a/contrib/go/_std_1.22/src/syscall/msan0.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !msan - -package syscall - -import ( - "unsafe" -) - -const msanenabled = false - -func msanRead(addr unsafe.Pointer, len int) { -} - -func msanWrite(addr unsafe.Pointer, len int) { -} diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux.go b/contrib/go/_std_1.22/src/syscall/syscall_linux.go deleted file mode 100644 index b6e84203e8df..000000000000 --- a/contrib/go/_std_1.22/src/syscall/syscall_linux.go +++ /dev/null @@ -1,1292 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Linux system calls. -// This file is compiled as ordinary Go code, -// but it is also input to mksyscall, -// which parses the //sys lines and generates system call stubs. -// Note that sometimes we use a lowercase //sys name and -// wrap it in our own nicer implementation. - -package syscall - -import ( - "internal/itoa" - "runtime" - "unsafe" -) - -// N.B. RawSyscall6 is provided via linkname by runtime/internal/syscall. -// -// Errno is uintptr and thus compatible with the runtime/internal/syscall -// definition. - -func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) - -// Pull in entersyscall/exitsyscall for Syscall/Syscall6. -// -// Note that this can't be a push linkname because the runtime already has a -// nameless linkname to export to assembly here and in x/sys. Additionally, -// entersyscall fetches the caller PC and SP and thus can't have a wrapper -// inbetween. - -//go:linkname runtime_entersyscall runtime.entersyscall -func runtime_entersyscall() - -//go:linkname runtime_exitsyscall runtime.exitsyscall -func runtime_exitsyscall() - -// N.B. For the Syscall functions below: -// -// //go:uintptrkeepalive because the uintptr argument may be converted pointers -// that need to be kept alive in the caller (this is implied for RawSyscall6 -// since it has no body). -// -// //go:nosplit because stack copying does not account for uintptrkeepalive, so -// the stack must not grow. Stack copying cannot blindly assume that all -// uintptr arguments are pointers, because some values may look like pointers, -// but not really be pointers, and adjusting their value would break the call. -// -// //go:norace, on RawSyscall, to avoid race instrumentation if RawSyscall is -// called after fork, or from a signal handler. -// -// //go:linkname to ensure ABI wrappers are generated for external callers -// (notably x/sys/unix assembly). - -//go:uintptrkeepalive -//go:nosplit -//go:norace -//go:linkname RawSyscall -func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { - return RawSyscall6(trap, a1, a2, a3, 0, 0, 0) -} - -//go:uintptrkeepalive -//go:nosplit -//go:linkname Syscall -func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { - runtime_entersyscall() - // N.B. Calling RawSyscall here is unsafe with atomic coverage - // instrumentation and race mode. - // - // Coverage instrumentation will add a sync/atomic call to RawSyscall. - // Race mode will add race instrumentation to sync/atomic. Race - // instrumentation requires a P, which we no longer have. - // - // RawSyscall6 is fine because it is implemented in assembly and thus - // has no coverage instrumentation. - // - // This is typically not a problem in the runtime because cmd/go avoids - // adding coverage instrumentation to the runtime in race mode. - r1, r2, err = RawSyscall6(trap, a1, a2, a3, 0, 0, 0) - runtime_exitsyscall() - return -} - -//go:uintptrkeepalive -//go:nosplit -//go:linkname Syscall6 -func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { - runtime_entersyscall() - r1, r2, err = RawSyscall6(trap, a1, a2, a3, a4, a5, a6) - runtime_exitsyscall() - return -} - -func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) -func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1 uintptr, err Errno) - -/* - * Wrapped - */ - -func Access(path string, mode uint32) (err error) { - return Faccessat(_AT_FDCWD, path, mode, 0) -} - -func Chmod(path string, mode uint32) (err error) { - return Fchmodat(_AT_FDCWD, path, mode, 0) -} - -func Chown(path string, uid int, gid int) (err error) { - return Fchownat(_AT_FDCWD, path, uid, gid, 0) -} - -func Creat(path string, mode uint32) (fd int, err error) { - return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) -} - -func EpollCreate(size int) (fd int, err error) { - if size <= 0 { - return -1, EINVAL - } - return EpollCreate1(0) -} - -func isGroupMember(gid int) bool { - groups, err := Getgroups() - if err != nil { - return false - } - - for _, g := range groups { - if g == gid { - return true - } - } - return false -} - -func isCapDacOverrideSet() bool { - const _CAP_DAC_OVERRIDE = 1 - var c caps - c.hdr.version = _LINUX_CAPABILITY_VERSION_3 - - _, _, err := RawSyscall(SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(&c.data[0])), 0) - - return err == 0 && c.data[0].effective&capToMask(_CAP_DAC_OVERRIDE) != 0 -} - -//sys faccessat(dirfd int, path string, mode uint32) (err error) -//sys faccessat2(dirfd int, path string, mode uint32, flags int) (err error) = _SYS_faccessat2 - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - if flags == 0 { - return faccessat(dirfd, path, mode) - } - - // Attempt to use the newer faccessat2, which supports flags directly, - // falling back if it doesn't exist. - // - // Don't attempt on Android, which does not allow faccessat2 through - // its seccomp policy [1] on any version of Android as of 2022-12-20. - // - // [1] https://cs.android.com/android/platform/superproject/+/master:bionic/libc/SECCOMP_BLOCKLIST_APP.TXT;l=4;drc=dbb8670dfdcc677f7e3b9262e93800fa14c4e417 - if runtime.GOOS != "android" { - if err := faccessat2(dirfd, path, mode, flags); err != ENOSYS && err != EPERM { - return err - } - } - - // The Linux kernel faccessat system call does not take any flags. - // The glibc faccessat implements the flags itself; see - // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/faccessat.c;hb=HEAD - // Because people naturally expect syscall.Faccessat to act - // like C faccessat, we do the same. - - if flags & ^(_AT_SYMLINK_NOFOLLOW|_AT_EACCESS) != 0 { - return EINVAL - } - - var st Stat_t - if err := fstatat(dirfd, path, &st, flags&_AT_SYMLINK_NOFOLLOW); err != nil { - return err - } - - mode &= 7 - if mode == 0 { - return nil - } - - // Fallback to checking permission bits. - var uid int - if flags&_AT_EACCESS != 0 { - uid = Geteuid() - if uid != 0 && isCapDacOverrideSet() { - // If CAP_DAC_OVERRIDE is set, file access check is - // done by the kernel in the same way as for root - // (see generic_permission() in the Linux sources). - uid = 0 - } - } else { - uid = Getuid() - } - - if uid == 0 { - if mode&1 == 0 { - // Root can read and write any file. - return nil - } - if st.Mode&0111 != 0 { - // Root can execute any file that anybody can execute. - return nil - } - return EACCES - } - - var fmode uint32 - if uint32(uid) == st.Uid { - fmode = (st.Mode >> 6) & 7 - } else { - var gid int - if flags&_AT_EACCESS != 0 { - gid = Getegid() - } else { - gid = Getgid() - } - - if uint32(gid) == st.Gid || isGroupMember(int(st.Gid)) { - fmode = (st.Mode >> 3) & 7 - } else { - fmode = st.Mode & 7 - } - } - - if fmode&mode == mode { - return nil - } - - return EACCES -} - -//sys fchmodat(dirfd int, path string, mode uint32) (err error) -//sys fchmodat2(dirfd int, path string, mode uint32, flags int) (err error) = _SYS_fchmodat2 - -func Fchmodat(dirfd int, path string, mode uint32, flags int) error { - // Linux fchmodat doesn't support the flags parameter, but fchmodat2 does. - // Try fchmodat2 if flags are specified. - if flags != 0 { - err := fchmodat2(dirfd, path, mode, flags) - if err == ENOSYS { - // fchmodat2 isn't available. If the flags are known to be valid, - // return EOPNOTSUPP to indicate that fchmodat doesn't support them. - if flags&^(_AT_SYMLINK_NOFOLLOW|_AT_EMPTY_PATH) != 0 { - return EINVAL - } else if flags&(_AT_SYMLINK_NOFOLLOW|_AT_EMPTY_PATH) != 0 { - return EOPNOTSUPP - } - } - return err - } - return fchmodat(dirfd, path, mode) -} - -//sys linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) - -func Link(oldpath string, newpath string) (err error) { - return linkat(_AT_FDCWD, oldpath, _AT_FDCWD, newpath, 0) -} - -func Mkdir(path string, mode uint32) (err error) { - return Mkdirat(_AT_FDCWD, path, mode) -} - -func Mknod(path string, mode uint32, dev int) (err error) { - return Mknodat(_AT_FDCWD, path, mode, dev) -} - -func Open(path string, mode int, perm uint32) (fd int, err error) { - return openat(_AT_FDCWD, path, mode|O_LARGEFILE, perm) -} - -//sys openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) - -func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) { - return openat(dirfd, path, flags|O_LARGEFILE, mode) -} - -func Pipe(p []int) error { - return Pipe2(p, 0) -} - -//sysnb pipe2(p *[2]_C_int, flags int) (err error) - -func Pipe2(p []int, flags int) error { - if len(p) != 2 { - return EINVAL - } - var pp [2]_C_int - err := pipe2(&pp, flags) - if err == nil { - p[0] = int(pp[0]) - p[1] = int(pp[1]) - } - return err -} - -//sys readlinkat(dirfd int, path string, buf []byte) (n int, err error) - -func Readlink(path string, buf []byte) (n int, err error) { - return readlinkat(_AT_FDCWD, path, buf) -} - -func Rename(oldpath string, newpath string) (err error) { - return Renameat(_AT_FDCWD, oldpath, _AT_FDCWD, newpath) -} - -func Rmdir(path string) error { - return unlinkat(_AT_FDCWD, path, _AT_REMOVEDIR) -} - -//sys symlinkat(oldpath string, newdirfd int, newpath string) (err error) - -func Symlink(oldpath string, newpath string) (err error) { - return symlinkat(oldpath, _AT_FDCWD, newpath) -} - -func Unlink(path string) error { - return unlinkat(_AT_FDCWD, path, 0) -} - -//sys unlinkat(dirfd int, path string, flags int) (err error) - -func Unlinkat(dirfd int, path string) error { - return unlinkat(dirfd, path, 0) -} - -func Utimes(path string, tv []Timeval) (err error) { - if len(tv) != 2 { - return EINVAL - } - return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) -} - -//sys utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) - -func UtimesNano(path string, ts []Timespec) (err error) { - if len(ts) != 2 { - return EINVAL - } - return utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) -} - -func Futimesat(dirfd int, path string, tv []Timeval) (err error) { - if len(tv) != 2 { - return EINVAL - } - return futimesat(dirfd, path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) -} - -func Futimes(fd int, tv []Timeval) (err error) { - // Believe it or not, this is the best we can do on Linux - // (and is what glibc does). - return Utimes("/proc/self/fd/"+itoa.Itoa(fd), tv) -} - -const ImplementsGetwd = true - -//sys Getcwd(buf []byte) (n int, err error) - -func Getwd() (wd string, err error) { - var buf [PathMax]byte - n, err := Getcwd(buf[0:]) - if err != nil { - return "", err - } - // Getcwd returns the number of bytes written to buf, including the NUL. - if n < 1 || n > len(buf) || buf[n-1] != 0 { - return "", EINVAL - } - // In some cases, Linux can return a path that starts with the - // "(unreachable)" prefix, which can potentially be a valid relative - // path. To work around that, return ENOENT if path is not absolute. - if buf[0] != '/' { - return "", ENOENT - } - - return string(buf[0 : n-1]), nil -} - -func Getgroups() (gids []int, err error) { - n, err := getgroups(0, nil) - if err != nil { - return nil, err - } - if n == 0 { - return nil, nil - } - - // Sanity check group count. Max is 1<<16 on Linux. - if n < 0 || n > 1<<20 { - return nil, EINVAL - } - - a := make([]_Gid_t, n) - n, err = getgroups(n, &a[0]) - if err != nil { - return nil, err - } - gids = make([]int, n) - for i, v := range a[0:n] { - gids[i] = int(v) - } - return -} - -var cgo_libc_setgroups unsafe.Pointer // non-nil if cgo linked. - -func Setgroups(gids []int) (err error) { - n := uintptr(len(gids)) - if n == 0 { - if cgo_libc_setgroups == nil { - if _, _, e1 := AllThreadsSyscall(_SYS_setgroups, 0, 0, 0); e1 != 0 { - err = errnoErr(e1) - } - return - } - if ret := cgocaller(cgo_libc_setgroups, 0, 0); ret != 0 { - err = errnoErr(Errno(ret)) - } - return - } - - a := make([]_Gid_t, len(gids)) - for i, v := range gids { - a[i] = _Gid_t(v) - } - if cgo_libc_setgroups == nil { - if _, _, e1 := AllThreadsSyscall(_SYS_setgroups, n, uintptr(unsafe.Pointer(&a[0])), 0); e1 != 0 { - err = errnoErr(e1) - } - return - } - if ret := cgocaller(cgo_libc_setgroups, n, uintptr(unsafe.Pointer(&a[0]))); ret != 0 { - err = errnoErr(Errno(ret)) - } - return -} - -type WaitStatus uint32 - -// Wait status is 7 bits at bottom, either 0 (exited), -// 0x7F (stopped), or a signal number that caused an exit. -// The 0x80 bit is whether there was a core dump. -// An extra number (exit code, signal causing a stop) -// is in the high bits. At least that's the idea. -// There are various irregularities. For example, the -// "continued" status is 0xFFFF, distinguishing itself -// from stopped via the core dump bit. - -const ( - mask = 0x7F - core = 0x80 - exited = 0x00 - stopped = 0x7F - shift = 8 -) - -func (w WaitStatus) Exited() bool { return w&mask == exited } - -func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != exited } - -func (w WaitStatus) Stopped() bool { return w&0xFF == stopped } - -func (w WaitStatus) Continued() bool { return w == 0xFFFF } - -func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 } - -func (w WaitStatus) ExitStatus() int { - if !w.Exited() { - return -1 - } - return int(w>>shift) & 0xFF -} - -func (w WaitStatus) Signal() Signal { - if !w.Signaled() { - return -1 - } - return Signal(w & mask) -} - -func (w WaitStatus) StopSignal() Signal { - if !w.Stopped() { - return -1 - } - return Signal(w>>shift) & 0xFF -} - -func (w WaitStatus) TrapCause() int { - if w.StopSignal() != SIGTRAP { - return -1 - } - return int(w>>shift) >> 8 -} - -//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) - -func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) { - var status _C_int - wpid, err = wait4(pid, &status, options, rusage) - if wstatus != nil { - *wstatus = WaitStatus(status) - } - return -} - -func Mkfifo(path string, mode uint32) (err error) { - return Mknod(path, mode|S_IFIFO, 0) -} - -func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { - if sa.Port < 0 || sa.Port > 0xFFFF { - return nil, 0, EINVAL - } - sa.raw.Family = AF_INET - p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) - p[0] = byte(sa.Port >> 8) - p[1] = byte(sa.Port) - sa.raw.Addr = sa.Addr - return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil -} - -func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { - if sa.Port < 0 || sa.Port > 0xFFFF { - return nil, 0, EINVAL - } - sa.raw.Family = AF_INET6 - p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) - p[0] = byte(sa.Port >> 8) - p[1] = byte(sa.Port) - sa.raw.Scope_id = sa.ZoneId - sa.raw.Addr = sa.Addr - return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil -} - -func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) { - name := sa.Name - n := len(name) - if n > len(sa.raw.Path) { - return nil, 0, EINVAL - } - if n == len(sa.raw.Path) && name[0] != '@' { - return nil, 0, EINVAL - } - sa.raw.Family = AF_UNIX - for i := 0; i < n; i++ { - sa.raw.Path[i] = int8(name[i]) - } - // length is family (uint16), name, NUL. - sl := _Socklen(2) - if n > 0 { - sl += _Socklen(n) + 1 - } - if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) { - // Check sl > 3 so we don't change unnamed socket behavior. - sa.raw.Path[0] = 0 - // Don't count trailing NUL for abstract address. - sl-- - } - - return unsafe.Pointer(&sa.raw), sl, nil -} - -type SockaddrLinklayer struct { - Protocol uint16 - Ifindex int - Hatype uint16 - Pkttype uint8 - Halen uint8 - Addr [8]byte - raw RawSockaddrLinklayer -} - -func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) { - if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff { - return nil, 0, EINVAL - } - sa.raw.Family = AF_PACKET - sa.raw.Protocol = sa.Protocol - sa.raw.Ifindex = int32(sa.Ifindex) - sa.raw.Hatype = sa.Hatype - sa.raw.Pkttype = sa.Pkttype - sa.raw.Halen = sa.Halen - sa.raw.Addr = sa.Addr - return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil -} - -type SockaddrNetlink struct { - Family uint16 - Pad uint16 - Pid uint32 - Groups uint32 - raw RawSockaddrNetlink -} - -func (sa *SockaddrNetlink) sockaddr() (unsafe.Pointer, _Socklen, error) { - sa.raw.Family = AF_NETLINK - sa.raw.Pad = sa.Pad - sa.raw.Pid = sa.Pid - sa.raw.Groups = sa.Groups - return unsafe.Pointer(&sa.raw), SizeofSockaddrNetlink, nil -} - -func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) { - switch rsa.Addr.Family { - case AF_NETLINK: - pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa)) - sa := new(SockaddrNetlink) - sa.Family = pp.Family - sa.Pad = pp.Pad - sa.Pid = pp.Pid - sa.Groups = pp.Groups - return sa, nil - - case AF_PACKET: - pp := (*RawSockaddrLinklayer)(unsafe.Pointer(rsa)) - sa := new(SockaddrLinklayer) - sa.Protocol = pp.Protocol - sa.Ifindex = int(pp.Ifindex) - sa.Hatype = pp.Hatype - sa.Pkttype = pp.Pkttype - sa.Halen = pp.Halen - sa.Addr = pp.Addr - return sa, nil - - case AF_UNIX: - pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa)) - sa := new(SockaddrUnix) - if pp.Path[0] == 0 { - // "Abstract" Unix domain socket. - // Rewrite leading NUL as @ for textual display. - // (This is the standard convention.) - // Not friendly to overwrite in place, - // but the callers below don't care. - pp.Path[0] = '@' - } - - // Assume path ends at NUL. - // This is not technically the Linux semantics for - // abstract Unix domain sockets--they are supposed - // to be uninterpreted fixed-size binary blobs--but - // everyone uses this convention. - n := 0 - for n < len(pp.Path) && pp.Path[n] != 0 { - n++ - } - sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n)) - return sa, nil - - case AF_INET: - pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) - sa := new(SockaddrInet4) - p := (*[2]byte)(unsafe.Pointer(&pp.Port)) - sa.Port = int(p[0])<<8 + int(p[1]) - sa.Addr = pp.Addr - return sa, nil - - case AF_INET6: - pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)) - sa := new(SockaddrInet6) - p := (*[2]byte)(unsafe.Pointer(&pp.Port)) - sa.Port = int(p[0])<<8 + int(p[1]) - sa.ZoneId = pp.Scope_id - sa.Addr = pp.Addr - return sa, nil - } - return nil, EAFNOSUPPORT -} - -func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) { - var rsa RawSockaddrAny - var len _Socklen = SizeofSockaddrAny - nfd, err = accept4(fd, &rsa, &len, flags) - if err != nil { - return - } - if len > SizeofSockaddrAny { - panic("RawSockaddrAny too small") - } - sa, err = anyToSockaddr(&rsa) - if err != nil { - Close(nfd) - nfd = 0 - } - return -} - -func Getsockname(fd int) (sa Sockaddr, err error) { - var rsa RawSockaddrAny - var len _Socklen = SizeofSockaddrAny - if err = getsockname(fd, &rsa, &len); err != nil { - return - } - return anyToSockaddr(&rsa) -} - -func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) { - vallen := _Socklen(4) - err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) - return value, err -} - -func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) { - var value IPMreq - vallen := _Socklen(SizeofIPMreq) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) { - var value IPMreqn - vallen := _Socklen(SizeofIPMreqn) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) { - var value IPv6Mreq - vallen := _Socklen(SizeofIPv6Mreq) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) { - var value IPv6MTUInfo - vallen := _Socklen(SizeofIPv6MTUInfo) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) { - var value ICMPv6Filter - vallen := _Socklen(SizeofICMPv6Filter) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptUcred(fd, level, opt int) (*Ucred, error) { - var value Ucred - vallen := _Socklen(SizeofUcred) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) { - return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) -} - -func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) { - var msg Msghdr - msg.Name = (*byte)(unsafe.Pointer(rsa)) - msg.Namelen = uint32(SizeofSockaddrAny) - var iov Iovec - if len(p) > 0 { - iov.Base = &p[0] - iov.SetLen(len(p)) - } - var dummy byte - if len(oob) > 0 { - if len(p) == 0 { - var sockType int - sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) - if err != nil { - return - } - // receive at least one normal byte - if sockType != SOCK_DGRAM { - iov.Base = &dummy - iov.SetLen(1) - } - } - msg.Control = &oob[0] - msg.SetControllen(len(oob)) - } - msg.Iov = &iov - msg.Iovlen = 1 - if n, err = recvmsg(fd, &msg, flags); err != nil { - return - } - oobn = int(msg.Controllen) - recvflags = int(msg.Flags) - return -} - -func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) { - var msg Msghdr - msg.Name = (*byte)(ptr) - msg.Namelen = uint32(salen) - var iov Iovec - if len(p) > 0 { - iov.Base = &p[0] - iov.SetLen(len(p)) - } - var dummy byte - if len(oob) > 0 { - if len(p) == 0 { - var sockType int - sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) - if err != nil { - return 0, err - } - // send at least one normal byte - if sockType != SOCK_DGRAM { - iov.Base = &dummy - iov.SetLen(1) - } - } - msg.Control = &oob[0] - msg.SetControllen(len(oob)) - } - msg.Iov = &iov - msg.Iovlen = 1 - if n, err = sendmsg(fd, &msg, flags); err != nil { - return 0, err - } - if len(oob) > 0 && len(p) == 0 { - n = 0 - } - return n, nil -} - -// BindToDevice binds the socket associated with fd to device. -func BindToDevice(fd int, device string) (err error) { - return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device) -} - -//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) -//sys ptracePtr(request int, pid int, addr uintptr, data unsafe.Pointer) (err error) = SYS_PTRACE - -func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err error) { - // The peek requests are machine-size oriented, so we wrap it - // to retrieve arbitrary-length data. - - // The ptrace syscall differs from glibc's ptrace. - // Peeks returns the word in *data, not as the return value. - - var buf [sizeofPtr]byte - - // Leading edge. PEEKTEXT/PEEKDATA don't require aligned - // access (PEEKUSER warns that it might), but if we don't - // align our reads, we might straddle an unmapped page - // boundary and not get the bytes leading up to the page - // boundary. - n := 0 - if addr%sizeofPtr != 0 { - err = ptracePtr(req, pid, addr-addr%sizeofPtr, unsafe.Pointer(&buf[0])) - if err != nil { - return 0, err - } - n += copy(out, buf[addr%sizeofPtr:]) - out = out[n:] - } - - // Remainder. - for len(out) > 0 { - // We use an internal buffer to guarantee alignment. - // It's not documented if this is necessary, but we're paranoid. - err = ptracePtr(req, pid, addr+uintptr(n), unsafe.Pointer(&buf[0])) - if err != nil { - return n, err - } - copied := copy(out, buf[0:]) - n += copied - out = out[copied:] - } - - return n, nil -} - -func PtracePeekText(pid int, addr uintptr, out []byte) (count int, err error) { - return ptracePeek(PTRACE_PEEKTEXT, pid, addr, out) -} - -func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) { - return ptracePeek(PTRACE_PEEKDATA, pid, addr, out) -} - -func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, err error) { - // As for ptracePeek, we need to align our accesses to deal - // with the possibility of straddling an invalid page. - - // Leading edge. - n := 0 - if addr%sizeofPtr != 0 { - var buf [sizeofPtr]byte - err = ptracePtr(peekReq, pid, addr-addr%sizeofPtr, unsafe.Pointer(&buf[0])) - if err != nil { - return 0, err - } - n += copy(buf[addr%sizeofPtr:], data) - word := *((*uintptr)(unsafe.Pointer(&buf[0]))) - err = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word) - if err != nil { - return 0, err - } - data = data[n:] - } - - // Interior. - for len(data) > sizeofPtr { - word := *((*uintptr)(unsafe.Pointer(&data[0]))) - err = ptrace(pokeReq, pid, addr+uintptr(n), word) - if err != nil { - return n, err - } - n += sizeofPtr - data = data[sizeofPtr:] - } - - // Trailing edge. - if len(data) > 0 { - var buf [sizeofPtr]byte - err = ptracePtr(peekReq, pid, addr+uintptr(n), unsafe.Pointer(&buf[0])) - if err != nil { - return n, err - } - copy(buf[0:], data) - word := *((*uintptr)(unsafe.Pointer(&buf[0]))) - err = ptrace(pokeReq, pid, addr+uintptr(n), word) - if err != nil { - return n, err - } - n += len(data) - } - - return n, nil -} - -func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) { - return ptracePoke(PTRACE_POKETEXT, PTRACE_PEEKTEXT, pid, addr, data) -} - -func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) { - return ptracePoke(PTRACE_POKEDATA, PTRACE_PEEKDATA, pid, addr, data) -} - -const ( - _NT_PRSTATUS = 1 -) - -func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) { - var iov Iovec - iov.Base = (*byte)(unsafe.Pointer(regsout)) - iov.SetLen(int(unsafe.Sizeof(*regsout))) - return ptracePtr(PTRACE_GETREGSET, pid, uintptr(_NT_PRSTATUS), unsafe.Pointer(&iov)) -} - -func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) { - var iov Iovec - iov.Base = (*byte)(unsafe.Pointer(regs)) - iov.SetLen(int(unsafe.Sizeof(*regs))) - return ptracePtr(PTRACE_SETREGSET, pid, uintptr(_NT_PRSTATUS), unsafe.Pointer(&iov)) -} - -func PtraceSetOptions(pid int, options int) (err error) { - return ptrace(PTRACE_SETOPTIONS, pid, 0, uintptr(options)) -} - -func PtraceGetEventMsg(pid int) (msg uint, err error) { - var data _C_long - err = ptracePtr(PTRACE_GETEVENTMSG, pid, 0, unsafe.Pointer(&data)) - msg = uint(data) - return -} - -func PtraceCont(pid int, signal int) (err error) { - return ptrace(PTRACE_CONT, pid, 0, uintptr(signal)) -} - -func PtraceSyscall(pid int, signal int) (err error) { - return ptrace(PTRACE_SYSCALL, pid, 0, uintptr(signal)) -} - -func PtraceSingleStep(pid int) (err error) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) } - -func PtraceAttach(pid int) (err error) { return ptrace(PTRACE_ATTACH, pid, 0, 0) } - -func PtraceDetach(pid int) (err error) { return ptrace(PTRACE_DETACH, pid, 0, 0) } - -//sys reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) - -func Reboot(cmd int) (err error) { - return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "") -} - -func ReadDirent(fd int, buf []byte) (n int, err error) { - return Getdents(fd, buf) -} - -func direntIno(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) -} - -func direntReclen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) -} - -func direntNamlen(buf []byte) (uint64, bool) { - reclen, ok := direntReclen(buf) - if !ok { - return 0, false - } - return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true -} - -//sys mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) - -func Mount(source string, target string, fstype string, flags uintptr, data string) (err error) { - // Certain file systems get rather angry and EINVAL if you give - // them an empty string of data, rather than NULL. - if data == "" { - return mount(source, target, fstype, flags, nil) - } - datap, err := BytePtrFromString(data) - if err != nil { - return err - } - return mount(source, target, fstype, flags, datap) -} - -// Sendto -// Recvfrom -// Socketpair - -/* - * Direct access - */ -//sys Acct(path string) (err error) -//sys Adjtimex(buf *Timex) (state int, err error) -//sys Chdir(path string) (err error) -//sys Chroot(path string) (err error) -//sys Close(fd int) (err error) -//sys Dup(oldfd int) (fd int, err error) -//sys Dup3(oldfd int, newfd int, flags int) (err error) -//sysnb EpollCreate1(flag int) (fd int, err error) -//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) -//sys Fallocate(fd int, mode uint32, off int64, len int64) (err error) -//sys Fchdir(fd int) (err error) -//sys Fchmod(fd int, mode uint32) (err error) -//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) -//sys fcntl(fd int, cmd int, arg int) (val int, err error) -//sys Fdatasync(fd int) (err error) -//sys Flock(fd int, how int) (err error) -//sys Fsync(fd int) (err error) -//sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64 -//sysnb Getpgid(pid int) (pgid int, err error) - -func Getpgrp() (pid int) { - pid, _ = Getpgid(0) - return -} - -//sysnb Getpid() (pid int) -//sysnb Getppid() (ppid int) -//sys Getpriority(which int, who int) (prio int, err error) -//sysnb Getrusage(who int, rusage *Rusage) (err error) -//sysnb Gettid() (tid int) -//sys Getxattr(path string, attr string, dest []byte) (sz int, err error) -//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) -//sysnb InotifyInit1(flags int) (fd int, err error) -//sysnb InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) -//sysnb Kill(pid int, sig Signal) (err error) -//sys Klogctl(typ int, buf []byte) (n int, err error) = SYS_SYSLOG -//sys Listxattr(path string, dest []byte) (sz int, err error) -//sys Mkdirat(dirfd int, path string, mode uint32) (err error) -//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error) -//sys Nanosleep(time *Timespec, leftover *Timespec) (err error) -//sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT -//sysnb prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64 -//sys read(fd int, p []byte) (n int, err error) -//sys Removexattr(path string, attr string) (err error) -//sys Setdomainname(p []byte) (err error) -//sys Sethostname(p []byte) (err error) -//sysnb Setpgid(pid int, pgid int) (err error) -//sysnb Setsid() (pid int, err error) -//sysnb Settimeofday(tv *Timeval) (err error) - -// Provided by runtime.syscall_runtime_doAllThreadsSyscall which stops the -// world and invokes the syscall on each OS thread. Once this function returns, -// all threads are in sync. -// -//go:uintptrescapes -func runtime_doAllThreadsSyscall(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) - -// AllThreadsSyscall performs a syscall on each OS thread of the Go -// runtime. It first invokes the syscall on one thread. Should that -// invocation fail, it returns immediately with the error status. -// Otherwise, it invokes the syscall on all of the remaining threads -// in parallel. It will terminate the program if it observes any -// invoked syscall's return value differs from that of the first -// invocation. -// -// AllThreadsSyscall is intended for emulating simultaneous -// process-wide state changes that require consistently modifying -// per-thread state of the Go runtime. -// -// AllThreadsSyscall is unaware of any threads that are launched -// explicitly by cgo linked code, so the function always returns -// ENOTSUP in binaries that use cgo. -// -//go:uintptrescapes -func AllThreadsSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { - if cgo_libc_setegid != nil { - return minus1, minus1, ENOTSUP - } - r1, r2, errno := runtime_doAllThreadsSyscall(trap, a1, a2, a3, 0, 0, 0) - return r1, r2, Errno(errno) -} - -// AllThreadsSyscall6 is like AllThreadsSyscall, but extended to six -// arguments. -// -//go:uintptrescapes -func AllThreadsSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { - if cgo_libc_setegid != nil { - return minus1, minus1, ENOTSUP - } - r1, r2, errno := runtime_doAllThreadsSyscall(trap, a1, a2, a3, a4, a5, a6) - return r1, r2, Errno(errno) -} - -// linked by runtime.cgocall.go -// -//go:uintptrescapes -func cgocaller(unsafe.Pointer, ...uintptr) uintptr - -var cgo_libc_setegid unsafe.Pointer // non-nil if cgo linked. - -const minus1 = ^uintptr(0) - -func Setegid(egid int) (err error) { - if cgo_libc_setegid == nil { - if _, _, e1 := AllThreadsSyscall(SYS_SETRESGID, minus1, uintptr(egid), minus1); e1 != 0 { - err = errnoErr(e1) - } - } else if ret := cgocaller(cgo_libc_setegid, uintptr(egid)); ret != 0 { - err = errnoErr(Errno(ret)) - } - return -} - -var cgo_libc_seteuid unsafe.Pointer // non-nil if cgo linked. - -func Seteuid(euid int) (err error) { - if cgo_libc_seteuid == nil { - if _, _, e1 := AllThreadsSyscall(SYS_SETRESUID, minus1, uintptr(euid), minus1); e1 != 0 { - err = errnoErr(e1) - } - } else if ret := cgocaller(cgo_libc_seteuid, uintptr(euid)); ret != 0 { - err = errnoErr(Errno(ret)) - } - return -} - -var cgo_libc_setgid unsafe.Pointer // non-nil if cgo linked. - -func Setgid(gid int) (err error) { - if cgo_libc_setgid == nil { - if _, _, e1 := AllThreadsSyscall(sys_SETGID, uintptr(gid), 0, 0); e1 != 0 { - err = errnoErr(e1) - } - } else if ret := cgocaller(cgo_libc_setgid, uintptr(gid)); ret != 0 { - err = errnoErr(Errno(ret)) - } - return -} - -var cgo_libc_setregid unsafe.Pointer // non-nil if cgo linked. - -func Setregid(rgid, egid int) (err error) { - if cgo_libc_setregid == nil { - if _, _, e1 := AllThreadsSyscall(sys_SETREGID, uintptr(rgid), uintptr(egid), 0); e1 != 0 { - err = errnoErr(e1) - } - } else if ret := cgocaller(cgo_libc_setregid, uintptr(rgid), uintptr(egid)); ret != 0 { - err = errnoErr(Errno(ret)) - } - return -} - -var cgo_libc_setresgid unsafe.Pointer // non-nil if cgo linked. - -func Setresgid(rgid, egid, sgid int) (err error) { - if cgo_libc_setresgid == nil { - if _, _, e1 := AllThreadsSyscall(sys_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)); e1 != 0 { - err = errnoErr(e1) - } - } else if ret := cgocaller(cgo_libc_setresgid, uintptr(rgid), uintptr(egid), uintptr(sgid)); ret != 0 { - err = errnoErr(Errno(ret)) - } - return -} - -var cgo_libc_setresuid unsafe.Pointer // non-nil if cgo linked. - -func Setresuid(ruid, euid, suid int) (err error) { - if cgo_libc_setresuid == nil { - if _, _, e1 := AllThreadsSyscall(sys_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)); e1 != 0 { - err = errnoErr(e1) - } - } else if ret := cgocaller(cgo_libc_setresuid, uintptr(ruid), uintptr(euid), uintptr(suid)); ret != 0 { - err = errnoErr(Errno(ret)) - } - return -} - -var cgo_libc_setreuid unsafe.Pointer // non-nil if cgo linked. - -func Setreuid(ruid, euid int) (err error) { - if cgo_libc_setreuid == nil { - if _, _, e1 := AllThreadsSyscall(sys_SETREUID, uintptr(ruid), uintptr(euid), 0); e1 != 0 { - err = errnoErr(e1) - } - } else if ret := cgocaller(cgo_libc_setreuid, uintptr(ruid), uintptr(euid)); ret != 0 { - err = errnoErr(Errno(ret)) - } - return -} - -var cgo_libc_setuid unsafe.Pointer // non-nil if cgo linked. - -func Setuid(uid int) (err error) { - if cgo_libc_setuid == nil { - if _, _, e1 := AllThreadsSyscall(sys_SETUID, uintptr(uid), 0, 0); e1 != 0 { - err = errnoErr(e1) - } - } else if ret := cgocaller(cgo_libc_setuid, uintptr(uid)); ret != 0 { - err = errnoErr(Errno(ret)) - } - return -} - -//sys Setpriority(which int, who int, prio int) (err error) -//sys Setxattr(path string, attr string, data []byte, flags int) (err error) -//sys Sync() -//sysnb Sysinfo(info *Sysinfo_t) (err error) -//sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error) -//sysnb Tgkill(tgid int, tid int, sig Signal) (err error) -//sysnb Times(tms *Tms) (ticks uintptr, err error) -//sysnb Umask(mask int) (oldmask int) -//sysnb Uname(buf *Utsname) (err error) -//sys Unmount(target string, flags int) (err error) = SYS_UMOUNT2 -//sys Unshare(flags int) (err error) -//sys write(fd int, p []byte) (n int, err error) -//sys exitThread(code int) (err error) = SYS_EXIT -//sys readlen(fd int, p *byte, np int) (n int, err error) = SYS_READ - -// mmap varies by architecture; see syscall_linux_*.go. -//sys munmap(addr uintptr, length uintptr) (err error) - -var mapper = &mmapper{ - active: make(map[*byte][]byte), - mmap: mmap, - munmap: munmap, -} - -func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { - return mapper.Mmap(fd, offset, length, prot, flags) -} - -func Munmap(b []byte) (err error) { - return mapper.Munmap(b) -} - -//sys Madvise(b []byte, advice int) (err error) -//sys Mprotect(b []byte, prot int) (err error) -//sys Mlock(b []byte) (err error) -//sys Munlock(b []byte) (err error) -//sys Mlockall(flags int) (err error) -//sys Munlockall() (err error) - -// prlimit changes a resource limit. We use a single definition so that -// we can tell StartProcess to not restore the original NOFILE limit. -// This is unexported but can be called from x/sys/unix. -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { - err = prlimit1(pid, resource, newlimit, old) - if err == nil && newlimit != nil && resource == RLIMIT_NOFILE { - origRlimitNofile.Store(nil) - } - return err -} diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_libc.go b/contrib/go/_std_1.22/src/syscall/syscall_openbsd_libc.go deleted file mode 100644 index ddf62f4d3f4f..000000000000 --- a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_libc.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build openbsd && !mips64 - -package syscall - -import ( - "internal/abi" -) - -var dupTrampoline = abi.FuncPCABI0(libc_dup3_trampoline) - -func init() { - execveOpenBSD = execve -} - -//sys directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) = SYS_syscall - -func syscallInternal(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { - return syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, 0, 0) -} - -func syscall6Internal(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { - return syscall10X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, a4, a5, a6, 0, 0, 0) -} - -func rawSyscallInternal(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { - return rawSyscall6X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, 0, 0) -} - -func rawSyscall6Internal(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { - return rawSyscall10X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, a4, a5, a6, 0, 0, 0) -} - -func syscall9Internal(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) { - return rawSyscall10X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, a4, a5, a6, a7, a8, a9) -} - -// Implemented in the runtime package (runtime/sys_openbsd3.go) -func syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) -func syscallX(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) -func syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) -func syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) -func syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno) -func syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno) -func rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) -func rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) -func rawSyscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) -func rawSyscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno) - -func syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) { - return syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, 0) -} -func syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) { - return syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, 0) -} - -//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_read -//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_lseek -//sys getcwd(buf []byte) (n int, err error) -//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) -//sysnb fork() (pid int, err error) -//sysnb execve(path *byte, argv **byte, envp **byte) (err error) -//sysnb exit(res int) (err error) -//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) -//sysnb getentropy(p []byte) (err error) -//sys fstatat(fd int, path string, stat *Stat_t, flags int) (err error) -//sys unlinkat(fd int, path string, flags int) (err error) -//sys openat(fd int, path string, flags int, perm uint32) (fdret int, err error) diff --git a/contrib/go/_std_1.22/src/syscall/syscall_windows.go b/contrib/go/_std_1.22/src/syscall/syscall_windows.go deleted file mode 100644 index d13acc5c441b..000000000000 --- a/contrib/go/_std_1.22/src/syscall/syscall_windows.go +++ /dev/null @@ -1,1449 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Windows system calls. - -package syscall - -import ( - errorspkg "errors" - "internal/bytealg" - "internal/itoa" - "internal/oserror" - "internal/race" - "runtime" - "sync" - "unsafe" -) - -type Handle uintptr - -const InvalidHandle = ^Handle(0) - -// StringToUTF16 returns the UTF-16 encoding of the UTF-8 string s, -// with a terminating NUL added. If s contains a NUL byte this -// function panics instead of returning an error. -// -// Deprecated: Use UTF16FromString instead. -func StringToUTF16(s string) []uint16 { - a, err := UTF16FromString(s) - if err != nil { - panic("syscall: string with NUL passed to StringToUTF16") - } - return a -} - -// UTF16FromString returns the UTF-16 encoding of the UTF-8 string -// s, with a terminating NUL added. If s contains a NUL byte at any -// location, it returns (nil, EINVAL). Unpaired surrogates -// are encoded using WTF-8. -func UTF16FromString(s string) ([]uint16, error) { - if bytealg.IndexByteString(s, 0) != -1 { - return nil, EINVAL - } - // Valid UTF-8 characters between 1 and 3 bytes require one uint16. - // Valid UTF-8 characters of 4 bytes require two uint16. - // Bytes with invalid UTF-8 encoding require maximum one uint16 per byte. - // So the number of UTF-8 code units (len(s)) is always greater or - // equal than the number of UTF-16 code units. - // Also account for the terminating NUL character. - buf := make([]uint16, 0, len(s)+1) - buf = encodeWTF16(s, buf) - return append(buf, 0), nil -} - -// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s, -// with a terminating NUL removed. Unpaired surrogates are decoded -// using WTF-8 instead of UTF-8 encoding. -func UTF16ToString(s []uint16) string { - maxLen := 0 - for i, v := range s { - if v == 0 { - s = s[0:i] - break - } - switch { - case v <= rune1Max: - maxLen += 1 - case v <= rune2Max: - maxLen += 2 - default: - // r is a non-surrogate that decodes to 3 bytes, - // or is an unpaired surrogate (also 3 bytes in WTF-8), - // or is one half of a valid surrogate pair. - // If it is half of a pair, we will add 3 for the second surrogate - // (total of 6) and overestimate by 2 bytes for the pair, - // since the resulting rune only requires 4 bytes. - maxLen += 3 - } - } - buf := decodeWTF16(s, make([]byte, 0, maxLen)) - return unsafe.String(unsafe.SliceData(buf), len(buf)) -} - -// utf16PtrToString is like UTF16ToString, but takes *uint16 -// as a parameter instead of []uint16. -func utf16PtrToString(p *uint16) string { - if p == nil { - return "" - } - end := unsafe.Pointer(p) - n := 0 - for *(*uint16)(end) != 0 { - end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p)) - n++ - } - return UTF16ToString(unsafe.Slice(p, n)) -} - -// StringToUTF16Ptr returns pointer to the UTF-16 encoding of -// the UTF-8 string s, with a terminating NUL added. If s -// contains a NUL byte this function panics instead of -// returning an error. -// -// Deprecated: Use UTF16PtrFromString instead. -func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] } - -// UTF16PtrFromString returns pointer to the UTF-16 encoding of -// the UTF-8 string s, with a terminating NUL added. If s -// contains a NUL byte at any location, it returns (nil, EINVAL). -// Unpaired surrogates are encoded using WTF-8. -func UTF16PtrFromString(s string) (*uint16, error) { - a, err := UTF16FromString(s) - if err != nil { - return nil, err - } - return &a[0], nil -} - -// Errno is the Windows error number. -// -// Errno values can be tested against error values using errors.Is. -// For example: -// -// _, _, err := syscall.Syscall(...) -// if errors.Is(err, fs.ErrNotExist) ... -type Errno uintptr - -func langid(pri, sub uint16) uint32 { return uint32(sub)<<10 | uint32(pri) } - -// FormatMessage is deprecated (msgsrc should be uintptr, not uint32, but can -// not be changed due to the Go 1 compatibility guarantee). -// -// Deprecated: Use FormatMessage from golang.org/x/sys/windows instead. -func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) { - return formatMessage(flags, uintptr(msgsrc), msgid, langid, buf, args) -} - -func (e Errno) Error() string { - // deal with special go errors - idx := int(e - APPLICATION_ERROR) - if 0 <= idx && idx < len(errors) { - return errors[idx] - } - // ask windows for the remaining errors - var flags uint32 = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_IGNORE_INSERTS - b := make([]uint16, 300) - n, err := formatMessage(flags, 0, uint32(e), langid(LANG_ENGLISH, SUBLANG_ENGLISH_US), b, nil) - if err != nil { - n, err = formatMessage(flags, 0, uint32(e), 0, b, nil) - if err != nil { - return "winapi error #" + itoa.Itoa(int(e)) - } - } - // trim terminating \r and \n - for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- { - } - return UTF16ToString(b[:n]) -} - -const ( - _ERROR_NOT_ENOUGH_MEMORY = Errno(8) - _ERROR_NOT_SUPPORTED = Errno(50) - _ERROR_BAD_NETPATH = Errno(53) - _ERROR_CALL_NOT_IMPLEMENTED = Errno(120) -) - -func (e Errno) Is(target error) bool { - switch target { - case oserror.ErrPermission: - return e == ERROR_ACCESS_DENIED || - e == EACCES || - e == EPERM - case oserror.ErrExist: - return e == ERROR_ALREADY_EXISTS || - e == ERROR_DIR_NOT_EMPTY || - e == ERROR_FILE_EXISTS || - e == EEXIST || - e == ENOTEMPTY - case oserror.ErrNotExist: - return e == ERROR_FILE_NOT_FOUND || - e == _ERROR_BAD_NETPATH || - e == ERROR_PATH_NOT_FOUND || - e == ENOENT - case errorspkg.ErrUnsupported: - return e == _ERROR_NOT_SUPPORTED || - e == _ERROR_CALL_NOT_IMPLEMENTED || - e == ENOSYS || - e == ENOTSUP || - e == EOPNOTSUPP || - e == EWINDOWS - } - return false -} - -func (e Errno) Temporary() bool { - return e == EINTR || e == EMFILE || e.Timeout() -} - -func (e Errno) Timeout() bool { - return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT -} - -// Implemented in runtime/syscall_windows.go. -func compileCallback(fn any, cleanstack bool) uintptr - -// NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention. -// This is useful when interoperating with Windows code requiring callbacks. -// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. -// Only a limited number of callbacks may be created in a single Go process, and any memory allocated -// for these callbacks is never released. -// Between NewCallback and NewCallbackCDecl, at least 1024 callbacks can always be created. -func NewCallback(fn any) uintptr { - return compileCallback(fn, true) -} - -// NewCallbackCDecl converts a Go function to a function pointer conforming to the cdecl calling convention. -// This is useful when interoperating with Windows code requiring callbacks. -// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. -// Only a limited number of callbacks may be created in a single Go process, and any memory allocated -// for these callbacks is never released. -// Between NewCallback and NewCallbackCDecl, at least 1024 callbacks can always be created. -func NewCallbackCDecl(fn any) uintptr { - return compileCallback(fn, false) -} - -// windows api calls - -//sys GetLastError() (lasterr error) -//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW -//sys FreeLibrary(handle Handle) (err error) -//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error) -//sys GetVersion() (ver uint32, err error) -//sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers -//sys formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW -//sys ExitProcess(exitcode uint32) -//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW -//sys readFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) = ReadFile -//sys writeFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) = WriteFile -//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff] -//sys CloseHandle(handle Handle) (err error) -//sys GetStdHandle(stdhandle int) (handle Handle, err error) [failretval==InvalidHandle] -//sys findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstFileW -//sys findNextFile1(handle Handle, data *win32finddata1) (err error) = FindNextFileW -//sys FindClose(handle Handle) (err error) -//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) -//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW -//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW -//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW -//sys RemoveDirectory(path *uint16) (err error) = RemoveDirectoryW -//sys DeleteFile(path *uint16) (err error) = DeleteFileW -//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW -//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW -//sys SetEndOfFile(handle Handle) (err error) -//sys GetSystemTimeAsFileTime(time *Filetime) -//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] -//sys createIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) = CreateIoCompletionPort -//sys getQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) = GetQueuedCompletionStatus -//sys postQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) = PostQueuedCompletionStatus -//sys CancelIo(s Handle) (err error) -//sys CancelIoEx(s Handle, o *Overlapped) (err error) -//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW -//sys CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = advapi32.CreateProcessAsUserW -//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) -//sys TerminateProcess(handle Handle, exitcode uint32) (err error) -//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) -//sys getStartupInfo(startupInfo *StartupInfo) = GetStartupInfoW -//sys GetCurrentProcess() (pseudoHandle Handle, err error) -//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) -//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) -//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff] -//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW -//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) -//sys GetFileType(filehandle Handle) (n uint32, err error) -//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW -//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext -//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom -//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW -//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW -//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW -//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW -//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) -//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW -//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW -//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW -//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW -//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW -//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0] -//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) -//sys FlushFileBuffers(handle Handle) (err error) -//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW -//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW -//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW -//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW -//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) -//sys UnmapViewOfFile(addr uintptr) (err error) -//sys FlushViewOfFile(addr uintptr, length uintptr) (err error) -//sys VirtualLock(addr uintptr, length uintptr) (err error) -//sys VirtualUnlock(addr uintptr, length uintptr) (err error) -//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile -//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW -//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW -//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) = crypt32.CertOpenStore -//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore -//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore -//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore -//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain -//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain -//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext -//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext -//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy -//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW -//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey -//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW -//sys regEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW -//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW -//sys getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId -//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode -//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW -//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW -//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot -//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW -//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW -//sys DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) -// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL. -//sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW -//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW -//sys initializeProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, attrcount uint32, flags uint32, size *uintptr) (err error) = InitializeProcThreadAttributeList -//sys deleteProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST) = DeleteProcThreadAttributeList -//sys updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) = UpdateProcThreadAttribute -//sys getFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) [n == 0 || n >= filePathSize] = kernel32.GetFinalPathNameByHandleW - -// syscall interface implementation for other packages - -func makeInheritSa() *SecurityAttributes { - var sa SecurityAttributes - sa.Length = uint32(unsafe.Sizeof(sa)) - sa.InheritHandle = 1 - return &sa -} - -func Open(path string, mode int, perm uint32) (fd Handle, err error) { - if len(path) == 0 { - return InvalidHandle, ERROR_FILE_NOT_FOUND - } - pathp, err := UTF16PtrFromString(path) - if err != nil { - return InvalidHandle, err - } - var access uint32 - switch mode & (O_RDONLY | O_WRONLY | O_RDWR) { - case O_RDONLY: - access = GENERIC_READ - case O_WRONLY: - access = GENERIC_WRITE - case O_RDWR: - access = GENERIC_READ | GENERIC_WRITE - } - if mode&O_CREAT != 0 { - access |= GENERIC_WRITE - } - if mode&O_APPEND != 0 { - access &^= GENERIC_WRITE - access |= FILE_APPEND_DATA - } - sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE) - var sa *SecurityAttributes - if mode&O_CLOEXEC == 0 { - sa = makeInheritSa() - } - var createmode uint32 - switch { - case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL): - createmode = CREATE_NEW - case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC): - createmode = CREATE_ALWAYS - case mode&O_CREAT == O_CREAT: - createmode = OPEN_ALWAYS - case mode&O_TRUNC == O_TRUNC: - createmode = TRUNCATE_EXISTING - default: - createmode = OPEN_EXISTING - } - var attrs uint32 = FILE_ATTRIBUTE_NORMAL - if perm&S_IWRITE == 0 { - attrs = FILE_ATTRIBUTE_READONLY - if createmode == CREATE_ALWAYS { - // We have been asked to create a read-only file. - // If the file already exists, the semantics of - // the Unix open system call is to preserve the - // existing permissions. If we pass CREATE_ALWAYS - // and FILE_ATTRIBUTE_READONLY to CreateFile, - // and the file already exists, CreateFile will - // change the file permissions. - // Avoid that to preserve the Unix semantics. - h, e := CreateFile(pathp, access, sharemode, sa, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) - switch e { - case ERROR_FILE_NOT_FOUND, _ERROR_BAD_NETPATH, ERROR_PATH_NOT_FOUND: - // File does not exist. These are the same - // errors as Errno.Is checks for ErrNotExist. - // Carry on to create the file. - default: - // Success or some different error. - return h, e - } - } - } - if createmode == OPEN_EXISTING && access == GENERIC_READ { - // Necessary for opening directory handles. - attrs |= FILE_FLAG_BACKUP_SEMANTICS - } - if mode&O_SYNC != 0 { - const _FILE_FLAG_WRITE_THROUGH = 0x80000000 - attrs |= _FILE_FLAG_WRITE_THROUGH - } - return CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0) -} - -func Read(fd Handle, p []byte) (n int, err error) { - var done uint32 - e := ReadFile(fd, p, &done, nil) - if e != nil { - if e == ERROR_BROKEN_PIPE { - // NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin - return 0, nil - } - return 0, e - } - return int(done), nil -} - -func Write(fd Handle, p []byte) (n int, err error) { - var done uint32 - e := WriteFile(fd, p, &done, nil) - if e != nil { - return 0, e - } - return int(done), nil -} - -func ReadFile(fd Handle, p []byte, done *uint32, overlapped *Overlapped) error { - err := readFile(fd, p, done, overlapped) - if race.Enabled { - if *done > 0 { - race.WriteRange(unsafe.Pointer(&p[0]), int(*done)) - } - race.Acquire(unsafe.Pointer(&ioSync)) - } - if msanenabled && *done > 0 { - msanWrite(unsafe.Pointer(&p[0]), int(*done)) - } - if asanenabled && *done > 0 { - asanWrite(unsafe.Pointer(&p[0]), int(*done)) - } - return err -} - -func WriteFile(fd Handle, p []byte, done *uint32, overlapped *Overlapped) error { - if race.Enabled { - race.ReleaseMerge(unsafe.Pointer(&ioSync)) - } - err := writeFile(fd, p, done, overlapped) - if race.Enabled && *done > 0 { - race.ReadRange(unsafe.Pointer(&p[0]), int(*done)) - } - if msanenabled && *done > 0 { - msanRead(unsafe.Pointer(&p[0]), int(*done)) - } - if asanenabled && *done > 0 { - asanRead(unsafe.Pointer(&p[0]), int(*done)) - } - return err -} - -var ioSync int64 - -var procSetFilePointerEx = modkernel32.NewProc("SetFilePointerEx") - -const ptrSize = unsafe.Sizeof(uintptr(0)) - -// setFilePointerEx calls SetFilePointerEx. -// See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilepointerex -func setFilePointerEx(handle Handle, distToMove int64, newFilePointer *int64, whence uint32) error { - var e1 Errno - if unsafe.Sizeof(uintptr(0)) == 8 { - _, _, e1 = Syscall6(procSetFilePointerEx.Addr(), 4, uintptr(handle), uintptr(distToMove), uintptr(unsafe.Pointer(newFilePointer)), uintptr(whence), 0, 0) - } else { - // Different 32-bit systems disgaree about whether distToMove starts 8-byte aligned. - switch runtime.GOARCH { - default: - panic("unsupported 32-bit architecture") - case "386": - // distToMove is a LARGE_INTEGER, which is 64 bits. - _, _, e1 = Syscall6(procSetFilePointerEx.Addr(), 5, uintptr(handle), uintptr(distToMove), uintptr(distToMove>>32), uintptr(unsafe.Pointer(newFilePointer)), uintptr(whence), 0) - case "arm": - // distToMove must be 8-byte aligned per ARM calling convention - // https://docs.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions#stage-c-assignment-of-arguments-to-registers-and-stack - _, _, e1 = Syscall6(procSetFilePointerEx.Addr(), 6, uintptr(handle), 0, uintptr(distToMove), uintptr(distToMove>>32), uintptr(unsafe.Pointer(newFilePointer)), uintptr(whence)) - } - } - if e1 != 0 { - return errnoErr(e1) - } - return nil -} - -func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) { - var w uint32 - switch whence { - case 0: - w = FILE_BEGIN - case 1: - w = FILE_CURRENT - case 2: - w = FILE_END - } - err = setFilePointerEx(fd, offset, &newoffset, w) - return -} - -func Close(fd Handle) (err error) { - return CloseHandle(fd) -} - -var ( - Stdin = getStdHandle(STD_INPUT_HANDLE) - Stdout = getStdHandle(STD_OUTPUT_HANDLE) - Stderr = getStdHandle(STD_ERROR_HANDLE) -) - -func getStdHandle(h int) (fd Handle) { - r, _ := GetStdHandle(h) - return r -} - -const ImplementsGetwd = true - -func Getwd() (wd string, err error) { - b := make([]uint16, 300) - // The path of the current directory may not fit in the initial 300-word - // buffer when long path support is enabled. The current directory may also - // change between subsequent calls of GetCurrentDirectory. As a result, we - // need to retry the call in a loop until the current directory fits, each - // time with a bigger buffer. - for { - n, e := GetCurrentDirectory(uint32(len(b)), &b[0]) - if e != nil { - return "", e - } - if int(n) <= len(b) { - return UTF16ToString(b[:n]), nil - } - b = make([]uint16, n) - } -} - -func Chdir(path string) (err error) { - pathp, err := UTF16PtrFromString(path) - if err != nil { - return err - } - return SetCurrentDirectory(pathp) -} - -func Mkdir(path string, mode uint32) (err error) { - pathp, err := UTF16PtrFromString(path) - if err != nil { - return err - } - return CreateDirectory(pathp, nil) -} - -func Rmdir(path string) (err error) { - pathp, err := UTF16PtrFromString(path) - if err != nil { - return err - } - return RemoveDirectory(pathp) -} - -func Unlink(path string) (err error) { - pathp, err := UTF16PtrFromString(path) - if err != nil { - return err - } - return DeleteFile(pathp) -} - -func Rename(oldpath, newpath string) (err error) { - from, err := UTF16PtrFromString(oldpath) - if err != nil { - return err - } - to, err := UTF16PtrFromString(newpath) - if err != nil { - return err - } - return MoveFile(from, to) -} - -func ComputerName() (name string, err error) { - var n uint32 = MAX_COMPUTERNAME_LENGTH + 1 - b := make([]uint16, n) - e := GetComputerName(&b[0], &n) - if e != nil { - return "", e - } - return UTF16ToString(b[:n]), nil -} - -func Ftruncate(fd Handle, length int64) (err error) { - curoffset, e := Seek(fd, 0, 1) - if e != nil { - return e - } - defer Seek(fd, curoffset, 0) - _, e = Seek(fd, length, 0) - if e != nil { - return e - } - e = SetEndOfFile(fd) - if e != nil { - return e - } - return nil -} - -func Gettimeofday(tv *Timeval) (err error) { - var ft Filetime - GetSystemTimeAsFileTime(&ft) - *tv = NsecToTimeval(ft.Nanoseconds()) - return nil -} - -func Pipe(p []Handle) (err error) { - if len(p) != 2 { - return EINVAL - } - var r, w Handle - e := CreatePipe(&r, &w, makeInheritSa(), 0) - if e != nil { - return e - } - p[0] = r - p[1] = w - return nil -} - -func Utimes(path string, tv []Timeval) (err error) { - if len(tv) != 2 { - return EINVAL - } - pathp, e := UTF16PtrFromString(path) - if e != nil { - return e - } - h, e := CreateFile(pathp, - FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) - if e != nil { - return e - } - defer Close(h) - a := Filetime{} - w := Filetime{} - if tv[0].Nanoseconds() != 0 { - a = NsecToFiletime(tv[0].Nanoseconds()) - } - if tv[0].Nanoseconds() != 0 { - w = NsecToFiletime(tv[1].Nanoseconds()) - } - return SetFileTime(h, nil, &a, &w) -} - -// This matches the value in os/file_windows.go. -const _UTIME_OMIT = -1 - -func UtimesNano(path string, ts []Timespec) (err error) { - if len(ts) != 2 { - return EINVAL - } - pathp, e := UTF16PtrFromString(path) - if e != nil { - return e - } - h, e := CreateFile(pathp, - FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) - if e != nil { - return e - } - defer Close(h) - a := Filetime{} - w := Filetime{} - if ts[0].Nsec != _UTIME_OMIT { - a = NsecToFiletime(TimespecToNsec(ts[0])) - } - if ts[1].Nsec != _UTIME_OMIT { - w = NsecToFiletime(TimespecToNsec(ts[1])) - } - return SetFileTime(h, nil, &a, &w) -} - -func Fsync(fd Handle) (err error) { - return FlushFileBuffers(fd) -} - -func Chmod(path string, mode uint32) (err error) { - p, e := UTF16PtrFromString(path) - if e != nil { - return e - } - attrs, e := GetFileAttributes(p) - if e != nil { - return e - } - if mode&S_IWRITE != 0 { - attrs &^= FILE_ATTRIBUTE_READONLY - } else { - attrs |= FILE_ATTRIBUTE_READONLY - } - return SetFileAttributes(p, attrs) -} - -func LoadCancelIoEx() error { - return procCancelIoEx.Find() -} - -func LoadSetFileCompletionNotificationModes() error { - return procSetFileCompletionNotificationModes.Find() -} - -// net api calls - -const socket_error = uintptr(^uint32(0)) - -//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup -//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup -//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl -//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket -//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt -//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt -//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind -//sys connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect -//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname -//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername -//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen -//sys shutdown(s Handle, how int32) (err error) [failretval==socket_error] = ws2_32.shutdown -//sys Closesocket(s Handle) (err error) [failretval==socket_error] = ws2_32.closesocket -//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx -//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs -//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecv -//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASend -//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom -//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo -//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname -//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname -//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs -//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname -//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W -//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree -//sys DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) = dnsapi.DnsNameCompare_W -//sys GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW -//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW -//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry -//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo -//sys SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) = kernel32.SetFileCompletionNotificationModes -//sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW - -// For testing: clients can set this flag to force -// creation of IPv6 sockets to return EAFNOSUPPORT. -var SocketDisableIPv6 bool - -type RawSockaddrInet4 struct { - Family uint16 - Port uint16 - Addr [4]byte /* in_addr */ - Zero [8]uint8 -} - -type RawSockaddrInet6 struct { - Family uint16 - Port uint16 - Flowinfo uint32 - Addr [16]byte /* in6_addr */ - Scope_id uint32 -} - -type RawSockaddr struct { - Family uint16 - Data [14]int8 -} - -type RawSockaddrAny struct { - Addr RawSockaddr - Pad [100]int8 -} - -type Sockaddr interface { - sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs -} - -type SockaddrInet4 struct { - Port int - Addr [4]byte - raw RawSockaddrInet4 -} - -func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) { - if sa.Port < 0 || sa.Port > 0xFFFF { - return nil, 0, EINVAL - } - sa.raw.Family = AF_INET - p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) - p[0] = byte(sa.Port >> 8) - p[1] = byte(sa.Port) - sa.raw.Addr = sa.Addr - return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil -} - -type SockaddrInet6 struct { - Port int - ZoneId uint32 - Addr [16]byte - raw RawSockaddrInet6 -} - -func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) { - if sa.Port < 0 || sa.Port > 0xFFFF { - return nil, 0, EINVAL - } - sa.raw.Family = AF_INET6 - p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) - p[0] = byte(sa.Port >> 8) - p[1] = byte(sa.Port) - sa.raw.Scope_id = sa.ZoneId - sa.raw.Addr = sa.Addr - return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil -} - -type RawSockaddrUnix struct { - Family uint16 - Path [UNIX_PATH_MAX]int8 -} - -type SockaddrUnix struct { - Name string - raw RawSockaddrUnix -} - -func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) { - name := sa.Name - n := len(name) - if n > len(sa.raw.Path) { - return nil, 0, EINVAL - } - if n == len(sa.raw.Path) && name[0] != '@' { - return nil, 0, EINVAL - } - sa.raw.Family = AF_UNIX - for i := 0; i < n; i++ { - sa.raw.Path[i] = int8(name[i]) - } - // length is family (uint16), name, NUL. - sl := int32(2) - if n > 0 { - sl += int32(n) + 1 - } - if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) { - // Check sl > 3 so we don't change unnamed socket behavior. - sa.raw.Path[0] = 0 - // Don't count trailing NUL for abstract address. - sl-- - } - - return unsafe.Pointer(&sa.raw), sl, nil -} - -func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) { - switch rsa.Addr.Family { - case AF_UNIX: - pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa)) - sa := new(SockaddrUnix) - if pp.Path[0] == 0 { - // "Abstract" Unix domain socket. - // Rewrite leading NUL as @ for textual display. - // (This is the standard convention.) - // Not friendly to overwrite in place, - // but the callers below don't care. - pp.Path[0] = '@' - } - - // Assume path ends at NUL. - // This is not technically the Linux semantics for - // abstract Unix domain sockets--they are supposed - // to be uninterpreted fixed-size binary blobs--but - // everyone uses this convention. - n := 0 - for n < len(pp.Path) && pp.Path[n] != 0 { - n++ - } - sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n)) - return sa, nil - - case AF_INET: - pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) - sa := new(SockaddrInet4) - p := (*[2]byte)(unsafe.Pointer(&pp.Port)) - sa.Port = int(p[0])<<8 + int(p[1]) - sa.Addr = pp.Addr - return sa, nil - - case AF_INET6: - pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)) - sa := new(SockaddrInet6) - p := (*[2]byte)(unsafe.Pointer(&pp.Port)) - sa.Port = int(p[0])<<8 + int(p[1]) - sa.ZoneId = pp.Scope_id - sa.Addr = pp.Addr - return sa, nil - } - return nil, EAFNOSUPPORT -} - -func Socket(domain, typ, proto int) (fd Handle, err error) { - if domain == AF_INET6 && SocketDisableIPv6 { - return InvalidHandle, EAFNOSUPPORT - } - return socket(int32(domain), int32(typ), int32(proto)) -} - -func SetsockoptInt(fd Handle, level, opt int, value int) (err error) { - v := int32(value) - return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))) -} - -func Bind(fd Handle, sa Sockaddr) (err error) { - ptr, n, err := sa.sockaddr() - if err != nil { - return err - } - return bind(fd, ptr, n) -} - -func Connect(fd Handle, sa Sockaddr) (err error) { - ptr, n, err := sa.sockaddr() - if err != nil { - return err - } - return connect(fd, ptr, n) -} - -func Getsockname(fd Handle) (sa Sockaddr, err error) { - var rsa RawSockaddrAny - l := int32(unsafe.Sizeof(rsa)) - if err = getsockname(fd, &rsa, &l); err != nil { - return - } - return rsa.Sockaddr() -} - -func Getpeername(fd Handle) (sa Sockaddr, err error) { - var rsa RawSockaddrAny - l := int32(unsafe.Sizeof(rsa)) - if err = getpeername(fd, &rsa, &l); err != nil { - return - } - return rsa.Sockaddr() -} - -func Listen(s Handle, n int) (err error) { - return listen(s, int32(n)) -} - -func Shutdown(fd Handle, how int) (err error) { - return shutdown(fd, int32(how)) -} - -func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (err error) { - var rsa unsafe.Pointer - var len int32 - if to != nil { - rsa, len, err = to.sockaddr() - if err != nil { - return err - } - } - r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) - if r1 == socket_error { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = EINVAL - } - } - return err -} - -func wsaSendtoInet4(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *SockaddrInet4, overlapped *Overlapped, croutine *byte) (err error) { - rsa, len, err := to.sockaddr() - if err != nil { - return err - } - r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) - if r1 == socket_error { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = EINVAL - } - } - return err -} - -func wsaSendtoInet6(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *SockaddrInet6, overlapped *Overlapped, croutine *byte) (err error) { - rsa, len, err := to.sockaddr() - if err != nil { - return err - } - r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) - if r1 == socket_error { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = EINVAL - } - } - return err -} - -func LoadGetAddrInfo() error { - return procGetAddrInfoW.Find() -} - -var connectExFunc struct { - once sync.Once - addr uintptr - err error -} - -func LoadConnectEx() error { - connectExFunc.once.Do(func() { - var s Handle - s, connectExFunc.err = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) - if connectExFunc.err != nil { - return - } - defer CloseHandle(s) - var n uint32 - connectExFunc.err = WSAIoctl(s, - SIO_GET_EXTENSION_FUNCTION_POINTER, - (*byte)(unsafe.Pointer(&WSAID_CONNECTEX)), - uint32(unsafe.Sizeof(WSAID_CONNECTEX)), - (*byte)(unsafe.Pointer(&connectExFunc.addr)), - uint32(unsafe.Sizeof(connectExFunc.addr)), - &n, nil, 0) - }) - return connectExFunc.err -} - -func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) { - r1, _, e1 := Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0) - if r1 == 0 { - if e1 != 0 { - err = error(e1) - } else { - err = EINVAL - } - } - return -} - -func ConnectEx(fd Handle, sa Sockaddr, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) error { - err := LoadConnectEx() - if err != nil { - return errorspkg.New("failed to find ConnectEx: " + err.Error()) - } - ptr, n, err := sa.sockaddr() - if err != nil { - return err - } - return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped) -} - -// Invented structures to support what package os expects. -type Rusage struct { - CreationTime Filetime - ExitTime Filetime - KernelTime Filetime - UserTime Filetime -} - -type WaitStatus struct { - ExitCode uint32 -} - -func (w WaitStatus) Exited() bool { return true } - -func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) } - -func (w WaitStatus) Signal() Signal { return -1 } - -func (w WaitStatus) CoreDump() bool { return false } - -func (w WaitStatus) Stopped() bool { return false } - -func (w WaitStatus) Continued() bool { return false } - -func (w WaitStatus) StopSignal() Signal { return -1 } - -func (w WaitStatus) Signaled() bool { return false } - -func (w WaitStatus) TrapCause() int { return -1 } - -// Timespec is an invented structure on Windows, but here for -// consistency with the syscall package for other operating systems. -type Timespec struct { - Sec int64 - Nsec int64 -} - -func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } - -func NsecToTimespec(nsec int64) (ts Timespec) { - ts.Sec = nsec / 1e9 - ts.Nsec = nsec % 1e9 - return -} - -// TODO(brainman): fix all needed for net - -func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, EWINDOWS } -func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) { - return 0, nil, EWINDOWS -} -func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return EWINDOWS } -func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return EWINDOWS } - -// The Linger struct is wrong but we only noticed after Go 1. -// sysLinger is the real system call structure. - -// BUG(brainman): The definition of Linger is not appropriate for direct use -// with Setsockopt and Getsockopt. -// Use SetsockoptLinger instead. - -type Linger struct { - Onoff int32 - Linger int32 -} - -type sysLinger struct { - Onoff uint16 - Linger uint16 -} - -type IPMreq struct { - Multiaddr [4]byte /* in_addr */ - Interface [4]byte /* in_addr */ -} - -type IPv6Mreq struct { - Multiaddr [16]byte /* in6_addr */ - Interface uint32 -} - -func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, EWINDOWS } - -func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { - sys := sysLinger{Onoff: uint16(l.Onoff), Linger: uint16(l.Linger)} - return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&sys)), int32(unsafe.Sizeof(sys))) -} - -func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) { - return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4) -} -func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) { - return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq))) -} -func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) { return EWINDOWS } - -func Getpid() (pid int) { return int(getCurrentProcessId()) } - -func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) { - // NOTE(rsc): The Win32finddata struct is wrong for the system call: - // the two paths are each one uint16 short. Use the correct struct, - // a win32finddata1, and then copy the results out. - // There is no loss of expressivity here, because the final - // uint16, if it is used, is supposed to be a NUL, and Go doesn't need that. - // For Go 1.1, we might avoid the allocation of win32finddata1 here - // by adding a final Bug [2]uint16 field to the struct and then - // adjusting the fields in the result directly. - var data1 win32finddata1 - handle, err = findFirstFile1(name, &data1) - if err == nil { - copyFindData(data, &data1) - } - return -} - -func FindNextFile(handle Handle, data *Win32finddata) (err error) { - var data1 win32finddata1 - err = findNextFile1(handle, &data1) - if err == nil { - copyFindData(data, &data1) - } - return -} - -func getProcessEntry(pid int) (*ProcessEntry32, error) { - snapshot, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) - if err != nil { - return nil, err - } - defer CloseHandle(snapshot) - var procEntry ProcessEntry32 - procEntry.Size = uint32(unsafe.Sizeof(procEntry)) - if err = Process32First(snapshot, &procEntry); err != nil { - return nil, err - } - for { - if procEntry.ProcessID == uint32(pid) { - return &procEntry, nil - } - err = Process32Next(snapshot, &procEntry) - if err != nil { - return nil, err - } - } -} - -func Getppid() (ppid int) { - pe, err := getProcessEntry(Getpid()) - if err != nil { - return -1 - } - return int(pe.ParentProcessID) -} - -func fdpath(fd Handle, buf []uint16) ([]uint16, error) { - const ( - FILE_NAME_NORMALIZED = 0 - VOLUME_NAME_DOS = 0 - ) - for { - n, err := getFinalPathNameByHandle(fd, &buf[0], uint32(len(buf)), FILE_NAME_NORMALIZED|VOLUME_NAME_DOS) - if err == nil { - buf = buf[:n] - break - } - if err != _ERROR_NOT_ENOUGH_MEMORY { - return nil, err - } - buf = append(buf, make([]uint16, n-uint32(len(buf)))...) - } - return buf, nil -} - -func Fchdir(fd Handle) (err error) { - var buf [MAX_PATH + 1]uint16 - path, err := fdpath(fd, buf[:]) - if err != nil { - return err - } - // When using VOLUME_NAME_DOS, the path is always pefixed by "\\?\". - // That prefix tells the Windows APIs to disable all string parsing and to send - // the string that follows it straight to the file system. - // Although SetCurrentDirectory and GetCurrentDirectory do support the "\\?\" prefix, - // some other Windows APIs don't. If the prefix is not removed here, it will leak - // to Getwd, and we don't want such a general-purpose function to always return a - // path with the "\\?\" prefix after Fchdir is called. - // The downside is that APIs that do support it will parse the path and try to normalize it, - // when it's already normalized. - if len(path) >= 4 && path[0] == '\\' && path[1] == '\\' && path[2] == '?' && path[3] == '\\' { - path = path[4:] - } - return SetCurrentDirectory(&path[0]) -} - -// TODO(brainman): fix all needed for os -func Link(oldpath, newpath string) (err error) { return EWINDOWS } -func Symlink(path, link string) (err error) { return EWINDOWS } - -func Fchmod(fd Handle, mode uint32) (err error) { return EWINDOWS } -func Chown(path string, uid int, gid int) (err error) { return EWINDOWS } -func Lchown(path string, uid int, gid int) (err error) { return EWINDOWS } -func Fchown(fd Handle, uid int, gid int) (err error) { return EWINDOWS } - -func Getuid() (uid int) { return -1 } -func Geteuid() (euid int) { return -1 } -func Getgid() (gid int) { return -1 } -func Getegid() (egid int) { return -1 } -func Getgroups() (gids []int, err error) { return nil, EWINDOWS } - -type Signal int - -func (s Signal) Signal() {} - -func (s Signal) String() string { - if 0 <= s && int(s) < len(signals) { - str := signals[s] - if str != "" { - return str - } - } - return "signal " + itoa.Itoa(int(s)) -} - -func LoadCreateSymbolicLink() error { - return procCreateSymbolicLinkW.Find() -} - -// Readlink returns the destination of the named symbolic link. -func Readlink(path string, buf []byte) (n int, err error) { - fd, err := CreateFile(StringToUTF16Ptr(path), GENERIC_READ, 0, nil, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0) - if err != nil { - return -1, err - } - defer CloseHandle(fd) - - rdbbuf := make([]byte, MAXIMUM_REPARSE_DATA_BUFFER_SIZE) - var bytesReturned uint32 - err = DeviceIoControl(fd, FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil) - if err != nil { - return -1, err - } - - rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0])) - var s string - switch rdb.ReparseTag { - case IO_REPARSE_TAG_SYMLINK: - data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) - p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) - s = UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) - if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 { - if len(s) >= 4 && s[:4] == `\??\` { - s = s[4:] - switch { - case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar - // do nothing - case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar - s = `\\` + s[4:] - default: - // unexpected; do nothing - } - } else { - // unexpected; do nothing - } - } - case _IO_REPARSE_TAG_MOUNT_POINT: - data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) - p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) - s = UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) - if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar - s = s[4:] - } else { - // unexpected; do nothing - } - default: - // the path is not a symlink or junction but another type of reparse - // point - return -1, ENOENT - } - n = copy(buf, []byte(s)) - - return n, nil -} - -// Deprecated: CreateIoCompletionPort has the wrong function signature. Use x/sys/windows.CreateIoCompletionPort. -func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (Handle, error) { - return createIoCompletionPort(filehandle, cphandle, uintptr(key), threadcnt) -} - -// Deprecated: GetQueuedCompletionStatus has the wrong function signature. Use x/sys/windows.GetQueuedCompletionStatus. -func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) error { - var ukey uintptr - var pukey *uintptr - if key != nil { - ukey = uintptr(*key) - pukey = &ukey - } - err := getQueuedCompletionStatus(cphandle, qty, pukey, overlapped, timeout) - if key != nil { - *key = uint32(ukey) - if uintptr(*key) != ukey && err == nil { - err = errorspkg.New("GetQueuedCompletionStatus returned key overflow") - } - } - return err -} - -// Deprecated: PostQueuedCompletionStatus has the wrong function signature. Use x/sys/windows.PostQueuedCompletionStatus. -func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) error { - return postQueuedCompletionStatus(cphandle, qty, uintptr(key), overlapped) -} - -// newProcThreadAttributeList allocates new PROC_THREAD_ATTRIBUTE_LIST, with -// the requested maximum number of attributes, which must be cleaned up by -// deleteProcThreadAttributeList. -func newProcThreadAttributeList(maxAttrCount uint32) (*_PROC_THREAD_ATTRIBUTE_LIST, error) { - var size uintptr - err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size) - if err != ERROR_INSUFFICIENT_BUFFER { - if err == nil { - return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList") - } - return nil, err - } - // size is guaranteed to be ≥1 by initializeProcThreadAttributeList. - al := (*_PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(&make([]byte, size)[0])) - err = initializeProcThreadAttributeList(al, maxAttrCount, 0, &size) - if err != nil { - return nil, err - } - return al, nil -} - -// RegEnumKeyEx enumerates the subkeys of an open registry key. -// Each call retrieves information about one subkey. name is -// a buffer that should be large enough to hold the name of the -// subkey plus a null terminating character. nameLen is its -// length. On return, nameLen will contain the actual length of the -// subkey. -// -// Should name not be large enough to hold the subkey, this function -// will return ERROR_MORE_DATA, and must be called again with an -// appropriately sized buffer. -// -// reserved must be nil. class and classLen behave like name and nameLen -// but for the class of the subkey, except that they are optional. -// lastWriteTime, if not nil, will be populated with the time the subkey -// was last written. -// -// The caller must enumerate all subkeys in order. That is -// RegEnumKeyEx must be called with index starting at 0, incrementing -// the index until the function returns ERROR_NO_MORE_ITEMS, or with -// the index of the last subkey (obtainable from RegQueryInfoKey), -// decrementing until index 0 is enumerated. -// -// Successive calls to this API must happen on the same OS thread, -// so call runtime.LockOSThread before calling this function. -func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) { - return regEnumKeyEx(key, index, name, nameLen, reserved, class, classLen, lastWriteTime) -} - -func GetStartupInfo(startupInfo *StartupInfo) error { - getStartupInfo(startupInfo) - return nil -} diff --git a/contrib/go/_std_1.22/src/syscall/types_windows.go b/contrib/go/_std_1.22/src/syscall/types_windows.go deleted file mode 100644 index b338ec47001f..000000000000 --- a/contrib/go/_std_1.22/src/syscall/types_windows.go +++ /dev/null @@ -1,1170 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -const ( - // Windows errors. - ERROR_FILE_NOT_FOUND Errno = 2 - ERROR_PATH_NOT_FOUND Errno = 3 - ERROR_ACCESS_DENIED Errno = 5 - ERROR_NO_MORE_FILES Errno = 18 - ERROR_HANDLE_EOF Errno = 38 - ERROR_NETNAME_DELETED Errno = 64 - ERROR_FILE_EXISTS Errno = 80 - ERROR_BROKEN_PIPE Errno = 109 - ERROR_BUFFER_OVERFLOW Errno = 111 - ERROR_INSUFFICIENT_BUFFER Errno = 122 - ERROR_MOD_NOT_FOUND Errno = 126 - ERROR_PROC_NOT_FOUND Errno = 127 - ERROR_DIR_NOT_EMPTY Errno = 145 - ERROR_ALREADY_EXISTS Errno = 183 - ERROR_ENVVAR_NOT_FOUND Errno = 203 - ERROR_MORE_DATA Errno = 234 - ERROR_OPERATION_ABORTED Errno = 995 - ERROR_IO_PENDING Errno = 997 - ERROR_NOT_FOUND Errno = 1168 - ERROR_PRIVILEGE_NOT_HELD Errno = 1314 - WSAEACCES Errno = 10013 - WSAECONNABORTED Errno = 10053 - WSAECONNRESET Errno = 10054 -) - -const ( - // Invented values to support what package os expects. - O_RDONLY = 0x00000 - O_WRONLY = 0x00001 - O_RDWR = 0x00002 - O_CREAT = 0x00040 - O_EXCL = 0x00080 - O_NOCTTY = 0x00100 - O_TRUNC = 0x00200 - O_NONBLOCK = 0x00800 - O_APPEND = 0x00400 - O_SYNC = 0x01000 - O_ASYNC = 0x02000 - O_CLOEXEC = 0x80000 -) - -const ( - // More invented values for signals - SIGHUP = Signal(0x1) - SIGINT = Signal(0x2) - SIGQUIT = Signal(0x3) - SIGILL = Signal(0x4) - SIGTRAP = Signal(0x5) - SIGABRT = Signal(0x6) - SIGBUS = Signal(0x7) - SIGFPE = Signal(0x8) - SIGKILL = Signal(0x9) - SIGSEGV = Signal(0xb) - SIGPIPE = Signal(0xd) - SIGALRM = Signal(0xe) - SIGTERM = Signal(0xf) -) - -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "bus error", - 8: "floating point exception", - 9: "killed", - 10: "user defined signal 1", - 11: "segmentation fault", - 12: "user defined signal 2", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", -} - -const ( - GENERIC_READ = 0x80000000 - GENERIC_WRITE = 0x40000000 - GENERIC_EXECUTE = 0x20000000 - GENERIC_ALL = 0x10000000 - - FILE_LIST_DIRECTORY = 0x00000001 - FILE_APPEND_DATA = 0x00000004 - FILE_WRITE_ATTRIBUTES = 0x00000100 - - FILE_SHARE_READ = 0x00000001 - FILE_SHARE_WRITE = 0x00000002 - FILE_SHARE_DELETE = 0x00000004 - FILE_ATTRIBUTE_READONLY = 0x00000001 - FILE_ATTRIBUTE_HIDDEN = 0x00000002 - FILE_ATTRIBUTE_SYSTEM = 0x00000004 - FILE_ATTRIBUTE_DIRECTORY = 0x00000010 - FILE_ATTRIBUTE_ARCHIVE = 0x00000020 - FILE_ATTRIBUTE_NORMAL = 0x00000080 - FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 - - INVALID_FILE_ATTRIBUTES = 0xffffffff - - CREATE_NEW = 1 - CREATE_ALWAYS = 2 - OPEN_EXISTING = 3 - OPEN_ALWAYS = 4 - TRUNCATE_EXISTING = 5 - - FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 - FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 - FILE_FLAG_OVERLAPPED = 0x40000000 - - HANDLE_FLAG_INHERIT = 0x00000001 - STARTF_USESTDHANDLES = 0x00000100 - STARTF_USESHOWWINDOW = 0x00000001 - DUPLICATE_CLOSE_SOURCE = 0x00000001 - DUPLICATE_SAME_ACCESS = 0x00000002 - - STD_INPUT_HANDLE = -10 - STD_OUTPUT_HANDLE = -11 - STD_ERROR_HANDLE = -12 - - FILE_BEGIN = 0 - FILE_CURRENT = 1 - FILE_END = 2 - - LANG_ENGLISH = 0x09 - SUBLANG_ENGLISH_US = 0x01 - - FORMAT_MESSAGE_ALLOCATE_BUFFER = 256 - FORMAT_MESSAGE_IGNORE_INSERTS = 512 - FORMAT_MESSAGE_FROM_STRING = 1024 - FORMAT_MESSAGE_FROM_HMODULE = 2048 - FORMAT_MESSAGE_FROM_SYSTEM = 4096 - FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192 - FORMAT_MESSAGE_MAX_WIDTH_MASK = 255 - - MAX_PATH = 260 - MAX_LONG_PATH = 32768 - - MAX_COMPUTERNAME_LENGTH = 15 - - TIME_ZONE_ID_UNKNOWN = 0 - TIME_ZONE_ID_STANDARD = 1 - - TIME_ZONE_ID_DAYLIGHT = 2 - IGNORE = 0 - INFINITE = 0xffffffff - - WAIT_TIMEOUT = 258 - WAIT_ABANDONED = 0x00000080 - WAIT_OBJECT_0 = 0x00000000 - WAIT_FAILED = 0xFFFFFFFF - - CREATE_NEW_PROCESS_GROUP = 0x00000200 - CREATE_UNICODE_ENVIRONMENT = 0x00000400 - - PROCESS_TERMINATE = 1 - PROCESS_QUERY_INFORMATION = 0x00000400 - SYNCHRONIZE = 0x00100000 - - PAGE_READONLY = 0x02 - PAGE_READWRITE = 0x04 - PAGE_WRITECOPY = 0x08 - PAGE_EXECUTE_READ = 0x20 - PAGE_EXECUTE_READWRITE = 0x40 - PAGE_EXECUTE_WRITECOPY = 0x80 - - FILE_MAP_COPY = 0x01 - FILE_MAP_WRITE = 0x02 - FILE_MAP_READ = 0x04 - FILE_MAP_EXECUTE = 0x20 - - CTRL_C_EVENT = 0 - CTRL_BREAK_EVENT = 1 - CTRL_CLOSE_EVENT = 2 - CTRL_LOGOFF_EVENT = 5 - CTRL_SHUTDOWN_EVENT = 6 -) - -const ( - // flags for CreateToolhelp32Snapshot - TH32CS_SNAPHEAPLIST = 0x01 - TH32CS_SNAPPROCESS = 0x02 - TH32CS_SNAPTHREAD = 0x04 - TH32CS_SNAPMODULE = 0x08 - TH32CS_SNAPMODULE32 = 0x10 - TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD - TH32CS_INHERIT = 0x80000000 -) - -const ( - // do not reorder - FILE_NOTIFY_CHANGE_FILE_NAME = 1 << iota - FILE_NOTIFY_CHANGE_DIR_NAME - FILE_NOTIFY_CHANGE_ATTRIBUTES - FILE_NOTIFY_CHANGE_SIZE - FILE_NOTIFY_CHANGE_LAST_WRITE - FILE_NOTIFY_CHANGE_LAST_ACCESS - FILE_NOTIFY_CHANGE_CREATION -) - -const ( - // do not reorder - FILE_ACTION_ADDED = iota + 1 - FILE_ACTION_REMOVED - FILE_ACTION_MODIFIED - FILE_ACTION_RENAMED_OLD_NAME - FILE_ACTION_RENAMED_NEW_NAME -) - -const ( - // wincrypt.h - PROV_RSA_FULL = 1 - PROV_RSA_SIG = 2 - PROV_DSS = 3 - PROV_FORTEZZA = 4 - PROV_MS_EXCHANGE = 5 - PROV_SSL = 6 - PROV_RSA_SCHANNEL = 12 - PROV_DSS_DH = 13 - PROV_EC_ECDSA_SIG = 14 - PROV_EC_ECNRA_SIG = 15 - PROV_EC_ECDSA_FULL = 16 - PROV_EC_ECNRA_FULL = 17 - PROV_DH_SCHANNEL = 18 - PROV_SPYRUS_LYNKS = 20 - PROV_RNG = 21 - PROV_INTEL_SEC = 22 - PROV_REPLACE_OWF = 23 - PROV_RSA_AES = 24 - CRYPT_VERIFYCONTEXT = 0xF0000000 - CRYPT_NEWKEYSET = 0x00000008 - CRYPT_DELETEKEYSET = 0x00000010 - CRYPT_MACHINE_KEYSET = 0x00000020 - CRYPT_SILENT = 0x00000040 - CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080 - - USAGE_MATCH_TYPE_AND = 0 - USAGE_MATCH_TYPE_OR = 1 - - X509_ASN_ENCODING = 0x00000001 - PKCS_7_ASN_ENCODING = 0x00010000 - - CERT_STORE_PROV_MEMORY = 2 - - CERT_STORE_ADD_ALWAYS = 4 - - CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004 - - CERT_TRUST_NO_ERROR = 0x00000000 - CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001 - CERT_TRUST_IS_REVOKED = 0x00000004 - CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008 - CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010 - CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020 - CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040 - CERT_TRUST_IS_CYCLIC = 0x00000080 - CERT_TRUST_INVALID_EXTENSION = 0x00000100 - CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200 - CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400 - CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800 - CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000 - CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000 - CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000 - CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000 - CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000 - CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000 - CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000 - CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000 - - CERT_CHAIN_POLICY_BASE = 1 - CERT_CHAIN_POLICY_AUTHENTICODE = 2 - CERT_CHAIN_POLICY_AUTHENTICODE_TS = 3 - CERT_CHAIN_POLICY_SSL = 4 - CERT_CHAIN_POLICY_BASIC_CONSTRAINTS = 5 - CERT_CHAIN_POLICY_NT_AUTH = 6 - CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7 - CERT_CHAIN_POLICY_EV = 8 - - CERT_E_EXPIRED = 0x800B0101 - CERT_E_ROLE = 0x800B0103 - CERT_E_PURPOSE = 0x800B0106 - CERT_E_UNTRUSTEDROOT = 0x800B0109 - CERT_E_CN_NO_MATCH = 0x800B010F - - AUTHTYPE_CLIENT = 1 - AUTHTYPE_SERVER = 2 -) - -var ( - OID_PKIX_KP_SERVER_AUTH = []byte("1.3.6.1.5.5.7.3.1\x00") - OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\x00") - OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\x00") -) - -// Pointer represents a pointer to an arbitrary Windows type. -// -// Pointer-typed fields may point to one of many different types. It's -// up to the caller to provide a pointer to the appropriate type, cast -// to Pointer. The caller must obey the unsafe.Pointer rules while -// doing so. -type Pointer *struct{} - -// Invented values to support what package os expects. -type Timeval struct { - Sec int32 - Usec int32 -} - -func (tv *Timeval) Nanoseconds() int64 { - return (int64(tv.Sec)*1e6 + int64(tv.Usec)) * 1e3 -} - -func NsecToTimeval(nsec int64) (tv Timeval) { - tv.Sec = int32(nsec / 1e9) - tv.Usec = int32(nsec % 1e9 / 1e3) - return -} - -type SecurityAttributes struct { - Length uint32 - SecurityDescriptor uintptr - InheritHandle uint32 -} - -type Overlapped struct { - Internal uintptr - InternalHigh uintptr - Offset uint32 - OffsetHigh uint32 - HEvent Handle -} - -type FileNotifyInformation struct { - NextEntryOffset uint32 - Action uint32 - FileNameLength uint32 - FileName uint16 -} - -type Filetime struct { - LowDateTime uint32 - HighDateTime uint32 -} - -// Nanoseconds returns Filetime ft in nanoseconds -// since Epoch (00:00:00 UTC, January 1, 1970). -func (ft *Filetime) Nanoseconds() int64 { - // 100-nanosecond intervals since January 1, 1601 - nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) - // change starting time to the Epoch (00:00:00 UTC, January 1, 1970) - nsec -= 116444736000000000 - // convert into nanoseconds - nsec *= 100 - return nsec -} - -func NsecToFiletime(nsec int64) (ft Filetime) { - // convert into 100-nanosecond - nsec /= 100 - // change starting time to January 1, 1601 - nsec += 116444736000000000 - // split into high / low - ft.LowDateTime = uint32(nsec & 0xffffffff) - ft.HighDateTime = uint32(nsec >> 32 & 0xffffffff) - return ft -} - -type Win32finddata struct { - FileAttributes uint32 - CreationTime Filetime - LastAccessTime Filetime - LastWriteTime Filetime - FileSizeHigh uint32 - FileSizeLow uint32 - Reserved0 uint32 - Reserved1 uint32 - FileName [MAX_PATH - 1]uint16 - AlternateFileName [13]uint16 -} - -// This is the actual system call structure. -// Win32finddata is what we committed to in Go 1. -type win32finddata1 struct { - FileAttributes uint32 - CreationTime Filetime - LastAccessTime Filetime - LastWriteTime Filetime - FileSizeHigh uint32 - FileSizeLow uint32 - Reserved0 uint32 - Reserved1 uint32 - FileName [MAX_PATH]uint16 - AlternateFileName [14]uint16 - - // The Microsoft documentation for this struct¹ describes three additional - // fields: dwFileType, dwCreatorType, and wFinderFlags. However, those fields - // are empirically only present in the macOS port of the Win32 API,² and thus - // not needed for binaries built for Windows. - // - // ¹ https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataw - // ² https://golang.org/issue/42637#issuecomment-760715755 -} - -func copyFindData(dst *Win32finddata, src *win32finddata1) { - dst.FileAttributes = src.FileAttributes - dst.CreationTime = src.CreationTime - dst.LastAccessTime = src.LastAccessTime - dst.LastWriteTime = src.LastWriteTime - dst.FileSizeHigh = src.FileSizeHigh - dst.FileSizeLow = src.FileSizeLow - dst.Reserved0 = src.Reserved0 - dst.Reserved1 = src.Reserved1 - - // The src is 1 element bigger than dst, but it must be NUL. - copy(dst.FileName[:], src.FileName[:]) - copy(dst.AlternateFileName[:], src.AlternateFileName[:]) -} - -type ByHandleFileInformation struct { - FileAttributes uint32 - CreationTime Filetime - LastAccessTime Filetime - LastWriteTime Filetime - VolumeSerialNumber uint32 - FileSizeHigh uint32 - FileSizeLow uint32 - NumberOfLinks uint32 - FileIndexHigh uint32 - FileIndexLow uint32 -} - -const ( - GetFileExInfoStandard = 0 - GetFileExMaxInfoLevel = 1 -) - -type Win32FileAttributeData struct { - FileAttributes uint32 - CreationTime Filetime - LastAccessTime Filetime - LastWriteTime Filetime - FileSizeHigh uint32 - FileSizeLow uint32 -} - -// ShowWindow constants -const ( - // winuser.h - SW_HIDE = 0 - SW_NORMAL = 1 - SW_SHOWNORMAL = 1 - SW_SHOWMINIMIZED = 2 - SW_SHOWMAXIMIZED = 3 - SW_MAXIMIZE = 3 - SW_SHOWNOACTIVATE = 4 - SW_SHOW = 5 - SW_MINIMIZE = 6 - SW_SHOWMINNOACTIVE = 7 - SW_SHOWNA = 8 - SW_RESTORE = 9 - SW_SHOWDEFAULT = 10 - SW_FORCEMINIMIZE = 11 -) - -type StartupInfo struct { - Cb uint32 - _ *uint16 - Desktop *uint16 - Title *uint16 - X uint32 - Y uint32 - XSize uint32 - YSize uint32 - XCountChars uint32 - YCountChars uint32 - FillAttribute uint32 - Flags uint32 - ShowWindow uint16 - _ uint16 - _ *byte - StdInput Handle - StdOutput Handle - StdErr Handle -} - -type _PROC_THREAD_ATTRIBUTE_LIST struct { - _ [1]byte -} - -const ( - _PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000 - _PROC_THREAD_ATTRIBUTE_HANDLE_LIST = 0x00020002 -) - -type _STARTUPINFOEXW struct { - StartupInfo - ProcThreadAttributeList *_PROC_THREAD_ATTRIBUTE_LIST -} - -const _EXTENDED_STARTUPINFO_PRESENT = 0x00080000 - -type ProcessInformation struct { - Process Handle - Thread Handle - ProcessId uint32 - ThreadId uint32 -} - -type ProcessEntry32 struct { - Size uint32 - Usage uint32 - ProcessID uint32 - DefaultHeapID uintptr - ModuleID uint32 - Threads uint32 - ParentProcessID uint32 - PriClassBase int32 - Flags uint32 - ExeFile [MAX_PATH]uint16 -} - -type Systemtime struct { - Year uint16 - Month uint16 - DayOfWeek uint16 - Day uint16 - Hour uint16 - Minute uint16 - Second uint16 - Milliseconds uint16 -} - -type Timezoneinformation struct { - Bias int32 - StandardName [32]uint16 - StandardDate Systemtime - StandardBias int32 - DaylightName [32]uint16 - DaylightDate Systemtime - DaylightBias int32 -} - -// Socket related. - -const ( - AF_UNSPEC = 0 - AF_UNIX = 1 - AF_INET = 2 - AF_INET6 = 23 - AF_NETBIOS = 17 - - SOCK_STREAM = 1 - SOCK_DGRAM = 2 - SOCK_RAW = 3 - SOCK_SEQPACKET = 5 - - IPPROTO_IP = 0 - IPPROTO_IPV6 = 0x29 - IPPROTO_TCP = 6 - IPPROTO_UDP = 17 - - SOL_SOCKET = 0xffff - SO_REUSEADDR = 4 - SO_KEEPALIVE = 8 - SO_DONTROUTE = 16 - SO_BROADCAST = 32 - SO_LINGER = 128 - SO_RCVBUF = 0x1002 - SO_SNDBUF = 0x1001 - SO_UPDATE_ACCEPT_CONTEXT = 0x700b - SO_UPDATE_CONNECT_CONTEXT = 0x7010 - - IOC_OUT = 0x40000000 - IOC_IN = 0x80000000 - IOC_VENDOR = 0x18000000 - IOC_INOUT = IOC_IN | IOC_OUT - IOC_WS2 = 0x08000000 - SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6 - SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4 - SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 - - // cf. https://learn.microsoft.com/en-US/troubleshoot/windows/win32/header-library-requirement-socket-ipproto-ip - - IP_TOS = 0x3 - IP_TTL = 0x4 - IP_MULTICAST_IF = 0x9 - IP_MULTICAST_TTL = 0xa - IP_MULTICAST_LOOP = 0xb - IP_ADD_MEMBERSHIP = 0xc - IP_DROP_MEMBERSHIP = 0xd - - IPV6_V6ONLY = 0x1b - IPV6_UNICAST_HOPS = 0x4 - IPV6_MULTICAST_IF = 0x9 - IPV6_MULTICAST_HOPS = 0xa - IPV6_MULTICAST_LOOP = 0xb - IPV6_JOIN_GROUP = 0xc - IPV6_LEAVE_GROUP = 0xd - - SOMAXCONN = 0x7fffffff - - TCP_NODELAY = 1 - - SHUT_RD = 0 - SHUT_WR = 1 - SHUT_RDWR = 2 - - WSADESCRIPTION_LEN = 256 - WSASYS_STATUS_LEN = 128 -) - -type WSABuf struct { - Len uint32 - Buf *byte -} - -// Invented values to support what package os expects. -const ( - S_IFMT = 0x1f000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 - S_ISUID = 0x800 - S_ISGID = 0x400 - S_ISVTX = 0x200 - S_IRUSR = 0x100 - S_IWRITE = 0x80 - S_IWUSR = 0x80 - S_IXUSR = 0x40 -) - -const ( - FILE_TYPE_CHAR = 0x0002 - FILE_TYPE_DISK = 0x0001 - FILE_TYPE_PIPE = 0x0003 - FILE_TYPE_REMOTE = 0x8000 - FILE_TYPE_UNKNOWN = 0x0000 -) - -type Hostent struct { - Name *byte - Aliases **byte - AddrType uint16 - Length uint16 - AddrList **byte -} - -type Protoent struct { - Name *byte - Aliases **byte - Proto uint16 -} - -const ( - DNS_TYPE_A = 0x0001 - DNS_TYPE_NS = 0x0002 - DNS_TYPE_MD = 0x0003 - DNS_TYPE_MF = 0x0004 - DNS_TYPE_CNAME = 0x0005 - DNS_TYPE_SOA = 0x0006 - DNS_TYPE_MB = 0x0007 - DNS_TYPE_MG = 0x0008 - DNS_TYPE_MR = 0x0009 - DNS_TYPE_NULL = 0x000a - DNS_TYPE_WKS = 0x000b - DNS_TYPE_PTR = 0x000c - DNS_TYPE_HINFO = 0x000d - DNS_TYPE_MINFO = 0x000e - DNS_TYPE_MX = 0x000f - DNS_TYPE_TEXT = 0x0010 - DNS_TYPE_RP = 0x0011 - DNS_TYPE_AFSDB = 0x0012 - DNS_TYPE_X25 = 0x0013 - DNS_TYPE_ISDN = 0x0014 - DNS_TYPE_RT = 0x0015 - DNS_TYPE_NSAP = 0x0016 - DNS_TYPE_NSAPPTR = 0x0017 - DNS_TYPE_SIG = 0x0018 - DNS_TYPE_KEY = 0x0019 - DNS_TYPE_PX = 0x001a - DNS_TYPE_GPOS = 0x001b - DNS_TYPE_AAAA = 0x001c - DNS_TYPE_LOC = 0x001d - DNS_TYPE_NXT = 0x001e - DNS_TYPE_EID = 0x001f - DNS_TYPE_NIMLOC = 0x0020 - DNS_TYPE_SRV = 0x0021 - DNS_TYPE_ATMA = 0x0022 - DNS_TYPE_NAPTR = 0x0023 - DNS_TYPE_KX = 0x0024 - DNS_TYPE_CERT = 0x0025 - DNS_TYPE_A6 = 0x0026 - DNS_TYPE_DNAME = 0x0027 - DNS_TYPE_SINK = 0x0028 - DNS_TYPE_OPT = 0x0029 - DNS_TYPE_DS = 0x002B - DNS_TYPE_RRSIG = 0x002E - DNS_TYPE_NSEC = 0x002F - DNS_TYPE_DNSKEY = 0x0030 - DNS_TYPE_DHCID = 0x0031 - DNS_TYPE_UINFO = 0x0064 - DNS_TYPE_UID = 0x0065 - DNS_TYPE_GID = 0x0066 - DNS_TYPE_UNSPEC = 0x0067 - DNS_TYPE_ADDRS = 0x00f8 - DNS_TYPE_TKEY = 0x00f9 - DNS_TYPE_TSIG = 0x00fa - DNS_TYPE_IXFR = 0x00fb - DNS_TYPE_AXFR = 0x00fc - DNS_TYPE_MAILB = 0x00fd - DNS_TYPE_MAILA = 0x00fe - DNS_TYPE_ALL = 0x00ff - DNS_TYPE_ANY = 0x00ff - DNS_TYPE_WINS = 0xff01 - DNS_TYPE_WINSR = 0xff02 - DNS_TYPE_NBSTAT = 0xff01 -) - -const ( - DNS_INFO_NO_RECORDS = 0x251D -) - -const ( - // flags inside DNSRecord.Dw - DnsSectionQuestion = 0x0000 - DnsSectionAnswer = 0x0001 - DnsSectionAuthority = 0x0002 - DnsSectionAdditional = 0x0003 -) - -type DNSSRVData struct { - Target *uint16 - Priority uint16 - Weight uint16 - Port uint16 - Pad uint16 -} - -type DNSPTRData struct { - Host *uint16 -} - -type DNSMXData struct { - NameExchange *uint16 - Preference uint16 - Pad uint16 -} - -type DNSTXTData struct { - StringCount uint16 - StringArray [1]*uint16 -} - -type DNSRecord struct { - Next *DNSRecord - Name *uint16 - Type uint16 - Length uint16 - Dw uint32 - Ttl uint32 - Reserved uint32 - Data [40]byte -} - -const ( - TF_DISCONNECT = 1 - TF_REUSE_SOCKET = 2 - TF_WRITE_BEHIND = 4 - TF_USE_DEFAULT_WORKER = 0 - TF_USE_SYSTEM_THREAD = 16 - TF_USE_KERNEL_APC = 32 -) - -type TransmitFileBuffers struct { - Head uintptr - HeadLength uint32 - Tail uintptr - TailLength uint32 -} - -const ( - IFF_UP = 1 - IFF_BROADCAST = 2 - IFF_LOOPBACK = 4 - IFF_POINTTOPOINT = 8 - IFF_MULTICAST = 16 -) - -const SIO_GET_INTERFACE_LIST = 0x4004747F - -// TODO(mattn): SockaddrGen is union of sockaddr/sockaddr_in/sockaddr_in6_old. -// will be fixed to change variable type as suitable. - -type SockaddrGen [24]byte - -type InterfaceInfo struct { - Flags uint32 - Address SockaddrGen - BroadcastAddress SockaddrGen - Netmask SockaddrGen -} - -type IpAddressString struct { - String [16]byte -} - -type IpMaskString IpAddressString - -type IpAddrString struct { - Next *IpAddrString - IpAddress IpAddressString - IpMask IpMaskString - Context uint32 -} - -const MAX_ADAPTER_NAME_LENGTH = 256 -const MAX_ADAPTER_DESCRIPTION_LENGTH = 128 -const MAX_ADAPTER_ADDRESS_LENGTH = 8 - -type IpAdapterInfo struct { - Next *IpAdapterInfo - ComboIndex uint32 - AdapterName [MAX_ADAPTER_NAME_LENGTH + 4]byte - Description [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte - AddressLength uint32 - Address [MAX_ADAPTER_ADDRESS_LENGTH]byte - Index uint32 - Type uint32 - DhcpEnabled uint32 - CurrentIpAddress *IpAddrString - IpAddressList IpAddrString - GatewayList IpAddrString - DhcpServer IpAddrString - HaveWins bool - PrimaryWinsServer IpAddrString - SecondaryWinsServer IpAddrString - LeaseObtained int64 - LeaseExpires int64 -} - -const MAXLEN_PHYSADDR = 8 -const MAX_INTERFACE_NAME_LEN = 256 -const MAXLEN_IFDESCR = 256 - -type MibIfRow struct { - Name [MAX_INTERFACE_NAME_LEN]uint16 - Index uint32 - Type uint32 - Mtu uint32 - Speed uint32 - PhysAddrLen uint32 - PhysAddr [MAXLEN_PHYSADDR]byte - AdminStatus uint32 - OperStatus uint32 - LastChange uint32 - InOctets uint32 - InUcastPkts uint32 - InNUcastPkts uint32 - InDiscards uint32 - InErrors uint32 - InUnknownProtos uint32 - OutOctets uint32 - OutUcastPkts uint32 - OutNUcastPkts uint32 - OutDiscards uint32 - OutErrors uint32 - OutQLen uint32 - DescrLen uint32 - Descr [MAXLEN_IFDESCR]byte -} - -type CertInfo struct { - // Not implemented -} - -type CertContext struct { - EncodingType uint32 - EncodedCert *byte - Length uint32 - CertInfo *CertInfo - Store Handle -} - -type CertChainContext struct { - Size uint32 - TrustStatus CertTrustStatus - ChainCount uint32 - Chains **CertSimpleChain - LowerQualityChainCount uint32 - LowerQualityChains **CertChainContext - HasRevocationFreshnessTime uint32 - RevocationFreshnessTime uint32 -} - -type CertTrustListInfo struct { - // Not implemented -} - -type CertSimpleChain struct { - Size uint32 - TrustStatus CertTrustStatus - NumElements uint32 - Elements **CertChainElement - TrustListInfo *CertTrustListInfo - HasRevocationFreshnessTime uint32 - RevocationFreshnessTime uint32 -} - -type CertChainElement struct { - Size uint32 - CertContext *CertContext - TrustStatus CertTrustStatus - RevocationInfo *CertRevocationInfo - IssuanceUsage *CertEnhKeyUsage - ApplicationUsage *CertEnhKeyUsage - ExtendedErrorInfo *uint16 -} - -type CertRevocationCrlInfo struct { - // Not implemented -} - -type CertRevocationInfo struct { - Size uint32 - RevocationResult uint32 - RevocationOid *byte - OidSpecificInfo Pointer - HasFreshnessTime uint32 - FreshnessTime uint32 - CrlInfo *CertRevocationCrlInfo -} - -type CertTrustStatus struct { - ErrorStatus uint32 - InfoStatus uint32 -} - -type CertUsageMatch struct { - Type uint32 - Usage CertEnhKeyUsage -} - -type CertEnhKeyUsage struct { - Length uint32 - UsageIdentifiers **byte -} - -type CertChainPara struct { - Size uint32 - RequestedUsage CertUsageMatch - RequstedIssuancePolicy CertUsageMatch - URLRetrievalTimeout uint32 - CheckRevocationFreshnessTime uint32 - RevocationFreshnessTime uint32 - CacheResync *Filetime -} - -type CertChainPolicyPara struct { - Size uint32 - Flags uint32 - ExtraPolicyPara Pointer -} - -type SSLExtraCertChainPolicyPara struct { - Size uint32 - AuthType uint32 - Checks uint32 - ServerName *uint16 -} - -type CertChainPolicyStatus struct { - Size uint32 - Error uint32 - ChainIndex uint32 - ElementIndex uint32 - ExtraPolicyStatus Pointer -} - -const ( - // do not reorder - HKEY_CLASSES_ROOT = 0x80000000 + iota - HKEY_CURRENT_USER - HKEY_LOCAL_MACHINE - HKEY_USERS - HKEY_PERFORMANCE_DATA - HKEY_CURRENT_CONFIG - HKEY_DYN_DATA - - KEY_QUERY_VALUE = 1 - KEY_SET_VALUE = 2 - KEY_CREATE_SUB_KEY = 4 - KEY_ENUMERATE_SUB_KEYS = 8 - KEY_NOTIFY = 16 - KEY_CREATE_LINK = 32 - KEY_WRITE = 0x20006 - KEY_EXECUTE = 0x20019 - KEY_READ = 0x20019 - KEY_WOW64_64KEY = 0x0100 - KEY_WOW64_32KEY = 0x0200 - KEY_ALL_ACCESS = 0xf003f -) - -const ( - // do not reorder - REG_NONE = iota - REG_SZ - REG_EXPAND_SZ - REG_BINARY - REG_DWORD_LITTLE_ENDIAN - REG_DWORD_BIG_ENDIAN - REG_LINK - REG_MULTI_SZ - REG_RESOURCE_LIST - REG_FULL_RESOURCE_DESCRIPTOR - REG_RESOURCE_REQUIREMENTS_LIST - REG_QWORD_LITTLE_ENDIAN - REG_DWORD = REG_DWORD_LITTLE_ENDIAN - REG_QWORD = REG_QWORD_LITTLE_ENDIAN -) - -type AddrinfoW struct { - Flags int32 - Family int32 - Socktype int32 - Protocol int32 - Addrlen uintptr - Canonname *uint16 - Addr Pointer - Next *AddrinfoW -} - -const ( - AI_PASSIVE = 1 - AI_CANONNAME = 2 - AI_NUMERICHOST = 4 -) - -type GUID struct { - Data1 uint32 - Data2 uint16 - Data3 uint16 - Data4 [8]byte -} - -var WSAID_CONNECTEX = GUID{ - 0x25a207b9, - 0xddf3, - 0x4660, - [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}, -} - -const ( - FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 - FILE_SKIP_SET_EVENT_ON_HANDLE = 2 -) - -const ( - WSAPROTOCOL_LEN = 255 - MAX_PROTOCOL_CHAIN = 7 - BASE_PROTOCOL = 1 - LAYERED_PROTOCOL = 0 - - XP1_CONNECTIONLESS = 0x00000001 - XP1_GUARANTEED_DELIVERY = 0x00000002 - XP1_GUARANTEED_ORDER = 0x00000004 - XP1_MESSAGE_ORIENTED = 0x00000008 - XP1_PSEUDO_STREAM = 0x00000010 - XP1_GRACEFUL_CLOSE = 0x00000020 - XP1_EXPEDITED_DATA = 0x00000040 - XP1_CONNECT_DATA = 0x00000080 - XP1_DISCONNECT_DATA = 0x00000100 - XP1_SUPPORT_BROADCAST = 0x00000200 - XP1_SUPPORT_MULTIPOINT = 0x00000400 - XP1_MULTIPOINT_CONTROL_PLANE = 0x00000800 - XP1_MULTIPOINT_DATA_PLANE = 0x00001000 - XP1_QOS_SUPPORTED = 0x00002000 - XP1_UNI_SEND = 0x00008000 - XP1_UNI_RECV = 0x00010000 - XP1_IFS_HANDLES = 0x00020000 - XP1_PARTIAL_MESSAGE = 0x00040000 - XP1_SAN_SUPPORT_SDP = 0x00080000 - - PFL_MULTIPLE_PROTO_ENTRIES = 0x00000001 - PFL_RECOMMENDED_PROTO_ENTRY = 0x00000002 - PFL_HIDDEN = 0x00000004 - PFL_MATCHES_PROTOCOL_ZERO = 0x00000008 - PFL_NETWORKDIRECT_PROVIDER = 0x00000010 -) - -type WSAProtocolInfo struct { - ServiceFlags1 uint32 - ServiceFlags2 uint32 - ServiceFlags3 uint32 - ServiceFlags4 uint32 - ProviderFlags uint32 - ProviderId GUID - CatalogEntryId uint32 - ProtocolChain WSAProtocolChain - Version int32 - AddressFamily int32 - MaxSockAddr int32 - MinSockAddr int32 - SocketType int32 - Protocol int32 - ProtocolMaxOffset int32 - NetworkByteOrder int32 - SecurityScheme int32 - MessageSize uint32 - ProviderReserved uint32 - ProtocolName [WSAPROTOCOL_LEN + 1]uint16 -} - -type WSAProtocolChain struct { - ChainLen int32 - ChainEntries [MAX_PROTOCOL_CHAIN]uint32 -} - -type TCPKeepalive struct { - OnOff uint32 - Time uint32 - Interval uint32 -} - -type symbolicLinkReparseBuffer struct { - SubstituteNameOffset uint16 - SubstituteNameLength uint16 - PrintNameOffset uint16 - PrintNameLength uint16 - Flags uint32 - PathBuffer [1]uint16 -} - -type mountPointReparseBuffer struct { - SubstituteNameOffset uint16 - SubstituteNameLength uint16 - PrintNameOffset uint16 - PrintNameLength uint16 - PathBuffer [1]uint16 -} - -type reparseDataBuffer struct { - ReparseTag uint32 - ReparseDataLength uint16 - Reserved uint16 - - // GenericReparseBuffer - reparseBuffer byte -} - -const ( - FSCTL_GET_REPARSE_POINT = 0x900A8 - MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024 - _IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 - IO_REPARSE_TAG_SYMLINK = 0xA000000C - SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1 - _SYMLINK_FLAG_RELATIVE = 1 -) - -const UNIX_PATH_MAX = 108 // defined in afunix.h diff --git a/contrib/go/_std_1.22/src/syscall/ya.make b/contrib/go/_std_1.22/src/syscall/ya.make deleted file mode 100644 index 41a879582683..000000000000 --- a/contrib/go/_std_1.22/src/syscall/ya.make +++ /dev/null @@ -1,157 +0,0 @@ -GO_LIBRARY() - -IF(SANITIZER_TYPE == "memory") - SRCS(msan.go) -ELSE() - SRCS(msan0.go) -ENDIF() - -IF(SANITIZER_TYPE == "address") - SRCS(asan.go) -ELSE() - SRCS(asan0.go) -ENDIF() - -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - asm_darwin_arm64.s - bpf_bsd.go - dirent.go - endian_little.go - env_unix.go - exec_libc2.go - exec_unix.go - flock_bsd.go - forkpipe.go - net.go - rlimit.go - rlimit_darwin.go - route_bsd.go - route_darwin.go - sockcmsg_unix.go - sockcmsg_unix_other.go - syscall.go - syscall_bsd.go - syscall_darwin.go - syscall_darwin_arm64.go - syscall_unix.go - time_nofake.go - timestruct.go - zerrors_darwin_arm64.go - zsyscall_darwin_arm64.go - zsyscall_darwin_arm64.s - zsysnum_darwin_arm64.go - ztypes_darwin_arm64.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - asm_darwin_amd64.s - bpf_bsd.go - dirent.go - endian_little.go - env_unix.go - exec_libc2.go - exec_unix.go - flock_bsd.go - forkpipe.go - net.go - rlimit.go - rlimit_darwin.go - route_bsd.go - route_darwin.go - sockcmsg_unix.go - sockcmsg_unix_other.go - syscall.go - syscall_bsd.go - syscall_darwin.go - syscall_darwin_amd64.go - syscall_unix.go - time_nofake.go - timestruct.go - zerrors_darwin_amd64.go - zsyscall_darwin_amd64.go - zsyscall_darwin_amd64.s - zsysnum_darwin_amd64.go - ztypes_darwin_amd64.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - asm_linux_arm64.s - dirent.go - endian_little.go - env_unix.go - exec_linux.go - exec_unix.go - flock_linux.go - forkpipe2.go - lsf_linux.go - net.go - netlink_linux.go - rlimit.go - rlimit_stub.go - setuidgid_linux.go - sockcmsg_linux.go - sockcmsg_unix.go - sockcmsg_unix_other.go - syscall.go - syscall_linux.go - syscall_linux_accept4.go - syscall_linux_arm64.go - syscall_unix.go - time_nofake.go - timestruct.go - zerrors_linux_arm64.go - zsyscall_linux_arm64.go - zsysnum_linux_arm64.go - ztypes_linux_arm64.go - ) -ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - asm_linux_amd64.s - dirent.go - endian_little.go - env_unix.go - exec_linux.go - exec_unix.go - flock_linux.go - forkpipe2.go - lsf_linux.go - net.go - netlink_linux.go - rlimit.go - rlimit_stub.go - setuidgid_linux.go - sockcmsg_linux.go - sockcmsg_unix.go - sockcmsg_unix_other.go - syscall.go - syscall_linux.go - syscall_linux_accept4.go - syscall_linux_amd64.go - syscall_unix.go - time_nofake.go - timestruct.go - zerrors_linux_amd64.go - zsyscall_linux_amd64.go - zsysnum_linux_amd64.go - ztypes_linux_amd64.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - dll_windows.go - endian_little.go - env_windows.go - exec_windows.go - net.go - security_windows.go - syscall.go - syscall_windows.go - time_nofake.go - types_windows.go - types_windows_amd64.go - wtf8_windows.go - zerrors_windows.go - zsyscall_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_windows.go b/contrib/go/_std_1.22/src/syscall/zsyscall_windows.go deleted file mode 100644 index 630270812db4..000000000000 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_windows.go +++ /dev/null @@ -1,1475 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package syscall - -import ( - "internal/syscall/windows/sysdll" - "unsafe" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = Errno(errnoERROR_IO_PENDING) - errERROR_EINVAL error = EINVAL -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -func errnoErr(e Errno) error { - switch e { - case 0: - return errERROR_EINVAL - case errnoERROR_IO_PENDING: - return errERROR_IO_PENDING - } - // TODO: add more here, after collecting data on the common - // error values see on Windows. (perhaps when running - // all.bat?) - return e -} - -var ( - modadvapi32 = NewLazyDLL(sysdll.Add("advapi32.dll")) - modcrypt32 = NewLazyDLL(sysdll.Add("crypt32.dll")) - moddnsapi = NewLazyDLL(sysdll.Add("dnsapi.dll")) - modiphlpapi = NewLazyDLL(sysdll.Add("iphlpapi.dll")) - modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll")) - modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll")) - modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll")) - modntdll = NewLazyDLL(sysdll.Add("ntdll.dll")) - modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll")) - modshell32 = NewLazyDLL(sysdll.Add("shell32.dll")) - moduserenv = NewLazyDLL(sysdll.Add("userenv.dll")) - modws2_32 = NewLazyDLL(sysdll.Add("ws2_32.dll")) - - procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") - procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW") - procCopySid = modadvapi32.NewProc("CopySid") - procCreateProcessAsUserW = modadvapi32.NewProc("CreateProcessAsUserW") - procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW") - procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom") - procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext") - procGetLengthSid = modadvapi32.NewProc("GetLengthSid") - procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation") - procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") - procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW") - procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken") - procRegCloseKey = modadvapi32.NewProc("RegCloseKey") - procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW") - procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW") - procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW") - procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW") - procCertAddCertificateContextToStore = modcrypt32.NewProc("CertAddCertificateContextToStore") - procCertCloseStore = modcrypt32.NewProc("CertCloseStore") - procCertCreateCertificateContext = modcrypt32.NewProc("CertCreateCertificateContext") - procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore") - procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain") - procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext") - procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain") - procCertOpenStore = modcrypt32.NewProc("CertOpenStore") - procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW") - procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy") - procDnsNameCompare_W = moddnsapi.NewProc("DnsNameCompare_W") - procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W") - procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree") - procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo") - procGetIfEntry = modiphlpapi.NewProc("GetIfEntry") - procCancelIo = modkernel32.NewProc("CancelIo") - procCancelIoEx = modkernel32.NewProc("CancelIoEx") - procCloseHandle = modkernel32.NewProc("CloseHandle") - procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW") - procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW") - procCreateFileW = modkernel32.NewProc("CreateFileW") - procCreateHardLinkW = modkernel32.NewProc("CreateHardLinkW") - procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") - procCreatePipe = modkernel32.NewProc("CreatePipe") - procCreateProcessW = modkernel32.NewProc("CreateProcessW") - procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW") - procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") - procDeleteFileW = modkernel32.NewProc("DeleteFileW") - procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList") - procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") - procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") - procExitProcess = modkernel32.NewProc("ExitProcess") - procFindClose = modkernel32.NewProc("FindClose") - procFindFirstFileW = modkernel32.NewProc("FindFirstFileW") - procFindNextFileW = modkernel32.NewProc("FindNextFileW") - procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers") - procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile") - procFormatMessageW = modkernel32.NewProc("FormatMessageW") - procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW") - procFreeLibrary = modkernel32.NewProc("FreeLibrary") - procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") - procGetComputerNameW = modkernel32.NewProc("GetComputerNameW") - procGetConsoleMode = modkernel32.NewProc("GetConsoleMode") - procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW") - procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess") - procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId") - procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW") - procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW") - procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess") - procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW") - procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW") - procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle") - procGetFileType = modkernel32.NewProc("GetFileType") - procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW") - procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW") - procGetLastError = modkernel32.NewProc("GetLastError") - procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW") - procGetProcAddress = modkernel32.NewProc("GetProcAddress") - procGetProcessTimes = modkernel32.NewProc("GetProcessTimes") - procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") - procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW") - procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW") - procGetStdHandle = modkernel32.NewProc("GetStdHandle") - procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime") - procGetTempPathW = modkernel32.NewProc("GetTempPathW") - procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation") - procGetVersion = modkernel32.NewProc("GetVersion") - procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList") - procLoadLibraryW = modkernel32.NewProc("LoadLibraryW") - procLocalFree = modkernel32.NewProc("LocalFree") - procMapViewOfFile = modkernel32.NewProc("MapViewOfFile") - procMoveFileW = modkernel32.NewProc("MoveFileW") - procOpenProcess = modkernel32.NewProc("OpenProcess") - procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus") - procProcess32FirstW = modkernel32.NewProc("Process32FirstW") - procProcess32NextW = modkernel32.NewProc("Process32NextW") - procReadConsoleW = modkernel32.NewProc("ReadConsoleW") - procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW") - procReadFile = modkernel32.NewProc("ReadFile") - procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW") - procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW") - procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") - procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") - procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW") - procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") - procSetFilePointer = modkernel32.NewProc("SetFilePointer") - procSetFileTime = modkernel32.NewProc("SetFileTime") - procSetHandleInformation = modkernel32.NewProc("SetHandleInformation") - procTerminateProcess = modkernel32.NewProc("TerminateProcess") - procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile") - procUpdateProcThreadAttribute = modkernel32.NewProc("UpdateProcThreadAttribute") - procVirtualLock = modkernel32.NewProc("VirtualLock") - procVirtualUnlock = modkernel32.NewProc("VirtualUnlock") - procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject") - procWriteConsoleW = modkernel32.NewProc("WriteConsoleW") - procWriteFile = modkernel32.NewProc("WriteFile") - procAcceptEx = modmswsock.NewProc("AcceptEx") - procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs") - procTransmitFile = modmswsock.NewProc("TransmitFile") - procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree") - procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation") - procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") - procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers") - procGetUserNameExW = modsecur32.NewProc("GetUserNameExW") - procTranslateNameW = modsecur32.NewProc("TranslateNameW") - procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") - procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") - procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW") - procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW") - procWSACleanup = modws2_32.NewProc("WSACleanup") - procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW") - procWSAIoctl = modws2_32.NewProc("WSAIoctl") - procWSARecv = modws2_32.NewProc("WSARecv") - procWSARecvFrom = modws2_32.NewProc("WSARecvFrom") - procWSASend = modws2_32.NewProc("WSASend") - procWSASendTo = modws2_32.NewProc("WSASendTo") - procWSAStartup = modws2_32.NewProc("WSAStartup") - procbind = modws2_32.NewProc("bind") - procclosesocket = modws2_32.NewProc("closesocket") - procconnect = modws2_32.NewProc("connect") - procgethostbyname = modws2_32.NewProc("gethostbyname") - procgetpeername = modws2_32.NewProc("getpeername") - procgetprotobyname = modws2_32.NewProc("getprotobyname") - procgetservbyname = modws2_32.NewProc("getservbyname") - procgetsockname = modws2_32.NewProc("getsockname") - procgetsockopt = modws2_32.NewProc("getsockopt") - proclisten = modws2_32.NewProc("listen") - procntohs = modws2_32.NewProc("ntohs") - procsetsockopt = modws2_32.NewProc("setsockopt") - procshutdown = modws2_32.NewProc("shutdown") - procsocket = modws2_32.NewProc("socket") -) - -func ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) { - r1, _, e1 := Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) { - r1, _, e1 := Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) { - r1, _, e1 := Syscall(procCopySid.Addr(), 3, uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) { - var _p0 uint32 - if inheritHandles { - _p0 = 1 - } - r1, _, e1 := Syscall12(procCreateProcessAsUserW.Addr(), 11, uintptr(token), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) { - r1, _, e1 := Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) { - r1, _, e1 := Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CryptReleaseContext(provhandle Handle, flags uint32) (err error) { - r1, _, e1 := Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetLengthSid(sid *SID) (len uint32) { - r0, _, _ := Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) - len = uint32(r0) - return -} - -func GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) { - r1, _, e1 := Syscall6(procGetTokenInformation.Addr(), 5, uintptr(t), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { - r1, _, e1 := Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { - r1, _, e1 := Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func OpenProcessToken(h Handle, access uint32, token *Token) (err error) { - r1, _, e1 := Syscall(procOpenProcessToken.Addr(), 3, uintptr(h), uintptr(access), uintptr(unsafe.Pointer(token))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func RegCloseKey(key Handle) (regerrno error) { - r0, _, _ := Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0) - if r0 != 0 { - regerrno = Errno(r0) - } - return -} - -func regEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) { - r0, _, _ := Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0) - if r0 != 0 { - regerrno = Errno(r0) - } - return -} - -func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) { - r0, _, _ := Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0) - if r0 != 0 { - regerrno = Errno(r0) - } - return -} - -func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) { - r0, _, _ := Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime))) - if r0 != 0 { - regerrno = Errno(r0) - } - return -} - -func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { - r0, _, _ := Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen))) - if r0 != 0 { - regerrno = Errno(r0) - } - return -} - -func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) { - r1, _, e1 := Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CertCloseStore(store Handle, flags uint32) (err error) { - r1, _, e1 := Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) { - r0, _, e1 := Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen)) - context = (*CertContext)(unsafe.Pointer(r0)) - if context == nil { - err = errnoErr(e1) - } - return -} - -func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) { - r0, _, e1 := Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0) - context = (*CertContext)(unsafe.Pointer(r0)) - if context == nil { - err = errnoErr(e1) - } - return -} - -func CertFreeCertificateChain(ctx *CertChainContext) { - Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) - return -} - -func CertFreeCertificateContext(ctx *CertContext) (err error) { - r1, _, e1 := Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) { - r1, _, e1 := Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) { - r0, _, e1 := Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0) - handle = Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) { - r0, _, e1 := Syscall(procCertOpenSystemStoreW.Addr(), 2, uintptr(hprov), uintptr(unsafe.Pointer(name)), 0) - store = Handle(r0) - if store == 0 { - err = errnoErr(e1) - } - return -} - -func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) { - r1, _, e1 := Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) { - r0, _, _ := Syscall(procDnsNameCompare_W.Addr(), 2, uintptr(unsafe.Pointer(name1)), uintptr(unsafe.Pointer(name2)), 0) - same = r0 != 0 - return -} - -func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { - var _p0 *uint16 - _p0, status = UTF16PtrFromString(name) - if status != nil { - return - } - return _DnsQuery(_p0, qtype, options, extra, qrs, pr) -} - -func _DnsQuery(name *uint16, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { - r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(name)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) - if r0 != 0 { - status = Errno(r0) - } - return -} - -func DnsRecordListFree(rl *DNSRecord, freetype uint32) { - Syscall(procDnsRecordListFree.Addr(), 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0) - return -} - -func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) { - r0, _, _ := Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0) - if r0 != 0 { - errcode = Errno(r0) - } - return -} - -func GetIfEntry(pIfRow *MibIfRow) (errcode error) { - r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0) - if r0 != 0 { - errcode = Errno(r0) - } - return -} - -func CancelIo(s Handle) (err error) { - r1, _, e1 := Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CancelIoEx(s Handle, o *Overlapped) (err error) { - r1, _, e1 := Syscall(procCancelIoEx.Addr(), 2, uintptr(s), uintptr(unsafe.Pointer(o)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CloseHandle(handle Handle) (err error) { - r1, _, e1 := Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) { - r1, _, e1 := Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) { - r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name))) - handle = Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) { - r0, _, e1 := Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) - handle = Handle(r0) - if handle == InvalidHandle { - err = errnoErr(e1) - } - return -} - -func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) { - r1, _, e1 := Syscall(procCreateHardLinkW.Addr(), 3, uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(existingfilename)), uintptr(reserved)) - if r1&0xff == 0 { - err = errnoErr(e1) - } - return -} - -func createIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) { - r0, _, e1 := Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) - handle = Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) { - r1, _, e1 := Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) { - var _p0 uint32 - if inheritHandles { - _p0 = 1 - } - r1, _, e1 := Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) { - r1, _, e1 := Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags)) - if r1&0xff == 0 { - err = errnoErr(e1) - } - return -} - -func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) { - r0, _, e1 := Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0) - handle = Handle(r0) - if handle == InvalidHandle { - err = errnoErr(e1) - } - return -} - -func DeleteFile(path *uint16) (err error) { - r1, _, e1 := Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func deleteProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST) { - Syscall(procDeleteProcThreadAttributeList.Addr(), 1, uintptr(unsafe.Pointer(attrlist)), 0, 0) - return -} - -func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) { - r1, _, e1 := Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), uintptr(ioControlCode), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferSize), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferSize), uintptr(unsafe.Pointer(bytesReturned)), uintptr(unsafe.Pointer(overlapped)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) { - var _p0 uint32 - if bInheritHandle { - _p0 = 1 - } - r1, _, e1 := Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func ExitProcess(exitcode uint32) { - Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0) - return -} - -func FindClose(handle Handle) (err error) { - r1, _, e1 := Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) { - r0, _, e1 := Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0) - handle = Handle(r0) - if handle == InvalidHandle { - err = errnoErr(e1) - } - return -} - -func findNextFile1(handle Handle, data *win32finddata1) (err error) { - r1, _, e1 := Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func FlushFileBuffers(handle Handle) (err error) { - r1, _, e1 := Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func FlushViewOfFile(addr uintptr, length uintptr) (err error) { - r1, _, e1 := Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) { - var _p0 *uint16 - if len(buf) > 0 { - _p0 = &buf[0] - } - r0, _, e1 := Syscall9(procFormatMessageW.Addr(), 7, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func FreeEnvironmentStrings(envs *uint16) (err error) { - r1, _, e1 := Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func FreeLibrary(handle Handle) (err error) { - r1, _, e1 := Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetCommandLine() (cmd *uint16) { - r0, _, _ := Syscall(procGetCommandLineW.Addr(), 0, 0, 0, 0) - cmd = (*uint16)(unsafe.Pointer(r0)) - return -} - -func GetComputerName(buf *uint16, n *uint32) (err error) { - r1, _, e1 := Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetConsoleMode(console Handle, mode *uint32) (err error) { - r1, _, e1 := Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) { - r0, _, e1 := Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetCurrentProcess() (pseudoHandle Handle, err error) { - r0, _, e1 := Syscall(procGetCurrentProcess.Addr(), 0, 0, 0, 0) - pseudoHandle = Handle(r0) - if pseudoHandle == 0 { - err = errnoErr(e1) - } - return -} - -func getCurrentProcessId() (pid uint32) { - r0, _, _ := Syscall(procGetCurrentProcessId.Addr(), 0, 0, 0, 0) - pid = uint32(r0) - return -} - -func GetEnvironmentStrings() (envs *uint16, err error) { - r0, _, e1 := Syscall(procGetEnvironmentStringsW.Addr(), 0, 0, 0, 0) - envs = (*uint16)(unsafe.Pointer(r0)) - if envs == nil { - err = errnoErr(e1) - } - return -} - -func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) { - r0, _, e1 := Syscall(procGetEnvironmentVariableW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size)) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) { - r1, _, e1 := Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) { - r1, _, e1 := Syscall(procGetFileAttributesExW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetFileAttributes(name *uint16) (attrs uint32, err error) { - r0, _, e1 := Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) - attrs = uint32(r0) - if attrs == INVALID_FILE_ATTRIBUTES { - err = errnoErr(e1) - } - return -} - -func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) { - r1, _, e1 := Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetFileType(filehandle Handle) (n uint32, err error) { - r0, _, e1 := Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func getFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) { - r0, _, e1 := Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0) - n = uint32(r0) - if n == 0 || n >= filePathSize { - err = errnoErr(e1) - } - return -} - -func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) { - r0, _, e1 := Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetLastError() (lasterr error) { - r0, _, _ := Syscall(procGetLastError.Addr(), 0, 0, 0, 0) - if r0 != 0 { - lasterr = Errno(r0) - } - return -} - -func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) { - r0, _, e1 := Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen)) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetProcAddress(module Handle, procname string) (proc uintptr, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(procname) - if err != nil { - return - } - return _GetProcAddress(module, _p0) -} - -func _GetProcAddress(module Handle, procname *byte) (proc uintptr, err error) { - r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(procname)), 0) - proc = uintptr(r0) - if proc == 0 { - err = errnoErr(e1) - } - return -} - -func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) { - r1, _, e1 := Syscall6(procGetProcessTimes.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func getQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) { - r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) { - r0, _, e1 := Syscall(procGetShortPathNameW.Addr(), 3, uintptr(unsafe.Pointer(longpath)), uintptr(unsafe.Pointer(shortpath)), uintptr(buflen)) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func getStartupInfo(startupInfo *StartupInfo) { - Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0) - return -} - -func GetStdHandle(stdhandle int) (handle Handle, err error) { - r0, _, e1 := Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0) - handle = Handle(r0) - if handle == InvalidHandle { - err = errnoErr(e1) - } - return -} - -func GetSystemTimeAsFileTime(time *Filetime) { - Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0) - return -} - -func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) { - r0, _, e1 := Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) { - r0, _, e1 := Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0) - rc = uint32(r0) - if rc == 0xffffffff { - err = errnoErr(e1) - } - return -} - -func GetVersion() (ver uint32, err error) { - r0, _, e1 := Syscall(procGetVersion.Addr(), 0, 0, 0, 0) - ver = uint32(r0) - if ver == 0 { - err = errnoErr(e1) - } - return -} - -func initializeProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, attrcount uint32, flags uint32, size *uintptr) (err error) { - r1, _, e1 := Syscall6(procInitializeProcThreadAttributeList.Addr(), 4, uintptr(unsafe.Pointer(attrlist)), uintptr(attrcount), uintptr(flags), uintptr(unsafe.Pointer(size)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func LoadLibrary(libname string) (handle Handle, err error) { - var _p0 *uint16 - _p0, err = UTF16PtrFromString(libname) - if err != nil { - return - } - return _LoadLibrary(_p0) -} - -func _LoadLibrary(libname *uint16) (handle Handle, err error) { - r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(libname)), 0, 0) - handle = Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func LocalFree(hmem Handle) (handle Handle, err error) { - r0, _, e1 := Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0) - handle = Handle(r0) - if handle != 0 { - err = errnoErr(e1) - } - return -} - -func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) { - r0, _, e1 := Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0) - addr = uintptr(r0) - if addr == 0 { - err = errnoErr(e1) - } - return -} - -func MoveFile(from *uint16, to *uint16) (err error) { - r1, _, e1 := Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) { - var _p0 uint32 - if inheritHandle { - _p0 = 1 - } - r0, _, e1 := Syscall(procOpenProcess.Addr(), 3, uintptr(da), uintptr(_p0), uintptr(pid)) - handle = Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func postQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) { - r1, _, e1 := Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) { - r1, _, e1 := Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) { - r1, _, e1 := Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) { - r1, _, e1 := Syscall6(procReadConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(toread), uintptr(unsafe.Pointer(read)), uintptr(unsafe.Pointer(inputControl)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { - var _p0 uint32 - if watchSubTree { - _p0 = 1 - } - r1, _, e1 := Syscall9(procReadDirectoryChangesW.Addr(), 8, uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func readFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) { - var _p0 *byte - if len(buf) > 0 { - _p0 = &buf[0] - } - r1, _, e1 := Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func RemoveDirectory(path *uint16) (err error) { - r1, _, e1 := Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func SetCurrentDirectory(path *uint16) (err error) { - r1, _, e1 := Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func SetEndOfFile(handle Handle) (err error) { - r1, _, e1 := Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { - r1, _, e1 := Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func SetFileAttributes(name *uint16, attrs uint32) (err error) { - r1, _, e1 := Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) { - r1, _, e1 := Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(handle), uintptr(flags), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) { - r0, _, e1 := Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0) - newlowoffset = uint32(r0) - if newlowoffset == 0xffffffff { - err = errnoErr(e1) - } - return -} - -func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) { - r1, _, e1 := Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) { - r1, _, e1 := Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func TerminateProcess(handle Handle, exitcode uint32) (err error) { - r1, _, e1 := Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func UnmapViewOfFile(addr uintptr) (err error) { - r1, _, e1 := Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) { - r1, _, e1 := Syscall9(procUpdateProcThreadAttribute.Addr(), 7, uintptr(unsafe.Pointer(attrlist)), uintptr(flags), uintptr(attr), uintptr(value), uintptr(size), uintptr(prevvalue), uintptr(unsafe.Pointer(returnedsize)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func VirtualLock(addr uintptr, length uintptr) (err error) { - r1, _, e1 := Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func VirtualUnlock(addr uintptr, length uintptr) (err error) { - r1, _, e1 := Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) { - r0, _, e1 := Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0) - event = uint32(r0) - if event == 0xffffffff { - err = errnoErr(e1) - } - return -} - -func WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) { - r1, _, e1 := Syscall6(procWriteConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(towrite), uintptr(unsafe.Pointer(written)), uintptr(unsafe.Pointer(reserved)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func writeFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) { - var _p0 *byte - if len(buf) > 0 { - _p0 = &buf[0] - } - r1, _, e1 := Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) { - r1, _, e1 := Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) { - Syscall9(procGetAcceptExSockaddrs.Addr(), 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0) - return -} - -func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) { - r1, _, e1 := Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func NetApiBufferFree(buf *byte) (neterr error) { - r0, _, _ := Syscall(procNetApiBufferFree.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0) - if r0 != 0 { - neterr = Errno(r0) - } - return -} - -func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) { - r0, _, _ := Syscall(procNetGetJoinInformation.Addr(), 3, uintptr(unsafe.Pointer(server)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bufType))) - if r0 != 0 { - neterr = Errno(r0) - } - return -} - -func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) { - r0, _, _ := Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0) - if r0 != 0 { - neterr = Errno(r0) - } - return -} - -func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) { - Syscall(procRtlGetNtVersionNumbers.Addr(), 3, uintptr(unsafe.Pointer(majorVersion)), uintptr(unsafe.Pointer(minorVersion)), uintptr(unsafe.Pointer(buildNumber))) - return -} - -func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) { - r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize))) - if r1&0xff == 0 { - err = errnoErr(e1) - } - return -} - -func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) { - r1, _, e1 := Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0) - if r1&0xff == 0 { - err = errnoErr(e1) - } - return -} - -func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) { - r0, _, e1 := Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0) - argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0)) - if argv == nil { - err = errnoErr(e1) - } - return -} - -func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) { - r1, _, e1 := Syscall(procGetUserProfileDirectoryW.Addr(), 3, uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func FreeAddrInfoW(addrinfo *AddrinfoW) { - Syscall(procFreeAddrInfoW.Addr(), 1, uintptr(unsafe.Pointer(addrinfo)), 0, 0) - return -} - -func GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) { - r0, _, _ := Syscall6(procGetAddrInfoW.Addr(), 4, uintptr(unsafe.Pointer(nodename)), uintptr(unsafe.Pointer(servicename)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(result)), 0, 0) - if r0 != 0 { - sockerr = Errno(r0) - } - return -} - -func WSACleanup() (err error) { - r1, _, e1 := Syscall(procWSACleanup.Addr(), 0, 0, 0, 0) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) { - r0, _, e1 := Syscall(procWSAEnumProtocolsW.Addr(), 3, uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength))) - n = int32(r0) - if n == -1 { - err = errnoErr(e1) - } - return -} - -func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { - r1, _, e1 := Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine)) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) { - r1, _, e1 := Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) { - r1, _, e1 := Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) { - r1, _, e1 := Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) { - r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func WSAStartup(verreq uint32, data *WSAData) (sockerr error) { - r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) - if r0 != 0 { - sockerr = Errno(r0) - } - return -} - -func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) { - r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func Closesocket(s Handle) (err error) { - r1, _, e1 := Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) { - r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func GetHostByName(name string) (h *Hostent, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(name) - if err != nil { - return - } - return _GetHostByName(_p0) -} - -func _GetHostByName(name *byte) (h *Hostent, err error) { - r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) - h = (*Hostent)(unsafe.Pointer(r0)) - if h == nil { - err = errnoErr(e1) - } - return -} - -func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { - r1, _, e1 := Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func GetProtoByName(name string) (p *Protoent, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(name) - if err != nil { - return - } - return _GetProtoByName(_p0) -} - -func _GetProtoByName(name *byte) (p *Protoent, err error) { - r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) - p = (*Protoent)(unsafe.Pointer(r0)) - if p == nil { - err = errnoErr(e1) - } - return -} - -func GetServByName(name string, proto string) (s *Servent, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(name) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(proto) - if err != nil { - return - } - return _GetServByName(_p0, _p1) -} - -func _GetServByName(name *byte, proto *byte) (s *Servent, err error) { - r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(proto)), 0) - s = (*Servent)(unsafe.Pointer(r0)) - if s == nil { - err = errnoErr(e1) - } - return -} - -func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { - r1, _, e1 := Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) { - r1, _, e1 := Syscall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(unsafe.Pointer(optlen)), 0) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func listen(s Handle, backlog int32) (err error) { - r1, _, e1 := Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func Ntohs(netshort uint16) (u uint16) { - r0, _, _ := Syscall(procntohs.Addr(), 1, uintptr(netshort), 0, 0) - u = uint16(r0) - return -} - -func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) { - r1, _, e1 := Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func shutdown(s Handle, how int32) (err error) { - r1, _, e1 := Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0) - if r1 == socket_error { - err = errnoErr(e1) - } - return -} - -func socket(af int32, typ int32, protocol int32) (handle Handle, err error) { - r0, _, e1 := Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol)) - handle = Handle(r0) - if handle == InvalidHandle { - err = errnoErr(e1) - } - return -} diff --git a/contrib/go/_std_1.22/src/text/template/doc.go b/contrib/go/_std_1.22/src/text/template/doc.go deleted file mode 100644 index 032784bc3f0c..000000000000 --- a/contrib/go/_std_1.22/src/text/template/doc.go +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package template implements data-driven templates for generating textual output. - -To generate HTML output, see [html/template], which has the same interface -as this package but automatically secures HTML output against certain attacks. - -Templates are executed by applying them to a data structure. Annotations in the -template refer to elements of the data structure (typically a field of a struct -or a key in a map) to control execution and derive values to be displayed. -Execution of the template walks the structure and sets the cursor, represented -by a period '.' and called "dot", to the value at the current location in the -structure as execution proceeds. - -The input text for a template is UTF-8-encoded text in any format. -"Actions"--data evaluations or control structures--are delimited by -"{{" and "}}"; all text outside actions is copied to the output unchanged. - -Once parsed, a template may be executed safely in parallel, although if parallel -executions share a Writer the output may be interleaved. - -Here is a trivial example that prints "17 items are made of wool". - - type Inventory struct { - Material string - Count uint - } - sweaters := Inventory{"wool", 17} - tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}") - if err != nil { panic(err) } - err = tmpl.Execute(os.Stdout, sweaters) - if err != nil { panic(err) } - -More intricate examples appear below. - -Text and spaces - -By default, all text between actions is copied verbatim when the template is -executed. For example, the string " items are made of " in the example above -appears on standard output when the program is run. - -However, to aid in formatting template source code, if an action's left -delimiter (by default "{{") is followed immediately by a minus sign and white -space, all trailing white space is trimmed from the immediately preceding text. -Similarly, if the right delimiter ("}}") is preceded by white space and a minus -sign, all leading white space is trimmed from the immediately following text. -In these trim markers, the white space must be present: -"{{- 3}}" is like "{{3}}" but trims the immediately preceding text, while -"{{-3}}" parses as an action containing the number -3. - -For instance, when executing the template whose source is - - "{{23 -}} < {{- 45}}" - -the generated output would be - - "23<45" - -For this trimming, the definition of white space characters is the same as in Go: -space, horizontal tab, carriage return, and newline. - -Actions - -Here is the list of actions. "Arguments" and "pipelines" are evaluations of -data, defined in detail in the corresponding sections that follow. - -*/ -// {{/* a comment */}} -// {{- /* a comment with white space trimmed from preceding and following text */ -}} -// A comment; discarded. May contain newlines. -// Comments do not nest and must start and end at the -// delimiters, as shown here. -/* - - {{pipeline}} - The default textual representation (the same as would be - printed by fmt.Print) of the value of the pipeline is copied - to the output. - - {{if pipeline}} T1 {{end}} - If the value of the pipeline is empty, no output is generated; - otherwise, T1 is executed. The empty values are false, 0, any - nil pointer or interface value, and any array, slice, map, or - string of length zero. - Dot is unaffected. - - {{if pipeline}} T1 {{else}} T0 {{end}} - If the value of the pipeline is empty, T0 is executed; - otherwise, T1 is executed. Dot is unaffected. - - {{if pipeline}} T1 {{else if pipeline}} T0 {{end}} - To simplify the appearance of if-else chains, the else action - of an if may include another if directly; the effect is exactly - the same as writing - {{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}} - - {{range pipeline}} T1 {{end}} - The value of the pipeline must be an array, slice, map, or channel. - If the value of the pipeline has length zero, nothing is output; - otherwise, dot is set to the successive elements of the array, - slice, or map and T1 is executed. If the value is a map and the - keys are of basic type with a defined order, the elements will be - visited in sorted key order. - - {{range pipeline}} T1 {{else}} T0 {{end}} - The value of the pipeline must be an array, slice, map, or channel. - If the value of the pipeline has length zero, dot is unaffected and - T0 is executed; otherwise, dot is set to the successive elements - of the array, slice, or map and T1 is executed. - - {{break}} - The innermost {{range pipeline}} loop is ended early, stopping the - current iteration and bypassing all remaining iterations. - - {{continue}} - The current iteration of the innermost {{range pipeline}} loop is - stopped, and the loop starts the next iteration. - - {{template "name"}} - The template with the specified name is executed with nil data. - - {{template "name" pipeline}} - The template with the specified name is executed with dot set - to the value of the pipeline. - - {{block "name" pipeline}} T1 {{end}} - A block is shorthand for defining a template - {{define "name"}} T1 {{end}} - and then executing it in place - {{template "name" pipeline}} - The typical use is to define a set of root templates that are - then customized by redefining the block templates within. - - {{with pipeline}} T1 {{end}} - If the value of the pipeline is empty, no output is generated; - otherwise, dot is set to the value of the pipeline and T1 is - executed. - - {{with pipeline}} T1 {{else}} T0 {{end}} - If the value of the pipeline is empty, dot is unaffected and T0 - is executed; otherwise, dot is set to the value of the pipeline - and T1 is executed. - -Arguments - -An argument is a simple value, denoted by one of the following. - - - A boolean, string, character, integer, floating-point, imaginary - or complex constant in Go syntax. These behave like Go's untyped - constants. Note that, as in Go, whether a large integer constant - overflows when assigned or passed to a function can depend on whether - the host machine's ints are 32 or 64 bits. - - The keyword nil, representing an untyped Go nil. - - The character '.' (period): - . - The result is the value of dot. - - A variable name, which is a (possibly empty) alphanumeric string - preceded by a dollar sign, such as - $piOver2 - or - $ - The result is the value of the variable. - Variables are described below. - - The name of a field of the data, which must be a struct, preceded - by a period, such as - .Field - The result is the value of the field. Field invocations may be - chained: - .Field1.Field2 - Fields can also be evaluated on variables, including chaining: - $x.Field1.Field2 - - The name of a key of the data, which must be a map, preceded - by a period, such as - .Key - The result is the map element value indexed by the key. - Key invocations may be chained and combined with fields to any - depth: - .Field1.Key1.Field2.Key2 - Although the key must be an alphanumeric identifier, unlike with - field names they do not need to start with an upper case letter. - Keys can also be evaluated on variables, including chaining: - $x.key1.key2 - - The name of a niladic method of the data, preceded by a period, - such as - .Method - The result is the value of invoking the method with dot as the - receiver, dot.Method(). Such a method must have one return value (of - any type) or two return values, the second of which is an error. - If it has two and the returned error is non-nil, execution terminates - and an error is returned to the caller as the value of Execute. - Method invocations may be chained and combined with fields and keys - to any depth: - .Field1.Key1.Method1.Field2.Key2.Method2 - Methods can also be evaluated on variables, including chaining: - $x.Method1.Field - - The name of a niladic function, such as - fun - The result is the value of invoking the function, fun(). The return - types and values behave as in methods. Functions and function - names are described below. - - A parenthesized instance of one the above, for grouping. The result - may be accessed by a field or map key invocation. - print (.F1 arg1) (.F2 arg2) - (.StructValuedMethod "arg").Field - -Arguments may evaluate to any type; if they are pointers the implementation -automatically indirects to the base type when required. -If an evaluation yields a function value, such as a function-valued -field of a struct, the function is not invoked automatically, but it -can be used as a truth value for an if action and the like. To invoke -it, use the call function, defined below. - -Pipelines - -A pipeline is a possibly chained sequence of "commands". A command is a simple -value (argument) or a function or method call, possibly with multiple arguments: - - Argument - The result is the value of evaluating the argument. - .Method [Argument...] - The method can be alone or the last element of a chain but, - unlike methods in the middle of a chain, it can take arguments. - The result is the value of calling the method with the - arguments: - dot.Method(Argument1, etc.) - functionName [Argument...] - The result is the value of calling the function associated - with the name: - function(Argument1, etc.) - Functions and function names are described below. - -A pipeline may be "chained" by separating a sequence of commands with pipeline -characters '|'. In a chained pipeline, the result of each command is -passed as the last argument of the following command. The output of the final -command in the pipeline is the value of the pipeline. - -The output of a command will be either one value or two values, the second of -which has type error. If that second value is present and evaluates to -non-nil, execution terminates and the error is returned to the caller of -Execute. - -Variables - -A pipeline inside an action may initialize a variable to capture the result. -The initialization has syntax - - $variable := pipeline - -where $variable is the name of the variable. An action that declares a -variable produces no output. - -Variables previously declared can also be assigned, using the syntax - - $variable = pipeline - -If a "range" action initializes a variable, the variable is set to the -successive elements of the iteration. Also, a "range" may declare two -variables, separated by a comma: - - range $index, $element := pipeline - -in which case $index and $element are set to the successive values of the -array/slice index or map key and element, respectively. Note that if there is -only one variable, it is assigned the element; this is opposite to the -convention in Go range clauses. - -A variable's scope extends to the "end" action of the control structure ("if", -"with", or "range") in which it is declared, or to the end of the template if -there is no such control structure. A template invocation does not inherit -variables from the point of its invocation. - -When execution begins, $ is set to the data argument passed to Execute, that is, -to the starting value of dot. - -Examples - -Here are some example one-line templates demonstrating pipelines and variables. -All produce the quoted word "output": - - {{"\"output\""}} - A string constant. - {{`"output"`}} - A raw string constant. - {{printf "%q" "output"}} - A function call. - {{"output" | printf "%q"}} - A function call whose final argument comes from the previous - command. - {{printf "%q" (print "out" "put")}} - A parenthesized argument. - {{"put" | printf "%s%s" "out" | printf "%q"}} - A more elaborate call. - {{"output" | printf "%s" | printf "%q"}} - A longer chain. - {{with "output"}}{{printf "%q" .}}{{end}} - A with action using dot. - {{with $x := "output" | printf "%q"}}{{$x}}{{end}} - A with action that creates and uses a variable. - {{with $x := "output"}}{{printf "%q" $x}}{{end}} - A with action that uses the variable in another action. - {{with $x := "output"}}{{$x | printf "%q"}}{{end}} - The same, but pipelined. - -Functions - -During execution functions are found in two function maps: first in the -template, then in the global function map. By default, no functions are defined -in the template but the Funcs method can be used to add them. - -Predefined global functions are named as follows. - - and - Returns the boolean AND of its arguments by returning the - first empty argument or the last argument. That is, - "and x y" behaves as "if x then y else x." - Evaluation proceeds through the arguments left to right - and returns when the result is determined. - call - Returns the result of calling the first argument, which - must be a function, with the remaining arguments as parameters. - Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where - Y is a func-valued field, map entry, or the like. - The first argument must be the result of an evaluation - that yields a value of function type (as distinct from - a predefined function such as print). The function must - return either one or two result values, the second of which - is of type error. If the arguments don't match the function - or the returned error value is non-nil, execution stops. - html - Returns the escaped HTML equivalent of the textual - representation of its arguments. This function is unavailable - in html/template, with a few exceptions. - index - Returns the result of indexing its first argument by the - following arguments. Thus "index x 1 2 3" is, in Go syntax, - x[1][2][3]. Each indexed item must be a map, slice, or array. - slice - slice returns the result of slicing its first argument by the - remaining arguments. Thus "slice x 1 2" is, in Go syntax, x[1:2], - while "slice x" is x[:], "slice x 1" is x[1:], and "slice x 1 2 3" - is x[1:2:3]. The first argument must be a string, slice, or array. - js - Returns the escaped JavaScript equivalent of the textual - representation of its arguments. - len - Returns the integer length of its argument. - not - Returns the boolean negation of its single argument. - or - Returns the boolean OR of its arguments by returning the - first non-empty argument or the last argument, that is, - "or x y" behaves as "if x then x else y". - Evaluation proceeds through the arguments left to right - and returns when the result is determined. - print - An alias for fmt.Sprint - printf - An alias for fmt.Sprintf - println - An alias for fmt.Sprintln - urlquery - Returns the escaped value of the textual representation of - its arguments in a form suitable for embedding in a URL query. - This function is unavailable in html/template, with a few - exceptions. - -The boolean functions take any zero value to be false and a non-zero -value to be true. - -There is also a set of binary comparison operators defined as -functions: - - eq - Returns the boolean truth of arg1 == arg2 - ne - Returns the boolean truth of arg1 != arg2 - lt - Returns the boolean truth of arg1 < arg2 - le - Returns the boolean truth of arg1 <= arg2 - gt - Returns the boolean truth of arg1 > arg2 - ge - Returns the boolean truth of arg1 >= arg2 - -For simpler multi-way equality tests, eq (only) accepts two or more -arguments and compares the second and subsequent to the first, -returning in effect - - arg1==arg2 || arg1==arg3 || arg1==arg4 ... - -(Unlike with || in Go, however, eq is a function call and all the -arguments will be evaluated.) - -The comparison functions work on any values whose type Go defines as -comparable. For basic types such as integers, the rules are relaxed: -size and exact type are ignored, so any integer value, signed or unsigned, -may be compared with any other integer value. (The arithmetic value is compared, -not the bit pattern, so all negative integers are less than all unsigned integers.) -However, as usual, one may not compare an int with a float32 and so on. - -Associated templates - -Each template is named by a string specified when it is created. Also, each -template is associated with zero or more other templates that it may invoke by -name; such associations are transitive and form a name space of templates. - -A template may use a template invocation to instantiate another associated -template; see the explanation of the "template" action above. The name must be -that of a template associated with the template that contains the invocation. - -Nested template definitions - -When parsing a template, another template may be defined and associated with the -template being parsed. Template definitions must appear at the top level of the -template, much like global variables in a Go program. - -The syntax of such definitions is to surround each template declaration with a -"define" and "end" action. - -The define action names the template being created by providing a string -constant. Here is a simple example: - - {{define "T1"}}ONE{{end}} - {{define "T2"}}TWO{{end}} - {{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}} - {{template "T3"}} - -This defines two templates, T1 and T2, and a third T3 that invokes the other two -when it is executed. Finally it invokes T3. If executed this template will -produce the text - - ONE TWO - -By construction, a template may reside in only one association. If it's -necessary to have a template addressable from multiple associations, the -template definition must be parsed multiple times to create distinct *Template -values, or must be copied with [Template.Clone] or [Template.AddParseTree]. - -Parse may be called multiple times to assemble the various associated templates; -see [ParseFiles], [ParseGlob], [Template.ParseFiles] and [Template.ParseGlob] -for simple ways to parse related templates stored in files. - -A template may be executed directly or through [Template.ExecuteTemplate], which executes -an associated template identified by name. To invoke our example above, we -might write, - - err := tmpl.Execute(os.Stdout, "no data needed") - if err != nil { - log.Fatalf("execution failed: %s", err) - } - -or to invoke a particular template explicitly by name, - - err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed") - if err != nil { - log.Fatalf("execution failed: %s", err) - } - -*/ -package template diff --git a/contrib/go/_std_1.22/src/text/template/exec.go b/contrib/go/_std_1.22/src/text/template/exec.go deleted file mode 100644 index 2b778fff696f..000000000000 --- a/contrib/go/_std_1.22/src/text/template/exec.go +++ /dev/null @@ -1,1067 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "errors" - "fmt" - "internal/fmtsort" - "io" - "reflect" - "runtime" - "strings" - "text/template/parse" -) - -// maxExecDepth specifies the maximum stack depth of templates within -// templates. This limit is only practically reached by accidentally -// recursive template invocations. This limit allows us to return -// an error instead of triggering a stack overflow. -var maxExecDepth = initMaxExecDepth() - -func initMaxExecDepth() int { - if runtime.GOARCH == "wasm" { - return 1000 - } - return 100000 -} - -// state represents the state of an execution. It's not part of the -// template so that multiple executions of the same template -// can execute in parallel. -type state struct { - tmpl *Template - wr io.Writer - node parse.Node // current node, for errors - vars []variable // push-down stack of variable values. - depth int // the height of the stack of executing templates. -} - -// variable holds the dynamic value of a variable such as $, $x etc. -type variable struct { - name string - value reflect.Value -} - -// push pushes a new variable on the stack. -func (s *state) push(name string, value reflect.Value) { - s.vars = append(s.vars, variable{name, value}) -} - -// mark returns the length of the variable stack. -func (s *state) mark() int { - return len(s.vars) -} - -// pop pops the variable stack up to the mark. -func (s *state) pop(mark int) { - s.vars = s.vars[0:mark] -} - -// setVar overwrites the last declared variable with the given name. -// Used by variable assignments. -func (s *state) setVar(name string, value reflect.Value) { - for i := s.mark() - 1; i >= 0; i-- { - if s.vars[i].name == name { - s.vars[i].value = value - return - } - } - s.errorf("undefined variable: %s", name) -} - -// setTopVar overwrites the top-nth variable on the stack. Used by range iterations. -func (s *state) setTopVar(n int, value reflect.Value) { - s.vars[len(s.vars)-n].value = value -} - -// varValue returns the value of the named variable. -func (s *state) varValue(name string) reflect.Value { - for i := s.mark() - 1; i >= 0; i-- { - if s.vars[i].name == name { - return s.vars[i].value - } - } - s.errorf("undefined variable: %s", name) - return zero -} - -var zero reflect.Value - -type missingValType struct{} - -var missingVal = reflect.ValueOf(missingValType{}) - -var missingValReflectType = reflect.TypeFor[missingValType]() - -func isMissing(v reflect.Value) bool { - return v.IsValid() && v.Type() == missingValReflectType -} - -// at marks the state to be on node n, for error reporting. -func (s *state) at(node parse.Node) { - s.node = node -} - -// doublePercent returns the string with %'s replaced by %%, if necessary, -// so it can be used safely inside a Printf format string. -func doublePercent(str string) string { - return strings.ReplaceAll(str, "%", "%%") -} - -// TODO: It would be nice if ExecError was more broken down, but -// the way ErrorContext embeds the template name makes the -// processing too clumsy. - -// ExecError is the custom error type returned when Execute has an -// error evaluating its template. (If a write error occurs, the actual -// error is returned; it will not be of type ExecError.) -type ExecError struct { - Name string // Name of template. - Err error // Pre-formatted error. -} - -func (e ExecError) Error() string { - return e.Err.Error() -} - -func (e ExecError) Unwrap() error { - return e.Err -} - -// errorf records an ExecError and terminates processing. -func (s *state) errorf(format string, args ...any) { - name := doublePercent(s.tmpl.Name()) - if s.node == nil { - format = fmt.Sprintf("template: %s: %s", name, format) - } else { - location, context := s.tmpl.ErrorContext(s.node) - format = fmt.Sprintf("template: %s: executing %q at <%s>: %s", location, name, doublePercent(context), format) - } - panic(ExecError{ - Name: s.tmpl.Name(), - Err: fmt.Errorf(format, args...), - }) -} - -// writeError is the wrapper type used internally when Execute has an -// error writing to its output. We strip the wrapper in errRecover. -// Note that this is not an implementation of error, so it cannot escape -// from the package as an error value. -type writeError struct { - Err error // Original error. -} - -func (s *state) writeError(err error) { - panic(writeError{ - Err: err, - }) -} - -// errRecover is the handler that turns panics into returns from the top -// level of Parse. -func errRecover(errp *error) { - e := recover() - if e != nil { - switch err := e.(type) { - case runtime.Error: - panic(e) - case writeError: - *errp = err.Err // Strip the wrapper. - case ExecError: - *errp = err // Keep the wrapper. - default: - panic(e) - } - } -} - -// ExecuteTemplate applies the template associated with t that has the given name -// to the specified data object and writes the output to wr. -// If an error occurs executing the template or writing its output, -// execution stops, but partial results may already have been written to -// the output writer. -// A template may be executed safely in parallel, although if parallel -// executions share a Writer the output may be interleaved. -func (t *Template) ExecuteTemplate(wr io.Writer, name string, data any) error { - tmpl := t.Lookup(name) - if tmpl == nil { - return fmt.Errorf("template: no template %q associated with template %q", name, t.name) - } - return tmpl.Execute(wr, data) -} - -// Execute applies a parsed template to the specified data object, -// and writes the output to wr. -// If an error occurs executing the template or writing its output, -// execution stops, but partial results may already have been written to -// the output writer. -// A template may be executed safely in parallel, although if parallel -// executions share a Writer the output may be interleaved. -// -// If data is a reflect.Value, the template applies to the concrete -// value that the reflect.Value holds, as in fmt.Print. -func (t *Template) Execute(wr io.Writer, data any) error { - return t.execute(wr, data) -} - -func (t *Template) execute(wr io.Writer, data any) (err error) { - defer errRecover(&err) - value, ok := data.(reflect.Value) - if !ok { - value = reflect.ValueOf(data) - } - state := &state{ - tmpl: t, - wr: wr, - vars: []variable{{"$", value}}, - } - if t.Tree == nil || t.Root == nil { - state.errorf("%q is an incomplete or empty template", t.Name()) - } - state.walk(value, t.Root) - return -} - -// DefinedTemplates returns a string listing the defined templates, -// prefixed by the string "; defined templates are: ". If there are none, -// it returns the empty string. For generating an error message here -// and in html/template. -func (t *Template) DefinedTemplates() string { - if t.common == nil { - return "" - } - var b strings.Builder - t.muTmpl.RLock() - defer t.muTmpl.RUnlock() - for name, tmpl := range t.tmpl { - if tmpl.Tree == nil || tmpl.Root == nil { - continue - } - if b.Len() == 0 { - b.WriteString("; defined templates are: ") - } else { - b.WriteString(", ") - } - fmt.Fprintf(&b, "%q", name) - } - return b.String() -} - -// Sentinel errors for use with panic to signal early exits from range loops. -var ( - walkBreak = errors.New("break") - walkContinue = errors.New("continue") -) - -// Walk functions step through the major pieces of the template structure, -// generating output as they go. -func (s *state) walk(dot reflect.Value, node parse.Node) { - s.at(node) - switch node := node.(type) { - case *parse.ActionNode: - // Do not pop variables so they persist until next end. - // Also, if the action declares variables, don't print the result. - val := s.evalPipeline(dot, node.Pipe) - if len(node.Pipe.Decl) == 0 { - s.printValue(node, val) - } - case *parse.BreakNode: - panic(walkBreak) - case *parse.CommentNode: - case *parse.ContinueNode: - panic(walkContinue) - case *parse.IfNode: - s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) - case *parse.ListNode: - for _, node := range node.Nodes { - s.walk(dot, node) - } - case *parse.RangeNode: - s.walkRange(dot, node) - case *parse.TemplateNode: - s.walkTemplate(dot, node) - case *parse.TextNode: - if _, err := s.wr.Write(node.Text); err != nil { - s.writeError(err) - } - case *parse.WithNode: - s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList) - default: - s.errorf("unknown node: %s", node) - } -} - -// walkIfOrWith walks an 'if' or 'with' node. The two control structures -// are identical in behavior except that 'with' sets dot. -func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) { - defer s.pop(s.mark()) - val := s.evalPipeline(dot, pipe) - truth, ok := isTrue(indirectInterface(val)) - if !ok { - s.errorf("if/with can't use %v", val) - } - if truth { - if typ == parse.NodeWith { - s.walk(val, list) - } else { - s.walk(dot, list) - } - } else if elseList != nil { - s.walk(dot, elseList) - } -} - -// IsTrue reports whether the value is 'true', in the sense of not the zero of its type, -// and whether the value has a meaningful truth value. This is the definition of -// truth used by if and other such actions. -func IsTrue(val any) (truth, ok bool) { - return isTrue(reflect.ValueOf(val)) -} - -func isTrue(val reflect.Value) (truth, ok bool) { - if !val.IsValid() { - // Something like var x interface{}, never set. It's a form of nil. - return false, true - } - switch val.Kind() { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - truth = val.Len() > 0 - case reflect.Bool: - truth = val.Bool() - case reflect.Complex64, reflect.Complex128: - truth = val.Complex() != 0 - case reflect.Chan, reflect.Func, reflect.Pointer, reflect.Interface: - truth = !val.IsNil() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - truth = val.Int() != 0 - case reflect.Float32, reflect.Float64: - truth = val.Float() != 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - truth = val.Uint() != 0 - case reflect.Struct: - truth = true // Struct values are always true. - default: - return - } - return truth, true -} - -func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { - s.at(r) - defer func() { - if r := recover(); r != nil && r != walkBreak { - panic(r) - } - }() - defer s.pop(s.mark()) - val, _ := indirect(s.evalPipeline(dot, r.Pipe)) - // mark top of stack before any variables in the body are pushed. - mark := s.mark() - oneIteration := func(index, elem reflect.Value) { - if len(r.Pipe.Decl) > 0 { - if r.Pipe.IsAssign { - // With two variables, index comes first. - // With one, we use the element. - if len(r.Pipe.Decl) > 1 { - s.setVar(r.Pipe.Decl[0].Ident[0], index) - } else { - s.setVar(r.Pipe.Decl[0].Ident[0], elem) - } - } else { - // Set top var (lexically the second if there - // are two) to the element. - s.setTopVar(1, elem) - } - } - if len(r.Pipe.Decl) > 1 { - if r.Pipe.IsAssign { - s.setVar(r.Pipe.Decl[1].Ident[0], elem) - } else { - // Set next var (lexically the first if there - // are two) to the index. - s.setTopVar(2, index) - } - } - defer s.pop(mark) - defer func() { - // Consume panic(walkContinue) - if r := recover(); r != nil && r != walkContinue { - panic(r) - } - }() - s.walk(elem, r.List) - } - switch val.Kind() { - case reflect.Array, reflect.Slice: - if val.Len() == 0 { - break - } - for i := 0; i < val.Len(); i++ { - oneIteration(reflect.ValueOf(i), val.Index(i)) - } - return - case reflect.Map: - if val.Len() == 0 { - break - } - om := fmtsort.Sort(val) - for i, key := range om.Key { - oneIteration(key, om.Value[i]) - } - return - case reflect.Chan: - if val.IsNil() { - break - } - if val.Type().ChanDir() == reflect.SendDir { - s.errorf("range over send-only channel %v", val) - break - } - i := 0 - for ; ; i++ { - elem, ok := val.Recv() - if !ok { - break - } - oneIteration(reflect.ValueOf(i), elem) - } - if i == 0 { - break - } - return - case reflect.Invalid: - break // An invalid value is likely a nil map, etc. and acts like an empty map. - default: - s.errorf("range can't iterate over %v", val) - } - if r.ElseList != nil { - s.walk(dot, r.ElseList) - } -} - -func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) { - s.at(t) - tmpl := s.tmpl.Lookup(t.Name) - if tmpl == nil { - s.errorf("template %q not defined", t.Name) - } - if s.depth == maxExecDepth { - s.errorf("exceeded maximum template depth (%v)", maxExecDepth) - } - // Variables declared by the pipeline persist. - dot = s.evalPipeline(dot, t.Pipe) - newState := *s - newState.depth++ - newState.tmpl = tmpl - // No dynamic scoping: template invocations inherit no variables. - newState.vars = []variable{{"$", dot}} - newState.walk(dot, tmpl.Root) -} - -// Eval functions evaluate pipelines, commands, and their elements and extract -// values from the data structure by examining fields, calling methods, and so on. -// The printing of those values happens only through walk functions. - -// evalPipeline returns the value acquired by evaluating a pipeline. If the -// pipeline has a variable declaration, the variable will be pushed on the -// stack. Callers should therefore pop the stack after they are finished -// executing commands depending on the pipeline value. -func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value reflect.Value) { - if pipe == nil { - return - } - s.at(pipe) - value = missingVal - for _, cmd := range pipe.Cmds { - value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg. - // If the object has type interface{}, dig down one level to the thing inside. - if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 { - value = reflect.ValueOf(value.Interface()) // lovely! - } - } - for _, variable := range pipe.Decl { - if pipe.IsAssign { - s.setVar(variable.Ident[0], value) - } else { - s.push(variable.Ident[0], value) - } - } - return value -} - -func (s *state) notAFunction(args []parse.Node, final reflect.Value) { - if len(args) > 1 || !isMissing(final) { - s.errorf("can't give argument to non-function %s", args[0]) - } -} - -func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final reflect.Value) reflect.Value { - firstWord := cmd.Args[0] - switch n := firstWord.(type) { - case *parse.FieldNode: - return s.evalFieldNode(dot, n, cmd.Args, final) - case *parse.ChainNode: - return s.evalChainNode(dot, n, cmd.Args, final) - case *parse.IdentifierNode: - // Must be a function. - return s.evalFunction(dot, n, cmd, cmd.Args, final) - case *parse.PipeNode: - // Parenthesized pipeline. The arguments are all inside the pipeline; final must be absent. - s.notAFunction(cmd.Args, final) - return s.evalPipeline(dot, n) - case *parse.VariableNode: - return s.evalVariableNode(dot, n, cmd.Args, final) - } - s.at(firstWord) - s.notAFunction(cmd.Args, final) - switch word := firstWord.(type) { - case *parse.BoolNode: - return reflect.ValueOf(word.True) - case *parse.DotNode: - return dot - case *parse.NilNode: - s.errorf("nil is not a command") - case *parse.NumberNode: - return s.idealConstant(word) - case *parse.StringNode: - return reflect.ValueOf(word.Text) - } - s.errorf("can't evaluate command %q", firstWord) - panic("not reached") -} - -// idealConstant is called to return the value of a number in a context where -// we don't know the type. In that case, the syntax of the number tells us -// its type, and we use Go rules to resolve. Note there is no such thing as -// a uint ideal constant in this situation - the value must be of int type. -func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value { - // These are ideal constants but we don't know the type - // and we have no context. (If it was a method argument, - // we'd know what we need.) The syntax guides us to some extent. - s.at(constant) - switch { - case constant.IsComplex: - return reflect.ValueOf(constant.Complex128) // incontrovertible. - - case constant.IsFloat && - !isHexInt(constant.Text) && !isRuneInt(constant.Text) && - strings.ContainsAny(constant.Text, ".eEpP"): - return reflect.ValueOf(constant.Float64) - - case constant.IsInt: - n := int(constant.Int64) - if int64(n) != constant.Int64 { - s.errorf("%s overflows int", constant.Text) - } - return reflect.ValueOf(n) - - case constant.IsUint: - s.errorf("%s overflows int", constant.Text) - } - return zero -} - -func isRuneInt(s string) bool { - return len(s) > 0 && s[0] == '\'' -} - -func isHexInt(s string) bool { - return len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && !strings.ContainsAny(s, "pP") -} - -func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value { - s.at(field) - return s.evalFieldChain(dot, dot, field, field.Ident, args, final) -} - -func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value { - s.at(chain) - if len(chain.Field) == 0 { - s.errorf("internal error: no fields in evalChainNode") - } - if chain.Node.Type() == parse.NodeNil { - s.errorf("indirection through explicit nil in %s", chain) - } - // (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields. - pipe := s.evalArg(dot, nil, chain.Node) - return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final) -} - -func (s *state) evalVariableNode(dot reflect.Value, variable *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value { - // $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields. - s.at(variable) - value := s.varValue(variable.Ident[0]) - if len(variable.Ident) == 1 { - s.notAFunction(args, final) - return value - } - return s.evalFieldChain(dot, value, variable, variable.Ident[1:], args, final) -} - -// evalFieldChain evaluates .X.Y.Z possibly followed by arguments. -// dot is the environment in which to evaluate arguments, while -// receiver is the value being walked along the chain. -func (s *state) evalFieldChain(dot, receiver reflect.Value, node parse.Node, ident []string, args []parse.Node, final reflect.Value) reflect.Value { - n := len(ident) - for i := 0; i < n-1; i++ { - receiver = s.evalField(dot, ident[i], node, nil, missingVal, receiver) - } - // Now if it's a method, it gets the arguments. - return s.evalField(dot, ident[n-1], node, args, final, receiver) -} - -func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd parse.Node, args []parse.Node, final reflect.Value) reflect.Value { - s.at(node) - name := node.Ident - function, isBuiltin, ok := findFunction(name, s.tmpl) - if !ok { - s.errorf("%q is not a defined function", name) - } - return s.evalCall(dot, function, isBuiltin, cmd, name, args, final) -} - -// evalField evaluates an expression like (.Field) or (.Field arg1 arg2). -// The 'final' argument represents the return value from the preceding -// value of the pipeline, if any. -func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value { - if !receiver.IsValid() { - if s.tmpl.option.missingKey == mapError { // Treat invalid value as missing map key. - s.errorf("nil data; no entry for key %q", fieldName) - } - return zero - } - typ := receiver.Type() - receiver, isNil := indirect(receiver) - if receiver.Kind() == reflect.Interface && isNil { - // Calling a method on a nil interface can't work. The - // MethodByName method call below would panic. - s.errorf("nil pointer evaluating %s.%s", typ, fieldName) - return zero - } - - // Unless it's an interface, need to get to a value of type *T to guarantee - // we see all methods of T and *T. - ptr := receiver - if ptr.Kind() != reflect.Interface && ptr.Kind() != reflect.Pointer && ptr.CanAddr() { - ptr = ptr.Addr() - } - if method := ptr.MethodByName(fieldName); method.IsValid() { - return s.evalCall(dot, method, false, node, fieldName, args, final) - } - hasArgs := len(args) > 1 || !isMissing(final) - // It's not a method; must be a field of a struct or an element of a map. - switch receiver.Kind() { - case reflect.Struct: - tField, ok := receiver.Type().FieldByName(fieldName) - if ok { - field, err := receiver.FieldByIndexErr(tField.Index) - if !tField.IsExported() { - s.errorf("%s is an unexported field of struct type %s", fieldName, typ) - } - if err != nil { - s.errorf("%v", err) - } - // If it's a function, we must call it. - if hasArgs { - s.errorf("%s has arguments but cannot be invoked as function", fieldName) - } - return field - } - case reflect.Map: - // If it's a map, attempt to use the field name as a key. - nameVal := reflect.ValueOf(fieldName) - if nameVal.Type().AssignableTo(receiver.Type().Key()) { - if hasArgs { - s.errorf("%s is not a method but has arguments", fieldName) - } - result := receiver.MapIndex(nameVal) - if !result.IsValid() { - switch s.tmpl.option.missingKey { - case mapInvalid: - // Just use the invalid value. - case mapZeroValue: - result = reflect.Zero(receiver.Type().Elem()) - case mapError: - s.errorf("map has no entry for key %q", fieldName) - } - } - return result - } - case reflect.Pointer: - etyp := receiver.Type().Elem() - if etyp.Kind() == reflect.Struct { - if _, ok := etyp.FieldByName(fieldName); !ok { - // If there's no such field, say "can't evaluate" - // instead of "nil pointer evaluating". - break - } - } - if isNil { - s.errorf("nil pointer evaluating %s.%s", typ, fieldName) - } - } - s.errorf("can't evaluate field %s in type %s", fieldName, typ) - panic("not reached") -} - -var ( - errorType = reflect.TypeFor[error]() - fmtStringerType = reflect.TypeFor[fmt.Stringer]() - reflectValueType = reflect.TypeFor[reflect.Value]() -) - -// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so -// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0] -// as the function itself. -func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value { - if args != nil { - args = args[1:] // Zeroth arg is function name/node; not passed to function. - } - typ := fun.Type() - numIn := len(args) - if !isMissing(final) { - numIn++ - } - numFixed := len(args) - if typ.IsVariadic() { - numFixed = typ.NumIn() - 1 // last arg is the variadic one. - if numIn < numFixed { - s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args)) - } - } else if numIn != typ.NumIn() { - s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), numIn) - } - if !goodFunc(typ) { - // TODO: This could still be a confusing error; maybe goodFunc should provide info. - s.errorf("can't call method/function %q with %d results", name, typ.NumOut()) - } - - unwrap := func(v reflect.Value) reflect.Value { - if v.Type() == reflectValueType { - v = v.Interface().(reflect.Value) - } - return v - } - - // Special case for builtin and/or, which short-circuit. - if isBuiltin && (name == "and" || name == "or") { - argType := typ.In(0) - var v reflect.Value - for _, arg := range args { - v = s.evalArg(dot, argType, arg).Interface().(reflect.Value) - if truth(v) == (name == "or") { - // This value was already unwrapped - // by the .Interface().(reflect.Value). - return v - } - } - if final != missingVal { - // The last argument to and/or is coming from - // the pipeline. We didn't short circuit on an earlier - // argument, so we are going to return this one. - // We don't have to evaluate final, but we do - // have to check its type. Then, since we are - // going to return it, we have to unwrap it. - v = unwrap(s.validateType(final, argType)) - } - return v - } - - // Build the arg list. - argv := make([]reflect.Value, numIn) - // Args must be evaluated. Fixed args first. - i := 0 - for ; i < numFixed && i < len(args); i++ { - argv[i] = s.evalArg(dot, typ.In(i), args[i]) - } - // Now the ... args. - if typ.IsVariadic() { - argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice. - for ; i < len(args); i++ { - argv[i] = s.evalArg(dot, argType, args[i]) - } - } - // Add final value if necessary. - if !isMissing(final) { - t := typ.In(typ.NumIn() - 1) - if typ.IsVariadic() { - if numIn-1 < numFixed { - // The added final argument corresponds to a fixed parameter of the function. - // Validate against the type of the actual parameter. - t = typ.In(numIn - 1) - } else { - // The added final argument corresponds to the variadic part. - // Validate against the type of the elements of the variadic slice. - t = t.Elem() - } - } - argv[i] = s.validateType(final, t) - } - v, err := safeCall(fun, argv) - // If we have an error that is not nil, stop execution and return that - // error to the caller. - if err != nil { - s.at(node) - s.errorf("error calling %s: %w", name, err) - } - return unwrap(v) -} - -// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero. -func canBeNil(typ reflect.Type) bool { - switch typ.Kind() { - case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice: - return true - case reflect.Struct: - return typ == reflectValueType - } - return false -} - -// validateType guarantees that the value is valid and assignable to the type. -func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value { - if !value.IsValid() { - if typ == nil { - // An untyped nil interface{}. Accept as a proper nil value. - return reflect.ValueOf(nil) - } - if canBeNil(typ) { - // Like above, but use the zero value of the non-nil type. - return reflect.Zero(typ) - } - s.errorf("invalid value; expected %s", typ) - } - if typ == reflectValueType && value.Type() != typ { - return reflect.ValueOf(value) - } - if typ != nil && !value.Type().AssignableTo(typ) { - if value.Kind() == reflect.Interface && !value.IsNil() { - value = value.Elem() - if value.Type().AssignableTo(typ) { - return value - } - // fallthrough - } - // Does one dereference or indirection work? We could do more, as we - // do with method receivers, but that gets messy and method receivers - // are much more constrained, so it makes more sense there than here. - // Besides, one is almost always all you need. - switch { - case value.Kind() == reflect.Pointer && value.Type().Elem().AssignableTo(typ): - value = value.Elem() - if !value.IsValid() { - s.errorf("dereference of nil pointer of type %s", typ) - } - case reflect.PointerTo(value.Type()).AssignableTo(typ) && value.CanAddr(): - value = value.Addr() - default: - s.errorf("wrong type for value; expected %s; got %s", typ, value.Type()) - } - } - return value -} - -func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) reflect.Value { - s.at(n) - switch arg := n.(type) { - case *parse.DotNode: - return s.validateType(dot, typ) - case *parse.NilNode: - if canBeNil(typ) { - return reflect.Zero(typ) - } - s.errorf("cannot assign nil to %s", typ) - case *parse.FieldNode: - return s.validateType(s.evalFieldNode(dot, arg, []parse.Node{n}, missingVal), typ) - case *parse.VariableNode: - return s.validateType(s.evalVariableNode(dot, arg, nil, missingVal), typ) - case *parse.PipeNode: - return s.validateType(s.evalPipeline(dot, arg), typ) - case *parse.IdentifierNode: - return s.validateType(s.evalFunction(dot, arg, arg, nil, missingVal), typ) - case *parse.ChainNode: - return s.validateType(s.evalChainNode(dot, arg, nil, missingVal), typ) - } - switch typ.Kind() { - case reflect.Bool: - return s.evalBool(typ, n) - case reflect.Complex64, reflect.Complex128: - return s.evalComplex(typ, n) - case reflect.Float32, reflect.Float64: - return s.evalFloat(typ, n) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return s.evalInteger(typ, n) - case reflect.Interface: - if typ.NumMethod() == 0 { - return s.evalEmptyInterface(dot, n) - } - case reflect.Struct: - if typ == reflectValueType { - return reflect.ValueOf(s.evalEmptyInterface(dot, n)) - } - case reflect.String: - return s.evalString(typ, n) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return s.evalUnsignedInteger(typ, n) - } - s.errorf("can't handle %s for arg of type %s", n, typ) - panic("not reached") -} - -func (s *state) evalBool(typ reflect.Type, n parse.Node) reflect.Value { - s.at(n) - if n, ok := n.(*parse.BoolNode); ok { - value := reflect.New(typ).Elem() - value.SetBool(n.True) - return value - } - s.errorf("expected bool; found %s", n) - panic("not reached") -} - -func (s *state) evalString(typ reflect.Type, n parse.Node) reflect.Value { - s.at(n) - if n, ok := n.(*parse.StringNode); ok { - value := reflect.New(typ).Elem() - value.SetString(n.Text) - return value - } - s.errorf("expected string; found %s", n) - panic("not reached") -} - -func (s *state) evalInteger(typ reflect.Type, n parse.Node) reflect.Value { - s.at(n) - if n, ok := n.(*parse.NumberNode); ok && n.IsInt { - value := reflect.New(typ).Elem() - value.SetInt(n.Int64) - return value - } - s.errorf("expected integer; found %s", n) - panic("not reached") -} - -func (s *state) evalUnsignedInteger(typ reflect.Type, n parse.Node) reflect.Value { - s.at(n) - if n, ok := n.(*parse.NumberNode); ok && n.IsUint { - value := reflect.New(typ).Elem() - value.SetUint(n.Uint64) - return value - } - s.errorf("expected unsigned integer; found %s", n) - panic("not reached") -} - -func (s *state) evalFloat(typ reflect.Type, n parse.Node) reflect.Value { - s.at(n) - if n, ok := n.(*parse.NumberNode); ok && n.IsFloat { - value := reflect.New(typ).Elem() - value.SetFloat(n.Float64) - return value - } - s.errorf("expected float; found %s", n) - panic("not reached") -} - -func (s *state) evalComplex(typ reflect.Type, n parse.Node) reflect.Value { - if n, ok := n.(*parse.NumberNode); ok && n.IsComplex { - value := reflect.New(typ).Elem() - value.SetComplex(n.Complex128) - return value - } - s.errorf("expected complex; found %s", n) - panic("not reached") -} - -func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Value { - s.at(n) - switch n := n.(type) { - case *parse.BoolNode: - return reflect.ValueOf(n.True) - case *parse.DotNode: - return dot - case *parse.FieldNode: - return s.evalFieldNode(dot, n, nil, missingVal) - case *parse.IdentifierNode: - return s.evalFunction(dot, n, n, nil, missingVal) - case *parse.NilNode: - // NilNode is handled in evalArg, the only place that calls here. - s.errorf("evalEmptyInterface: nil (can't happen)") - case *parse.NumberNode: - return s.idealConstant(n) - case *parse.StringNode: - return reflect.ValueOf(n.Text) - case *parse.VariableNode: - return s.evalVariableNode(dot, n, nil, missingVal) - case *parse.PipeNode: - return s.evalPipeline(dot, n) - } - s.errorf("can't handle assignment of %s to empty interface argument", n) - panic("not reached") -} - -// indirect returns the item at the end of indirection, and a bool to indicate -// if it's nil. If the returned bool is true, the returned value's kind will be -// either a pointer or interface. -func indirect(v reflect.Value) (rv reflect.Value, isNil bool) { - for ; v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface; v = v.Elem() { - if v.IsNil() { - return v, true - } - } - return v, false -} - -// indirectInterface returns the concrete value in an interface value, -// or else the zero reflect.Value. -// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x): -// the fact that x was an interface value is forgotten. -func indirectInterface(v reflect.Value) reflect.Value { - if v.Kind() != reflect.Interface { - return v - } - if v.IsNil() { - return reflect.Value{} - } - return v.Elem() -} - -// printValue writes the textual representation of the value to the output of -// the template. -func (s *state) printValue(n parse.Node, v reflect.Value) { - s.at(n) - iface, ok := printableValue(v) - if !ok { - s.errorf("can't print %s of type %s", n, v.Type()) - } - _, err := fmt.Fprint(s.wr, iface) - if err != nil { - s.writeError(err) - } -} - -// printableValue returns the, possibly indirected, interface value inside v that -// is best for a call to formatted printer. -func printableValue(v reflect.Value) (any, bool) { - if v.Kind() == reflect.Pointer { - v, _ = indirect(v) // fmt.Fprint handles nil. - } - if !v.IsValid() { - return "", true - } - - if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) { - if v.CanAddr() && (reflect.PointerTo(v.Type()).Implements(errorType) || reflect.PointerTo(v.Type()).Implements(fmtStringerType)) { - v = v.Addr() - } else { - switch v.Kind() { - case reflect.Chan, reflect.Func: - return nil, false - } - } - } - return v.Interface(), true -} diff --git a/contrib/go/_std_1.22/src/text/template/parse/parse.go b/contrib/go/_std_1.22/src/text/template/parse/parse.go deleted file mode 100644 index d43d5334ba04..000000000000 --- a/contrib/go/_std_1.22/src/text/template/parse/parse.go +++ /dev/null @@ -1,827 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package parse builds parse trees for templates as defined by text/template -// and html/template. Clients should use those packages to construct templates -// rather than this one, which provides shared internal data structures not -// intended for general use. -package parse - -import ( - "bytes" - "fmt" - "runtime" - "strconv" - "strings" -) - -// Tree is the representation of a single parsed template. -type Tree struct { - Name string // name of the template represented by the tree. - ParseName string // name of the top-level template during parsing, for error messages. - Root *ListNode // top-level root of the tree. - Mode Mode // parsing mode. - text string // text parsed to create the template (or its parent) - // Parsing only; cleared after parse. - funcs []map[string]any - lex *lexer - token [3]item // three-token lookahead for parser. - peekCount int - vars []string // variables defined at the moment. - treeSet map[string]*Tree - actionLine int // line of left delim starting action - rangeDepth int -} - -// A mode value is a set of flags (or 0). Modes control parser behavior. -type Mode uint - -const ( - ParseComments Mode = 1 << iota // parse comments and add them to AST - SkipFuncCheck // do not check that functions are defined -) - -// Copy returns a copy of the Tree. Any parsing state is discarded. -func (t *Tree) Copy() *Tree { - if t == nil { - return nil - } - return &Tree{ - Name: t.Name, - ParseName: t.ParseName, - Root: t.Root.CopyList(), - text: t.text, - } -} - -// Parse returns a map from template name to parse.Tree, created by parsing the -// templates described in the argument string. The top-level template will be -// given the specified name. If an error is encountered, parsing stops and an -// empty map is returned with the error. -func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]any) (map[string]*Tree, error) { - treeSet := make(map[string]*Tree) - t := New(name) - t.text = text - _, err := t.Parse(text, leftDelim, rightDelim, treeSet, funcs...) - return treeSet, err -} - -// next returns the next token. -func (t *Tree) next() item { - if t.peekCount > 0 { - t.peekCount-- - } else { - t.token[0] = t.lex.nextItem() - } - return t.token[t.peekCount] -} - -// backup backs the input stream up one token. -func (t *Tree) backup() { - t.peekCount++ -} - -// backup2 backs the input stream up two tokens. -// The zeroth token is already there. -func (t *Tree) backup2(t1 item) { - t.token[1] = t1 - t.peekCount = 2 -} - -// backup3 backs the input stream up three tokens -// The zeroth token is already there. -func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back. - t.token[1] = t1 - t.token[2] = t2 - t.peekCount = 3 -} - -// peek returns but does not consume the next token. -func (t *Tree) peek() item { - if t.peekCount > 0 { - return t.token[t.peekCount-1] - } - t.peekCount = 1 - t.token[0] = t.lex.nextItem() - return t.token[0] -} - -// nextNonSpace returns the next non-space token. -func (t *Tree) nextNonSpace() (token item) { - for { - token = t.next() - if token.typ != itemSpace { - break - } - } - return token -} - -// peekNonSpace returns but does not consume the next non-space token. -func (t *Tree) peekNonSpace() item { - token := t.nextNonSpace() - t.backup() - return token -} - -// Parsing. - -// New allocates a new parse tree with the given name. -func New(name string, funcs ...map[string]any) *Tree { - return &Tree{ - Name: name, - funcs: funcs, - } -} - -// ErrorContext returns a textual representation of the location of the node in the input text. -// The receiver is only used when the node does not have a pointer to the tree inside, -// which can occur in old code. -func (t *Tree) ErrorContext(n Node) (location, context string) { - pos := int(n.Position()) - tree := n.tree() - if tree == nil { - tree = t - } - text := tree.text[:pos] - byteNum := strings.LastIndex(text, "\n") - if byteNum == -1 { - byteNum = pos // On first line. - } else { - byteNum++ // After the newline. - byteNum = pos - byteNum - } - lineNum := 1 + strings.Count(text, "\n") - context = n.String() - return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context -} - -// errorf formats the error and terminates processing. -func (t *Tree) errorf(format string, args ...any) { - t.Root = nil - format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format) - panic(fmt.Errorf(format, args...)) -} - -// error terminates processing. -func (t *Tree) error(err error) { - t.errorf("%s", err) -} - -// expect consumes the next token and guarantees it has the required type. -func (t *Tree) expect(expected itemType, context string) item { - token := t.nextNonSpace() - if token.typ != expected { - t.unexpected(token, context) - } - return token -} - -// expectOneOf consumes the next token and guarantees it has one of the required types. -func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item { - token := t.nextNonSpace() - if token.typ != expected1 && token.typ != expected2 { - t.unexpected(token, context) - } - return token -} - -// unexpected complains about the token and terminates processing. -func (t *Tree) unexpected(token item, context string) { - if token.typ == itemError { - extra := "" - if t.actionLine != 0 && t.actionLine != token.line { - extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine) - if strings.HasSuffix(token.val, " action") { - extra = extra[len(" in action"):] // avoid "action in action" - } - } - t.errorf("%s%s", token, extra) - } - t.errorf("unexpected %s in %s", token, context) -} - -// recover is the handler that turns panics into returns from the top level of Parse. -func (t *Tree) recover(errp *error) { - e := recover() - if e != nil { - if _, ok := e.(runtime.Error); ok { - panic(e) - } - if t != nil { - t.stopParse() - } - *errp = e.(error) - } -} - -// startParse initializes the parser, using the lexer. -func (t *Tree) startParse(funcs []map[string]any, lex *lexer, treeSet map[string]*Tree) { - t.Root = nil - t.lex = lex - t.vars = []string{"$"} - t.funcs = funcs - t.treeSet = treeSet - lex.options = lexOptions{ - emitComment: t.Mode&ParseComments != 0, - breakOK: !t.hasFunction("break"), - continueOK: !t.hasFunction("continue"), - } -} - -// stopParse terminates parsing. -func (t *Tree) stopParse() { - t.lex = nil - t.vars = nil - t.funcs = nil - t.treeSet = nil -} - -// Parse parses the template definition string to construct a representation of -// the template for execution. If either action delimiter string is empty, the -// default ("{{" or "}}") is used. Embedded template definitions are added to -// the treeSet map. -func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]any) (tree *Tree, err error) { - defer t.recover(&err) - t.ParseName = t.Name - lexer := lex(t.Name, text, leftDelim, rightDelim) - t.startParse(funcs, lexer, treeSet) - t.text = text - t.parse() - t.add() - t.stopParse() - return t, nil -} - -// add adds tree to t.treeSet. -func (t *Tree) add() { - tree := t.treeSet[t.Name] - if tree == nil || IsEmptyTree(tree.Root) { - t.treeSet[t.Name] = t - return - } - if !IsEmptyTree(t.Root) { - t.errorf("template: multiple definition of template %q", t.Name) - } -} - -// IsEmptyTree reports whether this tree (node) is empty of everything but space or comments. -func IsEmptyTree(n Node) bool { - switch n := n.(type) { - case nil: - return true - case *ActionNode: - case *CommentNode: - return true - case *IfNode: - case *ListNode: - for _, node := range n.Nodes { - if !IsEmptyTree(node) { - return false - } - } - return true - case *RangeNode: - case *TemplateNode: - case *TextNode: - return len(bytes.TrimSpace(n.Text)) == 0 - case *WithNode: - default: - panic("unknown node: " + n.String()) - } - return false -} - -// parse is the top-level parser for a template, essentially the same -// as itemList except it also parses {{define}} actions. -// It runs to EOF. -func (t *Tree) parse() { - t.Root = t.newList(t.peek().pos) - for t.peek().typ != itemEOF { - if t.peek().typ == itemLeftDelim { - delim := t.next() - if t.nextNonSpace().typ == itemDefine { - newT := New("definition") // name will be updated once we know it. - newT.text = t.text - newT.Mode = t.Mode - newT.ParseName = t.ParseName - newT.startParse(t.funcs, t.lex, t.treeSet) - newT.parseDefinition() - continue - } - t.backup2(delim) - } - switch n := t.textOrAction(); n.Type() { - case nodeEnd, nodeElse: - t.errorf("unexpected %s", n) - default: - t.Root.append(n) - } - } -} - -// parseDefinition parses a {{define}} ... {{end}} template definition and -// installs the definition in t.treeSet. The "define" keyword has already -// been scanned. -func (t *Tree) parseDefinition() { - const context = "define clause" - name := t.expectOneOf(itemString, itemRawString, context) - var err error - t.Name, err = strconv.Unquote(name.val) - if err != nil { - t.error(err) - } - t.expect(itemRightDelim, context) - var end Node - t.Root, end = t.itemList() - if end.Type() != nodeEnd { - t.errorf("unexpected %s in %s", end, context) - } - t.add() - t.stopParse() -} - -// itemList: -// -// textOrAction* -// -// Terminates at {{end}} or {{else}}, returned separately. -func (t *Tree) itemList() (list *ListNode, next Node) { - list = t.newList(t.peekNonSpace().pos) - for t.peekNonSpace().typ != itemEOF { - n := t.textOrAction() - switch n.Type() { - case nodeEnd, nodeElse: - return list, n - } - list.append(n) - } - t.errorf("unexpected EOF") - return -} - -// textOrAction: -// -// text | comment | action -func (t *Tree) textOrAction() Node { - switch token := t.nextNonSpace(); token.typ { - case itemText: - return t.newText(token.pos, token.val) - case itemLeftDelim: - t.actionLine = token.line - defer t.clearActionLine() - return t.action() - case itemComment: - return t.newComment(token.pos, token.val) - default: - t.unexpected(token, "input") - } - return nil -} - -func (t *Tree) clearActionLine() { - t.actionLine = 0 -} - -// Action: -// -// control -// command ("|" command)* -// -// Left delim is past. Now get actions. -// First word could be a keyword such as range. -func (t *Tree) action() (n Node) { - switch token := t.nextNonSpace(); token.typ { - case itemBlock: - return t.blockControl() - case itemBreak: - return t.breakControl(token.pos, token.line) - case itemContinue: - return t.continueControl(token.pos, token.line) - case itemElse: - return t.elseControl() - case itemEnd: - return t.endControl() - case itemIf: - return t.ifControl() - case itemRange: - return t.rangeControl() - case itemTemplate: - return t.templateControl() - case itemWith: - return t.withControl() - } - t.backup() - token := t.peek() - // Do not pop variables; they persist until "end". - return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim)) -} - -// Break: -// -// {{break}} -// -// Break keyword is past. -func (t *Tree) breakControl(pos Pos, line int) Node { - if token := t.nextNonSpace(); token.typ != itemRightDelim { - t.unexpected(token, "{{break}}") - } - if t.rangeDepth == 0 { - t.errorf("{{break}} outside {{range}}") - } - return t.newBreak(pos, line) -} - -// Continue: -// -// {{continue}} -// -// Continue keyword is past. -func (t *Tree) continueControl(pos Pos, line int) Node { - if token := t.nextNonSpace(); token.typ != itemRightDelim { - t.unexpected(token, "{{continue}}") - } - if t.rangeDepth == 0 { - t.errorf("{{continue}} outside {{range}}") - } - return t.newContinue(pos, line) -} - -// Pipeline: -// -// declarations? command ('|' command)* -func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) { - token := t.peekNonSpace() - pipe = t.newPipeline(token.pos, token.line, nil) - // Are there declarations or assignments? -decls: - if v := t.peekNonSpace(); v.typ == itemVariable { - t.next() - // Since space is a token, we need 3-token look-ahead here in the worst case: - // in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an - // argument variable rather than a declaration. So remember the token - // adjacent to the variable so we can push it back if necessary. - tokenAfterVariable := t.peek() - next := t.peekNonSpace() - switch { - case next.typ == itemAssign, next.typ == itemDeclare: - pipe.IsAssign = next.typ == itemAssign - t.nextNonSpace() - pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val)) - t.vars = append(t.vars, v.val) - case next.typ == itemChar && next.val == ",": - t.nextNonSpace() - pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val)) - t.vars = append(t.vars, v.val) - if context == "range" && len(pipe.Decl) < 2 { - switch t.peekNonSpace().typ { - case itemVariable, itemRightDelim, itemRightParen: - // second initialized variable in a range pipeline - goto decls - default: - t.errorf("range can only initialize variables") - } - } - t.errorf("too many declarations in %s", context) - case tokenAfterVariable.typ == itemSpace: - t.backup3(v, tokenAfterVariable) - default: - t.backup2(v) - } - } - for { - switch token := t.nextNonSpace(); token.typ { - case end: - // At this point, the pipeline is complete - t.checkPipeline(pipe, context) - return - case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, - itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: - t.backup() - pipe.append(t.command()) - default: - t.unexpected(token, context) - } - } -} - -func (t *Tree) checkPipeline(pipe *PipeNode, context string) { - // Reject empty pipelines - if len(pipe.Cmds) == 0 { - t.errorf("missing value for %s", context) - } - // Only the first command of a pipeline can start with a non executable operand - for i, c := range pipe.Cmds[1:] { - switch c.Args[0].Type() { - case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString: - // With A|B|C, pipeline stage 2 is B - t.errorf("non executable command in pipeline stage %d", i+2) - } - } -} - -func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { - defer t.popVars(len(t.vars)) - pipe = t.pipeline(context, itemRightDelim) - if context == "range" { - t.rangeDepth++ - } - var next Node - list, next = t.itemList() - if context == "range" { - t.rangeDepth-- - } - switch next.Type() { - case nodeEnd: //done - case nodeElse: - if allowElseIf { - // Special case for "else if". If the "else" is followed immediately by an "if", - // the elseControl will have left the "if" token pending. Treat - // {{if a}}_{{else if b}}_{{end}} - // as - // {{if a}}_{{else}}{{if b}}_{{end}}{{end}}. - // To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}} - // is assumed. This technique works even for long if-else-if chains. - // TODO: Should we allow else-if in with and range? - if t.peek().typ == itemIf { - t.next() // Consume the "if" token. - elseList = t.newList(next.Position()) - elseList.append(t.ifControl()) - // Do not consume the next item - only one {{end}} required. - break - } - } - elseList, next = t.itemList() - if next.Type() != nodeEnd { - t.errorf("expected end; found %s", next) - } - } - return pipe.Position(), pipe.Line, pipe, list, elseList -} - -// If: -// -// {{if pipeline}} itemList {{end}} -// {{if pipeline}} itemList {{else}} itemList {{end}} -// -// If keyword is past. -func (t *Tree) ifControl() Node { - return t.newIf(t.parseControl(true, "if")) -} - -// Range: -// -// {{range pipeline}} itemList {{end}} -// {{range pipeline}} itemList {{else}} itemList {{end}} -// -// Range keyword is past. -func (t *Tree) rangeControl() Node { - r := t.newRange(t.parseControl(false, "range")) - return r -} - -// With: -// -// {{with pipeline}} itemList {{end}} -// {{with pipeline}} itemList {{else}} itemList {{end}} -// -// If keyword is past. -func (t *Tree) withControl() Node { - return t.newWith(t.parseControl(false, "with")) -} - -// End: -// -// {{end}} -// -// End keyword is past. -func (t *Tree) endControl() Node { - return t.newEnd(t.expect(itemRightDelim, "end").pos) -} - -// Else: -// -// {{else}} -// -// Else keyword is past. -func (t *Tree) elseControl() Node { - // Special case for "else if". - peek := t.peekNonSpace() - if peek.typ == itemIf { - // We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ". - return t.newElse(peek.pos, peek.line) - } - token := t.expect(itemRightDelim, "else") - return t.newElse(token.pos, token.line) -} - -// Block: -// -// {{block stringValue pipeline}} -// -// Block keyword is past. -// The name must be something that can evaluate to a string. -// The pipeline is mandatory. -func (t *Tree) blockControl() Node { - const context = "block clause" - - token := t.nextNonSpace() - name := t.parseTemplateName(token, context) - pipe := t.pipeline(context, itemRightDelim) - - block := New(name) // name will be updated once we know it. - block.text = t.text - block.Mode = t.Mode - block.ParseName = t.ParseName - block.startParse(t.funcs, t.lex, t.treeSet) - var end Node - block.Root, end = block.itemList() - if end.Type() != nodeEnd { - t.errorf("unexpected %s in %s", end, context) - } - block.add() - block.stopParse() - - return t.newTemplate(token.pos, token.line, name, pipe) -} - -// Template: -// -// {{template stringValue pipeline}} -// -// Template keyword is past. The name must be something that can evaluate -// to a string. -func (t *Tree) templateControl() Node { - const context = "template clause" - token := t.nextNonSpace() - name := t.parseTemplateName(token, context) - var pipe *PipeNode - if t.nextNonSpace().typ != itemRightDelim { - t.backup() - // Do not pop variables; they persist until "end". - pipe = t.pipeline(context, itemRightDelim) - } - return t.newTemplate(token.pos, token.line, name, pipe) -} - -func (t *Tree) parseTemplateName(token item, context string) (name string) { - switch token.typ { - case itemString, itemRawString: - s, err := strconv.Unquote(token.val) - if err != nil { - t.error(err) - } - name = s - default: - t.unexpected(token, context) - } - return -} - -// command: -// -// operand (space operand)* -// -// space-separated arguments up to a pipeline character or right delimiter. -// we consume the pipe character but leave the right delim to terminate the action. -func (t *Tree) command() *CommandNode { - cmd := t.newCommand(t.peekNonSpace().pos) - for { - t.peekNonSpace() // skip leading spaces. - operand := t.operand() - if operand != nil { - cmd.append(operand) - } - switch token := t.next(); token.typ { - case itemSpace: - continue - case itemRightDelim, itemRightParen: - t.backup() - case itemPipe: - // nothing here; break loop below - default: - t.unexpected(token, "operand") - } - break - } - if len(cmd.Args) == 0 { - t.errorf("empty command") - } - return cmd -} - -// operand: -// -// term .Field* -// -// An operand is a space-separated component of a command, -// a term possibly followed by field accesses. -// A nil return means the next item is not an operand. -func (t *Tree) operand() Node { - node := t.term() - if node == nil { - return nil - } - if t.peek().typ == itemField { - chain := t.newChain(t.peek().pos, node) - for t.peek().typ == itemField { - chain.Add(t.next().val) - } - // Compatibility with original API: If the term is of type NodeField - // or NodeVariable, just put more fields on the original. - // Otherwise, keep the Chain node. - // Obvious parsing errors involving literal values are detected here. - // More complex error cases will have to be handled at execution time. - switch node.Type() { - case NodeField: - node = t.newField(chain.Position(), chain.String()) - case NodeVariable: - node = t.newVariable(chain.Position(), chain.String()) - case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot: - t.errorf("unexpected . after term %q", node.String()) - default: - node = chain - } - } - return node -} - -// term: -// -// literal (number, string, nil, boolean) -// function (identifier) -// . -// .Field -// $ -// '(' pipeline ')' -// -// A term is a simple "expression". -// A nil return means the next item is not a term. -func (t *Tree) term() Node { - switch token := t.nextNonSpace(); token.typ { - case itemIdentifier: - checkFunc := t.Mode&SkipFuncCheck == 0 - if checkFunc && !t.hasFunction(token.val) { - t.errorf("function %q not defined", token.val) - } - return NewIdentifier(token.val).SetTree(t).SetPos(token.pos) - case itemDot: - return t.newDot(token.pos) - case itemNil: - return t.newNil(token.pos) - case itemVariable: - return t.useVar(token.pos, token.val) - case itemField: - return t.newField(token.pos, token.val) - case itemBool: - return t.newBool(token.pos, token.val == "true") - case itemCharConstant, itemComplex, itemNumber: - number, err := t.newNumber(token.pos, token.val, token.typ) - if err != nil { - t.error(err) - } - return number - case itemLeftParen: - return t.pipeline("parenthesized pipeline", itemRightParen) - case itemString, itemRawString: - s, err := strconv.Unquote(token.val) - if err != nil { - t.error(err) - } - return t.newString(token.pos, token.val, s) - } - t.backup() - return nil -} - -// hasFunction reports if a function name exists in the Tree's maps. -func (t *Tree) hasFunction(name string) bool { - for _, funcMap := range t.funcs { - if funcMap == nil { - continue - } - if funcMap[name] != nil { - return true - } - } - return false -} - -// popVars trims the variable list to the specified length -func (t *Tree) popVars(n int) { - t.vars = t.vars[:n] -} - -// useVar returns a node for a variable reference. It errors if the -// variable is not defined. -func (t *Tree) useVar(pos Pos, name string) Node { - v := t.newVariable(pos, name) - for _, varName := range t.vars { - if varName == v.Ident[0] { - return v - } - } - t.errorf("undefined variable %q", v.Ident[0]) - return nil -} diff --git a/contrib/go/_std_1.22/src/text/template/template.go b/contrib/go/_std_1.22/src/text/template/template.go deleted file mode 100644 index 776be9cd075d..000000000000 --- a/contrib/go/_std_1.22/src/text/template/template.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "reflect" - "sync" - "text/template/parse" -) - -// common holds the information shared by related templates. -type common struct { - tmpl map[string]*Template // Map from name to defined templates. - muTmpl sync.RWMutex // protects tmpl - option option - // We use two maps, one for parsing and one for execution. - // This separation makes the API cleaner since it doesn't - // expose reflection to the client. - muFuncs sync.RWMutex // protects parseFuncs and execFuncs - parseFuncs FuncMap - execFuncs map[string]reflect.Value -} - -// Template is the representation of a parsed template. The *parse.Tree -// field is exported only for use by html/template and should be treated -// as unexported by all other clients. -type Template struct { - name string - *parse.Tree - *common - leftDelim string - rightDelim string -} - -// New allocates a new, undefined template with the given name. -func New(name string) *Template { - t := &Template{ - name: name, - } - t.init() - return t -} - -// Name returns the name of the template. -func (t *Template) Name() string { - return t.name -} - -// New allocates a new, undefined template associated with the given one and with the same -// delimiters. The association, which is transitive, allows one template to -// invoke another with a {{template}} action. -// -// Because associated templates share underlying data, template construction -// cannot be done safely in parallel. Once the templates are constructed, they -// can be executed in parallel. -func (t *Template) New(name string) *Template { - t.init() - nt := &Template{ - name: name, - common: t.common, - leftDelim: t.leftDelim, - rightDelim: t.rightDelim, - } - return nt -} - -// init guarantees that t has a valid common structure. -func (t *Template) init() { - if t.common == nil { - c := new(common) - c.tmpl = make(map[string]*Template) - c.parseFuncs = make(FuncMap) - c.execFuncs = make(map[string]reflect.Value) - t.common = c - } -} - -// Clone returns a duplicate of the template, including all associated -// templates. The actual representation is not copied, but the name space of -// associated templates is, so further calls to Parse in the copy will add -// templates to the copy but not to the original. Clone can be used to prepare -// common templates and use them with variant definitions for other templates -// by adding the variants after the clone is made. -func (t *Template) Clone() (*Template, error) { - nt := t.copy(nil) - nt.init() - if t.common == nil { - return nt, nil - } - t.muTmpl.RLock() - defer t.muTmpl.RUnlock() - for k, v := range t.tmpl { - if k == t.name { - nt.tmpl[t.name] = nt - continue - } - // The associated templates share nt's common structure. - tmpl := v.copy(nt.common) - nt.tmpl[k] = tmpl - } - t.muFuncs.RLock() - defer t.muFuncs.RUnlock() - for k, v := range t.parseFuncs { - nt.parseFuncs[k] = v - } - for k, v := range t.execFuncs { - nt.execFuncs[k] = v - } - return nt, nil -} - -// copy returns a shallow copy of t, with common set to the argument. -func (t *Template) copy(c *common) *Template { - return &Template{ - name: t.name, - Tree: t.Tree, - common: c, - leftDelim: t.leftDelim, - rightDelim: t.rightDelim, - } -} - -// AddParseTree associates the argument parse tree with the template t, giving -// it the specified name. If the template has not been defined, this tree becomes -// its definition. If it has been defined and already has that name, the existing -// definition is replaced; otherwise a new template is created, defined, and returned. -func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { - t.init() - t.muTmpl.Lock() - defer t.muTmpl.Unlock() - nt := t - if name != t.name { - nt = t.New(name) - } - // Even if nt == t, we need to install it in the common.tmpl map. - if t.associate(nt, tree) || nt.Tree == nil { - nt.Tree = tree - } - return nt, nil -} - -// Templates returns a slice of defined templates associated with t. -func (t *Template) Templates() []*Template { - if t.common == nil { - return nil - } - // Return a slice so we don't expose the map. - t.muTmpl.RLock() - defer t.muTmpl.RUnlock() - m := make([]*Template, 0, len(t.tmpl)) - for _, v := range t.tmpl { - m = append(m, v) - } - return m -} - -// Delims sets the action delimiters to the specified strings, to be used in -// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template -// definitions will inherit the settings. An empty delimiter stands for the -// corresponding default: {{ or }}. -// The return value is the template, so calls can be chained. -func (t *Template) Delims(left, right string) *Template { - t.init() - t.leftDelim = left - t.rightDelim = right - return t -} - -// Funcs adds the elements of the argument map to the template's function map. -// It must be called before the template is parsed. -// It panics if a value in the map is not a function with appropriate return -// type or if the name cannot be used syntactically as a function in a template. -// It is legal to overwrite elements of the map. The return value is the template, -// so calls can be chained. -func (t *Template) Funcs(funcMap FuncMap) *Template { - t.init() - t.muFuncs.Lock() - defer t.muFuncs.Unlock() - addValueFuncs(t.execFuncs, funcMap) - addFuncs(t.parseFuncs, funcMap) - return t -} - -// Lookup returns the template with the given name that is associated with t. -// It returns nil if there is no such template or the template has no definition. -func (t *Template) Lookup(name string) *Template { - if t.common == nil { - return nil - } - t.muTmpl.RLock() - defer t.muTmpl.RUnlock() - return t.tmpl[name] -} - -// Parse parses text as a template body for t. -// Named template definitions ({{define ...}} or {{block ...}} statements) in text -// define additional templates associated with t and are removed from the -// definition of t itself. -// -// Templates can be redefined in successive calls to Parse. -// A template definition with a body containing only white space and comments -// is considered empty and will not replace an existing template's body. -// This allows using Parse to add new named template definitions without -// overwriting the main template body. -func (t *Template) Parse(text string) (*Template, error) { - t.init() - t.muFuncs.RLock() - trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins()) - t.muFuncs.RUnlock() - if err != nil { - return nil, err - } - // Add the newly parsed trees, including the one for t, into our common structure. - for name, tree := range trees { - if _, err := t.AddParseTree(name, tree); err != nil { - return nil, err - } - } - return t, nil -} - -// associate installs the new template into the group of templates associated -// with t. The two are already known to share the common structure. -// The boolean return value reports whether to store this tree as t.Tree. -func (t *Template) associate(new *Template, tree *parse.Tree) bool { - if new.common != t.common { - panic("internal error: associate not common") - } - if old := t.tmpl[new.name]; old != nil && parse.IsEmptyTree(tree.Root) && old.Tree != nil { - // If a template by that name exists, - // don't replace it with an empty template. - return false - } - t.tmpl[new.name] = new - return true -} diff --git a/contrib/go/_std_1.22/src/time/format.go b/contrib/go/_std_1.22/src/time/format.go deleted file mode 100644 index 7fbeddb54065..000000000000 --- a/contrib/go/_std_1.22/src/time/format.go +++ /dev/null @@ -1,1686 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package time - -import "errors" - -// These are predefined layouts for use in Time.Format and time.Parse. -// The reference time used in these layouts is the specific time stamp: -// -// 01/02 03:04:05PM '06 -0700 -// -// (January 2, 15:04:05, 2006, in time zone seven hours west of GMT). -// That value is recorded as the constant named Layout, listed below. As a Unix -// time, this is 1136239445. Since MST is GMT-0700, the reference would be -// printed by the Unix date command as: -// -// Mon Jan 2 15:04:05 MST 2006 -// -// It is a regrettable historic error that the date uses the American convention -// of putting the numerical month before the day. -// -// The example for Time.Format demonstrates the working of the layout string -// in detail and is a good reference. -// -// Note that the RFC822, RFC850, and RFC1123 formats should be applied -// only to local times. Applying them to UTC times will use "UTC" as the -// time zone abbreviation, while strictly speaking those RFCs require the -// use of "GMT" in that case. -// In general RFC1123Z should be used instead of RFC1123 for servers -// that insist on that format, and RFC3339 should be preferred for new protocols. -// RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting; -// when used with time.Parse they do not accept all the time formats -// permitted by the RFCs and they do accept time formats not formally defined. -// The RFC3339Nano format removes trailing zeros from the seconds field -// and thus may not sort correctly once formatted. -// -// Most programs can use one of the defined constants as the layout passed to -// Format or Parse. The rest of this comment can be ignored unless you are -// creating a custom layout string. -// -// To define your own format, write down what the reference time would look like -// formatted your way; see the values of constants like ANSIC, StampMicro or -// Kitchen for examples. The model is to demonstrate what the reference time -// looks like so that the Format and Parse methods can apply the same -// transformation to a general time value. -// -// Here is a summary of the components of a layout string. Each element shows by -// example the formatting of an element of the reference time. Only these values -// are recognized. Text in the layout string that is not recognized as part of -// the reference time is echoed verbatim during Format and expected to appear -// verbatim in the input to Parse. -// -// Year: "2006" "06" -// Month: "Jan" "January" "01" "1" -// Day of the week: "Mon" "Monday" -// Day of the month: "2" "_2" "02" -// Day of the year: "__2" "002" -// Hour: "15" "3" "03" (PM or AM) -// Minute: "4" "04" -// Second: "5" "05" -// AM/PM mark: "PM" -// -// Numeric time zone offsets format as follows: -// -// "-0700" ±hhmm -// "-07:00" ±hh:mm -// "-07" ±hh -// "-070000" ±hhmmss -// "-07:00:00" ±hh:mm:ss -// -// Replacing the sign in the format with a Z triggers -// the ISO 8601 behavior of printing Z instead of an -// offset for the UTC zone. Thus: -// -// "Z0700" Z or ±hhmm -// "Z07:00" Z or ±hh:mm -// "Z07" Z or ±hh -// "Z070000" Z or ±hhmmss -// "Z07:00:00" Z or ±hh:mm:ss -// -// Within the format string, the underscores in "_2" and "__2" represent spaces -// that may be replaced by digits if the following number has multiple digits, -// for compatibility with fixed-width Unix time formats. A leading zero represents -// a zero-padded value. -// -// The formats __2 and 002 are space-padded and zero-padded -// three-character day of year; there is no unpadded day of year format. -// -// A comma or decimal point followed by one or more zeros represents -// a fractional second, printed to the given number of decimal places. -// A comma or decimal point followed by one or more nines represents -// a fractional second, printed to the given number of decimal places, with -// trailing zeros removed. -// For example "15:04:05,000" or "15:04:05.000" formats or parses with -// millisecond precision. -// -// Some valid layouts are invalid time values for time.Parse, due to formats -// such as _ for space padding and Z for zone information. -const ( - Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order. - ANSIC = "Mon Jan _2 15:04:05 2006" - UnixDate = "Mon Jan _2 15:04:05 MST 2006" - RubyDate = "Mon Jan 02 15:04:05 -0700 2006" - RFC822 = "02 Jan 06 15:04 MST" - RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone - RFC850 = "Monday, 02-Jan-06 15:04:05 MST" - RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" - RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone - RFC3339 = "2006-01-02T15:04:05Z07:00" - RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" - Kitchen = "3:04PM" - // Handy time stamps. - Stamp = "Jan _2 15:04:05" - StampMilli = "Jan _2 15:04:05.000" - StampMicro = "Jan _2 15:04:05.000000" - StampNano = "Jan _2 15:04:05.000000000" - DateTime = "2006-01-02 15:04:05" - DateOnly = "2006-01-02" - TimeOnly = "15:04:05" -) - -const ( - _ = iota - stdLongMonth = iota + stdNeedDate // "January" - stdMonth // "Jan" - stdNumMonth // "1" - stdZeroMonth // "01" - stdLongWeekDay // "Monday" - stdWeekDay // "Mon" - stdDay // "2" - stdUnderDay // "_2" - stdZeroDay // "02" - stdUnderYearDay // "__2" - stdZeroYearDay // "002" - stdHour = iota + stdNeedClock // "15" - stdHour12 // "3" - stdZeroHour12 // "03" - stdMinute // "4" - stdZeroMinute // "04" - stdSecond // "5" - stdZeroSecond // "05" - stdLongYear = iota + stdNeedDate // "2006" - stdYear // "06" - stdPM = iota + stdNeedClock // "PM" - stdpm // "pm" - stdTZ = iota // "MST" - stdISO8601TZ // "Z0700" // prints Z for UTC - stdISO8601SecondsTZ // "Z070000" - stdISO8601ShortTZ // "Z07" - stdISO8601ColonTZ // "Z07:00" // prints Z for UTC - stdISO8601ColonSecondsTZ // "Z07:00:00" - stdNumTZ // "-0700" // always numeric - stdNumSecondsTz // "-070000" - stdNumShortTZ // "-07" // always numeric - stdNumColonTZ // "-07:00" // always numeric - stdNumColonSecondsTZ // "-07:00:00" - stdFracSecond0 // ".0", ".00", ... , trailing zeros included - stdFracSecond9 // ".9", ".99", ..., trailing zeros omitted - - stdNeedDate = 1 << 8 // need month, day, year - stdNeedClock = 2 << 8 // need hour, minute, second - stdArgShift = 16 // extra argument in high bits, above low stdArgShift - stdSeparatorShift = 28 // extra argument in high 4 bits for fractional second separators - stdMask = 1<= i+3 && layout[i:i+3] == "Jan" { - if len(layout) >= i+7 && layout[i:i+7] == "January" { - return layout[0:i], stdLongMonth, layout[i+7:] - } - if !startsWithLowerCase(layout[i+3:]) { - return layout[0:i], stdMonth, layout[i+3:] - } - } - - case 'M': // Monday, Mon, MST - if len(layout) >= i+3 { - if layout[i:i+3] == "Mon" { - if len(layout) >= i+6 && layout[i:i+6] == "Monday" { - return layout[0:i], stdLongWeekDay, layout[i+6:] - } - if !startsWithLowerCase(layout[i+3:]) { - return layout[0:i], stdWeekDay, layout[i+3:] - } - } - if layout[i:i+3] == "MST" { - return layout[0:i], stdTZ, layout[i+3:] - } - } - - case '0': // 01, 02, 03, 04, 05, 06, 002 - if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' { - return layout[0:i], std0x[layout[i+1]-'1'], layout[i+2:] - } - if len(layout) >= i+3 && layout[i+1] == '0' && layout[i+2] == '2' { - return layout[0:i], stdZeroYearDay, layout[i+3:] - } - - case '1': // 15, 1 - if len(layout) >= i+2 && layout[i+1] == '5' { - return layout[0:i], stdHour, layout[i+2:] - } - return layout[0:i], stdNumMonth, layout[i+1:] - - case '2': // 2006, 2 - if len(layout) >= i+4 && layout[i:i+4] == "2006" { - return layout[0:i], stdLongYear, layout[i+4:] - } - return layout[0:i], stdDay, layout[i+1:] - - case '_': // _2, _2006, __2 - if len(layout) >= i+2 && layout[i+1] == '2' { - //_2006 is really a literal _, followed by stdLongYear - if len(layout) >= i+5 && layout[i+1:i+5] == "2006" { - return layout[0 : i+1], stdLongYear, layout[i+5:] - } - return layout[0:i], stdUnderDay, layout[i+2:] - } - if len(layout) >= i+3 && layout[i+1] == '_' && layout[i+2] == '2' { - return layout[0:i], stdUnderYearDay, layout[i+3:] - } - - case '3': - return layout[0:i], stdHour12, layout[i+1:] - - case '4': - return layout[0:i], stdMinute, layout[i+1:] - - case '5': - return layout[0:i], stdSecond, layout[i+1:] - - case 'P': // PM - if len(layout) >= i+2 && layout[i+1] == 'M' { - return layout[0:i], stdPM, layout[i+2:] - } - - case 'p': // pm - if len(layout) >= i+2 && layout[i+1] == 'm' { - return layout[0:i], stdpm, layout[i+2:] - } - - case '-': // -070000, -07:00:00, -0700, -07:00, -07 - if len(layout) >= i+7 && layout[i:i+7] == "-070000" { - return layout[0:i], stdNumSecondsTz, layout[i+7:] - } - if len(layout) >= i+9 && layout[i:i+9] == "-07:00:00" { - return layout[0:i], stdNumColonSecondsTZ, layout[i+9:] - } - if len(layout) >= i+5 && layout[i:i+5] == "-0700" { - return layout[0:i], stdNumTZ, layout[i+5:] - } - if len(layout) >= i+6 && layout[i:i+6] == "-07:00" { - return layout[0:i], stdNumColonTZ, layout[i+6:] - } - if len(layout) >= i+3 && layout[i:i+3] == "-07" { - return layout[0:i], stdNumShortTZ, layout[i+3:] - } - - case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00, - if len(layout) >= i+7 && layout[i:i+7] == "Z070000" { - return layout[0:i], stdISO8601SecondsTZ, layout[i+7:] - } - if len(layout) >= i+9 && layout[i:i+9] == "Z07:00:00" { - return layout[0:i], stdISO8601ColonSecondsTZ, layout[i+9:] - } - if len(layout) >= i+5 && layout[i:i+5] == "Z0700" { - return layout[0:i], stdISO8601TZ, layout[i+5:] - } - if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" { - return layout[0:i], stdISO8601ColonTZ, layout[i+6:] - } - if len(layout) >= i+3 && layout[i:i+3] == "Z07" { - return layout[0:i], stdISO8601ShortTZ, layout[i+3:] - } - - case '.', ',': // ,000, or .000, or ,999, or .999 - repeated digits for fractional seconds. - if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') { - ch := layout[i+1] - j := i + 1 - for j < len(layout) && layout[j] == ch { - j++ - } - // String of digits must end here - only fractional second is all digits. - if !isDigit(layout, j) { - code := stdFracSecond0 - if layout[i+1] == '9' { - code = stdFracSecond9 - } - std := stdFracSecond(code, j-(i+1), c) - return layout[0:i], std, layout[j:] - } - } - } - } - return layout, 0, "" -} - -var longDayNames = []string{ - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", -} - -var shortDayNames = []string{ - "Sun", - "Mon", - "Tue", - "Wed", - "Thu", - "Fri", - "Sat", -} - -var shortMonthNames = []string{ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", -} - -var longMonthNames = []string{ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", -} - -// match reports whether s1 and s2 match ignoring case. -// It is assumed s1 and s2 are the same length. -func match(s1, s2 string) bool { - for i := 0; i < len(s1); i++ { - c1 := s1[i] - c2 := s2[i] - if c1 != c2 { - // Switch to lower-case; 'a'-'A' is known to be a single bit. - c1 |= 'a' - 'A' - c2 |= 'a' - 'A' - if c1 != c2 || c1 < 'a' || c1 > 'z' { - return false - } - } - } - return true -} - -func lookup(tab []string, val string) (int, string, error) { - for i, v := range tab { - if len(val) >= len(v) && match(val[0:len(v)], v) { - return i, val[len(v):], nil - } - } - return -1, val, errBad -} - -// appendInt appends the decimal form of x to b and returns the result. -// If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's. -// Duplicates functionality in strconv, but avoids dependency. -func appendInt(b []byte, x int, width int) []byte { - u := uint(x) - if x < 0 { - b = append(b, '-') - u = uint(-x) - } - - // 2-digit and 4-digit fields are the most common in time formats. - utod := func(u uint) byte { return '0' + byte(u) } - switch { - case width == 2 && u < 1e2: - return append(b, utod(u/1e1), utod(u%1e1)) - case width == 4 && u < 1e4: - return append(b, utod(u/1e3), utod(u/1e2%1e1), utod(u/1e1%1e1), utod(u%1e1)) - } - - // Compute the number of decimal digits. - var n int - if u == 0 { - n = 1 - } - for u2 := u; u2 > 0; u2 /= 10 { - n++ - } - - // Add 0-padding. - for pad := width - n; pad > 0; pad-- { - b = append(b, '0') - } - - // Ensure capacity. - if len(b)+n <= cap(b) { - b = b[:len(b)+n] - } else { - b = append(b, make([]byte, n)...) - } - - // Assemble decimal in reverse order. - i := len(b) - 1 - for u >= 10 && i > 0 { - q := u / 10 - b[i] = utod(u - q*10) - u = q - i-- - } - b[i] = utod(u) - return b -} - -// Never printed, just needs to be non-nil for return by atoi. -var errAtoi = errors.New("time: invalid number") - -// Duplicates functionality in strconv, but avoids dependency. -func atoi[bytes []byte | string](s bytes) (x int, err error) { - neg := false - if len(s) > 0 && (s[0] == '-' || s[0] == '+') { - neg = s[0] == '-' - s = s[1:] - } - q, rem, err := leadingInt(s) - x = int(q) - if err != nil || len(rem) > 0 { - return 0, errAtoi - } - if neg { - x = -x - } - return x, nil -} - -// The "std" value passed to appendNano contains two packed fields: the number of -// digits after the decimal and the separator character (period or comma). -// These functions pack and unpack that variable. -func stdFracSecond(code, n, c int) int { - // Use 0xfff to make the failure case even more absurd. - if c == '.' { - return code | ((n & 0xfff) << stdArgShift) - } - return code | ((n & 0xfff) << stdArgShift) | 1<> stdArgShift) & 0xfff -} - -func separator(std int) byte { - if (std >> stdSeparatorShift) == 0 { - return '.' - } - return ',' -} - -// appendNano appends a fractional second, as nanoseconds, to b -// and returns the result. The nanosec must be within [0, 999999999]. -func appendNano(b []byte, nanosec int, std int) []byte { - trim := std&stdMask == stdFracSecond9 - n := digitsLen(std) - if trim && (n == 0 || nanosec == 0) { - return b - } - dot := separator(std) - b = append(b, dot) - b = appendInt(b, nanosec, 9) - if n < 9 { - b = b[:len(b)-9+n] - } - if trim { - for len(b) > 0 && b[len(b)-1] == '0' { - b = b[:len(b)-1] - } - if len(b) > 0 && b[len(b)-1] == dot { - b = b[:len(b)-1] - } - } - return b -} - -// String returns the time formatted using the format string -// -// "2006-01-02 15:04:05.999999999 -0700 MST" -// -// If the time has a monotonic clock reading, the returned string -// includes a final field "m=±", where value is the monotonic -// clock reading formatted as a decimal number of seconds. -// -// The returned string is meant for debugging; for a stable serialized -// representation, use t.MarshalText, t.MarshalBinary, or t.Format -// with an explicit format string. -func (t Time) String() string { - s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST") - - // Format monotonic clock reading as m=±ddd.nnnnnnnnn. - if t.wall&hasMonotonic != 0 { - m2 := uint64(t.ext) - sign := byte('+') - if t.ext < 0 { - sign = '-' - m2 = -m2 - } - m1, m2 := m2/1e9, m2%1e9 - m0, m1 := m1/1e9, m1%1e9 - buf := make([]byte, 0, 24) - buf = append(buf, " m="...) - buf = append(buf, sign) - wid := 0 - if m0 != 0 { - buf = appendInt(buf, int(m0), 0) - wid = 9 - } - buf = appendInt(buf, int(m1), wid) - buf = append(buf, '.') - buf = appendInt(buf, int(m2), 9) - s += string(buf) - } - return s -} - -// GoString implements fmt.GoStringer and formats t to be printed in Go source -// code. -func (t Time) GoString() string { - abs := t.abs() - year, month, day, _ := absDate(abs, true) - hour, minute, second := absClock(abs) - - buf := make([]byte, 0, len("time.Date(9999, time.September, 31, 23, 59, 59, 999999999, time.Local)")) - buf = append(buf, "time.Date("...) - buf = appendInt(buf, year, 0) - if January <= month && month <= December { - buf = append(buf, ", time."...) - buf = append(buf, longMonthNames[month-1]...) - } else { - // It's difficult to construct a time.Time with a date outside the - // standard range but we might as well try to handle the case. - buf = appendInt(buf, int(month), 0) - } - buf = append(buf, ", "...) - buf = appendInt(buf, day, 0) - buf = append(buf, ", "...) - buf = appendInt(buf, hour, 0) - buf = append(buf, ", "...) - buf = appendInt(buf, minute, 0) - buf = append(buf, ", "...) - buf = appendInt(buf, second, 0) - buf = append(buf, ", "...) - buf = appendInt(buf, t.Nanosecond(), 0) - buf = append(buf, ", "...) - switch loc := t.Location(); loc { - case UTC, nil: - buf = append(buf, "time.UTC"...) - case Local: - buf = append(buf, "time.Local"...) - default: - // there are several options for how we could display this, none of - // which are great: - // - // - use Location(loc.name), which is not technically valid syntax - // - use LoadLocation(loc.name), which will cause a syntax error when - // embedded and also would require us to escape the string without - // importing fmt or strconv - // - try to use FixedZone, which would also require escaping the name - // and would represent e.g. "America/Los_Angeles" daylight saving time - // shifts inaccurately - // - use the pointer format, which is no worse than you'd get with the - // old fmt.Sprintf("%#v", t) format. - // - // Of these, Location(loc.name) is the least disruptive. This is an edge - // case we hope not to hit too often. - buf = append(buf, `time.Location(`...) - buf = append(buf, quote(loc.name)...) - buf = append(buf, ')') - } - buf = append(buf, ')') - return string(buf) -} - -// Format returns a textual representation of the time value formatted according -// to the layout defined by the argument. See the documentation for the -// constant called Layout to see how to represent the layout format. -// -// The executable example for Time.Format demonstrates the working -// of the layout string in detail and is a good reference. -func (t Time) Format(layout string) string { - const bufSize = 64 - var b []byte - max := len(layout) + 10 - if max < bufSize { - var buf [bufSize]byte - b = buf[:0] - } else { - b = make([]byte, 0, max) - } - b = t.AppendFormat(b, layout) - return string(b) -} - -// AppendFormat is like Format but appends the textual -// representation to b and returns the extended buffer. -func (t Time) AppendFormat(b []byte, layout string) []byte { - // Optimize for RFC3339 as it accounts for over half of all representations. - switch layout { - case RFC3339: - return t.appendFormatRFC3339(b, false) - case RFC3339Nano: - return t.appendFormatRFC3339(b, true) - default: - return t.appendFormat(b, layout) - } -} - -func (t Time) appendFormat(b []byte, layout string) []byte { - var ( - name, offset, abs = t.locabs() - - year int = -1 - month Month - day int - yday int - hour int = -1 - min int - sec int - ) - - // Each iteration generates one std value. - for layout != "" { - prefix, std, suffix := nextStdChunk(layout) - if prefix != "" { - b = append(b, prefix...) - } - if std == 0 { - break - } - layout = suffix - - // Compute year, month, day if needed. - if year < 0 && std&stdNeedDate != 0 { - year, month, day, yday = absDate(abs, true) - yday++ - } - - // Compute hour, minute, second if needed. - if hour < 0 && std&stdNeedClock != 0 { - hour, min, sec = absClock(abs) - } - - switch std & stdMask { - case stdYear: - y := year - if y < 0 { - y = -y - } - b = appendInt(b, y%100, 2) - case stdLongYear: - b = appendInt(b, year, 4) - case stdMonth: - b = append(b, month.String()[:3]...) - case stdLongMonth: - m := month.String() - b = append(b, m...) - case stdNumMonth: - b = appendInt(b, int(month), 0) - case stdZeroMonth: - b = appendInt(b, int(month), 2) - case stdWeekDay: - b = append(b, absWeekday(abs).String()[:3]...) - case stdLongWeekDay: - s := absWeekday(abs).String() - b = append(b, s...) - case stdDay: - b = appendInt(b, day, 0) - case stdUnderDay: - if day < 10 { - b = append(b, ' ') - } - b = appendInt(b, day, 0) - case stdZeroDay: - b = appendInt(b, day, 2) - case stdUnderYearDay: - if yday < 100 { - b = append(b, ' ') - if yday < 10 { - b = append(b, ' ') - } - } - b = appendInt(b, yday, 0) - case stdZeroYearDay: - b = appendInt(b, yday, 3) - case stdHour: - b = appendInt(b, hour, 2) - case stdHour12: - // Noon is 12PM, midnight is 12AM. - hr := hour % 12 - if hr == 0 { - hr = 12 - } - b = appendInt(b, hr, 0) - case stdZeroHour12: - // Noon is 12PM, midnight is 12AM. - hr := hour % 12 - if hr == 0 { - hr = 12 - } - b = appendInt(b, hr, 2) - case stdMinute: - b = appendInt(b, min, 0) - case stdZeroMinute: - b = appendInt(b, min, 2) - case stdSecond: - b = appendInt(b, sec, 0) - case stdZeroSecond: - b = appendInt(b, sec, 2) - case stdPM: - if hour >= 12 { - b = append(b, "PM"...) - } else { - b = append(b, "AM"...) - } - case stdpm: - if hour >= 12 { - b = append(b, "pm"...) - } else { - b = append(b, "am"...) - } - case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ: - // Ugly special case. We cheat and take the "Z" variants - // to mean "the time zone as formatted for ISO 8601". - if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) { - b = append(b, 'Z') - break - } - zone := offset / 60 // convert to minutes - absoffset := offset - if zone < 0 { - b = append(b, '-') - zone = -zone - absoffset = -absoffset - } else { - b = append(b, '+') - } - b = appendInt(b, zone/60, 2) - if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { - b = append(b, ':') - } - if std != stdNumShortTZ && std != stdISO8601ShortTZ { - b = appendInt(b, zone%60, 2) - } - - // append seconds if appropriate - if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { - if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { - b = append(b, ':') - } - b = appendInt(b, absoffset%60, 2) - } - - case stdTZ: - if name != "" { - b = append(b, name...) - break - } - // No time zone known for this time, but we must print one. - // Use the -0700 format. - zone := offset / 60 // convert to minutes - if zone < 0 { - b = append(b, '-') - zone = -zone - } else { - b = append(b, '+') - } - b = appendInt(b, zone/60, 2) - b = appendInt(b, zone%60, 2) - case stdFracSecond0, stdFracSecond9: - b = appendNano(b, t.Nanosecond(), std) - } - } - return b -} - -var errBad = errors.New("bad value for field") // placeholder not passed to user - -// ParseError describes a problem parsing a time string. -type ParseError struct { - Layout string - Value string - LayoutElem string - ValueElem string - Message string -} - -// newParseError creates a new ParseError. -// The provided value and valueElem are cloned to avoid escaping their values. -func newParseError(layout, value, layoutElem, valueElem, message string) *ParseError { - valueCopy := cloneString(value) - valueElemCopy := cloneString(valueElem) - return &ParseError{layout, valueCopy, layoutElem, valueElemCopy, message} -} - -// cloneString returns a string copy of s. -// Do not use strings.Clone to avoid dependency on strings package. -func cloneString(s string) string { - return string([]byte(s)) -} - -// These are borrowed from unicode/utf8 and strconv and replicate behavior in -// that package, since we can't take a dependency on either. -const ( - lowerhex = "0123456789abcdef" - runeSelf = 0x80 - runeError = '\uFFFD' -) - -func quote(s string) string { - buf := make([]byte, 1, len(s)+2) // slice will be at least len(s) + quotes - buf[0] = '"' - for i, c := range s { - if c >= runeSelf || c < ' ' { - // This means you are asking us to parse a time.Duration or - // time.Location with unprintable or non-ASCII characters in it. - // We don't expect to hit this case very often. We could try to - // reproduce strconv.Quote's behavior with full fidelity but - // given how rarely we expect to hit these edge cases, speed and - // conciseness are better. - var width int - if c == runeError { - width = 1 - if i+2 < len(s) && s[i:i+3] == string(runeError) { - width = 3 - } - } else { - width = len(string(c)) - } - for j := 0; j < width; j++ { - buf = append(buf, `\x`...) - buf = append(buf, lowerhex[s[i+j]>>4]) - buf = append(buf, lowerhex[s[i+j]&0xF]) - } - } else { - if c == '"' || c == '\\' { - buf = append(buf, '\\') - } - buf = append(buf, string(c)...) - } - } - buf = append(buf, '"') - return string(buf) -} - -// Error returns the string representation of a ParseError. -func (e *ParseError) Error() string { - if e.Message == "" { - return "parsing time " + - quote(e.Value) + " as " + - quote(e.Layout) + ": cannot parse " + - quote(e.ValueElem) + " as " + - quote(e.LayoutElem) - } - return "parsing time " + - quote(e.Value) + e.Message -} - -// isDigit reports whether s[i] is in range and is a decimal digit. -func isDigit[bytes []byte | string](s bytes, i int) bool { - if len(s) <= i { - return false - } - c := s[i] - return '0' <= c && c <= '9' -} - -// getnum parses s[0:1] or s[0:2] (fixed forces s[0:2]) -// as a decimal integer and returns the integer and the -// remainder of the string. -func getnum(s string, fixed bool) (int, string, error) { - if !isDigit(s, 0) { - return 0, s, errBad - } - if !isDigit(s, 1) { - if fixed { - return 0, s, errBad - } - return int(s[0] - '0'), s[1:], nil - } - return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil -} - -// getnum3 parses s[0:1], s[0:2], or s[0:3] (fixed forces s[0:3]) -// as a decimal integer and returns the integer and the remainder -// of the string. -func getnum3(s string, fixed bool) (int, string, error) { - var n, i int - for i = 0; i < 3 && isDigit(s, i); i++ { - n = n*10 + int(s[i]-'0') - } - if i == 0 || fixed && i != 3 { - return 0, s, errBad - } - return n, s[i:], nil -} - -func cutspace(s string) string { - for len(s) > 0 && s[0] == ' ' { - s = s[1:] - } - return s -} - -// skip removes the given prefix from value, -// treating runs of space characters as equivalent. -func skip(value, prefix string) (string, error) { - for len(prefix) > 0 { - if prefix[0] == ' ' { - if len(value) > 0 && value[0] != ' ' { - return value, errBad - } - prefix = cutspace(prefix) - value = cutspace(value) - continue - } - if len(value) == 0 || value[0] != prefix[0] { - return value, errBad - } - prefix = prefix[1:] - value = value[1:] - } - return value, nil -} - -// Parse parses a formatted string and returns the time value it represents. -// See the documentation for the constant called Layout to see how to -// represent the format. The second argument must be parseable using -// the format string (layout) provided as the first argument. -// -// The example for Time.Format demonstrates the working of the layout string -// in detail and is a good reference. -// -// When parsing (only), the input may contain a fractional second -// field immediately after the seconds field, even if the layout does not -// signify its presence. In that case either a comma or a decimal point -// followed by a maximal series of digits is parsed as a fractional second. -// Fractional seconds are truncated to nanosecond precision. -// -// Elements omitted from the layout are assumed to be zero or, when -// zero is impossible, one, so parsing "3:04pm" returns the time -// corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is -// 0, this time is before the zero Time). -// Years must be in the range 0000..9999. The day of the week is checked -// for syntax but it is otherwise ignored. -// -// For layouts specifying the two-digit year 06, a value NN >= 69 will be treated -// as 19NN and a value NN < 69 will be treated as 20NN. -// -// The remainder of this comment describes the handling of time zones. -// -// In the absence of a time zone indicator, Parse returns a time in UTC. -// -// When parsing a time with a zone offset like -0700, if the offset corresponds -// to a time zone used by the current location (Local), then Parse uses that -// location and zone in the returned time. Otherwise it records the time as -// being in a fabricated location with time fixed at the given zone offset. -// -// When parsing a time with a zone abbreviation like MST, if the zone abbreviation -// has a defined offset in the current location, then that offset is used. -// The zone abbreviation "UTC" is recognized as UTC regardless of location. -// If the zone abbreviation is unknown, Parse records the time as being -// in a fabricated location with the given zone abbreviation and a zero offset. -// This choice means that such a time can be parsed and reformatted with the -// same layout losslessly, but the exact instant used in the representation will -// differ by the actual zone offset. To avoid such problems, prefer time layouts -// that use a numeric zone offset, or use ParseInLocation. -func Parse(layout, value string) (Time, error) { - // Optimize for RFC3339 as it accounts for over half of all representations. - if layout == RFC3339 || layout == RFC3339Nano { - if t, ok := parseRFC3339(value, Local); ok { - return t, nil - } - } - return parse(layout, value, UTC, Local) -} - -// ParseInLocation is like Parse but differs in two important ways. -// First, in the absence of time zone information, Parse interprets a time as UTC; -// ParseInLocation interprets the time as in the given location. -// Second, when given a zone offset or abbreviation, Parse tries to match it -// against the Local location; ParseInLocation uses the given location. -func ParseInLocation(layout, value string, loc *Location) (Time, error) { - // Optimize for RFC3339 as it accounts for over half of all representations. - if layout == RFC3339 || layout == RFC3339Nano { - if t, ok := parseRFC3339(value, loc); ok { - return t, nil - } - } - return parse(layout, value, loc, loc) -} - -func parse(layout, value string, defaultLocation, local *Location) (Time, error) { - alayout, avalue := layout, value - rangeErrString := "" // set if a value is out of range - amSet := false // do we need to subtract 12 from the hour for midnight? - pmSet := false // do we need to add 12 to the hour? - - // Time being constructed. - var ( - year int - month int = -1 - day int = -1 - yday int = -1 - hour int - min int - sec int - nsec int - z *Location - zoneOffset int = -1 - zoneName string - ) - - // Each iteration processes one std value. - for { - var err error - prefix, std, suffix := nextStdChunk(layout) - stdstr := layout[len(prefix) : len(layout)-len(suffix)] - value, err = skip(value, prefix) - if err != nil { - return Time{}, newParseError(alayout, avalue, prefix, value, "") - } - if std == 0 { - if len(value) != 0 { - return Time{}, newParseError(alayout, avalue, "", value, ": extra text: "+quote(value)) - } - break - } - layout = suffix - var p string - hold := value - switch std & stdMask { - case stdYear: - if len(value) < 2 { - err = errBad - break - } - p, value = value[0:2], value[2:] - year, err = atoi(p) - if err != nil { - break - } - if year >= 69 { // Unix time starts Dec 31 1969 in some time zones - year += 1900 - } else { - year += 2000 - } - case stdLongYear: - if len(value) < 4 || !isDigit(value, 0) { - err = errBad - break - } - p, value = value[0:4], value[4:] - year, err = atoi(p) - case stdMonth: - month, value, err = lookup(shortMonthNames, value) - month++ - case stdLongMonth: - month, value, err = lookup(longMonthNames, value) - month++ - case stdNumMonth, stdZeroMonth: - month, value, err = getnum(value, std == stdZeroMonth) - if err == nil && (month <= 0 || 12 < month) { - rangeErrString = "month" - } - case stdWeekDay: - // Ignore weekday except for error checking. - _, value, err = lookup(shortDayNames, value) - case stdLongWeekDay: - _, value, err = lookup(longDayNames, value) - case stdDay, stdUnderDay, stdZeroDay: - if std == stdUnderDay && len(value) > 0 && value[0] == ' ' { - value = value[1:] - } - day, value, err = getnum(value, std == stdZeroDay) - // Note that we allow any one- or two-digit day here. - // The month, day, year combination is validated after we've completed parsing. - case stdUnderYearDay, stdZeroYearDay: - for i := 0; i < 2; i++ { - if std == stdUnderYearDay && len(value) > 0 && value[0] == ' ' { - value = value[1:] - } - } - yday, value, err = getnum3(value, std == stdZeroYearDay) - // Note that we allow any one-, two-, or three-digit year-day here. - // The year-day, year combination is validated after we've completed parsing. - case stdHour: - hour, value, err = getnum(value, false) - if hour < 0 || 24 <= hour { - rangeErrString = "hour" - } - case stdHour12, stdZeroHour12: - hour, value, err = getnum(value, std == stdZeroHour12) - if hour < 0 || 12 < hour { - rangeErrString = "hour" - } - case stdMinute, stdZeroMinute: - min, value, err = getnum(value, std == stdZeroMinute) - if min < 0 || 60 <= min { - rangeErrString = "minute" - } - case stdSecond, stdZeroSecond: - sec, value, err = getnum(value, std == stdZeroSecond) - if err != nil { - break - } - if sec < 0 || 60 <= sec { - rangeErrString = "second" - break - } - // Special case: do we have a fractional second but no - // fractional second in the format? - if len(value) >= 2 && commaOrPeriod(value[0]) && isDigit(value, 1) { - _, std, _ = nextStdChunk(layout) - std &= stdMask - if std == stdFracSecond0 || std == stdFracSecond9 { - // Fractional second in the layout; proceed normally - break - } - // No fractional second in the layout but we have one in the input. - n := 2 - for ; n < len(value) && isDigit(value, n); n++ { - } - nsec, rangeErrString, err = parseNanoseconds(value, n) - value = value[n:] - } - case stdPM: - if len(value) < 2 { - err = errBad - break - } - p, value = value[0:2], value[2:] - switch p { - case "PM": - pmSet = true - case "AM": - amSet = true - default: - err = errBad - } - case stdpm: - if len(value) < 2 { - err = errBad - break - } - p, value = value[0:2], value[2:] - switch p { - case "pm": - pmSet = true - case "am": - amSet = true - default: - err = errBad - } - case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ: - if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' { - value = value[1:] - z = UTC - break - } - var sign, hour, min, seconds string - if std == stdISO8601ColonTZ || std == stdNumColonTZ { - if len(value) < 6 { - err = errBad - break - } - if value[3] != ':' { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:] - } else if std == stdNumShortTZ || std == stdISO8601ShortTZ { - if len(value) < 3 { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], "00", "00", value[3:] - } else if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { - if len(value) < 9 { - err = errBad - break - } - if value[3] != ':' || value[6] != ':' { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], value[7:9], value[9:] - } else if std == stdISO8601SecondsTZ || std == stdNumSecondsTz { - if len(value) < 7 { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], value[5:7], value[7:] - } else { - if len(value) < 5 { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], "00", value[5:] - } - var hr, mm, ss int - hr, _, err = getnum(hour, true) - if err == nil { - mm, _, err = getnum(min, true) - } - if err == nil { - ss, _, err = getnum(seconds, true) - } - zoneOffset = (hr*60+mm)*60 + ss // offset is in seconds - switch sign[0] { - case '+': - case '-': - zoneOffset = -zoneOffset - default: - err = errBad - } - case stdTZ: - // Does it look like a time zone? - if len(value) >= 3 && value[0:3] == "UTC" { - z = UTC - value = value[3:] - break - } - n, ok := parseTimeZone(value) - if !ok { - err = errBad - break - } - zoneName, value = value[:n], value[n:] - - case stdFracSecond0: - // stdFracSecond0 requires the exact number of digits as specified in - // the layout. - ndigit := 1 + digitsLen(std) - if len(value) < ndigit { - err = errBad - break - } - nsec, rangeErrString, err = parseNanoseconds(value, ndigit) - value = value[ndigit:] - - case stdFracSecond9: - if len(value) < 2 || !commaOrPeriod(value[0]) || value[1] < '0' || '9' < value[1] { - // Fractional second omitted. - break - } - // Take any number of digits, even more than asked for, - // because it is what the stdSecond case would do. - i := 0 - for i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' { - i++ - } - nsec, rangeErrString, err = parseNanoseconds(value, 1+i) - value = value[1+i:] - } - if rangeErrString != "" { - return Time{}, newParseError(alayout, avalue, stdstr, value, ": "+rangeErrString+" out of range") - } - if err != nil { - return Time{}, newParseError(alayout, avalue, stdstr, hold, "") - } - } - if pmSet && hour < 12 { - hour += 12 - } else if amSet && hour == 12 { - hour = 0 - } - - // Convert yday to day, month. - if yday >= 0 { - var d int - var m int - if isLeap(year) { - if yday == 31+29 { - m = int(February) - d = 29 - } else if yday > 31+29 { - yday-- - } - } - if yday < 1 || yday > 365 { - return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year out of range") - } - if m == 0 { - m = (yday-1)/31 + 1 - if int(daysBefore[m]) < yday { - m++ - } - d = yday - int(daysBefore[m-1]) - } - // If month, day already seen, yday's m, d must match. - // Otherwise, set them from m, d. - if month >= 0 && month != m { - return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year does not match month") - } - month = m - if day >= 0 && day != d { - return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year does not match day") - } - day = d - } else { - if month < 0 { - month = int(January) - } - if day < 0 { - day = 1 - } - } - - // Validate the day of the month. - if day < 1 || day > daysIn(Month(month), year) { - return Time{}, newParseError(alayout, avalue, "", value, ": day out of range") - } - - if z != nil { - return Date(year, Month(month), day, hour, min, sec, nsec, z), nil - } - - if zoneOffset != -1 { - t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) - t.addSec(-int64(zoneOffset)) - - // Look for local zone with the given offset. - // If that zone was in effect at the given time, use it. - name, offset, _, _, _ := local.lookup(t.unixSec()) - if offset == zoneOffset && (zoneName == "" || name == zoneName) { - t.setLoc(local) - return t, nil - } - - // Otherwise create fake zone to record offset. - zoneNameCopy := cloneString(zoneName) // avoid leaking the input value - t.setLoc(FixedZone(zoneNameCopy, zoneOffset)) - return t, nil - } - - if zoneName != "" { - t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) - // Look for local zone with the given offset. - // If that zone was in effect at the given time, use it. - offset, ok := local.lookupName(zoneName, t.unixSec()) - if ok { - t.addSec(-int64(offset)) - t.setLoc(local) - return t, nil - } - - // Otherwise, create fake zone with unknown offset. - if len(zoneName) > 3 && zoneName[:3] == "GMT" { - offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT. - offset *= 3600 - } - zoneNameCopy := cloneString(zoneName) // avoid leaking the input value - t.setLoc(FixedZone(zoneNameCopy, offset)) - return t, nil - } - - // Otherwise, fall back to default. - return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil -} - -// parseTimeZone parses a time zone string and returns its length. Time zones -// are human-generated and unpredictable. We can't do precise error checking. -// On the other hand, for a correct parse there must be a time zone at the -// beginning of the string, so it's almost always true that there's one -// there. We look at the beginning of the string for a run of upper-case letters. -// If there are more than 5, it's an error. -// If there are 4 or 5 and the last is a T, it's a time zone. -// If there are 3, it's a time zone. -// Otherwise, other than special cases, it's not a time zone. -// GMT is special because it can have an hour offset. -func parseTimeZone(value string) (length int, ok bool) { - if len(value) < 3 { - return 0, false - } - // Special case 1: ChST and MeST are the only zones with a lower-case letter. - if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") { - return 4, true - } - // Special case 2: GMT may have an hour offset; treat it specially. - if value[:3] == "GMT" { - length = parseGMT(value) - return length, true - } - // Special Case 3: Some time zones are not named, but have +/-00 format - if value[0] == '+' || value[0] == '-' { - length = parseSignedOffset(value) - ok := length > 0 // parseSignedOffset returns 0 in case of bad input - return length, ok - } - // How many upper-case letters are there? Need at least three, at most five. - var nUpper int - for nUpper = 0; nUpper < 6; nUpper++ { - if nUpper >= len(value) { - break - } - if c := value[nUpper]; c < 'A' || 'Z' < c { - break - } - } - switch nUpper { - case 0, 1, 2, 6: - return 0, false - case 5: // Must end in T to match. - if value[4] == 'T' { - return 5, true - } - case 4: - // Must end in T, except one special case. - if value[3] == 'T' || value[:4] == "WITA" { - return 4, true - } - case 3: - return 3, true - } - return 0, false -} - -// parseGMT parses a GMT time zone. The input string is known to start "GMT". -// The function checks whether that is followed by a sign and a number in the -// range -23 through +23 excluding zero. -func parseGMT(value string) int { - value = value[3:] - if len(value) == 0 { - return 3 - } - - return 3 + parseSignedOffset(value) -} - -// parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04"). -// The function checks for a signed number in the range -23 through +23 excluding zero. -// Returns length of the found offset string or 0 otherwise. -func parseSignedOffset(value string) int { - sign := value[0] - if sign != '-' && sign != '+' { - return 0 - } - x, rem, err := leadingInt(value[1:]) - - // fail if nothing consumed by leadingInt - if err != nil || value[1:] == rem { - return 0 - } - if x > 23 { - return 0 - } - return len(value) - len(rem) -} - -func commaOrPeriod(b byte) bool { - return b == '.' || b == ',' -} - -func parseNanoseconds[bytes []byte | string](value bytes, nbytes int) (ns int, rangeErrString string, err error) { - if !commaOrPeriod(value[0]) { - err = errBad - return - } - if nbytes > 10 { - value = value[:10] - nbytes = 10 - } - if ns, err = atoi(value[1:nbytes]); err != nil { - return - } - if ns < 0 { - rangeErrString = "fractional second" - return - } - // We need nanoseconds, which means scaling by the number - // of missing digits in the format, maximum length 10. - scaleDigits := 10 - nbytes - for i := 0; i < scaleDigits; i++ { - ns *= 10 - } - return -} - -var errLeadingInt = errors.New("time: bad [0-9]*") // never printed - -// leadingInt consumes the leading [0-9]* from s. -func leadingInt[bytes []byte | string](s bytes) (x uint64, rem bytes, err error) { - i := 0 - for ; i < len(s); i++ { - c := s[i] - if c < '0' || c > '9' { - break - } - if x > 1<<63/10 { - // overflow - return 0, rem, errLeadingInt - } - x = x*10 + uint64(c) - '0' - if x > 1<<63 { - // overflow - return 0, rem, errLeadingInt - } - } - return x, s[i:], nil -} - -// leadingFraction consumes the leading [0-9]* from s. -// It is used only for fractions, so does not return an error on overflow, -// it just stops accumulating precision. -func leadingFraction(s string) (x uint64, scale float64, rem string) { - i := 0 - scale = 1 - overflow := false - for ; i < len(s); i++ { - c := s[i] - if c < '0' || c > '9' { - break - } - if overflow { - continue - } - if x > (1<<63-1)/10 { - // It's possible for overflow to give a positive number, so take care. - overflow = true - continue - } - y := x*10 + uint64(c) - '0' - if y > 1<<63 { - overflow = true - continue - } - x = y - scale *= 10 - } - return x, scale, s[i:] -} - -var unitMap = map[string]uint64{ - "ns": uint64(Nanosecond), - "us": uint64(Microsecond), - "µs": uint64(Microsecond), // U+00B5 = micro symbol - "μs": uint64(Microsecond), // U+03BC = Greek letter mu - "ms": uint64(Millisecond), - "s": uint64(Second), - "m": uint64(Minute), - "h": uint64(Hour), -} - -// ParseDuration parses a duration string. -// A duration string is a possibly signed sequence of -// decimal numbers, each with optional fraction and a unit suffix, -// such as "300ms", "-1.5h" or "2h45m". -// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". -func ParseDuration(s string) (Duration, error) { - // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ - orig := s - var d uint64 - neg := false - - // Consume [-+]? - if s != "" { - c := s[0] - if c == '-' || c == '+' { - neg = c == '-' - s = s[1:] - } - } - // Special case: if all that is left is "0", this is zero. - if s == "0" { - return 0, nil - } - if s == "" { - return 0, errors.New("time: invalid duration " + quote(orig)) - } - for s != "" { - var ( - v, f uint64 // integers before, after decimal point - scale float64 = 1 // value = v + f/scale - ) - - var err error - - // The next character must be [0-9.] - if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') { - return 0, errors.New("time: invalid duration " + quote(orig)) - } - // Consume [0-9]* - pl := len(s) - v, s, err = leadingInt(s) - if err != nil { - return 0, errors.New("time: invalid duration " + quote(orig)) - } - pre := pl != len(s) // whether we consumed anything before a period - - // Consume (\.[0-9]*)? - post := false - if s != "" && s[0] == '.' { - s = s[1:] - pl := len(s) - f, scale, s = leadingFraction(s) - post = pl != len(s) - } - if !pre && !post { - // no digits (e.g. ".s" or "-.s") - return 0, errors.New("time: invalid duration " + quote(orig)) - } - - // Consume unit. - i := 0 - for ; i < len(s); i++ { - c := s[i] - if c == '.' || '0' <= c && c <= '9' { - break - } - } - if i == 0 { - return 0, errors.New("time: missing unit in duration " + quote(orig)) - } - u := s[:i] - s = s[i:] - unit, ok := unitMap[u] - if !ok { - return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig)) - } - if v > 1<<63/unit { - // overflow - return 0, errors.New("time: invalid duration " + quote(orig)) - } - v *= unit - if f > 0 { - // float64 is needed to be nanosecond accurate for fractions of hours. - // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) - v += uint64(float64(f) * (float64(unit) / scale)) - if v > 1<<63 { - // overflow - return 0, errors.New("time: invalid duration " + quote(orig)) - } - } - d += v - if d > 1<<63 { - return 0, errors.New("time: invalid duration " + quote(orig)) - } - } - if neg { - return -Duration(d), nil - } - if d > 1<<63-1 { - return 0, errors.New("time: invalid duration " + quote(orig)) - } - return Duration(d), nil -} diff --git a/contrib/go/_std_1.22/src/time/sleep.go b/contrib/go/_std_1.22/src/time/sleep.go deleted file mode 100644 index 0aec4cacc6bf..000000000000 --- a/contrib/go/_std_1.22/src/time/sleep.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package time - -// Sleep pauses the current goroutine for at least the duration d. -// A negative or zero duration causes Sleep to return immediately. -func Sleep(d Duration) - -// Interface to timers implemented in package runtime. -// Must be in sync with ../runtime/time.go:/^type timer -type runtimeTimer struct { - pp uintptr - when int64 - period int64 - f func(any, uintptr) // NOTE: must not be closure - arg any - seq uintptr - nextwhen int64 - status uint32 -} - -// when is a helper function for setting the 'when' field of a runtimeTimer. -// It returns what the time will be, in nanoseconds, Duration d in the future. -// If d is negative, it is ignored. If the returned value would be less than -// zero because of an overflow, MaxInt64 is returned. -func when(d Duration) int64 { - if d <= 0 { - return runtimeNano() - } - t := runtimeNano() + int64(d) - if t < 0 { - // N.B. runtimeNano() and d are always positive, so addition - // (including overflow) will never result in t == 0. - t = 1<<63 - 1 // math.MaxInt64 - } - return t -} - -func startTimer(*runtimeTimer) -func stopTimer(*runtimeTimer) bool -func resetTimer(*runtimeTimer, int64) bool -func modTimer(t *runtimeTimer, when, period int64, f func(any, uintptr), arg any, seq uintptr) - -// The Timer type represents a single event. -// When the Timer expires, the current time will be sent on C, -// unless the Timer was created by AfterFunc. -// A Timer must be created with NewTimer or AfterFunc. -type Timer struct { - C <-chan Time - r runtimeTimer -} - -// Stop prevents the Timer from firing. -// It returns true if the call stops the timer, false if the timer has already -// expired or been stopped. -// Stop does not close the channel, to prevent a read from the channel succeeding -// incorrectly. -// -// To ensure the channel is empty after a call to Stop, check the -// return value and drain the channel. -// For example, assuming the program has not received from t.C already: -// -// if !t.Stop() { -// <-t.C -// } -// -// This cannot be done concurrent to other receives from the Timer's -// channel or other calls to the Timer's Stop method. -// -// For a timer created with AfterFunc(d, f), if t.Stop returns false, then the timer -// has already expired and the function f has been started in its own goroutine; -// Stop does not wait for f to complete before returning. -// If the caller needs to know whether f is completed, it must coordinate -// with f explicitly. -func (t *Timer) Stop() bool { - if t.r.f == nil { - panic("time: Stop called on uninitialized Timer") - } - return stopTimer(&t.r) -} - -// NewTimer creates a new Timer that will send -// the current time on its channel after at least duration d. -func NewTimer(d Duration) *Timer { - c := make(chan Time, 1) - t := &Timer{ - C: c, - r: runtimeTimer{ - when: when(d), - f: sendTime, - arg: c, - }, - } - startTimer(&t.r) - return t -} - -// Reset changes the timer to expire after duration d. -// It returns true if the timer had been active, false if the timer had -// expired or been stopped. -// -// For a Timer created with NewTimer, Reset should be invoked only on -// stopped or expired timers with drained channels. -// -// If a program has already received a value from t.C, the timer is known -// to have expired and the channel drained, so t.Reset can be used directly. -// If a program has not yet received a value from t.C, however, -// the timer must be stopped and—if Stop reports that the timer expired -// before being stopped—the channel explicitly drained: -// -// if !t.Stop() { -// <-t.C -// } -// t.Reset(d) -// -// This should not be done concurrent to other receives from the Timer's -// channel. -// -// Note that it is not possible to use Reset's return value correctly, as there -// is a race condition between draining the channel and the new timer expiring. -// Reset should always be invoked on stopped or expired channels, as described above. -// The return value exists to preserve compatibility with existing programs. -// -// For a Timer created with AfterFunc(d, f), Reset either reschedules -// when f will run, in which case Reset returns true, or schedules f -// to run again, in which case it returns false. -// When Reset returns false, Reset neither waits for the prior f to -// complete before returning nor does it guarantee that the subsequent -// goroutine running f does not run concurrently with the prior -// one. If the caller needs to know whether the prior execution of -// f is completed, it must coordinate with f explicitly. -func (t *Timer) Reset(d Duration) bool { - if t.r.f == nil { - panic("time: Reset called on uninitialized Timer") - } - w := when(d) - return resetTimer(&t.r, w) -} - -// sendTime does a non-blocking send of the current time on c. -func sendTime(c any, seq uintptr) { - select { - case c.(chan Time) <- Now(): - default: - } -} - -// After waits for the duration to elapse and then sends the current time -// on the returned channel. -// It is equivalent to NewTimer(d).C. -// The underlying Timer is not recovered by the garbage collector -// until the timer fires. If efficiency is a concern, use NewTimer -// instead and call Timer.Stop if the timer is no longer needed. -func After(d Duration) <-chan Time { - return NewTimer(d).C -} - -// AfterFunc waits for the duration to elapse and then calls f -// in its own goroutine. It returns a Timer that can -// be used to cancel the call using its Stop method. -// The returned Timer's C field is not used and will be nil. -func AfterFunc(d Duration, f func()) *Timer { - t := &Timer{ - r: runtimeTimer{ - when: when(d), - f: goFunc, - arg: f, - }, - } - startTimer(&t.r) - return t -} - -func goFunc(arg any, seq uintptr) { - go arg.(func())() -} diff --git a/contrib/go/_std_1.22/src/time/tick.go b/contrib/go/_std_1.22/src/time/tick.go deleted file mode 100644 index 9da16b5d5830..000000000000 --- a/contrib/go/_std_1.22/src/time/tick.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package time - -// A Ticker holds a channel that delivers “ticks” of a clock -// at intervals. -type Ticker struct { - C <-chan Time // The channel on which the ticks are delivered. - r runtimeTimer -} - -// NewTicker returns a new Ticker containing a channel that will send -// the current time on the channel after each tick. The period of the -// ticks is specified by the duration argument. The ticker will adjust -// the time interval or drop ticks to make up for slow receivers. -// The duration d must be greater than zero; if not, NewTicker will -// panic. Stop the ticker to release associated resources. -func NewTicker(d Duration) *Ticker { - if d <= 0 { - panic("non-positive interval for NewTicker") - } - // Give the channel a 1-element time buffer. - // If the client falls behind while reading, we drop ticks - // on the floor until the client catches up. - c := make(chan Time, 1) - t := &Ticker{ - C: c, - r: runtimeTimer{ - when: when(d), - period: int64(d), - f: sendTime, - arg: c, - }, - } - startTimer(&t.r) - return t -} - -// Stop turns off a ticker. After Stop, no more ticks will be sent. -// Stop does not close the channel, to prevent a concurrent goroutine -// reading from the channel from seeing an erroneous "tick". -func (t *Ticker) Stop() { - stopTimer(&t.r) -} - -// Reset stops a ticker and resets its period to the specified duration. -// The next tick will arrive after the new period elapses. The duration d -// must be greater than zero; if not, Reset will panic. -func (t *Ticker) Reset(d Duration) { - if d <= 0 { - panic("non-positive interval for Ticker.Reset") - } - if t.r.f == nil { - panic("time: Reset called on uninitialized Ticker") - } - modTimer(&t.r, when(d), int64(d), t.r.f, t.r.arg, t.r.seq) -} - -// Tick is a convenience wrapper for NewTicker providing access to the ticking -// channel only. While Tick is useful for clients that have no need to shut down -// the Ticker, be aware that without a way to shut it down the underlying -// Ticker cannot be recovered by the garbage collector; it "leaks". -// Unlike NewTicker, Tick will return nil if d <= 0. -func Tick(d Duration) <-chan Time { - if d <= 0 { - return nil - } - return NewTicker(d).C -} diff --git a/contrib/go/_std_1.22/src/time/time.go b/contrib/go/_std_1.22/src/time/time.go deleted file mode 100644 index 9d4c6e919e58..000000000000 --- a/contrib/go/_std_1.22/src/time/time.go +++ /dev/null @@ -1,1667 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package time provides functionality for measuring and displaying time. -// -// The calendrical calculations always assume a Gregorian calendar, with -// no leap seconds. -// -// # Monotonic Clocks -// -// Operating systems provide both a “wall clock,” which is subject to -// changes for clock synchronization, and a “monotonic clock,” which is -// not. The general rule is that the wall clock is for telling time and -// the monotonic clock is for measuring time. Rather than split the API, -// in this package the Time returned by time.Now contains both a wall -// clock reading and a monotonic clock reading; later time-telling -// operations use the wall clock reading, but later time-measuring -// operations, specifically comparisons and subtractions, use the -// monotonic clock reading. -// -// For example, this code always computes a positive elapsed time of -// approximately 20 milliseconds, even if the wall clock is changed during -// the operation being timed: -// -// start := time.Now() -// ... operation that takes 20 milliseconds ... -// t := time.Now() -// elapsed := t.Sub(start) -// -// Other idioms, such as time.Since(start), time.Until(deadline), and -// time.Now().Before(deadline), are similarly robust against wall clock -// resets. -// -// The rest of this section gives the precise details of how operations -// use monotonic clocks, but understanding those details is not required -// to use this package. -// -// The Time returned by time.Now contains a monotonic clock reading. -// If Time t has a monotonic clock reading, t.Add adds the same duration to -// both the wall clock and monotonic clock readings to compute the result. -// Because t.AddDate(y, m, d), t.Round(d), and t.Truncate(d) are wall time -// computations, they always strip any monotonic clock reading from their results. -// Because t.In, t.Local, and t.UTC are used for their effect on the interpretation -// of the wall time, they also strip any monotonic clock reading from their results. -// The canonical way to strip a monotonic clock reading is to use t = t.Round(0). -// -// If Times t and u both contain monotonic clock readings, the operations -// t.After(u), t.Before(u), t.Equal(u), t.Compare(u), and t.Sub(u) are carried out -// using the monotonic clock readings alone, ignoring the wall clock -// readings. If either t or u contains no monotonic clock reading, these -// operations fall back to using the wall clock readings. -// -// On some systems the monotonic clock will stop if the computer goes to sleep. -// On such a system, t.Sub(u) may not accurately reflect the actual -// time that passed between t and u. -// -// Because the monotonic clock reading has no meaning outside -// the current process, the serialized forms generated by t.GobEncode, -// t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic -// clock reading, and t.Format provides no format for it. Similarly, the -// constructors time.Date, time.Parse, time.ParseInLocation, and time.Unix, -// as well as the unmarshalers t.GobDecode, t.UnmarshalBinary. -// t.UnmarshalJSON, and t.UnmarshalText always create times with -// no monotonic clock reading. -// -// The monotonic clock reading exists only in Time values. It is not -// a part of Duration values or the Unix times returned by t.Unix and -// friends. -// -// Note that the Go == operator compares not just the time instant but -// also the Location and the monotonic clock reading. See the -// documentation for the Time type for a discussion of equality -// testing for Time values. -// -// For debugging, the result of t.String does include the monotonic -// clock reading if present. If t != u because of different monotonic clock readings, -// that difference will be visible when printing t.String() and u.String(). -// -// # Timer Resolution -// -// Timer resolution varies depending on the Go runtime, the operating system -// and the underlying hardware. -// On Unix, the resolution is approximately 1ms. -// On Windows, the default resolution is approximately 16ms, but -// a higher resolution may be requested using [golang.org/x/sys/windows.TimeBeginPeriod]. -package time - -import ( - "errors" - _ "unsafe" // for go:linkname -) - -// A Time represents an instant in time with nanosecond precision. -// -// Programs using times should typically store and pass them as values, -// not pointers. That is, time variables and struct fields should be of -// type time.Time, not *time.Time. -// -// A Time value can be used by multiple goroutines simultaneously except -// that the methods GobDecode, UnmarshalBinary, UnmarshalJSON and -// UnmarshalText are not concurrency-safe. -// -// Time instants can be compared using the Before, After, and Equal methods. -// The Sub method subtracts two instants, producing a Duration. -// The Add method adds a Time and a Duration, producing a Time. -// -// The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. -// As this time is unlikely to come up in practice, the IsZero method gives -// a simple way of detecting a time that has not been initialized explicitly. -// -// Each time has an associated Location. The methods Local, UTC, and In return a -// Time with a specific Location. Changing the Location of a Time value with -// these methods does not change the actual instant it represents, only the time -// zone in which to interpret it. -// -// Representations of a Time value saved by the GobEncode, MarshalBinary, -// MarshalJSON, and MarshalText methods store the Time.Location's offset, but not -// the location name. They therefore lose information about Daylight Saving Time. -// -// In addition to the required “wall clock” reading, a Time may contain an optional -// reading of the current process's monotonic clock, to provide additional precision -// for comparison or subtraction. -// See the “Monotonic Clocks” section in the package documentation for details. -// -// Note that the Go == operator compares not just the time instant but also the -// Location and the monotonic clock reading. Therefore, Time values should not -// be used as map or database keys without first guaranteeing that the -// identical Location has been set for all values, which can be achieved -// through use of the UTC or Local method, and that the monotonic clock reading -// has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u) -// to t == u, since t.Equal uses the most accurate comparison available and -// correctly handles the case when only one of its arguments has a monotonic -// clock reading. -type Time struct { - // wall and ext encode the wall time seconds, wall time nanoseconds, - // and optional monotonic clock reading in nanoseconds. - // - // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic), - // a 33-bit seconds field, and a 30-bit wall time nanoseconds field. - // The nanoseconds field is in the range [0, 999999999]. - // If the hasMonotonic bit is 0, then the 33-bit field must be zero - // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext. - // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit - // unsigned wall seconds since Jan 1 year 1885, and ext holds a - // signed 64-bit monotonic clock reading, nanoseconds since process start. - wall uint64 - ext int64 - - // loc specifies the Location that should be used to - // determine the minute, hour, month, day, and year - // that correspond to this Time. - // The nil location means UTC. - // All UTC times are represented with loc==nil, never loc==&utcLoc. - loc *Location -} - -const ( - hasMonotonic = 1 << 63 - maxWall = wallToInternal + (1<<33 - 1) // year 2157 - minWall = wallToInternal // year 1885 - nsecMask = 1<<30 - 1 - nsecShift = 30 -) - -// These helpers for manipulating the wall and monotonic clock readings -// take pointer receivers, even when they don't modify the time, -// to make them cheaper to call. - -// nsec returns the time's nanoseconds. -func (t *Time) nsec() int32 { - return int32(t.wall & nsecMask) -} - -// sec returns the time's seconds since Jan 1 year 1. -func (t *Time) sec() int64 { - if t.wall&hasMonotonic != 0 { - return wallToInternal + int64(t.wall<<1>>(nsecShift+1)) - } - return t.ext -} - -// unixSec returns the time's seconds since Jan 1 1970 (Unix time). -func (t *Time) unixSec() int64 { return t.sec() + internalToUnix } - -// addSec adds d seconds to the time. -func (t *Time) addSec(d int64) { - if t.wall&hasMonotonic != 0 { - sec := int64(t.wall << 1 >> (nsecShift + 1)) - dsec := sec + d - if 0 <= dsec && dsec <= 1<<33-1 { - t.wall = t.wall&nsecMask | uint64(dsec)< t.ext) == (d > 0) { - t.ext = sum - } else if d > 0 { - t.ext = 1<<63 - 1 - } else { - t.ext = -(1<<63 - 1) - } -} - -// setLoc sets the location associated with the time. -func (t *Time) setLoc(loc *Location) { - if loc == &utcLoc { - loc = nil - } - t.stripMono() - t.loc = loc -} - -// stripMono strips the monotonic clock reading in t. -func (t *Time) stripMono() { - if t.wall&hasMonotonic != 0 { - t.ext = t.sec() - t.wall &= nsecMask - } -} - -// setMono sets the monotonic clock reading in t. -// If t cannot hold a monotonic clock reading, -// because its wall time is too large, -// setMono is a no-op. -func (t *Time) setMono(m int64) { - if t.wall&hasMonotonic == 0 { - sec := t.ext - if sec < minWall || maxWall < sec { - return - } - t.wall |= hasMonotonic | uint64(sec-minWall)< u.ext - } - ts := t.sec() - us := u.sec() - return ts > us || ts == us && t.nsec() > u.nsec() -} - -// Before reports whether the time instant t is before u. -func (t Time) Before(u Time) bool { - if t.wall&u.wall&hasMonotonic != 0 { - return t.ext < u.ext - } - ts := t.sec() - us := u.sec() - return ts < us || ts == us && t.nsec() < u.nsec() -} - -// Compare compares the time instant t with u. If t is before u, it returns -1; -// if t is after u, it returns +1; if they're the same, it returns 0. -func (t Time) Compare(u Time) int { - var tc, uc int64 - if t.wall&u.wall&hasMonotonic != 0 { - tc, uc = t.ext, u.ext - } else { - tc, uc = t.sec(), u.sec() - if tc == uc { - tc, uc = int64(t.nsec()), int64(u.nsec()) - } - } - switch { - case tc < uc: - return -1 - case tc > uc: - return +1 - } - return 0 -} - -// Equal reports whether t and u represent the same time instant. -// Two times can be equal even if they are in different locations. -// For example, 6:00 +0200 and 4:00 UTC are Equal. -// See the documentation on the Time type for the pitfalls of using == with -// Time values; most code should use Equal instead. -func (t Time) Equal(u Time) bool { - if t.wall&u.wall&hasMonotonic != 0 { - return t.ext == u.ext - } - return t.sec() == u.sec() && t.nsec() == u.nsec() -} - -// A Month specifies a month of the year (January = 1, ...). -type Month int - -const ( - January Month = 1 + iota - February - March - April - May - June - July - August - September - October - November - December -) - -// String returns the English name of the month ("January", "February", ...). -func (m Month) String() string { - if January <= m && m <= December { - return longMonthNames[m-1] - } - buf := make([]byte, 20) - n := fmtInt(buf, uint64(m)) - return "%!Month(" + string(buf[n:]) + ")" -} - -// A Weekday specifies a day of the week (Sunday = 0, ...). -type Weekday int - -const ( - Sunday Weekday = iota - Monday - Tuesday - Wednesday - Thursday - Friday - Saturday -) - -// String returns the English name of the day ("Sunday", "Monday", ...). -func (d Weekday) String() string { - if Sunday <= d && d <= Saturday { - return longDayNames[d] - } - buf := make([]byte, 20) - n := fmtInt(buf, uint64(d)) - return "%!Weekday(" + string(buf[n:]) + ")" -} - -// Computations on time. -// -// The zero value for a Time is defined to be -// January 1, year 1, 00:00:00.000000000 UTC -// which (1) looks like a zero, or as close as you can get in a date -// (1-1-1 00:00:00 UTC), (2) is unlikely enough to arise in practice to -// be a suitable "not set" sentinel, unlike Jan 1 1970, and (3) has a -// non-negative year even in time zones west of UTC, unlike 1-1-0 -// 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York. -// -// The zero Time value does not force a specific epoch for the time -// representation. For example, to use the Unix epoch internally, we -// could define that to distinguish a zero value from Jan 1 1970, that -// time would be represented by sec=-1, nsec=1e9. However, it does -// suggest a representation, namely using 1-1-1 00:00:00 UTC as the -// epoch, and that's what we do. -// -// The Add and Sub computations are oblivious to the choice of epoch. -// -// The presentation computations - year, month, minute, and so on - all -// rely heavily on division and modulus by positive constants. For -// calendrical calculations we want these divisions to round down, even -// for negative values, so that the remainder is always positive, but -// Go's division (like most hardware division instructions) rounds to -// zero. We can still do those computations and then adjust the result -// for a negative numerator, but it's annoying to write the adjustment -// over and over. Instead, we can change to a different epoch so long -// ago that all the times we care about will be positive, and then round -// to zero and round down coincide. These presentation routines already -// have to add the zone offset, so adding the translation to the -// alternate epoch is cheap. For example, having a non-negative time t -// means that we can write -// -// sec = t % 60 -// -// instead of -// -// sec = t % 60 -// if sec < 0 { -// sec += 60 -// } -// -// everywhere. -// -// The calendar runs on an exact 400 year cycle: a 400-year calendar -// printed for 1970-2369 will apply as well to 2370-2769. Even the days -// of the week match up. It simplifies the computations to choose the -// cycle boundaries so that the exceptional years are always delayed as -// long as possible. That means choosing a year equal to 1 mod 400, so -// that the first leap year is the 4th year, the first missed leap year -// is the 100th year, and the missed missed leap year is the 400th year. -// So we'd prefer instead to print a calendar for 2001-2400 and reuse it -// for 2401-2800. -// -// Finally, it's convenient if the delta between the Unix epoch and -// long-ago epoch is representable by an int64 constant. -// -// These three considerations—choose an epoch as early as possible, that -// uses a year equal to 1 mod 400, and that is no more than 2⁶³ seconds -// earlier than 1970—bring us to the year -292277022399. We refer to -// this year as the absolute zero year, and to times measured as a uint64 -// seconds since this year as absolute times. -// -// Times measured as an int64 seconds since the year 1—the representation -// used for Time's sec field—are called internal times. -// -// Times measured as an int64 seconds since the year 1970 are called Unix -// times. -// -// It is tempting to just use the year 1 as the absolute epoch, defining -// that the routines are only valid for years >= 1. However, the -// routines would then be invalid when displaying the epoch in time zones -// west of UTC, since it is year 0. It doesn't seem tenable to say that -// printing the zero time correctly isn't supported in half the time -// zones. By comparison, it's reasonable to mishandle some times in -// the year -292277022399. -// -// All this is opaque to clients of the API and can be changed if a -// better implementation presents itself. - -const ( - // The unsigned zero year for internal calculations. - // Must be 1 mod 400, and times before it will not compute correctly, - // but otherwise can be changed at will. - absoluteZeroYear = -292277022399 - - // The year of the zero Time. - // Assumed by the unixToInternal computation below. - internalYear = 1 - - // Offsets to convert between internal and absolute or Unix times. - absoluteToInternal int64 = (absoluteZeroYear - internalYear) * 365.2425 * secondsPerDay - internalToAbsolute = -absoluteToInternal - - unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay - internalToUnix int64 = -unixToInternal - - wallToInternal int64 = (1884*365 + 1884/4 - 1884/100 + 1884/400) * secondsPerDay -) - -// IsZero reports whether t represents the zero time instant, -// January 1, year 1, 00:00:00 UTC. -func (t Time) IsZero() bool { - return t.sec() == 0 && t.nsec() == 0 -} - -// abs returns the time t as an absolute time, adjusted by the zone offset. -// It is called when computing a presentation property like Month or Hour. -func (t Time) abs() uint64 { - l := t.loc - // Avoid function calls when possible. - if l == nil || l == &localLoc { - l = l.get() - } - sec := t.unixSec() - if l != &utcLoc { - if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd { - sec += int64(l.cacheZone.offset) - } else { - _, offset, _, _, _ := l.lookup(sec) - sec += int64(offset) - } - } - return uint64(sec + (unixToInternal + internalToAbsolute)) -} - -// locabs is a combination of the Zone and abs methods, -// extracting both return values from a single zone lookup. -func (t Time) locabs() (name string, offset int, abs uint64) { - l := t.loc - if l == nil || l == &localLoc { - l = l.get() - } - // Avoid function call if we hit the local time cache. - sec := t.unixSec() - if l != &utcLoc { - if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd { - name = l.cacheZone.name - offset = l.cacheZone.offset - } else { - name, offset, _, _, _ = l.lookup(sec) - } - sec += int64(offset) - } else { - name = "UTC" - } - abs = uint64(sec + (unixToInternal + internalToAbsolute)) - return -} - -// Date returns the year, month, and day in which t occurs. -func (t Time) Date() (year int, month Month, day int) { - year, month, day, _ = t.date(true) - return -} - -// Year returns the year in which t occurs. -func (t Time) Year() int { - year, _, _, _ := t.date(false) - return year -} - -// Month returns the month of the year specified by t. -func (t Time) Month() Month { - _, month, _, _ := t.date(true) - return month -} - -// Day returns the day of the month specified by t. -func (t Time) Day() int { - _, _, day, _ := t.date(true) - return day -} - -// Weekday returns the day of the week specified by t. -func (t Time) Weekday() Weekday { - return absWeekday(t.abs()) -} - -// absWeekday is like Weekday but operates on an absolute time. -func absWeekday(abs uint64) Weekday { - // January 1 of the absolute year, like January 1 of 2001, was a Monday. - sec := (abs + uint64(Monday)*secondsPerDay) % secondsPerWeek - return Weekday(int(sec) / secondsPerDay) -} - -// ISOWeek returns the ISO 8601 year and week number in which t occurs. -// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to -// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1 -// of year n+1. -func (t Time) ISOWeek() (year, week int) { - // According to the rule that the first calendar week of a calendar year is - // the week including the first Thursday of that year, and that the last one is - // the week immediately preceding the first calendar week of the next calendar year. - // See https://www.iso.org/obp/ui#iso:std:iso:8601:-1:ed-1:v1:en:term:3.1.1.23 for details. - - // weeks start with Monday - // Monday Tuesday Wednesday Thursday Friday Saturday Sunday - // 1 2 3 4 5 6 7 - // +3 +2 +1 0 -1 -2 -3 - // the offset to Thursday - abs := t.abs() - d := Thursday - absWeekday(abs) - // handle Sunday - if d == 4 { - d = -3 - } - // find the Thursday of the calendar week - abs += uint64(d) * secondsPerDay - year, _, _, yday := absDate(abs, false) - return year, yday/7 + 1 -} - -// Clock returns the hour, minute, and second within the day specified by t. -func (t Time) Clock() (hour, min, sec int) { - return absClock(t.abs()) -} - -// absClock is like clock but operates on an absolute time. -func absClock(abs uint64) (hour, min, sec int) { - sec = int(abs % secondsPerDay) - hour = sec / secondsPerHour - sec -= hour * secondsPerHour - min = sec / secondsPerMinute - sec -= min * secondsPerMinute - return -} - -// Hour returns the hour within the day specified by t, in the range [0, 23]. -func (t Time) Hour() int { - return int(t.abs()%secondsPerDay) / secondsPerHour -} - -// Minute returns the minute offset within the hour specified by t, in the range [0, 59]. -func (t Time) Minute() int { - return int(t.abs()%secondsPerHour) / secondsPerMinute -} - -// Second returns the second offset within the minute specified by t, in the range [0, 59]. -func (t Time) Second() int { - return int(t.abs() % secondsPerMinute) -} - -// Nanosecond returns the nanosecond offset within the second specified by t, -// in the range [0, 999999999]. -func (t Time) Nanosecond() int { - return int(t.nsec()) -} - -// YearDay returns the day of the year specified by t, in the range [1,365] for non-leap years, -// and [1,366] in leap years. -func (t Time) YearDay() int { - _, _, _, yday := t.date(false) - return yday + 1 -} - -// A Duration represents the elapsed time between two instants -// as an int64 nanosecond count. The representation limits the -// largest representable duration to approximately 290 years. -type Duration int64 - -const ( - minDuration Duration = -1 << 63 - maxDuration Duration = 1<<63 - 1 -) - -// Common durations. There is no definition for units of Day or larger -// to avoid confusion across daylight savings time zone transitions. -// -// To count the number of units in a Duration, divide: -// -// second := time.Second -// fmt.Print(int64(second/time.Millisecond)) // prints 1000 -// -// To convert an integer number of units to a Duration, multiply: -// -// seconds := 10 -// fmt.Print(time.Duration(seconds)*time.Second) // prints 10s -const ( - Nanosecond Duration = 1 - Microsecond = 1000 * Nanosecond - Millisecond = 1000 * Microsecond - Second = 1000 * Millisecond - Minute = 60 * Second - Hour = 60 * Minute -) - -// String returns a string representing the duration in the form "72h3m0.5s". -// Leading zero units are omitted. As a special case, durations less than one -// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure -// that the leading digit is non-zero. The zero duration formats as 0s. -func (d Duration) String() string { - // This is inlinable to take advantage of "function outlining". - // Thus, the caller can decide whether a string must be heap allocated. - var arr [32]byte - n := d.format(&arr) - return string(arr[n:]) -} - -// format formats the representation of d into the end of buf and -// returns the offset of the first character. -func (d Duration) format(buf *[32]byte) int { - // Largest time is 2540400h10m10.000000000s - w := len(buf) - - u := uint64(d) - neg := d < 0 - if neg { - u = -u - } - - if u < uint64(Second) { - // Special case: if duration is smaller than a second, - // use smaller units, like 1.2ms - var prec int - w-- - buf[w] = 's' - w-- - switch { - case u == 0: - buf[w] = '0' - return w - case u < uint64(Microsecond): - // print nanoseconds - prec = 0 - buf[w] = 'n' - case u < uint64(Millisecond): - // print microseconds - prec = 3 - // U+00B5 'µ' micro sign == 0xC2 0xB5 - w-- // Need room for two bytes. - copy(buf[w:], "µ") - default: - // print milliseconds - prec = 6 - buf[w] = 'm' - } - w, u = fmtFrac(buf[:w], u, prec) - w = fmtInt(buf[:w], u) - } else { - w-- - buf[w] = 's' - - w, u = fmtFrac(buf[:w], u, 9) - - // u is now integer seconds - w = fmtInt(buf[:w], u%60) - u /= 60 - - // u is now integer minutes - if u > 0 { - w-- - buf[w] = 'm' - w = fmtInt(buf[:w], u%60) - u /= 60 - - // u is now integer hours - // Stop at hours because days can be different lengths. - if u > 0 { - w-- - buf[w] = 'h' - w = fmtInt(buf[:w], u) - } - } - } - - if neg { - w-- - buf[w] = '-' - } - - return w -} - -// fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the -// tail of buf, omitting trailing zeros. It omits the decimal -// point too when the fraction is 0. It returns the index where the -// output bytes begin and the value v/10**prec. -func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) { - // Omit trailing zeros up to and including decimal point. - w := len(buf) - print := false - for i := 0; i < prec; i++ { - digit := v % 10 - print = print || digit != 0 - if print { - w-- - buf[w] = byte(digit) + '0' - } - v /= 10 - } - if print { - w-- - buf[w] = '.' - } - return w, v -} - -// fmtInt formats v into the tail of buf. -// It returns the index where the output begins. -func fmtInt(buf []byte, v uint64) int { - w := len(buf) - if v == 0 { - w-- - buf[w] = '0' - } else { - for v > 0 { - w-- - buf[w] = byte(v%10) + '0' - v /= 10 - } - } - return w -} - -// Nanoseconds returns the duration as an integer nanosecond count. -func (d Duration) Nanoseconds() int64 { return int64(d) } - -// Microseconds returns the duration as an integer microsecond count. -func (d Duration) Microseconds() int64 { return int64(d) / 1e3 } - -// Milliseconds returns the duration as an integer millisecond count. -func (d Duration) Milliseconds() int64 { return int64(d) / 1e6 } - -// These methods return float64 because the dominant -// use case is for printing a floating point number like 1.5s, and -// a truncation to integer would make them not useful in those cases. -// Splitting the integer and fraction ourselves guarantees that -// converting the returned float64 to an integer rounds the same -// way that a pure integer conversion would have, even in cases -// where, say, float64(d.Nanoseconds())/1e9 would have rounded -// differently. - -// Seconds returns the duration as a floating point number of seconds. -func (d Duration) Seconds() float64 { - sec := d / Second - nsec := d % Second - return float64(sec) + float64(nsec)/1e9 -} - -// Minutes returns the duration as a floating point number of minutes. -func (d Duration) Minutes() float64 { - min := d / Minute - nsec := d % Minute - return float64(min) + float64(nsec)/(60*1e9) -} - -// Hours returns the duration as a floating point number of hours. -func (d Duration) Hours() float64 { - hour := d / Hour - nsec := d % Hour - return float64(hour) + float64(nsec)/(60*60*1e9) -} - -// Truncate returns the result of rounding d toward zero to a multiple of m. -// If m <= 0, Truncate returns d unchanged. -func (d Duration) Truncate(m Duration) Duration { - if m <= 0 { - return d - } - return d - d%m -} - -// lessThanHalf reports whether x+x < y but avoids overflow, -// assuming x and y are both positive (Duration is signed). -func lessThanHalf(x, y Duration) bool { - return uint64(x)+uint64(x) < uint64(y) -} - -// Round returns the result of rounding d to the nearest multiple of m. -// The rounding behavior for halfway values is to round away from zero. -// If the result exceeds the maximum (or minimum) -// value that can be stored in a Duration, -// Round returns the maximum (or minimum) duration. -// If m <= 0, Round returns d unchanged. -func (d Duration) Round(m Duration) Duration { - if m <= 0 { - return d - } - r := d % m - if d < 0 { - r = -r - if lessThanHalf(r, m) { - return d + r - } - if d1 := d - m + r; d1 < d { - return d1 - } - return minDuration // overflow - } - if lessThanHalf(r, m) { - return d - r - } - if d1 := d + m - r; d1 > d { - return d1 - } - return maxDuration // overflow -} - -// Abs returns the absolute value of d. -// As a special case, math.MinInt64 is converted to math.MaxInt64. -func (d Duration) Abs() Duration { - switch { - case d >= 0: - return d - case d == minDuration: - return maxDuration - default: - return -d - } -} - -// Add returns the time t+d. -func (t Time) Add(d Duration) Time { - dsec := int64(d / 1e9) - nsec := t.nsec() + int32(d%1e9) - if nsec >= 1e9 { - dsec++ - nsec -= 1e9 - } else if nsec < 0 { - dsec-- - nsec += 1e9 - } - t.wall = t.wall&^nsecMask | uint64(nsec) // update nsec - t.addSec(dsec) - if t.wall&hasMonotonic != 0 { - te := t.ext + int64(d) - if d < 0 && te > t.ext || d > 0 && te < t.ext { - // Monotonic clock reading now out of range; degrade to wall-only. - t.stripMono() - } else { - t.ext = te - } - } - return t -} - -// Sub returns the duration t-u. If the result exceeds the maximum (or minimum) -// value that can be stored in a Duration, the maximum (or minimum) duration -// will be returned. -// To compute t-d for a duration d, use t.Add(-d). -func (t Time) Sub(u Time) Duration { - if t.wall&u.wall&hasMonotonic != 0 { - return subMono(t.ext, u.ext) - } - d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec()) - // Check for overflow or underflow. - switch { - case u.Add(d).Equal(t): - return d // d is correct - case t.Before(u): - return minDuration // t - u is negative out of range - default: - return maxDuration // t - u is positive out of range - } -} - -func subMono(t, u int64) Duration { - d := Duration(t - u) - if d < 0 && t > u { - return maxDuration // t - u is positive out of range - } - if d > 0 && t < u { - return minDuration // t - u is negative out of range - } - return d -} - -// Since returns the time elapsed since t. -// It is shorthand for time.Now().Sub(t). -func Since(t Time) Duration { - if t.wall&hasMonotonic != 0 { - // Common case optimization: if t has monotonic time, then Sub will use only it. - return subMono(runtimeNano()-startNano, t.ext) - } - return Now().Sub(t) -} - -// Until returns the duration until t. -// It is shorthand for t.Sub(time.Now()). -func Until(t Time) Duration { - if t.wall&hasMonotonic != 0 { - // Common case optimization: if t has monotonic time, then Sub will use only it. - return subMono(t.ext, runtimeNano()-startNano) - } - return t.Sub(Now()) -} - -// AddDate returns the time corresponding to adding the -// given number of years, months, and days to t. -// For example, AddDate(-1, 2, 3) applied to January 1, 2011 -// returns March 4, 2010. -// -// Note that dates are fundamentally coupled to timezones, and calendrical -// periods like days don't have fixed durations. AddDate uses the Location of -// the Time value to determine these durations. That means that the same -// AddDate arguments can produce a different shift in absolute time depending on -// the base Time value and its Location. For example, AddDate(0, 0, 1) applied -// to 12:00 on March 27 always returns 12:00 on March 28. At some locations and -// in some years this is a 24 hour shift. In others it's a 23 hour shift due to -// daylight savings time transitions. -// -// AddDate normalizes its result in the same way that Date does, -// so, for example, adding one month to October 31 yields -// December 1, the normalized form for November 31. -func (t Time) AddDate(years int, months int, days int) Time { - year, month, day := t.Date() - hour, min, sec := t.Clock() - return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec()), t.Location()) -} - -const ( - secondsPerMinute = 60 - secondsPerHour = 60 * secondsPerMinute - secondsPerDay = 24 * secondsPerHour - secondsPerWeek = 7 * secondsPerDay - daysPer400Years = 365*400 + 97 - daysPer100Years = 365*100 + 24 - daysPer4Years = 365*4 + 1 -) - -// date computes the year, day of year, and when full=true, -// the month and day in which t occurs. -func (t Time) date(full bool) (year int, month Month, day int, yday int) { - return absDate(t.abs(), full) -} - -// absDate is like date but operates on an absolute time. -func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) { - // Split into time and day. - d := abs / secondsPerDay - - // Account for 400 year cycles. - n := d / daysPer400Years - y := 400 * n - d -= daysPer400Years * n - - // Cut off 100-year cycles. - // The last cycle has one extra leap year, so on the last day - // of that year, day / daysPer100Years will be 4 instead of 3. - // Cut it back down to 3 by subtracting n>>2. - n = d / daysPer100Years - n -= n >> 2 - y += 100 * n - d -= daysPer100Years * n - - // Cut off 4-year cycles. - // The last cycle has a missing leap year, which does not - // affect the computation. - n = d / daysPer4Years - y += 4 * n - d -= daysPer4Years * n - - // Cut off years within a 4-year cycle. - // The last year is a leap year, so on the last day of that year, - // day / 365 will be 4 instead of 3. Cut it back down to 3 - // by subtracting n>>2. - n = d / 365 - n -= n >> 2 - y += n - d -= 365 * n - - year = int(int64(y) + absoluteZeroYear) - yday = int(d) - - if !full { - return - } - - day = yday - if isLeap(year) { - // Leap year - switch { - case day > 31+29-1: - // After leap day; pretend it wasn't there. - day-- - case day == 31+29-1: - // Leap day. - month = February - day = 29 - return - } - } - - // Estimate month on assumption that every month has 31 days. - // The estimate may be too low by at most one month, so adjust. - month = Month(day / 31) - end := int(daysBefore[month+1]) - var begin int - if day >= end { - month++ - begin = end - } else { - begin = int(daysBefore[month]) - } - - month++ // because January is 1 - day = day - begin + 1 - return -} - -// daysBefore[m] counts the number of days in a non-leap year -// before month m begins. There is an entry for m=12, counting -// the number of days before January of next year (365). -var daysBefore = [...]int32{ - 0, - 31, - 31 + 28, - 31 + 28 + 31, - 31 + 28 + 31 + 30, - 31 + 28 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, -} - -func daysIn(m Month, year int) int { - if m == February && isLeap(year) { - return 29 - } - return int(daysBefore[m] - daysBefore[m-1]) -} - -// daysSinceEpoch takes a year and returns the number of days from -// the absolute epoch to the start of that year. -// This is basically (year - zeroYear) * 365, but accounting for leap days. -func daysSinceEpoch(year int) uint64 { - y := uint64(int64(year) - absoluteZeroYear) - - // Add in days from 400-year cycles. - n := y / 400 - y -= 400 * n - d := daysPer400Years * n - - // Add in 100-year cycles. - n = y / 100 - y -= 100 * n - d += daysPer100Years * n - - // Add in 4-year cycles. - n = y / 4 - y -= 4 * n - d += daysPer4Years * n - - // Add in non-leap years. - n = y - d += 365 * n - - return d -} - -// Provided by package runtime. -func now() (sec int64, nsec int32, mono int64) - -// runtimeNano returns the current value of the runtime clock in nanoseconds. -// -//go:linkname runtimeNano runtime.nanotime -func runtimeNano() int64 - -// Monotonic times are reported as offsets from startNano. -// We initialize startNano to runtimeNano() - 1 so that on systems where -// monotonic time resolution is fairly low (e.g. Windows 2008 -// which appears to have a default resolution of 15ms), -// we avoid ever reporting a monotonic time of 0. -// (Callers may want to use 0 as "time not set".) -var startNano int64 = runtimeNano() - 1 - -// Now returns the current local time. -func Now() Time { - sec, nsec, mono := now() - mono -= startNano - sec += unixToInternal - minWall - if uint64(sec)>>33 != 0 { - // Seconds field overflowed the 33 bits available when - // storing a monotonic time. This will be true after - // March 16, 2157. - return Time{uint64(nsec), sec + minWall, Local} - } - return Time{hasMonotonic | uint64(sec)< 32767 { - return nil, errors.New("Time.MarshalBinary: unexpected zone offset") - } - offsetMin = int16(offset) - } - - sec := t.sec() - nsec := t.nsec() - enc := []byte{ - version, // byte 0 : version - byte(sec >> 56), // bytes 1-8: seconds - byte(sec >> 48), - byte(sec >> 40), - byte(sec >> 32), - byte(sec >> 24), - byte(sec >> 16), - byte(sec >> 8), - byte(sec), - byte(nsec >> 24), // bytes 9-12: nanoseconds - byte(nsec >> 16), - byte(nsec >> 8), - byte(nsec), - byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes - byte(offsetMin), - } - if version == timeBinaryVersionV2 { - enc = append(enc, byte(offsetSec)) - } - - return enc, nil -} - -// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. -func (t *Time) UnmarshalBinary(data []byte) error { - buf := data - if len(buf) == 0 { - return errors.New("Time.UnmarshalBinary: no data") - } - - version := buf[0] - if version != timeBinaryVersionV1 && version != timeBinaryVersionV2 { - return errors.New("Time.UnmarshalBinary: unsupported version") - } - - wantLen := /*version*/ 1 + /*sec*/ 8 + /*nsec*/ 4 + /*zone offset*/ 2 - if version == timeBinaryVersionV2 { - wantLen++ - } - if len(buf) != wantLen { - return errors.New("Time.UnmarshalBinary: invalid length") - } - - buf = buf[1:] - sec := int64(buf[7]) | int64(buf[6])<<8 | int64(buf[5])<<16 | int64(buf[4])<<24 | - int64(buf[3])<<32 | int64(buf[2])<<40 | int64(buf[1])<<48 | int64(buf[0])<<56 - - buf = buf[8:] - nsec := int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24 - - buf = buf[4:] - offset := int(int16(buf[1])|int16(buf[0])<<8) * 60 - if version == timeBinaryVersionV2 { - offset += int(buf[2]) - } - - *t = Time{} - t.wall = uint64(nsec) - t.ext = sec - - if offset == -1*60 { - t.setLoc(&utcLoc) - } else if _, localoff, _, _, _ := Local.lookup(t.unixSec()); offset == localoff { - t.setLoc(Local) - } else { - t.setLoc(FixedZone("", offset)) - } - - return nil -} - -// TODO(rsc): Remove GobEncoder, GobDecoder, MarshalJSON, UnmarshalJSON in Go 2. -// The same semantics will be provided by the generic MarshalBinary, MarshalText, -// UnmarshalBinary, UnmarshalText. - -// GobEncode implements the gob.GobEncoder interface. -func (t Time) GobEncode() ([]byte, error) { - return t.MarshalBinary() -} - -// GobDecode implements the gob.GobDecoder interface. -func (t *Time) GobDecode(data []byte) error { - return t.UnmarshalBinary(data) -} - -// MarshalJSON implements the json.Marshaler interface. -// The time is a quoted string in the RFC 3339 format with sub-second precision. -// If the timestamp cannot be represented as valid RFC 3339 -// (e.g., the year is out of range), then an error is reported. -func (t Time) MarshalJSON() ([]byte, error) { - b := make([]byte, 0, len(RFC3339Nano)+len(`""`)) - b = append(b, '"') - b, err := t.appendStrictRFC3339(b) - b = append(b, '"') - if err != nil { - return nil, errors.New("Time.MarshalJSON: " + err.Error()) - } - return b, nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -// The time must be a quoted string in the RFC 3339 format. -func (t *Time) UnmarshalJSON(data []byte) error { - if string(data) == "null" { - return nil - } - // TODO(https://go.dev/issue/47353): Properly unescape a JSON string. - if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' { - return errors.New("Time.UnmarshalJSON: input is not a JSON string") - } - data = data[len(`"`) : len(data)-len(`"`)] - var err error - *t, err = parseStrictRFC3339(data) - return err -} - -// MarshalText implements the encoding.TextMarshaler interface. -// The time is formatted in RFC 3339 format with sub-second precision. -// If the timestamp cannot be represented as valid RFC 3339 -// (e.g., the year is out of range), then an error is reported. -func (t Time) MarshalText() ([]byte, error) { - b := make([]byte, 0, len(RFC3339Nano)) - b, err := t.appendStrictRFC3339(b) - if err != nil { - return nil, errors.New("Time.MarshalText: " + err.Error()) - } - return b, nil -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -// The time must be in the RFC 3339 format. -func (t *Time) UnmarshalText(data []byte) error { - var err error - *t, err = parseStrictRFC3339(data) - return err -} - -// Unix returns the local Time corresponding to the given Unix time, -// sec seconds and nsec nanoseconds since January 1, 1970 UTC. -// It is valid to pass nsec outside the range [0, 999999999]. -// Not all sec values have a corresponding time value. One such -// value is 1<<63-1 (the largest int64 value). -func Unix(sec int64, nsec int64) Time { - if nsec < 0 || nsec >= 1e9 { - n := nsec / 1e9 - sec += n - nsec -= n * 1e9 - if nsec < 0 { - nsec += 1e9 - sec-- - } - } - return unixTime(sec, int32(nsec)) -} - -// UnixMilli returns the local Time corresponding to the given Unix time, -// msec milliseconds since January 1, 1970 UTC. -func UnixMilli(msec int64) Time { - return Unix(msec/1e3, (msec%1e3)*1e6) -} - -// UnixMicro returns the local Time corresponding to the given Unix time, -// usec microseconds since January 1, 1970 UTC. -func UnixMicro(usec int64) Time { - return Unix(usec/1e6, (usec%1e6)*1e3) -} - -// IsDST reports whether the time in the configured location is in Daylight Savings Time. -func (t Time) IsDST() bool { - _, _, _, _, isDST := t.loc.lookup(t.Unix()) - return isDST -} - -func isLeap(year int) bool { - return year%4 == 0 && (year%100 != 0 || year%400 == 0) -} - -// norm returns nhi, nlo such that -// -// hi * base + lo == nhi * base + nlo -// 0 <= nlo < base -func norm(hi, lo, base int) (nhi, nlo int) { - if lo < 0 { - n := (-lo-1)/base + 1 - hi -= n - lo += n * base - } - if lo >= base { - n := lo / base - hi += n - lo -= n * base - } - return hi, lo -} - -// Date returns the Time corresponding to -// -// yyyy-mm-dd hh:mm:ss + nsec nanoseconds -// -// in the appropriate zone for that time in the given location. -// -// The month, day, hour, min, sec, and nsec values may be outside -// their usual ranges and will be normalized during the conversion. -// For example, October 32 converts to November 1. -// -// A daylight savings time transition skips or repeats times. -// For example, in the United States, March 13, 2011 2:15am never occurred, -// while November 6, 2011 1:15am occurred twice. In such cases, the -// choice of time zone, and therefore the time, is not well-defined. -// Date returns a time that is correct in one of the two zones involved -// in the transition, but it does not guarantee which. -// -// Date panics if loc is nil. -func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time { - if loc == nil { - panic("time: missing Location in call to Date") - } - - // Normalize month, overflowing into year. - m := int(month) - 1 - year, m = norm(year, m, 12) - month = Month(m) + 1 - - // Normalize nsec, sec, min, hour, overflowing into day. - sec, nsec = norm(sec, nsec, 1e9) - min, sec = norm(min, sec, 60) - hour, min = norm(hour, min, 60) - day, hour = norm(day, hour, 24) - - // Compute days since the absolute epoch. - d := daysSinceEpoch(year) - - // Add in days before this month. - d += uint64(daysBefore[month-1]) - if isLeap(year) && month >= March { - d++ // February 29 - } - - // Add in days before today. - d += uint64(day - 1) - - // Add in time elapsed today. - abs := d * secondsPerDay - abs += uint64(hour*secondsPerHour + min*secondsPerMinute + sec) - - unix := int64(abs) + (absoluteToInternal + internalToUnix) - - // Look for zone offset for expected time, so we can adjust to UTC. - // The lookup function expects UTC, so first we pass unix in the - // hope that it will not be too close to a zone transition, - // and then adjust if it is. - _, offset, start, end, _ := loc.lookup(unix) - if offset != 0 { - utc := unix - int64(offset) - // If utc is valid for the time zone we found, then we have the right offset. - // If not, we get the correct offset by looking up utc in the location. - if utc < start || utc >= end { - _, offset, _, _, _ = loc.lookup(utc) - } - unix -= int64(offset) - } - - t := unixTime(unix, int32(nsec)) - t.setLoc(loc) - return t -} - -// Truncate returns the result of rounding t down to a multiple of d (since the zero time). -// If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged. -// -// Truncate operates on the time as an absolute duration since the -// zero time; it does not operate on the presentation form of the -// time. Thus, Truncate(Hour) may return a time with a non-zero -// minute, depending on the time's Location. -func (t Time) Truncate(d Duration) Time { - t.stripMono() - if d <= 0 { - return t - } - _, r := div(t, d) - return t.Add(-r) -} - -// Round returns the result of rounding t to the nearest multiple of d (since the zero time). -// The rounding behavior for halfway values is to round up. -// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged. -// -// Round operates on the time as an absolute duration since the -// zero time; it does not operate on the presentation form of the -// time. Thus, Round(Hour) may return a time with a non-zero -// minute, depending on the time's Location. -func (t Time) Round(d Duration) Time { - t.stripMono() - if d <= 0 { - return t - } - _, r := div(t, d) - if lessThanHalf(r, d) { - return t.Add(-r) - } - return t.Add(d - r) -} - -// div divides t by d and returns the quotient parity and remainder. -// We don't use the quotient parity anymore (round half up instead of round to even) -// but it's still here in case we change our minds. -func div(t Time, d Duration) (qmod2 int, r Duration) { - neg := false - nsec := t.nsec() - sec := t.sec() - if sec < 0 { - // Operate on absolute value. - neg = true - sec = -sec - nsec = -nsec - if nsec < 0 { - nsec += 1e9 - sec-- // sec >= 1 before the -- so safe - } - } - - switch { - // Special case: 2d divides 1 second. - case d < Second && Second%(d+d) == 0: - qmod2 = int(nsec/int32(d)) & 1 - r = Duration(nsec % int32(d)) - - // Special case: d is a multiple of 1 second. - case d%Second == 0: - d1 := int64(d / Second) - qmod2 = int(sec/d1) & 1 - r = Duration(sec%d1)*Second + Duration(nsec) - - // General case. - // This could be faster if more cleverness were applied, - // but it's really only here to avoid special case restrictions in the API. - // No one will care about these cases. - default: - // Compute nanoseconds as 128-bit number. - sec := uint64(sec) - tmp := (sec >> 32) * 1e9 - u1 := tmp >> 32 - u0 := tmp << 32 - tmp = (sec & 0xFFFFFFFF) * 1e9 - u0x, u0 := u0, u0+tmp - if u0 < u0x { - u1++ - } - u0x, u0 = u0, u0+uint64(nsec) - if u0 < u0x { - u1++ - } - - // Compute remainder by subtracting r<>63 != 1 { - d1 <<= 1 - } - d0 := uint64(0) - for { - qmod2 = 0 - if u1 > d1 || u1 == d1 && u0 >= d0 { - // subtract - qmod2 = 1 - u0x, u0 = u0, u0-d0 - if u0 > u0x { - u1-- - } - u1 -= d1 - } - if d1 == 0 && d0 == uint64(d) { - break - } - d0 >>= 1 - d0 |= (d1 & 1) << 63 - d1 >>= 1 - } - r = Duration(u0) - } - - if neg && r != 0 { - // If input was negative and not an exact multiple of d, we computed q, r such that - // q*d + r = -t - // But the right answers are given by -(q-1), d-r: - // q*d + r = -t - // -q*d - r = t - // -(q-1)*d + (d - r) = t - qmod2 ^= 1 - r = d - r - } - return -} diff --git a/contrib/go/_std_1.22/src/time/ya.make b/contrib/go/_std_1.22/src/time/ya.make deleted file mode 100644 index fe9a540f5637..000000000000 --- a/contrib/go/_std_1.22/src/time/ya.make +++ /dev/null @@ -1,30 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - format.go - format_rfc3339.go - sleep.go - sys_unix.go - tick.go - time.go - zoneinfo.go - zoneinfo_goroot.go - zoneinfo_read.go - zoneinfo_unix.go - ) -ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - format.go - format_rfc3339.go - sleep.go - sys_windows.go - tick.go - time.go - zoneinfo.go - zoneinfo_abbrs_windows.go - zoneinfo_goroot.go - zoneinfo_read.go - zoneinfo_windows.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/ya.make b/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/ya.make deleted file mode 100644 index da2ccef32bbd..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/ya.make +++ /dev/null @@ -1,16 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - chacha_arm64.go - chacha_arm64.s - chacha_generic.go - xor.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - chacha_generic.go - chacha_noasm.go - xor.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make b/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make deleted file mode 100644 index aa4c7da61a48..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make +++ /dev/null @@ -1,18 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - chacha20poly1305.go - chacha20poly1305_generic.go - chacha20poly1305_noasm.go - xchacha20poly1305.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - chacha20poly1305.go - chacha20poly1305_amd64.go - chacha20poly1305_amd64.s - chacha20poly1305_generic.go - xchacha20poly1305.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go b/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go deleted file mode 100644 index d33c8890fc53..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.13 - -package poly1305 - -// Generic fallbacks for the math/bits intrinsics, copied from -// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had -// variable time fallbacks until Go 1.13. - -func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { - sum = x + y + carry - carryOut = ((x & y) | ((x | y) &^ sum)) >> 63 - return -} - -func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { - diff = x - y - borrow - borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 - return -} - -func bitsMul64(x, y uint64) (hi, lo uint64) { - const mask32 = 1<<32 - 1 - x0 := x & mask32 - x1 := x >> 32 - y0 := y & mask32 - y1 := y >> 32 - w0 := x0 * y0 - t := x1*y0 + w0>>32 - w1 := t & mask32 - w2 := t >> 32 - w1 += x0 * y1 - hi = x1*y1 + w2 + w1>>32 - lo = x * y - return -} diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go b/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go deleted file mode 100644 index 495c1fa69725..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.13 - -package poly1305 - -import "math/bits" - -func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { - return bits.Add64(x, y, carry) -} - -func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { - return bits.Sub64(x, y, borrow) -} - -func bitsMul64(x, y uint64) (hi, lo uint64) { - return bits.Mul64(x, y) -} diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make b/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make deleted file mode 100644 index 431e8ade99c7..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make +++ /dev/null @@ -1,18 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - bits_go1.13.go - mac_noasm.go - poly1305.go - sum_generic.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - bits_go1.13.go - poly1305.go - sum_amd64.go - sum_amd64.s - sum_generic.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/message.go b/contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/message.go deleted file mode 100644 index 42987ab7c5fe..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/message.go +++ /dev/null @@ -1,2720 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package dnsmessage provides a mostly RFC 1035 compliant implementation of -// DNS message packing and unpacking. -// -// The package also supports messages with Extension Mechanisms for DNS -// (EDNS(0)) as defined in RFC 6891. -// -// This implementation is designed to minimize heap allocations and avoid -// unnecessary packing and unpacking as much as possible. -package dnsmessage - -import ( - "errors" -) - -// Message formats - -// A Type is a type of DNS request and response. -type Type uint16 - -const ( - // ResourceHeader.Type and Question.Type - TypeA Type = 1 - TypeNS Type = 2 - TypeCNAME Type = 5 - TypeSOA Type = 6 - TypePTR Type = 12 - TypeMX Type = 15 - TypeTXT Type = 16 - TypeAAAA Type = 28 - TypeSRV Type = 33 - TypeOPT Type = 41 - - // Question.Type - TypeWKS Type = 11 - TypeHINFO Type = 13 - TypeMINFO Type = 14 - TypeAXFR Type = 252 - TypeALL Type = 255 -) - -var typeNames = map[Type]string{ - TypeA: "TypeA", - TypeNS: "TypeNS", - TypeCNAME: "TypeCNAME", - TypeSOA: "TypeSOA", - TypePTR: "TypePTR", - TypeMX: "TypeMX", - TypeTXT: "TypeTXT", - TypeAAAA: "TypeAAAA", - TypeSRV: "TypeSRV", - TypeOPT: "TypeOPT", - TypeWKS: "TypeWKS", - TypeHINFO: "TypeHINFO", - TypeMINFO: "TypeMINFO", - TypeAXFR: "TypeAXFR", - TypeALL: "TypeALL", -} - -// String implements fmt.Stringer.String. -func (t Type) String() string { - if n, ok := typeNames[t]; ok { - return n - } - return printUint16(uint16(t)) -} - -// GoString implements fmt.GoStringer.GoString. -func (t Type) GoString() string { - if n, ok := typeNames[t]; ok { - return "dnsmessage." + n - } - return printUint16(uint16(t)) -} - -// A Class is a type of network. -type Class uint16 - -const ( - // ResourceHeader.Class and Question.Class - ClassINET Class = 1 - ClassCSNET Class = 2 - ClassCHAOS Class = 3 - ClassHESIOD Class = 4 - - // Question.Class - ClassANY Class = 255 -) - -var classNames = map[Class]string{ - ClassINET: "ClassINET", - ClassCSNET: "ClassCSNET", - ClassCHAOS: "ClassCHAOS", - ClassHESIOD: "ClassHESIOD", - ClassANY: "ClassANY", -} - -// String implements fmt.Stringer.String. -func (c Class) String() string { - if n, ok := classNames[c]; ok { - return n - } - return printUint16(uint16(c)) -} - -// GoString implements fmt.GoStringer.GoString. -func (c Class) GoString() string { - if n, ok := classNames[c]; ok { - return "dnsmessage." + n - } - return printUint16(uint16(c)) -} - -// An OpCode is a DNS operation code. -type OpCode uint16 - -// GoString implements fmt.GoStringer.GoString. -func (o OpCode) GoString() string { - return printUint16(uint16(o)) -} - -// An RCode is a DNS response status code. -type RCode uint16 - -// Header.RCode values. -const ( - RCodeSuccess RCode = 0 // NoError - RCodeFormatError RCode = 1 // FormErr - RCodeServerFailure RCode = 2 // ServFail - RCodeNameError RCode = 3 // NXDomain - RCodeNotImplemented RCode = 4 // NotImp - RCodeRefused RCode = 5 // Refused -) - -var rCodeNames = map[RCode]string{ - RCodeSuccess: "RCodeSuccess", - RCodeFormatError: "RCodeFormatError", - RCodeServerFailure: "RCodeServerFailure", - RCodeNameError: "RCodeNameError", - RCodeNotImplemented: "RCodeNotImplemented", - RCodeRefused: "RCodeRefused", -} - -// String implements fmt.Stringer.String. -func (r RCode) String() string { - if n, ok := rCodeNames[r]; ok { - return n - } - return printUint16(uint16(r)) -} - -// GoString implements fmt.GoStringer.GoString. -func (r RCode) GoString() string { - if n, ok := rCodeNames[r]; ok { - return "dnsmessage." + n - } - return printUint16(uint16(r)) -} - -func printPaddedUint8(i uint8) string { - b := byte(i) - return string([]byte{ - b/100 + '0', - b/10%10 + '0', - b%10 + '0', - }) -} - -func printUint8Bytes(buf []byte, i uint8) []byte { - b := byte(i) - if i >= 100 { - buf = append(buf, b/100+'0') - } - if i >= 10 { - buf = append(buf, b/10%10+'0') - } - return append(buf, b%10+'0') -} - -func printByteSlice(b []byte) string { - if len(b) == 0 { - return "" - } - buf := make([]byte, 0, 5*len(b)) - buf = printUint8Bytes(buf, uint8(b[0])) - for _, n := range b[1:] { - buf = append(buf, ',', ' ') - buf = printUint8Bytes(buf, uint8(n)) - } - return string(buf) -} - -const hexDigits = "0123456789abcdef" - -func printString(str []byte) string { - buf := make([]byte, 0, len(str)) - for i := 0; i < len(str); i++ { - c := str[i] - if c == '.' || c == '-' || c == ' ' || - 'A' <= c && c <= 'Z' || - 'a' <= c && c <= 'z' || - '0' <= c && c <= '9' { - buf = append(buf, c) - continue - } - - upper := c >> 4 - lower := (c << 4) >> 4 - buf = append( - buf, - '\\', - 'x', - hexDigits[upper], - hexDigits[lower], - ) - } - return string(buf) -} - -func printUint16(i uint16) string { - return printUint32(uint32(i)) -} - -func printUint32(i uint32) string { - // Max value is 4294967295. - buf := make([]byte, 10) - for b, d := buf, uint32(1000000000); d > 0; d /= 10 { - b[0] = byte(i/d%10 + '0') - if b[0] == '0' && len(b) == len(buf) && len(buf) > 1 { - buf = buf[1:] - } - b = b[1:] - i %= d - } - return string(buf) -} - -func printBool(b bool) string { - if b { - return "true" - } - return "false" -} - -var ( - // ErrNotStarted indicates that the prerequisite information isn't - // available yet because the previous records haven't been appropriately - // parsed, skipped or finished. - ErrNotStarted = errors.New("parsing/packing of this type isn't available yet") - - // ErrSectionDone indicated that all records in the section have been - // parsed or finished. - ErrSectionDone = errors.New("parsing/packing of this section has completed") - - errBaseLen = errors.New("insufficient data for base length type") - errCalcLen = errors.New("insufficient data for calculated length type") - errReserved = errors.New("segment prefix is reserved") - errTooManyPtr = errors.New("too many pointers (>10)") - errInvalidPtr = errors.New("invalid pointer") - errInvalidName = errors.New("invalid dns name") - errNilResouceBody = errors.New("nil resource body") - errResourceLen = errors.New("insufficient data for resource body length") - errSegTooLong = errors.New("segment length too long") - errNameTooLong = errors.New("name too long") - errZeroSegLen = errors.New("zero length segment") - errResTooLong = errors.New("resource length too long") - errTooManyQuestions = errors.New("too many Questions to pack (>65535)") - errTooManyAnswers = errors.New("too many Answers to pack (>65535)") - errTooManyAuthorities = errors.New("too many Authorities to pack (>65535)") - errTooManyAdditionals = errors.New("too many Additionals to pack (>65535)") - errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)") - errStringTooLong = errors.New("character string exceeds maximum length (255)") - errCompressedSRV = errors.New("compressed name in SRV resource data") -) - -// Internal constants. -const ( - // packStartingCap is the default initial buffer size allocated during - // packing. - // - // The starting capacity doesn't matter too much, but most DNS responses - // Will be <= 512 bytes as it is the limit for DNS over UDP. - packStartingCap = 512 - - // uint16Len is the length (in bytes) of a uint16. - uint16Len = 2 - - // uint32Len is the length (in bytes) of a uint32. - uint32Len = 4 - - // headerLen is the length (in bytes) of a DNS header. - // - // A header is comprised of 6 uint16s and no padding. - headerLen = 6 * uint16Len -) - -type nestedError struct { - // s is the current level's error message. - s string - - // err is the nested error. - err error -} - -// nestedError implements error.Error. -func (e *nestedError) Error() string { - return e.s + ": " + e.err.Error() -} - -// Header is a representation of a DNS message header. -type Header struct { - ID uint16 - Response bool - OpCode OpCode - Authoritative bool - Truncated bool - RecursionDesired bool - RecursionAvailable bool - AuthenticData bool - CheckingDisabled bool - RCode RCode -} - -func (m *Header) pack() (id uint16, bits uint16) { - id = m.ID - bits = uint16(m.OpCode)<<11 | uint16(m.RCode) - if m.RecursionAvailable { - bits |= headerBitRA - } - if m.RecursionDesired { - bits |= headerBitRD - } - if m.Truncated { - bits |= headerBitTC - } - if m.Authoritative { - bits |= headerBitAA - } - if m.Response { - bits |= headerBitQR - } - if m.AuthenticData { - bits |= headerBitAD - } - if m.CheckingDisabled { - bits |= headerBitCD - } - return -} - -// GoString implements fmt.GoStringer.GoString. -func (m *Header) GoString() string { - return "dnsmessage.Header{" + - "ID: " + printUint16(m.ID) + ", " + - "Response: " + printBool(m.Response) + ", " + - "OpCode: " + m.OpCode.GoString() + ", " + - "Authoritative: " + printBool(m.Authoritative) + ", " + - "Truncated: " + printBool(m.Truncated) + ", " + - "RecursionDesired: " + printBool(m.RecursionDesired) + ", " + - "RecursionAvailable: " + printBool(m.RecursionAvailable) + ", " + - "AuthenticData: " + printBool(m.AuthenticData) + ", " + - "CheckingDisabled: " + printBool(m.CheckingDisabled) + ", " + - "RCode: " + m.RCode.GoString() + "}" -} - -// Message is a representation of a DNS message. -type Message struct { - Header - Questions []Question - Answers []Resource - Authorities []Resource - Additionals []Resource -} - -type section uint8 - -const ( - sectionNotStarted section = iota - sectionHeader - sectionQuestions - sectionAnswers - sectionAuthorities - sectionAdditionals - sectionDone - - headerBitQR = 1 << 15 // query/response (response=1) - headerBitAA = 1 << 10 // authoritative - headerBitTC = 1 << 9 // truncated - headerBitRD = 1 << 8 // recursion desired - headerBitRA = 1 << 7 // recursion available - headerBitAD = 1 << 5 // authentic data - headerBitCD = 1 << 4 // checking disabled -) - -var sectionNames = map[section]string{ - sectionHeader: "header", - sectionQuestions: "Question", - sectionAnswers: "Answer", - sectionAuthorities: "Authority", - sectionAdditionals: "Additional", -} - -// header is the wire format for a DNS message header. -type header struct { - id uint16 - bits uint16 - questions uint16 - answers uint16 - authorities uint16 - additionals uint16 -} - -func (h *header) count(sec section) uint16 { - switch sec { - case sectionQuestions: - return h.questions - case sectionAnswers: - return h.answers - case sectionAuthorities: - return h.authorities - case sectionAdditionals: - return h.additionals - } - return 0 -} - -// pack appends the wire format of the header to msg. -func (h *header) pack(msg []byte) []byte { - msg = packUint16(msg, h.id) - msg = packUint16(msg, h.bits) - msg = packUint16(msg, h.questions) - msg = packUint16(msg, h.answers) - msg = packUint16(msg, h.authorities) - return packUint16(msg, h.additionals) -} - -func (h *header) unpack(msg []byte, off int) (int, error) { - newOff := off - var err error - if h.id, newOff, err = unpackUint16(msg, newOff); err != nil { - return off, &nestedError{"id", err} - } - if h.bits, newOff, err = unpackUint16(msg, newOff); err != nil { - return off, &nestedError{"bits", err} - } - if h.questions, newOff, err = unpackUint16(msg, newOff); err != nil { - return off, &nestedError{"questions", err} - } - if h.answers, newOff, err = unpackUint16(msg, newOff); err != nil { - return off, &nestedError{"answers", err} - } - if h.authorities, newOff, err = unpackUint16(msg, newOff); err != nil { - return off, &nestedError{"authorities", err} - } - if h.additionals, newOff, err = unpackUint16(msg, newOff); err != nil { - return off, &nestedError{"additionals", err} - } - return newOff, nil -} - -func (h *header) header() Header { - return Header{ - ID: h.id, - Response: (h.bits & headerBitQR) != 0, - OpCode: OpCode(h.bits>>11) & 0xF, - Authoritative: (h.bits & headerBitAA) != 0, - Truncated: (h.bits & headerBitTC) != 0, - RecursionDesired: (h.bits & headerBitRD) != 0, - RecursionAvailable: (h.bits & headerBitRA) != 0, - AuthenticData: (h.bits & headerBitAD) != 0, - CheckingDisabled: (h.bits & headerBitCD) != 0, - RCode: RCode(h.bits & 0xF), - } -} - -// A Resource is a DNS resource record. -type Resource struct { - Header ResourceHeader - Body ResourceBody -} - -func (r *Resource) GoString() string { - return "dnsmessage.Resource{" + - "Header: " + r.Header.GoString() + - ", Body: &" + r.Body.GoString() + - "}" -} - -// A ResourceBody is a DNS resource record minus the header. -type ResourceBody interface { - // pack packs a Resource except for its header. - pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) - - // realType returns the actual type of the Resource. This is used to - // fill in the header Type field. - realType() Type - - // GoString implements fmt.GoStringer.GoString. - GoString() string -} - -// pack appends the wire format of the Resource to msg. -func (r *Resource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - if r.Body == nil { - return msg, errNilResouceBody - } - oldMsg := msg - r.Header.Type = r.Body.realType() - msg, lenOff, err := r.Header.pack(msg, compression, compressionOff) - if err != nil { - return msg, &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - msg, err = r.Body.pack(msg, compression, compressionOff) - if err != nil { - return msg, &nestedError{"content", err} - } - if err := r.Header.fixLen(msg, lenOff, preLen); err != nil { - return oldMsg, err - } - return msg, nil -} - -// A Parser allows incrementally parsing a DNS message. -// -// When parsing is started, the Header is parsed. Next, each Question can be -// either parsed or skipped. Alternatively, all Questions can be skipped at -// once. When all Questions have been parsed, attempting to parse Questions -// will return the [ErrSectionDone] error. -// After all Questions have been either parsed or skipped, all -// Answers, Authorities and Additionals can be either parsed or skipped in the -// same way, and each type of Resource must be fully parsed or skipped before -// proceeding to the next type of Resource. -// -// Parser is safe to copy to preserve the parsing state. -// -// Note that there is no requirement to fully skip or parse the message. -type Parser struct { - msg []byte - header header - - section section - off int - index int - resHeaderValid bool - resHeaderOffset int - resHeaderType Type - resHeaderLength uint16 -} - -// Start parses the header and enables the parsing of Questions. -func (p *Parser) Start(msg []byte) (Header, error) { - if p.msg != nil { - *p = Parser{} - } - p.msg = msg - var err error - if p.off, err = p.header.unpack(msg, 0); err != nil { - return Header{}, &nestedError{"unpacking header", err} - } - p.section = sectionQuestions - return p.header.header(), nil -} - -func (p *Parser) checkAdvance(sec section) error { - if p.section < sec { - return ErrNotStarted - } - if p.section > sec { - return ErrSectionDone - } - p.resHeaderValid = false - if p.index == int(p.header.count(sec)) { - p.index = 0 - p.section++ - return ErrSectionDone - } - return nil -} - -func (p *Parser) resource(sec section) (Resource, error) { - var r Resource - var err error - r.Header, err = p.resourceHeader(sec) - if err != nil { - return r, err - } - p.resHeaderValid = false - r.Body, p.off, err = unpackResourceBody(p.msg, p.off, r.Header) - if err != nil { - return Resource{}, &nestedError{"unpacking " + sectionNames[sec], err} - } - p.index++ - return r, nil -} - -func (p *Parser) resourceHeader(sec section) (ResourceHeader, error) { - if p.resHeaderValid { - p.off = p.resHeaderOffset - } - - if err := p.checkAdvance(sec); err != nil { - return ResourceHeader{}, err - } - var hdr ResourceHeader - off, err := hdr.unpack(p.msg, p.off) - if err != nil { - return ResourceHeader{}, err - } - p.resHeaderValid = true - p.resHeaderOffset = p.off - p.resHeaderType = hdr.Type - p.resHeaderLength = hdr.Length - p.off = off - return hdr, nil -} - -func (p *Parser) skipResource(sec section) error { - if p.resHeaderValid && p.section == sec { - newOff := p.off + int(p.resHeaderLength) - if newOff > len(p.msg) { - return errResourceLen - } - p.off = newOff - p.resHeaderValid = false - p.index++ - return nil - } - if err := p.checkAdvance(sec); err != nil { - return err - } - var err error - p.off, err = skipResource(p.msg, p.off) - if err != nil { - return &nestedError{"skipping: " + sectionNames[sec], err} - } - p.index++ - return nil -} - -// Question parses a single Question. -func (p *Parser) Question() (Question, error) { - if err := p.checkAdvance(sectionQuestions); err != nil { - return Question{}, err - } - var name Name - off, err := name.unpack(p.msg, p.off) - if err != nil { - return Question{}, &nestedError{"unpacking Question.Name", err} - } - typ, off, err := unpackType(p.msg, off) - if err != nil { - return Question{}, &nestedError{"unpacking Question.Type", err} - } - class, off, err := unpackClass(p.msg, off) - if err != nil { - return Question{}, &nestedError{"unpacking Question.Class", err} - } - p.off = off - p.index++ - return Question{name, typ, class}, nil -} - -// AllQuestions parses all Questions. -func (p *Parser) AllQuestions() ([]Question, error) { - // Multiple questions are valid according to the spec, - // but servers don't actually support them. There will - // be at most one question here. - // - // Do not pre-allocate based on info in p.header, since - // the data is untrusted. - qs := []Question{} - for { - q, err := p.Question() - if err == ErrSectionDone { - return qs, nil - } - if err != nil { - return nil, err - } - qs = append(qs, q) - } -} - -// SkipQuestion skips a single Question. -func (p *Parser) SkipQuestion() error { - if err := p.checkAdvance(sectionQuestions); err != nil { - return err - } - off, err := skipName(p.msg, p.off) - if err != nil { - return &nestedError{"skipping Question Name", err} - } - if off, err = skipType(p.msg, off); err != nil { - return &nestedError{"skipping Question Type", err} - } - if off, err = skipClass(p.msg, off); err != nil { - return &nestedError{"skipping Question Class", err} - } - p.off = off - p.index++ - return nil -} - -// SkipAllQuestions skips all Questions. -func (p *Parser) SkipAllQuestions() error { - for { - if err := p.SkipQuestion(); err == ErrSectionDone { - return nil - } else if err != nil { - return err - } - } -} - -// AnswerHeader parses a single Answer ResourceHeader. -func (p *Parser) AnswerHeader() (ResourceHeader, error) { - return p.resourceHeader(sectionAnswers) -} - -// Answer parses a single Answer Resource. -func (p *Parser) Answer() (Resource, error) { - return p.resource(sectionAnswers) -} - -// AllAnswers parses all Answer Resources. -func (p *Parser) AllAnswers() ([]Resource, error) { - // The most common query is for A/AAAA, which usually returns - // a handful of IPs. - // - // Pre-allocate up to a certain limit, since p.header is - // untrusted data. - n := int(p.header.answers) - if n > 20 { - n = 20 - } - as := make([]Resource, 0, n) - for { - a, err := p.Answer() - if err == ErrSectionDone { - return as, nil - } - if err != nil { - return nil, err - } - as = append(as, a) - } -} - -// SkipAnswer skips a single Answer Resource. -// -// It does not perform a complete validation of the resource header, which means -// it may return a nil error when the [AnswerHeader] would actually return an error. -func (p *Parser) SkipAnswer() error { - return p.skipResource(sectionAnswers) -} - -// SkipAllAnswers skips all Answer Resources. -func (p *Parser) SkipAllAnswers() error { - for { - if err := p.SkipAnswer(); err == ErrSectionDone { - return nil - } else if err != nil { - return err - } - } -} - -// AuthorityHeader parses a single Authority ResourceHeader. -func (p *Parser) AuthorityHeader() (ResourceHeader, error) { - return p.resourceHeader(sectionAuthorities) -} - -// Authority parses a single Authority Resource. -func (p *Parser) Authority() (Resource, error) { - return p.resource(sectionAuthorities) -} - -// AllAuthorities parses all Authority Resources. -func (p *Parser) AllAuthorities() ([]Resource, error) { - // Authorities contains SOA in case of NXDOMAIN and friends, - // otherwise it is empty. - // - // Pre-allocate up to a certain limit, since p.header is - // untrusted data. - n := int(p.header.authorities) - if n > 10 { - n = 10 - } - as := make([]Resource, 0, n) - for { - a, err := p.Authority() - if err == ErrSectionDone { - return as, nil - } - if err != nil { - return nil, err - } - as = append(as, a) - } -} - -// SkipAuthority skips a single Authority Resource. -// -// It does not perform a complete validation of the resource header, which means -// it may return a nil error when the [AuthorityHeader] would actually return an error. -func (p *Parser) SkipAuthority() error { - return p.skipResource(sectionAuthorities) -} - -// SkipAllAuthorities skips all Authority Resources. -func (p *Parser) SkipAllAuthorities() error { - for { - if err := p.SkipAuthority(); err == ErrSectionDone { - return nil - } else if err != nil { - return err - } - } -} - -// AdditionalHeader parses a single Additional ResourceHeader. -func (p *Parser) AdditionalHeader() (ResourceHeader, error) { - return p.resourceHeader(sectionAdditionals) -} - -// Additional parses a single Additional Resource. -func (p *Parser) Additional() (Resource, error) { - return p.resource(sectionAdditionals) -} - -// AllAdditionals parses all Additional Resources. -func (p *Parser) AllAdditionals() ([]Resource, error) { - // Additionals usually contain OPT, and sometimes A/AAAA - // glue records. - // - // Pre-allocate up to a certain limit, since p.header is - // untrusted data. - n := int(p.header.additionals) - if n > 10 { - n = 10 - } - as := make([]Resource, 0, n) - for { - a, err := p.Additional() - if err == ErrSectionDone { - return as, nil - } - if err != nil { - return nil, err - } - as = append(as, a) - } -} - -// SkipAdditional skips a single Additional Resource. -// -// It does not perform a complete validation of the resource header, which means -// it may return a nil error when the [AdditionalHeader] would actually return an error. -func (p *Parser) SkipAdditional() error { - return p.skipResource(sectionAdditionals) -} - -// SkipAllAdditionals skips all Additional Resources. -func (p *Parser) SkipAllAdditionals() error { - for { - if err := p.SkipAdditional(); err == ErrSectionDone { - return nil - } else if err != nil { - return err - } - } -} - -// CNAMEResource parses a single CNAMEResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) CNAMEResource() (CNAMEResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypeCNAME { - return CNAMEResource{}, ErrNotStarted - } - r, err := unpackCNAMEResource(p.msg, p.off) - if err != nil { - return CNAMEResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// MXResource parses a single MXResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) MXResource() (MXResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypeMX { - return MXResource{}, ErrNotStarted - } - r, err := unpackMXResource(p.msg, p.off) - if err != nil { - return MXResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// NSResource parses a single NSResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) NSResource() (NSResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypeNS { - return NSResource{}, ErrNotStarted - } - r, err := unpackNSResource(p.msg, p.off) - if err != nil { - return NSResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// PTRResource parses a single PTRResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) PTRResource() (PTRResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypePTR { - return PTRResource{}, ErrNotStarted - } - r, err := unpackPTRResource(p.msg, p.off) - if err != nil { - return PTRResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// SOAResource parses a single SOAResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) SOAResource() (SOAResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypeSOA { - return SOAResource{}, ErrNotStarted - } - r, err := unpackSOAResource(p.msg, p.off) - if err != nil { - return SOAResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// TXTResource parses a single TXTResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) TXTResource() (TXTResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypeTXT { - return TXTResource{}, ErrNotStarted - } - r, err := unpackTXTResource(p.msg, p.off, p.resHeaderLength) - if err != nil { - return TXTResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// SRVResource parses a single SRVResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) SRVResource() (SRVResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypeSRV { - return SRVResource{}, ErrNotStarted - } - r, err := unpackSRVResource(p.msg, p.off) - if err != nil { - return SRVResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// AResource parses a single AResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) AResource() (AResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypeA { - return AResource{}, ErrNotStarted - } - r, err := unpackAResource(p.msg, p.off) - if err != nil { - return AResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// AAAAResource parses a single AAAAResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) AAAAResource() (AAAAResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypeAAAA { - return AAAAResource{}, ErrNotStarted - } - r, err := unpackAAAAResource(p.msg, p.off) - if err != nil { - return AAAAResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// OPTResource parses a single OPTResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) OPTResource() (OPTResource, error) { - if !p.resHeaderValid || p.resHeaderType != TypeOPT { - return OPTResource{}, ErrNotStarted - } - r, err := unpackOPTResource(p.msg, p.off, p.resHeaderLength) - if err != nil { - return OPTResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// UnknownResource parses a single UnknownResource. -// -// One of the XXXHeader methods must have been called before calling this -// method. -func (p *Parser) UnknownResource() (UnknownResource, error) { - if !p.resHeaderValid { - return UnknownResource{}, ErrNotStarted - } - r, err := unpackUnknownResource(p.resHeaderType, p.msg, p.off, p.resHeaderLength) - if err != nil { - return UnknownResource{}, err - } - p.off += int(p.resHeaderLength) - p.resHeaderValid = false - p.index++ - return r, nil -} - -// Unpack parses a full Message. -func (m *Message) Unpack(msg []byte) error { - var p Parser - var err error - if m.Header, err = p.Start(msg); err != nil { - return err - } - if m.Questions, err = p.AllQuestions(); err != nil { - return err - } - if m.Answers, err = p.AllAnswers(); err != nil { - return err - } - if m.Authorities, err = p.AllAuthorities(); err != nil { - return err - } - if m.Additionals, err = p.AllAdditionals(); err != nil { - return err - } - return nil -} - -// Pack packs a full Message. -func (m *Message) Pack() ([]byte, error) { - return m.AppendPack(make([]byte, 0, packStartingCap)) -} - -// AppendPack is like Pack but appends the full Message to b and returns the -// extended buffer. -func (m *Message) AppendPack(b []byte) ([]byte, error) { - // Validate the lengths. It is very unlikely that anyone will try to - // pack more than 65535 of any particular type, but it is possible and - // we should fail gracefully. - if len(m.Questions) > int(^uint16(0)) { - return nil, errTooManyQuestions - } - if len(m.Answers) > int(^uint16(0)) { - return nil, errTooManyAnswers - } - if len(m.Authorities) > int(^uint16(0)) { - return nil, errTooManyAuthorities - } - if len(m.Additionals) > int(^uint16(0)) { - return nil, errTooManyAdditionals - } - - var h header - h.id, h.bits = m.Header.pack() - - h.questions = uint16(len(m.Questions)) - h.answers = uint16(len(m.Answers)) - h.authorities = uint16(len(m.Authorities)) - h.additionals = uint16(len(m.Additionals)) - - compressionOff := len(b) - msg := h.pack(b) - - // RFC 1035 allows (but does not require) compression for packing. RFC - // 1035 requires unpacking implementations to support compression, so - // unconditionally enabling it is fine. - // - // DNS lookups are typically done over UDP, and RFC 1035 states that UDP - // DNS messages can be a maximum of 512 bytes long. Without compression, - // many DNS response messages are over this limit, so enabling - // compression will help ensure compliance. - compression := map[string]uint16{} - - for i := range m.Questions { - var err error - if msg, err = m.Questions[i].pack(msg, compression, compressionOff); err != nil { - return nil, &nestedError{"packing Question", err} - } - } - for i := range m.Answers { - var err error - if msg, err = m.Answers[i].pack(msg, compression, compressionOff); err != nil { - return nil, &nestedError{"packing Answer", err} - } - } - for i := range m.Authorities { - var err error - if msg, err = m.Authorities[i].pack(msg, compression, compressionOff); err != nil { - return nil, &nestedError{"packing Authority", err} - } - } - for i := range m.Additionals { - var err error - if msg, err = m.Additionals[i].pack(msg, compression, compressionOff); err != nil { - return nil, &nestedError{"packing Additional", err} - } - } - - return msg, nil -} - -// GoString implements fmt.GoStringer.GoString. -func (m *Message) GoString() string { - s := "dnsmessage.Message{Header: " + m.Header.GoString() + ", " + - "Questions: []dnsmessage.Question{" - if len(m.Questions) > 0 { - s += m.Questions[0].GoString() - for _, q := range m.Questions[1:] { - s += ", " + q.GoString() - } - } - s += "}, Answers: []dnsmessage.Resource{" - if len(m.Answers) > 0 { - s += m.Answers[0].GoString() - for _, a := range m.Answers[1:] { - s += ", " + a.GoString() - } - } - s += "}, Authorities: []dnsmessage.Resource{" - if len(m.Authorities) > 0 { - s += m.Authorities[0].GoString() - for _, a := range m.Authorities[1:] { - s += ", " + a.GoString() - } - } - s += "}, Additionals: []dnsmessage.Resource{" - if len(m.Additionals) > 0 { - s += m.Additionals[0].GoString() - for _, a := range m.Additionals[1:] { - s += ", " + a.GoString() - } - } - return s + "}}" -} - -// A Builder allows incrementally packing a DNS message. -// -// Example usage: -// -// buf := make([]byte, 2, 514) -// b := NewBuilder(buf, Header{...}) -// b.EnableCompression() -// // Optionally start a section and add things to that section. -// // Repeat adding sections as necessary. -// buf, err := b.Finish() -// // If err is nil, buf[2:] will contain the built bytes. -type Builder struct { - // msg is the storage for the message being built. - msg []byte - - // section keeps track of the current section being built. - section section - - // header keeps track of what should go in the header when Finish is - // called. - header header - - // start is the starting index of the bytes allocated in msg for header. - start int - - // compression is a mapping from name suffixes to their starting index - // in msg. - compression map[string]uint16 -} - -// NewBuilder creates a new builder with compression disabled. -// -// Note: Most users will want to immediately enable compression with the -// EnableCompression method. See that method's comment for why you may or may -// not want to enable compression. -// -// The DNS message is appended to the provided initial buffer buf (which may be -// nil) as it is built. The final message is returned by the (*Builder).Finish -// method, which includes buf[:len(buf)] and may return the same underlying -// array if there was sufficient capacity in the slice. -func NewBuilder(buf []byte, h Header) Builder { - if buf == nil { - buf = make([]byte, 0, packStartingCap) - } - b := Builder{msg: buf, start: len(buf)} - b.header.id, b.header.bits = h.pack() - var hb [headerLen]byte - b.msg = append(b.msg, hb[:]...) - b.section = sectionHeader - return b -} - -// EnableCompression enables compression in the Builder. -// -// Leaving compression disabled avoids compression related allocations, but can -// result in larger message sizes. Be careful with this mode as it can cause -// messages to exceed the UDP size limit. -// -// According to RFC 1035, section 4.1.4, the use of compression is optional, but -// all implementations must accept both compressed and uncompressed DNS -// messages. -// -// Compression should be enabled before any sections are added for best results. -func (b *Builder) EnableCompression() { - b.compression = map[string]uint16{} -} - -func (b *Builder) startCheck(s section) error { - if b.section <= sectionNotStarted { - return ErrNotStarted - } - if b.section > s { - return ErrSectionDone - } - return nil -} - -// StartQuestions prepares the builder for packing Questions. -func (b *Builder) StartQuestions() error { - if err := b.startCheck(sectionQuestions); err != nil { - return err - } - b.section = sectionQuestions - return nil -} - -// StartAnswers prepares the builder for packing Answers. -func (b *Builder) StartAnswers() error { - if err := b.startCheck(sectionAnswers); err != nil { - return err - } - b.section = sectionAnswers - return nil -} - -// StartAuthorities prepares the builder for packing Authorities. -func (b *Builder) StartAuthorities() error { - if err := b.startCheck(sectionAuthorities); err != nil { - return err - } - b.section = sectionAuthorities - return nil -} - -// StartAdditionals prepares the builder for packing Additionals. -func (b *Builder) StartAdditionals() error { - if err := b.startCheck(sectionAdditionals); err != nil { - return err - } - b.section = sectionAdditionals - return nil -} - -func (b *Builder) incrementSectionCount() error { - var count *uint16 - var err error - switch b.section { - case sectionQuestions: - count = &b.header.questions - err = errTooManyQuestions - case sectionAnswers: - count = &b.header.answers - err = errTooManyAnswers - case sectionAuthorities: - count = &b.header.authorities - err = errTooManyAuthorities - case sectionAdditionals: - count = &b.header.additionals - err = errTooManyAdditionals - } - if *count == ^uint16(0) { - return err - } - *count++ - return nil -} - -// Question adds a single Question. -func (b *Builder) Question(q Question) error { - if b.section < sectionQuestions { - return ErrNotStarted - } - if b.section > sectionQuestions { - return ErrSectionDone - } - msg, err := q.pack(b.msg, b.compression, b.start) - if err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -func (b *Builder) checkResourceSection() error { - if b.section < sectionAnswers { - return ErrNotStarted - } - if b.section > sectionAdditionals { - return ErrSectionDone - } - return nil -} - -// CNAMEResource adds a single CNAMEResource. -func (b *Builder) CNAMEResource(h ResourceHeader, r CNAMEResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"CNAMEResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// MXResource adds a single MXResource. -func (b *Builder) MXResource(h ResourceHeader, r MXResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"MXResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// NSResource adds a single NSResource. -func (b *Builder) NSResource(h ResourceHeader, r NSResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"NSResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// PTRResource adds a single PTRResource. -func (b *Builder) PTRResource(h ResourceHeader, r PTRResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"PTRResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// SOAResource adds a single SOAResource. -func (b *Builder) SOAResource(h ResourceHeader, r SOAResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"SOAResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// TXTResource adds a single TXTResource. -func (b *Builder) TXTResource(h ResourceHeader, r TXTResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"TXTResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// SRVResource adds a single SRVResource. -func (b *Builder) SRVResource(h ResourceHeader, r SRVResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"SRVResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// AResource adds a single AResource. -func (b *Builder) AResource(h ResourceHeader, r AResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"AResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// AAAAResource adds a single AAAAResource. -func (b *Builder) AAAAResource(h ResourceHeader, r AAAAResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"AAAAResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// OPTResource adds a single OPTResource. -func (b *Builder) OPTResource(h ResourceHeader, r OPTResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"OPTResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// UnknownResource adds a single UnknownResource. -func (b *Builder) UnknownResource(h ResourceHeader, r UnknownResource) error { - if err := b.checkResourceSection(); err != nil { - return err - } - h.Type = r.realType() - msg, lenOff, err := h.pack(b.msg, b.compression, b.start) - if err != nil { - return &nestedError{"ResourceHeader", err} - } - preLen := len(msg) - if msg, err = r.pack(msg, b.compression, b.start); err != nil { - return &nestedError{"UnknownResource body", err} - } - if err := h.fixLen(msg, lenOff, preLen); err != nil { - return err - } - if err := b.incrementSectionCount(); err != nil { - return err - } - b.msg = msg - return nil -} - -// Finish ends message building and generates a binary message. -func (b *Builder) Finish() ([]byte, error) { - if b.section < sectionHeader { - return nil, ErrNotStarted - } - b.section = sectionDone - // Space for the header was allocated in NewBuilder. - b.header.pack(b.msg[b.start:b.start]) - return b.msg, nil -} - -// A ResourceHeader is the header of a DNS resource record. There are -// many types of DNS resource records, but they all share the same header. -type ResourceHeader struct { - // Name is the domain name for which this resource record pertains. - Name Name - - // Type is the type of DNS resource record. - // - // This field will be set automatically during packing. - Type Type - - // Class is the class of network to which this DNS resource record - // pertains. - Class Class - - // TTL is the length of time (measured in seconds) which this resource - // record is valid for (time to live). All Resources in a set should - // have the same TTL (RFC 2181 Section 5.2). - TTL uint32 - - // Length is the length of data in the resource record after the header. - // - // This field will be set automatically during packing. - Length uint16 -} - -// GoString implements fmt.GoStringer.GoString. -func (h *ResourceHeader) GoString() string { - return "dnsmessage.ResourceHeader{" + - "Name: " + h.Name.GoString() + ", " + - "Type: " + h.Type.GoString() + ", " + - "Class: " + h.Class.GoString() + ", " + - "TTL: " + printUint32(h.TTL) + ", " + - "Length: " + printUint16(h.Length) + "}" -} - -// pack appends the wire format of the ResourceHeader to oldMsg. -// -// lenOff is the offset in msg where the Length field was packed. -func (h *ResourceHeader) pack(oldMsg []byte, compression map[string]uint16, compressionOff int) (msg []byte, lenOff int, err error) { - msg = oldMsg - if msg, err = h.Name.pack(msg, compression, compressionOff); err != nil { - return oldMsg, 0, &nestedError{"Name", err} - } - msg = packType(msg, h.Type) - msg = packClass(msg, h.Class) - msg = packUint32(msg, h.TTL) - lenOff = len(msg) - msg = packUint16(msg, h.Length) - return msg, lenOff, nil -} - -func (h *ResourceHeader) unpack(msg []byte, off int) (int, error) { - newOff := off - var err error - if newOff, err = h.Name.unpack(msg, newOff); err != nil { - return off, &nestedError{"Name", err} - } - if h.Type, newOff, err = unpackType(msg, newOff); err != nil { - return off, &nestedError{"Type", err} - } - if h.Class, newOff, err = unpackClass(msg, newOff); err != nil { - return off, &nestedError{"Class", err} - } - if h.TTL, newOff, err = unpackUint32(msg, newOff); err != nil { - return off, &nestedError{"TTL", err} - } - if h.Length, newOff, err = unpackUint16(msg, newOff); err != nil { - return off, &nestedError{"Length", err} - } - return newOff, nil -} - -// fixLen updates a packed ResourceHeader to include the length of the -// ResourceBody. -// -// lenOff is the offset of the ResourceHeader.Length field in msg. -// -// preLen is the length that msg was before the ResourceBody was packed. -func (h *ResourceHeader) fixLen(msg []byte, lenOff int, preLen int) error { - conLen := len(msg) - preLen - if conLen > int(^uint16(0)) { - return errResTooLong - } - - // Fill in the length now that we know how long the content is. - packUint16(msg[lenOff:lenOff], uint16(conLen)) - h.Length = uint16(conLen) - - return nil -} - -// EDNS(0) wire constants. -const ( - edns0Version = 0 - - edns0DNSSECOK = 0x00008000 - ednsVersionMask = 0x00ff0000 - edns0DNSSECOKMask = 0x00ff8000 -) - -// SetEDNS0 configures h for EDNS(0). -// -// The provided extRCode must be an extended RCode. -func (h *ResourceHeader) SetEDNS0(udpPayloadLen int, extRCode RCode, dnssecOK bool) error { - h.Name = Name{Data: [255]byte{'.'}, Length: 1} // RFC 6891 section 6.1.2 - h.Type = TypeOPT - h.Class = Class(udpPayloadLen) - h.TTL = uint32(extRCode) >> 4 << 24 - if dnssecOK { - h.TTL |= edns0DNSSECOK - } - return nil -} - -// DNSSECAllowed reports whether the DNSSEC OK bit is set. -func (h *ResourceHeader) DNSSECAllowed() bool { - return h.TTL&edns0DNSSECOKMask == edns0DNSSECOK // RFC 6891 section 6.1.3 -} - -// ExtendedRCode returns an extended RCode. -// -// The provided rcode must be the RCode in DNS message header. -func (h *ResourceHeader) ExtendedRCode(rcode RCode) RCode { - if h.TTL&ednsVersionMask == edns0Version { // RFC 6891 section 6.1.3 - return RCode(h.TTL>>24<<4) | rcode - } - return rcode -} - -func skipResource(msg []byte, off int) (int, error) { - newOff, err := skipName(msg, off) - if err != nil { - return off, &nestedError{"Name", err} - } - if newOff, err = skipType(msg, newOff); err != nil { - return off, &nestedError{"Type", err} - } - if newOff, err = skipClass(msg, newOff); err != nil { - return off, &nestedError{"Class", err} - } - if newOff, err = skipUint32(msg, newOff); err != nil { - return off, &nestedError{"TTL", err} - } - length, newOff, err := unpackUint16(msg, newOff) - if err != nil { - return off, &nestedError{"Length", err} - } - if newOff += int(length); newOff > len(msg) { - return off, errResourceLen - } - return newOff, nil -} - -// packUint16 appends the wire format of field to msg. -func packUint16(msg []byte, field uint16) []byte { - return append(msg, byte(field>>8), byte(field)) -} - -func unpackUint16(msg []byte, off int) (uint16, int, error) { - if off+uint16Len > len(msg) { - return 0, off, errBaseLen - } - return uint16(msg[off])<<8 | uint16(msg[off+1]), off + uint16Len, nil -} - -func skipUint16(msg []byte, off int) (int, error) { - if off+uint16Len > len(msg) { - return off, errBaseLen - } - return off + uint16Len, nil -} - -// packType appends the wire format of field to msg. -func packType(msg []byte, field Type) []byte { - return packUint16(msg, uint16(field)) -} - -func unpackType(msg []byte, off int) (Type, int, error) { - t, o, err := unpackUint16(msg, off) - return Type(t), o, err -} - -func skipType(msg []byte, off int) (int, error) { - return skipUint16(msg, off) -} - -// packClass appends the wire format of field to msg. -func packClass(msg []byte, field Class) []byte { - return packUint16(msg, uint16(field)) -} - -func unpackClass(msg []byte, off int) (Class, int, error) { - c, o, err := unpackUint16(msg, off) - return Class(c), o, err -} - -func skipClass(msg []byte, off int) (int, error) { - return skipUint16(msg, off) -} - -// packUint32 appends the wire format of field to msg. -func packUint32(msg []byte, field uint32) []byte { - return append( - msg, - byte(field>>24), - byte(field>>16), - byte(field>>8), - byte(field), - ) -} - -func unpackUint32(msg []byte, off int) (uint32, int, error) { - if off+uint32Len > len(msg) { - return 0, off, errBaseLen - } - v := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]) - return v, off + uint32Len, nil -} - -func skipUint32(msg []byte, off int) (int, error) { - if off+uint32Len > len(msg) { - return off, errBaseLen - } - return off + uint32Len, nil -} - -// packText appends the wire format of field to msg. -func packText(msg []byte, field string) ([]byte, error) { - l := len(field) - if l > 255 { - return nil, errStringTooLong - } - msg = append(msg, byte(l)) - msg = append(msg, field...) - - return msg, nil -} - -func unpackText(msg []byte, off int) (string, int, error) { - if off >= len(msg) { - return "", off, errBaseLen - } - beginOff := off + 1 - endOff := beginOff + int(msg[off]) - if endOff > len(msg) { - return "", off, errCalcLen - } - return string(msg[beginOff:endOff]), endOff, nil -} - -// packBytes appends the wire format of field to msg. -func packBytes(msg []byte, field []byte) []byte { - return append(msg, field...) -} - -func unpackBytes(msg []byte, off int, field []byte) (int, error) { - newOff := off + len(field) - if newOff > len(msg) { - return off, errBaseLen - } - copy(field, msg[off:newOff]) - return newOff, nil -} - -const nonEncodedNameMax = 254 - -// A Name is a non-encoded and non-escaped domain name. It is used instead of strings to avoid -// allocations. -type Name struct { - Data [255]byte - Length uint8 -} - -// NewName creates a new Name from a string. -func NewName(name string) (Name, error) { - n := Name{Length: uint8(len(name))} - if len(name) > len(n.Data) { - return Name{}, errCalcLen - } - copy(n.Data[:], name) - return n, nil -} - -// MustNewName creates a new Name from a string and panics on error. -func MustNewName(name string) Name { - n, err := NewName(name) - if err != nil { - panic("creating name: " + err.Error()) - } - return n -} - -// String implements fmt.Stringer.String. -// -// Note: characters inside the labels are not escaped in any way. -func (n Name) String() string { - return string(n.Data[:n.Length]) -} - -// GoString implements fmt.GoStringer.GoString. -func (n *Name) GoString() string { - return `dnsmessage.MustNewName("` + printString(n.Data[:n.Length]) + `")` -} - -// pack appends the wire format of the Name to msg. -// -// Domain names are a sequence of counted strings split at the dots. They end -// with a zero-length string. Compression can be used to reuse domain suffixes. -// -// The compression map will be updated with new domain suffixes. If compression -// is nil, compression will not be used. -func (n *Name) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - oldMsg := msg - - if n.Length > nonEncodedNameMax { - return nil, errNameTooLong - } - - // Add a trailing dot to canonicalize name. - if n.Length == 0 || n.Data[n.Length-1] != '.' { - return oldMsg, errNonCanonicalName - } - - // Allow root domain. - if n.Data[0] == '.' && n.Length == 1 { - return append(msg, 0), nil - } - - var nameAsStr string - - // Emit sequence of counted strings, chopping at dots. - for i, begin := 0, 0; i < int(n.Length); i++ { - // Check for the end of the segment. - if n.Data[i] == '.' { - // The two most significant bits have special meaning. - // It isn't allowed for segments to be long enough to - // need them. - if i-begin >= 1<<6 { - return oldMsg, errSegTooLong - } - - // Segments must have a non-zero length. - if i-begin == 0 { - return oldMsg, errZeroSegLen - } - - msg = append(msg, byte(i-begin)) - - for j := begin; j < i; j++ { - msg = append(msg, n.Data[j]) - } - - begin = i + 1 - continue - } - - // We can only compress domain suffixes starting with a new - // segment. A pointer is two bytes with the two most significant - // bits set to 1 to indicate that it is a pointer. - if (i == 0 || n.Data[i-1] == '.') && compression != nil { - if ptr, ok := compression[string(n.Data[i:n.Length])]; ok { - // Hit. Emit a pointer instead of the rest of - // the domain. - return append(msg, byte(ptr>>8|0xC0), byte(ptr)), nil - } - - // Miss. Add the suffix to the compression table if the - // offset can be stored in the available 14 bits. - newPtr := len(msg) - compressionOff - if newPtr <= int(^uint16(0)>>2) { - if nameAsStr == "" { - // allocate n.Data on the heap once, to avoid allocating it - // multiple times (for next labels). - nameAsStr = string(n.Data[:n.Length]) - } - compression[nameAsStr[i:]] = uint16(newPtr) - } - } - } - return append(msg, 0), nil -} - -// unpack unpacks a domain name. -func (n *Name) unpack(msg []byte, off int) (int, error) { - return n.unpackCompressed(msg, off, true /* allowCompression */) -} - -func (n *Name) unpackCompressed(msg []byte, off int, allowCompression bool) (int, error) { - // currOff is the current working offset. - currOff := off - - // newOff is the offset where the next record will start. Pointers lead - // to data that belongs to other names and thus doesn't count towards to - // the usage of this name. - newOff := off - - // ptr is the number of pointers followed. - var ptr int - - // Name is a slice representation of the name data. - name := n.Data[:0] - -Loop: - for { - if currOff >= len(msg) { - return off, errBaseLen - } - c := int(msg[currOff]) - currOff++ - switch c & 0xC0 { - case 0x00: // String segment - if c == 0x00 { - // A zero length signals the end of the name. - break Loop - } - endOff := currOff + c - if endOff > len(msg) { - return off, errCalcLen - } - - // Reject names containing dots. - // See issue golang/go#56246 - for _, v := range msg[currOff:endOff] { - if v == '.' { - return off, errInvalidName - } - } - - name = append(name, msg[currOff:endOff]...) - name = append(name, '.') - currOff = endOff - case 0xC0: // Pointer - if !allowCompression { - return off, errCompressedSRV - } - if currOff >= len(msg) { - return off, errInvalidPtr - } - c1 := msg[currOff] - currOff++ - if ptr == 0 { - newOff = currOff - } - // Don't follow too many pointers, maybe there's a loop. - if ptr++; ptr > 10 { - return off, errTooManyPtr - } - currOff = (c^0xC0)<<8 | int(c1) - default: - // Prefixes 0x80 and 0x40 are reserved. - return off, errReserved - } - } - if len(name) == 0 { - name = append(name, '.') - } - if len(name) > nonEncodedNameMax { - return off, errNameTooLong - } - n.Length = uint8(len(name)) - if ptr == 0 { - newOff = currOff - } - return newOff, nil -} - -func skipName(msg []byte, off int) (int, error) { - // newOff is the offset where the next record will start. Pointers lead - // to data that belongs to other names and thus doesn't count towards to - // the usage of this name. - newOff := off - -Loop: - for { - if newOff >= len(msg) { - return off, errBaseLen - } - c := int(msg[newOff]) - newOff++ - switch c & 0xC0 { - case 0x00: - if c == 0x00 { - // A zero length signals the end of the name. - break Loop - } - // literal string - newOff += c - if newOff > len(msg) { - return off, errCalcLen - } - case 0xC0: - // Pointer to somewhere else in msg. - - // Pointers are two bytes. - newOff++ - - // Don't follow the pointer as the data here has ended. - break Loop - default: - // Prefixes 0x80 and 0x40 are reserved. - return off, errReserved - } - } - - return newOff, nil -} - -// A Question is a DNS query. -type Question struct { - Name Name - Type Type - Class Class -} - -// pack appends the wire format of the Question to msg. -func (q *Question) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - msg, err := q.Name.pack(msg, compression, compressionOff) - if err != nil { - return msg, &nestedError{"Name", err} - } - msg = packType(msg, q.Type) - return packClass(msg, q.Class), nil -} - -// GoString implements fmt.GoStringer.GoString. -func (q *Question) GoString() string { - return "dnsmessage.Question{" + - "Name: " + q.Name.GoString() + ", " + - "Type: " + q.Type.GoString() + ", " + - "Class: " + q.Class.GoString() + "}" -} - -func unpackResourceBody(msg []byte, off int, hdr ResourceHeader) (ResourceBody, int, error) { - var ( - r ResourceBody - err error - name string - ) - switch hdr.Type { - case TypeA: - var rb AResource - rb, err = unpackAResource(msg, off) - r = &rb - name = "A" - case TypeNS: - var rb NSResource - rb, err = unpackNSResource(msg, off) - r = &rb - name = "NS" - case TypeCNAME: - var rb CNAMEResource - rb, err = unpackCNAMEResource(msg, off) - r = &rb - name = "CNAME" - case TypeSOA: - var rb SOAResource - rb, err = unpackSOAResource(msg, off) - r = &rb - name = "SOA" - case TypePTR: - var rb PTRResource - rb, err = unpackPTRResource(msg, off) - r = &rb - name = "PTR" - case TypeMX: - var rb MXResource - rb, err = unpackMXResource(msg, off) - r = &rb - name = "MX" - case TypeTXT: - var rb TXTResource - rb, err = unpackTXTResource(msg, off, hdr.Length) - r = &rb - name = "TXT" - case TypeAAAA: - var rb AAAAResource - rb, err = unpackAAAAResource(msg, off) - r = &rb - name = "AAAA" - case TypeSRV: - var rb SRVResource - rb, err = unpackSRVResource(msg, off) - r = &rb - name = "SRV" - case TypeOPT: - var rb OPTResource - rb, err = unpackOPTResource(msg, off, hdr.Length) - r = &rb - name = "OPT" - default: - var rb UnknownResource - rb, err = unpackUnknownResource(hdr.Type, msg, off, hdr.Length) - r = &rb - name = "Unknown" - } - if err != nil { - return nil, off, &nestedError{name + " record", err} - } - return r, off + int(hdr.Length), nil -} - -// A CNAMEResource is a CNAME Resource record. -type CNAMEResource struct { - CNAME Name -} - -func (r *CNAMEResource) realType() Type { - return TypeCNAME -} - -// pack appends the wire format of the CNAMEResource to msg. -func (r *CNAMEResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - return r.CNAME.pack(msg, compression, compressionOff) -} - -// GoString implements fmt.GoStringer.GoString. -func (r *CNAMEResource) GoString() string { - return "dnsmessage.CNAMEResource{CNAME: " + r.CNAME.GoString() + "}" -} - -func unpackCNAMEResource(msg []byte, off int) (CNAMEResource, error) { - var cname Name - if _, err := cname.unpack(msg, off); err != nil { - return CNAMEResource{}, err - } - return CNAMEResource{cname}, nil -} - -// An MXResource is an MX Resource record. -type MXResource struct { - Pref uint16 - MX Name -} - -func (r *MXResource) realType() Type { - return TypeMX -} - -// pack appends the wire format of the MXResource to msg. -func (r *MXResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - oldMsg := msg - msg = packUint16(msg, r.Pref) - msg, err := r.MX.pack(msg, compression, compressionOff) - if err != nil { - return oldMsg, &nestedError{"MXResource.MX", err} - } - return msg, nil -} - -// GoString implements fmt.GoStringer.GoString. -func (r *MXResource) GoString() string { - return "dnsmessage.MXResource{" + - "Pref: " + printUint16(r.Pref) + ", " + - "MX: " + r.MX.GoString() + "}" -} - -func unpackMXResource(msg []byte, off int) (MXResource, error) { - pref, off, err := unpackUint16(msg, off) - if err != nil { - return MXResource{}, &nestedError{"Pref", err} - } - var mx Name - if _, err := mx.unpack(msg, off); err != nil { - return MXResource{}, &nestedError{"MX", err} - } - return MXResource{pref, mx}, nil -} - -// An NSResource is an NS Resource record. -type NSResource struct { - NS Name -} - -func (r *NSResource) realType() Type { - return TypeNS -} - -// pack appends the wire format of the NSResource to msg. -func (r *NSResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - return r.NS.pack(msg, compression, compressionOff) -} - -// GoString implements fmt.GoStringer.GoString. -func (r *NSResource) GoString() string { - return "dnsmessage.NSResource{NS: " + r.NS.GoString() + "}" -} - -func unpackNSResource(msg []byte, off int) (NSResource, error) { - var ns Name - if _, err := ns.unpack(msg, off); err != nil { - return NSResource{}, err - } - return NSResource{ns}, nil -} - -// A PTRResource is a PTR Resource record. -type PTRResource struct { - PTR Name -} - -func (r *PTRResource) realType() Type { - return TypePTR -} - -// pack appends the wire format of the PTRResource to msg. -func (r *PTRResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - return r.PTR.pack(msg, compression, compressionOff) -} - -// GoString implements fmt.GoStringer.GoString. -func (r *PTRResource) GoString() string { - return "dnsmessage.PTRResource{PTR: " + r.PTR.GoString() + "}" -} - -func unpackPTRResource(msg []byte, off int) (PTRResource, error) { - var ptr Name - if _, err := ptr.unpack(msg, off); err != nil { - return PTRResource{}, err - } - return PTRResource{ptr}, nil -} - -// An SOAResource is an SOA Resource record. -type SOAResource struct { - NS Name - MBox Name - Serial uint32 - Refresh uint32 - Retry uint32 - Expire uint32 - - // MinTTL the is the default TTL of Resources records which did not - // contain a TTL value and the TTL of negative responses. (RFC 2308 - // Section 4) - MinTTL uint32 -} - -func (r *SOAResource) realType() Type { - return TypeSOA -} - -// pack appends the wire format of the SOAResource to msg. -func (r *SOAResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - oldMsg := msg - msg, err := r.NS.pack(msg, compression, compressionOff) - if err != nil { - return oldMsg, &nestedError{"SOAResource.NS", err} - } - msg, err = r.MBox.pack(msg, compression, compressionOff) - if err != nil { - return oldMsg, &nestedError{"SOAResource.MBox", err} - } - msg = packUint32(msg, r.Serial) - msg = packUint32(msg, r.Refresh) - msg = packUint32(msg, r.Retry) - msg = packUint32(msg, r.Expire) - return packUint32(msg, r.MinTTL), nil -} - -// GoString implements fmt.GoStringer.GoString. -func (r *SOAResource) GoString() string { - return "dnsmessage.SOAResource{" + - "NS: " + r.NS.GoString() + ", " + - "MBox: " + r.MBox.GoString() + ", " + - "Serial: " + printUint32(r.Serial) + ", " + - "Refresh: " + printUint32(r.Refresh) + ", " + - "Retry: " + printUint32(r.Retry) + ", " + - "Expire: " + printUint32(r.Expire) + ", " + - "MinTTL: " + printUint32(r.MinTTL) + "}" -} - -func unpackSOAResource(msg []byte, off int) (SOAResource, error) { - var ns Name - off, err := ns.unpack(msg, off) - if err != nil { - return SOAResource{}, &nestedError{"NS", err} - } - var mbox Name - if off, err = mbox.unpack(msg, off); err != nil { - return SOAResource{}, &nestedError{"MBox", err} - } - serial, off, err := unpackUint32(msg, off) - if err != nil { - return SOAResource{}, &nestedError{"Serial", err} - } - refresh, off, err := unpackUint32(msg, off) - if err != nil { - return SOAResource{}, &nestedError{"Refresh", err} - } - retry, off, err := unpackUint32(msg, off) - if err != nil { - return SOAResource{}, &nestedError{"Retry", err} - } - expire, off, err := unpackUint32(msg, off) - if err != nil { - return SOAResource{}, &nestedError{"Expire", err} - } - minTTL, _, err := unpackUint32(msg, off) - if err != nil { - return SOAResource{}, &nestedError{"MinTTL", err} - } - return SOAResource{ns, mbox, serial, refresh, retry, expire, minTTL}, nil -} - -// A TXTResource is a TXT Resource record. -type TXTResource struct { - TXT []string -} - -func (r *TXTResource) realType() Type { - return TypeTXT -} - -// pack appends the wire format of the TXTResource to msg. -func (r *TXTResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - oldMsg := msg - for _, s := range r.TXT { - var err error - msg, err = packText(msg, s) - if err != nil { - return oldMsg, err - } - } - return msg, nil -} - -// GoString implements fmt.GoStringer.GoString. -func (r *TXTResource) GoString() string { - s := "dnsmessage.TXTResource{TXT: []string{" - if len(r.TXT) == 0 { - return s + "}}" - } - s += `"` + printString([]byte(r.TXT[0])) - for _, t := range r.TXT[1:] { - s += `", "` + printString([]byte(t)) - } - return s + `"}}` -} - -func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error) { - txts := make([]string, 0, 1) - for n := uint16(0); n < length; { - var t string - var err error - if t, off, err = unpackText(msg, off); err != nil { - return TXTResource{}, &nestedError{"text", err} - } - // Check if we got too many bytes. - if length-n < uint16(len(t))+1 { - return TXTResource{}, errCalcLen - } - n += uint16(len(t)) + 1 - txts = append(txts, t) - } - return TXTResource{txts}, nil -} - -// An SRVResource is an SRV Resource record. -type SRVResource struct { - Priority uint16 - Weight uint16 - Port uint16 - Target Name // Not compressed as per RFC 2782. -} - -func (r *SRVResource) realType() Type { - return TypeSRV -} - -// pack appends the wire format of the SRVResource to msg. -func (r *SRVResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - oldMsg := msg - msg = packUint16(msg, r.Priority) - msg = packUint16(msg, r.Weight) - msg = packUint16(msg, r.Port) - msg, err := r.Target.pack(msg, nil, compressionOff) - if err != nil { - return oldMsg, &nestedError{"SRVResource.Target", err} - } - return msg, nil -} - -// GoString implements fmt.GoStringer.GoString. -func (r *SRVResource) GoString() string { - return "dnsmessage.SRVResource{" + - "Priority: " + printUint16(r.Priority) + ", " + - "Weight: " + printUint16(r.Weight) + ", " + - "Port: " + printUint16(r.Port) + ", " + - "Target: " + r.Target.GoString() + "}" -} - -func unpackSRVResource(msg []byte, off int) (SRVResource, error) { - priority, off, err := unpackUint16(msg, off) - if err != nil { - return SRVResource{}, &nestedError{"Priority", err} - } - weight, off, err := unpackUint16(msg, off) - if err != nil { - return SRVResource{}, &nestedError{"Weight", err} - } - port, off, err := unpackUint16(msg, off) - if err != nil { - return SRVResource{}, &nestedError{"Port", err} - } - var target Name - if _, err := target.unpackCompressed(msg, off, false /* allowCompression */); err != nil { - return SRVResource{}, &nestedError{"Target", err} - } - return SRVResource{priority, weight, port, target}, nil -} - -// An AResource is an A Resource record. -type AResource struct { - A [4]byte -} - -func (r *AResource) realType() Type { - return TypeA -} - -// pack appends the wire format of the AResource to msg. -func (r *AResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - return packBytes(msg, r.A[:]), nil -} - -// GoString implements fmt.GoStringer.GoString. -func (r *AResource) GoString() string { - return "dnsmessage.AResource{" + - "A: [4]byte{" + printByteSlice(r.A[:]) + "}}" -} - -func unpackAResource(msg []byte, off int) (AResource, error) { - var a [4]byte - if _, err := unpackBytes(msg, off, a[:]); err != nil { - return AResource{}, err - } - return AResource{a}, nil -} - -// An AAAAResource is an AAAA Resource record. -type AAAAResource struct { - AAAA [16]byte -} - -func (r *AAAAResource) realType() Type { - return TypeAAAA -} - -// GoString implements fmt.GoStringer.GoString. -func (r *AAAAResource) GoString() string { - return "dnsmessage.AAAAResource{" + - "AAAA: [16]byte{" + printByteSlice(r.AAAA[:]) + "}}" -} - -// pack appends the wire format of the AAAAResource to msg. -func (r *AAAAResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - return packBytes(msg, r.AAAA[:]), nil -} - -func unpackAAAAResource(msg []byte, off int) (AAAAResource, error) { - var aaaa [16]byte - if _, err := unpackBytes(msg, off, aaaa[:]); err != nil { - return AAAAResource{}, err - } - return AAAAResource{aaaa}, nil -} - -// An OPTResource is an OPT pseudo Resource record. -// -// The pseudo resource record is part of the extension mechanisms for DNS -// as defined in RFC 6891. -type OPTResource struct { - Options []Option -} - -// An Option represents a DNS message option within OPTResource. -// -// The message option is part of the extension mechanisms for DNS as -// defined in RFC 6891. -type Option struct { - Code uint16 // option code - Data []byte -} - -// GoString implements fmt.GoStringer.GoString. -func (o *Option) GoString() string { - return "dnsmessage.Option{" + - "Code: " + printUint16(o.Code) + ", " + - "Data: []byte{" + printByteSlice(o.Data) + "}}" -} - -func (r *OPTResource) realType() Type { - return TypeOPT -} - -func (r *OPTResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - for _, opt := range r.Options { - msg = packUint16(msg, opt.Code) - l := uint16(len(opt.Data)) - msg = packUint16(msg, l) - msg = packBytes(msg, opt.Data) - } - return msg, nil -} - -// GoString implements fmt.GoStringer.GoString. -func (r *OPTResource) GoString() string { - s := "dnsmessage.OPTResource{Options: []dnsmessage.Option{" - if len(r.Options) == 0 { - return s + "}}" - } - s += r.Options[0].GoString() - for _, o := range r.Options[1:] { - s += ", " + o.GoString() - } - return s + "}}" -} - -func unpackOPTResource(msg []byte, off int, length uint16) (OPTResource, error) { - var opts []Option - for oldOff := off; off < oldOff+int(length); { - var err error - var o Option - o.Code, off, err = unpackUint16(msg, off) - if err != nil { - return OPTResource{}, &nestedError{"Code", err} - } - var l uint16 - l, off, err = unpackUint16(msg, off) - if err != nil { - return OPTResource{}, &nestedError{"Data", err} - } - o.Data = make([]byte, l) - if copy(o.Data, msg[off:]) != int(l) { - return OPTResource{}, &nestedError{"Data", errCalcLen} - } - off += int(l) - opts = append(opts, o) - } - return OPTResource{opts}, nil -} - -// An UnknownResource is a catch-all container for unknown record types. -type UnknownResource struct { - Type Type - Data []byte -} - -func (r *UnknownResource) realType() Type { - return r.Type -} - -// pack appends the wire format of the UnknownResource to msg. -func (r *UnknownResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { - return packBytes(msg, r.Data[:]), nil -} - -// GoString implements fmt.GoStringer.GoString. -func (r *UnknownResource) GoString() string { - return "dnsmessage.UnknownResource{" + - "Type: " + r.Type.GoString() + ", " + - "Data: []byte{" + printByteSlice(r.Data) + "}}" -} - -func unpackUnknownResource(recordType Type, msg []byte, off int, length uint16) (UnknownResource, error) { - parsed := UnknownResource{ - Type: recordType, - Data: make([]byte, length), - } - if _, err := unpackBytes(msg, off, parsed.Data); err != nil { - return UnknownResource{}, err - } - return parsed, nil -} diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu.go b/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu.go deleted file mode 100644 index 4756ad5f7951..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu.go +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package cpu implements processor feature detection for -// various CPU architectures. -package cpu - -import ( - "os" - "strings" -) - -// Initialized reports whether the CPU features were initialized. -// -// For some GOOS/GOARCH combinations initialization of the CPU features depends -// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm -// Initialized will report false if reading the file fails. -var Initialized bool - -// CacheLinePad is used to pad structs to avoid false sharing. -type CacheLinePad struct{ _ [cacheLineSize]byte } - -// X86 contains the supported CPU features of the -// current X86/AMD64 platform. If the current platform -// is not X86/AMD64 then all feature flags are false. -// -// X86 is padded to avoid false sharing. Further the HasAVX -// and HasAVX2 are only set if the OS supports XMM and YMM -// registers in addition to the CPUID feature bit being set. -var X86 struct { - _ CacheLinePad - HasAES bool // AES hardware implementation (AES NI) - HasADX bool // Multi-precision add-carry instruction extensions - HasAVX bool // Advanced vector extension - HasAVX2 bool // Advanced vector extension 2 - HasAVX512 bool // Advanced vector extension 512 - HasAVX512F bool // Advanced vector extension 512 Foundation Instructions - HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions - HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions - HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions - HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions - HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions - HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions - HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add - HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions - HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision - HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision - HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions - HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations - HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions - HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions - HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions - HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2 - HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms - HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions - HasAMXTile bool // Advanced Matrix Extension Tile instructions - HasAMXInt8 bool // Advanced Matrix Extension Int8 instructions - HasAMXBF16 bool // Advanced Matrix Extension BFloat16 instructions - HasBMI1 bool // Bit manipulation instruction set 1 - HasBMI2 bool // Bit manipulation instruction set 2 - HasCX16 bool // Compare and exchange 16 Bytes - HasERMS bool // Enhanced REP for MOVSB and STOSB - HasFMA bool // Fused-multiply-add instructions - HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. - HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM - HasPOPCNT bool // Hamming weight instruction POPCNT. - HasRDRAND bool // RDRAND instruction (on-chip random number generator) - HasRDSEED bool // RDSEED instruction (on-chip random number generator) - HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) - HasSSE3 bool // Streaming SIMD extension 3 - HasSSSE3 bool // Supplemental streaming SIMD extension 3 - HasSSE41 bool // Streaming SIMD extension 4 and 4.1 - HasSSE42 bool // Streaming SIMD extension 4 and 4.2 - _ CacheLinePad -} - -// ARM64 contains the supported CPU features of the -// current ARMv8(aarch64) platform. If the current platform -// is not arm64 then all feature flags are false. -var ARM64 struct { - _ CacheLinePad - HasFP bool // Floating-point instruction set (always available) - HasASIMD bool // Advanced SIMD (always available) - HasEVTSTRM bool // Event stream support - HasAES bool // AES hardware implementation - HasPMULL bool // Polynomial multiplication instruction set - HasSHA1 bool // SHA1 hardware implementation - HasSHA2 bool // SHA2 hardware implementation - HasCRC32 bool // CRC32 hardware implementation - HasATOMICS bool // Atomic memory operation instruction set - HasFPHP bool // Half precision floating-point instruction set - HasASIMDHP bool // Advanced SIMD half precision instruction set - HasCPUID bool // CPUID identification scheme registers - HasASIMDRDM bool // Rounding double multiply add/subtract instruction set - HasJSCVT bool // Javascript conversion from floating-point to integer - HasFCMA bool // Floating-point multiplication and addition of complex numbers - HasLRCPC bool // Release Consistent processor consistent support - HasDCPOP bool // Persistent memory support - HasSHA3 bool // SHA3 hardware implementation - HasSM3 bool // SM3 hardware implementation - HasSM4 bool // SM4 hardware implementation - HasASIMDDP bool // Advanced SIMD double precision instruction set - HasSHA512 bool // SHA512 hardware implementation - HasSVE bool // Scalable Vector Extensions - HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 - _ CacheLinePad -} - -// ARM contains the supported CPU features of the current ARM (32-bit) platform. -// All feature flags are false if: -// 1. the current platform is not arm, or -// 2. the current operating system is not Linux. -var ARM struct { - _ CacheLinePad - HasSWP bool // SWP instruction support - HasHALF bool // Half-word load and store support - HasTHUMB bool // ARM Thumb instruction set - Has26BIT bool // Address space limited to 26-bits - HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support - HasFPA bool // Floating point arithmetic support - HasVFP bool // Vector floating point support - HasEDSP bool // DSP Extensions support - HasJAVA bool // Java instruction set - HasIWMMXT bool // Intel Wireless MMX technology support - HasCRUNCH bool // MaverickCrunch context switching and handling - HasTHUMBEE bool // Thumb EE instruction set - HasNEON bool // NEON instruction set - HasVFPv3 bool // Vector floating point version 3 support - HasVFPv3D16 bool // Vector floating point version 3 D8-D15 - HasTLS bool // Thread local storage support - HasVFPv4 bool // Vector floating point version 4 support - HasIDIVA bool // Integer divide instruction support in ARM mode - HasIDIVT bool // Integer divide instruction support in Thumb mode - HasVFPD32 bool // Vector floating point version 3 D15-D31 - HasLPAE bool // Large Physical Address Extensions - HasEVTSTRM bool // Event stream support - HasAES bool // AES hardware implementation - HasPMULL bool // Polynomial multiplication instruction set - HasSHA1 bool // SHA1 hardware implementation - HasSHA2 bool // SHA2 hardware implementation - HasCRC32 bool // CRC32 hardware implementation - _ CacheLinePad -} - -// MIPS64X contains the supported CPU features of the current mips64/mips64le -// platforms. If the current platform is not mips64/mips64le or the current -// operating system is not Linux then all feature flags are false. -var MIPS64X struct { - _ CacheLinePad - HasMSA bool // MIPS SIMD architecture - _ CacheLinePad -} - -// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. -// If the current platform is not ppc64/ppc64le then all feature flags are false. -// -// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, -// since there are no optional categories. There are some exceptions that also -// require kernel support to work (DARN, SCV), so there are feature bits for -// those as well. The struct is padded to avoid false sharing. -var PPC64 struct { - _ CacheLinePad - HasDARN bool // Hardware random number generator (requires kernel enablement) - HasSCV bool // Syscall vectored (requires kernel enablement) - IsPOWER8 bool // ISA v2.07 (POWER8) - IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8 - _ CacheLinePad -} - -// S390X contains the supported CPU features of the current IBM Z -// (s390x) platform. If the current platform is not IBM Z then all -// feature flags are false. -// -// S390X is padded to avoid false sharing. Further HasVX is only set -// if the OS supports vector registers in addition to the STFLE -// feature bit being set. -var S390X struct { - _ CacheLinePad - HasZARCH bool // z/Architecture mode is active [mandatory] - HasSTFLE bool // store facility list extended - HasLDISP bool // long (20-bit) displacements - HasEIMM bool // 32-bit immediates - HasDFP bool // decimal floating point - HasETF3EH bool // ETF-3 enhanced - HasMSA bool // message security assist (CPACF) - HasAES bool // KM-AES{128,192,256} functions - HasAESCBC bool // KMC-AES{128,192,256} functions - HasAESCTR bool // KMCTR-AES{128,192,256} functions - HasAESGCM bool // KMA-GCM-AES{128,192,256} functions - HasGHASH bool // KIMD-GHASH function - HasSHA1 bool // K{I,L}MD-SHA-1 functions - HasSHA256 bool // K{I,L}MD-SHA-256 functions - HasSHA512 bool // K{I,L}MD-SHA-512 functions - HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions - HasVX bool // vector facility - HasVXE bool // vector-enhancements facility 1 - _ CacheLinePad -} - -func init() { - archInit() - initOptions() - processOptions() -} - -// options contains the cpu debug options that can be used in GODEBUG. -// Options are arch dependent and are added by the arch specific initOptions functions. -// Features that are mandatory for the specific GOARCH should have the Required field set -// (e.g. SSE2 on amd64). -var options []option - -// Option names should be lower case. e.g. avx instead of AVX. -type option struct { - Name string - Feature *bool - Specified bool // whether feature value was specified in GODEBUG - Enable bool // whether feature should be enabled - Required bool // whether feature is mandatory and can not be disabled -} - -func processOptions() { - env := os.Getenv("GODEBUG") -field: - for env != "" { - field := "" - i := strings.IndexByte(env, ',') - if i < 0 { - field, env = env, "" - } else { - field, env = env[:i], env[i+1:] - } - if len(field) < 4 || field[:4] != "cpu." { - continue - } - i = strings.IndexByte(field, '=') - if i < 0 { - print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n") - continue - } - key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" - - var enable bool - switch value { - case "on": - enable = true - case "off": - enable = false - default: - print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n") - continue field - } - - if key == "all" { - for i := range options { - options[i].Specified = true - options[i].Enable = enable || options[i].Required - } - continue field - } - - for i := range options { - if options[i].Name == key { - options[i].Specified = true - options[i].Enable = enable - continue field - } - } - - print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n") - } - - for _, o := range options { - if !o.Specified { - continue - } - - if o.Enable && !*o.Feature { - print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n") - continue - } - - if !o.Enable && o.Required { - print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n") - continue - } - - *o.Feature = o.Enable - } -} diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/ya.make b/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/ya.make deleted file mode 100644 index 6c60d7e95cc0..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/ya.make +++ /dev/null @@ -1,57 +0,0 @@ -GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - byteorder.go - cpu.go - cpu_arm64.go - cpu_arm64.s - cpu_gc_arm64.go - cpu_other_arm64.go - endian_little.go - parse.go - runtime_auxv.go - runtime_auxv_go121.go - ) -ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - byteorder.go - cpu.go - cpu_gc_x86.go - cpu_x86.go - cpu_x86.s - endian_little.go - parse.go - runtime_auxv.go - runtime_auxv_go121.go - ) -ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - byteorder.go - cpu.go - cpu_arm64.go - cpu_arm64.s - cpu_gc_arm64.go - cpu_linux_arm64.go - endian_little.go - hwcap_linux.go - parse.go - proc_cpuinfo_linux.go - runtime_auxv.go - runtime_auxv_go121.go - ) -ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) - SRCS( - byteorder.go - cpu.go - cpu_gc_x86.go - cpu_linux_noinit.go - cpu_x86.go - cpu_x86.s - endian_little.go - hwcap_linux.go - parse.go - runtime_auxv.go - runtime_auxv_go121.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/bufio/bufio.go b/contrib/go/_std_1.23/src/bufio/bufio.go similarity index 100% rename from contrib/go/_std_1.22/src/bufio/bufio.go rename to contrib/go/_std_1.23/src/bufio/bufio.go diff --git a/contrib/go/_std_1.22/src/bufio/scan.go b/contrib/go/_std_1.23/src/bufio/scan.go similarity index 100% rename from contrib/go/_std_1.22/src/bufio/scan.go rename to contrib/go/_std_1.23/src/bufio/scan.go diff --git a/contrib/go/_std_1.22/src/bufio/ya.make b/contrib/go/_std_1.23/src/bufio/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/bufio/ya.make rename to contrib/go/_std_1.23/src/bufio/ya.make diff --git a/contrib/go/_std_1.23/src/bytes/buffer.go b/contrib/go/_std_1.23/src/bytes/buffer.go new file mode 100644 index 000000000000..4176d670ec83 --- /dev/null +++ b/contrib/go/_std_1.23/src/bytes/buffer.go @@ -0,0 +1,482 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bytes + +// Simple byte buffer for marshaling data. + +import ( + "errors" + "io" + "unicode/utf8" +) + +// smallBufferSize is an initial allocation minimal capacity. +const smallBufferSize = 64 + +// A Buffer is a variable-sized buffer of bytes with [Buffer.Read] and [Buffer.Write] methods. +// The zero value for Buffer is an empty buffer ready to use. +type Buffer struct { + buf []byte // contents are the bytes buf[off : len(buf)] + off int // read at &buf[off], write at &buf[len(buf)] + lastRead readOp // last read operation, so that Unread* can work correctly. +} + +// The readOp constants describe the last action performed on +// the buffer, so that UnreadRune and UnreadByte can check for +// invalid usage. opReadRuneX constants are chosen such that +// converted to int they correspond to the rune size that was read. +type readOp int8 + +// Don't use iota for these, as the values need to correspond with the +// names and comments, which is easier to see when being explicit. +const ( + opRead readOp = -1 // Any other read operation. + opInvalid readOp = 0 // Non-read operation. + opReadRune1 readOp = 1 // Read rune of size 1. + opReadRune2 readOp = 2 // Read rune of size 2. + opReadRune3 readOp = 3 // Read rune of size 3. + opReadRune4 readOp = 4 // Read rune of size 4. +) + +// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer. +var ErrTooLarge = errors.New("bytes.Buffer: too large") +var errNegativeRead = errors.New("bytes.Buffer: reader returned negative count from Read") + +const maxInt = int(^uint(0) >> 1) + +// Bytes returns a slice of length b.Len() holding the unread portion of the buffer. +// The slice is valid for use only until the next buffer modification (that is, +// only until the next call to a method like [Buffer.Read], [Buffer.Write], [Buffer.Reset], or [Buffer.Truncate]). +// The slice aliases the buffer content at least until the next buffer modification, +// so immediate changes to the slice will affect the result of future reads. +func (b *Buffer) Bytes() []byte { return b.buf[b.off:] } + +// AvailableBuffer returns an empty buffer with b.Available() capacity. +// This buffer is intended to be appended to and +// passed to an immediately succeeding [Buffer.Write] call. +// The buffer is only valid until the next write operation on b. +func (b *Buffer) AvailableBuffer() []byte { return b.buf[len(b.buf):] } + +// String returns the contents of the unread portion of the buffer +// as a string. If the [Buffer] is a nil pointer, it returns "". +// +// To build strings more efficiently, see the [strings.Builder] type. +func (b *Buffer) String() string { + if b == nil { + // Special case, useful in debugging. + return "" + } + return string(b.buf[b.off:]) +} + +// empty reports whether the unread portion of the buffer is empty. +func (b *Buffer) empty() bool { return len(b.buf) <= b.off } + +// Len returns the number of bytes of the unread portion of the buffer; +// b.Len() == len(b.Bytes()). +func (b *Buffer) Len() int { return len(b.buf) - b.off } + +// Cap returns the capacity of the buffer's underlying byte slice, that is, the +// total space allocated for the buffer's data. +func (b *Buffer) Cap() int { return cap(b.buf) } + +// Available returns how many bytes are unused in the buffer. +func (b *Buffer) Available() int { return cap(b.buf) - len(b.buf) } + +// Truncate discards all but the first n unread bytes from the buffer +// but continues to use the same allocated storage. +// It panics if n is negative or greater than the length of the buffer. +func (b *Buffer) Truncate(n int) { + if n == 0 { + b.Reset() + return + } + b.lastRead = opInvalid + if n < 0 || n > b.Len() { + panic("bytes.Buffer: truncation out of range") + } + b.buf = b.buf[:b.off+n] +} + +// Reset resets the buffer to be empty, +// but it retains the underlying storage for use by future writes. +// Reset is the same as [Buffer.Truncate](0). +func (b *Buffer) Reset() { + b.buf = b.buf[:0] + b.off = 0 + b.lastRead = opInvalid +} + +// tryGrowByReslice is an inlineable version of grow for the fast-case where the +// internal buffer only needs to be resliced. +// It returns the index where bytes should be written and whether it succeeded. +func (b *Buffer) tryGrowByReslice(n int) (int, bool) { + if l := len(b.buf); n <= cap(b.buf)-l { + b.buf = b.buf[:l+n] + return l, true + } + return 0, false +} + +// grow grows the buffer to guarantee space for n more bytes. +// It returns the index where bytes should be written. +// If the buffer can't grow it will panic with ErrTooLarge. +func (b *Buffer) grow(n int) int { + m := b.Len() + // If buffer is empty, reset to recover space. + if m == 0 && b.off != 0 { + b.Reset() + } + // Try to grow by means of a reslice. + if i, ok := b.tryGrowByReslice(n); ok { + return i + } + if b.buf == nil && n <= smallBufferSize { + b.buf = make([]byte, n, smallBufferSize) + return 0 + } + c := cap(b.buf) + if n <= c/2-m { + // We can slide things down instead of allocating a new + // slice. We only need m+n <= c to slide, but + // we instead let capacity get twice as large so we + // don't spend all our time copying. + copy(b.buf, b.buf[b.off:]) + } else if c > maxInt-c-n { + panic(ErrTooLarge) + } else { + // Add b.off to account for b.buf[:b.off] being sliced off the front. + b.buf = growSlice(b.buf[b.off:], b.off+n) + } + // Restore b.off and len(b.buf). + b.off = 0 + b.buf = b.buf[:m+n] + return m +} + +// Grow grows the buffer's capacity, if necessary, to guarantee space for +// another n bytes. After Grow(n), at least n bytes can be written to the +// buffer without another allocation. +// If n is negative, Grow will panic. +// If the buffer can't grow it will panic with [ErrTooLarge]. +func (b *Buffer) Grow(n int) { + if n < 0 { + panic("bytes.Buffer.Grow: negative count") + } + m := b.grow(n) + b.buf = b.buf[:m] +} + +// Write appends the contents of p to the buffer, growing the buffer as +// needed. The return value n is the length of p; err is always nil. If the +// buffer becomes too large, Write will panic with [ErrTooLarge]. +func (b *Buffer) Write(p []byte) (n int, err error) { + b.lastRead = opInvalid + m, ok := b.tryGrowByReslice(len(p)) + if !ok { + m = b.grow(len(p)) + } + return copy(b.buf[m:], p), nil +} + +// WriteString appends the contents of s to the buffer, growing the buffer as +// needed. The return value n is the length of s; err is always nil. If the +// buffer becomes too large, WriteString will panic with [ErrTooLarge]. +func (b *Buffer) WriteString(s string) (n int, err error) { + b.lastRead = opInvalid + m, ok := b.tryGrowByReslice(len(s)) + if !ok { + m = b.grow(len(s)) + } + return copy(b.buf[m:], s), nil +} + +// MinRead is the minimum slice size passed to a [Buffer.Read] call by +// [Buffer.ReadFrom]. As long as the [Buffer] has at least MinRead bytes beyond +// what is required to hold the contents of r, [Buffer.ReadFrom] will not grow the +// underlying buffer. +const MinRead = 512 + +// ReadFrom reads data from r until EOF and appends it to the buffer, growing +// the buffer as needed. The return value n is the number of bytes read. Any +// error except io.EOF encountered during the read is also returned. If the +// buffer becomes too large, ReadFrom will panic with [ErrTooLarge]. +func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { + b.lastRead = opInvalid + for { + i := b.grow(MinRead) + b.buf = b.buf[:i] + m, e := r.Read(b.buf[i:cap(b.buf)]) + if m < 0 { + panic(errNegativeRead) + } + + b.buf = b.buf[:i+m] + n += int64(m) + if e == io.EOF { + return n, nil // e is EOF, so return nil explicitly + } + if e != nil { + return n, e + } + } +} + +// growSlice grows b by n, preserving the original content of b. +// If the allocation fails, it panics with ErrTooLarge. +func growSlice(b []byte, n int) []byte { + defer func() { + if recover() != nil { + panic(ErrTooLarge) + } + }() + // TODO(http://golang.org/issue/51462): We should rely on the append-make + // pattern so that the compiler can call runtime.growslice. For example: + // return append(b, make([]byte, n)...) + // This avoids unnecessary zero-ing of the first len(b) bytes of the + // allocated slice, but this pattern causes b to escape onto the heap. + // + // Instead use the append-make pattern with a nil slice to ensure that + // we allocate buffers rounded up to the closest size class. + c := len(b) + n // ensure enough space for n elements + if c < 2*cap(b) { + // The growth rate has historically always been 2x. In the future, + // we could rely purely on append to determine the growth rate. + c = 2 * cap(b) + } + b2 := append([]byte(nil), make([]byte, c)...) + copy(b2, b) + return b2[:len(b)] +} + +// WriteTo writes data to w until the buffer is drained or an error occurs. +// The return value n is the number of bytes written; it always fits into an +// int, but it is int64 to match the [io.WriterTo] interface. Any error +// encountered during the write is also returned. +func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) { + b.lastRead = opInvalid + if nBytes := b.Len(); nBytes > 0 { + m, e := w.Write(b.buf[b.off:]) + if m > nBytes { + panic("bytes.Buffer.WriteTo: invalid Write count") + } + b.off += m + n = int64(m) + if e != nil { + return n, e + } + // all bytes should have been written, by definition of + // Write method in io.Writer + if m != nBytes { + return n, io.ErrShortWrite + } + } + // Buffer is now empty; reset. + b.Reset() + return n, nil +} + +// WriteByte appends the byte c to the buffer, growing the buffer as needed. +// The returned error is always nil, but is included to match [bufio.Writer]'s +// WriteByte. If the buffer becomes too large, WriteByte will panic with +// [ErrTooLarge]. +func (b *Buffer) WriteByte(c byte) error { + b.lastRead = opInvalid + m, ok := b.tryGrowByReslice(1) + if !ok { + m = b.grow(1) + } + b.buf[m] = c + return nil +} + +// WriteRune appends the UTF-8 encoding of Unicode code point r to the +// buffer, returning its length and an error, which is always nil but is +// included to match [bufio.Writer]'s WriteRune. The buffer is grown as needed; +// if it becomes too large, WriteRune will panic with [ErrTooLarge]. +func (b *Buffer) WriteRune(r rune) (n int, err error) { + // Compare as uint32 to correctly handle negative runes. + if uint32(r) < utf8.RuneSelf { + b.WriteByte(byte(r)) + return 1, nil + } + b.lastRead = opInvalid + m, ok := b.tryGrowByReslice(utf8.UTFMax) + if !ok { + m = b.grow(utf8.UTFMax) + } + b.buf = utf8.AppendRune(b.buf[:m], r) + return len(b.buf) - m, nil +} + +// Read reads the next len(p) bytes from the buffer or until the buffer +// is drained. The return value n is the number of bytes read. If the +// buffer has no data to return, err is [io.EOF] (unless len(p) is zero); +// otherwise it is nil. +func (b *Buffer) Read(p []byte) (n int, err error) { + b.lastRead = opInvalid + if b.empty() { + // Buffer is empty, reset to recover space. + b.Reset() + if len(p) == 0 { + return 0, nil + } + return 0, io.EOF + } + n = copy(p, b.buf[b.off:]) + b.off += n + if n > 0 { + b.lastRead = opRead + } + return n, nil +} + +// Next returns a slice containing the next n bytes from the buffer, +// advancing the buffer as if the bytes had been returned by [Buffer.Read]. +// If there are fewer than n bytes in the buffer, Next returns the entire buffer. +// The slice is only valid until the next call to a read or write method. +func (b *Buffer) Next(n int) []byte { + b.lastRead = opInvalid + m := b.Len() + if n > m { + n = m + } + data := b.buf[b.off : b.off+n] + b.off += n + if n > 0 { + b.lastRead = opRead + } + return data +} + +// ReadByte reads and returns the next byte from the buffer. +// If no byte is available, it returns error [io.EOF]. +func (b *Buffer) ReadByte() (byte, error) { + if b.empty() { + // Buffer is empty, reset to recover space. + b.Reset() + return 0, io.EOF + } + c := b.buf[b.off] + b.off++ + b.lastRead = opRead + return c, nil +} + +// ReadRune reads and returns the next UTF-8-encoded +// Unicode code point from the buffer. +// If no bytes are available, the error returned is io.EOF. +// If the bytes are an erroneous UTF-8 encoding, it +// consumes one byte and returns U+FFFD, 1. +func (b *Buffer) ReadRune() (r rune, size int, err error) { + if b.empty() { + // Buffer is empty, reset to recover space. + b.Reset() + return 0, 0, io.EOF + } + c := b.buf[b.off] + if c < utf8.RuneSelf { + b.off++ + b.lastRead = opReadRune1 + return rune(c), 1, nil + } + r, n := utf8.DecodeRune(b.buf[b.off:]) + b.off += n + b.lastRead = readOp(n) + return r, n, nil +} + +// UnreadRune unreads the last rune returned by [Buffer.ReadRune]. +// If the most recent read or write operation on the buffer was +// not a successful [Buffer.ReadRune], UnreadRune returns an error. (In this regard +// it is stricter than [Buffer.UnreadByte], which will unread the last byte +// from any read operation.) +func (b *Buffer) UnreadRune() error { + if b.lastRead <= opInvalid { + return errors.New("bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune") + } + if b.off >= int(b.lastRead) { + b.off -= int(b.lastRead) + } + b.lastRead = opInvalid + return nil +} + +var errUnreadByte = errors.New("bytes.Buffer: UnreadByte: previous operation was not a successful read") + +// UnreadByte unreads the last byte returned by the most recent successful +// read operation that read at least one byte. If a write has happened since +// the last read, if the last read returned an error, or if the read read zero +// bytes, UnreadByte returns an error. +func (b *Buffer) UnreadByte() error { + if b.lastRead == opInvalid { + return errUnreadByte + } + b.lastRead = opInvalid + if b.off > 0 { + b.off-- + } + return nil +} + +// ReadBytes reads until the first occurrence of delim in the input, +// returning a slice containing the data up to and including the delimiter. +// If ReadBytes encounters an error before finding a delimiter, +// it returns the data read before the error and the error itself (often [io.EOF]). +// ReadBytes returns err != nil if and only if the returned data does not end in +// delim. +func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) { + slice, err := b.readSlice(delim) + // return a copy of slice. The buffer's backing array may + // be overwritten by later calls. + line = append(line, slice...) + return line, err +} + +// readSlice is like ReadBytes but returns a reference to internal buffer data. +func (b *Buffer) readSlice(delim byte) (line []byte, err error) { + i := IndexByte(b.buf[b.off:], delim) + end := b.off + i + 1 + if i < 0 { + end = len(b.buf) + err = io.EOF + } + line = b.buf[b.off:end] + b.off = end + b.lastRead = opRead + return line, err +} + +// ReadString reads until the first occurrence of delim in the input, +// returning a string containing the data up to and including the delimiter. +// If ReadString encounters an error before finding a delimiter, +// it returns the data read before the error and the error itself (often [io.EOF]). +// ReadString returns err != nil if and only if the returned data does not end +// in delim. +func (b *Buffer) ReadString(delim byte) (line string, err error) { + slice, err := b.readSlice(delim) + return string(slice), err +} + +// NewBuffer creates and initializes a new [Buffer] using buf as its +// initial contents. The new [Buffer] takes ownership of buf, and the +// caller should not use buf after this call. NewBuffer is intended to +// prepare a [Buffer] to read existing data. It can also be used to set +// the initial size of the internal buffer for writing. To do that, +// buf should have the desired capacity but a length of zero. +// +// In most cases, new([Buffer]) (or just declaring a [Buffer] variable) is +// sufficient to initialize a [Buffer]. +func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } + +// NewBufferString creates and initializes a new [Buffer] using string s as its +// initial contents. It is intended to prepare a buffer to read an existing +// string. +// +// In most cases, new([Buffer]) (or just declaring a [Buffer] variable) is +// sufficient to initialize a [Buffer]. +func NewBufferString(s string) *Buffer { + return &Buffer{buf: []byte(s)} +} diff --git a/contrib/go/_std_1.22/src/bytes/bytes.go b/contrib/go/_std_1.23/src/bytes/bytes.go similarity index 96% rename from contrib/go/_std_1.22/src/bytes/bytes.go rename to contrib/go/_std_1.23/src/bytes/bytes.go index 0679b43a20a3..45d8d0747535 100644 --- a/contrib/go/_std_1.22/src/bytes/bytes.go +++ b/contrib/go/_std_1.23/src/bytes/bytes.go @@ -10,6 +10,7 @@ import ( "internal/bytealg" "unicode" "unicode/utf8" + _ "unsafe" // for linkname ) // Equal reports whether a and b @@ -132,7 +133,7 @@ func LastIndexByte(s []byte, c byte) int { // IndexRune interprets s as a sequence of UTF-8-encoded code points. // It returns the byte index of the first occurrence in s of the given rune. // It returns -1 if rune is not present in s. -// If r is utf8.RuneError, it returns the first instance of any +// If r is [utf8.RuneError], it returns the first instance of any // invalid UTF-8 byte sequence. func IndexRune(s []byte, r rune) int { switch { @@ -354,22 +355,20 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte { // the subslices between those separators. // If sep is empty, SplitN splits after each UTF-8 sequence. // The count determines the number of subslices to return: +// - n > 0: at most n subslices; the last subslice will be the unsplit remainder; +// - n == 0: the result is nil (zero subslices); +// - n < 0: all subslices. // -// n > 0: at most n subslices; the last subslice will be the unsplit remainder. -// n == 0: the result is nil (zero subslices) -// n < 0: all subslices -// -// To split around the first instance of a separator, see Cut. +// To split around the first instance of a separator, see [Cut]. func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) } // SplitAfterN slices s into subslices after each instance of sep and // returns a slice of those subslices. // If sep is empty, SplitAfterN splits after each UTF-8 sequence. // The count determines the number of subslices to return: -// -// n > 0: at most n subslices; the last subslice will be the unsplit remainder. -// n == 0: the result is nil (zero subslices) -// n < 0: all subslices +// - n > 0: at most n subslices; the last subslice will be the unsplit remainder; +// - n == 0: the result is nil (zero subslices); +// - n < 0: all subslices. func SplitAfterN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, len(sep), n) } @@ -379,7 +378,7 @@ func SplitAfterN(s, sep []byte, n int) [][]byte { // If sep is empty, Split splits after each UTF-8 sequence. // It is equivalent to SplitN with a count of -1. // -// To split around the first instance of a separator, see Cut. +// To split around the first instance of a separator, see [Cut]. func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) } // SplitAfter slices s into all subslices after each instance of sep and @@ -394,7 +393,7 @@ var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1} // Fields interprets s as a sequence of UTF-8-encoded code points. // It splits the slice s around each instance of one or more consecutive white space -// characters, as defined by unicode.IsSpace, returning a slice of subslices of s or an +// characters, as defined by [unicode.IsSpace], returning a slice of subslices of s or an // empty slice if s contains only white space. func Fields(s []byte) [][]byte { // First count the fields. @@ -525,7 +524,7 @@ func Join(s [][]byte, sep []byte) []byte { n += len(v) } - b := bytealg.MakeNoZero(n) + b := bytealg.MakeNoZero(n)[:n:n] bp := copy(b, s[0]) for _, v := range s[1:] { bp += copy(b[bp:], sep) @@ -568,6 +567,18 @@ func Map(mapping func(r rune) rune, s []byte) []byte { return b } +// Despite being an exported symbol, +// Repeat is linknamed by widely used packages. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/num +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +// Note that this comment is not part of the doc comment. +// +//go:linkname Repeat + // Repeat returns a new byte slice consisting of count copies of b. // // It panics if count is negative or if the result of (len(b) * count) @@ -583,7 +594,7 @@ func Repeat(b []byte, count int) []byte { if count < 0 { panic("bytes: negative Repeat count") } - if len(b) >= maxInt/count { + if len(b) > maxInt/count { panic("bytes: Repeat output length overflow") } n := len(b) * count @@ -610,7 +621,7 @@ func Repeat(b []byte, count int) []byte { chunkMax = len(b) } } - nb := bytealg.MakeNoZero(n) + nb := bytealg.MakeNoZero(n)[:n:n] bp := copy(nb, b) for bp < n { chunk := bp @@ -640,7 +651,7 @@ func ToUpper(s []byte) []byte { // Just return a copy. return append([]byte(""), s...) } - b := bytealg.MakeNoZero(len(s)) + b := bytealg.MakeNoZero(len(s))[:len(s):len(s)] for i := 0; i < len(s); i++ { c := s[i] if 'a' <= c && c <= 'z' { @@ -670,7 +681,7 @@ func ToLower(s []byte) []byte { if !hasUpper { return append([]byte(""), s...) } - b := bytealg.MakeNoZero(len(s)) + b := bytealg.MakeNoZero(len(s))[:len(s):len(s)] for i := 0; i < len(s); i++ { c := s[i] if 'A' <= c && c <= 'Z' { diff --git a/contrib/go/_std_1.23/src/bytes/reader.go b/contrib/go/_std_1.23/src/bytes/reader.go new file mode 100644 index 000000000000..d4c3066e0620 --- /dev/null +++ b/contrib/go/_std_1.23/src/bytes/reader.go @@ -0,0 +1,159 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bytes + +import ( + "errors" + "io" + "unicode/utf8" +) + +// A Reader implements the [io.Reader], [io.ReaderAt], [io.WriterTo], [io.Seeker], +// [io.ByteScanner], and [io.RuneScanner] interfaces by reading from +// a byte slice. +// Unlike a [Buffer], a Reader is read-only and supports seeking. +// The zero value for Reader operates like a Reader of an empty slice. +type Reader struct { + s []byte + i int64 // current reading index + prevRune int // index of previous rune; or < 0 +} + +// Len returns the number of bytes of the unread portion of the +// slice. +func (r *Reader) Len() int { + if r.i >= int64(len(r.s)) { + return 0 + } + return int(int64(len(r.s)) - r.i) +} + +// Size returns the original length of the underlying byte slice. +// Size is the number of bytes available for reading via [Reader.ReadAt]. +// The result is unaffected by any method calls except [Reader.Reset]. +func (r *Reader) Size() int64 { return int64(len(r.s)) } + +// Read implements the [io.Reader] interface. +func (r *Reader) Read(b []byte) (n int, err error) { + if r.i >= int64(len(r.s)) { + return 0, io.EOF + } + r.prevRune = -1 + n = copy(b, r.s[r.i:]) + r.i += int64(n) + return +} + +// ReadAt implements the [io.ReaderAt] interface. +func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) { + // cannot modify state - see io.ReaderAt + if off < 0 { + return 0, errors.New("bytes.Reader.ReadAt: negative offset") + } + if off >= int64(len(r.s)) { + return 0, io.EOF + } + n = copy(b, r.s[off:]) + if n < len(b) { + err = io.EOF + } + return +} + +// ReadByte implements the [io.ByteReader] interface. +func (r *Reader) ReadByte() (byte, error) { + r.prevRune = -1 + if r.i >= int64(len(r.s)) { + return 0, io.EOF + } + b := r.s[r.i] + r.i++ + return b, nil +} + +// UnreadByte complements [Reader.ReadByte] in implementing the [io.ByteScanner] interface. +func (r *Reader) UnreadByte() error { + if r.i <= 0 { + return errors.New("bytes.Reader.UnreadByte: at beginning of slice") + } + r.prevRune = -1 + r.i-- + return nil +} + +// ReadRune implements the [io.RuneReader] interface. +func (r *Reader) ReadRune() (ch rune, size int, err error) { + if r.i >= int64(len(r.s)) { + r.prevRune = -1 + return 0, 0, io.EOF + } + r.prevRune = int(r.i) + if c := r.s[r.i]; c < utf8.RuneSelf { + r.i++ + return rune(c), 1, nil + } + ch, size = utf8.DecodeRune(r.s[r.i:]) + r.i += int64(size) + return +} + +// UnreadRune complements [Reader.ReadRune] in implementing the [io.RuneScanner] interface. +func (r *Reader) UnreadRune() error { + if r.i <= 0 { + return errors.New("bytes.Reader.UnreadRune: at beginning of slice") + } + if r.prevRune < 0 { + return errors.New("bytes.Reader.UnreadRune: previous operation was not ReadRune") + } + r.i = int64(r.prevRune) + r.prevRune = -1 + return nil +} + +// Seek implements the [io.Seeker] interface. +func (r *Reader) Seek(offset int64, whence int) (int64, error) { + r.prevRune = -1 + var abs int64 + switch whence { + case io.SeekStart: + abs = offset + case io.SeekCurrent: + abs = r.i + offset + case io.SeekEnd: + abs = int64(len(r.s)) + offset + default: + return 0, errors.New("bytes.Reader.Seek: invalid whence") + } + if abs < 0 { + return 0, errors.New("bytes.Reader.Seek: negative position") + } + r.i = abs + return abs, nil +} + +// WriteTo implements the [io.WriterTo] interface. +func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { + r.prevRune = -1 + if r.i >= int64(len(r.s)) { + return 0, nil + } + b := r.s[r.i:] + m, err := w.Write(b) + if m > len(b) { + panic("bytes.Reader.WriteTo: invalid Write count") + } + r.i += int64(m) + n = int64(m) + if m != len(b) && err == nil { + err = io.ErrShortWrite + } + return +} + +// Reset resets the [Reader] to be reading from b. +func (r *Reader) Reset(b []byte) { *r = Reader{b, 0, -1} } + +// NewReader returns a new [Reader] reading from b. +func NewReader(b []byte) *Reader { return &Reader{b, 0, -1} } diff --git a/contrib/go/_std_1.22/src/bytes/ya.make b/contrib/go/_std_1.23/src/bytes/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/bytes/ya.make rename to contrib/go/_std_1.23/src/bytes/ya.make diff --git a/contrib/go/_std_1.22/src/cmp/cmp.go b/contrib/go/_std_1.23/src/cmp/cmp.go similarity index 95% rename from contrib/go/_std_1.22/src/cmp/cmp.go rename to contrib/go/_std_1.23/src/cmp/cmp.go index 4d1af6a98c4e..a13834c39858 100644 --- a/contrib/go/_std_1.22/src/cmp/cmp.go +++ b/contrib/go/_std_1.23/src/cmp/cmp.go @@ -40,13 +40,19 @@ func Less[T Ordered](x, y T) bool { func Compare[T Ordered](x, y T) int { xNaN := isNaN(x) yNaN := isNaN(y) - if xNaN && yNaN { - return 0 + if xNaN { + if yNaN { + return 0 + } + return -1 + } + if yNaN { + return +1 } - if xNaN || x < y { + if x < y { return -1 } - if yNaN || x > y { + if x > y { return +1 } return 0 diff --git a/contrib/go/_std_1.22/src/cmp/ya.make b/contrib/go/_std_1.23/src/cmp/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/cmp/ya.make rename to contrib/go/_std_1.23/src/cmp/ya.make diff --git a/contrib/go/_std_1.22/src/compress/flate/deflate.go b/contrib/go/_std_1.23/src/compress/flate/deflate.go similarity index 99% rename from contrib/go/_std_1.22/src/compress/flate/deflate.go rename to contrib/go/_std_1.23/src/compress/flate/deflate.go index ea343b2298f3..0e07afab7de7 100644 --- a/contrib/go/_std_1.22/src/compress/flate/deflate.go +++ b/contrib/go/_std_1.23/src/compress/flate/deflate.go @@ -87,7 +87,6 @@ type compressor struct { // compression algorithm fill func(*compressor, []byte) int // copy data to window step func(*compressor) // process window - sync bool // requesting flush bestSpeed *deflateFast // Encoder for BestSpeed // Input hash chains @@ -107,6 +106,8 @@ type compressor struct { blockStart int // window index where current tokens start byteAvailable bool // if true, still need to process window[index-1]. + sync bool // requesting flush + // queued output tokens tokens []token diff --git a/contrib/go/_std_1.22/src/compress/flate/deflatefast.go b/contrib/go/_std_1.23/src/compress/flate/deflatefast.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/deflatefast.go rename to contrib/go/_std_1.23/src/compress/flate/deflatefast.go diff --git a/contrib/go/_std_1.22/src/compress/flate/dict_decoder.go b/contrib/go/_std_1.23/src/compress/flate/dict_decoder.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/dict_decoder.go rename to contrib/go/_std_1.23/src/compress/flate/dict_decoder.go diff --git a/contrib/go/_std_1.22/src/compress/flate/huffman_bit_writer.go b/contrib/go/_std_1.23/src/compress/flate/huffman_bit_writer.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/huffman_bit_writer.go rename to contrib/go/_std_1.23/src/compress/flate/huffman_bit_writer.go diff --git a/contrib/go/_std_1.22/src/compress/flate/huffman_code.go b/contrib/go/_std_1.23/src/compress/flate/huffman_code.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/huffman_code.go rename to contrib/go/_std_1.23/src/compress/flate/huffman_code.go diff --git a/contrib/go/_std_1.22/src/compress/flate/inflate.go b/contrib/go/_std_1.23/src/compress/flate/inflate.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/inflate.go rename to contrib/go/_std_1.23/src/compress/flate/inflate.go diff --git a/contrib/go/_std_1.22/src/compress/flate/token.go b/contrib/go/_std_1.23/src/compress/flate/token.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/token.go rename to contrib/go/_std_1.23/src/compress/flate/token.go diff --git a/contrib/go/_std_1.22/src/compress/flate/ya.make b/contrib/go/_std_1.23/src/compress/flate/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/ya.make rename to contrib/go/_std_1.23/src/compress/flate/ya.make diff --git a/contrib/go/_std_1.22/src/compress/gzip/gunzip.go b/contrib/go/_std_1.23/src/compress/gzip/gunzip.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/gzip/gunzip.go rename to contrib/go/_std_1.23/src/compress/gzip/gunzip.go diff --git a/contrib/go/_std_1.22/src/compress/gzip/gzip.go b/contrib/go/_std_1.23/src/compress/gzip/gzip.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/gzip/gzip.go rename to contrib/go/_std_1.23/src/compress/gzip/gzip.go index ab4598d89fda..5f24444237ce 100644 --- a/contrib/go/_std_1.22/src/compress/gzip/gzip.go +++ b/contrib/go/_std_1.23/src/compress/gzip/gzip.go @@ -30,11 +30,11 @@ type Writer struct { w io.Writer level int wroteHeader bool + closed bool + buf [10]byte compressor *flate.Writer digest uint32 // CRC-32, IEEE polynomial (section 8) size uint32 // Uncompressed size (section 2.3.1) - closed bool - buf [10]byte err error } diff --git a/contrib/go/_std_1.22/src/compress/gzip/ya.make b/contrib/go/_std_1.23/src/compress/gzip/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/compress/gzip/ya.make rename to contrib/go/_std_1.23/src/compress/gzip/ya.make diff --git a/contrib/go/_std_1.22/src/container/heap/heap.go b/contrib/go/_std_1.23/src/container/heap/heap.go similarity index 100% rename from contrib/go/_std_1.22/src/container/heap/heap.go rename to contrib/go/_std_1.23/src/container/heap/heap.go diff --git a/contrib/go/_std_1.22/src/container/heap/ya.make b/contrib/go/_std_1.23/src/container/heap/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/container/heap/ya.make rename to contrib/go/_std_1.23/src/container/heap/ya.make diff --git a/contrib/go/_std_1.22/src/container/list/list.go b/contrib/go/_std_1.23/src/container/list/list.go similarity index 100% rename from contrib/go/_std_1.22/src/container/list/list.go rename to contrib/go/_std_1.23/src/container/list/list.go diff --git a/contrib/go/_std_1.22/src/container/list/ya.make b/contrib/go/_std_1.23/src/container/list/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/container/list/ya.make rename to contrib/go/_std_1.23/src/container/list/ya.make diff --git a/contrib/go/_std_1.23/src/context/context.go b/contrib/go/_std_1.23/src/context/context.go new file mode 100644 index 000000000000..763d4f777ffb --- /dev/null +++ b/contrib/go/_std_1.23/src/context/context.go @@ -0,0 +1,792 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package context defines the Context type, which carries deadlines, +// cancellation signals, and other request-scoped values across API boundaries +// and between processes. +// +// Incoming requests to a server should create a [Context], and outgoing +// calls to servers should accept a Context. The chain of function +// calls between them must propagate the Context, optionally replacing +// it with a derived Context created using [WithCancel], [WithDeadline], +// [WithTimeout], or [WithValue]. When a Context is canceled, all +// Contexts derived from it are also canceled. +// +// The [WithCancel], [WithDeadline], and [WithTimeout] functions take a +// Context (the parent) and return a derived Context (the child) and a +// [CancelFunc]. Calling the CancelFunc cancels the child and its +// children, removes the parent's reference to the child, and stops +// any associated timers. Failing to call the CancelFunc leaks the +// child and its children until the parent is canceled or the timer +// fires. The go vet tool checks that CancelFuncs are used on all +// control-flow paths. +// +// The [WithCancelCause] function returns a [CancelCauseFunc], which +// takes an error and records it as the cancellation cause. Calling +// [Cause] on the canceled context or any of its children retrieves +// the cause. If no cause is specified, Cause(ctx) returns the same +// value as ctx.Err(). +// +// Programs that use Contexts should follow these rules to keep interfaces +// consistent across packages and enable static analysis tools to check context +// propagation: +// +// Do not store Contexts inside a struct type; instead, pass a Context +// explicitly to each function that needs it. The Context should be the first +// parameter, typically named ctx: +// +// func DoSomething(ctx context.Context, arg Arg) error { +// // ... use ctx ... +// } +// +// Do not pass a nil [Context], even if a function permits it. Pass [context.TODO] +// if you are unsure about which Context to use. +// +// Use context Values only for request-scoped data that transits processes and +// APIs, not for passing optional parameters to functions. +// +// The same Context may be passed to functions running in different goroutines; +// Contexts are safe for simultaneous use by multiple goroutines. +// +// See https://blog.golang.org/context for example code for a server that uses +// Contexts. +package context + +import ( + "errors" + "internal/reflectlite" + "sync" + "sync/atomic" + "time" +) + +// A Context carries a deadline, a cancellation signal, and other values across +// API boundaries. +// +// Context's methods may be called by multiple goroutines simultaneously. +type Context interface { + // Deadline returns the time when work done on behalf of this context + // should be canceled. Deadline returns ok==false when no deadline is + // set. Successive calls to Deadline return the same results. + Deadline() (deadline time.Time, ok bool) + + // Done returns a channel that's closed when work done on behalf of this + // context should be canceled. Done may return nil if this context can + // never be canceled. Successive calls to Done return the same value. + // The close of the Done channel may happen asynchronously, + // after the cancel function returns. + // + // WithCancel arranges for Done to be closed when cancel is called; + // WithDeadline arranges for Done to be closed when the deadline + // expires; WithTimeout arranges for Done to be closed when the timeout + // elapses. + // + // Done is provided for use in select statements: + // + // // Stream generates values with DoSomething and sends them to out + // // until DoSomething returns an error or ctx.Done is closed. + // func Stream(ctx context.Context, out chan<- Value) error { + // for { + // v, err := DoSomething(ctx) + // if err != nil { + // return err + // } + // select { + // case <-ctx.Done(): + // return ctx.Err() + // case out <- v: + // } + // } + // } + // + // See https://blog.golang.org/pipelines for more examples of how to use + // a Done channel for cancellation. + Done() <-chan struct{} + + // If Done is not yet closed, Err returns nil. + // If Done is closed, Err returns a non-nil error explaining why: + // Canceled if the context was canceled + // or DeadlineExceeded if the context's deadline passed. + // After Err returns a non-nil error, successive calls to Err return the same error. + Err() error + + // Value returns the value associated with this context for key, or nil + // if no value is associated with key. Successive calls to Value with + // the same key returns the same result. + // + // Use context values only for request-scoped data that transits + // processes and API boundaries, not for passing optional parameters to + // functions. + // + // A key identifies a specific value in a Context. Functions that wish + // to store values in Context typically allocate a key in a global + // variable then use that key as the argument to context.WithValue and + // Context.Value. A key can be any type that supports equality; + // packages should define keys as an unexported type to avoid + // collisions. + // + // Packages that define a Context key should provide type-safe accessors + // for the values stored using that key: + // + // // Package user defines a User type that's stored in Contexts. + // package user + // + // import "context" + // + // // User is the type of value stored in the Contexts. + // type User struct {...} + // + // // key is an unexported type for keys defined in this package. + // // This prevents collisions with keys defined in other packages. + // type key int + // + // // userKey is the key for user.User values in Contexts. It is + // // unexported; clients use user.NewContext and user.FromContext + // // instead of using this key directly. + // var userKey key + // + // // NewContext returns a new Context that carries value u. + // func NewContext(ctx context.Context, u *User) context.Context { + // return context.WithValue(ctx, userKey, u) + // } + // + // // FromContext returns the User value stored in ctx, if any. + // func FromContext(ctx context.Context) (*User, bool) { + // u, ok := ctx.Value(userKey).(*User) + // return u, ok + // } + Value(key any) any +} + +// Canceled is the error returned by [Context.Err] when the context is canceled. +var Canceled = errors.New("context canceled") + +// DeadlineExceeded is the error returned by [Context.Err] when the context's +// deadline passes. +var DeadlineExceeded error = deadlineExceededError{} + +type deadlineExceededError struct{} + +func (deadlineExceededError) Error() string { return "context deadline exceeded" } +func (deadlineExceededError) Timeout() bool { return true } +func (deadlineExceededError) Temporary() bool { return true } + +// An emptyCtx is never canceled, has no values, and has no deadline. +// It is the common base of backgroundCtx and todoCtx. +type emptyCtx struct{} + +func (emptyCtx) Deadline() (deadline time.Time, ok bool) { + return +} + +func (emptyCtx) Done() <-chan struct{} { + return nil +} + +func (emptyCtx) Err() error { + return nil +} + +func (emptyCtx) Value(key any) any { + return nil +} + +type backgroundCtx struct{ emptyCtx } + +func (backgroundCtx) String() string { + return "context.Background" +} + +type todoCtx struct{ emptyCtx } + +func (todoCtx) String() string { + return "context.TODO" +} + +// Background returns a non-nil, empty [Context]. It is never canceled, has no +// values, and has no deadline. It is typically used by the main function, +// initialization, and tests, and as the top-level Context for incoming +// requests. +func Background() Context { + return backgroundCtx{} +} + +// TODO returns a non-nil, empty [Context]. Code should use context.TODO when +// it's unclear which Context to use or it is not yet available (because the +// surrounding function has not yet been extended to accept a Context +// parameter). +func TODO() Context { + return todoCtx{} +} + +// A CancelFunc tells an operation to abandon its work. +// A CancelFunc does not wait for the work to stop. +// A CancelFunc may be called by multiple goroutines simultaneously. +// After the first call, subsequent calls to a CancelFunc do nothing. +type CancelFunc func() + +// WithCancel returns a copy of parent with a new Done channel. The returned +// context's Done channel is closed when the returned cancel function is called +// or when the parent context's Done channel is closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this [Context] complete. +func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { + c := withCancel(parent) + return c, func() { c.cancel(true, Canceled, nil) } +} + +// A CancelCauseFunc behaves like a [CancelFunc] but additionally sets the cancellation cause. +// This cause can be retrieved by calling [Cause] on the canceled Context or on +// any of its derived Contexts. +// +// If the context has already been canceled, CancelCauseFunc does not set the cause. +// For example, if childContext is derived from parentContext: +// - if parentContext is canceled with cause1 before childContext is canceled with cause2, +// then Cause(parentContext) == Cause(childContext) == cause1 +// - if childContext is canceled with cause2 before parentContext is canceled with cause1, +// then Cause(parentContext) == cause1 and Cause(childContext) == cause2 +type CancelCauseFunc func(cause error) + +// WithCancelCause behaves like [WithCancel] but returns a [CancelCauseFunc] instead of a [CancelFunc]. +// Calling cancel with a non-nil error (the "cause") records that error in ctx; +// it can then be retrieved using Cause(ctx). +// Calling cancel with nil sets the cause to Canceled. +// +// Example use: +// +// ctx, cancel := context.WithCancelCause(parent) +// cancel(myError) +// ctx.Err() // returns context.Canceled +// context.Cause(ctx) // returns myError +func WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc) { + c := withCancel(parent) + return c, func(cause error) { c.cancel(true, Canceled, cause) } +} + +func withCancel(parent Context) *cancelCtx { + if parent == nil { + panic("cannot create context from nil parent") + } + c := &cancelCtx{} + c.propagateCancel(parent, c) + return c +} + +// Cause returns a non-nil error explaining why c was canceled. +// The first cancellation of c or one of its parents sets the cause. +// If that cancellation happened via a call to CancelCauseFunc(err), +// then [Cause] returns err. +// Otherwise Cause(c) returns the same value as c.Err(). +// Cause returns nil if c has not been canceled yet. +func Cause(c Context) error { + if cc, ok := c.Value(&cancelCtxKey).(*cancelCtx); ok { + cc.mu.Lock() + defer cc.mu.Unlock() + return cc.cause + } + // There is no cancelCtxKey value, so we know that c is + // not a descendant of some Context created by WithCancelCause. + // Therefore, there is no specific cause to return. + // If this is not one of the standard Context types, + // it might still have an error even though it won't have a cause. + return c.Err() +} + +// AfterFunc arranges to call f in its own goroutine after ctx is done +// (canceled or timed out). +// If ctx is already done, AfterFunc calls f immediately in its own goroutine. +// +// Multiple calls to AfterFunc on a context operate independently; +// one does not replace another. +// +// Calling the returned stop function stops the association of ctx with f. +// It returns true if the call stopped f from being run. +// If stop returns false, +// either the context is done and f has been started in its own goroutine; +// or f was already stopped. +// The stop function does not wait for f to complete before returning. +// If the caller needs to know whether f is completed, +// it must coordinate with f explicitly. +// +// If ctx has a "AfterFunc(func()) func() bool" method, +// AfterFunc will use it to schedule the call. +func AfterFunc(ctx Context, f func()) (stop func() bool) { + a := &afterFuncCtx{ + f: f, + } + a.cancelCtx.propagateCancel(ctx, a) + return func() bool { + stopped := false + a.once.Do(func() { + stopped = true + }) + if stopped { + a.cancel(true, Canceled, nil) + } + return stopped + } +} + +type afterFuncer interface { + AfterFunc(func()) func() bool +} + +type afterFuncCtx struct { + cancelCtx + once sync.Once // either starts running f or stops f from running + f func() +} + +func (a *afterFuncCtx) cancel(removeFromParent bool, err, cause error) { + a.cancelCtx.cancel(false, err, cause) + if removeFromParent { + removeChild(a.Context, a) + } + a.once.Do(func() { + go a.f() + }) +} + +// A stopCtx is used as the parent context of a cancelCtx when +// an AfterFunc has been registered with the parent. +// It holds the stop function used to unregister the AfterFunc. +type stopCtx struct { + Context + stop func() bool +} + +// goroutines counts the number of goroutines ever created; for testing. +var goroutines atomic.Int32 + +// &cancelCtxKey is the key that a cancelCtx returns itself for. +var cancelCtxKey int + +// parentCancelCtx returns the underlying *cancelCtx for parent. +// It does this by looking up parent.Value(&cancelCtxKey) to find +// the innermost enclosing *cancelCtx and then checking whether +// parent.Done() matches that *cancelCtx. (If not, the *cancelCtx +// has been wrapped in a custom implementation providing a +// different done channel, in which case we should not bypass it.) +func parentCancelCtx(parent Context) (*cancelCtx, bool) { + done := parent.Done() + if done == closedchan || done == nil { + return nil, false + } + p, ok := parent.Value(&cancelCtxKey).(*cancelCtx) + if !ok { + return nil, false + } + pdone, _ := p.done.Load().(chan struct{}) + if pdone != done { + return nil, false + } + return p, true +} + +// removeChild removes a context from its parent. +func removeChild(parent Context, child canceler) { + if s, ok := parent.(stopCtx); ok { + s.stop() + return + } + p, ok := parentCancelCtx(parent) + if !ok { + return + } + p.mu.Lock() + if p.children != nil { + delete(p.children, child) + } + p.mu.Unlock() +} + +// A canceler is a context type that can be canceled directly. The +// implementations are *cancelCtx and *timerCtx. +type canceler interface { + cancel(removeFromParent bool, err, cause error) + Done() <-chan struct{} +} + +// closedchan is a reusable closed channel. +var closedchan = make(chan struct{}) + +func init() { + close(closedchan) +} + +// A cancelCtx can be canceled. When canceled, it also cancels any children +// that implement canceler. +type cancelCtx struct { + Context + + mu sync.Mutex // protects following fields + done atomic.Value // of chan struct{}, created lazily, closed by first cancel call + children map[canceler]struct{} // set to nil by the first cancel call + err error // set to non-nil by the first cancel call + cause error // set to non-nil by the first cancel call +} + +func (c *cancelCtx) Value(key any) any { + if key == &cancelCtxKey { + return c + } + return value(c.Context, key) +} + +func (c *cancelCtx) Done() <-chan struct{} { + d := c.done.Load() + if d != nil { + return d.(chan struct{}) + } + c.mu.Lock() + defer c.mu.Unlock() + d = c.done.Load() + if d == nil { + d = make(chan struct{}) + c.done.Store(d) + } + return d.(chan struct{}) +} + +func (c *cancelCtx) Err() error { + c.mu.Lock() + err := c.err + c.mu.Unlock() + return err +} + +// propagateCancel arranges for child to be canceled when parent is. +// It sets the parent context of cancelCtx. +func (c *cancelCtx) propagateCancel(parent Context, child canceler) { + c.Context = parent + + done := parent.Done() + if done == nil { + return // parent is never canceled + } + + select { + case <-done: + // parent is already canceled + child.cancel(false, parent.Err(), Cause(parent)) + return + default: + } + + if p, ok := parentCancelCtx(parent); ok { + // parent is a *cancelCtx, or derives from one. + p.mu.Lock() + if p.err != nil { + // parent has already been canceled + child.cancel(false, p.err, p.cause) + } else { + if p.children == nil { + p.children = make(map[canceler]struct{}) + } + p.children[child] = struct{}{} + } + p.mu.Unlock() + return + } + + if a, ok := parent.(afterFuncer); ok { + // parent implements an AfterFunc method. + c.mu.Lock() + stop := a.AfterFunc(func() { + child.cancel(false, parent.Err(), Cause(parent)) + }) + c.Context = stopCtx{ + Context: parent, + stop: stop, + } + c.mu.Unlock() + return + } + + goroutines.Add(1) + go func() { + select { + case <-parent.Done(): + child.cancel(false, parent.Err(), Cause(parent)) + case <-child.Done(): + } + }() +} + +type stringer interface { + String() string +} + +func contextName(c Context) string { + if s, ok := c.(stringer); ok { + return s.String() + } + return reflectlite.TypeOf(c).String() +} + +func (c *cancelCtx) String() string { + return contextName(c.Context) + ".WithCancel" +} + +// cancel closes c.done, cancels each of c's children, and, if +// removeFromParent is true, removes c from its parent's children. +// cancel sets c.cause to cause if this is the first time c is canceled. +func (c *cancelCtx) cancel(removeFromParent bool, err, cause error) { + if err == nil { + panic("context: internal error: missing cancel error") + } + if cause == nil { + cause = err + } + c.mu.Lock() + if c.err != nil { + c.mu.Unlock() + return // already canceled + } + c.err = err + c.cause = cause + d, _ := c.done.Load().(chan struct{}) + if d == nil { + c.done.Store(closedchan) + } else { + close(d) + } + for child := range c.children { + // NOTE: acquiring the child's lock while holding parent's lock. + child.cancel(false, err, cause) + } + c.children = nil + c.mu.Unlock() + + if removeFromParent { + removeChild(c.Context, c) + } +} + +// WithoutCancel returns a copy of parent that is not canceled when parent is canceled. +// The returned context returns no Deadline or Err, and its Done channel is nil. +// Calling [Cause] on the returned context returns nil. +func WithoutCancel(parent Context) Context { + if parent == nil { + panic("cannot create context from nil parent") + } + return withoutCancelCtx{parent} +} + +type withoutCancelCtx struct { + c Context +} + +func (withoutCancelCtx) Deadline() (deadline time.Time, ok bool) { + return +} + +func (withoutCancelCtx) Done() <-chan struct{} { + return nil +} + +func (withoutCancelCtx) Err() error { + return nil +} + +func (c withoutCancelCtx) Value(key any) any { + return value(c, key) +} + +func (c withoutCancelCtx) String() string { + return contextName(c.c) + ".WithoutCancel" +} + +// WithDeadline returns a copy of the parent context with the deadline adjusted +// to be no later than d. If the parent's deadline is already earlier than d, +// WithDeadline(parent, d) is semantically equivalent to parent. The returned +// [Context.Done] channel is closed when the deadline expires, when the returned +// cancel function is called, or when the parent context's Done channel is +// closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this [Context] complete. +func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) { + return WithDeadlineCause(parent, d, nil) +} + +// WithDeadlineCause behaves like [WithDeadline] but also sets the cause of the +// returned Context when the deadline is exceeded. The returned [CancelFunc] does +// not set the cause. +func WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc) { + if parent == nil { + panic("cannot create context from nil parent") + } + if cur, ok := parent.Deadline(); ok && cur.Before(d) { + // The current deadline is already sooner than the new one. + return WithCancel(parent) + } + c := &timerCtx{ + deadline: d, + } + c.cancelCtx.propagateCancel(parent, c) + dur := time.Until(d) + if dur <= 0 { + c.cancel(true, DeadlineExceeded, cause) // deadline has already passed + return c, func() { c.cancel(false, Canceled, nil) } + } + c.mu.Lock() + defer c.mu.Unlock() + if c.err == nil { + c.timer = time.AfterFunc(dur, func() { + c.cancel(true, DeadlineExceeded, cause) + }) + } + return c, func() { c.cancel(true, Canceled, nil) } +} + +// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to +// implement Done and Err. It implements cancel by stopping its timer then +// delegating to cancelCtx.cancel. +type timerCtx struct { + cancelCtx + timer *time.Timer // Under cancelCtx.mu. + + deadline time.Time +} + +func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { + return c.deadline, true +} + +func (c *timerCtx) String() string { + return contextName(c.cancelCtx.Context) + ".WithDeadline(" + + c.deadline.String() + " [" + + time.Until(c.deadline).String() + "])" +} + +func (c *timerCtx) cancel(removeFromParent bool, err, cause error) { + c.cancelCtx.cancel(false, err, cause) + if removeFromParent { + // Remove this timerCtx from its parent cancelCtx's children. + removeChild(c.cancelCtx.Context, c) + } + c.mu.Lock() + if c.timer != nil { + c.timer.Stop() + c.timer = nil + } + c.mu.Unlock() +} + +// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this [Context] complete: +// +// func slowOperationWithTimeout(ctx context.Context) (Result, error) { +// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) +// defer cancel() // releases resources if slowOperation completes before timeout elapses +// return slowOperation(ctx) +// } +func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { + return WithDeadline(parent, time.Now().Add(timeout)) +} + +// WithTimeoutCause behaves like [WithTimeout] but also sets the cause of the +// returned Context when the timeout expires. The returned [CancelFunc] does +// not set the cause. +func WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc) { + return WithDeadlineCause(parent, time.Now().Add(timeout), cause) +} + +// WithValue returns a copy of parent in which the value associated with key is +// val. +// +// Use context Values only for request-scoped data that transits processes and +// APIs, not for passing optional parameters to functions. +// +// The provided key must be comparable and should not be of type +// string or any other built-in type to avoid collisions between +// packages using context. Users of WithValue should define their own +// types for keys. To avoid allocating when assigning to an +// interface{}, context keys often have concrete type +// struct{}. Alternatively, exported context key variables' static +// type should be a pointer or interface. +func WithValue(parent Context, key, val any) Context { + if parent == nil { + panic("cannot create context from nil parent") + } + if key == nil { + panic("nil key") + } + if !reflectlite.TypeOf(key).Comparable() { + panic("key is not comparable") + } + return &valueCtx{parent, key, val} +} + +// A valueCtx carries a key-value pair. It implements Value for that key and +// delegates all other calls to the embedded Context. +type valueCtx struct { + Context + key, val any +} + +// stringify tries a bit to stringify v, without using fmt, since we don't +// want context depending on the unicode tables. This is only used by +// *valueCtx.String(). +func stringify(v any) string { + switch s := v.(type) { + case stringer: + return s.String() + case string: + return s + case nil: + return "" + } + return reflectlite.TypeOf(v).String() +} + +func (c *valueCtx) String() string { + return contextName(c.Context) + ".WithValue(" + + stringify(c.key) + ", " + + stringify(c.val) + ")" +} + +func (c *valueCtx) Value(key any) any { + if c.key == key { + return c.val + } + return value(c.Context, key) +} + +func value(c Context, key any) any { + for { + switch ctx := c.(type) { + case *valueCtx: + if key == ctx.key { + return ctx.val + } + c = ctx.Context + case *cancelCtx: + if key == &cancelCtxKey { + return c + } + c = ctx.Context + case withoutCancelCtx: + if key == &cancelCtxKey { + // This implements Cause(ctx) == nil + // when ctx is created using WithoutCancel. + return nil + } + c = ctx.c + case *timerCtx: + if key == &cancelCtxKey { + return &ctx.cancelCtx + } + c = ctx.Context + case backgroundCtx, todoCtx: + return nil + default: + return c.Value(key) + } + } +} diff --git a/contrib/go/_std_1.22/src/context/ya.make b/contrib/go/_std_1.23/src/context/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/context/ya.make rename to contrib/go/_std_1.23/src/context/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/aes/aes_gcm.go b/contrib/go/_std_1.23/src/crypto/aes/aes_gcm.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/aes/aes_gcm.go rename to contrib/go/_std_1.23/src/crypto/aes/aes_gcm.go index 036705fecaac..d9a9545f120f 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/aes_gcm.go +++ b/contrib/go/_std_1.23/src/crypto/aes/aes_gcm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 || arm64 +//go:build (amd64 || arm64) && !purego package aes @@ -45,7 +45,7 @@ var _ gcmAble = (*aesCipherGCM)(nil) // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only // called by [crypto/cipher.NewGCM] via the gcmAble interface. func (c *aesCipherGCM) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { - g := &gcmAsm{ks: c.enc, nonceSize: nonceSize, tagSize: tagSize} + g := &gcmAsm{ks: c.enc[:c.l], nonceSize: nonceSize, tagSize: tagSize} gcmAesInit(&g.productTable, g.ks) return g, nil } @@ -176,9 +176,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data))) if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } diff --git a/contrib/go/_std_1.23/src/crypto/aes/asm_amd64.s b/contrib/go/_std_1.23/src/crypto/aes/asm_amd64.s new file mode 100644 index 000000000000..d5e17401ea0e --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/aes/asm_amd64.s @@ -0,0 +1,276 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego + +#include "textflag.h" + +// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·encryptBlockAsm(SB),NOSPLIT,$0 + MOVQ nr+0(FP), CX + MOVQ xk+8(FP), AX + MOVQ dst+16(FP), DX + MOVQ src+24(FP), BX + MOVUPS 0(AX), X1 + MOVUPS 0(BX), X0 + ADDQ $16, AX + PXOR X1, X0 + SUBQ $12, CX + JE Lenc192 + JB Lenc128 +Lenc256: + MOVUPS 0(AX), X1 + AESENC X1, X0 + MOVUPS 16(AX), X1 + AESENC X1, X0 + ADDQ $32, AX +Lenc192: + MOVUPS 0(AX), X1 + AESENC X1, X0 + MOVUPS 16(AX), X1 + AESENC X1, X0 + ADDQ $32, AX +Lenc128: + MOVUPS 0(AX), X1 + AESENC X1, X0 + MOVUPS 16(AX), X1 + AESENC X1, X0 + MOVUPS 32(AX), X1 + AESENC X1, X0 + MOVUPS 48(AX), X1 + AESENC X1, X0 + MOVUPS 64(AX), X1 + AESENC X1, X0 + MOVUPS 80(AX), X1 + AESENC X1, X0 + MOVUPS 96(AX), X1 + AESENC X1, X0 + MOVUPS 112(AX), X1 + AESENC X1, X0 + MOVUPS 128(AX), X1 + AESENC X1, X0 + MOVUPS 144(AX), X1 + AESENCLAST X1, X0 + MOVUPS X0, 0(DX) + RET + +// func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·decryptBlockAsm(SB),NOSPLIT,$0 + MOVQ nr+0(FP), CX + MOVQ xk+8(FP), AX + MOVQ dst+16(FP), DX + MOVQ src+24(FP), BX + MOVUPS 0(AX), X1 + MOVUPS 0(BX), X0 + ADDQ $16, AX + PXOR X1, X0 + SUBQ $12, CX + JE Ldec192 + JB Ldec128 +Ldec256: + MOVUPS 0(AX), X1 + AESDEC X1, X0 + MOVUPS 16(AX), X1 + AESDEC X1, X0 + ADDQ $32, AX +Ldec192: + MOVUPS 0(AX), X1 + AESDEC X1, X0 + MOVUPS 16(AX), X1 + AESDEC X1, X0 + ADDQ $32, AX +Ldec128: + MOVUPS 0(AX), X1 + AESDEC X1, X0 + MOVUPS 16(AX), X1 + AESDEC X1, X0 + MOVUPS 32(AX), X1 + AESDEC X1, X0 + MOVUPS 48(AX), X1 + AESDEC X1, X0 + MOVUPS 64(AX), X1 + AESDEC X1, X0 + MOVUPS 80(AX), X1 + AESDEC X1, X0 + MOVUPS 96(AX), X1 + AESDEC X1, X0 + MOVUPS 112(AX), X1 + AESDEC X1, X0 + MOVUPS 128(AX), X1 + AESDEC X1, X0 + MOVUPS 144(AX), X1 + AESDECLAST X1, X0 + MOVUPS X0, 0(DX) + RET + +// func expandKeyAsm(nr int, key *byte, enc, dec *uint32) { +// Note that round keys are stored in uint128 format, not uint32 +TEXT ·expandKeyAsm(SB),NOSPLIT,$0 + MOVQ nr+0(FP), CX + MOVQ key+8(FP), AX + MOVQ enc+16(FP), BX + MOVQ dec+24(FP), DX + MOVUPS (AX), X0 + // enc + MOVUPS X0, (BX) + ADDQ $16, BX + PXOR X4, X4 // _expand_key_* expect X4 to be zero + CMPL CX, $12 + JE Lexp_enc192 + JB Lexp_enc128 +Lexp_enc256: + MOVUPS 16(AX), X2 + MOVUPS X2, (BX) + ADDQ $16, BX + AESKEYGENASSIST $0x01, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x01, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x02, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x02, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x04, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x04, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x08, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x08, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x10, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x10, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x20, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x20, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x40, X2, X1 + CALL _expand_key_256a<>(SB) + JMP Lexp_dec +Lexp_enc192: + MOVQ 16(AX), X2 + AESKEYGENASSIST $0x01, X2, X1 + CALL _expand_key_192a<>(SB) + AESKEYGENASSIST $0x02, X2, X1 + CALL _expand_key_192b<>(SB) + AESKEYGENASSIST $0x04, X2, X1 + CALL _expand_key_192a<>(SB) + AESKEYGENASSIST $0x08, X2, X1 + CALL _expand_key_192b<>(SB) + AESKEYGENASSIST $0x10, X2, X1 + CALL _expand_key_192a<>(SB) + AESKEYGENASSIST $0x20, X2, X1 + CALL _expand_key_192b<>(SB) + AESKEYGENASSIST $0x40, X2, X1 + CALL _expand_key_192a<>(SB) + AESKEYGENASSIST $0x80, X2, X1 + CALL _expand_key_192b<>(SB) + JMP Lexp_dec +Lexp_enc128: + AESKEYGENASSIST $0x01, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x02, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x04, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x08, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x10, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x20, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x40, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x80, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x1b, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x36, X0, X1 + CALL _expand_key_128<>(SB) +Lexp_dec: + // dec + SUBQ $16, BX + MOVUPS (BX), X1 + MOVUPS X1, (DX) + DECQ CX +Lexp_dec_loop: + MOVUPS -16(BX), X1 + AESIMC X1, X0 + MOVUPS X0, 16(DX) + SUBQ $16, BX + ADDQ $16, DX + DECQ CX + JNZ Lexp_dec_loop + MOVUPS -16(BX), X0 + MOVUPS X0, 16(DX) + RET + +TEXT _expand_key_128<>(SB),NOSPLIT,$0 + PSHUFD $0xff, X1, X1 + SHUFPS $0x10, X0, X4 + PXOR X4, X0 + SHUFPS $0x8c, X0, X4 + PXOR X4, X0 + PXOR X1, X0 + MOVUPS X0, (BX) + ADDQ $16, BX + RET + +TEXT _expand_key_192a<>(SB),NOSPLIT,$0 + PSHUFD $0x55, X1, X1 + SHUFPS $0x10, X0, X4 + PXOR X4, X0 + SHUFPS $0x8c, X0, X4 + PXOR X4, X0 + PXOR X1, X0 + + MOVAPS X2, X5 + MOVAPS X2, X6 + PSLLDQ $0x4, X5 + PSHUFD $0xff, X0, X3 + PXOR X3, X2 + PXOR X5, X2 + + MOVAPS X0, X1 + SHUFPS $0x44, X0, X6 + MOVUPS X6, (BX) + SHUFPS $0x4e, X2, X1 + MOVUPS X1, 16(BX) + ADDQ $32, BX + RET + +TEXT _expand_key_192b<>(SB),NOSPLIT,$0 + PSHUFD $0x55, X1, X1 + SHUFPS $0x10, X0, X4 + PXOR X4, X0 + SHUFPS $0x8c, X0, X4 + PXOR X4, X0 + PXOR X1, X0 + + MOVAPS X2, X5 + PSLLDQ $0x4, X5 + PSHUFD $0xff, X0, X3 + PXOR X3, X2 + PXOR X5, X2 + + MOVUPS X0, (BX) + ADDQ $16, BX + RET + +TEXT _expand_key_256a<>(SB),NOSPLIT,$0 + JMP _expand_key_128<>(SB) + +TEXT _expand_key_256b<>(SB),NOSPLIT,$0 + PSHUFD $0xaa, X1, X1 + SHUFPS $0x10, X2, X4 + PXOR X4, X2 + SHUFPS $0x8c, X2, X4 + PXOR X4, X2 + PXOR X1, X2 + + MOVUPS X2, (BX) + ADDQ $16, BX + RET diff --git a/contrib/go/_std_1.23/src/crypto/aes/asm_arm64.s b/contrib/go/_std_1.23/src/crypto/aes/asm_arm64.s new file mode 100644 index 000000000000..2bf5bee2b59f --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/aes/asm_arm64.s @@ -0,0 +1,283 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego + +#include "textflag.h" +DATA rotInvSRows<>+0x00(SB)/8, $0x080f0205040b0e01 +DATA rotInvSRows<>+0x08(SB)/8, $0x00070a0d0c030609 +GLOBL rotInvSRows<>(SB), (NOPTR+RODATA), $16 +DATA invSRows<>+0x00(SB)/8, $0x0b0e0104070a0d00 +DATA invSRows<>+0x08(SB)/8, $0x0306090c0f020508 +GLOBL invSRows<>(SB), (NOPTR+RODATA), $16 +// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·encryptBlockAsm(SB),NOSPLIT,$0 + MOVD nr+0(FP), R9 + MOVD xk+8(FP), R10 + MOVD dst+16(FP), R11 + MOVD src+24(FP), R12 + + VLD1 (R12), [V0.B16] + + CMP $12, R9 + BLT enc128 + BEQ enc196 +enc256: + VLD1.P 32(R10), [V1.B16, V2.B16] + AESE V1.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V2.B16, V0.B16 + AESMC V0.B16, V0.B16 +enc196: + VLD1.P 32(R10), [V3.B16, V4.B16] + AESE V3.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V4.B16, V0.B16 + AESMC V0.B16, V0.B16 +enc128: + VLD1.P 64(R10), [V5.B16, V6.B16, V7.B16, V8.B16] + VLD1.P 64(R10), [V9.B16, V10.B16, V11.B16, V12.B16] + VLD1.P 48(R10), [V13.B16, V14.B16, V15.B16] + AESE V5.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V6.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V7.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V8.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V9.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V10.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V11.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V12.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V13.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V14.B16, V0.B16 + VEOR V0.B16, V15.B16, V0.B16 + VST1 [V0.B16], (R11) + RET + +// func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·decryptBlockAsm(SB),NOSPLIT,$0 + MOVD nr+0(FP), R9 + MOVD xk+8(FP), R10 + MOVD dst+16(FP), R11 + MOVD src+24(FP), R12 + + VLD1 (R12), [V0.B16] + + CMP $12, R9 + BLT dec128 + BEQ dec196 +dec256: + VLD1.P 32(R10), [V1.B16, V2.B16] + AESD V1.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V2.B16, V0.B16 + AESIMC V0.B16, V0.B16 +dec196: + VLD1.P 32(R10), [V3.B16, V4.B16] + AESD V3.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V4.B16, V0.B16 + AESIMC V0.B16, V0.B16 +dec128: + VLD1.P 64(R10), [V5.B16, V6.B16, V7.B16, V8.B16] + VLD1.P 64(R10), [V9.B16, V10.B16, V11.B16, V12.B16] + VLD1.P 48(R10), [V13.B16, V14.B16, V15.B16] + AESD V5.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V6.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V7.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V8.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V9.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V10.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V11.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V12.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V13.B16, V0.B16 + AESIMC V0.B16, V0.B16 + AESD V14.B16, V0.B16 + VEOR V0.B16, V15.B16, V0.B16 + VST1 [V0.B16], (R11) + RET + +// func expandKeyAsm(nr int, key *byte, enc, dec *uint32) { +// Note that round keys are stored in uint128 format, not uint32 +TEXT ·expandKeyAsm(SB),NOSPLIT,$0 + MOVD nr+0(FP), R8 + MOVD key+8(FP), R9 + MOVD enc+16(FP), R10 + MOVD dec+24(FP), R11 + LDP rotInvSRows<>(SB), (R0, R1) + VMOV R0, V3.D[0] + VMOV R1, V3.D[1] + VEOR V0.B16, V0.B16, V0.B16 // All zeroes + MOVW $1, R13 + TBZ $1, R8, ks192 + TBNZ $2, R8, ks256 + LDPW (R9), (R4, R5) + LDPW 8(R9), (R6, R7) + STPW.P (R4, R5), 8(R10) + STPW.P (R6, R7), 8(R10) + MOVW $0x1b, R14 +ks128Loop: + VMOV R7, V2.S[0] + WORD $0x4E030042 // TBL V3.B16, [V2.B16], V2.B16 + AESE V0.B16, V2.B16 // Use AES to compute the SBOX + EORW R13, R4 + LSLW $1, R13 // Compute next Rcon + ANDSW $0x100, R13, ZR + CSELW NE, R14, R13, R13 // Fake modulo + SUBS $1, R8 + VMOV V2.S[0], R0 + EORW R0, R4 + EORW R4, R5 + EORW R5, R6 + EORW R6, R7 + STPW.P (R4, R5), 8(R10) + STPW.P (R6, R7), 8(R10) + BNE ks128Loop + CBZ R11, ksDone // If dec is nil we are done + SUB $176, R10 + // Decryption keys are encryption keys with InverseMixColumns applied + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + VMOV V0.B16, V7.B16 + AESIMC V1.B16, V6.B16 + AESIMC V2.B16, V5.B16 + AESIMC V3.B16, V4.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V11.B16 + AESIMC V1.B16, V10.B16 + AESIMC V2.B16, V9.B16 + AESIMC V3.B16, V8.B16 + VLD1 (R10), [V0.B16, V1.B16, V2.B16] + AESIMC V0.B16, V14.B16 + AESIMC V1.B16, V13.B16 + VMOV V2.B16, V12.B16 + VST1.P [V12.B16, V13.B16, V14.B16], 48(R11) + VST1.P [V8.B16, V9.B16, V10.B16, V11.B16], 64(R11) + VST1 [V4.B16, V5.B16, V6.B16, V7.B16], (R11) + B ksDone +ks192: + LDPW (R9), (R2, R3) + LDPW 8(R9), (R4, R5) + LDPW 16(R9), (R6, R7) + STPW.P (R2, R3), 8(R10) + STPW.P (R4, R5), 8(R10) + SUB $4, R8 +ks192Loop: + STPW.P (R6, R7), 8(R10) + VMOV R7, V2.S[0] + WORD $0x4E030042 //TBL V3.B16, [V2.B16], V2.B16 + AESE V0.B16, V2.B16 + EORW R13, R2 + LSLW $1, R13 + SUBS $1, R8 + VMOV V2.S[0], R0 + EORW R0, R2 + EORW R2, R3 + EORW R3, R4 + EORW R4, R5 + EORW R5, R6 + EORW R6, R7 + STPW.P (R2, R3), 8(R10) + STPW.P (R4, R5), 8(R10) + BNE ks192Loop + CBZ R11, ksDone + SUB $208, R10 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + VMOV V0.B16, V7.B16 + AESIMC V1.B16, V6.B16 + AESIMC V2.B16, V5.B16 + AESIMC V3.B16, V4.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V11.B16 + AESIMC V1.B16, V10.B16 + AESIMC V2.B16, V9.B16 + AESIMC V3.B16, V8.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V15.B16 + AESIMC V1.B16, V14.B16 + AESIMC V2.B16, V13.B16 + AESIMC V3.B16, V12.B16 + VLD1 (R10), [V0.B16] + VST1.P [V0.B16], 16(R11) + VST1.P [V12.B16, V13.B16, V14.B16, V15.B16], 64(R11) + VST1.P [V8.B16, V9.B16, V10.B16, V11.B16], 64(R11) + VST1 [V4.B16, V5.B16, V6.B16, V7.B16], (R11) + B ksDone +ks256: + LDP invSRows<>(SB), (R0, R1) + VMOV R0, V4.D[0] + VMOV R1, V4.D[1] + LDPW (R9), (R0, R1) + LDPW 8(R9), (R2, R3) + LDPW 16(R9), (R4, R5) + LDPW 24(R9), (R6, R7) + STPW.P (R0, R1), 8(R10) + STPW.P (R2, R3), 8(R10) + SUB $7, R8 +ks256Loop: + STPW.P (R4, R5), 8(R10) + STPW.P (R6, R7), 8(R10) + VMOV R7, V2.S[0] + WORD $0x4E030042 //TBL V3.B16, [V2.B16], V2.B16 + AESE V0.B16, V2.B16 + EORW R13, R0 + LSLW $1, R13 + SUBS $1, R8 + VMOV V2.S[0], R9 + EORW R9, R0 + EORW R0, R1 + EORW R1, R2 + EORW R2, R3 + VMOV R3, V2.S[0] + WORD $0x4E040042 //TBL V3.B16, [V2.B16], V2.B16 + AESE V0.B16, V2.B16 + VMOV V2.S[0], R9 + EORW R9, R4 + EORW R4, R5 + EORW R5, R6 + EORW R6, R7 + STPW.P (R0, R1), 8(R10) + STPW.P (R2, R3), 8(R10) + BNE ks256Loop + CBZ R11, ksDone + SUB $240, R10 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + VMOV V0.B16, V7.B16 + AESIMC V1.B16, V6.B16 + AESIMC V2.B16, V5.B16 + AESIMC V3.B16, V4.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V11.B16 + AESIMC V1.B16, V10.B16 + AESIMC V2.B16, V9.B16 + AESIMC V3.B16, V8.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V15.B16 + AESIMC V1.B16, V14.B16 + AESIMC V2.B16, V13.B16 + AESIMC V3.B16, V12.B16 + VLD1 (R10), [V0.B16, V1.B16, V2.B16] + AESIMC V0.B16, V18.B16 + AESIMC V1.B16, V17.B16 + VMOV V2.B16, V16.B16 + VST1.P [V16.B16, V17.B16, V18.B16], 48(R11) + VST1.P [V12.B16, V13.B16, V14.B16, V15.B16], 64(R11) + VST1.P [V8.B16, V9.B16, V10.B16, V11.B16], 64(R11) + VST1 [V4.B16, V5.B16, V6.B16, V7.B16], (R11) +ksDone: + RET diff --git a/contrib/go/_std_1.23/src/crypto/aes/asm_ppc64x.s b/contrib/go/_std_1.23/src/crypto/aes/asm_ppc64x.s new file mode 100644 index 000000000000..5a2b210920ed --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/aes/asm_ppc64x.s @@ -0,0 +1,675 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (ppc64 || ppc64le) && !purego + +// Based on CRYPTOGAMS code with the following comment: +// # ==================================================================== +// # Written by Andy Polyakov for the OpenSSL +// # project. The module is, however, dual licensed under OpenSSL and +// # CRYPTOGAMS licenses depending on where you obtain it. For further +// # details see http://www.openssl.org/~appro/cryptogams/. +// # ==================================================================== + +// Original code can be found at the link below: +// https://github.com/dot-asm/cryptogams/blob/master/ppc/aesp8-ppc.pl + +// Some function names were changed to be consistent with Go function +// names. For instance, function aes_p8_set_{en,de}crypt_key become +// set{En,De}cryptKeyAsm. I also split setEncryptKeyAsm in two parts +// and a new session was created (doEncryptKeyAsm). This was necessary to +// avoid arguments overwriting when setDecryptKeyAsm calls setEncryptKeyAsm. +// There were other modifications as well but kept the same functionality. + +#include "textflag.h" + +// For expandKeyAsm +#define INP R3 +#define BITS R4 +#define OUTENC R5 // Pointer to next expanded encrypt key +#define PTR R6 +#define CNT R7 +#define ROUNDS R8 +#define OUTDEC R9 // Pointer to next expanded decrypt key +#define TEMP R19 +#define ZERO V0 +#define IN0 V1 +#define IN1 V2 +#define KEY V3 +#define RCON V4 +#define MASK V5 +#define TMP V6 +#define STAGE V7 +#define OUTPERM V8 +#define OUTMASK V9 +#define OUTHEAD V10 +#define OUTTAIL V11 + +// For P9 instruction emulation +#define ESPERM V21 // Endian swapping permute into BE +#define TMP2 V22 // Temporary for P8_STXVB16X/P8_STXVB16X + +// For {en,de}cryptBlockAsm +#define BLK_INP R3 +#define BLK_OUT R4 +#define BLK_KEY R5 +#define BLK_ROUNDS R6 +#define BLK_IDX R7 + +DATA ·rcon+0x00(SB)/8, $0x0f0e0d0c0b0a0908 // Permute for vector doubleword endian swap +DATA ·rcon+0x08(SB)/8, $0x0706050403020100 +DATA ·rcon+0x10(SB)/8, $0x0100000001000000 // RCON +DATA ·rcon+0x18(SB)/8, $0x0100000001000000 // RCON +DATA ·rcon+0x20(SB)/8, $0x1b0000001b000000 +DATA ·rcon+0x28(SB)/8, $0x1b0000001b000000 +DATA ·rcon+0x30(SB)/8, $0x0d0e0f0c0d0e0f0c // MASK +DATA ·rcon+0x38(SB)/8, $0x0d0e0f0c0d0e0f0c // MASK +DATA ·rcon+0x40(SB)/8, $0x0000000000000000 +DATA ·rcon+0x48(SB)/8, $0x0000000000000000 +GLOBL ·rcon(SB), RODATA, $80 + +#ifdef GOARCH_ppc64le +# ifdef GOPPC64_power9 +#define P8_LXVB16X(RA,RB,VT) LXVB16X (RA+RB), VT +#define P8_STXVB16X(VS,RA,RB) STXVB16X VS, (RA+RB) +#define XXBRD_ON_LE(VA,VT) XXBRD VA, VT +# else +// On POWER8/ppc64le, emulate the POWER9 instructions by loading unaligned +// doublewords and byte-swapping each doubleword to emulate BE load/stores. +#define NEEDS_ESPERM +#define P8_LXVB16X(RA,RB,VT) \ + LXVD2X (RA+RB), VT \ + VPERM VT, VT, ESPERM, VT + +#define P8_STXVB16X(VS,RA,RB) \ + VPERM VS, VS, ESPERM, TMP2 \ + STXVD2X TMP2, (RA+RB) + +#define XXBRD_ON_LE(VA,VT) \ + VPERM VA, VA, ESPERM, VT + +# endif // defined(GOPPC64_power9) +#else +#define P8_LXVB16X(RA,RB,VT) LXVD2X (RA+RB), VT +#define P8_STXVB16X(VS,RA,RB) STXVD2X VS, (RA+RB) +#define XXBRD_ON_LE(VA, VT) +#endif // defined(GOARCH_ppc64le) + +// func setEncryptKeyAsm(nr int, key *byte, enc *uint32, dec *uint32) +TEXT ·expandKeyAsm(SB), NOSPLIT|NOFRAME, $0 + // Load the arguments inside the registers + MOVD nr+0(FP), ROUNDS + MOVD key+8(FP), INP + MOVD enc+16(FP), OUTENC + MOVD dec+24(FP), OUTDEC + +#ifdef NEEDS_ESPERM + MOVD $·rcon(SB), PTR // PTR points to rcon addr + LVX (PTR), ESPERM + ADD $0x10, PTR +#else + MOVD $·rcon+0x10(SB), PTR // PTR points to rcon addr (skipping permute vector) +#endif + + // Get key from memory and write aligned into VR + P8_LXVB16X(INP, R0, IN0) + ADD $0x10, INP, INP + MOVD $0x20, TEMP + + CMPW ROUNDS, $12 + LVX (PTR)(R0), RCON // lvx 4,0,6 Load first 16 bytes into RCON + LVX (PTR)(TEMP), MASK + ADD $0x10, PTR, PTR // addi 6,6,0x10 PTR to next 16 bytes of RCON + MOVD $8, CNT // li 7,8 CNT = 8 + VXOR ZERO, ZERO, ZERO // vxor 0,0,0 Zero to be zero :) + MOVD CNT, CTR // mtctr 7 Set the counter to 8 (rounds) + + // The expanded decrypt key is the expanded encrypt key stored in reverse order. + // Move OUTDEC to the last key location, and store in descending order. + ADD $160, OUTDEC, OUTDEC + BLT loop128 + ADD $32, OUTDEC, OUTDEC + BEQ l192 + ADD $32, OUTDEC, OUTDEC + JMP l256 + +loop128: + // Key schedule (Round 1 to 8) + VPERM IN0, IN0, MASK, KEY // vperm 3,1,1,5 Rotate-n-splat + VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12 + STXVD2X IN0, (R0+OUTENC) + STXVD2X IN0, (R0+OUTDEC) + VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4 + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VADDUWM RCON, RCON, RCON // vadduwm 4,4,4 + VXOR IN0, KEY, IN0 // vxor 1,1,3 + BDNZ loop128 + + LVX (PTR)(R0), RCON // lvx 4,0,6 Last two round keys + + // Key schedule (Round 9) + VPERM IN0, IN0, MASK, KEY // vperm 3,1,1,5 Rotate-n-spat + VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12 + STXVD2X IN0, (R0+OUTENC) + STXVD2X IN0, (R0+OUTDEC) + VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4 + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + + // Key schedule (Round 10) + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VADDUWM RCON, RCON, RCON // vadduwm 4,4,4 + VXOR IN0, KEY, IN0 // vxor 1,1,3 + + VPERM IN0, IN0, MASK, KEY // vperm 3,1,1,5 Rotate-n-splat + VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12 + STXVD2X IN0, (R0+OUTENC) + STXVD2X IN0, (R0+OUTDEC) + VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4 + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + + // Key schedule (Round 11) + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VXOR IN0, KEY, IN0 // vxor 1,1,3 + STXVD2X IN0, (R0+OUTENC) + STXVD2X IN0, (R0+OUTDEC) + + RET + +l192: + LXSDX (INP+R0), IN1 // Load next 8 bytes into upper half of VSR. + XXBRD_ON_LE(IN1, IN1) // and convert to BE ordering on LE hosts. + MOVD $4, CNT // li 7,4 + STXVD2X IN0, (R0+OUTENC) + STXVD2X IN0, (R0+OUTDEC) + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + VSPLTISB $8, KEY // vspltisb 3,8 + MOVD CNT, CTR // mtctr 7 + VSUBUBM MASK, KEY, MASK // vsububm 5,5,3 + +loop192: + VPERM IN1, IN1, MASK, KEY // vperm 3,2,2,5 + VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12 + VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4 + + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + + VSLDOI $8, ZERO, IN1, STAGE // vsldoi 7,0,2,8 + VSPLTW $3, IN0, TMP // vspltw 6,1,3 + VXOR TMP, IN1, TMP // vxor 6,6,2 + VSLDOI $12, ZERO, IN1, IN1 // vsldoi 2,0,2,12 + VADDUWM RCON, RCON, RCON // vadduwm 4,4,4 + VXOR IN1, TMP, IN1 // vxor 2,2,6 + VXOR IN0, KEY, IN0 // vxor 1,1,3 + VXOR IN1, KEY, IN1 // vxor 2,2,3 + VSLDOI $8, STAGE, IN0, STAGE // vsldoi 7,7,1,8 + + VPERM IN1, IN1, MASK, KEY // vperm 3,2,2,5 + VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12 + STXVD2X STAGE, (R0+OUTENC) + STXVD2X STAGE, (R0+OUTDEC) + VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4 + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + + VSLDOI $8, IN0, IN1, STAGE // vsldoi 7,1,2,8 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + STXVD2X STAGE, (R0+OUTENC) + STXVD2X STAGE, (R0+OUTDEC) + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + + VSPLTW $3, IN0, TMP // vspltw 6,1,3 + VXOR TMP, IN1, TMP // vxor 6,6,2 + VSLDOI $12, ZERO, IN1, IN1 // vsldoi 2,0,2,12 + VADDUWM RCON, RCON, RCON // vadduwm 4,4,4 + VXOR IN1, TMP, IN1 // vxor 2,2,6 + VXOR IN0, KEY, IN0 // vxor 1,1,3 + VXOR IN1, KEY, IN1 // vxor 2,2,3 + STXVD2X IN0, (R0+OUTENC) + STXVD2X IN0, (R0+OUTDEC) + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + BDNZ loop192 + + RET + +l256: + P8_LXVB16X(INP, R0, IN1) + MOVD $7, CNT // li 7,7 + STXVD2X IN0, (R0+OUTENC) + STXVD2X IN0, (R0+OUTDEC) + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + MOVD CNT, CTR // mtctr 7 + +loop256: + VPERM IN1, IN1, MASK, KEY // vperm 3,2,2,5 + VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12 + STXVD2X IN1, (R0+OUTENC) + STXVD2X IN1, (R0+OUTDEC) + VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4 + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN0, TMP, IN0 // vxor 1,1,6 + VADDUWM RCON, RCON, RCON // vadduwm 4,4,4 + VXOR IN0, KEY, IN0 // vxor 1,1,3 + STXVD2X IN0, (R0+OUTENC) + STXVD2X IN0, (R0+OUTDEC) + ADD $16, OUTENC, OUTENC + ADD $-16, OUTDEC, OUTDEC + BDZ done + + VSPLTW $3, IN0, KEY // vspltw 3,1,3 + VSLDOI $12, ZERO, IN1, TMP // vsldoi 6,0,2,12 + VSBOX KEY, KEY // vsbox 3,3 + + VXOR IN1, TMP, IN1 // vxor 2,2,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN1, TMP, IN1 // vxor 2,2,6 + VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12 + VXOR IN1, TMP, IN1 // vxor 2,2,6 + + VXOR IN1, KEY, IN1 // vxor 2,2,3 + JMP loop256 // b .Loop256 + +done: + RET + +// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·encryptBlockAsm(SB), NOSPLIT|NOFRAME, $0 + MOVD nr+0(FP), R6 // Round count/Key size + MOVD xk+8(FP), R5 // Key pointer + MOVD dst+16(FP), R3 // Dest pointer + MOVD src+24(FP), R4 // Src pointer +#ifdef NEEDS_ESPERM + MOVD $·rcon(SB), R7 + LVX (R7), ESPERM // Permute value for P8_ macros. +#endif + + // Set CR{1,2,3}EQ to hold the key size information. + CMPU R6, $10, CR1 + CMPU R6, $12, CR2 + CMPU R6, $14, CR3 + + MOVD $16, R6 + MOVD $32, R7 + MOVD $48, R8 + MOVD $64, R9 + MOVD $80, R10 + MOVD $96, R11 + MOVD $112, R12 + + // Load text in BE order + P8_LXVB16X(R4, R0, V0) + + // V1, V2 will hold keys, V0 is a temp. + // At completion, V2 will hold the ciphertext. + // Load xk[0:3] and xor with text + LXVD2X (R0+R5), V1 + VXOR V0, V1, V0 + + // Load xk[4:11] and cipher + LXVD2X (R6+R5), V1 + LXVD2X (R7+R5), V2 + VCIPHER V0, V1, V0 + VCIPHER V0, V2, V0 + + // Load xk[12:19] and cipher + LXVD2X (R8+R5), V1 + LXVD2X (R9+R5), V2 + VCIPHER V0, V1, V0 + VCIPHER V0, V2, V0 + + // Load xk[20:27] and cipher + LXVD2X (R10+R5), V1 + LXVD2X (R11+R5), V2 + VCIPHER V0, V1, V0 + VCIPHER V0, V2, V0 + + // Increment xk pointer to reuse constant offsets in R6-R12. + ADD $112, R5 + + // Load xk[28:35] and cipher + LXVD2X (R0+R5), V1 + LXVD2X (R6+R5), V2 + VCIPHER V0, V1, V0 + VCIPHER V0, V2, V0 + + // Load xk[36:43] and cipher + LXVD2X (R7+R5), V1 + LXVD2X (R8+R5), V2 + BEQ CR1, Ldec_tail // Key size 10? + VCIPHER V0, V1, V0 + VCIPHER V0, V2, V0 + + // Load xk[44:51] and cipher + LXVD2X (R9+R5), V1 + LXVD2X (R10+R5), V2 + BEQ CR2, Ldec_tail // Key size 12? + VCIPHER V0, V1, V0 + VCIPHER V0, V2, V0 + + // Load xk[52:59] and cipher + LXVD2X (R11+R5), V1 + LXVD2X (R12+R5), V2 + BNE CR3, Linvalid_key_len // Not key size 14? + // Fallthrough to final cipher + +Ldec_tail: + // Cipher last two keys such that key information is + // cleared from V1 and V2. + VCIPHER V0, V1, V1 + VCIPHERLAST V1, V2, V2 + + // Store the result in BE order. + P8_STXVB16X(V2, R3, R0) + RET + +Linvalid_key_len: + // Segfault, this should never happen. Only 3 keys sizes are created/used. + MOVD R0, 0(R0) + RET + +// func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·decryptBlockAsm(SB), NOSPLIT|NOFRAME, $0 + MOVD nr+0(FP), R6 // Round count/Key size + MOVD xk+8(FP), R5 // Key pointer + MOVD dst+16(FP), R3 // Dest pointer + MOVD src+24(FP), R4 // Src pointer +#ifdef NEEDS_ESPERM + MOVD $·rcon(SB), R7 + LVX (R7), ESPERM // Permute value for P8_ macros. +#endif + + // Set CR{1,2,3}EQ to hold the key size information. + CMPU R6, $10, CR1 + CMPU R6, $12, CR2 + CMPU R6, $14, CR3 + + MOVD $16, R6 + MOVD $32, R7 + MOVD $48, R8 + MOVD $64, R9 + MOVD $80, R10 + MOVD $96, R11 + MOVD $112, R12 + + // Load text in BE order + P8_LXVB16X(R4, R0, V0) + + // V1, V2 will hold keys, V0 is a temp. + // At completion, V2 will hold the text. + // Load xk[0:3] and xor with ciphertext + LXVD2X (R0+R5), V1 + VXOR V0, V1, V0 + + // Load xk[4:11] and cipher + LXVD2X (R6+R5), V1 + LXVD2X (R7+R5), V2 + VNCIPHER V0, V1, V0 + VNCIPHER V0, V2, V0 + + // Load xk[12:19] and cipher + LXVD2X (R8+R5), V1 + LXVD2X (R9+R5), V2 + VNCIPHER V0, V1, V0 + VNCIPHER V0, V2, V0 + + // Load xk[20:27] and cipher + LXVD2X (R10+R5), V1 + LXVD2X (R11+R5), V2 + VNCIPHER V0, V1, V0 + VNCIPHER V0, V2, V0 + + // Increment xk pointer to reuse constant offsets in R6-R12. + ADD $112, R5 + + // Load xk[28:35] and cipher + LXVD2X (R0+R5), V1 + LXVD2X (R6+R5), V2 + VNCIPHER V0, V1, V0 + VNCIPHER V0, V2, V0 + + // Load xk[36:43] and cipher + LXVD2X (R7+R5), V1 + LXVD2X (R8+R5), V2 + BEQ CR1, Ldec_tail // Key size 10? + VNCIPHER V0, V1, V0 + VNCIPHER V0, V2, V0 + + // Load xk[44:51] and cipher + LXVD2X (R9+R5), V1 + LXVD2X (R10+R5), V2 + BEQ CR2, Ldec_tail // Key size 12? + VNCIPHER V0, V1, V0 + VNCIPHER V0, V2, V0 + + // Load xk[52:59] and cipher + LXVD2X (R11+R5), V1 + LXVD2X (R12+R5), V2 + BNE CR3, Linvalid_key_len // Not key size 14? + // Fallthrough to final cipher + +Ldec_tail: + // Cipher last two keys such that key information is + // cleared from V1 and V2. + VNCIPHER V0, V1, V1 + VNCIPHERLAST V1, V2, V2 + + // Store the result in BE order. + P8_STXVB16X(V2, R3, R0) + RET + +Linvalid_key_len: + // Segfault, this should never happen. Only 3 keys sizes are created/used. + MOVD R0, 0(R0) + RET + +// Remove defines from above so they can be defined here +#undef INP +#undef OUTENC +#undef ROUNDS +#undef KEY +#undef TMP + +#define INP R3 +#define OUTP R4 +#define LEN R5 +#define KEYP R6 +#define ROUNDS R7 +#define IVP R8 +#define ENC R9 + +#define INOUT V2 +#define TMP V3 +#define IVEC V4 + +// Load the crypt key into VSRs. +// +// The expanded key is stored and loaded using +// STXVD2X/LXVD2X. The in-memory byte ordering +// depends on the endianness of the machine. The +// expanded keys are generated by expandKeyAsm above. +// +// Rkeyp holds the key pointer. It is clobbered. Once +// the expanded keys are loaded, it is not needed. +// +// R12,R14-R21 are scratch registers. +// For keyp of 10, V6, V11-V20 hold the expanded key. +// For keyp of 12, V6, V9-V20 hold the expanded key. +// For keyp of 14, V6, V7-V20 hold the expanded key. +#define LOAD_KEY(Rkeyp) \ + MOVD $16, R12 \ + MOVD $32, R14 \ + MOVD $48, R15 \ + MOVD $64, R16 \ + MOVD $80, R17 \ + MOVD $96, R18 \ + MOVD $112, R19 \ + MOVD $128, R20 \ + MOVD $144, R21 \ + LXVD2X (R0+Rkeyp), V6 \ + ADD $16, Rkeyp \ + BEQ CR1, L_start10 \ + BEQ CR2, L_start12 \ + LXVD2X (R0+Rkeyp), V7 \ + LXVD2X (R12+Rkeyp), V8 \ + ADD $32, Rkeyp \ + L_start12: \ + LXVD2X (R0+Rkeyp), V9 \ + LXVD2X (R12+Rkeyp), V10 \ + ADD $32, Rkeyp \ + L_start10: \ + LXVD2X (R0+Rkeyp), V11 \ + LXVD2X (R12+Rkeyp), V12 \ + LXVD2X (R14+Rkeyp), V13 \ + LXVD2X (R15+Rkeyp), V14 \ + LXVD2X (R16+Rkeyp), V15 \ + LXVD2X (R17+Rkeyp), V16 \ + LXVD2X (R18+Rkeyp), V17 \ + LXVD2X (R19+Rkeyp), V18 \ + LXVD2X (R20+Rkeyp), V19 \ + LXVD2X (R21+Rkeyp), V20 + +// Perform aes cipher operation for keysize 10/12/14 using the keys +// loaded by LOAD_KEY, and key size information held in CR1EQ/CR2EQ. +// +// Vxor is ideally V6 (Key[0-3]), but for slightly improved encrypting +// performance V6 and IVEC can be swapped (xor is both associative and +// commutative) during encryption: +// +// VXOR INOUT, IVEC, INOUT +// VXOR INOUT, V6, INOUT +// +// into +// +// VXOR INOUT, V6, INOUT +// VXOR INOUT, IVEC, INOUT +// +#define CIPHER_BLOCK(Vin, Vxor, Vout, vcipher, vciphel, label10, label12) \ + VXOR Vin, Vxor, Vout \ + BEQ CR1, label10 \ + BEQ CR2, label12 \ + vcipher Vout, V7, Vout \ + vcipher Vout, V8, Vout \ + label12: \ + vcipher Vout, V9, Vout \ + vcipher Vout, V10, Vout \ + label10: \ + vcipher Vout, V11, Vout \ + vcipher Vout, V12, Vout \ + vcipher Vout, V13, Vout \ + vcipher Vout, V14, Vout \ + vcipher Vout, V15, Vout \ + vcipher Vout, V16, Vout \ + vcipher Vout, V17, Vout \ + vcipher Vout, V18, Vout \ + vcipher Vout, V19, Vout \ + vciphel Vout, V20, Vout \ + +#define CLEAR_KEYS() \ + VXOR V6, V6, V6 \ + VXOR V7, V7, V7 \ + VXOR V8, V8, V8 \ + VXOR V9, V9, V9 \ + VXOR V10, V10, V10 \ + VXOR V11, V11, V11 \ + VXOR V12, V12, V12 \ + VXOR V13, V13, V13 \ + VXOR V14, V14, V14 \ + VXOR V15, V15, V15 \ + VXOR V16, V16, V16 \ + VXOR V17, V17, V17 \ + VXOR V18, V18, V18 \ + VXOR V19, V19, V19 \ + VXOR V20, V20, V20 + +//func cryptBlocksChain(src, dst *byte, length int, key *uint32, iv *byte, enc int, nr int) +TEXT ·cryptBlocksChain(SB), NOSPLIT|NOFRAME, $0 + MOVD src+0(FP), INP + MOVD dst+8(FP), OUTP + MOVD length+16(FP), LEN + MOVD key+24(FP), KEYP + MOVD iv+32(FP), IVP + MOVD enc+40(FP), ENC + MOVD nr+48(FP), ROUNDS + +#ifdef NEEDS_ESPERM + MOVD $·rcon(SB), R11 + LVX (R11), ESPERM // Permute value for P8_ macros. +#endif + + // Assume len > 0 && len % blockSize == 0. + CMPW ENC, $0 + P8_LXVB16X(IVP, R0, IVEC) + CMPU ROUNDS, $10, CR1 + CMPU ROUNDS, $12, CR2 // Only sizes 10/12/14 are supported. + + // Setup key in VSRs, and set loop count in CTR. + LOAD_KEY(KEYP) + SRD $4, LEN + MOVD LEN, CTR + + BEQ Lcbc_dec + + PCALIGN $16 +Lcbc_enc: + P8_LXVB16X(INP, R0, INOUT) + ADD $16, INP + VXOR INOUT, V6, INOUT + CIPHER_BLOCK(INOUT, IVEC, INOUT, VCIPHER, VCIPHERLAST, Lcbc_enc10, Lcbc_enc12) + VOR INOUT, INOUT, IVEC // ciphertext (INOUT) is IVEC for next block. + P8_STXVB16X(INOUT, OUTP, R0) + ADD $16, OUTP + BDNZ Lcbc_enc + + P8_STXVB16X(INOUT, IVP, R0) + CLEAR_KEYS() + RET + + PCALIGN $16 +Lcbc_dec: + P8_LXVB16X(INP, R0, TMP) + ADD $16, INP + CIPHER_BLOCK(TMP, V6, INOUT, VNCIPHER, VNCIPHERLAST, Lcbc_dec10, Lcbc_dec12) + VXOR INOUT, IVEC, INOUT + VOR TMP, TMP, IVEC // TMP is IVEC for next block. + P8_STXVB16X(INOUT, OUTP, R0) + ADD $16, OUTP + BDNZ Lcbc_dec + + P8_STXVB16X(IVEC, IVP, R0) + CLEAR_KEYS() + RET diff --git a/contrib/go/_std_1.23/src/crypto/aes/asm_s390x.s b/contrib/go/_std_1.23/src/crypto/aes/asm_s390x.s new file mode 100644 index 000000000000..5da0d8bf9cb3 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/aes/asm_s390x.s @@ -0,0 +1,193 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego + +#include "textflag.h" + +// func cryptBlocks(c code, key, dst, src *byte, length int) +TEXT ·cryptBlocks(SB),NOSPLIT,$0-40 + MOVD key+8(FP), R1 + MOVD dst+16(FP), R2 + MOVD src+24(FP), R4 + MOVD length+32(FP), R5 + MOVD c+0(FP), R0 +loop: + KM R2, R4 // cipher message (KM) + BVS loop // branch back if interrupted + XOR R0, R0 + RET + +// func cryptBlocksChain(c code, iv, key, dst, src *byte, length int) +TEXT ·cryptBlocksChain(SB),NOSPLIT,$48-48 + LA params-48(SP), R1 + MOVD iv+8(FP), R8 + MOVD key+16(FP), R9 + MVC $16, 0(R8), 0(R1) // move iv into params + MVC $32, 0(R9), 16(R1) // move key into params + MOVD dst+24(FP), R2 + MOVD src+32(FP), R4 + MOVD length+40(FP), R5 + MOVD c+0(FP), R0 +loop: + KMC R2, R4 // cipher message with chaining (KMC) + BVS loop // branch back if interrupted + XOR R0, R0 + MVC $16, 0(R1), 0(R8) // update iv + RET + +// func xorBytes(dst, a, b []byte) int +TEXT ·xorBytes(SB),NOSPLIT,$0-80 + MOVD dst_base+0(FP), R1 + MOVD a_base+24(FP), R2 + MOVD b_base+48(FP), R3 + MOVD a_len+32(FP), R4 + MOVD b_len+56(FP), R5 + CMPBLE R4, R5, skip + MOVD R5, R4 +skip: + MOVD R4, ret+72(FP) + MOVD $0, R5 + CMPBLT R4, $8, tail +loop: + MOVD 0(R2)(R5*1), R7 + MOVD 0(R3)(R5*1), R8 + XOR R7, R8 + MOVD R8, 0(R1)(R5*1) + LAY 8(R5), R5 + SUB $8, R4 + CMPBGE R4, $8, loop +tail: + CMPBEQ R4, $0, done + MOVB 0(R2)(R5*1), R7 + MOVB 0(R3)(R5*1), R8 + XOR R7, R8 + MOVB R8, 0(R1)(R5*1) + LAY 1(R5), R5 + SUB $1, R4 + BR tail +done: + RET + +// func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *[16]byte) +TEXT ·cryptBlocksGCM(SB),NOSPLIT,$0-112 + MOVD src_len+64(FP), R0 + MOVD buf_base+80(FP), R1 + MOVD cnt+104(FP), R12 + LMG (R12), R2, R3 + + // Check that the src size is less than or equal to the buffer size. + MOVD buf_len+88(FP), R4 + CMP R0, R4 + BGT crash + + // Check that the src size is a multiple of 16-bytes. + MOVD R0, R4 + AND $0xf, R4 + BLT crash // non-zero + + // Check that the src size is less than or equal to the dst size. + MOVD dst_len+40(FP), R4 + CMP R0, R4 + BGT crash + + MOVD R2, R4 + MOVD R2, R6 + MOVD R2, R8 + MOVD R3, R5 + MOVD R3, R7 + MOVD R3, R9 + ADDW $1, R5 + ADDW $2, R7 + ADDW $3, R9 +incr: + CMP R0, $64 + BLT tail + STMG R2, R9, (R1) + ADDW $4, R3 + ADDW $4, R5 + ADDW $4, R7 + ADDW $4, R9 + MOVD $64(R1), R1 + SUB $64, R0 + BR incr +tail: + CMP R0, $0 + BEQ crypt + STMG R2, R3, (R1) + ADDW $1, R3 + MOVD $16(R1), R1 + SUB $16, R0 + BR tail +crypt: + STMG R2, R3, (R12) // update next counter value + MOVD fn+0(FP), R0 // function code (encryption) + MOVD key_base+8(FP), R1 // key + MOVD buf_base+80(FP), R2 // counter values + MOVD dst_base+32(FP), R4 // dst + MOVD src_base+56(FP), R6 // src + MOVD src_len+64(FP), R7 // len +loop: + KMCTR R4, R2, R6 // cipher message with counter (KMCTR) + BVS loop // branch back if interrupted + RET +crash: + MOVD $0, (R0) + RET + +// func ghash(key *gcmHashKey, hash *[16]byte, data []byte) +TEXT ·ghash(SB),NOSPLIT,$32-40 + MOVD $65, R0 // GHASH function code + MOVD key+0(FP), R2 + LMG (R2), R6, R7 + MOVD hash+8(FP), R8 + LMG (R8), R4, R5 + MOVD $params-32(SP), R1 + STMG R4, R7, (R1) + LMG data+16(FP), R2, R3 // R2=base, R3=len +loop: + KIMD R0, R2 // compute intermediate message digest (KIMD) + BVS loop // branch back if interrupted + MVC $16, (R1), (R8) + MOVD $0, R0 + RET + +// func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount) +TEXT ·kmaGCM(SB),NOSPLIT,$112-120 + MOVD fn+0(FP), R0 + MOVD $params-112(SP), R1 + + // load ptr/len pairs + LMG dst+32(FP), R2, R3 // R2=base R3=len + LMG src+56(FP), R4, R5 // R4=base R5=len + LMG aad+80(FP), R6, R7 // R6=base R7=len + + // setup parameters + MOVD cnt+112(FP), R8 + XC $12, (R1), (R1) // reserved + MVC $4, 12(R8), 12(R1) // set chain value + MVC $16, (R8), 64(R1) // set initial counter value + XC $32, 16(R1), 16(R1) // set hash subkey and tag + SLD $3, R7, R12 + MOVD R12, 48(R1) // set total AAD length + SLD $3, R5, R12 + MOVD R12, 56(R1) // set total plaintext/ciphertext length + + LMG key+8(FP), R8, R9 // R8=base R9=len + MVC $16, (R8), 80(R1) // set key + CMPBEQ R9, $16, kma + MVC $8, 16(R8), 96(R1) + CMPBEQ R9, $24, kma + MVC $8, 24(R8), 104(R1) + +kma: + KMA R2, R6, R4 // Cipher Message with Authentication + BVS kma + + MOVD tag+104(FP), R2 + MVC $16, 16(R1), 0(R2) // copy tag to output + MOVD cnt+112(FP), R8 + MVC $4, 12(R1), 12(R8) // update counter value + + RET diff --git a/contrib/go/_std_1.23/src/crypto/aes/block.go b/contrib/go/_std_1.23/src/crypto/aes/block.go new file mode 100644 index 000000000000..618eb7752a40 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/aes/block.go @@ -0,0 +1,180 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This Go implementation is derived in part from the reference +// ANSI C implementation, which carries the following notice: +// +// rijndael-alg-fst.c +// +// @version 3.0 (December 2000) +// +// Optimised ANSI C code for the Rijndael cipher (now AES) +// +// @author Vincent Rijmen +// @author Antoon Bosselaers +// @author Paulo Barreto +// +// This code is hereby placed in the public domain. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS +// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission +// for implementation details. +// https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf +// https://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf + +package aes + +import "internal/byteorder" + +// Encrypt one block from src into dst, using the expanded key xk. +func encryptBlockGo(xk []uint32, dst, src []byte) { + _ = src[15] // early bounds check + s0 := byteorder.BeUint32(src[0:4]) + s1 := byteorder.BeUint32(src[4:8]) + s2 := byteorder.BeUint32(src[8:12]) + s3 := byteorder.BeUint32(src[12:16]) + + // First round just XORs input with key. + s0 ^= xk[0] + s1 ^= xk[1] + s2 ^= xk[2] + s3 ^= xk[3] + + // Middle rounds shuffle using tables. + // Number of rounds is set by length of expanded key. + nr := len(xk)/4 - 2 // - 2: one above, one more below + k := 4 + var t0, t1, t2, t3 uint32 + for r := 0; r < nr; r++ { + t0 = xk[k+0] ^ te0[uint8(s0>>24)] ^ te1[uint8(s1>>16)] ^ te2[uint8(s2>>8)] ^ te3[uint8(s3)] + t1 = xk[k+1] ^ te0[uint8(s1>>24)] ^ te1[uint8(s2>>16)] ^ te2[uint8(s3>>8)] ^ te3[uint8(s0)] + t2 = xk[k+2] ^ te0[uint8(s2>>24)] ^ te1[uint8(s3>>16)] ^ te2[uint8(s0>>8)] ^ te3[uint8(s1)] + t3 = xk[k+3] ^ te0[uint8(s3>>24)] ^ te1[uint8(s0>>16)] ^ te2[uint8(s1>>8)] ^ te3[uint8(s2)] + k += 4 + s0, s1, s2, s3 = t0, t1, t2, t3 + } + + // Last round uses s-box directly and XORs to produce output. + s0 = uint32(sbox0[t0>>24])<<24 | uint32(sbox0[t1>>16&0xff])<<16 | uint32(sbox0[t2>>8&0xff])<<8 | uint32(sbox0[t3&0xff]) + s1 = uint32(sbox0[t1>>24])<<24 | uint32(sbox0[t2>>16&0xff])<<16 | uint32(sbox0[t3>>8&0xff])<<8 | uint32(sbox0[t0&0xff]) + s2 = uint32(sbox0[t2>>24])<<24 | uint32(sbox0[t3>>16&0xff])<<16 | uint32(sbox0[t0>>8&0xff])<<8 | uint32(sbox0[t1&0xff]) + s3 = uint32(sbox0[t3>>24])<<24 | uint32(sbox0[t0>>16&0xff])<<16 | uint32(sbox0[t1>>8&0xff])<<8 | uint32(sbox0[t2&0xff]) + + s0 ^= xk[k+0] + s1 ^= xk[k+1] + s2 ^= xk[k+2] + s3 ^= xk[k+3] + + _ = dst[15] // early bounds check + byteorder.BePutUint32(dst[0:4], s0) + byteorder.BePutUint32(dst[4:8], s1) + byteorder.BePutUint32(dst[8:12], s2) + byteorder.BePutUint32(dst[12:16], s3) +} + +// Decrypt one block from src into dst, using the expanded key xk. +func decryptBlockGo(xk []uint32, dst, src []byte) { + _ = src[15] // early bounds check + s0 := byteorder.BeUint32(src[0:4]) + s1 := byteorder.BeUint32(src[4:8]) + s2 := byteorder.BeUint32(src[8:12]) + s3 := byteorder.BeUint32(src[12:16]) + + // First round just XORs input with key. + s0 ^= xk[0] + s1 ^= xk[1] + s2 ^= xk[2] + s3 ^= xk[3] + + // Middle rounds shuffle using tables. + // Number of rounds is set by length of expanded key. + nr := len(xk)/4 - 2 // - 2: one above, one more below + k := 4 + var t0, t1, t2, t3 uint32 + for r := 0; r < nr; r++ { + t0 = xk[k+0] ^ td0[uint8(s0>>24)] ^ td1[uint8(s3>>16)] ^ td2[uint8(s2>>8)] ^ td3[uint8(s1)] + t1 = xk[k+1] ^ td0[uint8(s1>>24)] ^ td1[uint8(s0>>16)] ^ td2[uint8(s3>>8)] ^ td3[uint8(s2)] + t2 = xk[k+2] ^ td0[uint8(s2>>24)] ^ td1[uint8(s1>>16)] ^ td2[uint8(s0>>8)] ^ td3[uint8(s3)] + t3 = xk[k+3] ^ td0[uint8(s3>>24)] ^ td1[uint8(s2>>16)] ^ td2[uint8(s1>>8)] ^ td3[uint8(s0)] + k += 4 + s0, s1, s2, s3 = t0, t1, t2, t3 + } + + // Last round uses s-box directly and XORs to produce output. + s0 = uint32(sbox1[t0>>24])<<24 | uint32(sbox1[t3>>16&0xff])<<16 | uint32(sbox1[t2>>8&0xff])<<8 | uint32(sbox1[t1&0xff]) + s1 = uint32(sbox1[t1>>24])<<24 | uint32(sbox1[t0>>16&0xff])<<16 | uint32(sbox1[t3>>8&0xff])<<8 | uint32(sbox1[t2&0xff]) + s2 = uint32(sbox1[t2>>24])<<24 | uint32(sbox1[t1>>16&0xff])<<16 | uint32(sbox1[t0>>8&0xff])<<8 | uint32(sbox1[t3&0xff]) + s3 = uint32(sbox1[t3>>24])<<24 | uint32(sbox1[t2>>16&0xff])<<16 | uint32(sbox1[t1>>8&0xff])<<8 | uint32(sbox1[t0&0xff]) + + s0 ^= xk[k+0] + s1 ^= xk[k+1] + s2 ^= xk[k+2] + s3 ^= xk[k+3] + + _ = dst[15] // early bounds check + byteorder.BePutUint32(dst[0:4], s0) + byteorder.BePutUint32(dst[4:8], s1) + byteorder.BePutUint32(dst[8:12], s2) + byteorder.BePutUint32(dst[12:16], s3) +} + +// Apply sbox0 to each byte in w. +func subw(w uint32) uint32 { + return uint32(sbox0[w>>24])<<24 | + uint32(sbox0[w>>16&0xff])<<16 | + uint32(sbox0[w>>8&0xff])<<8 | + uint32(sbox0[w&0xff]) +} + +// Rotate +func rotw(w uint32) uint32 { return w<<8 | w>>24 } + +// Key expansion algorithm. See FIPS-197, Figure 11. +// Their rcon[i] is our powx[i-1] << 24. +func expandKeyGo(key []byte, enc, dec []uint32) { + // Encryption key setup. + var i int + nk := len(key) / 4 + for i = 0; i < nk; i++ { + enc[i] = byteorder.BeUint32(key[4*i:]) + } + for ; i < len(enc); i++ { + t := enc[i-1] + if i%nk == 0 { + t = subw(rotw(t)) ^ (uint32(powx[i/nk-1]) << 24) + } else if nk > 6 && i%nk == 4 { + t = subw(t) + } + enc[i] = enc[i-nk] ^ t + } + + // Derive decryption key from encryption key. + // Reverse the 4-word round key sets from enc to produce dec. + // All sets but the first and last get the MixColumn transform applied. + if dec == nil { + return + } + n := len(enc) + for i := 0; i < n; i += 4 { + ei := n - i - 4 + for j := 0; j < 4; j++ { + x := enc[ei+j] + if i > 0 && i+4 < n { + x = td0[sbox0[x>>24]] ^ td1[sbox0[x>>16&0xff]] ^ td2[sbox0[x>>8&0xff]] ^ td3[sbox0[x&0xff]] + } + dec[i+j] = x + } + } +} diff --git a/contrib/go/_std_1.22/src/crypto/aes/cbc_ppc64x.go b/contrib/go/_std_1.23/src/crypto/aes/cbc_ppc64x.go similarity index 94% rename from contrib/go/_std_1.22/src/crypto/aes/cbc_ppc64x.go rename to contrib/go/_std_1.23/src/crypto/aes/cbc_ppc64x.go index c23c37156e51..d5b491e8e1fe 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cbc_ppc64x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cbc_ppc64x.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego package aes @@ -59,9 +59,9 @@ func (x *cbc) CryptBlocks(dst, src []byte) { } if len(src) > 0 { if x.enc == cbcEncrypt { - cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.enc[0], &x.iv[0], x.enc, len(x.b.enc)/4-1) + cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.enc[0], &x.iv[0], x.enc, int(x.b.l)/4-1) } else { - cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.dec[0], &x.iv[0], x.enc, len(x.b.dec)/4-1) + cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.dec[0], &x.iv[0], x.enc, int(x.b.l)/4-1) } } } diff --git a/contrib/go/_std_1.22/src/crypto/aes/cbc_s390x.go b/contrib/go/_std_1.23/src/crypto/aes/cbc_s390x.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/aes/cbc_s390x.go rename to contrib/go/_std_1.23/src/crypto/aes/cbc_s390x.go index eaa21f8a65f2..09c19ff39479 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cbc_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cbc_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package aes import ( diff --git a/contrib/go/_std_1.23/src/crypto/aes/cipher.go b/contrib/go/_std_1.23/src/crypto/aes/cipher.go new file mode 100644 index 000000000000..cde2e45d2ca5 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/aes/cipher.go @@ -0,0 +1,82 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package aes + +import ( + "crypto/cipher" + "crypto/internal/alias" + "crypto/internal/boring" + "strconv" +) + +// The AES block size in bytes. +const BlockSize = 16 + +// A cipher is an instance of AES encryption using a particular key. +type aesCipher struct { + l uint8 // only this length of the enc and dec array is actually used + enc [28 + 32]uint32 + dec [28 + 32]uint32 +} + +type KeySizeError int + +func (k KeySizeError) Error() string { + return "crypto/aes: invalid key size " + strconv.Itoa(int(k)) +} + +// NewCipher creates and returns a new [cipher.Block]. +// The key argument should be the AES key, +// either 16, 24, or 32 bytes to select +// AES-128, AES-192, or AES-256. +func NewCipher(key []byte) (cipher.Block, error) { + k := len(key) + switch k { + default: + return nil, KeySizeError(k) + case 16, 24, 32: + break + } + if boring.Enabled { + return boring.NewAESCipher(key) + } + return newCipher(key) +} + +// newCipherGeneric creates and returns a new cipher.Block +// implemented in pure Go. +func newCipherGeneric(key []byte) (cipher.Block, error) { + c := aesCipher{l: uint8(len(key) + 28)} + expandKeyGo(key, c.enc[:c.l], c.dec[:c.l]) + return &c, nil +} + +func (c *aesCipher) BlockSize() int { return BlockSize } + +func (c *aesCipher) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } + if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } + encryptBlockGo(c.enc[:c.l], dst, src) +} + +func (c *aesCipher) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } + if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } + decryptBlockGo(c.dec[:c.l], dst, src) +} diff --git a/contrib/go/_std_1.22/src/crypto/aes/cipher_asm.go b/contrib/go/_std_1.23/src/crypto/aes/cipher_asm.go similarity index 85% rename from contrib/go/_std_1.22/src/crypto/aes/cipher_asm.go rename to contrib/go/_std_1.23/src/crypto/aes/cipher_asm.go index 90031c5e2c58..3e5f589c2cdd 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cipher_asm.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cipher_asm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 || arm64 || ppc64 || ppc64le +//go:build (amd64 || arm64 || ppc64 || ppc64le) && !purego package aes @@ -44,8 +44,9 @@ func newCipher(key []byte) (cipher.Block, error) { if !supportsAES { return newCipherGeneric(key) } - n := len(key) + 28 - c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}} + // Note that under certain circumstances, we only return the inner aesCipherAsm. + // This avoids an unnecessary allocation of the aesCipher struct. + c := aesCipherGCM{aesCipherAsm{aesCipher{l: uint8(len(key) + 28)}}} var rounds int switch len(key) { case 128 / 8: @@ -60,9 +61,9 @@ func newCipher(key []byte) (cipher.Block, error) { expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0]) if supportsAES && supportsGFMUL { - return &aesCipherGCM{c}, nil + return &c, nil } - return &c, nil + return &c.aesCipherAsm, nil } func (c *aesCipherAsm) BlockSize() int { return BlockSize } @@ -78,7 +79,7 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("crypto/aes: invalid buffer overlap") } - encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0]) + encryptBlockAsm(int(c.l)/4-1, &c.enc[0], &dst[0], &src[0]) } func (c *aesCipherAsm) Decrypt(dst, src []byte) { @@ -92,7 +93,7 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("crypto/aes: invalid buffer overlap") } - decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0]) + decryptBlockAsm(int(c.l)/4-1, &c.dec[0], &dst[0], &src[0]) } // expandKey is used by BenchmarkExpand to ensure that the asm implementation diff --git a/contrib/go/_std_1.22/src/crypto/aes/cipher_generic.go b/contrib/go/_std_1.23/src/crypto/aes/cipher_generic.go similarity index 90% rename from contrib/go/_std_1.22/src/crypto/aes/cipher_generic.go rename to contrib/go/_std_1.23/src/crypto/aes/cipher_generic.go index 8a8a3fff3844..7c7d89aa873d 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cipher_generic.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cipher_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !s390x && !ppc64 && !ppc64le && !arm64 +//go:build (!amd64 && !s390x && !ppc64 && !ppc64le && !arm64) || purego package aes diff --git a/contrib/go/_std_1.22/src/crypto/aes/cipher_s390x.go b/contrib/go/_std_1.23/src/crypto/aes/cipher_s390x.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/cipher_s390x.go rename to contrib/go/_std_1.23/src/crypto/aes/cipher_s390x.go index 8dd3d8f0537f..1541890deab7 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cipher_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cipher_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package aes import ( diff --git a/contrib/go/_std_1.22/src/crypto/aes/const.go b/contrib/go/_std_1.23/src/crypto/aes/const.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/aes/const.go rename to contrib/go/_std_1.23/src/crypto/aes/const.go diff --git a/contrib/go/_std_1.22/src/crypto/aes/ctr_s390x.go b/contrib/go/_std_1.23/src/crypto/aes/ctr_s390x.go similarity index 90% rename from contrib/go/_std_1.22/src/crypto/aes/ctr_s390x.go rename to contrib/go/_std_1.23/src/crypto/aes/ctr_s390x.go index 921421533a44..56b82d58859c 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/ctr_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/ctr_s390x.go @@ -2,12 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package aes import ( "crypto/cipher" "crypto/internal/alias" - "encoding/binary" + "internal/byteorder" ) // Assert that aesCipherAsm implements the ctrAble interface. @@ -39,8 +41,8 @@ func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream { } var ac aesctr ac.block = c - ac.ctr[0] = binary.BigEndian.Uint64(iv[0:]) // high bits - ac.ctr[1] = binary.BigEndian.Uint64(iv[8:]) // low bits + ac.ctr[0] = byteorder.BeUint64(iv[0:]) // high bits + ac.ctr[1] = byteorder.BeUint64(iv[8:]) // low bits ac.buffer = ac.storage[:0] return &ac } @@ -50,8 +52,8 @@ func (c *aesctr) refill() { c.buffer = c.storage[:streamBufferSize] c0, c1 := c.ctr[0], c.ctr[1] for i := 0; i < streamBufferSize; i += 16 { - binary.BigEndian.PutUint64(c.buffer[i+0:], c0) - binary.BigEndian.PutUint64(c.buffer[i+8:], c1) + byteorder.BePutUint64(c.buffer[i+0:], c0) + byteorder.BePutUint64(c.buffer[i+8:], c1) // Increment in big endian: c0 is high, c1 is low. c1++ diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_amd64.s b/contrib/go/_std_1.23/src/crypto/aes/gcm_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_amd64.s rename to contrib/go/_std_1.23/src/crypto/aes/gcm_amd64.s index e6eedf326400..f787e6fd6bbe 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_amd64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // This is an optimized implementation of AES-GCM using AES-NI and CLMUL-NI // The implementation uses some optimization as described in: // [1] Gueron, S., Kounavis, M.E.: Intel® Carry-Less Multiplication diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_arm64.s b/contrib/go/_std_1.23/src/crypto/aes/gcm_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_arm64.s rename to contrib/go/_std_1.23/src/crypto/aes/gcm_arm64.s index c3501024c9f9..23ce1890e4e5 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" #define B0 V0 diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.go b/contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.go similarity index 91% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.go rename to contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.go index 2a7f898dc4be..f1e85129a8e0 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.go @@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64le || ppc64 +//go:build (ppc64le || ppc64) && !purego package aes import ( "crypto/cipher" "crypto/subtle" - "encoding/binary" "errors" + "internal/byteorder" "runtime" ) @@ -57,7 +57,7 @@ func counterCryptASM(nr int, out, in []byte, counter *[gcmBlockSize]byte, key *u // called by [crypto/cipher.NewGCM] via the gcmAble interface. func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { var h1, h2 uint64 - g := &gcmAsm{cipher: c, ks: c.enc, nonceSize: nonceSize, tagSize: tagSize} + g := &gcmAsm{cipher: c, ks: c.enc[:c.l], nonceSize: nonceSize, tagSize: tagSize} hle := make([]byte, gcmBlockSize) @@ -66,14 +66,14 @@ func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { // Reverse the bytes in each 8 byte chunk // Load little endian, store big endian if runtime.GOARCH == "ppc64le" { - h1 = binary.LittleEndian.Uint64(hle[:8]) - h2 = binary.LittleEndian.Uint64(hle[8:]) + h1 = byteorder.LeUint64(hle[:8]) + h2 = byteorder.LeUint64(hle[8:]) } else { - h1 = binary.BigEndian.Uint64(hle[:8]) - h2 = binary.BigEndian.Uint64(hle[8:]) + h1 = byteorder.BeUint64(hle[:8]) + h2 = byteorder.BeUint64(hle[8:]) } - binary.BigEndian.PutUint64(hle[:8], h1) - binary.BigEndian.PutUint64(hle[8:], h2) + byteorder.BePutUint64(hle[:8], h1) + byteorder.BePutUint64(hle[8:], h2) gcmInit(&g.productTable, hle) return g, nil @@ -119,14 +119,15 @@ func (g *gcmAsm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) { // counterCryptASM implements counterCrypt which then allows the loop to // be unrolled and optimized. func (g *gcmAsm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) { - counterCryptASM(len(g.cipher.enc)/4-1, out, in, counter, &g.cipher.enc[0]) + counterCryptASM(int(g.cipher.l)/4-1, out, in, counter, &g.cipher.enc[0]) + } // increments the rightmost 32-bits of the count value by 1. func gcmInc32(counterBlock *[16]byte) { c := counterBlock[len(counterBlock)-4:] - x := binary.BigEndian.Uint32(c) + 1 - binary.BigEndian.PutUint32(c, x) + x := byteorder.BeUint32(c) + 1 + byteorder.BePutUint32(c, x) } // paddedGHASH pads data with zeroes until its length is a multiple of @@ -211,9 +212,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { ret, out := sliceForAppend(dst, len(ciphertext)) if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.s b/contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.s index f661b2764279..987f4e718e12 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego // Portions based on CRYPTOGAMS code with the following comment: // # ==================================================================== diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_s390x.go b/contrib/go/_std_1.23/src/crypto/aes/gcm_s390x.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_s390x.go rename to contrib/go/_std_1.23/src/crypto/aes/gcm_s390x.go index cf0e28af695b..492ae5d83b48 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_s390x.go @@ -2,14 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package aes import ( "crypto/cipher" "crypto/internal/alias" "crypto/subtle" - "encoding/binary" "errors" + "internal/byteorder" "internal/cpu" ) @@ -23,14 +25,14 @@ type gcmCount [16]byte // inc increments the rightmost 32-bits of the count value by 1. func (x *gcmCount) inc() { - binary.BigEndian.PutUint32(x[len(x)-4:], binary.BigEndian.Uint32(x[len(x)-4:])+1) + byteorder.BePutUint32(x[len(x)-4:], byteorder.BeUint32(x[len(x)-4:])+1) } // gcmLengths writes len0 || len1 as big-endian values to a 16-byte array. func gcmLengths(len0, len1 uint64) [16]byte { v := [16]byte{} - binary.BigEndian.PutUint64(v[0:], len0) - binary.BigEndian.PutUint64(v[8:], len1) + byteorder.BePutUint64(v[0:], len0) + byteorder.BePutUint64(v[8:], len1) return v } @@ -269,9 +271,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { // so overwrites dst in the event of a tag mismatch. That // behavior is mimicked here in order to be consistent across // platforms. - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } @@ -361,9 +361,7 @@ func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { // so overwrites dst in the event of a tag mismatch. That // behavior is mimicked here in order to be consistent across // platforms. - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } diff --git a/contrib/go/_std_1.22/src/crypto/aes/modes.go b/contrib/go/_std_1.23/src/crypto/aes/modes.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/aes/modes.go rename to contrib/go/_std_1.23/src/crypto/aes/modes.go diff --git a/contrib/go/_std_1.23/src/crypto/aes/ya.make b/contrib/go/_std_1.23/src/crypto/aes/ya.make new file mode 100644 index 000000000000..ebc55b921a14 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/aes/ya.make @@ -0,0 +1,33 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + aes_gcm.go + asm_arm64.s + block.go + cipher.go + cipher_asm.go + const.go + gcm_arm64.s + modes.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + aes_gcm.go + asm_amd64.s + block.go + cipher.go + cipher_asm.go + const.go + gcm_amd64.s + modes.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + block.go + cipher.go + cipher_generic.go + const.go + modes.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/boring/boring.go b/contrib/go/_std_1.23/src/crypto/boring/boring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/boring/boring.go rename to contrib/go/_std_1.23/src/crypto/boring/boring.go diff --git a/contrib/go/_std_1.22/src/crypto/boring/ya.make b/contrib/go/_std_1.23/src/crypto/boring/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/boring/ya.make rename to contrib/go/_std_1.23/src/crypto/boring/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/cipher/cbc.go b/contrib/go/_std_1.23/src/crypto/cipher/cbc.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/cbc.go rename to contrib/go/_std_1.23/src/crypto/cipher/cbc.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/cfb.go b/contrib/go/_std_1.23/src/crypto/cipher/cfb.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/cfb.go rename to contrib/go/_std_1.23/src/crypto/cipher/cfb.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/cipher.go b/contrib/go/_std_1.23/src/crypto/cipher/cipher.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/cipher.go rename to contrib/go/_std_1.23/src/crypto/cipher/cipher.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/ctr.go b/contrib/go/_std_1.23/src/crypto/cipher/ctr.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/ctr.go rename to contrib/go/_std_1.23/src/crypto/cipher/ctr.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/gcm.go b/contrib/go/_std_1.23/src/crypto/cipher/gcm.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/cipher/gcm.go rename to contrib/go/_std_1.23/src/crypto/cipher/gcm.go index 928771f05f97..505be50c6ae5 100644 --- a/contrib/go/_std_1.22/src/crypto/cipher/gcm.go +++ b/contrib/go/_std_1.23/src/crypto/cipher/gcm.go @@ -7,8 +7,8 @@ package cipher import ( "crypto/internal/alias" "crypto/subtle" - "encoding/binary" "errors" + "internal/byteorder" ) // AEAD is a cipher mode providing authenticated encryption with associated @@ -137,8 +137,8 @@ func newGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, erro // would expect, say, 4*key to be in index 4 of the table but due to // this bit ordering it will actually be in index 0010 (base 2) = 2. x := gcmFieldElement{ - binary.BigEndian.Uint64(key[:8]), - binary.BigEndian.Uint64(key[8:]), + byteorder.BeUint64(key[:8]), + byteorder.BeUint64(key[8:]), } g.productTable[reverseBits(1)] = x @@ -234,9 +234,7 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { // so overwrites dst in the event of a tag mismatch. That // behavior is mimicked here in order to be consistent across // platforms. - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } @@ -323,8 +321,8 @@ func (g *gcm) mul(y *gcmFieldElement) { // Horner's rule. There must be a multiple of gcmBlockSize bytes in blocks. func (g *gcm) updateBlocks(y *gcmFieldElement, blocks []byte) { for len(blocks) > 0 { - y.low ^= binary.BigEndian.Uint64(blocks) - y.high ^= binary.BigEndian.Uint64(blocks[8:]) + y.low ^= byteorder.BeUint64(blocks) + y.high ^= byteorder.BeUint64(blocks[8:]) g.mul(y) blocks = blocks[gcmBlockSize:] } @@ -347,7 +345,7 @@ func (g *gcm) update(y *gcmFieldElement, data []byte) { // and increments it. func gcmInc32(counterBlock *[16]byte) { ctr := counterBlock[len(counterBlock)-4:] - binary.BigEndian.PutUint32(ctr, binary.BigEndian.Uint32(ctr)+1) + byteorder.BePutUint32(ctr, byteorder.BeUint32(ctr)+1) } // sliceForAppend takes a slice and a requested number of bytes. It returns a @@ -403,8 +401,8 @@ func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) { g.update(&y, nonce) y.high ^= uint64(len(nonce)) * 8 g.mul(&y) - binary.BigEndian.PutUint64(counter[:8], y.low) - binary.BigEndian.PutUint64(counter[8:], y.high) + byteorder.BePutUint64(counter[:8], y.low) + byteorder.BePutUint64(counter[8:], y.high) } } @@ -420,8 +418,8 @@ func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize] g.mul(&y) - binary.BigEndian.PutUint64(out, y.low) - binary.BigEndian.PutUint64(out[8:], y.high) + byteorder.BePutUint64(out, y.low) + byteorder.BePutUint64(out[8:], y.high) subtle.XORBytes(out, out, tagMask[:]) } diff --git a/contrib/go/_std_1.22/src/crypto/cipher/io.go b/contrib/go/_std_1.23/src/crypto/cipher/io.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/io.go rename to contrib/go/_std_1.23/src/crypto/cipher/io.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/ofb.go b/contrib/go/_std_1.23/src/crypto/cipher/ofb.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/ofb.go rename to contrib/go/_std_1.23/src/crypto/cipher/ofb.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/ya.make b/contrib/go/_std_1.23/src/crypto/cipher/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/ya.make rename to contrib/go/_std_1.23/src/crypto/cipher/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/crypto.go b/contrib/go/_std_1.23/src/crypto/crypto.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/crypto.go rename to contrib/go/_std_1.23/src/crypto/crypto.go diff --git a/contrib/go/_std_1.23/src/crypto/des/block.go b/contrib/go/_std_1.23/src/crypto/des/block.go new file mode 100644 index 000000000000..7a68a472b467 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/des/block.go @@ -0,0 +1,249 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package des + +import ( + "internal/byteorder" + "sync" +) + +func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) { + b := byteorder.BeUint64(src) + b = permuteInitialBlock(b) + left, right := uint32(b>>32), uint32(b) + + left = (left << 1) | (left >> 31) + right = (right << 1) | (right >> 31) + + if decrypt { + for i := 0; i < 8; i++ { + left, right = feistel(left, right, subkeys[15-2*i], subkeys[15-(2*i+1)]) + } + } else { + for i := 0; i < 8; i++ { + left, right = feistel(left, right, subkeys[2*i], subkeys[2*i+1]) + } + } + + left = (left << 31) | (left >> 1) + right = (right << 31) | (right >> 1) + + // switch left & right and perform final permutation + preOutput := (uint64(right) << 32) | uint64(left) + byteorder.BePutUint64(dst, permuteFinalBlock(preOutput)) +} + +// DES Feistel function. feistelBox must be initialized via +// feistelBoxOnce.Do(initFeistelBox) first. +func feistel(l, r uint32, k0, k1 uint64) (lout, rout uint32) { + var t uint32 + + t = r ^ uint32(k0>>32) + l ^= feistelBox[7][t&0x3f] ^ + feistelBox[5][(t>>8)&0x3f] ^ + feistelBox[3][(t>>16)&0x3f] ^ + feistelBox[1][(t>>24)&0x3f] + + t = ((r << 28) | (r >> 4)) ^ uint32(k0) + l ^= feistelBox[6][(t)&0x3f] ^ + feistelBox[4][(t>>8)&0x3f] ^ + feistelBox[2][(t>>16)&0x3f] ^ + feistelBox[0][(t>>24)&0x3f] + + t = l ^ uint32(k1>>32) + r ^= feistelBox[7][t&0x3f] ^ + feistelBox[5][(t>>8)&0x3f] ^ + feistelBox[3][(t>>16)&0x3f] ^ + feistelBox[1][(t>>24)&0x3f] + + t = ((l << 28) | (l >> 4)) ^ uint32(k1) + r ^= feistelBox[6][(t)&0x3f] ^ + feistelBox[4][(t>>8)&0x3f] ^ + feistelBox[2][(t>>16)&0x3f] ^ + feistelBox[0][(t>>24)&0x3f] + + return l, r +} + +// feistelBox[s][16*i+j] contains the output of permutationFunction +// for sBoxes[s][i][j] << 4*(7-s) +var feistelBox [8][64]uint32 + +var feistelBoxOnce sync.Once + +// general purpose function to perform DES block permutations. +func permuteBlock(src uint64, permutation []uint8) (block uint64) { + for position, n := range permutation { + bit := (src >> n) & 1 + block |= bit << uint((len(permutation)-1)-position) + } + return +} + +func initFeistelBox() { + for s := range sBoxes { + for i := 0; i < 4; i++ { + for j := 0; j < 16; j++ { + f := uint64(sBoxes[s][i][j]) << (4 * (7 - uint(s))) + f = permuteBlock(f, permutationFunction[:]) + + // Row is determined by the 1st and 6th bit. + // Column is the middle four bits. + row := uint8(((i & 2) << 4) | i&1) + col := uint8(j << 1) + t := row | col + + // The rotation was performed in the feistel rounds, being factored out and now mixed into the feistelBox. + f = (f << 1) | (f >> 31) + + feistelBox[s][t] = uint32(f) + } + } + } +} + +// permuteInitialBlock is equivalent to the permutation defined +// by initialPermutation. +func permuteInitialBlock(block uint64) uint64 { + // block = b7 b6 b5 b4 b3 b2 b1 b0 (8 bytes) + b1 := block >> 48 + b2 := block << 48 + block ^= b1 ^ b2 ^ b1<<48 ^ b2>>48 + + // block = b1 b0 b5 b4 b3 b2 b7 b6 + b1 = block >> 32 & 0xff00ff + b2 = (block & 0xff00ff00) + block ^= b1<<32 ^ b2 ^ b1<<8 ^ b2<<24 // exchange b0 b4 with b3 b7 + + // block is now b1 b3 b5 b7 b0 b2 b4 b6, the permutation: + // ... 8 + // ... 24 + // ... 40 + // ... 56 + // 7 6 5 4 3 2 1 0 + // 23 22 21 20 19 18 17 16 + // ... 32 + // ... 48 + + // exchange 4,5,6,7 with 32,33,34,35 etc. + b1 = block & 0x0f0f00000f0f0000 + b2 = block & 0x0000f0f00000f0f0 + block ^= b1 ^ b2 ^ b1>>12 ^ b2<<12 + + // block is the permutation: + // + // [+8] [+40] + // + // 7 6 5 4 + // 23 22 21 20 + // 3 2 1 0 + // 19 18 17 16 [+32] + + // exchange 0,1,4,5 with 18,19,22,23 + b1 = block & 0x3300330033003300 + b2 = block & 0x00cc00cc00cc00cc + block ^= b1 ^ b2 ^ b1>>6 ^ b2<<6 + + // block is the permutation: + // 15 14 + // 13 12 + // 11 10 + // 9 8 + // 7 6 + // 5 4 + // 3 2 + // 1 0 [+16] [+32] [+64] + + // exchange 0,2,4,6 with 9,11,13,15: + b1 = block & 0xaaaaaaaa55555555 + block ^= b1 ^ b1>>33 ^ b1<<33 + + // block is the permutation: + // 6 14 22 30 38 46 54 62 + // 4 12 20 28 36 44 52 60 + // 2 10 18 26 34 42 50 58 + // 0 8 16 24 32 40 48 56 + // 7 15 23 31 39 47 55 63 + // 5 13 21 29 37 45 53 61 + // 3 11 19 27 35 43 51 59 + // 1 9 17 25 33 41 49 57 + return block +} + +// permuteFinalBlock is equivalent to the permutation defined +// by finalPermutation. +func permuteFinalBlock(block uint64) uint64 { + // Perform the same bit exchanges as permuteInitialBlock + // but in reverse order. + b1 := block & 0xaaaaaaaa55555555 + block ^= b1 ^ b1>>33 ^ b1<<33 + + b1 = block & 0x3300330033003300 + b2 := block & 0x00cc00cc00cc00cc + block ^= b1 ^ b2 ^ b1>>6 ^ b2<<6 + + b1 = block & 0x0f0f00000f0f0000 + b2 = block & 0x0000f0f00000f0f0 + block ^= b1 ^ b2 ^ b1>>12 ^ b2<<12 + + b1 = block >> 32 & 0xff00ff + b2 = (block & 0xff00ff00) + block ^= b1<<32 ^ b2 ^ b1<<8 ^ b2<<24 + + b1 = block >> 48 + b2 = block << 48 + block ^= b1 ^ b2 ^ b1<<48 ^ b2>>48 + return block +} + +// creates 16 28-bit blocks rotated according +// to the rotation schedule. +func ksRotate(in uint32) (out []uint32) { + out = make([]uint32, 16) + last := in + for i := 0; i < 16; i++ { + // 28-bit circular left shift + left := (last << (4 + ksRotations[i])) >> 4 + right := (last << 4) >> (32 - ksRotations[i]) + out[i] = left | right + last = out[i] + } + return +} + +// creates 16 56-bit subkeys from the original key. +func (c *desCipher) generateSubkeys(keyBytes []byte) { + feistelBoxOnce.Do(initFeistelBox) + + // apply PC1 permutation to key + key := byteorder.BeUint64(keyBytes) + permutedKey := permuteBlock(key, permutedChoice1[:]) + + // rotate halves of permuted key according to the rotation schedule + leftRotations := ksRotate(uint32(permutedKey >> 28)) + rightRotations := ksRotate(uint32(permutedKey<<4) >> 4) + + // generate subkeys + for i := 0; i < 16; i++ { + // combine halves to form 56-bit input to PC2 + pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i]) + // apply PC2 permutation to 7 byte input + c.subkeys[i] = unpack(permuteBlock(pc2Input, permutedChoice2[:])) + } +} + +// Expand 48-bit input to 64-bit, with each 6-bit block padded by extra two bits at the top. +// By doing so, we can have the input blocks (four bits each), and the key blocks (six bits each) well-aligned without +// extra shifts/rotations for alignments. +func unpack(x uint64) uint64 { + return ((x>>(6*1))&0xff)<<(8*0) | + ((x>>(6*3))&0xff)<<(8*1) | + ((x>>(6*5))&0xff)<<(8*2) | + ((x>>(6*7))&0xff)<<(8*3) | + ((x>>(6*0))&0xff)<<(8*4) | + ((x>>(6*2))&0xff)<<(8*5) | + ((x>>(6*4))&0xff)<<(8*6) | + ((x>>(6*6))&0xff)<<(8*7) +} diff --git a/contrib/go/_std_1.23/src/crypto/des/cipher.go b/contrib/go/_std_1.23/src/crypto/des/cipher.go new file mode 100644 index 000000000000..04b73e7d3bf7 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/des/cipher.go @@ -0,0 +1,155 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package des + +import ( + "crypto/cipher" + "crypto/internal/alias" + "internal/byteorder" + "strconv" +) + +// The DES block size in bytes. +const BlockSize = 8 + +type KeySizeError int + +func (k KeySizeError) Error() string { + return "crypto/des: invalid key size " + strconv.Itoa(int(k)) +} + +// desCipher is an instance of DES encryption. +type desCipher struct { + subkeys [16]uint64 +} + +// NewCipher creates and returns a new [cipher.Block]. +func NewCipher(key []byte) (cipher.Block, error) { + if len(key) != 8 { + return nil, KeySizeError(len(key)) + } + + c := new(desCipher) + c.generateSubkeys(key) + return c, nil +} + +func (c *desCipher) BlockSize() int { return BlockSize } + +func (c *desCipher) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + cryptBlock(c.subkeys[:], dst, src, false) +} + +func (c *desCipher) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + cryptBlock(c.subkeys[:], dst, src, true) +} + +// A tripleDESCipher is an instance of TripleDES encryption. +type tripleDESCipher struct { + cipher1, cipher2, cipher3 desCipher +} + +// NewTripleDESCipher creates and returns a new [cipher.Block]. +func NewTripleDESCipher(key []byte) (cipher.Block, error) { + if len(key) != 24 { + return nil, KeySizeError(len(key)) + } + + c := new(tripleDESCipher) + c.cipher1.generateSubkeys(key[:8]) + c.cipher2.generateSubkeys(key[8:16]) + c.cipher3.generateSubkeys(key[16:]) + return c, nil +} + +func (c *tripleDESCipher) BlockSize() int { return BlockSize } + +func (c *tripleDESCipher) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + + b := byteorder.BeUint64(src) + b = permuteInitialBlock(b) + left, right := uint32(b>>32), uint32(b) + + left = (left << 1) | (left >> 31) + right = (right << 1) | (right >> 31) + + for i := 0; i < 8; i++ { + left, right = feistel(left, right, c.cipher1.subkeys[2*i], c.cipher1.subkeys[2*i+1]) + } + for i := 0; i < 8; i++ { + right, left = feistel(right, left, c.cipher2.subkeys[15-2*i], c.cipher2.subkeys[15-(2*i+1)]) + } + for i := 0; i < 8; i++ { + left, right = feistel(left, right, c.cipher3.subkeys[2*i], c.cipher3.subkeys[2*i+1]) + } + + left = (left << 31) | (left >> 1) + right = (right << 31) | (right >> 1) + + preOutput := (uint64(right) << 32) | uint64(left) + byteorder.BePutUint64(dst, permuteFinalBlock(preOutput)) +} + +func (c *tripleDESCipher) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + + b := byteorder.BeUint64(src) + b = permuteInitialBlock(b) + left, right := uint32(b>>32), uint32(b) + + left = (left << 1) | (left >> 31) + right = (right << 1) | (right >> 31) + + for i := 0; i < 8; i++ { + left, right = feistel(left, right, c.cipher3.subkeys[15-2*i], c.cipher3.subkeys[15-(2*i+1)]) + } + for i := 0; i < 8; i++ { + right, left = feistel(right, left, c.cipher2.subkeys[2*i], c.cipher2.subkeys[2*i+1]) + } + for i := 0; i < 8; i++ { + left, right = feistel(left, right, c.cipher1.subkeys[15-2*i], c.cipher1.subkeys[15-(2*i+1)]) + } + + left = (left << 31) | (left >> 1) + right = (right << 31) | (right >> 1) + + preOutput := (uint64(right) << 32) | uint64(left) + byteorder.BePutUint64(dst, permuteFinalBlock(preOutput)) +} diff --git a/contrib/go/_std_1.22/src/crypto/des/const.go b/contrib/go/_std_1.23/src/crypto/des/const.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/des/const.go rename to contrib/go/_std_1.23/src/crypto/des/const.go diff --git a/contrib/go/_std_1.22/src/crypto/des/ya.make b/contrib/go/_std_1.23/src/crypto/des/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/des/ya.make rename to contrib/go/_std_1.23/src/crypto/des/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/dsa/dsa.go b/contrib/go/_std_1.23/src/crypto/dsa/dsa.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/dsa/dsa.go rename to contrib/go/_std_1.23/src/crypto/dsa/dsa.go diff --git a/contrib/go/_std_1.22/src/crypto/dsa/ya.make b/contrib/go/_std_1.23/src/crypto/dsa/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/dsa/ya.make rename to contrib/go/_std_1.23/src/crypto/dsa/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/ecdh/ecdh.go b/contrib/go/_std_1.23/src/crypto/ecdh/ecdh.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdh/ecdh.go rename to contrib/go/_std_1.23/src/crypto/ecdh/ecdh.go diff --git a/contrib/go/_std_1.22/src/crypto/ecdh/nist.go b/contrib/go/_std_1.23/src/crypto/ecdh/nist.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/ecdh/nist.go rename to contrib/go/_std_1.23/src/crypto/ecdh/nist.go index b3664915449b..b91e8f38a5a7 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdh/nist.go +++ b/contrib/go/_std_1.23/src/crypto/ecdh/nist.go @@ -8,8 +8,8 @@ import ( "crypto/internal/boring" "crypto/internal/nistec" "crypto/internal/randutil" - "encoding/binary" "errors" + "internal/byteorder" "io" "math/bits" ) @@ -156,7 +156,7 @@ func isLess(a, b []byte) bool { // Perform a subtraction with borrow. var borrow uint64 for i := 0; i < len(bufA); i += 8 { - limbA, limbB := binary.LittleEndian.Uint64(bufA[i:]), binary.LittleEndian.Uint64(bufB[i:]) + limbA, limbB := byteorder.LeUint64(bufA[i:]), byteorder.LeUint64(bufB[i:]) _, borrow = bits.Sub64(limbA, limbB, borrow) } diff --git a/contrib/go/_std_1.22/src/crypto/ecdh/x25519.go b/contrib/go/_std_1.23/src/crypto/ecdh/x25519.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdh/x25519.go rename to contrib/go/_std_1.23/src/crypto/ecdh/x25519.go diff --git a/contrib/go/_std_1.22/src/crypto/ecdh/ya.make b/contrib/go/_std_1.23/src/crypto/ecdh/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdh/ya.make rename to contrib/go/_std_1.23/src/crypto/ecdh/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/boring.go b/contrib/go/_std_1.23/src/crypto/ecdsa/boring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdsa/boring.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/boring.go diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa.go b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa.go index 3ed15a888a75..2179b01e8e3d 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa.go +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa.go @@ -8,6 +8,10 @@ // Signatures generated by this package are not deterministic, but entropy is // mixed with the private key and the message, achieving the same level of // security in case of randomness source failure. +// +// Operations involving private keys are implemented using constant-time +// algorithms, as long as an [elliptic.Curve] returned by [elliptic.P224], +// [elliptic.P256], [elliptic.P384], or [elliptic.P521] is used. package ecdsa // [FIPS 186-4] references ANSI X9.62-2005 for the bulk of the ECDSA algorithm. @@ -457,14 +461,15 @@ var zeroReader = zr{} // Read replaces the contents of dst with zeros. It is safe for concurrent use. func (zr) Read(dst []byte) (n int, err error) { - for i := range dst { - dst[i] = 0 - } + clear(dst) return len(dst), nil } // VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the // public key, pub. Its return value records whether the signature is valid. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func VerifyASN1(pub *PublicKey, hash, sig []byte) bool { if boring.Enabled { key, err := boringPublicKey(pub) diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_legacy.go b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_legacy.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_legacy.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_legacy.go index 0b8489ab66fd..dc1c5d120ae6 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_legacy.go +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_legacy.go @@ -115,6 +115,9 @@ func signLegacy(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, er // Verify verifies the signature in r, s of hash using the public key, pub. Its // return value records whether the signature is valid. Most applications should // use VerifyASN1 instead of dealing directly with r, s. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { if r.Sign() <= 0 || s.Sign() <= 0 { return false diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_noasm.go b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_noasm.go similarity index 93% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_noasm.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_noasm.go index a72aa4b04ef5..e2fa8082f68d 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_noasm.go +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !s390x +//go:build !s390x || purego package ecdsa diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.go b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.go index 49f645a48927..8ebf15a525fb 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package ecdsa import ( diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.s b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.s similarity index 97% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.s rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.s index ea1f4469e991..2aae59c291d1 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func kdsa(fc uint64, params *[4096]byte) (errn uint64) diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/notboring.go b/contrib/go/_std_1.23/src/crypto/ecdsa/notboring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdsa/notboring.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/notboring.go diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ya.make b/contrib/go/_std_1.23/src/crypto/ecdsa/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ya.make rename to contrib/go/_std_1.23/src/crypto/ecdsa/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/ed25519/ed25519.go b/contrib/go/_std_1.23/src/crypto/ed25519/ed25519.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/ed25519/ed25519.go rename to contrib/go/_std_1.23/src/crypto/ed25519/ed25519.go index 1dda9e5e9a5a..b75c5a6458a2 100644 --- a/contrib/go/_std_1.22/src/crypto/ed25519/ed25519.go +++ b/contrib/go/_std_1.23/src/crypto/ed25519/ed25519.go @@ -10,6 +10,9 @@ // representation includes a public key suffix to make multiple signing // operations with the same key more efficient. This package refers to the RFC // 8032 private key as the “seed”. +// +// Operations involving private keys are implemented using constant-time +// algorithms. package ed25519 import ( @@ -258,6 +261,9 @@ func sign(signature, privateKey, message []byte, domPrefix, context string) { // Verify reports whether sig is a valid signature of message by publicKey. It // will panic if len(publicKey) is not [PublicKeySize]. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func Verify(publicKey PublicKey, message, sig []byte) bool { return verify(publicKey, message, sig, domPrefixPure, "") } @@ -270,6 +276,9 @@ func Verify(publicKey PublicKey, message, sig []byte) bool { // message is expected to be a SHA-512 hash, otherwise opts.Hash must be // [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two // passes over messages to be signed. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error { switch { case opts.Hash == crypto.SHA512: // Ed25519ph diff --git a/contrib/go/_std_1.22/src/crypto/ed25519/ya.make b/contrib/go/_std_1.23/src/crypto/ed25519/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ed25519/ya.make rename to contrib/go/_std_1.23/src/crypto/ed25519/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/elliptic/elliptic.go b/contrib/go/_std_1.23/src/crypto/elliptic/elliptic.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/elliptic/elliptic.go rename to contrib/go/_std_1.23/src/crypto/elliptic/elliptic.go diff --git a/contrib/go/_std_1.22/src/crypto/elliptic/nistec.go b/contrib/go/_std_1.23/src/crypto/elliptic/nistec.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/elliptic/nistec.go rename to contrib/go/_std_1.23/src/crypto/elliptic/nistec.go diff --git a/contrib/go/_std_1.22/src/crypto/elliptic/nistec_p256.go b/contrib/go/_std_1.23/src/crypto/elliptic/nistec_p256.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/elliptic/nistec_p256.go rename to contrib/go/_std_1.23/src/crypto/elliptic/nistec_p256.go diff --git a/contrib/go/_std_1.22/src/crypto/elliptic/params.go b/contrib/go/_std_1.23/src/crypto/elliptic/params.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/elliptic/params.go rename to contrib/go/_std_1.23/src/crypto/elliptic/params.go index 716e2c06ba87..0507d22b277f 100644 --- a/contrib/go/_std_1.22/src/crypto/elliptic/params.go +++ b/contrib/go/_std_1.23/src/crypto/elliptic/params.go @@ -201,7 +201,7 @@ func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int // Double implements [Curve.Double]. // -// Deprecated: the [CurveParams】 methods are deprecated and are not guaranteed to +// Deprecated: the [CurveParams] methods are deprecated and are not guaranteed to // provide any security property. For ECDH, use the [crypto/ecdh] package. // For ECDSA, use the [crypto/ecdsa] package with a [Curve] value returned directly // from [P224], [P256], [P384], or [P521]. diff --git a/contrib/go/_std_1.23/src/crypto/elliptic/ya.make b/contrib/go/_std_1.23/src/crypto/elliptic/ya.make new file mode 100644 index 000000000000..0b5e4d2e0e12 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/elliptic/ya.make @@ -0,0 +1,16 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + elliptic.go + nistec.go + nistec_p256.go + params.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + elliptic.go + nistec.go + params.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/hmac/hmac.go b/contrib/go/_std_1.23/src/crypto/hmac/hmac.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/hmac/hmac.go rename to contrib/go/_std_1.23/src/crypto/hmac/hmac.go diff --git a/contrib/go/_std_1.22/src/crypto/hmac/ya.make b/contrib/go/_std_1.23/src/crypto/hmac/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/hmac/ya.make rename to contrib/go/_std_1.23/src/crypto/hmac/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/alias/alias.go b/contrib/go/_std_1.23/src/crypto/internal/alias/alias.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/alias/alias.go rename to contrib/go/_std_1.23/src/crypto/internal/alias/alias.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/alias/ya.make b/contrib/go/_std_1.23/src/crypto/internal/alias/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/alias/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/alias/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/go.mod b/contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/go.mod similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/go.mod rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/go.mod diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/go.sum b/contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/go.sum similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/go.sum rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/go.sum diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go b/contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go diff --git a/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat.go b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat.go new file mode 100644 index 000000000000..5cbae40efe99 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat.go @@ -0,0 +1,787 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bigmod + +import ( + "errors" + "internal/byteorder" + "math/big" + "math/bits" +) + +const ( + // _W is the size in bits of our limbs. + _W = bits.UintSize + // _S is the size in bytes of our limbs. + _S = _W / 8 +) + +// choice represents a constant-time boolean. The value of choice is always +// either 1 or 0. We use an int instead of bool in order to make decisions in +// constant time by turning it into a mask. +type choice uint + +func not(c choice) choice { return 1 ^ c } + +const yes = choice(1) +const no = choice(0) + +// ctMask is all 1s if on is yes, and all 0s otherwise. +func ctMask(on choice) uint { return -uint(on) } + +// ctEq returns 1 if x == y, and 0 otherwise. The execution time of this +// function does not depend on its inputs. +func ctEq(x, y uint) choice { + // If x != y, then either x - y or y - x will generate a carry. + _, c1 := bits.Sub(x, y, 0) + _, c2 := bits.Sub(y, x, 0) + return not(choice(c1 | c2)) +} + +// Nat represents an arbitrary natural number +// +// Each Nat has an announced length, which is the number of limbs it has stored. +// Operations on this number are allowed to leak this length, but will not leak +// any information about the values contained in those limbs. +type Nat struct { + // limbs is little-endian in base 2^W with W = bits.UintSize. + limbs []uint +} + +// preallocTarget is the size in bits of the numbers used to implement the most +// common and most performant RSA key size. It's also enough to cover some of +// the operations of key sizes up to 4096. +const preallocTarget = 2048 +const preallocLimbs = (preallocTarget + _W - 1) / _W + +// NewNat returns a new nat with a size of zero, just like new(Nat), but with +// the preallocated capacity to hold a number of up to preallocTarget bits. +// NewNat inlines, so the allocation can live on the stack. +func NewNat() *Nat { + limbs := make([]uint, 0, preallocLimbs) + return &Nat{limbs} +} + +// expand expands x to n limbs, leaving its value unchanged. +func (x *Nat) expand(n int) *Nat { + if len(x.limbs) > n { + panic("bigmod: internal error: shrinking nat") + } + if cap(x.limbs) < n { + newLimbs := make([]uint, n) + copy(newLimbs, x.limbs) + x.limbs = newLimbs + return x + } + extraLimbs := x.limbs[len(x.limbs):n] + clear(extraLimbs) + x.limbs = x.limbs[:n] + return x +} + +// reset returns a zero nat of n limbs, reusing x's storage if n <= cap(x.limbs). +func (x *Nat) reset(n int) *Nat { + if cap(x.limbs) < n { + x.limbs = make([]uint, n) + return x + } + clear(x.limbs) + x.limbs = x.limbs[:n] + return x +} + +// set assigns x = y, optionally resizing x to the appropriate size. +func (x *Nat) set(y *Nat) *Nat { + x.reset(len(y.limbs)) + copy(x.limbs, y.limbs) + return x +} + +// setBig assigns x = n, optionally resizing n to the appropriate size. +// +// The announced length of x is set based on the actual bit size of the input, +// ignoring leading zeroes. +func (x *Nat) setBig(n *big.Int) *Nat { + limbs := n.Bits() + x.reset(len(limbs)) + for i := range limbs { + x.limbs[i] = uint(limbs[i]) + } + return x +} + +// Bytes returns x as a zero-extended big-endian byte slice. The size of the +// slice will match the size of m. +// +// x must have the same size as m and it must be reduced modulo m. +func (x *Nat) Bytes(m *Modulus) []byte { + i := m.Size() + bytes := make([]byte, i) + for _, limb := range x.limbs { + for j := 0; j < _S; j++ { + i-- + if i < 0 { + if limb == 0 { + break + } + panic("bigmod: modulus is smaller than nat") + } + bytes[i] = byte(limb) + limb >>= 8 + } + } + return bytes +} + +// SetBytes assigns x = b, where b is a slice of big-endian bytes. +// SetBytes returns an error if b >= m. +// +// The output will be resized to the size of m and overwritten. +func (x *Nat) SetBytes(b []byte, m *Modulus) (*Nat, error) { + if err := x.setBytes(b, m); err != nil { + return nil, err + } + if x.cmpGeq(m.nat) == yes { + return nil, errors.New("input overflows the modulus") + } + return x, nil +} + +// SetOverflowingBytes assigns x = b, where b is a slice of big-endian bytes. +// SetOverflowingBytes returns an error if b has a longer bit length than m, but +// reduces overflowing values up to 2^⌈log2(m)⌉ - 1. +// +// The output will be resized to the size of m and overwritten. +func (x *Nat) SetOverflowingBytes(b []byte, m *Modulus) (*Nat, error) { + if err := x.setBytes(b, m); err != nil { + return nil, err + } + leading := _W - bitLen(x.limbs[len(x.limbs)-1]) + if leading < m.leading { + return nil, errors.New("input overflows the modulus size") + } + x.maybeSubtractModulus(no, m) + return x, nil +} + +// bigEndianUint returns the contents of buf interpreted as a +// big-endian encoded uint value. +func bigEndianUint(buf []byte) uint { + if _W == 64 { + return uint(byteorder.BeUint64(buf)) + } + return uint(byteorder.BeUint32(buf)) +} + +func (x *Nat) setBytes(b []byte, m *Modulus) error { + x.resetFor(m) + i, k := len(b), 0 + for k < len(x.limbs) && i >= _S { + x.limbs[k] = bigEndianUint(b[i-_S : i]) + i -= _S + k++ + } + for s := 0; s < _W && k < len(x.limbs) && i > 0; s += 8 { + x.limbs[k] |= uint(b[i-1]) << s + i-- + } + if i > 0 { + return errors.New("input overflows the modulus size") + } + return nil +} + +// Equal returns 1 if x == y, and 0 otherwise. +// +// Both operands must have the same announced length. +func (x *Nat) Equal(y *Nat) choice { + // Eliminate bounds checks in the loop. + size := len(x.limbs) + xLimbs := x.limbs[:size] + yLimbs := y.limbs[:size] + + equal := yes + for i := 0; i < size; i++ { + equal &= ctEq(xLimbs[i], yLimbs[i]) + } + return equal +} + +// IsZero returns 1 if x == 0, and 0 otherwise. +func (x *Nat) IsZero() choice { + // Eliminate bounds checks in the loop. + size := len(x.limbs) + xLimbs := x.limbs[:size] + + zero := yes + for i := 0; i < size; i++ { + zero &= ctEq(xLimbs[i], 0) + } + return zero +} + +// cmpGeq returns 1 if x >= y, and 0 otherwise. +// +// Both operands must have the same announced length. +func (x *Nat) cmpGeq(y *Nat) choice { + // Eliminate bounds checks in the loop. + size := len(x.limbs) + xLimbs := x.limbs[:size] + yLimbs := y.limbs[:size] + + var c uint + for i := 0; i < size; i++ { + _, c = bits.Sub(xLimbs[i], yLimbs[i], c) + } + // If there was a carry, then subtracting y underflowed, so + // x is not greater than or equal to y. + return not(choice(c)) +} + +// assign sets x <- y if on == 1, and does nothing otherwise. +// +// Both operands must have the same announced length. +func (x *Nat) assign(on choice, y *Nat) *Nat { + // Eliminate bounds checks in the loop. + size := len(x.limbs) + xLimbs := x.limbs[:size] + yLimbs := y.limbs[:size] + + mask := ctMask(on) + for i := 0; i < size; i++ { + xLimbs[i] ^= mask & (xLimbs[i] ^ yLimbs[i]) + } + return x +} + +// add computes x += y and returns the carry. +// +// Both operands must have the same announced length. +func (x *Nat) add(y *Nat) (c uint) { + // Eliminate bounds checks in the loop. + size := len(x.limbs) + xLimbs := x.limbs[:size] + yLimbs := y.limbs[:size] + + for i := 0; i < size; i++ { + xLimbs[i], c = bits.Add(xLimbs[i], yLimbs[i], c) + } + return +} + +// sub computes x -= y. It returns the borrow of the subtraction. +// +// Both operands must have the same announced length. +func (x *Nat) sub(y *Nat) (c uint) { + // Eliminate bounds checks in the loop. + size := len(x.limbs) + xLimbs := x.limbs[:size] + yLimbs := y.limbs[:size] + + for i := 0; i < size; i++ { + xLimbs[i], c = bits.Sub(xLimbs[i], yLimbs[i], c) + } + return +} + +// Modulus is used for modular arithmetic, precomputing relevant constants. +// +// Moduli are assumed to be odd numbers. Moduli can also leak the exact +// number of bits needed to store their value, and are stored without padding. +// +// Their actual value is still kept secret. +type Modulus struct { + // The underlying natural number for this modulus. + // + // This will be stored without any padding, and shouldn't alias with any + // other natural number being used. + nat *Nat + leading int // number of leading zeros in the modulus + m0inv uint // -nat.limbs[0]⁻¹ mod _W + rr *Nat // R*R for montgomeryRepresentation +} + +// rr returns R*R with R = 2^(_W * n) and n = len(m.nat.limbs). +func rr(m *Modulus) *Nat { + rr := NewNat().ExpandFor(m) + n := uint(len(rr.limbs)) + mLen := uint(m.BitLen()) + logR := _W * n + + // We start by computing R = 2^(_W * n) mod m. We can get pretty close, to + // 2^⌊log₂m⌋, by setting the highest bit we can without having to reduce. + rr.limbs[n-1] = 1 << ((mLen - 1) % _W) + // Then we double until we reach 2^(_W * n). + for i := mLen - 1; i < logR; i++ { + rr.Add(rr, m) + } + + // Next we need to get from R to 2^(_W * n) R mod m (aka from one to R in + // the Montgomery domain, meaning we can use Montgomery multiplication now). + // We could do that by doubling _W * n times, or with a square-and-double + // chain log2(_W * n) long. Turns out the fastest thing is to start out with + // doublings, and switch to square-and-double once the exponent is large + // enough to justify the cost of the multiplications. + + // The threshold is selected experimentally as a linear function of n. + threshold := n / 4 + + // We calculate how many of the most-significant bits of the exponent we can + // compute before crossing the threshold, and we do it with doublings. + i := bits.UintSize + for logR>>i <= threshold { + i-- + } + for k := uint(0); k < logR>>i; k++ { + rr.Add(rr, m) + } + + // Then we process the remaining bits of the exponent with a + // square-and-double chain. + for i > 0 { + rr.montgomeryMul(rr, rr, m) + i-- + if logR>>i&1 != 0 { + rr.Add(rr, m) + } + } + + return rr +} + +// minusInverseModW computes -x⁻¹ mod _W with x odd. +// +// This operation is used to precompute a constant involved in Montgomery +// multiplication. +func minusInverseModW(x uint) uint { + // Every iteration of this loop doubles the least-significant bits of + // correct inverse in y. The first three bits are already correct (1⁻¹ = 1, + // 3⁻¹ = 3, 5⁻¹ = 5, and 7⁻¹ = 7 mod 8), so doubling five times is enough + // for 64 bits (and wastes only one iteration for 32 bits). + // + // See https://crypto.stackexchange.com/a/47496. + y := x + for i := 0; i < 5; i++ { + y = y * (2 - x*y) + } + return -y +} + +// NewModulusFromBig creates a new Modulus from a [big.Int]. +// +// The Int must be odd. The number of significant bits (and nothing else) is +// leaked through timing side-channels. +func NewModulusFromBig(n *big.Int) (*Modulus, error) { + if b := n.Bits(); len(b) == 0 { + return nil, errors.New("modulus must be >= 0") + } else if b[0]&1 != 1 { + return nil, errors.New("modulus must be odd") + } + m := &Modulus{} + m.nat = NewNat().setBig(n) + m.leading = _W - bitLen(m.nat.limbs[len(m.nat.limbs)-1]) + m.m0inv = minusInverseModW(m.nat.limbs[0]) + m.rr = rr(m) + return m, nil +} + +// bitLen is a version of bits.Len that only leaks the bit length of n, but not +// its value. bits.Len and bits.LeadingZeros use a lookup table for the +// low-order bits on some architectures. +func bitLen(n uint) int { + var len int + // We assume, here and elsewhere, that comparison to zero is constant time + // with respect to different non-zero values. + for n != 0 { + len++ + n >>= 1 + } + return len +} + +// Size returns the size of m in bytes. +func (m *Modulus) Size() int { + return (m.BitLen() + 7) / 8 +} + +// BitLen returns the size of m in bits. +func (m *Modulus) BitLen() int { + return len(m.nat.limbs)*_W - int(m.leading) +} + +// Nat returns m as a Nat. The return value must not be written to. +func (m *Modulus) Nat() *Nat { + return m.nat +} + +// shiftIn calculates x = x << _W + y mod m. +// +// This assumes that x is already reduced mod m. +func (x *Nat) shiftIn(y uint, m *Modulus) *Nat { + d := NewNat().resetFor(m) + + // Eliminate bounds checks in the loop. + size := len(m.nat.limbs) + xLimbs := x.limbs[:size] + dLimbs := d.limbs[:size] + mLimbs := m.nat.limbs[:size] + + // Each iteration of this loop computes x = 2x + b mod m, where b is a bit + // from y. Effectively, it left-shifts x and adds y one bit at a time, + // reducing it every time. + // + // To do the reduction, each iteration computes both 2x + b and 2x + b - m. + // The next iteration (and finally the return line) will use either result + // based on whether 2x + b overflows m. + needSubtraction := no + for i := _W - 1; i >= 0; i-- { + carry := (y >> i) & 1 + var borrow uint + mask := ctMask(needSubtraction) + for i := 0; i < size; i++ { + l := xLimbs[i] ^ (mask & (xLimbs[i] ^ dLimbs[i])) + xLimbs[i], carry = bits.Add(l, l, carry) + dLimbs[i], borrow = bits.Sub(xLimbs[i], mLimbs[i], borrow) + } + // Like in maybeSubtractModulus, we need the subtraction if either it + // didn't underflow (meaning 2x + b > m) or if computing 2x + b + // overflowed (meaning 2x + b > 2^_W*n > m). + needSubtraction = not(choice(borrow)) | choice(carry) + } + return x.assign(needSubtraction, d) +} + +// Mod calculates out = x mod m. +// +// This works regardless how large the value of x is. +// +// The output will be resized to the size of m and overwritten. +func (out *Nat) Mod(x *Nat, m *Modulus) *Nat { + out.resetFor(m) + // Working our way from the most significant to the least significant limb, + // we can insert each limb at the least significant position, shifting all + // previous limbs left by _W. This way each limb will get shifted by the + // correct number of bits. We can insert at least N - 1 limbs without + // overflowing m. After that, we need to reduce every time we shift. + i := len(x.limbs) - 1 + // For the first N - 1 limbs we can skip the actual shifting and position + // them at the shifted position, which starts at min(N - 2, i). + start := len(m.nat.limbs) - 2 + if i < start { + start = i + } + for j := start; j >= 0; j-- { + out.limbs[j] = x.limbs[i] + i-- + } + // We shift in the remaining limbs, reducing modulo m each time. + for i >= 0 { + out.shiftIn(x.limbs[i], m) + i-- + } + return out +} + +// ExpandFor ensures x has the right size to work with operations modulo m. +// +// The announced size of x must be smaller than or equal to that of m. +func (x *Nat) ExpandFor(m *Modulus) *Nat { + return x.expand(len(m.nat.limbs)) +} + +// resetFor ensures out has the right size to work with operations modulo m. +// +// out is zeroed and may start at any size. +func (out *Nat) resetFor(m *Modulus) *Nat { + return out.reset(len(m.nat.limbs)) +} + +// maybeSubtractModulus computes x -= m if and only if x >= m or if "always" is yes. +// +// It can be used to reduce modulo m a value up to 2m - 1, which is a common +// range for results computed by higher level operations. +// +// always is usually a carry that indicates that the operation that produced x +// overflowed its size, meaning abstractly x > 2^_W*n > m even if x < m. +// +// x and m operands must have the same announced length. +func (x *Nat) maybeSubtractModulus(always choice, m *Modulus) { + t := NewNat().set(x) + underflow := t.sub(m.nat) + // We keep the result if x - m didn't underflow (meaning x >= m) + // or if always was set. + keep := not(choice(underflow)) | choice(always) + x.assign(keep, t) +} + +// Sub computes x = x - y mod m. +// +// The length of both operands must be the same as the modulus. Both operands +// must already be reduced modulo m. +func (x *Nat) Sub(y *Nat, m *Modulus) *Nat { + underflow := x.sub(y) + // If the subtraction underflowed, add m. + t := NewNat().set(x) + t.add(m.nat) + x.assign(choice(underflow), t) + return x +} + +// Add computes x = x + y mod m. +// +// The length of both operands must be the same as the modulus. Both operands +// must already be reduced modulo m. +func (x *Nat) Add(y *Nat, m *Modulus) *Nat { + overflow := x.add(y) + x.maybeSubtractModulus(choice(overflow), m) + return x +} + +// montgomeryRepresentation calculates x = x * R mod m, with R = 2^(_W * n) and +// n = len(m.nat.limbs). +// +// Faster Montgomery multiplication replaces standard modular multiplication for +// numbers in this representation. +// +// This assumes that x is already reduced mod m. +func (x *Nat) montgomeryRepresentation(m *Modulus) *Nat { + // A Montgomery multiplication (which computes a * b / R) by R * R works out + // to a multiplication by R, which takes the value out of the Montgomery domain. + return x.montgomeryMul(x, m.rr, m) +} + +// montgomeryReduction calculates x = x / R mod m, with R = 2^(_W * n) and +// n = len(m.nat.limbs). +// +// This assumes that x is already reduced mod m. +func (x *Nat) montgomeryReduction(m *Modulus) *Nat { + // By Montgomery multiplying with 1 not in Montgomery representation, we + // convert out back from Montgomery representation, because it works out to + // dividing by R. + one := NewNat().ExpandFor(m) + one.limbs[0] = 1 + return x.montgomeryMul(x, one, m) +} + +// montgomeryMul calculates x = a * b / R mod m, with R = 2^(_W * n) and +// n = len(m.nat.limbs), also known as a Montgomery multiplication. +// +// All inputs should be the same length and already reduced modulo m. +// x will be resized to the size of m and overwritten. +func (x *Nat) montgomeryMul(a *Nat, b *Nat, m *Modulus) *Nat { + n := len(m.nat.limbs) + mLimbs := m.nat.limbs[:n] + aLimbs := a.limbs[:n] + bLimbs := b.limbs[:n] + + switch n { + default: + // Attempt to use a stack-allocated backing array. + T := make([]uint, 0, preallocLimbs*2) + if cap(T) < n*2 { + T = make([]uint, 0, n*2) + } + T = T[:n*2] + + // This loop implements Word-by-Word Montgomery Multiplication, as + // described in Algorithm 4 (Fig. 3) of "Efficient Software + // Implementations of Modular Exponentiation" by Shay Gueron + // [https://eprint.iacr.org/2011/239.pdf]. + var c uint + for i := 0; i < n; i++ { + _ = T[n+i] // bounds check elimination hint + + // Step 1 (T = a × b) is computed as a large pen-and-paper column + // multiplication of two numbers with n base-2^_W digits. If we just + // wanted to produce 2n-wide T, we would do + // + // for i := 0; i < n; i++ { + // d := bLimbs[i] + // T[n+i] = addMulVVW(T[i:n+i], aLimbs, d) + // } + // + // where d is a digit of the multiplier, T[i:n+i] is the shifted + // position of the product of that digit, and T[n+i] is the final carry. + // Note that T[i] isn't modified after processing the i-th digit. + // + // Instead of running two loops, one for Step 1 and one for Steps 2–6, + // the result of Step 1 is computed during the next loop. This is + // possible because each iteration only uses T[i] in Step 2 and then + // discards it in Step 6. + d := bLimbs[i] + c1 := addMulVVW(T[i:n+i], aLimbs, d) + + // Step 6 is replaced by shifting the virtual window we operate + // over: T of the algorithm is T[i:] for us. That means that T1 in + // Step 2 (T mod 2^_W) is simply T[i]. k0 in Step 3 is our m0inv. + Y := T[i] * m.m0inv + + // Step 4 and 5 add Y × m to T, which as mentioned above is stored + // at T[i:]. The two carries (from a × d and Y × m) are added up in + // the next word T[n+i], and the carry bit from that addition is + // brought forward to the next iteration. + c2 := addMulVVW(T[i:n+i], mLimbs, Y) + T[n+i], c = bits.Add(c1, c2, c) + } + + // Finally for Step 7 we copy the final T window into x, and subtract m + // if necessary (which as explained in maybeSubtractModulus can be the + // case both if x >= m, or if x overflowed). + // + // The paper suggests in Section 4 that we can do an "Almost Montgomery + // Multiplication" by subtracting only in the overflow case, but the + // cost is very similar since the constant time subtraction tells us if + // x >= m as a side effect, and taking care of the broken invariant is + // highly undesirable (see https://go.dev/issue/13907). + copy(x.reset(n).limbs, T[n:]) + x.maybeSubtractModulus(choice(c), m) + + // The following specialized cases follow the exact same algorithm, but + // optimized for the sizes most used in RSA. addMulVVW is implemented in + // assembly with loop unrolling depending on the architecture and bounds + // checks are removed by the compiler thanks to the constant size. + case 1024 / _W: + const n = 1024 / _W // compiler hint + T := make([]uint, n*2) + var c uint + for i := 0; i < n; i++ { + d := bLimbs[i] + c1 := addMulVVW1024(&T[i], &aLimbs[0], d) + Y := T[i] * m.m0inv + c2 := addMulVVW1024(&T[i], &mLimbs[0], Y) + T[n+i], c = bits.Add(c1, c2, c) + } + copy(x.reset(n).limbs, T[n:]) + x.maybeSubtractModulus(choice(c), m) + + case 1536 / _W: + const n = 1536 / _W // compiler hint + T := make([]uint, n*2) + var c uint + for i := 0; i < n; i++ { + d := bLimbs[i] + c1 := addMulVVW1536(&T[i], &aLimbs[0], d) + Y := T[i] * m.m0inv + c2 := addMulVVW1536(&T[i], &mLimbs[0], Y) + T[n+i], c = bits.Add(c1, c2, c) + } + copy(x.reset(n).limbs, T[n:]) + x.maybeSubtractModulus(choice(c), m) + + case 2048 / _W: + const n = 2048 / _W // compiler hint + T := make([]uint, n*2) + var c uint + for i := 0; i < n; i++ { + d := bLimbs[i] + c1 := addMulVVW2048(&T[i], &aLimbs[0], d) + Y := T[i] * m.m0inv + c2 := addMulVVW2048(&T[i], &mLimbs[0], Y) + T[n+i], c = bits.Add(c1, c2, c) + } + copy(x.reset(n).limbs, T[n:]) + x.maybeSubtractModulus(choice(c), m) + } + + return x +} + +// addMulVVW multiplies the multi-word value x by the single-word value y, +// adding the result to the multi-word value z and returning the final carry. +// It can be thought of as one row of a pen-and-paper column multiplication. +func addMulVVW(z, x []uint, y uint) (carry uint) { + _ = x[len(z)-1] // bounds check elimination hint + for i := range z { + hi, lo := bits.Mul(x[i], y) + lo, c := bits.Add(lo, z[i], 0) + // We use bits.Add with zero to get an add-with-carry instruction that + // absorbs the carry from the previous bits.Add. + hi, _ = bits.Add(hi, 0, c) + lo, c = bits.Add(lo, carry, 0) + hi, _ = bits.Add(hi, 0, c) + carry = hi + z[i] = lo + } + return carry +} + +// Mul calculates x = x * y mod m. +// +// The length of both operands must be the same as the modulus. Both operands +// must already be reduced modulo m. +func (x *Nat) Mul(y *Nat, m *Modulus) *Nat { + // A Montgomery multiplication by a value out of the Montgomery domain + // takes the result out of Montgomery representation. + xR := NewNat().set(x).montgomeryRepresentation(m) // xR = x * R mod m + return x.montgomeryMul(xR, y, m) // x = xR * y / R mod m +} + +// Exp calculates out = x^e mod m. +// +// The exponent e is represented in big-endian order. The output will be resized +// to the size of m and overwritten. x must already be reduced modulo m. +func (out *Nat) Exp(x *Nat, e []byte, m *Modulus) *Nat { + // We use a 4 bit window. For our RSA workload, 4 bit windows are faster + // than 2 bit windows, but use an extra 12 nats worth of scratch space. + // Using bit sizes that don't divide 8 are more complex to implement, but + // are likely to be more efficient if necessary. + + table := [(1 << 4) - 1]*Nat{ // table[i] = x ^ (i+1) + // newNat calls are unrolled so they are allocated on the stack. + NewNat(), NewNat(), NewNat(), NewNat(), NewNat(), + NewNat(), NewNat(), NewNat(), NewNat(), NewNat(), + NewNat(), NewNat(), NewNat(), NewNat(), NewNat(), + } + table[0].set(x).montgomeryRepresentation(m) + for i := 1; i < len(table); i++ { + table[i].montgomeryMul(table[i-1], table[0], m) + } + + out.resetFor(m) + out.limbs[0] = 1 + out.montgomeryRepresentation(m) + tmp := NewNat().ExpandFor(m) + for _, b := range e { + for _, j := range []int{4, 0} { + // Square four times. Optimization note: this can be implemented + // more efficiently than with generic Montgomery multiplication. + out.montgomeryMul(out, out, m) + out.montgomeryMul(out, out, m) + out.montgomeryMul(out, out, m) + out.montgomeryMul(out, out, m) + + // Select x^k in constant time from the table. + k := uint((b >> j) & 0b1111) + for i := range table { + tmp.assign(ctEq(k, uint(i+1)), table[i]) + } + + // Multiply by x^k, discarding the result if k = 0. + tmp.montgomeryMul(out, tmp, m) + out.assign(not(ctEq(k, 0)), tmp) + } + } + + return out.montgomeryReduction(m) +} + +// ExpShortVarTime calculates out = x^e mod m. +// +// The output will be resized to the size of m and overwritten. x must already +// be reduced modulo m. This leaks the exponent through timing side-channels. +func (out *Nat) ExpShortVarTime(x *Nat, e uint, m *Modulus) *Nat { + // For short exponents, precomputing a table and using a window like in Exp + // doesn't pay off. Instead, we do a simple conditional square-and-multiply + // chain, skipping the initial run of zeroes. + xR := NewNat().set(x).montgomeryRepresentation(m) + out.set(xR) + for i := bits.UintSize - bitLen(e) + 1; i < bits.UintSize; i++ { + out.montgomeryMul(out, out, m) + if k := (e >> (bits.UintSize - i - 1)) & 1; k != 0 { + out.montgomeryMul(out, xR, m) + } + } + return out.montgomeryReduction(m) +} diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_386.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_386.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_386.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_386.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_amd64.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_amd64.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_amd64.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_arm.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_arm.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_arm.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_arm64.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_arm64.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_arm64.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_asm.go b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_asm.go rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_asm.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_noasm.go b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_noasm.go rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_noasm.go diff --git a/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_ppc64x.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_ppc64x.s new file mode 100644 index 000000000000..94260ca29f3c --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_ppc64x.s @@ -0,0 +1,82 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego && (ppc64 || ppc64le) + +#include "textflag.h" + +// func addMulVVW1024(z, x *uint, y uint) (c uint) +TEXT ·addMulVVW1024(SB), $0-32 + MOVD $4, R6 // R6 = z_len/4 + JMP addMulVVWx<>(SB) + +// func addMulVVW1536(z, x *uint, y uint) (c uint) +TEXT ·addMulVVW1536(SB), $0-32 + MOVD $6, R6 // R6 = z_len/4 + JMP addMulVVWx<>(SB) + +// func addMulVVW2048(z, x *uint, y uint) (c uint) +TEXT ·addMulVVW2048(SB), $0-32 + MOVD $8, R6 // R6 = z_len/4 + JMP addMulVVWx<>(SB) + +// This local function expects to be called only by +// callers above. R6 contains the z length/4 +// since 4 values are processed for each +// loop iteration, and is guaranteed to be > 0. +// If other callers are added this function might +// need to change. +TEXT addMulVVWx<>(SB), NOSPLIT, $0 + MOVD z+0(FP), R3 + MOVD x+8(FP), R4 + MOVD y+16(FP), R5 + + MOVD $0, R9 // R9 = c = 0 + MOVD R6, CTR // Initialize loop counter + PCALIGN $16 + +loop: + MOVD 0(R4), R14 // x[i] + MOVD 8(R4), R16 // x[i+1] + MOVD 16(R4), R18 // x[i+2] + MOVD 24(R4), R20 // x[i+3] + MOVD 0(R3), R15 // z[i] + MOVD 8(R3), R17 // z[i+1] + MOVD 16(R3), R19 // z[i+2] + MOVD 24(R3), R21 // z[i+3] + MULLD R5, R14, R10 // low x[i]*y + MULHDU R5, R14, R11 // high x[i]*y + ADDC R15, R10 + ADDZE R11 + ADDC R9, R10 + ADDZE R11, R9 + MULLD R5, R16, R14 // low x[i+1]*y + MULHDU R5, R16, R15 // high x[i+1]*y + ADDC R17, R14 + ADDZE R15 + ADDC R9, R14 + ADDZE R15, R9 + MULLD R5, R18, R16 // low x[i+2]*y + MULHDU R5, R18, R17 // high x[i+2]*y + ADDC R19, R16 + ADDZE R17 + ADDC R9, R16 + ADDZE R17, R9 + MULLD R5, R20, R18 // low x[i+3]*y + MULHDU R5, R20, R19 // high x[i+3]*y + ADDC R21, R18 + ADDZE R19 + ADDC R9, R18 + ADDZE R19, R9 + MOVD R10, 0(R3) // z[i] + MOVD R14, 8(R3) // z[i+1] + MOVD R16, 16(R3) // z[i+2] + MOVD R18, 24(R3) // z[i+3] + ADD $32, R3 + ADD $32, R4 + BDNZ loop + +done: + MOVD R9, c+24(FP) + RET diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_riscv64.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_riscv64.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_riscv64.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_s390x.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_s390x.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_s390x.s diff --git a/contrib/go/_std_1.23/src/crypto/internal/bigmod/ya.make b/contrib/go/_std_1.23/src/crypto/internal/bigmod/ya.make new file mode 100644 index 000000000000..606f047d8bc8 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/bigmod/ya.make @@ -0,0 +1,21 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + nat.go + nat_arm64.s + nat_asm.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + nat.go + nat_amd64.s + nat_asm.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + nat.go + nat_arm.s + nat_asm.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/Dockerfile b/contrib/go/_std_1.23/src/crypto/internal/boring/Dockerfile similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/Dockerfile rename to contrib/go/_std_1.23/src/crypto/internal/boring/Dockerfile diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/LICENSE b/contrib/go/_std_1.23/src/crypto/internal/boring/LICENSE similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/LICENSE rename to contrib/go/_std_1.23/src/crypto/internal/boring/LICENSE diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/README.md b/contrib/go/_std_1.23/src/crypto/internal/boring/README.md similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/README.md rename to contrib/go/_std_1.23/src/crypto/internal/boring/README.md diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/aes.go b/contrib/go/_std_1.23/src/crypto/internal/boring/aes.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/aes.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/aes.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bbig/big.go b/contrib/go/_std_1.23/src/crypto/internal/boring/bbig/big.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bbig/big.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/bbig/big.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bbig/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/bbig/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bbig/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/bbig/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bcache/cache.go b/contrib/go/_std_1.23/src/crypto/internal/boring/bcache/cache.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bcache/cache.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/bcache/cache.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bcache/stub.s b/contrib/go/_std_1.23/src/crypto/internal/boring/bcache/stub.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bcache/stub.s rename to contrib/go/_std_1.23/src/crypto/internal/boring/bcache/stub.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bcache/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/bcache/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bcache/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/bcache/ya.make diff --git a/contrib/go/_std_1.23/src/crypto/internal/boring/boring.go b/contrib/go/_std_1.23/src/crypto/internal/boring/boring.go new file mode 100644 index 000000000000..90cf1edb75bb --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/boring/boring.go @@ -0,0 +1,123 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build boringcrypto && linux && (amd64 || arm64) && !android && !msan + +package boring + +/* +// goboringcrypto_linux_amd64.syso references pthread functions. +#cgo LDFLAGS: "-pthread" + +#include "goboringcrypto.h" +*/ +import "C" +import ( + "crypto/internal/boring/sig" + _ "crypto/internal/boring/syso" + "internal/stringslite" + "math/bits" + "unsafe" +) + +const available = true + +func init() { + C._goboringcrypto_BORINGSSL_bcm_power_on_self_test() + if C._goboringcrypto_FIPS_mode() != 1 { + panic("boringcrypto: not in FIPS mode") + } + sig.BoringCrypto() +} + +// Unreachable marks code that should be unreachable +// when BoringCrypto is in use. It panics. +func Unreachable() { + panic("boringcrypto: invalid code execution") +} + +// provided by runtime to avoid os import. +func runtime_arg0() string + +// UnreachableExceptTests marks code that should be unreachable +// when BoringCrypto is in use. It panics. +func UnreachableExceptTests() { + name := runtime_arg0() + // If BoringCrypto ran on Windows we'd need to allow _test.exe and .test.exe as well. + if !stringslite.HasSuffix(name, "_test") && !stringslite.HasSuffix(name, ".test") { + println("boringcrypto: unexpected code execution in", name) + panic("boringcrypto: invalid code execution") + } +} + +type fail string + +func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" } + +func wbase(b BigInt) *C.uint8_t { + if len(b) == 0 { + return nil + } + return (*C.uint8_t)(unsafe.Pointer(&b[0])) +} + +const wordBytes = bits.UintSize / 8 + +func bigToBN(x BigInt) *C.GO_BIGNUM { + return C._goboringcrypto_BN_le2bn(wbase(x), C.size_t(len(x)*wordBytes), nil) +} + +func bytesToBN(x []byte) *C.GO_BIGNUM { + return C._goboringcrypto_BN_bin2bn((*C.uint8_t)(&x[0]), C.size_t(len(x)), nil) +} + +func bnToBig(bn *C.GO_BIGNUM) BigInt { + x := make(BigInt, (C._goboringcrypto_BN_num_bytes(bn)+wordBytes-1)/wordBytes) + if C._goboringcrypto_BN_bn2le_padded(wbase(x), C.size_t(len(x)*wordBytes), bn) == 0 { + panic("boringcrypto: bignum conversion failed") + } + return x +} + +func bigToBn(bnp **C.GO_BIGNUM, b BigInt) bool { + if *bnp != nil { + C._goboringcrypto_BN_free(*bnp) + *bnp = nil + } + if b == nil { + return true + } + bn := bigToBN(b) + if bn == nil { + return false + } + *bnp = bn + return true +} + +// noescape hides a pointer from escape analysis. noescape is +// the identity function but escape analysis doesn't think the +// output depends on the input. noescape is inlined and currently +// compiles down to zero instructions. +// USE CAREFULLY! +// +//go:nosplit +func noescape(p unsafe.Pointer) unsafe.Pointer { + x := uintptr(p) + return unsafe.Pointer(x ^ 0) +} + +var zero byte + +// addr converts p to its base addr, including a noescape along the way. +// If p is nil, addr returns a non-nil pointer, so that the result can always +// be dereferenced. +// +//go:nosplit +func addr(p []byte) *byte { + if len(p) == 0 { + return &zero + } + return (*byte)(noescape(unsafe.Pointer(&p[0]))) +} diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/div_test.c b/contrib/go/_std_1.23/src/crypto/internal/boring/div_test.c similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/div_test.c rename to contrib/go/_std_1.23/src/crypto/internal/boring/div_test.c diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/doc.go b/contrib/go/_std_1.23/src/crypto/internal/boring/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/doc.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/doc.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/ecdh.go b/contrib/go/_std_1.23/src/crypto/internal/boring/ecdh.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/ecdh.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/ecdh.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/ecdsa.go b/contrib/go/_std_1.23/src/crypto/internal/boring/ecdsa.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/ecdsa.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/ecdsa.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/stub.s b/contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/stub.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/stub.s rename to contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/stub.s diff --git a/contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/tls.go b/contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/tls.go new file mode 100644 index 000000000000..b51f142fde83 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/tls.go @@ -0,0 +1,51 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build boringcrypto + +// Package fipstls allows control over whether crypto/tls requires FIPS-approved settings. +// This package only exists with GOEXPERIMENT=boringcrypto, but the effects are independent +// of the use of BoringCrypto. +package fipstls + +import ( + "internal/stringslite" + "sync/atomic" +) + +var required atomic.Bool + +// Force forces crypto/tls to restrict TLS configurations to FIPS-approved settings. +// By design, this call is impossible to undo (except in tests). +// +// Note that this call has an effect even in programs using +// standard crypto (that is, even when Enabled = false). +func Force() { + required.Store(true) +} + +// Abandon allows non-FIPS-approved settings. +// If called from a non-test binary, it panics. +func Abandon() { + // Note: Not using boring.UnreachableExceptTests because we want + // this test to happen even when boring.Enabled = false. + name := runtime_arg0() + // Allow _test for Go command, .test for Bazel, + // NaClMain for NaCl (where all binaries run as NaClMain), + // and empty string for Windows (where runtime_arg0 can't easily find the name). + // Since this is an internal package, testing that this isn't used on the + // other operating systems should suffice to catch any mistakes. + if !stringslite.HasSuffix(name, "_test") && !stringslite.HasSuffix(name, ".test") && name != "NaClMain" && name != "" { + panic("fipstls: invalid use of Abandon in " + name) + } + required.Store(false) +} + +// provided by runtime +func runtime_arg0() string + +// Required reports whether FIPS-approved settings are required. +func Required() bool { + return required.Load() +} diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/goboringcrypto.h b/contrib/go/_std_1.23/src/crypto/internal/boring/goboringcrypto.h similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/goboringcrypto.h rename to contrib/go/_std_1.23/src/crypto/internal/boring/goboringcrypto.h diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/hmac.go b/contrib/go/_std_1.23/src/crypto/internal/boring/hmac.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/hmac.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/hmac.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/notboring.go b/contrib/go/_std_1.23/src/crypto/internal/boring/notboring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/notboring.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/notboring.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/rand.go b/contrib/go/_std_1.23/src/crypto/internal/boring/rand.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/rand.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/rand.go diff --git a/contrib/go/_std_1.23/src/crypto/internal/boring/rsa.go b/contrib/go/_std_1.23/src/crypto/internal/boring/rsa.go new file mode 100644 index 000000000000..5ca86aa04275 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/boring/rsa.go @@ -0,0 +1,379 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build boringcrypto && linux && (amd64 || arm64) && !android && !msan + +package boring + +// #include "goboringcrypto.h" +import "C" +import ( + "crypto" + "crypto/subtle" + "errors" + "hash" + "runtime" + "strconv" + "unsafe" +) + +func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { + bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { + return nil, nil, nil, nil, nil, nil, nil, nil, e + } + + key := C._goboringcrypto_RSA_new() + if key == nil { + return bad(fail("RSA_new")) + } + defer C._goboringcrypto_RSA_free(key) + + if C._goboringcrypto_RSA_generate_key_fips(key, C.int(bits), nil) == 0 { + return bad(fail("RSA_generate_key_fips")) + } + + var n, e, d, p, q, dp, dq, qinv *C.GO_BIGNUM + C._goboringcrypto_RSA_get0_key(key, &n, &e, &d) + C._goboringcrypto_RSA_get0_factors(key, &p, &q) + C._goboringcrypto_RSA_get0_crt_params(key, &dp, &dq, &qinv) + return bnToBig(n), bnToBig(e), bnToBig(d), bnToBig(p), bnToBig(q), bnToBig(dp), bnToBig(dq), bnToBig(qinv), nil +} + +type PublicKeyRSA struct { + // _key MUST NOT be accessed directly. Instead, use the withKey method. + _key *C.GO_RSA +} + +func NewPublicKeyRSA(N, E BigInt) (*PublicKeyRSA, error) { + key := C._goboringcrypto_RSA_new() + if key == nil { + return nil, fail("RSA_new") + } + if !bigToBn(&key.n, N) || + !bigToBn(&key.e, E) { + return nil, fail("BN_bin2bn") + } + k := &PublicKeyRSA{_key: key} + runtime.SetFinalizer(k, (*PublicKeyRSA).finalize) + return k, nil +} + +func (k *PublicKeyRSA) finalize() { + C._goboringcrypto_RSA_free(k._key) +} + +func (k *PublicKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int { + // Because of the finalizer, any time _key is passed to cgo, that call must + // be followed by a call to runtime.KeepAlive, to make sure k is not + // collected (and finalized) before the cgo call returns. + defer runtime.KeepAlive(k) + return f(k._key) +} + +type PrivateKeyRSA struct { + // _key MUST NOT be accessed directly. Instead, use the withKey method. + _key *C.GO_RSA +} + +func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv BigInt) (*PrivateKeyRSA, error) { + key := C._goboringcrypto_RSA_new() + if key == nil { + return nil, fail("RSA_new") + } + if !bigToBn(&key.n, N) || + !bigToBn(&key.e, E) || + !bigToBn(&key.d, D) || + !bigToBn(&key.p, P) || + !bigToBn(&key.q, Q) || + !bigToBn(&key.dmp1, Dp) || + !bigToBn(&key.dmq1, Dq) || + !bigToBn(&key.iqmp, Qinv) { + return nil, fail("BN_bin2bn") + } + k := &PrivateKeyRSA{_key: key} + runtime.SetFinalizer(k, (*PrivateKeyRSA).finalize) + return k, nil +} + +func (k *PrivateKeyRSA) finalize() { + C._goboringcrypto_RSA_free(k._key) +} + +func (k *PrivateKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int { + // Because of the finalizer, any time _key is passed to cgo, that call must + // be followed by a call to runtime.KeepAlive, to make sure k is not + // collected (and finalized) before the cgo call returns. + defer runtime.KeepAlive(k) + return f(k._key) +} + +func setupRSA(withKey func(func(*C.GO_RSA) C.int) C.int, + padding C.int, h, mgfHash hash.Hash, label []byte, saltLen int, ch crypto.Hash, + init func(*C.GO_EVP_PKEY_CTX) C.int) (pkey *C.GO_EVP_PKEY, ctx *C.GO_EVP_PKEY_CTX, err error) { + defer func() { + if err != nil { + if pkey != nil { + C._goboringcrypto_EVP_PKEY_free(pkey) + pkey = nil + } + if ctx != nil { + C._goboringcrypto_EVP_PKEY_CTX_free(ctx) + ctx = nil + } + } + }() + + pkey = C._goboringcrypto_EVP_PKEY_new() + if pkey == nil { + return pkey, ctx, fail("EVP_PKEY_new") + } + if withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_EVP_PKEY_set1_RSA(pkey, key) + }) == 0 { + return pkey, ctx, fail("EVP_PKEY_set1_RSA") + } + ctx = C._goboringcrypto_EVP_PKEY_CTX_new(pkey, nil) + if ctx == nil { + return pkey, ctx, fail("EVP_PKEY_CTX_new") + } + if init(ctx) == 0 { + return pkey, ctx, fail("EVP_PKEY_operation_init") + } + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 0 { + return pkey, ctx, fail("EVP_PKEY_CTX_set_rsa_padding") + } + if padding == C.GO_RSA_PKCS1_OAEP_PADDING { + md := hashToMD(h) + if md == nil { + return pkey, ctx, errors.New("crypto/rsa: unsupported hash function") + } + mgfMD := hashToMD(mgfHash) + if mgfMD == nil { + return pkey, ctx, errors.New("crypto/rsa: unsupported hash function") + } + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) == 0 { + return pkey, ctx, fail("EVP_PKEY_set_rsa_oaep_md") + } + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgfMD) == 0 { + return pkey, ctx, fail("EVP_PKEY_set_rsa_mgf1_md") + } + // ctx takes ownership of label, so malloc a copy for BoringCrypto to free. + clabel := (*C.uint8_t)(C._goboringcrypto_OPENSSL_malloc(C.size_t(len(label)))) + if clabel == nil { + return pkey, ctx, fail("OPENSSL_malloc") + } + copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label) + if C._goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, clabel, C.size_t(len(label))) == 0 { + return pkey, ctx, fail("EVP_PKEY_CTX_set0_rsa_oaep_label") + } + } + if padding == C.GO_RSA_PKCS1_PSS_PADDING { + if saltLen != 0 { + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, C.int(saltLen)) == 0 { + return pkey, ctx, fail("EVP_PKEY_set_rsa_pss_saltlen") + } + } + md := cryptoHashToMD(ch) + if md == nil { + return pkey, ctx, errors.New("crypto/rsa: unsupported hash function") + } + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) == 0 { + return pkey, ctx, fail("EVP_PKEY_set_rsa_mgf1_md") + } + } + + return pkey, ctx, nil +} + +func cryptRSA(withKey func(func(*C.GO_RSA) C.int) C.int, + padding C.int, h, mgfHash hash.Hash, label []byte, saltLen int, ch crypto.Hash, + init func(*C.GO_EVP_PKEY_CTX) C.int, + crypt func(*C.GO_EVP_PKEY_CTX, *C.uint8_t, *C.size_t, *C.uint8_t, C.size_t) C.int, + in []byte) ([]byte, error) { + + pkey, ctx, err := setupRSA(withKey, padding, h, mgfHash, label, saltLen, ch, init) + if err != nil { + return nil, err + } + defer C._goboringcrypto_EVP_PKEY_free(pkey) + defer C._goboringcrypto_EVP_PKEY_CTX_free(ctx) + + var outLen C.size_t + if crypt(ctx, nil, &outLen, base(in), C.size_t(len(in))) == 0 { + return nil, fail("EVP_PKEY_decrypt/encrypt") + } + out := make([]byte, outLen) + if crypt(ctx, base(out), &outLen, base(in), C.size_t(len(in))) == 0 { + return nil, fail("EVP_PKEY_decrypt/encrypt") + } + return out[:outLen], nil +} + +func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { + return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, mgfHash, label, 0, 0, decryptInit, decrypt, ciphertext) +} + +func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) { + return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, mgfHash, label, 0, 0, encryptInit, encrypt, msg) +} + +func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { + return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, nil, 0, 0, decryptInit, decrypt, ciphertext) +} + +func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) { + return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, nil, 0, 0, encryptInit, encrypt, msg) +} + +func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { + return cryptRSA(priv.withKey, C.GO_RSA_NO_PADDING, nil, nil, nil, 0, 0, decryptInit, decrypt, ciphertext) +} + +func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) { + return cryptRSA(pub.withKey, C.GO_RSA_NO_PADDING, nil, nil, nil, 0, 0, encryptInit, encrypt, msg) +} + +// These dumb wrappers work around the fact that cgo functions cannot be used as values directly. + +func decryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int { + return C._goboringcrypto_EVP_PKEY_decrypt_init(ctx) +} + +func decrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int { + return C._goboringcrypto_EVP_PKEY_decrypt(ctx, out, outLen, in, inLen) +} + +func encryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int { + return C._goboringcrypto_EVP_PKEY_encrypt_init(ctx) +} + +func encrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int { + return C._goboringcrypto_EVP_PKEY_encrypt(ctx, out, outLen, in, inLen) +} + +var invalidSaltLenErr = errors.New("crypto/rsa: PSSOptions.SaltLength cannot be negative") + +func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { + md := cryptoHashToMD(h) + if md == nil { + return nil, errors.New("crypto/rsa: unsupported hash function") + } + + // A salt length of -2 is valid in BoringSSL, but not in crypto/rsa, so reject + // it, and lengths < -2, before we convert to the BoringSSL sentinel values. + if saltLen <= -2 { + return nil, invalidSaltLenErr + } + + // BoringSSL uses sentinel salt length values like we do, but the values don't + // fully match what we use. We both use -1 for salt length equal to hash length, + // but BoringSSL uses -2 to mean maximal size where we use 0. In the latter + // case convert to the BoringSSL version. + if saltLen == 0 { + saltLen = -2 + } + + var out []byte + var outLen C.size_t + if priv.withKey(func(key *C.GO_RSA) C.int { + out = make([]byte, C._goboringcrypto_RSA_size(key)) + return C._goboringcrypto_RSA_sign_pss_mgf1(key, &outLen, base(out), C.size_t(len(out)), + base(hashed), C.size_t(len(hashed)), md, nil, C.int(saltLen)) + }) == 0 { + return nil, fail("RSA_sign_pss_mgf1") + } + + return out[:outLen], nil +} + +func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { + md := cryptoHashToMD(h) + if md == nil { + return errors.New("crypto/rsa: unsupported hash function") + } + + // A salt length of -2 is valid in BoringSSL, but not in crypto/rsa, so reject + // it, and lengths < -2, before we convert to the BoringSSL sentinel values. + if saltLen <= -2 { + return invalidSaltLenErr + } + + // BoringSSL uses sentinel salt length values like we do, but the values don't + // fully match what we use. We both use -1 for salt length equal to hash length, + // but BoringSSL uses -2 to mean maximal size where we use 0. In the latter + // case convert to the BoringSSL version. + if saltLen == 0 { + saltLen = -2 + } + + if pub.withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_RSA_verify_pss_mgf1(key, base(hashed), C.size_t(len(hashed)), + md, nil, C.int(saltLen), base(sig), C.size_t(len(sig))) + }) == 0 { + return fail("RSA_verify_pss_mgf1") + } + return nil +} + +func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { + if h == 0 { + // No hashing. + var out []byte + var outLen C.size_t + if priv.withKey(func(key *C.GO_RSA) C.int { + out = make([]byte, C._goboringcrypto_RSA_size(key)) + return C._goboringcrypto_RSA_sign_raw(key, &outLen, base(out), C.size_t(len(out)), + base(hashed), C.size_t(len(hashed)), C.GO_RSA_PKCS1_PADDING) + }) == 0 { + return nil, fail("RSA_sign_raw") + } + return out[:outLen], nil + } + + md := cryptoHashToMD(h) + if md == nil { + return nil, errors.New("crypto/rsa: unsupported hash function: " + strconv.Itoa(int(h))) + } + nid := C._goboringcrypto_EVP_MD_type(md) + var out []byte + var outLen C.uint + if priv.withKey(func(key *C.GO_RSA) C.int { + out = make([]byte, C._goboringcrypto_RSA_size(key)) + return C._goboringcrypto_RSA_sign(nid, base(hashed), C.uint(len(hashed)), + base(out), &outLen, key) + }) == 0 { + return nil, fail("RSA_sign") + } + return out[:outLen], nil +} + +func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { + if h == 0 { + var out []byte + var outLen C.size_t + if pub.withKey(func(key *C.GO_RSA) C.int { + out = make([]byte, C._goboringcrypto_RSA_size(key)) + return C._goboringcrypto_RSA_verify_raw(key, &outLen, base(out), + C.size_t(len(out)), base(sig), C.size_t(len(sig)), C.GO_RSA_PKCS1_PADDING) + }) == 0 { + return fail("RSA_verify") + } + if subtle.ConstantTimeCompare(hashed, out[:outLen]) != 1 { + return fail("RSA_verify") + } + return nil + } + md := cryptoHashToMD(h) + if md == nil { + return errors.New("crypto/rsa: unsupported hash function") + } + nid := C._goboringcrypto_EVP_MD_type(md) + if pub.withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_RSA_verify(nid, base(hashed), C.size_t(len(hashed)), + base(sig), C.size_t(len(sig)), key) + }) == 0 { + return fail("RSA_verify") + } + return nil +} diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/sha.go b/contrib/go/_std_1.23/src/crypto/internal/boring/sha.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/sha.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/sha.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig.go b/contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig_amd64.s b/contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig_amd64.s rename to contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig_amd64.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig_other.s b/contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig_other.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig_other.s rename to contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig_other.s diff --git a/contrib/go/_std_1.23/src/crypto/internal/boring/sig/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/sig/ya.make new file mode 100644 index 000000000000..7a313eb1c27a --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/boring/sig/ya.make @@ -0,0 +1,13 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sig.go + sig_other.s + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sig.go + sig_amd64.s + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso b/contrib/go/_std_1.23/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso rename to contrib/go/_std_1.23/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso b/contrib/go/_std_1.23/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso rename to contrib/go/_std_1.23/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/syso/syso.go b/contrib/go/_std_1.23/src/crypto/internal/boring/syso/syso.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/syso/syso.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/syso/syso.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/syso/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/syso/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/syso/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/syso/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/ya.make diff --git a/contrib/go/_std_1.23/src/crypto/internal/cryptotest/hash.go b/contrib/go/_std_1.23/src/crypto/internal/cryptotest/hash.go new file mode 100644 index 000000000000..a950dcb28214 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/cryptotest/hash.go @@ -0,0 +1,189 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cryptotest + +import ( + "bytes" + "hash" + "io" + "math/rand" + "testing" + "time" +) + +type MakeHash func() hash.Hash + +// TestHash performs a set of tests on hash.Hash implementations, checking the +// documented requirements of Write, Sum, Reset, Size, and BlockSize. +func TestHash(t *testing.T, mh MakeHash) { + + // Test that Sum returns an appended digest matching output of Size + t.Run("SumAppend", func(t *testing.T) { + h := mh() + rng := newRandReader(t) + + emptyBuff := []byte("") + shortBuff := []byte("a") + longBuff := make([]byte, h.BlockSize()+1) + rng.Read(longBuff) + + // Set of example strings to append digest to + prefixes := [][]byte{nil, emptyBuff, shortBuff, longBuff} + + // Go to each string and check digest gets appended to and is correct size. + for _, prefix := range prefixes { + h.Reset() + + sum := getSum(t, h, prefix) // Append new digest to prefix + + // Check that Sum didn't alter the prefix + if !bytes.Equal(sum[0:len(prefix)], prefix) { + t.Errorf("Sum alters passed buffer instead of appending; got %x, want %x", sum[0:len(prefix)], prefix) + } + + // Check that the appended sum wasn't affected by the prefix + if expectedSum := getSum(t, h, nil); !bytes.Equal(sum[len(prefix):], expectedSum) { + t.Errorf("Sum behavior affected by data in the input buffer; got %x, want %x", sum[len(prefix):], expectedSum) + } + + // Check size of append + if got, want := len(sum)-len(prefix), h.Size(); got != want { + t.Errorf("Sum appends number of bytes != Size; got %v , want %v", got, want) + } + } + }) + + // Test that Hash.Write never returns error. + t.Run("WriteWithoutError", func(t *testing.T) { + h := mh() + rng := newRandReader(t) + + emptySlice := []byte("") + shortSlice := []byte("a") + longSlice := make([]byte, h.BlockSize()+1) + rng.Read(longSlice) + + // Set of example strings to append digest to + slices := [][]byte{emptySlice, shortSlice, longSlice} + + for _, slice := range slices { + writeToHash(t, h, slice) // Writes and checks Write doesn't error + } + }) + + t.Run("ResetState", func(t *testing.T) { + h := mh() + rng := newRandReader(t) + + emptySum := getSum(t, h, nil) + + // Write to hash and then Reset it and see if Sum is same as emptySum + writeEx := make([]byte, h.BlockSize()) + rng.Read(writeEx) + writeToHash(t, h, writeEx) + h.Reset() + resetSum := getSum(t, h, nil) + + if !bytes.Equal(emptySum, resetSum) { + t.Errorf("Reset hash yields different Sum than new hash; got %x, want %x", emptySum, resetSum) + } + }) + + // Check that Write isn't reading from beyond input slice's bounds + t.Run("OutOfBoundsRead", func(t *testing.T) { + h := mh() + blockSize := h.BlockSize() + rng := newRandReader(t) + + msg := make([]byte, blockSize) + rng.Read(msg) + writeToHash(t, h, msg) + expectedDigest := getSum(t, h, nil) // Record control digest + + h.Reset() + + // Make a buffer with msg in the middle and data on either end + buff := make([]byte, blockSize*3) + endOfPrefix, startOfSuffix := blockSize, blockSize*2 + + copy(buff[endOfPrefix:startOfSuffix], msg) + rng.Read(buff[:endOfPrefix]) + rng.Read(buff[startOfSuffix:]) + + writeToHash(t, h, buff[endOfPrefix:startOfSuffix]) + testDigest := getSum(t, h, nil) + + if !bytes.Equal(testDigest, expectedDigest) { + t.Errorf("Write affected by data outside of input slice bounds; got %x, want %x", testDigest, expectedDigest) + } + }) + + // Test that multiple calls to Write is stateful + t.Run("StatefulWrite", func(t *testing.T) { + h := mh() + rng := newRandReader(t) + + prefix, suffix := make([]byte, h.BlockSize()), make([]byte, h.BlockSize()) + rng.Read(prefix) + rng.Read(suffix) + + // Write prefix then suffix sequentially and record resulting hash + writeToHash(t, h, prefix) + writeToHash(t, h, suffix) + serialSum := getSum(t, h, nil) + + h.Reset() + + // Write prefix and suffix at the same time and record resulting hash + writeToHash(t, h, append(prefix, suffix...)) + compositeSum := getSum(t, h, nil) + + // Check that sequential writing results in the same as writing all at once + if !bytes.Equal(compositeSum, serialSum) { + t.Errorf("two successive Write calls resulted in a different Sum than a single one; got %x, want %x", compositeSum, serialSum) + } + }) +} + +// Helper function for writing. Verifies that Write does not error. +func writeToHash(t *testing.T, h hash.Hash, p []byte) { + t.Helper() + + before := make([]byte, len(p)) + copy(before, p) + + n, err := h.Write(p) + if err != nil || n != len(p) { + t.Errorf("Write returned error; got (%v, %v), want (nil, %v)", err, n, len(p)) + } + + if !bytes.Equal(p, before) { + t.Errorf("Write modified input slice; got %x, want %x", p, before) + } +} + +// Helper function for getting Sum. Checks that Sum doesn't change hash state. +func getSum(t *testing.T, h hash.Hash, buff []byte) []byte { + t.Helper() + + testBuff := make([]byte, len(buff)) + copy(testBuff, buff) + + sum := h.Sum(buff) + testSum := h.Sum(testBuff) + + // Check that Sum doesn't change underlying hash state + if !bytes.Equal(sum, testSum) { + t.Errorf("successive calls to Sum yield different results; got %x, want %x", sum, testSum) + } + + return sum +} + +func newRandReader(t *testing.T) io.Reader { + seed := time.Now().UnixNano() + t.Logf("Deterministic RNG seed: 0x%x", seed) + return rand.New(rand.NewSource(seed)) +} diff --git a/contrib/go/_std_1.23/src/crypto/internal/cryptotest/ya.make b/contrib/go/_std_1.23/src/crypto/internal/cryptotest/ya.make new file mode 100644 index 000000000000..617115214d07 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/cryptotest/ya.make @@ -0,0 +1,9 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (TRUE) + SRCS( + hash.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/doc.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/doc.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/doc.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/edwards25519.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/edwards25519.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/edwards25519.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/edwards25519.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go index 411399cb1e83..6765a688f455 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go @@ -17,7 +17,7 @@ import ( func main() { Package("crypto/internal/edwards25519/field") - ConstraintExpr("amd64,gc,!purego") + ConstraintExpr("!purego") feMul() feSquare() Generate() diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/go.mod b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/go.mod similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/go.mod rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/go.mod diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/go.sum b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/go.sum similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/go.sum rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/go.sum diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe.go index 5518ef2b9024..8a531f078ee2 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe.go @@ -7,8 +7,8 @@ package field import ( "crypto/subtle" - "encoding/binary" "errors" + "internal/byteorder" "math/bits" ) @@ -201,20 +201,20 @@ func (v *Element) SetBytes(x []byte) (*Element, error) { } // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51). - v.l0 = binary.LittleEndian.Uint64(x[0:8]) + v.l0 = byteorder.LeUint64(x[0:8]) v.l0 &= maskLow51Bits // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51). - v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3 + v.l1 = byteorder.LeUint64(x[6:14]) >> 3 v.l1 &= maskLow51Bits // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51). - v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6 + v.l2 = byteorder.LeUint64(x[12:20]) >> 6 v.l2 &= maskLow51Bits // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51). - v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1 + v.l3 = byteorder.LeUint64(x[19:27]) >> 1 v.l3 &= maskLow51Bits // Bits 204:255 (bytes 24:32, bits 192:256, shift 12, mask 51). // Note: not bytes 25:33, shift 4, to avoid overread. - v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12 + v.l4 = byteorder.LeUint64(x[24:32]) >> 12 v.l4 &= maskLow51Bits return v, nil @@ -235,7 +235,7 @@ func (v *Element) bytes(out *[32]byte) []byte { var buf [8]byte for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { bitsOffset := i * 51 - binary.LittleEndian.PutUint64(buf[:], l<= len(out) { diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.go similarity index 91% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.go index 70c541692c3a..00bf8f447922 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.go @@ -1,6 +1,6 @@ // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. -//go:build amd64 && gc && !purego +//go:build !purego package field diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.s b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.s rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.s index 60817acc4131..657851c85ed1 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.s @@ -1,6 +1,6 @@ // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. -//go:build amd64 && gc && !purego +//go:build !purego #include "textflag.h" diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go similarity index 89% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go index 9da280d1d887..4b81f25d1d0f 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 || !gc || purego +//go:build !amd64 || purego package field diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.go similarity index 89% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.go index 075fe9b92574..05c7cedd4e9c 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build arm64 && gc && !purego +//go:build !purego package field diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.s b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.s similarity index 96% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.s rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.s index 3126a434191c..ae207dae43e8 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build arm64 && gc && !purego +//go:build !purego #include "textflag.h" diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go similarity index 88% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go index fc029ac12dae..6b9e06a6e826 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !arm64 || !gc || purego +//go:build !arm64 || purego package field diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_generic.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_generic.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_generic.go diff --git a/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/ya.make b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/ya.make new file mode 100644 index 000000000000..0b4e7d3701ba --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/ya.make @@ -0,0 +1,26 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + fe.go + fe_amd64_noasm.go + fe_arm64.go + fe_arm64.s + fe_generic.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + fe.go + fe_amd64.go + fe_amd64.s + fe_arm64_noasm.go + fe_generic.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + fe.go + fe_amd64_noasm.go + fe_arm64_noasm.go + fe_generic.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar.go index 3fd1653877d2..9f652faca1ec 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar.go @@ -5,8 +5,8 @@ package edwards25519 import ( - "encoding/binary" "errors" + "internal/byteorder" ) // A Scalar is an integer modulo @@ -271,7 +271,7 @@ func (s *Scalar) nonAdjacentForm(w uint) [256]int8 { var digits [5]uint64 for i := 0; i < 4; i++ { - digits[i] = binary.LittleEndian.Uint64(b[i*8:]) + digits[i] = byteorder.LeUint64(b[i*8:]) } width := uint64(1 << w) diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar_fiat.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar_fiat.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar_fiat.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar_fiat.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalarmult.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalarmult.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalarmult.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalarmult.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/tables.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/tables.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/tables.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/tables.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/ya.make b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/ya.make diff --git a/contrib/go/_std_1.23/src/crypto/internal/hpke/hpke.go b/contrib/go/_std_1.23/src/crypto/internal/hpke/hpke.go new file mode 100644 index 000000000000..611c89aac0e1 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/hpke/hpke.go @@ -0,0 +1,259 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package hpke + +import ( + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/ecdh" + "crypto/rand" + "encoding/binary" + "errors" + "math/bits" + + "golang.org/x/crypto/chacha20poly1305" + "golang.org/x/crypto/hkdf" +) + +// testingOnlyGenerateKey is only used during testing, to provide +// a fixed test key to use when checking the RFC 9180 vectors. +var testingOnlyGenerateKey func() (*ecdh.PrivateKey, error) + +type hkdfKDF struct { + hash crypto.Hash +} + +func (kdf *hkdfKDF) LabeledExtract(suiteID []byte, salt []byte, label string, inputKey []byte) []byte { + labeledIKM := make([]byte, 0, 7+len(suiteID)+len(label)+len(inputKey)) + labeledIKM = append(labeledIKM, []byte("HPKE-v1")...) + labeledIKM = append(labeledIKM, suiteID...) + labeledIKM = append(labeledIKM, label...) + labeledIKM = append(labeledIKM, inputKey...) + return hkdf.Extract(kdf.hash.New, labeledIKM, salt) +} + +func (kdf *hkdfKDF) LabeledExpand(suiteID []byte, randomKey []byte, label string, info []byte, length uint16) []byte { + labeledInfo := make([]byte, 0, 2+7+len(suiteID)+len(label)+len(info)) + labeledInfo = binary.BigEndian.AppendUint16(labeledInfo, length) + labeledInfo = append(labeledInfo, []byte("HPKE-v1")...) + labeledInfo = append(labeledInfo, suiteID...) + labeledInfo = append(labeledInfo, label...) + labeledInfo = append(labeledInfo, info...) + out := make([]byte, length) + n, err := hkdf.Expand(kdf.hash.New, randomKey, labeledInfo).Read(out) + if err != nil || n != int(length) { + panic("hpke: LabeledExpand failed unexpectedly") + } + return out +} + +// dhKEM implements the KEM specified in RFC 9180, Section 4.1. +type dhKEM struct { + dh ecdh.Curve + kdf hkdfKDF + + suiteID []byte + nSecret uint16 +} + +var SupportedKEMs = map[uint16]struct { + curve ecdh.Curve + hash crypto.Hash + nSecret uint16 +}{ + // RFC 9180 Section 7.1 + 0x0020: {ecdh.X25519(), crypto.SHA256, 32}, +} + +func newDHKem(kemID uint16) (*dhKEM, error) { + suite, ok := SupportedKEMs[kemID] + if !ok { + return nil, errors.New("unsupported suite ID") + } + return &dhKEM{ + dh: suite.curve, + kdf: hkdfKDF{suite.hash}, + suiteID: binary.BigEndian.AppendUint16([]byte("KEM"), kemID), + nSecret: suite.nSecret, + }, nil +} + +func (dh *dhKEM) ExtractAndExpand(dhKey, kemContext []byte) []byte { + eaePRK := dh.kdf.LabeledExtract(dh.suiteID[:], nil, "eae_prk", dhKey) + return dh.kdf.LabeledExpand(dh.suiteID[:], eaePRK, "shared_secret", kemContext, dh.nSecret) +} + +func (dh *dhKEM) Encap(pubRecipient *ecdh.PublicKey) (sharedSecret []byte, encapPub []byte, err error) { + var privEph *ecdh.PrivateKey + if testingOnlyGenerateKey != nil { + privEph, err = testingOnlyGenerateKey() + } else { + privEph, err = dh.dh.GenerateKey(rand.Reader) + } + if err != nil { + return nil, nil, err + } + dhVal, err := privEph.ECDH(pubRecipient) + if err != nil { + return nil, nil, err + } + encPubEph := privEph.PublicKey().Bytes() + + encPubRecip := pubRecipient.Bytes() + kemContext := append(encPubEph, encPubRecip...) + + return dh.ExtractAndExpand(dhVal, kemContext), encPubEph, nil +} + +type Sender struct { + aead cipher.AEAD + kem *dhKEM + + sharedSecret []byte + + suiteID []byte + + key []byte + baseNonce []byte + exporterSecret []byte + + seqNum uint128 +} + +var aesGCMNew = func(key []byte) (cipher.AEAD, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + return cipher.NewGCM(block) +} + +var SupportedAEADs = map[uint16]struct { + keySize int + nonceSize int + aead func([]byte) (cipher.AEAD, error) +}{ + // RFC 9180, Section 7.3 + 0x0001: {keySize: 16, nonceSize: 12, aead: aesGCMNew}, + 0x0002: {keySize: 32, nonceSize: 12, aead: aesGCMNew}, + 0x0003: {keySize: chacha20poly1305.KeySize, nonceSize: chacha20poly1305.NonceSize, aead: chacha20poly1305.New}, +} + +var SupportedKDFs = map[uint16]func() *hkdfKDF{ + // RFC 9180, Section 7.2 + 0x0001: func() *hkdfKDF { return &hkdfKDF{crypto.SHA256} }, +} + +func SetupSender(kemID, kdfID, aeadID uint16, pub crypto.PublicKey, info []byte) ([]byte, *Sender, error) { + suiteID := SuiteID(kemID, kdfID, aeadID) + + kem, err := newDHKem(kemID) + if err != nil { + return nil, nil, err + } + pubRecipient, ok := pub.(*ecdh.PublicKey) + if !ok { + return nil, nil, errors.New("incorrect public key type") + } + sharedSecret, encapsulatedKey, err := kem.Encap(pubRecipient) + if err != nil { + return nil, nil, err + } + + kdfInit, ok := SupportedKDFs[kdfID] + if !ok { + return nil, nil, errors.New("unsupported KDF id") + } + kdf := kdfInit() + + aeadInfo, ok := SupportedAEADs[aeadID] + if !ok { + return nil, nil, errors.New("unsupported AEAD id") + } + + pskIDHash := kdf.LabeledExtract(suiteID, nil, "psk_id_hash", nil) + infoHash := kdf.LabeledExtract(suiteID, nil, "info_hash", info) + ksContext := append([]byte{0}, pskIDHash...) + ksContext = append(ksContext, infoHash...) + + secret := kdf.LabeledExtract(suiteID, sharedSecret, "secret", nil) + + key := kdf.LabeledExpand(suiteID, secret, "key", ksContext, uint16(aeadInfo.keySize) /* Nk - key size for AEAD */) + baseNonce := kdf.LabeledExpand(suiteID, secret, "base_nonce", ksContext, uint16(aeadInfo.nonceSize) /* Nn - nonce size for AEAD */) + exporterSecret := kdf.LabeledExpand(suiteID, secret, "exp", ksContext, uint16(kdf.hash.Size()) /* Nh - hash output size of the kdf*/) + + aead, err := aeadInfo.aead(key) + if err != nil { + return nil, nil, err + } + + return encapsulatedKey, &Sender{ + kem: kem, + aead: aead, + sharedSecret: sharedSecret, + suiteID: suiteID, + key: key, + baseNonce: baseNonce, + exporterSecret: exporterSecret, + }, nil +} + +func (s *Sender) nextNonce() []byte { + nonce := s.seqNum.bytes()[16-s.aead.NonceSize():] + for i := range s.baseNonce { + nonce[i] ^= s.baseNonce[i] + } + // Message limit is, according to the RFC, 2^95+1, which + // is somewhat confusing, but we do as we're told. + if s.seqNum.bitLen() >= (s.aead.NonceSize()*8)-1 { + panic("message limit reached") + } + s.seqNum = s.seqNum.addOne() + return nonce +} + +func (s *Sender) Seal(aad, plaintext []byte) ([]byte, error) { + + ciphertext := s.aead.Seal(nil, s.nextNonce(), plaintext, aad) + return ciphertext, nil +} + +func SuiteID(kemID, kdfID, aeadID uint16) []byte { + suiteID := make([]byte, 0, 4+2+2+2) + suiteID = append(suiteID, []byte("HPKE")...) + suiteID = binary.BigEndian.AppendUint16(suiteID, kemID) + suiteID = binary.BigEndian.AppendUint16(suiteID, kdfID) + suiteID = binary.BigEndian.AppendUint16(suiteID, aeadID) + return suiteID +} + +func ParseHPKEPublicKey(kemID uint16, bytes []byte) (*ecdh.PublicKey, error) { + kemInfo, ok := SupportedKEMs[kemID] + if !ok { + return nil, errors.New("unsupported KEM id") + } + return kemInfo.curve.NewPublicKey(bytes) +} + +type uint128 struct { + hi, lo uint64 +} + +func (u uint128) addOne() uint128 { + lo, carry := bits.Add64(u.lo, 1, 0) + return uint128{u.hi + carry, lo} +} + +func (u uint128) bitLen() int { + return bits.Len64(u.hi) + bits.Len64(u.lo) +} + +func (u uint128) bytes() []byte { + b := make([]byte, 16) + binary.BigEndian.PutUint64(b[0:], u.hi) + binary.BigEndian.PutUint64(b[8:], u.lo) + return b +} diff --git a/contrib/go/_std_1.23/src/crypto/internal/hpke/ya.make b/contrib/go/_std_1.23/src/crypto/internal/hpke/ya.make new file mode 100644 index 000000000000..e00f3e3a3539 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/hpke/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + hpke.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/crypto/internal/mlkem768/mlkem768.go b/contrib/go/_std_1.23/src/crypto/internal/mlkem768/mlkem768.go new file mode 100644 index 000000000000..76c6e80b4eb0 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/mlkem768/mlkem768.go @@ -0,0 +1,886 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package mlkem768 implements the quantum-resistant key encapsulation method +// ML-KEM (formerly known as Kyber). +// +// Only the recommended ML-KEM-768 parameter set is provided. +// +// The version currently implemented is the one specified by [NIST FIPS 203 ipd], +// with the unintentional transposition of the matrix A reverted to match the +// behavior of [Kyber version 3.0]. Future versions of this package might +// introduce backwards incompatible changes to implement changes to FIPS 203. +// +// [Kyber version 3.0]: https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf +// [NIST FIPS 203 ipd]: https://doi.org/10.6028/NIST.FIPS.203.ipd +package mlkem768 + +// This package targets security, correctness, simplicity, readability, and +// reviewability as its primary goals. All critical operations are performed in +// constant time. +// +// Variable and function names, as well as code layout, are selected to +// facilitate reviewing the implementation against the NIST FIPS 203 ipd +// document. +// +// Reviewers unfamiliar with polynomials or linear algebra might find the +// background at https://words.filippo.io/kyber-math/ useful. + +import ( + "crypto/rand" + "crypto/subtle" + "errors" + "internal/byteorder" + + "golang.org/x/crypto/sha3" +) + +const ( + // ML-KEM global constants. + n = 256 + q = 3329 + + log2q = 12 + + // ML-KEM-768 parameters. The code makes assumptions based on these values, + // they can't be changed blindly. + k = 3 + η = 2 + du = 10 + dv = 4 + + // encodingSizeX is the byte size of a ringElement or nttElement encoded + // by ByteEncode_X (FIPS 203 (DRAFT), Algorithm 4). + encodingSize12 = n * log2q / 8 + encodingSize10 = n * du / 8 + encodingSize4 = n * dv / 8 + encodingSize1 = n * 1 / 8 + + messageSize = encodingSize1 + decryptionKeySize = k * encodingSize12 + encryptionKeySize = k*encodingSize12 + 32 + + CiphertextSize = k*encodingSize10 + encodingSize4 + EncapsulationKeySize = encryptionKeySize + DecapsulationKeySize = decryptionKeySize + encryptionKeySize + 32 + 32 + SharedKeySize = 32 + SeedSize = 32 + 32 +) + +// A DecapsulationKey is the secret key used to decapsulate a shared key from a +// ciphertext. It includes various precomputed values. +type DecapsulationKey struct { + dk [DecapsulationKeySize]byte + encryptionKey + decryptionKey +} + +// Bytes returns the extended encoding of the decapsulation key, according to +// FIPS 203 (DRAFT). +func (dk *DecapsulationKey) Bytes() []byte { + var b [DecapsulationKeySize]byte + copy(b[:], dk.dk[:]) + return b[:] +} + +// EncapsulationKey returns the public encapsulation key necessary to produce +// ciphertexts. +func (dk *DecapsulationKey) EncapsulationKey() []byte { + var b [EncapsulationKeySize]byte + copy(b[:], dk.dk[decryptionKeySize:]) + return b[:] +} + +// encryptionKey is the parsed and expanded form of a PKE encryption key. +type encryptionKey struct { + t [k]nttElement // ByteDecode₁₂(ek[:384k]) + A [k * k]nttElement // A[i*k+j] = sampleNTT(ρ, j, i) +} + +// decryptionKey is the parsed and expanded form of a PKE decryption key. +type decryptionKey struct { + s [k]nttElement // ByteDecode₁₂(dk[:decryptionKeySize]) +} + +// GenerateKey generates a new decapsulation key, drawing random bytes from +// crypto/rand. The decapsulation key must be kept secret. +func GenerateKey() (*DecapsulationKey, error) { + // The actual logic is in a separate function to outline this allocation. + dk := &DecapsulationKey{} + return generateKey(dk) +} + +func generateKey(dk *DecapsulationKey) (*DecapsulationKey, error) { + var d [32]byte + if _, err := rand.Read(d[:]); err != nil { + return nil, errors.New("mlkem768: crypto/rand Read failed: " + err.Error()) + } + var z [32]byte + if _, err := rand.Read(z[:]); err != nil { + return nil, errors.New("mlkem768: crypto/rand Read failed: " + err.Error()) + } + return kemKeyGen(dk, &d, &z), nil +} + +// NewKeyFromSeed deterministically generates a decapsulation key from a 64-byte +// seed in the "d || z" form. The seed must be uniformly random. +func NewKeyFromSeed(seed []byte) (*DecapsulationKey, error) { + // The actual logic is in a separate function to outline this allocation. + dk := &DecapsulationKey{} + return newKeyFromSeed(dk, seed) +} + +func newKeyFromSeed(dk *DecapsulationKey, seed []byte) (*DecapsulationKey, error) { + if len(seed) != SeedSize { + return nil, errors.New("mlkem768: invalid seed length") + } + d := (*[32]byte)(seed[:32]) + z := (*[32]byte)(seed[32:]) + return kemKeyGen(dk, d, z), nil +} + +// NewKeyFromExtendedEncoding parses a decapsulation key from its FIPS 203 +// (DRAFT) extended encoding. +func NewKeyFromExtendedEncoding(decapsulationKey []byte) (*DecapsulationKey, error) { + // The actual logic is in a separate function to outline this allocation. + dk := &DecapsulationKey{} + return newKeyFromExtendedEncoding(dk, decapsulationKey) +} + +func newKeyFromExtendedEncoding(dk *DecapsulationKey, dkBytes []byte) (*DecapsulationKey, error) { + if len(dkBytes) != DecapsulationKeySize { + return nil, errors.New("mlkem768: invalid decapsulation key length") + } + + // Note that we don't check that H(ek) matches ekPKE, as that's not + // specified in FIPS 203 (DRAFT). This is one reason to prefer the seed + // private key format. + dk.dk = [DecapsulationKeySize]byte(dkBytes) + + dkPKE := dkBytes[:decryptionKeySize] + if err := parseDK(&dk.decryptionKey, dkPKE); err != nil { + return nil, err + } + + ekPKE := dkBytes[decryptionKeySize : decryptionKeySize+encryptionKeySize] + if err := parseEK(&dk.encryptionKey, ekPKE); err != nil { + return nil, err + } + + return dk, nil +} + +// kemKeyGen generates a decapsulation key. +// +// It implements ML-KEM.KeyGen according to FIPS 203 (DRAFT), Algorithm 15, and +// K-PKE.KeyGen according to FIPS 203 (DRAFT), Algorithm 12. The two are merged +// to save copies and allocations. +func kemKeyGen(dk *DecapsulationKey, d, z *[32]byte) *DecapsulationKey { + if dk == nil { + dk = &DecapsulationKey{} + } + + G := sha3.Sum512(d[:]) + ρ, σ := G[:32], G[32:] + + A := &dk.A + for i := byte(0); i < k; i++ { + for j := byte(0); j < k; j++ { + // Note that this is consistent with Kyber round 3, rather than with + // the initial draft of FIPS 203, because NIST signaled that the + // change was involuntary and will be reverted. + A[i*k+j] = sampleNTT(ρ, j, i) + } + } + + var N byte + s := &dk.s + for i := range s { + s[i] = ntt(samplePolyCBD(σ, N)) + N++ + } + e := make([]nttElement, k) + for i := range e { + e[i] = ntt(samplePolyCBD(σ, N)) + N++ + } + + t := &dk.t + for i := range t { // t = A ◦ s + e + t[i] = e[i] + for j := range s { + t[i] = polyAdd(t[i], nttMul(A[i*k+j], s[j])) + } + } + + // dkPKE ← ByteEncode₁₂(s) + // ekPKE ← ByteEncode₁₂(t) || ρ + // ek ← ekPKE + // dk ← dkPKE || ek || H(ek) || z + dkB := dk.dk[:0] + + for i := range s { + dkB = polyByteEncode(dkB, s[i]) + } + + for i := range t { + dkB = polyByteEncode(dkB, t[i]) + } + dkB = append(dkB, ρ...) + + H := sha3.New256() + H.Write(dkB[decryptionKeySize:]) + dkB = H.Sum(dkB) + + dkB = append(dkB, z[:]...) + + if len(dkB) != len(dk.dk) { + panic("mlkem768: internal error: invalid decapsulation key size") + } + + return dk +} + +// Encapsulate generates a shared key and an associated ciphertext from an +// encapsulation key, drawing random bytes from crypto/rand. +// If the encapsulation key is not valid, Encapsulate returns an error. +// +// The shared key must be kept secret. +func Encapsulate(encapsulationKey []byte) (ciphertext, sharedKey []byte, err error) { + // The actual logic is in a separate function to outline this allocation. + var cc [CiphertextSize]byte + return encapsulate(&cc, encapsulationKey) +} + +func encapsulate(cc *[CiphertextSize]byte, encapsulationKey []byte) (ciphertext, sharedKey []byte, err error) { + if len(encapsulationKey) != EncapsulationKeySize { + return nil, nil, errors.New("mlkem768: invalid encapsulation key length") + } + var m [messageSize]byte + if _, err := rand.Read(m[:]); err != nil { + return nil, nil, errors.New("mlkem768: crypto/rand Read failed: " + err.Error()) + } + return kemEncaps(cc, encapsulationKey, &m) +} + +// kemEncaps generates a shared key and an associated ciphertext. +// +// It implements ML-KEM.Encaps according to FIPS 203 (DRAFT), Algorithm 16. +func kemEncaps(cc *[CiphertextSize]byte, ek []byte, m *[messageSize]byte) (c, K []byte, err error) { + if cc == nil { + cc = &[CiphertextSize]byte{} + } + + H := sha3.Sum256(ek[:]) + g := sha3.New512() + g.Write(m[:]) + g.Write(H[:]) + G := g.Sum(nil) + K, r := G[:SharedKeySize], G[SharedKeySize:] + var ex encryptionKey + if err := parseEK(&ex, ek[:]); err != nil { + return nil, nil, err + } + c = pkeEncrypt(cc, &ex, m, r) + return c, K, nil +} + +// parseEK parses an encryption key from its encoded form. +// +// It implements the initial stages of K-PKE.Encrypt according to FIPS 203 +// (DRAFT), Algorithm 13. +func parseEK(ex *encryptionKey, ekPKE []byte) error { + if len(ekPKE) != encryptionKeySize { + return errors.New("mlkem768: invalid encryption key length") + } + + for i := range ex.t { + var err error + ex.t[i], err = polyByteDecode[nttElement](ekPKE[:encodingSize12]) + if err != nil { + return err + } + ekPKE = ekPKE[encodingSize12:] + } + ρ := ekPKE + + for i := byte(0); i < k; i++ { + for j := byte(0); j < k; j++ { + // See the note in pkeKeyGen about the order of the indices being + // consistent with Kyber round 3. + ex.A[i*k+j] = sampleNTT(ρ, j, i) + } + } + + return nil +} + +// pkeEncrypt encrypt a plaintext message. +// +// It implements K-PKE.Encrypt according to FIPS 203 (DRAFT), Algorithm 13, +// although the computation of t and AT is done in parseEK. +func pkeEncrypt(cc *[CiphertextSize]byte, ex *encryptionKey, m *[messageSize]byte, rnd []byte) []byte { + var N byte + r, e1 := make([]nttElement, k), make([]ringElement, k) + for i := range r { + r[i] = ntt(samplePolyCBD(rnd, N)) + N++ + } + for i := range e1 { + e1[i] = samplePolyCBD(rnd, N) + N++ + } + e2 := samplePolyCBD(rnd, N) + + u := make([]ringElement, k) // NTT⁻¹(AT ◦ r) + e1 + for i := range u { + u[i] = e1[i] + for j := range r { + // Note that i and j are inverted, as we need the transposed of A. + u[i] = polyAdd(u[i], inverseNTT(nttMul(ex.A[j*k+i], r[j]))) + } + } + + μ := ringDecodeAndDecompress1(m) + + var vNTT nttElement // t⊺ ◦ r + for i := range ex.t { + vNTT = polyAdd(vNTT, nttMul(ex.t[i], r[i])) + } + v := polyAdd(polyAdd(inverseNTT(vNTT), e2), μ) + + c := cc[:0] + for _, f := range u { + c = ringCompressAndEncode10(c, f) + } + c = ringCompressAndEncode4(c, v) + + return c +} + +// Decapsulate generates a shared key from a ciphertext and a decapsulation key. +// If the ciphertext is not valid, Decapsulate returns an error. +// +// The shared key must be kept secret. +func Decapsulate(dk *DecapsulationKey, ciphertext []byte) (sharedKey []byte, err error) { + if len(ciphertext) != CiphertextSize { + return nil, errors.New("mlkem768: invalid ciphertext length") + } + c := (*[CiphertextSize]byte)(ciphertext) + return kemDecaps(dk, c), nil +} + +// kemDecaps produces a shared key from a ciphertext. +// +// It implements ML-KEM.Decaps according to FIPS 203 (DRAFT), Algorithm 17. +func kemDecaps(dk *DecapsulationKey, c *[CiphertextSize]byte) (K []byte) { + h := dk.dk[decryptionKeySize+encryptionKeySize : decryptionKeySize+encryptionKeySize+32] + z := dk.dk[decryptionKeySize+encryptionKeySize+32:] + + m := pkeDecrypt(&dk.decryptionKey, c) + g := sha3.New512() + g.Write(m[:]) + g.Write(h) + G := g.Sum(nil) + Kprime, r := G[:SharedKeySize], G[SharedKeySize:] + J := sha3.NewShake256() + J.Write(z) + J.Write(c[:]) + Kout := make([]byte, SharedKeySize) + J.Read(Kout) + var cc [CiphertextSize]byte + c1 := pkeEncrypt(&cc, &dk.encryptionKey, (*[32]byte)(m), r) + + subtle.ConstantTimeCopy(subtle.ConstantTimeCompare(c[:], c1), Kout, Kprime) + return Kout +} + +// parseDK parses a decryption key from its encoded form. +// +// It implements the computation of s from K-PKE.Decrypt according to FIPS 203 +// (DRAFT), Algorithm 14. +func parseDK(dx *decryptionKey, dkPKE []byte) error { + if len(dkPKE) != decryptionKeySize { + return errors.New("mlkem768: invalid decryption key length") + } + + for i := range dx.s { + f, err := polyByteDecode[nttElement](dkPKE[:encodingSize12]) + if err != nil { + return err + } + dx.s[i] = f + dkPKE = dkPKE[encodingSize12:] + } + + return nil +} + +// pkeDecrypt decrypts a ciphertext. +// +// It implements K-PKE.Decrypt according to FIPS 203 (DRAFT), Algorithm 14, +// although the computation of s is done in parseDK. +func pkeDecrypt(dx *decryptionKey, c *[CiphertextSize]byte) []byte { + u := make([]ringElement, k) + for i := range u { + b := (*[encodingSize10]byte)(c[encodingSize10*i : encodingSize10*(i+1)]) + u[i] = ringDecodeAndDecompress10(b) + } + + b := (*[encodingSize4]byte)(c[encodingSize10*k:]) + v := ringDecodeAndDecompress4(b) + + var mask nttElement // s⊺ ◦ NTT(u) + for i := range dx.s { + mask = polyAdd(mask, nttMul(dx.s[i], ntt(u[i]))) + } + w := polySub(v, inverseNTT(mask)) + + return ringCompressAndEncode1(nil, w) +} + +// fieldElement is an integer modulo q, an element of ℤ_q. It is always reduced. +type fieldElement uint16 + +// fieldCheckReduced checks that a value a is < q. +func fieldCheckReduced(a uint16) (fieldElement, error) { + if a >= q { + return 0, errors.New("unreduced field element") + } + return fieldElement(a), nil +} + +// fieldReduceOnce reduces a value a < 2q. +func fieldReduceOnce(a uint16) fieldElement { + x := a - q + // If x underflowed, then x >= 2¹⁶ - q > 2¹⁵, so the top bit is set. + x += (x >> 15) * q + return fieldElement(x) +} + +func fieldAdd(a, b fieldElement) fieldElement { + x := uint16(a + b) + return fieldReduceOnce(x) +} + +func fieldSub(a, b fieldElement) fieldElement { + x := uint16(a - b + q) + return fieldReduceOnce(x) +} + +const ( + barrettMultiplier = 5039 // 2¹² * 2¹² / q + barrettShift = 24 // log₂(2¹² * 2¹²) +) + +// fieldReduce reduces a value a < 2q² using Barrett reduction, to avoid +// potentially variable-time division. +func fieldReduce(a uint32) fieldElement { + quotient := uint32((uint64(a) * barrettMultiplier) >> barrettShift) + return fieldReduceOnce(uint16(a - quotient*q)) +} + +func fieldMul(a, b fieldElement) fieldElement { + x := uint32(a) * uint32(b) + return fieldReduce(x) +} + +// fieldMulSub returns a * (b - c). This operation is fused to save a +// fieldReduceOnce after the subtraction. +func fieldMulSub(a, b, c fieldElement) fieldElement { + x := uint32(a) * uint32(b-c+q) + return fieldReduce(x) +} + +// fieldAddMul returns a * b + c * d. This operation is fused to save a +// fieldReduceOnce and a fieldReduce. +func fieldAddMul(a, b, c, d fieldElement) fieldElement { + x := uint32(a) * uint32(b) + x += uint32(c) * uint32(d) + return fieldReduce(x) +} + +// compress maps a field element uniformly to the range 0 to 2ᵈ-1, according to +// FIPS 203 (DRAFT), Definition 4.5. +func compress(x fieldElement, d uint8) uint16 { + // We want to compute (x * 2ᵈ) / q, rounded to nearest integer, with 1/2 + // rounding up (see FIPS 203 (DRAFT), Section 2.3). + + // Barrett reduction produces a quotient and a remainder in the range [0, 2q), + // such that dividend = quotient * q + remainder. + dividend := uint32(x) << d // x * 2ᵈ + quotient := uint32(uint64(dividend) * barrettMultiplier >> barrettShift) + remainder := dividend - quotient*q + + // Since the remainder is in the range [0, 2q), not [0, q), we need to + // portion it into three spans for rounding. + // + // [ 0, q/2 ) -> round to 0 + // [ q/2, q + q/2 ) -> round to 1 + // [ q + q/2, 2q ) -> round to 2 + // + // We can convert that to the following logic: add 1 if remainder > q/2, + // then add 1 again if remainder > q + q/2. + // + // Note that if remainder > x, then ⌊x⌋ - remainder underflows, and the top + // bit of the difference will be set. + quotient += (q/2 - remainder) >> 31 & 1 + quotient += (q + q/2 - remainder) >> 31 & 1 + + // quotient might have overflowed at this point, so reduce it by masking. + var mask uint32 = (1 << d) - 1 + return uint16(quotient & mask) +} + +// decompress maps a number x between 0 and 2ᵈ-1 uniformly to the full range of +// field elements, according to FIPS 203 (DRAFT), Definition 4.6. +func decompress(y uint16, d uint8) fieldElement { + // We want to compute (y * q) / 2ᵈ, rounded to nearest integer, with 1/2 + // rounding up (see FIPS 203 (DRAFT), Section 2.3). + + dividend := uint32(y) * q + quotient := dividend >> d // (y * q) / 2ᵈ + + // The d'th least-significant bit of the dividend (the most significant bit + // of the remainder) is 1 for the top half of the values that divide to the + // same quotient, which are the ones that round up. + quotient += dividend >> (d - 1) & 1 + + // quotient is at most (2¹¹-1) * q / 2¹¹ + 1 = 3328, so it didn't overflow. + return fieldElement(quotient) +} + +// ringElement is a polynomial, an element of R_q, represented as an array +// according to FIPS 203 (DRAFT), Section 2.4. +type ringElement [n]fieldElement + +// polyAdd adds two ringElements or nttElements. +func polyAdd[T ~[n]fieldElement](a, b T) (s T) { + for i := range s { + s[i] = fieldAdd(a[i], b[i]) + } + return s +} + +// polySub subtracts two ringElements or nttElements. +func polySub[T ~[n]fieldElement](a, b T) (s T) { + for i := range s { + s[i] = fieldSub(a[i], b[i]) + } + return s +} + +// polyByteEncode appends the 384-byte encoding of f to b. +// +// It implements ByteEncode₁₂, according to FIPS 203 (DRAFT), Algorithm 4. +func polyByteEncode[T ~[n]fieldElement](b []byte, f T) []byte { + out, B := sliceForAppend(b, encodingSize12) + for i := 0; i < n; i += 2 { + x := uint32(f[i]) | uint32(f[i+1])<<12 + B[0] = uint8(x) + B[1] = uint8(x >> 8) + B[2] = uint8(x >> 16) + B = B[3:] + } + return out +} + +// polyByteDecode decodes the 384-byte encoding of a polynomial, checking that +// all the coefficients are properly reduced. This achieves the "Modulus check" +// step of ML-KEM Encapsulation Input Validation. +// +// polyByteDecode is also used in ML-KEM Decapsulation, where the input +// validation is not required, but implicitly allowed by the specification. +// +// It implements ByteDecode₁₂, according to FIPS 203 (DRAFT), Algorithm 5. +func polyByteDecode[T ~[n]fieldElement](b []byte) (T, error) { + if len(b) != encodingSize12 { + return T{}, errors.New("mlkem768: invalid encoding length") + } + var f T + for i := 0; i < n; i += 2 { + d := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 + const mask12 = 0b1111_1111_1111 + var err error + if f[i], err = fieldCheckReduced(uint16(d & mask12)); err != nil { + return T{}, errors.New("mlkem768: invalid polynomial encoding") + } + if f[i+1], err = fieldCheckReduced(uint16(d >> 12)); err != nil { + return T{}, errors.New("mlkem768: invalid polynomial encoding") + } + b = b[3:] + } + return f, nil +} + +// sliceForAppend takes a slice and a requested number of bytes. It returns a +// slice with the contents of the given slice followed by that many bytes and a +// second slice that aliases into it and contains only the extra bytes. If the +// original slice has sufficient capacity then no allocation is performed. +func sliceForAppend(in []byte, n int) (head, tail []byte) { + if total := len(in) + n; cap(in) >= total { + head = in[:total] + } else { + head = make([]byte, total) + copy(head, in) + } + tail = head[len(in):] + return +} + +// ringCompressAndEncode1 appends a 32-byte encoding of a ring element to s, +// compressing one coefficients per bit. +// +// It implements Compress₁, according to FIPS 203 (DRAFT), Definition 4.5, +// followed by ByteEncode₁, according to FIPS 203 (DRAFT), Algorithm 4. +func ringCompressAndEncode1(s []byte, f ringElement) []byte { + s, b := sliceForAppend(s, encodingSize1) + for i := range b { + b[i] = 0 + } + for i := range f { + b[i/8] |= uint8(compress(f[i], 1) << (i % 8)) + } + return s +} + +// ringDecodeAndDecompress1 decodes a 32-byte slice to a ring element where each +// bit is mapped to 0 or ⌈q/2⌋. +// +// It implements ByteDecode₁, according to FIPS 203 (DRAFT), Algorithm 5, +// followed by Decompress₁, according to FIPS 203 (DRAFT), Definition 4.6. +func ringDecodeAndDecompress1(b *[encodingSize1]byte) ringElement { + var f ringElement + for i := range f { + b_i := b[i/8] >> (i % 8) & 1 + const halfQ = (q + 1) / 2 // ⌈q/2⌋, rounded up per FIPS 203 (DRAFT), Section 2.3 + f[i] = fieldElement(b_i) * halfQ // 0 decompresses to 0, and 1 to ⌈q/2⌋ + } + return f +} + +// ringCompressAndEncode4 appends a 128-byte encoding of a ring element to s, +// compressing two coefficients per byte. +// +// It implements Compress₄, according to FIPS 203 (DRAFT), Definition 4.5, +// followed by ByteEncode₄, according to FIPS 203 (DRAFT), Algorithm 4. +func ringCompressAndEncode4(s []byte, f ringElement) []byte { + s, b := sliceForAppend(s, encodingSize4) + for i := 0; i < n; i += 2 { + b[i/2] = uint8(compress(f[i], 4) | compress(f[i+1], 4)<<4) + } + return s +} + +// ringDecodeAndDecompress4 decodes a 128-byte encoding of a ring element where +// each four bits are mapped to an equidistant distribution. +// +// It implements ByteDecode₄, according to FIPS 203 (DRAFT), Algorithm 5, +// followed by Decompress₄, according to FIPS 203 (DRAFT), Definition 4.6. +func ringDecodeAndDecompress4(b *[encodingSize4]byte) ringElement { + var f ringElement + for i := 0; i < n; i += 2 { + f[i] = fieldElement(decompress(uint16(b[i/2]&0b1111), 4)) + f[i+1] = fieldElement(decompress(uint16(b[i/2]>>4), 4)) + } + return f +} + +// ringCompressAndEncode10 appends a 320-byte encoding of a ring element to s, +// compressing four coefficients per five bytes. +// +// It implements Compress₁₀, according to FIPS 203 (DRAFT), Definition 4.5, +// followed by ByteEncode₁₀, according to FIPS 203 (DRAFT), Algorithm 4. +func ringCompressAndEncode10(s []byte, f ringElement) []byte { + s, b := sliceForAppend(s, encodingSize10) + for i := 0; i < n; i += 4 { + var x uint64 + x |= uint64(compress(f[i+0], 10)) + x |= uint64(compress(f[i+1], 10)) << 10 + x |= uint64(compress(f[i+2], 10)) << 20 + x |= uint64(compress(f[i+3], 10)) << 30 + b[0] = uint8(x) + b[1] = uint8(x >> 8) + b[2] = uint8(x >> 16) + b[3] = uint8(x >> 24) + b[4] = uint8(x >> 32) + b = b[5:] + } + return s +} + +// ringDecodeAndDecompress10 decodes a 320-byte encoding of a ring element where +// each ten bits are mapped to an equidistant distribution. +// +// It implements ByteDecode₁₀, according to FIPS 203 (DRAFT), Algorithm 5, +// followed by Decompress₁₀, according to FIPS 203 (DRAFT), Definition 4.6. +func ringDecodeAndDecompress10(bb *[encodingSize10]byte) ringElement { + b := bb[:] + var f ringElement + for i := 0; i < n; i += 4 { + x := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 + b = b[5:] + f[i] = fieldElement(decompress(uint16(x>>0&0b11_1111_1111), 10)) + f[i+1] = fieldElement(decompress(uint16(x>>10&0b11_1111_1111), 10)) + f[i+2] = fieldElement(decompress(uint16(x>>20&0b11_1111_1111), 10)) + f[i+3] = fieldElement(decompress(uint16(x>>30&0b11_1111_1111), 10)) + } + return f +} + +// samplePolyCBD draws a ringElement from the special Dη distribution given a +// stream of random bytes generated by the PRF function, according to FIPS 203 +// (DRAFT), Algorithm 7 and Definition 4.1. +func samplePolyCBD(s []byte, b byte) ringElement { + prf := sha3.NewShake256() + prf.Write(s) + prf.Write([]byte{b}) + B := make([]byte, 128) + prf.Read(B) + + // SamplePolyCBD simply draws four (2η) bits for each coefficient, and adds + // the first two and subtracts the last two. + + var f ringElement + for i := 0; i < n; i += 2 { + b := B[i/2] + b_7, b_6, b_5, b_4 := b>>7, b>>6&1, b>>5&1, b>>4&1 + b_3, b_2, b_1, b_0 := b>>3&1, b>>2&1, b>>1&1, b&1 + f[i] = fieldSub(fieldElement(b_0+b_1), fieldElement(b_2+b_3)) + f[i+1] = fieldSub(fieldElement(b_4+b_5), fieldElement(b_6+b_7)) + } + return f +} + +// nttElement is an NTT representation, an element of T_q, represented as an +// array according to FIPS 203 (DRAFT), Section 2.4. +type nttElement [n]fieldElement + +// gammas are the values ζ^2BitRev7(i)+1 mod q for each index i. +var gammas = [128]fieldElement{17, 3312, 2761, 568, 583, 2746, 2649, 680, 1637, 1692, 723, 2606, 2288, 1041, 1100, 2229, 1409, 1920, 2662, 667, 3281, 48, 233, 3096, 756, 2573, 2156, 1173, 3015, 314, 3050, 279, 1703, 1626, 1651, 1678, 2789, 540, 1789, 1540, 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, 939, 2390, 2308, 1021, 2437, 892, 2388, 941, 733, 2596, 2337, 992, 268, 3061, 641, 2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, 1063, 2266, 319, 3010, 2773, 556, 757, 2572, 2099, 1230, 561, 2768, 2466, 863, 2594, 735, 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, 1143, 2186, 2150, 1179, 2775, 554, 886, 2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, 2110, 1219, 2935, 394, 885, 2444, 2154, 1175} + +// nttMul multiplies two nttElements. +// +// It implements MultiplyNTTs, according to FIPS 203 (DRAFT), Algorithm 10. +func nttMul(f, g nttElement) nttElement { + var h nttElement + // We use i += 2 for bounds check elimination. See https://go.dev/issue/66826. + for i := 0; i < 256; i += 2 { + a0, a1 := f[i], f[i+1] + b0, b1 := g[i], g[i+1] + h[i] = fieldAddMul(a0, b0, fieldMul(a1, b1), gammas[i/2]) + h[i+1] = fieldAddMul(a0, b1, a1, b0) + } + return h +} + +// zetas are the values ζ^BitRev7(k) mod q for each index k. +var zetas = [128]fieldElement{1, 1729, 2580, 3289, 2642, 630, 1897, 848, 1062, 1919, 193, 797, 2786, 3260, 569, 1746, 296, 2447, 1339, 1476, 3046, 56, 2240, 1333, 1426, 2094, 535, 2882, 2393, 2879, 1974, 821, 289, 331, 3253, 1756, 1197, 2304, 2277, 2055, 650, 1977, 2513, 632, 2865, 33, 1320, 1915, 2319, 1435, 807, 452, 1438, 2868, 1534, 2402, 2647, 2617, 1481, 648, 2474, 3110, 1227, 910, 17, 2761, 583, 2649, 1637, 723, 2288, 1100, 1409, 2662, 3281, 233, 756, 2156, 3015, 3050, 1703, 1651, 2789, 1789, 1847, 952, 1461, 2687, 939, 2308, 2437, 2388, 733, 2337, 268, 641, 1584, 2298, 2037, 3220, 375, 2549, 2090, 1645, 1063, 319, 2773, 757, 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154} + +// ntt maps a ringElement to its nttElement representation. +// +// It implements NTT, according to FIPS 203 (DRAFT), Algorithm 8. +func ntt(f ringElement) nttElement { + k := 1 + for len := 128; len >= 2; len /= 2 { + for start := 0; start < 256; start += 2 * len { + zeta := zetas[k] + k++ + // Bounds check elimination hint. + f, flen := f[start:start+len], f[start+len:start+len+len] + for j := 0; j < len; j++ { + t := fieldMul(zeta, flen[j]) + flen[j] = fieldSub(f[j], t) + f[j] = fieldAdd(f[j], t) + } + } + } + return nttElement(f) +} + +// inverseNTT maps a nttElement back to the ringElement it represents. +// +// It implements NTT⁻¹, according to FIPS 203 (DRAFT), Algorithm 9. +func inverseNTT(f nttElement) ringElement { + k := 127 + for len := 2; len <= 128; len *= 2 { + for start := 0; start < 256; start += 2 * len { + zeta := zetas[k] + k-- + // Bounds check elimination hint. + f, flen := f[start:start+len], f[start+len:start+len+len] + for j := 0; j < len; j++ { + t := f[j] + f[j] = fieldAdd(t, flen[j]) + flen[j] = fieldMulSub(zeta, flen[j], t) + } + } + } + for i := range f { + f[i] = fieldMul(f[i], 3303) // 3303 = 128⁻¹ mod q + } + return ringElement(f) +} + +// sampleNTT draws a uniformly random nttElement from a stream of uniformly +// random bytes generated by the XOF function, according to FIPS 203 (DRAFT), +// Algorithm 6 and Definition 4.2. +func sampleNTT(rho []byte, ii, jj byte) nttElement { + B := sha3.NewShake128() + B.Write(rho) + B.Write([]byte{ii, jj}) + + // SampleNTT essentially draws 12 bits at a time from r, interprets them in + // little-endian, and rejects values higher than q, until it drew 256 + // values. (The rejection rate is approximately 19%.) + // + // To do this from a bytes stream, it draws three bytes at a time, and + // splits them into two uint16 appropriately masked. + // + // r₀ r₁ r₂ + // |- - - - - - - -|- - - - - - - -|- - - - - - - -| + // + // Uint16(r₀ || r₁) + // |- - - - - - - - - - - - - - - -| + // |- - - - - - - - - - - -| + // d₁ + // + // Uint16(r₁ || r₂) + // |- - - - - - - - - - - - - - - -| + // |- - - - - - - - - - - -| + // d₂ + // + // Note that in little-endian, the rightmost bits are the most significant + // bits (dropped with a mask) and the leftmost bits are the least + // significant bits (dropped with a right shift). + + var a nttElement + var j int // index into a + var buf [24]byte // buffered reads from B + off := len(buf) // index into buf, starts in a "buffer fully consumed" state + for { + if off >= len(buf) { + B.Read(buf[:]) + off = 0 + } + d1 := byteorder.LeUint16(buf[off:]) & 0b1111_1111_1111 + d2 := byteorder.LeUint16(buf[off+1:]) >> 4 + off += 3 + if d1 < q { + a[j] = fieldElement(d1) + j++ + } + if j >= len(a) { + break + } + if d2 < q { + a[j] = fieldElement(d2) + j++ + } + if j >= len(a) { + break + } + } + return a +} diff --git a/contrib/go/_std_1.23/src/crypto/internal/mlkem768/ya.make b/contrib/go/_std_1.23/src/crypto/internal/mlkem768/ya.make new file mode 100644 index 000000000000..60ce6440a2a8 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/mlkem768/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + mlkem768.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/Dockerfile b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/Dockerfile similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/Dockerfile rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/Dockerfile diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/README b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/README similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/README rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/README diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/generate.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/generate.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/generate.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/generate.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224_fiat64.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224_fiat64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224_fiat64.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224_fiat64.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224_invert.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224_invert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224_invert.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224_invert.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256_fiat64.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256_fiat64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256_fiat64.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256_fiat64.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256_invert.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256_invert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256_invert.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256_invert.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384_fiat64.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384_fiat64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384_fiat64.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384_fiat64.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384_invert.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384_invert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384_invert.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384_invert.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521_fiat64.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521_fiat64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521_fiat64.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521_fiat64.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521_invert.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521_invert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521_invert.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521_invert.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/ya.make b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/generate.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/generate.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/generate.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/generate.go index 0e84cefb3657..27e8d13943b2 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/generate.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/generate.go @@ -40,7 +40,7 @@ var curves = []struct { P: "P256", Element: "fiat.P256Element", Params: elliptic.P256().Params(), - BuildTags: "!amd64 && !arm64 && !ppc64le && !s390x", + BuildTags: "(!amd64 && !arm64 && !ppc64le && !s390x) || purego", }, { P: "P384", diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/nistec.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/nistec.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/nistec.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/nistec.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p224.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p224.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p224.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p224.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p224_sqrt.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p224_sqrt.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p224_sqrt.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p224_sqrt.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256.go index 3cfa5fb37179..f2dfbbb1ee9b 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256.go @@ -4,7 +4,7 @@ // Code generated by generate.go. DO NOT EDIT. -//go:build !amd64 && !arm64 && !ppc64le && !s390x +//go:build (!amd64 && !arm64 && !ppc64le && !s390x) || purego package nistec diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm.go index 99a22b833f02..5dbd7efbd56d 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm.go @@ -10,14 +10,14 @@ // https://link.springer.com/article/10.1007%2Fs13389-014-0090-x // https://eprint.iacr.org/2013/816.pdf -//go:build amd64 || arm64 || ppc64le || s390x +//go:build (amd64 || arm64 || ppc64le || s390x) && !purego package nistec import ( _ "embed" - "encoding/binary" "errors" + "internal/byteorder" "math/bits" "runtime" "unsafe" @@ -327,7 +327,7 @@ func init() { if runtime.GOARCH == "s390x" { var newTable [43 * 32 * 2 * 4]uint64 for i, x := range (*[43 * 32 * 2 * 4][8]byte)(*p256PrecomputedPtr) { - newTable[i] = binary.LittleEndian.Uint64(x[:]) + newTable[i] = byteorder.LeUint64(x[:]) } newTablePtr := unsafe.Pointer(&newTable) p256PrecomputedPtr = &newTablePtr diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_amd64.s b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_amd64.s rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_amd64.s index 84e4cee9039c..f5c008319bd7 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_amd64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // This file contains constant-time, 64-bit assembly implementation of // P256. The optimizations performed here are described in detail in: // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_arm64.s b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_arm64.s rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_arm64.s index 1ba5df381b3a..d00a54db1adc 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // This file contains constant-time, 64-bit assembly implementation of // P256. The optimizations performed here are described in detail in: // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_ppc64le.s b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_ppc64le.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_ppc64le.s rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_ppc64le.s index 6b787609b999..b13bd512a6e3 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_ppc64le.s +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_ppc64le.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // This is a port of the s390x asm implementation. @@ -124,14 +126,23 @@ GLOBL p256mul<>(SB), 8, $160 #define PH V31 #define CAR1 V6 + +#define SEL V8 +#define ZER V9 + // func p256NegCond(val *p256Point, cond int) TEXT ·p256NegCond(SB), NOSPLIT, $0-16 MOVD val+0(FP), P1ptr MOVD $16, R16 - MOVD cond+8(FP), R6 - CMP $0, R6 - BC 12, 2, LR // just return if cond == 0 + // Copy cond into SEL (cond is R1 + 8 (cond offset) + 32) + MOVD $40, R17 + LXVDSX (R1)(R17), SEL + // Zeroize ZER + VSPLTISB $0, ZER + // SEL controls whether to return the original value (Y1H/Y1L) + // or the negated value (T1H/T1L). + VCMPEQUD SEL, ZER, SEL MOVD $p256mul<>+0x00(SB), CPOOL @@ -148,6 +159,9 @@ TEXT ·p256NegCond(SB), NOSPLIT, $0-16 VSUBUQM PL, Y1L, T1L // subtract part2 giving result VSUBEUQM PH, Y1H, CAR1, T1H // subtract part1 using carry from part2 + VSEL T1H, Y1H, SEL, T1H + VSEL T1L, Y1L, SEL, T1L + XXPERMDI T1H, T1H, $2, T1H XXPERMDI T1L, T1L, $2, T1L @@ -164,6 +178,8 @@ TEXT ·p256NegCond(SB), NOSPLIT, $0-16 #undef PL #undef PH #undef CAR1 +#undef SEL +#undef ZER #define P3ptr R3 #define P1ptr R4 diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_s390x.s b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_s390x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_s390x.s rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_s390x.s index 8da4f3f5b89d..77c9f63349a0 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" #include "go_asm.h" diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_table.bin b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_table.bin similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_table.bin rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_table.bin diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv.go index 1274fb7fd3f5..156a873188c3 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 || arm64 +//go:build (amd64 || arm64) && !purego package nistec diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv_noasm.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv_noasm.go similarity index 87% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv_noasm.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv_noasm.go index 213875ce7616..9cbb1a89dbaf 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv_noasm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !arm64 +//go:build (!amd64 && !arm64) || purego package nistec diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p384.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p384.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p384.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p384.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p521.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p521.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p521.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p521.go diff --git a/contrib/go/_std_1.23/src/crypto/internal/nistec/ya.make b/contrib/go/_std_1.23/src/crypto/internal/nistec/ya.make new file mode 100644 index 000000000000..84834014bbac --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/ya.make @@ -0,0 +1,39 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + nistec.go + p224.go + p224_sqrt.go + p256_asm.go + p256_asm_arm64.s + p256_ordinv.go + p384.go + p521.go + ) + + GO_EMBED_PATTERN(p256_asm_table.bin) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + nistec.go + p224.go + p224_sqrt.go + p256_asm.go + p256_asm_amd64.s + p256_ordinv.go + p384.go + p521.go + ) + + GO_EMBED_PATTERN(p256_asm_table.bin) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + nistec.go + p224.go + p224_sqrt.go + p256.go + p256_ordinv_noasm.go + p384.go + p521.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/internal/randutil/randutil.go b/contrib/go/_std_1.23/src/crypto/internal/randutil/randutil.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/randutil/randutil.go rename to contrib/go/_std_1.23/src/crypto/internal/randutil/randutil.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/randutil/ya.make b/contrib/go/_std_1.23/src/crypto/internal/randutil/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/randutil/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/randutil/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/ya.make b/contrib/go/_std_1.23/src/crypto/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/ya.make diff --git a/contrib/go/_std_1.23/src/crypto/md5/gen.go b/contrib/go/_std_1.23/src/crypto/md5/gen.go new file mode 100644 index 000000000000..5290c3627c9b --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/md5/gen.go @@ -0,0 +1,259 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build ignore + +// This program generates md5block.go +// Invoke as +// +// go run gen.go -output md5block.go + +package main + +import ( + "bytes" + "flag" + "go/format" + "log" + "os" + "strings" + "text/template" +) + +var filename = flag.String("output", "md5block.go", "output file name") + +func main() { + flag.Parse() + + var buf bytes.Buffer + + t := template.Must(template.New("main").Funcs(funcs).Parse(program)) + if err := t.Execute(&buf, data); err != nil { + log.Fatal(err) + } + + data, err := format.Source(buf.Bytes()) + if err != nil { + log.Fatal(err) + } + err = os.WriteFile(*filename, data, 0644) + if err != nil { + log.Fatal(err) + } +} + +type Data struct { + a, b, c, d string + Shift1 []int + Shift2 []int + Shift3 []int + Shift4 []int + Table1 []uint32 + Table2 []uint32 + Table3 []uint32 + Table4 []uint32 +} + +var funcs = template.FuncMap{ + "dup": dup, + "relabel": relabel, + "rotate": rotate, + "idx": idx, + "seq": seq, +} + +func dup(count int, x []int) []int { + var out []int + for i := 0; i < count; i++ { + out = append(out, x...) + } + return out +} + +func relabel(s string) string { + return strings.NewReplacer("arg0", data.a, "arg1", data.b, "arg2", data.c, "arg3", data.d).Replace(s) +} + +func rotate() string { + data.a, data.b, data.c, data.d = data.d, data.a, data.b, data.c + return "" // no output +} + +func idx(round, index int) int { + v := 0 + switch round { + case 1: + v = index + case 2: + v = (1 + 5*index) & 15 + case 3: + v = (5 + 3*index) & 15 + case 4: + v = (7 * index) & 15 + } + return v +} + +func seq(i int) []int { + s := make([]int, i) + for i := range s { + s[i] = i + } + return s +} + +var data = Data{ + a: "a", + b: "b", + c: "c", + d: "d", + Shift1: []int{7, 12, 17, 22}, + Shift2: []int{5, 9, 14, 20}, + Shift3: []int{4, 11, 16, 23}, + Shift4: []int{6, 10, 15, 21}, + + // table[i] = int((1<<32) * abs(sin(i+1 radians))). + Table1: []uint32{ + // round 1 + 0xd76aa478, + 0xe8c7b756, + 0x242070db, + 0xc1bdceee, + 0xf57c0faf, + 0x4787c62a, + 0xa8304613, + 0xfd469501, + 0x698098d8, + 0x8b44f7af, + 0xffff5bb1, + 0x895cd7be, + 0x6b901122, + 0xfd987193, + 0xa679438e, + 0x49b40821, + }, + Table2: []uint32{ + // round 2 + 0xf61e2562, + 0xc040b340, + 0x265e5a51, + 0xe9b6c7aa, + 0xd62f105d, + 0x2441453, + 0xd8a1e681, + 0xe7d3fbc8, + 0x21e1cde6, + 0xc33707d6, + 0xf4d50d87, + 0x455a14ed, + 0xa9e3e905, + 0xfcefa3f8, + 0x676f02d9, + 0x8d2a4c8a, + }, + Table3: []uint32{ + // round3 + 0xfffa3942, + 0x8771f681, + 0x6d9d6122, + 0xfde5380c, + 0xa4beea44, + 0x4bdecfa9, + 0xf6bb4b60, + 0xbebfbc70, + 0x289b7ec6, + 0xeaa127fa, + 0xd4ef3085, + 0x4881d05, + 0xd9d4d039, + 0xe6db99e5, + 0x1fa27cf8, + 0xc4ac5665, + }, + Table4: []uint32{ + // round 4 + 0xf4292244, + 0x432aff97, + 0xab9423a7, + 0xfc93a039, + 0x655b59c3, + 0x8f0ccc92, + 0xffeff47d, + 0x85845dd1, + 0x6fa87e4f, + 0xfe2ce6e0, + 0xa3014314, + 0x4e0811a1, + 0xf7537e82, + 0xbd3af235, + 0x2ad7d2bb, + 0xeb86d391, + }, +} + +var program = `// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by go run gen.go -output md5block.go; DO NOT EDIT. + +package md5 + +import ( + "internal/byteorder" + "math/bits" +) + +func blockGeneric(dig *digest, p []byte) { + // load state + a, b, c, d := dig.s[0], dig.s[1], dig.s[2], dig.s[3] + + for i := 0; i <= len(p)-BlockSize; i += BlockSize { + // eliminate bounds checks on p + q := p[i:] + q = q[:BlockSize:BlockSize] + + // save current state + aa, bb, cc, dd := a, b, c, d + + // load input block + {{range $i := seq 16 -}} + {{printf "x%x := byteorder.LeUint32(q[4*%#x:])" $i $i}} + {{end}} + + // round 1 + {{range $i, $s := dup 4 .Shift1 -}} + {{printf "arg0 = arg1 + bits.RotateLeft32((((arg2^arg3)&arg1)^arg3)+arg0+x%x+%#08x, %d)" (idx 1 $i) (index $.Table1 $i) $s | relabel}} + {{rotate -}} + {{end}} + + // round 2 + {{range $i, $s := dup 4 .Shift2 -}} + {{printf "arg0 = arg1 + bits.RotateLeft32((((arg1^arg2)&arg3)^arg2)+arg0+x%x+%#08x, %d)" (idx 2 $i) (index $.Table2 $i) $s | relabel}} + {{rotate -}} + {{end}} + + // round 3 + {{range $i, $s := dup 4 .Shift3 -}} + {{printf "arg0 = arg1 + bits.RotateLeft32((arg1^arg2^arg3)+arg0+x%x+%#08x, %d)" (idx 3 $i) (index $.Table3 $i) $s | relabel}} + {{rotate -}} + {{end}} + + // round 4 + {{range $i, $s := dup 4 .Shift4 -}} + {{printf "arg0 = arg1 + bits.RotateLeft32((arg2^(arg1|^arg3))+arg0+x%x+%#08x, %d)" (idx 4 $i) (index $.Table4 $i) $s | relabel}} + {{rotate -}} + {{end}} + + // add saved state + a += aa + b += bb + c += cc + d += dd + } + + // save state + dig.s[0], dig.s[1], dig.s[2], dig.s[3] = a, b, c, d +} +` diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5.go b/contrib/go/_std_1.23/src/crypto/md5/md5.go similarity index 83% rename from contrib/go/_std_1.22/src/crypto/md5/md5.go rename to contrib/go/_std_1.23/src/crypto/md5/md5.go index 83e9e4c07a0a..843678702bf9 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5.go +++ b/contrib/go/_std_1.23/src/crypto/md5/md5.go @@ -12,9 +12,9 @@ package md5 import ( "crypto" - "encoding/binary" "errors" "hash" + "internal/byteorder" ) func init() { @@ -59,13 +59,13 @@ const ( func (d *digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) - b = binary.BigEndian.AppendUint32(b, d.s[0]) - b = binary.BigEndian.AppendUint32(b, d.s[1]) - b = binary.BigEndian.AppendUint32(b, d.s[2]) - b = binary.BigEndian.AppendUint32(b, d.s[3]) + b = byteorder.BeAppendUint32(b, d.s[0]) + b = byteorder.BeAppendUint32(b, d.s[1]) + b = byteorder.BeAppendUint32(b, d.s[2]) + b = byteorder.BeAppendUint32(b, d.s[3]) b = append(b, d.x[:d.nx]...) b = b[:len(b)+len(d.x)-d.nx] // already zero - b = binary.BigEndian.AppendUint64(b, d.len) + b = byteorder.BeAppendUint64(b, d.len) return b, nil } @@ -88,11 +88,11 @@ func (d *digest) UnmarshalBinary(b []byte) error { } func consumeUint64(b []byte) ([]byte, uint64) { - return b[8:], binary.BigEndian.Uint64(b[0:8]) + return b[8:], byteorder.BeUint64(b[0:8]) } func consumeUint32(b []byte) ([]byte, uint32) { - return b[4:], binary.BigEndian.Uint32(b[0:4]) + return b[4:], byteorder.BeUint32(b[0:4]) } // New returns a new hash.Hash computing the MD5 checksum. The Hash also @@ -156,8 +156,8 @@ func (d *digest) checkSum() [Size]byte { // // 1 byte end marker :: 0-63 padding bytes :: 8 byte length tmp := [1 + 63 + 8]byte{0x80} - pad := (55 - d.len) % 64 // calculate number of padding bytes - binary.LittleEndian.PutUint64(tmp[1+pad:], d.len<<3) // append length in bits + pad := (55 - d.len) % 64 // calculate number of padding bytes + byteorder.LePutUint64(tmp[1+pad:], d.len<<3) // append length in bits d.Write(tmp[:1+pad+8]) // The previous write ensures that a whole number of @@ -167,10 +167,10 @@ func (d *digest) checkSum() [Size]byte { } var digest [Size]byte - binary.LittleEndian.PutUint32(digest[0:], d.s[0]) - binary.LittleEndian.PutUint32(digest[4:], d.s[1]) - binary.LittleEndian.PutUint32(digest[8:], d.s[2]) - binary.LittleEndian.PutUint32(digest[12:], d.s[3]) + byteorder.LePutUint32(digest[0:], d.s[0]) + byteorder.LePutUint32(digest[4:], d.s[1]) + byteorder.LePutUint32(digest[8:], d.s[2]) + byteorder.LePutUint32(digest[12:], d.s[3]) return digest } diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block.go b/contrib/go/_std_1.23/src/crypto/md5/md5block.go similarity index 86% rename from contrib/go/_std_1.22/src/crypto/md5/md5block.go rename to contrib/go/_std_1.23/src/crypto/md5/md5block.go index 4ff289e860f9..473496b8d0ac 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block.go +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block.go @@ -7,7 +7,7 @@ package md5 import ( - "encoding/binary" + "internal/byteorder" "math/bits" ) @@ -24,22 +24,22 @@ func blockGeneric(dig *digest, p []byte) { aa, bb, cc, dd := a, b, c, d // load input block - x0 := binary.LittleEndian.Uint32(q[4*0x0:]) - x1 := binary.LittleEndian.Uint32(q[4*0x1:]) - x2 := binary.LittleEndian.Uint32(q[4*0x2:]) - x3 := binary.LittleEndian.Uint32(q[4*0x3:]) - x4 := binary.LittleEndian.Uint32(q[4*0x4:]) - x5 := binary.LittleEndian.Uint32(q[4*0x5:]) - x6 := binary.LittleEndian.Uint32(q[4*0x6:]) - x7 := binary.LittleEndian.Uint32(q[4*0x7:]) - x8 := binary.LittleEndian.Uint32(q[4*0x8:]) - x9 := binary.LittleEndian.Uint32(q[4*0x9:]) - xa := binary.LittleEndian.Uint32(q[4*0xa:]) - xb := binary.LittleEndian.Uint32(q[4*0xb:]) - xc := binary.LittleEndian.Uint32(q[4*0xc:]) - xd := binary.LittleEndian.Uint32(q[4*0xd:]) - xe := binary.LittleEndian.Uint32(q[4*0xe:]) - xf := binary.LittleEndian.Uint32(q[4*0xf:]) + x0 := byteorder.LeUint32(q[4*0x0:]) + x1 := byteorder.LeUint32(q[4*0x1:]) + x2 := byteorder.LeUint32(q[4*0x2:]) + x3 := byteorder.LeUint32(q[4*0x3:]) + x4 := byteorder.LeUint32(q[4*0x4:]) + x5 := byteorder.LeUint32(q[4*0x5:]) + x6 := byteorder.LeUint32(q[4*0x6:]) + x7 := byteorder.LeUint32(q[4*0x7:]) + x8 := byteorder.LeUint32(q[4*0x8:]) + x9 := byteorder.LeUint32(q[4*0x9:]) + xa := byteorder.LeUint32(q[4*0xa:]) + xb := byteorder.LeUint32(q[4*0xb:]) + xc := byteorder.LeUint32(q[4*0xc:]) + xd := byteorder.LeUint32(q[4*0xd:]) + xe := byteorder.LeUint32(q[4*0xe:]) + xf := byteorder.LeUint32(q[4*0xf:]) // round 1 a = b + bits.RotateLeft32((((c^d)&b)^d)+a+x0+0xd76aa478, 7) diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_386.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_386.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_386.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_386.s index 30d4209a6240..b6c6509d3b52 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_386.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_386.s @@ -6,6 +6,8 @@ // #defines generating 8a assembly, and adjusted for 386, // by the Go Authors. +//go:build !purego + #include "textflag.h" // MD5 optimized for AMD64. diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_amd64.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_amd64.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_amd64.s index 75c8074b37eb..652506ae27fb 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_amd64.s @@ -5,6 +5,8 @@ // Translated from Perl generating GNU assembly into // #defines generating 6a assembly by the Go Authors. +//go:build !purego + #include "textflag.h" // MD5 optimized for AMD64. diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_arm.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_arm.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_arm.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_arm.s index 54d02b743a6a..13fdc5c3beb5 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_arm.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_arm.s @@ -4,6 +4,8 @@ // // ARM version of md5block.go +//go:build !purego + #include "textflag.h" // Register definitions diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_arm64.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_arm64.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_arm64.s index 39b9851d1fe1..5942218f76fb 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_arm64.s @@ -5,6 +5,8 @@ // ARM64 version of md5block.go // derived from crypto/md5/md5block_amd64.s +//go:build !purego + #include "textflag.h" TEXT ·block(SB),NOSPLIT,$0-32 diff --git a/contrib/go/_std_1.23/src/crypto/md5/md5block_decl.go b/contrib/go/_std_1.23/src/crypto/md5/md5block_decl.go new file mode 100644 index 000000000000..3664542fb920 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_decl.go @@ -0,0 +1,12 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (amd64 || 386 || arm || ppc64le || ppc64 || s390x || arm64) && !purego + +package md5 + +const haveAsm = true + +//go:noescape +func block(dig *digest, p []byte) diff --git a/contrib/go/_std_1.23/src/crypto/md5/md5block_generic.go b/contrib/go/_std_1.23/src/crypto/md5/md5block_generic.go new file mode 100644 index 000000000000..43cfebd38a90 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_generic.go @@ -0,0 +1,13 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (!amd64 && !386 && !arm && !ppc64le && !ppc64 && !s390x && !arm64) || purego + +package md5 + +const haveAsm = false + +func block(dig *digest, p []byte) { + blockGeneric(dig, p) +} diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_ppc64x.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_ppc64x.s index 69a20e7cad33..49a369548ee7 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_ppc64x.s @@ -10,7 +10,7 @@ // Licence: I hereby disclaim the copyright on this code and place it // in the public domain. -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego #include "textflag.h" @@ -200,7 +200,7 @@ loop: ADD R16, R4 ADD R17, R5 ADD $64, R6 - BC 16, 0, loop // bdnz + BDNZ loop end: MOVD dig+0(FP), R10 diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_s390x.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_s390x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_s390x.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_s390x.s index 68f501cfea83..2d18d28f2514 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_s390x.s @@ -10,6 +10,8 @@ // Licence: I hereby disclaim the copyright on this code and place it // in the public domain. +//go:build !purego + #include "textflag.h" // func block(dig *digest, p []byte) diff --git a/contrib/go/_std_1.23/src/crypto/md5/ya.make b/contrib/go/_std_1.23/src/crypto/md5/ya.make new file mode 100644 index 000000000000..55c3475b1137 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/md5/ya.make @@ -0,0 +1,24 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + md5.go + md5block.go + md5block_arm64.s + md5block_decl.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + md5.go + md5block.go + md5block_amd64.s + md5block_decl.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + md5.go + md5block.go + md5block_arm.s + md5block_decl.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/crypto/rand/rand.go b/contrib/go/_std_1.23/src/crypto/rand/rand.go new file mode 100644 index 000000000000..d16d7a1c9c3f --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/rand/rand.go @@ -0,0 +1,46 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package rand implements a cryptographically secure +// random number generator. +package rand + +import "io" + +// Reader is a global, shared instance of a cryptographically +// secure random number generator. +// +// - On Linux, FreeBSD, Dragonfly, and Solaris, Reader uses getrandom(2) +// if available, and /dev/urandom otherwise. +// - On macOS and iOS, Reader uses arc4random_buf(3). +// - On OpenBSD and NetBSD, Reader uses getentropy(2). +// - On other Unix-like systems, Reader reads from /dev/urandom. +// - On Windows, Reader uses the ProcessPrng API. +// - On js/wasm, Reader uses the Web Crypto API. +// - On wasip1/wasm, Reader uses random_get from wasi_snapshot_preview1. +var Reader io.Reader + +// Read is a helper function that calls Reader.Read using io.ReadFull. +// On return, n == len(b) if and only if err == nil. +func Read(b []byte) (n int, err error) { + return io.ReadFull(Reader, b) +} + +// batched returns a function that calls f to populate a []byte by chunking it +// into subslices of, at most, readMax bytes. +func batched(f func([]byte) error, readMax int) func([]byte) error { + return func(out []byte) error { + for len(out) > 0 { + read := len(out) + if read > readMax { + read = readMax + } + if err := f(out[:read]); err != nil { + return err + } + out = out[read:] + } + return nil + } +} diff --git a/contrib/go/_std_1.23/src/crypto/rand/rand_darwin.go b/contrib/go/_std_1.23/src/crypto/rand/rand_darwin.go new file mode 100644 index 000000000000..363ad69ec4a4 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/rand/rand_darwin.go @@ -0,0 +1,19 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rand + +import "internal/syscall/unix" + +func init() { + // arc4random_buf is the recommended application CSPRNG, accepts buffers of + // any size, and never returns an error. + // + // "The subsystem is re-seeded from the kernel random number subsystem on a + // regular basis, and also upon fork(2)." - arc4random(3) + // + // Note that despite its legacy name, it uses a secure CSPRNG (not RC4) in + // all supported macOS versions. + altGetRandom = func(b []byte) error { unix.ARC4Random(b); return nil } +} diff --git a/contrib/go/_std_1.23/src/crypto/rand/rand_getentropy.go b/contrib/go/_std_1.23/src/crypto/rand/rand_getentropy.go new file mode 100644 index 000000000000..855716c83dd0 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/rand/rand_getentropy.go @@ -0,0 +1,14 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build openbsd || netbsd + +package rand + +import "internal/syscall/unix" + +func init() { + // getentropy(2) returns a maximum of 256 bytes per call. + altGetRandom = batched(unix.GetEntropy, 256) +} diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_getrandom.go b/contrib/go/_std_1.23/src/crypto/rand/rand_getrandom.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_getrandom.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_getrandom.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_js.go b/contrib/go/_std_1.23/src/crypto/rand/rand_js.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_js.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_js.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_plan9.go b/contrib/go/_std_1.23/src/crypto/rand/rand_plan9.go similarity index 95% rename from contrib/go/_std_1.22/src/crypto/rand/rand_plan9.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_plan9.go index 5d0af0959e9d..d5320210fd9c 100644 --- a/contrib/go/_std_1.22/src/crypto/rand/rand_plan9.go +++ b/contrib/go/_std_1.23/src/crypto/rand/rand_plan9.go @@ -9,7 +9,7 @@ package rand import ( "crypto/aes" - "encoding/binary" + "internal/byteorder" "io" "os" "sync" @@ -44,6 +44,7 @@ func (r *reader) Read(b []byte) (n int, err error) { r.seedErr = err return } + defer entropy.Close() _, r.seedErr = io.ReadFull(entropy, r.key[:]) }) if r.seedErr != nil { @@ -65,7 +66,7 @@ func (r *reader) Read(b []byte) (n int, err error) { if counter == 0 { panic("crypto/rand counter wrapped") } - binary.LittleEndian.PutUint64(block[:], counter) + byteorder.LePutUint64(block[:], counter) } blockCipher.Encrypt(r.key[:aes.BlockSize], block[:]) inc() diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_unix.go b/contrib/go/_std_1.23/src/crypto/rand/rand_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_unix.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_unix.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_wasip1.go b/contrib/go/_std_1.23/src/crypto/rand/rand_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_wasip1.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_wasip1.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_windows.go b/contrib/go/_std_1.23/src/crypto/rand/rand_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_windows.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_windows.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/util.go b/contrib/go/_std_1.23/src/crypto/rand/util.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/util.go rename to contrib/go/_std_1.23/src/crypto/rand/util.go diff --git a/contrib/go/_std_1.23/src/crypto/rand/ya.make b/contrib/go/_std_1.23/src/crypto/rand/ya.make new file mode 100644 index 000000000000..a87775f9d6b8 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/rand/ya.make @@ -0,0 +1,23 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + rand.go + rand_darwin.go + rand_unix.go + util.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + rand.go + rand_getrandom.go + rand_unix.go + util.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + rand.go + rand_windows.go + util.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/rc4/rc4.go b/contrib/go/_std_1.23/src/crypto/rc4/rc4.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rc4/rc4.go rename to contrib/go/_std_1.23/src/crypto/rc4/rc4.go diff --git a/contrib/go/_std_1.22/src/crypto/rc4/ya.make b/contrib/go/_std_1.23/src/crypto/rc4/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rc4/ya.make rename to contrib/go/_std_1.23/src/crypto/rc4/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/rsa/boring.go b/contrib/go/_std_1.23/src/crypto/rsa/boring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rsa/boring.go rename to contrib/go/_std_1.23/src/crypto/rsa/boring.go diff --git a/contrib/go/_std_1.22/src/crypto/rsa/notboring.go b/contrib/go/_std_1.23/src/crypto/rsa/notboring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rsa/notboring.go rename to contrib/go/_std_1.23/src/crypto/rsa/notboring.go diff --git a/contrib/go/_std_1.22/src/crypto/rsa/pkcs1v15.go b/contrib/go/_std_1.23/src/crypto/rsa/pkcs1v15.go similarity index 91% rename from contrib/go/_std_1.22/src/crypto/rsa/pkcs1v15.go rename to contrib/go/_std_1.23/src/crypto/rsa/pkcs1v15.go index 2705036fddf4..2f958022f985 100644 --- a/contrib/go/_std_1.22/src/crypto/rsa/pkcs1v15.go +++ b/contrib/go/_std_1.23/src/crypto/rsa/pkcs1v15.go @@ -5,6 +5,7 @@ package rsa import ( + "bytes" "crypto" "crypto/internal/boring" "crypto/internal/randutil" @@ -285,17 +286,13 @@ var hashPrefixes = map[crypto.Hash][]byte{ // messages to signatures and identify the signed messages. As ever, // signatures provide authenticity, not confidentiality. func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) { - hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) + // pkcs1v15ConstructEM is called before boring.SignRSAPKCS1v15 to return + // consistent errors, including ErrMessageTooLong. + em, err := pkcs1v15ConstructEM(&priv.PublicKey, hash, hashed) if err != nil { return nil, err } - tLen := len(prefix) + hashLen - k := priv.Size() - if k < tLen+11 { - return nil, ErrMessageTooLong - } - if boring.Enabled { bkey, err := boringPrivateKey(priv) if err != nil { @@ -304,16 +301,37 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [ return boring.SignRSAPKCS1v15(bkey, hash, hashed) } + return decrypt(priv, em, withCheck) +} + +func pkcs1v15ConstructEM(pub *PublicKey, hash crypto.Hash, hashed []byte) ([]byte, error) { + // Special case: crypto.Hash(0) is used to indicate that the data is + // signed directly. + var prefix []byte + if hash != 0 { + if len(hashed) != hash.Size() { + return nil, errors.New("crypto/rsa: input must be hashed message") + } + var ok bool + prefix, ok = hashPrefixes[hash] + if !ok { + return nil, errors.New("crypto/rsa: unsupported hash function") + } + } + // EM = 0x00 || 0x01 || PS || 0x00 || T + k := pub.Size() + if k < len(prefix)+len(hashed)+2+8+1 { + return nil, ErrMessageTooLong + } em := make([]byte, k) em[1] = 1 - for i := 2; i < k-tLen-1; i++ { + for i := 2; i < k-len(prefix)-len(hashed)-1; i++ { em[i] = 0xff } - copy(em[k-tLen:k-hashLen], prefix) - copy(em[k-hashLen:k], hashed) - - return decrypt(priv, em, withCheck) + copy(em[k-len(prefix)-len(hashed):], prefix) + copy(em[k-len(hashed):], hashed) + return em, nil } // VerifyPKCS1v15 verifies an RSA PKCS #1 v1.5 signature. @@ -321,6 +339,9 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [ // function and sig is the signature. A valid signature is indicated by // returning a nil error. If hash is zero then hashed is used directly. This // isn't advisable except for interoperability. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error { if boring.Enabled { bkey, err := boringPublicKey(pub) @@ -333,21 +354,10 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) return nil } - hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) - if err != nil { - return err - } - - tLen := len(prefix) + hashLen - k := pub.Size() - if k < tLen+11 { - return ErrVerification - } - // RFC 8017 Section 8.2.2: If the length of the signature S is not k // octets (where k is the length in octets of the RSA modulus n), output // "invalid signature" and stop. - if k != len(sig) { + if pub.Size() != len(sig) { return ErrVerification } @@ -355,39 +365,14 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) if err != nil { return ErrVerification } - // EM = 0x00 || 0x01 || PS || 0x00 || T - - ok := subtle.ConstantTimeByteEq(em[0], 0) - ok &= subtle.ConstantTimeByteEq(em[1], 1) - ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed) - ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix) - ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0) - for i := 2; i < k-tLen-1; i++ { - ok &= subtle.ConstantTimeByteEq(em[i], 0xff) + expected, err := pkcs1v15ConstructEM(pub, hash, hashed) + if err != nil { + return ErrVerification } - - if ok != 1 { + if !bytes.Equal(em, expected) { return ErrVerification } return nil } - -func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) { - // Special case: crypto.Hash(0) is used to indicate that the data is - // signed directly. - if hash == 0 { - return inLen, nil, nil - } - - hashLen = hash.Size() - if inLen != hashLen { - return 0, nil, errors.New("crypto/rsa: input must be hashed message") - } - prefix, ok := hashPrefixes[hash] - if !ok { - return 0, nil, errors.New("crypto/rsa: unsupported hash function") - } - return -} diff --git a/contrib/go/_std_1.22/src/crypto/rsa/pss.go b/contrib/go/_std_1.23/src/crypto/rsa/pss.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/rsa/pss.go rename to contrib/go/_std_1.23/src/crypto/rsa/pss.go index b63b6eb01db6..e996e7aaa36b 100644 --- a/contrib/go/_std_1.22/src/crypto/rsa/pss.go +++ b/contrib/go/_std_1.23/src/crypto/rsa/pss.go @@ -338,6 +338,9 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, // result of hashing the input message using the given hash function. The opts // argument may be nil, in which case sensible defaults are used. opts.Hash is // ignored. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts *PSSOptions) error { if boring.Enabled { bkey, err := boringPublicKey(pub) diff --git a/contrib/go/_std_1.23/src/crypto/rsa/rsa.go b/contrib/go/_std_1.23/src/crypto/rsa/rsa.go new file mode 100644 index 000000000000..4d78d1eaaa6b --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/rsa/rsa.go @@ -0,0 +1,780 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package rsa implements RSA encryption as specified in PKCS #1 and RFC 8017. +// +// RSA is a single, fundamental operation that is used in this package to +// implement either public-key encryption or public-key signatures. +// +// The original specification for encryption and signatures with RSA is PKCS #1 +// and the terms "RSA encryption" and "RSA signatures" by default refer to +// PKCS #1 version 1.5. However, that specification has flaws and new designs +// should use version 2, usually called by just OAEP and PSS, where +// possible. +// +// Two sets of interfaces are included in this package. When a more abstract +// interface isn't necessary, there are functions for encrypting/decrypting +// with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract +// over the public key primitive, the PrivateKey type implements the +// Decrypter and Signer interfaces from the crypto package. +// +// Operations involving private keys are implemented using constant-time +// algorithms, except for [GenerateKey], [PrivateKey.Precompute], and +// [PrivateKey.Validate]. +package rsa + +import ( + "crypto" + "crypto/internal/bigmod" + "crypto/internal/boring" + "crypto/internal/boring/bbig" + "crypto/internal/randutil" + "crypto/rand" + "crypto/subtle" + "errors" + "hash" + "io" + "math" + "math/big" +) + +var bigOne = big.NewInt(1) + +// A PublicKey represents the public part of an RSA key. +// +// The value of the modulus N is considered secret by this library and protected +// from leaking through timing side-channels. However, neither the value of the +// exponent E nor the precise bit size of N are similarly protected. +type PublicKey struct { + N *big.Int // modulus + E int // public exponent +} + +// Any methods implemented on PublicKey might need to also be implemented on +// PrivateKey, as the latter embeds the former and will expose its methods. + +// Size returns the modulus size in bytes. Raw signatures and ciphertexts +// for or by this public key will have the same size. +func (pub *PublicKey) Size() int { + return (pub.N.BitLen() + 7) / 8 +} + +// Equal reports whether pub and x have the same value. +func (pub *PublicKey) Equal(x crypto.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + return bigIntEqual(pub.N, xx.N) && pub.E == xx.E +} + +// OAEPOptions is an interface for passing options to OAEP decryption using the +// crypto.Decrypter interface. +type OAEPOptions struct { + // Hash is the hash function that will be used when generating the mask. + Hash crypto.Hash + + // MGFHash is the hash function used for MGF1. + // If zero, Hash is used instead. + MGFHash crypto.Hash + + // Label is an arbitrary byte string that must be equal to the value + // used when encrypting. + Label []byte +} + +var ( + errPublicModulus = errors.New("crypto/rsa: missing public modulus") + errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small") + errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large") +) + +// checkPub sanity checks the public key before we use it. +// We require pub.E to fit into a 32-bit integer so that we +// do not have different behavior depending on whether +// int is 32 or 64 bits. See also +// https://www.imperialviolet.org/2012/03/16/rsae.html. +func checkPub(pub *PublicKey) error { + if pub.N == nil { + return errPublicModulus + } + if pub.E < 2 { + return errPublicExponentSmall + } + if pub.E > 1<<31-1 { + return errPublicExponentLarge + } + return nil +} + +// A PrivateKey represents an RSA key +type PrivateKey struct { + PublicKey // public part. + D *big.Int // private exponent + Primes []*big.Int // prime factors of N, has >= 2 elements. + + // Precomputed contains precomputed values that speed up RSA operations, + // if available. It must be generated by calling PrivateKey.Precompute and + // must not be modified. + Precomputed PrecomputedValues +} + +// Public returns the public key corresponding to priv. +func (priv *PrivateKey) Public() crypto.PublicKey { + return &priv.PublicKey +} + +// Equal reports whether priv and x have equivalent values. It ignores +// Precomputed values. +func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool { + xx, ok := x.(*PrivateKey) + if !ok { + return false + } + if !priv.PublicKey.Equal(&xx.PublicKey) || !bigIntEqual(priv.D, xx.D) { + return false + } + if len(priv.Primes) != len(xx.Primes) { + return false + } + for i := range priv.Primes { + if !bigIntEqual(priv.Primes[i], xx.Primes[i]) { + return false + } + } + return true +} + +// bigIntEqual reports whether a and b are equal leaking only their bit length +// through timing side-channels. +func bigIntEqual(a, b *big.Int) bool { + return subtle.ConstantTimeCompare(a.Bytes(), b.Bytes()) == 1 +} + +// Sign signs digest with priv, reading randomness from rand. If opts is a +// *[PSSOptions] then the PSS algorithm will be used, otherwise PKCS #1 v1.5 will +// be used. digest must be the result of hashing the input message using +// opts.HashFunc(). +// +// This method implements [crypto.Signer], which is an interface to support keys +// where the private part is kept in, for example, a hardware module. Common +// uses should use the Sign* functions in this package directly. +func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { + if pssOpts, ok := opts.(*PSSOptions); ok { + return SignPSS(rand, priv, pssOpts.Hash, digest, pssOpts) + } + + return SignPKCS1v15(rand, priv, opts.HashFunc(), digest) +} + +// Decrypt decrypts ciphertext with priv. If opts is nil or of type +// *[PKCS1v15DecryptOptions] then PKCS #1 v1.5 decryption is performed. Otherwise +// opts must have type *[OAEPOptions] and OAEP decryption is done. +func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) { + if opts == nil { + return DecryptPKCS1v15(rand, priv, ciphertext) + } + + switch opts := opts.(type) { + case *OAEPOptions: + if opts.MGFHash == 0 { + return decryptOAEP(opts.Hash.New(), opts.Hash.New(), rand, priv, ciphertext, opts.Label) + } else { + return decryptOAEP(opts.Hash.New(), opts.MGFHash.New(), rand, priv, ciphertext, opts.Label) + } + + case *PKCS1v15DecryptOptions: + if l := opts.SessionKeyLen; l > 0 { + plaintext = make([]byte, l) + if _, err := io.ReadFull(rand, plaintext); err != nil { + return nil, err + } + if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil { + return nil, err + } + return plaintext, nil + } else { + return DecryptPKCS1v15(rand, priv, ciphertext) + } + + default: + return nil, errors.New("crypto/rsa: invalid options for Decrypt") + } +} + +type PrecomputedValues struct { + Dp, Dq *big.Int // D mod (P-1) (or mod Q-1) + Qinv *big.Int // Q^-1 mod P + + // CRTValues is used for the 3rd and subsequent primes. Due to a + // historical accident, the CRT for the first two primes is handled + // differently in PKCS #1 and interoperability is sufficiently + // important that we mirror this. + // + // Deprecated: These values are still filled in by Precompute for + // backwards compatibility but are not used. Multi-prime RSA is very rare, + // and is implemented by this package without CRT optimizations to limit + // complexity. + CRTValues []CRTValue + + n, p, q *bigmod.Modulus // moduli for CRT with Montgomery precomputed constants +} + +// CRTValue contains the precomputed Chinese remainder theorem values. +type CRTValue struct { + Exp *big.Int // D mod (prime-1). + Coeff *big.Int // R·Coeff ≡ 1 mod Prime. + R *big.Int // product of primes prior to this (inc p and q). +} + +// Validate performs basic sanity checks on the key. +// It returns nil if the key is valid, or else an error describing a problem. +func (priv *PrivateKey) Validate() error { + if err := checkPub(&priv.PublicKey); err != nil { + return err + } + + // Check that Πprimes == n. + modulus := new(big.Int).Set(bigOne) + for _, prime := range priv.Primes { + // Any primes ≤ 1 will cause divide-by-zero panics later. + if prime.Cmp(bigOne) <= 0 { + return errors.New("crypto/rsa: invalid prime value") + } + modulus.Mul(modulus, prime) + } + if modulus.Cmp(priv.N) != 0 { + return errors.New("crypto/rsa: invalid modulus") + } + + // Check that de ≡ 1 mod p-1, for each prime. + // This implies that e is coprime to each p-1 as e has a multiplicative + // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) = + // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 + // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required. + congruence := new(big.Int) + de := new(big.Int).SetInt64(int64(priv.E)) + de.Mul(de, priv.D) + for _, prime := range priv.Primes { + pminus1 := new(big.Int).Sub(prime, bigOne) + congruence.Mod(de, pminus1) + if congruence.Cmp(bigOne) != 0 { + return errors.New("crypto/rsa: invalid exponents") + } + } + return nil +} + +// GenerateKey generates a random RSA private key of the given bit size. +// +// Most applications should use [crypto/rand.Reader] as rand. Note that the +// returned key does not depend deterministically on the bytes read from rand, +// and may change between calls and/or between versions. +func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) { + return GenerateMultiPrimeKey(random, 2, bits) +} + +// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit +// size and the given random source. +// +// Table 1 in "[On the Security of Multi-prime RSA]" suggests maximum numbers of +// primes for a given bit size. +// +// Although the public keys are compatible (actually, indistinguishable) from +// the 2-prime case, the private keys are not. Thus it may not be possible to +// export multi-prime private keys in certain formats or to subsequently import +// them into other code. +// +// This package does not implement CRT optimizations for multi-prime RSA, so the +// keys with more than two primes will have worse performance. +// +// Deprecated: The use of this function with a number of primes different from +// two is not recommended for the above security, compatibility, and performance +// reasons. Use [GenerateKey] instead. +// +// [On the Security of Multi-prime RSA]: http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf +func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) { + randutil.MaybeReadByte(random) + + if boring.Enabled && random == boring.RandReader && nprimes == 2 && + (bits == 2048 || bits == 3072 || bits == 4096) { + bN, bE, bD, bP, bQ, bDp, bDq, bQinv, err := boring.GenerateKeyRSA(bits) + if err != nil { + return nil, err + } + N := bbig.Dec(bN) + E := bbig.Dec(bE) + D := bbig.Dec(bD) + P := bbig.Dec(bP) + Q := bbig.Dec(bQ) + Dp := bbig.Dec(bDp) + Dq := bbig.Dec(bDq) + Qinv := bbig.Dec(bQinv) + e64 := E.Int64() + if !E.IsInt64() || int64(int(e64)) != e64 { + return nil, errors.New("crypto/rsa: generated key exponent too large") + } + + mn, err := bigmod.NewModulusFromBig(N) + if err != nil { + return nil, err + } + mp, err := bigmod.NewModulusFromBig(P) + if err != nil { + return nil, err + } + mq, err := bigmod.NewModulusFromBig(Q) + if err != nil { + return nil, err + } + + key := &PrivateKey{ + PublicKey: PublicKey{ + N: N, + E: int(e64), + }, + D: D, + Primes: []*big.Int{P, Q}, + Precomputed: PrecomputedValues{ + Dp: Dp, + Dq: Dq, + Qinv: Qinv, + CRTValues: make([]CRTValue, 0), // non-nil, to match Precompute + n: mn, + p: mp, + q: mq, + }, + } + return key, nil + } + + priv := new(PrivateKey) + priv.E = 65537 + + if nprimes < 2 { + return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2") + } + + if bits < 64 { + primeLimit := float64(uint64(1) << uint(bits/nprimes)) + // pi approximates the number of primes less than primeLimit + pi := primeLimit / (math.Log(primeLimit) - 1) + // Generated primes start with 11 (in binary) so we can only + // use a quarter of them. + pi /= 4 + // Use a factor of two to ensure that key generation terminates + // in a reasonable amount of time. + pi /= 2 + if pi <= float64(nprimes) { + return nil, errors.New("crypto/rsa: too few primes of given length to generate an RSA key") + } + } + + primes := make([]*big.Int, nprimes) + +NextSetOfPrimes: + for { + todo := bits + // crypto/rand should set the top two bits in each prime. + // Thus each prime has the form + // p_i = 2^bitlen(p_i) × 0.11... (in base 2). + // And the product is: + // P = 2^todo × α + // where α is the product of nprimes numbers of the form 0.11... + // + // If α < 1/2 (which can happen for nprimes > 2), we need to + // shift todo to compensate for lost bits: the mean value of 0.11... + // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2 + // will give good results. + if nprimes >= 7 { + todo += (nprimes - 2) / 5 + } + for i := 0; i < nprimes; i++ { + var err error + primes[i], err = rand.Prime(random, todo/(nprimes-i)) + if err != nil { + return nil, err + } + todo -= primes[i].BitLen() + } + + // Make sure that primes is pairwise unequal. + for i, prime := range primes { + for j := 0; j < i; j++ { + if prime.Cmp(primes[j]) == 0 { + continue NextSetOfPrimes + } + } + } + + n := new(big.Int).Set(bigOne) + totient := new(big.Int).Set(bigOne) + pminus1 := new(big.Int) + for _, prime := range primes { + n.Mul(n, prime) + pminus1.Sub(prime, bigOne) + totient.Mul(totient, pminus1) + } + if n.BitLen() != bits { + // This should never happen for nprimes == 2 because + // crypto/rand should set the top two bits in each prime. + // For nprimes > 2 we hope it does not happen often. + continue NextSetOfPrimes + } + + priv.D = new(big.Int) + e := big.NewInt(int64(priv.E)) + ok := priv.D.ModInverse(e, totient) + + if ok != nil { + priv.Primes = primes + priv.N = n + break + } + } + + priv.Precompute() + return priv, nil +} + +// incCounter increments a four byte, big-endian counter. +func incCounter(c *[4]byte) { + if c[3]++; c[3] != 0 { + return + } + if c[2]++; c[2] != 0 { + return + } + if c[1]++; c[1] != 0 { + return + } + c[0]++ +} + +// mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function +// specified in PKCS #1 v2.1. +func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { + var counter [4]byte + var digest []byte + + done := 0 + for done < len(out) { + hash.Write(seed) + hash.Write(counter[0:4]) + digest = hash.Sum(digest[:0]) + hash.Reset() + + for i := 0; i < len(digest) && done < len(out); i++ { + out[done] ^= digest[i] + done++ + } + incCounter(&counter) + } +} + +// ErrMessageTooLong is returned when attempting to encrypt or sign a message +// which is too large for the size of the key. When using [SignPSS], this can also +// be returned if the size of the salt is too large. +var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA key size") + +func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) { + boring.Unreachable() + + N, err := bigmod.NewModulusFromBig(pub.N) + if err != nil { + return nil, err + } + m, err := bigmod.NewNat().SetBytes(plaintext, N) + if err != nil { + return nil, err + } + e := uint(pub.E) + + return bigmod.NewNat().ExpShortVarTime(m, e, N).Bytes(N), nil +} + +// EncryptOAEP encrypts the given message with RSA-OAEP. +// +// OAEP is parameterised by a hash function that is used as a random oracle. +// Encryption and decryption of a given message must use the same hash function +// and sha256.New() is a reasonable choice. +// +// The random parameter is used as a source of entropy to ensure that +// encrypting the same message twice doesn't result in the same ciphertext. +// Most applications should use [crypto/rand.Reader] as random. +// +// The label parameter may contain arbitrary data that will not be encrypted, +// but which gives important context to the message. For example, if a given +// public key is used to encrypt two types of messages then distinct label +// values could be used to ensure that a ciphertext for one purpose cannot be +// used for another by an attacker. If not required it can be empty. +// +// The message must be no longer than the length of the public modulus minus +// twice the hash length, minus a further 2. +func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) { + // Note that while we don't commit to deterministic execution with respect + // to the random stream, we also don't apply MaybeReadByte, so per Hyrum's + // Law it's probably relied upon by some. It's a tolerable promise because a + // well-specified number of random bytes is included in the ciphertext, in a + // well-specified way. + + if err := checkPub(pub); err != nil { + return nil, err + } + hash.Reset() + k := pub.Size() + if len(msg) > k-2*hash.Size()-2 { + return nil, ErrMessageTooLong + } + + if boring.Enabled && random == boring.RandReader { + bkey, err := boringPublicKey(pub) + if err != nil { + return nil, err + } + return boring.EncryptRSAOAEP(hash, hash, bkey, msg, label) + } + boring.UnreachableExceptTests() + + hash.Write(label) + lHash := hash.Sum(nil) + hash.Reset() + + em := make([]byte, k) + seed := em[1 : 1+hash.Size()] + db := em[1+hash.Size():] + + copy(db[0:hash.Size()], lHash) + db[len(db)-len(msg)-1] = 1 + copy(db[len(db)-len(msg):], msg) + + _, err := io.ReadFull(random, seed) + if err != nil { + return nil, err + } + + mgf1XOR(db, hash, seed) + mgf1XOR(seed, hash, db) + + if boring.Enabled { + var bkey *boring.PublicKeyRSA + bkey, err = boringPublicKey(pub) + if err != nil { + return nil, err + } + return boring.EncryptRSANoPadding(bkey, em) + } + + return encrypt(pub, em) +} + +// ErrDecryption represents a failure to decrypt a message. +// It is deliberately vague to avoid adaptive attacks. +var ErrDecryption = errors.New("crypto/rsa: decryption error") + +// ErrVerification represents a failure to verify a signature. +// It is deliberately vague to avoid adaptive attacks. +var ErrVerification = errors.New("crypto/rsa: verification error") + +// Precompute performs some calculations that speed up private key operations +// in the future. +func (priv *PrivateKey) Precompute() { + if priv.Precomputed.n == nil && len(priv.Primes) == 2 { + // Precomputed values _should_ always be valid, but if they aren't + // just return. We could also panic. + var err error + priv.Precomputed.n, err = bigmod.NewModulusFromBig(priv.N) + if err != nil { + return + } + priv.Precomputed.p, err = bigmod.NewModulusFromBig(priv.Primes[0]) + if err != nil { + // Unset previous values, so we either have everything or nothing + priv.Precomputed.n = nil + return + } + priv.Precomputed.q, err = bigmod.NewModulusFromBig(priv.Primes[1]) + if err != nil { + // Unset previous values, so we either have everything or nothing + priv.Precomputed.n, priv.Precomputed.p = nil, nil + return + } + } + + // Fill in the backwards-compatibility *big.Int values. + if priv.Precomputed.Dp != nil { + return + } + + priv.Precomputed.Dp = new(big.Int).Sub(priv.Primes[0], bigOne) + priv.Precomputed.Dp.Mod(priv.D, priv.Precomputed.Dp) + + priv.Precomputed.Dq = new(big.Int).Sub(priv.Primes[1], bigOne) + priv.Precomputed.Dq.Mod(priv.D, priv.Precomputed.Dq) + + priv.Precomputed.Qinv = new(big.Int).ModInverse(priv.Primes[1], priv.Primes[0]) + + r := new(big.Int).Mul(priv.Primes[0], priv.Primes[1]) + priv.Precomputed.CRTValues = make([]CRTValue, len(priv.Primes)-2) + for i := 2; i < len(priv.Primes); i++ { + prime := priv.Primes[i] + values := &priv.Precomputed.CRTValues[i-2] + + values.Exp = new(big.Int).Sub(prime, bigOne) + values.Exp.Mod(priv.D, values.Exp) + + values.R = new(big.Int).Set(r) + values.Coeff = new(big.Int).ModInverse(r, prime) + + r.Mul(r, prime) + } +} + +const withCheck = true +const noCheck = false + +// decrypt performs an RSA decryption of ciphertext into out. If check is true, +// m^e is calculated and compared with ciphertext, in order to defend against +// errors in the CRT computation. +func decrypt(priv *PrivateKey, ciphertext []byte, check bool) ([]byte, error) { + if len(priv.Primes) <= 2 { + boring.Unreachable() + } + + var ( + err error + m, c *bigmod.Nat + N *bigmod.Modulus + t0 = bigmod.NewNat() + ) + if priv.Precomputed.n == nil { + N, err = bigmod.NewModulusFromBig(priv.N) + if err != nil { + return nil, ErrDecryption + } + c, err = bigmod.NewNat().SetBytes(ciphertext, N) + if err != nil { + return nil, ErrDecryption + } + m = bigmod.NewNat().Exp(c, priv.D.Bytes(), N) + } else { + N = priv.Precomputed.n + P, Q := priv.Precomputed.p, priv.Precomputed.q + Qinv, err := bigmod.NewNat().SetBytes(priv.Precomputed.Qinv.Bytes(), P) + if err != nil { + return nil, ErrDecryption + } + c, err = bigmod.NewNat().SetBytes(ciphertext, N) + if err != nil { + return nil, ErrDecryption + } + + // m = c ^ Dp mod p + m = bigmod.NewNat().Exp(t0.Mod(c, P), priv.Precomputed.Dp.Bytes(), P) + // m2 = c ^ Dq mod q + m2 := bigmod.NewNat().Exp(t0.Mod(c, Q), priv.Precomputed.Dq.Bytes(), Q) + // m = m - m2 mod p + m.Sub(t0.Mod(m2, P), P) + // m = m * Qinv mod p + m.Mul(Qinv, P) + // m = m * q mod N + m.ExpandFor(N).Mul(t0.Mod(Q.Nat(), N), N) + // m = m + m2 mod N + m.Add(m2.ExpandFor(N), N) + } + + if check { + c1 := bigmod.NewNat().ExpShortVarTime(m, uint(priv.E), N) + if c1.Equal(c) != 1 { + return nil, ErrDecryption + } + } + + return m.Bytes(N), nil +} + +// DecryptOAEP decrypts ciphertext using RSA-OAEP. +// +// OAEP is parameterised by a hash function that is used as a random oracle. +// Encryption and decryption of a given message must use the same hash function +// and sha256.New() is a reasonable choice. +// +// The random parameter is legacy and ignored, and it can be nil. +// +// The label parameter must match the value given when encrypting. See +// [EncryptOAEP] for details. +func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) { + return decryptOAEP(hash, hash, random, priv, ciphertext, label) +} + +func decryptOAEP(hash, mgfHash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) { + if err := checkPub(&priv.PublicKey); err != nil { + return nil, err + } + k := priv.Size() + if len(ciphertext) > k || + k < hash.Size()*2+2 { + return nil, ErrDecryption + } + + if boring.Enabled { + bkey, err := boringPrivateKey(priv) + if err != nil { + return nil, err + } + out, err := boring.DecryptRSAOAEP(hash, mgfHash, bkey, ciphertext, label) + if err != nil { + return nil, ErrDecryption + } + return out, nil + } + + em, err := decrypt(priv, ciphertext, noCheck) + if err != nil { + return nil, err + } + + hash.Write(label) + lHash := hash.Sum(nil) + hash.Reset() + + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) + + seed := em[1 : hash.Size()+1] + db := em[hash.Size()+1:] + + mgf1XOR(seed, mgfHash, db) + mgf1XOR(db, mgfHash, seed) + + lHash2 := db[0:hash.Size()] + + // We have to validate the plaintext in constant time in order to avoid + // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal + // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1 + // v2.0. In J. Kilian, editor, Advances in Cryptology. + lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2) + + // The remainder of the plaintext must be zero or more 0x00, followed + // by 0x01, followed by the message. + // lookingForIndex: 1 iff we are still looking for the 0x01 + // index: the offset of the first 0x01 byte + // invalid: 1 iff we saw a non-zero byte before the 0x01. + var lookingForIndex, index, invalid int + lookingForIndex = 1 + rest := db[hash.Size():] + + for i := 0; i < len(rest); i++ { + equals0 := subtle.ConstantTimeByteEq(rest[i], 0) + equals1 := subtle.ConstantTimeByteEq(rest[i], 1) + index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index) + lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex) + invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid) + } + + if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 { + return nil, ErrDecryption + } + + return rest[index+1:], nil +} diff --git a/contrib/go/_std_1.22/src/crypto/rsa/ya.make b/contrib/go/_std_1.23/src/crypto/rsa/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rsa/ya.make rename to contrib/go/_std_1.23/src/crypto/rsa/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1.go similarity index 85% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1.go index ac10fa15574f..c0742b9d83c5 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1.go @@ -11,9 +11,9 @@ package sha1 import ( "crypto" "crypto/internal/boring" - "encoding/binary" "errors" "hash" + "internal/byteorder" ) func init() { @@ -51,14 +51,14 @@ const ( func (d *digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) - b = binary.BigEndian.AppendUint32(b, d.h[0]) - b = binary.BigEndian.AppendUint32(b, d.h[1]) - b = binary.BigEndian.AppendUint32(b, d.h[2]) - b = binary.BigEndian.AppendUint32(b, d.h[3]) - b = binary.BigEndian.AppendUint32(b, d.h[4]) + b = byteorder.BeAppendUint32(b, d.h[0]) + b = byteorder.BeAppendUint32(b, d.h[1]) + b = byteorder.BeAppendUint32(b, d.h[2]) + b = byteorder.BeAppendUint32(b, d.h[3]) + b = byteorder.BeAppendUint32(b, d.h[4]) b = append(b, d.x[:d.nx]...) b = b[:len(b)+len(d.x)-d.nx] // already zero - b = binary.BigEndian.AppendUint64(b, d.len) + b = byteorder.BeAppendUint64(b, d.len) return b, nil } @@ -82,16 +82,11 @@ func (d *digest) UnmarshalBinary(b []byte) error { } func consumeUint64(b []byte) ([]byte, uint64) { - _ = b[7] - x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 - return b[8:], x + return b[8:], byteorder.BeUint64(b) } func consumeUint32(b []byte) ([]byte, uint32) { - _ = b[3] - x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 - return b[4:], x + return b[4:], byteorder.BeUint32(b) } func (d *digest) Reset() { @@ -167,7 +162,7 @@ func (d *digest) checkSum() [Size]byte { // Length in bits. len <<= 3 padlen := tmp[:t+8] - binary.BigEndian.PutUint64(padlen[t:], len) + byteorder.BePutUint64(padlen[t:], len) d.Write(padlen) if d.nx != 0 { @@ -176,11 +171,11 @@ func (d *digest) checkSum() [Size]byte { var digest [Size]byte - binary.BigEndian.PutUint32(digest[0:], d.h[0]) - binary.BigEndian.PutUint32(digest[4:], d.h[1]) - binary.BigEndian.PutUint32(digest[8:], d.h[2]) - binary.BigEndian.PutUint32(digest[12:], d.h[3]) - binary.BigEndian.PutUint32(digest[16:], d.h[4]) + byteorder.BePutUint32(digest[0:], d.h[0]) + byteorder.BePutUint32(digest[4:], d.h[1]) + byteorder.BePutUint32(digest[8:], d.h[2]) + byteorder.BePutUint32(digest[12:], d.h[3]) + byteorder.BePutUint32(digest[16:], d.h[4]) return digest } diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block.go diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_386.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_386.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_386.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_386.s index 34d023d424c0..33d3f1e9973f 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_386.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_386.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // SHA-1 block routine. See sha1block.go for Go equivalent. diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.go index 039813d7dc3f..92fa7a6fbc0d 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha1 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.s index 9bdf24cf49f2..6508612d8900 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.s @@ -10,6 +10,7 @@ // Ronen Zohar // Chandramouli Narayanan +//go:build !purego #include "textflag.h" diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm.s index 2236533ab4d9..209b1d89ae34 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm.s @@ -4,6 +4,8 @@ // // ARM version of md5block.go +//go:build !purego + #include "textflag.h" // SHA-1 block routine. See sha1block.go for Go equivalent. diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.go similarity index 95% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.go index 08d3df0000e6..e6d96a9080a8 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha1 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.s index d56838464ddb..d0ff0986b8b5 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" #define HASHUPDATECHOOSE \ diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_decl.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_decl.go similarity index 83% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_decl.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_decl.go index 8e20401c14c4..3edf5a43606d 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_decl.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build arm || 386 || s390x +//go:build (arm || 386 || s390x) && !purego package sha1 diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_generic.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_generic.go similarity index 78% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_generic.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_generic.go index ba35155d0b92..4c6f74d99d8f 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_generic.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !386 && !arm && !s390x && !arm64 +//go:build (!amd64 && !386 && !arm && !s390x && !arm64) || purego package sha1 diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.go similarity index 91% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.go index 446bf5d36e59..f8b0d8ba3100 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha1 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.s similarity index 96% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.s index 0fb7aef28371..7a2f4e39c401 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func block(dig *digest, p []byte) diff --git a/contrib/go/_std_1.23/src/crypto/sha1/ya.make b/contrib/go/_std_1.23/src/crypto/sha1/ya.make new file mode 100644 index 000000000000..0991b4bbfc69 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/sha1/ya.make @@ -0,0 +1,24 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sha1.go + sha1block.go + sha1block_arm64.go + sha1block_arm64.s + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sha1.go + sha1block.go + sha1block_amd64.go + sha1block_amd64.s + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sha1.go + sha1block.go + sha1block_arm.s + sha1block_decl.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256.go similarity index 81% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256.go index 0cc7fca0a606..68244fd63b0c 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256.go @@ -9,9 +9,9 @@ package sha256 import ( "crypto" "crypto/internal/boring" - "encoding/binary" "errors" "hash" + "internal/byteorder" ) func init() { @@ -70,17 +70,17 @@ func (d *digest) MarshalBinary() ([]byte, error) { } else { b = append(b, magic256...) } - b = binary.BigEndian.AppendUint32(b, d.h[0]) - b = binary.BigEndian.AppendUint32(b, d.h[1]) - b = binary.BigEndian.AppendUint32(b, d.h[2]) - b = binary.BigEndian.AppendUint32(b, d.h[3]) - b = binary.BigEndian.AppendUint32(b, d.h[4]) - b = binary.BigEndian.AppendUint32(b, d.h[5]) - b = binary.BigEndian.AppendUint32(b, d.h[6]) - b = binary.BigEndian.AppendUint32(b, d.h[7]) + b = byteorder.BeAppendUint32(b, d.h[0]) + b = byteorder.BeAppendUint32(b, d.h[1]) + b = byteorder.BeAppendUint32(b, d.h[2]) + b = byteorder.BeAppendUint32(b, d.h[3]) + b = byteorder.BeAppendUint32(b, d.h[4]) + b = byteorder.BeAppendUint32(b, d.h[5]) + b = byteorder.BeAppendUint32(b, d.h[6]) + b = byteorder.BeAppendUint32(b, d.h[7]) b = append(b, d.x[:d.nx]...) b = b[:len(b)+len(d.x)-d.nx] // already zero - b = binary.BigEndian.AppendUint64(b, d.len) + b = byteorder.BeAppendUint64(b, d.len) return b, nil } @@ -107,16 +107,11 @@ func (d *digest) UnmarshalBinary(b []byte) error { } func consumeUint64(b []byte) ([]byte, uint64) { - _ = b[7] - x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 - return b[8:], x + return b[8:], byteorder.BeUint64(b) } func consumeUint32(b []byte) ([]byte, uint32) { - _ = b[3] - x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 - return b[4:], x + return b[4:], byteorder.BeUint32(b) } func (d *digest) Reset() { @@ -226,7 +221,7 @@ func (d *digest) checkSum() [Size]byte { // Length in bits. len <<= 3 padlen := tmp[:t+8] - binary.BigEndian.PutUint64(padlen[t+0:], len) + byteorder.BePutUint64(padlen[t+0:], len) d.Write(padlen) if d.nx != 0 { @@ -235,15 +230,15 @@ func (d *digest) checkSum() [Size]byte { var digest [Size]byte - binary.BigEndian.PutUint32(digest[0:], d.h[0]) - binary.BigEndian.PutUint32(digest[4:], d.h[1]) - binary.BigEndian.PutUint32(digest[8:], d.h[2]) - binary.BigEndian.PutUint32(digest[12:], d.h[3]) - binary.BigEndian.PutUint32(digest[16:], d.h[4]) - binary.BigEndian.PutUint32(digest[20:], d.h[5]) - binary.BigEndian.PutUint32(digest[24:], d.h[6]) + byteorder.BePutUint32(digest[0:], d.h[0]) + byteorder.BePutUint32(digest[4:], d.h[1]) + byteorder.BePutUint32(digest[8:], d.h[2]) + byteorder.BePutUint32(digest[12:], d.h[3]) + byteorder.BePutUint32(digest[16:], d.h[4]) + byteorder.BePutUint32(digest[20:], d.h[5]) + byteorder.BePutUint32(digest[24:], d.h[6]) if !d.is224 { - binary.BigEndian.PutUint32(digest[28:], d.h[7]) + byteorder.BePutUint32(digest[28:], d.h[7]) } return digest diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block.go diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_386.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_386.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_386.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_386.s index 086a0ab25c88..0e27fa02d7e7 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_386.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_386.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // SHA256 block routine. See sha256block.go for Go equivalent. // // The algorithm is detailed in FIPS 180-4: diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.go similarity index 93% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.go index b5d2c9b574a2..fdd75a3f3e7e 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha256 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.s index bbde6285d178..2559f659a200 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // SHA256 block routine. See sha256block.go for Go equivalent. diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.go similarity index 95% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.go index e5da56636315..434b6f253d41 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha256 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.s index d5c1eb0b2e15..6757310c34e3 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" #define HASHUPDATE \ diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_decl.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_decl.go similarity index 77% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_decl.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_decl.go index 7d68cd95fe44..85374cbdbb59 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_decl.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build 386 || amd64 || s390x || ppc64le || ppc64 +//go:build (386 || amd64 || s390x || ppc64le || ppc64) && !purego package sha256 diff --git a/contrib/go/_std_1.23/src/crypto/sha256/sha256block_generic.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_generic.go new file mode 100644 index 000000000000..2964255f99cc --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_generic.go @@ -0,0 +1,11 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (!amd64 && !386 && !s390x && !ppc64le && !ppc64 && !arm64) || purego + +package sha256 + +func block(dig *digest, p []byte) { + blockGeneric(dig, p) +} diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_ppc64x.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_ppc64x.s index b229ef619a35..ba8fa623c11f 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_ppc64x.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego // Based on CRYPTOGAMS code with the following comment: // # ==================================================================== diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.go index 1a376c5f9353..0a1dc5785d2e 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha256 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.s similarity index 96% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.s index 9c30136b31ef..757d62f5125a 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func block(dig *digest, p []byte) diff --git a/contrib/go/_std_1.23/src/crypto/sha256/ya.make b/contrib/go/_std_1.23/src/crypto/sha256/ya.make new file mode 100644 index 000000000000..bb2b710f3925 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/sha256/ya.make @@ -0,0 +1,24 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sha256.go + sha256block.go + sha256block_arm64.go + sha256block_arm64.s + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sha256.go + sha256block.go + sha256block_amd64.go + sha256block_amd64.s + sha256block_decl.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sha256.go + sha256block.go + sha256block_generic.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512.go similarity index 88% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512.go index 9ae1b3aae2f0..dde83625f7b8 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512.go @@ -13,9 +13,9 @@ package sha512 import ( "crypto" "crypto/internal/boring" - "encoding/binary" "errors" "hash" + "internal/byteorder" ) func init() { @@ -153,17 +153,17 @@ func (d *digest) MarshalBinary() ([]byte, error) { default: return nil, errors.New("crypto/sha512: invalid hash function") } - b = binary.BigEndian.AppendUint64(b, d.h[0]) - b = binary.BigEndian.AppendUint64(b, d.h[1]) - b = binary.BigEndian.AppendUint64(b, d.h[2]) - b = binary.BigEndian.AppendUint64(b, d.h[3]) - b = binary.BigEndian.AppendUint64(b, d.h[4]) - b = binary.BigEndian.AppendUint64(b, d.h[5]) - b = binary.BigEndian.AppendUint64(b, d.h[6]) - b = binary.BigEndian.AppendUint64(b, d.h[7]) + b = byteorder.BeAppendUint64(b, d.h[0]) + b = byteorder.BeAppendUint64(b, d.h[1]) + b = byteorder.BeAppendUint64(b, d.h[2]) + b = byteorder.BeAppendUint64(b, d.h[3]) + b = byteorder.BeAppendUint64(b, d.h[4]) + b = byteorder.BeAppendUint64(b, d.h[5]) + b = byteorder.BeAppendUint64(b, d.h[6]) + b = byteorder.BeAppendUint64(b, d.h[7]) b = append(b, d.x[:d.nx]...) b = b[:len(b)+len(d.x)-d.nx] // already zero - b = binary.BigEndian.AppendUint64(b, d.len) + b = byteorder.BeAppendUint64(b, d.len) return b, nil } @@ -198,10 +198,7 @@ func (d *digest) UnmarshalBinary(b []byte) error { } func consumeUint64(b []byte) ([]byte, uint64) { - _ = b[7] - x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 - return b[8:], x + return b[8:], byteorder.BeUint64(b) } // New returns a new hash.Hash computing the SHA-512 checksum. @@ -316,8 +313,8 @@ func (d *digest) checkSum() [Size]byte { padlen := tmp[:t+16] // Upper 64 bits are always zero, because len variable has type uint64, // and tmp is already zeroed at that index, so we can skip updating it. - // binary.BigEndian.PutUint64(padlen[t+0:], 0) - binary.BigEndian.PutUint64(padlen[t+8:], len) + // byteorder.BePutUint64(padlen[t+0:], 0) + byteorder.BePutUint64(padlen[t+8:], len) d.Write(padlen) if d.nx != 0 { @@ -325,15 +322,15 @@ func (d *digest) checkSum() [Size]byte { } var digest [Size]byte - binary.BigEndian.PutUint64(digest[0:], d.h[0]) - binary.BigEndian.PutUint64(digest[8:], d.h[1]) - binary.BigEndian.PutUint64(digest[16:], d.h[2]) - binary.BigEndian.PutUint64(digest[24:], d.h[3]) - binary.BigEndian.PutUint64(digest[32:], d.h[4]) - binary.BigEndian.PutUint64(digest[40:], d.h[5]) + byteorder.BePutUint64(digest[0:], d.h[0]) + byteorder.BePutUint64(digest[8:], d.h[1]) + byteorder.BePutUint64(digest[16:], d.h[2]) + byteorder.BePutUint64(digest[24:], d.h[3]) + byteorder.BePutUint64(digest[32:], d.h[4]) + byteorder.BePutUint64(digest[40:], d.h[5]) if d.function != crypto.SHA384 { - binary.BigEndian.PutUint64(digest[48:], d.h[6]) - binary.BigEndian.PutUint64(digest[56:], d.h[7]) + byteorder.BePutUint64(digest[48:], d.h[6]) + byteorder.BePutUint64(digest[56:], d.h[7]) } return digest diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block.go diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.go index 8da3e1473f6c..fd1baecb32d8 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 +//go:build !purego package sha512 diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.s rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.s index 0fa0df2f60e8..bd4e3e6669f8 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // SHA512 block routine. See sha512block.go for Go equivalent. diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.go similarity index 94% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.go index 243eb5c1d63b..4e2793100a31 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha512 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.s rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.s index dfc35d69c388..25f3dbfe43d5 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // Based on the Linux Kernel with the following comment: // Algorithm based on https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fb87127bcefc17efab757606e1b1e333fd614dd0 // Originally written by Ard Biesheuvel diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_decl.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_decl.go similarity index 78% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_decl.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_decl.go index 4ad4418bc071..324659e62ca2 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_decl.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build s390x || ppc64le || ppc64 +//go:build (ppc64le || ppc64 || riscv64 || s390x) && !purego package sha512 diff --git a/contrib/go/_std_1.23/src/crypto/sha512/sha512block_generic.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_generic.go new file mode 100644 index 000000000000..9177722be12b --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_generic.go @@ -0,0 +1,11 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (!amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64 && !s390x) || purego + +package sha512 + +func block(dig *digest, p []byte) { + blockGeneric(dig, p) +} diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_ppc64x.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_ppc64x.s index 90dbf0f02b64..87aab80903c9 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_ppc64x.s @@ -10,7 +10,7 @@ // # details see http://www.openssl.org/~appro/cryptogams/. // # ==================================================================== -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego #include "textflag.h" diff --git a/contrib/go/_std_1.23/src/crypto/sha512/sha512block_riscv64.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_riscv64.s new file mode 100644 index 000000000000..7dcb0f80d0ab --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_riscv64.s @@ -0,0 +1,288 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego + +#include "textflag.h" + +// SHA512 block routine. See sha512block.go for Go equivalent. +// +// The algorithm is detailed in FIPS 180-4: +// +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// +// Wt = Mt; for 0 <= t <= 15 +// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 +// +// a = H0 +// b = H1 +// c = H2 +// d = H3 +// e = H4 +// f = H5 +// g = H6 +// h = H7 +// +// for t = 0 to 79 { +// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt +// T2 = BIGSIGMA0(a) + Maj(a,b,c) +// h = g +// g = f +// f = e +// e = d + T1 +// d = c +// c = b +// b = a +// a = T1 + T2 +// } +// +// H0 = a + H0 +// H1 = b + H1 +// H2 = c + H2 +// H3 = d + H3 +// H4 = e + H4 +// H5 = f + H5 +// H6 = g + H6 +// H7 = h + H7 + +// Wt = Mt; for 0 <= t <= 15 +#define MSGSCHEDULE0(index) \ + MOVBU ((index*8)+0)(X29), X5; \ + MOVBU ((index*8)+1)(X29), X6; \ + MOVBU ((index*8)+2)(X29), X7; \ + MOVBU ((index*8)+3)(X29), X8; \ + SLL $56, X5; \ + SLL $48, X6; \ + OR X5, X6, X5; \ + SLL $40, X7; \ + OR X5, X7, X5; \ + SLL $32, X8; \ + OR X5, X8, X5; \ + MOVBU ((index*8)+4)(X29), X9; \ + MOVBU ((index*8)+5)(X29), X6; \ + MOVBU ((index*8)+6)(X29), X7; \ + MOVBU ((index*8)+7)(X29), X8; \ + SLL $24, X9; \ + OR X5, X9, X5; \ + SLL $16, X6; \ + OR X5, X6, X5; \ + SLL $8, X7; \ + OR X5, X7, X5; \ + OR X5, X8, X5; \ + MOV X5, (index*8)(X19) + +// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 +// SIGMA0(x) = ROTR(1,x) XOR ROTR(8,x) XOR SHR(7,x) +// SIGMA1(x) = ROTR(19,x) XOR ROTR(61,x) XOR SHR(6,x) +#define MSGSCHEDULE1(index) \ + MOV (((index-2)&0xf)*8)(X19), X5; \ + MOV (((index-15)&0xf)*8)(X19), X6; \ + MOV (((index-7)&0xf)*8)(X19), X9; \ + MOV (((index-16)&0xf)*8)(X19), X21; \ + ROR $19, X5, X7; \ + ROR $61, X5, X8; \ + SRL $6, X5; \ + XOR X7, X5; \ + XOR X8, X5; \ + ADD X9, X5; \ + ROR $1, X6, X7; \ + ROR $8, X6, X8; \ + SRL $7, X6; \ + XOR X7, X6; \ + XOR X8, X6; \ + ADD X6, X5; \ + ADD X21, X5; \ + MOV X5, ((index&0xf)*8)(X19) + +// Calculate T1 in X5. +// h is also used as an accumulator. Wt is passed in X5. +// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt +// BIGSIGMA1(x) = ROTR(14,x) XOR ROTR(18,x) XOR ROTR(41,x) +// Ch(x, y, z) = (x AND y) XOR (NOT x AND z) +#define SHA512T1(index, e, f, g, h) \ + MOV (index*8)(X18), X8; \ + ADD X5, h; \ + ROR $14, e, X6; \ + ADD X8, h; \ + ROR $18, e, X7; \ + XOR X7, X6; \ + ROR $41, e, X8; \ + XOR X8, X6; \ + ADD X6, h; \ + AND e, f, X5; \ + NOT e, X7; \ + AND g, X7; \ + XOR X7, X5; \ + ADD h, X5 + +// Calculate T2 in X6. +// T2 = BIGSIGMA0(a) + Maj(a, b, c) +// BIGSIGMA0(x) = ROTR(28,x) XOR ROTR(34,x) XOR ROTR(39,x) +// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z) +#define SHA512T2(a, b, c) \ + ROR $28, a, X6; \ + ROR $34, a, X7; \ + XOR X7, X6; \ + ROR $39, a, X8; \ + XOR X8, X6; \ + AND a, b, X7; \ + AND a, c, X8; \ + XOR X8, X7; \ + AND b, c, X9; \ + XOR X9, X7; \ + ADD X7, X6 + +// Calculate T1 and T2, then e = d + T1 and a = T1 + T2. +// The values for e and a are stored in d and h, ready for rotation. +#define SHA512ROUND(index, a, b, c, d, e, f, g, h) \ + SHA512T1(index, e, f, g, h); \ + SHA512T2(a, b, c); \ + MOV X6, h; \ + ADD X5, d; \ + ADD X5, h + +#define SHA512ROUND0(index, a, b, c, d, e, f, g, h) \ + MSGSCHEDULE0(index); \ + SHA512ROUND(index, a, b, c, d, e, f, g, h) + +#define SHA512ROUND1(index, a, b, c, d, e, f, g, h) \ + MSGSCHEDULE1(index); \ + SHA512ROUND(index, a, b, c, d, e, f, g, h) + +// func block(dig *digest, p []byte) +TEXT ·block(SB),0,$128-32 + MOV p_base+8(FP), X29 + MOV p_len+16(FP), X30 + SRL $7, X30 + SLL $7, X30 + + ADD X29, X30, X28 + BEQ X28, X29, end + + MOV ·_K(SB), X18 // const table + ADD $8, X2, X19 // message schedule + + MOV dig+0(FP), X20 + MOV (0*8)(X20), X10 // a = H0 + MOV (1*8)(X20), X11 // b = H1 + MOV (2*8)(X20), X12 // c = H2 + MOV (3*8)(X20), X13 // d = H3 + MOV (4*8)(X20), X14 // e = H4 + MOV (5*8)(X20), X15 // f = H5 + MOV (6*8)(X20), X16 // g = H6 + MOV (7*8)(X20), X17 // h = H7 + +loop: + SHA512ROUND0(0, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND0(1, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND0(2, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND0(3, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND0(4, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND0(5, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND0(6, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND0(7, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND0(8, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND0(9, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND0(10, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND0(11, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND0(12, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND0(13, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND0(14, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND0(15, X11, X12, X13, X14, X15, X16, X17, X10) + + SHA512ROUND1(16, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(17, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(18, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(19, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(20, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(21, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(22, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(23, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(24, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(25, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(26, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(27, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(28, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(29, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(30, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(31, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(32, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(33, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(34, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(35, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(36, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(37, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(38, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(39, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(40, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(41, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(42, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(43, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(44, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(45, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(46, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(47, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(48, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(49, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(50, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(51, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(52, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(53, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(54, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(55, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(56, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(57, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(58, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(59, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(60, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(61, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(62, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(63, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(64, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(65, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(66, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(67, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(68, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(69, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(70, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(71, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(72, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(73, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(74, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(75, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(76, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(77, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(78, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(79, X11, X12, X13, X14, X15, X16, X17, X10) + + MOV (0*8)(X20), X5 + MOV (1*8)(X20), X6 + MOV (2*8)(X20), X7 + MOV (3*8)(X20), X8 + ADD X5, X10 // H0 = a + H0 + ADD X6, X11 // H1 = b + H1 + ADD X7, X12 // H2 = c + H2 + ADD X8, X13 // H3 = d + H3 + MOV X10, (0*8)(X20) + MOV X11, (1*8)(X20) + MOV X12, (2*8)(X20) + MOV X13, (3*8)(X20) + MOV (4*8)(X20), X5 + MOV (5*8)(X20), X6 + MOV (6*8)(X20), X7 + MOV (7*8)(X20), X8 + ADD X5, X14 // H4 = e + H4 + ADD X6, X15 // H5 = f + H5 + ADD X7, X16 // H6 = g + H6 + ADD X8, X17 // H7 = h + H7 + MOV X14, (4*8)(X20) + MOV X15, (5*8)(X20) + MOV X16, (6*8)(X20) + MOV X17, (7*8)(X20) + + ADD $128, X29 + BNE X28, X29, loop + +end: + RET diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.go index 7df29fd29828..d0f09ea9edb0 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha512 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.s similarity index 96% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.s rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.s index 9fdf3439007a..230bd414d38b 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func block(dig *digest, p []byte) diff --git a/contrib/go/_std_1.23/src/crypto/sha512/ya.make b/contrib/go/_std_1.23/src/crypto/sha512/ya.make new file mode 100644 index 000000000000..e485c1cf2771 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/sha512/ya.make @@ -0,0 +1,23 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sha512.go + sha512block.go + sha512block_arm64.go + sha512block_arm64.s + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sha512.go + sha512block.go + sha512block_amd64.go + sha512block_amd64.s + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + sha512.go + sha512block.go + sha512block_generic.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/subtle/constant_time.go b/contrib/go/_std_1.23/src/crypto/subtle/constant_time.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/constant_time.go rename to contrib/go/_std_1.23/src/crypto/subtle/constant_time.go diff --git a/contrib/go/_std_1.23/src/crypto/subtle/xor.go b/contrib/go/_std_1.23/src/crypto/subtle/xor.go new file mode 100644 index 000000000000..158dbcede904 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/subtle/xor.go @@ -0,0 +1,21 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package subtle + +// XORBytes sets dst[i] = x[i] ^ y[i] for all i < n = min(len(x), len(y)), +// returning n, the number of bytes written to dst. +// If dst does not have length at least n, +// XORBytes panics without writing anything to dst. +func XORBytes(dst, x, y []byte) int { + n := min(len(x), len(y)) + if n == 0 { + return 0 + } + if n > len(dst) { + panic("subtle.XORBytes: dst too short") + } + xorBytes(&dst[0], &x[0], &y[0], n) // arch-specific + return n +} diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_amd64.go b/contrib/go/_std_1.23/src/crypto/subtle/xor_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_amd64.go rename to contrib/go/_std_1.23/src/crypto/subtle/xor_amd64.go diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_amd64.s b/contrib/go/_std_1.23/src/crypto/subtle/xor_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_amd64.s rename to contrib/go/_std_1.23/src/crypto/subtle/xor_amd64.s diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_arm64.go b/contrib/go/_std_1.23/src/crypto/subtle/xor_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_arm64.go rename to contrib/go/_std_1.23/src/crypto/subtle/xor_arm64.go diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_arm64.s b/contrib/go/_std_1.23/src/crypto/subtle/xor_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_arm64.s rename to contrib/go/_std_1.23/src/crypto/subtle/xor_arm64.s diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_generic.go b/contrib/go/_std_1.23/src/crypto/subtle/xor_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_generic.go rename to contrib/go/_std_1.23/src/crypto/subtle/xor_generic.go diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.go b/contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.go rename to contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.go diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.s b/contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.s index 0de4350cb237..c1f72c5ced78 100644 --- a/contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.s @@ -89,7 +89,7 @@ xor16: ADD $16, R8 ADD $-16, R6 small: - CMP R6, R0 + CMP R6, $0 BC 12,2,LR // BEQLR xor8: #ifdef GOPPC64_power10 @@ -131,7 +131,7 @@ xor2: ADD $2,R8 ADD $-2,R6 xor1: - CMP R6, R0 + CMP R6, $0 BC 12,2,LR // BEQLR MOVBZ (R4)(R8), R14 // R14 = a[i] MOVBZ (R5)(R8), R15 // R15 = b[i] diff --git a/contrib/go/_std_1.23/src/crypto/subtle/ya.make b/contrib/go/_std_1.23/src/crypto/subtle/ya.make new file mode 100644 index 000000000000..6d69af896d6d --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/subtle/ya.make @@ -0,0 +1,23 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + constant_time.go + xor.go + xor_arm64.go + xor_arm64.s + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + constant_time.go + xor.go + xor_amd64.go + xor_amd64.s + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + constant_time.go + xor.go + xor_generic.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/tls/alert.go b/contrib/go/_std_1.23/src/crypto/tls/alert.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/tls/alert.go rename to contrib/go/_std_1.23/src/crypto/tls/alert.go index 33022cd2b4bf..2301c0673d83 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/alert.go +++ b/contrib/go/_std_1.23/src/crypto/tls/alert.go @@ -58,6 +58,7 @@ const ( alertUnknownPSKIdentity alert = 115 alertCertificateRequired alert = 116 alertNoApplicationProtocol alert = 120 + alertECHRequired alert = 121 ) var alertText = map[alert]string{ @@ -94,6 +95,7 @@ var alertText = map[alert]string{ alertUnknownPSKIdentity: "unknown PSK identity", alertCertificateRequired: "certificate required", alertNoApplicationProtocol: "no application protocol", + alertECHRequired: "encrypted client hello required", } func (e alert) String() string { diff --git a/contrib/go/_std_1.22/src/crypto/tls/auth.go b/contrib/go/_std_1.23/src/crypto/tls/auth.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/tls/auth.go rename to contrib/go/_std_1.23/src/crypto/tls/auth.go index 7c5675c6d933..5bb202cd6aa9 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/auth.go +++ b/contrib/go/_std_1.23/src/crypto/tls/auth.go @@ -242,7 +242,7 @@ func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureSche // Pick signature scheme in the peer's preference order, as our // preference order is not configurable. for _, preferredAlg := range peerAlgs { - if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, fipsSupportedSignatureAlgorithms) { + if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, defaultSupportedSignatureAlgorithmsFIPS) { continue } if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) { diff --git a/contrib/go/_std_1.23/src/crypto/tls/bogo_config.json b/contrib/go/_std_1.23/src/crypto/tls/bogo_config.json new file mode 100644 index 000000000000..2363dd5d659a --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/bogo_config.json @@ -0,0 +1,233 @@ +{ + "DisabledTests": { + "*-Async": "We don't support boringssl concept of async", + + "TLS-ECH-Client-Reject-NoClientCertificate-TLS12": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-Reject-TLS12": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-TLS12-RejectRetryConfigs": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-Rejected-OverrideName-TLS12": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-Reject-TLS12-NoFalseStart": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-TLS12SessionTicket": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-TLS12SessionID": "We won't attempt to negotiate 1.2 if ECH is enabled", + + "TLS-ECH-Client-Reject-ResumeInnerSession-TLS12": "We won't attempt to negotiate 1.2 if ECH is enabled (we could possibly test this if we had the ability to indicate not to send ECH on resumption?)", + + "TLS-ECH-Client-Reject-EarlyDataRejected": "We don't support switiching out ECH configs with this level of granularity", + + "TLS-ECH-Client-NoNPN": "We don't support NPN", + + "TLS-ECH-Client-ChannelID": "We don't support sending channel ID", + "TLS-ECH-Client-Reject-NoChannelID-TLS13": "We don't support sending channel ID", + "TLS-ECH-Client-Reject-NoChannelID-TLS12": "We don't support sending channel ID", + + "TLS-ECH-Client-GREASE-IgnoreHRRExtension": "We don't support ECH GREASE because we don't fallback to plaintext", + "TLS-ECH-Client-NoSupportedConfigs-GREASE": "We don't support ECH GREASE because we don't fallback to plaintext", + "TLS-ECH-Client-GREASEExtensions": "We don't support ECH GREASE because we don't fallback to plaintext", + "TLS-ECH-Client-GREASE-NoOverrideName": "We don't support ECH GREASE because we don't fallback to plaintext", + + "TLS-ECH-Client-UnsolicitedInnerServerNameAck": "We don't allow sending empty SNI without skipping certificate verification, TODO: could add special flag to bogo to indicate 'empty sni'", + + "TLS-ECH-Client-NoSupportedConfigs": "We don't support fallback to cleartext when there are no valid ECH configs", + "TLS-ECH-Client-SkipInvalidPublicName": "We don't support fallback to cleartext when there are no valid ECH configs", + + + "*ECH-Server*": "no ECH server support", + "SendV2ClientHello*": "We don't support SSLv2", + "*QUIC*": "No QUIC support", + "Compliance-fips*": "No FIPS", + "*DTLS*": "No DTLS", + "SendEmptyRecords*": "crypto/tls doesn't implement spam protections", + "SendWarningAlerts*": "crypto/tls doesn't implement spam protections", + "TooManyKeyUpdates": "crypto/tls doesn't implement spam protections (TODO: I think?)", + "KyberNotEnabledByDefaultInClients": "crypto/tls intentionally enables it", + "JustConfiguringKyberWorks": "we always send a X25519 key share with Kyber", + "KyberKeyShareIncludedSecond": "we always send the Kyber key share first", + "KyberKeyShareIncludedThird": "we always send the Kyber key share first", + "SkipNewSessionTicket": "TODO confusing? maybe bug", + "SendUserCanceledAlerts*": "TODO may be a real bug?", + "GREASE-Server-TLS13": "TODO ???", + "GarbageCertificate*": "TODO ask davidben, alertDecode vs alertBadCertificate", + "SendBogusAlertType": "sending wrong alert type", + "EchoTLS13CompatibilitySessionID": "TODO reject compat session ID", + "*Client-P-224*": "no P-224 support", + "*Server-P-224*": "no P-224 support", + "CurveID-Resume*": "unexposed curveID is not stored in the ticket yet", + "CheckLeafCurve": "TODO: first pass, this should be fixed", + "DisabledCurve-HelloRetryRequest-TLS13": "TODO: first pass, this should be fixed", + "UnsupportedCurve": "TODO: first pass, this should be fixed", + "SupportTicketsWithSessionID": "TODO: first pass, this should be fixed", + "NoNullCompression-TLS12": "TODO: first pass, this should be fixed", + "KeyUpdate-RequestACK": "TODO: first pass, this should be fixed", + "TLS13-HRR-InvalidCompressionMethod": "TODO: first pass, this should be fixed", + "InvalidCompressionMethod": "TODO: first pass, this should be fixed", + "TLS-TLS12-RSA_WITH_AES_128_GCM_SHA256-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS1-RSA_WITH_AES_128_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS11-RSA_WITH_AES_128_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS12-RSA_WITH_AES_128_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS12-RSA_WITH_AES_256_GCM_SHA384-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS1-RSA_WITH_AES_256_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS11-RSA_WITH_AES_256_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS12-RSA_WITH_AES_256_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS12-ECDHE_RSA_WITH_AES_128_CBC_SHA256-LargeRecord": "TODO: first pass, this should be fixed", + "RequireAnyClientCertificate-TLS1": "TODO: first pass, this should be fixed", + "RequireAnyClientCertificate-TLS11": "TODO: first pass, this should be fixed", + "RequireAnyClientCertificate-TLS12": "TODO: first pass, this should be fixed", + "ClientHelloVersionTooHigh": "TODO: first pass, this should be fixed", + "MinorVersionTolerance": "TODO: first pass, this should be fixed", + "IgnoreClientVersionOrder": "TODO: first pass, this should be fixed", + "SupportedVersionSelection-TLS12": "TODO: first pass, this should be fixed", + "MajorVersionTolerance": "TODO: first pass, this should be fixed", + "DuplicateExtensionServer-TLS-TLS1": "TODO: first pass, this should be fixed", + "DuplicateExtensionClient-TLS-TLS1": "TODO: first pass, this should be fixed", + "UnsolicitedServerNameAck-TLS-TLS1": "TODO: first pass, this should be fixed", + "TicketSessionIDLength-33-TLS-TLS1": "TODO: first pass, this should be fixed", + "DuplicateExtensionServer-TLS-TLS11": "TODO: first pass, this should be fixed", + "DuplicateExtensionClient-TLS-TLS11": "TODO: first pass, this should be fixed", + "UnsolicitedServerNameAck-TLS-TLS11": "TODO: first pass, this should be fixed", + "TicketSessionIDLength-33-TLS-TLS11": "TODO: first pass, this should be fixed", + "DuplicateExtensionServer-TLS-TLS12": "TODO: first pass, this should be fixed", + "DuplicateExtensionClient-TLS-TLS12": "TODO: first pass, this should be fixed", + "UnsolicitedServerNameAck-TLS-TLS12": "TODO: first pass, this should be fixed", + "TicketSessionIDLength-33-TLS-TLS12": "TODO: first pass, this should be fixed", + "DuplicateExtensionClient-TLS-TLS13": "TODO: first pass, this should be fixed", + "DuplicateExtensionServer-TLS-TLS13": "TODO: first pass, this should be fixed", + "UnsolicitedServerNameAck-TLS-TLS13": "TODO: first pass, this should be fixed", + "RenegotiationInfo-Forbidden-TLS13": "TODO: first pass, this should be fixed", + "EMS-Forbidden-TLS13": "TODO: first pass, this should be fixed", + "SendUnsolicitedOCSPOnCertificate-TLS13": "TODO: first pass, this should be fixed", + "SendUnsolicitedSCTOnCertificate-TLS13": "TODO: first pass, this should be fixed", + "SendUnknownExtensionOnCertificate-TLS13": "TODO: first pass, this should be fixed", + "Resume-Server-NoTickets-TLS1-TLS1-TLS": "TODO: first pass, this should be fixed", + "Resume-Server-NoTickets-TLS11-TLS11-TLS": "TODO: first pass, this should be fixed", + "Resume-Server-NoTickets-TLS12-TLS12-TLS": "TODO: first pass, this should be fixed", + "Resume-Server-NoPSKBinder": "TODO: first pass, this should be fixed", + "Resume-Server-PSKBinderFirstExtension": "TODO: first pass, this should be fixed", + "Resume-Server-PSKBinderFirstExtension-SecondBinder": "TODO: first pass, this should be fixed", + "Resume-Server-NoPSKBinder-SecondBinder": "TODO: first pass, this should be fixed", + "Resume-Server-OmitPSKsOnSecondClientHello": "TODO: first pass, this should be fixed", + "Renegotiate-Server-Forbidden": "TODO: first pass, this should be fixed", + "Renegotiate-Client-Forbidden-1": "TODO: first pass, this should be fixed", + "Client-Sign-RSA_PKCS1_SHA1-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-RSA_PKCS1_SHA256-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-RSA_PKCS1_SHA384-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-RSA_PKCS1_SHA512-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-ECDSA_SHA1-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-ECDSA_P224_SHA256-TLS13": "TODO: first pass, this should be fixed", + "ClientAuth-NoFallback-TLS13": "TODO: first pass, this should be fixed", + "ClientAuth-NoFallback-ECDSA": "TODO: first pass, this should be fixed", + "ClientAuth-NoFallback-RSA": "TODO: first pass, this should be fixed", + "ECDSACurveMismatch-Verify-TLS13": "TODO: first pass, this should be fixed", + "Ed25519DefaultDisable-NoAdvertise": "TODO: first pass, this should be fixed", + "Ed25519DefaultDisable-NoAccept": "TODO: first pass, this should be fixed", + "NoCommonSignatureAlgorithms-TLS12-Fallback": "TODO: first pass, this should be fixed", + "UnknownExtension-Client": "TODO: first pass, this should be fixed", + "UnknownUnencryptedExtension-Client-TLS13": "TODO: first pass, this should be fixed", + "UnofferedExtension-Client-TLS13": "TODO: first pass, this should be fixed", + "UnknownExtension-Client-TLS13": "TODO: first pass, this should be fixed", + "SendClientVersion-RSA": "TODO: first pass, this should be fixed", + "NoCommonCurves": "TODO: first pass, this should be fixed", + "PointFormat-EncryptedExtensions-TLS13": "TODO: first pass, this should be fixed", + "PointFormat-Client-MissingUncompressed": "TODO: first pass, this should be fixed", + "TLS13-SendNoKEMModesWithPSK-Server": "TODO: first pass, this should be fixed", + "TLS13-DuplicateTicketEarlyDataSupport": "TODO: first pass, this should be fixed", + "Basic-Client-NoTicket-TLS-Sync": "TODO: first pass, this should be fixed", + "Basic-Server-RSA-TLS-Sync": "TODO: first pass, this should be fixed", + "Basic-Client-NoTicket-TLS-Sync-SplitHandshakeRecords": "TODO: first pass, this should be fixed", + "Basic-Server-RSA-TLS-Sync-SplitHandshakeRecords": "TODO: first pass, this should be fixed", + "Basic-Client-NoTicket-TLS-Sync-PackHandshake": "TODO: first pass, this should be fixed", + "Basic-Server-RSA-TLS-Sync-PackHandshake": "TODO: first pass, this should be fixed", + "PartialSecondClientHelloAfterFirst": "TODO: first pass, this should be fixed", + "PartialServerHelloWithHelloRetryRequest": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Server-TLS1": "TODO: first pass, this should be fixed", + "PartialClientKeyExchangeWithClientHello": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Server-TLS1": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Client-TLS11": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Client-TLS1": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Client-TLS11": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Client-TLS12": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Client-TLS13": "TODO: first pass, this should be fixed", + "PartialNewSessionTicketWithServerHelloDone": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Server-TLS11": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Server-TLS12": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Server-TLS11": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Client-TLS12": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Server-TLS12": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Client-TLS13": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Client-TLS1": "TODO: first pass, this should be fixed", + "TrailingMessageData-ClientHello-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerHello-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerCertificate-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerHelloDone-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerKeyExchange-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-CertificateRequest-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-CertificateVerify-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerFinished-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ClientKeyExchange-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ClientHello-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ClientFinished-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-NewSessionTicket-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ClientCertificate-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-CertificateRequest-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ServerCertificateVerify-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-EncryptedExtensions-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ClientCertificate-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ClientCertificateVerify-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ServerCertificate-TLS": "TODO: first pass, this should be fixed", + "ResumeTLS12SessionID-TLS13": "TODO: first pass, this should be fixed", + "SkipEarlyData-TLS13": "TODO: first pass, this should be fixed", + "DuplicateKeyShares-TLS13": "TODO: first pass, this should be fixed", + "Server-TooLongSessionID-TLS13": "TODO: first pass, this should be fixed", + "Client-TooLongSessionID": "TODO: first pass, this should be fixed", + "Client-ShortSessionID": "TODO: first pass, this should be fixed", + "TLS12NoSessionID-TLS13": "TODO: first pass, this should be fixed", + "Server-TooLongSessionID-TLS12": "TODO: first pass, this should be fixed", + "EmptyEncryptedExtensions-TLS13": "TODO: first pass, this should be fixed", + "SkipEarlyData-SecondClientHelloEarlyData-TLS13": "TODO: first pass, this should be fixed", + "EncryptedExtensionsWithKeyShare-TLS13": "TODO: first pass, this should be fixed", + "HelloRetryRequest-DuplicateCurve-TLS13": "TODO: first pass, this should be fixed", + "HelloRetryRequest-DuplicateCookie-TLS13": "TODO: first pass, this should be fixed", + "HelloRetryRequest-Unknown-TLS13": "TODO: first pass, this should be fixed", + "SendPostHandshakeChangeCipherSpec-TLS13": "TODO: first pass, this should be fixed", + "ECDSAKeyUsage-Server-TLS12": "TODO: first pass, this should be fixed", + "ECDSAKeyUsage-Server-TLS13": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantEncipherment-GotEnciphermentTLS1": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Server-WantSignature-GotEncipherment-TLS1": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantSignature-GotSignature-TLS1": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantEncipherment-GotEnciphermentTLS11": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantSignature-GotSignature-TLS11": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantEncipherment-GotEnciphermentTLS12": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Server-WantSignature-GotEncipherment-TLS12": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Server-WantSignature-GotEncipherment-TLS11": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantSignature-GotSignature-TLS12": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantSignature-GotSignature-TLS13": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Server-WantSignature-GotEncipherment-TLS13": "TODO: first pass, this should be fixed", + "EmptyExtensions-ClientHello-TLS1": "TODO: first pass, this should be fixed", + "OmitExtensions-ClientHello-TLS1": "TODO: first pass, this should be fixed", + "EmptyExtensions-ClientHello-TLS12": "TODO: first pass, this should be fixed", + "OmitExtensions-ClientHello-TLS12": "TODO: first pass, this should be fixed", + "EmptyExtensions-ClientHello-TLS11": "TODO: first pass, this should be fixed", + "OmitExtensions-ClientHello-TLS11": "TODO: first pass, this should be fixed", + "DuplicateCertCompressionExt-TLS12": "TODO: first pass, this should be fixed", + "DuplicateCertCompressionExt-TLS13": "TODO: first pass, this should be fixed", + "Client-RejectJDK11DowngradeRandom": "TODO: first pass, this should be fixed", + "CheckClientCertificateTypes": "TODO: first pass, this should be fixed", + "CheckECDSACurve-TLS12": "TODO: first pass, this should be fixed", + "ALPNClient-RejectUnknown-TLS-TLS1": "TODO: first pass, this should be fixed", + "ALPNClient-RejectUnknown-TLS-TLS11": "TODO: first pass, this should be fixed", + "ALPNClient-RejectUnknown-TLS-TLS12": "TODO: first pass, this should be fixed", + "ALPNClient-RejectUnknown-TLS-TLS13": "TODO: first pass, this should be fixed", + "ClientHelloPadding": "TODO: first pass, this should be fixed", + "TLS13-ExpectTicketEarlyDataSupport": "TODO: first pass, this should be fixed", + "TLS13-EarlyData-TooMuchData-Client-TLS-Sync": "TODO: first pass, this should be fixed", + "TLS13-EarlyData-TooMuchData-Client-TLS-Sync-SplitHandshakeRecords": "TODO: first pass, this should be fixed", + "TLS13-EarlyData-TooMuchData-Client-TLS-Sync-PackHandshake": "TODO: first pass, this should be fixed", + "WrongMessageType-TLS13-EndOfEarlyData-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-EndOfEarlyData-TLS": "TODO: first pass, this should be fixed", + "SendHelloRetryRequest-2-TLS13": "TODO: first pass, this should be fixed", + "EarlyData-SkipEndOfEarlyData-TLS13": "TODO: first pass, this should be fixed", + "EarlyData-Server-BadFinished-TLS13": "TODO: first pass, this should be fixed", + "EarlyData-UnexpectedHandshake-Server-TLS13": "TODO: first pass, this should be fixed", + "EarlyData-CipherMismatch-Client-TLS13": "TODO: first pass, this should be fixed", + "Resume-Server-UnofferedCipher-TLS13": "TODO: first pass, this should be fixed" + } +} diff --git a/contrib/go/_std_1.23/src/crypto/tls/boring.go b/contrib/go/_std_1.23/src/crypto/tls/boring.go new file mode 100644 index 000000000000..c44ae92f2528 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/boring.go @@ -0,0 +1,15 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build boringcrypto + +package tls + +import "crypto/internal/boring/fipstls" + +// needFIPS returns fipstls.Required(), which is not available without the +// boringcrypto build tag. +func needFIPS() bool { + return fipstls.Required() +} diff --git a/contrib/go/_std_1.22/src/crypto/tls/cache.go b/contrib/go/_std_1.23/src/crypto/tls/cache.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/cache.go rename to contrib/go/_std_1.23/src/crypto/tls/cache.go diff --git a/contrib/go/_std_1.22/src/crypto/tls/cipher_suites.go b/contrib/go/_std_1.23/src/crypto/tls/cipher_suites.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/tls/cipher_suites.go rename to contrib/go/_std_1.23/src/crypto/tls/cipher_suites.go index 6f5bc37197a4..eebc66880d63 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/cipher_suites.go +++ b/contrib/go/_std_1.23/src/crypto/tls/cipher_suites.go @@ -18,6 +18,7 @@ import ( "hash" "internal/cpu" "runtime" + _ "unsafe" // for linkname "golang.org/x/crypto/chacha20poly1305" ) @@ -197,6 +198,16 @@ type cipherSuiteTLS13 struct { hash crypto.Hash } +// cipherSuitesTLS13 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/quic-go/quic-go +// - github.com/sagernet/quic-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cipherSuitesTLS13 var cipherSuitesTLS13 = []*cipherSuiteTLS13{ // TODO: replace with a map. {TLS_AES_128_GCM_SHA256, 16, aeadAESGCMTLS13, crypto.SHA256}, {TLS_CHACHA20_POLY1305_SHA256, 32, aeadChaCha20Poly1305, crypto.SHA256}, @@ -346,36 +357,11 @@ var rsaKexCiphers = map[uint16]bool{ TLS_RSA_WITH_AES_256_GCM_SHA384: true, } -var defaultCipherSuites []uint16 -var defaultCipherSuitesWithRSAKex []uint16 - -func init() { - defaultCipherSuites = make([]uint16, 0, len(cipherSuitesPreferenceOrder)) - defaultCipherSuitesWithRSAKex = make([]uint16, 0, len(cipherSuitesPreferenceOrder)) - for _, c := range cipherSuitesPreferenceOrder { - if disabledCipherSuites[c] { - continue - } - if !rsaKexCiphers[c] { - defaultCipherSuites = append(defaultCipherSuites, c) - } - defaultCipherSuitesWithRSAKex = append(defaultCipherSuitesWithRSAKex, c) - } -} - -// defaultCipherSuitesTLS13 is also the preference order, since there are no -// disabled by default TLS 1.3 cipher suites. The same AES vs ChaCha20 logic as -// cipherSuitesPreferenceOrder applies. -var defaultCipherSuitesTLS13 = []uint16{ - TLS_AES_128_GCM_SHA256, - TLS_AES_256_GCM_SHA384, - TLS_CHACHA20_POLY1305_SHA256, -} - -var defaultCipherSuitesTLS13NoAES = []uint16{ - TLS_CHACHA20_POLY1305_SHA256, - TLS_AES_128_GCM_SHA256, - TLS_AES_256_GCM_SHA384, +// tdesCiphers contains 3DES ciphers, +// which we also disable by default unless a GODEBUG is set. +var tdesCiphers = map[uint16]bool{ + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: true, + TLS_RSA_WITH_3DES_EDE_CBC_SHA: true, } var ( @@ -548,6 +534,16 @@ func aeadAESGCM(key, noncePrefix []byte) aead { return ret } +// aeadAESGCMTLS13 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/xtls/xray-core +// - github.com/v2fly/v2ray-core +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname aeadAESGCMTLS13 func aeadAESGCMTLS13(key, nonceMask []byte) aead { if len(nonceMask) != aeadNonceLength { panic("tls: internal error: wrong nonce length") diff --git a/contrib/go/_std_1.22/src/crypto/tls/common.go b/contrib/go/_std_1.23/src/crypto/tls/common.go similarity index 86% rename from contrib/go/_std_1.22/src/crypto/tls/common.go rename to contrib/go/_std_1.23/src/crypto/tls/common.go index 849e8b0a209d..5fd92d3c639b 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/common.go +++ b/contrib/go/_std_1.23/src/crypto/tls/common.go @@ -21,9 +21,11 @@ import ( "internal/godebug" "io" "net" + "slices" "strings" "sync" "time" + _ "unsafe" // for linkname ) const ( @@ -58,12 +60,13 @@ func VersionName(version uint16) string { } const ( - maxPlaintext = 16384 // maximum plaintext payload length - maxCiphertext = 16384 + 2048 // maximum ciphertext payload length - maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3 - recordHeaderLen = 5 // record header length - maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) - maxUselessRecords = 16 // maximum number of consecutive non-advancing records + maxPlaintext = 16384 // maximum plaintext payload length + maxCiphertext = 16384 + 2048 // maximum ciphertext payload length + maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3 + recordHeaderLen = 5 // record header length + maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) + maxHandshakeCertificateMsg = 262144 // maximum certificate message size (256 KiB) + maxUselessRecords = 16 // maximum number of consecutive non-advancing records ) // TLS record types. @@ -93,7 +96,6 @@ const ( typeFinished uint8 = 20 typeCertificateStatus uint8 = 22 typeKeyUpdate uint8 = 24 - typeNextProtocol uint8 = 67 // Not IANA assigned typeMessageHash uint8 = 254 // synthetic message ) @@ -123,6 +125,8 @@ const ( extensionKeyShare uint16 = 51 extensionQUICTransportParameters uint16 = 57 extensionRenegotiationInfo uint16 = 0xff01 + extensionECHOuterExtensions uint16 = 0xfd00 + extensionEncryptedClientHello uint16 = 0xfe0d ) // TLS signaling cipher suite values @@ -130,11 +134,13 @@ const ( scsvRenegotiation uint16 = 0x00ff ) -// CurveID is the type of a TLS identifier for an elliptic curve. See +// CurveID is the type of a TLS identifier for a key exchange mechanism. See // https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8. // -// In TLS 1.3, this type is called NamedGroup, but at this time this library -// only supports Elliptic Curve based groups. See RFC 8446, Section 4.2.7. +// In TLS 1.2, this registry used to support only elliptic curves. In TLS 1.3, +// it was extended to other groups and renamed NamedGroup. See RFC 8446, Section +// 4.2.7. It was then also extended to other mechanisms, such as hybrid +// post-quantum KEMs. type CurveID uint16 const ( @@ -142,6 +148,11 @@ const ( CurveP384 CurveID = 24 CurveP521 CurveID = 25 X25519 CurveID = 29 + + // Experimental codepoint for X25519Kyber768Draft00, specified in + // draft-tls-westerbaan-xyber768d00-03. Not exported, as support might be + // removed in the future. + x25519Kyber768Draft00 CurveID = 0x6399 // X25519Kyber768Draft00 ) // TLS 1.3 Key Share. See RFC 8446, Section 4.2.8. @@ -194,25 +205,6 @@ const ( // hash function associated with the Ed25519 signature scheme. var directSigning crypto.Hash = 0 -// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that -// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+ -// CertificateRequest. The two fields are merged to match with TLS 1.3. -// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc. -var defaultSupportedSignatureAlgorithms = []SignatureScheme{ - PSSWithSHA256, - ECDSAWithP256AndSHA256, - Ed25519, - PSSWithSHA384, - PSSWithSHA512, - PKCS1WithSHA256, - PKCS1WithSHA384, - PKCS1WithSHA512, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512, - PKCS1WithSHA1, - ECDSAWithSHA1, -} - // helloRetryRequestRandom is set as the Random value of a ServerHello // to signal that the message is actually a HelloRetryRequest. var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3. @@ -297,8 +289,20 @@ type ConnectionState struct { // resumed connections that don't support Extended Master Secret (RFC 7627). TLSUnique []byte + // ECHAccepted indicates if Encrypted Client Hello was offered by the client + // and accepted by the server. Currently, ECH is supported only on the + // client side. + ECHAccepted bool + // ekm is a closure exposed via ExportKeyingMaterial. ekm func(label string, context []byte, length int) ([]byte, error) + + // testingOnlyDidHRR is true if a HelloRetryRequest was sent/received. + testingOnlyDidHRR bool + + // testingOnlyCurveID is the selected CurveID, or zero if an RSA exchanges + // is performed. + testingOnlyCurveID CurveID } // ExportKeyingMaterial returns length bytes of exported key material in a new @@ -372,7 +376,7 @@ type ClientSessionCache interface { Put(sessionKey string, cs *ClientSessionState) } -//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go +//go:generate stringer -linecomment -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go // SignatureScheme identifies a signature algorithm supported by TLS. See // RFC 8446, Section 4.2.3. @@ -674,7 +678,9 @@ type Config struct { // If CipherSuites is nil, a safe default list is used. The default cipher // suites might change over time. In Go 1.22 RSA key exchange based cipher // suites were removed from the default list, but can be re-added with the - // GODEBUG setting tlsrsakex=1. + // GODEBUG setting tlsrsakex=1. In Go 1.23 3DES cipher suites were removed + // from the default list, but can be re-added with the GODEBUG setting + // tls3des=1. CipherSuites []uint16 // PreferServerCipherSuites is a legacy field and has no effect. @@ -754,6 +760,10 @@ type Config struct { // an ECDHE handshake, in preference order. If empty, the default will // be used. The client will use the first preference as the type for // its key share in TLS 1.3. This may change in the future. + // + // From Go 1.23, the default includes the X25519Kyber768Draft00 hybrid + // post-quantum key exchange. To disable it, set CurvePreferences explicitly + // or use the GODEBUG=tlskyber=0 environment variable. CurvePreferences []CurveID // DynamicRecordSizingDisabled disables adaptive sizing of TLS records. @@ -774,6 +784,41 @@ type Config struct { // used for debugging. KeyLogWriter io.Writer + // EncryptedClientHelloConfigList is a serialized ECHConfigList. If + // provided, clients will attempt to connect to servers using Encrypted + // Client Hello (ECH) using one of the provided ECHConfigs. Servers + // currently ignore this field. + // + // If the list contains no valid ECH configs, the handshake will fail + // and return an error. + // + // If EncryptedClientHelloConfigList is set, MinVersion, if set, must + // be VersionTLS13. + // + // When EncryptedClientHelloConfigList is set, the handshake will only + // succeed if ECH is sucessfully negotiated. If the server rejects ECH, + // an ECHRejectionError error will be returned, which may contain a new + // ECHConfigList that the server suggests using. + // + // How this field is parsed may change in future Go versions, if the + // encoding described in the final Encrypted Client Hello RFC changes. + EncryptedClientHelloConfigList []byte + + // EncryptedClientHelloRejectionVerify, if not nil, is called when ECH is + // rejected, in order to verify the ECH provider certificate in the outer + // Client Hello. If it returns a non-nil error, the handshake is aborted and + // that error results. + // + // Unlike VerifyPeerCertificate and VerifyConnection, normal certificate + // verification will not be performed before calling + // EncryptedClientHelloRejectionVerify. + // + // If EncryptedClientHelloRejectionVerify is nil and ECH is rejected, the + // roots in RootCAs will be used to verify the ECH providers public + // certificate. VerifyPeerCertificate and VerifyConnection are not called + // when ECH is rejected, even if set, and InsecureSkipVerify is ignored. + EncryptedClientHelloRejectionVerify func(ConnectionState) error + // mutex protects sessionTicketKeys and autoSessionTicketKeys. mutex sync.RWMutex // sessionTicketKeys contains zero or more ticket keys. If set, it means @@ -833,36 +878,38 @@ func (c *Config) Clone() *Config { c.mutex.RLock() defer c.mutex.RUnlock() return &Config{ - Rand: c.Rand, - Time: c.Time, - Certificates: c.Certificates, - NameToCertificate: c.NameToCertificate, - GetCertificate: c.GetCertificate, - GetClientCertificate: c.GetClientCertificate, - GetConfigForClient: c.GetConfigForClient, - VerifyPeerCertificate: c.VerifyPeerCertificate, - VerifyConnection: c.VerifyConnection, - RootCAs: c.RootCAs, - NextProtos: c.NextProtos, - ServerName: c.ServerName, - ClientAuth: c.ClientAuth, - ClientCAs: c.ClientCAs, - InsecureSkipVerify: c.InsecureSkipVerify, - CipherSuites: c.CipherSuites, - PreferServerCipherSuites: c.PreferServerCipherSuites, - SessionTicketsDisabled: c.SessionTicketsDisabled, - SessionTicketKey: c.SessionTicketKey, - ClientSessionCache: c.ClientSessionCache, - UnwrapSession: c.UnwrapSession, - WrapSession: c.WrapSession, - MinVersion: c.MinVersion, - MaxVersion: c.MaxVersion, - CurvePreferences: c.CurvePreferences, - DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, - Renegotiation: c.Renegotiation, - KeyLogWriter: c.KeyLogWriter, - sessionTicketKeys: c.sessionTicketKeys, - autoSessionTicketKeys: c.autoSessionTicketKeys, + Rand: c.Rand, + Time: c.Time, + Certificates: c.Certificates, + NameToCertificate: c.NameToCertificate, + GetCertificate: c.GetCertificate, + GetClientCertificate: c.GetClientCertificate, + GetConfigForClient: c.GetConfigForClient, + VerifyPeerCertificate: c.VerifyPeerCertificate, + VerifyConnection: c.VerifyConnection, + RootCAs: c.RootCAs, + NextProtos: c.NextProtos, + ServerName: c.ServerName, + ClientAuth: c.ClientAuth, + ClientCAs: c.ClientCAs, + InsecureSkipVerify: c.InsecureSkipVerify, + CipherSuites: c.CipherSuites, + PreferServerCipherSuites: c.PreferServerCipherSuites, + SessionTicketsDisabled: c.SessionTicketsDisabled, + SessionTicketKey: c.SessionTicketKey, + ClientSessionCache: c.ClientSessionCache, + UnwrapSession: c.UnwrapSession, + WrapSession: c.WrapSession, + MinVersion: c.MinVersion, + MaxVersion: c.MaxVersion, + CurvePreferences: c.CurvePreferences, + DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, + Renegotiation: c.Renegotiation, + KeyLogWriter: c.KeyLogWriter, + EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList, + EncryptedClientHelloRejectionVerify: c.EncryptedClientHelloRejectionVerify, + sessionTicketKeys: c.sessionTicketKeys, + autoSessionTicketKeys: c.autoSessionTicketKeys, } } @@ -1008,19 +1055,20 @@ func (c *Config) time() time.Time { return t() } -var tlsrsakex = godebug.New("tlsrsakex") - func (c *Config) cipherSuites() []uint16 { - if needFIPS() { - return fipsCipherSuites(c) - } - if c.CipherSuites != nil { - return c.CipherSuites + if c.CipherSuites == nil { + if needFIPS() { + return defaultCipherSuitesFIPS + } + return defaultCipherSuites() } - if tlsrsakex.Value() == "1" { - return defaultCipherSuitesWithRSAKex + if needFIPS() { + cipherSuites := slices.Clone(c.CipherSuites) + return slices.DeleteFunc(cipherSuites, func(id uint16) bool { + return !slices.Contains(defaultCipherSuitesFIPS, id) + }) } - return defaultCipherSuites + return c.CipherSuites } var supportedVersions = []uint16{ @@ -1040,7 +1088,7 @@ var tls10server = godebug.New("tls10server") func (c *Config) supportedVersions(isClient bool) []uint16 { versions := make([]uint16, 0, len(supportedVersions)) for _, v := range supportedVersions { - if needFIPS() && (v < fipsMinVersion(c) || v > fipsMaxVersion(c)) { + if needFIPS() && !slices.Contains(defaultSupportedVersionsFIPS, v) { continue } if (c == nil || c.MinVersion == 0) && v < VersionTLS12 { @@ -1048,6 +1096,9 @@ func (c *Config) supportedVersions(isClient bool) []uint16 { continue } } + if isClient && c.EncryptedClientHelloConfigList != nil && v < VersionTLS13 { + continue + } if c != nil && c.MinVersion != 0 && v < c.MinVersion { continue } @@ -1081,20 +1132,30 @@ func supportedVersionsFromMax(maxVersion uint16) []uint16 { return versions } -var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521} - -func (c *Config) curvePreferences() []CurveID { - if needFIPS() { - return fipsCurvePreferences(c) +func (c *Config) curvePreferences(version uint16) []CurveID { + var curvePreferences []CurveID + if c != nil && len(c.CurvePreferences) != 0 { + curvePreferences = slices.Clone(c.CurvePreferences) + if needFIPS() { + return slices.DeleteFunc(curvePreferences, func(c CurveID) bool { + return !slices.Contains(defaultCurvePreferencesFIPS, c) + }) + } + } else if needFIPS() { + curvePreferences = slices.Clone(defaultCurvePreferencesFIPS) + } else { + curvePreferences = defaultCurvePreferences() } - if c == nil || len(c.CurvePreferences) == 0 { - return defaultCurvePreferences + if version < VersionTLS13 { + return slices.DeleteFunc(curvePreferences, func(c CurveID) bool { + return c == x25519Kyber768Draft00 + }) } - return c.CurvePreferences + return curvePreferences } -func (c *Config) supportsCurve(curve CurveID) bool { - for _, cc := range c.curvePreferences() { +func (c *Config) supportsCurve(version uint16, curve CurveID) bool { + for _, cc := range c.curvePreferences(version) { if cc == curve { return true } @@ -1116,6 +1177,15 @@ func (c *Config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bo return 0, false } +// errNoCertificates should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/xtls/xray-core +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname errNoCertificates var errNoCertificates = errors.New("tls: no certificates configured") // getCertificate returns the best certificate for the given ClientHelloInfo, @@ -1253,7 +1323,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error { } // The only signed key exchange we support is ECDHE. - if !supportsECDHE(config, chi.SupportedCurves, chi.SupportedPoints) { + if !supportsECDHE(config, vers, chi.SupportedCurves, chi.SupportedPoints) { return supportsRSAFallback(errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange")) } @@ -1274,7 +1344,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error { } var curveOk bool for _, c := range chi.SupportedCurves { - if c == curve && config.supportsCurve(c) { + if c == curve && config.supportsCurve(vers, c) { curveOk = true break } @@ -1445,6 +1515,15 @@ type handshakeMessage interface { unmarshal([]byte) bool } +type handshakeMessageWithOriginalBytes interface { + handshakeMessage + + // originalBytes should return the original bytes that were passed to + // unmarshal to create the message. If the message was not produced by + // unmarshal, it should return nil. + originalBytes() []byte +} + // lruSessionCache is a ClientSessionCache implementation that uses an LRU // caching strategy. type lruSessionCache struct { @@ -1532,6 +1611,14 @@ func unexpectedMessageError(wanted, got any) error { return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted) } +// supportedSignatureAlgorithms returns the supported signature algorithms. +func supportedSignatureAlgorithms() []SignatureScheme { + if !needFIPS() { + return defaultSupportedSignatureAlgorithms + } + return defaultSupportedSignatureAlgorithmsFIPS +} + func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool { for _, s := range supportedSignatureAlgorithms { if s == sigAlg { diff --git a/contrib/go/_std_1.22/src/crypto/tls/common_string.go b/contrib/go/_std_1.23/src/crypto/tls/common_string.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/tls/common_string.go rename to contrib/go/_std_1.23/src/crypto/tls/common_string.go index 238108811f27..1752f810505b 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/common_string.go +++ b/contrib/go/_std_1.23/src/crypto/tls/common_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go"; DO NOT EDIT. +// Code generated by "stringer -linecomment -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go"; DO NOT EDIT. package tls @@ -71,11 +71,13 @@ func _() { _ = x[CurveP384-24] _ = x[CurveP521-25] _ = x[X25519-29] + _ = x[x25519Kyber768Draft00-25497] } const ( _CurveID_name_0 = "CurveP256CurveP384CurveP521" _CurveID_name_1 = "X25519" + _CurveID_name_2 = "X25519Kyber768Draft00" ) var ( @@ -89,6 +91,8 @@ func (i CurveID) String() string { return _CurveID_name_0[_CurveID_index_0[i]:_CurveID_index_0[i+1]] case i == 29: return _CurveID_name_1 + case i == 25497: + return _CurveID_name_2 default: return "CurveID(" + strconv.FormatInt(int64(i), 10) + ")" } diff --git a/contrib/go/_std_1.22/src/crypto/tls/conn.go b/contrib/go/_std_1.23/src/crypto/tls/conn.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/tls/conn.go rename to contrib/go/_std_1.23/src/crypto/tls/conn.go index 0e4669866e5e..bdbc2bde416a 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/conn.go +++ b/contrib/go/_std_1.23/src/crypto/tls/conn.go @@ -48,7 +48,9 @@ type Conn struct { handshakes int extMasterSecret bool didResume bool // whether this connection was a session resumption + didHRR bool // whether a HelloRetryRequest was sent/received cipherSuite uint16 + curveID CurveID ocspResponse []byte // stapled OCSP response scts [][]byte // signed certificate timestamps from server peerCertificates []*x509.Certificate @@ -69,6 +71,7 @@ type Conn struct { // resumptionSecret is the resumption_master_secret for handling // or sending NewSessionTicket messages. resumptionSecret []byte + echAccepted bool // ticketKeys is the set of active session ticket keys for this // connection. The first one is used to encrypt new tickets and @@ -1040,7 +1043,7 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) { } // writeHandshakeRecord writes a handshake message to the connection and updates -// the record layer state. If transcript is non-nil the marshalled message is +// the record layer state. If transcript is non-nil the marshaled message is // written to it. func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) { c.out.Lock() @@ -1087,10 +1090,22 @@ func (c *Conn) readHandshake(transcript transcriptHash) (any, error) { return nil, err } data := c.hand.Bytes() + + maxHandshakeSize := maxHandshake + // hasVers indicates we're past the first message, forcing someone trying to + // make us just allocate a large buffer to at least do the initial part of + // the handshake first. + if c.haveVers && data[0] == typeCertificate { + // Since certificate messages are likely to be the only messages that + // can be larger than maxHandshake, we use a special limit for just + // those messages. + maxHandshakeSize = maxHandshakeCertificateMsg + } + n := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) - if n > maxHandshake { + if n > maxHandshakeSize { c.sendAlertLocked(alertInternalError) - return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)) + return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshakeSize)) } if err := c.readHandshakeBytes(4 + n); err != nil { return nil, err @@ -1608,6 +1623,9 @@ func (c *Conn) connectionStateLocked() ConnectionState { state.Version = c.vers state.NegotiatedProtocol = c.clientProtocol state.DidResume = c.didResume + state.testingOnlyDidHRR = c.didHRR + // c.curveID is not set on TLS 1.0–1.2 resumptions. Fix that before exposing it. + state.testingOnlyCurveID = c.curveID state.NegotiatedProtocolIsMutual = true state.ServerName = c.serverName state.CipherSuite = c.cipherSuite @@ -1635,6 +1653,7 @@ func (c *Conn) connectionStateLocked() ConnectionState { } else { state.ekm = c.ekm } + state.ECHAccepted = c.echAccepted return state } diff --git a/contrib/go/_std_1.23/src/crypto/tls/defaults.go b/contrib/go/_std_1.23/src/crypto/tls/defaults.go new file mode 100644 index 000000000000..9b28acdc2d86 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/defaults.go @@ -0,0 +1,129 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "internal/godebug" + "slices" + _ "unsafe" // for linkname +) + +// Defaults are collected in this file to allow distributions to more easily patch +// them to apply local policies. + +var tlskyber = godebug.New("tlskyber") + +func defaultCurvePreferences() []CurveID { + if tlskyber.Value() == "0" { + return []CurveID{X25519, CurveP256, CurveP384, CurveP521} + } + // For now, x25519Kyber768Draft00 must always be followed by X25519. + return []CurveID{x25519Kyber768Draft00, X25519, CurveP256, CurveP384, CurveP521} +} + +// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that +// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+ +// CertificateRequest. The two fields are merged to match with TLS 1.3. +// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc. +var defaultSupportedSignatureAlgorithms = []SignatureScheme{ + PSSWithSHA256, + ECDSAWithP256AndSHA256, + Ed25519, + PSSWithSHA384, + PSSWithSHA512, + PKCS1WithSHA256, + PKCS1WithSHA384, + PKCS1WithSHA512, + ECDSAWithP384AndSHA384, + ECDSAWithP521AndSHA512, + PKCS1WithSHA1, + ECDSAWithSHA1, +} + +var tlsrsakex = godebug.New("tlsrsakex") +var tls3des = godebug.New("tls3des") + +func defaultCipherSuites() []uint16 { + suites := slices.Clone(cipherSuitesPreferenceOrder) + return slices.DeleteFunc(suites, func(c uint16) bool { + return disabledCipherSuites[c] || + tlsrsakex.Value() != "1" && rsaKexCiphers[c] || + tls3des.Value() != "1" && tdesCiphers[c] + }) +} + +// defaultCipherSuitesTLS13 is also the preference order, since there are no +// disabled by default TLS 1.3 cipher suites. The same AES vs ChaCha20 logic as +// cipherSuitesPreferenceOrder applies. +// +// defaultCipherSuitesTLS13 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/quic-go/quic-go +// - github.com/sagernet/quic-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname defaultCipherSuitesTLS13 +var defaultCipherSuitesTLS13 = []uint16{ + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_CHACHA20_POLY1305_SHA256, +} + +// defaultCipherSuitesTLS13NoAES should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/quic-go/quic-go +// - github.com/sagernet/quic-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname defaultCipherSuitesTLS13NoAES +var defaultCipherSuitesTLS13NoAES = []uint16{ + TLS_CHACHA20_POLY1305_SHA256, + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, +} + +var defaultSupportedVersionsFIPS = []uint16{ + VersionTLS12, +} + +// defaultCurvePreferencesFIPS are the FIPS-allowed curves, +// in preference order (most preferable first). +var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384, CurveP521} + +// defaultSupportedSignatureAlgorithmsFIPS currently are a subset of +// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1. +var defaultSupportedSignatureAlgorithmsFIPS = []SignatureScheme{ + PSSWithSHA256, + PSSWithSHA384, + PSSWithSHA512, + PKCS1WithSHA256, + ECDSAWithP256AndSHA256, + PKCS1WithSHA384, + ECDSAWithP384AndSHA384, + PKCS1WithSHA512, + ECDSAWithP521AndSHA512, +} + +// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites. +var defaultCipherSuitesFIPS = []uint16{ + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, +} + +// defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3. +var defaultCipherSuitesTLS13FIPS = []uint16{ + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, +} diff --git a/contrib/go/_std_1.23/src/crypto/tls/ech.go b/contrib/go/_std_1.23/src/crypto/tls/ech.go new file mode 100644 index 000000000000..7bf68589f870 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/ech.go @@ -0,0 +1,283 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "crypto/internal/hpke" + "errors" + "strings" + + "golang.org/x/crypto/cryptobyte" +) + +type echCipher struct { + KDFID uint16 + AEADID uint16 +} + +type echExtension struct { + Type uint16 + Data []byte +} + +type echConfig struct { + raw []byte + + Version uint16 + Length uint16 + + ConfigID uint8 + KemID uint16 + PublicKey []byte + SymmetricCipherSuite []echCipher + + MaxNameLength uint8 + PublicName []byte + Extensions []echExtension +} + +var errMalformedECHConfig = errors.New("tls: malformed ECHConfigList") + +// parseECHConfigList parses a draft-ietf-tls-esni-18 ECHConfigList, returning a +// slice of parsed ECHConfigs, in the same order they were parsed, or an error +// if the list is malformed. +func parseECHConfigList(data []byte) ([]echConfig, error) { + s := cryptobyte.String(data) + // Skip the length prefix + var length uint16 + if !s.ReadUint16(&length) { + return nil, errMalformedECHConfig + } + if length != uint16(len(data)-2) { + return nil, errMalformedECHConfig + } + var configs []echConfig + for len(s) > 0 { + var ec echConfig + ec.raw = []byte(s) + if !s.ReadUint16(&ec.Version) { + return nil, errMalformedECHConfig + } + if !s.ReadUint16(&ec.Length) { + return nil, errMalformedECHConfig + } + if len(ec.raw) < int(ec.Length)+4 { + return nil, errMalformedECHConfig + } + ec.raw = ec.raw[:ec.Length+4] + if ec.Version != extensionEncryptedClientHello { + s.Skip(int(ec.Length)) + continue + } + if !s.ReadUint8(&ec.ConfigID) { + return nil, errMalformedECHConfig + } + if !s.ReadUint16(&ec.KemID) { + return nil, errMalformedECHConfig + } + if !s.ReadUint16LengthPrefixed((*cryptobyte.String)(&ec.PublicKey)) { + return nil, errMalformedECHConfig + } + var cipherSuites cryptobyte.String + if !s.ReadUint16LengthPrefixed(&cipherSuites) { + return nil, errMalformedECHConfig + } + for !cipherSuites.Empty() { + var c echCipher + if !cipherSuites.ReadUint16(&c.KDFID) { + return nil, errMalformedECHConfig + } + if !cipherSuites.ReadUint16(&c.AEADID) { + return nil, errMalformedECHConfig + } + ec.SymmetricCipherSuite = append(ec.SymmetricCipherSuite, c) + } + if !s.ReadUint8(&ec.MaxNameLength) { + return nil, errMalformedECHConfig + } + var publicName cryptobyte.String + if !s.ReadUint8LengthPrefixed(&publicName) { + return nil, errMalformedECHConfig + } + ec.PublicName = publicName + var extensions cryptobyte.String + if !s.ReadUint16LengthPrefixed(&extensions) { + return nil, errMalformedECHConfig + } + for !extensions.Empty() { + var e echExtension + if !extensions.ReadUint16(&e.Type) { + return nil, errMalformedECHConfig + } + if !extensions.ReadUint16LengthPrefixed((*cryptobyte.String)(&e.Data)) { + return nil, errMalformedECHConfig + } + ec.Extensions = append(ec.Extensions, e) + } + + configs = append(configs, ec) + } + return configs, nil +} + +func pickECHConfig(list []echConfig) *echConfig { + for _, ec := range list { + if _, ok := hpke.SupportedKEMs[ec.KemID]; !ok { + continue + } + var validSCS bool + for _, cs := range ec.SymmetricCipherSuite { + if _, ok := hpke.SupportedAEADs[cs.AEADID]; !ok { + continue + } + if _, ok := hpke.SupportedKDFs[cs.KDFID]; !ok { + continue + } + validSCS = true + break + } + if !validSCS { + continue + } + if !validDNSName(string(ec.PublicName)) { + continue + } + var unsupportedExt bool + for _, ext := range ec.Extensions { + // If high order bit is set to 1 the extension is mandatory. + // Since we don't support any extensions, if we see a mandatory + // bit, we skip the config. + if ext.Type&uint16(1<<15) != 0 { + unsupportedExt = true + } + } + if unsupportedExt { + continue + } + return &ec + } + return nil +} + +func pickECHCipherSuite(suites []echCipher) (echCipher, error) { + for _, s := range suites { + // NOTE: all of the supported AEADs and KDFs are fine, rather than + // imposing some sort of preference here, we just pick the first valid + // suite. + if _, ok := hpke.SupportedAEADs[s.AEADID]; !ok { + continue + } + if _, ok := hpke.SupportedKDFs[s.KDFID]; !ok { + continue + } + return s, nil + } + return echCipher{}, errors.New("tls: no supported symmetric ciphersuites for ECH") +} + +func encodeInnerClientHello(inner *clientHelloMsg, maxNameLength int) ([]byte, error) { + h, err := inner.marshalMsg(true) + if err != nil { + return nil, err + } + h = h[4:] // strip four byte prefix + + var paddingLen int + if inner.serverName != "" { + paddingLen = max(0, maxNameLength-len(inner.serverName)) + } else { + paddingLen = maxNameLength + 9 + } + paddingLen = 31 - ((len(h) + paddingLen - 1) % 32) + + return append(h, make([]byte, paddingLen)...), nil +} + +func generateOuterECHExt(id uint8, kdfID, aeadID uint16, encodedKey []byte, payload []byte) ([]byte, error) { + var b cryptobyte.Builder + b.AddUint8(0) // outer + b.AddUint16(kdfID) + b.AddUint16(aeadID) + b.AddUint8(id) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(encodedKey) }) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(payload) }) + return b.Bytes() +} + +func computeAndUpdateOuterECHExtension(outer, inner *clientHelloMsg, ech *echContext, useKey bool) error { + var encapKey []byte + if useKey { + encapKey = ech.encapsulatedKey + } + encodedInner, err := encodeInnerClientHello(inner, int(ech.config.MaxNameLength)) + if err != nil { + return err + } + // NOTE: the tag lengths for all of the supported AEADs are the same (16 + // bytes), so we have hardcoded it here. If we add support for another AEAD + // with a different tag length, we will need to change this. + encryptedLen := len(encodedInner) + 16 // AEAD tag length + outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, make([]byte, encryptedLen)) + if err != nil { + return err + } + serializedOuter, err := outer.marshal() + if err != nil { + return err + } + serializedOuter = serializedOuter[4:] // strip the four byte prefix + encryptedInner, err := ech.hpkeContext.Seal(serializedOuter, encodedInner) + if err != nil { + return err + } + outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, encryptedInner) + if err != nil { + return err + } + return nil +} + +// validDNSName is a rather rudimentary check for the validity of a DNS name. +// This is used to check if the public_name in a ECHConfig is valid when we are +// picking a config. This can be somewhat lax because even if we pick a +// valid-looking name, the DNS layer will later reject it anyway. +func validDNSName(name string) bool { + if len(name) > 253 { + return false + } + labels := strings.Split(name, ".") + if len(labels) <= 1 { + return false + } + for _, l := range labels { + labelLen := len(l) + if labelLen == 0 { + return false + } + for i, r := range l { + if r == '-' && (i == 0 || i == labelLen-1) { + return false + } + if (r < '0' || r > '9') && (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && r != '-' { + return false + } + } + } + return true +} + +// ECHRejectionError is the error type returned when ECH is rejected by a remote +// server. If the server offered a ECHConfigList to use for retries, the +// RetryConfigList field will contain this list. +// +// The client may treat an ECHRejectionError with an empty set of RetryConfigs +// as a secure signal from the server. +type ECHRejectionError struct { + RetryConfigList []byte +} + +func (e *ECHRejectionError) Error() string { + return "tls: server rejected ECH" +} diff --git a/contrib/go/_std_1.22/src/crypto/tls/fipsonly/fipsonly.go b/contrib/go/_std_1.23/src/crypto/tls/fipsonly/fipsonly.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/fipsonly/fipsonly.go rename to contrib/go/_std_1.23/src/crypto/tls/fipsonly/fipsonly.go diff --git a/contrib/go/_std_1.22/src/crypto/tls/fipsonly/ya.make b/contrib/go/_std_1.23/src/crypto/tls/fipsonly/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/fipsonly/ya.make rename to contrib/go/_std_1.23/src/crypto/tls/fipsonly/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/tls/generate_cert.go b/contrib/go/_std_1.23/src/crypto/tls/generate_cert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/generate_cert.go rename to contrib/go/_std_1.23/src/crypto/tls/generate_cert.go diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_client.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_client.go similarity index 80% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_client.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_client.go index 08a2d47974c2..5025657590d3 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_client.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_client.go @@ -8,15 +8,17 @@ import ( "bytes" "context" "crypto" - "crypto/ecdh" "crypto/ecdsa" "crypto/ed25519" + "crypto/internal/hpke" + "crypto/internal/mlkem768" "crypto/rsa" "crypto/subtle" "crypto/x509" "errors" "fmt" "hash" + "internal/byteorder" "internal/godebug" "io" "net" @@ -39,52 +41,52 @@ type clientHandshakeState struct { var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme -func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { +func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echContext, error) { config := c.config if len(config.ServerName) == 0 && !config.InsecureSkipVerify { - return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") + return nil, nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") } nextProtosLength := 0 for _, proto := range config.NextProtos { if l := len(proto); l == 0 || l > 255 { - return nil, nil, errors.New("tls: invalid NextProtos value") + return nil, nil, nil, errors.New("tls: invalid NextProtos value") } else { nextProtosLength += 1 + l } } if nextProtosLength > 0xffff { - return nil, nil, errors.New("tls: NextProtos values too large") + return nil, nil, nil, errors.New("tls: NextProtos values too large") } supportedVersions := config.supportedVersions(roleClient) if len(supportedVersions) == 0 { - return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion") - } - - clientHelloVersion := config.maxSupportedVersion(roleClient) - // The version at the beginning of the ClientHello was capped at TLS 1.2 - // for compatibility reasons. The supported_versions extension is used - // to negotiate versions now. See RFC 8446, Section 4.2.1. - if clientHelloVersion > VersionTLS12 { - clientHelloVersion = VersionTLS12 + return nil, nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion") } + maxVersion := config.maxSupportedVersion(roleClient) hello := &clientHelloMsg{ - vers: clientHelloVersion, + vers: maxVersion, compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), extendedMasterSecret: true, ocspStapling: true, scts: true, serverName: hostnameInSNI(config.ServerName), - supportedCurves: config.curvePreferences(), + supportedCurves: config.curvePreferences(maxVersion), supportedPoints: []uint8{pointFormatUncompressed}, secureRenegotiationSupported: true, alpnProtocols: config.NextProtos, supportedVersions: supportedVersions, } + // The version at the beginning of the ClientHello was capped at TLS 1.2 + // for compatibility reasons. The supported_versions extension is used + // to negotiate versions now. See RFC 8446, Section 4.2.1. + if hello.vers > VersionTLS12 { + hello.vers = VersionTLS12 + } + if c.handshakes > 0 { hello.secureRenegotiation = c.clientFinished[:] } @@ -103,7 +105,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { } // Don't advertise TLS 1.2-only cipher suites unless // we're attempting TLS 1.2. - if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 { + if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 { continue } hello.cipherSuites = append(hello.cipherSuites, suiteId) @@ -111,7 +113,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { _, err := io.ReadFull(config.rand(), hello.random) if err != nil { - return nil, nil, errors.New("tls: short read from Rand: " + err.Error()) + return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error()) } // A random session ID is used to detect when the server accepted a ticket @@ -122,18 +124,18 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { if c.quic == nil { hello.sessionId = make([]byte, 32) if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil { - return nil, nil, errors.New("tls: short read from Rand: " + err.Error()) + return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error()) } } - if hello.vers >= VersionTLS12 { + if maxVersion >= VersionTLS12 { hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms() } if testingOnlyForceClientHelloSignatureAlgorithms != nil { hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms } - var key *ecdh.PrivateKey + var keyShareKeys *keySharePrivateKeys if hello.supportedVersions[0] == VersionTLS13 { // Reset the list of ciphers when the client only supports TLS 1.3. if len(hello.supportedVersions) == 1 { @@ -145,21 +147,46 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...) } - curveID := config.curvePreferences()[0] - if _, ok := curveForCurveID(curveID); !ok { - return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve") - } - key, err = generateECDHEKey(config.rand(), curveID) - if err != nil { - return nil, nil, err + curveID := config.curvePreferences(maxVersion)[0] + keyShareKeys = &keySharePrivateKeys{curveID: curveID} + if curveID == x25519Kyber768Draft00 { + keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519) + if err != nil { + return nil, nil, nil, err + } + seed := make([]byte, mlkem768.SeedSize) + if _, err := io.ReadFull(config.rand(), seed); err != nil { + return nil, nil, nil, err + } + keyShareKeys.kyber, err = mlkem768.NewKeyFromSeed(seed) + if err != nil { + return nil, nil, nil, err + } + // For draft-tls-westerbaan-xyber768d00-03, we send both a hybrid + // and a standard X25519 key share, since most servers will only + // support the latter. We reuse the same X25519 ephemeral key for + // both, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2. + hello.keyShares = []keyShare{ + {group: x25519Kyber768Draft00, data: append(keyShareKeys.ecdhe.PublicKey().Bytes(), + keyShareKeys.kyber.EncapsulationKey()...)}, + {group: X25519, data: keyShareKeys.ecdhe.PublicKey().Bytes()}, + } + } else { + if _, ok := curveForCurveID(curveID); !ok { + return nil, nil, nil, errors.New("tls: CurvePreferences includes unsupported curve") + } + keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), curveID) + if err != nil { + return nil, nil, nil, err + } + hello.keyShares = []keyShare{{group: curveID, data: keyShareKeys.ecdhe.PublicKey().Bytes()}} } - hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}} } if c.quic != nil { p, err := c.quicGetTransportParameters() if err != nil { - return nil, nil, err + return nil, nil, nil, err } if p == nil { p = []byte{} @@ -167,7 +194,60 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { hello.quicTransportParameters = p } - return hello, key, nil + var ech *echContext + if c.config.EncryptedClientHelloConfigList != nil { + if c.config.MinVersion != 0 && c.config.MinVersion < VersionTLS13 { + return nil, nil, nil, errors.New("tls: MinVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated") + } + if c.config.MaxVersion != 0 && c.config.MaxVersion <= VersionTLS12 { + return nil, nil, nil, errors.New("tls: MaxVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated") + } + echConfigs, err := parseECHConfigList(c.config.EncryptedClientHelloConfigList) + if err != nil { + return nil, nil, nil, err + } + echConfig := pickECHConfig(echConfigs) + if echConfig == nil { + return nil, nil, nil, errors.New("tls: EncryptedClientHelloConfigList contains no valid configs") + } + ech = &echContext{config: echConfig} + hello.encryptedClientHello = []byte{1} // indicate inner hello + // We need to explicitly set these 1.2 fields to nil, as we do not + // marshal them when encoding the inner hello, otherwise transcripts + // will later mismatch. + hello.supportedPoints = nil + hello.ticketSupported = false + hello.secureRenegotiationSupported = false + hello.extendedMasterSecret = false + + echPK, err := hpke.ParseHPKEPublicKey(ech.config.KemID, ech.config.PublicKey) + if err != nil { + return nil, nil, nil, err + } + suite, err := pickECHCipherSuite(ech.config.SymmetricCipherSuite) + if err != nil { + return nil, nil, nil, err + } + ech.kdfID, ech.aeadID = suite.KDFID, suite.AEADID + info := append([]byte("tls ech\x00"), ech.config.raw...) + ech.encapsulatedKey, ech.hpkeContext, err = hpke.SetupSender(ech.config.KemID, suite.KDFID, suite.AEADID, echPK, info) + if err != nil { + return nil, nil, nil, err + } + } + + return hello, keyShareKeys, ech, nil +} + +type echContext struct { + config *echConfig + hpkeContext *hpke.Sender + encapsulatedKey []byte + innerHello *clientHelloMsg + innerTranscript hash.Hash + kdfID uint16 + aeadID uint16 + echRejected bool } func (c *Conn) clientHandshake(ctx context.Context) (err error) { @@ -179,11 +259,10 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { // need to be reset. c.didResume = false - hello, ecdheKey, err := c.makeClientHello() + hello, keyShareKeys, ech, err := c.makeClientHello() if err != nil { return err } - c.serverName = hello.serverName session, earlySecret, binderKey, err := c.loadSession(hello) if err != nil { @@ -205,6 +284,31 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { }() } + if ech != nil { + // Split hello into inner and outer + ech.innerHello = hello.clone() + + // Overwrite the server name in the outer hello with the public facing + // name. + hello.serverName = string(ech.config.PublicName) + // Generate a new random for the outer hello. + hello.random = make([]byte, 32) + _, err = io.ReadFull(c.config.rand(), hello.random) + if err != nil { + return errors.New("tls: short read from Rand: " + err.Error()) + } + + // NOTE: we don't do PSK GREASE, in line with boringssl, it's meant to + // work around _possibly_ broken middleboxes, but there is little-to-no + // evidence that this is actually a problem. + + if err := computeAndUpdateOuterECHExtension(hello, ech.innerHello, ech, true); err != nil { + return err + } + } + + c.serverName = hello.serverName + if _, err := c.writeHandshakeRecord(hello, nil); err != nil { return err } @@ -249,17 +353,16 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { if c.vers == VersionTLS13 { hs := &clientHandshakeStateTLS13{ - c: c, - ctx: ctx, - serverHello: serverHello, - hello: hello, - ecdheKey: ecdheKey, - session: session, - earlySecret: earlySecret, - binderKey: binderKey, + c: c, + ctx: ctx, + serverHello: serverHello, + hello: hello, + keyShareKeys: keyShareKeys, + session: session, + earlySecret: earlySecret, + binderKey: binderKey, + echContext: ech, } - - // In TLS 1.3, session tickets are delivered after the handshake. return hs.handshake() } @@ -270,12 +373,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { hello: hello, session: session, } - - if err := hs.handshake(); err != nil { - return err - } - - return nil + return hs.handshake() } func (c *Conn) loadSession(hello *clientHelloMsg) ( @@ -284,7 +382,11 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( return nil, nil, nil, nil } - hello.ticketSupported = true + echInner := bytes.Equal(hello.encryptedClientHello, []byte{1}) + + // ticketSupported is a TLS 1.2 extension (as TLS 1.3 replaced tickets with PSK + // identities) and ECH requires and forces TLS 1.3. + hello.ticketSupported = true && !echInner if hello.supportedVersions[0] == VersionTLS13 { // Require DHE on resumption as it guarantees forward secrecy against @@ -347,7 +449,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( return nil, nil, nil, nil } - hello.sessionTicket = cs.ticket + hello.sessionTicket = session.ticket return } @@ -375,10 +477,14 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( return nil, nil, nil, nil } - if c.quic != nil && session.EarlyData { + if c.quic != nil { + if c.quic.enableSessionEvents { + c.quicResumeSession(session) + } + // For 0-RTT, the cipher suite has to match exactly, and we need to be // offering the same ALPN. - if mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil { + if session.EarlyData && mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil { for _, alpn := range hello.alpnProtocols { if alpn == session.alpnProtocol { hello.earlyData = true @@ -391,7 +497,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( // Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1. ticketAge := c.config.time().Sub(time.Unix(int64(session.createdAt), 0)) identity := pskIdentity{ - label: cs.ticket, + label: session.ticket, obfuscatedTicketAge: uint32(ticketAge/time.Millisecond) + session.ageAdd, } hello.pskIdentities = []pskIdentity{identity} @@ -401,13 +507,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( earlySecret = cipherSuite.extract(session.secret, nil) binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil) transcript := cipherSuite.hash.New() - helloBytes, err := hello.marshalWithoutBinders() - if err != nil { - return nil, nil, nil, err - } - transcript.Write(helloBytes) - pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)} - if err := hello.updateBinders(pskBinders); err != nil { + if err := computeAndUpdatePSK(hello, binderKey, transcript, cipherSuite.finishedHash); err != nil { return nil, nil, nil, err } @@ -527,8 +627,13 @@ func (hs *clientHandshakeState) pickCipherSuite() error { } if hs.c.config.CipherSuites == nil && !needFIPS() && rsaKexCiphers[hs.suite.id] { + tlsrsakex.Value() // ensure godebug is initialized tlsrsakex.IncNonDefault() } + if hs.c.config.CipherSuites == nil && !needFIPS() && tdesCiphers[hs.suite.id] { + tls3des.Value() // ensure godebug is initialized + tls3des.IncNonDefault() + } hs.c.cipherSuite = hs.suite.id return nil @@ -602,6 +707,9 @@ func (hs *clientHandshakeState) doFullHandshake() error { c.sendAlert(alertUnexpectedMessage) return err } + if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ { + c.curveID = CurveID(byteorder.BeUint16(skx.key[1:])) + } msg, err = c.readHandshake(&hs.finishedHash) if err != nil { @@ -915,13 +1023,11 @@ func (hs *clientHandshakeState) saveSessionTicket() error { return nil } - session, err := c.sessionState() - if err != nil { - return err - } + session := c.sessionState() session.secret = hs.masterSecret + session.ticket = hs.ticket - cs := &ClientSessionState{ticket: hs.ticket, session: session} + cs := &ClientSessionState{session: session} c.config.ClientSessionCache.Put(cacheKey, cs) return nil } @@ -982,7 +1088,32 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { certs[i] = cert.cert } - if !c.config.InsecureSkipVerify { + echRejected := c.config.EncryptedClientHelloConfigList != nil && !c.echAccepted + if echRejected { + if c.config.EncryptedClientHelloRejectionVerify != nil { + if err := c.config.EncryptedClientHelloRejectionVerify(c.connectionStateLocked()); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } else { + opts := x509.VerifyOptions{ + Roots: c.config.RootCAs, + CurrentTime: c.config.time(), + DNSName: c.serverName, + Intermediates: x509.NewCertPool(), + } + + for _, cert := range certs[1:] { + opts.Intermediates.AddCert(cert) + } + var err error + c.verifiedChains, err = certs[0].Verify(opts) + if err != nil { + c.sendAlert(alertBadCertificate) + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + } + } else if !c.config.InsecureSkipVerify { opts := x509.VerifyOptions{ Roots: c.config.RootCAs, CurrentTime: c.config.time(), @@ -1012,14 +1143,14 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { c.activeCertHandles = activeHandles c.peerCertificates = certs - if c.config.VerifyPeerCertificate != nil { + if c.config.VerifyPeerCertificate != nil && !echRejected { if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil { c.sendAlert(alertBadCertificate) return err } } - if c.config.VerifyConnection != nil { + if c.config.VerifyConnection != nil && !echRejected { if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { c.sendAlert(alertBadCertificate) return err @@ -1142,3 +1273,13 @@ func hostnameInSNI(name string) string { } return name } + +func computeAndUpdatePSK(m *clientHelloMsg, binderKey []byte, transcript hash.Hash, finishedHash func([]byte, hash.Hash) []byte) error { + helloBytes, err := m.marshalWithoutBinders() + if err != nil { + return err + } + transcript.Write(helloBytes) + pskBinders := [][]byte{finishedHash(binderKey, transcript)} + return m.updateBinders(pskBinders) +} diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_client_tls13.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_client_tls13.go similarity index 75% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_client_tls13.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_client_tls13.go index 2f59f6888c5d..db5e35d9a46c 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_client_tls13.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_client_tls13.go @@ -8,20 +8,22 @@ import ( "bytes" "context" "crypto" - "crypto/ecdh" "crypto/hmac" + "crypto/internal/mlkem768" "crypto/rsa" + "crypto/subtle" "errors" "hash" + "slices" "time" ) type clientHandshakeStateTLS13 struct { - c *Conn - ctx context.Context - serverHello *serverHelloMsg - hello *clientHelloMsg - ecdheKey *ecdh.PrivateKey + c *Conn + ctx context.Context + serverHello *serverHelloMsg + hello *clientHelloMsg + keyShareKeys *keySharePrivateKeys session *SessionState earlySecret []byte @@ -34,9 +36,11 @@ type clientHandshakeStateTLS13 struct { transcript hash.Hash masterSecret []byte trafficSecret []byte // client_application_traffic_secret_0 + + echContext *echContext } -// handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheKey, and, +// handshake requires hs.c, hs.hello, hs.serverHello, hs.keyShareKeys, and, // optionally, hs.session, hs.earlySecret and hs.binderKey to be set. func (hs *clientHandshakeStateTLS13) handshake() error { c := hs.c @@ -53,7 +57,7 @@ func (hs *clientHandshakeStateTLS13) handshake() error { } // Consistency check on the presence of a keyShare and its parameters. - if hs.ecdheKey == nil || len(hs.hello.keyShares) != 1 { + if hs.keyShareKeys == nil || hs.keyShareKeys.ecdhe == nil || len(hs.hello.keyShares) == 0 { return c.sendAlert(alertInternalError) } @@ -67,6 +71,13 @@ func (hs *clientHandshakeStateTLS13) handshake() error { return err } + if hs.echContext != nil { + hs.echContext.innerTranscript = hs.suite.hash.New() + if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil { + return err + } + } + if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) { if err := hs.sendDummyChangeCipherSpec(); err != nil { return err @@ -76,6 +87,41 @@ func (hs *clientHandshakeStateTLS13) handshake() error { } } + var echRetryConfigList []byte + if hs.echContext != nil { + confTranscript := cloneHash(hs.echContext.innerTranscript, hs.suite.hash) + confTranscript.Write(hs.serverHello.original[:30]) + confTranscript.Write(make([]byte, 8)) + confTranscript.Write(hs.serverHello.original[38:]) + acceptConfirmation := hs.suite.expandLabel( + hs.suite.extract(hs.echContext.innerHello.random, nil), + "ech accept confirmation", + confTranscript.Sum(nil), + 8, + ) + if subtle.ConstantTimeCompare(acceptConfirmation, hs.serverHello.random[len(hs.serverHello.random)-8:]) == 1 { + hs.hello = hs.echContext.innerHello + c.serverName = c.config.ServerName + hs.transcript = hs.echContext.innerTranscript + c.echAccepted = true + + if hs.serverHello.encryptedClientHello != nil { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: unexpected encrypted_client_hello extension in server hello despite ECH being accepted") + } + + if hs.hello.serverName == "" && hs.serverHello.serverNameAck { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: unexpected server_name extension in server hello") + } + } else { + hs.echContext.echRejected = true + // If the server sent us retry configs, we'll return these to + // the user so they can update their Config. + echRetryConfigList = hs.serverHello.encryptedClientHello + } + } + if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil { return err } @@ -109,6 +155,11 @@ func (hs *clientHandshakeStateTLS13) handshake() error { return err } + if hs.echContext != nil && hs.echContext.echRejected { + c.sendAlert(alertECHRequired) + return &ECHRejectionError{echRetryConfigList} + } + c.isHandshakeComplete.Store(true) return nil @@ -200,6 +251,48 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { return err } + var isInnerHello bool + hello := hs.hello + if hs.echContext != nil { + chHash = hs.echContext.innerTranscript.Sum(nil) + hs.echContext.innerTranscript.Reset() + hs.echContext.innerTranscript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) + hs.echContext.innerTranscript.Write(chHash) + + if hs.serverHello.encryptedClientHello != nil { + if len(hs.serverHello.encryptedClientHello) != 8 { + hs.c.sendAlert(alertDecodeError) + return errors.New("tls: malformed encrypted client hello extension") + } + + confTranscript := cloneHash(hs.echContext.innerTranscript, hs.suite.hash) + hrrHello := make([]byte, len(hs.serverHello.original)) + copy(hrrHello, hs.serverHello.original) + hrrHello = bytes.Replace(hrrHello, hs.serverHello.encryptedClientHello, make([]byte, 8), 1) + confTranscript.Write(hrrHello) + acceptConfirmation := hs.suite.expandLabel( + hs.suite.extract(hs.echContext.innerHello.random, nil), + "hrr ech accept confirmation", + confTranscript.Sum(nil), + 8, + ) + if subtle.ConstantTimeCompare(acceptConfirmation, hs.serverHello.encryptedClientHello) == 1 { + hello = hs.echContext.innerHello + c.serverName = c.config.ServerName + isInnerHello = true + c.echAccepted = true + } + } + + if err := transcriptMsg(hs.serverHello, hs.echContext.innerTranscript); err != nil { + return err + } + } else if hs.serverHello.encryptedClientHello != nil { + // Unsolicited ECH extension should be rejected + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: unexpected ECH extension in serverHello") + } + // The only HelloRetryRequest extensions we support are key_share and // cookie, and clients must abort the handshake if the HRR would not result // in any change in the ClientHello. @@ -209,7 +302,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { } if hs.serverHello.cookie != nil { - hs.hello.cookie = hs.serverHello.cookie + hello.cookie = hs.serverHello.cookie } if hs.serverHello.serverShare.group != 0 { @@ -221,21 +314,22 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { // a group we advertised but did not send a key share for, and send a key // share for it this time. if curveID := hs.serverHello.selectedGroup; curveID != 0 { - curveOK := false - for _, id := range hs.hello.supportedCurves { - if id == curveID { - curveOK = true - break - } - } - if !curveOK { + if !slices.Contains(hello.supportedCurves, curveID) { c.sendAlert(alertIllegalParameter) return errors.New("tls: server selected unsupported group") } - if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); sentID == curveID { + if slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool { + return ks.group == curveID + }) { c.sendAlert(alertIllegalParameter) return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share") } + // Note: we don't support selecting X25519Kyber768Draft00 in a HRR, + // because we currently only support it at all when CurvePreferences is + // empty, which will cause us to also send a key share for it. + // + // This will have to change once we support selecting hybrid KEMs + // without sending key shares for them. if _, ok := curveForCurveID(curveID); !ok { c.sendAlert(alertInternalError) return errors.New("tls: CurvePreferences includes unsupported curve") @@ -245,12 +339,11 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { c.sendAlert(alertInternalError) return err } - hs.ecdheKey = key - hs.hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}} + hs.keyShareKeys = &keySharePrivateKeys{curveID: curveID, ecdhe: key} + hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}} } - hs.hello.raw = nil - if len(hs.hello.pskIdentities) > 0 { + if len(hello.pskIdentities) > 0 { pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite) if pskSuite == nil { return c.sendAlert(alertInternalError) @@ -258,7 +351,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { if pskSuite.hash == hs.suite.hash { // Update binders and obfuscated_ticket_age. ticketAge := c.config.time().Sub(time.Unix(int64(hs.session.createdAt), 0)) - hs.hello.pskIdentities[0].obfuscatedTicketAge = uint32(ticketAge/time.Millisecond) + hs.session.ageAdd + hello.pskIdentities[0].obfuscatedTicketAge = uint32(ticketAge/time.Millisecond) + hs.session.ageAdd transcript := hs.suite.hash.New() transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) @@ -266,27 +359,40 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { if err := transcriptMsg(hs.serverHello, transcript); err != nil { return err } - helloBytes, err := hs.hello.marshalWithoutBinders() - if err != nil { - return err - } - transcript.Write(helloBytes) - pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)} - if err := hs.hello.updateBinders(pskBinders); err != nil { + + if err := computeAndUpdatePSK(hello, hs.binderKey, transcript, hs.suite.finishedHash); err != nil { return err } } else { // Server selected a cipher suite incompatible with the PSK. - hs.hello.pskIdentities = nil - hs.hello.pskBinders = nil + hello.pskIdentities = nil + hello.pskBinders = nil } } - if hs.hello.earlyData { - hs.hello.earlyData = false + if hello.earlyData { + hello.earlyData = false c.quicRejectedEarlyData() } + if isInnerHello { + // Any extensions which have changed in hello, but are mirrored in the + // outer hello and compressed, need to be copied to the outer hello, so + // they can be properly decompressed by the server. For now, the only + // extension which may have changed is keyShares. + hs.hello.keyShares = hello.keyShares + hs.echContext.innerHello = hello + if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil { + return err + } + + if err := computeAndUpdateOuterECHExtension(hs.hello, hs.echContext.innerHello, hs.echContext, false); err != nil { + return err + } + } else { + hs.hello = hello + } + if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil { return err } @@ -308,6 +414,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { return err } + c.didHRR = true return nil } @@ -333,7 +440,9 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error { c.sendAlert(alertIllegalParameter) return errors.New("tls: server did not send a key share") } - if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); hs.serverHello.serverShare.group != sentID { + if !slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool { + return ks.group == hs.serverHello.serverShare.group + }) { c.sendAlert(alertIllegalParameter) return errors.New("tls: server selected unsupported group") } @@ -372,16 +481,37 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error { func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { c := hs.c - peerKey, err := hs.ecdheKey.Curve().NewPublicKey(hs.serverHello.serverShare.data) + ecdhePeerData := hs.serverHello.serverShare.data + if hs.serverHello.serverShare.group == x25519Kyber768Draft00 { + if len(ecdhePeerData) != x25519PublicKeySize+mlkem768.CiphertextSize { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid server key share") + } + ecdhePeerData = hs.serverHello.serverShare.data[:x25519PublicKeySize] + } + peerKey, err := hs.keyShareKeys.ecdhe.Curve().NewPublicKey(ecdhePeerData) if err != nil { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid server key share") } - sharedKey, err := hs.ecdheKey.ECDH(peerKey) + sharedKey, err := hs.keyShareKeys.ecdhe.ECDH(peerKey) if err != nil { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid server key share") } + if hs.serverHello.serverShare.group == x25519Kyber768Draft00 { + if hs.keyShareKeys.kyber == nil { + return c.sendAlert(alertInternalError) + } + ciphertext := hs.serverHello.serverShare.data[x25519PublicKeySize:] + kyberShared, err := kyberDecapsulate(hs.keyShareKeys.kyber, ciphertext) + if err != nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid Kyber server key share") + } + sharedKey = append(sharedKey, kyberShared...) + } + c.curveID = hs.serverHello.serverShare.group earlySecret := hs.earlySecret if !hs.usingPSK { @@ -478,6 +608,10 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error { return errors.New("tls: server accepted 0-RTT with the wrong ALPN") } } + if hs.echContext != nil && !hs.echContext.echRejected && encryptedExtensions.echRetryConfigs != nil { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: server sent ECH retry configs after accepting ECH") + } return nil } @@ -631,6 +765,13 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error { return nil } + if hs.echContext != nil && hs.echContext.echRejected { + if _, err := hs.c.writeHandshakeRecord(&certificateMsgTLS13{}, hs.transcript); err != nil { + return err + } + return nil + } + cert, err := c.getClientCertificate(&CertificateRequestInfo{ AcceptableCAs: hs.certReq.certificateAuthorities, SignatureSchemes: hs.certReq.supportedSignatureAlgorithms, @@ -753,17 +894,17 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error { psk := cipherSuite.expandLabel(c.resumptionSecret, "resumption", msg.nonce, cipherSuite.hash.Size()) - session, err := c.sessionState() - if err != nil { - c.sendAlert(alertInternalError) - return err - } + session := c.sessionState() session.secret = psk session.useBy = uint64(c.config.time().Add(lifetime).Unix()) session.ageAdd = msg.ageAdd session.EarlyData = c.quic != nil && msg.maxEarlyData == 0xffffffff // RFC 9001, Section 4.6.1 - cs := &ClientSessionState{ticket: msg.label, session: session} - + session.ticket = msg.label + if c.quic != nil && c.quic.enableSessionEvents { + c.quicStoreSession(session) + return nil + } + cs := &ClientSessionState{session: session} if cacheKey := c.clientSessionCacheKey(); cacheKey != "" { c.config.ClientSessionCache.Put(cacheKey, cs) } diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_messages.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_messages.go similarity index 84% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_messages.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_messages.go index a86055a06013..8620b66a4749 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_messages.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_messages.go @@ -7,6 +7,7 @@ package tls import ( "errors" "fmt" + "slices" "strings" "golang.org/x/crypto/cryptobyte" @@ -68,7 +69,7 @@ func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { } type clientHelloMsg struct { - raw []byte + original []byte vers uint16 random []byte sessionId []byte @@ -95,13 +96,10 @@ type clientHelloMsg struct { pskIdentities []pskIdentity pskBinders [][]byte quicTransportParameters []byte + encryptedClientHello []byte } -func (m *clientHelloMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - +func (m *clientHelloMsg) marshalMsg(echInner bool) ([]byte, error) { var exts cryptobyte.Builder if len(m.serverName) > 0 { // RFC 6066, Section 3 @@ -115,27 +113,7 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { }) }) } - if m.ocspStapling { - // RFC 4366, Section 3.6 - exts.AddUint16(extensionStatusRequest) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint8(1) // status_type = ocsp - exts.AddUint16(0) // empty responder_id_list - exts.AddUint16(0) // empty request_extensions - }) - } - if len(m.supportedCurves) > 0 { - // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 - exts.AddUint16(extensionSupportedCurves) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, curve := range m.supportedCurves { - exts.AddUint16(uint16(curve)) - } - }) - }) - } - if len(m.supportedPoints) > 0 { + if len(m.supportedPoints) > 0 && !echInner { // RFC 4492, Section 5.1.2 exts.AddUint16(extensionSupportedPoints) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { @@ -144,36 +122,14 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { }) }) } - if m.ticketSupported { + if m.ticketSupported && !echInner { // RFC 5077, Section 3.2 exts.AddUint16(extensionSessionTicket) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { exts.AddBytes(m.sessionTicket) }) } - if len(m.supportedSignatureAlgorithms) > 0 { - // RFC 5246, Section 7.4.1.4.1 - exts.AddUint16(extensionSignatureAlgorithms) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithms { - exts.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - if len(m.supportedSignatureAlgorithmsCert) > 0 { - // RFC 8446, Section 4.2.3 - exts.AddUint16(extensionSignatureAlgorithmsCert) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { - exts.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - if m.secureRenegotiationSupported { + if m.secureRenegotiationSupported && !echInner { // RFC 5746, Section 3.2 exts.AddUint16(extensionRenegotiationInfo) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { @@ -182,82 +138,181 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { }) }) } - if m.extendedMasterSecret { + if m.extendedMasterSecret && !echInner { // RFC 7627 exts.AddUint16(extensionExtendedMasterSecret) exts.AddUint16(0) // empty extension_data } - if len(m.alpnProtocols) > 0 { - // RFC 7301, Section 3.1 - exts.AddUint16(extensionALPN) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, proto := range m.alpnProtocols { - exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes([]byte(proto)) - }) - } - }) - }) - } if m.scts { // RFC 6962, Section 3.3.1 exts.AddUint16(extensionSCT) exts.AddUint16(0) // empty extension_data } + if m.earlyData { + // RFC 8446, Section 4.2.10 + exts.AddUint16(extensionEarlyData) + exts.AddUint16(0) // empty extension_data + } + if m.quicTransportParameters != nil { // marshal zero-length parameters when present + // RFC 9001, Section 8.2 + exts.AddUint16(extensionQUICTransportParameters) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.quicTransportParameters) + }) + } + if len(m.encryptedClientHello) > 0 { + exts.AddUint16(extensionEncryptedClientHello) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.encryptedClientHello) + }) + } + // Note that any extension that can be compressed during ECH must be + // contiguous. If any additional extensions are to be compressed they must + // be added to the following block, so that they can be properly + // decompressed on the other side. + var echOuterExts []uint16 + if m.ocspStapling { + // RFC 4366, Section 3.6 + if echInner { + echOuterExts = append(echOuterExts, extensionStatusRequest) + } else { + exts.AddUint16(extensionStatusRequest) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8(1) // status_type = ocsp + exts.AddUint16(0) // empty responder_id_list + exts.AddUint16(0) // empty request_extensions + }) + } + } + if len(m.supportedCurves) > 0 { + // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 + if echInner { + echOuterExts = append(echOuterExts, extensionSupportedCurves) + } else { + exts.AddUint16(extensionSupportedCurves) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, curve := range m.supportedCurves { + exts.AddUint16(uint16(curve)) + } + }) + }) + } + } + if len(m.supportedSignatureAlgorithms) > 0 { + // RFC 5246, Section 7.4.1.4.1 + if echInner { + echOuterExts = append(echOuterExts, extensionSignatureAlgorithms) + } else { + exts.AddUint16(extensionSignatureAlgorithms) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, sigAlgo := range m.supportedSignatureAlgorithms { + exts.AddUint16(uint16(sigAlgo)) + } + }) + }) + } + } + if len(m.supportedSignatureAlgorithmsCert) > 0 { + // RFC 8446, Section 4.2.3 + if echInner { + echOuterExts = append(echOuterExts, extensionSignatureAlgorithmsCert) + } else { + exts.AddUint16(extensionSignatureAlgorithmsCert) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { + exts.AddUint16(uint16(sigAlgo)) + } + }) + }) + } + } + if len(m.alpnProtocols) > 0 { + // RFC 7301, Section 3.1 + if echInner { + echOuterExts = append(echOuterExts, extensionALPN) + } else { + exts.AddUint16(extensionALPN) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, proto := range m.alpnProtocols { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes([]byte(proto)) + }) + } + }) + }) + } + } if len(m.supportedVersions) > 0 { // RFC 8446, Section 4.2.1 - exts.AddUint16(extensionSupportedVersions) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, vers := range m.supportedVersions { - exts.AddUint16(vers) - } + if echInner { + echOuterExts = append(echOuterExts, extensionSupportedVersions) + } else { + exts.AddUint16(extensionSupportedVersions) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, vers := range m.supportedVersions { + exts.AddUint16(vers) + } + }) }) - }) + } } if len(m.cookie) > 0 { // RFC 8446, Section 4.2.2 - exts.AddUint16(extensionCookie) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + if echInner { + echOuterExts = append(echOuterExts, extensionCookie) + } else { + exts.AddUint16(extensionCookie) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes(m.cookie) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.cookie) + }) }) - }) + } } if len(m.keyShares) > 0 { // RFC 8446, Section 4.2.8 - exts.AddUint16(extensionKeyShare) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + if echInner { + echOuterExts = append(echOuterExts, extensionKeyShare) + } else { + exts.AddUint16(extensionKeyShare) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, ks := range m.keyShares { - exts.AddUint16(uint16(ks.group)) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes(ks.data) - }) - } + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, ks := range m.keyShares { + exts.AddUint16(uint16(ks.group)) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(ks.data) + }) + } + }) }) - }) - } - if m.earlyData { - // RFC 8446, Section 4.2.10 - exts.AddUint16(extensionEarlyData) - exts.AddUint16(0) // empty extension_data + } } if len(m.pskModes) > 0 { // RFC 8446, Section 4.2.9 - exts.AddUint16(extensionPSKModes) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes(m.pskModes) + if echInner { + echOuterExts = append(echOuterExts, extensionPSKModes) + } else { + exts.AddUint16(extensionPSKModes) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.pskModes) + }) }) - }) + } } - if m.quicTransportParameters != nil { // marshal zero-length parameters when present - // RFC 9001, Section 8.2 - exts.AddUint16(extensionQUICTransportParameters) + if len(echOuterExts) > 0 && echInner { + exts.AddUint16(extensionECHOuterExtensions) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes(m.quicTransportParameters) + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, e := range echOuterExts { + exts.AddUint16(e) + } + }) }) } if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension @@ -292,7 +347,9 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { b.AddUint16(m.vers) addBytesWithLength(b, m.random, 32) b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.sessionId) + if !echInner { + b.AddBytes(m.sessionId) + } }) b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { for _, suite := range m.cipherSuites { @@ -310,8 +367,11 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { } }) - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() +} + +func (m *clientHelloMsg) marshal() ([]byte, error) { + return m.marshalMsg(false) } // marshalWithoutBinders returns the ClientHello through the @@ -324,16 +384,21 @@ func (m *clientHelloMsg) marshalWithoutBinders() ([]byte, error) { bindersLen += len(binder) } - fullMessage, err := m.marshal() - if err != nil { - return nil, err + var fullMessage []byte + if m.original != nil { + fullMessage = m.original + } else { + var err error + fullMessage, err = m.marshal() + if err != nil { + return nil, err + } } return fullMessage[:len(fullMessage)-bindersLen], nil } -// updateBinders updates the m.pskBinders field, if necessary updating the -// cached marshaled representation. The supplied binders must have the same -// length as the current m.pskBinders. +// updateBinders updates the m.pskBinders field. The supplied binders must have +// the same length as the current m.pskBinders. func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error { if len(pskBinders) != len(m.pskBinders) { return errors.New("tls: internal error: pskBinders length mismatch") @@ -344,30 +409,12 @@ func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error { } } m.pskBinders = pskBinders - if m.raw != nil { - helloBytes, err := m.marshalWithoutBinders() - if err != nil { - return err - } - lenWithoutBinders := len(helloBytes) - b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders]) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, binder := range m.pskBinders { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(binder) - }) - } - }) - if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) { - return errors.New("tls: internal error: failed to update binders") - } - } return nil } func (m *clientHelloMsg) unmarshal(data []byte) bool { - *m = clientHelloMsg{raw: data} + *m = clientHelloMsg{original: data} s := cryptobyte.String(data) if !s.Skip(4) || // message type and uint24 length field @@ -625,8 +672,45 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return true } +func (m *clientHelloMsg) originalBytes() []byte { + return m.original +} + +func (m *clientHelloMsg) clone() *clientHelloMsg { + return &clientHelloMsg{ + original: slices.Clone(m.original), + vers: m.vers, + random: slices.Clone(m.random), + sessionId: slices.Clone(m.sessionId), + cipherSuites: slices.Clone(m.cipherSuites), + compressionMethods: slices.Clone(m.compressionMethods), + serverName: m.serverName, + ocspStapling: m.ocspStapling, + supportedCurves: slices.Clone(m.supportedCurves), + supportedPoints: slices.Clone(m.supportedPoints), + ticketSupported: m.ticketSupported, + sessionTicket: slices.Clone(m.sessionTicket), + supportedSignatureAlgorithms: slices.Clone(m.supportedSignatureAlgorithms), + supportedSignatureAlgorithmsCert: slices.Clone(m.supportedSignatureAlgorithmsCert), + secureRenegotiationSupported: m.secureRenegotiationSupported, + secureRenegotiation: slices.Clone(m.secureRenegotiation), + extendedMasterSecret: m.extendedMasterSecret, + alpnProtocols: slices.Clone(m.alpnProtocols), + scts: m.scts, + supportedVersions: slices.Clone(m.supportedVersions), + cookie: slices.Clone(m.cookie), + keyShares: slices.Clone(m.keyShares), + earlyData: m.earlyData, + pskModes: slices.Clone(m.pskModes), + pskIdentities: slices.Clone(m.pskIdentities), + pskBinders: slices.Clone(m.pskBinders), + quicTransportParameters: slices.Clone(m.quicTransportParameters), + encryptedClientHello: slices.Clone(m.encryptedClientHello), + } +} + type serverHelloMsg struct { - raw []byte + original []byte vers uint16 random []byte sessionId []byte @@ -644,6 +728,8 @@ type serverHelloMsg struct { selectedIdentityPresent bool selectedIdentity uint16 supportedPoints []uint8 + encryptedClientHello []byte + serverNameAck bool // HelloRetryRequest extensions cookie []byte @@ -651,10 +737,6 @@ type serverHelloMsg struct { } func (m *serverHelloMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var exts cryptobyte.Builder if m.ocspStapling { exts.AddUint16(extensionStatusRequest) @@ -742,6 +824,16 @@ func (m *serverHelloMsg) marshal() ([]byte, error) { }) }) } + if len(m.encryptedClientHello) > 0 { + exts.AddUint16(extensionEncryptedClientHello) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.encryptedClientHello) + }) + } + if m.serverNameAck { + exts.AddUint16(extensionServerName) + exts.AddUint16(0) + } extBytes, err := exts.Bytes() if err != nil { @@ -766,12 +858,11 @@ func (m *serverHelloMsg) marshal() ([]byte, error) { } }) - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *serverHelloMsg) unmarshal(data []byte) bool { - *m = serverHelloMsg{raw: data} + *m = serverHelloMsg{original: data} s := cryptobyte.String(data) if !s.Skip(4) || // message type and uint24 length field @@ -875,6 +966,16 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { len(m.supportedPoints) == 0 { return false } + case extensionEncryptedClientHello: // encrypted_client_hello + m.encryptedClientHello = make([]byte, len(extData)) + if !extData.CopyBytes(m.encryptedClientHello) { + return false + } + case extensionServerName: + if len(extData) != 0 { + return false + } + m.serverNameAck = true default: // Ignore unknown extensions. continue @@ -888,18 +989,18 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return true } +func (m *serverHelloMsg) originalBytes() []byte { + return m.original +} + type encryptedExtensionsMsg struct { - raw []byte alpnProtocol string quicTransportParameters []byte earlyData bool + echRetryConfigs []byte } func (m *encryptedExtensionsMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeEncryptedExtensions) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -926,16 +1027,20 @@ func (m *encryptedExtensionsMsg) marshal() ([]byte, error) { b.AddUint16(extensionEarlyData) b.AddUint16(0) // empty extension_data } + if len(m.echRetryConfigs) > 0 { + b.AddUint16(extensionEncryptedClientHello) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.echRetryConfigs) + }) + } }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { - *m = encryptedExtensionsMsg{raw: data} + *m = encryptedExtensionsMsg{} s := cryptobyte.String(data) var extensions cryptobyte.String @@ -972,6 +1077,11 @@ func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { case extensionEarlyData: // RFC 8446, Section 4.2.10 m.earlyData = true + case extensionEncryptedClientHello: + m.echRetryConfigs = make([]byte, len(extData)) + if !extData.CopyBytes(m.echRetryConfigs) { + return false + } default: // Ignore unknown extensions. continue @@ -998,15 +1108,10 @@ func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool { } type keyUpdateMsg struct { - raw []byte updateRequested bool } func (m *keyUpdateMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeKeyUpdate) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1017,13 +1122,10 @@ func (m *keyUpdateMsg) marshal() ([]byte, error) { } }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *keyUpdateMsg) unmarshal(data []byte) bool { - m.raw = data s := cryptobyte.String(data) var updateRequested uint8 @@ -1043,7 +1145,6 @@ func (m *keyUpdateMsg) unmarshal(data []byte) bool { } type newSessionTicketMsgTLS13 struct { - raw []byte lifetime uint32 ageAdd uint32 nonce []byte @@ -1052,10 +1153,6 @@ type newSessionTicketMsgTLS13 struct { } func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeNewSessionTicket) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1078,13 +1175,11 @@ func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) { }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool { - *m = newSessionTicketMsgTLS13{raw: data} + *m = newSessionTicketMsgTLS13{} s := cryptobyte.String(data) var extensions cryptobyte.String @@ -1125,7 +1220,6 @@ func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool { } type certificateRequestMsgTLS13 struct { - raw []byte ocspStapling bool scts bool supportedSignatureAlgorithms []SignatureScheme @@ -1134,10 +1228,6 @@ type certificateRequestMsgTLS13 struct { } func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeCertificateRequest) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1194,13 +1284,11 @@ func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) { }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool { - *m = certificateRequestMsgTLS13{raw: data} + *m = certificateRequestMsgTLS13{} s := cryptobyte.String(data) var context, extensions cryptobyte.String @@ -1276,15 +1364,10 @@ func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool { } type certificateMsg struct { - raw []byte certificates [][]byte } func (m *certificateMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var i int for _, slice := range m.certificates { i += len(slice) @@ -1311,8 +1394,7 @@ func (m *certificateMsg) marshal() ([]byte, error) { y = y[3+len(slice):] } - m.raw = x - return m.raw, nil + return x, nil } func (m *certificateMsg) unmarshal(data []byte) bool { @@ -1320,7 +1402,6 @@ func (m *certificateMsg) unmarshal(data []byte) bool { return false } - m.raw = data certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]) if uint32(len(data)) != certsLen+7 { return false @@ -1353,17 +1434,12 @@ func (m *certificateMsg) unmarshal(data []byte) bool { } type certificateMsgTLS13 struct { - raw []byte certificate Certificate ocspStapling bool scts bool } func (m *certificateMsgTLS13) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeCertificate) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1379,9 +1455,7 @@ func (m *certificateMsgTLS13) marshal() ([]byte, error) { marshalCertificate(b, certificate) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) { @@ -1422,7 +1496,7 @@ func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) { } func (m *certificateMsgTLS13) unmarshal(data []byte) bool { - *m = certificateMsgTLS13{raw: data} + *m = certificateMsgTLS13{} s := cryptobyte.String(data) var context cryptobyte.String @@ -1500,14 +1574,10 @@ func unmarshalCertificate(s *cryptobyte.String, certificate *Certificate) bool { } type serverKeyExchangeMsg struct { - raw []byte key []byte } func (m *serverKeyExchangeMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } length := len(m.key) x := make([]byte, length+4) x[0] = typeServerKeyExchange @@ -1516,12 +1586,10 @@ func (m *serverKeyExchangeMsg) marshal() ([]byte, error) { x[3] = uint8(length) copy(x[4:], m.key) - m.raw = x return x, nil } func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { - m.raw = data if len(data) < 4 { return false } @@ -1530,15 +1598,10 @@ func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { } type certificateStatusMsg struct { - raw []byte response []byte } func (m *certificateStatusMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeCertificateStatus) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1548,13 +1611,10 @@ func (m *certificateStatusMsg) marshal() ([]byte, error) { }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *certificateStatusMsg) unmarshal(data []byte) bool { - m.raw = data s := cryptobyte.String(data) var statusType uint8 @@ -1580,14 +1640,10 @@ func (m *serverHelloDoneMsg) unmarshal(data []byte) bool { } type clientKeyExchangeMsg struct { - raw []byte ciphertext []byte } func (m *clientKeyExchangeMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } length := len(m.ciphertext) x := make([]byte, length+4) x[0] = typeClientKeyExchange @@ -1596,12 +1652,10 @@ func (m *clientKeyExchangeMsg) marshal() ([]byte, error) { x[3] = uint8(length) copy(x[4:], m.ciphertext) - m.raw = x return x, nil } func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { - m.raw = data if len(data) < 4 { return false } @@ -1614,28 +1668,20 @@ func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { } type finishedMsg struct { - raw []byte verifyData []byte } func (m *finishedMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeFinished) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(m.verifyData) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *finishedMsg) unmarshal(data []byte) bool { - m.raw = data s := cryptobyte.String(data) return s.Skip(1) && readUint24LengthPrefixed(&s, &m.verifyData) && @@ -1643,7 +1689,6 @@ func (m *finishedMsg) unmarshal(data []byte) bool { } type certificateRequestMsg struct { - raw []byte // hasSignatureAlgorithm indicates whether this message includes a list of // supported signature algorithms. This change was introduced with TLS 1.2. hasSignatureAlgorithm bool @@ -1654,10 +1699,6 @@ type certificateRequestMsg struct { } func (m *certificateRequestMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - // See RFC 4346, Section 7.4.4. length := 1 + len(m.certificateTypes) + 2 casLength := 0 @@ -1704,13 +1745,10 @@ func (m *certificateRequestMsg) marshal() ([]byte, error) { y = y[len(ca):] } - m.raw = x - return m.raw, nil + return x, nil } func (m *certificateRequestMsg) unmarshal(data []byte) bool { - m.raw = data - if len(data) < 5 { return false } @@ -1785,17 +1823,12 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool { } type certificateVerifyMsg struct { - raw []byte hasSignatureAlgorithm bool // format change introduced in TLS 1.2 signatureAlgorithm SignatureScheme signature []byte } func (m *certificateVerifyMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeCertificateVerify) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1807,13 +1840,10 @@ func (m *certificateVerifyMsg) marshal() ([]byte, error) { }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *certificateVerifyMsg) unmarshal(data []byte) bool { - m.raw = data s := cryptobyte.String(data) if !s.Skip(4) { // message type and uint24 length field @@ -1828,15 +1858,10 @@ func (m *certificateVerifyMsg) unmarshal(data []byte) bool { } type newSessionTicketMsg struct { - raw []byte ticket []byte } func (m *newSessionTicketMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - // See RFC 5077, Section 3.3. ticketLen := len(m.ticket) length := 2 + 4 + ticketLen @@ -1849,14 +1874,10 @@ func (m *newSessionTicketMsg) marshal() ([]byte, error) { x[9] = uint8(ticketLen) copy(x[10:], m.ticket) - m.raw = x - - return m.raw, nil + return x, nil } func (m *newSessionTicketMsg) unmarshal(data []byte) bool { - m.raw = data - if len(data) < 10 { return false } @@ -1891,9 +1912,25 @@ type transcriptHash interface { Write([]byte) (int, error) } -// transcriptMsg is a helper used to marshal and hash messages which typically -// are not written to the wire, and as such aren't hashed during Conn.writeRecord. +// transcriptMsg is a helper used to hash messages which are not hashed when +// they are read from, or written to, the wire. This is typically the case for +// messages which are either not sent, or need to be hashed out of order from +// when they are read/written. +// +// For most messages, the message is marshalled using their marshal method, +// since their wire representation is idempotent. For clientHelloMsg and +// serverHelloMsg, we store the original wire representation of the message and +// use that for hashing, since unmarshal/marshal are not idempotent due to +// extension ordering and other malleable fields, which may cause differences +// between what was received and what we marshal. func transcriptMsg(msg handshakeMessage, h transcriptHash) error { + if msgWithOrig, ok := msg.(handshakeMessageWithOriginalBytes); ok { + if orig := msgWithOrig.originalBytes(); orig != nil { + h.Write(msgWithOrig.originalBytes()) + return nil + } + } + data, err := msg.marshal() if err != nil { return err diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_server.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_server.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_server.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_server.go index 4e84aa9d8f0a..ac3d915d1746 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_server.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_server.go @@ -15,6 +15,7 @@ import ( "errors" "fmt" "hash" + "internal/byteorder" "io" "time" ) @@ -169,6 +170,7 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) { c.out.version = c.vers if c.config.MinVersion == 0 && c.vers < VersionTLS12 { + tls10server.Value() // ensure godebug is initialized tls10server.IncNonDefault() } @@ -246,7 +248,7 @@ func (hs *serverHandshakeState) processClientHello() error { hs.hello.scts = hs.cert.SignedCertificateTimestamps } - hs.ecdheOk = supportsECDHE(c.config, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints) + hs.ecdheOk = supportsECDHE(c.config, c.vers, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints) if hs.ecdheOk && len(hs.clientHello.supportedPoints) > 0 { // Although omitting the ec_point_formats extension is permitted, some @@ -317,10 +319,10 @@ func negotiateALPN(serverProtos, clientProtos []string, quic bool) (string, erro // supportsECDHE returns whether ECDHE key exchanges can be used with this // pre-TLS 1.3 client. -func supportsECDHE(c *Config, supportedCurves []CurveID, supportedPoints []uint8) bool { +func supportsECDHE(c *Config, version uint16, supportedCurves []CurveID, supportedPoints []uint8) bool { supportsCurve := false for _, curve := range supportedCurves { - if c.supportsCurve(curve) { + if c.supportsCurve(version, curve) { supportsCurve = true break } @@ -371,8 +373,13 @@ func (hs *serverHandshakeState) pickCipherSuite() error { c.cipherSuite = hs.suite.id if c.config.CipherSuites == nil && !needFIPS() && rsaKexCiphers[hs.suite.id] { + tlsrsakex.Value() // ensure godebug is initialized tlsrsakex.IncNonDefault() } + if c.config.CipherSuites == nil && !needFIPS() && tdesCiphers[hs.suite.id] { + tls3des.Value() // ensure godebug is initialized + tls3des.IncNonDefault() + } for _, id := range hs.clientHello.cipherSuites { if id == TLS_FALLBACK_SCSV { @@ -585,6 +592,9 @@ func (hs *serverHandshakeState) doFullHandshake() error { return err } if skx != nil { + if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ { + c.curveID = CurveID(byteorder.BeUint16(skx.key[1:])) + } if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil { return err } @@ -810,10 +820,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error { c := hs.c m := new(newSessionTicketMsg) - state, err := c.sessionState() - if err != nil { - return err - } + state := c.sessionState() state.secret = hs.masterSecret if hs.sessionState != nil { // If this is re-wrapping an old key, then keep @@ -821,6 +828,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error { state.createdAt = hs.sessionState.createdAt } if c.config.WrapSession != nil { + var err error m.ticket, err = c.config.WrapSession(c.connectionStateLocked(), state) if err != nil { return err diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_server_tls13.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_server_tls13.go similarity index 90% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_server_tls13.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_server_tls13.go index 21d798de37db..503a732e0576 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_server_tls13.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_server_tls13.go @@ -9,11 +9,13 @@ import ( "context" "crypto" "crypto/hmac" + "crypto/internal/mlkem768" "crypto/rsa" - "encoding/binary" "errors" "hash" + "internal/byteorder" "io" + "slices" "time" ) @@ -177,25 +179,29 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { hs.hello.cipherSuite = hs.suite.id hs.transcript = hs.suite.hash.New() - // Pick the ECDHE group in server preference order, but give priority to - // groups with a key share, to avoid a HelloRetryRequest round-trip. + // Pick the key exchange method in server preference order, but give + // priority to key shares, to avoid a HelloRetryRequest round-trip. var selectedGroup CurveID var clientKeyShare *keyShare -GroupSelection: - for _, preferredGroup := range c.config.curvePreferences() { - for _, ks := range hs.clientHello.keyShares { - if ks.group == preferredGroup { - selectedGroup = ks.group - clientKeyShare = &ks - break GroupSelection + preferredGroups := c.config.curvePreferences(c.vers) + for _, preferredGroup := range preferredGroups { + ki := slices.IndexFunc(hs.clientHello.keyShares, func(ks keyShare) bool { + return ks.group == preferredGroup + }) + if ki != -1 { + clientKeyShare = &hs.clientHello.keyShares[ki] + selectedGroup = clientKeyShare.group + if !slices.Contains(hs.clientHello.supportedCurves, selectedGroup) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client sent key share for group it does not support") } + break } - if selectedGroup != 0 { - continue - } - for _, group := range hs.clientHello.supportedCurves { - if group == preferredGroup { - selectedGroup = group + } + if selectedGroup == 0 { + for _, preferredGroup := range preferredGroups { + if slices.Contains(hs.clientHello.supportedCurves, preferredGroup) { + selectedGroup = preferredGroup break } } @@ -205,23 +211,35 @@ GroupSelection: return errors.New("tls: no ECDHE curve supported by both client and server") } if clientKeyShare == nil { - if err := hs.doHelloRetryRequest(selectedGroup); err != nil { + ks, err := hs.doHelloRetryRequest(selectedGroup) + if err != nil { return err } - clientKeyShare = &hs.clientHello.keyShares[0] + clientKeyShare = ks } + c.curveID = selectedGroup - if _, ok := curveForCurveID(selectedGroup); !ok { + ecdhGroup := selectedGroup + ecdhData := clientKeyShare.data + if selectedGroup == x25519Kyber768Draft00 { + ecdhGroup = X25519 + if len(ecdhData) != x25519PublicKeySize+mlkem768.EncapsulationKeySize { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid Kyber client key share") + } + ecdhData = ecdhData[:x25519PublicKeySize] + } + if _, ok := curveForCurveID(ecdhGroup); !ok { c.sendAlert(alertInternalError) return errors.New("tls: CurvePreferences includes unsupported curve") } - key, err := generateECDHEKey(c.config.rand(), selectedGroup) + key, err := generateECDHEKey(c.config.rand(), ecdhGroup) if err != nil { c.sendAlert(alertInternalError) return err } hs.hello.serverShare = keyShare{group: selectedGroup, data: key.PublicKey().Bytes()} - peerKey, err := key.Curve().NewPublicKey(clientKeyShare.data) + peerKey, err := key.Curve().NewPublicKey(ecdhData) if err != nil { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid client key share") @@ -231,6 +249,15 @@ GroupSelection: c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid client key share") } + if selectedGroup == x25519Kyber768Draft00 { + ciphertext, kyberShared, err := kyberEncapsulate(clientKeyShare.data[x25519PublicKeySize:]) + if err != nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid Kyber client key share") + } + hs.sharedKey = append(hs.sharedKey, kyberShared...) + hs.hello.serverShare.data = append(hs.hello.serverShare.data, ciphertext...) + } selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil) if err != nil { @@ -350,6 +377,12 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error { continue } + if c.quic != nil && c.quic.enableSessionEvents { + if err := c.quicResumeSession(sessionState); err != nil { + return err + } + } + hs.earlySecret = hs.suite.extract(sessionState.secret, nil) binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil) // Clone the transcript in case a HelloRetryRequest was recorded. @@ -474,13 +507,13 @@ func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error { return hs.c.writeChangeCipherRecord() } -func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error { +func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) (*keyShare, error) { c := hs.c // The first ClientHello gets double-hashed into the transcript upon a // HelloRetryRequest. See RFC 8446, Section 4.4.1. if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil { - return err + return nil, err } chHash := hs.transcript.Sum(nil) hs.transcript.Reset() @@ -498,42 +531,49 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) } if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil { - return err + return nil, err } if err := hs.sendDummyChangeCipherSpec(); err != nil { - return err + return nil, err } // clientHelloMsg is not included in the transcript. msg, err := c.readHandshake(nil) if err != nil { - return err + return nil, err } clientHello, ok := msg.(*clientHelloMsg) if !ok { c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(clientHello, msg) + return nil, unexpectedMessageError(clientHello, msg) + } + + if len(clientHello.keyShares) != 1 { + c.sendAlert(alertIllegalParameter) + return nil, errors.New("tls: client didn't send one key share in second ClientHello") } + ks := &clientHello.keyShares[0] - if len(clientHello.keyShares) != 1 || clientHello.keyShares[0].group != selectedGroup { + if ks.group != selectedGroup { c.sendAlert(alertIllegalParameter) - return errors.New("tls: client sent invalid key share in second ClientHello") + return nil, errors.New("tls: client sent unexpected key share in second ClientHello") } if clientHello.earlyData { c.sendAlert(alertIllegalParameter) - return errors.New("tls: client indicated early data in second ClientHello") + return nil, errors.New("tls: client indicated early data in second ClientHello") } if illegalClientHelloChange(clientHello, hs.clientHello) { c.sendAlert(alertIllegalParameter) - return errors.New("tls: client illegally modified second ClientHello") + return nil, errors.New("tls: client illegally modified second ClientHello") } + c.didHRR = true hs.clientHello = clientHello - return nil + return ks, nil } // illegalClientHelloChange reports whether the two ClientHello messages are @@ -822,10 +862,10 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { if !hs.shouldSendSessionTickets() { return nil } - return c.sendSessionTicket(false) + return c.sendSessionTicket(false, nil) } -func (c *Conn) sendSessionTicket(earlyData bool) error { +func (c *Conn) sendSessionTicket(earlyData bool, extra [][]byte) error { suite := cipherSuiteTLS13ByID(c.cipherSuite) if suite == nil { return errors.New("tls: internal error: unknown cipher suite") @@ -837,13 +877,12 @@ func (c *Conn) sendSessionTicket(earlyData bool) error { m := new(newSessionTicketMsgTLS13) - state, err := c.sessionState() - if err != nil { - return err - } + state := c.sessionState() state.secret = psk state.EarlyData = earlyData + state.Extra = extra if c.config.WrapSession != nil { + var err error m.label, err = c.config.WrapSession(c.connectionStateLocked(), state) if err != nil { return err @@ -865,11 +904,10 @@ func (c *Conn) sendSessionTicket(earlyData bool) error { // The value is not stored anywhere; we never need to check the ticket age // because 0-RTT is not supported. ageAdd := make([]byte, 4) - _, err = c.config.rand().Read(ageAdd) - if err != nil { + if _, err := c.config.rand().Read(ageAdd); err != nil { return err } - m.ageAdd = binary.LittleEndian.Uint32(ageAdd) + m.ageAdd = byteorder.LeUint32(ageAdd) if earlyData { // RFC 9001, Section 4.6.1 diff --git a/contrib/go/_std_1.22/src/crypto/tls/key_agreement.go b/contrib/go/_std_1.23/src/crypto/tls/key_agreement.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/tls/key_agreement.go rename to contrib/go/_std_1.23/src/crypto/tls/key_agreement.go index 2c8c5b8d7713..3e96242b9798 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/key_agreement.go +++ b/contrib/go/_std_1.23/src/crypto/tls/key_agreement.go @@ -16,8 +16,8 @@ import ( "io" ) -// a keyAgreement implements the client and server side of a TLS key agreement -// protocol by generating and processing key exchange messages. +// A keyAgreement implements the client and server side of a TLS 1.0–1.2 key +// agreement protocol by generating and processing key exchange messages. type keyAgreement interface { // On the server side, the first two methods are called in order. @@ -126,7 +126,7 @@ func md5SHA1Hash(slices [][]byte) []byte { } // hashForServerKeyExchange hashes the given slices and returns their digest -// using the given hash function (for >= TLS 1.2) or using a default based on +// using the given hash function (for TLS 1.2) or using a default based on // the sigType (for earlier TLS versions). For Ed25519 signatures, which don't // do pre-hashing, it returns the concatenation of the slices. func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte { @@ -169,7 +169,7 @@ type ecdheKeyAgreement struct { func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { var curveID CurveID for _, c := range clientHello.supportedCurves { - if config.supportsCurve(c) { + if config.supportsCurve(ka.version, c) { curveID = c break } diff --git a/contrib/go/_std_1.22/src/crypto/tls/key_schedule.go b/contrib/go/_std_1.23/src/crypto/tls/key_schedule.go similarity index 82% rename from contrib/go/_std_1.22/src/crypto/tls/key_schedule.go rename to contrib/go/_std_1.23/src/crypto/tls/key_schedule.go index d7f082c9ee1e..1636baf79e72 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/key_schedule.go +++ b/contrib/go/_std_1.23/src/crypto/tls/key_schedule.go @@ -7,6 +7,7 @@ package tls import ( "crypto/ecdh" "crypto/hmac" + "crypto/internal/mlkem768" "errors" "fmt" "hash" @@ -14,6 +15,7 @@ import ( "golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/hkdf" + "golang.org/x/crypto/sha3" ) // This file contains the functions necessary to compute the TLS 1.3 key @@ -117,6 +119,45 @@ func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript } } +type keySharePrivateKeys struct { + curveID CurveID + ecdhe *ecdh.PrivateKey + kyber *mlkem768.DecapsulationKey +} + +// kyberDecapsulate implements decapsulation according to Kyber Round 3. +func kyberDecapsulate(dk *mlkem768.DecapsulationKey, c []byte) ([]byte, error) { + K, err := mlkem768.Decapsulate(dk, c) + if err != nil { + return nil, err + } + return kyberSharedSecret(K, c), nil +} + +// kyberEncapsulate implements encapsulation according to Kyber Round 3. +func kyberEncapsulate(ek []byte) (c, ss []byte, err error) { + c, ss, err = mlkem768.Encapsulate(ek) + if err != nil { + return nil, nil, err + } + return c, kyberSharedSecret(ss, c), nil +} + +func kyberSharedSecret(K, c []byte) []byte { + // Package mlkem768 implements ML-KEM, which compared to Kyber removed a + // final hashing step. Compute SHAKE-256(K || SHA3-256(c), 32) to match Kyber. + // See https://words.filippo.io/mlkem768/#bonus-track-using-a-ml-kem-implementation-as-kyber-v3. + h := sha3.NewShake256() + h.Write(K) + ch := sha3.Sum256(c) + h.Write(ch[:]) + out := make([]byte, 32) + h.Read(out) + return out +} + +const x25519PublicKeySize = 32 + // generateECDHEKey returns a PrivateKey that implements Diffie-Hellman // according to RFC 8446, Section 4.2.8.2. func generateECDHEKey(rand io.Reader, curveID CurveID) (*ecdh.PrivateKey, error) { diff --git a/contrib/go/_std_1.23/src/crypto/tls/notboring.go b/contrib/go/_std_1.23/src/crypto/tls/notboring.go new file mode 100644 index 000000000000..bdbc32e05b35 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/notboring.go @@ -0,0 +1,9 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !boringcrypto + +package tls + +func needFIPS() bool { return false } diff --git a/contrib/go/_std_1.22/src/crypto/tls/prf.go b/contrib/go/_std_1.23/src/crypto/tls/prf.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/prf.go rename to contrib/go/_std_1.23/src/crypto/tls/prf.go diff --git a/contrib/go/_std_1.22/src/crypto/tls/quic.go b/contrib/go/_std_1.23/src/crypto/tls/quic.go similarity index 80% rename from contrib/go/_std_1.22/src/crypto/tls/quic.go rename to contrib/go/_std_1.23/src/crypto/tls/quic.go index 3518169bf729..9dd6168b6235 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/quic.go +++ b/contrib/go/_std_1.23/src/crypto/tls/quic.go @@ -49,6 +49,13 @@ type QUICConn struct { // A QUICConfig configures a [QUICConn]. type QUICConfig struct { TLSConfig *Config + + // EnableSessionEvents may be set to true to enable the + // [QUICStoreSession] and [QUICResumeSession] events for client connections. + // When this event is enabled, sessions are not automatically + // stored in the client session cache. + // The application should use [QUICConn.StoreSession] to store sessions. + EnableSessionEvents bool } // A QUICEventKind is a type of operation on a QUIC connection. @@ -87,10 +94,29 @@ const ( // QUICRejectedEarlyData indicates that the server rejected 0-RTT data even // if we offered it. It's returned before QUICEncryptionLevelApplication // keys are returned. + // This event only occurs on client connections. QUICRejectedEarlyData // QUICHandshakeDone indicates that the TLS handshake has completed. QUICHandshakeDone + + // QUICResumeSession indicates that a client is attempting to resume a previous session. + // [QUICEvent.SessionState] is set. + // + // For client connections, this event occurs when the session ticket is selected. + // For server connections, this event occurs when receiving the client's session ticket. + // + // The application may set [QUICEvent.SessionState.EarlyData] to false before the + // next call to [QUICConn.NextEvent] to decline 0-RTT even if the session supports it. + QUICResumeSession + + // QUICStoreSession indicates that the server has provided state permitting + // the client to resume the session. + // [QUICEvent.SessionState] is set. + // The application should use [QUICConn.StoreSession] session to store the [SessionState]. + // The application may modify the [SessionState] before storing it. + // This event only occurs on client connections. + QUICStoreSession ) // A QUICEvent is an event occurring on a QUIC connection. @@ -109,6 +135,9 @@ type QUICEvent struct { // Set for QUICSetReadSecret and QUICSetWriteSecret. Suite uint16 + + // Set for QUICResumeSession and QUICStoreSession. + SessionState *SessionState } type quicState struct { @@ -127,12 +156,16 @@ type quicState struct { cancelc <-chan struct{} // handshake has been canceled cancel context.CancelFunc + waitingForDrain bool + // readbuf is shared between HandleData and the handshake goroutine. // HandshakeCryptoData passes ownership to the handshake goroutine by // reading from signalc, and reclaims ownership by reading from blockedc. readbuf []byte transportParams []byte // to send to the peer + + enableSessionEvents bool } // QUICClient returns a new TLS client side connection using QUICTransport as the @@ -140,7 +173,7 @@ type quicState struct { // // The config's MinVersion must be at least TLS 1.3. func QUICClient(config *QUICConfig) *QUICConn { - return newQUICConn(Client(nil, config.TLSConfig)) + return newQUICConn(Client(nil, config.TLSConfig), config) } // QUICServer returns a new TLS server side connection using QUICTransport as the @@ -148,13 +181,14 @@ func QUICClient(config *QUICConfig) *QUICConn { // // The config's MinVersion must be at least TLS 1.3. func QUICServer(config *QUICConfig) *QUICConn { - return newQUICConn(Server(nil, config.TLSConfig)) + return newQUICConn(Server(nil, config.TLSConfig), config) } -func newQUICConn(conn *Conn) *QUICConn { +func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn { conn.quic = &quicState{ - signalc: make(chan struct{}), - blockedc: make(chan struct{}), + signalc: make(chan struct{}), + blockedc: make(chan struct{}), + enableSessionEvents: config.EnableSessionEvents, } conn.quic.events = conn.quic.eventArr[:0] return &QUICConn{ @@ -190,6 +224,11 @@ func (q *QUICConn) NextEvent() QUICEvent { // to catch callers erroniously retaining it. qs.events[last].Data[0] = 0 } + if qs.nextEvent >= len(qs.events) && qs.waitingForDrain { + qs.waitingForDrain = false + <-qs.signalc + <-qs.blockedc + } if qs.nextEvent >= len(qs.events) { qs.events = qs.events[:0] qs.nextEvent = 0 @@ -255,6 +294,7 @@ func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error { type QUICSessionTicketOptions struct { // EarlyData specifies whether the ticket may be used for 0-RTT. EarlyData bool + Extra [][]byte } // SendSessionTicket sends a session ticket to the client. @@ -272,7 +312,25 @@ func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error { return quicError(errors.New("tls: SendSessionTicket called multiple times")) } q.sessionTicketSent = true - return quicError(c.sendSessionTicket(opts.EarlyData)) + return quicError(c.sendSessionTicket(opts.EarlyData, opts.Extra)) +} + +// StoreSession stores a session previously received in a QUICStoreSession event +// in the ClientSessionCache. +// The application may process additional events or modify the SessionState +// before storing the session. +func (q *QUICConn) StoreSession(session *SessionState) error { + c := q.conn + if !c.isClient { + return quicError(errors.New("tls: StoreSessionTicket called on the server")) + } + cacheKey := c.clientSessionCacheKey() + if cacheKey == "" { + return nil + } + cs := &ClientSessionState{session: session} + c.config.ClientSessionCache.Put(cacheKey, cs) + return nil } // ConnectionState returns basic TLS details about the connection. @@ -356,6 +414,27 @@ func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) { last.Data = append(last.Data, data...) } +func (c *Conn) quicResumeSession(session *SessionState) error { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICResumeSession, + SessionState: session, + }) + c.quic.waitingForDrain = true + for c.quic.waitingForDrain { + if err := c.quicWaitForSignal(); err != nil { + return err + } + } + return nil +} + +func (c *Conn) quicStoreSession(session *SessionState) { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICStoreSession, + SessionState: session, + }) +} + func (c *Conn) quicSetTransportParameters(params []byte) { c.quic.events = append(c.quic.events, QUICEvent{ Kind: QUICTransportParameters, diff --git a/contrib/go/_std_1.22/src/crypto/tls/ticket.go b/contrib/go/_std_1.23/src/crypto/tls/ticket.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/tls/ticket.go rename to contrib/go/_std_1.23/src/crypto/tls/ticket.go index b71e3afdb211..06aec5aa63f9 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/ticket.go +++ b/contrib/go/_std_1.23/src/crypto/tls/ticket.go @@ -96,6 +96,7 @@ type SessionState struct { // Client-side TLS 1.3-only fields. useBy uint64 // seconds since UNIX epoch ageAdd uint32 + ticket []byte } // Bytes encodes the session, including any private fields, so that it can be @@ -289,7 +290,7 @@ func ParseSessionState(data []byte) (*SessionState, error) { // sessionState returns a partially filled-out [SessionState] with information // from the current connection. -func (c *Conn) sessionState() (*SessionState, error) { +func (c *Conn) sessionState() *SessionState { return &SessionState{ version: c.vers, cipherSuite: c.cipherSuite, @@ -302,7 +303,7 @@ func (c *Conn) sessionState() (*SessionState, error) { isClient: c.isClient, extMasterSecret: c.extMasterSecret, verifiedChains: c.verifiedChains, - }, nil + } } // EncryptTicket encrypts a ticket with the [Config]'s configured (or default) @@ -396,7 +397,6 @@ func (c *Config) decryptTicket(encrypted []byte, ticketKeys []ticketKey) []byte // ClientSessionState contains the state needed by a client to // resume a previous TLS session. type ClientSessionState struct { - ticket []byte session *SessionState } @@ -406,7 +406,10 @@ type ClientSessionState struct { // It can be called by [ClientSessionCache.Put] to serialize (with // [SessionState.Bytes]) and store the session. func (cs *ClientSessionState) ResumptionState() (ticket []byte, state *SessionState, err error) { - return cs.ticket, cs.session, nil + if cs == nil || cs.session == nil { + return nil, nil, nil + } + return cs.session.ticket, cs.session, nil } // NewResumptionState returns a state value that can be returned by @@ -415,7 +418,8 @@ func (cs *ClientSessionState) ResumptionState() (ticket []byte, state *SessionSt // state needs to be returned by [ParseSessionState], and the ticket and session // state must have been returned by [ClientSessionState.ResumptionState]. func NewResumptionState(ticket []byte, state *SessionState) (*ClientSessionState, error) { + state.ticket = ticket return &ClientSessionState{ - ticket: ticket, session: state, + session: state, }, nil } diff --git a/contrib/go/_std_1.23/src/crypto/tls/tls.go b/contrib/go/_std_1.23/src/crypto/tls/tls.go new file mode 100644 index 000000000000..f3089f0ed68d --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/tls.go @@ -0,0 +1,372 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package tls partially implements TLS 1.2, as specified in RFC 5246, +// and TLS 1.3, as specified in RFC 8446. +package tls + +// BUG(agl): The crypto/tls package only implements some countermeasures +// against Lucky13 attacks on CBC-mode encryption, and only on SHA1 +// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and +// https://www.imperialviolet.org/2013/02/04/luckythirteen.html. + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "internal/godebug" + "net" + "os" + "strings" +) + +// Server returns a new TLS server side connection +// using conn as the underlying transport. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func Server(conn net.Conn, config *Config) *Conn { + c := &Conn{ + conn: conn, + config: config, + } + c.handshakeFn = c.serverHandshake + return c +} + +// Client returns a new TLS client side connection +// using conn as the underlying transport. +// The config cannot be nil: users must set either ServerName or +// InsecureSkipVerify in the config. +func Client(conn net.Conn, config *Config) *Conn { + c := &Conn{ + conn: conn, + config: config, + isClient: true, + } + c.handshakeFn = c.clientHandshake + return c +} + +// A listener implements a network listener (net.Listener) for TLS connections. +type listener struct { + net.Listener + config *Config +} + +// Accept waits for and returns the next incoming TLS connection. +// The returned connection is of type *Conn. +func (l *listener) Accept() (net.Conn, error) { + c, err := l.Listener.Accept() + if err != nil { + return nil, err + } + return Server(c, l.config), nil +} + +// NewListener creates a Listener which accepts connections from an inner +// Listener and wraps each connection with [Server]. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func NewListener(inner net.Listener, config *Config) net.Listener { + l := new(listener) + l.Listener = inner + l.config = config + return l +} + +// Listen creates a TLS listener accepting connections on the +// given network address using net.Listen. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func Listen(network, laddr string, config *Config) (net.Listener, error) { + // If this condition changes, consider updating http.Server.ServeTLS too. + if config == nil || len(config.Certificates) == 0 && + config.GetCertificate == nil && config.GetConfigForClient == nil { + return nil, errors.New("tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config") + } + l, err := net.Listen(network, laddr) + if err != nil { + return nil, err + } + return NewListener(l, config), nil +} + +type timeoutError struct{} + +func (timeoutError) Error() string { return "tls: DialWithDialer timed out" } +func (timeoutError) Timeout() bool { return true } +func (timeoutError) Temporary() bool { return true } + +// DialWithDialer connects to the given network address using dialer.Dial and +// then initiates a TLS handshake, returning the resulting TLS connection. Any +// timeout or deadline given in the dialer apply to connection and TLS +// handshake as a whole. +// +// DialWithDialer interprets a nil configuration as equivalent to the zero +// configuration; see the documentation of [Config] for the defaults. +// +// DialWithDialer uses context.Background internally; to specify the context, +// use [Dialer.DialContext] with NetDialer set to the desired dialer. +func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { + return dial(context.Background(), dialer, network, addr, config) +} + +func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { + if netDialer.Timeout != 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout) + defer cancel() + } + + if !netDialer.Deadline.IsZero() { + var cancel context.CancelFunc + ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline) + defer cancel() + } + + rawConn, err := netDialer.DialContext(ctx, network, addr) + if err != nil { + return nil, err + } + + colonPos := strings.LastIndex(addr, ":") + if colonPos == -1 { + colonPos = len(addr) + } + hostname := addr[:colonPos] + + if config == nil { + config = defaultConfig() + } + // If no ServerName is set, infer the ServerName + // from the hostname we're connecting to. + if config.ServerName == "" { + // Make a copy to avoid polluting argument or default. + c := config.Clone() + c.ServerName = hostname + config = c + } + + conn := Client(rawConn, config) + if err := conn.HandshakeContext(ctx); err != nil { + rawConn.Close() + return nil, err + } + return conn, nil +} + +// Dial connects to the given network address using net.Dial +// and then initiates a TLS handshake, returning the resulting +// TLS connection. +// Dial interprets a nil configuration as equivalent to +// the zero configuration; see the documentation of Config +// for the defaults. +func Dial(network, addr string, config *Config) (*Conn, error) { + return DialWithDialer(new(net.Dialer), network, addr, config) +} + +// Dialer dials TLS connections given a configuration and a Dialer for the +// underlying connection. +type Dialer struct { + // NetDialer is the optional dialer to use for the TLS connections' + // underlying TCP connections. + // A nil NetDialer is equivalent to the net.Dialer zero value. + NetDialer *net.Dialer + + // Config is the TLS configuration to use for new connections. + // A nil configuration is equivalent to the zero + // configuration; see the documentation of Config for the + // defaults. + Config *Config +} + +// Dial connects to the given network address and initiates a TLS +// handshake, returning the resulting TLS connection. +// +// The returned [Conn], if any, will always be of type *[Conn]. +// +// Dial uses context.Background internally; to specify the context, +// use [Dialer.DialContext]. +func (d *Dialer) Dial(network, addr string) (net.Conn, error) { + return d.DialContext(context.Background(), network, addr) +} + +func (d *Dialer) netDialer() *net.Dialer { + if d.NetDialer != nil { + return d.NetDialer + } + return new(net.Dialer) +} + +// DialContext connects to the given network address and initiates a TLS +// handshake, returning the resulting TLS connection. +// +// The provided Context must be non-nil. If the context expires before +// the connection is complete, an error is returned. Once successfully +// connected, any expiration of the context will not affect the +// connection. +// +// The returned [Conn], if any, will always be of type *[Conn]. +func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + c, err := dial(ctx, d.netDialer(), network, addr, d.Config) + if err != nil { + // Don't return c (a typed nil) in an interface. + return nil, err + } + return c, nil +} + +// LoadX509KeyPair reads and parses a public/private key pair from a pair of +// files. The files must contain PEM encoded data. The certificate file may +// contain intermediate certificates following the leaf certificate to form a +// certificate chain. On successful return, Certificate.Leaf will be populated. +// +// Before Go 1.23 Certificate.Leaf was left nil, and the parsed certificate was +// discarded. This behavior can be re-enabled by setting "x509keypairleaf=0" +// in the GODEBUG environment variable. +func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { + certPEMBlock, err := os.ReadFile(certFile) + if err != nil { + return Certificate{}, err + } + keyPEMBlock, err := os.ReadFile(keyFile) + if err != nil { + return Certificate{}, err + } + return X509KeyPair(certPEMBlock, keyPEMBlock) +} + +var x509keypairleaf = godebug.New("x509keypairleaf") + +// X509KeyPair parses a public/private key pair from a pair of +// PEM encoded data. On successful return, Certificate.Leaf will be populated. +// +// Before Go 1.23 Certificate.Leaf was left nil, and the parsed certificate was +// discarded. This behavior can be re-enabled by setting "x509keypairleaf=0" +// in the GODEBUG environment variable. +func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { + fail := func(err error) (Certificate, error) { return Certificate{}, err } + + var cert Certificate + var skippedBlockTypes []string + for { + var certDERBlock *pem.Block + certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) + if certDERBlock == nil { + break + } + if certDERBlock.Type == "CERTIFICATE" { + cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) + } else { + skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type) + } + } + + if len(cert.Certificate) == 0 { + if len(skippedBlockTypes) == 0 { + return fail(errors.New("tls: failed to find any PEM data in certificate input")) + } + if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") { + return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched")) + } + return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) + } + + skippedBlockTypes = skippedBlockTypes[:0] + var keyDERBlock *pem.Block + for { + keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) + if keyDERBlock == nil { + if len(skippedBlockTypes) == 0 { + return fail(errors.New("tls: failed to find any PEM data in key input")) + } + if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" { + return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key")) + } + return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) + } + if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { + break + } + skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type) + } + + // We don't need to parse the public key for TLS, but we so do anyway + // to check that it looks sane and matches the private key. + x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) + if err != nil { + return fail(err) + } + + if x509keypairleaf.Value() != "0" { + cert.Leaf = x509Cert + } else { + x509keypairleaf.IncNonDefault() + } + + cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) + if err != nil { + return fail(err) + } + + switch pub := x509Cert.PublicKey.(type) { + case *rsa.PublicKey: + priv, ok := cert.PrivateKey.(*rsa.PrivateKey) + if !ok { + return fail(errors.New("tls: private key type does not match public key type")) + } + if pub.N.Cmp(priv.N) != 0 { + return fail(errors.New("tls: private key does not match public key")) + } + case *ecdsa.PublicKey: + priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) + if !ok { + return fail(errors.New("tls: private key type does not match public key type")) + } + if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { + return fail(errors.New("tls: private key does not match public key")) + } + case ed25519.PublicKey: + priv, ok := cert.PrivateKey.(ed25519.PrivateKey) + if !ok { + return fail(errors.New("tls: private key type does not match public key type")) + } + if !bytes.Equal(priv.Public().(ed25519.PublicKey), pub) { + return fail(errors.New("tls: private key does not match public key")) + } + default: + return fail(errors.New("tls: unknown public key algorithm")) + } + + return cert, nil +} + +// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates +// PKCS #1 private keys by default, while OpenSSL 1.0.0 generates PKCS #8 keys. +// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. +func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { + if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { + return key, nil + } + if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { + switch key := key.(type) { + case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey: + return key, nil + default: + return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping") + } + } + if key, err := x509.ParseECPrivateKey(der); err == nil { + return key, nil + } + + return nil, errors.New("tls: failed to parse private key") +} diff --git a/contrib/go/_std_1.23/src/crypto/tls/ya.make b/contrib/go/_std_1.23/src/crypto/tls/ya.make new file mode 100644 index 000000000000..c94f89b127b1 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/ya.make @@ -0,0 +1,27 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + alert.go + auth.go + cache.go + cipher_suites.go + common.go + common_string.go + conn.go + defaults.go + ech.go + handshake_client.go + handshake_client_tls13.go + handshake_messages.go + handshake_server.go + handshake_server_tls13.go + key_agreement.go + key_schedule.go + notboring.go + prf.go + quic.go + ticket.go + tls.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/x509/boring.go b/contrib/go/_std_1.23/src/crypto/x509/boring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/boring.go rename to contrib/go/_std_1.23/src/crypto/x509/boring.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/cert_pool.go b/contrib/go/_std_1.23/src/crypto/x509/cert_pool.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/cert_pool.go rename to contrib/go/_std_1.23/src/crypto/x509/cert_pool.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/corefoundation.go b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/corefoundation.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/corefoundation.go rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/corefoundation.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/corefoundation.s b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/corefoundation.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/corefoundation.s rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/corefoundation.s diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/security.go b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/security.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/security.go rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/security.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/security.s b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/security.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/security.s rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/security.s diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/ya.make b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/ya.make rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/ya.make b/contrib/go/_std_1.23/src/crypto/x509/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/ya.make rename to contrib/go/_std_1.23/src/crypto/x509/internal/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/x509/notboring.go b/contrib/go/_std_1.23/src/crypto/x509/notboring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/notboring.go rename to contrib/go/_std_1.23/src/crypto/x509/notboring.go diff --git a/contrib/go/_std_1.23/src/crypto/x509/oid.go b/contrib/go/_std_1.23/src/crypto/x509/oid.go new file mode 100644 index 000000000000..fd438eacf954 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/x509/oid.go @@ -0,0 +1,385 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x509 + +import ( + "bytes" + "encoding/asn1" + "errors" + "math" + "math/big" + "math/bits" + "strconv" + "strings" +) + +var ( + errInvalidOID = errors.New("invalid oid") +) + +// An OID represents an ASN.1 OBJECT IDENTIFIER. +type OID struct { + der []byte +} + +// ParseOID parses a Object Identifier string, represented by ASCII numbers separated by dots. +func ParseOID(oid string) (OID, error) { + var o OID + return o, o.unmarshalOIDText(oid) +} + +func newOIDFromDER(der []byte) (OID, bool) { + if len(der) == 0 || der[len(der)-1]&0x80 != 0 { + return OID{}, false + } + + start := 0 + for i, v := range der { + // ITU-T X.690, section 8.19.2: + // The subidentifier shall be encoded in the fewest possible octets, + // that is, the leading octet of the subidentifier shall not have the value 0x80. + if i == start && v == 0x80 { + return OID{}, false + } + if v&0x80 == 0 { + start = i + 1 + } + } + + return OID{der}, true +} + +// OIDFromInts creates a new OID using ints, each integer is a separate component. +func OIDFromInts(oid []uint64) (OID, error) { + if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) { + return OID{}, errInvalidOID + } + + length := base128IntLength(oid[0]*40 + oid[1]) + for _, v := range oid[2:] { + length += base128IntLength(v) + } + + der := make([]byte, 0, length) + der = appendBase128Int(der, oid[0]*40+oid[1]) + for _, v := range oid[2:] { + der = appendBase128Int(der, v) + } + return OID{der}, nil +} + +func base128IntLength(n uint64) int { + if n == 0 { + return 1 + } + return (bits.Len64(n) + 6) / 7 +} + +func appendBase128Int(dst []byte, n uint64) []byte { + for i := base128IntLength(n) - 1; i >= 0; i-- { + o := byte(n >> uint(i*7)) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + dst = append(dst, o) + } + return dst +} + +func base128BigIntLength(n *big.Int) int { + if n.Cmp(big.NewInt(0)) == 0 { + return 1 + } + return (n.BitLen() + 6) / 7 +} + +func appendBase128BigInt(dst []byte, n *big.Int) []byte { + if n.Cmp(big.NewInt(0)) == 0 { + return append(dst, 0) + } + + for i := base128BigIntLength(n) - 1; i >= 0; i-- { + o := byte(big.NewInt(0).Rsh(n, uint(i)*7).Bits()[0]) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + dst = append(dst, o) + } + return dst +} + +// MarshalText implements [encoding.TextMarshaler] +func (o OID) MarshalText() ([]byte, error) { + return []byte(o.String()), nil +} + +// UnmarshalText implements [encoding.TextUnmarshaler] +func (o *OID) UnmarshalText(text []byte) error { + return o.unmarshalOIDText(string(text)) +} + +func (o *OID) unmarshalOIDText(oid string) error { + // (*big.Int).SetString allows +/- signs, but we don't want + // to allow them in the string representation of Object Identifier, so + // reject such encodings. + for _, c := range oid { + isDigit := c >= '0' && c <= '9' + if !isDigit && c != '.' { + return errInvalidOID + } + } + + var ( + firstNum string + secondNum string + ) + + var nextComponentExists bool + firstNum, oid, nextComponentExists = strings.Cut(oid, ".") + if !nextComponentExists { + return errInvalidOID + } + secondNum, oid, nextComponentExists = strings.Cut(oid, ".") + + var ( + first = big.NewInt(0) + second = big.NewInt(0) + ) + + if _, ok := first.SetString(firstNum, 10); !ok { + return errInvalidOID + } + if _, ok := second.SetString(secondNum, 10); !ok { + return errInvalidOID + } + + if first.Cmp(big.NewInt(2)) > 0 || (first.Cmp(big.NewInt(2)) < 0 && second.Cmp(big.NewInt(40)) >= 0) { + return errInvalidOID + } + + firstComponent := first.Mul(first, big.NewInt(40)) + firstComponent.Add(firstComponent, second) + + der := appendBase128BigInt(make([]byte, 0, 32), firstComponent) + + for nextComponentExists { + var strNum string + strNum, oid, nextComponentExists = strings.Cut(oid, ".") + b, ok := big.NewInt(0).SetString(strNum, 10) + if !ok { + return errInvalidOID + } + der = appendBase128BigInt(der, b) + } + + o.der = der + return nil +} + +// MarshalBinary implements [encoding.BinaryMarshaler] +func (o OID) MarshalBinary() ([]byte, error) { + return bytes.Clone(o.der), nil +} + +// UnmarshalBinary implements [encoding.BinaryUnmarshaler] +func (o *OID) UnmarshalBinary(b []byte) error { + oid, ok := newOIDFromDER(bytes.Clone(b)) + if !ok { + return errInvalidOID + } + *o = oid + return nil +} + +// Equal returns true when oid and other represents the same Object Identifier. +func (oid OID) Equal(other OID) bool { + // There is only one possible DER encoding of + // each unique Object Identifier. + return bytes.Equal(oid.der, other.der) +} + +func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, failed bool) { + offset = initOffset + var ret64 int64 + for shifted := 0; offset < len(bytes); shifted++ { + // 5 * 7 bits per byte == 35 bits of data + // Thus the representation is either non-minimal or too large for an int32 + if shifted == 5 { + failed = true + return + } + ret64 <<= 7 + b := bytes[offset] + // integers should be minimally encoded, so the leading octet should + // never be 0x80 + if shifted == 0 && b == 0x80 { + failed = true + return + } + ret64 |= int64(b & 0x7f) + offset++ + if b&0x80 == 0 { + ret = int(ret64) + // Ensure that the returned value fits in an int on all platforms + if ret64 > math.MaxInt32 { + failed = true + } + return + } + } + failed = true + return +} + +// EqualASN1OID returns whether an OID equals an asn1.ObjectIdentifier. If +// asn1.ObjectIdentifier cannot represent the OID specified by oid, because +// a component of OID requires more than 31 bits, it returns false. +func (oid OID) EqualASN1OID(other asn1.ObjectIdentifier) bool { + if len(other) < 2 { + return false + } + v, offset, failed := parseBase128Int(oid.der, 0) + if failed { + // This should never happen, since we've already parsed the OID, + // but just in case. + return false + } + if v < 80 { + a, b := v/40, v%40 + if other[0] != a || other[1] != b { + return false + } + } else { + a, b := 2, v-80 + if other[0] != a || other[1] != b { + return false + } + } + + i := 2 + for ; offset < len(oid.der); i++ { + v, offset, failed = parseBase128Int(oid.der, offset) + if failed { + // Again, shouldn't happen, since we've already parsed + // the OID, but better safe than sorry. + return false + } + if i >= len(other) || v != other[i] { + return false + } + } + + return i == len(other) +} + +// Strings returns the string representation of the Object Identifier. +func (oid OID) String() string { + var b strings.Builder + b.Grow(32) + const ( + valSize = 64 // size in bits of val. + bitsPerByte = 7 + maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1 + ) + var ( + start = 0 + val = uint64(0) + numBuf = make([]byte, 0, 21) + bigVal *big.Int + overflow bool + ) + for i, v := range oid.der { + curVal := v & 0x7F + valEnd := v&0x80 == 0 + if valEnd { + if start != 0 { + b.WriteByte('.') + } + } + if !overflow && val > maxValSafeShift { + if bigVal == nil { + bigVal = new(big.Int) + } + bigVal = bigVal.SetUint64(val) + overflow = true + } + if overflow { + bigVal = bigVal.Lsh(bigVal, bitsPerByte).Or(bigVal, big.NewInt(int64(curVal))) + if valEnd { + if start == 0 { + b.WriteString("2.") + bigVal = bigVal.Sub(bigVal, big.NewInt(80)) + } + numBuf = bigVal.Append(numBuf, 10) + b.Write(numBuf) + numBuf = numBuf[:0] + val = 0 + start = i + 1 + overflow = false + } + continue + } + val <<= bitsPerByte + val |= uint64(curVal) + if valEnd { + if start == 0 { + if val < 80 { + b.Write(strconv.AppendUint(numBuf, val/40, 10)) + b.WriteByte('.') + b.Write(strconv.AppendUint(numBuf, val%40, 10)) + } else { + b.WriteString("2.") + b.Write(strconv.AppendUint(numBuf, val-80, 10)) + } + } else { + b.Write(strconv.AppendUint(numBuf, val, 10)) + } + val = 0 + start = i + 1 + } + } + return b.String() +} + +func (oid OID) toASN1OID() (asn1.ObjectIdentifier, bool) { + out := make([]int, 0, len(oid.der)+1) + + const ( + valSize = 31 // amount of usable bits of val for OIDs. + bitsPerByte = 7 + maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1 + ) + + val := 0 + + for _, v := range oid.der { + if val > maxValSafeShift { + return nil, false + } + + val <<= bitsPerByte + val |= int(v & 0x7F) + + if v&0x80 == 0 { + if len(out) == 0 { + if val < 80 { + out = append(out, val/40) + out = append(out, val%40) + } else { + out = append(out, 2) + out = append(out, val-80) + } + val = 0 + continue + } + out = append(out, val) + val = 0 + } + } + + return out, true +} diff --git a/contrib/go/_std_1.23/src/crypto/x509/parser.go b/contrib/go/_std_1.23/src/crypto/x509/parser.go new file mode 100644 index 000000000000..3ba5f6a4e1dc --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/x509/parser.go @@ -0,0 +1,1231 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x509 + +import ( + "bytes" + "crypto/dsa" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rsa" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "fmt" + "internal/godebug" + "math/big" + "net" + "net/url" + "strconv" + "strings" + "time" + "unicode/utf16" + "unicode/utf8" + + "golang.org/x/crypto/cryptobyte" + cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" +) + +// isPrintable reports whether the given b is in the ASN.1 PrintableString set. +// This is a simplified version of encoding/asn1.isPrintable. +func isPrintable(b byte) bool { + return 'a' <= b && b <= 'z' || + 'A' <= b && b <= 'Z' || + '0' <= b && b <= '9' || + '\'' <= b && b <= ')' || + '+' <= b && b <= '/' || + b == ' ' || + b == ':' || + b == '=' || + b == '?' || + // This is technically not allowed in a PrintableString. + // However, x509 certificates with wildcard strings don't + // always use the correct string type so we permit it. + b == '*' || + // This is not technically allowed either. However, not + // only is it relatively common, but there are also a + // handful of CA certificates that contain it. At least + // one of which will not expire until 2027. + b == '&' +} + +// parseASN1String parses the ASN.1 string types T61String, PrintableString, +// UTF8String, BMPString, IA5String, and NumericString. This is mostly copied +// from the respective encoding/asn1.parse... methods, rather than just +// increasing the API surface of that package. +func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) { + switch tag { + case cryptobyte_asn1.T61String: + return string(value), nil + case cryptobyte_asn1.PrintableString: + for _, b := range value { + if !isPrintable(b) { + return "", errors.New("invalid PrintableString") + } + } + return string(value), nil + case cryptobyte_asn1.UTF8String: + if !utf8.Valid(value) { + return "", errors.New("invalid UTF-8 string") + } + return string(value), nil + case cryptobyte_asn1.Tag(asn1.TagBMPString): + if len(value)%2 != 0 { + return "", errors.New("invalid BMPString") + } + + // Strip terminator if present. + if l := len(value); l >= 2 && value[l-1] == 0 && value[l-2] == 0 { + value = value[:l-2] + } + + s := make([]uint16, 0, len(value)/2) + for len(value) > 0 { + s = append(s, uint16(value[0])<<8+uint16(value[1])) + value = value[2:] + } + + return string(utf16.Decode(s)), nil + case cryptobyte_asn1.IA5String: + s := string(value) + if isIA5String(s) != nil { + return "", errors.New("invalid IA5String") + } + return s, nil + case cryptobyte_asn1.Tag(asn1.TagNumericString): + for _, b := range value { + if !('0' <= b && b <= '9' || b == ' ') { + return "", errors.New("invalid NumericString") + } + } + return string(value), nil + } + return "", fmt.Errorf("unsupported string type: %v", tag) +} + +// parseName parses a DER encoded Name as defined in RFC 5280. We may +// want to export this function in the future for use in crypto/tls. +func parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) { + if !raw.ReadASN1(&raw, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid RDNSequence") + } + + var rdnSeq pkix.RDNSequence + for !raw.Empty() { + var rdnSet pkix.RelativeDistinguishedNameSET + var set cryptobyte.String + if !raw.ReadASN1(&set, cryptobyte_asn1.SET) { + return nil, errors.New("x509: invalid RDNSequence") + } + for !set.Empty() { + var atav cryptobyte.String + if !set.ReadASN1(&atav, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid RDNSequence: invalid attribute") + } + var attr pkix.AttributeTypeAndValue + if !atav.ReadASN1ObjectIdentifier(&attr.Type) { + return nil, errors.New("x509: invalid RDNSequence: invalid attribute type") + } + var rawValue cryptobyte.String + var valueTag cryptobyte_asn1.Tag + if !atav.ReadAnyASN1(&rawValue, &valueTag) { + return nil, errors.New("x509: invalid RDNSequence: invalid attribute value") + } + var err error + attr.Value, err = parseASN1String(valueTag, rawValue) + if err != nil { + return nil, fmt.Errorf("x509: invalid RDNSequence: invalid attribute value: %s", err) + } + rdnSet = append(rdnSet, attr) + } + + rdnSeq = append(rdnSeq, rdnSet) + } + + return &rdnSeq, nil +} + +func parseAI(der cryptobyte.String) (pkix.AlgorithmIdentifier, error) { + ai := pkix.AlgorithmIdentifier{} + if !der.ReadASN1ObjectIdentifier(&ai.Algorithm) { + return ai, errors.New("x509: malformed OID") + } + if der.Empty() { + return ai, nil + } + var params cryptobyte.String + var tag cryptobyte_asn1.Tag + if !der.ReadAnyASN1Element(¶ms, &tag) { + return ai, errors.New("x509: malformed parameters") + } + ai.Parameters.Tag = int(tag) + ai.Parameters.FullBytes = params + return ai, nil +} + +func parseTime(der *cryptobyte.String) (time.Time, error) { + var t time.Time + switch { + case der.PeekASN1Tag(cryptobyte_asn1.UTCTime): + if !der.ReadASN1UTCTime(&t) { + return t, errors.New("x509: malformed UTCTime") + } + case der.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime): + if !der.ReadASN1GeneralizedTime(&t) { + return t, errors.New("x509: malformed GeneralizedTime") + } + default: + return t, errors.New("x509: unsupported time format") + } + return t, nil +} + +func parseValidity(der cryptobyte.String) (time.Time, time.Time, error) { + notBefore, err := parseTime(&der) + if err != nil { + return time.Time{}, time.Time{}, err + } + notAfter, err := parseTime(&der) + if err != nil { + return time.Time{}, time.Time{}, err + } + + return notBefore, notAfter, nil +} + +func parseExtension(der cryptobyte.String) (pkix.Extension, error) { + var ext pkix.Extension + if !der.ReadASN1ObjectIdentifier(&ext.Id) { + return ext, errors.New("x509: malformed extension OID field") + } + if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { + if !der.ReadASN1Boolean(&ext.Critical) { + return ext, errors.New("x509: malformed extension critical field") + } + } + var val cryptobyte.String + if !der.ReadASN1(&val, cryptobyte_asn1.OCTET_STRING) { + return ext, errors.New("x509: malformed extension value field") + } + ext.Value = val + return ext, nil +} + +func parsePublicKey(keyData *publicKeyInfo) (any, error) { + oid := keyData.Algorithm.Algorithm + params := keyData.Algorithm.Parameters + der := cryptobyte.String(keyData.PublicKey.RightAlign()) + switch { + case oid.Equal(oidPublicKeyRSA): + // RSA public keys must have a NULL in the parameters. + // See RFC 3279, Section 2.3.1. + if !bytes.Equal(params.FullBytes, asn1.NullBytes) { + return nil, errors.New("x509: RSA key missing NULL parameters") + } + + p := &pkcs1PublicKey{N: new(big.Int)} + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid RSA public key") + } + if !der.ReadASN1Integer(p.N) { + return nil, errors.New("x509: invalid RSA modulus") + } + if !der.ReadASN1Integer(&p.E) { + return nil, errors.New("x509: invalid RSA public exponent") + } + + if p.N.Sign() <= 0 { + return nil, errors.New("x509: RSA modulus is not a positive number") + } + if p.E <= 0 { + return nil, errors.New("x509: RSA public exponent is not a positive number") + } + + pub := &rsa.PublicKey{ + E: p.E, + N: p.N, + } + return pub, nil + case oid.Equal(oidPublicKeyECDSA): + paramsDer := cryptobyte.String(params.FullBytes) + namedCurveOID := new(asn1.ObjectIdentifier) + if !paramsDer.ReadASN1ObjectIdentifier(namedCurveOID) { + return nil, errors.New("x509: invalid ECDSA parameters") + } + namedCurve := namedCurveFromOID(*namedCurveOID) + if namedCurve == nil { + return nil, errors.New("x509: unsupported elliptic curve") + } + x, y := elliptic.Unmarshal(namedCurve, der) + if x == nil { + return nil, errors.New("x509: failed to unmarshal elliptic curve point") + } + pub := &ecdsa.PublicKey{ + Curve: namedCurve, + X: x, + Y: y, + } + return pub, nil + case oid.Equal(oidPublicKeyEd25519): + // RFC 8410, Section 3 + // > For all of the OIDs, the parameters MUST be absent. + if len(params.FullBytes) != 0 { + return nil, errors.New("x509: Ed25519 key encoded with illegal parameters") + } + if len(der) != ed25519.PublicKeySize { + return nil, errors.New("x509: wrong Ed25519 public key size") + } + return ed25519.PublicKey(der), nil + case oid.Equal(oidPublicKeyX25519): + // RFC 8410, Section 3 + // > For all of the OIDs, the parameters MUST be absent. + if len(params.FullBytes) != 0 { + return nil, errors.New("x509: X25519 key encoded with illegal parameters") + } + return ecdh.X25519().NewPublicKey(der) + case oid.Equal(oidPublicKeyDSA): + y := new(big.Int) + if !der.ReadASN1Integer(y) { + return nil, errors.New("x509: invalid DSA public key") + } + pub := &dsa.PublicKey{ + Y: y, + Parameters: dsa.Parameters{ + P: new(big.Int), + Q: new(big.Int), + G: new(big.Int), + }, + } + paramsDer := cryptobyte.String(params.FullBytes) + if !paramsDer.ReadASN1(¶msDer, cryptobyte_asn1.SEQUENCE) || + !paramsDer.ReadASN1Integer(pub.Parameters.P) || + !paramsDer.ReadASN1Integer(pub.Parameters.Q) || + !paramsDer.ReadASN1Integer(pub.Parameters.G) { + return nil, errors.New("x509: invalid DSA parameters") + } + if pub.Y.Sign() <= 0 || pub.Parameters.P.Sign() <= 0 || + pub.Parameters.Q.Sign() <= 0 || pub.Parameters.G.Sign() <= 0 { + return nil, errors.New("x509: zero or negative DSA parameter") + } + return pub, nil + default: + return nil, errors.New("x509: unknown public key algorithm") + } +} + +func parseKeyUsageExtension(der cryptobyte.String) (KeyUsage, error) { + var usageBits asn1.BitString + if !der.ReadASN1BitString(&usageBits) { + return 0, errors.New("x509: invalid key usage") + } + + var usage int + for i := 0; i < 9; i++ { + if usageBits.At(i) != 0 { + usage |= 1 << uint(i) + } + } + return KeyUsage(usage), nil +} + +func parseBasicConstraintsExtension(der cryptobyte.String) (bool, int, error) { + var isCA bool + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return false, 0, errors.New("x509: invalid basic constraints") + } + if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { + if !der.ReadASN1Boolean(&isCA) { + return false, 0, errors.New("x509: invalid basic constraints") + } + } + maxPathLen := -1 + if der.PeekASN1Tag(cryptobyte_asn1.INTEGER) { + if !der.ReadASN1Integer(&maxPathLen) { + return false, 0, errors.New("x509: invalid basic constraints") + } + } + + // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285) + return isCA, maxPathLen, nil +} + +func forEachSAN(der cryptobyte.String, callback func(tag int, data []byte) error) error { + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid subject alternative names") + } + for !der.Empty() { + var san cryptobyte.String + var tag cryptobyte_asn1.Tag + if !der.ReadAnyASN1(&san, &tag) { + return errors.New("x509: invalid subject alternative name") + } + if err := callback(int(tag^0x80), san); err != nil { + return err + } + } + + return nil +} + +func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) { + err = forEachSAN(der, func(tag int, data []byte) error { + switch tag { + case nameTypeEmail: + email := string(data) + if err := isIA5String(email); err != nil { + return errors.New("x509: SAN rfc822Name is malformed") + } + emailAddresses = append(emailAddresses, email) + case nameTypeDNS: + name := string(data) + if err := isIA5String(name); err != nil { + return errors.New("x509: SAN dNSName is malformed") + } + dnsNames = append(dnsNames, string(name)) + case nameTypeURI: + uriStr := string(data) + if err := isIA5String(uriStr); err != nil { + return errors.New("x509: SAN uniformResourceIdentifier is malformed") + } + uri, err := url.Parse(uriStr) + if err != nil { + return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err) + } + if len(uri.Host) > 0 { + if _, ok := domainToReverseLabels(uri.Host); !ok { + return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr) + } + } + uris = append(uris, uri) + case nameTypeIP: + switch len(data) { + case net.IPv4len, net.IPv6len: + ipAddresses = append(ipAddresses, data) + default: + return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data))) + } + } + + return nil + }) + + return +} + +func parseAuthorityKeyIdentifier(e pkix.Extension) ([]byte, error) { + // RFC 5280, Section 4.2.1.1 + if e.Critical { + // Conforming CAs MUST mark this extension as non-critical + return nil, errors.New("x509: authority key identifier incorrectly marked critical") + } + val := cryptobyte.String(e.Value) + var akid cryptobyte.String + if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid authority key identifier") + } + if akid.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { + if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { + return nil, errors.New("x509: invalid authority key identifier") + } + return akid, nil + } + return nil, nil +} + +func parseExtKeyUsageExtension(der cryptobyte.String) ([]ExtKeyUsage, []asn1.ObjectIdentifier, error) { + var extKeyUsages []ExtKeyUsage + var unknownUsages []asn1.ObjectIdentifier + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return nil, nil, errors.New("x509: invalid extended key usages") + } + for !der.Empty() { + var eku asn1.ObjectIdentifier + if !der.ReadASN1ObjectIdentifier(&eku) { + return nil, nil, errors.New("x509: invalid extended key usages") + } + if extKeyUsage, ok := extKeyUsageFromOID(eku); ok { + extKeyUsages = append(extKeyUsages, extKeyUsage) + } else { + unknownUsages = append(unknownUsages, eku) + } + } + return extKeyUsages, unknownUsages, nil +} + +func parseCertificatePoliciesExtension(der cryptobyte.String) ([]OID, error) { + var oids []OID + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid certificate policies") + } + for !der.Empty() { + var cp cryptobyte.String + var OIDBytes cryptobyte.String + if !der.ReadASN1(&cp, cryptobyte_asn1.SEQUENCE) || !cp.ReadASN1(&OIDBytes, cryptobyte_asn1.OBJECT_IDENTIFIER) { + return nil, errors.New("x509: invalid certificate policies") + } + oid, ok := newOIDFromDER(OIDBytes) + if !ok { + return nil, errors.New("x509: invalid certificate policies") + } + oids = append(oids, oid) + } + return oids, nil +} + +// isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits. +func isValidIPMask(mask []byte) bool { + seenZero := false + + for _, b := range mask { + if seenZero { + if b != 0 { + return false + } + + continue + } + + switch b { + case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: + seenZero = true + case 0xff: + default: + return false + } + } + + return true +} + +func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandled bool, err error) { + // RFC 5280, 4.2.1.10 + + // NameConstraints ::= SEQUENCE { + // permittedSubtrees [0] GeneralSubtrees OPTIONAL, + // excludedSubtrees [1] GeneralSubtrees OPTIONAL } + // + // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + // + // GeneralSubtree ::= SEQUENCE { + // base GeneralName, + // minimum [0] BaseDistance DEFAULT 0, + // maximum [1] BaseDistance OPTIONAL } + // + // BaseDistance ::= INTEGER (0..MAX) + + outer := cryptobyte.String(e.Value) + var toplevel, permitted, excluded cryptobyte.String + var havePermitted, haveExcluded bool + if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) || + !outer.Empty() || + !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || + !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || + !toplevel.Empty() { + return false, errors.New("x509: invalid NameConstraints extension") + } + + if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 { + // From RFC 5280, Section 4.2.1.10: + // “either the permittedSubtrees field + // or the excludedSubtrees MUST be + // present” + return false, errors.New("x509: empty name constraints extension") + } + + getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) { + for !subtrees.Empty() { + var seq, value cryptobyte.String + var tag cryptobyte_asn1.Tag + if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) || + !seq.ReadAnyASN1(&value, &tag) { + return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") + } + + var ( + dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific() + emailTag = cryptobyte_asn1.Tag(1).ContextSpecific() + ipTag = cryptobyte_asn1.Tag(7).ContextSpecific() + uriTag = cryptobyte_asn1.Tag(6).ContextSpecific() + ) + + switch tag { + case dnsTag: + domain := string(value) + if err := isIA5String(domain); err != nil { + return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) + } + + trimmedDomain := domain + if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { + // constraints can have a leading + // period to exclude the domain + // itself, but that's not valid in a + // normal domain name. + trimmedDomain = trimmedDomain[1:] + } + if _, ok := domainToReverseLabels(trimmedDomain); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain) + } + dnsNames = append(dnsNames, domain) + + case ipTag: + l := len(value) + var ip, mask []byte + + switch l { + case 8: + ip = value[:4] + mask = value[4:] + + case 32: + ip = value[:16] + mask = value[16:] + + default: + return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l) + } + + if !isValidIPMask(mask) { + return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask) + } + + ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)}) + + case emailTag: + constraint := string(value) + if err := isIA5String(constraint); err != nil { + return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) + } + + // If the constraint contains an @ then + // it specifies an exact mailbox name. + if strings.Contains(constraint, "@") { + if _, ok := parseRFC2821Mailbox(constraint); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) + } + } else { + // Otherwise it's a domain name. + domain := constraint + if len(domain) > 0 && domain[0] == '.' { + domain = domain[1:] + } + if _, ok := domainToReverseLabels(domain); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) + } + } + emails = append(emails, constraint) + + case uriTag: + domain := string(value) + if err := isIA5String(domain); err != nil { + return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) + } + + if net.ParseIP(domain) != nil { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain) + } + + trimmedDomain := domain + if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { + // constraints can have a leading + // period to exclude the domain itself, + // but that's not valid in a normal + // domain name. + trimmedDomain = trimmedDomain[1:] + } + if _, ok := domainToReverseLabels(trimmedDomain); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain) + } + uriDomains = append(uriDomains, domain) + + default: + unhandled = true + } + } + + return dnsNames, ips, emails, uriDomains, nil + } + + if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil { + return false, err + } + if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil { + return false, err + } + out.PermittedDNSDomainsCritical = e.Critical + + return unhandled, nil +} + +func processExtensions(out *Certificate) error { + var err error + for _, e := range out.Extensions { + unhandled := false + + if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { + switch e.Id[3] { + case 15: + out.KeyUsage, err = parseKeyUsageExtension(e.Value) + if err != nil { + return err + } + case 19: + out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(e.Value) + if err != nil { + return err + } + out.BasicConstraintsValid = true + out.MaxPathLenZero = out.MaxPathLen == 0 + case 17: + out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value) + if err != nil { + return err + } + + if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 { + // If we didn't parse anything then we do the critical check, below. + unhandled = true + } + + case 30: + unhandled, err = parseNameConstraintsExtension(out, e) + if err != nil { + return err + } + + case 31: + // RFC 5280, 4.2.1.13 + + // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + // + // DistributionPoint ::= SEQUENCE { + // distributionPoint [0] DistributionPointName OPTIONAL, + // reasons [1] ReasonFlags OPTIONAL, + // cRLIssuer [2] GeneralNames OPTIONAL } + // + // DistributionPointName ::= CHOICE { + // fullName [0] GeneralNames, + // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + val := cryptobyte.String(e.Value) + if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid CRL distribution points") + } + for !val.Empty() { + var dpDER cryptobyte.String + if !val.ReadASN1(&dpDER, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid CRL distribution point") + } + var dpNameDER cryptobyte.String + var dpNamePresent bool + if !dpDER.ReadOptionalASN1(&dpNameDER, &dpNamePresent, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { + return errors.New("x509: invalid CRL distribution point") + } + if !dpNamePresent { + continue + } + if !dpNameDER.ReadASN1(&dpNameDER, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { + return errors.New("x509: invalid CRL distribution point") + } + for !dpNameDER.Empty() { + if !dpNameDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { + break + } + var uri cryptobyte.String + if !dpNameDER.ReadASN1(&uri, cryptobyte_asn1.Tag(6).ContextSpecific()) { + return errors.New("x509: invalid CRL distribution point") + } + out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(uri)) + } + } + + case 35: + out.AuthorityKeyId, err = parseAuthorityKeyIdentifier(e) + if err != nil { + return err + } + case 37: + out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value) + if err != nil { + return err + } + case 14: + // RFC 5280, 4.2.1.2 + if e.Critical { + // Conforming CAs MUST mark this extension as non-critical + return errors.New("x509: subject key identifier incorrectly marked critical") + } + val := cryptobyte.String(e.Value) + var skid cryptobyte.String + if !val.ReadASN1(&skid, cryptobyte_asn1.OCTET_STRING) { + return errors.New("x509: invalid subject key identifier") + } + out.SubjectKeyId = skid + case 32: + out.Policies, err = parseCertificatePoliciesExtension(e.Value) + if err != nil { + return err + } + out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, 0, len(out.Policies)) + for _, oid := range out.Policies { + if oid, ok := oid.toASN1OID(); ok { + out.PolicyIdentifiers = append(out.PolicyIdentifiers, oid) + } + } + default: + // Unknown extensions are recorded if critical. + unhandled = true + } + } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { + // RFC 5280 4.2.2.1: Authority Information Access + if e.Critical { + // Conforming CAs MUST mark this extension as non-critical + return errors.New("x509: authority info access incorrectly marked critical") + } + val := cryptobyte.String(e.Value) + if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid authority info access") + } + for !val.Empty() { + var aiaDER cryptobyte.String + if !val.ReadASN1(&aiaDER, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid authority info access") + } + var method asn1.ObjectIdentifier + if !aiaDER.ReadASN1ObjectIdentifier(&method) { + return errors.New("x509: invalid authority info access") + } + if !aiaDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { + continue + } + if !aiaDER.ReadASN1(&aiaDER, cryptobyte_asn1.Tag(6).ContextSpecific()) { + return errors.New("x509: invalid authority info access") + } + switch { + case method.Equal(oidAuthorityInfoAccessOcsp): + out.OCSPServer = append(out.OCSPServer, string(aiaDER)) + case method.Equal(oidAuthorityInfoAccessIssuers): + out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(aiaDER)) + } + } + } else { + // Unknown extensions are recorded if critical. + unhandled = true + } + + if e.Critical && unhandled { + out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id) + } + } + + return nil +} + +var x509negativeserial = godebug.New("x509negativeserial") + +func parseCertificate(der []byte) (*Certificate, error) { + cert := &Certificate{} + + input := cryptobyte.String(der) + // we read the SEQUENCE including length and tag bytes so that + // we can populate Certificate.Raw, before unwrapping the + // SEQUENCE so it can be operated on + if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed certificate") + } + cert.Raw = input + if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed certificate") + } + + var tbs cryptobyte.String + // do the same trick again as above to extract the raw + // bytes for Certificate.RawTBSCertificate + if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed tbs certificate") + } + cert.RawTBSCertificate = tbs + if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed tbs certificate") + } + + if !tbs.ReadOptionalASN1Integer(&cert.Version, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific(), 0) { + return nil, errors.New("x509: malformed version") + } + if cert.Version < 0 { + return nil, errors.New("x509: malformed version") + } + // for backwards compat reasons Version is one-indexed, + // rather than zero-indexed as defined in 5280 + cert.Version++ + if cert.Version > 3 { + return nil, errors.New("x509: invalid version") + } + + serial := new(big.Int) + if !tbs.ReadASN1Integer(serial) { + return nil, errors.New("x509: malformed serial number") + } + if serial.Sign() == -1 { + if x509negativeserial.Value() != "1" { + return nil, errors.New("x509: negative serial number") + } else { + x509negativeserial.IncNonDefault() + } + } + cert.SerialNumber = serial + + var sigAISeq cryptobyte.String + if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed signature algorithm identifier") + } + // Before parsing the inner algorithm identifier, extract + // the outer algorithm identifier and make sure that they + // match. + var outerSigAISeq cryptobyte.String + if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed algorithm identifier") + } + if !bytes.Equal(outerSigAISeq, sigAISeq) { + return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") + } + sigAI, err := parseAI(sigAISeq) + if err != nil { + return nil, err + } + cert.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) + + var issuerSeq cryptobyte.String + if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed issuer") + } + cert.RawIssuer = issuerSeq + issuerRDNs, err := parseName(issuerSeq) + if err != nil { + return nil, err + } + cert.Issuer.FillFromRDNSequence(issuerRDNs) + + var validity cryptobyte.String + if !tbs.ReadASN1(&validity, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed validity") + } + cert.NotBefore, cert.NotAfter, err = parseValidity(validity) + if err != nil { + return nil, err + } + + var subjectSeq cryptobyte.String + if !tbs.ReadASN1Element(&subjectSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed issuer") + } + cert.RawSubject = subjectSeq + subjectRDNs, err := parseName(subjectSeq) + if err != nil { + return nil, err + } + cert.Subject.FillFromRDNSequence(subjectRDNs) + + var spki cryptobyte.String + if !tbs.ReadASN1Element(&spki, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed spki") + } + cert.RawSubjectPublicKeyInfo = spki + if !spki.ReadASN1(&spki, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed spki") + } + var pkAISeq cryptobyte.String + if !spki.ReadASN1(&pkAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed public key algorithm identifier") + } + pkAI, err := parseAI(pkAISeq) + if err != nil { + return nil, err + } + cert.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(pkAI.Algorithm) + var spk asn1.BitString + if !spki.ReadASN1BitString(&spk) { + return nil, errors.New("x509: malformed subjectPublicKey") + } + if cert.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm { + cert.PublicKey, err = parsePublicKey(&publicKeyInfo{ + Algorithm: pkAI, + PublicKey: spk, + }) + if err != nil { + return nil, err + } + } + + if cert.Version > 1 { + if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).ContextSpecific()) { + return nil, errors.New("x509: malformed issuerUniqueID") + } + if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).ContextSpecific()) { + return nil, errors.New("x509: malformed subjectUniqueID") + } + if cert.Version == 3 { + var extensions cryptobyte.String + var present bool + if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(3).Constructed().ContextSpecific()) { + return nil, errors.New("x509: malformed extensions") + } + if present { + seenExts := make(map[string]bool) + if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extensions") + } + for !extensions.Empty() { + var extension cryptobyte.String + if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extension") + } + ext, err := parseExtension(extension) + if err != nil { + return nil, err + } + oidStr := ext.Id.String() + if seenExts[oidStr] { + return nil, fmt.Errorf("x509: certificate contains duplicate extension with OID %q", oidStr) + } + seenExts[oidStr] = true + cert.Extensions = append(cert.Extensions, ext) + } + err = processExtensions(cert) + if err != nil { + return nil, err + } + } + } + } + + var signature asn1.BitString + if !input.ReadASN1BitString(&signature) { + return nil, errors.New("x509: malformed signature") + } + cert.Signature = signature.RightAlign() + + return cert, nil +} + +// ParseCertificate parses a single certificate from the given ASN.1 DER data. +// +// Before Go 1.23, ParseCertificate accepted certificates with negative serial +// numbers. This behavior can be restored by including "x509negativeserial=1" in +// the GODEBUG environment variable. +func ParseCertificate(der []byte) (*Certificate, error) { + cert, err := parseCertificate(der) + if err != nil { + return nil, err + } + if len(der) != len(cert.Raw) { + return nil, errors.New("x509: trailing data") + } + return cert, err +} + +// ParseCertificates parses one or more certificates from the given ASN.1 DER +// data. The certificates must be concatenated with no intermediate padding. +func ParseCertificates(der []byte) ([]*Certificate, error) { + var certs []*Certificate + for len(der) > 0 { + cert, err := parseCertificate(der) + if err != nil { + return nil, err + } + certs = append(certs, cert) + der = der[len(cert.Raw):] + } + return certs, nil +} + +// The X.509 standards confusingly 1-indexed the version names, but 0-indexed +// the actual encoded version, so the version for X.509v2 is 1. +const x509v2Version = 1 + +// ParseRevocationList parses a X509 v2 [Certificate] Revocation List from the given +// ASN.1 DER data. +func ParseRevocationList(der []byte) (*RevocationList, error) { + rl := &RevocationList{} + + input := cryptobyte.String(der) + // we read the SEQUENCE including length and tag bytes so that + // we can populate RevocationList.Raw, before unwrapping the + // SEQUENCE so it can be operated on + if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + rl.Raw = input + if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + + var tbs cryptobyte.String + // do the same trick again as above to extract the raw + // bytes for Certificate.RawTBSCertificate + if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed tbs crl") + } + rl.RawTBSRevocationList = tbs + if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed tbs crl") + } + + var version int + if !tbs.PeekASN1Tag(cryptobyte_asn1.INTEGER) { + return nil, errors.New("x509: unsupported crl version") + } + if !tbs.ReadASN1Integer(&version) { + return nil, errors.New("x509: malformed crl") + } + if version != x509v2Version { + return nil, fmt.Errorf("x509: unsupported crl version: %d", version) + } + + var sigAISeq cryptobyte.String + if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed signature algorithm identifier") + } + // Before parsing the inner algorithm identifier, extract + // the outer algorithm identifier and make sure that they + // match. + var outerSigAISeq cryptobyte.String + if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed algorithm identifier") + } + if !bytes.Equal(outerSigAISeq, sigAISeq) { + return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") + } + sigAI, err := parseAI(sigAISeq) + if err != nil { + return nil, err + } + rl.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) + + var signature asn1.BitString + if !input.ReadASN1BitString(&signature) { + return nil, errors.New("x509: malformed signature") + } + rl.Signature = signature.RightAlign() + + var issuerSeq cryptobyte.String + if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed issuer") + } + rl.RawIssuer = issuerSeq + issuerRDNs, err := parseName(issuerSeq) + if err != nil { + return nil, err + } + rl.Issuer.FillFromRDNSequence(issuerRDNs) + + rl.ThisUpdate, err = parseTime(&tbs) + if err != nil { + return nil, err + } + if tbs.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime) || tbs.PeekASN1Tag(cryptobyte_asn1.UTCTime) { + rl.NextUpdate, err = parseTime(&tbs) + if err != nil { + return nil, err + } + } + + if tbs.PeekASN1Tag(cryptobyte_asn1.SEQUENCE) { + var revokedSeq cryptobyte.String + if !tbs.ReadASN1(&revokedSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + for !revokedSeq.Empty() { + rce := RevocationListEntry{} + + var certSeq cryptobyte.String + if !revokedSeq.ReadASN1Element(&certSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + rce.Raw = certSeq + if !certSeq.ReadASN1(&certSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + + rce.SerialNumber = new(big.Int) + if !certSeq.ReadASN1Integer(rce.SerialNumber) { + return nil, errors.New("x509: malformed serial number") + } + rce.RevocationTime, err = parseTime(&certSeq) + if err != nil { + return nil, err + } + var extensions cryptobyte.String + var present bool + if !certSeq.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extensions") + } + if present { + for !extensions.Empty() { + var extension cryptobyte.String + if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extension") + } + ext, err := parseExtension(extension) + if err != nil { + return nil, err + } + if ext.Id.Equal(oidExtensionReasonCode) { + val := cryptobyte.String(ext.Value) + if !val.ReadASN1Enum(&rce.ReasonCode) { + return nil, fmt.Errorf("x509: malformed reasonCode extension") + } + } + rce.Extensions = append(rce.Extensions, ext) + } + } + + rl.RevokedCertificateEntries = append(rl.RevokedCertificateEntries, rce) + rcDeprecated := pkix.RevokedCertificate{ + SerialNumber: rce.SerialNumber, + RevocationTime: rce.RevocationTime, + Extensions: rce.Extensions, + } + rl.RevokedCertificates = append(rl.RevokedCertificates, rcDeprecated) + } + } + + var extensions cryptobyte.String + var present bool + if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { + return nil, errors.New("x509: malformed extensions") + } + if present { + if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extensions") + } + for !extensions.Empty() { + var extension cryptobyte.String + if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extension") + } + ext, err := parseExtension(extension) + if err != nil { + return nil, err + } + if ext.Id.Equal(oidExtensionAuthorityKeyId) { + rl.AuthorityKeyId, err = parseAuthorityKeyIdentifier(ext) + if err != nil { + return nil, err + } + } else if ext.Id.Equal(oidExtensionCRLNumber) { + value := cryptobyte.String(ext.Value) + rl.Number = new(big.Int) + if !value.ReadASN1Integer(rl.Number) { + return nil, errors.New("x509: malformed crl number") + } + } + rl.Extensions = append(rl.Extensions, ext) + } + } + + return rl, nil +} diff --git a/contrib/go/_std_1.22/src/crypto/x509/pem_decrypt.go b/contrib/go/_std_1.23/src/crypto/x509/pem_decrypt.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pem_decrypt.go rename to contrib/go/_std_1.23/src/crypto/x509/pem_decrypt.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/pkcs1.go b/contrib/go/_std_1.23/src/crypto/x509/pkcs1.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pkcs1.go rename to contrib/go/_std_1.23/src/crypto/x509/pkcs1.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/pkcs8.go b/contrib/go/_std_1.23/src/crypto/x509/pkcs8.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pkcs8.go rename to contrib/go/_std_1.23/src/crypto/x509/pkcs8.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/pkix/pkix.go b/contrib/go/_std_1.23/src/crypto/x509/pkix/pkix.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pkix/pkix.go rename to contrib/go/_std_1.23/src/crypto/x509/pkix/pkix.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/pkix/ya.make b/contrib/go/_std_1.23/src/crypto/x509/pkix/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pkix/ya.make rename to contrib/go/_std_1.23/src/crypto/x509/pkix/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/x509/platform_root_cert.pem b/contrib/go/_std_1.23/src/crypto/x509/platform_root_cert.pem similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/platform_root_cert.pem rename to contrib/go/_std_1.23/src/crypto/x509/platform_root_cert.pem diff --git a/contrib/go/_std_1.22/src/crypto/x509/platform_root_key.pem b/contrib/go/_std_1.23/src/crypto/x509/platform_root_key.pem similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/platform_root_key.pem rename to contrib/go/_std_1.23/src/crypto/x509/platform_root_key.pem diff --git a/contrib/go/_std_1.22/src/crypto/x509/root.go b/contrib/go/_std_1.23/src/crypto/x509/root.go similarity index 86% rename from contrib/go/_std_1.22/src/crypto/x509/root.go rename to contrib/go/_std_1.23/src/crypto/x509/root.go index b454af2c4c19..fbd43430afa8 100644 --- a/contrib/go/_std_1.22/src/crypto/x509/root.go +++ b/contrib/go/_std_1.23/src/crypto/x509/root.go @@ -7,8 +7,18 @@ package x509 import ( "internal/godebug" "sync" + _ "unsafe" // for linkname ) +// systemRoots should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/breml/rootcerts +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname systemRoots var ( once sync.Once systemRootsMu sync.RWMutex diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_aix.go b/contrib/go/_std_1.23/src/crypto/x509/root_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_aix.go rename to contrib/go/_std_1.23/src/crypto/x509/root_aix.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_bsd.go b/contrib/go/_std_1.23/src/crypto/x509/root_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_bsd.go rename to contrib/go/_std_1.23/src/crypto/x509/root_bsd.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_darwin.go b/contrib/go/_std_1.23/src/crypto/x509/root_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_darwin.go rename to contrib/go/_std_1.23/src/crypto/x509/root_darwin.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_linux.go b/contrib/go/_std_1.23/src/crypto/x509/root_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_linux.go rename to contrib/go/_std_1.23/src/crypto/x509/root_linux.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_plan9.go b/contrib/go/_std_1.23/src/crypto/x509/root_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_plan9.go rename to contrib/go/_std_1.23/src/crypto/x509/root_plan9.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_solaris.go b/contrib/go/_std_1.23/src/crypto/x509/root_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_solaris.go rename to contrib/go/_std_1.23/src/crypto/x509/root_solaris.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_unix.go b/contrib/go/_std_1.23/src/crypto/x509/root_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_unix.go rename to contrib/go/_std_1.23/src/crypto/x509/root_unix.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_wasm.go b/contrib/go/_std_1.23/src/crypto/x509/root_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_wasm.go rename to contrib/go/_std_1.23/src/crypto/x509/root_wasm.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_windows.go b/contrib/go/_std_1.23/src/crypto/x509/root_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_windows.go rename to contrib/go/_std_1.23/src/crypto/x509/root_windows.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/sec1.go b/contrib/go/_std_1.23/src/crypto/x509/sec1.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/sec1.go rename to contrib/go/_std_1.23/src/crypto/x509/sec1.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/test-file.crt b/contrib/go/_std_1.23/src/crypto/x509/test-file.crt similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/test-file.crt rename to contrib/go/_std_1.23/src/crypto/x509/test-file.crt diff --git a/contrib/go/_std_1.22/src/crypto/x509/verify.go b/contrib/go/_std_1.23/src/crypto/x509/verify.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/x509/verify.go rename to contrib/go/_std_1.23/src/crypto/x509/verify.go index 6efbff28bf7b..bbccfce57742 100644 --- a/contrib/go/_std_1.22/src/crypto/x509/verify.go +++ b/contrib/go/_std_1.23/src/crypto/x509/verify.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "net" + "net/netip" "net/url" "reflect" "runtime" @@ -366,6 +367,11 @@ func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { } else { reverseLabels = append(reverseLabels, domain[i+1:]) domain = domain[:i] + if i == 0 { // domain == "" + // domain is prefixed with an empty label, append an empty + // string to reverseLabels to indicate this. + reverseLabels = append(reverseLabels, "") + } } } @@ -429,8 +435,10 @@ func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { } } - if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") || - net.ParseIP(host) != nil { + // netip.ParseAddr will reject the URI IPv6 literal form "[...]", so we + // check if _either_ the string parses as an IP, or if it is enclosed in + // square brackets. + if _, err := netip.ParseAddr(host); err == nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) { return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) } @@ -979,6 +987,11 @@ func validHostname(host string, isPattern bool) bool { if len(host) == 0 { return false } + if host == "*" { + // Bare wildcards are not allowed, they are not valid DNS names, + // nor are they allowed per RFC 6125. + return false + } for i, part := range strings.Split(host, ".") { if part == "" { diff --git a/contrib/go/_std_1.22/src/crypto/x509/x509.go b/contrib/go/_std_1.23/src/crypto/x509/x509.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/x509/x509.go rename to contrib/go/_std_1.23/src/crypto/x509/x509.go index 15b3b9ed35ee..50433058f74c 100644 --- a/contrib/go/_std_1.22/src/crypto/x509/x509.go +++ b/contrib/go/_std_1.23/src/crypto/x509/x509.go @@ -233,12 +233,21 @@ const ( ) func (algo SignatureAlgorithm) isRSAPSS() bool { - switch algo { - case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS: - return true - default: - return false + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + return details.isRSAPSS + } + } + return false +} + +func (algo SignatureAlgorithm) hashFunc() crypto.Hash { + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + return details.hash + } } + return crypto.Hash(0) } func (algo SignatureAlgorithm) String() string { @@ -281,8 +290,6 @@ func (algo PublicKeyAlgorithm) String() string { // // RFC 3279 2.2.1 RSA Signature Algorithms // -// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 } -// // md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } // // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } @@ -325,7 +332,6 @@ func (algo PublicKeyAlgorithm) String() string { // // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } var ( - oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} @@ -356,40 +362,43 @@ var signatureAlgorithmDetails = []struct { algo SignatureAlgorithm name string oid asn1.ObjectIdentifier + params asn1.RawValue pubKeyAlgo PublicKeyAlgorithm hash crypto.Hash + isRSAPSS bool }{ - {MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */}, - {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, RSA, crypto.MD5}, - {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, RSA, crypto.SHA1}, - {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1}, - {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, RSA, crypto.SHA256}, - {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, RSA, crypto.SHA384}, - {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, RSA, crypto.SHA512}, - {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA256}, - {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA384}, - {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA512}, - {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, DSA, crypto.SHA1}, - {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, DSA, crypto.SHA256}, - {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1}, - {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256}, - {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384}, - {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512}, - {PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */}, -} - -// hashToPSSParameters contains the DER encoded RSA PSS parameters for the + {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false}, + {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, + {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, + {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false}, + {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false}, + {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false}, + {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true}, + {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true}, + {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true}, + {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false}, + {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false}, + {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false}, + {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false}, + {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false}, + {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false}, + {PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false}, +} + +var emptyRawValue = asn1.RawValue{} + +// DER encoded RSA PSS parameters for the // SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3. // The parameters contain the following values: // - hashAlgorithm contains the associated hash identifier with NULL parameters // - maskGenAlgorithm always contains the default mgf1SHA1 identifier // - saltLength contains the length of the associated hash // - trailerField always contains the default trailerFieldBC value -var hashToPSSParameters = map[crypto.Hash]asn1.RawValue{ - crypto.SHA256: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}}, - crypto.SHA384: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}}, - crypto.SHA512: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}}, -} +var ( + pssParametersSHA256 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}} + pssParametersSHA384 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}} + pssParametersSHA512 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}} +) // pssParameters reflects the parameters in an AlgorithmIdentifier that // specifies RSA PSS. See RFC 3447, Appendix A.2.3. @@ -1102,7 +1111,7 @@ func isIA5String(s string) error { return nil } -var usePoliciesField = godebug.New("x509usepolicies") +var x509usepolicies = godebug.New("x509usepolicies") func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) { ret = make([]pkix.Extension, 10 /* maximum number of elements. */) @@ -1189,7 +1198,7 @@ func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKe n++ } - usePolicies := usePoliciesField.Value() == "1" + usePolicies := x509usepolicies.Value() == "1" if ((!usePolicies && len(template.PolicyIdentifiers) > 0) || (usePolicies && len(template.Policies) > 0)) && !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) { ret[n], err = marshalCertificatePolicies(template.Policies, template.PolicyIdentifiers) @@ -1382,8 +1391,8 @@ func marshalCertificatePolicies(policies []OID, policyIdentifiers []asn1.ObjectI b := cryptobyte.NewBuilder(make([]byte, 0, 128)) b.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { - if usePoliciesField.Value() == "1" { - usePoliciesField.IncNonDefault() + if x509usepolicies.Value() == "1" { + x509usepolicies.IncNonDefault() for _, v := range policies { child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { child.AddASN1(cryptobyte_asn1.OBJECT_IDENTIFIER, func(child *cryptobyte.Builder) { @@ -1436,81 +1445,91 @@ func subjectBytes(cert *Certificate) ([]byte, error) { return asn1.Marshal(cert.Subject.ToRDNSequence()) } -// signingParamsForPublicKey returns the parameters to use for signing with -// priv. If requestedSigAlgo is not zero then it overrides the default -// signature algorithm. -func signingParamsForPublicKey(pub any, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) { +// signingParamsForKey returns the signature algorithm and its Algorithm +// Identifier to use for signing, based on the key type. If sigAlgo is not zero +// then it overrides the default. +func signingParamsForKey(key crypto.Signer, sigAlgo SignatureAlgorithm) (SignatureAlgorithm, pkix.AlgorithmIdentifier, error) { + var ai pkix.AlgorithmIdentifier var pubType PublicKeyAlgorithm + var defaultAlgo SignatureAlgorithm - switch pub := pub.(type) { + switch pub := key.Public().(type) { case *rsa.PublicKey: pubType = RSA - hashFunc = crypto.SHA256 - sigAlgo.Algorithm = oidSignatureSHA256WithRSA - sigAlgo.Parameters = asn1.NullRawValue + defaultAlgo = SHA256WithRSA case *ecdsa.PublicKey: pubType = ECDSA - switch pub.Curve { case elliptic.P224(), elliptic.P256(): - hashFunc = crypto.SHA256 - sigAlgo.Algorithm = oidSignatureECDSAWithSHA256 + defaultAlgo = ECDSAWithSHA256 case elliptic.P384(): - hashFunc = crypto.SHA384 - sigAlgo.Algorithm = oidSignatureECDSAWithSHA384 + defaultAlgo = ECDSAWithSHA384 case elliptic.P521(): - hashFunc = crypto.SHA512 - sigAlgo.Algorithm = oidSignatureECDSAWithSHA512 + defaultAlgo = ECDSAWithSHA512 default: - err = errors.New("x509: unknown elliptic curve") + return 0, ai, errors.New("x509: unsupported elliptic curve") } case ed25519.PublicKey: pubType = Ed25519 - sigAlgo.Algorithm = oidSignatureEd25519 + defaultAlgo = PureEd25519 default: - err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported") + return 0, ai, errors.New("x509: only RSA, ECDSA and Ed25519 keys supported") } - if err != nil { - return + if sigAlgo == 0 { + sigAlgo = defaultAlgo } - if requestedSigAlgo == 0 { - return - } - - found := false for _, details := range signatureAlgorithmDetails { - if details.algo == requestedSigAlgo { + if details.algo == sigAlgo { if details.pubKeyAlgo != pubType { - err = errors.New("x509: requested SignatureAlgorithm does not match private key type") - return - } - sigAlgo.Algorithm, hashFunc = details.oid, details.hash - if hashFunc == 0 && pubType != Ed25519 { - err = errors.New("x509: cannot sign with hash function requested") - return - } - if hashFunc == crypto.MD5 { - err = errors.New("x509: signing with MD5 is not supported") - return + return 0, ai, errors.New("x509: requested SignatureAlgorithm does not match private key type") } - if requestedSigAlgo.isRSAPSS() { - sigAlgo.Parameters = hashToPSSParameters[hashFunc] + if details.hash == crypto.MD5 { + return 0, ai, errors.New("x509: signing with MD5 is not supported") } - found = true - break + + return sigAlgo, pkix.AlgorithmIdentifier{ + Algorithm: details.oid, + Parameters: details.params, + }, nil } } - if !found { - err = errors.New("x509: unknown SignatureAlgorithm") + return 0, ai, errors.New("x509: unknown SignatureAlgorithm") +} + +func signTBS(tbs []byte, key crypto.Signer, sigAlg SignatureAlgorithm, rand io.Reader) ([]byte, error) { + signed := tbs + hashFunc := sigAlg.hashFunc() + if hashFunc != 0 { + h := hashFunc.New() + h.Write(signed) + signed = h.Sum(nil) } - return + var signerOpts crypto.SignerOpts = hashFunc + if sigAlg.isRSAPSS() { + signerOpts = &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthEqualsHash, + Hash: hashFunc, + } + } + + signature, err := key.Sign(rand, signed, signerOpts) + if err != nil { + return nil, err + } + + // Check the signature to ensure the crypto.Signer behaved correctly. + if err := checkSignature(sigAlg, tbs, signature, key.Public(), true); err != nil { + return nil, fmt.Errorf("x509: signature returned by signer is invalid: %w", err) + } + + return signature, nil } // emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is @@ -1574,7 +1593,7 @@ var emptyASN1Subject = []byte{0x30, 0} // The PolicyIdentifier and Policies fields are both used to marshal certificate // policy OIDs. By default, only the PolicyIdentifier is marshaled, but if the // GODEBUG setting "x509usepolicies" has the value "1", the Policies field will -// be marshalled instead of the PolicyIdentifier field. The Policies field can +// be marshaled instead of the PolicyIdentifier field. The Policies field can // be used to marshal policy OIDs which have components that are larger than 31 // bits. func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv any) ([]byte, error) { @@ -1600,7 +1619,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen") } - hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm) if err != nil { return nil, err } @@ -1657,7 +1676,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv c := tbsCertificate{ Version: 2, SerialNumber: template.SerialNumber, - SignatureAlgorithm: signatureAlgorithm, + SignatureAlgorithm: algorithmIdentifier, Issuer: asn1.RawValue{FullBytes: asn1Issuer}, Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, Subject: asn1.RawValue{FullBytes: asn1Subject}, @@ -1671,42 +1690,16 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv } c.Raw = tbsCertContents - signed := tbsCertContents - if hashFunc != 0 { - h := hashFunc.New() - h.Write(signed) - signed = h.Sum(nil) - } - - var signerOpts crypto.SignerOpts = hashFunc - if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() { - signerOpts = &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthEqualsHash, - Hash: hashFunc, - } - } - - var signature []byte - signature, err = key.Sign(rand, signed, signerOpts) + signature, err := signTBS(tbsCertContents, key, signatureAlgorithm, rand) if err != nil { return nil, err } - signedCert, err := asn1.Marshal(certificate{ - c, - signatureAlgorithm, - asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, + return asn1.Marshal(certificate{ + TBSCertificate: c, + SignatureAlgorithm: algorithmIdentifier, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) - if err != nil { - return nil, err - } - - // Check the signature to ensure the crypto.Signer behaved correctly. - if err := checkSignature(getSignatureAlgorithmFromAI(signatureAlgorithm), c.Raw, signature, key.Public(), true); err != nil { - return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err) - } - - return signedCert, nil } // pemCRLPrefix is the magic string that indicates that we have a PEM encoded @@ -1756,7 +1749,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } - hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0) + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, 0) if err != nil { return nil, err } @@ -1770,7 +1763,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re tbsCertList := pkix.TBSCertificateList{ Version: 1, - Signature: signatureAlgorithm, + Signature: algorithmIdentifier, Issuer: c.Subject.ToRDNSequence(), ThisUpdate: now.UTC(), NextUpdate: expiry.UTC(), @@ -1783,32 +1776,25 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re aki.Id = oidExtensionAuthorityKeyId aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId}) if err != nil { - return + return nil, err } tbsCertList.Extensions = append(tbsCertList.Extensions, aki) } tbsCertListContents, err := asn1.Marshal(tbsCertList) if err != nil { - return - } - - signed := tbsCertListContents - if hashFunc != 0 { - h := hashFunc.New() - h.Write(signed) - signed = h.Sum(nil) + return nil, err } + tbsCertList.Raw = tbsCertListContents - var signature []byte - signature, err = key.Sign(rand, signed, hashFunc) + signature, err := signTBS(tbsCertListContents, key, signatureAlgorithm, rand) if err != nil { - return + return nil, err } return asn1.Marshal(pkix.CertificateList{ TBSCertList: tbsCertList, - SignatureAlgorithm: signatureAlgorithm, + SignatureAlgorithm: algorithmIdentifier, SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } @@ -1976,9 +1962,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } - var hashFunc crypto.Hash - var sigAlgo pkix.AlgorithmIdentifier - hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm) if err != nil { return nil, err } @@ -2050,7 +2034,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv rawAttributes, err := newRawAttributes(attributes) if err != nil { - return + return nil, err } // If not included in attributes, add a new attribute for the @@ -2100,30 +2084,19 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv tbsCSRContents, err := asn1.Marshal(tbsCSR) if err != nil { - return + return nil, err } tbsCSR.Raw = tbsCSRContents - signed := tbsCSRContents - if hashFunc != 0 { - h := hashFunc.New() - h.Write(signed) - signed = h.Sum(nil) - } - - var signature []byte - signature, err = key.Sign(rand, signed, hashFunc) + signature, err := signTBS(tbsCSRContents, key, signatureAlgorithm, rand) if err != nil { - return + return nil, err } return asn1.Marshal(certificateRequest{ TBSCSR: tbsCSR, - SignatureAlgorithm: sigAlgo, - SignatureValue: asn1.BitString{ - Bytes: signature, - BitLength: len(signature) * 8, - }, + SignatureAlgorithm: algorithmIdentifier, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } @@ -2351,7 +2324,7 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert return nil, errors.New("x509: template contains nil Number field") } - hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm) + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(priv, template.SignatureAlgorithm) if err != nil { return nil, err } @@ -2435,7 +2408,7 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert tbsCertList := tbsCertificateList{ Version: 1, // v2 - Signature: signatureAlgorithm, + Signature: algorithmIdentifier, Issuer: asn1.RawValue{FullBytes: issuerSubject}, ThisUpdate: template.ThisUpdate.UTC(), NextUpdate: template.NextUpdate.UTC(), @@ -2467,28 +2440,14 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert // then embedding in certificateList below. tbsCertList.Raw = tbsCertListContents - input := tbsCertListContents - if hashFunc != 0 { - h := hashFunc.New() - h.Write(tbsCertListContents) - input = h.Sum(nil) - } - var signerOpts crypto.SignerOpts = hashFunc - if template.SignatureAlgorithm.isRSAPSS() { - signerOpts = &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthEqualsHash, - Hash: hashFunc, - } - } - - signature, err := priv.Sign(rand, input, signerOpts) + signature, err := signTBS(tbsCertListContents, priv, signatureAlgorithm, rand) if err != nil { return nil, err } return asn1.Marshal(certificateList{ TBSCertList: tbsCertList, - SignatureAlgorithm: signatureAlgorithm, + SignatureAlgorithm: algorithmIdentifier, SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } diff --git a/contrib/go/_std_1.22/src/crypto/x509/x509_test_import.go b/contrib/go/_std_1.23/src/crypto/x509/x509_test_import.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/x509_test_import.go rename to contrib/go/_std_1.23/src/crypto/x509/x509_test_import.go diff --git a/contrib/go/_std_1.23/src/crypto/x509/ya.make b/contrib/go/_std_1.23/src/crypto/x509/ya.make new file mode 100644 index 000000000000..db0d6fda40d7 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/x509/ya.make @@ -0,0 +1,49 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + cert_pool.go + notboring.go + oid.go + parser.go + pem_decrypt.go + pkcs1.go + pkcs8.go + root.go + root_darwin.go + sec1.go + verify.go + x509.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + cert_pool.go + notboring.go + oid.go + parser.go + pem_decrypt.go + pkcs1.go + pkcs8.go + root.go + root_linux.go + root_unix.go + sec1.go + verify.go + x509.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + cert_pool.go + notboring.go + oid.go + parser.go + pem_decrypt.go + pkcs1.go + pkcs8.go + root.go + root_windows.go + sec1.go + verify.go + x509.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/ya.make b/contrib/go/_std_1.23/src/crypto/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ya.make rename to contrib/go/_std_1.23/src/crypto/ya.make diff --git a/contrib/go/_std_1.22/src/database/sql/driver/driver.go b/contrib/go/_std_1.23/src/database/sql/driver/driver.go similarity index 99% rename from contrib/go/_std_1.22/src/database/sql/driver/driver.go rename to contrib/go/_std_1.23/src/database/sql/driver/driver.go index da310bfb12a0..d0892e80fc28 100644 --- a/contrib/go/_std_1.22/src/database/sql/driver/driver.go +++ b/contrib/go/_std_1.23/src/database/sql/driver/driver.go @@ -415,7 +415,7 @@ type NamedValueChecker interface { type ColumnConverter interface { // ColumnConverter returns a ValueConverter for the provided // column index. If the type of a specific column isn't known - // or shouldn't be handled specially, DefaultValueConverter + // or shouldn't be handled specially, [DefaultParameterConverter] // can be returned. ColumnConverter(idx int) ValueConverter } diff --git a/contrib/go/_std_1.23/src/database/sql/driver/types.go b/contrib/go/_std_1.23/src/database/sql/driver/types.go new file mode 100644 index 000000000000..a322f85277c6 --- /dev/null +++ b/contrib/go/_std_1.23/src/database/sql/driver/types.go @@ -0,0 +1,302 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package driver + +import ( + "fmt" + "reflect" + "strconv" + "time" +) + +// ValueConverter is the interface providing the ConvertValue method. +// +// Various implementations of ValueConverter are provided by the +// driver package to provide consistent implementations of conversions +// between drivers. The ValueConverters have several uses: +// +// - converting from the [Value] types as provided by the sql package +// into a database table's specific column type and making sure it +// fits, such as making sure a particular int64 fits in a +// table's uint16 column. +// +// - converting a value as given from the database into one of the +// driver [Value] types. +// +// - by the [database/sql] package, for converting from a driver's [Value] type +// to a user's type in a scan. +type ValueConverter interface { + // ConvertValue converts a value to a driver Value. + ConvertValue(v any) (Value, error) +} + +// Valuer is the interface providing the Value method. +// +// Errors returned by the [Value] method are wrapped by the database/sql package. +// This allows callers to use [errors.Is] for precise error handling after operations +// like [database/sql.Query], [database/sql.Exec], or [database/sql.QueryRow]. +// +// Types implementing Valuer interface are able to convert +// themselves to a driver [Value]. +type Valuer interface { + // Value returns a driver Value. + // Value must not panic. + Value() (Value, error) +} + +// Bool is a [ValueConverter] that converts input values to bool. +// +// The conversion rules are: +// - booleans are returned unchanged +// - for integer types, +// 1 is true +// 0 is false, +// other integers are an error +// - for strings and []byte, same rules as [strconv.ParseBool] +// - all other types are an error +var Bool boolType + +type boolType struct{} + +var _ ValueConverter = boolType{} + +func (boolType) String() string { return "Bool" } + +func (boolType) ConvertValue(src any) (Value, error) { + switch s := src.(type) { + case bool: + return s, nil + case string: + b, err := strconv.ParseBool(s) + if err != nil { + return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) + } + return b, nil + case []byte: + b, err := strconv.ParseBool(string(s)) + if err != nil { + return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) + } + return b, nil + } + + sv := reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + iv := sv.Int() + if iv == 1 || iv == 0 { + return iv == 1, nil + } + return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", iv) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + uv := sv.Uint() + if uv == 1 || uv == 0 { + return uv == 1, nil + } + return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", uv) + } + + return nil, fmt.Errorf("sql/driver: couldn't convert %v (%T) into type bool", src, src) +} + +// Int32 is a [ValueConverter] that converts input values to int64, +// respecting the limits of an int32 value. +var Int32 int32Type + +type int32Type struct{} + +var _ ValueConverter = int32Type{} + +func (int32Type) ConvertValue(v any) (Value, error) { + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i64 := rv.Int() + if i64 > (1<<31)-1 || i64 < -(1<<31) { + return nil, fmt.Errorf("sql/driver: value %d overflows int32", v) + } + return i64, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u64 := rv.Uint() + if u64 > (1<<31)-1 { + return nil, fmt.Errorf("sql/driver: value %d overflows int32", v) + } + return int64(u64), nil + case reflect.String: + i, err := strconv.Atoi(rv.String()) + if err != nil { + return nil, fmt.Errorf("sql/driver: value %q can't be converted to int32", v) + } + return int64(i), nil + } + return nil, fmt.Errorf("sql/driver: unsupported value %v (type %T) converting to int32", v, v) +} + +// String is a [ValueConverter] that converts its input to a string. +// If the value is already a string or []byte, it's unchanged. +// If the value is of another type, conversion to string is done +// with fmt.Sprintf("%v", v). +var String stringType + +type stringType struct{} + +func (stringType) ConvertValue(v any) (Value, error) { + switch v.(type) { + case string, []byte: + return v, nil + } + return fmt.Sprintf("%v", v), nil +} + +// Null is a type that implements [ValueConverter] by allowing nil +// values but otherwise delegating to another [ValueConverter]. +type Null struct { + Converter ValueConverter +} + +func (n Null) ConvertValue(v any) (Value, error) { + if v == nil { + return nil, nil + } + return n.Converter.ConvertValue(v) +} + +// NotNull is a type that implements [ValueConverter] by disallowing nil +// values but otherwise delegating to another [ValueConverter]. +type NotNull struct { + Converter ValueConverter +} + +func (n NotNull) ConvertValue(v any) (Value, error) { + if v == nil { + return nil, fmt.Errorf("nil value not allowed") + } + return n.Converter.ConvertValue(v) +} + +// IsValue reports whether v is a valid [Value] parameter type. +func IsValue(v any) bool { + if v == nil { + return true + } + switch v.(type) { + case []byte, bool, float64, int64, string, time.Time: + return true + case decimalDecompose: + return true + } + return false +} + +// IsScanValue is equivalent to [IsValue]. +// It exists for compatibility. +func IsScanValue(v any) bool { + return IsValue(v) +} + +// DefaultParameterConverter is the default implementation of +// [ValueConverter] that's used when a [Stmt] doesn't implement +// [ColumnConverter]. +// +// DefaultParameterConverter returns its argument directly if +// IsValue(arg). Otherwise, if the argument implements [Valuer], its +// Value method is used to return a [Value]. As a fallback, the provided +// argument's underlying type is used to convert it to a [Value]: +// underlying integer types are converted to int64, floats to float64, +// bool, string, and []byte to themselves. If the argument is a nil +// pointer, defaultConverter.ConvertValue returns a nil [Value]. +// If the argument is a non-nil pointer, it is dereferenced and +// defaultConverter.ConvertValue is called recursively. Other types +// are an error. +var DefaultParameterConverter defaultConverter + +type defaultConverter struct{} + +var _ ValueConverter = defaultConverter{} + +var valuerReflectType = reflect.TypeFor[Valuer]() + +// callValuerValue returns vr.Value(), with one exception: +// If vr.Value is an auto-generated method on a pointer type and the +// pointer is nil, it would panic at runtime in the panicwrap +// method. Treat it like nil instead. +// Issue 8415. +// +// This is so people can implement driver.Value on value types and +// still use nil pointers to those types to mean nil/NULL, just like +// string/*string. +// +// This function is mirrored in the database/sql package. +func callValuerValue(vr Valuer) (v Value, err error) { + if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Pointer && + rv.IsNil() && + rv.Type().Elem().Implements(valuerReflectType) { + return nil, nil + } + return vr.Value() +} + +func (defaultConverter) ConvertValue(v any) (Value, error) { + if IsValue(v) { + return v, nil + } + + switch vr := v.(type) { + case Valuer: + sv, err := callValuerValue(vr) + if err != nil { + return nil, err + } + if !IsValue(sv) { + return nil, fmt.Errorf("non-Value type %T returned from Value", sv) + } + return sv, nil + + // For now, continue to prefer the Valuer interface over the decimal decompose interface. + case decimalDecompose: + return vr, nil + } + + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Pointer: + // indirect pointers + if rv.IsNil() { + return nil, nil + } else { + return defaultConverter{}.ConvertValue(rv.Elem().Interface()) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return rv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: + return int64(rv.Uint()), nil + case reflect.Uint64: + u64 := rv.Uint() + if u64 >= 1<<63 { + return nil, fmt.Errorf("uint64 values with high bit set are not supported") + } + return int64(u64), nil + case reflect.Float32, reflect.Float64: + return rv.Float(), nil + case reflect.Bool: + return rv.Bool(), nil + case reflect.Slice: + ek := rv.Type().Elem().Kind() + if ek == reflect.Uint8 { + return rv.Bytes(), nil + } + return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek) + case reflect.String: + return rv.String(), nil + } + return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) +} + +type decimalDecompose interface { + // Decompose returns the internal decimal state into parts. + // If the provided buf has sufficient capacity, buf may be returned as the coefficient with + // the value set and length set as appropriate. + Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) +} diff --git a/contrib/go/_std_1.22/src/database/sql/driver/ya.make b/contrib/go/_std_1.23/src/database/sql/driver/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/database/sql/driver/ya.make rename to contrib/go/_std_1.23/src/database/sql/driver/ya.make diff --git a/contrib/go/_std_1.22/src/embed/embed.go b/contrib/go/_std_1.23/src/embed/embed.go similarity index 96% rename from contrib/go/_std_1.22/src/embed/embed.go rename to contrib/go/_std_1.23/src/embed/embed.go index b7bb16099e56..f6c0ef9b9751 100644 --- a/contrib/go/_std_1.22/src/embed/embed.go +++ b/contrib/go/_std_1.23/src/embed/embed.go @@ -130,6 +130,8 @@ package embed import ( "errors" + "internal/bytealg" + "internal/stringslite" "io" "io/fs" "time" @@ -185,29 +187,14 @@ type FS struct { // comment in the FS struct above. isDir reports whether the // final trailing slash was present, indicating that name is a directory. func split(name string) (dir, elem string, isDir bool) { - if name[len(name)-1] == '/' { - isDir = true - name = name[:len(name)-1] - } - i := len(name) - 1 - for i >= 0 && name[i] != '/' { - i-- - } + name, isDir = stringslite.CutSuffix(name, "/") + i := bytealg.LastIndexByteString(name, '/') if i < 0 { return ".", name, isDir } return name[:i], name[i+1:], isDir } -// trimSlash trims a trailing slash from name, if present, -// returning the possibly shortened name. -func trimSlash(name string) string { - if len(name) > 0 && name[len(name)-1] == '/' { - return name[:len(name)-1] - } - return name -} - var ( _ fs.ReadDirFS = FS{} _ fs.ReadFileFS = FS{} @@ -274,7 +261,7 @@ func (f FS) lookup(name string) *file { idir, ielem, _ := split(files[i].name) return idir > dir || idir == dir && ielem >= elem }) - if i < len(files) && trimSlash(files[i].name) == name { + if i < len(files) && stringslite.TrimSuffix(files[i].name, "/") == name { return &files[i] } return nil diff --git a/contrib/go/_std_1.22/src/embed/internal/embedtest/concurrency.txt b/contrib/go/_std_1.23/src/embed/internal/embedtest/concurrency.txt similarity index 100% rename from contrib/go/_std_1.22/src/embed/internal/embedtest/concurrency.txt rename to contrib/go/_std_1.23/src/embed/internal/embedtest/concurrency.txt diff --git a/contrib/go/_std_1.22/src/embed/internal/embedtest/ya.make b/contrib/go/_std_1.23/src/embed/internal/embedtest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/embed/internal/embedtest/ya.make rename to contrib/go/_std_1.23/src/embed/internal/embedtest/ya.make diff --git a/contrib/go/_std_1.22/src/embed/internal/ya.make b/contrib/go/_std_1.23/src/embed/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/embed/internal/ya.make rename to contrib/go/_std_1.23/src/embed/internal/ya.make diff --git a/contrib/go/_std_1.22/src/embed/ya.make b/contrib/go/_std_1.23/src/embed/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/embed/ya.make rename to contrib/go/_std_1.23/src/embed/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/ascii85/ascii85.go b/contrib/go/_std_1.23/src/encoding/ascii85/ascii85.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/ascii85/ascii85.go rename to contrib/go/_std_1.23/src/encoding/ascii85/ascii85.go diff --git a/contrib/go/_std_1.22/src/encoding/ascii85/ya.make b/contrib/go/_std_1.23/src/encoding/ascii85/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/ascii85/ya.make rename to contrib/go/_std_1.23/src/encoding/ascii85/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/asn1/asn1.go b/contrib/go/_std_1.23/src/encoding/asn1/asn1.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/asn1/asn1.go rename to contrib/go/_std_1.23/src/encoding/asn1/asn1.go diff --git a/contrib/go/_std_1.22/src/encoding/asn1/common.go b/contrib/go/_std_1.23/src/encoding/asn1/common.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/asn1/common.go rename to contrib/go/_std_1.23/src/encoding/asn1/common.go diff --git a/contrib/go/_std_1.22/src/encoding/asn1/marshal.go b/contrib/go/_std_1.23/src/encoding/asn1/marshal.go similarity index 96% rename from contrib/go/_std_1.22/src/encoding/asn1/marshal.go rename to contrib/go/_std_1.23/src/encoding/asn1/marshal.go index d8c8fe17b374..b9c0b8bce054 100644 --- a/contrib/go/_std_1.22/src/encoding/asn1/marshal.go +++ b/contrib/go/_std_1.23/src/encoding/asn1/marshal.go @@ -10,7 +10,7 @@ import ( "fmt" "math/big" "reflect" - "sort" + "slices" "time" "unicode/utf8" ) @@ -105,15 +105,13 @@ func (s setEncoder) Encode(dst []byte) { e.Encode(l[i]) } - sort.Slice(l, func(i, j int) bool { - // Since we are using bytes.Compare to compare TLV encodings we - // don't need to right pad s[i] and s[j] to the same length as - // suggested in X690. If len(s[i]) < len(s[j]) the length octet of - // s[i], which is the first determining byte, will inherently be - // smaller than the length octet of s[j]. This lets us skip the - // padding step. - return bytes.Compare(l[i], l[j]) < 0 - }) + // Since we are using bytes.Compare to compare TLV encodings we + // don't need to right pad s[i] and s[j] to the same length as + // suggested in X690. If len(s[i]) < len(s[j]) the length octet of + // s[i], which is the first determining byte, will inherently be + // smaller than the length octet of s[j]. This lets us skip the + // padding step. + slices.SortFunc(l, bytes.Compare) var off int for _, b := range l { @@ -355,12 +353,11 @@ func appendTwoDigits(dst []byte, v int) []byte { } func appendFourDigits(dst []byte, v int) []byte { - var bytes [4]byte - for i := range bytes { - bytes[3-i] = '0' + byte(v%10) - v /= 10 - } - return append(dst, bytes[:]...) + return append(dst, + byte('0'+(v/1000)%10), + byte('0'+(v/100)%10), + byte('0'+(v/10)%10), + byte('0'+v%10)) } func outsideUTCRange(t time.Time) bool { diff --git a/contrib/go/_std_1.22/src/encoding/asn1/ya.make b/contrib/go/_std_1.23/src/encoding/asn1/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/asn1/ya.make rename to contrib/go/_std_1.23/src/encoding/asn1/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/base32/base32.go b/contrib/go/_std_1.23/src/encoding/base32/base32.go similarity index 99% rename from contrib/go/_std_1.22/src/encoding/base32/base32.go rename to contrib/go/_std_1.23/src/encoding/base32/base32.go index 4a61199a59d0..9e988ef39b4f 100644 --- a/contrib/go/_std_1.22/src/encoding/base32/base32.go +++ b/contrib/go/_std_1.23/src/encoding/base32/base32.go @@ -467,7 +467,7 @@ func (d *decoder) Read(p []byte) (n int, err error) { } // Read a chunk. - nn := len(p) / 5 * 8 + nn := (len(p) + 4) / 5 * 8 if nn < 8 { nn = 8 } diff --git a/contrib/go/_std_1.22/src/encoding/base32/ya.make b/contrib/go/_std_1.23/src/encoding/base32/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/base32/ya.make rename to contrib/go/_std_1.23/src/encoding/base32/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/base64/base64.go b/contrib/go/_std_1.23/src/encoding/base64/base64.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/base64/base64.go rename to contrib/go/_std_1.23/src/encoding/base64/base64.go diff --git a/contrib/go/_std_1.22/src/encoding/base64/ya.make b/contrib/go/_std_1.23/src/encoding/base64/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/base64/ya.make rename to contrib/go/_std_1.23/src/encoding/base64/ya.make diff --git a/contrib/go/_std_1.23/src/encoding/binary/binary.go b/contrib/go/_std_1.23/src/encoding/binary/binary.go new file mode 100644 index 000000000000..a150c0bf05be --- /dev/null +++ b/contrib/go/_std_1.23/src/encoding/binary/binary.go @@ -0,0 +1,1018 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package binary implements simple translation between numbers and byte +// sequences and encoding and decoding of varints. +// +// Numbers are translated by reading and writing fixed-size values. +// A fixed-size value is either a fixed-size arithmetic +// type (bool, int8, uint8, int16, float32, complex64, ...) +// or an array or struct containing only fixed-size values. +// +// The varint functions encode and decode single integer values using +// a variable-length encoding; smaller values require fewer bytes. +// For a specification, see +// https://developers.google.com/protocol-buffers/docs/encoding. +// +// This package favors simplicity over efficiency. Clients that require +// high-performance serialization, especially for large data structures, +// should look at more advanced solutions such as the [encoding/gob] +// package or [google.golang.org/protobuf] for protocol buffers. +package binary + +import ( + "errors" + "io" + "math" + "reflect" + "slices" + "sync" +) + +var errBufferTooSmall = errors.New("buffer too small") + +// A ByteOrder specifies how to convert byte slices into +// 16-, 32-, or 64-bit unsigned integers. +// +// It is implemented by [LittleEndian], [BigEndian], and [NativeEndian]. +type ByteOrder interface { + Uint16([]byte) uint16 + Uint32([]byte) uint32 + Uint64([]byte) uint64 + PutUint16([]byte, uint16) + PutUint32([]byte, uint32) + PutUint64([]byte, uint64) + String() string +} + +// AppendByteOrder specifies how to append 16-, 32-, or 64-bit unsigned integers +// into a byte slice. +// +// It is implemented by [LittleEndian], [BigEndian], and [NativeEndian]. +type AppendByteOrder interface { + AppendUint16([]byte, uint16) []byte + AppendUint32([]byte, uint32) []byte + AppendUint64([]byte, uint64) []byte + String() string +} + +// LittleEndian is the little-endian implementation of [ByteOrder] and [AppendByteOrder]. +var LittleEndian littleEndian + +// BigEndian is the big-endian implementation of [ByteOrder] and [AppendByteOrder]. +var BigEndian bigEndian + +type littleEndian struct{} + +func (littleEndian) Uint16(b []byte) uint16 { + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint16(b[0]) | uint16(b[1])<<8 +} + +func (littleEndian) PutUint16(b []byte, v uint16) { + _ = b[1] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) +} + +func (littleEndian) AppendUint16(b []byte, v uint16) []byte { + return append(b, + byte(v), + byte(v>>8), + ) +} + +func (littleEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func (littleEndian) PutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) +} + +func (littleEndian) AppendUint32(b []byte, v uint32) []byte { + return append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + ) +} + +func (littleEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func (littleEndian) PutUint64(b []byte, v uint64) { + _ = b[7] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) + b[4] = byte(v >> 32) + b[5] = byte(v >> 40) + b[6] = byte(v >> 48) + b[7] = byte(v >> 56) +} + +func (littleEndian) AppendUint64(b []byte, v uint64) []byte { + return append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + byte(v>>32), + byte(v>>40), + byte(v>>48), + byte(v>>56), + ) +} + +func (littleEndian) String() string { return "LittleEndian" } + +func (littleEndian) GoString() string { return "binary.LittleEndian" } + +type bigEndian struct{} + +func (bigEndian) Uint16(b []byte) uint16 { + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint16(b[1]) | uint16(b[0])<<8 +} + +func (bigEndian) PutUint16(b []byte, v uint16) { + _ = b[1] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 8) + b[1] = byte(v) +} + +func (bigEndian) AppendUint16(b []byte, v uint16) []byte { + return append(b, + byte(v>>8), + byte(v), + ) +} + +func (bigEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func (bigEndian) PutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 24) + b[1] = byte(v >> 16) + b[2] = byte(v >> 8) + b[3] = byte(v) +} + +func (bigEndian) AppendUint32(b []byte, v uint32) []byte { + return append(b, + byte(v>>24), + byte(v>>16), + byte(v>>8), + byte(v), + ) +} + +func (bigEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} + +func (bigEndian) PutUint64(b []byte, v uint64) { + _ = b[7] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 56) + b[1] = byte(v >> 48) + b[2] = byte(v >> 40) + b[3] = byte(v >> 32) + b[4] = byte(v >> 24) + b[5] = byte(v >> 16) + b[6] = byte(v >> 8) + b[7] = byte(v) +} + +func (bigEndian) AppendUint64(b []byte, v uint64) []byte { + return append(b, + byte(v>>56), + byte(v>>48), + byte(v>>40), + byte(v>>32), + byte(v>>24), + byte(v>>16), + byte(v>>8), + byte(v), + ) +} + +func (bigEndian) String() string { return "BigEndian" } + +func (bigEndian) GoString() string { return "binary.BigEndian" } + +func (nativeEndian) String() string { return "NativeEndian" } + +func (nativeEndian) GoString() string { return "binary.NativeEndian" } + +// Read reads structured binary data from r into data. +// Data must be a pointer to a fixed-size value or a slice +// of fixed-size values. +// Bytes read from r are decoded using the specified byte order +// and written to successive fields of the data. +// When decoding boolean values, a zero byte is decoded as false, and +// any other non-zero byte is decoded as true. +// When reading into structs, the field data for fields with +// blank (_) field names is skipped; i.e., blank field names +// may be used for padding. +// When reading into a struct, all non-blank fields must be exported +// or Read may panic. +// +// The error is [io.EOF] only if no bytes were read. +// If an [io.EOF] happens after reading some but not all the bytes, +// Read returns [io.ErrUnexpectedEOF]. +func Read(r io.Reader, order ByteOrder, data any) error { + // Fast path for basic types and slices. + if n, _ := intDataSize(data); n != 0 { + bs := make([]byte, n) + if _, err := io.ReadFull(r, bs); err != nil { + return err + } + + if decodeFast(bs, order, data) { + return nil + } + } + + // Fallback to reflect-based decoding. + v := reflect.ValueOf(data) + size := -1 + switch v.Kind() { + case reflect.Pointer: + v = v.Elem() + size = dataSize(v) + case reflect.Slice: + size = dataSize(v) + } + if size < 0 { + return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String()) + } + + d := &decoder{order: order, buf: make([]byte, size)} + if _, err := io.ReadFull(r, d.buf); err != nil { + return err + } + d.value(v) + return nil +} + +// Decode decodes binary data from buf into data according to +// the given byte order. +// It returns an error if buf is too small, otherwise the number of +// bytes consumed from buf. +func Decode(buf []byte, order ByteOrder, data any) (int, error) { + if n, _ := intDataSize(data); n != 0 { + if len(buf) < n { + return 0, errBufferTooSmall + } + + if decodeFast(buf, order, data) { + return n, nil + } + } + + // Fallback to reflect-based decoding. + v := reflect.ValueOf(data) + size := -1 + switch v.Kind() { + case reflect.Pointer: + v = v.Elem() + size = dataSize(v) + case reflect.Slice: + size = dataSize(v) + } + if size < 0 { + return 0, errors.New("binary.Decode: invalid type " + reflect.TypeOf(data).String()) + } + + if len(buf) < size { + return 0, errBufferTooSmall + } + d := &decoder{order: order, buf: buf[:size]} + d.value(v) + return size, nil +} + +func decodeFast(bs []byte, order ByteOrder, data any) bool { + switch data := data.(type) { + case *bool: + *data = bs[0] != 0 + case *int8: + *data = int8(bs[0]) + case *uint8: + *data = bs[0] + case *int16: + *data = int16(order.Uint16(bs)) + case *uint16: + *data = order.Uint16(bs) + case *int32: + *data = int32(order.Uint32(bs)) + case *uint32: + *data = order.Uint32(bs) + case *int64: + *data = int64(order.Uint64(bs)) + case *uint64: + *data = order.Uint64(bs) + case *float32: + *data = math.Float32frombits(order.Uint32(bs)) + case *float64: + *data = math.Float64frombits(order.Uint64(bs)) + case []bool: + for i, x := range bs { // Easier to loop over the input for 8-bit values. + data[i] = x != 0 + } + case []int8: + for i, x := range bs { + data[i] = int8(x) + } + case []uint8: + copy(data, bs) + case []int16: + for i := range data { + data[i] = int16(order.Uint16(bs[2*i:])) + } + case []uint16: + for i := range data { + data[i] = order.Uint16(bs[2*i:]) + } + case []int32: + for i := range data { + data[i] = int32(order.Uint32(bs[4*i:])) + } + case []uint32: + for i := range data { + data[i] = order.Uint32(bs[4*i:]) + } + case []int64: + for i := range data { + data[i] = int64(order.Uint64(bs[8*i:])) + } + case []uint64: + for i := range data { + data[i] = order.Uint64(bs[8*i:]) + } + case []float32: + for i := range data { + data[i] = math.Float32frombits(order.Uint32(bs[4*i:])) + } + case []float64: + for i := range data { + data[i] = math.Float64frombits(order.Uint64(bs[8*i:])) + } + default: + return false + } + return true +} + +// Write writes the binary representation of data into w. +// Data must be a fixed-size value or a slice of fixed-size +// values, or a pointer to such data. +// Boolean values encode as one byte: 1 for true, and 0 for false. +// Bytes written to w are encoded using the specified byte order +// and read from successive fields of the data. +// When writing structs, zero values are written for fields +// with blank (_) field names. +func Write(w io.Writer, order ByteOrder, data any) error { + // Fast path for basic types and slices. + if n, bs := intDataSize(data); n != 0 { + if bs == nil { + bs = make([]byte, n) + encodeFast(bs, order, data) + } + + _, err := w.Write(bs) + return err + } + + // Fallback to reflect-based encoding. + v := reflect.Indirect(reflect.ValueOf(data)) + size := dataSize(v) + if size < 0 { + return errors.New("binary.Write: some values are not fixed-sized in type " + reflect.TypeOf(data).String()) + } + + buf := make([]byte, size) + e := &encoder{order: order, buf: buf} + e.value(v) + _, err := w.Write(buf) + return err +} + +// Encode encodes the binary representation of data into buf according to +// the given byte order. +// It returns an error if buf is too small, otherwise the number of +// bytes written into buf. +func Encode(buf []byte, order ByteOrder, data any) (int, error) { + // Fast path for basic types and slices. + if n, _ := intDataSize(data); n != 0 { + if len(buf) < n { + return 0, errBufferTooSmall + } + + encodeFast(buf, order, data) + return n, nil + } + + // Fallback to reflect-based encoding. + v := reflect.Indirect(reflect.ValueOf(data)) + size := dataSize(v) + if size < 0 { + return 0, errors.New("binary.Encode: some values are not fixed-sized in type " + reflect.TypeOf(data).String()) + } + + if len(buf) < size { + return 0, errBufferTooSmall + } + e := &encoder{order: order, buf: buf} + e.value(v) + return size, nil +} + +// Append appends the binary representation of data to buf. +// buf may be nil, in which case a new buffer will be allocated. +// See [Write] on which data are acceptable. +// It returns the (possibily extended) buffer containing data or an error. +func Append(buf []byte, order ByteOrder, data any) ([]byte, error) { + // Fast path for basic types and slices. + if n, _ := intDataSize(data); n != 0 { + buf, pos := ensure(buf, n) + encodeFast(pos, order, data) + return buf, nil + } + + // Fallback to reflect-based encoding. + v := reflect.Indirect(reflect.ValueOf(data)) + size := dataSize(v) + if size < 0 { + return nil, errors.New("binary.Append: some values are not fixed-sized in type " + reflect.TypeOf(data).String()) + } + + buf, pos := ensure(buf, size) + e := &encoder{order: order, buf: pos} + e.value(v) + return buf, nil +} + +func encodeFast(bs []byte, order ByteOrder, data any) { + switch v := data.(type) { + case *bool: + if *v { + bs[0] = 1 + } else { + bs[0] = 0 + } + case bool: + if v { + bs[0] = 1 + } else { + bs[0] = 0 + } + case []bool: + for i, x := range v { + if x { + bs[i] = 1 + } else { + bs[i] = 0 + } + } + case *int8: + bs[0] = byte(*v) + case int8: + bs[0] = byte(v) + case []int8: + for i, x := range v { + bs[i] = byte(x) + } + case *uint8: + bs[0] = *v + case uint8: + bs[0] = v + case []uint8: + copy(bs, v) + case *int16: + order.PutUint16(bs, uint16(*v)) + case int16: + order.PutUint16(bs, uint16(v)) + case []int16: + for i, x := range v { + order.PutUint16(bs[2*i:], uint16(x)) + } + case *uint16: + order.PutUint16(bs, *v) + case uint16: + order.PutUint16(bs, v) + case []uint16: + for i, x := range v { + order.PutUint16(bs[2*i:], x) + } + case *int32: + order.PutUint32(bs, uint32(*v)) + case int32: + order.PutUint32(bs, uint32(v)) + case []int32: + for i, x := range v { + order.PutUint32(bs[4*i:], uint32(x)) + } + case *uint32: + order.PutUint32(bs, *v) + case uint32: + order.PutUint32(bs, v) + case []uint32: + for i, x := range v { + order.PutUint32(bs[4*i:], x) + } + case *int64: + order.PutUint64(bs, uint64(*v)) + case int64: + order.PutUint64(bs, uint64(v)) + case []int64: + for i, x := range v { + order.PutUint64(bs[8*i:], uint64(x)) + } + case *uint64: + order.PutUint64(bs, *v) + case uint64: + order.PutUint64(bs, v) + case []uint64: + for i, x := range v { + order.PutUint64(bs[8*i:], x) + } + case *float32: + order.PutUint32(bs, math.Float32bits(*v)) + case float32: + order.PutUint32(bs, math.Float32bits(v)) + case []float32: + for i, x := range v { + order.PutUint32(bs[4*i:], math.Float32bits(x)) + } + case *float64: + order.PutUint64(bs, math.Float64bits(*v)) + case float64: + order.PutUint64(bs, math.Float64bits(v)) + case []float64: + for i, x := range v { + order.PutUint64(bs[8*i:], math.Float64bits(x)) + } + } +} + +// Size returns how many bytes [Write] would generate to encode the value v, which +// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data. +// If v is neither of these, Size returns -1. +func Size(v any) int { + switch data := v.(type) { + case bool, int8, uint8: + return 1 + case *bool: + if data == nil { + return -1 + } + return 1 + case *int8: + if data == nil { + return -1 + } + return 1 + case *uint8: + if data == nil { + return -1 + } + return 1 + case []bool: + return len(data) + case []int8: + return len(data) + case []uint8: + return len(data) + case int16, uint16: + return 2 + case *int16: + if data == nil { + return -1 + } + return 2 + case *uint16: + if data == nil { + return -1 + } + return 2 + case []int16: + return 2 * len(data) + case []uint16: + return 2 * len(data) + case int32, uint32: + return 4 + case *int32: + if data == nil { + return -1 + } + return 4 + case *uint32: + if data == nil { + return -1 + } + return 4 + case []int32: + return 4 * len(data) + case []uint32: + return 4 * len(data) + case int64, uint64: + return 8 + case *int64: + if data == nil { + return -1 + } + return 8 + case *uint64: + if data == nil { + return -1 + } + return 8 + case []int64: + return 8 * len(data) + case []uint64: + return 8 * len(data) + case float32: + return 4 + case *float32: + if data == nil { + return -1 + } + return 4 + case float64: + return 8 + case *float64: + if data == nil { + return -1 + } + return 8 + case []float32: + return 4 * len(data) + case []float64: + return 8 * len(data) + } + return dataSize(reflect.Indirect(reflect.ValueOf(v))) +} + +var structSize sync.Map // map[reflect.Type]int + +// dataSize returns the number of bytes the actual data represented by v occupies in memory. +// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice +// it returns the length of the slice times the element size and does not count the memory +// occupied by the header. If the type of v is not acceptable, dataSize returns -1. +func dataSize(v reflect.Value) int { + switch v.Kind() { + case reflect.Slice, reflect.Array: + t := v.Type().Elem() + if size, ok := structSize.Load(t); ok { + return size.(int) * v.Len() + } + + size := sizeof(t) + if size >= 0 { + if t.Kind() == reflect.Struct { + structSize.Store(t, size) + } + return size * v.Len() + } + + case reflect.Struct: + t := v.Type() + if size, ok := structSize.Load(t); ok { + return size.(int) + } + size := sizeof(t) + structSize.Store(t, size) + return size + + default: + if v.IsValid() { + return sizeof(v.Type()) + } + } + + return -1 +} + +// sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable. +func sizeof(t reflect.Type) int { + switch t.Kind() { + case reflect.Array: + if s := sizeof(t.Elem()); s >= 0 { + return s * t.Len() + } + + case reflect.Struct: + sum := 0 + for i, n := 0, t.NumField(); i < n; i++ { + s := sizeof(t.Field(i).Type) + if s < 0 { + return -1 + } + sum += s + } + return sum + + case reflect.Bool, + reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + return int(t.Size()) + } + + return -1 +} + +type coder struct { + order ByteOrder + buf []byte + offset int +} + +type decoder coder +type encoder coder + +func (d *decoder) bool() bool { + x := d.buf[d.offset] + d.offset++ + return x != 0 +} + +func (e *encoder) bool(x bool) { + if x { + e.buf[e.offset] = 1 + } else { + e.buf[e.offset] = 0 + } + e.offset++ +} + +func (d *decoder) uint8() uint8 { + x := d.buf[d.offset] + d.offset++ + return x +} + +func (e *encoder) uint8(x uint8) { + e.buf[e.offset] = x + e.offset++ +} + +func (d *decoder) uint16() uint16 { + x := d.order.Uint16(d.buf[d.offset : d.offset+2]) + d.offset += 2 + return x +} + +func (e *encoder) uint16(x uint16) { + e.order.PutUint16(e.buf[e.offset:e.offset+2], x) + e.offset += 2 +} + +func (d *decoder) uint32() uint32 { + x := d.order.Uint32(d.buf[d.offset : d.offset+4]) + d.offset += 4 + return x +} + +func (e *encoder) uint32(x uint32) { + e.order.PutUint32(e.buf[e.offset:e.offset+4], x) + e.offset += 4 +} + +func (d *decoder) uint64() uint64 { + x := d.order.Uint64(d.buf[d.offset : d.offset+8]) + d.offset += 8 + return x +} + +func (e *encoder) uint64(x uint64) { + e.order.PutUint64(e.buf[e.offset:e.offset+8], x) + e.offset += 8 +} + +func (d *decoder) int8() int8 { return int8(d.uint8()) } + +func (e *encoder) int8(x int8) { e.uint8(uint8(x)) } + +func (d *decoder) int16() int16 { return int16(d.uint16()) } + +func (e *encoder) int16(x int16) { e.uint16(uint16(x)) } + +func (d *decoder) int32() int32 { return int32(d.uint32()) } + +func (e *encoder) int32(x int32) { e.uint32(uint32(x)) } + +func (d *decoder) int64() int64 { return int64(d.uint64()) } + +func (e *encoder) int64(x int64) { e.uint64(uint64(x)) } + +func (d *decoder) value(v reflect.Value) { + switch v.Kind() { + case reflect.Array: + l := v.Len() + for i := 0; i < l; i++ { + d.value(v.Index(i)) + } + + case reflect.Struct: + t := v.Type() + l := v.NumField() + for i := 0; i < l; i++ { + // Note: Calling v.CanSet() below is an optimization. + // It would be sufficient to check the field name, + // but creating the StructField info for each field is + // costly (run "go test -bench=ReadStruct" and compare + // results when making changes to this code). + if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" { + d.value(v) + } else { + d.skip(v) + } + } + + case reflect.Slice: + l := v.Len() + for i := 0; i < l; i++ { + d.value(v.Index(i)) + } + + case reflect.Bool: + v.SetBool(d.bool()) + + case reflect.Int8: + v.SetInt(int64(d.int8())) + case reflect.Int16: + v.SetInt(int64(d.int16())) + case reflect.Int32: + v.SetInt(int64(d.int32())) + case reflect.Int64: + v.SetInt(d.int64()) + + case reflect.Uint8: + v.SetUint(uint64(d.uint8())) + case reflect.Uint16: + v.SetUint(uint64(d.uint16())) + case reflect.Uint32: + v.SetUint(uint64(d.uint32())) + case reflect.Uint64: + v.SetUint(d.uint64()) + + case reflect.Float32: + v.SetFloat(float64(math.Float32frombits(d.uint32()))) + case reflect.Float64: + v.SetFloat(math.Float64frombits(d.uint64())) + + case reflect.Complex64: + v.SetComplex(complex( + float64(math.Float32frombits(d.uint32())), + float64(math.Float32frombits(d.uint32())), + )) + case reflect.Complex128: + v.SetComplex(complex( + math.Float64frombits(d.uint64()), + math.Float64frombits(d.uint64()), + )) + } +} + +func (e *encoder) value(v reflect.Value) { + switch v.Kind() { + case reflect.Array: + l := v.Len() + for i := 0; i < l; i++ { + e.value(v.Index(i)) + } + + case reflect.Struct: + t := v.Type() + l := v.NumField() + for i := 0; i < l; i++ { + // see comment for corresponding code in decoder.value() + if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" { + e.value(v) + } else { + e.skip(v) + } + } + + case reflect.Slice: + l := v.Len() + for i := 0; i < l; i++ { + e.value(v.Index(i)) + } + + case reflect.Bool: + e.bool(v.Bool()) + + case reflect.Int8: + e.int8(int8(v.Int())) + case reflect.Int16: + e.int16(int16(v.Int())) + case reflect.Int32: + e.int32(int32(v.Int())) + case reflect.Int64: + e.int64(v.Int()) + + case reflect.Uint8: + e.uint8(uint8(v.Uint())) + case reflect.Uint16: + e.uint16(uint16(v.Uint())) + case reflect.Uint32: + e.uint32(uint32(v.Uint())) + case reflect.Uint64: + e.uint64(v.Uint()) + + case reflect.Float32: + e.uint32(math.Float32bits(float32(v.Float()))) + case reflect.Float64: + e.uint64(math.Float64bits(v.Float())) + + case reflect.Complex64: + x := v.Complex() + e.uint32(math.Float32bits(float32(real(x)))) + e.uint32(math.Float32bits(float32(imag(x)))) + case reflect.Complex128: + x := v.Complex() + e.uint64(math.Float64bits(real(x))) + e.uint64(math.Float64bits(imag(x))) + } +} + +func (d *decoder) skip(v reflect.Value) { + d.offset += dataSize(v) +} + +func (e *encoder) skip(v reflect.Value) { + n := dataSize(v) + clear(e.buf[e.offset : e.offset+n]) + e.offset += n +} + +// intDataSize returns the size of the data required to represent the data when encoded, +// and optionally a byte slice containing the encoded data if no conversion is necessary. +// It returns zero, nil if the type cannot be implemented by the fast path in Read or Write. +func intDataSize(data any) (int, []byte) { + switch data := data.(type) { + case bool, int8, uint8, *bool, *int8, *uint8: + return 1, nil + case []bool: + return len(data), nil + case []int8: + return len(data), nil + case []uint8: + return len(data), data + case int16, uint16, *int16, *uint16: + return 2, nil + case []int16: + return 2 * len(data), nil + case []uint16: + return 2 * len(data), nil + case int32, uint32, *int32, *uint32: + return 4, nil + case []int32: + return 4 * len(data), nil + case []uint32: + return 4 * len(data), nil + case int64, uint64, *int64, *uint64: + return 8, nil + case []int64: + return 8 * len(data), nil + case []uint64: + return 8 * len(data), nil + case float32, *float32: + return 4, nil + case float64, *float64: + return 8, nil + case []float32: + return 4 * len(data), nil + case []float64: + return 8 * len(data), nil + } + return 0, nil +} + +// ensure grows buf to length len(buf) + n and returns the grown buffer +// and a slice starting at the original length of buf (that is, buf2[len(buf):]). +func ensure(buf []byte, n int) (buf2, pos []byte) { + l := len(buf) + buf = slices.Grow(buf, n)[:l+n] + return buf, buf[l:] +} diff --git a/contrib/go/_std_1.22/src/encoding/binary/native_endian_big.go b/contrib/go/_std_1.23/src/encoding/binary/native_endian_big.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/binary/native_endian_big.go rename to contrib/go/_std_1.23/src/encoding/binary/native_endian_big.go diff --git a/contrib/go/_std_1.22/src/encoding/binary/native_endian_little.go b/contrib/go/_std_1.23/src/encoding/binary/native_endian_little.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/binary/native_endian_little.go rename to contrib/go/_std_1.23/src/encoding/binary/native_endian_little.go diff --git a/contrib/go/_std_1.22/src/encoding/binary/varint.go b/contrib/go/_std_1.23/src/encoding/binary/varint.go similarity index 95% rename from contrib/go/_std_1.22/src/encoding/binary/varint.go rename to contrib/go/_std_1.23/src/encoding/binary/varint.go index 64dd9d61b443..c92ef82e823f 100644 --- a/contrib/go/_std_1.22/src/encoding/binary/varint.go +++ b/contrib/go/_std_1.23/src/encoding/binary/varint.go @@ -62,10 +62,9 @@ func PutUvarint(buf []byte, x uint64) int { // Uvarint decodes a uint64 from buf and returns that value and the // number of bytes read (> 0). If an error occurred, the value is 0 // and the number of bytes n is <= 0 meaning: -// -// n == 0: buf too small -// n < 0: value larger than 64 bits (overflow) -// and -n is the number of bytes read +// - n == 0: buf too small; +// - n < 0: value larger than 64 bits (overflow) and -n is the number of +// bytes read. func Uvarint(buf []byte) (uint64, int) { var x uint64 var s uint @@ -110,10 +109,9 @@ func PutVarint(buf []byte, x int64) int { // Varint decodes an int64 from buf and returns that value and the // number of bytes read (> 0). If an error occurred, the value is 0 // and the number of bytes n is <= 0 with the following meaning: -// -// n == 0: buf too small -// n < 0: value larger than 64 bits (overflow) -// and -n is the number of bytes read +// - n == 0: buf too small; +// - n < 0: value larger than 64 bits (overflow) +// and -n is the number of bytes read. func Varint(buf []byte) (int64, int) { ux, n := Uvarint(buf) // ok to continue in presence of error x := int64(ux >> 1) diff --git a/contrib/go/_std_1.22/src/encoding/binary/ya.make b/contrib/go/_std_1.23/src/encoding/binary/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/binary/ya.make rename to contrib/go/_std_1.23/src/encoding/binary/ya.make diff --git a/contrib/go/_std_1.23/src/encoding/csv/reader.go b/contrib/go/_std_1.23/src/encoding/csv/reader.go new file mode 100644 index 000000000000..df4702feded4 --- /dev/null +++ b/contrib/go/_std_1.23/src/encoding/csv/reader.go @@ -0,0 +1,467 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package csv reads and writes comma-separated values (CSV) files. +// There are many kinds of CSV files; this package supports the format +// described in RFC 4180, except that [Writer] uses LF +// instead of CRLF as newline character by default. +// +// A csv file contains zero or more records of one or more fields per record. +// Each record is separated by the newline character. The final record may +// optionally be followed by a newline character. +// +// field1,field2,field3 +// +// White space is considered part of a field. +// +// Carriage returns before newline characters are silently removed. +// +// Blank lines are ignored. A line with only whitespace characters (excluding +// the ending newline character) is not considered a blank line. +// +// Fields which start and stop with the quote character " are called +// quoted-fields. The beginning and ending quote are not part of the +// field. +// +// The source: +// +// normal string,"quoted-field" +// +// results in the fields +// +// {`normal string`, `quoted-field`} +// +// Within a quoted-field a quote character followed by a second quote +// character is considered a single quote. +// +// "the ""word"" is true","a ""quoted-field""" +// +// results in +// +// {`the "word" is true`, `a "quoted-field"`} +// +// Newlines and commas may be included in a quoted-field +// +// "Multi-line +// field","comma is ," +// +// results in +// +// {`Multi-line +// field`, `comma is ,`} +package csv + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "unicode" + "unicode/utf8" +) + +// A ParseError is returned for parsing errors. +// Line and column numbers are 1-indexed. +type ParseError struct { + StartLine int // Line where the record starts + Line int // Line where the error occurred + Column int // Column (1-based byte index) where the error occurred + Err error // The actual error +} + +func (e *ParseError) Error() string { + if e.Err == ErrFieldCount { + return fmt.Sprintf("record on line %d: %v", e.Line, e.Err) + } + if e.StartLine != e.Line { + return fmt.Sprintf("record on line %d; parse error on line %d, column %d: %v", e.StartLine, e.Line, e.Column, e.Err) + } + return fmt.Sprintf("parse error on line %d, column %d: %v", e.Line, e.Column, e.Err) +} + +func (e *ParseError) Unwrap() error { return e.Err } + +// These are the errors that can be returned in [ParseError.Err]. +var ( + ErrBareQuote = errors.New("bare \" in non-quoted-field") + ErrQuote = errors.New("extraneous or missing \" in quoted-field") + ErrFieldCount = errors.New("wrong number of fields") + + // Deprecated: ErrTrailingComma is no longer used. + ErrTrailingComma = errors.New("extra delimiter at end of line") +) + +var errInvalidDelim = errors.New("csv: invalid field or comment delimiter") + +func validDelim(r rune) bool { + return r != 0 && r != '"' && r != '\r' && r != '\n' && utf8.ValidRune(r) && r != utf8.RuneError +} + +// A Reader reads records from a CSV-encoded file. +// +// As returned by [NewReader], a Reader expects input conforming to RFC 4180. +// The exported fields can be changed to customize the details before the +// first call to [Reader.Read] or [Reader.ReadAll]. +// +// The Reader converts all \r\n sequences in its input to plain \n, +// including in multiline field values, so that the returned data does +// not depend on which line-ending convention an input file uses. +type Reader struct { + // Comma is the field delimiter. + // It is set to comma (',') by NewReader. + // Comma must be a valid rune and must not be \r, \n, + // or the Unicode replacement character (0xFFFD). + Comma rune + + // Comment, if not 0, is the comment character. Lines beginning with the + // Comment character without preceding whitespace are ignored. + // With leading whitespace the Comment character becomes part of the + // field, even if TrimLeadingSpace is true. + // Comment must be a valid rune and must not be \r, \n, + // or the Unicode replacement character (0xFFFD). + // It must also not be equal to Comma. + Comment rune + + // FieldsPerRecord is the number of expected fields per record. + // If FieldsPerRecord is positive, Read requires each record to + // have the given number of fields. If FieldsPerRecord is 0, Read sets it to + // the number of fields in the first record, so that future records must + // have the same field count. If FieldsPerRecord is negative, no check is + // made and records may have a variable number of fields. + FieldsPerRecord int + + // If LazyQuotes is true, a quote may appear in an unquoted field and a + // non-doubled quote may appear in a quoted field. + LazyQuotes bool + + // If TrimLeadingSpace is true, leading white space in a field is ignored. + // This is done even if the field delimiter, Comma, is white space. + TrimLeadingSpace bool + + // ReuseRecord controls whether calls to Read may return a slice sharing + // the backing array of the previous call's returned slice for performance. + // By default, each call to Read returns newly allocated memory owned by the caller. + ReuseRecord bool + + // Deprecated: TrailingComma is no longer used. + TrailingComma bool + + r *bufio.Reader + + // numLine is the current line being read in the CSV file. + numLine int + + // offset is the input stream byte offset of the current reader position. + offset int64 + + // rawBuffer is a line buffer only used by the readLine method. + rawBuffer []byte + + // recordBuffer holds the unescaped fields, one after another. + // The fields can be accessed by using the indexes in fieldIndexes. + // E.g., For the row `a,"b","c""d",e`, recordBuffer will contain `abc"de` + // and fieldIndexes will contain the indexes [1, 2, 5, 6]. + recordBuffer []byte + + // fieldIndexes is an index of fields inside recordBuffer. + // The i'th field ends at offset fieldIndexes[i] in recordBuffer. + fieldIndexes []int + + // fieldPositions is an index of field positions for the + // last record returned by Read. + fieldPositions []position + + // lastRecord is a record cache and only used when ReuseRecord == true. + lastRecord []string +} + +// NewReader returns a new Reader that reads from r. +func NewReader(r io.Reader) *Reader { + return &Reader{ + Comma: ',', + r: bufio.NewReader(r), + } +} + +// Read reads one record (a slice of fields) from r. +// If the record has an unexpected number of fields, +// Read returns the record along with the error [ErrFieldCount]. +// If the record contains a field that cannot be parsed, +// Read returns a partial record along with the parse error. +// The partial record contains all fields read before the error. +// If there is no data left to be read, Read returns nil, [io.EOF]. +// If [Reader.ReuseRecord] is true, the returned slice may be shared +// between multiple calls to Read. +func (r *Reader) Read() (record []string, err error) { + if r.ReuseRecord { + record, err = r.readRecord(r.lastRecord) + r.lastRecord = record + } else { + record, err = r.readRecord(nil) + } + return record, err +} + +// FieldPos returns the line and column corresponding to +// the start of the field with the given index in the slice most recently +// returned by [Reader.Read]. Numbering of lines and columns starts at 1; +// columns are counted in bytes, not runes. +// +// If this is called with an out-of-bounds index, it panics. +func (r *Reader) FieldPos(field int) (line, column int) { + if field < 0 || field >= len(r.fieldPositions) { + panic("out of range index passed to FieldPos") + } + p := &r.fieldPositions[field] + return p.line, p.col +} + +// InputOffset returns the input stream byte offset of the current reader +// position. The offset gives the location of the end of the most recently +// read row and the beginning of the next row. +func (r *Reader) InputOffset() int64 { + return r.offset +} + +// pos holds the position of a field in the current line. +type position struct { + line, col int +} + +// ReadAll reads all the remaining records from r. +// Each record is a slice of fields. +// A successful call returns err == nil, not err == [io.EOF]. Because ReadAll is +// defined to read until EOF, it does not treat end of file as an error to be +// reported. +func (r *Reader) ReadAll() (records [][]string, err error) { + for { + record, err := r.readRecord(nil) + if err == io.EOF { + return records, nil + } + if err != nil { + return nil, err + } + records = append(records, record) + } +} + +// readLine reads the next line (with the trailing endline). +// If EOF is hit without a trailing endline, it will be omitted. +// If some bytes were read, then the error is never [io.EOF]. +// The result is only valid until the next call to readLine. +func (r *Reader) readLine() ([]byte, error) { + line, err := r.r.ReadSlice('\n') + if err == bufio.ErrBufferFull { + r.rawBuffer = append(r.rawBuffer[:0], line...) + for err == bufio.ErrBufferFull { + line, err = r.r.ReadSlice('\n') + r.rawBuffer = append(r.rawBuffer, line...) + } + line = r.rawBuffer + } + readSize := len(line) + if readSize > 0 && err == io.EOF { + err = nil + // For backwards compatibility, drop trailing \r before EOF. + if line[readSize-1] == '\r' { + line = line[:readSize-1] + } + } + r.numLine++ + r.offset += int64(readSize) + // Normalize \r\n to \n on all input lines. + if n := len(line); n >= 2 && line[n-2] == '\r' && line[n-1] == '\n' { + line[n-2] = '\n' + line = line[:n-1] + } + return line, err +} + +// lengthNL reports the number of bytes for the trailing \n. +func lengthNL(b []byte) int { + if len(b) > 0 && b[len(b)-1] == '\n' { + return 1 + } + return 0 +} + +// nextRune returns the next rune in b or utf8.RuneError. +func nextRune(b []byte) rune { + r, _ := utf8.DecodeRune(b) + return r +} + +func (r *Reader) readRecord(dst []string) ([]string, error) { + if r.Comma == r.Comment || !validDelim(r.Comma) || (r.Comment != 0 && !validDelim(r.Comment)) { + return nil, errInvalidDelim + } + + // Read line (automatically skipping past empty lines and any comments). + var line []byte + var errRead error + for errRead == nil { + line, errRead = r.readLine() + if r.Comment != 0 && nextRune(line) == r.Comment { + line = nil + continue // Skip comment lines + } + if errRead == nil && len(line) == lengthNL(line) { + line = nil + continue // Skip empty lines + } + break + } + if errRead == io.EOF { + return nil, errRead + } + + // Parse each field in the record. + var err error + const quoteLen = len(`"`) + commaLen := utf8.RuneLen(r.Comma) + recLine := r.numLine // Starting line for record + r.recordBuffer = r.recordBuffer[:0] + r.fieldIndexes = r.fieldIndexes[:0] + r.fieldPositions = r.fieldPositions[:0] + pos := position{line: r.numLine, col: 1} +parseField: + for { + if r.TrimLeadingSpace { + i := bytes.IndexFunc(line, func(r rune) bool { + return !unicode.IsSpace(r) + }) + if i < 0 { + i = len(line) + pos.col -= lengthNL(line) + } + line = line[i:] + pos.col += i + } + if len(line) == 0 || line[0] != '"' { + // Non-quoted string field + i := bytes.IndexRune(line, r.Comma) + field := line + if i >= 0 { + field = field[:i] + } else { + field = field[:len(field)-lengthNL(field)] + } + // Check to make sure a quote does not appear in field. + if !r.LazyQuotes { + if j := bytes.IndexByte(field, '"'); j >= 0 { + col := pos.col + j + err = &ParseError{StartLine: recLine, Line: r.numLine, Column: col, Err: ErrBareQuote} + break parseField + } + } + r.recordBuffer = append(r.recordBuffer, field...) + r.fieldIndexes = append(r.fieldIndexes, len(r.recordBuffer)) + r.fieldPositions = append(r.fieldPositions, pos) + if i >= 0 { + line = line[i+commaLen:] + pos.col += i + commaLen + continue parseField + } + break parseField + } else { + // Quoted string field + fieldPos := pos + line = line[quoteLen:] + pos.col += quoteLen + for { + i := bytes.IndexByte(line, '"') + if i >= 0 { + // Hit next quote. + r.recordBuffer = append(r.recordBuffer, line[:i]...) + line = line[i+quoteLen:] + pos.col += i + quoteLen + switch rn := nextRune(line); { + case rn == '"': + // `""` sequence (append quote). + r.recordBuffer = append(r.recordBuffer, '"') + line = line[quoteLen:] + pos.col += quoteLen + case rn == r.Comma: + // `",` sequence (end of field). + line = line[commaLen:] + pos.col += commaLen + r.fieldIndexes = append(r.fieldIndexes, len(r.recordBuffer)) + r.fieldPositions = append(r.fieldPositions, fieldPos) + continue parseField + case lengthNL(line) == len(line): + // `"\n` sequence (end of line). + r.fieldIndexes = append(r.fieldIndexes, len(r.recordBuffer)) + r.fieldPositions = append(r.fieldPositions, fieldPos) + break parseField + case r.LazyQuotes: + // `"` sequence (bare quote). + r.recordBuffer = append(r.recordBuffer, '"') + default: + // `"*` sequence (invalid non-escaped quote). + err = &ParseError{StartLine: recLine, Line: r.numLine, Column: pos.col - quoteLen, Err: ErrQuote} + break parseField + } + } else if len(line) > 0 { + // Hit end of line (copy all data so far). + r.recordBuffer = append(r.recordBuffer, line...) + if errRead != nil { + break parseField + } + pos.col += len(line) + line, errRead = r.readLine() + if len(line) > 0 { + pos.line++ + pos.col = 1 + } + if errRead == io.EOF { + errRead = nil + } + } else { + // Abrupt end of file (EOF or error). + if !r.LazyQuotes && errRead == nil { + err = &ParseError{StartLine: recLine, Line: pos.line, Column: pos.col, Err: ErrQuote} + break parseField + } + r.fieldIndexes = append(r.fieldIndexes, len(r.recordBuffer)) + r.fieldPositions = append(r.fieldPositions, fieldPos) + break parseField + } + } + } + } + if err == nil { + err = errRead + } + + // Create a single string and create slices out of it. + // This pins the memory of the fields together, but allocates once. + str := string(r.recordBuffer) // Convert to string once to batch allocations + dst = dst[:0] + if cap(dst) < len(r.fieldIndexes) { + dst = make([]string, len(r.fieldIndexes)) + } + dst = dst[:len(r.fieldIndexes)] + var preIdx int + for i, idx := range r.fieldIndexes { + dst[i] = str[preIdx:idx] + preIdx = idx + } + + // Check or update the expected fields per record. + if r.FieldsPerRecord > 0 { + if len(dst) != r.FieldsPerRecord && err == nil { + err = &ParseError{ + StartLine: recLine, + Line: recLine, + Column: 1, + Err: ErrFieldCount, + } + } + } else if r.FieldsPerRecord == 0 { + r.FieldsPerRecord = len(dst) + } + return dst, err +} diff --git a/contrib/go/_std_1.22/src/encoding/csv/writer.go b/contrib/go/_std_1.23/src/encoding/csv/writer.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/csv/writer.go rename to contrib/go/_std_1.23/src/encoding/csv/writer.go diff --git a/contrib/go/_std_1.22/src/encoding/csv/ya.make b/contrib/go/_std_1.23/src/encoding/csv/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/csv/ya.make rename to contrib/go/_std_1.23/src/encoding/csv/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/encoding.go b/contrib/go/_std_1.23/src/encoding/encoding.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/encoding.go rename to contrib/go/_std_1.23/src/encoding/encoding.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/debug.go b/contrib/go/_std_1.23/src/encoding/gob/debug.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/debug.go rename to contrib/go/_std_1.23/src/encoding/gob/debug.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/dec_helpers.go b/contrib/go/_std_1.23/src/encoding/gob/dec_helpers.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/dec_helpers.go rename to contrib/go/_std_1.23/src/encoding/gob/dec_helpers.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/decgen.go b/contrib/go/_std_1.23/src/encoding/gob/decgen.go similarity index 98% rename from contrib/go/_std_1.22/src/encoding/gob/decgen.go rename to contrib/go/_std_1.23/src/encoding/gob/decgen.go index 27a30eaf61ab..af4cdbee9dfd 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/decgen.go +++ b/contrib/go/_std_1.23/src/encoding/gob/decgen.go @@ -192,6 +192,9 @@ func main() { if _, err := fd.Write(source); err != nil { log.Fatal(err) } + if err := fd.Close(); err != nil { + log.Fatal(err) + } } func printMaps(b *bytes.Buffer, upperClass string) { diff --git a/contrib/go/_std_1.23/src/encoding/gob/decode.go b/contrib/go/_std_1.23/src/encoding/gob/decode.go new file mode 100644 index 000000000000..26b5f6d62b63 --- /dev/null +++ b/contrib/go/_std_1.23/src/encoding/gob/decode.go @@ -0,0 +1,1309 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run decgen.go -output dec_helpers.go + +package gob + +import ( + "encoding" + "errors" + "internal/saferio" + "io" + "math" + "math/bits" + "reflect" +) + +var ( + errBadUint = errors.New("gob: encoded unsigned integer out of range") + errBadType = errors.New("gob: unknown type id or corrupted data") + errRange = errors.New("gob: bad data: field numbers out of bounds") +) + +type decHelper func(state *decoderState, v reflect.Value, length int, ovfl error) bool + +// decoderState is the execution state of an instance of the decoder. A new state +// is created for nested objects. +type decoderState struct { + dec *Decoder + // The buffer is stored with an extra indirection because it may be replaced + // if we load a type during decode (when reading an interface value). + b *decBuffer + fieldnum int // the last field number read. + next *decoderState // for free list +} + +// decBuffer is an extremely simple, fast implementation of a read-only byte buffer. +// It is initialized by calling Size and then copying the data into the slice returned by Bytes(). +type decBuffer struct { + data []byte + offset int // Read offset. +} + +func (d *decBuffer) Read(p []byte) (int, error) { + n := copy(p, d.data[d.offset:]) + if n == 0 && len(p) != 0 { + return 0, io.EOF + } + d.offset += n + return n, nil +} + +func (d *decBuffer) Drop(n int) { + if n > d.Len() { + panic("drop") + } + d.offset += n +} + +func (d *decBuffer) ReadByte() (byte, error) { + if d.offset >= len(d.data) { + return 0, io.EOF + } + c := d.data[d.offset] + d.offset++ + return c, nil +} + +func (d *decBuffer) Len() int { + return len(d.data) - d.offset +} + +func (d *decBuffer) Bytes() []byte { + return d.data[d.offset:] +} + +// SetBytes sets the buffer to the bytes, discarding any existing data. +func (d *decBuffer) SetBytes(data []byte) { + d.data = data + d.offset = 0 +} + +func (d *decBuffer) Reset() { + d.data = d.data[0:0] + d.offset = 0 +} + +// We pass the bytes.Buffer separately for easier testing of the infrastructure +// without requiring a full Decoder. +func (dec *Decoder) newDecoderState(buf *decBuffer) *decoderState { + d := dec.freeList + if d == nil { + d = new(decoderState) + d.dec = dec + } else { + dec.freeList = d.next + } + d.b = buf + return d +} + +func (dec *Decoder) freeDecoderState(d *decoderState) { + d.next = dec.freeList + dec.freeList = d +} + +func overflow(name string) error { + return errors.New(`value for "` + name + `" out of range`) +} + +// decodeUintReader reads an encoded unsigned integer from an io.Reader. +// Used only by the Decoder to read the message length. +func decodeUintReader(r io.Reader, buf []byte) (x uint64, width int, err error) { + width = 1 + n, err := io.ReadFull(r, buf[0:width]) + if n == 0 { + return + } + b := buf[0] + if b <= 0x7f { + return uint64(b), width, nil + } + n = -int(int8(b)) + if n > uint64Size { + err = errBadUint + return + } + width, err = io.ReadFull(r, buf[0:n]) + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return + } + // Could check that the high byte is zero but it's not worth it. + for _, b := range buf[0:width] { + x = x<<8 | uint64(b) + } + width++ // +1 for length byte + return +} + +// decodeUint reads an encoded unsigned integer from state.r. +// Does not check for overflow. +func (state *decoderState) decodeUint() (x uint64) { + b, err := state.b.ReadByte() + if err != nil { + error_(err) + } + if b <= 0x7f { + return uint64(b) + } + n := -int(int8(b)) + if n > uint64Size { + error_(errBadUint) + } + buf := state.b.Bytes() + if len(buf) < n { + errorf("invalid uint data length %d: exceeds input size %d", n, len(buf)) + } + // Don't need to check error; it's safe to loop regardless. + // Could check that the high byte is zero but it's not worth it. + for _, b := range buf[0:n] { + x = x<<8 | uint64(b) + } + state.b.Drop(n) + return x +} + +// decodeInt reads an encoded signed integer from state.r. +// Does not check for overflow. +func (state *decoderState) decodeInt() int64 { + x := state.decodeUint() + if x&1 != 0 { + return ^int64(x >> 1) + } + return int64(x >> 1) +} + +// getLength decodes the next uint and makes sure it is a possible +// size for a data item that follows, which means it must fit in a +// non-negative int and fit in the buffer. +func (state *decoderState) getLength() (int, bool) { + n := int(state.decodeUint()) + if n < 0 || state.b.Len() < n || tooBig <= n { + return 0, false + } + return n, true +} + +// decOp is the signature of a decoding operator for a given type. +type decOp func(i *decInstr, state *decoderState, v reflect.Value) + +// The 'instructions' of the decoding machine +type decInstr struct { + op decOp + field int // field number of the wire type + index []int // field access indices for destination type + ovfl error // error message for overflow/underflow (for arrays, of the elements) +} + +// ignoreUint discards a uint value with no destination. +func ignoreUint(i *decInstr, state *decoderState, v reflect.Value) { + state.decodeUint() +} + +// ignoreTwoUints discards a uint value with no destination. It's used to skip +// complex values. +func ignoreTwoUints(i *decInstr, state *decoderState, v reflect.Value) { + state.decodeUint() + state.decodeUint() +} + +// Since the encoder writes no zeros, if we arrive at a decoder we have +// a value to extract and store. The field number has already been read +// (it's how we knew to call this decoder). +// Each decoder is responsible for handling any indirections associated +// with the data structure. If any pointer so reached is nil, allocation must +// be done. + +// decAlloc takes a value and returns a settable value that can +// be assigned to. If the value is a pointer, decAlloc guarantees it points to storage. +// The callers to the individual decoders are expected to have used decAlloc. +// The individual decoders don't need it. +func decAlloc(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Pointer { + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + } + return v +} + +// decBool decodes a uint and stores it as a boolean in value. +func decBool(i *decInstr, state *decoderState, value reflect.Value) { + value.SetBool(state.decodeUint() != 0) +} + +// decInt8 decodes an integer and stores it as an int8 in value. +func decInt8(i *decInstr, state *decoderState, value reflect.Value) { + v := state.decodeInt() + if v < math.MinInt8 || math.MaxInt8 < v { + error_(i.ovfl) + } + value.SetInt(v) +} + +// decUint8 decodes an unsigned integer and stores it as a uint8 in value. +func decUint8(i *decInstr, state *decoderState, value reflect.Value) { + v := state.decodeUint() + if math.MaxUint8 < v { + error_(i.ovfl) + } + value.SetUint(v) +} + +// decInt16 decodes an integer and stores it as an int16 in value. +func decInt16(i *decInstr, state *decoderState, value reflect.Value) { + v := state.decodeInt() + if v < math.MinInt16 || math.MaxInt16 < v { + error_(i.ovfl) + } + value.SetInt(v) +} + +// decUint16 decodes an unsigned integer and stores it as a uint16 in value. +func decUint16(i *decInstr, state *decoderState, value reflect.Value) { + v := state.decodeUint() + if math.MaxUint16 < v { + error_(i.ovfl) + } + value.SetUint(v) +} + +// decInt32 decodes an integer and stores it as an int32 in value. +func decInt32(i *decInstr, state *decoderState, value reflect.Value) { + v := state.decodeInt() + if v < math.MinInt32 || math.MaxInt32 < v { + error_(i.ovfl) + } + value.SetInt(v) +} + +// decUint32 decodes an unsigned integer and stores it as a uint32 in value. +func decUint32(i *decInstr, state *decoderState, value reflect.Value) { + v := state.decodeUint() + if math.MaxUint32 < v { + error_(i.ovfl) + } + value.SetUint(v) +} + +// decInt64 decodes an integer and stores it as an int64 in value. +func decInt64(i *decInstr, state *decoderState, value reflect.Value) { + v := state.decodeInt() + value.SetInt(v) +} + +// decUint64 decodes an unsigned integer and stores it as a uint64 in value. +func decUint64(i *decInstr, state *decoderState, value reflect.Value) { + v := state.decodeUint() + value.SetUint(v) +} + +// Floating-point numbers are transmitted as uint64s holding the bits +// of the underlying representation. They are sent byte-reversed, with +// the exponent end coming out first, so integer floating point numbers +// (for example) transmit more compactly. This routine does the +// unswizzling. +func float64FromBits(u uint64) float64 { + v := bits.ReverseBytes64(u) + return math.Float64frombits(v) +} + +// float32FromBits decodes an unsigned integer, treats it as a 32-bit floating-point +// number, and returns it. It's a helper function for float32 and complex64. +// It returns a float64 because that's what reflection needs, but its return +// value is known to be accurately representable in a float32. +func float32FromBits(u uint64, ovfl error) float64 { + v := float64FromBits(u) + av := v + if av < 0 { + av = -av + } + // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK. + if math.MaxFloat32 < av && av <= math.MaxFloat64 { + error_(ovfl) + } + return v +} + +// decFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point +// number, and stores it in value. +func decFloat32(i *decInstr, state *decoderState, value reflect.Value) { + value.SetFloat(float32FromBits(state.decodeUint(), i.ovfl)) +} + +// decFloat64 decodes an unsigned integer, treats it as a 64-bit floating-point +// number, and stores it in value. +func decFloat64(i *decInstr, state *decoderState, value reflect.Value) { + value.SetFloat(float64FromBits(state.decodeUint())) +} + +// decComplex64 decodes a pair of unsigned integers, treats them as a +// pair of floating point numbers, and stores them as a complex64 in value. +// The real part comes first. +func decComplex64(i *decInstr, state *decoderState, value reflect.Value) { + real := float32FromBits(state.decodeUint(), i.ovfl) + imag := float32FromBits(state.decodeUint(), i.ovfl) + value.SetComplex(complex(real, imag)) +} + +// decComplex128 decodes a pair of unsigned integers, treats them as a +// pair of floating point numbers, and stores them as a complex128 in value. +// The real part comes first. +func decComplex128(i *decInstr, state *decoderState, value reflect.Value) { + real := float64FromBits(state.decodeUint()) + imag := float64FromBits(state.decodeUint()) + value.SetComplex(complex(real, imag)) +} + +// decUint8Slice decodes a byte slice and stores in value a slice header +// describing the data. +// uint8 slices are encoded as an unsigned count followed by the raw bytes. +func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) { + n, ok := state.getLength() + if !ok { + errorf("bad %s slice length: %d", value.Type(), n) + } + if value.Cap() < n { + safe := saferio.SliceCap[byte](uint64(n)) + if safe < 0 { + errorf("%s slice too big: %d elements", value.Type(), n) + } + value.Set(reflect.MakeSlice(value.Type(), safe, safe)) + ln := safe + i := 0 + for i < n { + if i >= ln { + // We didn't allocate the entire slice, + // due to using saferio.SliceCap. + // Grow the slice for one more element. + // The slice is full, so this should + // bump up the capacity. + value.Grow(1) + } + // Copy into s up to the capacity or n, + // whichever is less. + ln = value.Cap() + if ln > n { + ln = n + } + value.SetLen(ln) + sub := value.Slice(i, ln) + if _, err := state.b.Read(sub.Bytes()); err != nil { + errorf("error decoding []byte at %d: %s", i, err) + } + i = ln + } + } else { + value.SetLen(n) + if _, err := state.b.Read(value.Bytes()); err != nil { + errorf("error decoding []byte: %s", err) + } + } +} + +// decString decodes byte array and stores in value a string header +// describing the data. +// Strings are encoded as an unsigned count followed by the raw bytes. +func decString(i *decInstr, state *decoderState, value reflect.Value) { + n, ok := state.getLength() + if !ok { + errorf("bad %s slice length: %d", value.Type(), n) + } + // Read the data. + data := state.b.Bytes() + if len(data) < n { + errorf("invalid string length %d: exceeds input size %d", n, len(data)) + } + s := string(data[:n]) + state.b.Drop(n) + value.SetString(s) +} + +// ignoreUint8Array skips over the data for a byte slice value with no destination. +func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) { + n, ok := state.getLength() + if !ok { + errorf("slice length too large") + } + bn := state.b.Len() + if bn < n { + errorf("invalid slice length %d: exceeds input size %d", n, bn) + } + state.b.Drop(n) +} + +// Execution engine + +// The encoder engine is an array of instructions indexed by field number of the incoming +// decoder. It is executed with random access according to field number. +type decEngine struct { + instr []decInstr + numInstr int // the number of active instructions +} + +// decodeSingle decodes a top-level value that is not a struct and stores it in value. +// Such values are preceded by a zero, making them have the memory layout of a +// struct field (although with an illegal field number). +func (dec *Decoder) decodeSingle(engine *decEngine, value reflect.Value) { + state := dec.newDecoderState(&dec.buf) + defer dec.freeDecoderState(state) + state.fieldnum = singletonField + if state.decodeUint() != 0 { + errorf("decode: corrupted data: non-zero delta for singleton") + } + instr := &engine.instr[singletonField] + instr.op(instr, state, value) +} + +// decodeStruct decodes a top-level struct and stores it in value. +// Indir is for the value, not the type. At the time of the call it may +// differ from ut.indir, which was computed when the engine was built. +// This state cannot arise for decodeSingle, which is called directly +// from the user's value, not from the innards of an engine. +func (dec *Decoder) decodeStruct(engine *decEngine, value reflect.Value) { + state := dec.newDecoderState(&dec.buf) + defer dec.freeDecoderState(state) + state.fieldnum = -1 + for state.b.Len() > 0 { + delta := int(state.decodeUint()) + if delta < 0 { + errorf("decode: corrupted data: negative delta") + } + if delta == 0 { // struct terminator is zero delta fieldnum + break + } + if state.fieldnum >= len(engine.instr)-delta { // subtract to compare without overflow + error_(errRange) + } + fieldnum := state.fieldnum + delta + instr := &engine.instr[fieldnum] + var field reflect.Value + if instr.index != nil { + // Otherwise the field is unknown to us and instr.op is an ignore op. + field = value.FieldByIndex(instr.index) + if field.Kind() == reflect.Pointer { + field = decAlloc(field) + } + } + instr.op(instr, state, field) + state.fieldnum = fieldnum + } +} + +var noValue reflect.Value + +// ignoreStruct discards the data for a struct with no destination. +func (dec *Decoder) ignoreStruct(engine *decEngine) { + state := dec.newDecoderState(&dec.buf) + defer dec.freeDecoderState(state) + state.fieldnum = -1 + for state.b.Len() > 0 { + delta := int(state.decodeUint()) + if delta < 0 { + errorf("ignore decode: corrupted data: negative delta") + } + if delta == 0 { // struct terminator is zero delta fieldnum + break + } + fieldnum := state.fieldnum + delta + if fieldnum >= len(engine.instr) { + error_(errRange) + } + instr := &engine.instr[fieldnum] + instr.op(instr, state, noValue) + state.fieldnum = fieldnum + } +} + +// ignoreSingle discards the data for a top-level non-struct value with no +// destination. It's used when calling Decode with a nil value. +func (dec *Decoder) ignoreSingle(engine *decEngine) { + state := dec.newDecoderState(&dec.buf) + defer dec.freeDecoderState(state) + state.fieldnum = singletonField + delta := int(state.decodeUint()) + if delta != 0 { + errorf("decode: corrupted data: non-zero delta for singleton") + } + instr := &engine.instr[singletonField] + instr.op(instr, state, noValue) +} + +// decodeArrayHelper does the work for decoding arrays and slices. +func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) { + if helper != nil && helper(state, value, length, ovfl) { + return + } + instr := &decInstr{elemOp, 0, nil, ovfl} + isPtr := value.Type().Elem().Kind() == reflect.Pointer + ln := value.Len() + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding array or slice: length exceeds input size (%d elements)", length) + } + if i >= ln { + // This is a slice that we only partially allocated. + // Grow it up to length. + value.Grow(1) + cp := value.Cap() + if cp > length { + cp = length + } + value.SetLen(cp) + ln = cp + } + v := value.Index(i) + if isPtr { + v = decAlloc(v) + } + elemOp(instr, state, v) + } +} + +// decodeArray decodes an array and stores it in value. +// The length is an unsigned integer preceding the elements. Even though the length is redundant +// (it's part of the type), it's a useful check and is included in the encoding. +func (dec *Decoder) decodeArray(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) { + if n := state.decodeUint(); n != uint64(length) { + errorf("length mismatch in decodeArray") + } + dec.decodeArrayHelper(state, value, elemOp, length, ovfl, helper) +} + +// decodeIntoValue is a helper for map decoding. +func decodeIntoValue(state *decoderState, op decOp, isPtr bool, value reflect.Value, instr *decInstr) reflect.Value { + v := value + if isPtr { + v = decAlloc(value) + } + + op(instr, state, v) + return value +} + +// decodeMap decodes a map and stores it in value. +// Maps are encoded as a length followed by key:value pairs. +// Because the internals of maps are not visible to us, we must +// use reflection rather than pointer magic. +func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value reflect.Value, keyOp, elemOp decOp, ovfl error) { + n := int(state.decodeUint()) + if value.IsNil() { + value.Set(reflect.MakeMapWithSize(mtyp, n)) + } + keyIsPtr := mtyp.Key().Kind() == reflect.Pointer + elemIsPtr := mtyp.Elem().Kind() == reflect.Pointer + keyInstr := &decInstr{keyOp, 0, nil, ovfl} + elemInstr := &decInstr{elemOp, 0, nil, ovfl} + keyP := reflect.New(mtyp.Key()) + elemP := reflect.New(mtyp.Elem()) + for i := 0; i < n; i++ { + key := decodeIntoValue(state, keyOp, keyIsPtr, keyP.Elem(), keyInstr) + elem := decodeIntoValue(state, elemOp, elemIsPtr, elemP.Elem(), elemInstr) + value.SetMapIndex(key, elem) + keyP.Elem().SetZero() + elemP.Elem().SetZero() + } +} + +// ignoreArrayHelper does the work for discarding arrays and slices. +func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) { + instr := &decInstr{elemOp, 0, nil, errors.New("no error")} + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding array or slice: length exceeds input size (%d elements)", length) + } + elemOp(instr, state, noValue) + } +} + +// ignoreArray discards the data for an array value with no destination. +func (dec *Decoder) ignoreArray(state *decoderState, elemOp decOp, length int) { + if n := state.decodeUint(); n != uint64(length) { + errorf("length mismatch in ignoreArray") + } + dec.ignoreArrayHelper(state, elemOp, length) +} + +// ignoreMap discards the data for a map value with no destination. +func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) { + n := int(state.decodeUint()) + keyInstr := &decInstr{keyOp, 0, nil, errors.New("no error")} + elemInstr := &decInstr{elemOp, 0, nil, errors.New("no error")} + for i := 0; i < n; i++ { + keyOp(keyInstr, state, noValue) + elemOp(elemInstr, state, noValue) + } +} + +// decodeSlice decodes a slice and stores it in value. +// Slices are encoded as an unsigned length followed by the elements. +func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error, helper decHelper) { + u := state.decodeUint() + typ := value.Type() + size := uint64(typ.Elem().Size()) + nBytes := u * size + n := int(u) + // Take care with overflow in this calculation. + if n < 0 || uint64(n) != u || nBytes > tooBig || (size > 0 && nBytes/size != u) { + // We don't check n against buffer length here because if it's a slice + // of interfaces, there will be buffer reloads. + errorf("%s slice too big: %d elements of %d bytes", typ.Elem(), u, size) + } + if value.Cap() < n { + safe := saferio.SliceCapWithSize(size, uint64(n)) + if safe < 0 { + errorf("%s slice too big: %d elements of %d bytes", typ.Elem(), u, size) + } + value.Set(reflect.MakeSlice(typ, safe, safe)) + } else { + value.SetLen(n) + } + dec.decodeArrayHelper(state, value, elemOp, n, ovfl, helper) +} + +// ignoreSlice skips over the data for a slice value with no destination. +func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) { + dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint())) +} + +// decodeInterface decodes an interface value and stores it in value. +// Interfaces are encoded as the name of a concrete type followed by a value. +// If the name is empty, the value is nil and no value is sent. +func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, value reflect.Value) { + // Read the name of the concrete type. + nr := state.decodeUint() + if nr > 1<<31 { // zero is permissible for anonymous types + errorf("invalid type name length %d", nr) + } + if nr > uint64(state.b.Len()) { + errorf("invalid type name length %d: exceeds input size", nr) + } + n := int(nr) + name := state.b.Bytes()[:n] + state.b.Drop(n) + // Allocate the destination interface value. + if len(name) == 0 { + // Copy the nil interface value to the target. + value.SetZero() + return + } + if len(name) > 1024 { + errorf("name too long (%d bytes): %.20q...", len(name), name) + } + // The concrete type must be registered. + typi, ok := nameToConcreteType.Load(string(name)) + if !ok { + errorf("name not registered for interface: %q", name) + } + typ := typi.(reflect.Type) + + // Read the type id of the concrete value. + concreteId := dec.decodeTypeSequence(true) + if concreteId < 0 { + error_(dec.err) + } + // Byte count of value is next; we don't care what it is (it's there + // in case we want to ignore the value by skipping it completely). + state.decodeUint() + // Read the concrete value. + v := allocValue(typ) + dec.decodeValue(concreteId, v) + if dec.err != nil { + error_(dec.err) + } + // Assign the concrete value to the interface. + // Tread carefully; it might not satisfy the interface. + if !typ.AssignableTo(ityp) { + errorf("%s is not assignable to type %s", typ, ityp) + } + // Copy the interface value to the target. + value.Set(v) +} + +// ignoreInterface discards the data for an interface value with no destination. +func (dec *Decoder) ignoreInterface(state *decoderState) { + // Read the name of the concrete type. + n, ok := state.getLength() + if !ok { + errorf("bad interface encoding: name too large for buffer") + } + bn := state.b.Len() + if bn < n { + errorf("invalid interface value length %d: exceeds input size %d", n, bn) + } + state.b.Drop(n) + id := dec.decodeTypeSequence(true) + if id < 0 { + error_(dec.err) + } + // At this point, the decoder buffer contains a delimited value. Just toss it. + n, ok = state.getLength() + if !ok { + errorf("bad interface encoding: data length too large for buffer") + } + state.b.Drop(n) +} + +// decodeGobDecoder decodes something implementing the GobDecoder interface. +// The data is encoded as a byte slice. +func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, value reflect.Value) { + // Read the bytes for the value. + n, ok := state.getLength() + if !ok { + errorf("GobDecoder: length too large for buffer") + } + b := state.b.Bytes() + if len(b) < n { + errorf("GobDecoder: invalid data length %d: exceeds input size %d", n, len(b)) + } + b = b[:n] + state.b.Drop(n) + var err error + // We know it's one of these. + switch ut.externalDec { + case xGob: + err = value.Interface().(GobDecoder).GobDecode(b) + case xBinary: + err = value.Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(b) + case xText: + err = value.Interface().(encoding.TextUnmarshaler).UnmarshalText(b) + } + if err != nil { + error_(err) + } +} + +// ignoreGobDecoder discards the data for a GobDecoder value with no destination. +func (dec *Decoder) ignoreGobDecoder(state *decoderState) { + // Read the bytes for the value. + n, ok := state.getLength() + if !ok { + errorf("GobDecoder: length too large for buffer") + } + bn := state.b.Len() + if bn < n { + errorf("GobDecoder: invalid data length %d: exceeds input size %d", n, bn) + } + state.b.Drop(n) +} + +// Index by Go types. +var decOpTable = [...]decOp{ + reflect.Bool: decBool, + reflect.Int8: decInt8, + reflect.Int16: decInt16, + reflect.Int32: decInt32, + reflect.Int64: decInt64, + reflect.Uint8: decUint8, + reflect.Uint16: decUint16, + reflect.Uint32: decUint32, + reflect.Uint64: decUint64, + reflect.Float32: decFloat32, + reflect.Float64: decFloat64, + reflect.Complex64: decComplex64, + reflect.Complex128: decComplex128, + reflect.String: decString, +} + +// Indexed by gob types. tComplex will be added during type.init(). +var decIgnoreOpMap = map[typeId]decOp{ + tBool: ignoreUint, + tInt: ignoreUint, + tUint: ignoreUint, + tFloat: ignoreUint, + tBytes: ignoreUint8Array, + tString: ignoreUint8Array, + tComplex: ignoreTwoUints, +} + +// decOpFor returns the decoding op for the base type under rt and +// the indirection count to reach it. +func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProgress map[reflect.Type]*decOp) *decOp { + ut := userType(rt) + // If the type implements GobEncoder, we handle it without further processing. + if ut.externalDec != 0 { + return dec.gobDecodeOpFor(ut) + } + + // If this type is already in progress, it's a recursive type (e.g. map[string]*T). + // Return the pointer to the op we're already building. + if opPtr := inProgress[rt]; opPtr != nil { + return opPtr + } + typ := ut.base + var op decOp + k := typ.Kind() + if int(k) < len(decOpTable) { + op = decOpTable[k] + } + if op == nil { + inProgress[rt] = &op + // Special cases + switch t := typ; t.Kind() { + case reflect.Array: + name = "element of " + name + elemId := dec.wireType[wireId].ArrayT.Elem + elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress) + ovfl := overflow(name) + helper := decArrayHelper[t.Elem().Kind()] + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.decodeArray(state, value, *elemOp, t.Len(), ovfl, helper) + } + + case reflect.Map: + keyId := dec.wireType[wireId].MapT.Key + elemId := dec.wireType[wireId].MapT.Elem + keyOp := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress) + elemOp := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress) + ovfl := overflow(name) + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.decodeMap(t, state, value, *keyOp, *elemOp, ovfl) + } + + case reflect.Slice: + name = "element of " + name + if t.Elem().Kind() == reflect.Uint8 { + op = decUint8Slice + break + } + var elemId typeId + if tt := builtinIdToType(wireId); tt != nil { + elemId = tt.(*sliceType).Elem + } else { + elemId = dec.wireType[wireId].SliceT.Elem + } + elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress) + ovfl := overflow(name) + helper := decSliceHelper[t.Elem().Kind()] + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.decodeSlice(state, value, *elemOp, ovfl, helper) + } + + case reflect.Struct: + // Generate a closure that calls out to the engine for the nested type. + ut := userType(typ) + enginePtr, err := dec.getDecEnginePtr(wireId, ut) + if err != nil { + error_(err) + } + op = func(i *decInstr, state *decoderState, value reflect.Value) { + // indirect through enginePtr to delay evaluation for recursive structs. + dec.decodeStruct(*enginePtr, value) + } + case reflect.Interface: + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.decodeInterface(t, state, value) + } + } + } + if op == nil { + errorf("decode can't handle type %s", rt) + } + return &op +} + +var maxIgnoreNestingDepth = 10000 + +// decIgnoreOpFor returns the decoding op for a field that has no destination. +func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp { + // Track how deep we've recursed trying to skip nested ignored fields. + dec.ignoreDepth++ + defer func() { dec.ignoreDepth-- }() + if dec.ignoreDepth > maxIgnoreNestingDepth { + error_(errors.New("invalid nesting depth")) + } + // If this type is already in progress, it's a recursive type (e.g. map[string]*T). + // Return the pointer to the op we're already building. + if opPtr := inProgress[wireId]; opPtr != nil { + return opPtr + } + op, ok := decIgnoreOpMap[wireId] + if !ok { + inProgress[wireId] = &op + if wireId == tInterface { + // Special case because it's a method: the ignored item might + // define types and we need to record their state in the decoder. + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.ignoreInterface(state) + } + return &op + } + // Special cases + wire := dec.wireType[wireId] + switch { + case wire == nil: + errorf("bad data: undefined type %s", wireId.string()) + case wire.ArrayT != nil: + elemId := wire.ArrayT.Elem + elemOp := dec.decIgnoreOpFor(elemId, inProgress) + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len) + } + + case wire.MapT != nil: + keyId := dec.wireType[wireId].MapT.Key + elemId := dec.wireType[wireId].MapT.Elem + keyOp := dec.decIgnoreOpFor(keyId, inProgress) + elemOp := dec.decIgnoreOpFor(elemId, inProgress) + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.ignoreMap(state, *keyOp, *elemOp) + } + + case wire.SliceT != nil: + elemId := wire.SliceT.Elem + elemOp := dec.decIgnoreOpFor(elemId, inProgress) + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.ignoreSlice(state, *elemOp) + } + + case wire.StructT != nil: + // Generate a closure that calls out to the engine for the nested type. + enginePtr, err := dec.getIgnoreEnginePtr(wireId) + if err != nil { + error_(err) + } + op = func(i *decInstr, state *decoderState, value reflect.Value) { + // indirect through enginePtr to delay evaluation for recursive structs + state.dec.ignoreStruct(*enginePtr) + } + + case wire.GobEncoderT != nil, wire.BinaryMarshalerT != nil, wire.TextMarshalerT != nil: + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.ignoreGobDecoder(state) + } + } + } + if op == nil { + errorf("bad data: ignore can't handle type %s", wireId.string()) + } + return &op +} + +// gobDecodeOpFor returns the op for a type that is known to implement +// GobDecoder. +func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) *decOp { + rcvrType := ut.user + if ut.decIndir == -1 { + rcvrType = reflect.PointerTo(rcvrType) + } else if ut.decIndir > 0 { + for i := int8(0); i < ut.decIndir; i++ { + rcvrType = rcvrType.Elem() + } + } + var op decOp + op = func(i *decInstr, state *decoderState, value reflect.Value) { + // We now have the base type. We need its address if the receiver is a pointer. + if value.Kind() != reflect.Pointer && rcvrType.Kind() == reflect.Pointer { + value = value.Addr() + } + state.dec.decodeGobDecoder(ut, state, value) + } + return &op +} + +// compatibleType asks: Are these two gob Types compatible? +// Answers the question for basic types, arrays, maps and slices, plus +// GobEncoder/Decoder pairs. +// Structs are considered ok; fields will be checked later. +func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId, inProgress map[reflect.Type]typeId) bool { + if rhs, ok := inProgress[fr]; ok { + return rhs == fw + } + inProgress[fr] = fw + ut := userType(fr) + wire, ok := dec.wireType[fw] + // If wire was encoded with an encoding method, fr must have that method. + // And if not, it must not. + // At most one of the booleans in ut is set. + // We could possibly relax this constraint in the future in order to + // choose the decoding method using the data in the wireType. + // The parentheses look odd but are correct. + if (ut.externalDec == xGob) != (ok && wire.GobEncoderT != nil) || + (ut.externalDec == xBinary) != (ok && wire.BinaryMarshalerT != nil) || + (ut.externalDec == xText) != (ok && wire.TextMarshalerT != nil) { + return false + } + if ut.externalDec != 0 { // This test trumps all others. + return true + } + switch t := ut.base; t.Kind() { + default: + // chan, etc: cannot handle. + return false + case reflect.Bool: + return fw == tBool + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return fw == tInt + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return fw == tUint + case reflect.Float32, reflect.Float64: + return fw == tFloat + case reflect.Complex64, reflect.Complex128: + return fw == tComplex + case reflect.String: + return fw == tString + case reflect.Interface: + return fw == tInterface + case reflect.Array: + if !ok || wire.ArrayT == nil { + return false + } + array := wire.ArrayT + return t.Len() == array.Len && dec.compatibleType(t.Elem(), array.Elem, inProgress) + case reflect.Map: + if !ok || wire.MapT == nil { + return false + } + MapType := wire.MapT + return dec.compatibleType(t.Key(), MapType.Key, inProgress) && dec.compatibleType(t.Elem(), MapType.Elem, inProgress) + case reflect.Slice: + // Is it an array of bytes? + if t.Elem().Kind() == reflect.Uint8 { + return fw == tBytes + } + // Extract and compare element types. + var sw *sliceType + if tt := builtinIdToType(fw); tt != nil { + sw, _ = tt.(*sliceType) + } else if wire != nil { + sw = wire.SliceT + } + elem := userType(t.Elem()).base + return sw != nil && dec.compatibleType(elem, sw.Elem, inProgress) + case reflect.Struct: + return true + } +} + +// typeString returns a human-readable description of the type identified by remoteId. +func (dec *Decoder) typeString(remoteId typeId) string { + typeLock.Lock() + defer typeLock.Unlock() + if t := idToType(remoteId); t != nil { + // globally known type. + return t.string() + } + return dec.wireType[remoteId].string() +} + +// compileSingle compiles the decoder engine for a non-struct top-level value, including +// GobDecoders. +func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) { + rt := ut.user + engine = new(decEngine) + engine.instr = make([]decInstr, 1) // one item + name := rt.String() // best we can do + if !dec.compatibleType(rt, remoteId, make(map[reflect.Type]typeId)) { + remoteType := dec.typeString(remoteId) + // Common confusing case: local interface type, remote concrete type. + if ut.base.Kind() == reflect.Interface && remoteId != tInterface { + return nil, errors.New("gob: local interface type " + name + " can only be decoded from remote interface type; received concrete type " + remoteType) + } + return nil, errors.New("gob: decoding into local type " + name + ", received remote type " + remoteType) + } + op := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp)) + ovfl := errors.New(`value for "` + name + `" out of range`) + engine.instr[singletonField] = decInstr{*op, singletonField, nil, ovfl} + engine.numInstr = 1 + return +} + +// compileIgnoreSingle compiles the decoder engine for a non-struct top-level value that will be discarded. +func (dec *Decoder) compileIgnoreSingle(remoteId typeId) *decEngine { + engine := new(decEngine) + engine.instr = make([]decInstr, 1) // one item + op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp)) + ovfl := overflow(dec.typeString(remoteId)) + engine.instr[0] = decInstr{*op, 0, nil, ovfl} + engine.numInstr = 1 + return engine +} + +// compileDec compiles the decoder engine for a value. If the value is not a struct, +// it calls out to compileSingle. +func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) { + defer catchError(&err) + rt := ut.base + srt := rt + if srt.Kind() != reflect.Struct || ut.externalDec != 0 { + return dec.compileSingle(remoteId, ut) + } + var wireStruct *structType + // Builtin types can come from global pool; the rest must be defined by the decoder. + // Also we know we're decoding a struct now, so the client must have sent one. + if t := builtinIdToType(remoteId); t != nil { + wireStruct, _ = t.(*structType) + } else { + wire := dec.wireType[remoteId] + if wire == nil { + error_(errBadType) + } + wireStruct = wire.StructT + } + if wireStruct == nil { + errorf("type mismatch in decoder: want struct type %s; got non-struct", rt) + } + engine = new(decEngine) + engine.instr = make([]decInstr, len(wireStruct.Field)) + seen := make(map[reflect.Type]*decOp) + // Loop over the fields of the wire type. + for fieldnum := 0; fieldnum < len(wireStruct.Field); fieldnum++ { + wireField := wireStruct.Field[fieldnum] + if wireField.Name == "" { + errorf("empty name for remote field of type %s", wireStruct.Name) + } + ovfl := overflow(wireField.Name) + // Find the field of the local type with the same name. + localField, present := srt.FieldByName(wireField.Name) + // TODO(r): anonymous names + if !present || !isExported(wireField.Name) { + op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp)) + engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl} + continue + } + if !dec.compatibleType(localField.Type, wireField.Id, make(map[reflect.Type]typeId)) { + errorf("wrong type (%s) for received field %s.%s", localField.Type, wireStruct.Name, wireField.Name) + } + op := dec.decOpFor(wireField.Id, localField.Type, localField.Name, seen) + engine.instr[fieldnum] = decInstr{*op, fieldnum, localField.Index, ovfl} + engine.numInstr++ + } + return +} + +// getDecEnginePtr returns the engine for the specified type. +func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePtr **decEngine, err error) { + rt := ut.user + decoderMap, ok := dec.decoderCache[rt] + if !ok { + decoderMap = make(map[typeId]**decEngine) + dec.decoderCache[rt] = decoderMap + } + if enginePtr, ok = decoderMap[remoteId]; !ok { + // To handle recursive types, mark this engine as underway before compiling. + enginePtr = new(*decEngine) + decoderMap[remoteId] = enginePtr + *enginePtr, err = dec.compileDec(remoteId, ut) + if err != nil { + delete(decoderMap, remoteId) + } + } + return +} + +// emptyStruct is the type we compile into when ignoring a struct value. +type emptyStruct struct{} + +var emptyStructType = reflect.TypeFor[emptyStruct]() + +// getIgnoreEnginePtr returns the engine for the specified type when the value is to be discarded. +func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err error) { + var ok bool + if enginePtr, ok = dec.ignorerCache[wireId]; !ok { + // To handle recursive types, mark this engine as underway before compiling. + enginePtr = new(*decEngine) + dec.ignorerCache[wireId] = enginePtr + wire := dec.wireType[wireId] + if wire != nil && wire.StructT != nil { + *enginePtr, err = dec.compileDec(wireId, userType(emptyStructType)) + } else { + *enginePtr = dec.compileIgnoreSingle(wireId) + } + if err != nil { + delete(dec.ignorerCache, wireId) + } + } + return +} + +// decodeValue decodes the data stream representing a value and stores it in value. +func (dec *Decoder) decodeValue(wireId typeId, value reflect.Value) { + defer catchError(&dec.err) + // If the value is nil, it means we should just ignore this item. + if !value.IsValid() { + dec.decodeIgnoredValue(wireId) + return + } + // Dereference down to the underlying type. + ut := userType(value.Type()) + base := ut.base + var enginePtr **decEngine + enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut) + if dec.err != nil { + return + } + value = decAlloc(value) + engine := *enginePtr + if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 { + wt := dec.wireType[wireId] + if engine.numInstr == 0 && st.NumField() > 0 && + wt != nil && len(wt.StructT.Field) > 0 { + name := base.Name() + errorf("type mismatch: no fields matched compiling decoder for %s", name) + } + dec.decodeStruct(engine, value) + } else { + dec.decodeSingle(engine, value) + } +} + +// decodeIgnoredValue decodes the data stream representing a value of the specified type and discards it. +func (dec *Decoder) decodeIgnoredValue(wireId typeId) { + var enginePtr **decEngine + enginePtr, dec.err = dec.getIgnoreEnginePtr(wireId) + if dec.err != nil { + return + } + wire := dec.wireType[wireId] + if wire != nil && wire.StructT != nil { + dec.ignoreStruct(*enginePtr) + } else { + dec.ignoreSingle(*enginePtr) + } +} + +const ( + intBits = 32 << (^uint(0) >> 63) + uintptrBits = 32 << (^uintptr(0) >> 63) +) + +func init() { + var iop, uop decOp + switch intBits { + case 32: + iop = decInt32 + uop = decUint32 + case 64: + iop = decInt64 + uop = decUint64 + default: + panic("gob: unknown size of int/uint") + } + decOpTable[reflect.Int] = iop + decOpTable[reflect.Uint] = uop + + // Finally uintptr + switch uintptrBits { + case 32: + uop = decUint32 + case 64: + uop = decUint64 + default: + panic("gob: unknown size of uintptr") + } + decOpTable[reflect.Uintptr] = uop +} + +// Gob depends on being able to take the address +// of zeroed Values it creates, so use this wrapper instead +// of the standard reflect.Zero. +// Each call allocates once. +func allocValue(t reflect.Type) reflect.Value { + return reflect.New(t).Elem() +} diff --git a/contrib/go/_std_1.22/src/encoding/gob/decoder.go b/contrib/go/_std_1.23/src/encoding/gob/decoder.go similarity index 98% rename from contrib/go/_std_1.22/src/encoding/gob/decoder.go rename to contrib/go/_std_1.23/src/encoding/gob/decoder.go index c4b608801307..eae307838e20 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/decoder.go +++ b/contrib/go/_std_1.23/src/encoding/gob/decoder.go @@ -35,6 +35,8 @@ type Decoder struct { freeList *decoderState // list of free decoderStates; avoids reallocation countBuf []byte // used for decoding integers while parsing messages err error + // ignoreDepth tracks the depth of recursively parsed ignored fields + ignoreDepth int } // NewDecoder returns a new decoder that reads from the [io.Reader]. diff --git a/contrib/go/_std_1.23/src/encoding/gob/doc.go b/contrib/go/_std_1.23/src/encoding/gob/doc.go new file mode 100644 index 000000000000..30e7978b7c9d --- /dev/null +++ b/contrib/go/_std_1.23/src/encoding/gob/doc.go @@ -0,0 +1,423 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package gob manages streams of gobs - binary values exchanged between an +[Encoder] (transmitter) and a [Decoder] (receiver). A typical use is transporting +arguments and results of remote procedure calls (RPCs) such as those provided by +[net/rpc]. + +The implementation compiles a custom codec for each data type in the stream and +is most efficient when a single [Encoder] is used to transmit a stream of values, +amortizing the cost of compilation. + +# Basics + +A stream of gobs is self-describing. Each data item in the stream is preceded by +a specification of its type, expressed in terms of a small set of predefined +types. Pointers are not transmitted, but the things they point to are +transmitted; that is, the values are flattened. Nil pointers are not permitted, +as they have no value. Recursive types work fine, but +recursive values (data with cycles) are problematic. This may change. + +To use gobs, create an [Encoder] and present it with a series of data items as +values or addresses that can be dereferenced to values. The [Encoder] makes sure +all type information is sent before it is needed. At the receive side, a +[Decoder] retrieves values from the encoded stream and unpacks them into local +variables. + +# Types and Values + +The source and destination values/types need not correspond exactly. For structs, +fields (identified by name) that are in the source but absent from the receiving +variable will be ignored. Fields that are in the receiving variable but missing +from the transmitted type or value will be ignored in the destination. If a field +with the same name is present in both, their types must be compatible. Both the +receiver and transmitter will do all necessary indirection and dereferencing to +convert between gobs and actual Go values. For instance, a gob type that is +schematically, + + struct { A, B int } + +can be sent from or received into any of these Go types: + + struct { A, B int } // the same + *struct { A, B int } // extra indirection of the struct + struct { *A, **B int } // extra indirection of the fields + struct { A, B int64 } // different concrete value type; see below + +It may also be received into any of these: + + struct { A, B int } // the same + struct { B, A int } // ordering doesn't matter; matching is by name + struct { A, B, C int } // extra field (C) ignored + struct { B int } // missing field (A) ignored; data will be dropped + struct { B, C int } // missing field (A) ignored; extra field (C) ignored. + +Attempting to receive into these types will draw a decode error: + + struct { A int; B uint } // change of signedness for B + struct { A int; B float } // change of type for B + struct { } // no field names in common + struct { C, D int } // no field names in common + +Integers are transmitted two ways: arbitrary precision signed integers or +arbitrary precision unsigned integers. There is no int8, int16 etc. +discrimination in the gob format; there are only signed and unsigned integers. As +described below, the transmitter sends the value in a variable-length encoding; +the receiver accepts the value and stores it in the destination variable. +Floating-point numbers are always sent using IEEE 754 64-bit precision (see +below). + +Signed integers may be received into any signed integer variable: int, int16, etc.; +unsigned integers may be received into any unsigned integer variable; and floating +point values may be received into any floating point variable. However, +the destination variable must be able to represent the value or the decode +operation will fail. + +Structs, arrays and slices are also supported. Structs encode and decode only +exported fields. Strings and arrays of bytes are supported with a special, +efficient representation (see below). When a slice is decoded, if the existing +slice has capacity the slice will be extended in place; if not, a new array is +allocated. Regardless, the length of the resulting slice reports the number of +elements decoded. + +In general, if allocation is required, the decoder will allocate memory. If not, +it will update the destination variables with values read from the stream. It does +not initialize them first, so if the destination is a compound value such as a +map, struct, or slice, the decoded values will be merged elementwise into the +existing variables. + +Functions and channels will not be sent in a gob. Attempting to encode such a value +at the top level will fail. A struct field of chan or func type is treated exactly +like an unexported field and is ignored. + +Gob can encode a value of any type implementing the [GobEncoder] or +[encoding.BinaryMarshaler] interfaces by calling the corresponding method, +in that order of preference. + +Gob can decode a value of any type implementing the [GobDecoder] or +[encoding.BinaryUnmarshaler] interfaces by calling the corresponding method, +again in that order of preference. + +# Encoding Details + +This section documents the encoding, details that are not important for most +users. Details are presented bottom-up. + +An unsigned integer is sent one of two ways. If it is less than 128, it is sent +as a byte with that value. Otherwise it is sent as a minimal-length big-endian +(high byte first) byte stream holding the value, preceded by one byte holding the +byte count, negated. Thus 0 is transmitted as (00), 7 is transmitted as (07) and +256 is transmitted as (FE 01 00). + +A boolean is encoded within an unsigned integer: 0 for false, 1 for true. + +A signed integer, i, is encoded within an unsigned integer, u. Within u, bits 1 +upward contain the value; bit 0 says whether they should be complemented upon +receipt. The encode algorithm looks like this: + + var u uint + if i < 0 { + u = (^uint(i) << 1) | 1 // complement i, bit 0 is 1 + } else { + u = (uint(i) << 1) // do not complement i, bit 0 is 0 + } + encodeUnsigned(u) + +The low bit is therefore analogous to a sign bit, but making it the complement bit +instead guarantees that the largest negative integer is not a special case. For +example, -129=^128=(^256>>1) encodes as (FE 01 01). + +Floating-point numbers are always sent as a representation of a float64 value. +That value is converted to a uint64 using [math.Float64bits]. The uint64 is then +byte-reversed and sent as a regular unsigned integer. The byte-reversal means the +exponent and high-precision part of the mantissa go first. Since the low bits are +often zero, this can save encoding bytes. For instance, 17.0 is encoded in only +three bytes (FE 31 40). + +Strings and slices of bytes are sent as an unsigned count followed by that many +uninterpreted bytes of the value. + +All other slices and arrays are sent as an unsigned count followed by that many +elements using the standard gob encoding for their type, recursively. + +Maps are sent as an unsigned count followed by that many key, element +pairs. Empty but non-nil maps are sent, so if the receiver has not allocated +one already, one will always be allocated on receipt unless the transmitted map +is nil and not at the top level. + +In slices and arrays, as well as maps, all elements, even zero-valued elements, +are transmitted, even if all the elements are zero. + +Structs are sent as a sequence of (field number, field value) pairs. The field +value is sent using the standard gob encoding for its type, recursively. If a +field has the zero value for its type (except for arrays; see above), it is omitted +from the transmission. The field number is defined by the type of the encoded +struct: the first field of the encoded type is field 0, the second is field 1, +etc. When encoding a value, the field numbers are delta encoded for efficiency +and the fields are always sent in order of increasing field number; the deltas are +therefore unsigned. The initialization for the delta encoding sets the field +number to -1, so an unsigned integer field 0 with value 7 is transmitted as unsigned +delta = 1, unsigned value = 7 or (01 07). Finally, after all the fields have been +sent a terminating mark denotes the end of the struct. That mark is a delta=0 +value, which has representation (00). + +Interface types are not checked for compatibility; all interface types are +treated, for transmission, as members of a single "interface" type, analogous to +int or []byte - in effect they're all treated as interface{}. Interface values +are transmitted as a string identifying the concrete type being sent (a name +that must be pre-defined by calling [Register]), followed by a byte count of the +length of the following data (so the value can be skipped if it cannot be +stored), followed by the usual encoding of concrete (dynamic) value stored in +the interface value. (A nil interface value is identified by the empty string +and transmits no value.) Upon receipt, the decoder verifies that the unpacked +concrete item satisfies the interface of the receiving variable. + +If a value is passed to [Encoder.Encode] and the type is not a struct (or pointer to struct, +etc.), for simplicity of processing it is represented as a struct of one field. +The only visible effect of this is to encode a zero byte after the value, just as +after the last field of an encoded struct, so that the decode algorithm knows when +the top-level value is complete. + +The representation of types is described below. When a type is defined on a given +connection between an [Encoder] and [Decoder], it is assigned a signed integer type +id. When [Encoder.Encode](v) is called, it makes sure there is an id assigned for +the type of v and all its elements and then it sends the pair (typeid, encoded-v) +where typeid is the type id of the encoded type of v and encoded-v is the gob +encoding of the value v. + +To define a type, the encoder chooses an unused, positive type id and sends the +pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType +description, constructed from these types: + + type wireType struct { + ArrayT *ArrayType + SliceT *SliceType + StructT *StructType + MapT *MapType + GobEncoderT *gobEncoderType + BinaryMarshalerT *gobEncoderType + TextMarshalerT *gobEncoderType + + } + type arrayType struct { + CommonType + Elem typeId + Len int + } + type CommonType struct { + Name string // the name of the struct type + Id int // the id of the type, repeated so it's inside the type + } + type sliceType struct { + CommonType + Elem typeId + } + type structType struct { + CommonType + Field []*fieldType // the fields of the struct. + } + type fieldType struct { + Name string // the name of the field. + Id int // the type id of the field, which must be already defined + } + type mapType struct { + CommonType + Key typeId + Elem typeId + } + type gobEncoderType struct { + CommonType + } + +If there are nested type ids, the types for all inner type ids must be defined +before the top-level type id is used to describe an encoded-v. + +For simplicity in setup, the connection is defined to understand these types a +priori, as well as the basic gob types int, uint, etc. Their ids are: + + bool 1 + int 2 + uint 3 + float 4 + []byte 5 + string 6 + complex 7 + interface 8 + // gap for reserved ids. + WireType 16 + ArrayType 17 + CommonType 18 + SliceType 19 + StructType 20 + FieldType 21 + // 22 is slice of fieldType. + MapType 23 + +Finally, each message created by a call to Encode is preceded by an encoded +unsigned integer count of the number of bytes remaining in the message. After +the initial type name, interface values are wrapped the same way; in effect, the +interface value acts like a recursive invocation of Encode. + +In summary, a gob stream looks like + + (byteCount (-type id, encoding of a wireType)* (type id, encoding of a value))* + +where * signifies zero or more repetitions and the type id of a value must +be predefined or be defined before the value in the stream. + +Compatibility: Any future changes to the package will endeavor to maintain +compatibility with streams encoded using previous versions. That is, any released +version of this package should be able to decode data written with any previously +released version, subject to issues such as security fixes. See the Go compatibility +document for background: https://golang.org/doc/go1compat + +See "Gobs of data" for a design discussion of the gob wire format: +https://blog.golang.org/gobs-of-data + +# Security + +This package is not designed to be hardened against adversarial inputs, and is +outside the scope of https://go.dev/security/policy. In particular, the [Decoder] +does only basic sanity checking on decoded input sizes, and its limits are not +configurable. Care should be taken when decoding gob data from untrusted +sources, which may consume significant resources. +*/ +package gob + +/* +Grammar: + +Tokens starting with a lower case letter are terminals; int(n) +and uint(n) represent the signed/unsigned encodings of the value n. + +GobStream: + DelimitedMessage* +DelimitedMessage: + uint(lengthOfMessage) Message +Message: + TypeSequence TypedValue +TypeSequence + (TypeDefinition DelimitedTypeDefinition*)? +DelimitedTypeDefinition: + uint(lengthOfTypeDefinition) TypeDefinition +TypedValue: + int(typeId) Value +TypeDefinition: + int(-typeId) encodingOfWireType +Value: + SingletonValue | StructValue +SingletonValue: + uint(0) FieldValue +FieldValue: + builtinValue | ArrayValue | MapValue | SliceValue | StructValue | InterfaceValue +InterfaceValue: + NilInterfaceValue | NonNilInterfaceValue +NilInterfaceValue: + uint(0) +NonNilInterfaceValue: + ConcreteTypeName TypeSequence InterfaceContents +ConcreteTypeName: + uint(lengthOfName) [already read=n] name +InterfaceContents: + int(concreteTypeId) DelimitedValue +DelimitedValue: + uint(length) Value +ArrayValue: + uint(n) FieldValue*n [n elements] +MapValue: + uint(n) (FieldValue FieldValue)*n [n (key, value) pairs] +SliceValue: + uint(n) FieldValue*n [n elements] +StructValue: + (uint(fieldDelta) FieldValue)* +*/ + +/* +For implementers and the curious, here is an encoded example. Given + type Point struct {X, Y int} +and the value + p := Point{22, 33} +the bytes transmitted that encode p will be: + 1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00 + 01 02 01 01 58 01 04 00 01 01 59 01 04 00 00 00 + 07 ff 82 01 2c 01 42 00 +They are determined as follows. + +Since this is the first transmission of type Point, the type descriptor +for Point itself must be sent before the value. This is the first type +we've sent on this Encoder, so it has type id 65 (0 through 64 are +reserved). + + 1f // This item (a type descriptor) is 31 bytes long. + ff 81 // The negative of the id for the type we're defining, -65. + // This is one byte (indicated by FF = -1) followed by + // ^-65<<1 | 1. The low 1 bit signals to complement the + // rest upon receipt. + + // Now we send a type descriptor, which is itself a struct (wireType). + // The type of wireType itself is known (it's built in, as is the type of + // all its components), so we just need to send a *value* of type wireType + // that represents type "Point". + // Here starts the encoding of that value. + // Set the field number implicitly to -1; this is done at the beginning + // of every struct, including nested structs. + 03 // Add 3 to field number; now 2 (wireType.structType; this is a struct). + // structType starts with an embedded CommonType, which appears + // as a regular structure here too. + 01 // add 1 to field number (now 0); start of embedded CommonType. + 01 // add 1 to field number (now 0, the name of the type) + 05 // string is (unsigned) 5 bytes long + 50 6f 69 6e 74 // wireType.structType.CommonType.name = "Point" + 01 // add 1 to field number (now 1, the id of the type) + ff 82 // wireType.structType.CommonType._id = 65 + 00 // end of embedded wiretype.structType.CommonType struct + 01 // add 1 to field number (now 1, the field array in wireType.structType) + 02 // There are two fields in the type (len(structType.field)) + 01 // Start of first field structure; add 1 to get field number 0: field[0].name + 01 // 1 byte + 58 // structType.field[0].name = "X" + 01 // Add 1 to get field number 1: field[0].id + 04 // structType.field[0].typeId is 2 (signed int). + 00 // End of structType.field[0]; start structType.field[1]; set field number to -1. + 01 // Add 1 to get field number 0: field[1].name + 01 // 1 byte + 59 // structType.field[1].name = "Y" + 01 // Add 1 to get field number 1: field[1].id + 04 // struct.Type.field[1].typeId is 2 (signed int). + 00 // End of structType.field[1]; end of structType.field. + 00 // end of wireType.structType structure + 00 // end of wireType structure + +Now we can send the Point value. Again the field number resets to -1: + + 07 // this value is 7 bytes long + ff 82 // the type number, 65 (1 byte (-FF) followed by 65<<1) + 01 // add one to field number, yielding field 0 + 2c // encoding of signed "22" (0x2c = 44 = 22<<1); Point.x = 22 + 01 // add one to field number, yielding field 1 + 42 // encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33 + 00 // end of structure + +The type encoding is long and fairly intricate but we send it only once. +If p is transmitted a second time, the type is already known so the +output will be just: + + 07 ff 82 01 2c 01 42 00 + +A single non-struct value at top level is transmitted like a field with +delta tag 0. For instance, a signed integer with value 3 presented as +the argument to Encode will emit: + + 03 04 00 06 + +Which represents: + + 03 // this value is 3 bytes long + 04 // the type number, 2, represents an integer + 00 // tag delta 0 + 06 // value 3 + +*/ diff --git a/contrib/go/_std_1.22/src/encoding/gob/dump.go b/contrib/go/_std_1.23/src/encoding/gob/dump.go similarity index 96% rename from contrib/go/_std_1.22/src/encoding/gob/dump.go rename to contrib/go/_std_1.23/src/encoding/gob/dump.go index f4b1bebfba1d..b14d84164bcf 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/dump.go +++ b/contrib/go/_std_1.23/src/encoding/gob/dump.go @@ -24,6 +24,7 @@ func main() { fmt.Fprintf(os.Stderr, "dump: %s\n", err) os.Exit(1) } + defer file.Close() } gob.Debug(file) } diff --git a/contrib/go/_std_1.22/src/encoding/gob/enc_helpers.go b/contrib/go/_std_1.23/src/encoding/gob/enc_helpers.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/enc_helpers.go rename to contrib/go/_std_1.23/src/encoding/gob/enc_helpers.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/encgen.go b/contrib/go/_std_1.23/src/encoding/gob/encgen.go similarity index 98% rename from contrib/go/_std_1.22/src/encoding/gob/encgen.go rename to contrib/go/_std_1.23/src/encoding/gob/encgen.go index e5f68786a060..64f5c69bd44d 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/encgen.go +++ b/contrib/go/_std_1.23/src/encoding/gob/encgen.go @@ -170,6 +170,9 @@ func main() { if _, err := fd.Write(source); err != nil { log.Fatal(err) } + if err := fd.Close(); err != nil { + log.Fatal(err) + } } func printMaps(b *bytes.Buffer, upperClass string) { diff --git a/contrib/go/_std_1.23/src/encoding/gob/encode.go b/contrib/go/_std_1.23/src/encoding/gob/encode.go new file mode 100644 index 000000000000..5f4d2539faaf --- /dev/null +++ b/contrib/go/_std_1.23/src/encoding/gob/encode.go @@ -0,0 +1,670 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run encgen.go -output enc_helpers.go + +package gob + +import ( + "encoding" + "encoding/binary" + "math" + "math/bits" + "reflect" + "sync" +) + +const uint64Size = 8 + +type encHelper func(state *encoderState, v reflect.Value) bool + +// encoderState is the global execution state of an instance of the encoder. +// Field numbers are delta encoded and always increase. The field +// number is initialized to -1 so 0 comes out as delta(1). A delta of +// 0 terminates the structure. +type encoderState struct { + enc *Encoder + b *encBuffer + sendZero bool // encoding an array element or map key/value pair; send zero values + fieldnum int // the last field number written. + buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation. + next *encoderState // for free list +} + +// encBuffer is an extremely simple, fast implementation of a write-only byte buffer. +// It never returns a non-nil error, but Write returns an error value so it matches io.Writer. +type encBuffer struct { + data []byte + scratch [64]byte +} + +var encBufferPool = sync.Pool{ + New: func() any { + e := new(encBuffer) + e.data = e.scratch[0:0] + return e + }, +} + +func (e *encBuffer) writeByte(c byte) { + e.data = append(e.data, c) +} + +func (e *encBuffer) Write(p []byte) (int, error) { + e.data = append(e.data, p...) + return len(p), nil +} + +func (e *encBuffer) WriteString(s string) { + e.data = append(e.data, s...) +} + +func (e *encBuffer) Len() int { + return len(e.data) +} + +func (e *encBuffer) Bytes() []byte { + return e.data +} + +func (e *encBuffer) Reset() { + if len(e.data) >= tooBig { + e.data = e.scratch[0:0] + } else { + e.data = e.data[0:0] + } +} + +func (enc *Encoder) newEncoderState(b *encBuffer) *encoderState { + e := enc.freeList + if e == nil { + e = new(encoderState) + e.enc = enc + } else { + enc.freeList = e.next + } + e.sendZero = false + e.fieldnum = 0 + e.b = b + if len(b.data) == 0 { + b.data = b.scratch[0:0] + } + return e +} + +func (enc *Encoder) freeEncoderState(e *encoderState) { + e.next = enc.freeList + enc.freeList = e +} + +// Unsigned integers have a two-state encoding. If the number is less +// than 128 (0 through 0x7F), its value is written directly. +// Otherwise the value is written in big-endian byte order preceded +// by the byte length, negated. + +// encodeUint writes an encoded unsigned integer to state.b. +func (state *encoderState) encodeUint(x uint64) { + if x <= 0x7F { + state.b.writeByte(uint8(x)) + return + } + + binary.BigEndian.PutUint64(state.buf[1:], x) + bc := bits.LeadingZeros64(x) >> 3 // 8 - bytelen(x) + state.buf[bc] = uint8(bc - uint64Size) // and then we subtract 8 to get -bytelen(x) + + state.b.Write(state.buf[bc : uint64Size+1]) +} + +// encodeInt writes an encoded signed integer to state.w. +// The low bit of the encoding says whether to bit complement the (other bits of the) +// uint to recover the int. +func (state *encoderState) encodeInt(i int64) { + var x uint64 + if i < 0 { + x = uint64(^i<<1) | 1 + } else { + x = uint64(i << 1) + } + state.encodeUint(x) +} + +// encOp is the signature of an encoding operator for a given type. +type encOp func(i *encInstr, state *encoderState, v reflect.Value) + +// The 'instructions' of the encoding machine +type encInstr struct { + op encOp + field int // field number in input + index []int // struct index + indir int // how many pointer indirections to reach the value in the struct +} + +// update emits a field number and updates the state to record its value for delta encoding. +// If the instruction pointer is nil, it does nothing +func (state *encoderState) update(instr *encInstr) { + if instr != nil { + state.encodeUint(uint64(instr.field - state.fieldnum)) + state.fieldnum = instr.field + } +} + +// Each encoder for a composite is responsible for handling any +// indirections associated with the elements of the data structure. +// If any pointer so reached is nil, no bytes are written. If the +// data item is zero, no bytes are written. Single values - ints, +// strings etc. - are indirected before calling their encoders. +// Otherwise, the output (for a scalar) is the field number, as an +// encoded integer, followed by the field data in its appropriate +// format. + +// encIndirect dereferences pv indir times and returns the result. +func encIndirect(pv reflect.Value, indir int) reflect.Value { + for ; indir > 0; indir-- { + if pv.IsNil() { + break + } + pv = pv.Elem() + } + return pv +} + +// encBool encodes the bool referenced by v as an unsigned 0 or 1. +func encBool(i *encInstr, state *encoderState, v reflect.Value) { + b := v.Bool() + if b || state.sendZero { + state.update(i) + if b { + state.encodeUint(1) + } else { + state.encodeUint(0) + } + } +} + +// encInt encodes the signed integer (int int8 int16 int32 int64) referenced by v. +func encInt(i *encInstr, state *encoderState, v reflect.Value) { + value := v.Int() + if value != 0 || state.sendZero { + state.update(i) + state.encodeInt(value) + } +} + +// encUint encodes the unsigned integer (uint uint8 uint16 uint32 uint64 uintptr) referenced by v. +func encUint(i *encInstr, state *encoderState, v reflect.Value) { + value := v.Uint() + if value != 0 || state.sendZero { + state.update(i) + state.encodeUint(value) + } +} + +// floatBits returns a uint64 holding the bits of a floating-point number. +// Floating-point numbers are transmitted as uint64s holding the bits +// of the underlying representation. They are sent byte-reversed, with +// the exponent end coming out first, so integer floating point numbers +// (for example) transmit more compactly. This routine does the +// swizzling. +func floatBits(f float64) uint64 { + u := math.Float64bits(f) + return bits.ReverseBytes64(u) +} + +// encFloat encodes the floating point value (float32 float64) referenced by v. +func encFloat(i *encInstr, state *encoderState, v reflect.Value) { + f := v.Float() + if f != 0 || state.sendZero { + bits := floatBits(f) + state.update(i) + state.encodeUint(bits) + } +} + +// encComplex encodes the complex value (complex64 complex128) referenced by v. +// Complex numbers are just a pair of floating-point numbers, real part first. +func encComplex(i *encInstr, state *encoderState, v reflect.Value) { + c := v.Complex() + if c != 0+0i || state.sendZero { + rpart := floatBits(real(c)) + ipart := floatBits(imag(c)) + state.update(i) + state.encodeUint(rpart) + state.encodeUint(ipart) + } +} + +// encUint8Array encodes the byte array referenced by v. +// Byte arrays are encoded as an unsigned count followed by the raw bytes. +func encUint8Array(i *encInstr, state *encoderState, v reflect.Value) { + b := v.Bytes() + if len(b) > 0 || state.sendZero { + state.update(i) + state.encodeUint(uint64(len(b))) + state.b.Write(b) + } +} + +// encString encodes the string referenced by v. +// Strings are encoded as an unsigned count followed by the raw bytes. +func encString(i *encInstr, state *encoderState, v reflect.Value) { + s := v.String() + if len(s) > 0 || state.sendZero { + state.update(i) + state.encodeUint(uint64(len(s))) + state.b.WriteString(s) + } +} + +// encStructTerminator encodes the end of an encoded struct +// as delta field number of 0. +func encStructTerminator(i *encInstr, state *encoderState, v reflect.Value) { + state.encodeUint(0) +} + +// Execution engine + +// encEngine an array of instructions indexed by field number of the encoding +// data, typically a struct. It is executed top to bottom, walking the struct. +type encEngine struct { + instr []encInstr +} + +const singletonField = 0 + +// valid reports whether the value is valid and a non-nil pointer. +// (Slices, maps, and chans take care of themselves.) +func valid(v reflect.Value) bool { + switch v.Kind() { + case reflect.Invalid: + return false + case reflect.Pointer: + return !v.IsNil() + } + return true +} + +// encodeSingle encodes a single top-level non-struct value. +func (enc *Encoder) encodeSingle(b *encBuffer, engine *encEngine, value reflect.Value) { + state := enc.newEncoderState(b) + defer enc.freeEncoderState(state) + state.fieldnum = singletonField + // There is no surrounding struct to frame the transmission, so we must + // generate data even if the item is zero. To do this, set sendZero. + state.sendZero = true + instr := &engine.instr[singletonField] + if instr.indir > 0 { + value = encIndirect(value, instr.indir) + } + if valid(value) { + instr.op(instr, state, value) + } +} + +// encodeStruct encodes a single struct value. +func (enc *Encoder) encodeStruct(b *encBuffer, engine *encEngine, value reflect.Value) { + if !valid(value) { + return + } + state := enc.newEncoderState(b) + defer enc.freeEncoderState(state) + state.fieldnum = -1 + for i := 0; i < len(engine.instr); i++ { + instr := &engine.instr[i] + if i >= value.NumField() { + // encStructTerminator + instr.op(instr, state, reflect.Value{}) + break + } + field := value.FieldByIndex(instr.index) + if instr.indir > 0 { + field = encIndirect(field, instr.indir) + // TODO: Is field guaranteed valid? If so we could avoid this check. + if !valid(field) { + continue + } + } + instr.op(instr, state, field) + } +} + +// encodeArray encodes an array. +func (enc *Encoder) encodeArray(b *encBuffer, value reflect.Value, op encOp, elemIndir int, length int, helper encHelper) { + state := enc.newEncoderState(b) + defer enc.freeEncoderState(state) + state.fieldnum = -1 + state.sendZero = true + state.encodeUint(uint64(length)) + if helper != nil && helper(state, value) { + return + } + for i := 0; i < length; i++ { + elem := value.Index(i) + if elemIndir > 0 { + elem = encIndirect(elem, elemIndir) + // TODO: Is elem guaranteed valid? If so we could avoid this check. + if !valid(elem) { + errorf("encodeArray: nil element") + } + } + op(nil, state, elem) + } +} + +// encodeReflectValue is a helper for maps. It encodes the value v. +func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) { + for i := 0; i < indir && v.IsValid(); i++ { + v = reflect.Indirect(v) + } + if !v.IsValid() { + errorf("encodeReflectValue: nil element") + } + op(nil, state, v) +} + +// encodeMap encodes a map as unsigned count followed by key:value pairs. +func (enc *Encoder) encodeMap(b *encBuffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) { + state := enc.newEncoderState(b) + state.fieldnum = -1 + state.sendZero = true + state.encodeUint(uint64(mv.Len())) + mi := mv.MapRange() + for mi.Next() { + encodeReflectValue(state, mi.Key(), keyOp, keyIndir) + encodeReflectValue(state, mi.Value(), elemOp, elemIndir) + } + enc.freeEncoderState(state) +} + +// encodeInterface encodes the interface value iv. +// To send an interface, we send a string identifying the concrete type, followed +// by the type identifier (which might require defining that type right now), followed +// by the concrete value. A nil value gets sent as the empty string for the name, +// followed by no value. +func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) { + // Gobs can encode nil interface values but not typed interface + // values holding nil pointers, since nil pointers point to no value. + elem := iv.Elem() + if elem.Kind() == reflect.Pointer && elem.IsNil() { + errorf("gob: cannot encode nil pointer of type %s inside interface", iv.Elem().Type()) + } + state := enc.newEncoderState(b) + state.fieldnum = -1 + state.sendZero = true + if iv.IsNil() { + state.encodeUint(0) + return + } + + ut := userType(iv.Elem().Type()) + namei, ok := concreteTypeToName.Load(ut.base) + if !ok { + errorf("type not registered for interface: %s", ut.base) + } + name := namei.(string) + + // Send the name. + state.encodeUint(uint64(len(name))) + state.b.WriteString(name) + // Define the type id if necessary. + enc.sendTypeDescriptor(enc.writer(), state, ut) + // Send the type id. + enc.sendTypeId(state, ut) + // Encode the value into a new buffer. Any nested type definitions + // should be written to b, before the encoded value. + enc.pushWriter(b) + data := encBufferPool.Get().(*encBuffer) + data.Write(spaceForLength) + enc.encode(data, elem, ut) + if enc.err != nil { + error_(enc.err) + } + enc.popWriter() + enc.writeMessage(b, data) + data.Reset() + encBufferPool.Put(data) + if enc.err != nil { + error_(enc.err) + } + enc.freeEncoderState(state) +} + +// encodeGobEncoder encodes a value that implements the GobEncoder interface. +// The data is sent as a byte array. +func (enc *Encoder) encodeGobEncoder(b *encBuffer, ut *userTypeInfo, v reflect.Value) { + // TODO: should we catch panics from the called method? + + var data []byte + var err error + // We know it's one of these. + switch ut.externalEnc { + case xGob: + data, err = v.Interface().(GobEncoder).GobEncode() + case xBinary: + data, err = v.Interface().(encoding.BinaryMarshaler).MarshalBinary() + case xText: + data, err = v.Interface().(encoding.TextMarshaler).MarshalText() + } + if err != nil { + error_(err) + } + state := enc.newEncoderState(b) + state.fieldnum = -1 + state.encodeUint(uint64(len(data))) + state.b.Write(data) + enc.freeEncoderState(state) +} + +var encOpTable = [...]encOp{ + reflect.Bool: encBool, + reflect.Int: encInt, + reflect.Int8: encInt, + reflect.Int16: encInt, + reflect.Int32: encInt, + reflect.Int64: encInt, + reflect.Uint: encUint, + reflect.Uint8: encUint, + reflect.Uint16: encUint, + reflect.Uint32: encUint, + reflect.Uint64: encUint, + reflect.Uintptr: encUint, + reflect.Float32: encFloat, + reflect.Float64: encFloat, + reflect.Complex64: encComplex, + reflect.Complex128: encComplex, + reflect.String: encString, +} + +// encOpFor returns (a pointer to) the encoding op for the base type under rt and +// the indirection count to reach it. +func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp, building map[*typeInfo]bool) (*encOp, int) { + ut := userType(rt) + // If the type implements GobEncoder, we handle it without further processing. + if ut.externalEnc != 0 { + return gobEncodeOpFor(ut) + } + // If this type is already in progress, it's a recursive type (e.g. map[string]*T). + // Return the pointer to the op we're already building. + if opPtr := inProgress[rt]; opPtr != nil { + return opPtr, ut.indir + } + typ := ut.base + indir := ut.indir + k := typ.Kind() + var op encOp + if int(k) < len(encOpTable) { + op = encOpTable[k] + } + if op == nil { + inProgress[rt] = &op + // Special cases + switch t := typ; t.Kind() { + case reflect.Slice: + if t.Elem().Kind() == reflect.Uint8 { + op = encUint8Array + break + } + // Slices have a header; we decode it to find the underlying array. + elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) + helper := encSliceHelper[t.Elem().Kind()] + op = func(i *encInstr, state *encoderState, slice reflect.Value) { + if !state.sendZero && slice.Len() == 0 { + return + } + state.update(i) + state.enc.encodeArray(state.b, slice, *elemOp, elemIndir, slice.Len(), helper) + } + case reflect.Array: + // True arrays have size in the type. + elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) + helper := encArrayHelper[t.Elem().Kind()] + op = func(i *encInstr, state *encoderState, array reflect.Value) { + state.update(i) + state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len(), helper) + } + case reflect.Map: + keyOp, keyIndir := encOpFor(t.Key(), inProgress, building) + elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) + op = func(i *encInstr, state *encoderState, mv reflect.Value) { + // We send zero-length (but non-nil) maps because the + // receiver might want to use the map. (Maps don't use append.) + if !state.sendZero && mv.IsNil() { + return + } + state.update(i) + state.enc.encodeMap(state.b, mv, *keyOp, *elemOp, keyIndir, elemIndir) + } + case reflect.Struct: + // Generate a closure that calls out to the engine for the nested type. + getEncEngine(userType(typ), building) + info := mustGetTypeInfo(typ) + op = func(i *encInstr, state *encoderState, sv reflect.Value) { + state.update(i) + // indirect through info to delay evaluation for recursive structs + enc := info.encoder.Load() + state.enc.encodeStruct(state.b, enc, sv) + } + case reflect.Interface: + op = func(i *encInstr, state *encoderState, iv reflect.Value) { + if !state.sendZero && (!iv.IsValid() || iv.IsNil()) { + return + } + state.update(i) + state.enc.encodeInterface(state.b, iv) + } + } + } + if op == nil { + errorf("can't happen: encode type %s", rt) + } + return &op, indir +} + +// gobEncodeOpFor returns the op for a type that is known to implement GobEncoder. +func gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) { + rt := ut.user + if ut.encIndir == -1 { + rt = reflect.PointerTo(rt) + } else if ut.encIndir > 0 { + for i := int8(0); i < ut.encIndir; i++ { + rt = rt.Elem() + } + } + var op encOp + op = func(i *encInstr, state *encoderState, v reflect.Value) { + if ut.encIndir == -1 { + // Need to climb up one level to turn value into pointer. + if !v.CanAddr() { + errorf("unaddressable value of type %s", rt) + } + v = v.Addr() + } + if !state.sendZero && v.IsZero() { + return + } + state.update(i) + state.enc.encodeGobEncoder(state.b, ut, v) + } + return &op, int(ut.encIndir) // encIndir: op will get called with p == address of receiver. +} + +// compileEnc returns the engine to compile the type. +func compileEnc(ut *userTypeInfo, building map[*typeInfo]bool) *encEngine { + srt := ut.base + engine := new(encEngine) + seen := make(map[reflect.Type]*encOp) + rt := ut.base + if ut.externalEnc != 0 { + rt = ut.user + } + if ut.externalEnc == 0 && srt.Kind() == reflect.Struct { + for fieldNum, wireFieldNum := 0, 0; fieldNum < srt.NumField(); fieldNum++ { + f := srt.Field(fieldNum) + if !isSent(&f) { + continue + } + op, indir := encOpFor(f.Type, seen, building) + engine.instr = append(engine.instr, encInstr{*op, wireFieldNum, f.Index, indir}) + wireFieldNum++ + } + if srt.NumField() > 0 && len(engine.instr) == 0 { + errorf("type %s has no exported fields", rt) + } + engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, nil, 0}) + } else { + engine.instr = make([]encInstr, 1) + op, indir := encOpFor(rt, seen, building) + engine.instr[0] = encInstr{*op, singletonField, nil, indir} + } + return engine +} + +// getEncEngine returns the engine to compile the type. +func getEncEngine(ut *userTypeInfo, building map[*typeInfo]bool) *encEngine { + info, err := getTypeInfo(ut) + if err != nil { + error_(err) + } + enc := info.encoder.Load() + if enc == nil { + enc = buildEncEngine(info, ut, building) + } + return enc +} + +func buildEncEngine(info *typeInfo, ut *userTypeInfo, building map[*typeInfo]bool) *encEngine { + // Check for recursive types. + if building != nil && building[info] { + return nil + } + info.encInit.Lock() + defer info.encInit.Unlock() + enc := info.encoder.Load() + if enc == nil { + if building == nil { + building = make(map[*typeInfo]bool) + } + building[info] = true + enc = compileEnc(ut, building) + info.encoder.Store(enc) + } + return enc +} + +func (enc *Encoder) encode(b *encBuffer, value reflect.Value, ut *userTypeInfo) { + defer catchError(&enc.err) + engine := getEncEngine(ut, nil) + indir := ut.indir + if ut.externalEnc != 0 { + indir = int(ut.encIndir) + } + for i := 0; i < indir; i++ { + value = reflect.Indirect(value) + } + if ut.externalEnc == 0 && value.Type().Kind() == reflect.Struct { + enc.encodeStruct(b, engine, value) + } else { + enc.encodeSingle(b, engine, value) + } +} diff --git a/contrib/go/_std_1.22/src/encoding/gob/encoder.go b/contrib/go/_std_1.23/src/encoding/gob/encoder.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/encoder.go rename to contrib/go/_std_1.23/src/encoding/gob/encoder.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/error.go b/contrib/go/_std_1.23/src/encoding/gob/error.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/error.go rename to contrib/go/_std_1.23/src/encoding/gob/error.go diff --git a/contrib/go/_std_1.23/src/encoding/gob/type.go b/contrib/go/_std_1.23/src/encoding/gob/type.go new file mode 100644 index 000000000000..c3ac1dbd61fd --- /dev/null +++ b/contrib/go/_std_1.23/src/encoding/gob/type.go @@ -0,0 +1,945 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gob + +import ( + "encoding" + "errors" + "fmt" + "os" + "reflect" + "sync" + "sync/atomic" + "unicode" + "unicode/utf8" +) + +// userTypeInfo stores the information associated with a type the user has handed +// to the package. It's computed once and stored in a map keyed by reflection +// type. +type userTypeInfo struct { + user reflect.Type // the type the user handed us + base reflect.Type // the base type after all indirections + indir int // number of indirections to reach the base type + externalEnc int // xGob, xBinary, or xText + externalDec int // xGob, xBinary, or xText + encIndir int8 // number of indirections to reach the receiver type; may be negative + decIndir int8 // number of indirections to reach the receiver type; may be negative +} + +// externalEncoding bits +const ( + xGob = 1 + iota // GobEncoder or GobDecoder + xBinary // encoding.BinaryMarshaler or encoding.BinaryUnmarshaler + xText // encoding.TextMarshaler or encoding.TextUnmarshaler +) + +var userTypeCache sync.Map // map[reflect.Type]*userTypeInfo + +// validUserType returns, and saves, the information associated with user-provided type rt. +// If the user type is not valid, err will be non-nil. To be used when the error handler +// is not set up. +func validUserType(rt reflect.Type) (*userTypeInfo, error) { + if ui, ok := userTypeCache.Load(rt); ok { + return ui.(*userTypeInfo), nil + } + + // Construct a new userTypeInfo and atomically add it to the userTypeCache. + // If we lose the race, we'll waste a little CPU and create a little garbage + // but return the existing value anyway. + + ut := new(userTypeInfo) + ut.base = rt + ut.user = rt + // A type that is just a cycle of pointers (such as type T *T) cannot + // be represented in gobs, which need some concrete data. We use a + // cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6, + // pp 539-540. As we step through indirections, run another type at + // half speed. If they meet up, there's a cycle. + slowpoke := ut.base // walks half as fast as ut.base + for { + pt := ut.base + if pt.Kind() != reflect.Pointer { + break + } + ut.base = pt.Elem() + if ut.base == slowpoke { // ut.base lapped slowpoke + // recursive pointer type. + return nil, errors.New("can't represent recursive pointer type " + ut.base.String()) + } + if ut.indir%2 == 0 { + slowpoke = slowpoke.Elem() + } + ut.indir++ + } + + if ok, indir := implementsInterface(ut.user, gobEncoderInterfaceType); ok { + ut.externalEnc, ut.encIndir = xGob, indir + } else if ok, indir := implementsInterface(ut.user, binaryMarshalerInterfaceType); ok { + ut.externalEnc, ut.encIndir = xBinary, indir + } + + // NOTE(rsc): Would like to allow MarshalText here, but results in incompatibility + // with older encodings for net.IP. See golang.org/issue/6760. + // } else if ok, indir := implementsInterface(ut.user, textMarshalerInterfaceType); ok { + // ut.externalEnc, ut.encIndir = xText, indir + // } + + if ok, indir := implementsInterface(ut.user, gobDecoderInterfaceType); ok { + ut.externalDec, ut.decIndir = xGob, indir + } else if ok, indir := implementsInterface(ut.user, binaryUnmarshalerInterfaceType); ok { + ut.externalDec, ut.decIndir = xBinary, indir + } + + // See note above. + // } else if ok, indir := implementsInterface(ut.user, textUnmarshalerInterfaceType); ok { + // ut.externalDec, ut.decIndir = xText, indir + // } + + ui, _ := userTypeCache.LoadOrStore(rt, ut) + return ui.(*userTypeInfo), nil +} + +var ( + gobEncoderInterfaceType = reflect.TypeFor[GobEncoder]() + gobDecoderInterfaceType = reflect.TypeFor[GobDecoder]() + binaryMarshalerInterfaceType = reflect.TypeFor[encoding.BinaryMarshaler]() + binaryUnmarshalerInterfaceType = reflect.TypeFor[encoding.BinaryUnmarshaler]() + textMarshalerInterfaceType = reflect.TypeFor[encoding.TextMarshaler]() + textUnmarshalerInterfaceType = reflect.TypeFor[encoding.TextUnmarshaler]() + + wireTypeType = reflect.TypeFor[wireType]() +) + +// implementsInterface reports whether the type implements the +// gobEncoder/gobDecoder interface. +// It also returns the number of indirections required to get to the +// implementation. +func implementsInterface(typ, gobEncDecType reflect.Type) (success bool, indir int8) { + if typ == nil { + return + } + rt := typ + // The type might be a pointer and we need to keep + // dereferencing to the base type until we find an implementation. + for { + if rt.Implements(gobEncDecType) { + return true, indir + } + if p := rt; p.Kind() == reflect.Pointer { + indir++ + if indir > 100 { // insane number of indirections + return false, 0 + } + rt = p.Elem() + continue + } + break + } + // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy. + if typ.Kind() != reflect.Pointer { + // Not a pointer, but does the pointer work? + if reflect.PointerTo(typ).Implements(gobEncDecType) { + return true, -1 + } + } + return false, 0 +} + +// userType returns, and saves, the information associated with user-provided type rt. +// If the user type is not valid, it calls error. +func userType(rt reflect.Type) *userTypeInfo { + ut, err := validUserType(rt) + if err != nil { + error_(err) + } + return ut +} + +// A typeId represents a gob Type as an integer that can be passed on the wire. +// Internally, typeIds are used as keys to a map to recover the underlying type info. +type typeId int32 + +var typeLock sync.Mutex // set while building a type +const firstUserId = 64 // lowest id number granted to user + +type gobType interface { + id() typeId + setId(id typeId) + name() string + string() string // not public; only for debugging + safeString(seen map[typeId]bool) string +} + +var ( + types = make(map[reflect.Type]gobType, 32) + idToTypeSlice = make([]gobType, 1, firstUserId) + builtinIdToTypeSlice [firstUserId]gobType // set in init() after builtins are established +) + +func idToType(id typeId) gobType { + if id < 0 || int(id) >= len(idToTypeSlice) { + return nil + } + return idToTypeSlice[id] +} + +func builtinIdToType(id typeId) gobType { + if id < 0 || int(id) >= len(builtinIdToTypeSlice) { + return nil + } + return builtinIdToTypeSlice[id] +} + +func setTypeId(typ gobType) { + // When building recursive types, someone may get there before us. + if typ.id() != 0 { + return + } + nextId := typeId(len(idToTypeSlice)) + typ.setId(nextId) + idToTypeSlice = append(idToTypeSlice, typ) +} + +func (t typeId) gobType() gobType { + if t == 0 { + return nil + } + return idToType(t) +} + +// string returns the string representation of the type associated with the typeId. +func (t typeId) string() string { + if t.gobType() == nil { + return "" + } + return t.gobType().string() +} + +// Name returns the name of the type associated with the typeId. +func (t typeId) name() string { + if t.gobType() == nil { + return "" + } + return t.gobType().name() +} + +// CommonType holds elements of all types. +// It is a historical artifact, kept for binary compatibility and exported +// only for the benefit of the package's encoding of type descriptors. It is +// not intended for direct use by clients. +type CommonType struct { + Name string + Id typeId +} + +func (t *CommonType) id() typeId { return t.Id } + +func (t *CommonType) setId(id typeId) { t.Id = id } + +func (t *CommonType) string() string { return t.Name } + +func (t *CommonType) safeString(seen map[typeId]bool) string { + return t.Name +} + +func (t *CommonType) name() string { return t.Name } + +// Create and check predefined types +// The string for tBytes is "bytes" not "[]byte" to signify its specialness. + +var ( + // Primordial types, needed during initialization. + // Always passed as pointers so the interface{} type + // goes through without losing its interfaceness. + tBool = bootstrapType("bool", (*bool)(nil)) + tInt = bootstrapType("int", (*int)(nil)) + tUint = bootstrapType("uint", (*uint)(nil)) + tFloat = bootstrapType("float", (*float64)(nil)) + tBytes = bootstrapType("bytes", (*[]byte)(nil)) + tString = bootstrapType("string", (*string)(nil)) + tComplex = bootstrapType("complex", (*complex128)(nil)) + tInterface = bootstrapType("interface", (*any)(nil)) + // Reserve some Ids for compatible expansion + tReserved7 = bootstrapType("_reserved1", (*struct{ r7 int })(nil)) + tReserved6 = bootstrapType("_reserved1", (*struct{ r6 int })(nil)) + tReserved5 = bootstrapType("_reserved1", (*struct{ r5 int })(nil)) + tReserved4 = bootstrapType("_reserved1", (*struct{ r4 int })(nil)) + tReserved3 = bootstrapType("_reserved1", (*struct{ r3 int })(nil)) + tReserved2 = bootstrapType("_reserved1", (*struct{ r2 int })(nil)) + tReserved1 = bootstrapType("_reserved1", (*struct{ r1 int })(nil)) +) + +// Predefined because it's needed by the Decoder +var tWireType = mustGetTypeInfo(wireTypeType).id +var wireTypeUserInfo *userTypeInfo // userTypeInfo of wireType + +func init() { + // Some magic numbers to make sure there are no surprises. + checkId(16, tWireType) + checkId(17, mustGetTypeInfo(reflect.TypeFor[arrayType]()).id) + checkId(18, mustGetTypeInfo(reflect.TypeFor[CommonType]()).id) + checkId(19, mustGetTypeInfo(reflect.TypeFor[sliceType]()).id) + checkId(20, mustGetTypeInfo(reflect.TypeFor[structType]()).id) + checkId(21, mustGetTypeInfo(reflect.TypeFor[fieldType]()).id) + checkId(23, mustGetTypeInfo(reflect.TypeFor[mapType]()).id) + + copy(builtinIdToTypeSlice[:], idToTypeSlice) + + // Move the id space upwards to allow for growth in the predefined world + // without breaking existing files. + if nextId := len(idToTypeSlice); nextId > firstUserId { + panic(fmt.Sprintln("nextId too large:", nextId)) + } + idToTypeSlice = idToTypeSlice[:firstUserId] + registerBasics() + wireTypeUserInfo = userType(wireTypeType) +} + +// Array type +type arrayType struct { + CommonType + Elem typeId + Len int +} + +func newArrayType(name string) *arrayType { + a := &arrayType{CommonType{Name: name}, 0, 0} + return a +} + +func (a *arrayType) init(elem gobType, len int) { + // Set our type id before evaluating the element's, in case it's our own. + setTypeId(a) + a.Elem = elem.id() + a.Len = len +} + +func (a *arrayType) safeString(seen map[typeId]bool) string { + if seen[a.Id] { + return a.Name + } + seen[a.Id] = true + return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen)) +} + +func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) } + +// GobEncoder type (something that implements the GobEncoder interface) +type gobEncoderType struct { + CommonType +} + +func newGobEncoderType(name string) *gobEncoderType { + g := &gobEncoderType{CommonType{Name: name}} + setTypeId(g) + return g +} + +func (g *gobEncoderType) safeString(seen map[typeId]bool) string { + return g.Name +} + +func (g *gobEncoderType) string() string { return g.Name } + +// Map type +type mapType struct { + CommonType + Key typeId + Elem typeId +} + +func newMapType(name string) *mapType { + m := &mapType{CommonType{Name: name}, 0, 0} + return m +} + +func (m *mapType) init(key, elem gobType) { + // Set our type id before evaluating the element's, in case it's our own. + setTypeId(m) + m.Key = key.id() + m.Elem = elem.id() +} + +func (m *mapType) safeString(seen map[typeId]bool) string { + if seen[m.Id] { + return m.Name + } + seen[m.Id] = true + key := m.Key.gobType().safeString(seen) + elem := m.Elem.gobType().safeString(seen) + return fmt.Sprintf("map[%s]%s", key, elem) +} + +func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) } + +// Slice type +type sliceType struct { + CommonType + Elem typeId +} + +func newSliceType(name string) *sliceType { + s := &sliceType{CommonType{Name: name}, 0} + return s +} + +func (s *sliceType) init(elem gobType) { + // Set our type id before evaluating the element's, in case it's our own. + setTypeId(s) + // See the comments about ids in newTypeObject. Only slices and + // structs have mutual recursion. + if elem.id() == 0 { + setTypeId(elem) + } + s.Elem = elem.id() +} + +func (s *sliceType) safeString(seen map[typeId]bool) string { + if seen[s.Id] { + return s.Name + } + seen[s.Id] = true + return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen)) +} + +func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) } + +// Struct type +type fieldType struct { + Name string + Id typeId +} + +type structType struct { + CommonType + Field []fieldType +} + +func (s *structType) safeString(seen map[typeId]bool) string { + if s == nil { + return "" + } + if _, ok := seen[s.Id]; ok { + return s.Name + } + seen[s.Id] = true + str := s.Name + " = struct { " + for _, f := range s.Field { + str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen)) + } + str += "}" + return str +} + +func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) } + +func newStructType(name string) *structType { + s := &structType{CommonType{Name: name}, nil} + // For historical reasons we set the id here rather than init. + // See the comment in newTypeObject for details. + setTypeId(s) + return s +} + +// newTypeObject allocates a gobType for the reflection type rt. +// Unless ut represents a GobEncoder, rt should be the base type +// of ut. +// This is only called from the encoding side. The decoding side +// works through typeIds and userTypeInfos alone. +func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) { + // Does this type implement GobEncoder? + if ut.externalEnc != 0 { + return newGobEncoderType(name), nil + } + var err error + var type0, type1 gobType + defer func() { + if err != nil { + delete(types, rt) + } + }() + // Install the top-level type before the subtypes (e.g. struct before + // fields) so recursive types can be constructed safely. + switch t := rt; t.Kind() { + // All basic types are easy: they are predefined. + case reflect.Bool: + return tBool.gobType(), nil + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return tInt.gobType(), nil + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return tUint.gobType(), nil + + case reflect.Float32, reflect.Float64: + return tFloat.gobType(), nil + + case reflect.Complex64, reflect.Complex128: + return tComplex.gobType(), nil + + case reflect.String: + return tString.gobType(), nil + + case reflect.Interface: + return tInterface.gobType(), nil + + case reflect.Array: + at := newArrayType(name) + types[rt] = at + type0, err = getBaseType("", t.Elem()) + if err != nil { + return nil, err + } + // Historical aside: + // For arrays, maps, and slices, we set the type id after the elements + // are constructed. This is to retain the order of type id allocation after + // a fix made to handle recursive types, which changed the order in + // which types are built. Delaying the setting in this way preserves + // type ids while allowing recursive types to be described. Structs, + // done below, were already handling recursion correctly so they + // assign the top-level id before those of the field. + at.init(type0, t.Len()) + return at, nil + + case reflect.Map: + mt := newMapType(name) + types[rt] = mt + type0, err = getBaseType("", t.Key()) + if err != nil { + return nil, err + } + type1, err = getBaseType("", t.Elem()) + if err != nil { + return nil, err + } + mt.init(type0, type1) + return mt, nil + + case reflect.Slice: + // []byte == []uint8 is a special case + if t.Elem().Kind() == reflect.Uint8 { + return tBytes.gobType(), nil + } + st := newSliceType(name) + types[rt] = st + type0, err = getBaseType(t.Elem().Name(), t.Elem()) + if err != nil { + return nil, err + } + st.init(type0) + return st, nil + + case reflect.Struct: + st := newStructType(name) + types[rt] = st + idToTypeSlice[st.id()] = st + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if !isSent(&f) { + continue + } + typ := userType(f.Type).base + tname := typ.Name() + if tname == "" { + t := userType(f.Type).base + tname = t.String() + } + gt, err := getBaseType(tname, f.Type) + if err != nil { + return nil, err + } + // Some mutually recursive types can cause us to be here while + // still defining the element. Fix the element type id here. + // We could do this more neatly by setting the id at the start of + // building every type, but that would break binary compatibility. + if gt.id() == 0 { + setTypeId(gt) + } + st.Field = append(st.Field, fieldType{f.Name, gt.id()}) + } + return st, nil + + default: + return nil, errors.New("gob NewTypeObject can't handle type: " + rt.String()) + } +} + +// isExported reports whether this is an exported - upper case - name. +func isExported(name string) bool { + rune, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(rune) +} + +// isSent reports whether this struct field is to be transmitted. +// It will be transmitted only if it is exported and not a chan or func field +// or pointer to chan or func. +func isSent(field *reflect.StructField) bool { + if !isExported(field.Name) { + return false + } + // If the field is a chan or func or pointer thereto, don't send it. + // That is, treat it like an unexported field. + typ := field.Type + for typ.Kind() == reflect.Pointer { + typ = typ.Elem() + } + if typ.Kind() == reflect.Chan || typ.Kind() == reflect.Func { + return false + } + + return true +} + +// getBaseType returns the Gob type describing the given reflect.Type's base type. +// typeLock must be held. +func getBaseType(name string, rt reflect.Type) (gobType, error) { + ut := userType(rt) + return getType(name, ut, ut.base) +} + +// getType returns the Gob type describing the given reflect.Type. +// Should be called only when handling GobEncoders/Decoders, +// which may be pointers. All other types are handled through the +// base type, never a pointer. +// typeLock must be held. +func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) { + typ, present := types[rt] + if present { + return typ, nil + } + typ, err := newTypeObject(name, ut, rt) + if err == nil { + types[rt] = typ + } + return typ, err +} + +func checkId(want, got typeId) { + if want != got { + fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(got), int(want)) + panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string()) + } +} + +// used for building the basic types; called only from init(). the incoming +// interface always refers to a pointer. +func bootstrapType(name string, e any) typeId { + rt := reflect.TypeOf(e).Elem() + _, present := types[rt] + if present { + panic("bootstrap type already present: " + name + ", " + rt.String()) + } + typ := &CommonType{Name: name} + types[rt] = typ + setTypeId(typ) + return typ.id() +} + +// Representation of the information we send and receive about this type. +// Each value we send is preceded by its type definition: an encoded int. +// However, the very first time we send the value, we first send the pair +// (-id, wireType). +// For bootstrapping purposes, we assume that the recipient knows how +// to decode a wireType; it is exactly the wireType struct here, interpreted +// using the gob rules for sending a structure, except that we assume the +// ids for wireType and structType etc. are known. The relevant pieces +// are built in encode.go's init() function. +// To maintain binary compatibility, if you extend this type, always put +// the new fields last. +type wireType struct { + ArrayT *arrayType + SliceT *sliceType + StructT *structType + MapT *mapType + GobEncoderT *gobEncoderType + BinaryMarshalerT *gobEncoderType + TextMarshalerT *gobEncoderType +} + +func (w *wireType) string() string { + const unknown = "unknown type" + if w == nil { + return unknown + } + switch { + case w.ArrayT != nil: + return w.ArrayT.Name + case w.SliceT != nil: + return w.SliceT.Name + case w.StructT != nil: + return w.StructT.Name + case w.MapT != nil: + return w.MapT.Name + case w.GobEncoderT != nil: + return w.GobEncoderT.Name + case w.BinaryMarshalerT != nil: + return w.BinaryMarshalerT.Name + case w.TextMarshalerT != nil: + return w.TextMarshalerT.Name + } + return unknown +} + +type typeInfo struct { + id typeId + encInit sync.Mutex // protects creation of encoder + encoder atomic.Pointer[encEngine] + wire wireType +} + +// typeInfoMap is an atomic pointer to map[reflect.Type]*typeInfo. +// It's updated copy-on-write. Readers just do an atomic load +// to get the current version of the map. Writers make a full copy of +// the map and atomically update the pointer to point to the new map. +// Under heavy read contention, this is significantly faster than a map +// protected by a mutex. +var typeInfoMap atomic.Value + +// typeInfoMapInit is used instead of typeInfoMap during init time, +// as types are registered sequentially during init and we can save +// the overhead of making map copies. +// It is saved to typeInfoMap and set to nil before init finishes. +var typeInfoMapInit = make(map[reflect.Type]*typeInfo, 16) + +func lookupTypeInfo(rt reflect.Type) *typeInfo { + if m := typeInfoMapInit; m != nil { + return m[rt] + } + m, _ := typeInfoMap.Load().(map[reflect.Type]*typeInfo) + return m[rt] +} + +func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) { + rt := ut.base + if ut.externalEnc != 0 { + // We want the user type, not the base type. + rt = ut.user + } + if info := lookupTypeInfo(rt); info != nil { + return info, nil + } + return buildTypeInfo(ut, rt) +} + +// buildTypeInfo constructs the type information for the type +// and stores it in the type info map. +func buildTypeInfo(ut *userTypeInfo, rt reflect.Type) (*typeInfo, error) { + typeLock.Lock() + defer typeLock.Unlock() + + if info := lookupTypeInfo(rt); info != nil { + return info, nil + } + + gt, err := getBaseType(rt.Name(), rt) + if err != nil { + return nil, err + } + info := &typeInfo{id: gt.id()} + + if ut.externalEnc != 0 { + userType, err := getType(rt.Name(), ut, rt) + if err != nil { + return nil, err + } + gt := userType.id().gobType().(*gobEncoderType) + switch ut.externalEnc { + case xGob: + info.wire.GobEncoderT = gt + case xBinary: + info.wire.BinaryMarshalerT = gt + case xText: + info.wire.TextMarshalerT = gt + } + rt = ut.user + } else { + t := info.id.gobType() + switch typ := rt; typ.Kind() { + case reflect.Array: + info.wire.ArrayT = t.(*arrayType) + case reflect.Map: + info.wire.MapT = t.(*mapType) + case reflect.Slice: + // []byte == []uint8 is a special case handled separately + if typ.Elem().Kind() != reflect.Uint8 { + info.wire.SliceT = t.(*sliceType) + } + case reflect.Struct: + info.wire.StructT = t.(*structType) + } + } + + if m := typeInfoMapInit; m != nil { + m[rt] = info + return info, nil + } + + // Create new map with old contents plus new entry. + m, _ := typeInfoMap.Load().(map[reflect.Type]*typeInfo) + newm := make(map[reflect.Type]*typeInfo, len(m)) + for k, v := range m { + newm[k] = v + } + newm[rt] = info + typeInfoMap.Store(newm) + return info, nil +} + +// Called only when a panic is acceptable and unexpected. +func mustGetTypeInfo(rt reflect.Type) *typeInfo { + t, err := getTypeInfo(userType(rt)) + if err != nil { + panic("getTypeInfo: " + err.Error()) + } + return t +} + +// GobEncoder is the interface describing data that provides its own +// representation for encoding values for transmission to a GobDecoder. +// A type that implements GobEncoder and GobDecoder has complete +// control over the representation of its data and may therefore +// contain things such as private fields, channels, and functions, +// which are not usually transmissible in gob streams. +// +// Note: Since gobs can be stored permanently, it is good design +// to guarantee the encoding used by a GobEncoder is stable as the +// software evolves. For instance, it might make sense for GobEncode +// to include a version number in the encoding. +type GobEncoder interface { + // GobEncode returns a byte slice representing the encoding of the + // receiver for transmission to a GobDecoder, usually of the same + // concrete type. + GobEncode() ([]byte, error) +} + +// GobDecoder is the interface describing data that provides its own +// routine for decoding transmitted values sent by a GobEncoder. +type GobDecoder interface { + // GobDecode overwrites the receiver, which must be a pointer, + // with the value represented by the byte slice, which was written + // by GobEncode, usually for the same concrete type. + GobDecode([]byte) error +} + +var ( + nameToConcreteType sync.Map // map[string]reflect.Type + concreteTypeToName sync.Map // map[reflect.Type]string +) + +// RegisterName is like [Register] but uses the provided name rather than the +// type's default. +func RegisterName(name string, value any) { + if name == "" { + // reserved for nil + panic("attempt to register empty name") + } + + ut := userType(reflect.TypeOf(value)) + + // Check for incompatible duplicates. The name must refer to the + // same user type, and vice versa. + + // Store the name and type provided by the user.... + if t, dup := nameToConcreteType.LoadOrStore(name, reflect.TypeOf(value)); dup && t != ut.user { + panic(fmt.Sprintf("gob: registering duplicate types for %q: %s != %s", name, t, ut.user)) + } + + // but the flattened type in the type table, since that's what decode needs. + if n, dup := concreteTypeToName.LoadOrStore(ut.base, name); dup && n != name { + nameToConcreteType.Delete(name) + panic(fmt.Sprintf("gob: registering duplicate names for %s: %q != %q", ut.user, n, name)) + } +} + +// Register records a type, identified by a value for that type, under its +// internal type name. That name will identify the concrete type of a value +// sent or received as an interface variable. Only types that will be +// transferred as implementations of interface values need to be registered. +// Expecting to be used only during initialization, it panics if the mapping +// between types and names is not a bijection. +func Register(value any) { + // Default to printed representation for unnamed types + rt := reflect.TypeOf(value) + name := rt.String() + + // But for named types (or pointers to them), qualify with import path (but see inner comment). + // Dereference one pointer looking for a named type. + star := "" + if rt.Name() == "" { + if pt := rt; pt.Kind() == reflect.Pointer { + star = "*" + // NOTE: The following line should be rt = pt.Elem() to implement + // what the comment above claims, but fixing it would break compatibility + // with existing gobs. + // + // Given package p imported as "full/p" with these definitions: + // package p + // type T1 struct { ... } + // this table shows the intended and actual strings used by gob to + // name the types: + // + // Type Correct string Actual string + // + // T1 full/p.T1 full/p.T1 + // *T1 *full/p.T1 *p.T1 + // + // The missing full path cannot be fixed without breaking existing gob decoders. + rt = pt + } + } + if rt.Name() != "" { + if rt.PkgPath() == "" { + name = star + rt.Name() + } else { + name = star + rt.PkgPath() + "." + rt.Name() + } + } + + RegisterName(name, value) +} + +func registerBasics() { + Register(int(0)) + Register(int8(0)) + Register(int16(0)) + Register(int32(0)) + Register(int64(0)) + Register(uint(0)) + Register(uint8(0)) + Register(uint16(0)) + Register(uint32(0)) + Register(uint64(0)) + Register(float32(0)) + Register(float64(0)) + Register(complex64(0i)) + Register(complex128(0i)) + Register(uintptr(0)) + Register(false) + Register("") + Register([]byte(nil)) + Register([]int(nil)) + Register([]int8(nil)) + Register([]int16(nil)) + Register([]int32(nil)) + Register([]int64(nil)) + Register([]uint(nil)) + Register([]uint8(nil)) + Register([]uint16(nil)) + Register([]uint32(nil)) + Register([]uint64(nil)) + Register([]float32(nil)) + Register([]float64(nil)) + Register([]complex64(nil)) + Register([]complex128(nil)) + Register([]uintptr(nil)) + Register([]bool(nil)) + Register([]string(nil)) +} + +func init() { + typeInfoMap.Store(typeInfoMapInit) + typeInfoMapInit = nil +} diff --git a/contrib/go/_std_1.22/src/encoding/gob/ya.make b/contrib/go/_std_1.23/src/encoding/gob/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/ya.make rename to contrib/go/_std_1.23/src/encoding/gob/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/hex/hex.go b/contrib/go/_std_1.23/src/encoding/hex/hex.go similarity index 97% rename from contrib/go/_std_1.22/src/encoding/hex/hex.go rename to contrib/go/_std_1.23/src/encoding/hex/hex.go index 791d2bd4adfa..ba9cc0f967f6 100644 --- a/contrib/go/_std_1.22/src/encoding/hex/hex.go +++ b/contrib/go/_std_1.23/src/encoding/hex/hex.go @@ -136,11 +136,9 @@ func EncodeToString(src []byte) string { // If the input is malformed, DecodeString returns // the bytes decoded before the error. func DecodeString(s string) ([]byte, error) { - src := []byte(s) - // We can use the source slice itself as the destination - // because the decode loop increments by one and then the 'seen' byte is not used anymore. - n, err := Decode(src, src) - return src[:n], err + dst := make([]byte, DecodedLen(len(s))) + n, err := Decode(dst, []byte(s)) + return dst[:n], err } // Dump returns a string that contains a hex dump of the given data. The format diff --git a/contrib/go/_std_1.22/src/encoding/hex/ya.make b/contrib/go/_std_1.23/src/encoding/hex/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/hex/ya.make rename to contrib/go/_std_1.23/src/encoding/hex/ya.make diff --git a/contrib/go/_std_1.23/src/encoding/json/decode.go b/contrib/go/_std_1.23/src/encoding/json/decode.go new file mode 100644 index 000000000000..f8205704e38b --- /dev/null +++ b/contrib/go/_std_1.23/src/encoding/json/decode.go @@ -0,0 +1,1302 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Represents JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package json + +import ( + "encoding" + "encoding/base64" + "fmt" + "reflect" + "strconv" + "strings" + "unicode" + "unicode/utf16" + "unicode/utf8" + _ "unsafe" // for linkname +) + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. If v is nil or not a pointer, +// Unmarshal returns an [InvalidUnmarshalError]. +// +// Unmarshal uses the inverse of the encodings that +// [Marshal] uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a value implementing [Unmarshaler], +// Unmarshal calls that value's [Unmarshaler.UnmarshalJSON] method, including +// when the input is a JSON null. +// Otherwise, if the value implements [encoding.TextUnmarshaler] +// and the input is a JSON quoted string, Unmarshal calls +// [encoding.TextUnmarshaler.UnmarshalText] with the unquoted form of the string. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by [Marshal] (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. By +// default, object keys which don't have a corresponding struct field are +// ignored (see [Decoder.DisallowUnknownFields] for an alternative). +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// - bool, for JSON booleans +// - float64, for JSON numbers +// - string, for JSON strings +// - []interface{}, for JSON arrays +// - map[string]interface{}, for JSON objects +// - nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores +// key-value pairs from the JSON object into the map. The map's key type must +// either be any string type, an integer, or implement [encoding.TextUnmarshaler]. +// +// If the JSON-encoded data contain a syntax error, Unmarshal returns a [SyntaxError]. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an [UnmarshalTypeError] describing the earliest such error. In any +// case, it's not guaranteed that all the remaining fields following +// the problematic one will be unmarshaled into the target object. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// “not present,” unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +func Unmarshal(data []byte, v any) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + var d decodeState + err := checkValid(data, &d.scan) + if err != nil { + return err + } + + d.init(data) + return d.unmarshal(v) +} + +// Unmarshaler is the interface implemented by types +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +// +// By convention, to approximate the behavior of [Unmarshal] itself, +// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes + Struct string // name of the struct type containing the field + Field string // the full path from root node to the field +} + +func (e *UnmarshalTypeError) Error() string { + if e.Struct != "" || e.Field != "" { + return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() + } + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() +} + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// +// Deprecated: No longer used; kept for compatibility. +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() +} + +// An InvalidUnmarshalError describes an invalid argument passed to [Unmarshal]. +// (The argument to [Unmarshal] must be a non-nil pointer.) +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Pointer { + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" + } + return "json: Unmarshal(nil " + e.Type.String() + ")" +} + +func (d *decodeState) unmarshal(v any) error { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Pointer || rv.IsNil() { + return &InvalidUnmarshalError{reflect.TypeOf(v)} + } + + d.scan.reset() + d.scanWhile(scanSkipSpace) + // We decode rv not rv.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + err := d.value(rv) + if err != nil { + return d.addErrorContext(err) + } + return d.savedError +} + +// A Number represents a JSON number literal. +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +// An errorContext provides context for type errors during decoding. +type errorContext struct { + Struct reflect.Type + FieldStack []string +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner + errorContext *errorContext + savedError error + useNumber bool + disallowUnknownFields bool +} + +// readIndex returns the position of the last byte read. +func (d *decodeState) readIndex() int { + return d.off - 1 +} + +// phasePanicMsg is used as a panic message when we end up with something that +// shouldn't happen. It can indicate a bug in the JSON decoder, or that +// something is editing the data slice while the decoder executes. +const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + d.savedError = nil + if d.errorContext != nil { + d.errorContext.Struct = nil + // Reuse the allocated space for the FieldStack slice. + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + } + return d +} + +// saveError saves the first err it is called with, +// for reporting at the end of the unmarshal. +func (d *decodeState) saveError(err error) { + if d.savedError == nil { + d.savedError = d.addErrorContext(err) + } +} + +// addErrorContext returns a new error enhanced with information from d.errorContext +func (d *decodeState) addErrorContext(err error) error { + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { + switch err := err.(type) { + case *UnmarshalTypeError: + err.Struct = d.errorContext.Struct.Name() + err.Field = strings.Join(d.errorContext.FieldStack, ".") + } + } + return err +} + +// skip scans to the end of what was started. +func (d *decodeState) skip() { + s, data, i := &d.scan, d.data, d.off + depth := len(s.parseState) + for { + op := s.step(s, data[i]) + i++ + if len(s.parseState) < depth { + d.off = i + d.opcode = op + return + } + } +} + +// scanNext processes the byte at d.data[d.off]. +func (d *decodeState) scanNext() { + if d.off < len(d.data) { + d.opcode = d.scan.step(&d.scan, d.data[d.off]) + d.off++ + } else { + d.opcode = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +func (d *decodeState) scanWhile(op int) { + s, data, i := &d.scan, d.data, d.off + for i < len(data) { + newOp := s.step(s, data[i]) + i++ + if newOp != op { + d.opcode = newOp + d.off = i + return + } + } + + d.off = len(data) + 1 // mark processed EOF with len+1 + d.opcode = d.scan.eof() +} + +// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the +// common case where we're decoding a literal. The decoder scans the input +// twice, once for syntax errors and to check the length of the value, and the +// second to perform the decoding. +// +// Only in the second step do we use decodeState to tokenize literals, so we +// know there aren't any syntax errors. We can take advantage of that knowledge, +// and scan a literal's bytes much more quickly. +func (d *decodeState) rescanLiteral() { + data, i := d.data, d.off +Switch: + switch data[i-1] { + case '"': // string + for ; i < len(data); i++ { + switch data[i] { + case '\\': + i++ // escaped char + case '"': + i++ // tokenize the closing quote too + break Switch + } + } + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number + for ; i < len(data); i++ { + switch data[i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '.', 'e', 'E', '+', '-': + default: + break Switch + } + } + case 't': // true + i += len("rue") + case 'f': // false + i += len("alse") + case 'n': // null + i += len("ull") + } + if i < len(data) { + d.opcode = stateEndValue(&d.scan, data[i]) + } else { + d.opcode = scanEnd + } + d.off = i + 1 +} + +// value consumes a JSON value from d.data[d.off-1:], decoding into v, and +// reads the following byte ahead. If v is invalid, the value is discarded. +// The first byte of the value has been read already. +func (d *decodeState) value(v reflect.Value) error { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray: + if v.IsValid() { + if err := d.array(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginObject: + if v.IsValid() { + if err := d.object(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginLiteral: + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + if v.IsValid() { + if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { + return err + } + } + } + return nil +} + +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() any { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray, scanBeginObject: + d.skip() + d.scanNext() + + case scanBeginLiteral: + v := d.literalInterface() + switch v.(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// If it encounters an Unmarshaler, indirect stops and returns that. +// If decodingNull is true, indirect stops at the first settable pointer so it +// can be set to nil. +func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // Issue #24153 indicates that it is generally not a guaranteed property + // that you may round-trip a reflect.Value by calling Value.Addr().Elem() + // and expect the value to still be settable for values derived from + // unexported embedded struct fields. + // + // The logic below effectively does this when it first addresses the value + // (to satisfy possible pointer methods) and continues to dereference + // subsequent pointers as necessary. + // + // After the first round-trip, we set v back to the original value to + // preserve the original RW flags contained in reflect.Value. + v0 := v + haveAddr := false + + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Pointer && v.Type().Name() != "" && v.CanAddr() { + haveAddr = true + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Pointer && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Pointer) { + haveAddr = false + v = e + continue + } + } + + if v.Kind() != reflect.Pointer { + break + } + + if decodingNull && v.CanSet() { + break + } + + // Prevent infinite loop if v is an interface pointing to its own address: + // var v interface{} + // v = &v + if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { + v = v.Elem() + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if !decodingNull { + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + } + + if haveAddr { + v = v0 // restore original value after round-trip Value.Addr().Elem() + haveAddr = false + } else { + v = v.Elem() + } + } + return nil, nil, v +} + +// array consumes an array from d.data[d.off-1:], decoding into v. +// The first byte of the array ('[') has been read already. +func (d *decodeState) array(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + + // Check type of target. + switch v.Kind() { + case reflect.Interface: + if v.NumMethod() == 0 { + // Decoding into nil interface? Switch to non-reflect code. + ai := d.arrayInterface() + v.Set(reflect.ValueOf(ai)) + return nil + } + // Otherwise it's invalid. + fallthrough + default: + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + case reflect.Array, reflect.Slice: + break + } + + i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + // Expand slice length, growing the slice if necessary. + if v.Kind() == reflect.Slice { + if i >= v.Cap() { + v.Grow(1) + } + if i >= v.Len() { + v.SetLen(i + 1) + } + } + + if i < v.Len() { + // Decode into element. + if err := d.value(v.Index(i)); err != nil { + return err + } + } else { + // Ran out of fixed array: skip. + if err := d.value(reflect.Value{}); err != nil { + return err + } + } + i++ + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + + if i < v.Len() { + if v.Kind() == reflect.Array { + for ; i < v.Len(); i++ { + v.Index(i).SetZero() // zero remainder of array + } + } else { + v.SetLen(i) // truncate the slice + } + } + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } + return nil +} + +var nullLiteral = []byte("null") +var textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]() + +// object consumes an object from d.data[d.off-1:], decoding into v. +// The first byte ('{') of the object has been read already. +func (d *decodeState) object(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + t := v.Type() + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { + oi := d.objectInterface() + v.Set(reflect.ValueOf(oi)) + return nil + } + + var fields structFields + + // Check type of target: + // struct or + // map[T1]T2 where T1 is string, an integer type, + // or an encoding.TextUnmarshaler + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind, have an integer kind, + // or be an encoding.TextUnmarshaler. + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !reflect.PointerTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + fields = cachedTypeFields(t) + // ok + default: + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + + var mapElem reflect.Value + var origErrorContext errorContext + if d.errorContext != nil { + origErrorContext = *d.errorContext + } + + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquoteBytes(item) + if !ok { + panic(phasePanicMsg) + } + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := t.Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.SetZero() + } + subv = mapElem + } else { + f := fields.byExactName[string(key)] + if f == nil { + f = fields.byFoldedName[string(foldName(key))] + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Pointer { + if subv.IsNil() { + // If a struct embeds a pointer to an unexported type, + // it is not possible to set a newly allocated value + // since the field is unexported. + // + // See https://golang.org/issue/21357 + if !subv.CanSet() { + d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) + // Invalidate subv to ensure d.value(subv) skips over + // the JSON value without assigning it to subv. + subv = reflect.Value{} + destring = false + break + } + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + if d.errorContext == nil { + d.errorContext = new(errorContext) + } + d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) + d.errorContext.Struct = t + } else if d.disallowUnknownFields { + d.saveError(fmt.Errorf("json: unknown field %q", key)) + } + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + if err := d.literalStore(nullLiteral, subv, false); err != nil { + return err + } + case string: + if err := d.literalStore([]byte(qv), subv, true); err != nil { + return err + } + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + if err := d.value(subv); err != nil { + return err + } + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := t.Key() + var kv reflect.Value + if reflect.PointerTo(kt).Implements(textUnmarshalerType) { + kv = reflect.New(kt) + if err := d.literalStore(item, kv, true); err != nil { + return err + } + kv = kv.Elem() + } else { + switch kt.Kind() { + case reflect.String: + kv = reflect.New(kt).Elem() + kv.SetString(string(key)) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := string(key) + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || kt.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.New(kt).Elem() + kv.SetInt(n) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s := string(key) + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || kt.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.New(kt).Elem() + kv.SetUint(n) + default: + panic("json: Unexpected key type") // should never occur + } + } + if kv.IsValid() { + v.SetMapIndex(kv, subv) + } + } + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.errorContext != nil { + // Reset errorContext to its original state. + // Keep the same underlying array for FieldStack, to reuse the + // space and avoid unnecessary allocs. + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] + d.errorContext.Struct = origErrorContext.Struct + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return nil +} + +// convertNumber converts the number literal s to a float64 or a Number +// depending on the setting of d.useNumber. +func (d *decodeState) convertNumber(s string) (any, error) { + if d.useNumber { + return Number(s), nil + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeFor[float64](), Offset: int64(d.off)} + } + return f, nil +} + +var numberType = reflect.TypeFor[Number]() + +// literalStore decodes a literal stored in item into v. +// +// fromQuoted indicates whether this literal came from unwrapping a +// string from the ",string" struct tag option. this is used only to +// produce more helpful error messages. +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { + // Check for unmarshaler. + if len(item) == 0 { + // Empty string given. + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + isNull := item[0] == 'n' // null + u, ut, pv := indirect(v, isNull) + if u != nil { + return u.UnmarshalJSON(item) + } + if ut != nil { + if item[0] != '"' { + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + val := "number" + switch item[0] { + case 'n': + val = "null" + case 't', 'f': + val = "bool" + } + d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) + return nil + } + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + return ut.UnmarshalText(s) + } + + v = pv + + switch c := item[0]; c { + case 'n': // null + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "null" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice: + v.SetZero() + // otherwise, ignore null for primitives/string + } + case 't', 'f': // true, false + value := item[0] == 't' + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "true" && string(item) != "false" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + default: + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + case reflect.Bool: + v.SetBool(value) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(value)) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + case '"': // string + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + switch v.Kind() { + default: + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Slice: + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) + n, err := base64.StdEncoding.Decode(b, s) + if err != nil { + d.saveError(err) + break + } + v.SetBytes(b[:n]) + case reflect.String: + t := string(s) + if v.Type() == numberType && !isValidNumber(t) { + return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) + } + v.SetString(t) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(string(s))) + } else { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + default: // number + if c != '-' && (c < '0' || c > '9') { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + switch v.Kind() { + default: + if v.Kind() == reflect.String && v.Type() == numberType { + // s must be a valid number, because it's + // already been tokenized. + v.SetString(string(item)) + break + } + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Interface: + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + break + } + if v.NumMethod() != 0 { + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.Set(reflect.ValueOf(n)) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(string(item), 10, 64) + if err != nil || v.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(string(item), 10, 64) + if err != nil || v.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetUint(n) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(string(item), v.Type().Bits()) + if err != nil || v.OverflowFloat(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetFloat(n) + } + } + return nil +} + +// The xxxInterface routines build up a value to be stored +// in an empty interface. They are not strictly necessary, +// but they avoid the weight of reflection in this common case. + +// valueInterface is like value but returns interface{} +func (d *decodeState) valueInterface() (val any) { + switch d.opcode { + default: + panic(phasePanicMsg) + case scanBeginArray: + val = d.arrayInterface() + d.scanNext() + case scanBeginObject: + val = d.objectInterface() + d.scanNext() + case scanBeginLiteral: + val = d.literalInterface() + } + return +} + +// arrayInterface is like array but returns []interface{}. +func (d *decodeState) arrayInterface() []any { + var v = make([]any, 0) + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + v = append(v, d.valueInterface()) + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + return v +} + +// objectInterface is like object but returns map[string]interface{}. +func (d *decodeState) objectInterface() map[string]any { + m := make(map[string]any) + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read string key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + // Read value. + m[key] = d.valueInterface() + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return m +} + +// literalInterface consumes and returns a literal from d.data[d.off-1:] and +// it reads the following byte ahead. The first byte of the literal has been +// read already (that's how the caller knows it's a literal). +func (d *decodeState) literalInterface() any { + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + item := d.data[start:d.readIndex()] + + switch c := item[0]; c { + case 'n': // null + return nil + + case 't', 'f': // true, false + return c == 't' + + case '"': // string + s, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + return s + + default: // number + if c != '-' && (c < '0' || c > '9') { + panic(phasePanicMsg) + } + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + } + return n + } +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) + } + return r +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +// unquoteBytes should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname unquoteBytes +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/contrib/go/_std_1.23/src/encoding/json/encode.go b/contrib/go/_std_1.23/src/encoding/json/encode.go new file mode 100644 index 000000000000..7bee1a6805f4 --- /dev/null +++ b/contrib/go/_std_1.23/src/encoding/json/encode.go @@ -0,0 +1,1286 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package json implements encoding and decoding of JSON as defined in +// RFC 7159. The mapping between JSON and Go values is described +// in the documentation for the Marshal and Unmarshal functions. +// +// See "JSON and Go" for an introduction to this package: +// https://golang.org/doc/articles/json_and_go.html +package json + +import ( + "bytes" + "cmp" + "encoding" + "encoding/base64" + "fmt" + "math" + "reflect" + "slices" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" + _ "unsafe" // for linkname +) + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements [Marshaler] +// and is not a nil pointer, Marshal calls [Marshaler.MarshalJSON] +// to produce JSON. If no [Marshaler.MarshalJSON] method is present but the +// value implements [encoding.TextMarshaler] instead, Marshal calls +// [encoding.TextMarshaler.MarshalText] and encodes the result as a JSON string. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// [Unmarshaler.UnmarshalJSON]. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and [Number] values encode as JSON numbers. +// NaN and +/-Inf values will return an [UnsupportedValueError]. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// So that the JSON will be safe to embed inside HTML ") + +produces + + Hello, ! + +but the contextual autoescaping in html/template + + import "html/template" + ... + t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) + err = t.ExecuteTemplate(out, "T", "") + +produces safe, escaped HTML output + + Hello, <script>alert('you have been pwned')</script>! + +# Contexts + +This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing +functions to each simple action pipeline, so given the excerpt + + {{.}} + +At parse time each {{.}} is overwritten to add escaping functions as necessary. +In this case it becomes + + {{. | htmlescaper}} + +where urlescaper, attrescaper, and htmlescaper are aliases for internal escaping +functions. + +For these internal escaping functions, if an action pipeline evaluates to +a nil interface value, it is treated as though it were an empty string. + +# Namespaced and data- attributes + +Attributes with a namespace are treated as if they had no namespace. +Given the excerpt + + + +At parse time the attribute will be treated as if it were just "href". +So at parse time the template becomes: + + + +Similarly to attributes with namespaces, attributes with a "data-" prefix are +treated as if they had no "data-" prefix. So given + + + +At parse time this becomes + + + +If an attribute has both a namespace and a "data-" prefix, only the namespace +will be removed when determining the context. For example + + + +This is handled as if "my:data-href" was just "data-href" and not "href" as +it would be if the "data-" prefix were to be ignored too. Thus at parse +time this becomes just + + + +As a special case, attributes with the namespace "xmlns" are always treated +as containing URLs. Given the excerpts + + + + + +At parse time they become: + + + + + +# Errors + +See the documentation of ErrorCode for details. + +# A fuller picture + +The rest of this package comment may be skipped on first reading; it includes +details necessary to understand escaping contexts and error messages. Most users +will not need to understand these details. + +# Contexts + +Assuming {{.}} is `O'Reilly: How are you?`, the table below shows +how {{.}} appears when used in the context to the left. + + Context {{.}} After + {{.}} O'Reilly: How are <i>you</i>? + O'Reilly: How are you? + O'Reilly: How are %3ci%3eyou%3c/i%3e? + O'Reilly%3a%20How%20are%3ci%3e...%3f + O\x27Reilly: How are \x3ci\x3eyou...? + "O\x27Reilly: How are \x3ci\x3eyou...?" + O\x27Reilly: How are \x3ci\x3eyou...\x3f + +If used in an unsafe context, then the value might be filtered out: + + Context {{.}} After + #ZgotmplZ + +since "O'Reilly:" is not an allowed protocol like "http:". + +If {{.}} is the innocuous word, `left`, then it can appear more widely, + + Context {{.}} After + {{.}} left + left + left + left + left + left + left + left + left + +Non-string values can be used in JavaScript contexts. +If {{.}} is + + struct{A,B string}{ "foo", "bar" } + +in the escaped template + + + +then the template output is + + + +See package json to understand how non-string content is marshaled for +embedding in JavaScript contexts. + +# Typed Strings + +By default, this package assumes that all pipelines produce a plain text string. +It adds escaping pipeline stages necessary to correctly and safely embed that +plain text string in the appropriate context. + +When a data value is not plain text, you can make sure it is not over-escaped +by marking it with its type. + +Types HTML, JS, URL, and others from content.go can carry safe content that is +exempted from escaping. + +The template + + Hello, {{.}}! + +can be invoked with + + tmpl.Execute(out, template.HTML(`World`)) + +to produce + + Hello, World! + +instead of the + + Hello, <b>World<b>! + +that would have been produced if {{.}} was a regular string. + +# Security Model + +https://rawgit.com/mikesamuel/sanitized-jquery-templates/trunk/safetemplate.html#problem_definition defines "safe" as used by this package. + +This package assumes that template authors are trusted, that Execute's data +parameter is not, and seeks to preserve the properties below in the face +of untrusted data: + +Structure Preservation Property: +"... when a template author writes an HTML tag in a safe templating language, +the browser will interpret the corresponding portion of the output as a tag +regardless of the values of untrusted data, and similarly for other structures +such as attribute boundaries and JS and CSS string boundaries." + +Code Effect Property: +"... only code specified by the template author should run as a result of +injecting the template output into a page and all code specified by the +template author should run as a result of the same." + +Least Surprise Property: +"A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who +knows that contextual autoescaping happens should be able to look at a {{.}} +and correctly infer what sanitization happens." + +Previously, ECMAScript 6 template literal were disabled by default, and could be +enabled with the GODEBUG=jstmpllitinterp=1 environment variable. Template +literals are now supported by default, and setting jstmpllitinterp has no +effect. +*/ +package template diff --git a/contrib/go/_std_1.22/src/html/template/element_string.go b/contrib/go/_std_1.23/src/html/template/element_string.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/element_string.go rename to contrib/go/_std_1.23/src/html/template/element_string.go diff --git a/contrib/go/_std_1.22/src/html/template/error.go b/contrib/go/_std_1.23/src/html/template/error.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/error.go rename to contrib/go/_std_1.23/src/html/template/error.go diff --git a/contrib/go/_std_1.22/src/html/template/escape.go b/contrib/go/_std_1.23/src/html/template/escape.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/escape.go rename to contrib/go/_std_1.23/src/html/template/escape.go diff --git a/contrib/go/_std_1.22/src/html/template/html.go b/contrib/go/_std_1.23/src/html/template/html.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/html.go rename to contrib/go/_std_1.23/src/html/template/html.go diff --git a/contrib/go/_std_1.23/src/html/template/js.go b/contrib/go/_std_1.23/src/html/template/js.go new file mode 100644 index 000000000000..d1463dee1491 --- /dev/null +++ b/contrib/go/_std_1.23/src/html/template/js.go @@ -0,0 +1,485 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package template + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "strings" + "unicode/utf8" +) + +// jsWhitespace contains all of the JS whitespace characters, as defined +// by the \s character class. +// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Character_classes. +const jsWhitespace = "\f\n\r\t\v\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff" + +// nextJSCtx returns the context that determines whether a slash after the +// given run of tokens starts a regular expression instead of a division +// operator: / or /=. +// +// This assumes that the token run does not include any string tokens, comment +// tokens, regular expression literal tokens, or division operators. +// +// This fails on some valid but nonsensical JavaScript programs like +// "x = ++/foo/i" which is quite different than "x++/foo/i", but is not known to +// fail on any known useful programs. It is based on the draft +// JavaScript 2.0 lexical grammar and requires one token of lookbehind: +// https://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html +func nextJSCtx(s []byte, preceding jsCtx) jsCtx { + // Trim all JS whitespace characters + s = bytes.TrimRight(s, jsWhitespace) + if len(s) == 0 { + return preceding + } + + // All cases below are in the single-byte UTF-8 group. + switch c, n := s[len(s)-1], len(s); c { + case '+', '-': + // ++ and -- are not regexp preceders, but + and - are whether + // they are used as infix or prefix operators. + start := n - 1 + // Count the number of adjacent dashes or pluses. + for start > 0 && s[start-1] == c { + start-- + } + if (n-start)&1 == 1 { + // Reached for trailing minus signs since "---" is the + // same as "-- -". + return jsCtxRegexp + } + return jsCtxDivOp + case '.': + // Handle "42." + if n != 1 && '0' <= s[n-2] && s[n-2] <= '9' { + return jsCtxDivOp + } + return jsCtxRegexp + // Suffixes for all punctuators from section 7.7 of the language spec + // that only end binary operators not handled above. + case ',', '<', '>', '=', '*', '%', '&', '|', '^', '?': + return jsCtxRegexp + // Suffixes for all punctuators from section 7.7 of the language spec + // that are prefix operators not handled above. + case '!', '~': + return jsCtxRegexp + // Matches all the punctuators from section 7.7 of the language spec + // that are open brackets not handled above. + case '(', '[': + return jsCtxRegexp + // Matches all the punctuators from section 7.7 of the language spec + // that precede expression starts. + case ':', ';', '{': + return jsCtxRegexp + // CAVEAT: the close punctuators ('}', ']', ')') precede div ops and + // are handled in the default except for '}' which can precede a + // division op as in + // ({ valueOf: function () { return 42 } } / 2 + // which is valid, but, in practice, developers don't divide object + // literals, so our heuristic works well for code like + // function () { ... } /foo/.test(x) && sideEffect(); + // The ')' punctuator can precede a regular expression as in + // if (b) /foo/.test(x) && ... + // but this is much less likely than + // (a + b) / c + case '}': + return jsCtxRegexp + default: + // Look for an IdentifierName and see if it is a keyword that + // can precede a regular expression. + j := n + for j > 0 && isJSIdentPart(rune(s[j-1])) { + j-- + } + if regexpPrecederKeywords[string(s[j:])] { + return jsCtxRegexp + } + } + // Otherwise is a punctuator not listed above, or + // a string which precedes a div op, or an identifier + // which precedes a div op. + return jsCtxDivOp +} + +// regexpPrecederKeywords is a set of reserved JS keywords that can precede a +// regular expression in JS source. +var regexpPrecederKeywords = map[string]bool{ + "break": true, + "case": true, + "continue": true, + "delete": true, + "do": true, + "else": true, + "finally": true, + "in": true, + "instanceof": true, + "return": true, + "throw": true, + "try": true, + "typeof": true, + "void": true, +} + +var jsonMarshalType = reflect.TypeFor[json.Marshaler]() + +// indirectToJSONMarshaler returns the value, after dereferencing as many times +// as necessary to reach the base type (or nil) or an implementation of json.Marshal. +func indirectToJSONMarshaler(a any) any { + // text/template now supports passing untyped nil as a func call + // argument, so we must support it. Otherwise we'd panic below, as one + // cannot call the Type or Interface methods on an invalid + // reflect.Value. See golang.org/issue/18716. + if a == nil { + return nil + } + + v := reflect.ValueOf(a) + for !v.Type().Implements(jsonMarshalType) && v.Kind() == reflect.Pointer && !v.IsNil() { + v = v.Elem() + } + return v.Interface() +} + +// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has +// neither side-effects nor free variables outside (NaN, Infinity). +func jsValEscaper(args ...any) string { + var a any + if len(args) == 1 { + a = indirectToJSONMarshaler(args[0]) + switch t := a.(type) { + case JS: + return string(t) + case JSStr: + // TODO: normalize quotes. + return `"` + string(t) + `"` + case json.Marshaler: + // Do not treat as a Stringer. + case fmt.Stringer: + a = t.String() + } + } else { + for i, arg := range args { + args[i] = indirectToJSONMarshaler(arg) + } + a = fmt.Sprint(args...) + } + // TODO: detect cycles before calling Marshal which loops infinitely on + // cyclic data. This may be an unacceptable DoS risk. + b, err := json.Marshal(a) + if err != nil { + // While the standard JSON marshaler does not include user controlled + // information in the error message, if a type has a MarshalJSON method, + // the content of the error message is not guaranteed. Since we insert + // the error into the template, as part of a comment, we attempt to + // prevent the error from either terminating the comment, or the script + // block itself. + // + // In particular we: + // * replace "*/" comment end tokens with "* /", which does not + // terminate the comment + // * replace "", "", or " element, +// or in an HTML5 event handler attribute such as onclick. +func jsStrEscaper(args ...any) string { + s, t := stringify(args...) + if t == contentTypeJSStr { + return replace(s, jsStrNormReplacementTable) + } + return replace(s, jsStrReplacementTable) +} + +func jsTmplLitEscaper(args ...any) string { + s, _ := stringify(args...) + return replace(s, jsBqStrReplacementTable) +} + +// jsRegexpEscaper behaves like jsStrEscaper but escapes regular expression +// specials so the result is treated literally when included in a regular +// expression literal. /foo{{.X}}bar/ matches the string "foo" followed by +// the literal text of {{.X}} followed by the string "bar". +func jsRegexpEscaper(args ...any) string { + s, _ := stringify(args...) + s = replace(s, jsRegexpReplacementTable) + if s == "" { + // /{{.X}}/ should not produce a line comment when .X == "". + return "(?:)" + } + return s +} + +// replace replaces each rune r of s with replacementTable[r], provided that +// r < len(replacementTable). If replacementTable[r] is the empty string then +// no replacement is made. +// It also replaces runes U+2028 and U+2029 with the raw strings `\u2028` and +// `\u2029`. +func replace(s string, replacementTable []string) string { + var b strings.Builder + r, w, written := rune(0), 0, 0 + for i := 0; i < len(s); i += w { + // See comment in htmlEscaper. + r, w = utf8.DecodeRuneInString(s[i:]) + var repl string + switch { + case int(r) < len(lowUnicodeReplacementTable): + repl = lowUnicodeReplacementTable[r] + case int(r) < len(replacementTable) && replacementTable[r] != "": + repl = replacementTable[r] + case r == '\u2028': + repl = `\u2028` + case r == '\u2029': + repl = `\u2029` + default: + continue + } + if written == 0 { + b.Grow(len(s)) + } + b.WriteString(s[written:i]) + b.WriteString(repl) + written = i + w + } + if written == 0 { + return s + } + b.WriteString(s[written:]) + return b.String() +} + +var lowUnicodeReplacementTable = []string{ + 0: `\u0000`, 1: `\u0001`, 2: `\u0002`, 3: `\u0003`, 4: `\u0004`, 5: `\u0005`, 6: `\u0006`, + '\a': `\u0007`, + '\b': `\u0008`, + '\t': `\t`, + '\n': `\n`, + '\v': `\u000b`, // "\v" == "v" on IE 6. + '\f': `\f`, + '\r': `\r`, + 0xe: `\u000e`, 0xf: `\u000f`, 0x10: `\u0010`, 0x11: `\u0011`, 0x12: `\u0012`, 0x13: `\u0013`, + 0x14: `\u0014`, 0x15: `\u0015`, 0x16: `\u0016`, 0x17: `\u0017`, 0x18: `\u0018`, 0x19: `\u0019`, + 0x1a: `\u001a`, 0x1b: `\u001b`, 0x1c: `\u001c`, 0x1d: `\u001d`, 0x1e: `\u001e`, 0x1f: `\u001f`, +} + +var jsStrReplacementTable = []string{ + 0: `\u0000`, + '\t': `\t`, + '\n': `\n`, + '\v': `\u000b`, // "\v" == "v" on IE 6. + '\f': `\f`, + '\r': `\r`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. + '"': `\u0022`, + '`': `\u0060`, + '&': `\u0026`, + '\'': `\u0027`, + '+': `\u002b`, + '/': `\/`, + '<': `\u003c`, + '>': `\u003e`, + '\\': `\\`, +} + +// jsBqStrReplacementTable is like jsStrReplacementTable except it also contains +// the special characters for JS template literals: $, {, and }. +var jsBqStrReplacementTable = []string{ + 0: `\u0000`, + '\t': `\t`, + '\n': `\n`, + '\v': `\u000b`, // "\v" == "v" on IE 6. + '\f': `\f`, + '\r': `\r`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. + '"': `\u0022`, + '`': `\u0060`, + '&': `\u0026`, + '\'': `\u0027`, + '+': `\u002b`, + '/': `\/`, + '<': `\u003c`, + '>': `\u003e`, + '\\': `\\`, + '$': `\u0024`, + '{': `\u007b`, + '}': `\u007d`, +} + +// jsStrNormReplacementTable is like jsStrReplacementTable but does not +// overencode existing escapes since this table has no entry for `\`. +var jsStrNormReplacementTable = []string{ + 0: `\u0000`, + '\t': `\t`, + '\n': `\n`, + '\v': `\u000b`, // "\v" == "v" on IE 6. + '\f': `\f`, + '\r': `\r`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. + '"': `\u0022`, + '&': `\u0026`, + '\'': `\u0027`, + '`': `\u0060`, + '+': `\u002b`, + '/': `\/`, + '<': `\u003c`, + '>': `\u003e`, +} +var jsRegexpReplacementTable = []string{ + 0: `\u0000`, + '\t': `\t`, + '\n': `\n`, + '\v': `\u000b`, // "\v" == "v" on IE 6. + '\f': `\f`, + '\r': `\r`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. + '"': `\u0022`, + '$': `\$`, + '&': `\u0026`, + '\'': `\u0027`, + '(': `\(`, + ')': `\)`, + '*': `\*`, + '+': `\u002b`, + '-': `\-`, + '.': `\.`, + '/': `\/`, + '<': `\u003c`, + '>': `\u003e`, + '?': `\?`, + '[': `\[`, + '\\': `\\`, + ']': `\]`, + '^': `\^`, + '{': `\{`, + '|': `\|`, + '}': `\}`, +} + +// isJSIdentPart reports whether the given rune is a JS identifier part. +// It does not handle all the non-Latin letters, joiners, and combining marks, +// but it does handle every codepoint that can occur in a numeric literal or +// a keyword. +func isJSIdentPart(r rune) bool { + switch { + case r == '$': + return true + case '0' <= r && r <= '9': + return true + case 'A' <= r && r <= 'Z': + return true + case r == '_': + return true + case 'a' <= r && r <= 'z': + return true + } + return false +} + +// isJSType reports whether the given MIME type should be considered JavaScript. +// +// It is used to determine whether a script tag with a type attribute is a javascript container. +func isJSType(mimeType string) bool { + // per + // https://www.w3.org/TR/html5/scripting-1.html#attr-script-type + // https://tools.ietf.org/html/rfc7231#section-3.1.1 + // https://tools.ietf.org/html/rfc4329#section-3 + // https://www.ietf.org/rfc/rfc4627.txt + // discard parameters + mimeType, _, _ = strings.Cut(mimeType, ";") + mimeType = strings.ToLower(mimeType) + mimeType = strings.TrimSpace(mimeType) + switch mimeType { + case + "application/ecmascript", + "application/javascript", + "application/json", + "application/ld+json", + "application/x-ecmascript", + "application/x-javascript", + "module", + "text/ecmascript", + "text/javascript", + "text/javascript1.0", + "text/javascript1.1", + "text/javascript1.2", + "text/javascript1.3", + "text/javascript1.4", + "text/javascript1.5", + "text/jscript", + "text/livescript", + "text/x-ecmascript", + "text/x-javascript": + return true + default: + return false + } +} diff --git a/contrib/go/_std_1.22/src/html/template/jsctx_string.go b/contrib/go/_std_1.23/src/html/template/jsctx_string.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/jsctx_string.go rename to contrib/go/_std_1.23/src/html/template/jsctx_string.go diff --git a/contrib/go/_std_1.22/src/html/template/state_string.go b/contrib/go/_std_1.23/src/html/template/state_string.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/state_string.go rename to contrib/go/_std_1.23/src/html/template/state_string.go diff --git a/contrib/go/_std_1.23/src/html/template/template.go b/contrib/go/_std_1.23/src/html/template/template.go new file mode 100644 index 000000000000..2440fecbf9ea --- /dev/null +++ b/contrib/go/_std_1.23/src/html/template/template.go @@ -0,0 +1,530 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package template + +import ( + "fmt" + "io" + "io/fs" + "os" + "path" + "path/filepath" + "sync" + "text/template" + "text/template/parse" +) + +// Template is a specialized Template from "text/template" that produces a safe +// HTML document fragment. +type Template struct { + // Sticky error if escaping fails, or escapeOK if succeeded. + escapeErr error + // We could embed the text/template field, but it's safer not to because + // we need to keep our version of the name space and the underlying + // template's in sync. + text *template.Template + // The underlying template's parse tree, updated to be HTML-safe. + Tree *parse.Tree + *nameSpace // common to all associated templates +} + +// escapeOK is a sentinel value used to indicate valid escaping. +var escapeOK = fmt.Errorf("template escaped correctly") + +// nameSpace is the data structure shared by all templates in an association. +type nameSpace struct { + mu sync.Mutex + set map[string]*Template + escaped bool + esc escaper +} + +// Templates returns a slice of the templates associated with t, including t +// itself. +func (t *Template) Templates() []*Template { + ns := t.nameSpace + ns.mu.Lock() + defer ns.mu.Unlock() + // Return a slice so we don't expose the map. + m := make([]*Template, 0, len(ns.set)) + for _, v := range ns.set { + m = append(m, v) + } + return m +} + +// Option sets options for the template. Options are described by +// strings, either a simple string or "key=value". There can be at +// most one equals sign in an option string. If the option string +// is unrecognized or otherwise invalid, Option panics. +// +// Known options: +// +// missingkey: Control the behavior during execution if a map is +// indexed with a key that is not present in the map. +// +// "missingkey=default" or "missingkey=invalid" +// The default behavior: Do nothing and continue execution. +// If printed, the result of the index operation is the string +// "". +// "missingkey=zero" +// The operation returns the zero value for the map type's element. +// "missingkey=error" +// Execution stops immediately with an error. +func (t *Template) Option(opt ...string) *Template { + t.text.Option(opt...) + return t +} + +// checkCanParse checks whether it is OK to parse templates. +// If not, it returns an error. +func (t *Template) checkCanParse() error { + if t == nil { + return nil + } + t.nameSpace.mu.Lock() + defer t.nameSpace.mu.Unlock() + if t.nameSpace.escaped { + return fmt.Errorf("html/template: cannot Parse after Execute") + } + return nil +} + +// escape escapes all associated templates. +func (t *Template) escape() error { + t.nameSpace.mu.Lock() + defer t.nameSpace.mu.Unlock() + t.nameSpace.escaped = true + if t.escapeErr == nil { + if t.Tree == nil { + return fmt.Errorf("template: %q is an incomplete or empty template", t.Name()) + } + if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil { + return err + } + } else if t.escapeErr != escapeOK { + return t.escapeErr + } + return nil +} + +// Execute applies a parsed template to the specified data object, +// writing the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. +func (t *Template) Execute(wr io.Writer, data any) error { + if err := t.escape(); err != nil { + return err + } + return t.text.Execute(wr, data) +} + +// ExecuteTemplate applies the template associated with t that has the given +// name to the specified data object and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. +func (t *Template) ExecuteTemplate(wr io.Writer, name string, data any) error { + tmpl, err := t.lookupAndEscapeTemplate(name) + if err != nil { + return err + } + return tmpl.text.Execute(wr, data) +} + +// lookupAndEscapeTemplate guarantees that the template with the given name +// is escaped, or returns an error if it cannot be. It returns the named +// template. +func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) { + t.nameSpace.mu.Lock() + defer t.nameSpace.mu.Unlock() + t.nameSpace.escaped = true + tmpl = t.set[name] + if tmpl == nil { + return nil, fmt.Errorf("html/template: %q is undefined", name) + } + if tmpl.escapeErr != nil && tmpl.escapeErr != escapeOK { + return nil, tmpl.escapeErr + } + if tmpl.text.Tree == nil || tmpl.text.Root == nil { + return nil, fmt.Errorf("html/template: %q is an incomplete template", name) + } + if t.text.Lookup(name) == nil { + panic("html/template internal error: template escaping out of sync") + } + if tmpl.escapeErr == nil { + err = escapeTemplate(tmpl, tmpl.text.Root, name) + } + return tmpl, err +} + +// DefinedTemplates returns a string listing the defined templates, +// prefixed by the string "; defined templates are: ". If there are none, +// it returns the empty string. Used to generate an error message. +func (t *Template) DefinedTemplates() string { + return t.text.DefinedTemplates() +} + +// Parse parses text as a template body for t. +// Named template definitions ({{define ...}} or {{block ...}} statements) in text +// define additional templates associated with t and are removed from the +// definition of t itself. +// +// Templates can be redefined in successive calls to Parse, +// before the first use of [Template.Execute] on t or any associated template. +// A template definition with a body containing only white space and comments +// is considered empty and will not replace an existing template's body. +// This allows using Parse to add new named template definitions without +// overwriting the main template body. +func (t *Template) Parse(text string) (*Template, error) { + if err := t.checkCanParse(); err != nil { + return nil, err + } + + ret, err := t.text.Parse(text) + if err != nil { + return nil, err + } + + // In general, all the named templates might have changed underfoot. + // Regardless, some new ones may have been defined. + // The template.Template set has been updated; update ours. + t.nameSpace.mu.Lock() + defer t.nameSpace.mu.Unlock() + for _, v := range ret.Templates() { + name := v.Name() + tmpl := t.set[name] + if tmpl == nil { + tmpl = t.new(name) + } + tmpl.text = v + tmpl.Tree = v.Tree + } + return t, nil +} + +// AddParseTree creates a new template with the name and parse tree +// and associates it with t. +// +// It returns an error if t or any associated template has already been executed. +func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { + if err := t.checkCanParse(); err != nil { + return nil, err + } + + t.nameSpace.mu.Lock() + defer t.nameSpace.mu.Unlock() + text, err := t.text.AddParseTree(name, tree) + if err != nil { + return nil, err + } + ret := &Template{ + nil, + text, + text.Tree, + t.nameSpace, + } + t.set[name] = ret + return ret, nil +} + +// Clone returns a duplicate of the template, including all associated +// templates. The actual representation is not copied, but the name space of +// associated templates is, so further calls to [Template.Parse] in the copy will add +// templates to the copy but not to the original. [Template.Clone] can be used to prepare +// common templates and use them with variant definitions for other templates +// by adding the variants after the clone is made. +// +// It returns an error if t has already been executed. +func (t *Template) Clone() (*Template, error) { + t.nameSpace.mu.Lock() + defer t.nameSpace.mu.Unlock() + if t.escapeErr != nil { + return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) + } + textClone, err := t.text.Clone() + if err != nil { + return nil, err + } + ns := &nameSpace{set: make(map[string]*Template)} + ns.esc = makeEscaper(ns) + ret := &Template{ + nil, + textClone, + textClone.Tree, + ns, + } + ret.set[ret.Name()] = ret + for _, x := range textClone.Templates() { + name := x.Name() + src := t.set[name] + if src == nil || src.escapeErr != nil { + return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) + } + x.Tree = x.Tree.Copy() + ret.set[name] = &Template{ + nil, + x, + x.Tree, + ret.nameSpace, + } + } + // Return the template associated with the name of this template. + return ret.set[ret.Name()], nil +} + +// New allocates a new HTML template with the given name. +func New(name string) *Template { + ns := &nameSpace{set: make(map[string]*Template)} + ns.esc = makeEscaper(ns) + tmpl := &Template{ + nil, + template.New(name), + nil, + ns, + } + tmpl.set[name] = tmpl + return tmpl +} + +// New allocates a new HTML template associated with the given one +// and with the same delimiters. The association, which is transitive, +// allows one template to invoke another with a {{template}} action. +// +// If a template with the given name already exists, the new HTML template +// will replace it. The existing template will be reset and disassociated with +// t. +func (t *Template) New(name string) *Template { + t.nameSpace.mu.Lock() + defer t.nameSpace.mu.Unlock() + return t.new(name) +} + +// new is the implementation of New, without the lock. +func (t *Template) new(name string) *Template { + tmpl := &Template{ + nil, + t.text.New(name), + nil, + t.nameSpace, + } + if existing, ok := tmpl.set[name]; ok { + emptyTmpl := New(existing.Name()) + *existing = *emptyTmpl + } + tmpl.set[name] = tmpl + return tmpl +} + +// Name returns the name of the template. +func (t *Template) Name() string { + return t.text.Name() +} + +type FuncMap = template.FuncMap + +// Funcs adds the elements of the argument map to the template's function map. +// It must be called before the template is parsed. +// It panics if a value in the map is not a function with appropriate return +// type. However, it is legal to overwrite elements of the map. The return +// value is the template, so calls can be chained. +func (t *Template) Funcs(funcMap FuncMap) *Template { + t.text.Funcs(template.FuncMap(funcMap)) + return t +} + +// Delims sets the action delimiters to the specified strings, to be used in +// subsequent calls to [Template.Parse], [ParseFiles], or [ParseGlob]. Nested template +// definitions will inherit the settings. An empty delimiter stands for the +// corresponding default: {{ or }}. +// The return value is the template, so calls can be chained. +func (t *Template) Delims(left, right string) *Template { + t.text.Delims(left, right) + return t +} + +// Lookup returns the template with the given name that is associated with t, +// or nil if there is no such template. +func (t *Template) Lookup(name string) *Template { + t.nameSpace.mu.Lock() + defer t.nameSpace.mu.Unlock() + return t.set[name] +} + +// Must is a helper that wraps a call to a function returning ([*Template], error) +// and panics if the error is non-nil. It is intended for use in variable initializations +// such as +// +// var t = template.Must(template.New("name").Parse("html")) +func Must(t *Template, err error) *Template { + if err != nil { + panic(err) + } + return t +} + +// ParseFiles creates a new [Template] and parses the template definitions from +// the named files. The returned template's name will have the (base) name and +// (parsed) contents of the first file. There must be at least one file. +// If an error occurs, parsing stops and the returned [*Template] is nil. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template +// named "foo", while "a/foo" is unavailable. +func ParseFiles(filenames ...string) (*Template, error) { + return parseFiles(nil, readFileOS, filenames...) +} + +// ParseFiles parses the named files and associates the resulting templates with +// t. If an error occurs, parsing stops and the returned template is nil; +// otherwise it is t. There must be at least one file. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +// +// ParseFiles returns an error if t or any associated template has already been executed. +func (t *Template) ParseFiles(filenames ...string) (*Template, error) { + return parseFiles(t, readFileOS, filenames...) +} + +// parseFiles is the helper for the method and function. If the argument +// template is nil, it is created from the first file. +func parseFiles(t *Template, readFile func(string) (string, []byte, error), filenames ...string) (*Template, error) { + if err := t.checkCanParse(); err != nil { + return nil, err + } + + if len(filenames) == 0 { + // Not really a problem, but be consistent. + return nil, fmt.Errorf("html/template: no files named in call to ParseFiles") + } + for _, filename := range filenames { + name, b, err := readFile(filename) + if err != nil { + return nil, err + } + s := string(b) + // First template becomes return value if not already defined, + // and we use that one for subsequent New calls to associate + // all the templates together. Also, if this file has the same name + // as t, this file becomes the contents of t, so + // t, err := New(name).Funcs(xxx).ParseFiles(name) + // works. Otherwise we create a new template associated with t. + var tmpl *Template + if t == nil { + t = New(name) + } + if name == t.Name() { + tmpl = t + } else { + tmpl = t.New(name) + } + _, err = tmpl.Parse(s) + if err != nil { + return nil, err + } + } + return t, nil +} + +// ParseGlob creates a new [Template] and parses the template definitions from +// the files identified by the pattern. The files are matched according to the +// semantics of filepath.Match, and the pattern must match at least one file. +// The returned template will have the (base) name and (parsed) contents of the +// first file matched by the pattern. ParseGlob is equivalent to calling +// [ParseFiles] with the list of files matched by the pattern. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +func ParseGlob(pattern string) (*Template, error) { + return parseGlob(nil, pattern) +} + +// ParseGlob parses the template definitions in the files identified by the +// pattern and associates the resulting templates with t. The files are matched +// according to the semantics of filepath.Match, and the pattern must match at +// least one file. ParseGlob is equivalent to calling t.ParseFiles with the +// list of files matched by the pattern. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +// +// ParseGlob returns an error if t or any associated template has already been executed. +func (t *Template) ParseGlob(pattern string) (*Template, error) { + return parseGlob(t, pattern) +} + +// parseGlob is the implementation of the function and method ParseGlob. +func parseGlob(t *Template, pattern string) (*Template, error) { + if err := t.checkCanParse(); err != nil { + return nil, err + } + filenames, err := filepath.Glob(pattern) + if err != nil { + return nil, err + } + if len(filenames) == 0 { + return nil, fmt.Errorf("html/template: pattern matches no files: %#q", pattern) + } + return parseFiles(t, readFileOS, filenames...) +} + +// IsTrue reports whether the value is 'true', in the sense of not the zero of its type, +// and whether the value has a meaningful truth value. This is the definition of +// truth used by if and other such actions. +func IsTrue(val any) (truth, ok bool) { + return template.IsTrue(val) +} + +// ParseFS is like [ParseFiles] or [ParseGlob] but reads from the file system fs +// instead of the host operating system's file system. +// It accepts a list of glob patterns. +// (Note that most file names serve as glob patterns matching only themselves.) +func ParseFS(fs fs.FS, patterns ...string) (*Template, error) { + return parseFS(nil, fs, patterns) +} + +// ParseFS is like [Template.ParseFiles] or [Template.ParseGlob] but reads from the file system fs +// instead of the host operating system's file system. +// It accepts a list of glob patterns. +// (Note that most file names serve as glob patterns matching only themselves.) +func (t *Template) ParseFS(fs fs.FS, patterns ...string) (*Template, error) { + return parseFS(t, fs, patterns) +} + +func parseFS(t *Template, fsys fs.FS, patterns []string) (*Template, error) { + var filenames []string + for _, pattern := range patterns { + list, err := fs.Glob(fsys, pattern) + if err != nil { + return nil, err + } + if len(list) == 0 { + return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) + } + filenames = append(filenames, list...) + } + return parseFiles(t, readFileFS(fsys), filenames...) +} + +func readFileOS(file string) (name string, b []byte, err error) { + name = filepath.Base(file) + b, err = os.ReadFile(file) + return +} + +func readFileFS(fsys fs.FS) func(string) (string, []byte, error) { + return func(file string) (name string, b []byte, err error) { + name = path.Base(file) + b, err = fs.ReadFile(fsys, file) + return + } +} diff --git a/contrib/go/_std_1.22/src/html/template/transition.go b/contrib/go/_std_1.23/src/html/template/transition.go similarity index 99% rename from contrib/go/_std_1.22/src/html/template/transition.go rename to contrib/go/_std_1.23/src/html/template/transition.go index d5a05f66da40..c430389a345f 100644 --- a/contrib/go/_std_1.22/src/html/template/transition.go +++ b/contrib/go/_std_1.23/src/html/template/transition.go @@ -414,7 +414,7 @@ func tJSDelimited(c context, s []byte) (context, int) { // If " 0 && i+7 <= len(s) && bytes.Compare(bytes.ToLower(s[i-1:i+7]), []byte(" 0 && i+7 <= len(s) && bytes.Equal(bytes.ToLower(s[i-1:i+7]), []byte("func lookup table diff --git a/contrib/go/_std_1.23/src/internal/abi/type.go b/contrib/go/_std_1.23/src/internal/abi/type.go new file mode 100644 index 000000000000..b8eefe0da8db --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/abi/type.go @@ -0,0 +1,803 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package abi + +import ( + "unsafe" +) + +// Type is the runtime representation of a Go type. +// +// Be careful about accessing this type at build time, as the version +// of this type in the compiler/linker may not have the same layout +// as the version in the target binary, due to pointer width +// differences and any experiments. Use cmd/compile/internal/rttype +// or the functions in compiletype.go to access this type instead. +// (TODO: this admonition applies to every type in this package. +// Put it in some shared location?) +type Type struct { + Size_ uintptr + PtrBytes uintptr // number of (prefix) bytes in the type that can contain pointers + Hash uint32 // hash of type; avoids computation in hash tables + TFlag TFlag // extra type information flags + Align_ uint8 // alignment of variable with this type + FieldAlign_ uint8 // alignment of struct field with this type + Kind_ Kind // enumeration for C + // function for comparing objects of this type + // (ptr to object A, ptr to object B) -> ==? + Equal func(unsafe.Pointer, unsafe.Pointer) bool + // GCData stores the GC type data for the garbage collector. + // If the KindGCProg bit is set in kind, GCData is a GC program. + // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. + GCData *byte + Str NameOff // string form + PtrToThis TypeOff // type for pointer to this type, may be zero +} + +// A Kind represents the specific kind of type that a Type represents. +// The zero Kind is not a valid kind. +type Kind uint8 + +const ( + Invalid Kind = iota + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + Array + Chan + Func + Interface + Map + Pointer + Slice + String + Struct + UnsafePointer +) + +const ( + // TODO (khr, drchase) why aren't these in TFlag? Investigate, fix if possible. + KindDirectIface Kind = 1 << 5 + KindGCProg Kind = 1 << 6 // Type.gc points to GC program + KindMask Kind = (1 << 5) - 1 +) + +// TFlag is used by a Type to signal what extra type information is +// available in the memory directly following the Type value. +type TFlag uint8 + +const ( + // TFlagUncommon means that there is a data with a type, UncommonType, + // just beyond the shared-per-type common data. That is, the data + // for struct types will store their UncommonType at one offset, the + // data for interface types will store their UncommonType at a different + // offset. UncommonType is always accessed via a pointer that is computed + // using trust-us-we-are-the-implementors pointer arithmetic. + // + // For example, if t.Kind() == Struct and t.tflag&TFlagUncommon != 0, + // then t has UncommonType data and it can be accessed as: + // + // type structTypeUncommon struct { + // structType + // u UncommonType + // } + // u := &(*structTypeUncommon)(unsafe.Pointer(t)).u + TFlagUncommon TFlag = 1 << 0 + + // TFlagExtraStar means the name in the str field has an + // extraneous '*' prefix. This is because for most types T in + // a program, the type *T also exists and reusing the str data + // saves binary size. + TFlagExtraStar TFlag = 1 << 1 + + // TFlagNamed means the type has a name. + TFlagNamed TFlag = 1 << 2 + + // TFlagRegularMemory means that equal and hash functions can treat + // this type as a single region of t.size bytes. + TFlagRegularMemory TFlag = 1 << 3 + + // TFlagUnrolledBitmap marks special types that are unrolled-bitmap + // versions of types with GC programs. + // These types need to be deallocated when the underlying object + // is freed. + TFlagUnrolledBitmap TFlag = 1 << 4 +) + +// NameOff is the offset to a name from moduledata.types. See resolveNameOff in runtime. +type NameOff int32 + +// TypeOff is the offset to a type from moduledata.types. See resolveTypeOff in runtime. +type TypeOff int32 + +// TextOff is an offset from the top of a text section. See (rtype).textOff in runtime. +type TextOff int32 + +// String returns the name of k. +func (k Kind) String() string { + if int(k) < len(kindNames) { + return kindNames[k] + } + return kindNames[0] +} + +var kindNames = []string{ + Invalid: "invalid", + Bool: "bool", + Int: "int", + Int8: "int8", + Int16: "int16", + Int32: "int32", + Int64: "int64", + Uint: "uint", + Uint8: "uint8", + Uint16: "uint16", + Uint32: "uint32", + Uint64: "uint64", + Uintptr: "uintptr", + Float32: "float32", + Float64: "float64", + Complex64: "complex64", + Complex128: "complex128", + Array: "array", + Chan: "chan", + Func: "func", + Interface: "interface", + Map: "map", + Pointer: "ptr", + Slice: "slice", + String: "string", + Struct: "struct", + UnsafePointer: "unsafe.Pointer", +} + +// TypeOf returns the abi.Type of some value. +func TypeOf(a any) *Type { + eface := *(*EmptyInterface)(unsafe.Pointer(&a)) + // Types are either static (for compiler-created types) or + // heap-allocated but always reachable (for reflection-created + // types, held in the central map). So there is no need to + // escape types. noescape here help avoid unnecessary escape + // of v. + return (*Type)(NoEscape(unsafe.Pointer(eface.Type))) +} + +// TypeFor returns the abi.Type for a type parameter. +func TypeFor[T any]() *Type { + var v T + if t := TypeOf(v); t != nil { + return t // optimize for T being a non-interface kind + } + return TypeOf((*T)(nil)).Elem() // only for an interface kind +} + +func (t *Type) Kind() Kind { return t.Kind_ & KindMask } + +func (t *Type) HasName() bool { + return t.TFlag&TFlagNamed != 0 +} + +// Pointers reports whether t contains pointers. +func (t *Type) Pointers() bool { return t.PtrBytes != 0 } + +// IfaceIndir reports whether t is stored indirectly in an interface value. +func (t *Type) IfaceIndir() bool { + return t.Kind_&KindDirectIface == 0 +} + +// isDirectIface reports whether t is stored directly in an interface value. +func (t *Type) IsDirectIface() bool { + return t.Kind_&KindDirectIface != 0 +} + +func (t *Type) GcSlice(begin, end uintptr) []byte { + return unsafe.Slice(t.GCData, int(end))[begin:] +} + +// Method on non-interface type +type Method struct { + Name NameOff // name of method + Mtyp TypeOff // method type (without receiver) + Ifn TextOff // fn used in interface call (one-word receiver) + Tfn TextOff // fn used for normal method call +} + +// UncommonType is present only for defined types or types with methods +// (if T is a defined type, the uncommonTypes for T and *T have methods). +// Using a pointer to this struct reduces the overall size required +// to describe a non-defined type with no methods. +type UncommonType struct { + PkgPath NameOff // import path; empty for built-in types like int, string + Mcount uint16 // number of methods + Xcount uint16 // number of exported methods + Moff uint32 // offset from this uncommontype to [mcount]Method + _ uint32 // unused +} + +func (t *UncommonType) Methods() []Method { + if t.Mcount == 0 { + return nil + } + return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.mcount > 0"))[:t.Mcount:t.Mcount] +} + +func (t *UncommonType) ExportedMethods() []Method { + if t.Xcount == 0 { + return nil + } + return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.xcount > 0"))[:t.Xcount:t.Xcount] +} + +// addChecked returns p+x. +// +// The whySafe string is ignored, so that the function still inlines +// as efficiently as p+x, but all call sites should use the string to +// record why the addition is safe, which is to say why the addition +// does not cause x to advance to the very end of p's allocation +// and therefore point incorrectly at the next block in memory. +func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { + return unsafe.Pointer(uintptr(p) + x) +} + +// Imethod represents a method on an interface type +type Imethod struct { + Name NameOff // name of method + Typ TypeOff // .(*FuncType) underneath +} + +// ArrayType represents a fixed array type. +type ArrayType struct { + Type + Elem *Type // array element type + Slice *Type // slice type + Len uintptr +} + +// Len returns the length of t if t is an array type, otherwise 0 +func (t *Type) Len() int { + if t.Kind() == Array { + return int((*ArrayType)(unsafe.Pointer(t)).Len) + } + return 0 +} + +func (t *Type) Common() *Type { + return t +} + +type ChanDir int + +const ( + RecvDir ChanDir = 1 << iota // <-chan + SendDir // chan<- + BothDir = RecvDir | SendDir // chan + InvalidDir ChanDir = 0 +) + +// ChanType represents a channel type +type ChanType struct { + Type + Elem *Type + Dir ChanDir +} + +type structTypeUncommon struct { + StructType + u UncommonType +} + +// ChanDir returns the direction of t if t is a channel type, otherwise InvalidDir (0). +func (t *Type) ChanDir() ChanDir { + if t.Kind() == Chan { + ch := (*ChanType)(unsafe.Pointer(t)) + return ch.Dir + } + return InvalidDir +} + +// Uncommon returns a pointer to T's "uncommon" data if there is any, otherwise nil +func (t *Type) Uncommon() *UncommonType { + if t.TFlag&TFlagUncommon == 0 { + return nil + } + switch t.Kind() { + case Struct: + return &(*structTypeUncommon)(unsafe.Pointer(t)).u + case Pointer: + type u struct { + PtrType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Func: + type u struct { + FuncType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Slice: + type u struct { + SliceType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Array: + type u struct { + ArrayType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Chan: + type u struct { + ChanType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Map: + type u struct { + MapType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Interface: + type u struct { + InterfaceType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + default: + type u struct { + Type + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + } +} + +// Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil. +func (t *Type) Elem() *Type { + switch t.Kind() { + case Array: + tt := (*ArrayType)(unsafe.Pointer(t)) + return tt.Elem + case Chan: + tt := (*ChanType)(unsafe.Pointer(t)) + return tt.Elem + case Map: + tt := (*MapType)(unsafe.Pointer(t)) + return tt.Elem + case Pointer: + tt := (*PtrType)(unsafe.Pointer(t)) + return tt.Elem + case Slice: + tt := (*SliceType)(unsafe.Pointer(t)) + return tt.Elem + } + return nil +} + +// StructType returns t cast to a *StructType, or nil if its tag does not match. +func (t *Type) StructType() *StructType { + if t.Kind() != Struct { + return nil + } + return (*StructType)(unsafe.Pointer(t)) +} + +// MapType returns t cast to a *MapType, or nil if its tag does not match. +func (t *Type) MapType() *MapType { + if t.Kind() != Map { + return nil + } + return (*MapType)(unsafe.Pointer(t)) +} + +// ArrayType returns t cast to a *ArrayType, or nil if its tag does not match. +func (t *Type) ArrayType() *ArrayType { + if t.Kind() != Array { + return nil + } + return (*ArrayType)(unsafe.Pointer(t)) +} + +// FuncType returns t cast to a *FuncType, or nil if its tag does not match. +func (t *Type) FuncType() *FuncType { + if t.Kind() != Func { + return nil + } + return (*FuncType)(unsafe.Pointer(t)) +} + +// InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match. +func (t *Type) InterfaceType() *InterfaceType { + if t.Kind() != Interface { + return nil + } + return (*InterfaceType)(unsafe.Pointer(t)) +} + +// Size returns the size of data with type t. +func (t *Type) Size() uintptr { return t.Size_ } + +// Align returns the alignment of data with type t. +func (t *Type) Align() int { return int(t.Align_) } + +func (t *Type) FieldAlign() int { return int(t.FieldAlign_) } + +type InterfaceType struct { + Type + PkgPath Name // import path + Methods []Imethod // sorted by hash +} + +func (t *Type) ExportedMethods() []Method { + ut := t.Uncommon() + if ut == nil { + return nil + } + return ut.ExportedMethods() +} + +func (t *Type) NumMethod() int { + if t.Kind() == Interface { + tt := (*InterfaceType)(unsafe.Pointer(t)) + return tt.NumMethod() + } + return len(t.ExportedMethods()) +} + +// NumMethod returns the number of interface methods in the type's method set. +func (t *InterfaceType) NumMethod() int { return len(t.Methods) } + +type MapType struct { + Type + Key *Type + Elem *Type + Bucket *Type // internal type representing a hash bucket + // function for hashing keys (ptr to key, seed) -> hash + Hasher func(unsafe.Pointer, uintptr) uintptr + KeySize uint8 // size of key slot + ValueSize uint8 // size of elem slot + BucketSize uint16 // size of bucket + Flags uint32 +} + +// Note: flag values must match those used in the TMAP case +// in ../cmd/compile/internal/reflectdata/reflect.go:writeType. +func (mt *MapType) IndirectKey() bool { // store ptr to key instead of key itself + return mt.Flags&1 != 0 +} +func (mt *MapType) IndirectElem() bool { // store ptr to elem instead of elem itself + return mt.Flags&2 != 0 +} +func (mt *MapType) ReflexiveKey() bool { // true if k==k for all keys + return mt.Flags&4 != 0 +} +func (mt *MapType) NeedKeyUpdate() bool { // true if we need to update key on an overwrite + return mt.Flags&8 != 0 +} +func (mt *MapType) HashMightPanic() bool { // true if hash function might panic + return mt.Flags&16 != 0 +} + +func (t *Type) Key() *Type { + if t.Kind() == Map { + return (*MapType)(unsafe.Pointer(t)).Key + } + return nil +} + +type SliceType struct { + Type + Elem *Type // slice element type +} + +// funcType represents a function type. +// +// A *Type for each in and out parameter is stored in an array that +// directly follows the funcType (and possibly its uncommonType). So +// a function type with one method, one input, and one output is: +// +// struct { +// funcType +// uncommonType +// [2]*rtype // [0] is in, [1] is out +// } +type FuncType struct { + Type + InCount uint16 + OutCount uint16 // top bit is set if last input parameter is ... +} + +func (t *FuncType) In(i int) *Type { + return t.InSlice()[i] +} + +func (t *FuncType) NumIn() int { + return int(t.InCount) +} + +func (t *FuncType) NumOut() int { + return int(t.OutCount & (1<<15 - 1)) +} + +func (t *FuncType) Out(i int) *Type { + return (t.OutSlice()[i]) +} + +func (t *FuncType) InSlice() []*Type { + uadd := unsafe.Sizeof(*t) + if t.TFlag&TFlagUncommon != 0 { + uadd += unsafe.Sizeof(UncommonType{}) + } + if t.InCount == 0 { + return nil + } + return (*[1 << 16]*Type)(addChecked(unsafe.Pointer(t), uadd, "t.inCount > 0"))[:t.InCount:t.InCount] +} +func (t *FuncType) OutSlice() []*Type { + outCount := uint16(t.NumOut()) + if outCount == 0 { + return nil + } + uadd := unsafe.Sizeof(*t) + if t.TFlag&TFlagUncommon != 0 { + uadd += unsafe.Sizeof(UncommonType{}) + } + return (*[1 << 17]*Type)(addChecked(unsafe.Pointer(t), uadd, "outCount > 0"))[t.InCount : t.InCount+outCount : t.InCount+outCount] +} + +func (t *FuncType) IsVariadic() bool { + return t.OutCount&(1<<15) != 0 +} + +type PtrType struct { + Type + Elem *Type // pointer element (pointed at) type +} + +type StructField struct { + Name Name // name is always non-empty + Typ *Type // type of field + Offset uintptr // byte offset of field +} + +func (f *StructField) Embedded() bool { + return f.Name.IsEmbedded() +} + +type StructType struct { + Type + PkgPath Name + Fields []StructField +} + +// Name is an encoded type Name with optional extra data. +// +// The first byte is a bit field containing: +// +// 1<<0 the name is exported +// 1<<1 tag data follows the name +// 1<<2 pkgPath nameOff follows the name and tag +// 1<<3 the name is of an embedded (a.k.a. anonymous) field +// +// Following that, there is a varint-encoded length of the name, +// followed by the name itself. +// +// If tag data is present, it also has a varint-encoded length +// followed by the tag itself. +// +// If the import path follows, then 4 bytes at the end of +// the data form a nameOff. The import path is only set for concrete +// methods that are defined in a different package than their type. +// +// If a name starts with "*", then the exported bit represents +// whether the pointed to type is exported. +// +// Note: this encoding must match here and in: +// cmd/compile/internal/reflectdata/reflect.go +// cmd/link/internal/ld/decodesym.go + +type Name struct { + Bytes *byte +} + +// DataChecked does pointer arithmetic on n's Bytes, and that arithmetic is asserted to +// be safe for the reason in whySafe (which can appear in a backtrace, etc.) +func (n Name) DataChecked(off int, whySafe string) *byte { + return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), whySafe)) +} + +// Data does pointer arithmetic on n's Bytes, and that arithmetic is asserted to +// be safe because the runtime made the call (other packages use DataChecked) +func (n Name) Data(off int) *byte { + return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), "the runtime doesn't need to give you a reason")) +} + +// IsExported returns "is n exported?" +func (n Name) IsExported() bool { + return (*n.Bytes)&(1<<0) != 0 +} + +// HasTag returns true iff there is tag data following this name +func (n Name) HasTag() bool { + return (*n.Bytes)&(1<<1) != 0 +} + +// IsEmbedded returns true iff n is embedded (an anonymous field). +func (n Name) IsEmbedded() bool { + return (*n.Bytes)&(1<<3) != 0 +} + +// ReadVarint parses a varint as encoded by encoding/binary. +// It returns the number of encoded bytes and the encoded value. +func (n Name) ReadVarint(off int) (int, int) { + v := 0 + for i := 0; ; i++ { + x := *n.DataChecked(off+i, "read varint") + v += int(x&0x7f) << (7 * i) + if x&0x80 == 0 { + return i + 1, v + } + } +} + +// IsBlank indicates whether n is "_". +func (n Name) IsBlank() bool { + if n.Bytes == nil { + return false + } + _, l := n.ReadVarint(1) + return l == 1 && *n.Data(2) == '_' +} + +// writeVarint writes n to buf in varint form. Returns the +// number of bytes written. n must be nonnegative. +// Writes at most 10 bytes. +func writeVarint(buf []byte, n int) int { + for i := 0; ; i++ { + b := byte(n & 0x7f) + n >>= 7 + if n == 0 { + buf[i] = b + return i + 1 + } + buf[i] = b | 0x80 + } +} + +// Name returns the tag string for n, or empty if there is none. +func (n Name) Name() string { + if n.Bytes == nil { + return "" + } + i, l := n.ReadVarint(1) + return unsafe.String(n.DataChecked(1+i, "non-empty string"), l) +} + +// Tag returns the tag string for n, or empty if there is none. +func (n Name) Tag() string { + if !n.HasTag() { + return "" + } + i, l := n.ReadVarint(1) + i2, l2 := n.ReadVarint(1 + i + l) + return unsafe.String(n.DataChecked(1+i+l+i2, "non-empty string"), l2) +} + +func NewName(n, tag string, exported, embedded bool) Name { + if len(n) >= 1<<29 { + panic("abi.NewName: name too long: " + n[:1024] + "...") + } + if len(tag) >= 1<<29 { + panic("abi.NewName: tag too long: " + tag[:1024] + "...") + } + var nameLen [10]byte + var tagLen [10]byte + nameLenLen := writeVarint(nameLen[:], len(n)) + tagLenLen := writeVarint(tagLen[:], len(tag)) + + var bits byte + l := 1 + nameLenLen + len(n) + if exported { + bits |= 1 << 0 + } + if len(tag) > 0 { + l += tagLenLen + len(tag) + bits |= 1 << 1 + } + if embedded { + bits |= 1 << 3 + } + + b := make([]byte, l) + b[0] = bits + copy(b[1:], nameLen[:nameLenLen]) + copy(b[1+nameLenLen:], n) + if len(tag) > 0 { + tb := b[1+nameLenLen+len(n):] + copy(tb, tagLen[:tagLenLen]) + copy(tb[tagLenLen:], tag) + } + + return Name{Bytes: &b[0]} +} + +const ( + TraceArgsLimit = 10 // print no more than 10 args/components + TraceArgsMaxDepth = 5 // no more than 5 layers of nesting + + // maxLen is a (conservative) upper bound of the byte stream length. For + // each arg/component, it has no more than 2 bytes of data (size, offset), + // and no more than one {, }, ... at each level (it cannot have both the + // data and ... unless it is the last one, just be conservative). Plus 1 + // for _endSeq. + TraceArgsMaxLen = (TraceArgsMaxDepth*3+2)*TraceArgsLimit + 1 +) + +// Populate the data. +// The data is a stream of bytes, which contains the offsets and sizes of the +// non-aggregate arguments or non-aggregate fields/elements of aggregate-typed +// arguments, along with special "operators". Specifically, +// - for each non-aggregate arg/field/element, its offset from FP (1 byte) and +// size (1 byte) +// - special operators: +// - 0xff - end of sequence +// - 0xfe - print { (at the start of an aggregate-typed argument) +// - 0xfd - print } (at the end of an aggregate-typed argument) +// - 0xfc - print ... (more args/fields/elements) +// - 0xfb - print _ (offset too large) +const ( + TraceArgsEndSeq = 0xff + TraceArgsStartAgg = 0xfe + TraceArgsEndAgg = 0xfd + TraceArgsDotdotdot = 0xfc + TraceArgsOffsetTooLarge = 0xfb + TraceArgsSpecial = 0xf0 // above this are operators, below this are ordinary offsets +) + +// MaxPtrmaskBytes is the maximum length of a GC ptrmask bitmap, +// which holds 1-bit entries describing where pointers are in a given type. +// Above this length, the GC information is recorded as a GC program, +// which can express repetition compactly. In either form, the +// information is used by the runtime to initialize the heap bitmap, +// and for large types (like 128 or more words), they are roughly the +// same speed. GC programs are never much larger and often more +// compact. (If large arrays are involved, they can be arbitrarily +// more compact.) +// +// The cutoff must be large enough that any allocation large enough to +// use a GC program is large enough that it does not share heap bitmap +// bytes with any other objects, allowing the GC program execution to +// assume an aligned start and not use atomic operations. In the current +// runtime, this means all malloc size classes larger than the cutoff must +// be multiples of four words. On 32-bit systems that's 16 bytes, and +// all size classes >= 16 bytes are 16-byte aligned, so no real constraint. +// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed +// for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated +// is 32 pointers, the bits for which fit in 4 bytes. So MaxPtrmaskBytes +// must be >= 4. +// +// We used to use 16 because the GC programs do have some constant overhead +// to get started, and processing 128 pointers seems to be enough to +// amortize that overhead well. +// +// To make sure that the runtime's chansend can call typeBitsBulkBarrier, +// we raised the limit to 2048, so that even 32-bit systems are guaranteed to +// use bitmaps for objects up to 64 kB in size. +const MaxPtrmaskBytes = 2048 diff --git a/contrib/go/_std_1.23/src/internal/abi/ya.make b/contrib/go/_std_1.23/src/internal/abi/ya.make new file mode 100644 index 000000000000..0589a13c3997 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/abi/ya.make @@ -0,0 +1,57 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + abi.go + abi_arm64.go + abi_test.s + compiletype.go + escape.go + funcpc.go + iface.go + map.go + rangefuncconsts.go + runtime.go + stack.go + stub.s + switch.go + symtab.go + type.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + abi.go + abi_amd64.go + abi_test.s + compiletype.go + escape.go + funcpc.go + iface.go + map.go + rangefuncconsts.go + runtime.go + stack.go + stub.s + switch.go + symtab.go + type.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + abi.go + abi_generic.go + abi_test.s + compiletype.go + escape.go + funcpc.go + iface.go + map.go + rangefuncconsts.go + runtime.go + stack.go + stub.s + switch.go + symtab.go + type.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/asan/asan.go b/contrib/go/_std_1.23/src/internal/asan/asan.go new file mode 100644 index 000000000000..56814ebfb244 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/asan/asan.go @@ -0,0 +1,19 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build asan + +package asan + +import ( + "unsafe" +) + +const Enabled = true + +//go:linkname Read runtime.asanread +func Read(addr unsafe.Pointer, len uintptr) + +//go:linkname Write runtime.asanwrite +func Write(addr unsafe.Pointer, len uintptr) diff --git a/contrib/go/_std_1.23/src/internal/asan/doc.go b/contrib/go/_std_1.23/src/internal/asan/doc.go new file mode 100644 index 000000000000..21b1bc945b31 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/asan/doc.go @@ -0,0 +1,10 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package asan contains helper functions for manually instrumenting +// code for the address sanitizer. +// The runtime package intentionally exports these functions only in the +// asan build; this package exports them unconditionally but without the +// "asan" build tag they are no-ops. +package asan diff --git a/contrib/go/_std_1.23/src/internal/asan/noasan.go b/contrib/go/_std_1.23/src/internal/asan/noasan.go new file mode 100644 index 000000000000..c510d351460e --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/asan/noasan.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !asan + +package asan + +import ( + "unsafe" +) + +const Enabled = false + +func Read(addr unsafe.Pointer, len uintptr) {} + +func Write(addr unsafe.Pointer, len uintptr) {} diff --git a/contrib/go/_std_1.23/src/internal/asan/ya.make b/contrib/go/_std_1.23/src/internal/asan/ya.make new file mode 100644 index 000000000000..da4a42a32fde --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/asan/ya.make @@ -0,0 +1,8 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + doc.go + noasan.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/bisect/bisect.go b/contrib/go/_std_1.23/src/internal/bisect/bisect.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/bisect/bisect.go rename to contrib/go/_std_1.23/src/internal/bisect/bisect.go index 3e5a6849f7e3..a79bb8000daa 100644 --- a/contrib/go/_std_1.22/src/internal/bisect/bisect.go +++ b/contrib/go/_std_1.23/src/internal/bisect/bisect.go @@ -180,7 +180,6 @@ import ( "runtime" "sync" "sync/atomic" - "unsafe" ) // New creates and returns a new Matcher implementing the given pattern. @@ -311,22 +310,7 @@ type Matcher struct { quiet bool // disables all reporting. reset if verbose is true. use case is -d=fmahash=qn enable bool // when true, list is for “enable and report” (when false, “disable and report”) list []cond // conditions; later ones win over earlier ones - dedup atomicPointerDedup -} - -// atomicPointerDedup is an atomic.Pointer[dedup], -// but we are avoiding using Go 1.19's atomic.Pointer -// until the bootstrap toolchain can be relied upon to have it. -type atomicPointerDedup struct { - p unsafe.Pointer -} - -func (p *atomicPointerDedup) Load() *dedup { - return (*dedup)(atomic.LoadPointer(&p.p)) -} - -func (p *atomicPointerDedup) CompareAndSwap(old, new *dedup) bool { - return atomic.CompareAndSwapPointer(&p.p, unsafe.Pointer(old), unsafe.Pointer(new)) + dedup atomic.Pointer[dedup] } // A cond is a single condition in the matcher. @@ -512,7 +496,7 @@ func printStack(w Writer, h uint64, stk []uintptr) error { for { f, more := frames.Next() buf = append(buf, prefix...) - buf = append(buf, f.Func.Name()...) + buf = append(buf, f.Function...) buf = append(buf, "()\n"...) buf = append(buf, prefix...) buf = append(buf, '\t') diff --git a/contrib/go/_std_1.22/src/internal/bisect/ya.make b/contrib/go/_std_1.23/src/internal/bisect/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/bisect/ya.make rename to contrib/go/_std_1.23/src/internal/bisect/ya.make diff --git a/contrib/go/_std_1.23/src/internal/buildcfg/cfg.go b/contrib/go/_std_1.23/src/internal/buildcfg/cfg.go new file mode 100644 index 000000000000..a16e76b30558 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/buildcfg/cfg.go @@ -0,0 +1,414 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package buildcfg provides access to the build configuration +// described by the current environment. It is for use by build tools +// such as cmd/go or cmd/compile and for setting up go/build's Default context. +// +// Note that it does NOT provide access to the build configuration used to +// build the currently-running binary. For that, use runtime.GOOS etc +// as well as internal/goexperiment. +package buildcfg + +import ( + "fmt" + "os" + "path/filepath" + "strconv" + "strings" +) + +var ( + GOROOT = os.Getenv("GOROOT") // cached for efficiency + GOARCH = envOr("GOARCH", defaultGOARCH) + GOOS = envOr("GOOS", defaultGOOS) + GO386 = envOr("GO386", defaultGO386) + GOAMD64 = goamd64() + GOARM = goarm() + GOARM64 = goarm64() + GOMIPS = gomips() + GOMIPS64 = gomips64() + GOPPC64 = goppc64() + GORISCV64 = goriscv64() + GOWASM = gowasm() + ToolTags = toolTags() + GO_LDSO = defaultGO_LDSO + Version = version +) + +// Error is one of the errors found (if any) in the build configuration. +var Error error + +// Check exits the program with a fatal error if Error is non-nil. +func Check() { + if Error != nil { + fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), Error) + os.Exit(2) + } +} + +func envOr(key, value string) string { + if x := os.Getenv(key); x != "" { + return x + } + return value +} + +func goamd64() int { + switch v := envOr("GOAMD64", defaultGOAMD64); v { + case "v1": + return 1 + case "v2": + return 2 + case "v3": + return 3 + case "v4": + return 4 + } + Error = fmt.Errorf("invalid GOAMD64: must be v1, v2, v3, v4") + return int(defaultGOAMD64[len("v")] - '0') +} + +type goarmFeatures struct { + Version int + SoftFloat bool +} + +func (g goarmFeatures) String() string { + armStr := strconv.Itoa(g.Version) + if g.SoftFloat { + armStr += ",softfloat" + } else { + armStr += ",hardfloat" + } + return armStr +} + +func goarm() (g goarmFeatures) { + const ( + softFloatOpt = ",softfloat" + hardFloatOpt = ",hardfloat" + ) + def := defaultGOARM + if GOOS == "android" && GOARCH == "arm" { + // Android arm devices always support GOARM=7. + def = "7" + } + v := envOr("GOARM", def) + + floatSpecified := false + if strings.HasSuffix(v, softFloatOpt) { + g.SoftFloat = true + floatSpecified = true + v = v[:len(v)-len(softFloatOpt)] + } + if strings.HasSuffix(v, hardFloatOpt) { + floatSpecified = true + v = v[:len(v)-len(hardFloatOpt)] + } + + switch v { + case "5": + g.Version = 5 + case "6": + g.Version = 6 + case "7": + g.Version = 7 + default: + Error = fmt.Errorf("invalid GOARM: must start with 5, 6, or 7, and may optionally end in either %q or %q", hardFloatOpt, softFloatOpt) + g.Version = int(def[0] - '0') + } + + // 5 defaults to softfloat. 6 and 7 default to hardfloat. + if !floatSpecified && g.Version == 5 { + g.SoftFloat = true + } + return +} + +type Goarm64Features struct { + Version string + // Large Systems Extension + LSE bool + // ARM v8.0 Cryptographic Extension. It includes the following features: + // * FEAT_AES, which includes the AESD and AESE instructions. + // * FEAT_PMULL, which includes the PMULL, PMULL2 instructions. + // * FEAT_SHA1, which includes the SHA1* instructions. + // * FEAT_SHA256, which includes the SHA256* instructions. + Crypto bool +} + +func (g Goarm64Features) String() string { + arm64Str := g.Version + if g.LSE { + arm64Str += ",lse" + } + if g.Crypto { + arm64Str += ",crypto" + } + return arm64Str +} + +func ParseGoarm64(v string) (g Goarm64Features, e error) { + const ( + lseOpt = ",lse" + cryptoOpt = ",crypto" + ) + + g.LSE = false + g.Crypto = false + // We allow any combination of suffixes, in any order + for { + if strings.HasSuffix(v, lseOpt) { + g.LSE = true + v = v[:len(v)-len(lseOpt)] + continue + } + + if strings.HasSuffix(v, cryptoOpt) { + g.Crypto = true + v = v[:len(v)-len(cryptoOpt)] + continue + } + + break + } + + switch v { + case "v8.0": + g.Version = v + case "v8.1", "v8.2", "v8.3", "v8.4", "v8.5", "v8.6", "v8.7", "v8.8", "v8.9", + "v9.0", "v9.1", "v9.2", "v9.3", "v9.4", "v9.5": + g.Version = v + // LSE extension is mandatory starting from 8.1 + g.LSE = true + default: + e = fmt.Errorf("invalid GOARM64: must start with v8.{0-9} or v9.{0-5} and may optionally end in %q and/or %q", + lseOpt, cryptoOpt) + g.Version = defaultGOARM64 + } + + return +} + +func goarm64() (g Goarm64Features) { + g, Error = ParseGoarm64(envOr("GOARM64", defaultGOARM64)) + return +} + +// Returns true if g supports giving ARM64 ISA +// Note that this function doesn't accept / test suffixes (like ",lse" or ",crypto") +func (g Goarm64Features) Supports(s string) bool { + // We only accept "v{8-9}.{0-9}. Everything else is malformed. + if len(s) != 4 { + return false + } + + major := s[1] + minor := s[3] + + // We only accept "v{8-9}.{0-9}. Everything else is malformed. + if major < '8' || major > '9' || + minor < '0' || minor > '9' || + s[0] != 'v' || s[2] != '.' { + return false + } + + g_major := g.Version[1] + g_minor := g.Version[3] + + if major == g_major { + return minor <= g_minor + } else if g_major == '9' { + // v9.0 diverged from v8.5. This means we should compare with g_minor increased by five. + return minor <= g_minor+5 + } else { + return false + } +} + +func gomips() string { + switch v := envOr("GOMIPS", defaultGOMIPS); v { + case "hardfloat", "softfloat": + return v + } + Error = fmt.Errorf("invalid GOMIPS: must be hardfloat, softfloat") + return defaultGOMIPS +} + +func gomips64() string { + switch v := envOr("GOMIPS64", defaultGOMIPS64); v { + case "hardfloat", "softfloat": + return v + } + Error = fmt.Errorf("invalid GOMIPS64: must be hardfloat, softfloat") + return defaultGOMIPS64 +} + +func goppc64() int { + switch v := envOr("GOPPC64", defaultGOPPC64); v { + case "power8": + return 8 + case "power9": + return 9 + case "power10": + return 10 + } + Error = fmt.Errorf("invalid GOPPC64: must be power8, power9, power10") + return int(defaultGOPPC64[len("power")] - '0') +} + +func goriscv64() int { + switch v := envOr("GORISCV64", defaultGORISCV64); v { + case "rva20u64": + return 20 + case "rva22u64": + return 22 + } + Error = fmt.Errorf("invalid GORISCV64: must be rva20u64, rva22u64") + v := defaultGORISCV64[len("rva"):] + i := strings.IndexFunc(v, func(r rune) bool { + return r < '0' || r > '9' + }) + year, _ := strconv.Atoi(v[:i]) + return year +} + +type gowasmFeatures struct { + SatConv bool + SignExt bool +} + +func (f gowasmFeatures) String() string { + var flags []string + if f.SatConv { + flags = append(flags, "satconv") + } + if f.SignExt { + flags = append(flags, "signext") + } + return strings.Join(flags, ",") +} + +func gowasm() (f gowasmFeatures) { + for _, opt := range strings.Split(envOr("GOWASM", ""), ",") { + switch opt { + case "satconv": + f.SatConv = true + case "signext": + f.SignExt = true + case "": + // ignore + default: + Error = fmt.Errorf("invalid GOWASM: no such feature %q", opt) + } + } + return +} + +func Getgoextlinkenabled() string { + return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED) +} + +func toolTags() []string { + tags := experimentTags() + tags = append(tags, gogoarchTags()...) + return tags +} + +func experimentTags() []string { + var list []string + // For each experiment that has been enabled in the toolchain, define a + // build tag with the same name but prefixed by "goexperiment." which can be + // used for compiling alternative files for the experiment. This allows + // changes for the experiment, like extra struct fields in the runtime, + // without affecting the base non-experiment code at all. + for _, exp := range Experiment.Enabled() { + list = append(list, "goexperiment."+exp) + } + return list +} + +// GOGOARCH returns the name and value of the GO$GOARCH setting. +// For example, if GOARCH is "amd64" it might return "GOAMD64", "v2". +func GOGOARCH() (name, value string) { + switch GOARCH { + case "386": + return "GO386", GO386 + case "amd64": + return "GOAMD64", fmt.Sprintf("v%d", GOAMD64) + case "arm": + return "GOARM", GOARM.String() + case "arm64": + return "GOARM64", GOARM64.String() + case "mips", "mipsle": + return "GOMIPS", GOMIPS + case "mips64", "mips64le": + return "GOMIPS64", GOMIPS64 + case "ppc64", "ppc64le": + return "GOPPC64", fmt.Sprintf("power%d", GOPPC64) + case "wasm": + return "GOWASM", GOWASM.String() + } + return "", "" +} + +func gogoarchTags() []string { + switch GOARCH { + case "386": + return []string{GOARCH + "." + GO386} + case "amd64": + var list []string + for i := 1; i <= GOAMD64; i++ { + list = append(list, fmt.Sprintf("%s.v%d", GOARCH, i)) + } + return list + case "arm": + var list []string + for i := 5; i <= GOARM.Version; i++ { + list = append(list, fmt.Sprintf("%s.%d", GOARCH, i)) + } + return list + case "arm64": + var list []string + major := int(GOARM64.Version[1] - '0') + minor := int(GOARM64.Version[3] - '0') + for i := 0; i <= minor; i++ { + list = append(list, fmt.Sprintf("%s.v%d.%d", GOARCH, major, i)) + } + // ARM64 v9.x also includes support of v8.x+5 (i.e. v9.1 includes v8.(1+5) = v8.6). + if major == 9 { + for i := 0; i <= minor+5 && i <= 9; i++ { + list = append(list, fmt.Sprintf("%s.v%d.%d", GOARCH, 8, i)) + } + } + return list + case "mips", "mipsle": + return []string{GOARCH + "." + GOMIPS} + case "mips64", "mips64le": + return []string{GOARCH + "." + GOMIPS64} + case "ppc64", "ppc64le": + var list []string + for i := 8; i <= GOPPC64; i++ { + list = append(list, fmt.Sprintf("%s.power%d", GOARCH, i)) + } + return list + case "riscv64": + list := []string{GOARCH + "." + "rva20u64"} + if GORISCV64 >= 22 { + list = append(list, GOARCH+"."+"rva22u64") + } + return list + case "wasm": + var list []string + if GOWASM.SatConv { + list = append(list, GOARCH+".satconv") + } + if GOWASM.SignExt { + list = append(list, GOARCH+".signext") + } + return list + } + return nil +} diff --git a/contrib/go/_std_1.22/src/internal/buildcfg/exp.go b/contrib/go/_std_1.23/src/internal/buildcfg/exp.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/buildcfg/exp.go rename to contrib/go/_std_1.23/src/internal/buildcfg/exp.go index a45cfaf862ca..7c7cefba7b2a 100644 --- a/contrib/go/_std_1.22/src/internal/buildcfg/exp.go +++ b/contrib/go/_std_1.23/src/internal/buildcfg/exp.go @@ -62,19 +62,15 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (*ExperimentFlags, error) { // always on. var regabiSupported, regabiAlwaysOn bool switch goarch { - case "amd64", "arm64", "ppc64le", "ppc64", "riscv64": + case "amd64", "arm64", "loong64", "ppc64le", "ppc64", "riscv64": regabiAlwaysOn = true regabiSupported = true - case "loong64": - regabiSupported = true } baseline := goexperiment.Flags{ RegabiWrappers: regabiSupported, RegabiArgs: regabiSupported, CoverageRedesign: true, - AllocHeaders: true, - ExecTracer2: true, } // Start with the statically enabled set of experiments. diff --git a/contrib/go/_std_1.22/src/internal/buildcfg/ya.make b/contrib/go/_std_1.23/src/internal/buildcfg/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/buildcfg/ya.make rename to contrib/go/_std_1.23/src/internal/buildcfg/ya.make diff --git a/contrib/go/_std_1.22/src/internal/buildcfg/zbootstrap.go b/contrib/go/_std_1.23/src/internal/buildcfg/zbootstrap.go similarity index 82% rename from contrib/go/_std_1.22/src/internal/buildcfg/zbootstrap.go rename to contrib/go/_std_1.23/src/internal/buildcfg/zbootstrap.go index c4a47af3ef38..8f8f7bd486b9 100644 --- a/contrib/go/_std_1.22/src/internal/buildcfg/zbootstrap.go +++ b/contrib/go/_std_1.23/src/internal/buildcfg/zbootstrap.go @@ -7,12 +7,14 @@ import "runtime" const defaultGO386 = `sse2` const defaultGOAMD64 = `v1` const defaultGOARM = `7` +const defaultGOARM64 = `v8.0` const defaultGOMIPS = `hardfloat` const defaultGOMIPS64 = `hardfloat` const defaultGOPPC64 = `power8` +const defaultGORISCV64 = `rva20u64` const defaultGOEXPERIMENT = `` const defaultGO_EXTLINK_ENABLED = `` const defaultGO_LDSO = `` -const version = `go1.22.5` +const version = `go1.23.8` const defaultGOOS = runtime.GOOS const defaultGOARCH = runtime.GOARCH diff --git a/contrib/go/_std_1.22/src/internal/bytealg/bytealg.go b/contrib/go/_std_1.23/src/internal/bytealg/bytealg.go similarity index 95% rename from contrib/go/_std_1.22/src/internal/bytealg/bytealg.go rename to contrib/go/_std_1.23/src/internal/bytealg/bytealg.go index 1103891eeefe..6b79a2e1fabb 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/bytealg.go +++ b/contrib/go/_std_1.23/src/internal/bytealg/bytealg.go @@ -111,7 +111,8 @@ func LastIndexRabinKarp[T string | []byte](s, sep T) int { return -1 } -// MakeNoZero makes a slice of length and capacity n without zeroing the bytes. +// MakeNoZero makes a slice of length n and capacity of at least n Bytes +// without zeroing the bytes (including the bytes between len and cap). // It is the caller's responsibility to ensure uninitialized bytes // do not leak to the end user. func MakeNoZero(n int) []byte diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_386.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_386.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_386.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_386.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_arm.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_arm.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_arm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_arm64.s diff --git a/contrib/go/_std_1.23/src/internal/bytealg/compare_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/compare_generic.go new file mode 100644 index 000000000000..614ae8b8cf22 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/bytealg/compare_generic.go @@ -0,0 +1,76 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !386 && !amd64 && !s390x && !arm && !arm64 && !loong64 && !ppc64 && !ppc64le && !mips && !mipsle && !wasm && !mips64 && !mips64le && !riscv64 + +package bytealg + +import _ "unsafe" // for go:linkname + +func Compare(a, b []byte) int { + l := len(a) + if len(b) < l { + l = len(b) + } + if l == 0 || &a[0] == &b[0] { + goto samebytes + } + for i := 0; i < l; i++ { + c1, c2 := a[i], b[i] + if c1 < c2 { + return -1 + } + if c1 > c2 { + return +1 + } + } +samebytes: + if len(a) < len(b) { + return -1 + } + if len(a) > len(b) { + return +1 + } + return 0 +} + +func CompareString(a, b string) int { + return runtime_cmpstring(a, b) +} + +// runtime.cmpstring calls are emitted by the compiler. +// +// runtime.cmpstring should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/zhaochuninhefei/gmgo +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname runtime_cmpstring runtime.cmpstring +func runtime_cmpstring(a, b string) int { + l := len(a) + if len(b) < l { + l = len(b) + } + for i := 0; i < l; i++ { + c1, c2 := a[i], b[i] + if c1 < c2 { + return -1 + } + if c1 > c2 { + return +1 + } + } + if len(a) < len(b) { + return -1 + } + if len(a) > len(b) { + return +1 + } + return 0 +} diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_loong64.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_loong64.s similarity index 82% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_loong64.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_loong64.s index 311449ab1897..df72a1122bc7 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/compare_loong64.s +++ b/contrib/go/_std_1.23/src/internal/bytealg/compare_loong64.s @@ -6,13 +6,6 @@ #include "textflag.h" TEXT ·Compare(SB),NOSPLIT,$0-56 -#ifndef GOEXPERIMENT_regabiargs - MOVV a_base+0(FP), R4 - MOVV a_len+8(FP), R5 - MOVV b_base+24(FP), R6 - MOVV b_len+32(FP), R7 - MOVV $ret+48(FP), R13 -#else // R4 = a_base // R5 = a_len // R6 = a_cap (unused) @@ -21,17 +14,9 @@ TEXT ·Compare(SB),NOSPLIT,$0-56 // R9 = b_cap (unused) MOVV R7, R6 MOVV R8, R7 -#endif JMP cmpbody<>(SB) TEXT runtime·cmpstring(SB),NOSPLIT,$0-40 -#ifndef GOEXPERIMENT_regabiargs - MOVV a_base+0(FP), R4 - MOVV b_base+16(FP), R6 - MOVV a_len+8(FP), R5 - MOVV b_len+24(FP), R7 - MOVV $ret+32(FP), R13 -#endif // R4 = a_base // R5 = a_len // R6 = b_base @@ -100,7 +85,4 @@ samebytes: SUBV R9, R8, R4 ret: -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, (R13) -#endif RET diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_mips64x.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_mips64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_mips64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_mipsx.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_mipsx.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_mipsx.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_native.go b/contrib/go/_std_1.23/src/internal/bytealg/compare_native.go similarity index 88% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/compare_native.go index 34964e281c63..983ab069db40 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/compare_native.go +++ b/contrib/go/_std_1.23/src/internal/bytealg/compare_native.go @@ -11,6 +11,10 @@ import _ "unsafe" // For go:linkname //go:noescape func Compare(a, b []byte) int +func CompareString(a, b string) int { + return abigen_runtime_cmpstring(a, b) +} + // The declaration below generates ABI wrappers for functions // implemented in assembly in this package but declared in another // package. diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_riscv64.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_riscv64.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_riscv64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_wasm.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_wasm.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_wasm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/count_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_arm.s b/contrib/go/_std_1.23/src/internal/bytealg/count_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_arm.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_arm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/count_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/count_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/count_generic.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_native.go b/contrib/go/_std_1.23/src/internal/bytealg/count_native.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/count_native.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/count_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_riscv64.s b/contrib/go/_std_1.23/src/internal/bytealg/count_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_riscv64.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_riscv64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/count_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_386.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_386.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_386.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_386.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_arm.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_arm.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_arm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_arm64.s similarity index 97% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_arm64.s index d3aabba5871e..4db951547443 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/equal_arm64.s +++ b/contrib/go/_std_1.23/src/internal/bytealg/equal_arm64.s @@ -9,6 +9,9 @@ TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25 // short path to handle 0-byte case CBZ R2, equal + // short path to handle equal pointers + CMP R0, R1 + BEQ equal B memeqbody<>(SB) equal: MOVD $1, R0 diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/equal_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/equal_generic.go diff --git a/contrib/go/_std_1.23/src/internal/bytealg/equal_loong64.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_loong64.s new file mode 100644 index 000000000000..830b09bd2cf3 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/bytealg/equal_loong64.s @@ -0,0 +1,44 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "textflag.h" + +#define REGCTXT R29 + +// memequal(a, b unsafe.Pointer, size uintptr) bool +TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25 + BEQ R4, R5, eq + ADDV R4, R6, R7 + PCALIGN $16 +loop: + BNE R4, R7, test + MOVV $1, R4 + RET +test: + MOVBU (R4), R9 + ADDV $1, R4 + MOVBU (R5), R10 + ADDV $1, R5 + BEQ R9, R10, loop + + MOVB R0, R4 + RET +eq: + MOVV $1, R4 + RET + +// memequal_varlen(a, b unsafe.Pointer) bool +TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 + BEQ R4, R5, eq + MOVV 8(REGCTXT), R6 // compiler stores size at offset 8 in the closure + MOVV R4, 8(R3) + MOVV R5, 16(R3) + MOVV R6, 24(R3) + JAL runtime·memequal(SB) + MOVBU 32(R3), R4 + RET +eq: + MOVV $1, R4 + RET diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_mips64x.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_mips64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_mips64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_mipsx.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_mipsx.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_mipsx.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_native.go b/contrib/go/_std_1.23/src/internal/bytealg/equal_native.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/equal_native.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_riscv64.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_riscv64.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_riscv64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_wasm.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_wasm.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_wasm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_amd64.go b/contrib/go/_std_1.23/src/internal/bytealg/index_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_amd64.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_amd64.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/index_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/index_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_arm64.go b/contrib/go/_std_1.23/src/internal/bytealg/index_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_arm64.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_arm64.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/index_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/index_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/index_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_generic.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_native.go b/contrib/go/_std_1.23/src/internal/bytealg/index_native.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_native.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_ppc64x.go b/contrib/go/_std_1.23/src/internal/bytealg/index_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_ppc64x.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_ppc64x.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/index_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/index_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_s390x.go b/contrib/go/_std_1.23/src/internal/bytealg/index_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_s390x.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_s390x.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/index_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/index_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_386.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_386.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_386.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_386.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_arm.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_arm.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_arm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_generic.go diff --git a/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_loong64.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_loong64.s new file mode 100644 index 000000000000..c9591b3cdaa5 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_loong64.s @@ -0,0 +1,52 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "textflag.h" + +TEXT ·IndexByte(SB),NOSPLIT,$0-40 + // R4 = b_base + // R5 = b_len + // R6 = b_cap (unused) + // R7 = byte to find + AND $0xff, R7 + MOVV R4, R6 // store base for later + ADDV R4, R5 // end + ADDV $-1, R4 + + PCALIGN $16 +loop: + ADDV $1, R4 + BEQ R4, R5, notfound + MOVBU (R4), R8 + BNE R7, R8, loop + + SUBV R6, R4 // remove base + RET + +notfound: + MOVV $-1, R4 + RET + +TEXT ·IndexByteString(SB),NOSPLIT,$0-32 + // R4 = s_base + // R5 = s_len + // R6 = byte to find + MOVV R4, R7 // store base for later + ADDV R4, R5 // end + ADDV $-1, R4 + + PCALIGN $16 +loop: + ADDV $1, R4 + BEQ R4, R5, notfound + MOVBU (R4), R8 + BNE R6, R8, loop + + SUBV R7, R4 // remove base + RET + +notfound: + MOVV $-1, R4 + RET diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_mips64x.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_mips64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_mips64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_mipsx.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_mipsx.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_mipsx.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_native.go b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_native.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_native.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_riscv64.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_riscv64.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_riscv64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_wasm.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_wasm.s similarity index 98% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_wasm.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_wasm.s index ef4bd93070f4..d22e90448d43 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_wasm.s +++ b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_wasm.s @@ -12,7 +12,7 @@ TEXT ·IndexByte(SB), NOSPLIT, $0-40 I64Load b_len+8(FP) I32WrapI64 Call memchr<>(SB) - I64ExtendI32S + I64ExtendI32U Set R0 Get SP @@ -35,7 +35,7 @@ TEXT ·IndexByteString(SB), NOSPLIT, $0-32 I64Load s_len+8(FP) I32WrapI64 Call memchr<>(SB) - I64ExtendI32S + I64ExtendI32U Set R0 I64Const $-1 diff --git a/contrib/go/_std_1.22/src/internal/bytealg/lastindexbyte_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/lastindexbyte_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/lastindexbyte_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/lastindexbyte_generic.go diff --git a/contrib/go/_std_1.23/src/internal/bytealg/ya.make b/contrib/go/_std_1.23/src/internal/bytealg/ya.make new file mode 100644 index 000000000000..a575621a2f05 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/bytealg/ya.make @@ -0,0 +1,52 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + bytealg.go + compare_arm64.s + compare_native.go + count_arm64.s + count_native.go + equal_arm64.s + equal_generic.go + equal_native.go + index_arm64.go + index_arm64.s + index_native.go + indexbyte_arm64.s + indexbyte_native.go + lastindexbyte_generic.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + bytealg.go + compare_amd64.s + compare_native.go + count_amd64.s + count_native.go + equal_amd64.s + equal_generic.go + equal_native.go + index_amd64.go + index_amd64.s + index_native.go + indexbyte_amd64.s + indexbyte_native.go + lastindexbyte_generic.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + bytealg.go + compare_arm.s + compare_native.go + count_arm.s + count_native.go + equal_arm.s + equal_generic.go + equal_native.go + index_generic.go + indexbyte_arm.s + indexbyte_native.go + lastindexbyte_generic.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/byteorder/byteorder.go b/contrib/go/_std_1.23/src/internal/byteorder/byteorder.go new file mode 100644 index 000000000000..ba37856ccd97 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/byteorder/byteorder.go @@ -0,0 +1,149 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package byteorder provides functions for decoding and encoding +// little and big endian integer types from/to byte slices. +package byteorder + +func LeUint16(b []byte) uint16 { + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint16(b[0]) | uint16(b[1])<<8 +} + +func LePutUint16(b []byte, v uint16) { + _ = b[1] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) +} + +func LeAppendUint16(b []byte, v uint16) []byte { + return append(b, + byte(v), + byte(v>>8), + ) +} + +func LeUint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func LePutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) +} + +func LeAppendUint32(b []byte, v uint32) []byte { + return append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + ) +} + +func LeUint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func LePutUint64(b []byte, v uint64) { + _ = b[7] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) + b[4] = byte(v >> 32) + b[5] = byte(v >> 40) + b[6] = byte(v >> 48) + b[7] = byte(v >> 56) +} + +func LeAppendUint64(b []byte, v uint64) []byte { + return append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + byte(v>>32), + byte(v>>40), + byte(v>>48), + byte(v>>56), + ) +} + +func BeUint16(b []byte) uint16 { + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint16(b[1]) | uint16(b[0])<<8 +} + +func BePutUint16(b []byte, v uint16) { + _ = b[1] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 8) + b[1] = byte(v) +} + +func BeAppendUint16(b []byte, v uint16) []byte { + return append(b, + byte(v>>8), + byte(v), + ) +} + +func BeUint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func BePutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 24) + b[1] = byte(v >> 16) + b[2] = byte(v >> 8) + b[3] = byte(v) +} + +func BeAppendUint32(b []byte, v uint32) []byte { + return append(b, + byte(v>>24), + byte(v>>16), + byte(v>>8), + byte(v), + ) +} + +func BeUint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} + +func BePutUint64(b []byte, v uint64) { + _ = b[7] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 56) + b[1] = byte(v >> 48) + b[2] = byte(v >> 40) + b[3] = byte(v >> 32) + b[4] = byte(v >> 24) + b[5] = byte(v >> 16) + b[6] = byte(v >> 8) + b[7] = byte(v) +} + +func BeAppendUint64(b []byte, v uint64) []byte { + return append(b, + byte(v>>56), + byte(v>>48), + byte(v>>40), + byte(v>>32), + byte(v>>24), + byte(v>>16), + byte(v>>8), + byte(v), + ) +} diff --git a/contrib/go/_std_1.23/src/internal/byteorder/ya.make b/contrib/go/_std_1.23/src/internal/byteorder/ya.make new file mode 100644 index 000000000000..c39304ec1893 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/byteorder/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + byteorder.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8.go b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8.go new file mode 100644 index 000000000000..8f1b4e5315c9 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8.go @@ -0,0 +1,160 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package chacha8rand implements a pseudorandom generator +// based on ChaCha8. It is used by both runtime and math/rand/v2 +// and must have minimal dependencies. +package chacha8rand + +import "internal/byteorder" + +const ( + ctrInc = 4 // increment counter by 4 between block calls + ctrMax = 16 // reseed when counter reaches 16 + chunk = 32 // each chunk produced by block is 32 uint64s + reseed = 4 // reseed with 4 words +) + +// block is the chacha8rand block function. +func block(seed *[4]uint64, blocks *[32]uint64, counter uint32) + +// A State holds the state for a single random generator. +// It must be used from one goroutine at a time. +// If used by multiple goroutines at a time, the goroutines +// may see the same random values, but the code will not +// crash or cause out-of-bounds memory accesses. +type State struct { + buf [32]uint64 + seed [4]uint64 + i uint32 + n uint32 + c uint32 +} + +// Next returns the next random value, along with a boolean +// indicating whether one was available. +// If one is not available, the caller should call Refill +// and then repeat the call to Next. +// +// Next is //go:nosplit to allow its use in the runtime +// with per-m data without holding the per-m lock. +// +//go:nosplit +func (s *State) Next() (uint64, bool) { + i := s.i + if i >= s.n { + return 0, false + } + s.i = i + 1 + return s.buf[i&31], true // i&31 eliminates bounds check +} + +// Init seeds the State with the given seed value. +func (s *State) Init(seed [32]byte) { + s.Init64([4]uint64{ + byteorder.LeUint64(seed[0*8:]), + byteorder.LeUint64(seed[1*8:]), + byteorder.LeUint64(seed[2*8:]), + byteorder.LeUint64(seed[3*8:]), + }) +} + +// Init64 seeds the state with the given seed value. +func (s *State) Init64(seed [4]uint64) { + s.seed = seed + block(&s.seed, &s.buf, 0) + s.c = 0 + s.i = 0 + s.n = chunk +} + +// Refill refills the state with more random values. +// After a call to Refill, an immediate call to Next will succeed +// (unless multiple goroutines are incorrectly sharing a state). +func (s *State) Refill() { + s.c += ctrInc + if s.c == ctrMax { + // Reseed with generated uint64s for forward secrecy. + // Normally this is done immediately after computing a block, + // but we do it immediately before computing the next block, + // to allow a much smaller serialized state (just the seed plus offset). + // This gives a delayed benefit for the forward secrecy + // (you can reconstruct the recent past given a memory dump), + // which we deem acceptable in exchange for the reduced size. + s.seed[0] = s.buf[len(s.buf)-reseed+0] + s.seed[1] = s.buf[len(s.buf)-reseed+1] + s.seed[2] = s.buf[len(s.buf)-reseed+2] + s.seed[3] = s.buf[len(s.buf)-reseed+3] + s.c = 0 + } + block(&s.seed, &s.buf, s.c) + s.i = 0 + s.n = uint32(len(s.buf)) + if s.c == ctrMax-ctrInc { + s.n = uint32(len(s.buf)) - reseed + } +} + +// Reseed reseeds the state with new random values. +// After a call to Reseed, any previously returned random values +// have been erased from the memory of the state and cannot be +// recovered. +func (s *State) Reseed() { + var seed [4]uint64 + for i := range seed { + for { + x, ok := s.Next() + if ok { + seed[i] = x + break + } + s.Refill() + } + } + s.Init64(seed) +} + +// Marshal marshals the state into a byte slice. +// Marshal and Unmarshal are functions, not methods, +// so that they will not be linked into the runtime +// when it uses the State struct, since the runtime +// does not need these. +func Marshal(s *State) []byte { + data := make([]byte, 6*8) + copy(data, "chacha8:") + used := (s.c/ctrInc)*chunk + s.i + byteorder.BePutUint64(data[1*8:], uint64(used)) + for i, seed := range s.seed { + byteorder.LePutUint64(data[(2+i)*8:], seed) + } + return data +} + +type errUnmarshalChaCha8 struct{} + +func (*errUnmarshalChaCha8) Error() string { + return "invalid ChaCha8 encoding" +} + +// Unmarshal unmarshals the state from a byte slice. +func Unmarshal(s *State, data []byte) error { + if len(data) != 6*8 || string(data[:8]) != "chacha8:" { + return new(errUnmarshalChaCha8) + } + used := byteorder.BeUint64(data[1*8:]) + if used > (ctrMax/ctrInc)*chunk-reseed { + return new(errUnmarshalChaCha8) + } + for i := range s.seed { + s.seed[i] = byteorder.LeUint64(data[(2+i)*8:]) + } + s.c = ctrInc * (uint32(used) / chunk) + block(&s.seed, &s.buf, s.c) + s.i = uint32(used) % chunk + s.n = chunk + if s.c == ctrMax-ctrInc { + s.n = chunk - reseed + } + return nil +} diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_amd64.s b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_amd64.s rename to contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_arm64.s b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_arm64.s rename to contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_generic.go b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_generic.go rename to contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_generic.go diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_stub.s b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_stub.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_stub.s rename to contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_stub.s diff --git a/contrib/go/_std_1.23/src/internal/chacha8rand/ya.make b/contrib/go/_std_1.23/src/internal/chacha8rand/ya.make new file mode 100644 index 000000000000..9105cb109ee9 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/chacha8rand/ya.make @@ -0,0 +1,21 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + chacha8.go + chacha8_arm64.s + chacha8_generic.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + chacha8.go + chacha8_amd64.s + chacha8_generic.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + chacha8.go + chacha8_generic.go + chacha8_stub.s + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/concurrent/hashtriemap.go b/contrib/go/_std_1.23/src/internal/concurrent/hashtriemap.go new file mode 100644 index 000000000000..4f7e730d4fca --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/concurrent/hashtriemap.go @@ -0,0 +1,408 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package concurrent + +import ( + "internal/abi" + "internal/goarch" + "math/rand/v2" + "sync" + "sync/atomic" + "unsafe" +) + +// HashTrieMap is an implementation of a concurrent hash-trie. The implementation +// is designed around frequent loads, but offers decent performance for stores +// and deletes as well, especially if the map is larger. It's primary use-case is +// the unique package, but can be used elsewhere as well. +type HashTrieMap[K, V comparable] struct { + root *indirect[K, V] + keyHash hashFunc + keyEqual equalFunc + valEqual equalFunc + seed uintptr +} + +// NewHashTrieMap creates a new HashTrieMap for the provided key and value. +func NewHashTrieMap[K, V comparable]() *HashTrieMap[K, V] { + var m map[K]V + mapType := abi.TypeOf(m).MapType() + ht := &HashTrieMap[K, V]{ + root: newIndirectNode[K, V](nil), + keyHash: mapType.Hasher, + keyEqual: mapType.Key.Equal, + valEqual: mapType.Elem.Equal, + seed: uintptr(rand.Uint64()), + } + return ht +} + +type hashFunc func(unsafe.Pointer, uintptr) uintptr +type equalFunc func(unsafe.Pointer, unsafe.Pointer) bool + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (ht *HashTrieMap[K, V]) Load(key K) (value V, ok bool) { + hash := ht.keyHash(abi.NoEscape(unsafe.Pointer(&key)), ht.seed) + + i := ht.root + hashShift := 8 * goarch.PtrSize + for hashShift != 0 { + hashShift -= nChildrenLog2 + + n := i.children[(hash>>hashShift)&nChildrenMask].Load() + if n == nil { + return *new(V), false + } + if n.isEntry { + return n.entry().lookup(key, ht.keyEqual) + } + i = n.indirect() + } + panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (ht *HashTrieMap[K, V]) LoadOrStore(key K, value V) (result V, loaded bool) { + hash := ht.keyHash(abi.NoEscape(unsafe.Pointer(&key)), ht.seed) + var i *indirect[K, V] + var hashShift uint + var slot *atomic.Pointer[node[K, V]] + var n *node[K, V] + for { + // Find the key or a candidate location for insertion. + i = ht.root + hashShift = 8 * goarch.PtrSize + haveInsertPoint := false + for hashShift != 0 { + hashShift -= nChildrenLog2 + + slot = &i.children[(hash>>hashShift)&nChildrenMask] + n = slot.Load() + if n == nil { + // We found a nil slot which is a candidate for insertion. + haveInsertPoint = true + break + } + if n.isEntry { + // We found an existing entry, which is as far as we can go. + // If it stays this way, we'll have to replace it with an + // indirect node. + if v, ok := n.entry().lookup(key, ht.keyEqual); ok { + return v, true + } + haveInsertPoint = true + break + } + i = n.indirect() + } + if !haveInsertPoint { + panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + } + + // Grab the lock and double-check what we saw. + i.mu.Lock() + n = slot.Load() + if (n == nil || n.isEntry) && !i.dead.Load() { + // What we saw is still true, so we can continue with the insert. + break + } + // We have to start over. + i.mu.Unlock() + } + // N.B. This lock is held from when we broke out of the outer loop above. + // We specifically break this out so that we can use defer here safely. + // One option is to break this out into a new function instead, but + // there's so much local iteration state used below that this turns out + // to be cleaner. + defer i.mu.Unlock() + + var oldEntry *entry[K, V] + if n != nil { + oldEntry = n.entry() + if v, ok := oldEntry.lookup(key, ht.keyEqual); ok { + // Easy case: by loading again, it turns out exactly what we wanted is here! + return v, true + } + } + newEntry := newEntryNode(key, value) + if oldEntry == nil { + // Easy case: create a new entry and store it. + slot.Store(&newEntry.node) + } else { + // We possibly need to expand the entry already there into one or more new nodes. + // + // Publish the node last, which will make both oldEntry and newEntry visible. We + // don't want readers to be able to observe that oldEntry isn't in the tree. + slot.Store(ht.expand(oldEntry, newEntry, hash, hashShift, i)) + } + return value, false +} + +// expand takes oldEntry and newEntry whose hashes conflict from bit 64 down to hashShift and +// produces a subtree of indirect nodes to hold the two new entries. +func (ht *HashTrieMap[K, V]) expand(oldEntry, newEntry *entry[K, V], newHash uintptr, hashShift uint, parent *indirect[K, V]) *node[K, V] { + // Check for a hash collision. + oldHash := ht.keyHash(unsafe.Pointer(&oldEntry.key), ht.seed) + if oldHash == newHash { + // Store the old entry in the new entry's overflow list, then store + // the new entry. + newEntry.overflow.Store(oldEntry) + return &newEntry.node + } + // We have to add an indirect node. Worse still, we may need to add more than one. + newIndirect := newIndirectNode(parent) + top := newIndirect + for { + if hashShift == 0 { + panic("internal/concurrent.HashMapTrie: ran out of hash bits while inserting") + } + hashShift -= nChildrenLog2 // hashShift is for the level parent is at. We need to go deeper. + oi := (oldHash >> hashShift) & nChildrenMask + ni := (newHash >> hashShift) & nChildrenMask + if oi != ni { + newIndirect.children[oi].Store(&oldEntry.node) + newIndirect.children[ni].Store(&newEntry.node) + break + } + nextIndirect := newIndirectNode(newIndirect) + newIndirect.children[oi].Store(&nextIndirect.node) + newIndirect = nextIndirect + } + return &top.node +} + +// CompareAndDelete deletes the entry for key if its value is equal to old. +// +// If there is no current value for key in the map, CompareAndDelete returns false +// (even if the old value is the nil interface value). +func (ht *HashTrieMap[K, V]) CompareAndDelete(key K, old V) (deleted bool) { + hash := ht.keyHash(abi.NoEscape(unsafe.Pointer(&key)), ht.seed) + var i *indirect[K, V] + var hashShift uint + var slot *atomic.Pointer[node[K, V]] + var n *node[K, V] + for { + // Find the key or return when there's nothing to delete. + i = ht.root + hashShift = 8 * goarch.PtrSize + found := false + for hashShift != 0 { + hashShift -= nChildrenLog2 + + slot = &i.children[(hash>>hashShift)&nChildrenMask] + n = slot.Load() + if n == nil { + // Nothing to delete. Give up. + return + } + if n.isEntry { + // We found an entry. Check if it matches. + if _, ok := n.entry().lookup(key, ht.keyEqual); !ok { + // No match, nothing to delete. + return + } + // We've got something to delete. + found = true + break + } + i = n.indirect() + } + if !found { + panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + } + + // Grab the lock and double-check what we saw. + i.mu.Lock() + n = slot.Load() + if !i.dead.Load() { + if n == nil { + // Valid node that doesn't contain what we need. Nothing to delete. + i.mu.Unlock() + return + } + if n.isEntry { + // What we saw is still true, so we can continue with the delete. + break + } + } + // We have to start over. + i.mu.Unlock() + } + // Try to delete the entry. + e, deleted := n.entry().compareAndDelete(key, old, ht.keyEqual, ht.valEqual) + if !deleted { + // Nothing was actually deleted, which means the node is no longer there. + i.mu.Unlock() + return false + } + if e != nil { + // We didn't actually delete the whole entry, just one entry in the chain. + // Nothing else to do, since the parent is definitely not empty. + slot.Store(&e.node) + i.mu.Unlock() + return true + } + // Delete the entry. + slot.Store(nil) + + // Check if the node is now empty (and isn't the root), and delete it if able. + for i.parent != nil && i.empty() { + if hashShift == 8*goarch.PtrSize { + panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + } + hashShift += nChildrenLog2 + + // Delete the current node in the parent. + parent := i.parent + parent.mu.Lock() + i.dead.Store(true) + parent.children[(hash>>hashShift)&nChildrenMask].Store(nil) + i.mu.Unlock() + i = parent + } + i.mu.Unlock() + return true +} + +// All returns an iter.Seq2 that produces all key-value pairs in the map. +// The enumeration does not represent any consistent snapshot of the map, +// but is guaranteed to visit each unique key-value pair only once. It is +// safe to operate on the tree during iteration. No particular enumeration +// order is guaranteed. +func (ht *HashTrieMap[K, V]) All() func(yield func(K, V) bool) { + return func(yield func(key K, value V) bool) { + ht.iter(ht.root, yield) + } +} + +func (ht *HashTrieMap[K, V]) iter(i *indirect[K, V], yield func(key K, value V) bool) bool { + for j := range i.children { + n := i.children[j].Load() + if n == nil { + continue + } + if !n.isEntry { + if !ht.iter(n.indirect(), yield) { + return false + } + continue + } + e := n.entry() + for e != nil { + if !yield(e.key, e.value) { + return false + } + e = e.overflow.Load() + } + } + return true +} + +const ( + // 16 children. This seems to be the sweet spot for + // load performance: any smaller and we lose out on + // 50% or more in CPU performance. Any larger and the + // returns are minuscule (~1% improvement for 32 children). + nChildrenLog2 = 4 + nChildren = 1 << nChildrenLog2 + nChildrenMask = nChildren - 1 +) + +// indirect is an internal node in the hash-trie. +type indirect[K, V comparable] struct { + node[K, V] + dead atomic.Bool + mu sync.Mutex // Protects mutation to children and any children that are entry nodes. + parent *indirect[K, V] + children [nChildren]atomic.Pointer[node[K, V]] +} + +func newIndirectNode[K, V comparable](parent *indirect[K, V]) *indirect[K, V] { + return &indirect[K, V]{node: node[K, V]{isEntry: false}, parent: parent} +} + +func (i *indirect[K, V]) empty() bool { + nc := 0 + for j := range i.children { + if i.children[j].Load() != nil { + nc++ + } + } + return nc == 0 +} + +// entry is a leaf node in the hash-trie. +type entry[K, V comparable] struct { + node[K, V] + overflow atomic.Pointer[entry[K, V]] // Overflow for hash collisions. + key K + value V +} + +func newEntryNode[K, V comparable](key K, value V) *entry[K, V] { + return &entry[K, V]{ + node: node[K, V]{isEntry: true}, + key: key, + value: value, + } +} + +func (e *entry[K, V]) lookup(key K, equal equalFunc) (V, bool) { + for e != nil { + if equal(unsafe.Pointer(&e.key), abi.NoEscape(unsafe.Pointer(&key))) { + return e.value, true + } + e = e.overflow.Load() + } + return *new(V), false +} + +// compareAndDelete deletes an entry in the overflow chain if both the key and value compare +// equal. Returns the new entry chain and whether or not anything was deleted. +// +// compareAndDelete must be called under the mutex of the indirect node which e is a child of. +func (head *entry[K, V]) compareAndDelete(key K, value V, keyEqual, valEqual equalFunc) (*entry[K, V], bool) { + if keyEqual(unsafe.Pointer(&head.key), abi.NoEscape(unsafe.Pointer(&key))) && + valEqual(unsafe.Pointer(&head.value), abi.NoEscape(unsafe.Pointer(&value))) { + // Drop the head of the list. + return head.overflow.Load(), true + } + i := &head.overflow + e := i.Load() + for e != nil { + if keyEqual(unsafe.Pointer(&e.key), abi.NoEscape(unsafe.Pointer(&key))) && + valEqual(unsafe.Pointer(&e.value), abi.NoEscape(unsafe.Pointer(&value))) { + i.Store(e.overflow.Load()) + return head, true + } + i = &e.overflow + e = e.overflow.Load() + } + return head, false +} + +// node is the header for a node. It's polymorphic and +// is actually either an entry or an indirect. +type node[K, V comparable] struct { + isEntry bool +} + +func (n *node[K, V]) entry() *entry[K, V] { + if !n.isEntry { + panic("called entry on non-entry node") + } + return (*entry[K, V])(unsafe.Pointer(n)) +} + +func (n *node[K, V]) indirect() *indirect[K, V] { + if n.isEntry { + panic("called indirect on entry node") + } + return (*indirect[K, V])(unsafe.Pointer(n)) +} diff --git a/contrib/go/_std_1.23/src/internal/concurrent/ya.make b/contrib/go/_std_1.23/src/internal/concurrent/ya.make new file mode 100644 index 000000000000..db0f6f6f0788 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/concurrent/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + hashtriemap.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/coverage/rtcov/rtcov.go b/contrib/go/_std_1.23/src/internal/coverage/rtcov/rtcov.go new file mode 100644 index 000000000000..9e30d679007d --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/coverage/rtcov/rtcov.go @@ -0,0 +1,88 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rtcov + +import "unsafe" + +// This package contains types whose structure is shared between +// the runtime package and the "runtime/coverage" implementation. + +// CovMetaBlob is a container for holding the meta-data symbol (an +// RODATA variable) for an instrumented Go package. Here "p" points to +// the symbol itself, "len" is the length of the sym in bytes, and +// "hash" is an md5sum for the sym computed by the compiler. When +// the init function for a coverage-instrumented package executes, it +// will make a call into the runtime which will create a covMetaBlob +// object for the package and chain it onto a global list. +type CovMetaBlob struct { + P *byte + Len uint32 + Hash [16]byte + PkgPath string + PkgID int + CounterMode uint8 // coverage.CounterMode + CounterGranularity uint8 // coverage.CounterGranularity +} + +// CovCounterBlob is a container for encapsulating a counter section +// (BSS variable) for an instrumented Go module. Here "counters" +// points to the counter payload and "len" is the number of uint32 +// entries in the section. +type CovCounterBlob struct { + Counters *uint32 + Len uint64 +} + +// Meta is the top-level container for bits of state related to +// code coverage meta-data in the runtime. +var Meta struct { + // List contains the list of currently registered meta-data + // blobs for the running program. + List []CovMetaBlob + + // PkgMap records mappings from hard-coded package IDs to + // slots in the List above. + PkgMap map[int]int + + // Set to true if we discover a package mapping glitch. + hardCodedListNeedsUpdating bool +} + +// AddMeta is invoked during package "init" functions by the +// compiler when compiling for coverage instrumentation; here 'p' is a +// meta-data blob of length 'dlen' for the package in question, 'hash' +// is a compiler-computed md5.sum for the blob, 'pkpath' is the +// package path, 'pkid' is the hard-coded ID that the compiler is +// using for the package (or -1 if the compiler doesn't think a +// hard-coded ID is needed), and 'cmode'/'cgran' are the coverage +// counter mode and granularity requested by the user. Return value is +// the ID for the package for use by the package code itself, +// or 0 for impossible errors. +func AddMeta(p unsafe.Pointer, dlen uint32, hash [16]byte, pkgpath string, pkgid int, cmode uint8, cgran uint8) uint32 { + slot := len(Meta.List) + Meta.List = append(Meta.List, CovMetaBlob{ + P: (*byte)(p), + Len: dlen, + Hash: hash, + PkgPath: pkgpath, + PkgID: pkgid, + CounterMode: cmode, + CounterGranularity: cgran, + }) + if pkgid != -1 { + if Meta.PkgMap == nil { + Meta.PkgMap = make(map[int]int) + } + if _, ok := Meta.PkgMap[pkgid]; ok { + return 0 + } + // Record the real slot (position on meta-list) for this + // package; we'll use the map to fix things up later on. + Meta.PkgMap[pkgid] = slot + } + + // ID zero is reserved as invalid. + return uint32(slot + 1) +} diff --git a/contrib/go/_std_1.22/src/internal/coverage/rtcov/ya.make b/contrib/go/_std_1.23/src/internal/coverage/rtcov/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/coverage/rtcov/ya.make rename to contrib/go/_std_1.23/src/internal/coverage/rtcov/ya.make diff --git a/contrib/go/_std_1.23/src/internal/cpu/cpu.go b/contrib/go/_std_1.23/src/internal/cpu/cpu.go new file mode 100644 index 000000000000..9be280c6baf0 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/cpu/cpu.go @@ -0,0 +1,238 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cpu implements processor feature detection +// used by the Go standard library. +package cpu + +import _ "unsafe" // for linkname + +// DebugOptions is set to true by the runtime if the OS supports reading +// GODEBUG early in runtime startup. +// This should not be changed after it is initialized. +var DebugOptions bool + +// CacheLinePad is used to pad structs to avoid false sharing. +type CacheLinePad struct{ _ [CacheLinePadSize]byte } + +// CacheLineSize is the CPU's assumed cache line size. +// There is currently no runtime detection of the real cache line size +// so we use the constant per GOARCH CacheLinePadSize as an approximation. +var CacheLineSize uintptr = CacheLinePadSize + +// The booleans in X86 contain the correspondingly named cpuid feature bit. +// HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers +// in addition to the cpuid feature bit being set. +// The struct is padded to avoid false sharing. +var X86 struct { + _ CacheLinePad + HasAES bool + HasADX bool + HasAVX bool + HasAVX2 bool + HasAVX512F bool + HasAVX512BW bool + HasAVX512VL bool + HasBMI1 bool + HasBMI2 bool + HasERMS bool + HasFMA bool + HasOSXSAVE bool + HasPCLMULQDQ bool + HasPOPCNT bool + HasRDTSCP bool + HasSHA bool + HasSSE3 bool + HasSSSE3 bool + HasSSE41 bool + HasSSE42 bool + _ CacheLinePad +} + +// The booleans in ARM contain the correspondingly named cpu feature bit. +// The struct is padded to avoid false sharing. +var ARM struct { + _ CacheLinePad + HasVFPv4 bool + HasIDIVA bool + HasV7Atomics bool + _ CacheLinePad +} + +// The booleans in ARM64 contain the correspondingly named cpu feature bit. +// The struct is padded to avoid false sharing. +var ARM64 struct { + _ CacheLinePad + HasAES bool + HasPMULL bool + HasSHA1 bool + HasSHA2 bool + HasSHA512 bool + HasCRC32 bool + HasATOMICS bool + HasCPUID bool + IsNeoverse bool + _ CacheLinePad +} + +var MIPS64X struct { + _ CacheLinePad + HasMSA bool // MIPS SIMD architecture + _ CacheLinePad +} + +// For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (darn, scv), so there are feature bits for +// those as well. The minimum processor requirement is POWER8 (ISA 2.07). +// The struct is padded to avoid false sharing. +var PPC64 struct { + _ CacheLinePad + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9) + IsPOWER10 bool // ISA v3.1 (POWER10) + _ CacheLinePad +} + +var S390X struct { + _ CacheLinePad + HasZARCH bool // z architecture mode is active [mandatory] + HasSTFLE bool // store facility list extended [mandatory] + HasLDISP bool // long (20-bit) displacements [mandatory] + HasEIMM bool // 32-bit immediates [mandatory] + HasDFP bool // decimal floating point + HasETF3EH bool // ETF-3 enhanced + HasMSA bool // message security assist (CPACF) + HasAES bool // KM-AES{128,192,256} functions + HasAESCBC bool // KMC-AES{128,192,256} functions + HasAESCTR bool // KMCTR-AES{128,192,256} functions + HasAESGCM bool // KMA-GCM-AES{128,192,256} functions + HasGHASH bool // KIMD-GHASH function + HasSHA1 bool // K{I,L}MD-SHA-1 functions + HasSHA256 bool // K{I,L}MD-SHA-256 functions + HasSHA512 bool // K{I,L}MD-SHA-512 functions + HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions + HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. + HasVXE bool // vector-enhancements facility 1 + HasKDSA bool // elliptic curve functions + HasECDSA bool // NIST curves + HasEDDSA bool // Edwards curves + _ CacheLinePad +} + +// CPU feature variables are accessed by assembly code in various packages. +//go:linkname X86 +//go:linkname ARM +//go:linkname ARM64 +//go:linkname MIPS64X +//go:linkname PPC64 +//go:linkname S390X + +// Initialize examines the processor and sets the relevant variables above. +// This is called by the runtime package early in program initialization, +// before normal init functions are run. env is set by runtime if the OS supports +// cpu feature options in GODEBUG. +func Initialize(env string) { + doinit() + processOptions(env) +} + +// options contains the cpu debug options that can be used in GODEBUG. +// Options are arch dependent and are added by the arch specific doinit functions. +// Features that are mandatory for the specific GOARCH should not be added to options +// (e.g. SSE2 on amd64). +var options []option + +// Option names should be lower case. e.g. avx instead of AVX. +type option struct { + Name string + Feature *bool + Specified bool // whether feature value was specified in GODEBUG + Enable bool // whether feature should be enabled +} + +// processOptions enables or disables CPU feature values based on the parsed env string. +// The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2... +// where feature names is one of the architecture specific list stored in the +// cpu packages options variable and values are either 'on' or 'off'. +// If env contains cpu.all=off then all cpu features referenced through the options +// variable are disabled. Other feature names and values result in warning messages. +func processOptions(env string) { +field: + for env != "" { + field := "" + i := indexByte(env, ',') + if i < 0 { + field, env = env, "" + } else { + field, env = env[:i], env[i+1:] + } + if len(field) < 4 || field[:4] != "cpu." { + continue + } + i = indexByte(field, '=') + if i < 0 { + print("GODEBUG: no value specified for \"", field, "\"\n") + continue + } + key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" + + var enable bool + switch value { + case "on": + enable = true + case "off": + enable = false + default: + print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n") + continue field + } + + if key == "all" { + for i := range options { + options[i].Specified = true + options[i].Enable = enable + } + continue field + } + + for i := range options { + if options[i].Name == key { + options[i].Specified = true + options[i].Enable = enable + continue field + } + } + + print("GODEBUG: unknown cpu feature \"", key, "\"\n") + } + + for _, o := range options { + if !o.Specified { + continue + } + + if o.Enable && !*o.Feature { + print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n") + continue + } + + *o.Feature = o.Enable + } +} + +// indexByte returns the index of the first instance of c in s, +// or -1 if c is not present in s. +// indexByte is semantically the same as [strings.IndexByte]. +// We copy this function because "internal/cpu" should not have external dependencies. +func indexByte(s string, c byte) int { + for i := 0; i < len(s); i++ { + if s[i] == c { + return i + } + } + return -1 +} diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu.s b/contrib/go/_std_1.23/src/internal/cpu/cpu.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu.s rename to contrib/go/_std_1.23/src/internal/cpu/cpu.s diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64.s b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64.s rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_android.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_android.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_android.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_android.go diff --git a/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_darwin.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_darwin.go new file mode 100644 index 000000000000..2507780e5f1b --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_darwin.go @@ -0,0 +1,45 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build arm64 && darwin && !ios + +package cpu + +import _ "unsafe" // for linkname + +func osInit() { + ARM64.HasATOMICS = sysctlEnabled([]byte("hw.optional.armv8_1_atomics\x00")) + ARM64.HasCRC32 = sysctlEnabled([]byte("hw.optional.armv8_crc32\x00")) + ARM64.HasSHA512 = sysctlEnabled([]byte("hw.optional.armv8_2_sha512\x00")) + + // There are no hw.optional sysctl values for the below features on Mac OS 11.0 + // to detect their supported state dynamically. Assume the CPU features that + // Apple Silicon M1 supports to be available as a minimal set of features + // to all Go programs running on darwin/arm64. + ARM64.HasAES = true + ARM64.HasPMULL = true + ARM64.HasSHA1 = true + ARM64.HasSHA2 = true +} + +//go:noescape +func getsysctlbyname(name []byte) (int32, int32) + +// sysctlEnabled should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname sysctlEnabled +func sysctlEnabled(name []byte) bool { + ret, value := getsysctlbyname(name) + if ret < 0 { + return false + } + return value > 0 +} diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_freebsd.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_freebsd.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_freebsd.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_hwcap.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_hwcap.go similarity index 85% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_hwcap.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_hwcap.go index 2fabbb6edc36..34edf3eeb2a8 100644 --- a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_hwcap.go +++ b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_hwcap.go @@ -6,8 +6,19 @@ package cpu +import _ "unsafe" // for linkname + // HWCap may be initialized by archauxv and // should not be changed after it was initialized. +// +// Other widely used packages +// access HWCap using linkname as well, most notably: +// - github.com/klauspost/cpuid/v2 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname HWCap var HWCap uint // HWCAP bits. These are exposed by Linux. @@ -48,13 +59,13 @@ func hwcapInit(os string) { if ARM64.HasCPUID { midr := getMIDR() part_num := uint16((midr >> 4) & 0xfff) - implementor := byte((midr >> 24) & 0xff) + implementer := byte((midr >> 24) & 0xff) // d0c - NeoverseN1 // d40 - NeoverseV1 // d49 - NeoverseN2 // d4f - NeoverseV2 - if implementor == 'A' && (part_num == 0xd0c || part_num == 0xd40 || + if implementer == 'A' && (part_num == 0xd0c || part_num == 0xd40 || part_num == 0xd49 || part_num == 0xd4f) { ARM64.IsNeoverse = true } diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_linux.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_linux.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_linux.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_openbsd.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_openbsd.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_openbsd.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_other.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_other.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_other.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_other.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_loong64.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_loong64.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_loong64.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_mips.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_mips.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_mips.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_mips64x.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_mips64x.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_mips64x.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_mipsle.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_mipsle.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_mipsle.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_no_name.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_no_name.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_no_name.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_no_name.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_aix.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_aix.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_aix.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_linux.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_linux.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_linux.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_other.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_other.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_other.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_other.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_riscv64.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_riscv64.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_riscv64.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_s390x.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_s390x.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_s390x.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_s390x.s b/contrib/go/_std_1.23/src/internal/cpu/cpu_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_s390x.s rename to contrib/go/_std_1.23/src/internal/cpu/cpu_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_wasm.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_wasm.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_wasm.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_x86.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_x86.go similarity index 99% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_x86.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_x86.go index f8aa53abeb67..2b629d4da021 100644 --- a/contrib/go/_std_1.22/src/internal/cpu/cpu_x86.go +++ b/contrib/go/_std_1.23/src/internal/cpu/cpu_x86.go @@ -18,9 +18,6 @@ func xgetbv() (eax, edx uint32) func getGOAMD64level() int32 const ( - // edx bits - cpuid_SSE2 = 1 << 26 - // ecx bits cpuid_SSE3 = 1 << 0 cpuid_PCLMULQDQ = 1 << 1 diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_x86.s b/contrib/go/_std_1.23/src/internal/cpu/cpu_x86.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_x86.s rename to contrib/go/_std_1.23/src/internal/cpu/cpu_x86.s diff --git a/contrib/go/_std_1.23/src/internal/cpu/ya.make b/contrib/go/_std_1.23/src/internal/cpu/ya.make new file mode 100644 index 000000000000..cb898ffa8b22 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/cpu/ya.make @@ -0,0 +1,36 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + cpu.go + cpu.s + cpu_arm64.go + cpu_arm64.s + cpu_arm64_darwin.go + cpu_no_name.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + cpu.go + cpu.s + cpu_x86.go + cpu_x86.s + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + cpu.go + cpu.s + cpu_arm64.go + cpu_arm64.s + cpu_arm64_hwcap.go + cpu_arm64_linux.go + cpu_no_name.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + cpu.go + cpu.s + cpu_arm.go + cpu_no_name.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/filepathlite/path.go b/contrib/go/_std_1.23/src/internal/filepathlite/path.go new file mode 100644 index 000000000000..e3daa447d976 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path.go @@ -0,0 +1,274 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package filepathlite implements a subset of path/filepath, +// only using packages which may be imported by "os". +// +// Tests for these functions are in path/filepath. +package filepathlite + +import ( + "errors" + "internal/stringslite" + "io/fs" + "slices" +) + +var errInvalidPath = errors.New("invalid path") + +// A lazybuf is a lazily constructed path buffer. +// It supports append, reading previously appended bytes, +// and retrieving the final string. It does not allocate a buffer +// to hold the output until that output diverges from s. +type lazybuf struct { + path string + buf []byte + w int + volAndPath string + volLen int +} + +func (b *lazybuf) index(i int) byte { + if b.buf != nil { + return b.buf[i] + } + return b.path[i] +} + +func (b *lazybuf) append(c byte) { + if b.buf == nil { + if b.w < len(b.path) && b.path[b.w] == c { + b.w++ + return + } + b.buf = make([]byte, len(b.path)) + copy(b.buf, b.path[:b.w]) + } + b.buf[b.w] = c + b.w++ +} + +func (b *lazybuf) prepend(prefix ...byte) { + b.buf = slices.Insert(b.buf, 0, prefix...) + b.w += len(prefix) +} + +func (b *lazybuf) string() string { + if b.buf == nil { + return b.volAndPath[:b.volLen+b.w] + } + return b.volAndPath[:b.volLen] + string(b.buf[:b.w]) +} + +// Clean is filepath.Clean. +func Clean(path string) string { + originalPath := path + volLen := volumeNameLen(path) + path = path[volLen:] + if path == "" { + if volLen > 1 && IsPathSeparator(originalPath[0]) && IsPathSeparator(originalPath[1]) { + // should be UNC + return FromSlash(originalPath) + } + return originalPath + "." + } + rooted := IsPathSeparator(path[0]) + + // Invariants: + // reading from path; r is index of next byte to process. + // writing to buf; w is index of next byte to write. + // dotdot is index in buf where .. must stop, either because + // it is the leading slash or it is a leading ../../.. prefix. + n := len(path) + out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen} + r, dotdot := 0, 0 + if rooted { + out.append(Separator) + r, dotdot = 1, 1 + } + + for r < n { + switch { + case IsPathSeparator(path[r]): + // empty path element + r++ + case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])): + // . element + r++ + case path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])): + // .. element: remove to last separator + r += 2 + switch { + case out.w > dotdot: + // can backtrack + out.w-- + for out.w > dotdot && !IsPathSeparator(out.index(out.w)) { + out.w-- + } + case !rooted: + // cannot backtrack, but not rooted, so append .. element. + if out.w > 0 { + out.append(Separator) + } + out.append('.') + out.append('.') + dotdot = out.w + } + default: + // real path element. + // add slash if needed + if rooted && out.w != 1 || !rooted && out.w != 0 { + out.append(Separator) + } + // copy element + for ; r < n && !IsPathSeparator(path[r]); r++ { + out.append(path[r]) + } + } + } + + // Turn empty string into "." + if out.w == 0 { + out.append('.') + } + + postClean(&out) // avoid creating absolute paths on Windows + return FromSlash(out.string()) +} + +// IsLocal is filepath.IsLocal. +func IsLocal(path string) bool { + return isLocal(path) +} + +func unixIsLocal(path string) bool { + if IsAbs(path) || path == "" { + return false + } + hasDots := false + for p := path; p != ""; { + var part string + part, p, _ = stringslite.Cut(p, "/") + if part == "." || part == ".." { + hasDots = true + break + } + } + if hasDots { + path = Clean(path) + } + if path == ".." || stringslite.HasPrefix(path, "../") { + return false + } + return true +} + +// Localize is filepath.Localize. +func Localize(path string) (string, error) { + if !fs.ValidPath(path) { + return "", errInvalidPath + } + return localize(path) +} + +// ToSlash is filepath.ToSlash. +func ToSlash(path string) string { + if Separator == '/' { + return path + } + return replaceStringByte(path, Separator, '/') +} + +// FromSlash is filepath.ToSlash. +func FromSlash(path string) string { + if Separator == '/' { + return path + } + return replaceStringByte(path, '/', Separator) +} + +func replaceStringByte(s string, old, new byte) string { + if stringslite.IndexByte(s, old) == -1 { + return s + } + n := []byte(s) + for i := range n { + if n[i] == old { + n[i] = new + } + } + return string(n) +} + +// Split is filepath.Split. +func Split(path string) (dir, file string) { + vol := VolumeName(path) + i := len(path) - 1 + for i >= len(vol) && !IsPathSeparator(path[i]) { + i-- + } + return path[:i+1], path[i+1:] +} + +// Ext is filepath.Ext. +func Ext(path string) string { + for i := len(path) - 1; i >= 0 && !IsPathSeparator(path[i]); i-- { + if path[i] == '.' { + return path[i:] + } + } + return "" +} + +// Base is filepath.Base. +func Base(path string) string { + if path == "" { + return "." + } + // Strip trailing slashes. + for len(path) > 0 && IsPathSeparator(path[len(path)-1]) { + path = path[0 : len(path)-1] + } + // Throw away volume name + path = path[len(VolumeName(path)):] + // Find the last element + i := len(path) - 1 + for i >= 0 && !IsPathSeparator(path[i]) { + i-- + } + if i >= 0 { + path = path[i+1:] + } + // If empty now, it had only slashes. + if path == "" { + return string(Separator) + } + return path +} + +// Dir is filepath.Dir. +func Dir(path string) string { + vol := VolumeName(path) + i := len(path) - 1 + for i >= len(vol) && !IsPathSeparator(path[i]) { + i-- + } + dir := Clean(path[len(vol) : i+1]) + if dir == "." && len(vol) > 2 { + // must be UNC + return vol + } + return vol + dir +} + +// VolumeName is filepath.VolumeName. +func VolumeName(path string) string { + return FromSlash(path[:volumeNameLen(path)]) +} + +// VolumeNameLen returns the length of the leading volume name on Windows. +// It returns 0 elsewhere. +func VolumeNameLen(path string) int { + return volumeNameLen(path) +} diff --git a/contrib/go/_std_1.22/src/path/filepath/path_nonwindows.go b/contrib/go/_std_1.23/src/internal/filepathlite/path_nonwindows.go similarity index 91% rename from contrib/go/_std_1.22/src/path/filepath/path_nonwindows.go rename to contrib/go/_std_1.23/src/internal/filepathlite/path_nonwindows.go index db69f0228b0d..c9c4c02a3da1 100644 --- a/contrib/go/_std_1.22/src/path/filepath/path_nonwindows.go +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path_nonwindows.go @@ -4,6 +4,6 @@ //go:build !windows -package filepath +package filepathlite func postClean(out *lazybuf) {} diff --git a/contrib/go/_std_1.23/src/internal/filepathlite/path_plan9.go b/contrib/go/_std_1.23/src/internal/filepathlite/path_plan9.go new file mode 100644 index 000000000000..5bbb724f9113 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path_plan9.go @@ -0,0 +1,41 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package filepathlite + +import ( + "internal/bytealg" + "internal/stringslite" +) + +const ( + Separator = '/' // OS-specific path separator + ListSeparator = '\000' // OS-specific path list separator +) + +func IsPathSeparator(c uint8) bool { + return Separator == c +} + +func isLocal(path string) bool { + return unixIsLocal(path) +} + +func localize(path string) (string, error) { + if path[0] == '#' || bytealg.IndexByteString(path, 0) >= 0 { + return "", errInvalidPath + } + return path, nil +} + +// IsAbs reports whether the path is absolute. +func IsAbs(path string) bool { + return stringslite.HasPrefix(path, "/") || stringslite.HasPrefix(path, "#") +} + +// volumeNameLen returns length of the leading volume name on Windows. +// It returns 0 elsewhere. +func volumeNameLen(path string) int { + return 0 +} diff --git a/contrib/go/_std_1.23/src/internal/filepathlite/path_unix.go b/contrib/go/_std_1.23/src/internal/filepathlite/path_unix.go new file mode 100644 index 000000000000..e31f1ae74f74 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path_unix.go @@ -0,0 +1,43 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || (js && wasm) || wasip1 + +package filepathlite + +import ( + "internal/bytealg" + "internal/stringslite" +) + +const ( + Separator = '/' // OS-specific path separator + ListSeparator = ':' // OS-specific path list separator +) + +func IsPathSeparator(c uint8) bool { + return Separator == c +} + +func isLocal(path string) bool { + return unixIsLocal(path) +} + +func localize(path string) (string, error) { + if bytealg.IndexByteString(path, 0) >= 0 { + return "", errInvalidPath + } + return path, nil +} + +// IsAbs reports whether the path is absolute. +func IsAbs(path string) bool { + return stringslite.HasPrefix(path, "/") +} + +// volumeNameLen returns length of the leading volume name on Windows. +// It returns 0 elsewhere. +func volumeNameLen(path string) int { + return 0 +} diff --git a/contrib/go/_std_1.23/src/internal/filepathlite/path_windows.go b/contrib/go/_std_1.23/src/internal/filepathlite/path_windows.go new file mode 100644 index 000000000000..8f34838a98c5 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path_windows.go @@ -0,0 +1,329 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package filepathlite + +import ( + "internal/bytealg" + "internal/stringslite" + "syscall" +) + +const ( + Separator = '\\' // OS-specific path separator + ListSeparator = ';' // OS-specific path list separator +) + +func IsPathSeparator(c uint8) bool { + return c == '\\' || c == '/' +} + +func isLocal(path string) bool { + if path == "" { + return false + } + if IsPathSeparator(path[0]) { + // Path rooted in the current drive. + return false + } + if stringslite.IndexByte(path, ':') >= 0 { + // Colons are only valid when marking a drive letter ("C:foo"). + // Rejecting any path with a colon is conservative but safe. + return false + } + hasDots := false // contains . or .. path elements + for p := path; p != ""; { + var part string + part, p, _ = cutPath(p) + if part == "." || part == ".." { + hasDots = true + } + if isReservedName(part) { + return false + } + } + if hasDots { + path = Clean(path) + } + if path == ".." || stringslite.HasPrefix(path, `..\`) { + return false + } + return true +} + +func localize(path string) (string, error) { + for i := 0; i < len(path); i++ { + switch path[i] { + case ':', '\\', 0: + return "", errInvalidPath + } + } + containsSlash := false + for p := path; p != ""; { + // Find the next path element. + var element string + i := bytealg.IndexByteString(p, '/') + if i < 0 { + element = p + p = "" + } else { + containsSlash = true + element = p[:i] + p = p[i+1:] + } + if isReservedName(element) { + return "", errInvalidPath + } + } + if containsSlash { + // We can't depend on strings, so substitute \ for / manually. + buf := []byte(path) + for i, b := range buf { + if b == '/' { + buf[i] = '\\' + } + } + path = string(buf) + } + return path, nil +} + +// isReservedName reports if name is a Windows reserved device name. +// It does not detect names with an extension, which are also reserved on some Windows versions. +// +// For details, search for PRN in +// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. +func isReservedName(name string) bool { + // Device names can have arbitrary trailing characters following a dot or colon. + base := name + for i := 0; i < len(base); i++ { + switch base[i] { + case ':', '.': + base = base[:i] + } + } + // Trailing spaces in the last path element are ignored. + for len(base) > 0 && base[len(base)-1] == ' ' { + base = base[:len(base)-1] + } + if !isReservedBaseName(base) { + return false + } + if len(base) == len(name) { + return true + } + // The path element is a reserved name with an extension. + // Some Windows versions consider this a reserved name, + // while others do not. Use FullPath to see if the name is + // reserved. + if p, _ := syscall.FullPath(name); len(p) >= 4 && p[:4] == `\\.\` { + return true + } + return false +} + +func isReservedBaseName(name string) bool { + if len(name) == 3 { + switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { + case "CON", "PRN", "AUX", "NUL": + return true + } + } + if len(name) >= 4 { + switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { + case "COM", "LPT": + if len(name) == 4 && '1' <= name[3] && name[3] <= '9' { + return true + } + // Superscript ¹, ², and ³ are considered numbers as well. + switch name[3:] { + case "\u00b2", "\u00b3", "\u00b9": + return true + } + return false + } + } + + // Passing CONIN$ or CONOUT$ to CreateFile opens a console handle. + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#consoles + // + // While CONIN$ and CONOUT$ aren't documented as being files, + // they behave the same as CON. For example, ./CONIN$ also opens the console input. + if len(name) == 6 && name[5] == '$' && equalFold(name, "CONIN$") { + return true + } + if len(name) == 7 && name[6] == '$' && equalFold(name, "CONOUT$") { + return true + } + return false +} + +func equalFold(a, b string) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if toUpper(a[i]) != toUpper(b[i]) { + return false + } + } + return true +} + +func toUpper(c byte) byte { + if 'a' <= c && c <= 'z' { + return c - ('a' - 'A') + } + return c +} + +// IsAbs reports whether the path is absolute. +func IsAbs(path string) (b bool) { + l := volumeNameLen(path) + if l == 0 { + return false + } + // If the volume name starts with a double slash, this is an absolute path. + if IsPathSeparator(path[0]) && IsPathSeparator(path[1]) { + return true + } + path = path[l:] + if path == "" { + return false + } + return IsPathSeparator(path[0]) +} + +// volumeNameLen returns length of the leading volume name on Windows. +// It returns 0 elsewhere. +// +// See: +// https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats +// https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html +func volumeNameLen(path string) int { + switch { + case len(path) >= 2 && path[1] == ':': + // Path starts with a drive letter. + // + // Not all Windows functions necessarily enforce the requirement that + // drive letters be in the set A-Z, and we don't try to here. + // + // We don't handle the case of a path starting with a non-ASCII character, + // in which case the "drive letter" might be multiple bytes long. + return 2 + + case len(path) == 0 || !IsPathSeparator(path[0]): + // Path does not have a volume component. + return 0 + + case pathHasPrefixFold(path, `\\.\UNC`): + // We're going to treat the UNC host and share as part of the volume + // prefix for historical reasons, but this isn't really principled; + // Windows's own GetFullPathName will happily remove the first + // component of the path in this space, converting + // \\.\unc\a\b\..\c into \\.\unc\a\c. + return uncLen(path, len(`\\.\UNC\`)) + + case pathHasPrefixFold(path, `\\.`) || + pathHasPrefixFold(path, `\\?`) || pathHasPrefixFold(path, `\??`): + // Path starts with \\.\, and is a Local Device path; or + // path starts with \\?\ or \??\ and is a Root Local Device path. + // + // We treat the next component after the \\.\ prefix as + // part of the volume name, which means Clean(`\\?\c:\`) + // won't remove the trailing \. (See #64028.) + if len(path) == 3 { + return 3 // exactly \\. + } + _, rest, ok := cutPath(path[4:]) + if !ok { + return len(path) + } + return len(path) - len(rest) - 1 + + case len(path) >= 2 && IsPathSeparator(path[1]): + // Path starts with \\, and is a UNC path. + return uncLen(path, 2) + } + return 0 +} + +// pathHasPrefixFold tests whether the path s begins with prefix, +// ignoring case and treating all path separators as equivalent. +// If s is longer than prefix, then s[len(prefix)] must be a path separator. +func pathHasPrefixFold(s, prefix string) bool { + if len(s) < len(prefix) { + return false + } + for i := 0; i < len(prefix); i++ { + if IsPathSeparator(prefix[i]) { + if !IsPathSeparator(s[i]) { + return false + } + } else if toUpper(prefix[i]) != toUpper(s[i]) { + return false + } + } + if len(s) > len(prefix) && !IsPathSeparator(s[len(prefix)]) { + return false + } + return true +} + +// uncLen returns the length of the volume prefix of a UNC path. +// prefixLen is the prefix prior to the start of the UNC host; +// for example, for "//host/share", the prefixLen is len("//")==2. +func uncLen(path string, prefixLen int) int { + count := 0 + for i := prefixLen; i < len(path); i++ { + if IsPathSeparator(path[i]) { + count++ + if count == 2 { + return i + } + } + } + return len(path) +} + +// cutPath slices path around the first path separator. +func cutPath(path string) (before, after string, found bool) { + for i := range path { + if IsPathSeparator(path[i]) { + return path[:i], path[i+1:], true + } + } + return path, "", false +} + +// isUNC reports whether path is a UNC path. +func isUNC(path string) bool { + return len(path) > 1 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) +} + +// postClean adjusts the results of Clean to avoid turning a relative path +// into an absolute or rooted one. +func postClean(out *lazybuf) { + if out.volLen != 0 || out.buf == nil { + return + } + // If a ':' appears in the path element at the start of a path, + // insert a .\ at the beginning to avoid converting relative paths + // like a/../c: into c:. + for _, c := range out.buf { + if IsPathSeparator(c) { + break + } + if c == ':' { + out.prepend('.', Separator) + return + } + } + // If a path begins with \??\, insert a \. at the beginning + // to avoid converting paths like \a\..\??\c:\x into \??\c:\x + // (equivalent to c:\x). + if len(out.buf) >= 3 && IsPathSeparator(out.buf[0]) && out.buf[1] == '?' && out.buf[2] == '?' { + out.prepend(Separator, '.') + } +} diff --git a/contrib/go/_std_1.23/src/internal/filepathlite/ya.make b/contrib/go/_std_1.23/src/internal/filepathlite/ya.make new file mode 100644 index 000000000000..78f62dff429a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/filepathlite/ya.make @@ -0,0 +1,14 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + path.go + path_nonwindows.go + path_unix.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + path.go + path_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/fmtsort/sort.go b/contrib/go/_std_1.23/src/internal/fmtsort/sort.go new file mode 100644 index 000000000000..f51cdc7083a4 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/fmtsort/sort.go @@ -0,0 +1,154 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package fmtsort provides a general stable ordering mechanism +// for maps, on behalf of the fmt and text/template packages. +// It is not guaranteed to be efficient and works only for types +// that are valid map keys. +package fmtsort + +import ( + "cmp" + "reflect" + "slices" +) + +// Note: Throughout this package we avoid calling reflect.Value.Interface as +// it is not always legal to do so and it's easier to avoid the issue than to face it. + +// SortedMap is a slice of KeyValue pairs that simplifies sorting +// and iterating over map entries. +// +// Each KeyValue pair contains a map key and its corresponding value. +type SortedMap []KeyValue + +// KeyValue holds a single key and value pair found in a map. +type KeyValue struct { + Key, Value reflect.Value +} + +// Sort accepts a map and returns a SortedMap that has the same keys and +// values but in a stable sorted order according to the keys, modulo issues +// raised by unorderable key values such as NaNs. +// +// The ordering rules are more general than with Go's < operator: +// +// - when applicable, nil compares low +// - ints, floats, and strings order by < +// - NaN compares less than non-NaN floats +// - bool compares false before true +// - complex compares real, then imag +// - pointers compare by machine address +// - channel values compare by machine address +// - structs compare each field in turn +// - arrays compare each element in turn. +// Otherwise identical arrays compare by length. +// - interface values compare first by reflect.Type describing the concrete type +// and then by concrete value as described in the previous rules. +func Sort(mapValue reflect.Value) SortedMap { + if mapValue.Type().Kind() != reflect.Map { + return nil + } + // Note: this code is arranged to not panic even in the presence + // of a concurrent map update. The runtime is responsible for + // yelling loudly if that happens. See issue 33275. + n := mapValue.Len() + sorted := make(SortedMap, 0, n) + iter := mapValue.MapRange() + for iter.Next() { + sorted = append(sorted, KeyValue{iter.Key(), iter.Value()}) + } + slices.SortStableFunc(sorted, func(a, b KeyValue) int { + return compare(a.Key, b.Key) + }) + return sorted +} + +// compare compares two values of the same type. It returns -1, 0, 1 +// according to whether a > b (1), a == b (0), or a < b (-1). +// If the types differ, it returns -1. +// See the comment on Sort for the comparison rules. +func compare(aVal, bVal reflect.Value) int { + aType, bType := aVal.Type(), bVal.Type() + if aType != bType { + return -1 // No good answer possible, but don't return 0: they're not equal. + } + switch aVal.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return cmp.Compare(aVal.Int(), bVal.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return cmp.Compare(aVal.Uint(), bVal.Uint()) + case reflect.String: + return cmp.Compare(aVal.String(), bVal.String()) + case reflect.Float32, reflect.Float64: + return cmp.Compare(aVal.Float(), bVal.Float()) + case reflect.Complex64, reflect.Complex128: + a, b := aVal.Complex(), bVal.Complex() + if c := cmp.Compare(real(a), real(b)); c != 0 { + return c + } + return cmp.Compare(imag(a), imag(b)) + case reflect.Bool: + a, b := aVal.Bool(), bVal.Bool() + switch { + case a == b: + return 0 + case a: + return 1 + default: + return -1 + } + case reflect.Pointer, reflect.UnsafePointer: + return cmp.Compare(aVal.Pointer(), bVal.Pointer()) + case reflect.Chan: + if c, ok := nilCompare(aVal, bVal); ok { + return c + } + return cmp.Compare(aVal.Pointer(), bVal.Pointer()) + case reflect.Struct: + for i := 0; i < aVal.NumField(); i++ { + if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 { + return c + } + } + return 0 + case reflect.Array: + for i := 0; i < aVal.Len(); i++ { + if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 { + return c + } + } + return 0 + case reflect.Interface: + if c, ok := nilCompare(aVal, bVal); ok { + return c + } + c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type())) + if c != 0 { + return c + } + return compare(aVal.Elem(), bVal.Elem()) + default: + // Certain types cannot appear as keys (maps, funcs, slices), but be explicit. + panic("bad type in compare: " + aType.String()) + } +} + +// nilCompare checks whether either value is nil. If not, the boolean is false. +// If either value is nil, the boolean is true and the integer is the comparison +// value. The comparison is defined to be 0 if both are nil, otherwise the one +// nil value compares low. Both arguments must represent a chan, func, +// interface, map, pointer, or slice. +func nilCompare(aVal, bVal reflect.Value) (int, bool) { + if aVal.IsNil() { + if bVal.IsNil() { + return 0, true + } + return -1, true + } + if bVal.IsNil() { + return 1, true + } + return 0, false +} diff --git a/contrib/go/_std_1.22/src/internal/fmtsort/ya.make b/contrib/go/_std_1.23/src/internal/fmtsort/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/fmtsort/ya.make rename to contrib/go/_std_1.23/src/internal/fmtsort/ya.make diff --git a/contrib/go/_std_1.22/src/internal/goarch/gengoarch.go b/contrib/go/_std_1.23/src/internal/goarch/gengoarch.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/gengoarch.go rename to contrib/go/_std_1.23/src/internal/goarch/gengoarch.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch.go b/contrib/go/_std_1.23/src/internal/goarch/goarch.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_386.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_386.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_386.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_386.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_amd64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_amd64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_amd64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_arm.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_arm.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_arm.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_arm64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_arm64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_arm64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_loong64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_loong64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_loong64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_mips.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_mips.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_mips.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_mips64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_mips64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_mips64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_mips64le.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_mips64le.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_mips64le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_mipsle.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_mipsle.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_mipsle.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_ppc64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_ppc64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_ppc64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_ppc64le.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_ppc64le.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_ppc64le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_riscv64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_riscv64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_riscv64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_s390x.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_s390x.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_s390x.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_wasm.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_wasm.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_wasm.go diff --git a/contrib/go/_std_1.23/src/internal/goarch/ya.make b/contrib/go/_std_1.23/src/internal/goarch/ya.make new file mode 100644 index 000000000000..f831647324b1 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/goarch/ya.make @@ -0,0 +1,21 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + goarch.go + goarch_arm64.go + zgoarch_arm64.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + goarch.go + goarch_amd64.go + zgoarch_amd64.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + goarch.go + goarch_arm.go + zgoarch_arm.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_386.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_386.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_386.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_386.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_amd64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_amd64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_amd64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm64be.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm64be.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm64be.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm64be.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_armbe.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_armbe.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_armbe.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_armbe.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_loong64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_loong64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_loong64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64le.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64le.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64p32.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64p32.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64p32.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64p32.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64p32le.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64p32le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64p32le.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64p32le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mipsle.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mipsle.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mipsle.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc64le.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc64le.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc64le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_riscv.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_riscv.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_riscv.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_riscv.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_riscv64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_riscv64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_riscv64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_s390.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_s390.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_s390.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_s390.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_s390x.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_s390x.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_s390x.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_sparc.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_sparc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_sparc.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_sparc.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_sparc64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_sparc64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_sparc64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_sparc64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_wasm.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_wasm.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_wasm.go diff --git a/contrib/go/_std_1.22/src/internal/godebug/godebug.go b/contrib/go/_std_1.23/src/internal/godebug/godebug.go similarity index 88% rename from contrib/go/_std_1.22/src/internal/godebug/godebug.go rename to contrib/go/_std_1.23/src/internal/godebug/godebug.go index 36bfeaccc421..0756d313e6b9 100644 --- a/contrib/go/_std_1.22/src/internal/godebug/godebug.go +++ b/contrib/go/_std_1.23/src/internal/godebug/godebug.go @@ -22,8 +22,23 @@ // } // // Each time a non-default setting causes a change in program behavior, -// code should call [Setting.IncNonDefault] to increment a counter that can -// be reported by [runtime/metrics.Read]. +// code must call [Setting.IncNonDefault] to increment a counter that can +// be reported by [runtime/metrics.Read]. The call must only happen when +// the program executes a non-default behavior, not just when the setting +// is set to a non-default value. This is occasionally (but very rarely) +// infeasible, in which case the internal/godebugs table entry must set +// Opaque: true, and the documentation in doc/godebug.md should +// mention that metrics are unavailable. +// +// Conventionally, the global variable representing a godebug is named +// for the godebug itself, with no case changes: +// +// var gotypesalias = godebug.New("gotypesalias") // this +// var goTypesAlias = godebug.New("gotypesalias") // NOT THIS +// +// The test in internal/godebugs that checks for use of IncNonDefault +// requires the use of this convention. +// // Note that counters used with IncNonDefault must be added to // various tables in other packages. See the [Setting.IncNonDefault] // documentation for details. @@ -70,6 +85,11 @@ type value struct { // To disable that panic for access to an undocumented setting, // prefix the name with a #, as in godebug.New("#gofsystrace"). // The # is a signal to New but not part of the key used in $GODEBUG. +// +// Note that almost all settings should arrange to call [IncNonDefault] precisely +// when program behavior is changing from the default due to the setting +// (not just when the setting is different, but when program behavior changes). +// See the [internal/godebug] package comment for more. func New(name string) *Setting { return &Setting{name: name} } diff --git a/contrib/go/_std_1.22/src/internal/godebug/ya.make b/contrib/go/_std_1.23/src/internal/godebug/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/godebug/ya.make rename to contrib/go/_std_1.23/src/internal/godebug/ya.make diff --git a/contrib/go/_std_1.22/src/internal/godebugs/table.go b/contrib/go/_std_1.23/src/internal/godebugs/table.go similarity index 80% rename from contrib/go/_std_1.22/src/internal/godebugs/table.go rename to contrib/go/_std_1.23/src/internal/godebugs/table.go index 11c5b7d6fdb9..473a0992df89 100644 --- a/contrib/go/_std_1.22/src/internal/godebugs/table.go +++ b/contrib/go/_std_1.23/src/internal/godebugs/table.go @@ -25,18 +25,20 @@ type Info struct { // Note: After adding entries to this table, update the list in doc/godebug.md as well. // (Otherwise the test in this package will fail.) var All = []Info{ + {Name: "asynctimerchan", Package: "time", Changed: 23, Old: "1"}, {Name: "execerrdot", Package: "os/exec"}, {Name: "gocachehash", Package: "cmd/go"}, {Name: "gocachetest", Package: "cmd/go"}, {Name: "gocacheverify", Package: "cmd/go"}, - {Name: "gotypesalias", Package: "go/types"}, + {Name: "gotypesalias", Package: "go/types", Changed: 23, Old: "0"}, {Name: "http2client", Package: "net/http"}, {Name: "http2debug", Package: "net/http", Opaque: true}, {Name: "http2server", Package: "net/http"}, {Name: "httplaxcontentlength", Package: "net/http", Changed: 22, Old: "1"}, {Name: "httpmuxgo121", Package: "net/http", Changed: 22, Old: "1"}, + {Name: "httpservecontentkeepheaders", Package: "net/http", Changed: 23, Old: "1"}, {Name: "installgoroot", Package: "go/build"}, - {Name: "jstmpllitinterp", Package: "html/template"}, + {Name: "jstmpllitinterp", Package: "html/template", Opaque: true}, // bug #66217: remove Opaque //{Name: "multipartfiles", Package: "mime/multipart"}, {Name: "multipartmaxheaders", Package: "mime/multipart"}, {Name: "multipartmaxparts", Package: "mime/multipart"}, @@ -47,9 +49,15 @@ var All = []Info{ {Name: "randautoseed", Package: "math/rand"}, {Name: "tarinsecurepath", Package: "archive/tar"}, {Name: "tls10server", Package: "crypto/tls", Changed: 22, Old: "1"}, + {Name: "tls3des", Package: "crypto/tls", Changed: 23, Old: "1"}, + {Name: "tlskyber", Package: "crypto/tls", Changed: 23, Old: "0", Opaque: true}, {Name: "tlsmaxrsasize", Package: "crypto/tls"}, {Name: "tlsrsakex", Package: "crypto/tls", Changed: 22, Old: "1"}, {Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"}, + {Name: "winreadlinkvolume", Package: "os", Changed: 23, Old: "0"}, + {Name: "winsymlink", Package: "os", Changed: 23, Old: "0"}, + {Name: "x509keypairleaf", Package: "crypto/tls", Changed: 23, Old: "0"}, + {Name: "x509negativeserial", Package: "crypto/x509", Changed: 23, Old: "1"}, {Name: "x509sha1", Package: "crypto/x509"}, {Name: "x509usefallbackroots", Package: "crypto/x509"}, {Name: "x509usepolicies", Package: "crypto/x509"}, diff --git a/contrib/go/_std_1.22/src/internal/godebugs/ya.make b/contrib/go/_std_1.23/src/internal/godebugs/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/godebugs/ya.make rename to contrib/go/_std_1.23/src/internal/godebugs/ya.make diff --git a/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_off.go new file mode 100644 index 000000000000..620d34ec795a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_off.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build !goexperiment.aliastypeparams + +package goexperiment + +const AliasTypeParams = false +const AliasTypeParamsInt = 0 diff --git a/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_on.go new file mode 100644 index 000000000000..8f6872cdcd36 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_on.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build goexperiment.aliastypeparams + +package goexperiment + +const AliasTypeParams = true +const AliasTypeParamsInt = 1 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_arenas_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_arenas_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_arenas_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_arenas_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_arenas_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_arenas_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_arenas_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_arenas_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_boringcrypto_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_boringcrypto_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_boringcrypto_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_boringcrypto_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_boringcrypto_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_boringcrypto_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_boringcrypto_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_boringcrypto_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_cacheprog_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_cacheprog_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_cacheprog_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_cacheprog_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_cacheprog_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_cacheprog_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_cacheprog_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_cacheprog_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_cgocheck2_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_cgocheck2_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_cgocheck2_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_cgocheck2_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_cgocheck2_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_cgocheck2_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_cgocheck2_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_cgocheck2_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_coverageredesign_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_coverageredesign_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_coverageredesign_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_coverageredesign_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_coverageredesign_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_coverageredesign_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_coverageredesign_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_coverageredesign_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_fieldtrack_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_fieldtrack_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_fieldtrack_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_fieldtrack_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_fieldtrack_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_fieldtrack_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_fieldtrack_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_fieldtrack_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_heapminimum512kib_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_heapminimum512kib_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_heapminimum512kib_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_heapminimum512kib_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_heapminimum512kib_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_heapminimum512kib_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_heapminimum512kib_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_heapminimum512kib_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_loopvar_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_loopvar_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_loopvar_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_loopvar_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_loopvar_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_loopvar_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_loopvar_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_loopvar_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_newinliner_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_newinliner_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_newinliner_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_newinliner_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_newinliner_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_newinliner_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_newinliner_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_newinliner_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_preemptibleloops_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_preemptibleloops_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_preemptibleloops_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_preemptibleloops_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_preemptibleloops_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_preemptibleloops_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_preemptibleloops_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_preemptibleloops_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_rangefunc_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_rangefunc_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_rangefunc_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_rangefunc_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_rangefunc_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_rangefunc_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_rangefunc_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_rangefunc_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiargs_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiargs_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiargs_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiargs_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiargs_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiargs_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiargs_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiargs_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiwrappers_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiwrappers_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiwrappers_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiwrappers_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiwrappers_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiwrappers_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiwrappers_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiwrappers_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_staticlockranking_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_staticlockranking_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_staticlockranking_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_staticlockranking_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_staticlockranking_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_staticlockranking_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_staticlockranking_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_staticlockranking_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/flags.go b/contrib/go/_std_1.23/src/internal/goexperiment/flags.go similarity index 88% rename from contrib/go/_std_1.22/src/internal/goexperiment/flags.go rename to contrib/go/_std_1.23/src/internal/goexperiment/flags.go index dacc4c3b1357..3f9c5af68e36 100644 --- a/contrib/go/_std_1.22/src/internal/goexperiment/flags.go +++ b/contrib/go/_std_1.23/src/internal/goexperiment/flags.go @@ -91,12 +91,6 @@ type Flags struct { // to the outside world. Arenas bool - // PageTrace enables GODEBUG=pagetrace=/path/to/result. This feature - // is a GOEXPERIMENT due to a security risk with setuid binaries: - // this compels the Go runtime to write to some arbitrary file, which - // may be exploited. - PageTrace bool - // CgoCheck2 enables an expensive cgo rule checker. // When this experiment is enabled, cgo rule checks occur regardless // of the GODEBUG=cgocheck setting provided at runtime. @@ -117,14 +111,8 @@ type Flags struct { // RangeFunc enables range over func. RangeFunc bool - // Range enables range over int and func. - Range bool - - // AllocHeaders enables a different, more efficient way for the GC to - // manage heap metadata. - AllocHeaders bool - - // ExecTracer2 controls whether to use the new execution trace - // implementation. - ExecTracer2 bool + // AliasTypeParams enables type parameters for alias types. + // Requires that gotypesalias=1 is set with GODEBUG. + // This flag will be removed with Go 1.24. + AliasTypeParams bool } diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/mkconsts.go b/contrib/go/_std_1.23/src/internal/goexperiment/mkconsts.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/mkconsts.go rename to contrib/go/_std_1.23/src/internal/goexperiment/mkconsts.go diff --git a/contrib/go/_std_1.23/src/internal/goexperiment/ya.make b/contrib/go/_std_1.23/src/internal/goexperiment/ya.make new file mode 100644 index 000000000000..8009d90e8ba0 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/goexperiment/ya.make @@ -0,0 +1,22 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + exp_aliastypeparams_off.go + exp_arenas_off.go + exp_boringcrypto_off.go + exp_cacheprog_off.go + exp_cgocheck2_off.go + exp_coverageredesign_off.go + exp_fieldtrack_off.go + exp_heapminimum512kib_off.go + exp_loopvar_off.go + exp_newinliner_off.go + exp_preemptibleloops_off.go + exp_rangefunc_off.go + exp_regabiargs_off.go + exp_regabiwrappers_off.go + exp_staticlockranking_off.go + flags.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/goos/gengoos.go b/contrib/go/_std_1.23/src/internal/goos/gengoos.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/gengoos.go rename to contrib/go/_std_1.23/src/internal/goos/gengoos.go diff --git a/contrib/go/_std_1.22/src/internal/goos/goos.go b/contrib/go/_std_1.23/src/internal/goos/goos.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/goos.go rename to contrib/go/_std_1.23/src/internal/goos/goos.go diff --git a/contrib/go/_std_1.22/src/internal/goos/nonunix.go b/contrib/go/_std_1.23/src/internal/goos/nonunix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/nonunix.go rename to contrib/go/_std_1.23/src/internal/goos/nonunix.go diff --git a/contrib/go/_std_1.22/src/internal/goos/unix.go b/contrib/go/_std_1.23/src/internal/goos/unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/unix.go rename to contrib/go/_std_1.23/src/internal/goos/unix.go diff --git a/contrib/go/_std_1.23/src/internal/goos/ya.make b/contrib/go/_std_1.23/src/internal/goos/ya.make new file mode 100644 index 000000000000..df77329e0f12 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/goos/ya.make @@ -0,0 +1,21 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + goos.go + unix.go + zgoos_darwin.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + goos.go + unix.go + zgoos_linux.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + goos.go + nonunix.go + zgoos_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_aix.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_aix.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_aix.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_android.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_android.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_android.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_android.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_darwin.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_darwin.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_darwin.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_dragonfly.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_dragonfly.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_dragonfly.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_freebsd.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_freebsd.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_freebsd.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_hurd.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_hurd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_hurd.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_hurd.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_illumos.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_illumos.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_illumos.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_illumos.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_ios.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_ios.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_ios.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_ios.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_js.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_js.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_js.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_linux.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_linux.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_linux.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_netbsd.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_netbsd.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_netbsd.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_openbsd.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_openbsd.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_openbsd.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_plan9.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_plan9.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_plan9.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_solaris.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_solaris.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_solaris.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_wasip1.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_wasip1.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_wasip1.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_windows.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_windows.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_windows.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_zos.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_zos.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_zos.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_zos.go diff --git a/contrib/go/_std_1.22/src/internal/gover/gover.go b/contrib/go/_std_1.23/src/internal/gover/gover.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/gover/gover.go rename to contrib/go/_std_1.23/src/internal/gover/gover.go diff --git a/contrib/go/_std_1.22/src/internal/gover/ya.make b/contrib/go/_std_1.23/src/internal/gover/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/gover/ya.make rename to contrib/go/_std_1.23/src/internal/gover/ya.make diff --git a/contrib/go/_std_1.22/src/internal/goversion/goversion.go b/contrib/go/_std_1.23/src/internal/goversion/goversion.go similarity index 95% rename from contrib/go/_std_1.22/src/internal/goversion/goversion.go rename to contrib/go/_std_1.23/src/internal/goversion/goversion.go index 770ef113561e..a9d6f12ee14d 100644 --- a/contrib/go/_std_1.22/src/internal/goversion/goversion.go +++ b/contrib/go/_std_1.23/src/internal/goversion/goversion.go @@ -9,4 +9,4 @@ package goversion // // It should be updated at the start of each development cycle to be // the version of the next Go 1.x release. See golang.org/issue/40705. -const Version = 22 +const Version = 23 diff --git a/contrib/go/_std_1.22/src/internal/goversion/ya.make b/contrib/go/_std_1.23/src/internal/goversion/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/goversion/ya.make rename to contrib/go/_std_1.23/src/internal/goversion/ya.make diff --git a/contrib/go/_std_1.22/src/internal/itoa/itoa.go b/contrib/go/_std_1.23/src/internal/itoa/itoa.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/itoa/itoa.go rename to contrib/go/_std_1.23/src/internal/itoa/itoa.go diff --git a/contrib/go/_std_1.22/src/internal/itoa/ya.make b/contrib/go/_std_1.23/src/internal/itoa/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/itoa/ya.make rename to contrib/go/_std_1.23/src/internal/itoa/ya.make diff --git a/contrib/go/_std_1.23/src/internal/msan/doc.go b/contrib/go/_std_1.23/src/internal/msan/doc.go new file mode 100644 index 000000000000..e68d341e7ad2 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/msan/doc.go @@ -0,0 +1,9 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package msan contains helper functions for manually instrumenting code +// for the memory sanitizer. +// This package exports the private msan routines in runtime unconditionally +// but without the "msan" build tag they are no-ops. +package msan diff --git a/contrib/go/_std_1.23/src/internal/msan/msan.go b/contrib/go/_std_1.23/src/internal/msan/msan.go new file mode 100644 index 000000000000..518153ee5a91 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/msan/msan.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build msan + +package msan + +import ( + "unsafe" +) + +const Enabled = true + +//go:linkname Read runtime.msanread +func Read(addr unsafe.Pointer, sz uintptr) + +//go:linkname Write runtime.msanwrite +func Write(addr unsafe.Pointer, sz uintptr) + +//go:linkname Malloc runtime.msanmalloc +func Malloc(addr unsafe.Pointer, sz uintptr) + +//go:linkname Free runtime.msanfree +func Free(addr unsafe.Pointer, sz uintptr) + +//go:linkname Move runtime.msanmove +func Move(dst, src unsafe.Pointer, sz uintptr) diff --git a/contrib/go/_std_1.23/src/internal/msan/nomsan.go b/contrib/go/_std_1.23/src/internal/msan/nomsan.go new file mode 100644 index 000000000000..3dccda3ffd4a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/msan/nomsan.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !msan + +package msan + +import ( + "unsafe" +) + +const Enabled = false + +func Read(addr unsafe.Pointer, sz uintptr) { +} + +func Write(addr unsafe.Pointer, sz uintptr) { +} + +func Malloc(addr unsafe.Pointer, sz uintptr) { +} + +func Free(addr unsafe.Pointer, sz uintptr) { +} + +func Move(dst, src unsafe.Pointer, sz uintptr) { +} diff --git a/contrib/go/_std_1.23/src/internal/msan/ya.make b/contrib/go/_std_1.23/src/internal/msan/ya.make new file mode 100644 index 000000000000..6ef64ba5f992 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/msan/ya.make @@ -0,0 +1,8 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + doc.go + nomsan.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/nettrace/nettrace.go b/contrib/go/_std_1.23/src/internal/nettrace/nettrace.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/nettrace/nettrace.go rename to contrib/go/_std_1.23/src/internal/nettrace/nettrace.go diff --git a/contrib/go/_std_1.22/src/internal/nettrace/ya.make b/contrib/go/_std_1.23/src/internal/nettrace/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/nettrace/ya.make rename to contrib/go/_std_1.23/src/internal/nettrace/ya.make diff --git a/contrib/go/_std_1.22/src/internal/oserror/errors.go b/contrib/go/_std_1.23/src/internal/oserror/errors.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/oserror/errors.go rename to contrib/go/_std_1.23/src/internal/oserror/errors.go diff --git a/contrib/go/_std_1.22/src/internal/oserror/ya.make b/contrib/go/_std_1.23/src/internal/oserror/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/oserror/ya.make rename to contrib/go/_std_1.23/src/internal/oserror/ya.make diff --git a/contrib/go/_std_1.22/src/internal/poll/copy_file_range_linux.go b/contrib/go/_std_1.23/src/internal/poll/copy_file_range_linux.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/poll/copy_file_range_linux.go rename to contrib/go/_std_1.23/src/internal/poll/copy_file_range_linux.go index ba33f5145d48..3d51333d73e9 100644 --- a/contrib/go/_std_1.22/src/internal/poll/copy_file_range_linux.go +++ b/contrib/go/_std_1.23/src/internal/poll/copy_file_range_linux.go @@ -10,27 +10,20 @@ import ( "syscall" ) -var ( - kernelVersion53Once sync.Once - kernelVersion53 bool -) +var isKernelVersionGE53 = sync.OnceValue(func() bool { + major, minor := unix.KernelVersion() + // copy_file_range(2) is broken in various ways on kernels older than 5.3, + // see https://go.dev/issue/42400 and + // https://man7.org/linux/man-pages/man2/copy_file_range.2.html#VERSIONS + return major > 5 || (major == 5 && minor >= 3) +}) const maxCopyFileRangeRound = 1 << 30 // CopyFileRange copies at most remain bytes of data from src to dst, using // the copy_file_range system call. dst and src must refer to regular files. func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err error) { - kernelVersion53Once.Do(func() { - major, minor := unix.KernelVersion() - // copy_file_range(2) is broken in various ways on kernels older than 5.3, - // see issue #42400 and - // https://man7.org/linux/man-pages/man2/copy_file_range.2.html#VERSIONS - if major > 5 || (major == 5 && minor >= 3) { - kernelVersion53 = true - } - }) - - if !kernelVersion53 { + if !isKernelVersionGE53() { return 0, false, nil } diff --git a/contrib/go/_std_1.22/src/internal/poll/errno_unix.go b/contrib/go/_std_1.23/src/internal/poll/errno_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/errno_unix.go rename to contrib/go/_std_1.23/src/internal/poll/errno_unix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/errno_windows.go b/contrib/go/_std_1.23/src/internal/poll/errno_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/errno_windows.go rename to contrib/go/_std_1.23/src/internal/poll/errno_windows.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd.go b/contrib/go/_std_1.23/src/internal/poll/fd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd.go rename to contrib/go/_std_1.23/src/internal/poll/fd.go diff --git a/contrib/go/_std_1.23/src/internal/poll/fd_fsync_darwin.go b/contrib/go/_std_1.23/src/internal/poll/fd_fsync_darwin.go new file mode 100644 index 000000000000..e55b490d41a4 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/fd_fsync_darwin.go @@ -0,0 +1,32 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll + +import ( + "errors" + "internal/syscall/unix" + "syscall" +) + +// Fsync invokes SYS_FCNTL with SYS_FULLFSYNC because +// on OS X, SYS_FSYNC doesn't fully flush contents to disk. +// See Issue #26650 as well as the man page for fsync on OS X. +func (fd *FD) Fsync() error { + if err := fd.incref(); err != nil { + return err + } + defer fd.decref() + return ignoringEINTR(func() error { + _, err := unix.Fcntl(fd.Sysfd, syscall.F_FULLFSYNC, 0) + + // There are scenarios such as SMB mounts where fcntl will fail + // with ENOTSUP. In those cases fallback to fsync. + // See #64215 + if err != nil && errors.Is(err, syscall.ENOTSUP) { + err = syscall.Fsync(fd.Sysfd) + } + return err + }) +} diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_fsync_posix.go b/contrib/go/_std_1.23/src/internal/poll/fd_fsync_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_fsync_posix.go rename to contrib/go/_std_1.23/src/internal/poll/fd_fsync_posix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_fsync_windows.go b/contrib/go/_std_1.23/src/internal/poll/fd_fsync_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_fsync_windows.go rename to contrib/go/_std_1.23/src/internal/poll/fd_fsync_windows.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_io_plan9.go b/contrib/go/_std_1.23/src/internal/poll/fd_io_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_io_plan9.go rename to contrib/go/_std_1.23/src/internal/poll/fd_io_plan9.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_mutex.go b/contrib/go/_std_1.23/src/internal/poll/fd_mutex.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_mutex.go rename to contrib/go/_std_1.23/src/internal/poll/fd_mutex.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_opendir_darwin.go b/contrib/go/_std_1.23/src/internal/poll/fd_opendir_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_opendir_darwin.go rename to contrib/go/_std_1.23/src/internal/poll/fd_opendir_darwin.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_plan9.go b/contrib/go/_std_1.23/src/internal/poll/fd_plan9.go similarity index 92% rename from contrib/go/_std_1.22/src/internal/poll/fd_plan9.go rename to contrib/go/_std_1.23/src/internal/poll/fd_plan9.go index 7cc178a9d5a4..b65485200add 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_plan9.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_plan9.go @@ -6,8 +6,10 @@ package poll import ( "errors" + "internal/stringslite" "io" "sync" + "syscall" "time" ) @@ -202,11 +204,11 @@ func (fd *FD) ReadUnlock() { } func isHangup(err error) bool { - return err != nil && stringsHasSuffix(err.Error(), "Hangup") + return err != nil && stringslite.HasSuffix(err.Error(), "Hangup") } func isInterrupted(err error) bool { - return err != nil && stringsHasSuffix(err.Error(), "interrupted") + return err != nil && stringslite.HasSuffix(err.Error(), "interrupted") } // IsPollDescriptor reports whether fd is the descriptor being used by the poller. @@ -230,3 +232,14 @@ func (fd *FD) RawRead(f func(uintptr) bool) error { func (fd *FD) RawWrite(f func(uintptr) bool) error { return errors.New("not implemented") } + +func DupCloseOnExec(fd int) (int, string, error) { + nfd, err := syscall.Dup(int(fd), -1) + if err != nil { + return 0, "dup", err + } + // Plan9 has no syscall.CloseOnExec but + // its forkAndExecInChild closes all fds + // not related to the fork+exec. + return nfd, "", nil +} diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_poll_js.go b/contrib/go/_std_1.23/src/internal/poll/fd_poll_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_poll_js.go rename to contrib/go/_std_1.23/src/internal/poll/fd_poll_js.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_poll_runtime.go b/contrib/go/_std_1.23/src/internal/poll/fd_poll_runtime.go similarity index 92% rename from contrib/go/_std_1.22/src/internal/poll/fd_poll_runtime.go rename to contrib/go/_std_1.23/src/internal/poll/fd_poll_runtime.go index b51535ecf2f0..b78d15647669 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_poll_runtime.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_poll_runtime.go @@ -164,6 +164,16 @@ func setDeadlineImpl(fd *FD, t time.Time, mode int) error { // IsPollDescriptor reports whether fd is the descriptor being used by the poller. // This is only used for testing. +// +// IsPollDescriptor should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/opencontainers/runc +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname IsPollDescriptor func IsPollDescriptor(fd uintptr) bool { return runtime_isPollServerDescriptor(fd) } diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_posix.go b/contrib/go/_std_1.23/src/internal/poll/fd_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_posix.go rename to contrib/go/_std_1.23/src/internal/poll/fd_posix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_unix.go b/contrib/go/_std_1.23/src/internal/poll/fd_unix.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/poll/fd_unix.go rename to contrib/go/_std_1.23/src/internal/poll/fd_unix.go index 61c2338305ad..2535a3ae4dd4 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_unix.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_unix.go @@ -7,6 +7,7 @@ package poll import ( + "internal/itoa" "internal/syscall/unix" "io" "sync/atomic" @@ -379,6 +380,14 @@ func (fd *FD) Write(p []byte) (int, error) { } n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max]) if n > 0 { + if n > max-nn { + // This can reportedly happen when using + // some VPN software. Issue #61060. + // If we don't check this we will panic + // with slice bounds out of range. + // Use a more informative panic. + panic("invalid return from write: got " + itoa.Itoa(n) + " from a write of " + itoa.Itoa(max-nn)) + } nn += n } if nn == len(p) { @@ -678,7 +687,7 @@ func (fd *FD) Dup() (int, string, error) { // On Unix variants only, expose the IO event for the net code. -// WaitWrite waits until data can be read from fd. +// WaitWrite waits until data can be written to fd. func (fd *FD) WaitWrite() error { return fd.pd.waitWrite(fd.isFile) } diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_unixjs.go b/contrib/go/_std_1.23/src/internal/poll/fd_unixjs.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_unixjs.go rename to contrib/go/_std_1.23/src/internal/poll/fd_unixjs.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_wasip1.go b/contrib/go/_std_1.23/src/internal/poll/fd_wasip1.go similarity index 93% rename from contrib/go/_std_1.22/src/internal/poll/fd_wasip1.go rename to contrib/go/_std_1.23/src/internal/poll/fd_wasip1.go index aecd89669b48..195aaa9517d1 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_wasip1.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_wasip1.go @@ -5,6 +5,7 @@ package poll import ( + "internal/byteorder" "sync/atomic" "syscall" "unsafe" @@ -224,15 +225,11 @@ func readIntLE(b []byte, size uintptr) uint64 { case 1: return uint64(b[0]) case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 + return uint64(byteorder.LeUint16(b)) case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 + return uint64(byteorder.LeUint32(b)) case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + return uint64(byteorder.LeUint64(b)) default: panic("internal/poll: readInt with unsupported size") } diff --git a/contrib/go/_std_1.23/src/internal/poll/fd_windows.go b/contrib/go/_std_1.23/src/internal/poll/fd_windows.go new file mode 100644 index 000000000000..5eefeb90f193 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/fd_windows.go @@ -0,0 +1,1347 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll + +import ( + "errors" + "internal/race" + "internal/syscall/windows" + "io" + "sync" + "syscall" + "unicode/utf16" + "unicode/utf8" + "unsafe" +) + +var ( + initErr error + ioSync uint64 +) + +// This package uses the SetFileCompletionNotificationModes Windows +// API to skip calling GetQueuedCompletionStatus if an IO operation +// completes synchronously. There is a known bug where +// SetFileCompletionNotificationModes crashes on some systems (see +// https://support.microsoft.com/kb/2568167 for details). + +var useSetFileCompletionNotificationModes bool // determines is SetFileCompletionNotificationModes is present and safe to use + +// checkSetFileCompletionNotificationModes verifies that +// SetFileCompletionNotificationModes Windows API is present +// on the system and is safe to use. +// See https://support.microsoft.com/kb/2568167 for details. +func checkSetFileCompletionNotificationModes() { + err := syscall.LoadSetFileCompletionNotificationModes() + if err != nil { + return + } + protos := [2]int32{syscall.IPPROTO_TCP, 0} + var buf [32]syscall.WSAProtocolInfo + len := uint32(unsafe.Sizeof(buf)) + n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len) + if err != nil { + return + } + for i := int32(0); i < n; i++ { + if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 { + return + } + } + useSetFileCompletionNotificationModes = true +} + +// InitWSA initiates the use of the Winsock DLL by the current process. +// It is called from the net package at init time to avoid +// loading ws2_32.dll when net is not used. +var InitWSA = sync.OnceFunc(func() { + var d syscall.WSAData + e := syscall.WSAStartup(uint32(0x202), &d) + if e != nil { + initErr = e + } + checkSetFileCompletionNotificationModes() +}) + +// operation contains superset of data necessary to perform all async IO. +type operation struct { + // Used by IOCP interface, it must be first field + // of the struct, as our code rely on it. + o syscall.Overlapped + + // fields used by runtime.netpoll + runtimeCtx uintptr + mode int32 + + // fields used only by net package + fd *FD + buf syscall.WSABuf + msg windows.WSAMsg + sa syscall.Sockaddr + rsa *syscall.RawSockaddrAny + rsan int32 + handle syscall.Handle + flags uint32 + qty uint32 + bufs []syscall.WSABuf +} + +func (o *operation) InitBuf(buf []byte) { + o.buf.Len = uint32(len(buf)) + o.buf.Buf = nil + if len(buf) != 0 { + o.buf.Buf = &buf[0] + } +} + +func (o *operation) InitBufs(buf *[][]byte) { + if o.bufs == nil { + o.bufs = make([]syscall.WSABuf, 0, len(*buf)) + } else { + o.bufs = o.bufs[:0] + } + for _, b := range *buf { + if len(b) == 0 { + o.bufs = append(o.bufs, syscall.WSABuf{}) + continue + } + for len(b) > maxRW { + o.bufs = append(o.bufs, syscall.WSABuf{Len: maxRW, Buf: &b[0]}) + b = b[maxRW:] + } + if len(b) > 0 { + o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: &b[0]}) + } + } +} + +// ClearBufs clears all pointers to Buffers parameter captured +// by InitBufs, so it can be released by garbage collector. +func (o *operation) ClearBufs() { + for i := range o.bufs { + o.bufs[i].Buf = nil + } + o.bufs = o.bufs[:0] +} + +func (o *operation) InitMsg(p []byte, oob []byte) { + o.InitBuf(p) + o.msg.Buffers = &o.buf + o.msg.BufferCount = 1 + + o.msg.Name = nil + o.msg.Namelen = 0 + + o.msg.Flags = 0 + o.msg.Control.Len = uint32(len(oob)) + o.msg.Control.Buf = nil + if len(oob) != 0 { + o.msg.Control.Buf = &oob[0] + } +} + +// execIO executes a single IO operation o. It submits and cancels +// IO in the current thread for systems where Windows CancelIoEx API +// is available. Alternatively, it passes the request onto +// runtime netpoll and waits for completion or cancels request. +func execIO(o *operation, submit func(o *operation) error) (int, error) { + if o.fd.pd.runtimeCtx == 0 { + return 0, errors.New("internal error: polling on unsupported descriptor type") + } + + fd := o.fd + // Notify runtime netpoll about starting IO. + err := fd.pd.prepare(int(o.mode), fd.isFile) + if err != nil { + return 0, err + } + // Start IO. + err = submit(o) + switch err { + case nil: + // IO completed immediately + if o.fd.skipSyncNotif { + // No completion message will follow, so return immediately. + return int(o.qty), nil + } + // Need to get our completion message anyway. + case syscall.ERROR_IO_PENDING: + // IO started, and we have to wait for its completion. + err = nil + default: + return 0, err + } + // Wait for our request to complete. + err = fd.pd.wait(int(o.mode), fd.isFile) + if err == nil { + err = windows.WSAGetOverlappedResult(fd.Sysfd, &o.o, &o.qty, false, &o.flags) + // All is good. Extract our IO results and return. + if err != nil { + // More data available. Return back the size of received data. + if err == syscall.ERROR_MORE_DATA || err == windows.WSAEMSGSIZE { + return int(o.qty), err + } + return 0, err + } + return int(o.qty), nil + } + // IO is interrupted by "close" or "timeout" + netpollErr := err + switch netpollErr { + case ErrNetClosing, ErrFileClosing, ErrDeadlineExceeded: + // will deal with those. + default: + panic("unexpected runtime.netpoll error: " + netpollErr.Error()) + } + // Cancel our request. + err = syscall.CancelIoEx(fd.Sysfd, &o.o) + // Assuming ERROR_NOT_FOUND is returned, if IO is completed. + if err != nil && err != syscall.ERROR_NOT_FOUND { + // TODO(brainman): maybe do something else, but panic. + panic(err) + } + // Wait for cancellation to complete. + fd.pd.waitCanceled(int(o.mode)) + err = windows.WSAGetOverlappedResult(fd.Sysfd, &o.o, &o.qty, false, &o.flags) + if err != nil { + if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled + err = netpollErr + } + return 0, err + } + // We issued a cancellation request. But, it seems, IO operation succeeded + // before the cancellation request run. We need to treat the IO operation as + // succeeded (the bytes are actually sent/recv from network). + return int(o.qty), nil +} + +// FD is a file descriptor. The net and os packages embed this type in +// a larger type representing a network connection or OS file. +type FD struct { + // Lock sysfd and serialize access to Read and Write methods. + fdmu fdMutex + + // System file descriptor. Immutable until Close. + Sysfd syscall.Handle + + // Read operation. + rop operation + // Write operation. + wop operation + + // I/O poller. + pd pollDesc + + // Used to implement pread/pwrite. + l sync.Mutex + + // For console I/O. + lastbits []byte // first few bytes of the last incomplete rune in last write + readuint16 []uint16 // buffer to hold uint16s obtained with ReadConsole + readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8 + readbyteOffset int // readbyte[readOffset:] is yet to be consumed with file.Read + + // Semaphore signaled when file is closed. + csema uint32 + + skipSyncNotif bool + + // Whether this is a streaming descriptor, as opposed to a + // packet-based descriptor like a UDP socket. + IsStream bool + + // Whether a zero byte read indicates EOF. This is false for a + // message based socket connection. + ZeroReadIsEOF bool + + // Whether this is a file rather than a network socket. + isFile bool + + // The kind of this file. + kind fileKind +} + +// fileKind describes the kind of file. +type fileKind byte + +const ( + kindNet fileKind = iota + kindFile + kindConsole + kindPipe +) + +// logInitFD is set by tests to enable file descriptor initialization logging. +var logInitFD func(net string, fd *FD, err error) + +// Init initializes the FD. The Sysfd field should already be set. +// This can be called multiple times on a single FD. +// The net argument is a network name from the net package (e.g., "tcp"), +// or "file" or "console" or "dir". +// Set pollable to true if fd should be managed by runtime netpoll. +func (fd *FD) Init(net string, pollable bool) (string, error) { + if initErr != nil { + return "", initErr + } + + switch net { + case "file", "dir": + fd.kind = kindFile + case "console": + fd.kind = kindConsole + case "pipe": + fd.kind = kindPipe + case "tcp", "tcp4", "tcp6", + "udp", "udp4", "udp6", + "ip", "ip4", "ip6", + "unix", "unixgram", "unixpacket": + fd.kind = kindNet + default: + return "", errors.New("internal error: unknown network type " + net) + } + fd.isFile = fd.kind != kindNet + + var err error + if pollable { + // Only call init for a network socket. + // This means that we don't add files to the runtime poller. + // Adding files to the runtime poller can confuse matters + // if the user is doing their own overlapped I/O. + // See issue #21172. + // + // In general the code below avoids calling the execIO + // function for non-network sockets. If some method does + // somehow call execIO, then execIO, and therefore the + // calling method, will return an error, because + // fd.pd.runtimeCtx will be 0. + err = fd.pd.init(fd) + } + if logInitFD != nil { + logInitFD(net, fd, err) + } + if err != nil { + return "", err + } + if pollable && useSetFileCompletionNotificationModes { + // We do not use events, so we can skip them always. + flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE) + switch net { + case "tcp", "tcp4", "tcp6", + "udp", "udp4", "udp6": + flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS + } + err := syscall.SetFileCompletionNotificationModes(fd.Sysfd, flags) + if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 { + fd.skipSyncNotif = true + } + } + // Disable SIO_UDP_CONNRESET behavior. + // http://support.microsoft.com/kb/263823 + switch net { + case "udp", "udp4", "udp6": + ret := uint32(0) + flag := uint32(0) + size := uint32(unsafe.Sizeof(flag)) + err := syscall.WSAIoctl(fd.Sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) + if err != nil { + return "wsaioctl", err + } + } + fd.rop.mode = 'r' + fd.wop.mode = 'w' + fd.rop.fd = fd + fd.wop.fd = fd + fd.rop.runtimeCtx = fd.pd.runtimeCtx + fd.wop.runtimeCtx = fd.pd.runtimeCtx + return "", nil +} + +func (fd *FD) destroy() error { + if fd.Sysfd == syscall.InvalidHandle { + return syscall.EINVAL + } + // Poller may want to unregister fd in readiness notification mechanism, + // so this must be executed before fd.CloseFunc. + fd.pd.close() + var err error + switch fd.kind { + case kindNet: + // The net package uses the CloseFunc variable for testing. + err = CloseFunc(fd.Sysfd) + default: + err = syscall.CloseHandle(fd.Sysfd) + } + fd.Sysfd = syscall.InvalidHandle + runtime_Semrelease(&fd.csema) + return err +} + +// Close closes the FD. The underlying file descriptor is closed by +// the destroy method when there are no remaining references. +func (fd *FD) Close() error { + if !fd.fdmu.increfAndClose() { + return errClosing(fd.isFile) + } + if fd.kind == kindPipe { + syscall.CancelIoEx(fd.Sysfd, nil) + } + // unblock pending reader and writer + fd.pd.evict() + err := fd.decref() + // Wait until the descriptor is closed. If this was the only + // reference, it is already closed. + runtime_Semacquire(&fd.csema) + return err +} + +// Windows ReadFile and WSARecv use DWORD (uint32) parameter to pass buffer length. +// This prevents us reading blocks larger than 4GB. +// See golang.org/issue/26923. +const maxRW = 1 << 30 // 1GB is large enough and keeps subsequent reads aligned + +// Read implements io.Reader. +func (fd *FD) Read(buf []byte) (int, error) { + if err := fd.readLock(); err != nil { + return 0, err + } + defer fd.readUnlock() + + if len(buf) > maxRW { + buf = buf[:maxRW] + } + + var n int + var err error + if fd.isFile { + fd.l.Lock() + defer fd.l.Unlock() + switch fd.kind { + case kindConsole: + n, err = fd.readConsole(buf) + default: + n, err = syscall.Read(fd.Sysfd, buf) + if fd.kind == kindPipe && err == syscall.ERROR_OPERATION_ABORTED { + // Close uses CancelIoEx to interrupt concurrent I/O for pipes. + // If the fd is a pipe and the Read was interrupted by CancelIoEx, + // we assume it is interrupted by Close. + err = ErrFileClosing + } + } + if err != nil { + n = 0 + } + } else { + o := &fd.rop + o.InitBuf(buf) + n, err = execIO(o, func(o *operation) error { + return syscall.WSARecv(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil) + }) + if race.Enabled { + race.Acquire(unsafe.Pointer(&ioSync)) + } + } + if len(buf) != 0 { + err = fd.eofError(n, err) + } + return n, err +} + +var ReadConsole = syscall.ReadConsole // changed for testing + +// readConsole reads utf16 characters from console File, +// encodes them into utf8 and stores them in buffer b. +// It returns the number of utf8 bytes read and an error, if any. +func (fd *FD) readConsole(b []byte) (int, error) { + if len(b) == 0 { + return 0, nil + } + + if fd.readuint16 == nil { + // Note: syscall.ReadConsole fails for very large buffers. + // The limit is somewhere around (but not exactly) 16384. + // Stay well below. + fd.readuint16 = make([]uint16, 0, 10000) + fd.readbyte = make([]byte, 0, 4*cap(fd.readuint16)) + } + + for fd.readbyteOffset >= len(fd.readbyte) { + n := cap(fd.readuint16) - len(fd.readuint16) + if n > len(b) { + n = len(b) + } + var nw uint32 + err := ReadConsole(fd.Sysfd, &fd.readuint16[:len(fd.readuint16)+1][len(fd.readuint16)], uint32(n), &nw, nil) + if err != nil { + return 0, err + } + uint16s := fd.readuint16[:len(fd.readuint16)+int(nw)] + fd.readuint16 = fd.readuint16[:0] + buf := fd.readbyte[:0] + for i := 0; i < len(uint16s); i++ { + r := rune(uint16s[i]) + if utf16.IsSurrogate(r) { + if i+1 == len(uint16s) { + if nw > 0 { + // Save half surrogate pair for next time. + fd.readuint16 = fd.readuint16[:1] + fd.readuint16[0] = uint16(r) + break + } + r = utf8.RuneError + } else { + r = utf16.DecodeRune(r, rune(uint16s[i+1])) + if r != utf8.RuneError { + i++ + } + } + } + buf = utf8.AppendRune(buf, r) + } + fd.readbyte = buf + fd.readbyteOffset = 0 + if nw == 0 { + break + } + } + + src := fd.readbyte[fd.readbyteOffset:] + var i int + for i = 0; i < len(src) && i < len(b); i++ { + x := src[i] + if x == 0x1A { // Ctrl-Z + if i == 0 { + fd.readbyteOffset++ + } + break + } + b[i] = x + } + fd.readbyteOffset += i + return i, nil +} + +// Pread emulates the Unix pread system call. +func (fd *FD) Pread(b []byte, off int64) (int, error) { + if fd.kind == kindPipe { + // Pread does not work with pipes + return 0, syscall.ESPIPE + } + // Call incref, not readLock, because since pread specifies the + // offset it is independent from other reads. + if err := fd.incref(); err != nil { + return 0, err + } + defer fd.decref() + + if len(b) > maxRW { + b = b[:maxRW] + } + + fd.l.Lock() + defer fd.l.Unlock() + curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent) + if e != nil { + return 0, e + } + defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart) + o := syscall.Overlapped{ + OffsetHigh: uint32(off >> 32), + Offset: uint32(off), + } + var done uint32 + e = syscall.ReadFile(fd.Sysfd, b, &done, &o) + if e != nil { + done = 0 + if e == syscall.ERROR_HANDLE_EOF { + e = io.EOF + } + } + if len(b) != 0 { + e = fd.eofError(int(done), e) + } + return int(done), e +} + +// ReadFrom wraps the recvfrom network call. +func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) { + if len(buf) == 0 { + return 0, nil, nil + } + if len(buf) > maxRW { + buf = buf[:maxRW] + } + if err := fd.readLock(); err != nil { + return 0, nil, err + } + defer fd.readUnlock() + o := &fd.rop + o.InitBuf(buf) + n, err := execIO(o, func(o *operation) error { + if o.rsa == nil { + o.rsa = new(syscall.RawSockaddrAny) + } + o.rsan = int32(unsafe.Sizeof(*o.rsa)) + return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) + }) + err = fd.eofError(n, err) + if err != nil { + return n, nil, err + } + sa, _ := o.rsa.Sockaddr() + return n, sa, nil +} + +// ReadFromInet4 wraps the recvfrom network call for IPv4. +func (fd *FD) ReadFromInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error) { + if len(buf) == 0 { + return 0, nil + } + if len(buf) > maxRW { + buf = buf[:maxRW] + } + if err := fd.readLock(); err != nil { + return 0, err + } + defer fd.readUnlock() + o := &fd.rop + o.InitBuf(buf) + n, err := execIO(o, func(o *operation) error { + if o.rsa == nil { + o.rsa = new(syscall.RawSockaddrAny) + } + o.rsan = int32(unsafe.Sizeof(*o.rsa)) + return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) + }) + err = fd.eofError(n, err) + if err != nil { + return n, err + } + rawToSockaddrInet4(o.rsa, sa4) + return n, err +} + +// ReadFromInet6 wraps the recvfrom network call for IPv6. +func (fd *FD) ReadFromInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error) { + if len(buf) == 0 { + return 0, nil + } + if len(buf) > maxRW { + buf = buf[:maxRW] + } + if err := fd.readLock(); err != nil { + return 0, err + } + defer fd.readUnlock() + o := &fd.rop + o.InitBuf(buf) + n, err := execIO(o, func(o *operation) error { + if o.rsa == nil { + o.rsa = new(syscall.RawSockaddrAny) + } + o.rsan = int32(unsafe.Sizeof(*o.rsa)) + return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) + }) + err = fd.eofError(n, err) + if err != nil { + return n, err + } + rawToSockaddrInet6(o.rsa, sa6) + return n, err +} + +// Write implements io.Writer. +func (fd *FD) Write(buf []byte) (int, error) { + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + if fd.isFile { + fd.l.Lock() + defer fd.l.Unlock() + } + + ntotal := 0 + for len(buf) > 0 { + b := buf + if len(b) > maxRW { + b = b[:maxRW] + } + var n int + var err error + if fd.isFile { + switch fd.kind { + case kindConsole: + n, err = fd.writeConsole(b) + default: + n, err = syscall.Write(fd.Sysfd, b) + if fd.kind == kindPipe && err == syscall.ERROR_OPERATION_ABORTED { + // Close uses CancelIoEx to interrupt concurrent I/O for pipes. + // If the fd is a pipe and the Write was interrupted by CancelIoEx, + // we assume it is interrupted by Close. + err = ErrFileClosing + } + } + if err != nil { + n = 0 + } + } else { + if race.Enabled { + race.ReleaseMerge(unsafe.Pointer(&ioSync)) + } + o := &fd.wop + o.InitBuf(b) + n, err = execIO(o, func(o *operation) error { + return syscall.WSASend(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil) + }) + } + ntotal += n + if err != nil { + return ntotal, err + } + buf = buf[n:] + } + return ntotal, nil +} + +// writeConsole writes len(b) bytes to the console File. +// It returns the number of bytes written and an error, if any. +func (fd *FD) writeConsole(b []byte) (int, error) { + n := len(b) + runes := make([]rune, 0, 256) + if len(fd.lastbits) > 0 { + b = append(fd.lastbits, b...) + fd.lastbits = nil + + } + for len(b) >= utf8.UTFMax || utf8.FullRune(b) { + r, l := utf8.DecodeRune(b) + runes = append(runes, r) + b = b[l:] + } + if len(b) > 0 { + fd.lastbits = make([]byte, len(b)) + copy(fd.lastbits, b) + } + // syscall.WriteConsole seems to fail, if given large buffer. + // So limit the buffer to 16000 characters. This number was + // discovered by experimenting with syscall.WriteConsole. + const maxWrite = 16000 + for len(runes) > 0 { + m := len(runes) + if m > maxWrite { + m = maxWrite + } + chunk := runes[:m] + runes = runes[m:] + uint16s := utf16.Encode(chunk) + for len(uint16s) > 0 { + var written uint32 + err := syscall.WriteConsole(fd.Sysfd, &uint16s[0], uint32(len(uint16s)), &written, nil) + if err != nil { + return 0, err + } + uint16s = uint16s[written:] + } + } + return n, nil +} + +// Pwrite emulates the Unix pwrite system call. +func (fd *FD) Pwrite(buf []byte, off int64) (int, error) { + if fd.kind == kindPipe { + // Pwrite does not work with pipes + return 0, syscall.ESPIPE + } + // Call incref, not writeLock, because since pwrite specifies the + // offset it is independent from other writes. + if err := fd.incref(); err != nil { + return 0, err + } + defer fd.decref() + + fd.l.Lock() + defer fd.l.Unlock() + curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent) + if e != nil { + return 0, e + } + defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart) + + ntotal := 0 + for len(buf) > 0 { + b := buf + if len(b) > maxRW { + b = b[:maxRW] + } + var n uint32 + o := syscall.Overlapped{ + OffsetHigh: uint32(off >> 32), + Offset: uint32(off), + } + e = syscall.WriteFile(fd.Sysfd, b, &n, &o) + ntotal += int(n) + if e != nil { + return ntotal, e + } + buf = buf[n:] + off += int64(n) + } + return ntotal, nil +} + +// Writev emulates the Unix writev system call. +func (fd *FD) Writev(buf *[][]byte) (int64, error) { + if len(*buf) == 0 { + return 0, nil + } + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + if race.Enabled { + race.ReleaseMerge(unsafe.Pointer(&ioSync)) + } + o := &fd.wop + o.InitBufs(buf) + n, err := execIO(o, func(o *operation) error { + return syscall.WSASend(o.fd.Sysfd, &o.bufs[0], uint32(len(o.bufs)), &o.qty, 0, &o.o, nil) + }) + o.ClearBufs() + TestHookDidWritev(n) + consume(buf, int64(n)) + return int64(n), err +} + +// WriteTo wraps the sendto network call. +func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) { + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + + if len(buf) == 0 { + // handle zero-byte payload + o := &fd.wop + o.InitBuf(buf) + o.sa = sa + n, err := execIO(o, func(o *operation) error { + return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil) + }) + return n, err + } + + ntotal := 0 + for len(buf) > 0 { + b := buf + if len(b) > maxRW { + b = b[:maxRW] + } + o := &fd.wop + o.InitBuf(b) + o.sa = sa + n, err := execIO(o, func(o *operation) error { + return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil) + }) + ntotal += int(n) + if err != nil { + return ntotal, err + } + buf = buf[n:] + } + return ntotal, nil +} + +// WriteToInet4 is WriteTo, specialized for syscall.SockaddrInet4. +func (fd *FD) WriteToInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error) { + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + + if len(buf) == 0 { + // handle zero-byte payload + o := &fd.wop + o.InitBuf(buf) + n, err := execIO(o, func(o *operation) error { + return windows.WSASendtoInet4(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa4, &o.o, nil) + }) + return n, err + } + + ntotal := 0 + for len(buf) > 0 { + b := buf + if len(b) > maxRW { + b = b[:maxRW] + } + o := &fd.wop + o.InitBuf(b) + n, err := execIO(o, func(o *operation) error { + return windows.WSASendtoInet4(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa4, &o.o, nil) + }) + ntotal += int(n) + if err != nil { + return ntotal, err + } + buf = buf[n:] + } + return ntotal, nil +} + +// WriteToInet6 is WriteTo, specialized for syscall.SockaddrInet6. +func (fd *FD) WriteToInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error) { + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + + if len(buf) == 0 { + // handle zero-byte payload + o := &fd.wop + o.InitBuf(buf) + n, err := execIO(o, func(o *operation) error { + return windows.WSASendtoInet6(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa6, &o.o, nil) + }) + return n, err + } + + ntotal := 0 + for len(buf) > 0 { + b := buf + if len(b) > maxRW { + b = b[:maxRW] + } + o := &fd.wop + o.InitBuf(b) + n, err := execIO(o, func(o *operation) error { + return windows.WSASendtoInet6(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa6, &o.o, nil) + }) + ntotal += int(n) + if err != nil { + return ntotal, err + } + buf = buf[n:] + } + return ntotal, nil +} + +// Call ConnectEx. This doesn't need any locking, since it is only +// called when the descriptor is first created. This is here rather +// than in the net package so that it can use fd.wop. +func (fd *FD) ConnectEx(ra syscall.Sockaddr) error { + o := &fd.wop + o.sa = ra + _, err := execIO(o, func(o *operation) error { + return ConnectExFunc(o.fd.Sysfd, o.sa, nil, 0, nil, &o.o) + }) + return err +} + +func (fd *FD) acceptOne(s syscall.Handle, rawsa []syscall.RawSockaddrAny, o *operation) (string, error) { + // Submit accept request. + o.handle = s + o.rsan = int32(unsafe.Sizeof(rawsa[0])) + _, err := execIO(o, func(o *operation) error { + return AcceptFunc(o.fd.Sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o) + }) + if err != nil { + CloseFunc(s) + return "acceptex", err + } + + // Inherit properties of the listening socket. + err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.Sysfd)), int32(unsafe.Sizeof(fd.Sysfd))) + if err != nil { + CloseFunc(s) + return "setsockopt", err + } + + return "", nil +} + +// Accept handles accepting a socket. The sysSocket parameter is used +// to allocate the net socket. +func (fd *FD) Accept(sysSocket func() (syscall.Handle, error)) (syscall.Handle, []syscall.RawSockaddrAny, uint32, string, error) { + if err := fd.readLock(); err != nil { + return syscall.InvalidHandle, nil, 0, "", err + } + defer fd.readUnlock() + + o := &fd.rop + var rawsa [2]syscall.RawSockaddrAny + for { + s, err := sysSocket() + if err != nil { + return syscall.InvalidHandle, nil, 0, "", err + } + + errcall, err := fd.acceptOne(s, rawsa[:], o) + if err == nil { + return s, rawsa[:], uint32(o.rsan), "", nil + } + + // Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is + // returned here. These happen if connection reset is received + // before AcceptEx could complete. These errors relate to new + // connection, not to AcceptEx, so ignore broken connection and + // try AcceptEx again for more connections. + errno, ok := err.(syscall.Errno) + if !ok { + return syscall.InvalidHandle, nil, 0, errcall, err + } + switch errno { + case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET: + // ignore these and try again + default: + return syscall.InvalidHandle, nil, 0, errcall, err + } + } +} + +// Seek wraps syscall.Seek. +func (fd *FD) Seek(offset int64, whence int) (int64, error) { + if fd.kind == kindPipe { + return 0, syscall.ESPIPE + } + if err := fd.incref(); err != nil { + return 0, err + } + defer fd.decref() + + fd.l.Lock() + defer fd.l.Unlock() + + return syscall.Seek(fd.Sysfd, offset, whence) +} + +// Fchmod updates syscall.ByHandleFileInformation.Fileattributes when needed. +func (fd *FD) Fchmod(mode uint32) error { + if err := fd.incref(); err != nil { + return err + } + defer fd.decref() + + var d syscall.ByHandleFileInformation + if err := syscall.GetFileInformationByHandle(fd.Sysfd, &d); err != nil { + return err + } + attrs := d.FileAttributes + if mode&syscall.S_IWRITE != 0 { + attrs &^= syscall.FILE_ATTRIBUTE_READONLY + } else { + attrs |= syscall.FILE_ATTRIBUTE_READONLY + } + if attrs == d.FileAttributes { + return nil + } + + var du windows.FILE_BASIC_INFO + du.FileAttributes = attrs + return windows.SetFileInformationByHandle(fd.Sysfd, windows.FileBasicInfo, unsafe.Pointer(&du), uint32(unsafe.Sizeof(du))) +} + +// Fchdir wraps syscall.Fchdir. +func (fd *FD) Fchdir() error { + if err := fd.incref(); err != nil { + return err + } + defer fd.decref() + return syscall.Fchdir(fd.Sysfd) +} + +// GetFileType wraps syscall.GetFileType. +func (fd *FD) GetFileType() (uint32, error) { + if err := fd.incref(); err != nil { + return 0, err + } + defer fd.decref() + return syscall.GetFileType(fd.Sysfd) +} + +// GetFileInformationByHandle wraps GetFileInformationByHandle. +func (fd *FD) GetFileInformationByHandle(data *syscall.ByHandleFileInformation) error { + if err := fd.incref(); err != nil { + return err + } + defer fd.decref() + return syscall.GetFileInformationByHandle(fd.Sysfd, data) +} + +// RawRead invokes the user-defined function f for a read operation. +func (fd *FD) RawRead(f func(uintptr) bool) error { + if err := fd.readLock(); err != nil { + return err + } + defer fd.readUnlock() + for { + if f(uintptr(fd.Sysfd)) { + return nil + } + + // Use a zero-byte read as a way to get notified when this + // socket is readable. h/t https://stackoverflow.com/a/42019668/332798 + o := &fd.rop + o.InitBuf(nil) + if !fd.IsStream { + o.flags |= windows.MSG_PEEK + } + _, err := execIO(o, func(o *operation) error { + return syscall.WSARecv(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil) + }) + if err == windows.WSAEMSGSIZE { + // expected with a 0-byte peek, ignore. + } else if err != nil { + return err + } + } +} + +// RawWrite invokes the user-defined function f for a write operation. +func (fd *FD) RawWrite(f func(uintptr) bool) error { + if err := fd.writeLock(); err != nil { + return err + } + defer fd.writeUnlock() + + if f(uintptr(fd.Sysfd)) { + return nil + } + + // TODO(tmm1): find a way to detect socket writability + return syscall.EWINDOWS +} + +func sockaddrInet4ToRaw(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet4) int32 { + *rsa = syscall.RawSockaddrAny{} + raw := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa)) + raw.Family = syscall.AF_INET + p := (*[2]byte)(unsafe.Pointer(&raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + raw.Addr = sa.Addr + return int32(unsafe.Sizeof(*raw)) +} + +func sockaddrInet6ToRaw(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet6) int32 { + *rsa = syscall.RawSockaddrAny{} + raw := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa)) + raw.Family = syscall.AF_INET6 + p := (*[2]byte)(unsafe.Pointer(&raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + raw.Scope_id = sa.ZoneId + raw.Addr = sa.Addr + return int32(unsafe.Sizeof(*raw)) +} + +func rawToSockaddrInet4(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet4) { + pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa)) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + sa.Addr = pp.Addr +} + +func rawToSockaddrInet6(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet6) { + pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa)) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + sa.ZoneId = pp.Scope_id + sa.Addr = pp.Addr +} + +func sockaddrToRaw(rsa *syscall.RawSockaddrAny, sa syscall.Sockaddr) (int32, error) { + switch sa := sa.(type) { + case *syscall.SockaddrInet4: + sz := sockaddrInet4ToRaw(rsa, sa) + return sz, nil + case *syscall.SockaddrInet6: + sz := sockaddrInet6ToRaw(rsa, sa) + return sz, nil + default: + return 0, syscall.EWINDOWS + } +} + +// ReadMsg wraps the WSARecvMsg network call. +func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.Sockaddr, error) { + if err := fd.readLock(); err != nil { + return 0, 0, 0, nil, err + } + defer fd.readUnlock() + + if len(p) > maxRW { + p = p[:maxRW] + } + + o := &fd.rop + o.InitMsg(p, oob) + if o.rsa == nil { + o.rsa = new(syscall.RawSockaddrAny) + } + o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) + o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa)) + o.msg.Flags = uint32(flags) + n, err := execIO(o, func(o *operation) error { + return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil) + }) + err = fd.eofError(n, err) + var sa syscall.Sockaddr + if err == nil { + sa, err = o.rsa.Sockaddr() + } + return n, int(o.msg.Control.Len), int(o.msg.Flags), sa, err +} + +// ReadMsgInet4 is ReadMsg, but specialized to return a syscall.SockaddrInet4. +func (fd *FD) ReadMsgInet4(p []byte, oob []byte, flags int, sa4 *syscall.SockaddrInet4) (int, int, int, error) { + if err := fd.readLock(); err != nil { + return 0, 0, 0, err + } + defer fd.readUnlock() + + if len(p) > maxRW { + p = p[:maxRW] + } + + o := &fd.rop + o.InitMsg(p, oob) + if o.rsa == nil { + o.rsa = new(syscall.RawSockaddrAny) + } + o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) + o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa)) + o.msg.Flags = uint32(flags) + n, err := execIO(o, func(o *operation) error { + return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil) + }) + err = fd.eofError(n, err) + if err == nil { + rawToSockaddrInet4(o.rsa, sa4) + } + return n, int(o.msg.Control.Len), int(o.msg.Flags), err +} + +// ReadMsgInet6 is ReadMsg, but specialized to return a syscall.SockaddrInet6. +func (fd *FD) ReadMsgInet6(p []byte, oob []byte, flags int, sa6 *syscall.SockaddrInet6) (int, int, int, error) { + if err := fd.readLock(); err != nil { + return 0, 0, 0, err + } + defer fd.readUnlock() + + if len(p) > maxRW { + p = p[:maxRW] + } + + o := &fd.rop + o.InitMsg(p, oob) + if o.rsa == nil { + o.rsa = new(syscall.RawSockaddrAny) + } + o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) + o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa)) + o.msg.Flags = uint32(flags) + n, err := execIO(o, func(o *operation) error { + return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil) + }) + err = fd.eofError(n, err) + if err == nil { + rawToSockaddrInet6(o.rsa, sa6) + } + return n, int(o.msg.Control.Len), int(o.msg.Flags), err +} + +// WriteMsg wraps the WSASendMsg network call. +func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) { + if len(p) > maxRW { + return 0, 0, errors.New("packet is too large (only 1GB is allowed)") + } + + if err := fd.writeLock(); err != nil { + return 0, 0, err + } + defer fd.writeUnlock() + + o := &fd.wop + o.InitMsg(p, oob) + if sa != nil { + if o.rsa == nil { + o.rsa = new(syscall.RawSockaddrAny) + } + len, err := sockaddrToRaw(o.rsa, sa) + if err != nil { + return 0, 0, err + } + o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) + o.msg.Namelen = len + } + n, err := execIO(o, func(o *operation) error { + return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil) + }) + return n, int(o.msg.Control.Len), err +} + +// WriteMsgInet4 is WriteMsg specialized for syscall.SockaddrInet4. +func (fd *FD) WriteMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (int, int, error) { + if len(p) > maxRW { + return 0, 0, errors.New("packet is too large (only 1GB is allowed)") + } + + if err := fd.writeLock(); err != nil { + return 0, 0, err + } + defer fd.writeUnlock() + + o := &fd.wop + o.InitMsg(p, oob) + if o.rsa == nil { + o.rsa = new(syscall.RawSockaddrAny) + } + len := sockaddrInet4ToRaw(o.rsa, sa) + o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) + o.msg.Namelen = len + n, err := execIO(o, func(o *operation) error { + return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil) + }) + return n, int(o.msg.Control.Len), err +} + +// WriteMsgInet6 is WriteMsg specialized for syscall.SockaddrInet6. +func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (int, int, error) { + if len(p) > maxRW { + return 0, 0, errors.New("packet is too large (only 1GB is allowed)") + } + + if err := fd.writeLock(); err != nil { + return 0, 0, err + } + defer fd.writeUnlock() + + o := &fd.wop + o.InitMsg(p, oob) + if o.rsa == nil { + o.rsa = new(syscall.RawSockaddrAny) + } + len := sockaddrInet6ToRaw(o.rsa, sa) + o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) + o.msg.Namelen = len + n, err := execIO(o, func(o *operation) error { + return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil) + }) + return n, int(o.msg.Control.Len), err +} + +func DupCloseOnExec(fd int) (int, string, error) { + proc, err := syscall.GetCurrentProcess() + if err != nil { + return 0, "GetCurrentProcess", err + } + + var nfd syscall.Handle + const inherit = false // analogous to CLOEXEC + if err := syscall.DuplicateHandle(proc, syscall.Handle(fd), proc, &nfd, 0, inherit, syscall.DUPLICATE_SAME_ACCESS); err != nil { + return 0, "DuplicateHandle", err + } + return int(nfd), "", nil +} diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_writev_libc.go b/contrib/go/_std_1.23/src/internal/poll/fd_writev_libc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_writev_libc.go rename to contrib/go/_std_1.23/src/internal/poll/fd_writev_libc.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_writev_unix.go b/contrib/go/_std_1.23/src/internal/poll/fd_writev_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_writev_unix.go rename to contrib/go/_std_1.23/src/internal/poll/fd_writev_unix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/file_plan9.go b/contrib/go/_std_1.23/src/internal/poll/file_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/file_plan9.go rename to contrib/go/_std_1.23/src/internal/poll/file_plan9.go diff --git a/contrib/go/_std_1.22/src/internal/poll/hook_cloexec.go b/contrib/go/_std_1.23/src/internal/poll/hook_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/hook_cloexec.go rename to contrib/go/_std_1.23/src/internal/poll/hook_cloexec.go diff --git a/contrib/go/_std_1.22/src/internal/poll/hook_unix.go b/contrib/go/_std_1.23/src/internal/poll/hook_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/hook_unix.go rename to contrib/go/_std_1.23/src/internal/poll/hook_unix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/hook_windows.go b/contrib/go/_std_1.23/src/internal/poll/hook_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/hook_windows.go rename to contrib/go/_std_1.23/src/internal/poll/hook_windows.go diff --git a/contrib/go/_std_1.22/src/internal/poll/iovec_solaris.go b/contrib/go/_std_1.23/src/internal/poll/iovec_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/iovec_solaris.go rename to contrib/go/_std_1.23/src/internal/poll/iovec_solaris.go diff --git a/contrib/go/_std_1.22/src/internal/poll/iovec_unix.go b/contrib/go/_std_1.23/src/internal/poll/iovec_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/iovec_unix.go rename to contrib/go/_std_1.23/src/internal/poll/iovec_unix.go diff --git a/contrib/go/_std_1.23/src/internal/poll/sendfile.go b/contrib/go/_std_1.23/src/internal/poll/sendfile.go new file mode 100644 index 000000000000..41b0481c1aa3 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile.go @@ -0,0 +1,7 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll + +var TestHookDidSendFile = func(dstFD *FD, src int, written int64, err error, handled bool) {} diff --git a/contrib/go/_std_1.23/src/internal/poll/sendfile_bsd.go b/contrib/go/_std_1.23/src/internal/poll/sendfile_bsd.go new file mode 100644 index 000000000000..d1023d4ebb99 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile_bsd.go @@ -0,0 +1,77 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd + +package poll + +import "syscall" + +// maxSendfileSize is the largest chunk size we ask the kernel to copy +// at a time. +const maxSendfileSize int = 4 << 20 + +// SendFile wraps the sendfile system call. +func SendFile(dstFD *FD, src int, pos, remain int64) (written int64, err error, handled bool) { + defer func() { + TestHookDidSendFile(dstFD, src, written, err, handled) + }() + if err := dstFD.writeLock(); err != nil { + return 0, err, false + } + defer dstFD.writeUnlock() + + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err, false + } + + dst := dstFD.Sysfd + for remain > 0 { + n := maxSendfileSize + if int64(n) > remain { + n = int(remain) + } + m := n + pos1 := pos + n, err = syscall.Sendfile(dst, src, &pos1, n) + if n > 0 { + pos += int64(n) + written += int64(n) + remain -= int64(n) + // (n, nil) indicates that sendfile(2) has transferred + // the exact number of bytes we requested, or some unretryable + // error have occurred with partial bytes sent. Either way, we + // don't need to go through the following logic to check EINTR + // or fell into dstFD.pd.waitWrite, just continue to send the + // next chunk or break the loop. + if n == m { + continue + } else if err != syscall.EAGAIN && + err != syscall.EINTR && + err != syscall.EBUSY { + // Particularly, EPIPE. Errors like that would normally lead + // the subsequent sendfile(2) call to (-1, EBADF). + break + } + } else if err != syscall.EAGAIN && err != syscall.EINTR { + // This includes syscall.ENOSYS (no kernel + // support) and syscall.EINVAL (fd types which + // don't implement sendfile), and other errors. + // We should end the loop when there is no error + // returned from sendfile(2) or it is not a retryable error. + break + } + if err == syscall.EINTR { + continue + } + if err = dstFD.pd.waitWrite(dstFD.isFile); err != nil { + break + } + } + if err == syscall.EAGAIN { + err = nil + } + handled = written != 0 || (err != syscall.ENOSYS && err != syscall.EINVAL && err != syscall.EOPNOTSUPP && err != syscall.ENOTSUP) + return +} diff --git a/contrib/go/_std_1.23/src/internal/poll/sendfile_linux.go b/contrib/go/_std_1.23/src/internal/poll/sendfile_linux.go new file mode 100644 index 000000000000..1c4130d45da8 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile_linux.go @@ -0,0 +1,58 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll + +import "syscall" + +// maxSendfileSize is the largest chunk size we ask the kernel to copy +// at a time. +const maxSendfileSize int = 4 << 20 + +// SendFile wraps the sendfile system call. +func SendFile(dstFD *FD, src int, remain int64) (written int64, err error, handled bool) { + defer func() { + TestHookDidSendFile(dstFD, src, written, err, handled) + }() + if err := dstFD.writeLock(); err != nil { + return 0, err, false + } + defer dstFD.writeUnlock() + + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err, false + } + + dst := dstFD.Sysfd + for remain > 0 { + n := maxSendfileSize + if int64(n) > remain { + n = int(remain) + } + n, err = syscall.Sendfile(dst, src, nil, n) + if n > 0 { + written += int64(n) + remain -= int64(n) + continue + } else if err != syscall.EAGAIN && err != syscall.EINTR { + // This includes syscall.ENOSYS (no kernel + // support) and syscall.EINVAL (fd types which + // don't implement sendfile), and other errors. + // We should end the loop when there is no error + // returned from sendfile(2) or it is not a retryable error. + break + } + if err == syscall.EINTR { + continue + } + if err = dstFD.pd.waitWrite(dstFD.isFile); err != nil { + break + } + } + if err == syscall.EAGAIN { + err = nil + } + handled = written != 0 || (err != syscall.ENOSYS && err != syscall.EINVAL) + return +} diff --git a/contrib/go/_std_1.23/src/internal/poll/sendfile_solaris.go b/contrib/go/_std_1.23/src/internal/poll/sendfile_solaris.go new file mode 100644 index 000000000000..b7c3f81a1efd --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile_solaris.go @@ -0,0 +1,69 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll + +import "syscall" + +// Not strictly needed, but very helpful for debugging, see issue #10221. +// +//go:cgo_import_dynamic _ _ "libsendfile.so" +//go:cgo_import_dynamic _ _ "libsocket.so" + +// maxSendfileSize is the largest chunk size we ask the kernel to copy +// at a time. +const maxSendfileSize int = 4 << 20 + +// SendFile wraps the sendfile system call. +func SendFile(dstFD *FD, src int, pos, remain int64) (written int64, err error, handled bool) { + defer func() { + TestHookDidSendFile(dstFD, src, written, err, handled) + }() + if err := dstFD.writeLock(); err != nil { + return 0, err, false + } + defer dstFD.writeUnlock() + + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err, false + } + + dst := dstFD.Sysfd + for remain > 0 { + n := maxSendfileSize + if int64(n) > remain { + n = int(remain) + } + pos1 := pos + n, err = syscall.Sendfile(dst, src, &pos1, n) + if err == syscall.EAGAIN || err == syscall.EINTR { + // partial write may have occurred + n = int(pos1 - pos) + } + if n > 0 { + pos += int64(n) + written += int64(n) + remain -= int64(n) + continue + } else if err != syscall.EAGAIN && err != syscall.EINTR { + // This includes syscall.ENOSYS (no kernel + // support) and syscall.EINVAL (fd types which + // don't implement sendfile), and other errors. + // We should end the loop when there is no error + // returned from sendfile(2) or it is not a retryable error. + break + } + if err == syscall.EINTR { + continue + } + if err = dstFD.pd.waitWrite(dstFD.isFile); err != nil { + break + } + } + if err == syscall.EAGAIN { + err = nil + } + handled = written != 0 || (err != syscall.ENOSYS && err != syscall.EINVAL) + return +} diff --git a/contrib/go/_std_1.23/src/internal/poll/sendfile_windows.go b/contrib/go/_std_1.23/src/internal/poll/sendfile_windows.go new file mode 100644 index 000000000000..2ae8a8d1d791 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile_windows.go @@ -0,0 +1,87 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll + +import ( + "io" + "syscall" +) + +// SendFile wraps the TransmitFile call. +func SendFile(fd *FD, src syscall.Handle, n int64) (written int64, err error) { + defer func() { + TestHookDidSendFile(fd, 0, written, err, written > 0) + }() + if fd.kind == kindPipe { + // TransmitFile does not work with pipes + return 0, syscall.ESPIPE + } + if ft, _ := syscall.GetFileType(src); ft == syscall.FILE_TYPE_PIPE { + return 0, syscall.ESPIPE + } + + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + + o := &fd.wop + o.handle = src + + // TODO(brainman): skip calling syscall.Seek if OS allows it + curpos, err := syscall.Seek(o.handle, 0, io.SeekCurrent) + if err != nil { + return 0, err + } + + if n <= 0 { // We don't know the size of the file so infer it. + // Find the number of bytes offset from curpos until the end of the file. + n, err = syscall.Seek(o.handle, -curpos, io.SeekEnd) + if err != nil { + return + } + // Now seek back to the original position. + if _, err = syscall.Seek(o.handle, curpos, io.SeekStart); err != nil { + return + } + } + + // TransmitFile can be invoked in one call with at most + // 2,147,483,646 bytes: the maximum value for a 32-bit integer minus 1. + // See https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile + const maxChunkSizePerCall = int64(0x7fffffff - 1) + + for n > 0 { + chunkSize := maxChunkSizePerCall + if chunkSize > n { + chunkSize = n + } + + o.qty = uint32(chunkSize) + o.o.Offset = uint32(curpos) + o.o.OffsetHigh = uint32(curpos >> 32) + + nw, err := execIO(o, func(o *operation) error { + return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND) + }) + if err != nil { + return written, err + } + + curpos += int64(nw) + + // Some versions of Windows (Windows 10 1803) do not set + // file position after TransmitFile completes. + // So just use Seek to set file position. + if _, err = syscall.Seek(o.handle, curpos, io.SeekStart); err != nil { + return written, err + } + + n -= int64(nw) + written += int64(nw) + } + + return +} diff --git a/contrib/go/_std_1.23/src/internal/poll/sock_cloexec.go b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec.go new file mode 100644 index 000000000000..cbf7021804fa --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec.go @@ -0,0 +1,22 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements accept for platforms that provide a fast path for +// setting SetNonblock and CloseOnExec. + +//go:build dragonfly || freebsd || (linux && !arm) || netbsd || openbsd + +package poll + +import "syscall" + +// Wrapper around the accept system call that marks the returned file +// descriptor as nonblocking and close-on-exec. +func accept(s int) (int, syscall.Sockaddr, string, error) { + ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) + if err != nil { + return -1, nil, "accept4", err + } + return ns, sa, "", nil +} diff --git a/contrib/go/_std_1.22/src/internal/poll/sock_cloexec_accept.go b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec_accept.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sock_cloexec_accept.go rename to contrib/go/_std_1.23/src/internal/poll/sock_cloexec_accept.go diff --git a/contrib/go/_std_1.23/src/internal/poll/sock_cloexec_solaris.go b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec_solaris.go new file mode 100644 index 000000000000..92f150b6e5d8 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec_solaris.go @@ -0,0 +1,47 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements accept for platforms that provide a fast path for +// setting SetNonblock and CloseOnExec, but don't necessarily have accept4. +// The accept4(3c) function was added to Oracle Solaris in the Solaris 11.4.0 +// release. Thus, on releases prior to 11.4, we fall back to the combination +// of accept(3c) and fcntl(2). + +package poll + +import ( + "internal/syscall/unix" + "syscall" +) + +// Wrapper around the accept system call that marks the returned file +// descriptor as nonblocking and close-on-exec. +func accept(s int) (int, syscall.Sockaddr, string, error) { + // Perform a cheap test and try the fast path first. + if unix.SupportAccept4() { + ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) + if err != nil { + return -1, nil, "accept4", err + } + return ns, sa, "", nil + } + + // See ../syscall/exec_unix.go for description of ForkLock. + // It is probably okay to hold the lock across syscall.Accept + // because we have put fd.sysfd into non-blocking mode. + // However, a call to the File method will put it back into + // blocking mode. We can't take that risk, so no use of ForkLock here. + ns, sa, err := AcceptFunc(s) + if err == nil { + syscall.CloseOnExec(ns) + } + if err != nil { + return -1, nil, "accept", err + } + if err = syscall.SetNonblock(ns, true); err != nil { + CloseFunc(ns) + return -1, nil, "setnonblock", err + } + return ns, sa, "", nil +} diff --git a/contrib/go/_std_1.22/src/internal/poll/sockopt.go b/contrib/go/_std_1.23/src/internal/poll/sockopt.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockopt.go rename to contrib/go/_std_1.23/src/internal/poll/sockopt.go diff --git a/contrib/go/_std_1.22/src/internal/poll/sockopt_linux.go b/contrib/go/_std_1.23/src/internal/poll/sockopt_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockopt_linux.go rename to contrib/go/_std_1.23/src/internal/poll/sockopt_linux.go diff --git a/contrib/go/_std_1.22/src/internal/poll/sockopt_unix.go b/contrib/go/_std_1.23/src/internal/poll/sockopt_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockopt_unix.go rename to contrib/go/_std_1.23/src/internal/poll/sockopt_unix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/sockopt_windows.go b/contrib/go/_std_1.23/src/internal/poll/sockopt_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockopt_windows.go rename to contrib/go/_std_1.23/src/internal/poll/sockopt_windows.go diff --git a/contrib/go/_std_1.22/src/internal/poll/sockoptip.go b/contrib/go/_std_1.23/src/internal/poll/sockoptip.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockoptip.go rename to contrib/go/_std_1.23/src/internal/poll/sockoptip.go diff --git a/contrib/go/_std_1.23/src/internal/poll/splice_linux.go b/contrib/go/_std_1.23/src/internal/poll/splice_linux.go new file mode 100644 index 000000000000..193a56215c72 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/splice_linux.go @@ -0,0 +1,245 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll + +import ( + "internal/syscall/unix" + "runtime" + "sync" + "syscall" + "unsafe" +) + +const ( + // spliceNonblock doesn't make the splice itself necessarily nonblocking + // (because the actual file descriptors that are spliced from/to may block + // unless they have the O_NONBLOCK flag set), but it makes the splice pipe + // operations nonblocking. + spliceNonblock = 0x2 + + // maxSpliceSize is the maximum amount of data Splice asks + // the kernel to move in a single call to splice(2). + // We use 1MB as Splice writes data through a pipe, and 1MB is the default maximum pipe buffer size, + // which is determined by /proc/sys/fs/pipe-max-size. + maxSpliceSize = 1 << 20 +) + +// Splice transfers at most remain bytes of data from src to dst, using the +// splice system call to minimize copies of data from and to userspace. +// +// Splice gets a pipe buffer from the pool or creates a new one if needed, to serve as a buffer for the data transfer. +// src and dst must both be stream-oriented sockets. +func Splice(dst, src *FD, remain int64) (written int64, handled bool, err error) { + p, err := getPipe() + if err != nil { + return 0, false, err + } + defer putPipe(p) + var inPipe, n int + for err == nil && remain > 0 { + max := maxSpliceSize + if int64(max) > remain { + max = int(remain) + } + inPipe, err = spliceDrain(p.wfd, src, max) + // The operation is considered handled if splice returns no + // error, or an error other than EINVAL. An EINVAL means the + // kernel does not support splice for the socket type of src. + // The failed syscall does not consume any data so it is safe + // to fall back to a generic copy. + // + // spliceDrain should never return EAGAIN, so if err != nil, + // Splice cannot continue. + // + // If inPipe == 0 && err == nil, src is at EOF, and the + // transfer is complete. + handled = handled || (err != syscall.EINVAL) + if err != nil || inPipe == 0 { + break + } + p.data += inPipe + + n, err = splicePump(dst, p.rfd, inPipe) + if n > 0 { + written += int64(n) + remain -= int64(n) + p.data -= n + } + } + if err != nil { + return written, handled, err + } + return written, true, nil +} + +// spliceDrain moves data from a socket to a pipe. +// +// Invariant: when entering spliceDrain, the pipe is empty. It is either in its +// initial state, or splicePump has emptied it previously. +// +// Given this, spliceDrain can reasonably assume that the pipe is ready for +// writing, so if splice returns EAGAIN, it must be because the socket is not +// ready for reading. +// +// If spliceDrain returns (0, nil), src is at EOF. +func spliceDrain(pipefd int, sock *FD, max int) (int, error) { + if err := sock.readLock(); err != nil { + return 0, err + } + defer sock.readUnlock() + if err := sock.pd.prepareRead(sock.isFile); err != nil { + return 0, err + } + for { + // In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here, + // because it could return EAGAIN ceaselessly when the write end of the pipe is full, + // but this shouldn't be a concern here, since the pipe buffer must be sufficient for + // this data transmission on the basis of the workflow in Splice. + n, err := splice(pipefd, sock.Sysfd, max, spliceNonblock) + if err == syscall.EINTR { + continue + } + if err != syscall.EAGAIN { + return n, err + } + if sock.pd.pollable() { + if err := sock.pd.waitRead(sock.isFile); err != nil { + return n, err + } + } + } +} + +// splicePump moves all the buffered data from a pipe to a socket. +// +// Invariant: when entering splicePump, there are exactly inPipe +// bytes of data in the pipe, from a previous call to spliceDrain. +// +// By analogy to the condition from spliceDrain, splicePump +// only needs to poll the socket for readiness, if splice returns +// EAGAIN. +// +// If splicePump cannot move all the data in a single call to +// splice(2), it loops over the buffered data until it has written +// all of it to the socket. This behavior is similar to the Write +// step of an io.Copy in userspace. +func splicePump(sock *FD, pipefd int, inPipe int) (int, error) { + if err := sock.writeLock(); err != nil { + return 0, err + } + defer sock.writeUnlock() + if err := sock.pd.prepareWrite(sock.isFile); err != nil { + return 0, err + } + written := 0 + for inPipe > 0 { + // In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here, + // because it could return EAGAIN ceaselessly when the read end of the pipe is empty, + // but this shouldn't be a concern here, since the pipe buffer must contain inPipe size of + // data on the basis of the workflow in Splice. + n, err := splice(sock.Sysfd, pipefd, inPipe, spliceNonblock) + if err == syscall.EINTR { + continue + } + // Here, the condition n == 0 && err == nil should never be + // observed, since Splice controls the write side of the pipe. + if n > 0 { + inPipe -= n + written += n + continue + } + if err != syscall.EAGAIN { + return written, err + } + if sock.pd.pollable() { + if err := sock.pd.waitWrite(sock.isFile); err != nil { + return written, err + } + } + } + return written, nil +} + +// splice wraps the splice system call. Since the current implementation +// only uses splice on sockets and pipes, the offset arguments are unused. +// splice returns int instead of int64, because callers never ask it to +// move more data in a single call than can fit in an int32. +func splice(out int, in int, max int, flags int) (int, error) { + n, err := syscall.Splice(in, nil, out, nil, max, flags) + return int(n), err +} + +type splicePipeFields struct { + rfd int + wfd int + data int +} + +type splicePipe struct { + splicePipeFields + + // We want to use a finalizer, so ensure that the size is + // large enough to not use the tiny allocator. + _ [24 - unsafe.Sizeof(splicePipeFields{})%24]byte +} + +// splicePipePool caches pipes to avoid high-frequency construction and destruction of pipe buffers. +// The garbage collector will free all pipes in the sync.Pool periodically, thus we need to set up +// a finalizer for each pipe to close its file descriptors before the actual GC. +var splicePipePool = sync.Pool{New: newPoolPipe} + +func newPoolPipe() any { + // Discard the error which occurred during the creation of pipe buffer, + // redirecting the data transmission to the conventional way utilizing read() + write() as a fallback. + p := newPipe() + if p == nil { + return nil + } + runtime.SetFinalizer(p, destroyPipe) + return p +} + +// getPipe tries to acquire a pipe buffer from the pool or create a new one with newPipe() if it gets nil from the cache. +func getPipe() (*splicePipe, error) { + v := splicePipePool.Get() + if v == nil { + return nil, syscall.EINVAL + } + return v.(*splicePipe), nil +} + +func putPipe(p *splicePipe) { + // If there is still data left in the pipe, + // then close and discard it instead of putting it back into the pool. + if p.data != 0 { + runtime.SetFinalizer(p, nil) + destroyPipe(p) + return + } + splicePipePool.Put(p) +} + +// newPipe sets up a pipe for a splice operation. +func newPipe() *splicePipe { + var fds [2]int + if err := syscall.Pipe2(fds[:], syscall.O_CLOEXEC|syscall.O_NONBLOCK); err != nil { + return nil + } + + // Splice will loop writing maxSpliceSize bytes from the source to the pipe, + // and then write those bytes from the pipe to the destination. + // Set the pipe buffer size to maxSpliceSize to optimize that. + // Ignore errors here, as a smaller buffer size will work, + // although it will require more system calls. + unix.Fcntl(fds[0], syscall.F_SETPIPE_SZ, maxSpliceSize) + + return &splicePipe{splicePipeFields: splicePipeFields{rfd: fds[0], wfd: fds[1]}} +} + +// destroyPipe destroys a pipe. +func destroyPipe(p *splicePipe) { + CloseFunc(p.rfd) + CloseFunc(p.wfd) +} diff --git a/contrib/go/_std_1.22/src/internal/poll/sys_cloexec.go b/contrib/go/_std_1.23/src/internal/poll/sys_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sys_cloexec.go rename to contrib/go/_std_1.23/src/internal/poll/sys_cloexec.go diff --git a/contrib/go/_std_1.22/src/internal/poll/writev.go b/contrib/go/_std_1.23/src/internal/poll/writev.go similarity index 96% rename from contrib/go/_std_1.22/src/internal/poll/writev.go rename to contrib/go/_std_1.23/src/internal/poll/writev.go index 75c8b642b550..fb15c2730983 100644 --- a/contrib/go/_std_1.22/src/internal/poll/writev.go +++ b/contrib/go/_std_1.23/src/internal/poll/writev.go @@ -69,9 +69,7 @@ func (fd *FD) Writev(v *[][]byte) (int64, error) { TestHookDidWritev(int(wrote)) n += int64(wrote) consume(v, int64(wrote)) - for i := range iovecs { - iovecs[i] = syscall.Iovec{} - } + clear(iovecs) if err != nil { if err == syscall.EINTR { continue diff --git a/contrib/go/_std_1.23/src/internal/poll/ya.make b/contrib/go/_std_1.23/src/internal/poll/ya.make new file mode 100644 index 000000000000..2cb5b27c4e8c --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/ya.make @@ -0,0 +1,91 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + errno_unix.go + fd.go + fd_fsync_darwin.go + fd_mutex.go + fd_opendir_darwin.go + fd_poll_runtime.go + fd_posix.go + fd_unix.go + fd_unixjs.go + fd_writev_libc.go + hook_unix.go + iovec_unix.go + sendfile.go + sendfile_bsd.go + sockopt.go + sockopt_unix.go + sockoptip.go + sys_cloexec.go + writev.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + copy_file_range_linux.go + errno_unix.go + fd.go + fd_fsync_posix.go + fd_mutex.go + fd_poll_runtime.go + fd_posix.go + fd_unix.go + fd_unixjs.go + fd_writev_unix.go + hook_cloexec.go + hook_unix.go + iovec_unix.go + sendfile.go + sendfile_linux.go + sock_cloexec.go + sockopt.go + sockopt_linux.go + sockopt_unix.go + sockoptip.go + splice_linux.go + writev.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + copy_file_range_linux.go + errno_unix.go + fd.go + fd_fsync_posix.go + fd_mutex.go + fd_poll_runtime.go + fd_posix.go + fd_unix.go + fd_unixjs.go + fd_writev_unix.go + hook_cloexec.go + hook_unix.go + iovec_unix.go + sendfile.go + sendfile_linux.go + sock_cloexec_accept.go + sockopt.go + sockopt_linux.go + sockopt_unix.go + sockoptip.go + splice_linux.go + writev.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + errno_windows.go + fd.go + fd_fsync_windows.go + fd_mutex.go + fd_poll_runtime.go + fd_posix.go + fd_windows.go + hook_windows.go + sendfile.go + sendfile_windows.go + sockopt.go + sockopt_windows.go + sockoptip.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/profilerecord/profilerecord.go b/contrib/go/_std_1.23/src/internal/profilerecord/profilerecord.go new file mode 100644 index 000000000000..a5efdced8f77 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/profilerecord/profilerecord.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package profilerecord holds internal types used to represent profiling +// records with deep stack traces. +// +// TODO: Consider moving this to internal/runtime, see golang.org/issue/65355. +package profilerecord + +type StackRecord struct { + Stack []uintptr +} + +type MemProfileRecord struct { + AllocBytes, FreeBytes int64 + AllocObjects, FreeObjects int64 + Stack []uintptr +} + +func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes } +func (r *MemProfileRecord) InUseObjects() int64 { return r.AllocObjects - r.FreeObjects } + +type BlockProfileRecord struct { + Count int64 + Cycles int64 + Stack []uintptr +} diff --git a/contrib/go/_std_1.23/src/internal/profilerecord/ya.make b/contrib/go/_std_1.23/src/internal/profilerecord/ya.make new file mode 100644 index 000000000000..2a9f803d12de --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/profilerecord/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + profilerecord.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/race/doc.go b/contrib/go/_std_1.23/src/internal/race/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/race/doc.go rename to contrib/go/_std_1.23/src/internal/race/doc.go diff --git a/contrib/go/_std_1.22/src/internal/race/norace.go b/contrib/go/_std_1.23/src/internal/race/norace.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/race/norace.go rename to contrib/go/_std_1.23/src/internal/race/norace.go diff --git a/contrib/go/_std_1.22/src/internal/race/race.go b/contrib/go/_std_1.23/src/internal/race/race.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/race/race.go rename to contrib/go/_std_1.23/src/internal/race/race.go diff --git a/contrib/go/_std_1.23/src/internal/race/ya.make b/contrib/go/_std_1.23/src/internal/race/ya.make new file mode 100644 index 000000000000..258cb985b588 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/race/ya.make @@ -0,0 +1,13 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race.go + ) +ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + norace.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/asm.s b/contrib/go/_std_1.23/src/internal/reflectlite/asm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/reflectlite/asm.s rename to contrib/go/_std_1.23/src/internal/reflectlite/asm.s diff --git a/contrib/go/_std_1.23/src/internal/reflectlite/swapper.go b/contrib/go/_std_1.23/src/internal/reflectlite/swapper.go new file mode 100644 index 000000000000..e5ea535d5f85 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/reflectlite/swapper.go @@ -0,0 +1,78 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflectlite + +import ( + "internal/goarch" + "internal/unsafeheader" + "unsafe" +) + +// Swapper returns a function that swaps the elements in the provided +// slice. +// +// Swapper panics if the provided interface is not a slice. +func Swapper(slice any) func(i, j int) { + v := ValueOf(slice) + if v.Kind() != Slice { + panic(&ValueError{Method: "Swapper", Kind: v.Kind()}) + } + // Fast path for slices of size 0 and 1. Nothing to swap. + switch v.Len() { + case 0: + return func(i, j int) { panic("reflect: slice index out of range") } + case 1: + return func(i, j int) { + if i != 0 || j != 0 { + panic("reflect: slice index out of range") + } + } + } + + typ := v.Type().Elem().common() + size := typ.Size() + hasPtr := typ.Pointers() + + // Some common & small cases, without using memmove: + if hasPtr { + if size == goarch.PtrSize { + ps := *(*[]unsafe.Pointer)(v.ptr) + return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } + } + if typ.Kind() == String { + ss := *(*[]string)(v.ptr) + return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] } + } + } else { + switch size { + case 8: + is := *(*[]int64)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 4: + is := *(*[]int32)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 2: + is := *(*[]int16)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 1: + is := *(*[]int8)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + } + } + + s := (*unsafeheader.Slice)(v.ptr) + tmp := unsafe_New(typ) // swap scratch space + + return func(i, j int) { + if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) { + panic("reflect: slice index out of range") + } + val1 := arrayAt(s.Data, i, size, "i < s.Len") + val2 := arrayAt(s.Data, j, size, "j < s.Len") + typedmemmove(typ, tmp, val1) + typedmemmove(typ, val1, val2) + typedmemmove(typ, val2, tmp) + } +} diff --git a/contrib/go/_std_1.23/src/internal/reflectlite/type.go b/contrib/go/_std_1.23/src/internal/reflectlite/type.go new file mode 100644 index 000000000000..88cc50db9eda --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/reflectlite/type.go @@ -0,0 +1,643 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package reflectlite implements lightweight version of reflect, not using +// any package except for "runtime", "unsafe", and "internal/abi" +package reflectlite + +import ( + "internal/abi" + "unsafe" +) + +// Type is the representation of a Go type. +// +// Not all methods apply to all kinds of types. Restrictions, +// if any, are noted in the documentation for each method. +// Use the Kind method to find out the kind of type before +// calling kind-specific methods. Calling a method +// inappropriate to the kind of type causes a run-time panic. +// +// Type values are comparable, such as with the == operator, +// so they can be used as map keys. +// Two Type values are equal if they represent identical types. +type Type interface { + // Methods applicable to all types. + + // Name returns the type's name within its package for a defined type. + // For other (non-defined) types it returns the empty string. + Name() string + + // PkgPath returns a defined type's package path, that is, the import path + // that uniquely identifies the package, such as "encoding/base64". + // If the type was predeclared (string, error) or not defined (*T, struct{}, + // []int, or A where A is an alias for a non-defined type), the package path + // will be the empty string. + PkgPath() string + + // Size returns the number of bytes needed to store + // a value of the given type; it is analogous to unsafe.Sizeof. + Size() uintptr + + // Kind returns the specific kind of this type. + Kind() Kind + + // Implements reports whether the type implements the interface type u. + Implements(u Type) bool + + // AssignableTo reports whether a value of the type is assignable to type u. + AssignableTo(u Type) bool + + // Comparable reports whether values of this type are comparable. + Comparable() bool + + // String returns a string representation of the type. + // The string representation may use shortened package names + // (e.g., base64 instead of "encoding/base64") and is not + // guaranteed to be unique among types. To test for type identity, + // compare the Types directly. + String() string + + // Elem returns a type's element type. + // It panics if the type's Kind is not Ptr. + Elem() Type + + common() *abi.Type + uncommon() *uncommonType +} + +/* + * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go). + * A few are known to ../runtime/type.go to convey to debuggers. + * They are also known to ../runtime/type.go. + */ + +// A Kind represents the specific kind of type that a Type represents. +// The zero Kind is not a valid kind. +type Kind = abi.Kind + +const Ptr = abi.Pointer + +const ( + // Import-and-export these constants as necessary + Interface = abi.Interface + Slice = abi.Slice + String = abi.String + Struct = abi.Struct +) + +type nameOff = abi.NameOff +type typeOff = abi.TypeOff +type textOff = abi.TextOff + +type rtype struct { + *abi.Type +} + +// uncommonType is present only for defined types or types with methods +// (if T is a defined type, the uncommonTypes for T and *T have methods). +// Using a pointer to this struct reduces the overall size required +// to describe a non-defined type with no methods. +type uncommonType = abi.UncommonType + +// arrayType represents a fixed array type. +type arrayType = abi.ArrayType + +// chanType represents a channel type. +type chanType = abi.ChanType + +type funcType = abi.FuncType + +type interfaceType = abi.InterfaceType + +// ptrType represents a pointer type. +type ptrType = abi.PtrType + +// sliceType represents a slice type. +type sliceType = abi.SliceType + +// structType represents a struct type. +type structType = abi.StructType + +// name is an encoded type name with optional extra data. +// +// The first byte is a bit field containing: +// +// 1<<0 the name is exported +// 1<<1 tag data follows the name +// 1<<2 pkgPath nameOff follows the name and tag +// +// The next two bytes are the data length: +// +// l := uint16(data[1])<<8 | uint16(data[2]) +// +// Bytes [3:3+l] are the string data. +// +// If tag data follows then bytes 3+l and 3+l+1 are the tag length, +// with the data following. +// +// If the import path follows, then 4 bytes at the end of +// the data form a nameOff. The import path is only set for concrete +// methods that are defined in a different package than their type. +// +// If a name starts with "*", then the exported bit represents +// whether the pointed to type is exported. +type name struct { + bytes *byte +} + +func (n name) data(off int, whySafe string) *byte { + return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off), whySafe)) +} + +func (n name) isExported() bool { + return (*n.bytes)&(1<<0) != 0 +} + +func (n name) hasTag() bool { + return (*n.bytes)&(1<<1) != 0 +} + +func (n name) embedded() bool { + return (*n.bytes)&(1<<3) != 0 +} + +// readVarint parses a varint as encoded by encoding/binary. +// It returns the number of encoded bytes and the encoded value. +func (n name) readVarint(off int) (int, int) { + v := 0 + for i := 0; ; i++ { + x := *n.data(off+i, "read varint") + v += int(x&0x7f) << (7 * i) + if x&0x80 == 0 { + return i + 1, v + } + } +} + +func (n name) name() string { + if n.bytes == nil { + return "" + } + i, l := n.readVarint(1) + return unsafe.String(n.data(1+i, "non-empty string"), l) +} + +func (n name) tag() string { + if !n.hasTag() { + return "" + } + i, l := n.readVarint(1) + i2, l2 := n.readVarint(1 + i + l) + return unsafe.String(n.data(1+i+l+i2, "non-empty string"), l2) +} + +func pkgPath(n abi.Name) string { + if n.Bytes == nil || *n.DataChecked(0, "name flag field")&(1<<2) == 0 { + return "" + } + i, l := n.ReadVarint(1) + off := 1 + i + l + if n.HasTag() { + i2, l2 := n.ReadVarint(off) + off += i2 + l2 + } + var nameOff int32 + // Note that this field may not be aligned in memory, + // so we cannot use a direct int32 assignment here. + copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.DataChecked(off, "name offset field")))[:]) + pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n.Bytes), nameOff))} + return pkgPathName.name() +} + +/* + * The compiler knows the exact layout of all the data structures above. + * The compiler does not know about the data structures and methods below. + */ + +// resolveNameOff resolves a name offset from a base pointer. +// The (*rtype).nameOff method is a convenience wrapper for this function. +// Implemented in the runtime package. +// +//go:noescape +func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer + +// resolveTypeOff resolves an *rtype offset from a base type. +// The (*rtype).typeOff method is a convenience wrapper for this function. +// Implemented in the runtime package. +// +//go:noescape +func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer + +func (t rtype) nameOff(off nameOff) abi.Name { + return abi.Name{Bytes: (*byte)(resolveNameOff(unsafe.Pointer(t.Type), int32(off)))} +} + +func (t rtype) typeOff(off typeOff) *abi.Type { + return (*abi.Type)(resolveTypeOff(unsafe.Pointer(t.Type), int32(off))) +} + +func (t rtype) uncommon() *uncommonType { + return t.Uncommon() +} + +func (t rtype) String() string { + s := t.nameOff(t.Str).Name() + if t.TFlag&abi.TFlagExtraStar != 0 { + return s[1:] + } + return s +} + +func (t rtype) common() *abi.Type { return t.Type } + +func (t rtype) exportedMethods() []abi.Method { + ut := t.uncommon() + if ut == nil { + return nil + } + return ut.ExportedMethods() +} + +func (t rtype) NumMethod() int { + tt := t.Type.InterfaceType() + if tt != nil { + return tt.NumMethod() + } + return len(t.exportedMethods()) +} + +func (t rtype) PkgPath() string { + if t.TFlag&abi.TFlagNamed == 0 { + return "" + } + ut := t.uncommon() + if ut == nil { + return "" + } + return t.nameOff(ut.PkgPath).Name() +} + +func (t rtype) Name() string { + if !t.HasName() { + return "" + } + s := t.String() + i := len(s) - 1 + sqBrackets := 0 + for i >= 0 && (s[i] != '.' || sqBrackets != 0) { + switch s[i] { + case ']': + sqBrackets++ + case '[': + sqBrackets-- + } + i-- + } + return s[i+1:] +} + +func toRType(t *abi.Type) rtype { + return rtype{t} +} + +func elem(t *abi.Type) *abi.Type { + et := t.Elem() + if et != nil { + return et + } + panic("reflect: Elem of invalid type " + toRType(t).String()) +} + +func (t rtype) Elem() Type { + return toType(elem(t.common())) +} + +func (t rtype) In(i int) Type { + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: In of non-func type") + } + return toType(tt.InSlice()[i]) +} + +func (t rtype) Key() Type { + tt := t.Type.MapType() + if tt == nil { + panic("reflect: Key of non-map type") + } + return toType(tt.Key) +} + +func (t rtype) Len() int { + tt := t.Type.ArrayType() + if tt == nil { + panic("reflect: Len of non-array type") + } + return int(tt.Len) +} + +func (t rtype) NumField() int { + tt := t.Type.StructType() + if tt == nil { + panic("reflect: NumField of non-struct type") + } + return len(tt.Fields) +} + +func (t rtype) NumIn() int { + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: NumIn of non-func type") + } + return int(tt.InCount) +} + +func (t rtype) NumOut() int { + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: NumOut of non-func type") + } + return tt.NumOut() +} + +func (t rtype) Out(i int) Type { + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: Out of non-func type") + } + return toType(tt.OutSlice()[i]) +} + +// add returns p+x. +// +// The whySafe string is ignored, so that the function still inlines +// as efficiently as p+x, but all call sites should use the string to +// record why the addition is safe, which is to say why the addition +// does not cause x to advance to the very end of p's allocation +// and therefore point incorrectly at the next block in memory. +func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { + return unsafe.Pointer(uintptr(p) + x) +} + +// TypeOf returns the reflection Type that represents the dynamic type of i. +// If i is a nil interface value, TypeOf returns nil. +func TypeOf(i any) Type { + return toType(abi.TypeOf(i)) +} + +func (t rtype) Implements(u Type) bool { + if u == nil { + panic("reflect: nil type passed to Type.Implements") + } + if u.Kind() != Interface { + panic("reflect: non-interface type passed to Type.Implements") + } + return implements(u.common(), t.common()) +} + +func (t rtype) AssignableTo(u Type) bool { + if u == nil { + panic("reflect: nil type passed to Type.AssignableTo") + } + uu := u.common() + tt := t.common() + return directlyAssignable(uu, tt) || implements(uu, tt) +} + +func (t rtype) Comparable() bool { + return t.Equal != nil +} + +// implements reports whether the type V implements the interface type T. +func implements(T, V *abi.Type) bool { + t := T.InterfaceType() + if t == nil { + return false + } + if len(t.Methods) == 0 { + return true + } + rT := toRType(T) + rV := toRType(V) + + // The same algorithm applies in both cases, but the + // method tables for an interface type and a concrete type + // are different, so the code is duplicated. + // In both cases the algorithm is a linear scan over the two + // lists - T's methods and V's methods - simultaneously. + // Since method tables are stored in a unique sorted order + // (alphabetical, with no duplicate method names), the scan + // through V's methods must hit a match for each of T's + // methods along the way, or else V does not implement T. + // This lets us run the scan in overall linear time instead of + // the quadratic time a naive search would require. + // See also ../runtime/iface.go. + if V.Kind() == Interface { + v := (*interfaceType)(unsafe.Pointer(V)) + i := 0 + for j := 0; j < len(v.Methods); j++ { + tm := &t.Methods[i] + tmName := rT.nameOff(tm.Name) + vm := &v.Methods[j] + vmName := rV.nameOff(vm.Name) + if vmName.Name() == tmName.Name() && rV.typeOff(vm.Typ) == rT.typeOff(tm.Typ) { + if !tmName.IsExported() { + tmPkgPath := pkgPath(tmName) + if tmPkgPath == "" { + tmPkgPath = t.PkgPath.Name() + } + vmPkgPath := pkgPath(vmName) + if vmPkgPath == "" { + vmPkgPath = v.PkgPath.Name() + } + if tmPkgPath != vmPkgPath { + continue + } + } + if i++; i >= len(t.Methods) { + return true + } + } + } + return false + } + + v := V.Uncommon() + if v == nil { + return false + } + i := 0 + vmethods := v.Methods() + for j := 0; j < int(v.Mcount); j++ { + tm := &t.Methods[i] + tmName := rT.nameOff(tm.Name) + vm := vmethods[j] + vmName := rV.nameOff(vm.Name) + if vmName.Name() == tmName.Name() && rV.typeOff(vm.Mtyp) == rT.typeOff(tm.Typ) { + if !tmName.IsExported() { + tmPkgPath := pkgPath(tmName) + if tmPkgPath == "" { + tmPkgPath = t.PkgPath.Name() + } + vmPkgPath := pkgPath(vmName) + if vmPkgPath == "" { + vmPkgPath = rV.nameOff(v.PkgPath).Name() + } + if tmPkgPath != vmPkgPath { + continue + } + } + if i++; i >= len(t.Methods) { + return true + } + } + } + return false +} + +// directlyAssignable reports whether a value x of type V can be directly +// assigned (using memmove) to a value of type T. +// https://golang.org/doc/go_spec.html#Assignability +// Ignoring the interface rules (implemented elsewhere) +// and the ideal constant rules (no ideal constants at run time). +func directlyAssignable(T, V *abi.Type) bool { + // x's type V is identical to T? + if T == V { + return true + } + + // Otherwise at least one of T and V must not be defined + // and they must have the same kind. + if T.HasName() && V.HasName() || T.Kind() != V.Kind() { + return false + } + + // x's type T and V must have identical underlying types. + return haveIdenticalUnderlyingType(T, V, true) +} + +func haveIdenticalType(T, V *abi.Type, cmpTags bool) bool { + if cmpTags { + return T == V + } + + if toRType(T).Name() != toRType(V).Name() || T.Kind() != V.Kind() { + return false + } + + return haveIdenticalUnderlyingType(T, V, false) +} + +func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool { + if T == V { + return true + } + + kind := T.Kind() + if kind != V.Kind() { + return false + } + + // Non-composite types of equal kind have same underlying type + // (the predefined instance of the type). + if abi.Bool <= kind && kind <= abi.Complex128 || kind == abi.String || kind == abi.UnsafePointer { + return true + } + + // Composite types. + switch kind { + case abi.Array: + return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case abi.Chan: + // Special case: + // x is a bidirectional channel value, T is a channel type, + // and x's type V and T have identical element types. + if V.ChanDir() == abi.BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) { + return true + } + + // Otherwise continue test for identical underlying type. + return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case abi.Func: + t := (*funcType)(unsafe.Pointer(T)) + v := (*funcType)(unsafe.Pointer(V)) + if t.OutCount != v.OutCount || t.InCount != v.InCount { + return false + } + for i := 0; i < t.NumIn(); i++ { + if !haveIdenticalType(t.In(i), v.In(i), cmpTags) { + return false + } + } + for i := 0; i < t.NumOut(); i++ { + if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) { + return false + } + } + return true + + case Interface: + t := (*interfaceType)(unsafe.Pointer(T)) + v := (*interfaceType)(unsafe.Pointer(V)) + if len(t.Methods) == 0 && len(v.Methods) == 0 { + return true + } + // Might have the same methods but still + // need a run time conversion. + return false + + case abi.Map: + return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case Ptr, abi.Slice: + return haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case abi.Struct: + t := (*structType)(unsafe.Pointer(T)) + v := (*structType)(unsafe.Pointer(V)) + if len(t.Fields) != len(v.Fields) { + return false + } + if t.PkgPath.Name() != v.PkgPath.Name() { + return false + } + for i := range t.Fields { + tf := &t.Fields[i] + vf := &v.Fields[i] + if tf.Name.Name() != vf.Name.Name() { + return false + } + if !haveIdenticalType(tf.Typ, vf.Typ, cmpTags) { + return false + } + if cmpTags && tf.Name.Tag() != vf.Name.Tag() { + return false + } + if tf.Offset != vf.Offset { + return false + } + if tf.Embedded() != vf.Embedded() { + return false + } + } + return true + } + + return false +} + +// toType converts from a *rtype to a Type that can be returned +// to the client of package reflect. In gc, the only concern is that +// a nil *rtype must be replaced by a nil Type, but in gccgo this +// function takes care of ensuring that multiple *rtype for the same +// type are coalesced into a single Type. +func toType(t *abi.Type) Type { + if t == nil { + return nil + } + return toRType(t) +} diff --git a/contrib/go/_std_1.23/src/internal/reflectlite/value.go b/contrib/go/_std_1.23/src/internal/reflectlite/value.go new file mode 100644 index 000000000000..c38b498ea7e2 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/reflectlite/value.go @@ -0,0 +1,478 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflectlite + +import ( + "internal/abi" + "internal/goarch" + "internal/unsafeheader" + "runtime" + "unsafe" +) + +// Value is the reflection interface to a Go value. +// +// Not all methods apply to all kinds of values. Restrictions, +// if any, are noted in the documentation for each method. +// Use the Kind method to find out the kind of value before +// calling kind-specific methods. Calling a method +// inappropriate to the kind of type causes a run time panic. +// +// The zero Value represents no value. +// Its IsValid method returns false, its Kind method returns Invalid, +// its String method returns "", and all other methods panic. +// Most functions and methods never return an invalid value. +// If one does, its documentation states the conditions explicitly. +// +// A Value can be used concurrently by multiple goroutines provided that +// the underlying Go value can be used concurrently for the equivalent +// direct operations. +// +// To compare two Values, compare the results of the Interface method. +// Using == on two Values does not compare the underlying values +// they represent. +type Value struct { + // typ_ holds the type of the value represented by a Value. + // Access using the typ method to avoid escape of v. + typ_ *abi.Type + + // Pointer-valued data or, if flagIndir is set, pointer to data. + // Valid when either flagIndir is set or typ.pointers() is true. + ptr unsafe.Pointer + + // flag holds metadata about the value. + // The lowest bits are flag bits: + // - flagStickyRO: obtained via unexported not embedded field, so read-only + // - flagEmbedRO: obtained via unexported embedded field, so read-only + // - flagIndir: val holds a pointer to the data + // - flagAddr: v.CanAddr is true (implies flagIndir) + // Value cannot represent method values. + // The next five bits give the Kind of the value. + // This repeats typ.Kind() except for method values. + // The remaining 23+ bits give a method number for method values. + // If flag.kind() != Func, code can assume that flagMethod is unset. + // If ifaceIndir(typ), code can assume that flagIndir is set. + flag + + // A method value represents a curried method invocation + // like r.Read for some receiver r. The typ+val+flag bits describe + // the receiver r, but the flag's Kind bits say Func (methods are + // functions), and the top bits of the flag give the method number + // in r's type's method table. +} + +type flag uintptr + +const ( + flagKindWidth = 5 // there are 27 kinds + flagKindMask flag = 1<= len, +// because then the result will point outside the array. +// whySafe must explain why i < len. (Passing "i < len" is fine; +// the benefit is to surface this assumption at the call site.) +func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer { + return add(p, uintptr(i)*eltSize, "i < len") +} + +func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) + +// typedmemmove copies a value of type t to dst from src. +// +//go:noescape +func typedmemmove(t *abi.Type, dst, src unsafe.Pointer) + +// Dummy annotation marking that the value x escapes, +// for use in cases where the reflect code is so clever that +// the compiler cannot follow. +func escapes(x any) { + if dummy.b { + dummy.x = x + } +} + +var dummy struct { + b bool + x any +} diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/ya.make b/contrib/go/_std_1.23/src/internal/reflectlite/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/reflectlite/ya.make rename to contrib/go/_std_1.23/src/internal/reflectlite/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.go index e74dcaa92dd3..a023baddb764 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.go @@ -12,6 +12,7 @@ import "unsafe" // //go:linkname Load //go:linkname Loadp +//go:linkname LoadAcquintptr //go:nosplit //go:noinline diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_amd64.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_amd64.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_amd64.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_amd64.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_andor_generic.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_andor_generic.go similarity index 79% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_andor_generic.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_andor_generic.go index 00b402681ed6..433ee0bd6c21 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_andor_generic.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_andor_generic.go @@ -2,10 +2,21 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build arm || s390x || loong64 || mips || mipsle || mips64 || mips64le || wasm +//go:build arm || wasm + +// Export some functions via linkname to assembly in sync/atomic. +// +//go:linkname And32 +//go:linkname Or32 +//go:linkname And64 +//go:linkname Or64 +//go:linkname Anduintptr +//go:linkname Oruintptr package atomic +import _ "unsafe" // For linkname + //go:nosplit func And32(ptr *uint32, val uint32) uint32 { for { diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.go index 567e95124480..b58f643ca34c 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.go @@ -19,6 +19,7 @@ const ( // //go:linkname Xchg //go:linkname Xchguintptr +//go:linkname Xadd type spinlock struct { v uint32 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.s similarity index 91% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.s index 3a249d3ed2b0..ede56538b880 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.s @@ -128,17 +128,21 @@ TEXT ·Store64(SB), NOSPLIT, $0-16 TEXT ·Xchg(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW new+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif SWPALW R1, (R0), R2 MOVW R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 STLXRW R1, (R0), R3 CBNZ R3, load_store_loop MOVW R2, ret+16(FP) RET +#endif // uint64 Xchg64(ptr *uint64, new uint64) // Atomically: @@ -148,17 +152,21 @@ load_store_loop: TEXT ·Xchg64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD new+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif SWPALD R1, (R0), R2 MOVD R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R2 STLXR R1, (R0), R3 CBNZ R3, load_store_loop MOVD R2, ret+16(FP) RET +#endif // bool Cas(uint32 *ptr, uint32 old, uint32 new) // Atomically: @@ -171,14 +179,17 @@ TEXT ·Cas(SB), NOSPLIT, $0-17 MOVD ptr+0(FP), R0 MOVW old+8(FP), R1 MOVW new+12(FP), R2 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MOVD R1, R3 CASALW R3, (R0), R2 CMP R1, R3 CSET EQ, R0 MOVB R0, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R3 CMPW R1, R3 @@ -189,6 +200,7 @@ ok: CSET EQ, R0 MOVB R0, ret+16(FP) RET +#endif // bool ·Cas64(uint64 *ptr, uint64 old, uint64 new) // Atomically: @@ -202,14 +214,17 @@ TEXT ·Cas64(SB), NOSPLIT, $0-25 MOVD ptr+0(FP), R0 MOVD old+8(FP), R1 MOVD new+16(FP), R2 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MOVD R1, R3 CASALD R3, (R0), R2 CMP R1, R3 CSET EQ, R0 MOVB R0, ret+24(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R3 CMP R1, R3 @@ -220,6 +235,7 @@ ok: CSET EQ, R0 MOVB R0, ret+24(FP) RET +#endif // uint32 xadd(uint32 volatile *ptr, int32 delta) // Atomically: @@ -228,12 +244,15 @@ ok: TEXT ·Xadd(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW delta+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDADDALW R1, (R0), R2 ADD R1, R2 MOVW R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 ADDW R2, R1, R2 @@ -241,6 +260,7 @@ load_store_loop: CBNZ R3, load_store_loop MOVW R2, ret+16(FP) RET +#endif // uint64 Xadd64(uint64 volatile *ptr, int64 delta) // Atomically: @@ -249,12 +269,15 @@ load_store_loop: TEXT ·Xadd64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD delta+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDADDALD R1, (R0), R2 ADD R1, R2 MOVD R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R2 ADD R2, R1, R2 @@ -262,6 +285,7 @@ load_store_loop: CBNZ R3, load_store_loop MOVD R2, ret+16(FP) RET +#endif TEXT ·Xchgint32(SB), NOSPLIT, $0-20 B ·Xchg(SB) @@ -275,72 +299,91 @@ TEXT ·Xchguintptr(SB), NOSPLIT, $0-24 TEXT ·And8(SB), NOSPLIT, $0-9 MOVD ptr+0(FP), R0 MOVB val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MVN R1, R2 LDCLRALB R2, (R0), R3 RET +#ifndef GOARM64_LSE load_store_loop: LDAXRB (R0), R2 AND R1, R2 STLXRB R2, (R0), R3 CBNZ R3, load_store_loop RET +#endif TEXT ·Or8(SB), NOSPLIT, $0-9 MOVD ptr+0(FP), R0 MOVB val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDORALB R1, (R0), R2 RET +#ifndef GOARM64_LSE load_store_loop: LDAXRB (R0), R2 ORR R1, R2 STLXRB R2, (R0), R3 CBNZ R3, load_store_loop RET +#endif // func And(addr *uint32, v uint32) TEXT ·And(SB), NOSPLIT, $0-12 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MVN R1, R2 LDCLRALW R2, (R0), R3 RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 AND R1, R2 STLXRW R2, (R0), R3 CBNZ R3, load_store_loop RET +#endif // func Or(addr *uint32, v uint32) TEXT ·Or(SB), NOSPLIT, $0-12 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDORALW R1, (R0), R2 RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 ORR R1, R2 STLXRW R2, (R0), R3 CBNZ R3, load_store_loop RET +#endif // func Or32(addr *uint32, v uint32) old uint32 TEXT ·Or32(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDORALW R1, (R0), R2 MOVD R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 ORR R1, R2, R3 @@ -348,17 +391,21 @@ load_store_loop: CBNZ R4, load_store_loop MOVD R2, ret+16(FP) RET +#endif // func And32(addr *uint32, v uint32) old uint32 TEXT ·And32(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MVN R1, R2 LDCLRALW R2, (R0), R3 MOVD R3, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 AND R1, R2, R3 @@ -366,16 +413,20 @@ load_store_loop: CBNZ R4, load_store_loop MOVD R2, ret+16(FP) RET +#endif // func Or64(addr *uint64, v uint64) old uint64 TEXT ·Or64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDORALD R1, (R0), R2 MOVD R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R2 ORR R1, R2, R3 @@ -383,17 +434,21 @@ load_store_loop: CBNZ R4, load_store_loop MOVD R2, ret+16(FP) RET +#endif // func And64(addr *uint64, v uint64) old uint64 TEXT ·And64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MVN R1, R2 LDCLRALD R2, (R0), R3 MOVD R3, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R2 AND R1, R2, R3 @@ -401,6 +456,7 @@ load_store_loop: CBNZ R4, load_store_loop MOVD R2, ret+16(FP) RET +#endif // func Anduintptr(addr *uintptr, v uintptr) old uintptr TEXT ·Anduintptr(SB), NOSPLIT, $0-24 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.go index d82a5b8e2ac8..de6d4b4ba67d 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.go @@ -59,6 +59,24 @@ func Or8(ptr *uint8, val uint8) //go:noescape func Or(ptr *uint32, val uint32) +//go:noescape +func And32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Or32(ptr *uint32, val uint32) uint32 + +//go:noescape +func And64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Or64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Anduintptr(ptr *uintptr, val uintptr) uintptr + +//go:noescape +func Oruintptr(ptr *uintptr, val uintptr) uintptr + // NOTE: Do not add atomicxor8 (XOR is not idempotent). //go:noescape diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.s similarity index 78% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.s index 34193add3ed6..1812cb95fd4e 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.s @@ -256,7 +256,67 @@ TEXT ·And(SB), NOSPLIT, $0-12 DBAR RET -// uint32 runtime∕internal∕atomic·Load(uint32 volatile* ptr) +// func Or32(addr *uint32, v uint32) old uint32 +TEXT ·Or32(SB), NOSPLIT, $0-20 + MOVV ptr+0(FP), R4 + MOVW val+8(FP), R5 + DBAR + LL (R4), R6 + OR R5, R6, R7 + SC R7, (R4) + BEQ R7, -4(PC) + DBAR + MOVW R6, ret+16(FP) + RET + +// func And32(addr *uint32, v uint32) old uint32 +TEXT ·And32(SB), NOSPLIT, $0-20 + MOVV ptr+0(FP), R4 + MOVW val+8(FP), R5 + DBAR + LL (R4), R6 + AND R5, R6, R7 + SC R7, (R4) + BEQ R7, -4(PC) + DBAR + MOVW R6, ret+16(FP) + RET + +// func Or64(addr *uint64, v uint64) old uint64 +TEXT ·Or64(SB), NOSPLIT, $0-24 + MOVV ptr+0(FP), R4 + MOVV val+8(FP), R5 + DBAR + LLV (R4), R6 + OR R5, R6, R7 + SCV R7, (R4) + BEQ R7, -4(PC) + DBAR + MOVV R6, ret+16(FP) + RET + +// func And64(addr *uint64, v uint64) old uint64 +TEXT ·And64(SB), NOSPLIT, $0-24 + MOVV ptr+0(FP), R4 + MOVV val+8(FP), R5 + DBAR + LLV (R4), R6 + AND R5, R6, R7 + SCV R7, (R4) + BEQ R7, -4(PC) + DBAR + MOVV R6, ret+16(FP) + RET + +// func Anduintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Anduintptr(SB), NOSPLIT, $0-24 + JMP ·And64(SB) + +// func Oruintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Oruintptr(SB), NOSPLIT, $0-24 + JMP ·Or64(SB) + +// uint32 internal∕runtime∕atomic·Load(uint32 volatile* ptr) TEXT ·Load(SB),NOSPLIT|NOFRAME,$0-12 MOVV ptr+0(FP), R19 DBAR @@ -265,7 +325,7 @@ TEXT ·Load(SB),NOSPLIT|NOFRAME,$0-12 MOVW R19, ret+8(FP) RET -// uint8 runtime∕internal∕atomic·Load8(uint8 volatile* ptr) +// uint8 internal∕runtime∕atomic·Load8(uint8 volatile* ptr) TEXT ·Load8(SB),NOSPLIT|NOFRAME,$0-9 MOVV ptr+0(FP), R19 DBAR @@ -274,7 +334,7 @@ TEXT ·Load8(SB),NOSPLIT|NOFRAME,$0-9 MOVB R19, ret+8(FP) RET -// uint64 runtime∕internal∕atomic·Load64(uint64 volatile* ptr) +// uint64 internal∕runtime∕atomic·Load64(uint64 volatile* ptr) TEXT ·Load64(SB),NOSPLIT|NOFRAME,$0-16 MOVV ptr+0(FP), R19 DBAR @@ -283,7 +343,7 @@ TEXT ·Load64(SB),NOSPLIT|NOFRAME,$0-16 MOVV R19, ret+8(FP) RET -// void *runtime∕internal∕atomic·Loadp(void *volatile *ptr) +// void *internal∕runtime∕atomic·Loadp(void *volatile *ptr) TEXT ·Loadp(SB),NOSPLIT|NOFRAME,$0-16 MOVV ptr+0(FP), R19 DBAR @@ -292,7 +352,7 @@ TEXT ·Loadp(SB),NOSPLIT|NOFRAME,$0-16 MOVV R19, ret+8(FP) RET -// uint32 runtime∕internal∕atomic·LoadAcq(uint32 volatile* ptr) +// uint32 internal∕runtime∕atomic·LoadAcq(uint32 volatile* ptr) TEXT ·LoadAcq(SB),NOSPLIT|NOFRAME,$0-12 JMP ·Load(SB) diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.go index 1e12b83801db..f434c939e3c8 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.go @@ -61,6 +61,24 @@ func And(ptr *uint32, val uint32) //go:noescape func Or(ptr *uint32, val uint32) +//go:noescape +func And32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Or32(ptr *uint32, val uint32) uint32 + +//go:noescape +func And64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Or64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Anduintptr(ptr *uintptr, val uintptr) uintptr + +//go:noescape +func Oruintptr(ptr *uintptr, val uintptr) uintptr + //go:noescape func Cas64(ptr *uint64, old, new uint64) bool diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.s similarity index 84% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.s index b4411d87da65..7b0e080238d0 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.s @@ -310,6 +310,70 @@ TEXT ·And(SB), NOSPLIT, $0-12 SYNC RET +// func Or32(addr *uint32, v uint32) old uint32 +TEXT ·Or32(SB), NOSPLIT, $0-20 + MOVV ptr+0(FP), R1 + MOVW val+8(FP), R2 + + SYNC + LL (R1), R3 + OR R2, R3, R4 + SC R4, (R1) + BEQ R4, -3(PC) + SYNC + MOVW R3, ret+16(FP) + RET + +// func And32(addr *uint32, v uint32) old uint32 +TEXT ·And32(SB), NOSPLIT, $0-20 + MOVV ptr+0(FP), R1 + MOVW val+8(FP), R2 + + SYNC + LL (R1), R3 + AND R2, R3, R4 + SC R4, (R1) + BEQ R4, -3(PC) + SYNC + MOVW R3, ret+16(FP) + RET + +// func Or64(addr *uint64, v uint64) old uint64 +TEXT ·Or64(SB), NOSPLIT, $0-24 + MOVV ptr+0(FP), R1 + MOVV val+8(FP), R2 + + SYNC + LLV (R1), R3 + OR R2, R3, R4 + SCV R4, (R1) + BEQ R4, -3(PC) + SYNC + MOVV R3, ret+16(FP) + RET + +// func And64(addr *uint64, v uint64) old uint64 +TEXT ·And64(SB), NOSPLIT, $0-24 + MOVV ptr+0(FP), R1 + MOVV val+8(FP), R2 + + SYNC + LLV (R1), R3 + AND R2, R3, R4 + SCV R4, (R1) + BEQ R4, -3(PC) + SYNC + MOVV R3, ret+16(FP) + RET + +// func Anduintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Anduintptr(SB), NOSPLIT, $0-24 + JMP ·And64(SB) + +// func Oruintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Oruintptr(SB), NOSPLIT, $0-24 + JMP ·Or64(SB) + // uint32 ·Load(uint32 volatile* ptr) TEXT ·Load(SB),NOSPLIT|NOFRAME,$0-12 MOVV ptr+0(FP), R1 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.go similarity index 82% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.go index e3dcde1bde94..aba4143ea661 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.go @@ -11,6 +11,8 @@ //go:linkname Cas64 //go:linkname Load64 //go:linkname Store64 +//go:linkname Or64 +//go:linkname And64 package atomic @@ -104,6 +106,26 @@ func Store64(addr *uint64, val uint64) { return } +//go:nosplit +func Or64(addr *uint64, val uint64) (old uint64) { + for { + old = *addr + if Cas64(addr, old, old|val) { + return old + } + } +} + +//go:nosplit +func And64(addr *uint64, val uint64) (old uint64) { + for { + old = *addr + if Cas64(addr, old, old&val) { + return old + } + } +} + //go:noescape func Xadd(ptr *uint32, delta int32) uint32 @@ -143,6 +165,18 @@ func And(ptr *uint32, val uint32) //go:noescape func Or(ptr *uint32, val uint32) +//go:noescape +func And32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Or32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Anduintptr(ptr *uintptr, val uintptr) uintptr + +//go:noescape +func Oruintptr(ptr *uintptr, val uintptr) uintptr + //go:noescape func Store(ptr *uint32, val uint32) diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.s similarity index 87% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.s index 8f5fc53cb77e..4ccc0a363b7f 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.s @@ -240,6 +240,42 @@ TEXT ·And(SB), NOSPLIT, $0-8 SYNC RET +// func Or32(addr *uint32, v uint32) old uint32 +TEXT ·Or32(SB), NOSPLIT, $0-12 + MOVW ptr+0(FP), R1 + MOVW val+4(FP), R2 + + SYNC + LL (R1), R3 + OR R2, R3, R4 + SC R4, (R1) + BEQ R4, -4(PC) + SYNC + MOVW R3, ret+8(FP) + RET + +// func And32(addr *uint32, v uint32) old uint32 +TEXT ·And32(SB), NOSPLIT, $0-12 + MOVW ptr+0(FP), R1 + MOVW val+4(FP), R2 + + SYNC + LL (R1), R3 + AND R2, R3, R4 + SC R4, (R1) + BEQ R4, -4(PC) + SYNC + MOVW R3, ret+8(FP) + RET + +// func Anduintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Anduintptr(SB), NOSPLIT, $0-12 + JMP ·And32(SB) + +// func Oruintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Oruintptr(SB), NOSPLIT, $0-12 + JMP ·Or32(SB) + TEXT ·spinLock(SB),NOSPLIT,$0-4 MOVW state+0(FP), R1 MOVW $1, R2 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_ppc64x.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_ppc64x.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_ppc64x.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_ppc64x.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_riscv64.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_riscv64.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_riscv64.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_riscv64.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.go similarity index 85% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.go index 9855bf0780fb..68b4e160f9a8 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.go @@ -98,6 +98,24 @@ func And(ptr *uint32, val uint32) //go:noescape func Or(ptr *uint32, val uint32) +//go:noescape +func And32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Or32(ptr *uint32, val uint32) uint32 + +//go:noescape +func And64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Or64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Anduintptr(ptr *uintptr, val uintptr) uintptr + +//go:noescape +func Oruintptr(ptr *uintptr, val uintptr) uintptr + //go:noescape func Xadd(ptr *uint32, delta int32) uint32 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.s similarity index 82% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.s index a0c204b0e121..6e4ea0e32a7f 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.s @@ -246,3 +246,59 @@ TEXT ·And(SB), NOSPLIT, $0-12 MOVW val+8(FP), R4 LAN R4, R6, 0(R3) // R6 = *R3; *R3 &= R4; (atomic) RET + +// func Or32(addr *uint32, v uint32) old uint32 +TEXT ·Or32(SB), NOSPLIT, $0-20 + MOVD ptr+0(FP), R4 + MOVW val+8(FP), R5 + MOVW (R4), R3 +repeat: + OR R5, R3, R6 + CS R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4) + BNE repeat + MOVW R3, ret+16(FP) + RET + +// func And32(addr *uint32, v uint32) old uint32 +TEXT ·And32(SB), NOSPLIT, $0-20 + MOVD ptr+0(FP), R4 + MOVW val+8(FP), R5 + MOVW (R4), R3 +repeat: + AND R5, R3, R6 + CS R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4) + BNE repeat + MOVW R3, ret+16(FP) + RET + +// func Or64(addr *uint64, v uint64) old uint64 +TEXT ·Or64(SB), NOSPLIT, $0-24 + MOVD ptr+0(FP), R4 + MOVD val+8(FP), R5 + MOVD (R4), R3 +repeat: + OR R5, R3, R6 + CSG R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4) + BNE repeat + MOVD R3, ret+16(FP) + RET + +// func And64(addr *uint64, v uint64) old uint64 +TEXT ·And64(SB), NOSPLIT, $0-24 + MOVD ptr+0(FP), R4 + MOVD val+8(FP), R5 + MOVD (R4), R3 +repeat: + AND R5, R3, R6 + CSG R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4) + BNE repeat + MOVD R3, ret+16(FP) + RET + +// func Anduintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Anduintptr(SB), NOSPLIT, $0-24 + BR ·And64(SB) + +// func Oruintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Oruintptr(SB), NOSPLIT, $0-24 + BR ·Or64(SB) diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.go index 835fc43ccf9f..d1dcfec7adde 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.go @@ -13,6 +13,7 @@ //go:linkname Loadint32 //go:linkname Loadint64 //go:linkname Loaduintptr +//go:linkname LoadAcquintptr //go:linkname Xadd //go:linkname Xaddint32 //go:linkname Xaddint64 @@ -33,6 +34,7 @@ //go:linkname Storeint32 //go:linkname Storeint64 //go:linkname Storeuintptr +//go:linkname StoreReluintptr package atomic diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/doc.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/doc.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/doc.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/stubs.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/stubs.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/stubs.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/sys_linux_arm.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/sys_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/sys_linux_arm.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/sys_linux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/sys_nonlinux_arm.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/sys_nonlinux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/sys_nonlinux_arm.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/sys_nonlinux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/types.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/types.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/types.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/types.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/types_64bit.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/types_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/types_64bit.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/types_64bit.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/unaligned.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/unaligned.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/unaligned.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/unaligned.go diff --git a/contrib/go/_std_1.23/src/internal/runtime/atomic/ya.make b/contrib/go/_std_1.23/src/internal/runtime/atomic/ya.make new file mode 100644 index 000000000000..77fdf48ca7f2 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/ya.make @@ -0,0 +1,34 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + atomic_arm64.go + atomic_arm64.s + doc.go + stubs.go + types.go + types_64bit.go + unaligned.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + atomic_amd64.go + atomic_amd64.s + doc.go + stubs.go + types.go + types_64bit.go + unaligned.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + atomic_andor_generic.go + atomic_arm.go + atomic_arm.s + doc.go + stubs.go + sys_linux_arm.s + types.go + unaligned.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/runtime/exithook/hooks.go b/contrib/go/_std_1.23/src/internal/runtime/exithook/hooks.go new file mode 100644 index 000000000000..eb8aa1ce0a5c --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/exithook/hooks.go @@ -0,0 +1,85 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package exithook provides limited support for on-exit cleanup. +// +// CAREFUL! The expectation is that Add should only be called +// from a safe context (e.g. not an error/panic path or signal +// handler, preemption enabled, allocation allowed, write barriers +// allowed, etc), and that the exit function F will be invoked under +// similar circumstances. That is the say, we are expecting that F +// uses normal / high-level Go code as opposed to one of the more +// restricted dialects used for the trickier parts of the runtime. +package exithook + +import ( + "internal/runtime/atomic" + _ "unsafe" // for linkname +) + +// A Hook is a function to be run at program termination +// (when someone invokes os.Exit, or when main.main returns). +// Hooks are run in reverse order of registration: +// the first hook added is the last one run. +type Hook struct { + F func() // func to run + RunOnFailure bool // whether to run on non-zero exit code +} + +var ( + locked atomic.Int32 + runGoid atomic.Uint64 + hooks []Hook + running bool + + // runtime sets these for us + Gosched func() + Goid func() uint64 + Throw func(string) +) + +// Add adds a new exit hook. +func Add(h Hook) { + for !locked.CompareAndSwap(0, 1) { + Gosched() + } + hooks = append(hooks, h) + locked.Store(0) +} + +// Run runs the exit hooks. +// +// If an exit hook panics, Run will throw with the panic on the stack. +// If an exit hook invokes exit in the same goroutine, the goroutine will throw. +// If an exit hook invokes exit in another goroutine, that exit will block. +func Run(code int) { + for !locked.CompareAndSwap(0, 1) { + if Goid() == runGoid.Load() { + Throw("exit hook invoked exit") + } + Gosched() + } + defer locked.Store(0) + runGoid.Store(Goid()) + defer runGoid.Store(0) + + defer func() { + if e := recover(); e != nil { + Throw("exit hook invoked panic") + } + }() + + for len(hooks) > 0 { + h := hooks[len(hooks)-1] + hooks = hooks[:len(hooks)-1] + if code != 0 && !h.RunOnFailure { + continue + } + h.F() + } +} + +type exitError string + +func (e exitError) Error() string { return string(e) } diff --git a/contrib/go/_std_1.23/src/internal/runtime/exithook/ya.make b/contrib/go/_std_1.23/src/internal/runtime/exithook/ya.make new file mode 100644 index 000000000000..352818b36253 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/exithook/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + hooks.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_386.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_386.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_386.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_amd64.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_amd64.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_arm.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_arm.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_arm64.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_arm64.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_arm64.s diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_loong64.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_loong64.s new file mode 100644 index 000000000000..ff8ad75b055d --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_loong64.s @@ -0,0 +1,42 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +// func Syscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr) +// +// We need to convert to the syscall ABI. +// +// arg | ABIInternal | Syscall +// --------------------------- +// num | R4 | R11 +// a1 | R5 | R4 +// a2 | R6 | R5 +// a3 | R7 | R6 +// a4 | R8 | R7 +// a5 | R9 | R8 +// a6 | R10 | R9 +// +// r1 | R4 | R4 +// r2 | R5 | R5 +// err | R6 | part of R4 +TEXT ·Syscall6(SB),NOSPLIT,$0-80 + MOVV R4, R11 // syscall entry + MOVV R5, R4 + MOVV R6, R5 + MOVV R7, R6 + MOVV R8, R7 + MOVV R9, R8 + MOVV R10, R9 + SYSCALL + MOVV R0, R5 // r2 is not used. Always set to 0. + MOVW $-4096, R12 + BGEU R12, R4, ok + SUBVU R4, R0, R6 // errno + MOVV $-1, R4 // r1 + RET +ok: + // r1 already in R4 + MOVV R0, R6 // errno + RET diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_mips64x.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_mips64x.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_mipsx.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_mipsx.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_ppc64x.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_ppc64x.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_riscv64.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_riscv64.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_s390x.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_s390x.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_s390x.s diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux.go new file mode 100644 index 000000000000..b2e36a244f82 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux.go @@ -0,0 +1,19 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + EPOLLIN = 0x1 + EPOLLOUT = 0x4 + EPOLLERR = 0x8 + EPOLLHUP = 0x10 + EPOLLRDHUP = 0x2000 + EPOLLET = 0x80000000 + EPOLL_CLOEXEC = 0x80000 + EPOLL_CTL_ADD = 0x1 + EPOLL_CTL_DEL = 0x2 + EPOLL_CTL_MOD = 0x3 + EFD_CLOEXEC = 0x80000 +) diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_386.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_386.go new file mode 100644 index 000000000000..68e687fb14b7 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_386.go @@ -0,0 +1,22 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + SYS_FCNTL = 55 + SYS_MPROTECT = 125 + SYS_EPOLL_CTL = 255 + SYS_EPOLL_PWAIT = 319 + SYS_EPOLL_CREATE1 = 329 + SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 328 + + EFD_NONBLOCK = 0x800 +) + +type EpollEvent struct { + Events uint32 + Data [8]byte // to match amd64 +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_amd64.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_amd64.go new file mode 100644 index 000000000000..ec480f5817e0 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_amd64.go @@ -0,0 +1,22 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + SYS_MPROTECT = 10 + SYS_FCNTL = 72 + SYS_EPOLL_CTL = 233 + SYS_EPOLL_PWAIT = 281 + SYS_EPOLL_CREATE1 = 291 + SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 290 + + EFD_NONBLOCK = 0x800 +) + +type EpollEvent struct { + Events uint32 + Data [8]byte // unaligned uintptr +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm.go new file mode 100644 index 000000000000..c5d150301230 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm.go @@ -0,0 +1,23 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + SYS_FCNTL = 55 + SYS_MPROTECT = 125 + SYS_EPOLL_CTL = 251 + SYS_EPOLL_PWAIT = 346 + SYS_EPOLL_CREATE1 = 357 + SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 356 + + EFD_NONBLOCK = 0x800 +) + +type EpollEvent struct { + Events uint32 + _pad uint32 + Data [8]byte // to match amd64 +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm64.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm64.go new file mode 100644 index 000000000000..f743fe31a58d --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm64.go @@ -0,0 +1,23 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + SYS_EPOLL_CREATE1 = 20 + SYS_EPOLL_CTL = 21 + SYS_EPOLL_PWAIT = 22 + SYS_FCNTL = 25 + SYS_MPROTECT = 226 + SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 19 + + EFD_NONBLOCK = 0x800 +) + +type EpollEvent struct { + Events uint32 + _pad uint32 + Data [8]byte // to match amd64 +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_loong64.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_loong64.go new file mode 100644 index 000000000000..82218d15099a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_loong64.go @@ -0,0 +1,23 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + SYS_EPOLL_CREATE1 = 20 + SYS_EPOLL_CTL = 21 + SYS_EPOLL_PWAIT = 22 + SYS_FCNTL = 25 + SYS_MPROTECT = 226 + SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 19 + + EFD_NONBLOCK = 0x800 +) + +type EpollEvent struct { + Events uint32 + pad_cgo_0 [4]byte + Data [8]byte // unaligned uintptr +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mips64x.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mips64x.go new file mode 100644 index 000000000000..4e0fd1f5d1b1 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mips64x.go @@ -0,0 +1,25 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && (mips64 || mips64le) + +package syscall + +const ( + SYS_MPROTECT = 5010 + SYS_FCNTL = 5070 + SYS_EPOLL_CTL = 5208 + SYS_EPOLL_PWAIT = 5272 + SYS_EPOLL_CREATE1 = 5285 + SYS_EPOLL_PWAIT2 = 5441 + SYS_EVENTFD2 = 5284 + + EFD_NONBLOCK = 0x80 +) + +type EpollEvent struct { + Events uint32 + pad_cgo_0 [4]byte + Data [8]byte // unaligned uintptr +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mipsx.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mipsx.go new file mode 100644 index 000000000000..b87a355093e4 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mipsx.go @@ -0,0 +1,25 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && (mips || mipsle) + +package syscall + +const ( + SYS_FCNTL = 4055 + SYS_MPROTECT = 4125 + SYS_EPOLL_CTL = 4249 + SYS_EPOLL_PWAIT = 4313 + SYS_EPOLL_CREATE1 = 4326 + SYS_EPOLL_PWAIT2 = 4441 + SYS_EVENTFD2 = 4325 + + EFD_NONBLOCK = 0x80 +) + +type EpollEvent struct { + Events uint32 + pad_cgo_0 [4]byte + Data uint64 +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_ppc64x.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_ppc64x.go new file mode 100644 index 000000000000..8235edd795fa --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_ppc64x.go @@ -0,0 +1,25 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && (ppc64 || ppc64le) + +package syscall + +const ( + SYS_FCNTL = 55 + SYS_MPROTECT = 125 + SYS_EPOLL_CTL = 237 + SYS_EPOLL_PWAIT = 303 + SYS_EPOLL_CREATE1 = 315 + SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 314 + + EFD_NONBLOCK = 0x800 +) + +type EpollEvent struct { + Events uint32 + pad_cgo_0 [4]byte + Data [8]byte // unaligned uintptr +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_riscv64.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_riscv64.go new file mode 100644 index 000000000000..82218d15099a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_riscv64.go @@ -0,0 +1,23 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + SYS_EPOLL_CREATE1 = 20 + SYS_EPOLL_CTL = 21 + SYS_EPOLL_PWAIT = 22 + SYS_FCNTL = 25 + SYS_MPROTECT = 226 + SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 19 + + EFD_NONBLOCK = 0x800 +) + +type EpollEvent struct { + Events uint32 + pad_cgo_0 [4]byte + Data [8]byte // unaligned uintptr +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_s390x.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_s390x.go new file mode 100644 index 000000000000..08073c01f091 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_s390x.go @@ -0,0 +1,23 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + SYS_FCNTL = 55 + SYS_MPROTECT = 125 + SYS_EPOLL_CTL = 250 + SYS_EPOLL_PWAIT = 312 + SYS_EPOLL_CREATE1 = 327 + SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 323 + + EFD_NONBLOCK = 0x800 +) + +type EpollEvent struct { + Events uint32 + pad_cgo_0 [4]byte + Data [8]byte // unaligned uintptr +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/syscall_linux.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/syscall_linux.go new file mode 100644 index 000000000000..83df825169b9 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/syscall_linux.go @@ -0,0 +1,44 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package syscall provides the syscall primitives required for the runtime. +package syscall + +import ( + "unsafe" +) + +// TODO(https://go.dev/issue/51087): This package is incomplete and currently +// only contains very minimal support for Linux. + +// Syscall6 calls system call number 'num' with arguments a1-6. +func Syscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr) + +func EpollCreate1(flags int32) (fd int32, errno uintptr) { + r1, _, e := Syscall6(SYS_EPOLL_CREATE1, uintptr(flags), 0, 0, 0, 0, 0) + return int32(r1), e +} + +var _zero uintptr + +func EpollWait(epfd int32, events []EpollEvent, maxev, waitms int32) (n int32, errno uintptr) { + var ev unsafe.Pointer + if len(events) > 0 { + ev = unsafe.Pointer(&events[0]) + } else { + ev = unsafe.Pointer(&_zero) + } + r1, _, e := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(ev), uintptr(maxev), uintptr(waitms), 0, 0) + return int32(r1), e +} + +func EpollCtl(epfd, op, fd int32, event *EpollEvent) (errno uintptr) { + _, _, e := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0) + return e +} + +func Eventfd(initval, flags int32) (fd int32, errno uintptr) { + r1, _, e := Syscall6(SYS_EVENTFD2, uintptr(initval), uintptr(flags), 0, 0, 0, 0) + return int32(r1), e +} diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/ya.make b/contrib/go/_std_1.23/src/internal/runtime/syscall/ya.make new file mode 100644 index 000000000000..942d3e68ad82 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/ya.make @@ -0,0 +1,24 @@ +GO_LIBRARY() +IF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + asm_linux_arm64.s + defs_linux.go + defs_linux_arm64.go + syscall_linux.go + ) +ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + asm_linux_amd64.s + defs_linux.go + defs_linux_amd64.go + syscall_linux.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + asm_linux_arm.s + defs_linux.go + defs_linux_arm.go + syscall_linux.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/singleflight/singleflight.go b/contrib/go/_std_1.23/src/internal/singleflight/singleflight.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/singleflight/singleflight.go rename to contrib/go/_std_1.23/src/internal/singleflight/singleflight.go diff --git a/contrib/go/_std_1.22/src/internal/singleflight/ya.make b/contrib/go/_std_1.23/src/internal/singleflight/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/singleflight/ya.make rename to contrib/go/_std_1.23/src/internal/singleflight/ya.make diff --git a/contrib/go/_std_1.23/src/internal/stringslite/strings.go b/contrib/go/_std_1.23/src/internal/stringslite/strings.go new file mode 100644 index 000000000000..4114b8613000 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/stringslite/strings.go @@ -0,0 +1,150 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package stringslite implements a subset of strings, +// only using packages that may be imported by "os". +// +// Tests for these functions are in the strings package. +package stringslite + +import ( + "internal/bytealg" + "unsafe" +) + +func HasPrefix(s, prefix string) bool { + return len(s) >= len(prefix) && s[0:len(prefix)] == prefix +} + +func HasSuffix(s, suffix string) bool { + return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix +} + +func IndexByte(s string, c byte) int { + return bytealg.IndexByteString(s, c) +} + +func Index(s, substr string) int { + n := len(substr) + switch { + case n == 0: + return 0 + case n == 1: + return IndexByte(s, substr[0]) + case n == len(s): + if substr == s { + return 0 + } + return -1 + case n > len(s): + return -1 + case n <= bytealg.MaxLen: + // Use brute force when s and substr both are small + if len(s) <= bytealg.MaxBruteForce { + return bytealg.IndexString(s, substr) + } + c0 := substr[0] + c1 := substr[1] + i := 0 + t := len(s) - n + 1 + fails := 0 + for i < t { + if s[i] != c0 { + // IndexByte is faster than bytealg.IndexString, so use it as long as + // we're not getting lots of false positives. + o := IndexByte(s[i+1:t], c0) + if o < 0 { + return -1 + } + i += o + 1 + } + if s[i+1] == c1 && s[i:i+n] == substr { + return i + } + fails++ + i++ + // Switch to bytealg.IndexString when IndexByte produces too many false positives. + if fails > bytealg.Cutover(i) { + r := bytealg.IndexString(s[i:], substr) + if r >= 0 { + return r + i + } + return -1 + } + } + return -1 + } + c0 := substr[0] + c1 := substr[1] + i := 0 + t := len(s) - n + 1 + fails := 0 + for i < t { + if s[i] != c0 { + o := IndexByte(s[i+1:t], c0) + if o < 0 { + return -1 + } + i += o + 1 + } + if s[i+1] == c1 && s[i:i+n] == substr { + return i + } + i++ + fails++ + if fails >= 4+i>>4 && i < t { + // See comment in ../bytes/bytes.go. + j := bytealg.IndexRabinKarp(s[i:], substr) + if j < 0 { + return -1 + } + return i + j + } + } + return -1 +} + +func Cut(s, sep string) (before, after string, found bool) { + if i := Index(s, sep); i >= 0 { + return s[:i], s[i+len(sep):], true + } + return s, "", false +} + +func CutPrefix(s, prefix string) (after string, found bool) { + if !HasPrefix(s, prefix) { + return s, false + } + return s[len(prefix):], true +} + +func CutSuffix(s, suffix string) (before string, found bool) { + if !HasSuffix(s, suffix) { + return s, false + } + return s[:len(s)-len(suffix)], true +} + +func TrimPrefix(s, prefix string) string { + if HasPrefix(s, prefix) { + return s[len(prefix):] + } + return s +} + +func TrimSuffix(s, suffix string) string { + if HasSuffix(s, suffix) { + return s[:len(s)-len(suffix)] + } + return s +} + +func Clone(s string) string { + if len(s) == 0 { + return "" + } + b := make([]byte, len(s)) + copy(b, s) + return unsafe.String(&b[0], len(b)) +} diff --git a/contrib/go/_std_1.23/src/internal/stringslite/ya.make b/contrib/go/_std_1.23/src/internal/stringslite/ya.make new file mode 100644 index 000000000000..f101487a00e4 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/stringslite/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + strings.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/syscall/execenv/execenv_default.go b/contrib/go/_std_1.23/src/internal/syscall/execenv/execenv_default.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/execenv/execenv_default.go rename to contrib/go/_std_1.23/src/internal/syscall/execenv/execenv_default.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/execenv/execenv_windows.go b/contrib/go/_std_1.23/src/internal/syscall/execenv/execenv_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/execenv/execenv_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/execenv/execenv_windows.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/execenv/ya.make b/contrib/go/_std_1.23/src/internal/syscall/execenv/ya.make new file mode 100644 index 000000000000..ec3337b1c9f6 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/execenv/ya.make @@ -0,0 +1,11 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + execenv_default.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + execenv_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/arc4random_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/arc4random_darwin.go new file mode 100644 index 000000000000..a78204a3559a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/arc4random_darwin.go @@ -0,0 +1,24 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "internal/abi" + "unsafe" +) + +//go:cgo_import_dynamic libc_arc4random_buf arc4random_buf "/usr/lib/libSystem.B.dylib" + +func libc_arc4random_buf_trampoline() + +// ARC4Random calls the macOS arc4random_buf(3) function. +func ARC4Random(p []byte) { + // macOS 11 and 12 abort if length is 0. + if len(p) == 0 { + return + } + syscall_syscall(abi.FuncPCABI0(libc_arc4random_buf_trampoline), + uintptr(unsafe.Pointer(unsafe.SliceData(p))), uintptr(len(p)), 0) +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_aix_ppc64.s b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_aix_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/asm_aix_ppc64.s rename to contrib/go/_std_1.23/src/internal/syscall/unix/asm_aix_ppc64.s diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_darwin.s b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_darwin.s similarity index 90% rename from contrib/go/_std_1.22/src/internal/syscall/unix/asm_darwin.s rename to contrib/go/_std_1.23/src/internal/syscall/unix/asm_darwin.s index 10d16ce87f09..99f28765fe0c 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_darwin.s +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_darwin.s @@ -4,6 +4,7 @@ #include "textflag.h" +TEXT ·libc_arc4random_buf_trampoline(SB),NOSPLIT,$0-0; JMP libc_arc4random_buf(SB) TEXT ·libc_getaddrinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_getaddrinfo(SB) TEXT ·libc_freeaddrinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_freeaddrinfo(SB) TEXT ·libc_getnameinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_getnameinfo(SB) @@ -21,3 +22,4 @@ TEXT ·libc_getpwuid_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getpwuid_r(SB) TEXT ·libc_getgrnam_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getgrnam_r(SB) TEXT ·libc_getgrgid_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getgrgid_r(SB) TEXT ·libc_sysconf_trampoline(SB),NOSPLIT,$0-0; JMP libc_sysconf(SB) +TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0; JMP libc_faccessat(SB) diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/asm_openbsd.s b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_openbsd.s new file mode 100644 index 000000000000..cc54a14ca5e3 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_openbsd.s @@ -0,0 +1,10 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build openbsd && !mips64 + +#include "textflag.h" + +TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_faccessat(SB) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_solaris.s b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_solaris.s similarity index 82% rename from contrib/go/_std_1.22/src/internal/syscall/unix/asm_solaris.s rename to contrib/go/_std_1.23/src/internal/syscall/unix/asm_solaris.s index 205733831586..361ca7fc2a8c 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_solaris.s +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_solaris.s @@ -8,3 +8,6 @@ TEXT ·syscall6(SB),NOSPLIT,$0-88 JMP syscall·sysvicall6(SB) + +TEXT ·rawSyscall6(SB),NOSPLIT,$0-88 + JMP syscall·rawSysvicall6(SB) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_aix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_aix.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_aix.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_fstatat.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_fstatat.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_fstatat.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_fstatat.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_fstatat2.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_fstatat2.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_fstatat2.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_fstatat2.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_js.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_js.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_js.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_libc.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_libc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_libc.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_libc.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_libc2.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_libc2.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_libc2.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_libc2.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/at_solaris.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_solaris.go new file mode 100644 index 000000000000..ae1c1d64ca7b --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/at_solaris.go @@ -0,0 +1,25 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import "syscall" + +// Implemented as sysvicall6 in runtime/syscall_solaris.go. +func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) + +// Implemented as rawsysvicall6 in runtime/syscall_solaris.go. +func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) + +//go:cgo_import_dynamic libc_fstatat fstatat "libc.so" +//go:cgo_import_dynamic libc_openat openat "libc.so" +//go:cgo_import_dynamic libc_unlinkat unlinkat "libc.so" +//go:cgo_import_dynamic libc_uname uname "libc.so" + +const ( + AT_REMOVEDIR = 0x1 + AT_SYMLINK_NOFOLLOW = 0x1000 + + UTIME_OMIT = -0x2 +) diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_darwin.go new file mode 100644 index 000000000000..77b0af80b5de --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_darwin.go @@ -0,0 +1,14 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +const ( + AT_EACCESS = 0x10 + AT_FDCWD = -0x2 + AT_REMOVEDIR = 0x80 + AT_SYMLINK_NOFOLLOW = 0x0020 + + UTIME_OMIT = -0x2 +) diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_dragonfly.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_dragonfly.go new file mode 100644 index 000000000000..a8164dcc8ec7 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_dragonfly.go @@ -0,0 +1,20 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import "syscall" + +const ( + unlinkatTrap uintptr = syscall.SYS_UNLINKAT + openatTrap uintptr = syscall.SYS_OPENAT + fstatatTrap uintptr = syscall.SYS_FSTATAT + + AT_EACCESS = 0x4 + AT_FDCWD = 0xfffafdcd + AT_REMOVEDIR = 0x2 + AT_SYMLINK_NOFOLLOW = 0x1 + + UTIME_OMIT = -0x2 +) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_freebsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_freebsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_freebsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_fstatat_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_fstatat_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_fstatat_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_fstatat_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_netbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_netbsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_netbsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_openbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_openbsd.go new file mode 100644 index 000000000000..3b0c0dbd19cc --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_openbsd.go @@ -0,0 +1,20 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import "syscall" + +const unlinkatTrap uintptr = syscall.SYS_UNLINKAT +const openatTrap uintptr = syscall.SYS_OPENAT +const fstatatTrap uintptr = syscall.SYS_FSTATAT + +const ( + AT_EACCESS = 0x1 + AT_FDCWD = -0x64 + AT_REMOVEDIR = 0x08 + AT_SYMLINK_NOFOLLOW = 0x02 + + UTIME_OMIT = -0x1 +) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_wasip1.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_wasip1.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_wasip1.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/constants.go b/contrib/go/_std_1.23/src/internal/syscall/unix/constants.go new file mode 100644 index 000000000000..28092c2ddfde --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/constants.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package unix + +const ( + R_OK = 0x4 + W_OK = 0x2 + X_OK = 0x1 + + // NoFollowErrno is the error returned from open/openat called with + // O_NOFOLLOW flag, when the trailing component (basename) of the path + // is a symbolic link. + NoFollowErrno = noFollowErrno +) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/copy_file_range_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/copy_file_range_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/copy_file_range_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/copy_file_range_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_bsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_bsd.go similarity index 90% rename from contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_bsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_bsd.go index 3411e3ac40c3..7077af17b672 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_bsd.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build dragonfly || freebsd || netbsd +//go:build dragonfly || freebsd || netbsd || (openbsd && mips64) package unix diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_darwin.go new file mode 100644 index 000000000000..0fa8d17afeae --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_darwin.go @@ -0,0 +1,31 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "internal/abi" + "syscall" + "unsafe" +) + +func libc_faccessat_trampoline() + +//go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" + +func faccessat(dirfd int, path string, mode uint32, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(p)), uintptr(mode), uintptr(flags), 0, 0) + if errno != 0 { + return errno + } + return nil +} + +func Eaccess(path string, mode uint32) error { + return faccessat(AT_FDCWD, path, mode, AT_EACCESS) +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_linux.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_openbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_openbsd.go new file mode 100644 index 000000000000..5e91f11f6654 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_openbsd.go @@ -0,0 +1,36 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build openbsd && !mips64 + +package unix + +import ( + "internal/abi" + "syscall" + "unsafe" +) + +//go:linkname syscall_syscall6 syscall.syscall6 +func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) + +func libc_faccessat_trampoline() + +//go:cgo_import_dynamic libc_faccessat faccessat "libc.so" + +func faccessat(dirfd int, path string, mode uint32, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(p)), uintptr(mode), uintptr(flags), 0, 0) + if errno != 0 { + return errno + } + return err +} + +func Eaccess(path string, mode uint32) error { + return faccessat(AT_FDCWD, path, mode, AT_EACCESS) +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_other.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_other.go similarity index 75% rename from contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_other.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_other.go index 19a2be587e48..3da3a64f0e6a 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_other.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_other.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build unix && !dragonfly && !freebsd && !linux && !netbsd +//go:build unix && !darwin && !dragonfly && !freebsd && !linux && !openbsd && !netbsd package unix diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_386.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_386.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_64bit.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_64bit.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_64bit.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_arm.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_arm.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_js.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_js.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_js.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_unix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_unix.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_unix.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_wasip1.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_wasip1.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_wasip1.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_netbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_netbsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_netbsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_openbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_openbsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_openbsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_openbsd_mips64.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_openbsd_mips64.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_dragonfly.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_dragonfly.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_dragonfly.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_freebsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_freebsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_freebsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_solaris.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_solaris.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_solaris.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/ioctl_aix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/ioctl_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/ioctl_aix.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/ioctl_aix.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_other.go b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_other.go similarity index 88% rename from contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_other.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_other.go index 00af9f2ba018..fc65c1c823c7 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_other.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_other.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !linux +//go:build !linux && !solaris package unix diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_solaris.go b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_solaris.go new file mode 100644 index 000000000000..3f399411d76b --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_solaris.go @@ -0,0 +1,106 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "runtime" + "sync" + "syscall" + "unsafe" +) + +//go:linkname procUname libc_uname + +var procUname uintptr + +// utsname represents the fields of a struct utsname defined in . +type utsname struct { + Sysname [257]byte + Nodename [257]byte + Release [257]byte + Version [257]byte + Machine [257]byte +} + +// KernelVersion returns major and minor kernel version numbers +// parsed from the syscall.Uname's Version field, or (0, 0) if the +// version can't be obtained or parsed. +func KernelVersion() (major int, minor int) { + var un utsname + _, _, errno := rawSyscall6(uintptr(unsafe.Pointer(&procUname)), 1, uintptr(unsafe.Pointer(&un)), 0, 0, 0, 0, 0) + if errno != 0 { + return 0, 0 + } + + // The version string is in the form "...." + // on Solaris: https://blogs.oracle.com/solaris/post/whats-in-a-uname- + // Therefore, we use the Version field on Solaris when available. + ver := un.Version[:] + if runtime.GOOS == "illumos" { + // Illumos distributions use different formats without a parsable + // and unified pattern for the Version field while Release level + // string is guaranteed to be in x.y or x.y.z format regardless of + // whether the kernel is Solaris or illumos. + ver = un.Release[:] + } + + parseNext := func() (n int) { + for i, c := range ver { + if c == '.' { + ver = ver[i+1:] + return + } + if '0' <= c && c <= '9' { + n = n*10 + int(c-'0') + } + } + ver = nil + return + } + + major = parseNext() + minor = parseNext() + + return +} + +// SupportSockNonblockCloexec tests if SOCK_NONBLOCK and SOCK_CLOEXEC are supported +// for socket() system call, returns true if affirmative. +var SupportSockNonblockCloexec = sync.OnceValue(func() bool { + // First test if socket() supports SOCK_NONBLOCK and SOCK_CLOEXEC directly. + s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, 0) + if err == nil { + syscall.Close(s) + return true + } + if err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL { + // Something wrong with socket(), fall back to checking the kernel version. + major, minor := KernelVersion() + if runtime.GOOS == "illumos" { + return major > 5 || (major == 5 && minor >= 11) // minimal requirement is SunOS 5.11 + } + return major > 11 || (major == 11 && minor >= 4) + } + return false +}) + +// SupportAccept4 tests whether accept4 system call is available. +var SupportAccept4 = sync.OnceValue(func() bool { + for { + // Test if the accept4() is available. + _, _, err := syscall.Accept4(0, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) + if err == syscall.EINTR { + continue + } + return err != syscall.ENOSYS + } +}) + +// SupportTCPKeepAliveIdleIntvlCNT determines whether the TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT +// are available by checking the kernel version for Solaris 11.4. +var SupportTCPKeepAliveIdleIntvlCNT = sync.OnceValue(func() bool { + major, minor := KernelVersion() + return major > 11 || (major == 11 && minor >= 4) +}) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/net.go b/contrib/go/_std_1.23/src/internal/syscall/unix/net.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/net.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/net.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/net_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/net_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/net_darwin.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/net_darwin.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/net_js.go b/contrib/go/_std_1.23/src/internal/syscall/unix/net_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/net_js.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/net_js.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/net_wasip1.go b/contrib/go/_std_1.23/src/internal/syscall/unix/net_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/net_wasip1.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/net_wasip1.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_bsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_bsd.go new file mode 100644 index 000000000000..32c4de119012 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_bsd.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build dragonfly || freebsd + +package unix + +import "syscall" + +// References: +// - https://man.freebsd.org/cgi/man.cgi?open(2) +// - https://man.dragonflybsd.org/?command=open§ion=2 +const noFollowErrno = syscall.EMLINK diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_netbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_netbsd.go new file mode 100644 index 000000000000..3ae91e79cddc --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_netbsd.go @@ -0,0 +1,10 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import "syscall" + +// Reference: https://man.netbsd.org/open.2 +const noFollowErrno = syscall.EFTYPE diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_posix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_posix.go new file mode 100644 index 000000000000..de2ea14fc80b --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_posix.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix && !dragonfly && !freebsd && !netbsd + +package unix + +import "syscall" + +// POSIX.1-2008 says it's ELOOP. Most platforms follow: +// +// - aix: O_NOFOLLOW not documented (https://www.ibm.com/docs/ssw_aix_73/o_bostechref/open.html), assuming ELOOP +// - android: see linux +// - darwin: https://github.com/apple/darwin-xnu/blob/main/bsd/man/man2/open.2 +// - hurd: who knows if it works at all (https://www.gnu.org/software/hurd/open_issues/open_symlink.html) +// - illumos: https://illumos.org/man/2/open +// - ios: see darwin +// - linux: https://man7.org/linux/man-pages/man2/openat.2.html +// - openbsd: https://man.openbsd.org/open.2 +// - solaris: https://docs.oracle.com/cd/E23824_01/html/821-1463/open-2.html +const noFollowErrno = syscall.ELOOP diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_js.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_js.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_js.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_unix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_unix.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_unix.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_wasip1.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_wasip1.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_wasip1.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/pidfd_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/pidfd_linux.go new file mode 100644 index 000000000000..e9417623db79 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/pidfd_linux.go @@ -0,0 +1,23 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import "syscall" + +func PidFDSendSignal(pidfd uintptr, s syscall.Signal) error { + _, _, errno := syscall.Syscall(pidfdSendSignalTrap, pidfd, uintptr(s), 0) + if errno != 0 { + return errno + } + return nil +} + +func PidFDOpen(pid, flags int) (uintptr, error) { + pidfd, _, errno := syscall.Syscall(pidfdOpenTrap, uintptr(pid), uintptr(flags), 0) + if errno != 0 { + return ^uintptr(0), errno + } + return uintptr(pidfd), nil +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/pty_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/pty_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/pty_darwin.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/pty_darwin.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux.go new file mode 100644 index 000000000000..9f83114e45cf --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux.go @@ -0,0 +1,64 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "syscall" +) + +const is64bit = ^uint(0) >> 63 // 0 for 32-bit hosts, 1 for 64-bit ones. + +// SiginfoChild is a struct filled in by Linux waitid syscall. +// In C, siginfo_t contains a union with multiple members; +// this struct corresponds to one used when Signo is SIGCHLD. +// +// NOTE fields are exported to be used by TestSiginfoChildLayout. +type SiginfoChild struct { + Signo int32 + siErrnoCode // Two int32 fields, swapped on MIPS. + _ [is64bit]int32 // Extra padding for 64-bit hosts only. + + // End of common part. Beginning of signal-specific part. + + Pid int32 + Uid uint32 + Status int32 + + // Pad to 128 bytes. + _ [128 - (6+is64bit)*4]byte +} + +const ( + // Possible values for SiginfoChild.Code field. + _CLD_EXITED int32 = 1 + _CLD_KILLED = 2 + _CLD_DUMPED = 3 + _CLD_TRAPPED = 4 + _CLD_STOPPED = 5 + _CLD_CONTINUED = 6 + + // These are the same as in syscall/syscall_linux.go. + core = 0x80 + stopped = 0x7f + continued = 0xffff +) + +// WaitStatus converts SiginfoChild, as filled in by the waitid syscall, +// to syscall.WaitStatus. +func (s *SiginfoChild) WaitStatus() (ws syscall.WaitStatus) { + switch s.Code { + case _CLD_EXITED: + ws = syscall.WaitStatus(s.Status << 8) + case _CLD_DUMPED: + ws = syscall.WaitStatus(s.Status) | core + case _CLD_KILLED: + ws = syscall.WaitStatus(s.Status) + case _CLD_TRAPPED, _CLD_STOPPED: + ws = syscall.WaitStatus(s.Status<<8) | stopped + case _CLD_CONTINUED: + ws = continued + } + return +} diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_mipsx.go b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_mipsx.go new file mode 100644 index 000000000000..2fca0c55055e --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_mipsx.go @@ -0,0 +1,12 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && (mips || mipsle || mips64 || mips64le) + +package unix + +type siErrnoCode struct { + Code int32 + Errno int32 +} diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_other.go b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_other.go new file mode 100644 index 000000000000..cfdc4ddf51ce --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_other.go @@ -0,0 +1,12 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && !(mips || mipsle || mips64 || mips64le) + +package unix + +type siErrnoCode struct { + Errno int32 + Code int32 +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_386.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_386.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_386.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_386.go index 9f750a1c03e2..be048bcf734b 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_386.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_386.go @@ -8,4 +8,5 @@ const ( getrandomTrap uintptr = 355 copyFileRangeTrap uintptr = 377 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_amd64.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_amd64.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_amd64.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_amd64.go index 706898d41e5a..525de9cbd8c1 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_amd64.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_amd64.go @@ -8,4 +8,5 @@ const ( getrandomTrap uintptr = 318 copyFileRangeTrap uintptr = 326 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_arm.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_arm.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_arm.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_arm.go index c00644b5528a..b80389227868 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_arm.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_arm.go @@ -8,4 +8,5 @@ const ( getrandomTrap uintptr = 384 copyFileRangeTrap uintptr = 391 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_generic.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_generic.go similarity index 94% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_generic.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_generic.go index bf25428e7ec5..b06bf6927312 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_generic.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_generic.go @@ -14,4 +14,5 @@ const ( getrandomTrap uintptr = 278 copyFileRangeTrap uintptr = 285 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mips64x.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mips64x.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mips64x.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mips64x.go index 6a9e238ce3d3..8764f5dc8fcf 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mips64x.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mips64x.go @@ -10,4 +10,5 @@ const ( getrandomTrap uintptr = 5313 copyFileRangeTrap uintptr = 5320 pidfdSendSignalTrap uintptr = 5424 + pidfdOpenTrap uintptr = 5434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mipsx.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mipsx.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mipsx.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mipsx.go index 22d38f148edd..9b2e587ba55f 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mipsx.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mipsx.go @@ -10,4 +10,5 @@ const ( getrandomTrap uintptr = 4353 copyFileRangeTrap uintptr = 4360 pidfdSendSignalTrap uintptr = 4424 + pidfdOpenTrap uintptr = 4434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_ppc64x.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_ppc64x.go similarity index 90% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_ppc64x.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_ppc64x.go index 945ec28c2a04..03e9c197433e 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_ppc64x.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_ppc64x.go @@ -10,4 +10,5 @@ const ( getrandomTrap uintptr = 359 copyFileRangeTrap uintptr = 379 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_s390x.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_s390x.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_s390x.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_s390x.go index 2c7434382018..c6e3e02e46e3 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_s390x.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_s390x.go @@ -8,4 +8,5 @@ const ( getrandomTrap uintptr = 349 copyFileRangeTrap uintptr = 375 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_bsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_bsd.go new file mode 100644 index 000000000000..bac614df97c0 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_bsd.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd || netbsd || openbsd + +package unix + +import ( + "syscall" + "unsafe" +) + +//go:linkname ioctlPtr syscall.ioctlPtr +func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) + +// Note that pgid should really be pid_t, however _C_int (aka int32) is +// generally equivalent. + +func Tcsetpgrp(fd int, pgid int32) (err error) { + return ioctlPtr(fd, syscall.TIOCSPGRP, unsafe.Pointer(&pgid)) +} diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_linux.go new file mode 100644 index 000000000000..be208d9cd2ed --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_linux.go @@ -0,0 +1,21 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "syscall" + "unsafe" +) + +// Note that pgid should really be pid_t, however _C_int (aka int32) is +// generally equivalent. + +func Tcsetpgrp(fd int, pgid int32) (err error) { + _, _, errno := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCSPGRP), uintptr(unsafe.Pointer(&pgid)), 0, 0, 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/user_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/user_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/user_darwin.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/user_darwin.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/ya.make b/contrib/go/_std_1.23/src/internal/syscall/unix/ya.make new file mode 100644 index 000000000000..87107eccc428 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/ya.make @@ -0,0 +1,91 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + arc4random_darwin.go + asm_darwin.s + at_libc2.go + at_sysnum_darwin.go + constants.go + eaccess_darwin.go + fcntl_unix.go + kernel_version_other.go + net.go + net_darwin.go + nofollow_posix.go + nonblocking_unix.go + pty_darwin.go + tcsetpgrp_bsd.go + user_darwin.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + at.go + at_fstatat.go + at_sysnum_fstatat_linux.go + at_sysnum_linux.go + constants.go + copy_file_range_linux.go + eaccess_linux.go + fcntl_unix.go + getrandom.go + getrandom_linux.go + kernel_version_linux.go + net.go + nofollow_posix.go + nonblocking_unix.go + pidfd_linux.go + siginfo_linux.go + siginfo_linux_other.go + sysnum_linux_generic.go + tcsetpgrp_linux.go + ) +ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + at.go + at_fstatat.go + at_sysnum_linux.go + at_sysnum_newfstatat_linux.go + constants.go + copy_file_range_linux.go + eaccess_linux.go + fcntl_unix.go + getrandom.go + getrandom_linux.go + kernel_version_linux.go + net.go + nofollow_posix.go + nonblocking_unix.go + pidfd_linux.go + siginfo_linux.go + siginfo_linux_other.go + sysnum_linux_amd64.go + tcsetpgrp_linux.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + at.go + at_fstatat.go + at_sysnum_fstatat64_linux.go + at_sysnum_linux.go + constants.go + copy_file_range_linux.go + eaccess_linux.go + fcntl_unix.go + getrandom.go + getrandom_linux.go + kernel_version_linux.go + net.go + nofollow_posix.go + nonblocking_unix.go + pidfd_linux.go + siginfo_linux.go + siginfo_linux_other.go + sysnum_linux_arm.go + tcsetpgrp_linux.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + kernel_version_other.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/memory_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/memory_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/memory_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/memory_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/mksyscall.go b/contrib/go/_std_1.23/src/internal/syscall/windows/mksyscall.go similarity index 86% rename from contrib/go/_std_1.22/src/internal/syscall/windows/mksyscall.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/mksyscall.go index 81f08c627e64..f97ab526f815 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/mksyscall.go +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/mksyscall.go @@ -6,4 +6,4 @@ package windows -//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go +//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go version_windows.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/windows/net_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/net_windows.go new file mode 100644 index 000000000000..9fa5ecf84083 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/net_windows.go @@ -0,0 +1,29 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import ( + "syscall" + _ "unsafe" +) + +//go:linkname WSASendtoInet4 syscall.wsaSendtoInet4 +//go:noescape +func WSASendtoInet4(s syscall.Handle, bufs *syscall.WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *syscall.SockaddrInet4, overlapped *syscall.Overlapped, croutine *byte) (err error) + +//go:linkname WSASendtoInet6 syscall.wsaSendtoInet6 +//go:noescape +func WSASendtoInet6(s syscall.Handle, bufs *syscall.WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *syscall.SockaddrInet6, overlapped *syscall.Overlapped, croutine *byte) (err error) + +const ( + SIO_TCP_INITIAL_RTO = syscall.IOC_IN | syscall.IOC_VENDOR | 17 + TCP_INITIAL_RTO_UNSPECIFIED_RTT = ^uint16(0) + TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS = ^uint8(1) +) + +type TCP_INITIAL_RTO_PARAMETERS struct { + Rtt uint16 + MaxSynRetransmissions uint8 +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/psapi_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/psapi_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/psapi_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/psapi_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/key.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/key.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/key.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/key.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/mksyscall.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/mksyscall.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/mksyscall.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/mksyscall.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/syscall.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/syscall.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/syscall.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/value.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/value.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/value.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/value.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/ya.make b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/ya.make rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/ya.make diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/zsyscall_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/zsyscall_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/zsyscall_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/zsyscall_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/reparse_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/reparse_windows.go similarity index 94% rename from contrib/go/_std_1.22/src/internal/syscall/windows/reparse_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/reparse_windows.go index 02f32c675259..241dd523c541 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/reparse_windows.go +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/reparse_windows.go @@ -9,10 +9,13 @@ import ( "unsafe" ) +// Reparse tag values are taken from +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/c8e77b37-3909-4fe6-a4ea-2b9d423b1ee4 const ( FSCTL_SET_REPARSE_POINT = 0x000900A4 IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 IO_REPARSE_TAG_DEDUP = 0x80000013 + IO_REPARSE_TAG_AF_UNIX = 0x80000023 SYMLINK_FLAG_RELATIVE = 1 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/security_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/security_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/security_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/security_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/symlink_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/symlink_windows.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/syscall/windows/symlink_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/symlink_windows.go index 62e3f79986e2..b91246037b5e 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/symlink_windows.go +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/symlink_windows.go @@ -9,6 +9,7 @@ import "syscall" const ( ERROR_INVALID_PARAMETER syscall.Errno = 87 + FILE_SUPPORTS_OBJECT_IDS = 0x00010000 FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000 // symlink support for CreateSymbolicLink() starting with Windows 10 (1703, v10.0.14972) diff --git a/contrib/go/_std_1.23/src/internal/syscall/windows/syscall_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/syscall_windows.go new file mode 100644 index 000000000000..cc26a50bb0ac --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/syscall_windows.go @@ -0,0 +1,501 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import ( + "sync" + "syscall" + "unsafe" +) + +// CanUseLongPaths is true when the OS supports opting into +// proper long path handling without the need for fixups. +// +//go:linkname CanUseLongPaths +var CanUseLongPaths bool + +// UTF16PtrToString is like UTF16ToString, but takes *uint16 +// as a parameter instead of []uint16. +func UTF16PtrToString(p *uint16) string { + if p == nil { + return "" + } + end := unsafe.Pointer(p) + n := 0 + for *(*uint16)(end) != 0 { + end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p)) + n++ + } + return syscall.UTF16ToString(unsafe.Slice(p, n)) +} + +const ( + ERROR_BAD_LENGTH syscall.Errno = 24 + ERROR_SHARING_VIOLATION syscall.Errno = 32 + ERROR_LOCK_VIOLATION syscall.Errno = 33 + ERROR_NOT_SUPPORTED syscall.Errno = 50 + ERROR_CALL_NOT_IMPLEMENTED syscall.Errno = 120 + ERROR_INVALID_NAME syscall.Errno = 123 + ERROR_LOCK_FAILED syscall.Errno = 167 + ERROR_NO_UNICODE_TRANSLATION syscall.Errno = 1113 +) + +const ( + GAA_FLAG_INCLUDE_PREFIX = 0x00000010 + GAA_FLAG_INCLUDE_GATEWAYS = 0x0080 +) + +const ( + IF_TYPE_OTHER = 1 + IF_TYPE_ETHERNET_CSMACD = 6 + IF_TYPE_ISO88025_TOKENRING = 9 + IF_TYPE_PPP = 23 + IF_TYPE_SOFTWARE_LOOPBACK = 24 + IF_TYPE_ATM = 37 + IF_TYPE_IEEE80211 = 71 + IF_TYPE_TUNNEL = 131 + IF_TYPE_IEEE1394 = 144 +) + +type SocketAddress struct { + Sockaddr *syscall.RawSockaddrAny + SockaddrLength int32 +} + +type IpAdapterUnicastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterUnicastAddress + Address SocketAddress + PrefixOrigin int32 + SuffixOrigin int32 + DadState int32 + ValidLifetime uint32 + PreferredLifetime uint32 + LeaseLifetime uint32 + OnLinkPrefixLength uint8 +} + +type IpAdapterAnycastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterAnycastAddress + Address SocketAddress +} + +type IpAdapterMulticastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterMulticastAddress + Address SocketAddress +} + +type IpAdapterDnsServerAdapter struct { + Length uint32 + Reserved uint32 + Next *IpAdapterDnsServerAdapter + Address SocketAddress +} + +type IpAdapterPrefix struct { + Length uint32 + Flags uint32 + Next *IpAdapterPrefix + Address SocketAddress + PrefixLength uint32 +} + +type IpAdapterWinsServerAddress struct { + Length uint32 + Reserved uint32 + Next *IpAdapterWinsServerAddress + Address SocketAddress +} + +type IpAdapterGatewayAddress struct { + Length uint32 + Reserved uint32 + Next *IpAdapterGatewayAddress + Address SocketAddress +} + +type IpAdapterAddresses struct { + Length uint32 + IfIndex uint32 + Next *IpAdapterAddresses + AdapterName *byte + FirstUnicastAddress *IpAdapterUnicastAddress + FirstAnycastAddress *IpAdapterAnycastAddress + FirstMulticastAddress *IpAdapterMulticastAddress + FirstDnsServerAddress *IpAdapterDnsServerAdapter + DnsSuffix *uint16 + Description *uint16 + FriendlyName *uint16 + PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte + PhysicalAddressLength uint32 + Flags uint32 + Mtu uint32 + IfType uint32 + OperStatus uint32 + Ipv6IfIndex uint32 + ZoneIndices [16]uint32 + FirstPrefix *IpAdapterPrefix + TransmitLinkSpeed uint64 + ReceiveLinkSpeed uint64 + FirstWinsServerAddress *IpAdapterWinsServerAddress + FirstGatewayAddress *IpAdapterGatewayAddress + /* more fields might be present here. */ +} + +type SecurityAttributes struct { + Length uint16 + SecurityDescriptor uintptr + InheritHandle bool +} + +type FILE_BASIC_INFO struct { + CreationTime int64 + LastAccessTime int64 + LastWriteTime int64 + ChangedTime int64 + FileAttributes uint32 + + // Pad out to 8-byte alignment. + // + // Without this padding, TestChmod fails due to an argument validation error + // in SetFileInformationByHandle on windows/386. + // + // https://learn.microsoft.com/en-us/cpp/build/reference/zp-struct-member-alignment?view=msvc-170 + // says that “The C/C++ headers in the Windows SDK assume the platform's + // default alignment is used.” What we see here is padding rather than + // alignment, but maybe it is related. + _ uint32 +} + +const ( + IfOperStatusUp = 1 + IfOperStatusDown = 2 + IfOperStatusTesting = 3 + IfOperStatusUnknown = 4 + IfOperStatusDormant = 5 + IfOperStatusNotPresent = 6 + IfOperStatusLowerLayerDown = 7 +) + +//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses +//sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW +//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW +//sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW +//sys SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf unsafe.Pointer, bufsize uint32) (err error) = kernel32.SetFileInformationByHandle +//sys VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQuery +//sys GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPath2W + +const ( + // flags for CreateToolhelp32Snapshot + TH32CS_SNAPMODULE = 0x08 + TH32CS_SNAPMODULE32 = 0x10 +) + +const MAX_MODULE_NAME32 = 255 + +type ModuleEntry32 struct { + Size uint32 + ModuleID uint32 + ProcessID uint32 + GlblcntUsage uint32 + ProccntUsage uint32 + ModBaseAddr uintptr + ModBaseSize uint32 + ModuleHandle syscall.Handle + Module [MAX_MODULE_NAME32 + 1]uint16 + ExePath [syscall.MAX_PATH]uint16 +} + +const SizeofModuleEntry32 = unsafe.Sizeof(ModuleEntry32{}) + +//sys Module32First(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW +//sys Module32Next(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32NextW + +const ( + WSA_FLAG_OVERLAPPED = 0x01 + WSA_FLAG_NO_HANDLE_INHERIT = 0x80 + + WSAEINVAL syscall.Errno = 10022 + WSAEMSGSIZE syscall.Errno = 10040 + WSAEAFNOSUPPORT syscall.Errno = 10047 + + MSG_PEEK = 0x2 + MSG_TRUNC = 0x0100 + MSG_CTRUNC = 0x0200 + + socket_error = uintptr(^uint32(0)) +) + +var WSAID_WSASENDMSG = syscall.GUID{ + Data1: 0xa441e712, + Data2: 0x754f, + Data3: 0x43ca, + Data4: [8]byte{0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d}, +} + +var WSAID_WSARECVMSG = syscall.GUID{ + Data1: 0xf689d7c8, + Data2: 0x6f1f, + Data3: 0x436b, + Data4: [8]byte{0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22}, +} + +var sendRecvMsgFunc struct { + once sync.Once + sendAddr uintptr + recvAddr uintptr + err error +} + +type WSAMsg struct { + Name syscall.Pointer + Namelen int32 + Buffers *syscall.WSABuf + BufferCount uint32 + Control syscall.WSABuf + Flags uint32 +} + +//sys WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = ws2_32.WSASocketW +//sys WSAGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult + +func loadWSASendRecvMsg() error { + sendRecvMsgFunc.once.Do(func() { + var s syscall.Handle + s, sendRecvMsgFunc.err = syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) + if sendRecvMsgFunc.err != nil { + return + } + defer syscall.CloseHandle(s) + var n uint32 + sendRecvMsgFunc.err = syscall.WSAIoctl(s, + syscall.SIO_GET_EXTENSION_FUNCTION_POINTER, + (*byte)(unsafe.Pointer(&WSAID_WSARECVMSG)), + uint32(unsafe.Sizeof(WSAID_WSARECVMSG)), + (*byte)(unsafe.Pointer(&sendRecvMsgFunc.recvAddr)), + uint32(unsafe.Sizeof(sendRecvMsgFunc.recvAddr)), + &n, nil, 0) + if sendRecvMsgFunc.err != nil { + return + } + sendRecvMsgFunc.err = syscall.WSAIoctl(s, + syscall.SIO_GET_EXTENSION_FUNCTION_POINTER, + (*byte)(unsafe.Pointer(&WSAID_WSASENDMSG)), + uint32(unsafe.Sizeof(WSAID_WSASENDMSG)), + (*byte)(unsafe.Pointer(&sendRecvMsgFunc.sendAddr)), + uint32(unsafe.Sizeof(sendRecvMsgFunc.sendAddr)), + &n, nil, 0) + }) + return sendRecvMsgFunc.err +} + +func WSASendMsg(fd syscall.Handle, msg *WSAMsg, flags uint32, bytesSent *uint32, overlapped *syscall.Overlapped, croutine *byte) error { + err := loadWSASendRecvMsg() + if err != nil { + return err + } + r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.sendAddr, 6, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(flags), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return err +} + +func WSARecvMsg(fd syscall.Handle, msg *WSAMsg, bytesReceived *uint32, overlapped *syscall.Overlapped, croutine *byte) error { + err := loadWSASendRecvMsg() + if err != nil { + return err + } + r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.recvAddr, 5, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(bytesReceived)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0) + if r1 == socket_error { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return err +} + +const ( + ComputerNameNetBIOS = 0 + ComputerNameDnsHostname = 1 + ComputerNameDnsDomain = 2 + ComputerNameDnsFullyQualified = 3 + ComputerNamePhysicalNetBIOS = 4 + ComputerNamePhysicalDnsHostname = 5 + ComputerNamePhysicalDnsDomain = 6 + ComputerNamePhysicalDnsFullyQualified = 7 + ComputerNameMax = 8 + + MOVEFILE_REPLACE_EXISTING = 0x1 + MOVEFILE_COPY_ALLOWED = 0x2 + MOVEFILE_DELAY_UNTIL_REBOOT = 0x4 + MOVEFILE_WRITE_THROUGH = 0x8 + MOVEFILE_CREATE_HARDLINK = 0x10 + MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 +) + +func Rename(oldpath, newpath string) error { + from, err := syscall.UTF16PtrFromString(oldpath) + if err != nil { + return err + } + to, err := syscall.UTF16PtrFromString(newpath) + if err != nil { + return err + } + return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) +} + +//sys LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) = kernel32.LockFileEx +//sys UnlockFileEx(file syscall.Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) = kernel32.UnlockFileEx + +const ( + LOCKFILE_FAIL_IMMEDIATELY = 0x00000001 + LOCKFILE_EXCLUSIVE_LOCK = 0x00000002 +) + +const MB_ERR_INVALID_CHARS = 8 + +//sys GetACP() (acp uint32) = kernel32.GetACP +//sys GetConsoleCP() (ccp uint32) = kernel32.GetConsoleCP +//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar +//sys GetCurrentThread() (pseudoHandle syscall.Handle, err error) = kernel32.GetCurrentThread + +// Constants from lmshare.h +const ( + STYPE_DISKTREE = 0x00 + STYPE_TEMPORARY = 0x40000000 +) + +type SHARE_INFO_2 struct { + Netname *uint16 + Type uint32 + Remark *uint16 + Permissions uint32 + MaxUses uint32 + CurrentUses uint32 + Path *uint16 + Passwd *uint16 +} + +//sys NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) = netapi32.NetShareAdd +//sys NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) = netapi32.NetShareDel + +const ( + FILE_NAME_NORMALIZED = 0x0 + FILE_NAME_OPENED = 0x8 + + VOLUME_NAME_DOS = 0x0 + VOLUME_NAME_GUID = 0x1 + VOLUME_NAME_NONE = 0x4 + VOLUME_NAME_NT = 0x2 +) + +//sys GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) = kernel32.GetFinalPathNameByHandleW + +func ErrorLoadingGetTempPath2() error { + return procGetTempPath2W.Find() +} + +//sys CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock +//sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock +//sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW + +//sys ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng + +type FILE_ID_BOTH_DIR_INFO struct { + NextEntryOffset uint32 + FileIndex uint32 + CreationTime syscall.Filetime + LastAccessTime syscall.Filetime + LastWriteTime syscall.Filetime + ChangeTime syscall.Filetime + EndOfFile uint64 + AllocationSize uint64 + FileAttributes uint32 + FileNameLength uint32 + EaSize uint32 + ShortNameLength uint32 + ShortName [12]uint16 + FileID uint64 + FileName [1]uint16 +} + +type FILE_FULL_DIR_INFO struct { + NextEntryOffset uint32 + FileIndex uint32 + CreationTime syscall.Filetime + LastAccessTime syscall.Filetime + LastWriteTime syscall.Filetime + ChangeTime syscall.Filetime + EndOfFile uint64 + AllocationSize uint64 + FileAttributes uint32 + FileNameLength uint32 + EaSize uint32 + FileName [1]uint16 +} + +//sys GetVolumeInformationByHandle(file syscall.Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) = GetVolumeInformationByHandleW +//sys GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) = GetVolumeNameForVolumeMountPointW + +//sys RtlLookupFunctionEntry(pc uintptr, baseAddress *uintptr, table *byte) (ret uintptr) = kernel32.RtlLookupFunctionEntry +//sys RtlVirtualUnwind(handlerType uint32, baseAddress uintptr, pc uintptr, entry uintptr, ctxt uintptr, data *uintptr, frame *uintptr, ctxptrs *byte) (ret uintptr) = kernel32.RtlVirtualUnwind + +type SERVICE_STATUS struct { + ServiceType uint32 + CurrentState uint32 + ControlsAccepted uint32 + Win32ExitCode uint32 + ServiceSpecificExitCode uint32 + CheckPoint uint32 + WaitHint uint32 +} + +const ( + SERVICE_RUNNING = 4 + SERVICE_QUERY_STATUS = 4 +) + +//sys OpenService(mgr syscall.Handle, serviceName *uint16, access uint32) (handle syscall.Handle, err error) = advapi32.OpenServiceW +//sys QueryServiceStatus(hService syscall.Handle, lpServiceStatus *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus +//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle syscall.Handle, err error) [failretval==0] = advapi32.OpenSCManagerW + +func FinalPath(h syscall.Handle, flags uint32) (string, error) { + buf := make([]uint16, 100) + for { + n, err := GetFinalPathNameByHandle(h, &buf[0], uint32(len(buf)), flags) + if err != nil { + return "", err + } + if n < uint32(len(buf)) { + break + } + buf = make([]uint16, n) + } + return syscall.UTF16ToString(buf), nil +} + +// QueryPerformanceCounter retrieves the current value of performance counter. +// +//go:linkname QueryPerformanceCounter +func QueryPerformanceCounter() int64 // Implemented in runtime package. + +// QueryPerformanceFrequency retrieves the frequency of the performance counter. +// The returned value is represented as counts per second. +// +//go:linkname QueryPerformanceFrequency +func QueryPerformanceFrequency() int64 // Implemented in runtime package. diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/sysdll/sysdll.go b/contrib/go/_std_1.23/src/internal/syscall/windows/sysdll/sysdll.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/sysdll/sysdll.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/sysdll/sysdll.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/sysdll/ya.make b/contrib/go/_std_1.23/src/internal/syscall/windows/sysdll/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/sysdll/ya.make rename to contrib/go/_std_1.23/src/internal/syscall/windows/sysdll/ya.make diff --git a/contrib/go/_std_1.23/src/internal/syscall/windows/types_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/types_windows.go new file mode 100644 index 000000000000..126e07b8834c --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/types_windows.go @@ -0,0 +1,12 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +// Socket related. +const ( + TCP_KEEPIDLE = 0x03 + TCP_KEEPCNT = 0x10 + TCP_KEEPINTVL = 0x11 +) diff --git a/contrib/go/_std_1.23/src/internal/syscall/windows/version_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/version_windows.go new file mode 100644 index 000000000000..ff21fc59e5bf --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/version_windows.go @@ -0,0 +1,113 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import ( + "errors" + "sync" + "syscall" + "unsafe" +) + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow +type _OSVERSIONINFOW struct { + osVersionInfoSize uint32 + majorVersion uint32 + minorVersion uint32 + buildNumber uint32 + platformId uint32 + csdVersion [128]uint16 +} + +// According to documentation, RtlGetVersion function always succeeds. +//sys rtlGetVersion(info *_OSVERSIONINFOW) = ntdll.RtlGetVersion + +// version retrieves the major, minor, and build version numbers +// of the current Windows OS from the RtlGetVersion API. +func version() (major, minor, build uint32) { + info := _OSVERSIONINFOW{} + info.osVersionInfoSize = uint32(unsafe.Sizeof(info)) + rtlGetVersion(&info) + return info.majorVersion, info.minorVersion, info.buildNumber +} + +var ( + supportTCPKeepAliveIdle bool + supportTCPKeepAliveInterval bool + supportTCPKeepAliveCount bool +) + +var initTCPKeepAlive = sync.OnceFunc(func() { + s, err := WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, WSA_FLAG_NO_HANDLE_INHERIT) + if err != nil { + // Fallback to checking the Windows version. + major, _, build := version() + supportTCPKeepAliveIdle = major >= 10 && build >= 16299 + supportTCPKeepAliveInterval = major >= 10 && build >= 16299 + supportTCPKeepAliveCount = major >= 10 && build >= 15063 + return + } + defer syscall.Closesocket(s) + var optSupported = func(opt int) bool { + err := syscall.SetsockoptInt(s, syscall.IPPROTO_TCP, opt, 1) + return !errors.Is(err, syscall.WSAENOPROTOOPT) + } + supportTCPKeepAliveIdle = optSupported(TCP_KEEPIDLE) + supportTCPKeepAliveInterval = optSupported(TCP_KEEPINTVL) + supportTCPKeepAliveCount = optSupported(TCP_KEEPCNT) +}) + +// SupportTCPKeepAliveInterval indicates whether TCP_KEEPIDLE is supported. +// The minimal requirement is Windows 10.0.16299. +func SupportTCPKeepAliveIdle() bool { + initTCPKeepAlive() + return supportTCPKeepAliveIdle +} + +// SupportTCPKeepAliveInterval indicates whether TCP_KEEPINTVL is supported. +// The minimal requirement is Windows 10.0.16299. +func SupportTCPKeepAliveInterval() bool { + initTCPKeepAlive() + return supportTCPKeepAliveInterval +} + +// SupportTCPKeepAliveCount indicates whether TCP_KEEPCNT is supported. +// supports TCP_KEEPCNT. +// The minimal requirement is Windows 10.0.15063. +func SupportTCPKeepAliveCount() bool { + initTCPKeepAlive() + return supportTCPKeepAliveCount +} + +// SupportTCPInitialRTONoSYNRetransmissions indicates whether the current +// Windows version supports the TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS. +// The minimal requirement is Windows 10.0.16299. +var SupportTCPInitialRTONoSYNRetransmissions = sync.OnceValue(func() bool { + major, _, build := version() + return major >= 10 && build >= 16299 +}) + +// SupportUnixSocket indicates whether the current Windows version supports +// Unix Domain Sockets. +// The minimal requirement is Windows 10.0.17063. +var SupportUnixSocket = sync.OnceValue(func() bool { + var size uint32 + // First call to get the required buffer size in bytes. + // Ignore the error, it will always fail. + _, _ = syscall.WSAEnumProtocols(nil, nil, &size) + n := int32(size) / int32(unsafe.Sizeof(syscall.WSAProtocolInfo{})) + // Second call to get the actual protocols. + buf := make([]syscall.WSAProtocolInfo, n) + n, err := syscall.WSAEnumProtocols(nil, &buf[0], &size) + if err != nil { + return false + } + for i := int32(0); i < n; i++ { + if buf[i].AddressFamily == syscall.AF_UNIX { + return true + } + } + return false +}) diff --git a/contrib/go/_std_1.23/src/internal/syscall/windows/ya.make b/contrib/go/_std_1.23/src/internal/syscall/windows/ya.make new file mode 100644 index 000000000000..88a4da48a614 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/ya.make @@ -0,0 +1,16 @@ +GO_LIBRARY() +IF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + memory_windows.go + net_windows.go + psapi_windows.go + reparse_windows.go + security_windows.go + symlink_windows.go + syscall_windows.go + types_windows.go + version_windows.go + zsyscall_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/syscall/windows/zsyscall_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/zsyscall_windows.go new file mode 100644 index 000000000000..414ad2647d1a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/zsyscall_windows.go @@ -0,0 +1,456 @@ +// Code generated by 'go generate'; DO NOT EDIT. + +package windows + +import ( + "internal/syscall/windows/sysdll" + "syscall" + "unsafe" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_EINVAL error = syscall.EINVAL +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return errERROR_EINVAL + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) + modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll")) + modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) + modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) + modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) + modntdll = syscall.NewLazyDLL(sysdll.Add("ntdll.dll")) + modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) + moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) + modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) + + procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") + procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") + procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") + procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") + procOpenSCManagerW = modadvapi32.NewProc("OpenSCManagerW") + procOpenServiceW = modadvapi32.NewProc("OpenServiceW") + procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") + procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") + procRevertToSelf = modadvapi32.NewProc("RevertToSelf") + procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") + procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng") + procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") + procCreateEventW = modkernel32.NewProc("CreateEventW") + procGetACP = modkernel32.NewProc("GetACP") + procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") + procGetConsoleCP = modkernel32.NewProc("GetConsoleCP") + procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") + procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx") + procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW") + procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") + procGetTempPath2W = modkernel32.NewProc("GetTempPath2W") + procGetVolumeInformationByHandleW = modkernel32.NewProc("GetVolumeInformationByHandleW") + procGetVolumeNameForVolumeMountPointW = modkernel32.NewProc("GetVolumeNameForVolumeMountPointW") + procLockFileEx = modkernel32.NewProc("LockFileEx") + procModule32FirstW = modkernel32.NewProc("Module32FirstW") + procModule32NextW = modkernel32.NewProc("Module32NextW") + procMoveFileExW = modkernel32.NewProc("MoveFileExW") + procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar") + procRtlLookupFunctionEntry = modkernel32.NewProc("RtlLookupFunctionEntry") + procRtlVirtualUnwind = modkernel32.NewProc("RtlVirtualUnwind") + procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle") + procUnlockFileEx = modkernel32.NewProc("UnlockFileEx") + procVirtualQuery = modkernel32.NewProc("VirtualQuery") + procNetShareAdd = modnetapi32.NewProc("NetShareAdd") + procNetShareDel = modnetapi32.NewProc("NetShareDel") + procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups") + procRtlGetVersion = modntdll.NewProc("RtlGetVersion") + procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") + procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock") + procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock") + procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW") + procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult") + procWSASocketW = modws2_32.NewProc("WSASocketW") +) + +func adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) { + var _p0 uint32 + if disableAllPrivileges { + _p0 = 1 + } + r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen))) + ret = uint32(r0) + if true { + err = errnoErr(e1) + } + return +} + +func DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) { + r1, _, e1 := syscall.Syscall6(procDuplicateTokenEx.Addr(), 6, uintptr(hExistingToken), uintptr(dwDesiredAccess), uintptr(unsafe.Pointer(lpTokenAttributes)), uintptr(impersonationLevel), uintptr(tokenType), uintptr(unsafe.Pointer(phNewToken))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func ImpersonateSelf(impersonationlevel uint32) (err error) { + r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) { + r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemname)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(access)) + handle = syscall.Handle(r0) + if handle == 0 { + err = errnoErr(e1) + } + return +} + +func OpenService(mgr syscall.Handle, serviceName *uint16, access uint32) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall(procOpenServiceW.Addr(), 3, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(access)) + handle = syscall.Handle(r0) + if handle == 0 { + err = errnoErr(e1) + } + return +} + +func OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) { + var _p0 uint32 + if openasself { + _p0 = 1 + } + r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(h), uintptr(access), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func QueryServiceStatus(hService syscall.Handle, lpServiceStatus *SERVICE_STATUS) (err error) { + r1, _, e1 := syscall.Syscall(procQueryServiceStatus.Addr(), 2, uintptr(hService), uintptr(unsafe.Pointer(lpServiceStatus)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func RevertToSelf() (err error) { + r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation uintptr, tokenInformationLength uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetTokenInformation.Addr(), 4, uintptr(tokenHandle), uintptr(tokenInformationClass), uintptr(tokenInformation), uintptr(tokenInformationLength), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func ProcessPrng(buf []byte) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + r1, _, e1 := syscall.Syscall(procProcessPrng.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { + r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttrs)), uintptr(manualReset), uintptr(initialState), uintptr(unsafe.Pointer(name)), 0, 0) + handle = syscall.Handle(r0) + if handle == 0 { + err = errnoErr(e1) + } + return +} + +func GetACP() (acp uint32) { + r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0) + acp = uint32(r0) + return +} + +func GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nameformat), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetConsoleCP() (ccp uint32) { + r0, _, _ := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0) + ccp = uint32(r0) + return +} + +func GetCurrentThread() (pseudoHandle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) + pseudoHandle = syscall.Handle(r0) + if pseudoHandle == 0 { + err = errnoErr(e1) + } + return +} + +func GetFileInformationByHandleEx(handle syscall.Handle, class uint32, info *byte, bufsize uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(handle), uintptr(class), uintptr(unsafe.Pointer(info)), uintptr(bufsize), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetModuleFileNameW.Addr(), 3, uintptr(module), uintptr(unsafe.Pointer(fn)), uintptr(len)) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetTempPath2W.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func GetVolumeInformationByHandle(file syscall.Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procGetVolumeInformationByHandleW.Addr(), 8, uintptr(file), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetVolumeNameForVolumeMountPointW.Addr(), 3, uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferlength)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(file), uintptr(flags), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func Module32First(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procModule32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func Module32Next(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procModule32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) { + r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar)) + nwrite = int32(r0) + if nwrite == 0 { + err = errnoErr(e1) + } + return +} + +func RtlLookupFunctionEntry(pc uintptr, baseAddress *uintptr, table *byte) (ret uintptr) { + r0, _, _ := syscall.Syscall(procRtlLookupFunctionEntry.Addr(), 3, uintptr(pc), uintptr(unsafe.Pointer(baseAddress)), uintptr(unsafe.Pointer(table))) + ret = uintptr(r0) + return +} + +func RtlVirtualUnwind(handlerType uint32, baseAddress uintptr, pc uintptr, entry uintptr, ctxt uintptr, data *uintptr, frame *uintptr, ctxptrs *byte) (ret uintptr) { + r0, _, _ := syscall.Syscall9(procRtlVirtualUnwind.Addr(), 8, uintptr(handlerType), uintptr(baseAddress), uintptr(pc), uintptr(entry), uintptr(ctxt), uintptr(unsafe.Pointer(data)), uintptr(unsafe.Pointer(frame)), uintptr(unsafe.Pointer(ctxptrs)), 0) + ret = uintptr(r0) + return +} + +func SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf unsafe.Pointer, bufsize uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(handle), uintptr(fileInformationClass), uintptr(buf), uintptr(bufsize), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func UnlockFileEx(file syscall.Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall6(procUnlockFileEx.Addr(), 5, uintptr(file), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procVirtualQuery.Addr(), 3, uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) { + r0, _, _ := syscall.Syscall6(procNetShareAdd.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(parmErr)), 0, 0) + if r0 != 0 { + neterr = syscall.Errno(r0) + } + return +} + +func NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) { + r0, _, _ := syscall.Syscall(procNetShareDel.Addr(), 3, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(netName)), uintptr(reserved)) + if r0 != 0 { + neterr = syscall.Errno(r0) + } + return +} + +func NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, flags uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32) (neterr error) { + r0, _, _ := syscall.Syscall9(procNetUserGetLocalGroups.Addr(), 8, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(flags), uintptr(unsafe.Pointer(buf)), uintptr(prefMaxLen), uintptr(unsafe.Pointer(entriesRead)), uintptr(unsafe.Pointer(totalEntries)), 0) + if r0 != 0 { + neterr = syscall.Errno(r0) + } + return +} + +func rtlGetVersion(info *_OSVERSIONINFOW) { + syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0) + return +} + +func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(memCounters)), uintptr(cb)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) { + var _p0 uint32 + if inheritExisting { + _p0 = 1 + } + r1, _, e1 := syscall.Syscall(procCreateEnvironmentBlock.Addr(), 3, uintptr(unsafe.Pointer(block)), uintptr(token), uintptr(_p0)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func DestroyEnvironmentBlock(block *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procDestroyEnvironmentBlock.Addr(), 1, uintptr(unsafe.Pointer(block)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetProfilesDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func WSAGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { + var _p0 uint32 + if wait { + _p0 = 1 + } + r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protinfo)), uintptr(group), uintptr(flags)) + handle = syscall.Handle(r0) + if handle == syscall.InvalidHandle { + err = errnoErr(e1) + } + return +} diff --git a/contrib/go/_std_1.22/src/internal/testlog/exit.go b/contrib/go/_std_1.23/src/internal/testlog/exit.go similarity index 75% rename from contrib/go/_std_1.22/src/internal/testlog/exit.go rename to contrib/go/_std_1.23/src/internal/testlog/exit.go index e15defdb5b0b..b985c6b3f79b 100644 --- a/contrib/go/_std_1.22/src/internal/testlog/exit.go +++ b/contrib/go/_std_1.23/src/internal/testlog/exit.go @@ -4,7 +4,10 @@ package testlog -import "sync" +import ( + "sync" + _ "unsafe" // for linkname +) // PanicOnExit0 reports whether to panic on a call to os.Exit(0). // This is in the testlog package because, like other definitions in @@ -26,6 +29,15 @@ var panicOnExit0 struct { } // SetPanicOnExit0 sets panicOnExit0 to v. +// +// SetPanicOnExit0 should be an internal detail, +// but alternate implementations of go test in other +// build systems may need to access it using linkname. +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname SetPanicOnExit0 func SetPanicOnExit0(v bool) { panicOnExit0.mu.Lock() defer panicOnExit0.mu.Unlock() diff --git a/contrib/go/_std_1.22/src/internal/testlog/log.go b/contrib/go/_std_1.23/src/internal/testlog/log.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/testlog/log.go rename to contrib/go/_std_1.23/src/internal/testlog/log.go diff --git a/contrib/go/_std_1.22/src/internal/testlog/ya.make b/contrib/go/_std_1.23/src/internal/testlog/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/testlog/ya.make rename to contrib/go/_std_1.23/src/internal/testlog/ya.make diff --git a/contrib/go/_std_1.22/src/internal/types/errors/code_string.go b/contrib/go/_std_1.23/src/internal/types/errors/code_string.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/types/errors/code_string.go rename to contrib/go/_std_1.23/src/internal/types/errors/code_string.go index 719fc73a5a76..9ae675ef849d 100644 --- a/contrib/go/_std_1.22/src/internal/types/errors/code_string.go +++ b/contrib/go/_std_1.23/src/internal/types/errors/code_string.go @@ -155,6 +155,7 @@ func _() { _ = x[InvalidClear-148] _ = x[TypeTooLarge-149] _ = x[InvalidMinMaxOperand-150] + _ = x[TooNew-151] } const ( @@ -163,7 +164,7 @@ const ( _Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDot" _Code_name_3 = "InvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDecl" _Code_name_4 = "InvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString" - _Code_name_5 = "InvalidClearTypeTooLargeInvalidMinMaxOperand" + _Code_name_5 = "InvalidClearTypeTooLargeInvalidMinMaxOperandTooNew" ) var ( @@ -171,7 +172,7 @@ var ( _Code_index_2 = [...]uint16{0, 15, 22, 33, 56, 71, 83, 94, 109, 123, 138, 153, 166, 175, 189, 204, 215, 230, 239, 255, 275, 293, 312, 324, 343, 362, 378, 395, 414, 428, 439, 454, 467, 482, 498, 512, 528, 543, 560, 578, 593, 603, 613, 630, 652, 666, 680, 700, 718, 738, 756} _Code_index_3 = [...]uint16{0, 16, 31, 44, 54, 66, 77, 91, 104, 115, 125, 140, 151, 162, 175, 191, 208, 232, 249, 264, 274, 283, 296, 312, 328, 339, 354} _Code_index_4 = [...]uint16{0, 14, 30, 44, 61, 81, 94, 110, 124, 141, 158, 175, 190, 204, 218, 229, 241, 254, 271, 284, 295, 308, 320, 329, 336, 348, 364, 382, 400, 415, 432, 451, 465, 485, 497, 521, 544, 562, 584, 603} - _Code_index_5 = [...]uint8{0, 12, 24, 44} + _Code_index_5 = [...]uint8{0, 12, 24, 44, 50} ) func (i Code) String() string { @@ -190,7 +191,7 @@ func (i Code) String() string { case 108 <= i && i <= 146: i -= 108 return _Code_name_4[_Code_index_4[i]:_Code_index_4[i+1]] - case 148 <= i && i <= 150: + case 148 <= i && i <= 151: i -= 148 return _Code_name_5[_Code_index_5[i]:_Code_index_5[i+1]] default: diff --git a/contrib/go/_std_1.22/src/internal/types/errors/codes.go b/contrib/go/_std_1.23/src/internal/types/errors/codes.go similarity index 98% rename from contrib/go/_std_1.22/src/internal/types/errors/codes.go rename to contrib/go/_std_1.23/src/internal/types/errors/codes.go index cae688ff874b..c0e6aa6c2daf 100644 --- a/contrib/go/_std_1.22/src/internal/types/errors/codes.go +++ b/contrib/go/_std_1.23/src/internal/types/errors/codes.go @@ -4,7 +4,7 @@ package errors -//go:generate stringer -type Code codes.go +//go:generate go run golang.org/x/tools/cmd/stringer@latest -type Code codes.go type Code int @@ -1474,4 +1474,12 @@ const ( // var s, t []byte // var _ = max(s, t) InvalidMinMaxOperand + + // TooNew indicates that, through build tags or a go.mod file, + // a source file requires a version of Go that is newer than + // the logic of the type checker. As a consequence, the type + // checker may produce spurious errors or fail to report real + // errors. The solution is to rebuild the application with a + // newer Go release. + TooNew ) diff --git a/contrib/go/_std_1.22/src/internal/types/errors/generrordocs.go b/contrib/go/_std_1.23/src/internal/types/errors/generrordocs.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/types/errors/generrordocs.go rename to contrib/go/_std_1.23/src/internal/types/errors/generrordocs.go diff --git a/contrib/go/_std_1.22/src/internal/types/errors/ya.make b/contrib/go/_std_1.23/src/internal/types/errors/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/types/errors/ya.make rename to contrib/go/_std_1.23/src/internal/types/errors/ya.make diff --git a/contrib/go/_std_1.22/src/internal/unsafeheader/unsafeheader.go b/contrib/go/_std_1.23/src/internal/unsafeheader/unsafeheader.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/unsafeheader/unsafeheader.go rename to contrib/go/_std_1.23/src/internal/unsafeheader/unsafeheader.go diff --git a/contrib/go/_std_1.22/src/internal/unsafeheader/ya.make b/contrib/go/_std_1.23/src/internal/unsafeheader/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/unsafeheader/ya.make rename to contrib/go/_std_1.23/src/internal/unsafeheader/ya.make diff --git a/contrib/go/_std_1.23/src/internal/weak/pointer.go b/contrib/go/_std_1.23/src/internal/weak/pointer.go new file mode 100644 index 000000000000..8e05af2d23f0 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/weak/pointer.go @@ -0,0 +1,83 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +The weak package is a package for managing weak pointers. + +Weak pointers are pointers that explicitly do not keep a value live and +must be queried for a regular Go pointer. +The result of such a query may be observed as nil at any point after a +weakly-pointed-to object becomes eligible for reclamation by the garbage +collector. +More specifically, weak pointers become nil as soon as the garbage collector +identifies that the object is unreachable, before it is made reachable +again by a finalizer. +In terms of the C# language, these semantics are roughly equivalent to the +the semantics of "short" weak references. +In terms of the Java language, these semantics are roughly equivalent to the +semantics of the WeakReference type. + +Using go:linkname to access this package and the functions it references +is explicitly forbidden by the toolchain because the semantics of this +package have not gone through the proposal process. By exposing this +functionality, we risk locking in the existing semantics due to Hyrum's Law. + +If you believe you have a good use-case for weak references not already +covered by the standard library, file a proposal issue at +https://github.com/golang/go/issues instead of relying on this package. +*/ +package weak + +import ( + "internal/abi" + "runtime" + "unsafe" +) + +// Pointer is a weak pointer to a value of type T. +// +// This value is comparable is guaranteed to compare equal if the pointers +// that they were created from compare equal. This property is retained even +// after the object referenced by the pointer used to create a weak reference +// is reclaimed. +// +// If multiple weak pointers are made to different offsets within same object +// (for example, pointers to different fields of the same struct), those pointers +// will not compare equal. +// If a weak pointer is created from an object that becomes reachable again due +// to a finalizer, that weak pointer will not compare equal with weak pointers +// created before it became unreachable. +type Pointer[T any] struct { + u unsafe.Pointer +} + +// Make creates a weak pointer from a strong pointer to some value of type T. +func Make[T any](ptr *T) Pointer[T] { + // Explicitly force ptr to escape to the heap. + ptr = abi.Escape(ptr) + + var u unsafe.Pointer + if ptr != nil { + u = runtime_registerWeakPointer(unsafe.Pointer(ptr)) + } + runtime.KeepAlive(ptr) + return Pointer[T]{u} +} + +// Strong creates a strong pointer from the weak pointer. +// Returns nil if the original value for the weak pointer was reclaimed by +// the garbage collector. +// If a weak pointer points to an object with a finalizer, then Strong will +// return nil as soon as the object's finalizer is queued for execution. +func (p Pointer[T]) Strong() *T { + return (*T)(runtime_makeStrongFromWeak(p.u)) +} + +// Implemented in runtime. + +//go:linkname runtime_registerWeakPointer +func runtime_registerWeakPointer(unsafe.Pointer) unsafe.Pointer + +//go:linkname runtime_makeStrongFromWeak +func runtime_makeStrongFromWeak(unsafe.Pointer) unsafe.Pointer diff --git a/contrib/go/_std_1.23/src/internal/weak/ya.make b/contrib/go/_std_1.23/src/internal/weak/ya.make new file mode 100644 index 000000000000..4c8d8d9ab8eb --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/weak/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + pointer.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/io/fs/format.go b/contrib/go/_std_1.23/src/io/fs/format.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/format.go rename to contrib/go/_std_1.23/src/io/fs/format.go diff --git a/contrib/go/_std_1.22/src/io/fs/fs.go b/contrib/go/_std_1.23/src/io/fs/fs.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/fs.go rename to contrib/go/_std_1.23/src/io/fs/fs.go diff --git a/contrib/go/_std_1.22/src/io/fs/glob.go b/contrib/go/_std_1.23/src/io/fs/glob.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/glob.go rename to contrib/go/_std_1.23/src/io/fs/glob.go diff --git a/contrib/go/_std_1.22/src/io/fs/readdir.go b/contrib/go/_std_1.23/src/io/fs/readdir.go similarity index 93% rename from contrib/go/_std_1.22/src/io/fs/readdir.go rename to contrib/go/_std_1.23/src/io/fs/readdir.go index 22ced48073be..467d3bffeeb6 100644 --- a/contrib/go/_std_1.22/src/io/fs/readdir.go +++ b/contrib/go/_std_1.23/src/io/fs/readdir.go @@ -6,7 +6,8 @@ package fs import ( "errors" - "sort" + "internal/bytealg" + "slices" ) // ReadDirFS is the interface implemented by a file system @@ -42,7 +43,9 @@ func ReadDir(fsys FS, name string) ([]DirEntry, error) { } list, err := dir.ReadDir(-1) - sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() }) + slices.SortFunc(list, func(a, b DirEntry) int { + return bytealg.CompareString(a.Name(), b.Name()) + }) return list, err } diff --git a/contrib/go/_std_1.22/src/io/fs/readfile.go b/contrib/go/_std_1.23/src/io/fs/readfile.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/readfile.go rename to contrib/go/_std_1.23/src/io/fs/readfile.go diff --git a/contrib/go/_std_1.22/src/io/fs/stat.go b/contrib/go/_std_1.23/src/io/fs/stat.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/stat.go rename to contrib/go/_std_1.23/src/io/fs/stat.go diff --git a/contrib/go/_std_1.22/src/io/fs/sub.go b/contrib/go/_std_1.23/src/io/fs/sub.go similarity index 95% rename from contrib/go/_std_1.22/src/io/fs/sub.go rename to contrib/go/_std_1.23/src/io/fs/sub.go index 9999e63b26f2..70ac62307778 100644 --- a/contrib/go/_std_1.22/src/io/fs/sub.go +++ b/contrib/go/_std_1.23/src/io/fs/sub.go @@ -33,7 +33,7 @@ type SubFS interface { // chroot-style security mechanism, and Sub does not change that fact. func Sub(fsys FS, dir string) (FS, error) { if !ValidPath(dir) { - return nil, &PathError{Op: "sub", Path: dir, Err: errors.New("invalid name")} + return nil, &PathError{Op: "sub", Path: dir, Err: ErrInvalid} } if dir == "." { return fsys, nil @@ -52,7 +52,7 @@ type subFS struct { // fullName maps name to the fully-qualified name dir/name. func (f *subFS) fullName(op string, name string) (string, error) { if !ValidPath(name) { - return "", &PathError{Op: op, Path: name, Err: errors.New("invalid name")} + return "", &PathError{Op: op, Path: name, Err: ErrInvalid} } return path.Join(f.dir, name), nil } diff --git a/contrib/go/_std_1.22/src/io/fs/walk.go b/contrib/go/_std_1.23/src/io/fs/walk.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/walk.go rename to contrib/go/_std_1.23/src/io/fs/walk.go diff --git a/contrib/go/_std_1.22/src/io/fs/ya.make b/contrib/go/_std_1.23/src/io/fs/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/ya.make rename to contrib/go/_std_1.23/src/io/fs/ya.make diff --git a/contrib/go/_std_1.22/src/io/io.go b/contrib/go/_std_1.23/src/io/io.go similarity index 99% rename from contrib/go/_std_1.22/src/io/io.go rename to contrib/go/_std_1.23/src/io/io.go index 7f16e18d7d1b..00edcde763a5 100644 --- a/contrib/go/_std_1.22/src/io/io.go +++ b/contrib/go/_std_1.23/src/io/io.go @@ -411,8 +411,8 @@ func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { return wt.WriteTo(dst) } // Similarly, if the writer has a ReadFrom method, use it to do the copy. - if rt, ok := dst.(ReaderFrom); ok { - return rt.ReadFrom(src) + if rf, ok := dst.(ReaderFrom); ok { + return rf.ReadFrom(src) } if buf == nil { size := 32 * 1024 diff --git a/contrib/go/_std_1.22/src/io/ioutil/ioutil.go b/contrib/go/_std_1.23/src/io/ioutil/ioutil.go similarity index 96% rename from contrib/go/_std_1.22/src/io/ioutil/ioutil.go rename to contrib/go/_std_1.23/src/io/ioutil/ioutil.go index 67768e54cf55..af8ebe38501d 100644 --- a/contrib/go/_std_1.22/src/io/ioutil/ioutil.go +++ b/contrib/go/_std_1.23/src/io/ioutil/ioutil.go @@ -14,7 +14,8 @@ import ( "io" "io/fs" "os" - "sort" + "slices" + "strings" ) // ReadAll reads from r until an error or EOF and returns the data it read. @@ -76,7 +77,9 @@ func ReadDir(dirname string) ([]fs.FileInfo, error) { if err != nil { return nil, err } - sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() }) + slices.SortFunc(list, func(a, b os.FileInfo) int { + return strings.Compare(a.Name(), b.Name()) + }) return list, nil } diff --git a/contrib/go/_std_1.22/src/io/ioutil/tempfile.go b/contrib/go/_std_1.23/src/io/ioutil/tempfile.go similarity index 100% rename from contrib/go/_std_1.22/src/io/ioutil/tempfile.go rename to contrib/go/_std_1.23/src/io/ioutil/tempfile.go diff --git a/contrib/go/_std_1.22/src/io/ioutil/ya.make b/contrib/go/_std_1.23/src/io/ioutil/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/io/ioutil/ya.make rename to contrib/go/_std_1.23/src/io/ioutil/ya.make diff --git a/contrib/go/_std_1.22/src/io/multi.go b/contrib/go/_std_1.23/src/io/multi.go similarity index 100% rename from contrib/go/_std_1.22/src/io/multi.go rename to contrib/go/_std_1.23/src/io/multi.go diff --git a/contrib/go/_std_1.22/src/io/pipe.go b/contrib/go/_std_1.23/src/io/pipe.go similarity index 100% rename from contrib/go/_std_1.22/src/io/pipe.go rename to contrib/go/_std_1.23/src/io/pipe.go diff --git a/contrib/go/_std_1.22/src/io/ya.make b/contrib/go/_std_1.23/src/io/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/io/ya.make rename to contrib/go/_std_1.23/src/io/ya.make diff --git a/contrib/go/_std_1.23/src/iter/iter.go b/contrib/go/_std_1.23/src/iter/iter.go new file mode 100644 index 000000000000..14fd8f8115f3 --- /dev/null +++ b/contrib/go/_std_1.23/src/iter/iter.go @@ -0,0 +1,453 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package iter provides basic definitions and operations related to +iterators over sequences. + +# Iterators + +An iterator is a function that passes successive elements of a +sequence to a callback function, conventionally named yield. +The function stops either when the sequence is finished or +when yield returns false, indicating to stop the iteration early. +This package defines [Seq] and [Seq2] +(pronounced like seek—the first syllable of sequence) +as shorthands for iterators that pass 1 or 2 values per sequence element +to yield: + + type ( + Seq[V any] func(yield func(V) bool) + Seq2[K, V any] func(yield func(K, V) bool) + ) + +Seq2 represents a sequence of paired values, conventionally key-value +or index-value pairs. + +Yield returns true if the iterator should continue with the next +element in the sequence, false if it should stop. + +Iterator functions are most often called by a range loop, as in: + + func PrintAll[V any](seq iter.Seq[V]) { + for v := range seq { + fmt.Println(v) + } + } + +# Naming Conventions + +Iterator functions and methods are named for the sequence being walked: + + // All returns an iterator over all elements in s. + func (s *Set[V]) All() iter.Seq[V] + +The iterator method on a collection type is conventionally named All, +because it iterates a sequence of all the values in the collection. + +For a type containing multiple possible sequences, the iterator's name +can indicate which sequence is being provided: + + // Cities returns an iterator over the major cities in the country. + func (c *Country) Cities() iter.Seq[*City] + + // Languages returns an iterator over the official spoken languages of the country. + func (c *Country) Languages() iter.Seq[string] + +If an iterator requires additional configuration, the constructor function +can take additional configuration arguments: + + // Scan returns an iterator over key-value pairs with min ≤ key ≤ max. + func (m *Map[K, V]) Scan(min, max K) iter.Seq2[K, V] + + // Split returns an iterator over the (possibly-empty) substrings of s + // separated by sep. + func Split(s, sep string) iter.Seq[string] + +When there are multiple possible iteration orders, the method name may +indicate that order: + + // All returns an iterator over the list from head to tail. + func (l *List[V]) All() iter.Seq[V] + + // Backward returns an iterator over the list from tail to head. + func (l *List[V]) Backward() iter.Seq[V] + + // Preorder returns an iterator over all nodes of the syntax tree + // beneath (and including) the specified root, in depth-first preorder, + // visiting a parent node before its children. + func Preorder(root Node) iter.Seq[Node] + +# Single-Use Iterators + +Most iterators provide the ability to walk an entire sequence: +when called, the iterator does any setup necessary to start the +sequence, then calls yield on successive elements of the sequence, +and then cleans up before returning. Calling the iterator again +walks the sequence again. + +Some iterators break that convention, providing the ability to walk a +sequence only once. These “single-use iterators” typically report values +from a data stream that cannot be rewound to start over. +Calling the iterator again after stopping early may continue the +stream, but calling it again after the sequence is finished will yield +no values at all. Doc comments for functions or methods that return +single-use iterators should document this fact: + + // Lines returns an iterator over lines read from r. + // It returns a single-use iterator. + func (r *Reader) Lines() iter.Seq[string] + +# Pulling Values + +Functions and methods that accept or return iterators +should use the standard [Seq] or [Seq2] types, to ensure +compatibility with range loops and other iterator adapters. +The standard iterators can be thought of as “push iterators”, which +push values to the yield function. + +Sometimes a range loop is not the most natural way to consume values +of the sequence. In this case, [Pull] converts a standard push iterator +to a “pull iterator”, which can be called to pull one value at a time +from the sequence. [Pull] starts an iterator and returns a pair +of functions—next and stop—which return the next value from the iterator +and stop it, respectively. + +For example: + + // Pairs returns an iterator over successive pairs of values from seq. + func Pairs[V any](seq iter.Seq[V]) iter.Seq2[V, V] { + return func(yield func(V, V) bool) { + next, stop := iter.Pull(seq) + defer stop() + for { + v1, ok1 := next() + if !ok1 { + return + } + v2, ok2 := next() + // If ok2 is false, v2 should be the + // zero value; yield one last pair. + if !yield(v1, v2) { + return + } + if !ok2 { + return + } + } + } + } + +If clients do not consume the sequence to completion, they must call stop, +which allows the iterator function to finish and return. As shown in +the example, the conventional way to ensure this is to use defer. + +# Standard Library Usage + +A few packages in the standard library provide iterator-based APIs, +most notably the [maps] and [slices] packages. +For example, [maps.Keys] returns an iterator over the keys of a map, +while [slices.Sorted] collects the values of an iterator into a slice, +sorts them, and returns the slice, so to iterate over the sorted keys of a map: + + for _, key := range slices.Sorted(maps.Keys(m)) { + ... + } + +# Mutation + +Iterators provide only the values of the sequence, not any direct way +to modify it. If an iterator wishes to provide a mechanism for modifying +a sequence during iteration, the usual approach is to define a position type +with the extra operations and then provide an iterator over positions. + +For example, a tree implementation might provide: + + // Positions returns an iterator over positions in the sequence. + func (t *Tree[V]) Positions() iter.Seq[*Pos] + + // A Pos represents a position in the sequence. + // It is only valid during the yield call it is passed to. + type Pos[V any] struct { ... } + + // Pos returns the value at the cursor. + func (p *Pos[V]) Value() V + + // Delete deletes the value at this point in the iteration. + func (p *Pos[V]) Delete() + + // Set changes the value v at the cursor. + func (p *Pos[V]) Set(v V) + +And then a client could delete boring values from the tree using: + + for p := range t.Positions() { + if boring(p.Value()) { + p.Delete() + } + } +*/ +package iter + +import ( + "internal/race" + "runtime" + "unsafe" +) + +// Seq is an iterator over sequences of individual values. +// When called as seq(yield), seq calls yield(v) for each value v in the sequence, +// stopping early if yield returns false. +// See the [iter] package documentation for more details. +type Seq[V any] func(yield func(V) bool) + +// Seq2 is an iterator over sequences of pairs of values, most commonly key-value pairs. +// When called as seq(yield), seq calls yield(k, v) for each pair (k, v) in the sequence, +// stopping early if yield returns false. +// See the [iter] package documentation for more details. +type Seq2[K, V any] func(yield func(K, V) bool) + +type coro struct{} + +//go:linkname newcoro runtime.newcoro +func newcoro(func(*coro)) *coro + +//go:linkname coroswitch runtime.coroswitch +func coroswitch(*coro) + +// Pull converts the “push-style” iterator sequence seq +// into a “pull-style” iterator accessed by the two functions +// next and stop. +// +// Next returns the next value in the sequence +// and a boolean indicating whether the value is valid. +// When the sequence is over, next returns the zero V and false. +// It is valid to call next after reaching the end of the sequence +// or after calling stop. These calls will continue +// to return the zero V and false. +// +// Stop ends the iteration. It must be called when the caller is +// no longer interested in next values and next has not yet +// signaled that the sequence is over (with a false boolean return). +// It is valid to call stop multiple times and when next has +// already returned false. Typically, callers should “defer stop()”. +// +// It is an error to call next or stop from multiple goroutines +// simultaneously. +// +// If the iterator panics during a call to next (or stop), +// then next (or stop) itself panics with the same value. +func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func()) { + var ( + v V + ok bool + done bool + yieldNext bool + racer int + panicValue any + seqDone bool // to detect Goexit + ) + c := newcoro(func(c *coro) { + race.Acquire(unsafe.Pointer(&racer)) + if done { + race.Release(unsafe.Pointer(&racer)) + return + } + yield := func(v1 V) bool { + if done { + return false + } + if !yieldNext { + panic("iter.Pull: yield called again before next") + } + yieldNext = false + v, ok = v1, true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + return !done + } + // Recover and propagate panics from seq. + defer func() { + if p := recover(); p != nil { + panicValue = p + } else if !seqDone { + panicValue = goexitPanicValue + } + done = true // Invalidate iterator + race.Release(unsafe.Pointer(&racer)) + }() + seq(yield) + var v0 V + v, ok = v0, false + seqDone = true + }) + next = func() (v1 V, ok1 bool) { + race.Write(unsafe.Pointer(&racer)) // detect races + + if done { + return + } + if yieldNext { + panic("iter.Pull: next called again before yield") + } + yieldNext = true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + + // Propagate panics and goexits from seq. + if panicValue != nil { + if panicValue == goexitPanicValue { + // Propagate runtime.Goexit from seq. + runtime.Goexit() + } else { + panic(panicValue) + } + } + return v, ok + } + stop = func() { + race.Write(unsafe.Pointer(&racer)) // detect races + + if !done { + done = true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + + // Propagate panics and goexits from seq. + if panicValue != nil { + if panicValue == goexitPanicValue { + // Propagate runtime.Goexit from seq. + runtime.Goexit() + } else { + panic(panicValue) + } + } + } + } + return next, stop +} + +// Pull2 converts the “push-style” iterator sequence seq +// into a “pull-style” iterator accessed by the two functions +// next and stop. +// +// Next returns the next pair in the sequence +// and a boolean indicating whether the pair is valid. +// When the sequence is over, next returns a pair of zero values and false. +// It is valid to call next after reaching the end of the sequence +// or after calling stop. These calls will continue +// to return a pair of zero values and false. +// +// Stop ends the iteration. It must be called when the caller is +// no longer interested in next values and next has not yet +// signaled that the sequence is over (with a false boolean return). +// It is valid to call stop multiple times and when next has +// already returned false. Typically, callers should “defer stop()”. +// +// It is an error to call next or stop from multiple goroutines +// simultaneously. +// +// If the iterator panics during a call to next (or stop), +// then next (or stop) itself panics with the same value. +func Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func()) { + var ( + k K + v V + ok bool + done bool + yieldNext bool + racer int + panicValue any + seqDone bool + ) + c := newcoro(func(c *coro) { + race.Acquire(unsafe.Pointer(&racer)) + if done { + race.Release(unsafe.Pointer(&racer)) + return + } + yield := func(k1 K, v1 V) bool { + if done { + return false + } + if !yieldNext { + panic("iter.Pull2: yield called again before next") + } + yieldNext = false + k, v, ok = k1, v1, true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + return !done + } + // Recover and propagate panics from seq. + defer func() { + if p := recover(); p != nil { + panicValue = p + } else if !seqDone { + panicValue = goexitPanicValue + } + done = true // Invalidate iterator. + race.Release(unsafe.Pointer(&racer)) + }() + seq(yield) + var k0 K + var v0 V + k, v, ok = k0, v0, false + seqDone = true + }) + next = func() (k1 K, v1 V, ok1 bool) { + race.Write(unsafe.Pointer(&racer)) // detect races + + if done { + return + } + if yieldNext { + panic("iter.Pull2: next called again before yield") + } + yieldNext = true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + + // Propagate panics and goexits from seq. + if panicValue != nil { + if panicValue == goexitPanicValue { + // Propagate runtime.Goexit from seq. + runtime.Goexit() + } else { + panic(panicValue) + } + } + return k, v, ok + } + stop = func() { + race.Write(unsafe.Pointer(&racer)) // detect races + + if !done { + done = true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + + // Propagate panics and goexits from seq. + if panicValue != nil { + if panicValue == goexitPanicValue { + // Propagate runtime.Goexit from seq. + runtime.Goexit() + } else { + panic(panicValue) + } + } + } + } + return next, stop +} + +// goexitPanicValue is a sentinel value indicating that an iterator +// exited via runtime.Goexit. +var goexitPanicValue any = new(int) diff --git a/contrib/go/_std_1.23/src/iter/ya.make b/contrib/go/_std_1.23/src/iter/ya.make new file mode 100644 index 000000000000..620cac6c9345 --- /dev/null +++ b/contrib/go/_std_1.23/src/iter/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + iter.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/log/internal/internal.go b/contrib/go/_std_1.23/src/log/internal/internal.go similarity index 100% rename from contrib/go/_std_1.22/src/log/internal/internal.go rename to contrib/go/_std_1.23/src/log/internal/internal.go diff --git a/contrib/go/_std_1.22/src/log/internal/ya.make b/contrib/go/_std_1.23/src/log/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/internal/ya.make rename to contrib/go/_std_1.23/src/log/internal/ya.make diff --git a/contrib/go/_std_1.22/src/log/log.go b/contrib/go/_std_1.23/src/log/log.go similarity index 100% rename from contrib/go/_std_1.22/src/log/log.go rename to contrib/go/_std_1.23/src/log/log.go diff --git a/contrib/go/_std_1.22/src/log/slog/attr.go b/contrib/go/_std_1.23/src/log/slog/attr.go similarity index 97% rename from contrib/go/_std_1.22/src/log/slog/attr.go rename to contrib/go/_std_1.23/src/log/slog/attr.go index 2f459467cb6f..067c537cc973 100644 --- a/contrib/go/_std_1.22/src/log/slog/attr.go +++ b/contrib/go/_std_1.23/src/log/slog/attr.go @@ -5,7 +5,6 @@ package slog import ( - "fmt" "time" ) @@ -92,7 +91,7 @@ func (a Attr) Equal(b Attr) bool { } func (a Attr) String() string { - return fmt.Sprintf("%s=%s", a.Key, a.Value) + return a.Key + "=" + a.Value.String() } // isEmpty reports whether a has an empty key and a nil value. diff --git a/contrib/go/_std_1.23/src/log/slog/doc.go b/contrib/go/_std_1.23/src/log/slog/doc.go new file mode 100644 index 000000000000..cc034ca4b976 --- /dev/null +++ b/contrib/go/_std_1.23/src/log/slog/doc.go @@ -0,0 +1,322 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package slog provides structured logging, +in which log records include a message, +a severity level, and various other attributes +expressed as key-value pairs. + +It defines a type, [Logger], +which provides several methods (such as [Logger.Info] and [Logger.Error]) +for reporting events of interest. + +Each Logger is associated with a [Handler]. +A Logger output method creates a [Record] from the method arguments +and passes it to the Handler, which decides how to handle it. +There is a default Logger accessible through top-level functions +(such as [Info] and [Error]) that call the corresponding Logger methods. + +A log record consists of a time, a level, a message, and a set of key-value +pairs, where the keys are strings and the values may be of any type. +As an example, + + slog.Info("hello", "count", 3) + +creates a record containing the time of the call, +a level of Info, the message "hello", and a single +pair with key "count" and value 3. + +The [Info] top-level function calls the [Logger.Info] method on the default Logger. +In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. +Besides these convenience methods for common levels, +there is also a [Logger.Log] method which takes the level as an argument. +Each of these methods has a corresponding top-level function that uses the +default logger. + +The default handler formats the log record's message, time, level, and attributes +as a string and passes it to the [log] package. + + 2022/11/08 15:28:26 INFO hello count=3 + +For more control over the output format, create a logger with a different handler. +This statement uses [New] to create a new logger with a [TextHandler] +that writes structured records in text form to standard error: + + logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) + +[TextHandler] output is a sequence of key=value pairs, easily and unambiguously +parsed by machine. This statement: + + logger.Info("hello", "count", 3) + +produces this output: + + time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 + +The package also provides [JSONHandler], whose output is line-delimited JSON: + + logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + logger.Info("hello", "count", 3) + +produces this output: + + {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} + +Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. +There are options for setting the minimum level (see Levels, below), +displaying the source file and line of the log call, and +modifying attributes before they are logged. + +Setting a logger as the default with + + slog.SetDefault(logger) + +will cause the top-level functions like [Info] to use it. +[SetDefault] also updates the default logger used by the [log] package, +so that existing applications that use [log.Printf] and related functions +will send log records to the logger's handler without needing to be rewritten. + +Some attributes are common to many log calls. +For example, you may wish to include the URL or trace identifier of a server request +with all log events arising from the request. +Rather than repeat the attribute with every log call, you can use [Logger.With] +to construct a new Logger containing the attributes: + + logger2 := logger.With("url", r.URL) + +The arguments to With are the same key-value pairs used in [Logger.Info]. +The result is a new Logger with the same handler as the original, but additional +attributes that will appear in the output of every call. + +# Levels + +A [Level] is an integer representing the importance or severity of a log event. +The higher the level, the more severe the event. +This package defines constants for the most common levels, +but any int can be used as a level. + +In an application, you may wish to log messages only at a certain level or greater. +One common configuration is to log messages at Info or higher levels, +suppressing debug logging until it is needed. +The built-in handlers can be configured with the minimum level to output by +setting [HandlerOptions.Level]. +The program's `main` function typically does this. +The default value is LevelInfo. + +Setting the [HandlerOptions.Level] field to a [Level] value +fixes the handler's minimum level throughout its lifetime. +Setting it to a [LevelVar] allows the level to be varied dynamically. +A LevelVar holds a Level and is safe to read or write from multiple +goroutines. +To vary the level dynamically for an entire program, first initialize +a global LevelVar: + + var programLevel = new(slog.LevelVar) // Info by default + +Then use the LevelVar to construct a handler, and make it the default: + + h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) + slog.SetDefault(slog.New(h)) + +Now the program can change its logging level with a single statement: + + programLevel.Set(slog.LevelDebug) + +# Groups + +Attributes can be collected into groups. +A group has a name that is used to qualify the names of its attributes. +How this qualification is displayed depends on the handler. +[TextHandler] separates the group and attribute names with a dot. +[JSONHandler] treats each group as a separate JSON object, with the group name as the key. + +Use [Group] to create a Group attribute from a name and a list of key-value pairs: + + slog.Group("request", + "method", r.Method, + "url", r.URL) + +TextHandler would display this group as + + request.method=GET request.url=http://example.com + +JSONHandler would display it as + + "request":{"method":"GET","url":"http://example.com"} + +Use [Logger.WithGroup] to qualify all of a Logger's output +with a group name. Calling WithGroup on a Logger results in a +new Logger with the same Handler as the original, but with all +its attributes qualified by the group name. + +This can help prevent duplicate attribute keys in large systems, +where subsystems might use the same keys. +Pass each subsystem a different Logger with its own group name so that +potential duplicates are qualified: + + logger := slog.Default().With("id", systemID) + parserLogger := logger.WithGroup("parser") + parseInput(input, parserLogger) + +When parseInput logs with parserLogger, its keys will be qualified with "parser", +so even if it uses the common key "id", the log line will have distinct keys. + +# Contexts + +Some handlers may wish to include information from the [context.Context] that is +available at the call site. One example of such information +is the identifier for the current span when tracing is enabled. + +The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first +argument, as do their corresponding top-level functions. + +Although the convenience methods on Logger (Info and so on) and the +corresponding top-level functions do not take a context, the alternatives ending +in "Context" do. For example, + + slog.InfoContext(ctx, "message") + +It is recommended to pass a context to an output method if one is available. + +# Attrs and Values + +An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as +alternating keys and values. The statement + + slog.Info("hello", slog.Int("count", 3)) + +behaves the same as + + slog.Info("hello", "count", 3) + +There are convenience constructors for [Attr] such as [Int], [String], and [Bool] +for common types, as well as the function [Any] for constructing Attrs of any +type. + +The value part of an Attr is a type called [Value]. +Like an [any], a Value can hold any Go value, +but it can represent typical values, including all numbers and strings, +without an allocation. + +For the most efficient log output, use [Logger.LogAttrs]. +It is similar to [Logger.Log] but accepts only Attrs, not alternating +keys and values; this allows it, too, to avoid allocation. + +The call + + logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) + +is the most efficient way to achieve the same output as + + slog.InfoContext(ctx, "hello", "count", 3) + +# Customizing a type's logging behavior + +If a type implements the [LogValuer] interface, the [Value] returned from its LogValue +method is used for logging. You can use this to control how values of the type +appear in logs. For example, you can redact secret information like passwords, +or gather a struct's fields in a Group. See the examples under [LogValuer] for +details. + +A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] +method handles these cases carefully, avoiding infinite loops and unbounded recursion. +Handler authors and others may wish to use [Value.Resolve] instead of calling LogValue directly. + +# Wrapping output methods + +The logger functions use reflection over the call stack to find the file name +and line number of the logging call within the application. This can produce +incorrect source information for functions that wrap slog. For instance, if you +define this function in file mylog.go: + + func Infof(logger *slog.Logger, format string, args ...any) { + logger.Info(fmt.Sprintf(format, args...)) + } + +and you call it like this in main.go: + + Infof(slog.Default(), "hello, %s", "world") + +then slog will report the source file as mylog.go, not main.go. + +A correct implementation of Infof will obtain the source location +(pc) and pass it to NewRecord. +The Infof function in the package-level example called "wrapping" +demonstrates how to do this. + +# Working with Records + +Sometimes a Handler will need to modify a Record +before passing it on to another Handler or backend. +A Record contains a mixture of simple public fields (e.g. Time, Level, Message) +and hidden fields that refer to state (such as attributes) indirectly. This +means that modifying a simple copy of a Record (e.g. by calling +[Record.Add] or [Record.AddAttrs] to add attributes) +may have unexpected effects on the original. +Before modifying a Record, use [Record.Clone] to +create a copy that shares no state with the original, +or create a new Record with [NewRecord] +and build up its Attrs by traversing the old ones with [Record.Attrs]. + +# Performance considerations + +If profiling your application demonstrates that logging is taking significant time, +the following suggestions may help. + +If many log lines have a common attribute, use [Logger.With] to create a Logger with +that attribute. The built-in handlers will format that attribute only once, at the +call to [Logger.With]. The [Handler] interface is designed to allow that optimization, +and a well-written Handler should take advantage of it. + +The arguments to a log call are always evaluated, even if the log event is discarded. +If possible, defer computation so that it happens only if the value is actually logged. +For example, consider the call + + slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily + +The URL.String method will be called even if the logger discards Info-level events. +Instead, pass the URL directly: + + slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed + +The built-in [TextHandler] will call its String method, but only +if the log event is enabled. +Avoiding the call to String also preserves the structure of the underlying value. +For example [JSONHandler] emits the components of the parsed URL as a JSON object. +If you want to avoid eagerly paying the cost of the String call +without causing the handler to potentially inspect the structure of the value, +wrap the value in a fmt.Stringer implementation that hides its Marshal methods. + +You can also use the [LogValuer] interface to avoid unnecessary work in disabled log +calls. Say you need to log some expensive value: + + slog.Debug("frobbing", "value", computeExpensiveValue(arg)) + +Even if this line is disabled, computeExpensiveValue will be called. +To avoid that, define a type implementing LogValuer: + + type expensive struct { arg int } + + func (e expensive) LogValue() slog.Value { + return slog.AnyValue(computeExpensiveValue(e.arg)) + } + +Then use a value of that type in log calls: + + slog.Debug("frobbing", "value", expensive{arg}) + +Now computeExpensiveValue will only be called when the line is enabled. + +The built-in handlers acquire a lock before calling [io.Writer.Write] +to ensure that exactly one [Record] is written at a time in its entirety. +Although each log record has a timestamp, +the built-in handlers do not use that time to sort the written records. +User-defined handlers are responsible for their own locking and sorting. + +# Writing a handler + +For a guide to writing a custom handler, see https://golang.org/s/slog-handler-guide. +*/ +package slog diff --git a/contrib/go/_std_1.22/src/log/slog/handler.go b/contrib/go/_std_1.23/src/log/slog/handler.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/handler.go rename to contrib/go/_std_1.23/src/log/slog/handler.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/benchmarks/benchmarks.go b/contrib/go/_std_1.23/src/log/slog/internal/benchmarks/benchmarks.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/benchmarks/benchmarks.go rename to contrib/go/_std_1.23/src/log/slog/internal/benchmarks/benchmarks.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/benchmarks/handlers.go b/contrib/go/_std_1.23/src/log/slog/internal/benchmarks/handlers.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/benchmarks/handlers.go rename to contrib/go/_std_1.23/src/log/slog/internal/benchmarks/handlers.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/benchmarks/ya.make b/contrib/go/_std_1.23/src/log/slog/internal/benchmarks/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/benchmarks/ya.make rename to contrib/go/_std_1.23/src/log/slog/internal/benchmarks/ya.make diff --git a/contrib/go/_std_1.23/src/log/slog/internal/buffer/buffer.go b/contrib/go/_std_1.23/src/log/slog/internal/buffer/buffer.go new file mode 100644 index 000000000000..110c6281ab29 --- /dev/null +++ b/contrib/go/_std_1.23/src/log/slog/internal/buffer/buffer.go @@ -0,0 +1,66 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package buffer provides a pool-allocated byte buffer. +package buffer + +import "sync" + +// Buffer is a byte buffer. +// +// This implementation is adapted from the unexported type buffer +// in go/src/fmt/print.go. +type Buffer []byte + +// Having an initial size gives a dramatic speedup. +var bufPool = sync.Pool{ + New: func() any { + b := make([]byte, 0, 1024) + return (*Buffer)(&b) + }, +} + +func New() *Buffer { + return bufPool.Get().(*Buffer) +} + +func (b *Buffer) Free() { + // To reduce peak allocation, return only smaller buffers to the pool. + const maxBufferSize = 16 << 10 + if cap(*b) <= maxBufferSize { + *b = (*b)[:0] + bufPool.Put(b) + } +} + +func (b *Buffer) Reset() { + b.SetLen(0) +} + +func (b *Buffer) Write(p []byte) (int, error) { + *b = append(*b, p...) + return len(p), nil +} + +func (b *Buffer) WriteString(s string) (int, error) { + *b = append(*b, s...) + return len(s), nil +} + +func (b *Buffer) WriteByte(c byte) error { + *b = append(*b, c) + return nil +} + +func (b *Buffer) String() string { + return string(*b) +} + +func (b *Buffer) Len() int { + return len(*b) +} + +func (b *Buffer) SetLen(n int) { + *b = (*b)[:n] +} diff --git a/contrib/go/_std_1.22/src/log/slog/internal/buffer/ya.make b/contrib/go/_std_1.23/src/log/slog/internal/buffer/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/buffer/ya.make rename to contrib/go/_std_1.23/src/log/slog/internal/buffer/ya.make diff --git a/contrib/go/_std_1.22/src/log/slog/internal/ignorepc.go b/contrib/go/_std_1.23/src/log/slog/internal/ignorepc.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/ignorepc.go rename to contrib/go/_std_1.23/src/log/slog/internal/ignorepc.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/slogtest/slogtest.go b/contrib/go/_std_1.23/src/log/slog/internal/slogtest/slogtest.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/slogtest/slogtest.go rename to contrib/go/_std_1.23/src/log/slog/internal/slogtest/slogtest.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/slogtest/ya.make b/contrib/go/_std_1.23/src/log/slog/internal/slogtest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/slogtest/ya.make rename to contrib/go/_std_1.23/src/log/slog/internal/slogtest/ya.make diff --git a/contrib/go/_std_1.22/src/log/slog/internal/ya.make b/contrib/go/_std_1.23/src/log/slog/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/ya.make rename to contrib/go/_std_1.23/src/log/slog/internal/ya.make diff --git a/contrib/go/_std_1.22/src/log/slog/json_handler.go b/contrib/go/_std_1.23/src/log/slog/json_handler.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/json_handler.go rename to contrib/go/_std_1.23/src/log/slog/json_handler.go diff --git a/contrib/go/_std_1.22/src/log/slog/level.go b/contrib/go/_std_1.23/src/log/slog/level.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/level.go rename to contrib/go/_std_1.23/src/log/slog/level.go diff --git a/contrib/go/_std_1.22/src/log/slog/logger.go b/contrib/go/_std_1.23/src/log/slog/logger.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/logger.go rename to contrib/go/_std_1.23/src/log/slog/logger.go diff --git a/contrib/go/_std_1.22/src/log/slog/record.go b/contrib/go/_std_1.23/src/log/slog/record.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/record.go rename to contrib/go/_std_1.23/src/log/slog/record.go diff --git a/contrib/go/_std_1.22/src/log/slog/text_handler.go b/contrib/go/_std_1.23/src/log/slog/text_handler.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/text_handler.go rename to contrib/go/_std_1.23/src/log/slog/text_handler.go diff --git a/contrib/go/_std_1.23/src/log/slog/value.go b/contrib/go/_std_1.23/src/log/slog/value.go new file mode 100644 index 000000000000..6b0768eb1dea --- /dev/null +++ b/contrib/go/_std_1.23/src/log/slog/value.go @@ -0,0 +1,540 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package slog + +import ( + "fmt" + "math" + "runtime" + "slices" + "strconv" + "strings" + "time" + "unsafe" +) + +// A Value can represent any Go value, but unlike type any, +// it can represent most small values without an allocation. +// The zero Value corresponds to nil. +type Value struct { + _ [0]func() // disallow == + // num holds the value for Kinds Int64, Uint64, Float64, Bool and Duration, + // the string length for KindString, and nanoseconds since the epoch for KindTime. + num uint64 + // If any is of type Kind, then the value is in num as described above. + // If any is of type *time.Location, then the Kind is Time and time.Time value + // can be constructed from the Unix nanos in num and the location (monotonic time + // is not preserved). + // If any is of type stringptr, then the Kind is String and the string value + // consists of the length in num and the pointer in any. + // Otherwise, the Kind is Any and any is the value. + // (This implies that Attrs cannot store values of type Kind, *time.Location + // or stringptr.) + any any +} + +type ( + stringptr *byte // used in Value.any when the Value is a string + groupptr *Attr // used in Value.any when the Value is a []Attr +) + +// Kind is the kind of a [Value]. +type Kind int + +// The following list is sorted alphabetically, but it's also important that +// KindAny is 0 so that a zero Value represents nil. + +const ( + KindAny Kind = iota + KindBool + KindDuration + KindFloat64 + KindInt64 + KindString + KindTime + KindUint64 + KindGroup + KindLogValuer +) + +var kindStrings = []string{ + "Any", + "Bool", + "Duration", + "Float64", + "Int64", + "String", + "Time", + "Uint64", + "Group", + "LogValuer", +} + +func (k Kind) String() string { + if k >= 0 && int(k) < len(kindStrings) { + return kindStrings[k] + } + return "" +} + +// Unexported version of Kind, just so we can store Kinds in Values. +// (No user-provided value has this type.) +type kind Kind + +// Kind returns v's Kind. +func (v Value) Kind() Kind { + switch x := v.any.(type) { + case Kind: + return x + case stringptr: + return KindString + case timeLocation, timeTime: + return KindTime + case groupptr: + return KindGroup + case LogValuer: + return KindLogValuer + case kind: // a kind is just a wrapper for a Kind + return KindAny + default: + return KindAny + } +} + +//////////////// Constructors + +// StringValue returns a new [Value] for a string. +func StringValue(value string) Value { + return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))} +} + +// IntValue returns a [Value] for an int. +func IntValue(v int) Value { + return Int64Value(int64(v)) +} + +// Int64Value returns a [Value] for an int64. +func Int64Value(v int64) Value { + return Value{num: uint64(v), any: KindInt64} +} + +// Uint64Value returns a [Value] for a uint64. +func Uint64Value(v uint64) Value { + return Value{num: v, any: KindUint64} +} + +// Float64Value returns a [Value] for a floating-point number. +func Float64Value(v float64) Value { + return Value{num: math.Float64bits(v), any: KindFloat64} +} + +// BoolValue returns a [Value] for a bool. +func BoolValue(v bool) Value { + u := uint64(0) + if v { + u = 1 + } + return Value{num: u, any: KindBool} +} + +type ( + // Unexported version of *time.Location, just so we can store *time.Locations in + // Values. (No user-provided value has this type.) + timeLocation *time.Location + + // timeTime is for times where UnixNano is undefined. + timeTime time.Time +) + +// TimeValue returns a [Value] for a [time.Time]. +// It discards the monotonic portion. +func TimeValue(v time.Time) Value { + if v.IsZero() { + // UnixNano on the zero time is undefined, so represent the zero time + // with a nil *time.Location instead. time.Time.Location method never + // returns nil, so a Value with any == timeLocation(nil) cannot be + // mistaken for any other Value, time.Time or otherwise. + return Value{any: timeLocation(nil)} + } + nsec := v.UnixNano() + t := time.Unix(0, nsec) + if v.Equal(t) { + // UnixNano correctly represents the time, so use a zero-alloc representation. + return Value{num: uint64(nsec), any: timeLocation(v.Location())} + } + // Fall back to the general form. + // Strip the monotonic portion to match the other representation. + return Value{any: timeTime(v.Round(0))} +} + +// DurationValue returns a [Value] for a [time.Duration]. +func DurationValue(v time.Duration) Value { + return Value{num: uint64(v.Nanoseconds()), any: KindDuration} +} + +// GroupValue returns a new [Value] for a list of Attrs. +// The caller must not subsequently mutate the argument slice. +func GroupValue(as ...Attr) Value { + // Remove empty groups. + // It is simpler overall to do this at construction than + // to check each Group recursively for emptiness. + if n := countEmptyGroups(as); n > 0 { + as2 := make([]Attr, 0, len(as)-n) + for _, a := range as { + if !a.Value.isEmptyGroup() { + as2 = append(as2, a) + } + } + as = as2 + } + return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))} +} + +// countEmptyGroups returns the number of empty group values in its argument. +func countEmptyGroups(as []Attr) int { + n := 0 + for _, a := range as { + if a.Value.isEmptyGroup() { + n++ + } + } + return n +} + +// AnyValue returns a [Value] for the supplied value. +// +// If the supplied value is of type Value, it is returned +// unmodified. +// +// Given a value of one of Go's predeclared string, bool, or +// (non-complex) numeric types, AnyValue returns a Value of kind +// [KindString], [KindBool], [KindUint64], [KindInt64], or [KindFloat64]. +// The width of the original numeric type is not preserved. +// +// Given a [time.Time] or [time.Duration] value, AnyValue returns a Value of kind +// [KindTime] or [KindDuration]. The monotonic time is not preserved. +// +// For nil, or values of all other types, including named types whose +// underlying type is numeric, AnyValue returns a value of kind [KindAny]. +func AnyValue(v any) Value { + switch v := v.(type) { + case string: + return StringValue(v) + case int: + return Int64Value(int64(v)) + case uint: + return Uint64Value(uint64(v)) + case int64: + return Int64Value(v) + case uint64: + return Uint64Value(v) + case bool: + return BoolValue(v) + case time.Duration: + return DurationValue(v) + case time.Time: + return TimeValue(v) + case uint8: + return Uint64Value(uint64(v)) + case uint16: + return Uint64Value(uint64(v)) + case uint32: + return Uint64Value(uint64(v)) + case uintptr: + return Uint64Value(uint64(v)) + case int8: + return Int64Value(int64(v)) + case int16: + return Int64Value(int64(v)) + case int32: + return Int64Value(int64(v)) + case float64: + return Float64Value(v) + case float32: + return Float64Value(float64(v)) + case []Attr: + return GroupValue(v...) + case Kind: + return Value{any: kind(v)} + case Value: + return v + default: + return Value{any: v} + } +} + +//////////////// Accessors + +// Any returns v's value as an any. +func (v Value) Any() any { + switch v.Kind() { + case KindAny: + if k, ok := v.any.(kind); ok { + return Kind(k) + } + return v.any + case KindLogValuer: + return v.any + case KindGroup: + return v.group() + case KindInt64: + return int64(v.num) + case KindUint64: + return v.num + case KindFloat64: + return v.float() + case KindString: + return v.str() + case KindBool: + return v.bool() + case KindDuration: + return v.duration() + case KindTime: + return v.time() + default: + panic(fmt.Sprintf("bad kind: %s", v.Kind())) + } +} + +// String returns Value's value as a string, formatted like [fmt.Sprint]. Unlike +// the methods Int64, Float64, and so on, which panic if v is of the +// wrong kind, String never panics. +func (v Value) String() string { + if sp, ok := v.any.(stringptr); ok { + return unsafe.String(sp, v.num) + } + var buf []byte + return string(v.append(buf)) +} + +func (v Value) str() string { + return unsafe.String(v.any.(stringptr), v.num) +} + +// Int64 returns v's value as an int64. It panics +// if v is not a signed integer. +func (v Value) Int64() int64 { + if g, w := v.Kind(), KindInt64; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + return int64(v.num) +} + +// Uint64 returns v's value as a uint64. It panics +// if v is not an unsigned integer. +func (v Value) Uint64() uint64 { + if g, w := v.Kind(), KindUint64; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + return v.num +} + +// Bool returns v's value as a bool. It panics +// if v is not a bool. +func (v Value) Bool() bool { + if g, w := v.Kind(), KindBool; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + return v.bool() +} + +func (v Value) bool() bool { + return v.num == 1 +} + +// Duration returns v's value as a [time.Duration]. It panics +// if v is not a time.Duration. +func (v Value) Duration() time.Duration { + if g, w := v.Kind(), KindDuration; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + + return v.duration() +} + +func (v Value) duration() time.Duration { + return time.Duration(int64(v.num)) +} + +// Float64 returns v's value as a float64. It panics +// if v is not a float64. +func (v Value) Float64() float64 { + if g, w := v.Kind(), KindFloat64; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + + return v.float() +} + +func (v Value) float() float64 { + return math.Float64frombits(v.num) +} + +// Time returns v's value as a [time.Time]. It panics +// if v is not a time.Time. +func (v Value) Time() time.Time { + if g, w := v.Kind(), KindTime; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + return v.time() +} + +// See TimeValue to understand how times are represented. +func (v Value) time() time.Time { + switch a := v.any.(type) { + case timeLocation: + if a == nil { + return time.Time{} + } + return time.Unix(0, int64(v.num)).In(a) + case timeTime: + return time.Time(a) + default: + panic(fmt.Sprintf("bad time type %T", v.any)) + } +} + +// LogValuer returns v's value as a LogValuer. It panics +// if v is not a LogValuer. +func (v Value) LogValuer() LogValuer { + return v.any.(LogValuer) +} + +// Group returns v's value as a []Attr. +// It panics if v's [Kind] is not [KindGroup]. +func (v Value) Group() []Attr { + if sp, ok := v.any.(groupptr); ok { + return unsafe.Slice((*Attr)(sp), v.num) + } + panic("Group: bad kind") +} + +func (v Value) group() []Attr { + return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num) +} + +//////////////// Other + +// Equal reports whether v and w represent the same Go value. +func (v Value) Equal(w Value) bool { + k1 := v.Kind() + k2 := w.Kind() + if k1 != k2 { + return false + } + switch k1 { + case KindInt64, KindUint64, KindBool, KindDuration: + return v.num == w.num + case KindString: + return v.str() == w.str() + case KindFloat64: + return v.float() == w.float() + case KindTime: + return v.time().Equal(w.time()) + case KindAny, KindLogValuer: + return v.any == w.any // may panic if non-comparable + case KindGroup: + return slices.EqualFunc(v.group(), w.group(), Attr.Equal) + default: + panic(fmt.Sprintf("bad kind: %s", k1)) + } +} + +// isEmptyGroup reports whether v is a group that has no attributes. +func (v Value) isEmptyGroup() bool { + if v.Kind() != KindGroup { + return false + } + // We do not need to recursively examine the group's Attrs for emptiness, + // because GroupValue removed them when the group was constructed, and + // groups are immutable. + return len(v.group()) == 0 +} + +// append appends a text representation of v to dst. +// v is formatted as with fmt.Sprint. +func (v Value) append(dst []byte) []byte { + switch v.Kind() { + case KindString: + return append(dst, v.str()...) + case KindInt64: + return strconv.AppendInt(dst, int64(v.num), 10) + case KindUint64: + return strconv.AppendUint(dst, v.num, 10) + case KindFloat64: + return strconv.AppendFloat(dst, v.float(), 'g', -1, 64) + case KindBool: + return strconv.AppendBool(dst, v.bool()) + case KindDuration: + return append(dst, v.duration().String()...) + case KindTime: + return append(dst, v.time().String()...) + case KindGroup: + return fmt.Append(dst, v.group()) + case KindAny, KindLogValuer: + return fmt.Append(dst, v.any) + default: + panic(fmt.Sprintf("bad kind: %s", v.Kind())) + } +} + +// A LogValuer is any Go value that can convert itself into a Value for logging. +// +// This mechanism may be used to defer expensive operations until they are +// needed, or to expand a single value into a sequence of components. +type LogValuer interface { + LogValue() Value +} + +const maxLogValues = 100 + +// Resolve repeatedly calls LogValue on v while it implements [LogValuer], +// and returns the result. +// If v resolves to a group, the group's attributes' values are not recursively +// resolved. +// If the number of LogValue calls exceeds a threshold, a Value containing an +// error is returned. +// Resolve's return value is guaranteed not to be of Kind [KindLogValuer]. +func (v Value) Resolve() (rv Value) { + orig := v + defer func() { + if r := recover(); r != nil { + rv = AnyValue(fmt.Errorf("LogValue panicked\n%s", stack(3, 5))) + } + }() + + for i := 0; i < maxLogValues; i++ { + if v.Kind() != KindLogValuer { + return v + } + v = v.LogValuer().LogValue() + } + err := fmt.Errorf("LogValue called too many times on Value of type %T", orig.Any()) + return AnyValue(err) +} + +func stack(skip, nFrames int) string { + pcs := make([]uintptr, nFrames+1) + n := runtime.Callers(skip+1, pcs) + if n == 0 { + return "(no stack)" + } + frames := runtime.CallersFrames(pcs[:n]) + var b strings.Builder + i := 0 + for { + frame, more := frames.Next() + fmt.Fprintf(&b, "called from %s (%s:%d)\n", frame.Function, frame.File, frame.Line) + if !more { + break + } + i++ + if i >= nFrames { + fmt.Fprintf(&b, "(rest of stack elided)\n") + break + } + } + return b.String() +} diff --git a/contrib/go/_std_1.22/src/log/slog/ya.make b/contrib/go/_std_1.23/src/log/slog/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/ya.make rename to contrib/go/_std_1.23/src/log/slog/ya.make diff --git a/contrib/go/_std_1.22/src/log/syslog/doc.go b/contrib/go/_std_1.23/src/log/syslog/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/log/syslog/doc.go rename to contrib/go/_std_1.23/src/log/syslog/doc.go diff --git a/contrib/go/_std_1.22/src/log/syslog/syslog.go b/contrib/go/_std_1.23/src/log/syslog/syslog.go similarity index 100% rename from contrib/go/_std_1.22/src/log/syslog/syslog.go rename to contrib/go/_std_1.23/src/log/syslog/syslog.go diff --git a/contrib/go/_std_1.22/src/log/syslog/syslog_unix.go b/contrib/go/_std_1.23/src/log/syslog/syslog_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/log/syslog/syslog_unix.go rename to contrib/go/_std_1.23/src/log/syslog/syslog_unix.go diff --git a/contrib/go/_std_1.23/src/log/syslog/ya.make b/contrib/go/_std_1.23/src/log/syslog/ya.make new file mode 100644 index 000000000000..ab8411fee7ce --- /dev/null +++ b/contrib/go/_std_1.23/src/log/syslog/ya.make @@ -0,0 +1,15 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + syslog.go + syslog_unix.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/log/ya.make b/contrib/go/_std_1.23/src/log/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/ya.make rename to contrib/go/_std_1.23/src/log/ya.make diff --git a/contrib/go/_std_1.23/src/maps/iter.go b/contrib/go/_std_1.23/src/maps/iter.go new file mode 100644 index 000000000000..32f2d514c150 --- /dev/null +++ b/contrib/go/_std_1.23/src/maps/iter.go @@ -0,0 +1,62 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package maps + +import "iter" + +// All returns an iterator over key-value pairs from m. +// The iteration order is not specified and is not guaranteed +// to be the same from one call to the next. +func All[Map ~map[K]V, K comparable, V any](m Map) iter.Seq2[K, V] { + return func(yield func(K, V) bool) { + for k, v := range m { + if !yield(k, v) { + return + } + } + } +} + +// Keys returns an iterator over keys in m. +// The iteration order is not specified and is not guaranteed +// to be the same from one call to the next. +func Keys[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[K] { + return func(yield func(K) bool) { + for k := range m { + if !yield(k) { + return + } + } + } +} + +// Values returns an iterator over values in m. +// The iteration order is not specified and is not guaranteed +// to be the same from one call to the next. +func Values[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[V] { + return func(yield func(V) bool) { + for _, v := range m { + if !yield(v) { + return + } + } + } +} + +// Insert adds the key-value pairs from seq to m. +// If a key in seq already exists in m, its value will be overwritten. +func Insert[Map ~map[K]V, K comparable, V any](m Map, seq iter.Seq2[K, V]) { + for k, v := range seq { + m[k] = v + } +} + +// Collect collects key-value pairs from seq into a new map +// and returns it. +func Collect[K comparable, V any](seq iter.Seq2[K, V]) map[K]V { + m := make(map[K]V) + Insert(m, seq) + return m +} diff --git a/contrib/go/_std_1.23/src/maps/maps.go b/contrib/go/_std_1.23/src/maps/maps.go new file mode 100644 index 000000000000..b712dd3fe8eb --- /dev/null +++ b/contrib/go/_std_1.23/src/maps/maps.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package maps defines various functions useful with maps of any type. +// +// This package does not have any special handling for non-reflexive keys +// (keys k where k != k), such as floating-point NaNs. +package maps + +import ( + _ "unsafe" +) + +// Equal reports whether two maps contain the same key/value pairs. +// Values are compared using ==. +func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool { + if len(m1) != len(m2) { + return false + } + for k, v1 := range m1 { + if v2, ok := m2[k]; !ok || v1 != v2 { + return false + } + } + return true +} + +// EqualFunc is like Equal, but compares values using eq. +// Keys are still compared with ==. +func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool { + if len(m1) != len(m2) { + return false + } + for k, v1 := range m1 { + if v2, ok := m2[k]; !ok || !eq(v1, v2) { + return false + } + } + return true +} + +// clone is implemented in the runtime package. +// +//go:linkname clone maps.clone +func clone(m any) any + +// Clone returns a copy of m. This is a shallow clone: +// the new keys and values are set using ordinary assignment. +func Clone[M ~map[K]V, K comparable, V any](m M) M { + // Preserve nil in case it matters. + if m == nil { + return nil + } + return clone(m).(M) +} + +// Copy copies all key/value pairs in src adding them to dst. +// When a key in src is already present in dst, +// the value in dst will be overwritten by the value associated +// with the key in src. +func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) { + for k, v := range src { + dst[k] = v + } +} + +// DeleteFunc deletes any key/value pairs from m for which del returns true. +func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) { + for k, v := range m { + if del(k, v) { + delete(m, k) + } + } +} diff --git a/contrib/go/_std_1.23/src/maps/ya.make b/contrib/go/_std_1.23/src/maps/ya.make new file mode 100644 index 000000000000..bfef85a6a054 --- /dev/null +++ b/contrib/go/_std_1.23/src/maps/ya.make @@ -0,0 +1,8 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + iter.go + maps.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/math/abs.go b/contrib/go/_std_1.23/src/math/abs.go similarity index 100% rename from contrib/go/_std_1.22/src/math/abs.go rename to contrib/go/_std_1.23/src/math/abs.go diff --git a/contrib/go/_std_1.22/src/math/acos_s390x.s b/contrib/go/_std_1.23/src/math/acos_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/acos_s390x.s rename to contrib/go/_std_1.23/src/math/acos_s390x.s diff --git a/contrib/go/_std_1.22/src/math/acosh.go b/contrib/go/_std_1.23/src/math/acosh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/acosh.go rename to contrib/go/_std_1.23/src/math/acosh.go diff --git a/contrib/go/_std_1.22/src/math/acosh_s390x.s b/contrib/go/_std_1.23/src/math/acosh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/acosh_s390x.s rename to contrib/go/_std_1.23/src/math/acosh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/arith_s390x.go b/contrib/go/_std_1.23/src/math/arith_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/math/arith_s390x.go rename to contrib/go/_std_1.23/src/math/arith_s390x.go diff --git a/contrib/go/_std_1.22/src/math/asin.go b/contrib/go/_std_1.23/src/math/asin.go similarity index 100% rename from contrib/go/_std_1.22/src/math/asin.go rename to contrib/go/_std_1.23/src/math/asin.go diff --git a/contrib/go/_std_1.22/src/math/asin_s390x.s b/contrib/go/_std_1.23/src/math/asin_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/asin_s390x.s rename to contrib/go/_std_1.23/src/math/asin_s390x.s diff --git a/contrib/go/_std_1.22/src/math/asinh.go b/contrib/go/_std_1.23/src/math/asinh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/asinh.go rename to contrib/go/_std_1.23/src/math/asinh.go diff --git a/contrib/go/_std_1.22/src/math/asinh_s390x.s b/contrib/go/_std_1.23/src/math/asinh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/asinh_s390x.s rename to contrib/go/_std_1.23/src/math/asinh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/atan.go b/contrib/go/_std_1.23/src/math/atan.go similarity index 100% rename from contrib/go/_std_1.22/src/math/atan.go rename to contrib/go/_std_1.23/src/math/atan.go diff --git a/contrib/go/_std_1.22/src/math/atan2.go b/contrib/go/_std_1.23/src/math/atan2.go similarity index 100% rename from contrib/go/_std_1.22/src/math/atan2.go rename to contrib/go/_std_1.23/src/math/atan2.go diff --git a/contrib/go/_std_1.22/src/math/atan2_s390x.s b/contrib/go/_std_1.23/src/math/atan2_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/atan2_s390x.s rename to contrib/go/_std_1.23/src/math/atan2_s390x.s diff --git a/contrib/go/_std_1.22/src/math/atan_s390x.s b/contrib/go/_std_1.23/src/math/atan_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/atan_s390x.s rename to contrib/go/_std_1.23/src/math/atan_s390x.s diff --git a/contrib/go/_std_1.22/src/math/atanh.go b/contrib/go/_std_1.23/src/math/atanh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/atanh.go rename to contrib/go/_std_1.23/src/math/atanh.go diff --git a/contrib/go/_std_1.22/src/math/atanh_s390x.s b/contrib/go/_std_1.23/src/math/atanh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/atanh_s390x.s rename to contrib/go/_std_1.23/src/math/atanh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/big/accuracy_string.go b/contrib/go/_std_1.23/src/math/big/accuracy_string.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/accuracy_string.go rename to contrib/go/_std_1.23/src/math/big/accuracy_string.go diff --git a/contrib/go/_std_1.22/src/math/big/arith.go b/contrib/go/_std_1.23/src/math/big/arith.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith.go rename to contrib/go/_std_1.23/src/math/big/arith.go diff --git a/contrib/go/_std_1.22/src/math/big/arith_386.s b/contrib/go/_std_1.23/src/math/big/arith_386.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_386.s rename to contrib/go/_std_1.23/src/math/big/arith_386.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_amd64.go b/contrib/go/_std_1.23/src/math/big/arith_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_amd64.go rename to contrib/go/_std_1.23/src/math/big/arith_amd64.go diff --git a/contrib/go/_std_1.22/src/math/big/arith_amd64.s b/contrib/go/_std_1.23/src/math/big/arith_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_amd64.s rename to contrib/go/_std_1.23/src/math/big/arith_amd64.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_arm.s b/contrib/go/_std_1.23/src/math/big/arith_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_arm.s rename to contrib/go/_std_1.23/src/math/big/arith_arm.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_arm64.s b/contrib/go/_std_1.23/src/math/big/arith_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_arm64.s rename to contrib/go/_std_1.23/src/math/big/arith_arm64.s diff --git a/contrib/go/_std_1.23/src/math/big/arith_decl.go b/contrib/go/_std_1.23/src/math/big/arith_decl.go new file mode 100644 index 000000000000..3230a781a9de --- /dev/null +++ b/contrib/go/_std_1.23/src/math/big/arith_decl.go @@ -0,0 +1,98 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !math_big_pure_go + +package big + +import _ "unsafe" // for linkname + +// implemented in arith_$GOARCH.s + +// addVV should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname addVV +//go:noescape +func addVV(z, x, y []Word) (c Word) + +// subVV should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname subVV +//go:noescape +func subVV(z, x, y []Word) (c Word) + +// addVW should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname addVW +//go:noescape +func addVW(z, x []Word, y Word) (c Word) + +// subVW should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname subVW +//go:noescape +func subVW(z, x []Word, y Word) (c Word) + +// shlVU should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname shlVU +//go:noescape +func shlVU(z, x []Word, s uint) (c Word) + +//go:noescape +func shrVU(z, x []Word, s uint) (c Word) + +// mulAddVWW should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mulAddVWW +//go:noescape +func mulAddVWW(z, x []Word, y, r Word) (c Word) + +// addMulVVW should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname addMulVVW +//go:noescape +func addMulVVW(z, x []Word, y Word) (c Word) diff --git a/contrib/go/_std_1.22/src/math/big/arith_decl_pure.go b/contrib/go/_std_1.23/src/math/big/arith_decl_pure.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_decl_pure.go rename to contrib/go/_std_1.23/src/math/big/arith_decl_pure.go diff --git a/contrib/go/_std_1.22/src/math/big/arith_decl_s390x.go b/contrib/go/_std_1.23/src/math/big/arith_decl_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_decl_s390x.go rename to contrib/go/_std_1.23/src/math/big/arith_decl_s390x.go diff --git a/contrib/go/_std_1.22/src/math/big/arith_loong64.s b/contrib/go/_std_1.23/src/math/big/arith_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_loong64.s rename to contrib/go/_std_1.23/src/math/big/arith_loong64.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_mips64x.s b/contrib/go/_std_1.23/src/math/big/arith_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_mips64x.s rename to contrib/go/_std_1.23/src/math/big/arith_mips64x.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_mipsx.s b/contrib/go/_std_1.23/src/math/big/arith_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_mipsx.s rename to contrib/go/_std_1.23/src/math/big/arith_mipsx.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_ppc64x.s b/contrib/go/_std_1.23/src/math/big/arith_ppc64x.s similarity index 84% rename from contrib/go/_std_1.22/src/math/big/arith_ppc64x.s rename to contrib/go/_std_1.23/src/math/big/arith_ppc64x.s index 9512a12270d4..82aa7fb51e44 100644 --- a/contrib/go/_std_1.22/src/math/big/arith_ppc64x.s +++ b/contrib/go/_std_1.23/src/math/big/arith_ppc64x.s @@ -18,7 +18,7 @@ TEXT ·addVV(SB), NOSPLIT, $0 MOVD z+0(FP), R10 // R10 = z[] // If z_len = 0, we are done - CMP R0, R7 + CMP R7, $0 MOVD R0, R4 BEQ done @@ -28,12 +28,12 @@ TEXT ·addVV(SB), NOSPLIT, $0 MOVD 0(R9), R12 // R12 = y[i] ADD $-1, R7 // R7 = z_len - 1 ADDC R12, R11, R15 // R15 = x[i] + y[i], set CA - CMP R0, R7 + CMP R7, $0 MOVD R15, 0(R10) // z[i] BEQ final // If z_len was 1, we are done SRD $2, R7, R5 // R5 = z_len/4 - CMP R0, R5 + CMP R5, $0 MOVD R5, CTR // Set up loop counter BEQ tail // If R5 = 0, we can't use the loop @@ -62,10 +62,10 @@ loop: MOVD R22, 24(R10) // z[i+2] MOVDU R23, 32(R10) // z[i+3] ADD $-4, R7 // R7 = z_len - 4 - BC 16, 0, loop // bdnz + BDNZ loop // We may have more elements to read - CMP R0, R7 + CMP R7, $0 BEQ final // Process the remaining elements, one at a time @@ -74,7 +74,7 @@ tail: MOVDU 8(R9), R16 // R16 = y[i] ADD $-1, R7 // R7 = z_len - 1 ADDE R11, R16, R20 // R20 = x[i] + y[i] + CA - CMP R0, R7 + CMP R7, $0 MOVDU R20, 8(R10) // z[i] BEQ final // If R7 = 0, we are done @@ -82,7 +82,7 @@ tail: MOVDU 8(R9), R16 ADD $-1, R7 ADDE R11, R16, R20 - CMP R0, R7 + CMP R7, $0 MOVDU R20, 8(R10) BEQ final @@ -107,7 +107,7 @@ TEXT ·subVV(SB), NOSPLIT, $0 MOVD z+0(FP), R10 // R10 = z[] // If z_len = 0, we are done - CMP R0, R7 + CMP R7, $0 MOVD R0, R4 BEQ done @@ -117,12 +117,12 @@ TEXT ·subVV(SB), NOSPLIT, $0 MOVD 0(R9), R12 // R12 = y[i] ADD $-1, R7 // R7 = z_len - 1 SUBC R12, R11, R15 // R15 = x[i] - y[i], set CA - CMP R0, R7 + CMP R7, $0 MOVD R15, 0(R10) // z[i] BEQ final // If z_len was 1, we are done SRD $2, R7, R5 // R5 = z_len/4 - CMP R0, R5 + CMP R5, $0 MOVD R5, CTR // Set up loop counter BEQ tail // If R5 = 0, we can't use the loop @@ -151,10 +151,10 @@ loop: MOVD R22, 24(R10) // z[i+2] MOVDU R23, 32(R10) // z[i+3] ADD $-4, R7 // R7 = z_len - 4 - BC 16, 0, loop // bdnz + BDNZ loop // We may have more elements to read - CMP R0, R7 + CMP R7, $0 BEQ final // Process the remaining elements, one at a time @@ -163,7 +163,7 @@ tail: MOVDU 8(R9), R16 // R16 = y[i] ADD $-1, R7 // R7 = z_len - 1 SUBE R16, R11, R20 // R20 = x[i] - y[i] + CA - CMP R0, R7 + CMP R7, $0 MOVDU R20, 8(R10) // z[i] BEQ final // If R7 = 0, we are done @@ -171,7 +171,7 @@ tail: MOVDU 8(R9), R16 ADD $-1, R7 SUBE R16, R11, R20 - CMP R0, R7 + CMP R7, $0 MOVDU R20, 8(R10) BEQ final @@ -195,7 +195,7 @@ TEXT ·addVW(SB), NOSPLIT, $0 MOVD y+48(FP), R4 // R4 = y = c MOVD z_len+8(FP), R11 // R11 = z_len - CMP R0, R11 // If z_len is zero, return + CMP R11, $0 // If z_len is zero, return BEQ done // We will process the first iteration out of the loop so we capture @@ -204,14 +204,13 @@ TEXT ·addVW(SB), NOSPLIT, $0 MOVD 0(R8), R20 // R20 = x[i] ADD $-1, R11 // R11 = z_len - 1 ADDC R20, R4, R6 // R6 = x[i] + c - CMP R0, R11 // If z_len was 1, we are done + CMP R11, $0 // If z_len was 1, we are done MOVD R6, 0(R10) // z[i] BEQ final // We will read 4 elements per iteration - SRD $2, R11, R9 // R9 = z_len/4 + SRDCC $2, R11, R9 // R9 = z_len/4 DCBT (R8) - CMP R0, R9 MOVD R9, CTR // Set up the loop counter BEQ tail // If R9 = 0, we can't use the loop PCALIGN $16 @@ -230,10 +229,10 @@ loop: MOVD R26, 24(R10) // z[i+2] MOVDU R27, 32(R10) // z[i+3] ADD $-4, R11 // R11 = z_len - 4 - BC 16, 0, loop // bdnz + BDNZ loop // We may have some elements to read - CMP R0, R11 + CMP R11, $0 BEQ final tail: @@ -241,14 +240,14 @@ tail: ADDZE R20, R24 ADD $-1, R11 MOVDU R24, 8(R10) - CMP R0, R11 + CMP R11, $0 BEQ final MOVDU 8(R8), R20 ADDZE R20, R24 ADD $-1, R11 MOVDU R24, 8(R10) - CMP R0, R11 + CMP R11, $0 BEQ final MOVD 8(R8), R20 @@ -268,7 +267,7 @@ TEXT ·subVW(SB), NOSPLIT, $0 MOVD y+48(FP), R4 // R4 = y = c MOVD z_len+8(FP), R11 // R11 = z_len - CMP R0, R11 // If z_len is zero, return + CMP R11, $0 // If z_len is zero, return BEQ done // We will process the first iteration out of the loop so we capture @@ -277,14 +276,13 @@ TEXT ·subVW(SB), NOSPLIT, $0 MOVD 0(R8), R20 // R20 = x[i] ADD $-1, R11 // R11 = z_len - 1 SUBC R4, R20, R6 // R6 = x[i] - c - CMP R0, R11 // If z_len was 1, we are done + CMP R11, $0 // If z_len was 1, we are done MOVD R6, 0(R10) // z[i] BEQ final // We will read 4 elements per iteration - SRD $2, R11, R9 // R9 = z_len/4 + SRDCC $2, R11, R9 // R9 = z_len/4 DCBT (R8) - CMP R0, R9 MOVD R9, CTR // Set up the loop counter BEQ tail // If R9 = 0, we can't use the loop @@ -307,10 +305,10 @@ loop: MOVD R22, 24(R10) MOVDU R23, 32(R10) ADD $-4, R11 - BC 16, 0, loop // bdnz + BDNZ loop // We may have some elements to read - CMP R0, R11 + CMP R11, $0 BEQ final tail: @@ -318,14 +316,14 @@ tail: SUBE R0, R20 ADD $-1, R11 MOVDU R20, 8(R10) - CMP R0, R11 + CMP R11, $0 BEQ final MOVDU 8(R8), R20 SUBE R0, R20 ADD $-1, R11 MOVDU R20, 8(R10) - CMP R0, R11 + CMP R11, $0 BEQ final MOVD 8(R8), R20 @@ -348,9 +346,9 @@ TEXT ·shlVU(SB), NOSPLIT, $0 MOVD s+48(FP), R9 MOVD z_len+8(FP), R4 MOVD x_len+32(FP), R7 - CMP R9, R0 // s==0 copy(z,x) + CMP R9, $0 // s==0 copy(z,x) BEQ zeroshift - CMP R4, R0 // len(z)==0 return + CMP R4, $0 // len(z)==0 return BEQ done ADD $-1, R4, R5 // len(z)-1 @@ -360,7 +358,7 @@ TEXT ·shlVU(SB), NOSPLIT, $0 ADD R3, R7, R16 // save starting address &z[len(z)-1] MOVD (R6)(R7), R14 SRD R4, R14, R7 // compute x[len(z)-1]>>ŝ into R7 - CMP R5, R0 // iterate from i=len(z)-1 to 0 + CMP R5, $0 // iterate from i=len(z)-1 to 0 BEQ loopexit // Already at end? MOVD 0(R15),R10 // x[i] PCALIGN $16 @@ -382,7 +380,7 @@ loopexit: RET zeroshift: - CMP R6, R0 // x is null, nothing to copy + CMP R6, $0 // x is null, nothing to copy BEQ done CMP R6, R3 // if x is same as z, nothing to copy BEQ done @@ -423,9 +421,9 @@ TEXT ·shrVU(SB), NOSPLIT, $0 MOVD z_len+8(FP), R4 MOVD x_len+32(FP), R7 - CMP R9, R0 // s==0, copy(z,x) + CMP R9, $0 // s==0, copy(z,x) BEQ zeroshift - CMP R4, R0 // len(z)==0 return + CMP R4, $0 // len(z)==0 return BEQ done SUBC R9, $64, R5 // ŝ=_W-s, we skip & by _W-1 as the caller ensures s < _W(64) @@ -480,7 +478,7 @@ loopexit: RET zeroshift: - CMP R6, R0 // x is null, nothing to copy + CMP R6, $0 // x is null, nothing to copy BEQ done CMP R6, R3 // if x is same as z, nothing to copy BEQ done @@ -506,7 +504,7 @@ TEXT ·mulAddVWW(SB), NOSPLIT, $0 MOVD r+56(FP), R4 // R4 = r = c MOVD z_len+8(FP), R11 // R11 = z_len - CMP R0, R11 + CMP R11, $0 BEQ done MOVD 0(R8), R20 @@ -514,16 +512,14 @@ TEXT ·mulAddVWW(SB), NOSPLIT, $0 MULLD R9, R20, R6 // R6 = z0 = Low-order(x[i]*y) MULHDU R9, R20, R7 // R7 = z1 = High-order(x[i]*y) ADDC R4, R6 // R6 = z0 + r - ADDZE R7 // R7 = z1 + CA - CMP R0, R11 - MOVD R7, R4 // R4 = c + ADDZE R7, R4 // R4 = z1 + CA + CMP R11, $0 MOVD R6, 0(R10) // z[i] BEQ done // We will read 4 elements per iteration - SRD $2, R11, R14 // R14 = z_len/4 + SRDCC $2, R11, R14 // R14 = z_len/4 DCBT (R8) - CMP R0, R14 MOVD R14, CTR // Set up the loop counter BEQ tail // If R9 = 0, we can't use the loop PCALIGN $16 @@ -536,28 +532,25 @@ loop: MULLD R9, R20, R24 // R24 = z0[i] MULHDU R9, R20, R20 // R20 = z1[i] ADDC R4, R24 // R24 = z0[i] + c - ADDZE R20 // R7 = z1[i] + CA MULLD R9, R21, R25 MULHDU R9, R21, R21 - ADDC R20, R25 - ADDZE R21 + ADDE R20, R25 MULLD R9, R22, R26 MULHDU R9, R22, R22 MULLD R9, R23, R27 MULHDU R9, R23, R23 - ADDC R21, R26 - ADDZE R22 + ADDE R21, R26 MOVD R24, 8(R10) // z[i] MOVD R25, 16(R10) // z[i+1] - ADDC R22, R27 + ADDE R22, R27 ADDZE R23,R4 // update carry MOVD R26, 24(R10) // z[i+2] MOVDU R27, 32(R10) // z[i+3] ADD $-4, R11 // R11 = z_len - 4 - BC 16, 0, loop // bdnz + BDNZ loop // We may have some elements to read - CMP R0, R11 + CMP R11, $0 BEQ done // Process the remaining elements, one at a time @@ -567,10 +560,9 @@ tail: MULHDU R9, R20, R25 // R25 = z1[i] ADD $-1, R11 // R11 = z_len - 1 ADDC R4, R24 - ADDZE R25 + ADDZE R25, R4 MOVDU R24, 8(R10) // z[i] - CMP R0, R11 - MOVD R25, R4 // R4 = c + CMP R11, $0 BEQ done // If R11 = 0, we are done MOVDU 8(R8), R20 @@ -578,10 +570,9 @@ tail: MULHDU R9, R20, R25 ADD $-1, R11 ADDC R4, R24 - ADDZE R25 + ADDZE R25, R4 MOVDU R24, 8(R10) - CMP R0, R11 - MOVD R25, R4 + CMP R11, $0 BEQ done MOVD 8(R8), R20 @@ -589,9 +580,8 @@ tail: MULHDU R9, R20, R25 ADD $-1, R11 ADDC R4, R24 - ADDZE R25 + ADDZE R25,R4 MOVD R24, 8(R10) - MOVD R25, R4 done: MOVD R4, c+64(FP) @@ -599,33 +589,80 @@ done: // func addMulVVW(z, x []Word, y Word) (c Word) TEXT ·addMulVVW(SB), NOSPLIT, $0 - MOVD z+0(FP), R10 // R10 = z[] - MOVD x+24(FP), R8 // R8 = x[] - MOVD y+48(FP), R9 // R9 = y - MOVD z_len+8(FP), R22 // R22 = z_len - - MOVD R0, R3 // R3 will be the index register - CMP R0, R22 - MOVD R0, R4 // R4 = c = 0 - MOVD R22, CTR // Initialize loop counter - BEQ done - PCALIGN $16 + MOVD z+0(FP), R3 // R3 = z[] + MOVD x+24(FP), R4 // R4 = x[] + MOVD y+48(FP), R5 // R5 = y + MOVD z_len+8(FP), R6 // R6 = z_len + + CMP R6, $4 + MOVD R0, R9 // R9 = c = 0 + BLT tail + SRD $2, R6, R7 + MOVD R7, CTR // Initialize loop counter + PCALIGN $16 loop: - MOVD (R8)(R3), R20 // Load x[i] - MOVD (R10)(R3), R21 // Load z[i] - MULLD R9, R20, R6 // R6 = Low-order(x[i]*y) - MULHDU R9, R20, R7 // R7 = High-order(x[i]*y) - ADDC R21, R6 // R6 = z0 - ADDZE R7 // R7 = z1 - ADDC R4, R6 // R6 = z0 + c + 0 - ADDZE R7, R4 // c += z1 - MOVD R6, (R10)(R3) // Store z[i] - ADD $8, R3 - BC 16, 0, loop // bdnz + MOVD 0(R4), R14 // x[i] + MOVD 8(R4), R16 // x[i+1] + MOVD 16(R4), R18 // x[i+2] + MOVD 24(R4), R20 // x[i+3] + MOVD 0(R3), R15 // z[i] + MOVD 8(R3), R17 // z[i+1] + MOVD 16(R3), R19 // z[i+2] + MOVD 24(R3), R21 // z[i+3] + MULLD R5, R14, R10 // low x[i]*y + MULHDU R5, R14, R11 // high x[i]*y + ADDC R15, R10 + ADDZE R11 + ADDC R9, R10 + ADDZE R11, R9 + MULLD R5, R16, R14 // low x[i+1]*y + MULHDU R5, R16, R15 // high x[i+1]*y + ADDC R17, R14 + ADDZE R15 + ADDC R9, R14 + ADDZE R15, R9 + MULLD R5, R18, R16 // low x[i+2]*y + MULHDU R5, R18, R17 // high x[i+2]*y + ADDC R19, R16 + ADDZE R17 + ADDC R9, R16 + ADDZE R17, R9 + MULLD R5, R20, R18 // low x[i+3]*y + MULHDU R5, R20, R19 // high x[i+3]*y + ADDC R21, R18 + ADDZE R19 + ADDC R9, R18 + ADDZE R19, R9 + MOVD R10, 0(R3) // z[i] + MOVD R14, 8(R3) // z[i+1] + MOVD R16, 16(R3) // z[i+2] + MOVD R18, 24(R3) // z[i+3] + ADD $32, R3 + ADD $32, R4 + BDNZ loop + + ANDCC $3, R6 +tail: + CMP R6, $0 + BEQ done + MOVD R6, CTR + PCALIGN $16 +tailloop: + MOVD 0(R4), R14 + MOVD 0(R3), R15 + MULLD R5, R14, R10 + MULHDU R5, R14, R11 + ADDC R15, R10 + ADDZE R11 + ADDC R9, R10 + ADDZE R11, R9 + MOVD R10, 0(R3) + ADD $8, R3 + ADD $8, R4 + BDNZ tailloop done: - MOVD R4, c+56(FP) + MOVD R9, c+56(FP) RET - diff --git a/contrib/go/_std_1.22/src/math/big/arith_riscv64.s b/contrib/go/_std_1.23/src/math/big/arith_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_riscv64.s rename to contrib/go/_std_1.23/src/math/big/arith_riscv64.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_s390x.s b/contrib/go/_std_1.23/src/math/big/arith_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_s390x.s rename to contrib/go/_std_1.23/src/math/big/arith_s390x.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_wasm.s b/contrib/go/_std_1.23/src/math/big/arith_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_wasm.s rename to contrib/go/_std_1.23/src/math/big/arith_wasm.s diff --git a/contrib/go/_std_1.22/src/math/big/decimal.go b/contrib/go/_std_1.23/src/math/big/decimal.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/decimal.go rename to contrib/go/_std_1.23/src/math/big/decimal.go diff --git a/contrib/go/_std_1.22/src/math/big/doc.go b/contrib/go/_std_1.23/src/math/big/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/doc.go rename to contrib/go/_std_1.23/src/math/big/doc.go diff --git a/contrib/go/_std_1.22/src/math/big/float.go b/contrib/go/_std_1.23/src/math/big/float.go similarity index 98% rename from contrib/go/_std_1.22/src/math/big/float.go rename to contrib/go/_std_1.23/src/math/big/float.go index 1c97ec98c004..813c4ebfa747 100644 --- a/contrib/go/_std_1.22/src/math/big/float.go +++ b/contrib/go/_std_1.23/src/math/big/float.go @@ -48,10 +48,10 @@ const debugFloat = false // enable for debugging // // By setting the desired precision to 24 or 53 and using matching rounding // mode (typically [ToNearestEven]), Float operations produce the same results -// as the corresponding float32 or float64 IEEE-754 arithmetic for operands +// as the corresponding float32 or float64 IEEE 754 arithmetic for operands // that correspond to normal (i.e., not denormal) float32 or float64 numbers. // Exponent underflow and overflow lead to a 0 or an Infinity for different -// values than IEEE-754 because Float exponents have a much larger range. +// values than IEEE 754 because Float exponents have a much larger range. // // The zero (uninitialized) value for a Float is ready to use and represents // the number +0.0 exactly, with precision 0 and rounding mode [ToNearestEven]. @@ -73,7 +73,7 @@ type Float struct { } // An ErrNaN panic is raised by a [Float] operation that would lead to -// a NaN under IEEE-754 rules. An ErrNaN implements the error interface. +// a NaN under IEEE 754 rules. An ErrNaN implements the error interface. type ErrNaN struct { msg string } @@ -232,10 +232,9 @@ func (x *Float) Acc() Accuracy { } // Sign returns: -// -// -1 if x < 0 -// 0 if x is ±0 -// +1 if x > 0 +// - -1 if x < 0; +// - 0 if x is ±0; +// - +1 if x > 0. func (x *Float) Sign() int { if debugFloat { x.validate() @@ -393,7 +392,7 @@ func (x *Float) validate0() string { // have before calling round. z's mantissa must be normalized (with the msb set) // or empty. // -// CAUTION: The rounding modes ToNegativeInf, ToPositiveInf are affected by the +// CAUTION: The rounding modes [ToNegativeInf], [ToPositiveInf] are affected by the // sign of z. For correct rounding, the sign of z must be set correctly before // calling round. func (z *Float) round(sbit uint) { @@ -672,9 +671,8 @@ func (z *Float) Set(x *Float) *Float { return z } -// Copy sets z to x, with the same precision, rounding mode, and -// accuracy as x, and returns z. x is not changed even if z and -// x are the same. +// Copy sets z to x, with the same precision, rounding mode, and accuracy as x. +// Copy returns z. If x and z are identical, Copy is a no-op. func (z *Float) Copy(x *Float) *Float { if debugFloat { x.validate() @@ -734,7 +732,7 @@ func msb64(x nat) uint64 { } // Uint64 returns the unsigned integer resulting from truncating x -// towards zero. If 0 <= x <= math.MaxUint64, the result is [Exact] +// towards zero. If 0 <= x <= [math.MaxUint64], the result is [Exact] // if x is an integer and [Below] otherwise. // The result is (0, [Above]) for x < 0, and ([math.MaxUint64], [Below]) // for x > [math.MaxUint64]. @@ -1674,10 +1672,9 @@ func (z *Float) Quo(x, y *Float) *Float { } // Cmp compares x and y and returns: -// -// -1 if x < y -// 0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf) -// +1 if x > y +// - -1 if x < y; +// - 0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf); +// - +1 if x > y. func (x *Float) Cmp(y *Float) int { if debugFloat { x.validate() diff --git a/contrib/go/_std_1.22/src/math/big/floatconv.go b/contrib/go/_std_1.23/src/math/big/floatconv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/floatconv.go rename to contrib/go/_std_1.23/src/math/big/floatconv.go diff --git a/contrib/go/_std_1.22/src/math/big/floatmarsh.go b/contrib/go/_std_1.23/src/math/big/floatmarsh.go similarity index 94% rename from contrib/go/_std_1.22/src/math/big/floatmarsh.go rename to contrib/go/_std_1.23/src/math/big/floatmarsh.go index 8a908cef28ab..16be94697147 100644 --- a/contrib/go/_std_1.22/src/math/big/floatmarsh.go +++ b/contrib/go/_std_1.23/src/math/big/floatmarsh.go @@ -7,9 +7,9 @@ package big import ( - "encoding/binary" "errors" "fmt" + "internal/byteorder" ) // Gob codec version. Permits backward-compatible changes to the encoding. @@ -48,10 +48,10 @@ func (x *Float) GobEncode() ([]byte, error) { b |= 1 } buf[1] = b - binary.BigEndian.PutUint32(buf[2:], x.prec) + byteorder.BePutUint32(buf[2:], x.prec) if x.form == finite { - binary.BigEndian.PutUint32(buf[6:], uint32(x.exp)) + byteorder.BePutUint32(buf[6:], uint32(x.exp)) x.mant[len(x.mant)-n:].bytes(buf[10:]) // cut off unused trailing words } @@ -84,13 +84,13 @@ func (z *Float) GobDecode(buf []byte) error { z.acc = Accuracy((b>>3)&3) - 1 z.form = form((b >> 1) & 3) z.neg = b&1 != 0 - z.prec = binary.BigEndian.Uint32(buf[2:]) + z.prec = byteorder.BeUint32(buf[2:]) if z.form == finite { if len(buf) < 10 { return errors.New("Float.GobDecode: buffer too small for finite form float") } - z.exp = int32(binary.BigEndian.Uint32(buf[6:])) + z.exp = int32(byteorder.BeUint32(buf[6:])) z.mant = z.mant.setBytes(buf[10:]) } diff --git a/contrib/go/_std_1.22/src/math/big/ftoa.go b/contrib/go/_std_1.23/src/math/big/ftoa.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/ftoa.go rename to contrib/go/_std_1.23/src/math/big/ftoa.go diff --git a/contrib/go/_std_1.22/src/math/big/int.go b/contrib/go/_std_1.23/src/math/big/int.go similarity index 98% rename from contrib/go/_std_1.22/src/math/big/int.go rename to contrib/go/_std_1.23/src/math/big/int.go index b79b4592709f..944b70c0621a 100644 --- a/contrib/go/_std_1.22/src/math/big/int.go +++ b/contrib/go/_std_1.23/src/math/big/int.go @@ -38,10 +38,9 @@ type Int struct { var intOne = &Int{false, natOne} // Sign returns: -// -// -1 if x < 0 -// 0 if x == 0 -// +1 if x > 0 +// - -1 if x < 0; +// - 0 if x == 0; +// - +1 if x > 0. func (x *Int) Sign() int { // This function is used in cryptographic operations. It must not leak // anything but the Int's sign and bit size through side-channels. Any @@ -289,7 +288,7 @@ func (z *Int) Rem(x, y *Int) *Int { // r = x - y*q // // (See Daan Leijen, “Division and Modulus for Computer Scientists”.) -// See DivMod for Euclidean division and modulus (unlike Go). +// See [DivMod] for Euclidean division and modulus (unlike Go). func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) { z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs) z.neg, r.neg = len(z.abs) > 0 && x.neg != y.neg, len(r.abs) > 0 && x.neg // 0 has no sign @@ -366,10 +365,9 @@ func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) { } // Cmp compares x and y and returns: -// -// -1 if x < y -// 0 if x == y -// +1 if x > y +// - -1 if x < y; +// - 0 if x == y; +// - +1 if x > y. func (x *Int) Cmp(y *Int) (r int) { // x cmp y == x cmp y // x cmp (-y) == x @@ -392,10 +390,9 @@ func (x *Int) Cmp(y *Int) (r int) { } // CmpAbs compares the absolute values of x and y and returns: -// -// -1 if |x| < |y| -// 0 if |x| == |y| -// +1 if |x| > |y| +// - -1 if |x| < |y|; +// - 0 if |x| == |y|; +// - +1 if |x| > |y|. func (x *Int) CmpAbs(y *Int) int { return x.abs.cmp(y.abs) } @@ -533,10 +530,8 @@ func (x *Int) Bytes() []byte { // // If the absolute value of x doesn't fit in buf, FillBytes will panic. func (x *Int) FillBytes(buf []byte) []byte { - // Clear whole buffer. (This gets optimized into a memclr.) - for i := range buf { - buf[i] = 0 - } + // Clear whole buffer. + clear(buf) x.abs.bytes(buf) return buf } @@ -1152,9 +1147,10 @@ func (x *Int) Bit(i int) uint { } // SetBit sets z to x, with x's i'th bit set to b (0 or 1). -// That is, if b is 1 SetBit sets z = x | (1 << i); -// if b is 0 SetBit sets z = x &^ (1 << i). If b is not 0 or 1, -// SetBit will panic. +// That is, +// - if b is 1, SetBit sets z = x | (1 << i); +// - if b is 0, SetBit sets z = x &^ (1 << i); +// - if b is not 0 or 1, SetBit will panic. func (z *Int) SetBit(x *Int, i int, b uint) *Int { if i < 0 { panic("negative bit index") diff --git a/contrib/go/_std_1.22/src/math/big/intconv.go b/contrib/go/_std_1.23/src/math/big/intconv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/intconv.go rename to contrib/go/_std_1.23/src/math/big/intconv.go diff --git a/contrib/go/_std_1.22/src/math/big/intmarsh.go b/contrib/go/_std_1.23/src/math/big/intmarsh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/intmarsh.go rename to contrib/go/_std_1.23/src/math/big/intmarsh.go diff --git a/contrib/go/_std_1.23/src/math/big/nat.go b/contrib/go/_std_1.23/src/math/big/nat.go new file mode 100644 index 000000000000..23b2a0b8ddf0 --- /dev/null +++ b/contrib/go/_std_1.23/src/math/big/nat.go @@ -0,0 +1,1416 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements unsigned multi-precision integers (natural +// numbers). They are the building blocks for the implementation +// of signed integers, rationals, and floating-point numbers. +// +// Caution: This implementation relies on the function "alias" +// which assumes that (nat) slice capacities are never +// changed (no 3-operand slice expressions). If that +// changes, alias needs to be updated for correctness. + +package big + +import ( + "internal/byteorder" + "math/bits" + "math/rand" + "sync" +) + +// An unsigned integer x of the form +// +// x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0] +// +// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n, +// with the digits x[i] as the slice elements. +// +// A number is normalized if the slice contains no leading 0 digits. +// During arithmetic operations, denormalized values may occur but are +// always normalized before returning the final result. The normalized +// representation of 0 is the empty or nil slice (length = 0). +type nat []Word + +var ( + natOne = nat{1} + natTwo = nat{2} + natFive = nat{5} + natTen = nat{10} +) + +func (z nat) String() string { + return "0x" + string(z.itoa(false, 16)) +} + +func (z nat) norm() nat { + i := len(z) + for i > 0 && z[i-1] == 0 { + i-- + } + return z[0:i] +} + +func (z nat) make(n int) nat { + if n <= cap(z) { + return z[:n] // reuse z + } + if n == 1 { + // Most nats start small and stay that way; don't over-allocate. + return make(nat, 1) + } + // Choosing a good value for e has significant performance impact + // because it increases the chance that a value can be reused. + const e = 4 // extra capacity + return make(nat, n, n+e) +} + +func (z nat) setWord(x Word) nat { + if x == 0 { + return z[:0] + } + z = z.make(1) + z[0] = x + return z +} + +func (z nat) setUint64(x uint64) nat { + // single-word value + if w := Word(x); uint64(w) == x { + return z.setWord(w) + } + // 2-word value + z = z.make(2) + z[1] = Word(x >> 32) + z[0] = Word(x) + return z +} + +func (z nat) set(x nat) nat { + z = z.make(len(x)) + copy(z, x) + return z +} + +func (z nat) add(x, y nat) nat { + m := len(x) + n := len(y) + + switch { + case m < n: + return z.add(y, x) + case m == 0: + // n == 0 because m >= n; result is 0 + return z[:0] + case n == 0: + // result is x + return z.set(x) + } + // m > 0 + + z = z.make(m + 1) + c := addVV(z[0:n], x, y) + if m > n { + c = addVW(z[n:m], x[n:], c) + } + z[m] = c + + return z.norm() +} + +func (z nat) sub(x, y nat) nat { + m := len(x) + n := len(y) + + switch { + case m < n: + panic("underflow") + case m == 0: + // n == 0 because m >= n; result is 0 + return z[:0] + case n == 0: + // result is x + return z.set(x) + } + // m > 0 + + z = z.make(m) + c := subVV(z[0:n], x, y) + if m > n { + c = subVW(z[n:], x[n:], c) + } + if c != 0 { + panic("underflow") + } + + return z.norm() +} + +func (x nat) cmp(y nat) (r int) { + m := len(x) + n := len(y) + if m != n || m == 0 { + switch { + case m < n: + r = -1 + case m > n: + r = 1 + } + return + } + + i := m - 1 + for i > 0 && x[i] == y[i] { + i-- + } + + switch { + case x[i] < y[i]: + r = -1 + case x[i] > y[i]: + r = 1 + } + return +} + +func (z nat) mulAddWW(x nat, y, r Word) nat { + m := len(x) + if m == 0 || y == 0 { + return z.setWord(r) // result is r + } + // m > 0 + + z = z.make(m + 1) + z[m] = mulAddVWW(z[0:m], x, y, r) + + return z.norm() +} + +// basicMul multiplies x and y and leaves the result in z. +// The (non-normalized) result is placed in z[0 : len(x) + len(y)]. +func basicMul(z, x, y nat) { + clear(z[0 : len(x)+len(y)]) // initialize z + for i, d := range y { + if d != 0 { + z[len(x)+i] = addMulVVW(z[i:i+len(x)], x, d) + } + } +} + +// montgomery computes z mod m = x*y*2**(-n*_W) mod m, +// assuming k = -1/m mod 2**_W. +// z is used for storing the result which is returned; +// z must not alias x, y or m. +// See Gueron, "Efficient Software Implementations of Modular Exponentiation". +// https://eprint.iacr.org/2011/239.pdf +// In the terminology of that paper, this is an "Almost Montgomery Multiplication": +// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result +// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m. +func (z nat) montgomery(x, y, m nat, k Word, n int) nat { + // This code assumes x, y, m are all the same length, n. + // (required by addMulVVW and the for loop). + // It also assumes that x, y are already reduced mod m, + // or else the result will not be properly reduced. + if len(x) != n || len(y) != n || len(m) != n { + panic("math/big: mismatched montgomery number lengths") + } + z = z.make(n * 2) + clear(z) + var c Word + for i := 0; i < n; i++ { + d := y[i] + c2 := addMulVVW(z[i:n+i], x, d) + t := z[i] * k + c3 := addMulVVW(z[i:n+i], m, t) + cx := c + c2 + cy := cx + c3 + z[n+i] = cy + if cx < c2 || cy < c3 { + c = 1 + } else { + c = 0 + } + } + if c != 0 { + subVV(z[:n], z[n:], m) + } else { + copy(z[:n], z[n:]) + } + return z[:n] +} + +// Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks. +// Factored out for readability - do not use outside karatsuba. +func karatsubaAdd(z, x nat, n int) { + if c := addVV(z[0:n], z, x); c != 0 { + addVW(z[n:n+n>>1], z[n:], c) + } +} + +// Like karatsubaAdd, but does subtract. +func karatsubaSub(z, x nat, n int) { + if c := subVV(z[0:n], z, x); c != 0 { + subVW(z[n:n+n>>1], z[n:], c) + } +} + +// Operands that are shorter than karatsubaThreshold are multiplied using +// "grade school" multiplication; for longer operands the Karatsuba algorithm +// is used. +var karatsubaThreshold = 40 // computed by calibrate_test.go + +// karatsuba multiplies x and y and leaves the result in z. +// Both x and y must have the same length n and n must be a +// power of 2. The result vector z must have len(z) >= 6*n. +// The (non-normalized) result is placed in z[0 : 2*n]. +func karatsuba(z, x, y nat) { + n := len(y) + + // Switch to basic multiplication if numbers are odd or small. + // (n is always even if karatsubaThreshold is even, but be + // conservative) + if n&1 != 0 || n < karatsubaThreshold || n < 2 { + basicMul(z, x, y) + return + } + // n&1 == 0 && n >= karatsubaThreshold && n >= 2 + + // Karatsuba multiplication is based on the observation that + // for two numbers x and y with: + // + // x = x1*b + x0 + // y = y1*b + y0 + // + // the product x*y can be obtained with 3 products z2, z1, z0 + // instead of 4: + // + // x*y = x1*y1*b*b + (x1*y0 + x0*y1)*b + x0*y0 + // = z2*b*b + z1*b + z0 + // + // with: + // + // xd = x1 - x0 + // yd = y0 - y1 + // + // z1 = xd*yd + z2 + z0 + // = (x1-x0)*(y0 - y1) + z2 + z0 + // = x1*y0 - x1*y1 - x0*y0 + x0*y1 + z2 + z0 + // = x1*y0 - z2 - z0 + x0*y1 + z2 + z0 + // = x1*y0 + x0*y1 + + // split x, y into "digits" + n2 := n >> 1 // n2 >= 1 + x1, x0 := x[n2:], x[0:n2] // x = x1*b + y0 + y1, y0 := y[n2:], y[0:n2] // y = y1*b + y0 + + // z is used for the result and temporary storage: + // + // 6*n 5*n 4*n 3*n 2*n 1*n 0*n + // z = [z2 copy|z0 copy| xd*yd | yd:xd | x1*y1 | x0*y0 ] + // + // For each recursive call of karatsuba, an unused slice of + // z is passed in that has (at least) half the length of the + // caller's z. + + // compute z0 and z2 with the result "in place" in z + karatsuba(z, x0, y0) // z0 = x0*y0 + karatsuba(z[n:], x1, y1) // z2 = x1*y1 + + // compute xd (or the negative value if underflow occurs) + s := 1 // sign of product xd*yd + xd := z[2*n : 2*n+n2] + if subVV(xd, x1, x0) != 0 { // x1-x0 + s = -s + subVV(xd, x0, x1) // x0-x1 + } + + // compute yd (or the negative value if underflow occurs) + yd := z[2*n+n2 : 3*n] + if subVV(yd, y0, y1) != 0 { // y0-y1 + s = -s + subVV(yd, y1, y0) // y1-y0 + } + + // p = (x1-x0)*(y0-y1) == x1*y0 - x1*y1 - x0*y0 + x0*y1 for s > 0 + // p = (x0-x1)*(y0-y1) == x0*y0 - x0*y1 - x1*y0 + x1*y1 for s < 0 + p := z[n*3:] + karatsuba(p, xd, yd) + + // save original z2:z0 + // (ok to use upper half of z since we're done recurring) + r := z[n*4:] + copy(r, z[:n*2]) + + // add up all partial products + // + // 2*n n 0 + // z = [ z2 | z0 ] + // + [ z0 ] + // + [ z2 ] + // + [ p ] + // + karatsubaAdd(z[n2:], r, n) + karatsubaAdd(z[n2:], r[n:], n) + if s > 0 { + karatsubaAdd(z[n2:], p, n) + } else { + karatsubaSub(z[n2:], p, n) + } +} + +// alias reports whether x and y share the same base array. +// +// Note: alias assumes that the capacity of underlying arrays +// is never changed for nat values; i.e. that there are +// no 3-operand slice expressions in this code (or worse, +// reflect-based operations to the same effect). +func alias(x, y nat) bool { + return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1] +} + +// addAt implements z += x<<(_W*i); z must be long enough. +// (we don't use nat.add because we need z to stay the same +// slice, and we don't need to normalize z after each addition) +func addAt(z, x nat, i int) { + if n := len(x); n > 0 { + if c := addVV(z[i:i+n], z[i:], x); c != 0 { + j := i + n + if j < len(z) { + addVW(z[j:], z[j:], c) + } + } + } +} + +// karatsubaLen computes an approximation to the maximum k <= n such that +// k = p<= 0. Thus, the +// result is the largest number that can be divided repeatedly by 2 before +// becoming about the value of threshold. +func karatsubaLen(n, threshold int) int { + i := uint(0) + for n > threshold { + n >>= 1 + i++ + } + return n << i +} + +func (z nat) mul(x, y nat) nat { + m := len(x) + n := len(y) + + switch { + case m < n: + return z.mul(y, x) + case m == 0 || n == 0: + return z[:0] + case n == 1: + return z.mulAddWW(x, y[0], 0) + } + // m >= n > 1 + + // determine if z can be reused + if alias(z, x) || alias(z, y) { + z = nil // z is an alias for x or y - cannot reuse + } + + // use basic multiplication if the numbers are small + if n < karatsubaThreshold { + z = z.make(m + n) + basicMul(z, x, y) + return z.norm() + } + // m >= n && n >= karatsubaThreshold && n >= 2 + + // determine Karatsuba length k such that + // + // x = xh*b + x0 (0 <= x0 < b) + // y = yh*b + y0 (0 <= y0 < b) + // b = 1<<(_W*k) ("base" of digits xi, yi) + // + k := karatsubaLen(n, karatsubaThreshold) + // k <= n + + // multiply x0 and y0 via Karatsuba + x0 := x[0:k] // x0 is not normalized + y0 := y[0:k] // y0 is not normalized + z = z.make(max(6*k, m+n)) // enough space for karatsuba of x0*y0 and full result of x*y + karatsuba(z, x0, y0) + z = z[0 : m+n] // z has final length but may be incomplete + clear(z[2*k:]) // upper portion of z is garbage (and 2*k <= m+n since k <= n <= m) + + // If xh != 0 or yh != 0, add the missing terms to z. For + // + // xh = xi*b^i + ... + x2*b^2 + x1*b (0 <= xi < b) + // yh = y1*b (0 <= y1 < b) + // + // the missing terms are + // + // x0*y1*b and xi*y0*b^i, xi*y1*b^(i+1) for i > 0 + // + // since all the yi for i > 1 are 0 by choice of k: If any of them + // were > 0, then yh >= b^2 and thus y >= b^2. Then k' = k*2 would + // be a larger valid threshold contradicting the assumption about k. + // + if k < n || m != n { + tp := getNat(3 * k) + t := *tp + + // add x0*y1*b + x0 := x0.norm() + y1 := y[k:] // y1 is normalized because y is + t = t.mul(x0, y1) // update t so we don't lose t's underlying array + addAt(z, t, k) + + // add xi*y0< k { + xi = xi[:k] + } + xi = xi.norm() + t = t.mul(xi, y0) + addAt(z, t, i) + t = t.mul(xi, y1) + addAt(z, t, i+k) + } + + putNat(tp) + } + + return z.norm() +} + +// basicSqr sets z = x*x and is asymptotically faster than basicMul +// by about a factor of 2, but slower for small arguments due to overhead. +// Requirements: len(x) > 0, len(z) == 2*len(x) +// The (non-normalized) result is placed in z. +func basicSqr(z, x nat) { + n := len(x) + tp := getNat(2 * n) + t := *tp // temporary variable to hold the products + clear(t) + z[1], z[0] = mulWW(x[0], x[0]) // the initial square + for i := 1; i < n; i++ { + d := x[i] + // z collects the squares x[i] * x[i] + z[2*i+1], z[2*i] = mulWW(d, d) + // t collects the products x[i] * x[j] where j < i + t[2*i] = addMulVVW(t[i:2*i], x[0:i], d) + } + t[2*n-1] = shlVU(t[1:2*n-1], t[1:2*n-1], 1) // double the j < i products + addVV(z, z, t) // combine the result + putNat(tp) +} + +// karatsubaSqr squares x and leaves the result in z. +// len(x) must be a power of 2 and len(z) >= 6*len(x). +// The (non-normalized) result is placed in z[0 : 2*len(x)]. +// +// The algorithm and the layout of z are the same as for karatsuba. +func karatsubaSqr(z, x nat) { + n := len(x) + + if n&1 != 0 || n < karatsubaSqrThreshold || n < 2 { + basicSqr(z[:2*n], x) + return + } + + n2 := n >> 1 + x1, x0 := x[n2:], x[0:n2] + + karatsubaSqr(z, x0) + karatsubaSqr(z[n:], x1) + + // s = sign(xd*yd) == -1 for xd != 0; s == 1 for xd == 0 + xd := z[2*n : 2*n+n2] + if subVV(xd, x1, x0) != 0 { + subVV(xd, x0, x1) + } + + p := z[n*3:] + karatsubaSqr(p, xd) + + r := z[n*4:] + copy(r, z[:n*2]) + + karatsubaAdd(z[n2:], r, n) + karatsubaAdd(z[n2:], r[n:], n) + karatsubaSub(z[n2:], p, n) // s == -1 for p != 0; s == 1 for p == 0 +} + +// Operands that are shorter than basicSqrThreshold are squared using +// "grade school" multiplication; for operands longer than karatsubaSqrThreshold +// we use the Karatsuba algorithm optimized for x == y. +var basicSqrThreshold = 20 // computed by calibrate_test.go +var karatsubaSqrThreshold = 260 // computed by calibrate_test.go + +// z = x*x +func (z nat) sqr(x nat) nat { + n := len(x) + switch { + case n == 0: + return z[:0] + case n == 1: + d := x[0] + z = z.make(2) + z[1], z[0] = mulWW(d, d) + return z.norm() + } + + if alias(z, x) { + z = nil // z is an alias for x - cannot reuse + } + + if n < basicSqrThreshold { + z = z.make(2 * n) + basicMul(z, x, x) + return z.norm() + } + if n < karatsubaSqrThreshold { + z = z.make(2 * n) + basicSqr(z, x) + return z.norm() + } + + // Use Karatsuba multiplication optimized for x == y. + // The algorithm and layout of z are the same as for mul. + + // z = (x1*b + x0)^2 = x1^2*b^2 + 2*x1*x0*b + x0^2 + + k := karatsubaLen(n, karatsubaSqrThreshold) + + x0 := x[0:k] + z = z.make(max(6*k, 2*n)) + karatsubaSqr(z, x0) // z = x0^2 + z = z[0 : 2*n] + clear(z[2*k:]) + + if k < n { + tp := getNat(2 * k) + t := *tp + x0 := x0.norm() + x1 := x[k:] + t = t.mul(x0, x1) + addAt(z, t, k) + addAt(z, t, k) // z = 2*x1*x0*b + x0^2 + t = t.sqr(x1) + addAt(z, t, 2*k) // z = x1^2*b^2 + 2*x1*x0*b + x0^2 + putNat(tp) + } + + return z.norm() +} + +// mulRange computes the product of all the unsigned integers in the +// range [a, b] inclusively. If a > b (empty range), the result is 1. +func (z nat) mulRange(a, b uint64) nat { + switch { + case a == 0: + // cut long ranges short (optimization) + return z.setUint64(0) + case a > b: + return z.setUint64(1) + case a == b: + return z.setUint64(a) + case a+1 == b: + return z.mul(nat(nil).setUint64(a), nat(nil).setUint64(b)) + } + m := a + (b-a)/2 // avoid overflow + return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b)) +} + +// getNat returns a *nat of len n. The contents may not be zero. +// The pool holds *nat to avoid allocation when converting to interface{}. +func getNat(n int) *nat { + var z *nat + if v := natPool.Get(); v != nil { + z = v.(*nat) + } + if z == nil { + z = new(nat) + } + *z = z.make(n) + if n > 0 { + (*z)[0] = 0xfedcb // break code expecting zero + } + return z +} + +func putNat(x *nat) { + natPool.Put(x) +} + +var natPool sync.Pool + +// bitLen returns the length of x in bits. +// Unlike most methods, it works even if x is not normalized. +func (x nat) bitLen() int { + // This function is used in cryptographic operations. It must not leak + // anything but the Int's sign and bit size through side-channels. Any + // changes must be reviewed by a security expert. + if i := len(x) - 1; i >= 0 { + // bits.Len uses a lookup table for the low-order bits on some + // architectures. Neutralize any input-dependent behavior by setting all + // bits after the first one bit. + top := uint(x[i]) + top |= top >> 1 + top |= top >> 2 + top |= top >> 4 + top |= top >> 8 + top |= top >> 16 + top |= top >> 16 >> 16 // ">> 32" doesn't compile on 32-bit architectures + return i*_W + bits.Len(top) + } + return 0 +} + +// trailingZeroBits returns the number of consecutive least significant zero +// bits of x. +func (x nat) trailingZeroBits() uint { + if len(x) == 0 { + return 0 + } + var i uint + for x[i] == 0 { + i++ + } + // x[i] != 0 + return i*_W + uint(bits.TrailingZeros(uint(x[i]))) +} + +// isPow2 returns i, true when x == 2**i and 0, false otherwise. +func (x nat) isPow2() (uint, bool) { + var i uint + for x[i] == 0 { + i++ + } + if i == uint(len(x))-1 && x[i]&(x[i]-1) == 0 { + return i*_W + uint(bits.TrailingZeros(uint(x[i]))), true + } + return 0, false +} + +func same(x, y nat) bool { + return len(x) == len(y) && len(x) > 0 && &x[0] == &y[0] +} + +// z = x << s +func (z nat) shl(x nat, s uint) nat { + if s == 0 { + if same(z, x) { + return z + } + if !alias(z, x) { + return z.set(x) + } + } + + m := len(x) + if m == 0 { + return z[:0] + } + // m > 0 + + n := m + int(s/_W) + z = z.make(n + 1) + z[n] = shlVU(z[n-m:n], x, s%_W) + clear(z[0 : n-m]) + + return z.norm() +} + +// z = x >> s +func (z nat) shr(x nat, s uint) nat { + if s == 0 { + if same(z, x) { + return z + } + if !alias(z, x) { + return z.set(x) + } + } + + m := len(x) + n := m - int(s/_W) + if n <= 0 { + return z[:0] + } + // n > 0 + + z = z.make(n) + shrVU(z, x[m-n:], s%_W) + + return z.norm() +} + +func (z nat) setBit(x nat, i uint, b uint) nat { + j := int(i / _W) + m := Word(1) << (i % _W) + n := len(x) + switch b { + case 0: + z = z.make(n) + copy(z, x) + if j >= n { + // no need to grow + return z + } + z[j] &^= m + return z.norm() + case 1: + if j >= n { + z = z.make(j + 1) + clear(z[n:]) + } else { + z = z.make(n) + } + copy(z, x) + z[j] |= m + // no need to normalize + return z + } + panic("set bit is not 0 or 1") +} + +// bit returns the value of the i'th bit, with lsb == bit 0. +func (x nat) bit(i uint) uint { + j := i / _W + if j >= uint(len(x)) { + return 0 + } + // 0 <= j < len(x) + return uint(x[j] >> (i % _W) & 1) +} + +// sticky returns 1 if there's a 1 bit within the +// i least significant bits, otherwise it returns 0. +func (x nat) sticky(i uint) uint { + j := i / _W + if j >= uint(len(x)) { + if len(x) == 0 { + return 0 + } + return 1 + } + // 0 <= j < len(x) + for _, x := range x[:j] { + if x != 0 { + return 1 + } + } + if x[j]<<(_W-i%_W) != 0 { + return 1 + } + return 0 +} + +func (z nat) and(x, y nat) nat { + m := len(x) + n := len(y) + if m > n { + m = n + } + // m <= n + + z = z.make(m) + for i := 0; i < m; i++ { + z[i] = x[i] & y[i] + } + + return z.norm() +} + +// trunc returns z = x mod 2ⁿ. +func (z nat) trunc(x nat, n uint) nat { + w := (n + _W - 1) / _W + if uint(len(x)) < w { + return z.set(x) + } + z = z.make(int(w)) + copy(z, x) + if n%_W != 0 { + z[len(z)-1] &= 1<<(n%_W) - 1 + } + return z.norm() +} + +func (z nat) andNot(x, y nat) nat { + m := len(x) + n := len(y) + if n > m { + n = m + } + // m >= n + + z = z.make(m) + for i := 0; i < n; i++ { + z[i] = x[i] &^ y[i] + } + copy(z[n:m], x[n:m]) + + return z.norm() +} + +func (z nat) or(x, y nat) nat { + m := len(x) + n := len(y) + s := x + if m < n { + n, m = m, n + s = y + } + // m >= n + + z = z.make(m) + for i := 0; i < n; i++ { + z[i] = x[i] | y[i] + } + copy(z[n:m], s[n:m]) + + return z.norm() +} + +func (z nat) xor(x, y nat) nat { + m := len(x) + n := len(y) + s := x + if m < n { + n, m = m, n + s = y + } + // m >= n + + z = z.make(m) + for i := 0; i < n; i++ { + z[i] = x[i] ^ y[i] + } + copy(z[n:m], s[n:m]) + + return z.norm() +} + +// random creates a random integer in [0..limit), using the space in z if +// possible. n is the bit length of limit. +func (z nat) random(rand *rand.Rand, limit nat, n int) nat { + if alias(z, limit) { + z = nil // z is an alias for limit - cannot reuse + } + z = z.make(len(limit)) + + bitLengthOfMSW := uint(n % _W) + if bitLengthOfMSW == 0 { + bitLengthOfMSW = _W + } + mask := Word((1 << bitLengthOfMSW) - 1) + + for { + switch _W { + case 32: + for i := range z { + z[i] = Word(rand.Uint32()) + } + case 64: + for i := range z { + z[i] = Word(rand.Uint32()) | Word(rand.Uint32())<<32 + } + default: + panic("unknown word size") + } + z[len(limit)-1] &= mask + if z.cmp(limit) < 0 { + break + } + } + + return z.norm() +} + +// If m != 0 (i.e., len(m) != 0), expNN sets z to x**y mod m; +// otherwise it sets z to x**y. The result is the value of z. +func (z nat) expNN(x, y, m nat, slow bool) nat { + if alias(z, x) || alias(z, y) { + // We cannot allow in-place modification of x or y. + z = nil + } + + // x**y mod 1 == 0 + if len(m) == 1 && m[0] == 1 { + return z.setWord(0) + } + // m == 0 || m > 1 + + // x**0 == 1 + if len(y) == 0 { + return z.setWord(1) + } + // y > 0 + + // 0**y = 0 + if len(x) == 0 { + return z.setWord(0) + } + // x > 0 + + // 1**y = 1 + if len(x) == 1 && x[0] == 1 { + return z.setWord(1) + } + // x > 1 + + // x**1 == x + if len(y) == 1 && y[0] == 1 { + if len(m) != 0 { + return z.rem(x, m) + } + return z.set(x) + } + // y > 1 + + if len(m) != 0 { + // We likely end up being as long as the modulus. + z = z.make(len(m)) + + // If the exponent is large, we use the Montgomery method for odd values, + // and a 4-bit, windowed exponentiation for powers of two, + // and a CRT-decomposed Montgomery method for the remaining values + // (even values times non-trivial odd values, which decompose into one + // instance of each of the first two cases). + if len(y) > 1 && !slow { + if m[0]&1 == 1 { + return z.expNNMontgomery(x, y, m) + } + if logM, ok := m.isPow2(); ok { + return z.expNNWindowed(x, y, logM) + } + return z.expNNMontgomeryEven(x, y, m) + } + } + + z = z.set(x) + v := y[len(y)-1] // v > 0 because y is normalized and y > 0 + shift := nlz(v) + 1 + v <<= shift + var q nat + + const mask = 1 << (_W - 1) + + // We walk through the bits of the exponent one by one. Each time we + // see a bit, we square, thus doubling the power. If the bit is a one, + // we also multiply by x, thus adding one to the power. + + w := _W - int(shift) + // zz and r are used to avoid allocating in mul and div as + // otherwise the arguments would alias. + var zz, r nat + for j := 0; j < w; j++ { + zz = zz.sqr(z) + zz, z = z, zz + + if v&mask != 0 { + zz = zz.mul(z, x) + zz, z = z, zz + } + + if len(m) != 0 { + zz, r = zz.div(r, z, m) + zz, r, q, z = q, z, zz, r + } + + v <<= 1 + } + + for i := len(y) - 2; i >= 0; i-- { + v = y[i] + + for j := 0; j < _W; j++ { + zz = zz.sqr(z) + zz, z = z, zz + + if v&mask != 0 { + zz = zz.mul(z, x) + zz, z = z, zz + } + + if len(m) != 0 { + zz, r = zz.div(r, z, m) + zz, r, q, z = q, z, zz, r + } + + v <<= 1 + } + } + + return z.norm() +} + +// expNNMontgomeryEven calculates x**y mod m where m = m1 × m2 for m1 = 2ⁿ and m2 odd. +// It uses two recursive calls to expNN for x**y mod m1 and x**y mod m2 +// and then uses the Chinese Remainder Theorem to combine the results. +// The recursive call using m1 will use expNNWindowed, +// while the recursive call using m2 will use expNNMontgomery. +// For more details, see Ç. K. Koç, “Montgomery Reduction with Even Modulus”, +// IEE Proceedings: Computers and Digital Techniques, 141(5) 314-316, September 1994. +// http://www.people.vcu.edu/~jwang3/CMSC691/j34monex.pdf +func (z nat) expNNMontgomeryEven(x, y, m nat) nat { + // Split m = m₁ × m₂ where m₁ = 2ⁿ + n := m.trailingZeroBits() + m1 := nat(nil).shl(natOne, n) + m2 := nat(nil).shr(m, n) + + // We want z = x**y mod m. + // z₁ = x**y mod m1 = (x**y mod m) mod m1 = z mod m1 + // z₂ = x**y mod m2 = (x**y mod m) mod m2 = z mod m2 + // (We are using the math/big convention for names here, + // where the computation is z = x**y mod m, so its parts are z1 and z2. + // The paper is computing x = a**e mod n; it refers to these as x2 and z1.) + z1 := nat(nil).expNN(x, y, m1, false) + z2 := nat(nil).expNN(x, y, m2, false) + + // Reconstruct z from z₁, z₂ using CRT, using algorithm from paper, + // which uses only a single modInverse (and an easy one at that). + // p = (z₁ - z₂) × m₂⁻¹ (mod m₁) + // z = z₂ + p × m₂ + // The final addition is in range because: + // z = z₂ + p × m₂ + // ≤ z₂ + (m₁-1) × m₂ + // < m₂ + (m₁-1) × m₂ + // = m₁ × m₂ + // = m. + z = z.set(z2) + + // Compute (z₁ - z₂) mod m1 [m1 == 2**n] into z1. + z1 = z1.subMod2N(z1, z2, n) + + // Reuse z2 for p = (z₁ - z₂) [in z1] * m2⁻¹ (mod m₁ [= 2ⁿ]). + m2inv := nat(nil).modInverse(m2, m1) + z2 = z2.mul(z1, m2inv) + z2 = z2.trunc(z2, n) + + // Reuse z1 for p * m2. + z = z.add(z, z1.mul(z2, m2)) + + return z +} + +// expNNWindowed calculates x**y mod m using a fixed, 4-bit window, +// where m = 2**logM. +func (z nat) expNNWindowed(x, y nat, logM uint) nat { + if len(y) <= 1 { + panic("big: misuse of expNNWindowed") + } + if x[0]&1 == 0 { + // len(y) > 1, so y > logM. + // x is even, so x**y is a multiple of 2**y which is a multiple of 2**logM. + return z.setWord(0) + } + if logM == 1 { + return z.setWord(1) + } + + // zz is used to avoid allocating in mul as otherwise + // the arguments would alias. + w := int((logM + _W - 1) / _W) + zzp := getNat(w) + zz := *zzp + + const n = 4 + // powers[i] contains x^i. + var powers [1 << n]*nat + for i := range powers { + powers[i] = getNat(w) + } + *powers[0] = powers[0].set(natOne) + *powers[1] = powers[1].trunc(x, logM) + for i := 2; i < 1< mtop { + i = mtop + } + advance := false + z = z.setWord(1) + for ; i >= 0; i-- { + yi := y[i] + if i == mtop { + yi &= mmask + } + for j := 0; j < _W; j += n { + if advance { + // Account for use of 4 bits in previous iteration. + // Unrolled loop for significant performance + // gain. Use go test -bench=".*" in crypto/rsa + // to check performance before making changes. + zz = zz.sqr(z) + zz, z = z, zz + z = z.trunc(z, logM) + + zz = zz.sqr(z) + zz, z = z, zz + z = z.trunc(z, logM) + + zz = zz.sqr(z) + zz, z = z, zz + z = z.trunc(z, logM) + + zz = zz.sqr(z) + zz, z = z, zz + z = z.trunc(z, logM) + } + + zz = zz.mul(z, *powers[yi>>(_W-n)]) + zz, z = z, zz + z = z.trunc(z, logM) + + yi <<= n + advance = true + } + } + + *zzp = zz + putNat(zzp) + for i := range powers { + putNat(powers[i]) + } + + return z.norm() +} + +// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window. +// Uses Montgomery representation. +func (z nat) expNNMontgomery(x, y, m nat) nat { + numWords := len(m) + + // We want the lengths of x and m to be equal. + // It is OK if x >= m as long as len(x) == len(m). + if len(x) > numWords { + _, x = nat(nil).div(nil, x, m) + // Note: now len(x) <= numWords, not guaranteed ==. + } + if len(x) < numWords { + rr := make(nat, numWords) + copy(rr, x) + x = rr + } + + // Ideally the precomputations would be performed outside, and reused + // k0 = -m**-1 mod 2**_W. Algorithm from: Dumas, J.G. "On Newton–Raphson + // Iteration for Multiplicative Inverses Modulo Prime Powers". + k0 := 2 - m[0] + t := m[0] - 1 + for i := 1; i < _W; i <<= 1 { + t *= t + k0 *= (t + 1) + } + k0 = -k0 + + // RR = 2**(2*_W*len(m)) mod m + RR := nat(nil).setWord(1) + zz := nat(nil).shl(RR, uint(2*numWords*_W)) + _, RR = nat(nil).div(RR, zz, m) + if len(RR) < numWords { + zz = zz.make(numWords) + copy(zz, RR) + RR = zz + } + // one = 1, with equal length to that of m + one := make(nat, numWords) + one[0] = 1 + + const n = 4 + // powers[i] contains x^i + var powers [1 << n]nat + powers[0] = powers[0].montgomery(one, RR, m, k0, numWords) + powers[1] = powers[1].montgomery(x, RR, m, k0, numWords) + for i := 2; i < 1<= 0; i-- { + yi := y[i] + for j := 0; j < _W; j += n { + if i != len(y)-1 || j != 0 { + zz = zz.montgomery(z, z, m, k0, numWords) + z = z.montgomery(zz, zz, m, k0, numWords) + zz = zz.montgomery(z, z, m, k0, numWords) + z = z.montgomery(zz, zz, m, k0, numWords) + } + zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords) + z, zz = zz, z + yi <<= n + } + } + // convert to regular number + zz = zz.montgomery(z, one, m, k0, numWords) + + // One last reduction, just in case. + // See golang.org/issue/13907. + if zz.cmp(m) >= 0 { + // Common case is m has high bit set; in that case, + // since zz is the same length as m, there can be just + // one multiple of m to remove. Just subtract. + // We think that the subtract should be sufficient in general, + // so do that unconditionally, but double-check, + // in case our beliefs are wrong. + // The div is not expected to be reached. + zz = zz.sub(zz, m) + if zz.cmp(m) >= 0 { + _, zz = nat(nil).div(nil, zz, m) + } + } + + return zz.norm() +} + +// bytes writes the value of z into buf using big-endian encoding. +// The value of z is encoded in the slice buf[i:]. If the value of z +// cannot be represented in buf, bytes panics. The number i of unused +// bytes at the beginning of buf is returned as result. +func (z nat) bytes(buf []byte) (i int) { + // This function is used in cryptographic operations. It must not leak + // anything but the Int's sign and bit size through side-channels. Any + // changes must be reviewed by a security expert. + i = len(buf) + for _, d := range z { + for j := 0; j < _S; j++ { + i-- + if i >= 0 { + buf[i] = byte(d) + } else if byte(d) != 0 { + panic("math/big: buffer too small to fit value") + } + d >>= 8 + } + } + + if i < 0 { + i = 0 + } + for i < len(buf) && buf[i] == 0 { + i++ + } + + return +} + +// bigEndianWord returns the contents of buf interpreted as a big-endian encoded Word value. +func bigEndianWord(buf []byte) Word { + if _W == 64 { + return Word(byteorder.BeUint64(buf)) + } + return Word(byteorder.BeUint32(buf)) +} + +// setBytes interprets buf as the bytes of a big-endian unsigned +// integer, sets z to that value, and returns z. +func (z nat) setBytes(buf []byte) nat { + z = z.make((len(buf) + _S - 1) / _S) + + i := len(buf) + for k := 0; i >= _S; k++ { + z[k] = bigEndianWord(buf[i-_S : i]) + i -= _S + } + if i > 0 { + var d Word + for s := uint(0); i > 0; s += 8 { + d |= Word(buf[i-1]) << s + i-- + } + z[len(z)-1] = d + } + + return z.norm() +} + +// sqrt sets z = ⌊√x⌋ +func (z nat) sqrt(x nat) nat { + if x.cmp(natOne) <= 0 { + return z.set(x) + } + if alias(z, x) { + z = nil + } + + // Start with value known to be too large and repeat "z = ⌊(z + ⌊x/z⌋)/2⌋" until it stops getting smaller. + // See Brent and Zimmermann, Modern Computer Arithmetic, Algorithm 1.13 (SqrtInt). + // https://members.loria.fr/PZimmermann/mca/pub226.html + // If x is one less than a perfect square, the sequence oscillates between the correct z and z+1; + // otherwise it converges to the correct z and stays there. + var z1, z2 nat + z1 = z + z1 = z1.setUint64(1) + z1 = z1.shl(z1, uint(x.bitLen()+1)/2) // must be ≥ √x + for n := 0; ; n++ { + z2, _ = z2.div(nil, x, z1) + z2 = z2.add(z2, z1) + z2 = z2.shr(z2, 1) + if z2.cmp(z1) >= 0 { + // z1 is answer. + // Figure out whether z1 or z2 is currently aliased to z by looking at loop count. + if n&1 == 0 { + return z1 + } + return z.set(z1) + } + z1, z2 = z2, z1 + } +} + +// subMod2N returns z = (x - y) mod 2ⁿ. +func (z nat) subMod2N(x, y nat, n uint) nat { + if uint(x.bitLen()) > n { + if alias(z, x) { + // ok to overwrite x in place + x = x.trunc(x, n) + } else { + x = nat(nil).trunc(x, n) + } + } + if uint(y.bitLen()) > n { + if alias(z, y) { + // ok to overwrite y in place + y = y.trunc(y, n) + } else { + y = nat(nil).trunc(y, n) + } + } + if x.cmp(y) >= 0 { + return z.sub(x, y) + } + // x - y < 0; x - y mod 2ⁿ = x - y + 2ⁿ = 2ⁿ - (y - x) = 1 + 2ⁿ-1 - (y - x) = 1 + ^(y - x). + z = z.sub(y, x) + for uint(len(z))*_W < n { + z = append(z, 0) + } + for i := range z { + z[i] = ^z[i] + } + z = z.trunc(z, n) + return z.add(z, natOne) +} diff --git a/contrib/go/_std_1.22/src/math/big/natconv.go b/contrib/go/_std_1.23/src/math/big/natconv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/natconv.go rename to contrib/go/_std_1.23/src/math/big/natconv.go diff --git a/contrib/go/_std_1.22/src/math/big/natdiv.go b/contrib/go/_std_1.23/src/math/big/natdiv.go similarity index 99% rename from contrib/go/_std_1.22/src/math/big/natdiv.go rename to contrib/go/_std_1.23/src/math/big/natdiv.go index 14233a2ddb57..b55f9990cd59 100644 --- a/contrib/go/_std_1.22/src/math/big/natdiv.go +++ b/contrib/go/_std_1.23/src/math/big/natdiv.go @@ -392,7 +392,7 @@ Proof that q ≤ q̂: ≥ (1/y)·((x₁ - y₁ + 1)·S - x) [above: q̂·y₁ ≥ x₁ - y₁ + 1] = (1/y)·(x₁·S - y₁·S + S - x) [distribute S] = (1/y)·(S - x₀ - y₁·S) [-x = -x₁·S - x₀] - > -y₁·S / y [x₀ < S, so S - x₀ < 0; drop it] + > -y₁·S / y [x₀ < S, so S - x₀ > 0; drop it] ≥ -1 [y₁·S ≤ y] So q̂ - q > -1. @@ -734,7 +734,7 @@ func (z nat) divRecursive(u, v nat) { tmp := getNat(3 * len(v)) temps := make([]*nat, recDepth) - z.clear() + clear(z) z.divRecursiveStep(u, v, 0, tmp, temps) // Free temporaries. @@ -758,7 +758,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { u = u.norm() v = v.norm() if len(u) == 0 { - z.clear() + clear(z) return } @@ -816,7 +816,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { // Compute the 2-by-1 guess q̂, leaving r̂ in uu[s:B+n]. qhat := *temps[depth] - qhat.clear() + clear(qhat) qhat.divRecursiveStep(uu[s:B+n], v[s:], depth+1, tmp, temps) qhat = qhat.norm() @@ -833,7 +833,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { // But we can do the subtraction directly, as in the comment above // and in long division, because we know that q̂ is wrong by at most one. qhatv := tmp.make(3 * n) - qhatv.clear() + clear(qhatv) qhatv = qhatv.mul(qhat, v[:s]) for i := 0; i < 2; i++ { e := qhatv.cmp(uu.norm()) @@ -864,11 +864,11 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { // Choose shift = B-1 again. s := B - 1 qhat := *temps[depth] - qhat.clear() + clear(qhat) qhat.divRecursiveStep(u[s:].norm(), v[s:], depth+1, tmp, temps) qhat = qhat.norm() qhatv := tmp.make(3 * n) - qhatv.clear() + clear(qhatv) qhatv = qhatv.mul(qhat, v[:s]) // Set the correct remainder as before. for i := 0; i < 2; i++ { diff --git a/contrib/go/_std_1.22/src/math/big/prime.go b/contrib/go/_std_1.23/src/math/big/prime.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/prime.go rename to contrib/go/_std_1.23/src/math/big/prime.go diff --git a/contrib/go/_std_1.22/src/math/big/rat.go b/contrib/go/_std_1.23/src/math/big/rat.go similarity index 99% rename from contrib/go/_std_1.22/src/math/big/rat.go rename to contrib/go/_std_1.23/src/math/big/rat.go index cb32b783a1b0..e58433ecea33 100644 --- a/contrib/go/_std_1.22/src/math/big/rat.go +++ b/contrib/go/_std_1.23/src/math/big/rat.go @@ -388,10 +388,9 @@ func (z *Rat) Inv(x *Rat) *Rat { } // Sign returns: -// -// -1 if x < 0 -// 0 if x == 0 -// +1 if x > 0 +// - -1 if x < 0; +// - 0 if x == 0; +// - +1 if x > 0. func (x *Rat) Sign() int { return x.a.Sign() } @@ -477,10 +476,9 @@ func (z *Int) scaleDenom(x *Int, f nat) { } // Cmp compares x and y and returns: -// -// -1 if x < y -// 0 if x == y -// +1 if x > y +// - -1 if x < y; +// - 0 if x == y; +// - +1 if x > y. func (x *Rat) Cmp(y *Rat) int { var a, b Int a.scaleDenom(&x.a, y.b.abs) diff --git a/contrib/go/_std_1.22/src/math/big/ratconv.go b/contrib/go/_std_1.23/src/math/big/ratconv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/ratconv.go rename to contrib/go/_std_1.23/src/math/big/ratconv.go diff --git a/contrib/go/_std_1.22/src/math/big/ratmarsh.go b/contrib/go/_std_1.23/src/math/big/ratmarsh.go similarity index 94% rename from contrib/go/_std_1.22/src/math/big/ratmarsh.go rename to contrib/go/_std_1.23/src/math/big/ratmarsh.go index 033fb4459df8..69628294531f 100644 --- a/contrib/go/_std_1.22/src/math/big/ratmarsh.go +++ b/contrib/go/_std_1.23/src/math/big/ratmarsh.go @@ -7,9 +7,9 @@ package big import ( - "encoding/binary" "errors" "fmt" + "internal/byteorder" "math" ) @@ -29,7 +29,7 @@ func (x *Rat) GobEncode() ([]byte, error) { // this should never happen return nil, errors.New("Rat.GobEncode: numerator too large") } - binary.BigEndian.PutUint32(buf[j-4:j], uint32(n)) + byteorder.BePutUint32(buf[j-4:j], uint32(n)) j -= 1 + 4 b := ratGobVersion << 1 // make space for sign bit if x.a.neg { @@ -54,7 +54,7 @@ func (z *Rat) GobDecode(buf []byte) error { return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) } const j = 1 + 4 - ln := binary.BigEndian.Uint32(buf[j-4 : j]) + ln := byteorder.BeUint32(buf[j-4 : j]) if uint64(ln) > math.MaxInt-j { return errors.New("Rat.GobDecode: invalid length") } diff --git a/contrib/go/_std_1.22/src/math/big/roundingmode_string.go b/contrib/go/_std_1.23/src/math/big/roundingmode_string.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/roundingmode_string.go rename to contrib/go/_std_1.23/src/math/big/roundingmode_string.go diff --git a/contrib/go/_std_1.22/src/math/big/sqrt.go b/contrib/go/_std_1.23/src/math/big/sqrt.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/sqrt.go rename to contrib/go/_std_1.23/src/math/big/sqrt.go diff --git a/contrib/go/_std_1.23/src/math/big/ya.make b/contrib/go/_std_1.23/src/math/big/ya.make new file mode 100644 index 000000000000..554c2ccf5fd8 --- /dev/null +++ b/contrib/go/_std_1.23/src/math/big/ya.make @@ -0,0 +1,79 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + accuracy_string.go + arith.go + arith_arm64.s + arith_decl.go + decimal.go + doc.go + float.go + floatconv.go + floatmarsh.go + ftoa.go + int.go + intconv.go + intmarsh.go + nat.go + natconv.go + natdiv.go + prime.go + rat.go + ratconv.go + ratmarsh.go + roundingmode_string.go + sqrt.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + accuracy_string.go + arith.go + arith_amd64.go + arith_amd64.s + arith_decl.go + decimal.go + doc.go + float.go + floatconv.go + floatmarsh.go + ftoa.go + int.go + intconv.go + intmarsh.go + nat.go + natconv.go + natdiv.go + prime.go + rat.go + ratconv.go + ratmarsh.go + roundingmode_string.go + sqrt.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + accuracy_string.go + arith.go + arith_arm.s + arith_decl.go + decimal.go + doc.go + float.go + floatconv.go + floatmarsh.go + ftoa.go + int.go + intconv.go + intmarsh.go + nat.go + natconv.go + natdiv.go + prime.go + rat.go + ratconv.go + ratmarsh.go + roundingmode_string.go + sqrt.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/math/bits.go b/contrib/go/_std_1.23/src/math/bits.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits.go rename to contrib/go/_std_1.23/src/math/bits.go diff --git a/contrib/go/_std_1.22/src/math/bits/bits.go b/contrib/go/_std_1.23/src/math/bits/bits.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/bits.go rename to contrib/go/_std_1.23/src/math/bits/bits.go diff --git a/contrib/go/_std_1.22/src/math/bits/bits_errors.go b/contrib/go/_std_1.23/src/math/bits/bits_errors.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/bits_errors.go rename to contrib/go/_std_1.23/src/math/bits/bits_errors.go diff --git a/contrib/go/_std_1.22/src/math/bits/bits_errors_bootstrap.go b/contrib/go/_std_1.23/src/math/bits/bits_errors_bootstrap.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/bits_errors_bootstrap.go rename to contrib/go/_std_1.23/src/math/bits/bits_errors_bootstrap.go diff --git a/contrib/go/_std_1.22/src/math/bits/bits_tables.go b/contrib/go/_std_1.23/src/math/bits/bits_tables.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/bits_tables.go rename to contrib/go/_std_1.23/src/math/bits/bits_tables.go diff --git a/contrib/go/_std_1.22/src/math/bits/make_examples.go b/contrib/go/_std_1.23/src/math/bits/make_examples.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/make_examples.go rename to contrib/go/_std_1.23/src/math/bits/make_examples.go diff --git a/contrib/go/_std_1.22/src/math/bits/make_tables.go b/contrib/go/_std_1.23/src/math/bits/make_tables.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/make_tables.go rename to contrib/go/_std_1.23/src/math/bits/make_tables.go diff --git a/contrib/go/_std_1.22/src/math/bits/ya.make b/contrib/go/_std_1.23/src/math/bits/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/ya.make rename to contrib/go/_std_1.23/src/math/bits/ya.make diff --git a/contrib/go/_std_1.22/src/math/cbrt.go b/contrib/go/_std_1.23/src/math/cbrt.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cbrt.go rename to contrib/go/_std_1.23/src/math/cbrt.go diff --git a/contrib/go/_std_1.22/src/math/cbrt_s390x.s b/contrib/go/_std_1.23/src/math/cbrt_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/cbrt_s390x.s rename to contrib/go/_std_1.23/src/math/cbrt_s390x.s diff --git a/contrib/go/_std_1.22/src/math/cmplx/abs.go b/contrib/go/_std_1.23/src/math/cmplx/abs.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/abs.go rename to contrib/go/_std_1.23/src/math/cmplx/abs.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/asin.go b/contrib/go/_std_1.23/src/math/cmplx/asin.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/asin.go rename to contrib/go/_std_1.23/src/math/cmplx/asin.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/conj.go b/contrib/go/_std_1.23/src/math/cmplx/conj.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/conj.go rename to contrib/go/_std_1.23/src/math/cmplx/conj.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/exp.go b/contrib/go/_std_1.23/src/math/cmplx/exp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/exp.go rename to contrib/go/_std_1.23/src/math/cmplx/exp.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/isinf.go b/contrib/go/_std_1.23/src/math/cmplx/isinf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/isinf.go rename to contrib/go/_std_1.23/src/math/cmplx/isinf.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/isnan.go b/contrib/go/_std_1.23/src/math/cmplx/isnan.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/isnan.go rename to contrib/go/_std_1.23/src/math/cmplx/isnan.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/log.go b/contrib/go/_std_1.23/src/math/cmplx/log.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/log.go rename to contrib/go/_std_1.23/src/math/cmplx/log.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/phase.go b/contrib/go/_std_1.23/src/math/cmplx/phase.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/phase.go rename to contrib/go/_std_1.23/src/math/cmplx/phase.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/polar.go b/contrib/go/_std_1.23/src/math/cmplx/polar.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/polar.go rename to contrib/go/_std_1.23/src/math/cmplx/polar.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/pow.go b/contrib/go/_std_1.23/src/math/cmplx/pow.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/pow.go rename to contrib/go/_std_1.23/src/math/cmplx/pow.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/rect.go b/contrib/go/_std_1.23/src/math/cmplx/rect.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/rect.go rename to contrib/go/_std_1.23/src/math/cmplx/rect.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/sin.go b/contrib/go/_std_1.23/src/math/cmplx/sin.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/sin.go rename to contrib/go/_std_1.23/src/math/cmplx/sin.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/sqrt.go b/contrib/go/_std_1.23/src/math/cmplx/sqrt.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/sqrt.go rename to contrib/go/_std_1.23/src/math/cmplx/sqrt.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/tan.go b/contrib/go/_std_1.23/src/math/cmplx/tan.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/tan.go rename to contrib/go/_std_1.23/src/math/cmplx/tan.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/ya.make b/contrib/go/_std_1.23/src/math/cmplx/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/ya.make rename to contrib/go/_std_1.23/src/math/cmplx/ya.make diff --git a/contrib/go/_std_1.22/src/math/const.go b/contrib/go/_std_1.23/src/math/const.go similarity index 100% rename from contrib/go/_std_1.22/src/math/const.go rename to contrib/go/_std_1.23/src/math/const.go diff --git a/contrib/go/_std_1.22/src/math/copysign.go b/contrib/go/_std_1.23/src/math/copysign.go similarity index 100% rename from contrib/go/_std_1.22/src/math/copysign.go rename to contrib/go/_std_1.23/src/math/copysign.go diff --git a/contrib/go/_std_1.22/src/math/cosh_s390x.s b/contrib/go/_std_1.23/src/math/cosh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/cosh_s390x.s rename to contrib/go/_std_1.23/src/math/cosh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/dim.go b/contrib/go/_std_1.23/src/math/dim.go similarity index 100% rename from contrib/go/_std_1.22/src/math/dim.go rename to contrib/go/_std_1.23/src/math/dim.go diff --git a/contrib/go/_std_1.22/src/math/dim_amd64.s b/contrib/go/_std_1.23/src/math/dim_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_amd64.s rename to contrib/go/_std_1.23/src/math/dim_amd64.s diff --git a/contrib/go/_std_1.22/src/math/dim_arm64.s b/contrib/go/_std_1.23/src/math/dim_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_arm64.s rename to contrib/go/_std_1.23/src/math/dim_arm64.s diff --git a/contrib/go/_std_1.22/src/math/dim_asm.go b/contrib/go/_std_1.23/src/math/dim_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_asm.go rename to contrib/go/_std_1.23/src/math/dim_asm.go diff --git a/contrib/go/_std_1.22/src/math/dim_noasm.go b/contrib/go/_std_1.23/src/math/dim_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_noasm.go rename to contrib/go/_std_1.23/src/math/dim_noasm.go diff --git a/contrib/go/_std_1.22/src/math/dim_riscv64.s b/contrib/go/_std_1.23/src/math/dim_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_riscv64.s rename to contrib/go/_std_1.23/src/math/dim_riscv64.s diff --git a/contrib/go/_std_1.22/src/math/dim_s390x.s b/contrib/go/_std_1.23/src/math/dim_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_s390x.s rename to contrib/go/_std_1.23/src/math/dim_s390x.s diff --git a/contrib/go/_std_1.22/src/math/erf.go b/contrib/go/_std_1.23/src/math/erf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/erf.go rename to contrib/go/_std_1.23/src/math/erf.go diff --git a/contrib/go/_std_1.22/src/math/erf_s390x.s b/contrib/go/_std_1.23/src/math/erf_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/erf_s390x.s rename to contrib/go/_std_1.23/src/math/erf_s390x.s diff --git a/contrib/go/_std_1.22/src/math/erfc_s390x.s b/contrib/go/_std_1.23/src/math/erfc_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/erfc_s390x.s rename to contrib/go/_std_1.23/src/math/erfc_s390x.s diff --git a/contrib/go/_std_1.22/src/math/erfinv.go b/contrib/go/_std_1.23/src/math/erfinv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/erfinv.go rename to contrib/go/_std_1.23/src/math/erfinv.go diff --git a/contrib/go/_std_1.22/src/math/exp.go b/contrib/go/_std_1.23/src/math/exp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp.go rename to contrib/go/_std_1.23/src/math/exp.go diff --git a/contrib/go/_std_1.22/src/math/exp2_asm.go b/contrib/go/_std_1.23/src/math/exp2_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp2_asm.go rename to contrib/go/_std_1.23/src/math/exp2_asm.go diff --git a/contrib/go/_std_1.22/src/math/exp2_noasm.go b/contrib/go/_std_1.23/src/math/exp2_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp2_noasm.go rename to contrib/go/_std_1.23/src/math/exp2_noasm.go diff --git a/contrib/go/_std_1.22/src/math/exp_amd64.go b/contrib/go/_std_1.23/src/math/exp_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_amd64.go rename to contrib/go/_std_1.23/src/math/exp_amd64.go diff --git a/contrib/go/_std_1.22/src/math/exp_amd64.s b/contrib/go/_std_1.23/src/math/exp_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_amd64.s rename to contrib/go/_std_1.23/src/math/exp_amd64.s diff --git a/contrib/go/_std_1.22/src/math/exp_arm64.s b/contrib/go/_std_1.23/src/math/exp_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_arm64.s rename to contrib/go/_std_1.23/src/math/exp_arm64.s diff --git a/contrib/go/_std_1.22/src/math/exp_asm.go b/contrib/go/_std_1.23/src/math/exp_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_asm.go rename to contrib/go/_std_1.23/src/math/exp_asm.go diff --git a/contrib/go/_std_1.22/src/math/exp_noasm.go b/contrib/go/_std_1.23/src/math/exp_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_noasm.go rename to contrib/go/_std_1.23/src/math/exp_noasm.go diff --git a/contrib/go/_std_1.22/src/math/exp_s390x.s b/contrib/go/_std_1.23/src/math/exp_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_s390x.s rename to contrib/go/_std_1.23/src/math/exp_s390x.s diff --git a/contrib/go/_std_1.22/src/math/expm1.go b/contrib/go/_std_1.23/src/math/expm1.go similarity index 100% rename from contrib/go/_std_1.22/src/math/expm1.go rename to contrib/go/_std_1.23/src/math/expm1.go diff --git a/contrib/go/_std_1.22/src/math/expm1_s390x.s b/contrib/go/_std_1.23/src/math/expm1_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/expm1_s390x.s rename to contrib/go/_std_1.23/src/math/expm1_s390x.s diff --git a/contrib/go/_std_1.22/src/math/floor.go b/contrib/go/_std_1.23/src/math/floor.go similarity index 100% rename from contrib/go/_std_1.22/src/math/floor.go rename to contrib/go/_std_1.23/src/math/floor.go diff --git a/contrib/go/_std_1.22/src/math/floor_386.s b/contrib/go/_std_1.23/src/math/floor_386.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_386.s rename to contrib/go/_std_1.23/src/math/floor_386.s diff --git a/contrib/go/_std_1.22/src/math/floor_amd64.s b/contrib/go/_std_1.23/src/math/floor_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_amd64.s rename to contrib/go/_std_1.23/src/math/floor_amd64.s diff --git a/contrib/go/_std_1.22/src/math/floor_arm64.s b/contrib/go/_std_1.23/src/math/floor_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_arm64.s rename to contrib/go/_std_1.23/src/math/floor_arm64.s diff --git a/contrib/go/_std_1.22/src/math/floor_asm.go b/contrib/go/_std_1.23/src/math/floor_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_asm.go rename to contrib/go/_std_1.23/src/math/floor_asm.go diff --git a/contrib/go/_std_1.22/src/math/floor_noasm.go b/contrib/go/_std_1.23/src/math/floor_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_noasm.go rename to contrib/go/_std_1.23/src/math/floor_noasm.go diff --git a/contrib/go/_std_1.22/src/math/floor_ppc64x.s b/contrib/go/_std_1.23/src/math/floor_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_ppc64x.s rename to contrib/go/_std_1.23/src/math/floor_ppc64x.s diff --git a/contrib/go/_std_1.22/src/math/floor_s390x.s b/contrib/go/_std_1.23/src/math/floor_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_s390x.s rename to contrib/go/_std_1.23/src/math/floor_s390x.s diff --git a/contrib/go/_std_1.22/src/math/floor_wasm.s b/contrib/go/_std_1.23/src/math/floor_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_wasm.s rename to contrib/go/_std_1.23/src/math/floor_wasm.s diff --git a/contrib/go/_std_1.22/src/math/fma.go b/contrib/go/_std_1.23/src/math/fma.go similarity index 100% rename from contrib/go/_std_1.22/src/math/fma.go rename to contrib/go/_std_1.23/src/math/fma.go diff --git a/contrib/go/_std_1.22/src/math/frexp.go b/contrib/go/_std_1.23/src/math/frexp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/frexp.go rename to contrib/go/_std_1.23/src/math/frexp.go diff --git a/contrib/go/_std_1.22/src/math/gamma.go b/contrib/go/_std_1.23/src/math/gamma.go similarity index 100% rename from contrib/go/_std_1.22/src/math/gamma.go rename to contrib/go/_std_1.23/src/math/gamma.go diff --git a/contrib/go/_std_1.22/src/math/hypot.go b/contrib/go/_std_1.23/src/math/hypot.go similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot.go rename to contrib/go/_std_1.23/src/math/hypot.go diff --git a/contrib/go/_std_1.22/src/math/hypot_386.s b/contrib/go/_std_1.23/src/math/hypot_386.s similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot_386.s rename to contrib/go/_std_1.23/src/math/hypot_386.s diff --git a/contrib/go/_std_1.22/src/math/hypot_amd64.s b/contrib/go/_std_1.23/src/math/hypot_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot_amd64.s rename to contrib/go/_std_1.23/src/math/hypot_amd64.s diff --git a/contrib/go/_std_1.22/src/math/hypot_asm.go b/contrib/go/_std_1.23/src/math/hypot_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot_asm.go rename to contrib/go/_std_1.23/src/math/hypot_asm.go diff --git a/contrib/go/_std_1.22/src/math/hypot_noasm.go b/contrib/go/_std_1.23/src/math/hypot_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot_noasm.go rename to contrib/go/_std_1.23/src/math/hypot_noasm.go diff --git a/contrib/go/_std_1.22/src/math/j0.go b/contrib/go/_std_1.23/src/math/j0.go similarity index 100% rename from contrib/go/_std_1.22/src/math/j0.go rename to contrib/go/_std_1.23/src/math/j0.go diff --git a/contrib/go/_std_1.22/src/math/j1.go b/contrib/go/_std_1.23/src/math/j1.go similarity index 100% rename from contrib/go/_std_1.22/src/math/j1.go rename to contrib/go/_std_1.23/src/math/j1.go diff --git a/contrib/go/_std_1.22/src/math/jn.go b/contrib/go/_std_1.23/src/math/jn.go similarity index 100% rename from contrib/go/_std_1.22/src/math/jn.go rename to contrib/go/_std_1.23/src/math/jn.go diff --git a/contrib/go/_std_1.22/src/math/ldexp.go b/contrib/go/_std_1.23/src/math/ldexp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/ldexp.go rename to contrib/go/_std_1.23/src/math/ldexp.go diff --git a/contrib/go/_std_1.22/src/math/lgamma.go b/contrib/go/_std_1.23/src/math/lgamma.go similarity index 100% rename from contrib/go/_std_1.22/src/math/lgamma.go rename to contrib/go/_std_1.23/src/math/lgamma.go diff --git a/contrib/go/_std_1.22/src/math/log.go b/contrib/go/_std_1.23/src/math/log.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log.go rename to contrib/go/_std_1.23/src/math/log.go diff --git a/contrib/go/_std_1.22/src/math/log10.go b/contrib/go/_std_1.23/src/math/log10.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log10.go rename to contrib/go/_std_1.23/src/math/log10.go diff --git a/contrib/go/_std_1.22/src/math/log10_s390x.s b/contrib/go/_std_1.23/src/math/log10_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/log10_s390x.s rename to contrib/go/_std_1.23/src/math/log10_s390x.s diff --git a/contrib/go/_std_1.22/src/math/log1p.go b/contrib/go/_std_1.23/src/math/log1p.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log1p.go rename to contrib/go/_std_1.23/src/math/log1p.go diff --git a/contrib/go/_std_1.22/src/math/log1p_s390x.s b/contrib/go/_std_1.23/src/math/log1p_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/log1p_s390x.s rename to contrib/go/_std_1.23/src/math/log1p_s390x.s diff --git a/contrib/go/_std_1.22/src/math/log_amd64.s b/contrib/go/_std_1.23/src/math/log_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/log_amd64.s rename to contrib/go/_std_1.23/src/math/log_amd64.s diff --git a/contrib/go/_std_1.22/src/math/log_asm.go b/contrib/go/_std_1.23/src/math/log_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log_asm.go rename to contrib/go/_std_1.23/src/math/log_asm.go diff --git a/contrib/go/_std_1.22/src/math/log_s390x.s b/contrib/go/_std_1.23/src/math/log_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/log_s390x.s rename to contrib/go/_std_1.23/src/math/log_s390x.s diff --git a/contrib/go/_std_1.22/src/math/log_stub.go b/contrib/go/_std_1.23/src/math/log_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log_stub.go rename to contrib/go/_std_1.23/src/math/log_stub.go diff --git a/contrib/go/_std_1.22/src/math/logb.go b/contrib/go/_std_1.23/src/math/logb.go similarity index 100% rename from contrib/go/_std_1.22/src/math/logb.go rename to contrib/go/_std_1.23/src/math/logb.go diff --git a/contrib/go/_std_1.22/src/math/mod.go b/contrib/go/_std_1.23/src/math/mod.go similarity index 100% rename from contrib/go/_std_1.22/src/math/mod.go rename to contrib/go/_std_1.23/src/math/mod.go diff --git a/contrib/go/_std_1.22/src/math/modf.go b/contrib/go/_std_1.23/src/math/modf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/modf.go rename to contrib/go/_std_1.23/src/math/modf.go diff --git a/contrib/go/_std_1.22/src/math/modf_arm64.s b/contrib/go/_std_1.23/src/math/modf_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/modf_arm64.s rename to contrib/go/_std_1.23/src/math/modf_arm64.s diff --git a/contrib/go/_std_1.22/src/math/modf_asm.go b/contrib/go/_std_1.23/src/math/modf_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/modf_asm.go rename to contrib/go/_std_1.23/src/math/modf_asm.go diff --git a/contrib/go/_std_1.22/src/math/modf_noasm.go b/contrib/go/_std_1.23/src/math/modf_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/modf_noasm.go rename to contrib/go/_std_1.23/src/math/modf_noasm.go diff --git a/contrib/go/_std_1.22/src/math/modf_ppc64x.s b/contrib/go/_std_1.23/src/math/modf_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/modf_ppc64x.s rename to contrib/go/_std_1.23/src/math/modf_ppc64x.s diff --git a/contrib/go/_std_1.22/src/math/nextafter.go b/contrib/go/_std_1.23/src/math/nextafter.go similarity index 100% rename from contrib/go/_std_1.22/src/math/nextafter.go rename to contrib/go/_std_1.23/src/math/nextafter.go diff --git a/contrib/go/_std_1.22/src/math/pow.go b/contrib/go/_std_1.23/src/math/pow.go similarity index 100% rename from contrib/go/_std_1.22/src/math/pow.go rename to contrib/go/_std_1.23/src/math/pow.go diff --git a/contrib/go/_std_1.22/src/math/pow10.go b/contrib/go/_std_1.23/src/math/pow10.go similarity index 100% rename from contrib/go/_std_1.22/src/math/pow10.go rename to contrib/go/_std_1.23/src/math/pow10.go diff --git a/contrib/go/_std_1.22/src/math/pow_s390x.s b/contrib/go/_std_1.23/src/math/pow_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/pow_s390x.s rename to contrib/go/_std_1.23/src/math/pow_s390x.s diff --git a/contrib/go/_std_1.22/src/math/rand/exp.go b/contrib/go/_std_1.23/src/math/rand/exp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/exp.go rename to contrib/go/_std_1.23/src/math/rand/exp.go diff --git a/contrib/go/_std_1.22/src/math/rand/gen_cooked.go b/contrib/go/_std_1.23/src/math/rand/gen_cooked.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/gen_cooked.go rename to contrib/go/_std_1.23/src/math/rand/gen_cooked.go diff --git a/contrib/go/_std_1.22/src/math/rand/normal.go b/contrib/go/_std_1.23/src/math/rand/normal.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/normal.go rename to contrib/go/_std_1.23/src/math/rand/normal.go diff --git a/contrib/go/_std_1.23/src/math/rand/rand.go b/contrib/go/_std_1.23/src/math/rand/rand.go new file mode 100644 index 000000000000..61ff5c1b387a --- /dev/null +++ b/contrib/go/_std_1.23/src/math/rand/rand.go @@ -0,0 +1,548 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package rand implements pseudo-random number generators suitable for tasks +// such as simulation, but it should not be used for security-sensitive work. +// +// Random numbers are generated by a [Source], usually wrapped in a [Rand]. +// Both types should be used by a single goroutine at a time: sharing among +// multiple goroutines requires some kind of synchronization. +// +// Top-level functions, such as [Float64] and [Int], +// are safe for concurrent use by multiple goroutines. +// +// This package's outputs might be easily predictable regardless of how it's +// seeded. For random numbers suitable for security-sensitive work, see the +// crypto/rand package. +package rand + +import ( + "internal/godebug" + "sync" + "sync/atomic" + _ "unsafe" // for go:linkname +) + +// A Source represents a source of uniformly-distributed +// pseudo-random int64 values in the range [0, 1<<63). +// +// A Source is not safe for concurrent use by multiple goroutines. +type Source interface { + Int63() int64 + Seed(seed int64) +} + +// A Source64 is a [Source] that can also generate +// uniformly-distributed pseudo-random uint64 values in +// the range [0, 1<<64) directly. +// If a [Rand] r's underlying [Source] s implements Source64, +// then r.Uint64 returns the result of one call to s.Uint64 +// instead of making two calls to s.Int63. +type Source64 interface { + Source + Uint64() uint64 +} + +// NewSource returns a new pseudo-random [Source] seeded with the given value. +// Unlike the default [Source] used by top-level functions, this source is not +// safe for concurrent use by multiple goroutines. +// The returned [Source] implements [Source64]. +func NewSource(seed int64) Source { + return newSource(seed) +} + +func newSource(seed int64) *rngSource { + var rng rngSource + rng.Seed(seed) + return &rng +} + +// A Rand is a source of random numbers. +type Rand struct { + src Source + s64 Source64 // non-nil if src is source64 + + // readVal contains remainder of 63-bit integer used for bytes + // generation during most recent Read call. + // It is saved so next Read call can start where the previous + // one finished. + readVal int64 + // readPos indicates the number of low-order bytes of readVal + // that are still valid. + readPos int8 +} + +// New returns a new [Rand] that uses random values from src +// to generate other random values. +func New(src Source) *Rand { + s64, _ := src.(Source64) + return &Rand{src: src, s64: s64} +} + +// Seed uses the provided seed value to initialize the generator to a deterministic state. +// Seed should not be called concurrently with any other [Rand] method. +func (r *Rand) Seed(seed int64) { + if lk, ok := r.src.(*lockedSource); ok { + lk.seedPos(seed, &r.readPos) + return + } + + r.src.Seed(seed) + r.readPos = 0 +} + +// Int63 returns a non-negative pseudo-random 63-bit integer as an int64. +func (r *Rand) Int63() int64 { return r.src.Int63() } + +// Uint32 returns a pseudo-random 32-bit value as a uint32. +func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) } + +// Uint64 returns a pseudo-random 64-bit value as a uint64. +func (r *Rand) Uint64() uint64 { + if r.s64 != nil { + return r.s64.Uint64() + } + return uint64(r.Int63())>>31 | uint64(r.Int63())<<32 +} + +// Int31 returns a non-negative pseudo-random 31-bit integer as an int32. +func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) } + +// Int returns a non-negative pseudo-random int. +func (r *Rand) Int() int { + u := uint(r.Int63()) + return int(u << 1 >> 1) // clear sign bit if int == int32 +} + +// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n <= 0. +func (r *Rand) Int63n(n int64) int64 { + if n <= 0 { + panic("invalid argument to Int63n") + } + if n&(n-1) == 0 { // n is power of two, can mask + return r.Int63() & (n - 1) + } + max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) + v := r.Int63() + for v > max { + v = r.Int63() + } + return v % n +} + +// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n <= 0. +func (r *Rand) Int31n(n int32) int32 { + if n <= 0 { + panic("invalid argument to Int31n") + } + if n&(n-1) == 0 { // n is power of two, can mask + return r.Int31() & (n - 1) + } + max := int32((1 << 31) - 1 - (1<<31)%uint32(n)) + v := r.Int31() + for v > max { + v = r.Int31() + } + return v % n +} + +// int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). +// n must be > 0, but int31n does not check this; the caller must ensure it. +// int31n exists because Int31n is inefficient, but Go 1 compatibility +// requires that the stream of values produced by math/rand remain unchanged. +// int31n can thus only be used internally, by newly introduced APIs. +// +// For implementation details, see: +// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction +// https://lemire.me/blog/2016/06/30/fast-random-shuffling +func (r *Rand) int31n(n int32) int32 { + v := r.Uint32() + prod := uint64(v) * uint64(n) + low := uint32(prod) + if low < uint32(n) { + thresh := uint32(-n) % uint32(n) + for low < thresh { + v = r.Uint32() + prod = uint64(v) * uint64(n) + low = uint32(prod) + } + } + return int32(prod >> 32) +} + +// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n <= 0. +func (r *Rand) Intn(n int) int { + if n <= 0 { + panic("invalid argument to Intn") + } + if n <= 1<<31-1 { + return int(r.Int31n(int32(n))) + } + return int(r.Int63n(int64(n))) +} + +// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0). +func (r *Rand) Float64() float64 { + // A clearer, simpler implementation would be: + // return float64(r.Int63n(1<<53)) / (1<<53) + // However, Go 1 shipped with + // return float64(r.Int63()) / (1 << 63) + // and we want to preserve that value stream. + // + // There is one bug in the value stream: r.Int63() may be so close + // to 1<<63 that the division rounds up to 1.0, and we've guaranteed + // that the result is always less than 1.0. + // + // We tried to fix this by mapping 1.0 back to 0.0, but since float64 + // values near 0 are much denser than near 1, mapping 1 to 0 caused + // a theoretically significant overshoot in the probability of returning 0. + // Instead of that, if we round up to 1, just try again. + // Getting 1 only happens 1/2⁵³ of the time, so most clients + // will not observe it anyway. +again: + f := float64(r.Int63()) / (1 << 63) + if f == 1 { + goto again // resample; this branch is taken O(never) + } + return f +} + +// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0). +func (r *Rand) Float32() float32 { + // Same rationale as in Float64: we want to preserve the Go 1 value + // stream except we want to fix it not to return 1.0 + // This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64). +again: + f := float32(r.Float64()) + if f == 1 { + goto again // resample; this branch is taken O(very rarely) + } + return f +} + +// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers +// in the half-open interval [0,n). +func (r *Rand) Perm(n int) []int { + m := make([]int, n) + // In the following loop, the iteration when i=0 always swaps m[0] with m[0]. + // A change to remove this useless iteration is to assign 1 to i in the init + // statement. But Perm also effects r. Making this change will affect + // the final state of r. So this change can't be made for compatibility + // reasons for Go 1. + for i := 0; i < n; i++ { + j := r.Intn(i + 1) + m[i] = m[j] + m[j] = i + } + return m +} + +// Shuffle pseudo-randomizes the order of elements. +// n is the number of elements. Shuffle panics if n < 0. +// swap swaps the elements with indexes i and j. +func (r *Rand) Shuffle(n int, swap func(i, j int)) { + if n < 0 { + panic("invalid argument to Shuffle") + } + + // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle + // Shuffle really ought not be called with n that doesn't fit in 32 bits. + // Not only will it take a very long time, but with 2³¹! possible permutations, + // there's no way that any PRNG can have a big enough internal state to + // generate even a minuscule percentage of the possible permutations. + // Nevertheless, the right API signature accepts an int n, so handle it as best we can. + i := n - 1 + for ; i > 1<<31-1-1; i-- { + j := int(r.Int63n(int64(i + 1))) + swap(i, j) + } + for ; i > 0; i-- { + j := int(r.int31n(int32(i + 1))) + swap(i, j) + } +} + +// Read generates len(p) random bytes and writes them into p. It +// always returns len(p) and a nil error. +// Read should not be called concurrently with any other Rand method. +func (r *Rand) Read(p []byte) (n int, err error) { + switch src := r.src.(type) { + case *lockedSource: + return src.read(p, &r.readVal, &r.readPos) + case *runtimeSource: + return src.read(p, &r.readVal, &r.readPos) + } + return read(p, r.src, &r.readVal, &r.readPos) +} + +func read(p []byte, src Source, readVal *int64, readPos *int8) (n int, err error) { + pos := *readPos + val := *readVal + rng, _ := src.(*rngSource) + for n = 0; n < len(p); n++ { + if pos == 0 { + if rng != nil { + val = rng.Int63() + } else { + val = src.Int63() + } + pos = 7 + } + p[n] = byte(val) + val >>= 8 + pos-- + } + *readPos = pos + *readVal = val + return +} + +/* + * Top-level convenience functions + */ + +// globalRandGenerator is the source of random numbers for the top-level +// convenience functions. When possible it uses the runtime fastrand64 +// function to avoid locking. This is not possible if the user called Seed, +// either explicitly or implicitly via GODEBUG=randautoseed=0. +var globalRandGenerator atomic.Pointer[Rand] + +var randautoseed = godebug.New("randautoseed") + +// globalRand returns the generator to use for the top-level convenience +// functions. +func globalRand() *Rand { + if r := globalRandGenerator.Load(); r != nil { + return r + } + + // This is the first call. Initialize based on GODEBUG. + var r *Rand + if randautoseed.Value() == "0" { + randautoseed.IncNonDefault() + r = New(new(lockedSource)) + r.Seed(1) + } else { + r = &Rand{ + src: &runtimeSource{}, + s64: &runtimeSource{}, + } + } + + if !globalRandGenerator.CompareAndSwap(nil, r) { + // Two different goroutines called some top-level + // function at the same time. While the results in + // that case are unpredictable, if we just use r here, + // and we are using a seed, we will most likely return + // the same value for both calls. That doesn't seem ideal. + // Just use the first one to get in. + return globalRandGenerator.Load() + } + + return r +} + +//go:linkname runtime_rand runtime.rand +func runtime_rand() uint64 + +// runtimeSource is an implementation of Source64 that uses the runtime +// fastrand functions. +type runtimeSource struct { + // The mutex is used to avoid race conditions in Read. + mu sync.Mutex +} + +func (*runtimeSource) Int63() int64 { + return int64(runtime_rand() & rngMask) +} + +func (*runtimeSource) Seed(int64) { + panic("internal error: call to runtimeSource.Seed") +} + +func (*runtimeSource) Uint64() uint64 { + return runtime_rand() +} + +func (fs *runtimeSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) { + fs.mu.Lock() + n, err = read(p, fs, readVal, readPos) + fs.mu.Unlock() + return +} + +// Seed uses the provided seed value to initialize the default Source to a +// deterministic state. Seed values that have the same remainder when +// divided by 2³¹-1 generate the same pseudo-random sequence. +// Seed, unlike the [Rand.Seed] method, is safe for concurrent use. +// +// If Seed is not called, the generator is seeded randomly at program startup. +// +// Prior to Go 1.20, the generator was seeded like Seed(1) at program startup. +// To force the old behavior, call Seed(1) at program startup. +// Alternately, set GODEBUG=randautoseed=0 in the environment +// before making any calls to functions in this package. +// +// Deprecated: As of Go 1.20 there is no reason to call Seed with +// a random value. Programs that call Seed with a known value to get +// a specific sequence of results should use New(NewSource(seed)) to +// obtain a local random generator. +func Seed(seed int64) { + orig := globalRandGenerator.Load() + + // If we are already using a lockedSource, we can just re-seed it. + if orig != nil { + if _, ok := orig.src.(*lockedSource); ok { + orig.Seed(seed) + return + } + } + + // Otherwise either + // 1) orig == nil, which is the normal case when Seed is the first + // top-level function to be called, or + // 2) orig is already a runtimeSource, in which case we need to change + // to a lockedSource. + // Either way we do the same thing. + + r := New(new(lockedSource)) + r.Seed(seed) + + if !globalRandGenerator.CompareAndSwap(orig, r) { + // Something changed underfoot. Retry to be safe. + Seed(seed) + } +} + +// Int63 returns a non-negative pseudo-random 63-bit integer as an int64 +// from the default [Source]. +func Int63() int64 { return globalRand().Int63() } + +// Uint32 returns a pseudo-random 32-bit value as a uint32 +// from the default [Source]. +func Uint32() uint32 { return globalRand().Uint32() } + +// Uint64 returns a pseudo-random 64-bit value as a uint64 +// from the default [Source]. +func Uint64() uint64 { return globalRand().Uint64() } + +// Int31 returns a non-negative pseudo-random 31-bit integer as an int32 +// from the default [Source]. +func Int31() int32 { return globalRand().Int31() } + +// Int returns a non-negative pseudo-random int from the default [Source]. +func Int() int { return globalRand().Int() } + +// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n) +// from the default [Source]. +// It panics if n <= 0. +func Int63n(n int64) int64 { return globalRand().Int63n(n) } + +// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n) +// from the default [Source]. +// It panics if n <= 0. +func Int31n(n int32) int32 { return globalRand().Int31n(n) } + +// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n) +// from the default [Source]. +// It panics if n <= 0. +func Intn(n int) int { return globalRand().Intn(n) } + +// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0) +// from the default [Source]. +func Float64() float64 { return globalRand().Float64() } + +// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0) +// from the default [Source]. +func Float32() float32 { return globalRand().Float32() } + +// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers +// in the half-open interval [0,n) from the default [Source]. +func Perm(n int) []int { return globalRand().Perm(n) } + +// Shuffle pseudo-randomizes the order of elements using the default [Source]. +// n is the number of elements. Shuffle panics if n < 0. +// swap swaps the elements with indexes i and j. +func Shuffle(n int, swap func(i, j int)) { globalRand().Shuffle(n, swap) } + +// Read generates len(p) random bytes from the default [Source] and +// writes them into p. It always returns len(p) and a nil error. +// Read, unlike the [Rand.Read] method, is safe for concurrent use. +// +// Deprecated: For almost all use cases, [crypto/rand.Read] is more appropriate. +// If a deterministic source is required, use [math/rand/v2.ChaCha8.Read]. +func Read(p []byte) (n int, err error) { return globalRand().Read(p) } + +// NormFloat64 returns a normally distributed float64 in the range +// [-[math.MaxFloat64], +[math.MaxFloat64]] with +// standard normal distribution (mean = 0, stddev = 1) +// from the default [Source]. +// To produce a different normal distribution, callers can +// adjust the output using: +// +// sample = NormFloat64() * desiredStdDev + desiredMean +func NormFloat64() float64 { return globalRand().NormFloat64() } + +// ExpFloat64 returns an exponentially distributed float64 in the range +// (0, +[math.MaxFloat64]] with an exponential distribution whose rate parameter +// (lambda) is 1 and whose mean is 1/lambda (1) from the default [Source]. +// To produce a distribution with a different rate parameter, +// callers can adjust the output using: +// +// sample = ExpFloat64() / desiredRateParameter +func ExpFloat64() float64 { return globalRand().ExpFloat64() } + +type lockedSource struct { + lk sync.Mutex + s *rngSource +} + +func (r *lockedSource) Int63() (n int64) { + r.lk.Lock() + n = r.s.Int63() + r.lk.Unlock() + return +} + +func (r *lockedSource) Uint64() (n uint64) { + r.lk.Lock() + n = r.s.Uint64() + r.lk.Unlock() + return +} + +func (r *lockedSource) Seed(seed int64) { + r.lk.Lock() + r.seed(seed) + r.lk.Unlock() +} + +// seedPos implements Seed for a lockedSource without a race condition. +func (r *lockedSource) seedPos(seed int64, readPos *int8) { + r.lk.Lock() + r.seed(seed) + *readPos = 0 + r.lk.Unlock() +} + +// seed seeds the underlying source. +// The caller must have locked r.lk. +func (r *lockedSource) seed(seed int64) { + if r.s == nil { + r.s = newSource(seed) + } else { + r.s.Seed(seed) + } +} + +// read implements Read for a lockedSource without a race condition. +func (r *lockedSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) { + r.lk.Lock() + n, err = read(p, r.s, readVal, readPos) + r.lk.Unlock() + return +} diff --git a/contrib/go/_std_1.22/src/math/rand/rng.go b/contrib/go/_std_1.23/src/math/rand/rng.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/rng.go rename to contrib/go/_std_1.23/src/math/rand/rng.go diff --git a/contrib/go/_std_1.23/src/math/rand/v2/chacha8.go b/contrib/go/_std_1.23/src/math/rand/v2/chacha8.go new file mode 100644 index 000000000000..f9eaacf6017f --- /dev/null +++ b/contrib/go/_std_1.23/src/math/rand/v2/chacha8.go @@ -0,0 +1,110 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rand + +import ( + "errors" + "internal/byteorder" + "internal/chacha8rand" +) + +// A ChaCha8 is a ChaCha8-based cryptographically strong +// random number generator. +type ChaCha8 struct { + state chacha8rand.State + + // The last readLen bytes of readBuf are still to be consumed by Read. + readBuf [8]byte + readLen int // 0 <= readLen <= 8 +} + +// NewChaCha8 returns a new ChaCha8 seeded with the given seed. +func NewChaCha8(seed [32]byte) *ChaCha8 { + c := new(ChaCha8) + c.state.Init(seed) + return c +} + +// Seed resets the ChaCha8 to behave the same way as NewChaCha8(seed). +func (c *ChaCha8) Seed(seed [32]byte) { + c.state.Init(seed) + c.readLen = 0 + c.readBuf = [8]byte{} +} + +// Uint64 returns a uniformly distributed random uint64 value. +func (c *ChaCha8) Uint64() uint64 { + for { + x, ok := c.state.Next() + if ok { + return x + } + c.state.Refill() + } +} + +// Read reads exactly len(p) bytes into p. +// It always returns len(p) and a nil error. +// +// If calls to Read and Uint64 are interleaved, the order in which bits are +// returned by the two is undefined, and Read may return bits generated before +// the last call to Uint64. +func (c *ChaCha8) Read(p []byte) (n int, err error) { + if c.readLen > 0 { + n = copy(p, c.readBuf[len(c.readBuf)-c.readLen:]) + c.readLen -= n + p = p[n:] + } + for len(p) >= 8 { + byteorder.LePutUint64(p, c.Uint64()) + p = p[8:] + n += 8 + } + if len(p) > 0 { + byteorder.LePutUint64(c.readBuf[:], c.Uint64()) + n += copy(p, c.readBuf[:]) + c.readLen = 8 - len(p) + } + return +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +func (c *ChaCha8) UnmarshalBinary(data []byte) error { + data, ok := cutPrefix(data, []byte("readbuf:")) + if ok { + var buf []byte + buf, data, ok = readUint8LengthPrefixed(data) + if !ok { + return errors.New("invalid ChaCha8 Read buffer encoding") + } + c.readLen = copy(c.readBuf[len(c.readBuf)-len(buf):], buf) + } + return chacha8rand.Unmarshal(&c.state, data) +} + +func cutPrefix(s, prefix []byte) (after []byte, found bool) { + if len(s) < len(prefix) || string(s[:len(prefix)]) != string(prefix) { + return s, false + } + return s[len(prefix):], true +} + +func readUint8LengthPrefixed(b []byte) (buf, rest []byte, ok bool) { + if len(b) == 0 || len(b) < int(1+b[0]) { + return nil, nil, false + } + return b[1 : 1+b[0]], b[1+b[0]:], true +} + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (c *ChaCha8) MarshalBinary() ([]byte, error) { + if c.readLen > 0 { + out := []byte("readbuf:") + out = append(out, uint8(c.readLen)) + out = append(out, c.readBuf[len(c.readBuf)-c.readLen:]...) + return append(out, chacha8rand.Marshal(&c.state)...), nil + } + return chacha8rand.Marshal(&c.state), nil +} diff --git a/contrib/go/_std_1.22/src/math/rand/v2/exp.go b/contrib/go/_std_1.23/src/math/rand/v2/exp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/v2/exp.go rename to contrib/go/_std_1.23/src/math/rand/v2/exp.go diff --git a/contrib/go/_std_1.22/src/math/rand/v2/normal.go b/contrib/go/_std_1.23/src/math/rand/v2/normal.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/v2/normal.go rename to contrib/go/_std_1.23/src/math/rand/v2/normal.go diff --git a/contrib/go/_std_1.22/src/math/rand/v2/pcg.go b/contrib/go/_std_1.23/src/math/rand/v2/pcg.go similarity index 78% rename from contrib/go/_std_1.22/src/math/rand/v2/pcg.go rename to contrib/go/_std_1.23/src/math/rand/v2/pcg.go index 77708d799e26..4ccd5e320b97 100644 --- a/contrib/go/_std_1.22/src/math/rand/v2/pcg.go +++ b/contrib/go/_std_1.23/src/math/rand/v2/pcg.go @@ -6,6 +6,7 @@ package rand import ( "errors" + "internal/byteorder" "math/bits" ) @@ -30,32 +31,12 @@ func (p *PCG) Seed(seed1, seed2 uint64) { p.lo = seed2 } -// binary.bigEndian.Uint64, copied to avoid dependency -func beUint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 -} - -// binary.bigEndian.PutUint64, copied to avoid dependency -func bePutUint64(b []byte, v uint64) { - _ = b[7] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 56) - b[1] = byte(v >> 48) - b[2] = byte(v >> 40) - b[3] = byte(v >> 32) - b[4] = byte(v >> 24) - b[5] = byte(v >> 16) - b[6] = byte(v >> 8) - b[7] = byte(v) -} - // MarshalBinary implements the encoding.BinaryMarshaler interface. func (p *PCG) MarshalBinary() ([]byte, error) { b := make([]byte, 20) copy(b, "pcg:") - bePutUint64(b[4:], p.hi) - bePutUint64(b[4+8:], p.lo) + byteorder.BePutUint64(b[4:], p.hi) + byteorder.BePutUint64(b[4+8:], p.lo) return b, nil } @@ -66,8 +47,8 @@ func (p *PCG) UnmarshalBinary(data []byte) error { if len(data) != 20 || string(data[:4]) != "pcg:" { return errUnmarshalPCG } - p.hi = beUint64(data[4:]) - p.lo = beUint64(data[4+8:]) + p.hi = byteorder.BeUint64(data[4:]) + p.lo = byteorder.BeUint64(data[4+8:]) return nil } diff --git a/contrib/go/_std_1.23/src/math/rand/v2/rand.go b/contrib/go/_std_1.23/src/math/rand/v2/rand.go new file mode 100644 index 000000000000..fea1e3a2ba20 --- /dev/null +++ b/contrib/go/_std_1.23/src/math/rand/v2/rand.go @@ -0,0 +1,369 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package rand implements pseudo-random number generators suitable for tasks +// such as simulation, but it should not be used for security-sensitive work. +// +// Random numbers are generated by a [Source], usually wrapped in a [Rand]. +// Both types should be used by a single goroutine at a time: sharing among +// multiple goroutines requires some kind of synchronization. +// +// Top-level functions, such as [Float64] and [Int], +// are safe for concurrent use by multiple goroutines. +// +// This package's outputs might be easily predictable regardless of how it's +// seeded. For random numbers suitable for security-sensitive work, see the +// [crypto/rand] package. +package rand + +import ( + "math/bits" + _ "unsafe" // for go:linkname +) + +// A Source is a source of uniformly-distributed +// pseudo-random uint64 values in the range [0, 1<<64). +// +// A Source is not safe for concurrent use by multiple goroutines. +type Source interface { + Uint64() uint64 +} + +// A Rand is a source of random numbers. +type Rand struct { + src Source +} + +// New returns a new Rand that uses random values from src +// to generate other random values. +func New(src Source) *Rand { + return &Rand{src: src} +} + +// Int64 returns a non-negative pseudo-random 63-bit integer as an int64. +func (r *Rand) Int64() int64 { return int64(r.src.Uint64() &^ (1 << 63)) } + +// Uint32 returns a pseudo-random 32-bit value as a uint32. +func (r *Rand) Uint32() uint32 { return uint32(r.src.Uint64() >> 32) } + +// Uint64 returns a pseudo-random 64-bit value as a uint64. +func (r *Rand) Uint64() uint64 { return r.src.Uint64() } + +// Int32 returns a non-negative pseudo-random 31-bit integer as an int32. +func (r *Rand) Int32() int32 { return int32(r.src.Uint64() >> 33) } + +// Int returns a non-negative pseudo-random int. +func (r *Rand) Int() int { return int(uint(r.src.Uint64()) << 1 >> 1) } + +// Uint returns a pseudo-random uint. +func (r *Rand) Uint() uint { return uint(r.src.Uint64()) } + +// Int64N returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n <= 0. +func (r *Rand) Int64N(n int64) int64 { + if n <= 0 { + panic("invalid argument to Int64N") + } + return int64(r.uint64n(uint64(n))) +} + +// Uint64N returns, as a uint64, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n == 0. +func (r *Rand) Uint64N(n uint64) uint64 { + if n == 0 { + panic("invalid argument to Uint64N") + } + return r.uint64n(n) +} + +// uint64n is the no-bounds-checks version of Uint64N. +func (r *Rand) uint64n(n uint64) uint64 { + if is32bit && uint64(uint32(n)) == n { + return uint64(r.uint32n(uint32(n))) + } + if n&(n-1) == 0 { // n is power of two, can mask + return r.Uint64() & (n - 1) + } + + // Suppose we have a uint64 x uniform in the range [0,2⁶⁴) + // and want to reduce it to the range [0,n) preserving exact uniformity. + // We can simulate a scaling arbitrary precision x * (n/2⁶⁴) by + // the high bits of a double-width multiply of x*n, meaning (x*n)/2⁶⁴. + // Since there are 2⁶⁴ possible inputs x and only n possible outputs, + // the output is necessarily biased if n does not divide 2⁶⁴. + // In general (x*n)/2⁶⁴ = k for x*n in [k*2⁶⁴,(k+1)*2⁶⁴). + // There are either floor(2⁶⁴/n) or ceil(2⁶⁴/n) possible products + // in that range, depending on k. + // But suppose we reject the sample and try again when + // x*n is in [k*2⁶⁴, k*2⁶⁴+(2⁶⁴%n)), meaning rejecting fewer than n possible + // outcomes out of the 2⁶⁴. + // Now there are exactly floor(2⁶⁴/n) possible ways to produce + // each output value k, so we've restored uniformity. + // To get valid uint64 math, 2⁶⁴ % n = (2⁶⁴ - n) % n = -n % n, + // so the direct implementation of this algorithm would be: + // + // hi, lo := bits.Mul64(r.Uint64(), n) + // thresh := -n % n + // for lo < thresh { + // hi, lo = bits.Mul64(r.Uint64(), n) + // } + // + // That still leaves an expensive 64-bit division that we would rather avoid. + // We know that thresh < n, and n is usually much less than 2⁶⁴, so we can + // avoid the last four lines unless lo < n. + // + // See also: + // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction + // https://lemire.me/blog/2016/06/30/fast-random-shuffling + hi, lo := bits.Mul64(r.Uint64(), n) + if lo < n { + thresh := -n % n + for lo < thresh { + hi, lo = bits.Mul64(r.Uint64(), n) + } + } + return hi +} + +// uint32n is an identical computation to uint64n +// but optimized for 32-bit systems. +func (r *Rand) uint32n(n uint32) uint32 { + if n&(n-1) == 0 { // n is power of two, can mask + return uint32(r.Uint64()) & (n - 1) + } + // On 64-bit systems we still use the uint64 code below because + // the probability of a random uint64 lo being < a uint32 n is near zero, + // meaning the unbiasing loop almost never runs. + // On 32-bit systems, here we need to implement that same logic in 32-bit math, + // both to preserve the exact output sequence observed on 64-bit machines + // and to preserve the optimization that the unbiasing loop almost never runs. + // + // We want to compute + // hi, lo := bits.Mul64(r.Uint64(), n) + // In terms of 32-bit halves, this is: + // x1:x0 := r.Uint64() + // 0:hi, lo1:lo0 := bits.Mul64(x1:x0, 0:n) + // Writing out the multiplication in terms of bits.Mul32 allows + // using direct hardware instructions and avoiding + // the computations involving these zeros. + x := r.Uint64() + lo1a, lo0 := bits.Mul32(uint32(x), n) + hi, lo1b := bits.Mul32(uint32(x>>32), n) + lo1, c := bits.Add32(lo1a, lo1b, 0) + hi += c + if lo1 == 0 && lo0 < uint32(n) { + n64 := uint64(n) + thresh := uint32(-n64 % n64) + for lo1 == 0 && lo0 < thresh { + x := r.Uint64() + lo1a, lo0 = bits.Mul32(uint32(x), n) + hi, lo1b = bits.Mul32(uint32(x>>32), n) + lo1, c = bits.Add32(lo1a, lo1b, 0) + hi += c + } + } + return hi +} + +// Int32N returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n <= 0. +func (r *Rand) Int32N(n int32) int32 { + if n <= 0 { + panic("invalid argument to Int32N") + } + return int32(r.uint64n(uint64(n))) +} + +// Uint32N returns, as a uint32, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n == 0. +func (r *Rand) Uint32N(n uint32) uint32 { + if n == 0 { + panic("invalid argument to Uint32N") + } + return uint32(r.uint64n(uint64(n))) +} + +const is32bit = ^uint(0)>>32 == 0 + +// IntN returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n <= 0. +func (r *Rand) IntN(n int) int { + if n <= 0 { + panic("invalid argument to IntN") + } + return int(r.uint64n(uint64(n))) +} + +// UintN returns, as a uint, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n == 0. +func (r *Rand) UintN(n uint) uint { + if n == 0 { + panic("invalid argument to UintN") + } + return uint(r.uint64n(uint64(n))) +} + +// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0). +func (r *Rand) Float64() float64 { + // There are exactly 1<<53 float64s in [0,1). Use Intn(1<<53) / (1<<53). + return float64(r.Uint64()<<11>>11) / (1 << 53) +} + +// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0). +func (r *Rand) Float32() float32 { + // There are exactly 1<<24 float32s in [0,1). Use Intn(1<<24) / (1<<24). + return float32(r.Uint32()<<8>>8) / (1 << 24) +} + +// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers +// in the half-open interval [0,n). +func (r *Rand) Perm(n int) []int { + p := make([]int, n) + for i := range p { + p[i] = i + } + r.Shuffle(len(p), func(i, j int) { p[i], p[j] = p[j], p[i] }) + return p +} + +// Shuffle pseudo-randomizes the order of elements. +// n is the number of elements. Shuffle panics if n < 0. +// swap swaps the elements with indexes i and j. +func (r *Rand) Shuffle(n int, swap func(i, j int)) { + if n < 0 { + panic("invalid argument to Shuffle") + } + + // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle + // Shuffle really ought not be called with n that doesn't fit in 32 bits. + // Not only will it take a very long time, but with 2³¹! possible permutations, + // there's no way that any PRNG can have a big enough internal state to + // generate even a minuscule percentage of the possible permutations. + // Nevertheless, the right API signature accepts an int n, so handle it as best we can. + for i := n - 1; i > 0; i-- { + j := int(r.uint64n(uint64(i + 1))) + swap(i, j) + } +} + +/* + * Top-level convenience functions + */ + +// globalRand is the source of random numbers for the top-level +// convenience functions. +var globalRand = &Rand{src: runtimeSource{}} + +//go:linkname runtime_rand runtime.rand +func runtime_rand() uint64 + +// runtimeSource is a Source that uses the runtime fastrand functions. +type runtimeSource struct{} + +func (runtimeSource) Uint64() uint64 { + return runtime_rand() +} + +// Int64 returns a non-negative pseudo-random 63-bit integer as an int64 +// from the default Source. +func Int64() int64 { return globalRand.Int64() } + +// Uint32 returns a pseudo-random 32-bit value as a uint32 +// from the default Source. +func Uint32() uint32 { return globalRand.Uint32() } + +// Uint64N returns, as a uint64, a pseudo-random number in the half-open interval [0,n) +// from the default Source. +// It panics if n <= 0. +func Uint64N(n uint64) uint64 { return globalRand.Uint64N(n) } + +// Uint32N returns, as a uint32, a pseudo-random number in the half-open interval [0,n) +// from the default Source. +// It panics if n <= 0. +func Uint32N(n uint32) uint32 { return globalRand.Uint32N(n) } + +// Uint64 returns a pseudo-random 64-bit value as a uint64 +// from the default Source. +func Uint64() uint64 { return globalRand.Uint64() } + +// Int32 returns a non-negative pseudo-random 31-bit integer as an int32 +// from the default Source. +func Int32() int32 { return globalRand.Int32() } + +// Int returns a non-negative pseudo-random int from the default Source. +func Int() int { return globalRand.Int() } + +// Uint returns a pseudo-random uint from the default Source. +func Uint() uint { return globalRand.Uint() } + +// Int64N returns, as an int64, a pseudo-random number in the half-open interval [0,n) +// from the default Source. +// It panics if n <= 0. +func Int64N(n int64) int64 { return globalRand.Int64N(n) } + +// Int32N returns, as an int32, a pseudo-random number in the half-open interval [0,n) +// from the default Source. +// It panics if n <= 0. +func Int32N(n int32) int32 { return globalRand.Int32N(n) } + +// IntN returns, as an int, a pseudo-random number in the half-open interval [0,n) +// from the default Source. +// It panics if n <= 0. +func IntN(n int) int { return globalRand.IntN(n) } + +// UintN returns, as a uint, a pseudo-random number in the half-open interval [0,n) +// from the default Source. +// It panics if n <= 0. +func UintN(n uint) uint { return globalRand.UintN(n) } + +// N returns a pseudo-random number in the half-open interval [0,n) from the default Source. +// The type parameter Int can be any integer type. +// It panics if n <= 0. +func N[Int intType](n Int) Int { + if n <= 0 { + panic("invalid argument to N") + } + return Int(globalRand.uint64n(uint64(n))) +} + +type intType interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0) +// from the default Source. +func Float64() float64 { return globalRand.Float64() } + +// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0) +// from the default Source. +func Float32() float32 { return globalRand.Float32() } + +// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers +// in the half-open interval [0,n) from the default Source. +func Perm(n int) []int { return globalRand.Perm(n) } + +// Shuffle pseudo-randomizes the order of elements using the default Source. +// n is the number of elements. Shuffle panics if n < 0. +// swap swaps the elements with indexes i and j. +func Shuffle(n int, swap func(i, j int)) { globalRand.Shuffle(n, swap) } + +// NormFloat64 returns a normally distributed float64 in the range +// [-math.MaxFloat64, +math.MaxFloat64] with +// standard normal distribution (mean = 0, stddev = 1) +// from the default Source. +// To produce a different normal distribution, callers can +// adjust the output using: +// +// sample = NormFloat64() * desiredStdDev + desiredMean +func NormFloat64() float64 { return globalRand.NormFloat64() } + +// ExpFloat64 returns an exponentially distributed float64 in the range +// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter +// (lambda) is 1 and whose mean is 1/lambda (1) from the default Source. +// To produce a distribution with a different rate parameter, +// callers can adjust the output using: +// +// sample = ExpFloat64() / desiredRateParameter +func ExpFloat64() float64 { return globalRand.ExpFloat64() } diff --git a/contrib/go/_std_1.23/src/math/rand/v2/ya.make b/contrib/go/_std_1.23/src/math/rand/v2/ya.make new file mode 100644 index 000000000000..125d7ceabd69 --- /dev/null +++ b/contrib/go/_std_1.23/src/math/rand/v2/ya.make @@ -0,0 +1,12 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + chacha8.go + exp.go + normal.go + pcg.go + rand.go + zipf.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/math/rand/v2/zipf.go b/contrib/go/_std_1.23/src/math/rand/v2/zipf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/v2/zipf.go rename to contrib/go/_std_1.23/src/math/rand/v2/zipf.go diff --git a/contrib/go/_std_1.22/src/math/rand/ya.make b/contrib/go/_std_1.23/src/math/rand/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/ya.make rename to contrib/go/_std_1.23/src/math/rand/ya.make diff --git a/contrib/go/_std_1.22/src/math/rand/zipf.go b/contrib/go/_std_1.23/src/math/rand/zipf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/zipf.go rename to contrib/go/_std_1.23/src/math/rand/zipf.go diff --git a/contrib/go/_std_1.22/src/math/remainder.go b/contrib/go/_std_1.23/src/math/remainder.go similarity index 100% rename from contrib/go/_std_1.22/src/math/remainder.go rename to contrib/go/_std_1.23/src/math/remainder.go diff --git a/contrib/go/_std_1.22/src/math/signbit.go b/contrib/go/_std_1.23/src/math/signbit.go similarity index 100% rename from contrib/go/_std_1.22/src/math/signbit.go rename to contrib/go/_std_1.23/src/math/signbit.go diff --git a/contrib/go/_std_1.22/src/math/sin.go b/contrib/go/_std_1.23/src/math/sin.go similarity index 100% rename from contrib/go/_std_1.22/src/math/sin.go rename to contrib/go/_std_1.23/src/math/sin.go diff --git a/contrib/go/_std_1.22/src/math/sin_s390x.s b/contrib/go/_std_1.23/src/math/sin_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/sin_s390x.s rename to contrib/go/_std_1.23/src/math/sin_s390x.s diff --git a/contrib/go/_std_1.22/src/math/sincos.go b/contrib/go/_std_1.23/src/math/sincos.go similarity index 100% rename from contrib/go/_std_1.22/src/math/sincos.go rename to contrib/go/_std_1.23/src/math/sincos.go diff --git a/contrib/go/_std_1.22/src/math/sinh.go b/contrib/go/_std_1.23/src/math/sinh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/sinh.go rename to contrib/go/_std_1.23/src/math/sinh.go diff --git a/contrib/go/_std_1.22/src/math/sinh_s390x.s b/contrib/go/_std_1.23/src/math/sinh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/sinh_s390x.s rename to contrib/go/_std_1.23/src/math/sinh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/sqrt.go b/contrib/go/_std_1.23/src/math/sqrt.go similarity index 100% rename from contrib/go/_std_1.22/src/math/sqrt.go rename to contrib/go/_std_1.23/src/math/sqrt.go diff --git a/contrib/go/_std_1.22/src/math/stubs.go b/contrib/go/_std_1.23/src/math/stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/math/stubs.go rename to contrib/go/_std_1.23/src/math/stubs.go diff --git a/contrib/go/_std_1.22/src/math/stubs_s390x.s b/contrib/go/_std_1.23/src/math/stubs_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/stubs_s390x.s rename to contrib/go/_std_1.23/src/math/stubs_s390x.s diff --git a/contrib/go/_std_1.22/src/math/tan.go b/contrib/go/_std_1.23/src/math/tan.go similarity index 100% rename from contrib/go/_std_1.22/src/math/tan.go rename to contrib/go/_std_1.23/src/math/tan.go diff --git a/contrib/go/_std_1.22/src/math/tan_s390x.s b/contrib/go/_std_1.23/src/math/tan_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/tan_s390x.s rename to contrib/go/_std_1.23/src/math/tan_s390x.s diff --git a/contrib/go/_std_1.22/src/math/tanh.go b/contrib/go/_std_1.23/src/math/tanh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/tanh.go rename to contrib/go/_std_1.23/src/math/tanh.go diff --git a/contrib/go/_std_1.22/src/math/tanh_s390x.s b/contrib/go/_std_1.23/src/math/tanh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/tanh_s390x.s rename to contrib/go/_std_1.23/src/math/tanh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/trig_reduce.go b/contrib/go/_std_1.23/src/math/trig_reduce.go similarity index 100% rename from contrib/go/_std_1.22/src/math/trig_reduce.go rename to contrib/go/_std_1.23/src/math/trig_reduce.go diff --git a/contrib/go/_std_1.23/src/math/unsafe.go b/contrib/go/_std_1.23/src/math/unsafe.go new file mode 100644 index 000000000000..e251f62a2a13 --- /dev/null +++ b/contrib/go/_std_1.23/src/math/unsafe.go @@ -0,0 +1,41 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math + +import "unsafe" + +// Despite being an exported symbol, +// Float32bits is linknamed by widely used packages. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/num +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +// Note that this comment is not part of the doc comment. +// +//go:linkname Float32bits + +// Float32bits returns the IEEE 754 binary representation of f, +// with the sign bit of f and the result in the same bit position. +// Float32bits(Float32frombits(x)) == x. +func Float32bits(f float32) uint32 { return *(*uint32)(unsafe.Pointer(&f)) } + +// Float32frombits returns the floating-point number corresponding +// to the IEEE 754 binary representation b, with the sign bit of b +// and the result in the same bit position. +// Float32frombits(Float32bits(x)) == x. +func Float32frombits(b uint32) float32 { return *(*float32)(unsafe.Pointer(&b)) } + +// Float64bits returns the IEEE 754 binary representation of f, +// with the sign bit of f and the result in the same bit position, +// and Float64bits(Float64frombits(x)) == x. +func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) } + +// Float64frombits returns the floating-point number corresponding +// to the IEEE 754 binary representation b, with the sign bit of b +// and the result in the same bit position. +// Float64frombits(Float64bits(x)) == x. +func Float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) } diff --git a/contrib/go/_std_1.23/src/math/ya.make b/contrib/go/_std_1.23/src/math/ya.make new file mode 100644 index 000000000000..3217f82e503a --- /dev/null +++ b/contrib/go/_std_1.23/src/math/ya.make @@ -0,0 +1,181 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + abs.go + acosh.go + asin.go + asinh.go + atan.go + atan2.go + atanh.go + bits.go + cbrt.go + const.go + copysign.go + dim.go + dim_arm64.s + dim_asm.go + erf.go + erfinv.go + exp.go + exp2_asm.go + exp_arm64.s + exp_asm.go + expm1.go + floor.go + floor_arm64.s + floor_asm.go + fma.go + frexp.go + gamma.go + hypot.go + hypot_noasm.go + j0.go + j1.go + jn.go + ldexp.go + lgamma.go + log.go + log10.go + log1p.go + log_stub.go + logb.go + mod.go + modf.go + modf_arm64.s + modf_asm.go + nextafter.go + pow.go + pow10.go + remainder.go + signbit.go + sin.go + sincos.go + sinh.go + sqrt.go + stubs.go + tan.go + tanh.go + trig_reduce.go + unsafe.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + abs.go + acosh.go + asin.go + asinh.go + atan.go + atan2.go + atanh.go + bits.go + cbrt.go + const.go + copysign.go + dim.go + dim_amd64.s + dim_asm.go + erf.go + erfinv.go + exp.go + exp2_noasm.go + exp_amd64.go + exp_amd64.s + exp_asm.go + expm1.go + floor.go + floor_amd64.s + floor_asm.go + fma.go + frexp.go + gamma.go + hypot.go + hypot_amd64.s + hypot_asm.go + j0.go + j1.go + jn.go + ldexp.go + lgamma.go + log.go + log10.go + log1p.go + log_amd64.s + log_asm.go + logb.go + mod.go + modf.go + modf_noasm.go + nextafter.go + pow.go + pow10.go + remainder.go + signbit.go + sin.go + sincos.go + sinh.go + sqrt.go + stubs.go + tan.go + tanh.go + trig_reduce.go + unsafe.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + abs.go + acosh.go + asin.go + asinh.go + atan.go + atan2.go + atanh.go + bits.go + cbrt.go + const.go + copysign.go + dim.go + dim_noasm.go + erf.go + erfinv.go + exp.go + exp2_noasm.go + exp_noasm.go + expm1.go + floor.go + floor_noasm.go + fma.go + frexp.go + gamma.go + hypot.go + hypot_noasm.go + j0.go + j1.go + jn.go + ldexp.go + lgamma.go + log.go + log10.go + log1p.go + log_stub.go + logb.go + mod.go + modf.go + modf_noasm.go + nextafter.go + pow.go + pow10.go + remainder.go + signbit.go + sin.go + sincos.go + sinh.go + sqrt.go + stubs.go + tan.go + tanh.go + trig_reduce.go + unsafe.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/mime/encodedword.go b/contrib/go/_std_1.23/src/mime/encodedword.go similarity index 99% rename from contrib/go/_std_1.22/src/mime/encodedword.go rename to contrib/go/_std_1.23/src/mime/encodedword.go index e6b470b1fb0e..856433f8f3b3 100644 --- a/contrib/go/_std_1.22/src/mime/encodedword.go +++ b/contrib/go/_std_1.23/src/mime/encodedword.go @@ -226,7 +226,7 @@ func (d *WordDecoder) Decode(word string) (string, error) { } // DecodeHeader decodes all encoded-words of the given string. It returns an -// error if and only if CharsetReader of d returns an error. +// error if and only if WordDecoder.CharsetReader of d returns an error. func (d *WordDecoder) DecodeHeader(header string) (string, error) { // If there is no encoded-word, returns before creating a buffer. i := strings.Index(header, "=?") diff --git a/contrib/go/_std_1.22/src/mime/grammar.go b/contrib/go/_std_1.23/src/mime/grammar.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/grammar.go rename to contrib/go/_std_1.23/src/mime/grammar.go diff --git a/contrib/go/_std_1.22/src/mime/mediatype.go b/contrib/go/_std_1.23/src/mime/mediatype.go similarity index 98% rename from contrib/go/_std_1.22/src/mime/mediatype.go rename to contrib/go/_std_1.23/src/mime/mediatype.go index bc8d417e6289..97f3563a2d01 100644 --- a/contrib/go/_std_1.22/src/mime/mediatype.go +++ b/contrib/go/_std_1.23/src/mime/mediatype.go @@ -7,7 +7,7 @@ package mime import ( "errors" "fmt" - "sort" + "slices" "strings" "unicode" ) @@ -37,7 +37,7 @@ func FormatMediaType(t string, param map[string]string) string { for a := range param { attrs = append(attrs, a) } - sort.Strings(attrs) + slices.Sort(attrs) for _, attribute := range attrs { value := param[attribute] @@ -121,7 +121,7 @@ func checkMediaTypeDisposition(s string) error { return nil } -// ErrInvalidMediaParameter is returned by ParseMediaType if +// ErrInvalidMediaParameter is returned by [ParseMediaType] if // the media type value was found but there was an error parsing // the optional parameters var ErrInvalidMediaParameter = errors.New("mime: invalid media parameter") @@ -133,7 +133,7 @@ var ErrInvalidMediaParameter = errors.New("mime: invalid media parameter") // to lowercase and trimmed of white space and a non-nil map. // If there is an error parsing the optional parameter, // the media type will be returned along with the error -// ErrInvalidMediaParameter. +// [ErrInvalidMediaParameter]. // The returned map, params, maps from the lowercase // attribute to the attribute value with its case preserved. func ParseMediaType(v string) (mediatype string, params map[string]string, err error) { diff --git a/contrib/go/_std_1.22/src/mime/multipart/formdata.go b/contrib/go/_std_1.23/src/mime/multipart/formdata.go similarity index 92% rename from contrib/go/_std_1.22/src/mime/multipart/formdata.go rename to contrib/go/_std_1.23/src/mime/multipart/formdata.go index 85bad2a4cb63..d0e0151a6fbe 100644 --- a/contrib/go/_std_1.22/src/mime/multipart/formdata.go +++ b/contrib/go/_std_1.23/src/mime/multipart/formdata.go @@ -27,15 +27,15 @@ var ErrMessageTooLarge = errors.New("multipart: message too large") // It stores up to maxMemory bytes + 10MB (reserved for non-file parts) // in memory. File parts which can't be stored in memory will be stored on // disk in temporary files. -// It returns ErrMessageTooLarge if all non-file parts can't be stored in +// It returns [ErrMessageTooLarge] if all non-file parts can't be stored in // memory. func (r *Reader) ReadForm(maxMemory int64) (*Form, error) { return r.readForm(maxMemory) } var ( - multipartFiles = godebug.New("#multipartfiles") // TODO: document and remove # - multipartMaxParts = godebug.New("multipartmaxparts") + multipartfiles = godebug.New("#multipartfiles") // TODO: document and remove # + multipartmaxparts = godebug.New("multipartmaxparts") ) func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { @@ -46,15 +46,15 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { ) numDiskFiles := 0 combineFiles := true - if multipartFiles.Value() == "distinct" { + if multipartfiles.Value() == "distinct" { combineFiles = false - // multipartFiles.IncNonDefault() // TODO: uncomment after documenting + // multipartfiles.IncNonDefault() // TODO: uncomment after documenting } maxParts := 1000 - if s := multipartMaxParts.Value(); s != "" { + if s := multipartmaxparts.Value(); s != "" { if v, err := strconv.Atoi(s); err == nil && v >= 0 { maxParts = v - multipartMaxParts.IncNonDefault() + multipartmaxparts.IncNonDefault() } } maxHeaders := maxMIMEHeaders() @@ -228,7 +228,7 @@ func mimeHeaderSize(h textproto.MIMEHeader) (size int64) { // Form is a parsed multipart form. // Its File parts are stored either in memory or on disk, -// and are accessible via the *FileHeader's Open method. +// and are accessible via the [*FileHeader]'s Open method. // Its Value parts are stored as strings. // Both are keyed by field name. type Form struct { @@ -236,7 +236,7 @@ type Form struct { File map[string][]*FileHeader } -// RemoveAll removes any temporary files associated with a Form. +// RemoveAll removes any temporary files associated with a [Form]. func (f *Form) RemoveAll() error { var err error for _, fhs := range f.File { @@ -264,7 +264,7 @@ type FileHeader struct { tmpshared bool } -// Open opens and returns the FileHeader's associated File. +// Open opens and returns the [FileHeader]'s associated File. func (fh *FileHeader) Open() (File, error) { if b := fh.content; b != nil { r := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b))) diff --git a/contrib/go/_std_1.22/src/mime/multipart/multipart.go b/contrib/go/_std_1.23/src/mime/multipart/multipart.go similarity index 94% rename from contrib/go/_std_1.22/src/mime/multipart/multipart.go rename to contrib/go/_std_1.23/src/mime/multipart/multipart.go index da1f45810e88..17088bc30e1b 100644 --- a/contrib/go/_std_1.22/src/mime/multipart/multipart.go +++ b/contrib/go/_std_1.23/src/mime/multipart/multipart.go @@ -15,8 +15,8 @@ bodies generated by popular browsers. To protect against malicious inputs, this package sets limits on the size of the MIME data it processes. -Reader.NextPart and Reader.NextRawPart limit the number of headers in a -part to 10000 and Reader.ReadForm limits the total number of headers in all +[Reader.NextPart] and [Reader.NextRawPart] limit the number of headers in a +part to 10000 and [Reader.ReadForm] limits the total number of headers in all FileHeaders to 10000. These limits may be adjusted with the GODEBUG=multipartmaxheaders= setting. @@ -85,7 +85,7 @@ func (p *Part) FormName() string { return p.dispositionParams["name"] } -// FileName returns the filename parameter of the Part's Content-Disposition +// FileName returns the filename parameter of the [Part]'s Content-Disposition // header. If not empty, the filename is passed through filepath.Base (which is // platform dependent) before being returned. func (p *Part) FileName() string { @@ -110,11 +110,11 @@ func (p *Part) parseContentDisposition() { } } -// NewReader creates a new multipart Reader reading from r using the +// NewReader creates a new multipart [Reader] reading from r using the // given MIME boundary. // // The boundary is usually obtained from the "boundary" parameter of -// the message's "Content-Type" header. Use mime.ParseMediaType to +// the message's "Content-Type" header. Use [mime.ParseMediaType] to // parse such headers. func NewReader(r io.Reader, boundary string) *Reader { b := []byte("\r\n--" + boundary + "--") @@ -347,15 +347,15 @@ type Reader struct { // including header keys, values, and map overhead. const maxMIMEHeaderSize = 10 << 20 -// multipartMaxHeaders is the maximum number of header entries NextPart will return, +// multipartmaxheaders is the maximum number of header entries NextPart will return, // as well as the maximum combined total of header entries Reader.ReadForm will return // in FileHeaders. -var multipartMaxHeaders = godebug.New("multipartmaxheaders") +var multipartmaxheaders = godebug.New("multipartmaxheaders") func maxMIMEHeaders() int64 { - if s := multipartMaxHeaders.Value(); s != "" { + if s := multipartmaxheaders.Value(); s != "" { if v, err := strconv.ParseInt(s, 10, 64); err == nil && v >= 0 { - multipartMaxHeaders.IncNonDefault() + multipartmaxheaders.IncNonDefault() return v } } @@ -363,7 +363,7 @@ func maxMIMEHeaders() int64 { } // NextPart returns the next part in the multipart or an error. -// When there are no more parts, the error io.EOF is returned. +// When there are no more parts, the error [io.EOF] is returned. // // As a special case, if the "Content-Transfer-Encoding" header // has a value of "quoted-printable", that header is instead @@ -373,9 +373,9 @@ func (r *Reader) NextPart() (*Part, error) { } // NextRawPart returns the next part in the multipart or an error. -// When there are no more parts, the error io.EOF is returned. +// When there are no more parts, the error [io.EOF] is returned. // -// Unlike NextPart, it does not have special handling for +// Unlike [Reader.NextPart], it does not have special handling for // "Content-Transfer-Encoding: quoted-printable". func (r *Reader) NextRawPart() (*Part, error) { return r.nextPart(true, maxMIMEHeaderSize, maxMIMEHeaders()) diff --git a/contrib/go/_std_1.22/src/mime/multipart/readmimeheader.go b/contrib/go/_std_1.23/src/mime/multipart/readmimeheader.go similarity index 87% rename from contrib/go/_std_1.22/src/mime/multipart/readmimeheader.go rename to contrib/go/_std_1.23/src/mime/multipart/readmimeheader.go index 25aa6e209286..c6825069b0b5 100644 --- a/contrib/go/_std_1.22/src/mime/multipart/readmimeheader.go +++ b/contrib/go/_std_1.23/src/mime/multipart/readmimeheader.go @@ -1,6 +1,7 @@ // Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. + package multipart import ( @@ -8,7 +9,7 @@ import ( _ "unsafe" // for go:linkname ) -// readMIMEHeader is defined in package net/textproto. +// readMIMEHeader is defined in package [net/textproto]. // //go:linkname readMIMEHeader net/textproto.readMIMEHeader func readMIMEHeader(r *textproto.Reader, maxMemory, maxHeaders int64) (textproto.MIMEHeader, error) diff --git a/contrib/go/_std_1.23/src/mime/multipart/writer.go b/contrib/go/_std_1.23/src/mime/multipart/writer.go new file mode 100644 index 000000000000..5e589c499b33 --- /dev/null +++ b/contrib/go/_std_1.23/src/mime/multipart/writer.go @@ -0,0 +1,201 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package multipart + +import ( + "bytes" + "crypto/rand" + "errors" + "fmt" + "io" + "net/textproto" + "slices" + "strings" +) + +// A Writer generates multipart messages. +type Writer struct { + w io.Writer + boundary string + lastpart *part +} + +// NewWriter returns a new multipart [Writer] with a random boundary, +// writing to w. +func NewWriter(w io.Writer) *Writer { + return &Writer{ + w: w, + boundary: randomBoundary(), + } +} + +// Boundary returns the [Writer]'s boundary. +func (w *Writer) Boundary() string { + return w.boundary +} + +// SetBoundary overrides the [Writer]'s default randomly-generated +// boundary separator with an explicit value. +// +// SetBoundary must be called before any parts are created, may only +// contain certain ASCII characters, and must be non-empty and +// at most 70 bytes long. +func (w *Writer) SetBoundary(boundary string) error { + if w.lastpart != nil { + return errors.New("mime: SetBoundary called after write") + } + // rfc2046#section-5.1.1 + if len(boundary) < 1 || len(boundary) > 70 { + return errors.New("mime: invalid boundary length") + } + end := len(boundary) - 1 + for i, b := range boundary { + if 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' { + continue + } + switch b { + case '\'', '(', ')', '+', '_', ',', '-', '.', '/', ':', '=', '?': + continue + case ' ': + if i != end { + continue + } + } + return errors.New("mime: invalid boundary character") + } + w.boundary = boundary + return nil +} + +// FormDataContentType returns the Content-Type for an HTTP +// multipart/form-data with this [Writer]'s Boundary. +func (w *Writer) FormDataContentType() string { + b := w.boundary + // We must quote the boundary if it contains any of the + // tspecials characters defined by RFC 2045, or space. + if strings.ContainsAny(b, `()<>@,;:\"/[]?= `) { + b = `"` + b + `"` + } + return "multipart/form-data; boundary=" + b +} + +func randomBoundary() string { + var buf [30]byte + _, err := io.ReadFull(rand.Reader, buf[:]) + if err != nil { + panic(err) + } + return fmt.Sprintf("%x", buf[:]) +} + +// CreatePart creates a new multipart section with the provided +// header. The body of the part should be written to the returned +// [Writer]. After calling CreatePart, any previous part may no longer +// be written to. +func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) { + if w.lastpart != nil { + if err := w.lastpart.close(); err != nil { + return nil, err + } + } + var b bytes.Buffer + if w.lastpart != nil { + fmt.Fprintf(&b, "\r\n--%s\r\n", w.boundary) + } else { + fmt.Fprintf(&b, "--%s\r\n", w.boundary) + } + + keys := make([]string, 0, len(header)) + for k := range header { + keys = append(keys, k) + } + slices.Sort(keys) + for _, k := range keys { + for _, v := range header[k] { + fmt.Fprintf(&b, "%s: %s\r\n", k, v) + } + } + fmt.Fprintf(&b, "\r\n") + _, err := io.Copy(w.w, &b) + if err != nil { + return nil, err + } + p := &part{ + mw: w, + } + w.lastpart = p + return p, nil +} + +var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") + +func escapeQuotes(s string) string { + return quoteEscaper.Replace(s) +} + +// CreateFormFile is a convenience wrapper around [Writer.CreatePart]. It creates +// a new form-data header with the provided field name and file name. +func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) { + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", + fmt.Sprintf(`form-data; name="%s"; filename="%s"`, + escapeQuotes(fieldname), escapeQuotes(filename))) + h.Set("Content-Type", "application/octet-stream") + return w.CreatePart(h) +} + +// CreateFormField calls [Writer.CreatePart] with a header using the +// given field name. +func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) { + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", + fmt.Sprintf(`form-data; name="%s"`, escapeQuotes(fieldname))) + return w.CreatePart(h) +} + +// WriteField calls [Writer.CreateFormField] and then writes the given value. +func (w *Writer) WriteField(fieldname, value string) error { + p, err := w.CreateFormField(fieldname) + if err != nil { + return err + } + _, err = p.Write([]byte(value)) + return err +} + +// Close finishes the multipart message and writes the trailing +// boundary end line to the output. +func (w *Writer) Close() error { + if w.lastpart != nil { + if err := w.lastpart.close(); err != nil { + return err + } + w.lastpart = nil + } + _, err := fmt.Fprintf(w.w, "\r\n--%s--\r\n", w.boundary) + return err +} + +type part struct { + mw *Writer + closed bool + we error // last error that occurred writing +} + +func (p *part) close() error { + p.closed = true + return p.we +} + +func (p *part) Write(d []byte) (n int, err error) { + if p.closed { + return 0, errors.New("multipart: can't write to finished part") + } + n, err = p.mw.w.Write(d) + if err != nil { + p.we = err + } + return +} diff --git a/contrib/go/_std_1.22/src/mime/multipart/ya.make b/contrib/go/_std_1.23/src/mime/multipart/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/mime/multipart/ya.make rename to contrib/go/_std_1.23/src/mime/multipart/ya.make diff --git a/contrib/go/_std_1.22/src/mime/quotedprintable/reader.go b/contrib/go/_std_1.23/src/mime/quotedprintable/reader.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/quotedprintable/reader.go rename to contrib/go/_std_1.23/src/mime/quotedprintable/reader.go diff --git a/contrib/go/_std_1.23/src/mime/quotedprintable/writer.go b/contrib/go/_std_1.23/src/mime/quotedprintable/writer.go new file mode 100644 index 000000000000..69b5a1123263 --- /dev/null +++ b/contrib/go/_std_1.23/src/mime/quotedprintable/writer.go @@ -0,0 +1,172 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quotedprintable + +import "io" + +const lineMaxLen = 76 + +// A Writer is a quoted-printable writer that implements [io.WriteCloser]. +type Writer struct { + // Binary mode treats the writer's input as pure binary and processes end of + // line bytes as binary data. + Binary bool + + w io.Writer + i int + line [78]byte + cr bool +} + +// NewWriter returns a new [Writer] that writes to w. +func NewWriter(w io.Writer) *Writer { + return &Writer{w: w} +} + +// Write encodes p using quoted-printable encoding and writes it to the +// underlying [io.Writer]. It limits line length to 76 characters. The encoded +// bytes are not necessarily flushed until the [Writer] is closed. +func (w *Writer) Write(p []byte) (n int, err error) { + for i, b := range p { + switch { + // Simple writes are done in batch. + case b >= '!' && b <= '~' && b != '=': + continue + case isWhitespace(b) || !w.Binary && (b == '\n' || b == '\r'): + continue + } + + if i > n { + if err := w.write(p[n:i]); err != nil { + return n, err + } + n = i + } + + if err := w.encode(b); err != nil { + return n, err + } + n++ + } + + if n == len(p) { + return n, nil + } + + if err := w.write(p[n:]); err != nil { + return n, err + } + + return len(p), nil +} + +// Close closes the [Writer], flushing any unwritten data to the underlying +// [io.Writer], but does not close the underlying io.Writer. +func (w *Writer) Close() error { + if err := w.checkLastByte(); err != nil { + return err + } + + return w.flush() +} + +// write limits text encoded in quoted-printable to 76 characters per line. +func (w *Writer) write(p []byte) error { + for _, b := range p { + if b == '\n' || b == '\r' { + // If the previous byte was \r, the CRLF has already been inserted. + if w.cr && b == '\n' { + w.cr = false + continue + } + + if b == '\r' { + w.cr = true + } + + if err := w.checkLastByte(); err != nil { + return err + } + if err := w.insertCRLF(); err != nil { + return err + } + continue + } + + if w.i == lineMaxLen-1 { + if err := w.insertSoftLineBreak(); err != nil { + return err + } + } + + w.line[w.i] = b + w.i++ + w.cr = false + } + + return nil +} + +func (w *Writer) encode(b byte) error { + if lineMaxLen-1-w.i < 3 { + if err := w.insertSoftLineBreak(); err != nil { + return err + } + } + + w.line[w.i] = '=' + w.line[w.i+1] = upperhex[b>>4] + w.line[w.i+2] = upperhex[b&0x0f] + w.i += 3 + + return nil +} + +const upperhex = "0123456789ABCDEF" + +// checkLastByte encodes the last buffered byte if it is a space or a tab. +func (w *Writer) checkLastByte() error { + if w.i == 0 { + return nil + } + + b := w.line[w.i-1] + if isWhitespace(b) { + w.i-- + if err := w.encode(b); err != nil { + return err + } + } + + return nil +} + +func (w *Writer) insertSoftLineBreak() error { + w.line[w.i] = '=' + w.i++ + + return w.insertCRLF() +} + +func (w *Writer) insertCRLF() error { + w.line[w.i] = '\r' + w.line[w.i+1] = '\n' + w.i += 2 + + return w.flush() +} + +func (w *Writer) flush() error { + if _, err := w.w.Write(w.line[:w.i]); err != nil { + return err + } + + w.i = 0 + return nil +} + +func isWhitespace(b byte) bool { + return b == ' ' || b == '\t' +} diff --git a/contrib/go/_std_1.22/src/mime/quotedprintable/ya.make b/contrib/go/_std_1.23/src/mime/quotedprintable/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/mime/quotedprintable/ya.make rename to contrib/go/_std_1.23/src/mime/quotedprintable/ya.make diff --git a/contrib/go/_std_1.23/src/mime/type.go b/contrib/go/_std_1.23/src/mime/type.go new file mode 100644 index 000000000000..c86ebd3442c1 --- /dev/null +++ b/contrib/go/_std_1.23/src/mime/type.go @@ -0,0 +1,195 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package mime implements parts of the MIME spec. +package mime + +import ( + "fmt" + "slices" + "strings" + "sync" +) + +var ( + mimeTypes sync.Map // map[string]string; ".Z" => "application/x-compress" + mimeTypesLower sync.Map // map[string]string; ".z" => "application/x-compress" + + // extensions maps from MIME type to list of lowercase file + // extensions: "image/jpeg" => [".jpg", ".jpeg"] + extensionsMu sync.Mutex // Guards stores (but not loads) on extensions. + extensions sync.Map // map[string][]string; slice values are append-only. +) + +// setMimeTypes is used by initMime's non-test path, and by tests. +func setMimeTypes(lowerExt, mixExt map[string]string) { + mimeTypes.Clear() + mimeTypesLower.Clear() + extensions.Clear() + + for k, v := range lowerExt { + mimeTypesLower.Store(k, v) + } + for k, v := range mixExt { + mimeTypes.Store(k, v) + } + + extensionsMu.Lock() + defer extensionsMu.Unlock() + for k, v := range lowerExt { + justType, _, err := ParseMediaType(v) + if err != nil { + panic(err) + } + var exts []string + if ei, ok := extensions.Load(justType); ok { + exts = ei.([]string) + } + extensions.Store(justType, append(exts, k)) + } +} + +var builtinTypesLower = map[string]string{ + ".avif": "image/avif", + ".css": "text/css; charset=utf-8", + ".gif": "image/gif", + ".htm": "text/html; charset=utf-8", + ".html": "text/html; charset=utf-8", + ".jpeg": "image/jpeg", + ".jpg": "image/jpeg", + ".js": "text/javascript; charset=utf-8", + ".json": "application/json", + ".mjs": "text/javascript; charset=utf-8", + ".pdf": "application/pdf", + ".png": "image/png", + ".svg": "image/svg+xml", + ".wasm": "application/wasm", + ".webp": "image/webp", + ".xml": "text/xml; charset=utf-8", +} + +var once sync.Once // guards initMime + +var testInitMime, osInitMime func() + +func initMime() { + if fn := testInitMime; fn != nil { + fn() + } else { + setMimeTypes(builtinTypesLower, builtinTypesLower) + osInitMime() + } +} + +// TypeByExtension returns the MIME type associated with the file extension ext. +// The extension ext should begin with a leading dot, as in ".html". +// When ext has no associated type, TypeByExtension returns "". +// +// Extensions are looked up first case-sensitively, then case-insensitively. +// +// The built-in table is small but on unix it is augmented by the local +// system's MIME-info database or mime.types file(s) if available under one or +// more of these names: +// +// /usr/local/share/mime/globs2 +// /usr/share/mime/globs2 +// /etc/mime.types +// /etc/apache2/mime.types +// /etc/apache/mime.types +// +// On Windows, MIME types are extracted from the registry. +// +// Text types have the charset parameter set to "utf-8" by default. +func TypeByExtension(ext string) string { + once.Do(initMime) + + // Case-sensitive lookup. + if v, ok := mimeTypes.Load(ext); ok { + return v.(string) + } + + // Case-insensitive lookup. + // Optimistically assume a short ASCII extension and be + // allocation-free in that case. + var buf [10]byte + lower := buf[:0] + const utf8RuneSelf = 0x80 // from utf8 package, but not importing it. + for i := 0; i < len(ext); i++ { + c := ext[i] + if c >= utf8RuneSelf { + // Slow path. + si, _ := mimeTypesLower.Load(strings.ToLower(ext)) + s, _ := si.(string) + return s + } + if 'A' <= c && c <= 'Z' { + lower = append(lower, c+('a'-'A')) + } else { + lower = append(lower, c) + } + } + si, _ := mimeTypesLower.Load(string(lower)) + s, _ := si.(string) + return s +} + +// ExtensionsByType returns the extensions known to be associated with the MIME +// type typ. The returned extensions will each begin with a leading dot, as in +// ".html". When typ has no associated extensions, ExtensionsByType returns an +// nil slice. +func ExtensionsByType(typ string) ([]string, error) { + justType, _, err := ParseMediaType(typ) + if err != nil { + return nil, err + } + + once.Do(initMime) + s, ok := extensions.Load(justType) + if !ok { + return nil, nil + } + ret := append([]string(nil), s.([]string)...) + slices.Sort(ret) + return ret, nil +} + +// AddExtensionType sets the MIME type associated with +// the extension ext to typ. The extension should begin with +// a leading dot, as in ".html". +func AddExtensionType(ext, typ string) error { + if !strings.HasPrefix(ext, ".") { + return fmt.Errorf("mime: extension %q missing leading dot", ext) + } + once.Do(initMime) + return setExtensionType(ext, typ) +} + +func setExtensionType(extension, mimeType string) error { + justType, param, err := ParseMediaType(mimeType) + if err != nil { + return err + } + if strings.HasPrefix(mimeType, "text/") && param["charset"] == "" { + param["charset"] = "utf-8" + mimeType = FormatMediaType(mimeType, param) + } + extLower := strings.ToLower(extension) + + mimeTypes.Store(extension, mimeType) + mimeTypesLower.Store(extLower, mimeType) + + extensionsMu.Lock() + defer extensionsMu.Unlock() + var exts []string + if ei, ok := extensions.Load(justType); ok { + exts = ei.([]string) + } + for _, v := range exts { + if v == extLower { + return nil + } + } + extensions.Store(justType, append(exts, extLower)) + return nil +} diff --git a/contrib/go/_std_1.22/src/mime/type_dragonfly.go b/contrib/go/_std_1.23/src/mime/type_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_dragonfly.go rename to contrib/go/_std_1.23/src/mime/type_dragonfly.go diff --git a/contrib/go/_std_1.22/src/mime/type_freebsd.go b/contrib/go/_std_1.23/src/mime/type_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_freebsd.go rename to contrib/go/_std_1.23/src/mime/type_freebsd.go diff --git a/contrib/go/_std_1.22/src/mime/type_openbsd.go b/contrib/go/_std_1.23/src/mime/type_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_openbsd.go rename to contrib/go/_std_1.23/src/mime/type_openbsd.go diff --git a/contrib/go/_std_1.22/src/mime/type_plan9.go b/contrib/go/_std_1.23/src/mime/type_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_plan9.go rename to contrib/go/_std_1.23/src/mime/type_plan9.go diff --git a/contrib/go/_std_1.22/src/mime/type_unix.go b/contrib/go/_std_1.23/src/mime/type_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_unix.go rename to contrib/go/_std_1.23/src/mime/type_unix.go diff --git a/contrib/go/_std_1.22/src/mime/type_windows.go b/contrib/go/_std_1.23/src/mime/type_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_windows.go rename to contrib/go/_std_1.23/src/mime/type_windows.go diff --git a/contrib/go/_std_1.23/src/mime/ya.make b/contrib/go/_std_1.23/src/mime/ya.make new file mode 100644 index 000000000000..ef2024a40b6a --- /dev/null +++ b/contrib/go/_std_1.23/src/mime/ya.make @@ -0,0 +1,19 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + encodedword.go + grammar.go + mediatype.go + type.go + type_unix.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + encodedword.go + grammar.go + mediatype.go + type.go + type_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/net/addrselect.go b/contrib/go/_std_1.23/src/net/addrselect.go similarity index 99% rename from contrib/go/_std_1.22/src/net/addrselect.go rename to contrib/go/_std_1.23/src/net/addrselect.go index 4f07032c4a01..caff09b3772f 100644 --- a/contrib/go/_std_1.22/src/net/addrselect.go +++ b/contrib/go/_std_1.23/src/net/addrselect.go @@ -42,7 +42,7 @@ func sortByRFC6724withSrcs(addrs []IPAddr, srcs []netip.Addr) { // number is irrelevant. func srcAddrs(addrs []IPAddr) []netip.Addr { srcs := make([]netip.Addr, len(addrs)) - dst := UDPAddr{Port: 9} + dst := UDPAddr{Port: 53} for i := range addrs { dst.IP = addrs[i].IP dst.Zone = addrs[i].Zone diff --git a/contrib/go/_std_1.22/src/net/cgo_aix.go b/contrib/go/_std_1.23/src/net/cgo_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_aix.go rename to contrib/go/_std_1.23/src/net/cgo_aix.go diff --git a/contrib/go/_std_1.22/src/net/cgo_android.go b/contrib/go/_std_1.23/src/net/cgo_android.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_android.go rename to contrib/go/_std_1.23/src/net/cgo_android.go diff --git a/contrib/go/_std_1.22/src/net/cgo_bsd.go b/contrib/go/_std_1.23/src/net/cgo_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_bsd.go rename to contrib/go/_std_1.23/src/net/cgo_bsd.go diff --git a/contrib/go/_std_1.22/src/net/cgo_darwin.go b/contrib/go/_std_1.23/src/net/cgo_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_darwin.go rename to contrib/go/_std_1.23/src/net/cgo_darwin.go diff --git a/contrib/go/_std_1.22/src/net/cgo_linux.go b/contrib/go/_std_1.23/src/net/cgo_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_linux.go rename to contrib/go/_std_1.23/src/net/cgo_linux.go diff --git a/contrib/go/_std_1.22/src/net/cgo_netbsd.go b/contrib/go/_std_1.23/src/net/cgo_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_netbsd.go rename to contrib/go/_std_1.23/src/net/cgo_netbsd.go diff --git a/contrib/go/_std_1.22/src/net/cgo_openbsd.go b/contrib/go/_std_1.23/src/net/cgo_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_openbsd.go rename to contrib/go/_std_1.23/src/net/cgo_openbsd.go diff --git a/contrib/go/_std_1.22/src/net/cgo_resnew.go b/contrib/go/_std_1.23/src/net/cgo_resnew.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_resnew.go rename to contrib/go/_std_1.23/src/net/cgo_resnew.go diff --git a/contrib/go/_std_1.22/src/net/cgo_resold.go b/contrib/go/_std_1.23/src/net/cgo_resold.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_resold.go rename to contrib/go/_std_1.23/src/net/cgo_resold.go diff --git a/contrib/go/_std_1.22/src/net/cgo_socknew.go b/contrib/go/_std_1.23/src/net/cgo_socknew.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_socknew.go rename to contrib/go/_std_1.23/src/net/cgo_socknew.go diff --git a/contrib/go/_std_1.22/src/net/cgo_sockold.go b/contrib/go/_std_1.23/src/net/cgo_sockold.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_sockold.go rename to contrib/go/_std_1.23/src/net/cgo_sockold.go diff --git a/contrib/go/_std_1.22/src/net/cgo_solaris.go b/contrib/go/_std_1.23/src/net/cgo_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_solaris.go rename to contrib/go/_std_1.23/src/net/cgo_solaris.go diff --git a/contrib/go/_std_1.22/src/net/cgo_stub.go b/contrib/go/_std_1.23/src/net/cgo_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_stub.go rename to contrib/go/_std_1.23/src/net/cgo_stub.go diff --git a/contrib/go/_std_1.22/src/net/cgo_unix.go b/contrib/go/_std_1.23/src/net/cgo_unix.go similarity index 85% rename from contrib/go/_std_1.22/src/net/cgo_unix.go rename to contrib/go/_std_1.23/src/net/cgo_unix.go index 7ed5daad73a6..bc374c2c7688 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix.go @@ -14,6 +14,7 @@ package net import ( "context" "errors" + "internal/bytealg" "net/netip" "syscall" "unsafe" @@ -40,8 +41,20 @@ func (eai addrinfoErrno) isAddrinfoErrno() {} // doBlockingWithCtx executes a blocking function in a separate goroutine when the provided // context is cancellable. It is intended for use with calls that don't support context // cancellation (cgo, syscalls). blocking func may still be running after this function finishes. -func doBlockingWithCtx[T any](ctx context.Context, blocking func() (T, error)) (T, error) { +// For the duration of the execution of the blocking function, the thread is 'acquired' using [acquireThread], +// blocking might not be executed when the context gets canceled early. +func doBlockingWithCtx[T any](ctx context.Context, lookupName string, blocking func() (T, error)) (T, error) { + if err := acquireThread(ctx); err != nil { + var zero T + return zero, &DNSError{ + Name: lookupName, + Err: mapErr(err).Error(), + IsTimeout: err == context.DeadlineExceeded, + } + } + if ctx.Done() == nil { + defer releaseThread() return blocking() } @@ -52,6 +65,7 @@ func doBlockingWithCtx[T any](ctx context.Context, blocking func() (T, error)) ( res := make(chan result, 1) go func() { + defer releaseThread() var r result r.res, r.err = blocking() res <- r @@ -62,7 +76,11 @@ func doBlockingWithCtx[T any](ctx context.Context, blocking func() (T, error)) ( return r.res, r.err case <-ctx.Done(): var zero T - return zero, mapErr(ctx.Err()) + return zero, &DNSError{ + Name: lookupName, + Err: mapErr(ctx.Err()).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } } } @@ -97,7 +115,7 @@ func cgoLookupPort(ctx context.Context, network, service string) (port int, err *_C_ai_family(&hints) = _C_AF_INET6 } - return doBlockingWithCtx(ctx, func() (int, error) { + return doBlockingWithCtx(ctx, network+"/"+service, func() (int, error) { return cgoLookupServicePort(&hints, network, service) }) } @@ -114,19 +132,17 @@ func cgoLookupServicePort(hints *_C_struct_addrinfo, network, service string) (p var res *_C_struct_addrinfo gerrno, err := _C_getaddrinfo(nil, (*_C_char)(unsafe.Pointer(&cservice[0])), hints, &res) if gerrno != 0 { - isTemporary := false switch gerrno { case _C_EAI_SYSTEM: if err == nil { // see golang.org/issue/6232 err = syscall.EMFILE } + return 0, newDNSError(err, network+"/"+service, "") case _C_EAI_SERVICE, _C_EAI_NONAME: // Darwin returns EAI_NONAME. - return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true} + return 0, newDNSError(errUnknownPort, network+"/"+service, "") default: - err = addrinfoErrno(gerrno) - isTemporary = addrinfoErrno(gerrno).Temporary() + return 0, newDNSError(addrinfoErrno(gerrno), network+"/"+service, "") } - return 0, &DNSError{Err: err.Error(), Name: network + "/" + service, IsTemporary: isTemporary} } defer _C_freeaddrinfo(res) @@ -142,13 +158,10 @@ func cgoLookupServicePort(hints *_C_struct_addrinfo, network, service string) (p return int(p[0])<<8 | int(p[1]), nil } } - return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true} + return 0, newDNSError(errUnknownPort, network+"/"+service, "") } func cgoLookupHostIP(network, name string) (addrs []IPAddr, err error) { - acquireThread() - defer releaseThread() - var hints _C_struct_addrinfo *_C_ai_flags(&hints) = cgoAddrInfoFlags *_C_ai_socktype(&hints) = _C_SOCK_STREAM @@ -167,8 +180,6 @@ func cgoLookupHostIP(network, name string) (addrs []IPAddr, err error) { var res *_C_struct_addrinfo gerrno, err := _C_getaddrinfo((*_C_char)(unsafe.Pointer(h)), nil, &hints, &res) if gerrno != 0 { - isErrorNoSuchHost := false - isTemporary := false switch gerrno { case _C_EAI_SYSTEM: if err == nil { @@ -181,15 +192,13 @@ func cgoLookupHostIP(network, name string) (addrs []IPAddr, err error) { // comes up again. golang.org/issue/6232. err = syscall.EMFILE } + return nil, newDNSError(err, name, "") case _C_EAI_NONAME, _C_EAI_NODATA: - err = errNoSuchHost - isErrorNoSuchHost = true + return nil, newDNSError(errNoSuchHost, name, "") default: - err = addrinfoErrno(gerrno) - isTemporary = addrinfoErrno(gerrno).Temporary() + return nil, newDNSError(addrinfoErrno(gerrno), name, "") } - return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: isErrorNoSuchHost, IsTemporary: isTemporary} } defer _C_freeaddrinfo(res) @@ -213,7 +222,7 @@ func cgoLookupHostIP(network, name string) (addrs []IPAddr, err error) { } func cgoLookupIP(ctx context.Context, network, name string) (addrs []IPAddr, err error) { - return doBlockingWithCtx(ctx, func() ([]IPAddr, error) { + return doBlockingWithCtx(ctx, name, func() ([]IPAddr, error) { return cgoLookupHostIP(network, name) }) } @@ -241,15 +250,12 @@ func cgoLookupPTR(ctx context.Context, addr string) (names []string, err error) return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr} } - return doBlockingWithCtx(ctx, func() ([]string, error) { + return doBlockingWithCtx(ctx, addr, func() ([]string, error) { return cgoLookupAddrPTR(addr, sa, salen) }) } func cgoLookupAddrPTR(addr string, sa *_C_struct_sockaddr, salen _C_socklen_t) (names []string, err error) { - acquireThread() - defer releaseThread() - var gerrno int var b []byte for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 { @@ -260,27 +266,20 @@ func cgoLookupAddrPTR(addr string, sa *_C_struct_sockaddr, salen _C_socklen_t) ( } } if gerrno != 0 { - isErrorNoSuchHost := false - isTemporary := false switch gerrno { case _C_EAI_SYSTEM: if err == nil { // see golang.org/issue/6232 err = syscall.EMFILE } + return nil, newDNSError(err, addr, "") case _C_EAI_NONAME: - err = errNoSuchHost - isErrorNoSuchHost = true + return nil, newDNSError(errNoSuchHost, addr, "") default: - err = addrinfoErrno(gerrno) - isTemporary = addrinfoErrno(gerrno).Temporary() + return nil, newDNSError(addrinfoErrno(gerrno), addr, "") } - return nil, &DNSError{Err: err.Error(), Name: addr, IsTemporary: isTemporary, IsNotFound: isErrorNoSuchHost} } - for i := 0; i < len(b); i++ { - if b[i] == 0 { - b = b[:i] - break - } + if i := bytealg.IndexByte(b, 0); i != -1 { + b = b[:i] } return []string{absDomainName(string(b))}, nil } @@ -310,15 +309,12 @@ func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, // resSearch will make a call to the 'res_nsearch' routine in the C library // and parse the output as a slice of DNS resources. func resSearch(ctx context.Context, hostname string, rtype, class int) ([]dnsmessage.Resource, error) { - return doBlockingWithCtx(ctx, func() ([]dnsmessage.Resource, error) { + return doBlockingWithCtx(ctx, hostname, func() ([]dnsmessage.Resource, error) { return cgoResSearch(hostname, rtype, class) }) } func cgoResSearch(hostname string, rtype, class int) ([]dnsmessage.Resource, error) { - acquireThread() - defer releaseThread() - resStateSize := unsafe.Sizeof(_C_struct___res_state{}) var state *_C_struct___res_state if resStateSize > 0 { @@ -352,7 +348,7 @@ func cgoResSearch(hostname string, rtype, class int) ([]dnsmessage.Resource, err var size int for { - size, _ = _C_res_nsearch(state, (*_C_char)(unsafe.Pointer(s)), class, rtype, buf, bufSize) + size := _C_res_nsearch(state, (*_C_char)(unsafe.Pointer(s)), class, rtype, buf, bufSize) if size <= 0 || size > 0xffff { return nil, errors.New("res_nsearch failure") } diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_cgo.go b/contrib/go/_std_1.23/src/net/cgo_unix_cgo.go similarity index 99% rename from contrib/go/_std_1.22/src/net/cgo_unix_cgo.go rename to contrib/go/_std_1.23/src/net/cgo_unix_cgo.go index 7c609eddbf76..d38ae0a84f2b 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix_cgo.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix_cgo.go @@ -7,7 +7,7 @@ package net /* -#define _GNU_SOURCE +#define _GNU_SOURCE 1 #cgo CFLAGS: -fno-stack-protector #include diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_res.go b/contrib/go/_std_1.23/src/net/cgo_unix_cgo_res.go similarity index 82% rename from contrib/go/_std_1.22/src/net/cgo_unix_cgo_res.go rename to contrib/go/_std_1.23/src/net/cgo_unix_cgo_res.go index 37bbc9a762d8..c5f30238a13c 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_res.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix_cgo_res.go @@ -32,7 +32,7 @@ func _C_res_nclose(state *_C_struct___res_state) { return } -func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_uchar, anslen int) (int, error) { - x, err := C.res_search(dname, C.int(class), C.int(typ), ans, C.int(anslen)) - return int(x), err +func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_uchar, anslen int) int { + x := C.res_search(dname, C.int(class), C.int(typ), ans, C.int(anslen)) + return int(x) } diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_resn.go b/contrib/go/_std_1.23/src/net/cgo_unix_cgo_resn.go similarity index 83% rename from contrib/go/_std_1.22/src/net/cgo_unix_cgo_resn.go rename to contrib/go/_std_1.23/src/net/cgo_unix_cgo_resn.go index 4a5ff165dfae..4fc747b5a339 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_resn.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix_cgo_resn.go @@ -33,7 +33,7 @@ func _C_res_nclose(state *_C_struct___res_state) { C.res_nclose(state) } -func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_uchar, anslen int) (int, error) { - x, err := C.res_nsearch(state, dname, C.int(class), C.int(typ), ans, C.int(anslen)) - return int(x), err +func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_uchar, anslen int) int { + x := C.res_nsearch(state, dname, C.int(class), C.int(typ), ans, C.int(anslen)) + return int(x) } diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_syscall.go b/contrib/go/_std_1.23/src/net/cgo_unix_syscall.go similarity index 95% rename from contrib/go/_std_1.22/src/net/cgo_unix_syscall.go rename to contrib/go/_std_1.23/src/net/cgo_unix_syscall.go index ac9aaa78fe7c..735dcdfe368b 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix_syscall.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix_syscall.go @@ -73,8 +73,9 @@ func _C_res_ninit(state *_C_struct___res_state) error { return nil } -func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_char, anslen int) (int, error) { - return unix.ResNsearch(state, dname, class, typ, ans, anslen) +func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_char, anslen int) int { + x, _ := unix.ResNsearch(state, dname, class, typ, ans, anslen) + return x } func _C_res_nclose(state *_C_struct___res_state) { diff --git a/contrib/go/_std_1.22/src/net/conf.go b/contrib/go/_std_1.23/src/net/conf.go similarity index 95% rename from contrib/go/_std_1.22/src/net/conf.go rename to contrib/go/_std_1.23/src/net/conf.go index 15d73cf6ce1a..358f5434c4de 100644 --- a/contrib/go/_std_1.22/src/net/conf.go +++ b/contrib/go/_std_1.23/src/net/conf.go @@ -8,6 +8,7 @@ import ( "errors" "internal/bytealg" "internal/godebug" + "internal/stringslite" "io/fs" "os" "runtime" @@ -190,7 +191,7 @@ func (c *conf) mustUseGoResolver(r *Resolver) bool { if runtime.GOOS == "plan9" { // TODO(bradfitz): for now we only permit use of the PreferGo // implementation when there's a non-nil Resolver with a - // non-nil Dialer. This is a sign that they the code is trying + // non-nil Dialer. This is a sign that the code is trying // to use their DNS-speaking net.Conn (such as an in-memory // DNS cache) and they don't want to actually hit the network. // Once we add support for looking the default DNS servers @@ -335,16 +336,7 @@ func (c *conf) lookupOrder(r *Resolver, hostname string) (ret hostLookupOrder, d } // Canonicalize the hostname by removing any trailing dot. - if stringsHasSuffix(hostname, ".") { - hostname = hostname[:len(hostname)-1] - } - if canUseCgo && stringsHasSuffixFold(hostname, ".local") { - // Per RFC 6762, the ".local" TLD is special. And - // because Go's native resolver doesn't do mDNS or - // similar local resolution mechanisms, assume that - // libc might (via Avahi, etc) and use cgo. - return hostLookupCgo, dnsConf - } + hostname = stringslite.TrimSuffix(hostname, ".") nss := getSystemNSS() srcs := nss.sources["hosts"] @@ -403,10 +395,14 @@ func (c *conf) lookupOrder(r *Resolver, hostname string) (ret hostLookupOrder, d return hostLookupCgo, dnsConf } continue - case hostname != "" && stringsHasPrefix(src.source, "mdns"): - // e.g. "mdns4", "mdns4_minimal" - // We already returned true before if it was *.local. - // libc wouldn't have found a hit on this anyway. + case hostname != "" && stringslite.HasPrefix(src.source, "mdns"): + if stringsHasSuffixFold(hostname, ".local") { + // Per RFC 6762, the ".local" TLD is special. And + // because Go's native resolver doesn't do mDNS or + // similar local resolution mechanisms, assume that + // libc might (via Avahi, etc) and use cgo. + return hostLookupCgo, dnsConf + } // We don't parse mdns.allow files. They're rare. If one // exists, it might list other TLDs (besides .local) or even diff --git a/contrib/go/_std_1.22/src/net/dial.go b/contrib/go/_std_1.23/src/net/dial.go similarity index 94% rename from contrib/go/_std_1.22/src/net/dial.go rename to contrib/go/_std_1.23/src/net/dial.go index a6565c3ce5d1..28f346a372a7 100644 --- a/contrib/go/_std_1.22/src/net/dial.go +++ b/contrib/go/_std_1.23/src/net/dial.go @@ -14,9 +14,16 @@ import ( ) const ( - // defaultTCPKeepAlive is a default constant value for TCPKeepAlive times - // See go.dev/issue/31510 - defaultTCPKeepAlive = 15 * time.Second + // defaultTCPKeepAliveIdle is a default constant value for TCP_KEEPIDLE. + // See go.dev/issue/31510 for details. + defaultTCPKeepAliveIdle = 15 * time.Second + + // defaultTCPKeepAliveInterval is a default constant value for TCP_KEEPINTVL. + // It is the same as defaultTCPKeepAliveIdle, see go.dev/issue/31510 for details. + defaultTCPKeepAliveInterval = 15 * time.Second + + // defaultTCPKeepAliveCount is a default constant value for TCP_KEEPCNT. + defaultTCPKeepAliveCount = 9 // For the moment, MultiPath TCP is not used by default // See go.dev/issue/56539 @@ -116,13 +123,25 @@ type Dialer struct { // KeepAlive specifies the interval between keep-alive // probes for an active network connection. + // + // KeepAlive is ignored if KeepAliveConfig.Enable is true. + // // If zero, keep-alive probes are sent with a default value // (currently 15 seconds), if supported by the protocol and operating // system. Network protocols or operating systems that do - // not support keep-alives ignore this field. + // not support keep-alive ignore this field. // If negative, keep-alive probes are disabled. KeepAlive time.Duration + // KeepAliveConfig specifies the keep-alive probe configuration + // for an active network connection, when supported by the + // protocol and operating system. + // + // If KeepAliveConfig.Enable is true, keep-alive probes are enabled. + // If KeepAliveConfig.Enable is false and KeepAlive is negative, + // keep-alive probes are disabled. + KeepAliveConfig KeepAliveConfig + // Resolver optionally specifies an alternate resolver to use. Resolver *Resolver @@ -680,12 +699,24 @@ type ListenConfig struct { // KeepAlive specifies the keep-alive period for network // connections accepted by this listener. - // If zero, keep-alives are enabled if supported by the protocol + // + // KeepAlive is ignored if KeepAliveConfig.Enable is true. + // + // If zero, keep-alive are enabled if supported by the protocol // and operating system. Network protocols or operating systems - // that do not support keep-alives ignore this field. - // If negative, keep-alives are disabled. + // that do not support keep-alive ignore this field. + // If negative, keep-alive are disabled. KeepAlive time.Duration + // KeepAliveConfig specifies the keep-alive probe configuration + // for an active network connection, when supported by the + // protocol and operating system. + // + // If KeepAliveConfig.Enable is true, keep-alive probes are enabled. + // If KeepAliveConfig.Enable is false and KeepAlive is negative, + // keep-alive probes are disabled. + KeepAliveConfig KeepAliveConfig + // If mptcpStatus is set to a value allowing Multipath TCP (MPTCP) to be // used, any call to Listen with "tcp(4|6)" as network will use MPTCP if // supported by the operating system. diff --git a/contrib/go/_std_1.22/src/net/dnsclient.go b/contrib/go/_std_1.23/src/net/dnsclient.go similarity index 89% rename from contrib/go/_std_1.22/src/net/dnsclient.go rename to contrib/go/_std_1.23/src/net/dnsclient.go index 204620b2edb8..5f135cc21173 100644 --- a/contrib/go/_std_1.22/src/net/dnsclient.go +++ b/contrib/go/_std_1.23/src/net/dnsclient.go @@ -5,15 +5,17 @@ package net import ( + "cmp" "internal/bytealg" "internal/itoa" - "sort" + "slices" _ "unsafe" // for go:linkname "golang.org/x/net/dns/dnsmessage" ) // provided by runtime +// //go:linkname runtime_rand runtime.rand func runtime_rand() uint64 @@ -74,6 +76,16 @@ func equalASCIIName(x, y dnsmessage.Name) bool { // isDomainName checks if a string is a presentation-format domain name // (currently restricted to hostname-compatible "preferred name" LDH labels and // SRV-like "underscore labels"; see golang.org/issue/12421). +// +// isDomainName should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname isDomainName func isDomainName(s string) bool { // The root domain name is valid. See golang.org/issue/45715. if s == "." { @@ -159,12 +171,6 @@ type SRV struct { // byPriorityWeight sorts SRV records by ascending priority and weight. type byPriorityWeight []*SRV -func (s byPriorityWeight) Len() int { return len(s) } -func (s byPriorityWeight) Less(i, j int) bool { - return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight) -} -func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // shuffleByWeight shuffles SRV records by weight using the algorithm // described in RFC 2782. func (addrs byPriorityWeight) shuffleByWeight() { @@ -191,7 +197,12 @@ func (addrs byPriorityWeight) shuffleByWeight() { // sort reorders SRV records as specified in RFC 2782. func (addrs byPriorityWeight) sort() { - sort.Sort(addrs) + slices.SortFunc(addrs, func(a, b *SRV) int { + if r := cmp.Compare(a.Priority, b.Priority); r != 0 { + return r + } + return cmp.Compare(a.Weight, b.Weight) + }) i := 0 for j := 1; j < len(addrs); j++ { if addrs[i].Priority != addrs[j].Priority { @@ -208,20 +219,18 @@ type MX struct { Pref uint16 } -// byPref implements sort.Interface to sort MX records by preference +// byPref sorts MX records by preference type byPref []*MX -func (s byPref) Len() int { return len(s) } -func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref } -func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // sort reorders MX records as specified in RFC 5321. func (s byPref) sort() { for i := range s { j := randIntn(i + 1) s[i], s[j] = s[j], s[i] } - sort.Sort(s) + slices.SortFunc(s, func(a, b *MX) int { + return cmp.Compare(a.Pref, b.Pref) + }) } // An NS represents a single DNS NS record. diff --git a/contrib/go/_std_1.22/src/net/dnsclient_unix.go b/contrib/go/_std_1.23/src/net/dnsclient_unix.go similarity index 92% rename from contrib/go/_std_1.22/src/net/dnsclient_unix.go rename to contrib/go/_std_1.23/src/net/dnsclient_unix.go index 8821641a0162..54c7dc83bac6 100644 --- a/contrib/go/_std_1.22/src/net/dnsclient_unix.go +++ b/contrib/go/_std_1.23/src/net/dnsclient_unix.go @@ -49,7 +49,7 @@ var ( // errServerTemporarilyMisbehaving is like errServerMisbehaving, except // that when it gets translated to a DNSError, the IsTemporary field // gets set to true. - errServerTemporarilyMisbehaving = errors.New("server misbehaving") + errServerTemporarilyMisbehaving = &temporaryError{"server misbehaving"} ) // netedns0 controls whether we send an EDNS0 additional header. @@ -202,7 +202,14 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone { return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse } - if h.Truncated { // see RFC 5966 + // RFC 5966 indicates that when a client receives a UDP response with + // the TC flag set, it should take the TC flag as an indication that it + // should retry over TCP instead. + // The case when the TC flag is set in a TCP response is not well specified, + // so this implements the glibc resolver behavior, returning the existing + // dns response instead of returning a "errNoAnswerFromDNSServer" error. + // See go.dev/issue/64896 + if h.Truncated && network == "udp" { continue } return p, h, nil @@ -212,7 +219,7 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que // checkHeader performs basic sanity checks on the header. func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error { - rcode := extractExtendedRCode(*p, h) + rcode, hasAdd := extractExtendedRCode(*p, h) if rcode == dnsmessage.RCodeNameError { return errNoSuchHost @@ -225,7 +232,7 @@ func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error { // libresolv continues to the next server when it receives // an invalid referral response. See golang.org/issue/15434. - if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone { + if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone && !hasAdd { return errLameReferral } @@ -264,19 +271,22 @@ func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error { // extractExtendedRCode extracts the extended RCode from the OPT resource (EDNS(0)) // If an OPT record is not found, the RCode from the hdr is returned. -func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) dnsmessage.RCode { +// Another return value indicates whether an additional resource was found. +func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) (dnsmessage.RCode, bool) { p.SkipAllAnswers() p.SkipAllAuthorities() + hasAdd := false for { ahdr, err := p.AdditionalHeader() if err != nil { - return hdr.RCode + return hdr.RCode, hasAdd } + hasAdd = true if ahdr.Type == dnsmessage.TypeOPT { - return ahdr.ExtendedRCode(hdr.RCode) + return ahdr.ExtendedRCode(hdr.RCode), hasAdd } if err := p.SkipAdditional(); err != nil { - return hdr.RCode + return hdr.RCode, hasAdd } } } @@ -290,7 +300,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, n, err := dnsmessage.NewName(name) if err != nil { - return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage + return dnsmessage.Parser{}, "", &DNSError{Err: errCannotMarshalDNSMessage.Error(), Name: name} } q := dnsmessage.Question{ Name: n, @@ -304,14 +314,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP, cfg.trustAD) if err != nil { - dnsErr := &DNSError{ - Err: err.Error(), - Name: name, - Server: server, - } - if nerr, ok := err.(Error); ok && nerr.Timeout() { - dnsErr.IsTimeout = true - } + dnsErr := newDNSError(err, name, server) // Set IsTemporary for socket-level errors. Note that this flag // may also be used to indicate a SERVFAIL response. if _, ok := err.(*OpError); ok { @@ -322,41 +325,26 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, } if err := checkHeader(&p, h); err != nil { - dnsErr := &DNSError{ - Err: err.Error(), - Name: name, - Server: server, - } - if err == errServerTemporarilyMisbehaving { - dnsErr.IsTemporary = true - } if err == errNoSuchHost { // The name does not exist, so trying // another server won't help. - - dnsErr.IsNotFound = true - return p, server, dnsErr + return p, server, newDNSError(errNoSuchHost, name, server) } - lastErr = dnsErr + lastErr = newDNSError(err, name, server) continue } - err = skipToAnswer(&p, qtype) - if err == nil { - return p, server, nil - } - lastErr = &DNSError{ - Err: err.Error(), - Name: name, - Server: server, + if err := skipToAnswer(&p, qtype); err != nil { + if err == errNoSuchHost { + // The name does not exist, so trying + // another server won't help. + return p, server, newDNSError(errNoSuchHost, name, server) + } + lastErr = newDNSError(err, name, server) + continue } - if err == errNoSuchHost { - // The name does not exist, so trying another - // server won't help. - lastErr.(*DNSError).IsNotFound = true - return p, server, lastErr - } + return p, server, nil } } return dnsmessage.Parser{}, "", lastErr @@ -456,7 +444,7 @@ func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Typ // Other lookups might allow broader name syntax // (for example Multicast DNS allows UTF-8; see RFC 6762). // For consistency with libc resolvers, report no such host. - return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return dnsmessage.Parser{}, "", newDNSError(errNoSuchHost, name, "") } if conf == nil { @@ -584,7 +572,7 @@ func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hos } if order == hostLookupFiles { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return nil, newDNSError(errNoSuchHost, name, "") } } ips, _, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order, conf) @@ -634,13 +622,13 @@ func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name strin } if order == hostLookupFiles { - return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, name, "") } } if !isDomainName(name) { // See comment in func lookup above about use of errNoSuchHost. - return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, name, "") } type result struct { p dnsmessage.Parser @@ -845,7 +833,7 @@ func (r *Resolver) goLookupPTR(ctx context.Context, addr string, order hostLooku } if order == hostLookupFiles { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: addr, IsNotFound: true} + return nil, newDNSError(errNoSuchHost, addr, "") } } diff --git a/contrib/go/_std_1.23/src/net/dnsconfig.go b/contrib/go/_std_1.23/src/net/dnsconfig.go new file mode 100644 index 000000000000..7919c3c3b551 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/dnsconfig.go @@ -0,0 +1,58 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "os" + "sync/atomic" + "time" + _ "unsafe" +) + +// defaultNS is the default name servers to use in the absence of DNS configuration. +// +// defaultNS should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/pojntfx/hydrapp/hydrapp +// - github.com/mtibben/androiddnsfix +// - github.com/metacubex/mihomo +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname defaultNS +var defaultNS = []string{"127.0.0.1:53", "[::1]:53"} + +var getHostname = os.Hostname // variable for testing + +type dnsConfig struct { + servers []string // server addresses (in host:port form) to use + search []string // rooted suffixes to append to local name + ndots int // number of dots in name to trigger absolute lookup + timeout time.Duration // wait before giving up on a query, including retries + attempts int // lost packets before giving up on server + rotate bool // round robin among servers + unknownOpt bool // anything unknown was encountered + lookup []string // OpenBSD top-level database "lookup" order + err error // any error that occurs during open of resolv.conf + mtime time.Time // time of resolv.conf modification + soffset uint32 // used by serverOffset + singleRequest bool // use sequential A and AAAA queries instead of parallel queries + useTCP bool // force usage of TCP for DNS resolutions + trustAD bool // add AD flag to queries + noReload bool // do not check for config file updates +} + +// serverOffset returns an offset that can be used to determine +// indices of servers in c.servers when making queries. +// When the rotate option is enabled, this offset increases. +// Otherwise it is always 0. +func (c *dnsConfig) serverOffset() uint32 { + if c.rotate { + return atomic.AddUint32(&c.soffset, 1) - 1 // return 0 to start + } + return 0 +} diff --git a/contrib/go/_std_1.22/src/net/dnsconfig_unix.go b/contrib/go/_std_1.23/src/net/dnsconfig_unix.go similarity index 95% rename from contrib/go/_std_1.22/src/net/dnsconfig_unix.go rename to contrib/go/_std_1.23/src/net/dnsconfig_unix.go index b0a318279b99..0fcf2c6cc384 100644 --- a/contrib/go/_std_1.22/src/net/dnsconfig_unix.go +++ b/contrib/go/_std_1.23/src/net/dnsconfig_unix.go @@ -10,6 +10,7 @@ package net import ( "internal/bytealg" + "internal/stringslite" "net/netip" "time" ) @@ -75,7 +76,7 @@ func dnsReadConfig(filename string) *dnsConfig { case "options": // magic options for _, s := range f[1:] { switch { - case hasPrefix(s, "ndots:"): + case stringslite.HasPrefix(s, "ndots:"): n, _, _ := dtoi(s[6:]) if n < 0 { n = 0 @@ -83,13 +84,13 @@ func dnsReadConfig(filename string) *dnsConfig { n = 15 } conf.ndots = n - case hasPrefix(s, "timeout:"): + case stringslite.HasPrefix(s, "timeout:"): n, _, _ := dtoi(s[8:]) if n < 1 { n = 1 } conf.timeout = time.Duration(n) * time.Second - case hasPrefix(s, "attempts:"): + case stringslite.HasPrefix(s, "attempts:"): n, _, _ := dtoi(s[9:]) if n < 1 { n = 1 @@ -155,10 +156,6 @@ func dnsDefaultSearch() []string { return nil } -func hasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[:len(prefix)] == prefix -} - func ensureRooted(s string) string { if len(s) > 0 && s[len(s)-1] == '.' { return s diff --git a/contrib/go/_std_1.23/src/net/dnsconfig_windows.go b/contrib/go/_std_1.23/src/net/dnsconfig_windows.go new file mode 100644 index 000000000000..34455309dbb2 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/dnsconfig_windows.go @@ -0,0 +1,68 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "internal/syscall/windows" + "syscall" + "time" +) + +func dnsReadConfig(ignoredFilename string) (conf *dnsConfig) { + conf = &dnsConfig{ + ndots: 1, + timeout: 5 * time.Second, + attempts: 2, + } + defer func() { + if len(conf.servers) == 0 { + conf.servers = defaultNS + } + }() + aas, err := adapterAddresses() + if err != nil { + return + } + + for _, aa := range aas { + // Only take interfaces whose OperStatus is IfOperStatusUp(0x01) into DNS configs. + if aa.OperStatus != windows.IfOperStatusUp { + continue + } + + // Only take interfaces which have at least one gateway + if aa.FirstGatewayAddress == nil { + continue + } + + for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next { + sa, err := dns.Address.Sockaddr.Sockaddr() + if err != nil { + continue + } + var ip IP + switch sa := sa.(type) { + case *syscall.SockaddrInet4: + ip = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) + case *syscall.SockaddrInet6: + ip = make(IP, IPv6len) + copy(ip, sa.Addr[:]) + if ip[0] == 0xfe && ip[1] == 0xc0 { + // fec0/10 IPv6 addresses are site local anycast DNS + // addresses Microsoft sets by default if no other + // IPv6 DNS address is set. Site local anycast is + // deprecated since 2004, see + // https://datatracker.ietf.org/doc/html/rfc3879 + continue + } + default: + // Unexpected type. + continue + } + conf.servers = append(conf.servers, JoinHostPort(ip.String(), "53")) + } + } + return conf +} diff --git a/contrib/go/_std_1.22/src/net/error_plan9.go b/contrib/go/_std_1.23/src/net/error_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/error_plan9.go rename to contrib/go/_std_1.23/src/net/error_plan9.go diff --git a/contrib/go/_std_1.22/src/net/error_posix.go b/contrib/go/_std_1.23/src/net/error_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/error_posix.go rename to contrib/go/_std_1.23/src/net/error_posix.go diff --git a/contrib/go/_std_1.22/src/net/error_unix.go b/contrib/go/_std_1.23/src/net/error_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/error_unix.go rename to contrib/go/_std_1.23/src/net/error_unix.go diff --git a/contrib/go/_std_1.22/src/net/error_windows.go b/contrib/go/_std_1.23/src/net/error_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/error_windows.go rename to contrib/go/_std_1.23/src/net/error_windows.go diff --git a/contrib/go/_std_1.22/src/net/fd_fake.go b/contrib/go/_std_1.23/src/net/fd_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_fake.go rename to contrib/go/_std_1.23/src/net/fd_fake.go diff --git a/contrib/go/_std_1.22/src/net/fd_js.go b/contrib/go/_std_1.23/src/net/fd_js.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_js.go rename to contrib/go/_std_1.23/src/net/fd_js.go diff --git a/contrib/go/_std_1.22/src/net/fd_plan9.go b/contrib/go/_std_1.23/src/net/fd_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_plan9.go rename to contrib/go/_std_1.23/src/net/fd_plan9.go diff --git a/contrib/go/_std_1.22/src/net/fd_posix.go b/contrib/go/_std_1.23/src/net/fd_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_posix.go rename to contrib/go/_std_1.23/src/net/fd_posix.go diff --git a/contrib/go/_std_1.22/src/net/fd_unix.go b/contrib/go/_std_1.23/src/net/fd_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_unix.go rename to contrib/go/_std_1.23/src/net/fd_unix.go diff --git a/contrib/go/_std_1.22/src/net/fd_wasip1.go b/contrib/go/_std_1.23/src/net/fd_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_wasip1.go rename to contrib/go/_std_1.23/src/net/fd_wasip1.go diff --git a/contrib/go/_std_1.23/src/net/fd_windows.go b/contrib/go/_std_1.23/src/net/fd_windows.go new file mode 100644 index 000000000000..5d7a1d54c31a --- /dev/null +++ b/contrib/go/_std_1.23/src/net/fd_windows.go @@ -0,0 +1,221 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "context" + "internal/poll" + "internal/syscall/windows" + "os" + "runtime" + "syscall" + "unsafe" +) + +const ( + readSyscallName = "wsarecv" + readFromSyscallName = "wsarecvfrom" + readMsgSyscallName = "wsarecvmsg" + writeSyscallName = "wsasend" + writeToSyscallName = "wsasendto" + writeMsgSyscallName = "wsasendmsg" +) + +func init() { + poll.InitWSA() +} + +// canUseConnectEx reports whether we can use the ConnectEx Windows API call +// for the given network type. +func canUseConnectEx(net string) bool { + switch net { + case "tcp", "tcp4", "tcp6": + return true + } + // ConnectEx windows API does not support connectionless sockets. + return false +} + +func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) { + ret := &netFD{ + pfd: poll.FD{ + Sysfd: sysfd, + IsStream: sotype == syscall.SOCK_STREAM, + ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW, + }, + family: family, + sotype: sotype, + net: net, + } + return ret, nil +} + +func (fd *netFD) init() error { + errcall, err := fd.pfd.Init(fd.net, true) + if errcall != "" { + err = wrapSyscallError(errcall, err) + } + return err +} + +// Always returns nil for connected peer address result. +func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (syscall.Sockaddr, error) { + // Do not need to call fd.writeLock here, + // because fd is not yet accessible to user, + // so no concurrent operations are possible. + if err := fd.init(); err != nil { + return nil, err + } + + if ctx.Done() != nil { + // Propagate the Context's deadline and cancellation. + // If the context is already done, or if it has a nonzero deadline, + // ensure that that is applied before the call to ConnectEx begins + // so that we don't return spurious connections. + defer fd.pfd.SetWriteDeadline(noDeadline) + + if ctx.Err() != nil { + fd.pfd.SetWriteDeadline(aLongTimeAgo) + } else { + if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { + fd.pfd.SetWriteDeadline(deadline) + } + + done := make(chan struct{}) + stop := context.AfterFunc(ctx, func() { + // Force the runtime's poller to immediately give + // up waiting for writability. + fd.pfd.SetWriteDeadline(aLongTimeAgo) + close(done) + }) + defer func() { + if !stop() { + // Wait for the call to SetWriteDeadline to complete so that we can + // reset the deadline if everything else succeeded. + <-done + } + }() + } + } + + if !canUseConnectEx(fd.net) { + err := connectFunc(fd.pfd.Sysfd, ra) + return nil, os.NewSyscallError("connect", err) + } + // ConnectEx windows API requires an unconnected, previously bound socket. + if la == nil { + switch ra.(type) { + case *syscall.SockaddrInet4: + la = &syscall.SockaddrInet4{} + case *syscall.SockaddrInet6: + la = &syscall.SockaddrInet6{} + default: + panic("unexpected type in connect") + } + if err := syscall.Bind(fd.pfd.Sysfd, la); err != nil { + return nil, os.NewSyscallError("bind", err) + } + } + + var isloopback bool + switch ra := ra.(type) { + case *syscall.SockaddrInet4: + isloopback = ra.Addr[0] == 127 + case *syscall.SockaddrInet6: + isloopback = ra.Addr == [16]byte(IPv6loopback) + default: + panic("unexpected type in connect") + } + if isloopback { + // This makes ConnectEx() fails faster if the target port on the localhost + // is not reachable, instead of waiting for 2s. + params := windows.TCP_INITIAL_RTO_PARAMETERS{ + Rtt: windows.TCP_INITIAL_RTO_UNSPECIFIED_RTT, // use the default or overridden by the Administrator + MaxSynRetransmissions: 1, // minimum possible value before Windows 10.0.16299 + } + if windows.SupportTCPInitialRTONoSYNRetransmissions() { + // In Windows 10.0.16299 TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS makes ConnectEx() fails instantly. + params.MaxSynRetransmissions = windows.TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS + } + var out uint32 + // Don't abort the connection if WSAIoctl fails, as it is only an optimization. + // If it fails reliably, we expect TestDialClosedPortFailFast to detect it. + _ = fd.pfd.WSAIoctl(windows.SIO_TCP_INITIAL_RTO, (*byte)(unsafe.Pointer(¶ms)), uint32(unsafe.Sizeof(params)), nil, 0, &out, nil, 0) + } + + // Call ConnectEx API. + if err := fd.pfd.ConnectEx(ra); err != nil { + select { + case <-ctx.Done(): + return nil, mapErr(ctx.Err()) + default: + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("connectex", err) + } + return nil, err + } + } + // Refresh socket properties. + return nil, os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.pfd.Sysfd)), int32(unsafe.Sizeof(fd.pfd.Sysfd)))) +} + +func (c *conn) writeBuffers(v *Buffers) (int64, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + n, err := c.fd.writeBuffers(v) + if err != nil { + return n, &OpError{Op: "wsasend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, nil +} + +func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) { + n, err := fd.pfd.Writev((*[][]byte)(buf)) + runtime.KeepAlive(fd) + return n, wrapSyscallError("wsasend", err) +} + +func (fd *netFD) accept() (*netFD, error) { + s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) { + return sysSocket(fd.family, fd.sotype, 0) + }) + + if err != nil { + if errcall != "" { + err = wrapSyscallError(errcall, err) + } + return nil, err + } + + // Associate our new socket with IOCP. + netfd, err := newFD(s, fd.family, fd.sotype, fd.net) + if err != nil { + poll.CloseFunc(s) + return nil, err + } + if err := netfd.init(); err != nil { + fd.Close() + return nil, err + } + + // Get local and peer addr out of AcceptEx buffer. + var lrsa, rrsa *syscall.RawSockaddrAny + var llen, rlen int32 + syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])), + 0, rsan, rsan, &lrsa, &llen, &rrsa, &rlen) + lsa, _ := lrsa.Sockaddr() + rsa, _ := rrsa.Sockaddr() + + netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) + return netfd, nil +} + +// Unimplemented functions. + +func (fd *netFD) dup() (*os.File, error) { + // TODO: Implement this, perhaps using internal/poll.DupCloseOnExec. + return nil, syscall.EWINDOWS +} diff --git a/contrib/go/_std_1.22/src/net/file.go b/contrib/go/_std_1.23/src/net/file.go similarity index 100% rename from contrib/go/_std_1.22/src/net/file.go rename to contrib/go/_std_1.23/src/net/file.go diff --git a/contrib/go/_std_1.23/src/net/file_plan9.go b/contrib/go/_std_1.23/src/net/file_plan9.go new file mode 100644 index 000000000000..6c2151c4098a --- /dev/null +++ b/contrib/go/_std_1.23/src/net/file_plan9.go @@ -0,0 +1,135 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "errors" + "io" + "os" + "syscall" +) + +func (fd *netFD) status(ln int) (string, error) { + if !fd.ok() { + return "", syscall.EINVAL + } + + status, err := os.Open(fd.dir + "/status") + if err != nil { + return "", err + } + defer status.Close() + buf := make([]byte, ln) + n, err := io.ReadFull(status, buf[:]) + if err != nil { + return "", err + } + return string(buf[:n]), nil +} + +func newFileFD(f *os.File) (net *netFD, err error) { + var ctl *os.File + close := func(fd int) { + if err != nil { + syscall.Close(fd) + } + } + + path, err := syscall.Fd2path(int(f.Fd())) + if err != nil { + return nil, os.NewSyscallError("fd2path", err) + } + comp := splitAtBytes(path, "/") + n := len(comp) + if n < 3 || comp[0][0:3] != "net" { + return nil, syscall.EPLAN9 + } + + name := comp[2] + switch file := comp[n-1]; file { + case "ctl", "clone": + fd, err := syscall.Dup(int(f.Fd()), -1) + if err != nil { + return nil, os.NewSyscallError("dup", err) + } + defer close(fd) + + dir := netdir + "/" + comp[n-2] + ctl = os.NewFile(uintptr(fd), dir+"/"+file) + ctl.Seek(0, io.SeekStart) + var buf [16]byte + n, err := ctl.Read(buf[:]) + if err != nil { + return nil, err + } + name = string(buf[:n]) + default: + if len(comp) < 4 { + return nil, errors.New("could not find control file for connection") + } + dir := netdir + "/" + comp[1] + "/" + name + ctl, err = os.OpenFile(dir+"/ctl", os.O_RDWR, 0) + if err != nil { + return nil, err + } + defer close(int(ctl.Fd())) + } + dir := netdir + "/" + comp[1] + "/" + name + laddr, err := readPlan9Addr(comp[1], dir+"/local") + if err != nil { + return nil, err + } + return newFD(comp[1], name, nil, ctl, nil, laddr, nil) +} + +func fileConn(f *os.File) (Conn, error) { + fd, err := newFileFD(f) + if err != nil { + return nil, err + } + if !fd.ok() { + return nil, syscall.EINVAL + } + + fd.data, err = os.OpenFile(fd.dir+"/data", os.O_RDWR, 0) + if err != nil { + return nil, err + } + + switch fd.laddr.(type) { + case *TCPAddr: + return newTCPConn(fd, defaultTCPKeepAliveIdle, KeepAliveConfig{}, testPreHookSetKeepAlive, testHookSetKeepAlive), nil + case *UDPAddr: + return newUDPConn(fd), nil + } + return nil, syscall.EPLAN9 +} + +func fileListener(f *os.File) (Listener, error) { + fd, err := newFileFD(f) + if err != nil { + return nil, err + } + switch fd.laddr.(type) { + case *TCPAddr: + default: + return nil, syscall.EPLAN9 + } + + // check that file corresponds to a listener + s, err := fd.status(len("Listen")) + if err != nil { + return nil, err + } + if s != "Listen" { + return nil, errors.New("file does not represent a listener") + } + + return &TCPListener{fd: fd}, nil +} + +func filePacketConn(f *os.File) (PacketConn, error) { + return nil, syscall.EPLAN9 +} diff --git a/contrib/go/_std_1.22/src/net/file_stub.go b/contrib/go/_std_1.23/src/net/file_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/file_stub.go rename to contrib/go/_std_1.23/src/net/file_stub.go diff --git a/contrib/go/_std_1.23/src/net/file_unix.go b/contrib/go/_std_1.23/src/net/file_unix.go new file mode 100644 index 000000000000..c0212cef65db --- /dev/null +++ b/contrib/go/_std_1.23/src/net/file_unix.go @@ -0,0 +1,119 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package net + +import ( + "internal/poll" + "os" + "syscall" +) + +func dupSocket(f *os.File) (int, error) { + s, call, err := poll.DupCloseOnExec(int(f.Fd())) + if err != nil { + if call != "" { + err = os.NewSyscallError(call, err) + } + return -1, err + } + if err := syscall.SetNonblock(s, true); err != nil { + poll.CloseFunc(s) + return -1, os.NewSyscallError("setnonblock", err) + } + return s, nil +} + +func newFileFD(f *os.File) (*netFD, error) { + s, err := dupSocket(f) + if err != nil { + return nil, err + } + family := syscall.AF_UNSPEC + sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE) + if err != nil { + poll.CloseFunc(s) + return nil, os.NewSyscallError("getsockopt", err) + } + lsa, _ := syscall.Getsockname(s) + rsa, _ := syscall.Getpeername(s) + switch lsa.(type) { + case *syscall.SockaddrInet4: + family = syscall.AF_INET + case *syscall.SockaddrInet6: + family = syscall.AF_INET6 + case *syscall.SockaddrUnix: + family = syscall.AF_UNIX + default: + poll.CloseFunc(s) + return nil, syscall.EPROTONOSUPPORT + } + fd, err := newFD(s, family, sotype, "") + if err != nil { + poll.CloseFunc(s) + return nil, err + } + laddr := fd.addrFunc()(lsa) + raddr := fd.addrFunc()(rsa) + fd.net = laddr.Network() + if err := fd.init(); err != nil { + fd.Close() + return nil, err + } + fd.setAddr(laddr, raddr) + return fd, nil +} + +func fileConn(f *os.File) (Conn, error) { + fd, err := newFileFD(f) + if err != nil { + return nil, err + } + switch fd.laddr.(type) { + case *TCPAddr: + return newTCPConn(fd, defaultTCPKeepAliveIdle, KeepAliveConfig{}, testPreHookSetKeepAlive, testHookSetKeepAlive), nil + case *UDPAddr: + return newUDPConn(fd), nil + case *IPAddr: + return newIPConn(fd), nil + case *UnixAddr: + return newUnixConn(fd), nil + } + fd.Close() + return nil, syscall.EINVAL +} + +func fileListener(f *os.File) (Listener, error) { + fd, err := newFileFD(f) + if err != nil { + return nil, err + } + switch laddr := fd.laddr.(type) { + case *TCPAddr: + return &TCPListener{fd: fd}, nil + case *UnixAddr: + return &UnixListener{fd: fd, path: laddr.Name, unlink: false}, nil + } + fd.Close() + return nil, syscall.EINVAL +} + +func filePacketConn(f *os.File) (PacketConn, error) { + fd, err := newFileFD(f) + if err != nil { + return nil, err + } + switch fd.laddr.(type) { + case *UDPAddr: + return newUDPConn(fd), nil + case *IPAddr: + return newIPConn(fd), nil + case *UnixAddr: + return newUnixConn(fd), nil + } + fd.Close() + return nil, syscall.EINVAL +} diff --git a/contrib/go/_std_1.22/src/net/file_wasip1.go b/contrib/go/_std_1.23/src/net/file_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/net/file_wasip1.go rename to contrib/go/_std_1.23/src/net/file_wasip1.go diff --git a/contrib/go/_std_1.22/src/net/file_windows.go b/contrib/go/_std_1.23/src/net/file_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/file_windows.go rename to contrib/go/_std_1.23/src/net/file_windows.go diff --git a/contrib/go/_std_1.22/src/net/hook.go b/contrib/go/_std_1.23/src/net/hook.go similarity index 89% rename from contrib/go/_std_1.22/src/net/hook.go rename to contrib/go/_std_1.23/src/net/hook.go index eded34d48abe..08d1aa893481 100644 --- a/contrib/go/_std_1.22/src/net/hook.go +++ b/contrib/go/_std_1.23/src/net/hook.go @@ -6,7 +6,6 @@ package net import ( "context" - "time" ) var ( @@ -21,7 +20,8 @@ var ( ) ([]IPAddr, error) { return fn(ctx, network, host) } - testHookSetKeepAlive = func(time.Duration) {} + testPreHookSetKeepAlive = func(*netFD) {} + testHookSetKeepAlive = func(KeepAliveConfig) {} // testHookStepTime sleeps until time has moved forward by a nonzero amount. // This helps to avoid flakes in timeout tests by ensuring that an implausibly diff --git a/contrib/go/_std_1.22/src/net/hook_plan9.go b/contrib/go/_std_1.23/src/net/hook_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/hook_plan9.go rename to contrib/go/_std_1.23/src/net/hook_plan9.go diff --git a/contrib/go/_std_1.22/src/net/hook_unix.go b/contrib/go/_std_1.23/src/net/hook_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/hook_unix.go rename to contrib/go/_std_1.23/src/net/hook_unix.go diff --git a/contrib/go/_std_1.22/src/net/hook_windows.go b/contrib/go/_std_1.23/src/net/hook_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/hook_windows.go rename to contrib/go/_std_1.23/src/net/hook_windows.go diff --git a/contrib/go/_std_1.22/src/net/hosts.go b/contrib/go/_std_1.23/src/net/hosts.go similarity index 100% rename from contrib/go/_std_1.22/src/net/hosts.go rename to contrib/go/_std_1.23/src/net/hosts.go diff --git a/contrib/go/_std_1.22/src/net/http/cgi/cgi_main.go b/contrib/go/_std_1.23/src/net/http/cgi/cgi_main.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/cgi/cgi_main.go rename to contrib/go/_std_1.23/src/net/http/cgi/cgi_main.go index 8997d66a117d..033036d07fb1 100644 --- a/contrib/go/_std_1.22/src/net/http/cgi/cgi_main.go +++ b/contrib/go/_std_1.23/src/net/http/cgi/cgi_main.go @@ -10,7 +10,7 @@ import ( "net/http" "os" "path" - "sort" + "slices" "strings" "time" ) @@ -67,7 +67,7 @@ func testCGI() { for k := range params { keys = append(keys, k) } - sort.Strings(keys) + slices.Sort(keys) for _, key := range keys { fmt.Printf("param-%s=%s\r\n", key, params.Get(key)) } @@ -77,7 +77,7 @@ func testCGI() { for k := range envs { keys = append(keys, k) } - sort.Strings(keys) + slices.Sort(keys) for _, key := range keys { fmt.Printf("env-%s=%s\r\n", key, envs[key]) } diff --git a/contrib/go/_std_1.22/src/net/http/cgi/child.go b/contrib/go/_std_1.23/src/net/http/cgi/child.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/cgi/child.go rename to contrib/go/_std_1.23/src/net/http/cgi/child.go diff --git a/contrib/go/_std_1.22/src/net/http/cgi/host.go b/contrib/go/_std_1.23/src/net/http/cgi/host.go similarity index 99% rename from contrib/go/_std_1.22/src/net/http/cgi/host.go rename to contrib/go/_std_1.23/src/net/http/cgi/host.go index ef222ab73a75..c03fabb80772 100644 --- a/contrib/go/_std_1.22/src/net/http/cgi/host.go +++ b/contrib/go/_std_1.23/src/net/http/cgi/host.go @@ -277,7 +277,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { headerLines++ header, val, ok := strings.Cut(string(line), ":") if !ok { - h.printf("cgi: bogus header line: %s", string(line)) + h.printf("cgi: bogus header line: %s", line) continue } if !httpguts.ValidHeaderFieldName(header) { diff --git a/contrib/go/_std_1.22/src/net/http/cgi/ya.make b/contrib/go/_std_1.23/src/net/http/cgi/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/cgi/ya.make rename to contrib/go/_std_1.23/src/net/http/cgi/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/client.go b/contrib/go/_std_1.23/src/net/http/client.go similarity index 95% rename from contrib/go/_std_1.22/src/net/http/client.go rename to contrib/go/_std_1.23/src/net/http/client.go index 8fc348fe5d36..f8892c2bc2ea 100644 --- a/contrib/go/_std_1.22/src/net/http/client.go +++ b/contrib/go/_std_1.23/src/net/http/client.go @@ -20,7 +20,7 @@ import ( "net/http/internal/ascii" "net/url" "reflect" - "sort" + "slices" "strings" "sync" "sync/atomic" @@ -603,6 +603,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { Err: errors.New("http: nil Request.URL"), } } + _ = *c // panic early if c is nil; see go.dev/issue/53521 var ( deadline = c.deadline() @@ -612,8 +613,9 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { reqBodyClosed = false // have we closed the current req.Body? // Redirect behavior: - redirectMethod string - includeBody bool + redirectMethod string + includeBody = true + stripSensitiveHeaders = false ) uerr := func(err error) error { // the body may have been closed already by c.send() @@ -680,7 +682,12 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { // in case the user set Referer on their first request. // If they really want to override, they can do it in // their CheckRedirect func. - copyHeaders(req) + if !stripSensitiveHeaders && reqs[0].URL.Host != req.URL.Host { + if !shouldCopyHeaderOnRedirect(reqs[0].URL, req.URL) { + stripSensitiveHeaders = true + } + } + copyHeaders(req, stripSensitiveHeaders) // Add the Referer header from the most recent // request URL to the new one, if it's not https->http: @@ -725,10 +732,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { // c.send() always closes req.Body reqBodyClosed = true if !deadline.IsZero() && didTimeout() { - err = &httpError{ - err: err.Error() + " (Client.Timeout exceeded while awaiting headers)", - timeout: true, - } + err = &timeoutError{err.Error() + " (Client.Timeout exceeded while awaiting headers)"} } return nil, uerr(err) } @@ -746,7 +750,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { // makeHeadersCopier makes a function that copies headers from the // initial Request, ireq. For every redirect, this function must be called // so that it can copy headers into the upcoming Request. -func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { +func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensitiveHeaders bool) { // The headers to copy are from the very initial request. // We use a closured callback to keep a reference to these original headers. var ( @@ -760,8 +764,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { } } - preq := ireq // The previous request - return func(req *Request) { + return func(req *Request, stripSensitiveHeaders bool) { // If Jar is present and there was some initial cookies provided // via the request header, then we may need to alter the initial // cookies as we follow redirects since each redirect may end up @@ -790,7 +793,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { ss = append(ss, c.Name+"="+c.Value) } } - sort.Strings(ss) // Ensure deterministic headers + slices.Sort(ss) // Ensure deterministic headers ireqhdr.Set("Cookie", strings.Join(ss, "; ")) } } @@ -798,12 +801,15 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { // Copy the initial request's Header values // (at least the safe ones). for k, vv := range ireqhdr { - if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) { + sensitive := false + switch CanonicalHeaderKey(k) { + case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": + sensitive = true + } + if !(sensitive && stripSensitiveHeaders) { req.Header[k] = vv } } - - preq = req // Update previous Request with the current request } } @@ -968,10 +974,7 @@ func (b *cancelTimerBody) Read(p []byte) (n int, err error) { return n, err } if b.reqDidTimeout() { - err = &httpError{ - err: err.Error() + " (Client.Timeout or context cancellation while reading body)", - timeout: true, - } + err = &timeoutError{err.Error() + " (Client.Timeout or context cancellation while reading body)"} } return n, err } @@ -982,28 +985,23 @@ func (b *cancelTimerBody) Close() error { return err } -func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool { - switch CanonicalHeaderKey(headerKey) { - case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": - // Permit sending auth/cookie headers from "foo.com" - // to "sub.foo.com". - - // Note that we don't send all cookies to subdomains - // automatically. This function is only used for - // Cookies set explicitly on the initial outgoing - // client request. Cookies automatically added via the - // CookieJar mechanism continue to follow each - // cookie's scope as set by Set-Cookie. But for - // outgoing requests with the Cookie header set - // directly, we don't know their scope, so we assume - // it's for *.domain.com. - - ihost := idnaASCIIFromURL(initial) - dhost := idnaASCIIFromURL(dest) - return isDomainOrSubdomain(dhost, ihost) - } - // All other headers are copied: - return true +func shouldCopyHeaderOnRedirect(initial, dest *url.URL) bool { + // Permit sending auth/cookie headers from "foo.com" + // to "sub.foo.com". + + // Note that we don't send all cookies to subdomains + // automatically. This function is only used for + // Cookies set explicitly on the initial outgoing + // client request. Cookies automatically added via the + // CookieJar mechanism continue to follow each + // cookie's scope as set by Set-Cookie. But for + // outgoing requests with the Cookie header set + // directly, we don't know their scope, so we assume + // it's for *.domain.com. + + ihost := idnaASCIIFromURL(initial) + dhost := idnaASCIIFromURL(dest) + return isDomainOrSubdomain(dhost, ihost) } // isDomainOrSubdomain reports whether sub is a subdomain (or exact diff --git a/contrib/go/_std_1.23/src/net/http/clone.go b/contrib/go/_std_1.23/src/net/http/clone.go new file mode 100644 index 000000000000..71f424227313 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/http/clone.go @@ -0,0 +1,121 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http + +import ( + "mime/multipart" + "net/textproto" + "net/url" + _ "unsafe" // for linkname +) + +// cloneURLValues should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneURLValues +func cloneURLValues(v url.Values) url.Values { + if v == nil { + return nil + } + // http.Header and url.Values have the same representation, so temporarily + // treat it like http.Header, which does have a clone: + return url.Values(Header(v).Clone()) +} + +// cloneURL should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneURL +func cloneURL(u *url.URL) *url.URL { + if u == nil { + return nil + } + u2 := new(url.URL) + *u2 = *u + if u.User != nil { + u2.User = new(url.Userinfo) + *u2.User = *u.User + } + return u2 +} + +// cloneMultipartForm should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneMultipartForm +func cloneMultipartForm(f *multipart.Form) *multipart.Form { + if f == nil { + return nil + } + f2 := &multipart.Form{ + Value: (map[string][]string)(Header(f.Value).Clone()), + } + if f.File != nil { + m := make(map[string][]*multipart.FileHeader) + for k, vv := range f.File { + vv2 := make([]*multipart.FileHeader, len(vv)) + for i, v := range vv { + vv2[i] = cloneMultipartFileHeader(v) + } + m[k] = vv2 + } + f2.File = m + } + return f2 +} + +// cloneMultipartFileHeader should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneMultipartFileHeader +func cloneMultipartFileHeader(fh *multipart.FileHeader) *multipart.FileHeader { + if fh == nil { + return nil + } + fh2 := new(multipart.FileHeader) + *fh2 = *fh + fh2.Header = textproto.MIMEHeader(Header(fh.Header).Clone()) + return fh2 +} + +// cloneOrMakeHeader invokes Header.Clone but if the +// result is nil, it'll instead make and return a non-nil Header. +// +// cloneOrMakeHeader should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneOrMakeHeader +func cloneOrMakeHeader(hdr Header) Header { + clone := hdr.Clone() + if clone == nil { + clone = make(Header) + } + return clone +} diff --git a/contrib/go/_std_1.23/src/net/http/cookie.go b/contrib/go/_std_1.23/src/net/http/cookie.go new file mode 100644 index 000000000000..3483e1638190 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/http/cookie.go @@ -0,0 +1,535 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http + +import ( + "errors" + "fmt" + "log" + "net" + "net/http/internal/ascii" + "net/textproto" + "strconv" + "strings" + "time" +) + +// A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an +// HTTP response or the Cookie header of an HTTP request. +// +// See https://tools.ietf.org/html/rfc6265 for details. +type Cookie struct { + Name string + Value string + Quoted bool // indicates whether the Value was originally quoted + + Path string // optional + Domain string // optional + Expires time.Time // optional + RawExpires string // for reading cookies only + + // MaxAge=0 means no 'Max-Age' attribute specified. + // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' + // MaxAge>0 means Max-Age attribute present and given in seconds + MaxAge int + Secure bool + HttpOnly bool + SameSite SameSite + Partitioned bool + Raw string + Unparsed []string // Raw text of unparsed attribute-value pairs +} + +// SameSite allows a server to define a cookie attribute making it impossible for +// the browser to send this cookie along with cross-site requests. The main +// goal is to mitigate the risk of cross-origin information leakage, and provide +// some protection against cross-site request forgery attacks. +// +// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details. +type SameSite int + +const ( + SameSiteDefaultMode SameSite = iota + 1 + SameSiteLaxMode + SameSiteStrictMode + SameSiteNoneMode +) + +var ( + errBlankCookie = errors.New("http: blank cookie") + errEqualNotFoundInCookie = errors.New("http: '=' not found in cookie") + errInvalidCookieName = errors.New("http: invalid cookie name") + errInvalidCookieValue = errors.New("http: invalid cookie value") +) + +// ParseCookie parses a Cookie header value and returns all the cookies +// which were set in it. Since the same cookie name can appear multiple times +// the returned Values can contain more than one value for a given key. +func ParseCookie(line string) ([]*Cookie, error) { + parts := strings.Split(textproto.TrimString(line), ";") + if len(parts) == 1 && parts[0] == "" { + return nil, errBlankCookie + } + cookies := make([]*Cookie, 0, len(parts)) + for _, s := range parts { + s = textproto.TrimString(s) + name, value, found := strings.Cut(s, "=") + if !found { + return nil, errEqualNotFoundInCookie + } + if !isCookieNameValid(name) { + return nil, errInvalidCookieName + } + value, quoted, found := parseCookieValue(value, true) + if !found { + return nil, errInvalidCookieValue + } + cookies = append(cookies, &Cookie{Name: name, Value: value, Quoted: quoted}) + } + return cookies, nil +} + +// ParseSetCookie parses a Set-Cookie header value and returns a cookie. +// It returns an error on syntax error. +func ParseSetCookie(line string) (*Cookie, error) { + parts := strings.Split(textproto.TrimString(line), ";") + if len(parts) == 1 && parts[0] == "" { + return nil, errBlankCookie + } + parts[0] = textproto.TrimString(parts[0]) + name, value, ok := strings.Cut(parts[0], "=") + if !ok { + return nil, errEqualNotFoundInCookie + } + name = textproto.TrimString(name) + if !isCookieNameValid(name) { + return nil, errInvalidCookieName + } + value, quoted, ok := parseCookieValue(value, true) + if !ok { + return nil, errInvalidCookieValue + } + c := &Cookie{ + Name: name, + Value: value, + Quoted: quoted, + Raw: line, + } + for i := 1; i < len(parts); i++ { + parts[i] = textproto.TrimString(parts[i]) + if len(parts[i]) == 0 { + continue + } + + attr, val, _ := strings.Cut(parts[i], "=") + lowerAttr, isASCII := ascii.ToLower(attr) + if !isASCII { + continue + } + val, _, ok = parseCookieValue(val, false) + if !ok { + c.Unparsed = append(c.Unparsed, parts[i]) + continue + } + + switch lowerAttr { + case "samesite": + lowerVal, ascii := ascii.ToLower(val) + if !ascii { + c.SameSite = SameSiteDefaultMode + continue + } + switch lowerVal { + case "lax": + c.SameSite = SameSiteLaxMode + case "strict": + c.SameSite = SameSiteStrictMode + case "none": + c.SameSite = SameSiteNoneMode + default: + c.SameSite = SameSiteDefaultMode + } + continue + case "secure": + c.Secure = true + continue + case "httponly": + c.HttpOnly = true + continue + case "domain": + c.Domain = val + continue + case "max-age": + secs, err := strconv.Atoi(val) + if err != nil || secs != 0 && val[0] == '0' { + break + } + if secs <= 0 { + secs = -1 + } + c.MaxAge = secs + continue + case "expires": + c.RawExpires = val + exptime, err := time.Parse(time.RFC1123, val) + if err != nil { + exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val) + if err != nil { + c.Expires = time.Time{} + break + } + } + c.Expires = exptime.UTC() + continue + case "path": + c.Path = val + continue + case "partitioned": + c.Partitioned = true + continue + } + c.Unparsed = append(c.Unparsed, parts[i]) + } + return c, nil +} + +// readSetCookies parses all "Set-Cookie" values from +// the header h and returns the successfully parsed Cookies. +func readSetCookies(h Header) []*Cookie { + cookieCount := len(h["Set-Cookie"]) + if cookieCount == 0 { + return []*Cookie{} + } + cookies := make([]*Cookie, 0, cookieCount) + for _, line := range h["Set-Cookie"] { + if cookie, err := ParseSetCookie(line); err == nil { + cookies = append(cookies, cookie) + } + } + return cookies +} + +// SetCookie adds a Set-Cookie header to the provided [ResponseWriter]'s headers. +// The provided cookie must have a valid Name. Invalid cookies may be +// silently dropped. +func SetCookie(w ResponseWriter, cookie *Cookie) { + if v := cookie.String(); v != "" { + w.Header().Add("Set-Cookie", v) + } +} + +// String returns the serialization of the cookie for use in a [Cookie] +// header (if only Name and Value are set) or a Set-Cookie response +// header (if other fields are set). +// If c is nil or c.Name is invalid, the empty string is returned. +func (c *Cookie) String() string { + if c == nil || !isCookieNameValid(c.Name) { + return "" + } + // extraCookieLength derived from typical length of cookie attributes + // see RFC 6265 Sec 4.1. + const extraCookieLength = 110 + var b strings.Builder + b.Grow(len(c.Name) + len(c.Value) + len(c.Domain) + len(c.Path) + extraCookieLength) + b.WriteString(c.Name) + b.WriteRune('=') + b.WriteString(sanitizeCookieValue(c.Value, c.Quoted)) + + if len(c.Path) > 0 { + b.WriteString("; Path=") + b.WriteString(sanitizeCookiePath(c.Path)) + } + if len(c.Domain) > 0 { + if validCookieDomain(c.Domain) { + // A c.Domain containing illegal characters is not + // sanitized but simply dropped which turns the cookie + // into a host-only cookie. A leading dot is okay + // but won't be sent. + d := c.Domain + if d[0] == '.' { + d = d[1:] + } + b.WriteString("; Domain=") + b.WriteString(d) + } else { + log.Printf("net/http: invalid Cookie.Domain %q; dropping domain attribute", c.Domain) + } + } + var buf [len(TimeFormat)]byte + if validCookieExpires(c.Expires) { + b.WriteString("; Expires=") + b.Write(c.Expires.UTC().AppendFormat(buf[:0], TimeFormat)) + } + if c.MaxAge > 0 { + b.WriteString("; Max-Age=") + b.Write(strconv.AppendInt(buf[:0], int64(c.MaxAge), 10)) + } else if c.MaxAge < 0 { + b.WriteString("; Max-Age=0") + } + if c.HttpOnly { + b.WriteString("; HttpOnly") + } + if c.Secure { + b.WriteString("; Secure") + } + switch c.SameSite { + case SameSiteDefaultMode: + // Skip, default mode is obtained by not emitting the attribute. + case SameSiteNoneMode: + b.WriteString("; SameSite=None") + case SameSiteLaxMode: + b.WriteString("; SameSite=Lax") + case SameSiteStrictMode: + b.WriteString("; SameSite=Strict") + } + if c.Partitioned { + b.WriteString("; Partitioned") + } + return b.String() +} + +// Valid reports whether the cookie is valid. +func (c *Cookie) Valid() error { + if c == nil { + return errors.New("http: nil Cookie") + } + if !isCookieNameValid(c.Name) { + return errors.New("http: invalid Cookie.Name") + } + if !c.Expires.IsZero() && !validCookieExpires(c.Expires) { + return errors.New("http: invalid Cookie.Expires") + } + for i := 0; i < len(c.Value); i++ { + if !validCookieValueByte(c.Value[i]) { + return fmt.Errorf("http: invalid byte %q in Cookie.Value", c.Value[i]) + } + } + if len(c.Path) > 0 { + for i := 0; i < len(c.Path); i++ { + if !validCookiePathByte(c.Path[i]) { + return fmt.Errorf("http: invalid byte %q in Cookie.Path", c.Path[i]) + } + } + } + if len(c.Domain) > 0 { + if !validCookieDomain(c.Domain) { + return errors.New("http: invalid Cookie.Domain") + } + } + if c.Partitioned { + if !c.Secure { + return errors.New("http: partitioned cookies must be set with Secure") + } + } + return nil +} + +// readCookies parses all "Cookie" values from the header h and +// returns the successfully parsed Cookies. +// +// if filter isn't empty, only cookies of that name are returned. +func readCookies(h Header, filter string) []*Cookie { + lines := h["Cookie"] + if len(lines) == 0 { + return []*Cookie{} + } + + cookies := make([]*Cookie, 0, len(lines)+strings.Count(lines[0], ";")) + for _, line := range lines { + line = textproto.TrimString(line) + + var part string + for len(line) > 0 { // continue since we have rest + part, line, _ = strings.Cut(line, ";") + part = textproto.TrimString(part) + if part == "" { + continue + } + name, val, _ := strings.Cut(part, "=") + name = textproto.TrimString(name) + if !isCookieNameValid(name) { + continue + } + if filter != "" && filter != name { + continue + } + val, quoted, ok := parseCookieValue(val, true) + if !ok { + continue + } + cookies = append(cookies, &Cookie{Name: name, Value: val, Quoted: quoted}) + } + } + return cookies +} + +// validCookieDomain reports whether v is a valid cookie domain-value. +func validCookieDomain(v string) bool { + if isCookieDomainName(v) { + return true + } + if net.ParseIP(v) != nil && !strings.Contains(v, ":") { + return true + } + return false +} + +// validCookieExpires reports whether v is a valid cookie expires-value. +func validCookieExpires(t time.Time) bool { + // IETF RFC 6265 Section 5.1.1.5, the year must not be less than 1601 + return t.Year() >= 1601 +} + +// isCookieDomainName reports whether s is a valid domain name or a valid +// domain name with a leading dot '.'. It is almost a direct copy of +// package net's isDomainName. +func isCookieDomainName(s string) bool { + if len(s) == 0 { + return false + } + if len(s) > 255 { + return false + } + + if s[0] == '.' { + // A cookie a domain attribute may start with a leading dot. + s = s[1:] + } + last := byte('.') + ok := false // Ok once we've seen a letter. + partlen := 0 + for i := 0; i < len(s); i++ { + c := s[i] + switch { + default: + return false + case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': + // No '_' allowed here (in contrast to package net). + ok = true + partlen++ + case '0' <= c && c <= '9': + // fine + partlen++ + case c == '-': + // Byte before dash cannot be dot. + if last == '.' { + return false + } + partlen++ + case c == '.': + // Byte before dot cannot be dot, dash. + if last == '.' || last == '-' { + return false + } + if partlen > 63 || partlen == 0 { + return false + } + partlen = 0 + } + last = c + } + if last == '-' || partlen > 63 { + return false + } + + return ok +} + +var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-") + +func sanitizeCookieName(n string) string { + return cookieNameSanitizer.Replace(n) +} + +// sanitizeCookieValue produces a suitable cookie-value from v. +// It receives a quoted bool indicating whether the value was originally +// quoted. +// https://tools.ietf.org/html/rfc6265#section-4.1.1 +// +// cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) +// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E +// ; US-ASCII characters excluding CTLs, +// ; whitespace DQUOTE, comma, semicolon, +// ; and backslash +// +// We loosen this as spaces and commas are common in cookie values +// thus we produce a quoted cookie-value if v contains commas or spaces. +// See https://golang.org/issue/7243 for the discussion. +func sanitizeCookieValue(v string, quoted bool) string { + v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v) + if len(v) == 0 { + return v + } + if strings.ContainsAny(v, " ,") || quoted { + return `"` + v + `"` + } + return v +} + +func validCookieValueByte(b byte) bool { + return 0x20 <= b && b < 0x7f && b != '"' && b != ';' && b != '\\' +} + +// path-av = "Path=" path-value +// path-value = +func sanitizeCookiePath(v string) string { + return sanitizeOrWarn("Cookie.Path", validCookiePathByte, v) +} + +func validCookiePathByte(b byte) bool { + return 0x20 <= b && b < 0x7f && b != ';' +} + +func sanitizeOrWarn(fieldName string, valid func(byte) bool, v string) string { + ok := true + for i := 0; i < len(v); i++ { + if valid(v[i]) { + continue + } + log.Printf("net/http: invalid byte %q in %s; dropping invalid bytes", v[i], fieldName) + ok = false + break + } + if ok { + return v + } + buf := make([]byte, 0, len(v)) + for i := 0; i < len(v); i++ { + if b := v[i]; valid(b) { + buf = append(buf, b) + } + } + return string(buf) +} + +// parseCookieValue parses a cookie value according to RFC 6265. +// If allowDoubleQuote is true, parseCookieValue will consider that it +// is parsing the cookie-value; +// otherwise, it will consider that it is parsing a cookie-av value +// (cookie attribute-value). +// +// It returns the parsed cookie value, a boolean indicating whether the +// parsing was successful, and a boolean indicating whether the parsed +// value was enclosed in double quotes. +func parseCookieValue(raw string, allowDoubleQuote bool) (value string, quoted, ok bool) { + // Strip the quotes, if present. + if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' { + raw = raw[1 : len(raw)-1] + quoted = true + } + for i := 0; i < len(raw); i++ { + if !validCookieValueByte(raw[i]) { + return "", quoted, false + } + } + return raw, quoted, true +} + +func isCookieNameValid(raw string) bool { + if raw == "" { + return false + } + return strings.IndexFunc(raw, isNotToken) < 0 +} diff --git a/contrib/go/_std_1.22/src/net/http/cookiejar/jar.go b/contrib/go/_std_1.23/src/net/http/cookiejar/jar.go similarity index 97% rename from contrib/go/_std_1.22/src/net/http/cookiejar/jar.go rename to contrib/go/_std_1.23/src/net/http/cookiejar/jar.go index e7f5ddd4d009..2eec1a3e745b 100644 --- a/contrib/go/_std_1.22/src/net/http/cookiejar/jar.go +++ b/contrib/go/_std_1.23/src/net/http/cookiejar/jar.go @@ -6,13 +6,14 @@ package cookiejar import ( + "cmp" "errors" "fmt" "net" "net/http" "net/http/internal/ascii" "net/url" - "sort" + "slices" "strings" "sync" "time" @@ -92,6 +93,7 @@ func New(o *Options) (*Jar, error) { type entry struct { Name string Value string + Quoted bool Domain string Path string SameSite string @@ -209,18 +211,17 @@ func (j *Jar) cookies(u *url.URL, now time.Time) (cookies []*http.Cookie) { // sort according to RFC 6265 section 5.4 point 2: by longest // path and then by earliest creation time. - sort.Slice(selected, func(i, j int) bool { - s := selected - if len(s[i].Path) != len(s[j].Path) { - return len(s[i].Path) > len(s[j].Path) + slices.SortFunc(selected, func(a, b entry) int { + if r := cmp.Compare(b.Path, a.Path); r != 0 { + return r } - if ret := s[i].Creation.Compare(s[j].Creation); ret != 0 { - return ret < 0 + if r := a.Creation.Compare(b.Creation); r != 0 { + return r } - return s[i].seqNum < s[j].seqNum + return cmp.Compare(a.seqNum, b.seqNum) }) for _, e := range selected { - cookies = append(cookies, &http.Cookie{Name: e.Name, Value: e.Value}) + cookies = append(cookies, &http.Cookie{Name: e.Name, Value: e.Value, Quoted: e.Quoted}) } return cookies @@ -366,7 +367,7 @@ func isIP(host string) bool { // Probable IPv6 address. // Hostnames can't contain : or %, so this is definitely not a valid host. // Treating it as an IP is the more conservative option, and avoids the risk - // of interpeting ::1%.www.example.com as a subtomain of www.example.com. + // of interpreting ::1%.www.example.com as a subdomain of www.example.com. return true } return net.ParseIP(host) != nil @@ -429,6 +430,7 @@ func (j *Jar) newEntry(c *http.Cookie, now time.Time, defPath, host string) (e e } e.Value = c.Value + e.Quoted = c.Quoted e.Secure = c.Secure e.HttpOnly = c.HttpOnly diff --git a/contrib/go/_std_1.22/src/net/http/cookiejar/punycode.go b/contrib/go/_std_1.23/src/net/http/cookiejar/punycode.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/cookiejar/punycode.go rename to contrib/go/_std_1.23/src/net/http/cookiejar/punycode.go diff --git a/contrib/go/_std_1.22/src/net/http/cookiejar/ya.make b/contrib/go/_std_1.23/src/net/http/cookiejar/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/cookiejar/ya.make rename to contrib/go/_std_1.23/src/net/http/cookiejar/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/doc.go b/contrib/go/_std_1.23/src/net/http/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/doc.go rename to contrib/go/_std_1.23/src/net/http/doc.go diff --git a/contrib/go/_std_1.22/src/net/http/fcgi/child.go b/contrib/go/_std_1.23/src/net/http/fcgi/child.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/fcgi/child.go rename to contrib/go/_std_1.23/src/net/http/fcgi/child.go diff --git a/contrib/go/_std_1.22/src/net/http/fcgi/fcgi.go b/contrib/go/_std_1.23/src/net/http/fcgi/fcgi.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/fcgi/fcgi.go rename to contrib/go/_std_1.23/src/net/http/fcgi/fcgi.go diff --git a/contrib/go/_std_1.22/src/net/http/fcgi/ya.make b/contrib/go/_std_1.23/src/net/http/fcgi/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/fcgi/ya.make rename to contrib/go/_std_1.23/src/net/http/fcgi/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/filetransport.go b/contrib/go/_std_1.23/src/net/http/filetransport.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/filetransport.go rename to contrib/go/_std_1.23/src/net/http/filetransport.go index 7384b22fbe92..b08bae63487d 100644 --- a/contrib/go/_std_1.22/src/net/http/filetransport.go +++ b/contrib/go/_std_1.23/src/net/http/filetransport.go @@ -35,7 +35,7 @@ func NewFileTransport(fs FileSystem) RoundTripper { // NewFileTransportFS returns a new [RoundTripper], serving the provided // file system fsys. The returned RoundTripper ignores the URL host in its // incoming requests, as well as most other properties of the -// request. +// request. The files provided by fsys must implement [io.Seeker]. // // The typical use case for NewFileTransportFS is to register the "file" // protocol with a [Transport], as in: diff --git a/contrib/go/_std_1.22/src/net/http/fs.go b/contrib/go/_std_1.23/src/net/http/fs.go similarity index 90% rename from contrib/go/_std_1.22/src/net/http/fs.go rename to contrib/go/_std_1.23/src/net/http/fs.go index af7511a7a4bd..3a716fbd2cc7 100644 --- a/contrib/go/_std_1.22/src/net/http/fs.go +++ b/contrib/go/_std_1.23/src/net/http/fs.go @@ -9,7 +9,7 @@ package http import ( "errors" "fmt" - "internal/safefilepath" + "internal/godebug" "io" "io/fs" "mime" @@ -29,7 +29,7 @@ import ( // specific directory tree. // // While the [FileSystem.Open] method takes '/'-separated paths, a Dir's string -// value is a filename on the native file system, not a URL, so it is separated +// value is a directory path on the native file system, not a URL, so it is separated // by [filepath.Separator], which isn't necessarily '/'. // // Note that Dir could expose sensitive files and directories. Dir will follow @@ -70,7 +70,11 @@ func mapOpenError(originalErr error, name string, sep rune, stat func(string) (f // Open implements [FileSystem] using [os.Open], opening files for reading rooted // and relative to the directory d. func (d Dir) Open(name string) (File, error) { - path, err := safefilepath.FromFS(path.Clean("/" + name)) + path := path.Clean("/" + name)[1:] + if path == "" { + path = "." + } + path, err := filepath.Localize(path) if err != nil { return nil, errors.New("http: invalid or unsafe file path") } @@ -151,6 +155,8 @@ func dirList(w ResponseWriter, r *Request, f File) { sort.Slice(dirs, func(i, j int) bool { return dirs.name(i) < dirs.name(j) }) w.Header().Set("Content-Type", "text/html; charset=utf-8") + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "\n") fmt.Fprintf(w, "
\n")
 	for i, n := 0, dirs.len(); i < n; i++ {
 		name := dirs.name(i)
@@ -166,6 +172,40 @@ func dirList(w ResponseWriter, r *Request, f File) {
 	fmt.Fprintf(w, "
\n") } +// GODEBUG=httpservecontentkeepheaders=1 restores the pre-1.23 behavior of not deleting +// Cache-Control, Content-Encoding, Etag, or Last-Modified headers on ServeContent errors. +var httpservecontentkeepheaders = godebug.New("httpservecontentkeepheaders") + +// serveError serves an error from ServeFile, ServeFileFS, and ServeContent. +// Because those can all be configured by the caller by setting headers like +// Etag, Last-Modified, and Cache-Control to send on a successful response, +// the error path needs to clear them, since they may not be meant for errors. +func serveError(w ResponseWriter, text string, code int) { + h := w.Header() + + nonDefault := false + for _, k := range []string{ + "Cache-Control", + "Content-Encoding", + "Etag", + "Last-Modified", + } { + if !h.has(k) { + continue + } + if httpservecontentkeepheaders.Value() == "1" { + nonDefault = true + } else { + h.Del(k) + } + } + if nonDefault { + httpservecontentkeepheaders.IncNonDefault() + } + + Error(w, text, code) +} + // ServeContent replies to the request using the content in the // provided ReadSeeker. The main benefit of ServeContent over [io.Copy] // is that it handles Range requests properly, sets the MIME type, and @@ -186,11 +226,17 @@ func dirList(w ResponseWriter, r *Request, f File) { // // The content's Seek method must work: ServeContent uses // a seek to the end of the content to determine its size. +// Note that [*os.File] implements the [io.ReadSeeker] interface. // // If the caller has set w's ETag header formatted per RFC 7232, section 2.3, // ServeContent uses it to handle requests using If-Match, If-None-Match, or If-Range. // -// Note that [*os.File] implements the [io.ReadSeeker] interface. +// If an error occurs when serving the request (for example, when +// handling an invalid range request), ServeContent responds with an +// error message. By default, ServeContent strips the Cache-Control, +// Content-Encoding, ETag, and Last-Modified headers from error responses. +// The GODEBUG setting httpservecontentkeepheaders=1 causes ServeContent +// to preserve these headers. func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker) { sizeFunc := func() (int64, error) { size, err := content.Seek(0, io.SeekEnd) @@ -242,7 +288,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, ctype = DetectContentType(buf[:n]) _, err := content.Seek(0, io.SeekStart) // rewind to output whole file if err != nil { - Error(w, "seeker can't seek", StatusInternalServerError) + serveError(w, "seeker can't seek", StatusInternalServerError) return } } @@ -253,12 +299,12 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, size, err := sizeFunc() if err != nil { - Error(w, err.Error(), StatusInternalServerError) + serveError(w, err.Error(), StatusInternalServerError) return } if size < 0 { // Should never happen but just to be sure - Error(w, "negative content size computed", StatusInternalServerError) + serveError(w, "negative content size computed", StatusInternalServerError) return } @@ -280,7 +326,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size)) fallthrough default: - Error(w, err.Error(), StatusRequestedRangeNotSatisfiable) + serveError(w, err.Error(), StatusRequestedRangeNotSatisfiable) return } @@ -306,7 +352,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, // multipart responses." ra := ranges[0] if _, err := content.Seek(ra.start, io.SeekStart); err != nil { - Error(w, err.Error(), StatusRequestedRangeNotSatisfiable) + serveError(w, err.Error(), StatusRequestedRangeNotSatisfiable) return } sendSize = ra.length @@ -639,7 +685,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec f, err := fs.Open(name) if err != nil { msg, code := toHTTPError(err) - Error(w, msg, code) + serveError(w, msg, code) return } defer f.Close() @@ -647,7 +693,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec d, err := f.Stat() if err != nil { msg, code := toHTTPError(err) - Error(w, msg, code) + serveError(w, msg, code) return } @@ -660,11 +706,16 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec localRedirect(w, r, path.Base(url)+"/") return } - } else { - if url[len(url)-1] == '/' { - localRedirect(w, r, "../"+path.Base(url)) + } else if url[len(url)-1] == '/' { + base := path.Base(url) + if base == "/" || base == "." { + // The FileSystem maps a path like "/" or "/./" to a file instead of a directory. + msg := "http: attempting to traverse a non-directory" + serveError(w, msg, StatusInternalServerError) return } + localRedirect(w, r, "../"+base) + return } } @@ -737,7 +788,7 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) { // If the provided file or directory name is a relative path, it is // interpreted relative to the current directory and may ascend to // parent directories. If the provided name is constructed from user -// input, it should be sanitized before calling ServeFile. +// input, it should be sanitized before calling [ServeFile]. // // As a precaution, ServeFile will reject requests where r.URL.Path // contains a ".." path element; this protects against callers who @@ -759,7 +810,7 @@ func ServeFile(w ResponseWriter, r *Request, name string) { // here and ".." may not be wanted. // Note that name might not contain "..", for example if code (still // incorrectly) used filepath.Join(myDir, r.URL.Path). - Error(w, "invalid URL path", StatusBadRequest) + serveError(w, "invalid URL path", StatusBadRequest) return } dir, file := filepath.Split(name) @@ -768,23 +819,22 @@ func ServeFile(w ResponseWriter, r *Request, name string) { // ServeFileFS replies to the request with the contents // of the named file or directory from the file system fsys. +// The files provided by fsys must implement [io.Seeker]. // -// If the provided file or directory name is a relative path, it is -// interpreted relative to the current directory and may ascend to -// parent directories. If the provided name is constructed from user -// input, it should be sanitized before calling [ServeFile]. +// If the provided name is constructed from user input, it should be +// sanitized before calling [ServeFileFS]. // -// As a precaution, ServeFile will reject requests where r.URL.Path +// As a precaution, ServeFileFS will reject requests where r.URL.Path // contains a ".." path element; this protects against callers who // might unsafely use [filepath.Join] on r.URL.Path without sanitizing // it and then use that filepath.Join result as the name argument. // -// As another special case, ServeFile redirects any request where r.URL.Path +// As another special case, ServeFileFS redirects any request where r.URL.Path // ends in "/index.html" to the same path, without the final // "index.html". To avoid such redirects either modify the path or -// use ServeContent. +// use [ServeContent]. // -// Outside of those two special cases, ServeFile does not use +// Outside of those two special cases, ServeFileFS does not use // r.URL.Path for selecting the file or directory to serve; only the // file or directory provided in the name argument is used. func ServeFileFS(w ResponseWriter, r *Request, fsys fs.FS, name string) { @@ -794,7 +844,7 @@ func ServeFileFS(w ResponseWriter, r *Request, fsys fs.FS, name string) { // here and ".." may not be wanted. // Note that name might not contain "..", for example if code (still // incorrectly) used filepath.Join(myDir, r.URL.Path). - Error(w, "invalid URL path", StatusBadRequest) + serveError(w, "invalid URL path", StatusBadRequest) return } serveFile(w, r, FS(fsys), name, false) @@ -916,6 +966,7 @@ func FileServer(root FileSystem) Handler { // FileServerFS returns a handler that serves HTTP requests // with the contents of the file system fsys. +// The files provided by fsys must implement [io.Seeker]. // // As a special case, the returned file server redirects any request // ending in "/index.html" to the same path, without the final diff --git a/contrib/go/_std_1.22/src/net/http/h2_bundle.go b/contrib/go/_std_1.23/src/net/http/h2_bundle.go similarity index 97% rename from contrib/go/_std_1.22/src/net/http/h2_bundle.go rename to contrib/go/_std_1.23/src/net/http/h2_bundle.go index c1a2e76ea4d3..0b305844ae2c 100644 --- a/contrib/go/_std_1.22/src/net/http/h2_bundle.go +++ b/contrib/go/_std_1.23/src/net/http/h2_bundle.go @@ -15,6 +15,10 @@ // // See https://http2.golang.org/ for a test server running this code. // +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// package http @@ -2917,13 +2921,12 @@ func (mh *http2MetaHeadersFrame) checkPseudos() error { } func (fr *http2Framer) maxHeaderStringLen() int { - v := fr.maxHeaderListSize() - if uint32(int(v)) == v { - return int(v) + v := int(fr.maxHeaderListSize()) + if v < 0 { + // If maxHeaderListSize overflows an int, use no limit (0). + return 0 } - // They had a crazy big number for MaxHeaderBytes anyway, - // so give them unlimited header lengths: - return 0 + return v } // readMetaFrame returns 0 or more CONTINUATION frames from fr and @@ -3522,13 +3525,6 @@ type http2stringWriter interface { WriteString(s string) (n int, err error) } -// A gate lets two goroutines coordinate their activities. -type http2gate chan struct{} - -func (g http2gate) Done() { g <- struct{}{} } - -func (g http2gate) Wait() { <-g } - // A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed). type http2closeWaiter chan struct{} @@ -3701,6 +3697,17 @@ func http2validPseudoPath(v string) bool { // any size (as long as it's first). type http2incomparable [0]func() +// synctestGroupInterface is the methods of synctestGroup used by Server and Transport. +// It's defined as an interface here to let us keep synctestGroup entirely test-only +// and not a part of non-test builds. +type http2synctestGroupInterface interface { + Join() + Now() time.Time + NewTimer(d time.Duration) http2timer + AfterFunc(d time.Duration, f func()) http2timer + ContextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) +} + // pipe is a goroutine-safe io.Reader/io.Writer pair. It's like // io.Pipe except there are no PipeReader/PipeWriter halves, and the // underlying buffer is an interface. (io.Pipe is always unbuffered) @@ -3768,7 +3775,10 @@ func (p *http2pipe) Read(d []byte) (n int, err error) { } } -var http2errClosedPipeWrite = errors.New("write on closed buffer") +var ( + http2errClosedPipeWrite = errors.New("write on closed buffer") + http2errUninitializedPipeWrite = errors.New("write on uninitialized buffer") +) // Write copies bytes from p into the buffer and wakes a reader. // It is an error to write more data than the buffer can hold. @@ -3782,6 +3792,12 @@ func (p *http2pipe) Write(d []byte) (n int, err error) { if p.err != nil || p.breakErr != nil { return 0, http2errClosedPipeWrite } + // pipe.setBuffer is never invoked, leaving the buffer uninitialized. + // We shouldn't try to write to an uninitialized pipe, + // but returning an error is better than panicking. + if p.b == nil { + return 0, http2errUninitializedPipeWrite + } return p.b.Write(d) } @@ -3938,6 +3954,7 @@ type http2Server struct { // IdleTimeout specifies how long until idle clients should be // closed with a GOAWAY frame. PING frames are not considered // activity for the purposes of IdleTimeout. + // If zero or negative, there is no timeout. IdleTimeout time.Duration // MaxUploadBufferPerConnection is the size of the initial flow @@ -3967,6 +3984,39 @@ type http2Server struct { // so that we don't embed a Mutex in this struct, which will make the // struct non-copyable, which might break some callers. state *http2serverInternalState + + // Synchronization group used for testing. + // Outside of tests, this is nil. + group http2synctestGroupInterface +} + +func (s *http2Server) markNewGoroutine() { + if s.group != nil { + s.group.Join() + } +} + +func (s *http2Server) now() time.Time { + if s.group != nil { + return s.group.Now() + } + return time.Now() +} + +// newTimer creates a new time.Timer, or a synthetic timer in tests. +func (s *http2Server) newTimer(d time.Duration) http2timer { + if s.group != nil { + return s.group.NewTimer(d) + } + return http2timeTimer{time.NewTimer(d)} +} + +// afterFunc creates a new time.AfterFunc timer, or a synthetic timer in tests. +func (s *http2Server) afterFunc(d time.Duration, f func()) http2timer { + if s.group != nil { + return s.group.AfterFunc(d, f) + } + return http2timeTimer{time.AfterFunc(d, f)} } func (s *http2Server) initialConnRecvWindowSize() int32 { @@ -4213,6 +4263,10 @@ func (o *http2ServeConnOpts) handler() Handler { // // The opts parameter is optional. If nil, default values are used. func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) { + s.serveConn(c, opts, nil) +} + +func (s *http2Server) serveConn(c net.Conn, opts *http2ServeConnOpts, newf func(*http2serverConn)) { baseCtx, cancel := http2serverConnBaseContext(c, opts) defer cancel() @@ -4239,6 +4293,9 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) { pushEnabled: true, sawClientPreface: opts.SawClientPreface, } + if newf != nil { + newf(sc) + } s.state.registerConn(sc) defer s.state.unregisterConn(sc) @@ -4248,7 +4305,7 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) { // passes the connection off to us with the deadline already set. // Write deadlines are set per stream in serverConn.newStream. // Disarm the net.Conn write deadline here. - if sc.hs.WriteTimeout != 0 { + if sc.hs.WriteTimeout > 0 { sc.conn.SetWriteDeadline(time.Time{}) } @@ -4412,8 +4469,8 @@ type http2serverConn struct { inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop needToSendGoAway bool // we need to schedule a GOAWAY frame write goAwayCode http2ErrCode - shutdownTimer *time.Timer // nil until used - idleTimer *time.Timer // nil if unused + shutdownTimer http2timer // nil until used + idleTimer http2timer // nil if unused // Owned by the writeFrameAsync goroutine: headerWriteBuf bytes.Buffer @@ -4462,12 +4519,12 @@ type http2stream struct { flow http2outflow // limits writing from Handler to client inflow http2inflow // what the client is allowed to POST/etc to us state http2streamState - resetQueued bool // RST_STREAM queued for write; set by sc.resetStream - gotTrailerHeader bool // HEADER frame for trailers was seen - wroteHeaders bool // whether we wrote headers (not status 100) - readDeadline *time.Timer // nil if unused - writeDeadline *time.Timer // nil if unused - closeErr error // set before cw is closed + resetQueued bool // RST_STREAM queued for write; set by sc.resetStream + gotTrailerHeader bool // HEADER frame for trailers was seen + wroteHeaders bool // whether we wrote headers (not status 100) + readDeadline http2timer // nil if unused + writeDeadline http2timer // nil if unused + closeErr error // set before cw is closed trailer Header // accumulated trailers reqTrailer Header // handler's Request.Trailer @@ -4548,11 +4605,7 @@ func http2isClosedConnError(err error) bool { return false } - // TODO: remove this string search and be more like the Windows - // case below. That might involve modifying the standard library - // to return better error types. - str := err.Error() - if strings.Contains(str, "use of closed network connection") { + if errors.Is(err, net.ErrClosed) { return true } @@ -4631,8 +4684,9 @@ type http2readFrameResult struct { // consumer is done with the frame. // It's run on its own goroutine. func (sc *http2serverConn) readFrames() { - gate := make(http2gate) - gateDone := gate.Done + sc.srv.markNewGoroutine() + gate := make(chan struct{}) + gateDone := func() { gate <- struct{}{} } for { f, err := sc.framer.ReadFrame() select { @@ -4663,6 +4717,7 @@ type http2frameWriteResult struct { // At most one goroutine can be running writeFrameAsync at a time per // serverConn. func (sc *http2serverConn) writeFrameAsync(wr http2FrameWriteRequest, wd *http2writeData) { + sc.srv.markNewGoroutine() var err error if wd == nil { err = wr.write.writeFrame(sc) @@ -4741,14 +4796,14 @@ func (sc *http2serverConn) serve() { sc.setConnState(StateActive) sc.setConnState(StateIdle) - if sc.srv.IdleTimeout != 0 { - sc.idleTimer = time.AfterFunc(sc.srv.IdleTimeout, sc.onIdleTimer) + if sc.srv.IdleTimeout > 0 { + sc.idleTimer = sc.srv.afterFunc(sc.srv.IdleTimeout, sc.onIdleTimer) defer sc.idleTimer.Stop() } go sc.readFrames() // closed by defer sc.conn.Close above - settingsTimer := time.AfterFunc(http2firstSettingsTimeout, sc.onSettingsTimer) + settingsTimer := sc.srv.afterFunc(http2firstSettingsTimeout, sc.onSettingsTimer) defer settingsTimer.Stop() loopNum := 0 @@ -4879,10 +4934,10 @@ func (sc *http2serverConn) readPreface() error { errc <- nil } }() - timer := time.NewTimer(http2prefaceTimeout) // TODO: configurable on *Server? + timer := sc.srv.newTimer(http2prefaceTimeout) // TODO: configurable on *Server? defer timer.Stop() select { - case <-timer.C: + case <-timer.C(): return http2errPrefaceTimeout case err := <-errc: if err == nil { @@ -5247,7 +5302,7 @@ func (sc *http2serverConn) goAway(code http2ErrCode) { func (sc *http2serverConn) shutDownIn(d time.Duration) { sc.serveG.check() - sc.shutdownTimer = time.AfterFunc(d, sc.onShutdownTimer) + sc.shutdownTimer = sc.srv.afterFunc(d, sc.onShutdownTimer) } func (sc *http2serverConn) resetStream(se http2StreamError) { @@ -5461,7 +5516,7 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) { delete(sc.streams, st.id) if len(sc.streams) == 0 { sc.setConnState(StateIdle) - if sc.srv.IdleTimeout != 0 { + if sc.srv.IdleTimeout > 0 && sc.idleTimer != nil { sc.idleTimer.Reset(sc.srv.IdleTimeout) } if http2h1ServerKeepAlivesDisabled(sc.hs) { @@ -5483,6 +5538,7 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) { } } st.closeErr = err + st.cancelCtx() st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc sc.writeSched.CloseStream(st.id) } @@ -5841,9 +5897,9 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error { // similar to how the http1 server works. Here it's // technically more like the http1 Server's ReadHeaderTimeout // (in Go 1.8), though. That's a more sane option anyway. - if sc.hs.ReadTimeout != 0 { + if sc.hs.ReadTimeout > 0 { sc.conn.SetReadDeadline(time.Time{}) - st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout) + st.readDeadline = sc.srv.afterFunc(sc.hs.ReadTimeout, st.onReadTimeout) } return sc.scheduleHandler(id, rw, req, handler) @@ -5862,7 +5918,7 @@ func (sc *http2serverConn) upgradeRequest(req *Request) { // Disable any read deadline set by the net/http package // prior to the upgrade. - if sc.hs.ReadTimeout != 0 { + if sc.hs.ReadTimeout > 0 { sc.conn.SetReadDeadline(time.Time{}) } @@ -5940,8 +5996,8 @@ func (sc *http2serverConn) newStream(id, pusherID uint32, state http2streamState st.flow.conn = &sc.flow // link to conn-level counter st.flow.add(sc.initialStreamSendWindowSize) st.inflow.init(sc.srv.initialStreamRecvWindowSize()) - if sc.hs.WriteTimeout != 0 { - st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout) + if sc.hs.WriteTimeout > 0 { + st.writeDeadline = sc.srv.afterFunc(sc.hs.WriteTimeout, st.onWriteTimeout) } sc.streams[id] = st @@ -6165,6 +6221,7 @@ func (sc *http2serverConn) handlerDone() { // Run on its own goroutine. func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) { + sc.srv.markNewGoroutine() defer sc.sendServeMsg(http2handlerDoneMsg) didPanic := true defer func() { @@ -6461,7 +6518,7 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) { var date string if _, ok := rws.snapHeader["Date"]; !ok { // TODO(bradfitz): be faster here, like net/http? measure. - date = time.Now().UTC().Format(TimeFormat) + date = rws.conn.srv.now().UTC().Format(TimeFormat) } for _, v := range rws.snapHeader["Trailer"] { @@ -6583,7 +6640,7 @@ func (rws *http2responseWriterState) promoteUndeclaredTrailers() { func (w *http2responseWriter) SetReadDeadline(deadline time.Time) error { st := w.rws.stream - if !deadline.IsZero() && deadline.Before(time.Now()) { + if !deadline.IsZero() && deadline.Before(w.rws.conn.srv.now()) { // If we're setting a deadline in the past, reset the stream immediately // so writes after SetWriteDeadline returns will fail. st.onReadTimeout() @@ -6599,9 +6656,9 @@ func (w *http2responseWriter) SetReadDeadline(deadline time.Time) error { if deadline.IsZero() { st.readDeadline = nil } else if st.readDeadline == nil { - st.readDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onReadTimeout) + st.readDeadline = sc.srv.afterFunc(deadline.Sub(sc.srv.now()), st.onReadTimeout) } else { - st.readDeadline.Reset(deadline.Sub(time.Now())) + st.readDeadline.Reset(deadline.Sub(sc.srv.now())) } }) return nil @@ -6609,7 +6666,7 @@ func (w *http2responseWriter) SetReadDeadline(deadline time.Time) error { func (w *http2responseWriter) SetWriteDeadline(deadline time.Time) error { st := w.rws.stream - if !deadline.IsZero() && deadline.Before(time.Now()) { + if !deadline.IsZero() && deadline.Before(w.rws.conn.srv.now()) { // If we're setting a deadline in the past, reset the stream immediately // so writes after SetWriteDeadline returns will fail. st.onWriteTimeout() @@ -6625,9 +6682,9 @@ func (w *http2responseWriter) SetWriteDeadline(deadline time.Time) error { if deadline.IsZero() { st.writeDeadline = nil } else if st.writeDeadline == nil { - st.writeDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onWriteTimeout) + st.writeDeadline = sc.srv.afterFunc(deadline.Sub(sc.srv.now()), st.onWriteTimeout) } else { - st.writeDeadline.Reset(deadline.Sub(time.Now())) + st.writeDeadline.Reset(deadline.Sub(sc.srv.now())) } }) return nil @@ -7103,6 +7160,20 @@ func (sc *http2serverConn) countError(name string, err error) error { return err } +// A timer is a time.Timer, as an interface which can be replaced in tests. +type http2timer = interface { + C() <-chan time.Time + Reset(d time.Duration) bool + Stop() bool +} + +// timeTimer adapts a time.Timer to the timer interface. +type http2timeTimer struct { + *time.Timer +} + +func (t http2timeTimer) C() <-chan time.Time { return t.Timer.C } + const ( // transportDefaultConnFlow is how many connection-level flow control // tokens we give the server at start-up, past the default 64k. @@ -7212,6 +7283,12 @@ type http2Transport struct { // waiting for their turn. StrictMaxConcurrentStreams bool + // IdleConnTimeout is the maximum amount of time an idle + // (keep-alive) connection will remain idle before closing + // itself. + // Zero means no limit. + IdleConnTimeout time.Duration + // ReadIdleTimeout is the timeout after which a health check using ping // frame will be carried out if no frame is received on the connection. // Note that a ping response will is considered a received frame, so if @@ -7243,6 +7320,46 @@ type http2Transport struct { connPoolOnce sync.Once connPoolOrDef http2ClientConnPool // non-nil version of ConnPool + + *http2transportTestHooks +} + +// Hook points used for testing. +// Outside of tests, t.transportTestHooks is nil and these all have minimal implementations. +// Inside tests, see the testSyncHooks function docs. + +type http2transportTestHooks struct { + newclientconn func(*http2ClientConn) + group http2synctestGroupInterface +} + +func (t *http2Transport) markNewGoroutine() { + if t != nil && t.http2transportTestHooks != nil { + t.http2transportTestHooks.group.Join() + } +} + +// newTimer creates a new time.Timer, or a synthetic timer in tests. +func (t *http2Transport) newTimer(d time.Duration) http2timer { + if t.http2transportTestHooks != nil { + return t.http2transportTestHooks.group.NewTimer(d) + } + return http2timeTimer{time.NewTimer(d)} +} + +// afterFunc creates a new time.AfterFunc timer, or a synthetic timer in tests. +func (t *http2Transport) afterFunc(d time.Duration, f func()) http2timer { + if t.http2transportTestHooks != nil { + return t.http2transportTestHooks.group.AfterFunc(d, f) + } + return http2timeTimer{time.AfterFunc(d, f)} +} + +func (t *http2Transport) contextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) { + if t.http2transportTestHooks != nil { + return t.http2transportTestHooks.group.ContextWithTimeout(ctx, d) + } + return context.WithTimeout(ctx, d) } func (t *http2Transport) maxHeaderListSize() uint32 { @@ -7367,7 +7484,7 @@ type http2ClientConn struct { readerErr error // set before readerDone is closed idleTimeout time.Duration // or 0 for never - idleTimer *time.Timer + idleTimer http2timer mu sync.Mutex // guards following cond *sync.Cond // hold mu; broadcast on flow/closed changes @@ -7511,6 +7628,7 @@ func (cs *http2clientStream) closeReqBodyLocked() { cs.reqBodyClosed = make(chan struct{}) reqBodyClosed := cs.reqBodyClosed go func() { + cs.cc.t.markNewGoroutine() cs.reqBody.Close() close(reqBodyClosed) }() @@ -7603,15 +7721,6 @@ func http2authorityAddr(scheme string, authority string) (addr string) { return net.JoinHostPort(host, port) } -var http2retryBackoffHook func(time.Duration) *time.Timer - -func http2backoffNewTimer(d time.Duration) *time.Timer { - if http2retryBackoffHook != nil { - return http2retryBackoffHook(d) - } - return time.NewTimer(d) -} - // RoundTripOpt is like RoundTrip, but takes options. func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) { if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) { @@ -7639,13 +7748,13 @@ func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Res backoff := float64(uint(1) << (uint(retry) - 1)) backoff += backoff * (0.1 * mathrand.Float64()) d := time.Second * time.Duration(backoff) - timer := http2backoffNewTimer(d) + tm := t.newTimer(d) select { - case <-timer.C: + case <-tm.C(): t.vlogf("RoundTrip retrying after failure: %v", roundTripErr) continue case <-req.Context().Done(): - timer.Stop() + tm.Stop() err = req.Context().Err() } } @@ -7724,6 +7833,9 @@ func http2canRetryError(err error) bool { } func (t *http2Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*http2ClientConn, error) { + if t.http2transportTestHooks != nil { + return t.newClientConn(nil, singleUse) + } host, _, err := net.SplitHostPort(addr) if err != nil { return nil, err @@ -7817,9 +7929,10 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client pings: make(map[[8]byte]chan struct{}), reqHeaderMu: make(chan struct{}, 1), } - if d := t.idleConnTimeout(); d != 0 { - cc.idleTimeout = d - cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout) + if t.http2transportTestHooks != nil { + t.markNewGoroutine() + t.http2transportTestHooks.newclientconn(cc) + c = cc.tconn } if http2VerboseLogs { t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr()) @@ -7884,6 +7997,12 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client return nil, cc.werr } + // Start the idle timer after the connection is fully initialized. + if d := t.idleConnTimeout(); d != 0 { + cc.idleTimeout = d + cc.idleTimer = t.afterFunc(d, cc.onIdleTimeout) + } + go cc.readLoop() return cc, nil } @@ -7892,7 +8011,7 @@ func (cc *http2ClientConn) healthCheck() { pingTimeout := cc.t.pingTimeout() // We don't need to periodically ping in the health check, because the readLoop of ClientConn will // trigger the healthCheck again if there is no frame received. - ctx, cancel := context.WithTimeout(context.Background(), pingTimeout) + ctx, cancel := cc.t.contextWithTimeout(context.Background(), pingTimeout) defer cancel() cc.vlogf("http2: Transport sending health check") err := cc.Ping(ctx) @@ -7927,7 +8046,20 @@ func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) { } last := f.LastStreamID for streamID, cs := range cc.streams { - if streamID > last { + if streamID <= last { + // The server's GOAWAY indicates that it received this stream. + // It will either finish processing it, or close the connection + // without doing so. Either way, leave the stream alone for now. + continue + } + if streamID == 1 && cc.goAway.ErrCode != http2ErrCodeNo { + // Don't retry the first stream on a connection if we get a non-NO error. + // If the server is sending an error on a new connection, + // retrying the request on a new one probably isn't going to work. + cs.abortStreamLocked(fmt.Errorf("http2: Transport received GOAWAY from server ErrCode:%v", cc.goAway.ErrCode)) + } else { + // Aborting the stream with errClentConnGotGoAway indicates that + // the request should be retried on a new connection. cs.abortStreamLocked(http2errClientConnGotGoAway) } } @@ -8123,6 +8255,7 @@ func (cc *http2ClientConn) Shutdown(ctx context.Context) error { done := make(chan struct{}) cancelled := false // guarded by cc.mu go func() { + cc.t.markNewGoroutine() cc.mu.Lock() defer cc.mu.Unlock() for { @@ -8281,6 +8414,10 @@ func (cc *http2ClientConn) decrStreamReservationsLocked() { } func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { + return cc.roundTrip(req, nil) +} + +func (cc *http2ClientConn) roundTrip(req *Request, streamf func(*http2clientStream)) (*Response, error) { ctx := req.Context() cs := &http2clientStream{ cc: cc, @@ -8295,7 +8432,28 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { respHeaderRecv: make(chan struct{}), donec: make(chan struct{}), } - go cs.doRequest(req) + + // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? + if !cc.t.disableCompression() && + req.Header.Get("Accept-Encoding") == "" && + req.Header.Get("Range") == "" && + !cs.isHead { + // Request gzip only, not deflate. Deflate is ambiguous and + // not as universally supported anyway. + // See: https://zlib.net/zlib_faq.html#faq39 + // + // Note that we don't request this for HEAD requests, + // due to a bug in nginx: + // http://trac.nginx.org/nginx/ticket/358 + // https://golang.org/issue/5522 + // + // We don't request gzip if the request is for a range, since + // auto-decoding a portion of a gzipped document will just fail + // anyway. See https://golang.org/issue/8923 + cs.requestedGzip = true + } + + go cs.doRequest(req, streamf) waitDone := func() error { select { @@ -8388,8 +8546,9 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { // doRequest runs for the duration of the request lifetime. // // It sends the request and performs post-request cleanup (closing Request.Body, etc.). -func (cs *http2clientStream) doRequest(req *Request) { - err := cs.writeRequest(req) +func (cs *http2clientStream) doRequest(req *Request, streamf func(*http2clientStream)) { + cs.cc.t.markNewGoroutine() + err := cs.writeRequest(req, streamf) cs.cleanupWriteRequest(err) } @@ -8400,7 +8559,7 @@ func (cs *http2clientStream) doRequest(req *Request) { // // It returns non-nil if the request ends otherwise. // If the returned error is StreamError, the error Code may be used in resetting the stream. -func (cs *http2clientStream) writeRequest(req *Request) (err error) { +func (cs *http2clientStream) writeRequest(req *Request, streamf func(*http2clientStream)) (err error) { cc := cs.cc ctx := cs.ctx @@ -8438,24 +8597,8 @@ func (cs *http2clientStream) writeRequest(req *Request) (err error) { } cc.mu.Unlock() - // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? - if !cc.t.disableCompression() && - req.Header.Get("Accept-Encoding") == "" && - req.Header.Get("Range") == "" && - !cs.isHead { - // Request gzip only, not deflate. Deflate is ambiguous and - // not as universally supported anyway. - // See: https://zlib.net/zlib_faq.html#faq39 - // - // Note that we don't request this for HEAD requests, - // due to a bug in nginx: - // http://trac.nginx.org/nginx/ticket/358 - // https://golang.org/issue/5522 - // - // We don't request gzip if the request is for a range, since - // auto-decoding a portion of a gzipped document will just fail - // anyway. See https://golang.org/issue/8923 - cs.requestedGzip = true + if streamf != nil { + streamf(cs) } continueTimeout := cc.t.expectContinueTimeout() @@ -8518,9 +8661,9 @@ func (cs *http2clientStream) writeRequest(req *Request) (err error) { var respHeaderTimer <-chan time.Time var respHeaderRecv chan struct{} if d := cc.responseHeaderTimeout(); d != 0 { - timer := time.NewTimer(d) + timer := cc.t.newTimer(d) defer timer.Stop() - respHeaderTimer = timer.C + respHeaderTimer = timer.C() respHeaderRecv = cs.respHeaderRecv } // Wait until the peer half-closes its end of the stream, @@ -8942,6 +9085,22 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err er } } +func http2validateHeaders(hdrs Header) string { + for k, vv := range hdrs { + if !httpguts.ValidHeaderFieldName(k) { + return fmt.Sprintf("name %q", k) + } + for _, v := range vv { + if !httpguts.ValidHeaderFieldValue(v) { + // Don't include the value in the error, + // because it may be sensitive. + return fmt.Sprintf("value for header %q", k) + } + } + } + return "" +} + var http2errNilRequestURL = errors.New("http2: Request.URI is nil") // requires cc.wmu be held. @@ -8979,19 +9138,14 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail } } - // Check for any invalid headers and return an error before we + // Check for any invalid headers+trailers and return an error before we // potentially pollute our hpack state. (We want to be able to // continue to reuse the hpack encoder for future requests) - for k, vv := range req.Header { - if !httpguts.ValidHeaderFieldName(k) { - return nil, fmt.Errorf("invalid HTTP header name %q", k) - } - for _, v := range vv { - if !httpguts.ValidHeaderFieldValue(v) { - // Don't include the value in the error, because it may be sensitive. - return nil, fmt.Errorf("invalid HTTP header value for header %q", k) - } - } + if err := http2validateHeaders(req.Header); err != "" { + return nil, fmt.Errorf("invalid HTTP header %s", err) + } + if err := http2validateHeaders(req.Trailer); err != "" { + return nil, fmt.Errorf("invalid HTTP trailer %s", err) } enumerateHeaders := func(f func(name, value string)) { @@ -9232,6 +9386,7 @@ type http2clientConnReadLoop struct { // readLoop runs in its own goroutine and reads and dispatches frames. func (cc *http2ClientConn) readLoop() { + cc.t.markNewGoroutine() rl := &http2clientConnReadLoop{cc: cc} defer rl.cleanup() cc.readerErr = rl.run() @@ -9333,10 +9488,9 @@ func (rl *http2clientConnReadLoop) run() error { cc := rl.cc gotSettings := false readIdleTimeout := cc.t.ReadIdleTimeout - var t *time.Timer + var t http2timer if readIdleTimeout != 0 { - t = time.AfterFunc(readIdleTimeout, cc.healthCheck) - defer t.Stop() + t = cc.t.afterFunc(readIdleTimeout, cc.healthCheck) } for { f, err := cc.fr.ReadFrame() @@ -9978,6 +10132,15 @@ func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame fl = &cs.flow } if !fl.add(int32(f.Increment)) { + // For stream, the sender sends RST_STREAM with an error code of FLOW_CONTROL_ERROR + if cs != nil { + rl.endStreamError(cs, http2StreamError{ + StreamID: f.StreamID, + Code: http2ErrCodeFlowControl, + }) + return nil + } + return http2ConnectionError(http2ErrCodeFlowControl) } cc.cond.Broadcast() @@ -10022,24 +10185,26 @@ func (cc *http2ClientConn) Ping(ctx context.Context) error { } cc.mu.Unlock() } - errc := make(chan error, 1) + var pingError error + errc := make(chan struct{}) go func() { + cc.t.markNewGoroutine() cc.wmu.Lock() defer cc.wmu.Unlock() - if err := cc.fr.WritePing(false, p); err != nil { - errc <- err + if pingError = cc.fr.WritePing(false, p); pingError != nil { + close(errc) return } - if err := cc.bw.Flush(); err != nil { - errc <- err + if pingError = cc.bw.Flush(); pingError != nil { + close(errc) return } }() select { case <-c: return nil - case err := <-errc: - return err + case <-errc: + return pingError case <-ctx.Done(): return ctx.Err() case <-cc.readerDone: @@ -10211,9 +10376,17 @@ func (rt http2noDialH2RoundTripper) RoundTrip(req *Request) (*Response, error) { } func (t *http2Transport) idleConnTimeout() time.Duration { + // to keep things backwards compatible, we use non-zero values of + // IdleConnTimeout, followed by using the IdleConnTimeout on the underlying + // http1 transport, followed by 0 + if t.IdleConnTimeout != 0 { + return t.IdleConnTimeout + } + if t.t1 != nil { return t.t1.IdleConnTimeout } + return 0 } @@ -11340,8 +11513,8 @@ func (ws *http2priorityWriteScheduler) addClosedOrIdleNode(list *[]*http2priorit } func (ws *http2priorityWriteScheduler) removeNode(n *http2priorityNode) { - for k := n.kids; k != nil; k = k.next { - k.setParent(n.parent) + for n.kids != nil { + n.kids.setParent(n.parent) } n.setParent(nil) delete(ws.nodes, n.id) diff --git a/contrib/go/_std_1.22/src/net/http/h2_error.go b/contrib/go/_std_1.23/src/net/http/h2_error.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/h2_error.go rename to contrib/go/_std_1.23/src/net/http/h2_error.go diff --git a/contrib/go/_std_1.22/src/net/http/header.go b/contrib/go/_std_1.23/src/net/http/header.go similarity index 94% rename from contrib/go/_std_1.22/src/net/http/header.go rename to contrib/go/_std_1.23/src/net/http/header.go index 9d0f3a125d64..b8b080bece92 100644 --- a/contrib/go/_std_1.22/src/net/http/header.go +++ b/contrib/go/_std_1.23/src/net/http/header.go @@ -9,7 +9,7 @@ import ( "net/http/httptrace" "net/http/internal/ascii" "net/textproto" - "sort" + "slices" "strings" "sync" "time" @@ -152,17 +152,11 @@ type keyValues struct { values []string } -// A headerSorter implements sort.Interface by sorting a []keyValues -// by key. It's used as a pointer, so it can fit in a sort.Interface -// interface value without allocation. +// headerSorter contains a slice of keyValues sorted by keyValues.key. type headerSorter struct { kvs []keyValues } -func (s *headerSorter) Len() int { return len(s.kvs) } -func (s *headerSorter) Swap(i, j int) { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] } -func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key } - var headerSorterPool = sync.Pool{ New: func() any { return new(headerSorter) }, } @@ -182,7 +176,7 @@ func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *h } } hs.kvs = kvs - sort.Sort(hs) + slices.SortFunc(hs.kvs, func(a, b keyValues) int { return strings.Compare(a.key, b.key) }) return kvs, hs } diff --git a/contrib/go/_std_1.22/src/net/http/http.go b/contrib/go/_std_1.23/src/net/http/http.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/http.go rename to contrib/go/_std_1.23/src/net/http/http.go diff --git a/contrib/go/_std_1.22/src/net/http/httptest/httptest.go b/contrib/go/_std_1.23/src/net/http/httptest/httptest.go similarity index 86% rename from contrib/go/_std_1.22/src/net/http/httptest/httptest.go rename to contrib/go/_std_1.23/src/net/http/httptest/httptest.go index f0ca64362d7f..0c0dbb40e89b 100644 --- a/contrib/go/_std_1.22/src/net/http/httptest/httptest.go +++ b/contrib/go/_std_1.23/src/net/http/httptest/httptest.go @@ -8,13 +8,19 @@ package httptest import ( "bufio" "bytes" + "context" "crypto/tls" "io" "net/http" "strings" ) -// NewRequest returns a new incoming server Request, suitable +// NewRequest wraps NewRequestWithContext using context.Background. +func NewRequest(method, target string, body io.Reader) *http.Request { + return NewRequestWithContext(context.Background(), method, target, body) +} + +// NewRequestWithContext returns a new incoming server Request, suitable // for passing to an [http.Handler] for testing. // // The target is the RFC 7230 "request-target": it may be either a @@ -37,7 +43,7 @@ import ( // // To generate a client HTTP request instead of a server request, see // the NewRequest function in the net/http package. -func NewRequest(method, target string, body io.Reader) *http.Request { +func NewRequestWithContext(ctx context.Context, method, target string, body io.Reader) *http.Request { if method == "" { method = "GET" } @@ -45,6 +51,7 @@ func NewRequest(method, target string, body io.Reader) *http.Request { if err != nil { panic("invalid NewRequest arguments; " + err.Error()) } + req = req.WithContext(ctx) // HTTP/1.0 was used above to avoid needing a Host field. Change it to 1.1 here. req.Proto = "HTTP/1.1" diff --git a/contrib/go/_std_1.22/src/net/http/httptest/recorder.go b/contrib/go/_std_1.23/src/net/http/httptest/recorder.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httptest/recorder.go rename to contrib/go/_std_1.23/src/net/http/httptest/recorder.go diff --git a/contrib/go/_std_1.23/src/net/http/httptest/server.go b/contrib/go/_std_1.23/src/net/http/httptest/server.go new file mode 100644 index 000000000000..fa5492317969 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/http/httptest/server.go @@ -0,0 +1,386 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Implementation of Server + +package httptest + +import ( + "crypto/tls" + "crypto/x509" + "flag" + "fmt" + "log" + "net" + "net/http" + "net/http/internal/testcert" + "os" + "strings" + "sync" + "time" +) + +// A Server is an HTTP server listening on a system-chosen port on the +// local loopback interface, for use in end-to-end HTTP tests. +type Server struct { + URL string // base URL of form http://ipaddr:port with no trailing slash + Listener net.Listener + + // EnableHTTP2 controls whether HTTP/2 is enabled + // on the server. It must be set between calling + // NewUnstartedServer and calling Server.StartTLS. + EnableHTTP2 bool + + // TLS is the optional TLS configuration, populated with a new config + // after TLS is started. If set on an unstarted server before StartTLS + // is called, existing fields are copied into the new config. + TLS *tls.Config + + // Config may be changed after calling NewUnstartedServer and + // before Start or StartTLS. + Config *http.Server + + // certificate is a parsed version of the TLS config certificate, if present. + certificate *x509.Certificate + + // wg counts the number of outstanding HTTP requests on this server. + // Close blocks until all requests are finished. + wg sync.WaitGroup + + mu sync.Mutex // guards closed and conns + closed bool + conns map[net.Conn]http.ConnState // except terminal states + + // client is configured for use with the server. + // Its transport is automatically closed when Close is called. + client *http.Client +} + +func newLocalListener() net.Listener { + if serveFlag != "" { + l, err := net.Listen("tcp", serveFlag) + if err != nil { + panic(fmt.Sprintf("httptest: failed to listen on %v: %v", serveFlag, err)) + } + return l + } + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + if l, err = net.Listen("tcp6", "[::1]:0"); err != nil { + panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err)) + } + } + return l +} + +// When debugging a particular http server-based test, +// this flag lets you run +// +// go test -run='^BrokenTest$' -httptest.serve=127.0.0.1:8000 +// +// to start the broken server so you can interact with it manually. +// We only register this flag if it looks like the caller knows about it +// and is trying to use it as we don't want to pollute flags and this +// isn't really part of our API. Don't depend on this. +var serveFlag string + +func init() { + if strSliceContainsPrefix(os.Args, "-httptest.serve=") || strSliceContainsPrefix(os.Args, "--httptest.serve=") { + flag.StringVar(&serveFlag, "httptest.serve", "", "if non-empty, httptest.NewServer serves on this address and blocks.") + } +} + +func strSliceContainsPrefix(v []string, pre string) bool { + for _, s := range v { + if strings.HasPrefix(s, pre) { + return true + } + } + return false +} + +// NewServer starts and returns a new [Server]. +// The caller should call Close when finished, to shut it down. +func NewServer(handler http.Handler) *Server { + ts := NewUnstartedServer(handler) + ts.Start() + return ts +} + +// NewUnstartedServer returns a new [Server] but doesn't start it. +// +// After changing its configuration, the caller should call Start or +// StartTLS. +// +// The caller should call Close when finished, to shut it down. +func NewUnstartedServer(handler http.Handler) *Server { + return &Server{ + Listener: newLocalListener(), + Config: &http.Server{Handler: handler}, + } +} + +// Start starts a server from NewUnstartedServer. +func (s *Server) Start() { + if s.URL != "" { + panic("Server already started") + } + if s.client == nil { + s.client = &http.Client{Transport: &http.Transport{}} + } + s.URL = "http://" + s.Listener.Addr().String() + s.wrap() + s.goServe() + if serveFlag != "" { + fmt.Fprintln(os.Stderr, "httptest: serving on", s.URL) + select {} + } +} + +// StartTLS starts TLS on a server from NewUnstartedServer. +func (s *Server) StartTLS() { + if s.URL != "" { + panic("Server already started") + } + if s.client == nil { + s.client = &http.Client{} + } + cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey) + if err != nil { + panic(fmt.Sprintf("httptest: NewTLSServer: %v", err)) + } + + existingConfig := s.TLS + if existingConfig != nil { + s.TLS = existingConfig.Clone() + } else { + s.TLS = new(tls.Config) + } + if s.TLS.NextProtos == nil { + nextProtos := []string{"http/1.1"} + if s.EnableHTTP2 { + nextProtos = []string{"h2"} + } + s.TLS.NextProtos = nextProtos + } + if len(s.TLS.Certificates) == 0 { + s.TLS.Certificates = []tls.Certificate{cert} + } + s.certificate, err = x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0]) + if err != nil { + panic(fmt.Sprintf("httptest: NewTLSServer: %v", err)) + } + certpool := x509.NewCertPool() + certpool.AddCert(s.certificate) + s.client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: certpool, + }, + ForceAttemptHTTP2: s.EnableHTTP2, + } + s.Listener = tls.NewListener(s.Listener, s.TLS) + s.URL = "https://" + s.Listener.Addr().String() + s.wrap() + s.goServe() +} + +// NewTLSServer starts and returns a new [Server] using TLS. +// The caller should call Close when finished, to shut it down. +func NewTLSServer(handler http.Handler) *Server { + ts := NewUnstartedServer(handler) + ts.StartTLS() + return ts +} + +type closeIdleTransport interface { + CloseIdleConnections() +} + +// Close shuts down the server and blocks until all outstanding +// requests on this server have completed. +func (s *Server) Close() { + s.mu.Lock() + if !s.closed { + s.closed = true + s.Listener.Close() + s.Config.SetKeepAlivesEnabled(false) + for c, st := range s.conns { + // Force-close any idle connections (those between + // requests) and new connections (those which connected + // but never sent a request). StateNew connections are + // super rare and have only been seen (in + // previously-flaky tests) in the case of + // socket-late-binding races from the http Client + // dialing this server and then getting an idle + // connection before the dial completed. There is thus + // a connected connection in StateNew with no + // associated Request. We only close StateIdle and + // StateNew because they're not doing anything. It's + // possible StateNew is about to do something in a few + // milliseconds, but a previous CL to check again in a + // few milliseconds wasn't liked (early versions of + // https://golang.org/cl/15151) so now we just + // forcefully close StateNew. The docs for Server.Close say + // we wait for "outstanding requests", so we don't close things + // in StateActive. + if st == http.StateIdle || st == http.StateNew { + s.closeConn(c) + } + } + // If this server doesn't shut down in 5 seconds, tell the user why. + t := time.AfterFunc(5*time.Second, s.logCloseHangDebugInfo) + defer t.Stop() + } + s.mu.Unlock() + + // Not part of httptest.Server's correctness, but assume most + // users of httptest.Server will be using the standard + // transport, so help them out and close any idle connections for them. + if t, ok := http.DefaultTransport.(closeIdleTransport); ok { + t.CloseIdleConnections() + } + + // Also close the client idle connections. + if s.client != nil { + if t, ok := s.client.Transport.(closeIdleTransport); ok { + t.CloseIdleConnections() + } + } + + s.wg.Wait() +} + +func (s *Server) logCloseHangDebugInfo() { + s.mu.Lock() + defer s.mu.Unlock() + var buf strings.Builder + buf.WriteString("httptest.Server blocked in Close after 5 seconds, waiting for connections:\n") + for c, st := range s.conns { + fmt.Fprintf(&buf, " %T %p %v in state %v\n", c, c, c.RemoteAddr(), st) + } + log.Print(buf.String()) +} + +// CloseClientConnections closes any open HTTP connections to the test Server. +func (s *Server) CloseClientConnections() { + s.mu.Lock() + nconn := len(s.conns) + ch := make(chan struct{}, nconn) + for c := range s.conns { + go s.closeConnChan(c, ch) + } + s.mu.Unlock() + + // Wait for outstanding closes to finish. + // + // Out of paranoia for making a late change in Go 1.6, we + // bound how long this can wait, since golang.org/issue/14291 + // isn't fully understood yet. At least this should only be used + // in tests. + timer := time.NewTimer(5 * time.Second) + defer timer.Stop() + for i := 0; i < nconn; i++ { + select { + case <-ch: + case <-timer.C: + // Too slow. Give up. + return + } + } +} + +// Certificate returns the certificate used by the server, or nil if +// the server doesn't use TLS. +func (s *Server) Certificate() *x509.Certificate { + return s.certificate +} + +// Client returns an HTTP client configured for making requests to the server. +// It is configured to trust the server's TLS test certificate and will +// close its idle connections on [Server.Close]. +// Use Server.URL as the base URL to send requests to the server. +func (s *Server) Client() *http.Client { + return s.client +} + +func (s *Server) goServe() { + s.wg.Add(1) + go func() { + defer s.wg.Done() + s.Config.Serve(s.Listener) + }() +} + +// wrap installs the connection state-tracking hook to know which +// connections are idle. +func (s *Server) wrap() { + oldHook := s.Config.ConnState + s.Config.ConnState = func(c net.Conn, cs http.ConnState) { + s.mu.Lock() + defer s.mu.Unlock() + + switch cs { + case http.StateNew: + if _, exists := s.conns[c]; exists { + panic("invalid state transition") + } + if s.conns == nil { + s.conns = make(map[net.Conn]http.ConnState) + } + // Add c to the set of tracked conns and increment it to the + // waitgroup. + s.wg.Add(1) + s.conns[c] = cs + if s.closed { + // Probably just a socket-late-binding dial from + // the default transport that lost the race (and + // thus this connection is now idle and will + // never be used). + s.closeConn(c) + } + case http.StateActive: + if oldState, ok := s.conns[c]; ok { + if oldState != http.StateNew && oldState != http.StateIdle { + panic("invalid state transition") + } + s.conns[c] = cs + } + case http.StateIdle: + if oldState, ok := s.conns[c]; ok { + if oldState != http.StateActive { + panic("invalid state transition") + } + s.conns[c] = cs + } + if s.closed { + s.closeConn(c) + } + case http.StateHijacked, http.StateClosed: + // Remove c from the set of tracked conns and decrement it from the + // waitgroup, unless it was previously removed. + if _, ok := s.conns[c]; ok { + delete(s.conns, c) + // Keep Close from returning until the user's ConnState hook + // (if any) finishes. + defer s.wg.Done() + } + } + if oldHook != nil { + oldHook(c, cs) + } + } +} + +// closeConn closes c. +// s.mu must be held. +func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) } + +// closeConnChan is like closeConn, but takes an optional channel to receive a value +// when the goroutine closing c is done. +func (s *Server) closeConnChan(c net.Conn, done chan<- struct{}) { + c.Close() + if done != nil { + done <- struct{}{} + } +} diff --git a/contrib/go/_std_1.22/src/net/http/httptest/ya.make b/contrib/go/_std_1.23/src/net/http/httptest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httptest/ya.make rename to contrib/go/_std_1.23/src/net/http/httptest/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/httptrace/trace.go b/contrib/go/_std_1.23/src/net/http/httptrace/trace.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httptrace/trace.go rename to contrib/go/_std_1.23/src/net/http/httptrace/trace.go diff --git a/contrib/go/_std_1.22/src/net/http/httptrace/ya.make b/contrib/go/_std_1.23/src/net/http/httptrace/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httptrace/ya.make rename to contrib/go/_std_1.23/src/net/http/httptrace/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/httputil/dump.go b/contrib/go/_std_1.23/src/net/http/httputil/dump.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httputil/dump.go rename to contrib/go/_std_1.23/src/net/http/httputil/dump.go diff --git a/contrib/go/_std_1.22/src/net/http/httputil/httputil.go b/contrib/go/_std_1.23/src/net/http/httputil/httputil.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httputil/httputil.go rename to contrib/go/_std_1.23/src/net/http/httputil/httputil.go diff --git a/contrib/go/_std_1.22/src/net/http/httputil/persist.go b/contrib/go/_std_1.23/src/net/http/httputil/persist.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httputil/persist.go rename to contrib/go/_std_1.23/src/net/http/httputil/persist.go diff --git a/contrib/go/_std_1.22/src/net/http/httputil/reverseproxy.go b/contrib/go/_std_1.23/src/net/http/httputil/reverseproxy.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/httputil/reverseproxy.go rename to contrib/go/_std_1.23/src/net/http/httputil/reverseproxy.go index 5c70f0d27bb1..04248d5f531e 100644 --- a/contrib/go/_std_1.22/src/net/http/httputil/reverseproxy.go +++ b/contrib/go/_std_1.23/src/net/http/httputil/reverseproxy.go @@ -454,8 +454,19 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { outreq.Header.Set("User-Agent", "") } + var ( + roundTripMutex sync.Mutex + roundTripDone bool + ) trace := &httptrace.ClientTrace{ Got1xxResponse: func(code int, header textproto.MIMEHeader) error { + roundTripMutex.Lock() + defer roundTripMutex.Unlock() + if roundTripDone { + // If RoundTrip has returned, don't try to further modify + // the ResponseWriter's header map. + return nil + } h := rw.Header() copyHeader(h, http.Header(header)) rw.WriteHeader(code) @@ -468,6 +479,9 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { outreq = outreq.WithContext(httptrace.WithClientTrace(outreq.Context(), trace)) res, err := transport.RoundTrip(outreq) + roundTripMutex.Lock() + roundTripDone = true + roundTripMutex.Unlock() if err != nil { p.getErrorHandler()(rw, outreq, err) return diff --git a/contrib/go/_std_1.22/src/net/http/httputil/ya.make b/contrib/go/_std_1.23/src/net/http/httputil/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httputil/ya.make rename to contrib/go/_std_1.23/src/net/http/httputil/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/internal/ascii/print.go b/contrib/go/_std_1.23/src/net/http/internal/ascii/print.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/internal/ascii/print.go rename to contrib/go/_std_1.23/src/net/http/internal/ascii/print.go diff --git a/contrib/go/_std_1.22/src/net/http/internal/ascii/ya.make b/contrib/go/_std_1.23/src/net/http/internal/ascii/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/internal/ascii/ya.make rename to contrib/go/_std_1.23/src/net/http/internal/ascii/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/internal/chunked.go b/contrib/go/_std_1.23/src/net/http/internal/chunked.go similarity index 92% rename from contrib/go/_std_1.22/src/net/http/internal/chunked.go rename to contrib/go/_std_1.23/src/net/http/internal/chunked.go index 196b5d892589..0b08a97a0831 100644 --- a/contrib/go/_std_1.22/src/net/http/internal/chunked.go +++ b/contrib/go/_std_1.23/src/net/http/internal/chunked.go @@ -164,6 +164,19 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) { } return nil, err } + + // RFC 9112 permits parsers to accept a bare \n as a line ending in headers, + // but not in chunked encoding lines. See https://www.rfc-editor.org/errata/eid7633, + // which explicitly rejects a clarification permitting \n as a chunk terminator. + // + // Verify that the line ends in a CRLF, and that no CRs appear before the end. + if idx := bytes.IndexByte(p, '\r'); idx == -1 { + return nil, errors.New("chunked line ends with bare LF") + } else if idx != len(p)-2 { + return nil, errors.New("invalid CR in chunked line") + } + p = p[:len(p)-2] // trim CRLF + if len(p) >= maxLineLength { return nil, ErrLineTooLong } @@ -171,14 +184,14 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) { } func trimTrailingWhitespace(b []byte) []byte { - for len(b) > 0 && isASCIISpace(b[len(b)-1]) { + for len(b) > 0 && isOWS(b[len(b)-1]) { b = b[:len(b)-1] } return b } -func isASCIISpace(b byte) bool { - return b == ' ' || b == '\t' || b == '\n' || b == '\r' +func isOWS(b byte) bool { + return b == ' ' || b == '\t' } var semi = []byte(";") diff --git a/contrib/go/_std_1.23/src/net/http/internal/testcert/testcert.go b/contrib/go/_std_1.23/src/net/http/internal/testcert/testcert.go new file mode 100644 index 000000000000..78ce42e22826 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/http/internal/testcert/testcert.go @@ -0,0 +1,65 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package testcert contains a test-only localhost certificate. +package testcert + +import "strings" + +// LocalhostCert is a PEM-encoded TLS cert with SAN IPs +// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT. +// generated from src/crypto/tls: +// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com,*.example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h +var LocalhostCert = []byte(`-----BEGIN CERTIFICATE----- +MIIDSDCCAjCgAwIBAgIQEP/md970HysdBTpuzDOf0DANBgkqhkiG9w0BAQsFADAS +MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw +MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxcl69ROJdxjN+MJZnbFrYxyQooADCsJ6VDkuMyNQIix/Hk15Nk/u +FyBX1Me++aEpGmY3RIY4fUvELqT/srvAHsTXwVVSttMcY8pcAFmXSqo3x4MuUTG/ +jCX3Vftj0r3EM5M8ImY1rzA/jqTTLJg00rD+DmuDABcqQvoXw/RV8w1yTRi5BPoH +DFD/AWTt/YgMvk1l2Yq/xI8VbMUIpjBoGXxWsSevQ5i2s1mk9/yZzu0Ysp1tTlzD +qOPa4ysFjBitdXiwfxjxtv5nXqOCP5rheKO0sWLk0fetMp1OV5JSJMAJw6c2ZMkl +U2WMqAEpRjdE/vHfIuNg+yGaRRqI07NZRQIDAQABo4GXMIGUMA4GA1UdDwEB/wQE +AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQR5QIzmacmw78ZI1C4MXw7Q0wJ1jA9BgNVHREENjA0ggtleGFtcGxlLmNv +bYINKi5leGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG +9w0BAQsFAAOCAQEACrRNgiioUDzxQftd0fwOa6iRRcPampZRDtuaF68yNHoNWbOu +LUwc05eOWxRq3iABGSk2xg+FXM3DDeW4HhAhCFptq7jbVZ+4Jj6HeJG9mYRatAxR +Y/dEpa0D0EHhDxxVg6UzKOXB355n0IetGE/aWvyTV9SiDs6QsaC57Q9qq1/mitx5 +2GFBoapol9L5FxCc77bztzK8CpLujkBi25Vk6GAFbl27opLfpyxkM+rX/T6MXCPO +6/YBacNZ7ff1/57Etg4i5mNA6ubCpuc4Gi9oYqCNNohftr2lkJr7REdDR6OW0lsL +rF7r4gUnKeC7mYIH1zypY7laskopiLFAfe96Kg== +-----END CERTIFICATE-----`) + +// LocalhostKey is the private key for LocalhostCert. +var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFyXr1E4l3GM34 +wlmdsWtjHJCigAMKwnpUOS4zI1AiLH8eTXk2T+4XIFfUx775oSkaZjdEhjh9S8Qu +pP+yu8AexNfBVVK20xxjylwAWZdKqjfHgy5RMb+MJfdV+2PSvcQzkzwiZjWvMD+O +pNMsmDTSsP4Oa4MAFypC+hfD9FXzDXJNGLkE+gcMUP8BZO39iAy+TWXZir/EjxVs +xQimMGgZfFaxJ69DmLazWaT3/JnO7RiynW1OXMOo49rjKwWMGK11eLB/GPG2/mde +o4I/muF4o7SxYuTR960ynU5XklIkwAnDpzZkySVTZYyoASlGN0T+8d8i42D7IZpF +GojTs1lFAgMBAAECggEAIYthUi1lFBDd5gG4Rzlu+BlBIn5JhcqkCqLEBiJIFfOr +/4yuMRrvS3bNzqWt6xJ9MSAC4ZlN/VobRLnxL/QNymoiGYUKCT3Ww8nvPpPzR9OE +sE68TUL9tJw/zZJcRMKwgvrGqSLimfq53MxxkE+kLdOc0v9C8YH8Re26mB5ZcWYa +7YFyZQpKsQYnsmu/05cMbpOQrQWhtmIqRoyn8mG/par2s3NzjtpSE9NINyz26uFc +k/3ovFJQIHkUmTS7KHD3BgY5vuCqP98HramYnOysJ0WoYgvSDNCWw3037s5CCwJT +gCKuM+Ow6liFrj83RrdKBpm5QUGjfNpYP31o+QNP4QKBgQDSrUQ2XdgtAnibAV7u +7kbxOxro0EhIKso0Y/6LbDQgcXgxLqltkmeqZgG8nC3Z793lhlSasz2snhzzooV5 +5fTy1y8ikXqjhG0nNkInFyOhsI0auE28CFoDowaQd+5cmCatpN4Grqo5PNRXxm1w +HktfPEgoP11NNCFHvvN5fEKbbQKBgQDwVlOaV20IvW3IPq7cXZyiyabouFF9eTRo +VJka1Uv+JtyvL2P0NKkjYHOdN8gRblWqxQtJoTNk020rVA4UP1heiXALy50gvj/p +hMcybPTLYSPOhAGx838KIcvGR5oskP1aUCmFbFQzGELxhJ9diVVjxUtbG2DuwPKd +tD9TLxT2OQKBgQCcdlHSjp+dzdgERmBa0ludjGfPv9/uuNizUBAbO6D690psPFtY +JQMYaemgSd1DngEOFVWADt4e9M5Lose+YCoqr+UxpxmNlyv5kzJOFcFAs/4XeglB +PHKdgNW/NVKxMc6H54l9LPr+x05sYdGlEtqnP/3W5jhEvhJ5Vjc8YiyVgQKBgQCl +zwjyrGo+42GACy7cPYE5FeIfIDqoVByB9guC5bD98JXEDu/opQQjsgFRcBCJZhOY +M0UsURiB8ROaFu13rpQq9KrmmF0ZH+g8FSzQbzcbsTLg4VXCDXmR5esOKowFPypr +Sm667BfTAGP++D5ya7MLmCv6+RKQ5XD8uEQQAaV2kQKBgAD8qeJuWIXZT0VKkQrn +nIhgtzGERF/6sZdQGW2LxTbUDWG74AfFkkEbeBfwEkCZXY/xmnYqYABhvlSex8jU +supU6Eea21esIxIub2zv/Np0ojUb6rlqTPS4Ox1E27D787EJ3VOXpriSD10vyNnZ +jel6uj2FOP9g54s+GzlSVg/T +-----END RSA TESTING KEY-----`)) + +func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } diff --git a/contrib/go/_std_1.22/src/net/http/internal/testcert/ya.make b/contrib/go/_std_1.23/src/net/http/internal/testcert/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/internal/testcert/ya.make rename to contrib/go/_std_1.23/src/net/http/internal/testcert/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/internal/ya.make b/contrib/go/_std_1.23/src/net/http/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/internal/ya.make rename to contrib/go/_std_1.23/src/net/http/internal/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/jar.go b/contrib/go/_std_1.23/src/net/http/jar.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/jar.go rename to contrib/go/_std_1.23/src/net/http/jar.go diff --git a/contrib/go/_std_1.22/src/net/http/mapping.go b/contrib/go/_std_1.23/src/net/http/mapping.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/mapping.go rename to contrib/go/_std_1.23/src/net/http/mapping.go diff --git a/contrib/go/_std_1.22/src/net/http/method.go b/contrib/go/_std_1.23/src/net/http/method.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/method.go rename to contrib/go/_std_1.23/src/net/http/method.go diff --git a/contrib/go/_std_1.22/src/net/http/omithttp2.go b/contrib/go/_std_1.23/src/net/http/omithttp2.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/omithttp2.go rename to contrib/go/_std_1.23/src/net/http/omithttp2.go diff --git a/contrib/go/_std_1.22/src/net/http/pattern.go b/contrib/go/_std_1.23/src/net/http/pattern.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/pattern.go rename to contrib/go/_std_1.23/src/net/http/pattern.go index f6af19b0f443..8fd120e7775c 100644 --- a/contrib/go/_std_1.22/src/net/http/pattern.go +++ b/contrib/go/_std_1.23/src/net/http/pattern.go @@ -76,7 +76,7 @@ type segment struct { // a literal or a wildcard of the form "{name}", "{name...}", or "{$}". // // METHOD, HOST and PATH are all optional; that is, the string can be "/". -// If METHOD is present, it must be followed by a single space. +// If METHOD is present, it must be followed by at least one space or tab. // Wildcard names must be valid Go identifiers. // The "{$}" and "{name...}" wildcard must occur at the end of PATH. // PATH may end with a '/'. @@ -92,7 +92,10 @@ func parsePattern(s string) (_ *pattern, err error) { } }() - method, rest, found := strings.Cut(s, " ") + method, rest, found := s, "", false + if i := strings.IndexAny(s, " \t"); i >= 0 { + method, rest, found = s[:i], strings.TrimLeft(s[i+1:], " \t"), true + } if !found { rest = method method = "" diff --git a/contrib/go/_std_1.23/src/net/http/pprof/pprof.go b/contrib/go/_std_1.23/src/net/http/pprof/pprof.go new file mode 100644 index 000000000000..cf4b8415ca3a --- /dev/null +++ b/contrib/go/_std_1.23/src/net/http/pprof/pprof.go @@ -0,0 +1,468 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package pprof serves via its HTTP server runtime profiling data +// in the format expected by the pprof visualization tool. +// +// The package is typically only imported for the side effect of +// registering its HTTP handlers. +// The handled paths all begin with /debug/pprof/. +// As of Go 1.22, all the paths must be requested with GET. +// +// To use pprof, link this package into your program: +// +// import _ "net/http/pprof" +// +// If your application is not already running an http server, you +// need to start one. Add "net/http" and "log" to your imports and +// the following code to your main function: +// +// go func() { +// log.Println(http.ListenAndServe("localhost:6060", nil)) +// }() +// +// By default, all the profiles listed in [runtime/pprof.Profile] are +// available (via [Handler]), in addition to the [Cmdline], [Profile], [Symbol], +// and [Trace] profiles defined in this package. +// If you are not using DefaultServeMux, you will have to register handlers +// with the mux you are using. +// +// # Parameters +// +// Parameters can be passed via GET query params: +// +// - debug=N (all profiles): response format: N = 0: binary (default), N > 0: plaintext +// - gc=N (heap profile): N > 0: run a garbage collection cycle before profiling +// - seconds=N (allocs, block, goroutine, heap, mutex, threadcreate profiles): return a delta profile +// - seconds=N (cpu (profile), trace profiles): profile for the given duration +// +// # Usage examples +// +// Use the pprof tool to look at the heap profile: +// +// go tool pprof http://localhost:6060/debug/pprof/heap +// +// Or to look at a 30-second CPU profile: +// +// go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30 +// +// Or to look at the goroutine blocking profile, after calling +// [runtime.SetBlockProfileRate] in your program: +// +// go tool pprof http://localhost:6060/debug/pprof/block +// +// Or to look at the holders of contended mutexes, after calling +// [runtime.SetMutexProfileFraction] in your program: +// +// go tool pprof http://localhost:6060/debug/pprof/mutex +// +// The package also exports a handler that serves execution trace data +// for the "go tool trace" command. To collect a 5-second execution trace: +// +// curl -o trace.out http://localhost:6060/debug/pprof/trace?seconds=5 +// go tool trace trace.out +// +// To view all available profiles, open http://localhost:6060/debug/pprof/ +// in your browser. +// +// For a study of the facility in action, visit +// https://blog.golang.org/2011/06/profiling-go-programs.html. +package pprof + +import ( + "bufio" + "bytes" + "context" + "fmt" + "html" + "internal/godebug" + "internal/profile" + "io" + "log" + "net/http" + "net/url" + "os" + "runtime" + "runtime/pprof" + "runtime/trace" + "sort" + "strconv" + "strings" + "time" +) + +func init() { + prefix := "" + if godebug.New("httpmuxgo121").Value() != "1" { + prefix = "GET " + } + http.HandleFunc(prefix+"/debug/pprof/", Index) + http.HandleFunc(prefix+"/debug/pprof/cmdline", Cmdline) + http.HandleFunc(prefix+"/debug/pprof/profile", Profile) + http.HandleFunc(prefix+"/debug/pprof/symbol", Symbol) + http.HandleFunc(prefix+"/debug/pprof/trace", Trace) +} + +// Cmdline responds with the running program's +// command line, with arguments separated by NUL bytes. +// The package initialization registers it as /debug/pprof/cmdline. +func Cmdline(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + fmt.Fprint(w, strings.Join(os.Args, "\x00")) +} + +func sleep(r *http.Request, d time.Duration) { + select { + case <-time.After(d): + case <-r.Context().Done(): + } +} + +func configureWriteDeadline(w http.ResponseWriter, r *http.Request, seconds float64) { + srv, ok := r.Context().Value(http.ServerContextKey).(*http.Server) + if ok && srv.WriteTimeout > 0 { + timeout := srv.WriteTimeout + time.Duration(seconds*float64(time.Second)) + + rc := http.NewResponseController(w) + rc.SetWriteDeadline(time.Now().Add(timeout)) + } +} + +func serveError(w http.ResponseWriter, status int, txt string) { + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("X-Go-Pprof", "1") + w.Header().Del("Content-Disposition") + w.WriteHeader(status) + fmt.Fprintln(w, txt) +} + +// Profile responds with the pprof-formatted cpu profile. +// Profiling lasts for duration specified in seconds GET parameter, or for 30 seconds if not specified. +// The package initialization registers it as /debug/pprof/profile. +func Profile(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") + sec, err := strconv.ParseInt(r.FormValue("seconds"), 10, 64) + if sec <= 0 || err != nil { + sec = 30 + } + + configureWriteDeadline(w, r, float64(sec)) + + // Set Content Type assuming StartCPUProfile will work, + // because if it does it starts writing. + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", `attachment; filename="profile"`) + if err := pprof.StartCPUProfile(w); err != nil { + // StartCPUProfile failed, so no writes yet. + serveError(w, http.StatusInternalServerError, + fmt.Sprintf("Could not enable CPU profiling: %s", err)) + return + } + sleep(r, time.Duration(sec)*time.Second) + pprof.StopCPUProfile() +} + +// Trace responds with the execution trace in binary form. +// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified. +// The package initialization registers it as /debug/pprof/trace. +func Trace(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") + sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64) + if sec <= 0 || err != nil { + sec = 1 + } + + configureWriteDeadline(w, r, sec) + + // Set Content Type assuming trace.Start will work, + // because if it does it starts writing. + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", `attachment; filename="trace"`) + if err := trace.Start(w); err != nil { + // trace.Start failed, so no writes yet. + serveError(w, http.StatusInternalServerError, + fmt.Sprintf("Could not enable tracing: %s", err)) + return + } + sleep(r, time.Duration(sec*float64(time.Second))) + trace.Stop() +} + +// Symbol looks up the program counters listed in the request, +// responding with a table mapping program counters to function names. +// The package initialization registers it as /debug/pprof/symbol. +func Symbol(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + + // We have to read the whole POST body before + // writing any output. Buffer the output here. + var buf bytes.Buffer + + // We don't know how many symbols we have, but we + // do have symbol information. Pprof only cares whether + // this number is 0 (no symbols available) or > 0. + fmt.Fprintf(&buf, "num_symbols: 1\n") + + var b *bufio.Reader + if r.Method == "POST" { + b = bufio.NewReader(r.Body) + } else { + b = bufio.NewReader(strings.NewReader(r.URL.RawQuery)) + } + + for { + word, err := b.ReadSlice('+') + if err == nil { + word = word[0 : len(word)-1] // trim + + } + pc, _ := strconv.ParseUint(string(word), 0, 64) + if pc != 0 { + f := runtime.FuncForPC(uintptr(pc)) + if f != nil { + fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name()) + } + } + + // Wait until here to check for err; the last + // symbol will have an err because it doesn't end in +. + if err != nil { + if err != io.EOF { + fmt.Fprintf(&buf, "reading request: %v\n", err) + } + break + } + } + + w.Write(buf.Bytes()) +} + +// Handler returns an HTTP handler that serves the named profile. +// Available profiles can be found in [runtime/pprof.Profile]. +func Handler(name string) http.Handler { + return handler(name) +} + +type handler string + +func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") + p := pprof.Lookup(string(name)) + if p == nil { + serveError(w, http.StatusNotFound, "Unknown profile") + return + } + if sec := r.FormValue("seconds"); sec != "" { + name.serveDeltaProfile(w, r, p, sec) + return + } + gc, _ := strconv.Atoi(r.FormValue("gc")) + if name == "heap" && gc > 0 { + runtime.GC() + } + debug, _ := strconv.Atoi(r.FormValue("debug")) + if debug != 0 { + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + } else { + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name)) + } + p.WriteTo(w, debug) +} + +func (name handler) serveDeltaProfile(w http.ResponseWriter, r *http.Request, p *pprof.Profile, secStr string) { + sec, err := strconv.ParseInt(secStr, 10, 64) + if err != nil || sec <= 0 { + serveError(w, http.StatusBadRequest, `invalid value for "seconds" - must be a positive integer`) + return + } + // 'name' should be a key in profileSupportsDelta. + if !profileSupportsDelta[name] { + serveError(w, http.StatusBadRequest, `"seconds" parameter is not supported for this profile type`) + return + } + + configureWriteDeadline(w, r, float64(sec)) + + debug, _ := strconv.Atoi(r.FormValue("debug")) + if debug != 0 { + serveError(w, http.StatusBadRequest, "seconds and debug params are incompatible") + return + } + p0, err := collectProfile(p) + if err != nil { + serveError(w, http.StatusInternalServerError, "failed to collect profile") + return + } + + t := time.NewTimer(time.Duration(sec) * time.Second) + defer t.Stop() + + select { + case <-r.Context().Done(): + err := r.Context().Err() + if err == context.DeadlineExceeded { + serveError(w, http.StatusRequestTimeout, err.Error()) + } else { // TODO: what's a good status code for canceled requests? 400? + serveError(w, http.StatusInternalServerError, err.Error()) + } + return + case <-t.C: + } + + p1, err := collectProfile(p) + if err != nil { + serveError(w, http.StatusInternalServerError, "failed to collect profile") + return + } + ts := p1.TimeNanos + dur := p1.TimeNanos - p0.TimeNanos + + p0.Scale(-1) + + p1, err = profile.Merge([]*profile.Profile{p0, p1}) + if err != nil { + serveError(w, http.StatusInternalServerError, "failed to compute delta") + return + } + + p1.TimeNanos = ts // set since we don't know what profile.Merge set for TimeNanos. + p1.DurationNanos = dur + + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s-delta"`, name)) + p1.Write(w) +} + +func collectProfile(p *pprof.Profile) (*profile.Profile, error) { + var buf bytes.Buffer + if err := p.WriteTo(&buf, 0); err != nil { + return nil, err + } + ts := time.Now().UnixNano() + p0, err := profile.Parse(&buf) + if err != nil { + return nil, err + } + p0.TimeNanos = ts + return p0, nil +} + +var profileSupportsDelta = map[handler]bool{ + "allocs": true, + "block": true, + "goroutine": true, + "heap": true, + "mutex": true, + "threadcreate": true, +} + +var profileDescriptions = map[string]string{ + "allocs": "A sampling of all past memory allocations", + "block": "Stack traces that led to blocking on synchronization primitives", + "cmdline": "The command line invocation of the current program", + "goroutine": "Stack traces of all current goroutines. Use debug=2 as a query parameter to export in the same format as an unrecovered panic.", + "heap": "A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.", + "mutex": "Stack traces of holders of contended mutexes", + "profile": "CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile.", + "threadcreate": "Stack traces that led to the creation of new OS threads", + "trace": "A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.", +} + +type profileEntry struct { + Name string + Href string + Desc string + Count int +} + +// Index responds with the pprof-formatted profile named by the request. +// For example, "/debug/pprof/heap" serves the "heap" profile. +// Index responds to a request for "/debug/pprof/" with an HTML page +// listing the available profiles. +func Index(w http.ResponseWriter, r *http.Request) { + if name, found := strings.CutPrefix(r.URL.Path, "/debug/pprof/"); found { + if name != "" { + handler(name).ServeHTTP(w, r) + return + } + } + + w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set("Content-Type", "text/html; charset=utf-8") + + var profiles []profileEntry + for _, p := range pprof.Profiles() { + profiles = append(profiles, profileEntry{ + Name: p.Name(), + Href: p.Name(), + Desc: profileDescriptions[p.Name()], + Count: p.Count(), + }) + } + + // Adding other profiles exposed from within this package + for _, p := range []string{"cmdline", "profile", "trace"} { + profiles = append(profiles, profileEntry{ + Name: p, + Href: p, + Desc: profileDescriptions[p], + }) + } + + sort.Slice(profiles, func(i, j int) bool { + return profiles[i].Name < profiles[j].Name + }) + + if err := indexTmplExecute(w, profiles); err != nil { + log.Print(err) + } +} + +func indexTmplExecute(w io.Writer, profiles []profileEntry) error { + var b bytes.Buffer + b.WriteString(` + +/debug/pprof/ + + + +/debug/pprof/ +
+

Set debug=1 as a query parameter to export in legacy text format

+
+Types of profiles available: + + +`) + + for _, profile := range profiles { + link := &url.URL{Path: profile.Href, RawQuery: "debug=1"} + fmt.Fprintf(&b, "\n", profile.Count, link, html.EscapeString(profile.Name)) + } + + b.WriteString(`
CountProfile
%d%s
+
full goroutine stack dump +
+

+Profile Descriptions: +

    +`) + for _, profile := range profiles { + fmt.Fprintf(&b, "
  • %s:
    %s
  • \n", html.EscapeString(profile.Name), html.EscapeString(profile.Desc)) + } + b.WriteString(`
+

+ +`) + + _, err := w.Write(b.Bytes()) + return err +} diff --git a/contrib/go/_std_1.22/src/net/http/pprof/ya.make b/contrib/go/_std_1.23/src/net/http/pprof/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/pprof/ya.make rename to contrib/go/_std_1.23/src/net/http/pprof/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/request.go b/contrib/go/_std_1.23/src/net/http/request.go similarity index 97% rename from contrib/go/_std_1.22/src/net/http/request.go rename to contrib/go/_std_1.23/src/net/http/request.go index 99fdebcf9bb8..ad1b5a620b07 100644 --- a/contrib/go/_std_1.22/src/net/http/request.go +++ b/contrib/go/_std_1.23/src/net/http/request.go @@ -25,6 +25,7 @@ import ( "strconv" "strings" "sync" + _ "unsafe" // for linkname "golang.org/x/net/http/httpguts" "golang.org/x/net/idna" @@ -320,6 +321,10 @@ type Request struct { // redirects. Response *Response + // Pattern is the [ServeMux] pattern that matched the request. + // It is empty if the request was not matched against a pattern. + Pattern string + // ctx is either the client or server context. It should only // be modified via copying the whole Request using Clone or WithContext. // It is unexported to prevent people from using Context wrong @@ -372,6 +377,8 @@ func (r *Request) WithContext(ctx context.Context) *Request { // Clone returns a deep copy of r with its context changed to ctx. // The provided ctx must be non-nil. // +// Clone only makes a shallow copy of the Body field. +// // For an outgoing client request, the context controls the entire // lifetime of a request and its response: obtaining a connection, // sending the request, and reading the response headers and body. @@ -431,6 +438,15 @@ func (r *Request) Cookies() []*Cookie { return readCookies(r.Header, "") } +// CookiesNamed parses and returns the named HTTP cookies sent with the request +// or an empty slice if none matched. +func (r *Request) CookiesNamed(name string) []*Cookie { + if name == "" { + return []*Cookie{} + } + return readCookies(r.Header, name) +} + // ErrNoCookie is returned by Request's Cookie method when a cookie is not found. var ErrNoCookie = errors.New("http: named cookie not present") @@ -455,7 +471,7 @@ func (r *Request) Cookie(name string) (*Cookie, error) { // AddCookie only sanitizes c's name and value, and does not sanitize // a Cookie header already present in the request. func (r *Request) AddCookie(c *Cookie) { - s := fmt.Sprintf("%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value)) + s := fmt.Sprintf("%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value, c.Quoted)) if c := r.Header.Get("Cookie"); c != "" { r.Header.Set("Cookie", c+"; "+s) } else { @@ -973,6 +989,16 @@ func (r *Request) BasicAuth() (username, password string, ok bool) { // parseBasicAuth parses an HTTP Basic Authentication string. // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true). +// +// parseBasicAuth should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname parseBasicAuth func parseBasicAuth(auth string) (username, password string, ok bool) { const prefix = "Basic " // Case insensitive prefix match. See Issue 22736. @@ -1048,6 +1074,17 @@ func ReadRequest(b *bufio.Reader) (*Request, error) { return req, err } +// readRequest should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// - github.com/v2fly/v2ray-core/v4 +// - github.com/v2fly/v2ray-core/v5 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname readRequest func readRequest(b *bufio.Reader) (req *Request, err error) { tp := newTextprotoReader(b) defer putTextprotoReader(tp) diff --git a/contrib/go/_std_1.22/src/net/http/response.go b/contrib/go/_std_1.23/src/net/http/response.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/response.go rename to contrib/go/_std_1.23/src/net/http/response.go diff --git a/contrib/go/_std_1.22/src/net/http/responsecontroller.go b/contrib/go/_std_1.23/src/net/http/responsecontroller.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/responsecontroller.go rename to contrib/go/_std_1.23/src/net/http/responsecontroller.go diff --git a/contrib/go/_std_1.23/src/net/http/roundtrip.go b/contrib/go/_std_1.23/src/net/http/roundtrip.go new file mode 100644 index 000000000000..6674b8419f3d --- /dev/null +++ b/contrib/go/_std_1.23/src/net/http/roundtrip.go @@ -0,0 +1,31 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !js + +package http + +import _ "unsafe" // for linkname + +// RoundTrip should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/erda-project/erda-infra +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname badRoundTrip net/http.(*Transport).RoundTrip +func badRoundTrip(*Transport, *Request) (*Response, error) + +// RoundTrip implements the [RoundTripper] interface. +// +// For higher-level HTTP client support (such as handling of cookies +// and redirects), see [Get], [Post], and the [Client] type. +// +// Like the RoundTripper interface, the error types returned +// by RoundTrip are unspecified. +func (t *Transport) RoundTrip(req *Request) (*Response, error) { + return t.roundTrip(req) +} diff --git a/contrib/go/_std_1.22/src/net/http/roundtrip_js.go b/contrib/go/_std_1.23/src/net/http/roundtrip_js.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/roundtrip_js.go rename to contrib/go/_std_1.23/src/net/http/roundtrip_js.go diff --git a/contrib/go/_std_1.22/src/net/http/routing_index.go b/contrib/go/_std_1.23/src/net/http/routing_index.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/routing_index.go rename to contrib/go/_std_1.23/src/net/http/routing_index.go diff --git a/contrib/go/_std_1.22/src/net/http/routing_tree.go b/contrib/go/_std_1.23/src/net/http/routing_tree.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/routing_tree.go rename to contrib/go/_std_1.23/src/net/http/routing_tree.go index 8812ed04e249..fdc58ab6924e 100644 --- a/contrib/go/_std_1.22/src/net/http/routing_tree.go +++ b/contrib/go/_std_1.23/src/net/http/routing_tree.go @@ -34,8 +34,8 @@ type routingNode struct { // special children keys: // "/" trailing slash (resulting from {$}) // "" single wildcard - // "*" multi wildcard children mapping[string, *routingNode] + multiChild *routingNode // child with multi wildcard emptyChild *routingNode // optimization: child with key "" } @@ -63,7 +63,9 @@ func (n *routingNode) addSegments(segs []segment, p *pattern, h Handler) { if len(segs) != 1 { panic("multi wildcard not last") } - n.addChild("*").set(p, h) + c := &routingNode{} + n.multiChild = c + c.set(p, h) } else if seg.wild { n.addChild("").addSegments(segs[1:], p, h) } else { @@ -185,7 +187,7 @@ func (n *routingNode) matchPath(path string, matches []string) (*routingNode, [] } // Lastly, match the pattern (there can be at most one) that has a multi // wildcard in this position to the rest of the path. - if c := n.findChild("*"); c != nil { + if c := n.multiChild; c != nil { // Don't record a match for a nameless wildcard (which arises from a // trailing slash in the pattern). if c.pattern.lastSegment().s != "" { diff --git a/contrib/go/_std_1.22/src/net/http/servemux121.go b/contrib/go/_std_1.23/src/net/http/servemux121.go similarity index 96% rename from contrib/go/_std_1.22/src/net/http/servemux121.go rename to contrib/go/_std_1.23/src/net/http/servemux121.go index c0a4b7701056..923a28fb4406 100644 --- a/contrib/go/_std_1.22/src/net/http/servemux121.go +++ b/contrib/go/_std_1.23/src/net/http/servemux121.go @@ -10,6 +10,10 @@ package http // Changes are minimal: aside from the different receiver type, // they mostly involve renaming functions, usually by unexporting them. +// servemux121.go exists solely to provide a snapshot of +// the pre-Go 1.22 ServeMux implementation for backwards compatibility. +// Do not modify this file, it should remain frozen. + import ( "internal/godebug" "net/url" diff --git a/contrib/go/_std_1.23/src/net/http/server.go b/contrib/go/_std_1.23/src/net/http/server.go new file mode 100644 index 000000000000..1ff72a04550c --- /dev/null +++ b/contrib/go/_std_1.23/src/net/http/server.go @@ -0,0 +1,3908 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// HTTP server. See RFC 7230 through 7235. + +package http + +import ( + "bufio" + "bytes" + "context" + "crypto/tls" + "errors" + "fmt" + "internal/godebug" + "io" + "log" + "maps" + "math/rand" + "net" + "net/textproto" + "net/url" + urlpkg "net/url" + "path" + "runtime" + "slices" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + _ "unsafe" // for linkname + + "golang.org/x/net/http/httpguts" +) + +// Errors used by the HTTP server. +var ( + // ErrBodyNotAllowed is returned by ResponseWriter.Write calls + // when the HTTP method or response code does not permit a + // body. + ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body") + + // ErrHijacked is returned by ResponseWriter.Write calls when + // the underlying connection has been hijacked using the + // Hijacker interface. A zero-byte write on a hijacked + // connection will return ErrHijacked without any other side + // effects. + ErrHijacked = errors.New("http: connection has been hijacked") + + // ErrContentLength is returned by ResponseWriter.Write calls + // when a Handler set a Content-Length response header with a + // declared size and then attempted to write more bytes than + // declared. + ErrContentLength = errors.New("http: wrote more than the declared Content-Length") + + // Deprecated: ErrWriteAfterFlush is no longer returned by + // anything in the net/http package. Callers should not + // compare errors against this variable. + ErrWriteAfterFlush = errors.New("unused") +) + +// A Handler responds to an HTTP request. +// +// [Handler.ServeHTTP] should write reply headers and data to the [ResponseWriter] +// and then return. Returning signals that the request is finished; it +// is not valid to use the [ResponseWriter] or read from the +// [Request.Body] after or concurrently with the completion of the +// ServeHTTP call. +// +// Depending on the HTTP client software, HTTP protocol version, and +// any intermediaries between the client and the Go server, it may not +// be possible to read from the [Request.Body] after writing to the +// [ResponseWriter]. Cautious handlers should read the [Request.Body] +// first, and then reply. +// +// Except for reading the body, handlers should not modify the +// provided Request. +// +// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes +// that the effect of the panic was isolated to the active request. +// It recovers the panic, logs a stack trace to the server error log, +// and either closes the network connection or sends an HTTP/2 +// RST_STREAM, depending on the HTTP protocol. To abort a handler so +// the client sees an interrupted response but the server doesn't log +// an error, panic with the value [ErrAbortHandler]. +type Handler interface { + ServeHTTP(ResponseWriter, *Request) +} + +// A ResponseWriter interface is used by an HTTP handler to +// construct an HTTP response. +// +// A ResponseWriter may not be used after [Handler.ServeHTTP] has returned. +type ResponseWriter interface { + // Header returns the header map that will be sent by + // [ResponseWriter.WriteHeader]. The [Header] map also is the mechanism with which + // [Handler] implementations can set HTTP trailers. + // + // Changing the header map after a call to [ResponseWriter.WriteHeader] (or + // [ResponseWriter.Write]) has no effect unless the HTTP status code was of the + // 1xx class or the modified headers are trailers. + // + // There are two ways to set Trailers. The preferred way is to + // predeclare in the headers which trailers you will later + // send by setting the "Trailer" header to the names of the + // trailer keys which will come later. In this case, those + // keys of the Header map are treated as if they were + // trailers. See the example. The second way, for trailer + // keys not known to the [Handler] until after the first [ResponseWriter.Write], + // is to prefix the [Header] map keys with the [TrailerPrefix] + // constant value. + // + // To suppress automatic response headers (such as "Date"), set + // their value to nil. + Header() Header + + // Write writes the data to the connection as part of an HTTP reply. + // + // If [ResponseWriter.WriteHeader] has not yet been called, Write calls + // WriteHeader(http.StatusOK) before writing the data. If the Header + // does not contain a Content-Type line, Write adds a Content-Type set + // to the result of passing the initial 512 bytes of written data to + // [DetectContentType]. Additionally, if the total size of all written + // data is under a few KB and there are no Flush calls, the + // Content-Length header is added automatically. + // + // Depending on the HTTP protocol version and the client, calling + // Write or WriteHeader may prevent future reads on the + // Request.Body. For HTTP/1.x requests, handlers should read any + // needed request body data before writing the response. Once the + // headers have been flushed (due to either an explicit Flusher.Flush + // call or writing enough data to trigger a flush), the request body + // may be unavailable. For HTTP/2 requests, the Go HTTP server permits + // handlers to continue to read the request body while concurrently + // writing the response. However, such behavior may not be supported + // by all HTTP/2 clients. Handlers should read before writing if + // possible to maximize compatibility. + Write([]byte) (int, error) + + // WriteHeader sends an HTTP response header with the provided + // status code. + // + // If WriteHeader is not called explicitly, the first call to Write + // will trigger an implicit WriteHeader(http.StatusOK). + // Thus explicit calls to WriteHeader are mainly used to + // send error codes or 1xx informational responses. + // + // The provided code must be a valid HTTP 1xx-5xx status code. + // Any number of 1xx headers may be written, followed by at most + // one 2xx-5xx header. 1xx headers are sent immediately, but 2xx-5xx + // headers may be buffered. Use the Flusher interface to send + // buffered data. The header map is cleared when 2xx-5xx headers are + // sent, but not with 1xx headers. + // + // The server will automatically send a 100 (Continue) header + // on the first read from the request body if the request has + // an "Expect: 100-continue" header. + WriteHeader(statusCode int) +} + +// The Flusher interface is implemented by ResponseWriters that allow +// an HTTP handler to flush buffered data to the client. +// +// The default HTTP/1.x and HTTP/2 [ResponseWriter] implementations +// support [Flusher], but ResponseWriter wrappers may not. Handlers +// should always test for this ability at runtime. +// +// Note that even for ResponseWriters that support Flush, +// if the client is connected through an HTTP proxy, +// the buffered data may not reach the client until the response +// completes. +type Flusher interface { + // Flush sends any buffered data to the client. + Flush() +} + +// The Hijacker interface is implemented by ResponseWriters that allow +// an HTTP handler to take over the connection. +// +// The default [ResponseWriter] for HTTP/1.x connections supports +// Hijacker, but HTTP/2 connections intentionally do not. +// ResponseWriter wrappers may also not support Hijacker. Handlers +// should always test for this ability at runtime. +type Hijacker interface { + // Hijack lets the caller take over the connection. + // After a call to Hijack the HTTP server library + // will not do anything else with the connection. + // + // It becomes the caller's responsibility to manage + // and close the connection. + // + // The returned net.Conn may have read or write deadlines + // already set, depending on the configuration of the + // Server. It is the caller's responsibility to set + // or clear those deadlines as needed. + // + // The returned bufio.Reader may contain unprocessed buffered + // data from the client. + // + // After a call to Hijack, the original Request.Body must not + // be used. The original Request's Context remains valid and + // is not canceled until the Request's ServeHTTP method + // returns. + Hijack() (net.Conn, *bufio.ReadWriter, error) +} + +// The CloseNotifier interface is implemented by ResponseWriters which +// allow detecting when the underlying connection has gone away. +// +// This mechanism can be used to cancel long operations on the server +// if the client has disconnected before the response is ready. +// +// Deprecated: the CloseNotifier interface predates Go's context package. +// New code should use [Request.Context] instead. +type CloseNotifier interface { + // CloseNotify returns a channel that receives at most a + // single value (true) when the client connection has gone + // away. + // + // CloseNotify may wait to notify until Request.Body has been + // fully read. + // + // After the Handler has returned, there is no guarantee + // that the channel receives a value. + // + // If the protocol is HTTP/1.1 and CloseNotify is called while + // processing an idempotent request (such as GET) while + // HTTP/1.1 pipelining is in use, the arrival of a subsequent + // pipelined request may cause a value to be sent on the + // returned channel. In practice HTTP/1.1 pipelining is not + // enabled in browsers and not seen often in the wild. If this + // is a problem, use HTTP/2 or only use CloseNotify on methods + // such as POST. + CloseNotify() <-chan bool +} + +var ( + // ServerContextKey is a context key. It can be used in HTTP + // handlers with Context.Value to access the server that + // started the handler. The associated value will be of + // type *Server. + ServerContextKey = &contextKey{"http-server"} + + // LocalAddrContextKey is a context key. It can be used in + // HTTP handlers with Context.Value to access the local + // address the connection arrived on. + // The associated value will be of type net.Addr. + LocalAddrContextKey = &contextKey{"local-addr"} +) + +// A conn represents the server side of an HTTP connection. +type conn struct { + // server is the server on which the connection arrived. + // Immutable; never nil. + server *Server + + // cancelCtx cancels the connection-level context. + cancelCtx context.CancelFunc + + // rwc is the underlying network connection. + // This is never wrapped by other types and is the value given out + // to CloseNotifier callers. It is usually of type *net.TCPConn or + // *tls.Conn. + rwc net.Conn + + // remoteAddr is rwc.RemoteAddr().String(). It is not populated synchronously + // inside the Listener's Accept goroutine, as some implementations block. + // It is populated immediately inside the (*conn).serve goroutine. + // This is the value of a Handler's (*Request).RemoteAddr. + remoteAddr string + + // tlsState is the TLS connection state when using TLS. + // nil means not TLS. + tlsState *tls.ConnectionState + + // werr is set to the first write error to rwc. + // It is set via checkConnErrorWriter{w}, where bufw writes. + werr error + + // r is bufr's read source. It's a wrapper around rwc that provides + // io.LimitedReader-style limiting (while reading request headers) + // and functionality to support CloseNotifier. See *connReader docs. + r *connReader + + // bufr reads from r. + bufr *bufio.Reader + + // bufw writes to checkConnErrorWriter{c}, which populates werr on error. + bufw *bufio.Writer + + // lastMethod is the method of the most recent request + // on this connection, if any. + lastMethod string + + curReq atomic.Pointer[response] // (which has a Request in it) + + curState atomic.Uint64 // packed (unixtime<<8|uint8(ConnState)) + + // mu guards hijackedv + mu sync.Mutex + + // hijackedv is whether this connection has been hijacked + // by a Handler with the Hijacker interface. + // It is guarded by mu. + hijackedv bool +} + +func (c *conn) hijacked() bool { + c.mu.Lock() + defer c.mu.Unlock() + return c.hijackedv +} + +// c.mu must be held. +func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) { + if c.hijackedv { + return nil, nil, ErrHijacked + } + c.r.abortPendingRead() + + c.hijackedv = true + rwc = c.rwc + rwc.SetDeadline(time.Time{}) + + buf = bufio.NewReadWriter(c.bufr, bufio.NewWriter(rwc)) + if c.r.hasByte { + if _, err := c.bufr.Peek(c.bufr.Buffered() + 1); err != nil { + return nil, nil, fmt.Errorf("unexpected Peek failure reading buffered byte: %v", err) + } + } + c.setState(rwc, StateHijacked, runHooks) + return +} + +// This should be >= 512 bytes for DetectContentType, +// but otherwise it's somewhat arbitrary. +const bufferBeforeChunkingSize = 2048 + +// chunkWriter writes to a response's conn buffer, and is the writer +// wrapped by the response.w buffered writer. +// +// chunkWriter also is responsible for finalizing the Header, including +// conditionally setting the Content-Type and setting a Content-Length +// in cases where the handler's final output is smaller than the buffer +// size. It also conditionally adds chunk headers, when in chunking mode. +// +// See the comment above (*response).Write for the entire write flow. +type chunkWriter struct { + res *response + + // header is either nil or a deep clone of res.handlerHeader + // at the time of res.writeHeader, if res.writeHeader is + // called and extra buffering is being done to calculate + // Content-Type and/or Content-Length. + header Header + + // wroteHeader tells whether the header's been written to "the + // wire" (or rather: w.conn.buf). this is unlike + // (*response).wroteHeader, which tells only whether it was + // logically written. + wroteHeader bool + + // set by the writeHeader method: + chunking bool // using chunked transfer encoding for reply body +} + +var ( + crlf = []byte("\r\n") + colonSpace = []byte(": ") +) + +func (cw *chunkWriter) Write(p []byte) (n int, err error) { + if !cw.wroteHeader { + cw.writeHeader(p) + } + if cw.res.req.Method == "HEAD" { + // Eat writes. + return len(p), nil + } + if cw.chunking { + _, err = fmt.Fprintf(cw.res.conn.bufw, "%x\r\n", len(p)) + if err != nil { + cw.res.conn.rwc.Close() + return + } + } + n, err = cw.res.conn.bufw.Write(p) + if cw.chunking && err == nil { + _, err = cw.res.conn.bufw.Write(crlf) + } + if err != nil { + cw.res.conn.rwc.Close() + } + return +} + +func (cw *chunkWriter) flush() error { + if !cw.wroteHeader { + cw.writeHeader(nil) + } + return cw.res.conn.bufw.Flush() +} + +func (cw *chunkWriter) close() { + if !cw.wroteHeader { + cw.writeHeader(nil) + } + if cw.chunking { + bw := cw.res.conn.bufw // conn's bufio writer + // zero chunk to mark EOF + bw.WriteString("0\r\n") + if trailers := cw.res.finalTrailers(); trailers != nil { + trailers.Write(bw) // the writer handles noting errors + } + // final blank line after the trailers (whether + // present or not) + bw.WriteString("\r\n") + } +} + +// A response represents the server side of an HTTP response. +type response struct { + conn *conn + req *Request // request for this response + reqBody io.ReadCloser + cancelCtx context.CancelFunc // when ServeHTTP exits + wroteHeader bool // a non-1xx header has been (logically) written + wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive" + wantsClose bool // HTTP request has Connection "close" + + // canWriteContinue is an atomic boolean that says whether or + // not a 100 Continue header can be written to the + // connection. + // writeContinueMu must be held while writing the header. + // These two fields together synchronize the body reader (the + // expectContinueReader, which wants to write 100 Continue) + // against the main writer. + writeContinueMu sync.Mutex + canWriteContinue atomic.Bool + + w *bufio.Writer // buffers output in chunks to chunkWriter + cw chunkWriter + + // handlerHeader is the Header that Handlers get access to, + // which may be retained and mutated even after WriteHeader. + // handlerHeader is copied into cw.header at WriteHeader + // time, and privately mutated thereafter. + handlerHeader Header + calledHeader bool // handler accessed handlerHeader via Header + + written int64 // number of bytes written in body + contentLength int64 // explicitly-declared Content-Length; or -1 + status int // status code passed to WriteHeader + + // close connection after this reply. set on request and + // updated after response from handler if there's a + // "Connection: keep-alive" response header and a + // Content-Length. + closeAfterReply bool + + // When fullDuplex is false (the default), we consume any remaining + // request body before starting to write a response. + fullDuplex bool + + // requestBodyLimitHit is set by requestTooLarge when + // maxBytesReader hits its max size. It is checked in + // WriteHeader, to make sure we don't consume the + // remaining request body to try to advance to the next HTTP + // request. Instead, when this is set, we stop reading + // subsequent requests on this connection and stop reading + // input from it. + requestBodyLimitHit bool + + // trailers are the headers to be sent after the handler + // finishes writing the body. This field is initialized from + // the Trailer response header when the response header is + // written. + trailers []string + + handlerDone atomic.Bool // set true when the handler exits + + // Buffers for Date, Content-Length, and status code + dateBuf [len(TimeFormat)]byte + clenBuf [10]byte + statusBuf [3]byte + + // closeNotifyCh is the channel returned by CloseNotify. + // TODO(bradfitz): this is currently (for Go 1.8) always + // non-nil. Make this lazily-created again as it used to be? + closeNotifyCh chan bool + didCloseNotify atomic.Bool // atomic (only false->true winner should send) +} + +func (c *response) SetReadDeadline(deadline time.Time) error { + return c.conn.rwc.SetReadDeadline(deadline) +} + +func (c *response) SetWriteDeadline(deadline time.Time) error { + return c.conn.rwc.SetWriteDeadline(deadline) +} + +func (c *response) EnableFullDuplex() error { + c.fullDuplex = true + return nil +} + +// TrailerPrefix is a magic prefix for [ResponseWriter.Header] map keys +// that, if present, signals that the map entry is actually for +// the response trailers, and not the response headers. The prefix +// is stripped after the ServeHTTP call finishes and the values are +// sent in the trailers. +// +// This mechanism is intended only for trailers that are not known +// prior to the headers being written. If the set of trailers is fixed +// or known before the header is written, the normal Go trailers mechanism +// is preferred: +// +// https://pkg.go.dev/net/http#ResponseWriter +// https://pkg.go.dev/net/http#example-ResponseWriter-Trailers +const TrailerPrefix = "Trailer:" + +// finalTrailers is called after the Handler exits and returns a non-nil +// value if the Handler set any trailers. +func (w *response) finalTrailers() Header { + var t Header + for k, vv := range w.handlerHeader { + if kk, found := strings.CutPrefix(k, TrailerPrefix); found { + if t == nil { + t = make(Header) + } + t[kk] = vv + } + } + for _, k := range w.trailers { + if t == nil { + t = make(Header) + } + for _, v := range w.handlerHeader[k] { + t.Add(k, v) + } + } + return t +} + +// declareTrailer is called for each Trailer header when the +// response header is written. It notes that a header will need to be +// written in the trailers at the end of the response. +func (w *response) declareTrailer(k string) { + k = CanonicalHeaderKey(k) + if !httpguts.ValidTrailerHeader(k) { + // Forbidden by RFC 7230, section 4.1.2 + return + } + w.trailers = append(w.trailers, k) +} + +// requestTooLarge is called by maxBytesReader when too much input has +// been read from the client. +func (w *response) requestTooLarge() { + w.closeAfterReply = true + w.requestBodyLimitHit = true + if !w.wroteHeader { + w.Header().Set("Connection", "close") + } +} + +// disableWriteContinue stops Request.Body.Read from sending an automatic 100-Continue. +// If a 100-Continue is being written, it waits for it to complete before continuing. +func (w *response) disableWriteContinue() { + w.writeContinueMu.Lock() + w.canWriteContinue.Store(false) + w.writeContinueMu.Unlock() +} + +// writerOnly hides an io.Writer value's optional ReadFrom method +// from io.Copy. +type writerOnly struct { + io.Writer +} + +// ReadFrom is here to optimize copying from an [*os.File] regular file +// to a [*net.TCPConn] with sendfile, or from a supported src type such +// as a *net.TCPConn on Linux with splice. +func (w *response) ReadFrom(src io.Reader) (n int64, err error) { + buf := getCopyBuf() + defer putCopyBuf(buf) + + // Our underlying w.conn.rwc is usually a *TCPConn (with its + // own ReadFrom method). If not, just fall back to the normal + // copy method. + rf, ok := w.conn.rwc.(io.ReaderFrom) + if !ok { + return io.CopyBuffer(writerOnly{w}, src, buf) + } + + // Copy the first sniffLen bytes before switching to ReadFrom. + // This ensures we don't start writing the response before the + // source is available (see golang.org/issue/5660) and provides + // enough bytes to perform Content-Type sniffing when required. + if !w.cw.wroteHeader { + n0, err := io.CopyBuffer(writerOnly{w}, io.LimitReader(src, sniffLen), buf) + n += n0 + if err != nil || n0 < sniffLen { + return n, err + } + } + + w.w.Flush() // get rid of any previous writes + w.cw.flush() // make sure Header is written; flush data to rwc + + // Now that cw has been flushed, its chunking field is guaranteed initialized. + if !w.cw.chunking && w.bodyAllowed() { + n0, err := rf.ReadFrom(src) + n += n0 + w.written += n0 + return n, err + } + + n0, err := io.CopyBuffer(writerOnly{w}, src, buf) + n += n0 + return n, err +} + +// debugServerConnections controls whether all server connections are wrapped +// with a verbose logging wrapper. +const debugServerConnections = false + +// Create new connection from rwc. +func (srv *Server) newConn(rwc net.Conn) *conn { + c := &conn{ + server: srv, + rwc: rwc, + } + if debugServerConnections { + c.rwc = newLoggingConn("server", c.rwc) + } + return c +} + +type readResult struct { + _ incomparable + n int + err error + b byte // byte read, if n == 1 +} + +// connReader is the io.Reader wrapper used by *conn. It combines a +// selectively-activated io.LimitedReader (to bound request header +// read sizes) with support for selectively keeping an io.Reader.Read +// call blocked in a background goroutine to wait for activity and +// trigger a CloseNotifier channel. +type connReader struct { + conn *conn + + mu sync.Mutex // guards following + hasByte bool + byteBuf [1]byte + cond *sync.Cond + inRead bool + aborted bool // set true before conn.rwc deadline is set to past + remain int64 // bytes remaining +} + +func (cr *connReader) lock() { + cr.mu.Lock() + if cr.cond == nil { + cr.cond = sync.NewCond(&cr.mu) + } +} + +func (cr *connReader) unlock() { cr.mu.Unlock() } + +func (cr *connReader) startBackgroundRead() { + cr.lock() + defer cr.unlock() + if cr.inRead { + panic("invalid concurrent Body.Read call") + } + if cr.hasByte { + return + } + cr.inRead = true + cr.conn.rwc.SetReadDeadline(time.Time{}) + go cr.backgroundRead() +} + +func (cr *connReader) backgroundRead() { + n, err := cr.conn.rwc.Read(cr.byteBuf[:]) + cr.lock() + if n == 1 { + cr.hasByte = true + // We were past the end of the previous request's body already + // (since we wouldn't be in a background read otherwise), so + // this is a pipelined HTTP request. Prior to Go 1.11 we used to + // send on the CloseNotify channel and cancel the context here, + // but the behavior was documented as only "may", and we only + // did that because that's how CloseNotify accidentally behaved + // in very early Go releases prior to context support. Once we + // added context support, people used a Handler's + // Request.Context() and passed it along. Having that context + // cancel on pipelined HTTP requests caused problems. + // Fortunately, almost nothing uses HTTP/1.x pipelining. + // Unfortunately, apt-get does, or sometimes does. + // New Go 1.11 behavior: don't fire CloseNotify or cancel + // contexts on pipelined requests. Shouldn't affect people, but + // fixes cases like Issue 23921. This does mean that a client + // closing their TCP connection after sending a pipelined + // request won't cancel the context, but we'll catch that on any + // write failure (in checkConnErrorWriter.Write). + // If the server never writes, yes, there are still contrived + // server & client behaviors where this fails to ever cancel the + // context, but that's kinda why HTTP/1.x pipelining died + // anyway. + } + if ne, ok := err.(net.Error); ok && cr.aborted && ne.Timeout() { + // Ignore this error. It's the expected error from + // another goroutine calling abortPendingRead. + } else if err != nil { + cr.handleReadError(err) + } + cr.aborted = false + cr.inRead = false + cr.unlock() + cr.cond.Broadcast() +} + +func (cr *connReader) abortPendingRead() { + cr.lock() + defer cr.unlock() + if !cr.inRead { + return + } + cr.aborted = true + cr.conn.rwc.SetReadDeadline(aLongTimeAgo) + for cr.inRead { + cr.cond.Wait() + } + cr.conn.rwc.SetReadDeadline(time.Time{}) +} + +func (cr *connReader) setReadLimit(remain int64) { cr.remain = remain } +func (cr *connReader) setInfiniteReadLimit() { cr.remain = maxInt64 } +func (cr *connReader) hitReadLimit() bool { return cr.remain <= 0 } + +// handleReadError is called whenever a Read from the client returns a +// non-nil error. +// +// The provided non-nil err is almost always io.EOF or a "use of +// closed network connection". In any case, the error is not +// particularly interesting, except perhaps for debugging during +// development. Any error means the connection is dead and we should +// down its context. +// +// It may be called from multiple goroutines. +func (cr *connReader) handleReadError(_ error) { + cr.conn.cancelCtx() + cr.closeNotify() +} + +// may be called from multiple goroutines. +func (cr *connReader) closeNotify() { + res := cr.conn.curReq.Load() + if res != nil && !res.didCloseNotify.Swap(true) { + res.closeNotifyCh <- true + } +} + +func (cr *connReader) Read(p []byte) (n int, err error) { + cr.lock() + if cr.inRead { + cr.unlock() + if cr.conn.hijacked() { + panic("invalid Body.Read call. After hijacked, the original Request must not be used") + } + panic("invalid concurrent Body.Read call") + } + if cr.hitReadLimit() { + cr.unlock() + return 0, io.EOF + } + if len(p) == 0 { + cr.unlock() + return 0, nil + } + if int64(len(p)) > cr.remain { + p = p[:cr.remain] + } + if cr.hasByte { + p[0] = cr.byteBuf[0] + cr.hasByte = false + cr.unlock() + return 1, nil + } + cr.inRead = true + cr.unlock() + n, err = cr.conn.rwc.Read(p) + + cr.lock() + cr.inRead = false + if err != nil { + cr.handleReadError(err) + } + cr.remain -= int64(n) + cr.unlock() + + cr.cond.Broadcast() + return n, err +} + +var ( + bufioReaderPool sync.Pool + bufioWriter2kPool sync.Pool + bufioWriter4kPool sync.Pool +) + +const copyBufPoolSize = 32 * 1024 + +var copyBufPool = sync.Pool{New: func() any { return new([copyBufPoolSize]byte) }} + +func getCopyBuf() []byte { + return copyBufPool.Get().(*[copyBufPoolSize]byte)[:] +} +func putCopyBuf(b []byte) { + if len(b) != copyBufPoolSize { + panic("trying to put back buffer of the wrong size in the copyBufPool") + } + copyBufPool.Put((*[copyBufPoolSize]byte)(b)) +} + +func bufioWriterPool(size int) *sync.Pool { + switch size { + case 2 << 10: + return &bufioWriter2kPool + case 4 << 10: + return &bufioWriter4kPool + } + return nil +} + +// newBufioReader should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/gobwas/ws +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname newBufioReader +func newBufioReader(r io.Reader) *bufio.Reader { + if v := bufioReaderPool.Get(); v != nil { + br := v.(*bufio.Reader) + br.Reset(r) + return br + } + // Note: if this reader size is ever changed, update + // TestHandlerBodyClose's assumptions. + return bufio.NewReader(r) +} + +// putBufioReader should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/gobwas/ws +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname putBufioReader +func putBufioReader(br *bufio.Reader) { + br.Reset(nil) + bufioReaderPool.Put(br) +} + +// newBufioWriterSize should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/gobwas/ws +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname newBufioWriterSize +func newBufioWriterSize(w io.Writer, size int) *bufio.Writer { + pool := bufioWriterPool(size) + if pool != nil { + if v := pool.Get(); v != nil { + bw := v.(*bufio.Writer) + bw.Reset(w) + return bw + } + } + return bufio.NewWriterSize(w, size) +} + +// putBufioWriter should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/gobwas/ws +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname putBufioWriter +func putBufioWriter(bw *bufio.Writer) { + bw.Reset(nil) + if pool := bufioWriterPool(bw.Available()); pool != nil { + pool.Put(bw) + } +} + +// DefaultMaxHeaderBytes is the maximum permitted size of the headers +// in an HTTP request. +// This can be overridden by setting [Server.MaxHeaderBytes]. +const DefaultMaxHeaderBytes = 1 << 20 // 1 MB + +func (srv *Server) maxHeaderBytes() int { + if srv.MaxHeaderBytes > 0 { + return srv.MaxHeaderBytes + } + return DefaultMaxHeaderBytes +} + +func (srv *Server) initialReadLimitSize() int64 { + return int64(srv.maxHeaderBytes()) + 4096 // bufio slop +} + +// tlsHandshakeTimeout returns the time limit permitted for the TLS +// handshake, or zero for unlimited. +// +// It returns the minimum of any positive ReadHeaderTimeout, +// ReadTimeout, or WriteTimeout. +func (srv *Server) tlsHandshakeTimeout() time.Duration { + var ret time.Duration + for _, v := range [...]time.Duration{ + srv.ReadHeaderTimeout, + srv.ReadTimeout, + srv.WriteTimeout, + } { + if v <= 0 { + continue + } + if ret == 0 || v < ret { + ret = v + } + } + return ret +} + +// wrapper around io.ReadCloser which on first read, sends an +// HTTP/1.1 100 Continue header +type expectContinueReader struct { + resp *response + readCloser io.ReadCloser + closed atomic.Bool + sawEOF atomic.Bool +} + +func (ecr *expectContinueReader) Read(p []byte) (n int, err error) { + if ecr.closed.Load() { + return 0, ErrBodyReadAfterClose + } + w := ecr.resp + if w.canWriteContinue.Load() { + w.writeContinueMu.Lock() + if w.canWriteContinue.Load() { + w.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n") + w.conn.bufw.Flush() + w.canWriteContinue.Store(false) + } + w.writeContinueMu.Unlock() + } + n, err = ecr.readCloser.Read(p) + if err == io.EOF { + ecr.sawEOF.Store(true) + } + return +} + +func (ecr *expectContinueReader) Close() error { + ecr.closed.Store(true) + return ecr.readCloser.Close() +} + +// TimeFormat is the time format to use when generating times in HTTP +// headers. It is like [time.RFC1123] but hard-codes GMT as the time +// zone. The time being formatted must be in UTC for Format to +// generate the correct format. +// +// For parsing this time format, see [ParseTime]. +const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" + +// appendTime is a non-allocating version of []byte(t.UTC().Format(TimeFormat)) +func appendTime(b []byte, t time.Time) []byte { + const days = "SunMonTueWedThuFriSat" + const months = "JanFebMarAprMayJunJulAugSepOctNovDec" + + t = t.UTC() + yy, mm, dd := t.Date() + hh, mn, ss := t.Clock() + day := days[3*t.Weekday():] + mon := months[3*(mm-1):] + + return append(b, + day[0], day[1], day[2], ',', ' ', + byte('0'+dd/10), byte('0'+dd%10), ' ', + mon[0], mon[1], mon[2], ' ', + byte('0'+yy/1000), byte('0'+(yy/100)%10), byte('0'+(yy/10)%10), byte('0'+yy%10), ' ', + byte('0'+hh/10), byte('0'+hh%10), ':', + byte('0'+mn/10), byte('0'+mn%10), ':', + byte('0'+ss/10), byte('0'+ss%10), ' ', + 'G', 'M', 'T') +} + +var errTooLarge = errors.New("http: request too large") + +// Read next request from connection. +func (c *conn) readRequest(ctx context.Context) (w *response, err error) { + if c.hijacked() { + return nil, ErrHijacked + } + + var ( + wholeReqDeadline time.Time // or zero if none + hdrDeadline time.Time // or zero if none + ) + t0 := time.Now() + if d := c.server.readHeaderTimeout(); d > 0 { + hdrDeadline = t0.Add(d) + } + if d := c.server.ReadTimeout; d > 0 { + wholeReqDeadline = t0.Add(d) + } + c.rwc.SetReadDeadline(hdrDeadline) + if d := c.server.WriteTimeout; d > 0 { + defer func() { + c.rwc.SetWriteDeadline(time.Now().Add(d)) + }() + } + + c.r.setReadLimit(c.server.initialReadLimitSize()) + if c.lastMethod == "POST" { + // RFC 7230 section 3 tolerance for old buggy clients. + peek, _ := c.bufr.Peek(4) // ReadRequest will get err below + c.bufr.Discard(numLeadingCRorLF(peek)) + } + req, err := readRequest(c.bufr) + if err != nil { + if c.r.hitReadLimit() { + return nil, errTooLarge + } + return nil, err + } + + if !http1ServerSupportsRequest(req) { + return nil, statusError{StatusHTTPVersionNotSupported, "unsupported protocol version"} + } + + c.lastMethod = req.Method + c.r.setInfiniteReadLimit() + + hosts, haveHost := req.Header["Host"] + isH2Upgrade := req.isH2Upgrade() + if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade && req.Method != "CONNECT" { + return nil, badRequestError("missing required Host header") + } + if len(hosts) == 1 && !httpguts.ValidHostHeader(hosts[0]) { + return nil, badRequestError("malformed Host header") + } + for k, vv := range req.Header { + if !httpguts.ValidHeaderFieldName(k) { + return nil, badRequestError("invalid header name") + } + for _, v := range vv { + if !httpguts.ValidHeaderFieldValue(v) { + return nil, badRequestError("invalid header value") + } + } + } + delete(req.Header, "Host") + + ctx, cancelCtx := context.WithCancel(ctx) + req.ctx = ctx + req.RemoteAddr = c.remoteAddr + req.TLS = c.tlsState + if body, ok := req.Body.(*body); ok { + body.doEarlyClose = true + } + + // Adjust the read deadline if necessary. + if !hdrDeadline.Equal(wholeReqDeadline) { + c.rwc.SetReadDeadline(wholeReqDeadline) + } + + w = &response{ + conn: c, + cancelCtx: cancelCtx, + req: req, + reqBody: req.Body, + handlerHeader: make(Header), + contentLength: -1, + closeNotifyCh: make(chan bool, 1), + + // We populate these ahead of time so we're not + // reading from req.Header after their Handler starts + // and maybe mutates it (Issue 14940) + wants10KeepAlive: req.wantsHttp10KeepAlive(), + wantsClose: req.wantsClose(), + } + if isH2Upgrade { + w.closeAfterReply = true + } + w.cw.res = w + w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize) + return w, nil +} + +// http1ServerSupportsRequest reports whether Go's HTTP/1.x server +// supports the given request. +func http1ServerSupportsRequest(req *Request) bool { + if req.ProtoMajor == 1 { + return true + } + // Accept "PRI * HTTP/2.0" upgrade requests, so Handlers can + // wire up their own HTTP/2 upgrades. + if req.ProtoMajor == 2 && req.ProtoMinor == 0 && + req.Method == "PRI" && req.RequestURI == "*" { + return true + } + // Reject HTTP/0.x, and all other HTTP/2+ requests (which + // aren't encoded in ASCII anyway). + return false +} + +func (w *response) Header() Header { + if w.cw.header == nil && w.wroteHeader && !w.cw.wroteHeader { + // Accessing the header between logically writing it + // and physically writing it means we need to allocate + // a clone to snapshot the logically written state. + w.cw.header = w.handlerHeader.Clone() + } + w.calledHeader = true + return w.handlerHeader +} + +// maxPostHandlerReadBytes is the max number of Request.Body bytes not +// consumed by a handler that the server will read from the client +// in order to keep a connection alive. If there are more bytes +// than this, the server, to be paranoid, instead sends a +// "Connection close" response. +// +// This number is approximately what a typical machine's TCP buffer +// size is anyway. (if we have the bytes on the machine, we might as +// well read them) +const maxPostHandlerReadBytes = 256 << 10 + +func checkWriteHeaderCode(code int) { + // Issue 22880: require valid WriteHeader status codes. + // For now we only enforce that it's three digits. + // In the future we might block things over 599 (600 and above aren't defined + // at https://httpwg.org/specs/rfc7231.html#status.codes). + // But for now any three digits. + // + // We used to send "HTTP/1.1 000 0" on the wire in responses but there's + // no equivalent bogus thing we can realistically send in HTTP/2, + // so we'll consistently panic instead and help people find their bugs + // early. (We can't return an error from WriteHeader even if we wanted to.) + if code < 100 || code > 999 { + panic(fmt.Sprintf("invalid WriteHeader code %v", code)) + } +} + +// relevantCaller searches the call stack for the first function outside of net/http. +// The purpose of this function is to provide more helpful error messages. +func relevantCaller() runtime.Frame { + pc := make([]uintptr, 16) + n := runtime.Callers(1, pc) + frames := runtime.CallersFrames(pc[:n]) + var frame runtime.Frame + for { + frame, more := frames.Next() + if !strings.HasPrefix(frame.Function, "net/http.") { + return frame + } + if !more { + break + } + } + return frame +} + +func (w *response) WriteHeader(code int) { + if w.conn.hijacked() { + caller := relevantCaller() + w.conn.server.logf("http: response.WriteHeader on hijacked connection from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line) + return + } + if w.wroteHeader { + caller := relevantCaller() + w.conn.server.logf("http: superfluous response.WriteHeader call from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line) + return + } + checkWriteHeaderCode(code) + + if code < 101 || code > 199 { + // Sending a 100 Continue or any non-1xx header disables the + // automatically-sent 100 Continue from Request.Body.Read. + w.disableWriteContinue() + } + + // Handle informational headers. + // + // We shouldn't send any further headers after 101 Switching Protocols, + // so it takes the non-informational path. + if code >= 100 && code <= 199 && code != StatusSwitchingProtocols { + writeStatusLine(w.conn.bufw, w.req.ProtoAtLeast(1, 1), code, w.statusBuf[:]) + + // Per RFC 8297 we must not clear the current header map + w.handlerHeader.WriteSubset(w.conn.bufw, excludedHeadersNoBody) + w.conn.bufw.Write(crlf) + w.conn.bufw.Flush() + + return + } + + w.wroteHeader = true + w.status = code + + if w.calledHeader && w.cw.header == nil { + w.cw.header = w.handlerHeader.Clone() + } + + if cl := w.handlerHeader.get("Content-Length"); cl != "" { + v, err := strconv.ParseInt(cl, 10, 64) + if err == nil && v >= 0 { + w.contentLength = v + } else { + w.conn.server.logf("http: invalid Content-Length of %q", cl) + w.handlerHeader.Del("Content-Length") + } + } +} + +// extraHeader is the set of headers sometimes added by chunkWriter.writeHeader. +// This type is used to avoid extra allocations from cloning and/or populating +// the response Header map and all its 1-element slices. +type extraHeader struct { + contentType string + connection string + transferEncoding string + date []byte // written if not nil + contentLength []byte // written if not nil +} + +// Sorted the same as extraHeader.Write's loop. +var extraHeaderKeys = [][]byte{ + []byte("Content-Type"), + []byte("Connection"), + []byte("Transfer-Encoding"), +} + +var ( + headerContentLength = []byte("Content-Length: ") + headerDate = []byte("Date: ") +) + +// Write writes the headers described in h to w. +// +// This method has a value receiver, despite the somewhat large size +// of h, because it prevents an allocation. The escape analysis isn't +// smart enough to realize this function doesn't mutate h. +func (h extraHeader) Write(w *bufio.Writer) { + if h.date != nil { + w.Write(headerDate) + w.Write(h.date) + w.Write(crlf) + } + if h.contentLength != nil { + w.Write(headerContentLength) + w.Write(h.contentLength) + w.Write(crlf) + } + for i, v := range []string{h.contentType, h.connection, h.transferEncoding} { + if v != "" { + w.Write(extraHeaderKeys[i]) + w.Write(colonSpace) + w.WriteString(v) + w.Write(crlf) + } + } +} + +// writeHeader finalizes the header sent to the client and writes it +// to cw.res.conn.bufw. +// +// p is not written by writeHeader, but is the first chunk of the body +// that will be written. It is sniffed for a Content-Type if none is +// set explicitly. It's also used to set the Content-Length, if the +// total body size was small and the handler has already finished +// running. +func (cw *chunkWriter) writeHeader(p []byte) { + if cw.wroteHeader { + return + } + cw.wroteHeader = true + + w := cw.res + keepAlivesEnabled := w.conn.server.doKeepAlives() + isHEAD := w.req.Method == "HEAD" + + // header is written out to w.conn.buf below. Depending on the + // state of the handler, we either own the map or not. If we + // don't own it, the exclude map is created lazily for + // WriteSubset to remove headers. The setHeader struct holds + // headers we need to add. + header := cw.header + owned := header != nil + if !owned { + header = w.handlerHeader + } + var excludeHeader map[string]bool + delHeader := func(key string) { + if owned { + header.Del(key) + return + } + if _, ok := header[key]; !ok { + return + } + if excludeHeader == nil { + excludeHeader = make(map[string]bool) + } + excludeHeader[key] = true + } + var setHeader extraHeader + + // Don't write out the fake "Trailer:foo" keys. See TrailerPrefix. + trailers := false + for k := range cw.header { + if strings.HasPrefix(k, TrailerPrefix) { + if excludeHeader == nil { + excludeHeader = make(map[string]bool) + } + excludeHeader[k] = true + trailers = true + } + } + for _, v := range cw.header["Trailer"] { + trailers = true + foreachHeaderElement(v, cw.res.declareTrailer) + } + + te := header.get("Transfer-Encoding") + hasTE := te != "" + + // If the handler is done but never sent a Content-Length + // response header and this is our first (and last) write, set + // it, even to zero. This helps HTTP/1.0 clients keep their + // "keep-alive" connections alive. + // Exceptions: 304/204/1xx responses never get Content-Length, and if + // it was a HEAD request, we don't know the difference between + // 0 actual bytes and 0 bytes because the handler noticed it + // was a HEAD request and chose not to write anything. So for + // HEAD, the handler should either write the Content-Length or + // write non-zero bytes. If it's actually 0 bytes and the + // handler never looked at the Request.Method, we just don't + // send a Content-Length header. + // Further, we don't send an automatic Content-Length if they + // set a Transfer-Encoding, because they're generally incompatible. + if w.handlerDone.Load() && !trailers && !hasTE && bodyAllowedForStatus(w.status) && !header.has("Content-Length") && (!isHEAD || len(p) > 0) { + w.contentLength = int64(len(p)) + setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10) + } + + // If this was an HTTP/1.0 request with keep-alive and we sent a + // Content-Length back, we can make this a keep-alive response ... + if w.wants10KeepAlive && keepAlivesEnabled { + sentLength := header.get("Content-Length") != "" + if sentLength && header.get("Connection") == "keep-alive" { + w.closeAfterReply = false + } + } + + // Check for an explicit (and valid) Content-Length header. + hasCL := w.contentLength != -1 + + if w.wants10KeepAlive && (isHEAD || hasCL || !bodyAllowedForStatus(w.status)) { + _, connectionHeaderSet := header["Connection"] + if !connectionHeaderSet { + setHeader.connection = "keep-alive" + } + } else if !w.req.ProtoAtLeast(1, 1) || w.wantsClose { + w.closeAfterReply = true + } + + if header.get("Connection") == "close" || !keepAlivesEnabled { + w.closeAfterReply = true + } + + // If the client wanted a 100-continue but we never sent it to + // them (or, more strictly: we never finished reading their + // request body), don't reuse this connection. + // + // This behavior was first added on the theory that we don't know + // if the next bytes on the wire are going to be the remainder of + // the request body or the subsequent request (see issue 11549), + // but that's not correct: If we keep using the connection, + // the client is required to send the request body whether we + // asked for it or not. + // + // We probably do want to skip reusing the connection in most cases, + // however. If the client is offering a large request body that we + // don't intend to use, then it's better to close the connection + // than to read the body. For now, assume that if we're sending + // headers, the handler is done reading the body and we should + // drop the connection if we haven't seen EOF. + if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF.Load() { + w.closeAfterReply = true + } + + // We do this by default because there are a number of clients that + // send a full request before starting to read the response, and they + // can deadlock if we start writing the response with unconsumed body + // remaining. See Issue 15527 for some history. + // + // If full duplex mode has been enabled with ResponseController.EnableFullDuplex, + // then leave the request body alone. + // + // We don't take this path when w.closeAfterReply is set. + // We may not need to consume the request to get ready for the next one + // (since we're closing the conn), but a client which sends a full request + // before reading a response may deadlock in this case. + // This behavior has been present since CL 5268043 (2011), however, + // so it doesn't seem to be causing problems. + if w.req.ContentLength != 0 && !w.closeAfterReply && !w.fullDuplex { + var discard, tooBig bool + + switch bdy := w.req.Body.(type) { + case *expectContinueReader: + // We only get here if we have already fully consumed the request body + // (see above). + case *body: + bdy.mu.Lock() + switch { + case bdy.closed: + if !bdy.sawEOF { + // Body was closed in handler with non-EOF error. + w.closeAfterReply = true + } + case bdy.unreadDataSizeLocked() >= maxPostHandlerReadBytes: + tooBig = true + default: + discard = true + } + bdy.mu.Unlock() + default: + discard = true + } + + if discard { + _, err := io.CopyN(io.Discard, w.reqBody, maxPostHandlerReadBytes+1) + switch err { + case nil: + // There must be even more data left over. + tooBig = true + case ErrBodyReadAfterClose: + // Body was already consumed and closed. + case io.EOF: + // The remaining body was just consumed, close it. + err = w.reqBody.Close() + if err != nil { + w.closeAfterReply = true + } + default: + // Some other kind of error occurred, like a read timeout, or + // corrupt chunked encoding. In any case, whatever remains + // on the wire must not be parsed as another HTTP request. + w.closeAfterReply = true + } + } + + if tooBig { + w.requestTooLarge() + delHeader("Connection") + setHeader.connection = "close" + } + } + + code := w.status + if bodyAllowedForStatus(code) { + // If no content type, apply sniffing algorithm to body. + _, haveType := header["Content-Type"] + + // If the Content-Encoding was set and is non-blank, + // we shouldn't sniff the body. See Issue 31753. + ce := header.Get("Content-Encoding") + hasCE := len(ce) > 0 + if !hasCE && !haveType && !hasTE && len(p) > 0 { + setHeader.contentType = DetectContentType(p) + } + } else { + for _, k := range suppressedHeaders(code) { + delHeader(k) + } + } + + if !header.has("Date") { + setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now()) + } + + if hasCL && hasTE && te != "identity" { + // TODO: return an error if WriteHeader gets a return parameter + // For now just ignore the Content-Length. + w.conn.server.logf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d", + te, w.contentLength) + delHeader("Content-Length") + hasCL = false + } + + if w.req.Method == "HEAD" || !bodyAllowedForStatus(code) || code == StatusNoContent { + // Response has no body. + delHeader("Transfer-Encoding") + } else if hasCL { + // Content-Length has been provided, so no chunking is to be done. + delHeader("Transfer-Encoding") + } else if w.req.ProtoAtLeast(1, 1) { + // HTTP/1.1 or greater: Transfer-Encoding has been set to identity, and no + // content-length has been provided. The connection must be closed after the + // reply is written, and no chunking is to be done. This is the setup + // recommended in the Server-Sent Events candidate recommendation 11, + // section 8. + if hasTE && te == "identity" { + cw.chunking = false + w.closeAfterReply = true + delHeader("Transfer-Encoding") + } else { + // HTTP/1.1 or greater: use chunked transfer encoding + // to avoid closing the connection at EOF. + cw.chunking = true + setHeader.transferEncoding = "chunked" + if hasTE && te == "chunked" { + // We will send the chunked Transfer-Encoding header later. + delHeader("Transfer-Encoding") + } + } + } else { + // HTTP version < 1.1: cannot do chunked transfer + // encoding and we don't know the Content-Length so + // signal EOF by closing connection. + w.closeAfterReply = true + delHeader("Transfer-Encoding") // in case already set + } + + // Cannot use Content-Length with non-identity Transfer-Encoding. + if cw.chunking { + delHeader("Content-Length") + } + if !w.req.ProtoAtLeast(1, 0) { + return + } + + // Only override the Connection header if it is not a successful + // protocol switch response and if KeepAlives are not enabled. + // See https://golang.org/issue/36381. + delConnectionHeader := w.closeAfterReply && + (!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) && + !isProtocolSwitchResponse(w.status, header) + if delConnectionHeader { + delHeader("Connection") + if w.req.ProtoAtLeast(1, 1) { + setHeader.connection = "close" + } + } + + writeStatusLine(w.conn.bufw, w.req.ProtoAtLeast(1, 1), code, w.statusBuf[:]) + cw.header.WriteSubset(w.conn.bufw, excludeHeader) + setHeader.Write(w.conn.bufw) + w.conn.bufw.Write(crlf) +} + +// foreachHeaderElement splits v according to the "#rule" construction +// in RFC 7230 section 7 and calls fn for each non-empty element. +func foreachHeaderElement(v string, fn func(string)) { + v = textproto.TrimString(v) + if v == "" { + return + } + if !strings.Contains(v, ",") { + fn(v) + return + } + for _, f := range strings.Split(v, ",") { + if f = textproto.TrimString(f); f != "" { + fn(f) + } + } +} + +// writeStatusLine writes an HTTP/1.x Status-Line (RFC 7230 Section 3.1.2) +// to bw. is11 is whether the HTTP request is HTTP/1.1. false means HTTP/1.0. +// code is the response status code. +// scratch is an optional scratch buffer. If it has at least capacity 3, it's used. +func writeStatusLine(bw *bufio.Writer, is11 bool, code int, scratch []byte) { + if is11 { + bw.WriteString("HTTP/1.1 ") + } else { + bw.WriteString("HTTP/1.0 ") + } + if text := StatusText(code); text != "" { + bw.Write(strconv.AppendInt(scratch[:0], int64(code), 10)) + bw.WriteByte(' ') + bw.WriteString(text) + bw.WriteString("\r\n") + } else { + // don't worry about performance + fmt.Fprintf(bw, "%03d status code %d\r\n", code, code) + } +} + +// bodyAllowed reports whether a Write is allowed for this response type. +// It's illegal to call this before the header has been flushed. +func (w *response) bodyAllowed() bool { + if !w.wroteHeader { + panic("") + } + return bodyAllowedForStatus(w.status) +} + +// The Life Of A Write is like this: +// +// Handler starts. No header has been sent. The handler can either +// write a header, or just start writing. Writing before sending a header +// sends an implicitly empty 200 OK header. +// +// If the handler didn't declare a Content-Length up front, we either +// go into chunking mode or, if the handler finishes running before +// the chunking buffer size, we compute a Content-Length and send that +// in the header instead. +// +// Likewise, if the handler didn't set a Content-Type, we sniff that +// from the initial chunk of output. +// +// The Writers are wired together like: +// +// 1. *response (the ResponseWriter) -> +// 2. (*response).w, a [*bufio.Writer] of bufferBeforeChunkingSize bytes -> +// 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type) +// and which writes the chunk headers, if needed -> +// 4. conn.bufw, a *bufio.Writer of default (4kB) bytes, writing to -> +// 5. checkConnErrorWriter{c}, which notes any non-nil error on Write +// and populates c.werr with it if so, but otherwise writes to -> +// 6. the rwc, the [net.Conn]. +// +// TODO(bradfitz): short-circuit some of the buffering when the +// initial header contains both a Content-Type and Content-Length. +// Also short-circuit in (1) when the header's been sent and not in +// chunking mode, writing directly to (4) instead, if (2) has no +// buffered data. More generally, we could short-circuit from (1) to +// (3) even in chunking mode if the write size from (1) is over some +// threshold and nothing is in (2). The answer might be mostly making +// bufferBeforeChunkingSize smaller and having bufio's fast-paths deal +// with this instead. +func (w *response) Write(data []byte) (n int, err error) { + return w.write(len(data), data, "") +} + +func (w *response) WriteString(data string) (n int, err error) { + return w.write(len(data), nil, data) +} + +// either dataB or dataS is non-zero. +func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) { + if w.conn.hijacked() { + if lenData > 0 { + caller := relevantCaller() + w.conn.server.logf("http: response.Write on hijacked connection from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line) + } + return 0, ErrHijacked + } + + if w.canWriteContinue.Load() { + // Body reader wants to write 100 Continue but hasn't yet. Tell it not to. + w.disableWriteContinue() + } + + if !w.wroteHeader { + w.WriteHeader(StatusOK) + } + if lenData == 0 { + return 0, nil + } + if !w.bodyAllowed() { + return 0, ErrBodyNotAllowed + } + + w.written += int64(lenData) // ignoring errors, for errorKludge + if w.contentLength != -1 && w.written > w.contentLength { + return 0, ErrContentLength + } + if dataB != nil { + return w.w.Write(dataB) + } else { + return w.w.WriteString(dataS) + } +} + +func (w *response) finishRequest() { + w.handlerDone.Store(true) + + if !w.wroteHeader { + w.WriteHeader(StatusOK) + } + + w.w.Flush() + putBufioWriter(w.w) + w.cw.close() + w.conn.bufw.Flush() + + w.conn.r.abortPendingRead() + + // Close the body (regardless of w.closeAfterReply) so we can + // re-use its bufio.Reader later safely. + w.reqBody.Close() + + if w.req.MultipartForm != nil { + w.req.MultipartForm.RemoveAll() + } +} + +// shouldReuseConnection reports whether the underlying TCP connection can be reused. +// It must only be called after the handler is done executing. +func (w *response) shouldReuseConnection() bool { + if w.closeAfterReply { + // The request or something set while executing the + // handler indicated we shouldn't reuse this + // connection. + return false + } + + if w.req.Method != "HEAD" && w.contentLength != -1 && w.bodyAllowed() && w.contentLength != w.written { + // Did not write enough. Avoid getting out of sync. + return false + } + + // There was some error writing to the underlying connection + // during the request, so don't re-use this conn. + if w.conn.werr != nil { + return false + } + + if w.closedRequestBodyEarly() { + return false + } + + return true +} + +func (w *response) closedRequestBodyEarly() bool { + body, ok := w.req.Body.(*body) + return ok && body.didEarlyClose() +} + +func (w *response) Flush() { + w.FlushError() +} + +func (w *response) FlushError() error { + if !w.wroteHeader { + w.WriteHeader(StatusOK) + } + err := w.w.Flush() + e2 := w.cw.flush() + if err == nil { + err = e2 + } + return err +} + +func (c *conn) finalFlush() { + if c.bufr != nil { + // Steal the bufio.Reader (~4KB worth of memory) and its associated + // reader for a future connection. + putBufioReader(c.bufr) + c.bufr = nil + } + + if c.bufw != nil { + c.bufw.Flush() + // Steal the bufio.Writer (~4KB worth of memory) and its associated + // writer for a future connection. + putBufioWriter(c.bufw) + c.bufw = nil + } +} + +// Close the connection. +func (c *conn) close() { + c.finalFlush() + c.rwc.Close() +} + +// rstAvoidanceDelay is the amount of time we sleep after closing the +// write side of a TCP connection before closing the entire socket. +// By sleeping, we increase the chances that the client sees our FIN +// and processes its final data before they process the subsequent RST +// from closing a connection with known unread data. +// This RST seems to occur mostly on BSD systems. (And Windows?) +// This timeout is somewhat arbitrary (~latency around the planet), +// and may be modified by tests. +// +// TODO(bcmills): This should arguably be a server configuration parameter, +// not a hard-coded value. +var rstAvoidanceDelay = 500 * time.Millisecond + +type closeWriter interface { + CloseWrite() error +} + +var _ closeWriter = (*net.TCPConn)(nil) + +// closeWriteAndWait flushes any outstanding data and sends a FIN packet (if +// client is connected via TCP), signaling that we're done. We then +// pause for a bit, hoping the client processes it before any +// subsequent RST. +// +// See https://golang.org/issue/3595 +func (c *conn) closeWriteAndWait() { + c.finalFlush() + if tcp, ok := c.rwc.(closeWriter); ok { + tcp.CloseWrite() + } + + // When we return from closeWriteAndWait, the caller will fully close the + // connection. If client is still writing to the connection, this will cause + // the write to fail with ECONNRESET or similar. Unfortunately, many TCP + // implementations will also drop unread packets from the client's read buffer + // when a write fails, causing our final response to be truncated away too. + // + // As a result, https://www.rfc-editor.org/rfc/rfc7230#section-6.6 recommends + // that “[t]he server … continues to read from the connection until it + // receives a corresponding close by the client, or until the server is + // reasonably certain that its own TCP stack has received the client's + // acknowledgement of the packet(s) containing the server's last response.” + // + // Unfortunately, we have no straightforward way to be “reasonably certain” + // that we have received the client's ACK, and at any rate we don't want to + // allow a misbehaving client to soak up server connections indefinitely by + // withholding an ACK, nor do we want to go through the complexity or overhead + // of using low-level APIs to figure out when a TCP round-trip has completed. + // + // Instead, we declare that we are “reasonably certain” that we received the + // ACK if maxRSTAvoidanceDelay has elapsed. + time.Sleep(rstAvoidanceDelay) +} + +// validNextProto reports whether the proto is a valid ALPN protocol name. +// Everything is valid except the empty string and built-in protocol types, +// so that those can't be overridden with alternate implementations. +func validNextProto(proto string) bool { + switch proto { + case "", "http/1.1", "http/1.0": + return false + } + return true +} + +const ( + runHooks = true + skipHooks = false +) + +func (c *conn) setState(nc net.Conn, state ConnState, runHook bool) { + srv := c.server + switch state { + case StateNew: + srv.trackConn(c, true) + case StateHijacked, StateClosed: + srv.trackConn(c, false) + } + if state > 0xff || state < 0 { + panic("internal error") + } + packedState := uint64(time.Now().Unix()<<8) | uint64(state) + c.curState.Store(packedState) + if !runHook { + return + } + if hook := srv.ConnState; hook != nil { + hook(nc, state) + } +} + +func (c *conn) getState() (state ConnState, unixSec int64) { + packedState := c.curState.Load() + return ConnState(packedState & 0xff), int64(packedState >> 8) +} + +// badRequestError is a literal string (used by in the server in HTML, +// unescaped) to tell the user why their request was bad. It should +// be plain text without user info or other embedded errors. +func badRequestError(e string) error { return statusError{StatusBadRequest, e} } + +// statusError is an error used to respond to a request with an HTTP status. +// The text should be plain text without user info or other embedded errors. +type statusError struct { + code int + text string +} + +func (e statusError) Error() string { return StatusText(e.code) + ": " + e.text } + +// ErrAbortHandler is a sentinel panic value to abort a handler. +// While any panic from ServeHTTP aborts the response to the client, +// panicking with ErrAbortHandler also suppresses logging of a stack +// trace to the server's error log. +var ErrAbortHandler = errors.New("net/http: abort Handler") + +// isCommonNetReadError reports whether err is a common error +// encountered during reading a request off the network when the +// client has gone away or had its read fail somehow. This is used to +// determine which logs are interesting enough to log about. +func isCommonNetReadError(err error) bool { + if err == io.EOF { + return true + } + if neterr, ok := err.(net.Error); ok && neterr.Timeout() { + return true + } + if oe, ok := err.(*net.OpError); ok && oe.Op == "read" { + return true + } + return false +} + +// Serve a new connection. +func (c *conn) serve(ctx context.Context) { + if ra := c.rwc.RemoteAddr(); ra != nil { + c.remoteAddr = ra.String() + } + ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr()) + var inFlightResponse *response + defer func() { + if err := recover(); err != nil && err != ErrAbortHandler { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf) + } + if inFlightResponse != nil { + inFlightResponse.cancelCtx() + inFlightResponse.disableWriteContinue() + } + if !c.hijacked() { + if inFlightResponse != nil { + inFlightResponse.conn.r.abortPendingRead() + inFlightResponse.reqBody.Close() + } + c.close() + c.setState(c.rwc, StateClosed, runHooks) + } + }() + + if tlsConn, ok := c.rwc.(*tls.Conn); ok { + tlsTO := c.server.tlsHandshakeTimeout() + if tlsTO > 0 { + dl := time.Now().Add(tlsTO) + c.rwc.SetReadDeadline(dl) + c.rwc.SetWriteDeadline(dl) + } + if err := tlsConn.HandshakeContext(ctx); err != nil { + // If the handshake failed due to the client not speaking + // TLS, assume they're speaking plaintext HTTP and write a + // 400 response on the TLS conn's underlying net.Conn. + var reason string + if re, ok := err.(tls.RecordHeaderError); ok && re.Conn != nil && tlsRecordHeaderLooksLikeHTTP(re.RecordHeader) { + io.WriteString(re.Conn, "HTTP/1.0 400 Bad Request\r\n\r\nClient sent an HTTP request to an HTTPS server.\n") + re.Conn.Close() + reason = "client sent an HTTP request to an HTTPS server" + } else { + reason = err.Error() + } + c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), reason) + return + } + // Restore Conn-level deadlines. + if tlsTO > 0 { + c.rwc.SetReadDeadline(time.Time{}) + c.rwc.SetWriteDeadline(time.Time{}) + } + c.tlsState = new(tls.ConnectionState) + *c.tlsState = tlsConn.ConnectionState() + if proto := c.tlsState.NegotiatedProtocol; validNextProto(proto) { + if fn := c.server.TLSNextProto[proto]; fn != nil { + h := initALPNRequest{ctx, tlsConn, serverHandler{c.server}} + // Mark freshly created HTTP/2 as active and prevent any server state hooks + // from being run on these connections. This prevents closeIdleConns from + // closing such connections. See issue https://golang.org/issue/39776. + c.setState(c.rwc, StateActive, skipHooks) + fn(c.server, tlsConn, h) + } + return + } + } + + // HTTP/1.x from here on. + + ctx, cancelCtx := context.WithCancel(ctx) + c.cancelCtx = cancelCtx + defer cancelCtx() + + c.r = &connReader{conn: c} + c.bufr = newBufioReader(c.r) + c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) + + for { + w, err := c.readRequest(ctx) + if c.r.remain != c.server.initialReadLimitSize() { + // If we read any bytes off the wire, we're active. + c.setState(c.rwc, StateActive, runHooks) + } + if err != nil { + const errorHeaders = "\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: close\r\n\r\n" + + switch { + case err == errTooLarge: + // Their HTTP client may or may not be + // able to read this if we're + // responding to them and hanging up + // while they're still writing their + // request. Undefined behavior. + const publicErr = "431 Request Header Fields Too Large" + fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr) + c.closeWriteAndWait() + return + + case isUnsupportedTEError(err): + // Respond as per RFC 7230 Section 3.3.1 which says, + // A server that receives a request message with a + // transfer coding it does not understand SHOULD + // respond with 501 (Unimplemented). + code := StatusNotImplemented + + // We purposefully aren't echoing back the transfer-encoding's value, + // so as to mitigate the risk of cross side scripting by an attacker. + fmt.Fprintf(c.rwc, "HTTP/1.1 %d %s%sUnsupported transfer encoding", code, StatusText(code), errorHeaders) + return + + case isCommonNetReadError(err): + return // don't reply + + default: + if v, ok := err.(statusError); ok { + fmt.Fprintf(c.rwc, "HTTP/1.1 %d %s: %s%s%d %s: %s", v.code, StatusText(v.code), v.text, errorHeaders, v.code, StatusText(v.code), v.text) + return + } + const publicErr = "400 Bad Request" + fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr) + return + } + } + + // Expect 100 Continue support + req := w.req + if req.expectsContinue() { + if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 { + // Wrap the Body reader with one that replies on the connection + req.Body = &expectContinueReader{readCloser: req.Body, resp: w} + w.canWriteContinue.Store(true) + } + } else if req.Header.get("Expect") != "" { + w.sendExpectationFailed() + return + } + + c.curReq.Store(w) + + if requestBodyRemains(req.Body) { + registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead) + } else { + w.conn.r.startBackgroundRead() + } + + // HTTP cannot have multiple simultaneous active requests.[*] + // Until the server replies to this request, it can't read another, + // so we might as well run the handler in this goroutine. + // [*] Not strictly true: HTTP pipelining. We could let them all process + // in parallel even if their responses need to be serialized. + // But we're not going to implement HTTP pipelining because it + // was never deployed in the wild and the answer is HTTP/2. + inFlightResponse = w + serverHandler{c.server}.ServeHTTP(w, w.req) + inFlightResponse = nil + w.cancelCtx() + if c.hijacked() { + return + } + w.finishRequest() + c.rwc.SetWriteDeadline(time.Time{}) + if !w.shouldReuseConnection() { + if w.requestBodyLimitHit || w.closedRequestBodyEarly() { + c.closeWriteAndWait() + } + return + } + c.setState(c.rwc, StateIdle, runHooks) + c.curReq.Store(nil) + + if !w.conn.server.doKeepAlives() { + // We're in shutdown mode. We might've replied + // to the user without "Connection: close" and + // they might think they can send another + // request, but such is life with HTTP/1.1. + return + } + + if d := c.server.idleTimeout(); d > 0 { + c.rwc.SetReadDeadline(time.Now().Add(d)) + } else { + c.rwc.SetReadDeadline(time.Time{}) + } + + // Wait for the connection to become readable again before trying to + // read the next request. This prevents a ReadHeaderTimeout or + // ReadTimeout from starting until the first bytes of the next request + // have been received. + if _, err := c.bufr.Peek(4); err != nil { + return + } + + c.rwc.SetReadDeadline(time.Time{}) + } +} + +func (w *response) sendExpectationFailed() { + // TODO(bradfitz): let ServeHTTP handlers handle + // requests with non-standard expectation[s]? Seems + // theoretical at best, and doesn't fit into the + // current ServeHTTP model anyway. We'd need to + // make the ResponseWriter an optional + // "ExpectReplier" interface or something. + // + // For now we'll just obey RFC 7231 5.1.1 which says + // "A server that receives an Expect field-value other + // than 100-continue MAY respond with a 417 (Expectation + // Failed) status code to indicate that the unexpected + // expectation cannot be met." + w.Header().Set("Connection", "close") + w.WriteHeader(StatusExpectationFailed) + w.finishRequest() +} + +// Hijack implements the [Hijacker.Hijack] method. Our response is both a [ResponseWriter] +// and a [Hijacker]. +func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) { + if w.handlerDone.Load() { + panic("net/http: Hijack called after ServeHTTP finished") + } + w.disableWriteContinue() + if w.wroteHeader { + w.cw.flush() + } + + c := w.conn + c.mu.Lock() + defer c.mu.Unlock() + + // Release the bufioWriter that writes to the chunk writer, it is not + // used after a connection has been hijacked. + rwc, buf, err = c.hijackLocked() + if err == nil { + putBufioWriter(w.w) + w.w = nil + } + return rwc, buf, err +} + +func (w *response) CloseNotify() <-chan bool { + if w.handlerDone.Load() { + panic("net/http: CloseNotify called after ServeHTTP finished") + } + return w.closeNotifyCh +} + +func registerOnHitEOF(rc io.ReadCloser, fn func()) { + switch v := rc.(type) { + case *expectContinueReader: + registerOnHitEOF(v.readCloser, fn) + case *body: + v.registerOnHitEOF(fn) + default: + panic("unexpected type " + fmt.Sprintf("%T", rc)) + } +} + +// requestBodyRemains reports whether future calls to Read +// on rc might yield more data. +func requestBodyRemains(rc io.ReadCloser) bool { + if rc == NoBody { + return false + } + switch v := rc.(type) { + case *expectContinueReader: + return requestBodyRemains(v.readCloser) + case *body: + return v.bodyRemains() + default: + panic("unexpected type " + fmt.Sprintf("%T", rc)) + } +} + +// The HandlerFunc type is an adapter to allow the use of +// ordinary functions as HTTP handlers. If f is a function +// with the appropriate signature, HandlerFunc(f) is a +// [Handler] that calls f. +type HandlerFunc func(ResponseWriter, *Request) + +// ServeHTTP calls f(w, r). +func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { + f(w, r) +} + +// Helper handlers + +// Error replies to the request with the specified error message and HTTP code. +// It does not otherwise end the request; the caller should ensure no further +// writes are done to w. +// The error message should be plain text. +// +// Error deletes the Content-Length header, +// sets Content-Type to “text/plain; charset=utf-8”, +// and sets X-Content-Type-Options to “nosniff”. +// This configures the header properly for the error message, +// in case the caller had set it up expecting a successful output. +func Error(w ResponseWriter, error string, code int) { + h := w.Header() + + // Delete the Content-Length header, which might be for some other content. + // Assuming the error string fits in the writer's buffer, we'll figure + // out the correct Content-Length for it later. + // + // We don't delete Content-Encoding, because some middleware sets + // Content-Encoding: gzip and wraps the ResponseWriter to compress on-the-fly. + // See https://go.dev/issue/66343. + h.Del("Content-Length") + + // There might be content type already set, but we reset it to + // text/plain for the error message. + h.Set("Content-Type", "text/plain; charset=utf-8") + h.Set("X-Content-Type-Options", "nosniff") + w.WriteHeader(code) + fmt.Fprintln(w, error) +} + +// NotFound replies to the request with an HTTP 404 not found error. +func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) } + +// NotFoundHandler returns a simple request handler +// that replies to each request with a “404 page not found” reply. +func NotFoundHandler() Handler { return HandlerFunc(NotFound) } + +// StripPrefix returns a handler that serves HTTP requests by removing the +// given prefix from the request URL's Path (and RawPath if set) and invoking +// the handler h. StripPrefix handles a request for a path that doesn't begin +// with prefix by replying with an HTTP 404 not found error. The prefix must +// match exactly: if the prefix in the request contains escaped characters +// the reply is also an HTTP 404 not found error. +func StripPrefix(prefix string, h Handler) Handler { + if prefix == "" { + return h + } + return HandlerFunc(func(w ResponseWriter, r *Request) { + p := strings.TrimPrefix(r.URL.Path, prefix) + rp := strings.TrimPrefix(r.URL.RawPath, prefix) + if len(p) < len(r.URL.Path) && (r.URL.RawPath == "" || len(rp) < len(r.URL.RawPath)) { + r2 := new(Request) + *r2 = *r + r2.URL = new(url.URL) + *r2.URL = *r.URL + r2.URL.Path = p + r2.URL.RawPath = rp + h.ServeHTTP(w, r2) + } else { + NotFound(w, r) + } + }) +} + +// Redirect replies to the request with a redirect to url, +// which may be a path relative to the request path. +// +// The provided code should be in the 3xx range and is usually +// [StatusMovedPermanently], [StatusFound] or [StatusSeeOther]. +// +// If the Content-Type header has not been set, [Redirect] sets it +// to "text/html; charset=utf-8" and writes a small HTML body. +// Setting the Content-Type header to any value, including nil, +// disables that behavior. +func Redirect(w ResponseWriter, r *Request, url string, code int) { + if u, err := urlpkg.Parse(url); err == nil { + // If url was relative, make its path absolute by + // combining with request path. + // The client would probably do this for us, + // but doing it ourselves is more reliable. + // See RFC 7231, section 7.1.2 + if u.Scheme == "" && u.Host == "" { + oldpath := r.URL.Path + if oldpath == "" { // should not happen, but avoid a crash if it does + oldpath = "/" + } + + // no leading http://server + if url == "" || url[0] != '/' { + // make relative path absolute + olddir, _ := path.Split(oldpath) + url = olddir + url + } + + var query string + if i := strings.Index(url, "?"); i != -1 { + url, query = url[:i], url[i:] + } + + // clean up but preserve trailing slash + trailing := strings.HasSuffix(url, "/") + url = path.Clean(url) + if trailing && !strings.HasSuffix(url, "/") { + url += "/" + } + url += query + } + } + + h := w.Header() + + // RFC 7231 notes that a short HTML body is usually included in + // the response because older user agents may not understand 301/307. + // Do it only if the request didn't already have a Content-Type header. + _, hadCT := h["Content-Type"] + + h.Set("Location", hexEscapeNonASCII(url)) + if !hadCT && (r.Method == "GET" || r.Method == "HEAD") { + h.Set("Content-Type", "text/html; charset=utf-8") + } + w.WriteHeader(code) + + // Shouldn't send the body for POST or HEAD; that leaves GET. + if !hadCT && r.Method == "GET" { + body := "" + StatusText(code) + ".\n" + fmt.Fprintln(w, body) + } +} + +var htmlReplacer = strings.NewReplacer( + "&", "&", + "<", "<", + ">", ">", + // """ is shorter than """. + `"`, """, + // "'" is shorter than "'" and apos was not in HTML until HTML5. + "'", "'", +) + +func htmlEscape(s string) string { + return htmlReplacer.Replace(s) +} + +// Redirect to a fixed URL +type redirectHandler struct { + url string + code int +} + +func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) { + Redirect(w, r, rh.url, rh.code) +} + +// RedirectHandler returns a request handler that redirects +// each request it receives to the given url using the given +// status code. +// +// The provided code should be in the 3xx range and is usually +// [StatusMovedPermanently], [StatusFound] or [StatusSeeOther]. +func RedirectHandler(url string, code int) Handler { + return &redirectHandler{url, code} +} + +// ServeMux is an HTTP request multiplexer. +// It matches the URL of each incoming request against a list of registered +// patterns and calls the handler for the pattern that +// most closely matches the URL. +// +// # Patterns +// +// Patterns can match the method, host and path of a request. +// Some examples: +// +// - "/index.html" matches the path "/index.html" for any host and method. +// - "GET /static/" matches a GET request whose path begins with "/static/". +// - "example.com/" matches any request to the host "example.com". +// - "example.com/{$}" matches requests with host "example.com" and path "/". +// - "/b/{bucket}/o/{objectname...}" matches paths whose first segment is "b" +// and whose third segment is "o". The name "bucket" denotes the second +// segment and "objectname" denotes the remainder of the path. +// +// In general, a pattern looks like +// +// [METHOD ][HOST]/[PATH] +// +// All three parts are optional; "/" is a valid pattern. +// If METHOD is present, it must be followed by at least one space or tab. +// +// Literal (that is, non-wildcard) parts of a pattern match +// the corresponding parts of a request case-sensitively. +// +// A pattern with no method matches every method. A pattern +// with the method GET matches both GET and HEAD requests. +// Otherwise, the method must match exactly. +// +// A pattern with no host matches every host. +// A pattern with a host matches URLs on that host only. +// +// A path can include wildcard segments of the form {NAME} or {NAME...}. +// For example, "/b/{bucket}/o/{objectname...}". +// The wildcard name must be a valid Go identifier. +// Wildcards must be full path segments: they must be preceded by a slash and followed by +// either a slash or the end of the string. +// For example, "/b_{bucket}" is not a valid pattern. +// +// Normally a wildcard matches only a single path segment, +// ending at the next literal slash (not %2F) in the request URL. +// But if the "..." is present, then the wildcard matches the remainder of the URL path, including slashes. +// (Therefore it is invalid for a "..." wildcard to appear anywhere but at the end of a pattern.) +// The match for a wildcard can be obtained by calling [Request.PathValue] with the wildcard's name. +// A trailing slash in a path acts as an anonymous "..." wildcard. +// +// The special wildcard {$} matches only the end of the URL. +// For example, the pattern "/{$}" matches only the path "/", +// whereas the pattern "/" matches every path. +// +// For matching, both pattern paths and incoming request paths are unescaped segment by segment. +// So, for example, the path "/a%2Fb/100%25" is treated as having two segments, "a/b" and "100%". +// The pattern "/a%2fb/" matches it, but the pattern "/a/b/" does not. +// +// # Precedence +// +// If two or more patterns match a request, then the most specific pattern takes precedence. +// A pattern P1 is more specific than P2 if P1 matches a strict subset of P2’s requests; +// that is, if P2 matches all the requests of P1 and more. +// If neither is more specific, then the patterns conflict. +// There is one exception to this rule, for backwards compatibility: +// if two patterns would otherwise conflict and one has a host while the other does not, +// then the pattern with the host takes precedence. +// If a pattern passed to [ServeMux.Handle] or [ServeMux.HandleFunc] conflicts with +// another pattern that is already registered, those functions panic. +// +// As an example of the general rule, "/images/thumbnails/" is more specific than "/images/", +// so both can be registered. +// The former matches paths beginning with "/images/thumbnails/" +// and the latter will match any other path in the "/images/" subtree. +// +// As another example, consider the patterns "GET /" and "/index.html": +// both match a GET request for "/index.html", but the former pattern +// matches all other GET and HEAD requests, while the latter matches any +// request for "/index.html" that uses a different method. +// The patterns conflict. +// +// # Trailing-slash redirection +// +// Consider a [ServeMux] with a handler for a subtree, registered using a trailing slash or "..." wildcard. +// If the ServeMux receives a request for the subtree root without a trailing slash, +// it redirects the request by adding the trailing slash. +// This behavior can be overridden with a separate registration for the path without +// the trailing slash or "..." wildcard. For example, registering "/images/" causes ServeMux +// to redirect a request for "/images" to "/images/", unless "/images" has +// been registered separately. +// +// # Request sanitizing +// +// ServeMux also takes care of sanitizing the URL request path and the Host +// header, stripping the port number and redirecting any request containing . or +// .. segments or repeated slashes to an equivalent, cleaner URL. +// +// # Compatibility +// +// The pattern syntax and matching behavior of ServeMux changed significantly +// in Go 1.22. To restore the old behavior, set the GODEBUG environment variable +// to "httpmuxgo121=1". This setting is read once, at program startup; changes +// during execution will be ignored. +// +// The backwards-incompatible changes include: +// - Wildcards are just ordinary literal path segments in 1.21. +// For example, the pattern "/{x}" will match only that path in 1.21, +// but will match any one-segment path in 1.22. +// - In 1.21, no pattern was rejected, unless it was empty or conflicted with an existing pattern. +// In 1.22, syntactically invalid patterns will cause [ServeMux.Handle] and [ServeMux.HandleFunc] to panic. +// For example, in 1.21, the patterns "/{" and "/a{x}" match themselves, +// but in 1.22 they are invalid and will cause a panic when registered. +// - In 1.22, each segment of a pattern is unescaped; this was not done in 1.21. +// For example, in 1.22 the pattern "/%61" matches the path "/a" ("%61" being the URL escape sequence for "a"), +// but in 1.21 it would match only the path "/%2561" (where "%25" is the escape for the percent sign). +// - When matching patterns to paths, in 1.22 each segment of the path is unescaped; in 1.21, the entire path is unescaped. +// This change mostly affects how paths with %2F escapes adjacent to slashes are treated. +// See https://go.dev/issue/21955 for details. +type ServeMux struct { + mu sync.RWMutex + tree routingNode + index routingIndex + patterns []*pattern // TODO(jba): remove if possible + mux121 serveMux121 // used only when GODEBUG=httpmuxgo121=1 +} + +// NewServeMux allocates and returns a new [ServeMux]. +func NewServeMux() *ServeMux { + return &ServeMux{} +} + +// DefaultServeMux is the default [ServeMux] used by [Serve]. +var DefaultServeMux = &defaultServeMux + +var defaultServeMux ServeMux + +// cleanPath returns the canonical path for p, eliminating . and .. elements. +func cleanPath(p string) string { + if p == "" { + return "/" + } + if p[0] != '/' { + p = "/" + p + } + np := path.Clean(p) + // path.Clean removes trailing slash except for root; + // put the trailing slash back if necessary. + if p[len(p)-1] == '/' && np != "/" { + // Fast path for common case of p being the string we want: + if len(p) == len(np)+1 && strings.HasPrefix(p, np) { + np = p + } else { + np += "/" + } + } + return np +} + +// stripHostPort returns h without any trailing ":". +func stripHostPort(h string) string { + // If no port on host, return unchanged + if !strings.Contains(h, ":") { + return h + } + host, _, err := net.SplitHostPort(h) + if err != nil { + return h // on error, return unchanged + } + return host +} + +// Handler returns the handler to use for the given request, +// consulting r.Method, r.Host, and r.URL.Path. It always returns +// a non-nil handler. If the path is not in its canonical form, the +// handler will be an internally-generated handler that redirects +// to the canonical path. If the host contains a port, it is ignored +// when matching handlers. +// +// The path and host are used unchanged for CONNECT requests. +// +// Handler also returns the registered pattern that matches the +// request or, in the case of internally-generated redirects, +// the path that will match after following the redirect. +// +// If there is no registered handler that applies to the request, +// Handler returns a “page not found” handler and an empty pattern. +func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { + if use121 { + return mux.mux121.findHandler(r) + } + h, p, _, _ := mux.findHandler(r) + return h, p +} + +// findHandler finds a handler for a request. +// If there is a matching handler, it returns it and the pattern that matched. +// Otherwise it returns a Redirect or NotFound handler with the path that would match +// after the redirect. +func (mux *ServeMux) findHandler(r *Request) (h Handler, patStr string, _ *pattern, matches []string) { + var n *routingNode + host := r.URL.Host + escapedPath := r.URL.EscapedPath() + path := escapedPath + // CONNECT requests are not canonicalized. + if r.Method == "CONNECT" { + // If r.URL.Path is /tree and its handler is not registered, + // the /tree -> /tree/ redirect applies to CONNECT requests + // but the path canonicalization does not. + _, _, u := mux.matchOrRedirect(host, r.Method, path, r.URL) + if u != nil { + return RedirectHandler(u.String(), StatusMovedPermanently), u.Path, nil, nil + } + // Redo the match, this time with r.Host instead of r.URL.Host. + // Pass a nil URL to skip the trailing-slash redirect logic. + n, matches, _ = mux.matchOrRedirect(r.Host, r.Method, path, nil) + } else { + // All other requests have any port stripped and path cleaned + // before passing to mux.handler. + host = stripHostPort(r.Host) + path = cleanPath(path) + + // If the given path is /tree and its handler is not registered, + // redirect for /tree/. + var u *url.URL + n, matches, u = mux.matchOrRedirect(host, r.Method, path, r.URL) + if u != nil { + return RedirectHandler(u.String(), StatusMovedPermanently), u.Path, nil, nil + } + if path != escapedPath { + // Redirect to cleaned path. + patStr := "" + if n != nil { + patStr = n.pattern.String() + } + u := &url.URL{Path: path, RawQuery: r.URL.RawQuery} + return RedirectHandler(u.String(), StatusMovedPermanently), patStr, nil, nil + } + } + if n == nil { + // We didn't find a match with the request method. To distinguish between + // Not Found and Method Not Allowed, see if there is another pattern that + // matches except for the method. + allowedMethods := mux.matchingMethods(host, path) + if len(allowedMethods) > 0 { + return HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set("Allow", strings.Join(allowedMethods, ", ")) + Error(w, StatusText(StatusMethodNotAllowed), StatusMethodNotAllowed) + }), "", nil, nil + } + return NotFoundHandler(), "", nil, nil + } + return n.handler, n.pattern.String(), n.pattern, matches +} + +// matchOrRedirect looks up a node in the tree that matches the host, method and path. +// +// If the url argument is non-nil, handler also deals with trailing-slash +// redirection: when a path doesn't match exactly, the match is tried again +// after appending "/" to the path. If that second match succeeds, the last +// return value is the URL to redirect to. +func (mux *ServeMux) matchOrRedirect(host, method, path string, u *url.URL) (_ *routingNode, matches []string, redirectTo *url.URL) { + mux.mu.RLock() + defer mux.mu.RUnlock() + + n, matches := mux.tree.match(host, method, path) + // If we have an exact match, or we were asked not to try trailing-slash redirection, + // or the URL already has a trailing slash, then we're done. + if !exactMatch(n, path) && u != nil && !strings.HasSuffix(path, "/") { + // If there is an exact match with a trailing slash, then redirect. + path += "/" + n2, _ := mux.tree.match(host, method, path) + if exactMatch(n2, path) { + return nil, nil, &url.URL{Path: cleanPath(u.Path) + "/", RawQuery: u.RawQuery} + } + } + return n, matches, nil +} + +// exactMatch reports whether the node's pattern exactly matches the path. +// As a special case, if the node is nil, exactMatch return false. +// +// Before wildcards were introduced, it was clear that an exact match meant +// that the pattern and path were the same string. The only other possibility +// was that a trailing-slash pattern, like "/", matched a path longer than +// it, like "/a". +// +// With wildcards, we define an inexact match as any one where a multi wildcard +// matches a non-empty string. All other matches are exact. +// For example, these are all exact matches: +// +// pattern path +// /a /a +// /{x} /a +// /a/{$} /a/ +// /a/ /a/ +// +// The last case has a multi wildcard (implicitly), but the match is exact because +// the wildcard matches the empty string. +// +// Examples of matches that are not exact: +// +// pattern path +// / /a +// /a/{x...} /a/b +func exactMatch(n *routingNode, path string) bool { + if n == nil { + return false + } + // We can't directly implement the definition (empty match for multi + // wildcard) because we don't record a match for anonymous multis. + + // If there is no multi, the match is exact. + if !n.pattern.lastSegment().multi { + return true + } + + // If the path doesn't end in a trailing slash, then the multi match + // is non-empty. + if len(path) > 0 && path[len(path)-1] != '/' { + return false + } + // Only patterns ending in {$} or a multi wildcard can + // match a path with a trailing slash. + // For the match to be exact, the number of pattern + // segments should be the same as the number of slashes in the path. + // E.g. "/a/b/{$}" and "/a/b/{...}" exactly match "/a/b/", but "/a/" does not. + return len(n.pattern.segments) == strings.Count(path, "/") +} + +// matchingMethods return a sorted list of all methods that would match with the given host and path. +func (mux *ServeMux) matchingMethods(host, path string) []string { + // Hold the read lock for the entire method so that the two matches are done + // on the same set of registered patterns. + mux.mu.RLock() + defer mux.mu.RUnlock() + ms := map[string]bool{} + mux.tree.matchingMethods(host, path, ms) + // matchOrRedirect will try appending a trailing slash if there is no match. + if !strings.HasSuffix(path, "/") { + mux.tree.matchingMethods(host, path+"/", ms) + } + return slices.Sorted(maps.Keys(ms)) +} + +// ServeHTTP dispatches the request to the handler whose +// pattern most closely matches the request URL. +func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { + if r.RequestURI == "*" { + if r.ProtoAtLeast(1, 1) { + w.Header().Set("Connection", "close") + } + w.WriteHeader(StatusBadRequest) + return + } + var h Handler + if use121 { + h, _ = mux.mux121.findHandler(r) + } else { + h, r.Pattern, r.pat, r.matches = mux.findHandler(r) + } + h.ServeHTTP(w, r) +} + +// The four functions below all call ServeMux.register so that callerLocation +// always refers to user code. + +// Handle registers the handler for the given pattern. +// If the given pattern conflicts, with one that is already registered, Handle +// panics. +func (mux *ServeMux) Handle(pattern string, handler Handler) { + if use121 { + mux.mux121.handle(pattern, handler) + } else { + mux.register(pattern, handler) + } +} + +// HandleFunc registers the handler function for the given pattern. +// If the given pattern conflicts, with one that is already registered, HandleFunc +// panics. +func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { + if use121 { + mux.mux121.handleFunc(pattern, handler) + } else { + mux.register(pattern, HandlerFunc(handler)) + } +} + +// Handle registers the handler for the given pattern in [DefaultServeMux]. +// The documentation for [ServeMux] explains how patterns are matched. +func Handle(pattern string, handler Handler) { + if use121 { + DefaultServeMux.mux121.handle(pattern, handler) + } else { + DefaultServeMux.register(pattern, handler) + } +} + +// HandleFunc registers the handler function for the given pattern in [DefaultServeMux]. +// The documentation for [ServeMux] explains how patterns are matched. +func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { + if use121 { + DefaultServeMux.mux121.handleFunc(pattern, handler) + } else { + DefaultServeMux.register(pattern, HandlerFunc(handler)) + } +} + +func (mux *ServeMux) register(pattern string, handler Handler) { + if err := mux.registerErr(pattern, handler); err != nil { + panic(err) + } +} + +func (mux *ServeMux) registerErr(patstr string, handler Handler) error { + if patstr == "" { + return errors.New("http: invalid pattern") + } + if handler == nil { + return errors.New("http: nil handler") + } + if f, ok := handler.(HandlerFunc); ok && f == nil { + return errors.New("http: nil handler") + } + + pat, err := parsePattern(patstr) + if err != nil { + return fmt.Errorf("parsing %q: %w", patstr, err) + } + + // Get the caller's location, for better conflict error messages. + // Skip register and whatever calls it. + _, file, line, ok := runtime.Caller(3) + if !ok { + pat.loc = "unknown location" + } else { + pat.loc = fmt.Sprintf("%s:%d", file, line) + } + + mux.mu.Lock() + defer mux.mu.Unlock() + // Check for conflict. + if err := mux.index.possiblyConflictingPatterns(pat, func(pat2 *pattern) error { + if pat.conflictsWith(pat2) { + d := describeConflict(pat, pat2) + return fmt.Errorf("pattern %q (registered at %s) conflicts with pattern %q (registered at %s):\n%s", + pat, pat.loc, pat2, pat2.loc, d) + } + return nil + }); err != nil { + return err + } + mux.tree.addPattern(pat, handler) + mux.index.addPattern(pat) + mux.patterns = append(mux.patterns, pat) + return nil +} + +// Serve accepts incoming HTTP connections on the listener l, +// creating a new service goroutine for each. The service goroutines +// read requests and then call handler to reply to them. +// +// The handler is typically nil, in which case [DefaultServeMux] is used. +// +// HTTP/2 support is only enabled if the Listener returns [*tls.Conn] +// connections and they were configured with "h2" in the TLS +// Config.NextProtos. +// +// Serve always returns a non-nil error. +func Serve(l net.Listener, handler Handler) error { + srv := &Server{Handler: handler} + return srv.Serve(l) +} + +// ServeTLS accepts incoming HTTPS connections on the listener l, +// creating a new service goroutine for each. The service goroutines +// read requests and then call handler to reply to them. +// +// The handler is typically nil, in which case [DefaultServeMux] is used. +// +// Additionally, files containing a certificate and matching private key +// for the server must be provided. If the certificate is signed by a +// certificate authority, the certFile should be the concatenation +// of the server's certificate, any intermediates, and the CA's certificate. +// +// ServeTLS always returns a non-nil error. +func ServeTLS(l net.Listener, handler Handler, certFile, keyFile string) error { + srv := &Server{Handler: handler} + return srv.ServeTLS(l, certFile, keyFile) +} + +// A Server defines parameters for running an HTTP server. +// The zero value for Server is a valid configuration. +type Server struct { + // Addr optionally specifies the TCP address for the server to listen on, + // in the form "host:port". If empty, ":http" (port 80) is used. + // The service names are defined in RFC 6335 and assigned by IANA. + // See net.Dial for details of the address format. + Addr string + + Handler Handler // handler to invoke, http.DefaultServeMux if nil + + // DisableGeneralOptionsHandler, if true, passes "OPTIONS *" requests to the Handler, + // otherwise responds with 200 OK and Content-Length: 0. + DisableGeneralOptionsHandler bool + + // TLSConfig optionally provides a TLS configuration for use + // by ServeTLS and ListenAndServeTLS. Note that this value is + // cloned by ServeTLS and ListenAndServeTLS, so it's not + // possible to modify the configuration with methods like + // tls.Config.SetSessionTicketKeys. To use + // SetSessionTicketKeys, use Server.Serve with a TLS Listener + // instead. + TLSConfig *tls.Config + + // ReadTimeout is the maximum duration for reading the entire + // request, including the body. A zero or negative value means + // there will be no timeout. + // + // Because ReadTimeout does not let Handlers make per-request + // decisions on each request body's acceptable deadline or + // upload rate, most users will prefer to use + // ReadHeaderTimeout. It is valid to use them both. + ReadTimeout time.Duration + + // ReadHeaderTimeout is the amount of time allowed to read + // request headers. The connection's read deadline is reset + // after reading the headers and the Handler can decide what + // is considered too slow for the body. If zero, the value of + // ReadTimeout is used. If negative, or if zero and ReadTimeout + // is zero or negative, there is no timeout. + ReadHeaderTimeout time.Duration + + // WriteTimeout is the maximum duration before timing out + // writes of the response. It is reset whenever a new + // request's header is read. Like ReadTimeout, it does not + // let Handlers make decisions on a per-request basis. + // A zero or negative value means there will be no timeout. + WriteTimeout time.Duration + + // IdleTimeout is the maximum amount of time to wait for the + // next request when keep-alives are enabled. If zero, the value + // of ReadTimeout is used. If negative, or if zero and ReadTimeout + // is zero or negative, there is no timeout. + IdleTimeout time.Duration + + // MaxHeaderBytes controls the maximum number of bytes the + // server will read parsing the request header's keys and + // values, including the request line. It does not limit the + // size of the request body. + // If zero, DefaultMaxHeaderBytes is used. + MaxHeaderBytes int + + // TLSNextProto optionally specifies a function to take over + // ownership of the provided TLS connection when an ALPN + // protocol upgrade has occurred. The map key is the protocol + // name negotiated. The Handler argument should be used to + // handle HTTP requests and will initialize the Request's TLS + // and RemoteAddr if not already set. The connection is + // automatically closed when the function returns. + // If TLSNextProto is not nil, HTTP/2 support is not enabled + // automatically. + TLSNextProto map[string]func(*Server, *tls.Conn, Handler) + + // ConnState specifies an optional callback function that is + // called when a client connection changes state. See the + // ConnState type and associated constants for details. + ConnState func(net.Conn, ConnState) + + // ErrorLog specifies an optional logger for errors accepting + // connections, unexpected behavior from handlers, and + // underlying FileSystem errors. + // If nil, logging is done via the log package's standard logger. + ErrorLog *log.Logger + + // BaseContext optionally specifies a function that returns + // the base context for incoming requests on this server. + // The provided Listener is the specific Listener that's + // about to start accepting requests. + // If BaseContext is nil, the default is context.Background(). + // If non-nil, it must return a non-nil context. + BaseContext func(net.Listener) context.Context + + // ConnContext optionally specifies a function that modifies + // the context used for a new connection c. The provided ctx + // is derived from the base context and has a ServerContextKey + // value. + ConnContext func(ctx context.Context, c net.Conn) context.Context + + inShutdown atomic.Bool // true when server is in shutdown + + disableKeepAlives atomic.Bool + nextProtoOnce sync.Once // guards setupHTTP2_* init + nextProtoErr error // result of http2.ConfigureServer if used + + mu sync.Mutex + listeners map[*net.Listener]struct{} + activeConn map[*conn]struct{} + onShutdown []func() + + listenerGroup sync.WaitGroup +} + +// Close immediately closes all active net.Listeners and any +// connections in state [StateNew], [StateActive], or [StateIdle]. For a +// graceful shutdown, use [Server.Shutdown]. +// +// Close does not attempt to close (and does not even know about) +// any hijacked connections, such as WebSockets. +// +// Close returns any error returned from closing the [Server]'s +// underlying Listener(s). +func (srv *Server) Close() error { + srv.inShutdown.Store(true) + srv.mu.Lock() + defer srv.mu.Unlock() + err := srv.closeListenersLocked() + + // Unlock srv.mu while waiting for listenerGroup. + // The group Add and Done calls are made with srv.mu held, + // to avoid adding a new listener in the window between + // us setting inShutdown above and waiting here. + srv.mu.Unlock() + srv.listenerGroup.Wait() + srv.mu.Lock() + + for c := range srv.activeConn { + c.rwc.Close() + delete(srv.activeConn, c) + } + return err +} + +// shutdownPollIntervalMax is the max polling interval when checking +// quiescence during Server.Shutdown. Polling starts with a small +// interval and backs off to the max. +// Ideally we could find a solution that doesn't involve polling, +// but which also doesn't have a high runtime cost (and doesn't +// involve any contentious mutexes), but that is left as an +// exercise for the reader. +const shutdownPollIntervalMax = 500 * time.Millisecond + +// Shutdown gracefully shuts down the server without interrupting any +// active connections. Shutdown works by first closing all open +// listeners, then closing all idle connections, and then waiting +// indefinitely for connections to return to idle and then shut down. +// If the provided context expires before the shutdown is complete, +// Shutdown returns the context's error, otherwise it returns any +// error returned from closing the [Server]'s underlying Listener(s). +// +// When Shutdown is called, [Serve], [ListenAndServe], and +// [ListenAndServeTLS] immediately return [ErrServerClosed]. Make sure the +// program doesn't exit and waits instead for Shutdown to return. +// +// Shutdown does not attempt to close nor wait for hijacked +// connections such as WebSockets. The caller of Shutdown should +// separately notify such long-lived connections of shutdown and wait +// for them to close, if desired. See [Server.RegisterOnShutdown] for a way to +// register shutdown notification functions. +// +// Once Shutdown has been called on a server, it may not be reused; +// future calls to methods such as Serve will return ErrServerClosed. +func (srv *Server) Shutdown(ctx context.Context) error { + srv.inShutdown.Store(true) + + srv.mu.Lock() + lnerr := srv.closeListenersLocked() + for _, f := range srv.onShutdown { + go f() + } + srv.mu.Unlock() + srv.listenerGroup.Wait() + + pollIntervalBase := time.Millisecond + nextPollInterval := func() time.Duration { + // Add 10% jitter. + interval := pollIntervalBase + time.Duration(rand.Intn(int(pollIntervalBase/10))) + // Double and clamp for next time. + pollIntervalBase *= 2 + if pollIntervalBase > shutdownPollIntervalMax { + pollIntervalBase = shutdownPollIntervalMax + } + return interval + } + + timer := time.NewTimer(nextPollInterval()) + defer timer.Stop() + for { + if srv.closeIdleConns() { + return lnerr + } + select { + case <-ctx.Done(): + return ctx.Err() + case <-timer.C: + timer.Reset(nextPollInterval()) + } + } +} + +// RegisterOnShutdown registers a function to call on [Server.Shutdown]. +// This can be used to gracefully shutdown connections that have +// undergone ALPN protocol upgrade or that have been hijacked. +// This function should start protocol-specific graceful shutdown, +// but should not wait for shutdown to complete. +func (srv *Server) RegisterOnShutdown(f func()) { + srv.mu.Lock() + srv.onShutdown = append(srv.onShutdown, f) + srv.mu.Unlock() +} + +// closeIdleConns closes all idle connections and reports whether the +// server is quiescent. +func (s *Server) closeIdleConns() bool { + s.mu.Lock() + defer s.mu.Unlock() + quiescent := true + for c := range s.activeConn { + st, unixSec := c.getState() + // Issue 22682: treat StateNew connections as if + // they're idle if we haven't read the first request's + // header in over 5 seconds. + if st == StateNew && unixSec < time.Now().Unix()-5 { + st = StateIdle + } + if st != StateIdle || unixSec == 0 { + // Assume unixSec == 0 means it's a very new + // connection, without state set yet. + quiescent = false + continue + } + c.rwc.Close() + delete(s.activeConn, c) + } + return quiescent +} + +func (s *Server) closeListenersLocked() error { + var err error + for ln := range s.listeners { + if cerr := (*ln).Close(); cerr != nil && err == nil { + err = cerr + } + } + return err +} + +// A ConnState represents the state of a client connection to a server. +// It's used by the optional [Server.ConnState] hook. +type ConnState int + +const ( + // StateNew represents a new connection that is expected to + // send a request immediately. Connections begin at this + // state and then transition to either StateActive or + // StateClosed. + StateNew ConnState = iota + + // StateActive represents a connection that has read 1 or more + // bytes of a request. The Server.ConnState hook for + // StateActive fires before the request has entered a handler + // and doesn't fire again until the request has been + // handled. After the request is handled, the state + // transitions to StateClosed, StateHijacked, or StateIdle. + // For HTTP/2, StateActive fires on the transition from zero + // to one active request, and only transitions away once all + // active requests are complete. That means that ConnState + // cannot be used to do per-request work; ConnState only notes + // the overall state of the connection. + StateActive + + // StateIdle represents a connection that has finished + // handling a request and is in the keep-alive state, waiting + // for a new request. Connections transition from StateIdle + // to either StateActive or StateClosed. + StateIdle + + // StateHijacked represents a hijacked connection. + // This is a terminal state. It does not transition to StateClosed. + StateHijacked + + // StateClosed represents a closed connection. + // This is a terminal state. Hijacked connections do not + // transition to StateClosed. + StateClosed +) + +var stateName = map[ConnState]string{ + StateNew: "new", + StateActive: "active", + StateIdle: "idle", + StateHijacked: "hijacked", + StateClosed: "closed", +} + +func (c ConnState) String() string { + return stateName[c] +} + +// serverHandler delegates to either the server's Handler or +// DefaultServeMux and also handles "OPTIONS *" requests. +type serverHandler struct { + srv *Server +} + +// ServeHTTP should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/erda-project/erda-infra +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname badServeHTTP net/http.serverHandler.ServeHTTP +func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { + handler := sh.srv.Handler + if handler == nil { + handler = DefaultServeMux + } + if !sh.srv.DisableGeneralOptionsHandler && req.RequestURI == "*" && req.Method == "OPTIONS" { + handler = globalOptionsHandler{} + } + + handler.ServeHTTP(rw, req) +} + +func badServeHTTP(serverHandler, ResponseWriter, *Request) + +// AllowQuerySemicolons returns a handler that serves requests by converting any +// unescaped semicolons in the URL query to ampersands, and invoking the handler h. +// +// This restores the pre-Go 1.17 behavior of splitting query parameters on both +// semicolons and ampersands. (See golang.org/issue/25192). Note that this +// behavior doesn't match that of many proxies, and the mismatch can lead to +// security issues. +// +// AllowQuerySemicolons should be invoked before [Request.ParseForm] is called. +func AllowQuerySemicolons(h Handler) Handler { + return HandlerFunc(func(w ResponseWriter, r *Request) { + if strings.Contains(r.URL.RawQuery, ";") { + r2 := new(Request) + *r2 = *r + r2.URL = new(url.URL) + *r2.URL = *r.URL + r2.URL.RawQuery = strings.ReplaceAll(r.URL.RawQuery, ";", "&") + h.ServeHTTP(w, r2) + } else { + h.ServeHTTP(w, r) + } + }) +} + +// ListenAndServe listens on the TCP network address srv.Addr and then +// calls [Serve] to handle requests on incoming connections. +// Accepted connections are configured to enable TCP keep-alives. +// +// If srv.Addr is blank, ":http" is used. +// +// ListenAndServe always returns a non-nil error. After [Server.Shutdown] or [Server.Close], +// the returned error is [ErrServerClosed]. +func (srv *Server) ListenAndServe() error { + if srv.shuttingDown() { + return ErrServerClosed + } + addr := srv.Addr + if addr == "" { + addr = ":http" + } + ln, err := net.Listen("tcp", addr) + if err != nil { + return err + } + return srv.Serve(ln) +} + +var testHookServerServe func(*Server, net.Listener) // used if non-nil + +// shouldConfigureHTTP2ForServe reports whether Server.Serve should configure +// automatic HTTP/2. (which sets up the srv.TLSNextProto map) +func (srv *Server) shouldConfigureHTTP2ForServe() bool { + if srv.TLSConfig == nil { + // Compatibility with Go 1.6: + // If there's no TLSConfig, it's possible that the user just + // didn't set it on the http.Server, but did pass it to + // tls.NewListener and passed that listener to Serve. + // So we should configure HTTP/2 (to set up srv.TLSNextProto) + // in case the listener returns an "h2" *tls.Conn. + return true + } + // The user specified a TLSConfig on their http.Server. + // In this, case, only configure HTTP/2 if their tls.Config + // explicitly mentions "h2". Otherwise http2.ConfigureServer + // would modify the tls.Config to add it, but they probably already + // passed this tls.Config to tls.NewListener. And if they did, + // it's too late anyway to fix it. It would only be potentially racy. + // See Issue 15908. + return slices.Contains(srv.TLSConfig.NextProtos, http2NextProtoTLS) +} + +// ErrServerClosed is returned by the [Server.Serve], [ServeTLS], [ListenAndServe], +// and [ListenAndServeTLS] methods after a call to [Server.Shutdown] or [Server.Close]. +var ErrServerClosed = errors.New("http: Server closed") + +// Serve accepts incoming connections on the Listener l, creating a +// new service goroutine for each. The service goroutines read requests and +// then call srv.Handler to reply to them. +// +// HTTP/2 support is only enabled if the Listener returns [*tls.Conn] +// connections and they were configured with "h2" in the TLS +// Config.NextProtos. +// +// Serve always returns a non-nil error and closes l. +// After [Server.Shutdown] or [Server.Close], the returned error is [ErrServerClosed]. +func (srv *Server) Serve(l net.Listener) error { + if fn := testHookServerServe; fn != nil { + fn(srv, l) // call hook with unwrapped listener + } + + origListener := l + l = &onceCloseListener{Listener: l} + defer l.Close() + + if err := srv.setupHTTP2_Serve(); err != nil { + return err + } + + if !srv.trackListener(&l, true) { + return ErrServerClosed + } + defer srv.trackListener(&l, false) + + baseCtx := context.Background() + if srv.BaseContext != nil { + baseCtx = srv.BaseContext(origListener) + if baseCtx == nil { + panic("BaseContext returned a nil context") + } + } + + var tempDelay time.Duration // how long to sleep on accept failure + + ctx := context.WithValue(baseCtx, ServerContextKey, srv) + for { + rw, err := l.Accept() + if err != nil { + if srv.shuttingDown() { + return ErrServerClosed + } + if ne, ok := err.(net.Error); ok && ne.Temporary() { + if tempDelay == 0 { + tempDelay = 5 * time.Millisecond + } else { + tempDelay *= 2 + } + if max := 1 * time.Second; tempDelay > max { + tempDelay = max + } + srv.logf("http: Accept error: %v; retrying in %v", err, tempDelay) + time.Sleep(tempDelay) + continue + } + return err + } + connCtx := ctx + if cc := srv.ConnContext; cc != nil { + connCtx = cc(connCtx, rw) + if connCtx == nil { + panic("ConnContext returned nil") + } + } + tempDelay = 0 + c := srv.newConn(rw) + c.setState(c.rwc, StateNew, runHooks) // before Serve can return + go c.serve(connCtx) + } +} + +// ServeTLS accepts incoming connections on the Listener l, creating a +// new service goroutine for each. The service goroutines perform TLS +// setup and then read requests, calling srv.Handler to reply to them. +// +// Files containing a certificate and matching private key for the +// server must be provided if neither the [Server]'s +// TLSConfig.Certificates, TLSConfig.GetCertificate nor +// config.GetConfigForClient are populated. +// If the certificate is signed by a certificate authority, the +// certFile should be the concatenation of the server's certificate, +// any intermediates, and the CA's certificate. +// +// ServeTLS always returns a non-nil error. After [Server.Shutdown] or [Server.Close], the +// returned error is [ErrServerClosed]. +func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error { + // Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig + // before we clone it and create the TLS Listener. + if err := srv.setupHTTP2_ServeTLS(); err != nil { + return err + } + + config := cloneTLSConfig(srv.TLSConfig) + if !slices.Contains(config.NextProtos, "http/1.1") { + config.NextProtos = append(config.NextProtos, "http/1.1") + } + + configHasCert := len(config.Certificates) > 0 || config.GetCertificate != nil || config.GetConfigForClient != nil + if !configHasCert || certFile != "" || keyFile != "" { + var err error + config.Certificates = make([]tls.Certificate, 1) + config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return err + } + } + + tlsListener := tls.NewListener(l, config) + return srv.Serve(tlsListener) +} + +// trackListener adds or removes a net.Listener to the set of tracked +// listeners. +// +// We store a pointer to interface in the map set, in case the +// net.Listener is not comparable. This is safe because we only call +// trackListener via Serve and can track+defer untrack the same +// pointer to local variable there. We never need to compare a +// Listener from another caller. +// +// It reports whether the server is still up (not Shutdown or Closed). +func (s *Server) trackListener(ln *net.Listener, add bool) bool { + s.mu.Lock() + defer s.mu.Unlock() + if s.listeners == nil { + s.listeners = make(map[*net.Listener]struct{}) + } + if add { + if s.shuttingDown() { + return false + } + s.listeners[ln] = struct{}{} + s.listenerGroup.Add(1) + } else { + delete(s.listeners, ln) + s.listenerGroup.Done() + } + return true +} + +func (s *Server) trackConn(c *conn, add bool) { + s.mu.Lock() + defer s.mu.Unlock() + if s.activeConn == nil { + s.activeConn = make(map[*conn]struct{}) + } + if add { + s.activeConn[c] = struct{}{} + } else { + delete(s.activeConn, c) + } +} + +func (s *Server) idleTimeout() time.Duration { + if s.IdleTimeout != 0 { + return s.IdleTimeout + } + return s.ReadTimeout +} + +func (s *Server) readHeaderTimeout() time.Duration { + if s.ReadHeaderTimeout != 0 { + return s.ReadHeaderTimeout + } + return s.ReadTimeout +} + +func (s *Server) doKeepAlives() bool { + return !s.disableKeepAlives.Load() && !s.shuttingDown() +} + +func (s *Server) shuttingDown() bool { + return s.inShutdown.Load() +} + +// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled. +// By default, keep-alives are always enabled. Only very +// resource-constrained environments or servers in the process of +// shutting down should disable them. +func (srv *Server) SetKeepAlivesEnabled(v bool) { + if v { + srv.disableKeepAlives.Store(false) + return + } + srv.disableKeepAlives.Store(true) + + // Close idle HTTP/1 conns: + srv.closeIdleConns() + + // TODO: Issue 26303: close HTTP/2 conns as soon as they become idle. +} + +func (s *Server) logf(format string, args ...any) { + if s.ErrorLog != nil { + s.ErrorLog.Printf(format, args...) + } else { + log.Printf(format, args...) + } +} + +// logf prints to the ErrorLog of the *Server associated with request r +// via ServerContextKey. If there's no associated server, or if ErrorLog +// is nil, logging is done via the log package's standard logger. +func logf(r *Request, format string, args ...any) { + s, _ := r.Context().Value(ServerContextKey).(*Server) + if s != nil && s.ErrorLog != nil { + s.ErrorLog.Printf(format, args...) + } else { + log.Printf(format, args...) + } +} + +// ListenAndServe listens on the TCP network address addr and then calls +// [Serve] with handler to handle requests on incoming connections. +// Accepted connections are configured to enable TCP keep-alives. +// +// The handler is typically nil, in which case [DefaultServeMux] is used. +// +// ListenAndServe always returns a non-nil error. +func ListenAndServe(addr string, handler Handler) error { + server := &Server{Addr: addr, Handler: handler} + return server.ListenAndServe() +} + +// ListenAndServeTLS acts identically to [ListenAndServe], except that it +// expects HTTPS connections. Additionally, files containing a certificate and +// matching private key for the server must be provided. If the certificate +// is signed by a certificate authority, the certFile should be the concatenation +// of the server's certificate, any intermediates, and the CA's certificate. +func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error { + server := &Server{Addr: addr, Handler: handler} + return server.ListenAndServeTLS(certFile, keyFile) +} + +// ListenAndServeTLS listens on the TCP network address srv.Addr and +// then calls [ServeTLS] to handle requests on incoming TLS connections. +// Accepted connections are configured to enable TCP keep-alives. +// +// Filenames containing a certificate and matching private key for the +// server must be provided if neither the [Server]'s TLSConfig.Certificates +// nor TLSConfig.GetCertificate are populated. If the certificate is +// signed by a certificate authority, the certFile should be the +// concatenation of the server's certificate, any intermediates, and +// the CA's certificate. +// +// If srv.Addr is blank, ":https" is used. +// +// ListenAndServeTLS always returns a non-nil error. After [Server.Shutdown] or +// [Server.Close], the returned error is [ErrServerClosed]. +func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { + if srv.shuttingDown() { + return ErrServerClosed + } + addr := srv.Addr + if addr == "" { + addr = ":https" + } + + ln, err := net.Listen("tcp", addr) + if err != nil { + return err + } + + defer ln.Close() + + return srv.ServeTLS(ln, certFile, keyFile) +} + +// setupHTTP2_ServeTLS conditionally configures HTTP/2 on +// srv and reports whether there was an error setting it up. If it is +// not configured for policy reasons, nil is returned. +func (srv *Server) setupHTTP2_ServeTLS() error { + srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults) + return srv.nextProtoErr +} + +// setupHTTP2_Serve is called from (*Server).Serve and conditionally +// configures HTTP/2 on srv using a more conservative policy than +// setupHTTP2_ServeTLS because Serve is called after tls.Listen, +// and may be called concurrently. See shouldConfigureHTTP2ForServe. +// +// The tests named TestTransportAutomaticHTTP2* and +// TestConcurrentServerServe in server_test.go demonstrate some +// of the supported use cases and motivations. +func (srv *Server) setupHTTP2_Serve() error { + srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults_Serve) + return srv.nextProtoErr +} + +func (srv *Server) onceSetNextProtoDefaults_Serve() { + if srv.shouldConfigureHTTP2ForServe() { + srv.onceSetNextProtoDefaults() + } +} + +var http2server = godebug.New("http2server") + +// onceSetNextProtoDefaults configures HTTP/2, if the user hasn't +// configured otherwise. (by setting srv.TLSNextProto non-nil) +// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2_*). +func (srv *Server) onceSetNextProtoDefaults() { + if omitBundledHTTP2 { + return + } + if http2server.Value() == "0" { + http2server.IncNonDefault() + return + } + // Enable HTTP/2 by default if the user hasn't otherwise + // configured their TLSNextProto map. + if srv.TLSNextProto == nil { + conf := &http2Server{} + srv.nextProtoErr = http2ConfigureServer(srv, conf) + } +} + +// TimeoutHandler returns a [Handler] that runs h with the given time limit. +// +// The new Handler calls h.ServeHTTP to handle each request, but if a +// call runs for longer than its time limit, the handler responds with +// a 503 Service Unavailable error and the given message in its body. +// (If msg is empty, a suitable default message will be sent.) +// After such a timeout, writes by h to its [ResponseWriter] will return +// [ErrHandlerTimeout]. +// +// TimeoutHandler supports the [Pusher] interface but does not support +// the [Hijacker] or [Flusher] interfaces. +func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler { + return &timeoutHandler{ + handler: h, + body: msg, + dt: dt, + } +} + +// ErrHandlerTimeout is returned on [ResponseWriter] Write calls +// in handlers which have timed out. +var ErrHandlerTimeout = errors.New("http: Handler timeout") + +type timeoutHandler struct { + handler Handler + body string + dt time.Duration + + // When set, no context will be created and this context will + // be used instead. + testContext context.Context +} + +func (h *timeoutHandler) errorBody() string { + if h.body != "" { + return h.body + } + return "Timeout

Timeout

" +} + +func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { + ctx := h.testContext + if ctx == nil { + var cancelCtx context.CancelFunc + ctx, cancelCtx = context.WithTimeout(r.Context(), h.dt) + defer cancelCtx() + } + r = r.WithContext(ctx) + done := make(chan struct{}) + tw := &timeoutWriter{ + w: w, + h: make(Header), + req: r, + } + panicChan := make(chan any, 1) + go func() { + defer func() { + if p := recover(); p != nil { + panicChan <- p + } + }() + h.handler.ServeHTTP(tw, r) + close(done) + }() + select { + case p := <-panicChan: + panic(p) + case <-done: + tw.mu.Lock() + defer tw.mu.Unlock() + dst := w.Header() + for k, vv := range tw.h { + dst[k] = vv + } + if !tw.wroteHeader { + tw.code = StatusOK + } + w.WriteHeader(tw.code) + w.Write(tw.wbuf.Bytes()) + case <-ctx.Done(): + tw.mu.Lock() + defer tw.mu.Unlock() + switch err := ctx.Err(); err { + case context.DeadlineExceeded: + w.WriteHeader(StatusServiceUnavailable) + io.WriteString(w, h.errorBody()) + tw.err = ErrHandlerTimeout + default: + w.WriteHeader(StatusServiceUnavailable) + tw.err = err + } + } +} + +type timeoutWriter struct { + w ResponseWriter + h Header + wbuf bytes.Buffer + req *Request + + mu sync.Mutex + err error + wroteHeader bool + code int +} + +var _ Pusher = (*timeoutWriter)(nil) + +// Push implements the [Pusher] interface. +func (tw *timeoutWriter) Push(target string, opts *PushOptions) error { + if pusher, ok := tw.w.(Pusher); ok { + return pusher.Push(target, opts) + } + return ErrNotSupported +} + +func (tw *timeoutWriter) Header() Header { return tw.h } + +func (tw *timeoutWriter) Write(p []byte) (int, error) { + tw.mu.Lock() + defer tw.mu.Unlock() + if tw.err != nil { + return 0, tw.err + } + if !tw.wroteHeader { + tw.writeHeaderLocked(StatusOK) + } + return tw.wbuf.Write(p) +} + +func (tw *timeoutWriter) writeHeaderLocked(code int) { + checkWriteHeaderCode(code) + + switch { + case tw.err != nil: + return + case tw.wroteHeader: + if tw.req != nil { + caller := relevantCaller() + logf(tw.req, "http: superfluous response.WriteHeader call from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line) + } + default: + tw.wroteHeader = true + tw.code = code + } +} + +func (tw *timeoutWriter) WriteHeader(code int) { + tw.mu.Lock() + defer tw.mu.Unlock() + tw.writeHeaderLocked(code) +} + +// onceCloseListener wraps a net.Listener, protecting it from +// multiple Close calls. +type onceCloseListener struct { + net.Listener + once sync.Once + closeErr error +} + +func (oc *onceCloseListener) Close() error { + oc.once.Do(oc.close) + return oc.closeErr +} + +func (oc *onceCloseListener) close() { oc.closeErr = oc.Listener.Close() } + +// globalOptionsHandler responds to "OPTIONS *" requests. +type globalOptionsHandler struct{} + +func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) { + w.Header().Set("Content-Length", "0") + if r.ContentLength != 0 { + // Read up to 4KB of OPTIONS body (as mentioned in the + // spec as being reserved for future use), but anything + // over that is considered a waste of server resources + // (or an attack) and we abort and close the connection, + // courtesy of MaxBytesReader's EOF behavior. + mb := MaxBytesReader(w, r.Body, 4<<10) + io.Copy(io.Discard, mb) + } +} + +// initALPNRequest is an HTTP handler that initializes certain +// uninitialized fields in its *Request. Such partially-initialized +// Requests come from ALPN protocol handlers. +type initALPNRequest struct { + ctx context.Context + c *tls.Conn + h serverHandler +} + +// BaseContext is an exported but unadvertised [http.Handler] method +// recognized by x/net/http2 to pass down a context; the TLSNextProto +// API predates context support so we shoehorn through the only +// interface we have available. +func (h initALPNRequest) BaseContext() context.Context { return h.ctx } + +func (h initALPNRequest) ServeHTTP(rw ResponseWriter, req *Request) { + if req.TLS == nil { + req.TLS = &tls.ConnectionState{} + *req.TLS = h.c.ConnectionState() + } + if req.Body == nil { + req.Body = NoBody + } + if req.RemoteAddr == "" { + req.RemoteAddr = h.c.RemoteAddr().String() + } + h.h.ServeHTTP(rw, req) +} + +// loggingConn is used for debugging. +type loggingConn struct { + name string + net.Conn +} + +var ( + uniqNameMu sync.Mutex + uniqNameNext = make(map[string]int) +) + +func newLoggingConn(baseName string, c net.Conn) net.Conn { + uniqNameMu.Lock() + defer uniqNameMu.Unlock() + uniqNameNext[baseName]++ + return &loggingConn{ + name: fmt.Sprintf("%s-%d", baseName, uniqNameNext[baseName]), + Conn: c, + } +} + +func (c *loggingConn) Write(p []byte) (n int, err error) { + log.Printf("%s.Write(%d) = ....", c.name, len(p)) + n, err = c.Conn.Write(p) + log.Printf("%s.Write(%d) = %d, %v", c.name, len(p), n, err) + return +} + +func (c *loggingConn) Read(p []byte) (n int, err error) { + log.Printf("%s.Read(%d) = ....", c.name, len(p)) + n, err = c.Conn.Read(p) + log.Printf("%s.Read(%d) = %d, %v", c.name, len(p), n, err) + return +} + +func (c *loggingConn) Close() (err error) { + log.Printf("%s.Close() = ...", c.name) + err = c.Conn.Close() + log.Printf("%s.Close() = %v", c.name, err) + return +} + +// checkConnErrorWriter writes to c.rwc and records any write errors to c.werr. +// It only contains one field (and a pointer field at that), so it +// fits in an interface value without an extra allocation. +type checkConnErrorWriter struct { + c *conn +} + +func (w checkConnErrorWriter) Write(p []byte) (n int, err error) { + n, err = w.c.rwc.Write(p) + if err != nil && w.c.werr == nil { + w.c.werr = err + w.c.cancelCtx() + } + return +} + +func numLeadingCRorLF(v []byte) (n int) { + for _, b := range v { + if b == '\r' || b == '\n' { + n++ + continue + } + break + } + return +} + +// tlsRecordHeaderLooksLikeHTTP reports whether a TLS record header +// looks like it might've been a misdirected plaintext HTTP request. +func tlsRecordHeaderLooksLikeHTTP(hdr [5]byte) bool { + switch string(hdr[:]) { + case "GET /", "HEAD ", "POST ", "PUT /", "OPTIO": + return true + } + return false +} + +// MaxBytesHandler returns a [Handler] that runs h with its [ResponseWriter] and [Request.Body] wrapped by a MaxBytesReader. +func MaxBytesHandler(h Handler, n int64) Handler { + return HandlerFunc(func(w ResponseWriter, r *Request) { + r2 := *r + r2.Body = MaxBytesReader(w, r.Body, n) + h.ServeHTTP(w, &r2) + }) +} diff --git a/contrib/go/_std_1.22/src/net/http/sniff.go b/contrib/go/_std_1.23/src/net/http/sniff.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/sniff.go rename to contrib/go/_std_1.23/src/net/http/sniff.go diff --git a/contrib/go/_std_1.22/src/net/http/socks_bundle.go b/contrib/go/_std_1.23/src/net/http/socks_bundle.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/socks_bundle.go rename to contrib/go/_std_1.23/src/net/http/socks_bundle.go diff --git a/contrib/go/_std_1.22/src/net/http/status.go b/contrib/go/_std_1.23/src/net/http/status.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/status.go rename to contrib/go/_std_1.23/src/net/http/status.go diff --git a/contrib/go/_std_1.22/src/net/http/transfer.go b/contrib/go/_std_1.23/src/net/http/transfer.go similarity index 96% rename from contrib/go/_std_1.22/src/net/http/transfer.go rename to contrib/go/_std_1.23/src/net/http/transfer.go index 315c6e2723a2..5a3c6ceff578 100644 --- a/contrib/go/_std_1.22/src/net/http/transfer.go +++ b/contrib/go/_std_1.23/src/net/http/transfer.go @@ -16,7 +16,7 @@ import ( "net/http/internal/ascii" "net/textproto" "reflect" - "sort" + "slices" "strconv" "strings" "sync" @@ -318,7 +318,7 @@ func (t *transferWriter) writeHeader(w io.Writer, trace *httptrace.ClientTrace) keys = append(keys, k) } if len(keys) > 0 { - sort.Strings(keys) + slices.Sort(keys) // TODO: could do better allocation-wise here, but trailers are rare, // so being lazy for now. if _, err := io.WriteString(w, "Trailer: "+strings.Join(keys, ",")+"\r\n"); err != nil { @@ -650,19 +650,6 @@ func (t *transferReader) parseTransferEncoding() error { return &unsupportedTEError{fmt.Sprintf("unsupported transfer encoding: %q", raw[0])} } - // RFC 7230 3.3.2 says "A sender MUST NOT send a Content-Length header field - // in any message that contains a Transfer-Encoding header field." - // - // but also: "If a message is received with both a Transfer-Encoding and a - // Content-Length header field, the Transfer-Encoding overrides the - // Content-Length. Such a message might indicate an attempt to perform - // request smuggling (Section 9.5) or response splitting (Section 9.4) and - // ought to be handled as an error. A sender MUST remove the received - // Content-Length field prior to forwarding such a message downstream." - // - // Reportedly, these appear in the wild. - delete(t.Header, "Content-Length") - t.Chunked = true return nil } @@ -670,7 +657,7 @@ func (t *transferReader) parseTransferEncoding() error { // Determine the expected body length, using RFC 7230 Section 3.3. This // function is not a method, because ultimately it should be shared by // ReadResponse and ReadRequest. -func fixLength(isResponse bool, status int, requestMethod string, header Header, chunked bool) (int64, error) { +func fixLength(isResponse bool, status int, requestMethod string, header Header, chunked bool) (n int64, err error) { isRequest := !isResponse contentLens := header["Content-Length"] @@ -694,6 +681,14 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header, contentLens = header["Content-Length"] } + // Reject requests with invalid Content-Length headers. + if len(contentLens) > 0 { + n, err = parseContentLength(contentLens) + if err != nil { + return -1, err + } + } + // Logic based on response type or status if isResponse && noResponseBodyExpected(requestMethod) { return 0, nil @@ -706,17 +701,26 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header, return 0, nil } + // According to RFC 9112, "If a message is received with both a + // Transfer-Encoding and a Content-Length header field, the Transfer-Encoding + // overrides the Content-Length. Such a message might indicate an attempt to + // perform request smuggling (Section 11.2) or response splitting (Section 11.1) + // and ought to be handled as an error. An intermediary that chooses to forward + // the message MUST first remove the received Content-Length field and process + // the Transfer-Encoding (as described below) prior to forwarding the message downstream." + // + // Chunked-encoding requests with either valid Content-Length + // headers or no Content-Length headers are accepted after removing + // the Content-Length field from header. + // // Logic based on Transfer-Encoding if chunked { + header.Del("Content-Length") return -1, nil } + // Logic based on Content-Length if len(contentLens) > 0 { - // Logic based on Content-Length - n, err := parseContentLength(contentLens) - if err != nil { - return -1, err - } return n, nil } @@ -1039,7 +1043,7 @@ func (bl bodyLocked) Read(p []byte) (n int, err error) { return bl.b.readLocked(p) } -var laxContentLength = godebug.New("httplaxcontentlength") +var httplaxcontentlength = godebug.New("httplaxcontentlength") // parseContentLength checks that the header is valid and then trims // whitespace. It returns -1 if no value is set otherwise the value @@ -1053,8 +1057,8 @@ func parseContentLength(clHeaders []string) (int64, error) { // The Content-Length must be a valid numeric value. // See: https://datatracker.ietf.org/doc/html/rfc2616/#section-14.13 if cl == "" { - if laxContentLength.Value() == "1" { - laxContentLength.IncNonDefault() + if httplaxcontentlength.Value() == "1" { + httplaxcontentlength.IncNonDefault() return -1, nil } return 0, badStringError("invalid empty Content-Length", cl) diff --git a/contrib/go/_std_1.22/src/net/http/transport.go b/contrib/go/_std_1.23/src/net/http/transport.go similarity index 88% rename from contrib/go/_std_1.22/src/net/http/transport.go rename to contrib/go/_std_1.23/src/net/http/transport.go index 66c54ef5ac95..da9163a27ae6 100644 --- a/contrib/go/_std_1.22/src/net/http/transport.go +++ b/contrib/go/_std_1.23/src/net/http/transport.go @@ -30,6 +30,7 @@ import ( "sync" "sync/atomic" "time" + _ "unsafe" "golang.org/x/net/http/httpguts" "golang.org/x/net/http/httpproxy" @@ -100,7 +101,7 @@ type Transport struct { idleLRU connLRU reqMu sync.Mutex - reqCanceler map[cancelKey]func(error) + reqCanceler map[*Request]context.CancelCauseFunc altMu sync.Mutex // guards changing altProto only altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme @@ -108,14 +109,16 @@ type Transport struct { connsPerHostMu sync.Mutex connsPerHost map[connectMethodKey]int connsPerHostWait map[connectMethodKey]wantConnQueue // waiting getConns + dialsInProgress wantConnQueue // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the // request is aborted with the provided error. // // The proxy type is determined by the URL scheme. "http", - // "https", and "socks5" are supported. If the scheme is empty, + // "https", "socks5", and "socks5h" are supported. If the scheme is empty, // "http" is assumed. + // "socks5" is treated the same as "socks5h". // // If the proxy URL contains a userinfo subcomponent, // the proxy request will pass the username and password @@ -292,13 +295,6 @@ type Transport struct { ForceAttemptHTTP2 bool } -// A cancelKey is the key of the reqCanceler map. -// We wrap the *Request in this type since we want to use the original request, -// not any transient one created by roundTrip. -type cancelKey struct { - req *Request -} - func (t *Transport) writeBufferSize() int { if t.WriteBufferSize > 0 { return t.WriteBufferSize @@ -440,7 +436,6 @@ func (t *Transport) onceSetNextProtoDefaults() { // // The environment values may be either a complete URL or a // "host[:port]", in which case the "http" scheme is assumed. -// The schemes "http", "https", and "socks5" are supported. // An error is returned if the value is a different form. // // A nil URL and nil error are returned if no proxy is defined in the @@ -465,10 +460,12 @@ func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) { // optional extra headers to write and stores any error to return // from roundTrip. type transportRequest struct { - *Request // original request, not to be mutated - extra Header // extra headers to write, or nil - trace *httptrace.ClientTrace // optional - cancelKey cancelKey + *Request // original request, not to be mutated + extra Header // extra headers to write, or nil + trace *httptrace.ClientTrace // optional + + ctx context.Context // canceled when we are done with the request + cancel context.CancelCauseFunc mu sync.Mutex // guards err err error // first setError value for mapRoundTripError to consider @@ -513,8 +510,24 @@ func (t *Transport) alternateRoundTripper(req *Request) RoundTripper { return altProto[req.URL.Scheme] } +func validateHeaders(hdrs Header) string { + for k, vv := range hdrs { + if !httpguts.ValidHeaderFieldName(k) { + return fmt.Sprintf("field name %q", k) + } + for _, v := range vv { + if !httpguts.ValidHeaderFieldValue(v) { + // Don't include the value in the error, + // because it may be sensitive. + return fmt.Sprintf("field value for %q", k) + } + } + } + return "" +} + // roundTrip implements a RoundTripper over HTTP. -func (t *Transport) roundTrip(req *Request) (*Response, error) { +func (t *Transport) roundTrip(req *Request) (_ *Response, err error) { t.nextProtoOnce.Do(t.onceSetNextProtoDefaults) ctx := req.Context() trace := httptrace.ContextClientTrace(ctx) @@ -530,23 +543,20 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { scheme := req.URL.Scheme isHTTP := scheme == "http" || scheme == "https" if isHTTP { - for k, vv := range req.Header { - if !httpguts.ValidHeaderFieldName(k) { - req.closeBody() - return nil, fmt.Errorf("net/http: invalid header field name %q", k) - } - for _, v := range vv { - if !httpguts.ValidHeaderFieldValue(v) { - req.closeBody() - // Don't include the value in the error, because it may be sensitive. - return nil, fmt.Errorf("net/http: invalid header field value for %q", k) - } - } + // Validate the outgoing headers. + if err := validateHeaders(req.Header); err != "" { + req.closeBody() + return nil, fmt.Errorf("net/http: invalid header %s", err) + } + + // Validate the outgoing trailers too. + if err := validateHeaders(req.Trailer); err != "" { + req.closeBody() + return nil, fmt.Errorf("net/http: invalid trailer %s", err) } } origReq := req - cancelKey := cancelKey{origReq} req = setupRewindBody(req) if altRT := t.alternateRoundTripper(req); altRT != nil { @@ -572,16 +582,44 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { return nil, errors.New("http: no Host in request URL") } + // Transport request context. + // + // If RoundTrip returns an error, it cancels this context before returning. + // + // If RoundTrip returns no error: + // - For an HTTP/1 request, persistConn.readLoop cancels this context + // after reading the request body. + // - For an HTTP/2 request, RoundTrip cancels this context after the HTTP/2 + // RoundTripper returns. + ctx, cancel := context.WithCancelCause(req.Context()) + + // Convert Request.Cancel into context cancelation. + if origReq.Cancel != nil { + go awaitLegacyCancel(ctx, cancel, origReq) + } + + // Convert Transport.CancelRequest into context cancelation. + // + // This is lamentably expensive. CancelRequest has been deprecated for a long time + // and doesn't work on HTTP/2 requests. Perhaps we should drop support for it entirely. + cancel = t.prepareTransportCancel(origReq, cancel) + + defer func() { + if err != nil { + cancel(err) + } + }() + for { select { case <-ctx.Done(): req.closeBody() - return nil, ctx.Err() + return nil, context.Cause(ctx) default: } // treq gets modified by roundTrip, so we need to recreate for each retry. - treq := &transportRequest{Request: req, trace: trace, cancelKey: cancelKey} + treq := &transportRequest{Request: req, trace: trace, ctx: ctx, cancel: cancel} cm, err := t.connectMethodForRequest(treq) if err != nil { req.closeBody() @@ -594,7 +632,6 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { // to send it requests. pconn, err := t.getConn(treq, cm) if err != nil { - t.setReqCanceler(cancelKey, nil) req.closeBody() return nil, err } @@ -602,12 +639,19 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { var resp *Response if pconn.alt != nil { // HTTP/2 path. - t.setReqCanceler(cancelKey, nil) // not cancelable with CancelRequest resp, err = pconn.alt.RoundTrip(req) } else { resp, err = pconn.roundTrip(treq) } if err == nil { + if pconn.alt != nil { + // HTTP/2 requests are not cancelable with CancelRequest, + // so we have no further need for the request context. + // + // On the HTTP/1 path, roundTrip takes responsibility for + // canceling the context after the response body is read. + cancel(errRequestDone) + } resp.Request = origReq return resp, nil } @@ -644,6 +688,14 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { } } +func awaitLegacyCancel(ctx context.Context, cancel context.CancelCauseFunc, req *Request) { + select { + case <-req.Cancel: + cancel(errRequestCanceled) + case <-ctx.Done(): + } +} + var errCannotRewind = errors.New("net/http: cannot rewind body after connection loss") type readTrackingBody struct { @@ -793,35 +845,54 @@ func (t *Transport) CloseIdleConnections() { pconn.close(errCloseIdleConns) } } + t.connsPerHostMu.Lock() + t.dialsInProgress.all(func(w *wantConn) { + if w.cancelCtx != nil && !w.waiting() { + w.cancelCtx() + } + }) + t.connsPerHostMu.Unlock() if t2 := t.h2transport; t2 != nil { t2.CloseIdleConnections() } } +// prepareTransportCancel sets up state to convert Transport.CancelRequest into context cancelation. +func (t *Transport) prepareTransportCancel(req *Request, origCancel context.CancelCauseFunc) context.CancelCauseFunc { + // Historically, RoundTrip has not modified the Request in any way. + // We could avoid the need to keep a map of all in-flight requests by adding + // a field to the Request containing its cancel func, and setting that field + // while the request is in-flight. Callers aren't supposed to reuse a Request + // until after the response body is closed, so this wouldn't violate any + // concurrency guarantees. + cancel := func(err error) { + origCancel(err) + t.reqMu.Lock() + delete(t.reqCanceler, req) + t.reqMu.Unlock() + } + t.reqMu.Lock() + if t.reqCanceler == nil { + t.reqCanceler = make(map[*Request]context.CancelCauseFunc) + } + t.reqCanceler[req] = cancel + t.reqMu.Unlock() + return cancel +} + // CancelRequest cancels an in-flight request by closing its connection. // CancelRequest should only be called after [Transport.RoundTrip] has returned. // // Deprecated: Use [Request.WithContext] to create a request with a // cancelable context instead. CancelRequest cannot cancel HTTP/2 -// requests. +// requests. This may become a no-op in a future release of Go. func (t *Transport) CancelRequest(req *Request) { - t.cancelRequest(cancelKey{req}, errRequestCanceled) -} - -// Cancel an in-flight request, recording the error value. -// Returns whether the request was canceled. -func (t *Transport) cancelRequest(key cancelKey, err error) bool { - // This function must not return until the cancel func has completed. - // See: https://golang.org/issue/34658 t.reqMu.Lock() - defer t.reqMu.Unlock() - cancel := t.reqCanceler[key] - delete(t.reqCanceler, key) + cancel := t.reqCanceler[req] + t.reqMu.Unlock() if cancel != nil { - cancel(err) + cancel(errRequestCanceled) } - - return cancel != nil } // @@ -957,7 +1028,7 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error { // Loop over the waiting list until we find a w that isn't done already, and hand it pconn. for q.len() > 0 { w := q.popFront() - if w.tryDeliver(pconn, nil) { + if w.tryDeliver(pconn, nil, time.Time{}) { done = true break } @@ -969,7 +1040,7 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error { // list unconditionally, for any future clients too. for q.len() > 0 { w := q.popFront() - w.tryDeliver(pconn, nil) + w.tryDeliver(pconn, nil, time.Time{}) } } if q.len() == 0 { @@ -1073,7 +1144,7 @@ func (t *Transport) queueForIdleConn(w *wantConn) (delivered bool) { list = list[:len(list)-1] continue } - delivered = w.tryDeliver(pconn, nil) + delivered = w.tryDeliver(pconn, nil, pconn.idleAt) if delivered { if pconn.alt != nil { // HTTP/2: multiple clients can share pconn. @@ -1102,7 +1173,7 @@ func (t *Transport) queueForIdleConn(w *wantConn) (delivered bool) { t.idleConnWait = make(map[connectMethodKey]wantConnQueue) } q := t.idleConnWait[w.key] - q.cleanFront() + q.cleanFrontNotWaiting() q.pushBack(w) t.idleConnWait[w.key] = q return false @@ -1148,38 +1219,6 @@ func (t *Transport) removeIdleConnLocked(pconn *persistConn) bool { return removed } -func (t *Transport) setReqCanceler(key cancelKey, fn func(error)) { - t.reqMu.Lock() - defer t.reqMu.Unlock() - if t.reqCanceler == nil { - t.reqCanceler = make(map[cancelKey]func(error)) - } - if fn != nil { - t.reqCanceler[key] = fn - } else { - delete(t.reqCanceler, key) - } -} - -// replaceReqCanceler replaces an existing cancel function. If there is no cancel function -// for the request, we don't set the function and return false. -// Since CancelRequest will clear the canceler, we can use the return value to detect if -// the request was canceled since the last setReqCancel call. -func (t *Transport) replaceReqCanceler(key cancelKey, fn func(error)) bool { - t.reqMu.Lock() - defer t.reqMu.Unlock() - _, ok := t.reqCanceler[key] - if !ok { - return false - } - if fn != nil { - t.reqCanceler[key] = fn - } else { - delete(t.reqCanceler, key) - } - return true -} - var zeroDialer net.Dialer func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, error) { @@ -1207,9 +1246,8 @@ func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, e // These three options are racing against each other and use // wantConn to coordinate and agree about the winning outcome. type wantConn struct { - cm connectMethod - key connectMethodKey // cm.key() - ready chan struct{} // closed when pc, err pair is delivered + cm connectMethod + key connectMethodKey // cm.key() // hooks for testing to know when dials are done // beforeDial is called in the getConn goroutine when the dial is queued. @@ -1217,45 +1255,52 @@ type wantConn struct { beforeDial func() afterDial func() - mu sync.Mutex // protects ctx, pc, err, close(ready) - ctx context.Context // context for dial, cleared after delivered or canceled - pc *persistConn - err error + mu sync.Mutex // protects ctx, done and sending of the result + ctx context.Context // context for dial, cleared after delivered or canceled + cancelCtx context.CancelFunc + done bool // true after delivered or canceled + result chan connOrError // channel to deliver connection or error +} + +type connOrError struct { + pc *persistConn + err error + idleAt time.Time } // waiting reports whether w is still waiting for an answer (connection or error). func (w *wantConn) waiting() bool { - select { - case <-w.ready: - return false - default: - return true - } + w.mu.Lock() + defer w.mu.Unlock() + + return !w.done } // getCtxForDial returns context for dial or nil if connection was delivered or canceled. func (w *wantConn) getCtxForDial() context.Context { w.mu.Lock() defer w.mu.Unlock() + return w.ctx } // tryDeliver attempts to deliver pc, err to w and reports whether it succeeded. -func (w *wantConn) tryDeliver(pc *persistConn, err error) bool { +func (w *wantConn) tryDeliver(pc *persistConn, err error, idleAt time.Time) bool { w.mu.Lock() defer w.mu.Unlock() - if w.pc != nil || w.err != nil { + if w.done { return false } - - w.ctx = nil - w.pc = pc - w.err = err - if w.pc == nil && w.err == nil { + if (pc == nil) == (err == nil) { panic("net/http: internal error: misuse of tryDeliver") } - close(w.ready) + w.ctx = nil + w.done = true + + w.result <- connOrError{pc: pc, err: err, idleAt: idleAt} + close(w.result) + return true } @@ -1263,13 +1308,16 @@ func (w *wantConn) tryDeliver(pc *persistConn, err error) bool { // If a connection has been delivered already, cancel returns it with t.putOrCloseIdleConn. func (w *wantConn) cancel(t *Transport, err error) { w.mu.Lock() - if w.pc == nil && w.err == nil { - close(w.ready) // catch misbehavior in future delivery + var pc *persistConn + if w.done { + if r, ok := <-w.result; ok { + pc = r.pc + } + } else { + close(w.result) } - pc := w.pc w.ctx = nil - w.pc = nil - w.err = err + w.done = true w.mu.Unlock() if pc != nil { @@ -1330,9 +1378,9 @@ func (q *wantConnQueue) peekFront() *wantConn { return nil } -// cleanFront pops any wantConns that are no longer waiting from the head of the +// cleanFrontNotWaiting pops any wantConns that are no longer waiting from the head of the // queue, reporting whether any were popped. -func (q *wantConnQueue) cleanFront() (cleaned bool) { +func (q *wantConnQueue) cleanFrontNotWaiting() (cleaned bool) { for { w := q.peekFront() if w == nil || w.waiting() { @@ -1343,6 +1391,28 @@ func (q *wantConnQueue) cleanFront() (cleaned bool) { } } +// cleanFrontCanceled pops any wantConns with canceled dials from the head of the queue. +func (q *wantConnQueue) cleanFrontCanceled() { + for { + w := q.peekFront() + if w == nil || w.cancelCtx != nil { + return + } + q.popFront() + } +} + +// all iterates over all wantConns in the queue. +// The caller must not modify the queue while iterating. +func (q *wantConnQueue) all(f func(*wantConn)) { + for _, w := range q.head[q.headPos:] { + f(w) + } + for _, w := range q.tail { + f(w) + } +} + func (t *Transport) customDialTLS(ctx context.Context, network, addr string) (conn net.Conn, err error) { if t.DialTLSContext != nil { conn, err = t.DialTLSContext(ctx, network, addr) @@ -1359,7 +1429,7 @@ func (t *Transport) customDialTLS(ctx context.Context, network, addr string) (co // specified in the connectMethod. This includes doing a proxy CONNECT // and/or setting up TLS. If this doesn't return an error, the persistConn // is ready to write requests to. -func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persistConn, err error) { +func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (_ *persistConn, err error) { req := treq.Request trace := treq.trace ctx := req.Context() @@ -1367,11 +1437,19 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi trace.GetConn(cm.addr()) } + // Detach from the request context's cancellation signal. + // The dial should proceed even if the request is canceled, + // because a future request may be able to make use of the connection. + // + // We retain the request context's values. + dialCtx, dialCancel := context.WithCancel(context.WithoutCancel(ctx)) + w := &wantConn{ cm: cm, key: cm.key(), - ctx: ctx, - ready: make(chan struct{}, 1), + ctx: dialCtx, + cancelCtx: dialCancel, + result: make(chan connOrError, 1), beforeDial: testHookPrePendingDial, afterDial: testHookPostPendingDial, } @@ -1382,44 +1460,33 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi }() // Queue for idle connection. - if delivered := t.queueForIdleConn(w); delivered { - pc := w.pc - // Trace only for HTTP/1. - // HTTP/2 calls trace.GotConn itself. - if pc.alt == nil && trace != nil && trace.GotConn != nil { - trace.GotConn(pc.gotIdleConnTrace(pc.idleAt)) - } - // set request canceler to some non-nil function so we - // can detect whether it was cleared between now and when - // we enter roundTrip - t.setReqCanceler(treq.cancelKey, func(error) {}) - return pc, nil + if delivered := t.queueForIdleConn(w); !delivered { + t.queueForDial(w) } - cancelc := make(chan error, 1) - t.setReqCanceler(treq.cancelKey, func(err error) { cancelc <- err }) - - // Queue for permission to dial. - t.queueForDial(w) - // Wait for completion or cancellation. select { - case <-w.ready: + case r := <-w.result: // Trace success but only for HTTP/1. // HTTP/2 calls trace.GotConn itself. - if w.pc != nil && w.pc.alt == nil && trace != nil && trace.GotConn != nil { - trace.GotConn(httptrace.GotConnInfo{Conn: w.pc.conn, Reused: w.pc.isReused()}) + if r.pc != nil && r.pc.alt == nil && trace != nil && trace.GotConn != nil { + info := httptrace.GotConnInfo{ + Conn: r.pc.conn, + Reused: r.pc.isReused(), + } + if !r.idleAt.IsZero() { + info.WasIdle = true + info.IdleTime = time.Since(r.idleAt) + } + trace.GotConn(info) } - if w.err != nil { + if r.err != nil { // If the request has been canceled, that's probably - // what caused w.err; if so, prefer to return the + // what caused r.err; if so, prefer to return the // cancellation error (see golang.org/issue/16049). select { - case <-req.Cancel: - return nil, errRequestCanceledConn - case <-req.Context().Done(): - return nil, req.Context().Err() - case err := <-cancelc: + case <-treq.ctx.Done(): + err := context.Cause(treq.ctx) if err == errRequestCanceled { err = errRequestCanceledConn } @@ -1428,12 +1495,9 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi // return below } } - return w.pc, w.err - case <-req.Cancel: - return nil, errRequestCanceledConn - case <-req.Context().Done(): - return nil, req.Context().Err() - case err := <-cancelc: + return r.pc, r.err + case <-treq.ctx.Done(): + err := context.Cause(treq.ctx) if err == errRequestCanceled { err = errRequestCanceledConn } @@ -1445,20 +1509,21 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi // Once w receives permission to dial, it will do so in a separate goroutine. func (t *Transport) queueForDial(w *wantConn) { w.beforeDial() - if t.MaxConnsPerHost <= 0 { - go t.dialConnFor(w) - return - } t.connsPerHostMu.Lock() defer t.connsPerHostMu.Unlock() + if t.MaxConnsPerHost <= 0 { + t.startDialConnForLocked(w) + return + } + if n := t.connsPerHost[w.key]; n < t.MaxConnsPerHost { if t.connsPerHost == nil { t.connsPerHost = make(map[connectMethodKey]int) } t.connsPerHost[w.key] = n + 1 - go t.dialConnFor(w) + t.startDialConnForLocked(w) return } @@ -1466,11 +1531,24 @@ func (t *Transport) queueForDial(w *wantConn) { t.connsPerHostWait = make(map[connectMethodKey]wantConnQueue) } q := t.connsPerHostWait[w.key] - q.cleanFront() + q.cleanFrontNotWaiting() q.pushBack(w) t.connsPerHostWait[w.key] = q } +// startDialConnFor calls dialConn in a new goroutine. +// t.connsPerHostMu must be held. +func (t *Transport) startDialConnForLocked(w *wantConn) { + t.dialsInProgress.cleanFrontCanceled() + t.dialsInProgress.pushBack(w) + go func() { + t.dialConnFor(w) + t.connsPerHostMu.Lock() + defer t.connsPerHostMu.Unlock() + w.cancelCtx = nil + }() +} + // dialConnFor dials on behalf of w and delivers the result to w. // dialConnFor has received permission to dial w.cm and is counted in t.connCount[w.cm.key()]. // If the dial is canceled or unsuccessful, dialConnFor decrements t.connCount[w.cm.key()]. @@ -1483,7 +1561,7 @@ func (t *Transport) dialConnFor(w *wantConn) { } pc, err := t.dialConn(ctx, w.cm) - delivered := w.tryDeliver(pc, err) + delivered := w.tryDeliver(pc, err, time.Time{}) if err == nil && (!delivered || pc.alt != nil) { // pconn was not passed to w, // or it is HTTP/2 and can be shared. @@ -1520,7 +1598,7 @@ func (t *Transport) decConnsPerHost(key connectMethodKey) { for q.len() > 0 { w := q.popFront() if w.waiting() { - go t.dialConnFor(w) + t.startDialConnForLocked(w) done = true break } @@ -1601,6 +1679,8 @@ type erringRoundTripper interface { RoundTripErr() error } +var testHookProxyConnectTimeout = context.WithTimeout + func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *persistConn, err error) { pconn = &persistConn{ t: t, @@ -1665,7 +1745,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers switch { case cm.proxyURL == nil: // Do nothing. Not using a proxy. - case cm.proxyURL.Scheme == "socks5": + case cm.proxyURL.Scheme == "socks5" || cm.proxyURL.Scheme == "socks5h": conn := pconn.conn d := socksNewDialer("tcp", conn.RemoteAddr().String()) if u := cm.proxyURL.User; u != nil { @@ -1717,17 +1797,11 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers Header: hdr, } - // If there's no done channel (no deadline or cancellation - // from the caller possible), at least set some (long) - // timeout here. This will make sure we don't block forever - // and leak a goroutine if the connection stops replying - // after the TCP connect. - connectCtx := ctx - if ctx.Done() == nil { - newCtx, cancel := context.WithTimeout(ctx, 1*time.Minute) - defer cancel() - connectCtx = newCtx - } + // Set a (long) timeout here to make sure we don't block forever + // and leak a goroutine if the connection stops replying after + // the TCP connect. + connectCtx, cancel := testHookProxyConnectTimeout(ctx, 1*time.Minute) + defer cancel() didReadResponse := make(chan struct{}) // closed after CONNECT write+read is done or fails var ( @@ -1762,6 +1836,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers if t.OnProxyConnectResponse != nil { err = t.OnProxyConnectResponse(ctx, cm.proxyURL, connectReq, resp) if err != nil { + conn.Close() return nil, err } } @@ -2006,18 +2081,6 @@ func (pc *persistConn) isReused() bool { return r } -func (pc *persistConn) gotIdleConnTrace(idleAt time.Time) (t httptrace.GotConnInfo) { - pc.mu.Lock() - defer pc.mu.Unlock() - t.Reused = pc.reused - t.Conn = pc.conn - t.WasIdle = true - if !idleAt.IsZero() { - t.IdleTime = time.Since(idleAt) - } - return -} - func (pc *persistConn) cancelRequest(err error) { pc.mu.Lock() defer pc.mu.Unlock() @@ -2110,7 +2173,8 @@ func (pc *persistConn) readLoop() { pc.t.removeIdleConn(pc) }() - tryPutIdleConn := func(trace *httptrace.ClientTrace) bool { + tryPutIdleConn := func(treq *transportRequest) bool { + trace := treq.trace if err := pc.t.tryPutIdleConn(pc); err != nil { closeErr = err if trace != nil && trace.PutIdleConn != nil && err != errKeepAlivesDisabled { @@ -2149,7 +2213,7 @@ func (pc *persistConn) readLoop() { pc.mu.Unlock() rc := <-pc.reqch - trace := httptrace.ContextClientTrace(rc.req.Context()) + trace := rc.treq.trace var resp *Response if err == nil { @@ -2178,9 +2242,9 @@ func (pc *persistConn) readLoop() { pc.mu.Unlock() bodyWritable := resp.bodyIsWritable() - hasBody := rc.req.Method != "HEAD" && resp.ContentLength != 0 + hasBody := rc.treq.Request.Method != "HEAD" && resp.ContentLength != 0 - if resp.Close || rc.req.Close || resp.StatusCode <= 199 || bodyWritable { + if resp.Close || rc.treq.Request.Close || resp.StatusCode <= 199 || bodyWritable { // Don't do keep-alive on error if either party requested a close // or we get an unexpected informational (1xx) response. // StatusCode 100 is already handled above. @@ -2188,8 +2252,6 @@ func (pc *persistConn) readLoop() { } if !hasBody || bodyWritable { - replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil) - // Put the idle conn back into the pool before we send the response // so if they process it quickly and make another request, they'll // get this same conn. But we use the unbuffered channel 'rc' @@ -2198,7 +2260,7 @@ func (pc *persistConn) readLoop() { alive = alive && !pc.sawEOF && pc.wroteRequest() && - replaced && tryPutIdleConn(trace) + tryPutIdleConn(rc.treq) if bodyWritable { closeErr = errCallerOwnsConn @@ -2210,6 +2272,8 @@ func (pc *persistConn) readLoop() { return } + rc.treq.cancel(errRequestDone) + // Now that they've read from the unbuffered channel, they're safely // out of the select that also waits on this goroutine to die, so // we're allowed to exit now if needed (if alive is false) @@ -2260,25 +2324,22 @@ func (pc *persistConn) readLoop() { // reading the response body. (or for cancellation or death) select { case bodyEOF := <-waitForBodyRead: - replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil) // before pc might return to idle pool alive = alive && bodyEOF && !pc.sawEOF && pc.wroteRequest() && - replaced && tryPutIdleConn(trace) + tryPutIdleConn(rc.treq) if bodyEOF { eofc <- struct{}{} } - case <-rc.req.Cancel: + case <-rc.treq.ctx.Done(): alive = false - pc.t.cancelRequest(rc.cancelKey, errRequestCanceled) - case <-rc.req.Context().Done(): - alive = false - pc.t.cancelRequest(rc.cancelKey, rc.req.Context().Err()) + pc.cancelRequest(context.Cause(rc.treq.ctx)) case <-pc.closech: alive = false } + rc.treq.cancel(errRequestDone) testHookReadLoopBeforeNextRead() } } @@ -2331,7 +2392,7 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr continueCh := rc.continueCh for { - resp, err = ReadResponse(pc.br, rc.req) + resp, err = ReadResponse(pc.br, rc.treq.Request) if err != nil { return } @@ -2377,7 +2438,7 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr // Conceivably, it's one that doesn't need us to send the body. // Given that we'll send the body if ExpectContinueTimeout expires, // be consistent and always send it if we aren't closing the connection. - if resp.Close || rc.req.Close { + if resp.Close || rc.treq.Request.Close { close(continueCh) // don't send the body; the connection will close } else { continueCh <- struct{}{} // send the body @@ -2537,10 +2598,9 @@ type responseAndError struct { } type requestAndChan struct { - _ incomparable - req *Request - cancelKey cancelKey - ch chan responseAndError // unbuffered; always send in select on callerGone + _ incomparable + treq *transportRequest + ch chan responseAndError // unbuffered; always send in select on callerGone // whether the Transport (as opposed to the user client code) // added the Accept-Encoding gzip header. If the Transport @@ -2570,22 +2630,28 @@ type writeRequest struct { continueCh <-chan struct{} } -type httpError struct { - err string - timeout bool +// httpTimeoutError represents a timeout. +// It implements net.Error and wraps context.DeadlineExceeded. +type timeoutError struct { + err string } -func (e *httpError) Error() string { return e.err } -func (e *httpError) Timeout() bool { return e.timeout } -func (e *httpError) Temporary() bool { return true } +func (e *timeoutError) Error() string { return e.err } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } +func (e *timeoutError) Is(err error) bool { return err == context.DeadlineExceeded } -var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true} +var errTimeout error = &timeoutError{"net/http: timeout awaiting response headers"} // errRequestCanceled is set to be identical to the one from h2 to facilitate // testing. var errRequestCanceled = http2errRequestCanceled var errRequestCanceledConn = errors.New("net/http: request canceled while waiting for connection") // TODO: unify? +// errRequestDone is used to cancel the round trip Context after a request is successfully done. +// It should not be seen by the user. +var errRequestDone = errors.New("net/http: request completed") + func nop() {} // testHooks. Always non-nil. @@ -2602,10 +2668,6 @@ var ( func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) { testHookEnterRoundTrip() - if !pc.t.replaceReqCanceler(req.cancelKey, pc.cancelRequest) { - pc.t.putOrCloseIdleConn(pc) - return nil, errRequestCanceled - } pc.mu.Lock() pc.numExpectedResponses++ headerFn := pc.mutateHeaderFunc @@ -2654,12 +2716,6 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err gone := make(chan struct{}) defer close(gone) - defer func() { - if err != nil { - pc.t.setReqCanceler(req.cancelKey, nil) - } - }() - const debugRoundTrip = false // Write the request concurrently with waiting for a response, @@ -2671,25 +2727,35 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err resc := make(chan responseAndError) pc.reqch <- requestAndChan{ - req: req.Request, - cancelKey: req.cancelKey, + treq: req, ch: resc, addedGzip: requestedGzip, continueCh: continueCh, callerGone: gone, } + handleResponse := func(re responseAndError) (*Response, error) { + if (re.res == nil) == (re.err == nil) { + panic(fmt.Sprintf("internal error: exactly one of res or err should be set; nil=%v", re.res == nil)) + } + if debugRoundTrip { + req.logf("resc recv: %p, %T/%#v", re.res, re.err, re.err) + } + if re.err != nil { + return nil, pc.mapRoundTripError(req, startBytesWritten, re.err) + } + return re.res, nil + } + var respHeaderTimer <-chan time.Time - cancelChan := req.Request.Cancel - ctxDoneChan := req.Context().Done() + ctxDoneChan := req.ctx.Done() pcClosed := pc.closech - canceled := false for { testHookWaitResLoop() select { case err := <-writeErrCh: if debugRoundTrip { - req.logf("writeErrCh resv: %T/%#v", err, err) + req.logf("writeErrCh recv: %T/%#v", err, err) } if err != nil { pc.close(fmt.Errorf("write error: %w", err)) @@ -2704,13 +2770,18 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err respHeaderTimer = timer.C } case <-pcClosed: - pcClosed = nil - if canceled || pc.t.replaceReqCanceler(req.cancelKey, nil) { - if debugRoundTrip { - req.logf("closech recv: %T %#v", pc.closed, pc.closed) - } - return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed) + select { + case re := <-resc: + // The pconn closing raced with the response to the request, + // probably after the server wrote a response and immediately + // closed the connection. Use the response. + return handleResponse(re) + default: } + if debugRoundTrip { + req.logf("closech recv: %T %#v", pc.closed, pc.closed) + } + return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed) case <-respHeaderTimer: if debugRoundTrip { req.logf("timeout waiting for response headers.") @@ -2718,23 +2789,17 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err pc.close(errTimeout) return nil, errTimeout case re := <-resc: - if (re.res == nil) == (re.err == nil) { - panic(fmt.Sprintf("internal error: exactly one of res or err should be set; nil=%v", re.res == nil)) - } - if debugRoundTrip { - req.logf("resc recv: %p, %T/%#v", re.res, re.err, re.err) - } - if re.err != nil { - return nil, pc.mapRoundTripError(req, startBytesWritten, re.err) - } - return re.res, nil - case <-cancelChan: - canceled = pc.t.cancelRequest(req.cancelKey, errRequestCanceled) - cancelChan = nil + return handleResponse(re) case <-ctxDoneChan: - canceled = pc.t.cancelRequest(req.cancelKey, req.Context().Err()) - cancelChan = nil - ctxDoneChan = nil + select { + case re := <-resc: + // readLoop is responsible for canceling req.ctx after + // it reads the response body. Check for a response racing + // the context close, and use the response if available. + return handleResponse(re) + default: + } + pc.cancelRequest(context.Cause(req.ctx)) } } } @@ -2789,9 +2854,10 @@ func (pc *persistConn) closeLocked(err error) { } var portMap = map[string]string{ - "http": "80", - "https": "443", - "socks5": "1080", + "http": "80", + "https": "443", + "socks5": "1080", + "socks5h": "1080", } func idnaASCIIFromURL(url *url.URL) string { @@ -2932,6 +2998,16 @@ func (fakeLocker) Unlock() {} // cloneTLSConfig returns a shallow clone of cfg, or a new zero tls.Config if // cfg is nil. This is safe to call even if cfg is in active use by a TLS // client or server. +// +// cloneTLSConfig should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneTLSConfig func cloneTLSConfig(cfg *tls.Config) *tls.Config { if cfg == nil { return &tls.Config{} diff --git a/contrib/go/_std_1.22/src/net/http/transport_default_other.go b/contrib/go/_std_1.23/src/net/http/transport_default_other.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/transport_default_other.go rename to contrib/go/_std_1.23/src/net/http/transport_default_other.go diff --git a/contrib/go/_std_1.22/src/net/http/transport_default_wasm.go b/contrib/go/_std_1.23/src/net/http/transport_default_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/transport_default_wasm.go rename to contrib/go/_std_1.23/src/net/http/transport_default_wasm.go diff --git a/contrib/go/_std_1.22/src/net/http/triv.go b/contrib/go/_std_1.23/src/net/http/triv.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/triv.go rename to contrib/go/_std_1.23/src/net/http/triv.go diff --git a/contrib/go/_std_1.22/src/net/http/ya.make b/contrib/go/_std_1.23/src/net/http/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/ya.make rename to contrib/go/_std_1.23/src/net/http/ya.make diff --git a/contrib/go/_std_1.22/src/net/interface.go b/contrib/go/_std_1.23/src/net/interface.go similarity index 95% rename from contrib/go/_std_1.22/src/net/interface.go rename to contrib/go/_std_1.23/src/net/interface.go index 20ac07d31a4a..74bb4f0e1c61 100644 --- a/contrib/go/_std_1.22/src/net/interface.go +++ b/contrib/go/_std_1.23/src/net/interface.go @@ -9,6 +9,7 @@ import ( "internal/itoa" "sync" "time" + _ "unsafe" ) // BUG(mikio): On JS, methods and functions related to @@ -17,6 +18,16 @@ import ( // BUG(mikio): On AIX, DragonFly BSD, NetBSD, OpenBSD, Plan 9 and // Solaris, the MulticastAddrs method of Interface is not implemented. +// errNoSuchInterface should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname errNoSuchInterface + var ( errInvalidInterface = errors.New("invalid network interface") errInvalidInterfaceIndex = errors.New("invalid network interface index") diff --git a/contrib/go/_std_1.22/src/net/interface_aix.go b/contrib/go/_std_1.23/src/net/interface_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_aix.go rename to contrib/go/_std_1.23/src/net/interface_aix.go diff --git a/contrib/go/_std_1.22/src/net/interface_bsd.go b/contrib/go/_std_1.23/src/net/interface_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_bsd.go rename to contrib/go/_std_1.23/src/net/interface_bsd.go diff --git a/contrib/go/_std_1.22/src/net/interface_bsdvar.go b/contrib/go/_std_1.23/src/net/interface_bsdvar.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_bsdvar.go rename to contrib/go/_std_1.23/src/net/interface_bsdvar.go diff --git a/contrib/go/_std_1.22/src/net/interface_darwin.go b/contrib/go/_std_1.23/src/net/interface_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_darwin.go rename to contrib/go/_std_1.23/src/net/interface_darwin.go diff --git a/contrib/go/_std_1.22/src/net/interface_freebsd.go b/contrib/go/_std_1.23/src/net/interface_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_freebsd.go rename to contrib/go/_std_1.23/src/net/interface_freebsd.go diff --git a/contrib/go/_std_1.22/src/net/interface_linux.go b/contrib/go/_std_1.23/src/net/interface_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_linux.go rename to contrib/go/_std_1.23/src/net/interface_linux.go diff --git a/contrib/go/_std_1.22/src/net/interface_plan9.go b/contrib/go/_std_1.23/src/net/interface_plan9.go similarity index 98% rename from contrib/go/_std_1.22/src/net/interface_plan9.go rename to contrib/go/_std_1.23/src/net/interface_plan9.go index 92b2eed2591b..7c44566acf01 100644 --- a/contrib/go/_std_1.22/src/net/interface_plan9.go +++ b/contrib/go/_std_1.23/src/net/interface_plan9.go @@ -7,6 +7,7 @@ package net import ( "errors" "internal/itoa" + "internal/stringslite" "os" ) @@ -70,7 +71,7 @@ func readInterface(i int) (*Interface, error) { ifc.MTU = mtu // Not a loopback device ("/dev/null") or packet interface (e.g. "pkt2") - if stringsHasPrefix(device, netdir+"/") { + if stringslite.HasPrefix(device, netdir+"/") { deviceaddrf, err := open(device + "/addr") if err != nil { return nil, err diff --git a/contrib/go/_std_1.22/src/net/interface_solaris.go b/contrib/go/_std_1.23/src/net/interface_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_solaris.go rename to contrib/go/_std_1.23/src/net/interface_solaris.go diff --git a/contrib/go/_std_1.22/src/net/interface_stub.go b/contrib/go/_std_1.23/src/net/interface_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_stub.go rename to contrib/go/_std_1.23/src/net/interface_stub.go diff --git a/contrib/go/_std_1.22/src/net/interface_windows.go b/contrib/go/_std_1.23/src/net/interface_windows.go similarity index 96% rename from contrib/go/_std_1.22/src/net/interface_windows.go rename to contrib/go/_std_1.23/src/net/interface_windows.go index 22a13128499b..1b487dc47482 100644 --- a/contrib/go/_std_1.22/src/net/interface_windows.go +++ b/contrib/go/_std_1.23/src/net/interface_windows.go @@ -20,7 +20,8 @@ func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { l := uint32(15000) // recommended initial size for { b = make([]byte, l) - err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) + const flags = windows.GAA_FLAG_INCLUDE_PREFIX | windows.GAA_FLAG_INCLUDE_GATEWAYS + err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, flags, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) if err == nil { if l == 0 { return nil, nil diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch_posix.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch_posix.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch_posix.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch_stub.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch_stub.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch_stub.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch_unix.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch_unix.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch_unix.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch_windows.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch_windows.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch_windows.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/sys_cloexec.go b/contrib/go/_std_1.23/src/net/internal/socktest/sys_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/sys_cloexec.go rename to contrib/go/_std_1.23/src/net/internal/socktest/sys_cloexec.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/sys_unix.go b/contrib/go/_std_1.23/src/net/internal/socktest/sys_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/sys_unix.go rename to contrib/go/_std_1.23/src/net/internal/socktest/sys_unix.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/sys_windows.go b/contrib/go/_std_1.23/src/net/internal/socktest/sys_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/sys_windows.go rename to contrib/go/_std_1.23/src/net/internal/socktest/sys_windows.go diff --git a/contrib/go/_std_1.23/src/net/internal/socktest/ya.make b/contrib/go/_std_1.23/src/net/internal/socktest/ya.make new file mode 100644 index 000000000000..7fff60cffb35 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/internal/socktest/ya.make @@ -0,0 +1,27 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + switch.go + switch_posix.go + switch_unix.go + sys_unix.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + switch.go + switch_posix.go + switch_unix.go + sys_cloexec.go + sys_unix.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + switch.go + switch_posix.go + switch_windows.go + sys_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/net/internal/ya.make b/contrib/go/_std_1.23/src/net/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/ya.make rename to contrib/go/_std_1.23/src/net/internal/ya.make diff --git a/contrib/go/_std_1.22/src/net/ip.go b/contrib/go/_std_1.23/src/net/ip.go similarity index 98% rename from contrib/go/_std_1.22/src/net/ip.go rename to contrib/go/_std_1.23/src/net/ip.go index 6083dd8bf9f6..3e0e85e168a7 100644 --- a/contrib/go/_std_1.22/src/net/ip.go +++ b/contrib/go/_std_1.23/src/net/ip.go @@ -15,6 +15,7 @@ package net import ( "internal/bytealg" "internal/itoa" + "internal/stringslite" "net/netip" ) @@ -490,7 +491,8 @@ func (n *IPNet) String() string { // The string s can be in IPv4 dotted decimal ("192.0.2.1"), IPv6 // ("2001:db8::68"), or IPv4-mapped IPv6 ("::ffff:192.0.2.1") form. // If s is not a valid textual representation of an IP address, -// ParseIP returns nil. +// ParseIP returns nil. The returned address is always 16 bytes, +// IPv4 addresses are returned in IPv4-mapped IPv6 form. func ParseIP(s string) IP { if addr, valid := parseIP(s); valid { return IP(addr[:]) @@ -515,11 +517,10 @@ func parseIP(s string) ([16]byte, bool) { // For example, ParseCIDR("192.0.2.1/24") returns the IP address // 192.0.2.1 and the network 192.0.2.0/24. func ParseCIDR(s string) (IP, *IPNet, error) { - i := bytealg.IndexByteString(s, '/') - if i < 0 { + addr, mask, found := stringslite.Cut(s, "/") + if !found { return nil, nil, &ParseError{Type: "CIDR address", Text: s} } - addr, mask := s[:i], s[i+1:] ipAddr, err := netip.ParseAddr(addr) if err != nil || ipAddr.Zone() != "" { diff --git a/contrib/go/_std_1.22/src/net/iprawsock.go b/contrib/go/_std_1.23/src/net/iprawsock.go similarity index 100% rename from contrib/go/_std_1.22/src/net/iprawsock.go rename to contrib/go/_std_1.23/src/net/iprawsock.go diff --git a/contrib/go/_std_1.22/src/net/iprawsock_plan9.go b/contrib/go/_std_1.23/src/net/iprawsock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/iprawsock_plan9.go rename to contrib/go/_std_1.23/src/net/iprawsock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/iprawsock_posix.go b/contrib/go/_std_1.23/src/net/iprawsock_posix.go similarity index 95% rename from contrib/go/_std_1.22/src/net/iprawsock_posix.go rename to contrib/go/_std_1.23/src/net/iprawsock_posix.go index 73b41ab5226a..b25cb648c3dc 100644 --- a/contrib/go/_std_1.22/src/net/iprawsock_posix.go +++ b/contrib/go/_std_1.23/src/net/iprawsock_posix.go @@ -124,7 +124,7 @@ func (sd *sysDialer) dialIP(ctx context.Context, laddr, raddr *IPAddr) (*IPConn, } ctrlCtxFn := sd.Dialer.ControlContext if ctrlCtxFn == nil && sd.Dialer.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sd.Dialer.Control(network, address, c) } } @@ -145,9 +145,9 @@ func (sl *sysListener) listenIP(ctx context.Context, laddr *IPAddr) (*IPConn, er default: return nil, UnknownNetworkError(sl.network) } - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } diff --git a/contrib/go/_std_1.22/src/net/ipsock.go b/contrib/go/_std_1.23/src/net/ipsock.go similarity index 95% rename from contrib/go/_std_1.22/src/net/ipsock.go rename to contrib/go/_std_1.23/src/net/ipsock.go index 176dbc748e66..496faf346ec1 100644 --- a/contrib/go/_std_1.22/src/net/ipsock.go +++ b/contrib/go/_std_1.23/src/net/ipsock.go @@ -9,6 +9,7 @@ import ( "internal/bytealg" "runtime" "sync" + _ "unsafe" // for linkname ) // BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the @@ -307,6 +308,17 @@ func (r *Resolver) internetAddrList(ctx context.Context, net, addr string) (addr return filterAddrList(filter, ips, inetaddr, host) } +// loopbackIP should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/database64128/tfo-go/v2 +// - github.com/metacubex/tfo-go +// - github.com/sagernet/tfo-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname loopbackIP func loopbackIP(net string) IP { if net != "" && net[len(net)-1] == '6' { return IPv6loopback diff --git a/contrib/go/_std_1.22/src/net/ipsock_plan9.go b/contrib/go/_std_1.23/src/net/ipsock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/ipsock_plan9.go rename to contrib/go/_std_1.23/src/net/ipsock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/ipsock_posix.go b/contrib/go/_std_1.23/src/net/ipsock_posix.go similarity index 91% rename from contrib/go/_std_1.22/src/net/ipsock_posix.go rename to contrib/go/_std_1.23/src/net/ipsock_posix.go index 67ce1479c647..2aeabd44873f 100644 --- a/contrib/go/_std_1.22/src/net/ipsock_posix.go +++ b/contrib/go/_std_1.23/src/net/ipsock_posix.go @@ -12,6 +12,7 @@ import ( "net/netip" "runtime" "syscall" + _ "unsafe" // for linkname ) // probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication @@ -118,6 +119,18 @@ func (p *ipStackCapabilities) probe() { // Note that the latest DragonFly BSD and OpenBSD kernels allow // neither "net.inet6.ip6.v6only=1" change nor IPPROTO_IPV6 level // IPV6_V6ONLY socket option setting. +// +// favoriteAddrFamily should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/database64128/tfo-go/v2 +// - github.com/metacubex/tfo-go +// - github.com/sagernet/tfo-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname favoriteAddrFamily func favoriteAddrFamily(network string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) { switch network[len(network)-1] { case '4': @@ -192,6 +205,17 @@ func ipToSockaddrInet6(ip IP, port int, zone string) (syscall.SockaddrInet6, err return sa, nil } +// ipToSockaddr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/database64128/tfo-go/v2 +// - github.com/metacubex/tfo-go +// - github.com/sagernet/tfo-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname ipToSockaddr func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) { switch family { case syscall.AF_INET: diff --git a/contrib/go/_std_1.23/src/net/lookup.go b/contrib/go/_std_1.23/src/net/lookup.go new file mode 100644 index 000000000000..b04dfa23b987 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/lookup.go @@ -0,0 +1,905 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "context" + "errors" + "internal/nettrace" + "internal/singleflight" + "net/netip" + "sync" + + "golang.org/x/net/dns/dnsmessage" +) + +// protocols contains minimal mappings between internet protocol +// names and numbers for platforms that don't have a complete list of +// protocol numbers. +// +// See https://www.iana.org/assignments/protocol-numbers +// +// On Unix, this map is augmented by readProtocols via lookupProtocol. +var protocols = map[string]int{ + "icmp": 1, + "igmp": 2, + "tcp": 6, + "udp": 17, + "ipv6-icmp": 58, +} + +// services contains minimal mappings between services names and port +// numbers for platforms that don't have a complete list of port numbers. +// +// See https://www.iana.org/assignments/service-names-port-numbers +// +// On Unix, this map is augmented by readServices via goLookupPort. +var services = map[string]map[string]int{ + "udp": { + "domain": 53, + }, + "tcp": { + "ftp": 21, + "ftps": 990, + "gopher": 70, // ʕ◔ϖ◔ʔ + "http": 80, + "https": 443, + "imap2": 143, + "imap3": 220, + "imaps": 993, + "pop3": 110, + "pop3s": 995, + "smtp": 25, + "submissions": 465, + "ssh": 22, + "telnet": 23, + }, +} + +// dnsWaitGroup can be used by tests to wait for all DNS goroutines to +// complete. This avoids races on the test hooks. +var dnsWaitGroup sync.WaitGroup + +const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow + +func lookupProtocolMap(name string) (int, error) { + var lowerProtocol [maxProtoLength]byte + n := copy(lowerProtocol[:], name) + lowerASCIIBytes(lowerProtocol[:n]) + proto, found := protocols[string(lowerProtocol[:n])] + if !found || n != len(name) { + return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name} + } + return proto, nil +} + +// maxPortBufSize is the longest reasonable name of a service +// (non-numeric port). +// Currently the longest known IANA-unregistered name is +// "mobility-header", so we use that length, plus some slop in case +// something longer is added in the future. +const maxPortBufSize = len("mobility-header") + 10 + +func lookupPortMap(network, service string) (port int, error error) { + switch network { + case "ip": // no hints + if p, err := lookupPortMapWithNetwork("tcp", "ip", service); err == nil { + return p, nil + } + return lookupPortMapWithNetwork("udp", "ip", service) + case "tcp", "tcp4", "tcp6": + return lookupPortMapWithNetwork("tcp", "tcp", service) + case "udp", "udp4", "udp6": + return lookupPortMapWithNetwork("udp", "udp", service) + } + return 0, &DNSError{Err: "unknown network", Name: network + "/" + service} +} + +func lookupPortMapWithNetwork(network, errNetwork, service string) (port int, error error) { + if m, ok := services[network]; ok { + var lowerService [maxPortBufSize]byte + n := copy(lowerService[:], service) + lowerASCIIBytes(lowerService[:n]) + if port, ok := m[string(lowerService[:n])]; ok && n == len(service) { + return port, nil + } + return 0, newDNSError(errUnknownPort, errNetwork+"/"+service, "") + } + return 0, &DNSError{Err: "unknown network", Name: errNetwork + "/" + service} +} + +// ipVersion returns the provided network's IP version: '4', '6' or 0 +// if network does not end in a '4' or '6' byte. +func ipVersion(network string) byte { + if network == "" { + return 0 + } + n := network[len(network)-1] + if n != '4' && n != '6' { + n = 0 + } + return n +} + +// DefaultResolver is the resolver used by the package-level Lookup +// functions and by Dialers without a specified Resolver. +var DefaultResolver = &Resolver{} + +// A Resolver looks up names and numbers. +// +// A nil *Resolver is equivalent to a zero Resolver. +type Resolver struct { + // PreferGo controls whether Go's built-in DNS resolver is preferred + // on platforms where it's available. It is equivalent to setting + // GODEBUG=netdns=go, but scoped to just this resolver. + PreferGo bool + + // StrictErrors controls the behavior of temporary errors + // (including timeout, socket errors, and SERVFAIL) when using + // Go's built-in resolver. For a query composed of multiple + // sub-queries (such as an A+AAAA address lookup, or walking the + // DNS search list), this option causes such errors to abort the + // whole query instead of returning a partial result. This is + // not enabled by default because it may affect compatibility + // with resolvers that process AAAA queries incorrectly. + StrictErrors bool + + // Dial optionally specifies an alternate dialer for use by + // Go's built-in DNS resolver to make TCP and UDP connections + // to DNS services. The host in the address parameter will + // always be a literal IP address and not a host name, and the + // port in the address parameter will be a literal port number + // and not a service name. + // If the Conn returned is also a PacketConn, sent and received DNS + // messages must adhere to RFC 1035 section 4.2.1, "UDP usage". + // Otherwise, DNS messages transmitted over Conn must adhere + // to RFC 7766 section 5, "Transport Protocol Selection". + // If nil, the default dialer is used. + Dial func(ctx context.Context, network, address string) (Conn, error) + + // lookupGroup merges LookupIPAddr calls together for lookups for the same + // host. The lookupGroup key is the LookupIPAddr.host argument. + // The return values are ([]IPAddr, error). + lookupGroup singleflight.Group + + // TODO(bradfitz): optional interface impl override hook + // TODO(bradfitz): Timeout time.Duration? +} + +func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo } +func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors } + +func (r *Resolver) getLookupGroup() *singleflight.Group { + if r == nil { + return &DefaultResolver.lookupGroup + } + return &r.lookupGroup +} + +// LookupHost looks up the given host using the local resolver. +// It returns a slice of that host's addresses. +// +// LookupHost uses [context.Background] internally; to specify the context, use +// [Resolver.LookupHost]. +func LookupHost(host string) (addrs []string, err error) { + return DefaultResolver.LookupHost(context.Background(), host) +} + +// LookupHost looks up the given host using the local resolver. +// It returns a slice of that host's addresses. +func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) { + // Make sure that no matter what we do later, host=="" is rejected. + if host == "" { + return nil, newDNSError(errNoSuchHost, host, "") + } + if _, err := netip.ParseAddr(host); err == nil { + return []string{host}, nil + } + return r.lookupHost(ctx, host) +} + +// LookupIP looks up host using the local resolver. +// It returns a slice of that host's IPv4 and IPv6 addresses. +func LookupIP(host string) ([]IP, error) { + addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host) + if err != nil { + return nil, err + } + ips := make([]IP, len(addrs)) + for i, ia := range addrs { + ips[i] = ia.IP + } + return ips, nil +} + +// LookupIPAddr looks up host using the local resolver. +// It returns a slice of that host's IPv4 and IPv6 addresses. +func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) { + return r.lookupIPAddr(ctx, "ip", host) +} + +// LookupIP looks up host for the given network using the local resolver. +// It returns a slice of that host's IP addresses of the type specified by +// network. +// network must be one of "ip", "ip4" or "ip6". +func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) { + afnet, _, err := parseNetwork(ctx, network, false) + if err != nil { + return nil, err + } + switch afnet { + case "ip", "ip4", "ip6": + default: + return nil, UnknownNetworkError(network) + } + + if host == "" { + return nil, newDNSError(errNoSuchHost, host, "") + } + addrs, err := r.internetAddrList(ctx, afnet, host) + if err != nil { + return nil, err + } + + ips := make([]IP, 0, len(addrs)) + for _, addr := range addrs { + ips = append(ips, addr.(*IPAddr).IP) + } + return ips, nil +} + +// LookupNetIP looks up host using the local resolver. +// It returns a slice of that host's IP addresses of the type specified by +// network. +// The network must be one of "ip", "ip4" or "ip6". +func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) { + // TODO(bradfitz): make this efficient, making the internal net package + // type throughout be netip.Addr and only converting to the net.IP slice + // version at the edge. But for now (2021-10-20), this is a wrapper around + // the old way. + ips, err := r.LookupIP(ctx, network, host) + if err != nil { + return nil, err + } + ret := make([]netip.Addr, 0, len(ips)) + for _, ip := range ips { + if a, ok := netip.AddrFromSlice(ip); ok { + ret = append(ret, a) + } + } + return ret, nil +} + +// onlyValuesCtx is a context that uses an underlying context +// for value lookup if the underlying context hasn't yet expired. +type onlyValuesCtx struct { + context.Context + lookupValues context.Context +} + +var _ context.Context = (*onlyValuesCtx)(nil) + +// Value performs a lookup if the original context hasn't expired. +func (ovc *onlyValuesCtx) Value(key any) any { + select { + case <-ovc.lookupValues.Done(): + return nil + default: + return ovc.lookupValues.Value(key) + } +} + +// withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx +// for its values, otherwise it is never canceled and has no deadline. +// If the lookup context expires, any looked up values will return nil. +// See Issue 28600. +func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context { + return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx} +} + +// lookupIPAddr looks up host using the local resolver and particular network. +// It returns a slice of that host's IPv4 and IPv6 addresses. +func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) { + // Make sure that no matter what we do later, host=="" is rejected. + if host == "" { + return nil, newDNSError(errNoSuchHost, host, "") + } + if ip, err := netip.ParseAddr(host); err == nil { + return []IPAddr{{IP: IP(ip.AsSlice()).To16(), Zone: ip.Zone()}}, nil + } + trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) + if trace != nil && trace.DNSStart != nil { + trace.DNSStart(host) + } + // The underlying resolver func is lookupIP by default but it + // can be overridden by tests. This is needed by net/http, so it + // uses a context key instead of unexported variables. + resolverFunc := r.lookupIP + if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil { + resolverFunc = alt + } + + // We don't want a cancellation of ctx to affect the + // lookupGroup operation. Otherwise if our context gets + // canceled it might cause an error to be returned to a lookup + // using a completely different context. However we need to preserve + // only the values in context. See Issue 28600. + lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx)) + + lookupKey := network + "\000" + host + dnsWaitGroup.Add(1) + ch := r.getLookupGroup().DoChan(lookupKey, func() (any, error) { + return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host) + }) + + dnsWaitGroupDone := func(ch <-chan singleflight.Result, cancelFn context.CancelFunc) { + <-ch + dnsWaitGroup.Done() + cancelFn() + } + select { + case <-ctx.Done(): + // Our context was canceled. If we are the only + // goroutine looking up this key, then drop the key + // from the lookupGroup and cancel the lookup. + // If there are other goroutines looking up this key, + // let the lookup continue uncanceled, and let later + // lookups with the same key share the result. + // See issues 8602, 20703, 22724. + if r.getLookupGroup().ForgetUnshared(lookupKey) { + lookupGroupCancel() + go dnsWaitGroupDone(ch, func() {}) + } else { + go dnsWaitGroupDone(ch, lookupGroupCancel) + } + err := newDNSError(mapErr(ctx.Err()), host, "") + if trace != nil && trace.DNSDone != nil { + trace.DNSDone(nil, false, err) + } + return nil, err + case r := <-ch: + dnsWaitGroup.Done() + lookupGroupCancel() + err := r.Err + if err != nil { + if _, ok := err.(*DNSError); !ok { + err = newDNSError(mapErr(err), host, "") + } + } + if trace != nil && trace.DNSDone != nil { + addrs, _ := r.Val.([]IPAddr) + trace.DNSDone(ipAddrsEface(addrs), r.Shared, err) + } + return lookupIPReturn(r.Val, err, r.Shared) + } +} + +// lookupIPReturn turns the return values from singleflight.Do into +// the return values from LookupIP. +func lookupIPReturn(addrsi any, err error, shared bool) ([]IPAddr, error) { + if err != nil { + return nil, err + } + addrs := addrsi.([]IPAddr) + if shared { + clone := make([]IPAddr, len(addrs)) + copy(clone, addrs) + addrs = clone + } + return addrs, nil +} + +// ipAddrsEface returns an empty interface slice of addrs. +func ipAddrsEface(addrs []IPAddr) []any { + s := make([]any, len(addrs)) + for i, v := range addrs { + s[i] = v + } + return s +} + +// LookupPort looks up the port for the given network and service. +// +// LookupPort uses [context.Background] internally; to specify the context, use +// [Resolver.LookupPort]. +func LookupPort(network, service string) (port int, err error) { + return DefaultResolver.LookupPort(context.Background(), network, service) +} + +// LookupPort looks up the port for the given network and service. +// +// The network must be one of "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6" or "ip". +func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) { + port, needsLookup := parsePort(service) + if needsLookup { + switch network { + case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip": + case "": // a hint wildcard for Go 1.0 undocumented behavior + network = "ip" + default: + return 0, &AddrError{Err: "unknown network", Addr: network} + } + port, err = r.lookupPort(ctx, network, service) + if err != nil { + return 0, err + } + } + if 0 > port || port > 65535 { + return 0, &AddrError{Err: "invalid port", Addr: service} + } + return port, nil +} + +// LookupCNAME returns the canonical name for the given host. +// Callers that do not care about the canonical name can call +// [LookupHost] or [LookupIP] directly; both take care of resolving +// the canonical name as part of the lookup. +// +// A canonical name is the final name after following zero +// or more CNAME records. +// LookupCNAME does not return an error if host does not +// contain DNS "CNAME" records, as long as host resolves to +// address records. +// +// The returned canonical name is validated to be a properly +// formatted presentation-format domain name. +// +// LookupCNAME uses [context.Background] internally; to specify the context, use +// [Resolver.LookupCNAME]. +func LookupCNAME(host string) (cname string, err error) { + return DefaultResolver.LookupCNAME(context.Background(), host) +} + +// LookupCNAME returns the canonical name for the given host. +// Callers that do not care about the canonical name can call +// [LookupHost] or [LookupIP] directly; both take care of resolving +// the canonical name as part of the lookup. +// +// A canonical name is the final name after following zero +// or more CNAME records. +// LookupCNAME does not return an error if host does not +// contain DNS "CNAME" records, as long as host resolves to +// address records. +// +// The returned canonical name is validated to be a properly +// formatted presentation-format domain name. +func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { + cname, err := r.lookupCNAME(ctx, host) + if err != nil { + return "", err + } + if !isDomainName(cname) { + return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host} + } + return cname, nil +} + +// LookupSRV tries to resolve an [SRV] query of the given service, +// protocol, and domain name. The proto is "tcp" or "udp". +// The returned records are sorted by priority and randomized +// by weight within a priority. +// +// LookupSRV constructs the DNS name to look up following RFC 2782. +// That is, it looks up _service._proto.name. To accommodate services +// publishing SRV records under non-standard names, if both service +// and proto are empty strings, LookupSRV looks up name directly. +// +// The returned service names are validated to be properly +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the remaining results, if any. +func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { + return DefaultResolver.LookupSRV(context.Background(), service, proto, name) +} + +// LookupSRV tries to resolve an [SRV] query of the given service, +// protocol, and domain name. The proto is "tcp" or "udp". +// The returned records are sorted by priority and randomized +// by weight within a priority. +// +// LookupSRV constructs the DNS name to look up following RFC 2782. +// That is, it looks up _service._proto.name. To accommodate services +// publishing SRV records under non-standard names, if both service +// and proto are empty strings, LookupSRV looks up name directly. +// +// The returned service names are validated to be properly +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the remaining results, if any. +func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { + cname, addrs, err := r.lookupSRV(ctx, service, proto, name) + if err != nil { + return "", nil, err + } + if cname != "" && !isDomainName(cname) { + return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} + } + filteredAddrs := make([]*SRV, 0, len(addrs)) + for _, addr := range addrs { + if addr == nil { + continue + } + if !isDomainName(addr.Target) { + continue + } + filteredAddrs = append(filteredAddrs, addr) + } + if len(addrs) != len(filteredAddrs) { + return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} + } + return cname, filteredAddrs, nil +} + +// LookupMX returns the DNS MX records for the given domain name sorted by preference. +// +// The returned mail server names are validated to be properly +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the remaining results, if any. +// +// LookupMX uses [context.Background] internally; to specify the context, use +// [Resolver.LookupMX]. +func LookupMX(name string) ([]*MX, error) { + return DefaultResolver.LookupMX(context.Background(), name) +} + +// LookupMX returns the DNS MX records for the given domain name sorted by preference. +// +// The returned mail server names are validated to be properly +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the remaining results, if any. +func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { + records, err := r.lookupMX(ctx, name) + if err != nil { + return nil, err + } + filteredMX := make([]*MX, 0, len(records)) + for _, mx := range records { + if mx == nil { + continue + } + if !isDomainName(mx.Host) { + continue + } + filteredMX = append(filteredMX, mx) + } + if len(records) != len(filteredMX) { + return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} + } + return filteredMX, nil +} + +// LookupNS returns the DNS NS records for the given domain name. +// +// The returned name server names are validated to be properly +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the remaining results, if any. +// +// LookupNS uses [context.Background] internally; to specify the context, use +// [Resolver.LookupNS]. +func LookupNS(name string) ([]*NS, error) { + return DefaultResolver.LookupNS(context.Background(), name) +} + +// LookupNS returns the DNS NS records for the given domain name. +// +// The returned name server names are validated to be properly +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the remaining results, if any. +func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { + records, err := r.lookupNS(ctx, name) + if err != nil { + return nil, err + } + filteredNS := make([]*NS, 0, len(records)) + for _, ns := range records { + if ns == nil { + continue + } + if !isDomainName(ns.Host) { + continue + } + filteredNS = append(filteredNS, ns) + } + if len(records) != len(filteredNS) { + return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} + } + return filteredNS, nil +} + +// LookupTXT returns the DNS TXT records for the given domain name. +// +// LookupTXT uses [context.Background] internally; to specify the context, use +// [Resolver.LookupTXT]. +func LookupTXT(name string) ([]string, error) { + return DefaultResolver.lookupTXT(context.Background(), name) +} + +// LookupTXT returns the DNS TXT records for the given domain name. +func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) { + return r.lookupTXT(ctx, name) +} + +// LookupAddr performs a reverse lookup for the given address, returning a list +// of names mapping to that address. +// +// The returned names are validated to be properly formatted presentation-format +// domain names. If the response contains invalid names, those records are filtered +// out and an error will be returned alongside the remaining results, if any. +// +// When using the host C library resolver, at most one result will be +// returned. To bypass the host resolver, use a custom [Resolver]. +// +// LookupAddr uses [context.Background] internally; to specify the context, use +// [Resolver.LookupAddr]. +func LookupAddr(addr string) (names []string, err error) { + return DefaultResolver.LookupAddr(context.Background(), addr) +} + +// LookupAddr performs a reverse lookup for the given address, returning a list +// of names mapping to that address. +// +// The returned names are validated to be properly formatted presentation-format +// domain names. If the response contains invalid names, those records are filtered +// out and an error will be returned alongside the remaining results, if any. +func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { + names, err := r.lookupAddr(ctx, addr) + if err != nil { + return nil, err + } + filteredNames := make([]string, 0, len(names)) + for _, name := range names { + if isDomainName(name) { + filteredNames = append(filteredNames, name) + } + } + if len(names) != len(filteredNames) { + return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr} + } + return filteredNames, nil +} + +// errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup... +// method receives DNS records which contain invalid DNS names. This may be returned alongside +// results which have had the malformed records filtered out. +var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names" + +// dial makes a new connection to the provided server (which must be +// an IP address) with the provided network type, using either r.Dial +// (if both r and r.Dial are non-nil) or else Dialer.DialContext. +func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) { + // Calling Dial here is scary -- we have to be sure not to + // dial a name that will require a DNS lookup, or Dial will + // call back here to translate it. The DNS config parser has + // already checked that all the cfg.servers are IP + // addresses, which Dial will use without a DNS lookup. + var c Conn + var err error + if r != nil && r.Dial != nil { + c, err = r.Dial(ctx, network, server) + } else { + var d Dialer + c, err = d.DialContext(ctx, network, server) + } + if err != nil { + return nil, mapErr(err) + } + return c, nil +} + +// goLookupSRV returns the SRV records for a target name, built either +// from its component service ("sip"), protocol ("tcp"), and name +// ("example.com."), or from name directly (if service and proto are +// both empty). +// +// In either case, the returned target name ("_sip._tcp.example.com.") +// is also returned on success. +// +// The records are sorted by weight. +func (r *Resolver) goLookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*SRV, err error) { + if service == "" && proto == "" { + target = name + } else { + target = "_" + service + "._" + proto + "." + name + } + p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV, nil) + if err != nil { + return "", nil, err + } + var cname dnsmessage.Name + for { + h, err := p.AnswerHeader() + if err == dnsmessage.ErrSectionDone { + break + } + if err != nil { + return "", nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + if h.Type != dnsmessage.TypeSRV { + if err := p.SkipAnswer(); err != nil { + return "", nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + continue + } + if cname.Length == 0 && h.Name.Length != 0 { + cname = h.Name + } + srv, err := p.SRVResource() + if err != nil { + return "", nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight}) + } + byPriorityWeight(srvs).sort() + return cname.String(), srvs, nil +} + +// goLookupMX returns the MX records for name. +func (r *Resolver) goLookupMX(ctx context.Context, name string) ([]*MX, error) { + p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX, nil) + if err != nil { + return nil, err + } + var mxs []*MX + for { + h, err := p.AnswerHeader() + if err == dnsmessage.ErrSectionDone { + break + } + if err != nil { + return nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + if h.Type != dnsmessage.TypeMX { + if err := p.SkipAnswer(); err != nil { + return nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + continue + } + mx, err := p.MXResource() + if err != nil { + return nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref}) + + } + byPref(mxs).sort() + return mxs, nil +} + +// goLookupNS returns the NS records for name. +func (r *Resolver) goLookupNS(ctx context.Context, name string) ([]*NS, error) { + p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS, nil) + if err != nil { + return nil, err + } + var nss []*NS + for { + h, err := p.AnswerHeader() + if err == dnsmessage.ErrSectionDone { + break + } + if err != nil { + return nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + if h.Type != dnsmessage.TypeNS { + if err := p.SkipAnswer(); err != nil { + return nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + continue + } + ns, err := p.NSResource() + if err != nil { + return nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + nss = append(nss, &NS{Host: ns.NS.String()}) + } + return nss, nil +} + +// goLookupTXT returns the TXT records from name. +func (r *Resolver) goLookupTXT(ctx context.Context, name string) ([]string, error) { + p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT, nil) + if err != nil { + return nil, err + } + var txts []string + for { + h, err := p.AnswerHeader() + if err == dnsmessage.ErrSectionDone { + break + } + if err != nil { + return nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + if h.Type != dnsmessage.TypeTXT { + if err := p.SkipAnswer(); err != nil { + return nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + continue + } + txt, err := p.TXTResource() + if err != nil { + return nil, &DNSError{ + Err: "cannot unmarshal DNS message", + Name: name, + Server: server, + } + } + // Multiple strings in one TXT record need to be + // concatenated without separator to be consistent + // with previous Go resolver. + n := 0 + for _, s := range txt.TXT { + n += len(s) + } + txtJoin := make([]byte, 0, n) + for _, s := range txt.TXT { + txtJoin = append(txtJoin, s...) + } + if len(txts) == 0 { + txts = make([]string, 0, 1) + } + txts = append(txts, string(txtJoin)) + } + return txts, nil +} + +func parseCNAMEFromResources(resources []dnsmessage.Resource) (string, error) { + if len(resources) == 0 { + return "", errors.New("no CNAME record received") + } + c, ok := resources[0].Body.(*dnsmessage.CNAMEResource) + if !ok { + return "", errors.New("could not parse CNAME record") + } + return c.CNAME.String(), nil +} diff --git a/contrib/go/_std_1.22/src/net/lookup_plan9.go b/contrib/go/_std_1.23/src/net/lookup_plan9.go similarity index 93% rename from contrib/go/_std_1.22/src/net/lookup_plan9.go rename to contrib/go/_std_1.23/src/net/lookup_plan9.go index 8cfc4f6bb3b0..e3e371611f44 100644 --- a/contrib/go/_std_1.22/src/net/lookup_plan9.go +++ b/contrib/go/_std_1.23/src/net/lookup_plan9.go @@ -9,6 +9,7 @@ import ( "errors" "internal/bytealg" "internal/itoa" + "internal/stringslite" "io" "os" ) @@ -107,19 +108,13 @@ func queryDNS(ctx context.Context, addr string, typ string) (res []string, err e } func handlePlan9DNSError(err error, name string) error { - if stringsHasSuffix(err.Error(), "dns: name does not exist") || - stringsHasSuffix(err.Error(), "dns: resource does not exist; negrcode 0") || - stringsHasSuffix(err.Error(), "dns: resource does not exist; negrcode") { - return &DNSError{ - Err: errNoSuchHost.Error(), - Name: name, - IsNotFound: true, - } - } - return &DNSError{ - Err: err.Error(), - Name: name, + if stringslite.HasSuffix(err.Error(), "dns: name does not exist") || + stringslite.HasSuffix(err.Error(), "dns: resource does not exist; negrcode 0") || + stringslite.HasSuffix(err.Error(), "dns: resource does not exist; negrcode") || + stringslite.HasSuffix(err.Error(), "dns failure") { + err = errNoSuchHost } + return newDNSError(err, name, "") } // toLower returns a lower-case version of in. Restricting us to @@ -169,9 +164,6 @@ func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, e // host names in local network (e.g. from /lib/ndb/local) lines, err := queryCS(ctx, "net", host, "1") if err != nil { - if stringsHasSuffix(err.Error(), "dns failure") { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} - } return nil, handlePlan9DNSError(err, host) } loop: @@ -236,7 +228,7 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (por func (*Resolver) lookupPortWithNetwork(ctx context.Context, network, errNetwork, service string) (port int, err error) { lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service)) if err != nil { - if stringsHasSuffix(err.Error(), "can't translate service") { + if stringslite.HasSuffix(err.Error(), "can't translate service") { return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true} } return @@ -265,7 +257,9 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (cname string, lines, err := queryDNS(ctx, name, "cname") if err != nil { - if stringsHasSuffix(err.Error(), "dns failure") || stringsHasSuffix(err.Error(), "resource does not exist; negrcode 0") { + if stringslite.HasSuffix(err.Error(), "dns failure") || + stringslite.HasSuffix(err.Error(), "resource does not exist; negrcode 0") || + stringslite.HasSuffix(err.Error(), "resource does not exist; negrcode") { return absDomainName(name), nil } return "", handlePlan9DNSError(err, cname) diff --git a/contrib/go/_std_1.22/src/net/lookup_unix.go b/contrib/go/_std_1.23/src/net/lookup_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/lookup_unix.go rename to contrib/go/_std_1.23/src/net/lookup_unix.go diff --git a/contrib/go/_std_1.22/src/net/lookup_windows.go b/contrib/go/_std_1.23/src/net/lookup_windows.go similarity index 81% rename from contrib/go/_std_1.22/src/net/lookup_windows.go rename to contrib/go/_std_1.23/src/net/lookup_windows.go index 3048f3269b00..7d415bee4f07 100644 --- a/contrib/go/_std_1.22/src/net/lookup_windows.go +++ b/contrib/go/_std_1.23/src/net/lookup_windows.go @@ -54,7 +54,10 @@ func lookupProtocol(ctx context.Context, name string) (int, error) { } ch := make(chan result) // unbuffered go func() { - acquireThread() + if err := acquireThread(ctx); err != nil { + ch <- result{err: mapErr(err)} + return + } defer releaseThread() runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -70,12 +73,7 @@ func lookupProtocol(ctx context.Context, name string) (int, error) { if proto, err := lookupProtocolMap(name); err == nil { return proto, nil } - - dnsError := &DNSError{Err: r.err.Error(), Name: name} - if r.err == errNoSuchHost { - dnsError.IsNotFound = true - } - r.err = dnsError + r.err = newDNSError(r.err, name, "") } return r.proto, r.err case <-ctx.Done(): @@ -111,7 +109,13 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr } getaddr := func() ([]IPAddr, error) { - acquireThread() + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() hints := syscall.AddrinfoW{ Family: family, @@ -121,7 +125,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr var result *syscall.AddrinfoW name16p, err := syscall.UTF16PtrFromString(name) if err != nil { - return nil, &DNSError{Name: name, Err: err.Error()} + return nil, newDNSError(err, name, "") } dnsConf := getSystemDNSConfig() @@ -135,12 +139,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr } } if e != nil { - err := winError("getaddrinfow", e) - dnsError := &DNSError{Err: err.Error(), Name: name} - if err == errNoSuchHost { - dnsError.IsNotFound = true - } - return nil, dnsError + return nil, newDNSError(winError("getaddrinfow", e), name, "") } defer syscall.FreeAddrInfoW(result) addrs := make([]IPAddr, 0, 5) @@ -155,7 +154,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr zone := zoneCache.name(int((*syscall.RawSockaddrInet6)(addr).Scope_id)) addrs = append(addrs, IPAddr{IP: copyIP(a[:]), Zone: zone}) default: - return nil, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name} + return nil, newDNSError(syscall.EWINDOWS, name, "") } } return addrs, nil @@ -187,11 +186,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr // // For now we just let it finish and write to the // buffered channel. - return nil, &DNSError{ - Name: name, - Err: ctx.Err().Error(), - IsTimeout: ctx.Err() == context.DeadlineExceeded, - } + return nil, newDNSError(mapErr(ctx.Err()), name, "") } } @@ -200,8 +195,14 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int return lookupPortMap(network, service) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing + if err := acquireThread(ctx); err != nil { + return 0, &DNSError{ + Name: network + "/" + service, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var hints syscall.AddrinfoW @@ -237,14 +238,13 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int // for _WSAHOST_NOT_FOUND here to match the cgo (unix) version // cgo_unix.go (cgoLookupServicePort). if e == _WSATYPE_NOT_FOUND || e == _WSAHOST_NOT_FOUND { - return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true} + return 0, newDNSError(errUnknownPort, network+"/"+service, "") } - err := os.NewSyscallError("getaddrinfow", e) - return 0, &DNSError{Err: err.Error(), Name: network + "/" + service} + return 0, newDNSError(winError("getaddrinfow", e), network+"/"+service, "") } defer syscall.FreeAddrInfoW(result) if result == nil { - return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service} + return 0, newDNSError(syscall.EINVAL, network+"/"+service, "") } addr := unsafe.Pointer(result.Addr) switch result.Family { @@ -255,7 +255,7 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int a := (*syscall.RawSockaddrInet6)(addr) return int(syscall.Ntohs(a.Port)), nil } - return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service} + return 0, newDNSError(syscall.EINVAL, network+"/"+service, "") } func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) { @@ -263,8 +263,14 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) return r.goLookupCNAME(ctx, name, order, conf) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing + if err := acquireThread(ctx); err != nil { + return "", &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &rec, nil) @@ -274,8 +280,7 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) return absDomainName(name), nil } if e != nil { - err := winError("dnsquery", e) - return "", &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return "", newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -288,8 +293,14 @@ func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) ( if systemConf().mustUseGoResolver(r) { return r.goLookupSRV(ctx, service, proto, name) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing + if err := acquireThread(ctx); err != nil { + return "", nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var target string if service == "" && proto == "" { @@ -300,8 +311,7 @@ func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) ( var rec *syscall.DNSRecord e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return "", nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return "", nil, newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -318,14 +328,19 @@ func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) { if systemConf().mustUseGoResolver(r) { return r.goLookupMX(ctx, name) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing. + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return nil, newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -342,14 +357,19 @@ func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) { if systemConf().mustUseGoResolver(r) { return r.goLookupNS(ctx, name) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing. + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return nil, newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -365,14 +385,19 @@ func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) if systemConf().mustUseGoResolver(r) { return r.goLookupTXT(ctx, name) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing. + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return nil, newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -393,8 +418,14 @@ func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error return r.goLookupPTR(ctx, addr, order, conf) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing. + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: addr, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() arpa, err := reverseaddr(addr) if err != nil { @@ -403,8 +434,7 @@ func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error var rec *syscall.DNSRecord e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return nil, &DNSError{Err: err.Error(), Name: addr, IsNotFound: err == errNoSuchHost} + return nil, newDNSError(winError("dnsquery", e), addr, "") } defer syscall.DnsRecordListFree(rec, 1) diff --git a/contrib/go/_std_1.22/src/net/mac.go b/contrib/go/_std_1.23/src/net/mac.go similarity index 100% rename from contrib/go/_std_1.22/src/net/mac.go rename to contrib/go/_std_1.23/src/net/mac.go diff --git a/contrib/go/_std_1.23/src/net/mail/message.go b/contrib/go/_std_1.23/src/net/mail/message.go new file mode 100644 index 000000000000..21b075e78aff --- /dev/null +++ b/contrib/go/_std_1.23/src/net/mail/message.go @@ -0,0 +1,975 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package mail implements parsing of mail messages. + +For the most part, this package follows the syntax as specified by RFC 5322 and +extended by RFC 6532. +Notable divergences: + - Obsolete address formats are not parsed, including addresses with + embedded route information. + - The full range of spacing (the CFWS syntax element) is not supported, + such as breaking addresses across lines. + - No unicode normalization is performed. + - A leading From line is permitted, as in mbox format (RFC 4155). +*/ +package mail + +import ( + "bufio" + "errors" + "fmt" + "io" + "log" + "mime" + "net" + "net/textproto" + "strings" + "sync" + "time" + "unicode/utf8" +) + +var debug = debugT(false) + +type debugT bool + +func (d debugT) Printf(format string, args ...any) { + if d { + log.Printf(format, args...) + } +} + +// A Message represents a parsed mail message. +type Message struct { + Header Header + Body io.Reader +} + +// ReadMessage reads a message from r. +// The headers are parsed, and the body of the message will be available +// for reading from msg.Body. +func ReadMessage(r io.Reader) (msg *Message, err error) { + tp := textproto.NewReader(bufio.NewReader(r)) + + hdr, err := readHeader(tp) + if err != nil && (err != io.EOF || len(hdr) == 0) { + return nil, err + } + + return &Message{ + Header: Header(hdr), + Body: tp.R, + }, nil +} + +// readHeader reads the message headers from r. +// This is like textproto.ReadMIMEHeader, but doesn't validate. +// The fix for issue #53188 tightened up net/textproto to enforce +// restrictions of RFC 7230. +// This package implements RFC 5322, which does not have those restrictions. +// This function copies the relevant code from net/textproto, +// simplified for RFC 5322. +func readHeader(r *textproto.Reader) (map[string][]string, error) { + m := make(map[string][]string) + + // The first line cannot start with a leading space. + if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { + line, err := r.ReadLine() + if err != nil { + return m, err + } + return m, errors.New("malformed initial line: " + line) + } + + for { + kv, err := r.ReadContinuedLine() + if kv == "" { + return m, err + } + + // Key ends at first colon. + k, v, ok := strings.Cut(kv, ":") + if !ok { + return m, errors.New("malformed header line: " + kv) + } + key := textproto.CanonicalMIMEHeaderKey(k) + + // Permit empty key, because that is what we did in the past. + if key == "" { + continue + } + + // Skip initial spaces in value. + value := strings.TrimLeft(v, " \t") + + m[key] = append(m[key], value) + + if err != nil { + return m, err + } + } +} + +// Layouts suitable for passing to time.Parse. +// These are tried in order. +var ( + dateLayoutsBuildOnce sync.Once + dateLayouts []string +) + +func buildDateLayouts() { + // Generate layouts based on RFC 5322, section 3.3. + + dows := [...]string{"", "Mon, "} // day-of-week + days := [...]string{"2", "02"} // day = 1*2DIGIT + years := [...]string{"2006", "06"} // year = 4*DIGIT / 2*DIGIT + seconds := [...]string{":05", ""} // second + // "-0700 (MST)" is not in RFC 5322, but is common. + zones := [...]string{"-0700", "MST", "UT"} // zone = (("+" / "-") 4DIGIT) / "UT" / "GMT" / ... + + for _, dow := range dows { + for _, day := range days { + for _, year := range years { + for _, second := range seconds { + for _, zone := range zones { + s := dow + day + " Jan " + year + " 15:04" + second + " " + zone + dateLayouts = append(dateLayouts, s) + } + } + } + } + } +} + +// ParseDate parses an RFC 5322 date string. +func ParseDate(date string) (time.Time, error) { + dateLayoutsBuildOnce.Do(buildDateLayouts) + // CR and LF must match and are tolerated anywhere in the date field. + date = strings.ReplaceAll(date, "\r\n", "") + if strings.Contains(date, "\r") { + return time.Time{}, errors.New("mail: header has a CR without LF") + } + // Re-using some addrParser methods which support obsolete text, i.e. non-printable ASCII + p := addrParser{date, nil} + p.skipSpace() + + // RFC 5322: zone = (FWS ( "+" / "-" ) 4DIGIT) / obs-zone + // zone length is always 5 chars unless obsolete (obs-zone) + if ind := strings.IndexAny(p.s, "+-"); ind != -1 && len(p.s) >= ind+5 { + date = p.s[:ind+5] + p.s = p.s[ind+5:] + } else { + ind := strings.Index(p.s, "T") + if ind == 0 { + // In this case we have the following date formats: + // * Thu, 20 Nov 1997 09:55:06 MDT + // * Thu, 20 Nov 1997 09:55:06 MDT (MDT) + // * Thu, 20 Nov 1997 09:55:06 MDT (This comment) + ind = strings.Index(p.s[1:], "T") + if ind != -1 { + ind++ + } + } + + if ind != -1 && len(p.s) >= ind+5 { + // The last letter T of the obsolete time zone is checked when no standard time zone is found. + // If T is misplaced, the date to parse is garbage. + date = p.s[:ind+1] + p.s = p.s[ind+1:] + } + } + if !p.skipCFWS() { + return time.Time{}, errors.New("mail: misformatted parenthetical comment") + } + for _, layout := range dateLayouts { + t, err := time.Parse(layout, date) + if err == nil { + return t, nil + } + } + return time.Time{}, errors.New("mail: header could not be parsed") +} + +// A Header represents the key-value pairs in a mail message header. +type Header map[string][]string + +// Get gets the first value associated with the given key. +// It is case insensitive; CanonicalMIMEHeaderKey is used +// to canonicalize the provided key. +// If there are no values associated with the key, Get returns "". +// To access multiple values of a key, or to use non-canonical keys, +// access the map directly. +func (h Header) Get(key string) string { + return textproto.MIMEHeader(h).Get(key) +} + +var ErrHeaderNotPresent = errors.New("mail: header not in message") + +// Date parses the Date header field. +func (h Header) Date() (time.Time, error) { + hdr := h.Get("Date") + if hdr == "" { + return time.Time{}, ErrHeaderNotPresent + } + return ParseDate(hdr) +} + +// AddressList parses the named header field as a list of addresses. +func (h Header) AddressList(key string) ([]*Address, error) { + hdr := h.Get(key) + if hdr == "" { + return nil, ErrHeaderNotPresent + } + return ParseAddressList(hdr) +} + +// Address represents a single mail address. +// An address such as "Barry Gibbs " is represented +// as Address{Name: "Barry Gibbs", Address: "bg@example.com"}. +type Address struct { + Name string // Proper name; may be empty. + Address string // user@domain +} + +// ParseAddress parses a single RFC 5322 address, e.g. "Barry Gibbs " +func ParseAddress(address string) (*Address, error) { + return (&addrParser{s: address}).parseSingleAddress() +} + +// ParseAddressList parses the given string as a list of addresses. +func ParseAddressList(list string) ([]*Address, error) { + return (&addrParser{s: list}).parseAddressList() +} + +// An AddressParser is an RFC 5322 address parser. +type AddressParser struct { + // WordDecoder optionally specifies a decoder for RFC 2047 encoded-words. + WordDecoder *mime.WordDecoder +} + +// Parse parses a single RFC 5322 address of the +// form "Gogh Fir " or "foo@example.com". +func (p *AddressParser) Parse(address string) (*Address, error) { + return (&addrParser{s: address, dec: p.WordDecoder}).parseSingleAddress() +} + +// ParseList parses the given string as a list of comma-separated addresses +// of the form "Gogh Fir " or "foo@example.com". +func (p *AddressParser) ParseList(list string) ([]*Address, error) { + return (&addrParser{s: list, dec: p.WordDecoder}).parseAddressList() +} + +// String formats the address as a valid RFC 5322 address. +// If the address's name contains non-ASCII characters +// the name will be rendered according to RFC 2047. +func (a *Address) String() string { + // Format address local@domain + at := strings.LastIndex(a.Address, "@") + var local, domain string + if at < 0 { + // This is a malformed address ("@" is required in addr-spec); + // treat the whole address as local-part. + local = a.Address + } else { + local, domain = a.Address[:at], a.Address[at+1:] + } + + // Add quotes if needed + quoteLocal := false + for i, r := range local { + if isAtext(r, false) { + continue + } + if r == '.' { + // Dots are okay if they are surrounded by atext. + // We only need to check that the previous byte is + // not a dot, and this isn't the end of the string. + if i > 0 && local[i-1] != '.' && i < len(local)-1 { + continue + } + } + quoteLocal = true + break + } + if quoteLocal { + local = quoteString(local) + + } + + s := "<" + local + "@" + domain + ">" + + if a.Name == "" { + return s + } + + // If every character is printable ASCII, quoting is simple. + allPrintable := true + for _, r := range a.Name { + // isWSP here should actually be isFWS, + // but we don't support folding yet. + if !isVchar(r) && !isWSP(r) || isMultibyte(r) { + allPrintable = false + break + } + } + if allPrintable { + return quoteString(a.Name) + " " + s + } + + // Text in an encoded-word in a display-name must not contain certain + // characters like quotes or parentheses (see RFC 2047 section 5.3). + // When this is the case encode the name using base64 encoding. + if strings.ContainsAny(a.Name, "\"#$%&'(),.:;<>@[]^`{|}~") { + return mime.BEncoding.Encode("utf-8", a.Name) + " " + s + } + return mime.QEncoding.Encode("utf-8", a.Name) + " " + s +} + +type addrParser struct { + s string + dec *mime.WordDecoder // may be nil +} + +func (p *addrParser) parseAddressList() ([]*Address, error) { + var list []*Address + for { + p.skipSpace() + + // allow skipping empty entries (RFC5322 obs-addr-list) + if p.consume(',') { + continue + } + + addrs, err := p.parseAddress(true) + if err != nil { + return nil, err + } + list = append(list, addrs...) + + if !p.skipCFWS() { + return nil, errors.New("mail: misformatted parenthetical comment") + } + if p.empty() { + break + } + if p.peek() != ',' { + return nil, errors.New("mail: expected comma") + } + + // Skip empty entries for obs-addr-list. + for p.consume(',') { + p.skipSpace() + } + if p.empty() { + break + } + } + return list, nil +} + +func (p *addrParser) parseSingleAddress() (*Address, error) { + addrs, err := p.parseAddress(true) + if err != nil { + return nil, err + } + if !p.skipCFWS() { + return nil, errors.New("mail: misformatted parenthetical comment") + } + if !p.empty() { + return nil, fmt.Errorf("mail: expected single address, got %q", p.s) + } + if len(addrs) == 0 { + return nil, errors.New("mail: empty group") + } + if len(addrs) > 1 { + return nil, errors.New("mail: group with multiple addresses") + } + return addrs[0], nil +} + +// parseAddress parses a single RFC 5322 address at the start of p. +func (p *addrParser) parseAddress(handleGroup bool) ([]*Address, error) { + debug.Printf("parseAddress: %q", p.s) + p.skipSpace() + if p.empty() { + return nil, errors.New("mail: no address") + } + + // address = mailbox / group + // mailbox = name-addr / addr-spec + // group = display-name ":" [group-list] ";" [CFWS] + + // addr-spec has a more restricted grammar than name-addr, + // so try parsing it first, and fallback to name-addr. + // TODO(dsymonds): Is this really correct? + spec, err := p.consumeAddrSpec() + if err == nil { + var displayName string + p.skipSpace() + if !p.empty() && p.peek() == '(' { + displayName, err = p.consumeDisplayNameComment() + if err != nil { + return nil, err + } + } + + return []*Address{{ + Name: displayName, + Address: spec, + }}, err + } + debug.Printf("parseAddress: not an addr-spec: %v", err) + debug.Printf("parseAddress: state is now %q", p.s) + + // display-name + var displayName string + if p.peek() != '<' { + displayName, err = p.consumePhrase() + if err != nil { + return nil, err + } + } + debug.Printf("parseAddress: displayName=%q", displayName) + + p.skipSpace() + if handleGroup { + if p.consume(':') { + return p.consumeGroupList() + } + } + // angle-addr = "<" addr-spec ">" + if !p.consume('<') { + atext := true + for _, r := range displayName { + if !isAtext(r, true) { + atext = false + break + } + } + if atext { + // The input is like "foo.bar"; it's possible the input + // meant to be "foo.bar@domain", or "foo.bar <...>". + return nil, errors.New("mail: missing '@' or angle-addr") + } + // The input is like "Full Name", which couldn't possibly be a + // valid email address if followed by "@domain"; the input + // likely meant to be "Full Name <...>". + return nil, errors.New("mail: no angle-addr") + } + spec, err = p.consumeAddrSpec() + if err != nil { + return nil, err + } + if !p.consume('>') { + return nil, errors.New("mail: unclosed angle-addr") + } + debug.Printf("parseAddress: spec=%q", spec) + + return []*Address{{ + Name: displayName, + Address: spec, + }}, nil +} + +func (p *addrParser) consumeGroupList() ([]*Address, error) { + var group []*Address + // handle empty group. + p.skipSpace() + if p.consume(';') { + if !p.skipCFWS() { + return nil, errors.New("mail: misformatted parenthetical comment") + } + return group, nil + } + + for { + p.skipSpace() + // embedded groups not allowed. + addrs, err := p.parseAddress(false) + if err != nil { + return nil, err + } + group = append(group, addrs...) + + if !p.skipCFWS() { + return nil, errors.New("mail: misformatted parenthetical comment") + } + if p.consume(';') { + if !p.skipCFWS() { + return nil, errors.New("mail: misformatted parenthetical comment") + } + break + } + if !p.consume(',') { + return nil, errors.New("mail: expected comma") + } + } + return group, nil +} + +// consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p. +func (p *addrParser) consumeAddrSpec() (spec string, err error) { + debug.Printf("consumeAddrSpec: %q", p.s) + + orig := *p + defer func() { + if err != nil { + *p = orig + } + }() + + // local-part = dot-atom / quoted-string + var localPart string + p.skipSpace() + if p.empty() { + return "", errors.New("mail: no addr-spec") + } + if p.peek() == '"' { + // quoted-string + debug.Printf("consumeAddrSpec: parsing quoted-string") + localPart, err = p.consumeQuotedString() + if localPart == "" { + err = errors.New("mail: empty quoted string in addr-spec") + } + } else { + // dot-atom + debug.Printf("consumeAddrSpec: parsing dot-atom") + localPart, err = p.consumeAtom(true, false) + } + if err != nil { + debug.Printf("consumeAddrSpec: failed: %v", err) + return "", err + } + + if !p.consume('@') { + return "", errors.New("mail: missing @ in addr-spec") + } + + // domain = dot-atom / domain-literal + var domain string + p.skipSpace() + if p.empty() { + return "", errors.New("mail: no domain in addr-spec") + } + + if p.peek() == '[' { + // domain-literal + domain, err = p.consumeDomainLiteral() + if err != nil { + return "", err + } + } else { + // dot-atom + domain, err = p.consumeAtom(true, false) + if err != nil { + return "", err + } + } + + return localPart + "@" + domain, nil +} + +// consumePhrase parses the RFC 5322 phrase at the start of p. +func (p *addrParser) consumePhrase() (phrase string, err error) { + debug.Printf("consumePhrase: [%s]", p.s) + // phrase = 1*word + var words []string + var isPrevEncoded bool + for { + // obs-phrase allows CFWS after one word + if len(words) > 0 { + if !p.skipCFWS() { + return "", errors.New("mail: misformatted parenthetical comment") + } + } + // word = atom / quoted-string + var word string + p.skipSpace() + if p.empty() { + break + } + isEncoded := false + if p.peek() == '"' { + // quoted-string + word, err = p.consumeQuotedString() + } else { + // atom + // We actually parse dot-atom here to be more permissive + // than what RFC 5322 specifies. + word, err = p.consumeAtom(true, true) + if err == nil { + word, isEncoded, err = p.decodeRFC2047Word(word) + } + } + + if err != nil { + break + } + debug.Printf("consumePhrase: consumed %q", word) + if isPrevEncoded && isEncoded { + words[len(words)-1] += word + } else { + words = append(words, word) + } + isPrevEncoded = isEncoded + } + // Ignore any error if we got at least one word. + if err != nil && len(words) == 0 { + debug.Printf("consumePhrase: hit err: %v", err) + return "", fmt.Errorf("mail: missing word in phrase: %v", err) + } + phrase = strings.Join(words, " ") + return phrase, nil +} + +// consumeQuotedString parses the quoted string at the start of p. +func (p *addrParser) consumeQuotedString() (qs string, err error) { + // Assume first byte is '"'. + i := 1 + qsb := make([]rune, 0, 10) + + escaped := false + +Loop: + for { + r, size := utf8.DecodeRuneInString(p.s[i:]) + + switch { + case size == 0: + return "", errors.New("mail: unclosed quoted-string") + + case size == 1 && r == utf8.RuneError: + return "", fmt.Errorf("mail: invalid utf-8 in quoted-string: %q", p.s) + + case escaped: + // quoted-pair = ("\" (VCHAR / WSP)) + + if !isVchar(r) && !isWSP(r) { + return "", fmt.Errorf("mail: bad character in quoted-string: %q", r) + } + + qsb = append(qsb, r) + escaped = false + + case isQtext(r) || isWSP(r): + // qtext (printable US-ASCII excluding " and \), or + // FWS (almost; we're ignoring CRLF) + qsb = append(qsb, r) + + case r == '"': + break Loop + + case r == '\\': + escaped = true + + default: + return "", fmt.Errorf("mail: bad character in quoted-string: %q", r) + + } + + i += size + } + p.s = p.s[i+1:] + return string(qsb), nil +} + +// consumeAtom parses an RFC 5322 atom at the start of p. +// If dot is true, consumeAtom parses an RFC 5322 dot-atom instead. +// If permissive is true, consumeAtom will not fail on: +// - leading/trailing/double dots in the atom (see golang.org/issue/4938) +func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) { + i := 0 + +Loop: + for { + r, size := utf8.DecodeRuneInString(p.s[i:]) + switch { + case size == 1 && r == utf8.RuneError: + return "", fmt.Errorf("mail: invalid utf-8 in address: %q", p.s) + + case size == 0 || !isAtext(r, dot): + break Loop + + default: + i += size + + } + } + + if i == 0 { + return "", errors.New("mail: invalid string") + } + atom, p.s = p.s[:i], p.s[i:] + if !permissive { + if strings.HasPrefix(atom, ".") { + return "", errors.New("mail: leading dot in atom") + } + if strings.Contains(atom, "..") { + return "", errors.New("mail: double dot in atom") + } + if strings.HasSuffix(atom, ".") { + return "", errors.New("mail: trailing dot in atom") + } + } + return atom, nil +} + +// consumeDomainLiteral parses an RFC 5322 domain-literal at the start of p. +func (p *addrParser) consumeDomainLiteral() (string, error) { + // Skip the leading [ + if !p.consume('[') { + return "", errors.New(`mail: missing "[" in domain-literal`) + } + + // Parse the dtext + var dtext string + for { + if p.empty() { + return "", errors.New("mail: unclosed domain-literal") + } + if p.peek() == ']' { + break + } + + r, size := utf8.DecodeRuneInString(p.s) + if size == 1 && r == utf8.RuneError { + return "", fmt.Errorf("mail: invalid utf-8 in domain-literal: %q", p.s) + } + if !isDtext(r) { + return "", fmt.Errorf("mail: bad character in domain-literal: %q", r) + } + + dtext += p.s[:size] + p.s = p.s[size:] + } + + // Skip the trailing ] + if !p.consume(']') { + return "", errors.New("mail: unclosed domain-literal") + } + + // Check if the domain literal is an IP address + if net.ParseIP(dtext) == nil { + return "", fmt.Errorf("mail: invalid IP address in domain-literal: %q", dtext) + } + + return "[" + dtext + "]", nil +} + +func (p *addrParser) consumeDisplayNameComment() (string, error) { + if !p.consume('(') { + return "", errors.New("mail: comment does not start with (") + } + comment, ok := p.consumeComment() + if !ok { + return "", errors.New("mail: misformatted parenthetical comment") + } + + // TODO(stapelberg): parse quoted-string within comment + words := strings.FieldsFunc(comment, func(r rune) bool { return r == ' ' || r == '\t' }) + for idx, word := range words { + decoded, isEncoded, err := p.decodeRFC2047Word(word) + if err != nil { + return "", err + } + if isEncoded { + words[idx] = decoded + } + } + + return strings.Join(words, " "), nil +} + +func (p *addrParser) consume(c byte) bool { + if p.empty() || p.peek() != c { + return false + } + p.s = p.s[1:] + return true +} + +// skipSpace skips the leading space and tab characters. +func (p *addrParser) skipSpace() { + p.s = strings.TrimLeft(p.s, " \t") +} + +func (p *addrParser) peek() byte { + return p.s[0] +} + +func (p *addrParser) empty() bool { + return p.len() == 0 +} + +func (p *addrParser) len() int { + return len(p.s) +} + +// skipCFWS skips CFWS as defined in RFC5322. +func (p *addrParser) skipCFWS() bool { + p.skipSpace() + + for { + if !p.consume('(') { + break + } + + if _, ok := p.consumeComment(); !ok { + return false + } + + p.skipSpace() + } + + return true +} + +func (p *addrParser) consumeComment() (string, bool) { + // '(' already consumed. + depth := 1 + + var comment string + for { + if p.empty() || depth == 0 { + break + } + + if p.peek() == '\\' && p.len() > 1 { + p.s = p.s[1:] + } else if p.peek() == '(' { + depth++ + } else if p.peek() == ')' { + depth-- + } + if depth > 0 { + comment += p.s[:1] + } + p.s = p.s[1:] + } + + return comment, depth == 0 +} + +func (p *addrParser) decodeRFC2047Word(s string) (word string, isEncoded bool, err error) { + dec := p.dec + if dec == nil { + dec = &rfc2047Decoder + } + + // Substitute our own CharsetReader function so that we can tell + // whether an error from the Decode method was due to the + // CharsetReader (meaning the charset is invalid). + // We used to look for the charsetError type in the error result, + // but that behaves badly with CharsetReaders other than the + // one in rfc2047Decoder. + adec := *dec + charsetReaderError := false + adec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { + if dec.CharsetReader == nil { + charsetReaderError = true + return nil, charsetError(charset) + } + r, err := dec.CharsetReader(charset, input) + if err != nil { + charsetReaderError = true + } + return r, err + } + word, err = adec.Decode(s) + if err == nil { + return word, true, nil + } + + // If the error came from the character set reader + // (meaning the character set itself is invalid + // but the decoding worked fine until then), + // return the original text and the error, + // with isEncoded=true. + if charsetReaderError { + return s, true, err + } + + // Ignore invalid RFC 2047 encoded-word errors. + return s, false, nil +} + +var rfc2047Decoder = mime.WordDecoder{ + CharsetReader: func(charset string, input io.Reader) (io.Reader, error) { + return nil, charsetError(charset) + }, +} + +type charsetError string + +func (e charsetError) Error() string { + return fmt.Sprintf("charset not supported: %q", string(e)) +} + +// isAtext reports whether r is an RFC 5322 atext character. +// If dot is true, period is included. +func isAtext(r rune, dot bool) bool { + switch r { + case '.': + return dot + + // RFC 5322 3.2.3. specials + case '(', ')', '<', '>', '[', ']', ':', ';', '@', '\\', ',', '"': // RFC 5322 3.2.3. specials + return false + } + return isVchar(r) +} + +// isQtext reports whether r is an RFC 5322 qtext character. +func isQtext(r rune) bool { + // Printable US-ASCII, excluding backslash or quote. + if r == '\\' || r == '"' { + return false + } + return isVchar(r) +} + +// quoteString renders a string as an RFC 5322 quoted-string. +func quoteString(s string) string { + var b strings.Builder + b.WriteByte('"') + for _, r := range s { + if isQtext(r) || isWSP(r) { + b.WriteRune(r) + } else if isVchar(r) { + b.WriteByte('\\') + b.WriteRune(r) + } + } + b.WriteByte('"') + return b.String() +} + +// isVchar reports whether r is an RFC 5322 VCHAR character. +func isVchar(r rune) bool { + // Visible (printing) characters. + return '!' <= r && r <= '~' || isMultibyte(r) +} + +// isMultibyte reports whether r is a multi-byte UTF-8 character +// as supported by RFC 6532. +func isMultibyte(r rune) bool { + return r >= utf8.RuneSelf +} + +// isWSP reports whether r is a WSP (white space). +// WSP is a space or horizontal tab (RFC 5234 Appendix B). +func isWSP(r rune) bool { + return r == ' ' || r == '\t' +} + +// isDtext reports whether r is an RFC 5322 dtext character. +func isDtext(r rune) bool { + // Printable US-ASCII, excluding "[", "]", or "\". + if r == '[' || r == ']' || r == '\\' { + return false + } + return isVchar(r) +} diff --git a/contrib/go/_std_1.22/src/net/mail/ya.make b/contrib/go/_std_1.23/src/net/mail/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/mail/ya.make rename to contrib/go/_std_1.23/src/net/mail/ya.make diff --git a/contrib/go/_std_1.22/src/net/mptcpsock_linux.go b/contrib/go/_std_1.23/src/net/mptcpsock_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/mptcpsock_linux.go rename to contrib/go/_std_1.23/src/net/mptcpsock_linux.go diff --git a/contrib/go/_std_1.22/src/net/mptcpsock_stub.go b/contrib/go/_std_1.23/src/net/mptcpsock_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/mptcpsock_stub.go rename to contrib/go/_std_1.23/src/net/mptcpsock_stub.go diff --git a/contrib/go/_std_1.22/src/net/net.go b/contrib/go/_std_1.23/src/net/net.go similarity index 90% rename from contrib/go/_std_1.22/src/net/net.go rename to contrib/go/_std_1.23/src/net/net.go index 2dd1b5865e5d..f8b5834acba5 100644 --- a/contrib/go/_std_1.22/src/net/net.go +++ b/contrib/go/_std_1.23/src/net/net.go @@ -46,16 +46,19 @@ It can use a pure Go resolver that sends DNS requests directly to the servers listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C library routines such as getaddrinfo and getnameinfo. -By default the pure Go resolver is used, because a blocked DNS request consumes -only a goroutine, while a blocked C call consumes an operating system thread. +On Unix the pure Go resolver is preferred over the cgo resolver, because a blocked DNS +request consumes only a goroutine, while a blocked C call consumes an operating system thread. When cgo is available, the cgo-based resolver is used instead under a variety of conditions: on systems that do not let programs make direct DNS requests (OS X), when the LOCALDOMAIN environment variable is present (even if empty), when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, when the ASR_CONFIG environment variable is non-empty (OpenBSD only), when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the -Go resolver does not implement, and when the name being looked up ends in .local -or is an mDNS name. +Go resolver does not implement. + +On all systems (except Plan 9), when the cgo resolver is being used +this package applies a concurrent cgo lookup limit to prevent the system +from running out of system threads. Currently, it is limited to 500 concurrent lookups. The resolver decision can be overridden by setting the netdns value of the GODEBUG environment variable (see package runtime) to go or cgo, as in: @@ -97,6 +100,7 @@ import ( "sync" "syscall" "time" + _ "unsafe" // for linkname ) // Addr represents a network end point address. @@ -375,6 +379,18 @@ var listenerBacklogCache struct { } // listenerBacklog is a caching wrapper around maxListenerBacklog. +// +// listenerBacklog should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/database64128/tfo-go/v2 +// - github.com/metacubex/tfo-go +// - github.com/sagernet/tfo-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname listenerBacklog func listenerBacklog() int { listenerBacklogCache.Do(func() { listenerBacklogCache.val = maxListenerBacklog() }) return listenerBacklogCache.val @@ -620,11 +636,27 @@ func (e *DNSConfigError) Temporary() bool { return false } // Various errors contained in DNSError. var ( - errNoSuchHost = errors.New("no such host") + errNoSuchHost = ¬FoundError{"no such host"} + errUnknownPort = ¬FoundError{"unknown port"} ) +// notFoundError is a special error understood by the newDNSError function, +// which causes a creation of a DNSError with IsNotFound field set to true. +type notFoundError struct{ s string } + +func (e *notFoundError) Error() string { return e.s } + +// temporaryError is an error type that implements the [Error] interface. +// It returns true from the Temporary method. +type temporaryError struct{ s string } + +func (e *temporaryError) Error() string { return e.s } +func (e *temporaryError) Temporary() bool { return true } +func (e *temporaryError) Timeout() bool { return false } + // DNSError represents a DNS lookup error. type DNSError struct { + UnwrapErr error // error returned by the [DNSError.Unwrap] method, might be nil Err string // description of the error Name string // name looked for Server string // server used @@ -637,6 +669,41 @@ type DNSError struct { IsNotFound bool } +// newDNSError creates a new *DNSError. +// Based on the err, it sets the UnwrapErr, IsTimeout, IsTemporary, IsNotFound fields. +func newDNSError(err error, name, server string) *DNSError { + var ( + isTimeout bool + isTemporary bool + unwrapErr error + ) + + if err, ok := err.(Error); ok { + isTimeout = err.Timeout() + isTemporary = err.Temporary() + } + + // At this time, the only errors we wrap are context errors, to allow + // users to check for canceled/timed out requests. + if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) { + unwrapErr = err + } + + _, isNotFound := err.(*notFoundError) + return &DNSError{ + UnwrapErr: unwrapErr, + Err: err.Error(), + Name: name, + Server: server, + IsTimeout: isTimeout, + IsTemporary: isTemporary, + IsNotFound: isNotFound, + } +} + +// Unwrap returns e.UnwrapErr. +func (e *DNSError) Unwrap() error { return e.UnwrapErr } + func (e *DNSError) Error() string { if e == nil { return "" @@ -729,11 +796,16 @@ var threadLimit chan struct{} var threadOnce sync.Once -func acquireThread() { +func acquireThread(ctx context.Context) error { threadOnce.Do(func() { threadLimit = make(chan struct{}, concurrentThreadsLimit()) }) - threadLimit <- struct{}{} + select { + case threadLimit <- struct{}{}: + return nil + case <-ctx.Done(): + return ctx.Err() + } } func releaseThread() { diff --git a/contrib/go/_std_1.22/src/net/net_fake.go b/contrib/go/_std_1.23/src/net/net_fake.go similarity index 96% rename from contrib/go/_std_1.22/src/net/net_fake.go rename to contrib/go/_std_1.23/src/net/net_fake.go index 525ff3229683..f7eb28e01ac3 100644 --- a/contrib/go/_std_1.22/src/net/net_fake.go +++ b/contrib/go/_std_1.23/src/net/net_fake.go @@ -14,7 +14,6 @@ import ( "errors" "io" "os" - "runtime" "sync" "sync/atomic" "syscall" @@ -23,7 +22,6 @@ import ( var ( sockets sync.Map // fakeSockAddr → *netFD - fakeSocketIDs sync.Map // fakeNetFD.id → *netFD fakePorts sync.Map // int (port #) → *netFD nextPortCounter atomic.Int32 ) @@ -326,14 +324,27 @@ func (ffd *fakeNetFD) accept(laddr Addr) (*netFD, error) { incoming []*netFD ok bool ) + expired := ffd.readDeadline.Load().expired select { - case <-ffd.readDeadline.Load().expired: + case <-expired: return nil, os.ErrDeadlineExceeded case incoming, ok = <-ffd.incoming: if !ok { return nil, ErrClosed } + select { + case <-expired: + ffd.incoming <- incoming + return nil, os.ErrDeadlineExceeded + default: + } case incoming, ok = <-ffd.incomingFull: + select { + case <-expired: + ffd.incomingFull <- incoming + return nil, os.ErrDeadlineExceeded + default: + } } peer := incoming[0] @@ -448,16 +459,6 @@ func (pq *packetQueue) put(q packetQueueState) { func (pq *packetQueue) closeRead() error { q := pq.get() - - // Discard any unread packets. - for q.head != nil { - p := q.head - q.head = p.next - p.clear() - packetPool.Put(p) - } - q.nBytes = 0 - q.readClosed = true pq.put(q) return nil @@ -515,14 +516,6 @@ func (pq *packetQueue) send(dt *deadlineTimer, b []byte, from sockaddr, block bo full = pq.full } - // Before we check dt.expired, yield to other goroutines. - // This may help to prevent starvation of the goroutine that runs the - // deadlineTimer's time.After callback. - // - // TODO(#65178): Remove this when the runtime scheduler no longer starves - // runnable goroutines. - runtime.Gosched() - select { case <-dt.expired: return 0, os.ErrDeadlineExceeded @@ -545,7 +538,7 @@ func (pq *packetQueue) send(dt *deadlineTimer, b []byte, from sockaddr, block bo } if q.writeClosed { return 0, ErrClosed - } else if q.readClosed { + } else if q.readClosed && q.nBytes >= q.readBufferBytes { return 0, os.NewSyscallError("send", syscall.ECONNRESET) } @@ -574,14 +567,6 @@ func (pq *packetQueue) recvfrom(dt *deadlineTimer, b []byte, wholePacket bool, c empty = pq.empty } - // Before we check dt.expired, yield to other goroutines. - // This may help to prevent starvation of the goroutine that runs the - // deadlineTimer's time.After callback. - // - // TODO(#65178): Remove this when the runtime scheduler no longer starves - // runnable goroutines. - runtime.Gosched() - select { case <-dt.expired: return 0, nil, os.ErrDeadlineExceeded @@ -591,11 +576,13 @@ func (pq *packetQueue) recvfrom(dt *deadlineTimer, b []byte, wholePacket bool, c } defer func() { pq.put(q) }() + if q.readClosed { + return 0, nil, ErrClosed + } + p := q.head if p == nil { switch { - case q.readClosed: - return 0, nil, ErrClosed case q.writeClosed: if q.noLinger { return 0, nil, os.NewSyscallError("recvfrom", syscall.ECONNRESET) diff --git a/contrib/go/_std_1.22/src/net/netcgo_off.go b/contrib/go/_std_1.23/src/net/netcgo_off.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netcgo_off.go rename to contrib/go/_std_1.23/src/net/netcgo_off.go diff --git a/contrib/go/_std_1.22/src/net/netcgo_on.go b/contrib/go/_std_1.23/src/net/netcgo_on.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netcgo_on.go rename to contrib/go/_std_1.23/src/net/netcgo_on.go diff --git a/contrib/go/_std_1.22/src/net/netgo_netcgo.go b/contrib/go/_std_1.23/src/net/netgo_netcgo.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netgo_netcgo.go rename to contrib/go/_std_1.23/src/net/netgo_netcgo.go diff --git a/contrib/go/_std_1.22/src/net/netgo_off.go b/contrib/go/_std_1.23/src/net/netgo_off.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netgo_off.go rename to contrib/go/_std_1.23/src/net/netgo_off.go diff --git a/contrib/go/_std_1.22/src/net/netgo_on.go b/contrib/go/_std_1.23/src/net/netgo_on.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netgo_on.go rename to contrib/go/_std_1.23/src/net/netgo_on.go diff --git a/contrib/go/_std_1.22/src/net/netip/netip.go b/contrib/go/_std_1.23/src/net/netip/netip.go similarity index 91% rename from contrib/go/_std_1.22/src/net/netip/netip.go rename to contrib/go/_std_1.23/src/net/netip/netip.go index 92cb57efef9a..a1e93cb29bfb 100644 --- a/contrib/go/_std_1.22/src/net/netip/netip.go +++ b/contrib/go/_std_1.23/src/net/netip/netip.go @@ -14,12 +14,12 @@ package netip import ( "cmp" "errors" - "math" - "strconv" - "internal/bytealg" - "internal/intern" + "internal/byteorder" "internal/itoa" + "math" + "strconv" + "unique" ) // Sizes: (64-bit) @@ -53,22 +53,22 @@ type Addr struct { // bytewise processing. addr uint128 - // z is a combination of the address family and the IPv6 zone. - // - // nil means invalid IP address (for a zero Addr). - // z4 means an IPv4 address. - // z6noz means an IPv6 address without a zone. - // - // Otherwise it's the interned zone name string. - z *intern.Value + // Details about the address, wrapped up together and canonicalized. + z unique.Handle[addrDetail] +} + +// addrDetail represents the details of an Addr, like address family and IPv6 zone. +type addrDetail struct { + isV6 bool // IPv4 is false, IPv6 is true. + zoneV6 string // != "" only if IsV6 is true. } // z0, z4, and z6noz are sentinel Addr.z values. // See the Addr type's field docs. var ( - z0 = (*intern.Value)(nil) - z4 = new(intern.Value) - z6noz = new(intern.Value) + z0 unique.Handle[addrDetail] + z4 = unique.Make(addrDetail{}) + z6noz = unique.Make(addrDetail{isV6: true}) ) // IPv6LinkLocalAllNodes returns the IPv6 link-local all nodes multicast @@ -102,8 +102,8 @@ func AddrFrom4(addr [4]byte) Addr { func AddrFrom16(addr [16]byte) Addr { return Addr{ addr: uint128{ - beUint64(addr[:8]), - beUint64(addr[8:]), + byteorder.BeUint64(addr[:8]), + byteorder.BeUint64(addr[8:]), }, z: z6noz, } @@ -152,44 +152,53 @@ func (err parseAddrError) Error() string { return "ParseAddr(" + q(err.in) + "): " + err.msg } -// parseIPv4 parses s as an IPv4 address (in form "192.168.0.1"). -func parseIPv4(s string) (ip Addr, err error) { - var fields [4]uint8 +func parseIPv4Fields(in string, off, end int, fields []uint8) error { var val, pos int var digLen int // number of digits in current octet + s := in[off:end] for i := 0; i < len(s); i++ { if s[i] >= '0' && s[i] <= '9' { if digLen == 1 && val == 0 { - return Addr{}, parseAddrError{in: s, msg: "IPv4 field has octet with leading zero"} + return parseAddrError{in: in, msg: "IPv4 field has octet with leading zero"} } val = val*10 + int(s[i]) - '0' digLen++ if val > 255 { - return Addr{}, parseAddrError{in: s, msg: "IPv4 field has value >255"} + return parseAddrError{in: in, msg: "IPv4 field has value >255"} } } else if s[i] == '.' { // .1.2.3 // 1.2.3. // 1..2.3 if i == 0 || i == len(s)-1 || s[i-1] == '.' { - return Addr{}, parseAddrError{in: s, msg: "IPv4 field must have at least one digit", at: s[i:]} + return parseAddrError{in: in, msg: "IPv4 field must have at least one digit", at: s[i:]} } // 1.2.3.4.5 if pos == 3 { - return Addr{}, parseAddrError{in: s, msg: "IPv4 address too long"} + return parseAddrError{in: in, msg: "IPv4 address too long"} } fields[pos] = uint8(val) pos++ val = 0 digLen = 0 } else { - return Addr{}, parseAddrError{in: s, msg: "unexpected character", at: s[i:]} + return parseAddrError{in: in, msg: "unexpected character", at: s[i:]} } } if pos < 3 { - return Addr{}, parseAddrError{in: s, msg: "IPv4 address too short"} + return parseAddrError{in: in, msg: "IPv4 address too short"} } fields[3] = uint8(val) + return nil +} + +// parseIPv4 parses s as an IPv4 address (in form "192.168.0.1"). +func parseIPv4(s string) (ip Addr, err error) { + var fields [4]uint8 + err = parseIPv4Fields(s, 0, len(s), fields[:]) + if err != nil { + return Addr{}, err + } return AddrFrom4(fields), nil } @@ -242,6 +251,10 @@ func parseIPv6(in string) (Addr, error) { } else { break } + if off > 3 { + //more than 4 digits in group, fail. + return Addr{}, parseAddrError{in: in, msg: "each group must have 4 or less digits", at: s} + } if acc > math.MaxUint16 { // Overflow, fail. return Addr{}, parseAddrError{in: in, msg: "IPv6 field has value >=2^16", at: s} @@ -262,17 +275,15 @@ func parseIPv6(in string) (Addr, error) { // Not enough room. return Addr{}, parseAddrError{in: in, msg: "too many hex fields to fit an embedded IPv4 at the end of the address", at: s} } - // TODO: could make this a bit faster by having a helper - // that parses to a [4]byte, and have both parseIPv4 and - // parseIPv6 use it. - ip4, err := parseIPv4(s) + + end := len(in) + if len(zone) > 0 { + end -= len(zone) + 1 + } + err := parseIPv4Fields(in, end-len(s), end, ip[i:i+4]) if err != nil { - return Addr{}, parseAddrError{in: in, msg: err.Error(), at: s} + return Addr{}, err } - ip[i] = ip4.v4(0) - ip[i+1] = ip4.v4(1) - ip[i+2] = ip4.v4(2) - ip[i+3] = ip4.v4(3) s = "" i += 4 break @@ -324,9 +335,7 @@ func parseIPv6(in string) (Addr, error) { for j := i - 1; j >= ellipsis; j-- { ip[j+n] = ip[j] } - for j := ellipsis + n - 1; j >= ellipsis; j-- { - ip[j] = 0 - } + clear(ip[ellipsis : ellipsis+n]) } else if ellipsis >= 0 { // Ellipsis must represent at least one 0 group. return Addr{}, parseAddrError{in: in, msg: "the :: must expand to at least one field of zeros"} @@ -398,11 +407,10 @@ func (ip Addr) BitLen() int { // Zone returns ip's IPv6 scoped addressing zone, if any. func (ip Addr) Zone() string { - if ip.z == nil { + if ip.z == z0 { return "" } - zone, _ := ip.z.Get().(string) - return zone + return ip.z.Value().zoneV6 } // Compare returns an integer comparing two IPs. @@ -487,7 +495,7 @@ func (ip Addr) WithZone(zone string) Addr { ip.z = z6noz return ip } - ip.z = intern.GetByString(zone) + ip.z = unique.Make(addrDetail{isV6: true, zoneV6: zone}) return ip } @@ -692,8 +700,8 @@ func (ip Addr) Prefix(b int) (Prefix, error) { // [Addr.Zone] method to get it). // The ip zero value returns all zeroes. func (ip Addr) As16() (a16 [16]byte) { - bePutUint64(a16[:8], ip.addr.hi) - bePutUint64(a16[8:], ip.addr.lo) + byteorder.BePutUint64(a16[:8], ip.addr.hi) + byteorder.BePutUint64(a16[8:], ip.addr.lo) return a16 } @@ -702,7 +710,7 @@ func (ip Addr) As16() (a16 [16]byte) { // Note that 0.0.0.0 is not the zero Addr. func (ip Addr) As4() (a4 [4]byte) { if ip.z == z4 || ip.Is4In6() { - bePutUint32(a4[:], uint32(ip.addr.lo)) + byteorder.BePutUint32(a4[:], uint32(ip.addr.lo)) return a4 } if ip.z == z0 { @@ -718,12 +726,12 @@ func (ip Addr) AsSlice() []byte { return nil case z4: var ret [4]byte - bePutUint32(ret[:], uint32(ip.addr.lo)) + byteorder.BePutUint32(ret[:], uint32(ip.addr.lo)) return ret[:] default: var ret [16]byte - bePutUint64(ret[:8], ip.addr.hi) - bePutUint64(ret[8:], ip.addr.lo) + byteorder.BePutUint64(ret[:8], ip.addr.hi) + byteorder.BePutUint64(ret[8:], ip.addr.lo) return ret[:] } } @@ -780,11 +788,7 @@ func (ip Addr) String() string { return ip.string4() default: if ip.Is4In6() { - if z := ip.Zone(); z != "" { - return "::ffff:" + ip.Unmap().string4() + "%" + z - } else { - return "::ffff:" + ip.Unmap().string4() - } + return ip.string4In6() } return ip.string6() } @@ -801,13 +805,7 @@ func (ip Addr) AppendTo(b []byte) []byte { return ip.appendTo4(b) default: if ip.Is4In6() { - b = append(b, "::ffff:"...) - b = ip.Unmap().appendTo4(b) - if z := ip.Zone(); z != "" { - b = append(b, '%') - b = append(b, z...) - } - return b + return ip.appendTo4In6(b) } return ip.appendTo6(b) } @@ -871,6 +869,23 @@ func (ip Addr) appendTo4(ret []byte) []byte { return ret } +func (ip Addr) string4In6() string { + const max = len("::ffff:255.255.255.255%enp5s0") + ret := make([]byte, 0, max) + ret = ip.appendTo4In6(ret) + return string(ret) +} + +func (ip Addr) appendTo4In6(ret []byte) []byte { + ret = append(ret, "::ffff:"...) + ret = ip.Unmap().appendTo4(ret) + if ip.z != z6noz { + ret = append(ret, '%') + ret = append(ret, ip.Zone()...) + } + return ret +} + // string6 formats ip in IPv6 textual representation. It follows the // guidelines in section 4 of RFC 5952 // (https://tools.ietf.org/html/rfc5952#section-4): no unnecessary @@ -963,20 +978,15 @@ func (ip Addr) MarshalText() ([]byte, error) { b := make([]byte, 0, max) return ip.appendTo4(b), nil default: - max := len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") - b := make([]byte, 0, max) if ip.Is4In6() { - b = append(b, "::ffff:"...) - b = ip.Unmap().appendTo4(b) - if z := ip.Zone(); z != "" { - b = append(b, '%') - b = append(b, z...) - } - return b, nil + max := len("::ffff:255.255.255.255%enp5s0") + b := make([]byte, 0, max) + return ip.appendTo4In6(b), nil } + max := len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") + b := make([]byte, 0, max) return ip.appendTo6(b), nil } - } // UnmarshalText implements the encoding.TextUnmarshaler interface. @@ -1001,12 +1011,12 @@ func (ip Addr) marshalBinaryWithTrailingBytes(trailingBytes int) []byte { b = make([]byte, trailingBytes) case z4: b = make([]byte, 4+trailingBytes) - bePutUint32(b, uint32(ip.addr.lo)) + byteorder.BePutUint32(b, uint32(ip.addr.lo)) default: z := ip.Zone() b = make([]byte, 16+len(z)+trailingBytes) - bePutUint64(b[:8], ip.addr.hi) - bePutUint64(b[8:], ip.addr.lo) + byteorder.BePutUint64(b[:8], ip.addr.hi) + byteorder.BePutUint64(b[8:], ip.addr.lo) copy(b[16:], z) } return b @@ -1138,20 +1148,31 @@ func (p AddrPort) Compare(p2 AddrPort) int { } func (p AddrPort) String() string { + var b []byte switch p.ip.z { case z0: return "invalid AddrPort" case z4: const max = len("255.255.255.255:65535") - buf := make([]byte, 0, max) - buf = p.ip.appendTo4(buf) - buf = append(buf, ':') - buf = strconv.AppendUint(buf, uint64(p.port), 10) - return string(buf) + b = make([]byte, 0, max) + b = p.ip.appendTo4(b) default: - // TODO: this could be more efficient allocation-wise: - return "[" + p.ip.String() + "]:" + itoa.Uitoa(uint(p.port)) + if p.ip.Is4In6() { + const max = len("[::ffff:255.255.255.255%enp5s0]:65535") + b = make([]byte, 0, max) + b = append(b, '[') + b = p.ip.appendTo4In6(b) + } else { + const max = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535") + b = make([]byte, 0, max) + b = append(b, '[') + b = p.ip.appendTo6(b) + } + b = append(b, ']') } + b = append(b, ':') + b = strconv.AppendUint(b, uint64(p.port), 10) + return string(b) } // AppendTo appends a text encoding of p, @@ -1164,15 +1185,10 @@ func (p AddrPort) AppendTo(b []byte) []byte { case z4: b = p.ip.appendTo4(b) default: + b = append(b, '[') if p.ip.Is4In6() { - b = append(b, "[::ffff:"...) - b = p.ip.Unmap().appendTo4(b) - if z := p.ip.Zone(); z != "" { - b = append(b, '%') - b = append(b, z...) - } + b = p.ip.appendTo4In6(b) } else { - b = append(b, '[') b = p.ip.appendTo6(b) } b = append(b, ']') @@ -1217,7 +1233,7 @@ func (p *AddrPort) UnmarshalText(text []byte) error { // containing the port in little-endian. func (p AddrPort) MarshalBinary() ([]byte, error) { b := p.Addr().marshalBinaryWithTrailingBytes(2) - lePutUint16(b[len(b)-2:], p.Port()) + byteorder.LePutUint16(b[len(b)-2:], p.Port()) return b, nil } @@ -1232,7 +1248,7 @@ func (p *AddrPort) UnmarshalBinary(b []byte) error { if err != nil { return err } - *p = AddrPortFrom(addr, leUint16(b[len(b)-2:])) + *p = AddrPortFrom(addr, byteorder.LeUint16(b[len(b)-2:])) return nil } @@ -1303,6 +1319,15 @@ func (p Prefix) compare(p2 Prefix) int { return p.Addr().Compare(p2.Addr()) } +type parsePrefixError struct { + in string // the string given to ParsePrefix + msg string // an explanation of the parse failure +} + +func (err parsePrefixError) Error() string { + return "netip.ParsePrefix(" + strconv.Quote(err.in) + "): " + err.msg +} + // ParsePrefix parses s as an IP address prefix. // The string can be in the form "192.168.1.0/24" or "2001:db8::/32", // the CIDR notation defined in RFC 4632 and RFC 4291. @@ -1313,34 +1338,34 @@ func (p Prefix) compare(p2 Prefix) int { func ParsePrefix(s string) (Prefix, error) { i := bytealg.LastIndexByteString(s, '/') if i < 0 { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): no '/'") + return Prefix{}, parsePrefixError{in: s, msg: "no '/'"} } ip, err := ParseAddr(s[:i]) if err != nil { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): " + err.Error()) + return Prefix{}, parsePrefixError{in: s, msg: err.Error()} } // IPv6 zones are not allowed: https://go.dev/issue/51899 if ip.Is6() && ip.z != z6noz { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): IPv6 zones cannot be present in a prefix") + return Prefix{}, parsePrefixError{in: s, msg: "IPv6 zones cannot be present in a prefix"} } bitsStr := s[i+1:] // strconv.Atoi accepts a leading sign and leading zeroes, but we don't want that. if len(bitsStr) > 1 && (bitsStr[0] < '1' || bitsStr[0] > '9') { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): bad bits after slash: " + strconv.Quote(bitsStr)) + return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)} } bits, err := strconv.Atoi(bitsStr) if err != nil { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): bad bits after slash: " + strconv.Quote(bitsStr)) + return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)} } maxBits := 32 if ip.Is6() { maxBits = 128 } if bits < 0 || bits > maxBits { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): prefix length out of range") + return Prefix{}, parsePrefixError{in: s, msg: "prefix length out of range"} } return PrefixFrom(ip, bits), nil } diff --git a/contrib/go/_std_1.22/src/net/netip/uint128.go b/contrib/go/_std_1.23/src/net/netip/uint128.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netip/uint128.go rename to contrib/go/_std_1.23/src/net/netip/uint128.go diff --git a/contrib/go/_std_1.23/src/net/netip/ya.make b/contrib/go/_std_1.23/src/net/netip/ya.make new file mode 100644 index 000000000000..7042672f0897 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/netip/ya.make @@ -0,0 +1,8 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + netip.go + uint128.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/net/nss.go b/contrib/go/_std_1.23/src/net/nss.go similarity index 100% rename from contrib/go/_std_1.22/src/net/nss.go rename to contrib/go/_std_1.23/src/net/nss.go diff --git a/contrib/go/_std_1.23/src/net/parse.go b/contrib/go/_std_1.23/src/net/parse.go new file mode 100644 index 000000000000..106a303dfada --- /dev/null +++ b/contrib/go/_std_1.23/src/net/parse.go @@ -0,0 +1,272 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Simple file i/o and string manipulation, to avoid +// depending on strconv and bufio and strings. + +package net + +import ( + "internal/bytealg" + "io" + "os" + "time" +) + +type file struct { + file *os.File + data []byte + atEOF bool +} + +func (f *file) close() { f.file.Close() } + +func (f *file) getLineFromData() (s string, ok bool) { + data := f.data + i := 0 + for i = 0; i < len(data); i++ { + if data[i] == '\n' { + s = string(data[0:i]) + ok = true + // move data + i++ + n := len(data) - i + copy(data[0:], data[i:]) + f.data = data[0:n] + return + } + } + if f.atEOF && len(f.data) > 0 { + // EOF, return all we have + s = string(data) + f.data = f.data[0:0] + ok = true + } + return +} + +func (f *file) readLine() (s string, ok bool) { + if s, ok = f.getLineFromData(); ok { + return + } + if len(f.data) < cap(f.data) { + ln := len(f.data) + n, err := io.ReadFull(f.file, f.data[ln:cap(f.data)]) + if n >= 0 { + f.data = f.data[0 : ln+n] + } + if err == io.EOF || err == io.ErrUnexpectedEOF { + f.atEOF = true + } + } + s, ok = f.getLineFromData() + return +} + +func (f *file) stat() (mtime time.Time, size int64, err error) { + st, err := f.file.Stat() + if err != nil { + return time.Time{}, 0, err + } + return st.ModTime(), st.Size(), nil +} + +func open(name string) (*file, error) { + fd, err := os.Open(name) + if err != nil { + return nil, err + } + return &file{fd, make([]byte, 0, 64*1024), false}, nil +} + +func stat(name string) (mtime time.Time, size int64, err error) { + st, err := os.Stat(name) + if err != nil { + return time.Time{}, 0, err + } + return st.ModTime(), st.Size(), nil +} + +// Count occurrences in s of any bytes in t. +func countAnyByte(s string, t string) int { + n := 0 + for i := 0; i < len(s); i++ { + if bytealg.IndexByteString(t, s[i]) >= 0 { + n++ + } + } + return n +} + +// Split s at any bytes in t. +func splitAtBytes(s string, t string) []string { + a := make([]string, 1+countAnyByte(s, t)) + n := 0 + last := 0 + for i := 0; i < len(s); i++ { + if bytealg.IndexByteString(t, s[i]) >= 0 { + if last < i { + a[n] = s[last:i] + n++ + } + last = i + 1 + } + } + if last < len(s) { + a[n] = s[last:] + n++ + } + return a[0:n] +} + +func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") } + +// Bigger than we need, not too big to worry about overflow +const big = 0xFFFFFF + +// Decimal to integer. +// Returns number, characters consumed, success. +func dtoi(s string) (n int, i int, ok bool) { + n = 0 + for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { + n = n*10 + int(s[i]-'0') + if n >= big { + return big, i, false + } + } + if i == 0 { + return 0, 0, false + } + return n, i, true +} + +// Hexadecimal to integer. +// Returns number, characters consumed, success. +func xtoi(s string) (n int, i int, ok bool) { + n = 0 + for i = 0; i < len(s); i++ { + if '0' <= s[i] && s[i] <= '9' { + n *= 16 + n += int(s[i] - '0') + } else if 'a' <= s[i] && s[i] <= 'f' { + n *= 16 + n += int(s[i]-'a') + 10 + } else if 'A' <= s[i] && s[i] <= 'F' { + n *= 16 + n += int(s[i]-'A') + 10 + } else { + break + } + if n >= big { + return 0, i, false + } + } + if i == 0 { + return 0, i, false + } + return n, i, true +} + +// xtoi2 converts the next two hex digits of s into a byte. +// If s is longer than 2 bytes then the third byte must be e. +// If the first two bytes of s are not hex digits or the third byte +// does not match e, false is returned. +func xtoi2(s string, e byte) (byte, bool) { + if len(s) > 2 && s[2] != e { + return 0, false + } + n, ei, ok := xtoi(s[:2]) + return byte(n), ok && ei == 2 +} + +// hasUpperCase tells whether the given string contains at least one upper-case. +func hasUpperCase(s string) bool { + for i := range s { + if 'A' <= s[i] && s[i] <= 'Z' { + return true + } + } + return false +} + +// lowerASCIIBytes makes x ASCII lowercase in-place. +func lowerASCIIBytes(x []byte) { + for i, b := range x { + if 'A' <= b && b <= 'Z' { + x[i] += 'a' - 'A' + } + } +} + +// lowerASCII returns the ASCII lowercase version of b. +func lowerASCII(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// trimSpace returns x without any leading or trailing ASCII whitespace. +func trimSpace(x string) string { + for len(x) > 0 && isSpace(x[0]) { + x = x[1:] + } + for len(x) > 0 && isSpace(x[len(x)-1]) { + x = x[:len(x)-1] + } + return x +} + +// isSpace reports whether b is an ASCII space character. +func isSpace(b byte) bool { + return b == ' ' || b == '\t' || b == '\n' || b == '\r' +} + +// removeComment returns line, removing any '#' byte and any following +// bytes. +func removeComment(line string) string { + if i := bytealg.IndexByteString(line, '#'); i != -1 { + return line[:i] + } + return line +} + +// foreachField runs fn on each non-empty run of non-space bytes in x. +// It returns the first non-nil error returned by fn. +func foreachField(x string, fn func(field string) error) error { + x = trimSpace(x) + for len(x) > 0 { + sp := bytealg.IndexByteString(x, ' ') + if sp == -1 { + return fn(x) + } + if field := trimSpace(x[:sp]); len(field) > 0 { + if err := fn(field); err != nil { + return err + } + } + x = trimSpace(x[sp+1:]) + } + return nil +} + +// stringsHasSuffixFold reports whether s ends in suffix, +// ASCII-case-insensitively. +func stringsHasSuffixFold(s, suffix string) bool { + return len(s) >= len(suffix) && stringsEqualFold(s[len(s)-len(suffix):], suffix) +} + +// stringsEqualFold is strings.EqualFold, ASCII only. It reports whether s and t +// are equal, ASCII-case-insensitively. +func stringsEqualFold(s, t string) bool { + if len(s) != len(t) { + return false + } + for i := 0; i < len(s); i++ { + if lowerASCII(s[i]) != lowerASCII(t[i]) { + return false + } + } + return true +} diff --git a/contrib/go/_std_1.22/src/net/pipe.go b/contrib/go/_std_1.23/src/net/pipe.go similarity index 100% rename from contrib/go/_std_1.22/src/net/pipe.go rename to contrib/go/_std_1.23/src/net/pipe.go diff --git a/contrib/go/_std_1.22/src/net/port.go b/contrib/go/_std_1.23/src/net/port.go similarity index 100% rename from contrib/go/_std_1.22/src/net/port.go rename to contrib/go/_std_1.23/src/net/port.go diff --git a/contrib/go/_std_1.22/src/net/port_unix.go b/contrib/go/_std_1.23/src/net/port_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/port_unix.go rename to contrib/go/_std_1.23/src/net/port_unix.go diff --git a/contrib/go/_std_1.22/src/net/rawconn.go b/contrib/go/_std_1.23/src/net/rawconn.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rawconn.go rename to contrib/go/_std_1.23/src/net/rawconn.go diff --git a/contrib/go/_std_1.22/src/net/rlimit_js.go b/contrib/go/_std_1.23/src/net/rlimit_js.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rlimit_js.go rename to contrib/go/_std_1.23/src/net/rlimit_js.go diff --git a/contrib/go/_std_1.22/src/net/rlimit_unix.go b/contrib/go/_std_1.23/src/net/rlimit_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rlimit_unix.go rename to contrib/go/_std_1.23/src/net/rlimit_unix.go diff --git a/contrib/go/_std_1.22/src/net/rpc/client.go b/contrib/go/_std_1.23/src/net/rpc/client.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/client.go rename to contrib/go/_std_1.23/src/net/rpc/client.go diff --git a/contrib/go/_std_1.23/src/net/rpc/debug.go b/contrib/go/_std_1.23/src/net/rpc/debug.go new file mode 100644 index 000000000000..81d4ea368563 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/rpc/debug.go @@ -0,0 +1,95 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rpc + +/* + Some HTML presented at http://machine:port/debug/rpc + Lists services, their methods, and some statistics, still rudimentary. +*/ + +import ( + "fmt" + "html/template" + "net/http" + "slices" + "strings" +) + +const debugText = ` + + Services + {{range .}} +
+ Service {{.Name}} +
+ + + {{range .Method}} + + + + + {{end}} +
MethodCalls
{{.Name}}({{.Type.ArgType}}, {{.Type.ReplyType}}) error{{.Type.NumCalls}}
+ {{end}} + + ` + +var debug = template.Must(template.New("RPC debug").Parse(debugText)) + +// If set, print log statements for internal and I/O errors. +var debugLog = false + +type debugMethod struct { + Type *methodType + Name string +} + +type methodArray []debugMethod + +type debugService struct { + Service *service + Name string + Method []debugMethod +} + +type serviceArray []debugService + +func (s serviceArray) Len() int { return len(s) } +func (s serviceArray) Less(i, j int) bool { return s[i].Name < s[j].Name } +func (s serviceArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func (m methodArray) Len() int { return len(m) } +func (m methodArray) Less(i, j int) bool { return m[i].Name < m[j].Name } +func (m methodArray) Swap(i, j int) { m[i], m[j] = m[j], m[i] } + +type debugHTTP struct { + *Server +} + +// Runs at /debug/rpc +func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // Build a sorted version of the data. + var services serviceArray + server.serviceMap.Range(func(snamei, svci any) bool { + svc := svci.(*service) + ds := debugService{svc, snamei.(string), make([]debugMethod, 0, len(svc.method))} + for mname, method := range svc.method { + ds.Method = append(ds.Method, debugMethod{method, mname}) + } + slices.SortFunc(ds.Method, func(a, b debugMethod) int { + return strings.Compare(a.Name, b.Name) + }) + services = append(services, ds) + return true + }) + slices.SortFunc(services, func(a, b debugService) int { + return strings.Compare(a.Name, b.Name) + }) + err := debug.Execute(w, services) + if err != nil { + fmt.Fprintln(w, "rpc: error executing template:", err.Error()) + } +} diff --git a/contrib/go/_std_1.22/src/net/rpc/jsonrpc/client.go b/contrib/go/_std_1.23/src/net/rpc/jsonrpc/client.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/jsonrpc/client.go rename to contrib/go/_std_1.23/src/net/rpc/jsonrpc/client.go diff --git a/contrib/go/_std_1.22/src/net/rpc/jsonrpc/server.go b/contrib/go/_std_1.23/src/net/rpc/jsonrpc/server.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/jsonrpc/server.go rename to contrib/go/_std_1.23/src/net/rpc/jsonrpc/server.go diff --git a/contrib/go/_std_1.22/src/net/rpc/jsonrpc/ya.make b/contrib/go/_std_1.23/src/net/rpc/jsonrpc/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/jsonrpc/ya.make rename to contrib/go/_std_1.23/src/net/rpc/jsonrpc/ya.make diff --git a/contrib/go/_std_1.22/src/net/rpc/server.go b/contrib/go/_std_1.23/src/net/rpc/server.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/server.go rename to contrib/go/_std_1.23/src/net/rpc/server.go diff --git a/contrib/go/_std_1.22/src/net/rpc/ya.make b/contrib/go/_std_1.23/src/net/rpc/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/ya.make rename to contrib/go/_std_1.23/src/net/rpc/ya.make diff --git a/contrib/go/_std_1.23/src/net/sendfile_linux.go b/contrib/go/_std_1.23/src/net/sendfile_linux.go new file mode 100644 index 000000000000..f8a7bec8d381 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/sendfile_linux.go @@ -0,0 +1,55 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "internal/poll" + "io" + "os" +) + +const supportsSendfile = true + +// sendFile copies the contents of r to c using the sendfile +// system call to minimize copies. +// +// if handled == true, sendFile returns the number (potentially zero) of bytes +// copied and any non-EOF error. +// +// if handled == false, sendFile performed no work. +func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { + var remain int64 = 1<<63 - 1 // by default, copy until EOF + + lr, ok := r.(*io.LimitedReader) + if ok { + remain, r = lr.N, lr.R + if remain <= 0 { + return 0, nil, true + } + } + f, ok := r.(*os.File) + if !ok { + return 0, nil, false + } + + sc, err := f.SyscallConn() + if err != nil { + return 0, nil, false + } + + var werr error + err = sc.Read(func(fd uintptr) bool { + written, werr, handled = poll.SendFile(&c.pfd, int(fd), remain) + return true + }) + if err == nil { + err = werr + } + + if lr != nil { + lr.N = remain - written + } + return written, wrapSyscallError("sendfile", err), handled +} diff --git a/contrib/go/_std_1.23/src/net/sendfile_stub.go b/contrib/go/_std_1.23/src/net/sendfile_stub.go new file mode 100644 index 000000000000..7f31cc63e1ed --- /dev/null +++ b/contrib/go/_std_1.23/src/net/sendfile_stub.go @@ -0,0 +1,15 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !(linux || (darwin && !ios) || dragonfly || freebsd || solaris || windows) + +package net + +import "io" + +const supportsSendfile = false + +func sendFile(c *netFD, r io.Reader) (n int64, err error, handled bool) { + return 0, nil, false +} diff --git a/contrib/go/_std_1.22/src/net/sendfile_unix_alt.go b/contrib/go/_std_1.23/src/net/sendfile_unix_alt.go similarity index 84% rename from contrib/go/_std_1.22/src/net/sendfile_unix_alt.go rename to contrib/go/_std_1.23/src/net/sendfile_unix_alt.go index 5cb65ee7670c..4056856f3061 100644 --- a/contrib/go/_std_1.22/src/net/sendfile_unix_alt.go +++ b/contrib/go/_std_1.23/src/net/sendfile_unix_alt.go @@ -9,9 +9,12 @@ package net import ( "internal/poll" "io" - "os" + "io/fs" + "syscall" ) +const supportsSendfile = true + // sendFile copies the contents of r to c using the sendfile // system call to minimize copies. // @@ -34,7 +37,13 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { return 0, nil, true } } - f, ok := r.(*os.File) + // r might be an *os.File or an os.fileWithoutWriteTo. + // Type assert to an interface rather than *os.File directly to handle the latter case. + f, ok := r.(interface { + fs.File + io.Seeker + syscall.Conn + }) if !ok { return 0, nil, false } @@ -44,6 +53,9 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { if err != nil { return 0, err, false } + if fi.Mode()&(fs.ModeSymlink|fs.ModeDevice|fs.ModeCharDevice|fs.ModeIrregular) != 0 { + return 0, nil, false + } remain = fi.Size() } diff --git a/contrib/go/_std_1.23/src/net/sendfile_windows.go b/contrib/go/_std_1.23/src/net/sendfile_windows.go new file mode 100644 index 000000000000..0377a485daa0 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/sendfile_windows.go @@ -0,0 +1,49 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "internal/poll" + "io" + "os" + "syscall" +) + +const supportsSendfile = true + +// sendFile copies the contents of r to c using the TransmitFile +// system call to minimize copies. +// +// if handled == true, sendFile returns the number of bytes copied and any +// non-EOF error. +// +// if handled == false, sendFile performed no work. +func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) { + var n int64 = 0 // by default, copy until EOF. + + lr, ok := r.(*io.LimitedReader) + if ok { + n, r = lr.N, lr.R + if n <= 0 { + return 0, nil, true + } + } + + f, ok := r.(*os.File) + if !ok { + return 0, nil, false + } + + written, err = poll.SendFile(&fd.pfd, syscall.Handle(f.Fd()), n) + if err != nil { + err = wrapSyscallError("transmitfile", err) + } + + // If any byte was copied, regardless of any error + // encountered mid-way, handled must be set to true. + handled = written > 0 + + return +} diff --git a/contrib/go/_std_1.22/src/net/smtp/auth.go b/contrib/go/_std_1.23/src/net/smtp/auth.go similarity index 100% rename from contrib/go/_std_1.22/src/net/smtp/auth.go rename to contrib/go/_std_1.23/src/net/smtp/auth.go diff --git a/contrib/go/_std_1.22/src/net/smtp/smtp.go b/contrib/go/_std_1.23/src/net/smtp/smtp.go similarity index 98% rename from contrib/go/_std_1.22/src/net/smtp/smtp.go rename to contrib/go/_std_1.23/src/net/smtp/smtp.go index b7877936da57..d750a2854cbf 100644 --- a/contrib/go/_std_1.22/src/net/smtp/smtp.go +++ b/contrib/go/_std_1.23/src/net/smtp/smtp.go @@ -206,7 +206,7 @@ func (c *Client) Auth(a Auth) error { } resp64 := make([]byte, encoding.EncodedLen(len(resp))) encoding.Encode(resp64, resp) - code, msg64, err := c.cmd(0, strings.TrimSpace(fmt.Sprintf("AUTH %s %s", mech, resp64))) + code, msg64, err := c.cmd(0, "%s", strings.TrimSpace(fmt.Sprintf("AUTH %s %s", mech, resp64))) for err == nil { var msg []byte switch code { @@ -232,7 +232,7 @@ func (c *Client) Auth(a Auth) error { } resp64 = make([]byte, encoding.EncodedLen(len(resp))) encoding.Encode(resp64, resp) - code, msg64, err = c.cmd(0, string(resp64)) + code, msg64, err = c.cmd(0, "%s", resp64) } return err } diff --git a/contrib/go/_std_1.22/src/net/smtp/ya.make b/contrib/go/_std_1.23/src/net/smtp/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/smtp/ya.make rename to contrib/go/_std_1.23/src/net/smtp/ya.make diff --git a/contrib/go/_std_1.22/src/net/sock_bsd.go b/contrib/go/_std_1.23/src/net/sock_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_bsd.go rename to contrib/go/_std_1.23/src/net/sock_bsd.go diff --git a/contrib/go/_std_1.23/src/net/sock_cloexec.go b/contrib/go/_std_1.23/src/net/sock_cloexec.go new file mode 100644 index 000000000000..043522f0b6e1 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/sock_cloexec.go @@ -0,0 +1,25 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements sysSocket for platforms that provide a fast path for +// setting SetNonblock and CloseOnExec. + +//go:build dragonfly || freebsd || linux || netbsd || openbsd + +package net + +import ( + "os" + "syscall" +) + +// Wrapper around the socket system call that marks the returned file +// descriptor as nonblocking and close-on-exec. +func sysSocket(family, sotype, proto int) (int, error) { + s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto) + if err != nil { + return -1, os.NewSyscallError("socket", err) + } + return s, nil +} diff --git a/contrib/go/_std_1.23/src/net/sock_cloexec_solaris.go b/contrib/go/_std_1.23/src/net/sock_cloexec_solaris.go new file mode 100644 index 000000000000..04c3cdf25437 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/sock_cloexec_solaris.go @@ -0,0 +1,47 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements sysSocket for platforms that provide a fast path for +// setting SetNonblock and CloseOnExec, but don't necessarily support it. +// Support for SOCK_* flags as part of the type parameter was added to Oracle +// Solaris in the 11.4 release. Thus, on releases prior to 11.4, we fall back +// to the combination of socket(3c) and fcntl(2). + +package net + +import ( + "internal/poll" + "internal/syscall/unix" + "os" + "syscall" +) + +// Wrapper around the socket system call that marks the returned file +// descriptor as nonblocking and close-on-exec. +func sysSocket(family, sotype, proto int) (int, error) { + // Perform a cheap test and try the fast path first. + if unix.SupportSockNonblockCloexec() { + s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto) + if err != nil { + return -1, os.NewSyscallError("socket", err) + } + return s, nil + } + + // See ../syscall/exec_unix.go for description of ForkLock. + syscall.ForkLock.RLock() + s, err := socketFunc(family, sotype, proto) + if err == nil { + syscall.CloseOnExec(s) + } + syscall.ForkLock.RUnlock() + if err != nil { + return -1, os.NewSyscallError("socket", err) + } + if err = syscall.SetNonblock(s, true); err != nil { + poll.CloseFunc(s) + return -1, os.NewSyscallError("setnonblock", err) + } + return s, nil +} diff --git a/contrib/go/_std_1.22/src/net/sock_linux.go b/contrib/go/_std_1.23/src/net/sock_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_linux.go rename to contrib/go/_std_1.23/src/net/sock_linux.go diff --git a/contrib/go/_std_1.22/src/net/sock_plan9.go b/contrib/go/_std_1.23/src/net/sock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_plan9.go rename to contrib/go/_std_1.23/src/net/sock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/sock_posix.go b/contrib/go/_std_1.23/src/net/sock_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_posix.go rename to contrib/go/_std_1.23/src/net/sock_posix.go diff --git a/contrib/go/_std_1.22/src/net/sock_stub.go b/contrib/go/_std_1.23/src/net/sock_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_stub.go rename to contrib/go/_std_1.23/src/net/sock_stub.go diff --git a/contrib/go/_std_1.22/src/net/sock_windows.go b/contrib/go/_std_1.23/src/net/sock_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_windows.go rename to contrib/go/_std_1.23/src/net/sock_windows.go diff --git a/contrib/go/_std_1.22/src/net/sockaddr_posix.go b/contrib/go/_std_1.23/src/net/sockaddr_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockaddr_posix.go rename to contrib/go/_std_1.23/src/net/sockaddr_posix.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_aix.go b/contrib/go/_std_1.23/src/net/sockopt_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_aix.go rename to contrib/go/_std_1.23/src/net/sockopt_aix.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_bsd.go b/contrib/go/_std_1.23/src/net/sockopt_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_bsd.go rename to contrib/go/_std_1.23/src/net/sockopt_bsd.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_fake.go b/contrib/go/_std_1.23/src/net/sockopt_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_fake.go rename to contrib/go/_std_1.23/src/net/sockopt_fake.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_linux.go b/contrib/go/_std_1.23/src/net/sockopt_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_linux.go rename to contrib/go/_std_1.23/src/net/sockopt_linux.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_plan9.go b/contrib/go/_std_1.23/src/net/sockopt_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_plan9.go rename to contrib/go/_std_1.23/src/net/sockopt_plan9.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_posix.go b/contrib/go/_std_1.23/src/net/sockopt_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_posix.go rename to contrib/go/_std_1.23/src/net/sockopt_posix.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_solaris.go b/contrib/go/_std_1.23/src/net/sockopt_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_solaris.go rename to contrib/go/_std_1.23/src/net/sockopt_solaris.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_windows.go b/contrib/go/_std_1.23/src/net/sockopt_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_windows.go rename to contrib/go/_std_1.23/src/net/sockopt_windows.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_bsdvar.go b/contrib/go/_std_1.23/src/net/sockoptip_bsdvar.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_bsdvar.go rename to contrib/go/_std_1.23/src/net/sockoptip_bsdvar.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_linux.go b/contrib/go/_std_1.23/src/net/sockoptip_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_linux.go rename to contrib/go/_std_1.23/src/net/sockoptip_linux.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_posix.go b/contrib/go/_std_1.23/src/net/sockoptip_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_posix.go rename to contrib/go/_std_1.23/src/net/sockoptip_posix.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_stub.go b/contrib/go/_std_1.23/src/net/sockoptip_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_stub.go rename to contrib/go/_std_1.23/src/net/sockoptip_stub.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_windows.go b/contrib/go/_std_1.23/src/net/sockoptip_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_windows.go rename to contrib/go/_std_1.23/src/net/sockoptip_windows.go diff --git a/contrib/go/_std_1.23/src/net/splice_linux.go b/contrib/go/_std_1.23/src/net/splice_linux.go new file mode 100644 index 000000000000..b62e8a722db8 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/splice_linux.go @@ -0,0 +1,64 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "internal/poll" + "io" +) + +var pollSplice = poll.Splice + +// spliceFrom transfers data from r to c using the splice system call to minimize +// copies from and to userspace. c must be a TCP connection. +// Currently, spliceFrom is only enabled if r is a TCP or a stream-oriented Unix connection. +// +// If spliceFrom returns handled == false, it has performed no work. +func spliceFrom(c *netFD, r io.Reader) (written int64, err error, handled bool) { + var remain int64 = 1<<63 - 1 // by default, copy until EOF + lr, ok := r.(*io.LimitedReader) + if ok { + remain, r = lr.N, lr.R + if remain <= 0 { + return 0, nil, true + } + } + + var s *netFD + switch v := r.(type) { + case *TCPConn: + s = v.fd + case tcpConnWithoutWriteTo: + s = v.fd + case *UnixConn: + if v.fd.net != "unix" { + return 0, nil, false + } + s = v.fd + default: + return 0, nil, false + } + + written, handled, err = pollSplice(&c.pfd, &s.pfd, remain) + if lr != nil { + lr.N -= written + } + return written, wrapSyscallError("splice", err), handled +} + +// spliceTo transfers data from c to w using the splice system call to minimize +// copies from and to userspace. c must be a TCP connection. +// Currently, spliceTo is only enabled if w is a stream-oriented Unix connection. +// +// If spliceTo returns handled == false, it has performed no work. +func spliceTo(w io.Writer, c *netFD) (written int64, err error, handled bool) { + uc, ok := w.(*UnixConn) + if !ok || uc.fd.net != "unix" { + return + } + + written, handled, err = pollSplice(&uc.fd.pfd, &c.pfd, 1<<63-1) + return written, wrapSyscallError("splice", err), handled +} diff --git a/contrib/go/_std_1.22/src/net/splice_stub.go b/contrib/go/_std_1.23/src/net/splice_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/splice_stub.go rename to contrib/go/_std_1.23/src/net/splice_stub.go diff --git a/contrib/go/_std_1.22/src/net/sys_cloexec.go b/contrib/go/_std_1.23/src/net/sys_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sys_cloexec.go rename to contrib/go/_std_1.23/src/net/sys_cloexec.go diff --git a/contrib/go/_std_1.22/src/net/tcpsock.go b/contrib/go/_std_1.23/src/net/tcpsock.go similarity index 83% rename from contrib/go/_std_1.22/src/net/tcpsock.go rename to contrib/go/_std_1.23/src/net/tcpsock.go index 590516bff130..f5df502f0fd0 100644 --- a/contrib/go/_std_1.22/src/net/tcpsock.go +++ b/contrib/go/_std_1.23/src/net/tcpsock.go @@ -113,6 +113,41 @@ type TCPConn struct { conn } +// KeepAliveConfig contains TCP keep-alive options. +// +// If the Idle, Interval, or Count fields are zero, a default value is chosen. +// If a field is negative, the corresponding socket-level option will be left unchanged. +// +// Note that prior to Windows 10 version 1709, neither setting Idle and Interval +// separately nor changing Count (which is usually 10) is supported. +// Therefore, it's recommended to set both Idle and Interval to non-negative values +// in conjunction with a -1 for Count on those old Windows if you intend to customize +// the TCP keep-alive settings. +// By contrast, if only one of Idle and Interval is set to a non-negative value, +// the other will be set to the system default value, and ultimately, +// set both Idle and Interval to negative values if you want to leave them unchanged. +// +// Note that Solaris and its derivatives do not support setting Interval to a non-negative value +// and Count to a negative value, or vice-versa. +type KeepAliveConfig struct { + // If Enable is true, keep-alive probes are enabled. + Enable bool + + // Idle is the time that the connection must be idle before + // the first keep-alive probe is sent. + // If zero, a default value of 15 seconds is used. + Idle time.Duration + + // Interval is the time between keep-alive probes. + // If zero, a default value of 15 seconds is used. + Interval time.Duration + + // Count is the maximum number of keep-alive probes that + // can go unanswered before dropping a connection. + // If zero, a default value of 9 is used. + Count int +} + // SyscallConn returns a raw network connection. // This implements the [syscall.Conn] interface. func (c *TCPConn) SyscallConn() (syscall.RawConn, error) { @@ -206,12 +241,16 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error { return nil } -// SetKeepAlivePeriod sets period between keep-alives. +// SetKeepAlivePeriod sets the duration the connection needs to +// remain idle before TCP starts sending keepalive probes. +// +// Note that calling this method on Windows prior to Windows 10 version 1709 +// will reset the KeepAliveInterval to the default system value, which is normally 1 second. func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error { if !c.ok() { return syscall.EINVAL } - if err := setKeepAlivePeriod(c.fd, d); err != nil { + if err := setKeepAliveIdle(c.fd, d); err != nil { return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} } return nil @@ -247,19 +286,25 @@ func (c *TCPConn) MultipathTCP() (bool, error) { return isUsingMultipathTCP(c.fd), nil } -func newTCPConn(fd *netFD, keepAlive time.Duration, keepAliveHook func(time.Duration)) *TCPConn { +func newTCPConn(fd *netFD, keepAliveIdle time.Duration, keepAliveCfg KeepAliveConfig, preKeepAliveHook func(*netFD), keepAliveHook func(KeepAliveConfig)) *TCPConn { setNoDelay(fd, true) - if keepAlive == 0 { - keepAlive = defaultTCPKeepAlive + if !keepAliveCfg.Enable && keepAliveIdle >= 0 { + keepAliveCfg = KeepAliveConfig{ + Enable: true, + Idle: keepAliveIdle, + } } - if keepAlive > 0 { - setKeepAlive(fd, true) - setKeepAlivePeriod(fd, keepAlive) + c := &TCPConn{conn{fd}} + if keepAliveCfg.Enable { + if preKeepAliveHook != nil { + preKeepAliveHook(fd) + } + c.SetKeepAliveConfig(keepAliveCfg) if keepAliveHook != nil { - keepAliveHook(keepAlive) + keepAliveHook(keepAliveCfg) } } - return &TCPConn{conn{fd}} + return c } // DialTCP acts like [Dial] for TCP networks. diff --git a/contrib/go/_std_1.22/src/net/tcpsock_plan9.go b/contrib/go/_std_1.23/src/net/tcpsock_plan9.go similarity index 89% rename from contrib/go/_std_1.22/src/net/tcpsock_plan9.go rename to contrib/go/_std_1.23/src/net/tcpsock_plan9.go index 463dedcf44cd..430ed29ed42d 100644 --- a/contrib/go/_std_1.22/src/net/tcpsock_plan9.go +++ b/contrib/go/_std_1.23/src/net/tcpsock_plan9.go @@ -46,7 +46,7 @@ func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCP if err != nil { return nil, err } - return newTCPConn(fd, sd.Dialer.KeepAlive, testHookSetKeepAlive), nil + return newTCPConn(fd, sd.Dialer.KeepAlive, sd.Dialer.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil } func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil && ln.fd.ctl != nil } @@ -56,7 +56,7 @@ func (ln *TCPListener) accept() (*TCPConn, error) { if err != nil { return nil, err } - return newTCPConn(fd, ln.lc.KeepAlive, nil), nil + return newTCPConn(fd, ln.lc.KeepAlive, ln.lc.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil } func (ln *TCPListener) close() error { diff --git a/contrib/go/_std_1.22/src/net/tcpsock_posix.go b/contrib/go/_std_1.23/src/net/tcpsock_posix.go similarity index 93% rename from contrib/go/_std_1.22/src/net/tcpsock_posix.go rename to contrib/go/_std_1.23/src/net/tcpsock_posix.go index 01b5ec9ed056..7bca8dca555f 100644 --- a/contrib/go/_std_1.22/src/net/tcpsock_posix.go +++ b/contrib/go/_std_1.23/src/net/tcpsock_posix.go @@ -78,7 +78,7 @@ func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCP func (sd *sysDialer) doDialTCPProto(ctx context.Context, laddr, raddr *TCPAddr, proto int) (*TCPConn, error) { ctrlCtxFn := sd.Dialer.ControlContext if ctrlCtxFn == nil && sd.Dialer.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sd.Dialer.Control(network, address, c) } } @@ -118,7 +118,7 @@ func (sd *sysDialer) doDialTCPProto(ctx context.Context, laddr, raddr *TCPAddr, if err != nil { return nil, err } - return newTCPConn(fd, sd.Dialer.KeepAlive, testHookSetKeepAlive), nil + return newTCPConn(fd, sd.Dialer.KeepAlive, sd.Dialer.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil } func selfConnect(fd *netFD, err error) bool { @@ -160,7 +160,7 @@ func (ln *TCPListener) accept() (*TCPConn, error) { if err != nil { return nil, err } - return newTCPConn(fd, ln.lc.KeepAlive, nil), nil + return newTCPConn(fd, ln.lc.KeepAlive, ln.lc.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil } func (ln *TCPListener) close() error { @@ -180,9 +180,9 @@ func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListe } func (sl *sysListener) listenTCPProto(ctx context.Context, laddr *TCPAddr, proto int) (*TCPListener, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } diff --git a/contrib/go/_std_1.23/src/net/tcpsock_solaris.go b/contrib/go/_std_1.23/src/net/tcpsock_solaris.go new file mode 100644 index 000000000000..924e2f74002b --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsock_solaris.go @@ -0,0 +1,38 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !illumos + +package net + +import ( + "internal/syscall/unix" + "syscall" +) + +// SetKeepAliveConfig configures keep-alive messages sent by the operating system. +func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error { + if !c.ok() { + return syscall.EINVAL + } + + if err := setKeepAlive(c.fd, config.Enable); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if unix.SupportTCPKeepAliveIdleIntvlCNT() { + if err := setKeepAliveIdle(c.fd, config.Idle); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveInterval(c.fd, config.Interval); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveCount(c.fd, config.Count); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + } else if err := setKeepAliveIdleAndIntervalAndCount(c.fd, config.Idle, config.Interval, config.Count); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + + return nil +} diff --git a/contrib/go/_std_1.23/src/net/tcpsock_unix.go b/contrib/go/_std_1.23/src/net/tcpsock_unix.go new file mode 100644 index 000000000000..01879e38eeb6 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsock_unix.go @@ -0,0 +1,31 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (!windows && !solaris) || illumos + +package net + +import "syscall" + +// SetKeepAliveConfig configures keep-alive messages sent by the operating system. +func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error { + if !c.ok() { + return syscall.EINVAL + } + + if err := setKeepAlive(c.fd, config.Enable); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveIdle(c.fd, config.Idle); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveInterval(c.fd, config.Interval); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveCount(c.fd, config.Count); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + + return nil +} diff --git a/contrib/go/_std_1.23/src/net/tcpsock_windows.go b/contrib/go/_std_1.23/src/net/tcpsock_windows.go new file mode 100644 index 000000000000..70e8ea23e5b7 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsock_windows.go @@ -0,0 +1,36 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "internal/syscall/windows" + "syscall" +) + +// SetKeepAliveConfig configures keep-alive messages sent by the operating system. +func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error { + if !c.ok() { + return syscall.EINVAL + } + + if err := setKeepAlive(c.fd, config.Enable); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if windows.SupportTCPKeepAliveIdle() && windows.SupportTCPKeepAliveInterval() { + if err := setKeepAliveIdle(c.fd, config.Idle); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveInterval(c.fd, config.Interval); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + } else if err := setKeepAliveIdleAndInterval(c.fd, config.Idle, config.Interval); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveCount(c.fd, config.Count); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + + return nil +} diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_darwin.go b/contrib/go/_std_1.23/src/net/tcpsockopt_darwin.go new file mode 100644 index 000000000000..efe7f63323f0 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_darwin.go @@ -0,0 +1,57 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "runtime" + "syscall" + "time" +) + +// syscall.TCP_KEEPINTVL and syscall.TCP_KEEPCNT might be missing on some darwin architectures. +const ( + sysTCP_KEEPINTVL = 0x101 + sysTCP_KEEPCNT = 0x102 +) + +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if d == 0 { + d = defaultTCPKeepAliveIdle + } else if d < 0 { + return nil + } + + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + if d == 0 { + d = defaultTCPKeepAliveInterval + } else if d < 0 { + return nil + } + + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveCount(fd *netFD, n int) error { + if n == 0 { + n = defaultTCPKeepAliveCount + } else if n < 0 { + return nil + } + + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPCNT, n) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_openbsd.go b/contrib/go/_std_1.23/src/net/tcpsockopt_openbsd.go new file mode 100644 index 000000000000..d21b77c40688 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_openbsd.go @@ -0,0 +1,37 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "syscall" + "time" +) + +func setKeepAliveIdle(_ *netFD, d time.Duration) error { + if d < 0 { + return nil + } + // OpenBSD has no user-settable per-socket TCP keepalive + // options. + return syscall.ENOPROTOOPT +} + +func setKeepAliveInterval(_ *netFD, d time.Duration) error { + if d < 0 { + return nil + } + // OpenBSD has no user-settable per-socket TCP keepalive + // options. + return syscall.ENOPROTOOPT +} + +func setKeepAliveCount(_ *netFD, n int) error { + if n < 0 { + return nil + } + // OpenBSD has no user-settable per-socket TCP keepalive + // options. + return syscall.ENOPROTOOPT +} diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_plan9.go b/contrib/go/_std_1.23/src/net/tcpsockopt_plan9.go new file mode 100644 index 000000000000..017e87518aeb --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_plan9.go @@ -0,0 +1,42 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// TCP socket options for plan9 + +package net + +import ( + "internal/itoa" + "syscall" + "time" +) + +func setNoDelay(_ *netFD, _ bool) error { + return syscall.EPLAN9 +} + +// Set keep alive period. +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if d < 0 { + return nil + } + + cmd := "keepalive " + itoa.Itoa(int(d/time.Millisecond)) + _, e := fd.ctl.WriteAt([]byte(cmd), 0) + return e +} + +func setKeepAliveInterval(_ *netFD, d time.Duration) error { + if d < 0 { + return nil + } + return syscall.EPLAN9 +} + +func setKeepAliveCount(_ *netFD, n int) error { + if n < 0 { + return nil + } + return syscall.EPLAN9 +} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_posix.go b/contrib/go/_std_1.23/src/net/tcpsockopt_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/tcpsockopt_posix.go rename to contrib/go/_std_1.23/src/net/tcpsockopt_posix.go diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_solaris.go b/contrib/go/_std_1.23/src/net/tcpsockopt_solaris.go new file mode 100644 index 000000000000..df2ddbd11311 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_solaris.go @@ -0,0 +1,119 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !illumos + +package net + +import ( + "internal/syscall/unix" + "runtime" + "syscall" + "time" +) + +// Some macros of TCP Keep-Alive options on Solaris 11.4 may +// differ from those on OpenSolaris-based derivatives. +const ( + sysTCP_KEEPIDLE = 0x1D + sysTCP_KEEPINTVL = 0x1E + sysTCP_KEEPCNT = 0x1F +) + +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if !unix.SupportTCPKeepAliveIdleIntvlCNT() { + return setKeepAliveIdleAndIntervalAndCount(fd, d, -1, -1) + } + + if d == 0 { + d = defaultTCPKeepAliveIdle + } else if d < 0 { + return nil + } + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPIDLE, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + if !unix.SupportTCPKeepAliveIdleIntvlCNT() { + return syscall.EPROTOTYPE + } + + if d == 0 { + d = defaultTCPKeepAliveInterval + } else if d < 0 { + return nil + } + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveCount(fd *netFD, n int) error { + if !unix.SupportTCPKeepAliveIdleIntvlCNT() { + return syscall.EPROTOTYPE + } + + if n == 0 { + n = defaultTCPKeepAliveCount + } else if n < 0 { + return nil + } + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPCNT, n) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +// setKeepAliveIdleAndIntervalAndCount serves for Solaris prior to 11.4 by simulating +// the TCP_KEEPIDLE, TCP_KEEPINTVL, and TCP_KEEPCNT with `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`. +func setKeepAliveIdleAndIntervalAndCount(fd *netFD, idle, interval time.Duration, count int) error { + if idle == 0 { + idle = defaultTCPKeepAliveIdle + } + + // The kernel expects milliseconds so round to next highest + // millisecond. + if idle > 0 { + msecs := int(roundDurationUp(idle, time.Millisecond)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs) + runtime.KeepAlive(fd) + if err != nil { + return wrapSyscallError("setsockopt", err) + } + } + + if interval == 0 { + interval = defaultTCPKeepAliveInterval + } + if count == 0 { + count = defaultTCPKeepAliveCount + } + // TCP_KEEPINTVL and TCP_KEEPCNT are not available on Solaris + // prior to 11.4, so it's pointless to "leave it unchanged" + // with negative value for only one of them. On the other hand, + // setting both to negative values should pragmatically leave the + // TCP_KEEPALIVE_ABORT_THRESHOLD unchanged. + abortIdle := int(roundDurationUp(interval, time.Millisecond)) * count + if abortIdle < 0 { + return syscall.ENOPROTOOPT + } + if interval < 0 && count < 0 { + abortIdle = -1 + } + + if abortIdle > 0 { + // Note that the consequent probes will not be sent at equal intervals on Solaris, + // but will be sent using the exponential backoff algorithm. + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_ABORT_THRESHOLD, abortIdle) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) + } + + return nil +} diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_stub.go b/contrib/go/_std_1.23/src/net/tcpsockopt_stub.go new file mode 100644 index 000000000000..b789e0ae934e --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_stub.go @@ -0,0 +1,28 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build js || wasip1 + +package net + +import ( + "syscall" + "time" +) + +func setNoDelay(fd *netFD, noDelay bool) error { + return syscall.ENOPROTOOPT +} + +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + return syscall.ENOPROTOOPT +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + return syscall.ENOPROTOOPT +} + +func setKeepAliveCount(fd *netFD, n int) error { + return syscall.ENOPROTOOPT +} diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_unix.go b/contrib/go/_std_1.23/src/net/tcpsockopt_unix.go new file mode 100644 index 000000000000..1f7617897a4d --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_unix.go @@ -0,0 +1,53 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix || dragonfly || freebsd || illumos || linux || netbsd + +package net + +import ( + "runtime" + "syscall" + "time" +) + +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if d == 0 { + d = defaultTCPKeepAliveIdle + } else if d < 0 { + return nil + } + + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + if d == 0 { + d = defaultTCPKeepAliveInterval + } else if d < 0 { + return nil + } + + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveCount(fd *netFD, n int) error { + if n == 0 { + n = defaultTCPKeepAliveCount + } else if n < 0 { + return nil + } + + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, n) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_windows.go b/contrib/go/_std_1.23/src/net/tcpsockopt_windows.go new file mode 100644 index 000000000000..f635d47999a4 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_windows.go @@ -0,0 +1,118 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "internal/syscall/windows" + "os" + "runtime" + "syscall" + "time" + "unsafe" +) + +// Default values of KeepAliveTime and KeepAliveInterval on Windows, +// check out https://learn.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals#remarks for details. +const ( + defaultKeepAliveIdle = 2 * time.Hour + defaultKeepAliveInterval = time.Second +) + +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if !windows.SupportTCPKeepAliveIdle() { + return setKeepAliveIdleAndInterval(fd, d, -1) + } + + if d == 0 { + d = defaultTCPKeepAliveIdle + } else if d < 0 { + return nil + } + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, windows.TCP_KEEPIDLE, secs) + runtime.KeepAlive(fd) + return os.NewSyscallError("setsockopt", err) +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + if !windows.SupportTCPKeepAliveInterval() { + return setKeepAliveIdleAndInterval(fd, -1, d) + } + + if d == 0 { + d = defaultTCPKeepAliveInterval + } else if d < 0 { + return nil + } + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, windows.TCP_KEEPINTVL, secs) + runtime.KeepAlive(fd) + return os.NewSyscallError("setsockopt", err) +} + +func setKeepAliveCount(fd *netFD, n int) error { + if n == 0 { + n = defaultTCPKeepAliveCount + } else if n < 0 { + return nil + } + + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, windows.TCP_KEEPCNT, n) + runtime.KeepAlive(fd) + return os.NewSyscallError("setsockopt", err) +} + +// setKeepAliveIdleAndInterval serves for kernels prior to Windows 10, version 1709. +func setKeepAliveIdleAndInterval(fd *netFD, idle, interval time.Duration) error { + // WSAIoctl with SIO_KEEPALIVE_VALS control code requires all fields in + // `tcp_keepalive` struct to be provided. + // Otherwise, if any of the fields were not provided, just leaving them + // zero will knock off any existing values of keep-alive. + // Unfortunately, Windows doesn't support retrieving current keep-alive + // settings in any form programmatically, which disable us to first retrieve + // the current keep-alive settings, then set it without unwanted corruption. + switch { + case idle < 0 && interval >= 0: + // Given that we can't set KeepAliveInterval alone, and this code path + // is new, it doesn't exist before, so we just return an error. + return syscall.WSAENOPROTOOPT + case idle >= 0 && interval < 0: + // Although we can't set KeepAliveTime alone either, this existing code + // path had been backing up [SetKeepAlivePeriod] which used to be set both + // KeepAliveTime and KeepAliveInterval to 15 seconds. + // Now we will use the default of KeepAliveInterval on Windows if user doesn't + // provide one. + interval = defaultKeepAliveInterval + case idle < 0 && interval < 0: + // Nothing to do, just bail out. + return nil + case idle >= 0 && interval >= 0: + // Go ahead. + } + + if idle == 0 { + idle = defaultTCPKeepAliveIdle + } + if interval == 0 { + interval = defaultTCPKeepAliveInterval + } + + // The kernel expects milliseconds so round to next highest + // millisecond. + tcpKeepAliveIdle := uint32(roundDurationUp(idle, time.Millisecond)) + tcpKeepAliveInterval := uint32(roundDurationUp(interval, time.Millisecond)) + ka := syscall.TCPKeepalive{ + OnOff: 1, + Time: tcpKeepAliveIdle, + Interval: tcpKeepAliveInterval, + } + ret := uint32(0) + size := uint32(unsafe.Sizeof(ka)) + err := fd.pfd.WSAIoctl(syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0) + runtime.KeepAlive(fd) + return os.NewSyscallError("wsaioctl", err) +} diff --git a/contrib/go/_std_1.22/src/net/textproto/header.go b/contrib/go/_std_1.23/src/net/textproto/header.go similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/header.go rename to contrib/go/_std_1.23/src/net/textproto/header.go diff --git a/contrib/go/_std_1.22/src/net/textproto/pipeline.go b/contrib/go/_std_1.23/src/net/textproto/pipeline.go similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/pipeline.go rename to contrib/go/_std_1.23/src/net/textproto/pipeline.go diff --git a/contrib/go/_std_1.23/src/net/textproto/reader.go b/contrib/go/_std_1.23/src/net/textproto/reader.go new file mode 100644 index 000000000000..f98e05bd1d86 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/textproto/reader.go @@ -0,0 +1,841 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package textproto + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "math" + "strconv" + "strings" + "sync" + _ "unsafe" // for linkname +) + +// TODO: This should be a distinguishable error (ErrMessageTooLarge) +// to allow mime/multipart to detect it. +var errMessageTooLarge = errors.New("message too large") + +// A Reader implements convenience methods for reading requests +// or responses from a text protocol network connection. +type Reader struct { + R *bufio.Reader + dot *dotReader + buf []byte // a re-usable buffer for readContinuedLineSlice +} + +// NewReader returns a new [Reader] reading from r. +// +// To avoid denial of service attacks, the provided [bufio.Reader] +// should be reading from an [io.LimitReader] or similar Reader to bound +// the size of responses. +func NewReader(r *bufio.Reader) *Reader { + return &Reader{R: r} +} + +// ReadLine reads a single line from r, +// eliding the final \n or \r\n from the returned string. +func (r *Reader) ReadLine() (string, error) { + line, err := r.readLineSlice(-1) + return string(line), err +} + +// ReadLineBytes is like [Reader.ReadLine] but returns a []byte instead of a string. +func (r *Reader) ReadLineBytes() ([]byte, error) { + line, err := r.readLineSlice(-1) + if line != nil { + line = bytes.Clone(line) + } + return line, err +} + +// readLineSlice reads a single line from r, +// up to lim bytes long (or unlimited if lim is less than 0), +// eliding the final \r or \r\n from the returned string. +func (r *Reader) readLineSlice(lim int64) ([]byte, error) { + r.closeDot() + var line []byte + for { + l, more, err := r.R.ReadLine() + if err != nil { + return nil, err + } + if lim >= 0 && int64(len(line))+int64(len(l)) > lim { + return nil, errMessageTooLarge + } + // Avoid the copy if the first call produced a full line. + if line == nil && !more { + return l, nil + } + line = append(line, l...) + if !more { + break + } + } + return line, nil +} + +// ReadContinuedLine reads a possibly continued line from r, +// eliding the final trailing ASCII white space. +// Lines after the first are considered continuations if they +// begin with a space or tab character. In the returned data, +// continuation lines are separated from the previous line +// only by a single space: the newline and leading white space +// are removed. +// +// For example, consider this input: +// +// Line 1 +// continued... +// Line 2 +// +// The first call to ReadContinuedLine will return "Line 1 continued..." +// and the second will return "Line 2". +// +// Empty lines are never continued. +func (r *Reader) ReadContinuedLine() (string, error) { + line, err := r.readContinuedLineSlice(-1, noValidation) + return string(line), err +} + +// trim returns s with leading and trailing spaces and tabs removed. +// It does not assume Unicode or UTF-8. +func trim(s []byte) []byte { + i := 0 + for i < len(s) && (s[i] == ' ' || s[i] == '\t') { + i++ + } + n := len(s) + for n > i && (s[n-1] == ' ' || s[n-1] == '\t') { + n-- + } + return s[i:n] +} + +// ReadContinuedLineBytes is like [Reader.ReadContinuedLine] but +// returns a []byte instead of a string. +func (r *Reader) ReadContinuedLineBytes() ([]byte, error) { + line, err := r.readContinuedLineSlice(-1, noValidation) + if line != nil { + line = bytes.Clone(line) + } + return line, err +} + +// readContinuedLineSlice reads continued lines from the reader buffer, +// returning a byte slice with all lines. The validateFirstLine function +// is run on the first read line, and if it returns an error then this +// error is returned from readContinuedLineSlice. +// It reads up to lim bytes of data (or unlimited if lim is less than 0). +func (r *Reader) readContinuedLineSlice(lim int64, validateFirstLine func([]byte) error) ([]byte, error) { + if validateFirstLine == nil { + return nil, fmt.Errorf("missing validateFirstLine func") + } + + // Read the first line. + line, err := r.readLineSlice(lim) + if err != nil { + return nil, err + } + if len(line) == 0 { // blank line - no continuation + return line, nil + } + + if err := validateFirstLine(line); err != nil { + return nil, err + } + + // Optimistically assume that we have started to buffer the next line + // and it starts with an ASCII letter (the next header key), or a blank + // line, so we can avoid copying that buffered data around in memory + // and skipping over non-existent whitespace. + if r.R.Buffered() > 1 { + peek, _ := r.R.Peek(2) + if len(peek) > 0 && (isASCIILetter(peek[0]) || peek[0] == '\n') || + len(peek) == 2 && peek[0] == '\r' && peek[1] == '\n' { + return trim(line), nil + } + } + + // ReadByte or the next readLineSlice will flush the read buffer; + // copy the slice into buf. + r.buf = append(r.buf[:0], trim(line)...) + + if lim < 0 { + lim = math.MaxInt64 + } + lim -= int64(len(r.buf)) + + // Read continuation lines. + for r.skipSpace() > 0 { + r.buf = append(r.buf, ' ') + if int64(len(r.buf)) >= lim { + return nil, errMessageTooLarge + } + line, err := r.readLineSlice(lim - int64(len(r.buf))) + if err != nil { + break + } + r.buf = append(r.buf, trim(line)...) + } + return r.buf, nil +} + +// skipSpace skips R over all spaces and returns the number of bytes skipped. +func (r *Reader) skipSpace() int { + n := 0 + for { + c, err := r.R.ReadByte() + if err != nil { + // Bufio will keep err until next read. + break + } + if c != ' ' && c != '\t' { + r.R.UnreadByte() + break + } + n++ + } + return n +} + +func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err error) { + line, err := r.ReadLine() + if err != nil { + return + } + return parseCodeLine(line, expectCode) +} + +func parseCodeLine(line string, expectCode int) (code int, continued bool, message string, err error) { + if len(line) < 4 || line[3] != ' ' && line[3] != '-' { + err = ProtocolError("short response: " + line) + return + } + continued = line[3] == '-' + code, err = strconv.Atoi(line[0:3]) + if err != nil || code < 100 { + err = ProtocolError("invalid response code: " + line) + return + } + message = line[4:] + if 1 <= expectCode && expectCode < 10 && code/100 != expectCode || + 10 <= expectCode && expectCode < 100 && code/10 != expectCode || + 100 <= expectCode && expectCode < 1000 && code != expectCode { + err = &Error{code, message} + } + return +} + +// ReadCodeLine reads a response code line of the form +// +// code message +// +// where code is a three-digit status code and the message +// extends to the rest of the line. An example of such a line is: +// +// 220 plan9.bell-labs.com ESMTP +// +// If the prefix of the status does not match the digits in expectCode, +// ReadCodeLine returns with err set to &Error{code, message}. +// For example, if expectCode is 31, an error will be returned if +// the status is not in the range [310,319]. +// +// If the response is multi-line, ReadCodeLine returns an error. +// +// An expectCode <= 0 disables the check of the status code. +func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err error) { + code, continued, message, err := r.readCodeLine(expectCode) + if err == nil && continued { + err = ProtocolError("unexpected multi-line response: " + message) + } + return +} + +// ReadResponse reads a multi-line response of the form: +// +// code-message line 1 +// code-message line 2 +// ... +// code message line n +// +// where code is a three-digit status code. The first line starts with the +// code and a hyphen. The response is terminated by a line that starts +// with the same code followed by a space. Each line in message is +// separated by a newline (\n). +// +// See page 36 of RFC 959 (https://www.ietf.org/rfc/rfc959.txt) for +// details of another form of response accepted: +// +// code-message line 1 +// message line 2 +// ... +// code message line n +// +// If the prefix of the status does not match the digits in expectCode, +// ReadResponse returns with err set to &Error{code, message}. +// For example, if expectCode is 31, an error will be returned if +// the status is not in the range [310,319]. +// +// An expectCode <= 0 disables the check of the status code. +func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error) { + code, continued, message, err := r.readCodeLine(expectCode) + multi := continued + for continued { + line, err := r.ReadLine() + if err != nil { + return 0, "", err + } + + var code2 int + var moreMessage string + code2, continued, moreMessage, err = parseCodeLine(line, 0) + if err != nil || code2 != code { + message += "\n" + strings.TrimRight(line, "\r\n") + continued = true + continue + } + message += "\n" + moreMessage + } + if err != nil && multi && message != "" { + // replace one line error message with all lines (full message) + err = &Error{code, message} + } + return +} + +// DotReader returns a new [Reader] that satisfies Reads using the +// decoded text of a dot-encoded block read from r. +// The returned Reader is only valid until the next call +// to a method on r. +// +// Dot encoding is a common framing used for data blocks +// in text protocols such as SMTP. The data consists of a sequence +// of lines, each of which ends in "\r\n". The sequence itself +// ends at a line containing just a dot: ".\r\n". Lines beginning +// with a dot are escaped with an additional dot to avoid +// looking like the end of the sequence. +// +// The decoded form returned by the Reader's Read method +// rewrites the "\r\n" line endings into the simpler "\n", +// removes leading dot escapes if present, and stops with error [io.EOF] +// after consuming (and discarding) the end-of-sequence line. +func (r *Reader) DotReader() io.Reader { + r.closeDot() + r.dot = &dotReader{r: r} + return r.dot +} + +type dotReader struct { + r *Reader + state int +} + +// Read satisfies reads by decoding dot-encoded data read from d.r. +func (d *dotReader) Read(b []byte) (n int, err error) { + // Run data through a simple state machine to + // elide leading dots, rewrite trailing \r\n into \n, + // and detect ending .\r\n line. + const ( + stateBeginLine = iota // beginning of line; initial state; must be zero + stateDot // read . at beginning of line + stateDotCR // read .\r at beginning of line + stateCR // read \r (possibly at end of line) + stateData // reading data in middle of line + stateEOF // reached .\r\n end marker line + ) + br := d.r.R + for n < len(b) && d.state != stateEOF { + var c byte + c, err = br.ReadByte() + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + break + } + switch d.state { + case stateBeginLine: + if c == '.' { + d.state = stateDot + continue + } + if c == '\r' { + d.state = stateCR + continue + } + d.state = stateData + + case stateDot: + if c == '\r' { + d.state = stateDotCR + continue + } + if c == '\n' { + d.state = stateEOF + continue + } + d.state = stateData + + case stateDotCR: + if c == '\n' { + d.state = stateEOF + continue + } + // Not part of .\r\n. + // Consume leading dot and emit saved \r. + br.UnreadByte() + c = '\r' + d.state = stateData + + case stateCR: + if c == '\n' { + d.state = stateBeginLine + break + } + // Not part of \r\n. Emit saved \r + br.UnreadByte() + c = '\r' + d.state = stateData + + case stateData: + if c == '\r' { + d.state = stateCR + continue + } + if c == '\n' { + d.state = stateBeginLine + } + } + b[n] = c + n++ + } + if err == nil && d.state == stateEOF { + err = io.EOF + } + if err != nil && d.r.dot == d { + d.r.dot = nil + } + return +} + +// closeDot drains the current DotReader if any, +// making sure that it reads until the ending dot line. +func (r *Reader) closeDot() { + if r.dot == nil { + return + } + buf := make([]byte, 128) + for r.dot != nil { + // When Read reaches EOF or an error, + // it will set r.dot == nil. + r.dot.Read(buf) + } +} + +// ReadDotBytes reads a dot-encoding and returns the decoded data. +// +// See the documentation for the [Reader.DotReader] method for details about dot-encoding. +func (r *Reader) ReadDotBytes() ([]byte, error) { + return io.ReadAll(r.DotReader()) +} + +// ReadDotLines reads a dot-encoding and returns a slice +// containing the decoded lines, with the final \r\n or \n elided from each. +// +// See the documentation for the [Reader.DotReader] method for details about dot-encoding. +func (r *Reader) ReadDotLines() ([]string, error) { + // We could use ReadDotBytes and then Split it, + // but reading a line at a time avoids needing a + // large contiguous block of memory and is simpler. + var v []string + var err error + for { + var line string + line, err = r.ReadLine() + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + break + } + + // Dot by itself marks end; otherwise cut one dot. + if len(line) > 0 && line[0] == '.' { + if len(line) == 1 { + break + } + line = line[1:] + } + v = append(v, line) + } + return v, err +} + +var colon = []byte(":") + +// ReadMIMEHeader reads a MIME-style header from r. +// The header is a sequence of possibly continued Key: Value lines +// ending in a blank line. +// The returned map m maps [CanonicalMIMEHeaderKey](key) to a +// sequence of values in the same order encountered in the input. +// +// For example, consider this input: +// +// My-Key: Value 1 +// Long-Key: Even +// Longer Value +// My-Key: Value 2 +// +// Given that input, ReadMIMEHeader returns the map: +// +// map[string][]string{ +// "My-Key": {"Value 1", "Value 2"}, +// "Long-Key": {"Even Longer Value"}, +// } +func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { + return readMIMEHeader(r, math.MaxInt64, math.MaxInt64) +} + +// readMIMEHeader is accessed from mime/multipart. +//go:linkname readMIMEHeader + +// readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. +// It is called by the mime/multipart package. +func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) { + // Avoid lots of small slice allocations later by allocating one + // large one ahead of time which we'll cut up into smaller + // slices. If this isn't big enough later, we allocate small ones. + var strs []string + hint := r.upcomingHeaderKeys() + if hint > 0 { + if hint > 1000 { + hint = 1000 // set a cap to avoid overallocation + } + strs = make([]string, hint) + } + + m := make(MIMEHeader, hint) + + // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. + // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large + // MIMEHeaders average about 200 bytes per entry. + maxMemory -= 400 + const mapEntryOverhead = 200 + + // The first line cannot start with a leading space. + if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { + const errorLimit = 80 // arbitrary limit on how much of the line we'll quote + line, err := r.readLineSlice(errorLimit) + if err != nil { + return m, err + } + return m, ProtocolError("malformed MIME header initial line: " + string(line)) + } + + for { + kv, err := r.readContinuedLineSlice(maxMemory, mustHaveFieldNameColon) + if len(kv) == 0 { + return m, err + } + + // Key ends at first colon. + k, v, ok := bytes.Cut(kv, colon) + if !ok { + return m, ProtocolError("malformed MIME header line: " + string(kv)) + } + key, ok := canonicalMIMEHeaderKey(k) + if !ok { + return m, ProtocolError("malformed MIME header line: " + string(kv)) + } + for _, c := range v { + if !validHeaderValueByte(c) { + return m, ProtocolError("malformed MIME header line: " + string(kv)) + } + } + + maxHeaders-- + if maxHeaders < 0 { + return nil, errMessageTooLarge + } + + // Skip initial spaces in value. + value := string(bytes.TrimLeft(v, " \t")) + + vv := m[key] + if vv == nil { + maxMemory -= int64(len(key)) + maxMemory -= mapEntryOverhead + } + maxMemory -= int64(len(value)) + if maxMemory < 0 { + return m, errMessageTooLarge + } + if vv == nil && len(strs) > 0 { + // More than likely this will be a single-element key. + // Most headers aren't multi-valued. + // Set the capacity on strs[0] to 1, so any future append + // won't extend the slice into the other strings. + vv, strs = strs[:1:1], strs[1:] + vv[0] = value + m[key] = vv + } else { + m[key] = append(vv, value) + } + + if err != nil { + return m, err + } + } +} + +// noValidation is a no-op validation func for readContinuedLineSlice +// that permits any lines. +func noValidation(_ []byte) error { return nil } + +// mustHaveFieldNameColon ensures that, per RFC 7230, the +// field-name is on a single line, so the first line must +// contain a colon. +func mustHaveFieldNameColon(line []byte) error { + if bytes.IndexByte(line, ':') < 0 { + return ProtocolError(fmt.Sprintf("malformed MIME header: missing colon: %q", line)) + } + return nil +} + +var nl = []byte("\n") + +// upcomingHeaderKeys returns an approximation of the number of keys +// that will be in this header. If it gets confused, it returns 0. +func (r *Reader) upcomingHeaderKeys() (n int) { + // Try to determine the 'hint' size. + r.R.Peek(1) // force a buffer load if empty + s := r.R.Buffered() + if s == 0 { + return + } + peek, _ := r.R.Peek(s) + for len(peek) > 0 && n < 1000 { + var line []byte + line, peek, _ = bytes.Cut(peek, nl) + if len(line) == 0 || (len(line) == 1 && line[0] == '\r') { + // Blank line separating headers from the body. + break + } + if line[0] == ' ' || line[0] == '\t' { + // Folded continuation of the previous line. + continue + } + n++ + } + return n +} + +// CanonicalMIMEHeaderKey returns the canonical format of the +// MIME header key s. The canonicalization converts the first +// letter and any letter following a hyphen to upper case; +// the rest are converted to lowercase. For example, the +// canonical key for "accept-encoding" is "Accept-Encoding". +// MIME header keys are assumed to be ASCII only. +// If s contains a space or invalid header field bytes, it is +// returned without modifications. +func CanonicalMIMEHeaderKey(s string) string { + // Quick check for canonical encoding. + upper := true + for i := 0; i < len(s); i++ { + c := s[i] + if !validHeaderFieldByte(c) { + return s + } + if upper && 'a' <= c && c <= 'z' { + s, _ = canonicalMIMEHeaderKey([]byte(s)) + return s + } + if !upper && 'A' <= c && c <= 'Z' { + s, _ = canonicalMIMEHeaderKey([]byte(s)) + return s + } + upper = c == '-' + } + return s +} + +const toLower = 'a' - 'A' + +// validHeaderFieldByte reports whether c is a valid byte in a header +// field name. RFC 7230 says: +// +// header-field = field-name ":" OWS field-value OWS +// field-name = token +// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / +// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +// token = 1*tchar +func validHeaderFieldByte(c byte) bool { + // mask is a 128-bit bitmap with 1s for allowed bytes, + // so that the byte c can be tested with a shift and an and. + // If c >= 128, then 1<>64)) != 0 +} + +// validHeaderValueByte reports whether c is a valid byte in a header +// field value. RFC 7230 says: +// +// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] +// field-vchar = VCHAR / obs-text +// obs-text = %x80-FF +// +// RFC 5234 says: +// +// HTAB = %x09 +// SP = %x20 +// VCHAR = %x21-7E +func validHeaderValueByte(c byte) bool { + // mask is a 128-bit bitmap with 1s for allowed bytes, + // so that the byte c can be tested with a shift and an and. + // If c >= 128, then 1<>64)) == 0 +} + +// canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is +// allowed to mutate the provided byte slice before returning the +// string. +// +// For invalid inputs (if a contains spaces or non-token bytes), a +// is unchanged and a string copy is returned. +// +// ok is true if the header key contains only valid characters and spaces. +// ReadMIMEHeader accepts header keys containing spaces, but does not +// canonicalize them. +func canonicalMIMEHeaderKey(a []byte) (_ string, ok bool) { + if len(a) == 0 { + return "", false + } + + // See if a looks like a header key. If not, return it unchanged. + noCanon := false + for _, c := range a { + if validHeaderFieldByte(c) { + continue + } + // Don't canonicalize. + if c == ' ' { + // We accept invalid headers with a space before the + // colon, but must not canonicalize them. + // See https://go.dev/issue/34540. + noCanon = true + continue + } + return string(a), false + } + if noCanon { + return string(a), true + } + + upper := true + for i, c := range a { + // Canonicalize: first letter upper case + // and upper case after each dash. + // (Host, User-Agent, If-Modified-Since). + // MIME headers are ASCII only, so no Unicode issues. + if upper && 'a' <= c && c <= 'z' { + c -= toLower + } else if !upper && 'A' <= c && c <= 'Z' { + c += toLower + } + a[i] = c + upper = c == '-' // for next time + } + commonHeaderOnce.Do(initCommonHeader) + // The compiler recognizes m[string(byteSlice)] as a special + // case, so a copy of a's bytes into a new string does not + // happen in this map lookup: + if v := commonHeader[string(a)]; v != "" { + return v, true + } + return string(a), true +} + +// commonHeader interns common header strings. +var commonHeader map[string]string + +var commonHeaderOnce sync.Once + +func initCommonHeader() { + commonHeader = make(map[string]string) + for _, v := range []string{ + "Accept", + "Accept-Charset", + "Accept-Encoding", + "Accept-Language", + "Accept-Ranges", + "Cache-Control", + "Cc", + "Connection", + "Content-Id", + "Content-Language", + "Content-Length", + "Content-Transfer-Encoding", + "Content-Type", + "Cookie", + "Date", + "Dkim-Signature", + "Etag", + "Expires", + "From", + "Host", + "If-Modified-Since", + "If-None-Match", + "In-Reply-To", + "Last-Modified", + "Location", + "Message-Id", + "Mime-Version", + "Pragma", + "Received", + "Return-Path", + "Server", + "Set-Cookie", + "Subject", + "To", + "User-Agent", + "Via", + "X-Forwarded-For", + "X-Imforwards", + "X-Powered-By", + } { + commonHeader[v] = v + } +} diff --git a/contrib/go/_std_1.22/src/net/textproto/textproto.go b/contrib/go/_std_1.23/src/net/textproto/textproto.go similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/textproto.go rename to contrib/go/_std_1.23/src/net/textproto/textproto.go diff --git a/contrib/go/_std_1.22/src/net/textproto/writer.go b/contrib/go/_std_1.23/src/net/textproto/writer.go similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/writer.go rename to contrib/go/_std_1.23/src/net/textproto/writer.go diff --git a/contrib/go/_std_1.22/src/net/textproto/ya.make b/contrib/go/_std_1.23/src/net/textproto/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/ya.make rename to contrib/go/_std_1.23/src/net/textproto/ya.make diff --git a/contrib/go/_std_1.22/src/net/udpsock.go b/contrib/go/_std_1.23/src/net/udpsock.go similarity index 100% rename from contrib/go/_std_1.22/src/net/udpsock.go rename to contrib/go/_std_1.23/src/net/udpsock.go diff --git a/contrib/go/_std_1.22/src/net/udpsock_plan9.go b/contrib/go/_std_1.23/src/net/udpsock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/udpsock_plan9.go rename to contrib/go/_std_1.23/src/net/udpsock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/udpsock_posix.go b/contrib/go/_std_1.23/src/net/udpsock_posix.go similarity index 95% rename from contrib/go/_std_1.22/src/net/udpsock_posix.go rename to contrib/go/_std_1.23/src/net/udpsock_posix.go index 50350598317e..3cd1d0a76241 100644 --- a/contrib/go/_std_1.22/src/net/udpsock_posix.go +++ b/contrib/go/_std_1.23/src/net/udpsock_posix.go @@ -205,7 +205,7 @@ func (c *UDPConn) writeMsgAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) { ctrlCtxFn := sd.Dialer.ControlContext if ctrlCtxFn == nil && sd.Dialer.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sd.Dialer.Control(network, address, c) } } @@ -217,9 +217,9 @@ func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPCo } func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } @@ -231,9 +231,9 @@ func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, } func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } diff --git a/contrib/go/_std_1.22/src/net/unixsock.go b/contrib/go/_std_1.23/src/net/unixsock.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock.go rename to contrib/go/_std_1.23/src/net/unixsock.go diff --git a/contrib/go/_std_1.22/src/net/unixsock_plan9.go b/contrib/go/_std_1.23/src/net/unixsock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock_plan9.go rename to contrib/go/_std_1.23/src/net/unixsock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/unixsock_posix.go b/contrib/go/_std_1.23/src/net/unixsock_posix.go similarity index 95% rename from contrib/go/_std_1.22/src/net/unixsock_posix.go rename to contrib/go/_std_1.23/src/net/unixsock_posix.go index f6c8e8f0b0e7..dc01b3874a6e 100644 --- a/contrib/go/_std_1.22/src/net/unixsock_posix.go +++ b/contrib/go/_std_1.23/src/net/unixsock_posix.go @@ -157,7 +157,7 @@ func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err err func (sd *sysDialer) dialUnix(ctx context.Context, laddr, raddr *UnixAddr) (*UnixConn, error) { ctrlCtxFn := sd.Dialer.ControlContext if ctrlCtxFn == nil && sd.Dialer.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sd.Dialer.Control(network, address, c) } } @@ -217,9 +217,9 @@ func (l *UnixListener) SetUnlinkOnClose(unlink bool) { } func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } @@ -231,9 +231,9 @@ func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixLi } func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } diff --git a/contrib/go/_std_1.22/src/net/unixsock_readmsg_cloexec.go b/contrib/go/_std_1.23/src/net/unixsock_readmsg_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock_readmsg_cloexec.go rename to contrib/go/_std_1.23/src/net/unixsock_readmsg_cloexec.go diff --git a/contrib/go/_std_1.22/src/net/unixsock_readmsg_cmsg_cloexec.go b/contrib/go/_std_1.23/src/net/unixsock_readmsg_cmsg_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock_readmsg_cmsg_cloexec.go rename to contrib/go/_std_1.23/src/net/unixsock_readmsg_cmsg_cloexec.go diff --git a/contrib/go/_std_1.22/src/net/unixsock_readmsg_other.go b/contrib/go/_std_1.23/src/net/unixsock_readmsg_other.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock_readmsg_other.go rename to contrib/go/_std_1.23/src/net/unixsock_readmsg_other.go diff --git a/contrib/go/_std_1.22/src/net/url/url.go b/contrib/go/_std_1.23/src/net/url/url.go similarity index 97% rename from contrib/go/_std_1.22/src/net/url/url.go rename to contrib/go/_std_1.23/src/net/url/url.go index f362958edd72..7beaef1ba663 100644 --- a/contrib/go/_std_1.22/src/net/url/url.go +++ b/contrib/go/_std_1.23/src/net/url/url.go @@ -14,9 +14,10 @@ import ( "errors" "fmt" "path" - "sort" + "slices" "strconv" "strings" + _ "unsafe" // for linkname ) // Error reports an error and the operation and URL that caused it. @@ -677,6 +678,16 @@ func parseHost(host string) (string, error) { // - setPath("/foo%2fbar") will set Path="/foo/bar" and RawPath="/foo%2fbar" // setPath will return an error only if the provided path contains an invalid // escaping. +// +// setPath should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname badSetPath net/url.(*URL).setPath func (u *URL) setPath(p string) error { path, err := unescape(p, encodePath) if err != nil { @@ -692,6 +703,9 @@ func (u *URL) setPath(p string) error { return nil } +// for linkname because we cannot linkname methods directly +func badSetPath(*URL, string) error + // EscapedPath returns the escaped form of u.Path. // In general there are multiple possible escaped forms of any path. // EscapedPath returns u.RawPath when it is a valid escaping of u.Path. @@ -814,6 +828,22 @@ func validOptionalPort(port string) bool { // - if u.Fragment is empty, #fragment is omitted. func (u *URL) String() string { var buf strings.Builder + + n := len(u.Scheme) + if u.Opaque != "" { + n += len(u.Opaque) + } else { + if !u.OmitHost && (u.Scheme != "" || u.Host != "" || u.User != nil) { + username := u.User.Username() + password, _ := u.User.Password() + n += len(username) + len(password) + len(u.Host) + } + n += len(u.Path) + } + n += len(u.RawQuery) + len(u.RawFragment) + n += len(":" + "//" + "//" + ":" + "@" + "/" + "./" + "?" + "#") + buf.Grow(n) + if u.Scheme != "" { buf.WriteString(u.Scheme) buf.WriteByte(':') @@ -978,7 +1008,7 @@ func (v Values) Encode() string { for k := range v { keys = append(keys, k) } - sort.Strings(keys) + slices.Sort(keys) for _, k := range keys { vs := v[k] keyEscaped := QueryEscape(k) @@ -1108,6 +1138,13 @@ func (u *URL) ResolveReference(ref *URL) *URL { url.RawFragment = u.RawFragment } } + if ref.Path == "" && u.Opaque != "" { + url.Opaque = u.Opaque + url.User = nil + url.Host = "" + url.Path = "" + return &url + } // The "abs_path" or "rel_path" cases. url.Host = u.Host url.User = u.User diff --git a/contrib/go/_std_1.22/src/net/url/ya.make b/contrib/go/_std_1.23/src/net/url/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/url/ya.make rename to contrib/go/_std_1.23/src/net/url/ya.make diff --git a/contrib/go/_std_1.22/src/net/writev_unix.go b/contrib/go/_std_1.23/src/net/writev_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/writev_unix.go rename to contrib/go/_std_1.23/src/net/writev_unix.go diff --git a/contrib/go/_std_1.23/src/net/ya.make b/contrib/go/_std_1.23/src/net/ya.make new file mode 100644 index 000000000000..f2e9537d3c1a --- /dev/null +++ b/contrib/go/_std_1.23/src/net/ya.make @@ -0,0 +1,259 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + addrselect.go + cgo_darwin.go + cgo_unix.go + cgo_unix_syscall.go + conf.go + dial.go + dnsclient.go + dnsclient_unix.go + dnsconfig.go + dnsconfig_unix.go + error_posix.go + error_unix.go + fd_posix.go + fd_unix.go + file.go + file_unix.go + hook.go + hook_unix.go + hosts.go + interface.go + interface_bsd.go + interface_darwin.go + ip.go + iprawsock.go + iprawsock_posix.go + ipsock.go + ipsock_posix.go + lookup.go + lookup_unix.go + mac.go + mptcpsock_stub.go + net.go + netcgo_off.go + netgo_off.go + nss.go + parse.go + pipe.go + port.go + port_unix.go + rawconn.go + rlimit_unix.go + sendfile_unix_alt.go + sock_bsd.go + sock_posix.go + sockaddr_posix.go + sockopt_bsd.go + sockopt_posix.go + sockoptip_bsdvar.go + sockoptip_posix.go + splice_stub.go + sys_cloexec.go + tcpsock.go + tcpsock_posix.go + tcpsock_unix.go + tcpsockopt_darwin.go + tcpsockopt_posix.go + udpsock.go + udpsock_posix.go + unixsock.go + unixsock_posix.go + unixsock_readmsg_cloexec.go + writev_unix.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED) + SRCS( + addrselect.go + cgo_unix.go + conf.go + dial.go + dnsclient.go + dnsclient_unix.go + dnsconfig.go + dnsconfig_unix.go + error_posix.go + error_unix.go + fd_posix.go + fd_unix.go + file.go + file_unix.go + hook.go + hook_unix.go + hosts.go + interface.go + interface_linux.go + ip.go + iprawsock.go + iprawsock_posix.go + ipsock.go + ipsock_posix.go + lookup.go + lookup_unix.go + mac.go + mptcpsock_linux.go + net.go + netcgo_off.go + netgo_off.go + nss.go + parse.go + pipe.go + port.go + port_unix.go + rawconn.go + rlimit_unix.go + sendfile_linux.go + sock_cloexec.go + sock_linux.go + sock_posix.go + sockaddr_posix.go + sockopt_linux.go + sockopt_posix.go + sockoptip_linux.go + sockoptip_posix.go + splice_linux.go + tcpsock.go + tcpsock_posix.go + tcpsock_unix.go + tcpsockopt_posix.go + tcpsockopt_unix.go + udpsock.go + udpsock_posix.go + unixsock.go + unixsock_posix.go + unixsock_readmsg_cmsg_cloexec.go + writev_unix.go + ) + +IF (CGO_ENABLED) + CGO_SRCS( + cgo_linux.go + cgo_resnew.go + cgo_socknew.go + cgo_unix_cgo.go + cgo_unix_cgo_res.go + ) +ENDIF() +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + addrselect.go + cgo_stub.go + conf.go + dial.go + dnsclient.go + dnsclient_unix.go + dnsconfig.go + dnsconfig_unix.go + error_posix.go + error_unix.go + fd_posix.go + fd_unix.go + file.go + file_unix.go + hook.go + hook_unix.go + hosts.go + interface.go + interface_linux.go + ip.go + iprawsock.go + iprawsock_posix.go + ipsock.go + ipsock_posix.go + lookup.go + lookup_unix.go + mac.go + mptcpsock_linux.go + net.go + netcgo_off.go + netgo_off.go + nss.go + parse.go + pipe.go + port.go + port_unix.go + rawconn.go + rlimit_unix.go + sendfile_linux.go + sock_cloexec.go + sock_linux.go + sock_posix.go + sockaddr_posix.go + sockopt_linux.go + sockopt_posix.go + sockoptip_linux.go + sockoptip_posix.go + splice_linux.go + tcpsock.go + tcpsock_posix.go + tcpsock_unix.go + tcpsockopt_posix.go + tcpsockopt_unix.go + udpsock.go + udpsock_posix.go + unixsock.go + unixsock_posix.go + unixsock_readmsg_cmsg_cloexec.go + writev_unix.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + addrselect.go + conf.go + dial.go + dnsclient.go + dnsclient_unix.go + dnsconfig.go + dnsconfig_windows.go + error_posix.go + error_windows.go + fd_posix.go + fd_windows.go + file.go + file_windows.go + hook.go + hook_windows.go + hosts.go + interface.go + interface_windows.go + ip.go + iprawsock.go + iprawsock_posix.go + ipsock.go + ipsock_posix.go + lookup.go + lookup_windows.go + mac.go + mptcpsock_stub.go + net.go + netcgo_off.go + netgo_off.go + nss.go + parse.go + pipe.go + port.go + rawconn.go + sendfile_windows.go + sock_posix.go + sock_windows.go + sockaddr_posix.go + sockopt_posix.go + sockopt_windows.go + sockoptip_posix.go + sockoptip_windows.go + splice_stub.go + tcpsock.go + tcpsock_posix.go + tcpsock_windows.go + tcpsockopt_posix.go + tcpsockopt_windows.go + udpsock.go + udpsock_posix.go + unixsock.go + unixsock_posix.go + unixsock_readmsg_other.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/os/dir.go b/contrib/go/_std_1.23/src/os/dir.go new file mode 100644 index 000000000000..04392193aa6b --- /dev/null +++ b/contrib/go/_std_1.23/src/os/dir.go @@ -0,0 +1,191 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "internal/bytealg" + "internal/filepathlite" + "io" + "io/fs" + "slices" +) + +type readdirMode int + +const ( + readdirName readdirMode = iota + readdirDirEntry + readdirFileInfo +) + +// Readdir reads the contents of the directory associated with file and +// returns a slice of up to n [FileInfo] values, as would be returned +// by [Lstat], in directory order. Subsequent calls on the same file will yield +// further FileInfos. +// +// If n > 0, Readdir returns at most n FileInfo structures. In this case, if +// Readdir returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is [io.EOF]. +// +// If n <= 0, Readdir returns all the FileInfo from the directory in +// a single slice. In this case, if Readdir succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil error. If it encounters an error before the end of the +// directory, Readdir returns the FileInfo read until that point +// and a non-nil error. +// +// Most clients are better served by the more efficient ReadDir method. +func (f *File) Readdir(n int) ([]FileInfo, error) { + if f == nil { + return nil, ErrInvalid + } + _, _, infos, err := f.readdir(n, readdirFileInfo) + if infos == nil { + // Readdir has historically always returned a non-nil empty slice, never nil, + // even on error (except misuse with nil receiver above). + // Keep it that way to avoid breaking overly sensitive callers. + infos = []FileInfo{} + } + return infos, err +} + +// Readdirnames reads the contents of the directory associated with file +// and returns a slice of up to n names of files in the directory, +// in directory order. Subsequent calls on the same file will yield +// further names. +// +// If n > 0, Readdirnames returns at most n names. In this case, if +// Readdirnames returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is [io.EOF]. +// +// If n <= 0, Readdirnames returns all the names from the directory in +// a single slice. In this case, if Readdirnames succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil error. If it encounters an error before the end of the +// directory, Readdirnames returns the names read until that point and +// a non-nil error. +func (f *File) Readdirnames(n int) (names []string, err error) { + if f == nil { + return nil, ErrInvalid + } + names, _, _, err = f.readdir(n, readdirName) + if names == nil { + // Readdirnames has historically always returned a non-nil empty slice, never nil, + // even on error (except misuse with nil receiver above). + // Keep it that way to avoid breaking overly sensitive callers. + names = []string{} + } + return names, err +} + +// A DirEntry is an entry read from a directory +// (using the [ReadDir] function or a [File.ReadDir] method). +type DirEntry = fs.DirEntry + +// ReadDir reads the contents of the directory associated with the file f +// and returns a slice of [DirEntry] values in directory order. +// Subsequent calls on the same file will yield later DirEntry records in the directory. +// +// If n > 0, ReadDir returns at most n DirEntry records. +// In this case, if ReadDir returns an empty slice, it will return an error explaining why. +// At the end of a directory, the error is [io.EOF]. +// +// If n <= 0, ReadDir returns all the DirEntry records remaining in the directory. +// When it succeeds, it returns a nil error (not io.EOF). +func (f *File) ReadDir(n int) ([]DirEntry, error) { + if f == nil { + return nil, ErrInvalid + } + _, dirents, _, err := f.readdir(n, readdirDirEntry) + if dirents == nil { + // Match Readdir and Readdirnames: don't return nil slices. + dirents = []DirEntry{} + } + return dirents, err +} + +// testingForceReadDirLstat forces ReadDir to call Lstat, for testing that code path. +// This can be difficult to provoke on some Unix systems otherwise. +var testingForceReadDirLstat bool + +// ReadDir reads the named directory, +// returning all its directory entries sorted by filename. +// If an error occurs reading the directory, +// ReadDir returns the entries it was able to read before the error, +// along with the error. +func ReadDir(name string) ([]DirEntry, error) { + f, err := openDir(name) + if err != nil { + return nil, err + } + defer f.Close() + + dirs, err := f.ReadDir(-1) + slices.SortFunc(dirs, func(a, b DirEntry) int { + return bytealg.CompareString(a.Name(), b.Name()) + }) + return dirs, err +} + +// CopyFS copies the file system fsys into the directory dir, +// creating dir if necessary. +// +// Files are created with mode 0o666 plus any execute permissions +// from the source, and directories are created with mode 0o777 +// (before umask). +// +// CopyFS will not overwrite existing files. If a file name in fsys +// already exists in the destination, CopyFS will return an error +// such that errors.Is(err, fs.ErrExist) will be true. +// +// Symbolic links in fsys are not supported. A *PathError with Err set +// to ErrInvalid is returned when copying from a symbolic link. +// +// Symbolic links in dir are followed. +// +// Copying stops at and returns the first error encountered. +func CopyFS(dir string, fsys fs.FS) error { + return fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + fpath, err := filepathlite.Localize(path) + if err != nil { + return err + } + newPath := joinPath(dir, fpath) + if d.IsDir() { + return MkdirAll(newPath, 0777) + } + + // TODO(panjf2000): handle symlinks with the help of fs.ReadLinkFS + // once https://go.dev/issue/49580 is done. + // we also need filepathlite.IsLocal from https://go.dev/cl/564295. + if !d.Type().IsRegular() { + return &PathError{Op: "CopyFS", Path: path, Err: ErrInvalid} + } + + r, err := fsys.Open(path) + if err != nil { + return err + } + defer r.Close() + info, err := r.Stat() + if err != nil { + return err + } + w, err := OpenFile(newPath, O_CREATE|O_EXCL|O_WRONLY, 0666|info.Mode()&0777) + if err != nil { + return err + } + + if _, err := io.Copy(w, r); err != nil { + w.Close() + return &PathError{Op: "Copy", Path: newPath, Err: err} + } + return w.Close() + }) +} diff --git a/contrib/go/_std_1.22/src/os/dir_darwin.go b/contrib/go/_std_1.23/src/os/dir_darwin.go similarity index 93% rename from contrib/go/_std_1.22/src/os/dir_darwin.go rename to contrib/go/_std_1.23/src/os/dir_darwin.go index e6d5bda24bdd..91b67d8d61d1 100644 --- a/contrib/go/_std_1.22/src/os/dir_darwin.go +++ b/contrib/go/_std_1.23/src/os/dir_darwin.go @@ -25,16 +25,24 @@ func (d *dirInfo) close() { } func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { - if f.dirinfo == nil { + // If this file has no dirinfo, create one. + var d *dirInfo + for { + d = f.dirinfo.Load() + if d != nil { + break + } dir, call, errno := f.pfd.OpenDir() if errno != nil { return nil, nil, nil, &PathError{Op: call, Path: f.name, Err: errno} } - f.dirinfo = &dirInfo{ - dir: dir, + d = &dirInfo{dir: dir} + if f.dirinfo.CompareAndSwap(nil, d) { + break } + // We lost the race: try again. + d.close() } - d := f.dirinfo size := n if size <= 0 { diff --git a/contrib/go/_std_1.23/src/os/dir_plan9.go b/contrib/go/_std_1.23/src/os/dir_plan9.go new file mode 100644 index 000000000000..ab5c1efce5b0 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/dir_plan9.go @@ -0,0 +1,90 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "io" + "io/fs" + "syscall" +) + +func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { + // If this file has no dirinfo, create one. + d := file.dirinfo.Load() + if d == nil { + d = new(dirInfo) + file.dirinfo.Store(d) + } + d.mu.Lock() + defer d.mu.Unlock() + + size := n + if size <= 0 { + size = 100 + n = -1 + } + for n != 0 { + // Refill the buffer if necessary. + if d.bufp >= d.nbuf { + nb, err := file.Read(d.buf[:]) + + // Update the buffer state before checking for errors. + d.bufp, d.nbuf = 0, nb + + if err != nil { + if err == io.EOF { + break + } + return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: err} + } + if nb < syscall.STATFIXLEN { + return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: syscall.ErrShortStat} + } + } + + // Get a record from the buffer. + b := d.buf[d.bufp:] + m := int(uint16(b[0])|uint16(b[1])<<8) + 2 + if m < syscall.STATFIXLEN { + return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: syscall.ErrShortStat} + } + + dir, err := syscall.UnmarshalDir(b[:m]) + if err != nil { + return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: err} + } + + if mode == readdirName { + names = append(names, dir.Name) + } else { + f := fileInfoFromStat(dir) + if mode == readdirDirEntry { + dirents = append(dirents, dirEntry{f}) + } else { + infos = append(infos, f) + } + } + d.bufp += m + n-- + } + + if n > 0 && len(names)+len(dirents)+len(infos) == 0 { + return nil, nil, nil, io.EOF + } + return names, dirents, infos, nil +} + +type dirEntry struct { + fs *fileStat +} + +func (de dirEntry) Name() string { return de.fs.Name() } +func (de dirEntry) IsDir() bool { return de.fs.IsDir() } +func (de dirEntry) Type() FileMode { return de.fs.Mode().Type() } +func (de dirEntry) Info() (FileInfo, error) { return de.fs, nil } + +func (de dirEntry) String() string { + return fs.FormatDirEntry(de) +} diff --git a/contrib/go/_std_1.22/src/os/dir_unix.go b/contrib/go/_std_1.23/src/os/dir_unix.go similarity index 78% rename from contrib/go/_std_1.22/src/os/dir_unix.go rename to contrib/go/_std_1.23/src/os/dir_unix.go index 266a78acafce..d8b4faa05788 100644 --- a/contrib/go/_std_1.22/src/os/dir_unix.go +++ b/contrib/go/_std_1.23/src/os/dir_unix.go @@ -7,6 +7,8 @@ package os import ( + "internal/byteorder" + "internal/goarch" "io" "runtime" "sync" @@ -16,6 +18,7 @@ import ( // Auxiliary information if the File describes a directory type dirInfo struct { + mu sync.Mutex buf *[]byte // buffer for directory I/O nbuf int // length of buf; return value from Getdirentries bufp int // location of next record in buf. @@ -42,12 +45,17 @@ func (d *dirInfo) close() { } func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { - // If this file has no dirinfo, create one. - if f.dirinfo == nil { - f.dirinfo = new(dirInfo) - f.dirinfo.buf = dirBufPool.Get().(*[]byte) + // If this file has no dirInfo, create one. + d := f.dirinfo.Load() + if d == nil { + d = new(dirInfo) + f.dirinfo.Store(d) + } + d.mu.Lock() + defer d.mu.Unlock() + if d.buf == nil { + d.buf = dirBufPool.Get().(*[]byte) } - d := f.dirinfo // Change the meaning of n for the implementation below. // @@ -73,6 +81,9 @@ func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEn return names, dirents, infos, &PathError{Op: "readdirent", Path: f.name, Err: errno} } if d.nbuf <= 0 { + // Optimization: we can return the buffer to the pool, there is nothing else to read. + dirBufPool.Put(d.buf) + d.buf = nil break // EOF } } @@ -153,7 +164,7 @@ func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { if len(b) < int(off+size) { return 0, false } - if isBigEndian { + if goarch.BigEndian { return readIntBE(b[off:], size), true } return readIntLE(b[off:], size), true @@ -164,15 +175,11 @@ func readIntBE(b []byte, size uintptr) uint64 { case 1: return uint64(b[0]) case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[1]) | uint64(b[0])<<8 + return uint64(byteorder.BeUint16(b)) case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 + return uint64(byteorder.BeUint32(b)) case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + return uint64(byteorder.BeUint64(b)) default: panic("syscall: readInt with unsupported size") } @@ -183,15 +190,11 @@ func readIntLE(b []byte, size uintptr) uint64 { case 1: return uint64(b[0]) case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 + return uint64(byteorder.LeUint16(b)) case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 + return uint64(byteorder.LeUint32(b)) case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + return uint64(byteorder.LeUint64(b)) default: panic("syscall: readInt with unsupported size") } diff --git a/contrib/go/_std_1.23/src/os/dir_windows.go b/contrib/go/_std_1.23/src/os/dir_windows.go new file mode 100644 index 000000000000..52d5acda2afd --- /dev/null +++ b/contrib/go/_std_1.23/src/os/dir_windows.go @@ -0,0 +1,230 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "internal/syscall/windows" + "io" + "io/fs" + "runtime" + "sync" + "syscall" + "unsafe" +) + +// Auxiliary information if the File describes a directory +type dirInfo struct { + mu sync.Mutex + // buf is a slice pointer so the slice header + // does not escape to the heap when returning + // buf to dirBufPool. + buf *[]byte // buffer for directory I/O + bufp int // location of next record in buf + h syscall.Handle + vol uint32 + class uint32 // type of entries in buf + path string // absolute directory path, empty if the file system supports FILE_ID_BOTH_DIR_INFO +} + +const ( + // dirBufSize is the size of the dirInfo buffer. + // The buffer must be big enough to hold at least a single entry. + // The filename alone can be 512 bytes (MAX_PATH*2), and the fixed part of + // the FILE_ID_BOTH_DIR_INFO structure is 105 bytes, so dirBufSize + // should not be set below 1024 bytes (512+105+safety buffer). + // Windows 8.1 and earlier only works with buffer sizes up to 64 kB. + dirBufSize = 64 * 1024 // 64kB +) + +var dirBufPool = sync.Pool{ + New: func() any { + // The buffer must be at least a block long. + buf := make([]byte, dirBufSize) + return &buf + }, +} + +func (d *dirInfo) close() { + d.h = 0 + if d.buf != nil { + dirBufPool.Put(d.buf) + d.buf = nil + } +} + +// allowReadDirFileID indicates whether File.readdir should try to use FILE_ID_BOTH_DIR_INFO +// if the underlying file system supports it. +// Useful for testing purposes. +var allowReadDirFileID = true + +func (d *dirInfo) init(h syscall.Handle) { + d.h = h + d.class = windows.FileFullDirectoryRestartInfo + // The previous settings are enough to read the directory entries. + // The following code is only needed to support os.SameFile. + + // It is safe to query d.vol once and reuse the value. + // Hard links are not allowed to reference files in other volumes. + // Junctions and symbolic links can reference files and directories in other volumes, + // but the reparse point should still live in the parent volume. + var flags uint32 + err := windows.GetVolumeInformationByHandle(h, nil, 0, &d.vol, nil, &flags, nil, 0) + if err != nil { + d.vol = 0 // Set to zero in case Windows writes garbage to it. + // If we can't get the volume information, we can't use os.SameFile, + // but we can still read the directory entries. + return + } + if flags&windows.FILE_SUPPORTS_OBJECT_IDS == 0 { + // The file system does not support object IDs, no need to continue. + return + } + if allowReadDirFileID && flags&windows.FILE_SUPPORTS_OPEN_BY_FILE_ID != 0 { + // Use FileIdBothDirectoryRestartInfo if available as it returns the file ID + // without the need to open the file. + d.class = windows.FileIdBothDirectoryRestartInfo + } else { + // If FileIdBothDirectoryRestartInfo is not available but objects IDs are supported, + // get the directory path so that os.SameFile can use it to open the file + // and retrieve the file ID. + d.path, _ = windows.FinalPath(h, windows.FILE_NAME_OPENED) + } +} + +func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { + // If this file has no dirInfo, create one. + var d *dirInfo + for { + d = file.dirinfo.Load() + if d != nil { + break + } + d = new(dirInfo) + d.init(file.pfd.Sysfd) + if file.dirinfo.CompareAndSwap(nil, d) { + break + } + // We lost the race: try again. + d.close() + } + d.mu.Lock() + defer d.mu.Unlock() + if d.buf == nil { + d.buf = dirBufPool.Get().(*[]byte) + } + + wantAll := n <= 0 + if wantAll { + n = -1 + } + for n != 0 { + // Refill the buffer if necessary + if d.bufp == 0 { + err = windows.GetFileInformationByHandleEx(file.pfd.Sysfd, d.class, (*byte)(unsafe.Pointer(&(*d.buf)[0])), uint32(len(*d.buf))) + runtime.KeepAlive(file) + if err != nil { + if err == syscall.ERROR_NO_MORE_FILES { + // Optimization: we can return the buffer to the pool, there is nothing else to read. + dirBufPool.Put(d.buf) + d.buf = nil + break + } + if err == syscall.ERROR_FILE_NOT_FOUND && + (d.class == windows.FileIdBothDirectoryRestartInfo || d.class == windows.FileFullDirectoryRestartInfo) { + // GetFileInformationByHandleEx doesn't document the return error codes when the info class is FileIdBothDirectoryRestartInfo, + // but MS-FSA 2.1.5.6.3 [1] specifies that the underlying file system driver should return STATUS_NO_SUCH_FILE when + // reading an empty root directory, which is mapped to ERROR_FILE_NOT_FOUND by Windows. + // Note that some file system drivers may never return this error code, as the spec allows to return the "." and ".." + // entries in such cases, making the directory appear non-empty. + // The chances of false positive are very low, as we know that the directory exists, else GetVolumeInformationByHandle + // would have failed, and that the handle is still valid, as we haven't closed it. + // See go.dev/issue/61159. + // [1] https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fsa/fa8194e0-53ec-413b-8315-e8fa85396fd8 + break + } + if s, _ := file.Stat(); s != nil && !s.IsDir() { + err = &PathError{Op: "readdir", Path: file.name, Err: syscall.ENOTDIR} + } else { + err = &PathError{Op: "GetFileInformationByHandleEx", Path: file.name, Err: err} + } + return + } + if d.class == windows.FileIdBothDirectoryRestartInfo { + d.class = windows.FileIdBothDirectoryInfo + } else if d.class == windows.FileFullDirectoryRestartInfo { + d.class = windows.FileFullDirectoryInfo + } + } + // Drain the buffer + var islast bool + for n != 0 && !islast { + var nextEntryOffset uint32 + var nameslice []uint16 + entry := unsafe.Pointer(&(*d.buf)[d.bufp]) + if d.class == windows.FileIdBothDirectoryInfo { + info := (*windows.FILE_ID_BOTH_DIR_INFO)(entry) + nextEntryOffset = info.NextEntryOffset + nameslice = unsafe.Slice(&info.FileName[0], info.FileNameLength/2) + } else { + info := (*windows.FILE_FULL_DIR_INFO)(entry) + nextEntryOffset = info.NextEntryOffset + nameslice = unsafe.Slice(&info.FileName[0], info.FileNameLength/2) + } + d.bufp += int(nextEntryOffset) + islast = nextEntryOffset == 0 + if islast { + d.bufp = 0 + } + if (len(nameslice) == 1 && nameslice[0] == '.') || + (len(nameslice) == 2 && nameslice[0] == '.' && nameslice[1] == '.') { + // Ignore "." and ".." and avoid allocating a string for them. + continue + } + name := syscall.UTF16ToString(nameslice) + if mode == readdirName { + names = append(names, name) + } else { + var f *fileStat + if d.class == windows.FileIdBothDirectoryInfo { + f = newFileStatFromFileIDBothDirInfo((*windows.FILE_ID_BOTH_DIR_INFO)(entry)) + } else { + f = newFileStatFromFileFullDirInfo((*windows.FILE_FULL_DIR_INFO)(entry)) + if d.path != "" { + // Defer appending the entry name to the parent directory path until + // it is really needed, to avoid allocating a string that may not be used. + // It is currently only used in os.SameFile. + f.appendNameToPath = true + f.path = d.path + } + } + f.name = name + f.vol = d.vol + if mode == readdirDirEntry { + dirents = append(dirents, dirEntry{f}) + } else { + infos = append(infos, f) + } + } + n-- + } + } + if !wantAll && len(names)+len(dirents)+len(infos) == 0 { + return nil, nil, nil, io.EOF + } + return names, dirents, infos, nil +} + +type dirEntry struct { + fs *fileStat +} + +func (de dirEntry) Name() string { return de.fs.Name() } +func (de dirEntry) IsDir() bool { return de.fs.IsDir() } +func (de dirEntry) Type() FileMode { return de.fs.Mode().Type() } +func (de dirEntry) Info() (FileInfo, error) { return de.fs, nil } + +func (de dirEntry) String() string { + return fs.FormatDirEntry(de) +} diff --git a/contrib/go/_std_1.22/src/os/dirent_aix.go b/contrib/go/_std_1.23/src/os/dirent_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_aix.go rename to contrib/go/_std_1.23/src/os/dirent_aix.go diff --git a/contrib/go/_std_1.22/src/os/dirent_dragonfly.go b/contrib/go/_std_1.23/src/os/dirent_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_dragonfly.go rename to contrib/go/_std_1.23/src/os/dirent_dragonfly.go diff --git a/contrib/go/_std_1.22/src/os/dirent_freebsd.go b/contrib/go/_std_1.23/src/os/dirent_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_freebsd.go rename to contrib/go/_std_1.23/src/os/dirent_freebsd.go diff --git a/contrib/go/_std_1.22/src/os/dirent_js.go b/contrib/go/_std_1.23/src/os/dirent_js.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_js.go rename to contrib/go/_std_1.23/src/os/dirent_js.go diff --git a/contrib/go/_std_1.22/src/os/dirent_linux.go b/contrib/go/_std_1.23/src/os/dirent_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_linux.go rename to contrib/go/_std_1.23/src/os/dirent_linux.go diff --git a/contrib/go/_std_1.22/src/os/dirent_netbsd.go b/contrib/go/_std_1.23/src/os/dirent_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_netbsd.go rename to contrib/go/_std_1.23/src/os/dirent_netbsd.go diff --git a/contrib/go/_std_1.22/src/os/dirent_openbsd.go b/contrib/go/_std_1.23/src/os/dirent_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_openbsd.go rename to contrib/go/_std_1.23/src/os/dirent_openbsd.go diff --git a/contrib/go/_std_1.22/src/os/dirent_solaris.go b/contrib/go/_std_1.23/src/os/dirent_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_solaris.go rename to contrib/go/_std_1.23/src/os/dirent_solaris.go diff --git a/contrib/go/_std_1.22/src/os/dirent_wasip1.go b/contrib/go/_std_1.23/src/os/dirent_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_wasip1.go rename to contrib/go/_std_1.23/src/os/dirent_wasip1.go diff --git a/contrib/go/_std_1.22/src/os/env.go b/contrib/go/_std_1.23/src/os/env.go similarity index 97% rename from contrib/go/_std_1.22/src/os/env.go rename to contrib/go/_std_1.23/src/os/env.go index 63ad5ab4bd5f..9ac62451ae39 100644 --- a/contrib/go/_std_1.22/src/os/env.go +++ b/contrib/go/_std_1.23/src/os/env.go @@ -12,7 +12,7 @@ import ( ) // Expand replaces ${var} or $var in the string based on the mapping function. -// For example, os.ExpandEnv(s) is equivalent to os.Expand(s, os.Getenv). +// For example, [os.ExpandEnv](s) is equivalent to [os.Expand](s, [os.Getenv]). func Expand(s string, mapping func(string) string) string { var buf []byte // ${} is all ASCII, so bytes are fine for this operation. @@ -97,7 +97,7 @@ func getShellName(s string) (string, int) { // Getenv retrieves the value of the environment variable named by the key. // It returns the value, which will be empty if the variable is not present. -// To distinguish between an empty value and an unset value, use LookupEnv. +// To distinguish between an empty value and an unset value, use [LookupEnv]. func Getenv(key string) string { testlog.Getenv(key) v, _ := syscall.Getenv(key) diff --git a/contrib/go/_std_1.23/src/os/error.go b/contrib/go/_std_1.23/src/os/error.go new file mode 100644 index 000000000000..284b9e992cd4 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/error.go @@ -0,0 +1,141 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "internal/poll" + "io/fs" +) + +// Portable analogs of some common system call errors. +// +// Errors returned from this package may be tested against these errors +// with [errors.Is]. +var ( + // ErrInvalid indicates an invalid argument. + // Methods on File will return this error when the receiver is nil. + ErrInvalid = fs.ErrInvalid // "invalid argument" + + ErrPermission = fs.ErrPermission // "permission denied" + ErrExist = fs.ErrExist // "file already exists" + ErrNotExist = fs.ErrNotExist // "file does not exist" + ErrClosed = fs.ErrClosed // "file already closed" + + ErrNoDeadline = errNoDeadline() // "file type does not support deadline" + ErrDeadlineExceeded = errDeadlineExceeded() // "i/o timeout" +) + +func errNoDeadline() error { return poll.ErrNoDeadline } + +// errDeadlineExceeded returns the value for os.ErrDeadlineExceeded. +// This error comes from the internal/poll package, which is also +// used by package net. Doing it this way ensures that the net +// package will return os.ErrDeadlineExceeded for an exceeded deadline, +// as documented by net.Conn.SetDeadline, without requiring any extra +// work in the net package and without requiring the internal/poll +// package to import os (which it can't, because that would be circular). +func errDeadlineExceeded() error { return poll.ErrDeadlineExceeded } + +type timeout interface { + Timeout() bool +} + +// PathError records an error and the operation and file path that caused it. +type PathError = fs.PathError + +// SyscallError records an error from a specific system call. +type SyscallError struct { + Syscall string + Err error +} + +func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() } + +func (e *SyscallError) Unwrap() error { return e.Err } + +// Timeout reports whether this error represents a timeout. +func (e *SyscallError) Timeout() bool { + t, ok := e.Err.(timeout) + return ok && t.Timeout() +} + +// NewSyscallError returns, as an error, a new [SyscallError] +// with the given system call name and error details. +// As a convenience, if err is nil, NewSyscallError returns nil. +func NewSyscallError(syscall string, err error) error { + if err == nil { + return nil + } + return &SyscallError{syscall, err} +} + +// IsExist returns a boolean indicating whether its argument is known to report +// that a file or directory already exists. It is satisfied by [ErrExist] as +// well as some syscall errors. +// +// This function predates [errors.Is]. It only supports errors returned by +// the os package. New code should use errors.Is(err, fs.ErrExist). +func IsExist(err error) bool { + return underlyingErrorIs(err, ErrExist) +} + +// IsNotExist returns a boolean indicating whether its argument is known to +// report that a file or directory does not exist. It is satisfied by +// [ErrNotExist] as well as some syscall errors. +// +// This function predates [errors.Is]. It only supports errors returned by +// the os package. New code should use errors.Is(err, fs.ErrNotExist). +func IsNotExist(err error) bool { + return underlyingErrorIs(err, ErrNotExist) +} + +// IsPermission returns a boolean indicating whether its argument is known to +// report that permission is denied. It is satisfied by [ErrPermission] as well +// as some syscall errors. +// +// This function predates [errors.Is]. It only supports errors returned by +// the os package. New code should use errors.Is(err, fs.ErrPermission). +func IsPermission(err error) bool { + return underlyingErrorIs(err, ErrPermission) +} + +// IsTimeout returns a boolean indicating whether its argument is known +// to report that a timeout occurred. +// +// This function predates [errors.Is], and the notion of whether an +// error indicates a timeout can be ambiguous. For example, the Unix +// error EWOULDBLOCK sometimes indicates a timeout and sometimes does not. +// New code should use errors.Is with a value appropriate to the call +// returning the error, such as [os.ErrDeadlineExceeded]. +func IsTimeout(err error) bool { + terr, ok := underlyingError(err).(timeout) + return ok && terr.Timeout() +} + +func underlyingErrorIs(err, target error) bool { + // Note that this function is not errors.Is: + // underlyingError only unwraps the specific error-wrapping types + // that it historically did, not all errors implementing Unwrap(). + err = underlyingError(err) + if err == target { + return true + } + // To preserve prior behavior, only examine syscall errors. + e, ok := err.(syscallErrorType) + return ok && e.Is(target) +} + +// underlyingError returns the underlying error for known os error types. +func underlyingError(err error) error { + switch err := err.(type) { + case *PathError: + return err.Err + case *LinkError: + return err.Err + case *SyscallError: + return err.Err + } + return err +} diff --git a/contrib/go/_std_1.22/src/os/error_errno.go b/contrib/go/_std_1.23/src/os/error_errno.go similarity index 100% rename from contrib/go/_std_1.22/src/os/error_errno.go rename to contrib/go/_std_1.23/src/os/error_errno.go diff --git a/contrib/go/_std_1.22/src/os/error_plan9.go b/contrib/go/_std_1.23/src/os/error_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/error_plan9.go rename to contrib/go/_std_1.23/src/os/error_plan9.go diff --git a/contrib/go/_std_1.23/src/os/exec.go b/contrib/go/_std_1.23/src/os/exec.go new file mode 100644 index 000000000000..1220761df5ee --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec.go @@ -0,0 +1,404 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "errors" + "internal/testlog" + "runtime" + "sync" + "sync/atomic" + "syscall" + "time" +) + +// ErrProcessDone indicates a [Process] has finished. +var ErrProcessDone = errors.New("os: process already finished") + +type processMode uint8 + +const ( + // modePID means that Process operations such use the raw PID from the + // Pid field. handle is not used. + // + // This may be due to the host not supporting handles, or because + // Process was created as a literal, leaving handle unset. + // + // This must be the zero value so Process literals get modePID. + modePID processMode = iota + + // modeHandle means that Process operations use handle, which is + // initialized with an OS process handle. + // + // Note that Release and Wait will deactivate and eventually close the + // handle, so acquire may fail, indicating the reason. + modeHandle +) + +type processStatus uint64 + +const ( + // PID/handle OK to use. + statusOK processStatus = 0 + + // statusDone indicates that the PID/handle should not be used because + // the process is done (has been successfully Wait'd on). + statusDone processStatus = 1 << 62 + + // statusReleased indicates that the PID/handle should not be used + // because the process is released. + statusReleased processStatus = 1 << 63 + + processStatusMask = 0x3 << 62 +) + +// Process stores the information about a process created by [StartProcess]. +type Process struct { + Pid int + + mode processMode + + // State contains the atomic process state. + // + // In modePID, this consists only of the processStatus fields, which + // indicate if the process is done/released. + // + // In modeHandle, the lower bits also contain a reference count for the + // handle field. + // + // The Process itself initially holds 1 persistent reference. Any + // operation that uses the handle with a system call temporarily holds + // an additional transient reference. This prevents the handle from + // being closed prematurely, which could result in the OS allocating a + // different handle with the same value, leading to Process' methods + // operating on the wrong process. + // + // Release and Wait both drop the Process' persistent reference, but + // other concurrent references may delay actually closing the handle + // because they hold a transient reference. + // + // Regardless, we want new method calls to immediately treat the handle + // as unavailable after Release or Wait to avoid extending this delay. + // This is achieved by setting either processStatus flag when the + // Process' persistent reference is dropped. The only difference in the + // flags is the reason the handle is unavailable, which affects the + // errors returned by concurrent calls. + state atomic.Uint64 + + // Used only in modePID. + sigMu sync.RWMutex // avoid race between wait and signal + + // handle is the OS handle for process actions, used only in + // modeHandle. + // + // handle must be accessed only via the handleTransientAcquire method + // (or during closeHandle), not directly! handle is immutable. + // + // On Windows, it is a handle from OpenProcess. + // On Linux, it is a pidfd. + // It is unused on other GOOSes. + handle uintptr +} + +func newPIDProcess(pid int) *Process { + p := &Process{ + Pid: pid, + mode: modePID, + } + runtime.SetFinalizer(p, (*Process).Release) + return p +} + +func newHandleProcess(pid int, handle uintptr) *Process { + p := &Process{ + Pid: pid, + mode: modeHandle, + handle: handle, + } + p.state.Store(1) // 1 persistent reference + runtime.SetFinalizer(p, (*Process).Release) + return p +} + +func newDoneProcess(pid int) *Process { + p := &Process{ + Pid: pid, + mode: modeHandle, + // N.B Since we set statusDone, handle will never actually be + // used, so its value doesn't matter. + } + p.state.Store(uint64(statusDone)) // No persistent reference, as there is no handle. + runtime.SetFinalizer(p, (*Process).Release) + return p +} + +func (p *Process) handleTransientAcquire() (uintptr, processStatus) { + if p.mode != modeHandle { + panic("handleTransientAcquire called in invalid mode") + } + + for { + refs := p.state.Load() + if refs&processStatusMask != 0 { + return 0, processStatus(refs & processStatusMask) + } + new := refs + 1 + if !p.state.CompareAndSwap(refs, new) { + continue + } + return p.handle, statusOK + } +} + +func (p *Process) handleTransientRelease() { + if p.mode != modeHandle { + panic("handleTransientRelease called in invalid mode") + } + + for { + state := p.state.Load() + refs := state &^ processStatusMask + status := processStatus(state & processStatusMask) + if refs == 0 { + // This should never happen because + // handleTransientRelease is always paired with + // handleTransientAcquire. + panic("release of handle with refcount 0") + } + if refs == 1 && status == statusOK { + // Process holds a persistent reference and always sets + // a status when releasing that reference + // (handlePersistentRelease). Thus something has gone + // wrong if this is the last release but a status has + // not always been set. + panic("final release of handle without processStatus") + } + new := state - 1 + if !p.state.CompareAndSwap(state, new) { + continue + } + if new&^processStatusMask == 0 { + p.closeHandle() + } + return + } +} + +// Drop the Process' persistent reference on the handle, deactivating future +// Wait/Signal calls with the passed reason. +// +// Returns the status prior to this call. If this is not statusOK, then the +// reference was not dropped or status changed. +func (p *Process) handlePersistentRelease(reason processStatus) processStatus { + if p.mode != modeHandle { + panic("handlePersistentRelease called in invalid mode") + } + + for { + refs := p.state.Load() + status := processStatus(refs & processStatusMask) + if status != statusOK { + // Both Release and successful Wait will drop the + // Process' persistent reference on the handle. We + // can't allow concurrent calls to drop the reference + // twice, so we use the status as a guard to ensure the + // reference is dropped exactly once. + return status + } + if refs == 0 { + // This should never happen because dropping the + // persistent reference always sets a status. + panic("release of handle with refcount 0") + } + new := (refs - 1) | uint64(reason) + if !p.state.CompareAndSwap(refs, new) { + continue + } + if new&^processStatusMask == 0 { + p.closeHandle() + } + return status + } +} + +func (p *Process) pidStatus() processStatus { + if p.mode != modePID { + panic("pidStatus called in invalid mode") + } + + return processStatus(p.state.Load()) +} + +func (p *Process) pidDeactivate(reason processStatus) { + if p.mode != modePID { + panic("pidDeactivate called in invalid mode") + } + + // Both Release and successful Wait will deactivate the PID. Only one + // of those should win, so nothing left to do here if the compare + // fails. + // + // N.B. This means that results can be inconsistent. e.g., with a + // racing Release and Wait, Wait may successfully wait on the process, + // returning the wait status, while future calls error with "process + // released" rather than "process done". + p.state.CompareAndSwap(0, uint64(reason)) +} + +// ProcAttr holds the attributes that will be applied to a new process +// started by StartProcess. +type ProcAttr struct { + // If Dir is non-empty, the child changes into the directory before + // creating the process. + Dir string + // If Env is non-nil, it gives the environment variables for the + // new process in the form returned by Environ. + // If it is nil, the result of Environ will be used. + Env []string + // Files specifies the open files inherited by the new process. The + // first three entries correspond to standard input, standard output, and + // standard error. An implementation may support additional entries, + // depending on the underlying operating system. A nil entry corresponds + // to that file being closed when the process starts. + // On Unix systems, StartProcess will change these File values + // to blocking mode, which means that SetDeadline will stop working + // and calling Close will not interrupt a Read or Write. + Files []*File + + // Operating system-specific process creation attributes. + // Note that setting this field means that your program + // may not execute properly or even compile on some + // operating systems. + Sys *syscall.SysProcAttr +} + +// A Signal represents an operating system signal. +// The usual underlying implementation is operating system-dependent: +// on Unix it is syscall.Signal. +type Signal interface { + String() string + Signal() // to distinguish from other Stringers +} + +// Getpid returns the process id of the caller. +func Getpid() int { return syscall.Getpid() } + +// Getppid returns the process id of the caller's parent. +func Getppid() int { return syscall.Getppid() } + +// FindProcess looks for a running process by its pid. +// +// The [Process] it returns can be used to obtain information +// about the underlying operating system process. +// +// On Unix systems, FindProcess always succeeds and returns a Process +// for the given pid, regardless of whether the process exists. To test whether +// the process actually exists, see whether p.Signal(syscall.Signal(0)) reports +// an error. +func FindProcess(pid int) (*Process, error) { + return findProcess(pid) +} + +// StartProcess starts a new process with the program, arguments and attributes +// specified by name, argv and attr. The argv slice will become [os.Args] in the +// new process, so it normally starts with the program name. +// +// If the calling goroutine has locked the operating system thread +// with [runtime.LockOSThread] and modified any inheritable OS-level +// thread state (for example, Linux or Plan 9 name spaces), the new +// process will inherit the caller's thread state. +// +// StartProcess is a low-level interface. The [os/exec] package provides +// higher-level interfaces. +// +// If there is an error, it will be of type [*PathError]. +func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) { + testlog.Open(name) + return startProcess(name, argv, attr) +} + +// Release releases any resources associated with the [Process] p, +// rendering it unusable in the future. +// Release only needs to be called if [Process.Wait] is not. +func (p *Process) Release() error { + // Note to future authors: the Release API is cursed. + // + // On Unix and Plan 9, Release sets p.Pid = -1. This is the only part of the + // Process API that is not thread-safe, but it can't be changed now. + // + // On Windows, Release does _not_ modify p.Pid. + // + // On Windows, Wait calls Release after successfully waiting to + // proactively clean up resources. + // + // On Unix and Plan 9, Wait also proactively cleans up resources, but + // can not call Release, as Wait does not set p.Pid = -1. + // + // On Unix and Plan 9, calling Release a second time has no effect. + // + // On Windows, calling Release a second time returns EINVAL. + return p.release() +} + +// Kill causes the [Process] to exit immediately. Kill does not wait until +// the Process has actually exited. This only kills the Process itself, +// not any other processes it may have started. +func (p *Process) Kill() error { + return p.kill() +} + +// Wait waits for the [Process] to exit, and then returns a +// ProcessState describing its status and an error, if any. +// Wait releases any resources associated with the Process. +// On most operating systems, the Process must be a child +// of the current process or an error will be returned. +func (p *Process) Wait() (*ProcessState, error) { + return p.wait() +} + +// Signal sends a signal to the [Process]. +// Sending [Interrupt] on Windows is not implemented. +func (p *Process) Signal(sig Signal) error { + return p.signal(sig) +} + +// UserTime returns the user CPU time of the exited process and its children. +func (p *ProcessState) UserTime() time.Duration { + return p.userTime() +} + +// SystemTime returns the system CPU time of the exited process and its children. +func (p *ProcessState) SystemTime() time.Duration { + return p.systemTime() +} + +// Exited reports whether the program has exited. +// On Unix systems this reports true if the program exited due to calling exit, +// but false if the program terminated due to a signal. +func (p *ProcessState) Exited() bool { + return p.exited() +} + +// Success reports whether the program exited successfully, +// such as with exit status 0 on Unix. +func (p *ProcessState) Success() bool { + return p.success() +} + +// Sys returns system-dependent exit information about +// the process. Convert it to the appropriate underlying +// type, such as [syscall.WaitStatus] on Unix, to access its contents. +func (p *ProcessState) Sys() any { + return p.sys() +} + +// SysUsage returns system-dependent resource usage information about +// the exited process. Convert it to the appropriate underlying +// type, such as [*syscall.Rusage] on Unix, to access its contents. +// (On Unix, *syscall.Rusage matches struct rusage as defined in the +// getrusage(2) manual page.) +func (p *ProcessState) SysUsage() any { + return p.sysUsage() +} diff --git a/contrib/go/_std_1.23/src/os/exec/exec.go b/contrib/go/_std_1.23/src/os/exec/exec.go new file mode 100644 index 000000000000..da9f68fe28f1 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec/exec.go @@ -0,0 +1,1312 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package exec runs external commands. It wraps os.StartProcess to make it +// easier to remap stdin and stdout, connect I/O with pipes, and do other +// adjustments. +// +// Unlike the "system" library call from C and other languages, the +// os/exec package intentionally does not invoke the system shell and +// does not expand any glob patterns or handle other expansions, +// pipelines, or redirections typically done by shells. The package +// behaves more like C's "exec" family of functions. To expand glob +// patterns, either call the shell directly, taking care to escape any +// dangerous input, or use the [path/filepath] package's Glob function. +// To expand environment variables, use package os's ExpandEnv. +// +// Note that the examples in this package assume a Unix system. +// They may not run on Windows, and they do not run in the Go Playground +// used by golang.org and godoc.org. +// +// # Executables in the current directory +// +// The functions [Command] and [LookPath] look for a program +// in the directories listed in the current path, following the +// conventions of the host operating system. +// Operating systems have for decades included the current +// directory in this search, sometimes implicitly and sometimes +// configured explicitly that way by default. +// Modern practice is that including the current directory +// is usually unexpected and often leads to security problems. +// +// To avoid those security problems, as of Go 1.19, this package will not resolve a program +// using an implicit or explicit path entry relative to the current directory. +// That is, if you run [LookPath]("go"), it will not successfully return +// ./go on Unix nor .\go.exe on Windows, no matter how the path is configured. +// Instead, if the usual path algorithms would result in that answer, +// these functions return an error err satisfying [errors.Is](err, [ErrDot]). +// +// For example, consider these two program snippets: +// +// path, err := exec.LookPath("prog") +// if err != nil { +// log.Fatal(err) +// } +// use(path) +// +// and +// +// cmd := exec.Command("prog") +// if err := cmd.Run(); err != nil { +// log.Fatal(err) +// } +// +// These will not find and run ./prog or .\prog.exe, +// no matter how the current path is configured. +// +// Code that always wants to run a program from the current directory +// can be rewritten to say "./prog" instead of "prog". +// +// Code that insists on including results from relative path entries +// can instead override the error using an errors.Is check: +// +// path, err := exec.LookPath("prog") +// if errors.Is(err, exec.ErrDot) { +// err = nil +// } +// if err != nil { +// log.Fatal(err) +// } +// use(path) +// +// and +// +// cmd := exec.Command("prog") +// if errors.Is(cmd.Err, exec.ErrDot) { +// cmd.Err = nil +// } +// if err := cmd.Run(); err != nil { +// log.Fatal(err) +// } +// +// Setting the environment variable GODEBUG=execerrdot=0 +// disables generation of ErrDot entirely, temporarily restoring the pre-Go 1.19 +// behavior for programs that are unable to apply more targeted fixes. +// A future version of Go may remove support for this variable. +// +// Before adding such overrides, make sure you understand the +// security implications of doing so. +// See https://go.dev/blog/path-security for more information. +package exec + +import ( + "bytes" + "context" + "errors" + "internal/godebug" + "internal/syscall/execenv" + "io" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "syscall" + "time" +) + +// Error is returned by [LookPath] when it fails to classify a file as an +// executable. +type Error struct { + // Name is the file name for which the error occurred. + Name string + // Err is the underlying error. + Err error +} + +func (e *Error) Error() string { + return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error() +} + +func (e *Error) Unwrap() error { return e.Err } + +// ErrWaitDelay is returned by [Cmd.Wait] if the process exits with a +// successful status code but its output pipes are not closed before the +// command's WaitDelay expires. +var ErrWaitDelay = errors.New("exec: WaitDelay expired before I/O complete") + +// wrappedError wraps an error without relying on fmt.Errorf. +type wrappedError struct { + prefix string + err error +} + +func (w wrappedError) Error() string { + return w.prefix + ": " + w.err.Error() +} + +func (w wrappedError) Unwrap() error { + return w.err +} + +// Cmd represents an external command being prepared or run. +// +// A Cmd cannot be reused after calling its [Cmd.Run], [Cmd.Output] or [Cmd.CombinedOutput] +// methods. +type Cmd struct { + // Path is the path of the command to run. + // + // This is the only field that must be set to a non-zero + // value. If Path is relative, it is evaluated relative + // to Dir. + Path string + + // Args holds command line arguments, including the command as Args[0]. + // If the Args field is empty or nil, Run uses {Path}. + // + // In typical use, both Path and Args are set by calling Command. + Args []string + + // Env specifies the environment of the process. + // Each entry is of the form "key=value". + // If Env is nil, the new process uses the current process's + // environment. + // If Env contains duplicate environment keys, only the last + // value in the slice for each duplicate key is used. + // As a special case on Windows, SYSTEMROOT is always added if + // missing and not explicitly set to the empty string. + Env []string + + // Dir specifies the working directory of the command. + // If Dir is the empty string, Run runs the command in the + // calling process's current directory. + Dir string + + // Stdin specifies the process's standard input. + // + // If Stdin is nil, the process reads from the null device (os.DevNull). + // + // If Stdin is an *os.File, the process's standard input is connected + // directly to that file. + // + // Otherwise, during the execution of the command a separate + // goroutine reads from Stdin and delivers that data to the command + // over a pipe. In this case, Wait does not complete until the goroutine + // stops copying, either because it has reached the end of Stdin + // (EOF or a read error), or because writing to the pipe returned an error, + // or because a nonzero WaitDelay was set and expired. + Stdin io.Reader + + // Stdout and Stderr specify the process's standard output and error. + // + // If either is nil, Run connects the corresponding file descriptor + // to the null device (os.DevNull). + // + // If either is an *os.File, the corresponding output from the process + // is connected directly to that file. + // + // Otherwise, during the execution of the command a separate goroutine + // reads from the process over a pipe and delivers that data to the + // corresponding Writer. In this case, Wait does not complete until the + // goroutine reaches EOF or encounters an error or a nonzero WaitDelay + // expires. + // + // If Stdout and Stderr are the same writer, and have a type that can + // be compared with ==, at most one goroutine at a time will call Write. + Stdout io.Writer + Stderr io.Writer + + // ExtraFiles specifies additional open files to be inherited by the + // new process. It does not include standard input, standard output, or + // standard error. If non-nil, entry i becomes file descriptor 3+i. + // + // ExtraFiles is not supported on Windows. + ExtraFiles []*os.File + + // SysProcAttr holds optional, operating system-specific attributes. + // Run passes it to os.StartProcess as the os.ProcAttr's Sys field. + SysProcAttr *syscall.SysProcAttr + + // Process is the underlying process, once started. + Process *os.Process + + // ProcessState contains information about an exited process. + // If the process was started successfully, Wait or Run will + // populate its ProcessState when the command completes. + ProcessState *os.ProcessState + + // ctx is the context passed to CommandContext, if any. + ctx context.Context + + Err error // LookPath error, if any. + + // If Cancel is non-nil, the command must have been created with + // CommandContext and Cancel will be called when the command's + // Context is done. By default, CommandContext sets Cancel to + // call the Kill method on the command's Process. + // + // Typically a custom Cancel will send a signal to the command's + // Process, but it may instead take other actions to initiate cancellation, + // such as closing a stdin or stdout pipe or sending a shutdown request on a + // network socket. + // + // If the command exits with a success status after Cancel is + // called, and Cancel does not return an error equivalent to + // os.ErrProcessDone, then Wait and similar methods will return a non-nil + // error: either an error wrapping the one returned by Cancel, + // or the error from the Context. + // (If the command exits with a non-success status, or Cancel + // returns an error that wraps os.ErrProcessDone, Wait and similar methods + // continue to return the command's usual exit status.) + // + // If Cancel is set to nil, nothing will happen immediately when the command's + // Context is done, but a nonzero WaitDelay will still take effect. That may + // be useful, for example, to work around deadlocks in commands that do not + // support shutdown signals but are expected to always finish quickly. + // + // Cancel will not be called if Start returns a non-nil error. + Cancel func() error + + // If WaitDelay is non-zero, it bounds the time spent waiting on two sources + // of unexpected delay in Wait: a child process that fails to exit after the + // associated Context is canceled, and a child process that exits but leaves + // its I/O pipes unclosed. + // + // The WaitDelay timer starts when either the associated Context is done or a + // call to Wait observes that the child process has exited, whichever occurs + // first. When the delay has elapsed, the command shuts down the child process + // and/or its I/O pipes. + // + // If the child process has failed to exit — perhaps because it ignored or + // failed to receive a shutdown signal from a Cancel function, or because no + // Cancel function was set — then it will be terminated using os.Process.Kill. + // + // Then, if the I/O pipes communicating with the child process are still open, + // those pipes are closed in order to unblock any goroutines currently blocked + // on Read or Write calls. + // + // If pipes are closed due to WaitDelay, no Cancel call has occurred, + // and the command has otherwise exited with a successful status, Wait and + // similar methods will return ErrWaitDelay instead of nil. + // + // If WaitDelay is zero (the default), I/O pipes will be read until EOF, + // which might not occur until orphaned subprocesses of the command have + // also closed their descriptors for the pipes. + WaitDelay time.Duration + + // childIOFiles holds closers for any of the child process's + // stdin, stdout, and/or stderr files that were opened by the Cmd itself + // (not supplied by the caller). These should be closed as soon as they + // are inherited by the child process. + childIOFiles []io.Closer + + // parentIOPipes holds closers for the parent's end of any pipes + // connected to the child's stdin, stdout, and/or stderr streams + // that were opened by the Cmd itself (not supplied by the caller). + // These should be closed after Wait sees the command and copying + // goroutines exit, or after WaitDelay has expired. + parentIOPipes []io.Closer + + // goroutine holds a set of closures to execute to copy data + // to and/or from the command's I/O pipes. + goroutine []func() error + + // If goroutineErr is non-nil, it receives the first error from a copying + // goroutine once all such goroutines have completed. + // goroutineErr is set to nil once its error has been received. + goroutineErr <-chan error + + // If ctxResult is non-nil, it receives the result of watchCtx exactly once. + ctxResult <-chan ctxResult + + // The stack saved when the Command was created, if GODEBUG contains + // execwait=2. Used for debugging leaks. + createdByStack []byte + + // For a security release long ago, we created x/sys/execabs, + // which manipulated the unexported lookPathErr error field + // in this struct. For Go 1.19 we exported the field as Err error, + // above, but we have to keep lookPathErr around for use by + // old programs building against new toolchains. + // The String and Start methods look for an error in lookPathErr + // in preference to Err, to preserve the errors that execabs sets. + // + // In general we don't guarantee misuse of reflect like this, + // but the misuse of reflect was by us, the best of various bad + // options to fix the security problem, and people depend on + // those old copies of execabs continuing to work. + // The result is that we have to leave this variable around for the + // rest of time, a compatibility scar. + // + // See https://go.dev/blog/path-security + // and https://go.dev/issue/43724 for more context. + lookPathErr error + + // cachedLookExtensions caches the result of calling lookExtensions. + // It is set when Command is called with an absolute path, letting it do + // the work of resolving the extension, so Start doesn't need to do it again. + // This is only used on Windows. + cachedLookExtensions struct{ in, out string } +} + +// A ctxResult reports the result of watching the Context associated with a +// running command (and sending corresponding signals if needed). +type ctxResult struct { + err error + + // If timer is non-nil, it expires after WaitDelay has elapsed after + // the Context is done. + // + // (If timer is nil, that means that the Context was not done before the + // command completed, or no WaitDelay was set, or the WaitDelay already + // expired and its effect was already applied.) + timer *time.Timer +} + +var execwait = godebug.New("#execwait") +var execerrdot = godebug.New("execerrdot") + +// Command returns the [Cmd] struct to execute the named program with +// the given arguments. +// +// It sets only the Path and Args in the returned structure. +// +// If name contains no path separators, Command uses [LookPath] to +// resolve name to a complete path if possible. Otherwise it uses name +// directly as Path. +// +// The returned Cmd's Args field is constructed from the command name +// followed by the elements of arg, so arg should not include the +// command name itself. For example, Command("echo", "hello"). +// Args[0] is always name, not the possibly resolved Path. +// +// On Windows, processes receive the whole command line as a single string +// and do their own parsing. Command combines and quotes Args into a command +// line string with an algorithm compatible with applications using +// CommandLineToArgvW (which is the most common way). Notable exceptions are +// msiexec.exe and cmd.exe (and thus, all batch files), which have a different +// unquoting algorithm. In these or other similar cases, you can do the +// quoting yourself and provide the full command line in SysProcAttr.CmdLine, +// leaving Args empty. +func Command(name string, arg ...string) *Cmd { + cmd := &Cmd{ + Path: name, + Args: append([]string{name}, arg...), + } + + if v := execwait.Value(); v != "" { + if v == "2" { + // Obtain the caller stack. (This is equivalent to runtime/debug.Stack, + // copied to avoid importing the whole package.) + stack := make([]byte, 1024) + for { + n := runtime.Stack(stack, false) + if n < len(stack) { + stack = stack[:n] + break + } + stack = make([]byte, 2*len(stack)) + } + + if i := bytes.Index(stack, []byte("\nos/exec.Command(")); i >= 0 { + stack = stack[i+1:] + } + cmd.createdByStack = stack + } + + runtime.SetFinalizer(cmd, func(c *Cmd) { + if c.Process != nil && c.ProcessState == nil { + debugHint := "" + if c.createdByStack == nil { + debugHint = " (set GODEBUG=execwait=2 to capture stacks for debugging)" + } else { + os.Stderr.WriteString("GODEBUG=execwait=2 detected a leaked exec.Cmd created by:\n") + os.Stderr.Write(c.createdByStack) + os.Stderr.WriteString("\n") + debugHint = "" + } + panic("exec: Cmd started a Process but leaked without a call to Wait" + debugHint) + } + }) + } + + if filepath.Base(name) == name { + lp, err := LookPath(name) + if lp != "" { + // Update cmd.Path even if err is non-nil. + // If err is ErrDot (especially on Windows), lp may include a resolved + // extension (like .exe or .bat) that should be preserved. + cmd.Path = lp + } + if err != nil { + cmd.Err = err + } + } else if runtime.GOOS == "windows" && filepath.IsAbs(name) { + // We may need to add a filename extension from PATHEXT + // or verify an extension that is already present. + // Since the path is absolute, its extension should be unambiguous + // and independent of cmd.Dir, and we can go ahead and cache the lookup now. + // + // Note that we don't cache anything here for relative paths, because + // cmd.Dir may be set after we return from this function and that may + // cause the command to resolve to a different extension. + if lp, err := lookExtensions(name, ""); err == nil { + cmd.cachedLookExtensions.in, cmd.cachedLookExtensions.out = name, lp + } else { + cmd.Err = err + } + } + return cmd +} + +// CommandContext is like [Command] but includes a context. +// +// The provided context is used to interrupt the process +// (by calling cmd.Cancel or [os.Process.Kill]) +// if the context becomes done before the command completes on its own. +// +// CommandContext sets the command's Cancel function to invoke the Kill method +// on its Process, and leaves its WaitDelay unset. The caller may change the +// cancellation behavior by modifying those fields before starting the command. +func CommandContext(ctx context.Context, name string, arg ...string) *Cmd { + if ctx == nil { + panic("nil Context") + } + cmd := Command(name, arg...) + cmd.ctx = ctx + cmd.Cancel = func() error { + return cmd.Process.Kill() + } + return cmd +} + +// String returns a human-readable description of c. +// It is intended only for debugging. +// In particular, it is not suitable for use as input to a shell. +// The output of String may vary across Go releases. +func (c *Cmd) String() string { + if c.Err != nil || c.lookPathErr != nil { + // failed to resolve path; report the original requested path (plus args) + return strings.Join(c.Args, " ") + } + // report the exact executable path (plus args) + b := new(strings.Builder) + b.WriteString(c.Path) + for _, a := range c.Args[1:] { + b.WriteByte(' ') + b.WriteString(a) + } + return b.String() +} + +// interfaceEqual protects against panics from doing equality tests on +// two interfaces with non-comparable underlying types. +func interfaceEqual(a, b any) bool { + defer func() { + recover() + }() + return a == b +} + +func (c *Cmd) argv() []string { + if len(c.Args) > 0 { + return c.Args + } + return []string{c.Path} +} + +func (c *Cmd) childStdin() (*os.File, error) { + if c.Stdin == nil { + f, err := os.Open(os.DevNull) + if err != nil { + return nil, err + } + c.childIOFiles = append(c.childIOFiles, f) + return f, nil + } + + if f, ok := c.Stdin.(*os.File); ok { + return f, nil + } + + pr, pw, err := os.Pipe() + if err != nil { + return nil, err + } + + c.childIOFiles = append(c.childIOFiles, pr) + c.parentIOPipes = append(c.parentIOPipes, pw) + c.goroutine = append(c.goroutine, func() error { + _, err := io.Copy(pw, c.Stdin) + if skipStdinCopyError(err) { + err = nil + } + if err1 := pw.Close(); err == nil { + err = err1 + } + return err + }) + return pr, nil +} + +func (c *Cmd) childStdout() (*os.File, error) { + return c.writerDescriptor(c.Stdout) +} + +func (c *Cmd) childStderr(childStdout *os.File) (*os.File, error) { + if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) { + return childStdout, nil + } + return c.writerDescriptor(c.Stderr) +} + +// writerDescriptor returns an os.File to which the child process +// can write to send data to w. +// +// If w is nil, writerDescriptor returns a File that writes to os.DevNull. +func (c *Cmd) writerDescriptor(w io.Writer) (*os.File, error) { + if w == nil { + f, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0) + if err != nil { + return nil, err + } + c.childIOFiles = append(c.childIOFiles, f) + return f, nil + } + + if f, ok := w.(*os.File); ok { + return f, nil + } + + pr, pw, err := os.Pipe() + if err != nil { + return nil, err + } + + c.childIOFiles = append(c.childIOFiles, pw) + c.parentIOPipes = append(c.parentIOPipes, pr) + c.goroutine = append(c.goroutine, func() error { + _, err := io.Copy(w, pr) + pr.Close() // in case io.Copy stopped due to write error + return err + }) + return pw, nil +} + +func closeDescriptors(closers []io.Closer) { + for _, fd := range closers { + fd.Close() + } +} + +// Run starts the specified command and waits for it to complete. +// +// The returned error is nil if the command runs, has no problems +// copying stdin, stdout, and stderr, and exits with a zero exit +// status. +// +// If the command starts but does not complete successfully, the error is of +// type [*ExitError]. Other error types may be returned for other situations. +// +// If the calling goroutine has locked the operating system thread +// with [runtime.LockOSThread] and modified any inheritable OS-level +// thread state (for example, Linux or Plan 9 name spaces), the new +// process will inherit the caller's thread state. +func (c *Cmd) Run() error { + if err := c.Start(); err != nil { + return err + } + return c.Wait() +} + +// Start starts the specified command but does not wait for it to complete. +// +// If Start returns successfully, the c.Process field will be set. +// +// After a successful call to Start the [Cmd.Wait] method must be called in +// order to release associated system resources. +func (c *Cmd) Start() error { + // Check for doubled Start calls before we defer failure cleanup. If the prior + // call to Start succeeded, we don't want to spuriously close its pipes. + if c.Process != nil { + return errors.New("exec: already started") + } + + started := false + defer func() { + closeDescriptors(c.childIOFiles) + c.childIOFiles = nil + + if !started { + closeDescriptors(c.parentIOPipes) + c.parentIOPipes = nil + } + }() + + if c.Path == "" && c.Err == nil && c.lookPathErr == nil { + c.Err = errors.New("exec: no command") + } + if c.Err != nil || c.lookPathErr != nil { + if c.lookPathErr != nil { + return c.lookPathErr + } + return c.Err + } + lp := c.Path + if runtime.GOOS == "windows" { + if c.Path == c.cachedLookExtensions.in { + // If Command was called with an absolute path, we already resolved + // its extension and shouldn't need to do so again (provided c.Path + // wasn't set to another value between the calls to Command and Start). + lp = c.cachedLookExtensions.out + } else { + // If *Cmd was made without using Command at all, or if Command was + // called with a relative path, we had to wait until now to resolve + // it in case c.Dir was changed. + // + // Unfortunately, we cannot write the result back to c.Path because programs + // may assume that they can call Start concurrently with reading the path. + // (It is safe and non-racy to do so on Unix platforms, and users might not + // test with the race detector on all platforms; + // see https://go.dev/issue/62596.) + // + // So we will pass the fully resolved path to os.StartProcess, but leave + // c.Path as is: missing a bit of logging information seems less harmful + // than triggering a surprising data race, and if the user really cares + // about that bit of logging they can always use LookPath to resolve it. + var err error + lp, err = lookExtensions(c.Path, c.Dir) + if err != nil { + return err + } + } + } + if c.Cancel != nil && c.ctx == nil { + return errors.New("exec: command with a non-nil Cancel was not created with CommandContext") + } + if c.ctx != nil { + select { + case <-c.ctx.Done(): + return c.ctx.Err() + default: + } + } + + childFiles := make([]*os.File, 0, 3+len(c.ExtraFiles)) + stdin, err := c.childStdin() + if err != nil { + return err + } + childFiles = append(childFiles, stdin) + stdout, err := c.childStdout() + if err != nil { + return err + } + childFiles = append(childFiles, stdout) + stderr, err := c.childStderr(stdout) + if err != nil { + return err + } + childFiles = append(childFiles, stderr) + childFiles = append(childFiles, c.ExtraFiles...) + + env, err := c.environ() + if err != nil { + return err + } + + c.Process, err = os.StartProcess(lp, c.argv(), &os.ProcAttr{ + Dir: c.Dir, + Files: childFiles, + Env: env, + Sys: c.SysProcAttr, + }) + if err != nil { + return err + } + started = true + + // Don't allocate the goroutineErr channel unless there are goroutines to start. + if len(c.goroutine) > 0 { + goroutineErr := make(chan error, 1) + c.goroutineErr = goroutineErr + + type goroutineStatus struct { + running int + firstErr error + } + statusc := make(chan goroutineStatus, 1) + statusc <- goroutineStatus{running: len(c.goroutine)} + for _, fn := range c.goroutine { + go func(fn func() error) { + err := fn() + + status := <-statusc + if status.firstErr == nil { + status.firstErr = err + } + status.running-- + if status.running == 0 { + goroutineErr <- status.firstErr + } else { + statusc <- status + } + }(fn) + } + c.goroutine = nil // Allow the goroutines' closures to be GC'd when they complete. + } + + // If we have anything to do when the command's Context expires, + // start a goroutine to watch for cancellation. + // + // (Even if the command was created by CommandContext, a helper library may + // have explicitly set its Cancel field back to nil, indicating that it should + // be allowed to continue running after cancellation after all.) + if (c.Cancel != nil || c.WaitDelay != 0) && c.ctx != nil && c.ctx.Done() != nil { + resultc := make(chan ctxResult) + c.ctxResult = resultc + go c.watchCtx(resultc) + } + + return nil +} + +// watchCtx watches c.ctx until it is able to send a result to resultc. +// +// If c.ctx is done before a result can be sent, watchCtx calls c.Cancel, +// and/or kills cmd.Process it after c.WaitDelay has elapsed. +// +// watchCtx manipulates c.goroutineErr, so its result must be received before +// c.awaitGoroutines is called. +func (c *Cmd) watchCtx(resultc chan<- ctxResult) { + select { + case resultc <- ctxResult{}: + return + case <-c.ctx.Done(): + } + + var err error + if c.Cancel != nil { + if interruptErr := c.Cancel(); interruptErr == nil { + // We appear to have successfully interrupted the command, so any + // program behavior from this point may be due to ctx even if the + // command exits with code 0. + err = c.ctx.Err() + } else if errors.Is(interruptErr, os.ErrProcessDone) { + // The process already finished: we just didn't notice it yet. + // (Perhaps c.Wait hadn't been called, or perhaps it happened to race with + // c.ctx being canceled.) Don't inject a needless error. + } else { + err = wrappedError{ + prefix: "exec: canceling Cmd", + err: interruptErr, + } + } + } + if c.WaitDelay == 0 { + resultc <- ctxResult{err: err} + return + } + + timer := time.NewTimer(c.WaitDelay) + select { + case resultc <- ctxResult{err: err, timer: timer}: + // c.Process.Wait returned and we've handed the timer off to c.Wait. + // It will take care of goroutine shutdown from here. + return + case <-timer.C: + } + + killed := false + if killErr := c.Process.Kill(); killErr == nil { + // We appear to have killed the process. c.Process.Wait should return a + // non-nil error to c.Wait unless the Kill signal races with a successful + // exit, and if that does happen we shouldn't report a spurious error, + // so don't set err to anything here. + killed = true + } else if !errors.Is(killErr, os.ErrProcessDone) { + err = wrappedError{ + prefix: "exec: killing Cmd", + err: killErr, + } + } + + if c.goroutineErr != nil { + select { + case goroutineErr := <-c.goroutineErr: + // Forward goroutineErr only if we don't have reason to believe it was + // caused by a call to Cancel or Kill above. + if err == nil && !killed { + err = goroutineErr + } + default: + // Close the child process's I/O pipes, in case it abandoned some + // subprocess that inherited them and is still holding them open + // (see https://go.dev/issue/23019). + // + // We close the goroutine pipes only after we have sent any signals we're + // going to send to the process (via Signal or Kill above): if we send + // SIGKILL to the process, we would prefer for it to die of SIGKILL, not + // SIGPIPE. (However, this may still cause any orphaned subprocesses to + // terminate with SIGPIPE.) + closeDescriptors(c.parentIOPipes) + // Wait for the copying goroutines to finish, but report ErrWaitDelay for + // the error: any other error here could result from closing the pipes. + _ = <-c.goroutineErr + if err == nil { + err = ErrWaitDelay + } + } + + // Since we have already received the only result from c.goroutineErr, + // set it to nil to prevent awaitGoroutines from blocking on it. + c.goroutineErr = nil + } + + resultc <- ctxResult{err: err} +} + +// An ExitError reports an unsuccessful exit by a command. +type ExitError struct { + *os.ProcessState + + // Stderr holds a subset of the standard error output from the + // Cmd.Output method if standard error was not otherwise being + // collected. + // + // If the error output is long, Stderr may contain only a prefix + // and suffix of the output, with the middle replaced with + // text about the number of omitted bytes. + // + // Stderr is provided for debugging, for inclusion in error messages. + // Users with other needs should redirect Cmd.Stderr as needed. + Stderr []byte +} + +func (e *ExitError) Error() string { + return e.ProcessState.String() +} + +// Wait waits for the command to exit and waits for any copying to +// stdin or copying from stdout or stderr to complete. +// +// The command must have been started by [Cmd.Start]. +// +// The returned error is nil if the command runs, has no problems +// copying stdin, stdout, and stderr, and exits with a zero exit +// status. +// +// If the command fails to run or doesn't complete successfully, the +// error is of type [*ExitError]. Other error types may be +// returned for I/O problems. +// +// If any of c.Stdin, c.Stdout or c.Stderr are not an [*os.File], Wait also waits +// for the respective I/O loop copying to or from the process to complete. +// +// Wait releases any resources associated with the [Cmd]. +func (c *Cmd) Wait() error { + if c.Process == nil { + return errors.New("exec: not started") + } + if c.ProcessState != nil { + return errors.New("exec: Wait was already called") + } + + state, err := c.Process.Wait() + if err == nil && !state.Success() { + err = &ExitError{ProcessState: state} + } + c.ProcessState = state + + var timer *time.Timer + if c.ctxResult != nil { + watch := <-c.ctxResult + timer = watch.timer + // If c.Process.Wait returned an error, prefer that. + // Otherwise, report any error from the watchCtx goroutine, + // such as a Context cancellation or a WaitDelay overrun. + if err == nil && watch.err != nil { + err = watch.err + } + } + + if goroutineErr := c.awaitGoroutines(timer); err == nil { + // Report an error from the copying goroutines only if the program otherwise + // exited normally on its own. Otherwise, the copying error may be due to the + // abnormal termination. + err = goroutineErr + } + closeDescriptors(c.parentIOPipes) + c.parentIOPipes = nil + + return err +} + +// awaitGoroutines waits for the results of the goroutines copying data to or +// from the command's I/O pipes. +// +// If c.WaitDelay elapses before the goroutines complete, awaitGoroutines +// forcibly closes their pipes and returns ErrWaitDelay. +// +// If timer is non-nil, it must send to timer.C at the end of c.WaitDelay. +func (c *Cmd) awaitGoroutines(timer *time.Timer) error { + defer func() { + if timer != nil { + timer.Stop() + } + c.goroutineErr = nil + }() + + if c.goroutineErr == nil { + return nil // No running goroutines to await. + } + + if timer == nil { + if c.WaitDelay == 0 { + return <-c.goroutineErr + } + + select { + case err := <-c.goroutineErr: + // Avoid the overhead of starting a timer. + return err + default: + } + + // No existing timer was started: either there is no Context associated with + // the command, or c.Process.Wait completed before the Context was done. + timer = time.NewTimer(c.WaitDelay) + } + + select { + case <-timer.C: + closeDescriptors(c.parentIOPipes) + // Wait for the copying goroutines to finish, but ignore any error + // (since it was probably caused by closing the pipes). + _ = <-c.goroutineErr + return ErrWaitDelay + + case err := <-c.goroutineErr: + return err + } +} + +// Output runs the command and returns its standard output. +// Any returned error will usually be of type [*ExitError]. +// If c.Stderr was nil, Output populates [ExitError.Stderr]. +func (c *Cmd) Output() ([]byte, error) { + if c.Stdout != nil { + return nil, errors.New("exec: Stdout already set") + } + var stdout bytes.Buffer + c.Stdout = &stdout + + captureErr := c.Stderr == nil + if captureErr { + c.Stderr = &prefixSuffixSaver{N: 32 << 10} + } + + err := c.Run() + if err != nil && captureErr { + if ee, ok := err.(*ExitError); ok { + ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes() + } + } + return stdout.Bytes(), err +} + +// CombinedOutput runs the command and returns its combined standard +// output and standard error. +func (c *Cmd) CombinedOutput() ([]byte, error) { + if c.Stdout != nil { + return nil, errors.New("exec: Stdout already set") + } + if c.Stderr != nil { + return nil, errors.New("exec: Stderr already set") + } + var b bytes.Buffer + c.Stdout = &b + c.Stderr = &b + err := c.Run() + return b.Bytes(), err +} + +// StdinPipe returns a pipe that will be connected to the command's +// standard input when the command starts. +// The pipe will be closed automatically after [Cmd.Wait] sees the command exit. +// A caller need only call Close to force the pipe to close sooner. +// For example, if the command being run will not exit until standard input +// is closed, the caller must close the pipe. +func (c *Cmd) StdinPipe() (io.WriteCloser, error) { + if c.Stdin != nil { + return nil, errors.New("exec: Stdin already set") + } + if c.Process != nil { + return nil, errors.New("exec: StdinPipe after process started") + } + pr, pw, err := os.Pipe() + if err != nil { + return nil, err + } + c.Stdin = pr + c.childIOFiles = append(c.childIOFiles, pr) + c.parentIOPipes = append(c.parentIOPipes, pw) + return pw, nil +} + +// StdoutPipe returns a pipe that will be connected to the command's +// standard output when the command starts. +// +// [Cmd.Wait] will close the pipe after seeing the command exit, so most callers +// need not close the pipe themselves. It is thus incorrect to call Wait +// before all reads from the pipe have completed. +// For the same reason, it is incorrect to call [Cmd.Run] when using StdoutPipe. +// See the example for idiomatic usage. +func (c *Cmd) StdoutPipe() (io.ReadCloser, error) { + if c.Stdout != nil { + return nil, errors.New("exec: Stdout already set") + } + if c.Process != nil { + return nil, errors.New("exec: StdoutPipe after process started") + } + pr, pw, err := os.Pipe() + if err != nil { + return nil, err + } + c.Stdout = pw + c.childIOFiles = append(c.childIOFiles, pw) + c.parentIOPipes = append(c.parentIOPipes, pr) + return pr, nil +} + +// StderrPipe returns a pipe that will be connected to the command's +// standard error when the command starts. +// +// [Cmd.Wait] will close the pipe after seeing the command exit, so most callers +// need not close the pipe themselves. It is thus incorrect to call Wait +// before all reads from the pipe have completed. +// For the same reason, it is incorrect to use [Cmd.Run] when using StderrPipe. +// See the StdoutPipe example for idiomatic usage. +func (c *Cmd) StderrPipe() (io.ReadCloser, error) { + if c.Stderr != nil { + return nil, errors.New("exec: Stderr already set") + } + if c.Process != nil { + return nil, errors.New("exec: StderrPipe after process started") + } + pr, pw, err := os.Pipe() + if err != nil { + return nil, err + } + c.Stderr = pw + c.childIOFiles = append(c.childIOFiles, pw) + c.parentIOPipes = append(c.parentIOPipes, pr) + return pr, nil +} + +// prefixSuffixSaver is an io.Writer which retains the first N bytes +// and the last N bytes written to it. The Bytes() methods reconstructs +// it with a pretty error message. +type prefixSuffixSaver struct { + N int // max size of prefix or suffix + prefix []byte + suffix []byte // ring buffer once len(suffix) == N + suffixOff int // offset to write into suffix + skipped int64 + + // TODO(bradfitz): we could keep one large []byte and use part of it for + // the prefix, reserve space for the '... Omitting N bytes ...' message, + // then the ring buffer suffix, and just rearrange the ring buffer + // suffix when Bytes() is called, but it doesn't seem worth it for + // now just for error messages. It's only ~64KB anyway. +} + +func (w *prefixSuffixSaver) Write(p []byte) (n int, err error) { + lenp := len(p) + p = w.fill(&w.prefix, p) + + // Only keep the last w.N bytes of suffix data. + if overage := len(p) - w.N; overage > 0 { + p = p[overage:] + w.skipped += int64(overage) + } + p = w.fill(&w.suffix, p) + + // w.suffix is full now if p is non-empty. Overwrite it in a circle. + for len(p) > 0 { // 0, 1, or 2 iterations. + n := copy(w.suffix[w.suffixOff:], p) + p = p[n:] + w.skipped += int64(n) + w.suffixOff += n + if w.suffixOff == w.N { + w.suffixOff = 0 + } + } + return lenp, nil +} + +// fill appends up to len(p) bytes of p to *dst, such that *dst does not +// grow larger than w.N. It returns the un-appended suffix of p. +func (w *prefixSuffixSaver) fill(dst *[]byte, p []byte) (pRemain []byte) { + if remain := w.N - len(*dst); remain > 0 { + add := min(len(p), remain) + *dst = append(*dst, p[:add]...) + p = p[add:] + } + return p +} + +func (w *prefixSuffixSaver) Bytes() []byte { + if w.suffix == nil { + return w.prefix + } + if w.skipped == 0 { + return append(w.prefix, w.suffix...) + } + var buf bytes.Buffer + buf.Grow(len(w.prefix) + len(w.suffix) + 50) + buf.Write(w.prefix) + buf.WriteString("\n... omitting ") + buf.WriteString(strconv.FormatInt(w.skipped, 10)) + buf.WriteString(" bytes ...\n") + buf.Write(w.suffix[w.suffixOff:]) + buf.Write(w.suffix[:w.suffixOff]) + return buf.Bytes() +} + +// environ returns a best-effort copy of the environment in which the command +// would be run as it is currently configured. If an error occurs in computing +// the environment, it is returned alongside the best-effort copy. +func (c *Cmd) environ() ([]string, error) { + var err error + + env := c.Env + if env == nil { + env, err = execenv.Default(c.SysProcAttr) + if err != nil { + env = os.Environ() + // Note that the non-nil err is preserved despite env being overridden. + } + + if c.Dir != "" { + switch runtime.GOOS { + case "windows", "plan9": + // Windows and Plan 9 do not use the PWD variable, so we don't need to + // keep it accurate. + default: + // On POSIX platforms, PWD represents “an absolute pathname of the + // current working directory.” Since we are changing the working + // directory for the command, we should also update PWD to reflect that. + // + // Unfortunately, we didn't always do that, so (as proposed in + // https://go.dev/issue/50599) to avoid unintended collateral damage we + // only implicitly update PWD when Env is nil. That way, we're much + // less likely to override an intentional change to the variable. + if pwd, absErr := filepath.Abs(c.Dir); absErr == nil { + env = append(env, "PWD="+pwd) + } else if err == nil { + err = absErr + } + } + } + } + + env, dedupErr := dedupEnv(env) + if err == nil { + err = dedupErr + } + return addCriticalEnv(env), err +} + +// Environ returns a copy of the environment in which the command would be run +// as it is currently configured. +func (c *Cmd) Environ() []string { + // Intentionally ignore errors: environ returns a best-effort environment no matter what. + env, _ := c.environ() + return env +} + +// dedupEnv returns a copy of env with any duplicates removed, in favor of +// later values. +// Items not of the normal environment "key=value" form are preserved unchanged. +// Except on Plan 9, items containing NUL characters are removed, and +// an error is returned along with the remaining values. +func dedupEnv(env []string) ([]string, error) { + return dedupEnvCase(runtime.GOOS == "windows", runtime.GOOS == "plan9", env) +} + +// dedupEnvCase is dedupEnv with a case option for testing. +// If caseInsensitive is true, the case of keys is ignored. +// If nulOK is false, items containing NUL characters are allowed. +func dedupEnvCase(caseInsensitive, nulOK bool, env []string) ([]string, error) { + // Construct the output in reverse order, to preserve the + // last occurrence of each key. + var err error + out := make([]string, 0, len(env)) + saw := make(map[string]bool, len(env)) + for n := len(env); n > 0; n-- { + kv := env[n-1] + + // Reject NUL in environment variables to prevent security issues (#56284); + // except on Plan 9, which uses NUL as os.PathListSeparator (#56544). + if !nulOK && strings.IndexByte(kv, 0) != -1 { + err = errors.New("exec: environment variable contains NUL") + continue + } + + i := strings.Index(kv, "=") + if i == 0 { + // We observe in practice keys with a single leading "=" on Windows. + // TODO(#49886): Should we consume only the first leading "=" as part + // of the key, or parse through arbitrarily many of them until a non-"="? + i = strings.Index(kv[1:], "=") + 1 + } + if i < 0 { + if kv != "" { + // The entry is not of the form "key=value" (as it is required to be). + // Leave it as-is for now. + // TODO(#52436): should we strip or reject these bogus entries? + out = append(out, kv) + } + continue + } + k := kv[:i] + if caseInsensitive { + k = strings.ToLower(k) + } + if saw[k] { + continue + } + + saw[k] = true + out = append(out, kv) + } + + // Now reverse the slice to restore the original order. + for i := 0; i < len(out)/2; i++ { + j := len(out) - i - 1 + out[i], out[j] = out[j], out[i] + } + + return out, err +} + +// addCriticalEnv adds any critical environment variables that are required +// (or at least almost always required) on the operating system. +// Currently this is only used for Windows. +func addCriticalEnv(env []string) []string { + if runtime.GOOS != "windows" { + return env + } + for _, kv := range env { + k, _, ok := strings.Cut(kv, "=") + if !ok { + continue + } + if strings.EqualFold(k, "SYSTEMROOT") { + // We already have it. + return env + } + } + return append(env, "SYSTEMROOT="+os.Getenv("SYSTEMROOT")) +} + +// ErrDot indicates that a path lookup resolved to an executable +// in the current directory due to ‘.’ being in the path, either +// implicitly or explicitly. See the package documentation for details. +// +// Note that functions in this package do not return ErrDot directly. +// Code should use errors.Is(err, ErrDot), not err == ErrDot, +// to test whether a returned error err is due to this condition. +var ErrDot = errors.New("cannot run executable found relative to current directory") diff --git a/contrib/go/_std_1.22/src/os/exec/exec_plan9.go b/contrib/go/_std_1.23/src/os/exec/exec_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/exec_plan9.go rename to contrib/go/_std_1.23/src/os/exec/exec_plan9.go diff --git a/contrib/go/_std_1.22/src/os/exec/exec_unix.go b/contrib/go/_std_1.23/src/os/exec/exec_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/exec_unix.go rename to contrib/go/_std_1.23/src/os/exec/exec_unix.go diff --git a/contrib/go/_std_1.22/src/os/exec/exec_windows.go b/contrib/go/_std_1.23/src/os/exec/exec_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/exec_windows.go rename to contrib/go/_std_1.23/src/os/exec/exec_windows.go diff --git a/contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_plan9.go b/contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_plan9.go rename to contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_plan9.go diff --git a/contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_unix.go b/contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_unix.go rename to contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_unix.go diff --git a/contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_windows.go b/contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_windows.go rename to contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_windows.go diff --git a/contrib/go/_std_1.23/src/os/exec/internal/fdtest/ya.make b/contrib/go/_std_1.23/src/os/exec/internal/fdtest/ya.make new file mode 100644 index 000000000000..a78ded5d3db2 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec/internal/fdtest/ya.make @@ -0,0 +1,13 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + exists_unix.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + exists_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/os/exec/internal/ya.make b/contrib/go/_std_1.23/src/os/exec/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/internal/ya.make rename to contrib/go/_std_1.23/src/os/exec/internal/ya.make diff --git a/contrib/go/_std_1.22/src/os/exec/lp_plan9.go b/contrib/go/_std_1.23/src/os/exec/lp_plan9.go similarity index 96% rename from contrib/go/_std_1.22/src/os/exec/lp_plan9.go rename to contrib/go/_std_1.23/src/os/exec/lp_plan9.go index dffdbac35f8e..87359b3551d3 100644 --- a/contrib/go/_std_1.22/src/os/exec/lp_plan9.go +++ b/contrib/go/_std_1.23/src/os/exec/lp_plan9.go @@ -34,7 +34,7 @@ func findExecutable(file string) error { // // In older versions of Go, LookPath could return a path relative to the current directory. // As of Go 1.19, LookPath will instead return that path along with an error satisfying -// errors.Is(err, ErrDot). See the package documentation for more details. +// [errors.Is](err, [ErrDot]). See the package documentation for more details. func LookPath(file string) (string, error) { // skip the path lookup for these prefixes skip := []string{"/", "#", "./", "../"} diff --git a/contrib/go/_std_1.22/src/os/exec/lp_unix.go b/contrib/go/_std_1.23/src/os/exec/lp_unix.go similarity index 96% rename from contrib/go/_std_1.22/src/os/exec/lp_unix.go rename to contrib/go/_std_1.23/src/os/exec/lp_unix.go index 37871320786a..8617d45e983e 100644 --- a/contrib/go/_std_1.22/src/os/exec/lp_unix.go +++ b/contrib/go/_std_1.23/src/os/exec/lp_unix.go @@ -48,7 +48,7 @@ func findExecutable(file string) error { // // In older versions of Go, LookPath could return a path relative to the current directory. // As of Go 1.19, LookPath will instead return that path along with an error satisfying -// errors.Is(err, ErrDot). See the package documentation for more details. +// [errors.Is](err, [ErrDot]). See the package documentation for more details. func LookPath(file string) (string, error) { // NOTE(rsc): I wish we could use the Plan 9 behavior here // (only bypass the path if file begins with / or ./ or ../) diff --git a/contrib/go/_std_1.22/src/os/exec/lp_wasm.go b/contrib/go/_std_1.23/src/os/exec/lp_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/lp_wasm.go rename to contrib/go/_std_1.23/src/os/exec/lp_wasm.go diff --git a/contrib/go/_std_1.22/src/os/exec/lp_windows.go b/contrib/go/_std_1.23/src/os/exec/lp_windows.go similarity index 98% rename from contrib/go/_std_1.22/src/os/exec/lp_windows.go rename to contrib/go/_std_1.23/src/os/exec/lp_windows.go index 698a97c40f6f..0e058d41b0c1 100644 --- a/contrib/go/_std_1.22/src/os/exec/lp_windows.go +++ b/contrib/go/_std_1.23/src/os/exec/lp_windows.go @@ -66,7 +66,7 @@ func findExecutable(file string, exts []string) (string, error) { // // In older versions of Go, LookPath could return a path relative to the current directory. // As of Go 1.19, LookPath will instead return that path along with an error satisfying -// errors.Is(err, ErrDot). See the package documentation for more details. +// [errors.Is](err, [ErrDot]). See the package documentation for more details. func LookPath(file string) (string, error) { return lookPath(file, pathExt()) } diff --git a/contrib/go/_std_1.22/src/os/exec/read3.go b/contrib/go/_std_1.23/src/os/exec/read3.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/read3.go rename to contrib/go/_std_1.23/src/os/exec/read3.go diff --git a/contrib/go/_std_1.23/src/os/exec/ya.make b/contrib/go/_std_1.23/src/os/exec/ya.make new file mode 100644 index 000000000000..74b299242e38 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec/ya.make @@ -0,0 +1,17 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + exec.go + exec_unix.go + lp_unix.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + exec.go + exec_windows.go + lp_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/os/exec_linux.go b/contrib/go/_std_1.23/src/os/exec_linux.go new file mode 100644 index 000000000000..b47c6cb19198 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec_linux.go @@ -0,0 +1,13 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "syscall" +) + +func (p *Process) closeHandle() { + syscall.Close(int(p.handle)) +} diff --git a/contrib/go/_std_1.23/src/os/exec_nohandle.go b/contrib/go/_std_1.23/src/os/exec_nohandle.go new file mode 100644 index 000000000000..d06f4091c3eb --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec_nohandle.go @@ -0,0 +1,9 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !linux && !windows + +package os + +func (p *Process) closeHandle() {} diff --git a/contrib/go/_std_1.23/src/os/exec_plan9.go b/contrib/go/_std_1.23/src/os/exec_plan9.go new file mode 100644 index 000000000000..bc7a9cdcbc5f --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec_plan9.go @@ -0,0 +1,158 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "internal/itoa" + "runtime" + "syscall" + "time" +) + +// The only signal values guaranteed to be present in the os package +// on all systems are Interrupt (send the process an interrupt) and +// Kill (force the process to exit). Interrupt is not implemented on +// Windows; using it with [os.Process.Signal] will return an error. +var ( + Interrupt Signal = syscall.Note("interrupt") + Kill Signal = syscall.Note("kill") +) + +func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { + sysattr := &syscall.ProcAttr{ + Dir: attr.Dir, + Env: attr.Env, + Sys: attr.Sys, + } + + sysattr.Files = make([]uintptr, 0, len(attr.Files)) + for _, f := range attr.Files { + sysattr.Files = append(sysattr.Files, f.Fd()) + } + + pid, _, e := syscall.StartProcess(name, argv, sysattr) + if e != nil { + return nil, &PathError{Op: "fork/exec", Path: name, Err: e} + } + + return newPIDProcess(pid), nil +} + +func (p *Process) writeProcFile(file string, data string) error { + f, e := OpenFile("/proc/"+itoa.Itoa(p.Pid)+"/"+file, O_WRONLY, 0) + if e != nil { + return e + } + defer f.Close() + _, e = f.Write([]byte(data)) + return e +} + +func (p *Process) signal(sig Signal) error { + switch p.pidStatus() { + case statusDone: + return ErrProcessDone + case statusReleased: + return syscall.ENOENT + } + + if e := p.writeProcFile("note", sig.String()); e != nil { + return NewSyscallError("signal", e) + } + return nil +} + +func (p *Process) kill() error { + return p.signal(Kill) +} + +func (p *Process) wait() (ps *ProcessState, err error) { + var waitmsg syscall.Waitmsg + + switch p.pidStatus() { + case statusReleased: + return nil, ErrInvalid + } + + err = syscall.WaitProcess(p.Pid, &waitmsg) + if err != nil { + return nil, NewSyscallError("wait", err) + } + + p.pidDeactivate(statusDone) + ps = &ProcessState{ + pid: waitmsg.Pid, + status: &waitmsg, + } + return ps, nil +} + +func (p *Process) release() error { + p.Pid = -1 + + // Just mark the PID unusable. + p.pidDeactivate(statusReleased) + + // no need for a finalizer anymore + runtime.SetFinalizer(p, nil) + return nil +} + +func findProcess(pid int) (p *Process, err error) { + // NOOP for Plan 9. + return newPIDProcess(pid), nil +} + +// ProcessState stores information about a process, as reported by Wait. +type ProcessState struct { + pid int // The process's id. + status *syscall.Waitmsg // System-dependent status info. +} + +// Pid returns the process id of the exited process. +func (p *ProcessState) Pid() int { + return p.pid +} + +func (p *ProcessState) exited() bool { + return p.status.Exited() +} + +func (p *ProcessState) success() bool { + return p.status.ExitStatus() == 0 +} + +func (p *ProcessState) sys() any { + return p.status +} + +func (p *ProcessState) sysUsage() any { + return p.status +} + +func (p *ProcessState) userTime() time.Duration { + return time.Duration(p.status.Time[0]) * time.Millisecond +} + +func (p *ProcessState) systemTime() time.Duration { + return time.Duration(p.status.Time[1]) * time.Millisecond +} + +func (p *ProcessState) String() string { + if p == nil { + return "" + } + return "exit status: " + p.status.Msg +} + +// ExitCode returns the exit code of the exited process, or -1 +// if the process hasn't exited or was terminated by a signal. +func (p *ProcessState) ExitCode() int { + // return -1 if the process hasn't started. + if p == nil { + return -1 + } + return p.status.ExitStatus() +} diff --git a/contrib/go/_std_1.22/src/os/exec_posix.go b/contrib/go/_std_1.23/src/os/exec_posix.go similarity index 91% rename from contrib/go/_std_1.22/src/os/exec_posix.go rename to contrib/go/_std_1.23/src/os/exec_posix.go index 4f9ea08cde51..ff51247d56b7 100644 --- a/contrib/go/_std_1.22/src/os/exec_posix.go +++ b/contrib/go/_std_1.23/src/os/exec_posix.go @@ -35,10 +35,11 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e } } + attrSys, shouldDupPidfd := ensurePidfd(attr.Sys) sysattr := &syscall.ProcAttr{ Dir: attr.Dir, Env: attr.Env, - Sys: attr.Sys, + Sys: attrSys, } if sysattr.Env == nil { sysattr.Env, err = execenv.Default(sysattr.Sys) @@ -60,7 +61,16 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e return nil, &PathError{Op: "fork/exec", Path: name, Err: e} } - return newProcess(pid, h), nil + // For Windows, syscall.StartProcess above already returned a process handle. + if runtime.GOOS != "windows" { + var ok bool + h, ok = getPidfd(sysattr.Sys, shouldDupPidfd) + if !ok { + return newPIDProcess(pid), nil + } + } + + return newHandleProcess(pid, h), nil } func (p *Process) kill() error { diff --git a/contrib/go/_std_1.23/src/os/exec_unix.go b/contrib/go/_std_1.23/src/os/exec_unix.go new file mode 100644 index 000000000000..ba6146ada11b --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec_unix.go @@ -0,0 +1,178 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || (js && wasm) || wasip1 + +package os + +import ( + "errors" + "runtime" + "syscall" + "time" +) + +const ( + // Special values for Process.Pid. + pidUnset = 0 + pidReleased = -1 +) + +func (p *Process) wait() (ps *ProcessState, err error) { + // Which type of Process do we have? + switch p.mode { + case modeHandle: + // pidfd + return p.pidfdWait() + case modePID: + // Regular PID + return p.pidWait() + default: + panic("unreachable") + } +} + +func (p *Process) pidWait() (*ProcessState, error) { + // TODO(go.dev/issue/67642): When there are concurrent Wait calls, one + // may wait on the wrong process if the PID is reused after the + // completes its wait. + // + // Checking for statusDone here would not be a complete fix, as the PID + // could still be waited on and reused prior to blockUntilWaitable. + switch p.pidStatus() { + case statusReleased: + return nil, syscall.EINVAL + } + + // If we can block until Wait4 will succeed immediately, do so. + ready, err := p.blockUntilWaitable() + if err != nil { + return nil, err + } + if ready { + // Mark the process done now, before the call to Wait4, + // so that Process.pidSignal will not send a signal. + p.pidDeactivate(statusDone) + // Acquire a write lock on sigMu to wait for any + // active call to the signal method to complete. + p.sigMu.Lock() + p.sigMu.Unlock() + } + + var ( + status syscall.WaitStatus + rusage syscall.Rusage + pid1 int + e error + ) + for { + pid1, e = syscall.Wait4(p.Pid, &status, 0, &rusage) + if e != syscall.EINTR { + break + } + } + if e != nil { + return nil, NewSyscallError("wait", e) + } + p.pidDeactivate(statusDone) + return &ProcessState{ + pid: pid1, + status: status, + rusage: &rusage, + }, nil +} + +func (p *Process) signal(sig Signal) error { + s, ok := sig.(syscall.Signal) + if !ok { + return errors.New("os: unsupported signal type") + } + + // Which type of Process do we have? + switch p.mode { + case modeHandle: + // pidfd + return p.pidfdSendSignal(s) + case modePID: + // Regular PID + return p.pidSignal(s) + default: + panic("unreachable") + } +} + +func (p *Process) pidSignal(s syscall.Signal) error { + if p.Pid == pidReleased { + return errors.New("os: process already released") + } + if p.Pid == pidUnset { + return errors.New("os: process not initialized") + } + + p.sigMu.RLock() + defer p.sigMu.RUnlock() + + switch p.pidStatus() { + case statusDone: + return ErrProcessDone + case statusReleased: + return errors.New("os: process already released") + } + + return convertESRCH(syscall.Kill(p.Pid, s)) +} + +func convertESRCH(err error) error { + if err == syscall.ESRCH { + return ErrProcessDone + } + return err +} + +func (p *Process) release() error { + // We clear the Pid field only for API compatibility. On Unix, Release + // has always set Pid to -1. Internally, the implementation relies + // solely on statusReleased to determine that the Process is released. + p.Pid = pidReleased + + switch p.mode { + case modeHandle: + // Drop the Process' reference and mark handle unusable for + // future calls. + // + // Ignore the return value: we don't care if this was a no-op + // racing with Wait, or a double Release. + p.handlePersistentRelease(statusReleased) + case modePID: + // Just mark the PID unusable. + p.pidDeactivate(statusReleased) + } + // no need for a finalizer anymore + runtime.SetFinalizer(p, nil) + return nil +} + +func findProcess(pid int) (p *Process, err error) { + h, err := pidfdFind(pid) + if err == ErrProcessDone { + // We can't return an error here since users are not expecting + // it. Instead, return a process with a "done" state already + // and let a subsequent Signal or Wait call catch that. + return newDoneProcess(pid), nil + } else if err != nil { + // Ignore other errors from pidfdFind, as the callers + // do not expect them. Fall back to using the PID. + return newPIDProcess(pid), nil + } + // Use the handle. + return newHandleProcess(pid, h), nil +} + +func (p *ProcessState) userTime() time.Duration { + return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond +} + +func (p *ProcessState) systemTime() time.Duration { + return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond +} diff --git a/contrib/go/_std_1.22/src/os/exec_windows.go b/contrib/go/_std_1.23/src/os/exec_windows.go similarity index 83% rename from contrib/go/_std_1.22/src/os/exec_windows.go rename to contrib/go/_std_1.23/src/os/exec_windows.go index 061a12b10f3d..ab2dae1d7185 100644 --- a/contrib/go/_std_1.22/src/os/exec_windows.go +++ b/contrib/go/_std_1.23/src/os/exec_windows.go @@ -8,13 +8,23 @@ import ( "errors" "internal/syscall/windows" "runtime" - "sync/atomic" "syscall" "time" ) +// Note that Process.mode is always modeHandle because Windows always requires +// a handle. A manually-created Process literal is not valid. + func (p *Process) wait() (ps *ProcessState, err error) { - handle := atomic.LoadUintptr(&p.handle) + handle, status := p.handleTransientAcquire() + switch status { + case statusDone: + return nil, ErrProcessDone + case statusReleased: + return nil, syscall.EINVAL + } + defer p.handleTransientRelease() + s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE) switch s { case syscall.WAIT_OBJECT_0: @@ -34,19 +44,20 @@ func (p *Process) wait() (ps *ProcessState, err error) { if e != nil { return nil, NewSyscallError("GetProcessTimes", e) } - p.setDone() defer p.Release() return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil } func (p *Process) signal(sig Signal) error { - handle := atomic.LoadUintptr(&p.handle) - if handle == uintptr(syscall.InvalidHandle) { - return syscall.EINVAL - } - if p.done() { + handle, status := p.handleTransientAcquire() + switch status { + case statusDone: return ErrProcessDone + case statusReleased: + return syscall.EINVAL } + defer p.handleTransientRelease() + if sig == Kill { var terminationHandle syscall.Handle e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0) @@ -63,19 +74,24 @@ func (p *Process) signal(sig Signal) error { } func (p *Process) release() error { - handle := atomic.SwapUintptr(&p.handle, uintptr(syscall.InvalidHandle)) - if handle == uintptr(syscall.InvalidHandle) { + // Drop the Process' reference and mark handle unusable for + // future calls. + // + // The API on Windows expects EINVAL if Release is called multiple + // times. + if old := p.handlePersistentRelease(statusReleased); old == statusReleased { return syscall.EINVAL } - e := syscall.CloseHandle(syscall.Handle(handle)) - if e != nil { - return NewSyscallError("CloseHandle", e) - } + // no need for a finalizer anymore runtime.SetFinalizer(p, nil) return nil } +func (p *Process) closeHandle() { + syscall.CloseHandle(syscall.Handle(p.handle)) +} + func findProcess(pid int) (p *Process, err error) { const da = syscall.STANDARD_RIGHTS_READ | syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE @@ -83,7 +99,7 @@ func findProcess(pid int) (p *Process, err error) { if e != nil { return nil, NewSyscallError("OpenProcess", e) } - return newProcess(pid, uintptr(h)), nil + return newHandleProcess(pid, uintptr(h)), nil } func init() { diff --git a/contrib/go/_std_1.22/src/os/executable.go b/contrib/go/_std_1.23/src/os/executable.go similarity index 93% rename from contrib/go/_std_1.22/src/os/executable.go rename to contrib/go/_std_1.23/src/os/executable.go index cc3134af1c1e..ae7ec139c368 100644 --- a/contrib/go/_std_1.22/src/os/executable.go +++ b/contrib/go/_std_1.23/src/os/executable.go @@ -9,7 +9,7 @@ package os // pointing to the correct executable. If a symlink was used to start // the process, depending on the operating system, the result might // be the symlink or the path it pointed to. If a stable result is -// needed, path/filepath.EvalSymlinks might help. +// needed, [path/filepath.EvalSymlinks] might help. // // Executable returns an absolute path unless an error occurred. // diff --git a/contrib/go/_std_1.22/src/os/executable_darwin.go b/contrib/go/_std_1.23/src/os/executable_darwin.go similarity index 88% rename from contrib/go/_std_1.22/src/os/executable_darwin.go rename to contrib/go/_std_1.23/src/os/executable_darwin.go index dae9f4ee18ec..2bb50ab3fef4 100644 --- a/contrib/go/_std_1.22/src/os/executable_darwin.go +++ b/contrib/go/_std_1.23/src/os/executable_darwin.go @@ -4,8 +4,12 @@ package os -import "errors" +import ( + "errors" + _ "unsafe" // for linkname +) +//go:linkname executablePath var executablePath string // set by ../runtime/os_darwin.go var initCwd, initCwdErr = Getwd() diff --git a/contrib/go/_std_1.22/src/os/executable_dragonfly.go b/contrib/go/_std_1.23/src/os/executable_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_dragonfly.go rename to contrib/go/_std_1.23/src/os/executable_dragonfly.go diff --git a/contrib/go/_std_1.22/src/os/executable_freebsd.go b/contrib/go/_std_1.23/src/os/executable_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_freebsd.go rename to contrib/go/_std_1.23/src/os/executable_freebsd.go diff --git a/contrib/go/_std_1.22/src/os/executable_path.go b/contrib/go/_std_1.23/src/os/executable_path.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_path.go rename to contrib/go/_std_1.23/src/os/executable_path.go diff --git a/contrib/go/_std_1.22/src/os/executable_plan9.go b/contrib/go/_std_1.23/src/os/executable_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_plan9.go rename to contrib/go/_std_1.23/src/os/executable_plan9.go diff --git a/contrib/go/_std_1.23/src/os/executable_procfs.go b/contrib/go/_std_1.23/src/os/executable_procfs.go new file mode 100644 index 000000000000..6a2cd10be7c4 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/executable_procfs.go @@ -0,0 +1,30 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux || netbsd + +package os + +import ( + "errors" + "internal/stringslite" + "runtime" +) + +func executable() (string, error) { + var procfn string + switch runtime.GOOS { + default: + return "", errors.New("Executable not implemented for " + runtime.GOOS) + case "linux", "android": + procfn = "/proc/self/exe" + case "netbsd": + procfn = "/proc/curproc/exe" + } + path, err := Readlink(procfn) + + // When the executable has been deleted then Readlink returns a + // path appended with " (deleted)". + return stringslite.TrimSuffix(path, " (deleted)"), err +} diff --git a/contrib/go/_std_1.22/src/os/executable_solaris.go b/contrib/go/_std_1.23/src/os/executable_solaris.go similarity index 89% rename from contrib/go/_std_1.22/src/os/executable_solaris.go rename to contrib/go/_std_1.23/src/os/executable_solaris.go index b145980c5656..8ee897f4b0e5 100644 --- a/contrib/go/_std_1.22/src/os/executable_solaris.go +++ b/contrib/go/_std_1.23/src/os/executable_solaris.go @@ -4,8 +4,12 @@ package os -import "syscall" +import ( + "syscall" + _ "unsafe" // for linkname +) +//go:linkname executablePath var executablePath string // set by sysauxv in ../runtime/os3_solaris.go var initCwd, initCwdErr = Getwd() diff --git a/contrib/go/_std_1.22/src/os/executable_sysctl.go b/contrib/go/_std_1.23/src/os/executable_sysctl.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_sysctl.go rename to contrib/go/_std_1.23/src/os/executable_sysctl.go diff --git a/contrib/go/_std_1.22/src/os/executable_wasm.go b/contrib/go/_std_1.23/src/os/executable_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_wasm.go rename to contrib/go/_std_1.23/src/os/executable_wasm.go diff --git a/contrib/go/_std_1.22/src/os/executable_windows.go b/contrib/go/_std_1.23/src/os/executable_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_windows.go rename to contrib/go/_std_1.23/src/os/executable_windows.go diff --git a/contrib/go/_std_1.22/src/os/file.go b/contrib/go/_std_1.23/src/os/file.go similarity index 95% rename from contrib/go/_std_1.22/src/os/file.go rename to contrib/go/_std_1.23/src/os/file.go index 090ffba4dc73..ad869fc4938d 100644 --- a/contrib/go/_std_1.22/src/os/file.go +++ b/contrib/go/_std_1.23/src/os/file.go @@ -6,9 +6,9 @@ // functionality. The design is Unix-like, although the error handling is // Go-like; failing calls return values of type error rather than error numbers. // Often, more information is available within the error. For example, -// if a call that takes a file name fails, such as Open or Stat, the error +// if a call that takes a file name fails, such as [Open] or [Stat], the error // will include the failing file name when printed and will be of type -// *PathError, which may be unpacked for more information. +// [*PathError], which may be unpacked for more information. // // The os interface is intended to be uniform across all operating systems. // Features not generally available appear in the system-specific package syscall. @@ -34,15 +34,19 @@ // } // fmt.Printf("read %d bytes: %q\n", count, data[:count]) // -// Note: The maximum number of concurrent operations on a File may be limited by -// the OS or the system. The number should be high, but exceeding it may degrade -// performance or cause other issues. +// # Concurrency +// +// The methods of [File] correspond to file system operations. All are +// safe for concurrent use. The maximum number of concurrent +// operations on a File may be limited by the OS or the system. The +// number should be high, but exceeding it may degrade performance or +// cause other issues. package os import ( "errors" + "internal/filepathlite" "internal/poll" - "internal/safefilepath" "internal/testlog" "io" "io/fs" @@ -53,6 +57,8 @@ import ( ) // Name returns the name of the file as presented to Open. +// +// It is safe to call Name after [Close]. func (f *File) Name() string { return f.name } // Stdin, Stdout, and Stderr are open Files pointing to the standard input, @@ -279,7 +285,7 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) { return 0, err } r, e := f.seek(offset, whence) - if e == nil && f.dirinfo != nil && r != 0 { + if e == nil && f.dirinfo.Load() != nil && r != 0 { e = syscall.EISDIR } if e != nil { @@ -337,6 +343,11 @@ func Chdir(dir string) error { testlog.Open(dir) // observe likely non-existent directory return &PathError{Op: "chdir", Path: dir, Err: e} } + if runtime.GOOS == "windows" { + getwdCache.Lock() + getwdCache.dir = dir + getwdCache.Unlock() + } if log := testlog.Logger(); log != nil { wd, err := Getwd() if err == nil { @@ -355,7 +366,7 @@ func Open(name string) (*File, error) { } // Create creates or truncates the named file. If the file already exists, -// it is truncated. If the file does not exist, it is created with mode 0666 +// it is truncated. If the file does not exist, it is created with mode 0o666 // (before umask). If successful, methods on the returned File can // be used for I/O; the associated file descriptor has mode O_RDWR. // If there is an error, it will be of type *PathError. @@ -380,6 +391,14 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) { return f, nil } +// openDir opens a file which is assumed to be a directory. As such, it skips +// the syscalls that make the file descriptor non-blocking as these take time +// and will fail on file descriptors for directories. +func openDir(name string) (*File, error) { + testlog.Open(name) + return openDirNolog(name) +} + // lstat is overridden in tests. var lstat = Lstat @@ -583,11 +602,11 @@ func UserHomeDir() (string, error) { // On Unix, the mode's permission bits, ModeSetuid, ModeSetgid, and // ModeSticky are used. // -// On Windows, only the 0200 bit (owner writable) of mode is used; it +// On Windows, only the 0o200 bit (owner writable) of mode is used; it // controls whether the file's read-only attribute is set or cleared. // The other bits are currently unused. For compatibility with Go 1.12 -// and earlier, use a non-zero mode. Use mode 0400 for a read-only -// file and 0600 for a readable+writable file. +// and earlier, use a non-zero mode. Use mode 0o400 for a read-only +// file and 0o600 for a readable+writable file. // // On Plan 9, the mode's permission bits, ModeAppend, ModeExclusive, // and ModeTemporary are used. @@ -747,10 +766,7 @@ func (dir dirFS) join(name string) (string, error) { if dir == "" { return "", errors.New("os: DirFS with empty root") } - if !fs.ValidPath(name) { - return "", ErrInvalid - } - name, err := safefilepath.FromFS(name) + name, err := filepathlite.Localize(name) if err != nil { return "", ErrInvalid } diff --git a/contrib/go/_std_1.22/src/os/file_mutex_plan9.go b/contrib/go/_std_1.23/src/os/file_mutex_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/file_mutex_plan9.go rename to contrib/go/_std_1.23/src/os/file_mutex_plan9.go diff --git a/contrib/go/_std_1.22/src/os/file_open_unix.go b/contrib/go/_std_1.23/src/os/file_open_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/file_open_unix.go rename to contrib/go/_std_1.23/src/os/file_open_unix.go diff --git a/contrib/go/_std_1.22/src/os/file_open_wasip1.go b/contrib/go/_std_1.23/src/os/file_open_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/os/file_open_wasip1.go rename to contrib/go/_std_1.23/src/os/file_open_wasip1.go diff --git a/contrib/go/_std_1.23/src/os/file_plan9.go b/contrib/go/_std_1.23/src/os/file_plan9.go new file mode 100644 index 000000000000..ef277deccce0 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/file_plan9.go @@ -0,0 +1,619 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "internal/bytealg" + "internal/poll" + "internal/stringslite" + "io" + "runtime" + "sync" + "sync/atomic" + "syscall" + "time" +) + +// fixLongPath is a noop on non-Windows platforms. +func fixLongPath(path string) string { + return path +} + +// file is the real representation of *File. +// The extra level of indirection ensures that no clients of os +// can overwrite this data, which could cause the finalizer +// to close the wrong file descriptor. +type file struct { + fdmu poll.FDMutex + fd int + name string + dirinfo atomic.Pointer[dirInfo] // nil unless directory being read + appendMode bool // whether file is opened for appending +} + +// Fd returns the integer Plan 9 file descriptor referencing the open file. +// If f is closed, the file descriptor becomes invalid. +// If f is garbage collected, a finalizer may close the file descriptor, +// making it invalid; see [runtime.SetFinalizer] for more information on when +// a finalizer might be run. On Unix systems this will cause the [File.SetDeadline] +// methods to stop working. +// +// As an alternative, see the f.SyscallConn method. +func (f *File) Fd() uintptr { + if f == nil { + return ^(uintptr(0)) + } + return uintptr(f.fd) +} + +// NewFile returns a new File with the given file descriptor and +// name. The returned value will be nil if fd is not a valid file +// descriptor. +func NewFile(fd uintptr, name string) *File { + fdi := int(fd) + if fdi < 0 { + return nil + } + f := &File{&file{fd: fdi, name: name}} + runtime.SetFinalizer(f.file, (*file).close) + return f +} + +// Auxiliary information if the File describes a directory +type dirInfo struct { + mu sync.Mutex + buf [syscall.STATMAX]byte // buffer for directory I/O + nbuf int // length of buf; return value from Read + bufp int // location of next record in buf. +} + +func epipecheck(file *File, e error) { +} + +// DevNull is the name of the operating system's “null device.” +// On Unix-like systems, it is "/dev/null"; on Windows, "NUL". +const DevNull = "/dev/null" + +// syscallMode returns the syscall-specific mode bits from Go's portable mode bits. +func syscallMode(i FileMode) (o uint32) { + o |= uint32(i.Perm()) + if i&ModeAppend != 0 { + o |= syscall.DMAPPEND + } + if i&ModeExclusive != 0 { + o |= syscall.DMEXCL + } + if i&ModeTemporary != 0 { + o |= syscall.DMTMP + } + return +} + +// openFileNolog is the Plan 9 implementation of OpenFile. +func openFileNolog(name string, flag int, perm FileMode) (*File, error) { + var ( + fd int + e error + create bool + excl bool + trunc bool + append bool + ) + + if flag&O_CREATE == O_CREATE { + flag = flag & ^O_CREATE + create = true + } + if flag&O_EXCL == O_EXCL { + excl = true + } + if flag&O_TRUNC == O_TRUNC { + trunc = true + } + // O_APPEND is emulated on Plan 9 + if flag&O_APPEND == O_APPEND { + flag = flag &^ O_APPEND + append = true + } + + if (create && trunc) || excl { + fd, e = syscall.Create(name, flag, syscallMode(perm)) + } else { + fd, e = syscall.Open(name, flag) + if IsNotExist(e) && create { + fd, e = syscall.Create(name, flag, syscallMode(perm)) + if e != nil { + return nil, &PathError{Op: "create", Path: name, Err: e} + } + } + } + + if e != nil { + return nil, &PathError{Op: "open", Path: name, Err: e} + } + + if append { + if _, e = syscall.Seek(fd, 0, io.SeekEnd); e != nil { + return nil, &PathError{Op: "seek", Path: name, Err: e} + } + } + + return NewFile(uintptr(fd), name), nil +} + +func openDirNolog(name string) (*File, error) { + return openFileNolog(name, O_RDONLY, 0) +} + +// Close closes the File, rendering it unusable for I/O. +// On files that support SetDeadline, any pending I/O operations will +// be canceled and return immediately with an ErrClosed error. +// Close will return an error if it has already been called. +func (f *File) Close() error { + if f == nil { + return ErrInvalid + } + return f.file.close() +} + +func (file *file) close() error { + if !file.fdmu.IncrefAndClose() { + return &PathError{Op: "close", Path: file.name, Err: ErrClosed} + } + + // At this point we should cancel any pending I/O. + // How do we do that on Plan 9? + + err := file.decref() + + // no need for a finalizer anymore + runtime.SetFinalizer(file, nil) + return err +} + +// destroy actually closes the descriptor. This is called when +// there are no remaining references, by the decref, readUnlock, +// and writeUnlock methods. +func (file *file) destroy() error { + var err error + if e := syscall.Close(file.fd); e != nil { + err = &PathError{Op: "close", Path: file.name, Err: e} + } + return err +} + +// Stat returns the FileInfo structure describing file. +// If there is an error, it will be of type *PathError. +func (f *File) Stat() (FileInfo, error) { + if f == nil { + return nil, ErrInvalid + } + d, err := dirstat(f) + if err != nil { + return nil, err + } + return fileInfoFromStat(d), nil +} + +// Truncate changes the size of the file. +// It does not change the I/O offset. +// If there is an error, it will be of type *PathError. +func (f *File) Truncate(size int64) error { + if f == nil { + return ErrInvalid + } + + var d syscall.Dir + d.Null() + d.Length = size + + var buf [syscall.STATFIXLEN]byte + n, err := d.Marshal(buf[:]) + if err != nil { + return &PathError{Op: "truncate", Path: f.name, Err: err} + } + + if err := f.incref("truncate"); err != nil { + return err + } + defer f.decref() + + if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { + return &PathError{Op: "truncate", Path: f.name, Err: err} + } + return nil +} + +const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm) + +func (f *File) chmod(mode FileMode) error { + if f == nil { + return ErrInvalid + } + var d syscall.Dir + + odir, e := dirstat(f) + if e != nil { + return &PathError{Op: "chmod", Path: f.name, Err: e} + } + d.Null() + d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask + + var buf [syscall.STATFIXLEN]byte + n, err := d.Marshal(buf[:]) + if err != nil { + return &PathError{Op: "chmod", Path: f.name, Err: err} + } + + if err := f.incref("chmod"); err != nil { + return err + } + defer f.decref() + + if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { + return &PathError{Op: "chmod", Path: f.name, Err: err} + } + return nil +} + +// Sync commits the current contents of the file to stable storage. +// Typically, this means flushing the file system's in-memory copy +// of recently written data to disk. +func (f *File) Sync() error { + if f == nil { + return ErrInvalid + } + var d syscall.Dir + d.Null() + + var buf [syscall.STATFIXLEN]byte + n, err := d.Marshal(buf[:]) + if err != nil { + return &PathError{Op: "sync", Path: f.name, Err: err} + } + + if err := f.incref("sync"); err != nil { + return err + } + defer f.decref() + + if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { + return &PathError{Op: "sync", Path: f.name, Err: err} + } + return nil +} + +// read reads up to len(b) bytes from the File. +// It returns the number of bytes read and an error, if any. +func (f *File) read(b []byte) (n int, err error) { + if err := f.readLock(); err != nil { + return 0, err + } + defer f.readUnlock() + n, e := fixCount(syscall.Read(f.fd, b)) + if n == 0 && len(b) > 0 && e == nil { + return 0, io.EOF + } + return n, e +} + +// pread reads len(b) bytes from the File starting at byte offset off. +// It returns the number of bytes read and the error, if any. +// EOF is signaled by a zero count with err set to nil. +func (f *File) pread(b []byte, off int64) (n int, err error) { + if err := f.readLock(); err != nil { + return 0, err + } + defer f.readUnlock() + n, e := fixCount(syscall.Pread(f.fd, b, off)) + if n == 0 && len(b) > 0 && e == nil { + return 0, io.EOF + } + return n, e +} + +// write writes len(b) bytes to the File. +// It returns the number of bytes written and an error, if any. +// Since Plan 9 preserves message boundaries, never allow +// a zero-byte write. +func (f *File) write(b []byte) (n int, err error) { + if err := f.writeLock(); err != nil { + return 0, err + } + defer f.writeUnlock() + if len(b) == 0 { + return 0, nil + } + return fixCount(syscall.Write(f.fd, b)) +} + +// pwrite writes len(b) bytes to the File starting at byte offset off. +// It returns the number of bytes written and an error, if any. +// Since Plan 9 preserves message boundaries, never allow +// a zero-byte write. +func (f *File) pwrite(b []byte, off int64) (n int, err error) { + if err := f.writeLock(); err != nil { + return 0, err + } + defer f.writeUnlock() + if len(b) == 0 { + return 0, nil + } + return fixCount(syscall.Pwrite(f.fd, b, off)) +} + +// seek sets the offset for the next Read or Write on file to offset, interpreted +// according to whence: 0 means relative to the origin of the file, 1 means +// relative to the current offset, and 2 means relative to the end. +// It returns the new offset and an error, if any. +func (f *File) seek(offset int64, whence int) (ret int64, err error) { + if err := f.incref(""); err != nil { + return 0, err + } + defer f.decref() + // Free cached dirinfo, so we allocate a new one if we + // access this file as a directory again. See #35767 and #37161. + f.dirinfo.Store(nil) + return syscall.Seek(f.fd, offset, whence) +} + +// Truncate changes the size of the named file. +// If the file is a symbolic link, it changes the size of the link's target. +// If there is an error, it will be of type *PathError. +func Truncate(name string, size int64) error { + var d syscall.Dir + + d.Null() + d.Length = size + + var buf [syscall.STATFIXLEN]byte + n, err := d.Marshal(buf[:]) + if err != nil { + return &PathError{Op: "truncate", Path: name, Err: err} + } + if err = syscall.Wstat(name, buf[:n]); err != nil { + return &PathError{Op: "truncate", Path: name, Err: err} + } + return nil +} + +// Remove removes the named file or directory. +// If there is an error, it will be of type *PathError. +func Remove(name string) error { + if e := syscall.Remove(name); e != nil { + return &PathError{Op: "remove", Path: name, Err: e} + } + return nil +} + +func rename(oldname, newname string) error { + dirname := oldname[:bytealg.LastIndexByteString(oldname, '/')+1] + if stringslite.HasPrefix(newname, dirname) { + newname = newname[len(dirname):] + } else { + return &LinkError{"rename", oldname, newname, ErrInvalid} + } + + // If newname still contains slashes after removing the oldname + // prefix, the rename is cross-directory and must be rejected. + if bytealg.LastIndexByteString(newname, '/') >= 0 { + return &LinkError{"rename", oldname, newname, ErrInvalid} + } + + var d syscall.Dir + + d.Null() + d.Name = newname + + buf := make([]byte, syscall.STATFIXLEN+len(d.Name)) + n, err := d.Marshal(buf[:]) + if err != nil { + return &LinkError{"rename", oldname, newname, err} + } + + // If newname already exists and is not a directory, rename replaces it. + f, err := Stat(dirname + newname) + if err == nil && !f.IsDir() { + Remove(dirname + newname) + } + + if err = syscall.Wstat(oldname, buf[:n]); err != nil { + return &LinkError{"rename", oldname, newname, err} + } + return nil +} + +// See docs in file.go:Chmod. +func chmod(name string, mode FileMode) error { + var d syscall.Dir + + odir, e := dirstat(name) + if e != nil { + return &PathError{Op: "chmod", Path: name, Err: e} + } + d.Null() + d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask + + var buf [syscall.STATFIXLEN]byte + n, err := d.Marshal(buf[:]) + if err != nil { + return &PathError{Op: "chmod", Path: name, Err: err} + } + if err = syscall.Wstat(name, buf[:n]); err != nil { + return &PathError{Op: "chmod", Path: name, Err: err} + } + return nil +} + +// Chtimes changes the access and modification times of the named +// file, similar to the Unix utime() or utimes() functions. +// A zero time.Time value will leave the corresponding file time unchanged. +// +// The underlying filesystem may truncate or round the values to a +// less precise time unit. +// If there is an error, it will be of type *PathError. +func Chtimes(name string, atime time.Time, mtime time.Time) error { + var d syscall.Dir + + d.Null() + d.Atime = uint32(atime.Unix()) + d.Mtime = uint32(mtime.Unix()) + if atime.IsZero() { + d.Atime = 0xFFFFFFFF + } + if mtime.IsZero() { + d.Mtime = 0xFFFFFFFF + } + + var buf [syscall.STATFIXLEN]byte + n, err := d.Marshal(buf[:]) + if err != nil { + return &PathError{Op: "chtimes", Path: name, Err: err} + } + if err = syscall.Wstat(name, buf[:n]); err != nil { + return &PathError{Op: "chtimes", Path: name, Err: err} + } + return nil +} + +// Pipe returns a connected pair of Files; reads from r return bytes +// written to w. It returns the files and an error, if any. +func Pipe() (r *File, w *File, err error) { + var p [2]int + + if e := syscall.Pipe(p[0:]); e != nil { + return nil, nil, NewSyscallError("pipe", e) + } + + return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil +} + +// not supported on Plan 9 + +// Link creates newname as a hard link to the oldname file. +// If there is an error, it will be of type *LinkError. +func Link(oldname, newname string) error { + return &LinkError{"link", oldname, newname, syscall.EPLAN9} +} + +// Symlink creates newname as a symbolic link to oldname. +// On Windows, a symlink to a non-existent oldname creates a file symlink; +// if oldname is later created as a directory the symlink will not work. +// If there is an error, it will be of type *LinkError. +func Symlink(oldname, newname string) error { + return &LinkError{"symlink", oldname, newname, syscall.EPLAN9} +} + +func readlink(name string) (string, error) { + return "", &PathError{Op: "readlink", Path: name, Err: syscall.EPLAN9} +} + +// Chown changes the numeric uid and gid of the named file. +// If the file is a symbolic link, it changes the uid and gid of the link's target. +// A uid or gid of -1 means to not change that value. +// If there is an error, it will be of type *PathError. +// +// On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or +// EPLAN9 error, wrapped in *PathError. +func Chown(name string, uid, gid int) error { + return &PathError{Op: "chown", Path: name, Err: syscall.EPLAN9} +} + +// Lchown changes the numeric uid and gid of the named file. +// If the file is a symbolic link, it changes the uid and gid of the link itself. +// If there is an error, it will be of type *PathError. +func Lchown(name string, uid, gid int) error { + return &PathError{Op: "lchown", Path: name, Err: syscall.EPLAN9} +} + +// Chown changes the numeric uid and gid of the named file. +// If there is an error, it will be of type *PathError. +func (f *File) Chown(uid, gid int) error { + if f == nil { + return ErrInvalid + } + return &PathError{Op: "chown", Path: f.name, Err: syscall.EPLAN9} +} + +func tempDir() string { + dir := Getenv("TMPDIR") + if dir == "" { + dir = "/tmp" + } + return dir +} + +// Chdir changes the current working directory to the file, +// which must be a directory. +// If there is an error, it will be of type *PathError. +func (f *File) Chdir() error { + if err := f.incref("chdir"); err != nil { + return err + } + defer f.decref() + if e := syscall.Fchdir(f.fd); e != nil { + return &PathError{Op: "chdir", Path: f.name, Err: e} + } + return nil +} + +// setDeadline sets the read and write deadline. +func (f *File) setDeadline(time.Time) error { + if err := f.checkValid("SetDeadline"); err != nil { + return err + } + return poll.ErrNoDeadline +} + +// setReadDeadline sets the read deadline. +func (f *File) setReadDeadline(time.Time) error { + if err := f.checkValid("SetReadDeadline"); err != nil { + return err + } + return poll.ErrNoDeadline +} + +// setWriteDeadline sets the write deadline. +func (f *File) setWriteDeadline(time.Time) error { + if err := f.checkValid("SetWriteDeadline"); err != nil { + return err + } + return poll.ErrNoDeadline +} + +// checkValid checks whether f is valid for use, but does not prepare +// to actually use it. If f is not ready checkValid returns an appropriate +// error, perhaps incorporating the operation name op. +func (f *File) checkValid(op string) error { + if f == nil { + return ErrInvalid + } + if err := f.incref(op); err != nil { + return err + } + return f.decref() +} + +type rawConn struct{} + +func (c *rawConn) Control(f func(uintptr)) error { + return syscall.EPLAN9 +} + +func (c *rawConn) Read(f func(uintptr) bool) error { + return syscall.EPLAN9 +} + +func (c *rawConn) Write(f func(uintptr) bool) error { + return syscall.EPLAN9 +} + +func newRawConn(file *File) (*rawConn, error) { + return nil, syscall.EPLAN9 +} + +func ignoringEINTR(fn func() error) error { + return fn() +} diff --git a/contrib/go/_std_1.22/src/os/file_posix.go b/contrib/go/_std_1.23/src/os/file_posix.go similarity index 88% rename from contrib/go/_std_1.22/src/os/file_posix.go rename to contrib/go/_std_1.23/src/os/file_posix.go index 569265775337..8ff0ada46290 100644 --- a/contrib/go/_std_1.22/src/os/file_posix.go +++ b/contrib/go/_std_1.23/src/os/file_posix.go @@ -12,9 +12,9 @@ import ( "time" ) -// Close closes the File, rendering it unusable for I/O. -// On files that support SetDeadline, any pending I/O operations will -// be canceled and return immediately with an ErrClosed error. +// Close closes the [File], rendering it unusable for I/O. +// On files that support [File.SetDeadline], any pending I/O operations will +// be canceled and return immediately with an [ErrClosed] error. // Close will return an error if it has already been called. func (f *File) Close() error { if f == nil { @@ -98,9 +98,9 @@ func (f *File) chmod(mode FileMode) error { // Chown changes the numeric uid and gid of the named file. // If the file is a symbolic link, it changes the uid and gid of the link's target. // A uid or gid of -1 means to not change that value. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. // -// On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or +// On Windows or Plan 9, Chown always returns the [syscall.EWINDOWS] or // EPLAN9 error, wrapped in *PathError. func Chown(name string, uid, gid int) error { e := ignoringEINTR(func() error { @@ -114,9 +114,9 @@ func Chown(name string, uid, gid int) error { // Lchown changes the numeric uid and gid of the named file. // If the file is a symbolic link, it changes the uid and gid of the link itself. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. // -// On Windows, it always returns the syscall.EWINDOWS error, wrapped +// On Windows, it always returns the [syscall.EWINDOWS] error, wrapped // in *PathError. func Lchown(name string, uid, gid int) error { e := ignoringEINTR(func() error { @@ -129,9 +129,9 @@ func Lchown(name string, uid, gid int) error { } // Chown changes the numeric uid and gid of the named file. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. // -// On Windows, it always returns the syscall.EWINDOWS error, wrapped +// On Windows, it always returns the [syscall.EWINDOWS] error, wrapped // in *PathError. func (f *File) Chown(uid, gid int) error { if err := f.checkValid("chown"); err != nil { @@ -145,7 +145,7 @@ func (f *File) Chown(uid, gid int) error { // Truncate changes the size of the file. // It does not change the I/O offset. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. func (f *File) Truncate(size int64) error { if err := f.checkValid("truncate"); err != nil { return err @@ -171,11 +171,11 @@ func (f *File) Sync() error { // Chtimes changes the access and modification times of the named // file, similar to the Unix utime() or utimes() functions. -// A zero time.Time value will leave the corresponding file time unchanged. +// A zero [time.Time] value will leave the corresponding file time unchanged. // // The underlying filesystem may truncate or round the values to a // less precise time unit. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. func Chtimes(name string, atime time.Time, mtime time.Time) error { var utimes [2]syscall.Timespec set := func(i int, t time.Time) { @@ -195,7 +195,7 @@ func Chtimes(name string, atime time.Time, mtime time.Time) error { // Chdir changes the current working directory to the file, // which must be a directory. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. func (f *File) Chdir() error { if err := f.checkValid("chdir"); err != nil { return err diff --git a/contrib/go/_std_1.23/src/os/file_unix.go b/contrib/go/_std_1.23/src/os/file_unix.go new file mode 100644 index 000000000000..37bfaa1a72df --- /dev/null +++ b/contrib/go/_std_1.23/src/os/file_unix.go @@ -0,0 +1,512 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || (js && wasm) || wasip1 + +package os + +import ( + "internal/poll" + "internal/syscall/unix" + "io/fs" + "runtime" + "sync/atomic" + "syscall" + _ "unsafe" // for go:linkname +) + +const _UTIME_OMIT = unix.UTIME_OMIT + +// fixLongPath is a noop on non-Windows platforms. +func fixLongPath(path string) string { + return path +} + +func rename(oldname, newname string) error { + fi, err := Lstat(newname) + if err == nil && fi.IsDir() { + // There are two independent errors this function can return: + // one for a bad oldname, and one for a bad newname. + // At this point we've determined the newname is bad. + // But just in case oldname is also bad, prioritize returning + // the oldname error because that's what we did historically. + // However, if the old name and new name are not the same, yet + // they refer to the same file, it implies a case-only + // rename on a case-insensitive filesystem, which is ok. + if ofi, err := Lstat(oldname); err != nil { + if pe, ok := err.(*PathError); ok { + err = pe.Err + } + return &LinkError{"rename", oldname, newname, err} + } else if newname == oldname || !SameFile(fi, ofi) { + return &LinkError{"rename", oldname, newname, syscall.EEXIST} + } + } + err = ignoringEINTR(func() error { + return syscall.Rename(oldname, newname) + }) + if err != nil { + return &LinkError{"rename", oldname, newname, err} + } + return nil +} + +// file is the real representation of *File. +// The extra level of indirection ensures that no clients of os +// can overwrite this data, which could cause the finalizer +// to close the wrong file descriptor. +type file struct { + pfd poll.FD + name string + dirinfo atomic.Pointer[dirInfo] // nil unless directory being read + nonblock bool // whether we set nonblocking mode + stdoutOrErr bool // whether this is stdout or stderr + appendMode bool // whether file is opened for appending +} + +// Fd returns the integer Unix file descriptor referencing the open file. +// If f is closed, the file descriptor becomes invalid. +// If f is garbage collected, a finalizer may close the file descriptor, +// making it invalid; see [runtime.SetFinalizer] for more information on when +// a finalizer might be run. On Unix systems this will cause the [File.SetDeadline] +// methods to stop working. +// Because file descriptors can be reused, the returned file descriptor may +// only be closed through the [File.Close] method of f, or by its finalizer during +// garbage collection. Otherwise, during garbage collection the finalizer +// may close an unrelated file descriptor with the same (reused) number. +// +// As an alternative, see the f.SyscallConn method. +func (f *File) Fd() uintptr { + if f == nil { + return ^(uintptr(0)) + } + + // If we put the file descriptor into nonblocking mode, + // then set it to blocking mode before we return it, + // because historically we have always returned a descriptor + // opened in blocking mode. The File will continue to work, + // but any blocking operation will tie up a thread. + if f.nonblock { + f.pfd.SetBlocking() + } + + return uintptr(f.pfd.Sysfd) +} + +// NewFile returns a new File with the given file descriptor and +// name. The returned value will be nil if fd is not a valid file +// descriptor. On Unix systems, if the file descriptor is in +// non-blocking mode, NewFile will attempt to return a pollable File +// (one for which the SetDeadline methods work). +// +// After passing it to NewFile, fd may become invalid under the same +// conditions described in the comments of the Fd method, and the same +// constraints apply. +func NewFile(fd uintptr, name string) *File { + fdi := int(fd) + if fdi < 0 { + return nil + } + + flags, err := unix.Fcntl(fdi, syscall.F_GETFL, 0) + if err != nil { + flags = 0 + } + f := newFile(fdi, name, kindNewFile, unix.HasNonblockFlag(flags)) + f.appendMode = flags&syscall.O_APPEND != 0 + return f +} + +// net_newUnixFile is a hidden entry point called by net.conn.File. +// This is used so that a nonblocking network connection will become +// blocking if code calls the Fd method. We don't want that for direct +// calls to NewFile: passing a nonblocking descriptor to NewFile should +// remain nonblocking if you get it back using Fd. But for net.conn.File +// the call to NewFile is hidden from the user. Historically in that case +// the Fd method has returned a blocking descriptor, and we want to +// retain that behavior because existing code expects it and depends on it. +// +//go:linkname net_newUnixFile net.newUnixFile +func net_newUnixFile(fd int, name string) *File { + if fd < 0 { + panic("invalid FD") + } + + return newFile(fd, name, kindSock, true) +} + +// newFileKind describes the kind of file to newFile. +type newFileKind int + +const ( + // kindNewFile means that the descriptor was passed to us via NewFile. + kindNewFile newFileKind = iota + // kindOpenFile means that the descriptor was opened using + // Open, Create, or OpenFile. + kindOpenFile + // kindPipe means that the descriptor was opened using Pipe. + kindPipe + // kindSock means that the descriptor is a network file descriptor + // that was created from net package and was opened using net_newUnixFile. + kindSock + // kindNoPoll means that we should not put the descriptor into + // non-blocking mode, because we know it is not a pipe or FIFO. + // Used by openDirAt and openDirNolog for directories. + kindNoPoll +) + +// newFile is like NewFile, but if called from OpenFile or Pipe +// (as passed in the kind parameter) it tries to add the file to +// the runtime poller. +func newFile(fd int, name string, kind newFileKind, nonBlocking bool) *File { + f := &File{&file{ + pfd: poll.FD{ + Sysfd: fd, + IsStream: true, + ZeroReadIsEOF: true, + }, + name: name, + stdoutOrErr: fd == 1 || fd == 2, + }} + + pollable := kind == kindOpenFile || kind == kindPipe || kind == kindSock || nonBlocking + + // Things like regular files and FIFOs in kqueue on *BSD/Darwin + // may not work properly (or accurately according to its manual). + // As a result, we should avoid adding those to the kqueue-based + // netpoller. Check out #19093, #24164, and #66239 for more contexts. + // + // If the fd was passed to us via any path other than OpenFile, + // we assume those callers know what they were doing, so we won't + // perform this check and allow it to be added to the kqueue. + if kind == kindOpenFile { + switch runtime.GOOS { + case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd": + var st syscall.Stat_t + err := ignoringEINTR(func() error { + return syscall.Fstat(fd, &st) + }) + typ := st.Mode & syscall.S_IFMT + // Don't try to use kqueue with regular files on *BSDs. + // On FreeBSD a regular file is always + // reported as ready for writing. + // On Dragonfly, NetBSD and OpenBSD the fd is signaled + // only once as ready (both read and write). + // Issue 19093. + // Also don't add directories to the netpoller. + if err == nil && (typ == syscall.S_IFREG || typ == syscall.S_IFDIR) { + pollable = false + } + + // In addition to the behavior described above for regular files, + // on Darwin, kqueue does not work properly with fifos: + // closing the last writer does not cause a kqueue event + // for any readers. See issue #24164. + if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && typ == syscall.S_IFIFO { + pollable = false + } + } + } + + clearNonBlock := false + if pollable { + // The descriptor is already in non-blocking mode. + // We only set f.nonblock if we put the file into + // non-blocking mode. + if nonBlocking { + // See the comments on net_newUnixFile. + if kind == kindSock { + f.nonblock = true // tell Fd to return blocking descriptor + } + } else if err := syscall.SetNonblock(fd, true); err == nil { + f.nonblock = true + clearNonBlock = true + } else { + pollable = false + } + } + + // An error here indicates a failure to register + // with the netpoll system. That can happen for + // a file descriptor that is not supported by + // epoll/kqueue; for example, disk files on + // Linux systems. We assume that any real error + // will show up in later I/O. + // We do restore the blocking behavior if it was set by us. + if pollErr := f.pfd.Init("file", pollable); pollErr != nil && clearNonBlock { + if err := syscall.SetNonblock(fd, false); err == nil { + f.nonblock = false + } + } + + runtime.SetFinalizer(f.file, (*file).close) + return f +} + +func sigpipe() // implemented in package runtime + +// epipecheck raises SIGPIPE if we get an EPIPE error on standard +// output or standard error. See the SIGPIPE docs in os/signal, and +// issue 11845. +func epipecheck(file *File, e error) { + if e == syscall.EPIPE && file.stdoutOrErr { + sigpipe() + } +} + +// DevNull is the name of the operating system's “null device.” +// On Unix-like systems, it is "/dev/null"; on Windows, "NUL". +const DevNull = "/dev/null" + +// openFileNolog is the Unix implementation of OpenFile. +// Changes here should be reflected in openDirAt and openDirNolog, if relevant. +func openFileNolog(name string, flag int, perm FileMode) (*File, error) { + setSticky := false + if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 { + if _, err := Stat(name); IsNotExist(err) { + setSticky = true + } + } + + var ( + r int + s poll.SysFile + e error + ) + // We have to check EINTR here, per issues 11180 and 39237. + ignoringEINTR(func() error { + r, s, e = open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) + return e + }) + if e != nil { + return nil, &PathError{Op: "open", Path: name, Err: e} + } + + // open(2) itself won't handle the sticky bit on *BSD and Solaris + if setSticky { + setStickyBit(name) + } + + // There's a race here with fork/exec, which we are + // content to live with. See ../syscall/exec_unix.go. + if !supportsCloseOnExec { + syscall.CloseOnExec(r) + } + + f := newFile(r, name, kindOpenFile, unix.HasNonblockFlag(flag)) + f.pfd.SysFile = s + return f, nil +} + +func openDirNolog(name string) (*File, error) { + var ( + r int + s poll.SysFile + e error + ) + ignoringEINTR(func() error { + r, s, e = open(name, O_RDONLY|syscall.O_CLOEXEC, 0) + return e + }) + if e != nil { + return nil, &PathError{Op: "open", Path: name, Err: e} + } + + if !supportsCloseOnExec { + syscall.CloseOnExec(r) + } + + f := newFile(r, name, kindNoPoll, false) + f.pfd.SysFile = s + return f, nil +} + +func (file *file) close() error { + if file == nil { + return syscall.EINVAL + } + if info := file.dirinfo.Swap(nil); info != nil { + info.close() + } + var err error + if e := file.pfd.Close(); e != nil { + if e == poll.ErrFileClosing { + e = ErrClosed + } + err = &PathError{Op: "close", Path: file.name, Err: e} + } + + // no need for a finalizer anymore + runtime.SetFinalizer(file, nil) + return err +} + +// seek sets the offset for the next Read or Write on file to offset, interpreted +// according to whence: 0 means relative to the origin of the file, 1 means +// relative to the current offset, and 2 means relative to the end. +// It returns the new offset and an error, if any. +func (f *File) seek(offset int64, whence int) (ret int64, err error) { + if info := f.dirinfo.Swap(nil); info != nil { + // Free cached dirinfo, so we allocate a new one if we + // access this file as a directory again. See #35767 and #37161. + info.close() + } + ret, err = f.pfd.Seek(offset, whence) + runtime.KeepAlive(f) + return ret, err +} + +// Truncate changes the size of the named file. +// If the file is a symbolic link, it changes the size of the link's target. +// If there is an error, it will be of type *PathError. +func Truncate(name string, size int64) error { + e := ignoringEINTR(func() error { + return syscall.Truncate(name, size) + }) + if e != nil { + return &PathError{Op: "truncate", Path: name, Err: e} + } + return nil +} + +// Remove removes the named file or (empty) directory. +// If there is an error, it will be of type *PathError. +func Remove(name string) error { + // System call interface forces us to know + // whether name is a file or directory. + // Try both: it is cheaper on average than + // doing a Stat plus the right one. + e := ignoringEINTR(func() error { + return syscall.Unlink(name) + }) + if e == nil { + return nil + } + e1 := ignoringEINTR(func() error { + return syscall.Rmdir(name) + }) + if e1 == nil { + return nil + } + + // Both failed: figure out which error to return. + // OS X and Linux differ on whether unlink(dir) + // returns EISDIR, so can't use that. However, + // both agree that rmdir(file) returns ENOTDIR, + // so we can use that to decide which error is real. + // Rmdir might also return ENOTDIR if given a bad + // file path, like /etc/passwd/foo, but in that case, + // both errors will be ENOTDIR, so it's okay to + // use the error from unlink. + if e1 != syscall.ENOTDIR { + e = e1 + } + return &PathError{Op: "remove", Path: name, Err: e} +} + +func tempDir() string { + dir := Getenv("TMPDIR") + if dir == "" { + if runtime.GOOS == "android" { + dir = "/data/local/tmp" + } else { + dir = "/tmp" + } + } + return dir +} + +// Link creates newname as a hard link to the oldname file. +// If there is an error, it will be of type *LinkError. +func Link(oldname, newname string) error { + e := ignoringEINTR(func() error { + return syscall.Link(oldname, newname) + }) + if e != nil { + return &LinkError{"link", oldname, newname, e} + } + return nil +} + +// Symlink creates newname as a symbolic link to oldname. +// On Windows, a symlink to a non-existent oldname creates a file symlink; +// if oldname is later created as a directory the symlink will not work. +// If there is an error, it will be of type *LinkError. +func Symlink(oldname, newname string) error { + e := ignoringEINTR(func() error { + return syscall.Symlink(oldname, newname) + }) + if e != nil { + return &LinkError{"symlink", oldname, newname, e} + } + return nil +} + +func readlink(name string) (string, error) { + for len := 128; ; len *= 2 { + b := make([]byte, len) + var ( + n int + e error + ) + for { + n, e = fixCount(syscall.Readlink(name, b)) + if e != syscall.EINTR { + break + } + } + // buffer too small + if (runtime.GOOS == "aix" || runtime.GOOS == "wasip1") && e == syscall.ERANGE { + continue + } + if e != nil { + return "", &PathError{Op: "readlink", Path: name, Err: e} + } + if n < len { + return string(b[0:n]), nil + } + } +} + +type unixDirent struct { + parent string + name string + typ FileMode + info FileInfo +} + +func (d *unixDirent) Name() string { return d.name } +func (d *unixDirent) IsDir() bool { return d.typ.IsDir() } +func (d *unixDirent) Type() FileMode { return d.typ } + +func (d *unixDirent) Info() (FileInfo, error) { + if d.info != nil { + return d.info, nil + } + return lstat(d.parent + "/" + d.name) +} + +func (d *unixDirent) String() string { + return fs.FormatDirEntry(d) +} + +func newUnixDirent(parent, name string, typ FileMode) (DirEntry, error) { + ude := &unixDirent{ + parent: parent, + name: name, + typ: typ, + } + if typ != ^FileMode(0) && !testingForceReadDirLstat { + return ude, nil + } + + info, err := lstat(parent + "/" + name) + if err != nil { + return nil, err + } + + ude.typ = info.Mode().Type() + ude.info = info + return ude, nil +} diff --git a/contrib/go/_std_1.22/src/os/file_wasip1.go b/contrib/go/_std_1.23/src/os/file_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/os/file_wasip1.go rename to contrib/go/_std_1.23/src/os/file_wasip1.go diff --git a/contrib/go/_std_1.22/src/os/file_windows.go b/contrib/go/_std_1.23/src/os/file_windows.go similarity index 89% rename from contrib/go/_std_1.22/src/os/file_windows.go rename to contrib/go/_std_1.23/src/os/file_windows.go index 8b04ed6e47e3..cf652ca1bb3f 100644 --- a/contrib/go/_std_1.22/src/os/file_windows.go +++ b/contrib/go/_std_1.23/src/os/file_windows.go @@ -6,10 +6,13 @@ package os import ( "errors" + "internal/filepathlite" + "internal/godebug" "internal/poll" "internal/syscall/windows" "runtime" "sync" + "sync/atomic" "syscall" "unsafe" ) @@ -24,15 +27,15 @@ const _UTIME_OMIT = -1 type file struct { pfd poll.FD name string - dirinfo *dirInfo // nil unless directory being read - appendMode bool // whether file is opened for appending + dirinfo atomic.Pointer[dirInfo] // nil unless directory being read + appendMode bool // whether file is opened for appending } // Fd returns the Windows handle referencing the open file. // If f is closed, the file descriptor becomes invalid. // If f is garbage collected, a finalizer may close the file descriptor, -// making it invalid; see runtime.SetFinalizer for more information on when -// a finalizer might be run. On Unix systems this will cause the SetDeadline +// making it invalid; see [runtime.SetFinalizer] for more information on when +// a finalizer might be run. On Unix systems this will cause the [File.SetDeadline] // methods to stop working. func (file *File) Fd() uintptr { if file == nil { @@ -115,20 +118,19 @@ func openFileNolog(name string, flag int, perm FileMode) (*File, error) { } return nil, &PathError{Op: "open", Path: name, Err: e} } - f, e := newFile(r, name, "file"), nil - if e != nil { - return nil, &PathError{Op: "open", Path: name, Err: e} - } - return f, nil + return newFile(r, name, "file"), nil +} + +func openDirNolog(name string) (*File, error) { + return openFileNolog(name, O_RDONLY, 0) } func (file *file) close() error { if file == nil { return syscall.EINVAL } - if file.dirinfo != nil { - file.dirinfo.close() - file.dirinfo = nil + if info := file.dirinfo.Swap(nil); info != nil { + info.close() } var err error if e := file.pfd.Close(); e != nil { @@ -148,11 +150,10 @@ func (file *file) close() error { // relative to the current offset, and 2 means relative to the end. // It returns the new offset and an error, if any. func (f *File) seek(offset int64, whence int) (ret int64, err error) { - if f.dirinfo != nil { + if info := f.dirinfo.Swap(nil); info != nil { // Free cached dirinfo, so we allocate a new one if we // access this file as a directory again. See #35767 and #37161. - f.dirinfo.close() - f.dirinfo = nil + info.close() } ret, err = f.pfd.Seek(offset, whence) runtime.KeepAlive(f) @@ -287,14 +288,14 @@ func Link(oldname, newname string) error { // If there is an error, it will be of type *LinkError. func Symlink(oldname, newname string) error { // '/' does not work in link's content - oldname = fromSlash(oldname) + oldname = filepathlite.FromSlash(oldname) // need the exact location of the oldname when it's relative to determine if it's a directory destpath := oldname - if v := volumeName(oldname); v == "" { + if v := filepathlite.VolumeName(oldname); v == "" { if len(oldname) > 0 && IsPathSeparator(oldname[0]) { // oldname is relative to the volume containing newname. - if v = volumeName(newname); v != "" { + if v = filepathlite.VolumeName(newname); v != "" { // Prepend the volume explicitly, because it may be different from the // volume of the current working directory. destpath = v + oldname @@ -312,7 +313,18 @@ func Symlink(oldname, newname string) error { if err != nil { return &LinkError{"symlink", oldname, newname, err} } - o, err := syscall.UTF16PtrFromString(fixLongPath(oldname)) + var o *uint16 + if filepathlite.IsAbs(oldname) { + o, err = syscall.UTF16PtrFromString(fixLongPath(oldname)) + } else { + // Do not use fixLongPath on oldname for relative symlinks, + // as it would turn the name into an absolute path thus making + // an absolute symlink instead. + // Notice that CreateSymbolicLinkW does not fail for relative + // symlinks beyond MAX_PATH, so this does not prevent the + // creation of an arbitrary long path name. + o, err = syscall.UTF16PtrFromString(oldname) + } if err != nil { return &LinkError{"symlink", oldname, newname, err} } @@ -353,6 +365,8 @@ func openSymlink(path string) (syscall.Handle, error) { return h, nil } +var winreadlinkvolume = godebug.New("winreadlinkvolume") + // normaliseLinkPath converts absolute paths returned by // DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, ...) // into paths acceptable by all Windows APIs. @@ -360,7 +374,7 @@ func openSymlink(path string) (syscall.Handle, error) { // // \??\C:\foo\bar into C:\foo\bar // \??\UNC\foo\bar into \\foo\bar -// \??\Volume{abc}\ into C:\ +// \??\Volume{abc}\ into \\?\Volume{abc}\ func normaliseLinkPath(path string) (string, error) { if len(path) < 4 || path[:4] != `\??\` { // unexpected path, return it as is @@ -375,7 +389,11 @@ func normaliseLinkPath(path string) (string, error) { return `\\` + s[4:], nil } - // handle paths, like \??\Volume{abc}\... + // \??\Volume{abc}\ + if winreadlinkvolume.Value() != "0" { + return `\\?\` + path[4:], nil + } + winreadlinkvolume.IncNonDefault() h, err := openSymlink(path) if err != nil { diff --git a/contrib/go/_std_1.22/src/os/getwd.go b/contrib/go/_std_1.23/src/os/getwd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/getwd.go rename to contrib/go/_std_1.23/src/os/getwd.go diff --git a/contrib/go/_std_1.23/src/os/path.go b/contrib/go/_std_1.23/src/os/path.go new file mode 100644 index 000000000000..42de603ae1af --- /dev/null +++ b/contrib/go/_std_1.23/src/os/path.go @@ -0,0 +1,86 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "internal/filepathlite" + "syscall" +) + +// MkdirAll creates a directory named path, +// along with any necessary parents, and returns nil, +// or else returns an error. +// The permission bits perm (before umask) are used for all +// directories that MkdirAll creates. +// If path is already a directory, MkdirAll does nothing +// and returns nil. +func MkdirAll(path string, perm FileMode) error { + // Fast path: if we can tell whether path is a directory or file, stop with success or error. + dir, err := Stat(path) + if err == nil { + if dir.IsDir() { + return nil + } + return &PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} + } + + // Slow path: make sure parent exists and then call Mkdir for path. + + // Extract the parent folder from path by first removing any trailing + // path separator and then scanning backward until finding a path + // separator or reaching the beginning of the string. + i := len(path) - 1 + for i >= 0 && IsPathSeparator(path[i]) { + i-- + } + for i >= 0 && !IsPathSeparator(path[i]) { + i-- + } + if i < 0 { + i = 0 + } + + // If there is a parent directory, and it is not the volume name, + // recurse to ensure parent directory exists. + if parent := path[:i]; len(parent) > len(filepathlite.VolumeName(path)) { + err = MkdirAll(parent, perm) + if err != nil { + return err + } + } + + // Parent now exists; invoke Mkdir and use its result. + err = Mkdir(path, perm) + if err != nil { + // Handle arguments like "foo/." by + // double-checking that directory doesn't exist. + dir, err1 := Lstat(path) + if err1 == nil && dir.IsDir() { + return nil + } + return err + } + return nil +} + +// RemoveAll removes path and any children it contains. +// It removes everything it can but returns the first error +// it encounters. If the path does not exist, RemoveAll +// returns nil (no error). +// If there is an error, it will be of type [*PathError]. +func RemoveAll(path string) error { + return removeAll(path) +} + +// endsWithDot reports whether the final component of path is ".". +func endsWithDot(path string) bool { + if path == "." { + return true + } + if len(path) >= 2 && path[len(path)-1] == '.' && IsPathSeparator(path[len(path)-2]) { + return true + } + return false +} diff --git a/contrib/go/_std_1.23/src/os/path_plan9.go b/contrib/go/_std_1.23/src/os/path_plan9.go new file mode 100644 index 000000000000..b09b53a3d828 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/path_plan9.go @@ -0,0 +1,15 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +const ( + PathSeparator = '/' // OS-specific path separator + PathListSeparator = '\000' // OS-specific path list separator +) + +// IsPathSeparator reports whether c is a directory separator character. +func IsPathSeparator(c uint8) bool { + return PathSeparator == c +} diff --git a/contrib/go/_std_1.23/src/os/path_unix.go b/contrib/go/_std_1.23/src/os/path_unix.go new file mode 100644 index 000000000000..0189bcd2a1ee --- /dev/null +++ b/contrib/go/_std_1.23/src/os/path_unix.go @@ -0,0 +1,53 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || (js && wasm) || wasip1 + +package os + +const ( + PathSeparator = '/' // OS-specific path separator + PathListSeparator = ':' // OS-specific path list separator +) + +// IsPathSeparator reports whether c is a directory separator character. +func IsPathSeparator(c uint8) bool { + return PathSeparator == c +} + +// splitPath returns the base name and parent directory. +func splitPath(path string) (string, string) { + // if no better parent is found, the path is relative from "here" + dirname := "." + + // Remove all but one leading slash. + for len(path) > 1 && path[0] == '/' && path[1] == '/' { + path = path[1:] + } + + i := len(path) - 1 + + // Remove trailing slashes. + for ; i > 0 && path[i] == '/'; i-- { + path = path[:i] + } + + // if no slashes in path, base is path + basename := path + + // Remove leading directory path + for i--; i >= 0; i-- { + if path[i] == '/' { + if i == 0 { + dirname = path[:1] + } else { + dirname = path[:i] + } + basename = path[i+1:] + break + } + } + + return dirname, basename +} diff --git a/contrib/go/_std_1.23/src/os/path_windows.go b/contrib/go/_std_1.23/src/os/path_windows.go new file mode 100644 index 000000000000..f585aa5ee6de --- /dev/null +++ b/contrib/go/_std_1.23/src/os/path_windows.go @@ -0,0 +1,152 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "internal/filepathlite" + "internal/syscall/windows" + "syscall" +) + +const ( + PathSeparator = '\\' // OS-specific path separator + PathListSeparator = ';' // OS-specific path list separator +) + +// IsPathSeparator reports whether c is a directory separator character. +func IsPathSeparator(c uint8) bool { + // NOTE: Windows accepts / as path separator. + return c == '\\' || c == '/' +} + +func dirname(path string) string { + vol := filepathlite.VolumeName(path) + i := len(path) - 1 + for i >= len(vol) && !IsPathSeparator(path[i]) { + i-- + } + dir := path[len(vol) : i+1] + last := len(dir) - 1 + if last > 0 && IsPathSeparator(dir[last]) { + dir = dir[:last] + } + if dir == "" { + dir = "." + } + return vol + dir +} + +// fixLongPath returns the extended-length (\\?\-prefixed) form of +// path when needed, in order to avoid the default 260 character file +// path limit imposed by Windows. If the path is short enough or already +// has the extended-length prefix, fixLongPath returns path unmodified. +// If the path is relative and joining it with the current working +// directory results in a path that is too long, fixLongPath returns +// the absolute path with the extended-length prefix. +// +// See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation +func fixLongPath(path string) string { + if windows.CanUseLongPaths { + return path + } + return addExtendedPrefix(path) +} + +// addExtendedPrefix adds the extended path prefix (\\?\) to path. +func addExtendedPrefix(path string) string { + if len(path) >= 4 { + if path[:4] == `\??\` { + // Already extended with \??\ + return path + } + if IsPathSeparator(path[0]) && IsPathSeparator(path[1]) && path[2] == '?' && IsPathSeparator(path[3]) { + // Already extended with \\?\ or any combination of directory separators. + return path + } + } + + // Do nothing (and don't allocate) if the path is "short". + // Empirically (at least on the Windows Server 2013 builder), + // the kernel is arbitrarily okay with < 248 bytes. That + // matches what the docs above say: + // "When using an API to create a directory, the specified + // path cannot be so long that you cannot append an 8.3 file + // name (that is, the directory name cannot exceed MAX_PATH + // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248. + // + // The MSDN docs appear to say that a normal path that is 248 bytes long + // will work; empirically the path must be less then 248 bytes long. + pathLength := len(path) + if !filepathlite.IsAbs(path) { + // If the path is relative, we need to prepend the working directory + // plus a separator to the path before we can determine if it's too long. + // We don't want to call syscall.Getwd here, as that call is expensive to do + // every time fixLongPath is called with a relative path, so we use a cache. + // Note that getwdCache might be outdated if the working directory has been + // changed without using os.Chdir, i.e. using syscall.Chdir directly or cgo. + // This is fine, as the worst that can happen is that we fail to fix the path. + getwdCache.Lock() + if getwdCache.dir == "" { + // Init the working directory cache. + getwdCache.dir, _ = syscall.Getwd() + } + pathLength += len(getwdCache.dir) + 1 + getwdCache.Unlock() + } + + if pathLength < 248 { + // Don't fix. (This is how Go 1.7 and earlier worked, + // not automatically generating the \\?\ form) + return path + } + + var isUNC, isDevice bool + if len(path) >= 2 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) { + if len(path) >= 4 && path[2] == '.' && IsPathSeparator(path[3]) { + // Starts with //./ + isDevice = true + } else { + // Starts with // + isUNC = true + } + } + var prefix []uint16 + if isUNC { + // UNC path, prepend the \\?\UNC\ prefix. + prefix = []uint16{'\\', '\\', '?', '\\', 'U', 'N', 'C', '\\'} + } else if isDevice { + // Don't add the extended prefix to device paths, as it would + // change its meaning. + } else { + prefix = []uint16{'\\', '\\', '?', '\\'} + } + + p, err := syscall.UTF16FromString(path) + if err != nil { + return path + } + // Estimate the required buffer size using the path length plus the null terminator. + // pathLength includes the working directory. This should be accurate unless + // the working directory has changed without using os.Chdir. + n := uint32(pathLength) + 1 + var buf []uint16 + for { + buf = make([]uint16, n+uint32(len(prefix))) + n, err = syscall.GetFullPathName(&p[0], n, &buf[len(prefix)], nil) + if err != nil { + return path + } + if n <= uint32(len(buf)-len(prefix)) { + buf = buf[:n+uint32(len(prefix))] + break + } + } + if isUNC { + // Remove leading \\. + buf = buf[2:] + } + copy(buf, prefix) + return syscall.UTF16ToString(buf) +} diff --git a/contrib/go/_std_1.23/src/os/pidfd_linux.go b/contrib/go/_std_1.23/src/os/pidfd_linux.go new file mode 100644 index 000000000000..0bfef7759cc6 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/pidfd_linux.go @@ -0,0 +1,210 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Support for pidfd was added during the course of a few Linux releases: +// v5.1: pidfd_send_signal syscall; +// v5.2: CLONE_PIDFD flag for clone syscall; +// v5.3: pidfd_open syscall, clone3 syscall; +// v5.4: P_PIDFD idtype support for waitid syscall; +// v5.6: pidfd_getfd syscall. +// +// N.B. Alternative Linux implementations may not follow this ordering. e.g., +// QEMU user mode 7.2 added pidfd_open, but CLONE_PIDFD was not added until +// 8.0. + +package os + +import ( + "errors" + "internal/syscall/unix" + "runtime" + "sync" + "syscall" + "unsafe" +) + +// ensurePidfd initializes the PidFD field in sysAttr if it is not already set. +// It returns the original or modified SysProcAttr struct and a flag indicating +// whether the PidFD should be duplicated before using. +func ensurePidfd(sysAttr *syscall.SysProcAttr) (*syscall.SysProcAttr, bool) { + if !pidfdWorks() { + return sysAttr, false + } + + var pidfd int + + if sysAttr == nil { + return &syscall.SysProcAttr{ + PidFD: &pidfd, + }, false + } + if sysAttr.PidFD == nil { + newSys := *sysAttr // copy + newSys.PidFD = &pidfd + return &newSys, false + } + + return sysAttr, true +} + +// getPidfd returns the value of sysAttr.PidFD (or its duplicate if needDup is +// set) and a flag indicating whether the value can be used. +func getPidfd(sysAttr *syscall.SysProcAttr, needDup bool) (uintptr, bool) { + if !pidfdWorks() { + return 0, false + } + + h := *sysAttr.PidFD + if needDup { + dupH, e := unix.Fcntl(h, syscall.F_DUPFD_CLOEXEC, 0) + if e != nil { + return 0, false + } + h = dupH + } + return uintptr(h), true +} + +func pidfdFind(pid int) (uintptr, error) { + if !pidfdWorks() { + return 0, syscall.ENOSYS + } + + h, err := unix.PidFDOpen(pid, 0) + if err != nil { + return 0, convertESRCH(err) + } + return h, nil +} + +// _P_PIDFD is used as idtype argument to waitid syscall. +const _P_PIDFD = 3 + +func (p *Process) pidfdWait() (*ProcessState, error) { + // When pidfd is used, there is no wait/kill race (described in CL 23967) + // because the PID recycle issue doesn't exist (IOW, pidfd, unlike PID, + // is guaranteed to refer to one particular process). Thus, there is no + // need for the workaround (blockUntilWaitable + sigMu) from pidWait. + // + // We _do_ need to be careful about reuse of the pidfd FD number when + // closing the pidfd. See handle for more details. + handle, status := p.handleTransientAcquire() + switch status { + case statusDone: + // Process already completed Wait, or was not found by + // pidfdFind. Return ECHILD for consistency with what the wait + // syscall would return. + return nil, NewSyscallError("wait", syscall.ECHILD) + case statusReleased: + return nil, syscall.EINVAL + } + defer p.handleTransientRelease() + + var ( + info unix.SiginfoChild + rusage syscall.Rusage + e syscall.Errno + ) + for { + _, _, e = syscall.Syscall6(syscall.SYS_WAITID, _P_PIDFD, handle, uintptr(unsafe.Pointer(&info)), syscall.WEXITED, uintptr(unsafe.Pointer(&rusage)), 0) + if e != syscall.EINTR { + break + } + } + if e != 0 { + return nil, NewSyscallError("waitid", e) + } + // Release the Process' handle reference, in addition to the reference + // we took above. + p.handlePersistentRelease(statusDone) + return &ProcessState{ + pid: int(info.Pid), + status: info.WaitStatus(), + rusage: &rusage, + }, nil +} + +func (p *Process) pidfdSendSignal(s syscall.Signal) error { + handle, status := p.handleTransientAcquire() + switch status { + case statusDone: + return ErrProcessDone + case statusReleased: + return errors.New("os: process already released") + } + defer p.handleTransientRelease() + + return convertESRCH(unix.PidFDSendSignal(handle, s)) +} + +func pidfdWorks() bool { + return checkPidfdOnce() == nil +} + +var checkPidfdOnce = sync.OnceValue(checkPidfd) + +// checkPidfd checks whether all required pidfd-related syscalls work. This +// consists of pidfd_open and pidfd_send_signal syscalls, waitid syscall with +// idtype of P_PIDFD, and clone(CLONE_PIDFD). +// +// Reasons for non-working pidfd syscalls include an older kernel and an +// execution environment in which the above system calls are restricted by +// seccomp or a similar technology. +func checkPidfd() error { + // In Android version < 12, pidfd-related system calls are not allowed + // by seccomp and trigger the SIGSYS signal. See issue #69065. + if runtime.GOOS == "android" { + ignoreSIGSYS() + defer restoreSIGSYS() + } + + // Get a pidfd of the current process (opening of "/proc/self" won't + // work for waitid). + fd, err := unix.PidFDOpen(syscall.Getpid(), 0) + if err != nil { + return NewSyscallError("pidfd_open", err) + } + defer syscall.Close(int(fd)) + + // Check waitid(P_PIDFD) works. + for { + _, _, err = syscall.Syscall6(syscall.SYS_WAITID, _P_PIDFD, fd, 0, syscall.WEXITED, 0, 0) + if err != syscall.EINTR { + break + } + } + // Expect ECHILD from waitid since we're not our own parent. + if err != syscall.ECHILD { + return NewSyscallError("pidfd_wait", err) + } + + // Check pidfd_send_signal works (should be able to send 0 to itself). + if err := unix.PidFDSendSignal(fd, 0); err != nil { + return NewSyscallError("pidfd_send_signal", err) + } + + // Verify that clone(CLONE_PIDFD) works. + // + // This shouldn't be necessary since pidfd_open was added in Linux 5.3, + // after CLONE_PIDFD in Linux 5.2, but some alternative Linux + // implementations may not adhere to this ordering. + if err := checkClonePidfd(); err != nil { + return err + } + + return nil +} + +// Provided by syscall. +// +//go:linkname checkClonePidfd +func checkClonePidfd() error + +// Provided by runtime. +// +//go:linkname ignoreSIGSYS +func ignoreSIGSYS() + +//go:linkname restoreSIGSYS +func restoreSIGSYS() diff --git a/contrib/go/_std_1.23/src/os/pidfd_other.go b/contrib/go/_std_1.23/src/os/pidfd_other.go new file mode 100644 index 000000000000..ba9cbcb93830 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/pidfd_other.go @@ -0,0 +1,31 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (unix && !linux) || (js && wasm) || wasip1 || windows + +package os + +import "syscall" + +func ensurePidfd(sysAttr *syscall.SysProcAttr) (*syscall.SysProcAttr, bool) { + return sysAttr, false +} + +func getPidfd(_ *syscall.SysProcAttr, _ bool) (uintptr, bool) { + return 0, false +} + +func pidfdFind(_ int) (uintptr, error) { + return 0, syscall.ENOSYS +} + +func (p *Process) pidfdRelease() {} + +func (_ *Process) pidfdWait() (*ProcessState, error) { + panic("unreachable") +} + +func (_ *Process) pidfdSendSignal(_ syscall.Signal) error { + panic("unreachable") +} diff --git a/contrib/go/_std_1.22/src/os/pipe2_unix.go b/contrib/go/_std_1.23/src/os/pipe2_unix.go similarity index 86% rename from contrib/go/_std_1.22/src/os/pipe2_unix.go rename to contrib/go/_std_1.23/src/os/pipe2_unix.go index 2d293fdb4d96..dca83a529bb0 100644 --- a/contrib/go/_std_1.22/src/os/pipe2_unix.go +++ b/contrib/go/_std_1.23/src/os/pipe2_unix.go @@ -18,5 +18,5 @@ func Pipe() (r *File, w *File, err error) { return nil, nil, NewSyscallError("pipe2", e) } - return newFile(p[0], "|0", kindPipe), newFile(p[1], "|1", kindPipe), nil + return newFile(p[0], "|0", kindPipe, false), newFile(p[1], "|1", kindPipe, false), nil } diff --git a/contrib/go/_std_1.22/src/os/pipe_unix.go b/contrib/go/_std_1.23/src/os/pipe_unix.go similarity index 88% rename from contrib/go/_std_1.22/src/os/pipe_unix.go rename to contrib/go/_std_1.23/src/os/pipe_unix.go index 2eb11a04cb2d..5c1a953fda4c 100644 --- a/contrib/go/_std_1.22/src/os/pipe_unix.go +++ b/contrib/go/_std_1.23/src/os/pipe_unix.go @@ -24,5 +24,5 @@ func Pipe() (r *File, w *File, err error) { syscall.CloseOnExec(p[1]) syscall.ForkLock.RUnlock() - return newFile(p[0], "|0", kindPipe), newFile(p[1], "|1", kindPipe), nil + return newFile(p[0], "|0", kindPipe, false), newFile(p[1], "|1", kindPipe, false), nil } diff --git a/contrib/go/_std_1.22/src/os/pipe_wasm.go b/contrib/go/_std_1.23/src/os/pipe_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/os/pipe_wasm.go rename to contrib/go/_std_1.23/src/os/pipe_wasm.go diff --git a/contrib/go/_std_1.23/src/os/proc.go b/contrib/go/_std_1.23/src/os/proc.go new file mode 100644 index 000000000000..ea029158eecc --- /dev/null +++ b/contrib/go/_std_1.23/src/os/proc.go @@ -0,0 +1,80 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Process etc. + +package os + +import ( + "internal/testlog" + "runtime" + "syscall" +) + +// Args hold the command-line arguments, starting with the program name. +var Args []string + +func init() { + if runtime.GOOS == "windows" { + // Initialized in exec_windows.go. + return + } + Args = runtime_args() +} + +func runtime_args() []string // in package runtime + +// Getuid returns the numeric user id of the caller. +// +// On Windows, it returns -1. +func Getuid() int { return syscall.Getuid() } + +// Geteuid returns the numeric effective user id of the caller. +// +// On Windows, it returns -1. +func Geteuid() int { return syscall.Geteuid() } + +// Getgid returns the numeric group id of the caller. +// +// On Windows, it returns -1. +func Getgid() int { return syscall.Getgid() } + +// Getegid returns the numeric effective group id of the caller. +// +// On Windows, it returns -1. +func Getegid() int { return syscall.Getegid() } + +// Getgroups returns a list of the numeric ids of groups that the caller belongs to. +// +// On Windows, it returns [syscall.EWINDOWS]. See the [os/user] package +// for a possible alternative. +func Getgroups() ([]int, error) { + gids, e := syscall.Getgroups() + return gids, NewSyscallError("getgroups", e) +} + +// Exit causes the current program to exit with the given status code. +// Conventionally, code zero indicates success, non-zero an error. +// The program terminates immediately; deferred functions are not run. +// +// For portability, the status code should be in the range [0, 125]. +func Exit(code int) { + if code == 0 && testlog.PanicOnExit0() { + // We were told to panic on calls to os.Exit(0). + // This is used to fail tests that make an early + // unexpected call to os.Exit(0). + panic("unexpected call to os.Exit(0) during test") + } + + // Inform the runtime that os.Exit is being called. If -race is + // enabled, this will give race detector a chance to fail the + // program (racy programs do not have the right to finish + // successfully). If coverage is enabled, then this call will + // enable us to write out a coverage data file. + runtime_beforeExit(code) + + syscall.Exit(code) +} + +func runtime_beforeExit(exitCode int) // implemented in runtime diff --git a/contrib/go/_std_1.22/src/os/rawconn.go b/contrib/go/_std_1.23/src/os/rawconn.go similarity index 100% rename from contrib/go/_std_1.22/src/os/rawconn.go rename to contrib/go/_std_1.23/src/os/rawconn.go diff --git a/contrib/go/_std_1.22/src/os/removeall_at.go b/contrib/go/_std_1.23/src/os/removeall_at.go similarity index 97% rename from contrib/go/_std_1.22/src/os/removeall_at.go rename to contrib/go/_std_1.23/src/os/removeall_at.go index 774ca15823bb..cc254e0043fc 100644 --- a/contrib/go/_std_1.22/src/os/removeall_at.go +++ b/contrib/go/_std_1.23/src/os/removeall_at.go @@ -88,7 +88,7 @@ func removeAllFrom(parent *File, base string) error { if IsNotExist(err) { return nil } - if err == syscall.ENOTDIR { + if err == syscall.ENOTDIR || err == unix.NoFollowErrno { // Not a directory; return the error from the unix.Unlinkat. return &PathError{Op: "unlinkat", Path: base, Err: uErr} } @@ -187,5 +187,5 @@ func openDirAt(dirfd int, name string) (*File, error) { } // We use kindNoPoll because we know that this is a directory. - return newFile(r, name, kindNoPoll), nil + return newFile(r, name, kindNoPoll, false), nil } diff --git a/contrib/go/_std_1.22/src/os/removeall_noat.go b/contrib/go/_std_1.23/src/os/removeall_noat.go similarity index 100% rename from contrib/go/_std_1.22/src/os/removeall_noat.go rename to contrib/go/_std_1.23/src/os/removeall_noat.go diff --git a/contrib/go/_std_1.23/src/os/signal/doc.go b/contrib/go/_std_1.23/src/os/signal/doc.go new file mode 100644 index 000000000000..1d3e6eb573a5 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/signal/doc.go @@ -0,0 +1,232 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package signal implements access to incoming signals. + +Signals are primarily used on Unix-like systems. For the use of this +package on Windows and Plan 9, see below. + +# Types of signals + +The signals SIGKILL and SIGSTOP may not be caught by a program, and +therefore cannot be affected by this package. + +Synchronous signals are signals triggered by errors in program +execution: SIGBUS, SIGFPE, and SIGSEGV. These are only considered +synchronous when caused by program execution, not when sent using +[os.Process.Kill] or the kill program or some similar mechanism. In +general, except as discussed below, Go programs will convert a +synchronous signal into a run-time panic. + +The remaining signals are asynchronous signals. They are not +triggered by program errors, but are instead sent from the kernel or +from some other program. + +Of the asynchronous signals, the SIGHUP signal is sent when a program +loses its controlling terminal. The SIGINT signal is sent when the +user at the controlling terminal presses the interrupt character, +which by default is ^C (Control-C). The SIGQUIT signal is sent when +the user at the controlling terminal presses the quit character, which +by default is ^\ (Control-Backslash). In general you can cause a +program to simply exit by pressing ^C, and you can cause it to exit +with a stack dump by pressing ^\. + +# Default behavior of signals in Go programs + +By default, a synchronous signal is converted into a run-time panic. A +SIGHUP, SIGINT, or SIGTERM signal causes the program to exit. A +SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGSTKFLT, SIGEMT, or SIGSYS signal +causes the program to exit with a stack dump. A SIGTSTP, SIGTTIN, or +SIGTTOU signal gets the system default behavior (these signals are +used by the shell for job control). The SIGPROF signal is handled +directly by the Go runtime to implement runtime.CPUProfile. Other +signals will be caught but no action will be taken. + +If the Go program is started with either SIGHUP or SIGINT ignored +(signal handler set to SIG_IGN), they will remain ignored. + +If the Go program is started with a non-empty signal mask, that will +generally be honored. However, some signals are explicitly unblocked: +the synchronous signals, SIGILL, SIGTRAP, SIGSTKFLT, SIGCHLD, SIGPROF, +and, on Linux, signals 32 (SIGCANCEL) and 33 (SIGSETXID) +(SIGCANCEL and SIGSETXID are used internally by glibc). Subprocesses +started by [os.Exec], or by [os/exec], will inherit the +modified signal mask. + +# Changing the behavior of signals in Go programs + +The functions in this package allow a program to change the way Go +programs handle signals. + +Notify disables the default behavior for a given set of asynchronous +signals and instead delivers them over one or more registered +channels. Specifically, it applies to the signals SIGHUP, SIGINT, +SIGQUIT, SIGABRT, and SIGTERM. It also applies to the job control +signals SIGTSTP, SIGTTIN, and SIGTTOU, in which case the system +default behavior does not occur. It also applies to some signals that +otherwise cause no action: SIGUSR1, SIGUSR2, SIGPIPE, SIGALRM, +SIGCHLD, SIGCONT, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGWINCH, +SIGIO, SIGPWR, SIGINFO, SIGTHR, SIGWAITING, SIGLWP, SIGFREEZE, +SIGTHAW, SIGLOST, SIGXRES, SIGJVM1, SIGJVM2, and any real time signals +used on the system. Note that not all of these signals are available +on all systems. + +If the program was started with SIGHUP or SIGINT ignored, and [Notify] +is called for either signal, a signal handler will be installed for +that signal and it will no longer be ignored. If, later, [Reset] or +[Ignore] is called for that signal, or [Stop] is called on all channels +passed to Notify for that signal, the signal will once again be +ignored. Reset will restore the system default behavior for the +signal, while Ignore will cause the system to ignore the signal +entirely. + +If the program is started with a non-empty signal mask, some signals +will be explicitly unblocked as described above. If Notify is called +for a blocked signal, it will be unblocked. If, later, Reset is +called for that signal, or Stop is called on all channels passed to +Notify for that signal, the signal will once again be blocked. + +# SIGPIPE + +When a Go program writes to a broken pipe, the kernel will raise a +SIGPIPE signal. + +If the program has not called Notify to receive SIGPIPE signals, then +the behavior depends on the file descriptor number. A write to a +broken pipe on file descriptors 1 or 2 (standard output or standard +error) will cause the program to exit with a SIGPIPE signal. A write +to a broken pipe on some other file descriptor will take no action on +the SIGPIPE signal, and the write will fail with an EPIPE error. + +If the program has called Notify to receive SIGPIPE signals, the file +descriptor number does not matter. The SIGPIPE signal will be +delivered to the Notify channel, and the write will fail with an EPIPE +error. + +This means that, by default, command line programs will behave like +typical Unix command line programs, while other programs will not +crash with SIGPIPE when writing to a closed network connection. + +# Go programs that use cgo or SWIG + +In a Go program that includes non-Go code, typically C/C++ code +accessed using cgo or SWIG, Go's startup code normally runs first. It +configures the signal handlers as expected by the Go runtime, before +the non-Go startup code runs. If the non-Go startup code wishes to +install its own signal handlers, it must take certain steps to keep Go +working well. This section documents those steps and the overall +effect changes to signal handler settings by the non-Go code can have +on Go programs. In rare cases, the non-Go code may run before the Go +code, in which case the next section also applies. + +If the non-Go code called by the Go program does not change any signal +handlers or masks, then the behavior is the same as for a pure Go +program. + +If the non-Go code installs any signal handlers, it must use the +SA_ONSTACK flag with sigaction. Failing to do so is likely to cause +the program to crash if the signal is received. Go programs routinely +run with a limited stack, and therefore set up an alternate signal +stack. + +If the non-Go code installs a signal handler for any of the +synchronous signals (SIGBUS, SIGFPE, SIGSEGV), then it should record +the existing Go signal handler. If those signals occur while +executing Go code, it should invoke the Go signal handler (whether the +signal occurs while executing Go code can be determined by looking at +the PC passed to the signal handler). Otherwise some Go run-time +panics will not occur as expected. + +If the non-Go code installs a signal handler for any of the +asynchronous signals, it may invoke the Go signal handler or not as it +chooses. Naturally, if it does not invoke the Go signal handler, the +Go behavior described above will not occur. This can be an issue with +the SIGPROF signal in particular. + +The non-Go code should not change the signal mask on any threads +created by the Go runtime. If the non-Go code starts new threads +itself, those threads may set the signal mask as they please. + +If the non-Go code starts a new thread, changes the signal mask, and +then invokes a Go function in that thread, the Go runtime will +automatically unblock certain signals: the synchronous signals, +SIGILL, SIGTRAP, SIGSTKFLT, SIGCHLD, SIGPROF, SIGCANCEL, and +SIGSETXID. When the Go function returns, the non-Go signal mask will +be restored. + +If the Go signal handler is invoked on a non-Go thread not running Go +code, the handler generally forwards the signal to the non-Go code, as +follows. If the signal is SIGPROF, the Go handler does +nothing. Otherwise, the Go handler removes itself, unblocks the +signal, and raises it again, to invoke any non-Go handler or default +system handler. If the program does not exit, the Go handler then +reinstalls itself and continues execution of the program. + +If a SIGPIPE signal is received, the Go program will invoke the +special handling described above if the SIGPIPE is received on a Go +thread. If the SIGPIPE is received on a non-Go thread the signal will +be forwarded to the non-Go handler, if any; if there is none the +default system handler will cause the program to terminate. + +# Non-Go programs that call Go code + +When Go code is built with options like -buildmode=c-shared, it will +be run as part of an existing non-Go program. The non-Go code may +have already installed signal handlers when the Go code starts (that +may also happen in unusual cases when using cgo or SWIG; in that case, +the discussion here applies). For -buildmode=c-archive the Go runtime +will initialize signals at global constructor time. For +-buildmode=c-shared the Go runtime will initialize signals when the +shared library is loaded. + +If the Go runtime sees an existing signal handler for the SIGCANCEL or +SIGSETXID signals (which are used only on Linux), it will turn on +the SA_ONSTACK flag and otherwise keep the signal handler. + +For the synchronous signals and SIGPIPE, the Go runtime will install a +signal handler. It will save any existing signal handler. If a +synchronous signal arrives while executing non-Go code, the Go runtime +will invoke the existing signal handler instead of the Go signal +handler. + +Go code built with -buildmode=c-archive or -buildmode=c-shared will +not install any other signal handlers by default. If there is an +existing signal handler, the Go runtime will turn on the SA_ONSTACK +flag and otherwise keep the signal handler. If Notify is called for an +asynchronous signal, a Go signal handler will be installed for that +signal. If, later, Reset is called for that signal, the original +handling for that signal will be reinstalled, restoring the non-Go +signal handler if any. + +Go code built without -buildmode=c-archive or -buildmode=c-shared will +install a signal handler for the asynchronous signals listed above, +and save any existing signal handler. If a signal is delivered to a +non-Go thread, it will act as described above, except that if there is +an existing non-Go signal handler, that handler will be installed +before raising the signal. + +# Windows + +On Windows a ^C (Control-C) or ^BREAK (Control-Break) normally cause +the program to exit. If Notify is called for [os.Interrupt], ^C or ^BREAK +will cause [os.Interrupt] to be sent on the channel, and the program will +not exit. If Reset is called, or Stop is called on all channels passed +to Notify, then the default behavior will be restored. + +Additionally, if Notify is called, and Windows sends CTRL_CLOSE_EVENT, +CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT to the process, Notify will +return syscall.SIGTERM. Unlike Control-C and Control-Break, Notify does +not change process behavior when either CTRL_CLOSE_EVENT, +CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT is received - the process will +still get terminated unless it exits. But receiving syscall.SIGTERM will +give the process an opportunity to clean up before termination. + +# Plan 9 + +On Plan 9, signals have type syscall.Note, which is a string. Calling +Notify with a syscall.Note will cause that value to be sent on the +channel when that string is posted as a note. +*/ +package signal diff --git a/contrib/go/_std_1.22/src/os/signal/sig.s b/contrib/go/_std_1.23/src/os/signal/sig.s similarity index 100% rename from contrib/go/_std_1.22/src/os/signal/sig.s rename to contrib/go/_std_1.23/src/os/signal/sig.s diff --git a/contrib/go/_std_1.22/src/os/signal/signal.go b/contrib/go/_std_1.23/src/os/signal/signal.go similarity index 95% rename from contrib/go/_std_1.22/src/os/signal/signal.go rename to contrib/go/_std_1.23/src/os/signal/signal.go index 4250a7e0de60..9a4cd64fb75e 100644 --- a/contrib/go/_std_1.22/src/os/signal/signal.go +++ b/contrib/go/_std_1.23/src/os/signal/signal.go @@ -81,7 +81,7 @@ func cancel(sigs []os.Signal, action func(int)) { // Ignore causes the provided signals to be ignored. If they are received by // the program, nothing will happen. Ignore undoes the effect of any prior -// calls to Notify for the provided signals. +// calls to [Notify] for the provided signals. // If no signals are provided, all incoming signals will be ignored. func Ignore(sig ...os.Signal) { cancel(sig, ignoreSignal) @@ -113,7 +113,7 @@ var ( // // It is allowed to call Notify multiple times with the same channel: // each call expands the set of signals sent to that channel. -// The only way to remove signals from the set is to call Stop. +// The only way to remove signals from the set is to call [Stop]. // // It is allowed to call Notify multiple times with different channels // and the same signals: each channel receives copies of incoming @@ -167,7 +167,7 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) { } } -// Reset undoes the effect of any prior calls to Notify for the provided +// Reset undoes the effect of any prior calls to [Notify] for the provided // signals. // If no signals are provided, all signal handlers will be reset. func Reset(sig ...os.Signal) { @@ -175,7 +175,7 @@ func Reset(sig ...os.Signal) { } // Stop causes package signal to stop relaying incoming signals to c. -// It undoes the effect of all prior calls to Notify using c. +// It undoes the effect of all prior calls to [Notify] using c. // When Stop returns, it is guaranteed that c will receive no more signals. func Stop(c chan<- os.Signal) { handlers.Lock() @@ -264,9 +264,9 @@ func process(sig os.Signal) { // when the returned stop function is called, or when the parent context's // Done channel is closed, whichever happens first. // -// The stop function unregisters the signal behavior, which, like signal.Reset, +// The stop function unregisters the signal behavior, which, like [signal.Reset], // may restore the default behavior for a given signal. For example, the default -// behavior of a Go program receiving os.Interrupt is to exit. Calling +// behavior of a Go program receiving [os.Interrupt] is to exit. Calling // NotifyContext(parent, os.Interrupt) will change the behavior to cancel // the returned context. Future interrupts received will not trigger the default // (exit) behavior until the returned stop function is called. diff --git a/contrib/go/_std_1.22/src/os/signal/signal_plan9.go b/contrib/go/_std_1.23/src/os/signal/signal_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/signal/signal_plan9.go rename to contrib/go/_std_1.23/src/os/signal/signal_plan9.go diff --git a/contrib/go/_std_1.22/src/os/signal/signal_unix.go b/contrib/go/_std_1.23/src/os/signal/signal_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/signal/signal_unix.go rename to contrib/go/_std_1.23/src/os/signal/signal_unix.go diff --git a/contrib/go/_std_1.22/src/os/signal/ya.make b/contrib/go/_std_1.23/src/os/signal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/os/signal/ya.make rename to contrib/go/_std_1.23/src/os/signal/ya.make diff --git a/contrib/go/_std_1.22/src/os/stat.go b/contrib/go/_std_1.23/src/os/stat.go similarity index 76% rename from contrib/go/_std_1.22/src/os/stat.go rename to contrib/go/_std_1.23/src/os/stat.go index 11d9efa4573f..50acb6dbdd12 100644 --- a/contrib/go/_std_1.22/src/os/stat.go +++ b/contrib/go/_std_1.23/src/os/stat.go @@ -6,17 +6,17 @@ package os import "internal/testlog" -// Stat returns a FileInfo describing the named file. -// If there is an error, it will be of type *PathError. +// Stat returns a [FileInfo] describing the named file. +// If there is an error, it will be of type [*PathError]. func Stat(name string) (FileInfo, error) { testlog.Stat(name) return statNolog(name) } -// Lstat returns a FileInfo describing the named file. +// Lstat returns a [FileInfo] describing the named file. // If the file is a symbolic link, the returned FileInfo // describes the symbolic link. Lstat makes no attempt to follow the link. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. // // On Windows, if the file is a reparse point that is a surrogate for another // named entity (such as a symbolic link or mounted folder), the returned diff --git a/contrib/go/_std_1.22/src/os/stat_aix.go b/contrib/go/_std_1.23/src/os/stat_aix.go similarity index 95% rename from contrib/go/_std_1.22/src/os/stat_aix.go rename to contrib/go/_std_1.23/src/os/stat_aix.go index a37c9fdae41a..574e3d26ffd0 100644 --- a/contrib/go/_std_1.22/src/os/stat_aix.go +++ b/contrib/go/_std_1.23/src/os/stat_aix.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = int64(fs.sys.Size) fs.modTime = stTimespecToTime(fs.sys.Mtim) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_darwin.go b/contrib/go/_std_1.23/src/os/stat_darwin.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_darwin.go rename to contrib/go/_std_1.23/src/os/stat_darwin.go index b92ffd4a0a6f..70c5345aacde 100644 --- a/contrib/go/_std_1.22/src/os/stat_darwin.go +++ b/contrib/go/_std_1.23/src/os/stat_darwin.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtimespec.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_dragonfly.go b/contrib/go/_std_1.23/src/os/stat_dragonfly.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_dragonfly.go rename to contrib/go/_std_1.23/src/os/stat_dragonfly.go index 316c26c7cab7..01f2a14e2768 100644 --- a/contrib/go/_std_1.22/src/os/stat_dragonfly.go +++ b/contrib/go/_std_1.23/src/os/stat_dragonfly.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtim.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_freebsd.go b/contrib/go/_std_1.23/src/os/stat_freebsd.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_freebsd.go rename to contrib/go/_std_1.23/src/os/stat_freebsd.go index 919ee44dd6b5..7b786940454b 100644 --- a/contrib/go/_std_1.22/src/os/stat_freebsd.go +++ b/contrib/go/_std_1.23/src/os/stat_freebsd.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtimespec.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_js.go b/contrib/go/_std_1.23/src/os/stat_js.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_js.go rename to contrib/go/_std_1.23/src/os/stat_js.go index a137172e66de..d63461d6955f 100644 --- a/contrib/go/_std_1.22/src/os/stat_js.go +++ b/contrib/go/_std_1.23/src/os/stat_js.go @@ -7,12 +7,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtime, fs.sys.MtimeNsec) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_linux.go b/contrib/go/_std_1.23/src/os/stat_linux.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_linux.go rename to contrib/go/_std_1.23/src/os/stat_linux.go index 316c26c7cab7..01f2a14e2768 100644 --- a/contrib/go/_std_1.22/src/os/stat_linux.go +++ b/contrib/go/_std_1.23/src/os/stat_linux.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtim.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_netbsd.go b/contrib/go/_std_1.23/src/os/stat_netbsd.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_netbsd.go rename to contrib/go/_std_1.23/src/os/stat_netbsd.go index 919ee44dd6b5..7b786940454b 100644 --- a/contrib/go/_std_1.22/src/os/stat_netbsd.go +++ b/contrib/go/_std_1.23/src/os/stat_netbsd.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtimespec.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_openbsd.go b/contrib/go/_std_1.23/src/os/stat_openbsd.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_openbsd.go rename to contrib/go/_std_1.23/src/os/stat_openbsd.go index 316c26c7cab7..01f2a14e2768 100644 --- a/contrib/go/_std_1.22/src/os/stat_openbsd.go +++ b/contrib/go/_std_1.23/src/os/stat_openbsd.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtim.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_plan9.go b/contrib/go/_std_1.23/src/os/stat_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/stat_plan9.go rename to contrib/go/_std_1.23/src/os/stat_plan9.go diff --git a/contrib/go/_std_1.22/src/os/stat_solaris.go b/contrib/go/_std_1.23/src/os/stat_solaris.go similarity index 95% rename from contrib/go/_std_1.22/src/os/stat_solaris.go rename to contrib/go/_std_1.23/src/os/stat_solaris.go index 4e00ecb075f3..447044e2e267 100644 --- a/contrib/go/_std_1.22/src/os/stat_solaris.go +++ b/contrib/go/_std_1.23/src/os/stat_solaris.go @@ -5,6 +5,7 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) @@ -18,7 +19,7 @@ const ( ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtim.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_unix.go b/contrib/go/_std_1.23/src/os/stat_unix.go similarity index 86% rename from contrib/go/_std_1.22/src/os/stat_unix.go rename to contrib/go/_std_1.23/src/os/stat_unix.go index 431df33faef9..9a1f21211ca0 100644 --- a/contrib/go/_std_1.22/src/os/stat_unix.go +++ b/contrib/go/_std_1.23/src/os/stat_unix.go @@ -10,8 +10,8 @@ import ( "syscall" ) -// Stat returns the FileInfo structure describing file. -// If there is an error, it will be of type *PathError. +// Stat returns the [FileInfo] structure describing file. +// If there is an error, it will be of type [*PathError]. func (f *File) Stat() (FileInfo, error) { if f == nil { return nil, ErrInvalid @@ -19,7 +19,7 @@ func (f *File) Stat() (FileInfo, error) { var fs fileStat err := f.pfd.Fstat(&fs.sys) if err != nil { - return nil, &PathError{Op: "stat", Path: f.name, Err: err} + return nil, f.wrapErr("stat", err) } fillFileStatFromSys(&fs, f.name) return &fs, nil diff --git a/contrib/go/_std_1.22/src/os/stat_wasip1.go b/contrib/go/_std_1.23/src/os/stat_wasip1.go similarity index 93% rename from contrib/go/_std_1.22/src/os/stat_wasip1.go rename to contrib/go/_std_1.23/src/os/stat_wasip1.go index a4f0a20430b5..85a364988992 100644 --- a/contrib/go/_std_1.22/src/os/stat_wasip1.go +++ b/contrib/go/_std_1.23/src/os/stat_wasip1.go @@ -7,12 +7,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = int64(fs.sys.Size) fs.mode = FileMode(fs.sys.Mode) fs.modTime = time.Unix(0, int64(fs.sys.Mtime)) diff --git a/contrib/go/_std_1.22/src/os/stat_windows.go b/contrib/go/_std_1.23/src/os/stat_windows.go similarity index 84% rename from contrib/go/_std_1.22/src/os/stat_windows.go rename to contrib/go/_std_1.23/src/os/stat_windows.go index 668255f74adf..160a3893ce56 100644 --- a/contrib/go/_std_1.22/src/os/stat_windows.go +++ b/contrib/go/_std_1.23/src/os/stat_windows.go @@ -5,13 +5,14 @@ package os import ( + "internal/filepathlite" "internal/syscall/windows" "syscall" "unsafe" ) -// Stat returns the FileInfo structure describing file. -// If there is an error, it will be of type *PathError. +// Stat returns the [FileInfo] structure describing file. +// If there is an error, it will be of type [*PathError]. func (file *File) Stat() (FileInfo, error) { if file == nil { return nil, ErrInvalid @@ -33,6 +34,15 @@ func stat(funcname, name string, followSurrogates bool) (FileInfo, error) { // See https://golang.org/issues/19922#issuecomment-300031421 for details. var fa syscall.Win32FileAttributeData err = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa))) + if err == nil && fa.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { + // Not a surrogate for another named entity, because it isn't any kind of reparse point. + // The information we got from GetFileAttributesEx is good enough for now. + fs := newFileStatFromWin32FileAttributeData(&fa) + if err := fs.saveInfoFromPath(name); err != nil { + return nil, err + } + return fs, nil + } // GetFileAttributesEx fails with ERROR_SHARING_VIOLATION error for // files like c:\pagefile.sys. Use FindFirstFile for such files. @@ -53,28 +63,20 @@ func stat(funcname, name string, followSurrogates bool) (FileInfo, error) { } } - if err == nil && fa.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { - // Not a surrogate for another named entity, because it isn't any kind of reparse point. - // The information we got from GetFileAttributesEx is good enough for now. - fs := &fileStat{ - FileAttributes: fa.FileAttributes, - CreationTime: fa.CreationTime, - LastAccessTime: fa.LastAccessTime, - LastWriteTime: fa.LastWriteTime, - FileSizeHigh: fa.FileSizeHigh, - FileSizeLow: fa.FileSizeLow, - } - if err := fs.saveInfoFromPath(name); err != nil { - return nil, err - } - return fs, nil - } - // Use CreateFile to determine whether the file is a name surrogate and, if so, // save information about the link target. // Set FILE_FLAG_BACKUP_SEMANTICS so that CreateFile will create the handle // even if name refers to a directory. - h, err := syscall.CreateFile(namep, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0) + var flags uint32 = syscall.FILE_FLAG_BACKUP_SEMANTICS | syscall.FILE_FLAG_OPEN_REPARSE_POINT + h, err := syscall.CreateFile(namep, 0, 0, nil, syscall.OPEN_EXISTING, flags, 0) + + if err == windows.ERROR_INVALID_PARAMETER { + // Console handles, like "\\.\con", require generic read access. See + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#consoles. + // We haven't set it previously because it is normally not required + // to read attributes and some files may not allow it. + h, err = syscall.CreateFile(namep, syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING, flags, 0) + } if err != nil { // Since CreateFile failed, we can't determine whether name refers to a // name surrogate, or some other kind of reparse point. Since we can't return a @@ -106,7 +108,7 @@ func statHandle(name string, h syscall.Handle) (FileInfo, error) { } switch ft { case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR: - return &fileStat{name: basename(name), filetype: ft}, nil + return &fileStat{name: filepathlite.Base(name), filetype: ft}, nil } fs, err := newFileStatFromGetFileInformationByHandle(name, h) if err != nil { diff --git a/contrib/go/_std_1.22/src/os/sticky_bsd.go b/contrib/go/_std_1.23/src/os/sticky_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sticky_bsd.go rename to contrib/go/_std_1.23/src/os/sticky_bsd.go diff --git a/contrib/go/_std_1.22/src/os/sticky_notbsd.go b/contrib/go/_std_1.23/src/os/sticky_notbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sticky_notbsd.go rename to contrib/go/_std_1.23/src/os/sticky_notbsd.go diff --git a/contrib/go/_std_1.22/src/os/sys.go b/contrib/go/_std_1.23/src/os/sys.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys.go rename to contrib/go/_std_1.23/src/os/sys.go diff --git a/contrib/go/_std_1.22/src/os/sys_aix.go b/contrib/go/_std_1.23/src/os/sys_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_aix.go rename to contrib/go/_std_1.23/src/os/sys_aix.go diff --git a/contrib/go/_std_1.22/src/os/sys_bsd.go b/contrib/go/_std_1.23/src/os/sys_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_bsd.go rename to contrib/go/_std_1.23/src/os/sys_bsd.go diff --git a/contrib/go/_std_1.22/src/os/sys_js.go b/contrib/go/_std_1.23/src/os/sys_js.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_js.go rename to contrib/go/_std_1.23/src/os/sys_js.go diff --git a/contrib/go/_std_1.22/src/os/sys_linux.go b/contrib/go/_std_1.23/src/os/sys_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_linux.go rename to contrib/go/_std_1.23/src/os/sys_linux.go diff --git a/contrib/go/_std_1.22/src/os/sys_plan9.go b/contrib/go/_std_1.23/src/os/sys_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_plan9.go rename to contrib/go/_std_1.23/src/os/sys_plan9.go diff --git a/contrib/go/_std_1.22/src/os/sys_solaris.go b/contrib/go/_std_1.23/src/os/sys_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_solaris.go rename to contrib/go/_std_1.23/src/os/sys_solaris.go diff --git a/contrib/go/_std_1.22/src/os/sys_unix.go b/contrib/go/_std_1.23/src/os/sys_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_unix.go rename to contrib/go/_std_1.23/src/os/sys_unix.go diff --git a/contrib/go/_std_1.22/src/os/sys_wasip1.go b/contrib/go/_std_1.23/src/os/sys_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_wasip1.go rename to contrib/go/_std_1.23/src/os/sys_wasip1.go diff --git a/contrib/go/_std_1.22/src/os/sys_windows.go b/contrib/go/_std_1.23/src/os/sys_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_windows.go rename to contrib/go/_std_1.23/src/os/sys_windows.go diff --git a/contrib/go/_std_1.22/src/os/tempfile.go b/contrib/go/_std_1.23/src/os/tempfile.go similarity index 95% rename from contrib/go/_std_1.22/src/os/tempfile.go rename to contrib/go/_std_1.23/src/os/tempfile.go index 66c65e6c783c..af70b360b3a0 100644 --- a/contrib/go/_std_1.22/src/os/tempfile.go +++ b/contrib/go/_std_1.23/src/os/tempfile.go @@ -15,6 +15,7 @@ import ( // We generate random temporary file names so that there's a good // chance the file doesn't exist yet - keeps the number of tries in // TempFile to a minimum. +// //go:linkname runtime_rand runtime.rand func runtime_rand() uint64 @@ -26,7 +27,8 @@ func nextRandom() string { // opens the file for reading and writing, and returns the resulting file. // The filename is generated by taking pattern and adding a random string to the end. // If pattern includes a "*", the random string replaces the last "*". -// If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by TempDir. +// The file is created with mode 0o600 (before umask). +// If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by [TempDir]. // Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file. // The caller can use the file's Name method to find the pathname of the file. // It is the caller's responsibility to remove the file when it is no longer needed. @@ -77,6 +79,7 @@ func prefixAndSuffix(pattern string) (prefix, suffix string, err error) { // and returns the pathname of the new directory. // The new directory's name is generated by adding a random string to the end of pattern. // If pattern includes a "*", the random string replaces the last "*" instead. +// The directory is created with mode 0o700 (before umask). // If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir. // Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory. // It is the caller's responsibility to remove the directory when it is no longer needed. diff --git a/contrib/go/_std_1.23/src/os/types.go b/contrib/go/_std_1.23/src/os/types.go new file mode 100644 index 000000000000..d51a458f44f9 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/types.go @@ -0,0 +1,76 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "io/fs" + "syscall" +) + +// Getpagesize returns the underlying system's memory page size. +func Getpagesize() int { return syscall.Getpagesize() } + +// File represents an open file descriptor. +// +// The methods of File are safe for concurrent use. +type File struct { + *file // os specific +} + +// A FileInfo describes a file and is returned by [Stat] and [Lstat]. +type FileInfo = fs.FileInfo + +// A FileMode represents a file's mode and permission bits. +// The bits have the same definition on all systems, so that +// information about files can be moved from one system +// to another portably. Not all bits apply to all systems. +// The only required bit is [ModeDir] for directories. +type FileMode = fs.FileMode + +// The defined file mode bits are the most significant bits of the [FileMode]. +// The nine least-significant bits are the standard Unix rwxrwxrwx permissions. +// The values of these bits should be considered part of the public API and +// may be used in wire protocols or disk representations: they must not be +// changed, although new bits might be added. +const ( + // The single letters are the abbreviations + // used by the String method's formatting. + ModeDir = fs.ModeDir // d: is a directory + ModeAppend = fs.ModeAppend // a: append-only + ModeExclusive = fs.ModeExclusive // l: exclusive use + ModeTemporary = fs.ModeTemporary // T: temporary file; Plan 9 only + ModeSymlink = fs.ModeSymlink // L: symbolic link + ModeDevice = fs.ModeDevice // D: device file + ModeNamedPipe = fs.ModeNamedPipe // p: named pipe (FIFO) + ModeSocket = fs.ModeSocket // S: Unix domain socket + ModeSetuid = fs.ModeSetuid // u: setuid + ModeSetgid = fs.ModeSetgid // g: setgid + ModeCharDevice = fs.ModeCharDevice // c: Unix character device, when ModeDevice is set + ModeSticky = fs.ModeSticky // t: sticky + ModeIrregular = fs.ModeIrregular // ?: non-regular file; nothing else is known about this file + + // Mask for the type bits. For regular files, none will be set. + ModeType = fs.ModeType + + ModePerm = fs.ModePerm // Unix permission bits, 0o777 +) + +func (fs *fileStat) Name() string { return fs.name } +func (fs *fileStat) IsDir() bool { return fs.Mode().IsDir() } + +// SameFile reports whether fi1 and fi2 describe the same file. +// For example, on Unix this means that the device and inode fields +// of the two underlying structures are identical; on other systems +// the decision may be based on the path names. +// SameFile only applies to results returned by this package's [Stat]. +// It returns false in other cases. +func SameFile(fi1, fi2 FileInfo) bool { + fs1, ok1 := fi1.(*fileStat) + fs2, ok2 := fi2.(*fileStat) + if !ok1 || !ok2 { + return false + } + return sameFile(fs1, fs2) +} diff --git a/contrib/go/_std_1.22/src/os/types_plan9.go b/contrib/go/_std_1.23/src/os/types_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/types_plan9.go rename to contrib/go/_std_1.23/src/os/types_plan9.go diff --git a/contrib/go/_std_1.22/src/os/types_unix.go b/contrib/go/_std_1.23/src/os/types_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/types_unix.go rename to contrib/go/_std_1.23/src/os/types_unix.go diff --git a/contrib/go/_std_1.23/src/os/types_windows.go b/contrib/go/_std_1.23/src/os/types_windows.go new file mode 100644 index 000000000000..34648e796a87 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/types_windows.go @@ -0,0 +1,368 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "internal/filepathlite" + "internal/godebug" + "internal/syscall/windows" + "sync" + "syscall" + "time" + "unsafe" +) + +// A fileStat is the implementation of FileInfo returned by Stat and Lstat. +type fileStat struct { + name string + + // from ByHandleFileInformation, Win32FileAttributeData, Win32finddata, and GetFileInformationByHandleEx + FileAttributes uint32 + CreationTime syscall.Filetime + LastAccessTime syscall.Filetime + LastWriteTime syscall.Filetime + FileSizeHigh uint32 + FileSizeLow uint32 + + // from Win32finddata and GetFileInformationByHandleEx + ReparseTag uint32 + + // what syscall.GetFileType returns + filetype uint32 + + // used to implement SameFile + sync.Mutex + path string + vol uint32 + idxhi uint32 + idxlo uint32 + appendNameToPath bool +} + +// newFileStatFromGetFileInformationByHandle calls GetFileInformationByHandle +// to gather all required information about the file handle h. +func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (fs *fileStat, err error) { + var d syscall.ByHandleFileInformation + err = syscall.GetFileInformationByHandle(h, &d) + if err != nil { + return nil, &PathError{Op: "GetFileInformationByHandle", Path: path, Err: err} + } + + var reparseTag uint32 + if d.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { + var ti windows.FILE_ATTRIBUTE_TAG_INFO + err = windows.GetFileInformationByHandleEx(h, windows.FileAttributeTagInfo, (*byte)(unsafe.Pointer(&ti)), uint32(unsafe.Sizeof(ti))) + if err != nil { + return nil, &PathError{Op: "GetFileInformationByHandleEx", Path: path, Err: err} + } + reparseTag = ti.ReparseTag + } + + return &fileStat{ + name: filepathlite.Base(path), + FileAttributes: d.FileAttributes, + CreationTime: d.CreationTime, + LastAccessTime: d.LastAccessTime, + LastWriteTime: d.LastWriteTime, + FileSizeHigh: d.FileSizeHigh, + FileSizeLow: d.FileSizeLow, + vol: d.VolumeSerialNumber, + idxhi: d.FileIndexHigh, + idxlo: d.FileIndexLow, + ReparseTag: reparseTag, + // fileStat.path is used by os.SameFile to decide if it needs + // to fetch vol, idxhi and idxlo. But these are already set, + // so set fileStat.path to "" to prevent os.SameFile doing it again. + }, nil +} + +// newFileStatFromWin32FileAttributeData copies all required information +// from syscall.Win32FileAttributeData d into the newly created fileStat. +func newFileStatFromWin32FileAttributeData(d *syscall.Win32FileAttributeData) *fileStat { + return &fileStat{ + FileAttributes: d.FileAttributes, + CreationTime: d.CreationTime, + LastAccessTime: d.LastAccessTime, + LastWriteTime: d.LastWriteTime, + FileSizeHigh: d.FileSizeHigh, + FileSizeLow: d.FileSizeLow, + } +} + +// newFileStatFromFileIDBothDirInfo copies all required information +// from windows.FILE_ID_BOTH_DIR_INFO d into the newly created fileStat. +func newFileStatFromFileIDBothDirInfo(d *windows.FILE_ID_BOTH_DIR_INFO) *fileStat { + // The FILE_ID_BOTH_DIR_INFO MSDN documentations isn't completely correct. + // FileAttributes can contain any file attributes that is currently set on the file, + // not just the ones documented. + // EaSize contains the reparse tag if the file is a reparse point. + return &fileStat{ + FileAttributes: d.FileAttributes, + CreationTime: d.CreationTime, + LastAccessTime: d.LastAccessTime, + LastWriteTime: d.LastWriteTime, + FileSizeHigh: uint32(d.EndOfFile >> 32), + FileSizeLow: uint32(d.EndOfFile), + ReparseTag: d.EaSize, + idxhi: uint32(d.FileID >> 32), + idxlo: uint32(d.FileID), + } +} + +// newFileStatFromFileFullDirInfo copies all required information +// from windows.FILE_FULL_DIR_INFO d into the newly created fileStat. +func newFileStatFromFileFullDirInfo(d *windows.FILE_FULL_DIR_INFO) *fileStat { + return &fileStat{ + FileAttributes: d.FileAttributes, + CreationTime: d.CreationTime, + LastAccessTime: d.LastAccessTime, + LastWriteTime: d.LastWriteTime, + FileSizeHigh: uint32(d.EndOfFile >> 32), + FileSizeLow: uint32(d.EndOfFile), + ReparseTag: d.EaSize, + } +} + +// newFileStatFromWin32finddata copies all required information +// from syscall.Win32finddata d into the newly created fileStat. +func newFileStatFromWin32finddata(d *syscall.Win32finddata) *fileStat { + fs := &fileStat{ + FileAttributes: d.FileAttributes, + CreationTime: d.CreationTime, + LastAccessTime: d.LastAccessTime, + LastWriteTime: d.LastWriteTime, + FileSizeHigh: d.FileSizeHigh, + FileSizeLow: d.FileSizeLow, + } + if d.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { + // Per https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataw: + // “If the dwFileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT + // attribute, this member specifies the reparse point tag. Otherwise, this + // value is undefined and should not be used.” + fs.ReparseTag = d.Reserved0 + } + return fs +} + +// isReparseTagNameSurrogate determines whether a tag's associated +// reparse point is a surrogate for another named entity (for example, a mounted folder). +// +// See https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-isreparsetagnamesurrogate +// and https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-point-tags. +func (fs *fileStat) isReparseTagNameSurrogate() bool { + // True for IO_REPARSE_TAG_SYMLINK and IO_REPARSE_TAG_MOUNT_POINT. + return fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 && fs.ReparseTag&0x20000000 != 0 +} + +func (fs *fileStat) Size() int64 { + return int64(fs.FileSizeHigh)<<32 + int64(fs.FileSizeLow) +} + +var winsymlink = godebug.New("winsymlink") + +func (fs *fileStat) Mode() FileMode { + m := fs.mode() + if winsymlink.Value() == "0" { + old := fs.modePreGo1_23() + if old != m { + winsymlink.IncNonDefault() + m = old + } + } + return m +} + +func (fs *fileStat) mode() (m FileMode) { + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 { + m |= 0444 + } else { + m |= 0666 + } + + // Windows reports the FILE_ATTRIBUTE_DIRECTORY bit for reparse points + // that refer to directories, such as symlinks and mount points. + // However, we follow symlink POSIX semantics and do not set the mode bits. + // This allows users to walk directories without following links + // by just calling "fi, err := os.Lstat(name); err == nil && fi.IsDir()". + // Note that POSIX only defines the semantics for symlinks, not for + // mount points or other surrogate reparse points, but we treat them + // the same way for consistency. Also, mount points can contain infinite + // loops, so it is not safe to walk them without special handling. + if !fs.isReparseTagNameSurrogate() { + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { + m |= ModeDir | 0111 + } + + switch fs.filetype { + case syscall.FILE_TYPE_PIPE: + m |= ModeNamedPipe + case syscall.FILE_TYPE_CHAR: + m |= ModeDevice | ModeCharDevice + } + } + + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { + switch fs.ReparseTag { + case syscall.IO_REPARSE_TAG_SYMLINK: + m |= ModeSymlink + case windows.IO_REPARSE_TAG_AF_UNIX: + m |= ModeSocket + case windows.IO_REPARSE_TAG_DEDUP: + // If the Data Deduplication service is enabled on Windows Server, its + // Optimization job may convert regular files to IO_REPARSE_TAG_DEDUP + // whenever that job runs. + // + // However, DEDUP reparse points remain similar in most respects to + // regular files: they continue to support random-access reads and writes + // of persistent data, and they shouldn't add unexpected latency or + // unavailability in the way that a network filesystem might. + // + // Go programs may use ModeIrregular to filter out unusual files (such as + // raw device files on Linux, POSIX FIFO special files, and so on), so + // to avoid files changing unpredictably from regular to irregular we will + // consider DEDUP files to be close enough to regular to treat as such. + default: + m |= ModeIrregular + } + } + return +} + +// modePreGo1_23 returns the FileMode for the fileStat, using the pre-Go 1.23 +// logic for determining the file mode. +// The logic is subtle and not well-documented, so it is better to keep it +// separate from the new logic. +func (fs *fileStat) modePreGo1_23() (m FileMode) { + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 { + m |= 0444 + } else { + m |= 0666 + } + if fs.ReparseTag == syscall.IO_REPARSE_TAG_SYMLINK || + fs.ReparseTag == windows.IO_REPARSE_TAG_MOUNT_POINT { + return m | ModeSymlink + } + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { + m |= ModeDir | 0111 + } + switch fs.filetype { + case syscall.FILE_TYPE_PIPE: + m |= ModeNamedPipe + case syscall.FILE_TYPE_CHAR: + m |= ModeDevice | ModeCharDevice + } + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { + if fs.ReparseTag == windows.IO_REPARSE_TAG_AF_UNIX { + m |= ModeSocket + } + if m&ModeType == 0 { + if fs.ReparseTag == windows.IO_REPARSE_TAG_DEDUP { + // See comment in fs.Mode. + } else { + m |= ModeIrregular + } + } + } + return m +} + +func (fs *fileStat) ModTime() time.Time { + return time.Unix(0, fs.LastWriteTime.Nanoseconds()) +} + +// Sys returns syscall.Win32FileAttributeData for file fs. +func (fs *fileStat) Sys() any { + return &syscall.Win32FileAttributeData{ + FileAttributes: fs.FileAttributes, + CreationTime: fs.CreationTime, + LastAccessTime: fs.LastAccessTime, + LastWriteTime: fs.LastWriteTime, + FileSizeHigh: fs.FileSizeHigh, + FileSizeLow: fs.FileSizeLow, + } +} + +func (fs *fileStat) loadFileId() error { + fs.Lock() + defer fs.Unlock() + if fs.path == "" { + // already done + return nil + } + var path string + if fs.appendNameToPath { + path = fixLongPath(fs.path + `\` + fs.name) + } else { + path = fs.path + } + pathp, err := syscall.UTF16PtrFromString(path) + if err != nil { + return err + } + + // Per https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-points-and-file-operations, + // “Applications that use the CreateFile function should specify the + // FILE_FLAG_OPEN_REPARSE_POINT flag when opening the file if it is a reparse + // point.” + // + // And per https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew, + // “If the file is not a reparse point, then this flag is ignored.” + // + // So we set FILE_FLAG_OPEN_REPARSE_POINT unconditionally, since we want + // information about the reparse point itself. + // + // If the file is a symlink, the symlink target should have already been + // resolved when the fileStat was created, so we don't need to worry about + // resolving symlink reparse points again here. + attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS | syscall.FILE_FLAG_OPEN_REPARSE_POINT) + + h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0) + if err != nil { + return err + } + defer syscall.CloseHandle(h) + var i syscall.ByHandleFileInformation + err = syscall.GetFileInformationByHandle(h, &i) + if err != nil { + return err + } + fs.path = "" + fs.vol = i.VolumeSerialNumber + fs.idxhi = i.FileIndexHigh + fs.idxlo = i.FileIndexLow + return nil +} + +// saveInfoFromPath saves full path of the file to be used by os.SameFile later, +// and set name from path. +func (fs *fileStat) saveInfoFromPath(path string) error { + fs.path = path + if !filepathlite.IsAbs(fs.path) { + var err error + fs.path, err = syscall.FullPath(fs.path) + if err != nil { + return &PathError{Op: "FullPath", Path: path, Err: err} + } + } + fs.name = filepathlite.Base(path) + return nil +} + +func sameFile(fs1, fs2 *fileStat) bool { + e := fs1.loadFileId() + if e != nil { + return false + } + e = fs2.loadFileId() + if e != nil { + return false + } + return fs1.vol == fs2.vol && fs1.idxhi == fs2.idxhi && fs1.idxlo == fs2.idxlo +} + +// For testing. +func atime(fi FileInfo) time.Time { + return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) +} diff --git a/contrib/go/_std_1.22/src/os/user/cgo_listgroups_unix.go b/contrib/go/_std_1.23/src/os/user/cgo_listgroups_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/cgo_listgroups_unix.go rename to contrib/go/_std_1.23/src/os/user/cgo_listgroups_unix.go diff --git a/contrib/go/_std_1.22/src/os/user/cgo_lookup_cgo.go b/contrib/go/_std_1.23/src/os/user/cgo_lookup_cgo.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/cgo_lookup_cgo.go rename to contrib/go/_std_1.23/src/os/user/cgo_lookup_cgo.go diff --git a/contrib/go/_std_1.22/src/os/user/cgo_lookup_syscall.go b/contrib/go/_std_1.23/src/os/user/cgo_lookup_syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/cgo_lookup_syscall.go rename to contrib/go/_std_1.23/src/os/user/cgo_lookup_syscall.go diff --git a/contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go b/contrib/go/_std_1.23/src/os/user/cgo_lookup_unix.go similarity index 95% rename from contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go rename to contrib/go/_std_1.23/src/os/user/cgo_lookup_unix.go index 402429ba4ac5..458d8cd453ac 100644 --- a/contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go +++ b/contrib/go/_std_1.23/src/os/user/cgo_lookup_unix.go @@ -31,12 +31,12 @@ func lookupUser(username string) (*User, error) { (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf))) return errno }) + if err == syscall.ENOENT || (err == nil && !found) { + return nil, UnknownUserError(username) + } if err != nil { return nil, fmt.Errorf("user: lookup username %s: %v", username, err) } - if !found { - return nil, UnknownUserError(username) - } return buildUser(&pwd), err } @@ -58,12 +58,12 @@ func lookupUnixUid(uid int) (*User, error) { (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf))) return errno }) + if err == syscall.ENOENT || (err == nil && !found) { + return nil, UnknownUserIdError(uid) + } if err != nil { return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err) } - if !found { - return nil, UnknownUserIdError(uid) - } return buildUser(&pwd), nil } @@ -96,12 +96,12 @@ func lookupGroup(groupname string) (*Group, error) { (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf))) return errno }) + if err == syscall.ENOENT || (err == nil && !found) { + return nil, UnknownGroupError(groupname) + } if err != nil { return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err) } - if !found { - return nil, UnknownGroupError(groupname) - } return buildGroup(&grp), nil } @@ -123,12 +123,12 @@ func lookupUnixGid(gid int) (*Group, error) { (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf))) return syscall.Errno(errno) }) + if err == syscall.ENOENT || (err == nil && !found) { + return nil, UnknownGroupIdError(strconv.Itoa(gid)) + } if err != nil { return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err) } - if !found { - return nil, UnknownGroupIdError(strconv.Itoa(gid)) - } return buildGroup(&grp), nil } diff --git a/contrib/go/_std_1.22/src/os/user/getgrouplist_syscall.go b/contrib/go/_std_1.23/src/os/user/getgrouplist_syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/getgrouplist_syscall.go rename to contrib/go/_std_1.23/src/os/user/getgrouplist_syscall.go diff --git a/contrib/go/_std_1.22/src/os/user/getgrouplist_unix.go b/contrib/go/_std_1.23/src/os/user/getgrouplist_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/getgrouplist_unix.go rename to contrib/go/_std_1.23/src/os/user/getgrouplist_unix.go diff --git a/contrib/go/_std_1.22/src/os/user/listgroups_stub.go b/contrib/go/_std_1.23/src/os/user/listgroups_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/listgroups_stub.go rename to contrib/go/_std_1.23/src/os/user/listgroups_stub.go diff --git a/contrib/go/_std_1.22/src/os/user/listgroups_unix.go b/contrib/go/_std_1.23/src/os/user/listgroups_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/listgroups_unix.go rename to contrib/go/_std_1.23/src/os/user/listgroups_unix.go diff --git a/contrib/go/_std_1.23/src/os/user/lookup.go b/contrib/go/_std_1.23/src/os/user/lookup.go new file mode 100644 index 000000000000..fb10b53938bd --- /dev/null +++ b/contrib/go/_std_1.23/src/os/user/lookup.go @@ -0,0 +1,70 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package user + +import "sync" + +const ( + userFile = "/etc/passwd" + groupFile = "/etc/group" +) + +var colon = []byte{':'} + +// Current returns the current user. +// +// The first call will cache the current user information. +// Subsequent calls will return the cached value and will not reflect +// changes to the current user. +func Current() (*User, error) { + cache.Do(func() { cache.u, cache.err = current() }) + if cache.err != nil { + return nil, cache.err + } + u := *cache.u // copy + return &u, nil +} + +// cache of the current user +var cache struct { + sync.Once + u *User + err error +} + +// Lookup looks up a user by username. If the user cannot be found, the +// returned error is of type [UnknownUserError]. +func Lookup(username string) (*User, error) { + if u, err := Current(); err == nil && u.Username == username { + return u, err + } + return lookupUser(username) +} + +// LookupId looks up a user by userid. If the user cannot be found, the +// returned error is of type [UnknownUserIdError]. +func LookupId(uid string) (*User, error) { + if u, err := Current(); err == nil && u.Uid == uid { + return u, err + } + return lookupUserId(uid) +} + +// LookupGroup looks up a group by name. If the group cannot be found, the +// returned error is of type [UnknownGroupError]. +func LookupGroup(name string) (*Group, error) { + return lookupGroup(name) +} + +// LookupGroupId looks up a group by groupid. If the group cannot be found, the +// returned error is of type [UnknownGroupIdError]. +func LookupGroupId(gid string) (*Group, error) { + return lookupGroupId(gid) +} + +// GroupIds returns the list of group IDs that the user is a member of. +func (u *User) GroupIds() ([]string, error) { + return listGroups(u) +} diff --git a/contrib/go/_std_1.22/src/os/user/lookup_android.go b/contrib/go/_std_1.23/src/os/user/lookup_android.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_android.go rename to contrib/go/_std_1.23/src/os/user/lookup_android.go diff --git a/contrib/go/_std_1.22/src/os/user/lookup_plan9.go b/contrib/go/_std_1.23/src/os/user/lookup_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_plan9.go rename to contrib/go/_std_1.23/src/os/user/lookup_plan9.go diff --git a/contrib/go/_std_1.22/src/os/user/lookup_stubs.go b/contrib/go/_std_1.23/src/os/user/lookup_stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_stubs.go rename to contrib/go/_std_1.23/src/os/user/lookup_stubs.go diff --git a/contrib/go/_std_1.22/src/os/user/lookup_unix.go b/contrib/go/_std_1.23/src/os/user/lookup_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_unix.go rename to contrib/go/_std_1.23/src/os/user/lookup_unix.go diff --git a/contrib/go/_std_1.22/src/os/user/lookup_windows.go b/contrib/go/_std_1.23/src/os/user/lookup_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_windows.go rename to contrib/go/_std_1.23/src/os/user/lookup_windows.go diff --git a/contrib/go/_std_1.22/src/os/user/user.go b/contrib/go/_std_1.23/src/os/user/user.go similarity index 91% rename from contrib/go/_std_1.22/src/os/user/user.go rename to contrib/go/_std_1.23/src/os/user/user.go index 0307d2ad6a12..952da3d8bdab 100644 --- a/contrib/go/_std_1.22/src/os/user/user.go +++ b/contrib/go/_std_1.23/src/os/user/user.go @@ -63,14 +63,14 @@ type Group struct { Name string // group name } -// UnknownUserIdError is returned by LookupId when a user cannot be found. +// UnknownUserIdError is returned by [LookupId] when a user cannot be found. type UnknownUserIdError int func (e UnknownUserIdError) Error() string { return "user: unknown userid " + strconv.Itoa(int(e)) } -// UnknownUserError is returned by Lookup when +// UnknownUserError is returned by [Lookup] when // a user cannot be found. type UnknownUserError string @@ -78,7 +78,7 @@ func (e UnknownUserError) Error() string { return "user: unknown user " + string(e) } -// UnknownGroupIdError is returned by LookupGroupId when +// UnknownGroupIdError is returned by [LookupGroupId] when // a group cannot be found. type UnknownGroupIdError string @@ -86,7 +86,7 @@ func (e UnknownGroupIdError) Error() string { return "group: unknown groupid " + string(e) } -// UnknownGroupError is returned by LookupGroup when +// UnknownGroupError is returned by [LookupGroup] when // a group cannot be found. type UnknownGroupError string diff --git a/contrib/go/_std_1.23/src/os/user/ya.make b/contrib/go/_std_1.23/src/os/user/ya.make new file mode 100644 index 000000000000..aa89e4080031 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/user/ya.make @@ -0,0 +1,42 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + cgo_listgroups_unix.go + cgo_lookup_syscall.go + cgo_lookup_unix.go + getgrouplist_syscall.go + lookup.go + user.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED) + SRCS( + cgo_listgroups_unix.go + cgo_lookup_unix.go + lookup.go + user.go + ) + +IF (CGO_ENABLED) + CGO_SRCS( + cgo_lookup_cgo.go + getgrouplist_unix.go + ) +ENDIF() +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + listgroups_unix.go + lookup.go + lookup_stubs.go + lookup_unix.go + user.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + lookup.go + lookup_windows.go + user.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/os/wait6_dragonfly.go b/contrib/go/_std_1.23/src/os/wait6_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_dragonfly.go rename to contrib/go/_std_1.23/src/os/wait6_dragonfly.go diff --git a/contrib/go/_std_1.22/src/os/wait6_freebsd64.go b/contrib/go/_std_1.23/src/os/wait6_freebsd64.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_freebsd64.go rename to contrib/go/_std_1.23/src/os/wait6_freebsd64.go diff --git a/contrib/go/_std_1.22/src/os/wait6_freebsd_386.go b/contrib/go/_std_1.23/src/os/wait6_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_freebsd_386.go rename to contrib/go/_std_1.23/src/os/wait6_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/os/wait6_freebsd_arm.go b/contrib/go/_std_1.23/src/os/wait6_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_freebsd_arm.go rename to contrib/go/_std_1.23/src/os/wait6_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/os/wait6_netbsd.go b/contrib/go/_std_1.23/src/os/wait6_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_netbsd.go rename to contrib/go/_std_1.23/src/os/wait6_netbsd.go diff --git a/contrib/go/_std_1.22/src/os/wait_unimp.go b/contrib/go/_std_1.23/src/os/wait_unimp.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait_unimp.go rename to contrib/go/_std_1.23/src/os/wait_unimp.go diff --git a/contrib/go/_std_1.22/src/os/wait_wait6.go b/contrib/go/_std_1.23/src/os/wait_wait6.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait_wait6.go rename to contrib/go/_std_1.23/src/os/wait_wait6.go diff --git a/contrib/go/_std_1.22/src/os/wait_waitid.go b/contrib/go/_std_1.23/src/os/wait_waitid.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait_waitid.go rename to contrib/go/_std_1.23/src/os/wait_waitid.go diff --git a/contrib/go/_std_1.23/src/os/ya.make b/contrib/go/_std_1.23/src/os/ya.make new file mode 100644 index 000000000000..1a4ab0f67e0c --- /dev/null +++ b/contrib/go/_std_1.23/src/os/ya.make @@ -0,0 +1,112 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + dir.go + dir_darwin.go + env.go + error.go + error_errno.go + exec.go + exec_nohandle.go + exec_posix.go + exec_unix.go + executable.go + executable_darwin.go + file.go + file_open_unix.go + file_posix.go + file_unix.go + getwd.go + path.go + path_unix.go + pidfd_other.go + pipe_unix.go + proc.go + rawconn.go + removeall_at.go + stat.go + stat_darwin.go + stat_unix.go + sticky_bsd.go + sys.go + sys_bsd.go + sys_unix.go + tempfile.go + types.go + types_unix.go + wait_unimp.go + zero_copy_stub.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + dir.go + dir_unix.go + dirent_linux.go + env.go + error.go + error_errno.go + exec.go + exec_linux.go + exec_posix.go + exec_unix.go + executable.go + executable_procfs.go + file.go + file_open_unix.go + file_posix.go + file_unix.go + getwd.go + path.go + path_unix.go + pidfd_linux.go + pipe2_unix.go + proc.go + rawconn.go + removeall_at.go + stat.go + stat_linux.go + stat_unix.go + sticky_notbsd.go + sys.go + sys_linux.go + sys_unix.go + tempfile.go + types.go + types_unix.go + wait_waitid.go + zero_copy_linux.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + dir.go + dir_windows.go + env.go + error.go + error_errno.go + exec.go + exec_posix.go + exec_windows.go + executable.go + executable_windows.go + file.go + file_posix.go + file_windows.go + getwd.go + path.go + path_windows.go + pidfd_other.go + proc.go + rawconn.go + removeall_noat.go + stat.go + stat_windows.go + sticky_notbsd.go + sys.go + sys_windows.go + tempfile.go + types.go + types_windows.go + zero_copy_stub.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/os/zero_copy_linux.go b/contrib/go/_std_1.23/src/os/zero_copy_linux.go similarity index 89% rename from contrib/go/_std_1.22/src/os/zero_copy_linux.go rename to contrib/go/_std_1.23/src/os/zero_copy_linux.go index 7c45aefeee86..0afc19e125a2 100644 --- a/contrib/go/_std_1.22/src/os/zero_copy_linux.go +++ b/contrib/go/_std_1.23/src/os/zero_copy_linux.go @@ -13,9 +13,17 @@ import ( var ( pollCopyFileRange = poll.CopyFileRange pollSplice = poll.Splice - pollSendFile = poll.SendFile ) +// wrapSyscallError takes an error and a syscall name. If the error is +// a syscall.Errno, it wraps it in an os.SyscallError using the syscall name. +func wrapSyscallError(name string, err error) error { + if _, ok := err.(syscall.Errno); ok { + err = NewSyscallError(name, err) + } + return err +} + func (f *File) writeTo(w io.Writer) (written int64, handled bool, err error) { pfd, network := getPollFDAndNetwork(w) // TODO(panjf2000): same as File.spliceToFile. @@ -29,7 +37,7 @@ func (f *File) writeTo(w io.Writer) (written int64, handled bool, err error) { } rerr := sc.Read(func(fd uintptr) (done bool) { - written, err, handled = pollSendFile(pfd, int(fd), 1<<63-1) + written, err, handled = poll.SendFile(pfd, int(fd), 1<<63-1) return true }) @@ -78,14 +86,13 @@ func (f *File) spliceToFile(r io.Reader) (written int64, handled bool, err error return } - var syscallName string - written, handled, syscallName, err = pollSplice(&f.pfd, pfd, remain) + written, handled, err = pollSplice(&f.pfd, pfd, remain) if lr != nil { lr.N = remain - written } - return written, handled, wrapSyscallError(syscallName, err) + return written, handled, wrapSyscallError("splice", err) } func (f *File) copyFileRange(r io.Reader) (written int64, handled bool, err error) { diff --git a/contrib/go/_std_1.22/src/os/zero_copy_stub.go b/contrib/go/_std_1.23/src/os/zero_copy_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/os/zero_copy_stub.go rename to contrib/go/_std_1.23/src/os/zero_copy_stub.go diff --git a/contrib/go/_std_1.22/src/path/filepath/match.go b/contrib/go/_std_1.23/src/path/filepath/match.go similarity index 98% rename from contrib/go/_std_1.22/src/path/filepath/match.go rename to contrib/go/_std_1.23/src/path/filepath/match.go index 12f0bfa7d3e8..b93e89adb03a 100644 --- a/contrib/go/_std_1.22/src/path/filepath/match.go +++ b/contrib/go/_std_1.23/src/path/filepath/match.go @@ -6,9 +6,10 @@ package filepath import ( "errors" + "internal/filepathlite" "os" "runtime" - "sort" + "slices" "strings" "unicode/utf8" ) @@ -307,7 +308,7 @@ func cleanGlobPath(path string) string { // cleanGlobPathWindows is windows version of cleanGlobPath. func cleanGlobPathWindows(path string) (prefixLen int, cleaned string) { - vollen := volumeNameLen(path) + vollen := filepathlite.VolumeNameLen(path) switch { case path == "": return 0, "." @@ -344,7 +345,7 @@ func glob(dir, pattern string, matches []string) (m []string, e error) { defer d.Close() names, _ := d.Readdirnames(-1) - sort.Strings(names) + slices.Sort(names) for _, n := range names { matched, err := Match(pattern, n) diff --git a/contrib/go/_std_1.23/src/path/filepath/path.go b/contrib/go/_std_1.23/src/path/filepath/path.go new file mode 100644 index 000000000000..5ffd9f0b6c3f --- /dev/null +++ b/contrib/go/_std_1.23/src/path/filepath/path.go @@ -0,0 +1,475 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package filepath implements utility routines for manipulating filename paths +// in a way compatible with the target operating system-defined file paths. +// +// The filepath package uses either forward slashes or backslashes, +// depending on the operating system. To process paths such as URLs +// that always use forward slashes regardless of the operating +// system, see the [path] package. +package filepath + +import ( + "errors" + "internal/bytealg" + "internal/filepathlite" + "io/fs" + "os" + "slices" +) + +const ( + Separator = os.PathSeparator + ListSeparator = os.PathListSeparator +) + +// Clean returns the shortest path name equivalent to path +// by purely lexical processing. It applies the following rules +// iteratively until no further processing can be done: +// +// 1. Replace multiple [Separator] elements with a single one. +// 2. Eliminate each . path name element (the current directory). +// 3. Eliminate each inner .. path name element (the parent directory) +// along with the non-.. element that precedes it. +// 4. Eliminate .. elements that begin a rooted path: +// that is, replace "/.." by "/" at the beginning of a path, +// assuming Separator is '/'. +// +// The returned path ends in a slash only if it represents a root directory, +// such as "/" on Unix or `C:\` on Windows. +// +// Finally, any occurrences of slash are replaced by Separator. +// +// If the result of this process is an empty string, Clean +// returns the string ".". +// +// On Windows, Clean does not modify the volume name other than to replace +// occurrences of "/" with `\`. +// For example, Clean("//host/share/../x") returns `\\host\share\x`. +// +// See also Rob Pike, “Lexical File Names in Plan 9 or +// Getting Dot-Dot Right,” +// https://9p.io/sys/doc/lexnames.html +func Clean(path string) string { + return filepathlite.Clean(path) +} + +// IsLocal reports whether path, using lexical analysis only, has all of these properties: +// +// - is within the subtree rooted at the directory in which path is evaluated +// - is not an absolute path +// - is not empty +// - on Windows, is not a reserved name such as "NUL" +// +// If IsLocal(path) returns true, then +// Join(base, path) will always produce a path contained within base and +// Clean(path) will always produce an unrooted path with no ".." path elements. +// +// IsLocal is a purely lexical operation. +// In particular, it does not account for the effect of any symbolic links +// that may exist in the filesystem. +func IsLocal(path string) bool { + return filepathlite.IsLocal(path) +} + +// Localize converts a slash-separated path into an operating system path. +// The input path must be a valid path as reported by [io/fs.ValidPath]. +// +// Localize returns an error if the path cannot be represented by the operating system. +// For example, the path a\b is rejected on Windows, on which \ is a separator +// character and cannot be part of a filename. +// +// The path returned by Localize will always be local, as reported by IsLocal. +func Localize(path string) (string, error) { + return filepathlite.Localize(path) +} + +// ToSlash returns the result of replacing each separator character +// in path with a slash ('/') character. Multiple separators are +// replaced by multiple slashes. +func ToSlash(path string) string { + return filepathlite.ToSlash(path) +} + +// FromSlash returns the result of replacing each slash ('/') character +// in path with a separator character. Multiple slashes are replaced +// by multiple separators. +// +// See also the Localize function, which converts a slash-separated path +// as used by the io/fs package to an operating system path. +func FromSlash(path string) string { + return filepathlite.FromSlash(path) +} + +// SplitList splits a list of paths joined by the OS-specific [ListSeparator], +// usually found in PATH or GOPATH environment variables. +// Unlike strings.Split, SplitList returns an empty slice when passed an empty +// string. +func SplitList(path string) []string { + return splitList(path) +} + +// Split splits path immediately following the final [Separator], +// separating it into a directory and file name component. +// If there is no Separator in path, Split returns an empty dir +// and file set to path. +// The returned values have the property that path = dir+file. +func Split(path string) (dir, file string) { + return filepathlite.Split(path) +} + +// Join joins any number of path elements into a single path, +// separating them with an OS specific [Separator]. Empty elements +// are ignored. The result is Cleaned. However, if the argument +// list is empty or all its elements are empty, Join returns +// an empty string. +// On Windows, the result will only be a UNC path if the first +// non-empty element is a UNC path. +func Join(elem ...string) string { + return join(elem) +} + +// Ext returns the file name extension used by path. +// The extension is the suffix beginning at the final dot +// in the final element of path; it is empty if there is +// no dot. +func Ext(path string) string { + return filepathlite.Ext(path) +} + +// EvalSymlinks returns the path name after the evaluation of any symbolic +// links. +// If path is relative the result will be relative to the current directory, +// unless one of the components is an absolute symbolic link. +// EvalSymlinks calls [Clean] on the result. +func EvalSymlinks(path string) (string, error) { + return evalSymlinks(path) +} + +// IsAbs reports whether the path is absolute. +func IsAbs(path string) bool { + return filepathlite.IsAbs(path) +} + +// Abs returns an absolute representation of path. +// If the path is not absolute it will be joined with the current +// working directory to turn it into an absolute path. The absolute +// path name for a given file is not guaranteed to be unique. +// Abs calls [Clean] on the result. +func Abs(path string) (string, error) { + return abs(path) +} + +func unixAbs(path string) (string, error) { + if IsAbs(path) { + return Clean(path), nil + } + wd, err := os.Getwd() + if err != nil { + return "", err + } + return Join(wd, path), nil +} + +// Rel returns a relative path that is lexically equivalent to targpath when +// joined to basepath with an intervening separator. That is, +// [Join](basepath, Rel(basepath, targpath)) is equivalent to targpath itself. +// On success, the returned path will always be relative to basepath, +// even if basepath and targpath share no elements. +// An error is returned if targpath can't be made relative to basepath or if +// knowing the current working directory would be necessary to compute it. +// Rel calls [Clean] on the result. +func Rel(basepath, targpath string) (string, error) { + baseVol := VolumeName(basepath) + targVol := VolumeName(targpath) + base := Clean(basepath) + targ := Clean(targpath) + if sameWord(targ, base) { + return ".", nil + } + base = base[len(baseVol):] + targ = targ[len(targVol):] + if base == "." { + base = "" + } else if base == "" && filepathlite.VolumeNameLen(baseVol) > 2 /* isUNC */ { + // Treat any targetpath matching `\\host\share` basepath as absolute path. + base = string(Separator) + } + + // Can't use IsAbs - `\a` and `a` are both relative in Windows. + baseSlashed := len(base) > 0 && base[0] == Separator + targSlashed := len(targ) > 0 && targ[0] == Separator + if baseSlashed != targSlashed || !sameWord(baseVol, targVol) { + return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) + } + // Position base[b0:bi] and targ[t0:ti] at the first differing elements. + bl := len(base) + tl := len(targ) + var b0, bi, t0, ti int + for { + for bi < bl && base[bi] != Separator { + bi++ + } + for ti < tl && targ[ti] != Separator { + ti++ + } + if !sameWord(targ[t0:ti], base[b0:bi]) { + break + } + if bi < bl { + bi++ + } + if ti < tl { + ti++ + } + b0 = bi + t0 = ti + } + if base[b0:bi] == ".." { + return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) + } + if b0 != bl { + // Base elements left. Must go up before going down. + seps := bytealg.CountString(base[b0:bl], Separator) + size := 2 + seps*3 + if tl != t0 { + size += 1 + tl - t0 + } + buf := make([]byte, size) + n := copy(buf, "..") + for i := 0; i < seps; i++ { + buf[n] = Separator + copy(buf[n+1:], "..") + n += 3 + } + if t0 != tl { + buf[n] = Separator + copy(buf[n+1:], targ[t0:]) + } + return string(buf), nil + } + return targ[t0:], nil +} + +// SkipDir is used as a return value from [WalkFunc] to indicate that +// the directory named in the call is to be skipped. It is not returned +// as an error by any function. +var SkipDir error = fs.SkipDir + +// SkipAll is used as a return value from [WalkFunc] to indicate that +// all remaining files and directories are to be skipped. It is not returned +// as an error by any function. +var SkipAll error = fs.SkipAll + +// WalkFunc is the type of the function called by [Walk] to visit each +// file or directory. +// +// The path argument contains the argument to Walk as a prefix. +// That is, if Walk is called with root argument "dir" and finds a file +// named "a" in that directory, the walk function will be called with +// argument "dir/a". +// +// The directory and file are joined with Join, which may clean the +// directory name: if Walk is called with the root argument "x/../dir" +// and finds a file named "a" in that directory, the walk function will +// be called with argument "dir/a", not "x/../dir/a". +// +// The info argument is the fs.FileInfo for the named path. +// +// The error result returned by the function controls how Walk continues. +// If the function returns the special value [SkipDir], Walk skips the +// current directory (path if info.IsDir() is true, otherwise path's +// parent directory). If the function returns the special value [SkipAll], +// Walk skips all remaining files and directories. Otherwise, if the function +// returns a non-nil error, Walk stops entirely and returns that error. +// +// The err argument reports an error related to path, signaling that Walk +// will not walk into that directory. The function can decide how to +// handle that error; as described earlier, returning the error will +// cause Walk to stop walking the entire tree. +// +// Walk calls the function with a non-nil err argument in two cases. +// +// First, if an [os.Lstat] on the root directory or any directory or file +// in the tree fails, Walk calls the function with path set to that +// directory or file's path, info set to nil, and err set to the error +// from os.Lstat. +// +// Second, if a directory's Readdirnames method fails, Walk calls the +// function with path set to the directory's path, info, set to an +// [fs.FileInfo] describing the directory, and err set to the error from +// Readdirnames. +type WalkFunc func(path string, info fs.FileInfo, err error) error + +var lstat = os.Lstat // for testing + +// walkDir recursively descends path, calling walkDirFn. +func walkDir(path string, d fs.DirEntry, walkDirFn fs.WalkDirFunc) error { + if err := walkDirFn(path, d, nil); err != nil || !d.IsDir() { + if err == SkipDir && d.IsDir() { + // Successfully skipped directory. + err = nil + } + return err + } + + dirs, err := os.ReadDir(path) + if err != nil { + // Second call, to report ReadDir error. + err = walkDirFn(path, d, err) + if err != nil { + if err == SkipDir && d.IsDir() { + err = nil + } + return err + } + } + + for _, d1 := range dirs { + path1 := Join(path, d1.Name()) + if err := walkDir(path1, d1, walkDirFn); err != nil { + if err == SkipDir { + break + } + return err + } + } + return nil +} + +// walk recursively descends path, calling walkFn. +func walk(path string, info fs.FileInfo, walkFn WalkFunc) error { + if !info.IsDir() { + return walkFn(path, info, nil) + } + + names, err := readDirNames(path) + err1 := walkFn(path, info, err) + // If err != nil, walk can't walk into this directory. + // err1 != nil means walkFn want walk to skip this directory or stop walking. + // Therefore, if one of err and err1 isn't nil, walk will return. + if err != nil || err1 != nil { + // The caller's behavior is controlled by the return value, which is decided + // by walkFn. walkFn may ignore err and return nil. + // If walkFn returns SkipDir or SkipAll, it will be handled by the caller. + // So walk should return whatever walkFn returns. + return err1 + } + + for _, name := range names { + filename := Join(path, name) + fileInfo, err := lstat(filename) + if err != nil { + if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir { + return err + } + } else { + err = walk(filename, fileInfo, walkFn) + if err != nil { + if !fileInfo.IsDir() || err != SkipDir { + return err + } + } + } + } + return nil +} + +// WalkDir walks the file tree rooted at root, calling fn for each file or +// directory in the tree, including root. +// +// All errors that arise visiting files and directories are filtered by fn: +// see the [fs.WalkDirFunc] documentation for details. +// +// The files are walked in lexical order, which makes the output deterministic +// but requires WalkDir to read an entire directory into memory before proceeding +// to walk that directory. +// +// WalkDir does not follow symbolic links. +// +// WalkDir calls fn with paths that use the separator character appropriate +// for the operating system. This is unlike [io/fs.WalkDir], which always +// uses slash separated paths. +func WalkDir(root string, fn fs.WalkDirFunc) error { + info, err := os.Lstat(root) + if err != nil { + err = fn(root, nil, err) + } else { + err = walkDir(root, fs.FileInfoToDirEntry(info), fn) + } + if err == SkipDir || err == SkipAll { + return nil + } + return err +} + +// Walk walks the file tree rooted at root, calling fn for each file or +// directory in the tree, including root. +// +// All errors that arise visiting files and directories are filtered by fn: +// see the [WalkFunc] documentation for details. +// +// The files are walked in lexical order, which makes the output deterministic +// but requires Walk to read an entire directory into memory before proceeding +// to walk that directory. +// +// Walk does not follow symbolic links. +// +// Walk is less efficient than [WalkDir], introduced in Go 1.16, +// which avoids calling os.Lstat on every visited file or directory. +func Walk(root string, fn WalkFunc) error { + info, err := os.Lstat(root) + if err != nil { + err = fn(root, nil, err) + } else { + err = walk(root, info, fn) + } + if err == SkipDir || err == SkipAll { + return nil + } + return err +} + +// readDirNames reads the directory named by dirname and returns +// a sorted list of directory entry names. +func readDirNames(dirname string) ([]string, error) { + f, err := os.Open(dirname) + if err != nil { + return nil, err + } + names, err := f.Readdirnames(-1) + f.Close() + if err != nil { + return nil, err + } + slices.Sort(names) + return names, nil +} + +// Base returns the last element of path. +// Trailing path separators are removed before extracting the last element. +// If the path is empty, Base returns ".". +// If the path consists entirely of separators, Base returns a single separator. +func Base(path string) string { + return filepathlite.Base(path) +} + +// Dir returns all but the last element of path, typically the path's directory. +// After dropping the final element, Dir calls [Clean] on the path and trailing +// slashes are removed. +// If the path is empty, Dir returns ".". +// If the path consists entirely of separators, Dir returns a single separator. +// The returned path does not end in a separator unless it is the root directory. +func Dir(path string) string { + return filepathlite.Dir(path) +} + +// VolumeName returns leading volume name. +// Given "C:\foo\bar" it returns "C:" on Windows. +// Given "\\host\share\foo" it returns "\\host\share". +// On other platforms it returns "". +func VolumeName(path string) string { + return filepathlite.VolumeName(path) +} diff --git a/contrib/go/_std_1.23/src/path/filepath/path_plan9.go b/contrib/go/_std_1.23/src/path/filepath/path_plan9.go new file mode 100644 index 000000000000..0e5147b90b6c --- /dev/null +++ b/contrib/go/_std_1.23/src/path/filepath/path_plan9.go @@ -0,0 +1,42 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package filepath + +import ( + "strings" +) + +// HasPrefix exists for historical compatibility and should not be used. +// +// Deprecated: HasPrefix does not respect path boundaries and +// does not ignore case when required. +func HasPrefix(p, prefix string) bool { + return strings.HasPrefix(p, prefix) +} + +func splitList(path string) []string { + if path == "" { + return []string{} + } + return strings.Split(path, string(ListSeparator)) +} + +func abs(path string) (string, error) { + return unixAbs(path) +} + +func join(elem []string) string { + // If there's a bug here, fix the logic in ./path_unix.go too. + for i, e := range elem { + if e != "" { + return Clean(strings.Join(elem[i:], string(Separator))) + } + } + return "" +} + +func sameWord(a, b string) bool { + return a == b +} diff --git a/contrib/go/_std_1.23/src/path/filepath/path_unix.go b/contrib/go/_std_1.23/src/path/filepath/path_unix.go new file mode 100644 index 000000000000..6bc974db3fbe --- /dev/null +++ b/contrib/go/_std_1.23/src/path/filepath/path_unix.go @@ -0,0 +1,44 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || (js && wasm) || wasip1 + +package filepath + +import ( + "strings" +) + +// HasPrefix exists for historical compatibility and should not be used. +// +// Deprecated: HasPrefix does not respect path boundaries and +// does not ignore case when required. +func HasPrefix(p, prefix string) bool { + return strings.HasPrefix(p, prefix) +} + +func splitList(path string) []string { + if path == "" { + return []string{} + } + return strings.Split(path, string(ListSeparator)) +} + +func abs(path string) (string, error) { + return unixAbs(path) +} + +func join(elem []string) string { + // If there's a bug here, fix the logic in ./path_plan9.go too. + for i, e := range elem { + if e != "" { + return Clean(strings.Join(elem[i:], string(Separator))) + } + } + return "" +} + +func sameWord(a, b string) bool { + return a == b +} diff --git a/contrib/go/_std_1.23/src/path/filepath/path_windows.go b/contrib/go/_std_1.23/src/path/filepath/path_windows.go new file mode 100644 index 000000000000..d53f87f1ac1a --- /dev/null +++ b/contrib/go/_std_1.23/src/path/filepath/path_windows.go @@ -0,0 +1,114 @@ +package filepath + +import ( + "os" + "strings" + "syscall" +) + +// HasPrefix exists for historical compatibility and should not be used. +// +// Deprecated: HasPrefix does not respect path boundaries and +// does not ignore case when required. +func HasPrefix(p, prefix string) bool { + if strings.HasPrefix(p, prefix) { + return true + } + return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix)) +} + +func splitList(path string) []string { + // The same implementation is used in LookPath in os/exec; + // consider changing os/exec when changing this. + + if path == "" { + return []string{} + } + + // Split path, respecting but preserving quotes. + list := []string{} + start := 0 + quo := false + for i := 0; i < len(path); i++ { + switch c := path[i]; { + case c == '"': + quo = !quo + case c == ListSeparator && !quo: + list = append(list, path[start:i]) + start = i + 1 + } + } + list = append(list, path[start:]) + + // Remove quotes. + for i, s := range list { + list[i] = strings.ReplaceAll(s, `"`, ``) + } + + return list +} + +func abs(path string) (string, error) { + if path == "" { + // syscall.FullPath returns an error on empty path, because it's not a valid path. + // To implement Abs behavior of returning working directory on empty string input, + // special-case empty path by changing it to "." path. See golang.org/issue/24441. + path = "." + } + fullPath, err := syscall.FullPath(path) + if err != nil { + return "", err + } + return Clean(fullPath), nil +} + +func join(elem []string) string { + var b strings.Builder + var lastChar byte + for _, e := range elem { + switch { + case b.Len() == 0: + // Add the first non-empty path element unchanged. + case os.IsPathSeparator(lastChar): + // If the path ends in a slash, strip any leading slashes from the next + // path element to avoid creating a UNC path (any path starting with "\\") + // from non-UNC elements. + // + // The correct behavior for Join when the first element is an incomplete UNC + // path (for example, "\\") is underspecified. We currently join subsequent + // elements so Join("\\", "host", "share") produces "\\host\share". + for len(e) > 0 && os.IsPathSeparator(e[0]) { + e = e[1:] + } + // If the path is \ and the next path element is ??, + // add an extra .\ to create \.\?? rather than \??\ + // (a Root Local Device path). + if b.Len() == 1 && strings.HasPrefix(e, "??") && (len(e) == len("??") || os.IsPathSeparator(e[2])) { + b.WriteString(`.\`) + } + case lastChar == ':': + // If the path ends in a colon, keep the path relative to the current directory + // on a drive and don't add a separator. Preserve leading slashes in the next + // path element, which may make the path absolute. + // + // Join(`C:`, `f`) = `C:f` + // Join(`C:`, `\f`) = `C:\f` + default: + // In all other cases, add a separator between elements. + b.WriteByte('\\') + lastChar = '\\' + } + if len(e) > 0 { + b.WriteString(e) + lastChar = e[len(e)-1] + } + } + if b.Len() == 0 { + return "" + } + return Clean(b.String()) +} + +func sameWord(a, b string) bool { + return strings.EqualFold(a, b) +} diff --git a/contrib/go/_std_1.22/src/path/filepath/symlink.go b/contrib/go/_std_1.23/src/path/filepath/symlink.go similarity index 91% rename from contrib/go/_std_1.22/src/path/filepath/symlink.go rename to contrib/go/_std_1.23/src/path/filepath/symlink.go index f9435e0d5b90..a6047ae44437 100644 --- a/contrib/go/_std_1.22/src/path/filepath/symlink.go +++ b/contrib/go/_std_1.23/src/path/filepath/symlink.go @@ -6,6 +6,7 @@ package filepath import ( "errors" + "internal/filepathlite" "io/fs" "os" "runtime" @@ -13,7 +14,7 @@ import ( ) func walkSymlinks(path string) (string, error) { - volLen := volumeNameLen(path) + volLen := filepathlite.VolumeNameLen(path) pathSeparator := string(os.PathSeparator) if volLen < len(path) && os.IsPathSeparator(path[volLen]) { @@ -34,7 +35,7 @@ func walkSymlinks(path string) (string, error) { // On Windows, "." can be a symlink. // We look it up, and use the value if it is absolute. // If not, we just return ".". - isWindowsDot := runtime.GOOS == "windows" && path[volumeNameLen(path):] == "." + isWindowsDot := runtime.GOOS == "windows" && path[filepathlite.VolumeNameLen(path):] == "." // The next path component is in path[start:end]. if end == start { @@ -73,7 +74,7 @@ func walkSymlinks(path string) (string, error) { // Ordinary path component. Add it to result. - if len(dest) > volumeNameLen(dest) && !os.IsPathSeparator(dest[len(dest)-1]) { + if len(dest) > filepathlite.VolumeNameLen(dest) && !os.IsPathSeparator(dest[len(dest)-1]) { dest += pathSeparator } @@ -113,7 +114,7 @@ func walkSymlinks(path string) (string, error) { path = link + path[end:] - v := volumeNameLen(link) + v := filepathlite.VolumeNameLen(link) if v > 0 { // Symlink to drive name is an absolute path. if v < len(link) && os.IsPathSeparator(link[v]) { diff --git a/contrib/go/_std_1.22/src/path/filepath/symlink_plan9.go b/contrib/go/_std_1.23/src/path/filepath/symlink_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/path/filepath/symlink_plan9.go rename to contrib/go/_std_1.23/src/path/filepath/symlink_plan9.go diff --git a/contrib/go/_std_1.22/src/path/filepath/symlink_unix.go b/contrib/go/_std_1.23/src/path/filepath/symlink_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/path/filepath/symlink_unix.go rename to contrib/go/_std_1.23/src/path/filepath/symlink_unix.go diff --git a/contrib/go/_std_1.22/src/path/filepath/symlink_windows.go b/contrib/go/_std_1.23/src/path/filepath/symlink_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/path/filepath/symlink_windows.go rename to contrib/go/_std_1.23/src/path/filepath/symlink_windows.go diff --git a/contrib/go/_std_1.23/src/path/filepath/ya.make b/contrib/go/_std_1.23/src/path/filepath/ya.make new file mode 100644 index 000000000000..1c967ca84c62 --- /dev/null +++ b/contrib/go/_std_1.23/src/path/filepath/ya.make @@ -0,0 +1,19 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + match.go + path.go + path_unix.go + symlink.go + symlink_unix.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + match.go + path.go + path_windows.go + symlink.go + symlink_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/path/match.go b/contrib/go/_std_1.23/src/path/match.go similarity index 100% rename from contrib/go/_std_1.22/src/path/match.go rename to contrib/go/_std_1.23/src/path/match.go diff --git a/contrib/go/_std_1.22/src/path/path.go b/contrib/go/_std_1.23/src/path/path.go similarity index 100% rename from contrib/go/_std_1.22/src/path/path.go rename to contrib/go/_std_1.23/src/path/path.go diff --git a/contrib/go/_std_1.22/src/path/ya.make b/contrib/go/_std_1.23/src/path/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/path/ya.make rename to contrib/go/_std_1.23/src/path/ya.make diff --git a/contrib/go/_std_1.22/src/reflect/abi.go b/contrib/go/_std_1.23/src/reflect/abi.go similarity index 99% rename from contrib/go/_std_1.22/src/reflect/abi.go rename to contrib/go/_std_1.23/src/reflect/abi.go index 2b5f40538057..b67d8217430d 100644 --- a/contrib/go/_std_1.22/src/reflect/abi.go +++ b/contrib/go/_std_1.23/src/reflect/abi.go @@ -166,7 +166,7 @@ func (a *abiSeq) addRcvr(rcvr *abi.Type) (*abiStep, bool) { // The receiver is always one word. a.valueStart = append(a.valueStart, len(a.steps)) var ok, ptr bool - if ifaceIndir(rcvr) || rcvr.Pointers() { + if rcvr.IfaceIndir() || rcvr.Pointers() { ok = a.assignIntN(0, goarch.PtrSize, 1, 0b1) ptr = true } else { diff --git a/contrib/go/_std_1.23/src/reflect/arena.go b/contrib/go/_std_1.23/src/reflect/arena.go new file mode 100644 index 000000000000..769f8ebc7401 --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/arena.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build goexperiment.arenas + +package reflect + +import "arena" + +// ArenaNew returns a [Value] representing a pointer to a new zero value for the +// specified type, allocating storage for it in the provided arena. That is, +// the returned Value's Type is [PointerTo](typ). +func ArenaNew(a *arena.Arena, typ Type) Value { + return ValueOf(arena_New(a, PointerTo(typ))) +} + +func arena_New(a *arena.Arena, typ any) any diff --git a/contrib/go/_std_1.22/src/reflect/asm_386.s b/contrib/go/_std_1.23/src/reflect/asm_386.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_386.s rename to contrib/go/_std_1.23/src/reflect/asm_386.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_amd64.s b/contrib/go/_std_1.23/src/reflect/asm_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_amd64.s rename to contrib/go/_std_1.23/src/reflect/asm_amd64.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_arm.s b/contrib/go/_std_1.23/src/reflect/asm_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_arm.s rename to contrib/go/_std_1.23/src/reflect/asm_arm.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_arm64.s b/contrib/go/_std_1.23/src/reflect/asm_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_arm64.s rename to contrib/go/_std_1.23/src/reflect/asm_arm64.s diff --git a/contrib/go/_std_1.23/src/reflect/asm_loong64.s b/contrib/go/_std_1.23/src/reflect/asm_loong64.s new file mode 100644 index 000000000000..c0dc24449766 --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/asm_loong64.s @@ -0,0 +1,79 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" +#include "funcdata.h" + +#define REGCTXT R29 + +// The frames of each of the two functions below contain two locals, at offsets +// that are known to the runtime. +// +// The first local is a bool called retValid with a whole pointer-word reserved +// for it on the stack. The purpose of this word is so that the runtime knows +// whether the stack-allocated return space contains valid values for stack +// scanning. +// +// The second local is an abi.RegArgs value whose offset is also known to the +// runtime, so that a stack map for it can be constructed, since it contains +// pointers visible to the GC. +#define LOCAL_RETVALID 40 +#define LOCAL_REGARGS 48 + +// The frame size of the functions below is +// 32 (args of callReflect) + 8 (bool + padding) + 392 (abi.RegArgs) = 432. + +// makeFuncStub is the code half of the function returned by MakeFunc. +// See the comment on the declaration of makeFuncStub in makefunc.go +// for more details. +// No arg size here, runtime pulls arg map out of the func value. +TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$432 + NO_LOCAL_POINTERS + ADDV $LOCAL_REGARGS, R3, R25 // spillArgs using R25 + JAL runtime·spillArgs(SB) + MOVV REGCTXT, 32(R3) // save REGCTXT > args of moveMakeFuncArgPtrs < LOCAL_REGARGS + + MOVV REGCTXT, R4 + MOVV R25, R5 + JAL ·moveMakeFuncArgPtrs(SB) + MOVV 32(R3), REGCTXT // restore REGCTXT + + MOVV REGCTXT, 8(R3) + MOVV $argframe+0(FP), R20 + MOVV R20, 16(R3) + MOVV R0, LOCAL_RETVALID(R3) + ADDV $LOCAL_RETVALID, R3, R20 + MOVV R20, 24(R3) + ADDV $LOCAL_REGARGS, R3, R20 + MOVV R20, 32(R3) + JAL ·callReflect(SB) + ADDV $LOCAL_REGARGS, R3, R25 //unspillArgs using R25 + JAL runtime·unspillArgs(SB) + RET + +// methodValueCall is the code half of the function returned by makeMethodValue. +// See the comment on the declaration of methodValueCall in makefunc.go +// for more details. +// No arg size here; runtime pulls arg map out of the func value. +TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$432 + NO_LOCAL_POINTERS + ADDV $LOCAL_REGARGS, R3, R25 // spillArgs using R25 + JAL runtime·spillArgs(SB) + MOVV REGCTXT, 32(R3) // save REGCTXT > args of moveMakeFuncArgPtrs < LOCAL_REGARGS + MOVV REGCTXT, R4 + MOVV R25, R5 + JAL ·moveMakeFuncArgPtrs(SB) + MOVV 32(R3), REGCTXT // restore REGCTXT + MOVV REGCTXT, 8(R3) + MOVV $argframe+0(FP), R20 + MOVV R20, 16(R3) + MOVB R0, LOCAL_RETVALID(R3) + ADDV $LOCAL_RETVALID, R3, R20 + MOVV R20, 24(R3) + ADDV $LOCAL_REGARGS, R3, R20 + MOVV R20, 32(R3) // frame size to 32+SP as callreflect args) + JAL ·callMethod(SB) + ADDV $LOCAL_REGARGS, R3, R25 // unspillArgs using R25 + JAL runtime·unspillArgs(SB) + RET diff --git a/contrib/go/_std_1.22/src/reflect/asm_mips64x.s b/contrib/go/_std_1.23/src/reflect/asm_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_mips64x.s rename to contrib/go/_std_1.23/src/reflect/asm_mips64x.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_mipsx.s b/contrib/go/_std_1.23/src/reflect/asm_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_mipsx.s rename to contrib/go/_std_1.23/src/reflect/asm_mipsx.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_ppc64x.s b/contrib/go/_std_1.23/src/reflect/asm_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_ppc64x.s rename to contrib/go/_std_1.23/src/reflect/asm_ppc64x.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_riscv64.s b/contrib/go/_std_1.23/src/reflect/asm_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_riscv64.s rename to contrib/go/_std_1.23/src/reflect/asm_riscv64.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_s390x.s b/contrib/go/_std_1.23/src/reflect/asm_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_s390x.s rename to contrib/go/_std_1.23/src/reflect/asm_s390x.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_wasm.s b/contrib/go/_std_1.23/src/reflect/asm_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_wasm.s rename to contrib/go/_std_1.23/src/reflect/asm_wasm.s diff --git a/contrib/go/_std_1.23/src/reflect/badlinkname.go b/contrib/go/_std_1.23/src/reflect/badlinkname.go new file mode 100644 index 000000000000..eb701bff033d --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/badlinkname.go @@ -0,0 +1,130 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflect + +import ( + "internal/abi" + "unsafe" + _ "unsafe" +) + +// Widely used packages access these symbols using linkname, +// most notably: +// - github.com/goccy/go-json +// - github.com/goccy/go-reflect +// - github.com/sohaha/zlsgo +// - github.com/undefinedlabs/go-mpatch +// +// Do not remove or change the type signature. +// See go.dev/issue/67401 +// and go.dev/issue/67279. + +// ifaceIndir reports whether t is stored indirectly in an interface value. +// It is no longer used by this package and is here entirely for the +// linkname uses. +// +//go:linkname unusedIfaceIndir reflect.ifaceIndir +func unusedIfaceIndir(t *abi.Type) bool { + return t.Kind_&abi.KindDirectIface == 0 +} + +//go:linkname valueInterface + +// The compiler doesn't allow linknames on methods, for good reasons. +// We use this trick to push linknames of the methods. +// Do not call them in this package. + +//go:linkname badlinkname_rtype_Align reflect.(*rtype).Align +func badlinkname_rtype_Align(*rtype) int + +//go:linkname badlinkname_rtype_AssignableTo reflect.(*rtype).AssignableTo +func badlinkname_rtype_AssignableTo(*rtype, Type) bool + +//go:linkname badlinkname_rtype_Bits reflect.(*rtype).Bits +func badlinkname_rtype_Bits(*rtype) int + +//go:linkname badlinkname_rtype_ChanDir reflect.(*rtype).ChanDir +func badlinkname_rtype_ChanDir(*rtype) ChanDir + +//go:linkname badlinkname_rtype_Comparable reflect.(*rtype).Comparable +func badlinkname_rtype_Comparable(*rtype) bool + +//go:linkname badlinkname_rtype_ConvertibleTo reflect.(*rtype).ConvertibleTo +func badlinkname_rtype_ConvertibleTo(*rtype, Type) bool + +//go:linkname badlinkname_rtype_Elem reflect.(*rtype).Elem +func badlinkname_rtype_Elem(*rtype) Type + +//go:linkname badlinkname_rtype_Field reflect.(*rtype).Field +func badlinkname_rtype_Field(*rtype, int) StructField + +//go:linkname badlinkname_rtype_FieldAlign reflect.(*rtype).FieldAlign +func badlinkname_rtype_FieldAlign(*rtype) int + +//go:linkname badlinkname_rtype_FieldByIndex reflect.(*rtype).FieldByIndex +func badlinkname_rtype_FieldByIndex(*rtype, []int) StructField + +//go:linkname badlinkname_rtype_FieldByName reflect.(*rtype).FieldByName +func badlinkname_rtype_FieldByName(*rtype, string) (StructField, bool) + +//go:linkname badlinkname_rtype_FieldByNameFunc reflect.(*rtype).FieldByNameFunc +func badlinkname_rtype_FieldByNameFunc(*rtype, func(string) bool) (StructField, bool) + +//go:linkname badlinkname_rtype_Implements reflect.(*rtype).Implements +func badlinkname_rtype_Implements(*rtype, Type) bool + +//go:linkname badlinkname_rtype_In reflect.(*rtype).In +func badlinkname_rtype_In(*rtype, int) Type + +//go:linkname badlinkname_rtype_IsVariadic reflect.(*rtype).IsVariadic +func badlinkname_rtype_IsVariadic(*rtype) bool + +//go:linkname badlinkname_rtype_Key reflect.(*rtype).Key +func badlinkname_rtype_Key(*rtype) Type + +//go:linkname badlinkname_rtype_Kind reflect.(*rtype).Kind +func badlinkname_rtype_Kind(*rtype) Kind + +//go:linkname badlinkname_rtype_Len reflect.(*rtype).Len +func badlinkname_rtype_Len(*rtype) int + +//go:linkname badlinkname_rtype_Method reflect.(*rtype).Method +func badlinkname_rtype_Method(*rtype, int) Method + +//go:linkname badlinkname_rtype_MethodByName reflect.(*rtype).MethodByName +func badlinkname_rtype_MethodByName(*rtype, string) (Method, bool) + +//go:linkname badlinkname_rtype_Name reflect.(*rtype).Name +func badlinkname_rtype_Name(*rtype) string + +//go:linkname badlinkname_rtype_NumField reflect.(*rtype).NumField +func badlinkname_rtype_NumField(*rtype) int + +//go:linkname badlinkname_rtype_NumIn reflect.(*rtype).NumIn +func badlinkname_rtype_NumIn(*rtype) int + +//go:linkname badlinkname_rtype_NumMethod reflect.(*rtype).NumMethod +func badlinkname_rtype_NumMethod(*rtype) int + +//go:linkname badlinkname_rtype_NumOut reflect.(*rtype).NumOut +func badlinkname_rtype_NumOut(*rtype) int + +//go:linkname badlinkname_rtype_Out reflect.(*rtype).Out +func badlinkname_rtype_Out(*rtype, int) Type + +//go:linkname badlinkname_rtype_PkgPath reflect.(*rtype).PkgPath +func badlinkname_rtype_PkgPath(*rtype) string + +//go:linkname badlinkname_rtype_Size reflect.(*rtype).Size +func badlinkname_rtype_Size(*rtype) uintptr + +//go:linkname badlinkname_rtype_String reflect.(*rtype).String +func badlinkname_rtype_String(*rtype) string + +//go:linkname badlinkname_rtype_ptrTo reflect.(*rtype).ptrTo +func badlinkname_rtype_ptrTo(*rtype) *abi.Type + +//go:linkname badlinkname_Value_pointer reflect.(*Value).pointer +func badlinkname_Value_pointer(Value) unsafe.Pointer diff --git a/contrib/go/_std_1.22/src/reflect/deepequal.go b/contrib/go/_std_1.23/src/reflect/deepequal.go similarity index 99% rename from contrib/go/_std_1.22/src/reflect/deepequal.go rename to contrib/go/_std_1.23/src/reflect/deepequal.go index 961e17011839..502ea9f146be 100644 --- a/contrib/go/_std_1.22/src/reflect/deepequal.go +++ b/contrib/go/_std_1.23/src/reflect/deepequal.go @@ -39,7 +39,7 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool { hard := func(v1, v2 Value) bool { switch v1.Kind() { case Pointer: - if v1.typ().PtrBytes == 0 { + if !v1.typ().Pointers() { // not-in-heap pointers can't be cyclic. // At least, all of our current uses of runtime/internal/sys.NotInHeap // have that property. The runtime ones aren't cyclic (and we don't use diff --git a/contrib/go/_std_1.22/src/reflect/float32reg_generic.go b/contrib/go/_std_1.23/src/reflect/float32reg_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/float32reg_generic.go rename to contrib/go/_std_1.23/src/reflect/float32reg_generic.go diff --git a/contrib/go/_std_1.22/src/reflect/float32reg_ppc64x.s b/contrib/go/_std_1.23/src/reflect/float32reg_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/float32reg_ppc64x.s rename to contrib/go/_std_1.23/src/reflect/float32reg_ppc64x.s diff --git a/contrib/go/_std_1.22/src/reflect/float32reg_riscv64.s b/contrib/go/_std_1.23/src/reflect/float32reg_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/float32reg_riscv64.s rename to contrib/go/_std_1.23/src/reflect/float32reg_riscv64.s diff --git a/contrib/go/_std_1.22/src/reflect/internal/example1/example.go b/contrib/go/_std_1.23/src/reflect/internal/example1/example.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/example1/example.go rename to contrib/go/_std_1.23/src/reflect/internal/example1/example.go diff --git a/contrib/go/_std_1.22/src/reflect/internal/example1/ya.make b/contrib/go/_std_1.23/src/reflect/internal/example1/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/example1/ya.make rename to contrib/go/_std_1.23/src/reflect/internal/example1/ya.make diff --git a/contrib/go/_std_1.22/src/reflect/internal/example2/example.go b/contrib/go/_std_1.23/src/reflect/internal/example2/example.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/example2/example.go rename to contrib/go/_std_1.23/src/reflect/internal/example2/example.go diff --git a/contrib/go/_std_1.22/src/reflect/internal/example2/ya.make b/contrib/go/_std_1.23/src/reflect/internal/example2/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/example2/ya.make rename to contrib/go/_std_1.23/src/reflect/internal/example2/ya.make diff --git a/contrib/go/_std_1.22/src/reflect/internal/ya.make b/contrib/go/_std_1.23/src/reflect/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/ya.make rename to contrib/go/_std_1.23/src/reflect/internal/ya.make diff --git a/contrib/go/_std_1.23/src/reflect/iter.go b/contrib/go/_std_1.23/src/reflect/iter.go new file mode 100644 index 000000000000..03df87b17882 --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/iter.go @@ -0,0 +1,173 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflect + +import ( + "iter" +) + +func rangeNum[T int8 | int16 | int32 | int64 | int | + uint8 | uint16 | uint32 | uint64 | uint | + uintptr, N int64 | uint64](num N, t Type) iter.Seq[Value] { + return func(yield func(v Value) bool) { + convert := t.PkgPath() != "" + // cannot use range T(v) because no core type. + for i := T(0); i < T(num); i++ { + tmp := ValueOf(i) + // if the iteration value type is define by + // type T built-in type. + if convert { + tmp = tmp.Convert(t) + } + if !yield(tmp) { + return + } + } + } +} + +// Seq returns an iter.Seq[Value] that loops over the elements of v. +// If v's kind is Func, it must be a function that has no results and +// that takes a single argument of type func(T) bool for some type T. +// If v's kind is Pointer, the pointer element type must have kind Array. +// Otherwise v's kind must be Int, Int8, Int16, Int32, Int64, +// Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, +// Array, Chan, Map, Slice, or String. +func (v Value) Seq() iter.Seq[Value] { + if canRangeFunc(v.abiType()) { + return func(yield func(Value) bool) { + rf := MakeFunc(v.Type().In(0), func(in []Value) []Value { + return []Value{ValueOf(yield(in[0]))} + }) + v.Call([]Value{rf}) + } + } + switch v.kind() { + case Int: + return rangeNum[int](v.Int(), v.Type()) + case Int8: + return rangeNum[int8](v.Int(), v.Type()) + case Int16: + return rangeNum[int16](v.Int(), v.Type()) + case Int32: + return rangeNum[int32](v.Int(), v.Type()) + case Int64: + return rangeNum[int64](v.Int(), v.Type()) + case Uint: + return rangeNum[uint](v.Uint(), v.Type()) + case Uint8: + return rangeNum[uint8](v.Uint(), v.Type()) + case Uint16: + return rangeNum[uint16](v.Uint(), v.Type()) + case Uint32: + return rangeNum[uint32](v.Uint(), v.Type()) + case Uint64: + return rangeNum[uint64](v.Uint(), v.Type()) + case Uintptr: + return rangeNum[uintptr](v.Uint(), v.Type()) + case Pointer: + if v.Elem().kind() != Array { + break + } + return func(yield func(Value) bool) { + v = v.Elem() + for i := range v.Len() { + if !yield(ValueOf(i)) { + return + } + } + } + case Array, Slice: + return func(yield func(Value) bool) { + for i := range v.Len() { + if !yield(ValueOf(i)) { + return + } + } + } + case String: + return func(yield func(Value) bool) { + for i := range v.String() { + if !yield(ValueOf(i)) { + return + } + } + } + case Map: + return func(yield func(Value) bool) { + i := v.MapRange() + for i.Next() { + if !yield(i.Key()) { + return + } + } + } + case Chan: + return func(yield func(Value) bool) { + for value, ok := v.Recv(); ok; value, ok = v.Recv() { + if !yield(value) { + return + } + } + } + } + panic("reflect: " + v.Type().String() + " cannot produce iter.Seq[Value]") +} + +// Seq2 returns an iter.Seq2[Value, Value] that loops over the elements of v. +// If v's kind is Func, it must be a function that has no results and +// that takes a single argument of type func(K, V) bool for some type K, V. +// If v's kind is Pointer, the pointer element type must have kind Array. +// Otherwise v's kind must be Array, Map, Slice, or String. +func (v Value) Seq2() iter.Seq2[Value, Value] { + if canRangeFunc2(v.abiType()) { + return func(yield func(Value, Value) bool) { + rf := MakeFunc(v.Type().In(0), func(in []Value) []Value { + return []Value{ValueOf(yield(in[0], in[1]))} + }) + v.Call([]Value{rf}) + } + } + switch v.Kind() { + case Pointer: + if v.Elem().kind() != Array { + break + } + return func(yield func(Value, Value) bool) { + v = v.Elem() + for i := range v.Len() { + if !yield(ValueOf(i), v.Index(i)) { + return + } + } + } + case Array, Slice: + return func(yield func(Value, Value) bool) { + for i := range v.Len() { + if !yield(ValueOf(i), v.Index(i)) { + return + } + } + } + case String: + return func(yield func(Value, Value) bool) { + for i, v := range v.String() { + if !yield(ValueOf(i), ValueOf(v)) { + return + } + } + } + case Map: + return func(yield func(Value, Value) bool) { + i := v.MapRange() + for i.Next() { + if !yield(i.Key(), i.Value()) { + return + } + } + } + } + panic("reflect: " + v.Type().String() + " cannot produce iter.Seq2[Value, Value]") +} diff --git a/contrib/go/_std_1.22/src/reflect/makefunc.go b/contrib/go/_std_1.23/src/reflect/makefunc.go similarity index 96% rename from contrib/go/_std_1.22/src/reflect/makefunc.go rename to contrib/go/_std_1.23/src/reflect/makefunc.go index 2ed7f3890588..5da6cd2ec7d4 100644 --- a/contrib/go/_std_1.22/src/reflect/makefunc.go +++ b/contrib/go/_std_1.23/src/reflect/makefunc.go @@ -22,7 +22,7 @@ type makeFuncImpl struct { fn func([]Value) []Value } -// MakeFunc returns a new function of the given Type +// MakeFunc returns a new function of the given [Type] // that wraps the function fn. When called, that new function // does the following: // @@ -30,14 +30,14 @@ type makeFuncImpl struct { // - runs results := fn(args). // - returns the results as a slice of Values, one per formal result. // -// The implementation fn can assume that the argument Value slice +// The implementation fn can assume that the argument [Value] slice // has the number and type of arguments given by typ. // If typ describes a variadic function, the final Value is itself // a slice representing the variadic arguments, as in the // body of a variadic function. The result Value slice returned by fn // must have the number and type of results given by typ. // -// The Value.Call method allows the caller to invoke a typed function +// The [Value.Call] method allows the caller to invoke a typed function // in terms of Values; in contrast, MakeFunc allows the caller to implement // a typed function in terms of Values. // diff --git a/contrib/go/_std_1.22/src/reflect/stubs_ppc64x.go b/contrib/go/_std_1.23/src/reflect/stubs_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/stubs_ppc64x.go rename to contrib/go/_std_1.23/src/reflect/stubs_ppc64x.go diff --git a/contrib/go/_std_1.22/src/reflect/stubs_riscv64.go b/contrib/go/_std_1.23/src/reflect/stubs_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/stubs_riscv64.go rename to contrib/go/_std_1.23/src/reflect/stubs_riscv64.go diff --git a/contrib/go/_std_1.23/src/reflect/swapper.go b/contrib/go/_std_1.23/src/reflect/swapper.go new file mode 100644 index 000000000000..78f6a19e4a99 --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/swapper.go @@ -0,0 +1,79 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflect + +import ( + "internal/abi" + "internal/goarch" + "internal/unsafeheader" + "unsafe" +) + +// Swapper returns a function that swaps the elements in the provided +// slice. +// +// Swapper panics if the provided interface is not a slice. +func Swapper(slice any) func(i, j int) { + v := ValueOf(slice) + if v.Kind() != Slice { + panic(&ValueError{Method: "Swapper", Kind: v.Kind()}) + } + // Fast path for slices of size 0 and 1. Nothing to swap. + switch v.Len() { + case 0: + return func(i, j int) { panic("reflect: slice index out of range") } + case 1: + return func(i, j int) { + if i != 0 || j != 0 { + panic("reflect: slice index out of range") + } + } + } + + typ := v.Type().Elem().common() + size := typ.Size() + hasPtr := typ.Pointers() + + // Some common & small cases, without using memmove: + if hasPtr { + if size == goarch.PtrSize { + ps := *(*[]unsafe.Pointer)(v.ptr) + return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } + } + if typ.Kind() == abi.String { + ss := *(*[]string)(v.ptr) + return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] } + } + } else { + switch size { + case 8: + is := *(*[]int64)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 4: + is := *(*[]int32)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 2: + is := *(*[]int16)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 1: + is := *(*[]int8)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + } + } + + s := (*unsafeheader.Slice)(v.ptr) + tmp := unsafe_New(typ) // swap scratch space + + return func(i, j int) { + if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) { + panic("reflect: slice index out of range") + } + val1 := arrayAt(s.Data, i, size, "i < s.Len") + val2 := arrayAt(s.Data, j, size, "j < s.Len") + typedmemmove(typ, tmp, val1) + typedmemmove(typ, val1, val2) + typedmemmove(typ, val2, tmp) + } +} diff --git a/contrib/go/_std_1.23/src/reflect/type.go b/contrib/go/_std_1.23/src/reflect/type.go new file mode 100644 index 000000000000..07e2bf16447b --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/type.go @@ -0,0 +1,3086 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package reflect implements run-time reflection, allowing a program to +// manipulate objects with arbitrary types. The typical use is to take a value +// with static type interface{} and extract its dynamic type information by +// calling TypeOf, which returns a Type. +// +// A call to ValueOf returns a Value representing the run-time data. +// Zero takes a Type and returns a Value representing a zero value +// for that type. +// +// See "The Laws of Reflection" for an introduction to reflection in Go: +// https://golang.org/doc/articles/laws_of_reflection.html +package reflect + +import ( + "internal/abi" + "internal/goarch" + "strconv" + "sync" + "unicode" + "unicode/utf8" + "unsafe" +) + +// Type is the representation of a Go type. +// +// Not all methods apply to all kinds of types. Restrictions, +// if any, are noted in the documentation for each method. +// Use the Kind method to find out the kind of type before +// calling kind-specific methods. Calling a method +// inappropriate to the kind of type causes a run-time panic. +// +// Type values are comparable, such as with the == operator, +// so they can be used as map keys. +// Two Type values are equal if they represent identical types. +type Type interface { + // Methods applicable to all types. + + // Align returns the alignment in bytes of a value of + // this type when allocated in memory. + Align() int + + // FieldAlign returns the alignment in bytes of a value of + // this type when used as a field in a struct. + FieldAlign() int + + // Method returns the i'th method in the type's method set. + // It panics if i is not in the range [0, NumMethod()). + // + // For a non-interface type T or *T, the returned Method's Type and Func + // fields describe a function whose first argument is the receiver, + // and only exported methods are accessible. + // + // For an interface type, the returned Method's Type field gives the + // method signature, without a receiver, and the Func field is nil. + // + // Methods are sorted in lexicographic order. + Method(int) Method + + // MethodByName returns the method with that name in the type's + // method set and a boolean indicating if the method was found. + // + // For a non-interface type T or *T, the returned Method's Type and Func + // fields describe a function whose first argument is the receiver. + // + // For an interface type, the returned Method's Type field gives the + // method signature, without a receiver, and the Func field is nil. + MethodByName(string) (Method, bool) + + // NumMethod returns the number of methods accessible using Method. + // + // For a non-interface type, it returns the number of exported methods. + // + // For an interface type, it returns the number of exported and unexported methods. + NumMethod() int + + // Name returns the type's name within its package for a defined type. + // For other (non-defined) types it returns the empty string. + Name() string + + // PkgPath returns a defined type's package path, that is, the import path + // that uniquely identifies the package, such as "encoding/base64". + // If the type was predeclared (string, error) or not defined (*T, struct{}, + // []int, or A where A is an alias for a non-defined type), the package path + // will be the empty string. + PkgPath() string + + // Size returns the number of bytes needed to store + // a value of the given type; it is analogous to unsafe.Sizeof. + Size() uintptr + + // String returns a string representation of the type. + // The string representation may use shortened package names + // (e.g., base64 instead of "encoding/base64") and is not + // guaranteed to be unique among types. To test for type identity, + // compare the Types directly. + String() string + + // Kind returns the specific kind of this type. + Kind() Kind + + // Implements reports whether the type implements the interface type u. + Implements(u Type) bool + + // AssignableTo reports whether a value of the type is assignable to type u. + AssignableTo(u Type) bool + + // ConvertibleTo reports whether a value of the type is convertible to type u. + // Even if ConvertibleTo returns true, the conversion may still panic. + // For example, a slice of type []T is convertible to *[N]T, + // but the conversion will panic if its length is less than N. + ConvertibleTo(u Type) bool + + // Comparable reports whether values of this type are comparable. + // Even if Comparable returns true, the comparison may still panic. + // For example, values of interface type are comparable, + // but the comparison will panic if their dynamic type is not comparable. + Comparable() bool + + // Methods applicable only to some types, depending on Kind. + // The methods allowed for each kind are: + // + // Int*, Uint*, Float*, Complex*: Bits + // Array: Elem, Len + // Chan: ChanDir, Elem + // Func: In, NumIn, Out, NumOut, IsVariadic. + // Map: Key, Elem + // Pointer: Elem + // Slice: Elem + // Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField + + // Bits returns the size of the type in bits. + // It panics if the type's Kind is not one of the + // sized or unsized Int, Uint, Float, or Complex kinds. + Bits() int + + // ChanDir returns a channel type's direction. + // It panics if the type's Kind is not Chan. + ChanDir() ChanDir + + // IsVariadic reports whether a function type's final input parameter + // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's + // implicit actual type []T. + // + // For concreteness, if t represents func(x int, y ... float64), then + // + // t.NumIn() == 2 + // t.In(0) is the reflect.Type for "int" + // t.In(1) is the reflect.Type for "[]float64" + // t.IsVariadic() == true + // + // IsVariadic panics if the type's Kind is not Func. + IsVariadic() bool + + // Elem returns a type's element type. + // It panics if the type's Kind is not Array, Chan, Map, Pointer, or Slice. + Elem() Type + + // Field returns a struct type's i'th field. + // It panics if the type's Kind is not Struct. + // It panics if i is not in the range [0, NumField()). + Field(i int) StructField + + // FieldByIndex returns the nested field corresponding + // to the index sequence. It is equivalent to calling Field + // successively for each index i. + // It panics if the type's Kind is not Struct. + FieldByIndex(index []int) StructField + + // FieldByName returns the struct field with the given name + // and a boolean indicating if the field was found. + // If the returned field is promoted from an embedded struct, + // then Offset in the returned StructField is the offset in + // the embedded struct. + FieldByName(name string) (StructField, bool) + + // FieldByNameFunc returns the struct field with a name + // that satisfies the match function and a boolean indicating if + // the field was found. + // + // FieldByNameFunc considers the fields in the struct itself + // and then the fields in any embedded structs, in breadth first order, + // stopping at the shallowest nesting depth containing one or more + // fields satisfying the match function. If multiple fields at that depth + // satisfy the match function, they cancel each other + // and FieldByNameFunc returns no match. + // This behavior mirrors Go's handling of name lookup in + // structs containing embedded fields. + // + // If the returned field is promoted from an embedded struct, + // then Offset in the returned StructField is the offset in + // the embedded struct. + FieldByNameFunc(match func(string) bool) (StructField, bool) + + // In returns the type of a function type's i'th input parameter. + // It panics if the type's Kind is not Func. + // It panics if i is not in the range [0, NumIn()). + In(i int) Type + + // Key returns a map type's key type. + // It panics if the type's Kind is not Map. + Key() Type + + // Len returns an array type's length. + // It panics if the type's Kind is not Array. + Len() int + + // NumField returns a struct type's field count. + // It panics if the type's Kind is not Struct. + NumField() int + + // NumIn returns a function type's input parameter count. + // It panics if the type's Kind is not Func. + NumIn() int + + // NumOut returns a function type's output parameter count. + // It panics if the type's Kind is not Func. + NumOut() int + + // Out returns the type of a function type's i'th output parameter. + // It panics if the type's Kind is not Func. + // It panics if i is not in the range [0, NumOut()). + Out(i int) Type + + // OverflowComplex reports whether the complex128 x cannot be represented by type t. + // It panics if t's Kind is not Complex64 or Complex128. + OverflowComplex(x complex128) bool + + // OverflowFloat reports whether the float64 x cannot be represented by type t. + // It panics if t's Kind is not Float32 or Float64. + OverflowFloat(x float64) bool + + // OverflowInt reports whether the int64 x cannot be represented by type t. + // It panics if t's Kind is not Int, Int8, Int16, Int32, or Int64. + OverflowInt(x int64) bool + + // OverflowUint reports whether the uint64 x cannot be represented by type t. + // It panics if t's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64. + OverflowUint(x uint64) bool + + // CanSeq reports whether a [Value] with this type can be iterated over using [Value.Seq]. + CanSeq() bool + + // CanSeq2 reports whether a [Value] with this type can be iterated over using [Value.Seq2]. + CanSeq2() bool + + common() *abi.Type + uncommon() *uncommonType +} + +// BUG(rsc): FieldByName and related functions consider struct field names to be equal +// if the names are equal, even if they are unexported names originating +// in different packages. The practical effect of this is that the result of +// t.FieldByName("x") is not well defined if the struct type t contains +// multiple fields named x (embedded from different packages). +// FieldByName may return one of the fields named x or may report that there are none. +// See https://golang.org/issue/4876 for more details. + +/* + * These data structures are known to the compiler (../cmd/compile/internal/reflectdata/reflect.go). + * A few are known to ../runtime/type.go to convey to debuggers. + * They are also known to ../runtime/type.go. + */ + +// A Kind represents the specific kind of type that a [Type] represents. +// The zero Kind is not a valid kind. +type Kind uint + +const ( + Invalid Kind = iota + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + Array + Chan + Func + Interface + Map + Pointer + Slice + String + Struct + UnsafePointer +) + +// Ptr is the old name for the [Pointer] kind. +const Ptr = Pointer + +// uncommonType is present only for defined types or types with methods +// (if T is a defined type, the uncommonTypes for T and *T have methods). +// Using a pointer to this struct reduces the overall size required +// to describe a non-defined type with no methods. +type uncommonType = abi.UncommonType + +// Embed this type to get common/uncommon +type common struct { + abi.Type +} + +// rtype is the common implementation of most values. +// It is embedded in other struct types. +type rtype struct { + t abi.Type +} + +func (t *rtype) common() *abi.Type { + return &t.t +} + +func (t *rtype) uncommon() *abi.UncommonType { + return t.t.Uncommon() +} + +type aNameOff = abi.NameOff +type aTypeOff = abi.TypeOff +type aTextOff = abi.TextOff + +// ChanDir represents a channel type's direction. +type ChanDir int + +const ( + RecvDir ChanDir = 1 << iota // <-chan + SendDir // chan<- + BothDir = RecvDir | SendDir // chan +) + +// arrayType represents a fixed array type. +type arrayType = abi.ArrayType + +// chanType represents a channel type. +type chanType = abi.ChanType + +// funcType represents a function type. +// +// A *rtype for each in and out parameter is stored in an array that +// directly follows the funcType (and possibly its uncommonType). So +// a function type with one method, one input, and one output is: +// +// struct { +// funcType +// uncommonType +// [2]*rtype // [0] is in, [1] is out +// } +type funcType = abi.FuncType + +// interfaceType represents an interface type. +type interfaceType struct { + abi.InterfaceType // can embed directly because not a public type. +} + +func (t *interfaceType) nameOff(off aNameOff) abi.Name { + return toRType(&t.Type).nameOff(off) +} + +func nameOffFor(t *abi.Type, off aNameOff) abi.Name { + return toRType(t).nameOff(off) +} + +func typeOffFor(t *abi.Type, off aTypeOff) *abi.Type { + return toRType(t).typeOff(off) +} + +func (t *interfaceType) typeOff(off aTypeOff) *abi.Type { + return toRType(&t.Type).typeOff(off) +} + +func (t *interfaceType) common() *abi.Type { + return &t.Type +} + +func (t *interfaceType) uncommon() *abi.UncommonType { + return t.Uncommon() +} + +// mapType represents a map type. +type mapType struct { + abi.MapType +} + +// ptrType represents a pointer type. +type ptrType struct { + abi.PtrType +} + +// sliceType represents a slice type. +type sliceType struct { + abi.SliceType +} + +// Struct field +type structField = abi.StructField + +// structType represents a struct type. +type structType struct { + abi.StructType +} + +func pkgPath(n abi.Name) string { + if n.Bytes == nil || *n.DataChecked(0, "name flag field")&(1<<2) == 0 { + return "" + } + i, l := n.ReadVarint(1) + off := 1 + i + l + if n.HasTag() { + i2, l2 := n.ReadVarint(off) + off += i2 + l2 + } + var nameOff int32 + // Note that this field may not be aligned in memory, + // so we cannot use a direct int32 assignment here. + copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.DataChecked(off, "name offset field")))[:]) + pkgPathName := abi.Name{Bytes: (*byte)(resolveTypeOff(unsafe.Pointer(n.Bytes), nameOff))} + return pkgPathName.Name() +} + +func newName(n, tag string, exported, embedded bool) abi.Name { + return abi.NewName(n, tag, exported, embedded) +} + +/* + * The compiler knows the exact layout of all the data structures above. + * The compiler does not know about the data structures and methods below. + */ + +// Method represents a single method. +type Method struct { + // Name is the method name. + Name string + + // PkgPath is the package path that qualifies a lower case (unexported) + // method name. It is empty for upper case (exported) method names. + // The combination of PkgPath and Name uniquely identifies a method + // in a method set. + // See https://golang.org/ref/spec#Uniqueness_of_identifiers + PkgPath string + + Type Type // method type + Func Value // func with receiver as first argument + Index int // index for Type.Method +} + +// IsExported reports whether the method is exported. +func (m Method) IsExported() bool { + return m.PkgPath == "" +} + +// String returns the name of k. +func (k Kind) String() string { + if uint(k) < uint(len(kindNames)) { + return kindNames[uint(k)] + } + return "kind" + strconv.Itoa(int(k)) +} + +var kindNames = []string{ + Invalid: "invalid", + Bool: "bool", + Int: "int", + Int8: "int8", + Int16: "int16", + Int32: "int32", + Int64: "int64", + Uint: "uint", + Uint8: "uint8", + Uint16: "uint16", + Uint32: "uint32", + Uint64: "uint64", + Uintptr: "uintptr", + Float32: "float32", + Float64: "float64", + Complex64: "complex64", + Complex128: "complex128", + Array: "array", + Chan: "chan", + Func: "func", + Interface: "interface", + Map: "map", + Pointer: "ptr", + Slice: "slice", + String: "string", + Struct: "struct", + UnsafePointer: "unsafe.Pointer", +} + +// resolveNameOff resolves a name offset from a base pointer. +// The (*rtype).nameOff method is a convenience wrapper for this function. +// Implemented in the runtime package. +// +//go:noescape +func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer + +// resolveTypeOff resolves an *rtype offset from a base type. +// The (*rtype).typeOff method is a convenience wrapper for this function. +// Implemented in the runtime package. +// +//go:noescape +func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer + +// resolveTextOff resolves a function pointer offset from a base type. +// The (*rtype).textOff method is a convenience wrapper for this function. +// Implemented in the runtime package. +// +//go:noescape +func resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer + +// addReflectOff adds a pointer to the reflection lookup map in the runtime. +// It returns a new ID that can be used as a typeOff or textOff, and will +// be resolved correctly. Implemented in the runtime package. +// +// addReflectOff should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goplus/reflectx +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname addReflectOff +//go:noescape +func addReflectOff(ptr unsafe.Pointer) int32 + +// resolveReflectName adds a name to the reflection lookup map in the runtime. +// It returns a new nameOff that can be used to refer to the pointer. +func resolveReflectName(n abi.Name) aNameOff { + return aNameOff(addReflectOff(unsafe.Pointer(n.Bytes))) +} + +// resolveReflectType adds a *rtype to the reflection lookup map in the runtime. +// It returns a new typeOff that can be used to refer to the pointer. +func resolveReflectType(t *abi.Type) aTypeOff { + return aTypeOff(addReflectOff(unsafe.Pointer(t))) +} + +// resolveReflectText adds a function pointer to the reflection lookup map in +// the runtime. It returns a new textOff that can be used to refer to the +// pointer. +func resolveReflectText(ptr unsafe.Pointer) aTextOff { + return aTextOff(addReflectOff(ptr)) +} + +func (t *rtype) nameOff(off aNameOff) abi.Name { + return abi.Name{Bytes: (*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))} +} + +func (t *rtype) typeOff(off aTypeOff) *abi.Type { + return (*abi.Type)(resolveTypeOff(unsafe.Pointer(t), int32(off))) +} + +func (t *rtype) textOff(off aTextOff) unsafe.Pointer { + return resolveTextOff(unsafe.Pointer(t), int32(off)) +} + +func textOffFor(t *abi.Type, off aTextOff) unsafe.Pointer { + return toRType(t).textOff(off) +} + +func (t *rtype) String() string { + s := t.nameOff(t.t.Str).Name() + if t.t.TFlag&abi.TFlagExtraStar != 0 { + return s[1:] + } + return s +} + +func (t *rtype) Size() uintptr { return t.t.Size() } + +func (t *rtype) Bits() int { + if t == nil { + panic("reflect: Bits of nil Type") + } + k := t.Kind() + if k < Int || k > Complex128 { + panic("reflect: Bits of non-arithmetic Type " + t.String()) + } + return int(t.t.Size_) * 8 +} + +func (t *rtype) Align() int { return t.t.Align() } + +func (t *rtype) FieldAlign() int { return t.t.FieldAlign() } + +func (t *rtype) Kind() Kind { return Kind(t.t.Kind()) } + +func (t *rtype) exportedMethods() []abi.Method { + ut := t.uncommon() + if ut == nil { + return nil + } + return ut.ExportedMethods() +} + +func (t *rtype) NumMethod() int { + if t.Kind() == Interface { + tt := (*interfaceType)(unsafe.Pointer(t)) + return tt.NumMethod() + } + return len(t.exportedMethods()) +} + +func (t *rtype) Method(i int) (m Method) { + if t.Kind() == Interface { + tt := (*interfaceType)(unsafe.Pointer(t)) + return tt.Method(i) + } + methods := t.exportedMethods() + if i < 0 || i >= len(methods) { + panic("reflect: Method index out of range") + } + p := methods[i] + pname := t.nameOff(p.Name) + m.Name = pname.Name() + fl := flag(Func) + mtyp := t.typeOff(p.Mtyp) + ft := (*funcType)(unsafe.Pointer(mtyp)) + in := make([]Type, 0, 1+ft.NumIn()) + in = append(in, t) + for _, arg := range ft.InSlice() { + in = append(in, toRType(arg)) + } + out := make([]Type, 0, ft.NumOut()) + for _, ret := range ft.OutSlice() { + out = append(out, toRType(ret)) + } + mt := FuncOf(in, out, ft.IsVariadic()) + m.Type = mt + tfn := t.textOff(p.Tfn) + fn := unsafe.Pointer(&tfn) + m.Func = Value{&mt.(*rtype).t, fn, fl} + + m.Index = i + return m +} + +func (t *rtype) MethodByName(name string) (m Method, ok bool) { + if t.Kind() == Interface { + tt := (*interfaceType)(unsafe.Pointer(t)) + return tt.MethodByName(name) + } + ut := t.uncommon() + if ut == nil { + return Method{}, false + } + + methods := ut.ExportedMethods() + + // We are looking for the first index i where the string becomes >= s. + // This is a copy of sort.Search, with f(h) replaced by (t.nameOff(methods[h].name).name() >= name). + i, j := 0, len(methods) + for i < j { + h := int(uint(i+j) >> 1) // avoid overflow when computing h + // i ≤ h < j + if !(t.nameOff(methods[h].Name).Name() >= name) { + i = h + 1 // preserves f(i-1) == false + } else { + j = h // preserves f(j) == true + } + } + // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. + if i < len(methods) && name == t.nameOff(methods[i].Name).Name() { + return t.Method(i), true + } + + return Method{}, false +} + +func (t *rtype) PkgPath() string { + if t.t.TFlag&abi.TFlagNamed == 0 { + return "" + } + ut := t.uncommon() + if ut == nil { + return "" + } + return t.nameOff(ut.PkgPath).Name() +} + +func pkgPathFor(t *abi.Type) string { + return toRType(t).PkgPath() +} + +func (t *rtype) Name() string { + if !t.t.HasName() { + return "" + } + s := t.String() + i := len(s) - 1 + sqBrackets := 0 + for i >= 0 && (s[i] != '.' || sqBrackets != 0) { + switch s[i] { + case ']': + sqBrackets++ + case '[': + sqBrackets-- + } + i-- + } + return s[i+1:] +} + +func nameFor(t *abi.Type) string { + return toRType(t).Name() +} + +func (t *rtype) ChanDir() ChanDir { + if t.Kind() != Chan { + panic("reflect: ChanDir of non-chan type " + t.String()) + } + tt := (*abi.ChanType)(unsafe.Pointer(t)) + return ChanDir(tt.Dir) +} + +func toRType(t *abi.Type) *rtype { + return (*rtype)(unsafe.Pointer(t)) +} + +func elem(t *abi.Type) *abi.Type { + et := t.Elem() + if et != nil { + return et + } + panic("reflect: Elem of invalid type " + stringFor(t)) +} + +func (t *rtype) Elem() Type { + return toType(elem(t.common())) +} + +func (t *rtype) Field(i int) StructField { + if t.Kind() != Struct { + panic("reflect: Field of non-struct type " + t.String()) + } + tt := (*structType)(unsafe.Pointer(t)) + return tt.Field(i) +} + +func (t *rtype) FieldByIndex(index []int) StructField { + if t.Kind() != Struct { + panic("reflect: FieldByIndex of non-struct type " + t.String()) + } + tt := (*structType)(unsafe.Pointer(t)) + return tt.FieldByIndex(index) +} + +func (t *rtype) FieldByName(name string) (StructField, bool) { + if t.Kind() != Struct { + panic("reflect: FieldByName of non-struct type " + t.String()) + } + tt := (*structType)(unsafe.Pointer(t)) + return tt.FieldByName(name) +} + +func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) { + if t.Kind() != Struct { + panic("reflect: FieldByNameFunc of non-struct type " + t.String()) + } + tt := (*structType)(unsafe.Pointer(t)) + return tt.FieldByNameFunc(match) +} + +func (t *rtype) Key() Type { + if t.Kind() != Map { + panic("reflect: Key of non-map type " + t.String()) + } + tt := (*mapType)(unsafe.Pointer(t)) + return toType(tt.Key) +} + +func (t *rtype) Len() int { + if t.Kind() != Array { + panic("reflect: Len of non-array type " + t.String()) + } + tt := (*arrayType)(unsafe.Pointer(t)) + return int(tt.Len) +} + +func (t *rtype) NumField() int { + if t.Kind() != Struct { + panic("reflect: NumField of non-struct type " + t.String()) + } + tt := (*structType)(unsafe.Pointer(t)) + return len(tt.Fields) +} + +func (t *rtype) In(i int) Type { + if t.Kind() != Func { + panic("reflect: In of non-func type " + t.String()) + } + tt := (*abi.FuncType)(unsafe.Pointer(t)) + return toType(tt.InSlice()[i]) +} + +func (t *rtype) NumIn() int { + if t.Kind() != Func { + panic("reflect: NumIn of non-func type " + t.String()) + } + tt := (*abi.FuncType)(unsafe.Pointer(t)) + return tt.NumIn() +} + +func (t *rtype) NumOut() int { + if t.Kind() != Func { + panic("reflect: NumOut of non-func type " + t.String()) + } + tt := (*abi.FuncType)(unsafe.Pointer(t)) + return tt.NumOut() +} + +func (t *rtype) Out(i int) Type { + if t.Kind() != Func { + panic("reflect: Out of non-func type " + t.String()) + } + tt := (*abi.FuncType)(unsafe.Pointer(t)) + return toType(tt.OutSlice()[i]) +} + +func (t *rtype) IsVariadic() bool { + if t.Kind() != Func { + panic("reflect: IsVariadic of non-func type " + t.String()) + } + tt := (*abi.FuncType)(unsafe.Pointer(t)) + return tt.IsVariadic() +} + +func (t *rtype) OverflowComplex(x complex128) bool { + k := t.Kind() + switch k { + case Complex64: + return overflowFloat32(real(x)) || overflowFloat32(imag(x)) + case Complex128: + return false + } + panic("reflect: OverflowComplex of non-complex type " + t.String()) +} + +func (t *rtype) OverflowFloat(x float64) bool { + k := t.Kind() + switch k { + case Float32: + return overflowFloat32(x) + case Float64: + return false + } + panic("reflect: OverflowFloat of non-float type " + t.String()) +} + +func (t *rtype) OverflowInt(x int64) bool { + k := t.Kind() + switch k { + case Int, Int8, Int16, Int32, Int64: + bitSize := t.Size() * 8 + trunc := (x << (64 - bitSize)) >> (64 - bitSize) + return x != trunc + } + panic("reflect: OverflowInt of non-int type " + t.String()) +} + +func (t *rtype) OverflowUint(x uint64) bool { + k := t.Kind() + switch k { + case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64: + bitSize := t.Size() * 8 + trunc := (x << (64 - bitSize)) >> (64 - bitSize) + return x != trunc + } + panic("reflect: OverflowUint of non-uint type " + t.String()) +} + +func (t *rtype) CanSeq() bool { + switch t.Kind() { + case Int8, Int16, Int32, Int64, Int, Uint8, Uint16, Uint32, Uint64, Uint, Uintptr, Array, Slice, Chan, String, Map: + return true + case Func: + return canRangeFunc(&t.t) + case Pointer: + return t.Elem().Kind() == Array + } + return false +} + +func canRangeFunc(t *abi.Type) bool { + if t.Kind() != abi.Func { + return false + } + f := t.FuncType() + if f.InCount != 1 || f.OutCount != 0 { + return false + } + y := f.In(0) + if y.Kind() != abi.Func { + return false + } + yield := y.FuncType() + return yield.InCount == 1 && yield.OutCount == 1 && yield.Out(0).Kind() == abi.Bool +} + +func (t *rtype) CanSeq2() bool { + switch t.Kind() { + case Array, Slice, String, Map: + return true + case Func: + return canRangeFunc2(&t.t) + case Pointer: + return t.Elem().Kind() == Array + } + return false +} + +func canRangeFunc2(t *abi.Type) bool { + if t.Kind() != abi.Func { + return false + } + f := t.FuncType() + if f.InCount != 1 || f.OutCount != 0 { + return false + } + y := f.In(0) + if y.Kind() != abi.Func { + return false + } + yield := y.FuncType() + return yield.InCount == 2 && yield.OutCount == 1 && yield.Out(0).Kind() == abi.Bool +} + +// add returns p+x. +// +// The whySafe string is ignored, so that the function still inlines +// as efficiently as p+x, but all call sites should use the string to +// record why the addition is safe, which is to say why the addition +// does not cause x to advance to the very end of p's allocation +// and therefore point incorrectly at the next block in memory. +// +// add should be an internal detail (and is trivially copyable), +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/pinpoint-apm/pinpoint-go-agent +// - github.com/vmware/govmomi +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname add +func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { + return unsafe.Pointer(uintptr(p) + x) +} + +func (d ChanDir) String() string { + switch d { + case SendDir: + return "chan<-" + case RecvDir: + return "<-chan" + case BothDir: + return "chan" + } + return "ChanDir" + strconv.Itoa(int(d)) +} + +// Method returns the i'th method in the type's method set. +func (t *interfaceType) Method(i int) (m Method) { + if i < 0 || i >= len(t.Methods) { + return + } + p := &t.Methods[i] + pname := t.nameOff(p.Name) + m.Name = pname.Name() + if !pname.IsExported() { + m.PkgPath = pkgPath(pname) + if m.PkgPath == "" { + m.PkgPath = t.PkgPath.Name() + } + } + m.Type = toType(t.typeOff(p.Typ)) + m.Index = i + return +} + +// NumMethod returns the number of interface methods in the type's method set. +func (t *interfaceType) NumMethod() int { return len(t.Methods) } + +// MethodByName method with the given name in the type's method set. +func (t *interfaceType) MethodByName(name string) (m Method, ok bool) { + if t == nil { + return + } + var p *abi.Imethod + for i := range t.Methods { + p = &t.Methods[i] + if t.nameOff(p.Name).Name() == name { + return t.Method(i), true + } + } + return +} + +// A StructField describes a single field in a struct. +type StructField struct { + // Name is the field name. + Name string + + // PkgPath is the package path that qualifies a lower case (unexported) + // field name. It is empty for upper case (exported) field names. + // See https://golang.org/ref/spec#Uniqueness_of_identifiers + PkgPath string + + Type Type // field type + Tag StructTag // field tag string + Offset uintptr // offset within struct, in bytes + Index []int // index sequence for Type.FieldByIndex + Anonymous bool // is an embedded field +} + +// IsExported reports whether the field is exported. +func (f StructField) IsExported() bool { + return f.PkgPath == "" +} + +// A StructTag is the tag string in a struct field. +// +// By convention, tag strings are a concatenation of +// optionally space-separated key:"value" pairs. +// Each key is a non-empty string consisting of non-control +// characters other than space (U+0020 ' '), quote (U+0022 '"'), +// and colon (U+003A ':'). Each value is quoted using U+0022 '"' +// characters and Go string literal syntax. +type StructTag string + +// Get returns the value associated with key in the tag string. +// If there is no such key in the tag, Get returns the empty string. +// If the tag does not have the conventional format, the value +// returned by Get is unspecified. To determine whether a tag is +// explicitly set to the empty string, use [StructTag.Lookup]. +func (tag StructTag) Get(key string) string { + v, _ := tag.Lookup(key) + return v +} + +// Lookup returns the value associated with key in the tag string. +// If the key is present in the tag the value (which may be empty) +// is returned. Otherwise the returned value will be the empty string. +// The ok return value reports whether the value was explicitly set in +// the tag string. If the tag does not have the conventional format, +// the value returned by Lookup is unspecified. +func (tag StructTag) Lookup(key string) (value string, ok bool) { + // When modifying this code, also update the validateStructTag code + // in cmd/vet/structtag.go. + + for tag != "" { + // Skip leading space. + i := 0 + for i < len(tag) && tag[i] == ' ' { + i++ + } + tag = tag[i:] + if tag == "" { + break + } + + // Scan to colon. A space, a quote or a control character is a syntax error. + // Strictly speaking, control chars include the range [0x7f, 0x9f], not just + // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters + // as it is simpler to inspect the tag's bytes than the tag's runes. + i = 0 + for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { + i++ + } + if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { + break + } + name := string(tag[:i]) + tag = tag[i+1:] + + // Scan quoted string to find value. + i = 1 + for i < len(tag) && tag[i] != '"' { + if tag[i] == '\\' { + i++ + } + i++ + } + if i >= len(tag) { + break + } + qvalue := string(tag[:i+1]) + tag = tag[i+1:] + + if key == name { + value, err := strconv.Unquote(qvalue) + if err != nil { + break + } + return value, true + } + } + return "", false +} + +// Field returns the i'th struct field. +func (t *structType) Field(i int) (f StructField) { + if i < 0 || i >= len(t.Fields) { + panic("reflect: Field index out of bounds") + } + p := &t.Fields[i] + f.Type = toType(p.Typ) + f.Name = p.Name.Name() + f.Anonymous = p.Embedded() + if !p.Name.IsExported() { + f.PkgPath = t.PkgPath.Name() + } + if tag := p.Name.Tag(); tag != "" { + f.Tag = StructTag(tag) + } + f.Offset = p.Offset + + // NOTE(rsc): This is the only allocation in the interface + // presented by a reflect.Type. It would be nice to avoid, + // at least in the common cases, but we need to make sure + // that misbehaving clients of reflect cannot affect other + // uses of reflect. One possibility is CL 5371098, but we + // postponed that ugliness until there is a demonstrated + // need for the performance. This is issue 2320. + f.Index = []int{i} + return +} + +// TODO(gri): Should there be an error/bool indicator if the index +// is wrong for FieldByIndex? + +// FieldByIndex returns the nested field corresponding to index. +func (t *structType) FieldByIndex(index []int) (f StructField) { + f.Type = toType(&t.Type) + for i, x := range index { + if i > 0 { + ft := f.Type + if ft.Kind() == Pointer && ft.Elem().Kind() == Struct { + ft = ft.Elem() + } + f.Type = ft + } + f = f.Type.Field(x) + } + return +} + +// A fieldScan represents an item on the fieldByNameFunc scan work list. +type fieldScan struct { + typ *structType + index []int +} + +// FieldByNameFunc returns the struct field with a name that satisfies the +// match function and a boolean to indicate if the field was found. +func (t *structType) FieldByNameFunc(match func(string) bool) (result StructField, ok bool) { + // This uses the same condition that the Go language does: there must be a unique instance + // of the match at a given depth level. If there are multiple instances of a match at the + // same depth, they annihilate each other and inhibit any possible match at a lower level. + // The algorithm is breadth first search, one depth level at a time. + + // The current and next slices are work queues: + // current lists the fields to visit on this depth level, + // and next lists the fields on the next lower level. + current := []fieldScan{} + next := []fieldScan{{typ: t}} + + // nextCount records the number of times an embedded type has been + // encountered and considered for queueing in the 'next' slice. + // We only queue the first one, but we increment the count on each. + // If a struct type T can be reached more than once at a given depth level, + // then it annihilates itself and need not be considered at all when we + // process that next depth level. + var nextCount map[*structType]int + + // visited records the structs that have been considered already. + // Embedded pointer fields can create cycles in the graph of + // reachable embedded types; visited avoids following those cycles. + // It also avoids duplicated effort: if we didn't find the field in an + // embedded type T at level 2, we won't find it in one at level 4 either. + visited := map[*structType]bool{} + + for len(next) > 0 { + current, next = next, current[:0] + count := nextCount + nextCount = nil + + // Process all the fields at this depth, now listed in 'current'. + // The loop queues embedded fields found in 'next', for processing during the next + // iteration. The multiplicity of the 'current' field counts is recorded + // in 'count'; the multiplicity of the 'next' field counts is recorded in 'nextCount'. + for _, scan := range current { + t := scan.typ + if visited[t] { + // We've looked through this type before, at a higher level. + // That higher level would shadow the lower level we're now at, + // so this one can't be useful to us. Ignore it. + continue + } + visited[t] = true + for i := range t.Fields { + f := &t.Fields[i] + // Find name and (for embedded field) type for field f. + fname := f.Name.Name() + var ntyp *abi.Type + if f.Embedded() { + // Embedded field of type T or *T. + ntyp = f.Typ + if ntyp.Kind() == abi.Pointer { + ntyp = ntyp.Elem() + } + } + + // Does it match? + if match(fname) { + // Potential match + if count[t] > 1 || ok { + // Name appeared multiple times at this level: annihilate. + return StructField{}, false + } + result = t.Field(i) + result.Index = nil + result.Index = append(result.Index, scan.index...) + result.Index = append(result.Index, i) + ok = true + continue + } + + // Queue embedded struct fields for processing with next level, + // but only if we haven't seen a match yet at this level and only + // if the embedded types haven't already been queued. + if ok || ntyp == nil || ntyp.Kind() != abi.Struct { + continue + } + styp := (*structType)(unsafe.Pointer(ntyp)) + if nextCount[styp] > 0 { + nextCount[styp] = 2 // exact multiple doesn't matter + continue + } + if nextCount == nil { + nextCount = map[*structType]int{} + } + nextCount[styp] = 1 + if count[t] > 1 { + nextCount[styp] = 2 // exact multiple doesn't matter + } + var index []int + index = append(index, scan.index...) + index = append(index, i) + next = append(next, fieldScan{styp, index}) + } + } + if ok { + break + } + } + return +} + +// FieldByName returns the struct field with the given name +// and a boolean to indicate if the field was found. +func (t *structType) FieldByName(name string) (f StructField, present bool) { + // Quick check for top-level name, or struct without embedded fields. + hasEmbeds := false + if name != "" { + for i := range t.Fields { + tf := &t.Fields[i] + if tf.Name.Name() == name { + return t.Field(i), true + } + if tf.Embedded() { + hasEmbeds = true + } + } + } + if !hasEmbeds { + return + } + return t.FieldByNameFunc(func(s string) bool { return s == name }) +} + +// TypeOf returns the reflection [Type] that represents the dynamic type of i. +// If i is a nil interface value, TypeOf returns nil. +func TypeOf(i any) Type { + return toType(abi.TypeOf(i)) +} + +// rtypeOf directly extracts the *rtype of the provided value. +func rtypeOf(i any) *abi.Type { + return abi.TypeOf(i) +} + +// ptrMap is the cache for PointerTo. +var ptrMap sync.Map // map[*rtype]*ptrType + +// PtrTo returns the pointer type with element t. +// For example, if t represents type Foo, PtrTo(t) represents *Foo. +// +// PtrTo is the old spelling of [PointerTo]. +// The two functions behave identically. +// +// Deprecated: Superseded by [PointerTo]. +func PtrTo(t Type) Type { return PointerTo(t) } + +// PointerTo returns the pointer type with element t. +// For example, if t represents type Foo, PointerTo(t) represents *Foo. +func PointerTo(t Type) Type { + return toRType(t.(*rtype).ptrTo()) +} + +func (t *rtype) ptrTo() *abi.Type { + at := &t.t + if at.PtrToThis != 0 { + return t.typeOff(at.PtrToThis) + } + + // Check the cache. + if pi, ok := ptrMap.Load(t); ok { + return &pi.(*ptrType).Type + } + + // Look in known types. + s := "*" + t.String() + for _, tt := range typesByString(s) { + p := (*ptrType)(unsafe.Pointer(tt)) + if p.Elem != &t.t { + continue + } + pi, _ := ptrMap.LoadOrStore(t, p) + return &pi.(*ptrType).Type + } + + // Create a new ptrType starting with the description + // of an *unsafe.Pointer. + var iptr any = (*unsafe.Pointer)(nil) + prototype := *(**ptrType)(unsafe.Pointer(&iptr)) + pp := *prototype + + pp.Str = resolveReflectName(newName(s, "", false, false)) + pp.PtrToThis = 0 + + // For the type structures linked into the binary, the + // compiler provides a good hash of the string. + // Create a good hash for the new string by using + // the FNV-1 hash's mixing function to combine the + // old hash and the new "*". + pp.Hash = fnv1(t.t.Hash, '*') + + pp.Elem = at + + pi, _ := ptrMap.LoadOrStore(t, &pp) + return &pi.(*ptrType).Type +} + +func ptrTo(t *abi.Type) *abi.Type { + return toRType(t).ptrTo() +} + +// fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function. +func fnv1(x uint32, list ...byte) uint32 { + for _, b := range list { + x = x*16777619 ^ uint32(b) + } + return x +} + +func (t *rtype) Implements(u Type) bool { + if u == nil { + panic("reflect: nil type passed to Type.Implements") + } + if u.Kind() != Interface { + panic("reflect: non-interface type passed to Type.Implements") + } + return implements(u.common(), t.common()) +} + +func (t *rtype) AssignableTo(u Type) bool { + if u == nil { + panic("reflect: nil type passed to Type.AssignableTo") + } + uu := u.common() + return directlyAssignable(uu, t.common()) || implements(uu, t.common()) +} + +func (t *rtype) ConvertibleTo(u Type) bool { + if u == nil { + panic("reflect: nil type passed to Type.ConvertibleTo") + } + return convertOp(u.common(), t.common()) != nil +} + +func (t *rtype) Comparable() bool { + return t.t.Equal != nil +} + +// implements reports whether the type V implements the interface type T. +func implements(T, V *abi.Type) bool { + if T.Kind() != abi.Interface { + return false + } + t := (*interfaceType)(unsafe.Pointer(T)) + if len(t.Methods) == 0 { + return true + } + + // The same algorithm applies in both cases, but the + // method tables for an interface type and a concrete type + // are different, so the code is duplicated. + // In both cases the algorithm is a linear scan over the two + // lists - T's methods and V's methods - simultaneously. + // Since method tables are stored in a unique sorted order + // (alphabetical, with no duplicate method names), the scan + // through V's methods must hit a match for each of T's + // methods along the way, or else V does not implement T. + // This lets us run the scan in overall linear time instead of + // the quadratic time a naive search would require. + // See also ../runtime/iface.go. + if V.Kind() == abi.Interface { + v := (*interfaceType)(unsafe.Pointer(V)) + i := 0 + for j := 0; j < len(v.Methods); j++ { + tm := &t.Methods[i] + tmName := t.nameOff(tm.Name) + vm := &v.Methods[j] + vmName := nameOffFor(V, vm.Name) + if vmName.Name() == tmName.Name() && typeOffFor(V, vm.Typ) == t.typeOff(tm.Typ) { + if !tmName.IsExported() { + tmPkgPath := pkgPath(tmName) + if tmPkgPath == "" { + tmPkgPath = t.PkgPath.Name() + } + vmPkgPath := pkgPath(vmName) + if vmPkgPath == "" { + vmPkgPath = v.PkgPath.Name() + } + if tmPkgPath != vmPkgPath { + continue + } + } + if i++; i >= len(t.Methods) { + return true + } + } + } + return false + } + + v := V.Uncommon() + if v == nil { + return false + } + i := 0 + vmethods := v.Methods() + for j := 0; j < int(v.Mcount); j++ { + tm := &t.Methods[i] + tmName := t.nameOff(tm.Name) + vm := vmethods[j] + vmName := nameOffFor(V, vm.Name) + if vmName.Name() == tmName.Name() && typeOffFor(V, vm.Mtyp) == t.typeOff(tm.Typ) { + if !tmName.IsExported() { + tmPkgPath := pkgPath(tmName) + if tmPkgPath == "" { + tmPkgPath = t.PkgPath.Name() + } + vmPkgPath := pkgPath(vmName) + if vmPkgPath == "" { + vmPkgPath = nameOffFor(V, v.PkgPath).Name() + } + if tmPkgPath != vmPkgPath { + continue + } + } + if i++; i >= len(t.Methods) { + return true + } + } + } + return false +} + +// specialChannelAssignability reports whether a value x of channel type V +// can be directly assigned (using memmove) to another channel type T. +// https://golang.org/doc/go_spec.html#Assignability +// T and V must be both of Chan kind. +func specialChannelAssignability(T, V *abi.Type) bool { + // Special case: + // x is a bidirectional channel value, T is a channel type, + // x's type V and T have identical element types, + // and at least one of V or T is not a defined type. + return V.ChanDir() == abi.BothDir && (nameFor(T) == "" || nameFor(V) == "") && haveIdenticalType(T.Elem(), V.Elem(), true) +} + +// directlyAssignable reports whether a value x of type V can be directly +// assigned (using memmove) to a value of type T. +// https://golang.org/doc/go_spec.html#Assignability +// Ignoring the interface rules (implemented elsewhere) +// and the ideal constant rules (no ideal constants at run time). +func directlyAssignable(T, V *abi.Type) bool { + // x's type V is identical to T? + if T == V { + return true + } + + // Otherwise at least one of T and V must not be defined + // and they must have the same kind. + if T.HasName() && V.HasName() || T.Kind() != V.Kind() { + return false + } + + if T.Kind() == abi.Chan && specialChannelAssignability(T, V) { + return true + } + + // x's type T and V must have identical underlying types. + return haveIdenticalUnderlyingType(T, V, true) +} + +func haveIdenticalType(T, V *abi.Type, cmpTags bool) bool { + if cmpTags { + return T == V + } + + if nameFor(T) != nameFor(V) || T.Kind() != V.Kind() || pkgPathFor(T) != pkgPathFor(V) { + return false + } + + return haveIdenticalUnderlyingType(T, V, false) +} + +func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool { + if T == V { + return true + } + + kind := Kind(T.Kind()) + if kind != Kind(V.Kind()) { + return false + } + + // Non-composite types of equal kind have same underlying type + // (the predefined instance of the type). + if Bool <= kind && kind <= Complex128 || kind == String || kind == UnsafePointer { + return true + } + + // Composite types. + switch kind { + case Array: + return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case Chan: + return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case Func: + t := (*funcType)(unsafe.Pointer(T)) + v := (*funcType)(unsafe.Pointer(V)) + if t.OutCount != v.OutCount || t.InCount != v.InCount { + return false + } + for i := 0; i < t.NumIn(); i++ { + if !haveIdenticalType(t.In(i), v.In(i), cmpTags) { + return false + } + } + for i := 0; i < t.NumOut(); i++ { + if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) { + return false + } + } + return true + + case Interface: + t := (*interfaceType)(unsafe.Pointer(T)) + v := (*interfaceType)(unsafe.Pointer(V)) + if len(t.Methods) == 0 && len(v.Methods) == 0 { + return true + } + // Might have the same methods but still + // need a run time conversion. + return false + + case Map: + return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case Pointer, Slice: + return haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case Struct: + t := (*structType)(unsafe.Pointer(T)) + v := (*structType)(unsafe.Pointer(V)) + if len(t.Fields) != len(v.Fields) { + return false + } + if t.PkgPath.Name() != v.PkgPath.Name() { + return false + } + for i := range t.Fields { + tf := &t.Fields[i] + vf := &v.Fields[i] + if tf.Name.Name() != vf.Name.Name() { + return false + } + if !haveIdenticalType(tf.Typ, vf.Typ, cmpTags) { + return false + } + if cmpTags && tf.Name.Tag() != vf.Name.Tag() { + return false + } + if tf.Offset != vf.Offset { + return false + } + if tf.Embedded() != vf.Embedded() { + return false + } + } + return true + } + + return false +} + +// typelinks is implemented in package runtime. +// It returns a slice of the sections in each module, +// and a slice of *rtype offsets in each module. +// +// The types in each module are sorted by string. That is, the first +// two linked types of the first module are: +// +// d0 := sections[0] +// t1 := (*rtype)(add(d0, offset[0][0])) +// t2 := (*rtype)(add(d0, offset[0][1])) +// +// and +// +// t1.String() < t2.String() +// +// Note that strings are not unique identifiers for types: +// there can be more than one with a given string. +// Only types we might want to look up are included: +// pointers, channels, maps, slices, and arrays. +func typelinks() (sections []unsafe.Pointer, offset [][]int32) + +// rtypeOff should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname rtypeOff +func rtypeOff(section unsafe.Pointer, off int32) *abi.Type { + return (*abi.Type)(add(section, uintptr(off), "sizeof(rtype) > 0")) +} + +// typesByString returns the subslice of typelinks() whose elements have +// the given string representation. +// It may be empty (no known types with that string) or may have +// multiple elements (multiple types with that string). +// +// typesByString should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/aristanetworks/goarista +// - fortio.org/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname typesByString +func typesByString(s string) []*abi.Type { + sections, offset := typelinks() + var ret []*abi.Type + + for offsI, offs := range offset { + section := sections[offsI] + + // We are looking for the first index i where the string becomes >= s. + // This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s). + i, j := 0, len(offs) + for i < j { + h := int(uint(i+j) >> 1) // avoid overflow when computing h + // i ≤ h < j + if !(stringFor(rtypeOff(section, offs[h])) >= s) { + i = h + 1 // preserves f(i-1) == false + } else { + j = h // preserves f(j) == true + } + } + // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. + + // Having found the first, linear scan forward to find the last. + // We could do a second binary search, but the caller is going + // to do a linear scan anyway. + for j := i; j < len(offs); j++ { + typ := rtypeOff(section, offs[j]) + if stringFor(typ) != s { + break + } + ret = append(ret, typ) + } + } + return ret +} + +// The lookupCache caches ArrayOf, ChanOf, MapOf and SliceOf lookups. +var lookupCache sync.Map // map[cacheKey]*rtype + +// A cacheKey is the key for use in the lookupCache. +// Four values describe any of the types we are looking for: +// type kind, one or two subtypes, and an extra integer. +type cacheKey struct { + kind Kind + t1 *abi.Type + t2 *abi.Type + extra uintptr +} + +// The funcLookupCache caches FuncOf lookups. +// FuncOf does not share the common lookupCache since cacheKey is not +// sufficient to represent functions unambiguously. +var funcLookupCache struct { + sync.Mutex // Guards stores (but not loads) on m. + + // m is a map[uint32][]*rtype keyed by the hash calculated in FuncOf. + // Elements of m are append-only and thus safe for concurrent reading. + m sync.Map +} + +// ChanOf returns the channel type with the given direction and element type. +// For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int. +// +// The gc runtime imposes a limit of 64 kB on channel element types. +// If t's size is equal to or exceeds this limit, ChanOf panics. +func ChanOf(dir ChanDir, t Type) Type { + typ := t.common() + + // Look in cache. + ckey := cacheKey{Chan, typ, nil, uintptr(dir)} + if ch, ok := lookupCache.Load(ckey); ok { + return ch.(*rtype) + } + + // This restriction is imposed by the gc compiler and the runtime. + if typ.Size_ >= 1<<16 { + panic("reflect.ChanOf: element size too large") + } + + // Look in known types. + var s string + switch dir { + default: + panic("reflect.ChanOf: invalid dir") + case SendDir: + s = "chan<- " + stringFor(typ) + case RecvDir: + s = "<-chan " + stringFor(typ) + case BothDir: + typeStr := stringFor(typ) + if typeStr[0] == '<' { + // typ is recv chan, need parentheses as "<-" associates with leftmost + // chan possible, see: + // * https://golang.org/ref/spec#Channel_types + // * https://github.com/golang/go/issues/39897 + s = "chan (" + typeStr + ")" + } else { + s = "chan " + typeStr + } + } + for _, tt := range typesByString(s) { + ch := (*chanType)(unsafe.Pointer(tt)) + if ch.Elem == typ && ch.Dir == abi.ChanDir(dir) { + ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt)) + return ti.(Type) + } + } + + // Make a channel type. + var ichan any = (chan unsafe.Pointer)(nil) + prototype := *(**chanType)(unsafe.Pointer(&ichan)) + ch := *prototype + ch.TFlag = abi.TFlagRegularMemory + ch.Dir = abi.ChanDir(dir) + ch.Str = resolveReflectName(newName(s, "", false, false)) + ch.Hash = fnv1(typ.Hash, 'c', byte(dir)) + ch.Elem = typ + + ti, _ := lookupCache.LoadOrStore(ckey, toRType(&ch.Type)) + return ti.(Type) +} + +// MapOf returns the map type with the given key and element types. +// For example, if k represents int and e represents string, +// MapOf(k, e) represents map[int]string. +// +// If the key type is not a valid map key type (that is, if it does +// not implement Go's == operator), MapOf panics. +func MapOf(key, elem Type) Type { + ktyp := key.common() + etyp := elem.common() + + if ktyp.Equal == nil { + panic("reflect.MapOf: invalid key type " + stringFor(ktyp)) + } + + // Look in cache. + ckey := cacheKey{Map, ktyp, etyp, 0} + if mt, ok := lookupCache.Load(ckey); ok { + return mt.(Type) + } + + // Look in known types. + s := "map[" + stringFor(ktyp) + "]" + stringFor(etyp) + for _, tt := range typesByString(s) { + mt := (*mapType)(unsafe.Pointer(tt)) + if mt.Key == ktyp && mt.Elem == etyp { + ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt)) + return ti.(Type) + } + } + + // Make a map type. + // Note: flag values must match those used in the TMAP case + // in ../cmd/compile/internal/reflectdata/reflect.go:writeType. + var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil) + mt := **(**mapType)(unsafe.Pointer(&imap)) + mt.Str = resolveReflectName(newName(s, "", false, false)) + mt.TFlag = 0 + mt.Hash = fnv1(etyp.Hash, 'm', byte(ktyp.Hash>>24), byte(ktyp.Hash>>16), byte(ktyp.Hash>>8), byte(ktyp.Hash)) + mt.Key = ktyp + mt.Elem = etyp + mt.Bucket = bucketOf(ktyp, etyp) + mt.Hasher = func(p unsafe.Pointer, seed uintptr) uintptr { + return typehash(ktyp, p, seed) + } + mt.Flags = 0 + if ktyp.Size_ > abi.MapMaxKeyBytes { + mt.KeySize = uint8(goarch.PtrSize) + mt.Flags |= 1 // indirect key + } else { + mt.KeySize = uint8(ktyp.Size_) + } + if etyp.Size_ > abi.MapMaxElemBytes { + mt.ValueSize = uint8(goarch.PtrSize) + mt.Flags |= 2 // indirect value + } else { + mt.MapType.ValueSize = uint8(etyp.Size_) + } + mt.MapType.BucketSize = uint16(mt.Bucket.Size_) + if isReflexive(ktyp) { + mt.Flags |= 4 + } + if needKeyUpdate(ktyp) { + mt.Flags |= 8 + } + if hashMightPanic(ktyp) { + mt.Flags |= 16 + } + mt.PtrToThis = 0 + + ti, _ := lookupCache.LoadOrStore(ckey, toRType(&mt.Type)) + return ti.(Type) +} + +var funcTypes []Type +var funcTypesMutex sync.Mutex + +func initFuncTypes(n int) Type { + funcTypesMutex.Lock() + defer funcTypesMutex.Unlock() + if n >= len(funcTypes) { + newFuncTypes := make([]Type, n+1) + copy(newFuncTypes, funcTypes) + funcTypes = newFuncTypes + } + if funcTypes[n] != nil { + return funcTypes[n] + } + + funcTypes[n] = StructOf([]StructField{ + { + Name: "FuncType", + Type: TypeOf(funcType{}), + }, + { + Name: "Args", + Type: ArrayOf(n, TypeOf(&rtype{})), + }, + }) + return funcTypes[n] +} + +// FuncOf returns the function type with the given argument and result types. +// For example if k represents int and e represents string, +// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string. +// +// The variadic argument controls whether the function is variadic. FuncOf +// panics if the in[len(in)-1] does not represent a slice and variadic is +// true. +func FuncOf(in, out []Type, variadic bool) Type { + if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) { + panic("reflect.FuncOf: last arg of variadic func must be slice") + } + + // Make a func type. + var ifunc any = (func())(nil) + prototype := *(**funcType)(unsafe.Pointer(&ifunc)) + n := len(in) + len(out) + + if n > 128 { + panic("reflect.FuncOf: too many arguments") + } + + o := New(initFuncTypes(n)).Elem() + ft := (*funcType)(unsafe.Pointer(o.Field(0).Addr().Pointer())) + args := unsafe.Slice((**rtype)(unsafe.Pointer(o.Field(1).Addr().Pointer())), n)[0:0:n] + *ft = *prototype + + // Build a hash and minimally populate ft. + var hash uint32 + for _, in := range in { + t := in.(*rtype) + args = append(args, t) + hash = fnv1(hash, byte(t.t.Hash>>24), byte(t.t.Hash>>16), byte(t.t.Hash>>8), byte(t.t.Hash)) + } + if variadic { + hash = fnv1(hash, 'v') + } + hash = fnv1(hash, '.') + for _, out := range out { + t := out.(*rtype) + args = append(args, t) + hash = fnv1(hash, byte(t.t.Hash>>24), byte(t.t.Hash>>16), byte(t.t.Hash>>8), byte(t.t.Hash)) + } + + ft.TFlag = 0 + ft.Hash = hash + ft.InCount = uint16(len(in)) + ft.OutCount = uint16(len(out)) + if variadic { + ft.OutCount |= 1 << 15 + } + + // Look in cache. + if ts, ok := funcLookupCache.m.Load(hash); ok { + for _, t := range ts.([]*abi.Type) { + if haveIdenticalUnderlyingType(&ft.Type, t, true) { + return toRType(t) + } + } + } + + // Not in cache, lock and retry. + funcLookupCache.Lock() + defer funcLookupCache.Unlock() + if ts, ok := funcLookupCache.m.Load(hash); ok { + for _, t := range ts.([]*abi.Type) { + if haveIdenticalUnderlyingType(&ft.Type, t, true) { + return toRType(t) + } + } + } + + addToCache := func(tt *abi.Type) Type { + var rts []*abi.Type + if rti, ok := funcLookupCache.m.Load(hash); ok { + rts = rti.([]*abi.Type) + } + funcLookupCache.m.Store(hash, append(rts, tt)) + return toType(tt) + } + + // Look in known types for the same string representation. + str := funcStr(ft) + for _, tt := range typesByString(str) { + if haveIdenticalUnderlyingType(&ft.Type, tt, true) { + return addToCache(tt) + } + } + + // Populate the remaining fields of ft and store in cache. + ft.Str = resolveReflectName(newName(str, "", false, false)) + ft.PtrToThis = 0 + return addToCache(&ft.Type) +} +func stringFor(t *abi.Type) string { + return toRType(t).String() +} + +// funcStr builds a string representation of a funcType. +func funcStr(ft *funcType) string { + repr := make([]byte, 0, 64) + repr = append(repr, "func("...) + for i, t := range ft.InSlice() { + if i > 0 { + repr = append(repr, ", "...) + } + if ft.IsVariadic() && i == int(ft.InCount)-1 { + repr = append(repr, "..."...) + repr = append(repr, stringFor((*sliceType)(unsafe.Pointer(t)).Elem)...) + } else { + repr = append(repr, stringFor(t)...) + } + } + repr = append(repr, ')') + out := ft.OutSlice() + if len(out) == 1 { + repr = append(repr, ' ') + } else if len(out) > 1 { + repr = append(repr, " ("...) + } + for i, t := range out { + if i > 0 { + repr = append(repr, ", "...) + } + repr = append(repr, stringFor(t)...) + } + if len(out) > 1 { + repr = append(repr, ')') + } + return string(repr) +} + +// isReflexive reports whether the == operation on the type is reflexive. +// That is, x == x for all values x of type t. +func isReflexive(t *abi.Type) bool { + switch Kind(t.Kind()) { + case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, String, UnsafePointer: + return true + case Float32, Float64, Complex64, Complex128, Interface: + return false + case Array: + tt := (*arrayType)(unsafe.Pointer(t)) + return isReflexive(tt.Elem) + case Struct: + tt := (*structType)(unsafe.Pointer(t)) + for _, f := range tt.Fields { + if !isReflexive(f.Typ) { + return false + } + } + return true + default: + // Func, Map, Slice, Invalid + panic("isReflexive called on non-key type " + stringFor(t)) + } +} + +// needKeyUpdate reports whether map overwrites require the key to be copied. +func needKeyUpdate(t *abi.Type) bool { + switch Kind(t.Kind()) { + case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, UnsafePointer: + return false + case Float32, Float64, Complex64, Complex128, Interface, String: + // Float keys can be updated from +0 to -0. + // String keys can be updated to use a smaller backing store. + // Interfaces might have floats or strings in them. + return true + case Array: + tt := (*arrayType)(unsafe.Pointer(t)) + return needKeyUpdate(tt.Elem) + case Struct: + tt := (*structType)(unsafe.Pointer(t)) + for _, f := range tt.Fields { + if needKeyUpdate(f.Typ) { + return true + } + } + return false + default: + // Func, Map, Slice, Invalid + panic("needKeyUpdate called on non-key type " + stringFor(t)) + } +} + +// hashMightPanic reports whether the hash of a map key of type t might panic. +func hashMightPanic(t *abi.Type) bool { + switch Kind(t.Kind()) { + case Interface: + return true + case Array: + tt := (*arrayType)(unsafe.Pointer(t)) + return hashMightPanic(tt.Elem) + case Struct: + tt := (*structType)(unsafe.Pointer(t)) + for _, f := range tt.Fields { + if hashMightPanic(f.Typ) { + return true + } + } + return false + default: + return false + } +} + +func bucketOf(ktyp, etyp *abi.Type) *abi.Type { + if ktyp.Size_ > abi.MapMaxKeyBytes { + ktyp = ptrTo(ktyp) + } + if etyp.Size_ > abi.MapMaxElemBytes { + etyp = ptrTo(etyp) + } + + // Prepare GC data if any. + // A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+ptrSize bytes, + // or 2064 bytes, or 258 pointer-size words, or 33 bytes of pointer bitmap. + // Note that since the key and value are known to be <= 128 bytes, + // they're guaranteed to have bitmaps instead of GC programs. + var gcdata *byte + var ptrdata uintptr + + size := abi.MapBucketCount*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize + if size&uintptr(ktyp.Align_-1) != 0 || size&uintptr(etyp.Align_-1) != 0 { + panic("reflect: bad size computation in MapOf") + } + + if ktyp.Pointers() || etyp.Pointers() { + nptr := (abi.MapBucketCount*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize) / goarch.PtrSize + n := (nptr + 7) / 8 + + // Runtime needs pointer masks to be a multiple of uintptr in size. + n = (n + goarch.PtrSize - 1) &^ (goarch.PtrSize - 1) + mask := make([]byte, n) + base := uintptr(abi.MapBucketCount / goarch.PtrSize) + + if ktyp.Pointers() { + emitGCMask(mask, base, ktyp, abi.MapBucketCount) + } + base += abi.MapBucketCount * ktyp.Size_ / goarch.PtrSize + + if etyp.Pointers() { + emitGCMask(mask, base, etyp, abi.MapBucketCount) + } + base += abi.MapBucketCount * etyp.Size_ / goarch.PtrSize + + word := base + mask[word/8] |= 1 << (word % 8) + gcdata = &mask[0] + ptrdata = (word + 1) * goarch.PtrSize + + // overflow word must be last + if ptrdata != size { + panic("reflect: bad layout computation in MapOf") + } + } + + b := &abi.Type{ + Align_: goarch.PtrSize, + Size_: size, + Kind_: abi.Struct, + PtrBytes: ptrdata, + GCData: gcdata, + } + s := "bucket(" + stringFor(ktyp) + "," + stringFor(etyp) + ")" + b.Str = resolveReflectName(newName(s, "", false, false)) + return b +} + +func (t *rtype) gcSlice(begin, end uintptr) []byte { + return (*[1 << 30]byte)(unsafe.Pointer(t.t.GCData))[begin:end:end] +} + +// emitGCMask writes the GC mask for [n]typ into out, starting at bit +// offset base. +func emitGCMask(out []byte, base uintptr, typ *abi.Type, n uintptr) { + if typ.Kind_&abi.KindGCProg != 0 { + panic("reflect: unexpected GC program") + } + ptrs := typ.PtrBytes / goarch.PtrSize + words := typ.Size_ / goarch.PtrSize + mask := typ.GcSlice(0, (ptrs+7)/8) + for j := uintptr(0); j < ptrs; j++ { + if (mask[j/8]>>(j%8))&1 != 0 { + for i := uintptr(0); i < n; i++ { + k := base + i*words + j + out[k/8] |= 1 << (k % 8) + } + } + } +} + +// appendGCProg appends the GC program for the first ptrdata bytes of +// typ to dst and returns the extended slice. +func appendGCProg(dst []byte, typ *abi.Type) []byte { + if typ.Kind_&abi.KindGCProg != 0 { + // Element has GC program; emit one element. + n := uintptr(*(*uint32)(unsafe.Pointer(typ.GCData))) + prog := typ.GcSlice(4, 4+n-1) + return append(dst, prog...) + } + + // Element is small with pointer mask; use as literal bits. + ptrs := typ.PtrBytes / goarch.PtrSize + mask := typ.GcSlice(0, (ptrs+7)/8) + + // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). + for ; ptrs > 120; ptrs -= 120 { + dst = append(dst, 120) + dst = append(dst, mask[:15]...) + mask = mask[15:] + } + + dst = append(dst, byte(ptrs)) + dst = append(dst, mask...) + return dst +} + +// SliceOf returns the slice type with element type t. +// For example, if t represents int, SliceOf(t) represents []int. +func SliceOf(t Type) Type { + typ := t.common() + + // Look in cache. + ckey := cacheKey{Slice, typ, nil, 0} + if slice, ok := lookupCache.Load(ckey); ok { + return slice.(Type) + } + + // Look in known types. + s := "[]" + stringFor(typ) + for _, tt := range typesByString(s) { + slice := (*sliceType)(unsafe.Pointer(tt)) + if slice.Elem == typ { + ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt)) + return ti.(Type) + } + } + + // Make a slice type. + var islice any = ([]unsafe.Pointer)(nil) + prototype := *(**sliceType)(unsafe.Pointer(&islice)) + slice := *prototype + slice.TFlag = 0 + slice.Str = resolveReflectName(newName(s, "", false, false)) + slice.Hash = fnv1(typ.Hash, '[') + slice.Elem = typ + slice.PtrToThis = 0 + + ti, _ := lookupCache.LoadOrStore(ckey, toRType(&slice.Type)) + return ti.(Type) +} + +// The structLookupCache caches StructOf lookups. +// StructOf does not share the common lookupCache since we need to pin +// the memory associated with *structTypeFixedN. +var structLookupCache struct { + sync.Mutex // Guards stores (but not loads) on m. + + // m is a map[uint32][]Type keyed by the hash calculated in StructOf. + // Elements in m are append-only and thus safe for concurrent reading. + m sync.Map +} + +type structTypeUncommon struct { + structType + u uncommonType +} + +// isLetter reports whether a given 'rune' is classified as a Letter. +func isLetter(ch rune) bool { + return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch) +} + +// isValidFieldName checks if a string is a valid (struct) field name or not. +// +// According to the language spec, a field name should be an identifier. +// +// identifier = letter { letter | unicode_digit } . +// letter = unicode_letter | "_" . +func isValidFieldName(fieldName string) bool { + for i, c := range fieldName { + if i == 0 && !isLetter(c) { + return false + } + + if !(isLetter(c) || unicode.IsDigit(c)) { + return false + } + } + + return len(fieldName) > 0 +} + +// This must match cmd/compile/internal/compare.IsRegularMemory +func isRegularMemory(t Type) bool { + switch t.Kind() { + case Array: + elem := t.Elem() + if isRegularMemory(elem) { + return true + } + return elem.Comparable() && t.Len() == 0 + case Int8, Int16, Int32, Int64, Int, Uint8, Uint16, Uint32, Uint64, Uint, Uintptr, Chan, Pointer, Bool, UnsafePointer: + return true + case Struct: + num := t.NumField() + switch num { + case 0: + return true + case 1: + field := t.Field(0) + if field.Name == "_" { + return false + } + return isRegularMemory(field.Type) + default: + for i := range num { + field := t.Field(i) + if field.Name == "_" || !isRegularMemory(field.Type) || isPaddedField(t, i) { + return false + } + } + return true + } + } + return false +} + +// isPaddedField reports whether the i'th field of struct type t is followed +// by padding. +func isPaddedField(t Type, i int) bool { + field := t.Field(i) + if i+1 < t.NumField() { + return field.Offset+field.Type.Size() != t.Field(i+1).Offset + } + return field.Offset+field.Type.Size() != t.Size() +} + +// StructOf returns the struct type containing fields. +// The Offset and Index fields are ignored and computed as they would be +// by the compiler. +// +// StructOf currently does not support promoted methods of embedded fields +// and panics if passed unexported StructFields. +func StructOf(fields []StructField) Type { + var ( + hash = fnv1(0, []byte("struct {")...) + size uintptr + typalign uint8 + comparable = true + methods []abi.Method + + fs = make([]structField, len(fields)) + repr = make([]byte, 0, 64) + fset = map[string]struct{}{} // fields' names + + hasGCProg = false // records whether a struct-field type has a GCProg + ) + + lastzero := uintptr(0) + repr = append(repr, "struct {"...) + pkgpath := "" + for i, field := range fields { + if field.Name == "" { + panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name") + } + if !isValidFieldName(field.Name) { + panic("reflect.StructOf: field " + strconv.Itoa(i) + " has invalid name") + } + if field.Type == nil { + panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type") + } + f, fpkgpath := runtimeStructField(field) + ft := f.Typ + if ft.Kind_&abi.KindGCProg != 0 { + hasGCProg = true + } + if fpkgpath != "" { + if pkgpath == "" { + pkgpath = fpkgpath + } else if pkgpath != fpkgpath { + panic("reflect.Struct: fields with different PkgPath " + pkgpath + " and " + fpkgpath) + } + } + + // Update string and hash + name := f.Name.Name() + hash = fnv1(hash, []byte(name)...) + if !f.Embedded() { + repr = append(repr, (" " + name)...) + } else { + // Embedded field + if f.Typ.Kind() == abi.Pointer { + // Embedded ** and *interface{} are illegal + elem := ft.Elem() + if k := elem.Kind(); k == abi.Pointer || k == abi.Interface { + panic("reflect.StructOf: illegal embedded field type " + stringFor(ft)) + } + } + + switch Kind(f.Typ.Kind()) { + case Interface: + ift := (*interfaceType)(unsafe.Pointer(ft)) + for _, m := range ift.Methods { + if pkgPath(ift.nameOff(m.Name)) != "" { + // TODO(sbinet). Issue 15924. + panic("reflect: embedded interface with unexported method(s) not implemented") + } + + fnStub := resolveReflectText(unsafe.Pointer(abi.FuncPCABIInternal(embeddedIfaceMethStub))) + methods = append(methods, abi.Method{ + Name: resolveReflectName(ift.nameOff(m.Name)), + Mtyp: resolveReflectType(ift.typeOff(m.Typ)), + Ifn: fnStub, + Tfn: fnStub, + }) + } + case Pointer: + ptr := (*ptrType)(unsafe.Pointer(ft)) + if unt := ptr.Uncommon(); unt != nil { + if i > 0 && unt.Mcount > 0 { + // Issue 15924. + panic("reflect: embedded type with methods not implemented if type is not first field") + } + if len(fields) > 1 { + panic("reflect: embedded type with methods not implemented if there is more than one field") + } + for _, m := range unt.Methods() { + mname := nameOffFor(ft, m.Name) + if pkgPath(mname) != "" { + // TODO(sbinet). + // Issue 15924. + panic("reflect: embedded interface with unexported method(s) not implemented") + } + methods = append(methods, abi.Method{ + Name: resolveReflectName(mname), + Mtyp: resolveReflectType(typeOffFor(ft, m.Mtyp)), + Ifn: resolveReflectText(textOffFor(ft, m.Ifn)), + Tfn: resolveReflectText(textOffFor(ft, m.Tfn)), + }) + } + } + if unt := ptr.Elem.Uncommon(); unt != nil { + for _, m := range unt.Methods() { + mname := nameOffFor(ft, m.Name) + if pkgPath(mname) != "" { + // TODO(sbinet) + // Issue 15924. + panic("reflect: embedded interface with unexported method(s) not implemented") + } + methods = append(methods, abi.Method{ + Name: resolveReflectName(mname), + Mtyp: resolveReflectType(typeOffFor(ptr.Elem, m.Mtyp)), + Ifn: resolveReflectText(textOffFor(ptr.Elem, m.Ifn)), + Tfn: resolveReflectText(textOffFor(ptr.Elem, m.Tfn)), + }) + } + } + default: + if unt := ft.Uncommon(); unt != nil { + if i > 0 && unt.Mcount > 0 { + // Issue 15924. + panic("reflect: embedded type with methods not implemented if type is not first field") + } + if len(fields) > 1 && ft.Kind_&abi.KindDirectIface != 0 { + panic("reflect: embedded type with methods not implemented for non-pointer type") + } + for _, m := range unt.Methods() { + mname := nameOffFor(ft, m.Name) + if pkgPath(mname) != "" { + // TODO(sbinet) + // Issue 15924. + panic("reflect: embedded interface with unexported method(s) not implemented") + } + methods = append(methods, abi.Method{ + Name: resolveReflectName(mname), + Mtyp: resolveReflectType(typeOffFor(ft, m.Mtyp)), + Ifn: resolveReflectText(textOffFor(ft, m.Ifn)), + Tfn: resolveReflectText(textOffFor(ft, m.Tfn)), + }) + + } + } + } + } + if _, dup := fset[name]; dup && name != "_" { + panic("reflect.StructOf: duplicate field " + name) + } + fset[name] = struct{}{} + + hash = fnv1(hash, byte(ft.Hash>>24), byte(ft.Hash>>16), byte(ft.Hash>>8), byte(ft.Hash)) + + repr = append(repr, (" " + stringFor(ft))...) + if f.Name.HasTag() { + hash = fnv1(hash, []byte(f.Name.Tag())...) + repr = append(repr, (" " + strconv.Quote(f.Name.Tag()))...) + } + if i < len(fields)-1 { + repr = append(repr, ';') + } + + comparable = comparable && (ft.Equal != nil) + + offset := align(size, uintptr(ft.Align_)) + if offset < size { + panic("reflect.StructOf: struct size would exceed virtual address space") + } + if ft.Align_ > typalign { + typalign = ft.Align_ + } + size = offset + ft.Size_ + if size < offset { + panic("reflect.StructOf: struct size would exceed virtual address space") + } + f.Offset = offset + + if ft.Size_ == 0 { + lastzero = size + } + + fs[i] = f + } + + if size > 0 && lastzero == size { + // This is a non-zero sized struct that ends in a + // zero-sized field. We add an extra byte of padding, + // to ensure that taking the address of the final + // zero-sized field can't manufacture a pointer to the + // next object in the heap. See issue 9401. + size++ + if size == 0 { + panic("reflect.StructOf: struct size would exceed virtual address space") + } + } + + var typ *structType + var ut *uncommonType + + if len(methods) == 0 { + t := new(structTypeUncommon) + typ = &t.structType + ut = &t.u + } else { + // A *rtype representing a struct is followed directly in memory by an + // array of method objects representing the methods attached to the + // struct. To get the same layout for a run time generated type, we + // need an array directly following the uncommonType memory. + // A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN. + tt := New(StructOf([]StructField{ + {Name: "S", Type: TypeOf(structType{})}, + {Name: "U", Type: TypeOf(uncommonType{})}, + {Name: "M", Type: ArrayOf(len(methods), TypeOf(methods[0]))}, + })) + + typ = (*structType)(tt.Elem().Field(0).Addr().UnsafePointer()) + ut = (*uncommonType)(tt.Elem().Field(1).Addr().UnsafePointer()) + + copy(tt.Elem().Field(2).Slice(0, len(methods)).Interface().([]abi.Method), methods) + } + // TODO(sbinet): Once we allow embedding multiple types, + // methods will need to be sorted like the compiler does. + // TODO(sbinet): Once we allow non-exported methods, we will + // need to compute xcount as the number of exported methods. + ut.Mcount = uint16(len(methods)) + ut.Xcount = ut.Mcount + ut.Moff = uint32(unsafe.Sizeof(uncommonType{})) + + if len(fs) > 0 { + repr = append(repr, ' ') + } + repr = append(repr, '}') + hash = fnv1(hash, '}') + str := string(repr) + + // Round the size up to be a multiple of the alignment. + s := align(size, uintptr(typalign)) + if s < size { + panic("reflect.StructOf: struct size would exceed virtual address space") + } + size = s + + // Make the struct type. + var istruct any = struct{}{} + prototype := *(**structType)(unsafe.Pointer(&istruct)) + *typ = *prototype + typ.Fields = fs + if pkgpath != "" { + typ.PkgPath = newName(pkgpath, "", false, false) + } + + // Look in cache. + if ts, ok := structLookupCache.m.Load(hash); ok { + for _, st := range ts.([]Type) { + t := st.common() + if haveIdenticalUnderlyingType(&typ.Type, t, true) { + return toType(t) + } + } + } + + // Not in cache, lock and retry. + structLookupCache.Lock() + defer structLookupCache.Unlock() + if ts, ok := structLookupCache.m.Load(hash); ok { + for _, st := range ts.([]Type) { + t := st.common() + if haveIdenticalUnderlyingType(&typ.Type, t, true) { + return toType(t) + } + } + } + + addToCache := func(t Type) Type { + var ts []Type + if ti, ok := structLookupCache.m.Load(hash); ok { + ts = ti.([]Type) + } + structLookupCache.m.Store(hash, append(ts, t)) + return t + } + + // Look in known types. + for _, t := range typesByString(str) { + if haveIdenticalUnderlyingType(&typ.Type, t, true) { + // even if 't' wasn't a structType with methods, we should be ok + // as the 'u uncommonType' field won't be accessed except when + // tflag&abi.TFlagUncommon is set. + return addToCache(toType(t)) + } + } + + typ.Str = resolveReflectName(newName(str, "", false, false)) + if isRegularMemory(toType(&typ.Type)) { + typ.TFlag = abi.TFlagRegularMemory + } else { + typ.TFlag = 0 + } + typ.Hash = hash + typ.Size_ = size + typ.PtrBytes = typeptrdata(&typ.Type) + typ.Align_ = typalign + typ.FieldAlign_ = typalign + typ.PtrToThis = 0 + if len(methods) > 0 { + typ.TFlag |= abi.TFlagUncommon + } + + if hasGCProg { + lastPtrField := 0 + for i, ft := range fs { + if ft.Typ.Pointers() { + lastPtrField = i + } + } + prog := []byte{0, 0, 0, 0} // will be length of prog + var off uintptr + for i, ft := range fs { + if i > lastPtrField { + // gcprog should not include anything for any field after + // the last field that contains pointer data + break + } + if !ft.Typ.Pointers() { + // Ignore pointerless fields. + continue + } + // Pad to start of this field with zeros. + if ft.Offset > off { + n := (ft.Offset - off) / goarch.PtrSize + prog = append(prog, 0x01, 0x00) // emit a 0 bit + if n > 1 { + prog = append(prog, 0x81) // repeat previous bit + prog = appendVarint(prog, n-1) // n-1 times + } + off = ft.Offset + } + + prog = appendGCProg(prog, ft.Typ) + off += ft.Typ.PtrBytes + } + prog = append(prog, 0) + *(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4) + typ.Kind_ |= abi.KindGCProg + typ.GCData = &prog[0] + } else { + typ.Kind_ &^= abi.KindGCProg + bv := new(bitVector) + addTypeBits(bv, 0, &typ.Type) + if len(bv.data) > 0 { + typ.GCData = &bv.data[0] + } + } + typ.Equal = nil + if comparable { + typ.Equal = func(p, q unsafe.Pointer) bool { + for _, ft := range typ.Fields { + pi := add(p, ft.Offset, "&x.field safe") + qi := add(q, ft.Offset, "&x.field safe") + if !ft.Typ.Equal(pi, qi) { + return false + } + } + return true + } + } + + switch { + case len(fs) == 1 && !fs[0].Typ.IfaceIndir(): + // structs of 1 direct iface type can be direct + typ.Kind_ |= abi.KindDirectIface + default: + typ.Kind_ &^= abi.KindDirectIface + } + + return addToCache(toType(&typ.Type)) +} + +func embeddedIfaceMethStub() { + panic("reflect: StructOf does not support methods of embedded interfaces") +} + +// runtimeStructField takes a StructField value passed to StructOf and +// returns both the corresponding internal representation, of type +// structField, and the pkgpath value to use for this field. +func runtimeStructField(field StructField) (structField, string) { + if field.Anonymous && field.PkgPath != "" { + panic("reflect.StructOf: field \"" + field.Name + "\" is anonymous but has PkgPath set") + } + + if field.IsExported() { + // Best-effort check for misuse. + // Since this field will be treated as exported, not much harm done if Unicode lowercase slips through. + c := field.Name[0] + if 'a' <= c && c <= 'z' || c == '_' { + panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath") + } + } + + resolveReflectType(field.Type.common()) // install in runtime + f := structField{ + Name: newName(field.Name, string(field.Tag), field.IsExported(), field.Anonymous), + Typ: field.Type.common(), + Offset: 0, + } + return f, field.PkgPath +} + +// typeptrdata returns the length in bytes of the prefix of t +// containing pointer data. Anything after this offset is scalar data. +// keep in sync with ../cmd/compile/internal/reflectdata/reflect.go +func typeptrdata(t *abi.Type) uintptr { + switch t.Kind() { + case abi.Struct: + st := (*structType)(unsafe.Pointer(t)) + // find the last field that has pointers. + field := -1 + for i := range st.Fields { + ft := st.Fields[i].Typ + if ft.Pointers() { + field = i + } + } + if field == -1 { + return 0 + } + f := st.Fields[field] + return f.Offset + f.Typ.PtrBytes + + default: + panic("reflect.typeptrdata: unexpected type, " + stringFor(t)) + } +} + +// ArrayOf returns the array type with the given length and element type. +// For example, if t represents int, ArrayOf(5, t) represents [5]int. +// +// If the resulting type would be larger than the available address space, +// ArrayOf panics. +func ArrayOf(length int, elem Type) Type { + if length < 0 { + panic("reflect: negative length passed to ArrayOf") + } + + typ := elem.common() + + // Look in cache. + ckey := cacheKey{Array, typ, nil, uintptr(length)} + if array, ok := lookupCache.Load(ckey); ok { + return array.(Type) + } + + // Look in known types. + s := "[" + strconv.Itoa(length) + "]" + stringFor(typ) + for _, tt := range typesByString(s) { + array := (*arrayType)(unsafe.Pointer(tt)) + if array.Elem == typ { + ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt)) + return ti.(Type) + } + } + + // Make an array type. + var iarray any = [1]unsafe.Pointer{} + prototype := *(**arrayType)(unsafe.Pointer(&iarray)) + array := *prototype + array.TFlag = typ.TFlag & abi.TFlagRegularMemory + array.Str = resolveReflectName(newName(s, "", false, false)) + array.Hash = fnv1(typ.Hash, '[') + for n := uint32(length); n > 0; n >>= 8 { + array.Hash = fnv1(array.Hash, byte(n)) + } + array.Hash = fnv1(array.Hash, ']') + array.Elem = typ + array.PtrToThis = 0 + if typ.Size_ > 0 { + max := ^uintptr(0) / typ.Size_ + if uintptr(length) > max { + panic("reflect.ArrayOf: array size would exceed virtual address space") + } + } + array.Size_ = typ.Size_ * uintptr(length) + if length > 0 && typ.Pointers() { + array.PtrBytes = typ.Size_*uintptr(length-1) + typ.PtrBytes + } + array.Align_ = typ.Align_ + array.FieldAlign_ = typ.FieldAlign_ + array.Len = uintptr(length) + array.Slice = &(SliceOf(elem).(*rtype).t) + + switch { + case !typ.Pointers() || array.Size_ == 0: + // No pointers. + array.GCData = nil + array.PtrBytes = 0 + + case length == 1: + // In memory, 1-element array looks just like the element. + array.Kind_ |= typ.Kind_ & abi.KindGCProg + array.GCData = typ.GCData + array.PtrBytes = typ.PtrBytes + + case typ.Kind_&abi.KindGCProg == 0 && array.Size_ <= abi.MaxPtrmaskBytes*8*goarch.PtrSize: + // Element is small with pointer mask; array is still small. + // Create direct pointer mask by turning each 1 bit in elem + // into length 1 bits in larger mask. + n := (array.PtrBytes/goarch.PtrSize + 7) / 8 + // Runtime needs pointer masks to be a multiple of uintptr in size. + n = (n + goarch.PtrSize - 1) &^ (goarch.PtrSize - 1) + mask := make([]byte, n) + emitGCMask(mask, 0, typ, array.Len) + array.GCData = &mask[0] + + default: + // Create program that emits one element + // and then repeats to make the array. + prog := []byte{0, 0, 0, 0} // will be length of prog + prog = appendGCProg(prog, typ) + // Pad from ptrdata to size. + elemPtrs := typ.PtrBytes / goarch.PtrSize + elemWords := typ.Size_ / goarch.PtrSize + if elemPtrs < elemWords { + // Emit literal 0 bit, then repeat as needed. + prog = append(prog, 0x01, 0x00) + if elemPtrs+1 < elemWords { + prog = append(prog, 0x81) + prog = appendVarint(prog, elemWords-elemPtrs-1) + } + } + // Repeat length-1 times. + if elemWords < 0x80 { + prog = append(prog, byte(elemWords|0x80)) + } else { + prog = append(prog, 0x80) + prog = appendVarint(prog, elemWords) + } + prog = appendVarint(prog, uintptr(length)-1) + prog = append(prog, 0) + *(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4) + array.Kind_ |= abi.KindGCProg + array.GCData = &prog[0] + array.PtrBytes = array.Size_ // overestimate but ok; must match program + } + + etyp := typ + esize := etyp.Size() + + array.Equal = nil + if eequal := etyp.Equal; eequal != nil { + array.Equal = func(p, q unsafe.Pointer) bool { + for i := 0; i < length; i++ { + pi := arrayAt(p, i, esize, "i < length") + qi := arrayAt(q, i, esize, "i < length") + if !eequal(pi, qi) { + return false + } + + } + return true + } + } + + switch { + case length == 1 && !typ.IfaceIndir(): + // array of 1 direct iface type can be direct + array.Kind_ |= abi.KindDirectIface + default: + array.Kind_ &^= abi.KindDirectIface + } + + ti, _ := lookupCache.LoadOrStore(ckey, toRType(&array.Type)) + return ti.(Type) +} + +func appendVarint(x []byte, v uintptr) []byte { + for ; v >= 0x80; v >>= 7 { + x = append(x, byte(v|0x80)) + } + x = append(x, byte(v)) + return x +} + +// toType converts from a *rtype to a Type that can be returned +// to the client of package reflect. In gc, the only concern is that +// a nil *rtype must be replaced by a nil Type, but in gccgo this +// function takes care of ensuring that multiple *rtype for the same +// type are coalesced into a single Type. +// +// toType should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - fortio.org/log +// - github.com/goccy/go-json +// - github.com/goccy/go-reflect +// - github.com/sohaha/zlsgo +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname toType +func toType(t *abi.Type) Type { + if t == nil { + return nil + } + return toRType(t) +} + +type layoutKey struct { + ftyp *funcType // function signature + rcvr *abi.Type // receiver type, or nil if none +} + +type layoutType struct { + t *abi.Type + framePool *sync.Pool + abid abiDesc +} + +var layoutCache sync.Map // map[layoutKey]layoutType + +// funcLayout computes a struct type representing the layout of the +// stack-assigned function arguments and return values for the function +// type t. +// If rcvr != nil, rcvr specifies the type of the receiver. +// The returned type exists only for GC, so we only fill out GC relevant info. +// Currently, that's just size and the GC program. We also fill in +// the name for possible debugging use. +func funcLayout(t *funcType, rcvr *abi.Type) (frametype *abi.Type, framePool *sync.Pool, abid abiDesc) { + if t.Kind() != abi.Func { + panic("reflect: funcLayout of non-func type " + stringFor(&t.Type)) + } + if rcvr != nil && rcvr.Kind() == abi.Interface { + panic("reflect: funcLayout with interface receiver " + stringFor(rcvr)) + } + k := layoutKey{t, rcvr} + if lti, ok := layoutCache.Load(k); ok { + lt := lti.(layoutType) + return lt.t, lt.framePool, lt.abid + } + + // Compute the ABI layout. + abid = newAbiDesc(t, rcvr) + + // build dummy rtype holding gc program + x := &abi.Type{ + Align_: goarch.PtrSize, + // Don't add spill space here; it's only necessary in + // reflectcall's frame, not in the allocated frame. + // TODO(mknyszek): Remove this comment when register + // spill space in the frame is no longer required. + Size_: align(abid.retOffset+abid.ret.stackBytes, goarch.PtrSize), + PtrBytes: uintptr(abid.stackPtrs.n) * goarch.PtrSize, + } + if abid.stackPtrs.n > 0 { + x.GCData = &abid.stackPtrs.data[0] + } + + var s string + if rcvr != nil { + s = "methodargs(" + stringFor(rcvr) + ")(" + stringFor(&t.Type) + ")" + } else { + s = "funcargs(" + stringFor(&t.Type) + ")" + } + x.Str = resolveReflectName(newName(s, "", false, false)) + + // cache result for future callers + framePool = &sync.Pool{New: func() any { + return unsafe_New(x) + }} + lti, _ := layoutCache.LoadOrStore(k, layoutType{ + t: x, + framePool: framePool, + abid: abid, + }) + lt := lti.(layoutType) + return lt.t, lt.framePool, lt.abid +} + +// Note: this type must agree with runtime.bitvector. +type bitVector struct { + n uint32 // number of bits + data []byte +} + +// append a bit to the bitmap. +func (bv *bitVector) append(bit uint8) { + if bv.n%(8*goarch.PtrSize) == 0 { + // Runtime needs pointer masks to be a multiple of uintptr in size. + // Since reflect passes bv.data directly to the runtime as a pointer mask, + // we append a full uintptr of zeros at a time. + for i := 0; i < goarch.PtrSize; i++ { + bv.data = append(bv.data, 0) + } + } + bv.data[bv.n/8] |= bit << (bv.n % 8) + bv.n++ +} + +func addTypeBits(bv *bitVector, offset uintptr, t *abi.Type) { + if !t.Pointers() { + return + } + + switch Kind(t.Kind_ & abi.KindMask) { + case Chan, Func, Map, Pointer, Slice, String, UnsafePointer: + // 1 pointer at start of representation + for bv.n < uint32(offset/goarch.PtrSize) { + bv.append(0) + } + bv.append(1) + + case Interface: + // 2 pointers + for bv.n < uint32(offset/goarch.PtrSize) { + bv.append(0) + } + bv.append(1) + bv.append(1) + + case Array: + // repeat inner type + tt := (*arrayType)(unsafe.Pointer(t)) + for i := 0; i < int(tt.Len); i++ { + addTypeBits(bv, offset+uintptr(i)*tt.Elem.Size_, tt.Elem) + } + + case Struct: + // apply fields + tt := (*structType)(unsafe.Pointer(t)) + for i := range tt.Fields { + f := &tt.Fields[i] + addTypeBits(bv, offset+f.Offset, f.Typ) + } + } +} + +// TypeFor returns the [Type] that represents the type argument T. +func TypeFor[T any]() Type { + var v T + if t := TypeOf(v); t != nil { + return t // optimize for T being a non-interface kind + } + return TypeOf((*T)(nil)).Elem() // only for an interface kind +} diff --git a/contrib/go/_std_1.23/src/reflect/value.go b/contrib/go/_std_1.23/src/reflect/value.go new file mode 100644 index 000000000000..6e8e46aa594c --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/value.go @@ -0,0 +1,4045 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflect + +import ( + "errors" + "internal/abi" + "internal/goarch" + "internal/itoa" + "internal/unsafeheader" + "math" + "runtime" + "unsafe" +) + +// Value is the reflection interface to a Go value. +// +// Not all methods apply to all kinds of values. Restrictions, +// if any, are noted in the documentation for each method. +// Use the Kind method to find out the kind of value before +// calling kind-specific methods. Calling a method +// inappropriate to the kind of type causes a run time panic. +// +// The zero Value represents no value. +// Its [Value.IsValid] method returns false, its Kind method returns [Invalid], +// its String method returns "", and all other methods panic. +// Most functions and methods never return an invalid value. +// If one does, its documentation states the conditions explicitly. +// +// A Value can be used concurrently by multiple goroutines provided that +// the underlying Go value can be used concurrently for the equivalent +// direct operations. +// +// To compare two Values, compare the results of the Interface method. +// Using == on two Values does not compare the underlying values +// they represent. +type Value struct { + // typ_ holds the type of the value represented by a Value. + // Access using the typ method to avoid escape of v. + typ_ *abi.Type + + // Pointer-valued data or, if flagIndir is set, pointer to data. + // Valid when either flagIndir is set or typ.pointers() is true. + ptr unsafe.Pointer + + // flag holds metadata about the value. + // + // The lowest five bits give the Kind of the value, mirroring typ.Kind(). + // + // The next set of bits are flag bits: + // - flagStickyRO: obtained via unexported not embedded field, so read-only + // - flagEmbedRO: obtained via unexported embedded field, so read-only + // - flagIndir: val holds a pointer to the data + // - flagAddr: v.CanAddr is true (implies flagIndir and ptr is non-nil) + // - flagMethod: v is a method value. + // If ifaceIndir(typ), code can assume that flagIndir is set. + // + // The remaining 22+ bits give a method number for method values. + // If flag.kind() != Func, code can assume that flagMethod is unset. + flag + + // A method value represents a curried method invocation + // like r.Read for some receiver r. The typ+val+flag bits describe + // the receiver r, but the flag's Kind bits say Func (methods are + // functions), and the top bits of the flag give the method number + // in r's type's method table. +} + +type flag uintptr + +const ( + flagKindWidth = 5 // there are 27 kinds + flagKindMask flag = 1< len(prefix) && name[:len(prefix)] == prefix { + methodName := name[len(prefix):] + if len(methodName) > 0 && 'A' <= methodName[0] && methodName[0] <= 'Z' { + return name + } + } + } + return "unknown method" +} + +// nonEmptyInterface is the header for an interface value with methods. +type nonEmptyInterface struct { + itab *abi.ITab + word unsafe.Pointer +} + +// mustBe panics if f's kind is not expected. +// Making this a method on flag instead of on Value +// (and embedding flag in Value) means that we can write +// the very clear v.mustBe(Bool) and have it compile into +// v.flag.mustBe(Bool), which will only bother to copy the +// single important word for the receiver. +func (f flag) mustBe(expected Kind) { + // TODO(mvdan): use f.kind() again once mid-stack inlining gets better + if Kind(f&flagKindMask) != expected { + panic(&ValueError{valueMethodName(), f.kind()}) + } +} + +// mustBeExported panics if f records that the value was obtained using +// an unexported field. +func (f flag) mustBeExported() { + if f == 0 || f&flagRO != 0 { + f.mustBeExportedSlow() + } +} + +func (f flag) mustBeExportedSlow() { + if f == 0 { + panic(&ValueError{valueMethodName(), Invalid}) + } + if f&flagRO != 0 { + panic("reflect: " + valueMethodName() + " using value obtained using unexported field") + } +} + +// mustBeAssignable panics if f records that the value is not assignable, +// which is to say that either it was obtained using an unexported field +// or it is not addressable. +func (f flag) mustBeAssignable() { + if f&flagRO != 0 || f&flagAddr == 0 { + f.mustBeAssignableSlow() + } +} + +func (f flag) mustBeAssignableSlow() { + if f == 0 { + panic(&ValueError{valueMethodName(), Invalid}) + } + // Assignable if addressable and not read-only. + if f&flagRO != 0 { + panic("reflect: " + valueMethodName() + " using value obtained using unexported field") + } + if f&flagAddr == 0 { + panic("reflect: " + valueMethodName() + " using unaddressable value") + } +} + +// Addr returns a pointer value representing the address of v. +// It panics if [Value.CanAddr] returns false. +// Addr is typically used to obtain a pointer to a struct field +// or slice element in order to call a method that requires a +// pointer receiver. +func (v Value) Addr() Value { + if v.flag&flagAddr == 0 { + panic("reflect.Value.Addr of unaddressable value") + } + // Preserve flagRO instead of using v.flag.ro() so that + // v.Addr().Elem() is equivalent to v (#32772) + fl := v.flag & flagRO + return Value{ptrTo(v.typ()), v.ptr, fl | flag(Pointer)} +} + +// Bool returns v's underlying value. +// It panics if v's kind is not [Bool]. +func (v Value) Bool() bool { + // panicNotBool is split out to keep Bool inlineable. + if v.kind() != Bool { + v.panicNotBool() + } + return *(*bool)(v.ptr) +} + +func (v Value) panicNotBool() { + v.mustBe(Bool) +} + +var bytesType = rtypeOf(([]byte)(nil)) + +// Bytes returns v's underlying value. +// It panics if v's underlying value is not a slice of bytes or +// an addressable array of bytes. +func (v Value) Bytes() []byte { + // bytesSlow is split out to keep Bytes inlineable for unnamed []byte. + if v.typ_ == bytesType { // ok to use v.typ_ directly as comparison doesn't cause escape + return *(*[]byte)(v.ptr) + } + return v.bytesSlow() +} + +func (v Value) bytesSlow() []byte { + switch v.kind() { + case Slice: + if v.typ().Elem().Kind() != abi.Uint8 { + panic("reflect.Value.Bytes of non-byte slice") + } + // Slice is always bigger than a word; assume flagIndir. + return *(*[]byte)(v.ptr) + case Array: + if v.typ().Elem().Kind() != abi.Uint8 { + panic("reflect.Value.Bytes of non-byte array") + } + if !v.CanAddr() { + panic("reflect.Value.Bytes of unaddressable byte array") + } + p := (*byte)(v.ptr) + n := int((*arrayType)(unsafe.Pointer(v.typ())).Len) + return unsafe.Slice(p, n) + } + panic(&ValueError{"reflect.Value.Bytes", v.kind()}) +} + +// runes returns v's underlying value. +// It panics if v's underlying value is not a slice of runes (int32s). +func (v Value) runes() []rune { + v.mustBe(Slice) + if v.typ().Elem().Kind() != abi.Int32 { + panic("reflect.Value.Bytes of non-rune slice") + } + // Slice is always bigger than a word; assume flagIndir. + return *(*[]rune)(v.ptr) +} + +// CanAddr reports whether the value's address can be obtained with [Value.Addr]. +// Such values are called addressable. A value is addressable if it is +// an element of a slice, an element of an addressable array, +// a field of an addressable struct, or the result of dereferencing a pointer. +// If CanAddr returns false, calling [Value.Addr] will panic. +func (v Value) CanAddr() bool { + return v.flag&flagAddr != 0 +} + +// CanSet reports whether the value of v can be changed. +// A [Value] can be changed only if it is addressable and was not +// obtained by the use of unexported struct fields. +// If CanSet returns false, calling [Value.Set] or any type-specific +// setter (e.g., [Value.SetBool], [Value.SetInt]) will panic. +func (v Value) CanSet() bool { + return v.flag&(flagAddr|flagRO) == flagAddr +} + +// Call calls the function v with the input arguments in. +// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]). +// Call panics if v's Kind is not [Func]. +// It returns the output results as Values. +// As in Go, each input argument must be assignable to the +// type of the function's corresponding input parameter. +// If v is a variadic function, Call creates the variadic slice parameter +// itself, copying in the corresponding values. +func (v Value) Call(in []Value) []Value { + v.mustBe(Func) + v.mustBeExported() + return v.call("Call", in) +} + +// CallSlice calls the variadic function v with the input arguments in, +// assigning the slice in[len(in)-1] to v's final variadic argument. +// For example, if len(in) == 3, v.CallSlice(in) represents the Go call v(in[0], in[1], in[2]...). +// CallSlice panics if v's Kind is not [Func] or if v is not variadic. +// It returns the output results as Values. +// As in Go, each input argument must be assignable to the +// type of the function's corresponding input parameter. +func (v Value) CallSlice(in []Value) []Value { + v.mustBe(Func) + v.mustBeExported() + return v.call("CallSlice", in) +} + +var callGC bool // for testing; see TestCallMethodJump and TestCallArgLive + +const debugReflectCall = false + +func (v Value) call(op string, in []Value) []Value { + // Get function pointer, type. + t := (*funcType)(unsafe.Pointer(v.typ())) + var ( + fn unsafe.Pointer + rcvr Value + rcvrtype *abi.Type + ) + if v.flag&flagMethod != 0 { + rcvr = v + rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift) + } else if v.flag&flagIndir != 0 { + fn = *(*unsafe.Pointer)(v.ptr) + } else { + fn = v.ptr + } + + if fn == nil { + panic("reflect.Value.Call: call of nil function") + } + + isSlice := op == "CallSlice" + n := t.NumIn() + isVariadic := t.IsVariadic() + if isSlice { + if !isVariadic { + panic("reflect: CallSlice of non-variadic function") + } + if len(in) < n { + panic("reflect: CallSlice with too few input arguments") + } + if len(in) > n { + panic("reflect: CallSlice with too many input arguments") + } + } else { + if isVariadic { + n-- + } + if len(in) < n { + panic("reflect: Call with too few input arguments") + } + if !isVariadic && len(in) > n { + panic("reflect: Call with too many input arguments") + } + } + for _, x := range in { + if x.Kind() == Invalid { + panic("reflect: " + op + " using zero Value argument") + } + } + for i := 0; i < n; i++ { + if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(toRType(targ)) { + panic("reflect: " + op + " using " + xt.String() + " as type " + stringFor(targ)) + } + } + if !isSlice && isVariadic { + // prepare slice for remaining values + m := len(in) - n + slice := MakeSlice(toRType(t.In(n)), m, m) + elem := toRType(t.In(n)).Elem() // FIXME cast to slice type and Elem() + for i := 0; i < m; i++ { + x := in[n+i] + if xt := x.Type(); !xt.AssignableTo(elem) { + panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op) + } + slice.Index(i).Set(x) + } + origIn := in + in = make([]Value, n+1) + copy(in[:n], origIn) + in[n] = slice + } + + nin := len(in) + if nin != t.NumIn() { + panic("reflect.Value.Call: wrong argument count") + } + nout := t.NumOut() + + // Register argument space. + var regArgs abi.RegArgs + + // Compute frame type. + frametype, framePool, abid := funcLayout(t, rcvrtype) + + // Allocate a chunk of memory for frame if needed. + var stackArgs unsafe.Pointer + if frametype.Size() != 0 { + if nout == 0 { + stackArgs = framePool.Get().(unsafe.Pointer) + } else { + // Can't use pool if the function has return values. + // We will leak pointer to args in ret, so its lifetime is not scoped. + stackArgs = unsafe_New(frametype) + } + } + frameSize := frametype.Size() + + if debugReflectCall { + println("reflect.call", stringFor(&t.Type)) + abid.dump() + } + + // Copy inputs into args. + + // Handle receiver. + inStart := 0 + if rcvrtype != nil { + // Guaranteed to only be one word in size, + // so it will only take up exactly 1 abiStep (either + // in a register or on the stack). + switch st := abid.call.steps[0]; st.kind { + case abiStepStack: + storeRcvr(rcvr, stackArgs) + case abiStepPointer: + storeRcvr(rcvr, unsafe.Pointer(®Args.Ptrs[st.ireg])) + fallthrough + case abiStepIntReg: + storeRcvr(rcvr, unsafe.Pointer(®Args.Ints[st.ireg])) + case abiStepFloatReg: + storeRcvr(rcvr, unsafe.Pointer(®Args.Floats[st.freg])) + default: + panic("unknown ABI parameter kind") + } + inStart = 1 + } + + // Handle arguments. + for i, v := range in { + v.mustBeExported() + targ := toRType(t.In(i)) + // TODO(mknyszek): Figure out if it's possible to get some + // scratch space for this assignment check. Previously, it + // was possible to use space in the argument frame. + v = v.assignTo("reflect.Value.Call", &targ.t, nil) + stepsLoop: + for _, st := range abid.call.stepsForValue(i + inStart) { + switch st.kind { + case abiStepStack: + // Copy values to the "stack." + addr := add(stackArgs, st.stkOff, "precomputed stack arg offset") + if v.flag&flagIndir != 0 { + typedmemmove(&targ.t, addr, v.ptr) + } else { + *(*unsafe.Pointer)(addr) = v.ptr + } + // There's only one step for a stack-allocated value. + break stepsLoop + case abiStepIntReg, abiStepPointer: + // Copy values to "integer registers." + if v.flag&flagIndir != 0 { + offset := add(v.ptr, st.offset, "precomputed value offset") + if st.kind == abiStepPointer { + // Duplicate this pointer in the pointer area of the + // register space. Otherwise, there's the potential for + // this to be the last reference to v.ptr. + regArgs.Ptrs[st.ireg] = *(*unsafe.Pointer)(offset) + } + intToReg(®Args, st.ireg, st.size, offset) + } else { + if st.kind == abiStepPointer { + // See the comment in abiStepPointer case above. + regArgs.Ptrs[st.ireg] = v.ptr + } + regArgs.Ints[st.ireg] = uintptr(v.ptr) + } + case abiStepFloatReg: + // Copy values to "float registers." + if v.flag&flagIndir == 0 { + panic("attempted to copy pointer to FP register") + } + offset := add(v.ptr, st.offset, "precomputed value offset") + floatToReg(®Args, st.freg, st.size, offset) + default: + panic("unknown ABI part kind") + } + } + } + // TODO(mknyszek): Remove this when we no longer have + // caller reserved spill space. + frameSize = align(frameSize, goarch.PtrSize) + frameSize += abid.spill + + // Mark pointers in registers for the return path. + regArgs.ReturnIsPtr = abid.outRegPtrs + + if debugReflectCall { + regArgs.Dump() + } + + // For testing; see TestCallArgLive. + if callGC { + runtime.GC() + } + + // Call. + call(frametype, fn, stackArgs, uint32(frametype.Size()), uint32(abid.retOffset), uint32(frameSize), ®Args) + + // For testing; see TestCallMethodJump. + if callGC { + runtime.GC() + } + + var ret []Value + if nout == 0 { + if stackArgs != nil { + typedmemclr(frametype, stackArgs) + framePool.Put(stackArgs) + } + } else { + if stackArgs != nil { + // Zero the now unused input area of args, + // because the Values returned by this function contain pointers to the args object, + // and will thus keep the args object alive indefinitely. + typedmemclrpartial(frametype, stackArgs, 0, abid.retOffset) + } + + // Wrap Values around return values in args. + ret = make([]Value, nout) + for i := 0; i < nout; i++ { + tv := t.Out(i) + if tv.Size() == 0 { + // For zero-sized return value, args+off may point to the next object. + // In this case, return the zero value instead. + ret[i] = Zero(toRType(tv)) + continue + } + steps := abid.ret.stepsForValue(i) + if st := steps[0]; st.kind == abiStepStack { + // This value is on the stack. If part of a value is stack + // allocated, the entire value is according to the ABI. So + // just make an indirection into the allocated frame. + fl := flagIndir | flag(tv.Kind()) + ret[i] = Value{tv, add(stackArgs, st.stkOff, "tv.Size() != 0"), fl} + // Note: this does introduce false sharing between results - + // if any result is live, they are all live. + // (And the space for the args is live as well, but as we've + // cleared that space it isn't as big a deal.) + continue + } + + // Handle pointers passed in registers. + if !tv.IfaceIndir() { + // Pointer-valued data gets put directly + // into v.ptr. + if steps[0].kind != abiStepPointer { + print("kind=", steps[0].kind, ", type=", stringFor(tv), "\n") + panic("mismatch between ABI description and types") + } + ret[i] = Value{tv, regArgs.Ptrs[steps[0].ireg], flag(tv.Kind())} + continue + } + + // All that's left is values passed in registers that we need to + // create space for and copy values back into. + // + // TODO(mknyszek): We make a new allocation for each register-allocated + // value, but previously we could always point into the heap-allocated + // stack frame. This is a regression that could be fixed by adding + // additional space to the allocated stack frame and storing the + // register-allocated return values into the allocated stack frame and + // referring there in the resulting Value. + s := unsafe_New(tv) + for _, st := range steps { + switch st.kind { + case abiStepIntReg: + offset := add(s, st.offset, "precomputed value offset") + intFromReg(®Args, st.ireg, st.size, offset) + case abiStepPointer: + s := add(s, st.offset, "precomputed value offset") + *((*unsafe.Pointer)(s)) = regArgs.Ptrs[st.ireg] + case abiStepFloatReg: + offset := add(s, st.offset, "precomputed value offset") + floatFromReg(®Args, st.freg, st.size, offset) + case abiStepStack: + panic("register-based return value has stack component") + default: + panic("unknown ABI part kind") + } + } + ret[i] = Value{tv, s, flagIndir | flag(tv.Kind())} + } + } + + return ret +} + +// callReflect is the call implementation used by a function +// returned by MakeFunc. In many ways it is the opposite of the +// method Value.call above. The method above converts a call using Values +// into a call of a function with a concrete argument frame, while +// callReflect converts a call of a function with a concrete argument +// frame into a call using Values. +// It is in this file so that it can be next to the call method above. +// The remainder of the MakeFunc implementation is in makefunc.go. +// +// NOTE: This function must be marked as a "wrapper" in the generated code, +// so that the linker can make it work correctly for panic and recover. +// The gc compilers know to do that for the name "reflect.callReflect". +// +// ctxt is the "closure" generated by MakeFunc. +// frame is a pointer to the arguments to that closure on the stack. +// retValid points to a boolean which should be set when the results +// section of frame is set. +// +// regs contains the argument values passed in registers and will contain +// the values returned from ctxt.fn in registers. +func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool, regs *abi.RegArgs) { + if callGC { + // Call GC upon entry during testing. + // Getting our stack scanned here is the biggest hazard, because + // our caller (makeFuncStub) could have failed to place the last + // pointer to a value in regs' pointer space, in which case it + // won't be visible to the GC. + runtime.GC() + } + ftyp := ctxt.ftyp + f := ctxt.fn + + _, _, abid := funcLayout(ftyp, nil) + + // Copy arguments into Values. + ptr := frame + in := make([]Value, 0, int(ftyp.InCount)) + for i, typ := range ftyp.InSlice() { + if typ.Size() == 0 { + in = append(in, Zero(toRType(typ))) + continue + } + v := Value{typ, nil, flag(typ.Kind())} + steps := abid.call.stepsForValue(i) + if st := steps[0]; st.kind == abiStepStack { + if typ.IfaceIndir() { + // value cannot be inlined in interface data. + // Must make a copy, because f might keep a reference to it, + // and we cannot let f keep a reference to the stack frame + // after this function returns, not even a read-only reference. + v.ptr = unsafe_New(typ) + if typ.Size() > 0 { + typedmemmove(typ, v.ptr, add(ptr, st.stkOff, "typ.size > 0")) + } + v.flag |= flagIndir + } else { + v.ptr = *(*unsafe.Pointer)(add(ptr, st.stkOff, "1-ptr")) + } + } else { + if typ.IfaceIndir() { + // All that's left is values passed in registers that we need to + // create space for the values. + v.flag |= flagIndir + v.ptr = unsafe_New(typ) + for _, st := range steps { + switch st.kind { + case abiStepIntReg: + offset := add(v.ptr, st.offset, "precomputed value offset") + intFromReg(regs, st.ireg, st.size, offset) + case abiStepPointer: + s := add(v.ptr, st.offset, "precomputed value offset") + *((*unsafe.Pointer)(s)) = regs.Ptrs[st.ireg] + case abiStepFloatReg: + offset := add(v.ptr, st.offset, "precomputed value offset") + floatFromReg(regs, st.freg, st.size, offset) + case abiStepStack: + panic("register-based return value has stack component") + default: + panic("unknown ABI part kind") + } + } + } else { + // Pointer-valued data gets put directly + // into v.ptr. + if steps[0].kind != abiStepPointer { + print("kind=", steps[0].kind, ", type=", stringFor(typ), "\n") + panic("mismatch between ABI description and types") + } + v.ptr = regs.Ptrs[steps[0].ireg] + } + } + in = append(in, v) + } + + // Call underlying function. + out := f(in) + numOut := ftyp.NumOut() + if len(out) != numOut { + panic("reflect: wrong return count from function created by MakeFunc") + } + + // Copy results back into argument frame and register space. + if numOut > 0 { + for i, typ := range ftyp.OutSlice() { + v := out[i] + if v.typ() == nil { + panic("reflect: function created by MakeFunc using " + funcName(f) + + " returned zero Value") + } + if v.flag&flagRO != 0 { + panic("reflect: function created by MakeFunc using " + funcName(f) + + " returned value obtained from unexported field") + } + if typ.Size() == 0 { + continue + } + + // Convert v to type typ if v is assignable to a variable + // of type t in the language spec. + // See issue 28761. + // + // + // TODO(mknyszek): In the switch to the register ABI we lost + // the scratch space here for the register cases (and + // temporarily for all the cases). + // + // If/when this happens, take note of the following: + // + // We must clear the destination before calling assignTo, + // in case assignTo writes (with memory barriers) to the + // target location used as scratch space. See issue 39541. + v = v.assignTo("reflect.MakeFunc", typ, nil) + stepsLoop: + for _, st := range abid.ret.stepsForValue(i) { + switch st.kind { + case abiStepStack: + // Copy values to the "stack." + addr := add(ptr, st.stkOff, "precomputed stack arg offset") + // Do not use write barriers. The stack space used + // for this call is not adequately zeroed, and we + // are careful to keep the arguments alive until we + // return to makeFuncStub's caller. + if v.flag&flagIndir != 0 { + memmove(addr, v.ptr, st.size) + } else { + // This case must be a pointer type. + *(*uintptr)(addr) = uintptr(v.ptr) + } + // There's only one step for a stack-allocated value. + break stepsLoop + case abiStepIntReg, abiStepPointer: + // Copy values to "integer registers." + if v.flag&flagIndir != 0 { + offset := add(v.ptr, st.offset, "precomputed value offset") + intToReg(regs, st.ireg, st.size, offset) + } else { + // Only populate the Ints space on the return path. + // This is safe because out is kept alive until the + // end of this function, and the return path through + // makeFuncStub has no preemption, so these pointers + // are always visible to the GC. + regs.Ints[st.ireg] = uintptr(v.ptr) + } + case abiStepFloatReg: + // Copy values to "float registers." + if v.flag&flagIndir == 0 { + panic("attempted to copy pointer to FP register") + } + offset := add(v.ptr, st.offset, "precomputed value offset") + floatToReg(regs, st.freg, st.size, offset) + default: + panic("unknown ABI part kind") + } + } + } + } + + // Announce that the return values are valid. + // After this point the runtime can depend on the return values being valid. + *retValid = true + + // We have to make sure that the out slice lives at least until + // the runtime knows the return values are valid. Otherwise, the + // return values might not be scanned by anyone during a GC. + // (out would be dead, and the return slots not yet alive.) + runtime.KeepAlive(out) + + // runtime.getArgInfo expects to be able to find ctxt on the + // stack when it finds our caller, makeFuncStub. Make sure it + // doesn't get garbage collected. + runtime.KeepAlive(ctxt) +} + +// methodReceiver returns information about the receiver +// described by v. The Value v may or may not have the +// flagMethod bit set, so the kind cached in v.flag should +// not be used. +// The return value rcvrtype gives the method's actual receiver type. +// The return value t gives the method type signature (without the receiver). +// The return value fn is a pointer to the method code. +func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *abi.Type, t *funcType, fn unsafe.Pointer) { + i := methodIndex + if v.typ().Kind() == abi.Interface { + tt := (*interfaceType)(unsafe.Pointer(v.typ())) + if uint(i) >= uint(len(tt.Methods)) { + panic("reflect: internal error: invalid method index") + } + m := &tt.Methods[i] + if !tt.nameOff(m.Name).IsExported() { + panic("reflect: " + op + " of unexported method") + } + iface := (*nonEmptyInterface)(v.ptr) + if iface.itab == nil { + panic("reflect: " + op + " of method on nil interface value") + } + rcvrtype = iface.itab.Type + fn = unsafe.Pointer(&unsafe.Slice(&iface.itab.Fun[0], i+1)[i]) + t = (*funcType)(unsafe.Pointer(tt.typeOff(m.Typ))) + } else { + rcvrtype = v.typ() + ms := v.typ().ExportedMethods() + if uint(i) >= uint(len(ms)) { + panic("reflect: internal error: invalid method index") + } + m := ms[i] + if !nameOffFor(v.typ(), m.Name).IsExported() { + panic("reflect: " + op + " of unexported method") + } + ifn := textOffFor(v.typ(), m.Ifn) + fn = unsafe.Pointer(&ifn) + t = (*funcType)(unsafe.Pointer(typeOffFor(v.typ(), m.Mtyp))) + } + return +} + +// v is a method receiver. Store at p the word which is used to +// encode that receiver at the start of the argument list. +// Reflect uses the "interface" calling convention for +// methods, which always uses one word to record the receiver. +func storeRcvr(v Value, p unsafe.Pointer) { + t := v.typ() + if t.Kind() == abi.Interface { + // the interface data word becomes the receiver word + iface := (*nonEmptyInterface)(v.ptr) + *(*unsafe.Pointer)(p) = iface.word + } else if v.flag&flagIndir != 0 && !t.IfaceIndir() { + *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr) + } else { + *(*unsafe.Pointer)(p) = v.ptr + } +} + +// align returns the result of rounding x up to a multiple of n. +// n must be a power of two. +func align(x, n uintptr) uintptr { + return (x + n - 1) &^ (n - 1) +} + +// callMethod is the call implementation used by a function returned +// by makeMethodValue (used by v.Method(i).Interface()). +// It is a streamlined version of the usual reflect call: the caller has +// already laid out the argument frame for us, so we don't have +// to deal with individual Values for each argument. +// It is in this file so that it can be next to the two similar functions above. +// The remainder of the makeMethodValue implementation is in makefunc.go. +// +// NOTE: This function must be marked as a "wrapper" in the generated code, +// so that the linker can make it work correctly for panic and recover. +// The gc compilers know to do that for the name "reflect.callMethod". +// +// ctxt is the "closure" generated by makeMethodValue. +// frame is a pointer to the arguments to that closure on the stack. +// retValid points to a boolean which should be set when the results +// section of frame is set. +// +// regs contains the argument values passed in registers and will contain +// the values returned from ctxt.fn in registers. +func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *abi.RegArgs) { + rcvr := ctxt.rcvr + rcvrType, valueFuncType, methodFn := methodReceiver("call", rcvr, ctxt.method) + + // There are two ABIs at play here. + // + // methodValueCall was invoked with the ABI assuming there was no + // receiver ("value ABI") and that's what frame and regs are holding. + // + // Meanwhile, we need to actually call the method with a receiver, which + // has its own ABI ("method ABI"). Everything that follows is a translation + // between the two. + _, _, valueABI := funcLayout(valueFuncType, nil) + valueFrame, valueRegs := frame, regs + methodFrameType, methodFramePool, methodABI := funcLayout(valueFuncType, rcvrType) + + // Make a new frame that is one word bigger so we can store the receiver. + // This space is used for both arguments and return values. + methodFrame := methodFramePool.Get().(unsafe.Pointer) + var methodRegs abi.RegArgs + + // Deal with the receiver. It's guaranteed to only be one word in size. + switch st := methodABI.call.steps[0]; st.kind { + case abiStepStack: + // Only copy the receiver to the stack if the ABI says so. + // Otherwise, it'll be in a register already. + storeRcvr(rcvr, methodFrame) + case abiStepPointer: + // Put the receiver in a register. + storeRcvr(rcvr, unsafe.Pointer(&methodRegs.Ptrs[st.ireg])) + fallthrough + case abiStepIntReg: + storeRcvr(rcvr, unsafe.Pointer(&methodRegs.Ints[st.ireg])) + case abiStepFloatReg: + storeRcvr(rcvr, unsafe.Pointer(&methodRegs.Floats[st.freg])) + default: + panic("unknown ABI parameter kind") + } + + // Translate the rest of the arguments. + for i, t := range valueFuncType.InSlice() { + valueSteps := valueABI.call.stepsForValue(i) + methodSteps := methodABI.call.stepsForValue(i + 1) + + // Zero-sized types are trivial: nothing to do. + if len(valueSteps) == 0 { + if len(methodSteps) != 0 { + panic("method ABI and value ABI do not align") + } + continue + } + + // There are four cases to handle in translating each + // argument: + // 1. Stack -> stack translation. + // 2. Stack -> registers translation. + // 3. Registers -> stack translation. + // 4. Registers -> registers translation. + + // If the value ABI passes the value on the stack, + // then the method ABI does too, because it has strictly + // fewer arguments. Simply copy between the two. + if vStep := valueSteps[0]; vStep.kind == abiStepStack { + mStep := methodSteps[0] + // Handle stack -> stack translation. + if mStep.kind == abiStepStack { + if vStep.size != mStep.size { + panic("method ABI and value ABI do not align") + } + typedmemmove(t, + add(methodFrame, mStep.stkOff, "precomputed stack offset"), + add(valueFrame, vStep.stkOff, "precomputed stack offset")) + continue + } + // Handle stack -> register translation. + for _, mStep := range methodSteps { + from := add(valueFrame, vStep.stkOff+mStep.offset, "precomputed stack offset") + switch mStep.kind { + case abiStepPointer: + // Do the pointer copy directly so we get a write barrier. + methodRegs.Ptrs[mStep.ireg] = *(*unsafe.Pointer)(from) + fallthrough // We need to make sure this ends up in Ints, too. + case abiStepIntReg: + intToReg(&methodRegs, mStep.ireg, mStep.size, from) + case abiStepFloatReg: + floatToReg(&methodRegs, mStep.freg, mStep.size, from) + default: + panic("unexpected method step") + } + } + continue + } + // Handle register -> stack translation. + if mStep := methodSteps[0]; mStep.kind == abiStepStack { + for _, vStep := range valueSteps { + to := add(methodFrame, mStep.stkOff+vStep.offset, "precomputed stack offset") + switch vStep.kind { + case abiStepPointer: + // Do the pointer copy directly so we get a write barrier. + *(*unsafe.Pointer)(to) = valueRegs.Ptrs[vStep.ireg] + case abiStepIntReg: + intFromReg(valueRegs, vStep.ireg, vStep.size, to) + case abiStepFloatReg: + floatFromReg(valueRegs, vStep.freg, vStep.size, to) + default: + panic("unexpected value step") + } + } + continue + } + // Handle register -> register translation. + if len(valueSteps) != len(methodSteps) { + // Because it's the same type for the value, and it's assigned + // to registers both times, it should always take up the same + // number of registers for each ABI. + panic("method ABI and value ABI don't align") + } + for i, vStep := range valueSteps { + mStep := methodSteps[i] + if mStep.kind != vStep.kind { + panic("method ABI and value ABI don't align") + } + switch vStep.kind { + case abiStepPointer: + // Copy this too, so we get a write barrier. + methodRegs.Ptrs[mStep.ireg] = valueRegs.Ptrs[vStep.ireg] + fallthrough + case abiStepIntReg: + methodRegs.Ints[mStep.ireg] = valueRegs.Ints[vStep.ireg] + case abiStepFloatReg: + methodRegs.Floats[mStep.freg] = valueRegs.Floats[vStep.freg] + default: + panic("unexpected value step") + } + } + } + + methodFrameSize := methodFrameType.Size() + // TODO(mknyszek): Remove this when we no longer have + // caller reserved spill space. + methodFrameSize = align(methodFrameSize, goarch.PtrSize) + methodFrameSize += methodABI.spill + + // Mark pointers in registers for the return path. + methodRegs.ReturnIsPtr = methodABI.outRegPtrs + + // Call. + // Call copies the arguments from scratch to the stack, calls fn, + // and then copies the results back into scratch. + call(methodFrameType, methodFn, methodFrame, uint32(methodFrameType.Size()), uint32(methodABI.retOffset), uint32(methodFrameSize), &methodRegs) + + // Copy return values. + // + // This is somewhat simpler because both ABIs have an identical + // return value ABI (the types are identical). As a result, register + // results can simply be copied over. Stack-allocated values are laid + // out the same, but are at different offsets from the start of the frame + // Ignore any changes to args. + // Avoid constructing out-of-bounds pointers if there are no return values. + // because the arguments may be laid out differently. + if valueRegs != nil { + *valueRegs = methodRegs + } + if retSize := methodFrameType.Size() - methodABI.retOffset; retSize > 0 { + valueRet := add(valueFrame, valueABI.retOffset, "valueFrame's size > retOffset") + methodRet := add(methodFrame, methodABI.retOffset, "methodFrame's size > retOffset") + // This copies to the stack. Write barriers are not needed. + memmove(valueRet, methodRet, retSize) + } + + // Tell the runtime it can now depend on the return values + // being properly initialized. + *retValid = true + + // Clear the scratch space and put it back in the pool. + // This must happen after the statement above, so that the return + // values will always be scanned by someone. + typedmemclr(methodFrameType, methodFrame) + methodFramePool.Put(methodFrame) + + // See the comment in callReflect. + runtime.KeepAlive(ctxt) + + // Keep valueRegs alive because it may hold live pointer results. + // The caller (methodValueCall) has it as a stack object, which is only + // scanned when there is a reference to it. + runtime.KeepAlive(valueRegs) +} + +// funcName returns the name of f, for use in error messages. +func funcName(f func([]Value) []Value) string { + pc := *(*uintptr)(unsafe.Pointer(&f)) + rf := runtime.FuncForPC(pc) + if rf != nil { + return rf.Name() + } + return "closure" +} + +// Cap returns v's capacity. +// It panics if v's Kind is not [Array], [Chan], [Slice] or pointer to [Array]. +func (v Value) Cap() int { + // capNonSlice is split out to keep Cap inlineable for slice kinds. + if v.kind() == Slice { + return (*unsafeheader.Slice)(v.ptr).Cap + } + return v.capNonSlice() +} + +func (v Value) capNonSlice() int { + k := v.kind() + switch k { + case Array: + return v.typ().Len() + case Chan: + return chancap(v.pointer()) + case Ptr: + if v.typ().Elem().Kind() == abi.Array { + return v.typ().Elem().Len() + } + panic("reflect: call of reflect.Value.Cap on ptr to non-array Value") + } + panic(&ValueError{"reflect.Value.Cap", v.kind()}) +} + +// Close closes the channel v. +// It panics if v's Kind is not [Chan] or +// v is a receive-only channel. +func (v Value) Close() { + v.mustBe(Chan) + v.mustBeExported() + tt := (*chanType)(unsafe.Pointer(v.typ())) + if ChanDir(tt.Dir)&SendDir == 0 { + panic("reflect: close of receive-only channel") + } + + chanclose(v.pointer()) +} + +// CanComplex reports whether [Value.Complex] can be used without panicking. +func (v Value) CanComplex() bool { + switch v.kind() { + case Complex64, Complex128: + return true + default: + return false + } +} + +// Complex returns v's underlying value, as a complex128. +// It panics if v's Kind is not [Complex64] or [Complex128] +func (v Value) Complex() complex128 { + k := v.kind() + switch k { + case Complex64: + return complex128(*(*complex64)(v.ptr)) + case Complex128: + return *(*complex128)(v.ptr) + } + panic(&ValueError{"reflect.Value.Complex", v.kind()}) +} + +// Elem returns the value that the interface v contains +// or that the pointer v points to. +// It panics if v's Kind is not [Interface] or [Pointer]. +// It returns the zero Value if v is nil. +func (v Value) Elem() Value { + k := v.kind() + switch k { + case Interface: + var eface any + if v.typ().NumMethod() == 0 { + eface = *(*any)(v.ptr) + } else { + eface = (any)(*(*interface { + M() + })(v.ptr)) + } + x := unpackEface(eface) + if x.flag != 0 { + x.flag |= v.flag.ro() + } + return x + case Pointer: + ptr := v.ptr + if v.flag&flagIndir != 0 { + if v.typ().IfaceIndir() { + // This is a pointer to a not-in-heap object. ptr points to a uintptr + // in the heap. That uintptr is the address of a not-in-heap object. + // In general, pointers to not-in-heap objects can be total junk. + // But Elem() is asking to dereference it, so the user has asserted + // that at least it is a valid pointer (not just an integer stored in + // a pointer slot). So let's check, to make sure that it isn't a pointer + // that the runtime will crash on if it sees it during GC or write barriers. + // Since it is a not-in-heap pointer, all pointers to the heap are + // forbidden! That makes the test pretty easy. + // See issue 48399. + if !verifyNotInHeapPtr(*(*uintptr)(ptr)) { + panic("reflect: reflect.Value.Elem on an invalid notinheap pointer") + } + } + ptr = *(*unsafe.Pointer)(ptr) + } + // The returned value's address is v's value. + if ptr == nil { + return Value{} + } + tt := (*ptrType)(unsafe.Pointer(v.typ())) + typ := tt.Elem + fl := v.flag&flagRO | flagIndir | flagAddr + fl |= flag(typ.Kind()) + return Value{typ, ptr, fl} + } + panic(&ValueError{"reflect.Value.Elem", v.kind()}) +} + +// Field returns the i'th field of the struct v. +// It panics if v's Kind is not [Struct] or i is out of range. +func (v Value) Field(i int) Value { + if v.kind() != Struct { + panic(&ValueError{"reflect.Value.Field", v.kind()}) + } + tt := (*structType)(unsafe.Pointer(v.typ())) + if uint(i) >= uint(len(tt.Fields)) { + panic("reflect: Field index out of range") + } + field := &tt.Fields[i] + typ := field.Typ + + // Inherit permission bits from v, but clear flagEmbedRO. + fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind()) + // Using an unexported field forces flagRO. + if !field.Name.IsExported() { + if field.Embedded() { + fl |= flagEmbedRO + } else { + fl |= flagStickyRO + } + } + // Either flagIndir is set and v.ptr points at struct, + // or flagIndir is not set and v.ptr is the actual struct data. + // In the former case, we want v.ptr + offset. + // In the latter case, we must have field.offset = 0, + // so v.ptr + field.offset is still the correct address. + ptr := add(v.ptr, field.Offset, "same as non-reflect &v.field") + return Value{typ, ptr, fl} +} + +// FieldByIndex returns the nested field corresponding to index. +// It panics if evaluation requires stepping through a nil +// pointer or a field that is not a struct. +func (v Value) FieldByIndex(index []int) Value { + if len(index) == 1 { + return v.Field(index[0]) + } + v.mustBe(Struct) + for i, x := range index { + if i > 0 { + if v.Kind() == Pointer && v.typ().Elem().Kind() == abi.Struct { + if v.IsNil() { + panic("reflect: indirection through nil pointer to embedded struct") + } + v = v.Elem() + } + } + v = v.Field(x) + } + return v +} + +// FieldByIndexErr returns the nested field corresponding to index. +// It returns an error if evaluation requires stepping through a nil +// pointer, but panics if it must step through a field that +// is not a struct. +func (v Value) FieldByIndexErr(index []int) (Value, error) { + if len(index) == 1 { + return v.Field(index[0]), nil + } + v.mustBe(Struct) + for i, x := range index { + if i > 0 { + if v.Kind() == Ptr && v.typ().Elem().Kind() == abi.Struct { + if v.IsNil() { + return Value{}, errors.New("reflect: indirection through nil pointer to embedded struct field " + nameFor(v.typ().Elem())) + } + v = v.Elem() + } + } + v = v.Field(x) + } + return v, nil +} + +// FieldByName returns the struct field with the given name. +// It returns the zero Value if no field was found. +// It panics if v's Kind is not [Struct]. +func (v Value) FieldByName(name string) Value { + v.mustBe(Struct) + if f, ok := toRType(v.typ()).FieldByName(name); ok { + return v.FieldByIndex(f.Index) + } + return Value{} +} + +// FieldByNameFunc returns the struct field with a name +// that satisfies the match function. +// It panics if v's Kind is not [Struct]. +// It returns the zero Value if no field was found. +func (v Value) FieldByNameFunc(match func(string) bool) Value { + if f, ok := toRType(v.typ()).FieldByNameFunc(match); ok { + return v.FieldByIndex(f.Index) + } + return Value{} +} + +// CanFloat reports whether [Value.Float] can be used without panicking. +func (v Value) CanFloat() bool { + switch v.kind() { + case Float32, Float64: + return true + default: + return false + } +} + +// Float returns v's underlying value, as a float64. +// It panics if v's Kind is not [Float32] or [Float64] +func (v Value) Float() float64 { + k := v.kind() + switch k { + case Float32: + return float64(*(*float32)(v.ptr)) + case Float64: + return *(*float64)(v.ptr) + } + panic(&ValueError{"reflect.Value.Float", v.kind()}) +} + +var uint8Type = rtypeOf(uint8(0)) + +// Index returns v's i'th element. +// It panics if v's Kind is not [Array], [Slice], or [String] or i is out of range. +func (v Value) Index(i int) Value { + switch v.kind() { + case Array: + tt := (*arrayType)(unsafe.Pointer(v.typ())) + if uint(i) >= uint(tt.Len) { + panic("reflect: array index out of range") + } + typ := tt.Elem + offset := uintptr(i) * typ.Size() + + // Either flagIndir is set and v.ptr points at array, + // or flagIndir is not set and v.ptr is the actual array data. + // In the former case, we want v.ptr + offset. + // In the latter case, we must be doing Index(0), so offset = 0, + // so v.ptr + offset is still the correct address. + val := add(v.ptr, offset, "same as &v[i], i < tt.len") + fl := v.flag&(flagIndir|flagAddr) | v.flag.ro() | flag(typ.Kind()) // bits same as overall array + return Value{typ, val, fl} + + case Slice: + // Element flag same as Elem of Pointer. + // Addressable, indirect, possibly read-only. + s := (*unsafeheader.Slice)(v.ptr) + if uint(i) >= uint(s.Len) { + panic("reflect: slice index out of range") + } + tt := (*sliceType)(unsafe.Pointer(v.typ())) + typ := tt.Elem + val := arrayAt(s.Data, i, typ.Size(), "i < s.Len") + fl := flagAddr | flagIndir | v.flag.ro() | flag(typ.Kind()) + return Value{typ, val, fl} + + case String: + s := (*unsafeheader.String)(v.ptr) + if uint(i) >= uint(s.Len) { + panic("reflect: string index out of range") + } + p := arrayAt(s.Data, i, 1, "i < s.Len") + fl := v.flag.ro() | flag(Uint8) | flagIndir + return Value{uint8Type, p, fl} + } + panic(&ValueError{"reflect.Value.Index", v.kind()}) +} + +// CanInt reports whether Int can be used without panicking. +func (v Value) CanInt() bool { + switch v.kind() { + case Int, Int8, Int16, Int32, Int64: + return true + default: + return false + } +} + +// Int returns v's underlying value, as an int64. +// It panics if v's Kind is not [Int], [Int8], [Int16], [Int32], or [Int64]. +func (v Value) Int() int64 { + k := v.kind() + p := v.ptr + switch k { + case Int: + return int64(*(*int)(p)) + case Int8: + return int64(*(*int8)(p)) + case Int16: + return int64(*(*int16)(p)) + case Int32: + return int64(*(*int32)(p)) + case Int64: + return *(*int64)(p) + } + panic(&ValueError{"reflect.Value.Int", v.kind()}) +} + +// CanInterface reports whether [Value.Interface] can be used without panicking. +func (v Value) CanInterface() bool { + if v.flag == 0 { + panic(&ValueError{"reflect.Value.CanInterface", Invalid}) + } + return v.flag&flagRO == 0 +} + +// Interface returns v's current value as an interface{}. +// It is equivalent to: +// +// var i interface{} = (v's underlying value) +// +// It panics if the Value was obtained by accessing +// unexported struct fields. +func (v Value) Interface() (i any) { + return valueInterface(v, true) +} + +func valueInterface(v Value, safe bool) any { + if v.flag == 0 { + panic(&ValueError{"reflect.Value.Interface", Invalid}) + } + if safe && v.flag&flagRO != 0 { + // Do not allow access to unexported values via Interface, + // because they might be pointers that should not be + // writable or methods or function that should not be callable. + panic("reflect.Value.Interface: cannot return value obtained from unexported field or method") + } + if v.flag&flagMethod != 0 { + v = makeMethodValue("Interface", v) + } + + if v.kind() == Interface { + // Special case: return the element inside the interface. + // Empty interface has one layout, all interfaces with + // methods have a second layout. + if v.NumMethod() == 0 { + return *(*any)(v.ptr) + } + return *(*interface { + M() + })(v.ptr) + } + + return packEface(v) +} + +// InterfaceData returns a pair of unspecified uintptr values. +// It panics if v's Kind is not Interface. +// +// In earlier versions of Go, this function returned the interface's +// value as a uintptr pair. As of Go 1.4, the implementation of +// interface values precludes any defined use of InterfaceData. +// +// Deprecated: The memory representation of interface values is not +// compatible with InterfaceData. +func (v Value) InterfaceData() [2]uintptr { + v.mustBe(Interface) + // The compiler loses track as it converts to uintptr. Force escape. + escapes(v.ptr) + // We treat this as a read operation, so we allow + // it even for unexported data, because the caller + // has to import "unsafe" to turn it into something + // that can be abused. + // Interface value is always bigger than a word; assume flagIndir. + return *(*[2]uintptr)(v.ptr) +} + +// IsNil reports whether its argument v is nil. The argument must be +// a chan, func, interface, map, pointer, or slice value; if it is +// not, IsNil panics. Note that IsNil is not always equivalent to a +// regular comparison with nil in Go. For example, if v was created +// by calling [ValueOf] with an uninitialized interface variable i, +// i==nil will be true but v.IsNil will panic as v will be the zero +// Value. +func (v Value) IsNil() bool { + k := v.kind() + switch k { + case Chan, Func, Map, Pointer, UnsafePointer: + if v.flag&flagMethod != 0 { + return false + } + ptr := v.ptr + if v.flag&flagIndir != 0 { + ptr = *(*unsafe.Pointer)(ptr) + } + return ptr == nil + case Interface, Slice: + // Both interface and slice are nil if first word is 0. + // Both are always bigger than a word; assume flagIndir. + return *(*unsafe.Pointer)(v.ptr) == nil + } + panic(&ValueError{"reflect.Value.IsNil", v.kind()}) +} + +// IsValid reports whether v represents a value. +// It returns false if v is the zero Value. +// If [Value.IsValid] returns false, all other methods except String panic. +// Most functions and methods never return an invalid Value. +// If one does, its documentation states the conditions explicitly. +func (v Value) IsValid() bool { + return v.flag != 0 +} + +// IsZero reports whether v is the zero value for its type. +// It panics if the argument is invalid. +func (v Value) IsZero() bool { + switch v.kind() { + case Bool: + return !v.Bool() + case Int, Int8, Int16, Int32, Int64: + return v.Int() == 0 + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return v.Uint() == 0 + case Float32, Float64: + return v.Float() == 0 + case Complex64, Complex128: + return v.Complex() == 0 + case Array: + if v.flag&flagIndir == 0 { + return v.ptr == nil + } + typ := (*abi.ArrayType)(unsafe.Pointer(v.typ())) + // If the type is comparable, then compare directly with zero. + if typ.Equal != nil && typ.Size() <= abi.ZeroValSize { + // v.ptr doesn't escape, as Equal functions are compiler generated + // and never escape. The escape analysis doesn't know, as it is a + // function pointer call. + return typ.Equal(abi.NoEscape(v.ptr), unsafe.Pointer(&zeroVal[0])) + } + if typ.TFlag&abi.TFlagRegularMemory != 0 { + // For some types where the zero value is a value where all bits of this type are 0 + // optimize it. + return isZero(unsafe.Slice(((*byte)(v.ptr)), typ.Size())) + } + n := int(typ.Len) + for i := 0; i < n; i++ { + if !v.Index(i).IsZero() { + return false + } + } + return true + case Chan, Func, Interface, Map, Pointer, Slice, UnsafePointer: + return v.IsNil() + case String: + return v.Len() == 0 + case Struct: + if v.flag&flagIndir == 0 { + return v.ptr == nil + } + typ := (*abi.StructType)(unsafe.Pointer(v.typ())) + // If the type is comparable, then compare directly with zero. + if typ.Equal != nil && typ.Size() <= abi.ZeroValSize { + // See noescape justification above. + return typ.Equal(abi.NoEscape(v.ptr), unsafe.Pointer(&zeroVal[0])) + } + if typ.TFlag&abi.TFlagRegularMemory != 0 { + // For some types where the zero value is a value where all bits of this type are 0 + // optimize it. + return isZero(unsafe.Slice(((*byte)(v.ptr)), typ.Size())) + } + + n := v.NumField() + for i := 0; i < n; i++ { + if !v.Field(i).IsZero() && v.Type().Field(i).Name != "_" { + return false + } + } + return true + default: + // This should never happen, but will act as a safeguard for later, + // as a default value doesn't makes sense here. + panic(&ValueError{"reflect.Value.IsZero", v.Kind()}) + } +} + +// isZero For all zeros, performance is not as good as +// return bytealg.Count(b, byte(0)) == len(b) +func isZero(b []byte) bool { + if len(b) == 0 { + return true + } + const n = 32 + // Align memory addresses to 8 bytes. + for uintptr(unsafe.Pointer(&b[0]))%8 != 0 { + if b[0] != 0 { + return false + } + b = b[1:] + if len(b) == 0 { + return true + } + } + for len(b)%8 != 0 { + if b[len(b)-1] != 0 { + return false + } + b = b[:len(b)-1] + } + if len(b) == 0 { + return true + } + w := unsafe.Slice((*uint64)(unsafe.Pointer(&b[0])), len(b)/8) + for len(w)%n != 0 { + if w[0] != 0 { + return false + } + w = w[1:] + } + for len(w) >= n { + if w[0] != 0 || w[1] != 0 || w[2] != 0 || w[3] != 0 || + w[4] != 0 || w[5] != 0 || w[6] != 0 || w[7] != 0 || + w[8] != 0 || w[9] != 0 || w[10] != 0 || w[11] != 0 || + w[12] != 0 || w[13] != 0 || w[14] != 0 || w[15] != 0 || + w[16] != 0 || w[17] != 0 || w[18] != 0 || w[19] != 0 || + w[20] != 0 || w[21] != 0 || w[22] != 0 || w[23] != 0 || + w[24] != 0 || w[25] != 0 || w[26] != 0 || w[27] != 0 || + w[28] != 0 || w[29] != 0 || w[30] != 0 || w[31] != 0 { + return false + } + w = w[n:] + } + return true +} + +// SetZero sets v to be the zero value of v's type. +// It panics if [Value.CanSet] returns false. +func (v Value) SetZero() { + v.mustBeAssignable() + switch v.kind() { + case Bool: + *(*bool)(v.ptr) = false + case Int: + *(*int)(v.ptr) = 0 + case Int8: + *(*int8)(v.ptr) = 0 + case Int16: + *(*int16)(v.ptr) = 0 + case Int32: + *(*int32)(v.ptr) = 0 + case Int64: + *(*int64)(v.ptr) = 0 + case Uint: + *(*uint)(v.ptr) = 0 + case Uint8: + *(*uint8)(v.ptr) = 0 + case Uint16: + *(*uint16)(v.ptr) = 0 + case Uint32: + *(*uint32)(v.ptr) = 0 + case Uint64: + *(*uint64)(v.ptr) = 0 + case Uintptr: + *(*uintptr)(v.ptr) = 0 + case Float32: + *(*float32)(v.ptr) = 0 + case Float64: + *(*float64)(v.ptr) = 0 + case Complex64: + *(*complex64)(v.ptr) = 0 + case Complex128: + *(*complex128)(v.ptr) = 0 + case String: + *(*string)(v.ptr) = "" + case Slice: + *(*unsafeheader.Slice)(v.ptr) = unsafeheader.Slice{} + case Interface: + *(*abi.EmptyInterface)(v.ptr) = abi.EmptyInterface{} + case Chan, Func, Map, Pointer, UnsafePointer: + *(*unsafe.Pointer)(v.ptr) = nil + case Array, Struct: + typedmemclr(v.typ(), v.ptr) + default: + // This should never happen, but will act as a safeguard for later, + // as a default value doesn't makes sense here. + panic(&ValueError{"reflect.Value.SetZero", v.Kind()}) + } +} + +// Kind returns v's Kind. +// If v is the zero Value ([Value.IsValid] returns false), Kind returns Invalid. +func (v Value) Kind() Kind { + return v.kind() +} + +// Len returns v's length. +// It panics if v's Kind is not [Array], [Chan], [Map], [Slice], [String], or pointer to [Array]. +func (v Value) Len() int { + // lenNonSlice is split out to keep Len inlineable for slice kinds. + if v.kind() == Slice { + return (*unsafeheader.Slice)(v.ptr).Len + } + return v.lenNonSlice() +} + +func (v Value) lenNonSlice() int { + switch k := v.kind(); k { + case Array: + tt := (*arrayType)(unsafe.Pointer(v.typ())) + return int(tt.Len) + case Chan: + return chanlen(v.pointer()) + case Map: + return maplen(v.pointer()) + case String: + // String is bigger than a word; assume flagIndir. + return (*unsafeheader.String)(v.ptr).Len + case Ptr: + if v.typ().Elem().Kind() == abi.Array { + return v.typ().Elem().Len() + } + panic("reflect: call of reflect.Value.Len on ptr to non-array Value") + } + panic(&ValueError{"reflect.Value.Len", v.kind()}) +} + +var stringType = rtypeOf("") + +// MapIndex returns the value associated with key in the map v. +// It panics if v's Kind is not [Map]. +// It returns the zero Value if key is not found in the map or if v represents a nil map. +// As in Go, the key's value must be assignable to the map's key type. +func (v Value) MapIndex(key Value) Value { + v.mustBe(Map) + tt := (*mapType)(unsafe.Pointer(v.typ())) + + // Do not require key to be exported, so that DeepEqual + // and other programs can use all the keys returned by + // MapKeys as arguments to MapIndex. If either the map + // or the key is unexported, though, the result will be + // considered unexported. This is consistent with the + // behavior for structs, which allow read but not write + // of unexported fields. + + var e unsafe.Pointer + if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= abi.MapMaxElemBytes { + k := *(*string)(key.ptr) + e = mapaccess_faststr(v.typ(), v.pointer(), k) + } else { + key = key.assignTo("reflect.Value.MapIndex", tt.Key, nil) + var k unsafe.Pointer + if key.flag&flagIndir != 0 { + k = key.ptr + } else { + k = unsafe.Pointer(&key.ptr) + } + e = mapaccess(v.typ(), v.pointer(), k) + } + if e == nil { + return Value{} + } + typ := tt.Elem + fl := (v.flag | key.flag).ro() + fl |= flag(typ.Kind()) + return copyVal(typ, fl, e) +} + +// MapKeys returns a slice containing all the keys present in the map, +// in unspecified order. +// It panics if v's Kind is not [Map]. +// It returns an empty slice if v represents a nil map. +func (v Value) MapKeys() []Value { + v.mustBe(Map) + tt := (*mapType)(unsafe.Pointer(v.typ())) + keyType := tt.Key + + fl := v.flag.ro() | flag(keyType.Kind()) + + m := v.pointer() + mlen := int(0) + if m != nil { + mlen = maplen(m) + } + var it hiter + mapiterinit(v.typ(), m, &it) + a := make([]Value, mlen) + var i int + for i = 0; i < len(a); i++ { + key := mapiterkey(&it) + if key == nil { + // Someone deleted an entry from the map since we + // called maplen above. It's a data race, but nothing + // we can do about it. + break + } + a[i] = copyVal(keyType, fl, key) + mapiternext(&it) + } + return a[:i] +} + +// hiter's structure matches runtime.hiter's structure. +// Having a clone here allows us to embed a map iterator +// inside type MapIter so that MapIters can be re-used +// without doing any allocations. +type hiter struct { + key unsafe.Pointer + elem unsafe.Pointer + t unsafe.Pointer + h unsafe.Pointer + buckets unsafe.Pointer + bptr unsafe.Pointer + overflow *[]unsafe.Pointer + oldoverflow *[]unsafe.Pointer + startBucket uintptr + offset uint8 + wrapped bool + B uint8 + i uint8 + bucket uintptr + checkBucket uintptr +} + +func (h *hiter) initialized() bool { + return h.t != nil +} + +// A MapIter is an iterator for ranging over a map. +// See [Value.MapRange]. +type MapIter struct { + m Value + hiter hiter +} + +// Key returns the key of iter's current map entry. +func (iter *MapIter) Key() Value { + if !iter.hiter.initialized() { + panic("MapIter.Key called before Next") + } + iterkey := mapiterkey(&iter.hiter) + if iterkey == nil { + panic("MapIter.Key called on exhausted iterator") + } + + t := (*mapType)(unsafe.Pointer(iter.m.typ())) + ktype := t.Key + return copyVal(ktype, iter.m.flag.ro()|flag(ktype.Kind()), iterkey) +} + +// SetIterKey assigns to v the key of iter's current map entry. +// It is equivalent to v.Set(iter.Key()), but it avoids allocating a new Value. +// As in Go, the key must be assignable to v's type and +// must not be derived from an unexported field. +func (v Value) SetIterKey(iter *MapIter) { + if !iter.hiter.initialized() { + panic("reflect: Value.SetIterKey called before Next") + } + iterkey := mapiterkey(&iter.hiter) + if iterkey == nil { + panic("reflect: Value.SetIterKey called on exhausted iterator") + } + + v.mustBeAssignable() + var target unsafe.Pointer + if v.kind() == Interface { + target = v.ptr + } + + t := (*mapType)(unsafe.Pointer(iter.m.typ())) + ktype := t.Key + + iter.m.mustBeExported() // do not let unexported m leak + key := Value{ktype, iterkey, iter.m.flag | flag(ktype.Kind()) | flagIndir} + key = key.assignTo("reflect.MapIter.SetKey", v.typ(), target) + typedmemmove(v.typ(), v.ptr, key.ptr) +} + +// Value returns the value of iter's current map entry. +func (iter *MapIter) Value() Value { + if !iter.hiter.initialized() { + panic("MapIter.Value called before Next") + } + iterelem := mapiterelem(&iter.hiter) + if iterelem == nil { + panic("MapIter.Value called on exhausted iterator") + } + + t := (*mapType)(unsafe.Pointer(iter.m.typ())) + vtype := t.Elem + return copyVal(vtype, iter.m.flag.ro()|flag(vtype.Kind()), iterelem) +} + +// SetIterValue assigns to v the value of iter's current map entry. +// It is equivalent to v.Set(iter.Value()), but it avoids allocating a new Value. +// As in Go, the value must be assignable to v's type and +// must not be derived from an unexported field. +func (v Value) SetIterValue(iter *MapIter) { + if !iter.hiter.initialized() { + panic("reflect: Value.SetIterValue called before Next") + } + iterelem := mapiterelem(&iter.hiter) + if iterelem == nil { + panic("reflect: Value.SetIterValue called on exhausted iterator") + } + + v.mustBeAssignable() + var target unsafe.Pointer + if v.kind() == Interface { + target = v.ptr + } + + t := (*mapType)(unsafe.Pointer(iter.m.typ())) + vtype := t.Elem + + iter.m.mustBeExported() // do not let unexported m leak + elem := Value{vtype, iterelem, iter.m.flag | flag(vtype.Kind()) | flagIndir} + elem = elem.assignTo("reflect.MapIter.SetValue", v.typ(), target) + typedmemmove(v.typ(), v.ptr, elem.ptr) +} + +// Next advances the map iterator and reports whether there is another +// entry. It returns false when iter is exhausted; subsequent +// calls to [MapIter.Key], [MapIter.Value], or [MapIter.Next] will panic. +func (iter *MapIter) Next() bool { + if !iter.m.IsValid() { + panic("MapIter.Next called on an iterator that does not have an associated map Value") + } + if !iter.hiter.initialized() { + mapiterinit(iter.m.typ(), iter.m.pointer(), &iter.hiter) + } else { + if mapiterkey(&iter.hiter) == nil { + panic("MapIter.Next called on exhausted iterator") + } + mapiternext(&iter.hiter) + } + return mapiterkey(&iter.hiter) != nil +} + +// Reset modifies iter to iterate over v. +// It panics if v's Kind is not [Map] and v is not the zero Value. +// Reset(Value{}) causes iter to not to refer to any map, +// which may allow the previously iterated-over map to be garbage collected. +func (iter *MapIter) Reset(v Value) { + if v.IsValid() { + v.mustBe(Map) + } + iter.m = v + iter.hiter = hiter{} +} + +// MapRange returns a range iterator for a map. +// It panics if v's Kind is not [Map]. +// +// Call [MapIter.Next] to advance the iterator, and [MapIter.Key]/[MapIter.Value] to access each entry. +// [MapIter.Next] returns false when the iterator is exhausted. +// MapRange follows the same iteration semantics as a range statement. +// +// Example: +// +// iter := reflect.ValueOf(m).MapRange() +// for iter.Next() { +// k := iter.Key() +// v := iter.Value() +// ... +// } +func (v Value) MapRange() *MapIter { + // This is inlinable to take advantage of "function outlining". + // The allocation of MapIter can be stack allocated if the caller + // does not allow it to escape. + // See https://blog.filippo.io/efficient-go-apis-with-the-inliner/ + if v.kind() != Map { + v.panicNotMap() + } + return &MapIter{m: v} +} + +// Force slow panicking path not inlined, so it won't add to the +// inlining budget of the caller. +// TODO: undo when the inliner is no longer bottom-up only. +// +//go:noinline +func (f flag) panicNotMap() { + f.mustBe(Map) +} + +// copyVal returns a Value containing the map key or value at ptr, +// allocating a new variable as needed. +func copyVal(typ *abi.Type, fl flag, ptr unsafe.Pointer) Value { + if typ.IfaceIndir() { + // Copy result so future changes to the map + // won't change the underlying value. + c := unsafe_New(typ) + typedmemmove(typ, c, ptr) + return Value{typ, c, fl | flagIndir} + } + return Value{typ, *(*unsafe.Pointer)(ptr), fl} +} + +// Method returns a function value corresponding to v's i'th method. +// The arguments to a Call on the returned function should not include +// a receiver; the returned function will always use v as the receiver. +// Method panics if i is out of range or if v is a nil interface value. +func (v Value) Method(i int) Value { + if v.typ() == nil { + panic(&ValueError{"reflect.Value.Method", Invalid}) + } + if v.flag&flagMethod != 0 || uint(i) >= uint(toRType(v.typ()).NumMethod()) { + panic("reflect: Method index out of range") + } + if v.typ().Kind() == abi.Interface && v.IsNil() { + panic("reflect: Method on nil interface value") + } + fl := v.flag.ro() | (v.flag & flagIndir) + fl |= flag(Func) + fl |= flag(i)<> (64 - bitSize) + return x != trunc + } + panic(&ValueError{"reflect.Value.OverflowInt", v.kind()}) +} + +// OverflowUint reports whether the uint64 x cannot be represented by v's type. +// It panics if v's Kind is not [Uint], [Uintptr], [Uint8], [Uint16], [Uint32], or [Uint64]. +func (v Value) OverflowUint(x uint64) bool { + k := v.kind() + switch k { + case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64: + bitSize := v.typ_.Size() * 8 // ok to use v.typ_ directly as Size doesn't escape + trunc := (x << (64 - bitSize)) >> (64 - bitSize) + return x != trunc + } + panic(&ValueError{"reflect.Value.OverflowUint", v.kind()}) +} + +//go:nocheckptr +// This prevents inlining Value.Pointer when -d=checkptr is enabled, +// which ensures cmd/compile can recognize unsafe.Pointer(v.Pointer()) +// and make an exception. + +// Pointer returns v's value as a uintptr. +// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], [String], or [UnsafePointer]. +// +// If v's Kind is [Func], the returned pointer is an underlying +// code pointer, but not necessarily enough to identify a +// single function uniquely. The only guarantee is that the +// result is zero if and only if v is a nil func Value. +// +// If v's Kind is [Slice], the returned pointer is to the first +// element of the slice. If the slice is nil the returned value +// is 0. If the slice is empty but non-nil the return value is non-zero. +// +// If v's Kind is [String], the returned pointer is to the first +// element of the underlying bytes of string. +// +// It's preferred to use uintptr(Value.UnsafePointer()) to get the equivalent result. +func (v Value) Pointer() uintptr { + // The compiler loses track as it converts to uintptr. Force escape. + escapes(v.ptr) + + k := v.kind() + switch k { + case Pointer: + if !v.typ().Pointers() { + val := *(*uintptr)(v.ptr) + // Since it is a not-in-heap pointer, all pointers to the heap are + // forbidden! See comment in Value.Elem and issue #48399. + if !verifyNotInHeapPtr(val) { + panic("reflect: reflect.Value.Pointer on an invalid notinheap pointer") + } + return val + } + fallthrough + case Chan, Map, UnsafePointer: + return uintptr(v.pointer()) + case Func: + if v.flag&flagMethod != 0 { + // As the doc comment says, the returned pointer is an + // underlying code pointer but not necessarily enough to + // identify a single function uniquely. All method expressions + // created via reflect have the same underlying code pointer, + // so their Pointers are equal. The function used here must + // match the one used in makeMethodValue. + return methodValueCallCodePtr() + } + p := v.pointer() + // Non-nil func value points at data block. + // First word of data block is actual code. + if p != nil { + p = *(*unsafe.Pointer)(p) + } + return uintptr(p) + case Slice: + return uintptr((*unsafeheader.Slice)(v.ptr).Data) + case String: + return uintptr((*unsafeheader.String)(v.ptr).Data) + } + panic(&ValueError{"reflect.Value.Pointer", v.kind()}) +} + +// Recv receives and returns a value from the channel v. +// It panics if v's Kind is not [Chan]. +// The receive blocks until a value is ready. +// The boolean value ok is true if the value x corresponds to a send +// on the channel, false if it is a zero value received because the channel is closed. +func (v Value) Recv() (x Value, ok bool) { + v.mustBe(Chan) + v.mustBeExported() + return v.recv(false) +} + +// internal recv, possibly non-blocking (nb). +// v is known to be a channel. +func (v Value) recv(nb bool) (val Value, ok bool) { + tt := (*chanType)(unsafe.Pointer(v.typ())) + if ChanDir(tt.Dir)&RecvDir == 0 { + panic("reflect: recv on send-only channel") + } + t := tt.Elem + val = Value{t, nil, flag(t.Kind())} + var p unsafe.Pointer + if t.IfaceIndir() { + p = unsafe_New(t) + val.ptr = p + val.flag |= flagIndir + } else { + p = unsafe.Pointer(&val.ptr) + } + selected, ok := chanrecv(v.pointer(), nb, p) + if !selected { + val = Value{} + } + return +} + +// Send sends x on the channel v. +// It panics if v's kind is not [Chan] or if x's type is not the same type as v's element type. +// As in Go, x's value must be assignable to the channel's element type. +func (v Value) Send(x Value) { + v.mustBe(Chan) + v.mustBeExported() + v.send(x, false) +} + +// internal send, possibly non-blocking. +// v is known to be a channel. +func (v Value) send(x Value, nb bool) (selected bool) { + tt := (*chanType)(unsafe.Pointer(v.typ())) + if ChanDir(tt.Dir)&SendDir == 0 { + panic("reflect: send on recv-only channel") + } + x.mustBeExported() + x = x.assignTo("reflect.Value.Send", tt.Elem, nil) + var p unsafe.Pointer + if x.flag&flagIndir != 0 { + p = x.ptr + } else { + p = unsafe.Pointer(&x.ptr) + } + return chansend(v.pointer(), p, nb) +} + +// Set assigns x to the value v. +// It panics if [Value.CanSet] returns false. +// As in Go, x's value must be assignable to v's type and +// must not be derived from an unexported field. +func (v Value) Set(x Value) { + v.mustBeAssignable() + x.mustBeExported() // do not let unexported x leak + var target unsafe.Pointer + if v.kind() == Interface { + target = v.ptr + } + x = x.assignTo("reflect.Set", v.typ(), target) + if x.flag&flagIndir != 0 { + if x.ptr == unsafe.Pointer(&zeroVal[0]) { + typedmemclr(v.typ(), v.ptr) + } else { + typedmemmove(v.typ(), v.ptr, x.ptr) + } + } else { + *(*unsafe.Pointer)(v.ptr) = x.ptr + } +} + +// SetBool sets v's underlying value. +// It panics if v's Kind is not [Bool] or if [Value.CanSet] returns false. +func (v Value) SetBool(x bool) { + v.mustBeAssignable() + v.mustBe(Bool) + *(*bool)(v.ptr) = x +} + +// SetBytes sets v's underlying value. +// It panics if v's underlying value is not a slice of bytes. +func (v Value) SetBytes(x []byte) { + v.mustBeAssignable() + v.mustBe(Slice) + if toRType(v.typ()).Elem().Kind() != Uint8 { // TODO add Elem method, fix mustBe(Slice) to return slice. + panic("reflect.Value.SetBytes of non-byte slice") + } + *(*[]byte)(v.ptr) = x +} + +// setRunes sets v's underlying value. +// It panics if v's underlying value is not a slice of runes (int32s). +func (v Value) setRunes(x []rune) { + v.mustBeAssignable() + v.mustBe(Slice) + if v.typ().Elem().Kind() != abi.Int32 { + panic("reflect.Value.setRunes of non-rune slice") + } + *(*[]rune)(v.ptr) = x +} + +// SetComplex sets v's underlying value to x. +// It panics if v's Kind is not [Complex64] or [Complex128], or if [Value.CanSet] returns false. +func (v Value) SetComplex(x complex128) { + v.mustBeAssignable() + switch k := v.kind(); k { + default: + panic(&ValueError{"reflect.Value.SetComplex", v.kind()}) + case Complex64: + *(*complex64)(v.ptr) = complex64(x) + case Complex128: + *(*complex128)(v.ptr) = x + } +} + +// SetFloat sets v's underlying value to x. +// It panics if v's Kind is not [Float32] or [Float64], or if [Value.CanSet] returns false. +func (v Value) SetFloat(x float64) { + v.mustBeAssignable() + switch k := v.kind(); k { + default: + panic(&ValueError{"reflect.Value.SetFloat", v.kind()}) + case Float32: + *(*float32)(v.ptr) = float32(x) + case Float64: + *(*float64)(v.ptr) = x + } +} + +// SetInt sets v's underlying value to x. +// It panics if v's Kind is not [Int], [Int8], [Int16], [Int32], or [Int64], or if [Value.CanSet] returns false. +func (v Value) SetInt(x int64) { + v.mustBeAssignable() + switch k := v.kind(); k { + default: + panic(&ValueError{"reflect.Value.SetInt", v.kind()}) + case Int: + *(*int)(v.ptr) = int(x) + case Int8: + *(*int8)(v.ptr) = int8(x) + case Int16: + *(*int16)(v.ptr) = int16(x) + case Int32: + *(*int32)(v.ptr) = int32(x) + case Int64: + *(*int64)(v.ptr) = x + } +} + +// SetLen sets v's length to n. +// It panics if v's Kind is not [Slice] or if n is negative or +// greater than the capacity of the slice. +func (v Value) SetLen(n int) { + v.mustBeAssignable() + v.mustBe(Slice) + s := (*unsafeheader.Slice)(v.ptr) + if uint(n) > uint(s.Cap) { + panic("reflect: slice length out of range in SetLen") + } + s.Len = n +} + +// SetCap sets v's capacity to n. +// It panics if v's Kind is not [Slice] or if n is smaller than the length or +// greater than the capacity of the slice. +func (v Value) SetCap(n int) { + v.mustBeAssignable() + v.mustBe(Slice) + s := (*unsafeheader.Slice)(v.ptr) + if n < s.Len || n > s.Cap { + panic("reflect: slice capacity out of range in SetCap") + } + s.Cap = n +} + +// SetMapIndex sets the element associated with key in the map v to elem. +// It panics if v's Kind is not [Map]. +// If elem is the zero Value, SetMapIndex deletes the key from the map. +// Otherwise if v holds a nil map, SetMapIndex will panic. +// As in Go, key's elem must be assignable to the map's key type, +// and elem's value must be assignable to the map's elem type. +func (v Value) SetMapIndex(key, elem Value) { + v.mustBe(Map) + v.mustBeExported() + key.mustBeExported() + tt := (*mapType)(unsafe.Pointer(v.typ())) + + if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= abi.MapMaxElemBytes { + k := *(*string)(key.ptr) + if elem.typ() == nil { + mapdelete_faststr(v.typ(), v.pointer(), k) + return + } + elem.mustBeExported() + elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil) + var e unsafe.Pointer + if elem.flag&flagIndir != 0 { + e = elem.ptr + } else { + e = unsafe.Pointer(&elem.ptr) + } + mapassign_faststr(v.typ(), v.pointer(), k, e) + return + } + + key = key.assignTo("reflect.Value.SetMapIndex", tt.Key, nil) + var k unsafe.Pointer + if key.flag&flagIndir != 0 { + k = key.ptr + } else { + k = unsafe.Pointer(&key.ptr) + } + if elem.typ() == nil { + mapdelete(v.typ(), v.pointer(), k) + return + } + elem.mustBeExported() + elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil) + var e unsafe.Pointer + if elem.flag&flagIndir != 0 { + e = elem.ptr + } else { + e = unsafe.Pointer(&elem.ptr) + } + mapassign(v.typ(), v.pointer(), k, e) +} + +// SetUint sets v's underlying value to x. +// It panics if v's Kind is not [Uint], [Uintptr], [Uint8], [Uint16], [Uint32], or [Uint64], or if [Value.CanSet] returns false. +func (v Value) SetUint(x uint64) { + v.mustBeAssignable() + switch k := v.kind(); k { + default: + panic(&ValueError{"reflect.Value.SetUint", v.kind()}) + case Uint: + *(*uint)(v.ptr) = uint(x) + case Uint8: + *(*uint8)(v.ptr) = uint8(x) + case Uint16: + *(*uint16)(v.ptr) = uint16(x) + case Uint32: + *(*uint32)(v.ptr) = uint32(x) + case Uint64: + *(*uint64)(v.ptr) = x + case Uintptr: + *(*uintptr)(v.ptr) = uintptr(x) + } +} + +// SetPointer sets the [unsafe.Pointer] value v to x. +// It panics if v's Kind is not [UnsafePointer]. +func (v Value) SetPointer(x unsafe.Pointer) { + v.mustBeAssignable() + v.mustBe(UnsafePointer) + *(*unsafe.Pointer)(v.ptr) = x +} + +// SetString sets v's underlying value to x. +// It panics if v's Kind is not [String] or if [Value.CanSet] returns false. +func (v Value) SetString(x string) { + v.mustBeAssignable() + v.mustBe(String) + *(*string)(v.ptr) = x +} + +// Slice returns v[i:j]. +// It panics if v's Kind is not [Array], [Slice] or [String], or if v is an unaddressable array, +// or if the indexes are out of bounds. +func (v Value) Slice(i, j int) Value { + var ( + cap int + typ *sliceType + base unsafe.Pointer + ) + switch kind := v.kind(); kind { + default: + panic(&ValueError{"reflect.Value.Slice", v.kind()}) + + case Array: + if v.flag&flagAddr == 0 { + panic("reflect.Value.Slice: slice of unaddressable array") + } + tt := (*arrayType)(unsafe.Pointer(v.typ())) + cap = int(tt.Len) + typ = (*sliceType)(unsafe.Pointer(tt.Slice)) + base = v.ptr + + case Slice: + typ = (*sliceType)(unsafe.Pointer(v.typ())) + s := (*unsafeheader.Slice)(v.ptr) + base = s.Data + cap = s.Cap + + case String: + s := (*unsafeheader.String)(v.ptr) + if i < 0 || j < i || j > s.Len { + panic("reflect.Value.Slice: string slice index out of bounds") + } + var t unsafeheader.String + if i < s.Len { + t = unsafeheader.String{Data: arrayAt(s.Data, i, 1, "i < s.Len"), Len: j - i} + } + return Value{v.typ(), unsafe.Pointer(&t), v.flag} + } + + if i < 0 || j < i || j > cap { + panic("reflect.Value.Slice: slice index out of bounds") + } + + // Declare slice so that gc can see the base pointer in it. + var x []unsafe.Pointer + + // Reinterpret as *unsafeheader.Slice to edit. + s := (*unsafeheader.Slice)(unsafe.Pointer(&x)) + s.Len = j - i + s.Cap = cap - i + if cap-i > 0 { + s.Data = arrayAt(base, i, typ.Elem.Size(), "i < cap") + } else { + // do not advance pointer, to avoid pointing beyond end of slice + s.Data = base + } + + fl := v.flag.ro() | flagIndir | flag(Slice) + return Value{typ.Common(), unsafe.Pointer(&x), fl} +} + +// Slice3 is the 3-index form of the slice operation: it returns v[i:j:k]. +// It panics if v's Kind is not [Array] or [Slice], or if v is an unaddressable array, +// or if the indexes are out of bounds. +func (v Value) Slice3(i, j, k int) Value { + var ( + cap int + typ *sliceType + base unsafe.Pointer + ) + switch kind := v.kind(); kind { + default: + panic(&ValueError{"reflect.Value.Slice3", v.kind()}) + + case Array: + if v.flag&flagAddr == 0 { + panic("reflect.Value.Slice3: slice of unaddressable array") + } + tt := (*arrayType)(unsafe.Pointer(v.typ())) + cap = int(tt.Len) + typ = (*sliceType)(unsafe.Pointer(tt.Slice)) + base = v.ptr + + case Slice: + typ = (*sliceType)(unsafe.Pointer(v.typ())) + s := (*unsafeheader.Slice)(v.ptr) + base = s.Data + cap = s.Cap + } + + if i < 0 || j < i || k < j || k > cap { + panic("reflect.Value.Slice3: slice index out of bounds") + } + + // Declare slice so that the garbage collector + // can see the base pointer in it. + var x []unsafe.Pointer + + // Reinterpret as *unsafeheader.Slice to edit. + s := (*unsafeheader.Slice)(unsafe.Pointer(&x)) + s.Len = j - i + s.Cap = k - i + if k-i > 0 { + s.Data = arrayAt(base, i, typ.Elem.Size(), "i < k <= cap") + } else { + // do not advance pointer, to avoid pointing beyond end of slice + s.Data = base + } + + fl := v.flag.ro() | flagIndir | flag(Slice) + return Value{typ.Common(), unsafe.Pointer(&x), fl} +} + +// String returns the string v's underlying value, as a string. +// String is a special case because of Go's String method convention. +// Unlike the other getters, it does not panic if v's Kind is not [String]. +// Instead, it returns a string of the form "" where T is v's type. +// The fmt package treats Values specially. It does not call their String +// method implicitly but instead prints the concrete values they hold. +func (v Value) String() string { + // stringNonString is split out to keep String inlineable for string kinds. + if v.kind() == String { + return *(*string)(v.ptr) + } + return v.stringNonString() +} + +func (v Value) stringNonString() string { + if v.kind() == Invalid { + return "" + } + // If you call String on a reflect.Value of other type, it's better to + // print something than to panic. Useful in debugging. + return "<" + v.Type().String() + " Value>" +} + +// TryRecv attempts to receive a value from the channel v but will not block. +// It panics if v's Kind is not [Chan]. +// If the receive delivers a value, x is the transferred value and ok is true. +// If the receive cannot finish without blocking, x is the zero Value and ok is false. +// If the channel is closed, x is the zero value for the channel's element type and ok is false. +func (v Value) TryRecv() (x Value, ok bool) { + v.mustBe(Chan) + v.mustBeExported() + return v.recv(true) +} + +// TrySend attempts to send x on the channel v but will not block. +// It panics if v's Kind is not [Chan]. +// It reports whether the value was sent. +// As in Go, x's value must be assignable to the channel's element type. +func (v Value) TrySend(x Value) bool { + v.mustBe(Chan) + v.mustBeExported() + return v.send(x, true) +} + +// Type returns v's type. +func (v Value) Type() Type { + if v.flag != 0 && v.flag&flagMethod == 0 { + return (*rtype)(noescape(unsafe.Pointer(v.typ_))) // inline of toRType(v.typ()), for own inlining in inline test + } + return v.typeSlow() +} + +//go:noinline +func (v Value) typeSlow() Type { + return toRType(v.abiTypeSlow()) +} + +func (v Value) abiType() *abi.Type { + if v.flag != 0 && v.flag&flagMethod == 0 { + return v.typ() + } + return v.abiTypeSlow() +} + +func (v Value) abiTypeSlow() *abi.Type { + if v.flag == 0 { + panic(&ValueError{"reflect.Value.Type", Invalid}) + } + + typ := v.typ() + if v.flag&flagMethod == 0 { + return v.typ() + } + + // Method value. + // v.typ describes the receiver, not the method type. + i := int(v.flag) >> flagMethodShift + if v.typ().Kind() == abi.Interface { + // Method on interface. + tt := (*interfaceType)(unsafe.Pointer(typ)) + if uint(i) >= uint(len(tt.Methods)) { + panic("reflect: internal error: invalid method index") + } + m := &tt.Methods[i] + return typeOffFor(typ, m.Typ) + } + // Method on concrete type. + ms := typ.ExportedMethods() + if uint(i) >= uint(len(ms)) { + panic("reflect: internal error: invalid method index") + } + m := ms[i] + return typeOffFor(typ, m.Mtyp) +} + +// CanUint reports whether [Value.Uint] can be used without panicking. +func (v Value) CanUint() bool { + switch v.kind() { + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return true + default: + return false + } +} + +// Uint returns v's underlying value, as a uint64. +// It panics if v's Kind is not [Uint], [Uintptr], [Uint8], [Uint16], [Uint32], or [Uint64]. +func (v Value) Uint() uint64 { + k := v.kind() + p := v.ptr + switch k { + case Uint: + return uint64(*(*uint)(p)) + case Uint8: + return uint64(*(*uint8)(p)) + case Uint16: + return uint64(*(*uint16)(p)) + case Uint32: + return uint64(*(*uint32)(p)) + case Uint64: + return *(*uint64)(p) + case Uintptr: + return uint64(*(*uintptr)(p)) + } + panic(&ValueError{"reflect.Value.Uint", v.kind()}) +} + +//go:nocheckptr +// This prevents inlining Value.UnsafeAddr when -d=checkptr is enabled, +// which ensures cmd/compile can recognize unsafe.Pointer(v.UnsafeAddr()) +// and make an exception. + +// UnsafeAddr returns a pointer to v's data, as a uintptr. +// It panics if v is not addressable. +// +// It's preferred to use uintptr(Value.Addr().UnsafePointer()) to get the equivalent result. +func (v Value) UnsafeAddr() uintptr { + if v.typ() == nil { + panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid}) + } + if v.flag&flagAddr == 0 { + panic("reflect.Value.UnsafeAddr of unaddressable value") + } + // The compiler loses track as it converts to uintptr. Force escape. + escapes(v.ptr) + return uintptr(v.ptr) +} + +// UnsafePointer returns v's value as a [unsafe.Pointer]. +// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], [String] or [UnsafePointer]. +// +// If v's Kind is [Func], the returned pointer is an underlying +// code pointer, but not necessarily enough to identify a +// single function uniquely. The only guarantee is that the +// result is zero if and only if v is a nil func Value. +// +// If v's Kind is [Slice], the returned pointer is to the first +// element of the slice. If the slice is nil the returned value +// is nil. If the slice is empty but non-nil the return value is non-nil. +// +// If v's Kind is [String], the returned pointer is to the first +// element of the underlying bytes of string. +func (v Value) UnsafePointer() unsafe.Pointer { + k := v.kind() + switch k { + case Pointer: + if !v.typ().Pointers() { + // Since it is a not-in-heap pointer, all pointers to the heap are + // forbidden! See comment in Value.Elem and issue #48399. + if !verifyNotInHeapPtr(*(*uintptr)(v.ptr)) { + panic("reflect: reflect.Value.UnsafePointer on an invalid notinheap pointer") + } + return *(*unsafe.Pointer)(v.ptr) + } + fallthrough + case Chan, Map, UnsafePointer: + return v.pointer() + case Func: + if v.flag&flagMethod != 0 { + // As the doc comment says, the returned pointer is an + // underlying code pointer but not necessarily enough to + // identify a single function uniquely. All method expressions + // created via reflect have the same underlying code pointer, + // so their Pointers are equal. The function used here must + // match the one used in makeMethodValue. + code := methodValueCallCodePtr() + return *(*unsafe.Pointer)(unsafe.Pointer(&code)) + } + p := v.pointer() + // Non-nil func value points at data block. + // First word of data block is actual code. + if p != nil { + p = *(*unsafe.Pointer)(p) + } + return p + case Slice: + return (*unsafeheader.Slice)(v.ptr).Data + case String: + return (*unsafeheader.String)(v.ptr).Data + } + panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()}) +} + +// StringHeader is the runtime representation of a string. +// It cannot be used safely or portably and its representation may +// change in a later release. +// Moreover, the Data field is not sufficient to guarantee the data +// it references will not be garbage collected, so programs must keep +// a separate, correctly typed pointer to the underlying data. +// +// Deprecated: Use unsafe.String or unsafe.StringData instead. +type StringHeader struct { + Data uintptr + Len int +} + +// SliceHeader is the runtime representation of a slice. +// It cannot be used safely or portably and its representation may +// change in a later release. +// Moreover, the Data field is not sufficient to guarantee the data +// it references will not be garbage collected, so programs must keep +// a separate, correctly typed pointer to the underlying data. +// +// Deprecated: Use unsafe.Slice or unsafe.SliceData instead. +type SliceHeader struct { + Data uintptr + Len int + Cap int +} + +func typesMustMatch(what string, t1, t2 Type) { + if t1 != t2 { + panic(what + ": " + t1.String() + " != " + t2.String()) + } +} + +// arrayAt returns the i-th element of p, +// an array whose elements are eltSize bytes wide. +// The array pointed at by p must have at least i+1 elements: +// it is invalid (but impossible to check here) to pass i >= len, +// because then the result will point outside the array. +// whySafe must explain why i < len. (Passing "i < len" is fine; +// the benefit is to surface this assumption at the call site.) +func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer { + return add(p, uintptr(i)*eltSize, "i < len") +} + +// Grow increases the slice's capacity, if necessary, to guarantee space for +// another n elements. After Grow(n), at least n elements can be appended +// to the slice without another allocation. +// +// It panics if v's Kind is not a [Slice] or if n is negative or too large to +// allocate the memory. +func (v Value) Grow(n int) { + v.mustBeAssignable() + v.mustBe(Slice) + v.grow(n) +} + +// grow is identical to Grow but does not check for assignability. +func (v Value) grow(n int) { + p := (*unsafeheader.Slice)(v.ptr) + switch { + case n < 0: + panic("reflect.Value.Grow: negative len") + case p.Len+n < 0: + panic("reflect.Value.Grow: slice overflow") + case p.Len+n > p.Cap: + t := v.typ().Elem() + *p = growslice(t, *p, n) + } +} + +// extendSlice extends a slice by n elements. +// +// Unlike Value.grow, which modifies the slice in place and +// does not change the length of the slice in place, +// extendSlice returns a new slice value with the length +// incremented by the number of specified elements. +func (v Value) extendSlice(n int) Value { + v.mustBeExported() + v.mustBe(Slice) + + // Shallow copy the slice header to avoid mutating the source slice. + sh := *(*unsafeheader.Slice)(v.ptr) + s := &sh + v.ptr = unsafe.Pointer(s) + v.flag = flagIndir | flag(Slice) // equivalent flag to MakeSlice + + v.grow(n) // fine to treat as assignable since we allocate a new slice header + s.Len += n + return v +} + +// Clear clears the contents of a map or zeros the contents of a slice. +// +// It panics if v's Kind is not [Map] or [Slice]. +func (v Value) Clear() { + switch v.Kind() { + case Slice: + sh := *(*unsafeheader.Slice)(v.ptr) + st := (*sliceType)(unsafe.Pointer(v.typ())) + typedarrayclear(st.Elem, sh.Data, sh.Len) + case Map: + mapclear(v.typ(), v.pointer()) + default: + panic(&ValueError{"reflect.Value.Clear", v.Kind()}) + } +} + +// Append appends the values x to a slice s and returns the resulting slice. +// As in Go, each x's value must be assignable to the slice's element type. +func Append(s Value, x ...Value) Value { + s.mustBe(Slice) + n := s.Len() + s = s.extendSlice(len(x)) + for i, v := range x { + s.Index(n + i).Set(v) + } + return s +} + +// AppendSlice appends a slice t to a slice s and returns the resulting slice. +// The slices s and t must have the same element type. +func AppendSlice(s, t Value) Value { + s.mustBe(Slice) + t.mustBe(Slice) + typesMustMatch("reflect.AppendSlice", s.Type().Elem(), t.Type().Elem()) + ns := s.Len() + nt := t.Len() + s = s.extendSlice(nt) + Copy(s.Slice(ns, ns+nt), t) + return s +} + +// Copy copies the contents of src into dst until either +// dst has been filled or src has been exhausted. +// It returns the number of elements copied. +// Dst and src each must have kind [Slice] or [Array], and +// dst and src must have the same element type. +// +// As a special case, src can have kind [String] if the element type of dst is kind [Uint8]. +func Copy(dst, src Value) int { + dk := dst.kind() + if dk != Array && dk != Slice { + panic(&ValueError{"reflect.Copy", dk}) + } + if dk == Array { + dst.mustBeAssignable() + } + dst.mustBeExported() + + sk := src.kind() + var stringCopy bool + if sk != Array && sk != Slice { + stringCopy = sk == String && dst.typ().Elem().Kind() == abi.Uint8 + if !stringCopy { + panic(&ValueError{"reflect.Copy", sk}) + } + } + src.mustBeExported() + + de := dst.typ().Elem() + if !stringCopy { + se := src.typ().Elem() + typesMustMatch("reflect.Copy", toType(de), toType(se)) + } + + var ds, ss unsafeheader.Slice + if dk == Array { + ds.Data = dst.ptr + ds.Len = dst.Len() + ds.Cap = ds.Len + } else { + ds = *(*unsafeheader.Slice)(dst.ptr) + } + if sk == Array { + ss.Data = src.ptr + ss.Len = src.Len() + ss.Cap = ss.Len + } else if sk == Slice { + ss = *(*unsafeheader.Slice)(src.ptr) + } else { + sh := *(*unsafeheader.String)(src.ptr) + ss.Data = sh.Data + ss.Len = sh.Len + ss.Cap = sh.Len + } + + return typedslicecopy(de.Common(), ds, ss) +} + +// A runtimeSelect is a single case passed to rselect. +// This must match ../runtime/select.go:/runtimeSelect +type runtimeSelect struct { + dir SelectDir // SelectSend, SelectRecv or SelectDefault + typ *rtype // channel type + ch unsafe.Pointer // channel + val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir) +} + +// rselect runs a select. It returns the index of the chosen case. +// If the case was a receive, val is filled in with the received value. +// The conventional OK bool indicates whether the receive corresponds +// to a sent value. +// +// rselect generally doesn't escape the runtimeSelect slice, except +// that for the send case the value to send needs to escape. We don't +// have a way to represent that in the function signature. So we handle +// that with a forced escape in function Select. +// +//go:noescape +func rselect([]runtimeSelect) (chosen int, recvOK bool) + +// A SelectDir describes the communication direction of a select case. +type SelectDir int + +// NOTE: These values must match ../runtime/select.go:/selectDir. + +const ( + _ SelectDir = iota + SelectSend // case Chan <- Send + SelectRecv // case <-Chan: + SelectDefault // default +) + +// A SelectCase describes a single case in a select operation. +// The kind of case depends on Dir, the communication direction. +// +// If Dir is SelectDefault, the case represents a default case. +// Chan and Send must be zero Values. +// +// If Dir is SelectSend, the case represents a send operation. +// Normally Chan's underlying value must be a channel, and Send's underlying value must be +// assignable to the channel's element type. As a special case, if Chan is a zero Value, +// then the case is ignored, and the field Send will also be ignored and may be either zero +// or non-zero. +// +// If Dir is [SelectRecv], the case represents a receive operation. +// Normally Chan's underlying value must be a channel and Send must be a zero Value. +// If Chan is a zero Value, then the case is ignored, but Send must still be a zero Value. +// When a receive operation is selected, the received Value is returned by Select. +type SelectCase struct { + Dir SelectDir // direction of case + Chan Value // channel to use (for send or receive) + Send Value // value to send (for send) +} + +// Select executes a select operation described by the list of cases. +// Like the Go select statement, it blocks until at least one of the cases +// can proceed, makes a uniform pseudo-random choice, +// and then executes that case. It returns the index of the chosen case +// and, if that case was a receive operation, the value received and a +// boolean indicating whether the value corresponds to a send on the channel +// (as opposed to a zero value received because the channel is closed). +// Select supports a maximum of 65536 cases. +func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { + if len(cases) > 65536 { + panic("reflect.Select: too many cases (max 65536)") + } + // NOTE: Do not trust that caller is not modifying cases data underfoot. + // The range is safe because the caller cannot modify our copy of the len + // and each iteration makes its own copy of the value c. + var runcases []runtimeSelect + if len(cases) > 4 { + // Slice is heap allocated due to runtime dependent capacity. + runcases = make([]runtimeSelect, len(cases)) + } else { + // Slice can be stack allocated due to constant capacity. + runcases = make([]runtimeSelect, len(cases), 4) + } + + haveDefault := false + for i, c := range cases { + rc := &runcases[i] + rc.dir = c.Dir + switch c.Dir { + default: + panic("reflect.Select: invalid Dir") + + case SelectDefault: // default + if haveDefault { + panic("reflect.Select: multiple default cases") + } + haveDefault = true + if c.Chan.IsValid() { + panic("reflect.Select: default case has Chan value") + } + if c.Send.IsValid() { + panic("reflect.Select: default case has Send value") + } + + case SelectSend: + ch := c.Chan + if !ch.IsValid() { + break + } + ch.mustBe(Chan) + ch.mustBeExported() + tt := (*chanType)(unsafe.Pointer(ch.typ())) + if ChanDir(tt.Dir)&SendDir == 0 { + panic("reflect.Select: SendDir case using recv-only channel") + } + rc.ch = ch.pointer() + rc.typ = toRType(&tt.Type) + v := c.Send + if !v.IsValid() { + panic("reflect.Select: SendDir case missing Send value") + } + v.mustBeExported() + v = v.assignTo("reflect.Select", tt.Elem, nil) + if v.flag&flagIndir != 0 { + rc.val = v.ptr + } else { + rc.val = unsafe.Pointer(&v.ptr) + } + // The value to send needs to escape. See the comment at rselect for + // why we need forced escape. + escapes(rc.val) + + case SelectRecv: + if c.Send.IsValid() { + panic("reflect.Select: RecvDir case has Send value") + } + ch := c.Chan + if !ch.IsValid() { + break + } + ch.mustBe(Chan) + ch.mustBeExported() + tt := (*chanType)(unsafe.Pointer(ch.typ())) + if ChanDir(tt.Dir)&RecvDir == 0 { + panic("reflect.Select: RecvDir case using send-only channel") + } + rc.ch = ch.pointer() + rc.typ = toRType(&tt.Type) + rc.val = unsafe_New(tt.Elem) + } + } + + chosen, recvOK = rselect(runcases) + if runcases[chosen].dir == SelectRecv { + tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ)) + t := tt.Elem + p := runcases[chosen].val + fl := flag(t.Kind()) + if t.IfaceIndir() { + recv = Value{t, p, fl | flagIndir} + } else { + recv = Value{t, *(*unsafe.Pointer)(p), fl} + } + } + return chosen, recv, recvOK +} + +/* + * constructors + */ + +// implemented in package runtime + +//go:noescape +func unsafe_New(*abi.Type) unsafe.Pointer + +//go:noescape +func unsafe_NewArray(*abi.Type, int) unsafe.Pointer + +// MakeSlice creates a new zero-initialized slice value +// for the specified slice type, length, and capacity. +func MakeSlice(typ Type, len, cap int) Value { + if typ.Kind() != Slice { + panic("reflect.MakeSlice of non-slice type") + } + if len < 0 { + panic("reflect.MakeSlice: negative len") + } + if cap < 0 { + panic("reflect.MakeSlice: negative cap") + } + if len > cap { + panic("reflect.MakeSlice: len > cap") + } + + s := unsafeheader.Slice{Data: unsafe_NewArray(&(typ.Elem().(*rtype).t), cap), Len: len, Cap: cap} + return Value{&typ.(*rtype).t, unsafe.Pointer(&s), flagIndir | flag(Slice)} +} + +// SliceAt returns a [Value] representing a slice whose underlying +// data starts at p, with length and capacity equal to n. +// +// This is like [unsafe.Slice]. +func SliceAt(typ Type, p unsafe.Pointer, n int) Value { + unsafeslice(typ.common(), p, n) + s := unsafeheader.Slice{Data: p, Len: n, Cap: n} + return Value{SliceOf(typ).common(), unsafe.Pointer(&s), flagIndir | flag(Slice)} +} + +// MakeChan creates a new channel with the specified type and buffer size. +func MakeChan(typ Type, buffer int) Value { + if typ.Kind() != Chan { + panic("reflect.MakeChan of non-chan type") + } + if buffer < 0 { + panic("reflect.MakeChan: negative buffer size") + } + if typ.ChanDir() != BothDir { + panic("reflect.MakeChan: unidirectional channel type") + } + t := typ.common() + ch := makechan(t, buffer) + return Value{t, ch, flag(Chan)} +} + +// MakeMap creates a new map with the specified type. +func MakeMap(typ Type) Value { + return MakeMapWithSize(typ, 0) +} + +// MakeMapWithSize creates a new map with the specified type +// and initial space for approximately n elements. +func MakeMapWithSize(typ Type, n int) Value { + if typ.Kind() != Map { + panic("reflect.MakeMapWithSize of non-map type") + } + t := typ.common() + m := makemap(t, n) + return Value{t, m, flag(Map)} +} + +// Indirect returns the value that v points to. +// If v is a nil pointer, Indirect returns a zero Value. +// If v is not a pointer, Indirect returns v. +func Indirect(v Value) Value { + if v.Kind() != Pointer { + return v + } + return v.Elem() +} + +// ValueOf returns a new Value initialized to the concrete value +// stored in the interface i. ValueOf(nil) returns the zero Value. +func ValueOf(i any) Value { + if i == nil { + return Value{} + } + return unpackEface(i) +} + +// Zero returns a Value representing the zero value for the specified type. +// The result is different from the zero value of the Value struct, +// which represents no value at all. +// For example, Zero(TypeOf(42)) returns a Value with Kind [Int] and value 0. +// The returned value is neither addressable nor settable. +func Zero(typ Type) Value { + if typ == nil { + panic("reflect: Zero(nil)") + } + t := &typ.(*rtype).t + fl := flag(t.Kind()) + if t.IfaceIndir() { + var p unsafe.Pointer + if t.Size() <= abi.ZeroValSize { + p = unsafe.Pointer(&zeroVal[0]) + } else { + p = unsafe_New(t) + } + return Value{t, p, fl | flagIndir} + } + return Value{t, nil, fl} +} + +//go:linkname zeroVal runtime.zeroVal +var zeroVal [abi.ZeroValSize]byte + +// New returns a Value representing a pointer to a new zero value +// for the specified type. That is, the returned Value's Type is [PointerTo](typ). +func New(typ Type) Value { + if typ == nil { + panic("reflect: New(nil)") + } + t := &typ.(*rtype).t + pt := ptrTo(t) + if pt.IfaceIndir() { + // This is a pointer to a not-in-heap type. + panic("reflect: New of type that may not be allocated in heap (possibly undefined cgo C type)") + } + ptr := unsafe_New(t) + fl := flag(Pointer) + return Value{pt, ptr, fl} +} + +// NewAt returns a Value representing a pointer to a value of the +// specified type, using p as that pointer. +func NewAt(typ Type, p unsafe.Pointer) Value { + fl := flag(Pointer) + t := typ.(*rtype) + return Value{t.ptrTo(), p, fl} +} + +// assignTo returns a value v that can be assigned directly to dst. +// It panics if v is not assignable to dst. +// For a conversion to an interface type, target, if not nil, +// is a suggested scratch space to use. +// target must be initialized memory (or nil). +func (v Value) assignTo(context string, dst *abi.Type, target unsafe.Pointer) Value { + if v.flag&flagMethod != 0 { + v = makeMethodValue(context, v) + } + + switch { + case directlyAssignable(dst, v.typ()): + // Overwrite type so that they match. + // Same memory layout, so no harm done. + fl := v.flag&(flagAddr|flagIndir) | v.flag.ro() + fl |= flag(dst.Kind()) + return Value{dst, v.ptr, fl} + + case implements(dst, v.typ()): + if v.Kind() == Interface && v.IsNil() { + // A nil ReadWriter passed to nil Reader is OK, + // but using ifaceE2I below will panic. + // Avoid the panic by returning a nil dst (e.g., Reader) explicitly. + return Value{dst, nil, flag(Interface)} + } + x := valueInterface(v, false) + if target == nil { + target = unsafe_New(dst) + } + if dst.NumMethod() == 0 { + *(*any)(target) = x + } else { + ifaceE2I(dst, x, target) + } + return Value{dst, target, flagIndir | flag(Interface)} + } + + // Failed. + panic(context + ": value of type " + stringFor(v.typ()) + " is not assignable to type " + stringFor(dst)) +} + +// Convert returns the value v converted to type t. +// If the usual Go conversion rules do not allow conversion +// of the value v to type t, or if converting v to type t panics, Convert panics. +func (v Value) Convert(t Type) Value { + if v.flag&flagMethod != 0 { + v = makeMethodValue("Convert", v) + } + op := convertOp(t.common(), v.typ()) + if op == nil { + panic("reflect.Value.Convert: value of type " + stringFor(v.typ()) + " cannot be converted to type " + t.String()) + } + return op(v, t) +} + +// CanConvert reports whether the value v can be converted to type t. +// If v.CanConvert(t) returns true then v.Convert(t) will not panic. +func (v Value) CanConvert(t Type) bool { + vt := v.Type() + if !vt.ConvertibleTo(t) { + return false + } + // Converting from slice to array or to pointer-to-array can panic + // depending on the value. + switch { + case vt.Kind() == Slice && t.Kind() == Array: + if t.Len() > v.Len() { + return false + } + case vt.Kind() == Slice && t.Kind() == Pointer && t.Elem().Kind() == Array: + n := t.Elem().Len() + if n > v.Len() { + return false + } + } + return true +} + +// Comparable reports whether the value v is comparable. +// If the type of v is an interface, this checks the dynamic type. +// If this reports true then v.Interface() == x will not panic for any x, +// nor will v.Equal(u) for any Value u. +func (v Value) Comparable() bool { + k := v.Kind() + switch k { + case Invalid: + return false + + case Array: + switch v.Type().Elem().Kind() { + case Interface, Array, Struct: + for i := 0; i < v.Type().Len(); i++ { + if !v.Index(i).Comparable() { + return false + } + } + return true + } + return v.Type().Comparable() + + case Interface: + return v.IsNil() || v.Elem().Comparable() + + case Struct: + for i := 0; i < v.NumField(); i++ { + if !v.Field(i).Comparable() { + return false + } + } + return true + + default: + return v.Type().Comparable() + } +} + +// Equal reports true if v is equal to u. +// For two invalid values, Equal will report true. +// For an interface value, Equal will compare the value within the interface. +// Otherwise, If the values have different types, Equal will report false. +// Otherwise, for arrays and structs Equal will compare each element in order, +// and report false if it finds non-equal elements. +// During all comparisons, if values of the same type are compared, +// and the type is not comparable, Equal will panic. +func (v Value) Equal(u Value) bool { + if v.Kind() == Interface { + v = v.Elem() + } + if u.Kind() == Interface { + u = u.Elem() + } + + if !v.IsValid() || !u.IsValid() { + return v.IsValid() == u.IsValid() + } + + if v.Kind() != u.Kind() || v.Type() != u.Type() { + return false + } + + // Handle each Kind directly rather than calling valueInterface + // to avoid allocating. + switch v.Kind() { + default: + panic("reflect.Value.Equal: invalid Kind") + case Bool: + return v.Bool() == u.Bool() + case Int, Int8, Int16, Int32, Int64: + return v.Int() == u.Int() + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return v.Uint() == u.Uint() + case Float32, Float64: + return v.Float() == u.Float() + case Complex64, Complex128: + return v.Complex() == u.Complex() + case String: + return v.String() == u.String() + case Chan, Pointer, UnsafePointer: + return v.Pointer() == u.Pointer() + case Array: + // u and v have the same type so they have the same length + vl := v.Len() + if vl == 0 { + // panic on [0]func() + if !v.Type().Elem().Comparable() { + break + } + return true + } + for i := 0; i < vl; i++ { + if !v.Index(i).Equal(u.Index(i)) { + return false + } + } + return true + case Struct: + // u and v have the same type so they have the same fields + nf := v.NumField() + for i := 0; i < nf; i++ { + if !v.Field(i).Equal(u.Field(i)) { + return false + } + } + return true + case Func, Map, Slice: + break + } + panic("reflect.Value.Equal: values of type " + v.Type().String() + " are not comparable") +} + +// convertOp returns the function to convert a value of type src +// to a value of type dst. If the conversion is illegal, convertOp returns nil. +func convertOp(dst, src *abi.Type) func(Value, Type) Value { + switch Kind(src.Kind()) { + case Int, Int8, Int16, Int32, Int64: + switch Kind(dst.Kind()) { + case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return cvtInt + case Float32, Float64: + return cvtIntFloat + case String: + return cvtIntString + } + + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + switch Kind(dst.Kind()) { + case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return cvtUint + case Float32, Float64: + return cvtUintFloat + case String: + return cvtUintString + } + + case Float32, Float64: + switch Kind(dst.Kind()) { + case Int, Int8, Int16, Int32, Int64: + return cvtFloatInt + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return cvtFloatUint + case Float32, Float64: + return cvtFloat + } + + case Complex64, Complex128: + switch Kind(dst.Kind()) { + case Complex64, Complex128: + return cvtComplex + } + + case String: + if dst.Kind() == abi.Slice && pkgPathFor(dst.Elem()) == "" { + switch Kind(dst.Elem().Kind()) { + case Uint8: + return cvtStringBytes + case Int32: + return cvtStringRunes + } + } + + case Slice: + if dst.Kind() == abi.String && pkgPathFor(src.Elem()) == "" { + switch Kind(src.Elem().Kind()) { + case Uint8: + return cvtBytesString + case Int32: + return cvtRunesString + } + } + // "x is a slice, T is a pointer-to-array type, + // and the slice and array types have identical element types." + if dst.Kind() == abi.Pointer && dst.Elem().Kind() == abi.Array && src.Elem() == dst.Elem().Elem() { + return cvtSliceArrayPtr + } + // "x is a slice, T is an array type, + // and the slice and array types have identical element types." + if dst.Kind() == abi.Array && src.Elem() == dst.Elem() { + return cvtSliceArray + } + + case Chan: + if dst.Kind() == abi.Chan && specialChannelAssignability(dst, src) { + return cvtDirect + } + } + + // dst and src have same underlying type. + if haveIdenticalUnderlyingType(dst, src, false) { + return cvtDirect + } + + // dst and src are non-defined pointer types with same underlying base type. + if dst.Kind() == abi.Pointer && nameFor(dst) == "" && + src.Kind() == abi.Pointer && nameFor(src) == "" && + haveIdenticalUnderlyingType(elem(dst), elem(src), false) { + return cvtDirect + } + + if implements(dst, src) { + if src.Kind() == abi.Interface { + return cvtI2I + } + return cvtT2I + } + + return nil +} + +// makeInt returns a Value of type t equal to bits (possibly truncated), +// where t is a signed or unsigned int type. +func makeInt(f flag, bits uint64, t Type) Value { + typ := t.common() + ptr := unsafe_New(typ) + switch typ.Size() { + case 1: + *(*uint8)(ptr) = uint8(bits) + case 2: + *(*uint16)(ptr) = uint16(bits) + case 4: + *(*uint32)(ptr) = uint32(bits) + case 8: + *(*uint64)(ptr) = bits + } + return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} +} + +// makeFloat returns a Value of type t equal to v (possibly truncated to float32), +// where t is a float32 or float64 type. +func makeFloat(f flag, v float64, t Type) Value { + typ := t.common() + ptr := unsafe_New(typ) + switch typ.Size() { + case 4: + *(*float32)(ptr) = float32(v) + case 8: + *(*float64)(ptr) = v + } + return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} +} + +// makeFloat32 returns a Value of type t equal to v, where t is a float32 type. +func makeFloat32(f flag, v float32, t Type) Value { + typ := t.common() + ptr := unsafe_New(typ) + *(*float32)(ptr) = v + return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} +} + +// makeComplex returns a Value of type t equal to v (possibly truncated to complex64), +// where t is a complex64 or complex128 type. +func makeComplex(f flag, v complex128, t Type) Value { + typ := t.common() + ptr := unsafe_New(typ) + switch typ.Size() { + case 8: + *(*complex64)(ptr) = complex64(v) + case 16: + *(*complex128)(ptr) = v + } + return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} +} + +func makeString(f flag, v string, t Type) Value { + ret := New(t).Elem() + ret.SetString(v) + ret.flag = ret.flag&^flagAddr | f + return ret +} + +func makeBytes(f flag, v []byte, t Type) Value { + ret := New(t).Elem() + ret.SetBytes(v) + ret.flag = ret.flag&^flagAddr | f + return ret +} + +func makeRunes(f flag, v []rune, t Type) Value { + ret := New(t).Elem() + ret.setRunes(v) + ret.flag = ret.flag&^flagAddr | f + return ret +} + +// These conversion functions are returned by convertOp +// for classes of conversions. For example, the first function, cvtInt, +// takes any value v of signed int type and returns the value converted +// to type t, where t is any signed or unsigned int type. + +// convertOp: intXX -> [u]intXX +func cvtInt(v Value, t Type) Value { + return makeInt(v.flag.ro(), uint64(v.Int()), t) +} + +// convertOp: uintXX -> [u]intXX +func cvtUint(v Value, t Type) Value { + return makeInt(v.flag.ro(), v.Uint(), t) +} + +// convertOp: floatXX -> intXX +func cvtFloatInt(v Value, t Type) Value { + return makeInt(v.flag.ro(), uint64(int64(v.Float())), t) +} + +// convertOp: floatXX -> uintXX +func cvtFloatUint(v Value, t Type) Value { + return makeInt(v.flag.ro(), uint64(v.Float()), t) +} + +// convertOp: intXX -> floatXX +func cvtIntFloat(v Value, t Type) Value { + return makeFloat(v.flag.ro(), float64(v.Int()), t) +} + +// convertOp: uintXX -> floatXX +func cvtUintFloat(v Value, t Type) Value { + return makeFloat(v.flag.ro(), float64(v.Uint()), t) +} + +// convertOp: floatXX -> floatXX +func cvtFloat(v Value, t Type) Value { + if v.Type().Kind() == Float32 && t.Kind() == Float32 { + // Don't do any conversion if both types have underlying type float32. + // This avoids converting to float64 and back, which will + // convert a signaling NaN to a quiet NaN. See issue 36400. + return makeFloat32(v.flag.ro(), *(*float32)(v.ptr), t) + } + return makeFloat(v.flag.ro(), v.Float(), t) +} + +// convertOp: complexXX -> complexXX +func cvtComplex(v Value, t Type) Value { + return makeComplex(v.flag.ro(), v.Complex(), t) +} + +// convertOp: intXX -> string +func cvtIntString(v Value, t Type) Value { + s := "\uFFFD" + if x := v.Int(); int64(rune(x)) == x { + s = string(rune(x)) + } + return makeString(v.flag.ro(), s, t) +} + +// convertOp: uintXX -> string +func cvtUintString(v Value, t Type) Value { + s := "\uFFFD" + if x := v.Uint(); uint64(rune(x)) == x { + s = string(rune(x)) + } + return makeString(v.flag.ro(), s, t) +} + +// convertOp: []byte -> string +func cvtBytesString(v Value, t Type) Value { + return makeString(v.flag.ro(), string(v.Bytes()), t) +} + +// convertOp: string -> []byte +func cvtStringBytes(v Value, t Type) Value { + return makeBytes(v.flag.ro(), []byte(v.String()), t) +} + +// convertOp: []rune -> string +func cvtRunesString(v Value, t Type) Value { + return makeString(v.flag.ro(), string(v.runes()), t) +} + +// convertOp: string -> []rune +func cvtStringRunes(v Value, t Type) Value { + return makeRunes(v.flag.ro(), []rune(v.String()), t) +} + +// convertOp: []T -> *[N]T +func cvtSliceArrayPtr(v Value, t Type) Value { + n := t.Elem().Len() + if n > v.Len() { + panic("reflect: cannot convert slice with length " + itoa.Itoa(v.Len()) + " to pointer to array with length " + itoa.Itoa(n)) + } + h := (*unsafeheader.Slice)(v.ptr) + return Value{t.common(), h.Data, v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Pointer)} +} + +// convertOp: []T -> [N]T +func cvtSliceArray(v Value, t Type) Value { + n := t.Len() + if n > v.Len() { + panic("reflect: cannot convert slice with length " + itoa.Itoa(v.Len()) + " to array with length " + itoa.Itoa(n)) + } + h := (*unsafeheader.Slice)(v.ptr) + typ := t.common() + ptr := h.Data + c := unsafe_New(typ) + typedmemmove(typ, c, ptr) + ptr = c + + return Value{typ, ptr, v.flag&^(flagAddr|flagKindMask) | flag(Array)} +} + +// convertOp: direct copy +func cvtDirect(v Value, typ Type) Value { + f := v.flag + t := typ.common() + ptr := v.ptr + if f&flagAddr != 0 { + // indirect, mutable word - make a copy + c := unsafe_New(t) + typedmemmove(t, c, ptr) + ptr = c + f &^= flagAddr + } + return Value{t, ptr, v.flag.ro() | f} // v.flag.ro()|f == f? +} + +// convertOp: concrete -> interface +func cvtT2I(v Value, typ Type) Value { + target := unsafe_New(typ.common()) + x := valueInterface(v, false) + if typ.NumMethod() == 0 { + *(*any)(target) = x + } else { + ifaceE2I(typ.common(), x, target) + } + return Value{typ.common(), target, v.flag.ro() | flagIndir | flag(Interface)} +} + +// convertOp: interface -> interface +func cvtI2I(v Value, typ Type) Value { + if v.IsNil() { + ret := Zero(typ) + ret.flag |= v.flag.ro() + return ret + } + return cvtT2I(v.Elem(), typ) +} + +// implemented in ../runtime +// +//go:noescape +func chancap(ch unsafe.Pointer) int + +//go:noescape +func chanclose(ch unsafe.Pointer) + +//go:noescape +func chanlen(ch unsafe.Pointer) int + +// Note: some of the noescape annotations below are technically a lie, +// but safe in the context of this package. Functions like chansend0 +// and mapassign0 don't escape the referent, but may escape anything +// the referent points to (they do shallow copies of the referent). +// We add a 0 to their names and wrap them in functions with the +// proper escape behavior. + +//go:noescape +func chanrecv(ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool) + +//go:noescape +func chansend0(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool + +func chansend(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool { + contentEscapes(val) + return chansend0(ch, val, nb) +} + +func makechan(typ *abi.Type, size int) (ch unsafe.Pointer) +func makemap(t *abi.Type, cap int) (m unsafe.Pointer) + +//go:noescape +func mapaccess(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer) + +//go:noescape +func mapaccess_faststr(t *abi.Type, m unsafe.Pointer, key string) (val unsafe.Pointer) + +//go:noescape +func mapassign0(t *abi.Type, m unsafe.Pointer, key, val unsafe.Pointer) + +// mapassign should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/modern-go/reflect2 +// - github.com/goccy/go-json +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign +func mapassign(t *abi.Type, m unsafe.Pointer, key, val unsafe.Pointer) { + contentEscapes(key) + contentEscapes(val) + mapassign0(t, m, key, val) +} + +//go:noescape +func mapassign_faststr0(t *abi.Type, m unsafe.Pointer, key string, val unsafe.Pointer) + +func mapassign_faststr(t *abi.Type, m unsafe.Pointer, key string, val unsafe.Pointer) { + contentEscapes((*unsafeheader.String)(unsafe.Pointer(&key)).Data) + contentEscapes(val) + mapassign_faststr0(t, m, key, val) +} + +//go:noescape +func mapdelete(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) + +//go:noescape +func mapdelete_faststr(t *abi.Type, m unsafe.Pointer, key string) + +//go:noescape +func mapiterinit(t *abi.Type, m unsafe.Pointer, it *hiter) + +//go:noescape +func mapiterkey(it *hiter) (key unsafe.Pointer) + +//go:noescape +func mapiterelem(it *hiter) (elem unsafe.Pointer) + +//go:noescape +func mapiternext(it *hiter) + +//go:noescape +func maplen(m unsafe.Pointer) int + +func mapclear(t *abi.Type, m unsafe.Pointer) + +// call calls fn with "stackArgsSize" bytes of stack arguments laid out +// at stackArgs and register arguments laid out in regArgs. frameSize is +// the total amount of stack space that will be reserved by call, so this +// should include enough space to spill register arguments to the stack in +// case of preemption. +// +// After fn returns, call copies stackArgsSize-stackRetOffset result bytes +// back into stackArgs+stackRetOffset before returning, for any return +// values passed on the stack. Register-based return values will be found +// in the same regArgs structure. +// +// regArgs must also be prepared with an appropriate ReturnIsPtr bitmap +// indicating which registers will contain pointer-valued return values. The +// purpose of this bitmap is to keep pointers visible to the GC between +// returning from reflectcall and actually using them. +// +// If copying result bytes back from the stack, the caller must pass the +// argument frame type as stackArgsType, so that call can execute appropriate +// write barriers during the copy. +// +// Arguments passed through to call do not escape. The type is used only in a +// very limited callee of call, the stackArgs are copied, and regArgs is only +// used in the call frame. +// +//go:noescape +//go:linkname call runtime.reflectcall +func call(stackArgsType *abi.Type, f, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) + +func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) + +// memmove copies size bytes to dst from src. No write barriers are used. +// +//go:noescape +func memmove(dst, src unsafe.Pointer, size uintptr) + +// typedmemmove copies a value of type t to dst from src. +// +//go:noescape +func typedmemmove(t *abi.Type, dst, src unsafe.Pointer) + +// typedmemclr zeros the value at ptr of type t. +// +//go:noescape +func typedmemclr(t *abi.Type, ptr unsafe.Pointer) + +// typedmemclrpartial is like typedmemclr but assumes that +// dst points off bytes into the value and only clears size bytes. +// +//go:noescape +func typedmemclrpartial(t *abi.Type, ptr unsafe.Pointer, off, size uintptr) + +// typedslicecopy copies a slice of elemType values from src to dst, +// returning the number of elements copied. +// +//go:noescape +func typedslicecopy(t *abi.Type, dst, src unsafeheader.Slice) int + +// typedarrayclear zeroes the value at ptr of an array of elemType, +// only clears len elem. +// +//go:noescape +func typedarrayclear(elemType *abi.Type, ptr unsafe.Pointer, len int) + +//go:noescape +func typehash(t *abi.Type, p unsafe.Pointer, h uintptr) uintptr + +func verifyNotInHeapPtr(p uintptr) bool + +//go:noescape +func growslice(t *abi.Type, old unsafeheader.Slice, num int) unsafeheader.Slice + +//go:noescape +func unsafeslice(t *abi.Type, ptr unsafe.Pointer, len int) + +// Dummy annotation marking that the value x escapes, +// for use in cases where the reflect code is so clever that +// the compiler cannot follow. +func escapes(x any) { + if dummy.b { + dummy.x = x + } +} + +var dummy struct { + b bool + x any +} + +// Dummy annotation marking that the content of value x +// escapes (i.e. modeling roughly heap=*x), +// for use in cases where the reflect code is so clever that +// the compiler cannot follow. +func contentEscapes(x unsafe.Pointer) { + if dummy.b { + escapes(*(*any)(x)) // the dereference may not always be safe, but never executed + } +} + +// This is just a wrapper around abi.NoEscape. The inlining heuristics are +// finnicky and for whatever reason treat the local call to noescape as much +// lower cost with respect to the inliner budget. (That is, replacing calls to +// noescape with abi.NoEscape will cause inlining tests to fail.) +// +//go:nosplit +func noescape(p unsafe.Pointer) unsafe.Pointer { + return abi.NoEscape(p) +} diff --git a/contrib/go/_std_1.22/src/reflect/visiblefields.go b/contrib/go/_std_1.23/src/reflect/visiblefields.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/visiblefields.go rename to contrib/go/_std_1.23/src/reflect/visiblefields.go diff --git a/contrib/go/_std_1.23/src/reflect/ya.make b/contrib/go/_std_1.23/src/reflect/ya.make new file mode 100644 index 000000000000..eddc381f9769 --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/ya.make @@ -0,0 +1,45 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + abi.go + asm_arm64.s + badlinkname.go + deepequal.go + float32reg_generic.go + iter.go + makefunc.go + swapper.go + type.go + value.go + visiblefields.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + abi.go + asm_amd64.s + badlinkname.go + deepequal.go + float32reg_generic.go + iter.go + makefunc.go + swapper.go + type.go + value.go + visiblefields.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + abi.go + asm_arm.s + badlinkname.go + deepequal.go + float32reg_generic.go + iter.go + makefunc.go + swapper.go + type.go + value.go + visiblefields.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/regexp/backtrack.go b/contrib/go/_std_1.23/src/regexp/backtrack.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/backtrack.go rename to contrib/go/_std_1.23/src/regexp/backtrack.go diff --git a/contrib/go/_std_1.22/src/regexp/exec.go b/contrib/go/_std_1.23/src/regexp/exec.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/exec.go rename to contrib/go/_std_1.23/src/regexp/exec.go diff --git a/contrib/go/_std_1.22/src/regexp/onepass.go b/contrib/go/_std_1.23/src/regexp/onepass.go similarity index 97% rename from contrib/go/_std_1.22/src/regexp/onepass.go rename to contrib/go/_std_1.23/src/regexp/onepass.go index b3066e88ee43..53cbd9583941 100644 --- a/contrib/go/_std_1.22/src/regexp/onepass.go +++ b/contrib/go/_std_1.23/src/regexp/onepass.go @@ -6,7 +6,7 @@ package regexp import ( "regexp/syntax" - "sort" + "slices" "strings" "unicode" "unicode/utf8" @@ -282,13 +282,6 @@ func onePassCopy(prog *syntax.Prog) *onePassProg { return p } -// runeSlice exists to permit sorting the case-folded rune sets. -type runeSlice []rune - -func (p runeSlice) Len() int { return len(p) } -func (p runeSlice) Less(i, j int) bool { return p[i] < p[j] } -func (p runeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune} var anyRune = []rune{0, unicode.MaxRune} @@ -383,7 +376,7 @@ func makeOnePass(p *onePassProg) *onePassProg { for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) { runes = append(runes, r1, r1) } - sort.Sort(runeSlice(runes)) + slices.Sort(runes) } else { runes = append(runes, inst.Rune...) } @@ -407,7 +400,7 @@ func makeOnePass(p *onePassProg) *onePassProg { for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) { runes = append(runes, r1, r1) } - sort.Sort(runeSlice(runes)) + slices.Sort(runes) } else { runes = append(runes, inst.Rune[0], inst.Rune[0]) } diff --git a/contrib/go/_std_1.23/src/regexp/regexp.go b/contrib/go/_std_1.23/src/regexp/regexp.go new file mode 100644 index 000000000000..e06099425ebc --- /dev/null +++ b/contrib/go/_std_1.23/src/regexp/regexp.go @@ -0,0 +1,1299 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package regexp implements regular expression search. +// +// The syntax of the regular expressions accepted is the same +// general syntax used by Perl, Python, and other languages. +// More precisely, it is the syntax accepted by RE2 and described at +// https://golang.org/s/re2syntax, except for \C. +// For an overview of the syntax, see the [regexp/syntax] package. +// +// The regexp implementation provided by this package is +// guaranteed to run in time linear in the size of the input. +// (This is a property not guaranteed by most open source +// implementations of regular expressions.) For more information +// about this property, see https://swtch.com/~rsc/regexp/regexp1.html +// or any book about automata theory. +// +// All characters are UTF-8-encoded code points. +// Following [utf8.DecodeRune], each byte of an invalid UTF-8 sequence +// is treated as if it encoded utf8.RuneError (U+FFFD). +// +// There are 16 methods of [Regexp] that match a regular expression and identify +// the matched text. Their names are matched by this regular expression: +// +// Find(All)?(String)?(Submatch)?(Index)? +// +// If 'All' is present, the routine matches successive non-overlapping +// matches of the entire expression. Empty matches abutting a preceding +// match are ignored. The return value is a slice containing the successive +// return values of the corresponding non-'All' routine. These routines take +// an extra integer argument, n. If n >= 0, the function returns at most n +// matches/submatches; otherwise, it returns all of them. +// +// If 'String' is present, the argument is a string; otherwise it is a slice +// of bytes; return values are adjusted as appropriate. +// +// If 'Submatch' is present, the return value is a slice identifying the +// successive submatches of the expression. Submatches are matches of +// parenthesized subexpressions (also known as capturing groups) within the +// regular expression, numbered from left to right in order of opening +// parenthesis. Submatch 0 is the match of the entire expression, submatch 1 is +// the match of the first parenthesized subexpression, and so on. +// +// If 'Index' is present, matches and submatches are identified by byte index +// pairs within the input string: result[2*n:2*n+2] identifies the indexes of +// the nth submatch. The pair for n==0 identifies the match of the entire +// expression. If 'Index' is not present, the match is identified by the text +// of the match/submatch. If an index is negative or text is nil, it means that +// subexpression did not match any string in the input. For 'String' versions +// an empty string means either no match or an empty match. +// +// There is also a subset of the methods that can be applied to text read from +// an [io.RuneReader]: [Regexp.MatchReader], [Regexp.FindReaderIndex], +// [Regexp.FindReaderSubmatchIndex]. +// +// This set may grow. Note that regular expression matches may need to +// examine text beyond the text returned by a match, so the methods that +// match text from an [io.RuneReader] may read arbitrarily far into the input +// before returning. +// +// (There are a few other methods that do not match this pattern.) +package regexp + +import ( + "bytes" + "io" + "regexp/syntax" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// Regexp is the representation of a compiled regular expression. +// A Regexp is safe for concurrent use by multiple goroutines, +// except for configuration methods, such as [Regexp.Longest]. +type Regexp struct { + expr string // as passed to Compile + prog *syntax.Prog // compiled program + onepass *onePassProg // onepass program or nil + numSubexp int + maxBitStateLen int + subexpNames []string + prefix string // required prefix in unanchored matches + prefixBytes []byte // prefix, as a []byte + prefixRune rune // first rune in prefix + prefixEnd uint32 // pc for last rune in prefix + mpool int // pool for machines + matchcap int // size of recorded match lengths + prefixComplete bool // prefix is the entire regexp + cond syntax.EmptyOp // empty-width conditions required at start of match + minInputLen int // minimum length of the input in bytes + + // This field can be modified by the Longest method, + // but it is otherwise read-only. + longest bool // whether regexp prefers leftmost-longest match +} + +// String returns the source text used to compile the regular expression. +func (re *Regexp) String() string { + return re.expr +} + +// Copy returns a new [Regexp] object copied from re. +// Calling [Regexp.Longest] on one copy does not affect another. +// +// Deprecated: In earlier releases, when using a [Regexp] in multiple goroutines, +// giving each goroutine its own copy helped to avoid lock contention. +// As of Go 1.12, using Copy is no longer necessary to avoid lock contention. +// Copy may still be appropriate if the reason for its use is to make +// two copies with different [Regexp.Longest] settings. +func (re *Regexp) Copy() *Regexp { + re2 := *re + return &re2 +} + +// Compile parses a regular expression and returns, if successful, +// a [Regexp] object that can be used to match against text. +// +// When matching against text, the regexp returns a match that +// begins as early as possible in the input (leftmost), and among those +// it chooses the one that a backtracking search would have found first. +// This so-called leftmost-first matching is the same semantics +// that Perl, Python, and other implementations use, although this +// package implements it without the expense of backtracking. +// For POSIX leftmost-longest matching, see [CompilePOSIX]. +func Compile(expr string) (*Regexp, error) { + return compile(expr, syntax.Perl, false) +} + +// CompilePOSIX is like [Compile] but restricts the regular expression +// to POSIX ERE (egrep) syntax and changes the match semantics to +// leftmost-longest. +// +// That is, when matching against text, the regexp returns a match that +// begins as early as possible in the input (leftmost), and among those +// it chooses a match that is as long as possible. +// This so-called leftmost-longest matching is the same semantics +// that early regular expression implementations used and that POSIX +// specifies. +// +// However, there can be multiple leftmost-longest matches, with different +// submatch choices, and here this package diverges from POSIX. +// Among the possible leftmost-longest matches, this package chooses +// the one that a backtracking search would have found first, while POSIX +// specifies that the match be chosen to maximize the length of the first +// subexpression, then the second, and so on from left to right. +// The POSIX rule is computationally prohibitive and not even well-defined. +// See https://swtch.com/~rsc/regexp/regexp2.html#posix for details. +func CompilePOSIX(expr string) (*Regexp, error) { + return compile(expr, syntax.POSIX, true) +} + +// Longest makes future searches prefer the leftmost-longest match. +// That is, when matching against text, the regexp returns a match that +// begins as early as possible in the input (leftmost), and among those +// it chooses a match that is as long as possible. +// This method modifies the [Regexp] and may not be called concurrently +// with any other methods. +func (re *Regexp) Longest() { + re.longest = true +} + +func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) { + re, err := syntax.Parse(expr, mode) + if err != nil { + return nil, err + } + maxCap := re.MaxCap() + capNames := re.CapNames() + + re = re.Simplify() + prog, err := syntax.Compile(re) + if err != nil { + return nil, err + } + matchcap := prog.NumCap + if matchcap < 2 { + matchcap = 2 + } + regexp := &Regexp{ + expr: expr, + prog: prog, + onepass: compileOnePass(prog), + numSubexp: maxCap, + subexpNames: capNames, + cond: prog.StartCond(), + longest: longest, + matchcap: matchcap, + minInputLen: minInputLen(re), + } + if regexp.onepass == nil { + regexp.prefix, regexp.prefixComplete = prog.Prefix() + regexp.maxBitStateLen = maxBitStateLen(prog) + } else { + regexp.prefix, regexp.prefixComplete, regexp.prefixEnd = onePassPrefix(prog) + } + if regexp.prefix != "" { + // TODO(rsc): Remove this allocation by adding + // IndexString to package bytes. + regexp.prefixBytes = []byte(regexp.prefix) + regexp.prefixRune, _ = utf8.DecodeRuneInString(regexp.prefix) + } + + n := len(prog.Inst) + i := 0 + for matchSize[i] != 0 && matchSize[i] < n { + i++ + } + regexp.mpool = i + + return regexp, nil +} + +// Pools of *machine for use during (*Regexp).doExecute, +// split up by the size of the execution queues. +// matchPool[i] machines have queue size matchSize[i]. +// On a 64-bit system each queue entry is 16 bytes, +// so matchPool[0] has 16*2*128 = 4kB queues, etc. +// The final matchPool is a catch-all for very large queues. +var ( + matchSize = [...]int{128, 512, 2048, 16384, 0} + matchPool [len(matchSize)]sync.Pool +) + +// get returns a machine to use for matching re. +// It uses the re's machine cache if possible, to avoid +// unnecessary allocation. +func (re *Regexp) get() *machine { + m, ok := matchPool[re.mpool].Get().(*machine) + if !ok { + m = new(machine) + } + m.re = re + m.p = re.prog + if cap(m.matchcap) < re.matchcap { + m.matchcap = make([]int, re.matchcap) + for _, t := range m.pool { + t.cap = make([]int, re.matchcap) + } + } + + // Allocate queues if needed. + // Or reallocate, for "large" match pool. + n := matchSize[re.mpool] + if n == 0 { // large pool + n = len(re.prog.Inst) + } + if len(m.q0.sparse) < n { + m.q0 = queue{make([]uint32, n), make([]entry, 0, n)} + m.q1 = queue{make([]uint32, n), make([]entry, 0, n)} + } + return m +} + +// put returns a machine to the correct machine pool. +func (re *Regexp) put(m *machine) { + m.re = nil + m.p = nil + m.inputs.clear() + matchPool[re.mpool].Put(m) +} + +// minInputLen walks the regexp to find the minimum length of any matchable input. +func minInputLen(re *syntax.Regexp) int { + switch re.Op { + default: + return 0 + case syntax.OpAnyChar, syntax.OpAnyCharNotNL, syntax.OpCharClass: + return 1 + case syntax.OpLiteral: + l := 0 + for _, r := range re.Rune { + if r == utf8.RuneError { + l++ + } else { + l += utf8.RuneLen(r) + } + } + return l + case syntax.OpCapture, syntax.OpPlus: + return minInputLen(re.Sub[0]) + case syntax.OpRepeat: + return re.Min * minInputLen(re.Sub[0]) + case syntax.OpConcat: + l := 0 + for _, sub := range re.Sub { + l += minInputLen(sub) + } + return l + case syntax.OpAlternate: + l := minInputLen(re.Sub[0]) + var lnext int + for _, sub := range re.Sub[1:] { + lnext = minInputLen(sub) + if lnext < l { + l = lnext + } + } + return l + } +} + +// MustCompile is like [Compile] but panics if the expression cannot be parsed. +// It simplifies safe initialization of global variables holding compiled regular +// expressions. +func MustCompile(str string) *Regexp { + regexp, err := Compile(str) + if err != nil { + panic(`regexp: Compile(` + quote(str) + `): ` + err.Error()) + } + return regexp +} + +// MustCompilePOSIX is like [CompilePOSIX] but panics if the expression cannot be parsed. +// It simplifies safe initialization of global variables holding compiled regular +// expressions. +func MustCompilePOSIX(str string) *Regexp { + regexp, err := CompilePOSIX(str) + if err != nil { + panic(`regexp: CompilePOSIX(` + quote(str) + `): ` + err.Error()) + } + return regexp +} + +func quote(s string) string { + if strconv.CanBackquote(s) { + return "`" + s + "`" + } + return strconv.Quote(s) +} + +// NumSubexp returns the number of parenthesized subexpressions in this [Regexp]. +func (re *Regexp) NumSubexp() int { + return re.numSubexp +} + +// SubexpNames returns the names of the parenthesized subexpressions +// in this [Regexp]. The name for the first sub-expression is names[1], +// so that if m is a match slice, the name for m[i] is SubexpNames()[i]. +// Since the Regexp as a whole cannot be named, names[0] is always +// the empty string. The slice should not be modified. +func (re *Regexp) SubexpNames() []string { + return re.subexpNames +} + +// SubexpIndex returns the index of the first subexpression with the given name, +// or -1 if there is no subexpression with that name. +// +// Note that multiple subexpressions can be written using the same name, as in +// (?Pa+)(?Pb+), which declares two subexpressions named "bob". +// In this case, SubexpIndex returns the index of the leftmost such subexpression +// in the regular expression. +func (re *Regexp) SubexpIndex(name string) int { + if name != "" { + for i, s := range re.subexpNames { + if name == s { + return i + } + } + } + return -1 +} + +const endOfText rune = -1 + +// input abstracts different representations of the input text. It provides +// one-character lookahead. +type input interface { + step(pos int) (r rune, width int) // advance one rune + canCheckPrefix() bool // can we look ahead without losing info? + hasPrefix(re *Regexp) bool + index(re *Regexp, pos int) int + context(pos int) lazyFlag +} + +// inputString scans a string. +type inputString struct { + str string +} + +func (i *inputString) step(pos int) (rune, int) { + if pos < len(i.str) { + c := i.str[pos] + if c < utf8.RuneSelf { + return rune(c), 1 + } + return utf8.DecodeRuneInString(i.str[pos:]) + } + return endOfText, 0 +} + +func (i *inputString) canCheckPrefix() bool { + return true +} + +func (i *inputString) hasPrefix(re *Regexp) bool { + return strings.HasPrefix(i.str, re.prefix) +} + +func (i *inputString) index(re *Regexp, pos int) int { + return strings.Index(i.str[pos:], re.prefix) +} + +func (i *inputString) context(pos int) lazyFlag { + r1, r2 := endOfText, endOfText + // 0 < pos && pos <= len(i.str) + if uint(pos-1) < uint(len(i.str)) { + r1 = rune(i.str[pos-1]) + if r1 >= utf8.RuneSelf { + r1, _ = utf8.DecodeLastRuneInString(i.str[:pos]) + } + } + // 0 <= pos && pos < len(i.str) + if uint(pos) < uint(len(i.str)) { + r2 = rune(i.str[pos]) + if r2 >= utf8.RuneSelf { + r2, _ = utf8.DecodeRuneInString(i.str[pos:]) + } + } + return newLazyFlag(r1, r2) +} + +// inputBytes scans a byte slice. +type inputBytes struct { + str []byte +} + +func (i *inputBytes) step(pos int) (rune, int) { + if pos < len(i.str) { + c := i.str[pos] + if c < utf8.RuneSelf { + return rune(c), 1 + } + return utf8.DecodeRune(i.str[pos:]) + } + return endOfText, 0 +} + +func (i *inputBytes) canCheckPrefix() bool { + return true +} + +func (i *inputBytes) hasPrefix(re *Regexp) bool { + return bytes.HasPrefix(i.str, re.prefixBytes) +} + +func (i *inputBytes) index(re *Regexp, pos int) int { + return bytes.Index(i.str[pos:], re.prefixBytes) +} + +func (i *inputBytes) context(pos int) lazyFlag { + r1, r2 := endOfText, endOfText + // 0 < pos && pos <= len(i.str) + if uint(pos-1) < uint(len(i.str)) { + r1 = rune(i.str[pos-1]) + if r1 >= utf8.RuneSelf { + r1, _ = utf8.DecodeLastRune(i.str[:pos]) + } + } + // 0 <= pos && pos < len(i.str) + if uint(pos) < uint(len(i.str)) { + r2 = rune(i.str[pos]) + if r2 >= utf8.RuneSelf { + r2, _ = utf8.DecodeRune(i.str[pos:]) + } + } + return newLazyFlag(r1, r2) +} + +// inputReader scans a RuneReader. +type inputReader struct { + r io.RuneReader + atEOT bool + pos int +} + +func (i *inputReader) step(pos int) (rune, int) { + if !i.atEOT && pos != i.pos { + return endOfText, 0 + + } + r, w, err := i.r.ReadRune() + if err != nil { + i.atEOT = true + return endOfText, 0 + } + i.pos += w + return r, w +} + +func (i *inputReader) canCheckPrefix() bool { + return false +} + +func (i *inputReader) hasPrefix(re *Regexp) bool { + return false +} + +func (i *inputReader) index(re *Regexp, pos int) int { + return -1 +} + +func (i *inputReader) context(pos int) lazyFlag { + return 0 // not used +} + +// LiteralPrefix returns a literal string that must begin any match +// of the regular expression re. It returns the boolean true if the +// literal string comprises the entire regular expression. +func (re *Regexp) LiteralPrefix() (prefix string, complete bool) { + return re.prefix, re.prefixComplete +} + +// MatchReader reports whether the text returned by the [io.RuneReader] +// contains any match of the regular expression re. +func (re *Regexp) MatchReader(r io.RuneReader) bool { + return re.doMatch(r, nil, "") +} + +// MatchString reports whether the string s +// contains any match of the regular expression re. +func (re *Regexp) MatchString(s string) bool { + return re.doMatch(nil, nil, s) +} + +// Match reports whether the byte slice b +// contains any match of the regular expression re. +func (re *Regexp) Match(b []byte) bool { + return re.doMatch(nil, b, "") +} + +// MatchReader reports whether the text returned by the [io.RuneReader] +// contains any match of the regular expression pattern. +// More complicated queries need to use [Compile] and the full [Regexp] interface. +func MatchReader(pattern string, r io.RuneReader) (matched bool, err error) { + re, err := Compile(pattern) + if err != nil { + return false, err + } + return re.MatchReader(r), nil +} + +// MatchString reports whether the string s +// contains any match of the regular expression pattern. +// More complicated queries need to use [Compile] and the full [Regexp] interface. +func MatchString(pattern string, s string) (matched bool, err error) { + re, err := Compile(pattern) + if err != nil { + return false, err + } + return re.MatchString(s), nil +} + +// Match reports whether the byte slice b +// contains any match of the regular expression pattern. +// More complicated queries need to use [Compile] and the full [Regexp] interface. +func Match(pattern string, b []byte) (matched bool, err error) { + re, err := Compile(pattern) + if err != nil { + return false, err + } + return re.Match(b), nil +} + +// ReplaceAllString returns a copy of src, replacing matches of the [Regexp] +// with the replacement string repl. +// Inside repl, $ signs are interpreted as in [Regexp.Expand]. +func (re *Regexp) ReplaceAllString(src, repl string) string { + n := 2 + if strings.Contains(repl, "$") { + n = 2 * (re.numSubexp + 1) + } + b := re.replaceAll(nil, src, n, func(dst []byte, match []int) []byte { + return re.expand(dst, repl, nil, src, match) + }) + return string(b) +} + +// ReplaceAllLiteralString returns a copy of src, replacing matches of the [Regexp] +// with the replacement string repl. The replacement repl is substituted directly, +// without using [Regexp.Expand]. +func (re *Regexp) ReplaceAllLiteralString(src, repl string) string { + return string(re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte { + return append(dst, repl...) + })) +} + +// ReplaceAllStringFunc returns a copy of src in which all matches of the +// [Regexp] have been replaced by the return value of function repl applied +// to the matched substring. The replacement returned by repl is substituted +// directly, without using [Regexp.Expand]. +func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string { + b := re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte { + return append(dst, repl(src[match[0]:match[1]])...) + }) + return string(b) +} + +func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst []byte, m []int) []byte) []byte { + lastMatchEnd := 0 // end position of the most recent match + searchPos := 0 // position where we next look for a match + var buf []byte + var endPos int + if bsrc != nil { + endPos = len(bsrc) + } else { + endPos = len(src) + } + if nmatch > re.prog.NumCap { + nmatch = re.prog.NumCap + } + + var dstCap [2]int + for searchPos <= endPos { + a := re.doExecute(nil, bsrc, src, searchPos, nmatch, dstCap[:0]) + if len(a) == 0 { + break // no more matches + } + + // Copy the unmatched characters before this match. + if bsrc != nil { + buf = append(buf, bsrc[lastMatchEnd:a[0]]...) + } else { + buf = append(buf, src[lastMatchEnd:a[0]]...) + } + + // Now insert a copy of the replacement string, but not for a + // match of the empty string immediately after another match. + // (Otherwise, we get double replacement for patterns that + // match both empty and nonempty strings.) + if a[1] > lastMatchEnd || a[0] == 0 { + buf = repl(buf, a) + } + lastMatchEnd = a[1] + + // Advance past this match; always advance at least one character. + var width int + if bsrc != nil { + _, width = utf8.DecodeRune(bsrc[searchPos:]) + } else { + _, width = utf8.DecodeRuneInString(src[searchPos:]) + } + if searchPos+width > a[1] { + searchPos += width + } else if searchPos+1 > a[1] { + // This clause is only needed at the end of the input + // string. In that case, DecodeRuneInString returns width=0. + searchPos++ + } else { + searchPos = a[1] + } + } + + // Copy the unmatched characters after the last match. + if bsrc != nil { + buf = append(buf, bsrc[lastMatchEnd:]...) + } else { + buf = append(buf, src[lastMatchEnd:]...) + } + + return buf +} + +// ReplaceAll returns a copy of src, replacing matches of the [Regexp] +// with the replacement text repl. +// Inside repl, $ signs are interpreted as in [Regexp.Expand]. +func (re *Regexp) ReplaceAll(src, repl []byte) []byte { + n := 2 + if bytes.IndexByte(repl, '$') >= 0 { + n = 2 * (re.numSubexp + 1) + } + srepl := "" + b := re.replaceAll(src, "", n, func(dst []byte, match []int) []byte { + if len(srepl) != len(repl) { + srepl = string(repl) + } + return re.expand(dst, srepl, src, "", match) + }) + return b +} + +// ReplaceAllLiteral returns a copy of src, replacing matches of the [Regexp] +// with the replacement bytes repl. The replacement repl is substituted directly, +// without using [Regexp.Expand]. +func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte { + return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte { + return append(dst, repl...) + }) +} + +// ReplaceAllFunc returns a copy of src in which all matches of the +// [Regexp] have been replaced by the return value of function repl applied +// to the matched byte slice. The replacement returned by repl is substituted +// directly, without using [Regexp.Expand]. +func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte { + return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte { + return append(dst, repl(src[match[0]:match[1]])...) + }) +} + +// Bitmap used by func special to check whether a character needs to be escaped. +var specialBytes [16]byte + +// special reports whether byte b needs to be escaped by QuoteMeta. +func special(b byte) bool { + return b < utf8.RuneSelf && specialBytes[b%16]&(1<<(b/16)) != 0 +} + +func init() { + for _, b := range []byte(`\.+*?()|[]{}^$`) { + specialBytes[b%16] |= 1 << (b / 16) + } +} + +// QuoteMeta returns a string that escapes all regular expression metacharacters +// inside the argument text; the returned string is a regular expression matching +// the literal text. +func QuoteMeta(s string) string { + // A byte loop is correct because all metacharacters are ASCII. + var i int + for i = 0; i < len(s); i++ { + if special(s[i]) { + break + } + } + // No meta characters found, so return original string. + if i >= len(s) { + return s + } + + b := make([]byte, 2*len(s)-i) + copy(b, s[:i]) + j := i + for ; i < len(s); i++ { + if special(s[i]) { + b[j] = '\\' + j++ + } + b[j] = s[i] + j++ + } + return string(b[:j]) +} + +// The number of capture values in the program may correspond +// to fewer capturing expressions than are in the regexp. +// For example, "(a){0}" turns into an empty program, so the +// maximum capture in the program is 0 but we need to return +// an expression for \1. Pad appends -1s to the slice a as needed. +func (re *Regexp) pad(a []int) []int { + if a == nil { + // No match. + return nil + } + n := (1 + re.numSubexp) * 2 + for len(a) < n { + a = append(a, -1) + } + return a +} + +// allMatches calls deliver at most n times +// with the location of successive matches in the input text. +// The input text is b if non-nil, otherwise s. +func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) { + var end int + if b == nil { + end = len(s) + } else { + end = len(b) + } + + for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; { + matches := re.doExecute(nil, b, s, pos, re.prog.NumCap, nil) + if len(matches) == 0 { + break + } + + accept := true + if matches[1] == pos { + // We've found an empty match. + if matches[0] == prevMatchEnd { + // We don't allow an empty match right + // after a previous match, so ignore it. + accept = false + } + var width int + if b == nil { + is := inputString{str: s} + _, width = is.step(pos) + } else { + ib := inputBytes{str: b} + _, width = ib.step(pos) + } + if width > 0 { + pos += width + } else { + pos = end + 1 + } + } else { + pos = matches[1] + } + prevMatchEnd = matches[1] + + if accept { + deliver(re.pad(matches)) + i++ + } + } +} + +// Find returns a slice holding the text of the leftmost match in b of the regular expression. +// A return value of nil indicates no match. +func (re *Regexp) Find(b []byte) []byte { + var dstCap [2]int + a := re.doExecute(nil, b, "", 0, 2, dstCap[:0]) + if a == nil { + return nil + } + return b[a[0]:a[1]:a[1]] +} + +// FindIndex returns a two-element slice of integers defining the location of +// the leftmost match in b of the regular expression. The match itself is at +// b[loc[0]:loc[1]]. +// A return value of nil indicates no match. +func (re *Regexp) FindIndex(b []byte) (loc []int) { + a := re.doExecute(nil, b, "", 0, 2, nil) + if a == nil { + return nil + } + return a[0:2] +} + +// FindString returns a string holding the text of the leftmost match in s of the regular +// expression. If there is no match, the return value is an empty string, +// but it will also be empty if the regular expression successfully matches +// an empty string. Use [Regexp.FindStringIndex] or [Regexp.FindStringSubmatch] if it is +// necessary to distinguish these cases. +func (re *Regexp) FindString(s string) string { + var dstCap [2]int + a := re.doExecute(nil, nil, s, 0, 2, dstCap[:0]) + if a == nil { + return "" + } + return s[a[0]:a[1]] +} + +// FindStringIndex returns a two-element slice of integers defining the +// location of the leftmost match in s of the regular expression. The match +// itself is at s[loc[0]:loc[1]]. +// A return value of nil indicates no match. +func (re *Regexp) FindStringIndex(s string) (loc []int) { + a := re.doExecute(nil, nil, s, 0, 2, nil) + if a == nil { + return nil + } + return a[0:2] +} + +// FindReaderIndex returns a two-element slice of integers defining the +// location of the leftmost match of the regular expression in text read from +// the [io.RuneReader]. The match text was found in the input stream at +// byte offset loc[0] through loc[1]-1. +// A return value of nil indicates no match. +func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int) { + a := re.doExecute(r, nil, "", 0, 2, nil) + if a == nil { + return nil + } + return a[0:2] +} + +// FindSubmatch returns a slice of slices holding the text of the leftmost +// match of the regular expression in b and the matches, if any, of its +// subexpressions, as defined by the 'Submatch' descriptions in the package +// comment. +// A return value of nil indicates no match. +func (re *Regexp) FindSubmatch(b []byte) [][]byte { + var dstCap [4]int + a := re.doExecute(nil, b, "", 0, re.prog.NumCap, dstCap[:0]) + if a == nil { + return nil + } + ret := make([][]byte, 1+re.numSubexp) + for i := range ret { + if 2*i < len(a) && a[2*i] >= 0 { + ret[i] = b[a[2*i]:a[2*i+1]:a[2*i+1]] + } + } + return ret +} + +// Expand appends template to dst and returns the result; during the +// append, Expand replaces variables in the template with corresponding +// matches drawn from src. The match slice should have been returned by +// [Regexp.FindSubmatchIndex]. +// +// In the template, a variable is denoted by a substring of the form +// $name or ${name}, where name is a non-empty sequence of letters, +// digits, and underscores. A purely numeric name like $1 refers to +// the submatch with the corresponding index; other names refer to +// capturing parentheses named with the (?P...) syntax. A +// reference to an out of range or unmatched index or a name that is not +// present in the regular expression is replaced with an empty slice. +// +// In the $name form, name is taken to be as long as possible: $1x is +// equivalent to ${1x}, not ${1}x, and, $10 is equivalent to ${10}, not ${1}0. +// +// To insert a literal $ in the output, use $$ in the template. +func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte { + return re.expand(dst, string(template), src, "", match) +} + +// ExpandString is like [Regexp.Expand] but the template and source are strings. +// It appends to and returns a byte slice in order to give the calling +// code control over allocation. +func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte { + return re.expand(dst, template, nil, src, match) +} + +func (re *Regexp) expand(dst []byte, template string, bsrc []byte, src string, match []int) []byte { + for len(template) > 0 { + before, after, ok := strings.Cut(template, "$") + if !ok { + break + } + dst = append(dst, before...) + template = after + if template != "" && template[0] == '$' { + // Treat $$ as $. + dst = append(dst, '$') + template = template[1:] + continue + } + name, num, rest, ok := extract(template) + if !ok { + // Malformed; treat $ as raw text. + dst = append(dst, '$') + continue + } + template = rest + if num >= 0 { + if 2*num+1 < len(match) && match[2*num] >= 0 { + if bsrc != nil { + dst = append(dst, bsrc[match[2*num]:match[2*num+1]]...) + } else { + dst = append(dst, src[match[2*num]:match[2*num+1]]...) + } + } + } else { + for i, namei := range re.subexpNames { + if name == namei && 2*i+1 < len(match) && match[2*i] >= 0 { + if bsrc != nil { + dst = append(dst, bsrc[match[2*i]:match[2*i+1]]...) + } else { + dst = append(dst, src[match[2*i]:match[2*i+1]]...) + } + break + } + } + } + } + dst = append(dst, template...) + return dst +} + +// extract returns the name from a leading "name" or "{name}" in str. +// (The $ has already been removed by the caller.) +// If it is a number, extract returns num set to that number; otherwise num = -1. +func extract(str string) (name string, num int, rest string, ok bool) { + if str == "" { + return + } + brace := false + if str[0] == '{' { + brace = true + str = str[1:] + } + i := 0 + for i < len(str) { + rune, size := utf8.DecodeRuneInString(str[i:]) + if !unicode.IsLetter(rune) && !unicode.IsDigit(rune) && rune != '_' { + break + } + i += size + } + if i == 0 { + // empty name is not okay + return + } + name = str[:i] + if brace { + if i >= len(str) || str[i] != '}' { + // missing closing brace + return + } + i++ + } + + // Parse number. + num = 0 + for i := 0; i < len(name); i++ { + if name[i] < '0' || '9' < name[i] || num >= 1e8 { + num = -1 + break + } + num = num*10 + int(name[i]) - '0' + } + // Disallow leading zeros. + if name[0] == '0' && len(name) > 1 { + num = -1 + } + + rest = str[i:] + ok = true + return +} + +// FindSubmatchIndex returns a slice holding the index pairs identifying the +// leftmost match of the regular expression in b and the matches, if any, of +// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions +// in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindSubmatchIndex(b []byte) []int { + return re.pad(re.doExecute(nil, b, "", 0, re.prog.NumCap, nil)) +} + +// FindStringSubmatch returns a slice of strings holding the text of the +// leftmost match of the regular expression in s and the matches, if any, of +// its subexpressions, as defined by the 'Submatch' description in the +// package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindStringSubmatch(s string) []string { + var dstCap [4]int + a := re.doExecute(nil, nil, s, 0, re.prog.NumCap, dstCap[:0]) + if a == nil { + return nil + } + ret := make([]string, 1+re.numSubexp) + for i := range ret { + if 2*i < len(a) && a[2*i] >= 0 { + ret[i] = s[a[2*i]:a[2*i+1]] + } + } + return ret +} + +// FindStringSubmatchIndex returns a slice holding the index pairs +// identifying the leftmost match of the regular expression in s and the +// matches, if any, of its subexpressions, as defined by the 'Submatch' and +// 'Index' descriptions in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindStringSubmatchIndex(s string) []int { + return re.pad(re.doExecute(nil, nil, s, 0, re.prog.NumCap, nil)) +} + +// FindReaderSubmatchIndex returns a slice holding the index pairs +// identifying the leftmost match of the regular expression of text read by +// the [io.RuneReader], and the matches, if any, of its subexpressions, as defined +// by the 'Submatch' and 'Index' descriptions in the package comment. A +// return value of nil indicates no match. +func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int { + return re.pad(re.doExecute(r, nil, "", 0, re.prog.NumCap, nil)) +} + +const startSize = 10 // The size at which to start a slice in the 'All' routines. + +// FindAll is the 'All' version of [Regexp.Find]; it returns a slice of all successive +// matches of the expression, as defined by the 'All' description in the +// package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAll(b []byte, n int) [][]byte { + if n < 0 { + n = len(b) + 1 + } + var result [][]byte + re.allMatches("", b, n, func(match []int) { + if result == nil { + result = make([][]byte, 0, startSize) + } + result = append(result, b[match[0]:match[1]:match[1]]) + }) + return result +} + +// FindAllIndex is the 'All' version of [Regexp.FindIndex]; it returns a slice of all +// successive matches of the expression, as defined by the 'All' description +// in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllIndex(b []byte, n int) [][]int { + if n < 0 { + n = len(b) + 1 + } + var result [][]int + re.allMatches("", b, n, func(match []int) { + if result == nil { + result = make([][]int, 0, startSize) + } + result = append(result, match[0:2]) + }) + return result +} + +// FindAllString is the 'All' version of [Regexp.FindString]; it returns a slice of all +// successive matches of the expression, as defined by the 'All' description +// in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllString(s string, n int) []string { + if n < 0 { + n = len(s) + 1 + } + var result []string + re.allMatches(s, nil, n, func(match []int) { + if result == nil { + result = make([]string, 0, startSize) + } + result = append(result, s[match[0]:match[1]]) + }) + return result +} + +// FindAllStringIndex is the 'All' version of [Regexp.FindStringIndex]; it returns a +// slice of all successive matches of the expression, as defined by the 'All' +// description in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllStringIndex(s string, n int) [][]int { + if n < 0 { + n = len(s) + 1 + } + var result [][]int + re.allMatches(s, nil, n, func(match []int) { + if result == nil { + result = make([][]int, 0, startSize) + } + result = append(result, match[0:2]) + }) + return result +} + +// FindAllSubmatch is the 'All' version of [Regexp.FindSubmatch]; it returns a slice +// of all successive matches of the expression, as defined by the 'All' +// description in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte { + if n < 0 { + n = len(b) + 1 + } + var result [][][]byte + re.allMatches("", b, n, func(match []int) { + if result == nil { + result = make([][][]byte, 0, startSize) + } + slice := make([][]byte, len(match)/2) + for j := range slice { + if match[2*j] >= 0 { + slice[j] = b[match[2*j]:match[2*j+1]:match[2*j+1]] + } + } + result = append(result, slice) + }) + return result +} + +// FindAllSubmatchIndex is the 'All' version of [Regexp.FindSubmatchIndex]; it returns +// a slice of all successive matches of the expression, as defined by the +// 'All' description in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int { + if n < 0 { + n = len(b) + 1 + } + var result [][]int + re.allMatches("", b, n, func(match []int) { + if result == nil { + result = make([][]int, 0, startSize) + } + result = append(result, match) + }) + return result +} + +// FindAllStringSubmatch is the 'All' version of [Regexp.FindStringSubmatch]; it +// returns a slice of all successive matches of the expression, as defined by +// the 'All' description in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string { + if n < 0 { + n = len(s) + 1 + } + var result [][]string + re.allMatches(s, nil, n, func(match []int) { + if result == nil { + result = make([][]string, 0, startSize) + } + slice := make([]string, len(match)/2) + for j := range slice { + if match[2*j] >= 0 { + slice[j] = s[match[2*j]:match[2*j+1]] + } + } + result = append(result, slice) + }) + return result +} + +// FindAllStringSubmatchIndex is the 'All' version of +// [Regexp.FindStringSubmatchIndex]; it returns a slice of all successive matches of +// the expression, as defined by the 'All' description in the package +// comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int { + if n < 0 { + n = len(s) + 1 + } + var result [][]int + re.allMatches(s, nil, n, func(match []int) { + if result == nil { + result = make([][]int, 0, startSize) + } + result = append(result, match) + }) + return result +} + +// Split slices s into substrings separated by the expression and returns a slice of +// the substrings between those expression matches. +// +// The slice returned by this method consists of all the substrings of s +// not contained in the slice returned by [Regexp.FindAllString]. When called on an expression +// that contains no metacharacters, it is equivalent to [strings.SplitN]. +// +// Example: +// +// s := regexp.MustCompile("a*").Split("abaabaccadaaae", 5) +// // s: ["", "b", "b", "c", "cadaaae"] +// +// The count determines the number of substrings to return: +// - n > 0: at most n substrings; the last substring will be the unsplit remainder; +// - n == 0: the result is nil (zero substrings); +// - n < 0: all substrings. +func (re *Regexp) Split(s string, n int) []string { + + if n == 0 { + return nil + } + + if len(re.expr) > 0 && len(s) == 0 { + return []string{""} + } + + matches := re.FindAllStringIndex(s, n) + strings := make([]string, 0, len(matches)) + + beg := 0 + end := 0 + for _, match := range matches { + if n > 0 && len(strings) >= n-1 { + break + } + + end = match[0] + if match[1] != 0 { + strings = append(strings, s[beg:end]) + } + beg = match[1] + } + + if end != len(s) { + strings = append(strings, s[beg:]) + } + + return strings +} + +// MarshalText implements [encoding.TextMarshaler]. The output +// matches that of calling the [Regexp.String] method. +// +// Note that the output is lossy in some cases: This method does not indicate +// POSIX regular expressions (i.e. those compiled by calling [CompilePOSIX]), or +// those for which the [Regexp.Longest] method has been called. +func (re *Regexp) MarshalText() ([]byte, error) { + return []byte(re.String()), nil +} + +// UnmarshalText implements [encoding.TextUnmarshaler] by calling +// [Compile] on the encoded value. +func (re *Regexp) UnmarshalText(text []byte) error { + newRE, err := Compile(string(text)) + if err != nil { + return err + } + *re = *newRE + return nil +} diff --git a/contrib/go/_std_1.22/src/regexp/syntax/compile.go b/contrib/go/_std_1.23/src/regexp/syntax/compile.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/syntax/compile.go rename to contrib/go/_std_1.23/src/regexp/syntax/compile.go diff --git a/contrib/go/_std_1.23/src/regexp/syntax/doc.go b/contrib/go/_std_1.23/src/regexp/syntax/doc.go new file mode 100644 index 000000000000..877f1043ddda --- /dev/null +++ b/contrib/go/_std_1.23/src/regexp/syntax/doc.go @@ -0,0 +1,142 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by mksyntaxgo from the RE2 distribution. DO NOT EDIT. + +/* +Package syntax parses regular expressions into parse trees and compiles +parse trees into programs. Most clients of regular expressions will use the +facilities of package [regexp] (such as [regexp.Compile] and [regexp.Match]) instead of this package. + +# Syntax + +The regular expression syntax understood by this package when parsing with the [Perl] flag is as follows. +Parts of the syntax can be disabled by passing alternate flags to [Parse]. + +Single characters: + + . any character, possibly including newline (flag s=true) + [xyz] character class + [^xyz] negated character class + \d Perl character class + \D negated Perl character class + [[:alpha:]] ASCII character class + [[:^alpha:]] negated ASCII character class + \pN Unicode character class (one-letter name) + \p{Greek} Unicode character class + \PN negated Unicode character class (one-letter name) + \P{Greek} negated Unicode character class + +Composites: + + xy x followed by y + x|y x or y (prefer x) + +Repetitions: + + x* zero or more x, prefer more + x+ one or more x, prefer more + x? zero or one x, prefer one + x{n,m} n or n+1 or ... or m x, prefer more + x{n,} n or more x, prefer more + x{n} exactly n x + x*? zero or more x, prefer fewer + x+? one or more x, prefer fewer + x?? zero or one x, prefer zero + x{n,m}? n or n+1 or ... or m x, prefer fewer + x{n,}? n or more x, prefer fewer + x{n}? exactly n x + +Implementation restriction: The counting forms x{n,m}, x{n,}, and x{n} +reject forms that create a minimum or maximum repetition count above 1000. +Unlimited repetitions are not subject to this restriction. + +Grouping: + + (re) numbered capturing group (submatch) + (?Pre) named & numbered capturing group (submatch) + (?re) named & numbered capturing group (submatch) + (?:re) non-capturing group + (?flags) set flags within current group; non-capturing + (?flags:re) set flags during re; non-capturing + + Flag syntax is xyz (set) or -xyz (clear) or xy-z (set xy, clear z). The flags are: + + i case-insensitive (default false) + m multi-line mode: ^ and $ match begin/end line in addition to begin/end text (default false) + s let . match \n (default false) + U ungreedy: swap meaning of x* and x*?, x+ and x+?, etc (default false) + +Empty strings: + + ^ at beginning of text or line (flag m=true) + $ at end of text (like \z not \Z) or line (flag m=true) + \A at beginning of text + \b at ASCII word boundary (\w on one side and \W, \A, or \z on the other) + \B not at ASCII word boundary + \z at end of text + +Escape sequences: + + \a bell (== \007) + \f form feed (== \014) + \t horizontal tab (== \011) + \n newline (== \012) + \r carriage return (== \015) + \v vertical tab character (== \013) + \* literal *, for any punctuation character * + \123 octal character code (up to three digits) + \x7F hex character code (exactly two digits) + \x{10FFFF} hex character code + \Q...\E literal text ... even if ... has punctuation + +Character class elements: + + x single character + A-Z character range (inclusive) + \d Perl character class + [:foo:] ASCII character class foo + \p{Foo} Unicode character class Foo + \pF Unicode character class F (one-letter name) + +Named character classes as character class elements: + + [\d] digits (== \d) + [^\d] not digits (== \D) + [\D] not digits (== \D) + [^\D] not not digits (== \d) + [[:name:]] named ASCII class inside character class (== [:name:]) + [^[:name:]] named ASCII class inside negated character class (== [:^name:]) + [\p{Name}] named Unicode property inside character class (== \p{Name}) + [^\p{Name}] named Unicode property inside negated character class (== \P{Name}) + +Perl character classes (all ASCII-only): + + \d digits (== [0-9]) + \D not digits (== [^0-9]) + \s whitespace (== [\t\n\f\r ]) + \S not whitespace (== [^\t\n\f\r ]) + \w word characters (== [0-9A-Za-z_]) + \W not word characters (== [^0-9A-Za-z_]) + +ASCII character classes: + + [[:alnum:]] alphanumeric (== [0-9A-Za-z]) + [[:alpha:]] alphabetic (== [A-Za-z]) + [[:ascii:]] ASCII (== [\x00-\x7F]) + [[:blank:]] blank (== [\t ]) + [[:cntrl:]] control (== [\x00-\x1F\x7F]) + [[:digit:]] digits (== [0-9]) + [[:graph:]] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]) + [[:lower:]] lower case (== [a-z]) + [[:print:]] printable (== [ -~] == [ [:graph:]]) + [[:punct:]] punctuation (== [!-/:-@[-`{-~]) + [[:space:]] whitespace (== [\t\n\v\f\r ]) + [[:upper:]] upper case (== [A-Z]) + [[:word:]] word characters (== [0-9A-Za-z_]) + [[:xdigit:]] hex digit (== [0-9A-Fa-f]) + +Unicode character classes are those in [unicode.Categories] and [unicode.Scripts]. +*/ +package syntax diff --git a/contrib/go/_std_1.22/src/regexp/syntax/make_perl_groups.pl b/contrib/go/_std_1.23/src/regexp/syntax/make_perl_groups.pl similarity index 83% rename from contrib/go/_std_1.22/src/regexp/syntax/make_perl_groups.pl rename to contrib/go/_std_1.23/src/regexp/syntax/make_perl_groups.pl index 80a2c9ae6b9a..fafa41cf2cfa 100755 --- a/contrib/go/_std_1.22/src/regexp/syntax/make_perl_groups.pl +++ b/contrib/go/_std_1.23/src/regexp/syntax/make_perl_groups.pl @@ -11,7 +11,10 @@ # Perl about each letter from 0-128 and write down # its answer. -@posixclasses = ( +use strict; +use warnings; + +my @posixclasses = ( "[:alnum:]", "[:alpha:]", "[:ascii:]", @@ -28,13 +31,13 @@ "[:xdigit:]", ); -@perlclasses = ( +my @perlclasses = ( "\\d", "\\s", "\\w", ); -%overrides = ( +my %overrides = ( # Prior to Perl 5.18, \s did not match vertical tab. # RE2 preserves that original behaviour. "\\s:11" => 0, @@ -70,7 +73,7 @@ ($$@) } print "}\n\n"; my $n = @ranges; - $negname = $name; + my $negname = $name; if ($negname =~ /:/) { $negname =~ s/:/:^/; } else { @@ -97,13 +100,25 @@ ($@) my $count = @entries; } +# Prepare gofmt command +my $gofmt; + +if (@ARGV > 0 && $ARGV[0] =~ /\.go$/) { + # Send the output of gofmt to the given file + open($gofmt, '|-', 'gofmt >'.$ARGV[0]) or die; +} else { + open($gofmt, '|-', 'gofmt') or die; +} + +# Redirect STDOUT to gofmt input +select $gofmt; + print <perl_groups.go +// Code generated by make_perl_groups.pl; DO NOT EDIT. package syntax diff --git a/contrib/go/_std_1.22/src/regexp/syntax/op_string.go b/contrib/go/_std_1.23/src/regexp/syntax/op_string.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/syntax/op_string.go rename to contrib/go/_std_1.23/src/regexp/syntax/op_string.go diff --git a/contrib/go/_std_1.23/src/regexp/syntax/parse.go b/contrib/go/_std_1.23/src/regexp/syntax/parse.go new file mode 100644 index 000000000000..26242902f1eb --- /dev/null +++ b/contrib/go/_std_1.23/src/regexp/syntax/parse.go @@ -0,0 +1,2134 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syntax + +import ( + "sort" + "strings" + "unicode" + "unicode/utf8" +) + +// An Error describes a failure to parse a regular expression +// and gives the offending expression. +type Error struct { + Code ErrorCode + Expr string +} + +func (e *Error) Error() string { + return "error parsing regexp: " + e.Code.String() + ": `" + e.Expr + "`" +} + +// An ErrorCode describes a failure to parse a regular expression. +type ErrorCode string + +const ( + // Unexpected error + ErrInternalError ErrorCode = "regexp/syntax: internal error" + + // Parse errors + ErrInvalidCharClass ErrorCode = "invalid character class" + ErrInvalidCharRange ErrorCode = "invalid character class range" + ErrInvalidEscape ErrorCode = "invalid escape sequence" + ErrInvalidNamedCapture ErrorCode = "invalid named capture" + ErrInvalidPerlOp ErrorCode = "invalid or unsupported Perl syntax" + ErrInvalidRepeatOp ErrorCode = "invalid nested repetition operator" + ErrInvalidRepeatSize ErrorCode = "invalid repeat count" + ErrInvalidUTF8 ErrorCode = "invalid UTF-8" + ErrMissingBracket ErrorCode = "missing closing ]" + ErrMissingParen ErrorCode = "missing closing )" + ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator" + ErrTrailingBackslash ErrorCode = "trailing backslash at end of expression" + ErrUnexpectedParen ErrorCode = "unexpected )" + ErrNestingDepth ErrorCode = "expression nests too deeply" + ErrLarge ErrorCode = "expression too large" +) + +func (e ErrorCode) String() string { + return string(e) +} + +// Flags control the behavior of the parser and record information about regexp context. +type Flags uint16 + +const ( + FoldCase Flags = 1 << iota // case-insensitive match + Literal // treat pattern as literal string + ClassNL // allow character classes like [^a-z] and [[:space:]] to match newline + DotNL // allow . to match newline + OneLine // treat ^ and $ as only matching at beginning and end of text + NonGreedy // make repetition operators default to non-greedy + PerlX // allow Perl extensions + UnicodeGroups // allow \p{Han}, \P{Han} for Unicode group and negation + WasDollar // regexp OpEndText was $, not \z + Simple // regexp contains no counted repetition + + MatchNL = ClassNL | DotNL + + Perl = ClassNL | OneLine | PerlX | UnicodeGroups // as close to Perl as possible + POSIX Flags = 0 // POSIX syntax +) + +// Pseudo-ops for parsing stack. +const ( + opLeftParen = opPseudo + iota + opVerticalBar +) + +// maxHeight is the maximum height of a regexp parse tree. +// It is somewhat arbitrarily chosen, but the idea is to be large enough +// that no one will actually hit in real use but at the same time small enough +// that recursion on the Regexp tree will not hit the 1GB Go stack limit. +// The maximum amount of stack for a single recursive frame is probably +// closer to 1kB, so this could potentially be raised, but it seems unlikely +// that people have regexps nested even this deeply. +// We ran a test on Google's C++ code base and turned up only +// a single use case with depth > 100; it had depth 128. +// Using depth 1000 should be plenty of margin. +// As an optimization, we don't even bother calculating heights +// until we've allocated at least maxHeight Regexp structures. +const maxHeight = 1000 + +// maxSize is the maximum size of a compiled regexp in Insts. +// It too is somewhat arbitrarily chosen, but the idea is to be large enough +// to allow significant regexps while at the same time small enough that +// the compiled form will not take up too much memory. +// 128 MB is enough for a 3.3 million Inst structures, which roughly +// corresponds to a 3.3 MB regexp. +const ( + maxSize = 128 << 20 / instSize + instSize = 5 * 8 // byte, 2 uint32, slice is 5 64-bit words +) + +// maxRunes is the maximum number of runes allowed in a regexp tree +// counting the runes in all the nodes. +// Ignoring character classes p.numRunes is always less than the length of the regexp. +// Character classes can make it much larger: each \pL adds 1292 runes. +// 128 MB is enough for 32M runes, which is over 26k \pL instances. +// Note that repetitions do not make copies of the rune slices, +// so \pL{1000} is only one rune slice, not 1000. +// We could keep a cache of character classes we've seen, +// so that all the \pL we see use the same rune list, +// but that doesn't remove the problem entirely: +// consider something like [\pL01234][\pL01235][\pL01236]...[\pL^&*()]. +// And because the Rune slice is exposed directly in the Regexp, +// there is not an opportunity to change the representation to allow +// partial sharing between different character classes. +// So the limit is the best we can do. +const ( + maxRunes = 128 << 20 / runeSize + runeSize = 4 // rune is int32 +) + +type parser struct { + flags Flags // parse mode flags + stack []*Regexp // stack of parsed expressions + free *Regexp + numCap int // number of capturing groups seen + wholeRegexp string + tmpClass []rune // temporary char class work space + numRegexp int // number of regexps allocated + numRunes int // number of runes in char classes + repeats int64 // product of all repetitions seen + height map[*Regexp]int // regexp height, for height limit check + size map[*Regexp]int64 // regexp compiled size, for size limit check +} + +func (p *parser) newRegexp(op Op) *Regexp { + re := p.free + if re != nil { + p.free = re.Sub0[0] + *re = Regexp{} + } else { + re = new(Regexp) + p.numRegexp++ + } + re.Op = op + return re +} + +func (p *parser) reuse(re *Regexp) { + if p.height != nil { + delete(p.height, re) + } + re.Sub0[0] = p.free + p.free = re +} + +func (p *parser) checkLimits(re *Regexp) { + if p.numRunes > maxRunes { + panic(ErrLarge) + } + p.checkSize(re) + p.checkHeight(re) +} + +func (p *parser) checkSize(re *Regexp) { + if p.size == nil { + // We haven't started tracking size yet. + // Do a relatively cheap check to see if we need to start. + // Maintain the product of all the repeats we've seen + // and don't track if the total number of regexp nodes + // we've seen times the repeat product is in budget. + if p.repeats == 0 { + p.repeats = 1 + } + if re.Op == OpRepeat { + n := re.Max + if n == -1 { + n = re.Min + } + if n <= 0 { + n = 1 + } + if int64(n) > maxSize/p.repeats { + p.repeats = maxSize + } else { + p.repeats *= int64(n) + } + } + if int64(p.numRegexp) < maxSize/p.repeats { + return + } + + // We need to start tracking size. + // Make the map and belatedly populate it + // with info about everything we've constructed so far. + p.size = make(map[*Regexp]int64) + for _, re := range p.stack { + p.checkSize(re) + } + } + + if p.calcSize(re, true) > maxSize { + panic(ErrLarge) + } +} + +func (p *parser) calcSize(re *Regexp, force bool) int64 { + if !force { + if size, ok := p.size[re]; ok { + return size + } + } + + var size int64 + switch re.Op { + case OpLiteral: + size = int64(len(re.Rune)) + case OpCapture, OpStar: + // star can be 1+ or 2+; assume 2 pessimistically + size = 2 + p.calcSize(re.Sub[0], false) + case OpPlus, OpQuest: + size = 1 + p.calcSize(re.Sub[0], false) + case OpConcat: + for _, sub := range re.Sub { + size += p.calcSize(sub, false) + } + case OpAlternate: + for _, sub := range re.Sub { + size += p.calcSize(sub, false) + } + if len(re.Sub) > 1 { + size += int64(len(re.Sub)) - 1 + } + case OpRepeat: + sub := p.calcSize(re.Sub[0], false) + if re.Max == -1 { + if re.Min == 0 { + size = 2 + sub // x* + } else { + size = 1 + int64(re.Min)*sub // xxx+ + } + break + } + // x{2,5} = xx(x(x(x)?)?)? + size = int64(re.Max)*sub + int64(re.Max-re.Min) + } + + size = max(1, size) + p.size[re] = size + return size +} + +func (p *parser) checkHeight(re *Regexp) { + if p.numRegexp < maxHeight { + return + } + if p.height == nil { + p.height = make(map[*Regexp]int) + for _, re := range p.stack { + p.checkHeight(re) + } + } + if p.calcHeight(re, true) > maxHeight { + panic(ErrNestingDepth) + } +} + +func (p *parser) calcHeight(re *Regexp, force bool) int { + if !force { + if h, ok := p.height[re]; ok { + return h + } + } + h := 1 + for _, sub := range re.Sub { + hsub := p.calcHeight(sub, false) + if h < 1+hsub { + h = 1 + hsub + } + } + p.height[re] = h + return h +} + +// Parse stack manipulation. + +// push pushes the regexp re onto the parse stack and returns the regexp. +func (p *parser) push(re *Regexp) *Regexp { + p.numRunes += len(re.Rune) + if re.Op == OpCharClass && len(re.Rune) == 2 && re.Rune[0] == re.Rune[1] { + // Single rune. + if p.maybeConcat(re.Rune[0], p.flags&^FoldCase) { + return nil + } + re.Op = OpLiteral + re.Rune = re.Rune[:1] + re.Flags = p.flags &^ FoldCase + } else if re.Op == OpCharClass && len(re.Rune) == 4 && + re.Rune[0] == re.Rune[1] && re.Rune[2] == re.Rune[3] && + unicode.SimpleFold(re.Rune[0]) == re.Rune[2] && + unicode.SimpleFold(re.Rune[2]) == re.Rune[0] || + re.Op == OpCharClass && len(re.Rune) == 2 && + re.Rune[0]+1 == re.Rune[1] && + unicode.SimpleFold(re.Rune[0]) == re.Rune[1] && + unicode.SimpleFold(re.Rune[1]) == re.Rune[0] { + // Case-insensitive rune like [Aa] or [Δδ]. + if p.maybeConcat(re.Rune[0], p.flags|FoldCase) { + return nil + } + + // Rewrite as (case-insensitive) literal. + re.Op = OpLiteral + re.Rune = re.Rune[:1] + re.Flags = p.flags | FoldCase + } else { + // Incremental concatenation. + p.maybeConcat(-1, 0) + } + + p.stack = append(p.stack, re) + p.checkLimits(re) + return re +} + +// maybeConcat implements incremental concatenation +// of literal runes into string nodes. The parser calls this +// before each push, so only the top fragment of the stack +// might need processing. Since this is called before a push, +// the topmost literal is no longer subject to operators like * +// (Otherwise ab* would turn into (ab)*.) +// If r >= 0 and there's a node left over, maybeConcat uses it +// to push r with the given flags. +// maybeConcat reports whether r was pushed. +func (p *parser) maybeConcat(r rune, flags Flags) bool { + n := len(p.stack) + if n < 2 { + return false + } + + re1 := p.stack[n-1] + re2 := p.stack[n-2] + if re1.Op != OpLiteral || re2.Op != OpLiteral || re1.Flags&FoldCase != re2.Flags&FoldCase { + return false + } + + // Push re1 into re2. + re2.Rune = append(re2.Rune, re1.Rune...) + + // Reuse re1 if possible. + if r >= 0 { + re1.Rune = re1.Rune0[:1] + re1.Rune[0] = r + re1.Flags = flags + return true + } + + p.stack = p.stack[:n-1] + p.reuse(re1) + return false // did not push r +} + +// literal pushes a literal regexp for the rune r on the stack. +func (p *parser) literal(r rune) { + re := p.newRegexp(OpLiteral) + re.Flags = p.flags + if p.flags&FoldCase != 0 { + r = minFoldRune(r) + } + re.Rune0[0] = r + re.Rune = re.Rune0[:1] + p.push(re) +} + +// minFoldRune returns the minimum rune fold-equivalent to r. +func minFoldRune(r rune) rune { + if r < minFold || r > maxFold { + return r + } + m := r + r0 := r + for r = unicode.SimpleFold(r); r != r0; r = unicode.SimpleFold(r) { + m = min(m, r) + } + return m +} + +// op pushes a regexp with the given op onto the stack +// and returns that regexp. +func (p *parser) op(op Op) *Regexp { + re := p.newRegexp(op) + re.Flags = p.flags + return p.push(re) +} + +// repeat replaces the top stack element with itself repeated according to op, min, max. +// before is the regexp suffix starting at the repetition operator. +// after is the regexp suffix following after the repetition operator. +// repeat returns an updated 'after' and an error, if any. +func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (string, error) { + flags := p.flags + if p.flags&PerlX != 0 { + if len(after) > 0 && after[0] == '?' { + after = after[1:] + flags ^= NonGreedy + } + if lastRepeat != "" { + // In Perl it is not allowed to stack repetition operators: + // a** is a syntax error, not a doubled star, and a++ means + // something else entirely, which we don't support! + return "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(after)]} + } + } + n := len(p.stack) + if n == 0 { + return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]} + } + sub := p.stack[n-1] + if sub.Op >= opPseudo { + return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]} + } + + re := p.newRegexp(op) + re.Min = min + re.Max = max + re.Flags = flags + re.Sub = re.Sub0[:1] + re.Sub[0] = sub + p.stack[n-1] = re + p.checkLimits(re) + + if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) { + return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} + } + + return after, nil +} + +// repeatIsValid reports whether the repetition re is valid. +// Valid means that the combination of the top-level repetition +// and any inner repetitions does not exceed n copies of the +// innermost thing. +// This function rewalks the regexp tree and is called for every repetition, +// so we have to worry about inducing quadratic behavior in the parser. +// We avoid this by only calling repeatIsValid when min or max >= 2. +// In that case the depth of any >= 2 nesting can only get to 9 without +// triggering a parse error, so each subtree can only be rewalked 9 times. +func repeatIsValid(re *Regexp, n int) bool { + if re.Op == OpRepeat { + m := re.Max + if m == 0 { + return true + } + if m < 0 { + m = re.Min + } + if m > n { + return false + } + if m > 0 { + n /= m + } + } + for _, sub := range re.Sub { + if !repeatIsValid(sub, n) { + return false + } + } + return true +} + +// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation. +func (p *parser) concat() *Regexp { + p.maybeConcat(-1, 0) + + // Scan down to find pseudo-operator | or (. + i := len(p.stack) + for i > 0 && p.stack[i-1].Op < opPseudo { + i-- + } + subs := p.stack[i:] + p.stack = p.stack[:i] + + // Empty concatenation is special case. + if len(subs) == 0 { + return p.push(p.newRegexp(OpEmptyMatch)) + } + + return p.push(p.collapse(subs, OpConcat)) +} + +// alternate replaces the top of the stack (above the topmost '(') with its alternation. +func (p *parser) alternate() *Regexp { + // Scan down to find pseudo-operator (. + // There are no | above (. + i := len(p.stack) + for i > 0 && p.stack[i-1].Op < opPseudo { + i-- + } + subs := p.stack[i:] + p.stack = p.stack[:i] + + // Make sure top class is clean. + // All the others already are (see swapVerticalBar). + if len(subs) > 0 { + cleanAlt(subs[len(subs)-1]) + } + + // Empty alternate is special case + // (shouldn't happen but easy to handle). + if len(subs) == 0 { + return p.push(p.newRegexp(OpNoMatch)) + } + + return p.push(p.collapse(subs, OpAlternate)) +} + +// cleanAlt cleans re for eventual inclusion in an alternation. +func cleanAlt(re *Regexp) { + switch re.Op { + case OpCharClass: + re.Rune = cleanClass(&re.Rune) + if len(re.Rune) == 2 && re.Rune[0] == 0 && re.Rune[1] == unicode.MaxRune { + re.Rune = nil + re.Op = OpAnyChar + return + } + if len(re.Rune) == 4 && re.Rune[0] == 0 && re.Rune[1] == '\n'-1 && re.Rune[2] == '\n'+1 && re.Rune[3] == unicode.MaxRune { + re.Rune = nil + re.Op = OpAnyCharNotNL + return + } + if cap(re.Rune)-len(re.Rune) > 100 { + // re.Rune will not grow any more. + // Make a copy or inline to reclaim storage. + re.Rune = append(re.Rune0[:0], re.Rune...) + } + } +} + +// collapse returns the result of applying op to sub. +// If sub contains op nodes, they all get hoisted up +// so that there is never a concat of a concat or an +// alternate of an alternate. +func (p *parser) collapse(subs []*Regexp, op Op) *Regexp { + if len(subs) == 1 { + return subs[0] + } + re := p.newRegexp(op) + re.Sub = re.Sub0[:0] + for _, sub := range subs { + if sub.Op == op { + re.Sub = append(re.Sub, sub.Sub...) + p.reuse(sub) + } else { + re.Sub = append(re.Sub, sub) + } + } + if op == OpAlternate { + re.Sub = p.factor(re.Sub) + if len(re.Sub) == 1 { + old := re + re = re.Sub[0] + p.reuse(old) + } + } + return re +} + +// factor factors common prefixes from the alternation list sub. +// It returns a replacement list that reuses the same storage and +// frees (passes to p.reuse) any removed *Regexps. +// +// For example, +// +// ABC|ABD|AEF|BCX|BCY +// +// simplifies by literal prefix extraction to +// +// A(B(C|D)|EF)|BC(X|Y) +// +// which simplifies by character class introduction to +// +// A(B[CD]|EF)|BC[XY] +func (p *parser) factor(sub []*Regexp) []*Regexp { + if len(sub) < 2 { + return sub + } + + // Round 1: Factor out common literal prefixes. + var str []rune + var strflags Flags + start := 0 + out := sub[:0] + for i := 0; i <= len(sub); i++ { + // Invariant: the Regexps that were in sub[0:start] have been + // used or marked for reuse, and the slice space has been reused + // for out (len(out) <= start). + // + // Invariant: sub[start:i] consists of regexps that all begin + // with str as modified by strflags. + var istr []rune + var iflags Flags + if i < len(sub) { + istr, iflags = p.leadingString(sub[i]) + if iflags == strflags { + same := 0 + for same < len(str) && same < len(istr) && str[same] == istr[same] { + same++ + } + if same > 0 { + // Matches at least one rune in current range. + // Keep going around. + str = str[:same] + continue + } + } + } + + // Found end of a run with common leading literal string: + // sub[start:i] all begin with str[0:len(str)], but sub[i] + // does not even begin with str[0]. + // + // Factor out common string and append factored expression to out. + if i == start { + // Nothing to do - run of length 0. + } else if i == start+1 { + // Just one: don't bother factoring. + out = append(out, sub[start]) + } else { + // Construct factored form: prefix(suffix1|suffix2|...) + prefix := p.newRegexp(OpLiteral) + prefix.Flags = strflags + prefix.Rune = append(prefix.Rune[:0], str...) + + for j := start; j < i; j++ { + sub[j] = p.removeLeadingString(sub[j], len(str)) + p.checkLimits(sub[j]) + } + suffix := p.collapse(sub[start:i], OpAlternate) // recurse + + re := p.newRegexp(OpConcat) + re.Sub = append(re.Sub[:0], prefix, suffix) + out = append(out, re) + } + + // Prepare for next iteration. + start = i + str = istr + strflags = iflags + } + sub = out + + // Round 2: Factor out common simple prefixes, + // just the first piece of each concatenation. + // This will be good enough a lot of the time. + // + // Complex subexpressions (e.g. involving quantifiers) + // are not safe to factor because that collapses their + // distinct paths through the automaton, which affects + // correctness in some cases. + start = 0 + out = sub[:0] + var first *Regexp + for i := 0; i <= len(sub); i++ { + // Invariant: the Regexps that were in sub[0:start] have been + // used or marked for reuse, and the slice space has been reused + // for out (len(out) <= start). + // + // Invariant: sub[start:i] consists of regexps that all begin with ifirst. + var ifirst *Regexp + if i < len(sub) { + ifirst = p.leadingRegexp(sub[i]) + if first != nil && first.Equal(ifirst) && + // first must be a character class OR a fixed repeat of a character class. + (isCharClass(first) || (first.Op == OpRepeat && first.Min == first.Max && isCharClass(first.Sub[0]))) { + continue + } + } + + // Found end of a run with common leading regexp: + // sub[start:i] all begin with first but sub[i] does not. + // + // Factor out common regexp and append factored expression to out. + if i == start { + // Nothing to do - run of length 0. + } else if i == start+1 { + // Just one: don't bother factoring. + out = append(out, sub[start]) + } else { + // Construct factored form: prefix(suffix1|suffix2|...) + prefix := first + for j := start; j < i; j++ { + reuse := j != start // prefix came from sub[start] + sub[j] = p.removeLeadingRegexp(sub[j], reuse) + p.checkLimits(sub[j]) + } + suffix := p.collapse(sub[start:i], OpAlternate) // recurse + + re := p.newRegexp(OpConcat) + re.Sub = append(re.Sub[:0], prefix, suffix) + out = append(out, re) + } + + // Prepare for next iteration. + start = i + first = ifirst + } + sub = out + + // Round 3: Collapse runs of single literals into character classes. + start = 0 + out = sub[:0] + for i := 0; i <= len(sub); i++ { + // Invariant: the Regexps that were in sub[0:start] have been + // used or marked for reuse, and the slice space has been reused + // for out (len(out) <= start). + // + // Invariant: sub[start:i] consists of regexps that are either + // literal runes or character classes. + if i < len(sub) && isCharClass(sub[i]) { + continue + } + + // sub[i] is not a char or char class; + // emit char class for sub[start:i]... + if i == start { + // Nothing to do - run of length 0. + } else if i == start+1 { + out = append(out, sub[start]) + } else { + // Make new char class. + // Start with most complex regexp in sub[start]. + max := start + for j := start + 1; j < i; j++ { + if sub[max].Op < sub[j].Op || sub[max].Op == sub[j].Op && len(sub[max].Rune) < len(sub[j].Rune) { + max = j + } + } + sub[start], sub[max] = sub[max], sub[start] + + for j := start + 1; j < i; j++ { + mergeCharClass(sub[start], sub[j]) + p.reuse(sub[j]) + } + cleanAlt(sub[start]) + out = append(out, sub[start]) + } + + // ... and then emit sub[i]. + if i < len(sub) { + out = append(out, sub[i]) + } + start = i + 1 + } + sub = out + + // Round 4: Collapse runs of empty matches into a single empty match. + start = 0 + out = sub[:0] + for i := range sub { + if i+1 < len(sub) && sub[i].Op == OpEmptyMatch && sub[i+1].Op == OpEmptyMatch { + continue + } + out = append(out, sub[i]) + } + sub = out + + return sub +} + +// leadingString returns the leading literal string that re begins with. +// The string refers to storage in re or its children. +func (p *parser) leadingString(re *Regexp) ([]rune, Flags) { + if re.Op == OpConcat && len(re.Sub) > 0 { + re = re.Sub[0] + } + if re.Op != OpLiteral { + return nil, 0 + } + return re.Rune, re.Flags & FoldCase +} + +// removeLeadingString removes the first n leading runes +// from the beginning of re. It returns the replacement for re. +func (p *parser) removeLeadingString(re *Regexp, n int) *Regexp { + if re.Op == OpConcat && len(re.Sub) > 0 { + // Removing a leading string in a concatenation + // might simplify the concatenation. + sub := re.Sub[0] + sub = p.removeLeadingString(sub, n) + re.Sub[0] = sub + if sub.Op == OpEmptyMatch { + p.reuse(sub) + switch len(re.Sub) { + case 0, 1: + // Impossible but handle. + re.Op = OpEmptyMatch + re.Sub = nil + case 2: + old := re + re = re.Sub[1] + p.reuse(old) + default: + copy(re.Sub, re.Sub[1:]) + re.Sub = re.Sub[:len(re.Sub)-1] + } + } + return re + } + + if re.Op == OpLiteral { + re.Rune = re.Rune[:copy(re.Rune, re.Rune[n:])] + if len(re.Rune) == 0 { + re.Op = OpEmptyMatch + } + } + return re +} + +// leadingRegexp returns the leading regexp that re begins with. +// The regexp refers to storage in re or its children. +func (p *parser) leadingRegexp(re *Regexp) *Regexp { + if re.Op == OpEmptyMatch { + return nil + } + if re.Op == OpConcat && len(re.Sub) > 0 { + sub := re.Sub[0] + if sub.Op == OpEmptyMatch { + return nil + } + return sub + } + return re +} + +// removeLeadingRegexp removes the leading regexp in re. +// It returns the replacement for re. +// If reuse is true, it passes the removed regexp (if no longer needed) to p.reuse. +func (p *parser) removeLeadingRegexp(re *Regexp, reuse bool) *Regexp { + if re.Op == OpConcat && len(re.Sub) > 0 { + if reuse { + p.reuse(re.Sub[0]) + } + re.Sub = re.Sub[:copy(re.Sub, re.Sub[1:])] + switch len(re.Sub) { + case 0: + re.Op = OpEmptyMatch + re.Sub = nil + case 1: + old := re + re = re.Sub[0] + p.reuse(old) + } + return re + } + if reuse { + p.reuse(re) + } + return p.newRegexp(OpEmptyMatch) +} + +func literalRegexp(s string, flags Flags) *Regexp { + re := &Regexp{Op: OpLiteral} + re.Flags = flags + re.Rune = re.Rune0[:0] // use local storage for small strings + for _, c := range s { + if len(re.Rune) >= cap(re.Rune) { + // string is too long to fit in Rune0. let Go handle it + re.Rune = []rune(s) + break + } + re.Rune = append(re.Rune, c) + } + return re +} + +// Parsing. + +// Parse parses a regular expression string s, controlled by the specified +// Flags, and returns a regular expression parse tree. The syntax is +// described in the top-level comment. +func Parse(s string, flags Flags) (*Regexp, error) { + return parse(s, flags) +} + +func parse(s string, flags Flags) (_ *Regexp, err error) { + defer func() { + switch r := recover(); r { + default: + panic(r) + case nil: + // ok + case ErrLarge: // too big + err = &Error{Code: ErrLarge, Expr: s} + case ErrNestingDepth: + err = &Error{Code: ErrNestingDepth, Expr: s} + } + }() + + if flags&Literal != 0 { + // Trivial parser for literal string. + if err := checkUTF8(s); err != nil { + return nil, err + } + return literalRegexp(s, flags), nil + } + + // Otherwise, must do real work. + var ( + p parser + c rune + op Op + lastRepeat string + ) + p.flags = flags + p.wholeRegexp = s + t := s + for t != "" { + repeat := "" + BigSwitch: + switch t[0] { + default: + if c, t, err = nextRune(t); err != nil { + return nil, err + } + p.literal(c) + + case '(': + if p.flags&PerlX != 0 && len(t) >= 2 && t[1] == '?' { + // Flag changes and non-capturing groups. + if t, err = p.parsePerlFlags(t); err != nil { + return nil, err + } + break + } + p.numCap++ + p.op(opLeftParen).Cap = p.numCap + t = t[1:] + case '|': + p.parseVerticalBar() + t = t[1:] + case ')': + if err = p.parseRightParen(); err != nil { + return nil, err + } + t = t[1:] + case '^': + if p.flags&OneLine != 0 { + p.op(OpBeginText) + } else { + p.op(OpBeginLine) + } + t = t[1:] + case '$': + if p.flags&OneLine != 0 { + p.op(OpEndText).Flags |= WasDollar + } else { + p.op(OpEndLine) + } + t = t[1:] + case '.': + if p.flags&DotNL != 0 { + p.op(OpAnyChar) + } else { + p.op(OpAnyCharNotNL) + } + t = t[1:] + case '[': + if t, err = p.parseClass(t); err != nil { + return nil, err + } + case '*', '+', '?': + before := t + switch t[0] { + case '*': + op = OpStar + case '+': + op = OpPlus + case '?': + op = OpQuest + } + after := t[1:] + if after, err = p.repeat(op, 0, 0, before, after, lastRepeat); err != nil { + return nil, err + } + repeat = before + t = after + case '{': + op = OpRepeat + before := t + min, max, after, ok := p.parseRepeat(t) + if !ok { + // If the repeat cannot be parsed, { is a literal. + p.literal('{') + t = t[1:] + break + } + if min < 0 || min > 1000 || max > 1000 || max >= 0 && min > max { + // Numbers were too big, or max is present and min > max. + return nil, &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} + } + if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil { + return nil, err + } + repeat = before + t = after + case '\\': + if p.flags&PerlX != 0 && len(t) >= 2 { + switch t[1] { + case 'A': + p.op(OpBeginText) + t = t[2:] + break BigSwitch + case 'b': + p.op(OpWordBoundary) + t = t[2:] + break BigSwitch + case 'B': + p.op(OpNoWordBoundary) + t = t[2:] + break BigSwitch + case 'C': + // any byte; not supported + return nil, &Error{ErrInvalidEscape, t[:2]} + case 'Q': + // \Q ... \E: the ... is always literals + var lit string + lit, t, _ = strings.Cut(t[2:], `\E`) + for lit != "" { + c, rest, err := nextRune(lit) + if err != nil { + return nil, err + } + p.literal(c) + lit = rest + } + break BigSwitch + case 'z': + p.op(OpEndText) + t = t[2:] + break BigSwitch + } + } + + re := p.newRegexp(OpCharClass) + re.Flags = p.flags + + // Look for Unicode character group like \p{Han} + if len(t) >= 2 && (t[1] == 'p' || t[1] == 'P') { + r, rest, err := p.parseUnicodeClass(t, re.Rune0[:0]) + if err != nil { + return nil, err + } + if r != nil { + re.Rune = r + t = rest + p.push(re) + break BigSwitch + } + } + + // Perl character class escape. + if r, rest := p.parsePerlClassEscape(t, re.Rune0[:0]); r != nil { + re.Rune = r + t = rest + p.push(re) + break BigSwitch + } + p.reuse(re) + + // Ordinary single-character escape. + if c, t, err = p.parseEscape(t); err != nil { + return nil, err + } + p.literal(c) + } + lastRepeat = repeat + } + + p.concat() + if p.swapVerticalBar() { + // pop vertical bar + p.stack = p.stack[:len(p.stack)-1] + } + p.alternate() + + n := len(p.stack) + if n != 1 { + return nil, &Error{ErrMissingParen, s} + } + return p.stack[0], nil +} + +// parseRepeat parses {min} (max=min) or {min,} (max=-1) or {min,max}. +// If s is not of that form, it returns ok == false. +// If s has the right form but the values are too big, it returns min == -1, ok == true. +func (p *parser) parseRepeat(s string) (min, max int, rest string, ok bool) { + if s == "" || s[0] != '{' { + return + } + s = s[1:] + var ok1 bool + if min, s, ok1 = p.parseInt(s); !ok1 { + return + } + if s == "" { + return + } + if s[0] != ',' { + max = min + } else { + s = s[1:] + if s == "" { + return + } + if s[0] == '}' { + max = -1 + } else if max, s, ok1 = p.parseInt(s); !ok1 { + return + } else if max < 0 { + // parseInt found too big a number + min = -1 + } + } + if s == "" || s[0] != '}' { + return + } + rest = s[1:] + ok = true + return +} + +// parsePerlFlags parses a Perl flag setting or non-capturing group or both, +// like (?i) or (?: or (?i:. It removes the prefix from s and updates the parse state. +// The caller must have ensured that s begins with "(?". +func (p *parser) parsePerlFlags(s string) (rest string, err error) { + t := s + + // Check for named captures, first introduced in Python's regexp library. + // As usual, there are three slightly different syntaxes: + // + // (?Pexpr) the original, introduced by Python + // (?expr) the .NET alteration, adopted by Perl 5.10 + // (?'name'expr) another .NET alteration, adopted by Perl 5.10 + // + // Perl 5.10 gave in and implemented the Python version too, + // but they claim that the last two are the preferred forms. + // PCRE and languages based on it (specifically, PHP and Ruby) + // support all three as well. EcmaScript 4 uses only the Python form. + // + // In both the open source world (via Code Search) and the + // Google source tree, (?Pname) and (?name) are the + // dominant forms of named captures and both are supported. + startsWithP := len(t) > 4 && t[2] == 'P' && t[3] == '<' + startsWithName := len(t) > 3 && t[2] == '<' + + if startsWithP || startsWithName { + // position of expr start + exprStartPos := 4 + if startsWithName { + exprStartPos = 3 + } + + // Pull out name. + end := strings.IndexRune(t, '>') + if end < 0 { + if err = checkUTF8(t); err != nil { + return "", err + } + return "", &Error{ErrInvalidNamedCapture, s} + } + + capture := t[:end+1] // "(?P" or "(?" + name := t[exprStartPos:end] // "name" + if err = checkUTF8(name); err != nil { + return "", err + } + if !isValidCaptureName(name) { + return "", &Error{ErrInvalidNamedCapture, capture} + } + + // Like ordinary capture, but named. + p.numCap++ + re := p.op(opLeftParen) + re.Cap = p.numCap + re.Name = name + return t[end+1:], nil + } + + // Non-capturing group. Might also twiddle Perl flags. + var c rune + t = t[2:] // skip (? + flags := p.flags + sign := +1 + sawFlag := false +Loop: + for t != "" { + if c, t, err = nextRune(t); err != nil { + return "", err + } + switch c { + default: + break Loop + + // Flags. + case 'i': + flags |= FoldCase + sawFlag = true + case 'm': + flags &^= OneLine + sawFlag = true + case 's': + flags |= DotNL + sawFlag = true + case 'U': + flags |= NonGreedy + sawFlag = true + + // Switch to negation. + case '-': + if sign < 0 { + break Loop + } + sign = -1 + // Invert flags so that | above turn into &^ and vice versa. + // We'll invert flags again before using it below. + flags = ^flags + sawFlag = false + + // End of flags, starting group or not. + case ':', ')': + if sign < 0 { + if !sawFlag { + break Loop + } + flags = ^flags + } + if c == ':' { + // Open new group + p.op(opLeftParen) + } + p.flags = flags + return t, nil + } + } + + return "", &Error{ErrInvalidPerlOp, s[:len(s)-len(t)]} +} + +// isValidCaptureName reports whether name +// is a valid capture name: [A-Za-z0-9_]+. +// PCRE limits names to 32 bytes. +// Python rejects names starting with digits. +// We don't enforce either of those. +func isValidCaptureName(name string) bool { + if name == "" { + return false + } + for _, c := range name { + if c != '_' && !isalnum(c) { + return false + } + } + return true +} + +// parseInt parses a decimal integer. +func (p *parser) parseInt(s string) (n int, rest string, ok bool) { + if s == "" || s[0] < '0' || '9' < s[0] { + return + } + // Disallow leading zeros. + if len(s) >= 2 && s[0] == '0' && '0' <= s[1] && s[1] <= '9' { + return + } + t := s + for s != "" && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + rest = s + ok = true + // Have digits, compute value. + t = t[:len(t)-len(s)] + for i := 0; i < len(t); i++ { + // Avoid overflow. + if n >= 1e8 { + n = -1 + break + } + n = n*10 + int(t[i]) - '0' + } + return +} + +// can this be represented as a character class? +// single-rune literal string, char class, ., and .|\n. +func isCharClass(re *Regexp) bool { + return re.Op == OpLiteral && len(re.Rune) == 1 || + re.Op == OpCharClass || + re.Op == OpAnyCharNotNL || + re.Op == OpAnyChar +} + +// does re match r? +func matchRune(re *Regexp, r rune) bool { + switch re.Op { + case OpLiteral: + return len(re.Rune) == 1 && re.Rune[0] == r + case OpCharClass: + for i := 0; i < len(re.Rune); i += 2 { + if re.Rune[i] <= r && r <= re.Rune[i+1] { + return true + } + } + return false + case OpAnyCharNotNL: + return r != '\n' + case OpAnyChar: + return true + } + return false +} + +// parseVerticalBar handles a | in the input. +func (p *parser) parseVerticalBar() { + p.concat() + + // The concatenation we just parsed is on top of the stack. + // If it sits above an opVerticalBar, swap it below + // (things below an opVerticalBar become an alternation). + // Otherwise, push a new vertical bar. + if !p.swapVerticalBar() { + p.op(opVerticalBar) + } +} + +// mergeCharClass makes dst = dst|src. +// The caller must ensure that dst.Op >= src.Op, +// to reduce the amount of copying. +func mergeCharClass(dst, src *Regexp) { + switch dst.Op { + case OpAnyChar: + // src doesn't add anything. + case OpAnyCharNotNL: + // src might add \n + if matchRune(src, '\n') { + dst.Op = OpAnyChar + } + case OpCharClass: + // src is simpler, so either literal or char class + if src.Op == OpLiteral { + dst.Rune = appendLiteral(dst.Rune, src.Rune[0], src.Flags) + } else { + dst.Rune = appendClass(dst.Rune, src.Rune) + } + case OpLiteral: + // both literal + if src.Rune[0] == dst.Rune[0] && src.Flags == dst.Flags { + break + } + dst.Op = OpCharClass + dst.Rune = appendLiteral(dst.Rune[:0], dst.Rune[0], dst.Flags) + dst.Rune = appendLiteral(dst.Rune, src.Rune[0], src.Flags) + } +} + +// If the top of the stack is an element followed by an opVerticalBar +// swapVerticalBar swaps the two and returns true. +// Otherwise it returns false. +func (p *parser) swapVerticalBar() bool { + // If above and below vertical bar are literal or char class, + // can merge into a single char class. + n := len(p.stack) + if n >= 3 && p.stack[n-2].Op == opVerticalBar && isCharClass(p.stack[n-1]) && isCharClass(p.stack[n-3]) { + re1 := p.stack[n-1] + re3 := p.stack[n-3] + // Make re3 the more complex of the two. + if re1.Op > re3.Op { + re1, re3 = re3, re1 + p.stack[n-3] = re3 + } + mergeCharClass(re3, re1) + p.reuse(re1) + p.stack = p.stack[:n-1] + return true + } + + if n >= 2 { + re1 := p.stack[n-1] + re2 := p.stack[n-2] + if re2.Op == opVerticalBar { + if n >= 3 { + // Now out of reach. + // Clean opportunistically. + cleanAlt(p.stack[n-3]) + } + p.stack[n-2] = re1 + p.stack[n-1] = re2 + return true + } + } + return false +} + +// parseRightParen handles a ) in the input. +func (p *parser) parseRightParen() error { + p.concat() + if p.swapVerticalBar() { + // pop vertical bar + p.stack = p.stack[:len(p.stack)-1] + } + p.alternate() + + n := len(p.stack) + if n < 2 { + return &Error{ErrUnexpectedParen, p.wholeRegexp} + } + re1 := p.stack[n-1] + re2 := p.stack[n-2] + p.stack = p.stack[:n-2] + if re2.Op != opLeftParen { + return &Error{ErrUnexpectedParen, p.wholeRegexp} + } + // Restore flags at time of paren. + p.flags = re2.Flags + if re2.Cap == 0 { + // Just for grouping. + p.push(re1) + } else { + re2.Op = OpCapture + re2.Sub = re2.Sub0[:1] + re2.Sub[0] = re1 + p.push(re2) + } + return nil +} + +// parseEscape parses an escape sequence at the beginning of s +// and returns the rune. +func (p *parser) parseEscape(s string) (r rune, rest string, err error) { + t := s[1:] + if t == "" { + return 0, "", &Error{ErrTrailingBackslash, ""} + } + c, t, err := nextRune(t) + if err != nil { + return 0, "", err + } + +Switch: + switch c { + default: + if c < utf8.RuneSelf && !isalnum(c) { + // Escaped non-word characters are always themselves. + // PCRE is not quite so rigorous: it accepts things like + // \q, but we don't. We once rejected \_, but too many + // programs and people insist on using it, so allow \_. + return c, t, nil + } + + // Octal escapes. + case '1', '2', '3', '4', '5', '6', '7': + // Single non-zero digit is a backreference; not supported + if t == "" || t[0] < '0' || t[0] > '7' { + break + } + fallthrough + case '0': + // Consume up to three octal digits; already have one. + r = c - '0' + for i := 1; i < 3; i++ { + if t == "" || t[0] < '0' || t[0] > '7' { + break + } + r = r*8 + rune(t[0]) - '0' + t = t[1:] + } + return r, t, nil + + // Hexadecimal escapes. + case 'x': + if t == "" { + break + } + if c, t, err = nextRune(t); err != nil { + return 0, "", err + } + if c == '{' { + // Any number of digits in braces. + // Perl accepts any text at all; it ignores all text + // after the first non-hex digit. We require only hex digits, + // and at least one. + nhex := 0 + r = 0 + for { + if t == "" { + break Switch + } + if c, t, err = nextRune(t); err != nil { + return 0, "", err + } + if c == '}' { + break + } + v := unhex(c) + if v < 0 { + break Switch + } + r = r*16 + v + if r > unicode.MaxRune { + break Switch + } + nhex++ + } + if nhex == 0 { + break Switch + } + return r, t, nil + } + + // Easy case: two hex digits. + x := unhex(c) + if c, t, err = nextRune(t); err != nil { + return 0, "", err + } + y := unhex(c) + if x < 0 || y < 0 { + break + } + return x*16 + y, t, nil + + // C escapes. There is no case 'b', to avoid misparsing + // the Perl word-boundary \b as the C backspace \b + // when in POSIX mode. In Perl, /\b/ means word-boundary + // but /[\b]/ means backspace. We don't support that. + // If you want a backspace, embed a literal backspace + // character or use \x08. + case 'a': + return '\a', t, err + case 'f': + return '\f', t, err + case 'n': + return '\n', t, err + case 'r': + return '\r', t, err + case 't': + return '\t', t, err + case 'v': + return '\v', t, err + } + return 0, "", &Error{ErrInvalidEscape, s[:len(s)-len(t)]} +} + +// parseClassChar parses a character class character at the beginning of s +// and returns it. +func (p *parser) parseClassChar(s, wholeClass string) (r rune, rest string, err error) { + if s == "" { + return 0, "", &Error{Code: ErrMissingBracket, Expr: wholeClass} + } + + // Allow regular escape sequences even though + // many need not be escaped in this context. + if s[0] == '\\' { + return p.parseEscape(s) + } + + return nextRune(s) +} + +type charGroup struct { + sign int + class []rune +} + +//go:generate perl make_perl_groups.pl perl_groups.go + +// parsePerlClassEscape parses a leading Perl character class escape like \d +// from the beginning of s. If one is present, it appends the characters to r +// and returns the new slice r and the remainder of the string. +func (p *parser) parsePerlClassEscape(s string, r []rune) (out []rune, rest string) { + if p.flags&PerlX == 0 || len(s) < 2 || s[0] != '\\' { + return + } + g := perlGroup[s[0:2]] + if g.sign == 0 { + return + } + return p.appendGroup(r, g), s[2:] +} + +// parseNamedClass parses a leading POSIX named character class like [:alnum:] +// from the beginning of s. If one is present, it appends the characters to r +// and returns the new slice r and the remainder of the string. +func (p *parser) parseNamedClass(s string, r []rune) (out []rune, rest string, err error) { + if len(s) < 2 || s[0] != '[' || s[1] != ':' { + return + } + + i := strings.Index(s[2:], ":]") + if i < 0 { + return + } + i += 2 + name, s := s[0:i+2], s[i+2:] + g := posixGroup[name] + if g.sign == 0 { + return nil, "", &Error{ErrInvalidCharRange, name} + } + return p.appendGroup(r, g), s, nil +} + +func (p *parser) appendGroup(r []rune, g charGroup) []rune { + if p.flags&FoldCase == 0 { + if g.sign < 0 { + r = appendNegatedClass(r, g.class) + } else { + r = appendClass(r, g.class) + } + } else { + tmp := p.tmpClass[:0] + tmp = appendFoldedClass(tmp, g.class) + p.tmpClass = tmp + tmp = cleanClass(&p.tmpClass) + if g.sign < 0 { + r = appendNegatedClass(r, tmp) + } else { + r = appendClass(r, tmp) + } + } + return r +} + +var anyTable = &unicode.RangeTable{ + R16: []unicode.Range16{{Lo: 0, Hi: 1<<16 - 1, Stride: 1}}, + R32: []unicode.Range32{{Lo: 1 << 16, Hi: unicode.MaxRune, Stride: 1}}, +} + +// unicodeTable returns the unicode.RangeTable identified by name +// and the table of additional fold-equivalent code points. +func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) { + // Special case: "Any" means any. + if name == "Any" { + return anyTable, anyTable + } + if t := unicode.Categories[name]; t != nil { + return t, unicode.FoldCategory[name] + } + if t := unicode.Scripts[name]; t != nil { + return t, unicode.FoldScript[name] + } + return nil, nil +} + +// parseUnicodeClass parses a leading Unicode character class like \p{Han} +// from the beginning of s. If one is present, it appends the characters to r +// and returns the new slice r and the remainder of the string. +func (p *parser) parseUnicodeClass(s string, r []rune) (out []rune, rest string, err error) { + if p.flags&UnicodeGroups == 0 || len(s) < 2 || s[0] != '\\' || s[1] != 'p' && s[1] != 'P' { + return + } + + // Committed to parse or return error. + sign := +1 + if s[1] == 'P' { + sign = -1 + } + t := s[2:] + c, t, err := nextRune(t) + if err != nil { + return + } + var seq, name string + if c != '{' { + // Single-letter name. + seq = s[:len(s)-len(t)] + name = seq[2:] + } else { + // Name is in braces. + end := strings.IndexRune(s, '}') + if end < 0 { + if err = checkUTF8(s); err != nil { + return + } + return nil, "", &Error{ErrInvalidCharRange, s} + } + seq, t = s[:end+1], s[end+1:] + name = s[3:end] + if err = checkUTF8(name); err != nil { + return + } + } + + // Group can have leading negation too. \p{^Han} == \P{Han}, \P{^Han} == \p{Han}. + if name != "" && name[0] == '^' { + sign = -sign + name = name[1:] + } + + tab, fold := unicodeTable(name) + if tab == nil { + return nil, "", &Error{ErrInvalidCharRange, seq} + } + + if p.flags&FoldCase == 0 || fold == nil { + if sign > 0 { + r = appendTable(r, tab) + } else { + r = appendNegatedTable(r, tab) + } + } else { + // Merge and clean tab and fold in a temporary buffer. + // This is necessary for the negative case and just tidy + // for the positive case. + tmp := p.tmpClass[:0] + tmp = appendTable(tmp, tab) + tmp = appendTable(tmp, fold) + p.tmpClass = tmp + tmp = cleanClass(&p.tmpClass) + if sign > 0 { + r = appendClass(r, tmp) + } else { + r = appendNegatedClass(r, tmp) + } + } + return r, t, nil +} + +// parseClass parses a character class at the beginning of s +// and pushes it onto the parse stack. +func (p *parser) parseClass(s string) (rest string, err error) { + t := s[1:] // chop [ + re := p.newRegexp(OpCharClass) + re.Flags = p.flags + re.Rune = re.Rune0[:0] + + sign := +1 + if t != "" && t[0] == '^' { + sign = -1 + t = t[1:] + + // If character class does not match \n, add it here, + // so that negation later will do the right thing. + if p.flags&ClassNL == 0 { + re.Rune = append(re.Rune, '\n', '\n') + } + } + + class := re.Rune + first := true // ] and - are okay as first char in class + for t == "" || t[0] != ']' || first { + // POSIX: - is only okay unescaped as first or last in class. + // Perl: - is okay anywhere. + if t != "" && t[0] == '-' && p.flags&PerlX == 0 && !first && (len(t) == 1 || t[1] != ']') { + _, size := utf8.DecodeRuneInString(t[1:]) + return "", &Error{Code: ErrInvalidCharRange, Expr: t[:1+size]} + } + first = false + + // Look for POSIX [:alnum:] etc. + if len(t) > 2 && t[0] == '[' && t[1] == ':' { + nclass, nt, err := p.parseNamedClass(t, class) + if err != nil { + return "", err + } + if nclass != nil { + class, t = nclass, nt + continue + } + } + + // Look for Unicode character group like \p{Han}. + nclass, nt, err := p.parseUnicodeClass(t, class) + if err != nil { + return "", err + } + if nclass != nil { + class, t = nclass, nt + continue + } + + // Look for Perl character class symbols (extension). + if nclass, nt := p.parsePerlClassEscape(t, class); nclass != nil { + class, t = nclass, nt + continue + } + + // Single character or simple range. + rng := t + var lo, hi rune + if lo, t, err = p.parseClassChar(t, s); err != nil { + return "", err + } + hi = lo + // [a-] means (a|-) so check for final ]. + if len(t) >= 2 && t[0] == '-' && t[1] != ']' { + t = t[1:] + if hi, t, err = p.parseClassChar(t, s); err != nil { + return "", err + } + if hi < lo { + rng = rng[:len(rng)-len(t)] + return "", &Error{Code: ErrInvalidCharRange, Expr: rng} + } + } + if p.flags&FoldCase == 0 { + class = appendRange(class, lo, hi) + } else { + class = appendFoldedRange(class, lo, hi) + } + } + t = t[1:] // chop ] + + // Use &re.Rune instead of &class to avoid allocation. + re.Rune = class + class = cleanClass(&re.Rune) + if sign < 0 { + class = negateClass(class) + } + re.Rune = class + p.push(re) + return t, nil +} + +// cleanClass sorts the ranges (pairs of elements of r), +// merges them, and eliminates duplicates. +func cleanClass(rp *[]rune) []rune { + + // Sort by lo increasing, hi decreasing to break ties. + sort.Sort(ranges{rp}) + + r := *rp + if len(r) < 2 { + return r + } + + // Merge abutting, overlapping. + w := 2 // write index + for i := 2; i < len(r); i += 2 { + lo, hi := r[i], r[i+1] + if lo <= r[w-1]+1 { + // merge with previous range + if hi > r[w-1] { + r[w-1] = hi + } + continue + } + // new disjoint range + r[w] = lo + r[w+1] = hi + w += 2 + } + + return r[:w] +} + +// inCharClass reports whether r is in the class. +// It assumes the class has been cleaned by cleanClass. +func inCharClass(r rune, class []rune) bool { + _, ok := sort.Find(len(class)/2, func(i int) int { + lo, hi := class[2*i], class[2*i+1] + if r > hi { + return +1 + } + if r < lo { + return -1 + } + return 0 + }) + return ok +} + +// appendLiteral returns the result of appending the literal x to the class r. +func appendLiteral(r []rune, x rune, flags Flags) []rune { + if flags&FoldCase != 0 { + return appendFoldedRange(r, x, x) + } + return appendRange(r, x, x) +} + +// appendRange returns the result of appending the range lo-hi to the class r. +func appendRange(r []rune, lo, hi rune) []rune { + // Expand last range or next to last range if it overlaps or abuts. + // Checking two ranges helps when appending case-folded + // alphabets, so that one range can be expanding A-Z and the + // other expanding a-z. + n := len(r) + for i := 2; i <= 4; i += 2 { // twice, using i=2, i=4 + if n >= i { + rlo, rhi := r[n-i], r[n-i+1] + if lo <= rhi+1 && rlo <= hi+1 { + if lo < rlo { + r[n-i] = lo + } + if hi > rhi { + r[n-i+1] = hi + } + return r + } + } + } + + return append(r, lo, hi) +} + +const ( + // minimum and maximum runes involved in folding. + // checked during test. + minFold = 0x0041 + maxFold = 0x1e943 +) + +// appendFoldedRange returns the result of appending the range lo-hi +// and its case folding-equivalent runes to the class r. +func appendFoldedRange(r []rune, lo, hi rune) []rune { + // Optimizations. + if lo <= minFold && hi >= maxFold { + // Range is full: folding can't add more. + return appendRange(r, lo, hi) + } + if hi < minFold || lo > maxFold { + // Range is outside folding possibilities. + return appendRange(r, lo, hi) + } + if lo < minFold { + // [lo, minFold-1] needs no folding. + r = appendRange(r, lo, minFold-1) + lo = minFold + } + if hi > maxFold { + // [maxFold+1, hi] needs no folding. + r = appendRange(r, maxFold+1, hi) + hi = maxFold + } + + // Brute force. Depend on appendRange to coalesce ranges on the fly. + for c := lo; c <= hi; c++ { + r = appendRange(r, c, c) + f := unicode.SimpleFold(c) + for f != c { + r = appendRange(r, f, f) + f = unicode.SimpleFold(f) + } + } + return r +} + +// appendClass returns the result of appending the class x to the class r. +// It assume x is clean. +func appendClass(r []rune, x []rune) []rune { + for i := 0; i < len(x); i += 2 { + r = appendRange(r, x[i], x[i+1]) + } + return r +} + +// appendFoldedClass returns the result of appending the case folding of the class x to the class r. +func appendFoldedClass(r []rune, x []rune) []rune { + for i := 0; i < len(x); i += 2 { + r = appendFoldedRange(r, x[i], x[i+1]) + } + return r +} + +// appendNegatedClass returns the result of appending the negation of the class x to the class r. +// It assumes x is clean. +func appendNegatedClass(r []rune, x []rune) []rune { + nextLo := '\u0000' + for i := 0; i < len(x); i += 2 { + lo, hi := x[i], x[i+1] + if nextLo <= lo-1 { + r = appendRange(r, nextLo, lo-1) + } + nextLo = hi + 1 + } + if nextLo <= unicode.MaxRune { + r = appendRange(r, nextLo, unicode.MaxRune) + } + return r +} + +// appendTable returns the result of appending x to the class r. +func appendTable(r []rune, x *unicode.RangeTable) []rune { + for _, xr := range x.R16 { + lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride) + if stride == 1 { + r = appendRange(r, lo, hi) + continue + } + for c := lo; c <= hi; c += stride { + r = appendRange(r, c, c) + } + } + for _, xr := range x.R32 { + lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride) + if stride == 1 { + r = appendRange(r, lo, hi) + continue + } + for c := lo; c <= hi; c += stride { + r = appendRange(r, c, c) + } + } + return r +} + +// appendNegatedTable returns the result of appending the negation of x to the class r. +func appendNegatedTable(r []rune, x *unicode.RangeTable) []rune { + nextLo := '\u0000' // lo end of next class to add + for _, xr := range x.R16 { + lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride) + if stride == 1 { + if nextLo <= lo-1 { + r = appendRange(r, nextLo, lo-1) + } + nextLo = hi + 1 + continue + } + for c := lo; c <= hi; c += stride { + if nextLo <= c-1 { + r = appendRange(r, nextLo, c-1) + } + nextLo = c + 1 + } + } + for _, xr := range x.R32 { + lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride) + if stride == 1 { + if nextLo <= lo-1 { + r = appendRange(r, nextLo, lo-1) + } + nextLo = hi + 1 + continue + } + for c := lo; c <= hi; c += stride { + if nextLo <= c-1 { + r = appendRange(r, nextLo, c-1) + } + nextLo = c + 1 + } + } + if nextLo <= unicode.MaxRune { + r = appendRange(r, nextLo, unicode.MaxRune) + } + return r +} + +// negateClass overwrites r and returns r's negation. +// It assumes the class r is already clean. +func negateClass(r []rune) []rune { + nextLo := '\u0000' // lo end of next class to add + w := 0 // write index + for i := 0; i < len(r); i += 2 { + lo, hi := r[i], r[i+1] + if nextLo <= lo-1 { + r[w] = nextLo + r[w+1] = lo - 1 + w += 2 + } + nextLo = hi + 1 + } + r = r[:w] + if nextLo <= unicode.MaxRune { + // It's possible for the negation to have one more + // range - this one - than the original class, so use append. + r = append(r, nextLo, unicode.MaxRune) + } + return r +} + +// ranges implements sort.Interface on a []rune. +// The choice of receiver type definition is strange +// but avoids an allocation since we already have +// a *[]rune. +type ranges struct { + p *[]rune +} + +func (ra ranges) Less(i, j int) bool { + p := *ra.p + i *= 2 + j *= 2 + return p[i] < p[j] || p[i] == p[j] && p[i+1] > p[j+1] +} + +func (ra ranges) Len() int { + return len(*ra.p) / 2 +} + +func (ra ranges) Swap(i, j int) { + p := *ra.p + i *= 2 + j *= 2 + p[i], p[i+1], p[j], p[j+1] = p[j], p[j+1], p[i], p[i+1] +} + +func checkUTF8(s string) error { + for s != "" { + rune, size := utf8.DecodeRuneInString(s) + if rune == utf8.RuneError && size == 1 { + return &Error{Code: ErrInvalidUTF8, Expr: s} + } + s = s[size:] + } + return nil +} + +func nextRune(s string) (c rune, t string, err error) { + c, size := utf8.DecodeRuneInString(s) + if c == utf8.RuneError && size == 1 { + return 0, "", &Error{Code: ErrInvalidUTF8, Expr: s} + } + return c, s[size:], nil +} + +func isalnum(c rune) bool { + return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' +} + +func unhex(c rune) rune { + if '0' <= c && c <= '9' { + return c - '0' + } + if 'a' <= c && c <= 'f' { + return c - 'a' + 10 + } + if 'A' <= c && c <= 'F' { + return c - 'A' + 10 + } + return -1 +} diff --git a/contrib/go/_std_1.22/src/regexp/syntax/perl_groups.go b/contrib/go/_std_1.23/src/regexp/syntax/perl_groups.go similarity index 96% rename from contrib/go/_std_1.22/src/regexp/syntax/perl_groups.go rename to contrib/go/_std_1.23/src/regexp/syntax/perl_groups.go index effe4e686275..675466e5a0c3 100644 --- a/contrib/go/_std_1.22/src/regexp/syntax/perl_groups.go +++ b/contrib/go/_std_1.23/src/regexp/syntax/perl_groups.go @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// GENERATED BY make_perl_groups.pl; DO NOT EDIT. -// make_perl_groups.pl >perl_groups.go +// Code generated by make_perl_groups.pl; DO NOT EDIT. package syntax diff --git a/contrib/go/_std_1.22/src/regexp/syntax/prog.go b/contrib/go/_std_1.23/src/regexp/syntax/prog.go similarity index 97% rename from contrib/go/_std_1.22/src/regexp/syntax/prog.go rename to contrib/go/_std_1.23/src/regexp/syntax/prog.go index d69ae1a12d2d..6a3705ec8f90 100644 --- a/contrib/go/_std_1.22/src/regexp/syntax/prog.go +++ b/contrib/go/_std_1.23/src/regexp/syntax/prog.go @@ -191,7 +191,7 @@ Loop: const noMatch = -1 // MatchRune reports whether the instruction matches (and consumes) r. -// It should only be called when i.Op == InstRune. +// It should only be called when i.Op == [InstRune]. func (i *Inst) MatchRune(r rune) bool { return i.MatchRunePos(r) != noMatch } @@ -200,7 +200,7 @@ func (i *Inst) MatchRune(r rune) bool { // If so, MatchRunePos returns the index of the matching rune pair // (or, when len(i.Rune) == 1, rune singleton). // If not, MatchRunePos returns -1. -// MatchRunePos should only be called when i.Op == InstRune. +// MatchRunePos should only be called when i.Op == [InstRune]. func (i *Inst) MatchRunePos(r rune) int { rune := i.Rune @@ -262,7 +262,7 @@ func (i *Inst) MatchRunePos(r rune) int { // MatchEmptyWidth reports whether the instruction matches // an empty string between the runes before and after. -// It should only be called when i.Op == InstEmptyWidth. +// It should only be called when i.Op == [InstEmptyWidth]. func (i *Inst) MatchEmptyWidth(before rune, after rune) bool { switch EmptyOp(i.Arg) { case EmptyBeginLine: diff --git a/contrib/go/_std_1.23/src/regexp/syntax/regexp.go b/contrib/go/_std_1.23/src/regexp/syntax/regexp.go new file mode 100644 index 000000000000..f15d20512304 --- /dev/null +++ b/contrib/go/_std_1.23/src/regexp/syntax/regexp.go @@ -0,0 +1,464 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syntax + +// Note to implementers: +// In this package, re is always a *Regexp and r is always a rune. + +import ( + "slices" + "strconv" + "strings" + "unicode" +) + +// A Regexp is a node in a regular expression syntax tree. +type Regexp struct { + Op Op // operator + Flags Flags + Sub []*Regexp // subexpressions, if any + Sub0 [1]*Regexp // storage for short Sub + Rune []rune // matched runes, for OpLiteral, OpCharClass + Rune0 [2]rune // storage for short Rune + Min, Max int // min, max for OpRepeat + Cap int // capturing index, for OpCapture + Name string // capturing name, for OpCapture +} + +//go:generate stringer -type Op -trimprefix Op + +// An Op is a single regular expression operator. +type Op uint8 + +// Operators are listed in precedence order, tightest binding to weakest. +// Character class operators are listed simplest to most complex +// (OpLiteral, OpCharClass, OpAnyCharNotNL, OpAnyChar). + +const ( + OpNoMatch Op = 1 + iota // matches no strings + OpEmptyMatch // matches empty string + OpLiteral // matches Runes sequence + OpCharClass // matches Runes interpreted as range pair list + OpAnyCharNotNL // matches any character except newline + OpAnyChar // matches any character + OpBeginLine // matches empty string at beginning of line + OpEndLine // matches empty string at end of line + OpBeginText // matches empty string at beginning of text + OpEndText // matches empty string at end of text + OpWordBoundary // matches word boundary `\b` + OpNoWordBoundary // matches word non-boundary `\B` + OpCapture // capturing subexpression with index Cap, optional name Name + OpStar // matches Sub[0] zero or more times + OpPlus // matches Sub[0] one or more times + OpQuest // matches Sub[0] zero or one times + OpRepeat // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit) + OpConcat // matches concatenation of Subs + OpAlternate // matches alternation of Subs +) + +const opPseudo Op = 128 // where pseudo-ops start + +// Equal reports whether x and y have identical structure. +func (x *Regexp) Equal(y *Regexp) bool { + if x == nil || y == nil { + return x == y + } + if x.Op != y.Op { + return false + } + switch x.Op { + case OpEndText: + // The parse flags remember whether this is \z or \Z. + if x.Flags&WasDollar != y.Flags&WasDollar { + return false + } + + case OpLiteral, OpCharClass: + return slices.Equal(x.Rune, y.Rune) + + case OpAlternate, OpConcat: + return slices.EqualFunc(x.Sub, y.Sub, (*Regexp).Equal) + + case OpStar, OpPlus, OpQuest: + if x.Flags&NonGreedy != y.Flags&NonGreedy || !x.Sub[0].Equal(y.Sub[0]) { + return false + } + + case OpRepeat: + if x.Flags&NonGreedy != y.Flags&NonGreedy || x.Min != y.Min || x.Max != y.Max || !x.Sub[0].Equal(y.Sub[0]) { + return false + } + + case OpCapture: + if x.Cap != y.Cap || x.Name != y.Name || !x.Sub[0].Equal(y.Sub[0]) { + return false + } + } + return true +} + +// printFlags is a bit set indicating which flags (including non-capturing parens) to print around a regexp. +type printFlags uint8 + +const ( + flagI printFlags = 1 << iota // (?i: + flagM // (?m: + flagS // (?s: + flagOff // ) + flagPrec // (?: ) + negShift = 5 // flagI<") + case OpNoMatch: + b.WriteString(`[^\x00-\x{10FFFF}]`) + case OpEmptyMatch: + b.WriteString(`(?:)`) + case OpLiteral: + for _, r := range re.Rune { + escape(b, r, false) + } + case OpCharClass: + if len(re.Rune)%2 != 0 { + b.WriteString(`[invalid char class]`) + break + } + b.WriteRune('[') + if len(re.Rune) == 0 { + b.WriteString(`^\x00-\x{10FFFF}`) + } else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune && len(re.Rune) > 2 { + // Contains 0 and MaxRune. Probably a negated class. + // Print the gaps. + b.WriteRune('^') + for i := 1; i < len(re.Rune)-1; i += 2 { + lo, hi := re.Rune[i]+1, re.Rune[i+1]-1 + escape(b, lo, lo == '-') + if lo != hi { + if hi != lo+1 { + b.WriteRune('-') + } + escape(b, hi, hi == '-') + } + } + } else { + for i := 0; i < len(re.Rune); i += 2 { + lo, hi := re.Rune[i], re.Rune[i+1] + escape(b, lo, lo == '-') + if lo != hi { + if hi != lo+1 { + b.WriteRune('-') + } + escape(b, hi, hi == '-') + } + } + } + b.WriteRune(']') + case OpAnyCharNotNL, OpAnyChar: + b.WriteString(`.`) + case OpBeginLine: + b.WriteString(`^`) + case OpEndLine: + b.WriteString(`$`) + case OpBeginText: + b.WriteString(`\A`) + case OpEndText: + if re.Flags&WasDollar != 0 { + b.WriteString(`$`) + } else { + b.WriteString(`\z`) + } + case OpWordBoundary: + b.WriteString(`\b`) + case OpNoWordBoundary: + b.WriteString(`\B`) + case OpCapture: + if re.Name != "" { + b.WriteString(`(?P<`) + b.WriteString(re.Name) + b.WriteRune('>') + } else { + b.WriteRune('(') + } + if re.Sub[0].Op != OpEmptyMatch { + writeRegexp(b, re.Sub[0], flags[re.Sub[0]], flags) + } + b.WriteRune(')') + case OpStar, OpPlus, OpQuest, OpRepeat: + p := printFlags(0) + sub := re.Sub[0] + if sub.Op > OpCapture || sub.Op == OpLiteral && len(sub.Rune) > 1 { + p = flagPrec + } + writeRegexp(b, sub, p, flags) + + switch re.Op { + case OpStar: + b.WriteRune('*') + case OpPlus: + b.WriteRune('+') + case OpQuest: + b.WriteRune('?') + case OpRepeat: + b.WriteRune('{') + b.WriteString(strconv.Itoa(re.Min)) + if re.Max != re.Min { + b.WriteRune(',') + if re.Max >= 0 { + b.WriteString(strconv.Itoa(re.Max)) + } + } + b.WriteRune('}') + } + if re.Flags&NonGreedy != 0 { + b.WriteRune('?') + } + case OpConcat: + for _, sub := range re.Sub { + p := printFlags(0) + if sub.Op == OpAlternate { + p = flagPrec + } + writeRegexp(b, sub, p, flags) + } + case OpAlternate: + for i, sub := range re.Sub { + if i > 0 { + b.WriteRune('|') + } + writeRegexp(b, sub, 0, flags) + } + } +} + +func (re *Regexp) String() string { + var b strings.Builder + var flags map[*Regexp]printFlags + must, cant := calcFlags(re, &flags) + must |= (cant &^ flagI) << negShift + if must != 0 { + must |= flagOff + } + writeRegexp(&b, re, must, flags) + return b.String() +} + +const meta = `\.+*?()|[]{}^$` + +func escape(b *strings.Builder, r rune, force bool) { + if unicode.IsPrint(r) { + if strings.ContainsRune(meta, r) || force { + b.WriteRune('\\') + } + b.WriteRune(r) + return + } + + switch r { + case '\a': + b.WriteString(`\a`) + case '\f': + b.WriteString(`\f`) + case '\n': + b.WriteString(`\n`) + case '\r': + b.WriteString(`\r`) + case '\t': + b.WriteString(`\t`) + case '\v': + b.WriteString(`\v`) + default: + if r < 0x100 { + b.WriteString(`\x`) + s := strconv.FormatInt(int64(r), 16) + if len(s) == 1 { + b.WriteRune('0') + } + b.WriteString(s) + break + } + b.WriteString(`\x{`) + b.WriteString(strconv.FormatInt(int64(r), 16)) + b.WriteString(`}`) + } +} + +// MaxCap walks the regexp to find the maximum capture index. +func (re *Regexp) MaxCap() int { + m := 0 + if re.Op == OpCapture { + m = re.Cap + } + for _, sub := range re.Sub { + if n := sub.MaxCap(); m < n { + m = n + } + } + return m +} + +// CapNames walks the regexp to find the names of capturing groups. +func (re *Regexp) CapNames() []string { + names := make([]string, re.MaxCap()+1) + re.capNames(names) + return names +} + +func (re *Regexp) capNames(names []string) { + if re.Op == OpCapture { + names[re.Cap] = re.Name + } + for _, sub := range re.Sub { + sub.capNames(names) + } +} diff --git a/contrib/go/_std_1.22/src/regexp/syntax/simplify.go b/contrib/go/_std_1.23/src/regexp/syntax/simplify.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/syntax/simplify.go rename to contrib/go/_std_1.23/src/regexp/syntax/simplify.go diff --git a/contrib/go/_std_1.22/src/regexp/syntax/ya.make b/contrib/go/_std_1.23/src/regexp/syntax/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/regexp/syntax/ya.make rename to contrib/go/_std_1.23/src/regexp/syntax/ya.make diff --git a/contrib/go/_std_1.22/src/regexp/ya.make b/contrib/go/_std_1.23/src/regexp/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/regexp/ya.make rename to contrib/go/_std_1.23/src/regexp/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/HACKING.md b/contrib/go/_std_1.23/src/runtime/HACKING.md similarity index 99% rename from contrib/go/_std_1.22/src/runtime/HACKING.md rename to contrib/go/_std_1.23/src/runtime/HACKING.md index ce0b42a354ae..e1a43ba88e3d 100644 --- a/contrib/go/_std_1.22/src/runtime/HACKING.md +++ b/contrib/go/_std_1.23/src/runtime/HACKING.md @@ -173,7 +173,7 @@ In summary, Atomics ======= -The runtime uses its own atomics package at `runtime/internal/atomic`. +The runtime uses its own atomics package at `internal/runtime/atomic`. This corresponds to `sync/atomic`, but functions have different names for historical reasons and there are a few additional functions needed by the runtime. diff --git a/contrib/go/_std_1.22/src/runtime/Makefile b/contrib/go/_std_1.23/src/runtime/Makefile similarity index 100% rename from contrib/go/_std_1.22/src/runtime/Makefile rename to contrib/go/_std_1.23/src/runtime/Makefile diff --git a/contrib/go/_std_1.22/src/runtime/alg.go b/contrib/go/_std_1.23/src/runtime/alg.go similarity index 77% rename from contrib/go/_std_1.22/src/runtime/alg.go rename to contrib/go/_std_1.23/src/runtime/alg.go index ef4f859c231e..bfb9fa1d297b 100644 --- a/contrib/go/_std_1.22/src/runtime/alg.go +++ b/contrib/go/_std_1.23/src/runtime/alg.go @@ -45,9 +45,66 @@ func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr { var useAeshash bool // in asm_*.s + +// memhash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/aacfactory/fns +// - github.com/dgraph-io/ristretto +// - github.com/minio/simdjson-go +// - github.com/nbd-wtf/go-nostr +// - github.com/outcaste-io/ristretto +// - github.com/puzpuzpuz/xsync/v2 +// - github.com/puzpuzpuz/xsync/v3 +// - github.com/segmentio/parquet-go +// - github.com/parquet-go/parquet-go +// - github.com/authzed/spicedb +// - github.com/pingcap/badger +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memhash func memhash(p unsafe.Pointer, h, s uintptr) uintptr + +// memhash32 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/segmentio/parquet-go +// - github.com/parquet-go/parquet-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memhash32 func memhash32(p unsafe.Pointer, h uintptr) uintptr + +// memhash64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/segmentio/parquet-go +// - github.com/parquet-go/parquet-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memhash64 func memhash64(p unsafe.Pointer, h uintptr) uintptr + +// strhash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/aristanetworks/goarista +// - github.com/bytedance/sonic +// - github.com/bytedance/go-tagexpr/v2 +// - github.com/cloudwego/frugal +// - github.com/cloudwego/dynamicgo +// - github.com/v2fly/v2ray-core/v5 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname strhash func strhash(p unsafe.Pointer, h uintptr) uintptr func strhashFallback(a unsafe.Pointer, h uintptr) uintptr { @@ -100,7 +157,7 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr { if tab == nil { return h } - t := tab._type + t := tab.Type if t.Equal == nil { // Check hashability here. We could do this check inside // typehash, but we want to report the topmost type in @@ -115,6 +172,16 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr { } } +// nilinterhash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/anacrolix/stm +// - github.com/aristanetworks/goarista +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname nilinterhash func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { a := (*eface)(p) t := a._type @@ -142,6 +209,17 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { // maps generated by reflect.MapOf (reflect_typehash, below). // Note: this function must match the compiler generated // functions exactly. See issue 37716. +// +// typehash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/puzpuzpuz/xsync/v2 +// - github.com/puzpuzpuz/xsync/v3 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname typehash func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { if t.TFlag&abi.TFlagRegularMemory != 0 { // Handle ptr sizes specially, see issue 37086. @@ -154,30 +232,30 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { return memhash(p, h, t.Size_) } } - switch t.Kind_ & kindMask { - case kindFloat32: + switch t.Kind_ & abi.KindMask { + case abi.Float32: return f32hash(p, h) - case kindFloat64: + case abi.Float64: return f64hash(p, h) - case kindComplex64: + case abi.Complex64: return c64hash(p, h) - case kindComplex128: + case abi.Complex128: return c128hash(p, h) - case kindString: + case abi.String: return strhash(p, h) - case kindInterface: + case abi.Interface: i := (*interfacetype)(unsafe.Pointer(t)) if len(i.Methods) == 0 { return nilinterhash(p, h) } return interhash(p, h) - case kindArray: + case abi.Array: a := (*arraytype)(unsafe.Pointer(t)) for i := uintptr(0); i < a.Len; i++ { h = typehash(a.Elem, add(p, i*a.Elem.Size_), h) } return h - case kindStruct: + case abi.Struct: s := (*structtype)(unsafe.Pointer(t)) for _, f := range s.Fields { if f.Name.IsBlank() { @@ -204,10 +282,10 @@ func mapKeyError2(t *_type, p unsafe.Pointer) error { if t.TFlag&abi.TFlagRegularMemory != 0 { return nil } - switch t.Kind_ & kindMask { - case kindFloat32, kindFloat64, kindComplex64, kindComplex128, kindString: + switch t.Kind_ & abi.KindMask { + case abi.Float32, abi.Float64, abi.Complex64, abi.Complex128, abi.String: return nil - case kindInterface: + case abi.Interface: i := (*interfacetype)(unsafe.Pointer(t)) var t *_type var pdata *unsafe.Pointer @@ -223,7 +301,7 @@ func mapKeyError2(t *_type, p unsafe.Pointer) error { if a.tab == nil { return nil } - t = a.tab._type + t = a.tab.Type pdata = &a.data } @@ -236,7 +314,7 @@ func mapKeyError2(t *_type, p unsafe.Pointer) error { } else { return mapKeyError2(t, *pdata) } - case kindArray: + case abi.Array: a := (*arraytype)(unsafe.Pointer(t)) for i := uintptr(0); i < a.Len; i++ { if err := mapKeyError2(a.Elem, add(p, i*a.Elem.Size_)); err != nil { @@ -244,7 +322,7 @@ func mapKeyError2(t *_type, p unsafe.Pointer) error { } } return nil - case kindStruct: + case abi.Struct: s := (*structtype)(unsafe.Pointer(t)) for _, f := range s.Fields { if f.Name.IsBlank() { @@ -329,7 +407,7 @@ func ifaceeq(tab *itab, x, y unsafe.Pointer) bool { if tab == nil { return true } - t := tab._type + t := tab.Type eq := t.Equal if eq == nil { panic(errorString("comparing uncomparable type " + toRType(t).string())) @@ -342,6 +420,16 @@ func ifaceeq(tab *itab, x, y unsafe.Pointer) bool { } // Testing adapters for hash quality tests (see hash_test.go) +// +// stringHash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/k14s/starlark-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname stringHash func stringHash(s string, seed uintptr) uintptr { return strhash(noescape(unsafe.Pointer(&s)), seed) } @@ -391,7 +479,7 @@ func alginit() { return } for i := range hashkey { - hashkey[i] = uintptr(bootstrapRand()) | 1 // make sure these numbers are odd + hashkey[i] = uintptr(bootstrapRand()) } } diff --git a/contrib/go/_std_1.23/src/runtime/arena.go b/contrib/go/_std_1.23/src/runtime/arena.go new file mode 100644 index 000000000000..cd9a9dfae10a --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/arena.go @@ -0,0 +1,1122 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Implementation of (safe) user arenas. +// +// This file contains the implementation of user arenas wherein Go values can +// be manually allocated and freed in bulk. The act of manually freeing memory, +// potentially before a GC cycle, means that a garbage collection cycle can be +// delayed, improving efficiency by reducing GC cycle frequency. There are other +// potential efficiency benefits, such as improved locality and access to a more +// efficient allocation strategy. +// +// What makes the arenas here safe is that once they are freed, accessing the +// arena's memory will cause an explicit program fault, and the arena's address +// space will not be reused until no more pointers into it are found. There's one +// exception to this: if an arena allocated memory that isn't exhausted, it's placed +// back into a pool for reuse. This means that a crash is not always guaranteed. +// +// While this may seem unsafe, it still prevents memory corruption, and is in fact +// necessary in order to make new(T) a valid implementation of arenas. Such a property +// is desirable to allow for a trivial implementation. (It also avoids complexities +// that arise from synchronization with the GC when trying to set the arena chunks to +// fault while the GC is active.) +// +// The implementation works in layers. At the bottom, arenas are managed in chunks. +// Each chunk must be a multiple of the heap arena size, or the heap arena size must +// be divisible by the arena chunks. The address space for each chunk, and each +// corresponding heapArena for that address space, are eternally reserved for use as +// arena chunks. That is, they can never be used for the general heap. Each chunk +// is also represented by a single mspan, and is modeled as a single large heap +// allocation. It must be, because each chunk contains ordinary Go values that may +// point into the heap, so it must be scanned just like any other object. Any +// pointer into a chunk will therefore always cause the whole chunk to be scanned +// while its corresponding arena is still live. +// +// Chunks may be allocated either from new memory mapped by the OS on our behalf, +// or by reusing old freed chunks. When chunks are freed, their underlying memory +// is returned to the OS, set to fault on access, and may not be reused until the +// program doesn't point into the chunk anymore (the code refers to this state as +// "quarantined"), a property checked by the GC. +// +// The sweeper handles moving chunks out of this quarantine state to be ready for +// reuse. When the chunk is placed into the quarantine state, its corresponding +// span is marked as noscan so that the GC doesn't try to scan memory that would +// cause a fault. +// +// At the next layer are the user arenas themselves. They consist of a single +// active chunk which new Go values are bump-allocated into and a list of chunks +// that were exhausted when allocating into the arena. Once the arena is freed, +// it frees all full chunks it references, and places the active one onto a reuse +// list for a future arena to use. Each arena keeps its list of referenced chunks +// explicitly live until it is freed. Each user arena also maps to an object which +// has a finalizer attached that ensures the arena's chunks are all freed even if +// the arena itself is never explicitly freed. +// +// Pointer-ful memory is bump-allocated from low addresses to high addresses in each +// chunk, while pointer-free memory is bump-allocated from high address to low +// addresses. The reason for this is to take advantage of a GC optimization wherein +// the GC will stop scanning an object when there are no more pointers in it, which +// also allows us to elide clearing the heap bitmap for pointer-free Go values +// allocated into arenas. +// +// Note that arenas are not safe to use concurrently. +// +// In summary, there are 2 resources: arenas, and arena chunks. They exist in the +// following lifecycle: +// +// (1) A new arena is created via newArena. +// (2) Chunks are allocated to hold memory allocated into the arena with new or slice. +// (a) Chunks are first allocated from the reuse list of partially-used chunks. +// (b) If there are no such chunks, then chunks on the ready list are taken. +// (c) Failing all the above, memory for a new chunk is mapped. +// (3) The arena is freed, or all references to it are dropped, triggering its finalizer. +// (a) If the GC is not active, exhausted chunks are set to fault and placed on a +// quarantine list. +// (b) If the GC is active, exhausted chunks are placed on a fault list and will +// go through step (a) at a later point in time. +// (c) Any remaining partially-used chunk is placed on a reuse list. +// (4) Once no more pointers are found into quarantined arena chunks, the sweeper +// takes these chunks out of quarantine and places them on the ready list. + +package runtime + +import ( + "internal/abi" + "internal/goarch" + "internal/runtime/atomic" + "runtime/internal/math" + "runtime/internal/sys" + "unsafe" +) + +// Functions starting with arena_ are meant to be exported to downstream users +// of arenas. They should wrap these functions in a higher-lever API. +// +// The underlying arena and its resources are managed through an opaque unsafe.Pointer. + +// arena_newArena is a wrapper around newUserArena. +// +//go:linkname arena_newArena arena.runtime_arena_newArena +func arena_newArena() unsafe.Pointer { + return unsafe.Pointer(newUserArena()) +} + +// arena_arena_New is a wrapper around (*userArena).new, except that typ +// is an any (must be a *_type, still) and typ must be a type descriptor +// for a pointer to the type to actually be allocated, i.e. pass a *T +// to allocate a T. This is necessary because this function returns a *T. +// +//go:linkname arena_arena_New arena.runtime_arena_arena_New +func arena_arena_New(arena unsafe.Pointer, typ any) any { + t := (*_type)(efaceOf(&typ).data) + if t.Kind_&abi.KindMask != abi.Pointer { + throw("arena_New: non-pointer type") + } + te := (*ptrtype)(unsafe.Pointer(t)).Elem + x := ((*userArena)(arena)).new(te) + var result any + e := efaceOf(&result) + e._type = t + e.data = x + return result +} + +// arena_arena_Slice is a wrapper around (*userArena).slice. +// +//go:linkname arena_arena_Slice arena.runtime_arena_arena_Slice +func arena_arena_Slice(arena unsafe.Pointer, slice any, cap int) { + ((*userArena)(arena)).slice(slice, cap) +} + +// arena_arena_Free is a wrapper around (*userArena).free. +// +//go:linkname arena_arena_Free arena.runtime_arena_arena_Free +func arena_arena_Free(arena unsafe.Pointer) { + ((*userArena)(arena)).free() +} + +// arena_heapify takes a value that lives in an arena and makes a copy +// of it on the heap. Values that don't live in an arena are returned unmodified. +// +//go:linkname arena_heapify arena.runtime_arena_heapify +func arena_heapify(s any) any { + var v unsafe.Pointer + e := efaceOf(&s) + t := e._type + switch t.Kind_ & abi.KindMask { + case abi.String: + v = stringStructOf((*string)(e.data)).str + case abi.Slice: + v = (*slice)(e.data).array + case abi.Pointer: + v = e.data + default: + panic("arena: Clone only supports pointers, slices, and strings") + } + span := spanOf(uintptr(v)) + if span == nil || !span.isUserArenaChunk { + // Not stored in a user arena chunk. + return s + } + // Heap-allocate storage for a copy. + var x any + switch t.Kind_ & abi.KindMask { + case abi.String: + s1 := s.(string) + s2, b := rawstring(len(s1)) + copy(b, s1) + x = s2 + case abi.Slice: + len := (*slice)(e.data).len + et := (*slicetype)(unsafe.Pointer(t)).Elem + sl := new(slice) + *sl = slice{makeslicecopy(et, len, len, (*slice)(e.data).array), len, len} + xe := efaceOf(&x) + xe._type = t + xe.data = unsafe.Pointer(sl) + case abi.Pointer: + et := (*ptrtype)(unsafe.Pointer(t)).Elem + e2 := newobject(et) + typedmemmove(et, e2, e.data) + xe := efaceOf(&x) + xe._type = t + xe.data = e2 + } + return x +} + +const ( + // userArenaChunkBytes is the size of a user arena chunk. + userArenaChunkBytesMax = 8 << 20 + userArenaChunkBytes = uintptr(int64(userArenaChunkBytesMax-heapArenaBytes)&(int64(userArenaChunkBytesMax-heapArenaBytes)>>63) + heapArenaBytes) // min(userArenaChunkBytesMax, heapArenaBytes) + + // userArenaChunkPages is the number of pages a user arena chunk uses. + userArenaChunkPages = userArenaChunkBytes / pageSize + + // userArenaChunkMaxAllocBytes is the maximum size of an object that can + // be allocated from an arena. This number is chosen to cap worst-case + // fragmentation of user arenas to 25%. Larger allocations are redirected + // to the heap. + userArenaChunkMaxAllocBytes = userArenaChunkBytes / 4 +) + +func init() { + if userArenaChunkPages*pageSize != userArenaChunkBytes { + throw("user arena chunk size is not a multiple of the page size") + } + if userArenaChunkBytes%physPageSize != 0 { + throw("user arena chunk size is not a multiple of the physical page size") + } + if userArenaChunkBytes < heapArenaBytes { + if heapArenaBytes%userArenaChunkBytes != 0 { + throw("user arena chunk size is smaller than a heap arena, but doesn't divide it") + } + } else { + if userArenaChunkBytes%heapArenaBytes != 0 { + throw("user arena chunks size is larger than a heap arena, but not a multiple") + } + } + lockInit(&userArenaState.lock, lockRankUserArenaState) +} + +// userArenaChunkReserveBytes returns the amount of additional bytes to reserve for +// heap metadata. +func userArenaChunkReserveBytes() uintptr { + // In the allocation headers experiment, we reserve the end of the chunk for + // a pointer/scalar bitmap. We also reserve space for a dummy _type that + // refers to the bitmap. The PtrBytes field of the dummy _type indicates how + // many of those bits are valid. + return userArenaChunkBytes/goarch.PtrSize/8 + unsafe.Sizeof(_type{}) +} + +type userArena struct { + // fullList is a list of full chunks that have not enough free memory left, and + // that we'll free once this user arena is freed. + // + // Can't use mSpanList here because it's not-in-heap. + fullList *mspan + + // active is the user arena chunk we're currently allocating into. + active *mspan + + // refs is a set of references to the arena chunks so that they're kept alive. + // + // The last reference in the list always refers to active, while the rest of + // them correspond to fullList. Specifically, the head of fullList is the + // second-to-last one, fullList.next is the third-to-last, and so on. + // + // In other words, every time a new chunk becomes active, its appended to this + // list. + refs []unsafe.Pointer + + // defunct is true if free has been called on this arena. + // + // This is just a best-effort way to discover a concurrent allocation + // and free. Also used to detect a double-free. + defunct atomic.Bool +} + +// newUserArena creates a new userArena ready to be used. +func newUserArena() *userArena { + a := new(userArena) + SetFinalizer(a, func(a *userArena) { + // If arena handle is dropped without being freed, then call + // free on the arena, so the arena chunks are never reclaimed + // by the garbage collector. + a.free() + }) + a.refill() + return a +} + +// new allocates a new object of the provided type into the arena, and returns +// its pointer. +// +// This operation is not safe to call concurrently with other operations on the +// same arena. +func (a *userArena) new(typ *_type) unsafe.Pointer { + return a.alloc(typ, -1) +} + +// slice allocates a new slice backing store. slice must be a pointer to a slice +// (i.e. *[]T), because userArenaSlice will update the slice directly. +// +// cap determines the capacity of the slice backing store and must be non-negative. +// +// This operation is not safe to call concurrently with other operations on the +// same arena. +func (a *userArena) slice(sl any, cap int) { + if cap < 0 { + panic("userArena.slice: negative cap") + } + i := efaceOf(&sl) + typ := i._type + if typ.Kind_&abi.KindMask != abi.Pointer { + panic("slice result of non-ptr type") + } + typ = (*ptrtype)(unsafe.Pointer(typ)).Elem + if typ.Kind_&abi.KindMask != abi.Slice { + panic("slice of non-ptr-to-slice type") + } + typ = (*slicetype)(unsafe.Pointer(typ)).Elem + // t is now the element type of the slice we want to allocate. + + *((*slice)(i.data)) = slice{a.alloc(typ, cap), cap, cap} +} + +// free returns the userArena's chunks back to mheap and marks it as defunct. +// +// Must be called at most once for any given arena. +// +// This operation is not safe to call concurrently with other operations on the +// same arena. +func (a *userArena) free() { + // Check for a double-free. + if a.defunct.Load() { + panic("arena double free") + } + + // Mark ourselves as defunct. + a.defunct.Store(true) + SetFinalizer(a, nil) + + // Free all the full arenas. + // + // The refs on this list are in reverse order from the second-to-last. + s := a.fullList + i := len(a.refs) - 2 + for s != nil { + a.fullList = s.next + s.next = nil + freeUserArenaChunk(s, a.refs[i]) + s = a.fullList + i-- + } + if a.fullList != nil || i >= 0 { + // There's still something left on the full list, or we + // failed to actually iterate over the entire refs list. + throw("full list doesn't match refs list in length") + } + + // Put the active chunk onto the reuse list. + // + // Note that active's reference is always the last reference in refs. + s = a.active + if s != nil { + if raceenabled || msanenabled || asanenabled { + // Don't reuse arenas with sanitizers enabled. We want to catch + // any use-after-free errors aggressively. + freeUserArenaChunk(s, a.refs[len(a.refs)-1]) + } else { + lock(&userArenaState.lock) + userArenaState.reuse = append(userArenaState.reuse, liveUserArenaChunk{s, a.refs[len(a.refs)-1]}) + unlock(&userArenaState.lock) + } + } + // nil out a.active so that a race with freeing will more likely cause a crash. + a.active = nil + a.refs = nil +} + +// alloc reserves space in the current chunk or calls refill and reserves space +// in a new chunk. If cap is negative, the type will be taken literally, otherwise +// it will be considered as an element type for a slice backing store with capacity +// cap. +func (a *userArena) alloc(typ *_type, cap int) unsafe.Pointer { + s := a.active + var x unsafe.Pointer + for { + x = s.userArenaNextFree(typ, cap) + if x != nil { + break + } + s = a.refill() + } + return x +} + +// refill inserts the current arena chunk onto the full list and obtains a new +// one, either from the partial list or allocating a new one, both from mheap. +func (a *userArena) refill() *mspan { + // If there's an active chunk, assume it's full. + s := a.active + if s != nil { + if s.userArenaChunkFree.size() > userArenaChunkMaxAllocBytes { + // It's difficult to tell when we're actually out of memory + // in a chunk because the allocation that failed may still leave + // some free space available. However, that amount of free space + // should never exceed the maximum allocation size. + throw("wasted too much memory in an arena chunk") + } + s.next = a.fullList + a.fullList = s + a.active = nil + s = nil + } + var x unsafe.Pointer + + // Check the partially-used list. + lock(&userArenaState.lock) + if len(userArenaState.reuse) > 0 { + // Pick off the last arena chunk from the list. + n := len(userArenaState.reuse) - 1 + x = userArenaState.reuse[n].x + s = userArenaState.reuse[n].mspan + userArenaState.reuse[n].x = nil + userArenaState.reuse[n].mspan = nil + userArenaState.reuse = userArenaState.reuse[:n] + } + unlock(&userArenaState.lock) + if s == nil { + // Allocate a new one. + x, s = newUserArenaChunk() + if s == nil { + throw("out of memory") + } + } + a.refs = append(a.refs, x) + a.active = s + return s +} + +type liveUserArenaChunk struct { + *mspan // Must represent a user arena chunk. + + // Reference to mspan.base() to keep the chunk alive. + x unsafe.Pointer +} + +var userArenaState struct { + lock mutex + + // reuse contains a list of partially-used and already-live + // user arena chunks that can be quickly reused for another + // arena. + // + // Protected by lock. + reuse []liveUserArenaChunk + + // fault contains full user arena chunks that need to be faulted. + // + // Protected by lock. + fault []liveUserArenaChunk +} + +// userArenaNextFree reserves space in the user arena for an item of the specified +// type. If cap is not -1, this is for an array of cap elements of type t. +func (s *mspan) userArenaNextFree(typ *_type, cap int) unsafe.Pointer { + size := typ.Size_ + if cap > 0 { + if size > ^uintptr(0)/uintptr(cap) { + // Overflow. + throw("out of memory") + } + size *= uintptr(cap) + } + if size == 0 || cap == 0 { + return unsafe.Pointer(&zerobase) + } + if size > userArenaChunkMaxAllocBytes { + // Redirect allocations that don't fit into a chunk well directly + // from the heap. + if cap >= 0 { + return newarray(typ, cap) + } + return newobject(typ) + } + + // Prevent preemption as we set up the space for a new object. + // + // Act like we're allocating. + mp := acquirem() + if mp.mallocing != 0 { + throw("malloc deadlock") + } + if mp.gsignal == getg() { + throw("malloc during signal") + } + mp.mallocing = 1 + + var ptr unsafe.Pointer + if !typ.Pointers() { + // Allocate pointer-less objects from the tail end of the chunk. + v, ok := s.userArenaChunkFree.takeFromBack(size, typ.Align_) + if ok { + ptr = unsafe.Pointer(v) + } + } else { + v, ok := s.userArenaChunkFree.takeFromFront(size, typ.Align_) + if ok { + ptr = unsafe.Pointer(v) + } + } + if ptr == nil { + // Failed to allocate. + mp.mallocing = 0 + releasem(mp) + return nil + } + if s.needzero != 0 { + throw("arena chunk needs zeroing, but should already be zeroed") + } + // Set up heap bitmap and do extra accounting. + if typ.Pointers() { + if cap >= 0 { + userArenaHeapBitsSetSliceType(typ, cap, ptr, s) + } else { + userArenaHeapBitsSetType(typ, ptr, s) + } + c := getMCache(mp) + if c == nil { + throw("mallocgc called without a P or outside bootstrapping") + } + if cap > 0 { + c.scanAlloc += size - (typ.Size_ - typ.PtrBytes) + } else { + c.scanAlloc += typ.PtrBytes + } + } + + // Ensure that the stores above that initialize x to + // type-safe memory and set the heap bits occur before + // the caller can make ptr observable to the garbage + // collector. Otherwise, on weakly ordered machines, + // the garbage collector could follow a pointer to x, + // but see uninitialized memory or stale heap bits. + publicationBarrier() + + mp.mallocing = 0 + releasem(mp) + + return ptr +} + +// userArenaHeapBitsSetSliceType is the equivalent of heapBitsSetType but for +// Go slice backing store values allocated in a user arena chunk. It sets up the +// heap bitmap for n consecutive values with type typ allocated at address ptr. +func userArenaHeapBitsSetSliceType(typ *_type, n int, ptr unsafe.Pointer, s *mspan) { + mem, overflow := math.MulUintptr(typ.Size_, uintptr(n)) + if overflow || n < 0 || mem > maxAlloc { + panic(plainError("runtime: allocation size out of range")) + } + for i := 0; i < n; i++ { + userArenaHeapBitsSetType(typ, add(ptr, uintptr(i)*typ.Size_), s) + } +} + +// userArenaHeapBitsSetType is the equivalent of heapSetType but for +// non-slice-backing-store Go values allocated in a user arena chunk. It +// sets up the type metadata for the value with type typ allocated at address ptr. +// base is the base address of the arena chunk. +func userArenaHeapBitsSetType(typ *_type, ptr unsafe.Pointer, s *mspan) { + base := s.base() + h := s.writeUserArenaHeapBits(uintptr(ptr)) + + p := typ.GCData // start of 1-bit pointer mask (or GC program) + var gcProgBits uintptr + if typ.Kind_&abi.KindGCProg != 0 { + // Expand gc program, using the object itself for storage. + gcProgBits = runGCProg(addb(p, 4), (*byte)(ptr)) + p = (*byte)(ptr) + } + nb := typ.PtrBytes / goarch.PtrSize + + for i := uintptr(0); i < nb; i += ptrBits { + k := nb - i + if k > ptrBits { + k = ptrBits + } + // N.B. On big endian platforms we byte swap the data that we + // read from GCData, which is always stored in little-endian order + // by the compiler. writeUserArenaHeapBits handles data in + // a platform-ordered way for efficiency, but stores back the + // data in little endian order, since we expose the bitmap through + // a dummy type. + h = h.write(s, readUintptr(addb(p, i/8)), k) + } + // Note: we call pad here to ensure we emit explicit 0 bits + // for the pointerless tail of the object. This ensures that + // there's only a single noMorePtrs mark for the next object + // to clear. We don't need to do this to clear stale noMorePtrs + // markers from previous uses because arena chunk pointer bitmaps + // are always fully cleared when reused. + h = h.pad(s, typ.Size_-typ.PtrBytes) + h.flush(s, uintptr(ptr), typ.Size_) + + if typ.Kind_&abi.KindGCProg != 0 { + // Zero out temporary ptrmask buffer inside object. + memclrNoHeapPointers(ptr, (gcProgBits+7)/8) + } + + // Update the PtrBytes value in the type information. After this + // point, the GC will observe the new bitmap. + s.largeType.PtrBytes = uintptr(ptr) - base + typ.PtrBytes + + // Double-check that the bitmap was written out correctly. + const doubleCheck = false + if doubleCheck { + doubleCheckHeapPointersInterior(uintptr(ptr), uintptr(ptr), typ.Size_, typ.Size_, typ, &s.largeType, s) + } +} + +type writeUserArenaHeapBits struct { + offset uintptr // offset in span that the low bit of mask represents the pointer state of. + mask uintptr // some pointer bits starting at the address addr. + valid uintptr // number of bits in buf that are valid (including low) + low uintptr // number of low-order bits to not overwrite +} + +func (s *mspan) writeUserArenaHeapBits(addr uintptr) (h writeUserArenaHeapBits) { + offset := addr - s.base() + + // We start writing bits maybe in the middle of a heap bitmap word. + // Remember how many bits into the word we started, so we can be sure + // not to overwrite the previous bits. + h.low = offset / goarch.PtrSize % ptrBits + + // round down to heap word that starts the bitmap word. + h.offset = offset - h.low*goarch.PtrSize + + // We don't have any bits yet. + h.mask = 0 + h.valid = h.low + + return +} + +// write appends the pointerness of the next valid pointer slots +// using the low valid bits of bits. 1=pointer, 0=scalar. +func (h writeUserArenaHeapBits) write(s *mspan, bits, valid uintptr) writeUserArenaHeapBits { + if h.valid+valid <= ptrBits { + // Fast path - just accumulate the bits. + h.mask |= bits << h.valid + h.valid += valid + return h + } + // Too many bits to fit in this word. Write the current word + // out and move on to the next word. + + data := h.mask | bits<> (ptrBits - h.valid) // leftover for next word + h.valid += valid - ptrBits // have h.valid+valid bits, writing ptrBits of them + + // Flush mask to the memory bitmap. + idx := h.offset / (ptrBits * goarch.PtrSize) + m := uintptr(1)< ptrBits { + h = h.write(s, 0, ptrBits) + words -= ptrBits + } + return h.write(s, 0, words) +} + +// Flush the bits that have been written, and add zeros as needed +// to cover the full object [addr, addr+size). +func (h writeUserArenaHeapBits) flush(s *mspan, addr, size uintptr) { + offset := addr - s.base() + + // zeros counts the number of bits needed to represent the object minus the + // number of bits we've already written. This is the number of 0 bits + // that need to be added. + zeros := (offset+size-h.offset)/goarch.PtrSize - h.valid + + // Add zero bits up to the bitmap word boundary + if zeros > 0 { + z := ptrBits - h.valid + if z > zeros { + z = zeros + } + h.valid += z + zeros -= z + } + + // Find word in bitmap that we're going to write. + bitmap := s.heapBits() + idx := h.offset / (ptrBits * goarch.PtrSize) + + // Write remaining bits. + if h.valid != h.low { + m := uintptr(1)< 0 { + c := getMCache(mp) + if c == nil { + throw("newUserArenaChunk called without a P or outside bootstrapping") + } + // Note cache c only valid while m acquired; see #47302 + if rate != 1 && userArenaChunkBytes < c.nextSample { + c.nextSample -= userArenaChunkBytes + } else { + profilealloc(mp, unsafe.Pointer(span.base()), userArenaChunkBytes) + } + } + mp.mallocing = 0 + releasem(mp) + + // Again, because this chunk counts toward heapLive, potentially trigger a GC. + if t := (gcTrigger{kind: gcTriggerHeap}); t.test() { + gcStart(t) + } + + if debug.malloc { + if inittrace.active && inittrace.id == getg().goid { + // Init functions are executed sequentially in a single goroutine. + inittrace.bytes += uint64(userArenaChunkBytes) + } + } + + // Double-check it's aligned to the physical page size. Based on the current + // implementation this is trivially true, but it need not be in the future. + // However, if it's not aligned to the physical page size then we can't properly + // set it to fault later. + if uintptr(x)%physPageSize != 0 { + throw("user arena chunk is not aligned to the physical page size") + } + + return x, span +} + +// isUnusedUserArenaChunk indicates that the arena chunk has been set to fault +// and doesn't contain any scannable memory anymore. However, it might still be +// mSpanInUse as it sits on the quarantine list, since it needs to be swept. +// +// This is not safe to execute unless the caller has ownership of the mspan or +// the world is stopped (preemption is prevented while the relevant state changes). +// +// This is really only meant to be used by accounting tests in the runtime to +// distinguish when a span shouldn't be counted (since mSpanInUse might not be +// enough). +func (s *mspan) isUnusedUserArenaChunk() bool { + return s.isUserArenaChunk && s.spanclass == makeSpanClass(0, true) +} + +// setUserArenaChunkToFault sets the address space for the user arena chunk to fault +// and releases any underlying memory resources. +// +// Must be in a non-preemptible state to ensure the consistency of statistics +// exported to MemStats. +func (s *mspan) setUserArenaChunkToFault() { + if !s.isUserArenaChunk { + throw("invalid span in heapArena for user arena") + } + if s.npages*pageSize != userArenaChunkBytes { + throw("span on userArena.faultList has invalid size") + } + + // Update the span class to be noscan. What we want to happen is that + // any pointer into the span keeps it from getting recycled, so we want + // the mark bit to get set, but we're about to set the address space to fault, + // so we have to prevent the GC from scanning this memory. + // + // It's OK to set it here because (1) a GC isn't in progress, so the scanning code + // won't make a bad decision, (2) we're currently non-preemptible and in the runtime, + // so a GC is blocked from starting. We might race with sweeping, which could + // put it on the "wrong" sweep list, but really don't care because the chunk is + // treated as a large object span and there's no meaningful difference between scan + // and noscan large objects in the sweeper. The STW at the start of the GC acts as a + // barrier for this update. + s.spanclass = makeSpanClass(0, true) + + // Actually set the arena chunk to fault, so we'll get dangling pointer errors. + // sysFault currently uses a method on each OS that forces it to evacuate all + // memory backing the chunk. + sysFault(unsafe.Pointer(s.base()), s.npages*pageSize) + + // Everything on the list is counted as in-use, however sysFault transitions to + // Reserved, not Prepared, so we skip updating heapFree or heapReleased and just + // remove the memory from the total altogether; it's just address space now. + gcController.heapInUse.add(-int64(s.npages * pageSize)) + + // Count this as a free of an object right now as opposed to when + // the span gets off the quarantine list. The main reason is so that the + // amount of bytes allocated doesn't exceed how much is counted as + // "mapped ready," which could cause a deadlock in the pacer. + gcController.totalFree.Add(int64(s.elemsize)) + + // Update consistent stats to match. + // + // We're non-preemptible, so it's safe to update consistent stats (our P + // won't change out from under us). + stats := memstats.heapStats.acquire() + atomic.Xaddint64(&stats.committed, -int64(s.npages*pageSize)) + atomic.Xaddint64(&stats.inHeap, -int64(s.npages*pageSize)) + atomic.Xadd64(&stats.largeFreeCount, 1) + atomic.Xadd64(&stats.largeFree, int64(s.elemsize)) + memstats.heapStats.release() + + // This counts as a free, so update heapLive. + gcController.update(-int64(s.elemsize), 0) + + // Mark it as free for the race detector. + if raceenabled { + racefree(unsafe.Pointer(s.base()), s.elemsize) + } + + systemstack(func() { + // Add the user arena to the quarantine list. + lock(&mheap_.lock) + mheap_.userArena.quarantineList.insert(s) + unlock(&mheap_.lock) + }) +} + +// inUserArenaChunk returns true if p points to a user arena chunk. +func inUserArenaChunk(p uintptr) bool { + s := spanOf(p) + if s == nil { + return false + } + return s.isUserArenaChunk +} + +// freeUserArenaChunk releases the user arena represented by s back to the runtime. +// +// x must be a live pointer within s. +// +// The runtime will set the user arena to fault once it's safe (the GC is no longer running) +// and then once the user arena is no longer referenced by the application, will allow it to +// be reused. +func freeUserArenaChunk(s *mspan, x unsafe.Pointer) { + if !s.isUserArenaChunk { + throw("span is not for a user arena") + } + if s.npages*pageSize != userArenaChunkBytes { + throw("invalid user arena span size") + } + + // Mark the region as free to various sanitizers immediately instead + // of handling them at sweep time. + if raceenabled { + racefree(unsafe.Pointer(s.base()), s.elemsize) + } + if msanenabled { + msanfree(unsafe.Pointer(s.base()), s.elemsize) + } + if asanenabled { + asanpoison(unsafe.Pointer(s.base()), s.elemsize) + } + + // Make ourselves non-preemptible as we manipulate state and statistics. + // + // Also required by setUserArenaChunksToFault. + mp := acquirem() + + // We can only set user arenas to fault if we're in the _GCoff phase. + if gcphase == _GCoff { + lock(&userArenaState.lock) + faultList := userArenaState.fault + userArenaState.fault = nil + unlock(&userArenaState.lock) + + s.setUserArenaChunkToFault() + for _, lc := range faultList { + lc.mspan.setUserArenaChunkToFault() + } + + // Until the chunks are set to fault, keep them alive via the fault list. + KeepAlive(x) + KeepAlive(faultList) + } else { + // Put the user arena on the fault list. + lock(&userArenaState.lock) + userArenaState.fault = append(userArenaState.fault, liveUserArenaChunk{s, x}) + unlock(&userArenaState.lock) + } + releasem(mp) +} + +// allocUserArenaChunk attempts to reuse a free user arena chunk represented +// as a span. +// +// Must be in a non-preemptible state to ensure the consistency of statistics +// exported to MemStats. +// +// Acquires the heap lock. Must run on the system stack for that reason. +// +//go:systemstack +func (h *mheap) allocUserArenaChunk() *mspan { + var s *mspan + var base uintptr + + // First check the free list. + lock(&h.lock) + if !h.userArena.readyList.isEmpty() { + s = h.userArena.readyList.first + h.userArena.readyList.remove(s) + base = s.base() + } else { + // Free list was empty, so allocate a new arena. + hintList := &h.userArena.arenaHints + if raceenabled { + // In race mode just use the regular heap hints. We might fragment + // the address space, but the race detector requires that the heap + // is mapped contiguously. + hintList = &h.arenaHints + } + v, size := h.sysAlloc(userArenaChunkBytes, hintList, false) + if size%userArenaChunkBytes != 0 { + throw("sysAlloc size is not divisible by userArenaChunkBytes") + } + if size > userArenaChunkBytes { + // We got more than we asked for. This can happen if + // heapArenaSize > userArenaChunkSize, or if sysAlloc just returns + // some extra as a result of trying to find an aligned region. + // + // Divide it up and put it on the ready list. + for i := userArenaChunkBytes; i < size; i += userArenaChunkBytes { + s := h.allocMSpanLocked() + s.init(uintptr(v)+i, userArenaChunkPages) + h.userArena.readyList.insertBack(s) + } + size = userArenaChunkBytes + } + base = uintptr(v) + if base == 0 { + // Out of memory. + unlock(&h.lock) + return nil + } + s = h.allocMSpanLocked() + } + unlock(&h.lock) + + // sysAlloc returns Reserved address space, and any span we're + // reusing is set to fault (so, also Reserved), so transition + // it to Prepared and then Ready. + // + // Unlike (*mheap).grow, just map in everything that we + // asked for. We're likely going to use it all. + sysMap(unsafe.Pointer(base), userArenaChunkBytes, &gcController.heapReleased) + sysUsed(unsafe.Pointer(base), userArenaChunkBytes, userArenaChunkBytes) + + // Model the user arena as a heap span for a large object. + spc := makeSpanClass(0, false) + h.initSpan(s, spanAllocHeap, spc, base, userArenaChunkPages) + s.isUserArenaChunk = true + s.elemsize -= userArenaChunkReserveBytes() + s.limit = s.base() + s.elemsize + s.freeindex = 1 + s.allocCount = 1 + + // Account for this new arena chunk memory. + gcController.heapInUse.add(int64(userArenaChunkBytes)) + gcController.heapReleased.add(-int64(userArenaChunkBytes)) + + stats := memstats.heapStats.acquire() + atomic.Xaddint64(&stats.inHeap, int64(userArenaChunkBytes)) + atomic.Xaddint64(&stats.committed, int64(userArenaChunkBytes)) + + // Model the arena as a single large malloc. + atomic.Xadd64(&stats.largeAlloc, int64(s.elemsize)) + atomic.Xadd64(&stats.largeAllocCount, 1) + memstats.heapStats.release() + + // Count the alloc in inconsistent, internal stats. + gcController.totalAlloc.Add(int64(s.elemsize)) + + // Update heapLive. + gcController.update(int64(s.elemsize), 0) + + // This must clear the entire heap bitmap so that it's safe + // to allocate noscan data without writing anything out. + s.initHeapBits(true) + + // Clear the span preemptively. It's an arena chunk, so let's assume + // everything is going to be used. + // + // This also seems to make a massive difference as to whether or + // not Linux decides to back this memory with transparent huge + // pages. There's latency involved in this zeroing, but the hugepage + // gains are almost always worth it. Note: it's important that we + // clear even if it's freshly mapped and we know there's no point + // to zeroing as *that* is the critical signal to use huge pages. + memclrNoHeapPointers(unsafe.Pointer(s.base()), s.elemsize) + s.needzero = 0 + + s.freeIndexForScan = 1 + + // Set up the range for allocation. + s.userArenaChunkFree = makeAddrRange(base, base+s.elemsize) + + // Put the large span in the mcentral swept list so that it's + // visible to the background sweeper. + h.central[spc].mcentral.fullSwept(h.sweepgen).push(s) + + // Set up an allocation header. Avoid write barriers here because this type + // is not a real type, and it exists in an invalid location. + *(*uintptr)(unsafe.Pointer(&s.largeType)) = uintptr(unsafe.Pointer(s.limit)) + *(*uintptr)(unsafe.Pointer(&s.largeType.GCData)) = s.limit + unsafe.Sizeof(_type{}) + s.largeType.PtrBytes = 0 + s.largeType.Size_ = s.elemsize + + return s +} diff --git a/contrib/go/_std_1.23/src/runtime/asan.go b/contrib/go/_std_1.23/src/runtime/asan.go new file mode 100644 index 000000000000..d79637a334db --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/asan.go @@ -0,0 +1,69 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build asan + +package runtime + +import ( + "unsafe" +) + +// Public address sanitizer API. +func ASanRead(addr unsafe.Pointer, len int) { + sp := getcallersp() + pc := getcallerpc() + doasanread(addr, uintptr(len), sp, pc) +} + +func ASanWrite(addr unsafe.Pointer, len int) { + sp := getcallersp() + pc := getcallerpc() + doasanwrite(addr, uintptr(len), sp, pc) +} + +// Private interface for the runtime. +const asanenabled = true + +// asan{read,write} are nosplit because they may be called between +// fork and exec, when the stack must not grow. See issue #50391. + +//go:linkname asanread +//go:nosplit +func asanread(addr unsafe.Pointer, sz uintptr) { + sp := getcallersp() + pc := getcallerpc() + doasanread(addr, sz, sp, pc) +} + +//go:linkname asanwrite +//go:nosplit +func asanwrite(addr unsafe.Pointer, sz uintptr) { + sp := getcallersp() + pc := getcallerpc() + doasanwrite(addr, sz, sp, pc) +} + +//go:noescape +func doasanread(addr unsafe.Pointer, sz, sp, pc uintptr) + +//go:noescape +func doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr) + +//go:noescape +func asanunpoison(addr unsafe.Pointer, sz uintptr) + +//go:noescape +func asanpoison(addr unsafe.Pointer, sz uintptr) + +//go:noescape +func asanregisterglobals(addr unsafe.Pointer, n uintptr) + +// These are called from asan_GOARCH.s +// +//go:cgo_import_static __asan_read_go +//go:cgo_import_static __asan_write_go +//go:cgo_import_static __asan_unpoison_go +//go:cgo_import_static __asan_poison_go +//go:cgo_import_static __asan_register_globals_go diff --git a/contrib/go/_std_1.22/src/runtime/asan/asan.go b/contrib/go/_std_1.23/src/runtime/asan/asan.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asan/asan.go rename to contrib/go/_std_1.23/src/runtime/asan/asan.go diff --git a/contrib/go/_std_1.22/src/runtime/asan/ya.make b/contrib/go/_std_1.23/src/runtime/asan/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asan/ya.make rename to contrib/go/_std_1.23/src/runtime/asan/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/asan0.go b/contrib/go/_std_1.23/src/runtime/asan0.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asan0.go rename to contrib/go/_std_1.23/src/runtime/asan0.go diff --git a/contrib/go/_std_1.22/src/runtime/asan_amd64.s b/contrib/go/_std_1.23/src/runtime/asan_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asan_amd64.s rename to contrib/go/_std_1.23/src/runtime/asan_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/asan_arm64.s b/contrib/go/_std_1.23/src/runtime/asan_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asan_arm64.s rename to contrib/go/_std_1.23/src/runtime/asan_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/asan_loong64.s b/contrib/go/_std_1.23/src/runtime/asan_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asan_loong64.s rename to contrib/go/_std_1.23/src/runtime/asan_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/asan_ppc64le.s b/contrib/go/_std_1.23/src/runtime/asan_ppc64le.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asan_ppc64le.s rename to contrib/go/_std_1.23/src/runtime/asan_ppc64le.s diff --git a/contrib/go/_std_1.22/src/runtime/asan_riscv64.s b/contrib/go/_std_1.23/src/runtime/asan_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asan_riscv64.s rename to contrib/go/_std_1.23/src/runtime/asan_riscv64.s diff --git a/contrib/go/_std_1.23/src/runtime/asm.s b/contrib/go/_std_1.23/src/runtime/asm.s new file mode 100644 index 000000000000..f487e441009c --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/asm.s @@ -0,0 +1,15 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +#ifndef GOARCH_amd64 +TEXT ·sigpanic0(SB),NOSPLIT,$0-0 + JMP ·sigpanic(SB) +#endif + +// See map.go comment on the need for this routine. +TEXT ·mapinitnoop(SB),NOSPLIT,$0-0 + RET + diff --git a/contrib/go/_std_1.22/src/runtime/asm_386.s b/contrib/go/_std_1.23/src/runtime/asm_386.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/asm_386.s rename to contrib/go/_std_1.23/src/runtime/asm_386.s index 67ffc243539e..5aafe14be9a1 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_386.s +++ b/contrib/go/_std_1.23/src/runtime/asm_386.s @@ -398,6 +398,35 @@ bad: CALL AX INT $3 +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-4 + MOVL fn+0(FP), AX + + get_tls(CX) + MOVL g(CX), BX // BX = g + MOVL g_m(BX), DX // DX = curm + + // set g to gcrash + LEAL runtime·gcrash(SB), BX // g = &gcrash + MOVL DX, g_m(BX) // g.m = curm + MOVL BX, m_g0(DX) // curm.g0 = g + get_tls(CX) + MOVL BX, g(CX) + + // switch to crashstack + MOVL (g_stack+stack_hi)(BX), DX + SUBL $(4*8), DX + MOVL DX, SP + + // call target function + MOVL AX, DX + MOVL 0(AX), AX + CALL AX + + // should never return + CALL runtime·abort(SB) + UNDEF + /* * support for morestack */ @@ -408,11 +437,19 @@ bad: // the top of a stack (for example, morestack calling newstack // calling the scheduler calling newm calling gc), so we must // record an argument size. For that purpose, it has no arguments. -TEXT runtime·morestack(SB),NOSPLIT,$0-0 +TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 // Cannot grow scheduler stack (m->g0). get_tls(CX) - MOVL g(CX), BX - MOVL g_m(BX), BX + MOVL g(CX), DI + MOVL g_m(DI), BX + + // Set g->sched to context in f. + MOVL 0(SP), AX // f's PC + MOVL AX, (g_sched+gobuf_pc)(DI) + LEAL 4(SP), AX // f's SP + MOVL AX, (g_sched+gobuf_sp)(DI) + MOVL DX, (g_sched+gobuf_ctxt)(DI) + MOVL m_g0(BX), SI CMPL g(CX), SI JNE 3(PC) @@ -437,13 +474,6 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 MOVL g(CX), SI MOVL SI, (m_morebuf+gobuf_g)(BX) - // Set g->sched to context in f. - MOVL 0(SP), AX // f's PC - MOVL AX, (g_sched+gobuf_pc)(SI) - LEAL 4(SP), AX // f's SP - MOVL AX, (g_sched+gobuf_sp)(SI) - MOVL DX, (g_sched+gobuf_ctxt)(SI) - // Call newstack on m->g0's stack. MOVL m_g0(BX), BP MOVL BP, g(CX) diff --git a/contrib/go/_std_1.22/src/runtime/asm_amd64.h b/contrib/go/_std_1.23/src/runtime/asm_amd64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_amd64.h rename to contrib/go/_std_1.23/src/runtime/asm_amd64.h diff --git a/contrib/go/_std_1.23/src/runtime/asm_amd64.s b/contrib/go/_std_1.23/src/runtime/asm_amd64.s new file mode 100644 index 000000000000..cdf9874a7f93 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/asm_amd64.s @@ -0,0 +1,2143 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "go_tls.h" +#include "funcdata.h" +#include "textflag.h" +#include "cgo/abi_amd64.h" + +// _rt0_amd64 is common startup code for most amd64 systems when using +// internal linking. This is the entry point for the program from the +// kernel for an ordinary -buildmode=exe program. The stack holds the +// number of arguments and the C-style argv. +TEXT _rt0_amd64(SB),NOSPLIT,$-8 + MOVQ 0(SP), DI // argc + LEAQ 8(SP), SI // argv + JMP runtime·rt0_go(SB) + +// main is common startup code for most amd64 systems when using +// external linking. The C startup code will call the symbol "main" +// passing argc and argv in the usual C ABI registers DI and SI. +TEXT main(SB),NOSPLIT,$-8 + JMP runtime·rt0_go(SB) + +// _rt0_amd64_lib is common startup code for most amd64 systems when +// using -buildmode=c-archive or -buildmode=c-shared. The linker will +// arrange to invoke this function as a global constructor (for +// c-archive) or when the shared library is loaded (for c-shared). +// We expect argc and argv to be passed in the usual C ABI registers +// DI and SI. +TEXT _rt0_amd64_lib(SB),NOSPLIT|NOFRAME,$0 + // Transition from C ABI to Go ABI. + PUSH_REGS_HOST_TO_ABI0() + + MOVQ DI, _rt0_amd64_lib_argc<>(SB) + MOVQ SI, _rt0_amd64_lib_argv<>(SB) + + // Synchronous initialization. + CALL runtime·libpreinit(SB) + + // Create a new thread to finish Go runtime initialization. + MOVQ _cgo_sys_thread_create(SB), AX + TESTQ AX, AX + JZ nocgo + + // We're calling back to C. + // Align stack per ELF ABI requirements. + MOVQ SP, BX // Callee-save in C ABI + ANDQ $~15, SP + MOVQ $_rt0_amd64_lib_go(SB), DI + MOVQ $0, SI + CALL AX + MOVQ BX, SP + JMP restore + +nocgo: + ADJSP $16 + MOVQ $0x800000, 0(SP) // stacksize + MOVQ $_rt0_amd64_lib_go(SB), AX + MOVQ AX, 8(SP) // fn + CALL runtime·newosproc0(SB) + ADJSP $-16 + +restore: + POP_REGS_HOST_TO_ABI0() + RET + +// _rt0_amd64_lib_go initializes the Go runtime. +// This is started in a separate thread by _rt0_amd64_lib. +TEXT _rt0_amd64_lib_go(SB),NOSPLIT,$0 + MOVQ _rt0_amd64_lib_argc<>(SB), DI + MOVQ _rt0_amd64_lib_argv<>(SB), SI + JMP runtime·rt0_go(SB) + +DATA _rt0_amd64_lib_argc<>(SB)/8, $0 +GLOBL _rt0_amd64_lib_argc<>(SB),NOPTR, $8 +DATA _rt0_amd64_lib_argv<>(SB)/8, $0 +GLOBL _rt0_amd64_lib_argv<>(SB),NOPTR, $8 + +#ifdef GOAMD64_v2 +DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v2 microarchitecture support.\n" +#endif + +#ifdef GOAMD64_v3 +DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v3 microarchitecture support.\n" +#endif + +#ifdef GOAMD64_v4 +DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v4 microarchitecture support.\n" +#endif + +GLOBL bad_cpu_msg<>(SB), RODATA, $84 + +// Define a list of AMD64 microarchitecture level features +// https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels + + // SSE3 SSSE3 CMPXCHNG16 SSE4.1 SSE4.2 POPCNT +#define V2_FEATURES_CX (1 << 0 | 1 << 9 | 1 << 13 | 1 << 19 | 1 << 20 | 1 << 23) + // LAHF/SAHF +#define V2_EXT_FEATURES_CX (1 << 0) + // FMA MOVBE OSXSAVE AVX F16C +#define V3_FEATURES_CX (V2_FEATURES_CX | 1 << 12 | 1 << 22 | 1 << 27 | 1 << 28 | 1 << 29) + // ABM (FOR LZNCT) +#define V3_EXT_FEATURES_CX (V2_EXT_FEATURES_CX | 1 << 5) + // BMI1 AVX2 BMI2 +#define V3_EXT_FEATURES_BX (1 << 3 | 1 << 5 | 1 << 8) + // XMM YMM +#define V3_OS_SUPPORT_AX (1 << 1 | 1 << 2) + +#define V4_FEATURES_CX V3_FEATURES_CX + +#define V4_EXT_FEATURES_CX V3_EXT_FEATURES_CX + // AVX512F AVX512DQ AVX512CD AVX512BW AVX512VL +#define V4_EXT_FEATURES_BX (V3_EXT_FEATURES_BX | 1 << 16 | 1 << 17 | 1 << 28 | 1 << 30 | 1 << 31) + // OPMASK ZMM +#define V4_OS_SUPPORT_AX (V3_OS_SUPPORT_AX | 1 << 5 | (1 << 6 | 1 << 7)) + +#ifdef GOAMD64_v2 +#define NEED_MAX_CPUID 0x80000001 +#define NEED_FEATURES_CX V2_FEATURES_CX +#define NEED_EXT_FEATURES_CX V2_EXT_FEATURES_CX +#endif + +#ifdef GOAMD64_v3 +#define NEED_MAX_CPUID 0x80000001 +#define NEED_FEATURES_CX V3_FEATURES_CX +#define NEED_EXT_FEATURES_CX V3_EXT_FEATURES_CX +#define NEED_EXT_FEATURES_BX V3_EXT_FEATURES_BX +#define NEED_OS_SUPPORT_AX V3_OS_SUPPORT_AX +#endif + +#ifdef GOAMD64_v4 +#define NEED_MAX_CPUID 0x80000001 +#define NEED_FEATURES_CX V4_FEATURES_CX +#define NEED_EXT_FEATURES_CX V4_EXT_FEATURES_CX +#define NEED_EXT_FEATURES_BX V4_EXT_FEATURES_BX + +// Darwin requires a different approach to check AVX512 support, see CL 285572. +#ifdef GOOS_darwin +#define NEED_OS_SUPPORT_AX V3_OS_SUPPORT_AX +// These values are from: +// https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/osfmk/i386/cpu_capabilities.h +#define commpage64_base_address 0x00007fffffe00000 +#define commpage64_cpu_capabilities64 (commpage64_base_address+0x010) +#define commpage64_version (commpage64_base_address+0x01E) +#define AVX512F 0x0000004000000000 +#define AVX512CD 0x0000008000000000 +#define AVX512DQ 0x0000010000000000 +#define AVX512BW 0x0000020000000000 +#define AVX512VL 0x0000100000000000 +#define NEED_DARWIN_SUPPORT (AVX512F | AVX512DQ | AVX512CD | AVX512BW | AVX512VL) +#else +#define NEED_OS_SUPPORT_AX V4_OS_SUPPORT_AX +#endif + +#endif + +TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 + // copy arguments forward on an even stack + MOVQ DI, AX // argc + MOVQ SI, BX // argv + SUBQ $(5*8), SP // 3args 2auto + ANDQ $~15, SP + MOVQ AX, 24(SP) + MOVQ BX, 32(SP) + + // create istack out of the given (operating system) stack. + // _cgo_init may update stackguard. + MOVQ $runtime·g0(SB), DI + LEAQ (-64*1024)(SP), BX + MOVQ BX, g_stackguard0(DI) + MOVQ BX, g_stackguard1(DI) + MOVQ BX, (g_stack+stack_lo)(DI) + MOVQ SP, (g_stack+stack_hi)(DI) + + // find out information about the processor we're on + MOVL $0, AX + CPUID + CMPL AX, $0 + JE nocpuinfo + + CMPL BX, $0x756E6547 // "Genu" + JNE notintel + CMPL DX, $0x49656E69 // "ineI" + JNE notintel + CMPL CX, $0x6C65746E // "ntel" + JNE notintel + MOVB $1, runtime·isIntel(SB) + +notintel: + // Load EAX=1 cpuid flags + MOVL $1, AX + CPUID + MOVL AX, runtime·processorVersionInfo(SB) + +nocpuinfo: + // if there is an _cgo_init, call it. + MOVQ _cgo_init(SB), AX + TESTQ AX, AX + JZ needtls + // arg 1: g0, already in DI + MOVQ $setg_gcc<>(SB), SI // arg 2: setg_gcc + MOVQ $0, DX // arg 3, 4: not used when using platform's TLS + MOVQ $0, CX +#ifdef GOOS_android + MOVQ $runtime·tls_g(SB), DX // arg 3: &tls_g + // arg 4: TLS base, stored in slot 0 (Android's TLS_SLOT_SELF). + // Compensate for tls_g (+16). + MOVQ -16(TLS), CX +#endif +#ifdef GOOS_windows + MOVQ $runtime·tls_g(SB), DX // arg 3: &tls_g + // Adjust for the Win64 calling convention. + MOVQ CX, R9 // arg 4 + MOVQ DX, R8 // arg 3 + MOVQ SI, DX // arg 2 + MOVQ DI, CX // arg 1 +#endif + CALL AX + + // update stackguard after _cgo_init + MOVQ $runtime·g0(SB), CX + MOVQ (g_stack+stack_lo)(CX), AX + ADDQ $const_stackGuard, AX + MOVQ AX, g_stackguard0(CX) + MOVQ AX, g_stackguard1(CX) + +#ifndef GOOS_windows + JMP ok +#endif +needtls: +#ifdef GOOS_plan9 + // skip TLS setup on Plan 9 + JMP ok +#endif +#ifdef GOOS_solaris + // skip TLS setup on Solaris + JMP ok +#endif +#ifdef GOOS_illumos + // skip TLS setup on illumos + JMP ok +#endif +#ifdef GOOS_darwin + // skip TLS setup on Darwin + JMP ok +#endif +#ifdef GOOS_openbsd + // skip TLS setup on OpenBSD + JMP ok +#endif + +#ifdef GOOS_windows + CALL runtime·wintls(SB) +#endif + + LEAQ runtime·m0+m_tls(SB), DI + CALL runtime·settls(SB) + + // store through it, to make sure it works + get_tls(BX) + MOVQ $0x123, g(BX) + MOVQ runtime·m0+m_tls(SB), AX + CMPQ AX, $0x123 + JEQ 2(PC) + CALL runtime·abort(SB) +ok: + // set the per-goroutine and per-mach "registers" + get_tls(BX) + LEAQ runtime·g0(SB), CX + MOVQ CX, g(BX) + LEAQ runtime·m0(SB), AX + + // save m->g0 = g0 + MOVQ CX, m_g0(AX) + // save m0 to g0->m + MOVQ AX, g_m(CX) + + CLD // convention is D is always left cleared + + // Check GOAMD64 requirements + // We need to do this after setting up TLS, so that + // we can report an error if there is a failure. See issue 49586. +#ifdef NEED_FEATURES_CX + MOVL $0, AX + CPUID + CMPL AX, $0 + JE bad_cpu + MOVL $1, AX + CPUID + ANDL $NEED_FEATURES_CX, CX + CMPL CX, $NEED_FEATURES_CX + JNE bad_cpu +#endif + +#ifdef NEED_MAX_CPUID + MOVL $0x80000000, AX + CPUID + CMPL AX, $NEED_MAX_CPUID + JL bad_cpu +#endif + +#ifdef NEED_EXT_FEATURES_BX + MOVL $7, AX + MOVL $0, CX + CPUID + ANDL $NEED_EXT_FEATURES_BX, BX + CMPL BX, $NEED_EXT_FEATURES_BX + JNE bad_cpu +#endif + +#ifdef NEED_EXT_FEATURES_CX + MOVL $0x80000001, AX + CPUID + ANDL $NEED_EXT_FEATURES_CX, CX + CMPL CX, $NEED_EXT_FEATURES_CX + JNE bad_cpu +#endif + +#ifdef NEED_OS_SUPPORT_AX + XORL CX, CX + XGETBV + ANDL $NEED_OS_SUPPORT_AX, AX + CMPL AX, $NEED_OS_SUPPORT_AX + JNE bad_cpu +#endif + +#ifdef NEED_DARWIN_SUPPORT + MOVQ $commpage64_version, BX + CMPW (BX), $13 // cpu_capabilities64 undefined in versions < 13 + JL bad_cpu + MOVQ $commpage64_cpu_capabilities64, BX + MOVQ (BX), BX + MOVQ $NEED_DARWIN_SUPPORT, CX + ANDQ CX, BX + CMPQ BX, CX + JNE bad_cpu +#endif + + CALL runtime·check(SB) + + MOVL 24(SP), AX // copy argc + MOVL AX, 0(SP) + MOVQ 32(SP), AX // copy argv + MOVQ AX, 8(SP) + CALL runtime·args(SB) + CALL runtime·osinit(SB) + CALL runtime·schedinit(SB) + + // create a new goroutine to start program + MOVQ $runtime·mainPC(SB), AX // entry + PUSHQ AX + CALL runtime·newproc(SB) + POPQ AX + + // start this M + CALL runtime·mstart(SB) + + CALL runtime·abort(SB) // mstart should never return + RET + +bad_cpu: // show that the program requires a certain microarchitecture level. + MOVQ $2, 0(SP) + MOVQ $bad_cpu_msg<>(SB), AX + MOVQ AX, 8(SP) + MOVQ $84, 16(SP) + CALL runtime·write(SB) + MOVQ $1, 0(SP) + CALL runtime·exit(SB) + CALL runtime·abort(SB) + RET + + // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are + // intended to be called by debuggers. + MOVQ $runtime·debugPinnerV1(SB), AX + MOVQ $runtime·debugCallV2(SB), AX + RET + +// mainPC is a function value for runtime.main, to be passed to newproc. +// The reference to runtime.main is made via ABIInternal, since the +// actual function (not the ABI0 wrapper) is needed by newproc. +DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) +GLOBL runtime·mainPC(SB),RODATA,$8 + +TEXT runtime·breakpoint(SB),NOSPLIT,$0-0 + BYTE $0xcc + RET + +TEXT runtime·asminit(SB),NOSPLIT,$0-0 + // No per-thread init. + RET + +TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME|NOFRAME,$0 + CALL runtime·mstart0(SB) + RET // not reached + +/* + * go-routine + */ + +// func gogo(buf *gobuf) +// restore state from Gobuf; longjmp +TEXT runtime·gogo(SB), NOSPLIT, $0-8 + MOVQ buf+0(FP), BX // gobuf + MOVQ gobuf_g(BX), DX + MOVQ 0(DX), CX // make sure g != nil + JMP gogo<>(SB) + +TEXT gogo<>(SB), NOSPLIT, $0 + get_tls(CX) + MOVQ DX, g(CX) + MOVQ DX, R14 // set the g register + MOVQ gobuf_sp(BX), SP // restore SP + MOVQ gobuf_ret(BX), AX + MOVQ gobuf_ctxt(BX), DX + MOVQ gobuf_bp(BX), BP + MOVQ $0, gobuf_sp(BX) // clear to help garbage collector + MOVQ $0, gobuf_ret(BX) + MOVQ $0, gobuf_ctxt(BX) + MOVQ $0, gobuf_bp(BX) + MOVQ gobuf_pc(BX), BX + JMP BX + +// func mcall(fn func(*g)) +// Switch to m->g0's stack, call fn(g). +// Fn must never return. It should gogo(&g->sched) +// to keep running g. +TEXT runtime·mcall(SB), NOSPLIT, $0-8 + MOVQ AX, DX // DX = fn + + // Save state in g->sched. The caller's SP and PC are restored by gogo to + // resume execution in the caller's frame (implicit return). The caller's BP + // is also restored to support frame pointer unwinding. + MOVQ SP, BX // hide (SP) reads from vet + MOVQ 8(BX), BX // caller's PC + MOVQ BX, (g_sched+gobuf_pc)(R14) + LEAQ fn+0(FP), BX // caller's SP + MOVQ BX, (g_sched+gobuf_sp)(R14) + // Get the caller's frame pointer by dereferencing BP. Storing BP as it is + // can cause a frame pointer cycle, see CL 476235. + MOVQ (BP), BX // caller's BP + MOVQ BX, (g_sched+gobuf_bp)(R14) + + // switch to m->g0 & its stack, call fn + MOVQ g_m(R14), BX + MOVQ m_g0(BX), SI // SI = g.m.g0 + CMPQ SI, R14 // if g == m->g0 call badmcall + JNE goodm + JMP runtime·badmcall(SB) +goodm: + MOVQ R14, AX // AX (and arg 0) = g + MOVQ SI, R14 // g = g.m.g0 + get_tls(CX) // Set G in TLS + MOVQ R14, g(CX) + MOVQ (g_sched+gobuf_sp)(R14), SP // sp = g0.sched.sp + PUSHQ AX // open up space for fn's arg spill slot + MOVQ 0(DX), R12 + CALL R12 // fn(g) + // The Windows native stack unwinder incorrectly classifies the next instruction + // as part of the function epilogue, producing a wrong call stack. + // Add a NOP to work around this issue. See go.dev/issue/67007. + BYTE $0x90 + POPQ AX + JMP runtime·badmcall2(SB) + RET + +// systemstack_switch is a dummy routine that systemstack leaves at the bottom +// of the G stack. We need to distinguish the routine that +// lives at the bottom of the G stack from the one that lives +// at the top of the system stack because the one at the top of +// the system stack terminates the stack walk (see topofstack()). +// The frame layout needs to match systemstack +// so that it can pretend to be systemstack_switch. +TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 + UNDEF + // Make sure this function is not leaf, + // so the frame is saved. + CALL runtime·abort(SB) + RET + +// func systemstack(fn func()) +TEXT runtime·systemstack(SB), NOSPLIT, $0-8 + MOVQ fn+0(FP), DI // DI = fn + get_tls(CX) + MOVQ g(CX), AX // AX = g + MOVQ g_m(AX), BX // BX = m + + CMPQ AX, m_gsignal(BX) + JEQ noswitch + + MOVQ m_g0(BX), DX // DX = g0 + CMPQ AX, DX + JEQ noswitch + + CMPQ AX, m_curg(BX) + JNE bad + + // Switch stacks. + // The original frame pointer is stored in BP, + // which is useful for stack unwinding. + // Save our state in g->sched. Pretend to + // be systemstack_switch if the G stack is scanned. + CALL gosave_systemstack_switch<>(SB) + + // switch to g0 + MOVQ DX, g(CX) + MOVQ DX, R14 // set the g register + MOVQ (g_sched+gobuf_sp)(DX), SP + + // call target function + MOVQ DI, DX + MOVQ 0(DI), DI + CALL DI + + // switch back to g + get_tls(CX) + MOVQ g(CX), AX + MOVQ g_m(AX), BX + MOVQ m_curg(BX), AX + MOVQ AX, g(CX) + MOVQ (g_sched+gobuf_sp)(AX), SP + MOVQ (g_sched+gobuf_bp)(AX), BP + MOVQ $0, (g_sched+gobuf_sp)(AX) + MOVQ $0, (g_sched+gobuf_bp)(AX) + RET + +noswitch: + // already on m stack; tail call the function + // Using a tail call here cleans up tracebacks since we won't stop + // at an intermediate systemstack. + MOVQ DI, DX + MOVQ 0(DI), DI + // The function epilogue is not called on a tail call. + // Pop BP from the stack to simulate it. + POPQ BP + JMP DI + +bad: + // Bad: g is not gsignal, not g0, not curg. What is it? + MOVQ $runtime·badsystemstack(SB), AX + CALL AX + INT $3 + +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 + MOVQ g_m(R14), BX // curm + + // set g to gcrash + LEAQ runtime·gcrash(SB), R14 // g = &gcrash + MOVQ BX, g_m(R14) // g.m = curm + MOVQ R14, m_g0(BX) // curm.g0 = g + get_tls(CX) + MOVQ R14, g(CX) + + // switch to crashstack + MOVQ (g_stack+stack_hi)(R14), BX + SUBQ $(4*8), BX + MOVQ BX, SP + + // call target function + MOVQ AX, DX + MOVQ 0(AX), AX + CALL AX + + // should never return + CALL runtime·abort(SB) + UNDEF + +/* + * support for morestack + */ + +// Called during function prolog when more stack is needed. +// +// The traceback routines see morestack on a g0 as being +// the top of a stack (for example, morestack calling newstack +// calling the scheduler calling newm calling gc), so we must +// record an argument size. For that purpose, it has no arguments. +TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 + // Cannot grow scheduler stack (m->g0). + get_tls(CX) + MOVQ g(CX), DI // DI = g + MOVQ g_m(DI), BX // BX = m + + // Set g->sched to context in f. + MOVQ 0(SP), AX // f's PC + MOVQ AX, (g_sched+gobuf_pc)(DI) + LEAQ 8(SP), AX // f's SP + MOVQ AX, (g_sched+gobuf_sp)(DI) + MOVQ BP, (g_sched+gobuf_bp)(DI) + MOVQ DX, (g_sched+gobuf_ctxt)(DI) + + MOVQ m_g0(BX), SI // SI = m.g0 + CMPQ DI, SI + JNE 3(PC) + CALL runtime·badmorestackg0(SB) + CALL runtime·abort(SB) + + // Cannot grow signal stack (m->gsignal). + MOVQ m_gsignal(BX), SI + CMPQ DI, SI + JNE 3(PC) + CALL runtime·badmorestackgsignal(SB) + CALL runtime·abort(SB) + + // Called from f. + // Set m->morebuf to f's caller. + NOP SP // tell vet SP changed - stop checking offsets + MOVQ 8(SP), AX // f's caller's PC + MOVQ AX, (m_morebuf+gobuf_pc)(BX) + LEAQ 16(SP), AX // f's caller's SP + MOVQ AX, (m_morebuf+gobuf_sp)(BX) + MOVQ DI, (m_morebuf+gobuf_g)(BX) + + // Call newstack on m->g0's stack. + MOVQ m_g0(BX), BX + MOVQ BX, g(CX) + MOVQ (g_sched+gobuf_sp)(BX), SP + MOVQ (g_sched+gobuf_bp)(BX), BP + CALL runtime·newstack(SB) + CALL runtime·abort(SB) // crash if newstack returns + RET + +// morestack but not preserving ctxt. +TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 + MOVL $0, DX + JMP runtime·morestack(SB) + +// spillArgs stores return values from registers to a *internal/abi.RegArgs in R12. +TEXT ·spillArgs(SB),NOSPLIT,$0-0 + MOVQ AX, 0(R12) + MOVQ BX, 8(R12) + MOVQ CX, 16(R12) + MOVQ DI, 24(R12) + MOVQ SI, 32(R12) + MOVQ R8, 40(R12) + MOVQ R9, 48(R12) + MOVQ R10, 56(R12) + MOVQ R11, 64(R12) + MOVQ X0, 72(R12) + MOVQ X1, 80(R12) + MOVQ X2, 88(R12) + MOVQ X3, 96(R12) + MOVQ X4, 104(R12) + MOVQ X5, 112(R12) + MOVQ X6, 120(R12) + MOVQ X7, 128(R12) + MOVQ X8, 136(R12) + MOVQ X9, 144(R12) + MOVQ X10, 152(R12) + MOVQ X11, 160(R12) + MOVQ X12, 168(R12) + MOVQ X13, 176(R12) + MOVQ X14, 184(R12) + RET + +// unspillArgs loads args into registers from a *internal/abi.RegArgs in R12. +TEXT ·unspillArgs(SB),NOSPLIT,$0-0 + MOVQ 0(R12), AX + MOVQ 8(R12), BX + MOVQ 16(R12), CX + MOVQ 24(R12), DI + MOVQ 32(R12), SI + MOVQ 40(R12), R8 + MOVQ 48(R12), R9 + MOVQ 56(R12), R10 + MOVQ 64(R12), R11 + MOVQ 72(R12), X0 + MOVQ 80(R12), X1 + MOVQ 88(R12), X2 + MOVQ 96(R12), X3 + MOVQ 104(R12), X4 + MOVQ 112(R12), X5 + MOVQ 120(R12), X6 + MOVQ 128(R12), X7 + MOVQ 136(R12), X8 + MOVQ 144(R12), X9 + MOVQ 152(R12), X10 + MOVQ 160(R12), X11 + MOVQ 168(R12), X12 + MOVQ 176(R12), X13 + MOVQ 184(R12), X14 + RET + +// reflectcall: call a function with the given argument list +// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). +// we don't have variable-sized frames, so we use a small number +// of constant-sized-frame functions to encode a few bits of size in the pc. +// Caution: ugly multiline assembly macros in your future! + +#define DISPATCH(NAME,MAXSIZE) \ + CMPQ CX, $MAXSIZE; \ + JA 3(PC); \ + MOVQ $NAME(SB), AX; \ + JMP AX +// Note: can't just "JMP NAME(SB)" - bad inlining results. + +TEXT ·reflectcall(SB), NOSPLIT, $0-48 + MOVLQZX frameSize+32(FP), CX + DISPATCH(runtime·call16, 16) + DISPATCH(runtime·call32, 32) + DISPATCH(runtime·call64, 64) + DISPATCH(runtime·call128, 128) + DISPATCH(runtime·call256, 256) + DISPATCH(runtime·call512, 512) + DISPATCH(runtime·call1024, 1024) + DISPATCH(runtime·call2048, 2048) + DISPATCH(runtime·call4096, 4096) + DISPATCH(runtime·call8192, 8192) + DISPATCH(runtime·call16384, 16384) + DISPATCH(runtime·call32768, 32768) + DISPATCH(runtime·call65536, 65536) + DISPATCH(runtime·call131072, 131072) + DISPATCH(runtime·call262144, 262144) + DISPATCH(runtime·call524288, 524288) + DISPATCH(runtime·call1048576, 1048576) + DISPATCH(runtime·call2097152, 2097152) + DISPATCH(runtime·call4194304, 4194304) + DISPATCH(runtime·call8388608, 8388608) + DISPATCH(runtime·call16777216, 16777216) + DISPATCH(runtime·call33554432, 33554432) + DISPATCH(runtime·call67108864, 67108864) + DISPATCH(runtime·call134217728, 134217728) + DISPATCH(runtime·call268435456, 268435456) + DISPATCH(runtime·call536870912, 536870912) + DISPATCH(runtime·call1073741824, 1073741824) + MOVQ $runtime·badreflectcall(SB), AX + JMP AX + +#define CALLFN(NAME,MAXSIZE) \ +TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ + NO_LOCAL_POINTERS; \ + /* copy arguments to stack */ \ + MOVQ stackArgs+16(FP), SI; \ + MOVLQZX stackArgsSize+24(FP), CX; \ + MOVQ SP, DI; \ + REP;MOVSB; \ + /* set up argument registers */ \ + MOVQ regArgs+40(FP), R12; \ + CALL ·unspillArgs(SB); \ + /* call function */ \ + MOVQ f+8(FP), DX; \ + PCDATA $PCDATA_StackMapIndex, $0; \ + MOVQ (DX), R12; \ + CALL R12; \ + /* copy register return values back */ \ + MOVQ regArgs+40(FP), R12; \ + CALL ·spillArgs(SB); \ + MOVLQZX stackArgsSize+24(FP), CX; \ + MOVLQZX stackRetOffset+28(FP), BX; \ + MOVQ stackArgs+16(FP), DI; \ + MOVQ stackArgsType+0(FP), DX; \ + MOVQ SP, SI; \ + ADDQ BX, DI; \ + ADDQ BX, SI; \ + SUBQ BX, CX; \ + CALL callRet<>(SB); \ + RET + +// callRet copies return values back at the end of call*. This is a +// separate function so it can allocate stack space for the arguments +// to reflectcallmove. It does not follow the Go ABI; it expects its +// arguments in registers. +TEXT callRet<>(SB), NOSPLIT, $40-0 + NO_LOCAL_POINTERS + MOVQ DX, 0(SP) + MOVQ DI, 8(SP) + MOVQ SI, 16(SP) + MOVQ CX, 24(SP) + MOVQ R12, 32(SP) + CALL runtime·reflectcallmove(SB) + RET + +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) + +TEXT runtime·procyield(SB),NOSPLIT,$0-0 + MOVL cycles+0(FP), AX +again: + PAUSE + SUBL $1, AX + JNZ again + RET + + +TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 + // Stores are already ordered on x86, so this is just a + // compile barrier. + RET + +// Save state of caller into g->sched, +// but using fake PC from systemstack_switch. +// Must only be called from functions with frame pointer +// and without locals ($0) or else unwinding from +// systemstack_switch is incorrect. +// Smashes R9. +TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 + // Take systemstack_switch PC and add 8 bytes to skip + // the prologue. The final location does not matter + // as long as we are between the prologue and the epilogue. + MOVQ $runtime·systemstack_switch+8(SB), R9 + MOVQ R9, (g_sched+gobuf_pc)(R14) + LEAQ 8(SP), R9 + MOVQ R9, (g_sched+gobuf_sp)(R14) + MOVQ $0, (g_sched+gobuf_ret)(R14) + MOVQ BP, (g_sched+gobuf_bp)(R14) + // Assert ctxt is zero. See func save. + MOVQ (g_sched+gobuf_ctxt)(R14), R9 + TESTQ R9, R9 + JZ 2(PC) + CALL runtime·abort(SB) + RET + +// func asmcgocall_no_g(fn, arg unsafe.Pointer) +// Call fn(arg) aligned appropriately for the gcc ABI. +// Called on a system stack, and there may be no g yet (during needm). +TEXT ·asmcgocall_no_g(SB),NOSPLIT,$32-16 + MOVQ fn+0(FP), AX + MOVQ arg+8(FP), BX + MOVQ SP, DX + ANDQ $~15, SP // alignment + MOVQ DX, 8(SP) + MOVQ BX, DI // DI = first argument in AMD64 ABI + MOVQ BX, CX // CX = first argument in Win64 + CALL AX + MOVQ 8(SP), DX + MOVQ DX, SP + RET + +// asmcgocall_landingpad calls AX with BX as argument. +// Must be called on the system stack. +TEXT ·asmcgocall_landingpad(SB),NOSPLIT,$0-0 +#ifdef GOOS_windows + // Make sure we have enough room for 4 stack-backed fast-call + // registers as per Windows amd64 calling convention. + ADJSP $32 + // On Windows, asmcgocall_landingpad acts as landing pad for exceptions + // thrown in the cgo call. Exceptions that reach this function will be + // handled by runtime.sehtramp thanks to the SEH metadata added + // by the compiler. + // Note that runtime.sehtramp can't be attached directly to asmcgocall + // because its initial stack pointer can be outside the system stack bounds, + // and Windows stops the stack unwinding without calling the exception handler + // when it reaches that point. + MOVQ BX, CX // CX = first argument in Win64 + CALL AX + // The exception handler is not called if the next instruction is part of + // the epilogue, which includes the RET instruction, so we need to add a NOP here. + BYTE $0x90 + ADJSP $-32 + RET +#endif + // Tail call AX on non-Windows, as the extra stack frame is not needed. + MOVQ BX, DI // DI = first argument in AMD64 ABI + JMP AX + +// func asmcgocall(fn, arg unsafe.Pointer) int32 +// Call fn(arg) on the scheduler stack, +// aligned appropriately for the gcc ABI. +// See cgocall.go for more details. +TEXT ·asmcgocall(SB),NOSPLIT,$0-20 + MOVQ fn+0(FP), AX + MOVQ arg+8(FP), BX + + MOVQ SP, DX + + // Figure out if we need to switch to m->g0 stack. + // We get called to create new OS threads too, and those + // come in on the m->g0 stack already. Or we might already + // be on the m->gsignal stack. + get_tls(CX) + MOVQ g(CX), DI + CMPQ DI, $0 + JEQ nosave + MOVQ g_m(DI), R8 + MOVQ m_gsignal(R8), SI + CMPQ DI, SI + JEQ nosave + MOVQ m_g0(R8), SI + CMPQ DI, SI + JEQ nosave + + // Switch to system stack. + // The original frame pointer is stored in BP, + // which is useful for stack unwinding. + CALL gosave_systemstack_switch<>(SB) + MOVQ SI, g(CX) + MOVQ (g_sched+gobuf_sp)(SI), SP + + // Now on a scheduling stack (a pthread-created stack). + SUBQ $16, SP + ANDQ $~15, SP // alignment for gcc ABI + MOVQ DI, 8(SP) // save g + MOVQ (g_stack+stack_hi)(DI), DI + SUBQ DX, DI + MOVQ DI, 0(SP) // save depth in stack (can't just save SP, as stack might be copied during a callback) + CALL runtime·asmcgocall_landingpad(SB) + + // Restore registers, g, stack pointer. + get_tls(CX) + MOVQ 8(SP), DI + MOVQ (g_stack+stack_hi)(DI), SI + SUBQ 0(SP), SI + MOVQ DI, g(CX) + MOVQ SI, SP + + MOVL AX, ret+16(FP) + RET + +nosave: + // Running on a system stack, perhaps even without a g. + // Having no g can happen during thread creation or thread teardown + // (see needm/dropm on Solaris, for example). + // This code is like the above sequence but without saving/restoring g + // and without worrying about the stack moving out from under us + // (because we're on a system stack, not a goroutine stack). + // The above code could be used directly if already on a system stack, + // but then the only path through this code would be a rare case on Solaris. + // Using this code for all "already on system stack" calls exercises it more, + // which should help keep it correct. + SUBQ $16, SP + ANDQ $~15, SP + MOVQ $0, 8(SP) // where above code stores g, in case someone looks during debugging + MOVQ DX, 0(SP) // save original stack pointer + CALL runtime·asmcgocall_landingpad(SB) + MOVQ 0(SP), SI // restore original stack pointer + MOVQ SI, SP + MOVL AX, ret+16(FP) + RET + +#ifdef GOOS_windows +// Dummy TLS that's used on Windows so that we don't crash trying +// to restore the G register in needm. needm and its callees are +// very careful never to actually use the G, the TLS just can't be +// unset since we're in Go code. +GLOBL zeroTLS<>(SB),RODATA,$const_tlsSize +#endif + +// func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) +// See cgocall.go for more details. +TEXT ·cgocallback(SB),NOSPLIT,$24-24 + NO_LOCAL_POINTERS + + // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. + // It is used to dropm while thread is exiting. + MOVQ fn+0(FP), AX + CMPQ AX, $0 + JNE loadg + // Restore the g from frame. + get_tls(CX) + MOVQ frame+8(FP), BX + MOVQ BX, g(CX) + JMP dropm + +loadg: + // If g is nil, Go did not create the current thread, + // or if this thread never called into Go on pthread platforms. + // Call needm to obtain one m for temporary use. + // In this case, we're running on the thread stack, so there's + // lots of space, but the linker doesn't know. Hide the call from + // the linker analysis by using an indirect call through AX. + get_tls(CX) +#ifdef GOOS_windows + MOVL $0, BX + CMPQ CX, $0 + JEQ 2(PC) +#endif + MOVQ g(CX), BX + CMPQ BX, $0 + JEQ needm + MOVQ g_m(BX), BX + MOVQ BX, savedm-8(SP) // saved copy of oldm + JMP havem +needm: +#ifdef GOOS_windows + // Set up a dummy TLS value. needm is careful not to use it, + // but it needs to be there to prevent autogenerated code from + // crashing when it loads from it. + // We don't need to clear it or anything later because needm + // will set up TLS properly. + MOVQ $zeroTLS<>(SB), DI + CALL runtime·settls(SB) +#endif + // On some platforms (Windows) we cannot call needm through + // an ABI wrapper because there's no TLS set up, and the ABI + // wrapper will try to restore the G register (R14) from TLS. + // Clear X15 because Go expects it and we're not calling + // through a wrapper, but otherwise avoid setting the G + // register in the wrapper and call needm directly. It + // takes no arguments and doesn't return any values so + // there's no need to handle that. Clear R14 so that there's + // a bad value in there, in case needm tries to use it. + XORPS X15, X15 + XORQ R14, R14 + MOVQ $runtime·needAndBindM(SB), AX + CALL AX + MOVQ $0, savedm-8(SP) + get_tls(CX) + MOVQ g(CX), BX + MOVQ g_m(BX), BX + + // Set m->sched.sp = SP, so that if a panic happens + // during the function we are about to execute, it will + // have a valid SP to run on the g0 stack. + // The next few lines (after the havem label) + // will save this SP onto the stack and then write + // the same SP back to m->sched.sp. That seems redundant, + // but if an unrecovered panic happens, unwindm will + // restore the g->sched.sp from the stack location + // and then systemstack will try to use it. If we don't set it here, + // that restored SP will be uninitialized (typically 0) and + // will not be usable. + MOVQ m_g0(BX), SI + MOVQ SP, (g_sched+gobuf_sp)(SI) + +havem: + // Now there's a valid m, and we're running on its m->g0. + // Save current m->g0->sched.sp on stack and then set it to SP. + // Save current sp in m->g0->sched.sp in preparation for + // switch back to m->curg stack. + // NOTE: unwindm knows that the saved g->sched.sp is at 0(SP). + MOVQ m_g0(BX), SI + MOVQ (g_sched+gobuf_sp)(SI), AX + MOVQ AX, 0(SP) + MOVQ SP, (g_sched+gobuf_sp)(SI) + + // Switch to m->curg stack and call runtime.cgocallbackg. + // Because we are taking over the execution of m->curg + // but *not* resuming what had been running, we need to + // save that information (m->curg->sched) so we can restore it. + // We can restore m->curg->sched.sp easily, because calling + // runtime.cgocallbackg leaves SP unchanged upon return. + // To save m->curg->sched.pc, we push it onto the curg stack and + // open a frame the same size as cgocallback's g0 frame. + // Once we switch to the curg stack, the pushed PC will appear + // to be the return PC of cgocallback, so that the traceback + // will seamlessly trace back into the earlier calls. + MOVQ m_curg(BX), SI + MOVQ SI, g(CX) + MOVQ (g_sched+gobuf_sp)(SI), DI // prepare stack as DI + MOVQ (g_sched+gobuf_pc)(SI), BX + MOVQ BX, -8(DI) // "push" return PC on the g stack + // Gather our arguments into registers. + MOVQ fn+0(FP), BX + MOVQ frame+8(FP), CX + MOVQ ctxt+16(FP), DX + // Compute the size of the frame, including return PC and, if + // GOEXPERIMENT=framepointer, the saved base pointer + LEAQ fn+0(FP), AX + SUBQ SP, AX // AX is our actual frame size + SUBQ AX, DI // Allocate the same frame size on the g stack + MOVQ DI, SP + + MOVQ BX, 0(SP) + MOVQ CX, 8(SP) + MOVQ DX, 16(SP) + MOVQ $runtime·cgocallbackg(SB), AX + CALL AX // indirect call to bypass nosplit check. We're on a different stack now. + + // Compute the size of the frame again. FP and SP have + // completely different values here than they did above, + // but only their difference matters. + LEAQ fn+0(FP), AX + SUBQ SP, AX + + // Restore g->sched (== m->curg->sched) from saved values. + get_tls(CX) + MOVQ g(CX), SI + MOVQ SP, DI + ADDQ AX, DI + MOVQ -8(DI), BX + MOVQ BX, (g_sched+gobuf_pc)(SI) + MOVQ DI, (g_sched+gobuf_sp)(SI) + + // Switch back to m->g0's stack and restore m->g0->sched.sp. + // (Unlike m->curg, the g0 goroutine never uses sched.pc, + // so we do not have to restore it.) + MOVQ g(CX), BX + MOVQ g_m(BX), BX + MOVQ m_g0(BX), SI + MOVQ SI, g(CX) + MOVQ (g_sched+gobuf_sp)(SI), SP + MOVQ 0(SP), AX + MOVQ AX, (g_sched+gobuf_sp)(SI) + + // If the m on entry was nil, we called needm above to borrow an m, + // 1. for the duration of the call on non-pthread platforms, + // 2. or the duration of the C thread alive on pthread platforms. + // If the m on entry wasn't nil, + // 1. the thread might be a Go thread, + // 2. or it wasn't the first call from a C thread on pthread platforms, + // since then we skip dropm to reuse the m in the first call. + MOVQ savedm-8(SP), BX + CMPQ BX, $0 + JNE done + + // Skip dropm to reuse it in the next call, when a pthread key has been created. + MOVQ _cgo_pthread_key_created(SB), AX + // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. + CMPQ AX, $0 + JEQ dropm + CMPQ (AX), $0 + JNE done + +dropm: + MOVQ $runtime·dropm(SB), AX + CALL AX +#ifdef GOOS_windows + // We need to clear the TLS pointer in case the next + // thread that comes into Go tries to reuse that space + // but uses the same M. + XORQ DI, DI + CALL runtime·settls(SB) +#endif +done: + + // Done! + RET + +// func setg(gg *g) +// set g. for use by needm. +TEXT runtime·setg(SB), NOSPLIT, $0-8 + MOVQ gg+0(FP), BX + get_tls(CX) + MOVQ BX, g(CX) + RET + +// void setg_gcc(G*); set g called from gcc. +TEXT setg_gcc<>(SB),NOSPLIT,$0 + get_tls(AX) + MOVQ DI, g(AX) + MOVQ DI, R14 // set the g register + RET + +TEXT runtime·abort(SB),NOSPLIT,$0-0 + INT $3 +loop: + JMP loop + +// check that SP is in range [g->stack.lo, g->stack.hi) +TEXT runtime·stackcheck(SB), NOSPLIT|NOFRAME, $0-0 + get_tls(CX) + MOVQ g(CX), AX + CMPQ (g_stack+stack_hi)(AX), SP + JHI 2(PC) + CALL runtime·abort(SB) + CMPQ SP, (g_stack+stack_lo)(AX) + JHI 2(PC) + CALL runtime·abort(SB) + RET + +// func cputicks() int64 +TEXT runtime·cputicks(SB),NOSPLIT,$0-0 + CMPB internal∕cpu·X86+const_offsetX86HasRDTSCP(SB), $1 + JNE fences + // Instruction stream serializing RDTSCP is supported. + // RDTSCP is supported by Intel Nehalem (2008) and + // AMD K8 Rev. F (2006) and newer. + RDTSCP +done: + SHLQ $32, DX + ADDQ DX, AX + MOVQ AX, ret+0(FP) + RET +fences: + // MFENCE is instruction stream serializing and flushes the + // store buffers on AMD. The serialization semantics of LFENCE on AMD + // are dependent on MSR C001_1029 and CPU generation. + // LFENCE on Intel does wait for all previous instructions to have executed. + // Intel recommends MFENCE;LFENCE in its manuals before RDTSC to have all + // previous instructions executed and all previous loads and stores to globally visible. + // Using MFENCE;LFENCE here aligns the serializing properties without + // runtime detection of CPU manufacturer. + MFENCE + LFENCE + RDTSC + JMP done + +// func memhash(p unsafe.Pointer, h, s uintptr) uintptr +// hash function using AES hardware instructions +TEXT runtime·memhash(SB),NOSPLIT,$0-32 + // AX = ptr to data + // BX = seed + // CX = size + CMPB runtime·useAeshash(SB), $0 + JEQ noaes + JMP aeshashbody<>(SB) +noaes: + JMP runtime·memhashFallback(SB) + +// func strhash(p unsafe.Pointer, h uintptr) uintptr +TEXT runtime·strhash(SB),NOSPLIT,$0-24 + // AX = ptr to string struct + // BX = seed + CMPB runtime·useAeshash(SB), $0 + JEQ noaes + MOVQ 8(AX), CX // length of string + MOVQ (AX), AX // string data + JMP aeshashbody<>(SB) +noaes: + JMP runtime·strhashFallback(SB) + +// AX: data +// BX: hash seed +// CX: length +// At return: AX = return value +TEXT aeshashbody<>(SB),NOSPLIT,$0-0 + // Fill an SSE register with our seeds. + MOVQ BX, X0 // 64 bits of per-table hash seed + PINSRW $4, CX, X0 // 16 bits of length + PSHUFHW $0, X0, X0 // repeat length 4 times total + MOVO X0, X1 // save unscrambled seed + PXOR runtime·aeskeysched(SB), X0 // xor in per-process seed + AESENC X0, X0 // scramble seed + + CMPQ CX, $16 + JB aes0to15 + JE aes16 + CMPQ CX, $32 + JBE aes17to32 + CMPQ CX, $64 + JBE aes33to64 + CMPQ CX, $128 + JBE aes65to128 + JMP aes129plus + +aes0to15: + TESTQ CX, CX + JE aes0 + + ADDQ $16, AX + TESTW $0xff0, AX + JE endofpage + + // 16 bytes loaded at this address won't cross + // a page boundary, so we can load it directly. + MOVOU -16(AX), X1 + ADDQ CX, CX + MOVQ $masks<>(SB), AX + PAND (AX)(CX*8), X1 +final1: + PXOR X0, X1 // xor data with seed + AESENC X1, X1 // scramble combo 3 times + AESENC X1, X1 + AESENC X1, X1 + MOVQ X1, AX // return X1 + RET + +endofpage: + // address ends in 1111xxxx. Might be up against + // a page boundary, so load ending at last byte. + // Then shift bytes down using pshufb. + MOVOU -32(AX)(CX*1), X1 + ADDQ CX, CX + MOVQ $shifts<>(SB), AX + PSHUFB (AX)(CX*8), X1 + JMP final1 + +aes0: + // Return scrambled input seed + AESENC X0, X0 + MOVQ X0, AX // return X0 + RET + +aes16: + MOVOU (AX), X1 + JMP final1 + +aes17to32: + // make second starting seed + PXOR runtime·aeskeysched+16(SB), X1 + AESENC X1, X1 + + // load data to be hashed + MOVOU (AX), X2 + MOVOU -16(AX)(CX*1), X3 + + // xor with seed + PXOR X0, X2 + PXOR X1, X3 + + // scramble 3 times + AESENC X2, X2 + AESENC X3, X3 + AESENC X2, X2 + AESENC X3, X3 + AESENC X2, X2 + AESENC X3, X3 + + // combine results + PXOR X3, X2 + MOVQ X2, AX // return X2 + RET + +aes33to64: + // make 3 more starting seeds + MOVO X1, X2 + MOVO X1, X3 + PXOR runtime·aeskeysched+16(SB), X1 + PXOR runtime·aeskeysched+32(SB), X2 + PXOR runtime·aeskeysched+48(SB), X3 + AESENC X1, X1 + AESENC X2, X2 + AESENC X3, X3 + + MOVOU (AX), X4 + MOVOU 16(AX), X5 + MOVOU -32(AX)(CX*1), X6 + MOVOU -16(AX)(CX*1), X7 + + PXOR X0, X4 + PXOR X1, X5 + PXOR X2, X6 + PXOR X3, X7 + + AESENC X4, X4 + AESENC X5, X5 + AESENC X6, X6 + AESENC X7, X7 + + AESENC X4, X4 + AESENC X5, X5 + AESENC X6, X6 + AESENC X7, X7 + + AESENC X4, X4 + AESENC X5, X5 + AESENC X6, X6 + AESENC X7, X7 + + PXOR X6, X4 + PXOR X7, X5 + PXOR X5, X4 + MOVQ X4, AX // return X4 + RET + +aes65to128: + // make 7 more starting seeds + MOVO X1, X2 + MOVO X1, X3 + MOVO X1, X4 + MOVO X1, X5 + MOVO X1, X6 + MOVO X1, X7 + PXOR runtime·aeskeysched+16(SB), X1 + PXOR runtime·aeskeysched+32(SB), X2 + PXOR runtime·aeskeysched+48(SB), X3 + PXOR runtime·aeskeysched+64(SB), X4 + PXOR runtime·aeskeysched+80(SB), X5 + PXOR runtime·aeskeysched+96(SB), X6 + PXOR runtime·aeskeysched+112(SB), X7 + AESENC X1, X1 + AESENC X2, X2 + AESENC X3, X3 + AESENC X4, X4 + AESENC X5, X5 + AESENC X6, X6 + AESENC X7, X7 + + // load data + MOVOU (AX), X8 + MOVOU 16(AX), X9 + MOVOU 32(AX), X10 + MOVOU 48(AX), X11 + MOVOU -64(AX)(CX*1), X12 + MOVOU -48(AX)(CX*1), X13 + MOVOU -32(AX)(CX*1), X14 + MOVOU -16(AX)(CX*1), X15 + + // xor with seed + PXOR X0, X8 + PXOR X1, X9 + PXOR X2, X10 + PXOR X3, X11 + PXOR X4, X12 + PXOR X5, X13 + PXOR X6, X14 + PXOR X7, X15 + + // scramble 3 times + AESENC X8, X8 + AESENC X9, X9 + AESENC X10, X10 + AESENC X11, X11 + AESENC X12, X12 + AESENC X13, X13 + AESENC X14, X14 + AESENC X15, X15 + + AESENC X8, X8 + AESENC X9, X9 + AESENC X10, X10 + AESENC X11, X11 + AESENC X12, X12 + AESENC X13, X13 + AESENC X14, X14 + AESENC X15, X15 + + AESENC X8, X8 + AESENC X9, X9 + AESENC X10, X10 + AESENC X11, X11 + AESENC X12, X12 + AESENC X13, X13 + AESENC X14, X14 + AESENC X15, X15 + + // combine results + PXOR X12, X8 + PXOR X13, X9 + PXOR X14, X10 + PXOR X15, X11 + PXOR X10, X8 + PXOR X11, X9 + PXOR X9, X8 + // X15 must be zero on return + PXOR X15, X15 + MOVQ X8, AX // return X8 + RET + +aes129plus: + // make 7 more starting seeds + MOVO X1, X2 + MOVO X1, X3 + MOVO X1, X4 + MOVO X1, X5 + MOVO X1, X6 + MOVO X1, X7 + PXOR runtime·aeskeysched+16(SB), X1 + PXOR runtime·aeskeysched+32(SB), X2 + PXOR runtime·aeskeysched+48(SB), X3 + PXOR runtime·aeskeysched+64(SB), X4 + PXOR runtime·aeskeysched+80(SB), X5 + PXOR runtime·aeskeysched+96(SB), X6 + PXOR runtime·aeskeysched+112(SB), X7 + AESENC X1, X1 + AESENC X2, X2 + AESENC X3, X3 + AESENC X4, X4 + AESENC X5, X5 + AESENC X6, X6 + AESENC X7, X7 + + // start with last (possibly overlapping) block + MOVOU -128(AX)(CX*1), X8 + MOVOU -112(AX)(CX*1), X9 + MOVOU -96(AX)(CX*1), X10 + MOVOU -80(AX)(CX*1), X11 + MOVOU -64(AX)(CX*1), X12 + MOVOU -48(AX)(CX*1), X13 + MOVOU -32(AX)(CX*1), X14 + MOVOU -16(AX)(CX*1), X15 + + // xor in seed + PXOR X0, X8 + PXOR X1, X9 + PXOR X2, X10 + PXOR X3, X11 + PXOR X4, X12 + PXOR X5, X13 + PXOR X6, X14 + PXOR X7, X15 + + // compute number of remaining 128-byte blocks + DECQ CX + SHRQ $7, CX + + PCALIGN $16 +aesloop: + // scramble state + AESENC X8, X8 + AESENC X9, X9 + AESENC X10, X10 + AESENC X11, X11 + AESENC X12, X12 + AESENC X13, X13 + AESENC X14, X14 + AESENC X15, X15 + + // scramble state, xor in a block + MOVOU (AX), X0 + MOVOU 16(AX), X1 + MOVOU 32(AX), X2 + MOVOU 48(AX), X3 + AESENC X0, X8 + AESENC X1, X9 + AESENC X2, X10 + AESENC X3, X11 + MOVOU 64(AX), X4 + MOVOU 80(AX), X5 + MOVOU 96(AX), X6 + MOVOU 112(AX), X7 + AESENC X4, X12 + AESENC X5, X13 + AESENC X6, X14 + AESENC X7, X15 + + ADDQ $128, AX + DECQ CX + JNE aesloop + + // 3 more scrambles to finish + AESENC X8, X8 + AESENC X9, X9 + AESENC X10, X10 + AESENC X11, X11 + AESENC X12, X12 + AESENC X13, X13 + AESENC X14, X14 + AESENC X15, X15 + AESENC X8, X8 + AESENC X9, X9 + AESENC X10, X10 + AESENC X11, X11 + AESENC X12, X12 + AESENC X13, X13 + AESENC X14, X14 + AESENC X15, X15 + AESENC X8, X8 + AESENC X9, X9 + AESENC X10, X10 + AESENC X11, X11 + AESENC X12, X12 + AESENC X13, X13 + AESENC X14, X14 + AESENC X15, X15 + + PXOR X12, X8 + PXOR X13, X9 + PXOR X14, X10 + PXOR X15, X11 + PXOR X10, X8 + PXOR X11, X9 + PXOR X9, X8 + // X15 must be zero on return + PXOR X15, X15 + MOVQ X8, AX // return X8 + RET + +// func memhash32(p unsafe.Pointer, h uintptr) uintptr +// ABIInternal for performance. +TEXT runtime·memhash32(SB),NOSPLIT,$0-24 + // AX = ptr to data + // BX = seed + CMPB runtime·useAeshash(SB), $0 + JEQ noaes + MOVQ BX, X0 // X0 = seed + PINSRD $2, (AX), X0 // data + AESENC runtime·aeskeysched+0(SB), X0 + AESENC runtime·aeskeysched+16(SB), X0 + AESENC runtime·aeskeysched+32(SB), X0 + MOVQ X0, AX // return X0 + RET +noaes: + JMP runtime·memhash32Fallback(SB) + +// func memhash64(p unsafe.Pointer, h uintptr) uintptr +// ABIInternal for performance. +TEXT runtime·memhash64(SB),NOSPLIT,$0-24 + // AX = ptr to data + // BX = seed + CMPB runtime·useAeshash(SB), $0 + JEQ noaes + MOVQ BX, X0 // X0 = seed + PINSRQ $1, (AX), X0 // data + AESENC runtime·aeskeysched+0(SB), X0 + AESENC runtime·aeskeysched+16(SB), X0 + AESENC runtime·aeskeysched+32(SB), X0 + MOVQ X0, AX // return X0 + RET +noaes: + JMP runtime·memhash64Fallback(SB) + +// simple mask to get rid of data in the high part of the register. +DATA masks<>+0x00(SB)/8, $0x0000000000000000 +DATA masks<>+0x08(SB)/8, $0x0000000000000000 +DATA masks<>+0x10(SB)/8, $0x00000000000000ff +DATA masks<>+0x18(SB)/8, $0x0000000000000000 +DATA masks<>+0x20(SB)/8, $0x000000000000ffff +DATA masks<>+0x28(SB)/8, $0x0000000000000000 +DATA masks<>+0x30(SB)/8, $0x0000000000ffffff +DATA masks<>+0x38(SB)/8, $0x0000000000000000 +DATA masks<>+0x40(SB)/8, $0x00000000ffffffff +DATA masks<>+0x48(SB)/8, $0x0000000000000000 +DATA masks<>+0x50(SB)/8, $0x000000ffffffffff +DATA masks<>+0x58(SB)/8, $0x0000000000000000 +DATA masks<>+0x60(SB)/8, $0x0000ffffffffffff +DATA masks<>+0x68(SB)/8, $0x0000000000000000 +DATA masks<>+0x70(SB)/8, $0x00ffffffffffffff +DATA masks<>+0x78(SB)/8, $0x0000000000000000 +DATA masks<>+0x80(SB)/8, $0xffffffffffffffff +DATA masks<>+0x88(SB)/8, $0x0000000000000000 +DATA masks<>+0x90(SB)/8, $0xffffffffffffffff +DATA masks<>+0x98(SB)/8, $0x00000000000000ff +DATA masks<>+0xa0(SB)/8, $0xffffffffffffffff +DATA masks<>+0xa8(SB)/8, $0x000000000000ffff +DATA masks<>+0xb0(SB)/8, $0xffffffffffffffff +DATA masks<>+0xb8(SB)/8, $0x0000000000ffffff +DATA masks<>+0xc0(SB)/8, $0xffffffffffffffff +DATA masks<>+0xc8(SB)/8, $0x00000000ffffffff +DATA masks<>+0xd0(SB)/8, $0xffffffffffffffff +DATA masks<>+0xd8(SB)/8, $0x000000ffffffffff +DATA masks<>+0xe0(SB)/8, $0xffffffffffffffff +DATA masks<>+0xe8(SB)/8, $0x0000ffffffffffff +DATA masks<>+0xf0(SB)/8, $0xffffffffffffffff +DATA masks<>+0xf8(SB)/8, $0x00ffffffffffffff +GLOBL masks<>(SB),RODATA,$256 + +// func checkASM() bool +TEXT ·checkASM(SB),NOSPLIT,$0-1 + // check that masks<>(SB) and shifts<>(SB) are aligned to 16-byte + MOVQ $masks<>(SB), AX + MOVQ $shifts<>(SB), BX + ORQ BX, AX + TESTQ $15, AX + SETEQ ret+0(FP) + RET + +// these are arguments to pshufb. They move data down from +// the high bytes of the register to the low bytes of the register. +// index is how many bytes to move. +DATA shifts<>+0x00(SB)/8, $0x0000000000000000 +DATA shifts<>+0x08(SB)/8, $0x0000000000000000 +DATA shifts<>+0x10(SB)/8, $0xffffffffffffff0f +DATA shifts<>+0x18(SB)/8, $0xffffffffffffffff +DATA shifts<>+0x20(SB)/8, $0xffffffffffff0f0e +DATA shifts<>+0x28(SB)/8, $0xffffffffffffffff +DATA shifts<>+0x30(SB)/8, $0xffffffffff0f0e0d +DATA shifts<>+0x38(SB)/8, $0xffffffffffffffff +DATA shifts<>+0x40(SB)/8, $0xffffffff0f0e0d0c +DATA shifts<>+0x48(SB)/8, $0xffffffffffffffff +DATA shifts<>+0x50(SB)/8, $0xffffff0f0e0d0c0b +DATA shifts<>+0x58(SB)/8, $0xffffffffffffffff +DATA shifts<>+0x60(SB)/8, $0xffff0f0e0d0c0b0a +DATA shifts<>+0x68(SB)/8, $0xffffffffffffffff +DATA shifts<>+0x70(SB)/8, $0xff0f0e0d0c0b0a09 +DATA shifts<>+0x78(SB)/8, $0xffffffffffffffff +DATA shifts<>+0x80(SB)/8, $0x0f0e0d0c0b0a0908 +DATA shifts<>+0x88(SB)/8, $0xffffffffffffffff +DATA shifts<>+0x90(SB)/8, $0x0e0d0c0b0a090807 +DATA shifts<>+0x98(SB)/8, $0xffffffffffffff0f +DATA shifts<>+0xa0(SB)/8, $0x0d0c0b0a09080706 +DATA shifts<>+0xa8(SB)/8, $0xffffffffffff0f0e +DATA shifts<>+0xb0(SB)/8, $0x0c0b0a0908070605 +DATA shifts<>+0xb8(SB)/8, $0xffffffffff0f0e0d +DATA shifts<>+0xc0(SB)/8, $0x0b0a090807060504 +DATA shifts<>+0xc8(SB)/8, $0xffffffff0f0e0d0c +DATA shifts<>+0xd0(SB)/8, $0x0a09080706050403 +DATA shifts<>+0xd8(SB)/8, $0xffffff0f0e0d0c0b +DATA shifts<>+0xe0(SB)/8, $0x0908070605040302 +DATA shifts<>+0xe8(SB)/8, $0xffff0f0e0d0c0b0a +DATA shifts<>+0xf0(SB)/8, $0x0807060504030201 +DATA shifts<>+0xf8(SB)/8, $0xff0f0e0d0c0b0a09 +GLOBL shifts<>(SB),RODATA,$256 + +TEXT runtime·return0(SB), NOSPLIT, $0 + MOVL $0, AX + RET + + +// Called from cgo wrappers, this function returns g->m->curg.stack.hi. +// Must obey the gcc calling convention. +TEXT _cgo_topofstack(SB),NOSPLIT,$0 + get_tls(CX) + MOVQ g(CX), AX + MOVQ g_m(AX), AX + MOVQ m_curg(AX), AX + MOVQ (g_stack+stack_hi)(AX), AX + RET + +// The top-most function running on a goroutine +// returns to goexit+PCQuantum. +TEXT runtime·goexit(SB),NOSPLIT|TOPFRAME|NOFRAME,$0-0 + BYTE $0x90 // NOP + CALL runtime·goexit1(SB) // does not return + // traceback from goexit1 must hit code range of goexit + BYTE $0x90 // NOP + +// This is called from .init_array and follows the platform, not Go, ABI. +TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 + PUSHQ R15 // The access to global variables below implicitly uses R15, which is callee-save + MOVQ runtime·lastmoduledatap(SB), AX + MOVQ DI, moduledata_next(AX) + MOVQ DI, runtime·lastmoduledatap(SB) + POPQ R15 + RET + +// Initialize special registers then jump to sigpanic. +// This function is injected from the signal handler for panicking +// signals. It is quite painful to set X15 in the signal context, +// so we do it here. +TEXT ·sigpanic0(SB),NOSPLIT,$0-0 + get_tls(R14) + MOVQ g(R14), R14 +#ifndef GOOS_plan9 + XORPS X15, X15 +#endif + JMP ·sigpanic(SB) + +// gcWriteBarrier informs the GC about heap pointer writes. +// +// gcWriteBarrier returns space in a write barrier buffer which +// should be filled in by the caller. +// gcWriteBarrier does NOT follow the Go ABI. It accepts the +// number of bytes of buffer needed in R11, and returns a pointer +// to the buffer space in R11. +// It clobbers FLAGS. It does not clobber any general-purpose registers, +// but may clobber others (e.g., SSE registers). +// Typical use would be, when doing *(CX+88) = AX +// CMPL $0, runtime.writeBarrier(SB) +// JEQ dowrite +// CALL runtime.gcBatchBarrier2(SB) +// MOVQ AX, (R11) +// MOVQ 88(CX), DX +// MOVQ DX, 8(R11) +// dowrite: +// MOVQ AX, 88(CX) +TEXT gcWriteBarrier<>(SB),NOSPLIT,$112 + // Save the registers clobbered by the fast path. This is slightly + // faster than having the caller spill these. + MOVQ R12, 96(SP) + MOVQ R13, 104(SP) +retry: + // TODO: Consider passing g.m.p in as an argument so they can be shared + // across a sequence of write barriers. + MOVQ g_m(R14), R13 + MOVQ m_p(R13), R13 + // Get current buffer write position. + MOVQ (p_wbBuf+wbBuf_next)(R13), R12 // original next position + ADDQ R11, R12 // new next position + // Is the buffer full? + CMPQ R12, (p_wbBuf+wbBuf_end)(R13) + JA flush + // Commit to the larger buffer. + MOVQ R12, (p_wbBuf+wbBuf_next)(R13) + // Make return value (the original next position) + SUBQ R11, R12 + MOVQ R12, R11 + // Restore registers. + MOVQ 96(SP), R12 + MOVQ 104(SP), R13 + RET + +flush: + // Save all general purpose registers since these could be + // clobbered by wbBufFlush and were not saved by the caller. + // It is possible for wbBufFlush to clobber other registers + // (e.g., SSE registers), but the compiler takes care of saving + // those in the caller if necessary. This strikes a balance + // with registers that are likely to be used. + // + // We don't have type information for these, but all code under + // here is NOSPLIT, so nothing will observe these. + // + // TODO: We could strike a different balance; e.g., saving X0 + // and not saving GP registers that are less likely to be used. + MOVQ DI, 0(SP) + MOVQ AX, 8(SP) + MOVQ BX, 16(SP) + MOVQ CX, 24(SP) + MOVQ DX, 32(SP) + // DI already saved + MOVQ SI, 40(SP) + MOVQ BP, 48(SP) + MOVQ R8, 56(SP) + MOVQ R9, 64(SP) + MOVQ R10, 72(SP) + MOVQ R11, 80(SP) + // R12 already saved + // R13 already saved + // R14 is g + MOVQ R15, 88(SP) + + CALL runtime·wbBufFlush(SB) + + MOVQ 0(SP), DI + MOVQ 8(SP), AX + MOVQ 16(SP), BX + MOVQ 24(SP), CX + MOVQ 32(SP), DX + MOVQ 40(SP), SI + MOVQ 48(SP), BP + MOVQ 56(SP), R8 + MOVQ 64(SP), R9 + MOVQ 72(SP), R10 + MOVQ 80(SP), R11 + MOVQ 88(SP), R15 + JMP retry + +TEXT runtime·gcWriteBarrier1(SB),NOSPLIT|NOFRAME,$0 + MOVL $8, R11 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier2(SB),NOSPLIT|NOFRAME,$0 + MOVL $16, R11 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier3(SB),NOSPLIT|NOFRAME,$0 + MOVL $24, R11 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier4(SB),NOSPLIT|NOFRAME,$0 + MOVL $32, R11 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier5(SB),NOSPLIT|NOFRAME,$0 + MOVL $40, R11 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier6(SB),NOSPLIT|NOFRAME,$0 + MOVL $48, R11 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier7(SB),NOSPLIT|NOFRAME,$0 + MOVL $56, R11 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier8(SB),NOSPLIT|NOFRAME,$0 + MOVL $64, R11 + JMP gcWriteBarrier<>(SB) + +DATA debugCallFrameTooLarge<>+0x00(SB)/20, $"call frame too large" +GLOBL debugCallFrameTooLarge<>(SB), RODATA, $20 // Size duplicated below + +// debugCallV2 is the entry point for debugger-injected function +// calls on running goroutines. It informs the runtime that a +// debug call has been injected and creates a call frame for the +// debugger to fill in. +// +// To inject a function call, a debugger should: +// 1. Check that the goroutine is in state _Grunning and that +// there are at least 256 bytes free on the stack. +// 2. Push the current PC on the stack (updating SP). +// 3. Write the desired argument frame size at SP-16 (using the SP +// after step 2). +// 4. Save all machine registers (including flags and XMM registers) +// so they can be restored later by the debugger. +// 5. Set the PC to debugCallV2 and resume execution. +// +// If the goroutine is in state _Grunnable, then it's not generally +// safe to inject a call because it may return out via other runtime +// operations. Instead, the debugger should unwind the stack to find +// the return to non-runtime code, add a temporary breakpoint there, +// and inject the call once that breakpoint is hit. +// +// If the goroutine is in any other state, it's not safe to inject a call. +// +// This function communicates back to the debugger by setting R12 and +// invoking INT3 to raise a breakpoint signal. See the comments in the +// implementation for the protocol the debugger is expected to +// follow. InjectDebugCall in the runtime tests demonstrates this protocol. +// +// The debugger must ensure that any pointers passed to the function +// obey escape analysis requirements. Specifically, it must not pass +// a stack pointer to an escaping argument. debugCallV2 cannot check +// this invariant. +// +// This is ABIInternal because Go code injects its PC directly into new +// goroutine stacks. +TEXT runtime·debugCallV2(SB),NOSPLIT,$152-0 + // Save all registers that may contain pointers so they can be + // conservatively scanned. + // + // We can't do anything that might clobber any of these + // registers before this. + MOVQ R15, r15-(14*8+8)(SP) + MOVQ R14, r14-(13*8+8)(SP) + MOVQ R13, r13-(12*8+8)(SP) + MOVQ R12, r12-(11*8+8)(SP) + MOVQ R11, r11-(10*8+8)(SP) + MOVQ R10, r10-(9*8+8)(SP) + MOVQ R9, r9-(8*8+8)(SP) + MOVQ R8, r8-(7*8+8)(SP) + MOVQ DI, di-(6*8+8)(SP) + MOVQ SI, si-(5*8+8)(SP) + MOVQ BP, bp-(4*8+8)(SP) + MOVQ BX, bx-(3*8+8)(SP) + MOVQ DX, dx-(2*8+8)(SP) + // Save the frame size before we clobber it. Either of the last + // saves could clobber this depending on whether there's a saved BP. + MOVQ frameSize-24(FP), DX // aka -16(RSP) before prologue + MOVQ CX, cx-(1*8+8)(SP) + MOVQ AX, ax-(0*8+8)(SP) + + // Save the argument frame size. + MOVQ DX, frameSize-128(SP) + + // Perform a safe-point check. + MOVQ retpc-8(FP), AX // Caller's PC + MOVQ AX, 0(SP) + CALL runtime·debugCallCheck(SB) + MOVQ 8(SP), AX + TESTQ AX, AX + JZ good + // The safety check failed. Put the reason string at the top + // of the stack. + MOVQ AX, 0(SP) + MOVQ 16(SP), AX + MOVQ AX, 8(SP) + // Set R12 to 8 and invoke INT3. The debugger should get the + // reason a call can't be injected from the top of the stack + // and resume execution. + MOVQ $8, R12 + BYTE $0xcc + JMP restore + +good: + // Registers are saved and it's safe to make a call. + // Open up a call frame, moving the stack if necessary. + // + // Once the frame is allocated, this will set R12 to 0 and + // invoke INT3. The debugger should write the argument + // frame for the call at SP, set up argument registers, push + // the trapping PC on the stack, set the PC to the function to + // call, set RDX to point to the closure (if a closure call), + // and resume execution. + // + // If the function returns, this will set R12 to 1 and invoke + // INT3. The debugger can then inspect any return value saved + // on the stack at SP and in registers and resume execution again. + // + // If the function panics, this will set R12 to 2 and invoke INT3. + // The interface{} value of the panic will be at SP. The debugger + // can inspect the panic value and resume execution again. +#define DEBUG_CALL_DISPATCH(NAME,MAXSIZE) \ + CMPQ AX, $MAXSIZE; \ + JA 5(PC); \ + MOVQ $NAME(SB), AX; \ + MOVQ AX, 0(SP); \ + CALL runtime·debugCallWrap(SB); \ + JMP restore + + MOVQ frameSize-128(SP), AX + DEBUG_CALL_DISPATCH(debugCall32<>, 32) + DEBUG_CALL_DISPATCH(debugCall64<>, 64) + DEBUG_CALL_DISPATCH(debugCall128<>, 128) + DEBUG_CALL_DISPATCH(debugCall256<>, 256) + DEBUG_CALL_DISPATCH(debugCall512<>, 512) + DEBUG_CALL_DISPATCH(debugCall1024<>, 1024) + DEBUG_CALL_DISPATCH(debugCall2048<>, 2048) + DEBUG_CALL_DISPATCH(debugCall4096<>, 4096) + DEBUG_CALL_DISPATCH(debugCall8192<>, 8192) + DEBUG_CALL_DISPATCH(debugCall16384<>, 16384) + DEBUG_CALL_DISPATCH(debugCall32768<>, 32768) + DEBUG_CALL_DISPATCH(debugCall65536<>, 65536) + // The frame size is too large. Report the error. + MOVQ $debugCallFrameTooLarge<>(SB), AX + MOVQ AX, 0(SP) + MOVQ $20, 8(SP) // length of debugCallFrameTooLarge string + MOVQ $8, R12 + BYTE $0xcc + JMP restore + +restore: + // Calls and failures resume here. + // + // Set R12 to 16 and invoke INT3. The debugger should restore + // all registers except RIP and RSP and resume execution. + MOVQ $16, R12 + BYTE $0xcc + // We must not modify flags after this point. + + // Restore pointer-containing registers, which may have been + // modified from the debugger's copy by stack copying. + MOVQ ax-(0*8+8)(SP), AX + MOVQ cx-(1*8+8)(SP), CX + MOVQ dx-(2*8+8)(SP), DX + MOVQ bx-(3*8+8)(SP), BX + MOVQ bp-(4*8+8)(SP), BP + MOVQ si-(5*8+8)(SP), SI + MOVQ di-(6*8+8)(SP), DI + MOVQ r8-(7*8+8)(SP), R8 + MOVQ r9-(8*8+8)(SP), R9 + MOVQ r10-(9*8+8)(SP), R10 + MOVQ r11-(10*8+8)(SP), R11 + MOVQ r12-(11*8+8)(SP), R12 + MOVQ r13-(12*8+8)(SP), R13 + MOVQ r14-(13*8+8)(SP), R14 + MOVQ r15-(14*8+8)(SP), R15 + + RET + +// runtime.debugCallCheck assumes that functions defined with the +// DEBUG_CALL_FN macro are safe points to inject calls. +#define DEBUG_CALL_FN(NAME,MAXSIZE) \ +TEXT NAME(SB),WRAPPER,$MAXSIZE-0; \ + NO_LOCAL_POINTERS; \ + MOVQ $0, R12; \ + BYTE $0xcc; \ + MOVQ $1, R12; \ + BYTE $0xcc; \ + RET +DEBUG_CALL_FN(debugCall32<>, 32) +DEBUG_CALL_FN(debugCall64<>, 64) +DEBUG_CALL_FN(debugCall128<>, 128) +DEBUG_CALL_FN(debugCall256<>, 256) +DEBUG_CALL_FN(debugCall512<>, 512) +DEBUG_CALL_FN(debugCall1024<>, 1024) +DEBUG_CALL_FN(debugCall2048<>, 2048) +DEBUG_CALL_FN(debugCall4096<>, 4096) +DEBUG_CALL_FN(debugCall8192<>, 8192) +DEBUG_CALL_FN(debugCall16384<>, 16384) +DEBUG_CALL_FN(debugCall32768<>, 32768) +DEBUG_CALL_FN(debugCall65536<>, 65536) + +// func debugCallPanicked(val interface{}) +TEXT runtime·debugCallPanicked(SB),NOSPLIT,$16-16 + // Copy the panic value to the top of stack. + MOVQ val_type+0(FP), AX + MOVQ AX, 0(SP) + MOVQ val_data+8(FP), AX + MOVQ AX, 8(SP) + MOVQ $2, R12 + BYTE $0xcc + RET + +// Note: these functions use a special calling convention to save generated code space. +// Arguments are passed in registers, but the space for those arguments are allocated +// in the caller's stack frame. These stubs write the args into that stack space and +// then tail call to the corresponding runtime handler. +// The tail call makes these stubs disappear in backtraces. +// Defined as ABIInternal since they do not use the stack-based Go ABI. +TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 + MOVQ CX, BX + JMP runtime·goPanicIndex(SB) +TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 + MOVQ CX, BX + JMP runtime·goPanicIndexU(SB) +TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 + MOVQ CX, AX + MOVQ DX, BX + JMP runtime·goPanicSliceAlen(SB) +TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 + MOVQ CX, AX + MOVQ DX, BX + JMP runtime·goPanicSliceAlenU(SB) +TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 + MOVQ CX, AX + MOVQ DX, BX + JMP runtime·goPanicSliceAcap(SB) +TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 + MOVQ CX, AX + MOVQ DX, BX + JMP runtime·goPanicSliceAcapU(SB) +TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 + MOVQ CX, BX + JMP runtime·goPanicSliceB(SB) +TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 + MOVQ CX, BX + JMP runtime·goPanicSliceBU(SB) +TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 + MOVQ DX, AX + JMP runtime·goPanicSlice3Alen(SB) +TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 + MOVQ DX, AX + JMP runtime·goPanicSlice3AlenU(SB) +TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 + MOVQ DX, AX + JMP runtime·goPanicSlice3Acap(SB) +TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 + MOVQ DX, AX + JMP runtime·goPanicSlice3AcapU(SB) +TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 + MOVQ CX, AX + MOVQ DX, BX + JMP runtime·goPanicSlice3B(SB) +TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 + MOVQ CX, AX + MOVQ DX, BX + JMP runtime·goPanicSlice3BU(SB) +TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 + MOVQ CX, BX + JMP runtime·goPanicSlice3C(SB) +TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 + MOVQ CX, BX + JMP runtime·goPanicSlice3CU(SB) +TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 + MOVQ DX, AX + JMP runtime·goPanicSliceConvert(SB) + +#ifdef GOOS_android +// Use the free TLS_SLOT_APP slot #2 on Android Q. +// Earlier androids are set up in gcc_android.c. +DATA runtime·tls_g+0(SB)/8, $16 +GLOBL runtime·tls_g+0(SB), NOPTR, $8 +#endif +#ifdef GOOS_windows +GLOBL runtime·tls_g+0(SB), NOPTR, $8 +#endif + +// The compiler and assembler's -spectre=ret mode rewrites +// all indirect CALL AX / JMP AX instructions to be +// CALL retpolineAX / JMP retpolineAX. +// See https://support.google.com/faqs/answer/7625886. +#define RETPOLINE(reg) \ + /* CALL setup */ BYTE $0xE8; BYTE $(2+2); BYTE $0; BYTE $0; BYTE $0; \ + /* nospec: */ \ + /* PAUSE */ BYTE $0xF3; BYTE $0x90; \ + /* JMP nospec */ BYTE $0xEB; BYTE $-(2+2); \ + /* setup: */ \ + /* MOVQ AX, 0(SP) */ BYTE $0x48|((reg&8)>>1); BYTE $0x89; \ + BYTE $0x04|((reg&7)<<3); BYTE $0x24; \ + /* RET */ BYTE $0xC3 + +TEXT runtime·retpolineAX(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(0) +TEXT runtime·retpolineCX(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(1) +TEXT runtime·retpolineDX(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(2) +TEXT runtime·retpolineBX(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(3) +/* SP is 4, can't happen / magic encodings */ +TEXT runtime·retpolineBP(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(5) +TEXT runtime·retpolineSI(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(6) +TEXT runtime·retpolineDI(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(7) +TEXT runtime·retpolineR8(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(8) +TEXT runtime·retpolineR9(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(9) +TEXT runtime·retpolineR10(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(10) +TEXT runtime·retpolineR11(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(11) +TEXT runtime·retpolineR12(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(12) +TEXT runtime·retpolineR13(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(13) +TEXT runtime·retpolineR14(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(14) +TEXT runtime·retpolineR15(SB),NOSPLIT|NOFRAME,$0; RETPOLINE(15) + +TEXT ·getfp(SB),NOSPLIT|NOFRAME,$0 + MOVQ BP, AX + RET diff --git a/contrib/go/_std_1.22/src/runtime/asm_arm.s b/contrib/go/_std_1.23/src/runtime/asm_arm.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/asm_arm.s rename to contrib/go/_std_1.23/src/runtime/asm_arm.s index 31a0584fb5d8..4d57ec6062ce 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_arm.s +++ b/contrib/go/_std_1.23/src/runtime/asm_arm.s @@ -333,6 +333,30 @@ noswitch: MOVW.P 4(R13), R14 // restore LR B (R0) +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-4 + MOVW fn+0(FP), R7 // context register + MOVW g_m(g), R1 // curm + + // set g to gcrash + MOVW $runtime·gcrash(SB), R0 + BL setg<>(SB) // g = &gcrash + MOVW R1, g_m(g) // g.m = curm + MOVW g, m_g0(R1) // curm.g0 = g + + // switch to crashstack + MOVW (g_stack+stack_hi)(g), R1 + SUB $(4*8), R1 + MOVW R1, R13 + + // call target function + MOVW 0(R7), R0 + BL (R0) + + // should never return + CALL runtime·abort(SB) + UNDEF + /* * support for morestack */ @@ -349,6 +373,14 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 // Cannot grow scheduler stack (m->g0). MOVW g_m(g), R8 MOVW m_g0(R8), R4 + + // Called from f. + // Set g->sched to context in f. + MOVW R13, (g_sched+gobuf_sp)(g) + MOVW LR, (g_sched+gobuf_pc)(g) + MOVW R3, (g_sched+gobuf_lr)(g) + MOVW R7, (g_sched+gobuf_ctxt)(g) + CMP g, R4 BNE 3(PC) BL runtime·badmorestackg0(SB) @@ -361,13 +393,6 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 BL runtime·badmorestackgsignal(SB) B runtime·abort(SB) - // Called from f. - // Set g->sched to context in f. - MOVW R13, (g_sched+gobuf_sp)(g) - MOVW LR, (g_sched+gobuf_pc)(g) - MOVW R3, (g_sched+gobuf_lr)(g) - MOVW R7, (g_sched+gobuf_ctxt)(g) - // Called from f. // Set m->morebuf to f's caller. MOVW R3, (m_morebuf+gobuf_pc)(R8) // f's caller's PC diff --git a/contrib/go/_std_1.23/src/runtime/asm_arm64.s b/contrib/go/_std_1.23/src/runtime/asm_arm64.s new file mode 100644 index 000000000000..64a188058939 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/asm_arm64.s @@ -0,0 +1,1599 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "go_tls.h" +#include "tls_arm64.h" +#include "funcdata.h" +#include "textflag.h" + +TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 + // SP = stack; R0 = argc; R1 = argv + + SUB $32, RSP + MOVW R0, 8(RSP) // argc + MOVD R1, 16(RSP) // argv + +#ifdef TLS_darwin + // Initialize TLS. + MOVD ZR, g // clear g, make sure it's not junk. + SUB $32, RSP + MRS_TPIDR_R0 + AND $~7, R0 + MOVD R0, 16(RSP) // arg2: TLS base + MOVD $runtime·tls_g(SB), R2 + MOVD R2, 8(RSP) // arg1: &tlsg + BL ·tlsinit(SB) + ADD $32, RSP +#endif + + // create istack out of the given (operating system) stack. + // _cgo_init may update stackguard. + MOVD $runtime·g0(SB), g + MOVD RSP, R7 + MOVD $(-64*1024)(R7), R0 + MOVD R0, g_stackguard0(g) + MOVD R0, g_stackguard1(g) + MOVD R0, (g_stack+stack_lo)(g) + MOVD R7, (g_stack+stack_hi)(g) + + // if there is a _cgo_init, call it using the gcc ABI. + MOVD _cgo_init(SB), R12 + CBZ R12, nocgo + +#ifdef GOOS_android + MRS_TPIDR_R0 // load TLS base pointer + MOVD R0, R3 // arg 3: TLS base pointer + MOVD $runtime·tls_g(SB), R2 // arg 2: &tls_g +#else + MOVD $0, R2 // arg 2: not used when using platform's TLS +#endif + MOVD $setg_gcc<>(SB), R1 // arg 1: setg + MOVD g, R0 // arg 0: G + SUB $16, RSP // reserve 16 bytes for sp-8 where fp may be saved. + BL (R12) + ADD $16, RSP + +nocgo: + BL runtime·save_g(SB) + // update stackguard after _cgo_init + MOVD (g_stack+stack_lo)(g), R0 + ADD $const_stackGuard, R0 + MOVD R0, g_stackguard0(g) + MOVD R0, g_stackguard1(g) + + // set the per-goroutine and per-mach "registers" + MOVD $runtime·m0(SB), R0 + + // save m->g0 = g0 + MOVD g, m_g0(R0) + // save m0 to g0->m + MOVD R0, g_m(g) + + BL runtime·check(SB) + +#ifdef GOOS_windows + BL runtime·wintls(SB) +#endif + + MOVW 8(RSP), R0 // copy argc + MOVW R0, -8(RSP) + MOVD 16(RSP), R0 // copy argv + MOVD R0, 0(RSP) + BL runtime·args(SB) + BL runtime·osinit(SB) + BL runtime·schedinit(SB) + + // create a new goroutine to start program + MOVD $runtime·mainPC(SB), R0 // entry + SUB $16, RSP + MOVD R0, 8(RSP) // arg + MOVD $0, 0(RSP) // dummy LR + BL runtime·newproc(SB) + ADD $16, RSP + + // start this M + BL runtime·mstart(SB) + + // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are + // intended to be called by debuggers. + MOVD $runtime·debugPinnerV1(SB), R0 + MOVD $runtime·debugCallV2(SB), R0 + + MOVD $0, R0 + MOVD R0, (R0) // boom + UNDEF + +DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) +GLOBL runtime·mainPC(SB),RODATA,$8 + +// Windows ARM64 needs an immediate 0xf000 argument. +// See go.dev/issues/53837. +#define BREAK \ +#ifdef GOOS_windows \ + BRK $0xf000 \ +#else \ + BRK \ +#endif \ + + +TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0 + BREAK + RET + +TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0 + RET + +TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 + BL runtime·mstart0(SB) + RET // not reached + +/* + * go-routine + */ + +// void gogo(Gobuf*) +// restore state from Gobuf; longjmp +TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8 + MOVD buf+0(FP), R5 + MOVD gobuf_g(R5), R6 + MOVD 0(R6), R4 // make sure g != nil + B gogo<>(SB) + +TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 + MOVD R6, g + BL runtime·save_g(SB) + + MOVD gobuf_sp(R5), R0 + MOVD R0, RSP + MOVD gobuf_bp(R5), R29 + MOVD gobuf_lr(R5), LR + MOVD gobuf_ret(R5), R0 + MOVD gobuf_ctxt(R5), R26 + MOVD $0, gobuf_sp(R5) + MOVD $0, gobuf_bp(R5) + MOVD $0, gobuf_ret(R5) + MOVD $0, gobuf_lr(R5) + MOVD $0, gobuf_ctxt(R5) + CMP ZR, ZR // set condition codes for == test, needed by stack split + MOVD gobuf_pc(R5), R6 + B (R6) + +// void mcall(fn func(*g)) +// Switch to m->g0's stack, call fn(g). +// Fn must never return. It should gogo(&g->sched) +// to keep running g. +TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 + MOVD R0, R26 // context + + // Save caller state in g->sched + MOVD RSP, R0 + MOVD R0, (g_sched+gobuf_sp)(g) + MOVD R29, (g_sched+gobuf_bp)(g) + MOVD LR, (g_sched+gobuf_pc)(g) + MOVD $0, (g_sched+gobuf_lr)(g) + + // Switch to m->g0 & its stack, call fn. + MOVD g, R3 + MOVD g_m(g), R8 + MOVD m_g0(R8), g + BL runtime·save_g(SB) + CMP g, R3 + BNE 2(PC) + B runtime·badmcall(SB) + + MOVD (g_sched+gobuf_sp)(g), R0 + MOVD R0, RSP // sp = m->g0->sched.sp + MOVD (g_sched+gobuf_bp)(g), R29 + MOVD R3, R0 // arg = g + MOVD $0, -16(RSP) // dummy LR + SUB $16, RSP + MOVD 0(R26), R4 // code pointer + BL (R4) + B runtime·badmcall2(SB) + +// systemstack_switch is a dummy routine that systemstack leaves at the bottom +// of the G stack. We need to distinguish the routine that +// lives at the bottom of the G stack from the one that lives +// at the top of the system stack because the one at the top of +// the system stack terminates the stack walk (see topofstack()). +TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 + UNDEF + BL (LR) // make sure this function is not leaf + RET + +// func systemstack(fn func()) +TEXT runtime·systemstack(SB), NOSPLIT, $0-8 + MOVD fn+0(FP), R3 // R3 = fn + MOVD R3, R26 // context + MOVD g_m(g), R4 // R4 = m + + MOVD m_gsignal(R4), R5 // R5 = gsignal + CMP g, R5 + BEQ noswitch + + MOVD m_g0(R4), R5 // R5 = g0 + CMP g, R5 + BEQ noswitch + + MOVD m_curg(R4), R6 + CMP g, R6 + BEQ switch + + // Bad: g is not gsignal, not g0, not curg. What is it? + // Hide call from linker nosplit analysis. + MOVD $runtime·badsystemstack(SB), R3 + BL (R3) + B runtime·abort(SB) + +switch: + // save our state in g->sched. Pretend to + // be systemstack_switch if the G stack is scanned. + BL gosave_systemstack_switch<>(SB) + + // switch to g0 + MOVD R5, g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R3 + MOVD R3, RSP + MOVD (g_sched+gobuf_bp)(g), R29 + + // call target function + MOVD 0(R26), R3 // code pointer + BL (R3) + + // switch back to g + MOVD g_m(g), R3 + MOVD m_curg(R3), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R0 + MOVD R0, RSP + MOVD (g_sched+gobuf_bp)(g), R29 + MOVD $0, (g_sched+gobuf_sp)(g) + MOVD $0, (g_sched+gobuf_bp)(g) + RET + +noswitch: + // already on m stack, just call directly + // Using a tail call here cleans up tracebacks since we won't stop + // at an intermediate systemstack. + MOVD 0(R26), R3 // code pointer + MOVD.P 16(RSP), R30 // restore LR + SUB $8, RSP, R29 // restore FP + B (R3) + +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 + MOVD R0, R26 // context register + MOVD g_m(g), R1 // curm + + // set g to gcrash + MOVD $runtime·gcrash(SB), g // g = &gcrash + BL runtime·save_g(SB) // clobbers R0 + MOVD R1, g_m(g) // g.m = curm + MOVD g, m_g0(R1) // curm.g0 = g + + // switch to crashstack + MOVD (g_stack+stack_hi)(g), R1 + SUB $(4*8), R1 + MOVD R1, RSP + + // call target function + MOVD 0(R26), R0 + CALL (R0) + + // should never return + CALL runtime·abort(SB) + UNDEF + +/* + * support for morestack + */ + +// Called during function prolog when more stack is needed. +// Caller has already loaded: +// R3 prolog's LR (R30) +// +// The traceback routines see morestack on a g0 as being +// the top of a stack (for example, morestack calling newstack +// calling the scheduler calling newm calling gc), so we must +// record an argument size. For that purpose, it has no arguments. +TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 + // Cannot grow scheduler stack (m->g0). + MOVD g_m(g), R8 + MOVD m_g0(R8), R4 + + // Called from f. + // Set g->sched to context in f + MOVD RSP, R0 + MOVD R0, (g_sched+gobuf_sp)(g) + MOVD R29, (g_sched+gobuf_bp)(g) + MOVD LR, (g_sched+gobuf_pc)(g) + MOVD R3, (g_sched+gobuf_lr)(g) + MOVD R26, (g_sched+gobuf_ctxt)(g) + + CMP g, R4 + BNE 3(PC) + BL runtime·badmorestackg0(SB) + B runtime·abort(SB) + + // Cannot grow signal stack (m->gsignal). + MOVD m_gsignal(R8), R4 + CMP g, R4 + BNE 3(PC) + BL runtime·badmorestackgsignal(SB) + B runtime·abort(SB) + + // Called from f. + // Set m->morebuf to f's callers. + MOVD R3, (m_morebuf+gobuf_pc)(R8) // f's caller's PC + MOVD RSP, R0 + MOVD R0, (m_morebuf+gobuf_sp)(R8) // f's caller's RSP + MOVD g, (m_morebuf+gobuf_g)(R8) + + // Call newstack on m->g0's stack. + MOVD m_g0(R8), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R0 + MOVD R0, RSP + MOVD (g_sched+gobuf_bp)(g), R29 + MOVD.W $0, -16(RSP) // create a call frame on g0 (saved LR; keep 16-aligned) + BL runtime·newstack(SB) + + // Not reached, but make sure the return PC from the call to newstack + // is still in this function, and not the beginning of the next. + UNDEF + +TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 + // Force SPWRITE. This function doesn't actually write SP, + // but it is called with a special calling convention where + // the caller doesn't save LR on stack but passes it as a + // register (R3), and the unwinder currently doesn't understand. + // Make it SPWRITE to stop unwinding. (See issue 54332) + MOVD RSP, RSP + + MOVW $0, R26 + B runtime·morestack(SB) + +// spillArgs stores return values from registers to a *internal/abi.RegArgs in R20. +TEXT ·spillArgs(SB),NOSPLIT,$0-0 + STP (R0, R1), (0*8)(R20) + STP (R2, R3), (2*8)(R20) + STP (R4, R5), (4*8)(R20) + STP (R6, R7), (6*8)(R20) + STP (R8, R9), (8*8)(R20) + STP (R10, R11), (10*8)(R20) + STP (R12, R13), (12*8)(R20) + STP (R14, R15), (14*8)(R20) + FSTPD (F0, F1), (16*8)(R20) + FSTPD (F2, F3), (18*8)(R20) + FSTPD (F4, F5), (20*8)(R20) + FSTPD (F6, F7), (22*8)(R20) + FSTPD (F8, F9), (24*8)(R20) + FSTPD (F10, F11), (26*8)(R20) + FSTPD (F12, F13), (28*8)(R20) + FSTPD (F14, F15), (30*8)(R20) + RET + +// unspillArgs loads args into registers from a *internal/abi.RegArgs in R20. +TEXT ·unspillArgs(SB),NOSPLIT,$0-0 + LDP (0*8)(R20), (R0, R1) + LDP (2*8)(R20), (R2, R3) + LDP (4*8)(R20), (R4, R5) + LDP (6*8)(R20), (R6, R7) + LDP (8*8)(R20), (R8, R9) + LDP (10*8)(R20), (R10, R11) + LDP (12*8)(R20), (R12, R13) + LDP (14*8)(R20), (R14, R15) + FLDPD (16*8)(R20), (F0, F1) + FLDPD (18*8)(R20), (F2, F3) + FLDPD (20*8)(R20), (F4, F5) + FLDPD (22*8)(R20), (F6, F7) + FLDPD (24*8)(R20), (F8, F9) + FLDPD (26*8)(R20), (F10, F11) + FLDPD (28*8)(R20), (F12, F13) + FLDPD (30*8)(R20), (F14, F15) + RET + +// reflectcall: call a function with the given argument list +// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). +// we don't have variable-sized frames, so we use a small number +// of constant-sized-frame functions to encode a few bits of size in the pc. +// Caution: ugly multiline assembly macros in your future! + +#define DISPATCH(NAME,MAXSIZE) \ + MOVD $MAXSIZE, R27; \ + CMP R27, R16; \ + BGT 3(PC); \ + MOVD $NAME(SB), R27; \ + B (R27) +// Note: can't just "B NAME(SB)" - bad inlining results. + +TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-48 + MOVWU frameSize+32(FP), R16 + DISPATCH(runtime·call16, 16) + DISPATCH(runtime·call32, 32) + DISPATCH(runtime·call64, 64) + DISPATCH(runtime·call128, 128) + DISPATCH(runtime·call256, 256) + DISPATCH(runtime·call512, 512) + DISPATCH(runtime·call1024, 1024) + DISPATCH(runtime·call2048, 2048) + DISPATCH(runtime·call4096, 4096) + DISPATCH(runtime·call8192, 8192) + DISPATCH(runtime·call16384, 16384) + DISPATCH(runtime·call32768, 32768) + DISPATCH(runtime·call65536, 65536) + DISPATCH(runtime·call131072, 131072) + DISPATCH(runtime·call262144, 262144) + DISPATCH(runtime·call524288, 524288) + DISPATCH(runtime·call1048576, 1048576) + DISPATCH(runtime·call2097152, 2097152) + DISPATCH(runtime·call4194304, 4194304) + DISPATCH(runtime·call8388608, 8388608) + DISPATCH(runtime·call16777216, 16777216) + DISPATCH(runtime·call33554432, 33554432) + DISPATCH(runtime·call67108864, 67108864) + DISPATCH(runtime·call134217728, 134217728) + DISPATCH(runtime·call268435456, 268435456) + DISPATCH(runtime·call536870912, 536870912) + DISPATCH(runtime·call1073741824, 1073741824) + MOVD $runtime·badreflectcall(SB), R0 + B (R0) + +#define CALLFN(NAME,MAXSIZE) \ +TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ + NO_LOCAL_POINTERS; \ + /* copy arguments to stack */ \ + MOVD stackArgs+16(FP), R3; \ + MOVWU stackArgsSize+24(FP), R4; \ + ADD $8, RSP, R5; \ + BIC $0xf, R4, R6; \ + CBZ R6, 6(PC); \ + /* if R6=(argsize&~15) != 0 */ \ + ADD R6, R5, R6; \ + /* copy 16 bytes a time */ \ + LDP.P 16(R3), (R7, R8); \ + STP.P (R7, R8), 16(R5); \ + CMP R5, R6; \ + BNE -3(PC); \ + AND $0xf, R4, R6; \ + CBZ R6, 6(PC); \ + /* if R6=(argsize&15) != 0 */ \ + ADD R6, R5, R6; \ + /* copy 1 byte a time for the rest */ \ + MOVBU.P 1(R3), R7; \ + MOVBU.P R7, 1(R5); \ + CMP R5, R6; \ + BNE -3(PC); \ + /* set up argument registers */ \ + MOVD regArgs+40(FP), R20; \ + CALL ·unspillArgs(SB); \ + /* call function */ \ + MOVD f+8(FP), R26; \ + MOVD (R26), R20; \ + PCDATA $PCDATA_StackMapIndex, $0; \ + BL (R20); \ + /* copy return values back */ \ + MOVD regArgs+40(FP), R20; \ + CALL ·spillArgs(SB); \ + MOVD stackArgsType+0(FP), R7; \ + MOVD stackArgs+16(FP), R3; \ + MOVWU stackArgsSize+24(FP), R4; \ + MOVWU stackRetOffset+28(FP), R6; \ + ADD $8, RSP, R5; \ + ADD R6, R5; \ + ADD R6, R3; \ + SUB R6, R4; \ + BL callRet<>(SB); \ + RET + +// callRet copies return values back at the end of call*. This is a +// separate function so it can allocate stack space for the arguments +// to reflectcallmove. It does not follow the Go ABI; it expects its +// arguments in registers. +TEXT callRet<>(SB), NOSPLIT, $48-0 + NO_LOCAL_POINTERS + STP (R7, R3), 8(RSP) + STP (R5, R4), 24(RSP) + MOVD R20, 40(RSP) + BL runtime·reflectcallmove(SB) + RET + +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) + +// func memhash32(p unsafe.Pointer, h uintptr) uintptr +TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 + MOVB runtime·useAeshash(SB), R10 + CBZ R10, noaes + MOVD $runtime·aeskeysched+0(SB), R3 + + VEOR V0.B16, V0.B16, V0.B16 + VLD1 (R3), [V2.B16] + VLD1 (R0), V0.S[1] + VMOV R1, V0.S[0] + + AESE V2.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V2.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V2.B16, V0.B16 + + VMOV V0.D[0], R0 + RET +noaes: + B runtime·memhash32Fallback(SB) + +// func memhash64(p unsafe.Pointer, h uintptr) uintptr +TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 + MOVB runtime·useAeshash(SB), R10 + CBZ R10, noaes + MOVD $runtime·aeskeysched+0(SB), R3 + + VEOR V0.B16, V0.B16, V0.B16 + VLD1 (R3), [V2.B16] + VLD1 (R0), V0.D[1] + VMOV R1, V0.D[0] + + AESE V2.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V2.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V2.B16, V0.B16 + + VMOV V0.D[0], R0 + RET +noaes: + B runtime·memhash64Fallback(SB) + +// func memhash(p unsafe.Pointer, h, size uintptr) uintptr +TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 + MOVB runtime·useAeshash(SB), R10 + CBZ R10, noaes + B aeshashbody<>(SB) +noaes: + B runtime·memhashFallback(SB) + +// func strhash(p unsafe.Pointer, h uintptr) uintptr +TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 + MOVB runtime·useAeshash(SB), R10 + CBZ R10, noaes + LDP (R0), (R0, R2) // string data / length + B aeshashbody<>(SB) +noaes: + B runtime·strhashFallback(SB) + +// R0: data +// R1: seed data +// R2: length +// At return, R0 = return value +TEXT aeshashbody<>(SB),NOSPLIT|NOFRAME,$0 + VEOR V30.B16, V30.B16, V30.B16 + VMOV R1, V30.D[0] + VMOV R2, V30.D[1] // load length into seed + + MOVD $runtime·aeskeysched+0(SB), R4 + VLD1.P 16(R4), [V0.B16] + AESE V30.B16, V0.B16 + AESMC V0.B16, V0.B16 + CMP $16, R2 + BLO aes0to15 + BEQ aes16 + CMP $32, R2 + BLS aes17to32 + CMP $64, R2 + BLS aes33to64 + CMP $128, R2 + BLS aes65to128 + B aes129plus + +aes0to15: + CBZ R2, aes0 + VEOR V2.B16, V2.B16, V2.B16 + TBZ $3, R2, less_than_8 + VLD1.P 8(R0), V2.D[0] + +less_than_8: + TBZ $2, R2, less_than_4 + VLD1.P 4(R0), V2.S[2] + +less_than_4: + TBZ $1, R2, less_than_2 + VLD1.P 2(R0), V2.H[6] + +less_than_2: + TBZ $0, R2, done + VLD1 (R0), V2.B[14] +done: + AESE V0.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V0.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V0.B16, V2.B16 + AESMC V2.B16, V2.B16 + + VMOV V2.D[0], R0 + RET + +aes0: + VMOV V0.D[0], R0 + RET + +aes16: + VLD1 (R0), [V2.B16] + B done + +aes17to32: + // make second seed + VLD1 (R4), [V1.B16] + AESE V30.B16, V1.B16 + AESMC V1.B16, V1.B16 + SUB $16, R2, R10 + VLD1.P (R0)(R10), [V2.B16] + VLD1 (R0), [V3.B16] + + AESE V0.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V1.B16, V3.B16 + AESMC V3.B16, V3.B16 + + AESE V0.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V1.B16, V3.B16 + AESMC V3.B16, V3.B16 + + AESE V0.B16, V2.B16 + AESE V1.B16, V3.B16 + + VEOR V3.B16, V2.B16, V2.B16 + + VMOV V2.D[0], R0 + RET + +aes33to64: + VLD1 (R4), [V1.B16, V2.B16, V3.B16] + AESE V30.B16, V1.B16 + AESMC V1.B16, V1.B16 + AESE V30.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V30.B16, V3.B16 + AESMC V3.B16, V3.B16 + SUB $32, R2, R10 + + VLD1.P (R0)(R10), [V4.B16, V5.B16] + VLD1 (R0), [V6.B16, V7.B16] + + AESE V0.B16, V4.B16 + AESMC V4.B16, V4.B16 + AESE V1.B16, V5.B16 + AESMC V5.B16, V5.B16 + AESE V2.B16, V6.B16 + AESMC V6.B16, V6.B16 + AESE V3.B16, V7.B16 + AESMC V7.B16, V7.B16 + + AESE V0.B16, V4.B16 + AESMC V4.B16, V4.B16 + AESE V1.B16, V5.B16 + AESMC V5.B16, V5.B16 + AESE V2.B16, V6.B16 + AESMC V6.B16, V6.B16 + AESE V3.B16, V7.B16 + AESMC V7.B16, V7.B16 + + AESE V0.B16, V4.B16 + AESE V1.B16, V5.B16 + AESE V2.B16, V6.B16 + AESE V3.B16, V7.B16 + + VEOR V6.B16, V4.B16, V4.B16 + VEOR V7.B16, V5.B16, V5.B16 + VEOR V5.B16, V4.B16, V4.B16 + + VMOV V4.D[0], R0 + RET + +aes65to128: + VLD1.P 64(R4), [V1.B16, V2.B16, V3.B16, V4.B16] + VLD1 (R4), [V5.B16, V6.B16, V7.B16] + AESE V30.B16, V1.B16 + AESMC V1.B16, V1.B16 + AESE V30.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V30.B16, V3.B16 + AESMC V3.B16, V3.B16 + AESE V30.B16, V4.B16 + AESMC V4.B16, V4.B16 + AESE V30.B16, V5.B16 + AESMC V5.B16, V5.B16 + AESE V30.B16, V6.B16 + AESMC V6.B16, V6.B16 + AESE V30.B16, V7.B16 + AESMC V7.B16, V7.B16 + + SUB $64, R2, R10 + VLD1.P (R0)(R10), [V8.B16, V9.B16, V10.B16, V11.B16] + VLD1 (R0), [V12.B16, V13.B16, V14.B16, V15.B16] + AESE V0.B16, V8.B16 + AESMC V8.B16, V8.B16 + AESE V1.B16, V9.B16 + AESMC V9.B16, V9.B16 + AESE V2.B16, V10.B16 + AESMC V10.B16, V10.B16 + AESE V3.B16, V11.B16 + AESMC V11.B16, V11.B16 + AESE V4.B16, V12.B16 + AESMC V12.B16, V12.B16 + AESE V5.B16, V13.B16 + AESMC V13.B16, V13.B16 + AESE V6.B16, V14.B16 + AESMC V14.B16, V14.B16 + AESE V7.B16, V15.B16 + AESMC V15.B16, V15.B16 + + AESE V0.B16, V8.B16 + AESMC V8.B16, V8.B16 + AESE V1.B16, V9.B16 + AESMC V9.B16, V9.B16 + AESE V2.B16, V10.B16 + AESMC V10.B16, V10.B16 + AESE V3.B16, V11.B16 + AESMC V11.B16, V11.B16 + AESE V4.B16, V12.B16 + AESMC V12.B16, V12.B16 + AESE V5.B16, V13.B16 + AESMC V13.B16, V13.B16 + AESE V6.B16, V14.B16 + AESMC V14.B16, V14.B16 + AESE V7.B16, V15.B16 + AESMC V15.B16, V15.B16 + + AESE V0.B16, V8.B16 + AESE V1.B16, V9.B16 + AESE V2.B16, V10.B16 + AESE V3.B16, V11.B16 + AESE V4.B16, V12.B16 + AESE V5.B16, V13.B16 + AESE V6.B16, V14.B16 + AESE V7.B16, V15.B16 + + VEOR V12.B16, V8.B16, V8.B16 + VEOR V13.B16, V9.B16, V9.B16 + VEOR V14.B16, V10.B16, V10.B16 + VEOR V15.B16, V11.B16, V11.B16 + VEOR V10.B16, V8.B16, V8.B16 + VEOR V11.B16, V9.B16, V9.B16 + VEOR V9.B16, V8.B16, V8.B16 + + VMOV V8.D[0], R0 + RET + +aes129plus: + PRFM (R0), PLDL1KEEP + VLD1.P 64(R4), [V1.B16, V2.B16, V3.B16, V4.B16] + VLD1 (R4), [V5.B16, V6.B16, V7.B16] + AESE V30.B16, V1.B16 + AESMC V1.B16, V1.B16 + AESE V30.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V30.B16, V3.B16 + AESMC V3.B16, V3.B16 + AESE V30.B16, V4.B16 + AESMC V4.B16, V4.B16 + AESE V30.B16, V5.B16 + AESMC V5.B16, V5.B16 + AESE V30.B16, V6.B16 + AESMC V6.B16, V6.B16 + AESE V30.B16, V7.B16 + AESMC V7.B16, V7.B16 + ADD R0, R2, R10 + SUB $128, R10, R10 + VLD1.P 64(R10), [V8.B16, V9.B16, V10.B16, V11.B16] + VLD1 (R10), [V12.B16, V13.B16, V14.B16, V15.B16] + SUB $1, R2, R2 + LSR $7, R2, R2 + +aesloop: + AESE V8.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V9.B16, V1.B16 + AESMC V1.B16, V1.B16 + AESE V10.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V11.B16, V3.B16 + AESMC V3.B16, V3.B16 + AESE V12.B16, V4.B16 + AESMC V4.B16, V4.B16 + AESE V13.B16, V5.B16 + AESMC V5.B16, V5.B16 + AESE V14.B16, V6.B16 + AESMC V6.B16, V6.B16 + AESE V15.B16, V7.B16 + AESMC V7.B16, V7.B16 + + VLD1.P 64(R0), [V8.B16, V9.B16, V10.B16, V11.B16] + AESE V8.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V9.B16, V1.B16 + AESMC V1.B16, V1.B16 + AESE V10.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V11.B16, V3.B16 + AESMC V3.B16, V3.B16 + + VLD1.P 64(R0), [V12.B16, V13.B16, V14.B16, V15.B16] + AESE V12.B16, V4.B16 + AESMC V4.B16, V4.B16 + AESE V13.B16, V5.B16 + AESMC V5.B16, V5.B16 + AESE V14.B16, V6.B16 + AESMC V6.B16, V6.B16 + AESE V15.B16, V7.B16 + AESMC V7.B16, V7.B16 + SUB $1, R2, R2 + CBNZ R2, aesloop + + AESE V8.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V9.B16, V1.B16 + AESMC V1.B16, V1.B16 + AESE V10.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V11.B16, V3.B16 + AESMC V3.B16, V3.B16 + AESE V12.B16, V4.B16 + AESMC V4.B16, V4.B16 + AESE V13.B16, V5.B16 + AESMC V5.B16, V5.B16 + AESE V14.B16, V6.B16 + AESMC V6.B16, V6.B16 + AESE V15.B16, V7.B16 + AESMC V7.B16, V7.B16 + + AESE V8.B16, V0.B16 + AESMC V0.B16, V0.B16 + AESE V9.B16, V1.B16 + AESMC V1.B16, V1.B16 + AESE V10.B16, V2.B16 + AESMC V2.B16, V2.B16 + AESE V11.B16, V3.B16 + AESMC V3.B16, V3.B16 + AESE V12.B16, V4.B16 + AESMC V4.B16, V4.B16 + AESE V13.B16, V5.B16 + AESMC V5.B16, V5.B16 + AESE V14.B16, V6.B16 + AESMC V6.B16, V6.B16 + AESE V15.B16, V7.B16 + AESMC V7.B16, V7.B16 + + AESE V8.B16, V0.B16 + AESE V9.B16, V1.B16 + AESE V10.B16, V2.B16 + AESE V11.B16, V3.B16 + AESE V12.B16, V4.B16 + AESE V13.B16, V5.B16 + AESE V14.B16, V6.B16 + AESE V15.B16, V7.B16 + + VEOR V0.B16, V1.B16, V0.B16 + VEOR V2.B16, V3.B16, V2.B16 + VEOR V4.B16, V5.B16, V4.B16 + VEOR V6.B16, V7.B16, V6.B16 + VEOR V0.B16, V2.B16, V0.B16 + VEOR V4.B16, V6.B16, V4.B16 + VEOR V4.B16, V0.B16, V0.B16 + + VMOV V0.D[0], R0 + RET + +TEXT runtime·procyield(SB),NOSPLIT,$0-0 + MOVWU cycles+0(FP), R0 +again: + YIELD + SUBW $1, R0 + CBNZ R0, again + RET + +// Save state of caller into g->sched, +// but using fake PC from systemstack_switch. +// Must only be called from functions with no locals ($0) +// or else unwinding from systemstack_switch is incorrect. +// Smashes R0. +TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 + MOVD $runtime·systemstack_switch(SB), R0 + ADD $8, R0 // get past prologue + MOVD R0, (g_sched+gobuf_pc)(g) + MOVD RSP, R0 + MOVD R0, (g_sched+gobuf_sp)(g) + MOVD R29, (g_sched+gobuf_bp)(g) + MOVD $0, (g_sched+gobuf_lr)(g) + MOVD $0, (g_sched+gobuf_ret)(g) + // Assert ctxt is zero. See func save. + MOVD (g_sched+gobuf_ctxt)(g), R0 + CBZ R0, 2(PC) + CALL runtime·abort(SB) + RET + +// func asmcgocall_no_g(fn, arg unsafe.Pointer) +// Call fn(arg) aligned appropriately for the gcc ABI. +// Called on a system stack, and there may be no g yet (during needm). +TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16 + MOVD fn+0(FP), R1 + MOVD arg+8(FP), R0 + SUB $16, RSP // skip over saved frame pointer below RSP + BL (R1) + ADD $16, RSP // skip over saved frame pointer below RSP + RET + +// func asmcgocall(fn, arg unsafe.Pointer) int32 +// Call fn(arg) on the scheduler stack, +// aligned appropriately for the gcc ABI. +// See cgocall.go for more details. +TEXT ·asmcgocall(SB),NOSPLIT,$0-20 + MOVD fn+0(FP), R1 + MOVD arg+8(FP), R0 + + MOVD RSP, R2 // save original stack pointer + CBZ g, nosave + MOVD g, R4 + + // Figure out if we need to switch to m->g0 stack. + // We get called to create new OS threads too, and those + // come in on the m->g0 stack already. Or we might already + // be on the m->gsignal stack. + MOVD g_m(g), R8 + MOVD m_gsignal(R8), R3 + CMP R3, g + BEQ nosave + MOVD m_g0(R8), R3 + CMP R3, g + BEQ nosave + + // Switch to system stack. + MOVD R0, R9 // gosave_systemstack_switch<> and save_g might clobber R0 + BL gosave_systemstack_switch<>(SB) + MOVD R3, g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R0 + MOVD R0, RSP + MOVD (g_sched+gobuf_bp)(g), R29 + MOVD R9, R0 + + // Now on a scheduling stack (a pthread-created stack). + // Save room for two of our pointers /*, plus 32 bytes of callee + // save area that lives on the caller stack. */ + MOVD RSP, R13 + SUB $16, R13 + MOVD R13, RSP + MOVD R4, 0(RSP) // save old g on stack + MOVD (g_stack+stack_hi)(R4), R4 + SUB R2, R4 + MOVD R4, 8(RSP) // save depth in old g stack (can't just save SP, as stack might be copied during a callback) + BL (R1) + MOVD R0, R9 + + // Restore g, stack pointer. R0 is errno, so don't touch it + MOVD 0(RSP), g + BL runtime·save_g(SB) + MOVD (g_stack+stack_hi)(g), R5 + MOVD 8(RSP), R6 + SUB R6, R5 + MOVD R9, R0 + MOVD R5, RSP + + MOVW R0, ret+16(FP) + RET + +nosave: + // Running on a system stack, perhaps even without a g. + // Having no g can happen during thread creation or thread teardown + // (see needm/dropm on Solaris, for example). + // This code is like the above sequence but without saving/restoring g + // and without worrying about the stack moving out from under us + // (because we're on a system stack, not a goroutine stack). + // The above code could be used directly if already on a system stack, + // but then the only path through this code would be a rare case on Solaris. + // Using this code for all "already on system stack" calls exercises it more, + // which should help keep it correct. + MOVD RSP, R13 + SUB $16, R13 + MOVD R13, RSP + MOVD $0, R4 + MOVD R4, 0(RSP) // Where above code stores g, in case someone looks during debugging. + MOVD R2, 8(RSP) // Save original stack pointer. + BL (R1) + // Restore stack pointer. + MOVD 8(RSP), R2 + MOVD R2, RSP + MOVD R0, ret+16(FP) + RET + +// cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) +// See cgocall.go for more details. +TEXT ·cgocallback(SB),NOSPLIT,$24-24 + NO_LOCAL_POINTERS + + // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. + // It is used to dropm while thread is exiting. + MOVD fn+0(FP), R1 + CBNZ R1, loadg + // Restore the g from frame. + MOVD frame+8(FP), g + B dropm + +loadg: + // Load g from thread-local storage. + BL runtime·load_g(SB) + + // If g is nil, Go did not create the current thread, + // or if this thread never called into Go on pthread platforms. + // Call needm to obtain one for temporary use. + // In this case, we're running on the thread stack, so there's + // lots of space, but the linker doesn't know. Hide the call from + // the linker analysis by using an indirect call. + CBZ g, needm + + MOVD g_m(g), R8 + MOVD R8, savedm-8(SP) + B havem + +needm: + MOVD g, savedm-8(SP) // g is zero, so is m. + MOVD $runtime·needAndBindM(SB), R0 + BL (R0) + + // Set m->g0->sched.sp = SP, so that if a panic happens + // during the function we are about to execute, it will + // have a valid SP to run on the g0 stack. + // The next few lines (after the havem label) + // will save this SP onto the stack and then write + // the same SP back to m->sched.sp. That seems redundant, + // but if an unrecovered panic happens, unwindm will + // restore the g->sched.sp from the stack location + // and then systemstack will try to use it. If we don't set it here, + // that restored SP will be uninitialized (typically 0) and + // will not be usable. + MOVD g_m(g), R8 + MOVD m_g0(R8), R3 + MOVD RSP, R0 + MOVD R0, (g_sched+gobuf_sp)(R3) + MOVD R29, (g_sched+gobuf_bp)(R3) + +havem: + // Now there's a valid m, and we're running on its m->g0. + // Save current m->g0->sched.sp on stack and then set it to SP. + // Save current sp in m->g0->sched.sp in preparation for + // switch back to m->curg stack. + // NOTE: unwindm knows that the saved g->sched.sp is at 16(RSP) aka savedsp-16(SP). + // Beware that the frame size is actually 32+16. + MOVD m_g0(R8), R3 + MOVD (g_sched+gobuf_sp)(R3), R4 + MOVD R4, savedsp-16(SP) + MOVD RSP, R0 + MOVD R0, (g_sched+gobuf_sp)(R3) + + // Switch to m->curg stack and call runtime.cgocallbackg. + // Because we are taking over the execution of m->curg + // but *not* resuming what had been running, we need to + // save that information (m->curg->sched) so we can restore it. + // We can restore m->curg->sched.sp easily, because calling + // runtime.cgocallbackg leaves SP unchanged upon return. + // To save m->curg->sched.pc, we push it onto the curg stack and + // open a frame the same size as cgocallback's g0 frame. + // Once we switch to the curg stack, the pushed PC will appear + // to be the return PC of cgocallback, so that the traceback + // will seamlessly trace back into the earlier calls. + MOVD m_curg(R8), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 + MOVD (g_sched+gobuf_pc)(g), R5 + MOVD R5, -48(R4) + MOVD (g_sched+gobuf_bp)(g), R5 + MOVD R5, -56(R4) + // Gather our arguments into registers. + MOVD fn+0(FP), R1 + MOVD frame+8(FP), R2 + MOVD ctxt+16(FP), R3 + MOVD $-48(R4), R0 // maintain 16-byte SP alignment + MOVD R0, RSP // switch stack + MOVD R1, 8(RSP) + MOVD R2, 16(RSP) + MOVD R3, 24(RSP) + MOVD $runtime·cgocallbackg(SB), R0 + CALL (R0) // indirect call to bypass nosplit check. We're on a different stack now. + + // Restore g->sched (== m->curg->sched) from saved values. + MOVD 0(RSP), R5 + MOVD R5, (g_sched+gobuf_pc)(g) + MOVD RSP, R4 + ADD $48, R4, R4 + MOVD R4, (g_sched+gobuf_sp)(g) + + // Switch back to m->g0's stack and restore m->g0->sched.sp. + // (Unlike m->curg, the g0 goroutine never uses sched.pc, + // so we do not have to restore it.) + MOVD g_m(g), R8 + MOVD m_g0(R8), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R0 + MOVD R0, RSP + MOVD savedsp-16(SP), R4 + MOVD R4, (g_sched+gobuf_sp)(g) + + // If the m on entry was nil, we called needm above to borrow an m, + // 1. for the duration of the call on non-pthread platforms, + // 2. or the duration of the C thread alive on pthread platforms. + // If the m on entry wasn't nil, + // 1. the thread might be a Go thread, + // 2. or it wasn't the first call from a C thread on pthread platforms, + // since then we skip dropm to reuse the m in the first call. + MOVD savedm-8(SP), R6 + CBNZ R6, droppedm + + // Skip dropm to reuse it in the next call, when a pthread key has been created. + MOVD _cgo_pthread_key_created(SB), R6 + // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. + CBZ R6, dropm + MOVD (R6), R6 + CBNZ R6, droppedm + +dropm: + MOVD $runtime·dropm(SB), R0 + BL (R0) +droppedm: + + // Done! + RET + +// Called from cgo wrappers, this function returns g->m->curg.stack.hi. +// Must obey the gcc calling convention. +TEXT _cgo_topofstack(SB),NOSPLIT,$24 + // g (R28) and REGTMP (R27) might be clobbered by load_g. They + // are callee-save in the gcc calling convention, so save them. + MOVD R27, savedR27-8(SP) + MOVD g, saveG-16(SP) + + BL runtime·load_g(SB) + MOVD g_m(g), R0 + MOVD m_curg(R0), R0 + MOVD (g_stack+stack_hi)(R0), R0 + + MOVD saveG-16(SP), g + MOVD savedR28-8(SP), R27 + RET + +// void setg(G*); set g. for use by needm. +TEXT runtime·setg(SB), NOSPLIT, $0-8 + MOVD gg+0(FP), g + // This only happens if iscgo, so jump straight to save_g + BL runtime·save_g(SB) + RET + +// void setg_gcc(G*); set g called from gcc +TEXT setg_gcc<>(SB),NOSPLIT,$8 + MOVD R0, g + MOVD R27, savedR27-8(SP) + BL runtime·save_g(SB) + MOVD savedR27-8(SP), R27 + RET + +TEXT runtime·emptyfunc(SB),0,$0-0 + RET + +TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 + MOVD ZR, R0 + MOVD (R0), R0 + UNDEF + +TEXT runtime·return0(SB), NOSPLIT, $0 + MOVW $0, R0 + RET + +// The top-most function running on a goroutine +// returns to goexit+PCQuantum. +TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 + MOVD R0, R0 // NOP + BL runtime·goexit1(SB) // does not return + +// This is called from .init_array and follows the platform, not Go, ABI. +TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 + SUB $0x10, RSP + MOVD R27, 8(RSP) // The access to global variables below implicitly uses R27, which is callee-save + MOVD runtime·lastmoduledatap(SB), R1 + MOVD R0, moduledata_next(R1) + MOVD R0, runtime·lastmoduledatap(SB) + MOVD 8(RSP), R27 + ADD $0x10, RSP + RET + +TEXT ·checkASM(SB),NOSPLIT,$0-1 + MOVW $1, R3 + MOVB R3, ret+0(FP) + RET + +// gcWriteBarrier informs the GC about heap pointer writes. +// +// gcWriteBarrier does NOT follow the Go ABI. It accepts the +// number of bytes of buffer needed in R25, and returns a pointer +// to the buffer space in R25. +// It clobbers condition codes. +// It does not clobber any general-purpose registers except R27, +// but may clobber others (e.g., floating point registers) +// The act of CALLing gcWriteBarrier will clobber R30 (LR). +TEXT gcWriteBarrier<>(SB),NOSPLIT,$200 + // Save the registers clobbered by the fast path. + STP (R0, R1), 184(RSP) +retry: + MOVD g_m(g), R0 + MOVD m_p(R0), R0 + MOVD (p_wbBuf+wbBuf_next)(R0), R1 + MOVD (p_wbBuf+wbBuf_end)(R0), R27 + // Increment wbBuf.next position. + ADD R25, R1 + // Is the buffer full? + CMP R27, R1 + BHI flush + // Commit to the larger buffer. + MOVD R1, (p_wbBuf+wbBuf_next)(R0) + // Make return value (the original next position) + SUB R25, R1, R25 + // Restore registers. + LDP 184(RSP), (R0, R1) + RET + +flush: + // Save all general purpose registers since these could be + // clobbered by wbBufFlush and were not saved by the caller. + // R0 and R1 already saved + STP (R2, R3), 1*8(RSP) + STP (R4, R5), 3*8(RSP) + STP (R6, R7), 5*8(RSP) + STP (R8, R9), 7*8(RSP) + STP (R10, R11), 9*8(RSP) + STP (R12, R13), 11*8(RSP) + STP (R14, R15), 13*8(RSP) + // R16, R17 may be clobbered by linker trampoline + // R18 is unused. + STP (R19, R20), 15*8(RSP) + STP (R21, R22), 17*8(RSP) + STP (R23, R24), 19*8(RSP) + STP (R25, R26), 21*8(RSP) + // R27 is temp register. + // R28 is g. + // R29 is frame pointer (unused). + // R30 is LR, which was saved by the prologue. + // R31 is SP. + + CALL runtime·wbBufFlush(SB) + LDP 1*8(RSP), (R2, R3) + LDP 3*8(RSP), (R4, R5) + LDP 5*8(RSP), (R6, R7) + LDP 7*8(RSP), (R8, R9) + LDP 9*8(RSP), (R10, R11) + LDP 11*8(RSP), (R12, R13) + LDP 13*8(RSP), (R14, R15) + LDP 15*8(RSP), (R19, R20) + LDP 17*8(RSP), (R21, R22) + LDP 19*8(RSP), (R23, R24) + LDP 21*8(RSP), (R25, R26) + JMP retry + +TEXT runtime·gcWriteBarrier1(SB),NOSPLIT,$0 + MOVD $8, R25 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier2(SB),NOSPLIT,$0 + MOVD $16, R25 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier3(SB),NOSPLIT,$0 + MOVD $24, R25 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier4(SB),NOSPLIT,$0 + MOVD $32, R25 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier5(SB),NOSPLIT,$0 + MOVD $40, R25 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier6(SB),NOSPLIT,$0 + MOVD $48, R25 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier7(SB),NOSPLIT,$0 + MOVD $56, R25 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier8(SB),NOSPLIT,$0 + MOVD $64, R25 + JMP gcWriteBarrier<>(SB) + +DATA debugCallFrameTooLarge<>+0x00(SB)/20, $"call frame too large" +GLOBL debugCallFrameTooLarge<>(SB), RODATA, $20 // Size duplicated below + +// debugCallV2 is the entry point for debugger-injected function +// calls on running goroutines. It informs the runtime that a +// debug call has been injected and creates a call frame for the +// debugger to fill in. +// +// To inject a function call, a debugger should: +// 1. Check that the goroutine is in state _Grunning and that +// there are at least 288 bytes free on the stack. +// 2. Set SP as SP-16. +// 3. Store the current LR in (SP) (using the SP after step 2). +// 4. Store the current PC in the LR register. +// 5. Write the desired argument frame size at SP-16 +// 6. Save all machine registers (including flags and fpsimd registers) +// so they can be restored later by the debugger. +// 7. Set the PC to debugCallV2 and resume execution. +// +// If the goroutine is in state _Grunnable, then it's not generally +// safe to inject a call because it may return out via other runtime +// operations. Instead, the debugger should unwind the stack to find +// the return to non-runtime code, add a temporary breakpoint there, +// and inject the call once that breakpoint is hit. +// +// If the goroutine is in any other state, it's not safe to inject a call. +// +// This function communicates back to the debugger by setting R20 and +// invoking BRK to raise a breakpoint signal. Note that the signal PC of +// the signal triggered by the BRK instruction is the PC where the signal +// is trapped, not the next PC, so to resume execution, the debugger needs +// to set the signal PC to PC+4. See the comments in the implementation for +// the protocol the debugger is expected to follow. InjectDebugCall in the +// runtime tests demonstrates this protocol. +// +// The debugger must ensure that any pointers passed to the function +// obey escape analysis requirements. Specifically, it must not pass +// a stack pointer to an escaping argument. debugCallV2 cannot check +// this invariant. +// +// This is ABIInternal because Go code injects its PC directly into new +// goroutine stacks. +TEXT runtime·debugCallV2(SB),NOSPLIT|NOFRAME,$0-0 + STP (R29, R30), -280(RSP) + SUB $272, RSP, RSP + SUB $8, RSP, R29 + // Save all registers that may contain pointers so they can be + // conservatively scanned. + // + // We can't do anything that might clobber any of these + // registers before this. + STP (R27, g), (30*8)(RSP) + STP (R25, R26), (28*8)(RSP) + STP (R23, R24), (26*8)(RSP) + STP (R21, R22), (24*8)(RSP) + STP (R19, R20), (22*8)(RSP) + STP (R16, R17), (20*8)(RSP) + STP (R14, R15), (18*8)(RSP) + STP (R12, R13), (16*8)(RSP) + STP (R10, R11), (14*8)(RSP) + STP (R8, R9), (12*8)(RSP) + STP (R6, R7), (10*8)(RSP) + STP (R4, R5), (8*8)(RSP) + STP (R2, R3), (6*8)(RSP) + STP (R0, R1), (4*8)(RSP) + + // Perform a safe-point check. + MOVD R30, 8(RSP) // Caller's PC + CALL runtime·debugCallCheck(SB) + MOVD 16(RSP), R0 + CBZ R0, good + + // The safety check failed. Put the reason string at the top + // of the stack. + MOVD R0, 8(RSP) + MOVD 24(RSP), R0 + MOVD R0, 16(RSP) + + // Set R20 to 8 and invoke BRK. The debugger should get the + // reason a call can't be injected from SP+8 and resume execution. + MOVD $8, R20 + BREAK + JMP restore + +good: + // Registers are saved and it's safe to make a call. + // Open up a call frame, moving the stack if necessary. + // + // Once the frame is allocated, this will set R20 to 0 and + // invoke BRK. The debugger should write the argument + // frame for the call at SP+8, set up argument registers, + // set the LR as the signal PC + 4, set the PC to the function + // to call, set R26 to point to the closure (if a closure call), + // and resume execution. + // + // If the function returns, this will set R20 to 1 and invoke + // BRK. The debugger can then inspect any return value saved + // on the stack at SP+8 and in registers. To resume execution, + // the debugger should restore the LR from (SP). + // + // If the function panics, this will set R20 to 2 and invoke BRK. + // The interface{} value of the panic will be at SP+8. The debugger + // can inspect the panic value and resume execution again. +#define DEBUG_CALL_DISPATCH(NAME,MAXSIZE) \ + CMP $MAXSIZE, R0; \ + BGT 5(PC); \ + MOVD $NAME(SB), R0; \ + MOVD R0, 8(RSP); \ + CALL runtime·debugCallWrap(SB); \ + JMP restore + + MOVD 256(RSP), R0 // the argument frame size + DEBUG_CALL_DISPATCH(debugCall32<>, 32) + DEBUG_CALL_DISPATCH(debugCall64<>, 64) + DEBUG_CALL_DISPATCH(debugCall128<>, 128) + DEBUG_CALL_DISPATCH(debugCall256<>, 256) + DEBUG_CALL_DISPATCH(debugCall512<>, 512) + DEBUG_CALL_DISPATCH(debugCall1024<>, 1024) + DEBUG_CALL_DISPATCH(debugCall2048<>, 2048) + DEBUG_CALL_DISPATCH(debugCall4096<>, 4096) + DEBUG_CALL_DISPATCH(debugCall8192<>, 8192) + DEBUG_CALL_DISPATCH(debugCall16384<>, 16384) + DEBUG_CALL_DISPATCH(debugCall32768<>, 32768) + DEBUG_CALL_DISPATCH(debugCall65536<>, 65536) + // The frame size is too large. Report the error. + MOVD $debugCallFrameTooLarge<>(SB), R0 + MOVD R0, 8(RSP) + MOVD $20, R0 + MOVD R0, 16(RSP) // length of debugCallFrameTooLarge string + MOVD $8, R20 + BREAK + JMP restore + +restore: + // Calls and failures resume here. + // + // Set R20 to 16 and invoke BRK. The debugger should restore + // all registers except for PC and RSP and resume execution. + MOVD $16, R20 + BREAK + // We must not modify flags after this point. + + // Restore pointer-containing registers, which may have been + // modified from the debugger's copy by stack copying. + LDP (30*8)(RSP), (R27, g) + LDP (28*8)(RSP), (R25, R26) + LDP (26*8)(RSP), (R23, R24) + LDP (24*8)(RSP), (R21, R22) + LDP (22*8)(RSP), (R19, R20) + LDP (20*8)(RSP), (R16, R17) + LDP (18*8)(RSP), (R14, R15) + LDP (16*8)(RSP), (R12, R13) + LDP (14*8)(RSP), (R10, R11) + LDP (12*8)(RSP), (R8, R9) + LDP (10*8)(RSP), (R6, R7) + LDP (8*8)(RSP), (R4, R5) + LDP (6*8)(RSP), (R2, R3) + LDP (4*8)(RSP), (R0, R1) + + LDP -8(RSP), (R29, R27) + ADD $288, RSP, RSP // Add 16 more bytes, see saveSigContext + MOVD -16(RSP), R30 // restore old lr + JMP (R27) + +// runtime.debugCallCheck assumes that functions defined with the +// DEBUG_CALL_FN macro are safe points to inject calls. +#define DEBUG_CALL_FN(NAME,MAXSIZE) \ +TEXT NAME(SB),WRAPPER,$MAXSIZE-0; \ + NO_LOCAL_POINTERS; \ + MOVD $0, R20; \ + BREAK; \ + MOVD $1, R20; \ + BREAK; \ + RET +DEBUG_CALL_FN(debugCall32<>, 32) +DEBUG_CALL_FN(debugCall64<>, 64) +DEBUG_CALL_FN(debugCall128<>, 128) +DEBUG_CALL_FN(debugCall256<>, 256) +DEBUG_CALL_FN(debugCall512<>, 512) +DEBUG_CALL_FN(debugCall1024<>, 1024) +DEBUG_CALL_FN(debugCall2048<>, 2048) +DEBUG_CALL_FN(debugCall4096<>, 4096) +DEBUG_CALL_FN(debugCall8192<>, 8192) +DEBUG_CALL_FN(debugCall16384<>, 16384) +DEBUG_CALL_FN(debugCall32768<>, 32768) +DEBUG_CALL_FN(debugCall65536<>, 65536) + +// func debugCallPanicked(val interface{}) +TEXT runtime·debugCallPanicked(SB),NOSPLIT,$16-16 + // Copy the panic value to the top of stack at SP+8. + MOVD val_type+0(FP), R0 + MOVD R0, 8(RSP) + MOVD val_data+8(FP), R0 + MOVD R0, 16(RSP) + MOVD $2, R20 + BREAK + RET + +// Note: these functions use a special calling convention to save generated code space. +// Arguments are passed in registers, but the space for those arguments are allocated +// in the caller's stack frame. These stubs write the args into that stack space and +// then tail call to the corresponding runtime handler. +// The tail call makes these stubs disappear in backtraces. +// +// Defined as ABIInternal since the compiler generates ABIInternal +// calls to it directly and it does not use the stack-based Go ABI. +TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 + JMP runtime·goPanicIndex(SB) +TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicIndexU(SB) +TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 + MOVD R1, R0 + MOVD R2, R1 + JMP runtime·goPanicSliceAlen(SB) +TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 + MOVD R1, R0 + MOVD R2, R1 + JMP runtime·goPanicSliceAlenU(SB) +TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 + MOVD R1, R0 + MOVD R2, R1 + JMP runtime·goPanicSliceAcap(SB) +TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 + MOVD R1, R0 + MOVD R2, R1 + JMP runtime·goPanicSliceAcapU(SB) +TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceB(SB) +TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceBU(SB) +TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 + MOVD R2, R0 + MOVD R3, R1 + JMP runtime·goPanicSlice3Alen(SB) +TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 + MOVD R2, R0 + MOVD R3, R1 + JMP runtime·goPanicSlice3AlenU(SB) +TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 + MOVD R2, R0 + MOVD R3, R1 + JMP runtime·goPanicSlice3Acap(SB) +TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 + MOVD R2, R0 + MOVD R3, R1 + JMP runtime·goPanicSlice3AcapU(SB) +TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 + MOVD R1, R0 + MOVD R2, R1 + JMP runtime·goPanicSlice3B(SB) +TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 + MOVD R1, R0 + MOVD R2, R1 + JMP runtime·goPanicSlice3BU(SB) +TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3C(SB) +TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3CU(SB) +TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 + MOVD R2, R0 + MOVD R3, R1 + JMP runtime·goPanicSliceConvert(SB) + +TEXT ·getfp(SB),NOSPLIT|NOFRAME,$0 + MOVD R29, R0 + RET diff --git a/contrib/go/_std_1.23/src/runtime/asm_loong64.s b/contrib/go/_std_1.23/src/runtime/asm_loong64.s new file mode 100644 index 000000000000..c16b27a0f276 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/asm_loong64.s @@ -0,0 +1,957 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "go_tls.h" +#include "funcdata.h" +#include "textflag.h" + +#define REGCTXT R29 + +TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 + // R3 = stack; R4 = argc; R5 = argv + + ADDV $-24, R3 + MOVW R4, 8(R3) // argc + MOVV R5, 16(R3) // argv + + // create istack out of the given (operating system) stack. + // _cgo_init may update stackguard. + MOVV $runtime·g0(SB), g + MOVV $(-64*1024), R30 + ADDV R30, R3, R19 + MOVV R19, g_stackguard0(g) + MOVV R19, g_stackguard1(g) + MOVV R19, (g_stack+stack_lo)(g) + MOVV R3, (g_stack+stack_hi)(g) + + // if there is a _cgo_init, call it using the gcc ABI. + MOVV _cgo_init(SB), R25 + BEQ R25, nocgo + + MOVV R0, R7 // arg 3: not used + MOVV R0, R6 // arg 2: not used + MOVV $setg_gcc<>(SB), R5 // arg 1: setg + MOVV g, R4 // arg 0: G + JAL (R25) + +nocgo: + // update stackguard after _cgo_init + MOVV (g_stack+stack_lo)(g), R19 + ADDV $const_stackGuard, R19 + MOVV R19, g_stackguard0(g) + MOVV R19, g_stackguard1(g) + + // set the per-goroutine and per-mach "registers" + MOVV $runtime·m0(SB), R19 + + // save m->g0 = g0 + MOVV g, m_g0(R19) + // save m0 to g0->m + MOVV R19, g_m(g) + + JAL runtime·check(SB) + + // args are already prepared + JAL runtime·args(SB) + JAL runtime·osinit(SB) + JAL runtime·schedinit(SB) + + // create a new goroutine to start program + MOVV $runtime·mainPC(SB), R19 // entry + ADDV $-16, R3 + MOVV R19, 8(R3) + MOVV R0, 0(R3) + JAL runtime·newproc(SB) + ADDV $16, R3 + + // start this M + JAL runtime·mstart(SB) + + MOVV R0, 1(R0) + RET + +DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) +GLOBL runtime·mainPC(SB),RODATA,$8 + +TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0 + BREAK + RET + +TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0 + RET + +TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 + JAL runtime·mstart0(SB) + RET // not reached + +// func cputicks() int64 +TEXT runtime·cputicks(SB),NOSPLIT,$0-8 + RDTIMED R0, R4 + MOVV R4, ret+0(FP) + RET + +/* + * go-routine + */ + +// void gogo(Gobuf*) +// restore state from Gobuf; longjmp +TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8 + MOVV buf+0(FP), R4 + MOVV gobuf_g(R4), R5 + MOVV 0(R5), R0 // make sure g != nil + JMP gogo<>(SB) + +TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 + MOVV R5, g + JAL runtime·save_g(SB) + + MOVV gobuf_sp(R4), R3 + MOVV gobuf_lr(R4), R1 + MOVV gobuf_ret(R4), R19 + MOVV gobuf_ctxt(R4), REGCTXT + MOVV R0, gobuf_sp(R4) + MOVV R0, gobuf_ret(R4) + MOVV R0, gobuf_lr(R4) + MOVV R0, gobuf_ctxt(R4) + MOVV gobuf_pc(R4), R6 + JMP (R6) + +// void mcall(fn func(*g)) +// Switch to m->g0's stack, call fn(g). +// Fn must never return. It should gogo(&g->sched) +// to keep running g. +TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 + MOVV R4, REGCTXT + // Save caller state in g->sched + MOVV R3, (g_sched+gobuf_sp)(g) + MOVV R1, (g_sched+gobuf_pc)(g) + MOVV R0, (g_sched+gobuf_lr)(g) + + // Switch to m->g0 & its stack, call fn. + MOVV g, R4 // arg = g + MOVV g_m(g), R20 + MOVV m_g0(R20), g + JAL runtime·save_g(SB) + BNE g, R4, 2(PC) + JMP runtime·badmcall(SB) + MOVV 0(REGCTXT), R20 // code pointer + MOVV (g_sched+gobuf_sp)(g), R3 // sp = m->g0->sched.sp + ADDV $-16, R3 + MOVV R4, 8(R3) + MOVV R0, 0(R3) + JAL (R20) + JMP runtime·badmcall2(SB) + +// systemstack_switch is a dummy routine that systemstack leaves at the bottom +// of the G stack. We need to distinguish the routine that +// lives at the bottom of the G stack from the one that lives +// at the top of the system stack because the one at the top of +// the system stack terminates the stack walk (see topofstack()). +TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 + UNDEF + JAL (R1) // make sure this function is not leaf + RET + +// func systemstack(fn func()) +TEXT runtime·systemstack(SB), NOSPLIT, $0-8 + MOVV fn+0(FP), R19 // R19 = fn + MOVV R19, REGCTXT // context + MOVV g_m(g), R4 // R4 = m + + MOVV m_gsignal(R4), R5 // R5 = gsignal + BEQ g, R5, noswitch + + MOVV m_g0(R4), R5 // R5 = g0 + BEQ g, R5, noswitch + + MOVV m_curg(R4), R6 + BEQ g, R6, switch + + // Bad: g is not gsignal, not g0, not curg. What is it? + // Hide call from linker nosplit analysis. + MOVV $runtime·badsystemstack(SB), R7 + JAL (R7) + JAL runtime·abort(SB) + +switch: + // save our state in g->sched. Pretend to + // be systemstack_switch if the G stack is scanned. + JAL gosave_systemstack_switch<>(SB) + + // switch to g0 + MOVV R5, g + JAL runtime·save_g(SB) + MOVV (g_sched+gobuf_sp)(g), R19 + MOVV R19, R3 + + // call target function + MOVV 0(REGCTXT), R6 // code pointer + JAL (R6) + + // switch back to g + MOVV g_m(g), R4 + MOVV m_curg(R4), g + JAL runtime·save_g(SB) + MOVV (g_sched+gobuf_sp)(g), R3 + MOVV R0, (g_sched+gobuf_sp)(g) + RET + +noswitch: + // already on m stack, just call directly + // Using a tail call here cleans up tracebacks since we won't stop + // at an intermediate systemstack. + MOVV 0(REGCTXT), R4 // code pointer + MOVV 0(R3), R1 // restore LR + ADDV $8, R3 + JMP (R4) + +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 + MOVV fn+0(FP), REGCTXT // context register + MOVV g_m(g), R4 // curm + + // set g to gcrash + MOVV $runtime·gcrash(SB), g // g = &gcrash + JAL runtime·save_g(SB) + MOVV R4, g_m(g) // g.m = curm + MOVV g, m_g0(R4) // curm.g0 = g + + // switch to crashstack + MOVV (g_stack+stack_hi)(g), R4 + ADDV $(-4*8), R4, R3 + + // call target function + MOVV 0(REGCTXT), R6 + JAL (R6) + + // should never return + JAL runtime·abort(SB) + UNDEF + +/* + * support for morestack + */ + +// Called during function prolog when more stack is needed. +// Caller has already loaded: +// loong64: R31: LR +// +// The traceback routines see morestack on a g0 as being +// the top of a stack (for example, morestack calling newstack +// calling the scheduler calling newm calling gc), so we must +// record an argument size. For that purpose, it has no arguments. +TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 + // Called from f. + // Set g->sched to context in f. + MOVV R3, (g_sched+gobuf_sp)(g) + MOVV R1, (g_sched+gobuf_pc)(g) + MOVV R31, (g_sched+gobuf_lr)(g) + MOVV REGCTXT, (g_sched+gobuf_ctxt)(g) + + // Cannot grow scheduler stack (m->g0). + MOVV g_m(g), R7 + MOVV m_g0(R7), R8 + BNE g, R8, 3(PC) + JAL runtime·badmorestackg0(SB) + JAL runtime·abort(SB) + + // Cannot grow signal stack (m->gsignal). + MOVV m_gsignal(R7), R8 + BNE g, R8, 3(PC) + JAL runtime·badmorestackgsignal(SB) + JAL runtime·abort(SB) + + // Called from f. + // Set m->morebuf to f's caller. + MOVV R31, (m_morebuf+gobuf_pc)(R7) // f's caller's PC + MOVV R3, (m_morebuf+gobuf_sp)(R7) // f's caller's SP + MOVV g, (m_morebuf+gobuf_g)(R7) + + // Call newstack on m->g0's stack. + MOVV m_g0(R7), g + JAL runtime·save_g(SB) + MOVV (g_sched+gobuf_sp)(g), R3 + // Create a stack frame on g0 to call newstack. + MOVV R0, -8(R3) // Zero saved LR in frame + ADDV $-8, R3 + JAL runtime·newstack(SB) + + // Not reached, but make sure the return PC from the call to newstack + // is still in this function, and not the beginning of the next. + UNDEF + +TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 + // Force SPWRITE. This function doesn't actually write SP, + // but it is called with a special calling convention where + // the caller doesn't save LR on stack but passes it as a + // register (R5), and the unwinder currently doesn't understand. + // Make it SPWRITE to stop unwinding. (See issue 54332) + MOVV R3, R3 + + MOVV R0, REGCTXT + JMP runtime·morestack(SB) + +// reflectcall: call a function with the given argument list +// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). +// we don't have variable-sized frames, so we use a small number +// of constant-sized-frame functions to encode a few bits of size in the pc. +// Caution: ugly multiline assembly macros in your future! + +#define DISPATCH(NAME,MAXSIZE) \ + MOVV $MAXSIZE, R30; \ + SGTU R19, R30, R30; \ + BNE R30, 3(PC); \ + MOVV $NAME(SB), R4; \ + JMP (R4) +// Note: can't just "BR NAME(SB)" - bad inlining results. + +TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-48 + MOVWU frameSize+32(FP), R19 + DISPATCH(runtime·call32, 32) + DISPATCH(runtime·call64, 64) + DISPATCH(runtime·call128, 128) + DISPATCH(runtime·call256, 256) + DISPATCH(runtime·call512, 512) + DISPATCH(runtime·call1024, 1024) + DISPATCH(runtime·call2048, 2048) + DISPATCH(runtime·call4096, 4096) + DISPATCH(runtime·call8192, 8192) + DISPATCH(runtime·call16384, 16384) + DISPATCH(runtime·call32768, 32768) + DISPATCH(runtime·call65536, 65536) + DISPATCH(runtime·call131072, 131072) + DISPATCH(runtime·call262144, 262144) + DISPATCH(runtime·call524288, 524288) + DISPATCH(runtime·call1048576, 1048576) + DISPATCH(runtime·call2097152, 2097152) + DISPATCH(runtime·call4194304, 4194304) + DISPATCH(runtime·call8388608, 8388608) + DISPATCH(runtime·call16777216, 16777216) + DISPATCH(runtime·call33554432, 33554432) + DISPATCH(runtime·call67108864, 67108864) + DISPATCH(runtime·call134217728, 134217728) + DISPATCH(runtime·call268435456, 268435456) + DISPATCH(runtime·call536870912, 536870912) + DISPATCH(runtime·call1073741824, 1073741824) + MOVV $runtime·badreflectcall(SB), R4 + JMP (R4) + +#define CALLFN(NAME,MAXSIZE) \ +TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ + NO_LOCAL_POINTERS; \ + /* copy arguments to stack */ \ + MOVV arg+16(FP), R4; \ + MOVWU argsize+24(FP), R5; \ + MOVV R3, R12; \ + ADDV $8, R12; \ + ADDV R12, R5; \ + BEQ R12, R5, 6(PC); \ + MOVBU (R4), R6; \ + ADDV $1, R4; \ + MOVBU R6, (R12); \ + ADDV $1, R12; \ + JMP -5(PC); \ + /* set up argument registers */ \ + MOVV regArgs+40(FP), R25; \ + JAL ·unspillArgs(SB); \ + /* call function */ \ + MOVV f+8(FP), REGCTXT; \ + MOVV (REGCTXT), R25; \ + PCDATA $PCDATA_StackMapIndex, $0; \ + JAL (R25); \ + /* copy return values back */ \ + MOVV regArgs+40(FP), R25; \ + JAL ·spillArgs(SB); \ + MOVV argtype+0(FP), R7; \ + MOVV arg+16(FP), R4; \ + MOVWU n+24(FP), R5; \ + MOVWU retoffset+28(FP), R6; \ + ADDV $8, R3, R12; \ + ADDV R6, R12; \ + ADDV R6, R4; \ + SUBVU R6, R5; \ + JAL callRet<>(SB); \ + RET + +// callRet copies return values back at the end of call*. This is a +// separate function so it can allocate stack space for the arguments +// to reflectcallmove. It does not follow the Go ABI; it expects its +// arguments in registers. +TEXT callRet<>(SB), NOSPLIT, $40-0 + NO_LOCAL_POINTERS + MOVV R7, 8(R3) + MOVV R4, 16(R3) + MOVV R12, 24(R3) + MOVV R5, 32(R3) + MOVV R25, 40(R3) + JAL runtime·reflectcallmove(SB) + RET + +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) + +TEXT runtime·procyield(SB),NOSPLIT,$0-0 + RET + +// Save state of caller into g->sched. +// but using fake PC from systemstack_switch. +// Must only be called from functions with no locals ($0) +// or else unwinding from systemstack_switch is incorrect. +// Smashes R19. +TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 + MOVV $runtime·systemstack_switch(SB), R19 + ADDV $8, R19 + MOVV R19, (g_sched+gobuf_pc)(g) + MOVV R3, (g_sched+gobuf_sp)(g) + MOVV R0, (g_sched+gobuf_lr)(g) + MOVV R0, (g_sched+gobuf_ret)(g) + // Assert ctxt is zero. See func save. + MOVV (g_sched+gobuf_ctxt)(g), R19 + BEQ R19, 2(PC) + JAL runtime·abort(SB) + RET + +// func asmcgocall(fn, arg unsafe.Pointer) int32 +// Call fn(arg) on the scheduler stack, +// aligned appropriately for the gcc ABI. +// See cgocall.go for more details. +TEXT ·asmcgocall(SB),NOSPLIT,$0-20 + MOVV fn+0(FP), R25 + MOVV arg+8(FP), R4 + + MOVV R3, R12 // save original stack pointer + MOVV g, R13 + + // Figure out if we need to switch to m->g0 stack. + // We get called to create new OS threads too, and those + // come in on the m->g0 stack already. + MOVV g_m(g), R5 + MOVV m_gsignal(R5), R6 + BEQ R6, g, g0 + MOVV m_g0(R5), R6 + BEQ R6, g, g0 + + JAL gosave_systemstack_switch<>(SB) + MOVV R6, g + JAL runtime·save_g(SB) + MOVV (g_sched+gobuf_sp)(g), R3 + + // Now on a scheduling stack (a pthread-created stack). +g0: + // Save room for two of our pointers. + ADDV $-16, R3 + MOVV R13, 0(R3) // save old g on stack + MOVV (g_stack+stack_hi)(R13), R13 + SUBVU R12, R13 + MOVV R13, 8(R3) // save depth in old g stack (can't just save SP, as stack might be copied during a callback) + JAL (R25) + + // Restore g, stack pointer. R4 is return value. + MOVV 0(R3), g + JAL runtime·save_g(SB) + MOVV (g_stack+stack_hi)(g), R5 + MOVV 8(R3), R6 + SUBVU R6, R5 + MOVV R5, R3 + + MOVW R4, ret+16(FP) + RET + +// func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) +// See cgocall.go for more details. +TEXT ·cgocallback(SB),NOSPLIT,$24-24 + NO_LOCAL_POINTERS + + // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. + // It is used to dropm while thread is exiting. + MOVV fn+0(FP), R5 + BNE R5, loadg + // Restore the g from frame. + MOVV frame+8(FP), g + JMP dropm + +loadg: + // Load m and g from thread-local storage. + MOVB runtime·iscgo(SB), R19 + BEQ R19, nocgo + JAL runtime·load_g(SB) +nocgo: + + // If g is nil, Go did not create the current thread, + // or if this thread never called into Go on pthread platforms. + // Call needm to obtain one for temporary use. + // In this case, we're running on the thread stack, so there's + // lots of space, but the linker doesn't know. Hide the call from + // the linker analysis by using an indirect call. + BEQ g, needm + + MOVV g_m(g), R12 + MOVV R12, savedm-8(SP) + JMP havem + +needm: + MOVV g, savedm-8(SP) // g is zero, so is m. + MOVV $runtime·needAndBindM(SB), R4 + JAL (R4) + + // Set m->sched.sp = SP, so that if a panic happens + // during the function we are about to execute, it will + // have a valid SP to run on the g0 stack. + // The next few lines (after the havem label) + // will save this SP onto the stack and then write + // the same SP back to m->sched.sp. That seems redundant, + // but if an unrecovered panic happens, unwindm will + // restore the g->sched.sp from the stack location + // and then systemstack will try to use it. If we don't set it here, + // that restored SP will be uninitialized (typically 0) and + // will not be usable. + MOVV g_m(g), R12 + MOVV m_g0(R12), R19 + MOVV R3, (g_sched+gobuf_sp)(R19) + +havem: + // Now there's a valid m, and we're running on its m->g0. + // Save current m->g0->sched.sp on stack and then set it to SP. + // Save current sp in m->g0->sched.sp in preparation for + // switch back to m->curg stack. + // NOTE: unwindm knows that the saved g->sched.sp is at 8(R29) aka savedsp-16(SP). + MOVV m_g0(R12), R19 + MOVV (g_sched+gobuf_sp)(R19), R13 + MOVV R13, savedsp-24(SP) // must match frame size + MOVV R3, (g_sched+gobuf_sp)(R19) + + // Switch to m->curg stack and call runtime.cgocallbackg. + // Because we are taking over the execution of m->curg + // but *not* resuming what had been running, we need to + // save that information (m->curg->sched) so we can restore it. + // We can restore m->curg->sched.sp easily, because calling + // runtime.cgocallbackg leaves SP unchanged upon return. + // To save m->curg->sched.pc, we push it onto the stack. + // This has the added benefit that it looks to the traceback + // routine like cgocallbackg is going to return to that + // PC (because the frame we allocate below has the same + // size as cgocallback_gofunc's frame declared above) + // so that the traceback will seamlessly trace back into + // the earlier calls. + MOVV m_curg(R12), g + JAL runtime·save_g(SB) + MOVV (g_sched+gobuf_sp)(g), R13 // prepare stack as R13 + MOVV (g_sched+gobuf_pc)(g), R4 + MOVV R4, -(24+8)(R13) // "saved LR"; must match frame size + MOVV fn+0(FP), R5 + MOVV frame+8(FP), R6 + MOVV ctxt+16(FP), R7 + MOVV $-(24+8)(R13), R3 + MOVV R5, 8(R3) + MOVV R6, 16(R3) + MOVV R7, 24(R3) + JAL runtime·cgocallbackg(SB) + + // Restore g->sched (== m->curg->sched) from saved values. + MOVV 0(R3), R4 + MOVV R4, (g_sched+gobuf_pc)(g) + MOVV $(24+8)(R3), R13 // must match frame size + MOVV R13, (g_sched+gobuf_sp)(g) + + // Switch back to m->g0's stack and restore m->g0->sched.sp. + // (Unlike m->curg, the g0 goroutine never uses sched.pc, + // so we do not have to restore it.) + MOVV g_m(g), R12 + MOVV m_g0(R12), g + JAL runtime·save_g(SB) + MOVV (g_sched+gobuf_sp)(g), R3 + MOVV savedsp-24(SP), R13 // must match frame size + MOVV R13, (g_sched+gobuf_sp)(g) + + // If the m on entry was nil, we called needm above to borrow an m, + // 1. for the duration of the call on non-pthread platforms, + // 2. or the duration of the C thread alive on pthread platforms. + // If the m on entry wasn't nil, + // 1. the thread might be a Go thread, + // 2. or it wasn't the first call from a C thread on pthread platforms, + // since then we skip dropm to resue the m in the first call. + MOVV savedm-8(SP), R12 + BNE R12, droppedm + + // Skip dropm to reuse it in the next call, when a pthread key has been created. + MOVV _cgo_pthread_key_created(SB), R12 + // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. + BEQ R12, dropm + MOVV (R12), R12 + BNE R12, droppedm + +dropm: + MOVV $runtime·dropm(SB), R4 + JAL (R4) +droppedm: + + // Done! + RET + +// void setg(G*); set g. for use by needm. +TEXT runtime·setg(SB), NOSPLIT, $0-8 + MOVV gg+0(FP), g + // This only happens if iscgo, so jump straight to save_g + JAL runtime·save_g(SB) + RET + +// void setg_gcc(G*); set g called from gcc with g in R19 +TEXT setg_gcc<>(SB),NOSPLIT,$0-0 + MOVV R19, g + JAL runtime·save_g(SB) + RET + +TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 + MOVW (R0), R0 + UNDEF + +// AES hashing not implemented for loong64 +TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 + JMP runtime·memhashFallback(SB) +TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 + JMP runtime·strhashFallback(SB) +TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 + JMP runtime·memhash32Fallback(SB) +TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 + JMP runtime·memhash64Fallback(SB) + +TEXT runtime·return0(SB), NOSPLIT, $0 + MOVW $0, R19 + RET + +// Called from cgo wrappers, this function returns g->m->curg.stack.hi. +// Must obey the gcc calling convention. +TEXT _cgo_topofstack(SB),NOSPLIT,$16 + // g (R22) and REGTMP (R30) might be clobbered by load_g. They + // are callee-save in the gcc calling convention, so save them. + MOVV R30, savedREGTMP-16(SP) + MOVV g, savedG-8(SP) + + JAL runtime·load_g(SB) + MOVV g_m(g), R19 + MOVV m_curg(R19), R19 + MOVV (g_stack+stack_hi)(R19), R4 // return value in R4 + + MOVV savedG-8(SP), g + MOVV savedREGTMP-16(SP), R30 + RET + +// The top-most function running on a goroutine +// returns to goexit+PCQuantum. +TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 + NOOP + JAL runtime·goexit1(SB) // does not return + // traceback from goexit1 must hit code range of goexit + NOOP + +// This is called from .init_array and follows the platform, not Go, ABI. +TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 + ADDV $-0x10, R3 + MOVV R30, 8(R3) // The access to global variables below implicitly uses R30, which is callee-save + MOVV runtime·lastmoduledatap(SB), R12 + MOVV R4, moduledata_next(R12) + MOVV R4, runtime·lastmoduledatap(SB) + MOVV 8(R3), R30 + ADDV $0x10, R3 + RET + +TEXT ·checkASM(SB),NOSPLIT,$0-1 + MOVW $1, R19 + MOVB R19, ret+0(FP) + RET + +// spillArgs stores return values from registers to a *internal/abi.RegArgs in R25. +TEXT ·spillArgs(SB),NOSPLIT,$0-0 + MOVV R4, (0*8)(R25) + MOVV R5, (1*8)(R25) + MOVV R6, (2*8)(R25) + MOVV R7, (3*8)(R25) + MOVV R8, (4*8)(R25) + MOVV R9, (5*8)(R25) + MOVV R10, (6*8)(R25) + MOVV R11, (7*8)(R25) + MOVV R12, (8*8)(R25) + MOVV R13, (9*8)(R25) + MOVV R14, (10*8)(R25) + MOVV R15, (11*8)(R25) + MOVV R16, (12*8)(R25) + MOVV R17, (13*8)(R25) + MOVV R18, (14*8)(R25) + MOVV R19, (15*8)(R25) + MOVD F0, (16*8)(R25) + MOVD F1, (17*8)(R25) + MOVD F2, (18*8)(R25) + MOVD F3, (19*8)(R25) + MOVD F4, (20*8)(R25) + MOVD F5, (21*8)(R25) + MOVD F6, (22*8)(R25) + MOVD F7, (23*8)(R25) + MOVD F8, (24*8)(R25) + MOVD F9, (25*8)(R25) + MOVD F10, (26*8)(R25) + MOVD F11, (27*8)(R25) + MOVD F12, (28*8)(R25) + MOVD F13, (29*8)(R25) + MOVD F14, (30*8)(R25) + MOVD F15, (31*8)(R25) + RET + +// unspillArgs loads args into registers from a *internal/abi.RegArgs in R25. +TEXT ·unspillArgs(SB),NOSPLIT,$0-0 + MOVV (0*8)(R25), R4 + MOVV (1*8)(R25), R5 + MOVV (2*8)(R25), R6 + MOVV (3*8)(R25), R7 + MOVV (4*8)(R25), R8 + MOVV (5*8)(R25), R9 + MOVV (6*8)(R25), R10 + MOVV (7*8)(R25), R11 + MOVV (8*8)(R25), R12 + MOVV (9*8)(R25), R13 + MOVV (10*8)(R25), R14 + MOVV (11*8)(R25), R15 + MOVV (12*8)(R25), R16 + MOVV (13*8)(R25), R17 + MOVV (14*8)(R25), R18 + MOVV (15*8)(R25), R19 + MOVD (16*8)(R25), F0 + MOVD (17*8)(R25), F1 + MOVD (18*8)(R25), F2 + MOVD (19*8)(R25), F3 + MOVD (20*8)(R25), F4 + MOVD (21*8)(R25), F5 + MOVD (22*8)(R25), F6 + MOVD (23*8)(R25), F7 + MOVD (24*8)(R25), F8 + MOVD (25*8)(R25), F9 + MOVD (26*8)(R25), F10 + MOVD (27*8)(R25), F11 + MOVD (28*8)(R25), F12 + MOVD (29*8)(R25), F13 + MOVD (30*8)(R25), F14 + MOVD (31*8)(R25), F15 + RET + +// gcWriteBarrier informs the GC about heap pointer writes. +// +// gcWriteBarrier does NOT follow the Go ABI. It accepts the +// number of bytes of buffer needed in R29, and returns a pointer +// to the buffer space in R29. +// It clobbers R30 (the linker temp register). +// The act of CALLing gcWriteBarrier will clobber R1 (LR). +// It does not clobber any other general-purpose registers, +// but may clobber others (e.g., floating point registers). +TEXT gcWriteBarrier<>(SB),NOSPLIT,$216 + // Save the registers clobbered by the fast path. + MOVV R19, 208(R3) + MOVV R13, 216(R3) +retry: + MOVV g_m(g), R19 + MOVV m_p(R19), R19 + MOVV (p_wbBuf+wbBuf_next)(R19), R13 + MOVV (p_wbBuf+wbBuf_end)(R19), R30 // R30 is linker temp register + // Increment wbBuf.next position. + ADDV R29, R13 + // Is the buffer full? + BLTU R30, R13, flush + // Commit to the larger buffer. + MOVV R13, (p_wbBuf+wbBuf_next)(R19) + // Make return value (the original next position) + SUBV R29, R13, R29 + // Restore registers. + MOVV 208(R3), R19 + MOVV 216(R3), R13 + RET + +flush: + // Save all general purpose registers since these could be + // clobbered by wbBufFlush and were not saved by the caller. + MOVV R27, 8(R3) + MOVV R28, 16(R3) + // R1 is LR, which was saved by the prologue. + MOVV R2, 24(R3) + // R3 is SP. + MOVV R4, 32(R3) + MOVV R5, 40(R3) + MOVV R6, 48(R3) + MOVV R7, 56(R3) + MOVV R8, 64(R3) + MOVV R9, 72(R3) + MOVV R10, 80(R3) + MOVV R11, 88(R3) + MOVV R12, 96(R3) + // R13 already saved + MOVV R14, 104(R3) + MOVV R15, 112(R3) + MOVV R16, 120(R3) + MOVV R17, 128(R3) + MOVV R18, 136(R3) + // R19 already saved + MOVV R20, 144(R3) + MOVV R21, 152(R3) + // R22 is g. + MOVV R23, 160(R3) + MOVV R24, 168(R3) + MOVV R25, 176(R3) + MOVV R26, 184(R3) + // R27 already saved + // R28 already saved. + MOVV R29, 192(R3) + // R30 is tmp register. + MOVV R31, 200(R3) + + CALL runtime·wbBufFlush(SB) + + MOVV 8(R3), R27 + MOVV 16(R3), R28 + MOVV 24(R3), R2 + MOVV 32(R3), R4 + MOVV 40(R3), R5 + MOVV 48(R3), R6 + MOVV 56(R3), R7 + MOVV 64(R3), R8 + MOVV 72(R3), R9 + MOVV 80(R3), R10 + MOVV 88(R3), R11 + MOVV 96(R3), R12 + MOVV 104(R3), R14 + MOVV 112(R3), R15 + MOVV 120(R3), R16 + MOVV 128(R3), R17 + MOVV 136(R3), R18 + MOVV 144(R3), R20 + MOVV 152(R3), R21 + MOVV 160(R3), R23 + MOVV 168(R3), R24 + MOVV 176(R3), R25 + MOVV 184(R3), R26 + MOVV 192(R3), R29 + MOVV 200(R3), R31 + JMP retry + +TEXT runtime·gcWriteBarrier1(SB),NOSPLIT,$0 + MOVV $8, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier2(SB),NOSPLIT,$0 + MOVV $16, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier3(SB),NOSPLIT,$0 + MOVV $24, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier4(SB),NOSPLIT,$0 + MOVV $32, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier5(SB),NOSPLIT,$0 + MOVV $40, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier6(SB),NOSPLIT,$0 + MOVV $48, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier7(SB),NOSPLIT,$0 + MOVV $56, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier8(SB),NOSPLIT,$0 + MOVV $64, R29 + JMP gcWriteBarrier<>(SB) + +// Note: these functions use a special calling convention to save generated code space. +// Arguments are passed in registers, but the space for those arguments are allocated +// in the caller's stack frame. These stubs write the args into that stack space and +// then tail call to the corresponding runtime handler. +// The tail call makes these stubs disappear in backtraces. +TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 + MOVV R20, R4 + MOVV R21, R5 + JMP runtime·goPanicIndex(SB) +TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 + MOVV R20, R4 + MOVV R21, R5 + JMP runtime·goPanicIndexU(SB) +TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 + MOVV R21, R4 + MOVV R23, R5 + JMP runtime·goPanicSliceAlen(SB) +TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 + MOVV R21, R4 + MOVV R23, R5 + JMP runtime·goPanicSliceAlenU(SB) +TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 + MOVV R21, R4 + MOVV R23, R5 + JMP runtime·goPanicSliceAcap(SB) +TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 + MOVV R21, R4 + MOVV R23, R5 + JMP runtime·goPanicSliceAcapU(SB) +TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 + MOVV R20, R4 + MOVV R21, R5 + JMP runtime·goPanicSliceB(SB) +TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 + MOVV R20, R4 + MOVV R21, R5 + JMP runtime·goPanicSliceBU(SB) +TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 + MOVV R23, R4 + MOVV R24, R5 + JMP runtime·goPanicSlice3Alen(SB) +TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 + MOVV R23, R4 + MOVV R24, R5 + JMP runtime·goPanicSlice3AlenU(SB) +TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 + MOVV R23, R4 + MOVV R24, R5 + JMP runtime·goPanicSlice3Acap(SB) +TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 + MOVV R23, R4 + MOVV R24, R5 + JMP runtime·goPanicSlice3AcapU(SB) +TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 + MOVV R21, R4 + MOVV R23, R5 + JMP runtime·goPanicSlice3B(SB) +TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 + MOVV R21, R4 + MOVV R23, R5 + JMP runtime·goPanicSlice3BU(SB) +TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 + MOVV R20, R4 + MOVV R21, R5 + JMP runtime·goPanicSlice3C(SB) +TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 + MOVV R20, R4 + MOVV R21, R5 + JMP runtime·goPanicSlice3CU(SB) +TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 + MOVV R23, R4 + MOVV R24, R5 + JMP runtime·goPanicSliceConvert(SB) diff --git a/contrib/go/_std_1.22/src/runtime/asm_mips64x.s b/contrib/go/_std_1.23/src/runtime/asm_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_mips64x.s rename to contrib/go/_std_1.23/src/runtime/asm_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/asm_mipsx.s b/contrib/go/_std_1.23/src/runtime/asm_mipsx.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/asm_mipsx.s rename to contrib/go/_std_1.23/src/runtime/asm_mipsx.s index eed4a05b38b9..ca95f22bd67f 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_mipsx.s +++ b/contrib/go/_std_1.23/src/runtime/asm_mipsx.s @@ -204,6 +204,29 @@ noswitch: ADD $4, R29 JMP (R4) +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-4 + MOVW fn+0(FP), REGCTXT // context register + MOVW g_m(g), R2 // curm + + // set g to gcrash + MOVW $runtime·gcrash(SB), g // g = &gcrash + CALL runtime·save_g(SB) + MOVW R2, g_m(g) // g.m = curm + MOVW g, m_g0(R2) // curm.g0 = g + + // switch to crashstack + MOVW (g_stack+stack_hi)(g), R2 + ADDU $(-4*8), R2, R29 + + // call target function + MOVW 0(REGCTXT), R25 + JAL (R25) + + // should never return + CALL runtime·abort(SB) + UNDEF + /* * support for morestack */ @@ -217,6 +240,13 @@ noswitch: // calling the scheduler calling newm calling gc), so we must // record an argument size. For that purpose, it has no arguments. TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 + // Called from f. + // Set g->sched to context in f. + MOVW R29, (g_sched+gobuf_sp)(g) + MOVW R31, (g_sched+gobuf_pc)(g) + MOVW R3, (g_sched+gobuf_lr)(g) + MOVW REGCTXT, (g_sched+gobuf_ctxt)(g) + // Cannot grow scheduler stack (m->g0). MOVW g_m(g), R7 MOVW m_g0(R7), R8 @@ -230,13 +260,6 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 JAL runtime·badmorestackgsignal(SB) JAL runtime·abort(SB) - // Called from f. - // Set g->sched to context in f. - MOVW R29, (g_sched+gobuf_sp)(g) - MOVW R31, (g_sched+gobuf_pc)(g) - MOVW R3, (g_sched+gobuf_lr)(g) - MOVW REGCTXT, (g_sched+gobuf_ctxt)(g) - // Called from f. // Set m->morebuf to f's caller. MOVW R3, (m_morebuf+gobuf_pc)(R7) // f's caller's PC diff --git a/contrib/go/_std_1.22/src/runtime/asm_ppc64x.h b/contrib/go/_std_1.23/src/runtime/asm_ppc64x.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_ppc64x.h rename to contrib/go/_std_1.23/src/runtime/asm_ppc64x.h diff --git a/contrib/go/_std_1.23/src/runtime/asm_ppc64x.s b/contrib/go/_std_1.23/src/runtime/asm_ppc64x.s new file mode 100644 index 000000000000..2b8c4d42a3de --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/asm_ppc64x.s @@ -0,0 +1,1622 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build ppc64 || ppc64le + +#include "go_asm.h" +#include "go_tls.h" +#include "funcdata.h" +#include "textflag.h" +#include "asm_ppc64x.h" + +#ifdef GOOS_aix +#define cgoCalleeStackSize 48 +#else +#define cgoCalleeStackSize 32 +#endif + +TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 + // R1 = stack; R3 = argc; R4 = argv; R13 = C TLS base pointer + + // initialize essential registers + BL runtime·reginit(SB) + + SUB $(FIXED_FRAME+16), R1 + MOVD R2, 24(R1) // stash the TOC pointer away again now we've created a new frame + MOVW R3, FIXED_FRAME+0(R1) // argc + MOVD R4, FIXED_FRAME+8(R1) // argv + + // create istack out of the given (operating system) stack. + // _cgo_init may update stackguard. + MOVD $runtime·g0(SB), g + BL runtime·save_g(SB) + MOVD $(-64*1024), R31 + ADD R31, R1, R3 + MOVD R3, g_stackguard0(g) + MOVD R3, g_stackguard1(g) + MOVD R3, (g_stack+stack_lo)(g) + MOVD R1, (g_stack+stack_hi)(g) + + // If there is a _cgo_init, call it using the gcc ABI. + MOVD _cgo_init(SB), R12 + CMP R12, $0 + BEQ nocgo + +#ifdef GO_PPC64X_HAS_FUNCDESC + // Load the real entry address from the first slot of the function descriptor. + MOVD 8(R12), R2 + MOVD (R12), R12 +#endif + MOVD R12, CTR // r12 = "global function entry point" + MOVD R13, R5 // arg 2: TLS base pointer + MOVD $setg_gcc<>(SB), R4 // arg 1: setg + MOVD g, R3 // arg 0: G + // C functions expect 32 (48 for AIX) bytes of space on caller + // stack frame and a 16-byte aligned R1 + MOVD R1, R14 // save current stack + SUB $cgoCalleeStackSize, R1 // reserve the callee area + RLDCR $0, R1, $~15, R1 // 16-byte align + BL (CTR) // may clobber R0, R3-R12 + MOVD R14, R1 // restore stack +#ifndef GOOS_aix + MOVD 24(R1), R2 +#endif + XOR R0, R0 // fix R0 + +nocgo: + // update stackguard after _cgo_init + MOVD (g_stack+stack_lo)(g), R3 + ADD $const_stackGuard, R3 + MOVD R3, g_stackguard0(g) + MOVD R3, g_stackguard1(g) + + // set the per-goroutine and per-mach "registers" + MOVD $runtime·m0(SB), R3 + + // save m->g0 = g0 + MOVD g, m_g0(R3) + // save m0 to g0->m + MOVD R3, g_m(g) + + BL runtime·check(SB) + + // args are already prepared + BL runtime·args(SB) + BL runtime·osinit(SB) + BL runtime·schedinit(SB) + + // create a new goroutine to start program + MOVD $runtime·mainPC(SB), R3 // entry + MOVDU R3, -8(R1) + MOVDU R0, -8(R1) + MOVDU R0, -8(R1) + MOVDU R0, -8(R1) + MOVDU R0, -8(R1) + BL runtime·newproc(SB) + ADD $(8+FIXED_FRAME), R1 + + // start this M + BL runtime·mstart(SB) + // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are + // intended to be called by debuggers. +#ifdef GOARCH_ppc64le + MOVD $runtime·debugPinnerV1(SB), R31 + MOVD $runtime·debugCallV2(SB), R31 +#endif + MOVD R0, 0(R0) + RET + +DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) +GLOBL runtime·mainPC(SB),RODATA,$8 + +TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0 + TW $31, R0, R0 + RET + +TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0 + RET + +// Any changes must be reflected to runtime/cgo/gcc_aix_ppc64.S:.crosscall_ppc64 +TEXT _cgo_reginit(SB),NOSPLIT|NOFRAME,$0-0 + // crosscall_ppc64 and crosscall2 need to reginit, but can't + // get at the 'runtime.reginit' symbol. + BR runtime·reginit(SB) + +TEXT runtime·reginit(SB),NOSPLIT|NOFRAME,$0-0 + // set R0 to zero, it's expected by the toolchain + XOR R0, R0 + RET + +TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 + BL runtime·mstart0(SB) + RET // not reached + +/* + * go-routine + */ + +// void gogo(Gobuf*) +// restore state from Gobuf; longjmp +TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8 + MOVD buf+0(FP), R5 + MOVD gobuf_g(R5), R6 + MOVD 0(R6), R4 // make sure g != nil + BR gogo<>(SB) + +TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 + MOVD R6, g + BL runtime·save_g(SB) + + MOVD gobuf_sp(R5), R1 + MOVD gobuf_lr(R5), R31 +#ifndef GOOS_aix + MOVD 24(R1), R2 // restore R2 +#endif + MOVD R31, LR + MOVD gobuf_ret(R5), R3 + MOVD gobuf_ctxt(R5), R11 + MOVD R0, gobuf_sp(R5) + MOVD R0, gobuf_ret(R5) + MOVD R0, gobuf_lr(R5) + MOVD R0, gobuf_ctxt(R5) + CMP R0, R0 // set condition codes for == test, needed by stack split + MOVD gobuf_pc(R5), R12 + MOVD R12, CTR + BR (CTR) + +// void mcall(fn func(*g)) +// Switch to m->g0's stack, call fn(g). +// Fn must never return. It should gogo(&g->sched) +// to keep running g. +TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 + // Save caller state in g->sched + // R11 should be safe across save_g?? + MOVD R3, R11 + MOVD R1, (g_sched+gobuf_sp)(g) + MOVD LR, R31 + MOVD R31, (g_sched+gobuf_pc)(g) + MOVD R0, (g_sched+gobuf_lr)(g) + + // Switch to m->g0 & its stack, call fn. + MOVD g, R3 + MOVD g_m(g), R8 + MOVD m_g0(R8), g + BL runtime·save_g(SB) + CMP g, R3 + BNE 2(PC) + BR runtime·badmcall(SB) + MOVD 0(R11), R12 // code pointer + MOVD R12, CTR + MOVD (g_sched+gobuf_sp)(g), R1 // sp = m->g0->sched.sp + // Don't need to do anything special for regabiargs here + // R3 is g; stack is set anyway + MOVDU R3, -8(R1) + MOVDU R0, -8(R1) + MOVDU R0, -8(R1) + MOVDU R0, -8(R1) + MOVDU R0, -8(R1) + BL (CTR) + MOVD 24(R1), R2 + BR runtime·badmcall2(SB) + +// systemstack_switch is a dummy routine that systemstack leaves at the bottom +// of the G stack. We need to distinguish the routine that +// lives at the bottom of the G stack from the one that lives +// at the top of the system stack because the one at the top of +// the system stack terminates the stack walk (see topofstack()). +TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 + // We have several undefs here so that 16 bytes past + // $runtime·systemstack_switch lies within them whether or not the + // instructions that derive r2 from r12 are there. + UNDEF + UNDEF + UNDEF + BL (LR) // make sure this function is not leaf + RET + +// func systemstack(fn func()) +TEXT runtime·systemstack(SB), NOSPLIT, $0-8 + MOVD fn+0(FP), R3 // R3 = fn + MOVD R3, R11 // context + MOVD g_m(g), R4 // R4 = m + + MOVD m_gsignal(R4), R5 // R5 = gsignal + CMP g, R5 + BEQ noswitch + + MOVD m_g0(R4), R5 // R5 = g0 + CMP g, R5 + BEQ noswitch + + MOVD m_curg(R4), R6 + CMP g, R6 + BEQ switch + + // Bad: g is not gsignal, not g0, not curg. What is it? + // Hide call from linker nosplit analysis. + MOVD $runtime·badsystemstack(SB), R12 + MOVD R12, CTR + BL (CTR) + BL runtime·abort(SB) + +switch: + // save our state in g->sched. Pretend to + // be systemstack_switch if the G stack is scanned. + BL gosave_systemstack_switch<>(SB) + + // switch to g0 + MOVD R5, g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R1 + + // call target function + MOVD 0(R11), R12 // code pointer + MOVD R12, CTR + BL (CTR) + + // restore TOC pointer. It seems unlikely that we will use systemstack + // to call a function defined in another module, but the results of + // doing so would be so confusing that it's worth doing this. + MOVD g_m(g), R3 + MOVD m_curg(R3), g + MOVD (g_sched+gobuf_sp)(g), R3 +#ifndef GOOS_aix + MOVD 24(R3), R2 +#endif + // switch back to g + MOVD g_m(g), R3 + MOVD m_curg(R3), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R1 + MOVD R0, (g_sched+gobuf_sp)(g) + RET + +noswitch: + // already on m stack, just call directly + // On other arches we do a tail call here, but it appears to be + // impossible to tail call a function pointer in shared mode on + // ppc64 because the caller is responsible for restoring the TOC. + MOVD 0(R11), R12 // code pointer + MOVD R12, CTR + BL (CTR) +#ifndef GOOS_aix + MOVD 24(R1), R2 +#endif + RET + +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 + MOVD R3, R11 // context register + MOVD g_m(g), R3 // curm + + // set g to gcrash + MOVD $runtime·gcrash(SB), g // g = &gcrash + CALL runtime·save_g(SB) // clobbers R31 + MOVD R3, g_m(g) // g.m = curm + MOVD g, m_g0(R3) // curm.g0 = g + + // switch to crashstack + MOVD (g_stack+stack_hi)(g), R3 + SUB $(4*8), R3 + MOVD R3, R1 + + // call target function + MOVD 0(R11), R12 // code pointer + MOVD R12, CTR + BL (CTR) + + // should never return + CALL runtime·abort(SB) + UNDEF + +/* + * support for morestack + */ + +// Called during function prolog when more stack is needed. +// Caller has already loaded: +// R3: framesize, R4: argsize, R5: LR +// +// The traceback routines see morestack on a g0 as being +// the top of a stack (for example, morestack calling newstack +// calling the scheduler calling newm calling gc), so we must +// record an argument size. For that purpose, it has no arguments. +TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 + // Called from f. + // Set g->sched to context in f. + MOVD R1, (g_sched+gobuf_sp)(g) + MOVD LR, R8 + MOVD R8, (g_sched+gobuf_pc)(g) + MOVD R5, (g_sched+gobuf_lr)(g) + MOVD R11, (g_sched+gobuf_ctxt)(g) + + // Cannot grow scheduler stack (m->g0). + MOVD g_m(g), R7 + MOVD m_g0(R7), R8 + CMP g, R8 + BNE 3(PC) + BL runtime·badmorestackg0(SB) + BL runtime·abort(SB) + + // Cannot grow signal stack (m->gsignal). + MOVD m_gsignal(R7), R8 + CMP g, R8 + BNE 3(PC) + BL runtime·badmorestackgsignal(SB) + BL runtime·abort(SB) + + // Called from f. + // Set m->morebuf to f's caller. + MOVD R5, (m_morebuf+gobuf_pc)(R7) // f's caller's PC + MOVD R1, (m_morebuf+gobuf_sp)(R7) // f's caller's SP + MOVD g, (m_morebuf+gobuf_g)(R7) + + // Call newstack on m->g0's stack. + MOVD m_g0(R7), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R1 + MOVDU R0, -(FIXED_FRAME+0)(R1) // create a call frame on g0 + BL runtime·newstack(SB) + + // Not reached, but make sure the return PC from the call to newstack + // is still in this function, and not the beginning of the next. + UNDEF + +TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 + // Force SPWRITE. This function doesn't actually write SP, + // but it is called with a special calling convention where + // the caller doesn't save LR on stack but passes it as a + // register (R5), and the unwinder currently doesn't understand. + // Make it SPWRITE to stop unwinding. (See issue 54332) + // Use OR R0, R1 instead of MOVD R1, R1 as the MOVD instruction + // has a special affect on Power8,9,10 by lowering the thread + // priority and causing a slowdown in execution time + + OR R0, R1 + MOVD R0, R11 + BR runtime·morestack(SB) + +// reflectcall: call a function with the given argument list +// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). +// we don't have variable-sized frames, so we use a small number +// of constant-sized-frame functions to encode a few bits of size in the pc. +// Caution: ugly multiline assembly macros in your future! + +#define DISPATCH(NAME,MAXSIZE) \ + MOVD $MAXSIZE, R31; \ + CMP R3, R31; \ + BGT 4(PC); \ + MOVD $NAME(SB), R12; \ + MOVD R12, CTR; \ + BR (CTR) +// Note: can't just "BR NAME(SB)" - bad inlining results. + +TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-48 + MOVWZ frameSize+32(FP), R3 + DISPATCH(runtime·call16, 16) + DISPATCH(runtime·call32, 32) + DISPATCH(runtime·call64, 64) + DISPATCH(runtime·call128, 128) + DISPATCH(runtime·call256, 256) + DISPATCH(runtime·call512, 512) + DISPATCH(runtime·call1024, 1024) + DISPATCH(runtime·call2048, 2048) + DISPATCH(runtime·call4096, 4096) + DISPATCH(runtime·call8192, 8192) + DISPATCH(runtime·call16384, 16384) + DISPATCH(runtime·call32768, 32768) + DISPATCH(runtime·call65536, 65536) + DISPATCH(runtime·call131072, 131072) + DISPATCH(runtime·call262144, 262144) + DISPATCH(runtime·call524288, 524288) + DISPATCH(runtime·call1048576, 1048576) + DISPATCH(runtime·call2097152, 2097152) + DISPATCH(runtime·call4194304, 4194304) + DISPATCH(runtime·call8388608, 8388608) + DISPATCH(runtime·call16777216, 16777216) + DISPATCH(runtime·call33554432, 33554432) + DISPATCH(runtime·call67108864, 67108864) + DISPATCH(runtime·call134217728, 134217728) + DISPATCH(runtime·call268435456, 268435456) + DISPATCH(runtime·call536870912, 536870912) + DISPATCH(runtime·call1073741824, 1073741824) + MOVD $runtime·badreflectcall(SB), R12 + MOVD R12, CTR + BR (CTR) + +#define CALLFN(NAME,MAXSIZE) \ +TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ + NO_LOCAL_POINTERS; \ + /* copy arguments to stack */ \ + MOVD stackArgs+16(FP), R3; \ + MOVWZ stackArgsSize+24(FP), R4; \ + MOVD R1, R5; \ + CMP R4, $8; \ + BLT tailsetup; \ + /* copy 8 at a time if possible */ \ + ADD $(FIXED_FRAME-8), R5; \ + SUB $8, R3; \ +top: \ + MOVDU 8(R3), R7; \ + MOVDU R7, 8(R5); \ + SUB $8, R4; \ + CMP R4, $8; \ + BGE top; \ + /* handle remaining bytes */ \ + CMP $0, R4; \ + BEQ callfn; \ + ADD $7, R3; \ + ADD $7, R5; \ + BR tail; \ +tailsetup: \ + CMP $0, R4; \ + BEQ callfn; \ + ADD $(FIXED_FRAME-1), R5; \ + SUB $1, R3; \ +tail: \ + MOVBU 1(R3), R6; \ + MOVBU R6, 1(R5); \ + SUB $1, R4; \ + CMP $0, R4; \ + BGT tail; \ +callfn: \ + /* call function */ \ + MOVD f+8(FP), R11; \ +#ifdef GOOS_aix \ + /* AIX won't trigger a SIGSEGV if R11 = nil */ \ + /* So it manually triggers it */ \ + CMP R11, $0 \ + BNE 2(PC) \ + MOVD R0, 0(R0) \ +#endif \ + MOVD regArgs+40(FP), R20; \ + BL runtime·unspillArgs(SB); \ + MOVD (R11), R12; \ + MOVD R12, CTR; \ + PCDATA $PCDATA_StackMapIndex, $0; \ + BL (CTR); \ +#ifndef GOOS_aix \ + MOVD 24(R1), R2; \ +#endif \ + /* copy return values back */ \ + MOVD regArgs+40(FP), R20; \ + BL runtime·spillArgs(SB); \ + MOVD stackArgsType+0(FP), R7; \ + MOVD stackArgs+16(FP), R3; \ + MOVWZ stackArgsSize+24(FP), R4; \ + MOVWZ stackRetOffset+28(FP), R6; \ + ADD $FIXED_FRAME, R1, R5; \ + ADD R6, R5; \ + ADD R6, R3; \ + SUB R6, R4; \ + BL callRet<>(SB); \ + RET + +// callRet copies return values back at the end of call*. This is a +// separate function so it can allocate stack space for the arguments +// to reflectcallmove. It does not follow the Go ABI; it expects its +// arguments in registers. +TEXT callRet<>(SB), NOSPLIT, $40-0 + NO_LOCAL_POINTERS + MOVD R7, FIXED_FRAME+0(R1) + MOVD R3, FIXED_FRAME+8(R1) + MOVD R5, FIXED_FRAME+16(R1) + MOVD R4, FIXED_FRAME+24(R1) + MOVD R20, FIXED_FRAME+32(R1) + BL runtime·reflectcallmove(SB) + RET + +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) + +TEXT runtime·procyield(SB),NOSPLIT|NOFRAME,$0-4 + MOVW cycles+0(FP), R7 + // POWER does not have a pause/yield instruction equivalent. + // Instead, we can lower the program priority by setting the + // Program Priority Register prior to the wait loop and set it + // back to default afterwards. On Linux, the default priority is + // medium-low. For details, see page 837 of the ISA 3.0. + OR R1, R1, R1 // Set PPR priority to low +again: + SUB $1, R7 + CMP $0, R7 + BNE again + OR R6, R6, R6 // Set PPR priority back to medium-low + RET + +// Save state of caller into g->sched, +// but using fake PC from systemstack_switch. +// Must only be called from functions with no locals ($0) +// or else unwinding from systemstack_switch is incorrect. +// Smashes R31. +TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 + MOVD $runtime·systemstack_switch(SB), R31 + ADD $16, R31 // get past prologue (including r2-setting instructions when they're there) + MOVD R31, (g_sched+gobuf_pc)(g) + MOVD R1, (g_sched+gobuf_sp)(g) + MOVD R0, (g_sched+gobuf_lr)(g) + MOVD R0, (g_sched+gobuf_ret)(g) + // Assert ctxt is zero. See func save. + MOVD (g_sched+gobuf_ctxt)(g), R31 + CMP R31, $0 + BEQ 2(PC) + BL runtime·abort(SB) + RET + +#ifdef GOOS_aix +#define asmcgocallSaveOffset cgoCalleeStackSize + 8 +#else +#define asmcgocallSaveOffset cgoCalleeStackSize +#endif + +// func asmcgocall_no_g(fn, arg unsafe.Pointer) +// Call fn(arg) aligned appropriately for the gcc ABI. +// Called on a system stack, and there may be no g yet (during needm). +TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16 + MOVD fn+0(FP), R3 + MOVD arg+8(FP), R4 + + MOVD R1, R15 + SUB $(asmcgocallSaveOffset+8), R1 + RLDCR $0, R1, $~15, R1 // 16-byte alignment for gcc ABI + MOVD R15, asmcgocallSaveOffset(R1) + + MOVD R0, 0(R1) // clear back chain pointer (TODO can we give it real back trace information?) + + // This is a "global call", so put the global entry point in r12 + MOVD R3, R12 + +#ifdef GO_PPC64X_HAS_FUNCDESC + // Load the real entry address from the first slot of the function descriptor. + MOVD 8(R12), R2 + MOVD (R12), R12 +#endif + MOVD R12, CTR + MOVD R4, R3 // arg in r3 + BL (CTR) + + // C code can clobber R0, so set it back to 0. F27-F31 are + // callee save, so we don't need to recover those. + XOR R0, R0 + + MOVD asmcgocallSaveOffset(R1), R1 // Restore stack pointer. +#ifndef GOOS_aix + MOVD 24(R1), R2 +#endif + + RET + +// func asmcgocall(fn, arg unsafe.Pointer) int32 +// Call fn(arg) on the scheduler stack, +// aligned appropriately for the gcc ABI. +// See cgocall.go for more details. +TEXT ·asmcgocall(SB),NOSPLIT,$0-20 + // R3 = fn + // R4 = arg + + MOVD R1, R7 // save original stack pointer + CMP $0, g + BEQ nosave + MOVD g, R5 + + // Figure out if we need to switch to m->g0 stack. + // We get called to create new OS threads too, and those + // come in on the m->g0 stack already. Or we might already + // be on the m->gsignal stack. + MOVD g_m(g), R8 + MOVD m_gsignal(R8), R6 + CMP R6, g + BEQ nosave + MOVD m_g0(R8), R6 + CMP R6, g + BEQ nosave + + BL gosave_systemstack_switch<>(SB) + MOVD R6, g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R1 + + // Now on a scheduling stack (a pthread-created stack). +#ifdef GOOS_aix + // Create a fake LR to improve backtrace. + MOVD $runtime·asmcgocall(SB), R6 + MOVD R6, 16(R1) + // AIX also saves one argument on the stack. + SUB $8, R1 +#endif + // Save room for two of our pointers, plus the callee + // save area that lives on the caller stack. + // Do arithmetics in R10 to hide from the assembler + // counting it as SP delta, which is irrelevant as we are + // on the system stack. + SUB $(asmcgocallSaveOffset+16), R1, R10 + RLDCR $0, R10, $~15, R1 // 16-byte alignment for gcc ABI + MOVD R5, (asmcgocallSaveOffset+8)(R1) // save old g on stack + MOVD (g_stack+stack_hi)(R5), R5 + SUB R7, R5 + MOVD R5, asmcgocallSaveOffset(R1) // save depth in old g stack (can't just save SP, as stack might be copied during a callback) +#ifdef GOOS_aix + MOVD R7, 0(R1) // Save frame pointer to allow manual backtrace with gdb +#else + MOVD R0, 0(R1) // clear back chain pointer (TODO can we give it real back trace information?) +#endif + // This is a "global call", so put the global entry point in r12 + MOVD R3, R12 + +#ifdef GO_PPC64X_HAS_FUNCDESC + // Load the real entry address from the first slot of the function descriptor. + MOVD 8(R12), R2 + MOVD (R12), R12 +#endif + MOVD R12, CTR + MOVD R4, R3 // arg in r3 + BL (CTR) + + // Reinitialise zero value register. + XOR R0, R0 + + // Restore g, stack pointer, toc pointer. + // R3 is errno, so don't touch it + MOVD (asmcgocallSaveOffset+8)(R1), g + MOVD (g_stack+stack_hi)(g), R5 + MOVD asmcgocallSaveOffset(R1), R6 + SUB R6, R5 +#ifndef GOOS_aix + MOVD 24(R5), R2 +#endif + MOVD R5, R1 + BL runtime·save_g(SB) + + // ret = R3 + RET + +nosave: + // Running on a system stack, perhaps even without a g. + // Having no g can happen during thread creation or thread teardown. + // This code is like the above sequence but without saving/restoring g + // and without worrying about the stack moving out from under us + // (because we're on a system stack, not a goroutine stack). + // The above code could be used directly if already on a system stack, + // but then the only path through this code would be a rare case. + // Using this code for all "already on system stack" calls exercises it more, + // which should help keep it correct. + + SUB $(asmcgocallSaveOffset+8), R1, R10 + RLDCR $0, R10, $~15, R1 // 16-byte alignment for gcc ABI + MOVD R7, asmcgocallSaveOffset(R1) // Save original stack pointer. + + MOVD R3, R12 // fn +#ifdef GO_PPC64X_HAS_FUNCDESC + // Load the real entry address from the first slot of the function descriptor. + MOVD 8(R12), R2 + MOVD (R12), R12 +#endif + MOVD R12, CTR + MOVD R4, R3 // arg + BL (CTR) + + // Reinitialise zero value register. + XOR R0, R0 + + MOVD asmcgocallSaveOffset(R1), R1 // Restore stack pointer. +#ifndef GOOS_aix + MOVD 24(R1), R2 +#endif + // ret = R3 + RET + +// func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) +// See cgocall.go for more details. +TEXT ·cgocallback(SB),NOSPLIT,$24-24 + NO_LOCAL_POINTERS + + // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. + // It is used to dropm while thread is exiting. + MOVD fn+0(FP), R5 + CMP R5, $0 + BNE loadg + // Restore the g from frame. + MOVD frame+8(FP), g + BR dropm + +loadg: + // Load m and g from thread-local storage. +#ifndef GOOS_openbsd + MOVBZ runtime·iscgo(SB), R3 + CMP R3, $0 + BEQ nocgo +#endif + BL runtime·load_g(SB) +nocgo: + + // If g is nil, Go did not create the current thread, + // or if this thread never called into Go on pthread platforms. + // Call needm to obtain one for temporary use. + // In this case, we're running on the thread stack, so there's + // lots of space, but the linker doesn't know. Hide the call from + // the linker analysis by using an indirect call. + CMP g, $0 + BEQ needm + + MOVD g_m(g), R8 + MOVD R8, savedm-8(SP) + BR havem + +needm: + MOVD g, savedm-8(SP) // g is zero, so is m. + MOVD $runtime·needAndBindM(SB), R12 + MOVD R12, CTR + BL (CTR) + + // Set m->sched.sp = SP, so that if a panic happens + // during the function we are about to execute, it will + // have a valid SP to run on the g0 stack. + // The next few lines (after the havem label) + // will save this SP onto the stack and then write + // the same SP back to m->sched.sp. That seems redundant, + // but if an unrecovered panic happens, unwindm will + // restore the g->sched.sp from the stack location + // and then systemstack will try to use it. If we don't set it here, + // that restored SP will be uninitialized (typically 0) and + // will not be usable. + MOVD g_m(g), R8 + MOVD m_g0(R8), R3 + MOVD R1, (g_sched+gobuf_sp)(R3) + +havem: + // Now there's a valid m, and we're running on its m->g0. + // Save current m->g0->sched.sp on stack and then set it to SP. + // Save current sp in m->g0->sched.sp in preparation for + // switch back to m->curg stack. + // NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP). + MOVD m_g0(R8), R3 + MOVD (g_sched+gobuf_sp)(R3), R4 + MOVD R4, savedsp-24(SP) // must match frame size + MOVD R1, (g_sched+gobuf_sp)(R3) + + // Switch to m->curg stack and call runtime.cgocallbackg. + // Because we are taking over the execution of m->curg + // but *not* resuming what had been running, we need to + // save that information (m->curg->sched) so we can restore it. + // We can restore m->curg->sched.sp easily, because calling + // runtime.cgocallbackg leaves SP unchanged upon return. + // To save m->curg->sched.pc, we push it onto the curg stack and + // open a frame the same size as cgocallback's g0 frame. + // Once we switch to the curg stack, the pushed PC will appear + // to be the return PC of cgocallback, so that the traceback + // will seamlessly trace back into the earlier calls. + MOVD m_curg(R8), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 + MOVD (g_sched+gobuf_pc)(g), R5 + MOVD R5, -(24+FIXED_FRAME)(R4) // "saved LR"; must match frame size + // Gather our arguments into registers. + MOVD fn+0(FP), R5 + MOVD frame+8(FP), R6 + MOVD ctxt+16(FP), R7 + MOVD $-(24+FIXED_FRAME)(R4), R1 // switch stack; must match frame size + MOVD R5, FIXED_FRAME+0(R1) + MOVD R6, FIXED_FRAME+8(R1) + MOVD R7, FIXED_FRAME+16(R1) + + MOVD $runtime·cgocallbackg(SB), R12 + MOVD R12, CTR + CALL (CTR) // indirect call to bypass nosplit check. We're on a different stack now. + + // Restore g->sched (== m->curg->sched) from saved values. + MOVD 0(R1), R5 + MOVD R5, (g_sched+gobuf_pc)(g) + MOVD $(24+FIXED_FRAME)(R1), R4 // must match frame size + MOVD R4, (g_sched+gobuf_sp)(g) + + // Switch back to m->g0's stack and restore m->g0->sched.sp. + // (Unlike m->curg, the g0 goroutine never uses sched.pc, + // so we do not have to restore it.) + MOVD g_m(g), R8 + MOVD m_g0(R8), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R1 + MOVD savedsp-24(SP), R4 // must match frame size + MOVD R4, (g_sched+gobuf_sp)(g) + + // If the m on entry was nil, we called needm above to borrow an m, + // 1. for the duration of the call on non-pthread platforms, + // 2. or the duration of the C thread alive on pthread platforms. + // If the m on entry wasn't nil, + // 1. the thread might be a Go thread, + // 2. or it wasn't the first call from a C thread on pthread platforms, + // since then we skip dropm to reuse the m in the first call. + MOVD savedm-8(SP), R6 + CMP R6, $0 + BNE droppedm + + // Skip dropm to reuse it in the next call, when a pthread key has been created. + MOVD _cgo_pthread_key_created(SB), R6 + // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. + CMP R6, $0 + BEQ dropm + MOVD (R6), R6 + CMP R6, $0 + BNE droppedm + +dropm: + MOVD $runtime·dropm(SB), R12 + MOVD R12, CTR + BL (CTR) +droppedm: + + // Done! + RET + +// void setg(G*); set g. for use by needm. +TEXT runtime·setg(SB), NOSPLIT, $0-8 + MOVD gg+0(FP), g + // This only happens if iscgo, so jump straight to save_g + BL runtime·save_g(SB) + RET + +#ifdef GO_PPC64X_HAS_FUNCDESC +DEFINE_PPC64X_FUNCDESC(setg_gcc<>, _setg_gcc<>) +TEXT _setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 +#else +TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 +#endif + // The standard prologue clobbers R31, which is callee-save in + // the C ABI, so we have to use $-8-0 and save LR ourselves. + MOVD LR, R4 + // Also save g and R31, since they're callee-save in C ABI + MOVD R31, R5 + MOVD g, R6 + + MOVD R3, g + BL runtime·save_g(SB) + + MOVD R6, g + MOVD R5, R31 + MOVD R4, LR + RET + +TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 + MOVW (R0), R0 + UNDEF + +#define TBR 268 + +// int64 runtime·cputicks(void) +TEXT runtime·cputicks(SB),NOSPLIT,$0-8 + MOVD SPR(TBR), R3 + MOVD R3, ret+0(FP) + RET + +// spillArgs stores return values from registers to a *internal/abi.RegArgs in R20. +TEXT runtime·spillArgs(SB),NOSPLIT,$0-0 + MOVD R3, 0(R20) + MOVD R4, 8(R20) + MOVD R5, 16(R20) + MOVD R6, 24(R20) + MOVD R7, 32(R20) + MOVD R8, 40(R20) + MOVD R9, 48(R20) + MOVD R10, 56(R20) + MOVD R14, 64(R20) + MOVD R15, 72(R20) + MOVD R16, 80(R20) + MOVD R17, 88(R20) + FMOVD F1, 96(R20) + FMOVD F2, 104(R20) + FMOVD F3, 112(R20) + FMOVD F4, 120(R20) + FMOVD F5, 128(R20) + FMOVD F6, 136(R20) + FMOVD F7, 144(R20) + FMOVD F8, 152(R20) + FMOVD F9, 160(R20) + FMOVD F10, 168(R20) + FMOVD F11, 176(R20) + FMOVD F12, 184(R20) + RET + +// unspillArgs loads args into registers from a *internal/abi.RegArgs in R20. +TEXT runtime·unspillArgs(SB),NOSPLIT,$0-0 + MOVD 0(R20), R3 + MOVD 8(R20), R4 + MOVD 16(R20), R5 + MOVD 24(R20), R6 + MOVD 32(R20), R7 + MOVD 40(R20), R8 + MOVD 48(R20), R9 + MOVD 56(R20), R10 + MOVD 64(R20), R14 + MOVD 72(R20), R15 + MOVD 80(R20), R16 + MOVD 88(R20), R17 + FMOVD 96(R20), F1 + FMOVD 104(R20), F2 + FMOVD 112(R20), F3 + FMOVD 120(R20), F4 + FMOVD 128(R20), F5 + FMOVD 136(R20), F6 + FMOVD 144(R20), F7 + FMOVD 152(R20), F8 + FMOVD 160(R20), F9 + FMOVD 168(R20), F10 + FMOVD 176(R20), F11 + FMOVD 184(R20), F12 + RET + +// AES hashing not implemented for ppc64 +TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 + JMP runtime·memhashFallback(SB) +TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 + JMP runtime·strhashFallback(SB) +TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 + JMP runtime·memhash32Fallback(SB) +TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 + JMP runtime·memhash64Fallback(SB) + +TEXT runtime·return0(SB), NOSPLIT, $0 + MOVW $0, R3 + RET + +// Called from cgo wrappers, this function returns g->m->curg.stack.hi. +// Must obey the gcc calling convention. +#ifdef GOOS_aix +// On AIX, _cgo_topofstack is defined in runtime/cgo, because it must +// be a longcall in order to prevent trampolines from ld. +TEXT __cgo_topofstack(SB),NOSPLIT|NOFRAME,$0 +#else +TEXT _cgo_topofstack(SB),NOSPLIT|NOFRAME,$0 +#endif + // g (R30) and R31 are callee-save in the C ABI, so save them + MOVD g, R4 + MOVD R31, R5 + MOVD LR, R6 + + BL runtime·load_g(SB) // clobbers g (R30), R31 + MOVD g_m(g), R3 + MOVD m_curg(R3), R3 + MOVD (g_stack+stack_hi)(R3), R3 + + MOVD R4, g + MOVD R5, R31 + MOVD R6, LR + RET + +// The top-most function running on a goroutine +// returns to goexit+PCQuantum. +// +// When dynamically linking Go, it can be returned to from a function +// implemented in a different module and so needs to reload the TOC pointer +// from the stack (although this function declares that it does not set up x-a +// frame, newproc1 does in fact allocate one for goexit and saves the TOC +// pointer in the correct place). +// goexit+_PCQuantum is halfway through the usual global entry point prologue +// that derives r2 from r12 which is a bit silly, but not harmful. +TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 + MOVD 24(R1), R2 + BL runtime·goexit1(SB) // does not return + // traceback from goexit1 must hit code range of goexit + MOVD R0, R0 // NOP + +// prepGoExitFrame saves the current TOC pointer (i.e. the TOC pointer for the +// module containing runtime) to the frame that goexit will execute in when +// the goroutine exits. It's implemented in assembly mainly because that's the +// easiest way to get access to R2. +TEXT runtime·prepGoExitFrame(SB),NOSPLIT,$0-8 + MOVD sp+0(FP), R3 + MOVD R2, 24(R3) + RET + +TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0 + ADD $-8, R1 + MOVD R31, 0(R1) + MOVD runtime·lastmoduledatap(SB), R4 + MOVD R3, moduledata_next(R4) + MOVD R3, runtime·lastmoduledatap(SB) + MOVD 0(R1), R31 + ADD $8, R1 + RET + +TEXT ·checkASM(SB),NOSPLIT,$0-1 + MOVW $1, R3 + MOVB R3, ret+0(FP) + RET + +// gcWriteBarrier informs the GC about heap pointer writes. +// +// gcWriteBarrier does NOT follow the Go ABI. It accepts the +// number of bytes of buffer needed in R29, and returns a pointer +// to the buffer space in R29. +// It clobbers condition codes. +// It does not clobber R0 through R17 (except special registers), +// but may clobber any other register, *including* R31. +TEXT gcWriteBarrier<>(SB),NOSPLIT,$120 + // The standard prologue clobbers R31. + // We use R18, R19, and R31 as scratch registers. +retry: + MOVD g_m(g), R18 + MOVD m_p(R18), R18 + MOVD (p_wbBuf+wbBuf_next)(R18), R19 + MOVD (p_wbBuf+wbBuf_end)(R18), R31 + // Increment wbBuf.next position. + ADD R29, R19 + // Is the buffer full? + CMPU R31, R19 + BLT flush + // Commit to the larger buffer. + MOVD R19, (p_wbBuf+wbBuf_next)(R18) + // Make return value (the original next position) + SUB R29, R19, R29 + RET + +flush: + // Save registers R0 through R15 since these were not saved by the caller. + // We don't save all registers on ppc64 because it takes too much space. + MOVD R20, (FIXED_FRAME+0)(R1) + MOVD R21, (FIXED_FRAME+8)(R1) + // R0 is always 0, so no need to spill. + // R1 is SP. + // R2 is SB. + MOVD R3, (FIXED_FRAME+16)(R1) + MOVD R4, (FIXED_FRAME+24)(R1) + MOVD R5, (FIXED_FRAME+32)(R1) + MOVD R6, (FIXED_FRAME+40)(R1) + MOVD R7, (FIXED_FRAME+48)(R1) + MOVD R8, (FIXED_FRAME+56)(R1) + MOVD R9, (FIXED_FRAME+64)(R1) + MOVD R10, (FIXED_FRAME+72)(R1) + // R11, R12 may be clobbered by external-linker-inserted trampoline + // R13 is REGTLS + MOVD R14, (FIXED_FRAME+80)(R1) + MOVD R15, (FIXED_FRAME+88)(R1) + MOVD R16, (FIXED_FRAME+96)(R1) + MOVD R17, (FIXED_FRAME+104)(R1) + MOVD R29, (FIXED_FRAME+112)(R1) + + CALL runtime·wbBufFlush(SB) + + MOVD (FIXED_FRAME+0)(R1), R20 + MOVD (FIXED_FRAME+8)(R1), R21 + MOVD (FIXED_FRAME+16)(R1), R3 + MOVD (FIXED_FRAME+24)(R1), R4 + MOVD (FIXED_FRAME+32)(R1), R5 + MOVD (FIXED_FRAME+40)(R1), R6 + MOVD (FIXED_FRAME+48)(R1), R7 + MOVD (FIXED_FRAME+56)(R1), R8 + MOVD (FIXED_FRAME+64)(R1), R9 + MOVD (FIXED_FRAME+72)(R1), R10 + MOVD (FIXED_FRAME+80)(R1), R14 + MOVD (FIXED_FRAME+88)(R1), R15 + MOVD (FIXED_FRAME+96)(R1), R16 + MOVD (FIXED_FRAME+104)(R1), R17 + MOVD (FIXED_FRAME+112)(R1), R29 + JMP retry + +TEXT runtime·gcWriteBarrier1(SB),NOSPLIT,$0 + MOVD $8, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier2(SB),NOSPLIT,$0 + MOVD $16, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier3(SB),NOSPLIT,$0 + MOVD $24, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier4(SB),NOSPLIT,$0 + MOVD $32, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier5(SB),NOSPLIT,$0 + MOVD $40, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier6(SB),NOSPLIT,$0 + MOVD $48, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier7(SB),NOSPLIT,$0 + MOVD $56, R29 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier8(SB),NOSPLIT,$0 + MOVD $64, R29 + JMP gcWriteBarrier<>(SB) + +DATA debugCallFrameTooLarge<>+0x00(SB)/20, $"call frame too large" +GLOBL debugCallFrameTooLarge<>(SB), RODATA, $20 // Size duplicated below + +// debugCallV2 is the entry point for debugger-injected function +// calls on running goroutines. It informs the runtime that a +// debug call has been injected and creates a call frame for the +// debugger to fill in. +// +// To inject a function call, a debugger should: +// 1. Check that the goroutine is in state _Grunning and that +// there are at least 320 bytes free on the stack. +// 2. Set SP as SP-32. +// 3. Store the current LR in (SP) (using the SP after step 2). +// 4. Store the current PC in the LR register. +// 5. Write the desired argument frame size at SP-32 +// 6. Save all machine registers (including flags and floating point registers) +// so they can be restored later by the debugger. +// 7. Set the PC to debugCallV2 and resume execution. +// +// If the goroutine is in state _Grunnable, then it's not generally +// safe to inject a call because it may return out via other runtime +// operations. Instead, the debugger should unwind the stack to find +// the return to non-runtime code, add a temporary breakpoint there, +// and inject the call once that breakpoint is hit. +// +// If the goroutine is in any other state, it's not safe to inject a call. +// +// This function communicates back to the debugger by setting R20 and +// invoking TW to raise a breakpoint signal. Note that the signal PC of +// the signal triggered by the TW instruction is the PC where the signal +// is trapped, not the next PC, so to resume execution, the debugger needs +// to set the signal PC to PC+4. See the comments in the implementation for +// the protocol the debugger is expected to follow. InjectDebugCall in the +// runtime tests demonstrates this protocol. +// The debugger must ensure that any pointers passed to the function +// obey escape analysis requirements. Specifically, it must not pass +// a stack pointer to an escaping argument. debugCallV2 cannot check +// this invariant. +// +// This is ABIInternal because Go code injects its PC directly into new +// goroutine stacks. +#ifdef GOARCH_ppc64le +TEXT runtime·debugCallV2(SB), NOSPLIT|NOFRAME, $0-0 + // save scratch register R31 first + MOVD R31, -184(R1) + MOVD 0(R1), R31 + // save caller LR + MOVD R31, -304(R1) + MOVD -32(R1), R31 + // save argument frame size + MOVD R31, -192(R1) + MOVD LR, R31 + MOVD R31, -320(R1) + ADD $-320, R1 + // save all registers that can contain pointers + // and the CR register + MOVW CR, R31 + MOVD R31, 8(R1) + MOVD R2, 24(R1) + MOVD R3, 56(R1) + MOVD R4, 64(R1) + MOVD R5, 72(R1) + MOVD R6, 80(R1) + MOVD R7, 88(R1) + MOVD R8, 96(R1) + MOVD R9, 104(R1) + MOVD R10, 112(R1) + MOVD R11, 120(R1) + MOVD R12, 144(R1) + MOVD R13, 152(R1) + MOVD R14, 160(R1) + MOVD R15, 168(R1) + MOVD R16, 176(R1) + MOVD R17, 184(R1) + MOVD R18, 192(R1) + MOVD R19, 200(R1) + MOVD R20, 208(R1) + MOVD R21, 216(R1) + MOVD R22, 224(R1) + MOVD R23, 232(R1) + MOVD R24, 240(R1) + MOVD R25, 248(R1) + MOVD R26, 256(R1) + MOVD R27, 264(R1) + MOVD R28, 272(R1) + MOVD R29, 280(R1) + MOVD g, 288(R1) + MOVD LR, R31 + MOVD R31, 32(R1) + CALL runtime·debugCallCheck(SB) + MOVD 40(R1), R22 + XOR R0, R0 + CMP R22, $0 + BEQ good + MOVD 48(R1), R22 + MOVD $8, R20 + TW $31, R0, R0 + + BR restore + +good: +#define DEBUG_CALL_DISPATCH(NAME,MAXSIZE) \ + MOVD $MAXSIZE, R23; \ + CMP R26, R23; \ + BGT 5(PC); \ + MOVD $NAME(SB), R26; \ + MOVD R26, 32(R1); \ + CALL runtime·debugCallWrap(SB); \ + BR restore + + // the argument frame size + MOVD 128(R1), R26 + + DEBUG_CALL_DISPATCH(debugCall32<>, 32) + DEBUG_CALL_DISPATCH(debugCall64<>, 64) + DEBUG_CALL_DISPATCH(debugCall128<>, 128) + DEBUG_CALL_DISPATCH(debugCall256<>, 256) + DEBUG_CALL_DISPATCH(debugCall512<>, 512) + DEBUG_CALL_DISPATCH(debugCall1024<>, 1024) + DEBUG_CALL_DISPATCH(debugCall2048<>, 2048) + DEBUG_CALL_DISPATCH(debugCall4096<>, 4096) + DEBUG_CALL_DISPATCH(debugCall8192<>, 8192) + DEBUG_CALL_DISPATCH(debugCall16384<>, 16384) + DEBUG_CALL_DISPATCH(debugCall32768<>, 32768) + DEBUG_CALL_DISPATCH(debugCall65536<>, 65536) + // The frame size is too large. Report the error. + MOVD $debugCallFrameTooLarge<>(SB), R22 + MOVD R22, 32(R1) + MOVD $20, R22 + // length of debugCallFrameTooLarge string + MOVD R22, 40(R1) + MOVD $8, R20 + TW $31, R0, R0 + BR restore +restore: + MOVD $16, R20 + TW $31, R0, R0 + // restore all registers that can contain + // pointers including CR + MOVD 8(R1), R31 + MOVW R31, CR + MOVD 24(R1), R2 + MOVD 56(R1), R3 + MOVD 64(R1), R4 + MOVD 72(R1), R5 + MOVD 80(R1), R6 + MOVD 88(R1), R7 + MOVD 96(R1), R8 + MOVD 104(R1), R9 + MOVD 112(R1), R10 + MOVD 120(R1), R11 + MOVD 144(R1), R12 + MOVD 152(R1), R13 + MOVD 160(R1), R14 + MOVD 168(R1), R15 + MOVD 176(R1), R16 + MOVD 184(R1), R17 + MOVD 192(R1), R18 + MOVD 200(R1), R19 + MOVD 208(R1), R20 + MOVD 216(R1), R21 + MOVD 224(R1), R22 + MOVD 232(R1), R23 + MOVD 240(R1), R24 + MOVD 248(R1), R25 + MOVD 256(R1), R26 + MOVD 264(R1), R27 + MOVD 272(R1), R28 + MOVD 280(R1), R29 + MOVD 288(R1), g + MOVD 16(R1), R31 + // restore old LR + MOVD R31, LR + // restore caller PC + MOVD 0(R1), CTR + MOVD 136(R1), R31 + // Add 32 bytes more to compensate for SP change in saveSigContext + ADD $352, R1 + JMP (CTR) +#endif +#define DEBUG_CALL_FN(NAME,MAXSIZE) \ +TEXT NAME(SB),WRAPPER,$MAXSIZE-0; \ + NO_LOCAL_POINTERS; \ + MOVD $0, R20; \ + TW $31, R0, R0 \ + MOVD $1, R20; \ + TW $31, R0, R0 \ + RET +DEBUG_CALL_FN(debugCall32<>, 32) +DEBUG_CALL_FN(debugCall64<>, 64) +DEBUG_CALL_FN(debugCall128<>, 128) +DEBUG_CALL_FN(debugCall256<>, 256) +DEBUG_CALL_FN(debugCall512<>, 512) +DEBUG_CALL_FN(debugCall1024<>, 1024) +DEBUG_CALL_FN(debugCall2048<>, 2048) +DEBUG_CALL_FN(debugCall4096<>, 4096) +DEBUG_CALL_FN(debugCall8192<>, 8192) +DEBUG_CALL_FN(debugCall16384<>, 16384) +DEBUG_CALL_FN(debugCall32768<>, 32768) +DEBUG_CALL_FN(debugCall65536<>, 65536) + +#ifdef GOARCH_ppc64le +// func debugCallPanicked(val interface{}) +TEXT runtime·debugCallPanicked(SB),NOSPLIT,$32-16 + // Copy the panic value to the top of stack at SP+32. + MOVD val_type+0(FP), R31 + MOVD R31, 32(R1) + MOVD val_data+8(FP), R31 + MOVD R31, 40(R1) + MOVD $2, R20 + TW $31, R0, R0 + RET +#endif +// Note: these functions use a special calling convention to save generated code space. +// Arguments are passed in registers, but the space for those arguments are allocated +// in the caller's stack frame. These stubs write the args into that stack space and +// then tail call to the corresponding runtime handler. +// The tail call makes these stubs disappear in backtraces. +TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 + JMP runtime·goPanicIndex(SB) +TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicIndexU(SB) +TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 + MOVD R4, R3 + MOVD R5, R4 + JMP runtime·goPanicSliceAlen(SB) +TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 + MOVD R4, R3 + MOVD R5, R4 + JMP runtime·goPanicSliceAlenU(SB) +TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 + MOVD R4, R3 + MOVD R5, R4 + JMP runtime·goPanicSliceAcap(SB) +TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 + MOVD R4, R3 + MOVD R5, R4 + JMP runtime·goPanicSliceAcapU(SB) +TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceB(SB) +TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceBU(SB) +TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 + MOVD R5, R3 + MOVD R6, R4 + JMP runtime·goPanicSlice3Alen(SB) +TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 + MOVD R5, R3 + MOVD R6, R4 + JMP runtime·goPanicSlice3AlenU(SB) +TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 + MOVD R5, R3 + MOVD R6, R4 + JMP runtime·goPanicSlice3Acap(SB) +TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 + MOVD R5, R3 + MOVD R6, R4 + JMP runtime·goPanicSlice3AcapU(SB) +TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 + MOVD R4, R3 + MOVD R5, R4 + JMP runtime·goPanicSlice3B(SB) +TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 + MOVD R4, R3 + MOVD R5, R4 + JMP runtime·goPanicSlice3BU(SB) +TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3C(SB) +TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3CU(SB) +TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 + MOVD R5, R3 + MOVD R6, R4 + JMP runtime·goPanicSliceConvert(SB) + +// These functions are used when internal linking cgo with external +// objects compiled with the -Os on gcc. They reduce prologue/epilogue +// size by deferring preservation of callee-save registers to a shared +// function. These are defined in PPC64 ELFv2 2.3.3 (but also present +// in ELFv1) +// +// These appear unused, but the linker will redirect calls to functions +// like _savegpr0_14 or _restgpr1_14 to runtime.elf_savegpr0 or +// runtime.elf_restgpr1 with an appropriate offset based on the number +// register operations required when linking external objects which +// make these calls. For GPR/FPR saves, the minimum register value is +// 14, for VR it is 20. +// +// These are only used when linking such cgo code internally. Note, R12 +// and R0 may be used in different ways than regular ELF compliant +// functions. +TEXT runtime·elf_savegpr0(SB),NOSPLIT|NOFRAME,$0 + // R0 holds the LR of the caller's caller, R1 holds save location + MOVD R14, -144(R1) + MOVD R15, -136(R1) + MOVD R16, -128(R1) + MOVD R17, -120(R1) + MOVD R18, -112(R1) + MOVD R19, -104(R1) + MOVD R20, -96(R1) + MOVD R21, -88(R1) + MOVD R22, -80(R1) + MOVD R23, -72(R1) + MOVD R24, -64(R1) + MOVD R25, -56(R1) + MOVD R26, -48(R1) + MOVD R27, -40(R1) + MOVD R28, -32(R1) + MOVD R29, -24(R1) + MOVD g, -16(R1) + MOVD R31, -8(R1) + MOVD R0, 16(R1) + RET +TEXT runtime·elf_restgpr0(SB),NOSPLIT|NOFRAME,$0 + // R1 holds save location. This returns to the LR saved on stack (bypassing the caller) + MOVD -144(R1), R14 + MOVD -136(R1), R15 + MOVD -128(R1), R16 + MOVD -120(R1), R17 + MOVD -112(R1), R18 + MOVD -104(R1), R19 + MOVD -96(R1), R20 + MOVD -88(R1), R21 + MOVD -80(R1), R22 + MOVD -72(R1), R23 + MOVD -64(R1), R24 + MOVD -56(R1), R25 + MOVD -48(R1), R26 + MOVD -40(R1), R27 + MOVD -32(R1), R28 + MOVD -24(R1), R29 + MOVD -16(R1), g + MOVD -8(R1), R31 + MOVD 16(R1), R0 // Load and return to saved LR + MOVD R0, LR + RET +TEXT runtime·elf_savegpr1(SB),NOSPLIT|NOFRAME,$0 + // R12 holds the save location + MOVD R14, -144(R12) + MOVD R15, -136(R12) + MOVD R16, -128(R12) + MOVD R17, -120(R12) + MOVD R18, -112(R12) + MOVD R19, -104(R12) + MOVD R20, -96(R12) + MOVD R21, -88(R12) + MOVD R22, -80(R12) + MOVD R23, -72(R12) + MOVD R24, -64(R12) + MOVD R25, -56(R12) + MOVD R26, -48(R12) + MOVD R27, -40(R12) + MOVD R28, -32(R12) + MOVD R29, -24(R12) + MOVD g, -16(R12) + MOVD R31, -8(R12) + RET +TEXT runtime·elf_restgpr1(SB),NOSPLIT|NOFRAME,$0 + // R12 holds the save location + MOVD -144(R12), R14 + MOVD -136(R12), R15 + MOVD -128(R12), R16 + MOVD -120(R12), R17 + MOVD -112(R12), R18 + MOVD -104(R12), R19 + MOVD -96(R12), R20 + MOVD -88(R12), R21 + MOVD -80(R12), R22 + MOVD -72(R12), R23 + MOVD -64(R12), R24 + MOVD -56(R12), R25 + MOVD -48(R12), R26 + MOVD -40(R12), R27 + MOVD -32(R12), R28 + MOVD -24(R12), R29 + MOVD -16(R12), g + MOVD -8(R12), R31 + RET +TEXT runtime·elf_savefpr(SB),NOSPLIT|NOFRAME,$0 + // R0 holds the LR of the caller's caller, R1 holds save location + FMOVD F14, -144(R1) + FMOVD F15, -136(R1) + FMOVD F16, -128(R1) + FMOVD F17, -120(R1) + FMOVD F18, -112(R1) + FMOVD F19, -104(R1) + FMOVD F20, -96(R1) + FMOVD F21, -88(R1) + FMOVD F22, -80(R1) + FMOVD F23, -72(R1) + FMOVD F24, -64(R1) + FMOVD F25, -56(R1) + FMOVD F26, -48(R1) + FMOVD F27, -40(R1) + FMOVD F28, -32(R1) + FMOVD F29, -24(R1) + FMOVD F30, -16(R1) + FMOVD F31, -8(R1) + MOVD R0, 16(R1) + RET +TEXT runtime·elf_restfpr(SB),NOSPLIT|NOFRAME,$0 + // R1 holds save location. This returns to the LR saved on stack (bypassing the caller) + FMOVD -144(R1), F14 + FMOVD -136(R1), F15 + FMOVD -128(R1), F16 + FMOVD -120(R1), F17 + FMOVD -112(R1), F18 + FMOVD -104(R1), F19 + FMOVD -96(R1), F20 + FMOVD -88(R1), F21 + FMOVD -80(R1), F22 + FMOVD -72(R1), F23 + FMOVD -64(R1), F24 + FMOVD -56(R1), F25 + FMOVD -48(R1), F26 + FMOVD -40(R1), F27 + FMOVD -32(R1), F28 + FMOVD -24(R1), F29 + FMOVD -16(R1), F30 + FMOVD -8(R1), F31 + MOVD 16(R1), R0 // Load and return to saved LR + MOVD R0, LR + RET +TEXT runtime·elf_savevr(SB),NOSPLIT|NOFRAME,$0 + // R0 holds the save location, R12 is clobbered + MOVD $-192, R12 + STVX V20, (R0+R12) + MOVD $-176, R12 + STVX V21, (R0+R12) + MOVD $-160, R12 + STVX V22, (R0+R12) + MOVD $-144, R12 + STVX V23, (R0+R12) + MOVD $-128, R12 + STVX V24, (R0+R12) + MOVD $-112, R12 + STVX V25, (R0+R12) + MOVD $-96, R12 + STVX V26, (R0+R12) + MOVD $-80, R12 + STVX V27, (R0+R12) + MOVD $-64, R12 + STVX V28, (R0+R12) + MOVD $-48, R12 + STVX V29, (R0+R12) + MOVD $-32, R12 + STVX V30, (R0+R12) + MOVD $-16, R12 + STVX V31, (R0+R12) + RET +TEXT runtime·elf_restvr(SB),NOSPLIT|NOFRAME,$0 + // R0 holds the save location, R12 is clobbered + MOVD $-192, R12 + LVX (R0+R12), V20 + MOVD $-176, R12 + LVX (R0+R12), V21 + MOVD $-160, R12 + LVX (R0+R12), V22 + MOVD $-144, R12 + LVX (R0+R12), V23 + MOVD $-128, R12 + LVX (R0+R12), V24 + MOVD $-112, R12 + LVX (R0+R12), V25 + MOVD $-96, R12 + LVX (R0+R12), V26 + MOVD $-80, R12 + LVX (R0+R12), V27 + MOVD $-64, R12 + LVX (R0+R12), V28 + MOVD $-48, R12 + LVX (R0+R12), V29 + MOVD $-32, R12 + LVX (R0+R12), V30 + MOVD $-16, R12 + LVX (R0+R12), V31 + RET diff --git a/contrib/go/_std_1.22/src/runtime/asm_riscv64.s b/contrib/go/_std_1.23/src/runtime/asm_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_riscv64.s rename to contrib/go/_std_1.23/src/runtime/asm_riscv64.s diff --git a/contrib/go/_std_1.23/src/runtime/asm_s390x.s b/contrib/go/_std_1.23/src/runtime/asm_s390x.s new file mode 100644 index 000000000000..f2354a6d5361 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/asm_s390x.s @@ -0,0 +1,974 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "go_tls.h" +#include "funcdata.h" +#include "textflag.h" + +// _rt0_s390x_lib is common startup code for s390x systems when +// using -buildmode=c-archive or -buildmode=c-shared. The linker will +// arrange to invoke this function as a global constructor (for +// c-archive) or when the shared library is loaded (for c-shared). +// We expect argc and argv to be passed in the usual C ABI registers +// R2 and R3. +TEXT _rt0_s390x_lib(SB), NOSPLIT|NOFRAME, $0 + STMG R6, R15, 48(R15) + MOVD R2, _rt0_s390x_lib_argc<>(SB) + MOVD R3, _rt0_s390x_lib_argv<>(SB) + + // Save R6-R15 in the register save area of the calling function. + STMG R6, R15, 48(R15) + + // Allocate 80 bytes on the stack. + MOVD $-80(R15), R15 + + // Save F8-F15 in our stack frame. + FMOVD F8, 16(R15) + FMOVD F9, 24(R15) + FMOVD F10, 32(R15) + FMOVD F11, 40(R15) + FMOVD F12, 48(R15) + FMOVD F13, 56(R15) + FMOVD F14, 64(R15) + FMOVD F15, 72(R15) + + // Synchronous initialization. + MOVD $runtime·libpreinit(SB), R1 + BL R1 + + // Create a new thread to finish Go runtime initialization. + MOVD _cgo_sys_thread_create(SB), R1 + CMP R1, $0 + BEQ nocgo + MOVD $_rt0_s390x_lib_go(SB), R2 + MOVD $0, R3 + BL R1 + BR restore + +nocgo: + MOVD $0x800000, R1 // stacksize + MOVD R1, 0(R15) + MOVD $_rt0_s390x_lib_go(SB), R1 + MOVD R1, 8(R15) // fn + MOVD $runtime·newosproc(SB), R1 + BL R1 + +restore: + // Restore F8-F15 from our stack frame. + FMOVD 16(R15), F8 + FMOVD 24(R15), F9 + FMOVD 32(R15), F10 + FMOVD 40(R15), F11 + FMOVD 48(R15), F12 + FMOVD 56(R15), F13 + FMOVD 64(R15), F14 + FMOVD 72(R15), F15 + MOVD $80(R15), R15 + + // Restore R6-R15. + LMG 48(R15), R6, R15 + RET + +// _rt0_s390x_lib_go initializes the Go runtime. +// This is started in a separate thread by _rt0_s390x_lib. +TEXT _rt0_s390x_lib_go(SB), NOSPLIT|NOFRAME, $0 + MOVD _rt0_s390x_lib_argc<>(SB), R2 + MOVD _rt0_s390x_lib_argv<>(SB), R3 + MOVD $runtime·rt0_go(SB), R1 + BR R1 + +DATA _rt0_s390x_lib_argc<>(SB)/8, $0 +GLOBL _rt0_s390x_lib_argc<>(SB), NOPTR, $8 +DATA _rt0_s90x_lib_argv<>(SB)/8, $0 +GLOBL _rt0_s390x_lib_argv<>(SB), NOPTR, $8 + +TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 + // R2 = argc; R3 = argv; R11 = temp; R13 = g; R15 = stack pointer + // C TLS base pointer in AR0:AR1 + + // initialize essential registers + XOR R0, R0 + + SUB $24, R15 + MOVW R2, 8(R15) // argc + MOVD R3, 16(R15) // argv + + // create istack out of the given (operating system) stack. + // _cgo_init may update stackguard. + MOVD $runtime·g0(SB), g + MOVD R15, R11 + SUB $(64*1024), R11 + MOVD R11, g_stackguard0(g) + MOVD R11, g_stackguard1(g) + MOVD R11, (g_stack+stack_lo)(g) + MOVD R15, (g_stack+stack_hi)(g) + + // if there is a _cgo_init, call it using the gcc ABI. + MOVD _cgo_init(SB), R11 + CMPBEQ R11, $0, nocgo + MOVW AR0, R4 // (AR0 << 32 | AR1) is the TLS base pointer; MOVD is translated to EAR + SLD $32, R4, R4 + MOVW AR1, R4 // arg 2: TLS base pointer + MOVD $setg_gcc<>(SB), R3 // arg 1: setg + MOVD g, R2 // arg 0: G + // C functions expect 160 bytes of space on caller stack frame + // and an 8-byte aligned stack pointer + MOVD R15, R9 // save current stack (R9 is preserved in the Linux ABI) + SUB $160, R15 // reserve 160 bytes + MOVD $~7, R6 + AND R6, R15 // 8-byte align + BL R11 // this call clobbers volatile registers according to Linux ABI (R0-R5, R14) + MOVD R9, R15 // restore stack + XOR R0, R0 // zero R0 + +nocgo: + // update stackguard after _cgo_init + MOVD (g_stack+stack_lo)(g), R2 + ADD $const_stackGuard, R2 + MOVD R2, g_stackguard0(g) + MOVD R2, g_stackguard1(g) + + // set the per-goroutine and per-mach "registers" + MOVD $runtime·m0(SB), R2 + + // save m->g0 = g0 + MOVD g, m_g0(R2) + // save m0 to g0->m + MOVD R2, g_m(g) + + BL runtime·check(SB) + + // argc/argv are already prepared on stack + BL runtime·args(SB) + BL runtime·checkS390xCPU(SB) + BL runtime·osinit(SB) + BL runtime·schedinit(SB) + + // create a new goroutine to start program + MOVD $runtime·mainPC(SB), R2 // entry + SUB $16, R15 + MOVD R2, 8(R15) + MOVD $0, 0(R15) + BL runtime·newproc(SB) + ADD $16, R15 + + // start this M + BL runtime·mstart(SB) + + MOVD $0, 1(R0) + RET + +DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) +GLOBL runtime·mainPC(SB),RODATA,$8 + +TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0 + BRRK + RET + +TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0 + RET + +TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 + CALL runtime·mstart0(SB) + RET // not reached + +/* + * go-routine + */ + +// void gogo(Gobuf*) +// restore state from Gobuf; longjmp +TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8 + MOVD buf+0(FP), R5 + MOVD gobuf_g(R5), R6 + MOVD 0(R6), R7 // make sure g != nil + BR gogo<>(SB) + +TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 + MOVD R6, g + BL runtime·save_g(SB) + + MOVD 0(g), R4 + MOVD gobuf_sp(R5), R15 + MOVD gobuf_lr(R5), LR + MOVD gobuf_ret(R5), R3 + MOVD gobuf_ctxt(R5), R12 + MOVD $0, gobuf_sp(R5) + MOVD $0, gobuf_ret(R5) + MOVD $0, gobuf_lr(R5) + MOVD $0, gobuf_ctxt(R5) + CMP R0, R0 // set condition codes for == test, needed by stack split + MOVD gobuf_pc(R5), R6 + BR (R6) + +// void mcall(fn func(*g)) +// Switch to m->g0's stack, call fn(g). +// Fn must never return. It should gogo(&g->sched) +// to keep running g. +TEXT runtime·mcall(SB), NOSPLIT, $-8-8 + // Save caller state in g->sched + MOVD R15, (g_sched+gobuf_sp)(g) + MOVD LR, (g_sched+gobuf_pc)(g) + MOVD $0, (g_sched+gobuf_lr)(g) + + // Switch to m->g0 & its stack, call fn. + MOVD g, R3 + MOVD g_m(g), R8 + MOVD m_g0(R8), g + BL runtime·save_g(SB) + CMP g, R3 + BNE 2(PC) + BR runtime·badmcall(SB) + MOVD fn+0(FP), R12 // context + MOVD 0(R12), R4 // code pointer + MOVD (g_sched+gobuf_sp)(g), R15 // sp = m->g0->sched.sp + SUB $16, R15 + MOVD R3, 8(R15) + MOVD $0, 0(R15) + BL (R4) + BR runtime·badmcall2(SB) + +// systemstack_switch is a dummy routine that systemstack leaves at the bottom +// of the G stack. We need to distinguish the routine that +// lives at the bottom of the G stack from the one that lives +// at the top of the system stack because the one at the top of +// the system stack terminates the stack walk (see topofstack()). +TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 + UNDEF + BL (LR) // make sure this function is not leaf + RET + +// func systemstack(fn func()) +TEXT runtime·systemstack(SB), NOSPLIT, $0-8 + MOVD fn+0(FP), R3 // R3 = fn + MOVD R3, R12 // context + MOVD g_m(g), R4 // R4 = m + + MOVD m_gsignal(R4), R5 // R5 = gsignal + CMPBEQ g, R5, noswitch + + MOVD m_g0(R4), R5 // R5 = g0 + CMPBEQ g, R5, noswitch + + MOVD m_curg(R4), R6 + CMPBEQ g, R6, switch + + // Bad: g is not gsignal, not g0, not curg. What is it? + // Hide call from linker nosplit analysis. + MOVD $runtime·badsystemstack(SB), R3 + BL (R3) + BL runtime·abort(SB) + +switch: + // save our state in g->sched. Pretend to + // be systemstack_switch if the G stack is scanned. + BL gosave_systemstack_switch<>(SB) + + // switch to g0 + MOVD R5, g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R15 + + // call target function + MOVD 0(R12), R3 // code pointer + BL (R3) + + // switch back to g + MOVD g_m(g), R3 + MOVD m_curg(R3), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R15 + MOVD $0, (g_sched+gobuf_sp)(g) + RET + +noswitch: + // already on m stack, just call directly + // Using a tail call here cleans up tracebacks since we won't stop + // at an intermediate systemstack. + MOVD 0(R12), R3 // code pointer + MOVD 0(R15), LR // restore LR + ADD $8, R15 + BR (R3) + +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 + MOVD fn+0(FP), R12 // context + MOVD g_m(g), R4 // curm + + // set g to gcrash + MOVD $runtime·gcrash(SB), g // g = &gcrash + BL runtime·save_g(SB) + MOVD R4, g_m(g) // g.m = curm + MOVD g, m_g0(R4) // curm.g0 = g + + // switch to crashstack + MOVD (g_stack+stack_hi)(g), R4 + ADD $(-4*8), R4, R15 + + // call target function + MOVD 0(R12), R3 // code pointer + BL (R3) + + // should never return + BL runtime·abort(SB) + UNDEF + +/* + * support for morestack + */ + +// Called during function prolog when more stack is needed. +// Caller has already loaded: +// R3: framesize, R4: argsize, R5: LR +// +// The traceback routines see morestack on a g0 as being +// the top of a stack (for example, morestack calling newstack +// calling the scheduler calling newm calling gc), so we must +// record an argument size. For that purpose, it has no arguments. +TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 + // Called from f. + // Set g->sched to context in f. + MOVD R15, (g_sched+gobuf_sp)(g) + MOVD LR, R8 + MOVD R8, (g_sched+gobuf_pc)(g) + MOVD R5, (g_sched+gobuf_lr)(g) + MOVD R12, (g_sched+gobuf_ctxt)(g) + + // Cannot grow scheduler stack (m->g0). + MOVD g_m(g), R7 + MOVD m_g0(R7), R8 + CMPBNE g, R8, 3(PC) + BL runtime·badmorestackg0(SB) + BL runtime·abort(SB) + + // Cannot grow signal stack (m->gsignal). + MOVD m_gsignal(R7), R8 + CMP g, R8 + BNE 3(PC) + BL runtime·badmorestackgsignal(SB) + BL runtime·abort(SB) + + // Called from f. + // Set m->morebuf to f's caller. + MOVD R5, (m_morebuf+gobuf_pc)(R7) // f's caller's PC + MOVD R15, (m_morebuf+gobuf_sp)(R7) // f's caller's SP + MOVD g, (m_morebuf+gobuf_g)(R7) + + // Call newstack on m->g0's stack. + MOVD m_g0(R7), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R15 + // Create a stack frame on g0 to call newstack. + MOVD $0, -8(R15) // Zero saved LR in frame + SUB $8, R15 + BL runtime·newstack(SB) + + // Not reached, but make sure the return PC from the call to newstack + // is still in this function, and not the beginning of the next. + UNDEF + +TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 + // Force SPWRITE. This function doesn't actually write SP, + // but it is called with a special calling convention where + // the caller doesn't save LR on stack but passes it as a + // register (R5), and the unwinder currently doesn't understand. + // Make it SPWRITE to stop unwinding. (See issue 54332) + MOVD R15, R15 + + MOVD $0, R12 + BR runtime·morestack(SB) + +// reflectcall: call a function with the given argument list +// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). +// we don't have variable-sized frames, so we use a small number +// of constant-sized-frame functions to encode a few bits of size in the pc. +// Caution: ugly multiline assembly macros in your future! + +#define DISPATCH(NAME,MAXSIZE) \ + MOVD $MAXSIZE, R4; \ + CMP R3, R4; \ + BGT 3(PC); \ + MOVD $NAME(SB), R5; \ + BR (R5) +// Note: can't just "BR NAME(SB)" - bad inlining results. + +TEXT ·reflectcall(SB), NOSPLIT, $-8-48 + MOVWZ frameSize+32(FP), R3 + DISPATCH(runtime·call16, 16) + DISPATCH(runtime·call32, 32) + DISPATCH(runtime·call64, 64) + DISPATCH(runtime·call128, 128) + DISPATCH(runtime·call256, 256) + DISPATCH(runtime·call512, 512) + DISPATCH(runtime·call1024, 1024) + DISPATCH(runtime·call2048, 2048) + DISPATCH(runtime·call4096, 4096) + DISPATCH(runtime·call8192, 8192) + DISPATCH(runtime·call16384, 16384) + DISPATCH(runtime·call32768, 32768) + DISPATCH(runtime·call65536, 65536) + DISPATCH(runtime·call131072, 131072) + DISPATCH(runtime·call262144, 262144) + DISPATCH(runtime·call524288, 524288) + DISPATCH(runtime·call1048576, 1048576) + DISPATCH(runtime·call2097152, 2097152) + DISPATCH(runtime·call4194304, 4194304) + DISPATCH(runtime·call8388608, 8388608) + DISPATCH(runtime·call16777216, 16777216) + DISPATCH(runtime·call33554432, 33554432) + DISPATCH(runtime·call67108864, 67108864) + DISPATCH(runtime·call134217728, 134217728) + DISPATCH(runtime·call268435456, 268435456) + DISPATCH(runtime·call536870912, 536870912) + DISPATCH(runtime·call1073741824, 1073741824) + MOVD $runtime·badreflectcall(SB), R5 + BR (R5) + +#define CALLFN(NAME,MAXSIZE) \ +TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ + NO_LOCAL_POINTERS; \ + /* copy arguments to stack */ \ + MOVD stackArgs+16(FP), R4; \ + MOVWZ stackArgsSize+24(FP), R5; \ + MOVD $stack-MAXSIZE(SP), R6; \ +loopArgs: /* copy 256 bytes at a time */ \ + CMP R5, $256; \ + BLT tailArgs; \ + SUB $256, R5; \ + MVC $256, 0(R4), 0(R6); \ + MOVD $256(R4), R4; \ + MOVD $256(R6), R6; \ + BR loopArgs; \ +tailArgs: /* copy remaining bytes */ \ + CMP R5, $0; \ + BEQ callFunction; \ + SUB $1, R5; \ + EXRL $callfnMVC<>(SB), R5; \ +callFunction: \ + MOVD f+8(FP), R12; \ + MOVD (R12), R8; \ + PCDATA $PCDATA_StackMapIndex, $0; \ + BL (R8); \ + /* copy return values back */ \ + MOVD stackArgsType+0(FP), R7; \ + MOVD stackArgs+16(FP), R6; \ + MOVWZ stackArgsSize+24(FP), R5; \ + MOVD $stack-MAXSIZE(SP), R4; \ + MOVWZ stackRetOffset+28(FP), R1; \ + ADD R1, R4; \ + ADD R1, R6; \ + SUB R1, R5; \ + BL callRet<>(SB); \ + RET + +// callRet copies return values back at the end of call*. This is a +// separate function so it can allocate stack space for the arguments +// to reflectcallmove. It does not follow the Go ABI; it expects its +// arguments in registers. +TEXT callRet<>(SB), NOSPLIT, $40-0 + MOVD R7, 8(R15) + MOVD R6, 16(R15) + MOVD R4, 24(R15) + MOVD R5, 32(R15) + MOVD $0, 40(R15) + BL runtime·reflectcallmove(SB) + RET + +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) + +// Not a function: target for EXRL (execute relative long) instruction. +TEXT callfnMVC<>(SB),NOSPLIT|NOFRAME,$0-0 + MVC $1, 0(R4), 0(R6) + +TEXT runtime·procyield(SB),NOSPLIT,$0-0 + RET + +// Save state of caller into g->sched, +// but using fake PC from systemstack_switch. +// Must only be called from functions with no locals ($0) +// or else unwinding from systemstack_switch is incorrect. +// Smashes R1. +TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 + MOVD $runtime·systemstack_switch(SB), R1 + ADD $16, R1 // get past prologue + MOVD R1, (g_sched+gobuf_pc)(g) + MOVD R15, (g_sched+gobuf_sp)(g) + MOVD $0, (g_sched+gobuf_lr)(g) + MOVD $0, (g_sched+gobuf_ret)(g) + // Assert ctxt is zero. See func save. + MOVD (g_sched+gobuf_ctxt)(g), R1 + CMPBEQ R1, $0, 2(PC) + BL runtime·abort(SB) + RET + +// func asmcgocall(fn, arg unsafe.Pointer) int32 +// Call fn(arg) on the scheduler stack, +// aligned appropriately for the gcc ABI. +// See cgocall.go for more details. +TEXT ·asmcgocall(SB),NOSPLIT,$0-20 + // R2 = argc; R3 = argv; R11 = temp; R13 = g; R15 = stack pointer + // C TLS base pointer in AR0:AR1 + MOVD fn+0(FP), R3 + MOVD arg+8(FP), R4 + + MOVD R15, R2 // save original stack pointer + MOVD g, R5 + + // Figure out if we need to switch to m->g0 stack. + // We get called to create new OS threads too, and those + // come in on the m->g0 stack already. Or we might already + // be on the m->gsignal stack. + MOVD g_m(g), R6 + MOVD m_gsignal(R6), R7 + CMPBEQ R7, g, g0 + MOVD m_g0(R6), R7 + CMPBEQ R7, g, g0 + BL gosave_systemstack_switch<>(SB) + MOVD R7, g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R15 + + // Now on a scheduling stack (a pthread-created stack). +g0: + // Save room for two of our pointers, plus 160 bytes of callee + // save area that lives on the caller stack. + SUB $176, R15 + MOVD $~7, R6 + AND R6, R15 // 8-byte alignment for gcc ABI + MOVD R5, 168(R15) // save old g on stack + MOVD (g_stack+stack_hi)(R5), R5 + SUB R2, R5 + MOVD R5, 160(R15) // save depth in old g stack (can't just save SP, as stack might be copied during a callback) + MOVD $0, 0(R15) // clear back chain pointer (TODO can we give it real back trace information?) + MOVD R4, R2 // arg in R2 + BL R3 // can clobber: R0-R5, R14, F0-F3, F5, F7-F15 + + XOR R0, R0 // set R0 back to 0. + // Restore g, stack pointer. + MOVD 168(R15), g + BL runtime·save_g(SB) + MOVD (g_stack+stack_hi)(g), R5 + MOVD 160(R15), R6 + SUB R6, R5 + MOVD R5, R15 + + MOVW R2, ret+16(FP) + RET + +// cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) +// See cgocall.go for more details. +TEXT ·cgocallback(SB),NOSPLIT,$24-24 + NO_LOCAL_POINTERS + + // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g. + // It is used to dropm while thread is exiting. + MOVD fn+0(FP), R1 + CMPBNE R1, $0, loadg + // Restore the g from frame. + MOVD frame+8(FP), g + BR dropm + +loadg: + // Load m and g from thread-local storage. + MOVB runtime·iscgo(SB), R3 + CMPBEQ R3, $0, nocgo + BL runtime·load_g(SB) + +nocgo: + // If g is nil, Go did not create the current thread, + // or if this thread never called into Go on pthread platforms. + // Call needm to obtain one for temporary use. + // In this case, we're running on the thread stack, so there's + // lots of space, but the linker doesn't know. Hide the call from + // the linker analysis by using an indirect call. + CMPBEQ g, $0, needm + + MOVD g_m(g), R8 + MOVD R8, savedm-8(SP) + BR havem + +needm: + MOVD g, savedm-8(SP) // g is zero, so is m. + MOVD $runtime·needAndBindM(SB), R3 + BL (R3) + + // Set m->sched.sp = SP, so that if a panic happens + // during the function we are about to execute, it will + // have a valid SP to run on the g0 stack. + // The next few lines (after the havem label) + // will save this SP onto the stack and then write + // the same SP back to m->sched.sp. That seems redundant, + // but if an unrecovered panic happens, unwindm will + // restore the g->sched.sp from the stack location + // and then systemstack will try to use it. If we don't set it here, + // that restored SP will be uninitialized (typically 0) and + // will not be usable. + MOVD g_m(g), R8 + MOVD m_g0(R8), R3 + MOVD R15, (g_sched+gobuf_sp)(R3) + +havem: + // Now there's a valid m, and we're running on its m->g0. + // Save current m->g0->sched.sp on stack and then set it to SP. + // Save current sp in m->g0->sched.sp in preparation for + // switch back to m->curg stack. + // NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP). + MOVD m_g0(R8), R3 + MOVD (g_sched+gobuf_sp)(R3), R4 + MOVD R4, savedsp-24(SP) // must match frame size + MOVD R15, (g_sched+gobuf_sp)(R3) + + // Switch to m->curg stack and call runtime.cgocallbackg. + // Because we are taking over the execution of m->curg + // but *not* resuming what had been running, we need to + // save that information (m->curg->sched) so we can restore it. + // We can restore m->curg->sched.sp easily, because calling + // runtime.cgocallbackg leaves SP unchanged upon return. + // To save m->curg->sched.pc, we push it onto the curg stack and + // open a frame the same size as cgocallback's g0 frame. + // Once we switch to the curg stack, the pushed PC will appear + // to be the return PC of cgocallback, so that the traceback + // will seamlessly trace back into the earlier calls. + MOVD m_curg(R8), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 + MOVD (g_sched+gobuf_pc)(g), R5 + MOVD R5, -(24+8)(R4) // "saved LR"; must match frame size + // Gather our arguments into registers. + MOVD fn+0(FP), R1 + MOVD frame+8(FP), R2 + MOVD ctxt+16(FP), R3 + MOVD $-(24+8)(R4), R15 // switch stack; must match frame size + MOVD R1, 8(R15) + MOVD R2, 16(R15) + MOVD R3, 24(R15) + BL runtime·cgocallbackg(SB) + + // Restore g->sched (== m->curg->sched) from saved values. + MOVD 0(R15), R5 + MOVD R5, (g_sched+gobuf_pc)(g) + MOVD $(24+8)(R15), R4 // must match frame size + MOVD R4, (g_sched+gobuf_sp)(g) + + // Switch back to m->g0's stack and restore m->g0->sched.sp. + // (Unlike m->curg, the g0 goroutine never uses sched.pc, + // so we do not have to restore it.) + MOVD g_m(g), R8 + MOVD m_g0(R8), g + BL runtime·save_g(SB) + MOVD (g_sched+gobuf_sp)(g), R15 + MOVD savedsp-24(SP), R4 // must match frame size + MOVD R4, (g_sched+gobuf_sp)(g) + + // If the m on entry was nil, we called needm above to borrow an m, + // 1. for the duration of the call on non-pthread platforms, + // 2. or the duration of the C thread alive on pthread platforms. + // If the m on entry wasn't nil, + // 1. the thread might be a Go thread, + // 2. or it wasn't the first call from a C thread on pthread platforms, + // since then we skip dropm to reuse the m in the first call. + MOVD savedm-8(SP), R6 + CMPBNE R6, $0, droppedm + + // Skip dropm to reuse it in the next call, when a pthread key has been created. + MOVD _cgo_pthread_key_created(SB), R6 + // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm. + CMPBEQ R6, $0, dropm + MOVD (R6), R6 + CMPBNE R6, $0, droppedm + +dropm: + MOVD $runtime·dropm(SB), R3 + BL (R3) +droppedm: + + // Done! + RET + +// void setg(G*); set g. for use by needm. +TEXT runtime·setg(SB), NOSPLIT, $0-8 + MOVD gg+0(FP), g + // This only happens if iscgo, so jump straight to save_g + BL runtime·save_g(SB) + RET + +// void setg_gcc(G*); set g in C TLS. +// Must obey the gcc calling convention. +TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 + // The standard prologue clobbers LR (R14), which is callee-save in + // the C ABI, so we have to use NOFRAME and save LR ourselves. + MOVD LR, R1 + // Also save g, R10, and R11 since they're callee-save in C ABI + MOVD R10, R3 + MOVD g, R4 + MOVD R11, R5 + + MOVD R2, g + BL runtime·save_g(SB) + + MOVD R5, R11 + MOVD R4, g + MOVD R3, R10 + MOVD R1, LR + RET + +TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 + MOVW (R0), R0 + UNDEF + +// int64 runtime·cputicks(void) +TEXT runtime·cputicks(SB),NOSPLIT,$0-8 + // The TOD clock on s390 counts from the year 1900 in ~250ps intervals. + // This means that since about 1972 the msb has been set, making the + // result of a call to STORE CLOCK (stck) a negative number. + // We clear the msb to make it positive. + STCK ret+0(FP) // serialises before and after call + MOVD ret+0(FP), R3 // R3 will wrap to 0 in the year 2043 + SLD $1, R3 + SRD $1, R3 + MOVD R3, ret+0(FP) + RET + +// AES hashing not implemented for s390x +TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 + JMP runtime·memhashFallback(SB) +TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 + JMP runtime·strhashFallback(SB) +TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 + JMP runtime·memhash32Fallback(SB) +TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 + JMP runtime·memhash64Fallback(SB) + +TEXT runtime·return0(SB), NOSPLIT, $0 + MOVW $0, R3 + RET + +// Called from cgo wrappers, this function returns g->m->curg.stack.hi. +// Must obey the gcc calling convention. +TEXT _cgo_topofstack(SB),NOSPLIT|NOFRAME,$0 + // g (R13), R10, R11 and LR (R14) are callee-save in the C ABI, so save them + MOVD g, R1 + MOVD R10, R3 + MOVD LR, R4 + MOVD R11, R5 + + BL runtime·load_g(SB) // clobbers g (R13), R10, R11 + MOVD g_m(g), R2 + MOVD m_curg(R2), R2 + MOVD (g_stack+stack_hi)(R2), R2 + + MOVD R1, g + MOVD R3, R10 + MOVD R4, LR + MOVD R5, R11 + RET + +// The top-most function running on a goroutine +// returns to goexit+PCQuantum. +TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 + BYTE $0x07; BYTE $0x00; // 2-byte nop + BL runtime·goexit1(SB) // does not return + // traceback from goexit1 must hit code range of goexit + BYTE $0x07; BYTE $0x00; // 2-byte nop + +TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 + // Stores are already ordered on s390x, so this is just a + // compile barrier. + RET + +// This is called from .init_array and follows the platform, not Go, ABI. +// We are overly conservative. We could only save the registers we use. +// However, since this function is only called once per loaded module +// performance is unimportant. +TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0 + // Save R6-R15 in the register save area of the calling function. + // Don't bother saving F8-F15 as we aren't doing any calls. + STMG R6, R15, 48(R15) + + // append the argument (passed in R2, as per the ELF ABI) to the + // moduledata linked list. + MOVD runtime·lastmoduledatap(SB), R1 + MOVD R2, moduledata_next(R1) + MOVD R2, runtime·lastmoduledatap(SB) + + // Restore R6-R15. + LMG 48(R15), R6, R15 + RET + +TEXT ·checkASM(SB),NOSPLIT,$0-1 + MOVB $1, ret+0(FP) + RET + +// gcWriteBarrier informs the GC about heap pointer writes. +// +// gcWriteBarrier does NOT follow the Go ABI. It accepts the +// number of bytes of buffer needed in R9, and returns a pointer +// to the buffer space in R9. +// It clobbers R10 (the temp register) and R1 (used by PLT stub). +// It does not clobber any other general-purpose registers, +// but may clobber others (e.g., floating point registers). +TEXT gcWriteBarrier<>(SB),NOSPLIT,$96 + // Save the registers clobbered by the fast path. + MOVD R4, 96(R15) +retry: + MOVD g_m(g), R1 + MOVD m_p(R1), R1 + // Increment wbBuf.next position. + MOVD R9, R4 + ADD (p_wbBuf+wbBuf_next)(R1), R4 + // Is the buffer full? + MOVD (p_wbBuf+wbBuf_end)(R1), R10 + CMPUBGT R4, R10, flush + // Commit to the larger buffer. + MOVD R4, (p_wbBuf+wbBuf_next)(R1) + // Make return value (the original next position) + SUB R9, R4, R9 + // Restore registers. + MOVD 96(R15), R4 + RET + +flush: + // Save all general purpose registers since these could be + // clobbered by wbBufFlush and were not saved by the caller. + STMG R2, R3, 8(R15) + MOVD R0, 24(R15) + // R1 already saved. + // R4 already saved. + STMG R5, R12, 32(R15) // save R5 - R12 + // R13 is g. + // R14 is LR. + // R15 is SP. + + CALL runtime·wbBufFlush(SB) + + LMG 8(R15), R2, R3 // restore R2 - R3 + MOVD 24(R15), R0 // restore R0 + LMG 32(R15), R5, R12 // restore R5 - R12 + JMP retry + +TEXT runtime·gcWriteBarrier1(SB),NOSPLIT,$0 + MOVD $8, R9 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier2(SB),NOSPLIT,$0 + MOVD $16, R9 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier3(SB),NOSPLIT,$0 + MOVD $24, R9 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier4(SB),NOSPLIT,$0 + MOVD $32, R9 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier5(SB),NOSPLIT,$0 + MOVD $40, R9 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier6(SB),NOSPLIT,$0 + MOVD $48, R9 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier7(SB),NOSPLIT,$0 + MOVD $56, R9 + JMP gcWriteBarrier<>(SB) +TEXT runtime·gcWriteBarrier8(SB),NOSPLIT,$0 + MOVD $64, R9 + JMP gcWriteBarrier<>(SB) + +// Note: these functions use a special calling convention to save generated code space. +// Arguments are passed in registers, but the space for those arguments are allocated +// in the caller's stack frame. These stubs write the args into that stack space and +// then tail call to the corresponding runtime handler. +// The tail call makes these stubs disappear in backtraces. +TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 + MOVD R0, x+0(FP) + MOVD R1, y+8(FP) + JMP runtime·goPanicIndex(SB) +TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 + MOVD R0, x+0(FP) + MOVD R1, y+8(FP) + JMP runtime·goPanicIndexU(SB) +TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 + MOVD R1, x+0(FP) + MOVD R2, y+8(FP) + JMP runtime·goPanicSliceAlen(SB) +TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 + MOVD R1, x+0(FP) + MOVD R2, y+8(FP) + JMP runtime·goPanicSliceAlenU(SB) +TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 + MOVD R1, x+0(FP) + MOVD R2, y+8(FP) + JMP runtime·goPanicSliceAcap(SB) +TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 + MOVD R1, x+0(FP) + MOVD R2, y+8(FP) + JMP runtime·goPanicSliceAcapU(SB) +TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 + MOVD R0, x+0(FP) + MOVD R1, y+8(FP) + JMP runtime·goPanicSliceB(SB) +TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 + MOVD R0, x+0(FP) + MOVD R1, y+8(FP) + JMP runtime·goPanicSliceBU(SB) +TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 + MOVD R2, x+0(FP) + MOVD R3, y+8(FP) + JMP runtime·goPanicSlice3Alen(SB) +TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 + MOVD R2, x+0(FP) + MOVD R3, y+8(FP) + JMP runtime·goPanicSlice3AlenU(SB) +TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 + MOVD R2, x+0(FP) + MOVD R3, y+8(FP) + JMP runtime·goPanicSlice3Acap(SB) +TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 + MOVD R2, x+0(FP) + MOVD R3, y+8(FP) + JMP runtime·goPanicSlice3AcapU(SB) +TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 + MOVD R1, x+0(FP) + MOVD R2, y+8(FP) + JMP runtime·goPanicSlice3B(SB) +TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 + MOVD R1, x+0(FP) + MOVD R2, y+8(FP) + JMP runtime·goPanicSlice3BU(SB) +TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 + MOVD R0, x+0(FP) + MOVD R1, y+8(FP) + JMP runtime·goPanicSlice3C(SB) +TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 + MOVD R0, x+0(FP) + MOVD R1, y+8(FP) + JMP runtime·goPanicSlice3CU(SB) +TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 + MOVD R2, x+0(FP) + MOVD R3, y+8(FP) + JMP runtime·goPanicSliceConvert(SB) diff --git a/contrib/go/_std_1.22/src/runtime/asm_wasm.s b/contrib/go/_std_1.23/src/runtime/asm_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_wasm.s rename to contrib/go/_std_1.23/src/runtime/asm_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_arm64.s b/contrib/go/_std_1.23/src/runtime/atomic_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_arm64.s rename to contrib/go/_std_1.23/src/runtime/atomic_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_loong64.s b/contrib/go/_std_1.23/src/runtime/atomic_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_loong64.s rename to contrib/go/_std_1.23/src/runtime/atomic_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_mips64x.s b/contrib/go/_std_1.23/src/runtime/atomic_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_mips64x.s rename to contrib/go/_std_1.23/src/runtime/atomic_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_mipsx.s b/contrib/go/_std_1.23/src/runtime/atomic_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_mipsx.s rename to contrib/go/_std_1.23/src/runtime/atomic_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_pointer.go b/contrib/go/_std_1.23/src/runtime/atomic_pointer.go similarity index 88% rename from contrib/go/_std_1.22/src/runtime/atomic_pointer.go rename to contrib/go/_std_1.23/src/runtime/atomic_pointer.go index b61bf0b8b2a1..df067ede77f8 100644 --- a/contrib/go/_std_1.22/src/runtime/atomic_pointer.go +++ b/contrib/go/_std_1.23/src/runtime/atomic_pointer.go @@ -6,7 +6,7 @@ package runtime import ( "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -18,6 +18,16 @@ import ( // atomicwb performs a write barrier before an atomic pointer write. // The caller should guard the call with "if writeBarrier.enabled". // +// atomicwb should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname atomicwb //go:nosplit func atomicwb(ptr *unsafe.Pointer, new unsafe.Pointer) { slot := (*uintptr)(unsafe.Pointer(ptr)) @@ -43,7 +53,7 @@ func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) { // (like StoreNoWB but with the write barrier). // //go:nosplit -//go:linkname atomic_storePointer runtime/internal/atomic.storePointer +//go:linkname atomic_storePointer internal/runtime/atomic.storePointer func atomic_storePointer(ptr *unsafe.Pointer, new unsafe.Pointer) { atomicstorep(unsafe.Pointer(ptr), new) } @@ -52,7 +62,7 @@ func atomic_storePointer(ptr *unsafe.Pointer, new unsafe.Pointer) { // (like CompareAndSwapNoWB but with the write barrier). // //go:nosplit -//go:linkname atomic_casPointer runtime/internal/atomic.casPointer +//go:linkname atomic_casPointer internal/runtime/atomic.casPointer func atomic_casPointer(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool { if writeBarrier.enabled { atomicwb(ptr, new) diff --git a/contrib/go/_std_1.22/src/runtime/atomic_ppc64x.s b/contrib/go/_std_1.23/src/runtime/atomic_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/atomic_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_riscv64.s b/contrib/go/_std_1.23/src/runtime/atomic_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_riscv64.s rename to contrib/go/_std_1.23/src/runtime/atomic_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/auxv_none.go b/contrib/go/_std_1.23/src/runtime/auxv_none.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/auxv_none.go rename to contrib/go/_std_1.23/src/runtime/auxv_none.go diff --git a/contrib/go/_std_1.23/src/runtime/badlinkname.go b/contrib/go/_std_1.23/src/runtime/badlinkname.go new file mode 100644 index 000000000000..b195bebbda69 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/badlinkname.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import _ "unsafe" + +// These should be an internal details +// but widely used packages access them using linkname. +// Do not remove or change the type signature. +// See go.dev/issue/67401. + +// Notable members of the hall of shame include: +// - github.com/dgraph-io/ristretto +// - github.com/outcaste-io/ristretto +// - github.com/clubpay/ronykit +//go:linkname cputicks + +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor (from assembly) +//go:linkname sched diff --git a/contrib/go/_std_1.23/src/runtime/badlinkname_linux.go b/contrib/go/_std_1.23/src/runtime/badlinkname_linux.go new file mode 100644 index 000000000000..ad74528da28c --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/badlinkname_linux.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 || arm64 + +package runtime + +import _ "unsafe" + +// As of Go 1.22, the symbols below are found to be pulled via +// linkname in the wild. We provide a push linkname here, to +// keep them accessible with pull linknames. +// This may change in the future. Please do not depend on them +// in new code. + +//go:linkname vdsoClockgettimeSym diff --git a/contrib/go/_std_1.23/src/runtime/cgo.go b/contrib/go/_std_1.23/src/runtime/cgo.go new file mode 100644 index 000000000000..8285d87fcf67 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/cgo.go @@ -0,0 +1,90 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +//go:cgo_export_static main + +// Filled in by runtime/cgo when linked into binary. + +//go:linkname _cgo_init _cgo_init +//go:linkname _cgo_thread_start _cgo_thread_start +//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create +//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done +//go:linkname _cgo_callers _cgo_callers +//go:linkname _cgo_set_context_function _cgo_set_context_function +//go:linkname _cgo_yield _cgo_yield +//go:linkname _cgo_pthread_key_created _cgo_pthread_key_created +//go:linkname _cgo_bindm _cgo_bindm +//go:linkname _cgo_getstackbound _cgo_getstackbound + +var ( + _cgo_init unsafe.Pointer + _cgo_thread_start unsafe.Pointer + _cgo_sys_thread_create unsafe.Pointer + _cgo_notify_runtime_init_done unsafe.Pointer + _cgo_callers unsafe.Pointer + _cgo_set_context_function unsafe.Pointer + _cgo_yield unsafe.Pointer + _cgo_pthread_key_created unsafe.Pointer + _cgo_bindm unsafe.Pointer + _cgo_getstackbound unsafe.Pointer +) + +// iscgo is set to true by the runtime/cgo package +// +// iscgo should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname iscgo +var iscgo bool + +// set_crosscall2 is set by the runtime/cgo package +// set_crosscall2 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname set_crosscall2 +var set_crosscall2 func() + +// cgoHasExtraM is set on startup when an extra M is created for cgo. +// The extra M must be created before any C/C++ code calls cgocallback. +var cgoHasExtraM bool + +// cgoUse is called by cgo-generated code (using go:linkname to get at +// an unexported name). The calls serve two purposes: +// 1) they are opaque to escape analysis, so the argument is considered to +// escape to the heap. +// 2) they keep the argument alive until the call site; the call is emitted after +// the end of the (presumed) use of the argument by C. +// cgoUse should not actually be called (see cgoAlwaysFalse). +func cgoUse(any) { throw("cgoUse should not be called") } + +// cgoAlwaysFalse is a boolean value that is always false. +// The cgo-generated code says if cgoAlwaysFalse { cgoUse(p) }. +// The compiler cannot see that cgoAlwaysFalse is always false, +// so it emits the test and keeps the call, giving the desired +// escape analysis result. The test is cheaper than the call. +var cgoAlwaysFalse bool + +var cgo_yield = &_cgo_yield + +func cgoNoCallback(v bool) { + g := getg() + if g.nocgocallback && v { + panic("runtime: unexpected setting cgoNoCallback") + } + g.nocgocallback = v +} diff --git a/contrib/go/_std_1.22/src/runtime/cgo/abi_amd64.h b/contrib/go/_std_1.23/src/runtime/cgo/abi_amd64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/abi_amd64.h rename to contrib/go/_std_1.23/src/runtime/cgo/abi_amd64.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/abi_arm64.h b/contrib/go/_std_1.23/src/runtime/cgo/abi_arm64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/abi_arm64.h rename to contrib/go/_std_1.23/src/runtime/cgo/abi_arm64.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/abi_loong64.h b/contrib/go/_std_1.23/src/runtime/cgo/abi_loong64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/abi_loong64.h rename to contrib/go/_std_1.23/src/runtime/cgo/abi_loong64.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/abi_ppc64x.h b/contrib/go/_std_1.23/src/runtime/cgo/abi_ppc64x.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/abi_ppc64x.h rename to contrib/go/_std_1.23/src/runtime/cgo/abi_ppc64x.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_386.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_386.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_386.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_amd64.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_amd64.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_arm.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_arm.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_arm64.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_arm64.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_loong64.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_loong64.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_mips64x.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_mips64x.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_mipsx.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_mipsx.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_ppc64x.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_riscv64.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_riscv64.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_s390x.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_s390x.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_wasm.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_wasm.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/callbacks.go b/contrib/go/_std_1.23/src/runtime/cgo/callbacks.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/callbacks.go rename to contrib/go/_std_1.23/src/runtime/cgo/callbacks.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/callbacks_aix.go b/contrib/go/_std_1.23/src/runtime/cgo/callbacks_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/callbacks_aix.go rename to contrib/go/_std_1.23/src/runtime/cgo/callbacks_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/callbacks_traceback.go b/contrib/go/_std_1.23/src/runtime/cgo/callbacks_traceback.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/callbacks_traceback.go rename to contrib/go/_std_1.23/src/runtime/cgo/callbacks_traceback.go diff --git a/contrib/go/_std_1.23/src/runtime/cgo/cgo.go b/contrib/go/_std_1.23/src/runtime/cgo/cgo.go new file mode 100644 index 000000000000..6b0acf70235d --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/cgo/cgo.go @@ -0,0 +1,41 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package cgo contains runtime support for code generated +by the cgo tool. See the documentation for the cgo command +for details on using cgo. +*/ +package cgo + +/* + +#cgo darwin,!arm64 LDFLAGS: -lpthread +#cgo darwin,arm64 LDFLAGS: -framework CoreFoundation +#cgo dragonfly LDFLAGS: -lpthread +#cgo freebsd LDFLAGS: -lpthread +#cgo android LDFLAGS: -llog +#cgo !android,linux LDFLAGS: -lpthread +#cgo netbsd LDFLAGS: -lpthread +#cgo openbsd LDFLAGS: -lpthread +#cgo aix LDFLAGS: -Wl,-berok +#cgo solaris LDFLAGS: -lxnet +#cgo solaris LDFLAGS: -lsocket + +// Use -fno-stack-protector to avoid problems locating the +// proper support functions. See issues #52919, #54313, #58385. +// Use -Wdeclaration-after-statement because some CI builds use it. +#cgo CFLAGS: -Wall -Werror -fno-stack-protector -Wdeclaration-after-statement + +#cgo solaris CPPFLAGS: -D_POSIX_PTHREAD_SEMANTICS + +*/ +import "C" + +import "runtime/internal/sys" + +// Incomplete is used specifically for the semantics of incomplete C types. +type Incomplete struct { + _ sys.NotInHeap +} diff --git a/contrib/go/_std_1.22/src/runtime/cgo/dragonfly.go b/contrib/go/_std_1.23/src/runtime/cgo/dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/dragonfly.go rename to contrib/go/_std_1.23/src/runtime/cgo/dragonfly.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/freebsd.go b/contrib/go/_std_1.23/src/runtime/cgo/freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/freebsd.go rename to contrib/go/_std_1.23/src/runtime/cgo/freebsd.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_386.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_386.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_386.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_386.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_aix_ppc64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_aix_ppc64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_aix_ppc64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_aix_ppc64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_aix_ppc64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_aix_ppc64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_aix_ppc64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_aix_ppc64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_amd64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_amd64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_amd64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_amd64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_android.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_android.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_android.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_android.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_arm.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_arm.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_arm.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_arm.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_arm64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_arm64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_arm64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_arm64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_context.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_context.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_context.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_context.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_arm64.c similarity index 86% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_arm64.c index f1344de8e19b..7e313767ac39 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_arm64.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_arm64.c @@ -75,19 +75,27 @@ threadentry(void *v) static void init_working_dir() { - CFBundleRef bundle = CFBundleGetMainBundle(); + CFBundleRef bundle; + CFURLRef url_ref; + CFStringRef url_str_ref; + char buf[MAXPATHLEN]; + Boolean res; + int url_len; + char *dir; + CFStringRef wd_ref; + + bundle = CFBundleGetMainBundle(); if (bundle == NULL) { fprintf(stderr, "runtime/cgo: no main bundle\n"); return; } - CFURLRef url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL); + url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL); if (url_ref == NULL) { // No Info.plist found. It can happen on Corellium virtual devices. return; } - CFStringRef url_str_ref = CFURLGetString(url_ref); - char buf[MAXPATHLEN]; - Boolean res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8); + url_str_ref = CFURLGetString(url_ref); + res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8); CFRelease(url_ref); if (!res) { fprintf(stderr, "runtime/cgo: cannot get URL string\n"); @@ -96,13 +104,13 @@ init_working_dir() // url is of the form "file:///path/to/Info.plist". // strip it down to the working directory "/path/to". - int url_len = strlen(buf); + url_len = strlen(buf); if (url_len < sizeof("file://")+sizeof("/Info.plist")) { fprintf(stderr, "runtime/cgo: bad URL: %s\n", buf); return; } buf[url_len-sizeof("/Info.plist")+1] = 0; - char *dir = &buf[0] + sizeof("file://")-1; + dir = &buf[0] + sizeof("file://")-1; if (chdir(dir) != 0) { fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir); @@ -110,7 +118,7 @@ init_working_dir() // The test harness in go_ios_exec passes the relative working directory // in the GoExecWrapperWorkingDirectory property of the app bundle. - CFStringRef wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory")); + wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory")); if (wd_ref != NULL) { if (!CFStringGetCString(wd_ref, buf, sizeof(buf), kCFStringEncodingUTF8)) { fprintf(stderr, "runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n"); diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_dragonfly_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_dragonfly_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_dragonfly_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_dragonfly_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_fatalf.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_fatalf.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_fatalf.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_fatalf.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd_sigaction.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd_sigaction.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd_sigaction.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd_sigaction.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit.c similarity index 94% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit.c index 68f4a023795d..6cceae34c6c3 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit.c @@ -4,6 +4,13 @@ //go:build unix +// When cross-compiling with clang to linux/armv5, atomics are emulated +// and cause a compiler warning. This results in a build failure since +// cgo uses -Werror. See #65290. +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Watomic-alignment" + #include #include #include @@ -41,9 +48,11 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) { uintptr_t _cgo_wait_runtime_init_done(void) { void (*pfn)(struct context_arg*); + int done; + pfn = __atomic_load_n(&cgo_context_function, __ATOMIC_CONSUME); - int done = 2; + done = 2; if (__atomic_load_n(&runtime_init_done, __ATOMIC_CONSUME) != done) { pthread_mutex_lock(&runtime_init_mu); while (__atomic_load_n(&runtime_init_done, __ATOMIC_CONSUME) == 0) { diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit_windows.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit_windows.c similarity index 98% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit_windows.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit_windows.c index 9a8c65ea291a..d43d12a24ae2 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit_windows.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit_windows.c @@ -69,8 +69,10 @@ x_cgo_sys_thread_create(void (*func)(void*), void* arg) { int _cgo_is_runtime_initialized() { + int status; + EnterCriticalSection(&runtime_init_cs); - int status = runtime_init_done; + status = runtime_init_done; LeaveCriticalSection(&runtime_init_cs); return status; } diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_arm64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_arm64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_ppc64x.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_ppc64x.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_ppc64x.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_ppc64x.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_s390x.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_s390x.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_s390x.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_s390x.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_loong64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_loong64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_loong64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_loong64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_mips64x.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_mips64x.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_mips64x.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_mips64x.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_mipsx.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_mipsx.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_mipsx.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_mipsx.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_mmap.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_mmap.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_mmap.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_mmap.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_netbsd.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_netbsd.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_netbsd.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_netbsd.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_openbsd.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_openbsd.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_openbsd.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_openbsd.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_ppc64x.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_ppc64x.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_ppc64x.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_ppc64x.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_riscv64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_riscv64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_riscv64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_riscv64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_s390x.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_s390x.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_s390x.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_s390x.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_setenv.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_setenv.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_setenv.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_setenv.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_sigaction.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_sigaction.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_sigaction.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_sigaction.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_signal2_ios_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_signal2_ios_arm64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_signal2_ios_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_signal2_ios_arm64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_arm64.c similarity index 98% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_arm64.c index 87055e942243..3872f62de130 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_arm64.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_arm64.c @@ -168,7 +168,7 @@ mach_exception_handler(void *port) { // Calls catch_exception_raise. extern boolean_t exc_server(); - mach_msg_server(exc_server, 2048, (mach_port_t)port, 0); + mach_msg_server(exc_server, 2048, (mach_port_t)(uintptr_t)port, 0); abort(); // never returns } diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_nolldb.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_nolldb.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_nolldb.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_nolldb.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_solaris_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_solaris_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_solaris_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_solaris_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_darwin.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_darwin.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_darwin.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_darwin.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_unix.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_unix.c similarity index 89% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_unix.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_unix.c index 884281dc1566..df0049a4f37a 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_unix.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_unix.c @@ -31,8 +31,11 @@ x_cgo_getstackbound(uintptr bounds[2]) pthread_attr_get_np(pthread_self(), &attr); pthread_attr_getstack(&attr, &addr, &size); // low address #else - pthread_attr_getstacksize(&attr, &size); - addr = __builtin_frame_address(0) + 4096 - size; + // We don't know how to get the current stacks, leave it as + // 0 and the caller will use an estimate based on the current + // SP. + addr = 0; + size = 0; #endif pthread_attr_destroy(&attr); diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_windows.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_windows.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_windows.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_windows.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_traceback.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_traceback.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_traceback.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_traceback.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_util.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_util.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_util.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_util.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_386.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_386.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_386.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_386.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_arm64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_arm64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/handle.go b/contrib/go/_std_1.23/src/runtime/cgo/handle.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/handle.go rename to contrib/go/_std_1.23/src/runtime/cgo/handle.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/iscgo.go b/contrib/go/_std_1.23/src/runtime/cgo/iscgo.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/iscgo.go rename to contrib/go/_std_1.23/src/runtime/cgo/iscgo.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/libcgo.h b/contrib/go/_std_1.23/src/runtime/cgo/libcgo.h similarity index 98% rename from contrib/go/_std_1.22/src/runtime/cgo/libcgo.h rename to contrib/go/_std_1.23/src/runtime/cgo/libcgo.h index 295c12c53c11..26da68fadb67 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/libcgo.h +++ b/contrib/go/_std_1.23/src/runtime/cgo/libcgo.h @@ -76,7 +76,7 @@ void x_cgo_getstackbound(uintptr bounds[2]); /* * Prints error then calls abort. For linux and android. */ -void fatalf(const char* format, ...); +void fatalf(const char* format, ...) __attribute__ ((noreturn)); /* * Registers the current mach thread port for EXC_BAD_ACCESS processing. diff --git a/contrib/go/_std_1.22/src/runtime/cgo/libcgo_unix.h b/contrib/go/_std_1.23/src/runtime/cgo/libcgo_unix.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/libcgo_unix.h rename to contrib/go/_std_1.23/src/runtime/cgo/libcgo_unix.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/libcgo_windows.h b/contrib/go/_std_1.23/src/runtime/cgo/libcgo_windows.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/libcgo_windows.h rename to contrib/go/_std_1.23/src/runtime/cgo/libcgo_windows.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/linux.go b/contrib/go/_std_1.23/src/runtime/cgo/linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/linux.go rename to contrib/go/_std_1.23/src/runtime/cgo/linux.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/linux_syscall.c b/contrib/go/_std_1.23/src/runtime/cgo/linux_syscall.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/linux_syscall.c rename to contrib/go/_std_1.23/src/runtime/cgo/linux_syscall.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/mmap.go b/contrib/go/_std_1.23/src/runtime/cgo/mmap.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/mmap.go rename to contrib/go/_std_1.23/src/runtime/cgo/mmap.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/netbsd.go b/contrib/go/_std_1.23/src/runtime/cgo/netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/netbsd.go rename to contrib/go/_std_1.23/src/runtime/cgo/netbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/openbsd.go b/contrib/go/_std_1.23/src/runtime/cgo/openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/openbsd.go rename to contrib/go/_std_1.23/src/runtime/cgo/openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/setenv.go b/contrib/go/_std_1.23/src/runtime/cgo/setenv.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/setenv.go rename to contrib/go/_std_1.23/src/runtime/cgo/setenv.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/sigaction.go b/contrib/go/_std_1.23/src/runtime/cgo/sigaction.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/sigaction.go rename to contrib/go/_std_1.23/src/runtime/cgo/sigaction.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/signal_ios_arm64.go b/contrib/go/_std_1.23/src/runtime/cgo/signal_ios_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/signal_ios_arm64.go rename to contrib/go/_std_1.23/src/runtime/cgo/signal_ios_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/signal_ios_arm64.s b/contrib/go/_std_1.23/src/runtime/cgo/signal_ios_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/signal_ios_arm64.s rename to contrib/go/_std_1.23/src/runtime/cgo/signal_ios_arm64.s diff --git a/contrib/go/_std_1.23/src/runtime/cgo/ya.make b/contrib/go/_std_1.23/src/runtime/cgo/ya.make new file mode 100644 index 000000000000..6c962d759581 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/cgo/ya.make @@ -0,0 +1,145 @@ +IF (CGO_ENABLED) + GO_LIBRARY() + + PEERDIR( + library/cpp/sanitizer/include + ) + + NO_COMPILER_WARNINGS() + + SRCS( + abi_loong64.h + abi_ppc64x.h + callbacks.go + CGO_EXPORT gcc_context.c + CGO_EXPORT gcc_util.c + handle.go + iscgo.go + libcgo.h + libcgo_unix.h + ) + + CGO_SRCS( + cgo.go + ) + + IF (ARCH_ARM64) + SRCS( + abi_arm64.h + asm_arm64.s + gcc_arm64.S + ) + ENDIF() + + IF (ARCH_X86_64) + SRCS( + abi_amd64.h + asm_amd64.s + gcc_amd64.S + ) + ENDIF() + + IF (ARCH_ARM7) + SRCS( + asm_arm.s + gcc_arm.S + ) + ENDIF() + + IF (OS_DARWIN) + SRCS( + callbacks_traceback.go + CGO_EXPORT gcc_libinit.c + CGO_EXPORT gcc_setenv.c + CGO_EXPORT gcc_stack_darwin.c + CGO_EXPORT gcc_traceback.c + setenv.go + ) + + IF (ARCH_ARM64) + CGO_LDFLAGS( + -framework + CoreFoundation + ) + + SRCS( + CGO_EXPORT gcc_darwin_arm64.c + ) + ENDIF() + + IF (ARCH_X86_64) + CGO_LDFLAGS( + -lpthread + ) + + SRCS( + CGO_EXPORT gcc_darwin_amd64.c + ) + ENDIF() + ENDIF() + + IF (OS_LINUX) + CGO_LDFLAGS(-lpthread -ldl -lresolv) + + SRCS( + callbacks_traceback.go + CGO_EXPORT gcc_fatalf.c + CGO_EXPORT gcc_libinit.c + CGO_EXPORT gcc_setenv.c + CGO_EXPORT gcc_stack_unix.c + CGO_EXPORT gcc_traceback.c + linux.go + CGO_EXPORT linux_syscall.c + setenv.go + ) + + IF (ARCH_ARM64 OR ARCH_X86_64) + SRCS( + CGO_EXPORT gcc_mmap.c + mmap.go + CGO_EXPORT gcc_sigaction.c + sigaction.go + ) + ENDIF() + + IF (ARCH_ARM64) + SRCS( + CGO_EXPORT gcc_linux_arm64.c + ) + ENDIF() + + IF (ARCH_X86_64) + SRCS( + CGO_EXPORT gcc_linux_amd64.c + ) + ENDIF() + + IF (ARCH_ARM7) + SRCS( + CGO_EXPORT gcc_linux.c + ) + ENDIF() + ENDIF() + + IF (OS_WINDOWS) + SRCS( + CGO_EXPORT gcc_libinit_windows.c + CGO_EXPORT gcc_stack_windows.c + libcgo_windows.h + ) + + IF (ARCH_ARM64) + SRCS( + CGO_EXPORT gcc_windows_arm64.c + ) + ENDIF() + + IF (ARCH_X86_64) + SRCS( + CGO_EXPORT gcc_windows_amd64.c + ) + ENDIF() + ENDIF() + + END() +ENDIF() diff --git a/contrib/go/_std_1.22/src/runtime/cgo_mmap.go b/contrib/go/_std_1.23/src/runtime/cgo_mmap.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo_mmap.go rename to contrib/go/_std_1.23/src/runtime/cgo_mmap.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo_ppc64x.go b/contrib/go/_std_1.23/src/runtime/cgo_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/cgo_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo_sigaction.go b/contrib/go/_std_1.23/src/runtime/cgo_sigaction.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo_sigaction.go rename to contrib/go/_std_1.23/src/runtime/cgo_sigaction.go diff --git a/contrib/go/_std_1.22/src/runtime/cgocall.go b/contrib/go/_std_1.23/src/runtime/cgocall.go similarity index 84% rename from contrib/go/_std_1.22/src/runtime/cgocall.go rename to contrib/go/_std_1.23/src/runtime/cgocall.go index 0d3cc40903a3..375e9d6d4a12 100644 --- a/contrib/go/_std_1.22/src/runtime/cgocall.go +++ b/contrib/go/_std_1.23/src/runtime/cgocall.go @@ -85,6 +85,7 @@ package runtime import ( + "internal/abi" "internal/goarch" "internal/goexperiment" "runtime/internal/sys" @@ -120,6 +121,15 @@ var ncgocall uint64 // number of cgo calls in total for dead m // platforms. Syscalls may have untyped arguments on the stack, so // it's not safe to grow or scan the stack. // +// cgocall should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cgocall //go:nosplit func cgocall(fn, arg unsafe.Pointer) int32 { if !iscgo && GOOS != "solaris" && GOOS != "illumos" && GOOS != "windows" { @@ -181,8 +191,14 @@ func cgocall(fn, arg unsafe.Pointer) int32 { osPreemptExtExit(mp) + // Save current syscall parameters, so m.winsyscall can be + // used again if callback decide to make syscall. + winsyscall := mp.winsyscall + exitsyscall() + getg().m.winsyscall = winsyscall + // Note that raceacquire must be called only after exitsyscall has // wired this M to a P. if raceenabled { @@ -215,34 +231,6 @@ func cgocall(fn, arg unsafe.Pointer) int32 { func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) { g0 := mp.g0 - inBound := sp > g0.stack.lo && sp <= g0.stack.hi - if mp.ncgo > 0 && !inBound { - // ncgo > 0 indicates that this M was in Go further up the stack - // (it called C and is now receiving a callback). - // - // !inBound indicates that we were called with SP outside the - // expected system stack bounds (C changed the stack out from - // under us between the cgocall and cgocallback?). - // - // It is not safe for the C call to change the stack out from - // under us, so throw. - - // Note that this case isn't possible for signal == true, as - // that is always passing a new M from needm. - - // Stack is bogus, but reset the bounds anyway so we can print. - hi := g0.stack.hi - lo := g0.stack.lo - g0.stack.hi = sp + 1024 - g0.stack.lo = sp - 32*1024 - g0.stackguard0 = g0.stack.lo + stackGuard - g0.stackguard1 = g0.stackguard0 - - print("M ", mp.id, " procid ", mp.procid, " runtime: cgocallback with sp=", hex(sp), " out of bounds [", hex(lo), ", ", hex(hi), "]") - print("\n") - exit(2) - } - if !mp.isextra { // We allocated the stack for standard Ms. Don't replace the // stack bounds with estimated ones when we already initialized @@ -250,26 +238,37 @@ func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) { return } - // This M does not have Go further up the stack. However, it may have - // previously called into Go, initializing the stack bounds. Between - // that call returning and now the stack may have changed (perhaps the - // C thread is running a coroutine library). We need to update the - // stack bounds for this case. + inBound := sp > g0.stack.lo && sp <= g0.stack.hi + if inBound && mp.g0StackAccurate { + // This M has called into Go before and has the stack bounds + // initialized. We have the accurate stack bounds, and the SP + // is in bounds. We expect it continues to run within the same + // bounds. + return + } + + // We don't have an accurate stack bounds (either it never calls + // into Go before, or we couldn't get the accurate bounds), or the + // current SP is not within the previous bounds (the stack may have + // changed between calls). We need to update the stack bounds. // // N.B. we need to update the stack bounds even if SP appears to - // already be in bounds. Our "bounds" may actually be estimated dummy - // bounds (below). The actual stack bounds could have shifted but still - // have partial overlap with our dummy bounds. If we failed to update - // in that case, we could find ourselves seemingly called near the - // bottom of the stack bounds, where we quickly run out of space. + // already be in bounds, if our bounds are estimated dummy bounds + // (below). We may be in a different region within the same actual + // stack bounds, but our estimates were not accurate. Or the actual + // stack bounds could have shifted but still have partial overlap with + // our dummy bounds. If we failed to update in that case, we could find + // ourselves seemingly called near the bottom of the stack bounds, where + // we quickly run out of space. // Set the stack bounds to match the current stack. If we don't // actually know how big the stack is, like we don't know how big any // scheduling stack is, but we assume there's at least 32 kB. If we // can get a more accurate stack bound from pthread, use that, provided - // it actually contains SP.. + // it actually contains SP. g0.stack.hi = sp + 1024 g0.stack.lo = sp - 32*1024 + mp.g0StackAccurate = false if !signal && _cgo_getstackbound != nil { // Don't adjust if called from the signal handler. // We are on the signal stack, not the pthread stack. @@ -280,12 +279,16 @@ func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) { asmcgocall(_cgo_getstackbound, unsafe.Pointer(&bounds)) // getstackbound is an unsupported no-op on Windows. // + // On Unix systems, if the API to get accurate stack bounds is + // not available, it returns zeros. + // // Don't use these bounds if they don't contain SP. Perhaps we // were called by something not using the standard thread // stack. if bounds[0] != 0 && sp > bounds[0] && sp <= bounds[1] { g0.stack.lo = bounds[0] g0.stack.hi = bounds[1] + mp.g0StackAccurate = true } } g0.stackguard0 = g0.stack.lo + stackGuard @@ -303,6 +306,8 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { } sp := gp.m.g0.sched.sp // system sp saved by cgocallback. + oldStack := gp.m.g0.stack + oldAccurate := gp.m.g0StackAccurate callbackUpdateSystemStack(gp.m, sp, false) // The call from C is on gp.m's g0 stack, so we must ensure @@ -314,16 +319,22 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { checkm := gp.m - // Save current syscall parameters, so m.syscall can be + // Save current syscall parameters, so m.winsyscall can be // used again if callback decide to make syscall. - syscall := gp.m.syscall + winsyscall := gp.m.winsyscall // entersyscall saves the caller's SP to allow the GC to trace the Go // stack. However, since we're returning to an earlier stack frame and // need to pair with the entersyscall() call made by cgocall, we must // save syscall* and let reentersyscall restore them. + // + // Note: savedsp and savedbp MUST be held in locals as an unsafe.Pointer. + // When we call into Go, the stack is free to be moved. If these locals + // aren't visible in the stack maps, they won't get updated properly, + // and will end up being stale when restored by reentersyscall. savedsp := unsafe.Pointer(gp.syscallsp) savedpc := gp.syscallpc + savedbp := unsafe.Pointer(gp.syscallbp) exitsyscall() // coming out of cgo call gp.m.incgo = false if gp.m.isextra { @@ -344,7 +355,9 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { gp.m.incgo = true unlockOSThread() - if gp.m.isextra { + if gp.m.isextra && gp.m.ncgo == 0 { + // There are no active cgocalls above this frame (ncgo == 0), + // thus there can't be more Go frames above this frame. gp.m.isExtraInC = true } @@ -355,9 +368,15 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { osPreemptExtEnter(gp.m) // going back to cgo call - reentersyscall(savedpc, uintptr(savedsp)) + reentersyscall(savedpc, uintptr(savedsp), uintptr(savedbp)) - gp.m.syscall = syscall + gp.m.winsyscall = winsyscall + + // Restore the old g0 stack bounds + gp.m.g0.stack = oldStack + gp.m.g0.stackguard0 = oldStack.lo + stackGuard + gp.m.g0.stackguard1 = gp.m.g0.stackguard0 + gp.m.g0StackAccurate = oldAccurate } func cgocallbackg1(fn, frame unsafe.Pointer, ctxt uintptr) { @@ -512,29 +531,29 @@ func cgoCheckPointer(ptr any, arg any) { t := ep._type top := true - if arg != nil && (t.Kind_&kindMask == kindPtr || t.Kind_&kindMask == kindUnsafePointer) { + if arg != nil && (t.Kind_&abi.KindMask == abi.Pointer || t.Kind_&abi.KindMask == abi.UnsafePointer) { p := ep.data - if t.Kind_&kindDirectIface == 0 { + if t.Kind_&abi.KindDirectIface == 0 { p = *(*unsafe.Pointer)(p) } if p == nil || !cgoIsGoPointer(p) { return } aep := efaceOf(&arg) - switch aep._type.Kind_ & kindMask { - case kindBool: - if t.Kind_&kindMask == kindUnsafePointer { + switch aep._type.Kind_ & abi.KindMask { + case abi.Bool: + if t.Kind_&abi.KindMask == abi.UnsafePointer { // We don't know the type of the element. break } pt := (*ptrtype)(unsafe.Pointer(t)) cgoCheckArg(pt.Elem, p, true, false, cgoCheckPointerFail) return - case kindSlice: + case abi.Slice: // Check the slice rather than the pointer. ep = aep t = ep._type - case kindArray: + case abi.Array: // Check the array rather than the pointer. // Pass top as false since we have a pointer // to the array. @@ -546,7 +565,7 @@ func cgoCheckPointer(ptr any, arg any) { } } - cgoCheckArg(t, ep.data, t.Kind_&kindDirectIface == 0, top, cgoCheckPointerFail) + cgoCheckArg(t, ep.data, t.Kind_&abi.KindDirectIface == 0, top, cgoCheckPointerFail) } const cgoCheckPointerFail = "cgo argument has Go pointer to unpinned Go pointer" @@ -558,33 +577,33 @@ const cgoResultFail = "cgo result is unpinned Go pointer or points to unpinned G // level, where Go pointers are allowed. Go pointers to pinned objects are // allowed as long as they don't reference other unpinned pointers. func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { - if t.PtrBytes == 0 || p == nil { + if !t.Pointers() || p == nil { // If the type has no pointers there is nothing to do. return } - switch t.Kind_ & kindMask { + switch t.Kind_ & abi.KindMask { default: throw("can't happen") - case kindArray: + case abi.Array: at := (*arraytype)(unsafe.Pointer(t)) if !indir { if at.Len != 1 { throw("can't happen") } - cgoCheckArg(at.Elem, p, at.Elem.Kind_&kindDirectIface == 0, top, msg) + cgoCheckArg(at.Elem, p, at.Elem.Kind_&abi.KindDirectIface == 0, top, msg) return } for i := uintptr(0); i < at.Len; i++ { cgoCheckArg(at.Elem, p, true, top, msg) p = add(p, at.Elem.Size_) } - case kindChan, kindMap: + case abi.Chan, abi.Map: // These types contain internal pointers that will // always be allocated in the Go heap. It's never OK // to pass them to C. panic(errorString(msg)) - case kindFunc: + case abi.Func: if indir { p = *(*unsafe.Pointer)(p) } @@ -592,7 +611,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { return } panic(errorString(msg)) - case kindInterface: + case abi.Interface: it := *(**_type)(p) if it == nil { return @@ -610,8 +629,8 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { if !top && !isPinned(p) { panic(errorString(msg)) } - cgoCheckArg(it, p, it.Kind_&kindDirectIface == 0, false, msg) - case kindSlice: + cgoCheckArg(it, p, it.Kind_&abi.KindDirectIface == 0, false, msg) + case abi.Slice: st := (*slicetype)(unsafe.Pointer(t)) s := (*slice)(p) p = s.array @@ -621,14 +640,14 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { if !top && !isPinned(p) { panic(errorString(msg)) } - if st.Elem.PtrBytes == 0 { + if !st.Elem.Pointers() { return } for i := 0; i < s.cap; i++ { cgoCheckArg(st.Elem, p, true, false, msg) p = add(p, st.Elem.Size_) } - case kindString: + case abi.String: ss := (*stringStruct)(p) if !cgoIsGoPointer(ss.str) { return @@ -636,22 +655,22 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { if !top && !isPinned(ss.str) { panic(errorString(msg)) } - case kindStruct: + case abi.Struct: st := (*structtype)(unsafe.Pointer(t)) if !indir { if len(st.Fields) != 1 { throw("can't happen") } - cgoCheckArg(st.Fields[0].Typ, p, st.Fields[0].Typ.Kind_&kindDirectIface == 0, top, msg) + cgoCheckArg(st.Fields[0].Typ, p, st.Fields[0].Typ.Kind_&abi.KindDirectIface == 0, top, msg) return } for _, f := range st.Fields { - if f.Typ.PtrBytes == 0 { + if !f.Typ.Pointers() { continue } cgoCheckArg(f.Typ, add(p, f.Offset), true, top, msg) } - case kindPtr, kindUnsafePointer: + case abi.Pointer, abi.UnsafePointer: if indir { p = *(*unsafe.Pointer)(p) if p == nil { @@ -681,30 +700,15 @@ func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) { if base == 0 { return } - if goexperiment.AllocHeaders { - tp := span.typePointersOfUnchecked(base) - for { - var addr uintptr - if tp, addr = tp.next(base + span.elemsize); addr == 0 { - break - } - pp := *(*unsafe.Pointer)(unsafe.Pointer(addr)) - if cgoIsGoPointer(pp) && !isPinned(pp) { - panic(errorString(msg)) - } + tp := span.typePointersOfUnchecked(base) + for { + var addr uintptr + if tp, addr = tp.next(base + span.elemsize); addr == 0 { + break } - } else { - n := span.elemsize - hbits := heapBitsForAddr(base, n) - for { - var addr uintptr - if hbits, addr = hbits.next(); addr == 0 { - break - } - pp := *(*unsafe.Pointer)(unsafe.Pointer(addr)) - if cgoIsGoPointer(pp) && !isPinned(pp) { - panic(errorString(msg)) - } + pp := *(*unsafe.Pointer)(unsafe.Pointer(addr)) + if cgoIsGoPointer(pp) && !isPinned(pp) { + panic(errorString(msg)) } } return @@ -765,5 +769,5 @@ func cgoCheckResult(val any) { ep := efaceOf(&val) t := ep._type - cgoCheckArg(t, ep.data, t.Kind_&kindDirectIface == 0, false, cgoResultFail) + cgoCheckArg(t, ep.data, t.Kind_&abi.KindDirectIface == 0, false, cgoResultFail) } diff --git a/contrib/go/_std_1.22/src/runtime/cgocallback.go b/contrib/go/_std_1.23/src/runtime/cgocallback.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgocallback.go rename to contrib/go/_std_1.23/src/runtime/cgocallback.go diff --git a/contrib/go/_std_1.22/src/runtime/cgocheck.go b/contrib/go/_std_1.23/src/runtime/cgocheck.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/cgocheck.go rename to contrib/go/_std_1.23/src/runtime/cgocheck.go index 3d6de4f855dc..3f2c271953db 100644 --- a/contrib/go/_std_1.22/src/runtime/cgocheck.go +++ b/contrib/go/_std_1.23/src/runtime/cgocheck.go @@ -8,8 +8,8 @@ package runtime import ( + "internal/abi" "internal/goarch" - "internal/goexperiment" "unsafe" ) @@ -90,7 +90,7 @@ func cgoCheckMemmove(typ *_type, dst, src unsafe.Pointer) { //go:nosplit //go:nowritebarrier func cgoCheckMemmove2(typ *_type, dst, src unsafe.Pointer, off, size uintptr) { - if typ.PtrBytes == 0 { + if !typ.Pointers() { return } if !cgoIsGoPointer(src) { @@ -111,7 +111,7 @@ func cgoCheckMemmove2(typ *_type, dst, src unsafe.Pointer, off, size uintptr) { //go:nosplit //go:nowritebarrier func cgoCheckSliceCopy(typ *_type, dst, src unsafe.Pointer, n int) { - if typ.PtrBytes == 0 { + if !typ.Pointers() { return } if !cgoIsGoPointer(src) { @@ -142,7 +142,7 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) { size = ptrdataSize } - if typ.Kind_&kindGCProg == 0 { + if typ.Kind_&abi.KindGCProg == 0 { cgoCheckBits(src, typ.GCData, off, size) return } @@ -177,29 +177,15 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) { } // src must be in the regular heap. - if goexperiment.AllocHeaders { - tp := s.typePointersOf(uintptr(src), size) - for { - var addr uintptr - if tp, addr = tp.next(uintptr(src) + size); addr == 0 { - break - } - v := *(*unsafe.Pointer)(unsafe.Pointer(addr)) - if cgoIsGoPointer(v) && !isPinned(v) { - throw(cgoWriteBarrierFail) - } + tp := s.typePointersOf(uintptr(src), size) + for { + var addr uintptr + if tp, addr = tp.next(uintptr(src) + size); addr == 0 { + break } - } else { - hbits := heapBitsForAddr(uintptr(src), size) - for { - var addr uintptr - if hbits, addr = hbits.next(); addr == 0 { - break - } - v := *(*unsafe.Pointer)(unsafe.Pointer(addr)) - if cgoIsGoPointer(v) && !isPinned(v) { - throw(cgoWriteBarrierFail) - } + v := *(*unsafe.Pointer)(unsafe.Pointer(addr)) + if cgoIsGoPointer(v) && !isPinned(v) { + throw(cgoWriteBarrierFail) } } } @@ -247,7 +233,7 @@ func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) { //go:nowritebarrier //go:systemstack func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) { - if typ.PtrBytes == 0 { + if !typ.Pointers() { return } @@ -259,14 +245,14 @@ func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) { size = ptrdataSize } - if typ.Kind_&kindGCProg == 0 { + if typ.Kind_&abi.KindGCProg == 0 { cgoCheckBits(src, typ.GCData, off, size) return } - switch typ.Kind_ & kindMask { + switch typ.Kind_ & abi.KindMask { default: throw("can't happen") - case kindArray: + case abi.Array: at := (*arraytype)(unsafe.Pointer(typ)) for i := uintptr(0); i < at.Len; i++ { if off < at.Elem.Size_ { @@ -284,7 +270,7 @@ func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) { } size -= checked } - case kindStruct: + case abi.Struct: st := (*structtype)(unsafe.Pointer(typ)) for _, f := range st.Fields { if off < f.Typ.Size_ { diff --git a/contrib/go/_std_1.23/src/runtime/chan.go b/contrib/go/_std_1.23/src/runtime/chan.go new file mode 100644 index 000000000000..f1cd74a3fd16 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/chan.go @@ -0,0 +1,935 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +// This file contains the implementation of Go channels. + +// Invariants: +// At least one of c.sendq and c.recvq is empty, +// except for the case of an unbuffered channel with a single goroutine +// blocked on it for both sending and receiving using a select statement, +// in which case the length of c.sendq and c.recvq is limited only by the +// size of the select statement. +// +// For buffered channels, also: +// c.qcount > 0 implies that c.recvq is empty. +// c.qcount < c.dataqsiz implies that c.sendq is empty. + +import ( + "internal/abi" + "internal/runtime/atomic" + "runtime/internal/math" + "unsafe" +) + +const ( + maxAlign = 8 + hchanSize = unsafe.Sizeof(hchan{}) + uintptr(-int(unsafe.Sizeof(hchan{}))&(maxAlign-1)) + debugChan = false +) + +type hchan struct { + qcount uint // total data in the queue + dataqsiz uint // size of the circular queue + buf unsafe.Pointer // points to an array of dataqsiz elements + elemsize uint16 + closed uint32 + timer *timer // timer feeding this chan + elemtype *_type // element type + sendx uint // send index + recvx uint // receive index + recvq waitq // list of recv waiters + sendq waitq // list of send waiters + + // lock protects all fields in hchan, as well as several + // fields in sudogs blocked on this channel. + // + // Do not change another G's status while holding this lock + // (in particular, do not ready a G), as this can deadlock + // with stack shrinking. + lock mutex +} + +type waitq struct { + first *sudog + last *sudog +} + +//go:linkname reflect_makechan reflect.makechan +func reflect_makechan(t *chantype, size int) *hchan { + return makechan(t, size) +} + +func makechan64(t *chantype, size int64) *hchan { + if int64(int(size)) != size { + panic(plainError("makechan: size out of range")) + } + + return makechan(t, int(size)) +} + +func makechan(t *chantype, size int) *hchan { + elem := t.Elem + + // compiler checks this but be safe. + if elem.Size_ >= 1<<16 { + throw("makechan: invalid channel element type") + } + if hchanSize%maxAlign != 0 || elem.Align_ > maxAlign { + throw("makechan: bad alignment") + } + + mem, overflow := math.MulUintptr(elem.Size_, uintptr(size)) + if overflow || mem > maxAlloc-hchanSize || size < 0 { + panic(plainError("makechan: size out of range")) + } + + // Hchan does not contain pointers interesting for GC when elements stored in buf do not contain pointers. + // buf points into the same allocation, elemtype is persistent. + // SudoG's are referenced from their owning thread so they can't be collected. + // TODO(dvyukov,rlh): Rethink when collector can move allocated objects. + var c *hchan + switch { + case mem == 0: + // Queue or element size is zero. + c = (*hchan)(mallocgc(hchanSize, nil, true)) + // Race detector uses this location for synchronization. + c.buf = c.raceaddr() + case !elem.Pointers(): + // Elements do not contain pointers. + // Allocate hchan and buf in one call. + c = (*hchan)(mallocgc(hchanSize+mem, nil, true)) + c.buf = add(unsafe.Pointer(c), hchanSize) + default: + // Elements contain pointers. + c = new(hchan) + c.buf = mallocgc(mem, elem, true) + } + + c.elemsize = uint16(elem.Size_) + c.elemtype = elem + c.dataqsiz = uint(size) + lockInit(&c.lock, lockRankHchan) + + if debugChan { + print("makechan: chan=", c, "; elemsize=", elem.Size_, "; dataqsiz=", size, "\n") + } + return c +} + +// chanbuf(c, i) is pointer to the i'th slot in the buffer. +// +// chanbuf should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/fjl/memsize +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname chanbuf +func chanbuf(c *hchan, i uint) unsafe.Pointer { + return add(c.buf, uintptr(i)*uintptr(c.elemsize)) +} + +// full reports whether a send on c would block (that is, the channel is full). +// It uses a single word-sized read of mutable state, so although +// the answer is instantaneously true, the correct answer may have changed +// by the time the calling function receives the return value. +func full(c *hchan) bool { + // c.dataqsiz is immutable (never written after the channel is created) + // so it is safe to read at any time during channel operation. + if c.dataqsiz == 0 { + // Assumes that a pointer read is relaxed-atomic. + return c.recvq.first == nil + } + // Assumes that a uint read is relaxed-atomic. + return c.qcount == c.dataqsiz +} + +// entry point for c <- x from compiled code. +// +//go:nosplit +func chansend1(c *hchan, elem unsafe.Pointer) { + chansend(c, elem, true, getcallerpc()) +} + +/* + * generic single channel send/recv + * If block is not nil, + * then the protocol will not + * sleep but return if it could + * not complete. + * + * sleep can wake up with g.param == nil + * when a channel involved in the sleep has + * been closed. it is easiest to loop and re-run + * the operation; we'll see that it's now closed. + */ +func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { + if c == nil { + if !block { + return false + } + gopark(nil, nil, waitReasonChanSendNilChan, traceBlockForever, 2) + throw("unreachable") + } + + if debugChan { + print("chansend: chan=", c, "\n") + } + + if raceenabled { + racereadpc(c.raceaddr(), callerpc, abi.FuncPCABIInternal(chansend)) + } + + // Fast path: check for failed non-blocking operation without acquiring the lock. + // + // After observing that the channel is not closed, we observe that the channel is + // not ready for sending. Each of these observations is a single word-sized read + // (first c.closed and second full()). + // Because a closed channel cannot transition from 'ready for sending' to + // 'not ready for sending', even if the channel is closed between the two observations, + // they imply a moment between the two when the channel was both not yet closed + // and not ready for sending. We behave as if we observed the channel at that moment, + // and report that the send cannot proceed. + // + // It is okay if the reads are reordered here: if we observe that the channel is not + // ready for sending and then observe that it is not closed, that implies that the + // channel wasn't closed during the first observation. However, nothing here + // guarantees forward progress. We rely on the side effects of lock release in + // chanrecv() and closechan() to update this thread's view of c.closed and full(). + if !block && c.closed == 0 && full(c) { + return false + } + + var t0 int64 + if blockprofilerate > 0 { + t0 = cputicks() + } + + lock(&c.lock) + + if c.closed != 0 { + unlock(&c.lock) + panic(plainError("send on closed channel")) + } + + if sg := c.recvq.dequeue(); sg != nil { + // Found a waiting receiver. We pass the value we want to send + // directly to the receiver, bypassing the channel buffer (if any). + send(c, sg, ep, func() { unlock(&c.lock) }, 3) + return true + } + + if c.qcount < c.dataqsiz { + // Space is available in the channel buffer. Enqueue the element to send. + qp := chanbuf(c, c.sendx) + if raceenabled { + racenotify(c, c.sendx, nil) + } + typedmemmove(c.elemtype, qp, ep) + c.sendx++ + if c.sendx == c.dataqsiz { + c.sendx = 0 + } + c.qcount++ + unlock(&c.lock) + return true + } + + if !block { + unlock(&c.lock) + return false + } + + // Block on the channel. Some receiver will complete our operation for us. + gp := getg() + mysg := acquireSudog() + mysg.releasetime = 0 + if t0 != 0 { + mysg.releasetime = -1 + } + // No stack splits between assigning elem and enqueuing mysg + // on gp.waiting where copystack can find it. + mysg.elem = ep + mysg.waitlink = nil + mysg.g = gp + mysg.isSelect = false + mysg.c = c + gp.waiting = mysg + gp.param = nil + c.sendq.enqueue(mysg) + // Signal to anyone trying to shrink our stack that we're about + // to park on a channel. The window between when this G's status + // changes and when we set gp.activeStackChans is not safe for + // stack shrinking. + gp.parkingOnChan.Store(true) + gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceBlockChanSend, 2) + // Ensure the value being sent is kept alive until the + // receiver copies it out. The sudog has a pointer to the + // stack object, but sudogs aren't considered as roots of the + // stack tracer. + KeepAlive(ep) + + // someone woke us up. + if mysg != gp.waiting { + throw("G waiting list is corrupted") + } + gp.waiting = nil + gp.activeStackChans = false + closed := !mysg.success + gp.param = nil + if mysg.releasetime > 0 { + blockevent(mysg.releasetime-t0, 2) + } + mysg.c = nil + releaseSudog(mysg) + if closed { + if c.closed == 0 { + throw("chansend: spurious wakeup") + } + panic(plainError("send on closed channel")) + } + return true +} + +// send processes a send operation on an empty channel c. +// The value ep sent by the sender is copied to the receiver sg. +// The receiver is then woken up to go on its merry way. +// Channel c must be empty and locked. send unlocks c with unlockf. +// sg must already be dequeued from c. +// ep must be non-nil and point to the heap or the caller's stack. +func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) { + if raceenabled { + if c.dataqsiz == 0 { + racesync(c, sg) + } else { + // Pretend we go through the buffer, even though + // we copy directly. Note that we need to increment + // the head/tail locations only when raceenabled. + racenotify(c, c.recvx, nil) + racenotify(c, c.recvx, sg) + c.recvx++ + if c.recvx == c.dataqsiz { + c.recvx = 0 + } + c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz + } + } + if sg.elem != nil { + sendDirect(c.elemtype, sg, ep) + sg.elem = nil + } + gp := sg.g + unlockf() + gp.param = unsafe.Pointer(sg) + sg.success = true + if sg.releasetime != 0 { + sg.releasetime = cputicks() + } + goready(gp, skip+1) +} + +// timerchandrain removes all elements in channel c's buffer. +// It reports whether any elements were removed. +// Because it is only intended for timers, it does not +// handle waiting senders at all (all timer channels +// use non-blocking sends to fill the buffer). +func timerchandrain(c *hchan) bool { + // Note: Cannot use empty(c) because we are called + // while holding c.timer.sendLock, and empty(c) will + // call c.timer.maybeRunChan, which will deadlock. + // We are emptying the channel, so we only care about + // the count, not about potentially filling it up. + if atomic.Loaduint(&c.qcount) == 0 { + return false + } + lock(&c.lock) + any := false + for c.qcount > 0 { + any = true + typedmemclr(c.elemtype, chanbuf(c, c.recvx)) + c.recvx++ + if c.recvx == c.dataqsiz { + c.recvx = 0 + } + c.qcount-- + } + unlock(&c.lock) + return any +} + +// Sends and receives on unbuffered or empty-buffered channels are the +// only operations where one running goroutine writes to the stack of +// another running goroutine. The GC assumes that stack writes only +// happen when the goroutine is running and are only done by that +// goroutine. Using a write barrier is sufficient to make up for +// violating that assumption, but the write barrier has to work. +// typedmemmove will call bulkBarrierPreWrite, but the target bytes +// are not in the heap, so that will not help. We arrange to call +// memmove and typeBitsBulkBarrier instead. + +func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) { + // src is on our stack, dst is a slot on another stack. + + // Once we read sg.elem out of sg, it will no longer + // be updated if the destination's stack gets copied (shrunk). + // So make sure that no preemption points can happen between read & use. + dst := sg.elem + typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.Size_) + // No need for cgo write barrier checks because dst is always + // Go memory. + memmove(dst, src, t.Size_) +} + +func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) { + // dst is on our stack or the heap, src is on another stack. + // The channel is locked, so src will not move during this + // operation. + src := sg.elem + typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.Size_) + memmove(dst, src, t.Size_) +} + +func closechan(c *hchan) { + if c == nil { + panic(plainError("close of nil channel")) + } + + lock(&c.lock) + if c.closed != 0 { + unlock(&c.lock) + panic(plainError("close of closed channel")) + } + + if raceenabled { + callerpc := getcallerpc() + racewritepc(c.raceaddr(), callerpc, abi.FuncPCABIInternal(closechan)) + racerelease(c.raceaddr()) + } + + c.closed = 1 + + var glist gList + + // release all readers + for { + sg := c.recvq.dequeue() + if sg == nil { + break + } + if sg.elem != nil { + typedmemclr(c.elemtype, sg.elem) + sg.elem = nil + } + if sg.releasetime != 0 { + sg.releasetime = cputicks() + } + gp := sg.g + gp.param = unsafe.Pointer(sg) + sg.success = false + if raceenabled { + raceacquireg(gp, c.raceaddr()) + } + glist.push(gp) + } + + // release all writers (they will panic) + for { + sg := c.sendq.dequeue() + if sg == nil { + break + } + sg.elem = nil + if sg.releasetime != 0 { + sg.releasetime = cputicks() + } + gp := sg.g + gp.param = unsafe.Pointer(sg) + sg.success = false + if raceenabled { + raceacquireg(gp, c.raceaddr()) + } + glist.push(gp) + } + unlock(&c.lock) + + // Ready all Gs now that we've dropped the channel lock. + for !glist.empty() { + gp := glist.pop() + gp.schedlink = 0 + goready(gp, 3) + } +} + +// empty reports whether a read from c would block (that is, the channel is +// empty). It is atomically correct and sequentially consistent at the moment +// it returns, but since the channel is unlocked, the channel may become +// non-empty immediately afterward. +func empty(c *hchan) bool { + // c.dataqsiz is immutable. + if c.dataqsiz == 0 { + return atomic.Loadp(unsafe.Pointer(&c.sendq.first)) == nil + } + // c.timer is also immutable (it is set after make(chan) but before any channel operations). + // All timer channels have dataqsiz > 0. + if c.timer != nil { + c.timer.maybeRunChan() + } + return atomic.Loaduint(&c.qcount) == 0 +} + +// entry points for <- c from compiled code. +// +//go:nosplit +func chanrecv1(c *hchan, elem unsafe.Pointer) { + chanrecv(c, elem, true) +} + +//go:nosplit +func chanrecv2(c *hchan, elem unsafe.Pointer) (received bool) { + _, received = chanrecv(c, elem, true) + return +} + +// chanrecv receives on channel c and writes the received data to ep. +// ep may be nil, in which case received data is ignored. +// If block == false and no elements are available, returns (false, false). +// Otherwise, if c is closed, zeros *ep and returns (true, false). +// Otherwise, fills in *ep with an element and returns (true, true). +// A non-nil ep must point to the heap or the caller's stack. +func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) { + // raceenabled: don't need to check ep, as it is always on the stack + // or is new memory allocated by reflect. + + if debugChan { + print("chanrecv: chan=", c, "\n") + } + + if c == nil { + if !block { + return + } + gopark(nil, nil, waitReasonChanReceiveNilChan, traceBlockForever, 2) + throw("unreachable") + } + + if c.timer != nil { + c.timer.maybeRunChan() + } + + // Fast path: check for failed non-blocking operation without acquiring the lock. + if !block && empty(c) { + // After observing that the channel is not ready for receiving, we observe whether the + // channel is closed. + // + // Reordering of these checks could lead to incorrect behavior when racing with a close. + // For example, if the channel was open and not empty, was closed, and then drained, + // reordered reads could incorrectly indicate "open and empty". To prevent reordering, + // we use atomic loads for both checks, and rely on emptying and closing to happen in + // separate critical sections under the same lock. This assumption fails when closing + // an unbuffered channel with a blocked send, but that is an error condition anyway. + if atomic.Load(&c.closed) == 0 { + // Because a channel cannot be reopened, the later observation of the channel + // being not closed implies that it was also not closed at the moment of the + // first observation. We behave as if we observed the channel at that moment + // and report that the receive cannot proceed. + return + } + // The channel is irreversibly closed. Re-check whether the channel has any pending data + // to receive, which could have arrived between the empty and closed checks above. + // Sequential consistency is also required here, when racing with such a send. + if empty(c) { + // The channel is irreversibly closed and empty. + if raceenabled { + raceacquire(c.raceaddr()) + } + if ep != nil { + typedmemclr(c.elemtype, ep) + } + return true, false + } + } + + var t0 int64 + if blockprofilerate > 0 { + t0 = cputicks() + } + + lock(&c.lock) + + if c.closed != 0 { + if c.qcount == 0 { + if raceenabled { + raceacquire(c.raceaddr()) + } + unlock(&c.lock) + if ep != nil { + typedmemclr(c.elemtype, ep) + } + return true, false + } + // The channel has been closed, but the channel's buffer have data. + } else { + // Just found waiting sender with not closed. + if sg := c.sendq.dequeue(); sg != nil { + // Found a waiting sender. If buffer is size 0, receive value + // directly from sender. Otherwise, receive from head of queue + // and add sender's value to the tail of the queue (both map to + // the same buffer slot because the queue is full). + recv(c, sg, ep, func() { unlock(&c.lock) }, 3) + return true, true + } + } + + if c.qcount > 0 { + // Receive directly from queue + qp := chanbuf(c, c.recvx) + if raceenabled { + racenotify(c, c.recvx, nil) + } + if ep != nil { + typedmemmove(c.elemtype, ep, qp) + } + typedmemclr(c.elemtype, qp) + c.recvx++ + if c.recvx == c.dataqsiz { + c.recvx = 0 + } + c.qcount-- + unlock(&c.lock) + return true, true + } + + if !block { + unlock(&c.lock) + return false, false + } + + // no sender available: block on this channel. + gp := getg() + mysg := acquireSudog() + mysg.releasetime = 0 + if t0 != 0 { + mysg.releasetime = -1 + } + // No stack splits between assigning elem and enqueuing mysg + // on gp.waiting where copystack can find it. + mysg.elem = ep + mysg.waitlink = nil + gp.waiting = mysg + + mysg.g = gp + mysg.isSelect = false + mysg.c = c + gp.param = nil + c.recvq.enqueue(mysg) + if c.timer != nil { + blockTimerChan(c) + } + + // Signal to anyone trying to shrink our stack that we're about + // to park on a channel. The window between when this G's status + // changes and when we set gp.activeStackChans is not safe for + // stack shrinking. + gp.parkingOnChan.Store(true) + gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanReceive, traceBlockChanRecv, 2) + + // someone woke us up + if mysg != gp.waiting { + throw("G waiting list is corrupted") + } + if c.timer != nil { + unblockTimerChan(c) + } + gp.waiting = nil + gp.activeStackChans = false + if mysg.releasetime > 0 { + blockevent(mysg.releasetime-t0, 2) + } + success := mysg.success + gp.param = nil + mysg.c = nil + releaseSudog(mysg) + return true, success +} + +// recv processes a receive operation on a full channel c. +// There are 2 parts: +// 1. The value sent by the sender sg is put into the channel +// and the sender is woken up to go on its merry way. +// 2. The value received by the receiver (the current G) is +// written to ep. +// +// For synchronous channels, both values are the same. +// For asynchronous channels, the receiver gets its data from +// the channel buffer and the sender's data is put in the +// channel buffer. +// Channel c must be full and locked. recv unlocks c with unlockf. +// sg must already be dequeued from c. +// A non-nil ep must point to the heap or the caller's stack. +func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) { + if c.dataqsiz == 0 { + if raceenabled { + racesync(c, sg) + } + if ep != nil { + // copy data from sender + recvDirect(c.elemtype, sg, ep) + } + } else { + // Queue is full. Take the item at the + // head of the queue. Make the sender enqueue + // its item at the tail of the queue. Since the + // queue is full, those are both the same slot. + qp := chanbuf(c, c.recvx) + if raceenabled { + racenotify(c, c.recvx, nil) + racenotify(c, c.recvx, sg) + } + // copy data from queue to receiver + if ep != nil { + typedmemmove(c.elemtype, ep, qp) + } + // copy data from sender to queue + typedmemmove(c.elemtype, qp, sg.elem) + c.recvx++ + if c.recvx == c.dataqsiz { + c.recvx = 0 + } + c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz + } + sg.elem = nil + gp := sg.g + unlockf() + gp.param = unsafe.Pointer(sg) + sg.success = true + if sg.releasetime != 0 { + sg.releasetime = cputicks() + } + goready(gp, skip+1) +} + +func chanparkcommit(gp *g, chanLock unsafe.Pointer) bool { + // There are unlocked sudogs that point into gp's stack. Stack + // copying must lock the channels of those sudogs. + // Set activeStackChans here instead of before we try parking + // because we could self-deadlock in stack growth on the + // channel lock. + gp.activeStackChans = true + // Mark that it's safe for stack shrinking to occur now, + // because any thread acquiring this G's stack for shrinking + // is guaranteed to observe activeStackChans after this store. + gp.parkingOnChan.Store(false) + // Make sure we unlock after setting activeStackChans and + // unsetting parkingOnChan. The moment we unlock chanLock + // we risk gp getting readied by a channel operation and + // so gp could continue running before everything before + // the unlock is visible (even to gp itself). + unlock((*mutex)(chanLock)) + return true +} + +// compiler implements +// +// select { +// case c <- v: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if selectnbsend(c, v) { +// ... foo +// } else { +// ... bar +// } +func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) { + return chansend(c, elem, false, getcallerpc()) +} + +// compiler implements +// +// select { +// case v, ok = <-c: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if selected, ok = selectnbrecv(&v, c); selected { +// ... foo +// } else { +// ... bar +// } +func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected, received bool) { + return chanrecv(c, elem, false) +} + +//go:linkname reflect_chansend reflect.chansend0 +func reflect_chansend(c *hchan, elem unsafe.Pointer, nb bool) (selected bool) { + return chansend(c, elem, !nb, getcallerpc()) +} + +//go:linkname reflect_chanrecv reflect.chanrecv +func reflect_chanrecv(c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) { + return chanrecv(c, elem, !nb) +} + +func chanlen(c *hchan) int { + if c == nil { + return 0 + } + async := debug.asynctimerchan.Load() != 0 + if c.timer != nil && async { + c.timer.maybeRunChan() + } + if c.timer != nil && !async { + // timer channels have a buffered implementation + // but present to users as unbuffered, so that we can + // undo sends without users noticing. + return 0 + } + return int(c.qcount) +} + +func chancap(c *hchan) int { + if c == nil { + return 0 + } + if c.timer != nil { + async := debug.asynctimerchan.Load() != 0 + if async { + return int(c.dataqsiz) + } + // timer channels have a buffered implementation + // but present to users as unbuffered, so that we can + // undo sends without users noticing. + return 0 + } + return int(c.dataqsiz) +} + +//go:linkname reflect_chanlen reflect.chanlen +func reflect_chanlen(c *hchan) int { + return chanlen(c) +} + +//go:linkname reflectlite_chanlen internal/reflectlite.chanlen +func reflectlite_chanlen(c *hchan) int { + return chanlen(c) +} + +//go:linkname reflect_chancap reflect.chancap +func reflect_chancap(c *hchan) int { + return chancap(c) +} + +//go:linkname reflect_chanclose reflect.chanclose +func reflect_chanclose(c *hchan) { + closechan(c) +} + +func (q *waitq) enqueue(sgp *sudog) { + sgp.next = nil + x := q.last + if x == nil { + sgp.prev = nil + q.first = sgp + q.last = sgp + return + } + sgp.prev = x + x.next = sgp + q.last = sgp +} + +func (q *waitq) dequeue() *sudog { + for { + sgp := q.first + if sgp == nil { + return nil + } + y := sgp.next + if y == nil { + q.first = nil + q.last = nil + } else { + y.prev = nil + q.first = y + sgp.next = nil // mark as removed (see dequeueSudoG) + } + + // if a goroutine was put on this queue because of a + // select, there is a small window between the goroutine + // being woken up by a different case and it grabbing the + // channel locks. Once it has the lock + // it removes itself from the queue, so we won't see it after that. + // We use a flag in the G struct to tell us when someone + // else has won the race to signal this goroutine but the goroutine + // hasn't removed itself from the queue yet. + if sgp.isSelect && !sgp.g.selectDone.CompareAndSwap(0, 1) { + continue + } + + return sgp + } +} + +func (c *hchan) raceaddr() unsafe.Pointer { + // Treat read-like and write-like operations on the channel to + // happen at this address. Avoid using the address of qcount + // or dataqsiz, because the len() and cap() builtins read + // those addresses, and we don't want them racing with + // operations like close(). + return unsafe.Pointer(&c.buf) +} + +func racesync(c *hchan, sg *sudog) { + racerelease(chanbuf(c, 0)) + raceacquireg(sg.g, chanbuf(c, 0)) + racereleaseg(sg.g, chanbuf(c, 0)) + raceacquire(chanbuf(c, 0)) +} + +// Notify the race detector of a send or receive involving buffer entry idx +// and a channel c or its communicating partner sg. +// This function handles the special case of c.elemsize==0. +func racenotify(c *hchan, idx uint, sg *sudog) { + // We could have passed the unsafe.Pointer corresponding to entry idx + // instead of idx itself. However, in a future version of this function, + // we can use idx to better handle the case of elemsize==0. + // A future improvement to the detector is to call TSan with c and idx: + // this way, Go will continue to not allocating buffer entries for channels + // of elemsize==0, yet the race detector can be made to handle multiple + // sync objects underneath the hood (one sync object per idx) + qp := chanbuf(c, idx) + // When elemsize==0, we don't allocate a full buffer for the channel. + // Instead of individual buffer entries, the race detector uses the + // c.buf as the only buffer entry. This simplification prevents us from + // following the memory model's happens-before rules (rules that are + // implemented in racereleaseacquire). Instead, we accumulate happens-before + // information in the synchronization object associated with c.buf. + if c.elemsize == 0 { + if sg == nil { + raceacquire(qp) + racerelease(qp) + } else { + raceacquireg(sg.g, qp) + racereleaseg(sg.g, qp) + } + } else { + if sg == nil { + racereleaseacquire(qp) + } else { + racereleaseacquireg(sg.g, qp) + } + } +} diff --git a/contrib/go/_std_1.22/src/runtime/checkptr.go b/contrib/go/_std_1.23/src/runtime/checkptr.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/checkptr.go rename to contrib/go/_std_1.23/src/runtime/checkptr.go index 3c49645a446f..be64ae7f0cb8 100644 --- a/contrib/go/_std_1.22/src/runtime/checkptr.go +++ b/contrib/go/_std_1.23/src/runtime/checkptr.go @@ -16,7 +16,7 @@ func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) { // Note that we allow unaligned pointers if the types they point to contain // no pointers themselves. See issue 37298. // TODO(mdempsky): What about fieldAlign? - if elem.PtrBytes != 0 && uintptr(p)&(uintptr(elem.Align_)-1) != 0 { + if elem.Pointers() && uintptr(p)&(uintptr(elem.Align_)-1) != 0 { throw("checkptr: misaligned pointer conversion") } @@ -76,6 +76,16 @@ func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) { // checkptrBase(p1) == checkptrBase(p2). However, the converse/inverse // is not necessarily true as allocations can have trailing padding, // and multiple variables may be packed into a single allocation. +// +// checkptrBase should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname checkptrBase func checkptrBase(p unsafe.Pointer) uintptr { // stack if gp := getg(); gp.stack.lo <= uintptr(p) && uintptr(p) < gp.stack.hi { diff --git a/contrib/go/_std_1.22/src/runtime/compiler.go b/contrib/go/_std_1.23/src/runtime/compiler.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/compiler.go rename to contrib/go/_std_1.23/src/runtime/compiler.go diff --git a/contrib/go/_std_1.22/src/runtime/complex.go b/contrib/go/_std_1.23/src/runtime/complex.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/complex.go rename to contrib/go/_std_1.23/src/runtime/complex.go diff --git a/contrib/go/_std_1.23/src/runtime/coro.go b/contrib/go/_std_1.23/src/runtime/coro.go new file mode 100644 index 000000000000..d93817f92f1c --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/coro.go @@ -0,0 +1,243 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +// A coro represents extra concurrency without extra parallelism, +// as would be needed for a coroutine implementation. +// The coro does not represent a specific coroutine, only the ability +// to do coroutine-style control transfers. +// It can be thought of as like a special channel that always has +// a goroutine blocked on it. If another goroutine calls coroswitch(c), +// the caller becomes the goroutine blocked in c, and the goroutine +// formerly blocked in c starts running. +// These switches continue until a call to coroexit(c), +// which ends the use of the coro by releasing the blocked +// goroutine in c and exiting the current goroutine. +// +// Coros are heap allocated and garbage collected, so that user code +// can hold a pointer to a coro without causing potential dangling +// pointer errors. +type coro struct { + gp guintptr + f func(*coro) + + // State for validating thread-lock interactions. + mp *m + lockedExt uint32 // mp's external LockOSThread counter at coro creation time. + lockedInt uint32 // mp's internal lockOSThread counter at coro creation time. +} + +//go:linkname newcoro + +// newcoro creates a new coro containing a +// goroutine blocked waiting to run f +// and returns that coro. +func newcoro(f func(*coro)) *coro { + c := new(coro) + c.f = f + pc := getcallerpc() + gp := getg() + systemstack(func() { + mp := gp.m + start := corostart + startfv := *(**funcval)(unsafe.Pointer(&start)) + gp = newproc1(startfv, gp, pc, true, waitReasonCoroutine) + + // Scribble down locked thread state if needed and/or donate + // thread-lock state to the new goroutine. + if mp.lockedExt+mp.lockedInt != 0 { + c.mp = mp + c.lockedExt = mp.lockedExt + c.lockedInt = mp.lockedInt + } + }) + gp.coroarg = c + c.gp.set(gp) + return c +} + +// corostart is the entry func for a new coroutine. +// It runs the coroutine user function f passed to corostart +// and then calls coroexit to remove the extra concurrency. +func corostart() { + gp := getg() + c := gp.coroarg + gp.coroarg = nil + + defer coroexit(c) + c.f(c) +} + +// coroexit is like coroswitch but closes the coro +// and exits the current goroutine +func coroexit(c *coro) { + gp := getg() + gp.coroarg = c + gp.coroexit = true + mcall(coroswitch_m) +} + +//go:linkname coroswitch + +// coroswitch switches to the goroutine blocked on c +// and then blocks the current goroutine on c. +func coroswitch(c *coro) { + gp := getg() + gp.coroarg = c + mcall(coroswitch_m) +} + +// coroswitch_m is the implementation of coroswitch +// that runs on the m stack. +// +// Note: Coroutine switches are expected to happen at +// an order of magnitude (or more) higher frequency +// than regular goroutine switches, so this path is heavily +// optimized to remove unnecessary work. +// The fast path here is three CAS: the one at the top on gp.atomicstatus, +// the one in the middle to choose the next g, +// and the one at the bottom on gnext.atomicstatus. +// It is important not to add more atomic operations or other +// expensive operations to the fast path. +func coroswitch_m(gp *g) { + c := gp.coroarg + gp.coroarg = nil + exit := gp.coroexit + gp.coroexit = false + mp := gp.m + + // Track and validate thread-lock interactions. + // + // The rules with thread-lock interactions are simple. When a coro goroutine is switched to, + // the same thread must be used, and the locked state must match with the thread-lock state of + // the goroutine which called newcoro. Thread-lock state consists of the thread and the number + // of internal (cgo callback, etc.) and external (LockOSThread) thread locks. + locked := gp.lockedm != 0 + if c.mp != nil || locked { + if mp != c.mp || mp.lockedInt != c.lockedInt || mp.lockedExt != c.lockedExt { + print("coro: got thread ", unsafe.Pointer(mp), ", want ", unsafe.Pointer(c.mp), "\n") + print("coro: got lock internal ", mp.lockedInt, ", want ", c.lockedInt, "\n") + print("coro: got lock external ", mp.lockedExt, ", want ", c.lockedExt, "\n") + throw("coro: OS thread locking must match locking at coroutine creation") + } + } + + // Acquire tracer for writing for the duration of this call. + // + // There's a lot of state manipulation performed with shortcuts + // but we need to make sure the tracer can only observe the + // start and end states to maintain a coherent model and avoid + // emitting an event for every single transition. + trace := traceAcquire() + + if locked { + // Detach the goroutine from the thread; we'll attach to the goroutine we're + // switching to before returning. + gp.lockedm.set(nil) + } + + if exit { + // The M might have a non-zero OS thread lock count when we get here, gdestroy + // will avoid destroying the M if the G isn't explicitly locked to it via lockedm, + // which we cleared above. It's fine to gdestroy here also, even when locked to + // the thread, because we'll be switching back to another goroutine anyway, which + // will take back its thread-lock state before returning. + gdestroy(gp) + gp = nil + } else { + // If we can CAS ourselves directly from running to waiting, so do, + // keeping the control transfer as lightweight as possible. + gp.waitreason = waitReasonCoroutine + if !gp.atomicstatus.CompareAndSwap(_Grunning, _Gwaiting) { + // The CAS failed: use casgstatus, which will take care of + // coordinating with the garbage collector about the state change. + casgstatus(gp, _Grunning, _Gwaiting) + } + + // Clear gp.m. + setMNoWB(&gp.m, nil) + } + + // The goroutine stored in c is the one to run next. + // Swap it with ourselves. + var gnext *g + for { + // Note: this is a racy load, but it will eventually + // get the right value, and if it gets the wrong value, + // the c.gp.cas will fail, so no harm done other than + // a wasted loop iteration. + // The cas will also sync c.gp's + // memory enough that the next iteration of the racy load + // should see the correct value. + // We are avoiding the atomic load to keep this path + // as lightweight as absolutely possible. + // (The atomic load is free on x86 but not free elsewhere.) + next := c.gp + if next.ptr() == nil { + throw("coroswitch on exited coro") + } + var self guintptr + self.set(gp) + if c.gp.cas(next, self) { + gnext = next.ptr() + break + } + } + + // Check if we're switching to ourselves. This case is able to break our + // thread-lock invariants and an unbuffered channel implementation of + // coroswitch would deadlock. It's clear that this case should just not + // work. + if gnext == gp { + throw("coroswitch of a goroutine to itself") + } + + // Emit the trace event after getting gnext but before changing curg. + // GoSwitch expects that the current G is running and that we haven't + // switched yet for correct status emission. + if trace.ok() { + trace.GoSwitch(gnext, exit) + } + + // Start running next, without heavy scheduling machinery. + // Set mp.curg and gnext.m and then update scheduling state + // directly if possible. + setGNoWB(&mp.curg, gnext) + setMNoWB(&gnext.m, mp) + + // Synchronize with any out-standing goroutine profile. We're about to start + // executing, and an invariant of the profiler is that we tryRecordGoroutineProfile + // whenever a goroutine is about to start running. + // + // N.B. We must do this before transitioning to _Grunning but after installing gnext + // in curg, so that we have a valid curg for allocation (tryRecordGoroutineProfile + // may allocate). + if goroutineProfile.active { + tryRecordGoroutineProfile(gnext, nil, osyield) + } + + if !gnext.atomicstatus.CompareAndSwap(_Gwaiting, _Grunning) { + // The CAS failed: use casgstatus, which will take care of + // coordinating with the garbage collector about the state change. + casgstatus(gnext, _Gwaiting, _Grunnable) + casgstatus(gnext, _Grunnable, _Grunning) + } + + // Donate locked state. + if locked { + mp.lockedg.set(gnext) + gnext.lockedm.set(mp) + } + + // Release the trace locker. We've completed all the necessary transitions.. + if trace.ok() { + traceRelease(trace) + } + + // Switch to gnext. Does not return. + gogo(&gnext.sched) +} diff --git a/contrib/go/_std_1.23/src/runtime/coverage/coverage.go b/contrib/go/_std_1.23/src/runtime/coverage/coverage.go new file mode 100644 index 000000000000..6b99a0bce6e6 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/coverage/coverage.go @@ -0,0 +1,66 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package coverage + +import ( + "internal/coverage/cfile" + "io" +) + +// initHook is invoked from main.init in programs built with -cover. +// The call is emitted by the compiler. +func initHook(istest bool) { + cfile.InitHook(istest) +} + +// WriteMetaDir writes a coverage meta-data file for the currently +// running program to the directory specified in 'dir'. An error will +// be returned if the operation can't be completed successfully (for +// example, if the currently running program was not built with +// "-cover", or if the directory does not exist). +func WriteMetaDir(dir string) error { + return cfile.WriteMetaDir(dir) +} + +// WriteMeta writes the meta-data content (the payload that would +// normally be emitted to a meta-data file) for the currently running +// program to the writer 'w'. An error will be returned if the +// operation can't be completed successfully (for example, if the +// currently running program was not built with "-cover", or if a +// write fails). +func WriteMeta(w io.Writer) error { + return cfile.WriteMeta(w) +} + +// WriteCountersDir writes a coverage counter-data file for the +// currently running program to the directory specified in 'dir'. An +// error will be returned if the operation can't be completed +// successfully (for example, if the currently running program was not +// built with "-cover", or if the directory does not exist). The +// counter data written will be a snapshot taken at the point of the +// call. +func WriteCountersDir(dir string) error { + return cfile.WriteCountersDir(dir) +} + +// WriteCounters writes coverage counter-data content for the +// currently running program to the writer 'w'. An error will be +// returned if the operation can't be completed successfully (for +// example, if the currently running program was not built with +// "-cover", or if a write fails). The counter data written will be a +// snapshot taken at the point of the invocation. +func WriteCounters(w io.Writer) error { + return cfile.WriteCounters(w) +} + +// ClearCounters clears/resets all coverage counter variables in the +// currently running program. It returns an error if the program in +// question was not built with the "-cover" flag. Clearing of coverage +// counters is also not supported for programs not using atomic +// counter mode (see more detailed comments below for the rationale +// here). +func ClearCounters() error { + return cfile.ClearCounters() +} diff --git a/contrib/go/_std_1.23/src/runtime/coverage/ya.make b/contrib/go/_std_1.23/src/runtime/coverage/ya.make new file mode 100644 index 000000000000..abbf058eef1e --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/coverage/ya.make @@ -0,0 +1,9 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (TRUE) + SRCS( + coverage.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/covercounter.go b/contrib/go/_std_1.23/src/runtime/covercounter.go similarity index 79% rename from contrib/go/_std_1.22/src/runtime/covercounter.go rename to contrib/go/_std_1.23/src/runtime/covercounter.go index 72842bdd94c8..6dbc882d16e7 100644 --- a/contrib/go/_std_1.22/src/runtime/covercounter.go +++ b/contrib/go/_std_1.23/src/runtime/covercounter.go @@ -9,8 +9,8 @@ import ( "unsafe" ) -//go:linkname runtime_coverage_getCovCounterList runtime/coverage.getCovCounterList -func runtime_coverage_getCovCounterList() []rtcov.CovCounterBlob { +//go:linkname coverage_getCovCounterList internal/coverage/cfile.getCovCounterList +func coverage_getCovCounterList() []rtcov.CovCounterBlob { res := []rtcov.CovCounterBlob{} u32sz := unsafe.Sizeof(uint32(0)) for datap := &firstmoduledata; datap != nil; datap = datap.next { diff --git a/contrib/go/_std_1.23/src/runtime/covermeta.go b/contrib/go/_std_1.23/src/runtime/covermeta.go new file mode 100644 index 000000000000..57a6b29e9154 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/covermeta.go @@ -0,0 +1,20 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/coverage/rtcov" + "unsafe" +) + +// The compiler emits calls to runtime.addCovMeta +// but this code has moved to rtcov.AddMeta. +func addCovMeta(p unsafe.Pointer, dlen uint32, hash [16]byte, pkgpath string, pkgid int, cmode uint8, cgran uint8) uint32 { + id := rtcov.AddMeta(p, dlen, hash, pkgpath, pkgid, cmode, cgran) + if id == 0 { + throw("runtime.addCovMeta: coverage package map collision") + } + return id +} diff --git a/contrib/go/_std_1.22/src/runtime/cpuflags.go b/contrib/go/_std_1.23/src/runtime/cpuflags.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cpuflags.go rename to contrib/go/_std_1.23/src/runtime/cpuflags.go diff --git a/contrib/go/_std_1.22/src/runtime/cpuflags_amd64.go b/contrib/go/_std_1.23/src/runtime/cpuflags_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cpuflags_amd64.go rename to contrib/go/_std_1.23/src/runtime/cpuflags_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/cpuflags_arm64.go b/contrib/go/_std_1.23/src/runtime/cpuflags_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cpuflags_arm64.go rename to contrib/go/_std_1.23/src/runtime/cpuflags_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/cpuprof.go b/contrib/go/_std_1.23/src/runtime/cpuprof.go similarity index 91% rename from contrib/go/_std_1.22/src/runtime/cpuprof.go rename to contrib/go/_std_1.23/src/runtime/cpuprof.go index b2898ba9094e..100a78258a2c 100644 --- a/contrib/go/_std_1.22/src/runtime/cpuprof.go +++ b/contrib/go/_std_1.23/src/runtime/cpuprof.go @@ -209,8 +209,17 @@ func CPUProfile() []byte { panic("CPUProfile no longer available") } -//go:linkname runtime_pprof_runtime_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond -func runtime_pprof_runtime_cyclesPerSecond() int64 { +// runtime/pprof.runtime_cyclesPerSecond should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/grafana/pyroscope-go/godeltaprof +// - github.com/pyroscope-io/godeltaprof +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname pprof_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond +func pprof_cyclesPerSecond() int64 { return ticksPerSecond() } @@ -222,6 +231,14 @@ func runtime_pprof_runtime_cyclesPerSecond() int64 { // The returned data contains a whole number of records, and tags contains // exactly one entry per record. // +// runtime_pprof_readProfile should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/pyroscope-io/pyroscope +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname runtime_pprof_readProfile runtime/pprof.readProfile func runtime_pprof_readProfile() ([]uint64, []unsafe.Pointer, bool) { lock(&cpuprof.lock) diff --git a/contrib/go/_std_1.22/src/runtime/cputicks.go b/contrib/go/_std_1.23/src/runtime/cputicks.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cputicks.go rename to contrib/go/_std_1.23/src/runtime/cputicks.go diff --git a/contrib/go/_std_1.22/src/runtime/create_file_nounix.go b/contrib/go/_std_1.23/src/runtime/create_file_nounix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/create_file_nounix.go rename to contrib/go/_std_1.23/src/runtime/create_file_nounix.go diff --git a/contrib/go/_std_1.22/src/runtime/create_file_unix.go b/contrib/go/_std_1.23/src/runtime/create_file_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/create_file_unix.go rename to contrib/go/_std_1.23/src/runtime/create_file_unix.go diff --git a/contrib/go/_std_1.23/src/runtime/debug.go b/contrib/go/_std_1.23/src/runtime/debug.go new file mode 100644 index 000000000000..c477e2b9f6e4 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/debug.go @@ -0,0 +1,145 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/runtime/atomic" + "unsafe" +) + +// GOMAXPROCS sets the maximum number of CPUs that can be executing +// simultaneously and returns the previous setting. It defaults to +// the value of [runtime.NumCPU]. If n < 1, it does not change the current setting. +// This call will go away when the scheduler improves. +func GOMAXPROCS(n int) int { + if GOARCH == "wasm" && n > 1 { + n = 1 // WebAssembly has no threads yet, so only one CPU is possible. + } + + lock(&sched.lock) + ret := int(gomaxprocs) + unlock(&sched.lock) + if n <= 0 || n == ret { + return ret + } + + stw := stopTheWorldGC(stwGOMAXPROCS) + + // newprocs will be processed by startTheWorld + newprocs = int32(n) + + startTheWorldGC(stw) + return ret +} + +// NumCPU returns the number of logical CPUs usable by the current process. +// +// The set of available CPUs is checked by querying the operating system +// at process startup. Changes to operating system CPU allocation after +// process startup are not reflected. +func NumCPU() int { + return int(ncpu) +} + +// NumCgoCall returns the number of cgo calls made by the current process. +func NumCgoCall() int64 { + var n = int64(atomic.Load64(&ncgocall)) + for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { + n += int64(mp.ncgocall) + } + return n +} + +func totalMutexWaitTimeNanos() int64 { + total := sched.totalMutexWaitTime.Load() + + total += sched.totalRuntimeLockWaitTime.Load() + for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { + total += mp.mLockProfile.waitTime.Load() + } + + return total +} + +// NumGoroutine returns the number of goroutines that currently exist. +func NumGoroutine() int { + return int(gcount()) +} + +//go:linkname debug_modinfo runtime/debug.modinfo +func debug_modinfo() string { + return modinfo +} + +// mayMoreStackPreempt is a maymorestack hook that forces a preemption +// at every possible cooperative preemption point. +// +// This is valuable to apply to the runtime, which can be sensitive to +// preemption points. To apply this to all preemption points in the +// runtime and runtime-like code, use the following in bash or zsh: +// +// X=(-{gc,asm}flags={runtime/...,reflect,sync}=-d=maymorestack=runtime.mayMoreStackPreempt) GOFLAGS=${X[@]} +// +// This must be deeply nosplit because it is called from a function +// prologue before the stack is set up and because the compiler will +// call it from any splittable prologue (leading to infinite +// recursion). +// +// Ideally it should also use very little stack because the linker +// doesn't currently account for this in nosplit stack depth checking. +// +// Ensure mayMoreStackPreempt can be called for all ABIs. +// +//go:nosplit +//go:linkname mayMoreStackPreempt +func mayMoreStackPreempt() { + // Don't do anything on the g0 or gsignal stack. + gp := getg() + if gp == gp.m.g0 || gp == gp.m.gsignal { + return + } + // Force a preemption, unless the stack is already poisoned. + if gp.stackguard0 < stackPoisonMin { + gp.stackguard0 = stackPreempt + } +} + +// mayMoreStackMove is a maymorestack hook that forces stack movement +// at every possible point. +// +// See mayMoreStackPreempt. +// +//go:nosplit +//go:linkname mayMoreStackMove +func mayMoreStackMove() { + // Don't do anything on the g0 or gsignal stack. + gp := getg() + if gp == gp.m.g0 || gp == gp.m.gsignal { + return + } + // Force stack movement, unless the stack is already poisoned. + if gp.stackguard0 < stackPoisonMin { + gp.stackguard0 = stackForceMove + } +} + +// debugPinnerKeepUnpin is used to make runtime.(*Pinner).Unpin reachable. +var debugPinnerKeepUnpin bool = false + +// debugPinnerV1 returns a new Pinner that pins itself. This function can be +// used by debuggers to easily obtain a Pinner that will not be garbage +// collected (or moved in memory) even if no references to it exist in the +// target program. This pinner in turn can be used to extend this property +// to other objects, which debuggers can use to simplify the evaluation of +// expressions involving multiple call injections. +func debugPinnerV1() *Pinner { + p := new(Pinner) + p.Pin(unsafe.Pointer(p)) + if debugPinnerKeepUnpin { + // Make Unpin reachable. + p.Unpin() + } + return p +} diff --git a/contrib/go/_std_1.22/src/runtime/debug/debug.s b/contrib/go/_std_1.23/src/runtime/debug/debug.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debug/debug.s rename to contrib/go/_std_1.23/src/runtime/debug/debug.s diff --git a/contrib/go/_std_1.22/src/runtime/debug/garbage.go b/contrib/go/_std_1.23/src/runtime/debug/garbage.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/debug/garbage.go rename to contrib/go/_std_1.23/src/runtime/debug/garbage.go index cb3248d64d4a..ec74ba0165a0 100644 --- a/contrib/go/_std_1.22/src/runtime/debug/garbage.go +++ b/contrib/go/_std_1.23/src/runtime/debug/garbage.go @@ -6,7 +6,7 @@ package debug import ( "runtime" - "sort" + "slices" "time" ) @@ -63,15 +63,13 @@ func ReadGCStats(stats *GCStats) { if len(stats.PauseQuantiles) > 0 { if n == 0 { - for i := range stats.PauseQuantiles { - stats.PauseQuantiles[i] = 0 - } + clear(stats.PauseQuantiles) } else { // There's room for a second copy of the data in stats.Pause. // See the allocation at the top of the function. sorted := stats.Pause[n : n+n] copy(sorted, stats.Pause) - sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] }) + slices.Sort(sorted) nq := len(stats.PauseQuantiles) - 1 for i := 0; i < nq; i++ { stats.PauseQuantiles[i] = sorted[len(sorted)*i/nq] diff --git a/contrib/go/_std_1.22/src/runtime/debug/mod.go b/contrib/go/_std_1.23/src/runtime/debug/mod.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debug/mod.go rename to contrib/go/_std_1.23/src/runtime/debug/mod.go diff --git a/contrib/go/_std_1.23/src/runtime/debug/stack.go b/contrib/go/_std_1.23/src/runtime/debug/stack.go new file mode 100644 index 000000000000..d7a860b7dc94 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/debug/stack.go @@ -0,0 +1,93 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package debug contains facilities for programs to debug themselves while +// they are running. +package debug + +import ( + "internal/poll" + "os" + "runtime" + _ "unsafe" // for linkname +) + +// PrintStack prints to standard error the stack trace returned by runtime.Stack. +func PrintStack() { + os.Stderr.Write(Stack()) +} + +// Stack returns a formatted stack trace of the goroutine that calls it. +// It calls [runtime.Stack] with a large enough buffer to capture the entire trace. +func Stack() []byte { + buf := make([]byte, 1024) + for { + n := runtime.Stack(buf, false) + if n < len(buf) { + return buf[:n] + } + buf = make([]byte, 2*len(buf)) + } +} + +// CrashOptions provides options that control the formatting of the +// fatal crash message. +type CrashOptions struct { + /* for future expansion */ +} + +// SetCrashOutput configures a single additional file where unhandled +// panics and other fatal errors are printed, in addition to standard error. +// There is only one additional file: calling SetCrashOutput again overrides +// any earlier call. +// SetCrashOutput duplicates f's file descriptor, so the caller may safely +// close f as soon as SetCrashOutput returns. +// To disable this additional crash output, call SetCrashOutput(nil). +// If called concurrently with a crash, some in-progress output may be written +// to the old file even after an overriding SetCrashOutput returns. +func SetCrashOutput(f *os.File, opts CrashOptions) error { + fd := ^uintptr(0) + if f != nil { + // The runtime will write to this file descriptor from + // low-level routines during a panic, possibly without + // a G, so we must call f.Fd() eagerly. This creates a + // danger that that the file descriptor is no longer + // valid at the time of the write, because the caller + // (incorrectly) called f.Close() and the kernel + // reissued the fd in a later call to open(2), leading + // to crashes being written to the wrong file. + // + // So, we duplicate the fd to obtain a private one + // that cannot be closed by the user. + // This also alleviates us from concerns about the + // lifetime and finalization of f. + // (DupCloseOnExec returns an fd, not a *File, so + // there is no finalizer, and we are responsible for + // closing it.) + // + // The new fd must be close-on-exec, otherwise if the + // crash monitor is a child process, it may inherit + // it, so it will never see EOF from the pipe even + // when this process crashes. + // + // A side effect of Fd() is that it calls SetBlocking, + // which is important so that writes of a crash report + // to a full pipe buffer don't get lost. + fd2, _, err := poll.DupCloseOnExec(int(f.Fd())) + if err != nil { + return err + } + runtime.KeepAlive(f) // prevent finalization before dup + fd = uintptr(fd2) + } + if prev := runtime_setCrashFD(fd); prev != ^uintptr(0) { + // We use NewFile+Close because it is portable + // unlike syscall.Close, whose parameter type varies. + os.NewFile(prev, "").Close() // ignore error + } + return nil +} + +//go:linkname runtime_setCrashFD runtime.setCrashFD +func runtime_setCrashFD(uintptr) uintptr diff --git a/contrib/go/_std_1.22/src/runtime/debug/stubs.go b/contrib/go/_std_1.23/src/runtime/debug/stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debug/stubs.go rename to contrib/go/_std_1.23/src/runtime/debug/stubs.go diff --git a/contrib/go/_std_1.22/src/runtime/debug/ya.make b/contrib/go/_std_1.23/src/runtime/debug/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debug/ya.make rename to contrib/go/_std_1.23/src/runtime/debug/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/debugcall.go b/contrib/go/_std_1.23/src/runtime/debugcall.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/debugcall.go rename to contrib/go/_std_1.23/src/runtime/debugcall.go index 5dd83063ff9c..fee4116aa5e7 100644 --- a/contrib/go/_std_1.22/src/runtime/debugcall.go +++ b/contrib/go/_std_1.23/src/runtime/debugcall.go @@ -124,7 +124,7 @@ func debugCallWrap(dispatch uintptr) { // closure and start the goroutine with that closure, but the compiler disallows // implicit closure allocation in the runtime. fn := debugCallWrap1 - newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), gp, callerpc) + newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), gp, callerpc, false, waitReasonZero) args := &debugCallWrapArgs{ dispatch: dispatch, callingG: gp, @@ -167,9 +167,14 @@ func debugCallWrap(dispatch uintptr) { // Park the calling goroutine. trace := traceAcquire() - casGToWaiting(gp, _Grunning, waitReasonDebugCall) if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. trace.GoPark(traceBlockDebugCall, 1) + } + casGToWaiting(gp, _Grunning, waitReasonDebugCall) + if trace.ok() { traceRelease(trace) } dropg() @@ -228,9 +233,14 @@ func debugCallWrap1() { // the scheduler will schedule us again and we'll // finish exiting. trace := traceAcquire() - casgstatus(gp, _Grunning, _Grunnable) if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. trace.GoSched() + } + casgstatus(gp, _Grunning, _Grunnable) + if trace.ok() { traceRelease(trace) } dropg() diff --git a/contrib/go/_std_1.22/src/runtime/debuglog.go b/contrib/go/_std_1.23/src/runtime/debuglog.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/debuglog.go rename to contrib/go/_std_1.23/src/runtime/debuglog.go index 873f1b45bddc..695cd204f592 100644 --- a/contrib/go/_std_1.22/src/runtime/debuglog.go +++ b/contrib/go/_std_1.23/src/runtime/debuglog.go @@ -16,7 +16,8 @@ package runtime import ( - "runtime/internal/atomic" + "internal/abi" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -277,8 +278,8 @@ func (l *dlogger) p(x any) *dlogger { l.w.uvarint(0) } else { v := efaceOf(&x) - switch v._type.Kind_ & kindMask { - case kindChan, kindFunc, kindMap, kindPtr, kindUnsafePointer: + switch v._type.Kind_ & abi.KindMask { + case abi.Chan, abi.Func, abi.Map, abi.Pointer, abi.UnsafePointer: l.w.uvarint(uint64(uintptr(v.data))) default: throw("not a pointer type") diff --git a/contrib/go/_std_1.22/src/runtime/debuglog_off.go b/contrib/go/_std_1.23/src/runtime/debuglog_off.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debuglog_off.go rename to contrib/go/_std_1.23/src/runtime/debuglog_off.go diff --git a/contrib/go/_std_1.22/src/runtime/debuglog_on.go b/contrib/go/_std_1.23/src/runtime/debuglog_on.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debuglog_on.go rename to contrib/go/_std_1.23/src/runtime/debuglog_on.go diff --git a/contrib/go/_std_1.22/src/runtime/defs1_linux.go b/contrib/go/_std_1.23/src/runtime/defs1_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs1_linux.go rename to contrib/go/_std_1.23/src/runtime/defs1_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_386.go b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_386.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs1_netbsd_386.go rename to contrib/go/_std_1.23/src/runtime/defs1_netbsd_386.go index f7fe45b4ab64..16c55def9269 100644 --- a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_386.go +++ b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_386.go @@ -84,12 +84,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = 0x0 _EVFILT_WRITE = 0x1 + _EVFILT_USER = 0x8 + + _NOTE_TRIGGER = 0x1000000 ) type sigset struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_amd64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs1_netbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs1_netbsd_amd64.go index 80908cd93185..7a035a99c80b 100644 --- a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_amd64.go @@ -84,12 +84,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = 0x0 _EVFILT_WRITE = 0x1 + _EVFILT_USER = 0x8 + + _NOTE_TRIGGER = 0x1000000 ) type sigset struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm.go b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm.go index c63e592ff145..77a59d4a05bf 100644 --- a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm.go +++ b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm.go @@ -84,12 +84,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = 0x0 _EVFILT_WRITE = 0x1 + _EVFILT_USER = 0x8 + + _NOTE_TRIGGER = 0x1000000 ) type sigset struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm64.go index 804b5b0b3f67..0720461f26cb 100644 --- a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm64.go +++ b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm64.go @@ -84,12 +84,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = 0x0 _EVFILT_WRITE = 0x1 + _EVFILT_USER = 0x8 + + _NOTE_TRIGGER = 0x1000000 ) type sigset struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs1_solaris_amd64.go b/contrib/go/_std_1.23/src/runtime/defs1_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs1_solaris_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs1_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs2_linux.go b/contrib/go/_std_1.23/src/runtime/defs2_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs2_linux.go rename to contrib/go/_std_1.23/src/runtime/defs2_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs3_linux.go b/contrib/go/_std_1.23/src/runtime/defs3_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs3_linux.go rename to contrib/go/_std_1.23/src/runtime/defs3_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_aix.go b/contrib/go/_std_1.23/src/runtime/defs_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_aix.go rename to contrib/go/_std_1.23/src/runtime/defs_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_aix_ppc64.go b/contrib/go/_std_1.23/src/runtime/defs_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_aix_ppc64.go rename to contrib/go/_std_1.23/src/runtime/defs_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_arm_linux.go b/contrib/go/_std_1.23/src/runtime/defs_arm_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_arm_linux.go rename to contrib/go/_std_1.23/src/runtime/defs_arm_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_darwin.go b/contrib/go/_std_1.23/src/runtime/defs_darwin.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_darwin.go rename to contrib/go/_std_1.23/src/runtime/defs_darwin.go index e37443307f37..9de59be20ba8 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_darwin.go +++ b/contrib/go/_std_1.23/src/runtime/defs_darwin.go @@ -106,12 +106,17 @@ const ( EV_ADD = C.EV_ADD EV_DELETE = C.EV_DELETE + EV_ENABLE = C.EV_ENABLE + EV_DISABLE = C.EV_DISABLE EV_CLEAR = C.EV_CLEAR EV_RECEIPT = C.EV_RECEIPT EV_ERROR = C.EV_ERROR EV_EOF = C.EV_EOF EVFILT_READ = C.EVFILT_READ EVFILT_WRITE = C.EVFILT_WRITE + EVFILT_USER = C.EVFILT_USER + + NOTE_TRIGGER = C.NOTE_TRIGGER PTHREAD_CREATE_DETACHED = C.PTHREAD_CREATE_DETACHED diff --git a/contrib/go/_std_1.22/src/runtime/defs_darwin_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_darwin_amd64.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/defs_darwin_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_darwin_amd64.go index f998b0be9118..c0ca16d46309 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_darwin_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_darwin_amd64.go @@ -85,12 +85,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xa + + _NOTE_TRIGGER = 0x1000000 _PTHREAD_CREATE_DETACHED = 0x2 diff --git a/contrib/go/_std_1.22/src/runtime/defs_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_darwin_arm64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_darwin_arm64.go index e07b08e0eec9..cb534cacda4f 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_darwin_arm64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_darwin_arm64.go @@ -85,12 +85,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xa + + _NOTE_TRIGGER = 0x1000000 _PTHREAD_CREATE_DETACHED = 0x2 diff --git a/contrib/go/_std_1.22/src/runtime/defs_dragonfly.go b/contrib/go/_std_1.23/src/runtime/defs_dragonfly.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/defs_dragonfly.go rename to contrib/go/_std_1.23/src/runtime/defs_dragonfly.go index 0463f1f116ae..d94461fe473d 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_dragonfly.go +++ b/contrib/go/_std_1.23/src/runtime/defs_dragonfly.go @@ -109,11 +109,16 @@ const ( EV_ADD = C.EV_ADD EV_DELETE = C.EV_DELETE + EV_ENABLE = C.EV_ENABLE + EV_DISABLE = C.EV_DISABLE EV_CLEAR = C.EV_CLEAR EV_ERROR = C.EV_ERROR EV_EOF = C.EV_EOF EVFILT_READ = C.EVFILT_READ EVFILT_WRITE = C.EVFILT_WRITE + EVFILT_USER = C.EVFILT_USER + + NOTE_TRIGGER = C.NOTE_TRIGGER ) type Rtprio C.struct_rtprio diff --git a/contrib/go/_std_1.22/src/runtime/defs_dragonfly_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_dragonfly_amd64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_dragonfly_amd64.go index 41bfb085d1ac..b142ae1d14d1 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_dragonfly_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_dragonfly_amd64.go @@ -88,11 +88,16 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0x9 + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd.go index d86ae9133afa..70d82b90dae8 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd.go @@ -136,12 +136,17 @@ const ( EV_ADD = C.EV_ADD EV_DELETE = C.EV_DELETE + EV_ENABLE = C.EV_ENABLE + EV_DISABLE = C.EV_DISABLE EV_CLEAR = C.EV_CLEAR EV_RECEIPT = C.EV_RECEIPT EV_ERROR = C.EV_ERROR EV_EOF = C.EV_EOF EVFILT_READ = C.EVFILT_READ EVFILT_WRITE = C.EVFILT_WRITE + EVFILT_USER = C.EVFILT_USER + + NOTE_TRIGGER = C.NOTE_TRIGGER ) type Rtprio C.struct_rtprio diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_386.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_386.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_386.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_386.go index ee8274188ae6..42a0faf74dcc 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_386.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_386.go @@ -104,12 +104,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_amd64.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_amd64.go index 9003f9201565..8f0b08d48aed 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_amd64.go @@ -104,12 +104,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_arm.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_arm.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_arm.go index 68cc1b9545b7..dbb54da51bd2 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_arm.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_arm.go @@ -104,12 +104,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_arm64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_arm64.go index 1d6723621ae7..83b639381be3 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_arm64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_arm64.go @@ -104,12 +104,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_riscv64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_riscv64.go index b977bde5515e..5d9a5ac7fda8 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_riscv64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_riscv64.go @@ -103,12 +103,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_illumos_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_illumos_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_illumos_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_illumos_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux.go b/contrib/go/_std_1.23/src/runtime/defs_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux.go rename to contrib/go/_std_1.23/src/runtime/defs_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_386.go b/contrib/go/_std_1.23/src/runtime/defs_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_386.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_arm.go b/contrib/go/_std_1.23/src/runtime/defs_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_loong64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_loong64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_mips64x.go b/contrib/go/_std_1.23/src/runtime/defs_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_mips64x.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_mipsx.go b/contrib/go/_std_1.23/src/runtime/defs_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_mipsx.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_ppc64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_ppc64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_ppc64le.go b/contrib/go/_std_1.23/src/runtime/defs_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_ppc64le.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_riscv64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_riscv64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_s390x.go b/contrib/go/_std_1.23/src/runtime/defs_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_s390x.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_netbsd.go b/contrib/go/_std_1.23/src/runtime/defs_netbsd.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/defs_netbsd.go rename to contrib/go/_std_1.23/src/runtime/defs_netbsd.go index 43923e3075b7..ec4d796bd325 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_netbsd.go +++ b/contrib/go/_std_1.23/src/runtime/defs_netbsd.go @@ -110,12 +110,17 @@ const ( EV_ADD = C.EV_ADD EV_DELETE = C.EV_DELETE + EV_ENABLE = C.EV_ENABLE + EV_DISABLE = C.EV_DISABLE EV_CLEAR = C.EV_CLEAR EV_RECEIPT = 0 EV_ERROR = C.EV_ERROR EV_EOF = C.EV_EOF EVFILT_READ = C.EVFILT_READ EVFILT_WRITE = C.EVFILT_WRITE + EVFILT_USER = C.EVFILT_USER + + NOTE_TRIGGER = C.NOTE_TRIGGER ) type Sigset C.sigset_t diff --git a/contrib/go/_std_1.22/src/runtime/defs_netbsd_386.go b/contrib/go/_std_1.23/src/runtime/defs_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_netbsd_386.go rename to contrib/go/_std_1.23/src/runtime/defs_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_netbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_netbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_netbsd_arm.go b/contrib/go/_std_1.23/src/runtime/defs_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_netbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_386.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_386.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_arm.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_mips64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_mips64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_ppc64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_plan9_386.go b/contrib/go/_std_1.23/src/runtime/defs_plan9_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_plan9_386.go rename to contrib/go/_std_1.23/src/runtime/defs_plan9_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_plan9_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_plan9_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_plan9_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_plan9_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_plan9_arm.go b/contrib/go/_std_1.23/src/runtime/defs_plan9_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_plan9_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_plan9_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_solaris.go b/contrib/go/_std_1.23/src/runtime/defs_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_solaris.go rename to contrib/go/_std_1.23/src/runtime/defs_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_solaris_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_solaris_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows.go b/contrib/go/_std_1.23/src/runtime/defs_windows.go similarity index 88% rename from contrib/go/_std_1.22/src/runtime/defs_windows.go rename to contrib/go/_std_1.23/src/runtime/defs_windows.go index 2dbe1446898e..2f09afbe1fef 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_windows.go +++ b/contrib/go/_std_1.23/src/runtime/defs_windows.go @@ -89,3 +89,13 @@ type memoryBasicInformation struct { protect uint32 type_ uint32 } + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow +type _OSVERSIONINFOW struct { + osVersionInfoSize uint32 + majorVersion uint32 + minorVersion uint32 + buildNumber uint32 + platformId uint32 + csdVersion [128]uint16 +} diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows_386.go b/contrib/go/_std_1.23/src/runtime/defs_windows_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_windows_386.go rename to contrib/go/_std_1.23/src/runtime/defs_windows_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_windows_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_windows_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_windows_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows_arm.go b/contrib/go/_std_1.23/src/runtime/defs_windows_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_windows_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_windows_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_windows_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_windows_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_windows_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/duff_386.s b/contrib/go/_std_1.23/src/runtime/duff_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_386.s rename to contrib/go/_std_1.23/src/runtime/duff_386.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_amd64.s b/contrib/go/_std_1.23/src/runtime/duff_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_amd64.s rename to contrib/go/_std_1.23/src/runtime/duff_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_arm.s b/contrib/go/_std_1.23/src/runtime/duff_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_arm.s rename to contrib/go/_std_1.23/src/runtime/duff_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_arm64.s b/contrib/go/_std_1.23/src/runtime/duff_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_arm64.s rename to contrib/go/_std_1.23/src/runtime/duff_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_loong64.s b/contrib/go/_std_1.23/src/runtime/duff_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_loong64.s rename to contrib/go/_std_1.23/src/runtime/duff_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_mips64x.s b/contrib/go/_std_1.23/src/runtime/duff_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_mips64x.s rename to contrib/go/_std_1.23/src/runtime/duff_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_ppc64x.s b/contrib/go/_std_1.23/src/runtime/duff_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/duff_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_riscv64.s b/contrib/go/_std_1.23/src/runtime/duff_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_riscv64.s rename to contrib/go/_std_1.23/src/runtime/duff_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_s390x.s b/contrib/go/_std_1.23/src/runtime/duff_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_s390x.s rename to contrib/go/_std_1.23/src/runtime/duff_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/env_plan9.go b/contrib/go/_std_1.23/src/runtime/env_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/env_plan9.go rename to contrib/go/_std_1.23/src/runtime/env_plan9.go diff --git a/contrib/go/_std_1.23/src/runtime/env_posix.go b/contrib/go/_std_1.23/src/runtime/env_posix.go new file mode 100644 index 000000000000..323ce7de9a0f --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/env_posix.go @@ -0,0 +1,89 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +func gogetenv(key string) string { + env := environ() + if env == nil { + throw("getenv before env init") + } + for _, s := range env { + if len(s) > len(key) && s[len(key)] == '=' && envKeyEqual(s[:len(key)], key) { + return s[len(key)+1:] + } + } + return "" +} + +// envKeyEqual reports whether a == b, with ASCII-only case insensitivity +// on Windows. The two strings must have the same length. +func envKeyEqual(a, b string) bool { + if GOOS == "windows" { // case insensitive + for i := 0; i < len(a); i++ { + ca, cb := a[i], b[i] + if ca == cb || lowerASCII(ca) == lowerASCII(cb) { + continue + } + return false + } + return true + } + return a == b +} + +func lowerASCII(c byte) byte { + if 'A' <= c && c <= 'Z' { + return c + ('a' - 'A') + } + return c +} + +// _cgo_setenv should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname _cgo_setenv +var _cgo_setenv unsafe.Pointer // pointer to C function + +// _cgo_unsetenv should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname _cgo_unsetenv +var _cgo_unsetenv unsafe.Pointer // pointer to C function + +// Update the C environment if cgo is loaded. +func setenv_c(k string, v string) { + if _cgo_setenv == nil { + return + } + arg := [2]unsafe.Pointer{cstring(k), cstring(v)} + asmcgocall(_cgo_setenv, unsafe.Pointer(&arg)) +} + +// Update the C environment if cgo is loaded. +func unsetenv_c(k string) { + if _cgo_unsetenv == nil { + return + } + arg := [1]unsafe.Pointer{cstring(k)} + asmcgocall(_cgo_unsetenv, unsafe.Pointer(&arg)) +} + +func cstring(s string) unsafe.Pointer { + p := make([]byte, len(s)+1) + copy(p, s) + return unsafe.Pointer(&p[0]) +} diff --git a/contrib/go/_std_1.23/src/runtime/error.go b/contrib/go/_std_1.23/src/runtime/error.go new file mode 100644 index 000000000000..406f36ca5f9d --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/error.go @@ -0,0 +1,356 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/abi" + "internal/bytealg" +) + +// The Error interface identifies a run time error. +type Error interface { + error + + // RuntimeError is a no-op function but + // serves to distinguish types that are run time + // errors from ordinary errors: a type is a + // run time error if it has a RuntimeError method. + RuntimeError() +} + +// A TypeAssertionError explains a failed type assertion. +type TypeAssertionError struct { + _interface *_type + concrete *_type + asserted *_type + missingMethod string // one method needed by Interface, missing from Concrete +} + +func (*TypeAssertionError) RuntimeError() {} + +func (e *TypeAssertionError) Error() string { + inter := "interface" + if e._interface != nil { + inter = toRType(e._interface).string() + } + as := toRType(e.asserted).string() + if e.concrete == nil { + return "interface conversion: " + inter + " is nil, not " + as + } + cs := toRType(e.concrete).string() + if e.missingMethod == "" { + msg := "interface conversion: " + inter + " is " + cs + ", not " + as + if cs == as { + // provide slightly clearer error message + if toRType(e.concrete).pkgpath() != toRType(e.asserted).pkgpath() { + msg += " (types from different packages)" + } else { + msg += " (types from different scopes)" + } + } + return msg + } + return "interface conversion: " + cs + " is not " + as + + ": missing method " + e.missingMethod +} + +// itoa converts val to a decimal representation. The result is +// written somewhere within buf and the location of the result is returned. +// buf must be at least 20 bytes. +// +//go:nosplit +func itoa(buf []byte, val uint64) []byte { + i := len(buf) - 1 + for val >= 10 { + buf[i] = byte(val%10 + '0') + i-- + val /= 10 + } + buf[i] = byte(val + '0') + return buf[i:] +} + +// An errorString represents a runtime error described by a single string. +type errorString string + +func (e errorString) RuntimeError() {} + +func (e errorString) Error() string { + return "runtime error: " + string(e) +} + +type errorAddressString struct { + msg string // error message + addr uintptr // memory address where the error occurred +} + +func (e errorAddressString) RuntimeError() {} + +func (e errorAddressString) Error() string { + return "runtime error: " + e.msg +} + +// Addr returns the memory address where a fault occurred. +// The address provided is best-effort. +// The veracity of the result may depend on the platform. +// Errors providing this method will only be returned as +// a result of using [runtime/debug.SetPanicOnFault]. +func (e errorAddressString) Addr() uintptr { + return e.addr +} + +// plainError represents a runtime error described a string without +// the prefix "runtime error: " after invoking errorString.Error(). +// See Issue #14965. +type plainError string + +func (e plainError) RuntimeError() {} + +func (e plainError) Error() string { + return string(e) +} + +// A boundsError represents an indexing or slicing operation gone wrong. +type boundsError struct { + x int64 + y int + // Values in an index or slice expression can be signed or unsigned. + // That means we'd need 65 bits to encode all possible indexes, from -2^63 to 2^64-1. + // Instead, we keep track of whether x should be interpreted as signed or unsigned. + // y is known to be nonnegative and to fit in an int. + signed bool + code boundsErrorCode +} + +type boundsErrorCode uint8 + +const ( + boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed + + boundsSliceAlen // s[?:x], 0 <= x <= len(s) failed + boundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed + boundsSliceB // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen) + + boundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed + boundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed + boundsSlice3B // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen) + boundsSlice3C // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen) + + boundsConvert // (*[x]T)(s), 0 <= x <= len(s) failed + // Note: in the above, len(s) and cap(s) are stored in y +) + +// boundsErrorFmts provide error text for various out-of-bounds panics. +// Note: if you change these strings, you should adjust the size of the buffer +// in boundsError.Error below as well. +var boundsErrorFmts = [...]string{ + boundsIndex: "index out of range [%x] with length %y", + boundsSliceAlen: "slice bounds out of range [:%x] with length %y", + boundsSliceAcap: "slice bounds out of range [:%x] with capacity %y", + boundsSliceB: "slice bounds out of range [%x:%y]", + boundsSlice3Alen: "slice bounds out of range [::%x] with length %y", + boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y", + boundsSlice3B: "slice bounds out of range [:%x:%y]", + boundsSlice3C: "slice bounds out of range [%x:%y:]", + boundsConvert: "cannot convert slice with length %y to array or pointer to array with length %x", +} + +// boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y. +var boundsNegErrorFmts = [...]string{ + boundsIndex: "index out of range [%x]", + boundsSliceAlen: "slice bounds out of range [:%x]", + boundsSliceAcap: "slice bounds out of range [:%x]", + boundsSliceB: "slice bounds out of range [%x:]", + boundsSlice3Alen: "slice bounds out of range [::%x]", + boundsSlice3Acap: "slice bounds out of range [::%x]", + boundsSlice3B: "slice bounds out of range [:%x:]", + boundsSlice3C: "slice bounds out of range [%x::]", +} + +func (e boundsError) RuntimeError() {} + +func appendIntStr(b []byte, v int64, signed bool) []byte { + if signed && v < 0 { + b = append(b, '-') + v = -v + } + var buf [20]byte + b = append(b, itoa(buf[:], uint64(v))...) + return b +} + +func (e boundsError) Error() string { + fmt := boundsErrorFmts[e.code] + if e.signed && e.x < 0 { + fmt = boundsNegErrorFmts[e.code] + } + // max message length is 99: "runtime error: slice bounds out of range [::%x] with capacity %y" + // x can be at most 20 characters. y can be at most 19. + b := make([]byte, 0, 100) + b = append(b, "runtime error: "...) + for i := 0; i < len(fmt); i++ { + c := fmt[i] + if c != '%' { + b = append(b, c) + continue + } + i++ + switch fmt[i] { + case 'x': + b = appendIntStr(b, e.x, e.signed) + case 'y': + b = appendIntStr(b, int64(e.y), true) + } + } + return string(b) +} + +type stringer interface { + String() string +} + +// printpanicval prints an argument passed to panic. +// If panic is called with a value that has a String or Error method, +// it has already been converted into a string by preprintpanics. +// +// To ensure that the traceback can be unambiguously parsed even when +// the panic value contains "\ngoroutine" and other stack-like +// strings, newlines in the string representation of v are replaced by +// "\n\t". +func printpanicval(v any) { + switch v := v.(type) { + case nil: + print("nil") + case bool: + print(v) + case int: + print(v) + case int8: + print(v) + case int16: + print(v) + case int32: + print(v) + case int64: + print(v) + case uint: + print(v) + case uint8: + print(v) + case uint16: + print(v) + case uint32: + print(v) + case uint64: + print(v) + case uintptr: + print(v) + case float32: + print(v) + case float64: + print(v) + case complex64: + print(v) + case complex128: + print(v) + case string: + printindented(v) + default: + printanycustomtype(v) + } +} + +// Invariant: each newline in the string representation is followed by a tab. +func printanycustomtype(i any) { + eface := efaceOf(&i) + typestring := toRType(eface._type).string() + + switch eface._type.Kind_ { + case abi.String: + print(typestring, `("`) + printindented(*(*string)(eface.data)) + print(`")`) + case abi.Bool: + print(typestring, "(", *(*bool)(eface.data), ")") + case abi.Int: + print(typestring, "(", *(*int)(eface.data), ")") + case abi.Int8: + print(typestring, "(", *(*int8)(eface.data), ")") + case abi.Int16: + print(typestring, "(", *(*int16)(eface.data), ")") + case abi.Int32: + print(typestring, "(", *(*int32)(eface.data), ")") + case abi.Int64: + print(typestring, "(", *(*int64)(eface.data), ")") + case abi.Uint: + print(typestring, "(", *(*uint)(eface.data), ")") + case abi.Uint8: + print(typestring, "(", *(*uint8)(eface.data), ")") + case abi.Uint16: + print(typestring, "(", *(*uint16)(eface.data), ")") + case abi.Uint32: + print(typestring, "(", *(*uint32)(eface.data), ")") + case abi.Uint64: + print(typestring, "(", *(*uint64)(eface.data), ")") + case abi.Uintptr: + print(typestring, "(", *(*uintptr)(eface.data), ")") + case abi.Float32: + print(typestring, "(", *(*float32)(eface.data), ")") + case abi.Float64: + print(typestring, "(", *(*float64)(eface.data), ")") + case abi.Complex64: + print(typestring, *(*complex64)(eface.data)) + case abi.Complex128: + print(typestring, *(*complex128)(eface.data)) + default: + print("(", typestring, ") ", eface.data) + } +} + +// printindented prints s, replacing "\n" with "\n\t". +func printindented(s string) { + for { + i := bytealg.IndexByteString(s, '\n') + if i < 0 { + break + } + i += len("\n") + print(s[:i]) + print("\t") + s = s[i:] + } + print(s) +} + +// panicwrap generates a panic for a call to a wrapped value method +// with a nil pointer receiver. +// +// It is called from the generated wrapper code. +func panicwrap() { + pc := getcallerpc() + name := funcNameForPrint(funcname(findfunc(pc))) + // name is something like "main.(*T).F". + // We want to extract pkg ("main"), typ ("T"), and meth ("F"). + // Do it by finding the parens. + i := bytealg.IndexByteString(name, '(') + if i < 0 { + throw("panicwrap: no ( in " + name) + } + pkg := name[:i-1] + if i+2 >= len(name) || name[i-1:i+2] != ".(*" { + throw("panicwrap: unexpected string after package name: " + name) + } + name = name[i+2:] + i = bytealg.IndexByteString(name, ')') + if i < 0 { + throw("panicwrap: no ) in " + name) + } + if i+2 >= len(name) || name[i:i+2] != ")." { + throw("panicwrap: unexpected string after type name: " + name) + } + typ := name[:i] + meth := name[i+2:] + panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")) +} diff --git a/contrib/go/_std_1.22/src/runtime/extern.go b/contrib/go/_std_1.23/src/runtime/extern.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/extern.go rename to contrib/go/_std_1.23/src/runtime/extern.go index e42122fd3a1c..2019be4ddec4 100644 --- a/contrib/go/_std_1.22/src/runtime/extern.go +++ b/contrib/go/_std_1.23/src/runtime/extern.go @@ -35,9 +35,6 @@ time. The GODEBUG variable controls debugging variables within the runtime. It is a comma-separated list of name=val pairs setting these named variables: - allocfreetrace: setting allocfreetrace=1 causes every allocation to be - profiled and a stack trace printed on each object's allocation and free. - clobberfree: setting clobberfree=1 causes the garbage collector to clobber the memory content of an object with bad content when it frees the object. @@ -145,6 +142,13 @@ It is a comma-separated list of name=val pairs setting these named variables: When set to 0 memory profiling is disabled. Refer to the description of MemProfileRate for the default value. + profstackdepth: profstackdepth=128 (the default) will set the maximum stack + depth used by all pprof profilers except for the CPU profiler to 128 frames. + Stack traces that exceed this limit will be truncated to the limit starting + from the leaf frame. Setting profstackdepth to any value above 1024 will + silently default to 1024. Future versions of Go may remove this limitation + and extend profstackdepth to apply to the CPU profiler and execution tracer. + pagetrace: setting pagetrace=/path/to/file will write out a trace of page events that can be viewed, analyzed, and visualized using the x/debug/cmd/pagetrace tool. Build your program with GOEXPERIMENT=pagetrace to enable this functionality. Do not @@ -198,9 +202,8 @@ It is a comma-separated list of name=val pairs setting these named variables: tracebackancestors: setting tracebackancestors=N extends tracebacks with the stacks at which goroutines were created, where N limits the number of ancestor goroutines to - report. This also extends the information returned by runtime.Stack. Ancestor's goroutine - IDs will refer to the ID of the goroutine at the time of creation; it's possible for this - ID to be reused for another goroutine. Setting N to 0 will report no ancestry information. + report. This also extends the information returned by runtime.Stack. + Setting N to 0 will report no ancestry information. tracefpunwindoff: setting tracefpunwindoff=1 forces the execution tracer to use the runtime's default stack unwinder instead of frame pointer unwinding. @@ -211,6 +214,9 @@ It is a comma-separated list of name=val pairs setting these named variables: applies if a program is built with GOEXPERIMENT=exectracer2. Used primarily for testing and debugging the execution tracer. + tracecheckstackownership: setting tracecheckstackownership=1 enables a debug check in the + execution tracer to double-check stack ownership before taking a stack trace. + asyncpreemptoff: asyncpreemptoff=1 disables signal-based asynchronous goroutine preemption. This makes some loops non-preemptible for long periods, which may delay GC and @@ -294,7 +300,7 @@ import ( // call. The boolean ok is false if it was not possible to recover the information. func Caller(skip int) (pc uintptr, file string, line int, ok bool) { rpc := make([]uintptr, 1) - n := callers(skip+1, rpc[:]) + n := callers(skip+1, rpc) if n < 1 { return } diff --git a/contrib/go/_std_1.22/src/runtime/fastlog2.go b/contrib/go/_std_1.23/src/runtime/fastlog2.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/fastlog2.go rename to contrib/go/_std_1.23/src/runtime/fastlog2.go diff --git a/contrib/go/_std_1.22/src/runtime/fastlog2table.go b/contrib/go/_std_1.23/src/runtime/fastlog2table.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/fastlog2table.go rename to contrib/go/_std_1.23/src/runtime/fastlog2table.go diff --git a/contrib/go/_std_1.22/src/runtime/fds_nonunix.go b/contrib/go/_std_1.23/src/runtime/fds_nonunix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/fds_nonunix.go rename to contrib/go/_std_1.23/src/runtime/fds_nonunix.go diff --git a/contrib/go/_std_1.22/src/runtime/fds_unix.go b/contrib/go/_std_1.23/src/runtime/fds_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/fds_unix.go rename to contrib/go/_std_1.23/src/runtime/fds_unix.go diff --git a/contrib/go/_std_1.22/src/runtime/float.go b/contrib/go/_std_1.23/src/runtime/float.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/float.go rename to contrib/go/_std_1.23/src/runtime/float.go diff --git a/contrib/go/_std_1.22/src/runtime/funcdata.h b/contrib/go/_std_1.23/src/runtime/funcdata.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/funcdata.h rename to contrib/go/_std_1.23/src/runtime/funcdata.h diff --git a/contrib/go/_std_1.22/src/runtime/go_tls.h b/contrib/go/_std_1.23/src/runtime/go_tls.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/go_tls.h rename to contrib/go/_std_1.23/src/runtime/go_tls.h diff --git a/contrib/go/_std_1.22/src/runtime/hash32.go b/contrib/go/_std_1.23/src/runtime/hash32.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/hash32.go rename to contrib/go/_std_1.23/src/runtime/hash32.go diff --git a/contrib/go/_std_1.22/src/runtime/hash64.go b/contrib/go/_std_1.23/src/runtime/hash64.go similarity index 76% rename from contrib/go/_std_1.22/src/runtime/hash64.go rename to contrib/go/_std_1.23/src/runtime/hash64.go index 2864a4b963dd..05cdb8111372 100644 --- a/contrib/go/_std_1.22/src/runtime/hash64.go +++ b/contrib/go/_std_1.23/src/runtime/hash64.go @@ -15,16 +15,12 @@ import ( ) const ( - m1 = 0xa0761d6478bd642f - m2 = 0xe7037ed1a0b428db - m3 = 0x8ebc6af09c88c6e3 - m4 = 0x589965cc75374cc3 m5 = 0x1d8e4e27c47d124f ) func memhashFallback(p unsafe.Pointer, seed, s uintptr) uintptr { var a, b uintptr - seed ^= hashkey[0] ^ m1 + seed ^= hashkey[0] switch { case s == 0: return seed @@ -50,32 +46,32 @@ func memhashFallback(p unsafe.Pointer, seed, s uintptr) uintptr { seed1 := seed seed2 := seed for ; l > 48; l -= 48 { - seed = mix(r8(p)^m2, r8(add(p, 8))^seed) - seed1 = mix(r8(add(p, 16))^m3, r8(add(p, 24))^seed1) - seed2 = mix(r8(add(p, 32))^m4, r8(add(p, 40))^seed2) + seed = mix(r8(p)^hashkey[1], r8(add(p, 8))^seed) + seed1 = mix(r8(add(p, 16))^hashkey[2], r8(add(p, 24))^seed1) + seed2 = mix(r8(add(p, 32))^hashkey[3], r8(add(p, 40))^seed2) p = add(p, 48) } seed ^= seed1 ^ seed2 } for ; l > 16; l -= 16 { - seed = mix(r8(p)^m2, r8(add(p, 8))^seed) + seed = mix(r8(p)^hashkey[1], r8(add(p, 8))^seed) p = add(p, 16) } a = r8(add(p, l-16)) b = r8(add(p, l-8)) } - return mix(m5^s, mix(a^m2, b^seed)) + return mix(m5^s, mix(a^hashkey[1], b^seed)) } func memhash32Fallback(p unsafe.Pointer, seed uintptr) uintptr { a := r4(p) - return mix(m5^4, mix(a^m2, a^seed^hashkey[0]^m1)) + return mix(m5^4, mix(a^hashkey[1], a^seed^hashkey[0])) } func memhash64Fallback(p unsafe.Pointer, seed uintptr) uintptr { a := r8(p) - return mix(m5^8, mix(a^m2, a^seed^hashkey[0]^m1)) + return mix(m5^8, mix(a^hashkey[1], a^seed^hashkey[0])) } func mix(a, b uintptr) uintptr { diff --git a/contrib/go/_std_1.22/src/runtime/heapdump.go b/contrib/go/_std_1.23/src/runtime/heapdump.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/heapdump.go rename to contrib/go/_std_1.23/src/runtime/heapdump.go index 276c5bfaf615..95fb62dc425c 100644 --- a/contrib/go/_std_1.22/src/runtime/heapdump.go +++ b/contrib/go/_std_1.23/src/runtime/heapdump.go @@ -14,7 +14,6 @@ package runtime import ( "internal/abi" "internal/goarch" - "internal/goexperiment" "unsafe" ) @@ -206,7 +205,7 @@ func dumptype(t *_type) { dwritebyte('.') dwrite(unsafe.Pointer(unsafe.StringData(name)), uintptr(len(name))) } - dumpbool(t.Kind_&kindDirectIface == 0 || t.PtrBytes != 0) + dumpbool(t.Kind_&abi.KindDirectIface == 0 || t.PtrBytes != 0) } // dump an object. @@ -540,7 +539,7 @@ func dumpparams() { } func itab_callback(tab *itab) { - t := tab._type + t := tab.Type dumptype(t) dumpint(tagItab) dumpint(uint64(uintptr(unsafe.Pointer(tab)))) @@ -735,31 +734,16 @@ func makeheapobjbv(p uintptr, size uintptr) bitvector { tmpbuf = (*[1 << 30]byte)(p)[:n] } // Convert heap bitmap to pointer bitmap. - for i := uintptr(0); i < nptr/8+1; i++ { - tmpbuf[i] = 0 - } - if goexperiment.AllocHeaders { - s := spanOf(p) - tp := s.typePointersOf(p, size) - for { - var addr uintptr - if tp, addr = tp.next(p + size); addr == 0 { - break - } - i := (addr - p) / goarch.PtrSize - tmpbuf[i/8] |= 1 << (i % 8) - } - } else { - hbits := heapBitsForAddr(p, size) - for { - var addr uintptr - hbits, addr = hbits.next() - if addr == 0 { - break - } - i := (addr - p) / goarch.PtrSize - tmpbuf[i/8] |= 1 << (i % 8) + clear(tmpbuf[:nptr/8+1]) + s := spanOf(p) + tp := s.typePointersOf(p, size) + for { + var addr uintptr + if tp, addr = tp.next(p + size); addr == 0 { + break } + i := (addr - p) / goarch.PtrSize + tmpbuf[i/8] |= 1 << (i % 8) } return bitvector{int32(nptr), &tmpbuf[0]} } diff --git a/contrib/go/_std_1.22/src/runtime/histogram.go b/contrib/go/_std_1.23/src/runtime/histogram.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/histogram.go rename to contrib/go/_std_1.23/src/runtime/histogram.go index f243667b5542..95230d1f39d5 100644 --- a/contrib/go/_std_1.22/src/runtime/histogram.go +++ b/contrib/go/_std_1.23/src/runtime/histogram.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) diff --git a/contrib/go/_std_1.23/src/runtime/iface.go b/contrib/go/_std_1.23/src/runtime/iface.go new file mode 100644 index 000000000000..41a10ae01215 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/iface.go @@ -0,0 +1,735 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/abi" + "internal/goarch" + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +const itabInitSize = 512 + +var ( + itabLock mutex // lock for accessing itab table + itabTable = &itabTableInit // pointer to current table + itabTableInit = itabTableType{size: itabInitSize} // starter table +) + +// Note: change the formula in the mallocgc call in itabAdd if you change these fields. +type itabTableType struct { + size uintptr // length of entries array. Always a power of 2. + count uintptr // current number of filled entries. + entries [itabInitSize]*itab // really [size] large +} + +func itabHashFunc(inter *interfacetype, typ *_type) uintptr { + // compiler has provided some good hash codes for us. + return uintptr(inter.Type.Hash ^ typ.Hash) +} + +// getitab should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname getitab +func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { + if len(inter.Methods) == 0 { + throw("internal error - misuse of itab") + } + + // easy case + if typ.TFlag&abi.TFlagUncommon == 0 { + if canfail { + return nil + } + name := toRType(&inter.Type).nameOff(inter.Methods[0].Name) + panic(&TypeAssertionError{nil, typ, &inter.Type, name.Name()}) + } + + var m *itab + + // First, look in the existing table to see if we can find the itab we need. + // This is by far the most common case, so do it without locks. + // Use atomic to ensure we see any previous writes done by the thread + // that updates the itabTable field (with atomic.Storep in itabAdd). + t := (*itabTableType)(atomic.Loadp(unsafe.Pointer(&itabTable))) + if m = t.find(inter, typ); m != nil { + goto finish + } + + // Not found. Grab the lock and try again. + lock(&itabLock) + if m = itabTable.find(inter, typ); m != nil { + unlock(&itabLock) + goto finish + } + + // Entry doesn't exist yet. Make a new entry & add it. + m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.Methods)-1)*goarch.PtrSize, 0, &memstats.other_sys)) + m.Inter = inter + m.Type = typ + // The hash is used in type switches. However, compiler statically generates itab's + // for all interface/type pairs used in switches (which are added to itabTable + // in itabsinit). The dynamically-generated itab's never participate in type switches, + // and thus the hash is irrelevant. + // Note: m.Hash is _not_ the hash used for the runtime itabTable hash table. + m.Hash = 0 + itabInit(m, true) + itabAdd(m) + unlock(&itabLock) +finish: + if m.Fun[0] != 0 { + return m + } + if canfail { + return nil + } + // this can only happen if the conversion + // was already done once using the , ok form + // and we have a cached negative result. + // The cached result doesn't record which + // interface function was missing, so initialize + // the itab again to get the missing function name. + panic(&TypeAssertionError{concrete: typ, asserted: &inter.Type, missingMethod: itabInit(m, false)}) +} + +// find finds the given interface/type pair in t. +// Returns nil if the given interface/type pair isn't present. +func (t *itabTableType) find(inter *interfacetype, typ *_type) *itab { + // Implemented using quadratic probing. + // Probe sequence is h(i) = h0 + i*(i+1)/2 mod 2^k. + // We're guaranteed to hit all table entries using this probe sequence. + mask := t.size - 1 + h := itabHashFunc(inter, typ) & mask + for i := uintptr(1); ; i++ { + p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) + // Use atomic read here so if we see m != nil, we also see + // the initializations of the fields of m. + // m := *p + m := (*itab)(atomic.Loadp(unsafe.Pointer(p))) + if m == nil { + return nil + } + if m.Inter == inter && m.Type == typ { + return m + } + h += i + h &= mask + } +} + +// itabAdd adds the given itab to the itab hash table. +// itabLock must be held. +func itabAdd(m *itab) { + // Bugs can lead to calling this while mallocing is set, + // typically because this is called while panicking. + // Crash reliably, rather than only when we need to grow + // the hash table. + if getg().m.mallocing != 0 { + throw("malloc deadlock") + } + + t := itabTable + if t.count >= 3*(t.size/4) { // 75% load factor + // Grow hash table. + // t2 = new(itabTableType) + some additional entries + // We lie and tell malloc we want pointer-free memory because + // all the pointed-to values are not in the heap. + t2 := (*itabTableType)(mallocgc((2+2*t.size)*goarch.PtrSize, nil, true)) + t2.size = t.size * 2 + + // Copy over entries. + // Note: while copying, other threads may look for an itab and + // fail to find it. That's ok, they will then try to get the itab lock + // and as a consequence wait until this copying is complete. + iterate_itabs(t2.add) + if t2.count != t.count { + throw("mismatched count during itab table copy") + } + // Publish new hash table. Use an atomic write: see comment in getitab. + atomicstorep(unsafe.Pointer(&itabTable), unsafe.Pointer(t2)) + // Adopt the new table as our own. + t = itabTable + // Note: the old table can be GC'ed here. + } + t.add(m) +} + +// add adds the given itab to itab table t. +// itabLock must be held. +func (t *itabTableType) add(m *itab) { + // See comment in find about the probe sequence. + // Insert new itab in the first empty spot in the probe sequence. + mask := t.size - 1 + h := itabHashFunc(m.Inter, m.Type) & mask + for i := uintptr(1); ; i++ { + p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) + m2 := *p + if m2 == m { + // A given itab may be used in more than one module + // and thanks to the way global symbol resolution works, the + // pointed-to itab may already have been inserted into the + // global 'hash'. + return + } + if m2 == nil { + // Use atomic write here so if a reader sees m, it also + // sees the correctly initialized fields of m. + // NoWB is ok because m is not in heap memory. + // *p = m + atomic.StorepNoWB(unsafe.Pointer(p), unsafe.Pointer(m)) + t.count++ + return + } + h += i + h &= mask + } +} + +// itabInit fills in the m.Fun array with all the code pointers for +// the m.Inter/m.Type pair. If the type does not implement the interface, +// it sets m.Fun[0] to 0 and returns the name of an interface function that is missing. +// If !firstTime, itabInit will not write anything to m.Fun (see issue 65962). +// It is ok to call this multiple times on the same m, even concurrently +// (although it will only be called once with firstTime==true). +func itabInit(m *itab, firstTime bool) string { + inter := m.Inter + typ := m.Type + x := typ.Uncommon() + + // both inter and typ have method sorted by name, + // and interface names are unique, + // so can iterate over both in lock step; + // the loop is O(ni+nt) not O(ni*nt). + ni := len(inter.Methods) + nt := int(x.Mcount) + xmhdr := (*[1 << 16]abi.Method)(add(unsafe.Pointer(x), uintptr(x.Moff)))[:nt:nt] + j := 0 + methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.Fun[0]))[:ni:ni] + var fun0 unsafe.Pointer +imethods: + for k := 0; k < ni; k++ { + i := &inter.Methods[k] + itype := toRType(&inter.Type).typeOff(i.Typ) + name := toRType(&inter.Type).nameOff(i.Name) + iname := name.Name() + ipkg := pkgPath(name) + if ipkg == "" { + ipkg = inter.PkgPath.Name() + } + for ; j < nt; j++ { + t := &xmhdr[j] + rtyp := toRType(typ) + tname := rtyp.nameOff(t.Name) + if rtyp.typeOff(t.Mtyp) == itype && tname.Name() == iname { + pkgPath := pkgPath(tname) + if pkgPath == "" { + pkgPath = rtyp.nameOff(x.PkgPath).Name() + } + if tname.IsExported() || pkgPath == ipkg { + ifn := rtyp.textOff(t.Ifn) + if k == 0 { + fun0 = ifn // we'll set m.Fun[0] at the end + } else if firstTime { + methods[k] = ifn + } + continue imethods + } + } + } + // didn't find method + // Leaves m.Fun[0] set to 0. + return iname + } + if firstTime { + m.Fun[0] = uintptr(fun0) + } + return "" +} + +func itabsinit() { + lockInit(&itabLock, lockRankItab) + lock(&itabLock) + for _, md := range activeModules() { + for _, i := range md.itablinks { + itabAdd(i) + } + } + unlock(&itabLock) +} + +// panicdottypeE is called when doing an e.(T) conversion and the conversion fails. +// have = the dynamic type we have. +// want = the static type we're trying to convert to. +// iface = the static type we're converting from. +func panicdottypeE(have, want, iface *_type) { + panic(&TypeAssertionError{iface, have, want, ""}) +} + +// panicdottypeI is called when doing an i.(T) conversion and the conversion fails. +// Same args as panicdottypeE, but "have" is the dynamic itab we have. +func panicdottypeI(have *itab, want, iface *_type) { + var t *_type + if have != nil { + t = have.Type + } + panicdottypeE(t, want, iface) +} + +// panicnildottype is called when doing an i.(T) conversion and the interface i is nil. +// want = the static type we're trying to convert to. +func panicnildottype(want *_type) { + panic(&TypeAssertionError{nil, nil, want, ""}) + // TODO: Add the static type we're converting from as well. + // It might generate a better error message. + // Just to match other nil conversion errors, we don't for now. +} + +// The specialized convTx routines need a type descriptor to use when calling mallocgc. +// We don't need the type to be exact, just to have the correct size, alignment, and pointer-ness. +// However, when debugging, it'd be nice to have some indication in mallocgc where the types came from, +// so we use named types here. +// We then construct interface values of these types, +// and then extract the type word to use as needed. +type ( + uint16InterfacePtr uint16 + uint32InterfacePtr uint32 + uint64InterfacePtr uint64 + stringInterfacePtr string + sliceInterfacePtr []byte +) + +var ( + uint16Eface any = uint16InterfacePtr(0) + uint32Eface any = uint32InterfacePtr(0) + uint64Eface any = uint64InterfacePtr(0) + stringEface any = stringInterfacePtr("") + sliceEface any = sliceInterfacePtr(nil) + + uint16Type *_type = efaceOf(&uint16Eface)._type + uint32Type *_type = efaceOf(&uint32Eface)._type + uint64Type *_type = efaceOf(&uint64Eface)._type + stringType *_type = efaceOf(&stringEface)._type + sliceType *_type = efaceOf(&sliceEface)._type +) + +// The conv and assert functions below do very similar things. +// The convXXX functions are guaranteed by the compiler to succeed. +// The assertXXX functions may fail (either panicking or returning false, +// depending on whether they are 1-result or 2-result). +// The convXXX functions succeed on a nil input, whereas the assertXXX +// functions fail on a nil input. + +// convT converts a value of type t, which is pointed to by v, to a pointer that can +// be used as the second word of an interface value. +func convT(t *_type, v unsafe.Pointer) unsafe.Pointer { + if raceenabled { + raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convT)) + } + if msanenabled { + msanread(v, t.Size_) + } + if asanenabled { + asanread(v, t.Size_) + } + x := mallocgc(t.Size_, t, true) + typedmemmove(t, x, v) + return x +} +func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer { + // TODO: maybe take size instead of type? + if raceenabled { + raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convTnoptr)) + } + if msanenabled { + msanread(v, t.Size_) + } + if asanenabled { + asanread(v, t.Size_) + } + + x := mallocgc(t.Size_, t, false) + memmove(x, v, t.Size_) + return x +} + +func convT16(val uint16) (x unsafe.Pointer) { + if val < uint16(len(staticuint64s)) { + x = unsafe.Pointer(&staticuint64s[val]) + if goarch.BigEndian { + x = add(x, 6) + } + } else { + x = mallocgc(2, uint16Type, false) + *(*uint16)(x) = val + } + return +} + +func convT32(val uint32) (x unsafe.Pointer) { + if val < uint32(len(staticuint64s)) { + x = unsafe.Pointer(&staticuint64s[val]) + if goarch.BigEndian { + x = add(x, 4) + } + } else { + x = mallocgc(4, uint32Type, false) + *(*uint32)(x) = val + } + return +} + +// convT64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname convT64 +func convT64(val uint64) (x unsafe.Pointer) { + if val < uint64(len(staticuint64s)) { + x = unsafe.Pointer(&staticuint64s[val]) + } else { + x = mallocgc(8, uint64Type, false) + *(*uint64)(x) = val + } + return +} + +// convTstring should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname convTstring +func convTstring(val string) (x unsafe.Pointer) { + if val == "" { + x = unsafe.Pointer(&zeroVal[0]) + } else { + x = mallocgc(unsafe.Sizeof(val), stringType, true) + *(*string)(x) = val + } + return +} + +// convTslice should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname convTslice +func convTslice(val []byte) (x unsafe.Pointer) { + // Note: this must work for any element type, not just byte. + if (*slice)(unsafe.Pointer(&val)).array == nil { + x = unsafe.Pointer(&zeroVal[0]) + } else { + x = mallocgc(unsafe.Sizeof(val), sliceType, true) + *(*[]byte)(x) = val + } + return +} + +func assertE2I(inter *interfacetype, t *_type) *itab { + if t == nil { + // explicit conversions require non-nil interface value. + panic(&TypeAssertionError{nil, nil, &inter.Type, ""}) + } + return getitab(inter, t, false) +} + +func assertE2I2(inter *interfacetype, t *_type) *itab { + if t == nil { + return nil + } + return getitab(inter, t, true) +} + +// typeAssert builds an itab for the concrete type t and the +// interface type s.Inter. If the conversion is not possible it +// panics if s.CanFail is false and returns nil if s.CanFail is true. +func typeAssert(s *abi.TypeAssert, t *_type) *itab { + var tab *itab + if t == nil { + if !s.CanFail { + panic(&TypeAssertionError{nil, nil, &s.Inter.Type, ""}) + } + } else { + tab = getitab(s.Inter, t, s.CanFail) + } + + if !abi.UseInterfaceSwitchCache(GOARCH) { + return tab + } + + // Maybe update the cache, so the next time the generated code + // doesn't need to call into the runtime. + if cheaprand()&1023 != 0 { + // Only bother updating the cache ~1 in 1000 times. + return tab + } + // Load the current cache. + oldC := (*abi.TypeAssertCache)(atomic.Loadp(unsafe.Pointer(&s.Cache))) + + if cheaprand()&uint32(oldC.Mask) != 0 { + // As cache gets larger, choose to update it less often + // so we can amortize the cost of building a new cache. + return tab + } + + // Make a new cache. + newC := buildTypeAssertCache(oldC, t, tab) + + // Update cache. Use compare-and-swap so if multiple threads + // are fighting to update the cache, at least one of their + // updates will stick. + atomic_casPointer((*unsafe.Pointer)(unsafe.Pointer(&s.Cache)), unsafe.Pointer(oldC), unsafe.Pointer(newC)) + + return tab +} + +func buildTypeAssertCache(oldC *abi.TypeAssertCache, typ *_type, tab *itab) *abi.TypeAssertCache { + oldEntries := unsafe.Slice(&oldC.Entries[0], oldC.Mask+1) + + // Count the number of entries we need. + n := 1 + for _, e := range oldEntries { + if e.Typ != 0 { + n++ + } + } + + // Figure out how big a table we need. + // We need at least one more slot than the number of entries + // so that we are guaranteed an empty slot (for termination). + newN := n * 2 // make it at most 50% full + newN = 1 << sys.Len64(uint64(newN-1)) // round up to a power of 2 + + // Allocate the new table. + newSize := unsafe.Sizeof(abi.TypeAssertCache{}) + uintptr(newN-1)*unsafe.Sizeof(abi.TypeAssertCacheEntry{}) + newC := (*abi.TypeAssertCache)(mallocgc(newSize, nil, true)) + newC.Mask = uintptr(newN - 1) + newEntries := unsafe.Slice(&newC.Entries[0], newN) + + // Fill the new table. + addEntry := func(typ *_type, tab *itab) { + h := int(typ.Hash) & (newN - 1) + for { + if newEntries[h].Typ == 0 { + newEntries[h].Typ = uintptr(unsafe.Pointer(typ)) + newEntries[h].Itab = uintptr(unsafe.Pointer(tab)) + return + } + h = (h + 1) & (newN - 1) + } + } + for _, e := range oldEntries { + if e.Typ != 0 { + addEntry((*_type)(unsafe.Pointer(e.Typ)), (*itab)(unsafe.Pointer(e.Itab))) + } + } + addEntry(typ, tab) + + return newC +} + +// Empty type assert cache. Contains one entry with a nil Typ (which +// causes a cache lookup to fail immediately.) +var emptyTypeAssertCache = abi.TypeAssertCache{Mask: 0} + +// interfaceSwitch compares t against the list of cases in s. +// If t matches case i, interfaceSwitch returns the case index i and +// an itab for the pair . +// If there is no match, return N,nil, where N is the number +// of cases. +func interfaceSwitch(s *abi.InterfaceSwitch, t *_type) (int, *itab) { + cases := unsafe.Slice(&s.Cases[0], s.NCases) + + // Results if we don't find a match. + case_ := len(cases) + var tab *itab + + // Look through each case in order. + for i, c := range cases { + tab = getitab(c, t, true) + if tab != nil { + case_ = i + break + } + } + + if !abi.UseInterfaceSwitchCache(GOARCH) { + return case_, tab + } + + // Maybe update the cache, so the next time the generated code + // doesn't need to call into the runtime. + if cheaprand()&1023 != 0 { + // Only bother updating the cache ~1 in 1000 times. + // This ensures we don't waste memory on switches, or + // switch arguments, that only happen a few times. + return case_, tab + } + // Load the current cache. + oldC := (*abi.InterfaceSwitchCache)(atomic.Loadp(unsafe.Pointer(&s.Cache))) + + if cheaprand()&uint32(oldC.Mask) != 0 { + // As cache gets larger, choose to update it less often + // so we can amortize the cost of building a new cache + // (that cost is linear in oldc.Mask). + return case_, tab + } + + // Make a new cache. + newC := buildInterfaceSwitchCache(oldC, t, case_, tab) + + // Update cache. Use compare-and-swap so if multiple threads + // are fighting to update the cache, at least one of their + // updates will stick. + atomic_casPointer((*unsafe.Pointer)(unsafe.Pointer(&s.Cache)), unsafe.Pointer(oldC), unsafe.Pointer(newC)) + + return case_, tab +} + +// buildInterfaceSwitchCache constructs an interface switch cache +// containing all the entries from oldC plus the new entry +// (typ,case_,tab). +func buildInterfaceSwitchCache(oldC *abi.InterfaceSwitchCache, typ *_type, case_ int, tab *itab) *abi.InterfaceSwitchCache { + oldEntries := unsafe.Slice(&oldC.Entries[0], oldC.Mask+1) + + // Count the number of entries we need. + n := 1 + for _, e := range oldEntries { + if e.Typ != 0 { + n++ + } + } + + // Figure out how big a table we need. + // We need at least one more slot than the number of entries + // so that we are guaranteed an empty slot (for termination). + newN := n * 2 // make it at most 50% full + newN = 1 << sys.Len64(uint64(newN-1)) // round up to a power of 2 + + // Allocate the new table. + newSize := unsafe.Sizeof(abi.InterfaceSwitchCache{}) + uintptr(newN-1)*unsafe.Sizeof(abi.InterfaceSwitchCacheEntry{}) + newC := (*abi.InterfaceSwitchCache)(mallocgc(newSize, nil, true)) + newC.Mask = uintptr(newN - 1) + newEntries := unsafe.Slice(&newC.Entries[0], newN) + + // Fill the new table. + addEntry := func(typ *_type, case_ int, tab *itab) { + h := int(typ.Hash) & (newN - 1) + for { + if newEntries[h].Typ == 0 { + newEntries[h].Typ = uintptr(unsafe.Pointer(typ)) + newEntries[h].Case = case_ + newEntries[h].Itab = uintptr(unsafe.Pointer(tab)) + return + } + h = (h + 1) & (newN - 1) + } + } + for _, e := range oldEntries { + if e.Typ != 0 { + addEntry((*_type)(unsafe.Pointer(e.Typ)), e.Case, (*itab)(unsafe.Pointer(e.Itab))) + } + } + addEntry(typ, case_, tab) + + return newC +} + +// Empty interface switch cache. Contains one entry with a nil Typ (which +// causes a cache lookup to fail immediately.) +var emptyInterfaceSwitchCache = abi.InterfaceSwitchCache{Mask: 0} + +// reflect_ifaceE2I is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// +//go:linkname reflect_ifaceE2I reflect.ifaceE2I +func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { + *dst = iface{assertE2I(inter, e._type), e.data} +} + +//go:linkname reflectlite_ifaceE2I internal/reflectlite.ifaceE2I +func reflectlite_ifaceE2I(inter *interfacetype, e eface, dst *iface) { + *dst = iface{assertE2I(inter, e._type), e.data} +} + +func iterate_itabs(fn func(*itab)) { + // Note: only runs during stop the world or with itabLock held, + // so no other locks/atomics needed. + t := itabTable + for i := uintptr(0); i < t.size; i++ { + m := *(**itab)(add(unsafe.Pointer(&t.entries), i*goarch.PtrSize)) + if m != nil { + fn(m) + } + } +} + +// staticuint64s is used to avoid allocating in convTx for small integer values. +var staticuint64s = [...]uint64{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +} + +// The linker redirects a reference of a method that it determined +// unreachable to a reference to this function, so it will throw if +// ever called. +func unreachableMethod() { + throw("unreachable method called. linker bug?") +} diff --git a/contrib/go/_std_1.22/src/runtime/internal/math/math.go b/contrib/go/_std_1.23/src/runtime/internal/math/math.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/math/math.go rename to contrib/go/_std_1.23/src/runtime/internal/math/math.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/math/ya.make b/contrib/go/_std_1.23/src/runtime/internal/math/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/math/ya.make rename to contrib/go/_std_1.23/src/runtime/internal/math/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/internal/startlinetest/func_amd64.go b/contrib/go/_std_1.23/src/runtime/internal/startlinetest/func_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/startlinetest/func_amd64.go rename to contrib/go/_std_1.23/src/runtime/internal/startlinetest/func_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/startlinetest/func_amd64.s b/contrib/go/_std_1.23/src/runtime/internal/startlinetest/func_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/startlinetest/func_amd64.s rename to contrib/go/_std_1.23/src/runtime/internal/startlinetest/func_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/startlinetest/ya.make b/contrib/go/_std_1.23/src/runtime/internal/startlinetest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/startlinetest/ya.make rename to contrib/go/_std_1.23/src/runtime/internal/startlinetest/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/consts.go b/contrib/go/_std_1.23/src/runtime/internal/sys/consts.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/consts.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/consts.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/consts_norace.go b/contrib/go/_std_1.23/src/runtime/internal/sys/consts_norace.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/consts_norace.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/consts_norace.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/consts_race.go b/contrib/go/_std_1.23/src/runtime/internal/sys/consts_race.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/consts_race.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/consts_race.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/intrinsics.go b/contrib/go/_std_1.23/src/runtime/internal/sys/intrinsics.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/intrinsics.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/intrinsics.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/nih.go b/contrib/go/_std_1.23/src/runtime/internal/sys/nih.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/nih.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/nih.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/sys.go b/contrib/go/_std_1.23/src/runtime/internal/sys/sys.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/sys.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/sys.go diff --git a/contrib/go/_std_1.23/src/runtime/internal/sys/ya.make b/contrib/go/_std_1.23/src/runtime/internal/sys/ya.make new file mode 100644 index 000000000000..9f2d15dc7bd2 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/internal/sys/ya.make @@ -0,0 +1,21 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) + SRCS( + consts.go + consts_race.go + intrinsics.go + nih.go + sys.go + zversion.go + ) +ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + consts.go + consts_norace.go + intrinsics.go + nih.go + sys.go + zversion.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/zversion.go b/contrib/go/_std_1.23/src/runtime/internal/sys/zversion.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/zversion.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/zversion.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/wasitest/ya.make b/contrib/go/_std_1.23/src/runtime/internal/wasitest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/wasitest/ya.make rename to contrib/go/_std_1.23/src/runtime/internal/wasitest/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/internal/ya.make b/contrib/go/_std_1.23/src/runtime/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/ya.make rename to contrib/go/_std_1.23/src/runtime/internal/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/lfstack.go b/contrib/go/_std_1.23/src/runtime/lfstack.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/lfstack.go rename to contrib/go/_std_1.23/src/runtime/lfstack.go index a91ae64e5383..cbec6e844726 100644 --- a/contrib/go/_std_1.22/src/runtime/lfstack.go +++ b/contrib/go/_std_1.23/src/runtime/lfstack.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/libfuzzer.go b/contrib/go/_std_1.23/src/runtime/libfuzzer.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/libfuzzer.go rename to contrib/go/_std_1.23/src/runtime/libfuzzer.go diff --git a/contrib/go/_std_1.22/src/runtime/libfuzzer_amd64.s b/contrib/go/_std_1.23/src/runtime/libfuzzer_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/libfuzzer_amd64.s rename to contrib/go/_std_1.23/src/runtime/libfuzzer_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/libfuzzer_arm64.s b/contrib/go/_std_1.23/src/runtime/libfuzzer_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/libfuzzer_arm64.s rename to contrib/go/_std_1.23/src/runtime/libfuzzer_arm64.s diff --git a/contrib/go/_std_1.23/src/runtime/linkname.go b/contrib/go/_std_1.23/src/runtime/linkname.go new file mode 100644 index 000000000000..dd7f67425103 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/linkname.go @@ -0,0 +1,34 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import _ "unsafe" + +// used in internal/godebug and syscall +//go:linkname write + +// used by cgo +//go:linkname _cgo_panic_internal +//go:linkname cgoAlwaysFalse +//go:linkname cgoUse +//go:linkname cgoCheckPointer +//go:linkname cgoCheckResult +//go:linkname cgoNoCallback +//go:linkname gobytes +//go:linkname gostringn + +// used in plugin +//go:linkname doInit + +// used in math/bits +//go:linkname overflowError +//go:linkname divideError + +// used in tests +//go:linkname extraMInUse +//go:linkname blockevent +//go:linkname haveHighResSleep +//go:linkname blockUntilEmptyFinalizerQueue +//go:linkname lockedOSThread diff --git a/contrib/go/_std_1.23/src/runtime/linkname_unix.go b/contrib/go/_std_1.23/src/runtime/linkname_unix.go new file mode 100644 index 000000000000..65f876fa4baf --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/linkname_unix.go @@ -0,0 +1,12 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package runtime + +import _ "unsafe" + +// used in internal/syscall/unix +//go:linkname fcntl diff --git a/contrib/go/_std_1.22/src/runtime/lock_futex.go b/contrib/go/_std_1.23/src/runtime/lock_futex.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/lock_futex.go rename to contrib/go/_std_1.23/src/runtime/lock_futex.go index 867e2b34d066..58690e45e4d5 100644 --- a/contrib/go/_std_1.22/src/runtime/lock_futex.go +++ b/contrib/go/_std_1.23/src/runtime/lock_futex.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/lock_js.go b/contrib/go/_std_1.23/src/runtime/lock_js.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/lock_js.go rename to contrib/go/_std_1.23/src/runtime/lock_js.go diff --git a/contrib/go/_std_1.22/src/runtime/lock_sema.go b/contrib/go/_std_1.23/src/runtime/lock_sema.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/lock_sema.go rename to contrib/go/_std_1.23/src/runtime/lock_sema.go index 073e7d410e4c..32d2235ad3ab 100644 --- a/contrib/go/_std_1.22/src/runtime/lock_sema.go +++ b/contrib/go/_std_1.23/src/runtime/lock_sema.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/lock_wasip1.go b/contrib/go/_std_1.23/src/runtime/lock_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/lock_wasip1.go rename to contrib/go/_std_1.23/src/runtime/lock_wasip1.go diff --git a/contrib/go/_std_1.23/src/runtime/lockrank.go b/contrib/go/_std_1.23/src/runtime/lockrank.go new file mode 100644 index 000000000000..373838332f56 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/lockrank.go @@ -0,0 +1,227 @@ +// Code generated by mklockrank.go; DO NOT EDIT. + +package runtime + +type lockRank int + +// Constants representing the ranks of all non-leaf runtime locks, in rank order. +// Locks with lower rank must be taken before locks with higher rank, +// in addition to satisfying the partial order in lockPartialOrder. +// A few ranks allow self-cycles, which are specified in lockPartialOrder. +const ( + lockRankUnknown lockRank = iota + + lockRankSysmon + lockRankScavenge + lockRankForcegc + lockRankDefer + lockRankSweepWaiters + lockRankAssistQueue + lockRankStrongFromWeakQueue + lockRankSweep + lockRankTestR + lockRankTestW + lockRankTimerSend + lockRankAllocmW + lockRankExecW + lockRankCpuprof + lockRankPollCache + lockRankPollDesc + lockRankWakeableSleep + lockRankHchan + // SCHED + lockRankAllocmR + lockRankExecR + lockRankSched + lockRankAllg + lockRankAllp + lockRankNotifyList + lockRankSudog + lockRankTimers + lockRankTimer + lockRankNetpollInit + lockRankRoot + lockRankItab + lockRankReflectOffs + lockRankUserArenaState + // TRACEGLOBAL + lockRankTraceBuf + lockRankTraceStrings + // MALLOC + lockRankFin + lockRankSpanSetSpine + lockRankMspanSpecial + lockRankTraceTypeTab + // MPROF + lockRankGcBitsArenas + lockRankProfInsert + lockRankProfBlock + lockRankProfMemActive + lockRankProfMemFuture + // STACKGROW + lockRankGscan + lockRankStackpool + lockRankStackLarge + lockRankHchanLeaf + // WB + lockRankWbufSpans + lockRankMheap + lockRankMheapSpecial + lockRankGlobalAlloc + // TRACE + lockRankTrace + lockRankTraceStackTab + lockRankPanic + lockRankDeadlock + lockRankRaceFini + lockRankAllocmRInternal + lockRankExecRInternal + lockRankTestRInternal +) + +// lockRankLeafRank is the rank of lock that does not have a declared rank, +// and hence is a leaf lock. +const lockRankLeafRank lockRank = 1000 + +// lockNames gives the names associated with each of the above ranks. +var lockNames = []string{ + lockRankSysmon: "sysmon", + lockRankScavenge: "scavenge", + lockRankForcegc: "forcegc", + lockRankDefer: "defer", + lockRankSweepWaiters: "sweepWaiters", + lockRankAssistQueue: "assistQueue", + lockRankStrongFromWeakQueue: "strongFromWeakQueue", + lockRankSweep: "sweep", + lockRankTestR: "testR", + lockRankTestW: "testW", + lockRankTimerSend: "timerSend", + lockRankAllocmW: "allocmW", + lockRankExecW: "execW", + lockRankCpuprof: "cpuprof", + lockRankPollCache: "pollCache", + lockRankPollDesc: "pollDesc", + lockRankWakeableSleep: "wakeableSleep", + lockRankHchan: "hchan", + lockRankAllocmR: "allocmR", + lockRankExecR: "execR", + lockRankSched: "sched", + lockRankAllg: "allg", + lockRankAllp: "allp", + lockRankNotifyList: "notifyList", + lockRankSudog: "sudog", + lockRankTimers: "timers", + lockRankTimer: "timer", + lockRankNetpollInit: "netpollInit", + lockRankRoot: "root", + lockRankItab: "itab", + lockRankReflectOffs: "reflectOffs", + lockRankUserArenaState: "userArenaState", + lockRankTraceBuf: "traceBuf", + lockRankTraceStrings: "traceStrings", + lockRankFin: "fin", + lockRankSpanSetSpine: "spanSetSpine", + lockRankMspanSpecial: "mspanSpecial", + lockRankTraceTypeTab: "traceTypeTab", + lockRankGcBitsArenas: "gcBitsArenas", + lockRankProfInsert: "profInsert", + lockRankProfBlock: "profBlock", + lockRankProfMemActive: "profMemActive", + lockRankProfMemFuture: "profMemFuture", + lockRankGscan: "gscan", + lockRankStackpool: "stackpool", + lockRankStackLarge: "stackLarge", + lockRankHchanLeaf: "hchanLeaf", + lockRankWbufSpans: "wbufSpans", + lockRankMheap: "mheap", + lockRankMheapSpecial: "mheapSpecial", + lockRankGlobalAlloc: "globalAlloc", + lockRankTrace: "trace", + lockRankTraceStackTab: "traceStackTab", + lockRankPanic: "panic", + lockRankDeadlock: "deadlock", + lockRankRaceFini: "raceFini", + lockRankAllocmRInternal: "allocmRInternal", + lockRankExecRInternal: "execRInternal", + lockRankTestRInternal: "testRInternal", +} + +func (rank lockRank) String() string { + if rank == 0 { + return "UNKNOWN" + } + if rank == lockRankLeafRank { + return "LEAF" + } + if rank < 0 || int(rank) >= len(lockNames) { + return "BAD RANK" + } + return lockNames[rank] +} + +// lockPartialOrder is the transitive closure of the lock rank graph. +// An entry for rank X lists all of the ranks that can already be held +// when rank X is acquired. +// +// Lock ranks that allow self-cycles list themselves. +var lockPartialOrder [][]lockRank = [][]lockRank{ + lockRankSysmon: {}, + lockRankScavenge: {lockRankSysmon}, + lockRankForcegc: {lockRankSysmon}, + lockRankDefer: {}, + lockRankSweepWaiters: {}, + lockRankAssistQueue: {}, + lockRankStrongFromWeakQueue: {}, + lockRankSweep: {}, + lockRankTestR: {}, + lockRankTestW: {}, + lockRankTimerSend: {}, + lockRankAllocmW: {}, + lockRankExecW: {}, + lockRankCpuprof: {}, + lockRankPollCache: {}, + lockRankPollDesc: {}, + lockRankWakeableSleep: {}, + lockRankHchan: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan}, + lockRankAllocmR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan}, + lockRankExecR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan}, + lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR}, + lockRankAllg: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched}, + lockRankAllp: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched}, + lockRankNotifyList: {}, + lockRankSudog: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList}, + lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers}, + lockRankTimer: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers}, + lockRankNetpollInit: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers, lockRankTimer}, + lockRankRoot: {}, + lockRankItab: {}, + lockRankReflectOffs: {lockRankItab}, + lockRankUserArenaState: {}, + lockRankTraceBuf: {lockRankSysmon, lockRankScavenge}, + lockRankTraceStrings: {lockRankSysmon, lockRankScavenge, lockRankTraceBuf}, + lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankTraceTypeTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial}, + lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive}, + lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture}, + lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf}, + lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans}, + lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, + lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial}, + lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, + lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace}, + lockRankPanic: {}, + lockRankDeadlock: {lockRankPanic, lockRankDeadlock}, + lockRankRaceFini: {lockRankPanic}, + lockRankAllocmRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankAllocmW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR}, + lockRankExecRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankExecR}, + lockRankTestRInternal: {lockRankTestR, lockRankTestW}, +} diff --git a/contrib/go/_std_1.22/src/runtime/lockrank_off.go b/contrib/go/_std_1.23/src/runtime/lockrank_off.go similarity index 84% rename from contrib/go/_std_1.22/src/runtime/lockrank_off.go rename to contrib/go/_std_1.23/src/runtime/lockrank_off.go index c86726f3dd7d..18aef6bd2b3f 100644 --- a/contrib/go/_std_1.22/src/runtime/lockrank_off.go +++ b/contrib/go/_std_1.23/src/runtime/lockrank_off.go @@ -27,7 +27,8 @@ func lockWithRank(l *mutex, rank lockRank) { // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func acquireLockRank(rank lockRank) { +func acquireLockRankAndM(rank lockRank) { + acquirem() } func unlockWithRank(l *mutex) { @@ -37,9 +38,13 @@ func unlockWithRank(l *mutex) { // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func releaseLockRank(rank lockRank) { +func releaseLockRankAndM(rank lockRank) { + releasem(getg().m) } +// This function may be called in nosplit context and thus must be nosplit. +// +//go:nosplit func lockWithRankMayAcquire(l *mutex, rank lockRank) { } diff --git a/contrib/go/_std_1.22/src/runtime/lockrank_on.go b/contrib/go/_std_1.23/src/runtime/lockrank_on.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/lockrank_on.go rename to contrib/go/_std_1.23/src/runtime/lockrank_on.go index b1d99997947a..120ebc21fae5 100644 --- a/contrib/go/_std_1.22/src/runtime/lockrank_on.go +++ b/contrib/go/_std_1.23/src/runtime/lockrank_on.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -104,12 +104,16 @@ func printHeldLocks(gp *g) { } } -// acquireLockRank acquires a rank which is not associated with a mutex lock +// acquireLockRankAndM acquires a rank which is not associated with a mutex +// lock. To maintain the invariant that an M with m.locks==0 does not hold any +// lock-like resources, it also acquires the M. // // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func acquireLockRank(rank lockRank) { +func acquireLockRankAndM(rank lockRank) { + acquirem() + gp := getg() // Log the new class. See comment on lockWithRank. systemstack(func() { @@ -189,12 +193,14 @@ func unlockWithRank(l *mutex) { }) } -// releaseLockRank releases a rank which is not associated with a mutex lock +// releaseLockRankAndM releases a rank which is not associated with a mutex +// lock. To maintain the invariant that an M with m.locks==0 does not hold any +// lock-like resources, it also releases the M. // // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func releaseLockRank(rank lockRank) { +func releaseLockRankAndM(rank lockRank) { gp := getg() systemstack(func() { found := false @@ -211,6 +217,8 @@ func releaseLockRank(rank lockRank) { throw("lockRank release without matching lockRank acquire") } }) + + releasem(getg().m) } // nosplit because it may be called from nosplit contexts. diff --git a/contrib/go/_std_1.22/src/runtime/malloc.go b/contrib/go/_std_1.23/src/runtime/malloc.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/malloc.go rename to contrib/go/_std_1.23/src/runtime/malloc.go index e2cb2e456e86..b92a213245d4 100644 --- a/contrib/go/_std_1.22/src/runtime/malloc.go +++ b/contrib/go/_std_1.23/src/runtime/malloc.go @@ -102,9 +102,8 @@ package runtime import ( "internal/goarch" - "internal/goexperiment" "internal/goos" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/math" "runtime/internal/sys" "unsafe" @@ -425,26 +424,24 @@ func mallocinit() { print("pagesPerArena (", pagesPerArena, ") is not divisible by pagesPerReclaimerChunk (", pagesPerReclaimerChunk, ")\n") throw("bad pagesPerReclaimerChunk") } - if goexperiment.AllocHeaders { - // Check that the minimum size (exclusive) for a malloc header is also - // a size class boundary. This is important to making sure checks align - // across different parts of the runtime. - minSizeForMallocHeaderIsSizeClass := false - for i := 0; i < len(class_to_size); i++ { - if minSizeForMallocHeader == uintptr(class_to_size[i]) { - minSizeForMallocHeaderIsSizeClass = true - break - } - } - if !minSizeForMallocHeaderIsSizeClass { - throw("min size of malloc header is not a size class boundary") - } - // Check that the pointer bitmap for all small sizes without a malloc header - // fits in a word. - if minSizeForMallocHeader/goarch.PtrSize > 8*goarch.PtrSize { - throw("max pointer/scan bitmap size for headerless objects is too large") + // Check that the minimum size (exclusive) for a malloc header is also + // a size class boundary. This is important to making sure checks align + // across different parts of the runtime. + minSizeForMallocHeaderIsSizeClass := false + for i := 0; i < len(class_to_size); i++ { + if minSizeForMallocHeader == uintptr(class_to_size[i]) { + minSizeForMallocHeaderIsSizeClass = true + break } } + if !minSizeForMallocHeaderIsSizeClass { + throw("min size of malloc header is not a size class boundary") + } + // Check that the pointer bitmap for all small sizes without a malloc header + // fits in a word. + if minSizeForMallocHeader/goarch.PtrSize > 8*goarch.PtrSize { + throw("max pointer/scan bitmap size for headerless objects is too large") + } if minTagBits > taggedPointerBits { throw("taggedPointerbits too small") @@ -968,6 +965,21 @@ func (c *mcache) nextFree(spc spanClass) (v gclinkptr, s *mspan, shouldhelpgc bo // Allocate an object of size bytes. // Small objects are allocated from the per-P cache's free lists. // Large objects (> 32 kB) are allocated straight from the heap. +// +// mallocgc should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/cockroachdb/cockroach +// - github.com/cockroachdb/pebble +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mallocgc func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { if gcphase == _GCmarktermination { throw("mallocgc called with gcphase == _GCmarktermination") @@ -1043,7 +1055,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { var span *mspan var header **_type var x unsafe.Pointer - noscan := typ == nil || typ.PtrBytes == 0 + noscan := typ == nil || !typ.Pointers() // In some cases block zeroing can profitably (for latency reduction purposes) // be delayed till preemption is possible; delayedZeroing tracks that state. delayedZeroing := false @@ -1132,7 +1144,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { size = maxTinySize } else { hasHeader := !noscan && !heapBitsInSpan(size) - if goexperiment.AllocHeaders && hasHeader { + if hasHeader { size += mallocHeaderSize } var sizeclass uint8 @@ -1152,7 +1164,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { if needzero && span.needzero != 0 { memclrNoHeapPointers(x, size) } - if goexperiment.AllocHeaders && hasHeader { + if hasHeader { header = (**_type)(x) x = add(x, mallocHeaderSize) size -= mallocHeaderSize @@ -1168,34 +1180,16 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { size = span.elemsize x = unsafe.Pointer(span.base()) if needzero && span.needzero != 0 { - if noscan { - delayedZeroing = true - } else { - memclrNoHeapPointers(x, size) - } + delayedZeroing = true } - if goexperiment.AllocHeaders && !noscan { + if !noscan { + // Tell the GC not to look at this yet. + span.largeType = nil header = &span.largeType } } - if !noscan { - if goexperiment.AllocHeaders { - c.scanAlloc += heapSetType(uintptr(x), dataSize, typ, header, span) - } else { - var scanSize uintptr - heapBitsSetType(uintptr(x), size, dataSize, typ) - if dataSize > typ.Size_ { - // Array allocation. If there are any - // pointers, GC has to scan to the last - // element. - if typ.PtrBytes != 0 { - scanSize = dataSize - typ.Size_ + typ.PtrBytes - } - } else { - scanSize = typ.PtrBytes - } - c.scanAlloc += scanSize - } + if !noscan && !delayedZeroing { + c.scanAlloc += heapSetType(uintptr(x), dataSize, typ, header, span) } // Ensure that the stores above that initialize x to @@ -1243,19 +1237,11 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { asanunpoison(x, userSize) } - // If !goexperiment.AllocHeaders, "size" doesn't include the - // allocation header, so use span.elemsize as the "full" size - // for various computations below. - // // TODO(mknyszek): We should really count the header as part - // of gc_sys or something, but it's risky to change the - // accounting so much right now. Just pretend its internal - // fragmentation and match the GC's accounting by using the - // whole allocation slot. - fullSize := size - if goexperiment.AllocHeaders { - fullSize = span.elemsize - } + // of gc_sys or something. The code below just pretends it is + // internal fragmentation and matches the GC's accounting by + // using the whole allocation slot. + fullSize := span.elemsize if rate := MemProfileRate; rate > 0 { // Note cache c only valid while m acquired; see #47302 // @@ -1270,28 +1256,38 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { mp.mallocing = 0 releasem(mp) - // Pointerfree data can be zeroed late in a context where preemption can occur. + // Objects can be zeroed late in a context where preemption can occur. + // If the object contains pointers, its pointer data must be cleared + // or otherwise indicate that the GC shouldn't scan it. // x will keep the memory alive. if delayedZeroing { - if !noscan { - throw("delayed zeroing on data that may contain pointers") - } - if goexperiment.AllocHeaders && header != nil { - throw("unexpected malloc header in delayed zeroing of large object") - } // N.B. size == fullSize always in this case. memclrNoHeapPointersChunked(size, x) // This is a possible preemption point: see #47302 - } - if debug.malloc { - if debug.allocfreetrace != 0 { - tracealloc(x, size, typ) + // Finish storing the type information for this case. + if !noscan { + mp := acquirem() + getMCache(mp).scanAlloc += heapSetType(uintptr(x), dataSize, typ, header, span) + + // Publish the type information with the zeroed memory. + publicationBarrier() + releasem(mp) } + } + if debug.malloc { if inittrace.active && inittrace.id == getg().goid { // Init functions are executed sequentially in a single goroutine. inittrace.bytes += uint64(fullSize) } + + if traceAllocFreeEnabled() { + trace := traceAcquire() + if trace.ok() { + trace.HeapObjectAlloc(uintptr(x), typ) + traceRelease(trace) + } + } } if assistG != nil { @@ -1390,6 +1386,17 @@ func newobject(typ *_type) unsafe.Pointer { return mallocgc(typ.Size_, typ, true) } +// reflect_unsafe_New is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/goccy/json +// - github.com/modern-go/reflect2 +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_unsafe_New reflect.unsafe_New func reflect_unsafe_New(typ *_type) unsafe.Pointer { return mallocgc(typ.Size_, typ, true) @@ -1401,6 +1408,18 @@ func reflectlite_unsafe_New(typ *_type) unsafe.Pointer { } // newarray allocates an array of n elements of type typ. +// +// newarray should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname newarray func newarray(typ *_type, n int) unsafe.Pointer { if n == 1 { return mallocgc(typ.Size_, typ, true) @@ -1412,6 +1431,20 @@ func newarray(typ *_type, n int) unsafe.Pointer { return mallocgc(mem, typ, true) } +// reflect_unsafe_NewArray is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/bytedance/sonic +// - github.com/goccy/json +// - github.com/modern-go/reflect2 +// - github.com/segmentio/encoding +// - github.com/segmentio/kafka-go +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_unsafe_NewArray reflect.unsafe_NewArray func reflect_unsafe_NewArray(typ *_type, n int) unsafe.Pointer { return newarray(typ, n) @@ -1423,7 +1456,7 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) { throw("profilealloc called without a P or outside bootstrapping") } c.nextSample = nextSample() - mProf_Malloc(x, size) + mProf_Malloc(mp, x, size) } // nextSample returns the next sampling point for heap profiling. The goal is diff --git a/contrib/go/_std_1.23/src/runtime/map.go b/contrib/go/_std_1.23/src/runtime/map.go new file mode 100644 index 000000000000..52d56fb57a4d --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/map.go @@ -0,0 +1,1911 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +// This file contains the implementation of Go's map type. +// +// A map is just a hash table. The data is arranged +// into an array of buckets. Each bucket contains up to +// 8 key/elem pairs. The low-order bits of the hash are +// used to select a bucket. Each bucket contains a few +// high-order bits of each hash to distinguish the entries +// within a single bucket. +// +// If more than 8 keys hash to a bucket, we chain on +// extra buckets. +// +// When the hashtable grows, we allocate a new array +// of buckets twice as big. Buckets are incrementally +// copied from the old bucket array to the new bucket array. +// +// Map iterators walk through the array of buckets and +// return the keys in walk order (bucket #, then overflow +// chain order, then bucket index). To maintain iteration +// semantics, we never move keys within their bucket (if +// we did, keys might be returned 0 or 2 times). When +// growing the table, iterators remain iterating through the +// old table and must check the new table if the bucket +// they are iterating through has been moved ("evacuated") +// to the new table. + +// Picking loadFactor: too large and we have lots of overflow +// buckets, too small and we waste a lot of space. I wrote +// a simple program to check some stats for different loads: +// (64-bit, 8 byte keys and elems) +// loadFactor %overflow bytes/entry hitprobe missprobe +// 4.00 2.13 20.77 3.00 4.00 +// 4.50 4.05 17.30 3.25 4.50 +// 5.00 6.85 14.77 3.50 5.00 +// 5.50 10.55 12.94 3.75 5.50 +// 6.00 15.27 11.67 4.00 6.00 +// 6.50 20.90 10.79 4.25 6.50 +// 7.00 27.14 10.15 4.50 7.00 +// 7.50 34.03 9.73 4.75 7.50 +// 8.00 41.10 9.40 5.00 8.00 +// +// %overflow = percentage of buckets which have an overflow bucket +// bytes/entry = overhead bytes used per key/elem pair +// hitprobe = # of entries to check when looking up a present key +// missprobe = # of entries to check when looking up an absent key +// +// Keep in mind this data is for maximally loaded tables, i.e. just +// before the table grows. Typical tables will be somewhat less loaded. + +import ( + "internal/abi" + "internal/goarch" + "internal/runtime/atomic" + "runtime/internal/math" + "unsafe" +) + +const ( + // Maximum number of key/elem pairs a bucket can hold. + bucketCntBits = abi.MapBucketCountBits + + // Maximum average load of a bucket that triggers growth is bucketCnt*13/16 (about 80% full) + // Because of minimum alignment rules, bucketCnt is known to be at least 8. + // Represent as loadFactorNum/loadFactorDen, to allow integer math. + loadFactorDen = 2 + loadFactorNum = loadFactorDen * abi.MapBucketCount * 13 / 16 + + // data offset should be the size of the bmap struct, but needs to be + // aligned correctly. For amd64p32 this means 64-bit alignment + // even though pointers are 32 bit. + dataOffset = unsafe.Offsetof(struct { + b bmap + v int64 + }{}.v) + + // Possible tophash values. We reserve a few possibilities for special marks. + // Each bucket (including its overflow buckets, if any) will have either all or none of its + // entries in the evacuated* states (except during the evacuate() method, which only happens + // during map writes and thus no one else can observe the map during that time). + emptyRest = 0 // this cell is empty, and there are no more non-empty cells at higher indexes or overflows. + emptyOne = 1 // this cell is empty + evacuatedX = 2 // key/elem is valid. Entry has been evacuated to first half of larger table. + evacuatedY = 3 // same as above, but evacuated to second half of larger table. + evacuatedEmpty = 4 // cell is empty, bucket is evacuated. + minTopHash = 5 // minimum tophash for a normal filled cell. + + // flags + iterator = 1 // there may be an iterator using buckets + oldIterator = 2 // there may be an iterator using oldbuckets + hashWriting = 4 // a goroutine is writing to the map + sameSizeGrow = 8 // the current map growth is to a new map of the same size + + // sentinel bucket ID for iterator checks + noCheck = 1<<(8*goarch.PtrSize) - 1 +) + +// isEmpty reports whether the given tophash array entry represents an empty bucket entry. +func isEmpty(x uint8) bool { + return x <= emptyOne +} + +// A header for a Go map. +type hmap struct { + // Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go. + // Make sure this stays in sync with the compiler's definition. + count int // # live cells == size of map. Must be first (used by len() builtin) + flags uint8 + B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items) + noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details + hash0 uint32 // hash seed + + buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. + oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing + nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated) + + extra *mapextra // optional fields +} + +// mapextra holds fields that are not present on all maps. +type mapextra struct { + // If both key and elem do not contain pointers and are inline, then we mark bucket + // type as containing no pointers. This avoids scanning such maps. + // However, bmap.overflow is a pointer. In order to keep overflow buckets + // alive, we store pointers to all overflow buckets in hmap.extra.overflow and hmap.extra.oldoverflow. + // overflow and oldoverflow are only used if key and elem do not contain pointers. + // overflow contains overflow buckets for hmap.buckets. + // oldoverflow contains overflow buckets for hmap.oldbuckets. + // The indirection allows to store a pointer to the slice in hiter. + overflow *[]*bmap + oldoverflow *[]*bmap + + // nextOverflow holds a pointer to a free overflow bucket. + nextOverflow *bmap +} + +// A bucket for a Go map. +type bmap struct { + // tophash generally contains the top byte of the hash value + // for each key in this bucket. If tophash[0] < minTopHash, + // tophash[0] is a bucket evacuation state instead. + tophash [abi.MapBucketCount]uint8 + // Followed by bucketCnt keys and then bucketCnt elems. + // NOTE: packing all the keys together and then all the elems together makes the + // code a bit more complicated than alternating key/elem/key/elem/... but it allows + // us to eliminate padding which would be needed for, e.g., map[int64]int8. + // Followed by an overflow pointer. +} + +// A hash iteration structure. +// If you modify hiter, also change cmd/compile/internal/reflectdata/reflect.go +// and reflect/value.go to match the layout of this structure. +type hiter struct { + key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/compile/internal/walk/range.go). + elem unsafe.Pointer // Must be in second position (see cmd/compile/internal/walk/range.go). + t *maptype + h *hmap + buckets unsafe.Pointer // bucket ptr at hash_iter initialization time + bptr *bmap // current bucket + overflow *[]*bmap // keeps overflow buckets of hmap.buckets alive + oldoverflow *[]*bmap // keeps overflow buckets of hmap.oldbuckets alive + startBucket uintptr // bucket iteration started at + offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1) + wrapped bool // already wrapped around from end of bucket array to beginning + B uint8 + i uint8 + bucket uintptr + checkBucket uintptr +} + +// bucketShift returns 1<> (goarch.PtrSize*8 - 8)) + if top < minTopHash { + top += minTopHash + } + return top +} + +func evacuated(b *bmap) bool { + h := b.tophash[0] + return h > emptyOne && h < minTopHash +} + +func (b *bmap) overflow(t *maptype) *bmap { + return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.BucketSize)-goarch.PtrSize)) +} + +func (b *bmap) setoverflow(t *maptype, ovf *bmap) { + *(**bmap)(add(unsafe.Pointer(b), uintptr(t.BucketSize)-goarch.PtrSize)) = ovf +} + +func (b *bmap) keys() unsafe.Pointer { + return add(unsafe.Pointer(b), dataOffset) +} + +// incrnoverflow increments h.noverflow. +// noverflow counts the number of overflow buckets. +// This is used to trigger same-size map growth. +// See also tooManyOverflowBuckets. +// To keep hmap small, noverflow is a uint16. +// When there are few buckets, noverflow is an exact count. +// When there are many buckets, noverflow is an approximate count. +func (h *hmap) incrnoverflow() { + // We trigger same-size map growth if there are + // as many overflow buckets as buckets. + // We need to be able to count to 1< maxAlloc { + hint = 0 + } + + // initialize Hmap + if h == nil { + h = new(hmap) + } + h.hash0 = uint32(rand()) + + // Find the size parameter B which will hold the requested # of elements. + // For hint < 0 overLoadFactor returns false since hint < bucketCnt. + B := uint8(0) + for overLoadFactor(hint, B) { + B++ + } + h.B = B + + // allocate initial hash table + // if B == 0, the buckets field is allocated lazily later (in mapassign) + // If hint is large zeroing this memory could take a while. + if h.B != 0 { + var nextOverflow *bmap + h.buckets, nextOverflow = makeBucketArray(t, h.B, nil) + if nextOverflow != nil { + h.extra = new(mapextra) + h.extra.nextOverflow = nextOverflow + } + } + + return h +} + +// makeBucketArray initializes a backing array for map buckets. +// 1<= 4 { + // Add on the estimated number of overflow buckets + // required to insert the median number of elements + // used with this value of b. + nbuckets += bucketShift(b - 4) + sz := t.Bucket.Size_ * nbuckets + up := roundupsize(sz, !t.Bucket.Pointers()) + if up != sz { + nbuckets = up / t.Bucket.Size_ + } + } + + if dirtyalloc == nil { + buckets = newarray(t.Bucket, int(nbuckets)) + } else { + // dirtyalloc was previously generated by + // the above newarray(t.Bucket, int(nbuckets)) + // but may not be empty. + buckets = dirtyalloc + size := t.Bucket.Size_ * nbuckets + if t.Bucket.Pointers() { + memclrHasPointers(buckets, size) + } else { + memclrNoHeapPointers(buckets, size) + } + } + + if base != nbuckets { + // We preallocated some overflow buckets. + // To keep the overhead of tracking these overflow buckets to a minimum, + // we use the convention that if a preallocated overflow bucket's overflow + // pointer is nil, then there are more available by bumping the pointer. + // We need a safe non-nil pointer for the last overflow bucket; just use buckets. + nextOverflow = (*bmap)(add(buckets, base*uintptr(t.BucketSize))) + last := (*bmap)(add(buckets, (nbuckets-1)*uintptr(t.BucketSize))) + last.setoverflow(t, (*bmap)(buckets)) + } + return buckets, nextOverflow +} + +// mapaccess1 returns a pointer to h[key]. Never returns nil, instead +// it will return a reference to the zero object for the elem type if +// the key is not in the map. +// NOTE: The returned pointer may keep the whole map live, so don't +// hold onto it for very long. +func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { + if raceenabled && h != nil { + callerpc := getcallerpc() + pc := abi.FuncPCABIInternal(mapaccess1) + racereadpc(unsafe.Pointer(h), callerpc, pc) + raceReadObjectPC(t.Key, key, callerpc, pc) + } + if msanenabled && h != nil { + msanread(key, t.Key.Size_) + } + if asanenabled && h != nil { + asanread(key, t.Key.Size_) + } + if h == nil || h.count == 0 { + if err := mapKeyError(t, key); err != nil { + panic(err) // see issue 23734 + } + return unsafe.Pointer(&zeroVal[0]) + } + if h.flags&hashWriting != 0 { + fatal("concurrent map read and map write") + } + hash := t.Hasher(key, uintptr(h.hash0)) + m := bucketMask(h.B) + b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.BucketSize))) + if c := h.oldbuckets; c != nil { + if !h.sameSizeGrow() { + // There used to be half as many buckets; mask down one more power of two. + m >>= 1 + } + oldb := (*bmap)(add(c, (hash&m)*uintptr(t.BucketSize))) + if !evacuated(oldb) { + b = oldb + } + } + top := tophash(hash) +bucketloop: + for ; b != nil; b = b.overflow(t) { + for i := uintptr(0); i < abi.MapBucketCount; i++ { + if b.tophash[i] != top { + if b.tophash[i] == emptyRest { + break bucketloop + } + continue + } + k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) + if t.IndirectKey() { + k = *((*unsafe.Pointer)(k)) + } + if t.Key.Equal(key, k) { + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + if t.IndirectElem() { + e = *((*unsafe.Pointer)(e)) + } + return e + } + } + } + return unsafe.Pointer(&zeroVal[0]) +} + +// mapaccess2 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapaccess2 +func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) { + if raceenabled && h != nil { + callerpc := getcallerpc() + pc := abi.FuncPCABIInternal(mapaccess2) + racereadpc(unsafe.Pointer(h), callerpc, pc) + raceReadObjectPC(t.Key, key, callerpc, pc) + } + if msanenabled && h != nil { + msanread(key, t.Key.Size_) + } + if asanenabled && h != nil { + asanread(key, t.Key.Size_) + } + if h == nil || h.count == 0 { + if err := mapKeyError(t, key); err != nil { + panic(err) // see issue 23734 + } + return unsafe.Pointer(&zeroVal[0]), false + } + if h.flags&hashWriting != 0 { + fatal("concurrent map read and map write") + } + hash := t.Hasher(key, uintptr(h.hash0)) + m := bucketMask(h.B) + b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.BucketSize))) + if c := h.oldbuckets; c != nil { + if !h.sameSizeGrow() { + // There used to be half as many buckets; mask down one more power of two. + m >>= 1 + } + oldb := (*bmap)(add(c, (hash&m)*uintptr(t.BucketSize))) + if !evacuated(oldb) { + b = oldb + } + } + top := tophash(hash) +bucketloop: + for ; b != nil; b = b.overflow(t) { + for i := uintptr(0); i < abi.MapBucketCount; i++ { + if b.tophash[i] != top { + if b.tophash[i] == emptyRest { + break bucketloop + } + continue + } + k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) + if t.IndirectKey() { + k = *((*unsafe.Pointer)(k)) + } + if t.Key.Equal(key, k) { + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + if t.IndirectElem() { + e = *((*unsafe.Pointer)(e)) + } + return e, true + } + } + } + return unsafe.Pointer(&zeroVal[0]), false +} + +// returns both key and elem. Used by map iterator. +func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe.Pointer) { + if h == nil || h.count == 0 { + return nil, nil + } + hash := t.Hasher(key, uintptr(h.hash0)) + m := bucketMask(h.B) + b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.BucketSize))) + if c := h.oldbuckets; c != nil { + if !h.sameSizeGrow() { + // There used to be half as many buckets; mask down one more power of two. + m >>= 1 + } + oldb := (*bmap)(add(c, (hash&m)*uintptr(t.BucketSize))) + if !evacuated(oldb) { + b = oldb + } + } + top := tophash(hash) +bucketloop: + for ; b != nil; b = b.overflow(t) { + for i := uintptr(0); i < abi.MapBucketCount; i++ { + if b.tophash[i] != top { + if b.tophash[i] == emptyRest { + break bucketloop + } + continue + } + k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) + if t.IndirectKey() { + k = *((*unsafe.Pointer)(k)) + } + if t.Key.Equal(key, k) { + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + if t.IndirectElem() { + e = *((*unsafe.Pointer)(e)) + } + return k, e + } + } + } + return nil, nil +} + +func mapaccess1_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) unsafe.Pointer { + e := mapaccess1(t, h, key) + if e == unsafe.Pointer(&zeroVal[0]) { + return zero + } + return e +} + +func mapaccess2_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) (unsafe.Pointer, bool) { + e := mapaccess1(t, h, key) + if e == unsafe.Pointer(&zeroVal[0]) { + return zero, false + } + return e, true +} + +// Like mapaccess, but allocates a slot for the key if it is not present in the map. +// +// mapassign should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign +func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { + if h == nil { + panic(plainError("assignment to entry in nil map")) + } + if raceenabled { + callerpc := getcallerpc() + pc := abi.FuncPCABIInternal(mapassign) + racewritepc(unsafe.Pointer(h), callerpc, pc) + raceReadObjectPC(t.Key, key, callerpc, pc) + } + if msanenabled { + msanread(key, t.Key.Size_) + } + if asanenabled { + asanread(key, t.Key.Size_) + } + if h.flags&hashWriting != 0 { + fatal("concurrent map writes") + } + hash := t.Hasher(key, uintptr(h.hash0)) + + // Set hashWriting after calling t.hasher, since t.hasher may panic, + // in which case we have not actually done a write. + h.flags ^= hashWriting + + if h.buckets == nil { + h.buckets = newobject(t.Bucket) // newarray(t.Bucket, 1) + } + +again: + bucket := hash & bucketMask(h.B) + if h.growing() { + growWork(t, h, bucket) + } + b := (*bmap)(add(h.buckets, bucket*uintptr(t.BucketSize))) + top := tophash(hash) + + var inserti *uint8 + var insertk unsafe.Pointer + var elem unsafe.Pointer +bucketloop: + for { + for i := uintptr(0); i < abi.MapBucketCount; i++ { + if b.tophash[i] != top { + if isEmpty(b.tophash[i]) && inserti == nil { + inserti = &b.tophash[i] + insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) + elem = add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + } + if b.tophash[i] == emptyRest { + break bucketloop + } + continue + } + k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) + if t.IndirectKey() { + k = *((*unsafe.Pointer)(k)) + } + if !t.Key.Equal(key, k) { + continue + } + // already have a mapping for key. Update it. + if t.NeedKeyUpdate() { + typedmemmove(t.Key, k, key) + } + elem = add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + goto done + } + ovf := b.overflow(t) + if ovf == nil { + break + } + b = ovf + } + + // Did not find mapping for key. Allocate new cell & add entry. + + // If we hit the max load factor or we have too many overflow buckets, + // and we're not already in the middle of growing, start growing. + if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { + hashGrow(t, h) + goto again // Growing the table invalidates everything, so try again + } + + if inserti == nil { + // The current bucket and all the overflow buckets connected to it are full, allocate a new one. + newb := h.newoverflow(t, b) + inserti = &newb.tophash[0] + insertk = add(unsafe.Pointer(newb), dataOffset) + elem = add(insertk, abi.MapBucketCount*uintptr(t.KeySize)) + } + + // store new key/elem at insert position + if t.IndirectKey() { + kmem := newobject(t.Key) + *(*unsafe.Pointer)(insertk) = kmem + insertk = kmem + } + if t.IndirectElem() { + vmem := newobject(t.Elem) + *(*unsafe.Pointer)(elem) = vmem + } + typedmemmove(t.Key, insertk, key) + *inserti = top + h.count++ + +done: + if h.flags&hashWriting == 0 { + fatal("concurrent map writes") + } + h.flags &^= hashWriting + if t.IndirectElem() { + elem = *((*unsafe.Pointer)(elem)) + } + return elem +} + +// mapdelete should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapdelete +func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { + if raceenabled && h != nil { + callerpc := getcallerpc() + pc := abi.FuncPCABIInternal(mapdelete) + racewritepc(unsafe.Pointer(h), callerpc, pc) + raceReadObjectPC(t.Key, key, callerpc, pc) + } + if msanenabled && h != nil { + msanread(key, t.Key.Size_) + } + if asanenabled && h != nil { + asanread(key, t.Key.Size_) + } + if h == nil || h.count == 0 { + if err := mapKeyError(t, key); err != nil { + panic(err) // see issue 23734 + } + return + } + if h.flags&hashWriting != 0 { + fatal("concurrent map writes") + } + + hash := t.Hasher(key, uintptr(h.hash0)) + + // Set hashWriting after calling t.hasher, since t.hasher may panic, + // in which case we have not actually done a write (delete). + h.flags ^= hashWriting + + bucket := hash & bucketMask(h.B) + if h.growing() { + growWork(t, h, bucket) + } + b := (*bmap)(add(h.buckets, bucket*uintptr(t.BucketSize))) + bOrig := b + top := tophash(hash) +search: + for ; b != nil; b = b.overflow(t) { + for i := uintptr(0); i < abi.MapBucketCount; i++ { + if b.tophash[i] != top { + if b.tophash[i] == emptyRest { + break search + } + continue + } + k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) + k2 := k + if t.IndirectKey() { + k2 = *((*unsafe.Pointer)(k2)) + } + if !t.Key.Equal(key, k2) { + continue + } + // Only clear key if there are pointers in it. + if t.IndirectKey() { + *(*unsafe.Pointer)(k) = nil + } else if t.Key.Pointers() { + memclrHasPointers(k, t.Key.Size_) + } + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + if t.IndirectElem() { + *(*unsafe.Pointer)(e) = nil + } else if t.Elem.Pointers() { + memclrHasPointers(e, t.Elem.Size_) + } else { + memclrNoHeapPointers(e, t.Elem.Size_) + } + b.tophash[i] = emptyOne + // If the bucket now ends in a bunch of emptyOne states, + // change those to emptyRest states. + // It would be nice to make this a separate function, but + // for loops are not currently inlineable. + if i == abi.MapBucketCount-1 { + if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { + goto notLast + } + } else { + if b.tophash[i+1] != emptyRest { + goto notLast + } + } + for { + b.tophash[i] = emptyRest + if i == 0 { + if b == bOrig { + break // beginning of initial bucket, we're done. + } + // Find previous bucket, continue at its last entry. + c := b + for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { + } + i = abi.MapBucketCount - 1 + } else { + i-- + } + if b.tophash[i] != emptyOne { + break + } + } + notLast: + h.count-- + // Reset the hash seed to make it more difficult for attackers to + // repeatedly trigger hash collisions. See issue 25237. + if h.count == 0 { + h.hash0 = uint32(rand()) + } + break search + } + } + + if h.flags&hashWriting == 0 { + fatal("concurrent map writes") + } + h.flags &^= hashWriting +} + +// mapiterinit initializes the hiter struct used for ranging over maps. +// The hiter struct pointed to by 'it' is allocated on the stack +// by the compilers order pass or on the heap by reflect_mapiterinit. +// Both need to have zeroed hiter since the struct contains pointers. +// +// mapiterinit should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/goccy/go-json +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapiterinit +func mapiterinit(t *maptype, h *hmap, it *hiter) { + if raceenabled && h != nil { + callerpc := getcallerpc() + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapiterinit)) + } + + it.t = t + if h == nil || h.count == 0 { + return + } + + if unsafe.Sizeof(hiter{})/goarch.PtrSize != 12 { + throw("hash_iter size incorrect") // see cmd/compile/internal/reflectdata/reflect.go + } + it.h = h + + // grab snapshot of bucket state + it.B = h.B + it.buckets = h.buckets + if !t.Bucket.Pointers() { + // Allocate the current slice and remember pointers to both current and old. + // This preserves all relevant overflow buckets alive even if + // the table grows and/or overflow buckets are added to the table + // while we are iterating. + h.createOverflow() + it.overflow = h.extra.overflow + it.oldoverflow = h.extra.oldoverflow + } + + // decide where to start + r := uintptr(rand()) + it.startBucket = r & bucketMask(h.B) + it.offset = uint8(r >> h.B & (abi.MapBucketCount - 1)) + + // iterator state + it.bucket = it.startBucket + + // Remember we have an iterator. + // Can run concurrently with another mapiterinit(). + if old := h.flags; old&(iterator|oldIterator) != iterator|oldIterator { + atomic.Or8(&h.flags, iterator|oldIterator) + } + + mapiternext(it) +} + +// mapiternext should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapiternext +func mapiternext(it *hiter) { + h := it.h + if raceenabled { + callerpc := getcallerpc() + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapiternext)) + } + if h.flags&hashWriting != 0 { + fatal("concurrent map iteration and map write") + } + t := it.t + bucket := it.bucket + b := it.bptr + i := it.i + checkBucket := it.checkBucket + +next: + if b == nil { + if bucket == it.startBucket && it.wrapped { + // end of iteration + it.key = nil + it.elem = nil + return + } + if h.growing() && it.B == h.B { + // Iterator was started in the middle of a grow, and the grow isn't done yet. + // If the bucket we're looking at hasn't been filled in yet (i.e. the old + // bucket hasn't been evacuated) then we need to iterate through the old + // bucket and only return the ones that will be migrated to this bucket. + oldbucket := bucket & it.h.oldbucketmask() + b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.BucketSize))) + if !evacuated(b) { + checkBucket = bucket + } else { + b = (*bmap)(add(it.buckets, bucket*uintptr(t.BucketSize))) + checkBucket = noCheck + } + } else { + b = (*bmap)(add(it.buckets, bucket*uintptr(t.BucketSize))) + checkBucket = noCheck + } + bucket++ + if bucket == bucketShift(it.B) { + bucket = 0 + it.wrapped = true + } + i = 0 + } + for ; i < abi.MapBucketCount; i++ { + offi := (i + it.offset) & (abi.MapBucketCount - 1) + if isEmpty(b.tophash[offi]) || b.tophash[offi] == evacuatedEmpty { + // TODO: emptyRest is hard to use here, as we start iterating + // in the middle of a bucket. It's feasible, just tricky. + continue + } + k := add(unsafe.Pointer(b), dataOffset+uintptr(offi)*uintptr(t.KeySize)) + if t.IndirectKey() { + k = *((*unsafe.Pointer)(k)) + } + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+uintptr(offi)*uintptr(t.ValueSize)) + if checkBucket != noCheck && !h.sameSizeGrow() { + // Special case: iterator was started during a grow to a larger size + // and the grow is not done yet. We're working on a bucket whose + // oldbucket has not been evacuated yet. Or at least, it wasn't + // evacuated when we started the bucket. So we're iterating + // through the oldbucket, skipping any keys that will go + // to the other new bucket (each oldbucket expands to two + // buckets during a grow). + if t.ReflexiveKey() || t.Key.Equal(k, k) { + // If the item in the oldbucket is not destined for + // the current new bucket in the iteration, skip it. + hash := t.Hasher(k, uintptr(h.hash0)) + if hash&bucketMask(it.B) != checkBucket { + continue + } + } else { + // Hash isn't repeatable if k != k (NaNs). We need a + // repeatable and randomish choice of which direction + // to send NaNs during evacuation. We'll use the low + // bit of tophash to decide which way NaNs go. + // NOTE: this case is why we need two evacuate tophash + // values, evacuatedX and evacuatedY, that differ in + // their low bit. + if checkBucket>>(it.B-1) != uintptr(b.tophash[offi]&1) { + continue + } + } + } + if (b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY) || + !(t.ReflexiveKey() || t.Key.Equal(k, k)) { + // This is the golden data, we can return it. + // OR + // key!=key, so the entry can't be deleted or updated, so we can just return it. + // That's lucky for us because when key!=key we can't look it up successfully. + it.key = k + if t.IndirectElem() { + e = *((*unsafe.Pointer)(e)) + } + it.elem = e + } else { + // The hash table has grown since the iterator was started. + // The golden data for this key is now somewhere else. + // Check the current hash table for the data. + // This code handles the case where the key + // has been deleted, updated, or deleted and reinserted. + // NOTE: we need to regrab the key as it has potentially been + // updated to an equal() but not identical key (e.g. +0.0 vs -0.0). + rk, re := mapaccessK(t, h, k) + if rk == nil { + continue // key has been deleted + } + it.key = rk + it.elem = re + } + it.bucket = bucket + if it.bptr != b { // avoid unnecessary write barrier; see issue 14921 + it.bptr = b + } + it.i = i + 1 + it.checkBucket = checkBucket + return + } + b = b.overflow(t) + i = 0 + goto next +} + +// mapclear deletes all keys from a map. +// It is called by the compiler. +// +// mapclear should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapclear +func mapclear(t *maptype, h *hmap) { + if raceenabled && h != nil { + callerpc := getcallerpc() + pc := abi.FuncPCABIInternal(mapclear) + racewritepc(unsafe.Pointer(h), callerpc, pc) + } + + if h == nil || h.count == 0 { + return + } + + if h.flags&hashWriting != 0 { + fatal("concurrent map writes") + } + + h.flags ^= hashWriting + + // Mark buckets empty, so existing iterators can be terminated, see issue #59411. + markBucketsEmpty := func(bucket unsafe.Pointer, mask uintptr) { + for i := uintptr(0); i <= mask; i++ { + b := (*bmap)(add(bucket, i*uintptr(t.BucketSize))) + for ; b != nil; b = b.overflow(t) { + for i := uintptr(0); i < abi.MapBucketCount; i++ { + b.tophash[i] = emptyRest + } + } + } + } + markBucketsEmpty(h.buckets, bucketMask(h.B)) + if oldBuckets := h.oldbuckets; oldBuckets != nil { + markBucketsEmpty(oldBuckets, h.oldbucketmask()) + } + + h.flags &^= sameSizeGrow + h.oldbuckets = nil + h.nevacuate = 0 + h.noverflow = 0 + h.count = 0 + + // Reset the hash seed to make it more difficult for attackers to + // repeatedly trigger hash collisions. See issue 25237. + h.hash0 = uint32(rand()) + + // Keep the mapextra allocation but clear any extra information. + if h.extra != nil { + *h.extra = mapextra{} + } + + // makeBucketArray clears the memory pointed to by h.buckets + // and recovers any overflow buckets by generating them + // as if h.buckets was newly alloced. + _, nextOverflow := makeBucketArray(t, h.B, h.buckets) + if nextOverflow != nil { + // If overflow buckets are created then h.extra + // will have been allocated during initial bucket creation. + h.extra.nextOverflow = nextOverflow + } + + if h.flags&hashWriting == 0 { + fatal("concurrent map writes") + } + h.flags &^= hashWriting +} + +func hashGrow(t *maptype, h *hmap) { + // If we've hit the load factor, get bigger. + // Otherwise, there are too many overflow buckets, + // so keep the same number of buckets and "grow" laterally. + bigger := uint8(1) + if !overLoadFactor(h.count+1, h.B) { + bigger = 0 + h.flags |= sameSizeGrow + } + oldbuckets := h.buckets + newbuckets, nextOverflow := makeBucketArray(t, h.B+bigger, nil) + + flags := h.flags &^ (iterator | oldIterator) + if h.flags&iterator != 0 { + flags |= oldIterator + } + // commit the grow (atomic wrt gc) + h.B += bigger + h.flags = flags + h.oldbuckets = oldbuckets + h.buckets = newbuckets + h.nevacuate = 0 + h.noverflow = 0 + + if h.extra != nil && h.extra.overflow != nil { + // Promote current overflow buckets to the old generation. + if h.extra.oldoverflow != nil { + throw("oldoverflow is not nil") + } + h.extra.oldoverflow = h.extra.overflow + h.extra.overflow = nil + } + if nextOverflow != nil { + if h.extra == nil { + h.extra = new(mapextra) + } + h.extra.nextOverflow = nextOverflow + } + + // the actual copying of the hash table data is done incrementally + // by growWork() and evacuate(). +} + +// overLoadFactor reports whether count items placed in 1< abi.MapBucketCount && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen) +} + +// tooManyOverflowBuckets reports whether noverflow buckets is too many for a map with 1< 15 { + B = 15 + } + // The compiler doesn't see here that B < 16; mask B to generate shorter shift code. + return noverflow >= uint16(1)<<(B&15) +} + +// growing reports whether h is growing. The growth may be to the same size or bigger. +func (h *hmap) growing() bool { + return h.oldbuckets != nil +} + +// sameSizeGrow reports whether the current growth is to a map of the same size. +func (h *hmap) sameSizeGrow() bool { + return h.flags&sameSizeGrow != 0 +} + +//go:linkname sameSizeGrowForIssue69110Test +func sameSizeGrowForIssue69110Test(h *hmap) bool { + return h.sameSizeGrow() +} + +// noldbuckets calculates the number of buckets prior to the current map growth. +func (h *hmap) noldbuckets() uintptr { + oldB := h.B + if !h.sameSizeGrow() { + oldB-- + } + return bucketShift(oldB) +} + +// oldbucketmask provides a mask that can be applied to calculate n % noldbuckets(). +func (h *hmap) oldbucketmask() uintptr { + return h.noldbuckets() - 1 +} + +func growWork(t *maptype, h *hmap, bucket uintptr) { + // make sure we evacuate the oldbucket corresponding + // to the bucket we're about to use + evacuate(t, h, bucket&h.oldbucketmask()) + + // evacuate one more oldbucket to make progress on growing + if h.growing() { + evacuate(t, h, h.nevacuate) + } +} + +func bucketEvacuated(t *maptype, h *hmap, bucket uintptr) bool { + b := (*bmap)(add(h.oldbuckets, bucket*uintptr(t.BucketSize))) + return evacuated(b) +} + +// evacDst is an evacuation destination. +type evacDst struct { + b *bmap // current destination bucket + i int // key/elem index into b + k unsafe.Pointer // pointer to current key storage + e unsafe.Pointer // pointer to current elem storage +} + +func evacuate(t *maptype, h *hmap, oldbucket uintptr) { + b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.BucketSize))) + newbit := h.noldbuckets() + if !evacuated(b) { + // TODO: reuse overflow buckets instead of using new ones, if there + // is no iterator using the old buckets. (If !oldIterator.) + + // xy contains the x and y (low and high) evacuation destinations. + var xy [2]evacDst + x := &xy[0] + x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.BucketSize))) + x.k = add(unsafe.Pointer(x.b), dataOffset) + x.e = add(x.k, abi.MapBucketCount*uintptr(t.KeySize)) + + if !h.sameSizeGrow() { + // Only calculate y pointers if we're growing bigger. + // Otherwise GC can see bad pointers. + y := &xy[1] + y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.BucketSize))) + y.k = add(unsafe.Pointer(y.b), dataOffset) + y.e = add(y.k, abi.MapBucketCount*uintptr(t.KeySize)) + } + + for ; b != nil; b = b.overflow(t) { + k := add(unsafe.Pointer(b), dataOffset) + e := add(k, abi.MapBucketCount*uintptr(t.KeySize)) + for i := 0; i < abi.MapBucketCount; i, k, e = i+1, add(k, uintptr(t.KeySize)), add(e, uintptr(t.ValueSize)) { + top := b.tophash[i] + if isEmpty(top) { + b.tophash[i] = evacuatedEmpty + continue + } + if top < minTopHash { + throw("bad map state") + } + k2 := k + if t.IndirectKey() { + k2 = *((*unsafe.Pointer)(k2)) + } + var useY uint8 + if !h.sameSizeGrow() { + // Compute hash to make our evacuation decision (whether we need + // to send this key/elem to bucket x or bucket y). + hash := t.Hasher(k2, uintptr(h.hash0)) + if h.flags&iterator != 0 && !t.ReflexiveKey() && !t.Key.Equal(k2, k2) { + // If key != key (NaNs), then the hash could be (and probably + // will be) entirely different from the old hash. Moreover, + // it isn't reproducible. Reproducibility is required in the + // presence of iterators, as our evacuation decision must + // match whatever decision the iterator made. + // Fortunately, we have the freedom to send these keys either + // way. Also, tophash is meaningless for these kinds of keys. + // We let the low bit of tophash drive the evacuation decision. + // We recompute a new random tophash for the next level so + // these keys will get evenly distributed across all buckets + // after multiple grows. + useY = top & 1 + top = tophash(hash) + } else { + if hash&newbit != 0 { + useY = 1 + } + } + } + + if evacuatedX+1 != evacuatedY || evacuatedX^1 != evacuatedY { + throw("bad evacuatedN") + } + + b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY + dst := &xy[useY] // evacuation destination + + if dst.i == abi.MapBucketCount { + dst.b = h.newoverflow(t, dst.b) + dst.i = 0 + dst.k = add(unsafe.Pointer(dst.b), dataOffset) + dst.e = add(dst.k, abi.MapBucketCount*uintptr(t.KeySize)) + } + dst.b.tophash[dst.i&(abi.MapBucketCount-1)] = top // mask dst.i as an optimization, to avoid a bounds check + if t.IndirectKey() { + *(*unsafe.Pointer)(dst.k) = k2 // copy pointer + } else { + typedmemmove(t.Key, dst.k, k) // copy elem + } + if t.IndirectElem() { + *(*unsafe.Pointer)(dst.e) = *(*unsafe.Pointer)(e) + } else { + typedmemmove(t.Elem, dst.e, e) + } + dst.i++ + // These updates might push these pointers past the end of the + // key or elem arrays. That's ok, as we have the overflow pointer + // at the end of the bucket to protect against pointing past the + // end of the bucket. + dst.k = add(dst.k, uintptr(t.KeySize)) + dst.e = add(dst.e, uintptr(t.ValueSize)) + } + } + // Unlink the overflow buckets & clear key/elem to help GC. + if h.flags&oldIterator == 0 && t.Bucket.Pointers() { + b := add(h.oldbuckets, oldbucket*uintptr(t.BucketSize)) + // Preserve b.tophash because the evacuation + // state is maintained there. + ptr := add(b, dataOffset) + n := uintptr(t.BucketSize) - dataOffset + memclrHasPointers(ptr, n) + } + } + + if oldbucket == h.nevacuate { + advanceEvacuationMark(h, t, newbit) + } +} + +func advanceEvacuationMark(h *hmap, t *maptype, newbit uintptr) { + h.nevacuate++ + // Experiments suggest that 1024 is overkill by at least an order of magnitude. + // Put it in there as a safeguard anyway, to ensure O(1) behavior. + stop := h.nevacuate + 1024 + if stop > newbit { + stop = newbit + } + for h.nevacuate != stop && bucketEvacuated(t, h, h.nevacuate) { + h.nevacuate++ + } + if h.nevacuate == newbit { // newbit == # of oldbuckets + // Growing is all done. Free old main bucket array. + h.oldbuckets = nil + // Can discard old overflow buckets as well. + // If they are still referenced by an iterator, + // then the iterator holds a pointers to the slice. + if h.extra != nil { + h.extra.oldoverflow = nil + } + h.flags &^= sameSizeGrow + } +} + +// Reflect stubs. Called from ../reflect/asm_*.s + +// reflect_makemap is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/goccy/go-json +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_makemap reflect.makemap +func reflect_makemap(t *maptype, cap int) *hmap { + // Check invariants and reflects math. + if t.Key.Equal == nil { + throw("runtime.reflect_makemap: unsupported map key type") + } + if t.Key.Size_ > abi.MapMaxKeyBytes && (!t.IndirectKey() || t.KeySize != uint8(goarch.PtrSize)) || + t.Key.Size_ <= abi.MapMaxKeyBytes && (t.IndirectKey() || t.KeySize != uint8(t.Key.Size_)) { + throw("key size wrong") + } + if t.Elem.Size_ > abi.MapMaxElemBytes && (!t.IndirectElem() || t.ValueSize != uint8(goarch.PtrSize)) || + t.Elem.Size_ <= abi.MapMaxElemBytes && (t.IndirectElem() || t.ValueSize != uint8(t.Elem.Size_)) { + throw("elem size wrong") + } + if t.Key.Align_ > abi.MapBucketCount { + throw("key align too big") + } + if t.Elem.Align_ > abi.MapBucketCount { + throw("elem align too big") + } + if t.Key.Size_%uintptr(t.Key.Align_) != 0 { + throw("key size not a multiple of key align") + } + if t.Elem.Size_%uintptr(t.Elem.Align_) != 0 { + throw("elem size not a multiple of elem align") + } + if abi.MapBucketCount < 8 { + throw("bucketsize too small for proper alignment") + } + if dataOffset%uintptr(t.Key.Align_) != 0 { + throw("need padding in bucket (key)") + } + if dataOffset%uintptr(t.Elem.Align_) != 0 { + throw("need padding in bucket (elem)") + } + + return makemap(t, cap, nil) +} + +// reflect_mapaccess is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_mapaccess reflect.mapaccess +func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { + elem, ok := mapaccess2(t, h, key) + if !ok { + // reflect wants nil for a missing element + elem = nil + } + return elem +} + +//go:linkname reflect_mapaccess_faststr reflect.mapaccess_faststr +func reflect_mapaccess_faststr(t *maptype, h *hmap, key string) unsafe.Pointer { + elem, ok := mapaccess2_faststr(t, h, key) + if !ok { + // reflect wants nil for a missing element + elem = nil + } + return elem +} + +// reflect_mapassign is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// +//go:linkname reflect_mapassign reflect.mapassign0 +func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, elem unsafe.Pointer) { + p := mapassign(t, h, key) + typedmemmove(t.Elem, p, elem) +} + +//go:linkname reflect_mapassign_faststr reflect.mapassign_faststr0 +func reflect_mapassign_faststr(t *maptype, h *hmap, key string, elem unsafe.Pointer) { + p := mapassign_faststr(t, h, key) + typedmemmove(t.Elem, p, elem) +} + +//go:linkname reflect_mapdelete reflect.mapdelete +func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { + mapdelete(t, h, key) +} + +//go:linkname reflect_mapdelete_faststr reflect.mapdelete_faststr +func reflect_mapdelete_faststr(t *maptype, h *hmap, key string) { + mapdelete_faststr(t, h, key) +} + +// reflect_mapiterinit is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/modern-go/reflect2 +// - gitee.com/quant1x/gox +// - github.com/v2pro/plz +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_mapiterinit reflect.mapiterinit +func reflect_mapiterinit(t *maptype, h *hmap, it *hiter) { + mapiterinit(t, h, it) +} + +// reflect_mapiternext is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/goccy/go-json +// - github.com/v2pro/plz +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_mapiternext reflect.mapiternext +func reflect_mapiternext(it *hiter) { + mapiternext(it) +} + +// reflect_mapiterkey is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_mapiterkey reflect.mapiterkey +func reflect_mapiterkey(it *hiter) unsafe.Pointer { + return it.key +} + +// reflect_mapiterelem is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_mapiterelem reflect.mapiterelem +func reflect_mapiterelem(it *hiter) unsafe.Pointer { + return it.elem +} + +// reflect_maplen is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_maplen reflect.maplen +func reflect_maplen(h *hmap) int { + if h == nil { + return 0 + } + if raceenabled { + callerpc := getcallerpc() + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(reflect_maplen)) + } + return h.count +} + +//go:linkname reflect_mapclear reflect.mapclear +func reflect_mapclear(t *maptype, h *hmap) { + mapclear(t, h) +} + +//go:linkname reflectlite_maplen internal/reflectlite.maplen +func reflectlite_maplen(h *hmap) int { + if h == nil { + return 0 + } + if raceenabled { + callerpc := getcallerpc() + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(reflect_maplen)) + } + return h.count +} + +// mapinitnoop is a no-op function known the Go linker; if a given global +// map (of the right size) is determined to be dead, the linker will +// rewrite the relocation (from the package init func) from the outlined +// map init function to this symbol. Defined in assembly so as to avoid +// complications with instrumentation (coverage, etc). +func mapinitnoop() + +// mapclone for implementing maps.Clone +// +//go:linkname mapclone maps.clone +func mapclone(m any) any { + e := efaceOf(&m) + e.data = unsafe.Pointer(mapclone2((*maptype)(unsafe.Pointer(e._type)), (*hmap)(e.data))) + return m +} + +// moveToBmap moves a bucket from src to dst. It returns the destination bucket or new destination bucket if it overflows +// and the pos that the next key/value will be written, if pos == bucketCnt means needs to written in overflow bucket. +func moveToBmap(t *maptype, h *hmap, dst *bmap, pos int, src *bmap) (*bmap, int) { + for i := 0; i < abi.MapBucketCount; i++ { + if isEmpty(src.tophash[i]) { + continue + } + + for ; pos < abi.MapBucketCount; pos++ { + if isEmpty(dst.tophash[pos]) { + break + } + } + + if pos == abi.MapBucketCount { + dst = h.newoverflow(t, dst) + pos = 0 + } + + srcK := add(unsafe.Pointer(src), dataOffset+uintptr(i)*uintptr(t.KeySize)) + srcEle := add(unsafe.Pointer(src), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+uintptr(i)*uintptr(t.ValueSize)) + dstK := add(unsafe.Pointer(dst), dataOffset+uintptr(pos)*uintptr(t.KeySize)) + dstEle := add(unsafe.Pointer(dst), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+uintptr(pos)*uintptr(t.ValueSize)) + + dst.tophash[pos] = src.tophash[i] + if t.IndirectKey() { + srcK = *(*unsafe.Pointer)(srcK) + if t.NeedKeyUpdate() { + kStore := newobject(t.Key) + typedmemmove(t.Key, kStore, srcK) + srcK = kStore + } + // Note: if NeedKeyUpdate is false, then the memory + // used to store the key is immutable, so we can share + // it between the original map and its clone. + *(*unsafe.Pointer)(dstK) = srcK + } else { + typedmemmove(t.Key, dstK, srcK) + } + if t.IndirectElem() { + srcEle = *(*unsafe.Pointer)(srcEle) + eStore := newobject(t.Elem) + typedmemmove(t.Elem, eStore, srcEle) + *(*unsafe.Pointer)(dstEle) = eStore + } else { + typedmemmove(t.Elem, dstEle, srcEle) + } + pos++ + h.count++ + } + return dst, pos +} + +func mapclone2(t *maptype, src *hmap) *hmap { + hint := src.count + if overLoadFactor(hint, src.B) { + // Note: in rare cases (e.g. during a same-sized grow) the map + // can be overloaded. Make sure we don't allocate a destination + // bucket array larger than the source bucket array. + // This will cause the cloned map to be overloaded also, + // but that's better than crashing. See issue 69110. + hint = int(loadFactorNum * (bucketShift(src.B) / loadFactorDen)) + } + dst := makemap(t, hint, nil) + dst.hash0 = src.hash0 + dst.nevacuate = 0 + // flags do not need to be copied here, just like a new map has no flags. + + if src.count == 0 { + return dst + } + + if src.flags&hashWriting != 0 { + fatal("concurrent map clone and map write") + } + + if src.B == 0 && !(t.IndirectKey() && t.NeedKeyUpdate()) && !t.IndirectElem() { + // Quick copy for small maps. + dst.buckets = newobject(t.Bucket) + dst.count = src.count + typedmemmove(t.Bucket, dst.buckets, src.buckets) + return dst + } + + if dst.B == 0 { + dst.buckets = newobject(t.Bucket) + } + dstArraySize := int(bucketShift(dst.B)) + srcArraySize := int(bucketShift(src.B)) + for i := 0; i < dstArraySize; i++ { + dstBmap := (*bmap)(add(dst.buckets, uintptr(i*int(t.BucketSize)))) + pos := 0 + for j := 0; j < srcArraySize; j += dstArraySize { + srcBmap := (*bmap)(add(src.buckets, uintptr((i+j)*int(t.BucketSize)))) + for srcBmap != nil { + dstBmap, pos = moveToBmap(t, dst, dstBmap, pos, srcBmap) + srcBmap = srcBmap.overflow(t) + } + } + } + + if src.oldbuckets == nil { + return dst + } + + oldB := src.B + srcOldbuckets := src.oldbuckets + if !src.sameSizeGrow() { + oldB-- + } + oldSrcArraySize := int(bucketShift(oldB)) + + for i := 0; i < oldSrcArraySize; i++ { + srcBmap := (*bmap)(add(srcOldbuckets, uintptr(i*int(t.BucketSize)))) + if evacuated(srcBmap) { + continue + } + + if oldB >= dst.B { // main bucket bits in dst is less than oldB bits in src + dstBmap := (*bmap)(add(dst.buckets, (uintptr(i)&bucketMask(dst.B))*uintptr(t.BucketSize))) + for dstBmap.overflow(t) != nil { + dstBmap = dstBmap.overflow(t) + } + pos := 0 + for srcBmap != nil { + dstBmap, pos = moveToBmap(t, dst, dstBmap, pos, srcBmap) + srcBmap = srcBmap.overflow(t) + } + continue + } + + // oldB < dst.B, so a single source bucket may go to multiple destination buckets. + // Process entries one at a time. + for srcBmap != nil { + // move from oldBlucket to new bucket + for i := uintptr(0); i < abi.MapBucketCount; i++ { + if isEmpty(srcBmap.tophash[i]) { + continue + } + + if src.flags&hashWriting != 0 { + fatal("concurrent map clone and map write") + } + + srcK := add(unsafe.Pointer(srcBmap), dataOffset+i*uintptr(t.KeySize)) + if t.IndirectKey() { + srcK = *((*unsafe.Pointer)(srcK)) + } + + srcEle := add(unsafe.Pointer(srcBmap), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + if t.IndirectElem() { + srcEle = *((*unsafe.Pointer)(srcEle)) + } + dstEle := mapassign(t, dst, srcK) + typedmemmove(t.Elem, dstEle, srcEle) + } + srcBmap = srcBmap.overflow(t) + } + } + return dst +} + +// keys for implementing maps.keys +// +//go:linkname keys maps.keys +func keys(m any, p unsafe.Pointer) { + e := efaceOf(&m) + t := (*maptype)(unsafe.Pointer(e._type)) + h := (*hmap)(e.data) + + if h == nil || h.count == 0 { + return + } + s := (*slice)(p) + r := int(rand()) + offset := uint8(r >> h.B & (abi.MapBucketCount - 1)) + if h.B == 0 { + copyKeys(t, h, (*bmap)(h.buckets), s, offset) + return + } + arraySize := int(bucketShift(h.B)) + buckets := h.buckets + for i := 0; i < arraySize; i++ { + bucket := (i + r) & (arraySize - 1) + b := (*bmap)(add(buckets, uintptr(bucket)*uintptr(t.BucketSize))) + copyKeys(t, h, b, s, offset) + } + + if h.growing() { + oldArraySize := int(h.noldbuckets()) + for i := 0; i < oldArraySize; i++ { + bucket := (i + r) & (oldArraySize - 1) + b := (*bmap)(add(h.oldbuckets, uintptr(bucket)*uintptr(t.BucketSize))) + if evacuated(b) { + continue + } + copyKeys(t, h, b, s, offset) + } + } + return +} + +func copyKeys(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) { + for b != nil { + for i := uintptr(0); i < abi.MapBucketCount; i++ { + offi := (i + uintptr(offset)) & (abi.MapBucketCount - 1) + if isEmpty(b.tophash[offi]) { + continue + } + if h.flags&hashWriting != 0 { + fatal("concurrent map read and map write") + } + k := add(unsafe.Pointer(b), dataOffset+offi*uintptr(t.KeySize)) + if t.IndirectKey() { + k = *((*unsafe.Pointer)(k)) + } + if s.len >= s.cap { + fatal("concurrent map read and map write") + } + typedmemmove(t.Key, add(s.array, uintptr(s.len)*uintptr(t.Key.Size())), k) + s.len++ + } + b = b.overflow(t) + } +} + +// values for implementing maps.values +// +//go:linkname values maps.values +func values(m any, p unsafe.Pointer) { + e := efaceOf(&m) + t := (*maptype)(unsafe.Pointer(e._type)) + h := (*hmap)(e.data) + if h == nil || h.count == 0 { + return + } + s := (*slice)(p) + r := int(rand()) + offset := uint8(r >> h.B & (abi.MapBucketCount - 1)) + if h.B == 0 { + copyValues(t, h, (*bmap)(h.buckets), s, offset) + return + } + arraySize := int(bucketShift(h.B)) + buckets := h.buckets + for i := 0; i < arraySize; i++ { + bucket := (i + r) & (arraySize - 1) + b := (*bmap)(add(buckets, uintptr(bucket)*uintptr(t.BucketSize))) + copyValues(t, h, b, s, offset) + } + + if h.growing() { + oldArraySize := int(h.noldbuckets()) + for i := 0; i < oldArraySize; i++ { + bucket := (i + r) & (oldArraySize - 1) + b := (*bmap)(add(h.oldbuckets, uintptr(bucket)*uintptr(t.BucketSize))) + if evacuated(b) { + continue + } + copyValues(t, h, b, s, offset) + } + } + return +} + +func copyValues(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) { + for b != nil { + for i := uintptr(0); i < abi.MapBucketCount; i++ { + offi := (i + uintptr(offset)) & (abi.MapBucketCount - 1) + if isEmpty(b.tophash[offi]) { + continue + } + + if h.flags&hashWriting != 0 { + fatal("concurrent map read and map write") + } + + ele := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+offi*uintptr(t.ValueSize)) + if t.IndirectElem() { + ele = *((*unsafe.Pointer)(ele)) + } + if s.len >= s.cap { + fatal("concurrent map read and map write") + } + typedmemmove(t.Elem, add(s.array, uintptr(s.len)*uintptr(t.Elem.Size())), ele) + s.len++ + } + b = b.overflow(t) + } +} diff --git a/contrib/go/_std_1.22/src/runtime/map_fast32.go b/contrib/go/_std_1.23/src/runtime/map_fast32.go similarity index 81% rename from contrib/go/_std_1.22/src/runtime/map_fast32.go rename to contrib/go/_std_1.23/src/runtime/map_fast32.go index e1dd495365b3..0eb8562f5102 100644 --- a/contrib/go/_std_1.22/src/runtime/map_fast32.go +++ b/contrib/go/_std_1.23/src/runtime/map_fast32.go @@ -41,15 +41,24 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { } } for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 4) { if *(*uint32)(k) == key && !isEmpty(b.tophash[i]) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*4+i*uintptr(t.ValueSize)) } } } return unsafe.Pointer(&zeroVal[0]) } +// mapaccess2_fast32 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapaccess2_fast32 func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -81,15 +90,26 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { } } for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 4) { if *(*uint32)(k) == key && !isEmpty(b.tophash[i]) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*4+i*uintptr(t.ValueSize)), true } } } return unsafe.Pointer(&zeroVal[0]), false } +// mapassign_fast32 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_fast32 func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -123,7 +143,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if isEmpty(b.tophash[i]) { if insertb == nil { inserti = i @@ -163,7 +183,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = tophash(hash) // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*4) // store new key at insert position @@ -172,7 +192,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*4+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*4+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -180,6 +200,15 @@ done: return elem } +// mapassign_fast32ptr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_fast32ptr func mapassign_fast32ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -213,7 +242,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if isEmpty(b.tophash[i]) { if insertb == nil { inserti = i @@ -253,7 +282,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = tophash(hash) // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*4) // store new key at insert position @@ -262,7 +291,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*4+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*4+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -295,20 +324,20 @@ func mapdelete_fast32(t *maptype, h *hmap, key uint32) { bOrig := b search: for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 4) { if key != *(*uint32)(k) || isEmpty(b.tophash[i]) { continue } // Only clear key if there are pointers in it. // This can only happen if pointers are 32 bit // wide as 64 bit pointers do not fit into a 32 bit key. - if goarch.PtrSize == 4 && t.Key.PtrBytes != 0 { + if goarch.PtrSize == 4 && t.Key.Pointers() { // The key must be a pointer as we checked pointers are // 32 bits wide and the key is 32 bits wide also. *(*unsafe.Pointer)(k) = nil } - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.ValueSize)) - if t.Elem.PtrBytes != 0 { + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*4+i*uintptr(t.ValueSize)) + if t.Elem.Pointers() { memclrHasPointers(e, t.Elem.Size_) } else { memclrNoHeapPointers(e, t.Elem.Size_) @@ -316,7 +345,7 @@ search: b.tophash[i] = emptyOne // If the bucket now ends in a bunch of emptyOne states, // change those to emptyRest states. - if i == bucketCnt-1 { + if i == abi.MapBucketCount-1 { if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { goto notLast } @@ -335,7 +364,7 @@ search: c := b for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { } - i = bucketCnt - 1 + i = abi.MapBucketCount - 1 } else { i-- } @@ -383,7 +412,7 @@ func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { x := &xy[0] x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.BucketSize))) x.k = add(unsafe.Pointer(x.b), dataOffset) - x.e = add(x.k, bucketCnt*4) + x.e = add(x.k, abi.MapBucketCount*4) if !h.sameSizeGrow() { // Only calculate y pointers if we're growing bigger. @@ -391,13 +420,13 @@ func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { y := &xy[1] y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.BucketSize))) y.k = add(unsafe.Pointer(y.b), dataOffset) - y.e = add(y.k, bucketCnt*4) + y.e = add(y.k, abi.MapBucketCount*4) } for ; b != nil; b = b.overflow(t) { k := add(unsafe.Pointer(b), dataOffset) - e := add(k, bucketCnt*4) - for i := 0; i < bucketCnt; i, k, e = i+1, add(k, 4), add(e, uintptr(t.ValueSize)) { + e := add(k, abi.MapBucketCount*4) + for i := 0; i < abi.MapBucketCount; i, k, e = i+1, add(k, 4), add(e, uintptr(t.ValueSize)) { top := b.tophash[i] if isEmpty(top) { b.tophash[i] = evacuatedEmpty @@ -419,16 +448,16 @@ func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap dst := &xy[useY] // evacuation destination - if dst.i == bucketCnt { + if dst.i == abi.MapBucketCount { dst.b = h.newoverflow(t, dst.b) dst.i = 0 dst.k = add(unsafe.Pointer(dst.b), dataOffset) - dst.e = add(dst.k, bucketCnt*4) + dst.e = add(dst.k, abi.MapBucketCount*4) } - dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + dst.b.tophash[dst.i&(abi.MapBucketCount-1)] = top // mask dst.i as an optimization, to avoid a bounds check // Copy key. - if goarch.PtrSize == 4 && t.Key.PtrBytes != 0 && writeBarrier.enabled { + if goarch.PtrSize == 4 && t.Key.Pointers() && writeBarrier.enabled { // Write with a write barrier. *(*unsafe.Pointer)(dst.k) = *(*unsafe.Pointer)(k) } else { @@ -446,7 +475,7 @@ func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { } } // Unlink the overflow buckets & clear key/elem to help GC. - if h.flags&oldIterator == 0 && t.Bucket.PtrBytes != 0 { + if h.flags&oldIterator == 0 && t.Bucket.Pointers() { b := add(h.oldbuckets, oldbucket*uintptr(t.BucketSize)) // Preserve b.tophash because the evacuation // state is maintained there. diff --git a/contrib/go/_std_1.22/src/runtime/map_fast64.go b/contrib/go/_std_1.23/src/runtime/map_fast64.go similarity index 81% rename from contrib/go/_std_1.22/src/runtime/map_fast64.go rename to contrib/go/_std_1.23/src/runtime/map_fast64.go index 7ca35ec6cb13..aca60eb2a80b 100644 --- a/contrib/go/_std_1.22/src/runtime/map_fast64.go +++ b/contrib/go/_std_1.23/src/runtime/map_fast64.go @@ -41,15 +41,24 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { } } for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 8) { if *(*uint64)(k) == key && !isEmpty(b.tophash[i]) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*8+i*uintptr(t.ValueSize)) } } } return unsafe.Pointer(&zeroVal[0]) } +// mapaccess2_fast64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapaccess2_fast64 func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -81,15 +90,26 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { } } for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 8) { if *(*uint64)(k) == key && !isEmpty(b.tophash[i]) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*8+i*uintptr(t.ValueSize)), true } } } return unsafe.Pointer(&zeroVal[0]), false } +// mapassign_fast64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_fast64 func mapassign_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -123,7 +143,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if isEmpty(b.tophash[i]) { if insertb == nil { insertb = b @@ -163,7 +183,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = tophash(hash) // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*8) // store new key at insert position @@ -172,7 +192,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*8+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*8+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -180,6 +200,17 @@ done: return elem } +// mapassign_fast64ptr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_fast64ptr func mapassign_fast64ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -213,7 +244,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if isEmpty(b.tophash[i]) { if insertb == nil { insertb = b @@ -253,7 +284,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = tophash(hash) // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*8) // store new key at insert position @@ -262,7 +293,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*8+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*8+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -295,12 +326,12 @@ func mapdelete_fast64(t *maptype, h *hmap, key uint64) { bOrig := b search: for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 8) { if key != *(*uint64)(k) || isEmpty(b.tophash[i]) { continue } // Only clear key if there are pointers in it. - if t.Key.PtrBytes != 0 { + if t.Key.Pointers() { if goarch.PtrSize == 8 { *(*unsafe.Pointer)(k) = nil } else { @@ -309,8 +340,8 @@ search: memclrHasPointers(k, 8) } } - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.ValueSize)) - if t.Elem.PtrBytes != 0 { + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*8+i*uintptr(t.ValueSize)) + if t.Elem.Pointers() { memclrHasPointers(e, t.Elem.Size_) } else { memclrNoHeapPointers(e, t.Elem.Size_) @@ -318,7 +349,7 @@ search: b.tophash[i] = emptyOne // If the bucket now ends in a bunch of emptyOne states, // change those to emptyRest states. - if i == bucketCnt-1 { + if i == abi.MapBucketCount-1 { if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { goto notLast } @@ -337,7 +368,7 @@ search: c := b for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { } - i = bucketCnt - 1 + i = abi.MapBucketCount - 1 } else { i-- } @@ -385,7 +416,7 @@ func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { x := &xy[0] x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.BucketSize))) x.k = add(unsafe.Pointer(x.b), dataOffset) - x.e = add(x.k, bucketCnt*8) + x.e = add(x.k, abi.MapBucketCount*8) if !h.sameSizeGrow() { // Only calculate y pointers if we're growing bigger. @@ -393,13 +424,13 @@ func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { y := &xy[1] y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.BucketSize))) y.k = add(unsafe.Pointer(y.b), dataOffset) - y.e = add(y.k, bucketCnt*8) + y.e = add(y.k, abi.MapBucketCount*8) } for ; b != nil; b = b.overflow(t) { k := add(unsafe.Pointer(b), dataOffset) - e := add(k, bucketCnt*8) - for i := 0; i < bucketCnt; i, k, e = i+1, add(k, 8), add(e, uintptr(t.ValueSize)) { + e := add(k, abi.MapBucketCount*8) + for i := 0; i < abi.MapBucketCount; i, k, e = i+1, add(k, 8), add(e, uintptr(t.ValueSize)) { top := b.tophash[i] if isEmpty(top) { b.tophash[i] = evacuatedEmpty @@ -421,16 +452,16 @@ func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap dst := &xy[useY] // evacuation destination - if dst.i == bucketCnt { + if dst.i == abi.MapBucketCount { dst.b = h.newoverflow(t, dst.b) dst.i = 0 dst.k = add(unsafe.Pointer(dst.b), dataOffset) - dst.e = add(dst.k, bucketCnt*8) + dst.e = add(dst.k, abi.MapBucketCount*8) } - dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + dst.b.tophash[dst.i&(abi.MapBucketCount-1)] = top // mask dst.i as an optimization, to avoid a bounds check // Copy key. - if t.Key.PtrBytes != 0 && writeBarrier.enabled { + if t.Key.Pointers() && writeBarrier.enabled { if goarch.PtrSize == 8 { // Write with a write barrier. *(*unsafe.Pointer)(dst.k) = *(*unsafe.Pointer)(k) @@ -454,7 +485,7 @@ func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { } } // Unlink the overflow buckets & clear key/elem to help GC. - if h.flags&oldIterator == 0 && t.Bucket.PtrBytes != 0 { + if h.flags&oldIterator == 0 && t.Bucket.Pointers() { b := add(h.oldbuckets, oldbucket*uintptr(t.BucketSize)) // Preserve b.tophash because the evacuation // state is maintained there. diff --git a/contrib/go/_std_1.22/src/runtime/map_faststr.go b/contrib/go/_std_1.23/src/runtime/map_faststr.go similarity index 77% rename from contrib/go/_std_1.22/src/runtime/map_faststr.go rename to contrib/go/_std_1.23/src/runtime/map_faststr.go index 22e1f61f0660..5461a9f81e81 100644 --- a/contrib/go/_std_1.22/src/runtime/map_faststr.go +++ b/contrib/go/_std_1.23/src/runtime/map_faststr.go @@ -27,7 +27,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { b := (*bmap)(h.buckets) if key.len < 32 { // short key, doing lots of comparisons is ok - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -36,14 +36,14 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)) } } return unsafe.Pointer(&zeroVal[0]) } // long key, try not to do more comparisons than necessary - keymaybe := uintptr(bucketCnt) - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + keymaybe := uintptr(abi.MapBucketCount) + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -52,7 +52,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { continue } if k.str == key.str { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)) } // check first 4 bytes if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) { @@ -62,16 +62,16 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) { continue } - if keymaybe != bucketCnt { + if keymaybe != abi.MapBucketCount { // Two keys are potential matches. Use hash to distinguish them. goto dohash } keymaybe = i } - if keymaybe != bucketCnt { + if keymaybe != abi.MapBucketCount { k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*goarch.PtrSize)) if memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+keymaybe*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+keymaybe*uintptr(t.ValueSize)) } } return unsafe.Pointer(&zeroVal[0]) @@ -92,19 +92,28 @@ dohash: } top := tophash(hash) for ; b != nil; b = b.overflow(t) { - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || b.tophash[i] != top { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)) } } } return unsafe.Pointer(&zeroVal[0]) } +// mapaccess2_faststr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapaccess2_faststr func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -122,7 +131,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { b := (*bmap)(h.buckets) if key.len < 32 { // short key, doing lots of comparisons is ok - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -131,14 +140,14 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true } } return unsafe.Pointer(&zeroVal[0]), false } // long key, try not to do more comparisons than necessary - keymaybe := uintptr(bucketCnt) - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + keymaybe := uintptr(abi.MapBucketCount) + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -147,7 +156,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { continue } if k.str == key.str { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true } // check first 4 bytes if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) { @@ -157,16 +166,16 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) { continue } - if keymaybe != bucketCnt { + if keymaybe != abi.MapBucketCount { // Two keys are potential matches. Use hash to distinguish them. goto dohash } keymaybe = i } - if keymaybe != bucketCnt { + if keymaybe != abi.MapBucketCount { k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*goarch.PtrSize)) if memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+keymaybe*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+keymaybe*uintptr(t.ValueSize)), true } } return unsafe.Pointer(&zeroVal[0]), false @@ -187,19 +196,30 @@ dohash: } top := tophash(hash) for ; b != nil; b = b.overflow(t) { - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || b.tophash[i] != top { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true } } } return unsafe.Pointer(&zeroVal[0]), false } +// mapassign_faststr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_faststr func mapassign_faststr(t *maptype, h *hmap, s string) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -235,7 +255,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if b.tophash[i] != top { if isEmpty(b.tophash[i]) && insertb == nil { insertb = b @@ -282,7 +302,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = top // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = top // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*2*goarch.PtrSize) // store new key at insert position @@ -290,7 +310,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*2*goarch.PtrSize+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -325,7 +345,7 @@ func mapdelete_faststr(t *maptype, h *hmap, ky string) { top := tophash(hash) search: for ; b != nil; b = b.overflow(t) { - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || b.tophash[i] != top { continue @@ -335,8 +355,8 @@ search: } // Clear key's pointer. k.str = nil - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)) - if t.Elem.PtrBytes != 0 { + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)) + if t.Elem.Pointers() { memclrHasPointers(e, t.Elem.Size_) } else { memclrNoHeapPointers(e, t.Elem.Size_) @@ -344,7 +364,7 @@ search: b.tophash[i] = emptyOne // If the bucket now ends in a bunch of emptyOne states, // change those to emptyRest states. - if i == bucketCnt-1 { + if i == abi.MapBucketCount-1 { if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { goto notLast } @@ -363,7 +383,7 @@ search: c := b for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { } - i = bucketCnt - 1 + i = abi.MapBucketCount - 1 } else { i-- } @@ -411,7 +431,7 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { x := &xy[0] x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.BucketSize))) x.k = add(unsafe.Pointer(x.b), dataOffset) - x.e = add(x.k, bucketCnt*2*goarch.PtrSize) + x.e = add(x.k, abi.MapBucketCount*2*goarch.PtrSize) if !h.sameSizeGrow() { // Only calculate y pointers if we're growing bigger. @@ -419,13 +439,13 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { y := &xy[1] y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.BucketSize))) y.k = add(unsafe.Pointer(y.b), dataOffset) - y.e = add(y.k, bucketCnt*2*goarch.PtrSize) + y.e = add(y.k, abi.MapBucketCount*2*goarch.PtrSize) } for ; b != nil; b = b.overflow(t) { k := add(unsafe.Pointer(b), dataOffset) - e := add(k, bucketCnt*2*goarch.PtrSize) - for i := 0; i < bucketCnt; i, k, e = i+1, add(k, 2*goarch.PtrSize), add(e, uintptr(t.ValueSize)) { + e := add(k, abi.MapBucketCount*2*goarch.PtrSize) + for i := 0; i < abi.MapBucketCount; i, k, e = i+1, add(k, 2*goarch.PtrSize), add(e, uintptr(t.ValueSize)) { top := b.tophash[i] if isEmpty(top) { b.tophash[i] = evacuatedEmpty @@ -447,13 +467,13 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap dst := &xy[useY] // evacuation destination - if dst.i == bucketCnt { + if dst.i == abi.MapBucketCount { dst.b = h.newoverflow(t, dst.b) dst.i = 0 dst.k = add(unsafe.Pointer(dst.b), dataOffset) - dst.e = add(dst.k, bucketCnt*2*goarch.PtrSize) + dst.e = add(dst.k, abi.MapBucketCount*2*goarch.PtrSize) } - dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + dst.b.tophash[dst.i&(abi.MapBucketCount-1)] = top // mask dst.i as an optimization, to avoid a bounds check // Copy key. *(*string)(dst.k) = *(*string)(k) @@ -469,7 +489,7 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { } } // Unlink the overflow buckets & clear key/elem to help GC. - if h.flags&oldIterator == 0 && t.Bucket.PtrBytes != 0 { + if h.flags&oldIterator == 0 && t.Bucket.Pointers() { b := add(h.oldbuckets, oldbucket*uintptr(t.BucketSize)) // Preserve b.tophash because the evacuation // state is maintained there. diff --git a/contrib/go/_std_1.22/src/runtime/mbarrier.go b/contrib/go/_std_1.23/src/runtime/mbarrier.go similarity index 85% rename from contrib/go/_std_1.22/src/runtime/mbarrier.go rename to contrib/go/_std_1.23/src/runtime/mbarrier.go index c4b6c2a789cd..7dc8a1a5e56d 100644 --- a/contrib/go/_std_1.22/src/runtime/mbarrier.go +++ b/contrib/go/_std_1.23/src/runtime/mbarrier.go @@ -148,12 +148,22 @@ import ( // TODO: Perfect for go:nosplitrec since we can't have a safe point // anywhere in the bulk barrier or memmove. // +// typedmemmove should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname typedmemmove //go:nosplit func typedmemmove(typ *abi.Type, dst, src unsafe.Pointer) { if dst == src { return } - if writeBarrier.enabled && typ.PtrBytes != 0 { + if writeBarrier.enabled && typ.Pointers() { // This always copies a full value of type typ so it's safe // to pass typ along as an optimization. See the comment on // bulkBarrierPreWrite. @@ -199,6 +209,18 @@ func wbMove(typ *_type, dst, src unsafe.Pointer) { bulkBarrierPreWrite(uintptr(dst), uintptr(src), typ.PtrBytes, typ) } +// reflect_typedmemmove is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/goccy/json +// - github.com/modern-go/reflect2 +// - github.com/ugorji/go/codec +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_typedmemmove reflect.typedmemmove func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) { if raceenabled { @@ -232,7 +254,7 @@ func reflectlite_typedmemmove(typ *_type, dst, src unsafe.Pointer) { // //go:nosplit func reflectcallmove(typ *_type, dst, src unsafe.Pointer, size uintptr, regs *abi.RegArgs) { - if writeBarrier.enabled && typ != nil && typ.PtrBytes != 0 && size >= goarch.PtrSize { + if writeBarrier.enabled && typ != nil && typ.Pointers() && size >= goarch.PtrSize { // Pass nil for the type. dst does not point to value of type typ, // but rather points into one, so applying the optimization is not // safe. See the comment on this function. @@ -248,6 +270,15 @@ func reflectcallmove(typ *_type, dst, src unsafe.Pointer, size uintptr, regs *ab } } +// typedslicecopy should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/segmentio/encoding +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname typedslicecopy //go:nosplit func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe.Pointer, srcLen int) int { n := dstLen @@ -303,9 +334,21 @@ func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe return n } +// reflect_typedslicecopy is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_typedslicecopy reflect.typedslicecopy func reflect_typedslicecopy(elemType *_type, dst, src slice) int { - if elemType.PtrBytes == 0 { + if !elemType.Pointers() { return slicecopy(dst.array, dst.len, src.array, src.len, elemType.Size_) } return typedslicecopy(elemType, dst.array, dst.len, src.array, src.len) @@ -323,7 +366,7 @@ func reflect_typedslicecopy(elemType *_type, dst, src slice) int { // //go:nosplit func typedmemclr(typ *_type, ptr unsafe.Pointer) { - if writeBarrier.enabled && typ.PtrBytes != 0 { + if writeBarrier.enabled && typ.Pointers() { // This always clears a whole value of type typ, so it's // safe to pass a type here and apply the optimization. // See the comment on bulkBarrierPreWrite. @@ -332,6 +375,14 @@ func typedmemclr(typ *_type, ptr unsafe.Pointer) { memclrNoHeapPointers(ptr, typ.Size_) } +// reflect_typedslicecopy is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_typedmemclr reflect.typedmemclr func reflect_typedmemclr(typ *_type, ptr unsafe.Pointer) { typedmemclr(typ, ptr) @@ -339,7 +390,7 @@ func reflect_typedmemclr(typ *_type, ptr unsafe.Pointer) { //go:linkname reflect_typedmemclrpartial reflect.typedmemclrpartial func reflect_typedmemclrpartial(typ *_type, ptr unsafe.Pointer, off, size uintptr) { - if writeBarrier.enabled && typ.PtrBytes != 0 { + if writeBarrier.enabled && typ.Pointers() { // Pass nil for the type. ptr does not point to value of type typ, // but rather points into one so it's not safe to apply the optimization. // See the comment on this function in the reflect package and the @@ -352,7 +403,7 @@ func reflect_typedmemclrpartial(typ *_type, ptr unsafe.Pointer, off, size uintpt //go:linkname reflect_typedarrayclear reflect.typedarrayclear func reflect_typedarrayclear(typ *_type, ptr unsafe.Pointer, len int) { size := typ.Size_ * uintptr(len) - if writeBarrier.enabled && typ.PtrBytes != 0 { + if writeBarrier.enabled && typ.Pointers() { // This always clears whole elements of an array, so it's // safe to pass a type here. See the comment on bulkBarrierPreWrite. bulkBarrierPreWrite(uintptr(ptr), 0, size, typ) @@ -365,6 +416,15 @@ func reflect_typedarrayclear(typ *_type, ptr unsafe.Pointer, len int) { // pointers, usually by checking typ.PtrBytes. However, ptr // does not have to point to the start of the allocation. // +// memclrHasPointers should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memclrHasPointers //go:nosplit func memclrHasPointers(ptr unsafe.Pointer, n uintptr) { // Pass nil for the type since we don't have one here anyway. diff --git a/contrib/go/_std_1.23/src/runtime/mbitmap.go b/contrib/go/_std_1.23/src/runtime/mbitmap.go new file mode 100644 index 000000000000..689fac103ccf --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/mbitmap.go @@ -0,0 +1,1912 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Garbage collector: type and heap bitmaps. +// +// Stack, data, and bss bitmaps +// +// Stack frames and global variables in the data and bss sections are +// described by bitmaps with 1 bit per pointer-sized word. A "1" bit +// means the word is a live pointer to be visited by the GC (referred to +// as "pointer"). A "0" bit means the word should be ignored by GC +// (referred to as "scalar", though it could be a dead pointer value). +// +// Heap bitmaps +// +// The heap bitmap comprises 1 bit for each pointer-sized word in the heap, +// recording whether a pointer is stored in that word or not. This bitmap +// is stored at the end of a span for small objects and is unrolled at +// runtime from type metadata for all larger objects. Objects without +// pointers have neither a bitmap nor associated type metadata. +// +// Bits in all cases correspond to words in little-endian order. +// +// For small objects, if s is the mspan for the span starting at "start", +// then s.heapBits() returns a slice containing the bitmap for the whole span. +// That is, s.heapBits()[0] holds the goarch.PtrSize*8 bits for the first +// goarch.PtrSize*8 words from "start" through "start+63*ptrSize" in the span. +// On a related note, small objects are always small enough that their bitmap +// fits in goarch.PtrSize*8 bits, so writing out bitmap data takes two bitmap +// writes at most (because object boundaries don't generally lie on +// s.heapBits()[i] boundaries). +// +// For larger objects, if t is the type for the object starting at "start", +// within some span whose mspan is s, then the bitmap at t.GCData is "tiled" +// from "start" through "start+s.elemsize". +// Specifically, the first bit of t.GCData corresponds to the word at "start", +// the second to the word after "start", and so on up to t.PtrBytes. At t.PtrBytes, +// we skip to "start+t.Size_" and begin again from there. This process is +// repeated until we hit "start+s.elemsize". +// This tiling algorithm supports array data, since the type always refers to +// the element type of the array. Single objects are considered the same as +// single-element arrays. +// The tiling algorithm may scan data past the end of the compiler-recognized +// object, but any unused data within the allocation slot (i.e. within s.elemsize) +// is zeroed, so the GC just observes nil pointers. +// Note that this "tiled" bitmap isn't stored anywhere; it is generated on-the-fly. +// +// For objects without their own span, the type metadata is stored in the first +// word before the object at the beginning of the allocation slot. For objects +// with their own span, the type metadata is stored in the mspan. +// +// The bitmap for small unallocated objects in scannable spans is not maintained +// (can be junk). + +package runtime + +import ( + "internal/abi" + "internal/goarch" + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +const ( + // A malloc header is functionally a single type pointer, but + // we need to use 8 here to ensure 8-byte alignment of allocations + // on 32-bit platforms. It's wasteful, but a lot of code relies on + // 8-byte alignment for 8-byte atomics. + mallocHeaderSize = 8 + + // The minimum object size that has a malloc header, exclusive. + // + // The size of this value controls overheads from the malloc header. + // The minimum size is bound by writeHeapBitsSmall, which assumes that the + // pointer bitmap for objects of a size smaller than this doesn't cross + // more than one pointer-word boundary. This sets an upper-bound on this + // value at the number of bits in a uintptr, multiplied by the pointer + // size in bytes. + // + // We choose a value here that has a natural cutover point in terms of memory + // overheads. This value just happens to be the maximum possible value this + // can be. + // + // A span with heap bits in it will have 128 bytes of heap bits on 64-bit + // platforms, and 256 bytes of heap bits on 32-bit platforms. The first size + // class where malloc headers match this overhead for 64-bit platforms is + // 512 bytes (8 KiB / 512 bytes * 8 bytes-per-header = 128 bytes of overhead). + // On 32-bit platforms, this same point is the 256 byte size class + // (8 KiB / 256 bytes * 8 bytes-per-header = 256 bytes of overhead). + // + // Guaranteed to be exactly at a size class boundary. The reason this value is + // an exclusive minimum is subtle. Suppose we're allocating a 504-byte object + // and its rounded up to 512 bytes for the size class. If minSizeForMallocHeader + // is 512 and an inclusive minimum, then a comparison against minSizeForMallocHeader + // by the two values would produce different results. In other words, the comparison + // would not be invariant to size-class rounding. Eschewing this property means a + // more complex check or possibly storing additional state to determine whether a + // span has malloc headers. + minSizeForMallocHeader = goarch.PtrSize * ptrBits +) + +// heapBitsInSpan returns true if the size of an object implies its ptr/scalar +// data is stored at the end of the span, and is accessible via span.heapBits. +// +// Note: this works for both rounded-up sizes (span.elemsize) and unrounded +// type sizes because minSizeForMallocHeader is guaranteed to be at a size +// class boundary. +// +//go:nosplit +func heapBitsInSpan(userSize uintptr) bool { + // N.B. minSizeForMallocHeader is an exclusive minimum so that this function is + // invariant under size-class rounding on its input. + return userSize <= minSizeForMallocHeader +} + +// typePointers is an iterator over the pointers in a heap object. +// +// Iteration through this type implements the tiling algorithm described at the +// top of this file. +type typePointers struct { + // elem is the address of the current array element of type typ being iterated over. + // Objects that are not arrays are treated as single-element arrays, in which case + // this value does not change. + elem uintptr + + // addr is the address the iterator is currently working from and describes + // the address of the first word referenced by mask. + addr uintptr + + // mask is a bitmask where each bit corresponds to pointer-words after addr. + // Bit 0 is the pointer-word at addr, Bit 1 is the next word, and so on. + // If a bit is 1, then there is a pointer at that word. + // nextFast and next mask out bits in this mask as their pointers are processed. + mask uintptr + + // typ is a pointer to the type information for the heap object's type. + // This may be nil if the object is in a span where heapBitsInSpan(span.elemsize) is true. + typ *_type +} + +// typePointersOf returns an iterator over all heap pointers in the range [addr, addr+size). +// +// addr and addr+size must be in the range [span.base(), span.limit). +// +// Note: addr+size must be passed as the limit argument to the iterator's next method on +// each iteration. This slightly awkward API is to allow typePointers to be destructured +// by the compiler. +// +// nosplit because it is used during write barriers and must not be preempted. +// +//go:nosplit +func (span *mspan) typePointersOf(addr, size uintptr) typePointers { + base := span.objBase(addr) + tp := span.typePointersOfUnchecked(base) + if base == addr && size == span.elemsize { + return tp + } + return tp.fastForward(addr-tp.addr, addr+size) +} + +// typePointersOfUnchecked is like typePointersOf, but assumes addr is the base +// of an allocation slot in a span (the start of the object if no header, the +// header otherwise). It returns an iterator that generates all pointers +// in the range [addr, addr+span.elemsize). +// +// nosplit because it is used during write barriers and must not be preempted. +// +//go:nosplit +func (span *mspan) typePointersOfUnchecked(addr uintptr) typePointers { + const doubleCheck = false + if doubleCheck && span.objBase(addr) != addr { + print("runtime: addr=", addr, " base=", span.objBase(addr), "\n") + throw("typePointersOfUnchecked consisting of non-base-address for object") + } + + spc := span.spanclass + if spc.noscan() { + return typePointers{} + } + if heapBitsInSpan(span.elemsize) { + // Handle header-less objects. + return typePointers{elem: addr, addr: addr, mask: span.heapBitsSmallForAddr(addr)} + } + + // All of these objects have a header. + var typ *_type + if spc.sizeclass() != 0 { + // Pull the allocation header from the first word of the object. + typ = *(**_type)(unsafe.Pointer(addr)) + addr += mallocHeaderSize + } else { + typ = span.largeType + if typ == nil { + // Allow a nil type here for delayed zeroing. See mallocgc. + return typePointers{} + } + } + gcdata := typ.GCData + return typePointers{elem: addr, addr: addr, mask: readUintptr(gcdata), typ: typ} +} + +// typePointersOfType is like typePointersOf, but assumes addr points to one or more +// contiguous instances of the provided type. The provided type must not be nil and +// it must not have its type metadata encoded as a gcprog. +// +// It returns an iterator that tiles typ.GCData starting from addr. It's the caller's +// responsibility to limit iteration. +// +// nosplit because its callers are nosplit and require all their callees to be nosplit. +// +//go:nosplit +func (span *mspan) typePointersOfType(typ *abi.Type, addr uintptr) typePointers { + const doubleCheck = false + if doubleCheck && (typ == nil || typ.Kind_&abi.KindGCProg != 0) { + throw("bad type passed to typePointersOfType") + } + if span.spanclass.noscan() { + return typePointers{} + } + // Since we have the type, pretend we have a header. + gcdata := typ.GCData + return typePointers{elem: addr, addr: addr, mask: readUintptr(gcdata), typ: typ} +} + +// nextFast is the fast path of next. nextFast is written to be inlineable and, +// as the name implies, fast. +// +// Callers that are performance-critical should iterate using the following +// pattern: +// +// for { +// var addr uintptr +// if tp, addr = tp.nextFast(); addr == 0 { +// if tp, addr = tp.next(limit); addr == 0 { +// break +// } +// } +// // Use addr. +// ... +// } +// +// nosplit because it is used during write barriers and must not be preempted. +// +//go:nosplit +func (tp typePointers) nextFast() (typePointers, uintptr) { + // TESTQ/JEQ + if tp.mask == 0 { + return tp, 0 + } + // BSFQ + var i int + if goarch.PtrSize == 8 { + i = sys.TrailingZeros64(uint64(tp.mask)) + } else { + i = sys.TrailingZeros32(uint32(tp.mask)) + } + // BTCQ + tp.mask ^= uintptr(1) << (i & (ptrBits - 1)) + // LEAQ (XX)(XX*8) + return tp, tp.addr + uintptr(i)*goarch.PtrSize +} + +// next advances the pointers iterator, returning the updated iterator and +// the address of the next pointer. +// +// limit must be the same each time it is passed to next. +// +// nosplit because it is used during write barriers and must not be preempted. +// +//go:nosplit +func (tp typePointers) next(limit uintptr) (typePointers, uintptr) { + for { + if tp.mask != 0 { + return tp.nextFast() + } + + // Stop if we don't actually have type information. + if tp.typ == nil { + return typePointers{}, 0 + } + + // Advance to the next element if necessary. + if tp.addr+goarch.PtrSize*ptrBits >= tp.elem+tp.typ.PtrBytes { + tp.elem += tp.typ.Size_ + tp.addr = tp.elem + } else { + tp.addr += ptrBits * goarch.PtrSize + } + + // Check if we've exceeded the limit with the last update. + if tp.addr >= limit { + return typePointers{}, 0 + } + + // Grab more bits and try again. + tp.mask = readUintptr(addb(tp.typ.GCData, (tp.addr-tp.elem)/goarch.PtrSize/8)) + if tp.addr+goarch.PtrSize*ptrBits > limit { + bits := (tp.addr + goarch.PtrSize*ptrBits - limit) / goarch.PtrSize + tp.mask &^= ((1 << (bits)) - 1) << (ptrBits - bits) + } + } +} + +// fastForward moves the iterator forward by n bytes. n must be a multiple +// of goarch.PtrSize. limit must be the same limit passed to next for this +// iterator. +// +// nosplit because it is used during write barriers and must not be preempted. +// +//go:nosplit +func (tp typePointers) fastForward(n, limit uintptr) typePointers { + // Basic bounds check. + target := tp.addr + n + if target >= limit { + return typePointers{} + } + if tp.typ == nil { + // Handle small objects. + // Clear any bits before the target address. + tp.mask &^= (1 << ((target - tp.addr) / goarch.PtrSize)) - 1 + // Clear any bits past the limit. + if tp.addr+goarch.PtrSize*ptrBits > limit { + bits := (tp.addr + goarch.PtrSize*ptrBits - limit) / goarch.PtrSize + tp.mask &^= ((1 << (bits)) - 1) << (ptrBits - bits) + } + return tp + } + + // Move up elem and addr. + // Offsets within an element are always at a ptrBits*goarch.PtrSize boundary. + if n >= tp.typ.Size_ { + // elem needs to be moved to the element containing + // tp.addr + n. + oldelem := tp.elem + tp.elem += (tp.addr - tp.elem + n) / tp.typ.Size_ * tp.typ.Size_ + tp.addr = tp.elem + alignDown(n-(tp.elem-oldelem), ptrBits*goarch.PtrSize) + } else { + tp.addr += alignDown(n, ptrBits*goarch.PtrSize) + } + + if tp.addr-tp.elem >= tp.typ.PtrBytes { + // We're starting in the non-pointer area of an array. + // Move up to the next element. + tp.elem += tp.typ.Size_ + tp.addr = tp.elem + tp.mask = readUintptr(tp.typ.GCData) + + // We may have exceeded the limit after this. Bail just like next does. + if tp.addr >= limit { + return typePointers{} + } + } else { + // Grab the mask, but then clear any bits before the target address and any + // bits over the limit. + tp.mask = readUintptr(addb(tp.typ.GCData, (tp.addr-tp.elem)/goarch.PtrSize/8)) + tp.mask &^= (1 << ((target - tp.addr) / goarch.PtrSize)) - 1 + } + if tp.addr+goarch.PtrSize*ptrBits > limit { + bits := (tp.addr + goarch.PtrSize*ptrBits - limit) / goarch.PtrSize + tp.mask &^= ((1 << (bits)) - 1) << (ptrBits - bits) + } + return tp +} + +// objBase returns the base pointer for the object containing addr in span. +// +// Assumes that addr points into a valid part of span (span.base() <= addr < span.limit). +// +//go:nosplit +func (span *mspan) objBase(addr uintptr) uintptr { + return span.base() + span.objIndex(addr)*span.elemsize +} + +// bulkBarrierPreWrite executes a write barrier +// for every pointer slot in the memory range [src, src+size), +// using pointer/scalar information from [dst, dst+size). +// This executes the write barriers necessary before a memmove. +// src, dst, and size must be pointer-aligned. +// The range [dst, dst+size) must lie within a single object. +// It does not perform the actual writes. +// +// As a special case, src == 0 indicates that this is being used for a +// memclr. bulkBarrierPreWrite will pass 0 for the src of each write +// barrier. +// +// Callers should call bulkBarrierPreWrite immediately before +// calling memmove(dst, src, size). This function is marked nosplit +// to avoid being preempted; the GC must not stop the goroutine +// between the memmove and the execution of the barriers. +// The caller is also responsible for cgo pointer checks if this +// may be writing Go pointers into non-Go memory. +// +// Pointer data is not maintained for allocations containing +// no pointers at all; any caller of bulkBarrierPreWrite must first +// make sure the underlying allocation contains pointers, usually +// by checking typ.PtrBytes. +// +// The typ argument is the type of the space at src and dst (and the +// element type if src and dst refer to arrays) and it is optional. +// If typ is nil, the barrier will still behave as expected and typ +// is used purely as an optimization. However, it must be used with +// care. +// +// If typ is not nil, then src and dst must point to one or more values +// of type typ. The caller must ensure that the ranges [src, src+size) +// and [dst, dst+size) refer to one or more whole values of type src and +// dst (leaving off the pointerless tail of the space is OK). If this +// precondition is not followed, this function will fail to scan the +// right pointers. +// +// When in doubt, pass nil for typ. That is safe and will always work. +// +// Callers must perform cgo checks if goexperiment.CgoCheck2. +// +//go:nosplit +func bulkBarrierPreWrite(dst, src, size uintptr, typ *abi.Type) { + if (dst|src|size)&(goarch.PtrSize-1) != 0 { + throw("bulkBarrierPreWrite: unaligned arguments") + } + if !writeBarrier.enabled { + return + } + s := spanOf(dst) + if s == nil { + // If dst is a global, use the data or BSS bitmaps to + // execute write barriers. + for _, datap := range activeModules() { + if datap.data <= dst && dst < datap.edata { + bulkBarrierBitmap(dst, src, size, dst-datap.data, datap.gcdatamask.bytedata) + return + } + } + for _, datap := range activeModules() { + if datap.bss <= dst && dst < datap.ebss { + bulkBarrierBitmap(dst, src, size, dst-datap.bss, datap.gcbssmask.bytedata) + return + } + } + return + } else if s.state.get() != mSpanInUse || dst < s.base() || s.limit <= dst { + // dst was heap memory at some point, but isn't now. + // It can't be a global. It must be either our stack, + // or in the case of direct channel sends, it could be + // another stack. Either way, no need for barriers. + // This will also catch if dst is in a freed span, + // though that should never have. + return + } + buf := &getg().m.p.ptr().wbBuf + + // Double-check that the bitmaps generated in the two possible paths match. + const doubleCheck = false + if doubleCheck { + doubleCheckTypePointersOfType(s, typ, dst, size) + } + + var tp typePointers + if typ != nil && typ.Kind_&abi.KindGCProg == 0 { + tp = s.typePointersOfType(typ, dst) + } else { + tp = s.typePointersOf(dst, size) + } + if src == 0 { + for { + var addr uintptr + if tp, addr = tp.next(dst + size); addr == 0 { + break + } + dstx := (*uintptr)(unsafe.Pointer(addr)) + p := buf.get1() + p[0] = *dstx + } + } else { + for { + var addr uintptr + if tp, addr = tp.next(dst + size); addr == 0 { + break + } + dstx := (*uintptr)(unsafe.Pointer(addr)) + srcx := (*uintptr)(unsafe.Pointer(src + (addr - dst))) + p := buf.get2() + p[0] = *dstx + p[1] = *srcx + } + } +} + +// bulkBarrierPreWriteSrcOnly is like bulkBarrierPreWrite but +// does not execute write barriers for [dst, dst+size). +// +// In addition to the requirements of bulkBarrierPreWrite +// callers need to ensure [dst, dst+size) is zeroed. +// +// This is used for special cases where e.g. dst was just +// created and zeroed with malloc. +// +// The type of the space can be provided purely as an optimization. +// See bulkBarrierPreWrite's comment for more details -- use this +// optimization with great care. +// +//go:nosplit +func bulkBarrierPreWriteSrcOnly(dst, src, size uintptr, typ *abi.Type) { + if (dst|src|size)&(goarch.PtrSize-1) != 0 { + throw("bulkBarrierPreWrite: unaligned arguments") + } + if !writeBarrier.enabled { + return + } + buf := &getg().m.p.ptr().wbBuf + s := spanOf(dst) + + // Double-check that the bitmaps generated in the two possible paths match. + const doubleCheck = false + if doubleCheck { + doubleCheckTypePointersOfType(s, typ, dst, size) + } + + var tp typePointers + if typ != nil && typ.Kind_&abi.KindGCProg == 0 { + tp = s.typePointersOfType(typ, dst) + } else { + tp = s.typePointersOf(dst, size) + } + for { + var addr uintptr + if tp, addr = tp.next(dst + size); addr == 0 { + break + } + srcx := (*uintptr)(unsafe.Pointer(addr - dst + src)) + p := buf.get1() + p[0] = *srcx + } +} + +// initHeapBits initializes the heap bitmap for a span. +// +// TODO(mknyszek): This should set the heap bits for single pointer +// allocations eagerly to avoid calling heapSetType at allocation time, +// just to write one bit. +func (s *mspan) initHeapBits(forceClear bool) { + if (!s.spanclass.noscan() && heapBitsInSpan(s.elemsize)) || s.isUserArenaChunk { + b := s.heapBits() + clear(b) + } +} + +// heapBits returns the heap ptr/scalar bits stored at the end of the span for +// small object spans and heap arena spans. +// +// Note that the uintptr of each element means something different for small object +// spans and for heap arena spans. Small object spans are easy: they're never interpreted +// as anything but uintptr, so they're immune to differences in endianness. However, the +// heapBits for user arena spans is exposed through a dummy type descriptor, so the byte +// ordering needs to match the same byte ordering the compiler would emit. The compiler always +// emits the bitmap data in little endian byte ordering, so on big endian platforms these +// uintptrs will have their byte orders swapped from what they normally would be. +// +// heapBitsInSpan(span.elemsize) or span.isUserArenaChunk must be true. +// +//go:nosplit +func (span *mspan) heapBits() []uintptr { + const doubleCheck = false + + if doubleCheck && !span.isUserArenaChunk { + if span.spanclass.noscan() { + throw("heapBits called for noscan") + } + if span.elemsize > minSizeForMallocHeader { + throw("heapBits called for span class that should have a malloc header") + } + } + // Find the bitmap at the end of the span. + // + // Nearly every span with heap bits is exactly one page in size. Arenas are the only exception. + if span.npages == 1 { + // This will be inlined and constant-folded down. + return heapBitsSlice(span.base(), pageSize) + } + return heapBitsSlice(span.base(), span.npages*pageSize) +} + +// Helper for constructing a slice for the span's heap bits. +// +//go:nosplit +func heapBitsSlice(spanBase, spanSize uintptr) []uintptr { + bitmapSize := spanSize / goarch.PtrSize / 8 + elems := int(bitmapSize / goarch.PtrSize) + var sl notInHeapSlice + sl = notInHeapSlice{(*notInHeap)(unsafe.Pointer(spanBase + spanSize - bitmapSize)), elems, elems} + return *(*[]uintptr)(unsafe.Pointer(&sl)) +} + +// heapBitsSmallForAddr loads the heap bits for the object stored at addr from span.heapBits. +// +// addr must be the base pointer of an object in the span. heapBitsInSpan(span.elemsize) +// must be true. +// +//go:nosplit +func (span *mspan) heapBitsSmallForAddr(addr uintptr) uintptr { + spanSize := span.npages * pageSize + bitmapSize := spanSize / goarch.PtrSize / 8 + hbits := (*byte)(unsafe.Pointer(span.base() + spanSize - bitmapSize)) + + // These objects are always small enough that their bitmaps + // fit in a single word, so just load the word or two we need. + // + // Mirrors mspan.writeHeapBitsSmall. + // + // We should be using heapBits(), but unfortunately it introduces + // both bounds checks panics and throw which causes us to exceed + // the nosplit limit in quite a few cases. + i := (addr - span.base()) / goarch.PtrSize / ptrBits + j := (addr - span.base()) / goarch.PtrSize % ptrBits + bits := span.elemsize / goarch.PtrSize + word0 := (*uintptr)(unsafe.Pointer(addb(hbits, goarch.PtrSize*(i+0)))) + word1 := (*uintptr)(unsafe.Pointer(addb(hbits, goarch.PtrSize*(i+1)))) + + var read uintptr + if j+bits > ptrBits { + // Two reads. + bits0 := ptrBits - j + bits1 := bits - bits0 + read = *word0 >> j + read |= (*word1 & ((1 << bits1) - 1)) << bits0 + } else { + // One read. + read = (*word0 >> j) & ((1 << bits) - 1) + } + return read +} + +// writeHeapBitsSmall writes the heap bits for small objects whose ptr/scalar data is +// stored as a bitmap at the end of the span. +// +// Assumes dataSize is <= ptrBits*goarch.PtrSize. x must be a pointer into the span. +// heapBitsInSpan(dataSize) must be true. dataSize must be >= typ.Size_. +// +//go:nosplit +func (span *mspan) writeHeapBitsSmall(x, dataSize uintptr, typ *_type) (scanSize uintptr) { + // The objects here are always really small, so a single load is sufficient. + src0 := readUintptr(typ.GCData) + + // Create repetitions of the bitmap if we have a small array. + bits := span.elemsize / goarch.PtrSize + scanSize = typ.PtrBytes + src := src0 + switch typ.Size_ { + case goarch.PtrSize: + src = (1 << (dataSize / goarch.PtrSize)) - 1 + default: + for i := typ.Size_; i < dataSize; i += typ.Size_ { + src |= src0 << (i / goarch.PtrSize) + scanSize += typ.Size_ + } + } + + // Since we're never writing more than one uintptr's worth of bits, we're either going + // to do one or two writes. + dst := span.heapBits() + o := (x - span.base()) / goarch.PtrSize + i := o / ptrBits + j := o % ptrBits + if j+bits > ptrBits { + // Two writes. + bits0 := ptrBits - j + bits1 := bits - bits0 + dst[i+0] = dst[i+0]&(^uintptr(0)>>bits0) | (src << j) + dst[i+1] = dst[i+1]&^((1<> bits0) + } else { + // One write. + dst[i] = (dst[i] &^ (((1 << bits) - 1) << j)) | (src << j) + } + + const doubleCheck = false + if doubleCheck { + srcRead := span.heapBitsSmallForAddr(x) + if srcRead != src { + print("runtime: x=", hex(x), " i=", i, " j=", j, " bits=", bits, "\n") + print("runtime: dataSize=", dataSize, " typ.Size_=", typ.Size_, " typ.PtrBytes=", typ.PtrBytes, "\n") + print("runtime: src0=", hex(src0), " src=", hex(src), " srcRead=", hex(srcRead), "\n") + throw("bad pointer bits written for small object") + } + } + return +} + +// heapSetType records that the new allocation [x, x+size) +// holds in [x, x+dataSize) one or more values of type typ. +// (The number of values is given by dataSize / typ.Size.) +// If dataSize < size, the fragment [x+dataSize, x+size) is +// recorded as non-pointer data. +// It is known that the type has pointers somewhere; +// malloc does not call heapSetType when there are no pointers. +// +// There can be read-write races between heapSetType and things +// that read the heap metadata like scanobject. However, since +// heapSetType is only used for objects that have not yet been +// made reachable, readers will ignore bits being modified by this +// function. This does mean this function cannot transiently modify +// shared memory that belongs to neighboring objects. Also, on weakly-ordered +// machines, callers must execute a store/store (publication) barrier +// between calling this function and making the object reachable. +func heapSetType(x, dataSize uintptr, typ *_type, header **_type, span *mspan) (scanSize uintptr) { + const doubleCheck = false + + gctyp := typ + if header == nil { + if doubleCheck && (!heapBitsInSpan(dataSize) || !heapBitsInSpan(span.elemsize)) { + throw("tried to write heap bits, but no heap bits in span") + } + // Handle the case where we have no malloc header. + scanSize = span.writeHeapBitsSmall(x, dataSize, typ) + } else { + if typ.Kind_&abi.KindGCProg != 0 { + // Allocate space to unroll the gcprog. This space will consist of + // a dummy _type value and the unrolled gcprog. The dummy _type will + // refer to the bitmap, and the mspan will refer to the dummy _type. + if span.spanclass.sizeclass() != 0 { + throw("GCProg for type that isn't large") + } + spaceNeeded := alignUp(unsafe.Sizeof(_type{}), goarch.PtrSize) + heapBitsOff := spaceNeeded + spaceNeeded += alignUp(typ.PtrBytes/goarch.PtrSize/8, goarch.PtrSize) + npages := alignUp(spaceNeeded, pageSize) / pageSize + var progSpan *mspan + systemstack(func() { + progSpan = mheap_.allocManual(npages, spanAllocPtrScalarBits) + memclrNoHeapPointers(unsafe.Pointer(progSpan.base()), progSpan.npages*pageSize) + }) + // Write a dummy _type in the new space. + // + // We only need to write size, PtrBytes, and GCData, since that's all + // the GC cares about. + gctyp = (*_type)(unsafe.Pointer(progSpan.base())) + gctyp.Size_ = typ.Size_ + gctyp.PtrBytes = typ.PtrBytes + gctyp.GCData = (*byte)(add(unsafe.Pointer(progSpan.base()), heapBitsOff)) + gctyp.TFlag = abi.TFlagUnrolledBitmap + + // Expand the GC program into space reserved at the end of the new span. + runGCProg(addb(typ.GCData, 4), gctyp.GCData) + } + + // Write out the header. + *header = gctyp + scanSize = span.elemsize + } + + if doubleCheck { + doubleCheckHeapPointers(x, dataSize, gctyp, header, span) + + // To exercise the less common path more often, generate + // a random interior pointer and make sure iterating from + // that point works correctly too. + maxIterBytes := span.elemsize + if header == nil { + maxIterBytes = dataSize + } + off := alignUp(uintptr(cheaprand())%dataSize, goarch.PtrSize) + size := dataSize - off + if size == 0 { + off -= goarch.PtrSize + size += goarch.PtrSize + } + interior := x + off + size -= alignDown(uintptr(cheaprand())%size, goarch.PtrSize) + if size == 0 { + size = goarch.PtrSize + } + // Round up the type to the size of the type. + size = (size + gctyp.Size_ - 1) / gctyp.Size_ * gctyp.Size_ + if interior+size > x+maxIterBytes { + size = x + maxIterBytes - interior + } + doubleCheckHeapPointersInterior(x, interior, size, dataSize, gctyp, header, span) + } + return +} + +func doubleCheckHeapPointers(x, dataSize uintptr, typ *_type, header **_type, span *mspan) { + // Check that scanning the full object works. + tp := span.typePointersOfUnchecked(span.objBase(x)) + maxIterBytes := span.elemsize + if header == nil { + maxIterBytes = dataSize + } + bad := false + for i := uintptr(0); i < maxIterBytes; i += goarch.PtrSize { + // Compute the pointer bit we want at offset i. + want := false + if i < span.elemsize { + off := i % typ.Size_ + if off < typ.PtrBytes { + j := off / goarch.PtrSize + want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 + } + } + if want { + var addr uintptr + tp, addr = tp.next(x + span.elemsize) + if addr == 0 { + println("runtime: found bad iterator") + } + if addr != x+i { + print("runtime: addr=", hex(addr), " x+i=", hex(x+i), "\n") + bad = true + } + } + } + if !bad { + var addr uintptr + tp, addr = tp.next(x + span.elemsize) + if addr == 0 { + return + } + println("runtime: extra pointer:", hex(addr)) + } + print("runtime: hasHeader=", header != nil, " typ.Size_=", typ.Size_, " hasGCProg=", typ.Kind_&abi.KindGCProg != 0, "\n") + print("runtime: x=", hex(x), " dataSize=", dataSize, " elemsize=", span.elemsize, "\n") + print("runtime: typ=", unsafe.Pointer(typ), " typ.PtrBytes=", typ.PtrBytes, "\n") + print("runtime: limit=", hex(x+span.elemsize), "\n") + tp = span.typePointersOfUnchecked(x) + dumpTypePointers(tp) + for { + var addr uintptr + if tp, addr = tp.next(x + span.elemsize); addr == 0 { + println("runtime: would've stopped here") + dumpTypePointers(tp) + break + } + print("runtime: addr=", hex(addr), "\n") + dumpTypePointers(tp) + } + throw("heapSetType: pointer entry not correct") +} + +func doubleCheckHeapPointersInterior(x, interior, size, dataSize uintptr, typ *_type, header **_type, span *mspan) { + bad := false + if interior < x { + print("runtime: interior=", hex(interior), " x=", hex(x), "\n") + throw("found bad interior pointer") + } + off := interior - x + tp := span.typePointersOf(interior, size) + for i := off; i < off+size; i += goarch.PtrSize { + // Compute the pointer bit we want at offset i. + want := false + if i < span.elemsize { + off := i % typ.Size_ + if off < typ.PtrBytes { + j := off / goarch.PtrSize + want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 + } + } + if want { + var addr uintptr + tp, addr = tp.next(interior + size) + if addr == 0 { + println("runtime: found bad iterator") + bad = true + } + if addr != x+i { + print("runtime: addr=", hex(addr), " x+i=", hex(x+i), "\n") + bad = true + } + } + } + if !bad { + var addr uintptr + tp, addr = tp.next(interior + size) + if addr == 0 { + return + } + println("runtime: extra pointer:", hex(addr)) + } + print("runtime: hasHeader=", header != nil, " typ.Size_=", typ.Size_, "\n") + print("runtime: x=", hex(x), " dataSize=", dataSize, " elemsize=", span.elemsize, " interior=", hex(interior), " size=", size, "\n") + print("runtime: limit=", hex(interior+size), "\n") + tp = span.typePointersOf(interior, size) + dumpTypePointers(tp) + for { + var addr uintptr + if tp, addr = tp.next(interior + size); addr == 0 { + println("runtime: would've stopped here") + dumpTypePointers(tp) + break + } + print("runtime: addr=", hex(addr), "\n") + dumpTypePointers(tp) + } + + print("runtime: want: ") + for i := off; i < off+size; i += goarch.PtrSize { + // Compute the pointer bit we want at offset i. + want := false + if i < dataSize { + off := i % typ.Size_ + if off < typ.PtrBytes { + j := off / goarch.PtrSize + want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 + } + } + if want { + print("1") + } else { + print("0") + } + } + println() + + throw("heapSetType: pointer entry not correct") +} + +//go:nosplit +func doubleCheckTypePointersOfType(s *mspan, typ *_type, addr, size uintptr) { + if typ == nil || typ.Kind_&abi.KindGCProg != 0 { + return + } + if typ.Kind_&abi.KindMask == abi.Interface { + // Interfaces are unfortunately inconsistently handled + // when it comes to the type pointer, so it's easy to + // produce a lot of false positives here. + return + } + tp0 := s.typePointersOfType(typ, addr) + tp1 := s.typePointersOf(addr, size) + failed := false + for { + var addr0, addr1 uintptr + tp0, addr0 = tp0.next(addr + size) + tp1, addr1 = tp1.next(addr + size) + if addr0 != addr1 { + failed = true + break + } + if addr0 == 0 { + break + } + } + if failed { + tp0 := s.typePointersOfType(typ, addr) + tp1 := s.typePointersOf(addr, size) + print("runtime: addr=", hex(addr), " size=", size, "\n") + print("runtime: type=", toRType(typ).string(), "\n") + dumpTypePointers(tp0) + dumpTypePointers(tp1) + for { + var addr0, addr1 uintptr + tp0, addr0 = tp0.next(addr + size) + tp1, addr1 = tp1.next(addr + size) + print("runtime: ", hex(addr0), " ", hex(addr1), "\n") + if addr0 == 0 && addr1 == 0 { + break + } + } + throw("mismatch between typePointersOfType and typePointersOf") + } +} + +func dumpTypePointers(tp typePointers) { + print("runtime: tp.elem=", hex(tp.elem), " tp.typ=", unsafe.Pointer(tp.typ), "\n") + print("runtime: tp.addr=", hex(tp.addr), " tp.mask=") + for i := uintptr(0); i < ptrBits; i++ { + if tp.mask&(uintptr(1)< snelems { + throw("s.freeindex > s.nelems") + } + + aCache := s.allocCache + + bitIndex := sys.TrailingZeros64(aCache) + for bitIndex == 64 { + // Move index to start of next cached bits. + sfreeindex = (sfreeindex + 64) &^ (64 - 1) + if sfreeindex >= snelems { + s.freeindex = snelems + return snelems + } + whichByte := sfreeindex / 8 + // Refill s.allocCache with the next 64 alloc bits. + s.refillAllocCache(whichByte) + aCache = s.allocCache + bitIndex = sys.TrailingZeros64(aCache) + // nothing available in cached bits + // grab the next 8 bytes and try again. + } + result := sfreeindex + uint16(bitIndex) + if result >= snelems { + s.freeindex = snelems + return snelems + } + + s.allocCache >>= uint(bitIndex + 1) + sfreeindex = result + 1 + + if sfreeindex%64 == 0 && sfreeindex != snelems { + // We just incremented s.freeindex so it isn't 0. + // As each 1 in s.allocCache was encountered and used for allocation + // it was shifted away. At this point s.allocCache contains all 0s. + // Refill s.allocCache so that it corresponds + // to the bits at s.allocBits starting at s.freeindex. + whichByte := sfreeindex / 8 + s.refillAllocCache(whichByte) + } + s.freeindex = sfreeindex + return result +} + +// isFree reports whether the index'th object in s is unallocated. +// +// The caller must ensure s.state is mSpanInUse, and there must have +// been no preemption points since ensuring this (which could allow a +// GC transition, which would allow the state to change). +func (s *mspan) isFree(index uintptr) bool { + if index < uintptr(s.freeIndexForScan) { + return false + } + bytep, mask := s.allocBits.bitp(index) + return *bytep&mask == 0 +} + +// divideByElemSize returns n/s.elemsize. +// n must be within [0, s.npages*_PageSize), +// or may be exactly s.npages*_PageSize +// if s.elemsize is from sizeclasses.go. +// +// nosplit, because it is called by objIndex, which is nosplit +// +//go:nosplit +func (s *mspan) divideByElemSize(n uintptr) uintptr { + const doubleCheck = false + + // See explanation in mksizeclasses.go's computeDivMagic. + q := uintptr((uint64(n) * uint64(s.divMul)) >> 32) + + if doubleCheck && q != n/s.elemsize { + println(n, "/", s.elemsize, "should be", n/s.elemsize, "but got", q) + throw("bad magic division") + } + return q +} + +// nosplit, because it is called by other nosplit code like findObject +// +//go:nosplit +func (s *mspan) objIndex(p uintptr) uintptr { + return s.divideByElemSize(p - s.base()) +} + +func markBitsForAddr(p uintptr) markBits { + s := spanOf(p) + objIndex := s.objIndex(p) + return s.markBitsForIndex(objIndex) +} + +func (s *mspan) markBitsForIndex(objIndex uintptr) markBits { + bytep, mask := s.gcmarkBits.bitp(objIndex) + return markBits{bytep, mask, objIndex} +} + +func (s *mspan) markBitsForBase() markBits { + return markBits{&s.gcmarkBits.x, uint8(1), 0} +} + +// isMarked reports whether mark bit m is set. +func (m markBits) isMarked() bool { + return *m.bytep&m.mask != 0 +} + +// setMarked sets the marked bit in the markbits, atomically. +func (m markBits) setMarked() { + // Might be racing with other updates, so use atomic update always. + // We used to be clever here and use a non-atomic update in certain + // cases, but it's not worth the risk. + atomic.Or8(m.bytep, m.mask) +} + +// setMarkedNonAtomic sets the marked bit in the markbits, non-atomically. +func (m markBits) setMarkedNonAtomic() { + *m.bytep |= m.mask +} + +// clearMarked clears the marked bit in the markbits, atomically. +func (m markBits) clearMarked() { + // Might be racing with other updates, so use atomic update always. + // We used to be clever here and use a non-atomic update in certain + // cases, but it's not worth the risk. + atomic.And8(m.bytep, ^m.mask) +} + +// markBitsForSpan returns the markBits for the span base address base. +func markBitsForSpan(base uintptr) (mbits markBits) { + mbits = markBitsForAddr(base) + if mbits.mask != 1 { + throw("markBitsForSpan: unaligned start") + } + return mbits +} + +// advance advances the markBits to the next object in the span. +func (m *markBits) advance() { + if m.mask == 1<<7 { + m.bytep = (*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(m.bytep)) + 1)) + m.mask = 1 + } else { + m.mask = m.mask << 1 + } + m.index++ +} + +// clobberdeadPtr is a special value that is used by the compiler to +// clobber dead stack slots, when -clobberdead flag is set. +const clobberdeadPtr = uintptr(0xdeaddead | 0xdeaddead<<((^uintptr(0)>>63)*32)) + +// badPointer throws bad pointer in heap panic. +func badPointer(s *mspan, p, refBase, refOff uintptr) { + // Typically this indicates an incorrect use + // of unsafe or cgo to store a bad pointer in + // the Go heap. It may also indicate a runtime + // bug. + // + // TODO(austin): We could be more aggressive + // and detect pointers to unallocated objects + // in allocated spans. + printlock() + print("runtime: pointer ", hex(p)) + if s != nil { + state := s.state.get() + if state != mSpanInUse { + print(" to unallocated span") + } else { + print(" to unused region of span") + } + print(" span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", state) + } + print("\n") + if refBase != 0 { + print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n") + gcDumpObject("object", refBase, refOff) + } + getg().m.traceback = 2 + throw("found bad pointer in Go heap (incorrect use of unsafe or cgo?)") +} + +// findObject returns the base address for the heap object containing +// the address p, the object's span, and the index of the object in s. +// If p does not point into a heap object, it returns base == 0. +// +// If p points is an invalid heap pointer and debug.invalidptr != 0, +// findObject panics. +// +// refBase and refOff optionally give the base address of the object +// in which the pointer p was found and the byte offset at which it +// was found. These are used for error reporting. +// +// It is nosplit so it is safe for p to be a pointer to the current goroutine's stack. +// Since p is a uintptr, it would not be adjusted if the stack were to move. +// +// findObject should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname findObject +//go:nosplit +func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex uintptr) { + s = spanOf(p) + // If s is nil, the virtual address has never been part of the heap. + // This pointer may be to some mmap'd region, so we allow it. + if s == nil { + if (GOARCH == "amd64" || GOARCH == "arm64") && p == clobberdeadPtr && debug.invalidptr != 0 { + // Crash if clobberdeadPtr is seen. Only on AMD64 and ARM64 for now, + // as they are the only platform where compiler's clobberdead mode is + // implemented. On these platforms clobberdeadPtr cannot be a valid address. + badPointer(s, p, refBase, refOff) + } + return + } + // If p is a bad pointer, it may not be in s's bounds. + // + // Check s.state to synchronize with span initialization + // before checking other fields. See also spanOfHeap. + if state := s.state.get(); state != mSpanInUse || p < s.base() || p >= s.limit { + // Pointers into stacks are also ok, the runtime manages these explicitly. + if state == mSpanManual { + return + } + // The following ensures that we are rigorous about what data + // structures hold valid pointers. + if debug.invalidptr != 0 { + badPointer(s, p, refBase, refOff) + } + return + } + + objIndex = s.objIndex(p) + base = s.base() + objIndex*s.elemsize + return +} + +// reflect_verifyNotInHeapPtr reports whether converting the not-in-heap pointer into a unsafe.Pointer is ok. +// +//go:linkname reflect_verifyNotInHeapPtr reflect.verifyNotInHeapPtr +func reflect_verifyNotInHeapPtr(p uintptr) bool { + // Conversion to a pointer is ok as long as findObject above does not call badPointer. + // Since we're already promised that p doesn't point into the heap, just disallow heap + // pointers and the special clobbered pointer. + return spanOf(p) == nil && p != clobberdeadPtr +} + +const ptrBits = 8 * goarch.PtrSize + +// bulkBarrierBitmap executes write barriers for copying from [src, +// src+size) to [dst, dst+size) using a 1-bit pointer bitmap. src is +// assumed to start maskOffset bytes into the data covered by the +// bitmap in bits (which may not be a multiple of 8). +// +// This is used by bulkBarrierPreWrite for writes to data and BSS. +// +//go:nosplit +func bulkBarrierBitmap(dst, src, size, maskOffset uintptr, bits *uint8) { + word := maskOffset / goarch.PtrSize + bits = addb(bits, word/8) + mask := uint8(1) << (word % 8) + + buf := &getg().m.p.ptr().wbBuf + for i := uintptr(0); i < size; i += goarch.PtrSize { + if mask == 0 { + bits = addb(bits, 1) + if *bits == 0 { + // Skip 8 words. + i += 7 * goarch.PtrSize + continue + } + mask = 1 + } + if *bits&mask != 0 { + dstx := (*uintptr)(unsafe.Pointer(dst + i)) + if src == 0 { + p := buf.get1() + p[0] = *dstx + } else { + srcx := (*uintptr)(unsafe.Pointer(src + i)) + p := buf.get2() + p[0] = *dstx + p[1] = *srcx + } + } + mask <<= 1 + } +} + +// typeBitsBulkBarrier executes a write barrier for every +// pointer that would be copied from [src, src+size) to [dst, +// dst+size) by a memmove using the type bitmap to locate those +// pointer slots. +// +// The type typ must correspond exactly to [src, src+size) and [dst, dst+size). +// dst, src, and size must be pointer-aligned. +// The type typ must have a plain bitmap, not a GC program. +// The only use of this function is in channel sends, and the +// 64 kB channel element limit takes care of this for us. +// +// Must not be preempted because it typically runs right before memmove, +// and the GC must observe them as an atomic action. +// +// Callers must perform cgo checks if goexperiment.CgoCheck2. +// +//go:nosplit +func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) { + if typ == nil { + throw("runtime: typeBitsBulkBarrier without type") + } + if typ.Size_ != size { + println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " of size ", typ.Size_, " but memory size", size) + throw("runtime: invalid typeBitsBulkBarrier") + } + if typ.Kind_&abi.KindGCProg != 0 { + println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " with GC prog") + throw("runtime: invalid typeBitsBulkBarrier") + } + if !writeBarrier.enabled { + return + } + ptrmask := typ.GCData + buf := &getg().m.p.ptr().wbBuf + var bits uint32 + for i := uintptr(0); i < typ.PtrBytes; i += goarch.PtrSize { + if i&(goarch.PtrSize*8-1) == 0 { + bits = uint32(*ptrmask) + ptrmask = addb(ptrmask, 1) + } else { + bits = bits >> 1 + } + if bits&1 != 0 { + dstx := (*uintptr)(unsafe.Pointer(dst + i)) + srcx := (*uintptr)(unsafe.Pointer(src + i)) + p := buf.get2() + p[0] = *dstx + p[1] = *srcx + } + } +} + +// countAlloc returns the number of objects allocated in span s by +// scanning the mark bitmap. +func (s *mspan) countAlloc() int { + count := 0 + bytes := divRoundUp(uintptr(s.nelems), 8) + // Iterate over each 8-byte chunk and count allocations + // with an intrinsic. Note that newMarkBits guarantees that + // gcmarkBits will be 8-byte aligned, so we don't have to + // worry about edge cases, irrelevant bits will simply be zero. + for i := uintptr(0); i < bytes; i += 8 { + // Extract 64 bits from the byte pointer and get a OnesCount. + // Note that the unsafe cast here doesn't preserve endianness, + // but that's OK. We only care about how many bits are 1, not + // about the order we discover them in. + mrkBits := *(*uint64)(unsafe.Pointer(s.gcmarkBits.bytep(i))) + count += sys.OnesCount64(mrkBits) + } + return count +} + +// Read the bytes starting at the aligned pointer p into a uintptr. +// Read is little-endian. +func readUintptr(p *byte) uintptr { + x := *(*uintptr)(unsafe.Pointer(p)) + if goarch.BigEndian { + if goarch.PtrSize == 8 { + return uintptr(sys.Bswap64(uint64(x))) + } + return uintptr(sys.Bswap32(uint32(x))) + } + return x +} + +var debugPtrmask struct { + lock mutex + data *byte +} + +// progToPointerMask returns the 1-bit pointer mask output by the GC program prog. +// size the size of the region described by prog, in bytes. +// The resulting bitvector will have no more than size/goarch.PtrSize bits. +func progToPointerMask(prog *byte, size uintptr) bitvector { + n := (size/goarch.PtrSize + 7) / 8 + x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1] + x[len(x)-1] = 0xa1 // overflow check sentinel + n = runGCProg(prog, &x[0]) + if x[len(x)-1] != 0xa1 { + throw("progToPointerMask: overflow") + } + return bitvector{int32(n), &x[0]} +} + +// Packed GC pointer bitmaps, aka GC programs. +// +// For large types containing arrays, the type information has a +// natural repetition that can be encoded to save space in the +// binary and in the memory representation of the type information. +// +// The encoding is a simple Lempel-Ziv style bytecode machine +// with the following instructions: +// +// 00000000: stop +// 0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes +// 10000000 n c: repeat the previous n bits c times; n, c are varints +// 1nnnnnnn c: repeat the previous n bits c times; c is a varint + +// runGCProg returns the number of 1-bit entries written to memory. +func runGCProg(prog, dst *byte) uintptr { + dstStart := dst + + // Bits waiting to be written to memory. + var bits uintptr + var nbits uintptr + + p := prog +Run: + for { + // Flush accumulated full bytes. + // The rest of the loop assumes that nbits <= 7. + for ; nbits >= 8; nbits -= 8 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + + // Process one instruction. + inst := uintptr(*p) + p = add1(p) + n := inst & 0x7F + if inst&0x80 == 0 { + // Literal bits; n == 0 means end of program. + if n == 0 { + // Program is over. + break Run + } + nbyte := n / 8 + for i := uintptr(0); i < nbyte; i++ { + bits |= uintptr(*p) << nbits + p = add1(p) + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + if n %= 8; n > 0 { + bits |= uintptr(*p) << nbits + p = add1(p) + nbits += n + } + continue Run + } + + // Repeat. If n == 0, it is encoded in a varint in the next bytes. + if n == 0 { + for off := uint(0); ; off += 7 { + x := uintptr(*p) + p = add1(p) + n |= (x & 0x7F) << off + if x&0x80 == 0 { + break + } + } + } + + // Count is encoded in a varint in the next bytes. + c := uintptr(0) + for off := uint(0); ; off += 7 { + x := uintptr(*p) + p = add1(p) + c |= (x & 0x7F) << off + if x&0x80 == 0 { + break + } + } + c *= n // now total number of bits to copy + + // If the number of bits being repeated is small, load them + // into a register and use that register for the entire loop + // instead of repeatedly reading from memory. + // Handling fewer than 8 bits here makes the general loop simpler. + // The cutoff is goarch.PtrSize*8 - 7 to guarantee that when we add + // the pattern to a bit buffer holding at most 7 bits (a partial byte) + // it will not overflow. + src := dst + const maxBits = goarch.PtrSize*8 - 7 + if n <= maxBits { + // Start with bits in output buffer. + pattern := bits + npattern := nbits + + // If we need more bits, fetch them from memory. + src = subtract1(src) + for npattern < n { + pattern <<= 8 + pattern |= uintptr(*src) + src = subtract1(src) + npattern += 8 + } + + // We started with the whole bit output buffer, + // and then we loaded bits from whole bytes. + // Either way, we might now have too many instead of too few. + // Discard the extra. + if npattern > n { + pattern >>= npattern - n + npattern = n + } + + // Replicate pattern to at most maxBits. + if npattern == 1 { + // One bit being repeated. + // If the bit is 1, make the pattern all 1s. + // If the bit is 0, the pattern is already all 0s, + // but we can claim that the number of bits + // in the word is equal to the number we need (c), + // because right shift of bits will zero fill. + if pattern == 1 { + pattern = 1<8 bits, there will be full bytes to flush + // on each iteration. + for ; c >= npattern; c -= npattern { + bits |= pattern << nbits + nbits += npattern + for nbits >= 8 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + nbits -= 8 + } + } + + // Add final fragment to bit buffer. + if c > 0 { + pattern &= 1< nbits because n > maxBits and nbits <= 7 + // Leading src fragment. + src = subtractb(src, (off+7)/8) + if frag := off & 7; frag != 0 { + bits |= uintptr(*src) >> (8 - frag) << nbits + src = add1(src) + nbits += frag + c -= frag + } + // Main loop: load one byte, write another. + // The bits are rotating through the bit buffer. + for i := c / 8; i > 0; i-- { + bits |= uintptr(*src) << nbits + src = add1(src) + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + // Final src fragment. + if c %= 8; c > 0 { + bits |= (uintptr(*src) & (1< 0; nbits -= 8 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + return totalBits +} + +// materializeGCProg allocates space for the (1-bit) pointer bitmask +// for an object of size ptrdata. Then it fills that space with the +// pointer bitmask specified by the program prog. +// The bitmask starts at s.startAddr. +// The result must be deallocated with dematerializeGCProg. +func materializeGCProg(ptrdata uintptr, prog *byte) *mspan { + // Each word of ptrdata needs one bit in the bitmap. + bitmapBytes := divRoundUp(ptrdata, 8*goarch.PtrSize) + // Compute the number of pages needed for bitmapBytes. + pages := divRoundUp(bitmapBytes, pageSize) + s := mheap_.allocManual(pages, spanAllocPtrScalarBits) + runGCProg(addb(prog, 4), (*byte)(unsafe.Pointer(s.startAddr))) + return s +} +func dematerializeGCProg(s *mspan) { + mheap_.freeManual(s, spanAllocPtrScalarBits) +} + +func dumpGCProg(p *byte) { + nptr := 0 + for { + x := *p + p = add1(p) + if x == 0 { + print("\t", nptr, " end\n") + break + } + if x&0x80 == 0 { + print("\t", nptr, " lit ", x, ":") + n := int(x+7) / 8 + for i := 0; i < n; i++ { + print(" ", hex(*p)) + p = add1(p) + } + print("\n") + nptr += int(x) + } else { + nbit := int(x &^ 0x80) + if nbit == 0 { + for nb := uint(0); ; nb += 7 { + x := *p + p = add1(p) + nbit |= int(x&0x7f) << nb + if x&0x80 == 0 { + break + } + } + } + count := 0 + for nb := uint(0); ; nb += 7 { + x := *p + p = add1(p) + count |= int(x&0x7f) << nb + if x&0x80 == 0 { + break + } + } + print("\t", nptr, " repeat ", nbit, " × ", count, "\n") + nptr += nbit * count + } + } +} + +// Testing. + +// reflect_gcbits returns the GC type info for x, for testing. +// The result is the bitmap entries (0 or 1), one entry per byte. +// +//go:linkname reflect_gcbits reflect.gcbits +func reflect_gcbits(x any) []byte { + return getgcmask(x) +} + +// Returns GC type info for the pointer stored in ep for testing. +// If ep points to the stack, only static live information will be returned +// (i.e. not for objects which are only dynamically live stack objects). +func getgcmask(ep any) (mask []byte) { + e := *efaceOf(&ep) + p := e.data + t := e._type + + var et *_type + if t.Kind_&abi.KindMask != abi.Pointer { + throw("bad argument to getgcmask: expected type to be a pointer to the value type whose mask is being queried") + } + et = (*ptrtype)(unsafe.Pointer(t)).Elem + + // data or bss + for _, datap := range activeModules() { + // data + if datap.data <= uintptr(p) && uintptr(p) < datap.edata { + bitmap := datap.gcdatamask.bytedata + n := et.Size_ + mask = make([]byte, n/goarch.PtrSize) + for i := uintptr(0); i < n; i += goarch.PtrSize { + off := (uintptr(p) + i - datap.data) / goarch.PtrSize + mask[i/goarch.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 + } + return + } + + // bss + if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss { + bitmap := datap.gcbssmask.bytedata + n := et.Size_ + mask = make([]byte, n/goarch.PtrSize) + for i := uintptr(0); i < n; i += goarch.PtrSize { + off := (uintptr(p) + i - datap.bss) / goarch.PtrSize + mask[i/goarch.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 + } + return + } + } + + // heap + if base, s, _ := findObject(uintptr(p), 0, 0); base != 0 { + if s.spanclass.noscan() { + return nil + } + limit := base + s.elemsize + + // Move the base up to the iterator's start, because + // we want to hide evidence of a malloc header from the + // caller. + tp := s.typePointersOfUnchecked(base) + base = tp.addr + + // Unroll the full bitmap the GC would actually observe. + maskFromHeap := make([]byte, (limit-base)/goarch.PtrSize) + for { + var addr uintptr + if tp, addr = tp.next(limit); addr == 0 { + break + } + maskFromHeap[(addr-base)/goarch.PtrSize] = 1 + } + + // Double-check that every part of the ptr/scalar we're not + // showing the caller is zeroed. This keeps us honest that + // that information is actually irrelevant. + for i := limit; i < s.elemsize; i++ { + if *(*byte)(unsafe.Pointer(i)) != 0 { + throw("found non-zeroed tail of allocation") + } + } + + // Callers (and a check we're about to run) expects this mask + // to end at the last pointer. + for len(maskFromHeap) > 0 && maskFromHeap[len(maskFromHeap)-1] == 0 { + maskFromHeap = maskFromHeap[:len(maskFromHeap)-1] + } + + if et.Kind_&abi.KindGCProg == 0 { + // Unroll again, but this time from the type information. + maskFromType := make([]byte, (limit-base)/goarch.PtrSize) + tp = s.typePointersOfType(et, base) + for { + var addr uintptr + if tp, addr = tp.next(limit); addr == 0 { + break + } + maskFromType[(addr-base)/goarch.PtrSize] = 1 + } + + // Validate that the prefix of maskFromType is equal to + // maskFromHeap. maskFromType may contain more pointers than + // maskFromHeap produces because maskFromHeap may be able to + // get exact type information for certain classes of objects. + // With maskFromType, we're always just tiling the type bitmap + // through to the elemsize. + // + // It's OK if maskFromType has pointers in elemsize that extend + // past the actual populated space; we checked above that all + // that space is zeroed, so just the GC will just see nil pointers. + differs := false + for i := range maskFromHeap { + if maskFromHeap[i] != maskFromType[i] { + differs = true + break + } + } + + if differs { + print("runtime: heap mask=") + for _, b := range maskFromHeap { + print(b) + } + println() + print("runtime: type mask=") + for _, b := range maskFromType { + print(b) + } + println() + print("runtime: type=", toRType(et).string(), "\n") + throw("found two different masks from two different methods") + } + } + + // Select the heap mask to return. We may not have a type mask. + mask = maskFromHeap + + // Make sure we keep ep alive. We may have stopped referencing + // ep's data pointer sometime before this point and it's possible + // for that memory to get freed. + KeepAlive(ep) + return + } + + // stack + if gp := getg(); gp.m.curg.stack.lo <= uintptr(p) && uintptr(p) < gp.m.curg.stack.hi { + found := false + var u unwinder + for u.initAt(gp.m.curg.sched.pc, gp.m.curg.sched.sp, 0, gp.m.curg, 0); u.valid(); u.next() { + if u.frame.sp <= uintptr(p) && uintptr(p) < u.frame.varp { + found = true + break + } + } + if found { + locals, _, _ := u.frame.getStackMap(false) + if locals.n == 0 { + return + } + size := uintptr(locals.n) * goarch.PtrSize + n := (*ptrtype)(unsafe.Pointer(t)).Elem.Size_ + mask = make([]byte, n/goarch.PtrSize) + for i := uintptr(0); i < n; i += goarch.PtrSize { + off := (uintptr(p) + i - u.frame.varp + size) / goarch.PtrSize + mask[i/goarch.PtrSize] = locals.ptrbit(off) + } + } + return + } + + // otherwise, not something the GC knows about. + // possibly read-only data, like malloc(0). + // must not have pointers + return +} diff --git a/contrib/go/_std_1.22/src/runtime/mcache.go b/contrib/go/_std_1.23/src/runtime/mcache.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mcache.go rename to contrib/go/_std_1.23/src/runtime/mcache.go index d4b6eef13ac4..e8da133a6949 100644 --- a/contrib/go/_std_1.22/src/runtime/mcache.go +++ b/contrib/go/_std_1.23/src/runtime/mcache.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/mcentral.go b/contrib/go/_std_1.23/src/runtime/mcentral.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mcentral.go rename to contrib/go/_std_1.23/src/runtime/mcentral.go index e190b56c86b3..bf597e1936da 100644 --- a/contrib/go/_std_1.22/src/runtime/mcentral.go +++ b/contrib/go/_std_1.23/src/runtime/mcentral.go @@ -13,7 +13,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" ) diff --git a/contrib/go/_std_1.22/src/runtime/mcheckmark.go b/contrib/go/_std_1.23/src/runtime/mcheckmark.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/mcheckmark.go rename to contrib/go/_std_1.23/src/runtime/mcheckmark.go index 73c1a10d23bc..258f8892727c 100644 --- a/contrib/go/_std_1.22/src/runtime/mcheckmark.go +++ b/contrib/go/_std_1.23/src/runtime/mcheckmark.go @@ -14,7 +14,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -52,9 +52,7 @@ func startCheckmarks() { arena.checkmarks = bitmap } else { // Otherwise clear the existing bitmap. - for i := range bitmap.b { - bitmap.b[i] = 0 - } + clear(bitmap.b[:]) } } // Enable checkmarking. diff --git a/contrib/go/_std_1.22/src/runtime/mem.go b/contrib/go/_std_1.23/src/runtime/mem.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem.go rename to contrib/go/_std_1.23/src/runtime/mem.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_aix.go b/contrib/go/_std_1.23/src/runtime/mem_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_aix.go rename to contrib/go/_std_1.23/src/runtime/mem_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_bsd.go b/contrib/go/_std_1.23/src/runtime/mem_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_bsd.go rename to contrib/go/_std_1.23/src/runtime/mem_bsd.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_darwin.go b/contrib/go/_std_1.23/src/runtime/mem_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_darwin.go rename to contrib/go/_std_1.23/src/runtime/mem_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_js.go b/contrib/go/_std_1.23/src/runtime/mem_js.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_js.go rename to contrib/go/_std_1.23/src/runtime/mem_js.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_linux.go b/contrib/go/_std_1.23/src/runtime/mem_linux.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/mem_linux.go rename to contrib/go/_std_1.23/src/runtime/mem_linux.go index d63c38c209d8..9aaa57ac9e71 100644 --- a/contrib/go/_std_1.22/src/runtime/mem_linux.go +++ b/contrib/go/_std_1.23/src/runtime/mem_linux.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -150,7 +150,8 @@ func sysFreeOS(v unsafe.Pointer, n uintptr) { } func sysFaultOS(v unsafe.Pointer, n uintptr) { - mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE|_MAP_FIXED, -1, 0) + mprotect(v, n, _PROT_NONE) + madvise(v, n, _MADV_DONTNEED) } func sysReserveOS(v unsafe.Pointer, n uintptr) unsafe.Pointer { diff --git a/contrib/go/_std_1.22/src/runtime/mem_plan9.go b/contrib/go/_std_1.23/src/runtime/mem_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_plan9.go rename to contrib/go/_std_1.23/src/runtime/mem_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_sbrk.go b/contrib/go/_std_1.23/src/runtime/mem_sbrk.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_sbrk.go rename to contrib/go/_std_1.23/src/runtime/mem_sbrk.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_wasip1.go b/contrib/go/_std_1.23/src/runtime/mem_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_wasip1.go rename to contrib/go/_std_1.23/src/runtime/mem_wasip1.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_wasm.go b/contrib/go/_std_1.23/src/runtime/mem_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_wasm.go rename to contrib/go/_std_1.23/src/runtime/mem_wasm.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_windows.go b/contrib/go/_std_1.23/src/runtime/mem_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_windows.go rename to contrib/go/_std_1.23/src/runtime/mem_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/memclr_386.s b/contrib/go/_std_1.23/src/runtime/memclr_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_386.s rename to contrib/go/_std_1.23/src/runtime/memclr_386.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_amd64.s b/contrib/go/_std_1.23/src/runtime/memclr_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_amd64.s rename to contrib/go/_std_1.23/src/runtime/memclr_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_arm.s b/contrib/go/_std_1.23/src/runtime/memclr_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_arm.s rename to contrib/go/_std_1.23/src/runtime/memclr_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_arm64.s b/contrib/go/_std_1.23/src/runtime/memclr_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_arm64.s rename to contrib/go/_std_1.23/src/runtime/memclr_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_loong64.s b/contrib/go/_std_1.23/src/runtime/memclr_loong64.s similarity index 90% rename from contrib/go/_std_1.22/src/runtime/memclr_loong64.s rename to contrib/go/_std_1.23/src/runtime/memclr_loong64.s index 313e4d4f3379..1d45e82d498d 100644 --- a/contrib/go/_std_1.22/src/runtime/memclr_loong64.s +++ b/contrib/go/_std_1.23/src/runtime/memclr_loong64.s @@ -7,10 +7,6 @@ // func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-16 -#ifndef GOEXPERIMENT_regabiargs - MOVV ptr+0(FP), R4 - MOVV n+8(FP), R5 -#endif ADDV R4, R5, R6 // if less than 8 bytes, do one byte at a time diff --git a/contrib/go/_std_1.22/src/runtime/memclr_mips64x.s b/contrib/go/_std_1.23/src/runtime/memclr_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_mips64x.s rename to contrib/go/_std_1.23/src/runtime/memclr_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_mipsx.s b/contrib/go/_std_1.23/src/runtime/memclr_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_mipsx.s rename to contrib/go/_std_1.23/src/runtime/memclr_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_plan9_386.s b/contrib/go/_std_1.23/src/runtime/memclr_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_plan9_386.s rename to contrib/go/_std_1.23/src/runtime/memclr_plan9_386.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_plan9_amd64.s b/contrib/go/_std_1.23/src/runtime/memclr_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_plan9_amd64.s rename to contrib/go/_std_1.23/src/runtime/memclr_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_ppc64x.s b/contrib/go/_std_1.23/src/runtime/memclr_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/memclr_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_riscv64.s b/contrib/go/_std_1.23/src/runtime/memclr_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_riscv64.s rename to contrib/go/_std_1.23/src/runtime/memclr_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_s390x.s b/contrib/go/_std_1.23/src/runtime/memclr_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_s390x.s rename to contrib/go/_std_1.23/src/runtime/memclr_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_wasm.s b/contrib/go/_std_1.23/src/runtime/memclr_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_wasm.s rename to contrib/go/_std_1.23/src/runtime/memclr_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_386.s b/contrib/go/_std_1.23/src/runtime/memmove_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_386.s rename to contrib/go/_std_1.23/src/runtime/memmove_386.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_amd64.s b/contrib/go/_std_1.23/src/runtime/memmove_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_amd64.s rename to contrib/go/_std_1.23/src/runtime/memmove_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_arm.s b/contrib/go/_std_1.23/src/runtime/memmove_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_arm.s rename to contrib/go/_std_1.23/src/runtime/memmove_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_arm64.s b/contrib/go/_std_1.23/src/runtime/memmove_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_arm64.s rename to contrib/go/_std_1.23/src/runtime/memmove_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_loong64.s b/contrib/go/_std_1.23/src/runtime/memmove_loong64.s similarity index 94% rename from contrib/go/_std_1.22/src/runtime/memmove_loong64.s rename to contrib/go/_std_1.23/src/runtime/memmove_loong64.s index 5b7aeba698c3..a94cf999bc4a 100644 --- a/contrib/go/_std_1.22/src/runtime/memmove_loong64.s +++ b/contrib/go/_std_1.23/src/runtime/memmove_loong64.s @@ -8,11 +8,6 @@ // func memmove(to, from unsafe.Pointer, n uintptr) TEXT runtime·memmove(SB), NOSPLIT|NOFRAME, $0-24 -#ifndef GOEXPERIMENT_regabiargs - MOVV to+0(FP), R4 - MOVV from+8(FP), R5 - MOVV n+16(FP), R6 -#endif BNE R6, check RET diff --git a/contrib/go/_std_1.22/src/runtime/memmove_mips64x.s b/contrib/go/_std_1.23/src/runtime/memmove_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_mips64x.s rename to contrib/go/_std_1.23/src/runtime/memmove_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_mipsx.s b/contrib/go/_std_1.23/src/runtime/memmove_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_mipsx.s rename to contrib/go/_std_1.23/src/runtime/memmove_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_plan9_386.s b/contrib/go/_std_1.23/src/runtime/memmove_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_plan9_386.s rename to contrib/go/_std_1.23/src/runtime/memmove_plan9_386.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_plan9_amd64.s b/contrib/go/_std_1.23/src/runtime/memmove_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_plan9_amd64.s rename to contrib/go/_std_1.23/src/runtime/memmove_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_ppc64x.s b/contrib/go/_std_1.23/src/runtime/memmove_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/memmove_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_riscv64.s b/contrib/go/_std_1.23/src/runtime/memmove_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_riscv64.s rename to contrib/go/_std_1.23/src/runtime/memmove_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_s390x.s b/contrib/go/_std_1.23/src/runtime/memmove_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_s390x.s rename to contrib/go/_std_1.23/src/runtime/memmove_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_wasm.s b/contrib/go/_std_1.23/src/runtime/memmove_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_wasm.s rename to contrib/go/_std_1.23/src/runtime/memmove_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/metrics.go b/contrib/go/_std_1.23/src/runtime/metrics.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/metrics.go rename to contrib/go/_std_1.23/src/runtime/metrics.go index f97a3804ab32..417f1071bb70 100644 --- a/contrib/go/_std_1.22/src/runtime/metrics.go +++ b/contrib/go/_std_1.23/src/runtime/metrics.go @@ -95,77 +95,77 @@ func initMetrics() { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcAssistTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCAssistTime)) }, }, "/cpu/classes/gc/mark/dedicated:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcDedicatedTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCDedicatedTime)) }, }, "/cpu/classes/gc/mark/idle:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcIdleTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCIdleTime)) }, }, "/cpu/classes/gc/pause:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcPauseTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCPauseTime)) }, }, "/cpu/classes/gc/total:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcTotalTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCTotalTime)) }, }, "/cpu/classes/idle:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.idleTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.IdleTime)) }, }, "/cpu/classes/scavenge/assist:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.scavengeAssistTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.ScavengeAssistTime)) }, }, "/cpu/classes/scavenge/background:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.scavengeBgTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.ScavengeBgTime)) }, }, "/cpu/classes/scavenge/total:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.scavengeTotalTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.ScavengeTotalTime)) }, }, "/cpu/classes/total:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.totalTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.TotalTime)) }, }, "/cpu/classes/user:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.userTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.UserTime)) }, }, "/gc/cycles/automatic:gc-cycles": { diff --git a/contrib/go/_std_1.22/src/runtime/metrics/description.go b/contrib/go/_std_1.23/src/runtime/metrics/description.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/description.go rename to contrib/go/_std_1.23/src/runtime/metrics/description.go diff --git a/contrib/go/_std_1.23/src/runtime/metrics/doc.go b/contrib/go/_std_1.23/src/runtime/metrics/doc.go new file mode 100644 index 000000000000..da3d956d480b --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/metrics/doc.go @@ -0,0 +1,492 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Note: run 'go generate' (which will run 'go test -generate') to update the "Supported metrics" list. +//go:generate go test -run=Docs -generate + +/* +Package metrics provides a stable interface to access implementation-defined +metrics exported by the Go runtime. This package is similar to existing functions +like [runtime.ReadMemStats] and [runtime/debug.ReadGCStats], but significantly more general. + +The set of metrics defined by this package may evolve as the runtime itself +evolves, and also enables variation across Go implementations, whose relevant +metric sets may not intersect. + +# Interface + +Metrics are designated by a string key, rather than, for example, a field name in +a struct. The full list of supported metrics is always available in the slice of +Descriptions returned by [All]. Each [Description] also includes useful information +about the metric. + +Thus, users of this API are encouraged to sample supported metrics defined by the +slice returned by All to remain compatible across Go versions. Of course, situations +arise where reading specific metrics is critical. For these cases, users are +encouraged to use build tags, and although metrics may be deprecated and removed, +users should consider this to be an exceptional and rare event, coinciding with a +very large change in a particular Go implementation. + +Each metric key also has a "kind" (see [ValueKind]) that describes the format of the +metric's value. +In the interest of not breaking users of this package, the "kind" for a given metric +is guaranteed not to change. If it must change, then a new metric will be introduced +with a new key and a new "kind." + +# Metric key format + +As mentioned earlier, metric keys are strings. Their format is simple and well-defined, +designed to be both human and machine readable. It is split into two components, +separated by a colon: a rooted path and a unit. The choice to include the unit in +the key is motivated by compatibility: if a metric's unit changes, its semantics likely +did also, and a new key should be introduced. + +For more details on the precise definition of the metric key's path and unit formats, see +the documentation of the Name field of the Description struct. + +# A note about floats + +This package supports metrics whose values have a floating-point representation. In +order to improve ease-of-use, this package promises to never produce the following +classes of floating-point values: NaN, infinity. + +# Supported metrics + +Below is the full list of supported metrics, ordered lexicographically. + + /cgo/go-to-c-calls:calls + Count of calls made from Go to C by the current process. + + /cpu/classes/gc/mark/assist:cpu-seconds + Estimated total CPU time goroutines spent performing GC + tasks to assist the GC and prevent it from falling behind the + application. This metric is an overestimate, and not directly + comparable to system CPU time measurements. Compare only with + other /cpu/classes metrics. + + /cpu/classes/gc/mark/dedicated:cpu-seconds + Estimated total CPU time spent performing GC tasks on processors + (as defined by GOMAXPROCS) dedicated to those tasks. This metric + is an overestimate, and not directly comparable to system CPU + time measurements. Compare only with other /cpu/classes metrics. + + /cpu/classes/gc/mark/idle:cpu-seconds + Estimated total CPU time spent performing GC tasks on spare CPU + resources that the Go scheduler could not otherwise find a use + for. This should be subtracted from the total GC CPU time to + obtain a measure of compulsory GC CPU time. This metric is an + overestimate, and not directly comparable to system CPU time + measurements. Compare only with other /cpu/classes metrics. + + /cpu/classes/gc/pause:cpu-seconds + Estimated total CPU time spent with the application paused by + the GC. Even if only one thread is running during the pause, + this is computed as GOMAXPROCS times the pause latency because + nothing else can be executing. This is the exact sum of samples + in /sched/pauses/total/gc:seconds if each sample is multiplied + by GOMAXPROCS at the time it is taken. This metric is an + overestimate, and not directly comparable to system CPU time + measurements. Compare only with other /cpu/classes metrics. + + /cpu/classes/gc/total:cpu-seconds + Estimated total CPU time spent performing GC tasks. This metric + is an overestimate, and not directly comparable to system CPU + time measurements. Compare only with other /cpu/classes metrics. + Sum of all metrics in /cpu/classes/gc. + + /cpu/classes/idle:cpu-seconds + Estimated total available CPU time not spent executing + any Go or Go runtime code. In other words, the part of + /cpu/classes/total:cpu-seconds that was unused. This metric is + an overestimate, and not directly comparable to system CPU time + measurements. Compare only with other /cpu/classes metrics. + + /cpu/classes/scavenge/assist:cpu-seconds + Estimated total CPU time spent returning unused memory to the + underlying platform in response eagerly in response to memory + pressure. This metric is an overestimate, and not directly + comparable to system CPU time measurements. Compare only with + other /cpu/classes metrics. + + /cpu/classes/scavenge/background:cpu-seconds + Estimated total CPU time spent performing background tasks to + return unused memory to the underlying platform. This metric is + an overestimate, and not directly comparable to system CPU time + measurements. Compare only with other /cpu/classes metrics. + + /cpu/classes/scavenge/total:cpu-seconds + Estimated total CPU time spent performing tasks that return + unused memory to the underlying platform. This metric is an + overestimate, and not directly comparable to system CPU time + measurements. Compare only with other /cpu/classes metrics. + Sum of all metrics in /cpu/classes/scavenge. + + /cpu/classes/total:cpu-seconds + Estimated total available CPU time for user Go code or the Go + runtime, as defined by GOMAXPROCS. In other words, GOMAXPROCS + integrated over the wall-clock duration this process has been + executing for. This metric is an overestimate, and not directly + comparable to system CPU time measurements. Compare only with + other /cpu/classes metrics. Sum of all metrics in /cpu/classes. + + /cpu/classes/user:cpu-seconds + Estimated total CPU time spent running user Go code. This may + also include some small amount of time spent in the Go runtime. + This metric is an overestimate, and not directly comparable + to system CPU time measurements. Compare only with other + /cpu/classes metrics. + + /gc/cycles/automatic:gc-cycles + Count of completed GC cycles generated by the Go runtime. + + /gc/cycles/forced:gc-cycles + Count of completed GC cycles forced by the application. + + /gc/cycles/total:gc-cycles + Count of all completed GC cycles. + + /gc/gogc:percent + Heap size target percentage configured by the user, otherwise + 100. This value is set by the GOGC environment variable, and the + runtime/debug.SetGCPercent function. + + /gc/gomemlimit:bytes + Go runtime memory limit configured by the user, otherwise + math.MaxInt64. This value is set by the GOMEMLIMIT environment + variable, and the runtime/debug.SetMemoryLimit function. + + /gc/heap/allocs-by-size:bytes + Distribution of heap allocations by approximate size. + Bucket counts increase monotonically. Note that this does not + include tiny objects as defined by /gc/heap/tiny/allocs:objects, + only tiny blocks. + + /gc/heap/allocs:bytes + Cumulative sum of memory allocated to the heap by the + application. + + /gc/heap/allocs:objects + Cumulative count of heap allocations triggered by the + application. Note that this does not include tiny objects as + defined by /gc/heap/tiny/allocs:objects, only tiny blocks. + + /gc/heap/frees-by-size:bytes + Distribution of freed heap allocations by approximate size. + Bucket counts increase monotonically. Note that this does not + include tiny objects as defined by /gc/heap/tiny/allocs:objects, + only tiny blocks. + + /gc/heap/frees:bytes + Cumulative sum of heap memory freed by the garbage collector. + + /gc/heap/frees:objects + Cumulative count of heap allocations whose storage was freed + by the garbage collector. Note that this does not include tiny + objects as defined by /gc/heap/tiny/allocs:objects, only tiny + blocks. + + /gc/heap/goal:bytes + Heap size target for the end of the GC cycle. + + /gc/heap/live:bytes + Heap memory occupied by live objects that were marked by the + previous GC. + + /gc/heap/objects:objects + Number of objects, live or unswept, occupying heap memory. + + /gc/heap/tiny/allocs:objects + Count of small allocations that are packed together into blocks. + These allocations are counted separately from other allocations + because each individual allocation is not tracked by the + runtime, only their block. Each block is already accounted for + in allocs-by-size and frees-by-size. + + /gc/limiter/last-enabled:gc-cycle + GC cycle the last time the GC CPU limiter was enabled. + This metric is useful for diagnosing the root cause of an + out-of-memory error, because the limiter trades memory for CPU + time when the GC's CPU time gets too high. This is most likely + to occur with use of SetMemoryLimit. The first GC cycle is cycle + 1, so a value of 0 indicates that it was never enabled. + + /gc/pauses:seconds + Deprecated. Prefer the identical /sched/pauses/total/gc:seconds. + + /gc/scan/globals:bytes + The total amount of global variable space that is scannable. + + /gc/scan/heap:bytes + The total amount of heap space that is scannable. + + /gc/scan/stack:bytes + The number of bytes of stack that were scanned last GC cycle. + + /gc/scan/total:bytes + The total amount space that is scannable. Sum of all metrics in + /gc/scan. + + /gc/stack/starting-size:bytes + The stack size of new goroutines. + + /godebug/non-default-behavior/asynctimerchan:events + The number of non-default behaviors executed by the time package + due to a non-default GODEBUG=asynctimerchan=... setting. + + /godebug/non-default-behavior/execerrdot:events + The number of non-default behaviors executed by the os/exec + package due to a non-default GODEBUG=execerrdot=... setting. + + /godebug/non-default-behavior/gocachehash:events + The number of non-default behaviors executed by the cmd/go + package due to a non-default GODEBUG=gocachehash=... setting. + + /godebug/non-default-behavior/gocachetest:events + The number of non-default behaviors executed by the cmd/go + package due to a non-default GODEBUG=gocachetest=... setting. + + /godebug/non-default-behavior/gocacheverify:events + The number of non-default behaviors executed by the cmd/go + package due to a non-default GODEBUG=gocacheverify=... setting. + + /godebug/non-default-behavior/gotypesalias:events + The number of non-default behaviors executed by the go/types + package due to a non-default GODEBUG=gotypesalias=... setting. + + /godebug/non-default-behavior/http2client:events + The number of non-default behaviors executed by the net/http + package due to a non-default GODEBUG=http2client=... setting. + + /godebug/non-default-behavior/http2server:events + The number of non-default behaviors executed by the net/http + package due to a non-default GODEBUG=http2server=... setting. + + /godebug/non-default-behavior/httplaxcontentlength:events + The number of non-default behaviors executed by the net/http + package due to a non-default GODEBUG=httplaxcontentlength=... + setting. + + /godebug/non-default-behavior/httpmuxgo121:events + The number of non-default behaviors executed by the net/http + package due to a non-default GODEBUG=httpmuxgo121=... setting. + + /godebug/non-default-behavior/httpservecontentkeepheaders:events + The number of non-default behaviors executed + by the net/http package due to a non-default + GODEBUG=httpservecontentkeepheaders=... setting. + + /godebug/non-default-behavior/installgoroot:events + The number of non-default behaviors executed by the go/build + package due to a non-default GODEBUG=installgoroot=... setting. + + /godebug/non-default-behavior/multipartmaxheaders:events + The number of non-default behaviors executed by + the mime/multipart package due to a non-default + GODEBUG=multipartmaxheaders=... setting. + + /godebug/non-default-behavior/multipartmaxparts:events + The number of non-default behaviors executed by + the mime/multipart package due to a non-default + GODEBUG=multipartmaxparts=... setting. + + /godebug/non-default-behavior/multipathtcp:events + The number of non-default behaviors executed by the net package + due to a non-default GODEBUG=multipathtcp=... setting. + + /godebug/non-default-behavior/netedns0:events + The number of non-default behaviors executed by the net package + due to a non-default GODEBUG=netedns0=... setting. + + /godebug/non-default-behavior/panicnil:events + The number of non-default behaviors executed by the runtime + package due to a non-default GODEBUG=panicnil=... setting. + + /godebug/non-default-behavior/randautoseed:events + The number of non-default behaviors executed by the math/rand + package due to a non-default GODEBUG=randautoseed=... setting. + + /godebug/non-default-behavior/tarinsecurepath:events + The number of non-default behaviors executed by the archive/tar + package due to a non-default GODEBUG=tarinsecurepath=... + setting. + + /godebug/non-default-behavior/tls10server:events + The number of non-default behaviors executed by the crypto/tls + package due to a non-default GODEBUG=tls10server=... setting. + + /godebug/non-default-behavior/tls3des:events + The number of non-default behaviors executed by the crypto/tls + package due to a non-default GODEBUG=tls3des=... setting. + + /godebug/non-default-behavior/tlsmaxrsasize:events + The number of non-default behaviors executed by the crypto/tls + package due to a non-default GODEBUG=tlsmaxrsasize=... setting. + + /godebug/non-default-behavior/tlsrsakex:events + The number of non-default behaviors executed by the crypto/tls + package due to a non-default GODEBUG=tlsrsakex=... setting. + + /godebug/non-default-behavior/tlsunsafeekm:events + The number of non-default behaviors executed by the crypto/tls + package due to a non-default GODEBUG=tlsunsafeekm=... setting. + + /godebug/non-default-behavior/winreadlinkvolume:events + The number of non-default behaviors executed by the os package + due to a non-default GODEBUG=winreadlinkvolume=... setting. + + /godebug/non-default-behavior/winsymlink:events + The number of non-default behaviors executed by the os package + due to a non-default GODEBUG=winsymlink=... setting. + + /godebug/non-default-behavior/x509keypairleaf:events + The number of non-default behaviors executed by the crypto/tls + package due to a non-default GODEBUG=x509keypairleaf=... + setting. + + /godebug/non-default-behavior/x509negativeserial:events + The number of non-default behaviors executed by the crypto/x509 + package due to a non-default GODEBUG=x509negativeserial=... + setting. + + /godebug/non-default-behavior/x509sha1:events + The number of non-default behaviors executed by the crypto/x509 + package due to a non-default GODEBUG=x509sha1=... setting. + + /godebug/non-default-behavior/x509usefallbackroots:events + The number of non-default behaviors executed by the crypto/x509 + package due to a non-default GODEBUG=x509usefallbackroots=... + setting. + + /godebug/non-default-behavior/x509usepolicies:events + The number of non-default behaviors executed by the crypto/x509 + package due to a non-default GODEBUG=x509usepolicies=... + setting. + + /godebug/non-default-behavior/zipinsecurepath:events + The number of non-default behaviors executed by the archive/zip + package due to a non-default GODEBUG=zipinsecurepath=... + setting. + + /memory/classes/heap/free:bytes + Memory that is completely free and eligible to be returned to + the underlying system, but has not been. This metric is the + runtime's estimate of free address space that is backed by + physical memory. + + /memory/classes/heap/objects:bytes + Memory occupied by live objects and dead objects that have not + yet been marked free by the garbage collector. + + /memory/classes/heap/released:bytes + Memory that is completely free and has been returned to the + underlying system. This metric is the runtime's estimate of free + address space that is still mapped into the process, but is not + backed by physical memory. + + /memory/classes/heap/stacks:bytes + Memory allocated from the heap that is reserved for stack space, + whether or not it is currently in-use. Currently, this + represents all stack memory for goroutines. It also includes all + OS thread stacks in non-cgo programs. Note that stacks may be + allocated differently in the future, and this may change. + + /memory/classes/heap/unused:bytes + Memory that is reserved for heap objects but is not currently + used to hold heap objects. + + /memory/classes/metadata/mcache/free:bytes + Memory that is reserved for runtime mcache structures, but not + in-use. + + /memory/classes/metadata/mcache/inuse:bytes + Memory that is occupied by runtime mcache structures that are + currently being used. + + /memory/classes/metadata/mspan/free:bytes + Memory that is reserved for runtime mspan structures, but not + in-use. + + /memory/classes/metadata/mspan/inuse:bytes + Memory that is occupied by runtime mspan structures that are + currently being used. + + /memory/classes/metadata/other:bytes + Memory that is reserved for or used to hold runtime metadata. + + /memory/classes/os-stacks:bytes + Stack memory allocated by the underlying operating system. + In non-cgo programs this metric is currently zero. This may + change in the future.In cgo programs this metric includes + OS thread stacks allocated directly from the OS. Currently, + this only accounts for one stack in c-shared and c-archive build + modes, and other sources of stacks from the OS are not measured. + This too may change in the future. + + /memory/classes/other:bytes + Memory used by execution trace buffers, structures for debugging + the runtime, finalizer and profiler specials, and more. + + /memory/classes/profiling/buckets:bytes + Memory that is used by the stack trace hash map used for + profiling. + + /memory/classes/total:bytes + All memory mapped by the Go runtime into the current process + as read-write. Note that this does not include memory mapped + by code called via cgo or via the syscall package. Sum of all + metrics in /memory/classes. + + /sched/gomaxprocs:threads + The current runtime.GOMAXPROCS setting, or the number of + operating system threads that can execute user-level Go code + simultaneously. + + /sched/goroutines:goroutines + Count of live goroutines. + + /sched/latencies:seconds + Distribution of the time goroutines have spent in the scheduler + in a runnable state before actually running. Bucket counts + increase monotonically. + + /sched/pauses/stopping/gc:seconds + Distribution of individual GC-related stop-the-world stopping + latencies. This is the time it takes from deciding to stop the + world until all Ps are stopped. This is a subset of the total + GC-related stop-the-world time (/sched/pauses/total/gc:seconds). + During this time, some threads may be executing. Bucket counts + increase monotonically. + + /sched/pauses/stopping/other:seconds + Distribution of individual non-GC-related stop-the-world + stopping latencies. This is the time it takes from deciding + to stop the world until all Ps are stopped. This is a + subset of the total non-GC-related stop-the-world time + (/sched/pauses/total/other:seconds). During this time, some + threads may be executing. Bucket counts increase monotonically. + + /sched/pauses/total/gc:seconds + Distribution of individual GC-related stop-the-world pause + latencies. This is the time from deciding to stop the world + until the world is started again. Some of this time is spent + getting all threads to stop (this is measured directly in + /sched/pauses/stopping/gc:seconds), during which some threads + may still be running. Bucket counts increase monotonically. + + /sched/pauses/total/other:seconds + Distribution of individual non-GC-related stop-the-world + pause latencies. This is the time from deciding to stop the + world until the world is started again. Some of this time + is spent getting all threads to stop (measured directly in + /sched/pauses/stopping/other:seconds). Bucket counts increase + monotonically. + + /sync/mutex/wait/total:seconds + Approximate cumulative time goroutines have spent blocked on a + sync.Mutex, sync.RWMutex, or runtime-internal lock. This metric + is useful for identifying global changes in lock contention. + Collect a mutex or block profile using the runtime/pprof package + for more detailed contention data. +*/ +package metrics diff --git a/contrib/go/_std_1.22/src/runtime/metrics/histogram.go b/contrib/go/_std_1.23/src/runtime/metrics/histogram.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/histogram.go rename to contrib/go/_std_1.23/src/runtime/metrics/histogram.go diff --git a/contrib/go/_std_1.22/src/runtime/metrics/sample.go b/contrib/go/_std_1.23/src/runtime/metrics/sample.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/sample.go rename to contrib/go/_std_1.23/src/runtime/metrics/sample.go diff --git a/contrib/go/_std_1.22/src/runtime/metrics/value.go b/contrib/go/_std_1.23/src/runtime/metrics/value.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/value.go rename to contrib/go/_std_1.23/src/runtime/metrics/value.go diff --git a/contrib/go/_std_1.22/src/runtime/metrics/ya.make b/contrib/go/_std_1.23/src/runtime/metrics/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/ya.make rename to contrib/go/_std_1.23/src/runtime/metrics/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/mfinal.go b/contrib/go/_std_1.23/src/runtime/mfinal.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mfinal.go rename to contrib/go/_std_1.23/src/runtime/mfinal.go index 7d9d547c0f99..78313fb74c6b 100644 --- a/contrib/go/_std_1.22/src/runtime/mfinal.go +++ b/contrib/go/_std_1.23/src/runtime/mfinal.go @@ -9,8 +9,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -235,11 +234,11 @@ func runfinq() { // confusing the write barrier. *(*[2]uintptr)(frame) = [2]uintptr{} } - switch f.fint.Kind_ & kindMask { - case kindPtr: + switch f.fint.Kind_ & abi.KindMask { + case abi.Pointer: // direct use of pointer *(*unsafe.Pointer)(r) = f.arg - case kindInterface: + case abi.Interface: ityp := (*interfacetype)(unsafe.Pointer(f.fint)) // set up with empty interface (*eface)(r)._type = &f.ot.Type @@ -378,9 +377,11 @@ func blockUntilEmptyFinalizerQueue(timeout int64) bool { // In order to use finalizers correctly, the program must ensure that // the object is reachable until it is no longer required. // Objects stored in global variables, or that can be found by tracing -// pointers from a global variable, are reachable. For other objects, -// pass the object to a call of the [KeepAlive] function to mark the -// last point in the function where the object must be reachable. +// pointers from a global variable, are reachable. A function argument or +// receiver may become unreachable at the last point where the function +// mentions it. To make an unreachable object reachable, pass the object +// to a call of the [KeepAlive] function to mark the last point in the +// function where the object must be reachable. // // For example, if p points to a struct, such as os.File, that contains // a file descriptor d, and p has a finalizer that closes that file @@ -418,7 +419,7 @@ func SetFinalizer(obj any, finalizer any) { if etyp == nil { throw("runtime.SetFinalizer: first argument is nil") } - if etyp.Kind_&kindMask != kindPtr { + if etyp.Kind_&abi.KindMask != abi.Pointer { throw("runtime.SetFinalizer: first argument is " + toRType(etyp).string() + ", not pointer") } ot := (*ptrtype)(unsafe.Pointer(etyp)) @@ -442,14 +443,14 @@ func SetFinalizer(obj any, finalizer any) { } // Move base forward if we've got an allocation header. - if goexperiment.AllocHeaders && !span.spanclass.noscan() && !heapBitsInSpan(span.elemsize) && span.spanclass.sizeclass() != 0 { + if !span.spanclass.noscan() && !heapBitsInSpan(span.elemsize) && span.spanclass.sizeclass() != 0 { base += mallocHeaderSize } if uintptr(e.data) != base { // As an implementation detail we allow to set finalizers for an inner byte // of an object if it could come from tiny alloc (see mallocgc for details). - if ot.Elem == nil || ot.Elem.PtrBytes != 0 || ot.Elem.Size_ >= maxTinySize { + if ot.Elem == nil || ot.Elem.Pointers() || ot.Elem.Size_ >= maxTinySize { throw("runtime.SetFinalizer: pointer not at beginning of allocated block") } } @@ -464,7 +465,7 @@ func SetFinalizer(obj any, finalizer any) { return } - if ftyp.Kind_&kindMask != kindFunc { + if ftyp.Kind_&abi.KindMask != abi.Func { throw("runtime.SetFinalizer: second argument is " + toRType(ftyp).string() + ", not a function") } ft := (*functype)(unsafe.Pointer(ftyp)) @@ -479,13 +480,13 @@ func SetFinalizer(obj any, finalizer any) { case fint == etyp: // ok - same type goto okarg - case fint.Kind_&kindMask == kindPtr: + case fint.Kind_&abi.KindMask == abi.Pointer: if (fint.Uncommon() == nil || etyp.Uncommon() == nil) && (*ptrtype)(unsafe.Pointer(fint)).Elem == ot.Elem { // ok - not same type, but both pointers, // one or the other is unnamed, and same element type, so assignable. goto okarg } - case fint.Kind_&kindMask == kindInterface: + case fint.Kind_&abi.KindMask == abi.Interface: ityp := (*interfacetype)(unsafe.Pointer(fint)) if len(ityp.Methods) == 0 { // ok - satisfies empty interface diff --git a/contrib/go/_std_1.22/src/runtime/mfixalloc.go b/contrib/go/_std_1.23/src/runtime/mfixalloc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mfixalloc.go rename to contrib/go/_std_1.23/src/runtime/mfixalloc.go diff --git a/contrib/go/_std_1.22/src/runtime/mgc.go b/contrib/go/_std_1.23/src/runtime/mgc.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/mgc.go rename to contrib/go/_std_1.23/src/runtime/mgc.go index 6c51517522a1..f72edc2afe95 100644 --- a/contrib/go/_std_1.22/src/runtime/mgc.go +++ b/contrib/go/_std_1.23/src/runtime/mgc.go @@ -130,7 +130,7 @@ package runtime import ( "internal/cpu" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -190,6 +190,7 @@ func gcinit() { work.markDoneSema = 1 lockInit(&work.sweepWaiters.lock, lockRankSweepWaiters) lockInit(&work.assistQueue.lock, lockRankAssistQueue) + lockInit(&work.strongFromWeak.lock, lockRankStrongFromWeakQueue) lockInit(&work.wbufSpans.lock, lockRankWbufSpans) } @@ -215,6 +216,17 @@ var gcphase uint32 // If you change it, you must change builtin/runtime.go, too. // If you change the first four bytes, you must also change the write // barrier insertion code. +// +// writeBarrier should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname writeBarrier var writeBarrier struct { enabled bool // compiler emits a check of this before calling write barrier pad [3]byte // compiler uses 32-bit load for "enabled" field @@ -378,8 +390,7 @@ type workType struct { // markDoneSema protects transitions from mark to mark termination. markDoneSema uint32 - bgMarkReady note // signal background mark worker has started - bgMarkDone uint32 // cas to 1 when at a background mark completion point + bgMarkDone uint32 // cas to 1 when at a background mark completion point // Background mark completion signaling // mode is the concurrency mode of the current GC cycle. @@ -408,6 +419,26 @@ type workType struct { list gList } + // strongFromWeak controls how the GC interacts with weak->strong + // pointer conversions. + strongFromWeak struct { + // block is a flag set during mark termination that prevents + // new weak->strong conversions from executing by blocking the + // goroutine and enqueuing it onto q. + // + // Mutated only by one goroutine at a time in gcMarkDone, + // with globally-synchronizing events like forEachP and + // stopTheWorld. + block bool + + // q is a queue of goroutines that attempted to perform a + // weak->strong conversion during mark termination. + // + // Protected by lock. + lock mutex + q gQueue + } + // cycles is the number of completed GC cycles, where a GC // cycle is sweep termination, mark, mark termination, and // sweep. This differs from memstats.numgc, which is @@ -418,7 +449,10 @@ type workType struct { stwprocs, maxprocs int32 tSweepTerm, tMark, tMarkTerm, tEnd int64 // nanotime() of phase start - pauseNS int64 // total STW time this cycle + // pauseNS is the total STW time this cycle, measured as the time between + // when stopping began (just before trying to stop Ps) and just after the + // world started again. + pauseNS int64 // debug.gctrace heap sizes for this cycle. heap0, heap1, heap2 uint64 @@ -680,6 +714,10 @@ func gcStart(trigger gcTrigger) { systemstack(func() { stw = stopTheWorldWithSema(stwGCSweepTerm) }) + + // Accumulate fine-grained stopping time. + work.cpuStats.accumulateGCPauseTime(stw.stoppingCPUTime, 1) + // Finish sweep before we start concurrent scan. systemstack(func() { finishsweep_m() @@ -742,16 +780,19 @@ func gcStart(trigger gcTrigger) { // returns, so make sure we're not preemptible. mp = acquirem() + // Update the CPU stats pause time. + // + // Use maxprocs instead of stwprocs here because the total time + // computed in the CPU stats is based on maxprocs, and we want them + // to be comparable. + work.cpuStats.accumulateGCPauseTime(nanotime()-stw.finishedStopping, work.maxprocs) + // Concurrent mark. systemstack(func() { now = startTheWorldWithSema(0, stw) - work.pauseNS += now - stw.start + work.pauseNS += now - stw.startedStopping work.tMark = now - sweepTermCpu := int64(work.stwprocs) * (work.tMark - work.tSweepTerm) - work.cpuStats.gcPauseTime += sweepTermCpu - work.cpuStats.gcTotalTime += sweepTermCpu - // Release the CPU limiter. gcCPULimiter.finishGCTransition(now) }) @@ -780,6 +821,19 @@ func gcStart(trigger gcTrigger) { // This is protected by markDoneSema. var gcMarkDoneFlushed uint32 +// gcDebugMarkDone contains fields used to debug/test mark termination. +var gcDebugMarkDone struct { + // spinAfterRaggedBarrier forces gcMarkDone to spin after it executes + // the ragged barrier. + spinAfterRaggedBarrier atomic.Bool + + // restartedDueTo27993 indicates that we restarted mark termination + // due to the bug described in issue #27993. + // + // Protected by worldsema. + restartedDueTo27993 bool +} + // gcMarkDone transitions the GC from mark to mark termination if all // reachable objects have been marked (that is, there are no grey // objects and can be no more in the future). Otherwise, it flushes @@ -822,6 +876,10 @@ top: // stop the world later, so acquire worldsema now. semacquire(&worldsema) + // Prevent weak->strong conversions from generating additional + // GC work. forEachP will guarantee that it is observed globally. + work.strongFromWeak.block = true + // Flush all local buffers and collect flushedWork flags. gcMarkDoneFlushed = 0 forEachP(waitReasonGCMarkTermination, func(pp *p) { @@ -852,6 +910,10 @@ top: goto top } + // For debugging/testing. + for gcDebugMarkDone.spinAfterRaggedBarrier.Load() { + } + // There was no global work, no local work, and no Ps // communicated work since we took markDoneSema. Therefore // there are no grey objects and no more objects can be @@ -867,6 +929,9 @@ top: // below. The important thing is that the wb remains active until // all marking is complete. This includes writes made by the GC. + // Accumulate fine-grained stopping time. + work.cpuStats.accumulateGCPauseTime(stw.stoppingCPUTime, 1) + // There is sometimes work left over when we enter mark termination due // to write barriers performed after the completion barrier above. // Detect this and resume concurrent mark. This is obviously @@ -887,10 +952,16 @@ top: } }) if restart { + gcDebugMarkDone.restartedDueTo27993 = true + getg().m.preemptoff = "" systemstack(func() { + // Accumulate the time we were stopped before we had to start again. + work.cpuStats.accumulateGCPauseTime(nanotime()-stw.finishedStopping, work.maxprocs) + + // Start the world again. now := startTheWorldWithSema(0, stw) - work.pauseNS += now - stw.start + work.pauseNS += now - stw.startedStopping }) semrelease(&worldsema) goto top @@ -909,6 +980,11 @@ top: // start the world again. gcWakeAllAssists() + // Wake all blocked weak->strong conversions. These will run + // when we start the world again. + work.strongFromWeak.block = false + gcWakeAllStrongFromWeak() + // Likewise, release the transition lock. Blocked // workers and assists will run when we start the // world again. @@ -943,7 +1019,7 @@ func gcMarkTermination(stw worldStop) { // N.B. The execution tracer is not aware of this status // transition and handles it specially based on the // wait reason. - casGToWaiting(curgp, _Grunning, waitReasonGarbageCollection) + casGToWaitingForGC(curgp, _Grunning, waitReasonGarbageCollection) // Run gc on the g0 stack. We do this so that the g stack // we're currently running on will no longer change. Cuts @@ -1010,7 +1086,7 @@ func gcMarkTermination(stw worldStop) { now := nanotime() sec, nsec, _ := time_now() unixNow := sec*1e9 + int64(nsec) - work.pauseNS += now - stw.start + work.pauseNS += now - stw.startedStopping work.tEnd = now atomic.Store64(&memstats.last_gc_unix, uint64(unixNow)) // must be Unix time to make sense to user atomic.Store64(&memstats.last_gc_nanotime, uint64(now)) // monotonic time for us @@ -1018,18 +1094,20 @@ func gcMarkTermination(stw worldStop) { memstats.pause_end[memstats.numgc%uint32(len(memstats.pause_end))] = uint64(unixNow) memstats.pause_total_ns += uint64(work.pauseNS) - markTermCpu := int64(work.stwprocs) * (work.tEnd - work.tMarkTerm) - work.cpuStats.gcPauseTime += markTermCpu - work.cpuStats.gcTotalTime += markTermCpu - // Accumulate CPU stats. // - // Pass gcMarkPhase=true so we can get all the latest GC CPU stats in there too. + // Use maxprocs instead of stwprocs for GC pause time because the total time + // computed in the CPU stats is based on maxprocs, and we want them to be + // comparable. + // + // Pass gcMarkPhase=true to accumulate so we can get all the latest GC CPU stats + // in there too. + work.cpuStats.accumulateGCPauseTime(now-stw.finishedStopping, work.maxprocs) work.cpuStats.accumulate(now, true) // Compute overall GC CPU utilization. // Omit idle marking time from the overall utilization here since it's "free". - memstats.gc_cpu_fraction = float64(work.cpuStats.gcTotalTime-work.cpuStats.gcIdleTime) / float64(work.cpuStats.totalTime) + memstats.gc_cpu_fraction = float64(work.cpuStats.GCTotalTime-work.cpuStats.GCIdleTime) / float64(work.cpuStats.TotalTime) // Reset assist time and background time stats. // @@ -1167,7 +1245,7 @@ func gcMarkTermination(stw worldStop) { gcController.assistTime.Load(), gcController.dedicatedMarkTime.Load() + gcController.fractionalMarkTime.Load(), gcController.idleMarkTime.Load(), - markTermCpu, + int64(work.stwprocs) * (work.tEnd - work.tMarkTerm), } { if i == 2 || i == 3 { // Separate mark time components with /. @@ -1230,11 +1308,34 @@ func gcBgMarkStartWorkers() { // // Worker Gs don't exit if gomaxprocs is reduced. If it is raised // again, we can reuse the old workers; no need to create new workers. + if gcBgMarkWorkerCount >= gomaxprocs { + return + } + + // Increment mp.locks when allocating. We are called within gcStart, + // and thus must not trigger another gcStart via an allocation. gcStart + // bails when allocating with locks held, so simulate that for these + // allocations. + // + // TODO(prattmic): cleanup gcStart to use a more explicit "in gcStart" + // check for bailing. + mp := acquirem() + ready := make(chan struct{}, 1) + releasem(mp) + for gcBgMarkWorkerCount < gomaxprocs { - go gcBgMarkWorker() + mp := acquirem() // See above, we allocate a closure here. + go gcBgMarkWorker(ready) + releasem(mp) - notetsleepg(&work.bgMarkReady, -1) - noteclear(&work.bgMarkReady) + // N.B. we intentionally wait on each goroutine individually + // rather than starting all in a batch and then waiting once + // afterwards. By running one goroutine at a time, we can take + // advantage of runnext to bounce back and forth between + // workers and this goroutine. In an overloaded application, + // this can reduce GC start latency by prioritizing these + // goroutines rather than waiting on the end of the run queue. + <-ready // The worker is now guaranteed to be added to the pool before // its P's next findRunnableGCWorker. @@ -1273,7 +1374,7 @@ type gcBgMarkWorkerNode struct { m muintptr } -func gcBgMarkWorker() { +func gcBgMarkWorker(ready chan struct{}) { gp := getg() // We pass node to a gopark unlock function, so it can't be on @@ -1286,7 +1387,8 @@ func gcBgMarkWorker() { node.gp.set(gp) node.m.set(acquirem()) - notewakeup(&work.bgMarkReady) + + ready <- struct{}{} // After this point, the background mark worker is generally scheduled // cooperatively by gcController.findRunnableGCWorker. While performing // work on the P, preemption is disabled because we are working on @@ -1299,10 +1401,10 @@ func gcBgMarkWorker() { // fine; it will eventually gopark again for further scheduling via // findRunnableGCWorker. // - // Since we disable preemption before notifying bgMarkReady, we - // guarantee that this G will be in the worker pool for the next - // findRunnableGCWorker. This isn't strictly necessary, but it reduces - // latency between _GCmark starting and the workers starting. + // Since we disable preemption before notifying ready, we guarantee that + // this G will be in the worker pool for the next findRunnableGCWorker. + // This isn't strictly necessary, but it reduces latency between + // _GCmark starting and the workers starting. for { // Go to sleep until woken by @@ -1379,7 +1481,7 @@ func gcBgMarkWorker() { // N.B. The execution tracer is not aware of this status // transition and handles it specially based on the // wait reason. - casGToWaiting(gp, _Grunning, waitReasonGCWorkerActive) + casGToWaitingForGC(gp, _Grunning, waitReasonGCWorkerActive) switch pp.gcMarkWorkerMode { default: throw("gcBgMarkWorker: unexpected gcMarkWorkerMode") @@ -1468,10 +1570,6 @@ func gcMarkWorkAvailable(p *p) bool { // All gcWork caches must be empty. // STW is in effect at this point. func gcMark(startTime int64) { - if debug.allocfreetrace > 0 { - tracegc() - } - if gcphase != _GCmarktermination { throw("in gcMark expecting to see gcphase as _GCmarktermination") } @@ -1642,9 +1740,7 @@ func gcResetMarkState() { unlock(&mheap_.lock) for _, ai := range arenas { ha := mheap_.arenas[ai.l1()][ai.l2()] - for i := range ha.pageMarks { - ha.pageMarks[i] = 0 - } + clear(ha.pageMarks[:]) } work.bytesMarked = 0 @@ -1654,8 +1750,18 @@ func gcResetMarkState() { // Hooks for other packages var poolcleanup func() -var boringCaches []unsafe.Pointer // for crypto/internal/boring - +var boringCaches []unsafe.Pointer // for crypto/internal/boring +var uniqueMapCleanup chan struct{} // for unique + +// sync_runtime_registerPoolCleanup should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname sync_runtime_registerPoolCleanup sync.runtime_registerPoolCleanup func sync_runtime_registerPoolCleanup(f func()) { poolcleanup = f @@ -1666,6 +1772,18 @@ func boring_registerCache(p unsafe.Pointer) { boringCaches = append(boringCaches, p) } +//go:linkname unique_runtime_registerUniqueMapCleanup unique.runtime_registerUniqueMapCleanup +func unique_runtime_registerUniqueMapCleanup(f func()) { + // Start the goroutine in the runtime so it's counted as a system goroutine. + uniqueMapCleanup = make(chan struct{}, 1) + go func(cleanup func()) { + for { + <-uniqueMapCleanup + cleanup() + } + }(f) +} + func clearpools() { // clear sync.Pools if poolcleanup != nil { @@ -1677,6 +1795,14 @@ func clearpools() { atomicstorep(p, nil) } + // clear unique maps + if uniqueMapCleanup != nil { + select { + case uniqueMapCleanup <- struct{}{}: + default: + } + } + // Clear central sudog cache. // Leave per-P caches alone, they have strictly bounded size. // Disconnect cached list before dropping it on the floor, diff --git a/contrib/go/_std_1.22/src/runtime/mgclimit.go b/contrib/go/_std_1.23/src/runtime/mgclimit.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mgclimit.go rename to contrib/go/_std_1.23/src/runtime/mgclimit.go index ef3cc081cec3..ad86fbd65bce 100644 --- a/contrib/go/_std_1.22/src/runtime/mgclimit.go +++ b/contrib/go/_std_1.23/src/runtime/mgclimit.go @@ -4,7 +4,7 @@ package runtime -import "runtime/internal/atomic" +import "internal/runtime/atomic" // gcCPULimiter is a mechanism to limit GC CPU utilization in situations // where it might become excessive and inhibit application progress (e.g. @@ -33,16 +33,6 @@ type gcCPULimiterState struct { lock atomic.Uint32 enabled atomic.Bool - bucket struct { - // Invariants: - // - fill >= 0 - // - capacity >= 0 - // - fill <= capacity - fill, capacity uint64 - } - // overflow is the cumulative amount of GC CPU time that we tried to fill the - // bucket with but exceeded its capacity. - overflow uint64 // gcEnabled is an internal copy of gcBlackenEnabled that determines // whether the limiter tracks total assist time. @@ -55,6 +45,20 @@ type gcCPULimiterState struct { // the mark and sweep phases. transitioning bool + // test indicates whether this instance of the struct was made for testing purposes. + test bool + + bucket struct { + // Invariants: + // - fill >= 0 + // - capacity >= 0 + // - fill <= capacity + fill, capacity uint64 + } + // overflow is the cumulative amount of GC CPU time that we tried to fill the + // bucket with but exceeded its capacity. + overflow uint64 + // assistTimePool is the accumulated assist time since the last update. assistTimePool atomic.Int64 @@ -77,9 +81,6 @@ type gcCPULimiterState struct { // // gomaxprocs isn't used directly so as to keep this structure unit-testable. nprocs int32 - - // test indicates whether this instance of the struct was made for testing purposes. - test bool } // limiting returns true if the CPU limiter is currently enabled, meaning the Go GC diff --git a/contrib/go/_std_1.22/src/runtime/mgcmark.go b/contrib/go/_std_1.23/src/runtime/mgcmark.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mgcmark.go rename to contrib/go/_std_1.23/src/runtime/mgcmark.go index b515568eb003..61e917df4108 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcmark.go +++ b/contrib/go/_std_1.23/src/runtime/mgcmark.go @@ -9,8 +9,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -73,9 +72,7 @@ func gcMarkRootPrepare() { if nDataRoots > work.nDataRoots { work.nDataRoots = nDataRoots } - } - for _, datap := range activeModules() { nBSSRoots := nBlocks(datap.ebss - datap.bss) if nBSSRoots > work.nBSSRoots { work.nBSSRoots = nBSSRoots @@ -220,7 +217,7 @@ func markroot(gcw *gcWork, i uint32, flushBgCredit bool) int64 { userG := getg().m.curg selfScan := gp == userG && readgstatus(userG) == _Grunning if selfScan { - casGToWaiting(userG, _Grunning, waitReasonGarbageCollectionScan) + casGToWaitingForGC(userG, _Grunning, waitReasonGarbageCollectionScan) } // TODO: suspendG blocks (and spins) until gp @@ -331,6 +328,13 @@ func markrootSpans(gcw *gcWork, shard int) { // 2) Finalizer specials (which are not in the garbage // collected heap) are roots. In practice, this means the fn // field must be scanned. + // + // Objects with weak handles have only one invariant related + // to this function: weak handle specials (which are not in the + // garbage collected heap) are roots. In practice, this means + // the handle field must be scanned. Note that the value the + // handle pointer referenced does *not* need to be scanned. See + // the definition of specialWeakHandle for details. sg := mheap_.sweepgen // Find the arena and page index into that arena for this shard. @@ -376,24 +380,28 @@ func markrootSpans(gcw *gcWork, shard int) { // removed from the list while we're traversing it. lock(&s.speciallock) for sp := s.specials; sp != nil; sp = sp.next { - if sp.kind != _KindSpecialFinalizer { - continue - } - // don't mark finalized object, but scan it so we - // retain everything it points to. - spf := (*specialfinalizer)(unsafe.Pointer(sp)) - // A finalizer can be set for an inner byte of an object, find object beginning. - p := s.base() + uintptr(spf.special.offset)/s.elemsize*s.elemsize - - // Mark everything that can be reached from - // the object (but *not* the object itself or - // we'll never collect it). - if !s.spanclass.noscan() { - scanobject(p, gcw) - } + switch sp.kind { + case _KindSpecialFinalizer: + // don't mark finalized object, but scan it so we + // retain everything it points to. + spf := (*specialfinalizer)(unsafe.Pointer(sp)) + // A finalizer can be set for an inner byte of an object, find object beginning. + p := s.base() + uintptr(spf.special.offset)/s.elemsize*s.elemsize + + // Mark everything that can be reached from + // the object (but *not* the object itself or + // we'll never collect it). + if !s.spanclass.noscan() { + scanobject(p, gcw) + } - // The special itself is a root. - scanblock(uintptr(unsafe.Pointer(&spf.fn)), goarch.PtrSize, &oneptrmask[0], gcw, nil) + // The special itself is a root. + scanblock(uintptr(unsafe.Pointer(&spf.fn)), goarch.PtrSize, &oneptrmask[0], gcw, nil) + case _KindSpecialWeakHandle: + // The special itself is a root. + spw := (*specialWeakHandle)(unsafe.Pointer(sp)) + scanblock(uintptr(unsafe.Pointer(&spw.handle)), goarch.PtrSize, &oneptrmask[0], gcw, nil) + } } unlock(&s.speciallock) } @@ -417,15 +425,9 @@ func gcAssistAlloc(gp *g) { // This extremely verbose boolean indicates whether we've // entered mark assist from the perspective of the tracer. // - // In the old tracer, this is just before we call gcAssistAlloc1 - // *and* tracing is enabled. Because the old tracer doesn't - // do any extra tracking, we need to be careful to not emit an - // "end" event if there was no corresponding "begin" for the - // mark assist. - // - // In the new tracer, this is just before we call gcAssistAlloc1 + // In the tracer, this is just before we call gcAssistAlloc1 // *regardless* of whether tracing is enabled. This is because - // the new tracer allows for tracing to begin (and advance + // the tracer allows for tracing to begin (and advance // generations) in the middle of a GC mark phase, so we need to // record some state so that the tracer can pick it up to ensure // a consistent trace result. @@ -521,18 +523,6 @@ retry: if !enteredMarkAssistForTracing { trace := traceAcquire() if trace.ok() { - if !goexperiment.ExecTracer2 { - // In the old tracer, enter mark assist tracing only - // if we actually traced an event. Otherwise a goroutine - // waking up from mark assist post-GC might end up - // writing a stray "end" event. - // - // This means inMarkAssist will not be meaningful - // in the old tracer; that's OK, it's unused. - // - // See the comment on enteredMarkAssistForTracing. - enteredMarkAssistForTracing = true - } trace.GCMarkAssistStart() // Set this *after* we trace the start, otherwise we may // emit an in-progress event for an assist we're about to start. @@ -541,14 +531,12 @@ retry: } else { gp.inMarkAssist = true } - if goexperiment.ExecTracer2 { - // In the new tracer, set enter mark assist tracing if we - // ever pass this point, because we must manage inMarkAssist - // correctly. - // - // See the comment on enteredMarkAssistForTracing. - enteredMarkAssistForTracing = true - } + // In the new tracer, set enter mark assist tracing if we + // ever pass this point, because we must manage inMarkAssist + // correctly. + // + // See the comment on enteredMarkAssistForTracing. + enteredMarkAssistForTracing = true } // Perform assist work @@ -657,7 +645,7 @@ func gcAssistAlloc1(gp *g, scanWork int64) { } // gcDrainN requires the caller to be preemptible. - casGToWaiting(gp, _Grunning, waitReasonGCAssistMarking) + casGToWaitingForGC(gp, _Grunning, waitReasonGCAssistMarking) // drain own cached work first in the hopes that it // will be more cache friendly. @@ -1437,34 +1425,18 @@ func scanobject(b uintptr, gcw *gcWork) { // of the object. n = s.base() + s.elemsize - b n = min(n, maxObletBytes) - if goexperiment.AllocHeaders { - tp = s.typePointersOfUnchecked(s.base()) - tp = tp.fastForward(b-tp.addr, b+n) - } + tp = s.typePointersOfUnchecked(s.base()) + tp = tp.fastForward(b-tp.addr, b+n) } else { - if goexperiment.AllocHeaders { - tp = s.typePointersOfUnchecked(b) - } + tp = s.typePointersOfUnchecked(b) } - var hbits heapBits - if !goexperiment.AllocHeaders { - hbits = heapBitsForAddr(b, n) - } var scanSize uintptr for { var addr uintptr - if goexperiment.AllocHeaders { - if tp, addr = tp.nextFast(); addr == 0 { - if tp, addr = tp.next(b + n); addr == 0 { - break - } - } - } else { - if hbits, addr = hbits.nextFast(); addr == 0 { - if hbits, addr = hbits.next(); addr == 0 { - break - } + if tp, addr = tp.nextFast(); addr == 0 { + if tp, addr = tp.next(b + n); addr == 0 { + break } } diff --git a/contrib/go/_std_1.22/src/runtime/mgcpacer.go b/contrib/go/_std_1.23/src/runtime/mgcpacer.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mgcpacer.go rename to contrib/go/_std_1.23/src/runtime/mgcpacer.go index e9af3d60cdc2..cda87fe94844 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcpacer.go +++ b/contrib/go/_std_1.23/src/runtime/mgcpacer.go @@ -7,7 +7,7 @@ package runtime import ( "internal/cpu" "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" _ "unsafe" // for go:linkname ) diff --git a/contrib/go/_std_1.22/src/runtime/mgcscavenge.go b/contrib/go/_std_1.23/src/runtime/mgcscavenge.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mgcscavenge.go rename to contrib/go/_std_1.23/src/runtime/mgcscavenge.go index 86c2103f1868..4f0bd9c28dc0 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcscavenge.go +++ b/contrib/go/_std_1.23/src/runtime/mgcscavenge.go @@ -92,7 +92,7 @@ package runtime import ( "internal/goos" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -281,15 +281,19 @@ type scavengerState struct { // g is the goroutine the scavenger is bound to. g *g - // parked is whether or not the scavenger is parked. - parked bool - // timer is the timer used for the scavenger to sleep. timer *timer // sysmonWake signals to sysmon that it should wake the scavenger. sysmonWake atomic.Uint32 + // parked is whether or not the scavenger is parked. + parked bool + + // printControllerReset instructs printScavTrace to signal that + // the controller was reset. + printControllerReset bool + // targetCPUFraction is the target CPU overhead for the scavenger. targetCPUFraction float64 @@ -312,10 +316,6 @@ type scavengerState struct { // value. Used if the controller's assumptions fail to hold. controllerCooldown int64 - // printControllerReset instructs printScavTrace to signal that - // the controller was reset. - printControllerReset bool - // sleepStub is a stub used for testing to avoid actually having // the scavenger sleep. // @@ -361,10 +361,10 @@ func (s *scavengerState) init() { s.g = getg() s.timer = new(timer) - s.timer.arg = s - s.timer.f = func(s any, _ uintptr) { + f := func(s any, _ uintptr, _ int64) { s.(*scavengerState).wake() } + s.timer.init(f, s) // input: fraction of CPU time actually used. // setpoint: ideal CPU fraction. @@ -497,7 +497,7 @@ func (s *scavengerState) sleep(worked float64) { // because we can't close over any variables without // failing escape analysis. start := nanotime() - resetTimer(s.timer, start+sleepTime) + s.timer.reset(start+sleepTime, 0) // Mark ourselves as asleep and go to sleep. s.parked = true @@ -512,7 +512,7 @@ func (s *scavengerState) sleep(worked float64) { // reason we might fail is that we've already woken up, but the timer // might be in the process of firing on some other P; essentially we're // racing with it. That's totally OK. Double wake-ups are perfectly safe. - stopTimer(s.timer) + s.timer.stop() unlock(&s.lock) } else { unlock(&s.lock) @@ -773,8 +773,6 @@ func (p *pageAlloc) scavengeOne(ci chunkIdx, searchIdx uint, max uintptr) uintpt unlock(p.mheapLock) if !p.test { - pageTraceScav(getg().m.p.ptr(), 0, addr, uintptr(npages)) - // Only perform sys* operations if we're not in a test. // It's dangerous to do so otherwise. sysUnused(unsafe.Pointer(addr), uintptr(npages)*pageSize) diff --git a/contrib/go/_std_1.22/src/runtime/mgcstack.go b/contrib/go/_std_1.23/src/runtime/mgcstack.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mgcstack.go rename to contrib/go/_std_1.23/src/runtime/mgcstack.go diff --git a/contrib/go/_std_1.22/src/runtime/mgcsweep.go b/contrib/go/_std_1.23/src/runtime/mgcsweep.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mgcsweep.go rename to contrib/go/_std_1.23/src/runtime/mgcsweep.go index 35be7949472f..f53330a5b976 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcsweep.go +++ b/contrib/go/_std_1.23/src/runtime/mgcsweep.go @@ -26,8 +26,7 @@ package runtime import ( "internal/abi" - "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -553,31 +552,44 @@ func (sl *sweepLocked) sweep(preserve bool) bool { mbits := s.markBitsForIndex(objIndex) if !mbits.isMarked() { // This object is not marked and has at least one special record. - // Pass 1: see if it has at least one finalizer. - hasFin := false + // Pass 1: see if it has a finalizer. + hasFinAndRevived := false endOffset := p - s.base() + size for tmp := siter.s; tmp != nil && uintptr(tmp.offset) < endOffset; tmp = tmp.next { if tmp.kind == _KindSpecialFinalizer { // Stop freeing of object if it has a finalizer. mbits.setMarkedNonAtomic() - hasFin = true + hasFinAndRevived = true break } } - // Pass 2: queue all finalizers _or_ handle profile record. - for siter.valid() && uintptr(siter.s.offset) < endOffset { - // Find the exact byte for which the special was setup - // (as opposed to object beginning). - special := siter.s - p := s.base() + uintptr(special.offset) - if special.kind == _KindSpecialFinalizer || !hasFin { + if hasFinAndRevived { + // Pass 2: queue all finalizers and clear any weak handles. Weak handles are cleared + // before finalization as specified by the internal/weak package. See the documentation + // for that package for more details. + for siter.valid() && uintptr(siter.s.offset) < endOffset { + // Find the exact byte for which the special was setup + // (as opposed to object beginning). + special := siter.s + p := s.base() + uintptr(special.offset) + if special.kind == _KindSpecialFinalizer || special.kind == _KindSpecialWeakHandle { + siter.unlinkAndNext() + freeSpecial(special, unsafe.Pointer(p), size) + } else { + // All other specials only apply when an object is freed, + // so just keep the special record. + siter.next() + } + } + } else { + // Pass 2: the object is truly dead, free (and handle) all specials. + for siter.valid() && uintptr(siter.s.offset) < endOffset { + // Find the exact byte for which the special was setup + // (as opposed to object beginning). + special := siter.s + p := s.base() + uintptr(special.offset) siter.unlinkAndNext() freeSpecial(special, unsafe.Pointer(p), size) - } else { - // The object has finalizers, so we're keeping it alive. - // All other specials only apply when an object is freed, - // so just keep the special record. - siter.next() } } } else { @@ -596,16 +608,19 @@ func (sl *sweepLocked) sweep(preserve bool) bool { spanHasNoSpecials(s) } - if debug.allocfreetrace != 0 || debug.clobberfree != 0 || raceenabled || msanenabled || asanenabled { - // Find all newly freed objects. This doesn't have to - // efficient; allocfreetrace has massive overhead. + if traceAllocFreeEnabled() || debug.clobberfree != 0 || raceenabled || msanenabled || asanenabled { + // Find all newly freed objects. mbits := s.markBitsForBase() abits := s.allocBitsForIndex(0) for i := uintptr(0); i < uintptr(s.nelems); i++ { if !mbits.isMarked() && (abits.index < uintptr(s.freeindex) || abits.isMarked()) { x := s.base() + i*s.elemsize - if debug.allocfreetrace != 0 { - tracefree(unsafe.Pointer(x), size) + if traceAllocFreeEnabled() { + trace := traceAcquire() + if trace.ok() { + trace.HeapObjectFree(x) + traceRelease(trace) + } } if debug.clobberfree != 0 { clobberfree(unsafe.Pointer(x), size) @@ -803,8 +818,8 @@ func (sl *sweepLocked) sweep(preserve bool) bool { } else { mheap_.freeSpan(s) } - if goexperiment.AllocHeaders && s.largeType != nil && s.largeType.TFlag&abi.TFlagUnrolledBitmap != 0 { - // In the allocheaders experiment, the unrolled GCProg bitmap is allocated separately. + if s.largeType != nil && s.largeType.TFlag&abi.TFlagUnrolledBitmap != 0 { + // The unrolled GCProg bitmap is allocated separately. // Free the space for the unrolled bitmap. systemstack(func() { s := spanOf(uintptr(unsafe.Pointer(s.largeType))) diff --git a/contrib/go/_std_1.22/src/runtime/mgcwork.go b/contrib/go/_std_1.23/src/runtime/mgcwork.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mgcwork.go rename to contrib/go/_std_1.23/src/runtime/mgcwork.go index 7ab89754d42a..b91a6bd464d7 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcwork.go +++ b/contrib/go/_std_1.23/src/runtime/mgcwork.go @@ -6,7 +6,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/mheap.go b/contrib/go/_std_1.23/src/runtime/mheap.go similarity index 89% rename from contrib/go/_std_1.22/src/runtime/mheap.go rename to contrib/go/_std_1.23/src/runtime/mheap.go index 00693283467b..bfca2d105b74 100644 --- a/contrib/go/_std_1.22/src/runtime/mheap.go +++ b/contrib/go/_std_1.23/src/runtime/mheap.go @@ -11,8 +11,7 @@ package runtime import ( "internal/cpu" "internal/goarch" - "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -208,6 +207,7 @@ type mheap struct { specialprofilealloc fixalloc // allocator for specialprofile* specialReachableAlloc fixalloc // allocator for specialReachable specialPinCounterAlloc fixalloc // allocator for specialPinCounter + specialWeakHandleAlloc fixalloc // allocator for specialWeakHandle speciallock mutex // lock for special record allocators. arenaHintAlloc fixalloc // allocator for arenaHints @@ -240,9 +240,6 @@ var mheap_ mheap type heapArena struct { _ sys.NotInHeap - // heapArenaPtrScalar contains pointer/scalar data about the heap for this heap arena. - heapArenaPtrScalar - // spans maps from virtual address page ID within this arena to *mspan. // For allocated spans, their pages map to the span itself. // For free spans, only the lowest and highest pages map to the span itself. @@ -749,6 +746,7 @@ func (h *mheap) init() { h.specialprofilealloc.init(unsafe.Sizeof(specialprofile{}), nil, nil, &memstats.other_sys) h.specialReachableAlloc.init(unsafe.Sizeof(specialReachable{}), nil, nil, &memstats.other_sys) h.specialPinCounterAlloc.init(unsafe.Sizeof(specialPinCounter{}), nil, nil, &memstats.other_sys) + h.specialWeakHandleAlloc.init(unsafe.Sizeof(specialWeakHandle{}), nil, nil, &memstats.gcMiscSys) h.arenaHintAlloc.init(unsafe.Sizeof(arenaHint{}), nil, nil, &memstats.other_sys) // Don't zero mspan allocations. Background sweeping can @@ -1368,7 +1366,14 @@ HaveSpan: } memstats.heapStats.release() - pageTraceAlloc(pp, now, base, npages) + // Trace the span alloc. + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.SpanAlloc(s) + traceRelease(trace) + } + } return s } @@ -1397,8 +1402,8 @@ func (h *mheap) initSpan(s *mspan, typ spanAllocType, spanclass spanClass, base, s.divMul = 0 } else { s.elemsize = uintptr(class_to_size[sizeclass]) - if goexperiment.AllocHeaders && !s.spanclass.noscan() && heapBitsInSpan(s.elemsize) { - // In the allocheaders experiment, reserve space for the pointer/scan bitmap at the end. + if !s.spanclass.noscan() && heapBitsInSpan(s.elemsize) { + // Reserve space for the pointer/scan bitmap at the end. s.nelems = uint16((nbytes - (nbytes / goarch.PtrSize / 8)) / s.elemsize) } else { s.nelems = uint16(nbytes / s.elemsize) @@ -1549,7 +1554,14 @@ func (h *mheap) grow(npage uintptr) (uintptr, bool) { // Free the span back into the heap. func (h *mheap) freeSpan(s *mspan) { systemstack(func() { - pageTraceFree(getg().m.p.ptr(), 0, s.base(), s.npages) + // Trace the span free. + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.SpanFree(s) + traceRelease(trace) + } + } lock(&h.lock) if msanenabled { @@ -1581,7 +1593,14 @@ func (h *mheap) freeSpan(s *mspan) { // //go:systemstack func (h *mheap) freeManual(s *mspan, typ spanAllocType) { - pageTraceFree(getg().m.p.ptr(), 0, s.base(), s.npages) + // Trace the span free. + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.SpanFree(s) + traceRelease(trace) + } + } s.needzero = 1 lock(&h.lock) @@ -1793,18 +1812,18 @@ func (list *mSpanList) takeAll(other *mSpanList) { } const ( + // _KindSpecialFinalizer is for tracking finalizers. _KindSpecialFinalizer = 1 - _KindSpecialProfile = 2 + // _KindSpecialWeakHandle is used for creating weak pointers. + _KindSpecialWeakHandle = 2 + // _KindSpecialProfile is for memory profiling. + _KindSpecialProfile = 3 // _KindSpecialReachable is a special used for tracking // reachability during testing. - _KindSpecialReachable = 3 + _KindSpecialReachable = 4 // _KindSpecialPinCounter is a special used for objects that are pinned // multiple times - _KindSpecialPinCounter = 4 - // Note: The finalizer special must be first because if we're freeing - // an object, a finalizer special will cause the freeing operation - // to abort, and we want to keep the other special records around - // if that happens. + _KindSpecialPinCounter = 5 ) type special struct { @@ -1989,6 +2008,235 @@ func removefinalizer(p unsafe.Pointer) { unlock(&mheap_.speciallock) } +// The described object has a weak pointer. +// +// Weak pointers in the GC have the following invariants: +// +// - Strong-to-weak conversions must ensure the strong pointer +// remains live until the weak handle is installed. This ensures +// that creating a weak pointer cannot fail. +// +// - Weak-to-strong conversions require the weakly-referenced +// object to be swept before the conversion may proceed. This +// ensures that weak-to-strong conversions cannot resurrect +// dead objects by sweeping them before that happens. +// +// - Weak handles are unique and canonical for each byte offset into +// an object that a strong pointer may point to, until an object +// becomes unreachable. +// +// - Weak handles contain nil as soon as an object becomes unreachable +// the first time, before a finalizer makes it reachable again. New +// weak handles created after resurrection are newly unique. +// +// specialWeakHandle is allocated from non-GC'd memory, so any heap +// pointers must be specially handled. +type specialWeakHandle struct { + _ sys.NotInHeap + special special + // handle is a reference to the actual weak pointer. + // It is always heap-allocated and must be explicitly kept + // live so long as this special exists. + handle *atomic.Uintptr +} + +//go:linkname internal_weak_runtime_registerWeakPointer internal/weak.runtime_registerWeakPointer +func internal_weak_runtime_registerWeakPointer(p unsafe.Pointer) unsafe.Pointer { + return unsafe.Pointer(getOrAddWeakHandle(unsafe.Pointer(p))) +} + +//go:linkname internal_weak_runtime_makeStrongFromWeak internal/weak.runtime_makeStrongFromWeak +func internal_weak_runtime_makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer { + handle := (*atomic.Uintptr)(u) + + // Prevent preemption. We want to make sure that another GC cycle can't start + // and that work.strongFromWeak.block can't change out from under us. + mp := acquirem() + + // Yield to the GC if necessary. + if work.strongFromWeak.block { + releasem(mp) + + // Try to park and wait for mark termination. + // N.B. gcParkStrongFromWeak calls acquirem before returning. + mp = gcParkStrongFromWeak() + } + + p := handle.Load() + if p == 0 { + releasem(mp) + return nil + } + // Be careful. p may or may not refer to valid memory anymore, as it could've been + // swept and released already. It's always safe to ensure a span is swept, though, + // even if it's just some random span. + span := spanOfHeap(p) + if span == nil { + // The span probably got swept and released. + releasem(mp) + return nil + } + // Ensure the span is swept. + span.ensureSwept() + + // Now we can trust whatever we get from handle, so make a strong pointer. + // + // Even if we just swept some random span that doesn't contain this object, because + // this object is long dead and its memory has since been reused, we'll just observe nil. + ptr := unsafe.Pointer(handle.Load()) + + // This is responsible for maintaining the same GC-related + // invariants as the Yuasa part of the write barrier. During + // the mark phase, it's possible that we just created the only + // valid pointer to the object pointed to by ptr. If it's only + // ever referenced from our stack, and our stack is blackened + // already, we could fail to mark it. So, mark it now. + if gcphase != _GCoff { + shade(uintptr(ptr)) + } + releasem(mp) + + // Explicitly keep ptr alive. This seems unnecessary since we return ptr, + // but let's be explicit since it's important we keep ptr alive across the + // call to shade. + KeepAlive(ptr) + return ptr +} + +// gcParkStrongFromWeak puts the current goroutine on the weak->strong queue and parks. +func gcParkStrongFromWeak() *m { + // Prevent preemption as we check strongFromWeak, so it can't change out from under us. + mp := acquirem() + + for work.strongFromWeak.block { + lock(&work.strongFromWeak.lock) + releasem(mp) // N.B. Holding the lock prevents preemption. + + // Queue ourselves up. + work.strongFromWeak.q.pushBack(getg()) + + // Park. + goparkunlock(&work.strongFromWeak.lock, waitReasonGCWeakToStrongWait, traceBlockGCWeakToStrongWait, 2) + + // Re-acquire the current M since we're going to check the condition again. + mp = acquirem() + + // Re-check condition. We may have awoken in the next GC's mark termination phase. + } + return mp +} + +// gcWakeAllStrongFromWeak wakes all currently blocked weak->strong +// conversions. This is used at the end of a GC cycle. +// +// work.strongFromWeak.block must be false to prevent woken goroutines +// from immediately going back to sleep. +func gcWakeAllStrongFromWeak() { + lock(&work.strongFromWeak.lock) + list := work.strongFromWeak.q.popList() + injectglist(&list) + unlock(&work.strongFromWeak.lock) +} + +// Retrieves or creates a weak pointer handle for the object p. +func getOrAddWeakHandle(p unsafe.Pointer) *atomic.Uintptr { + // First try to retrieve without allocating. + if handle := getWeakHandle(p); handle != nil { + // Keep p alive for the duration of the function to ensure + // that it cannot die while we're trying to do this. + KeepAlive(p) + return handle + } + + lock(&mheap_.speciallock) + s := (*specialWeakHandle)(mheap_.specialWeakHandleAlloc.alloc()) + unlock(&mheap_.speciallock) + + handle := new(atomic.Uintptr) + s.special.kind = _KindSpecialWeakHandle + s.handle = handle + handle.Store(uintptr(p)) + if addspecial(p, &s.special) { + // This is responsible for maintaining the same + // GC-related invariants as markrootSpans in any + // situation where it's possible that markrootSpans + // has already run but mark termination hasn't yet. + if gcphase != _GCoff { + mp := acquirem() + gcw := &mp.p.ptr().gcw + // Mark the weak handle itself, since the + // special isn't part of the GC'd heap. + scanblock(uintptr(unsafe.Pointer(&s.handle)), goarch.PtrSize, &oneptrmask[0], gcw, nil) + releasem(mp) + } + + // Keep p alive for the duration of the function to ensure + // that it cannot die while we're trying to do this. + // + // Same for handle, which is only stored in the special. + // There's a window where it might die if we don't keep it + // alive explicitly. Returning it here is probably good enough, + // but let's be defensive and explicit. See #70455. + KeepAlive(p) + KeepAlive(handle) + return handle + } + + // There was an existing handle. Free the special + // and try again. We must succeed because we're explicitly + // keeping p live until the end of this function. Either + // we, or someone else, must have succeeded, because we can + // only fail in the event of a race, and p will still be + // be valid no matter how much time we spend here. + lock(&mheap_.speciallock) + mheap_.specialWeakHandleAlloc.free(unsafe.Pointer(s)) + unlock(&mheap_.speciallock) + + handle = getWeakHandle(p) + if handle == nil { + throw("failed to get or create weak handle") + } + + // Keep p alive for the duration of the function to ensure + // that it cannot die while we're trying to do this. + // + // Same for handle, just to be defensive. + KeepAlive(p) + KeepAlive(handle) + return handle +} + +func getWeakHandle(p unsafe.Pointer) *atomic.Uintptr { + span := spanOfHeap(uintptr(p)) + if span == nil { + throw("getWeakHandle on invalid pointer") + } + + // Ensure that the span is swept. + // Sweeping accesses the specials list w/o locks, so we have + // to synchronize with it. And it's just much safer. + mp := acquirem() + span.ensureSwept() + + offset := uintptr(p) - span.base() + + lock(&span.speciallock) + + // Find the existing record and return the handle if one exists. + var handle *atomic.Uintptr + iter, exists := span.specialFindSplicePoint(offset, _KindSpecialWeakHandle) + if exists { + handle = ((*specialWeakHandle)(unsafe.Pointer(*iter))).handle + } + unlock(&span.speciallock) + releasem(mp) + + // Keep p alive for the duration of the function to ensure + // that it cannot die while we're trying to do this. + KeepAlive(p) + return handle +} + // The described object is being heap profiled. type specialprofile struct { _ sys.NotInHeap @@ -2060,6 +2308,12 @@ func freeSpecial(s *special, p unsafe.Pointer, size uintptr) { lock(&mheap_.speciallock) mheap_.specialfinalizeralloc.free(unsafe.Pointer(sf)) unlock(&mheap_.speciallock) + case _KindSpecialWeakHandle: + sw := (*specialWeakHandle)(unsafe.Pointer(s)) + sw.handle.Store(0) + lock(&mheap_.speciallock) + mheap_.specialWeakHandleAlloc.free(unsafe.Pointer(s)) + unlock(&mheap_.speciallock) case _KindSpecialProfile: sp := (*specialprofile)(unsafe.Pointer(s)) mProf_Free(sp.b, size) diff --git a/contrib/go/_std_1.22/src/runtime/minmax.go b/contrib/go/_std_1.23/src/runtime/minmax.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/minmax.go rename to contrib/go/_std_1.23/src/runtime/minmax.go diff --git a/contrib/go/_std_1.22/src/runtime/mkduff.go b/contrib/go/_std_1.23/src/runtime/mkduff.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mkduff.go rename to contrib/go/_std_1.23/src/runtime/mkduff.go diff --git a/contrib/go/_std_1.22/src/runtime/mkfastlog2table.go b/contrib/go/_std_1.23/src/runtime/mkfastlog2table.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mkfastlog2table.go rename to contrib/go/_std_1.23/src/runtime/mkfastlog2table.go diff --git a/contrib/go/_std_1.22/src/runtime/mklockrank.go b/contrib/go/_std_1.23/src/runtime/mklockrank.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mklockrank.go rename to contrib/go/_std_1.23/src/runtime/mklockrank.go index c8e34d8f00a0..3391afc65725 100644 --- a/contrib/go/_std_1.22/src/runtime/mklockrank.go +++ b/contrib/go/_std_1.23/src/runtime/mklockrank.go @@ -50,23 +50,24 @@ NONE < defer; NONE < sweepWaiters, assistQueue, + strongFromWeakQueue, sweep; # Test only NONE < testR, testW; +NONE < timerSend; + # Scheduler, timers, netpoll -NONE < - allocmW, - execW, - cpuprof, - pollDesc, - wakeableSleep; +NONE < allocmW, execW, cpuprof, pollCache, pollDesc, wakeableSleep; +scavenge, sweep, testR, wakeableSleep, timerSend < hchan; assistQueue, cpuprof, forcegc, + hchan, pollDesc, # pollDesc can interact with timers, which can lock sched. scavenge, + strongFromWeakQueue, sweep, sweepWaiters, testR, @@ -75,17 +76,17 @@ assistQueue, < SCHED # Below SCHED is the scheduler implementation. < allocmR, - execR -< sched; + execR; +allocmR, execR, hchan < sched; sched < allg, allp; -allp, wakeableSleep < timers; -timers < netpollInit; # Channels -scavenge, sweep, testR, wakeableSleep < hchan; NONE < notifyList; hchan, notifyList < sudog; +hchan, pollDesc, wakeableSleep < timers; +timers, timerSend < timer < netpollInit; + # Semaphores NONE < root; @@ -111,12 +112,13 @@ traceBuf < traceStrings; # Malloc allg, allocmR, + allp, # procresize execR, # May grow stack execW, # May allocate after BeforeFork hchan, notifyList, reflectOffs, - timers, + timer, traceStrings, userArenaState # Above MALLOC are things that can allocate memory. @@ -125,6 +127,7 @@ allg, < fin, spanSetSpine, mspanSpecial, + traceTypeTab, MPROF; # We can acquire gcBitsArenas for pinner bits, and @@ -161,7 +164,9 @@ gscan < hchanLeaf; defer, gscan, mspanSpecial, - sudog + pollCache, + sudog, + timer # Anything that can have write barriers can acquire WB. # Above WB, we can have write barriers. < WB diff --git a/contrib/go/_std_1.22/src/runtime/mkpreempt.go b/contrib/go/_std_1.23/src/runtime/mkpreempt.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mkpreempt.go rename to contrib/go/_std_1.23/src/runtime/mkpreempt.go diff --git a/contrib/go/_std_1.22/src/runtime/mksizeclasses.go b/contrib/go/_std_1.23/src/runtime/mksizeclasses.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mksizeclasses.go rename to contrib/go/_std_1.23/src/runtime/mksizeclasses.go index 26ca49e6eb13..bb06ba1eddc3 100644 --- a/contrib/go/_std_1.22/src/runtime/mksizeclasses.go +++ b/contrib/go/_std_1.23/src/runtime/mksizeclasses.go @@ -75,6 +75,7 @@ func main() { const ( // Constants that we use and will transfer to the runtime. + minHeapAlign = 8 maxSmallSize = 32 << 10 smallSizeDiv = 8 smallSizeMax = 1024 @@ -99,7 +100,7 @@ func makeClasses() []class { classes = append(classes, class{}) // class #0 is a dummy entry - align := 8 + align := minHeapAlign for size := align; size <= maxSmallSize; size += align { if powerOfTwo(size) { // bump alignment once in a while if size >= 2048 { @@ -288,6 +289,7 @@ func maxObjsPerSpan(classes []class) int { func printClasses(w io.Writer, classes []class) { fmt.Fprintln(w, "const (") + fmt.Fprintf(w, "minHeapAlign = %d\n", minHeapAlign) fmt.Fprintf(w, "_MaxSmallSize = %d\n", maxSmallSize) fmt.Fprintf(w, "smallSizeDiv = %d\n", smallSizeDiv) fmt.Fprintf(w, "smallSizeMax = %d\n", smallSizeMax) diff --git a/contrib/go/_std_1.22/src/runtime/mmap.go b/contrib/go/_std_1.23/src/runtime/mmap.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mmap.go rename to contrib/go/_std_1.23/src/runtime/mmap.go diff --git a/contrib/go/_std_1.22/src/runtime/mpagealloc.go b/contrib/go/_std_1.23/src/runtime/mpagealloc.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mpagealloc.go rename to contrib/go/_std_1.23/src/runtime/mpagealloc.go index d533f84180fb..46d3ebacaf8a 100644 --- a/contrib/go/_std_1.22/src/runtime/mpagealloc.go +++ b/contrib/go/_std_1.23/src/runtime/mpagealloc.go @@ -48,7 +48,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -511,10 +511,7 @@ func (p *pageAlloc) update(base, npages uintptr, contig, alloc bool) { // either totally allocated or freed. whole := p.summary[len(p.summary)-1][sc+1 : ec] if alloc { - // Should optimize into a memclr. - for i := range whole { - whole[i] = 0 - } + clear(whole) } else { for i := range whole { whole[i] = freeChunkSum diff --git a/contrib/go/_std_1.22/src/runtime/mpagealloc_32bit.go b/contrib/go/_std_1.23/src/runtime/mpagealloc_32bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mpagealloc_32bit.go rename to contrib/go/_std_1.23/src/runtime/mpagealloc_32bit.go diff --git a/contrib/go/_std_1.22/src/runtime/mpagealloc_64bit.go b/contrib/go/_std_1.23/src/runtime/mpagealloc_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mpagealloc_64bit.go rename to contrib/go/_std_1.23/src/runtime/mpagealloc_64bit.go diff --git a/contrib/go/_std_1.22/src/runtime/mpagecache.go b/contrib/go/_std_1.23/src/runtime/mpagecache.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mpagecache.go rename to contrib/go/_std_1.23/src/runtime/mpagecache.go diff --git a/contrib/go/_std_1.22/src/runtime/mpallocbits.go b/contrib/go/_std_1.23/src/runtime/mpallocbits.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mpallocbits.go rename to contrib/go/_std_1.23/src/runtime/mpallocbits.go index 6b5f15dbd8ed..d8a9d25789d6 100644 --- a/contrib/go/_std_1.22/src/runtime/mpallocbits.go +++ b/contrib/go/_std_1.23/src/runtime/mpallocbits.go @@ -85,18 +85,14 @@ func (b *pageBits) clearRange(i, n uint) { _ = b[j/64] // Clear leading bits. b[i/64] &^= ^uint64(0) << (i % 64) - for k := i/64 + 1; k < j/64; k++ { - b[k] = 0 - } + clear(b[i/64+1 : j/64]) // Clear trailing bits. b[j/64] &^= (uint64(1) << (j%64 + 1)) - 1 } // clearAll frees all the bits of b. func (b *pageBits) clearAll() { - for i := range b { - b[i] = 0 - } + clear(b[:]) } // clearBlock64 clears the 64-bit aligned block of bits containing the i'th bit that @@ -328,7 +324,6 @@ func (b *pallocBits) findLargeN(npages uintptr, searchIdx uint) (uint, uint) { } s := uint(sys.TrailingZeros64(x)) if s+size >= uint(npages) { - size += s return start, newSearchIdx } if s < 64 { diff --git a/contrib/go/_std_1.22/src/runtime/mprof.go b/contrib/go/_std_1.23/src/runtime/mprof.go similarity index 75% rename from contrib/go/_std_1.22/src/runtime/mprof.go rename to contrib/go/_std_1.23/src/runtime/mprof.go index abdd2f3e8c9d..ee3e59a9aa99 100644 --- a/contrib/go/_std_1.22/src/runtime/mprof.go +++ b/contrib/go/_std_1.23/src/runtime/mprof.go @@ -9,7 +9,9 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/goarch" + "internal/profilerecord" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -39,11 +41,20 @@ const ( // size of bucket hash table buckHashSize = 179999 - // maxStack is the max depth of stack to record in bucket. - // Note that it's only used internally as a guard against - // wildly out-of-bounds slicing of the PCs that come after - // a bucket struct, and it could increase in the future. - maxStack = 32 + // maxSkip is to account for deferred inline expansion + // when using frame pointer unwinding. We record the stack + // with "physical" frame pointers but handle skipping "logical" + // frames at some point after collecting the stack. So + // we need extra space in order to avoid getting fewer than the + // desired maximum number of frames after expansion. + // This should be at least as large as the largest skip value + // used for profiling; otherwise stacks may be truncated inconsistently + maxSkip = 5 + + // maxProfStackDepth is the highest valid value for debug.profstackdepth. + // It's used for the bucket.stk func. + // TODO(fg): can we get rid of this? + maxProfStackDepth = 1024 ) type bucketType int @@ -231,10 +242,11 @@ func newBucket(typ bucketType, nstk int) *bucket { return b } -// stk returns the slice in b holding the stack. +// stk returns the slice in b holding the stack. The caller can asssume that the +// backing array is immutable. func (b *bucket) stk() []uintptr { - stk := (*[maxStack]uintptr)(add(unsafe.Pointer(b), unsafe.Sizeof(*b))) - if b.nstk > maxStack { + stk := (*[maxProfStackDepth]uintptr)(add(unsafe.Pointer(b), unsafe.Sizeof(*b))) + if b.nstk > maxProfStackDepth { // prove that slicing works; otherwise a failure requires a P throw("bad profile stack count") } @@ -422,15 +434,22 @@ func mProf_PostSweep() { } // Called by malloc to record a profiled block. -func mProf_Malloc(p unsafe.Pointer, size uintptr) { - var stk [maxStack]uintptr - nstk := callers(4, stk[:]) - +func mProf_Malloc(mp *m, p unsafe.Pointer, size uintptr) { + if mp.profStack == nil { + // mp.profStack is nil if we happen to sample an allocation during the + // initialization of mp. This case is rare, so we just ignore such + // allocations. Change MemProfileRate to 1 if you need to reproduce such + // cases for testing purposes. + return + } + // Only use the part of mp.profStack we need and ignore the extra space + // reserved for delayed inline expansion with frame pointer unwinding. + nstk := callers(4, mp.profStack[:debug.profstackdepth]) index := (mProfCycle.read() + 2) % uint32(len(memRecord{}.future)) - b := stkbucket(memProfile, size, stk[:nstk], true) - mp := b.mp() - mpc := &mp.future[index] + b := stkbucket(memProfile, size, mp.profStack[:nstk], true) + mr := b.mp() + mpc := &mr.future[index] lock(&profMemFutureLock[index]) mpc.allocs++ @@ -504,17 +523,98 @@ func blocksampled(cycles, rate int64) bool { return true } +// saveblockevent records a profile event of the type specified by which. +// cycles is the quantity associated with this event and rate is the sampling rate, +// used to adjust the cycles value in the manner determined by the profile type. +// skip is the number of frames to omit from the traceback associated with the event. +// The traceback will be recorded from the stack of the goroutine associated with the current m. +// skip should be positive if this event is recorded from the current stack +// (e.g. when this is not called from a system stack) func saveblockevent(cycles, rate int64, skip int, which bucketType) { + if debug.profstackdepth == 0 { + // profstackdepth is set to 0 by the user, so mp.profStack is nil and we + // can't record a stack trace. + return + } + if skip > maxSkip { + print("requested skip=", skip) + throw("invalid skip value") + } gp := getg() + mp := acquirem() // we must not be preempted while accessing profstack + var nstk int - var stk [maxStack]uintptr - if gp.m.curg == nil || gp.m.curg == gp { - nstk = callers(skip, stk[:]) + if tracefpunwindoff() || gp.m.hasCgoOnStack() { + if gp.m.curg == nil || gp.m.curg == gp { + nstk = callers(skip, mp.profStack) + } else { + nstk = gcallers(gp.m.curg, skip, mp.profStack) + } } else { - nstk = gcallers(gp.m.curg, skip, stk[:]) + if gp.m.curg == nil || gp.m.curg == gp { + if skip > 0 { + // We skip one fewer frame than the provided value for frame + // pointer unwinding because the skip value includes the current + // frame, whereas the saved frame pointer will give us the + // caller's return address first (so, not including + // saveblockevent) + skip -= 1 + } + nstk = fpTracebackPartialExpand(skip, unsafe.Pointer(getfp()), mp.profStack) + } else { + mp.profStack[0] = gp.m.curg.sched.pc + nstk = 1 + fpTracebackPartialExpand(skip, unsafe.Pointer(gp.m.curg.sched.bp), mp.profStack[1:]) + } } - saveBlockEventStack(cycles, rate, stk[:nstk], which) + saveBlockEventStack(cycles, rate, mp.profStack[:nstk], which) + releasem(mp) +} + +// fpTracebackPartialExpand records a call stack obtained starting from fp. +// This function will skip the given number of frames, properly accounting for +// inlining, and save remaining frames as "physical" return addresses. The +// consumer should later use CallersFrames or similar to expand inline frames. +func fpTracebackPartialExpand(skip int, fp unsafe.Pointer, pcBuf []uintptr) int { + var n int + lastFuncID := abi.FuncIDNormal + skipOrAdd := func(retPC uintptr) bool { + if skip > 0 { + skip-- + } else if n < len(pcBuf) { + pcBuf[n] = retPC + n++ + } + return n < len(pcBuf) + } + for n < len(pcBuf) && fp != nil { + // return addr sits one word above the frame pointer + pc := *(*uintptr)(unsafe.Pointer(uintptr(fp) + goarch.PtrSize)) + + if skip > 0 { + callPC := pc - 1 + fi := findfunc(callPC) + u, uf := newInlineUnwinder(fi, callPC) + for ; uf.valid(); uf = u.next(uf) { + sf := u.srcFunc(uf) + if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(lastFuncID) { + // ignore wrappers + } else if more := skipOrAdd(uf.pc + 1); !more { + return n + } + lastFuncID = sf.funcID + } + } else { + // We've skipped the desired number of frames, so no need + // to perform further inline expansion now. + pcBuf[n] = pc + n++ + } + + // follow the frame pointer to the next one + fp = unsafe.Pointer(*(*uintptr)(fp)) + } + return n } // lockTimer assists with profiling contention on runtime-internal locks. @@ -613,12 +713,12 @@ func (lt *lockTimer) end() { } type mLockProfile struct { - waitTime atomic.Int64 // total nanoseconds spent waiting in runtime.lockWithRank - stack [maxStack]uintptr // stack that experienced contention in runtime.lockWithRank - pending uintptr // *mutex that experienced contention (to be traceback-ed) - cycles int64 // cycles attributable to "pending" (if set), otherwise to "stack" - cyclesLost int64 // contention for which we weren't able to record a call stack - disabled bool // attribute all time to "lost" + waitTime atomic.Int64 // total nanoseconds spent waiting in runtime.lockWithRank + stack []uintptr // stack that experienced contention in runtime.lockWithRank + pending uintptr // *mutex that experienced contention (to be traceback-ed) + cycles int64 // cycles attributable to "pending" (if set), otherwise to "stack" + cyclesLost int64 // contention for which we weren't able to record a call stack + disabled bool // attribute all time to "lost" } func (prof *mLockProfile) recordLock(cycles int64, l *mutex) { @@ -675,6 +775,12 @@ func (prof *mLockProfile) recordUnlock(l *mutex) { } func (prof *mLockProfile) captureStack() { + if debug.profstackdepth == 0 { + // profstackdepth is set to 0 by the user, so mp.profStack is nil and we + // can't record a stack trace. + return + } + skip := 3 // runtime.(*mLockProfile).recordUnlock runtime.unlock2 runtime.unlockWithRank if staticLockRanking { // When static lock ranking is enabled, we'll always be on the system @@ -690,9 +796,10 @@ func (prof *mLockProfile) captureStack() { } prof.pending = 0 + prof.stack[0] = logicalStackSentinel if debug.runtimeContentionStacks.Load() == 0 { - prof.stack[0] = abi.FuncPCABIInternal(_LostContendedRuntimeLock) + sys.PCQuantum - prof.stack[1] = 0 + prof.stack[1] = abi.FuncPCABIInternal(_LostContendedRuntimeLock) + sys.PCQuantum + prof.stack[2] = 0 return } @@ -703,7 +810,7 @@ func (prof *mLockProfile) captureStack() { systemstack(func() { var u unwinder u.initAt(pc, sp, 0, gp, unwindSilentErrors|unwindJumpStack) - nstk = tracebackPCs(&u, skip, prof.stack[:]) + nstk = 1 + tracebackPCs(&u, skip, prof.stack[1:]) }) if nstk < len(prof.stack) { prof.stack[nstk] = 0 @@ -718,7 +825,7 @@ func (prof *mLockProfile) store() { mp := acquirem() prof.disabled = true - nstk := maxStack + nstk := int(debug.profstackdepth) for i := 0; i < nstk; i++ { if pc := prof.stack[i]; pc == 0 { nstk = i @@ -733,6 +840,7 @@ func (prof *mLockProfile) store() { saveBlockEventStack(cycles, rate, prof.stack[:nstk], mutexProfile) if lost > 0 { lostStk := [...]uintptr{ + logicalStackSentinel, abi.FuncPCABIInternal(_LostContendedRuntimeLock) + sys.PCQuantum, } saveBlockEventStack(lost, rate, lostStk[:], mutexProfile) @@ -829,9 +937,10 @@ func (r *StackRecord) Stack() []uintptr { // at the beginning of main). var MemProfileRate int = 512 * 1024 -// disableMemoryProfiling is set by the linker if runtime.MemProfile +// disableMemoryProfiling is set by the linker if memory profiling // is not used and the link type guarantees nobody else could use it // elsewhere. +// We check if the runtime.memProfileInternal symbol is present. var disableMemoryProfiling bool // A MemProfileRecord describes the live objects allocated @@ -883,6 +992,23 @@ func (r *MemProfileRecord) Stack() []uintptr { // the testing package's -test.memprofile flag instead // of calling MemProfile directly. func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) { + return memProfileInternal(len(p), inuseZero, func(r profilerecord.MemProfileRecord) { + copyMemProfileRecord(&p[0], r) + p = p[1:] + }) +} + +// memProfileInternal returns the number of records n in the profile. If there +// are less than size records, copyFn is invoked for each record, and ok returns +// true. +// +// The linker set disableMemoryProfiling to true to disable memory profiling +// if this function is not reachable. Mark it noinline to ensure the symbol exists. +// (This function is big and normally not inlined anyway.) +// See also disableMemoryProfiling above and cmd/link/internal/ld/lib.go:linksetup. +// +//go:noinline +func memProfileInternal(size int, inuseZero bool, copyFn func(profilerecord.MemProfileRecord)) (n int, ok bool) { cycle := mProfCycle.read() // If we're between mProf_NextCycle and mProf_Flush, take care // of flushing to the active profile so we only have to look @@ -922,14 +1048,19 @@ func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) { } } } - if n <= len(p) { + if n <= size { ok = true - idx := 0 for b := head; b != nil; b = b.allnext { mp := b.mp() if inuseZero || mp.active.alloc_bytes != mp.active.free_bytes { - record(&p[idx], b) - idx++ + r := profilerecord.MemProfileRecord{ + AllocBytes: int64(mp.active.alloc_bytes), + FreeBytes: int64(mp.active.free_bytes), + AllocObjects: int64(mp.active.allocs), + FreeObjects: int64(mp.active.frees), + Stack: b.stk(), + } + copyFn(r) } } } @@ -937,26 +1068,30 @@ func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) { return } -// Write b's data to r. -func record(r *MemProfileRecord, b *bucket) { - mp := b.mp() - r.AllocBytes = int64(mp.active.alloc_bytes) - r.FreeBytes = int64(mp.active.free_bytes) - r.AllocObjects = int64(mp.active.allocs) - r.FreeObjects = int64(mp.active.frees) +func copyMemProfileRecord(dst *MemProfileRecord, src profilerecord.MemProfileRecord) { + dst.AllocBytes = src.AllocBytes + dst.FreeBytes = src.FreeBytes + dst.AllocObjects = src.AllocObjects + dst.FreeObjects = src.FreeObjects if raceenabled { - racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(), abi.FuncPCABIInternal(MemProfile)) + racewriterangepc(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0), getcallerpc(), abi.FuncPCABIInternal(MemProfile)) } if msanenabled { - msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) + msanwrite(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0)) } if asanenabled { - asanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) - } - copy(r.Stack0[:], b.stk()) - for i := int(b.nstk); i < len(r.Stack0); i++ { - r.Stack0[i] = 0 + asanwrite(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0)) } + i := copy(dst.Stack0[:], src.Stack) + clear(dst.Stack0[i:]) +} + +//go:linkname pprof_memProfileInternal +func pprof_memProfileInternal(p []profilerecord.MemProfileRecord, inuseZero bool) (n int, ok bool) { + return memProfileInternal(len(p), inuseZero, func(r profilerecord.MemProfileRecord) { + p[0] = r + p = p[1:] + }) } func iterate_memprof(fn func(*bucket, uintptr, *uintptr, uintptr, uintptr, uintptr)) { @@ -985,43 +1120,98 @@ type BlockProfileRecord struct { // the [testing] package's -test.blockprofile flag instead // of calling BlockProfile directly. func BlockProfile(p []BlockProfileRecord) (n int, ok bool) { + var m int + n, ok = blockProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) { + copyBlockProfileRecord(&p[m], r) + m++ + }) + if ok { + expandFrames(p[:n]) + } + return +} + +func expandFrames(p []BlockProfileRecord) { + expandedStack := makeProfStack() + for i := range p { + cf := CallersFrames(p[i].Stack()) + j := 0 + for j < len(expandedStack) { + f, more := cf.Next() + // f.PC is a "call PC", but later consumers will expect + // "return PCs" + expandedStack[j] = f.PC + 1 + j++ + if !more { + break + } + } + k := copy(p[i].Stack0[:], expandedStack[:j]) + clear(p[i].Stack0[k:]) + } +} + +// blockProfileInternal returns the number of records n in the profile. If there +// are less than size records, copyFn is invoked for each record, and ok returns +// true. +func blockProfileInternal(size int, copyFn func(profilerecord.BlockProfileRecord)) (n int, ok bool) { lock(&profBlockLock) head := (*bucket)(bbuckets.Load()) for b := head; b != nil; b = b.allnext { n++ } - if n <= len(p) { + if n <= size { ok = true for b := head; b != nil; b = b.allnext { bp := b.bp() - r := &p[0] - r.Count = int64(bp.count) + r := profilerecord.BlockProfileRecord{ + Count: int64(bp.count), + Cycles: bp.cycles, + Stack: b.stk(), + } // Prevent callers from having to worry about division by zero errors. // See discussion on http://golang.org/cl/299991. if r.Count == 0 { r.Count = 1 } - r.Cycles = bp.cycles - if raceenabled { - racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(), abi.FuncPCABIInternal(BlockProfile)) - } - if msanenabled { - msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) - } - if asanenabled { - asanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) - } - i := copy(r.Stack0[:], b.stk()) - for ; i < len(r.Stack0); i++ { - r.Stack0[i] = 0 - } - p = p[1:] + copyFn(r) } } unlock(&profBlockLock) return } +// copyBlockProfileRecord copies the sample values and call stack from src to dst. +// The call stack is copied as-is. The caller is responsible for handling inline +// expansion, needed when the call stack was collected with frame pointer unwinding. +func copyBlockProfileRecord(dst *BlockProfileRecord, src profilerecord.BlockProfileRecord) { + dst.Count = src.Count + dst.Cycles = src.Cycles + if raceenabled { + racewriterangepc(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0), getcallerpc(), abi.FuncPCABIInternal(BlockProfile)) + } + if msanenabled { + msanwrite(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0)) + } + if asanenabled { + asanwrite(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0)) + } + // We just copy the stack here without inline expansion + // (needed if frame pointer unwinding is used) + // since this function is called under the profile lock, + // and doing something that might allocate can violate lock ordering. + i := copy(dst.Stack0[:], src.Stack) + clear(dst.Stack0[i:]) +} + +//go:linkname pprof_blockProfileInternal +func pprof_blockProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) { + return blockProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) { + p[0] = r + p = p[1:] + }) +} + // MutexProfile returns n, the number of records in the current mutex profile. // If len(p) >= n, MutexProfile copies the profile into p and returns n, true. // Otherwise, MutexProfile does not change p, and returns n, false. @@ -1029,29 +1219,50 @@ func BlockProfile(p []BlockProfileRecord) (n int, ok bool) { // Most clients should use the [runtime/pprof] package // instead of calling MutexProfile directly. func MutexProfile(p []BlockProfileRecord) (n int, ok bool) { + var m int + n, ok = mutexProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) { + copyBlockProfileRecord(&p[m], r) + m++ + }) + if ok { + expandFrames(p[:n]) + } + return +} + +// mutexProfileInternal returns the number of records n in the profile. If there +// are less than size records, copyFn is invoked for each record, and ok returns +// true. +func mutexProfileInternal(size int, copyFn func(profilerecord.BlockProfileRecord)) (n int, ok bool) { lock(&profBlockLock) head := (*bucket)(xbuckets.Load()) for b := head; b != nil; b = b.allnext { n++ } - if n <= len(p) { + if n <= size { ok = true for b := head; b != nil; b = b.allnext { bp := b.bp() - r := &p[0] - r.Count = int64(bp.count) - r.Cycles = bp.cycles - i := copy(r.Stack0[:], b.stk()) - for ; i < len(r.Stack0); i++ { - r.Stack0[i] = 0 + r := profilerecord.BlockProfileRecord{ + Count: int64(bp.count), + Cycles: bp.cycles, + Stack: b.stk(), } - p = p[1:] + copyFn(r) } } unlock(&profBlockLock) return } +//go:linkname pprof_mutexProfileInternal +func pprof_mutexProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) { + return mutexProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) { + p[0] = r + p = p[1:] + }) +} + // ThreadCreateProfile returns n, the number of records in the thread creation profile. // If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true. // If len(p) < n, ThreadCreateProfile does not change p and returns n, false. @@ -1059,28 +1270,46 @@ func MutexProfile(p []BlockProfileRecord) (n int, ok bool) { // Most clients should use the runtime/pprof package instead // of calling ThreadCreateProfile directly. func ThreadCreateProfile(p []StackRecord) (n int, ok bool) { + return threadCreateProfileInternal(len(p), func(r profilerecord.StackRecord) { + i := copy(p[0].Stack0[:], r.Stack) + clear(p[0].Stack0[i:]) + p = p[1:] + }) +} + +// threadCreateProfileInternal returns the number of records n in the profile. +// If there are less than size records, copyFn is invoked for each record, and +// ok returns true. +func threadCreateProfileInternal(size int, copyFn func(profilerecord.StackRecord)) (n int, ok bool) { first := (*m)(atomic.Loadp(unsafe.Pointer(&allm))) for mp := first; mp != nil; mp = mp.alllink { n++ } - if n <= len(p) { + if n <= size { ok = true - i := 0 for mp := first; mp != nil; mp = mp.alllink { - p[i].Stack0 = mp.createstack - i++ + r := profilerecord.StackRecord{Stack: mp.createstack[:]} + copyFn(r) } } return } -//go:linkname runtime_goroutineProfileWithLabels runtime/pprof.runtime_goroutineProfileWithLabels -func runtime_goroutineProfileWithLabels(p []StackRecord, labels []unsafe.Pointer) (n int, ok bool) { +//go:linkname pprof_threadCreateInternal +func pprof_threadCreateInternal(p []profilerecord.StackRecord) (n int, ok bool) { + return threadCreateProfileInternal(len(p), func(r profilerecord.StackRecord) { + p[0] = r + p = p[1:] + }) +} + +//go:linkname pprof_goroutineProfileWithLabels +func pprof_goroutineProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { return goroutineProfileWithLabels(p, labels) } // labels may be nil. If labels is non-nil, it must have the same length as p. -func goroutineProfileWithLabels(p []StackRecord, labels []unsafe.Pointer) (n int, ok bool) { +func goroutineProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { if labels != nil && len(labels) != len(p) { labels = nil } @@ -1092,7 +1321,7 @@ var goroutineProfile = struct { sema uint32 active bool offset atomic.Int64 - records []StackRecord + records []profilerecord.StackRecord labels []unsafe.Pointer }{ sema: 1, @@ -1131,11 +1360,20 @@ func (p *goroutineProfileStateHolder) CompareAndSwap(old, new goroutineProfileSt return (*atomic.Uint32)(p).CompareAndSwap(uint32(old), uint32(new)) } -func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Pointer) (n int, ok bool) { +func goroutineProfileWithLabelsConcurrent(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { + if len(p) == 0 { + // An empty slice is obviously too small. Return a rough + // allocation estimate without bothering to STW. As long as + // this is close, then we'll only need to STW once (on the next + // call). + return int(gcount()), false + } + semacquire(&goroutineProfile.sema) ourg := getg() + pcbuf := makeProfStack() // see saveg() for explanation stw := stopTheWorld(stwGoroutineProfile) // Using gcount while the world is stopped should give us a consistent view // of the number of live goroutines, minus the number of goroutines that are @@ -1162,7 +1400,7 @@ func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Point sp := getcallersp() pc := getcallerpc() systemstack(func() { - saveg(pc, sp, ourg, &p[0]) + saveg(pc, sp, ourg, &p[0], pcbuf) }) if labels != nil { labels[0] = ourg.labels @@ -1184,7 +1422,7 @@ func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Point if fing != nil { fing.goroutineProfiled.Store(goroutineProfileSatisfied) if readgstatus(fing) != _Gdead && !isSystemGoroutine(fing, false) { - doRecordGoroutineProfile(fing) + doRecordGoroutineProfile(fing, pcbuf) } } startTheWorld(stw) @@ -1201,7 +1439,7 @@ func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Point // call will start by adding itself to the profile (before the act of // executing can cause any changes in its stack). forEachGRace(func(gp1 *g) { - tryRecordGoroutineProfile(gp1, Gosched) + tryRecordGoroutineProfile(gp1, pcbuf, Gosched) }) stw = stopTheWorld(stwGoroutineProfileCleanup) @@ -1245,13 +1483,13 @@ func tryRecordGoroutineProfileWB(gp1 *g) { if getg().m.p.ptr() == nil { throw("no P available, write barriers are forbidden") } - tryRecordGoroutineProfile(gp1, osyield) + tryRecordGoroutineProfile(gp1, nil, osyield) } // tryRecordGoroutineProfile ensures that gp1 has the appropriate representation // in the current goroutine profile: either that it should not be profiled, or // that a snapshot of its call stack and labels are now in the profile. -func tryRecordGoroutineProfile(gp1 *g, yield func()) { +func tryRecordGoroutineProfile(gp1 *g, pcbuf []uintptr, yield func()) { if readgstatus(gp1) == _Gdead { // Dead goroutines should not appear in the profile. Goroutines that // start while profile collection is active will get goroutineProfiled @@ -1286,7 +1524,7 @@ func tryRecordGoroutineProfile(gp1 *g, yield func()) { // in this limbo. mp := acquirem() if gp1.goroutineProfiled.CompareAndSwap(goroutineProfileAbsent, goroutineProfileInProgress) { - doRecordGoroutineProfile(gp1) + doRecordGoroutineProfile(gp1, pcbuf) gp1.goroutineProfiled.Store(goroutineProfileSatisfied) } releasem(mp) @@ -1300,7 +1538,7 @@ func tryRecordGoroutineProfile(gp1 *g, yield func()) { // goroutine that is coordinating the goroutine profile (running on its own // stack), or from the scheduler in preparation to execute gp1 (running on the // system stack). -func doRecordGoroutineProfile(gp1 *g) { +func doRecordGoroutineProfile(gp1 *g, pcbuf []uintptr) { if readgstatus(gp1) == _Grunning { print("doRecordGoroutineProfile gp1=", gp1.goid, "\n") throw("cannot read stack of running goroutine") @@ -1323,14 +1561,14 @@ func doRecordGoroutineProfile(gp1 *g) { // set gp1.goroutineProfiled to goroutineProfileInProgress and so are still // preventing it from being truly _Grunnable. So we'll use the system stack // to avoid schedule delays. - systemstack(func() { saveg(^uintptr(0), ^uintptr(0), gp1, &goroutineProfile.records[offset]) }) + systemstack(func() { saveg(^uintptr(0), ^uintptr(0), gp1, &goroutineProfile.records[offset], pcbuf) }) if goroutineProfile.labels != nil { goroutineProfile.labels[offset] = gp1.labels } } -func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n int, ok bool) { +func goroutineProfileWithLabelsSync(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { gp := getg() isOK := func(gp1 *g) bool { @@ -1339,6 +1577,7 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n return gp1 != gp && readgstatus(gp1) != _Gdead && !isSystemGoroutine(gp1, false) } + pcbuf := makeProfStack() // see saveg() for explanation stw := stopTheWorld(stwGoroutineProfile) // World is stopped, no locking required. @@ -1357,7 +1596,7 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n sp := getcallersp() pc := getcallerpc() systemstack(func() { - saveg(pc, sp, gp, &r[0]) + saveg(pc, sp, gp, &r[0], pcbuf) }) r = r[1:] @@ -1382,7 +1621,7 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n // The world is stopped, so it cannot use cgocall (which will be // blocked at exitsyscall). Do it on the system stack so it won't // call into the schedular (see traceback.go:cgoContextPCs). - systemstack(func() { saveg(^uintptr(0), ^uintptr(0), gp1, &r[0]) }) + systemstack(func() { saveg(^uintptr(0), ^uintptr(0), gp1, &r[0], pcbuf) }) if labels != nil { lbl[0] = gp1.labels lbl = lbl[1:] @@ -1406,17 +1645,42 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n // Most clients should use the [runtime/pprof] package instead // of calling GoroutineProfile directly. func GoroutineProfile(p []StackRecord) (n int, ok bool) { + records := make([]profilerecord.StackRecord, len(p)) + n, ok = goroutineProfileInternal(records) + if !ok { + return + } + for i, mr := range records[0:n] { + l := copy(p[i].Stack0[:], mr.Stack) + clear(p[i].Stack0[l:]) + } + return +} +func goroutineProfileInternal(p []profilerecord.StackRecord) (n int, ok bool) { return goroutineProfileWithLabels(p, nil) } -func saveg(pc, sp uintptr, gp *g, r *StackRecord) { +func saveg(pc, sp uintptr, gp *g, r *profilerecord.StackRecord, pcbuf []uintptr) { + // To reduce memory usage, we want to allocate a r.Stack that is just big + // enough to hold gp's stack trace. Naively we might achieve this by + // recording our stack trace into mp.profStack, and then allocating a + // r.Stack of the right size. However, mp.profStack is also used for + // allocation profiling, so it could get overwritten if the slice allocation + // gets profiled. So instead we record the stack trace into a temporary + // pcbuf which is usually given to us by our caller. When it's not, we have + // to allocate one here. This will only happen for goroutines that were in a + // syscall when the goroutine profile started or for goroutines that manage + // to execute before we finish iterating over all the goroutines. + if pcbuf == nil { + pcbuf = makeProfStack() + } + var u unwinder u.initAt(pc, sp, 0, gp, unwindSilentErrors) - n := tracebackPCs(&u, 0, r.Stack0[:]) - if n < len(r.Stack0) { - r.Stack0[n] = 0 - } + n := tracebackPCs(&u, 0, pcbuf) + r.Stack = make([]uintptr, n) + copy(r.Stack, pcbuf) } // Stack formats a stack trace of the calling goroutine into buf @@ -1457,61 +1721,3 @@ func Stack(buf []byte, all bool) int { } return n } - -// Tracing of alloc/free/gc. - -var tracelock mutex - -func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) { - lock(&tracelock) - gp := getg() - gp.m.traceback = 2 - if typ == nil { - print("tracealloc(", p, ", ", hex(size), ")\n") - } else { - print("tracealloc(", p, ", ", hex(size), ", ", toRType(typ).string(), ")\n") - } - if gp.m.curg == nil || gp == gp.m.curg { - goroutineheader(gp) - pc := getcallerpc() - sp := getcallersp() - systemstack(func() { - traceback(pc, sp, 0, gp) - }) - } else { - goroutineheader(gp.m.curg) - traceback(^uintptr(0), ^uintptr(0), 0, gp.m.curg) - } - print("\n") - gp.m.traceback = 0 - unlock(&tracelock) -} - -func tracefree(p unsafe.Pointer, size uintptr) { - lock(&tracelock) - gp := getg() - gp.m.traceback = 2 - print("tracefree(", p, ", ", hex(size), ")\n") - goroutineheader(gp) - pc := getcallerpc() - sp := getcallersp() - systemstack(func() { - traceback(pc, sp, 0, gp) - }) - print("\n") - gp.m.traceback = 0 - unlock(&tracelock) -} - -func tracegc() { - lock(&tracelock) - gp := getg() - gp.m.traceback = 2 - print("tracegc()\n") - // running on m->g0 stack; show all non-g0 goroutines - tracebackothers(gp) - print("end tracegc\n") - print("\n") - gp.m.traceback = 0 - unlock(&tracelock) -} diff --git a/contrib/go/_std_1.22/src/runtime/mranges.go b/contrib/go/_std_1.23/src/runtime/mranges.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mranges.go rename to contrib/go/_std_1.23/src/runtime/mranges.go index 6dd1a7524732..85795a941884 100644 --- a/contrib/go/_std_1.22/src/runtime/mranges.go +++ b/contrib/go/_std_1.23/src/runtime/mranges.go @@ -11,7 +11,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.23/src/runtime/msan.go b/contrib/go/_std_1.23/src/runtime/msan.go new file mode 100644 index 000000000000..cb740dc2d86a --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/msan.go @@ -0,0 +1,67 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build msan + +package runtime + +import ( + "unsafe" +) + +// Public memory sanitizer API. + +func MSanRead(addr unsafe.Pointer, len int) { + msanread(addr, uintptr(len)) +} + +func MSanWrite(addr unsafe.Pointer, len int) { + msanwrite(addr, uintptr(len)) +} + +// Private interface for the runtime. +const msanenabled = true + +// If we are running on the system stack, the C program may have +// marked part of that stack as uninitialized. We don't instrument +// the runtime, but operations like a slice copy can call msanread +// anyhow for values on the stack. Just ignore msanread when running +// on the system stack. The other msan functions are fine. +// +//go:linkname msanread +//go:nosplit +func msanread(addr unsafe.Pointer, sz uintptr) { + gp := getg() + if gp == nil || gp.m == nil || gp == gp.m.g0 || gp == gp.m.gsignal { + return + } + domsanread(addr, sz) +} + +//go:noescape +func domsanread(addr unsafe.Pointer, sz uintptr) + +//go:linkname msanwrite +//go:noescape +func msanwrite(addr unsafe.Pointer, sz uintptr) + +//go:linkname msanmalloc +//go:noescape +func msanmalloc(addr unsafe.Pointer, sz uintptr) + +//go:linkname msanfree +//go:noescape +func msanfree(addr unsafe.Pointer, sz uintptr) + +//go:linkname msanmove +//go:noescape +func msanmove(dst, src unsafe.Pointer, sz uintptr) + +// These are called from msan_GOARCH.s +// +//go:cgo_import_static __msan_read_go +//go:cgo_import_static __msan_write_go +//go:cgo_import_static __msan_malloc_go +//go:cgo_import_static __msan_free_go +//go:cgo_import_static __msan_memmove diff --git a/contrib/go/_std_1.22/src/runtime/msan/msan.go b/contrib/go/_std_1.23/src/runtime/msan/msan.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan/msan.go rename to contrib/go/_std_1.23/src/runtime/msan/msan.go diff --git a/contrib/go/_std_1.22/src/runtime/msan/ya.make b/contrib/go/_std_1.23/src/runtime/msan/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan/ya.make rename to contrib/go/_std_1.23/src/runtime/msan/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/msan0.go b/contrib/go/_std_1.23/src/runtime/msan0.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan0.go rename to contrib/go/_std_1.23/src/runtime/msan0.go diff --git a/contrib/go/_std_1.22/src/runtime/msan_amd64.s b/contrib/go/_std_1.23/src/runtime/msan_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan_amd64.s rename to contrib/go/_std_1.23/src/runtime/msan_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/msan_arm64.s b/contrib/go/_std_1.23/src/runtime/msan_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan_arm64.s rename to contrib/go/_std_1.23/src/runtime/msan_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/msan_loong64.s b/contrib/go/_std_1.23/src/runtime/msan_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan_loong64.s rename to contrib/go/_std_1.23/src/runtime/msan_loong64.s diff --git a/contrib/go/_std_1.23/src/runtime/msize.go b/contrib/go/_std_1.23/src/runtime/msize.go new file mode 100644 index 000000000000..64d1531ab098 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/msize.go @@ -0,0 +1,34 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Malloc small size classes. +// +// See malloc.go for overview. +// See also mksizeclasses.go for how we decide what size classes to use. + +package runtime + +// Returns size of the memory block that mallocgc will allocate if you ask for the size, +// minus any inline space for metadata. +func roundupsize(size uintptr, noscan bool) (reqSize uintptr) { + reqSize = size + if reqSize <= maxSmallSize-mallocHeaderSize { + // Small object. + if !noscan && reqSize > minSizeForMallocHeader { // !noscan && !heapBitsInSpan(reqSize) + reqSize += mallocHeaderSize + } + // (reqSize - size) is either mallocHeaderSize or 0. We need to subtract mallocHeaderSize + // from the result if we have one, since mallocgc will add it back in. + if reqSize <= smallSizeMax-8 { + return uintptr(class_to_size[size_to_class8[divRoundUp(reqSize, smallSizeDiv)]]) - (reqSize - size) + } + return uintptr(class_to_size[size_to_class128[divRoundUp(reqSize-smallSizeMax, largeSizeDiv)]]) - (reqSize - size) + } + // Large object. Align reqSize up to the next page. Check for overflow. + reqSize += pageSize - 1 + if reqSize < size { + return size + } + return reqSize &^ (pageSize - 1) +} diff --git a/contrib/go/_std_1.22/src/runtime/mspanset.go b/contrib/go/_std_1.23/src/runtime/mspanset.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mspanset.go rename to contrib/go/_std_1.23/src/runtime/mspanset.go index 5687627e3a20..3aa2b5b3937f 100644 --- a/contrib/go/_std_1.22/src/runtime/mspanset.go +++ b/contrib/go/_std_1.23/src/runtime/mspanset.go @@ -7,7 +7,7 @@ package runtime import ( "internal/cpu" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/mstats.go b/contrib/go/_std_1.23/src/runtime/mstats.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mstats.go rename to contrib/go/_std_1.23/src/runtime/mstats.go index 87afec47c868..c10ca402217c 100644 --- a/contrib/go/_std_1.22/src/runtime/mstats.go +++ b/contrib/go/_std_1.23/src/runtime/mstats.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -905,20 +905,30 @@ type cpuStats struct { // they don't accurately compute on-CPU time (so some of the time // could be spent scheduled away by the OS). - gcAssistTime int64 // GC assists - gcDedicatedTime int64 // GC dedicated mark workers + pauses - gcIdleTime int64 // GC idle mark workers - gcPauseTime int64 // GC pauses (all GOMAXPROCS, even if just 1 is running) - gcTotalTime int64 + GCAssistTime int64 // GC assists + GCDedicatedTime int64 // GC dedicated mark workers + pauses + GCIdleTime int64 // GC idle mark workers + GCPauseTime int64 // GC pauses (all GOMAXPROCS, even if just 1 is running) + GCTotalTime int64 - scavengeAssistTime int64 // background scavenger - scavengeBgTime int64 // scavenge assists - scavengeTotalTime int64 + ScavengeAssistTime int64 // background scavenger + ScavengeBgTime int64 // scavenge assists + ScavengeTotalTime int64 - idleTime int64 // Time Ps spent in _Pidle. - userTime int64 // Time Ps spent in _Prunning or _Psyscall that's not any of the above. + IdleTime int64 // Time Ps spent in _Pidle. + UserTime int64 // Time Ps spent in _Prunning or _Psyscall that's not any of the above. - totalTime int64 // GOMAXPROCS * (monotonic wall clock time elapsed) + TotalTime int64 // GOMAXPROCS * (monotonic wall clock time elapsed) +} + +// accumulateGCPauseTime add dt*stwProcs to the GC CPU pause time stats. dt should be +// the actual time spent paused, for orthogonality. maxProcs should be GOMAXPROCS, +// not work.stwprocs, since this number must be comparable to a total time computed +// from GOMAXPROCS. +func (s *cpuStats) accumulateGCPauseTime(dt int64, maxProcs int32) { + cpu := dt * int64(maxProcs) + s.GCPauseTime += cpu + s.GCTotalTime += cpu } // accumulate takes a cpuStats and adds in the current state of all GC CPU @@ -951,19 +961,19 @@ func (s *cpuStats) accumulate(now int64, gcMarkPhase bool) { scavBgCpu := scavenge.backgroundTime.Load() // Update cumulative GC CPU stats. - s.gcAssistTime += markAssistCpu - s.gcDedicatedTime += markDedicatedCpu + markFractionalCpu - s.gcIdleTime += markIdleCpu - s.gcTotalTime += markAssistCpu + markDedicatedCpu + markFractionalCpu + markIdleCpu + s.GCAssistTime += markAssistCpu + s.GCDedicatedTime += markDedicatedCpu + markFractionalCpu + s.GCIdleTime += markIdleCpu + s.GCTotalTime += markAssistCpu + markDedicatedCpu + markFractionalCpu + markIdleCpu // Update cumulative scavenge CPU stats. - s.scavengeAssistTime += scavAssistCpu - s.scavengeBgTime += scavBgCpu - s.scavengeTotalTime += scavAssistCpu + scavBgCpu + s.ScavengeAssistTime += scavAssistCpu + s.ScavengeBgTime += scavBgCpu + s.ScavengeTotalTime += scavAssistCpu + scavBgCpu // Update total CPU. - s.totalTime = sched.totaltime + (now-sched.procresizetime)*int64(gomaxprocs) - s.idleTime += sched.idleTime.Load() + s.TotalTime = sched.totaltime + (now-sched.procresizetime)*int64(gomaxprocs) + s.IdleTime += sched.idleTime.Load() // Compute userTime. We compute this indirectly as everything that's not the above. // @@ -973,5 +983,5 @@ func (s *cpuStats) accumulate(now int64, gcMarkPhase bool) { // else via sysmon. Meanwhile if we subtract GC time from whatever's left, we get non-GC // _Prunning time. Note that this still leaves time spent in sweeping and in the scheduler, // but that's fine. The overwhelming majority of this time will be actual user time. - s.userTime = s.totalTime - (s.gcTotalTime + s.scavengeTotalTime + s.idleTime) + s.UserTime = s.TotalTime - (s.GCTotalTime + s.ScavengeTotalTime + s.IdleTime) } diff --git a/contrib/go/_std_1.22/src/runtime/mwbbuf.go b/contrib/go/_std_1.23/src/runtime/mwbbuf.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mwbbuf.go rename to contrib/go/_std_1.23/src/runtime/mwbbuf.go index 7419bd291dbf..b998d2b2bdf5 100644 --- a/contrib/go/_std_1.22/src/runtime/mwbbuf.go +++ b/contrib/go/_std_1.23/src/runtime/mwbbuf.go @@ -24,7 +24,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/nbpipe_pipe.go b/contrib/go/_std_1.23/src/runtime/nbpipe_pipe.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/nbpipe_pipe.go rename to contrib/go/_std_1.23/src/runtime/nbpipe_pipe.go diff --git a/contrib/go/_std_1.22/src/runtime/nbpipe_pipe2.go b/contrib/go/_std_1.23/src/runtime/nbpipe_pipe2.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/nbpipe_pipe2.go rename to contrib/go/_std_1.23/src/runtime/nbpipe_pipe2.go diff --git a/contrib/go/_std_1.22/src/runtime/net_plan9.go b/contrib/go/_std_1.23/src/runtime/net_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/net_plan9.go rename to contrib/go/_std_1.23/src/runtime/net_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/netpoll.go b/contrib/go/_std_1.23/src/runtime/netpoll.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/netpoll.go rename to contrib/go/_std_1.23/src/runtime/netpoll.go index 9c2e40ce8a56..7b37d91b24a4 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -102,9 +102,11 @@ type pollDesc struct { lock mutex // protects the following fields closing bool + rrun bool // whether rt is running + wrun bool // whether wt is running user uint32 // user settable cookie rseq uintptr // protects from stale read timers - rt timer // read deadline timer (set if rt.f != nil) + rt timer // read deadline timer rd int64 // read deadline (a nanotime in the future, -1 when expired) wseq uintptr // protects from stale write timers wt timer // write deadline timer @@ -205,6 +207,9 @@ var ( netpollWaiters atomic.Uint32 ) +// netpollWaiters is accessed in tests +//go:linkname netpollWaiters + //go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit func poll_runtime_pollServerInit() { netpollGenericInit() @@ -213,6 +218,7 @@ func poll_runtime_pollServerInit() { func netpollGenericInit() { if netpollInited.Load() == 0 { lockInit(&netpollInitLock, lockRankNetpollInit) + lockInit(&pollcache.lock, lockRankPollCache) lock(&netpollInitLock) if netpollInited.Load() == 0 { netpollinit() @@ -391,39 +397,35 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { if combo { rtf = netpollDeadline } - if pd.rt.f == nil { + if !pd.rrun { if pd.rd > 0 { - pd.rt.f = rtf // Copy current seq into the timer arg. // Timer func will check the seq against current descriptor seq, // if they differ the descriptor was reused or timers were reset. - pd.rt.arg = pd.makeArg() - pd.rt.seq = pd.rseq - resettimer(&pd.rt, pd.rd) + pd.rt.modify(pd.rd, 0, rtf, pd.makeArg(), pd.rseq) + pd.rrun = true } } else if pd.rd != rd0 || combo != combo0 { pd.rseq++ // invalidate current timers if pd.rd > 0 { - modtimer(&pd.rt, pd.rd, 0, rtf, pd.makeArg(), pd.rseq) + pd.rt.modify(pd.rd, 0, rtf, pd.makeArg(), pd.rseq) } else { - deltimer(&pd.rt) - pd.rt.f = nil + pd.rt.stop() + pd.rrun = false } } - if pd.wt.f == nil { + if !pd.wrun { if pd.wd > 0 && !combo { - pd.wt.f = netpollWriteDeadline - pd.wt.arg = pd.makeArg() - pd.wt.seq = pd.wseq - resettimer(&pd.wt, pd.wd) + pd.wt.modify(pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq) + pd.wrun = true } } else if pd.wd != wd0 || combo != combo0 { pd.wseq++ // invalidate current timers if pd.wd > 0 && !combo { - modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq) + pd.wt.modify(pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq) } else { - deltimer(&pd.wt) - pd.wt.f = nil + pd.wt.stop() + pd.wrun = false } } // If we set the new deadline in the past, unblock currently pending IO if any. @@ -460,13 +462,13 @@ func poll_runtime_pollUnblock(pd *pollDesc) { delta := int32(0) rg = netpollunblock(pd, 'r', false, &delta) wg = netpollunblock(pd, 'w', false, &delta) - if pd.rt.f != nil { - deltimer(&pd.rt) - pd.rt.f = nil + if pd.rrun { + pd.rt.stop() + pd.rrun = false } - if pd.wt.f != nil { - deltimer(&pd.wt) - pd.wt.f = nil + if pd.wrun { + pd.wt.stop() + pd.wrun = false } unlock(&pd.lock) if rg != nil { @@ -633,7 +635,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) { delta := int32(0) var rg *g if read { - if pd.rd <= 0 || pd.rt.f == nil { + if pd.rd <= 0 || !pd.rrun { throw("runtime: inconsistent read deadline") } pd.rd = -1 @@ -642,7 +644,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) { } var wg *g if write { - if pd.wd <= 0 || pd.wt.f == nil && !read { + if pd.wd <= 0 || !pd.wrun && !read { throw("runtime: inconsistent write deadline") } pd.wd = -1 @@ -659,15 +661,15 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) { netpollAdjustWaiters(delta) } -func netpollDeadline(arg any, seq uintptr) { +func netpollDeadline(arg any, seq uintptr, delta int64) { netpolldeadlineimpl(arg.(*pollDesc), seq, true, true) } -func netpollReadDeadline(arg any, seq uintptr) { +func netpollReadDeadline(arg any, seq uintptr, delta int64) { netpolldeadlineimpl(arg.(*pollDesc), seq, true, false) } -func netpollWriteDeadline(arg any, seq uintptr) { +func netpollWriteDeadline(arg any, seq uintptr, delta int64) { netpolldeadlineimpl(arg.(*pollDesc), seq, false, true) } @@ -696,13 +698,15 @@ func (c *pollCache) alloc() *pollDesc { mem := persistentalloc(n*pdSize, 0, &memstats.other_sys) for i := uintptr(0); i < n; i++ { pd := (*pollDesc)(add(mem, i*pdSize)) + lockInit(&pd.lock, lockRankPollDesc) + pd.rt.init(nil, nil) + pd.wt.init(nil, nil) pd.link = c.first c.first = pd } } pd := c.first c.first = pd.link - lockInit(&pd.lock, lockRankPollDesc) unlock(&c.lock) return pd } diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_aix.go b/contrib/go/_std_1.23/src/runtime/netpoll_aix.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/netpoll_aix.go rename to contrib/go/_std_1.23/src/runtime/netpoll_aix.go index a34b4d8bcfba..2df5a5711145 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_aix.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_aix.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.23/src/runtime/netpoll_epoll.go b/contrib/go/_std_1.23/src/runtime/netpoll_epoll.go new file mode 100644 index 000000000000..ff6e0b5f89cc --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/netpoll_epoll.go @@ -0,0 +1,173 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux + +package runtime + +import ( + "internal/runtime/atomic" + "internal/runtime/syscall" + "unsafe" +) + +var ( + epfd int32 = -1 // epoll descriptor + netpollEventFd uintptr // eventfd for netpollBreak + netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak +) + +func netpollinit() { + var errno uintptr + epfd, errno = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC) + if errno != 0 { + println("runtime: epollcreate failed with", errno) + throw("runtime: netpollinit failed") + } + efd, errno := syscall.Eventfd(0, syscall.EFD_CLOEXEC|syscall.EFD_NONBLOCK) + if errno != 0 { + println("runtime: eventfd failed with", -errno) + throw("runtime: eventfd failed") + } + ev := syscall.EpollEvent{ + Events: syscall.EPOLLIN, + } + *(**uintptr)(unsafe.Pointer(&ev.Data)) = &netpollEventFd + errno = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, efd, &ev) + if errno != 0 { + println("runtime: epollctl failed with", errno) + throw("runtime: epollctl failed") + } + netpollEventFd = uintptr(efd) +} + +func netpollIsPollDescriptor(fd uintptr) bool { + return fd == uintptr(epfd) || fd == netpollEventFd +} + +func netpollopen(fd uintptr, pd *pollDesc) uintptr { + var ev syscall.EpollEvent + ev.Events = syscall.EPOLLIN | syscall.EPOLLOUT | syscall.EPOLLRDHUP | syscall.EPOLLET + tp := taggedPointerPack(unsafe.Pointer(pd), pd.fdseq.Load()) + *(*taggedPointer)(unsafe.Pointer(&ev.Data)) = tp + return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, int32(fd), &ev) +} + +func netpollclose(fd uintptr) uintptr { + var ev syscall.EpollEvent + return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, int32(fd), &ev) +} + +func netpollarm(pd *pollDesc, mode int) { + throw("runtime: unused") +} + +// netpollBreak interrupts an epollwait. +func netpollBreak() { + // Failing to cas indicates there is an in-flight wakeup, so we're done here. + if !netpollWakeSig.CompareAndSwap(0, 1) { + return + } + + var one uint64 = 1 + oneSize := int32(unsafe.Sizeof(one)) + for { + n := write(netpollEventFd, noescape(unsafe.Pointer(&one)), oneSize) + if n == oneSize { + break + } + if n == -_EINTR { + continue + } + if n == -_EAGAIN { + return + } + println("runtime: netpollBreak write failed with", -n) + throw("runtime: netpollBreak write failed") + } +} + +// netpoll checks for ready network connections. +// Returns list of goroutines that become runnable. +// delay < 0: blocks indefinitely +// delay == 0: does not block, just polls +// delay > 0: block for up to that many nanoseconds +func netpoll(delay int64) (gList, int32) { + if epfd == -1 { + return gList{}, 0 + } + var waitms int32 + if delay < 0 { + waitms = -1 + } else if delay == 0 { + waitms = 0 + } else if delay < 1e6 { + waitms = 1 + } else if delay < 1e15 { + waitms = int32(delay / 1e6) + } else { + // An arbitrary cap on how long to wait for a timer. + // 1e9 ms == ~11.5 days. + waitms = 1e9 + } + var events [128]syscall.EpollEvent +retry: + n, errno := syscall.EpollWait(epfd, events[:], int32(len(events)), waitms) + if errno != 0 { + if errno != _EINTR { + println("runtime: epollwait on fd", epfd, "failed with", errno) + throw("runtime: netpoll failed") + } + // If a timed sleep was interrupted, just return to + // recalculate how long we should sleep now. + if waitms > 0 { + return gList{}, 0 + } + goto retry + } + var toRun gList + delta := int32(0) + for i := int32(0); i < n; i++ { + ev := events[i] + if ev.Events == 0 { + continue + } + + if *(**uintptr)(unsafe.Pointer(&ev.Data)) == &netpollEventFd { + if ev.Events != syscall.EPOLLIN { + println("runtime: netpoll: eventfd ready for", ev.Events) + throw("runtime: netpoll: eventfd ready for something unexpected") + } + if delay != 0 { + // netpollBreak could be picked up by a + // nonblocking poll. Only read the 8-byte + // integer if blocking. + // Since EFD_SEMAPHORE was not specified, + // the eventfd counter will be reset to 0. + var one uint64 + read(int32(netpollEventFd), noescape(unsafe.Pointer(&one)), int32(unsafe.Sizeof(one))) + netpollWakeSig.Store(0) + } + continue + } + + var mode int32 + if ev.Events&(syscall.EPOLLIN|syscall.EPOLLRDHUP|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 { + mode += 'r' + } + if ev.Events&(syscall.EPOLLOUT|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 { + mode += 'w' + } + if mode != 0 { + tp := *(*taggedPointer)(unsafe.Pointer(&ev.Data)) + pd := (*pollDesc)(tp.pointer()) + tag := tp.tag() + if pd.fdseq.Load() == tag { + pd.setEventErr(ev.Events == syscall.EPOLLERR, tag) + delta += netpollready(&toRun, pd, mode) + } + } + } + return toRun, delta +} diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_fake.go b/contrib/go/_std_1.23/src/runtime/netpoll_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/netpoll_fake.go rename to contrib/go/_std_1.23/src/runtime/netpoll_fake.go diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_kqueue.go b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue.go similarity index 76% rename from contrib/go/_std_1.22/src/runtime/netpoll_kqueue.go rename to contrib/go/_std_1.23/src/runtime/netpoll_kqueue.go index d774dce3034c..6cd80d5c30d1 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_kqueue.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue.go @@ -10,15 +10,12 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) var ( - kq int32 = -1 - - netpollBreakRd, netpollBreakWr uintptr // for netpollBreak - + kq int32 = -1 netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak ) @@ -29,27 +26,7 @@ func netpollinit() { throw("runtime: netpollinit failed") } closeonexec(kq) - r, w, errno := nonblockingPipe() - if errno != 0 { - println("runtime: pipe failed with", -errno) - throw("runtime: pipe failed") - } - ev := keventt{ - filter: _EVFILT_READ, - flags: _EV_ADD, - } - *(*uintptr)(unsafe.Pointer(&ev.ident)) = uintptr(r) - n := kevent(kq, &ev, 1, nil, 0, nil) - if n < 0 { - println("runtime: kevent failed with", -n) - throw("runtime: kevent failed") - } - netpollBreakRd = uintptr(r) - netpollBreakWr = uintptr(w) -} - -func netpollIsPollDescriptor(fd uintptr) bool { - return fd == uintptr(kq) || fd == netpollBreakRd || fd == netpollBreakWr + addWakeupEvent(kq) } func netpollopen(fd uintptr, pd *pollDesc) int32 { @@ -99,18 +76,7 @@ func netpollBreak() { return } - for { - var b byte - n := write(netpollBreakWr, unsafe.Pointer(&b), 1) - if n == 1 || n == -_EAGAIN { - break - } - if n == -_EINTR { - continue - } - println("runtime: netpollBreak write failed with", -n) - throw("runtime: netpollBreak write failed") - } + wakeNetpoll(kq) } // netpoll checks for ready network connections. @@ -159,17 +125,11 @@ retry: for i := 0; i < int(n); i++ { ev := &events[i] - if uintptr(ev.ident) == netpollBreakRd { - if ev.filter != _EVFILT_READ { - println("runtime: netpoll: break fd ready for", ev.filter) - throw("runtime: netpoll: break fd ready for something unexpected") - } + if isWakeup(ev) { if delay != 0 { - // netpollBreak could be picked up by a - // nonblocking poll. Only read the byte - // if blocking. - var tmp [16]byte - read(int32(netpollBreakRd), noescape(unsafe.Pointer(&tmp[0])), int32(len(tmp))) + // netpollBreak could be picked up by a nonblocking poll. + // Only call drainWakeupEvent and reset the netpollWakeSig if blocking. + drainWakeupEvent(kq) netpollWakeSig.Store(0) } continue diff --git a/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_event.go b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_event.go new file mode 100644 index 000000000000..d5f783e607e8 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_event.go @@ -0,0 +1,80 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd + +package runtime + +// Magic number of identifier used for EVFILT_USER. +// This number had zero Google results when it's created. +// That way, people will be directed here when this number +// get printed somehow and they search for it. +const kqIdent = 0xee1eb9f4 + +func addWakeupEvent(kq int32) { + ev := keventt{ + ident: kqIdent, + filter: _EVFILT_USER, + flags: _EV_ADD, + } + for { + n := kevent(kq, &ev, 1, nil, 0, nil) + if n == 0 { + break + } + if n == -_EINTR { + // All changes contained in the changelist should have been applied + // before returning EINTR. But let's be skeptical and retry it anyway, + // to make a 100% commitment. + continue + } + println("runtime: kevent for EVFILT_USER failed with", -n) + throw("runtime: kevent failed") + } +} + +func wakeNetpoll(kq int32) { + ev := keventt{ + ident: kqIdent, + filter: _EVFILT_USER, + flags: _EV_ENABLE, + fflags: _NOTE_TRIGGER, + } + for { + n := kevent(kq, &ev, 1, nil, 0, nil) + if n == 0 { + break + } + if n == -_EINTR { + // Check out the comment in addWakeupEvent. + continue + } + println("runtime: netpollBreak write failed with", -n) + throw("runtime: netpollBreak write failed") + } +} + +func isWakeup(ev *keventt) bool { + if ev.filter == _EVFILT_USER { + if ev.ident == kqIdent { + return true + } + println("runtime: netpoll: break fd ready for", ev.ident) + throw("runtime: netpoll: break fd ready for something unexpected") + } + return false +} + +func drainWakeupEvent(kq int32) { + ev := keventt{ + ident: kqIdent, + filter: _EVFILT_USER, + flags: _EV_DISABLE, + } + kevent(kq, &ev, 1, nil, 0, nil) +} + +func netpollIsPollDescriptor(fd uintptr) bool { + return fd == uintptr(kq) +} diff --git a/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_pipe.go b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_pipe.go new file mode 100644 index 000000000000..98f73e84d29f --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_pipe.go @@ -0,0 +1,73 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build netbsd || openbsd + +package runtime + +import "unsafe" + +// TODO(panjf2000): NetBSD didn't implement EVFILT_USER for user-established events +// until NetBSD 10.0, check out https://www.netbsd.org/releases/formal-10/NetBSD-10.0.html +// Therefore we use the pipe to wake up the kevent on NetBSD at this point. Get back here +// and switch to EVFILT_USER when we bump up the minimal requirement of NetBSD to 10.0. +// Alternatively, maybe we can use EVFILT_USER on the NetBSD by checking the kernel version +// via uname(3) and fall back to the pipe if the kernel version is older than 10.0. + +var netpollBreakRd, netpollBreakWr uintptr // for netpollBreak + +func addWakeupEvent(kq int32) { + r, w, errno := nonblockingPipe() + if errno != 0 { + println("runtime: pipe failed with", -errno) + throw("runtime: pipe failed") + } + ev := keventt{ + filter: _EVFILT_READ, + flags: _EV_ADD, + } + *(*uintptr)(unsafe.Pointer(&ev.ident)) = uintptr(r) + n := kevent(kq, &ev, 1, nil, 0, nil) + if n < 0 { + println("runtime: kevent failed with", -n) + throw("runtime: kevent failed") + } + netpollBreakRd = uintptr(r) + netpollBreakWr = uintptr(w) +} + +func wakeNetpoll(_ int32) { + for { + var b byte + n := write(netpollBreakWr, unsafe.Pointer(&b), 1) + if n == 1 || n == -_EAGAIN { + break + } + if n == -_EINTR { + continue + } + println("runtime: netpollBreak write failed with", -n) + throw("runtime: netpollBreak write failed") + } +} + +func isWakeup(ev *keventt) bool { + if uintptr(ev.ident) == netpollBreakRd { + if ev.filter == _EVFILT_READ { + return true + } + println("runtime: netpoll: break fd ready for", ev.filter) + throw("runtime: netpoll: break fd ready for something unexpected") + } + return false +} + +func drainWakeupEvent(_ int32) { + var buf [16]byte + read(int32(netpollBreakRd), noescape(unsafe.Pointer(&buf[0])), int32(len(buf))) +} + +func netpollIsPollDescriptor(fd uintptr) bool { + return fd == uintptr(kq) || fd == netpollBreakRd || fd == netpollBreakWr +} diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_solaris.go b/contrib/go/_std_1.23/src/runtime/netpoll_solaris.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/netpoll_solaris.go rename to contrib/go/_std_1.23/src/runtime/netpoll_solaris.go index 41f145c86692..fddc29000b78 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_solaris.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_solaris.go @@ -6,7 +6,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_stub.go b/contrib/go/_std_1.23/src/runtime/netpoll_stub.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/netpoll_stub.go rename to contrib/go/_std_1.23/src/runtime/netpoll_stub.go index d950661acf3d..c1bda3fa8b0d 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_stub.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_stub.go @@ -6,7 +6,7 @@ package runtime -import "runtime/internal/atomic" +import "internal/runtime/atomic" var netpollInited atomic.Uint32 diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_wasip1.go b/contrib/go/_std_1.23/src/runtime/netpoll_wasip1.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/netpoll_wasip1.go rename to contrib/go/_std_1.23/src/runtime/netpoll_wasip1.go index 9903726809f8..e6b299a20fa8 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_wasip1.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_wasip1.go @@ -205,9 +205,7 @@ func netpoll(delay int64) (gList, int32) { } evts = evts[:len(pollsubs)] - for i := range evts { - evts[i] = event{} - } + clear(evts) retry: var nevents size diff --git a/contrib/go/_std_1.23/src/runtime/netpoll_windows.go b/contrib/go/_std_1.23/src/runtime/netpoll_windows.go new file mode 100644 index 000000000000..c3c10af72379 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/netpoll_windows.go @@ -0,0 +1,284 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/goarch" + "internal/runtime/atomic" + "unsafe" +) + +const _DWORD_MAX = 0xffffffff + +const _INVALID_HANDLE_VALUE = ^uintptr(0) + +// Sources are used to identify the event that created an overlapped entry. +// The source values are arbitrary. There is no risk of collision with user +// defined values because the only way to set the key of an overlapped entry +// is using the iocphandle, which is not accessible to user code. +const ( + netpollSourceReady = iota + 1 + netpollSourceBreak + netpollSourceTimer +) + +const ( + // sourceBits is the number of bits needed to represent a source. + // 4 bits can hold 16 different sources, which is more than enough. + // It is set to a low value so the overlapped entry key can + // contain as much bits as possible for the pollDesc pointer. + sourceBits = 4 // 4 bits can hold 16 different sources, which is more than enough. + sourceMasks = 1< (1< 0: block for up to that many nanoseconds +func netpoll(delay int64) (gList, int32) { + if iocphandle == _INVALID_HANDLE_VALUE { + return gList{}, 0 + } + + var entries [64]overlappedEntry + var wait uint32 + var toRun gList + mp := getg().m + + if delay >= 1e15 { + // An arbitrary cap on how long to wait for a timer. + // 1e15 ns == ~11.5 days. + delay = 1e15 + } + + if delay > 0 && mp.waitIocpHandle != 0 { + // GetQueuedCompletionStatusEx doesn't use a high resolution timer internally, + // so we use a separate higher resolution timer associated with a wait completion + // packet to wake up the poller. Note that the completion packet can be delivered + // to another thread, and the Go scheduler expects netpoll to only block up to delay, + // so we still need to use a timeout with GetQueuedCompletionStatusEx. + // TODO: Improve the Go scheduler to support non-blocking timers. + signaled := netpollQueueTimer(delay) + if signaled { + // There is a small window between the SetWaitableTimer and the NtAssociateWaitCompletionPacket + // where the timer can expire. We can return immediately in this case. + return gList{}, 0 + } + } + if delay < 0 { + wait = _INFINITE + } else if delay == 0 { + wait = 0 + } else if delay < 1e6 { + wait = 1 + } else { + wait = uint32(delay / 1e6) + } + n := len(entries) / int(gomaxprocs) + if n < 8 { + n = 8 + } + if delay != 0 { + mp.blocked = true + } + if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 { + mp.blocked = false + errno := getlasterror() + if errno == _WAIT_TIMEOUT { + return gList{}, 0 + } + println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")") + throw("runtime: netpoll failed") + } + mp.blocked = false + delta := int32(0) + for i := 0; i < n; i++ { + e := &entries[i] + switch unpackNetpollSource(e.key) { + case netpollSourceReady: + op := pollOperationFromOverlappedEntry(e) + if op == nil { + // Entry from outside the Go runtime and internal/poll, ignore. + continue + } + // Entry from internal/poll. + mode := op.mode + if mode != 'r' && mode != 'w' { + println("runtime: GetQueuedCompletionStatusEx returned net_op with invalid mode=", mode) + throw("runtime: netpoll failed") + } + delta += netpollready(&toRun, op.pd, mode) + case netpollSourceBreak: + netpollWakeSig.Store(0) + if delay == 0 { + // Forward the notification to the blocked poller. + netpollBreak() + } + case netpollSourceTimer: + // TODO: We could avoid calling NtCancelWaitCompletionPacket for expired wait completion packets. + default: + println("runtime: GetQueuedCompletionStatusEx returned net_op with invalid key=", e.key) + throw("runtime: netpoll failed") + } + } + return toRun, delta +} + +// netpollQueueTimer queues a timer to wake up the poller after the given delay. +// It returns true if the timer expired during this call. +func netpollQueueTimer(delay int64) (signaled bool) { + const ( + STATUS_SUCCESS = 0x00000000 + STATUS_PENDING = 0x00000103 + STATUS_CANCELLED = 0xC0000120 + ) + mp := getg().m + // A wait completion packet can only be associated with one timer at a time, + // so we need to cancel the previous one if it exists. This wouldn't be necessary + // if the poller would only be woken up by the timer, in which case the association + // would be automatically canceled, but it can also be woken up by other events, + // such as a netpollBreak, so we can get to this point with a timer that hasn't + // expired yet. In this case, the completion packet can still be picked up by + // another thread, so defer the cancellation until it is really necessary. + errno := stdcall2(_NtCancelWaitCompletionPacket, mp.waitIocpHandle, 1) + switch errno { + case STATUS_CANCELLED: + // STATUS_CANCELLED is returned when the associated timer has already expired, + // in which automatically cancels the wait completion packet. + fallthrough + case STATUS_SUCCESS: + dt := -delay / 100 // relative sleep (negative), 100ns units + if stdcall6(_SetWaitableTimer, mp.waitIocpTimer, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0) == 0 { + println("runtime: SetWaitableTimer failed; errno=", getlasterror()) + throw("runtime: netpoll failed") + } + key := packNetpollKey(netpollSourceTimer, nil) + if errno := stdcall8(_NtAssociateWaitCompletionPacket, mp.waitIocpHandle, iocphandle, mp.waitIocpTimer, key, 0, 0, 0, uintptr(unsafe.Pointer(&signaled))); errno != 0 { + println("runtime: NtAssociateWaitCompletionPacket failed; errno=", errno) + throw("runtime: netpoll failed") + } + case STATUS_PENDING: + // STATUS_PENDING is returned if the wait operation can't be canceled yet. + // This can happen if this thread was woken up by another event, such as a netpollBreak, + // and the timer expired just while calling NtCancelWaitCompletionPacket, in which case + // this call fails to cancel the association to avoid a race condition. + // This is a rare case, so we can just avoid using the high resolution timer this time. + default: + println("runtime: NtCancelWaitCompletionPacket failed; errno=", errno) + throw("runtime: netpoll failed") + } + return signaled +} diff --git a/contrib/go/_std_1.22/src/runtime/nonwindows_stub.go b/contrib/go/_std_1.23/src/runtime/nonwindows_stub.go similarity index 75% rename from contrib/go/_std_1.22/src/runtime/nonwindows_stub.go rename to contrib/go/_std_1.23/src/runtime/nonwindows_stub.go index 033f026c4217..859ae48004ff 100644 --- a/contrib/go/_std_1.22/src/runtime/nonwindows_stub.go +++ b/contrib/go/_std_1.23/src/runtime/nonwindows_stub.go @@ -12,6 +12,8 @@ package runtime // timer precision to keep the timer error acceptable. const osRelaxMinNS = 0 +var haveHighResSleep = true + // osRelax is called by the scheduler when transitioning to and from // all Ps being idle. func osRelax(relax bool) {} @@ -19,3 +21,8 @@ func osRelax(relax bool) {} // enableWER is called by setTraceback("wer"). // Windows Error Reporting (WER) is only supported on Windows. func enableWER() {} + +// winlibcall is not implemented on non-Windows systems, +// but it is used in non-OS-specific parts of the runtime. +// Define it as an empty struct to avoid wasting stack space. +type winlibcall struct{} diff --git a/contrib/go/_std_1.22/src/runtime/os2_aix.go b/contrib/go/_std_1.23/src/runtime/os2_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_aix.go rename to contrib/go/_std_1.23/src/runtime/os2_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/os2_freebsd.go b/contrib/go/_std_1.23/src/runtime/os2_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_freebsd.go rename to contrib/go/_std_1.23/src/runtime/os2_freebsd.go diff --git a/contrib/go/_std_1.22/src/runtime/os2_openbsd.go b/contrib/go/_std_1.23/src/runtime/os2_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_openbsd.go rename to contrib/go/_std_1.23/src/runtime/os2_openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/os2_plan9.go b/contrib/go/_std_1.23/src/runtime/os2_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_plan9.go rename to contrib/go/_std_1.23/src/runtime/os2_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/os2_solaris.go b/contrib/go/_std_1.23/src/runtime/os2_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_solaris.go rename to contrib/go/_std_1.23/src/runtime/os2_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/os3_plan9.go b/contrib/go/_std_1.23/src/runtime/os3_plan9.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/os3_plan9.go rename to contrib/go/_std_1.23/src/runtime/os3_plan9.go index 8c9cbe28ec2f..dd1570561803 100644 --- a/contrib/go/_std_1.22/src/runtime/os3_plan9.go +++ b/contrib/go/_std_1.23/src/runtime/os3_plan9.go @@ -7,6 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" + "internal/stringslite" "unsafe" ) @@ -47,7 +48,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { // level by the program but will otherwise be ignored. flags = _SigNotify for sig, t = range sigtable { - if hasPrefix(notestr, t.name) { + if stringslite.HasPrefix(notestr, t.name) { flags = t.flags break } diff --git a/contrib/go/_std_1.22/src/runtime/os3_solaris.go b/contrib/go/_std_1.23/src/runtime/os3_solaris.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os3_solaris.go rename to contrib/go/_std_1.23/src/runtime/os3_solaris.go index 92daf13b1a2d..cf163a6bf401 100644 --- a/contrib/go/_std_1.22/src/runtime/os3_solaris.go +++ b/contrib/go/_std_1.23/src/runtime/os3_solaris.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_aix.go b/contrib/go/_std_1.23/src/runtime/os_aix.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os_aix.go rename to contrib/go/_std_1.23/src/runtime/os_aix.go index 3a5078a64c45..93464cb997f3 100644 --- a/contrib/go/_std_1.22/src/runtime/os_aix.go +++ b/contrib/go/_std_1.23/src/runtime/os_aix.go @@ -8,7 +8,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_android.go b/contrib/go/_std_1.23/src/runtime/os_android.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_android.go rename to contrib/go/_std_1.23/src/runtime/os_android.go diff --git a/contrib/go/_std_1.22/src/runtime/os_darwin.go b/contrib/go/_std_1.23/src/runtime/os_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_darwin.go rename to contrib/go/_std_1.23/src/runtime/os_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/os_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/os_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_dragonfly.go b/contrib/go/_std_1.23/src/runtime/os_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_dragonfly.go rename to contrib/go/_std_1.23/src/runtime/os_dragonfly.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd.go b/contrib/go/_std_1.23/src/runtime/os_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd2.go b/contrib/go/_std_1.23/src/runtime/os_freebsd2.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd2.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd2.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_amd64.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_arm.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_arm.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_arm64.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_noauxv.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_noauxv.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_noauxv.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_noauxv.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_illumos.go b/contrib/go/_std_1.23/src/runtime/os_illumos.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_illumos.go rename to contrib/go/_std_1.23/src/runtime/os_illumos.go diff --git a/contrib/go/_std_1.22/src/runtime/os_js.go b/contrib/go/_std_1.23/src/runtime/os_js.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_js.go rename to contrib/go/_std_1.23/src/runtime/os_js.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux.go b/contrib/go/_std_1.23/src/runtime/os_linux.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/os_linux.go rename to contrib/go/_std_1.23/src/runtime/os_linux.go index 0ba607fe1f18..e80d390e0d09 100644 --- a/contrib/go/_std_1.22/src/runtime/os_linux.go +++ b/contrib/go/_std_1.23/src/runtime/os_linux.go @@ -7,8 +7,8 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" - "runtime/internal/syscall" + "internal/runtime/atomic" + "internal/runtime/syscall" "unsafe" ) @@ -402,9 +402,9 @@ func unminit() { func mdestroy(mp *m) { } -//#ifdef GOARCH_386 -//#define sa_handler k_sa_handler -//#endif +// #ifdef GOARCH_386 +// #define sa_handler k_sa_handler +// #endif func sigreturn__sigaction() func sigtramp() // Called via C ABI @@ -879,8 +879,9 @@ func runPerThreadSyscall() { } const ( - _SI_USER = 0 - _SI_TKILL = -6 + _SI_USER = 0 + _SI_TKILL = -6 + _SYS_SECCOMP = 1 ) // sigFromUser reports whether the signal was sent because of a call @@ -891,3 +892,17 @@ func (c *sigctxt) sigFromUser() bool { code := int32(c.sigcode()) return code == _SI_USER || code == _SI_TKILL } + +// sigFromSeccomp reports whether the signal was sent from seccomp. +// +//go:nosplit +func (c *sigctxt) sigFromSeccomp() bool { + code := int32(c.sigcode()) + return code == _SYS_SECCOMP +} + +//go:nosplit +func mprotect(addr unsafe.Pointer, n uintptr, prot int32) (ret int32, errno int32) { + r, _, err := syscall.Syscall6(syscall.SYS_MPROTECT, uintptr(addr), n, uintptr(prot), 0, 0, 0) + return int32(r), int32(err) +} diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_arm.go b/contrib/go/_std_1.23/src/runtime/os_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_arm.go rename to contrib/go/_std_1.23/src/runtime/os_linux_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_arm64.go b/contrib/go/_std_1.23/src/runtime/os_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_be64.go b/contrib/go/_std_1.23/src/runtime/os_linux_be64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_be64.go rename to contrib/go/_std_1.23/src/runtime/os_linux_be64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_generic.go b/contrib/go/_std_1.23/src/runtime/os_linux_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_generic.go rename to contrib/go/_std_1.23/src/runtime/os_linux_generic.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_loong64.go b/contrib/go/_std_1.23/src/runtime/os_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_loong64.go rename to contrib/go/_std_1.23/src/runtime/os_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_mips64x.go b/contrib/go/_std_1.23/src/runtime/os_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_mips64x.go rename to contrib/go/_std_1.23/src/runtime/os_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_mipsx.go b/contrib/go/_std_1.23/src/runtime/os_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_mipsx.go rename to contrib/go/_std_1.23/src/runtime/os_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_noauxv.go b/contrib/go/_std_1.23/src/runtime/os_linux_noauxv.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_noauxv.go rename to contrib/go/_std_1.23/src/runtime/os_linux_noauxv.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_novdso.go b/contrib/go/_std_1.23/src/runtime/os_linux_novdso.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_novdso.go rename to contrib/go/_std_1.23/src/runtime/os_linux_novdso.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_ppc64x.go b/contrib/go/_std_1.23/src/runtime/os_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/os_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_riscv64.go b/contrib/go/_std_1.23/src/runtime/os_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_riscv64.go rename to contrib/go/_std_1.23/src/runtime/os_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_s390x.go b/contrib/go/_std_1.23/src/runtime/os_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_s390x.go rename to contrib/go/_std_1.23/src/runtime/os_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_x86.go b/contrib/go/_std_1.23/src/runtime/os_linux_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_x86.go rename to contrib/go/_std_1.23/src/runtime/os_linux_x86.go diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd.go b/contrib/go/_std_1.23/src/runtime/os_netbsd.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os_netbsd.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd.go index 8abb688aae37..735ace25adb3 100644 --- a/contrib/go/_std_1.22/src/runtime/os_netbsd.go +++ b/contrib/go/_std_1.23/src/runtime/os_netbsd.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd_386.go b/contrib/go/_std_1.23/src/runtime/os_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_netbsd_386.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/os_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_netbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd_arm.go b/contrib/go/_std_1.23/src/runtime/os_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_netbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/os_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_netbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_nonopenbsd.go b/contrib/go/_std_1.23/src/runtime/os_nonopenbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_nonopenbsd.go rename to contrib/go/_std_1.23/src/runtime/os_nonopenbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/os_only_solaris.go b/contrib/go/_std_1.23/src/runtime/os_only_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_only_solaris.go rename to contrib/go/_std_1.23/src/runtime/os_only_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd.go b/contrib/go/_std_1.23/src/runtime/os_openbsd.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os_openbsd.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd.go index 856979910a9f..9a21d6a8d052 100644 --- a/contrib/go/_std_1.22/src/runtime/os_openbsd.go +++ b/contrib/go/_std_1.23/src/runtime/os_openbsd.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_arm.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_libc.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_libc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_libc.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_libc.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_mips64.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_mips64.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_syscall.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_syscall.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_syscall.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_syscall1.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_syscall1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_syscall1.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_syscall1.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_syscall2.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_syscall2.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_syscall2.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_syscall2.go index 0b796ade43a6..072f53320dc5 100644 --- a/contrib/go/_std_1.22/src/runtime/os_openbsd_syscall2.go +++ b/contrib/go/_std_1.23/src/runtime/os_openbsd_syscall2.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_plan9.go b/contrib/go/_std_1.23/src/runtime/os_plan9.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/os_plan9.go rename to contrib/go/_std_1.23/src/runtime/os_plan9.go index 77446d09d3b5..2dbb42ad037d 100644 --- a/contrib/go/_std_1.22/src/runtime/os_plan9.go +++ b/contrib/go/_std_1.23/src/runtime/os_plan9.go @@ -6,7 +6,8 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" + "internal/stringslite" "unsafe" ) @@ -124,7 +125,7 @@ func indexNoFloat(s, t string) int { return 0 } for i := 0; i < len(s); i++ { - if s[i] == t[0] && hasPrefix(s[i:], t) { + if s[i] == t[0] && stringslite.HasPrefix(s[i:], t) { return i } } @@ -132,20 +133,20 @@ func indexNoFloat(s, t string) int { } func atolwhex(p string) int64 { - for hasPrefix(p, " ") || hasPrefix(p, "\t") { + for stringslite.HasPrefix(p, " ") || stringslite.HasPrefix(p, "\t") { p = p[1:] } neg := false - if hasPrefix(p, "-") || hasPrefix(p, "+") { + if stringslite.HasPrefix(p, "-") || stringslite.HasPrefix(p, "+") { neg = p[0] == '-' p = p[1:] - for hasPrefix(p, " ") || hasPrefix(p, "\t") { + for stringslite.HasPrefix(p, " ") || stringslite.HasPrefix(p, "\t") { p = p[1:] } } var n int64 switch { - case hasPrefix(p, "0x"), hasPrefix(p, "0X"): + case stringslite.HasPrefix(p, "0x"), stringslite.HasPrefix(p, "0X"): p = p[2:] for ; len(p) > 0; p = p[1:] { if '0' <= p[0] && p[0] <= '9' { @@ -158,7 +159,7 @@ func atolwhex(p string) int64 { break } } - case hasPrefix(p, "0"): + case stringslite.HasPrefix(p, "0"): for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] { n = n*8 + int64(p[0]-'0') } diff --git a/contrib/go/_std_1.22/src/runtime/os_plan9_arm.go b/contrib/go/_std_1.23/src/runtime/os_plan9_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_plan9_arm.go rename to contrib/go/_std_1.23/src/runtime/os_plan9_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_solaris.go b/contrib/go/_std_1.23/src/runtime/os_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_solaris.go rename to contrib/go/_std_1.23/src/runtime/os_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/os_unix.go b/contrib/go/_std_1.23/src/runtime/os_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_unix.go rename to contrib/go/_std_1.23/src/runtime/os_unix.go diff --git a/contrib/go/_std_1.23/src/runtime/os_unix_nonlinux.go b/contrib/go/_std_1.23/src/runtime/os_unix_nonlinux.go new file mode 100644 index 000000000000..0e8b61c3b11a --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/os_unix_nonlinux.go @@ -0,0 +1,22 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix && !linux + +package runtime + +// sigFromUser reports whether the signal was sent because of a call +// to kill. +// +//go:nosplit +func (c *sigctxt) sigFromUser() bool { + return c.sigcode() == _SI_USER +} + +// sigFromSeccomp reports whether the signal was sent from seccomp. +// +//go:nosplit +func (c *sigctxt) sigFromSeccomp() bool { + return false +} diff --git a/contrib/go/_std_1.22/src/runtime/os_wasip1.go b/contrib/go/_std_1.23/src/runtime/os_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_wasip1.go rename to contrib/go/_std_1.23/src/runtime/os_wasip1.go diff --git a/contrib/go/_std_1.22/src/runtime/os_wasm.go b/contrib/go/_std_1.23/src/runtime/os_wasm.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os_wasm.go rename to contrib/go/_std_1.23/src/runtime/os_wasm.go index ce260de67e5c..fbafc319b988 100644 --- a/contrib/go/_std_1.22/src/runtime/os_wasm.go +++ b/contrib/go/_std_1.23/src/runtime/os_wasm.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_windows.go b/contrib/go/_std_1.23/src/runtime/os_windows.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/os_windows.go rename to contrib/go/_std_1.23/src/runtime/os_windows.go index 6533b6400490..4aabc29644e6 100644 --- a/contrib/go/_std_1.22/src/runtime/os_windows.go +++ b/contrib/go/_std_1.23/src/runtime/os_windows.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -20,7 +20,6 @@ const ( //go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll" //go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll" -//go:cgo_import_dynamic runtime._CreateFileA CreateFileA%7 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll" @@ -44,6 +43,7 @@ const ( //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" //go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll" //go:cgo_import_dynamic runtime._QueryPerformanceCounter QueryPerformanceCounter%1 "kernel32.dll" +//go:cgo_import_dynamic runtime._QueryPerformanceFrequency QueryPerformanceFrequency%1 "kernel32.dll" //go:cgo_import_dynamic runtime._RaiseFailFastException RaiseFailFastException%3 "kernel32.dll" //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll" //go:cgo_import_dynamic runtime._RtlLookupFunctionEntry RtlLookupFunctionEntry%3 "kernel32.dll" @@ -78,7 +78,6 @@ var ( _AddVectoredExceptionHandler, _CloseHandle, _CreateEventA, - _CreateFileA, _CreateIoCompletionPort, _CreateThread, _CreateWaitableTimerA, @@ -102,6 +101,7 @@ var ( _LoadLibraryW, _PostQueuedCompletionStatus, _QueryPerformanceCounter, + _QueryPerformanceFrequency, _RaiseFailFastException, _ResumeThread, _RtlLookupFunctionEntry, @@ -133,13 +133,15 @@ var ( // Load ntdll.dll manually during startup, otherwise Mingw // links wrong printf function to cgo executable (see issue // 12030 for details). - _RtlGetCurrentPeb stdFunction - _RtlGetNtVersionNumbers stdFunction + _NtCreateWaitCompletionPacket stdFunction + _NtAssociateWaitCompletionPacket stdFunction + _NtCancelWaitCompletionPacket stdFunction + _RtlGetCurrentPeb stdFunction + _RtlGetVersion stdFunction // These are from non-kernel32.dll, so we prefer to LoadLibraryEx them. _timeBeginPeriod, _timeEndPeriod, - _WSAGetOverlappedResult, _ stdFunction ) @@ -148,7 +150,6 @@ var ( ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} - ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} ) // Function to be called by windows CreateThread @@ -165,7 +166,9 @@ type mOS struct { waitsema uintptr // semaphore for parking on locks resumesema uintptr // semaphore to indicate suspend/resume - highResTimer uintptr // high resolution timer handle used in usleep + highResTimer uintptr // high resolution timer handle used in usleep + waitIocpTimer uintptr // high resolution timer handle used in netpoll + waitIocpHandle uintptr // wait completion handle used in netpoll // preemptExtLock synchronizes preemptM with entry/exit from // external C code. @@ -213,6 +216,8 @@ func asmstdcall(fn unsafe.Pointer) var asmstdcallAddr unsafe.Pointer +type winlibcall libcall + func windowsFindfunc(lib uintptr, name []byte) stdFunction { if name[len(name)-1] != 0 { throw("usage") @@ -243,6 +248,20 @@ func windowsLoadSystemLib(name []uint16) uintptr { return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) } +//go:linkname windows_QueryPerformanceCounter internal/syscall/windows.QueryPerformanceCounter +func windows_QueryPerformanceCounter() int64 { + var counter int64 + stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter))) + return counter +} + +//go:linkname windows_QueryPerformanceFrequency internal/syscall/windows.QueryPerformanceFrequency +func windows_QueryPerformanceFrequency() int64 { + var frequency int64 + stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&frequency))) + return frequency +} + func loadOptionalSyscalls() { bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:]) if bcryptPrimitives == 0 { @@ -254,27 +273,20 @@ func loadOptionalSyscalls() { if n32 == 0 { throw("ntdll.dll not found") } - _RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000")) - _RtlGetNtVersionNumbers = windowsFindfunc(n32, []byte("RtlGetNtVersionNumbers\000")) - - m32 := windowsLoadSystemLib(winmmdll[:]) - if m32 == 0 { - throw("winmm.dll not found") - } - _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000")) - _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000")) - if _timeBeginPeriod == nil || _timeEndPeriod == nil { - throw("timeBegin/EndPeriod not found") - } - - ws232 := windowsLoadSystemLib(ws2_32dll[:]) - if ws232 == 0 { - throw("ws2_32.dll not found") - } - _WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000")) - if _WSAGetOverlappedResult == nil { - throw("WSAGetOverlappedResult not found") + _NtCreateWaitCompletionPacket = windowsFindfunc(n32, []byte("NtCreateWaitCompletionPacket\000")) + if _NtCreateWaitCompletionPacket != nil { + // These functions should exists if NtCreateWaitCompletionPacket exists. + _NtAssociateWaitCompletionPacket = windowsFindfunc(n32, []byte("NtAssociateWaitCompletionPacket\000")) + if _NtAssociateWaitCompletionPacket == nil { + throw("NtCreateWaitCompletionPacket exists but NtAssociateWaitCompletionPacket does not") + } + _NtCancelWaitCompletionPacket = windowsFindfunc(n32, []byte("NtCancelWaitCompletionPacket\000")) + if _NtCancelWaitCompletionPacket == nil { + throw("NtCreateWaitCompletionPacket exists but NtCancelWaitCompletionPacket does not") + } } + _RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000")) + _RtlGetVersion = windowsFindfunc(n32, []byte("RtlGetVersion\000")) } func monitorSuspendResume() { @@ -310,21 +322,6 @@ func monitorSuspendResume() { uintptr(unsafe.Pointer(¶ms)), uintptr(unsafe.Pointer(&handle))) } -//go:nosplit -func getLoadLibrary() uintptr { - return uintptr(unsafe.Pointer(_LoadLibraryW)) -} - -//go:nosplit -func getLoadLibraryEx() uintptr { - return uintptr(unsafe.Pointer(_LoadLibraryExW)) -} - -//go:nosplit -func getGetProcAddress() uintptr { - return uintptr(unsafe.Pointer(_GetProcAddress)) -} - func getproccount() int32 { var mask, sysmask uintptr ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask))) @@ -397,6 +394,13 @@ func osRelax(relax bool) uint32 { // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available. var haveHighResTimer = false +// haveHighResSleep indicates that NtCreateWaitCompletionPacket +// exists and haveHighResTimer is true. +// NtCreateWaitCompletionPacket has been available since Windows 10, +// but has just been publicly documented, so some platforms, like Wine, +// doesn't support it yet. +var haveHighResSleep = false + // createHighResTimer calls CreateWaitableTimerEx with // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag to create high // resolution timer. createHighResTimer returns new timer @@ -420,78 +424,50 @@ func initHighResTimer() { h := createHighResTimer() if h != 0 { haveHighResTimer = true + haveHighResSleep = _NtCreateWaitCompletionPacket != nil stdcall1(_CloseHandle, h) + } else { + // Only load winmm.dll if we need it. + // This avoids a dependency on winmm.dll for Go programs + // that run on new Windows versions. + m32 := windowsLoadSystemLib(winmmdll[:]) + if m32 == 0 { + print("runtime: LoadLibraryExW failed; errno=", getlasterror(), "\n") + throw("winmm.dll not found") + } + _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000")) + _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000")) + if _timeBeginPeriod == nil || _timeEndPeriod == nil { + print("runtime: GetProcAddress failed; errno=", getlasterror(), "\n") + throw("timeBegin/EndPeriod not found") + } } } -//go:linkname canUseLongPaths os.canUseLongPaths +//go:linkname canUseLongPaths internal/syscall/windows.CanUseLongPaths var canUseLongPaths bool -// We want this to be large enough to hold the contents of sysDirectory, *plus* -// a slash and another component that itself is greater than MAX_PATH. -var longFileName [(_MAX_PATH+1)*2 + 1]byte - -// initLongPathSupport initializes the canUseLongPaths variable, which is -// linked into os.canUseLongPaths for determining whether or not long paths -// need to be fixed up. In the best case, this function is running on newer -// Windows 10 builds, which have a bit field member of the PEB called -// "IsLongPathAwareProcess." When this is set, we don't need to go through the -// error-prone fixup function in order to access long paths. So this init -// function first checks the Windows build number, sets the flag, and then -// tests to see if it's actually working. If everything checks out, then -// canUseLongPaths is set to true, and later when called, os.fixLongPath -// returns early without doing work. +// initLongPathSupport enables long path support. func initLongPathSupport() { const ( IsLongPathAwareProcess = 0x80 PebBitFieldOffset = 3 - OPEN_EXISTING = 3 - ERROR_PATH_NOT_FOUND = 3 ) // Check that we're ≥ 10.0.15063. - var maj, min, build uint32 - stdcall3(_RtlGetNtVersionNumbers, uintptr(unsafe.Pointer(&maj)), uintptr(unsafe.Pointer(&min)), uintptr(unsafe.Pointer(&build))) - if maj < 10 || (maj == 10 && min == 0 && build&0xffff < 15063) { + info := _OSVERSIONINFOW{} + info.osVersionInfoSize = uint32(unsafe.Sizeof(info)) + stdcall1(_RtlGetVersion, uintptr(unsafe.Pointer(&info))) + if info.majorVersion < 10 || (info.majorVersion == 10 && info.minorVersion == 0 && info.buildNumber < 15063) { return } // Set the IsLongPathAwareProcess flag of the PEB's bit field. + // This flag is not documented, but it's known to be used + // by Windows to enable long path support. bitField := (*byte)(unsafe.Pointer(stdcall0(_RtlGetCurrentPeb) + PebBitFieldOffset)) - originalBitField := *bitField *bitField |= IsLongPathAwareProcess - // Check that this actually has an effect, by constructing a large file - // path and seeing whether we get ERROR_PATH_NOT_FOUND, rather than - // some other error, which would indicate the path is too long, and - // hence long path support is not successful. This whole section is NOT - // strictly necessary, but is a nice validity check for the near to - // medium term, when this functionality is still relatively new in - // Windows. - targ := longFileName[len(longFileName)-33 : len(longFileName)-1] - if readRandom(targ) != len(targ) { - readTimeRandom(targ) - } - start := copy(longFileName[:], sysDirectory[:sysDirectoryLen]) - const dig = "0123456789abcdef" - for i := 0; i < 32; i++ { - longFileName[start+i*2] = dig[longFileName[len(longFileName)-33+i]>>4] - longFileName[start+i*2+1] = dig[longFileName[len(longFileName)-33+i]&0xf] - } - start += 64 - for i := start; i < len(longFileName)-1; i++ { - longFileName[i] = 'A' - } - stdcall7(_CreateFileA, uintptr(unsafe.Pointer(&longFileName[0])), 0, 0, 0, OPEN_EXISTING, 0, 0) - // The ERROR_PATH_NOT_FOUND error value is distinct from - // ERROR_FILE_NOT_FOUND or ERROR_INVALID_NAME, the latter of which we - // expect here due to the final component being too long. - if getlasterror() == ERROR_PATH_NOT_FOUND { - *bitField = originalBitField - println("runtime: warning: IsLongPathAwareProcess failed to enable long paths; proceeding in fixup mode") - return - } - canUseLongPaths = true } @@ -850,7 +826,7 @@ func sigblock(exiting bool) { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, cannot allocate memory. +// Called on the new thread, cannot allocate Go memory. func minit() { var thandle uintptr if stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 { @@ -871,6 +847,19 @@ func minit() { throw("CreateWaitableTimerEx when creating timer failed") } } + if mp.waitIocpHandle == 0 && haveHighResSleep { + mp.waitIocpTimer = createHighResTimer() + if mp.waitIocpTimer == 0 { + print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n") + throw("CreateWaitableTimerEx when creating timer failed") + } + const GENERIC_ALL = 0x10000000 + errno := stdcall3(_NtCreateWaitCompletionPacket, uintptr(unsafe.Pointer(&mp.waitIocpHandle)), GENERIC_ALL, 0) + if mp.waitIocpHandle == 0 { + print("runtime: NtCreateWaitCompletionPacket failed; errno=", errno, "\n") + throw("NtCreateWaitCompletionPacket failed") + } + } unlock(&mp.threadLock) // Query the true stack base from the OS. Currently we're @@ -925,6 +914,14 @@ func mdestroy(mp *m) { stdcall1(_CloseHandle, mp.highResTimer) mp.highResTimer = 0 } + if mp.waitIocpTimer != 0 { + stdcall1(_CloseHandle, mp.waitIocpTimer) + mp.waitIocpTimer = 0 + } + if mp.waitIocpHandle != 0 { + stdcall1(_CloseHandle, mp.waitIocpHandle) + mp.waitIocpHandle = 0 + } if mp.waitsema != 0 { stdcall1(_CloseHandle, mp.waitsema) mp.waitsema = 0 diff --git a/contrib/go/_std_1.22/src/runtime/os_windows_arm.go b/contrib/go/_std_1.23/src/runtime/os_windows_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_windows_arm.go rename to contrib/go/_std_1.23/src/runtime/os_windows_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_windows_arm64.go b/contrib/go/_std_1.23/src/runtime/os_windows_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_windows_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_windows_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/panic.go b/contrib/go/_std_1.23/src/runtime/panic.go similarity index 92% rename from contrib/go/_std_1.22/src/runtime/panic.go rename to contrib/go/_std_1.23/src/runtime/panic.go index 36d658aa4c9d..12bbf96a2136 100644 --- a/contrib/go/_std_1.22/src/runtime/panic.go +++ b/contrib/go/_std_1.23/src/runtime/panic.go @@ -7,7 +7,8 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" + "internal/stringslite" "runtime/internal/sys" "unsafe" ) @@ -53,7 +54,7 @@ const ( // pc should be the program counter of the compiler-generated code that // triggered this panic. func panicCheck1(pc uintptr, msg string) { - if goarch.IsWasm == 0 && hasPrefix(funcname(findfunc(pc)), "runtime.") { + if goarch.IsWasm == 0 && stringslite.HasPrefix(funcname(findfunc(pc)), "runtime.") { // Note: wasm can't tail call, so we can't get the original caller's pc. throw(msg) } @@ -296,11 +297,24 @@ func deferproc(fn func()) { // been set and must not be clobbered. } -var rangeExitError = error(errorString("range function continued iteration after exit")) +var rangeDoneError = error(errorString("range function continued iteration after function for loop body returned false")) +var rangePanicError = error(errorString("range function continued iteration after loop body panic")) +var rangeExhaustedError = error(errorString("range function continued iteration after whole loop exit")) +var rangeMissingPanicError = error(errorString("range function recovered a loop body panic and did not resume panicking")) //go:noinline -func panicrangeexit() { - panic(rangeExitError) +func panicrangestate(state int) { + switch abi.RF_State(state) { + case abi.RF_DONE: + panic(rangeDoneError) + case abi.RF_PANIC: + panic(rangePanicError) + case abi.RF_EXHAUSTED: + panic(rangeExhaustedError) + case abi.RF_MISSING_PANIC: + panic(rangeMissingPanicError) + } + throw("unexpected state passed to panicrangestate") } // deferrangefunc is called by functions that are about to @@ -377,10 +391,16 @@ func deferrangefunc() any { throw("defer on system stack") } + fn := findfunc(getcallerpc()) + if fn.deferreturn == 0 { + throw("no deferreturn") + } + d := newdefer() d.link = gp._defer gp._defer = d - d.pc = getcallerpc() + + d.pc = fn.entry() + uintptr(fn.deferreturn) // We must not be preempted between calling getcallersp and // storing it to d.sp because getcallersp's result is a // uintptr stack pointer. @@ -420,17 +440,18 @@ func deferprocat(fn func(), frame any) { return0() } -// deferconvert converts a rangefunc defer list into an ordinary list. +// deferconvert converts the rangefunc defer list of d0 into an ordinary list +// following d0. // See the doc comment for deferrangefunc for details. -func deferconvert(d *_defer) *_defer { - head := d.head +func deferconvert(d0 *_defer) { + head := d0.head if raceenabled { racereadpc(unsafe.Pointer(head), getcallerpc(), abi.FuncPCABIInternal(deferconvert)) } - tail := d.link - d.rangefunc = false - d0 := d + tail := d0.link + d0.rangefunc = false + var d *_defer for { d = head.Load() if head.CompareAndSwap(d, badDefer()) { @@ -438,8 +459,7 @@ func deferconvert(d *_defer) *_defer { } } if d == nil { - freedefer(d0) - return tail + return } for d1 := d; ; d1 = d1.link { d1.sp = d0.sp @@ -449,8 +469,8 @@ func deferconvert(d *_defer) *_defer { break } } - freedefer(d0) - return d + d0.link = d + return } // deferprocStack queues a new deferred function with a defer record on the stack. @@ -528,22 +548,18 @@ func newdefer() *_defer { return d } -// Free the given defer. -// The defer cannot be used after this call. -// -// This is nosplit because the incoming defer is in a perilous state. -// It's not on any defer list, so stack copying won't adjust stack -// pointers in it (namely, d.link). Hence, if we were to copy the -// stack, d could then contain a stale pointer. -// -//go:nosplit -func freedefer(d *_defer) { +// popDefer pops the head of gp's defer list and frees it. +func popDefer(gp *g) { + d := gp._defer + d.fn = nil // Can in theory point to the stack + // We must not copy the stack between the updating gp._defer and setting + // d.link to nil. Between these two steps, d is not on any defer list, so + // stack copying won't adjust stack pointers in it (namely, d.link). Hence, + // if we were to copy the stack, d could then contain a stale pointer. + gp._defer = d.link d.link = nil // After this point we can copy the stack. - if d.fn != nil { - freedeferfn() - } if !d.heap { return } @@ -579,13 +595,6 @@ func freedefer(d *_defer) { mp, pp = nil, nil } -// Separate function so that it can split stack. -// Windows otherwise runs out of stack space. -func freedeferfn() { - // fn must be cleared before d is unlinked from gp. - throw("freedefer with d.fn != nil") -} - // deferreturn runs deferred functions for the caller's frame. // The compiler inserts a call to this at the end of any // function which calls defer. @@ -667,7 +676,7 @@ func printpanics(p *_panic) { return } print("panic: ") - printany(p.arg) + printpanicval(p.arg) if p.recovered { print(" [recovered]") } @@ -717,6 +726,18 @@ func (*PanicNilError) RuntimeError() {} var panicnil = &godebugInc{name: "panicnil"} // The implementation of the predeclared function panic. +// The compiler emits calls to this function. +// +// gopanic should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - go.undefinedlabs.com/scopeagent +// - github.com/goplus/igop +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname gopanic func gopanic(e any) { if e == nil { if debug.panicnil.Load() != 1 { @@ -729,20 +750,20 @@ func gopanic(e any) { gp := getg() if gp.m.curg != gp { print("panic: ") - printany(e) + printpanicval(e) print("\n") throw("panic on system stack") } if gp.m.mallocing != 0 { print("panic: ") - printany(e) + printpanicval(e) print("\n") throw("panic during malloc") } if gp.m.preemptoff != "" { print("panic: ") - printany(e) + printpanicval(e) print("\n") print("preempt off reason: ") print(gp.m.preemptoff) @@ -751,7 +772,7 @@ func gopanic(e any) { } if gp.m.locks != 0 { print("panic: ") - printany(e) + printpanicval(e) print("\n") throw("panic holding locks") } @@ -770,6 +791,16 @@ func gopanic(e any) { fn() } + // If we're tracing, flush the current generation to make the trace more + // readable. + // + // TODO(aktau): Handle a panic from within traceAdvance more gracefully. + // Currently it would hang. Not handled now because it is very unlikely, and + // already unrecoverable. + if traceEnabled() { + traceAdvance(false) + } + // ran out of deferred calls - old-school panic now // Because it is unsafe to call arbitrary user code after freezing // the world, we call preprintpanics to invoke all necessary Error @@ -876,12 +907,12 @@ func (p *_panic) nextDefer() (func(), bool) { Recheck: if d := gp._defer; d != nil && d.sp == uintptr(p.sp) { if d.rangefunc { - gp._defer = deferconvert(d) + deferconvert(d) + popDefer(gp) goto Recheck } fn := d.fn - d.fn = nil // TODO(mdempsky): Instead of having each deferproc call have // its own "deferreturn(); return" sequence, we should just make @@ -889,8 +920,7 @@ func (p *_panic) nextDefer() (func(), bool) { p.retpc = d.pc // Unlink and free. - gp._defer = d.link - freedefer(d) + popDefer(gp) return fn, true } @@ -1012,12 +1042,32 @@ func sync_fatal(s string) { // throw should be used for runtime-internal fatal errors where Go itself, // rather than user code, may be at fault for the failure. // +// NOTE: temporarily marked "go:noinline" pending investigation/fix of +// issue #67274, so as to fix longtest builders. +// +// throw should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cockroachdb/pebble +// - github.com/dgraph-io/ristretto +// - github.com/outcaste-io/ristretto +// - github.com/pingcap/br +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname throw //go:nosplit func throw(s string) { // Everything throw does should be recursively nosplit so it // can be called even when it's unsafe to grow the stack. systemstack(func() { - print("fatal error: ", s, "\n") + print("fatal error: ") + printindented(s) // logically printpanicval(s), but avoids convTstring write barrier + print("\n") }) fatalthrow(throwTypeRuntime) @@ -1036,7 +1086,9 @@ func fatal(s string) { // Everything fatal does should be recursively nosplit so it // can be called even when it's unsafe to grow the stack. systemstack(func() { - print("fatal error: ", s, "\n") + print("fatal error: ") + printindented(s) // logically printpanicval(s), but avoids convTstring write barrier + print("\n") }) fatalthrow(throwTypeUser) @@ -1169,6 +1221,8 @@ func recovery(gp *g) { // only gets us to the caller's fp. gp.sched.bp = sp - goarch.PtrSize } + // The value in ret is delivered IN A REGISTER, even if there is a + // stack ABI. gp.sched.ret = 1 gogo(&gp.sched) } diff --git a/contrib/go/_std_1.22/src/runtime/panic32.go b/contrib/go/_std_1.23/src/runtime/panic32.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/panic32.go rename to contrib/go/_std_1.23/src/runtime/panic32.go diff --git a/contrib/go/_std_1.22/src/runtime/pinner.go b/contrib/go/_std_1.23/src/runtime/pinner.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/pinner.go rename to contrib/go/_std_1.23/src/runtime/pinner.go index 1ede1113eecf..7a9c3815803b 100644 --- a/contrib/go/_std_1.22/src/runtime/pinner.go +++ b/contrib/go/_std_1.23/src/runtime/pinner.go @@ -5,7 +5,8 @@ package runtime import ( - "runtime/internal/atomic" + "internal/abi" + "internal/runtime/atomic" "unsafe" ) @@ -107,7 +108,7 @@ func pinnerGetPtr(i *any) unsafe.Pointer { if etyp == nil { panic(errorString("runtime.Pinner: argument is nil")) } - if kind := etyp.Kind_ & kindMask; kind != kindPtr && kind != kindUnsafePointer { + if kind := etyp.Kind_ & abi.KindMask; kind != abi.Pointer && kind != abi.UnsafePointer { panic(errorString("runtime.Pinner: argument is not a pointer: " + toRType(etyp).string())) } if inUserArenaChunk(uintptr(e.data)) { @@ -271,7 +272,7 @@ func (s *mspan) pinnerBitSize() uintptr { } // newPinnerBits returns a pointer to 8 byte aligned bytes to be used for this -// span's pinner bits. newPinneBits is used to mark objects that are pinned. +// span's pinner bits. newPinnerBits is used to mark objects that are pinned. // They are copied when the span is swept. func (s *mspan) newPinnerBits() *pinnerBits { return (*pinnerBits)(newMarkBits(uintptr(s.nelems) * 2)) diff --git a/contrib/go/_std_1.22/src/runtime/plugin.go b/contrib/go/_std_1.23/src/runtime/plugin.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/plugin.go rename to contrib/go/_std_1.23/src/runtime/plugin.go index 40dfefde1701..4b6821b1fbbc 100644 --- a/contrib/go/_std_1.22/src/runtime/plugin.go +++ b/contrib/go/_std_1.23/src/runtime/plugin.go @@ -4,7 +4,10 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) //go:linkname plugin_lastmoduleinit plugin.lastmoduleinit func plugin_lastmoduleinit() (path string, syms map[string]any, initTasks []*initTask, errstr string) { @@ -85,7 +88,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]any, initTasks []*ini (*valp)[0] = unsafe.Pointer(t) name := symName.Name() - if t.Kind_&kindMask == kindFunc { + if t.Kind_&abi.KindMask == abi.Func { name = "." + name } syms[name] = val diff --git a/contrib/go/_std_1.22/src/runtime/pprof/defs_darwin.go b/contrib/go/_std_1.23/src/runtime/pprof/defs_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/defs_darwin.go rename to contrib/go/_std_1.23/src/runtime/pprof/defs_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/defs_darwin_amd64.go b/contrib/go/_std_1.23/src/runtime/pprof/defs_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/defs_darwin_amd64.go rename to contrib/go/_std_1.23/src/runtime/pprof/defs_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/defs_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/pprof/defs_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/defs_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/pprof/defs_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/elf.go b/contrib/go/_std_1.23/src/runtime/pprof/elf.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/elf.go rename to contrib/go/_std_1.23/src/runtime/pprof/elf.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/label.go b/contrib/go/_std_1.23/src/runtime/pprof/label.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/pprof/label.go rename to contrib/go/_std_1.23/src/runtime/pprof/label.go index 3684ae34e51c..41eece2f74c0 100644 --- a/contrib/go/_std_1.22/src/runtime/pprof/label.go +++ b/contrib/go/_std_1.23/src/runtime/pprof/label.go @@ -7,7 +7,7 @@ package pprof import ( "context" "fmt" - "sort" + "slices" "strings" ) @@ -49,7 +49,7 @@ func (l *labelMap) String() string { keyVals = append(keyVals, fmt.Sprintf("%q:%q", k, v)) } - sort.Strings(keyVals) + slices.Sort(keyVals) return "{" + strings.Join(keyVals, ", ") + "}" } diff --git a/contrib/go/_std_1.22/src/runtime/pprof/map.go b/contrib/go/_std_1.23/src/runtime/pprof/map.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/map.go rename to contrib/go/_std_1.23/src/runtime/pprof/map.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pe.go b/contrib/go/_std_1.23/src/runtime/pprof/pe.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/pe.go rename to contrib/go/_std_1.23/src/runtime/pprof/pe.go diff --git a/contrib/go/_std_1.23/src/runtime/pprof/pprof.go b/contrib/go/_std_1.23/src/runtime/pprof/pprof.go new file mode 100644 index 000000000000..4b7a9f63c650 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/pprof/pprof.go @@ -0,0 +1,996 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package pprof writes runtime profiling data in the format expected +// by the pprof visualization tool. +// +// # Profiling a Go program +// +// The first step to profiling a Go program is to enable profiling. +// Support for profiling benchmarks built with the standard testing +// package is built into go test. For example, the following command +// runs benchmarks in the current directory and writes the CPU and +// memory profiles to cpu.prof and mem.prof: +// +// go test -cpuprofile cpu.prof -memprofile mem.prof -bench . +// +// To add equivalent profiling support to a standalone program, add +// code like the following to your main function: +// +// var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") +// var memprofile = flag.String("memprofile", "", "write memory profile to `file`") +// +// func main() { +// flag.Parse() +// if *cpuprofile != "" { +// f, err := os.Create(*cpuprofile) +// if err != nil { +// log.Fatal("could not create CPU profile: ", err) +// } +// defer f.Close() // error handling omitted for example +// if err := pprof.StartCPUProfile(f); err != nil { +// log.Fatal("could not start CPU profile: ", err) +// } +// defer pprof.StopCPUProfile() +// } +// +// // ... rest of the program ... +// +// if *memprofile != "" { +// f, err := os.Create(*memprofile) +// if err != nil { +// log.Fatal("could not create memory profile: ", err) +// } +// defer f.Close() // error handling omitted for example +// runtime.GC() // get up-to-date statistics +// if err := pprof.WriteHeapProfile(f); err != nil { +// log.Fatal("could not write memory profile: ", err) +// } +// } +// } +// +// There is also a standard HTTP interface to profiling data. Adding +// the following line will install handlers under the /debug/pprof/ +// URL to download live profiles: +// +// import _ "net/http/pprof" +// +// See the net/http/pprof package for more details. +// +// Profiles can then be visualized with the pprof tool: +// +// go tool pprof cpu.prof +// +// There are many commands available from the pprof command line. +// Commonly used commands include "top", which prints a summary of the +// top program hot-spots, and "web", which opens an interactive graph +// of hot-spots and their call graphs. Use "help" for information on +// all pprof commands. +// +// For more information about pprof, see +// https://github.com/google/pprof/blob/main/doc/README.md. +package pprof + +import ( + "bufio" + "cmp" + "fmt" + "internal/abi" + "internal/profilerecord" + "io" + "runtime" + "slices" + "sort" + "strings" + "sync" + "text/tabwriter" + "time" + "unsafe" +) + +// BUG(rsc): Profiles are only as good as the kernel support used to generate them. +// See https://golang.org/issue/13841 for details about known problems. + +// A Profile is a collection of stack traces showing the call sequences +// that led to instances of a particular event, such as allocation. +// Packages can create and maintain their own profiles; the most common +// use is for tracking resources that must be explicitly closed, such as files +// or network connections. +// +// A Profile's methods can be called from multiple goroutines simultaneously. +// +// Each Profile has a unique name. A few profiles are predefined: +// +// goroutine - stack traces of all current goroutines +// heap - a sampling of memory allocations of live objects +// allocs - a sampling of all past memory allocations +// threadcreate - stack traces that led to the creation of new OS threads +// block - stack traces that led to blocking on synchronization primitives +// mutex - stack traces of holders of contended mutexes +// +// These predefined profiles maintain themselves and panic on an explicit +// [Profile.Add] or [Profile.Remove] method call. +// +// The CPU profile is not available as a Profile. It has a special API, +// the [StartCPUProfile] and [StopCPUProfile] functions, because it streams +// output to a writer during profiling. +// +// # Heap profile +// +// The heap profile reports statistics as of the most recently completed +// garbage collection; it elides more recent allocation to avoid skewing +// the profile away from live data and toward garbage. +// If there has been no garbage collection at all, the heap profile reports +// all known allocations. This exception helps mainly in programs running +// without garbage collection enabled, usually for debugging purposes. +// +// The heap profile tracks both the allocation sites for all live objects in +// the application memory and for all objects allocated since the program start. +// Pprof's -inuse_space, -inuse_objects, -alloc_space, and -alloc_objects +// flags select which to display, defaulting to -inuse_space (live objects, +// scaled by size). +// +// # Allocs profile +// +// The allocs profile is the same as the heap profile but changes the default +// pprof display to -alloc_space, the total number of bytes allocated since +// the program began (including garbage-collected bytes). +// +// # Block profile +// +// The block profile tracks time spent blocked on synchronization primitives, +// such as [sync.Mutex], [sync.RWMutex], [sync.WaitGroup], [sync.Cond], and +// channel send/receive/select. +// +// Stack traces correspond to the location that blocked (for example, +// [sync.Mutex.Lock]). +// +// Sample values correspond to cumulative time spent blocked at that stack +// trace, subject to time-based sampling specified by +// [runtime.SetBlockProfileRate]. +// +// # Mutex profile +// +// The mutex profile tracks contention on mutexes, such as [sync.Mutex], +// [sync.RWMutex], and runtime-internal locks. +// +// Stack traces correspond to the end of the critical section causing +// contention. For example, a lock held for a long time while other goroutines +// are waiting to acquire the lock will report contention when the lock is +// finally unlocked (that is, at [sync.Mutex.Unlock]). +// +// Sample values correspond to the approximate cumulative time other goroutines +// spent blocked waiting for the lock, subject to event-based sampling +// specified by [runtime.SetMutexProfileFraction]. For example, if a caller +// holds a lock for 1s while 5 other goroutines are waiting for the entire +// second to acquire the lock, its unlock call stack will report 5s of +// contention. +// +// Runtime-internal locks are always reported at the location +// "runtime._LostContendedRuntimeLock". More detailed stack traces for +// runtime-internal locks can be obtained by setting +// `GODEBUG=runtimecontentionstacks=1` (see package [runtime] docs for +// caveats). +type Profile struct { + name string + mu sync.Mutex + m map[any][]uintptr + count func() int + write func(io.Writer, int) error +} + +// profiles records all registered profiles. +var profiles struct { + mu sync.Mutex + m map[string]*Profile +} + +var goroutineProfile = &Profile{ + name: "goroutine", + count: countGoroutine, + write: writeGoroutine, +} + +var threadcreateProfile = &Profile{ + name: "threadcreate", + count: countThreadCreate, + write: writeThreadCreate, +} + +var heapProfile = &Profile{ + name: "heap", + count: countHeap, + write: writeHeap, +} + +var allocsProfile = &Profile{ + name: "allocs", + count: countHeap, // identical to heap profile + write: writeAlloc, +} + +var blockProfile = &Profile{ + name: "block", + count: countBlock, + write: writeBlock, +} + +var mutexProfile = &Profile{ + name: "mutex", + count: countMutex, + write: writeMutex, +} + +func lockProfiles() { + profiles.mu.Lock() + if profiles.m == nil { + // Initial built-in profiles. + profiles.m = map[string]*Profile{ + "goroutine": goroutineProfile, + "threadcreate": threadcreateProfile, + "heap": heapProfile, + "allocs": allocsProfile, + "block": blockProfile, + "mutex": mutexProfile, + } + } +} + +func unlockProfiles() { + profiles.mu.Unlock() +} + +// NewProfile creates a new profile with the given name. +// If a profile with that name already exists, NewProfile panics. +// The convention is to use a 'import/path.' prefix to create +// separate name spaces for each package. +// For compatibility with various tools that read pprof data, +// profile names should not contain spaces. +func NewProfile(name string) *Profile { + lockProfiles() + defer unlockProfiles() + if name == "" { + panic("pprof: NewProfile with empty name") + } + if profiles.m[name] != nil { + panic("pprof: NewProfile name already in use: " + name) + } + p := &Profile{ + name: name, + m: map[any][]uintptr{}, + } + profiles.m[name] = p + return p +} + +// Lookup returns the profile with the given name, or nil if no such profile exists. +func Lookup(name string) *Profile { + lockProfiles() + defer unlockProfiles() + return profiles.m[name] +} + +// Profiles returns a slice of all the known profiles, sorted by name. +func Profiles() []*Profile { + lockProfiles() + defer unlockProfiles() + + all := make([]*Profile, 0, len(profiles.m)) + for _, p := range profiles.m { + all = append(all, p) + } + + slices.SortFunc(all, func(a, b *Profile) int { + return strings.Compare(a.name, b.name) + }) + return all +} + +// Name returns this profile's name, which can be passed to [Lookup] to reobtain the profile. +func (p *Profile) Name() string { + return p.name +} + +// Count returns the number of execution stacks currently in the profile. +func (p *Profile) Count() int { + p.mu.Lock() + defer p.mu.Unlock() + if p.count != nil { + return p.count() + } + return len(p.m) +} + +// Add adds the current execution stack to the profile, associated with value. +// Add stores value in an internal map, so value must be suitable for use as +// a map key and will not be garbage collected until the corresponding +// call to [Profile.Remove]. Add panics if the profile already contains a stack for value. +// +// The skip parameter has the same meaning as [runtime.Caller]'s skip +// and controls where the stack trace begins. Passing skip=0 begins the +// trace in the function calling Add. For example, given this +// execution stack: +// +// Add +// called from rpc.NewClient +// called from mypkg.Run +// called from main.main +// +// Passing skip=0 begins the stack trace at the call to Add inside rpc.NewClient. +// Passing skip=1 begins the stack trace at the call to NewClient inside mypkg.Run. +func (p *Profile) Add(value any, skip int) { + if p.name == "" { + panic("pprof: use of uninitialized Profile") + } + if p.write != nil { + panic("pprof: Add called on built-in Profile " + p.name) + } + + stk := make([]uintptr, 32) + n := runtime.Callers(skip+1, stk[:]) + stk = stk[:n] + if len(stk) == 0 { + // The value for skip is too large, and there's no stack trace to record. + stk = []uintptr{abi.FuncPCABIInternal(lostProfileEvent)} + } + + p.mu.Lock() + defer p.mu.Unlock() + if p.m[value] != nil { + panic("pprof: Profile.Add of duplicate value") + } + p.m[value] = stk +} + +// Remove removes the execution stack associated with value from the profile. +// It is a no-op if the value is not in the profile. +func (p *Profile) Remove(value any) { + p.mu.Lock() + defer p.mu.Unlock() + delete(p.m, value) +} + +// WriteTo writes a pprof-formatted snapshot of the profile to w. +// If a write to w returns an error, WriteTo returns that error. +// Otherwise, WriteTo returns nil. +// +// The debug parameter enables additional output. +// Passing debug=0 writes the gzip-compressed protocol buffer described +// in https://github.com/google/pprof/tree/main/proto#overview. +// Passing debug=1 writes the legacy text format with comments +// translating addresses to function names and line numbers, so that a +// programmer can read the profile without tools. +// +// The predefined profiles may assign meaning to other debug values; +// for example, when printing the "goroutine" profile, debug=2 means to +// print the goroutine stacks in the same form that a Go program uses +// when dying due to an unrecovered panic. +func (p *Profile) WriteTo(w io.Writer, debug int) error { + if p.name == "" { + panic("pprof: use of zero Profile") + } + if p.write != nil { + return p.write(w, debug) + } + + // Obtain consistent snapshot under lock; then process without lock. + p.mu.Lock() + all := make([][]uintptr, 0, len(p.m)) + for _, stk := range p.m { + all = append(all, stk) + } + p.mu.Unlock() + + // Map order is non-deterministic; make output deterministic. + slices.SortFunc(all, slices.Compare) + + return printCountProfile(w, debug, p.name, stackProfile(all)) +} + +type stackProfile [][]uintptr + +func (x stackProfile) Len() int { return len(x) } +func (x stackProfile) Stack(i int) []uintptr { return x[i] } +func (x stackProfile) Label(i int) *labelMap { return nil } + +// A countProfile is a set of stack traces to be printed as counts +// grouped by stack trace. There are multiple implementations: +// all that matters is that we can find out how many traces there are +// and obtain each trace in turn. +type countProfile interface { + Len() int + Stack(i int) []uintptr + Label(i int) *labelMap +} + +// expandInlinedFrames copies the call stack from pcs into dst, expanding any +// PCs corresponding to inlined calls into the corresponding PCs for the inlined +// functions. Returns the number of frames copied to dst. +func expandInlinedFrames(dst, pcs []uintptr) int { + cf := runtime.CallersFrames(pcs) + var n int + for n < len(dst) { + f, more := cf.Next() + // f.PC is a "call PC", but later consumers will expect + // "return PCs" + dst[n] = f.PC + 1 + n++ + if !more { + break + } + } + return n +} + +// printCountCycleProfile outputs block profile records (for block or mutex profiles) +// as the pprof-proto format output. Translations from cycle count to time duration +// are done because The proto expects count and time (nanoseconds) instead of count +// and the number of cycles for block, contention profiles. +func printCountCycleProfile(w io.Writer, countName, cycleName string, records []profilerecord.BlockProfileRecord) error { + // Output profile in protobuf form. + b := newProfileBuilder(w) + b.pbValueType(tagProfile_PeriodType, countName, "count") + b.pb.int64Opt(tagProfile_Period, 1) + b.pbValueType(tagProfile_SampleType, countName, "count") + b.pbValueType(tagProfile_SampleType, cycleName, "nanoseconds") + + cpuGHz := float64(pprof_cyclesPerSecond()) / 1e9 + + values := []int64{0, 0} + var locs []uint64 + expandedStack := pprof_makeProfStack() + for _, r := range records { + values[0] = r.Count + values[1] = int64(float64(r.Cycles) / cpuGHz) + // For count profiles, all stack addresses are + // return PCs, which is what appendLocsForStack expects. + n := expandInlinedFrames(expandedStack, r.Stack) + locs = b.appendLocsForStack(locs[:0], expandedStack[:n]) + b.pbSample(values, locs, nil) + } + b.build() + return nil +} + +// printCountProfile prints a countProfile at the specified debug level. +// The profile will be in compressed proto format unless debug is nonzero. +func printCountProfile(w io.Writer, debug int, name string, p countProfile) error { + // Build count of each stack. + var buf strings.Builder + key := func(stk []uintptr, lbls *labelMap) string { + buf.Reset() + fmt.Fprintf(&buf, "@") + for _, pc := range stk { + fmt.Fprintf(&buf, " %#x", pc) + } + if lbls != nil { + buf.WriteString("\n# labels: ") + buf.WriteString(lbls.String()) + } + return buf.String() + } + count := map[string]int{} + index := map[string]int{} + var keys []string + n := p.Len() + for i := 0; i < n; i++ { + k := key(p.Stack(i), p.Label(i)) + if count[k] == 0 { + index[k] = i + keys = append(keys, k) + } + count[k]++ + } + + sort.Sort(&keysByCount{keys, count}) + + if debug > 0 { + // Print debug profile in legacy format + tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) + fmt.Fprintf(tw, "%s profile: total %d\n", name, p.Len()) + for _, k := range keys { + fmt.Fprintf(tw, "%d %s\n", count[k], k) + printStackRecord(tw, p.Stack(index[k]), false) + } + return tw.Flush() + } + + // Output profile in protobuf form. + b := newProfileBuilder(w) + b.pbValueType(tagProfile_PeriodType, name, "count") + b.pb.int64Opt(tagProfile_Period, 1) + b.pbValueType(tagProfile_SampleType, name, "count") + + values := []int64{0} + var locs []uint64 + for _, k := range keys { + values[0] = int64(count[k]) + // For count profiles, all stack addresses are + // return PCs, which is what appendLocsForStack expects. + locs = b.appendLocsForStack(locs[:0], p.Stack(index[k])) + idx := index[k] + var labels func() + if p.Label(idx) != nil { + labels = func() { + for k, v := range *p.Label(idx) { + b.pbLabel(tagSample_Label, k, v, 0) + } + } + } + b.pbSample(values, locs, labels) + } + b.build() + return nil +} + +// keysByCount sorts keys with higher counts first, breaking ties by key string order. +type keysByCount struct { + keys []string + count map[string]int +} + +func (x *keysByCount) Len() int { return len(x.keys) } +func (x *keysByCount) Swap(i, j int) { x.keys[i], x.keys[j] = x.keys[j], x.keys[i] } +func (x *keysByCount) Less(i, j int) bool { + ki, kj := x.keys[i], x.keys[j] + ci, cj := x.count[ki], x.count[kj] + if ci != cj { + return ci > cj + } + return ki < kj +} + +// printStackRecord prints the function + source line information +// for a single stack trace. +func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) { + show := allFrames + frames := runtime.CallersFrames(stk) + for { + frame, more := frames.Next() + name := frame.Function + if name == "" { + show = true + fmt.Fprintf(w, "#\t%#x\n", frame.PC) + } else if name != "runtime.goexit" && (show || !strings.HasPrefix(name, "runtime.")) { + // Hide runtime.goexit and any runtime functions at the beginning. + // This is useful mainly for allocation traces. + show = true + fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", frame.PC, name, frame.PC-frame.Entry, frame.File, frame.Line) + } + if !more { + break + } + } + if !show { + // We didn't print anything; do it again, + // and this time include runtime functions. + printStackRecord(w, stk, true) + return + } + fmt.Fprintf(w, "\n") +} + +// Interface to system profiles. + +// WriteHeapProfile is shorthand for [Lookup]("heap").WriteTo(w, 0). +// It is preserved for backwards compatibility. +func WriteHeapProfile(w io.Writer) error { + return writeHeap(w, 0) +} + +// countHeap returns the number of records in the heap profile. +func countHeap() int { + n, _ := runtime.MemProfile(nil, true) + return n +} + +// writeHeap writes the current runtime heap profile to w. +func writeHeap(w io.Writer, debug int) error { + return writeHeapInternal(w, debug, "") +} + +// writeAlloc writes the current runtime heap profile to w +// with the total allocation space as the default sample type. +func writeAlloc(w io.Writer, debug int) error { + return writeHeapInternal(w, debug, "alloc_space") +} + +func writeHeapInternal(w io.Writer, debug int, defaultSampleType string) error { + var memStats *runtime.MemStats + if debug != 0 { + // Read mem stats first, so that our other allocations + // do not appear in the statistics. + memStats = new(runtime.MemStats) + runtime.ReadMemStats(memStats) + } + + // Find out how many records there are (the call + // pprof_memProfileInternal(nil, true) below), + // allocate that many records, and get the data. + // There's a race—more records might be added between + // the two calls—so allocate a few extra records for safety + // and also try again if we're very unlucky. + // The loop should only execute one iteration in the common case. + var p []profilerecord.MemProfileRecord + n, ok := pprof_memProfileInternal(nil, true) + for { + // Allocate room for a slightly bigger profile, + // in case a few more entries have been added + // since the call to MemProfile. + p = make([]profilerecord.MemProfileRecord, n+50) + n, ok = pprof_memProfileInternal(p, true) + if ok { + p = p[0:n] + break + } + // Profile grew; try again. + } + + if debug == 0 { + return writeHeapProto(w, p, int64(runtime.MemProfileRate), defaultSampleType) + } + + slices.SortFunc(p, func(a, b profilerecord.MemProfileRecord) int { + return cmp.Compare(a.InUseBytes(), b.InUseBytes()) + }) + + b := bufio.NewWriter(w) + tw := tabwriter.NewWriter(b, 1, 8, 1, '\t', 0) + w = tw + + var total runtime.MemProfileRecord + for i := range p { + r := &p[i] + total.AllocBytes += r.AllocBytes + total.AllocObjects += r.AllocObjects + total.FreeBytes += r.FreeBytes + total.FreeObjects += r.FreeObjects + } + + // Technically the rate is MemProfileRate not 2*MemProfileRate, + // but early versions of the C++ heap profiler reported 2*MemProfileRate, + // so that's what pprof has come to expect. + rate := 2 * runtime.MemProfileRate + + // pprof reads a profile with alloc == inuse as being a "2-column" profile + // (objects and bytes, not distinguishing alloc from inuse), + // but then such a profile can't be merged using pprof *.prof with + // other 4-column profiles where alloc != inuse. + // The easiest way to avoid this bug is to adjust allocBytes so it's never == inuseBytes. + // pprof doesn't use these header values anymore except for checking equality. + inUseBytes := total.InUseBytes() + allocBytes := total.AllocBytes + if inUseBytes == allocBytes { + allocBytes++ + } + + fmt.Fprintf(w, "heap profile: %d: %d [%d: %d] @ heap/%d\n", + total.InUseObjects(), inUseBytes, + total.AllocObjects, allocBytes, + rate) + + for i := range p { + r := &p[i] + fmt.Fprintf(w, "%d: %d [%d: %d] @", + r.InUseObjects(), r.InUseBytes(), + r.AllocObjects, r.AllocBytes) + for _, pc := range r.Stack { + fmt.Fprintf(w, " %#x", pc) + } + fmt.Fprintf(w, "\n") + printStackRecord(w, r.Stack, false) + } + + // Print memstats information too. + // Pprof will ignore, but useful for people + s := memStats + fmt.Fprintf(w, "\n# runtime.MemStats\n") + fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc) + fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc) + fmt.Fprintf(w, "# Sys = %d\n", s.Sys) + fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups) + fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs) + fmt.Fprintf(w, "# Frees = %d\n", s.Frees) + + fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc) + fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys) + fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle) + fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse) + fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased) + fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects) + + fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys) + fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys) + fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys) + fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys) + fmt.Fprintf(w, "# GCSys = %d\n", s.GCSys) + fmt.Fprintf(w, "# OtherSys = %d\n", s.OtherSys) + + fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC) + fmt.Fprintf(w, "# LastGC = %d\n", s.LastGC) + fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs) + fmt.Fprintf(w, "# PauseEnd = %d\n", s.PauseEnd) + fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC) + fmt.Fprintf(w, "# NumForcedGC = %d\n", s.NumForcedGC) + fmt.Fprintf(w, "# GCCPUFraction = %v\n", s.GCCPUFraction) + fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC) + + // Also flush out MaxRSS on supported platforms. + addMaxRSS(w) + + tw.Flush() + return b.Flush() +} + +// countThreadCreate returns the size of the current ThreadCreateProfile. +func countThreadCreate() int { + n, _ := runtime.ThreadCreateProfile(nil) + return n +} + +// writeThreadCreate writes the current runtime ThreadCreateProfile to w. +func writeThreadCreate(w io.Writer, debug int) error { + // Until https://golang.org/issues/6104 is addressed, wrap + // ThreadCreateProfile because there's no point in tracking labels when we + // don't get any stack-traces. + return writeRuntimeProfile(w, debug, "threadcreate", func(p []profilerecord.StackRecord, _ []unsafe.Pointer) (n int, ok bool) { + return pprof_threadCreateInternal(p) + }) +} + +// countGoroutine returns the number of goroutines. +func countGoroutine() int { + return runtime.NumGoroutine() +} + +// writeGoroutine writes the current runtime GoroutineProfile to w. +func writeGoroutine(w io.Writer, debug int) error { + if debug >= 2 { + return writeGoroutineStacks(w) + } + return writeRuntimeProfile(w, debug, "goroutine", pprof_goroutineProfileWithLabels) +} + +func writeGoroutineStacks(w io.Writer) error { + // We don't know how big the buffer needs to be to collect + // all the goroutines. Start with 1 MB and try a few times, doubling each time. + // Give up and use a truncated trace if 64 MB is not enough. + buf := make([]byte, 1<<20) + for i := 0; ; i++ { + n := runtime.Stack(buf, true) + if n < len(buf) { + buf = buf[:n] + break + } + if len(buf) >= 64<<20 { + // Filled 64 MB - stop there. + break + } + buf = make([]byte, 2*len(buf)) + } + _, err := w.Write(buf) + return err +} + +func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]profilerecord.StackRecord, []unsafe.Pointer) (int, bool)) error { + // Find out how many records there are (fetch(nil)), + // allocate that many records, and get the data. + // There's a race—more records might be added between + // the two calls—so allocate a few extra records for safety + // and also try again if we're very unlucky. + // The loop should only execute one iteration in the common case. + var p []profilerecord.StackRecord + var labels []unsafe.Pointer + n, ok := fetch(nil, nil) + + for { + // Allocate room for a slightly bigger profile, + // in case a few more entries have been added + // since the call to ThreadProfile. + p = make([]profilerecord.StackRecord, n+10) + labels = make([]unsafe.Pointer, n+10) + n, ok = fetch(p, labels) + if ok { + p = p[0:n] + break + } + // Profile grew; try again. + } + + return printCountProfile(w, debug, name, &runtimeProfile{p, labels}) +} + +type runtimeProfile struct { + stk []profilerecord.StackRecord + labels []unsafe.Pointer +} + +func (p *runtimeProfile) Len() int { return len(p.stk) } +func (p *runtimeProfile) Stack(i int) []uintptr { return p.stk[i].Stack } +func (p *runtimeProfile) Label(i int) *labelMap { return (*labelMap)(p.labels[i]) } + +var cpu struct { + sync.Mutex + profiling bool + done chan bool +} + +// StartCPUProfile enables CPU profiling for the current process. +// While profiling, the profile will be buffered and written to w. +// StartCPUProfile returns an error if profiling is already enabled. +// +// On Unix-like systems, StartCPUProfile does not work by default for +// Go code built with -buildmode=c-archive or -buildmode=c-shared. +// StartCPUProfile relies on the SIGPROF signal, but that signal will +// be delivered to the main program's SIGPROF signal handler (if any) +// not to the one used by Go. To make it work, call [os/signal.Notify] +// for [syscall.SIGPROF], but note that doing so may break any profiling +// being done by the main program. +func StartCPUProfile(w io.Writer) error { + // The runtime routines allow a variable profiling rate, + // but in practice operating systems cannot trigger signals + // at more than about 500 Hz, and our processing of the + // signal is not cheap (mostly getting the stack trace). + // 100 Hz is a reasonable choice: it is frequent enough to + // produce useful data, rare enough not to bog down the + // system, and a nice round number to make it easy to + // convert sample counts to seconds. Instead of requiring + // each client to specify the frequency, we hard code it. + const hz = 100 + + cpu.Lock() + defer cpu.Unlock() + if cpu.done == nil { + cpu.done = make(chan bool) + } + // Double-check. + if cpu.profiling { + return fmt.Errorf("cpu profiling already in use") + } + cpu.profiling = true + runtime.SetCPUProfileRate(hz) + go profileWriter(w) + return nil +} + +// readProfile, provided by the runtime, returns the next chunk of +// binary CPU profiling stack trace data, blocking until data is available. +// If profiling is turned off and all the profile data accumulated while it was +// on has been returned, readProfile returns eof=true. +// The caller must save the returned data and tags before calling readProfile again. +func readProfile() (data []uint64, tags []unsafe.Pointer, eof bool) + +func profileWriter(w io.Writer) { + b := newProfileBuilder(w) + var err error + for { + time.Sleep(100 * time.Millisecond) + data, tags, eof := readProfile() + if e := b.addCPUData(data, tags); e != nil && err == nil { + err = e + } + if eof { + break + } + } + if err != nil { + // The runtime should never produce an invalid or truncated profile. + // It drops records that can't fit into its log buffers. + panic("runtime/pprof: converting profile: " + err.Error()) + } + b.build() + cpu.done <- true +} + +// StopCPUProfile stops the current CPU profile, if any. +// StopCPUProfile only returns after all the writes for the +// profile have completed. +func StopCPUProfile() { + cpu.Lock() + defer cpu.Unlock() + + if !cpu.profiling { + return + } + cpu.profiling = false + runtime.SetCPUProfileRate(0) + <-cpu.done +} + +// countBlock returns the number of records in the blocking profile. +func countBlock() int { + n, _ := runtime.BlockProfile(nil) + return n +} + +// countMutex returns the number of records in the mutex profile. +func countMutex() int { + n, _ := runtime.MutexProfile(nil) + return n +} + +// writeBlock writes the current blocking profile to w. +func writeBlock(w io.Writer, debug int) error { + return writeProfileInternal(w, debug, "contention", pprof_blockProfileInternal) +} + +// writeMutex writes the current mutex profile to w. +func writeMutex(w io.Writer, debug int) error { + return writeProfileInternal(w, debug, "mutex", pprof_mutexProfileInternal) +} + +// writeProfileInternal writes the current blocking or mutex profile depending on the passed parameters. +func writeProfileInternal(w io.Writer, debug int, name string, runtimeProfile func([]profilerecord.BlockProfileRecord) (int, bool)) error { + var p []profilerecord.BlockProfileRecord + n, ok := runtimeProfile(nil) + for { + p = make([]profilerecord.BlockProfileRecord, n+50) + n, ok = runtimeProfile(p) + if ok { + p = p[:n] + break + } + } + + slices.SortFunc(p, func(a, b profilerecord.BlockProfileRecord) int { + return cmp.Compare(b.Cycles, a.Cycles) + }) + + if debug <= 0 { + return printCountCycleProfile(w, "contentions", "delay", p) + } + + b := bufio.NewWriter(w) + tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) + w = tw + + fmt.Fprintf(w, "--- %v:\n", name) + fmt.Fprintf(w, "cycles/second=%v\n", pprof_cyclesPerSecond()) + if name == "mutex" { + fmt.Fprintf(w, "sampling period=%d\n", runtime.SetMutexProfileFraction(-1)) + } + expandedStack := pprof_makeProfStack() + for i := range p { + r := &p[i] + fmt.Fprintf(w, "%v %v @", r.Cycles, r.Count) + n := expandInlinedFrames(expandedStack, r.Stack) + stack := expandedStack[:n] + for _, pc := range stack { + fmt.Fprintf(w, " %#x", pc) + } + fmt.Fprint(w, "\n") + if debug > 0 { + printStackRecord(w, stack, true) + } + } + + if tw != nil { + tw.Flush() + } + return b.Flush() +} + +//go:linkname pprof_goroutineProfileWithLabels runtime.pprof_goroutineProfileWithLabels +func pprof_goroutineProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) + +//go:linkname pprof_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond +func pprof_cyclesPerSecond() int64 + +//go:linkname pprof_memProfileInternal runtime.pprof_memProfileInternal +func pprof_memProfileInternal(p []profilerecord.MemProfileRecord, inuseZero bool) (n int, ok bool) + +//go:linkname pprof_blockProfileInternal runtime.pprof_blockProfileInternal +func pprof_blockProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) + +//go:linkname pprof_mutexProfileInternal runtime.pprof_mutexProfileInternal +func pprof_mutexProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) + +//go:linkname pprof_threadCreateInternal runtime.pprof_threadCreateInternal +func pprof_threadCreateInternal(p []profilerecord.StackRecord) (n int, ok bool) + +//go:linkname pprof_fpunwindExpand runtime.pprof_fpunwindExpand +func pprof_fpunwindExpand(dst, src []uintptr) int + +//go:linkname pprof_makeProfStack runtime.pprof_makeProfStack +func pprof_makeProfStack() []uintptr diff --git a/contrib/go/_std_1.23/src/runtime/pprof/pprof_norusage.go b/contrib/go/_std_1.23/src/runtime/pprof/pprof_norusage.go new file mode 100644 index 000000000000..ef3cef42bdda --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/pprof/pprof_norusage.go @@ -0,0 +1,15 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !unix && !windows + +package pprof + +import ( + "io" +) + +// Stub call for platforms that don't support rusage. +func addMaxRSS(w io.Writer) { +} diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pprof_rusage.go b/contrib/go/_std_1.23/src/runtime/pprof/pprof_rusage.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/pprof_rusage.go rename to contrib/go/_std_1.23/src/runtime/pprof/pprof_rusage.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pprof_windows.go b/contrib/go/_std_1.23/src/runtime/pprof/pprof_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/pprof_windows.go rename to contrib/go/_std_1.23/src/runtime/pprof/pprof_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/proto.go b/contrib/go/_std_1.23/src/runtime/pprof/proto.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/proto.go rename to contrib/go/_std_1.23/src/runtime/pprof/proto.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/proto_darwin.go b/contrib/go/_std_1.23/src/runtime/pprof/proto_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/proto_darwin.go rename to contrib/go/_std_1.23/src/runtime/pprof/proto_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/proto_other.go b/contrib/go/_std_1.23/src/runtime/pprof/proto_other.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/proto_other.go rename to contrib/go/_std_1.23/src/runtime/pprof/proto_other.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/proto_windows.go b/contrib/go/_std_1.23/src/runtime/pprof/proto_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/proto_windows.go rename to contrib/go/_std_1.23/src/runtime/pprof/proto_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/protobuf.go b/contrib/go/_std_1.23/src/runtime/pprof/protobuf.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/protobuf.go rename to contrib/go/_std_1.23/src/runtime/pprof/protobuf.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/protomem.go b/contrib/go/_std_1.23/src/runtime/pprof/protomem.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/pprof/protomem.go rename to contrib/go/_std_1.23/src/runtime/pprof/protomem.go index fa75a28c6263..ab3550f43f9a 100644 --- a/contrib/go/_std_1.22/src/runtime/pprof/protomem.go +++ b/contrib/go/_std_1.23/src/runtime/pprof/protomem.go @@ -5,6 +5,7 @@ package pprof import ( + "internal/profilerecord" "io" "math" "runtime" @@ -12,7 +13,7 @@ import ( ) // writeHeapProto writes the current heap profile in protobuf format to w. -func writeHeapProto(w io.Writer, p []runtime.MemProfileRecord, rate int64, defaultSampleType string) error { +func writeHeapProto(w io.Writer, p []profilerecord.MemProfileRecord, rate int64, defaultSampleType string) error { b := newProfileBuilder(w) b.pbValueType(tagProfile_PeriodType, "space", "bytes") b.pb.int64Opt(tagProfile_Period, rate) @@ -29,7 +30,7 @@ func writeHeapProto(w io.Writer, p []runtime.MemProfileRecord, rate int64, defau for _, r := range p { hideRuntime := true for tries := 0; tries < 2; tries++ { - stk := r.Stack() + stk := r.Stack // For heap profiles, all stack // addresses are return PCs, which is // what appendLocsForStack expects. diff --git a/contrib/go/_std_1.22/src/runtime/pprof/runtime.go b/contrib/go/_std_1.23/src/runtime/pprof/runtime.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/runtime.go rename to contrib/go/_std_1.23/src/runtime/pprof/runtime.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/vminfo_darwin.go b/contrib/go/_std_1.23/src/runtime/pprof/vminfo_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/vminfo_darwin.go rename to contrib/go/_std_1.23/src/runtime/pprof/vminfo_darwin.go diff --git a/contrib/go/_std_1.23/src/runtime/pprof/ya.make b/contrib/go/_std_1.23/src/runtime/pprof/ya.make new file mode 100644 index 000000000000..7559a49dea08 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/pprof/ya.make @@ -0,0 +1,65 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + defs_darwin_arm64.go + elf.go + label.go + map.go + pe.go + pprof.go + pprof_rusage.go + proto.go + proto_darwin.go + protobuf.go + protomem.go + runtime.go + vminfo_darwin.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + defs_darwin_amd64.go + elf.go + label.go + map.go + pe.go + pprof.go + pprof_rusage.go + proto.go + proto_darwin.go + protobuf.go + protomem.go + runtime.go + vminfo_darwin.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + elf.go + label.go + map.go + pe.go + pprof.go + pprof_rusage.go + proto.go + proto_other.go + protobuf.go + protomem.go + runtime.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + elf.go + label.go + map.go + pe.go + pprof.go + pprof_windows.go + proto.go + proto_windows.go + protobuf.go + protomem.go + runtime.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/preempt.go b/contrib/go/_std_1.23/src/runtime/preempt.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/preempt.go rename to contrib/go/_std_1.23/src/runtime/preempt.go index 82d85cd70761..839f3875be31 100644 --- a/contrib/go/_std_1.22/src/runtime/preempt.go +++ b/contrib/go/_std_1.23/src/runtime/preempt.go @@ -55,6 +55,7 @@ package runtime import ( "internal/abi" "internal/goarch" + "internal/stringslite" ) type suspendGState struct { @@ -416,16 +417,23 @@ func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) { // Check the inner-most name u, uf := newInlineUnwinder(f, pc) name := u.srcFunc(uf).name() - if hasPrefix(name, "runtime.") || - hasPrefix(name, "runtime/internal/") || - hasPrefix(name, "reflect.") { + if stringslite.HasPrefix(name, "runtime.") || + stringslite.HasPrefix(name, "runtime/internal/") || + stringslite.HasPrefix(name, "internal/runtime/") || + stringslite.HasPrefix(name, "reflect.") { // For now we never async preempt the runtime or // anything closely tied to the runtime. Known issues // include: various points in the scheduler ("don't // preempt between here and here"), much of the defer // implementation (untyped info on stack), bulk write - // barriers (write barrier check), - // reflect.{makeFuncStub,methodValueCall}. + // barriers (write barrier check), atomic functions in + // internal/runtime/atomic, reflect.{makeFuncStub,methodValueCall}. + // + // Note that this is a subset of the runtimePkgs in pkgspecial.go + // and these checks are theoretically redundant because the compiler + // marks "all points" in runtime functions as unsafe for async preemption. + // But for some reason, we can't eliminate these checks until https://go.dev/issue/72031 + // is resolved. // // TODO(austin): We should improve this, or opt things // in incrementally. diff --git a/contrib/go/_std_1.22/src/runtime/preempt_386.s b/contrib/go/_std_1.23/src/runtime/preempt_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_386.s rename to contrib/go/_std_1.23/src/runtime/preempt_386.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_amd64.s b/contrib/go/_std_1.23/src/runtime/preempt_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_amd64.s rename to contrib/go/_std_1.23/src/runtime/preempt_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_arm.s b/contrib/go/_std_1.23/src/runtime/preempt_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_arm.s rename to contrib/go/_std_1.23/src/runtime/preempt_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_arm64.s b/contrib/go/_std_1.23/src/runtime/preempt_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_arm64.s rename to contrib/go/_std_1.23/src/runtime/preempt_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_loong64.s b/contrib/go/_std_1.23/src/runtime/preempt_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_loong64.s rename to contrib/go/_std_1.23/src/runtime/preempt_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_mips64x.s b/contrib/go/_std_1.23/src/runtime/preempt_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_mips64x.s rename to contrib/go/_std_1.23/src/runtime/preempt_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_mipsx.s b/contrib/go/_std_1.23/src/runtime/preempt_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_mipsx.s rename to contrib/go/_std_1.23/src/runtime/preempt_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_nonwindows.go b/contrib/go/_std_1.23/src/runtime/preempt_nonwindows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_nonwindows.go rename to contrib/go/_std_1.23/src/runtime/preempt_nonwindows.go diff --git a/contrib/go/_std_1.22/src/runtime/preempt_ppc64x.s b/contrib/go/_std_1.23/src/runtime/preempt_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/preempt_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_riscv64.s b/contrib/go/_std_1.23/src/runtime/preempt_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_riscv64.s rename to contrib/go/_std_1.23/src/runtime/preempt_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_s390x.s b/contrib/go/_std_1.23/src/runtime/preempt_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_s390x.s rename to contrib/go/_std_1.23/src/runtime/preempt_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_wasm.s b/contrib/go/_std_1.23/src/runtime/preempt_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_wasm.s rename to contrib/go/_std_1.23/src/runtime/preempt_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/print.go b/contrib/go/_std_1.23/src/runtime/print.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/print.go rename to contrib/go/_std_1.23/src/runtime/print.go diff --git a/contrib/go/_std_1.23/src/runtime/proc.go b/contrib/go/_std_1.23/src/runtime/proc.go new file mode 100644 index 000000000000..e3cdf71911be --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/proc.go @@ -0,0 +1,7313 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/abi" + "internal/cpu" + "internal/goarch" + "internal/goos" + "internal/runtime/atomic" + "internal/runtime/exithook" + "internal/stringslite" + "runtime/internal/sys" + "unsafe" +) + +// set using cmd/go/internal/modload.ModInfoProg +var modinfo string + +// Goroutine scheduler +// The scheduler's job is to distribute ready-to-run goroutines over worker threads. +// +// The main concepts are: +// G - goroutine. +// M - worker thread, or machine. +// P - processor, a resource that is required to execute Go code. +// M must have an associated P to execute Go code, however it can be +// blocked or in a syscall w/o an associated P. +// +// Design doc at https://golang.org/s/go11sched. + +// Worker thread parking/unparking. +// We need to balance between keeping enough running worker threads to utilize +// available hardware parallelism and parking excessive running worker threads +// to conserve CPU resources and power. This is not simple for two reasons: +// (1) scheduler state is intentionally distributed (in particular, per-P work +// queues), so it is not possible to compute global predicates on fast paths; +// (2) for optimal thread management we would need to know the future (don't park +// a worker thread when a new goroutine will be readied in near future). +// +// Three rejected approaches that would work badly: +// 1. Centralize all scheduler state (would inhibit scalability). +// 2. Direct goroutine handoff. That is, when we ready a new goroutine and there +// is a spare P, unpark a thread and handoff it the thread and the goroutine. +// This would lead to thread state thrashing, as the thread that readied the +// goroutine can be out of work the very next moment, we will need to park it. +// Also, it would destroy locality of computation as we want to preserve +// dependent goroutines on the same thread; and introduce additional latency. +// 3. Unpark an additional thread whenever we ready a goroutine and there is an +// idle P, but don't do handoff. This would lead to excessive thread parking/ +// unparking as the additional threads will instantly park without discovering +// any work to do. +// +// The current approach: +// +// This approach applies to three primary sources of potential work: readying a +// goroutine, new/modified-earlier timers, and idle-priority GC. See below for +// additional details. +// +// We unpark an additional thread when we submit work if (this is wakep()): +// 1. There is an idle P, and +// 2. There are no "spinning" worker threads. +// +// A worker thread is considered spinning if it is out of local work and did +// not find work in the global run queue or netpoller; the spinning state is +// denoted in m.spinning and in sched.nmspinning. Threads unparked this way are +// also considered spinning; we don't do goroutine handoff so such threads are +// out of work initially. Spinning threads spin on looking for work in per-P +// run queues and timer heaps or from the GC before parking. If a spinning +// thread finds work it takes itself out of the spinning state and proceeds to +// execution. If it does not find work it takes itself out of the spinning +// state and then parks. +// +// If there is at least one spinning thread (sched.nmspinning>1), we don't +// unpark new threads when submitting work. To compensate for that, if the last +// spinning thread finds work and stops spinning, it must unpark a new spinning +// thread. This approach smooths out unjustified spikes of thread unparking, +// but at the same time guarantees eventual maximal CPU parallelism +// utilization. +// +// The main implementation complication is that we need to be very careful +// during spinning->non-spinning thread transition. This transition can race +// with submission of new work, and either one part or another needs to unpark +// another worker thread. If they both fail to do that, we can end up with +// semi-persistent CPU underutilization. +// +// The general pattern for submission is: +// 1. Submit work to the local or global run queue, timer heap, or GC state. +// 2. #StoreLoad-style memory barrier. +// 3. Check sched.nmspinning. +// +// The general pattern for spinning->non-spinning transition is: +// 1. Decrement nmspinning. +// 2. #StoreLoad-style memory barrier. +// 3. Check all per-P work queues and GC for new work. +// +// Note that all this complexity does not apply to global run queue as we are +// not sloppy about thread unparking when submitting to global queue. Also see +// comments for nmspinning manipulation. +// +// How these different sources of work behave varies, though it doesn't affect +// the synchronization approach: +// * Ready goroutine: this is an obvious source of work; the goroutine is +// immediately ready and must run on some thread eventually. +// * New/modified-earlier timer: The current timer implementation (see time.go) +// uses netpoll in a thread with no work available to wait for the soonest +// timer. If there is no thread waiting, we want a new spinning thread to go +// wait. +// * Idle-priority GC: The GC wakes a stopped idle thread to contribute to +// background GC work (note: currently disabled per golang.org/issue/19112). +// Also see golang.org/issue/44313, as this should be extended to all GC +// workers. + +var ( + m0 m + g0 g + mcache0 *mcache + raceprocctx0 uintptr + raceFiniLock mutex +) + +// This slice records the initializing tasks that need to be +// done to start up the runtime. It is built by the linker. +var runtime_inittasks []*initTask + +// main_init_done is a signal used by cgocallbackg that initialization +// has been completed. It is made before _cgo_notify_runtime_init_done, +// so all cgo calls can rely on it existing. When main_init is complete, +// it is closed, meaning cgocallbackg can reliably receive from it. +var main_init_done chan bool + +//go:linkname main_main main.main +func main_main() + +// mainStarted indicates that the main M has started. +var mainStarted bool + +// runtimeInitTime is the nanotime() at which the runtime started. +var runtimeInitTime int64 + +// Value to use for signal mask for newly created M's. +var initSigmask sigset + +// The main goroutine. +func main() { + mp := getg().m + + // Racectx of m0->g0 is used only as the parent of the main goroutine. + // It must not be used for anything else. + mp.g0.racectx = 0 + + // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. + // Using decimal instead of binary GB and MB because + // they look nicer in the stack overflow failure message. + if goarch.PtrSize == 8 { + maxstacksize = 1000000000 + } else { + maxstacksize = 250000000 + } + + // An upper limit for max stack size. Used to avoid random crashes + // after calling SetMaxStack and trying to allocate a stack that is too big, + // since stackalloc works with 32-bit sizes. + maxstackceiling = 2 * maxstacksize + + // Allow newproc to start new Ms. + mainStarted = true + + if haveSysmon { + systemstack(func() { + newm(sysmon, nil, -1) + }) + } + + // Lock the main goroutine onto this, the main OS thread, + // during initialization. Most programs won't care, but a few + // do require certain calls to be made by the main thread. + // Those can arrange for main.main to run in the main thread + // by calling runtime.LockOSThread during initialization + // to preserve the lock. + lockOSThread() + + if mp != &m0 { + throw("runtime.main not on m0") + } + + // Record when the world started. + // Must be before doInit for tracing init. + runtimeInitTime = nanotime() + if runtimeInitTime == 0 { + throw("nanotime returning zero") + } + + if debug.inittrace != 0 { + inittrace.id = getg().goid + inittrace.active = true + } + + doInit(runtime_inittasks) // Must be before defer. + + // Defer unlock so that runtime.Goexit during init does the unlock too. + needUnlock := true + defer func() { + if needUnlock { + unlockOSThread() + } + }() + + gcenable() + + main_init_done = make(chan bool) + if iscgo { + if _cgo_pthread_key_created == nil { + throw("_cgo_pthread_key_created missing") + } + + if _cgo_thread_start == nil { + throw("_cgo_thread_start missing") + } + if GOOS != "windows" { + if _cgo_setenv == nil { + throw("_cgo_setenv missing") + } + if _cgo_unsetenv == nil { + throw("_cgo_unsetenv missing") + } + } + if _cgo_notify_runtime_init_done == nil { + throw("_cgo_notify_runtime_init_done missing") + } + + // Set the x_crosscall2_ptr C function pointer variable point to crosscall2. + if set_crosscall2 == nil { + throw("set_crosscall2 missing") + } + set_crosscall2() + + // Start the template thread in case we enter Go from + // a C-created thread and need to create a new thread. + startTemplateThread() + cgocall(_cgo_notify_runtime_init_done, nil) + } + + // Run the initializing tasks. Depending on build mode this + // list can arrive a few different ways, but it will always + // contain the init tasks computed by the linker for all the + // packages in the program (excluding those added at runtime + // by package plugin). Run through the modules in dependency + // order (the order they are initialized by the dynamic + // loader, i.e. they are added to the moduledata linked list). + for m := &firstmoduledata; m != nil; m = m.next { + doInit(m.inittasks) + } + + // Disable init tracing after main init done to avoid overhead + // of collecting statistics in malloc and newproc + inittrace.active = false + + close(main_init_done) + + needUnlock = false + unlockOSThread() + + if isarchive || islibrary { + // A program compiled with -buildmode=c-archive or c-shared + // has a main, but it is not executed. + return + } + fn := main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime + fn() + if raceenabled { + runExitHooks(0) // run hooks now, since racefini does not return + racefini() + } + + // Make racy client program work: if panicking on + // another goroutine at the same time as main returns, + // let the other goroutine finish printing the panic trace. + // Once it does, it will exit. See issues 3934 and 20018. + if runningPanicDefers.Load() != 0 { + // Running deferred functions should not take long. + for c := 0; c < 1000; c++ { + if runningPanicDefers.Load() == 0 { + break + } + Gosched() + } + } + if panicking.Load() != 0 { + gopark(nil, nil, waitReasonPanicWait, traceBlockForever, 1) + } + runExitHooks(0) + + exit(0) + for { + var x *int32 + *x = 0 + } +} + +// os_beforeExit is called from os.Exit(0). +// +//go:linkname os_beforeExit os.runtime_beforeExit +func os_beforeExit(exitCode int) { + runExitHooks(exitCode) + if exitCode == 0 && raceenabled { + racefini() + } +} + +func init() { + exithook.Gosched = Gosched + exithook.Goid = func() uint64 { return getg().goid } + exithook.Throw = throw +} + +func runExitHooks(code int) { + exithook.Run(code) +} + +// start forcegc helper goroutine +func init() { + go forcegchelper() +} + +func forcegchelper() { + forcegc.g = getg() + lockInit(&forcegc.lock, lockRankForcegc) + for { + lock(&forcegc.lock) + if forcegc.idle.Load() { + throw("forcegc: phase error") + } + forcegc.idle.Store(true) + goparkunlock(&forcegc.lock, waitReasonForceGCIdle, traceBlockSystemGoroutine, 1) + // this goroutine is explicitly resumed by sysmon + if debug.gctrace > 0 { + println("GC forced") + } + // Time-triggered, fully concurrent. + gcStart(gcTrigger{kind: gcTriggerTime, now: nanotime()}) + } +} + +// Gosched yields the processor, allowing other goroutines to run. It does not +// suspend the current goroutine, so execution resumes automatically. +// +//go:nosplit +func Gosched() { + checkTimeouts() + mcall(gosched_m) +} + +// goschedguarded yields the processor like gosched, but also checks +// for forbidden states and opts out of the yield in those cases. +// +//go:nosplit +func goschedguarded() { + mcall(goschedguarded_m) +} + +// goschedIfBusy yields the processor like gosched, but only does so if +// there are no idle Ps or if we're on the only P and there's nothing in +// the run queue. In both cases, there is freely available idle time. +// +//go:nosplit +func goschedIfBusy() { + gp := getg() + // Call gosched if gp.preempt is set; we may be in a tight loop that + // doesn't otherwise yield. + if !gp.preempt && sched.npidle.Load() > 0 { + return + } + mcall(gosched_m) +} + +// Puts the current goroutine into a waiting state and calls unlockf on the +// system stack. +// +// If unlockf returns false, the goroutine is resumed. +// +// unlockf must not access this G's stack, as it may be moved between +// the call to gopark and the call to unlockf. +// +// Note that because unlockf is called after putting the G into a waiting +// state, the G may have already been readied by the time unlockf is called +// unless there is external synchronization preventing the G from being +// readied. If unlockf returns false, it must guarantee that the G cannot be +// externally readied. +// +// Reason explains why the goroutine has been parked. It is displayed in stack +// traces and heap dumps. Reasons should be unique and descriptive. Do not +// re-use reasons, add new ones. +// +// gopark should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname gopark +func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceReason traceBlockReason, traceskip int) { + if reason != waitReasonSleep { + checkTimeouts() // timeouts may expire while two goroutines keep the scheduler busy + } + mp := acquirem() + gp := mp.curg + status := readgstatus(gp) + if status != _Grunning && status != _Gscanrunning { + throw("gopark: bad g status") + } + mp.waitlock = lock + mp.waitunlockf = unlockf + gp.waitreason = reason + mp.waitTraceBlockReason = traceReason + mp.waitTraceSkip = traceskip + releasem(mp) + // can't do anything that might move the G between Ms here. + mcall(park_m) +} + +// Puts the current goroutine into a waiting state and unlocks the lock. +// The goroutine can be made runnable again by calling goready(gp). +func goparkunlock(lock *mutex, reason waitReason, traceReason traceBlockReason, traceskip int) { + gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceReason, traceskip) +} + +// goready should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname goready +func goready(gp *g, traceskip int) { + systemstack(func() { + ready(gp, traceskip, true) + }) +} + +//go:nosplit +func acquireSudog() *sudog { + // Delicate dance: the semaphore implementation calls + // acquireSudog, acquireSudog calls new(sudog), + // new calls malloc, malloc can call the garbage collector, + // and the garbage collector calls the semaphore implementation + // in stopTheWorld. + // Break the cycle by doing acquirem/releasem around new(sudog). + // The acquirem/releasem increments m.locks during new(sudog), + // which keeps the garbage collector from being invoked. + mp := acquirem() + pp := mp.p.ptr() + if len(pp.sudogcache) == 0 { + lock(&sched.sudoglock) + // First, try to grab a batch from central cache. + for len(pp.sudogcache) < cap(pp.sudogcache)/2 && sched.sudogcache != nil { + s := sched.sudogcache + sched.sudogcache = s.next + s.next = nil + pp.sudogcache = append(pp.sudogcache, s) + } + unlock(&sched.sudoglock) + // If the central cache is empty, allocate a new one. + if len(pp.sudogcache) == 0 { + pp.sudogcache = append(pp.sudogcache, new(sudog)) + } + } + n := len(pp.sudogcache) + s := pp.sudogcache[n-1] + pp.sudogcache[n-1] = nil + pp.sudogcache = pp.sudogcache[:n-1] + if s.elem != nil { + throw("acquireSudog: found s.elem != nil in cache") + } + releasem(mp) + return s +} + +//go:nosplit +func releaseSudog(s *sudog) { + if s.elem != nil { + throw("runtime: sudog with non-nil elem") + } + if s.isSelect { + throw("runtime: sudog with non-false isSelect") + } + if s.next != nil { + throw("runtime: sudog with non-nil next") + } + if s.prev != nil { + throw("runtime: sudog with non-nil prev") + } + if s.waitlink != nil { + throw("runtime: sudog with non-nil waitlink") + } + if s.c != nil { + throw("runtime: sudog with non-nil c") + } + gp := getg() + if gp.param != nil { + throw("runtime: releaseSudog with non-nil gp.param") + } + mp := acquirem() // avoid rescheduling to another P + pp := mp.p.ptr() + if len(pp.sudogcache) == cap(pp.sudogcache) { + // Transfer half of local cache to the central cache. + var first, last *sudog + for len(pp.sudogcache) > cap(pp.sudogcache)/2 { + n := len(pp.sudogcache) + p := pp.sudogcache[n-1] + pp.sudogcache[n-1] = nil + pp.sudogcache = pp.sudogcache[:n-1] + if first == nil { + first = p + } else { + last.next = p + } + last = p + } + lock(&sched.sudoglock) + last.next = sched.sudogcache + sched.sudogcache = first + unlock(&sched.sudoglock) + } + pp.sudogcache = append(pp.sudogcache, s) + releasem(mp) +} + +// called from assembly. +func badmcall(fn func(*g)) { + throw("runtime: mcall called on m->g0 stack") +} + +func badmcall2(fn func(*g)) { + throw("runtime: mcall function returned") +} + +func badreflectcall() { + panic(plainError("arg size to reflect.call more than 1GB")) +} + +//go:nosplit +//go:nowritebarrierrec +func badmorestackg0() { + if !crashStackImplemented { + writeErrStr("fatal: morestack on g0\n") + return + } + + g := getg() + switchToCrashStack(func() { + print("runtime: morestack on g0, stack [", hex(g.stack.lo), " ", hex(g.stack.hi), "], sp=", hex(g.sched.sp), ", called from\n") + g.m.traceback = 2 // include pc and sp in stack trace + traceback1(g.sched.pc, g.sched.sp, g.sched.lr, g, 0) + print("\n") + + throw("morestack on g0") + }) +} + +//go:nosplit +//go:nowritebarrierrec +func badmorestackgsignal() { + writeErrStr("fatal: morestack on gsignal\n") +} + +//go:nosplit +func badctxt() { + throw("ctxt != 0") +} + +// gcrash is a fake g that can be used when crashing due to bad +// stack conditions. +var gcrash g + +var crashingG atomic.Pointer[g] + +// Switch to crashstack and call fn, with special handling of +// concurrent and recursive cases. +// +// Nosplit as it is called in a bad stack condition (we know +// morestack would fail). +// +//go:nosplit +//go:nowritebarrierrec +func switchToCrashStack(fn func()) { + me := getg() + if crashingG.CompareAndSwapNoWB(nil, me) { + switchToCrashStack0(fn) // should never return + abort() + } + if crashingG.Load() == me { + // recursive crashing. too bad. + writeErrStr("fatal: recursive switchToCrashStack\n") + abort() + } + // Another g is crashing. Give it some time, hopefully it will finish traceback. + usleep_no_g(100) + writeErrStr("fatal: concurrent switchToCrashStack\n") + abort() +} + +// Disable crash stack on Windows for now. Apparently, throwing an exception +// on a non-system-allocated crash stack causes EXCEPTION_STACK_OVERFLOW and +// hangs the process (see issue 63938). +const crashStackImplemented = GOOS != "windows" + +//go:noescape +func switchToCrashStack0(fn func()) // in assembly + +func lockedOSThread() bool { + gp := getg() + return gp.lockedm != 0 && gp.m.lockedg != 0 +} + +var ( + // allgs contains all Gs ever created (including dead Gs), and thus + // never shrinks. + // + // Access via the slice is protected by allglock or stop-the-world. + // Readers that cannot take the lock may (carefully!) use the atomic + // variables below. + allglock mutex + allgs []*g + + // allglen and allgptr are atomic variables that contain len(allgs) and + // &allgs[0] respectively. Proper ordering depends on totally-ordered + // loads and stores. Writes are protected by allglock. + // + // allgptr is updated before allglen. Readers should read allglen + // before allgptr to ensure that allglen is always <= len(allgptr). New + // Gs appended during the race can be missed. For a consistent view of + // all Gs, allglock must be held. + // + // allgptr copies should always be stored as a concrete type or + // unsafe.Pointer, not uintptr, to ensure that GC can still reach it + // even if it points to a stale array. + allglen uintptr + allgptr **g +) + +func allgadd(gp *g) { + if readgstatus(gp) == _Gidle { + throw("allgadd: bad status Gidle") + } + + lock(&allglock) + allgs = append(allgs, gp) + if &allgs[0] != allgptr { + atomicstorep(unsafe.Pointer(&allgptr), unsafe.Pointer(&allgs[0])) + } + atomic.Storeuintptr(&allglen, uintptr(len(allgs))) + unlock(&allglock) +} + +// allGsSnapshot returns a snapshot of the slice of all Gs. +// +// The world must be stopped or allglock must be held. +func allGsSnapshot() []*g { + assertWorldStoppedOrLockHeld(&allglock) + + // Because the world is stopped or allglock is held, allgadd + // cannot happen concurrently with this. allgs grows + // monotonically and existing entries never change, so we can + // simply return a copy of the slice header. For added safety, + // we trim everything past len because that can still change. + return allgs[:len(allgs):len(allgs)] +} + +// atomicAllG returns &allgs[0] and len(allgs) for use with atomicAllGIndex. +func atomicAllG() (**g, uintptr) { + length := atomic.Loaduintptr(&allglen) + ptr := (**g)(atomic.Loadp(unsafe.Pointer(&allgptr))) + return ptr, length +} + +// atomicAllGIndex returns ptr[i] with the allgptr returned from atomicAllG. +func atomicAllGIndex(ptr **g, i uintptr) *g { + return *(**g)(add(unsafe.Pointer(ptr), i*goarch.PtrSize)) +} + +// forEachG calls fn on every G from allgs. +// +// forEachG takes a lock to exclude concurrent addition of new Gs. +func forEachG(fn func(gp *g)) { + lock(&allglock) + for _, gp := range allgs { + fn(gp) + } + unlock(&allglock) +} + +// forEachGRace calls fn on every G from allgs. +// +// forEachGRace avoids locking, but does not exclude addition of new Gs during +// execution, which may be missed. +func forEachGRace(fn func(gp *g)) { + ptr, length := atomicAllG() + for i := uintptr(0); i < length; i++ { + gp := atomicAllGIndex(ptr, i) + fn(gp) + } + return +} + +const ( + // Number of goroutine ids to grab from sched.goidgen to local per-P cache at once. + // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number. + _GoidCacheBatch = 16 +) + +// cpuinit sets up CPU feature flags and calls internal/cpu.Initialize. env should be the complete +// value of the GODEBUG environment variable. +func cpuinit(env string) { + switch GOOS { + case "aix", "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "illumos", "solaris", "linux": + cpu.DebugOptions = true + } + cpu.Initialize(env) + + // Support cpu feature variables are used in code generated by the compiler + // to guard execution of instructions that can not be assumed to be always supported. + switch GOARCH { + case "386", "amd64": + x86HasPOPCNT = cpu.X86.HasPOPCNT + x86HasSSE41 = cpu.X86.HasSSE41 + x86HasFMA = cpu.X86.HasFMA + + case "arm": + armHasVFPv4 = cpu.ARM.HasVFPv4 + + case "arm64": + arm64HasATOMICS = cpu.ARM64.HasATOMICS + } +} + +// getGodebugEarly extracts the environment variable GODEBUG from the environment on +// Unix-like operating systems and returns it. This function exists to extract GODEBUG +// early before much of the runtime is initialized. +func getGodebugEarly() string { + const prefix = "GODEBUG=" + var env string + switch GOOS { + case "aix", "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "illumos", "solaris", "linux": + // Similar to goenv_unix but extracts the environment value for + // GODEBUG directly. + // TODO(moehrmann): remove when general goenvs() can be called before cpuinit() + n := int32(0) + for argv_index(argv, argc+1+n) != nil { + n++ + } + + for i := int32(0); i < n; i++ { + p := argv_index(argv, argc+1+i) + s := unsafe.String(p, findnull(p)) + + if stringslite.HasPrefix(s, prefix) { + env = gostring(p)[len(prefix):] + break + } + } + } + return env +} + +// The bootstrap sequence is: +// +// call osinit +// call schedinit +// make & queue new G +// call runtime·mstart +// +// The new G calls runtime·main. +func schedinit() { + lockInit(&sched.lock, lockRankSched) + lockInit(&sched.sysmonlock, lockRankSysmon) + lockInit(&sched.deferlock, lockRankDefer) + lockInit(&sched.sudoglock, lockRankSudog) + lockInit(&deadlock, lockRankDeadlock) + lockInit(&paniclk, lockRankPanic) + lockInit(&allglock, lockRankAllg) + lockInit(&allpLock, lockRankAllp) + lockInit(&reflectOffs.lock, lockRankReflectOffs) + lockInit(&finlock, lockRankFin) + lockInit(&cpuprof.lock, lockRankCpuprof) + allocmLock.init(lockRankAllocmR, lockRankAllocmRInternal, lockRankAllocmW) + execLock.init(lockRankExecR, lockRankExecRInternal, lockRankExecW) + traceLockInit() + // Enforce that this lock is always a leaf lock. + // All of this lock's critical sections should be + // extremely short. + lockInit(&memstats.heapStats.noPLock, lockRankLeafRank) + + // raceinit must be the first call to race detector. + // In particular, it must be done before mallocinit below calls racemapshadow. + gp := getg() + if raceenabled { + gp.racectx, raceprocctx0 = raceinit() + } + + sched.maxmcount = 10000 + crashFD.Store(^uintptr(0)) + + // The world starts stopped. + worldStopped() + + ticks.init() // run as early as possible + moduledataverify() + stackinit() + mallocinit() + godebug := getGodebugEarly() + cpuinit(godebug) // must run before alginit + randinit() // must run before alginit, mcommoninit + alginit() // maps, hash, rand must not be used before this call + mcommoninit(gp.m, -1) + modulesinit() // provides activeModules + typelinksinit() // uses maps, activeModules + itabsinit() // uses activeModules + stkobjinit() // must run before GC starts + + sigsave(&gp.m.sigmask) + initSigmask = gp.m.sigmask + + goargs() + goenvs() + secure() + checkfds() + parsedebugvars() + gcinit() + + // Allocate stack space that can be used when crashing due to bad stack + // conditions, e.g. morestack on g0. + gcrash.stack = stackalloc(16384) + gcrash.stackguard0 = gcrash.stack.lo + 1000 + gcrash.stackguard1 = gcrash.stack.lo + 1000 + + // if disableMemoryProfiling is set, update MemProfileRate to 0 to turn off memprofile. + // Note: parsedebugvars may update MemProfileRate, but when disableMemoryProfiling is + // set to true by the linker, it means that nothing is consuming the profile, it is + // safe to set MemProfileRate to 0. + if disableMemoryProfiling { + MemProfileRate = 0 + } + + // mcommoninit runs before parsedebugvars, so init profstacks again. + mProfStackInit(gp.m) + + lock(&sched.lock) + sched.lastpoll.Store(nanotime()) + procs := ncpu + if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 { + procs = n + } + if procresize(procs) != nil { + throw("unknown runnable goroutine during bootstrap") + } + unlock(&sched.lock) + + // World is effectively started now, as P's can run. + worldStarted() + + if buildVersion == "" { + // Condition should never trigger. This code just serves + // to ensure runtime·buildVersion is kept in the resulting binary. + buildVersion = "unknown" + } + if len(modinfo) == 1 { + // Condition should never trigger. This code just serves + // to ensure runtime·modinfo is kept in the resulting binary. + modinfo = "" + } +} + +func dumpgstatus(gp *g) { + thisg := getg() + print("runtime: gp: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n") + print("runtime: getg: g=", thisg, ", goid=", thisg.goid, ", g->atomicstatus=", readgstatus(thisg), "\n") +} + +// sched.lock must be held. +func checkmcount() { + assertLockHeld(&sched.lock) + + // Exclude extra M's, which are used for cgocallback from threads + // created in C. + // + // The purpose of the SetMaxThreads limit is to avoid accidental fork + // bomb from something like millions of goroutines blocking on system + // calls, causing the runtime to create millions of threads. By + // definition, this isn't a problem for threads created in C, so we + // exclude them from the limit. See https://go.dev/issue/60004. + count := mcount() - int32(extraMInUse.Load()) - int32(extraMLength.Load()) + if count > sched.maxmcount { + print("runtime: program exceeds ", sched.maxmcount, "-thread limit\n") + throw("thread exhaustion") + } +} + +// mReserveID returns the next ID to use for a new m. This new m is immediately +// considered 'running' by checkdead. +// +// sched.lock must be held. +func mReserveID() int64 { + assertLockHeld(&sched.lock) + + if sched.mnext+1 < sched.mnext { + throw("runtime: thread ID overflow") + } + id := sched.mnext + sched.mnext++ + checkmcount() + return id +} + +// Pre-allocated ID may be passed as 'id', or omitted by passing -1. +func mcommoninit(mp *m, id int64) { + gp := getg() + + // g0 stack won't make sense for user (and is not necessary unwindable). + if gp != gp.m.g0 { + callers(1, mp.createstack[:]) + } + + lock(&sched.lock) + + if id >= 0 { + mp.id = id + } else { + mp.id = mReserveID() + } + + mrandinit(mp) + + mpreinit(mp) + if mp.gsignal != nil { + mp.gsignal.stackguard1 = mp.gsignal.stack.lo + stackGuard + } + + // Add to allm so garbage collector doesn't free g->m + // when it is just in a register or thread-local storage. + mp.alllink = allm + + // NumCgoCall() and others iterate over allm w/o schedlock, + // so we need to publish it safely. + atomicstorep(unsafe.Pointer(&allm), unsafe.Pointer(mp)) + unlock(&sched.lock) + + // Allocate memory to hold a cgo traceback if the cgo call crashes. + if iscgo || GOOS == "solaris" || GOOS == "illumos" || GOOS == "windows" { + mp.cgoCallers = new(cgoCallers) + } + mProfStackInit(mp) +} + +// mProfStackInit is used to eagerly initialize stack trace buffers for +// profiling. Lazy allocation would have to deal with reentrancy issues in +// malloc and runtime locks for mLockProfile. +// TODO(mknyszek): Implement lazy allocation if this becomes a problem. +func mProfStackInit(mp *m) { + if debug.profstackdepth == 0 { + // debug.profstack is set to 0 by the user, or we're being called from + // schedinit before parsedebugvars. + return + } + mp.profStack = makeProfStackFP() + mp.mLockProfile.stack = makeProfStackFP() +} + +// makeProfStackFP creates a buffer large enough to hold a maximum-sized stack +// trace as well as any additional frames needed for frame pointer unwinding +// with delayed inline expansion. +func makeProfStackFP() []uintptr { + // The "1" term is to account for the first stack entry being + // taken up by a "skip" sentinel value for profilers which + // defer inline frame expansion until the profile is reported. + // The "maxSkip" term is for frame pointer unwinding, where we + // want to end up with debug.profstackdebth frames but will discard + // some "physical" frames to account for skipping. + return make([]uintptr, 1+maxSkip+debug.profstackdepth) +} + +// makeProfStack returns a buffer large enough to hold a maximum-sized stack +// trace. +func makeProfStack() []uintptr { return make([]uintptr, debug.profstackdepth) } + +//go:linkname pprof_makeProfStack +func pprof_makeProfStack() []uintptr { return makeProfStack() } + +func (mp *m) becomeSpinning() { + mp.spinning = true + sched.nmspinning.Add(1) + sched.needspinning.Store(0) +} + +func (mp *m) hasCgoOnStack() bool { + return mp.ncgo > 0 || mp.isextra +} + +const ( + // osHasLowResTimer indicates that the platform's internal timer system has a low resolution, + // typically on the order of 1 ms or more. + osHasLowResTimer = GOOS == "windows" || GOOS == "openbsd" || GOOS == "netbsd" + + // osHasLowResClockInt is osHasLowResClock but in integer form, so it can be used to create + // constants conditionally. + osHasLowResClockInt = goos.IsWindows + + // osHasLowResClock indicates that timestamps produced by nanotime on the platform have a + // low resolution, typically on the order of 1 ms or more. + osHasLowResClock = osHasLowResClockInt > 0 +) + +// Mark gp ready to run. +func ready(gp *g, traceskip int, next bool) { + status := readgstatus(gp) + + // Mark runnable. + mp := acquirem() // disable preemption because it can be holding p in a local var + if status&^_Gscan != _Gwaiting { + dumpgstatus(gp) + throw("bad g->status in ready") + } + + // status is Gwaiting or Gscanwaiting, make Grunnable and put on runq + trace := traceAcquire() + casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, traceskip) + traceRelease(trace) + } + runqput(mp.p.ptr(), gp, next) + wakep() + releasem(mp) +} + +// freezeStopWait is a large value that freezetheworld sets +// sched.stopwait to in order to request that all Gs permanently stop. +const freezeStopWait = 0x7fffffff + +// freezing is set to non-zero if the runtime is trying to freeze the +// world. +var freezing atomic.Bool + +// Similar to stopTheWorld but best-effort and can be called several times. +// There is no reverse operation, used during crashing. +// This function must not lock any mutexes. +func freezetheworld() { + freezing.Store(true) + if debug.dontfreezetheworld > 0 { + // Don't prempt Ps to stop goroutines. That will perturb + // scheduler state, making debugging more difficult. Instead, + // allow goroutines to continue execution. + // + // fatalpanic will tracebackothers to trace all goroutines. It + // is unsafe to trace a running goroutine, so tracebackothers + // will skip running goroutines. That is OK and expected, we + // expect users of dontfreezetheworld to use core files anyway. + // + // However, allowing the scheduler to continue running free + // introduces a race: a goroutine may be stopped when + // tracebackothers checks its status, and then start running + // later when we are in the middle of traceback, potentially + // causing a crash. + // + // To mitigate this, when an M naturally enters the scheduler, + // schedule checks if freezing is set and if so stops + // execution. This guarantees that while Gs can transition from + // running to stopped, they can never transition from stopped + // to running. + // + // The sleep here allows racing Ms that missed freezing and are + // about to run a G to complete the transition to running + // before we start traceback. + usleep(1000) + return + } + + // stopwait and preemption requests can be lost + // due to races with concurrently executing threads, + // so try several times + for i := 0; i < 5; i++ { + // this should tell the scheduler to not start any new goroutines + sched.stopwait = freezeStopWait + sched.gcwaiting.Store(true) + // this should stop running goroutines + if !preemptall() { + break // no running goroutines + } + usleep(1000) + } + // to be sure + usleep(1000) + preemptall() + usleep(1000) +} + +// All reads and writes of g's status go through readgstatus, casgstatus +// castogscanstatus, casfrom_Gscanstatus. +// +//go:nosplit +func readgstatus(gp *g) uint32 { + return gp.atomicstatus.Load() +} + +// The Gscanstatuses are acting like locks and this releases them. +// If it proves to be a performance hit we should be able to make these +// simple atomic stores but for now we are going to throw if +// we see an inconsistent state. +func casfrom_Gscanstatus(gp *g, oldval, newval uint32) { + success := false + + // Check that transition is valid. + switch oldval { + default: + print("runtime: casfrom_Gscanstatus bad oldval gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n") + dumpgstatus(gp) + throw("casfrom_Gscanstatus:top gp->status is not in scan state") + case _Gscanrunnable, + _Gscanwaiting, + _Gscanrunning, + _Gscansyscall, + _Gscanpreempted: + if newval == oldval&^_Gscan { + success = gp.atomicstatus.CompareAndSwap(oldval, newval) + } + } + if !success { + print("runtime: casfrom_Gscanstatus failed gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n") + dumpgstatus(gp) + throw("casfrom_Gscanstatus: gp->status is not in scan state") + } + releaseLockRankAndM(lockRankGscan) +} + +// This will return false if the gp is not in the expected status and the cas fails. +// This acts like a lock acquire while the casfromgstatus acts like a lock release. +func castogscanstatus(gp *g, oldval, newval uint32) bool { + switch oldval { + case _Grunnable, + _Grunning, + _Gwaiting, + _Gsyscall: + if newval == oldval|_Gscan { + r := gp.atomicstatus.CompareAndSwap(oldval, newval) + if r { + acquireLockRankAndM(lockRankGscan) + } + return r + + } + } + print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n") + throw("castogscanstatus") + panic("not reached") +} + +// casgstatusAlwaysTrack is a debug flag that causes casgstatus to always track +// various latencies on every transition instead of sampling them. +var casgstatusAlwaysTrack = false + +// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus +// and casfrom_Gscanstatus instead. +// casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that +// put it in the Gscan state is finished. +// +//go:nosplit +func casgstatus(gp *g, oldval, newval uint32) { + if (oldval&_Gscan != 0) || (newval&_Gscan != 0) || oldval == newval { + systemstack(func() { + // Call on the systemstack to prevent print and throw from counting + // against the nosplit stack reservation. + print("runtime: casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n") + throw("casgstatus: bad incoming values") + }) + } + + lockWithRankMayAcquire(nil, lockRankGscan) + + // See https://golang.org/cl/21503 for justification of the yield delay. + const yieldDelay = 5 * 1000 + var nextYield int64 + + // loop if gp->atomicstatus is in a scan state giving + // GC time to finish and change the state to oldval. + for i := 0; !gp.atomicstatus.CompareAndSwap(oldval, newval); i++ { + if oldval == _Gwaiting && gp.atomicstatus.Load() == _Grunnable { + systemstack(func() { + // Call on the systemstack to prevent throw from counting + // against the nosplit stack reservation. + throw("casgstatus: waiting for Gwaiting but is Grunnable") + }) + } + if i == 0 { + nextYield = nanotime() + yieldDelay + } + if nanotime() < nextYield { + for x := 0; x < 10 && gp.atomicstatus.Load() != oldval; x++ { + procyield(1) + } + } else { + osyield() + nextYield = nanotime() + yieldDelay/2 + } + } + + if oldval == _Grunning { + // Track every gTrackingPeriod time a goroutine transitions out of running. + if casgstatusAlwaysTrack || gp.trackingSeq%gTrackingPeriod == 0 { + gp.tracking = true + } + gp.trackingSeq++ + } + if !gp.tracking { + return + } + + // Handle various kinds of tracking. + // + // Currently: + // - Time spent in runnable. + // - Time spent blocked on a sync.Mutex or sync.RWMutex. + switch oldval { + case _Grunnable: + // We transitioned out of runnable, so measure how much + // time we spent in this state and add it to + // runnableTime. + now := nanotime() + gp.runnableTime += now - gp.trackingStamp + gp.trackingStamp = 0 + case _Gwaiting: + if !gp.waitreason.isMutexWait() { + // Not blocking on a lock. + break + } + // Blocking on a lock, measure it. Note that because we're + // sampling, we have to multiply by our sampling period to get + // a more representative estimate of the absolute value. + // gTrackingPeriod also represents an accurate sampling period + // because we can only enter this state from _Grunning. + now := nanotime() + sched.totalMutexWaitTime.Add((now - gp.trackingStamp) * gTrackingPeriod) + gp.trackingStamp = 0 + } + switch newval { + case _Gwaiting: + if !gp.waitreason.isMutexWait() { + // Not blocking on a lock. + break + } + // Blocking on a lock. Write down the timestamp. + now := nanotime() + gp.trackingStamp = now + case _Grunnable: + // We just transitioned into runnable, so record what + // time that happened. + now := nanotime() + gp.trackingStamp = now + case _Grunning: + // We're transitioning into running, so turn off + // tracking and record how much time we spent in + // runnable. + gp.tracking = false + sched.timeToRun.record(gp.runnableTime) + gp.runnableTime = 0 + } +} + +// casGToWaiting transitions gp from old to _Gwaiting, and sets the wait reason. +// +// Use this over casgstatus when possible to ensure that a waitreason is set. +func casGToWaiting(gp *g, old uint32, reason waitReason) { + // Set the wait reason before calling casgstatus, because casgstatus will use it. + gp.waitreason = reason + casgstatus(gp, old, _Gwaiting) +} + +// casGToWaitingForGC transitions gp from old to _Gwaiting, and sets the wait reason. +// The wait reason must be a valid isWaitingForGC wait reason. +// +// Use this over casgstatus when possible to ensure that a waitreason is set. +func casGToWaitingForGC(gp *g, old uint32, reason waitReason) { + if !reason.isWaitingForGC() { + throw("casGToWaitingForGC with non-isWaitingForGC wait reason") + } + casGToWaiting(gp, old, reason) +} + +// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable. +// Returns old status. Cannot call casgstatus directly, because we are racing with an +// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus, +// it might have become Grunnable by the time we get to the cas. If we called casgstatus, +// it would loop waiting for the status to go back to Gwaiting, which it never will. +// +//go:nosplit +func casgcopystack(gp *g) uint32 { + for { + oldstatus := readgstatus(gp) &^ _Gscan + if oldstatus != _Gwaiting && oldstatus != _Grunnable { + throw("copystack: bad status, not Gwaiting or Grunnable") + } + if gp.atomicstatus.CompareAndSwap(oldstatus, _Gcopystack) { + return oldstatus + } + } +} + +// casGToPreemptScan transitions gp from _Grunning to _Gscan|_Gpreempted. +// +// TODO(austin): This is the only status operation that both changes +// the status and locks the _Gscan bit. Rethink this. +func casGToPreemptScan(gp *g, old, new uint32) { + if old != _Grunning || new != _Gscan|_Gpreempted { + throw("bad g transition") + } + acquireLockRankAndM(lockRankGscan) + for !gp.atomicstatus.CompareAndSwap(_Grunning, _Gscan|_Gpreempted) { + } +} + +// casGFromPreempted attempts to transition gp from _Gpreempted to +// _Gwaiting. If successful, the caller is responsible for +// re-scheduling gp. +func casGFromPreempted(gp *g, old, new uint32) bool { + if old != _Gpreempted || new != _Gwaiting { + throw("bad g transition") + } + gp.waitreason = waitReasonPreempted + return gp.atomicstatus.CompareAndSwap(_Gpreempted, _Gwaiting) +} + +// stwReason is an enumeration of reasons the world is stopping. +type stwReason uint8 + +// Reasons to stop-the-world. +// +// Avoid reusing reasons and add new ones instead. +const ( + stwUnknown stwReason = iota // "unknown" + stwGCMarkTerm // "GC mark termination" + stwGCSweepTerm // "GC sweep termination" + stwWriteHeapDump // "write heap dump" + stwGoroutineProfile // "goroutine profile" + stwGoroutineProfileCleanup // "goroutine profile cleanup" + stwAllGoroutinesStack // "all goroutines stack trace" + stwReadMemStats // "read mem stats" + stwAllThreadsSyscall // "AllThreadsSyscall" + stwGOMAXPROCS // "GOMAXPROCS" + stwStartTrace // "start trace" + stwStopTrace // "stop trace" + stwForTestCountPagesInUse // "CountPagesInUse (test)" + stwForTestReadMetricsSlow // "ReadMetricsSlow (test)" + stwForTestReadMemStatsSlow // "ReadMemStatsSlow (test)" + stwForTestPageCachePagesLeaked // "PageCachePagesLeaked (test)" + stwForTestResetDebugLog // "ResetDebugLog (test)" +) + +func (r stwReason) String() string { + return stwReasonStrings[r] +} + +func (r stwReason) isGC() bool { + return r == stwGCMarkTerm || r == stwGCSweepTerm +} + +// If you add to this list, also add it to src/internal/trace/parser.go. +// If you change the values of any of the stw* constants, bump the trace +// version number and make a copy of this. +var stwReasonStrings = [...]string{ + stwUnknown: "unknown", + stwGCMarkTerm: "GC mark termination", + stwGCSweepTerm: "GC sweep termination", + stwWriteHeapDump: "write heap dump", + stwGoroutineProfile: "goroutine profile", + stwGoroutineProfileCleanup: "goroutine profile cleanup", + stwAllGoroutinesStack: "all goroutines stack trace", + stwReadMemStats: "read mem stats", + stwAllThreadsSyscall: "AllThreadsSyscall", + stwGOMAXPROCS: "GOMAXPROCS", + stwStartTrace: "start trace", + stwStopTrace: "stop trace", + stwForTestCountPagesInUse: "CountPagesInUse (test)", + stwForTestReadMetricsSlow: "ReadMetricsSlow (test)", + stwForTestReadMemStatsSlow: "ReadMemStatsSlow (test)", + stwForTestPageCachePagesLeaked: "PageCachePagesLeaked (test)", + stwForTestResetDebugLog: "ResetDebugLog (test)", +} + +// worldStop provides context from the stop-the-world required by the +// start-the-world. +type worldStop struct { + reason stwReason + startedStopping int64 + finishedStopping int64 + stoppingCPUTime int64 +} + +// Temporary variable for stopTheWorld, when it can't write to the stack. +// +// Protected by worldsema. +var stopTheWorldContext worldStop + +// stopTheWorld stops all P's from executing goroutines, interrupting +// all goroutines at GC safe points and records reason as the reason +// for the stop. On return, only the current goroutine's P is running. +// stopTheWorld must not be called from a system stack and the caller +// must not hold worldsema. The caller must call startTheWorld when +// other P's should resume execution. +// +// stopTheWorld is safe for multiple goroutines to call at the +// same time. Each will execute its own stop, and the stops will +// be serialized. +// +// This is also used by routines that do stack dumps. If the system is +// in panic or being exited, this may not reliably stop all +// goroutines. +// +// Returns the STW context. When starting the world, this context must be +// passed to startTheWorld. +func stopTheWorld(reason stwReason) worldStop { + semacquire(&worldsema) + gp := getg() + gp.m.preemptoff = reason.String() + systemstack(func() { + // Mark the goroutine which called stopTheWorld preemptible so its + // stack may be scanned. + // This lets a mark worker scan us while we try to stop the world + // since otherwise we could get in a mutual preemption deadlock. + // We must not modify anything on the G stack because a stack shrink + // may occur. A stack shrink is otherwise OK though because in order + // to return from this function (and to leave the system stack) we + // must have preempted all goroutines, including any attempting + // to scan our stack, in which case, any stack shrinking will + // have already completed by the time we exit. + // + // N.B. The execution tracer is not aware of this status + // transition and handles it specially based on the + // wait reason. + casGToWaitingForGC(gp, _Grunning, waitReasonStoppingTheWorld) + stopTheWorldContext = stopTheWorldWithSema(reason) // avoid write to stack + casgstatus(gp, _Gwaiting, _Grunning) + }) + return stopTheWorldContext +} + +// startTheWorld undoes the effects of stopTheWorld. +// +// w must be the worldStop returned by stopTheWorld. +func startTheWorld(w worldStop) { + systemstack(func() { startTheWorldWithSema(0, w) }) + + // worldsema must be held over startTheWorldWithSema to ensure + // gomaxprocs cannot change while worldsema is held. + // + // Release worldsema with direct handoff to the next waiter, but + // acquirem so that semrelease1 doesn't try to yield our time. + // + // Otherwise if e.g. ReadMemStats is being called in a loop, + // it might stomp on other attempts to stop the world, such as + // for starting or ending GC. The operation this blocks is + // so heavy-weight that we should just try to be as fair as + // possible here. + // + // We don't want to just allow us to get preempted between now + // and releasing the semaphore because then we keep everyone + // (including, for example, GCs) waiting longer. + mp := acquirem() + mp.preemptoff = "" + semrelease1(&worldsema, true, 0) + releasem(mp) +} + +// stopTheWorldGC has the same effect as stopTheWorld, but blocks +// until the GC is not running. It also blocks a GC from starting +// until startTheWorldGC is called. +func stopTheWorldGC(reason stwReason) worldStop { + semacquire(&gcsema) + return stopTheWorld(reason) +} + +// startTheWorldGC undoes the effects of stopTheWorldGC. +// +// w must be the worldStop returned by stopTheWorld. +func startTheWorldGC(w worldStop) { + startTheWorld(w) + semrelease(&gcsema) +} + +// Holding worldsema grants an M the right to try to stop the world. +var worldsema uint32 = 1 + +// Holding gcsema grants the M the right to block a GC, and blocks +// until the current GC is done. In particular, it prevents gomaxprocs +// from changing concurrently. +// +// TODO(mknyszek): Once gomaxprocs and the execution tracer can handle +// being changed/enabled during a GC, remove this. +var gcsema uint32 = 1 + +// stopTheWorldWithSema is the core implementation of stopTheWorld. +// The caller is responsible for acquiring worldsema and disabling +// preemption first and then should stopTheWorldWithSema on the system +// stack: +// +// semacquire(&worldsema, 0) +// m.preemptoff = "reason" +// var stw worldStop +// systemstack(func() { +// stw = stopTheWorldWithSema(reason) +// }) +// +// When finished, the caller must either call startTheWorld or undo +// these three operations separately: +// +// m.preemptoff = "" +// systemstack(func() { +// now = startTheWorldWithSema(stw) +// }) +// semrelease(&worldsema) +// +// It is allowed to acquire worldsema once and then execute multiple +// startTheWorldWithSema/stopTheWorldWithSema pairs. +// Other P's are able to execute between successive calls to +// startTheWorldWithSema and stopTheWorldWithSema. +// Holding worldsema causes any other goroutines invoking +// stopTheWorld to block. +// +// Returns the STW context. When starting the world, this context must be +// passed to startTheWorldWithSema. +func stopTheWorldWithSema(reason stwReason) worldStop { + trace := traceAcquire() + if trace.ok() { + trace.STWStart(reason) + traceRelease(trace) + } + gp := getg() + + // If we hold a lock, then we won't be able to stop another M + // that is blocked trying to acquire the lock. + if gp.m.locks > 0 { + throw("stopTheWorld: holding locks") + } + + lock(&sched.lock) + start := nanotime() // exclude time waiting for sched.lock from start and total time metrics. + sched.stopwait = gomaxprocs + sched.gcwaiting.Store(true) + preemptall() + // stop current P + gp.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic. + gp.m.p.ptr().gcStopTime = start + sched.stopwait-- + // try to retake all P's in Psyscall status + trace = traceAcquire() + for _, pp := range allp { + s := pp.status + if s == _Psyscall && atomic.Cas(&pp.status, s, _Pgcstop) { + if trace.ok() { + trace.ProcSteal(pp, false) + } + pp.syscalltick++ + pp.gcStopTime = nanotime() + sched.stopwait-- + } + } + if trace.ok() { + traceRelease(trace) + } + + // stop idle P's + now := nanotime() + for { + pp, _ := pidleget(now) + if pp == nil { + break + } + pp.status = _Pgcstop + pp.gcStopTime = nanotime() + sched.stopwait-- + } + wait := sched.stopwait > 0 + unlock(&sched.lock) + + // wait for remaining P's to stop voluntarily + if wait { + for { + // wait for 100us, then try to re-preempt in case of any races + if notetsleep(&sched.stopnote, 100*1000) { + noteclear(&sched.stopnote) + break + } + preemptall() + } + } + + finish := nanotime() + startTime := finish - start + if reason.isGC() { + sched.stwStoppingTimeGC.record(startTime) + } else { + sched.stwStoppingTimeOther.record(startTime) + } + + // Double-check we actually stopped everything, and all the invariants hold. + // Also accumulate all the time spent by each P in _Pgcstop up to the point + // where everything was stopped. This will be accumulated into the total pause + // CPU time by the caller. + stoppingCPUTime := int64(0) + bad := "" + if sched.stopwait != 0 { + bad = "stopTheWorld: not stopped (stopwait != 0)" + } else { + for _, pp := range allp { + if pp.status != _Pgcstop { + bad = "stopTheWorld: not stopped (status != _Pgcstop)" + } + if pp.gcStopTime == 0 && bad == "" { + bad = "stopTheWorld: broken CPU time accounting" + } + stoppingCPUTime += finish - pp.gcStopTime + pp.gcStopTime = 0 + } + } + if freezing.Load() { + // Some other thread is panicking. This can cause the + // sanity checks above to fail if the panic happens in + // the signal handler on a stopped thread. Either way, + // we should halt this thread. + lock(&deadlock) + lock(&deadlock) + } + if bad != "" { + throw(bad) + } + + worldStopped() + + return worldStop{ + reason: reason, + startedStopping: start, + finishedStopping: finish, + stoppingCPUTime: stoppingCPUTime, + } +} + +// reason is the same STW reason passed to stopTheWorld. start is the start +// time returned by stopTheWorld. +// +// now is the current time; prefer to pass 0 to capture a fresh timestamp. +// +// stattTheWorldWithSema returns now. +func startTheWorldWithSema(now int64, w worldStop) int64 { + assertWorldStopped() + + mp := acquirem() // disable preemption because it can be holding p in a local var + if netpollinited() { + list, delta := netpoll(0) // non-blocking + injectglist(&list) + netpollAdjustWaiters(delta) + } + lock(&sched.lock) + + procs := gomaxprocs + if newprocs != 0 { + procs = newprocs + newprocs = 0 + } + p1 := procresize(procs) + sched.gcwaiting.Store(false) + if sched.sysmonwait.Load() { + sched.sysmonwait.Store(false) + notewakeup(&sched.sysmonnote) + } + unlock(&sched.lock) + + worldStarted() + + for p1 != nil { + p := p1 + p1 = p1.link.ptr() + if p.m != 0 { + mp := p.m.ptr() + p.m = 0 + if mp.nextp != 0 { + throw("startTheWorld: inconsistent mp->nextp") + } + mp.nextp.set(p) + notewakeup(&mp.park) + } else { + // Start M to run P. Do not start another M below. + newm(nil, p, -1) + } + } + + // Capture start-the-world time before doing clean-up tasks. + if now == 0 { + now = nanotime() + } + totalTime := now - w.startedStopping + if w.reason.isGC() { + sched.stwTotalTimeGC.record(totalTime) + } else { + sched.stwTotalTimeOther.record(totalTime) + } + trace := traceAcquire() + if trace.ok() { + trace.STWDone() + traceRelease(trace) + } + + // Wakeup an additional proc in case we have excessive runnable goroutines + // in local queues or in the global queue. If we don't, the proc will park itself. + // If we have lots of excessive work, resetspinning will unpark additional procs as necessary. + wakep() + + releasem(mp) + + return now +} + +// usesLibcall indicates whether this runtime performs system calls +// via libcall. +func usesLibcall() bool { + switch GOOS { + case "aix", "darwin", "illumos", "ios", "solaris", "windows": + return true + case "openbsd": + return GOARCH != "mips64" + } + return false +} + +// mStackIsSystemAllocated indicates whether this runtime starts on a +// system-allocated stack. +func mStackIsSystemAllocated() bool { + switch GOOS { + case "aix", "darwin", "plan9", "illumos", "ios", "solaris", "windows": + return true + case "openbsd": + return GOARCH != "mips64" + } + return false +} + +// mstart is the entry-point for new Ms. +// It is written in assembly, uses ABI0, is marked TOPFRAME, and calls mstart0. +func mstart() + +// mstart0 is the Go entry-point for new Ms. +// This must not split the stack because we may not even have stack +// bounds set up yet. +// +// May run during STW (because it doesn't have a P yet), so write +// barriers are not allowed. +// +//go:nosplit +//go:nowritebarrierrec +func mstart0() { + gp := getg() + + osStack := gp.stack.lo == 0 + if osStack { + // Initialize stack bounds from system stack. + // Cgo may have left stack size in stack.hi. + // minit may update the stack bounds. + // + // Note: these bounds may not be very accurate. + // We set hi to &size, but there are things above + // it. The 1024 is supposed to compensate this, + // but is somewhat arbitrary. + size := gp.stack.hi + if size == 0 { + size = 16384 * sys.StackGuardMultiplier + } + gp.stack.hi = uintptr(noescape(unsafe.Pointer(&size))) + gp.stack.lo = gp.stack.hi - size + 1024 + } + // Initialize stack guard so that we can start calling regular + // Go code. + gp.stackguard0 = gp.stack.lo + stackGuard + // This is the g0, so we can also call go:systemstack + // functions, which check stackguard1. + gp.stackguard1 = gp.stackguard0 + mstart1() + + // Exit this thread. + if mStackIsSystemAllocated() { + // Windows, Solaris, illumos, Darwin, AIX and Plan 9 always system-allocate + // the stack, but put it in gp.stack before mstart, + // so the logic above hasn't set osStack yet. + osStack = true + } + mexit(osStack) +} + +// The go:noinline is to guarantee the getcallerpc/getcallersp below are safe, +// so that we can set up g0.sched to return to the call of mstart1 above. +// +//go:noinline +func mstart1() { + gp := getg() + + if gp != gp.m.g0 { + throw("bad runtime·mstart") + } + + // Set up m.g0.sched as a label returning to just + // after the mstart1 call in mstart0 above, for use by goexit0 and mcall. + // We're never coming back to mstart1 after we call schedule, + // so other calls can reuse the current frame. + // And goexit0 does a gogo that needs to return from mstart1 + // and let mstart0 exit the thread. + gp.sched.g = guintptr(unsafe.Pointer(gp)) + gp.sched.pc = getcallerpc() + gp.sched.sp = getcallersp() + + asminit() + minit() + + // Install signal handlers; after minit so that minit can + // prepare the thread to be able to handle the signals. + if gp.m == &m0 { + mstartm0() + } + + if fn := gp.m.mstartfn; fn != nil { + fn() + } + + if gp.m != &m0 { + acquirep(gp.m.nextp.ptr()) + gp.m.nextp = 0 + } + schedule() +} + +// mstartm0 implements part of mstart1 that only runs on the m0. +// +// Write barriers are allowed here because we know the GC can't be +// running yet, so they'll be no-ops. +// +//go:yeswritebarrierrec +func mstartm0() { + // Create an extra M for callbacks on threads not created by Go. + // An extra M is also needed on Windows for callbacks created by + // syscall.NewCallback. See issue #6751 for details. + if (iscgo || GOOS == "windows") && !cgoHasExtraM { + cgoHasExtraM = true + newextram() + } + initsig(false) +} + +// mPark causes a thread to park itself, returning once woken. +// +//go:nosplit +func mPark() { + gp := getg() + notesleep(&gp.m.park) + noteclear(&gp.m.park) +} + +// mexit tears down and exits the current thread. +// +// Don't call this directly to exit the thread, since it must run at +// the top of the thread stack. Instead, use gogo(&gp.m.g0.sched) to +// unwind the stack to the point that exits the thread. +// +// It is entered with m.p != nil, so write barriers are allowed. It +// will release the P before exiting. +// +//go:yeswritebarrierrec +func mexit(osStack bool) { + mp := getg().m + + if mp == &m0 { + // This is the main thread. Just wedge it. + // + // On Linux, exiting the main thread puts the process + // into a non-waitable zombie state. On Plan 9, + // exiting the main thread unblocks wait even though + // other threads are still running. On Solaris we can + // neither exitThread nor return from mstart. Other + // bad things probably happen on other platforms. + // + // We could try to clean up this M more before wedging + // it, but that complicates signal handling. + handoffp(releasep()) + lock(&sched.lock) + sched.nmfreed++ + checkdead() + unlock(&sched.lock) + mPark() + throw("locked m0 woke up") + } + + sigblock(true) + unminit() + + // Free the gsignal stack. + if mp.gsignal != nil { + stackfree(mp.gsignal.stack) + // On some platforms, when calling into VDSO (e.g. nanotime) + // we store our g on the gsignal stack, if there is one. + // Now the stack is freed, unlink it from the m, so we + // won't write to it when calling VDSO code. + mp.gsignal = nil + } + + // Remove m from allm. + lock(&sched.lock) + for pprev := &allm; *pprev != nil; pprev = &(*pprev).alllink { + if *pprev == mp { + *pprev = mp.alllink + goto found + } + } + throw("m not found in allm") +found: + // Events must not be traced after this point. + + // Delay reaping m until it's done with the stack. + // + // Put mp on the free list, though it will not be reaped while freeWait + // is freeMWait. mp is no longer reachable via allm, so even if it is + // on an OS stack, we must keep a reference to mp alive so that the GC + // doesn't free mp while we are still using it. + // + // Note that the free list must not be linked through alllink because + // some functions walk allm without locking, so may be using alllink. + // + // N.B. It's important that the M appears on the free list simultaneously + // with it being removed so that the tracer can find it. + mp.freeWait.Store(freeMWait) + mp.freelink = sched.freem + sched.freem = mp + unlock(&sched.lock) + + atomic.Xadd64(&ncgocall, int64(mp.ncgocall)) + sched.totalRuntimeLockWaitTime.Add(mp.mLockProfile.waitTime.Load()) + + // Release the P. + handoffp(releasep()) + // After this point we must not have write barriers. + + // Invoke the deadlock detector. This must happen after + // handoffp because it may have started a new M to take our + // P's work. + lock(&sched.lock) + sched.nmfreed++ + checkdead() + unlock(&sched.lock) + + if GOOS == "darwin" || GOOS == "ios" { + // Make sure pendingPreemptSignals is correct when an M exits. + // For #41702. + if mp.signalPending.Load() != 0 { + pendingPreemptSignals.Add(-1) + } + } + + // Destroy all allocated resources. After this is called, we may no + // longer take any locks. + mdestroy(mp) + + if osStack { + // No more uses of mp, so it is safe to drop the reference. + mp.freeWait.Store(freeMRef) + + // Return from mstart and let the system thread + // library free the g0 stack and terminate the thread. + return + } + + // mstart is the thread's entry point, so there's nothing to + // return to. Exit the thread directly. exitThread will clear + // m.freeWait when it's done with the stack and the m can be + // reaped. + exitThread(&mp.freeWait) +} + +// forEachP calls fn(p) for every P p when p reaches a GC safe point. +// If a P is currently executing code, this will bring the P to a GC +// safe point and execute fn on that P. If the P is not executing code +// (it is idle or in a syscall), this will call fn(p) directly while +// preventing the P from exiting its state. This does not ensure that +// fn will run on every CPU executing Go code, but it acts as a global +// memory barrier. GC uses this as a "ragged barrier." +// +// The caller must hold worldsema. fn must not refer to any +// part of the current goroutine's stack, since the GC may move it. +func forEachP(reason waitReason, fn func(*p)) { + systemstack(func() { + gp := getg().m.curg + // Mark the user stack as preemptible so that it may be scanned. + // Otherwise, our attempt to force all P's to a safepoint could + // result in a deadlock as we attempt to preempt a worker that's + // trying to preempt us (e.g. for a stack scan). + // + // N.B. The execution tracer is not aware of this status + // transition and handles it specially based on the + // wait reason. + casGToWaitingForGC(gp, _Grunning, reason) + forEachPInternal(fn) + casgstatus(gp, _Gwaiting, _Grunning) + }) +} + +// forEachPInternal calls fn(p) for every P p when p reaches a GC safe point. +// It is the internal implementation of forEachP. +// +// The caller must hold worldsema and either must ensure that a GC is not +// running (otherwise this may deadlock with the GC trying to preempt this P) +// or it must leave its goroutine in a preemptible state before it switches +// to the systemstack. Due to these restrictions, prefer forEachP when possible. +// +//go:systemstack +func forEachPInternal(fn func(*p)) { + mp := acquirem() + pp := getg().m.p.ptr() + + lock(&sched.lock) + if sched.safePointWait != 0 { + throw("forEachP: sched.safePointWait != 0") + } + sched.safePointWait = gomaxprocs - 1 + sched.safePointFn = fn + + // Ask all Ps to run the safe point function. + for _, p2 := range allp { + if p2 != pp { + atomic.Store(&p2.runSafePointFn, 1) + } + } + preemptall() + + // Any P entering _Pidle or _Psyscall from now on will observe + // p.runSafePointFn == 1 and will call runSafePointFn when + // changing its status to _Pidle/_Psyscall. + + // Run safe point function for all idle Ps. sched.pidle will + // not change because we hold sched.lock. + for p := sched.pidle.ptr(); p != nil; p = p.link.ptr() { + if atomic.Cas(&p.runSafePointFn, 1, 0) { + fn(p) + sched.safePointWait-- + } + } + + wait := sched.safePointWait > 0 + unlock(&sched.lock) + + // Run fn for the current P. + fn(pp) + + // Force Ps currently in _Psyscall into _Pidle and hand them + // off to induce safe point function execution. + for _, p2 := range allp { + s := p2.status + + // We need to be fine-grained about tracing here, since handoffp + // might call into the tracer, and the tracer is non-reentrant. + trace := traceAcquire() + if s == _Psyscall && p2.runSafePointFn == 1 && atomic.Cas(&p2.status, s, _Pidle) { + if trace.ok() { + // It's important that we traceRelease before we call handoffp, which may also traceAcquire. + trace.ProcSteal(p2, false) + traceRelease(trace) + } + p2.syscalltick++ + handoffp(p2) + } else if trace.ok() { + traceRelease(trace) + } + } + + // Wait for remaining Ps to run fn. + if wait { + for { + // Wait for 100us, then try to re-preempt in + // case of any races. + // + // Requires system stack. + if notetsleep(&sched.safePointNote, 100*1000) { + noteclear(&sched.safePointNote) + break + } + preemptall() + } + } + if sched.safePointWait != 0 { + throw("forEachP: not done") + } + for _, p2 := range allp { + if p2.runSafePointFn != 0 { + throw("forEachP: P did not run fn") + } + } + + lock(&sched.lock) + sched.safePointFn = nil + unlock(&sched.lock) + releasem(mp) +} + +// runSafePointFn runs the safe point function, if any, for this P. +// This should be called like +// +// if getg().m.p.runSafePointFn != 0 { +// runSafePointFn() +// } +// +// runSafePointFn must be checked on any transition in to _Pidle or +// _Psyscall to avoid a race where forEachP sees that the P is running +// just before the P goes into _Pidle/_Psyscall and neither forEachP +// nor the P run the safe-point function. +func runSafePointFn() { + p := getg().m.p.ptr() + // Resolve the race between forEachP running the safe-point + // function on this P's behalf and this P running the + // safe-point function directly. + if !atomic.Cas(&p.runSafePointFn, 1, 0) { + return + } + sched.safePointFn(p) + lock(&sched.lock) + sched.safePointWait-- + if sched.safePointWait == 0 { + notewakeup(&sched.safePointNote) + } + unlock(&sched.lock) +} + +// When running with cgo, we call _cgo_thread_start +// to start threads for us so that we can play nicely with +// foreign code. +var cgoThreadStart unsafe.Pointer + +type cgothreadstart struct { + g guintptr + tls *uint64 + fn unsafe.Pointer +} + +// Allocate a new m unassociated with any thread. +// Can use p for allocation context if needed. +// fn is recorded as the new m's m.mstartfn. +// id is optional pre-allocated m ID. Omit by passing -1. +// +// This function is allowed to have write barriers even if the caller +// isn't because it borrows pp. +// +//go:yeswritebarrierrec +func allocm(pp *p, fn func(), id int64) *m { + allocmLock.rlock() + + // The caller owns pp, but we may borrow (i.e., acquirep) it. We must + // disable preemption to ensure it is not stolen, which would make the + // caller lose ownership. + acquirem() + + gp := getg() + if gp.m.p == 0 { + acquirep(pp) // temporarily borrow p for mallocs in this function + } + + // Release the free M list. We need to do this somewhere and + // this may free up a stack we can use. + if sched.freem != nil { + lock(&sched.lock) + var newList *m + for freem := sched.freem; freem != nil; { + // Wait for freeWait to indicate that freem's stack is unused. + wait := freem.freeWait.Load() + if wait == freeMWait { + next := freem.freelink + freem.freelink = newList + newList = freem + freem = next + continue + } + // Drop any remaining trace resources. + // Ms can continue to emit events all the way until wait != freeMWait, + // so it's only safe to call traceThreadDestroy at this point. + if traceEnabled() || traceShuttingDown() { + traceThreadDestroy(freem) + } + // Free the stack if needed. For freeMRef, there is + // nothing to do except drop freem from the sched.freem + // list. + if wait == freeMStack { + // stackfree must be on the system stack, but allocm is + // reachable off the system stack transitively from + // startm. + systemstack(func() { + stackfree(freem.g0.stack) + }) + } + freem = freem.freelink + } + sched.freem = newList + unlock(&sched.lock) + } + + mp := new(m) + mp.mstartfn = fn + mcommoninit(mp, id) + + // In case of cgo or Solaris or illumos or Darwin, pthread_create will make us a stack. + // Windows and Plan 9 will layout sched stack on OS stack. + if iscgo || mStackIsSystemAllocated() { + mp.g0 = malg(-1) + } else { + mp.g0 = malg(16384 * sys.StackGuardMultiplier) + } + mp.g0.m = mp + + if pp == gp.m.p.ptr() { + releasep() + } + + releasem(gp.m) + allocmLock.runlock() + return mp +} + +// needm is called when a cgo callback happens on a +// thread without an m (a thread not created by Go). +// In this case, needm is expected to find an m to use +// and return with m, g initialized correctly. +// Since m and g are not set now (likely nil, but see below) +// needm is limited in what routines it can call. In particular +// it can only call nosplit functions (textflag 7) and cannot +// do any scheduling that requires an m. +// +// In order to avoid needing heavy lifting here, we adopt +// the following strategy: there is a stack of available m's +// that can be stolen. Using compare-and-swap +// to pop from the stack has ABA races, so we simulate +// a lock by doing an exchange (via Casuintptr) to steal the stack +// head and replace the top pointer with MLOCKED (1). +// This serves as a simple spin lock that we can use even +// without an m. The thread that locks the stack in this way +// unlocks the stack by storing a valid stack head pointer. +// +// In order to make sure that there is always an m structure +// available to be stolen, we maintain the invariant that there +// is always one more than needed. At the beginning of the +// program (if cgo is in use) the list is seeded with a single m. +// If needm finds that it has taken the last m off the list, its job +// is - once it has installed its own m so that it can do things like +// allocate memory - to create a spare m and put it on the list. +// +// Each of these extra m's also has a g0 and a curg that are +// pressed into service as the scheduling stack and current +// goroutine for the duration of the cgo callback. +// +// It calls dropm to put the m back on the list, +// 1. when the callback is done with the m in non-pthread platforms, +// 2. or when the C thread exiting on pthread platforms. +// +// The signal argument indicates whether we're called from a signal +// handler. +// +//go:nosplit +func needm(signal bool) { + if (iscgo || GOOS == "windows") && !cgoHasExtraM { + // Can happen if C/C++ code calls Go from a global ctor. + // Can also happen on Windows if a global ctor uses a + // callback created by syscall.NewCallback. See issue #6751 + // for details. + // + // Can not throw, because scheduler is not initialized yet. + writeErrStr("fatal error: cgo callback before cgo call\n") + exit(1) + } + + // Save and block signals before getting an M. + // The signal handler may call needm itself, + // and we must avoid a deadlock. Also, once g is installed, + // any incoming signals will try to execute, + // but we won't have the sigaltstack settings and other data + // set up appropriately until the end of minit, which will + // unblock the signals. This is the same dance as when + // starting a new m to run Go code via newosproc. + var sigmask sigset + sigsave(&sigmask) + sigblock(false) + + // getExtraM is safe here because of the invariant above, + // that the extra list always contains or will soon contain + // at least one m. + mp, last := getExtraM() + + // Set needextram when we've just emptied the list, + // so that the eventual call into cgocallbackg will + // allocate a new m for the extra list. We delay the + // allocation until then so that it can be done + // after exitsyscall makes sure it is okay to be + // running at all (that is, there's no garbage collection + // running right now). + mp.needextram = last + + // Store the original signal mask for use by minit. + mp.sigmask = sigmask + + // Install TLS on some platforms (previously setg + // would do this if necessary). + osSetupTLS(mp) + + // Install g (= m->g0) and set the stack bounds + // to match the current stack. + setg(mp.g0) + sp := getcallersp() + callbackUpdateSystemStack(mp, sp, signal) + + // Should mark we are already in Go now. + // Otherwise, we may call needm again when we get a signal, before cgocallbackg1, + // which means the extram list may be empty, that will cause a deadlock. + mp.isExtraInC = false + + // Initialize this thread to use the m. + asminit() + minit() + + // Emit a trace event for this dead -> syscall transition, + // but only if we're not in a signal handler. + // + // N.B. the tracer can run on a bare M just fine, we just have + // to make sure to do this before setg(nil) and unminit. + var trace traceLocker + if !signal { + trace = traceAcquire() + } + + // mp.curg is now a real goroutine. + casgstatus(mp.curg, _Gdead, _Gsyscall) + sched.ngsys.Add(-1) + + if !signal { + if trace.ok() { + trace.GoCreateSyscall(mp.curg) + traceRelease(trace) + } + } + mp.isExtraInSig = signal +} + +// Acquire an extra m and bind it to the C thread when a pthread key has been created. +// +//go:nosplit +func needAndBindM() { + needm(false) + + if _cgo_pthread_key_created != nil && *(*uintptr)(_cgo_pthread_key_created) != 0 { + cgoBindM() + } +} + +// newextram allocates m's and puts them on the extra list. +// It is called with a working local m, so that it can do things +// like call schedlock and allocate. +func newextram() { + c := extraMWaiters.Swap(0) + if c > 0 { + for i := uint32(0); i < c; i++ { + oneNewExtraM() + } + } else if extraMLength.Load() == 0 { + // Make sure there is at least one extra M. + oneNewExtraM() + } +} + +// oneNewExtraM allocates an m and puts it on the extra list. +func oneNewExtraM() { + // Create extra goroutine locked to extra m. + // The goroutine is the context in which the cgo callback will run. + // The sched.pc will never be returned to, but setting it to + // goexit makes clear to the traceback routines where + // the goroutine stack ends. + mp := allocm(nil, nil, -1) + gp := malg(4096) + gp.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum + gp.sched.sp = gp.stack.hi + gp.sched.sp -= 4 * goarch.PtrSize // extra space in case of reads slightly beyond frame + gp.sched.lr = 0 + gp.sched.g = guintptr(unsafe.Pointer(gp)) + gp.syscallpc = gp.sched.pc + gp.syscallsp = gp.sched.sp + gp.stktopsp = gp.sched.sp + // malg returns status as _Gidle. Change to _Gdead before + // adding to allg where GC can see it. We use _Gdead to hide + // this from tracebacks and stack scans since it isn't a + // "real" goroutine until needm grabs it. + casgstatus(gp, _Gidle, _Gdead) + gp.m = mp + mp.curg = gp + mp.isextra = true + // mark we are in C by default. + mp.isExtraInC = true + mp.lockedInt++ + mp.lockedg.set(gp) + gp.lockedm.set(mp) + gp.goid = sched.goidgen.Add(1) + if raceenabled { + gp.racectx = racegostart(abi.FuncPCABIInternal(newextram) + sys.PCQuantum) + } + // put on allg for garbage collector + allgadd(gp) + + // gp is now on the allg list, but we don't want it to be + // counted by gcount. It would be more "proper" to increment + // sched.ngfree, but that requires locking. Incrementing ngsys + // has the same effect. + sched.ngsys.Add(1) + + // Add m to the extra list. + addExtraM(mp) +} + +// dropm puts the current m back onto the extra list. +// +// 1. On systems without pthreads, like Windows +// dropm is called when a cgo callback has called needm but is now +// done with the callback and returning back into the non-Go thread. +// +// The main expense here is the call to signalstack to release the +// m's signal stack, and then the call to needm on the next callback +// from this thread. It is tempting to try to save the m for next time, +// which would eliminate both these costs, but there might not be +// a next time: the current thread (which Go does not control) might exit. +// If we saved the m for that thread, there would be an m leak each time +// such a thread exited. Instead, we acquire and release an m on each +// call. These should typically not be scheduling operations, just a few +// atomics, so the cost should be small. +// +// 2. On systems with pthreads +// dropm is called while a non-Go thread is exiting. +// We allocate a pthread per-thread variable using pthread_key_create, +// to register a thread-exit-time destructor. +// And store the g into a thread-specific value associated with the pthread key, +// when first return back to C. +// So that the destructor would invoke dropm while the non-Go thread is exiting. +// This is much faster since it avoids expensive signal-related syscalls. +// +// This always runs without a P, so //go:nowritebarrierrec is required. +// +// This may run with a different stack than was recorded in g0 (there is no +// call to callbackUpdateSystemStack prior to dropm), so this must be +// //go:nosplit to avoid the stack bounds check. +// +//go:nowritebarrierrec +//go:nosplit +func dropm() { + // Clear m and g, and return m to the extra list. + // After the call to setg we can only call nosplit functions + // with no pointer manipulation. + mp := getg().m + + // Emit a trace event for this syscall -> dead transition. + // + // N.B. the tracer can run on a bare M just fine, we just have + // to make sure to do this before setg(nil) and unminit. + var trace traceLocker + if !mp.isExtraInSig { + trace = traceAcquire() + } + + // Return mp.curg to dead state. + casgstatus(mp.curg, _Gsyscall, _Gdead) + mp.curg.preemptStop = false + sched.ngsys.Add(1) + + if !mp.isExtraInSig { + if trace.ok() { + trace.GoDestroySyscall() + traceRelease(trace) + } + } + + // Trash syscalltick so that it doesn't line up with mp.old.syscalltick anymore. + // + // In the new tracer, we model needm and dropm and a goroutine being created and + // destroyed respectively. The m then might get reused with a different procid but + // still with a reference to oldp, and still with the same syscalltick. The next + // time a G is "created" in needm, it'll return and quietly reacquire its P from a + // different m with a different procid, which will confuse the trace parser. By + // trashing syscalltick, we ensure that it'll appear as if we lost the P to the + // tracer parser and that we just reacquired it. + // + // Trash the value by decrementing because that gets us as far away from the value + // the syscall exit code expects as possible. Setting to zero is risky because + // syscalltick could already be zero (and in fact, is initialized to zero). + mp.syscalltick-- + + // Reset trace state unconditionally. This goroutine is being 'destroyed' + // from the perspective of the tracer. + mp.curg.trace.reset() + + // Flush all the M's buffers. This is necessary because the M might + // be used on a different thread with a different procid, so we have + // to make sure we don't write into the same buffer. + if traceEnabled() || traceShuttingDown() { + // Acquire sched.lock across thread destruction. One of the invariants of the tracer + // is that a thread cannot disappear from the tracer's view (allm or freem) without + // it noticing, so it requires that sched.lock be held over traceThreadDestroy. + // + // This isn't strictly necessary in this case, because this thread never leaves allm, + // but the critical section is short and dropm is rare on pthread platforms, so just + // take the lock and play it safe. traceThreadDestroy also asserts that the lock is held. + lock(&sched.lock) + traceThreadDestroy(mp) + unlock(&sched.lock) + } + mp.isExtraInSig = false + + // Block signals before unminit. + // Unminit unregisters the signal handling stack (but needs g on some systems). + // Setg(nil) clears g, which is the signal handler's cue not to run Go handlers. + // It's important not to try to handle a signal between those two steps. + sigmask := mp.sigmask + sigblock(false) + unminit() + + setg(nil) + + // Clear g0 stack bounds to ensure that needm always refreshes the + // bounds when reusing this M. + g0 := mp.g0 + g0.stack.hi = 0 + g0.stack.lo = 0 + g0.stackguard0 = 0 + g0.stackguard1 = 0 + mp.g0StackAccurate = false + + putExtraM(mp) + + msigrestore(sigmask) +} + +// bindm store the g0 of the current m into a thread-specific value. +// +// We allocate a pthread per-thread variable using pthread_key_create, +// to register a thread-exit-time destructor. +// We are here setting the thread-specific value of the pthread key, to enable the destructor. +// So that the pthread_key_destructor would dropm while the C thread is exiting. +// +// And the saved g will be used in pthread_key_destructor, +// since the g stored in the TLS by Go might be cleared in some platforms, +// before the destructor invoked, so, we restore g by the stored g, before dropm. +// +// We store g0 instead of m, to make the assembly code simpler, +// since we need to restore g0 in runtime.cgocallback. +// +// On systems without pthreads, like Windows, bindm shouldn't be used. +// +// NOTE: this always runs without a P, so, nowritebarrierrec required. +// +//go:nosplit +//go:nowritebarrierrec +func cgoBindM() { + if GOOS == "windows" || GOOS == "plan9" { + fatal("bindm in unexpected GOOS") + } + g := getg() + if g.m.g0 != g { + fatal("the current g is not g0") + } + if _cgo_bindm != nil { + asmcgocall(_cgo_bindm, unsafe.Pointer(g)) + } +} + +// A helper function for EnsureDropM. +// +// getm should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - fortio.org/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname getm +func getm() uintptr { + return uintptr(unsafe.Pointer(getg().m)) +} + +var ( + // Locking linked list of extra M's, via mp.schedlink. Must be accessed + // only via lockextra/unlockextra. + // + // Can't be atomic.Pointer[m] because we use an invalid pointer as a + // "locked" sentinel value. M's on this list remain visible to the GC + // because their mp.curg is on allgs. + extraM atomic.Uintptr + // Number of M's in the extraM list. + extraMLength atomic.Uint32 + // Number of waiters in lockextra. + extraMWaiters atomic.Uint32 + + // Number of extra M's in use by threads. + extraMInUse atomic.Uint32 +) + +// lockextra locks the extra list and returns the list head. +// The caller must unlock the list by storing a new list head +// to extram. If nilokay is true, then lockextra will +// return a nil list head if that's what it finds. If nilokay is false, +// lockextra will keep waiting until the list head is no longer nil. +// +//go:nosplit +func lockextra(nilokay bool) *m { + const locked = 1 + + incr := false + for { + old := extraM.Load() + if old == locked { + osyield_no_g() + continue + } + if old == 0 && !nilokay { + if !incr { + // Add 1 to the number of threads + // waiting for an M. + // This is cleared by newextram. + extraMWaiters.Add(1) + incr = true + } + usleep_no_g(1) + continue + } + if extraM.CompareAndSwap(old, locked) { + return (*m)(unsafe.Pointer(old)) + } + osyield_no_g() + continue + } +} + +//go:nosplit +func unlockextra(mp *m, delta int32) { + extraMLength.Add(delta) + extraM.Store(uintptr(unsafe.Pointer(mp))) +} + +// Return an M from the extra M list. Returns last == true if the list becomes +// empty because of this call. +// +// Spins waiting for an extra M, so caller must ensure that the list always +// contains or will soon contain at least one M. +// +//go:nosplit +func getExtraM() (mp *m, last bool) { + mp = lockextra(false) + extraMInUse.Add(1) + unlockextra(mp.schedlink.ptr(), -1) + return mp, mp.schedlink.ptr() == nil +} + +// Returns an extra M back to the list. mp must be from getExtraM. Newly +// allocated M's should use addExtraM. +// +//go:nosplit +func putExtraM(mp *m) { + extraMInUse.Add(-1) + addExtraM(mp) +} + +// Adds a newly allocated M to the extra M list. +// +//go:nosplit +func addExtraM(mp *m) { + mnext := lockextra(true) + mp.schedlink.set(mnext) + unlockextra(mp, 1) +} + +var ( + // allocmLock is locked for read when creating new Ms in allocm and their + // addition to allm. Thus acquiring this lock for write blocks the + // creation of new Ms. + allocmLock rwmutex + + // execLock serializes exec and clone to avoid bugs or unspecified + // behaviour around exec'ing while creating/destroying threads. See + // issue #19546. + execLock rwmutex +) + +// These errors are reported (via writeErrStr) by some OS-specific +// versions of newosproc and newosproc0. +const ( + failthreadcreate = "runtime: failed to create new OS thread\n" + failallocatestack = "runtime: failed to allocate stack for the new OS thread\n" +) + +// newmHandoff contains a list of m structures that need new OS threads. +// This is used by newm in situations where newm itself can't safely +// start an OS thread. +var newmHandoff struct { + lock mutex + + // newm points to a list of M structures that need new OS + // threads. The list is linked through m.schedlink. + newm muintptr + + // waiting indicates that wake needs to be notified when an m + // is put on the list. + waiting bool + wake note + + // haveTemplateThread indicates that the templateThread has + // been started. This is not protected by lock. Use cas to set + // to 1. + haveTemplateThread uint32 +} + +// Create a new m. It will start off with a call to fn, or else the scheduler. +// fn needs to be static and not a heap allocated closure. +// May run with m.p==nil, so write barriers are not allowed. +// +// id is optional pre-allocated m ID. Omit by passing -1. +// +//go:nowritebarrierrec +func newm(fn func(), pp *p, id int64) { + // allocm adds a new M to allm, but they do not start until created by + // the OS in newm1 or the template thread. + // + // doAllThreadsSyscall requires that every M in allm will eventually + // start and be signal-able, even with a STW. + // + // Disable preemption here until we start the thread to ensure that + // newm is not preempted between allocm and starting the new thread, + // ensuring that anything added to allm is guaranteed to eventually + // start. + acquirem() + + mp := allocm(pp, fn, id) + mp.nextp.set(pp) + mp.sigmask = initSigmask + if gp := getg(); gp != nil && gp.m != nil && (gp.m.lockedExt != 0 || gp.m.incgo) && GOOS != "plan9" { + // We're on a locked M or a thread that may have been + // started by C. The kernel state of this thread may + // be strange (the user may have locked it for that + // purpose). We don't want to clone that into another + // thread. Instead, ask a known-good thread to create + // the thread for us. + // + // This is disabled on Plan 9. See golang.org/issue/22227. + // + // TODO: This may be unnecessary on Windows, which + // doesn't model thread creation off fork. + lock(&newmHandoff.lock) + if newmHandoff.haveTemplateThread == 0 { + throw("on a locked thread with no template thread") + } + mp.schedlink = newmHandoff.newm + newmHandoff.newm.set(mp) + if newmHandoff.waiting { + newmHandoff.waiting = false + notewakeup(&newmHandoff.wake) + } + unlock(&newmHandoff.lock) + // The M has not started yet, but the template thread does not + // participate in STW, so it will always process queued Ms and + // it is safe to releasem. + releasem(getg().m) + return + } + newm1(mp) + releasem(getg().m) +} + +func newm1(mp *m) { + if iscgo { + var ts cgothreadstart + if _cgo_thread_start == nil { + throw("_cgo_thread_start missing") + } + ts.g.set(mp.g0) + ts.tls = (*uint64)(unsafe.Pointer(&mp.tls[0])) + ts.fn = unsafe.Pointer(abi.FuncPCABI0(mstart)) + if msanenabled { + msanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts)) + } + if asanenabled { + asanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts)) + } + execLock.rlock() // Prevent process clone. + asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts)) + execLock.runlock() + return + } + execLock.rlock() // Prevent process clone. + newosproc(mp) + execLock.runlock() +} + +// startTemplateThread starts the template thread if it is not already +// running. +// +// The calling thread must itself be in a known-good state. +func startTemplateThread() { + if GOARCH == "wasm" { // no threads on wasm yet + return + } + + // Disable preemption to guarantee that the template thread will be + // created before a park once haveTemplateThread is set. + mp := acquirem() + if !atomic.Cas(&newmHandoff.haveTemplateThread, 0, 1) { + releasem(mp) + return + } + newm(templateThread, nil, -1) + releasem(mp) +} + +// templateThread is a thread in a known-good state that exists solely +// to start new threads in known-good states when the calling thread +// may not be in a good state. +// +// Many programs never need this, so templateThread is started lazily +// when we first enter a state that might lead to running on a thread +// in an unknown state. +// +// templateThread runs on an M without a P, so it must not have write +// barriers. +// +//go:nowritebarrierrec +func templateThread() { + lock(&sched.lock) + sched.nmsys++ + checkdead() + unlock(&sched.lock) + + for { + lock(&newmHandoff.lock) + for newmHandoff.newm != 0 { + newm := newmHandoff.newm.ptr() + newmHandoff.newm = 0 + unlock(&newmHandoff.lock) + for newm != nil { + next := newm.schedlink.ptr() + newm.schedlink = 0 + newm1(newm) + newm = next + } + lock(&newmHandoff.lock) + } + newmHandoff.waiting = true + noteclear(&newmHandoff.wake) + unlock(&newmHandoff.lock) + notesleep(&newmHandoff.wake) + } +} + +// Stops execution of the current m until new work is available. +// Returns with acquired P. +func stopm() { + gp := getg() + + if gp.m.locks != 0 { + throw("stopm holding locks") + } + if gp.m.p != 0 { + throw("stopm holding p") + } + if gp.m.spinning { + throw("stopm spinning") + } + + lock(&sched.lock) + mput(gp.m) + unlock(&sched.lock) + mPark() + acquirep(gp.m.nextp.ptr()) + gp.m.nextp = 0 +} + +func mspinning() { + // startm's caller incremented nmspinning. Set the new M's spinning. + getg().m.spinning = true +} + +// Schedules some M to run the p (creates an M if necessary). +// If p==nil, tries to get an idle P, if no idle P's does nothing. +// May run with m.p==nil, so write barriers are not allowed. +// If spinning is set, the caller has incremented nmspinning and must provide a +// P. startm will set m.spinning in the newly started M. +// +// Callers passing a non-nil P must call from a non-preemptible context. See +// comment on acquirem below. +// +// Argument lockheld indicates whether the caller already acquired the +// scheduler lock. Callers holding the lock when making the call must pass +// true. The lock might be temporarily dropped, but will be reacquired before +// returning. +// +// Must not have write barriers because this may be called without a P. +// +//go:nowritebarrierrec +func startm(pp *p, spinning, lockheld bool) { + // Disable preemption. + // + // Every owned P must have an owner that will eventually stop it in the + // event of a GC stop request. startm takes transient ownership of a P + // (either from argument or pidleget below) and transfers ownership to + // a started M, which will be responsible for performing the stop. + // + // Preemption must be disabled during this transient ownership, + // otherwise the P this is running on may enter GC stop while still + // holding the transient P, leaving that P in limbo and deadlocking the + // STW. + // + // Callers passing a non-nil P must already be in non-preemptible + // context, otherwise such preemption could occur on function entry to + // startm. Callers passing a nil P may be preemptible, so we must + // disable preemption before acquiring a P from pidleget below. + mp := acquirem() + if !lockheld { + lock(&sched.lock) + } + if pp == nil { + if spinning { + // TODO(prattmic): All remaining calls to this function + // with _p_ == nil could be cleaned up to find a P + // before calling startm. + throw("startm: P required for spinning=true") + } + pp, _ = pidleget(0) + if pp == nil { + if !lockheld { + unlock(&sched.lock) + } + releasem(mp) + return + } + } + nmp := mget() + if nmp == nil { + // No M is available, we must drop sched.lock and call newm. + // However, we already own a P to assign to the M. + // + // Once sched.lock is released, another G (e.g., in a syscall), + // could find no idle P while checkdead finds a runnable G but + // no running M's because this new M hasn't started yet, thus + // throwing in an apparent deadlock. + // This apparent deadlock is possible when startm is called + // from sysmon, which doesn't count as a running M. + // + // Avoid this situation by pre-allocating the ID for the new M, + // thus marking it as 'running' before we drop sched.lock. This + // new M will eventually run the scheduler to execute any + // queued G's. + id := mReserveID() + unlock(&sched.lock) + + var fn func() + if spinning { + // The caller incremented nmspinning, so set m.spinning in the new M. + fn = mspinning + } + newm(fn, pp, id) + + if lockheld { + lock(&sched.lock) + } + // Ownership transfer of pp committed by start in newm. + // Preemption is now safe. + releasem(mp) + return + } + if !lockheld { + unlock(&sched.lock) + } + if nmp.spinning { + throw("startm: m is spinning") + } + if nmp.nextp != 0 { + throw("startm: m has p") + } + if spinning && !runqempty(pp) { + throw("startm: p has runnable gs") + } + // The caller incremented nmspinning, so set m.spinning in the new M. + nmp.spinning = spinning + nmp.nextp.set(pp) + notewakeup(&nmp.park) + // Ownership transfer of pp committed by wakeup. Preemption is now + // safe. + releasem(mp) +} + +// Hands off P from syscall or locked M. +// Always runs without a P, so write barriers are not allowed. +// +//go:nowritebarrierrec +func handoffp(pp *p) { + // handoffp must start an M in any situation where + // findrunnable would return a G to run on pp. + + // if it has local work, start it straight away + if !runqempty(pp) || sched.runqsize != 0 { + startm(pp, false, false) + return + } + // if there's trace work to do, start it straight away + if (traceEnabled() || traceShuttingDown()) && traceReaderAvailable() != nil { + startm(pp, false, false) + return + } + // if it has GC work, start it straight away + if gcBlackenEnabled != 0 && gcMarkWorkAvailable(pp) { + startm(pp, false, false) + return + } + // no local work, check that there are no spinning/idle M's, + // otherwise our help is not required + if sched.nmspinning.Load()+sched.npidle.Load() == 0 && sched.nmspinning.CompareAndSwap(0, 1) { // TODO: fast atomic + sched.needspinning.Store(0) + startm(pp, true, false) + return + } + lock(&sched.lock) + if sched.gcwaiting.Load() { + pp.status = _Pgcstop + pp.gcStopTime = nanotime() + sched.stopwait-- + if sched.stopwait == 0 { + notewakeup(&sched.stopnote) + } + unlock(&sched.lock) + return + } + if pp.runSafePointFn != 0 && atomic.Cas(&pp.runSafePointFn, 1, 0) { + sched.safePointFn(pp) + sched.safePointWait-- + if sched.safePointWait == 0 { + notewakeup(&sched.safePointNote) + } + } + if sched.runqsize != 0 { + unlock(&sched.lock) + startm(pp, false, false) + return + } + // If this is the last running P and nobody is polling network, + // need to wakeup another M to poll network. + if sched.npidle.Load() == gomaxprocs-1 && sched.lastpoll.Load() != 0 { + unlock(&sched.lock) + startm(pp, false, false) + return + } + + // The scheduler lock cannot be held when calling wakeNetPoller below + // because wakeNetPoller may call wakep which may call startm. + when := pp.timers.wakeTime() + pidleput(pp, 0) + unlock(&sched.lock) + + if when != 0 { + wakeNetPoller(when) + } +} + +// Tries to add one more P to execute G's. +// Called when a G is made runnable (newproc, ready). +// Must be called with a P. +// +// wakep should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname wakep +func wakep() { + // Be conservative about spinning threads, only start one if none exist + // already. + if sched.nmspinning.Load() != 0 || !sched.nmspinning.CompareAndSwap(0, 1) { + return + } + + // Disable preemption until ownership of pp transfers to the next M in + // startm. Otherwise preemption here would leave pp stuck waiting to + // enter _Pgcstop. + // + // See preemption comment on acquirem in startm for more details. + mp := acquirem() + + var pp *p + lock(&sched.lock) + pp, _ = pidlegetSpinning(0) + if pp == nil { + if sched.nmspinning.Add(-1) < 0 { + throw("wakep: negative nmspinning") + } + unlock(&sched.lock) + releasem(mp) + return + } + // Since we always have a P, the race in the "No M is available" + // comment in startm doesn't apply during the small window between the + // unlock here and lock in startm. A checkdead in between will always + // see at least one running M (ours). + unlock(&sched.lock) + + startm(pp, true, false) + + releasem(mp) +} + +// Stops execution of the current m that is locked to a g until the g is runnable again. +// Returns with acquired P. +func stoplockedm() { + gp := getg() + + if gp.m.lockedg == 0 || gp.m.lockedg.ptr().lockedm.ptr() != gp.m { + throw("stoplockedm: inconsistent locking") + } + if gp.m.p != 0 { + // Schedule another M to run this p. + pp := releasep() + handoffp(pp) + } + incidlelocked(1) + // Wait until another thread schedules lockedg again. + mPark() + status := readgstatus(gp.m.lockedg.ptr()) + if status&^_Gscan != _Grunnable { + print("runtime:stoplockedm: lockedg (atomicstatus=", status, ") is not Grunnable or Gscanrunnable\n") + dumpgstatus(gp.m.lockedg.ptr()) + throw("stoplockedm: not runnable") + } + acquirep(gp.m.nextp.ptr()) + gp.m.nextp = 0 +} + +// Schedules the locked m to run the locked gp. +// May run during STW, so write barriers are not allowed. +// +//go:nowritebarrierrec +func startlockedm(gp *g) { + mp := gp.lockedm.ptr() + if mp == getg().m { + throw("startlockedm: locked to me") + } + if mp.nextp != 0 { + throw("startlockedm: m has p") + } + // directly handoff current P to the locked m + incidlelocked(-1) + pp := releasep() + mp.nextp.set(pp) + notewakeup(&mp.park) + stopm() +} + +// Stops the current m for stopTheWorld. +// Returns when the world is restarted. +func gcstopm() { + gp := getg() + + if !sched.gcwaiting.Load() { + throw("gcstopm: not waiting for gc") + } + if gp.m.spinning { + gp.m.spinning = false + // OK to just drop nmspinning here, + // startTheWorld will unpark threads as necessary. + if sched.nmspinning.Add(-1) < 0 { + throw("gcstopm: negative nmspinning") + } + } + pp := releasep() + lock(&sched.lock) + pp.status = _Pgcstop + pp.gcStopTime = nanotime() + sched.stopwait-- + if sched.stopwait == 0 { + notewakeup(&sched.stopnote) + } + unlock(&sched.lock) + stopm() +} + +// Schedules gp to run on the current M. +// If inheritTime is true, gp inherits the remaining time in the +// current time slice. Otherwise, it starts a new time slice. +// Never returns. +// +// Write barriers are allowed because this is called immediately after +// acquiring a P in several places. +// +//go:yeswritebarrierrec +func execute(gp *g, inheritTime bool) { + mp := getg().m + + if goroutineProfile.active { + // Make sure that gp has had its stack written out to the goroutine + // profile, exactly as it was when the goroutine profiler first stopped + // the world. + tryRecordGoroutineProfile(gp, nil, osyield) + } + + // Assign gp.m before entering _Grunning so running Gs have an + // M. + mp.curg = gp + gp.m = mp + casgstatus(gp, _Grunnable, _Grunning) + gp.waitsince = 0 + gp.preempt = false + gp.stackguard0 = gp.stack.lo + stackGuard + if !inheritTime { + mp.p.ptr().schedtick++ + } + + // Check whether the profiler needs to be turned on or off. + hz := sched.profilehz + if mp.profilehz != hz { + setThreadCPUProfiler(hz) + } + + trace := traceAcquire() + if trace.ok() { + trace.GoStart() + traceRelease(trace) + } + + gogo(&gp.sched) +} + +// Finds a runnable goroutine to execute. +// Tries to steal from other P's, get g from local or global queue, poll network. +// tryWakeP indicates that the returned goroutine is not normal (GC worker, trace +// reader) so the caller should try to wake a P. +func findRunnable() (gp *g, inheritTime, tryWakeP bool) { + mp := getg().m + + // The conditions here and in handoffp must agree: if + // findrunnable would return a G to run, handoffp must start + // an M. + +top: + pp := mp.p.ptr() + if sched.gcwaiting.Load() { + gcstopm() + goto top + } + if pp.runSafePointFn != 0 { + runSafePointFn() + } + + // now and pollUntil are saved for work stealing later, + // which may steal timers. It's important that between now + // and then, nothing blocks, so these numbers remain mostly + // relevant. + now, pollUntil, _ := pp.timers.check(0) + + // Try to schedule the trace reader. + if traceEnabled() || traceShuttingDown() { + gp := traceReader() + if gp != nil { + trace := traceAcquire() + casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 0) + traceRelease(trace) + } + return gp, false, true + } + } + + // Try to schedule a GC worker. + if gcBlackenEnabled != 0 { + gp, tnow := gcController.findRunnableGCWorker(pp, now) + if gp != nil { + return gp, false, true + } + now = tnow + } + + // Check the global runnable queue once in a while to ensure fairness. + // Otherwise two goroutines can completely occupy the local runqueue + // by constantly respawning each other. + if pp.schedtick%61 == 0 && sched.runqsize > 0 { + lock(&sched.lock) + gp := globrunqget(pp, 1) + unlock(&sched.lock) + if gp != nil { + return gp, false, false + } + } + + // Wake up the finalizer G. + if fingStatus.Load()&(fingWait|fingWake) == fingWait|fingWake { + if gp := wakefing(); gp != nil { + ready(gp, 0, true) + } + } + if *cgo_yield != nil { + asmcgocall(*cgo_yield, nil) + } + + // local runq + if gp, inheritTime := runqget(pp); gp != nil { + return gp, inheritTime, false + } + + // global runq + if sched.runqsize != 0 { + lock(&sched.lock) + gp := globrunqget(pp, 0) + unlock(&sched.lock) + if gp != nil { + return gp, false, false + } + } + + // Poll network. + // This netpoll is only an optimization before we resort to stealing. + // We can safely skip it if there are no waiters or a thread is blocked + // in netpoll already. If there is any kind of logical race with that + // blocked thread (e.g. it has already returned from netpoll, but does + // not set lastpoll yet), this thread will do blocking netpoll below + // anyway. + if netpollinited() && netpollAnyWaiters() && sched.lastpoll.Load() != 0 { + if list, delta := netpoll(0); !list.empty() { // non-blocking + gp := list.pop() + injectglist(&list) + netpollAdjustWaiters(delta) + trace := traceAcquire() + casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 0) + traceRelease(trace) + } + return gp, false, false + } + } + + // Spinning Ms: steal work from other Ps. + // + // Limit the number of spinning Ms to half the number of busy Ps. + // This is necessary to prevent excessive CPU consumption when + // GOMAXPROCS>>1 but the program parallelism is low. + if mp.spinning || 2*sched.nmspinning.Load() < gomaxprocs-sched.npidle.Load() { + if !mp.spinning { + mp.becomeSpinning() + } + + gp, inheritTime, tnow, w, newWork := stealWork(now) + if gp != nil { + // Successfully stole. + return gp, inheritTime, false + } + if newWork { + // There may be new timer or GC work; restart to + // discover. + goto top + } + + now = tnow + if w != 0 && (pollUntil == 0 || w < pollUntil) { + // Earlier timer to wait for. + pollUntil = w + } + } + + // We have nothing to do. + // + // If we're in the GC mark phase, can safely scan and blacken objects, + // and have work to do, run idle-time marking rather than give up the P. + if gcBlackenEnabled != 0 && gcMarkWorkAvailable(pp) && gcController.addIdleMarkWorker() { + node := (*gcBgMarkWorkerNode)(gcBgMarkWorkerPool.pop()) + if node != nil { + pp.gcMarkWorkerMode = gcMarkWorkerIdleMode + gp := node.gp.ptr() + + trace := traceAcquire() + casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 0) + traceRelease(trace) + } + return gp, false, false + } + gcController.removeIdleMarkWorker() + } + + // wasm only: + // If a callback returned and no other goroutine is awake, + // then wake event handler goroutine which pauses execution + // until a callback was triggered. + gp, otherReady := beforeIdle(now, pollUntil) + if gp != nil { + trace := traceAcquire() + casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 0) + traceRelease(trace) + } + return gp, false, false + } + if otherReady { + goto top + } + + // Before we drop our P, make a snapshot of the allp slice, + // which can change underfoot once we no longer block + // safe-points. We don't need to snapshot the contents because + // everything up to cap(allp) is immutable. + allpSnapshot := allp + // Also snapshot masks. Value changes are OK, but we can't allow + // len to change out from under us. + idlepMaskSnapshot := idlepMask + timerpMaskSnapshot := timerpMask + + // return P and block + lock(&sched.lock) + if sched.gcwaiting.Load() || pp.runSafePointFn != 0 { + unlock(&sched.lock) + goto top + } + if sched.runqsize != 0 { + gp := globrunqget(pp, 0) + unlock(&sched.lock) + return gp, false, false + } + if !mp.spinning && sched.needspinning.Load() == 1 { + // See "Delicate dance" comment below. + mp.becomeSpinning() + unlock(&sched.lock) + goto top + } + if releasep() != pp { + throw("findrunnable: wrong p") + } + now = pidleput(pp, now) + unlock(&sched.lock) + + // Delicate dance: thread transitions from spinning to non-spinning + // state, potentially concurrently with submission of new work. We must + // drop nmspinning first and then check all sources again (with + // #StoreLoad memory barrier in between). If we do it the other way + // around, another thread can submit work after we've checked all + // sources but before we drop nmspinning; as a result nobody will + // unpark a thread to run the work. + // + // This applies to the following sources of work: + // + // * Goroutines added to the global or a per-P run queue. + // * New/modified-earlier timers on a per-P timer heap. + // * Idle-priority GC work (barring golang.org/issue/19112). + // + // If we discover new work below, we need to restore m.spinning as a + // signal for resetspinning to unpark a new worker thread (because + // there can be more than one starving goroutine). + // + // However, if after discovering new work we also observe no idle Ps + // (either here or in resetspinning), we have a problem. We may be + // racing with a non-spinning M in the block above, having found no + // work and preparing to release its P and park. Allowing that P to go + // idle will result in loss of work conservation (idle P while there is + // runnable work). This could result in complete deadlock in the + // unlikely event that we discover new work (from netpoll) right as we + // are racing with _all_ other Ps going idle. + // + // We use sched.needspinning to synchronize with non-spinning Ms going + // idle. If needspinning is set when they are about to drop their P, + // they abort the drop and instead become a new spinning M on our + // behalf. If we are not racing and the system is truly fully loaded + // then no spinning threads are required, and the next thread to + // naturally become spinning will clear the flag. + // + // Also see "Worker thread parking/unparking" comment at the top of the + // file. + wasSpinning := mp.spinning + if mp.spinning { + mp.spinning = false + if sched.nmspinning.Add(-1) < 0 { + throw("findrunnable: negative nmspinning") + } + + // Note the for correctness, only the last M transitioning from + // spinning to non-spinning must perform these rechecks to + // ensure no missed work. However, the runtime has some cases + // of transient increments of nmspinning that are decremented + // without going through this path, so we must be conservative + // and perform the check on all spinning Ms. + // + // See https://go.dev/issue/43997. + + // Check global and P runqueues again. + + lock(&sched.lock) + if sched.runqsize != 0 { + pp, _ := pidlegetSpinning(0) + if pp != nil { + gp := globrunqget(pp, 0) + if gp == nil { + throw("global runq empty with non-zero runqsize") + } + unlock(&sched.lock) + acquirep(pp) + mp.becomeSpinning() + return gp, false, false + } + } + unlock(&sched.lock) + + pp := checkRunqsNoP(allpSnapshot, idlepMaskSnapshot) + if pp != nil { + acquirep(pp) + mp.becomeSpinning() + goto top + } + + // Check for idle-priority GC work again. + pp, gp := checkIdleGCNoP() + if pp != nil { + acquirep(pp) + mp.becomeSpinning() + + // Run the idle worker. + pp.gcMarkWorkerMode = gcMarkWorkerIdleMode + trace := traceAcquire() + casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 0) + traceRelease(trace) + } + return gp, false, false + } + + // Finally, check for timer creation or expiry concurrently with + // transitioning from spinning to non-spinning. + // + // Note that we cannot use checkTimers here because it calls + // adjusttimers which may need to allocate memory, and that isn't + // allowed when we don't have an active P. + pollUntil = checkTimersNoP(allpSnapshot, timerpMaskSnapshot, pollUntil) + } + + // Poll network until next timer. + if netpollinited() && (netpollAnyWaiters() || pollUntil != 0) && sched.lastpoll.Swap(0) != 0 { + sched.pollUntil.Store(pollUntil) + if mp.p != 0 { + throw("findrunnable: netpoll with p") + } + if mp.spinning { + throw("findrunnable: netpoll with spinning") + } + delay := int64(-1) + if pollUntil != 0 { + if now == 0 { + now = nanotime() + } + delay = pollUntil - now + if delay < 0 { + delay = 0 + } + } + if faketime != 0 { + // When using fake time, just poll. + delay = 0 + } + list, delta := netpoll(delay) // block until new work is available + // Refresh now again, after potentially blocking. + now = nanotime() + sched.pollUntil.Store(0) + sched.lastpoll.Store(now) + if faketime != 0 && list.empty() { + // Using fake time and nothing is ready; stop M. + // When all M's stop, checkdead will call timejump. + stopm() + goto top + } + lock(&sched.lock) + pp, _ := pidleget(now) + unlock(&sched.lock) + if pp == nil { + injectglist(&list) + netpollAdjustWaiters(delta) + } else { + acquirep(pp) + if !list.empty() { + gp := list.pop() + injectglist(&list) + netpollAdjustWaiters(delta) + trace := traceAcquire() + casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 0) + traceRelease(trace) + } + return gp, false, false + } + if wasSpinning { + mp.becomeSpinning() + } + goto top + } + } else if pollUntil != 0 && netpollinited() { + pollerPollUntil := sched.pollUntil.Load() + if pollerPollUntil == 0 || pollerPollUntil > pollUntil { + netpollBreak() + } + } + stopm() + goto top +} + +// pollWork reports whether there is non-background work this P could +// be doing. This is a fairly lightweight check to be used for +// background work loops, like idle GC. It checks a subset of the +// conditions checked by the actual scheduler. +func pollWork() bool { + if sched.runqsize != 0 { + return true + } + p := getg().m.p.ptr() + if !runqempty(p) { + return true + } + if netpollinited() && netpollAnyWaiters() && sched.lastpoll.Load() != 0 { + if list, delta := netpoll(0); !list.empty() { + injectglist(&list) + netpollAdjustWaiters(delta) + return true + } + } + return false +} + +// stealWork attempts to steal a runnable goroutine or timer from any P. +// +// If newWork is true, new work may have been readied. +// +// If now is not 0 it is the current time. stealWork returns the passed time or +// the current time if now was passed as 0. +func stealWork(now int64) (gp *g, inheritTime bool, rnow, pollUntil int64, newWork bool) { + pp := getg().m.p.ptr() + + ranTimer := false + + const stealTries = 4 + for i := 0; i < stealTries; i++ { + stealTimersOrRunNextG := i == stealTries-1 + + for enum := stealOrder.start(cheaprand()); !enum.done(); enum.next() { + if sched.gcwaiting.Load() { + // GC work may be available. + return nil, false, now, pollUntil, true + } + p2 := allp[enum.position()] + if pp == p2 { + continue + } + + // Steal timers from p2. This call to checkTimers is the only place + // where we might hold a lock on a different P's timers. We do this + // once on the last pass before checking runnext because stealing + // from the other P's runnext should be the last resort, so if there + // are timers to steal do that first. + // + // We only check timers on one of the stealing iterations because + // the time stored in now doesn't change in this loop and checking + // the timers for each P more than once with the same value of now + // is probably a waste of time. + // + // timerpMask tells us whether the P may have timers at all. If it + // can't, no need to check at all. + if stealTimersOrRunNextG && timerpMask.read(enum.position()) { + tnow, w, ran := p2.timers.check(now) + now = tnow + if w != 0 && (pollUntil == 0 || w < pollUntil) { + pollUntil = w + } + if ran { + // Running the timers may have + // made an arbitrary number of G's + // ready and added them to this P's + // local run queue. That invalidates + // the assumption of runqsteal + // that it always has room to add + // stolen G's. So check now if there + // is a local G to run. + if gp, inheritTime := runqget(pp); gp != nil { + return gp, inheritTime, now, pollUntil, ranTimer + } + ranTimer = true + } + } + + // Don't bother to attempt to steal if p2 is idle. + if !idlepMask.read(enum.position()) { + if gp := runqsteal(pp, p2, stealTimersOrRunNextG); gp != nil { + return gp, false, now, pollUntil, ranTimer + } + } + } + } + + // No goroutines found to steal. Regardless, running a timer may have + // made some goroutine ready that we missed. Indicate the next timer to + // wait for. + return nil, false, now, pollUntil, ranTimer +} + +// Check all Ps for a runnable G to steal. +// +// On entry we have no P. If a G is available to steal and a P is available, +// the P is returned which the caller should acquire and attempt to steal the +// work to. +func checkRunqsNoP(allpSnapshot []*p, idlepMaskSnapshot pMask) *p { + for id, p2 := range allpSnapshot { + if !idlepMaskSnapshot.read(uint32(id)) && !runqempty(p2) { + lock(&sched.lock) + pp, _ := pidlegetSpinning(0) + if pp == nil { + // Can't get a P, don't bother checking remaining Ps. + unlock(&sched.lock) + return nil + } + unlock(&sched.lock) + return pp + } + } + + // No work available. + return nil +} + +// Check all Ps for a timer expiring sooner than pollUntil. +// +// Returns updated pollUntil value. +func checkTimersNoP(allpSnapshot []*p, timerpMaskSnapshot pMask, pollUntil int64) int64 { + for id, p2 := range allpSnapshot { + if timerpMaskSnapshot.read(uint32(id)) { + w := p2.timers.wakeTime() + if w != 0 && (pollUntil == 0 || w < pollUntil) { + pollUntil = w + } + } + } + + return pollUntil +} + +// Check for idle-priority GC, without a P on entry. +// +// If some GC work, a P, and a worker G are all available, the P and G will be +// returned. The returned P has not been wired yet. +func checkIdleGCNoP() (*p, *g) { + // N.B. Since we have no P, gcBlackenEnabled may change at any time; we + // must check again after acquiring a P. As an optimization, we also check + // if an idle mark worker is needed at all. This is OK here, because if we + // observe that one isn't needed, at least one is currently running. Even if + // it stops running, its own journey into the scheduler should schedule it + // again, if need be (at which point, this check will pass, if relevant). + if atomic.Load(&gcBlackenEnabled) == 0 || !gcController.needIdleMarkWorker() { + return nil, nil + } + if !gcMarkWorkAvailable(nil) { + return nil, nil + } + + // Work is available; we can start an idle GC worker only if there is + // an available P and available worker G. + // + // We can attempt to acquire these in either order, though both have + // synchronization concerns (see below). Workers are almost always + // available (see comment in findRunnableGCWorker for the one case + // there may be none). Since we're slightly less likely to find a P, + // check for that first. + // + // Synchronization: note that we must hold sched.lock until we are + // committed to keeping it. Otherwise we cannot put the unnecessary P + // back in sched.pidle without performing the full set of idle + // transition checks. + // + // If we were to check gcBgMarkWorkerPool first, we must somehow handle + // the assumption in gcControllerState.findRunnableGCWorker that an + // empty gcBgMarkWorkerPool is only possible if gcMarkDone is running. + lock(&sched.lock) + pp, now := pidlegetSpinning(0) + if pp == nil { + unlock(&sched.lock) + return nil, nil + } + + // Now that we own a P, gcBlackenEnabled can't change (as it requires STW). + if gcBlackenEnabled == 0 || !gcController.addIdleMarkWorker() { + pidleput(pp, now) + unlock(&sched.lock) + return nil, nil + } + + node := (*gcBgMarkWorkerNode)(gcBgMarkWorkerPool.pop()) + if node == nil { + pidleput(pp, now) + unlock(&sched.lock) + gcController.removeIdleMarkWorker() + return nil, nil + } + + unlock(&sched.lock) + + return pp, node.gp.ptr() +} + +// wakeNetPoller wakes up the thread sleeping in the network poller if it isn't +// going to wake up before the when argument; or it wakes an idle P to service +// timers and the network poller if there isn't one already. +func wakeNetPoller(when int64) { + if sched.lastpoll.Load() == 0 { + // In findrunnable we ensure that when polling the pollUntil + // field is either zero or the time to which the current + // poll is expected to run. This can have a spurious wakeup + // but should never miss a wakeup. + pollerPollUntil := sched.pollUntil.Load() + if pollerPollUntil == 0 || pollerPollUntil > when { + netpollBreak() + } + } else { + // There are no threads in the network poller, try to get + // one there so it can handle new timers. + if GOOS != "plan9" { // Temporary workaround - see issue #42303. + wakep() + } + } +} + +func resetspinning() { + gp := getg() + if !gp.m.spinning { + throw("resetspinning: not a spinning m") + } + gp.m.spinning = false + nmspinning := sched.nmspinning.Add(-1) + if nmspinning < 0 { + throw("findrunnable: negative nmspinning") + } + // M wakeup policy is deliberately somewhat conservative, so check if we + // need to wakeup another P here. See "Worker thread parking/unparking" + // comment at the top of the file for details. + wakep() +} + +// injectglist adds each runnable G on the list to some run queue, +// and clears glist. If there is no current P, they are added to the +// global queue, and up to npidle M's are started to run them. +// Otherwise, for each idle P, this adds a G to the global queue +// and starts an M. Any remaining G's are added to the current P's +// local run queue. +// This may temporarily acquire sched.lock. +// Can run concurrently with GC. +func injectglist(glist *gList) { + if glist.empty() { + return + } + + // Mark all the goroutines as runnable before we put them + // on the run queues. + head := glist.head.ptr() + var tail *g + qsize := 0 + trace := traceAcquire() + for gp := head; gp != nil; gp = gp.schedlink.ptr() { + tail = gp + qsize++ + casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 0) + } + } + if trace.ok() { + traceRelease(trace) + } + + // Turn the gList into a gQueue. + var q gQueue + q.head.set(head) + q.tail.set(tail) + *glist = gList{} + + startIdle := func(n int) { + for i := 0; i < n; i++ { + mp := acquirem() // See comment in startm. + lock(&sched.lock) + + pp, _ := pidlegetSpinning(0) + if pp == nil { + unlock(&sched.lock) + releasem(mp) + break + } + + startm(pp, false, true) + unlock(&sched.lock) + releasem(mp) + } + } + + pp := getg().m.p.ptr() + if pp == nil { + lock(&sched.lock) + globrunqputbatch(&q, int32(qsize)) + unlock(&sched.lock) + startIdle(qsize) + return + } + + npidle := int(sched.npidle.Load()) + var ( + globq gQueue + n int + ) + for n = 0; n < npidle && !q.empty(); n++ { + g := q.pop() + globq.pushBack(g) + } + if n > 0 { + lock(&sched.lock) + globrunqputbatch(&globq, int32(n)) + unlock(&sched.lock) + startIdle(n) + qsize -= n + } + + if !q.empty() { + runqputbatch(pp, &q, qsize) + } + + // Some P's might have become idle after we loaded `sched.npidle` + // but before any goroutines were added to the queue, which could + // lead to idle P's when there is work available in the global queue. + // That could potentially last until other goroutines become ready + // to run. That said, we need to find a way to hedge + // + // Calling wakep() here is the best bet, it will do nothing in the + // common case (no racing on `sched.npidle`), while it could wake one + // more P to execute G's, which might end up with >1 P's: the first one + // wakes another P and so forth until there is no more work, but this + // ought to be an extremely rare case. + // + // Also see "Worker thread parking/unparking" comment at the top of the file for details. + wakep() +} + +// One round of scheduler: find a runnable goroutine and execute it. +// Never returns. +func schedule() { + mp := getg().m + + if mp.locks != 0 { + throw("schedule: holding locks") + } + + if mp.lockedg != 0 { + stoplockedm() + execute(mp.lockedg.ptr(), false) // Never returns. + } + + // We should not schedule away from a g that is executing a cgo call, + // since the cgo call is using the m's g0 stack. + if mp.incgo { + throw("schedule: in cgo") + } + +top: + pp := mp.p.ptr() + pp.preempt = false + + // Safety check: if we are spinning, the run queue should be empty. + // Check this before calling checkTimers, as that might call + // goready to put a ready goroutine on the local run queue. + if mp.spinning && (pp.runnext != 0 || pp.runqhead != pp.runqtail) { + throw("schedule: spinning with local work") + } + + gp, inheritTime, tryWakeP := findRunnable() // blocks until work is available + + if debug.dontfreezetheworld > 0 && freezing.Load() { + // See comment in freezetheworld. We don't want to perturb + // scheduler state, so we didn't gcstopm in findRunnable, but + // also don't want to allow new goroutines to run. + // + // Deadlock here rather than in the findRunnable loop so if + // findRunnable is stuck in a loop we don't perturb that + // either. + lock(&deadlock) + lock(&deadlock) + } + + // This thread is going to run a goroutine and is not spinning anymore, + // so if it was marked as spinning we need to reset it now and potentially + // start a new spinning M. + if mp.spinning { + resetspinning() + } + + if sched.disable.user && !schedEnabled(gp) { + // Scheduling of this goroutine is disabled. Put it on + // the list of pending runnable goroutines for when we + // re-enable user scheduling and look again. + lock(&sched.lock) + if schedEnabled(gp) { + // Something re-enabled scheduling while we + // were acquiring the lock. + unlock(&sched.lock) + } else { + sched.disable.runnable.pushBack(gp) + sched.disable.n++ + unlock(&sched.lock) + goto top + } + } + + // If about to schedule a not-normal goroutine (a GCworker or tracereader), + // wake a P if there is one. + if tryWakeP { + wakep() + } + if gp.lockedm != 0 { + // Hands off own p to the locked m, + // then blocks waiting for a new p. + startlockedm(gp) + goto top + } + + execute(gp, inheritTime) +} + +// dropg removes the association between m and the current goroutine m->curg (gp for short). +// Typically a caller sets gp's status away from Grunning and then +// immediately calls dropg to finish the job. The caller is also responsible +// for arranging that gp will be restarted using ready at an +// appropriate time. After calling dropg and arranging for gp to be +// readied later, the caller can do other work but eventually should +// call schedule to restart the scheduling of goroutines on this m. +func dropg() { + gp := getg() + + setMNoWB(&gp.m.curg.m, nil) + setGNoWB(&gp.m.curg, nil) +} + +func parkunlock_c(gp *g, lock unsafe.Pointer) bool { + unlock((*mutex)(lock)) + return true +} + +// park continuation on g0. +func park_m(gp *g) { + mp := getg().m + + trace := traceAcquire() + + if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. + trace.GoPark(mp.waitTraceBlockReason, mp.waitTraceSkip) + } + // N.B. Not using casGToWaiting here because the waitreason is + // set by park_m's caller. + casgstatus(gp, _Grunning, _Gwaiting) + if trace.ok() { + traceRelease(trace) + } + + dropg() + + if fn := mp.waitunlockf; fn != nil { + ok := fn(gp, mp.waitlock) + mp.waitunlockf = nil + mp.waitlock = nil + if !ok { + trace := traceAcquire() + casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 2) + traceRelease(trace) + } + execute(gp, true) // Schedule it back, never returns. + } + } + schedule() +} + +func goschedImpl(gp *g, preempted bool) { + trace := traceAcquire() + status := readgstatus(gp) + if status&^_Gscan != _Grunning { + dumpgstatus(gp) + throw("bad g status") + } + if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. + if preempted { + trace.GoPreempt() + } else { + trace.GoSched() + } + } + casgstatus(gp, _Grunning, _Grunnable) + if trace.ok() { + traceRelease(trace) + } + + dropg() + lock(&sched.lock) + globrunqput(gp) + unlock(&sched.lock) + + if mainStarted { + wakep() + } + + schedule() +} + +// Gosched continuation on g0. +func gosched_m(gp *g) { + goschedImpl(gp, false) +} + +// goschedguarded is a forbidden-states-avoided version of gosched_m. +func goschedguarded_m(gp *g) { + if !canPreemptM(gp.m) { + gogo(&gp.sched) // never return + } + goschedImpl(gp, false) +} + +func gopreempt_m(gp *g) { + goschedImpl(gp, true) +} + +// preemptPark parks gp and puts it in _Gpreempted. +// +//go:systemstack +func preemptPark(gp *g) { + status := readgstatus(gp) + if status&^_Gscan != _Grunning { + dumpgstatus(gp) + throw("bad g status") + } + + if gp.asyncSafePoint { + // Double-check that async preemption does not + // happen in SPWRITE assembly functions. + // isAsyncSafePoint must exclude this case. + f := findfunc(gp.sched.pc) + if !f.valid() { + throw("preempt at unknown pc") + } + if f.flag&abi.FuncFlagSPWrite != 0 { + println("runtime: unexpected SPWRITE function", funcname(f), "in async preempt") + throw("preempt SPWRITE") + } + } + + // Transition from _Grunning to _Gscan|_Gpreempted. We can't + // be in _Grunning when we dropg because then we'd be running + // without an M, but the moment we're in _Gpreempted, + // something could claim this G before we've fully cleaned it + // up. Hence, we set the scan bit to lock down further + // transitions until we can dropg. + casGToPreemptScan(gp, _Grunning, _Gscan|_Gpreempted) + dropg() + + // Be careful about how we trace this next event. The ordering + // is subtle. + // + // The moment we CAS into _Gpreempted, suspendG could CAS to + // _Gwaiting, do its work, and ready the goroutine. All of + // this could happen before we even get the chance to emit + // an event. The end result is that the events could appear + // out of order, and the tracer generally assumes the scheduler + // takes care of the ordering between GoPark and GoUnpark. + // + // The answer here is simple: emit the event while we still hold + // the _Gscan bit on the goroutine. We still need to traceAcquire + // and traceRelease across the CAS because the tracer could be + // what's calling suspendG in the first place, and we want the + // CAS and event emission to appear atomic to the tracer. + trace := traceAcquire() + if trace.ok() { + trace.GoPark(traceBlockPreempted, 0) + } + casfrom_Gscanstatus(gp, _Gscan|_Gpreempted, _Gpreempted) + if trace.ok() { + traceRelease(trace) + } + schedule() +} + +// goyield is like Gosched, but it: +// - emits a GoPreempt trace event instead of a GoSched trace event +// - puts the current G on the runq of the current P instead of the globrunq +// +// goyield should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname goyield +func goyield() { + checkTimeouts() + mcall(goyield_m) +} + +func goyield_m(gp *g) { + trace := traceAcquire() + pp := gp.m.p.ptr() + if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. + trace.GoPreempt() + } + casgstatus(gp, _Grunning, _Grunnable) + if trace.ok() { + traceRelease(trace) + } + dropg() + runqput(pp, gp, false) + schedule() +} + +// Finishes execution of the current goroutine. +func goexit1() { + if raceenabled { + racegoend() + } + trace := traceAcquire() + if trace.ok() { + trace.GoEnd() + traceRelease(trace) + } + mcall(goexit0) +} + +// goexit continuation on g0. +func goexit0(gp *g) { + gdestroy(gp) + schedule() +} + +func gdestroy(gp *g) { + mp := getg().m + pp := mp.p.ptr() + + casgstatus(gp, _Grunning, _Gdead) + gcController.addScannableStack(pp, -int64(gp.stack.hi-gp.stack.lo)) + if isSystemGoroutine(gp, false) { + sched.ngsys.Add(-1) + } + gp.m = nil + locked := gp.lockedm != 0 + gp.lockedm = 0 + mp.lockedg = 0 + gp.preemptStop = false + gp.paniconfault = false + gp._defer = nil // should be true already but just in case. + gp._panic = nil // non-nil for Goexit during panic. points at stack-allocated data. + gp.writebuf = nil + gp.waitreason = waitReasonZero + gp.param = nil + gp.labels = nil + gp.timer = nil + + if gcBlackenEnabled != 0 && gp.gcAssistBytes > 0 { + // Flush assist credit to the global pool. This gives + // better information to pacing if the application is + // rapidly creating an exiting goroutines. + assistWorkPerByte := gcController.assistWorkPerByte.Load() + scanCredit := int64(assistWorkPerByte * float64(gp.gcAssistBytes)) + gcController.bgScanCredit.Add(scanCredit) + gp.gcAssistBytes = 0 + } + + dropg() + + if GOARCH == "wasm" { // no threads yet on wasm + gfput(pp, gp) + return + } + + if locked && mp.lockedInt != 0 { + print("runtime: mp.lockedInt = ", mp.lockedInt, "\n") + throw("exited a goroutine internally locked to the OS thread") + } + gfput(pp, gp) + if locked { + // The goroutine may have locked this thread because + // it put it in an unusual kernel state. Kill it + // rather than returning it to the thread pool. + + // Return to mstart, which will release the P and exit + // the thread. + if GOOS != "plan9" { // See golang.org/issue/22227. + gogo(&mp.g0.sched) + } else { + // Clear lockedExt on plan9 since we may end up re-using + // this thread. + mp.lockedExt = 0 + } + } +} + +// save updates getg().sched to refer to pc and sp so that a following +// gogo will restore pc and sp. +// +// save must not have write barriers because invoking a write barrier +// can clobber getg().sched. +// +//go:nosplit +//go:nowritebarrierrec +func save(pc, sp, bp uintptr) { + gp := getg() + + if gp == gp.m.g0 || gp == gp.m.gsignal { + // m.g0.sched is special and must describe the context + // for exiting the thread. mstart1 writes to it directly. + // m.gsignal.sched should not be used at all. + // This check makes sure save calls do not accidentally + // run in contexts where they'd write to system g's. + throw("save on system g not allowed") + } + + gp.sched.pc = pc + gp.sched.sp = sp + gp.sched.lr = 0 + gp.sched.ret = 0 + gp.sched.bp = bp + // We need to ensure ctxt is zero, but can't have a write + // barrier here. However, it should always already be zero. + // Assert that. + if gp.sched.ctxt != nil { + badctxt() + } +} + +// The goroutine g is about to enter a system call. +// Record that it's not using the cpu anymore. +// This is called only from the go syscall library and cgocall, +// not from the low-level system calls used by the runtime. +// +// Entersyscall cannot split the stack: the save must +// make g->sched refer to the caller's stack segment, because +// entersyscall is going to return immediately after. +// +// Nothing entersyscall calls can split the stack either. +// We cannot safely move the stack during an active call to syscall, +// because we do not know which of the uintptr arguments are +// really pointers (back into the stack). +// In practice, this means that we make the fast path run through +// entersyscall doing no-split things, and the slow path has to use systemstack +// to run bigger things on the system stack. +// +// reentersyscall is the entry point used by cgo callbacks, where explicitly +// saved SP and PC are restored. This is needed when exitsyscall will be called +// from a function further up in the call stack than the parent, as g->syscallsp +// must always point to a valid stack frame. entersyscall below is the normal +// entry point for syscalls, which obtains the SP and PC from the caller. +// +//go:nosplit +func reentersyscall(pc, sp, bp uintptr) { + trace := traceAcquire() + gp := getg() + + // Disable preemption because during this function g is in Gsyscall status, + // but can have inconsistent g->sched, do not let GC observe it. + gp.m.locks++ + + // Entersyscall must not call any function that might split/grow the stack. + // (See details in comment above.) + // Catch calls that might, by replacing the stack guard with something that + // will trip any stack check and leaving a flag to tell newstack to die. + gp.stackguard0 = stackPreempt + gp.throwsplit = true + + // Leave SP around for GC and traceback. + save(pc, sp, bp) + gp.syscallsp = sp + gp.syscallpc = pc + gp.syscallbp = bp + casgstatus(gp, _Grunning, _Gsyscall) + if staticLockRanking { + // When doing static lock ranking casgstatus can call + // systemstack which clobbers g.sched. + save(pc, sp, bp) + } + if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp { + systemstack(func() { + print("entersyscall inconsistent sp ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + throw("entersyscall") + }) + } + if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp { + systemstack(func() { + print("entersyscall inconsistent bp ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + throw("entersyscall") + }) + } + + if trace.ok() { + systemstack(func() { + trace.GoSysCall() + traceRelease(trace) + }) + // systemstack itself clobbers g.sched.{pc,sp} and we might + // need them later when the G is genuinely blocked in a + // syscall + save(pc, sp, bp) + } + + if sched.sysmonwait.Load() { + systemstack(entersyscall_sysmon) + save(pc, sp, bp) + } + + if gp.m.p.ptr().runSafePointFn != 0 { + // runSafePointFn may stack split if run on this stack + systemstack(runSafePointFn) + save(pc, sp, bp) + } + + gp.m.syscalltick = gp.m.p.ptr().syscalltick + pp := gp.m.p.ptr() + pp.m = 0 + gp.m.oldp.set(pp) + gp.m.p = 0 + atomic.Store(&pp.status, _Psyscall) + if sched.gcwaiting.Load() { + systemstack(entersyscall_gcwait) + save(pc, sp, bp) + } + + gp.m.locks-- +} + +// Standard syscall entry used by the go syscall library and normal cgo calls. +// +// This is exported via linkname to assembly in the syscall package and x/sys. +// +// Other packages should not be accessing entersyscall directly, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:nosplit +//go:linkname entersyscall +func entersyscall() { + // N.B. getcallerfp cannot be written directly as argument in the call + // to reentersyscall because it forces spilling the other arguments to + // the stack. This results in exceeding the nosplit stack requirements + // on some platforms. + fp := getcallerfp() + reentersyscall(getcallerpc(), getcallersp(), fp) +} + +func entersyscall_sysmon() { + lock(&sched.lock) + if sched.sysmonwait.Load() { + sched.sysmonwait.Store(false) + notewakeup(&sched.sysmonnote) + } + unlock(&sched.lock) +} + +func entersyscall_gcwait() { + gp := getg() + pp := gp.m.oldp.ptr() + + lock(&sched.lock) + trace := traceAcquire() + if sched.stopwait > 0 && atomic.Cas(&pp.status, _Psyscall, _Pgcstop) { + if trace.ok() { + // This is a steal in the new tracer. While it's very likely + // that we were the ones to put this P into _Psyscall, between + // then and now it's totally possible it had been stolen and + // then put back into _Psyscall for us to acquire here. In such + // case ProcStop would be incorrect. + // + // TODO(mknyszek): Consider emitting a ProcStop instead when + // gp.m.syscalltick == pp.syscalltick, since then we know we never + // lost the P. + trace.ProcSteal(pp, true) + traceRelease(trace) + } + pp.gcStopTime = nanotime() + pp.syscalltick++ + if sched.stopwait--; sched.stopwait == 0 { + notewakeup(&sched.stopnote) + } + } else if trace.ok() { + traceRelease(trace) + } + unlock(&sched.lock) +} + +// The same as entersyscall(), but with a hint that the syscall is blocking. + +// entersyscallblock should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname entersyscallblock +//go:nosplit +func entersyscallblock() { + gp := getg() + + gp.m.locks++ // see comment in entersyscall + gp.throwsplit = true + gp.stackguard0 = stackPreempt // see comment in entersyscall + gp.m.syscalltick = gp.m.p.ptr().syscalltick + gp.m.p.ptr().syscalltick++ + + // Leave SP around for GC and traceback. + pc := getcallerpc() + sp := getcallersp() + bp := getcallerfp() + save(pc, sp, bp) + gp.syscallsp = gp.sched.sp + gp.syscallpc = gp.sched.pc + gp.syscallbp = gp.sched.bp + if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp { + sp1 := sp + sp2 := gp.sched.sp + sp3 := gp.syscallsp + systemstack(func() { + print("entersyscallblock inconsistent sp ", hex(sp1), " ", hex(sp2), " ", hex(sp3), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + throw("entersyscallblock") + }) + } + casgstatus(gp, _Grunning, _Gsyscall) + if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp { + systemstack(func() { + print("entersyscallblock inconsistent sp ", hex(sp), " ", hex(gp.sched.sp), " ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + throw("entersyscallblock") + }) + } + if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp { + systemstack(func() { + print("entersyscallblock inconsistent bp ", hex(bp), " ", hex(gp.sched.bp), " ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + throw("entersyscallblock") + }) + } + + systemstack(entersyscallblock_handoff) + + // Resave for traceback during blocked call. + save(getcallerpc(), getcallersp(), getcallerfp()) + + gp.m.locks-- +} + +func entersyscallblock_handoff() { + trace := traceAcquire() + if trace.ok() { + trace.GoSysCall() + traceRelease(trace) + } + handoffp(releasep()) +} + +// The goroutine g exited its system call. +// Arrange for it to run on a cpu again. +// This is called only from the go syscall library, not +// from the low-level system calls used by the runtime. +// +// Write barriers are not allowed because our P may have been stolen. +// +// This is exported via linkname to assembly in the syscall package. +// +// exitsyscall should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:nosplit +//go:nowritebarrierrec +//go:linkname exitsyscall +func exitsyscall() { + gp := getg() + + gp.m.locks++ // see comment in entersyscall + if getcallersp() > gp.syscallsp { + throw("exitsyscall: syscall frame is no longer valid") + } + + gp.waitsince = 0 + oldp := gp.m.oldp.ptr() + gp.m.oldp = 0 + if exitsyscallfast(oldp) { + // When exitsyscallfast returns success, we have a P so can now use + // write barriers + if goroutineProfile.active { + // Make sure that gp has had its stack written out to the goroutine + // profile, exactly as it was when the goroutine profiler first + // stopped the world. + systemstack(func() { + tryRecordGoroutineProfileWB(gp) + }) + } + trace := traceAcquire() + if trace.ok() { + lostP := oldp != gp.m.p.ptr() || gp.m.syscalltick != gp.m.p.ptr().syscalltick + systemstack(func() { + // Write out syscall exit eagerly. + // + // It's important that we write this *after* we know whether we + // lost our P or not (determined by exitsyscallfast). + trace.GoSysExit(lostP) + if lostP { + // We lost the P at some point, even though we got it back here. + // Trace that we're starting again, because there was a traceGoSysBlock + // call somewhere in exitsyscallfast (indicating that this goroutine + // had blocked) and we're about to start running again. + trace.GoStart() + } + }) + } + // There's a cpu for us, so we can run. + gp.m.p.ptr().syscalltick++ + // We need to cas the status and scan before resuming... + casgstatus(gp, _Gsyscall, _Grunning) + if trace.ok() { + traceRelease(trace) + } + + // Garbage collector isn't running (since we are), + // so okay to clear syscallsp. + gp.syscallsp = 0 + gp.m.locks-- + if gp.preempt { + // restore the preemption request in case we've cleared it in newstack + gp.stackguard0 = stackPreempt + } else { + // otherwise restore the real stackGuard, we've spoiled it in entersyscall/entersyscallblock + gp.stackguard0 = gp.stack.lo + stackGuard + } + gp.throwsplit = false + + if sched.disable.user && !schedEnabled(gp) { + // Scheduling of this goroutine is disabled. + Gosched() + } + + return + } + + gp.m.locks-- + + // Call the scheduler. + mcall(exitsyscall0) + + // Scheduler returned, so we're allowed to run now. + // Delete the syscallsp information that we left for + // the garbage collector during the system call. + // Must wait until now because until gosched returns + // we don't know for sure that the garbage collector + // is not running. + gp.syscallsp = 0 + gp.m.p.ptr().syscalltick++ + gp.throwsplit = false +} + +//go:nosplit +func exitsyscallfast(oldp *p) bool { + // Freezetheworld sets stopwait but does not retake P's. + if sched.stopwait == freezeStopWait { + return false + } + + // Try to re-acquire the last P. + trace := traceAcquire() + if oldp != nil && oldp.status == _Psyscall && atomic.Cas(&oldp.status, _Psyscall, _Pidle) { + // There's a cpu for us, so we can run. + wirep(oldp) + exitsyscallfast_reacquired(trace) + if trace.ok() { + traceRelease(trace) + } + return true + } + if trace.ok() { + traceRelease(trace) + } + + // Try to get any other idle P. + if sched.pidle != 0 { + var ok bool + systemstack(func() { + ok = exitsyscallfast_pidle() + }) + if ok { + return true + } + } + return false +} + +// exitsyscallfast_reacquired is the exitsyscall path on which this G +// has successfully reacquired the P it was running on before the +// syscall. +// +//go:nosplit +func exitsyscallfast_reacquired(trace traceLocker) { + gp := getg() + if gp.m.syscalltick != gp.m.p.ptr().syscalltick { + if trace.ok() { + // The p was retaken and then enter into syscall again (since gp.m.syscalltick has changed). + // traceGoSysBlock for this syscall was already emitted, + // but here we effectively retake the p from the new syscall running on the same p. + systemstack(func() { + // We're stealing the P. It's treated + // as if it temporarily stopped running. Then, start running. + trace.ProcSteal(gp.m.p.ptr(), true) + trace.ProcStart() + }) + } + gp.m.p.ptr().syscalltick++ + } +} + +func exitsyscallfast_pidle() bool { + lock(&sched.lock) + pp, _ := pidleget(0) + if pp != nil && sched.sysmonwait.Load() { + sched.sysmonwait.Store(false) + notewakeup(&sched.sysmonnote) + } + unlock(&sched.lock) + if pp != nil { + acquirep(pp) + return true + } + return false +} + +// exitsyscall slow path on g0. +// Failed to acquire P, enqueue gp as runnable. +// +// Called via mcall, so gp is the calling g from this M. +// +//go:nowritebarrierrec +func exitsyscall0(gp *g) { + var trace traceLocker + traceExitingSyscall() + trace = traceAcquire() + casgstatus(gp, _Gsyscall, _Grunnable) + traceExitedSyscall() + if trace.ok() { + // Write out syscall exit eagerly. + // + // It's important that we write this *after* we know whether we + // lost our P or not (determined by exitsyscallfast). + trace.GoSysExit(true) + traceRelease(trace) + } + dropg() + lock(&sched.lock) + var pp *p + if schedEnabled(gp) { + pp, _ = pidleget(0) + } + var locked bool + if pp == nil { + globrunqput(gp) + + // Below, we stoplockedm if gp is locked. globrunqput releases + // ownership of gp, so we must check if gp is locked prior to + // committing the release by unlocking sched.lock, otherwise we + // could race with another M transitioning gp from unlocked to + // locked. + locked = gp.lockedm != 0 + } else if sched.sysmonwait.Load() { + sched.sysmonwait.Store(false) + notewakeup(&sched.sysmonnote) + } + unlock(&sched.lock) + if pp != nil { + acquirep(pp) + execute(gp, false) // Never returns. + } + if locked { + // Wait until another thread schedules gp and so m again. + // + // N.B. lockedm must be this M, as this g was running on this M + // before entersyscall. + stoplockedm() + execute(gp, false) // Never returns. + } + stopm() + schedule() // Never returns. +} + +// Called from syscall package before fork. +// +// syscall_runtime_BeforeFork is for package syscall, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/containerd/containerd +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname syscall_runtime_BeforeFork syscall.runtime_BeforeFork +//go:nosplit +func syscall_runtime_BeforeFork() { + gp := getg().m.curg + + // Block signals during a fork, so that the child does not run + // a signal handler before exec if a signal is sent to the process + // group. See issue #18600. + gp.m.locks++ + sigsave(&gp.m.sigmask) + sigblock(false) + + // This function is called before fork in syscall package. + // Code between fork and exec must not allocate memory nor even try to grow stack. + // Here we spoil g.stackguard0 to reliably detect any attempts to grow stack. + // runtime_AfterFork will undo this in parent process, but not in child. + gp.stackguard0 = stackFork +} + +// Called from syscall package after fork in parent. +// +// syscall_runtime_AfterFork is for package syscall, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/containerd/containerd +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname syscall_runtime_AfterFork syscall.runtime_AfterFork +//go:nosplit +func syscall_runtime_AfterFork() { + gp := getg().m.curg + + // See the comments in beforefork. + gp.stackguard0 = gp.stack.lo + stackGuard + + msigrestore(gp.m.sigmask) + + gp.m.locks-- +} + +// inForkedChild is true while manipulating signals in the child process. +// This is used to avoid calling libc functions in case we are using vfork. +var inForkedChild bool + +// Called from syscall package after fork in child. +// It resets non-sigignored signals to the default handler, and +// restores the signal mask in preparation for the exec. +// +// Because this might be called during a vfork, and therefore may be +// temporarily sharing address space with the parent process, this must +// not change any global variables or calling into C code that may do so. +// +// syscall_runtime_AfterForkInChild is for package syscall, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/containerd/containerd +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname syscall_runtime_AfterForkInChild syscall.runtime_AfterForkInChild +//go:nosplit +//go:nowritebarrierrec +func syscall_runtime_AfterForkInChild() { + // It's OK to change the global variable inForkedChild here + // because we are going to change it back. There is no race here, + // because if we are sharing address space with the parent process, + // then the parent process can not be running concurrently. + inForkedChild = true + + clearSignalHandlers() + + // When we are the child we are the only thread running, + // so we know that nothing else has changed gp.m.sigmask. + msigrestore(getg().m.sigmask) + + inForkedChild = false +} + +// pendingPreemptSignals is the number of preemption signals +// that have been sent but not received. This is only used on Darwin. +// For #41702. +var pendingPreemptSignals atomic.Int32 + +// Called from syscall package before Exec. +// +//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec +func syscall_runtime_BeforeExec() { + // Prevent thread creation during exec. + execLock.lock() + + // On Darwin, wait for all pending preemption signals to + // be received. See issue #41702. + if GOOS == "darwin" || GOOS == "ios" { + for pendingPreemptSignals.Load() > 0 { + osyield() + } + } +} + +// Called from syscall package after Exec. +// +//go:linkname syscall_runtime_AfterExec syscall.runtime_AfterExec +func syscall_runtime_AfterExec() { + execLock.unlock() +} + +// Allocate a new g, with a stack big enough for stacksize bytes. +func malg(stacksize int32) *g { + newg := new(g) + if stacksize >= 0 { + stacksize = round2(stackSystem + stacksize) + systemstack(func() { + newg.stack = stackalloc(uint32(stacksize)) + }) + newg.stackguard0 = newg.stack.lo + stackGuard + newg.stackguard1 = ^uintptr(0) + // Clear the bottom word of the stack. We record g + // there on gsignal stack during VDSO on ARM and ARM64. + *(*uintptr)(unsafe.Pointer(newg.stack.lo)) = 0 + } + return newg +} + +// Create a new g running fn. +// Put it on the queue of g's waiting to run. +// The compiler turns a go statement into a call to this. +func newproc(fn *funcval) { + gp := getg() + pc := getcallerpc() + systemstack(func() { + newg := newproc1(fn, gp, pc, false, waitReasonZero) + + pp := getg().m.p.ptr() + runqput(pp, newg, true) + + if mainStarted { + wakep() + } + }) +} + +// Create a new g in state _Grunnable (or _Gwaiting if parked is true), starting at fn. +// callerpc is the address of the go statement that created this. The caller is responsible +// for adding the new g to the scheduler. If parked is true, waitreason must be non-zero. +func newproc1(fn *funcval, callergp *g, callerpc uintptr, parked bool, waitreason waitReason) *g { + if fn == nil { + fatal("go of nil func value") + } + + mp := acquirem() // disable preemption because we hold M and P in local vars. + pp := mp.p.ptr() + newg := gfget(pp) + if newg == nil { + newg = malg(stackMin) + casgstatus(newg, _Gidle, _Gdead) + allgadd(newg) // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack. + } + if newg.stack.hi == 0 { + throw("newproc1: newg missing stack") + } + + if readgstatus(newg) != _Gdead { + throw("newproc1: new g is not Gdead") + } + + totalSize := uintptr(4*goarch.PtrSize + sys.MinFrameSize) // extra space in case of reads slightly beyond frame + totalSize = alignUp(totalSize, sys.StackAlign) + sp := newg.stack.hi - totalSize + if usesLR { + // caller's LR + *(*uintptr)(unsafe.Pointer(sp)) = 0 + prepGoExitFrame(sp) + } + if GOARCH == "arm64" { + // caller's FP + *(*uintptr)(unsafe.Pointer(sp - goarch.PtrSize)) = 0 + } + + memclrNoHeapPointers(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched)) + newg.sched.sp = sp + newg.stktopsp = sp + newg.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum // +PCQuantum so that previous instruction is in same function + newg.sched.g = guintptr(unsafe.Pointer(newg)) + gostartcallfn(&newg.sched, fn) + newg.parentGoid = callergp.goid + newg.gopc = callerpc + newg.ancestors = saveAncestors(callergp) + newg.startpc = fn.fn + if isSystemGoroutine(newg, false) { + sched.ngsys.Add(1) + } else { + // Only user goroutines inherit pprof labels. + if mp.curg != nil { + newg.labels = mp.curg.labels + } + if goroutineProfile.active { + // A concurrent goroutine profile is running. It should include + // exactly the set of goroutines that were alive when the goroutine + // profiler first stopped the world. That does not include newg, so + // mark it as not needing a profile before transitioning it from + // _Gdead. + newg.goroutineProfiled.Store(goroutineProfileSatisfied) + } + } + // Track initial transition? + newg.trackingSeq = uint8(cheaprand()) + if newg.trackingSeq%gTrackingPeriod == 0 { + newg.tracking = true + } + gcController.addScannableStack(pp, int64(newg.stack.hi-newg.stack.lo)) + + // Get a goid and switch to runnable. Make all this atomic to the tracer. + trace := traceAcquire() + var status uint32 = _Grunnable + if parked { + status = _Gwaiting + newg.waitreason = waitreason + } + casgstatus(newg, _Gdead, status) + if pp.goidcache == pp.goidcacheend { + // Sched.goidgen is the last allocated id, + // this batch must be [sched.goidgen+1, sched.goidgen+GoidCacheBatch]. + // At startup sched.goidgen=0, so main goroutine receives goid=1. + pp.goidcache = sched.goidgen.Add(_GoidCacheBatch) + pp.goidcache -= _GoidCacheBatch - 1 + pp.goidcacheend = pp.goidcache + _GoidCacheBatch + } + newg.goid = pp.goidcache + pp.goidcache++ + newg.trace.reset() + if trace.ok() { + trace.GoCreate(newg, newg.startpc, parked) + traceRelease(trace) + } + + // Set up race context. + if raceenabled { + newg.racectx = racegostart(callerpc) + newg.raceignore = 0 + if newg.labels != nil { + // See note in proflabel.go on labelSync's role in synchronizing + // with the reads in the signal handler. + racereleasemergeg(newg, unsafe.Pointer(&labelSync)) + } + } + releasem(mp) + + return newg +} + +// saveAncestors copies previous ancestors of the given caller g and +// includes info for the current caller into a new set of tracebacks for +// a g being created. +func saveAncestors(callergp *g) *[]ancestorInfo { + // Copy all prior info, except for the root goroutine (goid 0). + if debug.tracebackancestors <= 0 || callergp.goid == 0 { + return nil + } + var callerAncestors []ancestorInfo + if callergp.ancestors != nil { + callerAncestors = *callergp.ancestors + } + n := int32(len(callerAncestors)) + 1 + if n > debug.tracebackancestors { + n = debug.tracebackancestors + } + ancestors := make([]ancestorInfo, n) + copy(ancestors[1:], callerAncestors) + + var pcs [tracebackInnerFrames]uintptr + npcs := gcallers(callergp, 0, pcs[:]) + ipcs := make([]uintptr, npcs) + copy(ipcs, pcs[:]) + ancestors[0] = ancestorInfo{ + pcs: ipcs, + goid: callergp.goid, + gopc: callergp.gopc, + } + + ancestorsp := new([]ancestorInfo) + *ancestorsp = ancestors + return ancestorsp +} + +// Put on gfree list. +// If local list is too long, transfer a batch to the global list. +func gfput(pp *p, gp *g) { + if readgstatus(gp) != _Gdead { + throw("gfput: bad status (not Gdead)") + } + + stksize := gp.stack.hi - gp.stack.lo + + if stksize != uintptr(startingStackSize) { + // non-standard stack size - free it. + stackfree(gp.stack) + gp.stack.lo = 0 + gp.stack.hi = 0 + gp.stackguard0 = 0 + } + + pp.gFree.push(gp) + pp.gFree.n++ + if pp.gFree.n >= 64 { + var ( + inc int32 + stackQ gQueue + noStackQ gQueue + ) + for pp.gFree.n >= 32 { + gp := pp.gFree.pop() + pp.gFree.n-- + if gp.stack.lo == 0 { + noStackQ.push(gp) + } else { + stackQ.push(gp) + } + inc++ + } + lock(&sched.gFree.lock) + sched.gFree.noStack.pushAll(noStackQ) + sched.gFree.stack.pushAll(stackQ) + sched.gFree.n += inc + unlock(&sched.gFree.lock) + } +} + +// Get from gfree list. +// If local list is empty, grab a batch from global list. +func gfget(pp *p) *g { +retry: + if pp.gFree.empty() && (!sched.gFree.stack.empty() || !sched.gFree.noStack.empty()) { + lock(&sched.gFree.lock) + // Move a batch of free Gs to the P. + for pp.gFree.n < 32 { + // Prefer Gs with stacks. + gp := sched.gFree.stack.pop() + if gp == nil { + gp = sched.gFree.noStack.pop() + if gp == nil { + break + } + } + sched.gFree.n-- + pp.gFree.push(gp) + pp.gFree.n++ + } + unlock(&sched.gFree.lock) + goto retry + } + gp := pp.gFree.pop() + if gp == nil { + return nil + } + pp.gFree.n-- + if gp.stack.lo != 0 && gp.stack.hi-gp.stack.lo != uintptr(startingStackSize) { + // Deallocate old stack. We kept it in gfput because it was the + // right size when the goroutine was put on the free list, but + // the right size has changed since then. + systemstack(func() { + stackfree(gp.stack) + gp.stack.lo = 0 + gp.stack.hi = 0 + gp.stackguard0 = 0 + }) + } + if gp.stack.lo == 0 { + // Stack was deallocated in gfput or just above. Allocate a new one. + systemstack(func() { + gp.stack = stackalloc(startingStackSize) + }) + gp.stackguard0 = gp.stack.lo + stackGuard + } else { + if raceenabled { + racemalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo) + } + if msanenabled { + msanmalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo) + } + if asanenabled { + asanunpoison(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo) + } + } + return gp +} + +// Purge all cached G's from gfree list to the global list. +func gfpurge(pp *p) { + var ( + inc int32 + stackQ gQueue + noStackQ gQueue + ) + for !pp.gFree.empty() { + gp := pp.gFree.pop() + pp.gFree.n-- + if gp.stack.lo == 0 { + noStackQ.push(gp) + } else { + stackQ.push(gp) + } + inc++ + } + lock(&sched.gFree.lock) + sched.gFree.noStack.pushAll(noStackQ) + sched.gFree.stack.pushAll(stackQ) + sched.gFree.n += inc + unlock(&sched.gFree.lock) +} + +// Breakpoint executes a breakpoint trap. +func Breakpoint() { + breakpoint() +} + +// dolockOSThread is called by LockOSThread and lockOSThread below +// after they modify m.locked. Do not allow preemption during this call, +// or else the m might be different in this function than in the caller. +// +//go:nosplit +func dolockOSThread() { + if GOARCH == "wasm" { + return // no threads on wasm yet + } + gp := getg() + gp.m.lockedg.set(gp) + gp.lockedm.set(gp.m) +} + +// LockOSThread wires the calling goroutine to its current operating system thread. +// The calling goroutine will always execute in that thread, +// and no other goroutine will execute in it, +// until the calling goroutine has made as many calls to +// [UnlockOSThread] as to LockOSThread. +// If the calling goroutine exits without unlocking the thread, +// the thread will be terminated. +// +// All init functions are run on the startup thread. Calling LockOSThread +// from an init function will cause the main function to be invoked on +// that thread. +// +// A goroutine should call LockOSThread before calling OS services or +// non-Go library functions that depend on per-thread state. +// +//go:nosplit +func LockOSThread() { + if atomic.Load(&newmHandoff.haveTemplateThread) == 0 && GOOS != "plan9" { + // If we need to start a new thread from the locked + // thread, we need the template thread. Start it now + // while we're in a known-good state. + startTemplateThread() + } + gp := getg() + gp.m.lockedExt++ + if gp.m.lockedExt == 0 { + gp.m.lockedExt-- + panic("LockOSThread nesting overflow") + } + dolockOSThread() +} + +//go:nosplit +func lockOSThread() { + getg().m.lockedInt++ + dolockOSThread() +} + +// dounlockOSThread is called by UnlockOSThread and unlockOSThread below +// after they update m->locked. Do not allow preemption during this call, +// or else the m might be in different in this function than in the caller. +// +//go:nosplit +func dounlockOSThread() { + if GOARCH == "wasm" { + return // no threads on wasm yet + } + gp := getg() + if gp.m.lockedInt != 0 || gp.m.lockedExt != 0 { + return + } + gp.m.lockedg = 0 + gp.lockedm = 0 +} + +// UnlockOSThread undoes an earlier call to LockOSThread. +// If this drops the number of active LockOSThread calls on the +// calling goroutine to zero, it unwires the calling goroutine from +// its fixed operating system thread. +// If there are no active LockOSThread calls, this is a no-op. +// +// Before calling UnlockOSThread, the caller must ensure that the OS +// thread is suitable for running other goroutines. If the caller made +// any permanent changes to the state of the thread that would affect +// other goroutines, it should not call this function and thus leave +// the goroutine locked to the OS thread until the goroutine (and +// hence the thread) exits. +// +//go:nosplit +func UnlockOSThread() { + gp := getg() + if gp.m.lockedExt == 0 { + return + } + gp.m.lockedExt-- + dounlockOSThread() +} + +//go:nosplit +func unlockOSThread() { + gp := getg() + if gp.m.lockedInt == 0 { + systemstack(badunlockosthread) + } + gp.m.lockedInt-- + dounlockOSThread() +} + +func badunlockosthread() { + throw("runtime: internal error: misuse of lockOSThread/unlockOSThread") +} + +func gcount() int32 { + n := int32(atomic.Loaduintptr(&allglen)) - sched.gFree.n - sched.ngsys.Load() + for _, pp := range allp { + n -= pp.gFree.n + } + + // All these variables can be changed concurrently, so the result can be inconsistent. + // But at least the current goroutine is running. + if n < 1 { + n = 1 + } + return n +} + +func mcount() int32 { + return int32(sched.mnext - sched.nmfreed) +} + +var prof struct { + signalLock atomic.Uint32 + + // Must hold signalLock to write. Reads may be lock-free, but + // signalLock should be taken to synchronize with changes. + hz atomic.Int32 +} + +func _System() { _System() } +func _ExternalCode() { _ExternalCode() } +func _LostExternalCode() { _LostExternalCode() } +func _GC() { _GC() } +func _LostSIGPROFDuringAtomic64() { _LostSIGPROFDuringAtomic64() } +func _LostContendedRuntimeLock() { _LostContendedRuntimeLock() } +func _VDSO() { _VDSO() } + +// Called if we receive a SIGPROF signal. +// Called by the signal handler, may run during STW. +// +//go:nowritebarrierrec +func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { + if prof.hz.Load() == 0 { + return + } + + // If mp.profilehz is 0, then profiling is not enabled for this thread. + // We must check this to avoid a deadlock between setcpuprofilerate + // and the call to cpuprof.add, below. + if mp != nil && mp.profilehz == 0 { + return + } + + // On mips{,le}/arm, 64bit atomics are emulated with spinlocks, in + // internal/runtime/atomic. If SIGPROF arrives while the program is inside + // the critical section, it creates a deadlock (when writing the sample). + // As a workaround, create a counter of SIGPROFs while in critical section + // to store the count, and pass it to sigprof.add() later when SIGPROF is + // received from somewhere else (with _LostSIGPROFDuringAtomic64 as pc). + if GOARCH == "mips" || GOARCH == "mipsle" || GOARCH == "arm" { + if f := findfunc(pc); f.valid() { + if stringslite.HasPrefix(funcname(f), "internal/runtime/atomic") { + cpuprof.lostAtomic++ + return + } + } + if GOARCH == "arm" && goarm < 7 && GOOS == "linux" && pc&0xffff0000 == 0xffff0000 { + // internal/runtime/atomic functions call into kernel + // helpers on arm < 7. See + // internal/runtime/atomic/sys_linux_arm.s. + cpuprof.lostAtomic++ + return + } + } + + // Profiling runs concurrently with GC, so it must not allocate. + // Set a trap in case the code does allocate. + // Note that on windows, one thread takes profiles of all the + // other threads, so mp is usually not getg().m. + // In fact mp may not even be stopped. + // See golang.org/issue/17165. + getg().m.mallocing++ + + var u unwinder + var stk [maxCPUProfStack]uintptr + n := 0 + if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 { + cgoOff := 0 + // Check cgoCallersUse to make sure that we are not + // interrupting other code that is fiddling with + // cgoCallers. We are running in a signal handler + // with all signals blocked, so we don't have to worry + // about any other code interrupting us. + if mp.cgoCallersUse.Load() == 0 && mp.cgoCallers != nil && mp.cgoCallers[0] != 0 { + for cgoOff < len(mp.cgoCallers) && mp.cgoCallers[cgoOff] != 0 { + cgoOff++ + } + n += copy(stk[:], mp.cgoCallers[:cgoOff]) + mp.cgoCallers[0] = 0 + } + + // Collect Go stack that leads to the cgo call. + u.initAt(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, unwindSilentErrors) + } else if usesLibcall() && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 { + // Libcall, i.e. runtime syscall on windows. + // Collect Go stack that leads to the call. + u.initAt(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), unwindSilentErrors) + } else if mp != nil && mp.vdsoSP != 0 { + // VDSO call, e.g. nanotime1 on Linux. + // Collect Go stack that leads to the call. + u.initAt(mp.vdsoPC, mp.vdsoSP, 0, gp, unwindSilentErrors|unwindJumpStack) + } else { + u.initAt(pc, sp, lr, gp, unwindSilentErrors|unwindTrap|unwindJumpStack) + } + n += tracebackPCs(&u, 0, stk[n:]) + + if n <= 0 { + // Normal traceback is impossible or has failed. + // Account it against abstract "System" or "GC". + n = 2 + if inVDSOPage(pc) { + pc = abi.FuncPCABIInternal(_VDSO) + sys.PCQuantum + } else if pc > firstmoduledata.etext { + // "ExternalCode" is better than "etext". + pc = abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum + } + stk[0] = pc + if mp.preemptoff != "" { + stk[1] = abi.FuncPCABIInternal(_GC) + sys.PCQuantum + } else { + stk[1] = abi.FuncPCABIInternal(_System) + sys.PCQuantum + } + } + + if prof.hz.Load() != 0 { + // Note: it can happen on Windows that we interrupted a system thread + // with no g, so gp could nil. The other nil checks are done out of + // caution, but not expected to be nil in practice. + var tagPtr *unsafe.Pointer + if gp != nil && gp.m != nil && gp.m.curg != nil { + tagPtr = &gp.m.curg.labels + } + cpuprof.add(tagPtr, stk[:n]) + + gprof := gp + var mp *m + var pp *p + if gp != nil && gp.m != nil { + if gp.m.curg != nil { + gprof = gp.m.curg + } + mp = gp.m + pp = gp.m.p.ptr() + } + traceCPUSample(gprof, mp, pp, stk[:n]) + } + getg().m.mallocing-- +} + +// setcpuprofilerate sets the CPU profiling rate to hz times per second. +// If hz <= 0, setcpuprofilerate turns off CPU profiling. +func setcpuprofilerate(hz int32) { + // Force sane arguments. + if hz < 0 { + hz = 0 + } + + // Disable preemption, otherwise we can be rescheduled to another thread + // that has profiling enabled. + gp := getg() + gp.m.locks++ + + // Stop profiler on this thread so that it is safe to lock prof. + // if a profiling signal came in while we had prof locked, + // it would deadlock. + setThreadCPUProfiler(0) + + for !prof.signalLock.CompareAndSwap(0, 1) { + osyield() + } + if prof.hz.Load() != hz { + setProcessCPUProfiler(hz) + prof.hz.Store(hz) + } + prof.signalLock.Store(0) + + lock(&sched.lock) + sched.profilehz = hz + unlock(&sched.lock) + + if hz != 0 { + setThreadCPUProfiler(hz) + } + + gp.m.locks-- +} + +// init initializes pp, which may be a freshly allocated p or a +// previously destroyed p, and transitions it to status _Pgcstop. +func (pp *p) init(id int32) { + pp.id = id + pp.status = _Pgcstop + pp.sudogcache = pp.sudogbuf[:0] + pp.deferpool = pp.deferpoolbuf[:0] + pp.wbBuf.reset() + if pp.mcache == nil { + if id == 0 { + if mcache0 == nil { + throw("missing mcache?") + } + // Use the bootstrap mcache0. Only one P will get + // mcache0: the one with ID 0. + pp.mcache = mcache0 + } else { + pp.mcache = allocmcache() + } + } + if raceenabled && pp.raceprocctx == 0 { + if id == 0 { + pp.raceprocctx = raceprocctx0 + raceprocctx0 = 0 // bootstrap + } else { + pp.raceprocctx = raceproccreate() + } + } + lockInit(&pp.timers.mu, lockRankTimers) + + // This P may get timers when it starts running. Set the mask here + // since the P may not go through pidleget (notably P 0 on startup). + timerpMask.set(id) + // Similarly, we may not go through pidleget before this P starts + // running if it is P 0 on startup. + idlepMask.clear(id) +} + +// destroy releases all of the resources associated with pp and +// transitions it to status _Pdead. +// +// sched.lock must be held and the world must be stopped. +func (pp *p) destroy() { + assertLockHeld(&sched.lock) + assertWorldStopped() + + // Move all runnable goroutines to the global queue + for pp.runqhead != pp.runqtail { + // Pop from tail of local queue + pp.runqtail-- + gp := pp.runq[pp.runqtail%uint32(len(pp.runq))].ptr() + // Push onto head of global queue + globrunqputhead(gp) + } + if pp.runnext != 0 { + globrunqputhead(pp.runnext.ptr()) + pp.runnext = 0 + } + + // Move all timers to the local P. + getg().m.p.ptr().timers.take(&pp.timers) + + // Flush p's write barrier buffer. + if gcphase != _GCoff { + wbBufFlush1(pp) + pp.gcw.dispose() + } + for i := range pp.sudogbuf { + pp.sudogbuf[i] = nil + } + pp.sudogcache = pp.sudogbuf[:0] + pp.pinnerCache = nil + for j := range pp.deferpoolbuf { + pp.deferpoolbuf[j] = nil + } + pp.deferpool = pp.deferpoolbuf[:0] + systemstack(func() { + for i := 0; i < pp.mspancache.len; i++ { + // Safe to call since the world is stopped. + mheap_.spanalloc.free(unsafe.Pointer(pp.mspancache.buf[i])) + } + pp.mspancache.len = 0 + lock(&mheap_.lock) + pp.pcache.flush(&mheap_.pages) + unlock(&mheap_.lock) + }) + freemcache(pp.mcache) + pp.mcache = nil + gfpurge(pp) + if raceenabled { + if pp.timers.raceCtx != 0 { + // The race detector code uses a callback to fetch + // the proc context, so arrange for that callback + // to see the right thing. + // This hack only works because we are the only + // thread running. + mp := getg().m + phold := mp.p.ptr() + mp.p.set(pp) + + racectxend(pp.timers.raceCtx) + pp.timers.raceCtx = 0 + + mp.p.set(phold) + } + raceprocdestroy(pp.raceprocctx) + pp.raceprocctx = 0 + } + pp.gcAssistTime = 0 + pp.status = _Pdead +} + +// Change number of processors. +// +// sched.lock must be held, and the world must be stopped. +// +// gcworkbufs must not be being modified by either the GC or the write barrier +// code, so the GC must not be running if the number of Ps actually changes. +// +// Returns list of Ps with local work, they need to be scheduled by the caller. +func procresize(nprocs int32) *p { + assertLockHeld(&sched.lock) + assertWorldStopped() + + old := gomaxprocs + if old < 0 || nprocs <= 0 { + throw("procresize: invalid arg") + } + trace := traceAcquire() + if trace.ok() { + trace.Gomaxprocs(nprocs) + traceRelease(trace) + } + + // update statistics + now := nanotime() + if sched.procresizetime != 0 { + sched.totaltime += int64(old) * (now - sched.procresizetime) + } + sched.procresizetime = now + + maskWords := (nprocs + 31) / 32 + + // Grow allp if necessary. + if nprocs > int32(len(allp)) { + // Synchronize with retake, which could be running + // concurrently since it doesn't run on a P. + lock(&allpLock) + if nprocs <= int32(cap(allp)) { + allp = allp[:nprocs] + } else { + nallp := make([]*p, nprocs) + // Copy everything up to allp's cap so we + // never lose old allocated Ps. + copy(nallp, allp[:cap(allp)]) + allp = nallp + } + + if maskWords <= int32(cap(idlepMask)) { + idlepMask = idlepMask[:maskWords] + timerpMask = timerpMask[:maskWords] + } else { + nidlepMask := make([]uint32, maskWords) + // No need to copy beyond len, old Ps are irrelevant. + copy(nidlepMask, idlepMask) + idlepMask = nidlepMask + + ntimerpMask := make([]uint32, maskWords) + copy(ntimerpMask, timerpMask) + timerpMask = ntimerpMask + } + unlock(&allpLock) + } + + // initialize new P's + for i := old; i < nprocs; i++ { + pp := allp[i] + if pp == nil { + pp = new(p) + } + pp.init(i) + atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp)) + } + + gp := getg() + if gp.m.p != 0 && gp.m.p.ptr().id < nprocs { + // continue to use the current P + gp.m.p.ptr().status = _Prunning + gp.m.p.ptr().mcache.prepareForSweep() + } else { + // release the current P and acquire allp[0]. + // + // We must do this before destroying our current P + // because p.destroy itself has write barriers, so we + // need to do that from a valid P. + if gp.m.p != 0 { + trace := traceAcquire() + if trace.ok() { + // Pretend that we were descheduled + // and then scheduled again to keep + // the trace consistent. + trace.GoSched() + trace.ProcStop(gp.m.p.ptr()) + traceRelease(trace) + } + gp.m.p.ptr().m = 0 + } + gp.m.p = 0 + pp := allp[0] + pp.m = 0 + pp.status = _Pidle + acquirep(pp) + trace := traceAcquire() + if trace.ok() { + trace.GoStart() + traceRelease(trace) + } + } + + // g.m.p is now set, so we no longer need mcache0 for bootstrapping. + mcache0 = nil + + // release resources from unused P's + for i := nprocs; i < old; i++ { + pp := allp[i] + pp.destroy() + // can't free P itself because it can be referenced by an M in syscall + } + + // Trim allp. + if int32(len(allp)) != nprocs { + lock(&allpLock) + allp = allp[:nprocs] + idlepMask = idlepMask[:maskWords] + timerpMask = timerpMask[:maskWords] + unlock(&allpLock) + } + + var runnablePs *p + for i := nprocs - 1; i >= 0; i-- { + pp := allp[i] + if gp.m.p.ptr() == pp { + continue + } + pp.status = _Pidle + if runqempty(pp) { + pidleput(pp, now) + } else { + pp.m.set(mget()) + pp.link.set(runnablePs) + runnablePs = pp + } + } + stealOrder.reset(uint32(nprocs)) + var int32p *int32 = &gomaxprocs // make compiler check that gomaxprocs is an int32 + atomic.Store((*uint32)(unsafe.Pointer(int32p)), uint32(nprocs)) + if old != nprocs { + // Notify the limiter that the amount of procs has changed. + gcCPULimiter.resetCapacity(now, nprocs) + } + return runnablePs +} + +// Associate p and the current m. +// +// This function is allowed to have write barriers even if the caller +// isn't because it immediately acquires pp. +// +//go:yeswritebarrierrec +func acquirep(pp *p) { + // Do the part that isn't allowed to have write barriers. + wirep(pp) + + // Have p; write barriers now allowed. + + // Perform deferred mcache flush before this P can allocate + // from a potentially stale mcache. + pp.mcache.prepareForSweep() + + trace := traceAcquire() + if trace.ok() { + trace.ProcStart() + traceRelease(trace) + } +} + +// wirep is the first step of acquirep, which actually associates the +// current M to pp. This is broken out so we can disallow write +// barriers for this part, since we don't yet have a P. +// +//go:nowritebarrierrec +//go:nosplit +func wirep(pp *p) { + gp := getg() + + if gp.m.p != 0 { + // Call on the systemstack to avoid a nosplit overflow build failure + // on some platforms when built with -N -l. See #64113. + systemstack(func() { + throw("wirep: already in go") + }) + } + if pp.m != 0 || pp.status != _Pidle { + // Call on the systemstack to avoid a nosplit overflow build failure + // on some platforms when built with -N -l. See #64113. + systemstack(func() { + id := int64(0) + if pp.m != 0 { + id = pp.m.ptr().id + } + print("wirep: p->m=", pp.m, "(", id, ") p->status=", pp.status, "\n") + throw("wirep: invalid p state") + }) + } + gp.m.p.set(pp) + pp.m.set(gp.m) + pp.status = _Prunning +} + +// Disassociate p and the current m. +func releasep() *p { + trace := traceAcquire() + if trace.ok() { + trace.ProcStop(getg().m.p.ptr()) + traceRelease(trace) + } + return releasepNoTrace() +} + +// Disassociate p and the current m without tracing an event. +func releasepNoTrace() *p { + gp := getg() + + if gp.m.p == 0 { + throw("releasep: invalid arg") + } + pp := gp.m.p.ptr() + if pp.m.ptr() != gp.m || pp.status != _Prunning { + print("releasep: m=", gp.m, " m->p=", gp.m.p.ptr(), " p->m=", hex(pp.m), " p->status=", pp.status, "\n") + throw("releasep: invalid p state") + } + gp.m.p = 0 + pp.m = 0 + pp.status = _Pidle + return pp +} + +func incidlelocked(v int32) { + lock(&sched.lock) + sched.nmidlelocked += v + if v > 0 { + checkdead() + } + unlock(&sched.lock) +} + +// Check for deadlock situation. +// The check is based on number of running M's, if 0 -> deadlock. +// sched.lock must be held. +func checkdead() { + assertLockHeld(&sched.lock) + + // For -buildmode=c-shared or -buildmode=c-archive it's OK if + // there are no running goroutines. The calling program is + // assumed to be running. + if islibrary || isarchive { + return + } + + // If we are dying because of a signal caught on an already idle thread, + // freezetheworld will cause all running threads to block. + // And runtime will essentially enter into deadlock state, + // except that there is a thread that will call exit soon. + if panicking.Load() > 0 { + return + } + + // If we are not running under cgo, but we have an extra M then account + // for it. (It is possible to have an extra M on Windows without cgo to + // accommodate callbacks created by syscall.NewCallback. See issue #6751 + // for details.) + var run0 int32 + if !iscgo && cgoHasExtraM && extraMLength.Load() > 0 { + run0 = 1 + } + + run := mcount() - sched.nmidle - sched.nmidlelocked - sched.nmsys + if run > run0 { + return + } + if run < 0 { + print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", mcount(), " nmsys=", sched.nmsys, "\n") + unlock(&sched.lock) + throw("checkdead: inconsistent counts") + } + + grunning := 0 + forEachG(func(gp *g) { + if isSystemGoroutine(gp, false) { + return + } + s := readgstatus(gp) + switch s &^ _Gscan { + case _Gwaiting, + _Gpreempted: + grunning++ + case _Grunnable, + _Grunning, + _Gsyscall: + print("runtime: checkdead: find g ", gp.goid, " in status ", s, "\n") + unlock(&sched.lock) + throw("checkdead: runnable g") + } + }) + if grunning == 0 { // possible if main goroutine calls runtime·Goexit() + unlock(&sched.lock) // unlock so that GODEBUG=scheddetail=1 doesn't hang + fatal("no goroutines (main called runtime.Goexit) - deadlock!") + } + + // Maybe jump time forward for playground. + if faketime != 0 { + if when := timeSleepUntil(); when < maxWhen { + faketime = when + + // Start an M to steal the timer. + pp, _ := pidleget(faketime) + if pp == nil { + // There should always be a free P since + // nothing is running. + unlock(&sched.lock) + throw("checkdead: no p for timer") + } + mp := mget() + if mp == nil { + // There should always be a free M since + // nothing is running. + unlock(&sched.lock) + throw("checkdead: no m for timer") + } + // M must be spinning to steal. We set this to be + // explicit, but since this is the only M it would + // become spinning on its own anyways. + sched.nmspinning.Add(1) + mp.spinning = true + mp.nextp.set(pp) + notewakeup(&mp.park) + return + } + } + + // There are no goroutines running, so we can look at the P's. + for _, pp := range allp { + if len(pp.timers.heap) > 0 { + return + } + } + + unlock(&sched.lock) // unlock so that GODEBUG=scheddetail=1 doesn't hang + fatal("all goroutines are asleep - deadlock!") +} + +// forcegcperiod is the maximum time in nanoseconds between garbage +// collections. If we go this long without a garbage collection, one +// is forced to run. +// +// This is a variable for testing purposes. It normally doesn't change. +var forcegcperiod int64 = 2 * 60 * 1e9 + +// needSysmonWorkaround is true if the workaround for +// golang.org/issue/42515 is needed on NetBSD. +var needSysmonWorkaround bool = false + +// haveSysmon indicates whether there is sysmon thread support. +// +// No threads on wasm yet, so no sysmon. +const haveSysmon = GOARCH != "wasm" + +// Always runs without a P, so write barriers are not allowed. +// +//go:nowritebarrierrec +func sysmon() { + lock(&sched.lock) + sched.nmsys++ + checkdead() + unlock(&sched.lock) + + lasttrace := int64(0) + idle := 0 // how many cycles in succession we had not wokeup somebody + delay := uint32(0) + + for { + if idle == 0 { // start with 20us sleep... + delay = 20 + } else if idle > 50 { // start doubling the sleep after 1ms... + delay *= 2 + } + if delay > 10*1000 { // up to 10ms + delay = 10 * 1000 + } + usleep(delay) + + // sysmon should not enter deep sleep if schedtrace is enabled so that + // it can print that information at the right time. + // + // It should also not enter deep sleep if there are any active P's so + // that it can retake P's from syscalls, preempt long running G's, and + // poll the network if all P's are busy for long stretches. + // + // It should wakeup from deep sleep if any P's become active either due + // to exiting a syscall or waking up due to a timer expiring so that it + // can resume performing those duties. If it wakes from a syscall it + // resets idle and delay as a bet that since it had retaken a P from a + // syscall before, it may need to do it again shortly after the + // application starts work again. It does not reset idle when waking + // from a timer to avoid adding system load to applications that spend + // most of their time sleeping. + now := nanotime() + if debug.schedtrace <= 0 && (sched.gcwaiting.Load() || sched.npidle.Load() == gomaxprocs) { + lock(&sched.lock) + if sched.gcwaiting.Load() || sched.npidle.Load() == gomaxprocs { + syscallWake := false + next := timeSleepUntil() + if next > now { + sched.sysmonwait.Store(true) + unlock(&sched.lock) + // Make wake-up period small enough + // for the sampling to be correct. + sleep := forcegcperiod / 2 + if next-now < sleep { + sleep = next - now + } + shouldRelax := sleep >= osRelaxMinNS + if shouldRelax { + osRelax(true) + } + syscallWake = notetsleep(&sched.sysmonnote, sleep) + if shouldRelax { + osRelax(false) + } + lock(&sched.lock) + sched.sysmonwait.Store(false) + noteclear(&sched.sysmonnote) + } + if syscallWake { + idle = 0 + delay = 20 + } + } + unlock(&sched.lock) + } + + lock(&sched.sysmonlock) + // Update now in case we blocked on sysmonnote or spent a long time + // blocked on schedlock or sysmonlock above. + now = nanotime() + + // trigger libc interceptors if needed + if *cgo_yield != nil { + asmcgocall(*cgo_yield, nil) + } + // poll network if not polled for more than 10ms + lastpoll := sched.lastpoll.Load() + if netpollinited() && lastpoll != 0 && lastpoll+10*1000*1000 < now { + sched.lastpoll.CompareAndSwap(lastpoll, now) + list, delta := netpoll(0) // non-blocking - returns list of goroutines + if !list.empty() { + // Need to decrement number of idle locked M's + // (pretending that one more is running) before injectglist. + // Otherwise it can lead to the following situation: + // injectglist grabs all P's but before it starts M's to run the P's, + // another M returns from syscall, finishes running its G, + // observes that there is no work to do and no other running M's + // and reports deadlock. + incidlelocked(-1) + injectglist(&list) + incidlelocked(1) + netpollAdjustWaiters(delta) + } + } + if GOOS == "netbsd" && needSysmonWorkaround { + // netpoll is responsible for waiting for timer + // expiration, so we typically don't have to worry + // about starting an M to service timers. (Note that + // sleep for timeSleepUntil above simply ensures sysmon + // starts running again when that timer expiration may + // cause Go code to run again). + // + // However, netbsd has a kernel bug that sometimes + // misses netpollBreak wake-ups, which can lead to + // unbounded delays servicing timers. If we detect this + // overrun, then startm to get something to handle the + // timer. + // + // See issue 42515 and + // https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50094. + if next := timeSleepUntil(); next < now { + startm(nil, false, false) + } + } + if scavenger.sysmonWake.Load() != 0 { + // Kick the scavenger awake if someone requested it. + scavenger.wake() + } + // retake P's blocked in syscalls + // and preempt long running G's + if retake(now) != 0 { + idle = 0 + } else { + idle++ + } + // check if we need to force a GC + if t := (gcTrigger{kind: gcTriggerTime, now: now}); t.test() && forcegc.idle.Load() { + lock(&forcegc.lock) + forcegc.idle.Store(false) + var list gList + list.push(forcegc.g) + injectglist(&list) + unlock(&forcegc.lock) + } + if debug.schedtrace > 0 && lasttrace+int64(debug.schedtrace)*1000000 <= now { + lasttrace = now + schedtrace(debug.scheddetail > 0) + } + unlock(&sched.sysmonlock) + } +} + +type sysmontick struct { + schedtick uint32 + syscalltick uint32 + schedwhen int64 + syscallwhen int64 +} + +// forcePreemptNS is the time slice given to a G before it is +// preempted. +const forcePreemptNS = 10 * 1000 * 1000 // 10ms + +func retake(now int64) uint32 { + n := 0 + // Prevent allp slice changes. This lock will be completely + // uncontended unless we're already stopping the world. + lock(&allpLock) + // We can't use a range loop over allp because we may + // temporarily drop the allpLock. Hence, we need to re-fetch + // allp each time around the loop. + for i := 0; i < len(allp); i++ { + pp := allp[i] + if pp == nil { + // This can happen if procresize has grown + // allp but not yet created new Ps. + continue + } + pd := &pp.sysmontick + s := pp.status + sysretake := false + if s == _Prunning || s == _Psyscall { + // Preempt G if it's running on the same schedtick for + // too long. This could be from a single long-running + // goroutine or a sequence of goroutines run via + // runnext, which share a single schedtick time slice. + t := int64(pp.schedtick) + if int64(pd.schedtick) != t { + pd.schedtick = uint32(t) + pd.schedwhen = now + } else if pd.schedwhen+forcePreemptNS <= now { + preemptone(pp) + // In case of syscall, preemptone() doesn't + // work, because there is no M wired to P. + sysretake = true + } + } + if s == _Psyscall { + // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us). + t := int64(pp.syscalltick) + if !sysretake && int64(pd.syscalltick) != t { + pd.syscalltick = uint32(t) + pd.syscallwhen = now + continue + } + // On the one hand we don't want to retake Ps if there is no other work to do, + // but on the other hand we want to retake them eventually + // because they can prevent the sysmon thread from deep sleep. + if runqempty(pp) && sched.nmspinning.Load()+sched.npidle.Load() > 0 && pd.syscallwhen+10*1000*1000 > now { + continue + } + // Drop allpLock so we can take sched.lock. + unlock(&allpLock) + // Need to decrement number of idle locked M's + // (pretending that one more is running) before the CAS. + // Otherwise the M from which we retake can exit the syscall, + // increment nmidle and report deadlock. + incidlelocked(-1) + trace := traceAcquire() + if atomic.Cas(&pp.status, s, _Pidle) { + if trace.ok() { + trace.ProcSteal(pp, false) + traceRelease(trace) + } + n++ + pp.syscalltick++ + handoffp(pp) + } else if trace.ok() { + traceRelease(trace) + } + incidlelocked(1) + lock(&allpLock) + } + } + unlock(&allpLock) + return uint32(n) +} + +// Tell all goroutines that they have been preempted and they should stop. +// This function is purely best-effort. It can fail to inform a goroutine if a +// processor just started running it. +// No locks need to be held. +// Returns true if preemption request was issued to at least one goroutine. +func preemptall() bool { + res := false + for _, pp := range allp { + if pp.status != _Prunning { + continue + } + if preemptone(pp) { + res = true + } + } + return res +} + +// Tell the goroutine running on processor P to stop. +// This function is purely best-effort. It can incorrectly fail to inform the +// goroutine. It can inform the wrong goroutine. Even if it informs the +// correct goroutine, that goroutine might ignore the request if it is +// simultaneously executing newstack. +// No lock needs to be held. +// Returns true if preemption request was issued. +// The actual preemption will happen at some point in the future +// and will be indicated by the gp->status no longer being +// Grunning +func preemptone(pp *p) bool { + mp := pp.m.ptr() + if mp == nil || mp == getg().m { + return false + } + gp := mp.curg + if gp == nil || gp == mp.g0 { + return false + } + + gp.preempt = true + + // Every call in a goroutine checks for stack overflow by + // comparing the current stack pointer to gp->stackguard0. + // Setting gp->stackguard0 to StackPreempt folds + // preemption into the normal stack overflow check. + gp.stackguard0 = stackPreempt + + // Request an async preemption of this P. + if preemptMSupported && debug.asyncpreemptoff == 0 { + pp.preempt = true + preemptM(mp) + } + + return true +} + +var starttime int64 + +func schedtrace(detailed bool) { + now := nanotime() + if starttime == 0 { + starttime = now + } + + lock(&sched.lock) + print("SCHED ", (now-starttime)/1e6, "ms: gomaxprocs=", gomaxprocs, " idleprocs=", sched.npidle.Load(), " threads=", mcount(), " spinningthreads=", sched.nmspinning.Load(), " needspinning=", sched.needspinning.Load(), " idlethreads=", sched.nmidle, " runqueue=", sched.runqsize) + if detailed { + print(" gcwaiting=", sched.gcwaiting.Load(), " nmidlelocked=", sched.nmidlelocked, " stopwait=", sched.stopwait, " sysmonwait=", sched.sysmonwait.Load(), "\n") + } + // We must be careful while reading data from P's, M's and G's. + // Even if we hold schedlock, most data can be changed concurrently. + // E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil. + for i, pp := range allp { + mp := pp.m.ptr() + h := atomic.Load(&pp.runqhead) + t := atomic.Load(&pp.runqtail) + if detailed { + print(" P", i, ": status=", pp.status, " schedtick=", pp.schedtick, " syscalltick=", pp.syscalltick, " m=") + if mp != nil { + print(mp.id) + } else { + print("nil") + } + print(" runqsize=", t-h, " gfreecnt=", pp.gFree.n, " timerslen=", len(pp.timers.heap), "\n") + } else { + // In non-detailed mode format lengths of per-P run queues as: + // [len1 len2 len3 len4] + print(" ") + if i == 0 { + print("[") + } + print(t - h) + if i == len(allp)-1 { + print("]\n") + } + } + } + + if !detailed { + unlock(&sched.lock) + return + } + + for mp := allm; mp != nil; mp = mp.alllink { + pp := mp.p.ptr() + print(" M", mp.id, ": p=") + if pp != nil { + print(pp.id) + } else { + print("nil") + } + print(" curg=") + if mp.curg != nil { + print(mp.curg.goid) + } else { + print("nil") + } + print(" mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, " locks=", mp.locks, " dying=", mp.dying, " spinning=", mp.spinning, " blocked=", mp.blocked, " lockedg=") + if lockedg := mp.lockedg.ptr(); lockedg != nil { + print(lockedg.goid) + } else { + print("nil") + } + print("\n") + } + + forEachG(func(gp *g) { + print(" G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason.String(), ") m=") + if gp.m != nil { + print(gp.m.id) + } else { + print("nil") + } + print(" lockedm=") + if lockedm := gp.lockedm.ptr(); lockedm != nil { + print(lockedm.id) + } else { + print("nil") + } + print("\n") + }) + unlock(&sched.lock) +} + +// schedEnableUser enables or disables the scheduling of user +// goroutines. +// +// This does not stop already running user goroutines, so the caller +// should first stop the world when disabling user goroutines. +func schedEnableUser(enable bool) { + lock(&sched.lock) + if sched.disable.user == !enable { + unlock(&sched.lock) + return + } + sched.disable.user = !enable + if enable { + n := sched.disable.n + sched.disable.n = 0 + globrunqputbatch(&sched.disable.runnable, n) + unlock(&sched.lock) + for ; n != 0 && sched.npidle.Load() != 0; n-- { + startm(nil, false, false) + } + } else { + unlock(&sched.lock) + } +} + +// schedEnabled reports whether gp should be scheduled. It returns +// false is scheduling of gp is disabled. +// +// sched.lock must be held. +func schedEnabled(gp *g) bool { + assertLockHeld(&sched.lock) + + if sched.disable.user { + return isSystemGoroutine(gp, true) + } + return true +} + +// Put mp on midle list. +// sched.lock must be held. +// May run during STW, so write barriers are not allowed. +// +//go:nowritebarrierrec +func mput(mp *m) { + assertLockHeld(&sched.lock) + + mp.schedlink = sched.midle + sched.midle.set(mp) + sched.nmidle++ + checkdead() +} + +// Try to get an m from midle list. +// sched.lock must be held. +// May run during STW, so write barriers are not allowed. +// +//go:nowritebarrierrec +func mget() *m { + assertLockHeld(&sched.lock) + + mp := sched.midle.ptr() + if mp != nil { + sched.midle = mp.schedlink + sched.nmidle-- + } + return mp +} + +// Put gp on the global runnable queue. +// sched.lock must be held. +// May run during STW, so write barriers are not allowed. +// +//go:nowritebarrierrec +func globrunqput(gp *g) { + assertLockHeld(&sched.lock) + + sched.runq.pushBack(gp) + sched.runqsize++ +} + +// Put gp at the head of the global runnable queue. +// sched.lock must be held. +// May run during STW, so write barriers are not allowed. +// +//go:nowritebarrierrec +func globrunqputhead(gp *g) { + assertLockHeld(&sched.lock) + + sched.runq.push(gp) + sched.runqsize++ +} + +// Put a batch of runnable goroutines on the global runnable queue. +// This clears *batch. +// sched.lock must be held. +// May run during STW, so write barriers are not allowed. +// +//go:nowritebarrierrec +func globrunqputbatch(batch *gQueue, n int32) { + assertLockHeld(&sched.lock) + + sched.runq.pushBackAll(*batch) + sched.runqsize += n + *batch = gQueue{} +} + +// Try get a batch of G's from the global runnable queue. +// sched.lock must be held. +func globrunqget(pp *p, max int32) *g { + assertLockHeld(&sched.lock) + + if sched.runqsize == 0 { + return nil + } + + n := sched.runqsize/gomaxprocs + 1 + if n > sched.runqsize { + n = sched.runqsize + } + if max > 0 && n > max { + n = max + } + if n > int32(len(pp.runq))/2 { + n = int32(len(pp.runq)) / 2 + } + + sched.runqsize -= n + + gp := sched.runq.pop() + n-- + for ; n > 0; n-- { + gp1 := sched.runq.pop() + runqput(pp, gp1, false) + } + return gp +} + +// pMask is an atomic bitstring with one bit per P. +type pMask []uint32 + +// read returns true if P id's bit is set. +func (p pMask) read(id uint32) bool { + word := id / 32 + mask := uint32(1) << (id % 32) + return (atomic.Load(&p[word]) & mask) != 0 +} + +// set sets P id's bit. +func (p pMask) set(id int32) { + word := id / 32 + mask := uint32(1) << (id % 32) + atomic.Or(&p[word], mask) +} + +// clear clears P id's bit. +func (p pMask) clear(id int32) { + word := id / 32 + mask := uint32(1) << (id % 32) + atomic.And(&p[word], ^mask) +} + +// pidleput puts p on the _Pidle list. now must be a relatively recent call +// to nanotime or zero. Returns now or the current time if now was zero. +// +// This releases ownership of p. Once sched.lock is released it is no longer +// safe to use p. +// +// sched.lock must be held. +// +// May run during STW, so write barriers are not allowed. +// +//go:nowritebarrierrec +func pidleput(pp *p, now int64) int64 { + assertLockHeld(&sched.lock) + + if !runqempty(pp) { + throw("pidleput: P has non-empty run queue") + } + if now == 0 { + now = nanotime() + } + if pp.timers.len.Load() == 0 { + timerpMask.clear(pp.id) + } + idlepMask.set(pp.id) + pp.link = sched.pidle + sched.pidle.set(pp) + sched.npidle.Add(1) + if !pp.limiterEvent.start(limiterEventIdle, now) { + throw("must be able to track idle limiter event") + } + return now +} + +// pidleget tries to get a p from the _Pidle list, acquiring ownership. +// +// sched.lock must be held. +// +// May run during STW, so write barriers are not allowed. +// +//go:nowritebarrierrec +func pidleget(now int64) (*p, int64) { + assertLockHeld(&sched.lock) + + pp := sched.pidle.ptr() + if pp != nil { + // Timer may get added at any time now. + if now == 0 { + now = nanotime() + } + timerpMask.set(pp.id) + idlepMask.clear(pp.id) + sched.pidle = pp.link + sched.npidle.Add(-1) + pp.limiterEvent.stop(limiterEventIdle, now) + } + return pp, now +} + +// pidlegetSpinning tries to get a p from the _Pidle list, acquiring ownership. +// This is called by spinning Ms (or callers than need a spinning M) that have +// found work. If no P is available, this must synchronized with non-spinning +// Ms that may be preparing to drop their P without discovering this work. +// +// sched.lock must be held. +// +// May run during STW, so write barriers are not allowed. +// +//go:nowritebarrierrec +func pidlegetSpinning(now int64) (*p, int64) { + assertLockHeld(&sched.lock) + + pp, now := pidleget(now) + if pp == nil { + // See "Delicate dance" comment in findrunnable. We found work + // that we cannot take, we must synchronize with non-spinning + // Ms that may be preparing to drop their P. + sched.needspinning.Store(1) + return nil, now + } + + return pp, now +} + +// runqempty reports whether pp has no Gs on its local run queue. +// It never returns true spuriously. +func runqempty(pp *p) bool { + // Defend against a race where 1) pp has G1 in runqnext but runqhead == runqtail, + // 2) runqput on pp kicks G1 to the runq, 3) runqget on pp empties runqnext. + // Simply observing that runqhead == runqtail and then observing that runqnext == nil + // does not mean the queue is empty. + for { + head := atomic.Load(&pp.runqhead) + tail := atomic.Load(&pp.runqtail) + runnext := atomic.Loaduintptr((*uintptr)(unsafe.Pointer(&pp.runnext))) + if tail == atomic.Load(&pp.runqtail) { + return head == tail && runnext == 0 + } + } +} + +// To shake out latent assumptions about scheduling order, +// we introduce some randomness into scheduling decisions +// when running with the race detector. +// The need for this was made obvious by changing the +// (deterministic) scheduling order in Go 1.5 and breaking +// many poorly-written tests. +// With the randomness here, as long as the tests pass +// consistently with -race, they shouldn't have latent scheduling +// assumptions. +const randomizeScheduler = raceenabled + +// runqput tries to put g on the local runnable queue. +// If next is false, runqput adds g to the tail of the runnable queue. +// If next is true, runqput puts g in the pp.runnext slot. +// If the run queue is full, runnext puts g on the global queue. +// Executed only by the owner P. +func runqput(pp *p, gp *g, next bool) { + if !haveSysmon && next { + // A runnext goroutine shares the same time slice as the + // current goroutine (inheritTime from runqget). To prevent a + // ping-pong pair of goroutines from starving all others, we + // depend on sysmon to preempt "long-running goroutines". That + // is, any set of goroutines sharing the same time slice. + // + // If there is no sysmon, we must avoid runnext entirely or + // risk starvation. + next = false + } + if randomizeScheduler && next && randn(2) == 0 { + next = false + } + + if next { + retryNext: + oldnext := pp.runnext + if !pp.runnext.cas(oldnext, guintptr(unsafe.Pointer(gp))) { + goto retryNext + } + if oldnext == 0 { + return + } + // Kick the old runnext out to the regular run queue. + gp = oldnext.ptr() + } + +retry: + h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with consumers + t := pp.runqtail + if t-h < uint32(len(pp.runq)) { + pp.runq[t%uint32(len(pp.runq))].set(gp) + atomic.StoreRel(&pp.runqtail, t+1) // store-release, makes the item available for consumption + return + } + if runqputslow(pp, gp, h, t) { + return + } + // the queue is not full, now the put above must succeed + goto retry +} + +// Put g and a batch of work from local runnable queue on global queue. +// Executed only by the owner P. +func runqputslow(pp *p, gp *g, h, t uint32) bool { + var batch [len(pp.runq)/2 + 1]*g + + // First, grab a batch from local queue. + n := t - h + n = n / 2 + if n != uint32(len(pp.runq)/2) { + throw("runqputslow: queue is not full") + } + for i := uint32(0); i < n; i++ { + batch[i] = pp.runq[(h+i)%uint32(len(pp.runq))].ptr() + } + if !atomic.CasRel(&pp.runqhead, h, h+n) { // cas-release, commits consume + return false + } + batch[n] = gp + + if randomizeScheduler { + for i := uint32(1); i <= n; i++ { + j := cheaprandn(i + 1) + batch[i], batch[j] = batch[j], batch[i] + } + } + + // Link the goroutines. + for i := uint32(0); i < n; i++ { + batch[i].schedlink.set(batch[i+1]) + } + var q gQueue + q.head.set(batch[0]) + q.tail.set(batch[n]) + + // Now put the batch on global queue. + lock(&sched.lock) + globrunqputbatch(&q, int32(n+1)) + unlock(&sched.lock) + return true +} + +// runqputbatch tries to put all the G's on q on the local runnable queue. +// If the queue is full, they are put on the global queue; in that case +// this will temporarily acquire the scheduler lock. +// Executed only by the owner P. +func runqputbatch(pp *p, q *gQueue, qsize int) { + h := atomic.LoadAcq(&pp.runqhead) + t := pp.runqtail + n := uint32(0) + for !q.empty() && t-h < uint32(len(pp.runq)) { + gp := q.pop() + pp.runq[t%uint32(len(pp.runq))].set(gp) + t++ + n++ + } + qsize -= int(n) + + if randomizeScheduler { + off := func(o uint32) uint32 { + return (pp.runqtail + o) % uint32(len(pp.runq)) + } + for i := uint32(1); i < n; i++ { + j := cheaprandn(i + 1) + pp.runq[off(i)], pp.runq[off(j)] = pp.runq[off(j)], pp.runq[off(i)] + } + } + + atomic.StoreRel(&pp.runqtail, t) + if !q.empty() { + lock(&sched.lock) + globrunqputbatch(q, int32(qsize)) + unlock(&sched.lock) + } +} + +// Get g from local runnable queue. +// If inheritTime is true, gp should inherit the remaining time in the +// current time slice. Otherwise, it should start a new time slice. +// Executed only by the owner P. +func runqget(pp *p) (gp *g, inheritTime bool) { + // If there's a runnext, it's the next G to run. + next := pp.runnext + // If the runnext is non-0 and the CAS fails, it could only have been stolen by another P, + // because other Ps can race to set runnext to 0, but only the current P can set it to non-0. + // Hence, there's no need to retry this CAS if it fails. + if next != 0 && pp.runnext.cas(next, 0) { + return next.ptr(), true + } + + for { + h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with other consumers + t := pp.runqtail + if t == h { + return nil, false + } + gp := pp.runq[h%uint32(len(pp.runq))].ptr() + if atomic.CasRel(&pp.runqhead, h, h+1) { // cas-release, commits consume + return gp, false + } + } +} + +// runqdrain drains the local runnable queue of pp and returns all goroutines in it. +// Executed only by the owner P. +func runqdrain(pp *p) (drainQ gQueue, n uint32) { + oldNext := pp.runnext + if oldNext != 0 && pp.runnext.cas(oldNext, 0) { + drainQ.pushBack(oldNext.ptr()) + n++ + } + +retry: + h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with other consumers + t := pp.runqtail + qn := t - h + if qn == 0 { + return + } + if qn > uint32(len(pp.runq)) { // read inconsistent h and t + goto retry + } + + if !atomic.CasRel(&pp.runqhead, h, h+qn) { // cas-release, commits consume + goto retry + } + + // We've inverted the order in which it gets G's from the local P's runnable queue + // and then advances the head pointer because we don't want to mess up the statuses of G's + // while runqdrain() and runqsteal() are running in parallel. + // Thus we should advance the head pointer before draining the local P into a gQueue, + // so that we can update any gp.schedlink only after we take the full ownership of G, + // meanwhile, other P's can't access to all G's in local P's runnable queue and steal them. + // See https://groups.google.com/g/golang-dev/c/0pTKxEKhHSc/m/6Q85QjdVBQAJ for more details. + for i := uint32(0); i < qn; i++ { + gp := pp.runq[(h+i)%uint32(len(pp.runq))].ptr() + drainQ.pushBack(gp) + n++ + } + return +} + +// Grabs a batch of goroutines from pp's runnable queue into batch. +// Batch is a ring buffer starting at batchHead. +// Returns number of grabbed goroutines. +// Can be executed by any P. +func runqgrab(pp *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool) uint32 { + for { + h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with other consumers + t := atomic.LoadAcq(&pp.runqtail) // load-acquire, synchronize with the producer + n := t - h + n = n - n/2 + if n == 0 { + if stealRunNextG { + // Try to steal from pp.runnext. + if next := pp.runnext; next != 0 { + if pp.status == _Prunning { + // Sleep to ensure that pp isn't about to run the g + // we are about to steal. + // The important use case here is when the g running + // on pp ready()s another g and then almost + // immediately blocks. Instead of stealing runnext + // in this window, back off to give pp a chance to + // schedule runnext. This will avoid thrashing gs + // between different Ps. + // A sync chan send/recv takes ~50ns as of time of + // writing, so 3us gives ~50x overshoot. + if !osHasLowResTimer { + usleep(3) + } else { + // On some platforms system timer granularity is + // 1-15ms, which is way too much for this + // optimization. So just yield. + osyield() + } + } + if !pp.runnext.cas(next, 0) { + continue + } + batch[batchHead%uint32(len(batch))] = next + return 1 + } + } + return 0 + } + if n > uint32(len(pp.runq)/2) { // read inconsistent h and t + continue + } + for i := uint32(0); i < n; i++ { + g := pp.runq[(h+i)%uint32(len(pp.runq))] + batch[(batchHead+i)%uint32(len(batch))] = g + } + if atomic.CasRel(&pp.runqhead, h, h+n) { // cas-release, commits consume + return n + } + } +} + +// Steal half of elements from local runnable queue of p2 +// and put onto local runnable queue of p. +// Returns one of the stolen elements (or nil if failed). +func runqsteal(pp, p2 *p, stealRunNextG bool) *g { + t := pp.runqtail + n := runqgrab(p2, &pp.runq, t, stealRunNextG) + if n == 0 { + return nil + } + n-- + gp := pp.runq[(t+n)%uint32(len(pp.runq))].ptr() + if n == 0 { + return gp + } + h := atomic.LoadAcq(&pp.runqhead) // load-acquire, synchronize with consumers + if t-h+n >= uint32(len(pp.runq)) { + throw("runqsteal: runq overflow") + } + atomic.StoreRel(&pp.runqtail, t+n) // store-release, makes the item available for consumption + return gp +} + +// A gQueue is a dequeue of Gs linked through g.schedlink. A G can only +// be on one gQueue or gList at a time. +type gQueue struct { + head guintptr + tail guintptr +} + +// empty reports whether q is empty. +func (q *gQueue) empty() bool { + return q.head == 0 +} + +// push adds gp to the head of q. +func (q *gQueue) push(gp *g) { + gp.schedlink = q.head + q.head.set(gp) + if q.tail == 0 { + q.tail.set(gp) + } +} + +// pushBack adds gp to the tail of q. +func (q *gQueue) pushBack(gp *g) { + gp.schedlink = 0 + if q.tail != 0 { + q.tail.ptr().schedlink.set(gp) + } else { + q.head.set(gp) + } + q.tail.set(gp) +} + +// pushBackAll adds all Gs in q2 to the tail of q. After this q2 must +// not be used. +func (q *gQueue) pushBackAll(q2 gQueue) { + if q2.tail == 0 { + return + } + q2.tail.ptr().schedlink = 0 + if q.tail != 0 { + q.tail.ptr().schedlink = q2.head + } else { + q.head = q2.head + } + q.tail = q2.tail +} + +// pop removes and returns the head of queue q. It returns nil if +// q is empty. +func (q *gQueue) pop() *g { + gp := q.head.ptr() + if gp != nil { + q.head = gp.schedlink + if q.head == 0 { + q.tail = 0 + } + } + return gp +} + +// popList takes all Gs in q and returns them as a gList. +func (q *gQueue) popList() gList { + stack := gList{q.head} + *q = gQueue{} + return stack +} + +// A gList is a list of Gs linked through g.schedlink. A G can only be +// on one gQueue or gList at a time. +type gList struct { + head guintptr +} + +// empty reports whether l is empty. +func (l *gList) empty() bool { + return l.head == 0 +} + +// push adds gp to the head of l. +func (l *gList) push(gp *g) { + gp.schedlink = l.head + l.head.set(gp) +} + +// pushAll prepends all Gs in q to l. +func (l *gList) pushAll(q gQueue) { + if !q.empty() { + q.tail.ptr().schedlink = l.head + l.head = q.head + } +} + +// pop removes and returns the head of l. If l is empty, it returns nil. +func (l *gList) pop() *g { + gp := l.head.ptr() + if gp != nil { + l.head = gp.schedlink + } + return gp +} + +//go:linkname setMaxThreads runtime/debug.setMaxThreads +func setMaxThreads(in int) (out int) { + lock(&sched.lock) + out = int(sched.maxmcount) + if in > 0x7fffffff { // MaxInt32 + sched.maxmcount = 0x7fffffff + } else { + sched.maxmcount = int32(in) + } + checkmcount() + unlock(&sched.lock) + return +} + +// procPin should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/choleraehyq/pid +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname procPin +//go:nosplit +func procPin() int { + gp := getg() + mp := gp.m + + mp.locks++ + return int(mp.p.ptr().id) +} + +// procUnpin should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/choleraehyq/pid +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname procUnpin +//go:nosplit +func procUnpin() { + gp := getg() + gp.m.locks-- +} + +//go:linkname sync_runtime_procPin sync.runtime_procPin +//go:nosplit +func sync_runtime_procPin() int { + return procPin() +} + +//go:linkname sync_runtime_procUnpin sync.runtime_procUnpin +//go:nosplit +func sync_runtime_procUnpin() { + procUnpin() +} + +//go:linkname sync_atomic_runtime_procPin sync/atomic.runtime_procPin +//go:nosplit +func sync_atomic_runtime_procPin() int { + return procPin() +} + +//go:linkname sync_atomic_runtime_procUnpin sync/atomic.runtime_procUnpin +//go:nosplit +func sync_atomic_runtime_procUnpin() { + procUnpin() +} + +// Active spinning for sync.Mutex. +// +// sync_runtime_canSpin should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/livekit/protocol +// - github.com/sagernet/gvisor +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname sync_runtime_canSpin sync.runtime_canSpin +//go:nosplit +func sync_runtime_canSpin(i int) bool { + // sync.Mutex is cooperative, so we are conservative with spinning. + // Spin only few times and only if running on a multicore machine and + // GOMAXPROCS>1 and there is at least one other running P and local runq is empty. + // As opposed to runtime mutex we don't do passive spinning here, + // because there can be work on global runq or on other Ps. + if i >= active_spin || ncpu <= 1 || gomaxprocs <= sched.npidle.Load()+sched.nmspinning.Load()+1 { + return false + } + if p := getg().m.p.ptr(); !runqempty(p) { + return false + } + return true +} + +// sync_runtime_doSpin should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/livekit/protocol +// - github.com/sagernet/gvisor +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname sync_runtime_doSpin sync.runtime_doSpin +//go:nosplit +func sync_runtime_doSpin() { + procyield(active_spin_cnt) +} + +var stealOrder randomOrder + +// randomOrder/randomEnum are helper types for randomized work stealing. +// They allow to enumerate all Ps in different pseudo-random orders without repetitions. +// The algorithm is based on the fact that if we have X such that X and GOMAXPROCS +// are coprime, then a sequences of (i + X) % GOMAXPROCS gives the required enumeration. +type randomOrder struct { + count uint32 + coprimes []uint32 +} + +type randomEnum struct { + i uint32 + count uint32 + pos uint32 + inc uint32 +} + +func (ord *randomOrder) reset(count uint32) { + ord.count = count + ord.coprimes = ord.coprimes[:0] + for i := uint32(1); i <= count; i++ { + if gcd(i, count) == 1 { + ord.coprimes = append(ord.coprimes, i) + } + } +} + +func (ord *randomOrder) start(i uint32) randomEnum { + return randomEnum{ + count: ord.count, + pos: i % ord.count, + inc: ord.coprimes[i/ord.count%uint32(len(ord.coprimes))], + } +} + +func (enum *randomEnum) done() bool { + return enum.i == enum.count +} + +func (enum *randomEnum) next() { + enum.i++ + enum.pos = (enum.pos + enum.inc) % enum.count +} + +func (enum *randomEnum) position() uint32 { + return enum.pos +} + +func gcd(a, b uint32) uint32 { + for b != 0 { + a, b = b, a%b + } + return a +} + +// An initTask represents the set of initializations that need to be done for a package. +// Keep in sync with ../../test/noinit.go:initTask +type initTask struct { + state uint32 // 0 = uninitialized, 1 = in progress, 2 = done + nfns uint32 + // followed by nfns pcs, uintptr sized, one per init function to run +} + +// inittrace stores statistics for init functions which are +// updated by malloc and newproc when active is true. +var inittrace tracestat + +type tracestat struct { + active bool // init tracing activation status + id uint64 // init goroutine id + allocs uint64 // heap allocations + bytes uint64 // heap allocated bytes +} + +func doInit(ts []*initTask) { + for _, t := range ts { + doInit1(t) + } +} + +func doInit1(t *initTask) { + switch t.state { + case 2: // fully initialized + return + case 1: // initialization in progress + throw("recursive call during initialization - linker skew") + default: // not initialized yet + t.state = 1 // initialization in progress + + var ( + start int64 + before tracestat + ) + + if inittrace.active { + start = nanotime() + // Load stats non-atomically since tracinit is updated only by this init goroutine. + before = inittrace + } + + if t.nfns == 0 { + // We should have pruned all of these in the linker. + throw("inittask with no functions") + } + + firstFunc := add(unsafe.Pointer(t), 8) + for i := uint32(0); i < t.nfns; i++ { + p := add(firstFunc, uintptr(i)*goarch.PtrSize) + f := *(*func())(unsafe.Pointer(&p)) + f() + } + + if inittrace.active { + end := nanotime() + // Load stats non-atomically since tracinit is updated only by this init goroutine. + after := inittrace + + f := *(*func())(unsafe.Pointer(&firstFunc)) + pkg := funcpkgpath(findfunc(abi.FuncPCABIInternal(f))) + + var sbuf [24]byte + print("init ", pkg, " @") + print(string(fmtNSAsMS(sbuf[:], uint64(start-runtimeInitTime))), " ms, ") + print(string(fmtNSAsMS(sbuf[:], uint64(end-start))), " ms clock, ") + print(string(itoa(sbuf[:], after.bytes-before.bytes)), " bytes, ") + print(string(itoa(sbuf[:], after.allocs-before.allocs)), " allocs") + print("\n") + } + + t.state = 2 // initialization done + } +} diff --git a/contrib/go/_std_1.22/src/runtime/profbuf.go b/contrib/go/_std_1.23/src/runtime/profbuf.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/profbuf.go rename to contrib/go/_std_1.23/src/runtime/profbuf.go index d3afbcd8c745..8ae626b1b085 100644 --- a/contrib/go/_std_1.22/src/runtime/profbuf.go +++ b/contrib/go/_std_1.23/src/runtime/profbuf.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -367,10 +367,8 @@ func (b *profBuf) write(tagPtr *unsafe.Pointer, now int64, hdr []uint64, stk []u data[0] = uint64(2 + b.hdrsize + uintptr(len(stk))) // length data[1] = uint64(now) // time stamp // header, zero-padded - i := uintptr(copy(data[2:2+b.hdrsize], hdr)) - for ; i < b.hdrsize; i++ { - data[2+i] = 0 - } + i := copy(data[2:2+b.hdrsize], hdr) + clear(data[2+i : 2+b.hdrsize]) for i, pc := range stk { data[2+b.hdrsize+uintptr(i)] = uint64(pc) } @@ -469,9 +467,7 @@ Read: dst := b.overflowBuf dst[0] = uint64(2 + b.hdrsize + 1) dst[1] = time - for i := uintptr(0); i < b.hdrsize; i++ { - dst[2+i] = 0 - } + clear(dst[2 : 2+b.hdrsize]) dst[2+b.hdrsize] = uint64(count) return dst[:2+b.hdrsize+1], overflowTag[:1], false } diff --git a/contrib/go/_std_1.23/src/runtime/proflabel.go b/contrib/go/_std_1.23/src/runtime/proflabel.go new file mode 100644 index 000000000000..1a5e7e5e2f14 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/proflabel.go @@ -0,0 +1,58 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +var labelSync uintptr + +// runtime_setProfLabel should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/localsession +// - github.com/DataDog/datadog-agent +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname runtime_setProfLabel runtime/pprof.runtime_setProfLabel +func runtime_setProfLabel(labels unsafe.Pointer) { + // Introduce race edge for read-back via profile. + // This would more properly use &getg().labels as the sync address, + // but we do the read in a signal handler and can't call the race runtime then. + // + // This uses racereleasemerge rather than just racerelease so + // the acquire in profBuf.read synchronizes with *all* prior + // setProfLabel operations, not just the most recent one. This + // is important because profBuf.read will observe different + // labels set by different setProfLabel operations on + // different goroutines, so it needs to synchronize with all + // of them (this wouldn't be an issue if we could synchronize + // on &getg().labels since we would synchronize with each + // most-recent labels write separately.) + // + // racereleasemerge is like a full read-modify-write on + // labelSync, rather than just a store-release, so it carries + // a dependency on the previous racereleasemerge, which + // ultimately carries forward to the acquire in profBuf.read. + if raceenabled { + racereleasemerge(unsafe.Pointer(&labelSync)) + } + getg().labels = labels +} + +// runtime_getProfLabel should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/localsession +// - github.com/DataDog/datadog-agent +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel +func runtime_getProfLabel() unsafe.Pointer { + return getg().labels +} diff --git a/contrib/go/_std_1.22/src/runtime/race.go b/contrib/go/_std_1.23/src/runtime/race.go similarity index 91% rename from contrib/go/_std_1.22/src/runtime/race.go rename to contrib/go/_std_1.23/src/runtime/race.go index ca4f05197990..7d5cbce49ee2 100644 --- a/contrib/go/_std_1.22/src/runtime/race.go +++ b/contrib/go/_std_1.23/src/runtime/race.go @@ -93,8 +93,8 @@ const raceenabled = true // callerpc is a return PC of the function that calls this function, // pc is start PC of the function that calls this function. func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { - kind := t.Kind_ & kindMask - if kind == kindArray || kind == kindStruct { + kind := t.Kind_ & abi.KindMask + if kind == abi.Array || kind == abi.Struct { // for composite objects we have to read every address // because a write might happen to any subobject. racereadrangepc(addr, t.Size_, callerpc, pc) @@ -106,8 +106,8 @@ func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { } func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { - kind := t.Kind_ & kindMask - if kind == kindArray || kind == kindStruct { + kind := t.Kind_ & abi.KindMask + if kind == abi.Array || kind == abi.Struct { // for composite objects we have to write every address // because a write might happen to any subobject. racewriterangepc(addr, t.Size_, callerpc, pc) @@ -323,6 +323,10 @@ var __tsan_report_count byte //go:cgo_import_static __tsan_go_atomic64_exchange //go:cgo_import_static __tsan_go_atomic32_fetch_add //go:cgo_import_static __tsan_go_atomic64_fetch_add +//go:cgo_import_static __tsan_go_atomic32_fetch_and +//go:cgo_import_static __tsan_go_atomic64_fetch_and +//go:cgo_import_static __tsan_go_atomic32_fetch_or +//go:cgo_import_static __tsan_go_atomic64_fetch_or //go:cgo_import_static __tsan_go_atomic32_compare_exchange //go:cgo_import_static __tsan_go_atomic64_compare_exchange @@ -642,6 +646,36 @@ func abigen_sync_atomic_AddUint64(addr *uint64, delta uint64) (new uint64) //go:linkname abigen_sync_atomic_AddUintptr sync/atomic.AddUintptr func abigen_sync_atomic_AddUintptr(addr *uintptr, delta uintptr) (new uintptr) +//go:linkname abigen_sync_atomic_AndInt32 sync/atomic.AndInt32 +func abigen_sync_atomic_AndInt32(addr *int32, mask int32) (old int32) + +//go:linkname abigen_sync_atomic_AndUint32 sync/atomic.AndUint32 +func abigen_sync_atomic_AndUint32(addr *uint32, mask uint32) (old uint32) + +//go:linkname abigen_sync_atomic_AndInt64 sync/atomic.AndInt64 +func abigen_sync_atomic_AndInt64(addr *int64, mask int64) (old int64) + +//go:linkname abigen_sync_atomic_AndUint64 sync/atomic.AndUint64 +func abigen_sync_atomic_AndUint64(addr *uint64, mask uint64) (old uint64) + +//go:linkname abigen_sync_atomic_AndUintptr sync/atomic.AndUintptr +func abigen_sync_atomic_AndUintptr(addr *uintptr, mask uintptr) (old uintptr) + +//go:linkname abigen_sync_atomic_OrInt32 sync/atomic.OrInt32 +func abigen_sync_atomic_OrInt32(addr *int32, mask int32) (old int32) + +//go:linkname abigen_sync_atomic_OrUint32 sync/atomic.OrUint32 +func abigen_sync_atomic_OrUint32(addr *uint32, mask uint32) (old uint32) + +//go:linkname abigen_sync_atomic_OrInt64 sync/atomic.OrInt64 +func abigen_sync_atomic_OrInt64(addr *int64, mask int64) (old int64) + +//go:linkname abigen_sync_atomic_OrUint64 sync/atomic.OrUint64 +func abigen_sync_atomic_OrUint64(addr *uint64, mask uint64) (old uint64) + +//go:linkname abigen_sync_atomic_OrUintptr sync/atomic.OrUintptr +func abigen_sync_atomic_OrUintptr(addr *uintptr, mask uintptr) (old uintptr) + //go:linkname abigen_sync_atomic_CompareAndSwapInt32 sync/atomic.CompareAndSwapInt32 func abigen_sync_atomic_CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool) diff --git a/contrib/go/_std_1.22/src/runtime/race/README b/contrib/go/_std_1.23/src/runtime/race/README similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/README rename to contrib/go/_std_1.23/src/runtime/race/README diff --git a/contrib/go/_std_1.22/src/runtime/race/doc.go b/contrib/go/_std_1.23/src/runtime/race/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/doc.go rename to contrib/go/_std_1.23/src/runtime/race/doc.go diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/doc.go b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/doc.go rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/doc.go diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_darwin.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_darwin.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_darwin.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_darwin.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_freebsd.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_freebsd.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_freebsd.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_freebsd.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_linux.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_linux.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_linux.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_linux.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_netbsd.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_netbsd.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_netbsd.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_netbsd.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_openbsd.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_openbsd.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_openbsd.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_openbsd.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_windows.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_windows.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_windows.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_windows.syso diff --git a/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/ya.make b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/ya.make new file mode 100644 index 000000000000..1c86c9c503c1 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/ya.make @@ -0,0 +1,28 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + race_darwin.syso + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race_darwin.syso + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + race_linux.syso + ) +ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race_linux.syso + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race_windows.syso + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/doc.go b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/doc.go rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/doc.go diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/race_linux.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/race_linux.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/race_linux.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/race_linux.syso diff --git a/contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/ya.make b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/ya.make new file mode 100644 index 000000000000..9d6026226191 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/ya.make @@ -0,0 +1,9 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + race_linux.syso + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/ya.make b/contrib/go/_std_1.23/src/runtime/race/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/ya.make rename to contrib/go/_std_1.23/src/runtime/race/internal/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/race/race.go b/contrib/go/_std_1.23/src/runtime/race/race.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race.go rename to contrib/go/_std_1.23/src/runtime/race/race.go diff --git a/contrib/go/_std_1.22/src/runtime/race/race_darwin_amd64.go b/contrib/go/_std_1.23/src/runtime/race/race_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_darwin_amd64.go rename to contrib/go/_std_1.23/src/runtime/race/race_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/race/race_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/race/race_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/race/race_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/race/race_darwin_arm64.syso b/contrib/go/_std_1.23/src/runtime/race/race_darwin_arm64.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_darwin_arm64.syso rename to contrib/go/_std_1.23/src/runtime/race/race_darwin_arm64.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/race_linux_arm64.syso b/contrib/go/_std_1.23/src/runtime/race/race_linux_arm64.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_linux_arm64.syso rename to contrib/go/_std_1.23/src/runtime/race/race_linux_arm64.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/race_linux_ppc64le.syso b/contrib/go/_std_1.23/src/runtime/race/race_linux_ppc64le.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_linux_ppc64le.syso rename to contrib/go/_std_1.23/src/runtime/race/race_linux_ppc64le.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/race_linux_s390x.syso b/contrib/go/_std_1.23/src/runtime/race/race_linux_s390x.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_linux_s390x.syso rename to contrib/go/_std_1.23/src/runtime/race/race_linux_s390x.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/race_v1_amd64.go b/contrib/go/_std_1.23/src/runtime/race/race_v1_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_v1_amd64.go rename to contrib/go/_std_1.23/src/runtime/race/race_v1_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/race/race_v3_amd64.go b/contrib/go/_std_1.23/src/runtime/race/race_v3_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_v3_amd64.go rename to contrib/go/_std_1.23/src/runtime/race/race_v3_amd64.go diff --git a/contrib/go/_std_1.23/src/runtime/race/ya.make b/contrib/go/_std_1.23/src/runtime/race/ya.make new file mode 100644 index 000000000000..4ec901771c98 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/race/ya.make @@ -0,0 +1,58 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race_darwin_arm64.go + race_darwin_arm64.syso + ) +ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race_darwin_arm64.syso + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race_darwin_amd64.go + race_v1_amd64.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race_v1_amd64.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED) + SRCS( + doc.go + race_linux_arm64.syso + ) + +IF (CGO_ENABLED) + CGO_SRCS( + race.go + ) +ENDIF() +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race_linux_arm64.syso + ) +ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED) + SRCS( + doc.go + race_v1_amd64.go + ) + +IF (CGO_ENABLED) + CGO_SRCS( + race.go + ) +ENDIF() +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/race0.go b/contrib/go/_std_1.23/src/runtime/race0.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race0.go rename to contrib/go/_std_1.23/src/runtime/race0.go diff --git a/contrib/go/_std_1.22/src/runtime/race_amd64.s b/contrib/go/_std_1.23/src/runtime/race_amd64.s similarity index 92% rename from contrib/go/_std_1.22/src/runtime/race_amd64.s rename to contrib/go/_std_1.23/src/runtime/race_amd64.s index 45c1255509c8..c4a6d493162c 100644 --- a/contrib/go/_std_1.22/src/runtime/race_amd64.s +++ b/contrib/go/_std_1.23/src/runtime/race_amd64.s @@ -303,6 +303,57 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24 GO_ARGS JMP sync∕atomic·AddInt64(SB) +// And +TEXT sync∕atomic·AndInt32(SB), NOSPLIT|NOFRAME, $0-20 + GO_ARGS + MOVQ $__tsan_go_atomic32_fetch_and(SB), AX + CALL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndInt64(SB), NOSPLIT|NOFRAME, $0-24 + GO_ARGS + MOVQ $__tsan_go_atomic64_fetch_and(SB), AX + CALL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·AndInt32(SB) + +TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +// Or +TEXT sync∕atomic·OrInt32(SB), NOSPLIT|NOFRAME, $0-20 + GO_ARGS + MOVQ $__tsan_go_atomic32_fetch_or(SB), AX + CALL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrInt64(SB), NOSPLIT|NOFRAME, $0-24 + GO_ARGS + MOVQ $__tsan_go_atomic64_fetch_or(SB), AX + CALL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·OrInt32(SB) + +TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + +TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + + // CompareAndSwap TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT|NOFRAME, $0-17 GO_ARGS diff --git a/contrib/go/_std_1.22/src/runtime/race_arm64.s b/contrib/go/_std_1.23/src/runtime/race_arm64.s similarity index 91% rename from contrib/go/_std_1.22/src/runtime/race_arm64.s rename to contrib/go/_std_1.23/src/runtime/race_arm64.s index c818345852f6..c42a6c137752 100644 --- a/contrib/go/_std_1.22/src/runtime/race_arm64.s +++ b/contrib/go/_std_1.23/src/runtime/race_arm64.s @@ -312,6 +312,56 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24 GO_ARGS JMP sync∕atomic·AddInt64(SB) +// And +TEXT sync∕atomic·AndInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_and(SB), R9 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_and(SB), R9 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·AndInt32(SB) + +TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +// Or +TEXT sync∕atomic·OrInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_or(SB), R9 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_or(SB), R9 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·OrInt32(SB) + +TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + +TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + // CompareAndSwap TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17 GO_ARGS @@ -419,6 +469,10 @@ TEXT racecall<>(SB), NOSPLIT|NOFRAME, $0-0 MOVD (g_sched+gobuf_sp)(R11), R12 MOVD R12, RSP call: + // Decrement SP past where the frame pointer is saved in the Go arm64 + // ABI (one word below the stack pointer) so the race detector library + // code doesn't clobber it + SUB $16, RSP BL R9 MOVD R19, RSP JMP (R20) diff --git a/contrib/go/_std_1.22/src/runtime/race_ppc64le.s b/contrib/go/_std_1.23/src/runtime/race_ppc64le.s similarity index 93% rename from contrib/go/_std_1.22/src/runtime/race_ppc64le.s rename to contrib/go/_std_1.23/src/runtime/race_ppc64le.s index 39cfffc39bbe..43829479bde8 100644 --- a/contrib/go/_std_1.22/src/runtime/race_ppc64le.s +++ b/contrib/go/_std_1.23/src/runtime/race_ppc64le.s @@ -325,6 +325,52 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24 GO_ARGS BR sync∕atomic·AddInt64(SB) +// And +TEXT sync∕atomic·AndInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_and(SB), R8 + BR racecallatomic<>(SB) + +TEXT sync∕atomic·AndInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_and(SB), R8 + BR racecallatomic<>(SB) + +TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20 + GO_ARGS + BR sync∕atomic·AndInt32(SB) + +TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24 + GO_ARGS + BR sync∕atomic·AndInt64(SB) + +TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + BR sync∕atomic·AndInt64(SB) + +// Or +TEXT sync∕atomic·OrInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_or(SB), R8 + BR racecallatomic<>(SB) + +TEXT sync∕atomic·OrInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_or(SB), R8 + BR racecallatomic<>(SB) + +TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20 + GO_ARGS + BR sync∕atomic·OrInt32(SB) + +TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24 + GO_ARGS + BR sync∕atomic·OrInt64(SB) + +TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + BR sync∕atomic·OrInt64(SB) + // CompareAndSwap in tsan TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17 GO_ARGS diff --git a/contrib/go/_std_1.22/src/runtime/race_s390x.s b/contrib/go/_std_1.23/src/runtime/race_s390x.s similarity index 91% rename from contrib/go/_std_1.22/src/runtime/race_s390x.s rename to contrib/go/_std_1.23/src/runtime/race_s390x.s index dadc12f4dbfb..8e6a5d576ab4 100644 --- a/contrib/go/_std_1.22/src/runtime/race_s390x.s +++ b/contrib/go/_std_1.23/src/runtime/race_s390x.s @@ -274,6 +274,56 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24 GO_ARGS JMP sync∕atomic·AddInt64(SB) +// And +TEXT sync∕atomic·AndInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_and(SB), R1 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_and(SB), R1 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·AndInt32(SB) + +TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +// Or +TEXT sync∕atomic·OrInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_or(SB), R1 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_or(SB), R1 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·OrInt32(SB) + +TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + +TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + // CompareAndSwap TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17 diff --git a/contrib/go/_std_1.23/src/runtime/rand.go b/contrib/go/_std_1.23/src/runtime/rand.go new file mode 100644 index 000000000000..a66553feebe3 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/rand.go @@ -0,0 +1,280 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Random number generation + +package runtime + +import ( + "internal/chacha8rand" + "internal/goarch" + "runtime/internal/math" + "unsafe" + _ "unsafe" // for go:linkname +) + +// OS-specific startup can set startupRand if the OS passes +// random data to the process at startup time. +// For example Linux passes 16 bytes in the auxv vector. +var startupRand []byte + +// globalRand holds the global random state. +// It is only used at startup and for creating new m's. +// Otherwise the per-m random state should be used +// by calling goodrand. +var globalRand struct { + lock mutex + seed [32]byte + state chacha8rand.State + init bool +} + +var readRandomFailed bool + +// randinit initializes the global random state. +// It must be called before any use of grand. +func randinit() { + lock(&globalRand.lock) + if globalRand.init { + fatal("randinit twice") + } + + seed := &globalRand.seed + if startupRand != nil { + for i, c := range startupRand { + seed[i%len(seed)] ^= c + } + clear(startupRand) + startupRand = nil + } else { + if readRandom(seed[:]) != len(seed) { + // readRandom should never fail, but if it does we'd rather + // not make Go binaries completely unusable, so make up + // some random data based on the current time. + readRandomFailed = true + readTimeRandom(seed[:]) + } + } + globalRand.state.Init(*seed) + clear(seed[:]) + globalRand.init = true + unlock(&globalRand.lock) +} + +// readTimeRandom stretches any entropy in the current time +// into entropy the length of r and XORs it into r. +// This is a fallback for when readRandom does not read +// the full requested amount. +// Whatever entropy r already contained is preserved. +func readTimeRandom(r []byte) { + // Inspired by wyrand. + // An earlier version of this code used getg().m.procid as well, + // but note that this is called so early in startup that procid + // is not initialized yet. + v := uint64(nanotime()) + for len(r) > 0 { + v ^= 0xa0761d6478bd642f + v *= 0xe7037ed1a0b428db + size := 8 + if len(r) < 8 { + size = len(r) + } + for i := 0; i < size; i++ { + r[i] ^= byte(v >> (8 * i)) + } + r = r[size:] + v = v>>32 | v<<32 + } +} + +// bootstrapRand returns a random uint64 from the global random generator. +func bootstrapRand() uint64 { + lock(&globalRand.lock) + if !globalRand.init { + fatal("randinit missed") + } + for { + if x, ok := globalRand.state.Next(); ok { + unlock(&globalRand.lock) + return x + } + globalRand.state.Refill() + } +} + +// bootstrapRandReseed reseeds the bootstrap random number generator, +// clearing from memory any trace of previously returned random numbers. +func bootstrapRandReseed() { + lock(&globalRand.lock) + if !globalRand.init { + fatal("randinit missed") + } + globalRand.state.Reseed() + unlock(&globalRand.lock) +} + +// rand32 is uint32(rand()), called from compiler-generated code. +// +//go:nosplit +func rand32() uint32 { + return uint32(rand()) +} + +// rand returns a random uint64 from the per-m chacha8 state. +// Do not change signature: used via linkname from other packages. +// +//go:nosplit +//go:linkname rand +func rand() uint64 { + // Note: We avoid acquirem here so that in the fast path + // there is just a getg, an inlined c.Next, and a return. + // The performance difference on a 16-core AMD is + // 3.7ns/call this way versus 4.3ns/call with acquirem (+16%). + mp := getg().m + c := &mp.chacha8 + for { + // Note: c.Next is marked nosplit, + // so we don't need to use mp.locks + // on the fast path, which is that the + // first attempt succeeds. + x, ok := c.Next() + if ok { + return x + } + mp.locks++ // hold m even though c.Refill may do stack split checks + c.Refill() + mp.locks-- + } +} + +// mrandinit initializes the random state of an m. +func mrandinit(mp *m) { + var seed [4]uint64 + for i := range seed { + seed[i] = bootstrapRand() + } + bootstrapRandReseed() // erase key we just extracted + mp.chacha8.Init64(seed) + mp.cheaprand = rand() +} + +// randn is like rand() % n but faster. +// Do not change signature: used via linkname from other packages. +// +//go:nosplit +//go:linkname randn +func randn(n uint32) uint32 { + // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ + return uint32((uint64(uint32(rand())) * uint64(n)) >> 32) +} + +// cheaprand is a non-cryptographic-quality 32-bit random generator +// suitable for calling at very high frequency (such as during scheduling decisions) +// and at sensitive moments in the runtime (such as during stack unwinding). +// it is "cheap" in the sense of both expense and quality. +// +// cheaprand must not be exported to other packages: +// the rule is that other packages using runtime-provided +// randomness must always use rand. +// +// cheaprand should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cheaprand +//go:nosplit +func cheaprand() uint32 { + mp := getg().m + // Implement wyrand: https://github.com/wangyi-fudan/wyhash + // Only the platform that math.Mul64 can be lowered + // by the compiler should be in this list. + if goarch.IsAmd64|goarch.IsArm64|goarch.IsPpc64| + goarch.IsPpc64le|goarch.IsMips64|goarch.IsMips64le| + goarch.IsS390x|goarch.IsRiscv64|goarch.IsLoong64 == 1 { + mp.cheaprand += 0xa0761d6478bd642f + hi, lo := math.Mul64(mp.cheaprand, mp.cheaprand^0xe7037ed1a0b428db) + return uint32(hi ^ lo) + } + + // Implement xorshift64+: 2 32-bit xorshift sequences added together. + // Shift triplet [17,7,16] was calculated as indicated in Marsaglia's + // Xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf + // This generator passes the SmallCrush suite, part of TestU01 framework: + // http://simul.iro.umontreal.ca/testu01/tu01.html + t := (*[2]uint32)(unsafe.Pointer(&mp.cheaprand)) + s1, s0 := t[0], t[1] + s1 ^= s1 << 17 + s1 = s1 ^ s0 ^ s1>>7 ^ s0>>16 + t[0], t[1] = s0, s1 + return s0 + s1 +} + +// cheaprand64 is a non-cryptographic-quality 63-bit random generator +// suitable for calling at very high frequency (such as during sampling decisions). +// it is "cheap" in the sense of both expense and quality. +// +// cheaprand64 must not be exported to other packages: +// the rule is that other packages using runtime-provided +// randomness must always use rand. +// +// cheaprand64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/zhangyunhao116/fastrand +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cheaprand64 +//go:nosplit +func cheaprand64() int64 { + return int64(cheaprand())<<31 ^ int64(cheaprand()) +} + +// cheaprandn is like cheaprand() % n but faster. +// +// cheaprandn must not be exported to other packages: +// the rule is that other packages using runtime-provided +// randomness must always use randn. +// +// cheaprandn should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cheaprandn +//go:nosplit +func cheaprandn(n uint32) uint32 { + // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ + return uint32((uint64(cheaprand()) * uint64(n)) >> 32) +} + +// Too much legacy code has go:linkname references +// to runtime.fastrand and friends, so keep these around for now. +// Code should migrate to math/rand/v2.Uint64, +// which is just as fast, but that's only available in Go 1.22+. +// It would be reasonable to remove these in Go 1.24. +// Do not call these from package runtime. + +//go:linkname legacy_fastrand runtime.fastrand +func legacy_fastrand() uint32 { + return uint32(rand()) +} + +//go:linkname legacy_fastrandn runtime.fastrandn +func legacy_fastrandn(n uint32) uint32 { + return randn(n) +} + +//go:linkname legacy_fastrand64 runtime.fastrand64 +func legacy_fastrand64() uint64 { + return rand() +} diff --git a/contrib/go/_std_1.22/src/runtime/rdebug.go b/contrib/go/_std_1.23/src/runtime/rdebug.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rdebug.go rename to contrib/go/_std_1.23/src/runtime/rdebug.go diff --git a/contrib/go/_std_1.22/src/runtime/retry.go b/contrib/go/_std_1.23/src/runtime/retry.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/retry.go rename to contrib/go/_std_1.23/src/runtime/retry.go diff --git a/contrib/go/_std_1.23/src/runtime/rt0_aix_ppc64.s b/contrib/go/_std_1.23/src/runtime/rt0_aix_ppc64.s new file mode 100644 index 000000000000..74c57bb1dc91 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/rt0_aix_ppc64.s @@ -0,0 +1,192 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" +#include "asm_ppc64x.h" + +// _rt0_ppc64_aix is a function descriptor of the entrypoint function +// __start. This name is needed by cmd/link. +DEFINE_PPC64X_FUNCDESC(_rt0_ppc64_aix, __start<>) + +// The starting function must return in the loader to +// initialise some libraries, especially libthread which +// creates the main thread and adds the TLS in R13 +// R19 contains a function descriptor to the loader function +// which needs to be called. +// This code is similar to the __start function in C +TEXT __start<>(SB),NOSPLIT,$-8 + XOR R0, R0 + MOVD $libc___n_pthreads(SB), R4 + MOVD 0(R4), R4 + MOVD $libc___mod_init(SB), R5 + MOVD 0(R5), R5 + MOVD 0(R19), R0 + MOVD R2, 40(R1) + MOVD 8(R19), R2 + MOVD R18, R3 + MOVD R0, CTR + BL (CTR) // Return to AIX loader + + // Launch rt0_go + MOVD 40(R1), R2 + MOVD R14, R3 // argc + MOVD R15, R4 // argv + BL _main(SB) + + +DEFINE_PPC64X_FUNCDESC(main, _main) +TEXT _main(SB),NOSPLIT,$-8 + MOVD $runtime·rt0_go(SB), R12 + MOVD R12, CTR + BR (CTR) + +// Paramater save space required to cross-call into _cgo_sys_thread_create +#define PARAM_SPACE 16 + +TEXT _rt0_ppc64_aix_lib(SB),NOSPLIT,$-8 + // Start with standard C stack frame layout and linkage. + MOVD LR, R0 + MOVD R0, 16(R1) // Save LR in caller's frame. + MOVW CR, R0 // Save CR in caller's frame + MOVD R0, 8(R1) + + MOVDU R1, -344-PARAM_SPACE(R1) // Allocate frame. + + // Preserve callee-save registers. + MOVD R14, 48+PARAM_SPACE(R1) + MOVD R15, 56+PARAM_SPACE(R1) + MOVD R16, 64+PARAM_SPACE(R1) + MOVD R17, 72+PARAM_SPACE(R1) + MOVD R18, 80+PARAM_SPACE(R1) + MOVD R19, 88+PARAM_SPACE(R1) + MOVD R20, 96+PARAM_SPACE(R1) + MOVD R21,104+PARAM_SPACE(R1) + MOVD R22, 112+PARAM_SPACE(R1) + MOVD R23, 120+PARAM_SPACE(R1) + MOVD R24, 128+PARAM_SPACE(R1) + MOVD R25, 136+PARAM_SPACE(R1) + MOVD R26, 144+PARAM_SPACE(R1) + MOVD R27, 152+PARAM_SPACE(R1) + MOVD R28, 160+PARAM_SPACE(R1) + MOVD R29, 168+PARAM_SPACE(R1) + MOVD g, 176+PARAM_SPACE(R1) // R30 + MOVD R31, 184+PARAM_SPACE(R1) + FMOVD F14, 192+PARAM_SPACE(R1) + FMOVD F15, 200+PARAM_SPACE(R1) + FMOVD F16, 208+PARAM_SPACE(R1) + FMOVD F17, 216+PARAM_SPACE(R1) + FMOVD F18, 224+PARAM_SPACE(R1) + FMOVD F19, 232+PARAM_SPACE(R1) + FMOVD F20, 240+PARAM_SPACE(R1) + FMOVD F21, 248+PARAM_SPACE(R1) + FMOVD F22, 256+PARAM_SPACE(R1) + FMOVD F23, 264+PARAM_SPACE(R1) + FMOVD F24, 272+PARAM_SPACE(R1) + FMOVD F25, 280+PARAM_SPACE(R1) + FMOVD F26, 288+PARAM_SPACE(R1) + FMOVD F27, 296+PARAM_SPACE(R1) + FMOVD F28, 304+PARAM_SPACE(R1) + FMOVD F29, 312+PARAM_SPACE(R1) + FMOVD F30, 320+PARAM_SPACE(R1) + FMOVD F31, 328+PARAM_SPACE(R1) + + // Synchronous initialization. + MOVD $runtime·reginit(SB), R12 + MOVD R12, CTR + BL (CTR) + + MOVBZ runtime·isarchive(SB), R3 // Check buildmode = c-archive + CMP $0, R3 + BEQ done + + MOVD R14, _rt0_ppc64_aix_lib_argc<>(SB) + MOVD R15, _rt0_ppc64_aix_lib_argv<>(SB) + + MOVD $runtime·libpreinit(SB), R12 + MOVD R12, CTR + BL (CTR) + + // Create a new thread to do the runtime initialization and return. + MOVD _cgo_sys_thread_create(SB), R12 + CMP $0, R12 + BEQ nocgo + MOVD $_rt0_ppc64_aix_lib_go(SB), R3 + MOVD $0, R4 + MOVD R2, 40(R1) + MOVD 8(R12), R2 + MOVD (R12), R12 + MOVD R12, CTR + BL (CTR) + MOVD 40(R1), R2 + BR done + +nocgo: + MOVD $0x800000, R12 // stacksize = 8192KB + MOVD R12, 8(R1) + MOVD $_rt0_ppc64_aix_lib_go(SB), R12 + MOVD R12, 16(R1) + MOVD $runtime·newosproc0(SB),R12 + MOVD R12, CTR + BL (CTR) + +done: + // Restore saved registers. + MOVD 48+PARAM_SPACE(R1), R14 + MOVD 56+PARAM_SPACE(R1), R15 + MOVD 64+PARAM_SPACE(R1), R16 + MOVD 72+PARAM_SPACE(R1), R17 + MOVD 80+PARAM_SPACE(R1), R18 + MOVD 88+PARAM_SPACE(R1), R19 + MOVD 96+PARAM_SPACE(R1), R20 + MOVD 104+PARAM_SPACE(R1), R21 + MOVD 112+PARAM_SPACE(R1), R22 + MOVD 120+PARAM_SPACE(R1), R23 + MOVD 128+PARAM_SPACE(R1), R24 + MOVD 136+PARAM_SPACE(R1), R25 + MOVD 144+PARAM_SPACE(R1), R26 + MOVD 152+PARAM_SPACE(R1), R27 + MOVD 160+PARAM_SPACE(R1), R28 + MOVD 168+PARAM_SPACE(R1), R29 + MOVD 176+PARAM_SPACE(R1), g // R30 + MOVD 184+PARAM_SPACE(R1), R31 + FMOVD 196+PARAM_SPACE(R1), F14 + FMOVD 200+PARAM_SPACE(R1), F15 + FMOVD 208+PARAM_SPACE(R1), F16 + FMOVD 216+PARAM_SPACE(R1), F17 + FMOVD 224+PARAM_SPACE(R1), F18 + FMOVD 232+PARAM_SPACE(R1), F19 + FMOVD 240+PARAM_SPACE(R1), F20 + FMOVD 248+PARAM_SPACE(R1), F21 + FMOVD 256+PARAM_SPACE(R1), F22 + FMOVD 264+PARAM_SPACE(R1), F23 + FMOVD 272+PARAM_SPACE(R1), F24 + FMOVD 280+PARAM_SPACE(R1), F25 + FMOVD 288+PARAM_SPACE(R1), F26 + FMOVD 296+PARAM_SPACE(R1), F27 + FMOVD 304+PARAM_SPACE(R1), F28 + FMOVD 312+PARAM_SPACE(R1), F29 + FMOVD 320+PARAM_SPACE(R1), F30 + FMOVD 328+PARAM_SPACE(R1), F31 + + ADD $344+PARAM_SPACE, R1 + + MOVD 8(R1), R0 + MOVFL R0, $0xff + MOVD 16(R1), R0 + MOVD R0, LR + RET + +DEFINE_PPC64X_FUNCDESC(_rt0_ppc64_aix_lib_go, __rt0_ppc64_aix_lib_go) + +TEXT __rt0_ppc64_aix_lib_go(SB),NOSPLIT,$0 + MOVD _rt0_ppc64_aix_lib_argc<>(SB), R3 + MOVD _rt0_ppc64_aix_lib_argv<>(SB), R4 + MOVD $runtime·rt0_go(SB), R12 + MOVD R12, CTR + BR (CTR) + +DATA _rt0_ppc64_aix_lib_argc<>(SB)/8, $0 +GLOBL _rt0_ppc64_aix_lib_argc<>(SB),NOPTR, $8 +DATA _rt0_ppc64_aix_lib_argv<>(SB)/8, $0 +GLOBL _rt0_ppc64_aix_lib_argv<>(SB),NOPTR, $8 diff --git a/contrib/go/_std_1.22/src/runtime/rt0_android_386.s b/contrib/go/_std_1.23/src/runtime/rt0_android_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_android_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_android_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_android_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_android_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_android_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_android_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_android_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_android_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_android_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_android_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_android_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_android_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_android_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_android_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_darwin_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_darwin_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_darwin_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_darwin_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_darwin_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_darwin_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_darwin_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_darwin_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_dragonfly_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_dragonfly_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_dragonfly_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_dragonfly_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_386.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_riscv64.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_riscv64.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_illumos_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_illumos_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_illumos_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_illumos_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_ios_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_ios_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_ios_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_ios_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_ios_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_ios_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_ios_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_ios_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_js_wasm.s b/contrib/go/_std_1.23/src/runtime/rt0_js_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_js_wasm.s rename to contrib/go/_std_1.23/src/runtime/rt0_js_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_386.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_loong64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_loong64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_mips64x.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_mips64x.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_mipsx.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_mipsx.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64le.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64le.s similarity index 99% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64le.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64le.s index 417ada21bf0c..4b7d8e1b940a 100644 --- a/contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64le.s +++ b/contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64le.s @@ -78,7 +78,7 @@ TEXT _main<>(SB),NOSPLIT,$-8 // passes argc/argv similar to the linux kernel, R13 (TLS) is // initialized, and R3/R4 are undefined. MOVD (R1), R12 - CMP R0, R12 + CMP R12, $0 BEQ tls_and_argcv_in_reg // Arguments are passed via the stack (musl loader or a static binary) @@ -86,7 +86,7 @@ TEXT _main<>(SB),NOSPLIT,$-8 ADD $8, R1, R4 // argv // Did the TLS pointer get set? If so, don't change it (e.g musl). - CMP R0, R13 + CMP R13, $0 BNE tls_and_argcv_in_reg MOVD $runtime·m0+m_tls(SB), R13 // TLS diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_riscv64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_riscv64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_s390x.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_s390x.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_netbsd_386.s b/contrib/go/_std_1.23/src/runtime/rt0_netbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_netbsd_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_netbsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_netbsd_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_netbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_netbsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_netbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_netbsd_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_netbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_netbsd_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_netbsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_netbsd_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_netbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_netbsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_netbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_386.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_mips64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_mips64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_mips64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_mips64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_ppc64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_ppc64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_ppc64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_riscv64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_riscv64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_plan9_386.s b/contrib/go/_std_1.23/src/runtime/rt0_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_plan9_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_plan9_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_plan9_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_plan9_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_plan9_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_plan9_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_plan9_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_plan9_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_solaris_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_solaris_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_solaris_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_solaris_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_wasip1_wasm.s b/contrib/go/_std_1.23/src/runtime/rt0_wasip1_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_wasip1_wasm.s rename to contrib/go/_std_1.23/src/runtime/rt0_wasip1_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_windows_386.s b/contrib/go/_std_1.23/src/runtime/rt0_windows_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_windows_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_windows_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_windows_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_windows_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_windows_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_windows_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_windows_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_windows_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_windows_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_windows_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_windows_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_windows_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_windows_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_windows_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/runtime-gdb.py b/contrib/go/_std_1.23/src/runtime/runtime-gdb.py similarity index 100% rename from contrib/go/_std_1.22/src/runtime/runtime-gdb.py rename to contrib/go/_std_1.23/src/runtime/runtime-gdb.py diff --git a/contrib/go/_std_1.23/src/runtime/runtime.go b/contrib/go/_std_1.23/src/runtime/runtime.go new file mode 100644 index 000000000000..e8e614815d23 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/runtime.go @@ -0,0 +1,325 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/abi" + "internal/runtime/atomic" + "unsafe" +) + +//go:generate go run wincallback.go +//go:generate go run mkduff.go +//go:generate go run mkfastlog2table.go +//go:generate go run mklockrank.go -o lockrank.go + +var ticks ticksType + +type ticksType struct { + // lock protects access to start* and val. + lock mutex + startTicks int64 + startTime int64 + val atomic.Int64 +} + +// init initializes ticks to maximize the chance that we have a good ticksPerSecond reference. +// +// Must not run concurrently with ticksPerSecond. +func (t *ticksType) init() { + lock(&ticks.lock) + t.startTime = nanotime() + t.startTicks = cputicks() + unlock(&ticks.lock) +} + +// minTimeForTicksPerSecond is the minimum elapsed time we require to consider our ticksPerSecond +// measurement to be of decent enough quality for profiling. +// +// There's a linear relationship here between minimum time and error from the true value. +// The error from the true ticks-per-second in a linux/amd64 VM seems to be: +// - 1 ms -> ~0.02% error +// - 5 ms -> ~0.004% error +// - 10 ms -> ~0.002% error +// - 50 ms -> ~0.0003% error +// - 100 ms -> ~0.0001% error +// +// We're willing to take 0.004% error here, because ticksPerSecond is intended to be used for +// converting durations, not timestamps. Durations are usually going to be much larger, and so +// the tiny error doesn't matter. The error is definitely going to be a problem when trying to +// use this for timestamps, as it'll make those timestamps much less likely to line up. +const minTimeForTicksPerSecond = 5_000_000*(1-osHasLowResClockInt) + 100_000_000*osHasLowResClockInt + +// ticksPerSecond returns a conversion rate between the cputicks clock and the nanotime clock. +// +// Note: Clocks are hard. Using this as an actual conversion rate for timestamps is ill-advised +// and should be avoided when possible. Use only for durations, where a tiny error term isn't going +// to make a meaningful difference in even a 1ms duration. If an accurate timestamp is needed, +// use nanotime instead. (The entire Windows platform is a broad exception to this rule, where nanotime +// produces timestamps on such a coarse granularity that the error from this conversion is actually +// preferable.) +// +// The strategy for computing the conversion rate is to write down nanotime and cputicks as +// early in process startup as possible. From then, we just need to wait until we get values +// from nanotime that we can use (some platforms have a really coarse system time granularity). +// We require some amount of time to pass to ensure that the conversion rate is fairly accurate +// in aggregate. But because we compute this rate lazily, there's a pretty good chance a decent +// amount of time has passed by the time we get here. +// +// Must be called from a normal goroutine context (running regular goroutine with a P). +// +// Called by runtime/pprof in addition to runtime code. +// +// TODO(mknyszek): This doesn't account for things like CPU frequency scaling. Consider +// a more sophisticated and general approach in the future. +func ticksPerSecond() int64 { + // Get the conversion rate if we've already computed it. + r := ticks.val.Load() + if r != 0 { + return r + } + + // Compute the conversion rate. + for { + lock(&ticks.lock) + r = ticks.val.Load() + if r != 0 { + unlock(&ticks.lock) + return r + } + + // Grab the current time in both clocks. + nowTime := nanotime() + nowTicks := cputicks() + + // See if we can use these times. + if nowTicks > ticks.startTicks && nowTime-ticks.startTime > minTimeForTicksPerSecond { + // Perform the calculation with floats. We don't want to risk overflow. + r = int64(float64(nowTicks-ticks.startTicks) * 1e9 / float64(nowTime-ticks.startTime)) + if r == 0 { + // Zero is both a sentinel value and it would be bad if callers used this as + // a divisor. We tried out best, so just make it 1. + r++ + } + ticks.val.Store(r) + unlock(&ticks.lock) + break + } + unlock(&ticks.lock) + + // Sleep in one millisecond increments until we have a reliable time. + timeSleep(1_000_000) + } + return r +} + +var envs []string +var argslice []string + +//go:linkname syscall_runtime_envs syscall.runtime_envs +func syscall_runtime_envs() []string { return append([]string{}, envs...) } + +//go:linkname syscall_Getpagesize syscall.Getpagesize +func syscall_Getpagesize() int { return int(physPageSize) } + +//go:linkname os_runtime_args os.runtime_args +func os_runtime_args() []string { return append([]string{}, argslice...) } + +//go:linkname syscall_Exit syscall.Exit +//go:nosplit +func syscall_Exit(code int) { + exit(int32(code)) +} + +var godebugDefault string +var godebugUpdate atomic.Pointer[func(string, string)] +var godebugEnv atomic.Pointer[string] // set by parsedebugvars +var godebugNewIncNonDefault atomic.Pointer[func(string) func()] + +//go:linkname godebug_setUpdate internal/godebug.setUpdate +func godebug_setUpdate(update func(string, string)) { + p := new(func(string, string)) + *p = update + godebugUpdate.Store(p) + godebugNotify(false) +} + +//go:linkname godebug_setNewIncNonDefault internal/godebug.setNewIncNonDefault +func godebug_setNewIncNonDefault(newIncNonDefault func(string) func()) { + p := new(func(string) func()) + *p = newIncNonDefault + godebugNewIncNonDefault.Store(p) +} + +// A godebugInc provides access to internal/godebug's IncNonDefault function +// for a given GODEBUG setting. +// Calls before internal/godebug registers itself are dropped on the floor. +type godebugInc struct { + name string + inc atomic.Pointer[func()] +} + +func (g *godebugInc) IncNonDefault() { + inc := g.inc.Load() + if inc == nil { + newInc := godebugNewIncNonDefault.Load() + if newInc == nil { + return + } + inc = new(func()) + *inc = (*newInc)(g.name) + if raceenabled { + racereleasemerge(unsafe.Pointer(&g.inc)) + } + if !g.inc.CompareAndSwap(nil, inc) { + inc = g.inc.Load() + } + } + if raceenabled { + raceacquire(unsafe.Pointer(&g.inc)) + } + (*inc)() +} + +func godebugNotify(envChanged bool) { + update := godebugUpdate.Load() + var env string + if p := godebugEnv.Load(); p != nil { + env = *p + } + if envChanged { + reparsedebugvars(env) + } + if update != nil { + (*update)(godebugDefault, env) + } +} + +//go:linkname syscall_runtimeSetenv syscall.runtimeSetenv +func syscall_runtimeSetenv(key, value string) { + setenv_c(key, value) + if key == "GODEBUG" { + p := new(string) + *p = value + godebugEnv.Store(p) + godebugNotify(true) + } +} + +//go:linkname syscall_runtimeUnsetenv syscall.runtimeUnsetenv +func syscall_runtimeUnsetenv(key string) { + unsetenv_c(key) + if key == "GODEBUG" { + godebugEnv.Store(nil) + godebugNotify(true) + } +} + +// writeErrStr writes a string to descriptor 2. +// If SetCrashOutput(f) was called, it also writes to f. +// +//go:nosplit +func writeErrStr(s string) { + writeErrData(unsafe.StringData(s), int32(len(s))) +} + +// writeErrData is the common parts of writeErr{,Str}. +// +//go:nosplit +func writeErrData(data *byte, n int32) { + write(2, unsafe.Pointer(data), n) + + // If crashing, print a copy to the SetCrashOutput fd. + gp := getg() + if gp != nil && gp.m.dying > 0 || + gp == nil && panicking.Load() > 0 { + if fd := crashFD.Load(); fd != ^uintptr(0) { + write(fd, unsafe.Pointer(data), n) + } + } +} + +// crashFD is an optional file descriptor to use for fatal panics, as +// set by debug.SetCrashOutput (see #42888). If it is a valid fd (not +// all ones), writeErr and related functions write to it in addition +// to standard error. +// +// Initialized to -1 in schedinit. +var crashFD atomic.Uintptr + +//go:linkname setCrashFD +func setCrashFD(fd uintptr) uintptr { + // Don't change the crash FD if a crash is already in progress. + // + // Unlike the case below, this is not required for correctness, but it + // is generally nicer to have all of the crash output go to the same + // place rather than getting split across two different FDs. + if panicking.Load() > 0 { + return ^uintptr(0) + } + + old := crashFD.Swap(fd) + + // If we are panicking, don't return the old FD to runtime/debug for + // closing. writeErrData may have already read the old FD from crashFD + // before the swap and closing it would cause the write to be lost [1]. + // The old FD will never be closed, but we are about to crash anyway. + // + // On the writeErrData thread, panicking.Add(1) happens-before + // crashFD.Load() [2]. + // + // On this thread, swapping old FD for new in crashFD happens-before + // panicking.Load() > 0. + // + // Therefore, if panicking.Load() == 0 here (old FD will be closed), it + // is impossible for the writeErrData thread to observe + // crashFD.Load() == old FD. + // + // [1] Or, if really unlucky, another concurrent open could reuse the + // FD, sending the write into an unrelated file. + // + // [2] If gp != nil, it occurs when incrementing gp.m.dying in + // startpanic_m. If gp == nil, we read panicking.Load() > 0, so an Add + // must have happened-before. + if panicking.Load() > 0 { + return ^uintptr(0) + } + return old +} + +// auxv is populated on relevant platforms but defined here for all platforms +// so x/sys/cpu can assume the getAuxv symbol exists without keeping its list +// of auxv-using GOOS build tags in sync. +// +// It contains an even number of elements, (tag, value) pairs. +var auxv []uintptr + +// golang.org/x/sys/cpu uses getAuxv via linkname. +// Do not remove or change the type signature. +// (See go.dev/issue/57336.) +// +// getAuxv should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cilium/ebpf +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname getAuxv +func getAuxv() []uintptr { return auxv } + +// zeroVal is used by reflect via linkname. +// +// zeroVal should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname zeroVal +var zeroVal [abi.ZeroValSize]byte diff --git a/contrib/go/_std_1.22/src/runtime/runtime1.go b/contrib/go/_std_1.23/src/runtime/runtime1.go similarity index 81% rename from contrib/go/_std_1.22/src/runtime/runtime1.go rename to contrib/go/_std_1.23/src/runtime/runtime1.go index afe1bdd298b9..03ef74b8dc4b 100644 --- a/contrib/go/_std_1.22/src/runtime/runtime1.go +++ b/contrib/go/_std_1.23/src/runtime/runtime1.go @@ -7,7 +7,7 @@ package runtime import ( "internal/bytealg" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -307,44 +307,66 @@ type dbgVar struct { // existing int var for that value, which may // already have an initial value. var debug struct { - cgocheck int32 - clobberfree int32 - disablethp int32 - dontfreezetheworld int32 - efence int32 - gccheckmark int32 - gcpacertrace int32 - gcshrinkstackoff int32 - gcstoptheworld int32 - gctrace int32 - invalidptr int32 - madvdontneed int32 // for Linux; issue 28466 - runtimeContentionStacks atomic.Int32 - scavtrace int32 - scheddetail int32 - schedtrace int32 - tracebackancestors int32 - asyncpreemptoff int32 - harddecommit int32 - adaptivestackstart int32 - tracefpunwindoff int32 - traceadvanceperiod int32 + cgocheck int32 + clobberfree int32 + disablethp int32 + dontfreezetheworld int32 + efence int32 + gccheckmark int32 + gcpacertrace int32 + gcshrinkstackoff int32 + gcstoptheworld int32 + gctrace int32 + invalidptr int32 + madvdontneed int32 // for Linux; issue 28466 + runtimeContentionStacks atomic.Int32 + scavtrace int32 + scheddetail int32 + schedtrace int32 + tracebackancestors int32 + asyncpreemptoff int32 + harddecommit int32 + adaptivestackstart int32 + tracefpunwindoff int32 + traceadvanceperiod int32 + traceCheckStackOwnership int32 + profstackdepth int32 // debug.malloc is used as a combined debug check // in the malloc function and should be set // if any of the below debug options is != 0. - malloc bool - allocfreetrace int32 - inittrace int32 - sbrk int32 + malloc bool + inittrace int32 + sbrk int32 + // traceallocfree controls whether execution traces contain + // detailed trace data about memory allocation. This value + // affects debug.malloc only if it is != 0 and the execution + // tracer is enabled, in which case debug.malloc will be + // set to "true" if it isn't already while tracing is enabled. + // It will be set while the world is stopped, so it's safe. + // The value of traceallocfree can be changed any time in response + // to os.Setenv("GODEBUG"). + traceallocfree atomic.Int32 panicnil atomic.Int32 + + // asynctimerchan controls whether timer channels + // behave asynchronously (as in Go 1.22 and earlier) + // instead of their Go 1.23+ synchronous behavior. + // The value can change at any time (in response to os.Setenv("GODEBUG")) + // and affects all extant timer channels immediately. + // Programs wouldn't normally change over an execution, + // but allowing it is convenient for testing and for programs + // that do an os.Setenv in main.init or main.main. + asynctimerchan atomic.Int32 } var dbgvars = []*dbgVar{ - {name: "allocfreetrace", value: &debug.allocfreetrace}, - {name: "clobberfree", value: &debug.clobberfree}, + {name: "adaptivestackstart", value: &debug.adaptivestackstart}, + {name: "asyncpreemptoff", value: &debug.asyncpreemptoff}, + {name: "asynctimerchan", atomic: &debug.asynctimerchan}, {name: "cgocheck", value: &debug.cgocheck}, + {name: "clobberfree", value: &debug.clobberfree}, {name: "disablethp", value: &debug.disablethp}, {name: "dontfreezetheworld", value: &debug.dontfreezetheworld}, {name: "efence", value: &debug.efence}, @@ -353,21 +375,22 @@ var dbgvars = []*dbgVar{ {name: "gcshrinkstackoff", value: &debug.gcshrinkstackoff}, {name: "gcstoptheworld", value: &debug.gcstoptheworld}, {name: "gctrace", value: &debug.gctrace}, + {name: "harddecommit", value: &debug.harddecommit}, + {name: "inittrace", value: &debug.inittrace}, {name: "invalidptr", value: &debug.invalidptr}, {name: "madvdontneed", value: &debug.madvdontneed}, + {name: "panicnil", atomic: &debug.panicnil}, + {name: "profstackdepth", value: &debug.profstackdepth, def: 128}, {name: "runtimecontentionstacks", atomic: &debug.runtimeContentionStacks}, {name: "sbrk", value: &debug.sbrk}, {name: "scavtrace", value: &debug.scavtrace}, {name: "scheddetail", value: &debug.scheddetail}, {name: "schedtrace", value: &debug.schedtrace}, + {name: "traceadvanceperiod", value: &debug.traceadvanceperiod}, + {name: "traceallocfree", atomic: &debug.traceallocfree}, + {name: "tracecheckstackownership", value: &debug.traceCheckStackOwnership}, {name: "tracebackancestors", value: &debug.tracebackancestors}, - {name: "asyncpreemptoff", value: &debug.asyncpreemptoff}, - {name: "inittrace", value: &debug.inittrace}, - {name: "harddecommit", value: &debug.harddecommit}, - {name: "adaptivestackstart", value: &debug.adaptivestackstart}, {name: "tracefpunwindoff", value: &debug.tracefpunwindoff}, - {name: "panicnil", atomic: &debug.panicnil}, - {name: "traceadvanceperiod", value: &debug.traceadvanceperiod}, } func parsedebugvars() { @@ -412,7 +435,8 @@ func parsedebugvars() { // apply environment settings parsegodebug(godebug, nil) - debug.malloc = (debug.allocfreetrace | debug.inittrace | debug.sbrk) != 0 + debug.malloc = (debug.inittrace | debug.sbrk) != 0 + debug.profstackdepth = min(debug.profstackdepth, maxProfStackDepth) setTraceback(gogetenv("GOTRACEBACK")) traceback_env = traceback_cache @@ -592,6 +616,20 @@ func releasem(mp *m) { } } +// reflect_typelinks is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/goccy/json +// - github.com/modern-go/reflect2 +// - github.com/vmware/govmomi +// - github.com/pinpoint-apm/pinpoint-go-agent +// - github.com/timandy/routine +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_typelinks reflect.typelinks func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { modules := activeModules() @@ -606,6 +644,14 @@ func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { // reflect_resolveNameOff resolves a name offset from a base pointer. // +// reflect_resolveNameOff is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/agiledragon/gomonkey/v2 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_resolveNameOff reflect.resolveNameOff func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer { return unsafe.Pointer(resolveNameOff(ptrInModule, nameOff(off)).Bytes) @@ -613,6 +659,17 @@ func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointe // reflect_resolveTypeOff resolves an *rtype offset from a base type. // +// reflect_resolveTypeOff is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/v2pro/plz +// - github.com/timandy/routine +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_resolveTypeOff reflect.resolveTypeOff func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { return unsafe.Pointer(toRType((*_type)(rtype)).typeOff(typeOff(off))) @@ -620,6 +677,15 @@ func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { // reflect_resolveTextOff resolves a function pointer offset from a base type. // +// reflect_resolveTextOff is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// - github.com/agiledragon/gomonkey/v2 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_resolveTextOff reflect.resolveTextOff func reflect_resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { return toRType((*_type)(rtype)).textOff(textOff(off)) diff --git a/contrib/go/_std_1.22/src/runtime/runtime2.go b/contrib/go/_std_1.23/src/runtime/runtime2.go similarity index 88% rename from contrib/go/_std_1.22/src/runtime/runtime2.go rename to contrib/go/_std_1.23/src/runtime/runtime2.go index 63320d4a8a30..ca69719db0e2 100644 --- a/contrib/go/_std_1.22/src/runtime/runtime2.go +++ b/contrib/go/_std_1.23/src/runtime/runtime2.go @@ -8,7 +8,7 @@ import ( "internal/abi" "internal/chacha8rand" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -437,6 +437,7 @@ type g struct { sched gobuf syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc + syscallbp uintptr // if status==Gsyscall, syscallbp = sched.bp to use in fpTraceback stktopsp uintptr // expected sp at top of stack, to check in traceback // param is a generic pointer parameter field used to pass // values in particular contexts where other storage for the @@ -506,14 +507,15 @@ type g struct { cgoCtxt []uintptr // cgo traceback context labels unsafe.Pointer // profiler labels timer *timer // cached timer for time.Sleep + sleepWhen int64 // when to sleep until selectDone atomic.Uint32 // are we participating in a select and did someone win the race? - coroarg *coro // argument during coroutine transfers - // goroutineProfiled indicates the status of this goroutine's stack for the // current in-progress goroutine profile goroutineProfiled goroutineProfileStateHolder + coroarg *coro // argument during coroutine transfers + // Per-G tracer state. trace gTraceState @@ -554,56 +556,58 @@ type m struct { _ uint32 // align next field to 8 bytes // Fields not known to debuggers. - procid uint64 // for debuggers, but offset not hard-coded - gsignal *g // signal-handling g - goSigStack gsignalStack // Go-allocated signal handling stack - sigmask sigset // storage for saved signal mask - tls [tlsSlots]uintptr // thread-local storage (for x86 extern register) - mstartfn func() - curg *g // current running goroutine - caughtsig guintptr // goroutine running during fatal signal - p puintptr // attached p for executing go code (nil if not executing go code) - nextp puintptr - oldp puintptr // the p that was attached before executing a syscall - id int64 - mallocing int32 - throwing throwType - preemptoff string // if != "", keep curg running on this m - locks int32 - dying int32 - profilehz int32 - spinning bool // m is out of work and is actively looking for work - blocked bool // m is blocked on a note - newSigstack bool // minit on C thread called sigaltstack - printlock int8 - incgo bool // m is executing a cgo call - isextra bool // m is an extra m - isExtraInC bool // m is an extra m that is not executing Go code - isExtraInSig bool // m is an extra m in a signal handler - freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait) - needextram bool - traceback uint8 - ncgocall uint64 // number of cgo calls in total - ncgo int32 // number of cgo calls currently in progress - cgoCallersUse atomic.Uint32 // if non-zero, cgoCallers in use temporarily - cgoCallers *cgoCallers // cgo traceback if crashing in cgo call - park note - alllink *m // on allm - schedlink muintptr - lockedg guintptr - createstack [32]uintptr // stack that created this thread, it's used for StackRecord.Stack0, so it must align with it. - lockedExt uint32 // tracking for external LockOSThread - lockedInt uint32 // tracking for internal lockOSThread - nextwaitm muintptr // next m waiting for lock + procid uint64 // for debuggers, but offset not hard-coded + gsignal *g // signal-handling g + goSigStack gsignalStack // Go-allocated signal handling stack + sigmask sigset // storage for saved signal mask + tls [tlsSlots]uintptr // thread-local storage (for x86 extern register) + mstartfn func() + curg *g // current running goroutine + caughtsig guintptr // goroutine running during fatal signal + p puintptr // attached p for executing go code (nil if not executing go code) + nextp puintptr + oldp puintptr // the p that was attached before executing a syscall + id int64 + mallocing int32 + throwing throwType + preemptoff string // if != "", keep curg running on this m + locks int32 + dying int32 + profilehz int32 + spinning bool // m is out of work and is actively looking for work + blocked bool // m is blocked on a note + newSigstack bool // minit on C thread called sigaltstack + printlock int8 + incgo bool // m is executing a cgo call + isextra bool // m is an extra m + isExtraInC bool // m is an extra m that does not have any Go frames + isExtraInSig bool // m is an extra m in a signal handler + freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait) + needextram bool + g0StackAccurate bool // whether the g0 stack has accurate bounds + traceback uint8 + ncgocall uint64 // number of cgo calls in total + ncgo int32 // number of cgo calls currently in progress + cgoCallersUse atomic.Uint32 // if non-zero, cgoCallers in use temporarily + cgoCallers *cgoCallers // cgo traceback if crashing in cgo call + park note + alllink *m // on allm + schedlink muintptr + lockedg guintptr + createstack [32]uintptr // stack that created this thread, it's used for StackRecord.Stack0, so it must align with it. + lockedExt uint32 // tracking for external LockOSThread + lockedInt uint32 // tracking for internal lockOSThread + nextwaitm muintptr // next m waiting for lock mLockProfile mLockProfile // fields relating to runtime.lock contention + profStack []uintptr // used for memory/block/mutex stack traces // wait* are used to carry arguments from gopark into park_m, because // there's no stack to put them on. That is their sole purpose. waitunlockf func(*g, unsafe.Pointer) bool waitlock unsafe.Pointer - waitTraceBlockReason traceBlockReason waitTraceSkip int + waitTraceBlockReason traceBlockReason syscalltick uint32 freelink *m // on sched.freem @@ -611,11 +615,11 @@ type m struct { // these are here because they are too large to be on the stack // of low-level NOSPLIT functions. - libcall libcall - libcallpc uintptr // for cpu profiler - libcallsp uintptr - libcallg guintptr - syscall libcall // stores syscall parameters on windows + libcall libcall + libcallpc uintptr // for cpu profiler + libcallsp uintptr + libcallg guintptr + winsyscall winlibcall // stores syscall parameters on windows vdsoSP uintptr // SP for traceback while in VDSO call (0 if not in call) vdsoPC uintptr // PC for traceback while in VDSO call @@ -708,16 +712,6 @@ type p struct { palloc persistentAlloc // per-P to avoid mutex - // The when field of the first entry on the timer heap. - // This is 0 if the timer heap is empty. - timer0When atomic.Int64 - - // The earliest known nextwhen field of a timer with - // timerModifiedEarlier status. Because the timer may have been - // modified again, there need not be any timer with this value. - // This is 0 if there are no timerModifiedEarlier timers. - timerModifiedEarliest atomic.Int64 - // Per-P GC state gcAssistTime int64 // Nanoseconds in assistAlloc gcFractionalMarkTime int64 // Nanoseconds in fractional mark worker (atomic) @@ -751,23 +745,8 @@ type p struct { // writing any stats. Its value is even when not, odd when it is. statsSeq atomic.Uint32 - // Lock for timers. We normally access the timers while running - // on this P, but the scheduler can also do it from a different P. - timersLock mutex - - // Actions to take at some time. This is used to implement the - // standard library's time package. - // Must hold timersLock to access. - timers []*timer - - // Number of timers in P's heap. - numTimers atomic.Uint32 - - // Number of timerDeleted timers in P's heap. - deletedTimers atomic.Uint32 - - // Race context used while executing timer functions. - timerRaceCtx uintptr + // Timer heap. + timers timers // maxStackScanDelta accumulates the amount of stack space held by // live goroutines (i.e. those eligible for stack scanning). @@ -787,10 +766,8 @@ type p struct { // scheduler ASAP (regardless of what G is running on it). preempt bool - // pageTraceBuf is a buffer for writing out page allocation/free/scavenge traces. - // - // Used only if GOEXPERIMENT=pagetrace. - pageTraceBuf pageTraceBuf + // gcStopTime is the nanotime timestamp that this P last entered _Pgcstop. + gcStopTime int64 // Padding is no longer needed. False sharing is now not a worry because p is large enough // that its size class is an integer multiple of the cache line size (for any of our architectures). @@ -990,17 +967,7 @@ type funcinl struct { startLine int32 } -// layout of Itab known to compilers -// allocated in non-garbage-collected memory -// Needs to be in sync with -// ../cmd/compile/internal/reflectdata/reflect.go:/^func.WritePluginTable. -type itab struct { - inter *interfacetype - _type *_type - hash uint32 // copy of _type.hash. Used for type switches. - _ [4]byte - fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter. -} +type itab = abi.ITab // Lock-free stack node. // Also known to export_test.go. @@ -1129,6 +1096,7 @@ const ( waitReasonTraceProcStatus // "trace proc status" waitReasonPageTraceFlush // "page trace flush" waitReasonCoroutine // "coroutine" + waitReasonGCWeakToStrongWait // "GC weak to strong wait" ) var waitReasonStrings = [...]string{ @@ -1169,6 +1137,7 @@ var waitReasonStrings = [...]string{ waitReasonTraceProcStatus: "trace proc status", waitReasonPageTraceFlush: "page trace flush", waitReasonCoroutine: "coroutine", + waitReasonGCWeakToStrongWait: "GC weak to strong wait", } func (w waitReason) String() string { @@ -1184,6 +1153,29 @@ func (w waitReason) isMutexWait() bool { w == waitReasonSyncRWMutexLock } +func (w waitReason) isWaitingForGC() bool { + return isWaitingForGC[w] +} + +// isWaitingForGC indicates that a goroutine is only entering _Gwaiting and +// setting a waitReason because it needs to be able to let the GC take ownership +// of its stack. The G is always actually executing on the system stack, in +// these cases. +// +// TODO(mknyszek): Consider replacing this with a new dedicated G status. +var isWaitingForGC = [len(waitReasonStrings)]bool{ + waitReasonStoppingTheWorld: true, + waitReasonGCMarkTermination: true, + waitReasonGarbageCollection: true, + waitReasonGarbageCollectionScan: true, + waitReasonTraceGoroutineStatus: true, + waitReasonTraceProcStatus: true, + waitReasonPageTraceFlush: true, + waitReasonGCAssistMarking: true, + waitReasonGCWorkerActive: true, + waitReasonFlushProcCaches: true, +} + var ( allm *m gomaxprocs int32 @@ -1191,13 +1183,17 @@ var ( forcegc forcegcstate sched schedt newprocs int32 +) +var ( // allpLock protects P-less reads and size changes of allp, idlepMask, // and timerpMask, and all writes to allp. allpLock mutex + // len(allp) == gomaxprocs; may change at safe points, otherwise // immutable. allp []*p + // Bitmask of Ps in _Pidle list, one bit per P. Reads and writes must // be atomic. Length may change at safe points. // @@ -1209,10 +1205,41 @@ var ( // // N.B., procresize takes ownership of all Ps in stopTheWorldWithSema. idlepMask pMask + // Bitmask of Ps that may have a timer, one bit per P. Reads and writes // must be atomic. Length may change at safe points. + // + // Ideally, the timer mask would be kept immediately consistent on any timer + // operations. Unfortunately, updating a shared global data structure in the + // timer hot path adds too much overhead in applications frequently switching + // between no timers and some timers. + // + // As a compromise, the timer mask is updated only on pidleget / pidleput. A + // running P (returned by pidleget) may add a timer at any time, so its mask + // must be set. An idle P (passed to pidleput) cannot add new timers while + // idle, so if it has no timers at that time, its mask may be cleared. + // + // Thus, we get the following effects on timer-stealing in findrunnable: + // + // - Idle Ps with no timers when they go idle are never checked in findrunnable + // (for work- or timer-stealing; this is the ideal case). + // - Running Ps must always be checked. + // - Idle Ps whose timers are stolen must continue to be checked until they run + // again, even after timer expiration. + // + // When the P starts running again, the mask should be set, as a timer may be + // added at any time. + // + // TODO(prattmic): Additional targeted updates may improve the above cases. + // e.g., updating the mask when stealing a timer. timerpMask pMask +) + +// goarmsoftfp is used by runtime/cgo assembly. +// +//go:linkname goarmsoftfp +var ( // Pool of GC parked background workers. Entries are type // *gcBgMarkWorkerNode. gcBgMarkWorkerPool lfstack @@ -1226,8 +1253,21 @@ var ( // Set on startup in asm_{386,amd64}.s processorVersionInfo uint32 isIntel bool +) - // set by cmd/link on arm systems +// set by cmd/link on arm systems +// accessed using linkname by internal/runtime/atomic. +// +// goarm should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/creativeprojects/go-selfupdate +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname goarm +var ( goarm uint8 goarmsoftfp uint8 ) @@ -1240,3 +1280,17 @@ var ( // Must agree with internal/buildcfg.FramePointerEnabled. const framepointer_enabled = GOARCH == "amd64" || GOARCH == "arm64" + +// getcallerfp returns the frame pointer of the caller of the caller +// of this function. +// +//go:nosplit +//go:noinline +func getcallerfp() uintptr { + fp := getfp() // This frame's FP. + if fp != 0 { + fp = *(*uintptr)(unsafe.Pointer(fp)) // The caller's FP. + fp = *(*uintptr)(unsafe.Pointer(fp)) // The caller's caller's FP. + } + return fp +} diff --git a/contrib/go/_std_1.22/src/runtime/runtime_boring.go b/contrib/go/_std_1.23/src/runtime/runtime_boring.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/runtime_boring.go rename to contrib/go/_std_1.23/src/runtime/runtime_boring.go diff --git a/contrib/go/_std_1.23/src/runtime/rwmutex.go b/contrib/go/_std_1.23/src/runtime/rwmutex.go new file mode 100644 index 000000000000..4f9585f98d6b --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/rwmutex.go @@ -0,0 +1,164 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/runtime/atomic" +) + +// This is a copy of sync/rwmutex.go rewritten to work in the runtime. + +// A rwmutex is a reader/writer mutual exclusion lock. +// The lock can be held by an arbitrary number of readers or a single writer. +// This is a variant of sync.RWMutex, for the runtime package. +// Like mutex, rwmutex blocks the calling M. +// It does not interact with the goroutine scheduler. +type rwmutex struct { + rLock mutex // protects readers, readerPass, writer + readers muintptr // list of pending readers + readerPass uint32 // number of pending readers to skip readers list + + wLock mutex // serializes writers + writer muintptr // pending writer waiting for completing readers + + readerCount atomic.Int32 // number of pending readers + readerWait atomic.Int32 // number of departing readers + + readRank lockRank // semantic lock rank for read locking +} + +// Lock ranking an rwmutex has two aspects: +// +// Semantic ranking: this rwmutex represents some higher level lock that +// protects some resource (e.g., allocmLock protects creation of new Ms). The +// read and write locks of that resource need to be represented in the lock +// rank. +// +// Internal ranking: as an implementation detail, rwmutex uses two mutexes: +// rLock and wLock. These have lock order requirements: wLock must be locked +// before rLock. This also needs to be represented in the lock rank. +// +// Semantic ranking is represented by acquiring readRank during read lock and +// writeRank during write lock. +// +// wLock is held for the duration of a write lock, so it uses writeRank +// directly, both for semantic and internal ranking. rLock is only held +// temporarily inside the rlock/lock methods, so it uses readRankInternal to +// represent internal ranking. Semantic ranking is represented by a separate +// acquire of readRank for the duration of a read lock. +// +// The lock ranking must document this ordering: +// - readRankInternal is a leaf lock. +// - readRank is taken before readRankInternal. +// - writeRank is taken before readRankInternal. +// - readRank is placed in the lock order wherever a read lock of this rwmutex +// belongs. +// - writeRank is placed in the lock order wherever a write lock of this +// rwmutex belongs. +func (rw *rwmutex) init(readRank, readRankInternal, writeRank lockRank) { + rw.readRank = readRank + + lockInit(&rw.rLock, readRankInternal) + lockInit(&rw.wLock, writeRank) +} + +const rwmutexMaxReaders = 1 << 30 + +// rlock locks rw for reading. +func (rw *rwmutex) rlock() { + // The reader must not be allowed to lose its P or else other + // things blocking on the lock may consume all of the Ps and + // deadlock (issue #20903). Alternatively, we could drop the P + // while sleeping. + acquireLockRankAndM(rw.readRank) + lockWithRankMayAcquire(&rw.rLock, getLockRank(&rw.rLock)) + + if rw.readerCount.Add(1) < 0 { + // A writer is pending. Park on the reader queue. + systemstack(func() { + lock(&rw.rLock) + if rw.readerPass > 0 { + // Writer finished. + rw.readerPass -= 1 + unlock(&rw.rLock) + } else { + // Queue this reader to be woken by + // the writer. + m := getg().m + m.schedlink = rw.readers + rw.readers.set(m) + unlock(&rw.rLock) + notesleep(&m.park) + noteclear(&m.park) + } + }) + } +} + +// runlock undoes a single rlock call on rw. +func (rw *rwmutex) runlock() { + if r := rw.readerCount.Add(-1); r < 0 { + if r+1 == 0 || r+1 == -rwmutexMaxReaders { + throw("runlock of unlocked rwmutex") + } + // A writer is pending. + if rw.readerWait.Add(-1) == 0 { + // The last reader unblocks the writer. + lock(&rw.rLock) + w := rw.writer.ptr() + if w != nil { + notewakeup(&w.park) + } + unlock(&rw.rLock) + } + } + releaseLockRankAndM(rw.readRank) +} + +// lock locks rw for writing. +func (rw *rwmutex) lock() { + // Resolve competition with other writers and stick to our P. + lock(&rw.wLock) + m := getg().m + // Announce that there is a pending writer. + r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders + // Wait for any active readers to complete. + lock(&rw.rLock) + if r != 0 && rw.readerWait.Add(r) != 0 { + // Wait for reader to wake us up. + systemstack(func() { + rw.writer.set(m) + unlock(&rw.rLock) + notesleep(&m.park) + noteclear(&m.park) + }) + } else { + unlock(&rw.rLock) + } +} + +// unlock unlocks rw for writing. +func (rw *rwmutex) unlock() { + // Announce to readers that there is no active writer. + r := rw.readerCount.Add(rwmutexMaxReaders) + if r >= rwmutexMaxReaders { + throw("unlock of unlocked rwmutex") + } + // Unblock blocked readers. + lock(&rw.rLock) + for rw.readers.ptr() != nil { + reader := rw.readers.ptr() + rw.readers = reader.schedlink + reader.schedlink.set(nil) + notewakeup(&reader.park) + r -= 1 + } + // If r > 0, there are pending readers that aren't on the + // queue. Tell them to skip waiting. + rw.readerPass += uint32(r) + unlock(&rw.rLock) + // Allow other writers to proceed. + unlock(&rw.wLock) +} diff --git a/contrib/go/_std_1.22/src/runtime/security_aix.go b/contrib/go/_std_1.23/src/runtime/security_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/security_aix.go rename to contrib/go/_std_1.23/src/runtime/security_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/security_issetugid.go b/contrib/go/_std_1.23/src/runtime/security_issetugid.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/security_issetugid.go rename to contrib/go/_std_1.23/src/runtime/security_issetugid.go diff --git a/contrib/go/_std_1.22/src/runtime/security_linux.go b/contrib/go/_std_1.23/src/runtime/security_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/security_linux.go rename to contrib/go/_std_1.23/src/runtime/security_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/security_nonunix.go b/contrib/go/_std_1.23/src/runtime/security_nonunix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/security_nonunix.go rename to contrib/go/_std_1.23/src/runtime/security_nonunix.go diff --git a/contrib/go/_std_1.22/src/runtime/security_unix.go b/contrib/go/_std_1.23/src/runtime/security_unix.go similarity index 89% rename from contrib/go/_std_1.22/src/runtime/security_unix.go rename to contrib/go/_std_1.23/src/runtime/security_unix.go index fa54090df248..6ef3b5b328c6 100644 --- a/contrib/go/_std_1.22/src/runtime/security_unix.go +++ b/contrib/go/_std_1.23/src/runtime/security_unix.go @@ -6,6 +6,10 @@ package runtime +import ( + "internal/stringslite" +) + func secure() { initSecureMode() @@ -25,7 +29,7 @@ func secure() { func secureEnv() { var hasTraceback bool for i := 0; i < len(envs); i++ { - if hasPrefix(envs[i], "GOTRACEBACK=") { + if stringslite.HasPrefix(envs[i], "GOTRACEBACK=") { hasTraceback = true envs[i] = "GOTRACEBACK=none" } diff --git a/contrib/go/_std_1.22/src/runtime/select.go b/contrib/go/_std_1.23/src/runtime/select.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/select.go rename to contrib/go/_std_1.23/src/runtime/select.go index b3a3085cb03b..17c49d7484a3 100644 --- a/contrib/go/_std_1.22/src/runtime/select.go +++ b/contrib/go/_std_1.23/src/runtime/select.go @@ -173,6 +173,10 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo continue } + if cas.c.timer != nil { + cas.c.timer.maybeRunChan() + } + j := cheaprandn(uint32(norder + 1)) pollorder[norder] = pollorder[j] pollorder[j] = uint16(i) @@ -315,6 +319,10 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo } else { c.recvq.enqueue(sg) } + + if c.timer != nil { + blockTimerChan(c) + } } // wait for someone to wake us up @@ -351,6 +359,9 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo for _, casei := range lockorder { k = &scases[casei] + if k.c.timer != nil { + unblockTimerChan(k.c) + } if sg == sglist { // sg has already been dequeued by the G that woke us up. casi = int(casei) diff --git a/contrib/go/_std_1.22/src/runtime/sema.go b/contrib/go/_std_1.23/src/runtime/sema.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/sema.go rename to contrib/go/_std_1.23/src/runtime/sema.go index c87fc7658e9a..f6b1b84f5f12 100644 --- a/contrib/go/_std_1.22/src/runtime/sema.go +++ b/contrib/go/_std_1.23/src/runtime/sema.go @@ -21,7 +21,7 @@ package runtime import ( "internal/cpu" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -57,6 +57,15 @@ func (t *semTable) rootFor(addr *uint32) *semaRoot { return &t[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root } +// sync_runtime_Semacquire should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname sync_runtime_Semacquire sync.runtime_Semacquire func sync_runtime_Semacquire(addr *uint32) { semacquire1(addr, false, semaBlockProfile, 0, waitReasonSemacquire) @@ -67,6 +76,15 @@ func poll_runtime_Semacquire(addr *uint32) { semacquire1(addr, false, semaBlockProfile, 0, waitReasonSemacquire) } +// sync_runtime_Semrelease should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname sync_runtime_Semrelease sync.runtime_Semrelease func sync_runtime_Semrelease(addr *uint32, handoff bool, skipframes int) { semrelease1(addr, handoff, skipframes) diff --git a/contrib/go/_std_1.22/src/runtime/sigaction.go b/contrib/go/_std_1.23/src/runtime/sigaction.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigaction.go rename to contrib/go/_std_1.23/src/runtime/sigaction.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_386.go b/contrib/go/_std_1.23/src/runtime/signal_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_386.go rename to contrib/go/_std_1.23/src/runtime/signal_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_aix_ppc64.go b/contrib/go/_std_1.23/src/runtime/signal_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_aix_ppc64.go rename to contrib/go/_std_1.23/src/runtime/signal_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_arm.go b/contrib/go/_std_1.23/src/runtime/signal_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_darwin.go b/contrib/go/_std_1.23/src/runtime/signal_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_darwin.go rename to contrib/go/_std_1.23/src/runtime/signal_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_darwin_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_darwin_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_dragonfly.go b/contrib/go/_std_1.23/src/runtime/signal_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_dragonfly.go rename to contrib/go/_std_1.23/src/runtime/signal_dragonfly.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_dragonfly_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_386.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_386.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_arm.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_386.go b/contrib/go/_std_1.23/src/runtime/signal_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_386.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_arm.go b/contrib/go/_std_1.23/src/runtime/signal_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_loong64.go b/contrib/go/_std_1.23/src/runtime/signal_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_loong64.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_mips64x.go b/contrib/go/_std_1.23/src/runtime/signal_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_mips64x.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_mipsx.go b/contrib/go/_std_1.23/src/runtime/signal_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_mipsx.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_ppc64x.go b/contrib/go/_std_1.23/src/runtime/signal_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_riscv64.go b/contrib/go/_std_1.23/src/runtime/signal_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_riscv64.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_s390x.go b/contrib/go/_std_1.23/src/runtime/signal_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_s390x.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_loong64.go b/contrib/go/_std_1.23/src/runtime/signal_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_loong64.go rename to contrib/go/_std_1.23/src/runtime/signal_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_mips64x.go b/contrib/go/_std_1.23/src/runtime/signal_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_mips64x.go rename to contrib/go/_std_1.23/src/runtime/signal_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_mipsx.go b/contrib/go/_std_1.23/src/runtime/signal_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_mipsx.go rename to contrib/go/_std_1.23/src/runtime/signal_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd_386.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd_386.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd_arm.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_386.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_386.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_arm.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_mips64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_mips64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_ppc64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_plan9.go b/contrib/go/_std_1.23/src/runtime/signal_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_plan9.go rename to contrib/go/_std_1.23/src/runtime/signal_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_ppc64x.go b/contrib/go/_std_1.23/src/runtime/signal_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/signal_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_riscv64.go b/contrib/go/_std_1.23/src/runtime/signal_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_riscv64.go rename to contrib/go/_std_1.23/src/runtime/signal_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_solaris.go b/contrib/go/_std_1.23/src/runtime/signal_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_solaris.go rename to contrib/go/_std_1.23/src/runtime/signal_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_solaris_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_solaris_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_unix.go b/contrib/go/_std_1.23/src/runtime/signal_unix.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/signal_unix.go rename to contrib/go/_std_1.23/src/runtime/signal_unix.go index 84391d58ed7f..6f40f440e807 100644 --- a/contrib/go/_std_1.22/src/runtime/signal_unix.go +++ b/contrib/go/_std_1.23/src/runtime/signal_unix.go @@ -8,7 +8,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -605,6 +605,19 @@ var crashing atomic.Int32 var testSigtrap func(info *siginfo, ctxt *sigctxt, gp *g) bool var testSigusr1 func(gp *g) bool +// sigsysIgnored is non-zero if we are currently ignoring SIGSYS. See issue #69065. +var sigsysIgnored uint32 + +//go:linkname ignoreSIGSYS os.ignoreSIGSYS +func ignoreSIGSYS() { + atomic.Store(&sigsysIgnored, 1) +} + +//go:linkname restoreSIGSYS os.restoreSIGSYS +func restoreSIGSYS() { + atomic.Store(&sigsysIgnored, 0) +} + // sighandler is invoked when a signal occurs. The global g will be // set to a gsignal goroutine and we will be running on the alternate // signal stack. The parameter gp will be the value of the global g @@ -715,6 +728,10 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { return } + if sig == _SIGSYS && c.sigFromSeccomp() && atomic.Load(&sigsysIgnored) != 0 { + return + } + if flags&_SigKill != 0 { dieFromSignal(sig) } @@ -752,6 +769,9 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { } if docrash { + var crashSleepMicros uint32 = 5000 + var watchdogTimeoutMicros uint32 = 2000 * crashSleepMicros + isCrashThread := false if crashing.CompareAndSwap(0, 1) { isCrashThread = true @@ -769,19 +789,35 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { // The faulting m is crashing first so it is the faulting thread in the core dump (see issue #63277): // in expected operation, the first m will wait until the last m has received the SIGQUIT, // and then run crash/exit and the process is gone. - // However, if it spends more than 5 seconds to send SIGQUIT to all ms, - // any of ms may crash/exit the process after waiting for 5 seconds. + // However, if it spends more than 10 seconds to send SIGQUIT to all ms, + // any of ms may crash/exit the process after waiting for 10 seconds. print("\n-----\n\n") raiseproc(_SIGQUIT) } if isCrashThread { - i := 0 - for (crashing.Load() < mcount()-int32(extraMLength.Load())) && i < 10 { - i++ - usleep(500 * 1000) + // Sleep for short intervals so that we can crash quickly after all ms have received SIGQUIT. + // Reset the timer whenever we see more ms received SIGQUIT + // to make it have enough time to crash (see issue #64752). + timeout := watchdogTimeoutMicros + maxCrashing := crashing.Load() + for timeout > 0 && (crashing.Load() < mcount()-int32(extraMLength.Load())) { + usleep(crashSleepMicros) + timeout -= crashSleepMicros + + if c := crashing.Load(); c > maxCrashing { + // We make progress, so reset the watchdog timeout + maxCrashing = c + timeout = watchdogTimeoutMicros + } } } else { - usleep(5 * 1000 * 1000) + maxCrashing := int32(0) + c := crashing.Load() + for c > maxCrashing { + maxCrashing = c + usleep(watchdogTimeoutMicros) + c = crashing.Load() + } } printDebugLog() crash() @@ -953,10 +989,17 @@ func raisebadsignal(sig uint32, c *sigctxt) { } var handler uintptr + var flags int32 if sig >= _NSIG { handler = _SIG_DFL } else { handler = atomic.Loaduintptr(&fwdSig[sig]) + flags = sigtable[sig].flags + } + + // If the signal is ignored, raising the signal is no-op. + if handler == _SIG_IGN || (handler == _SIG_DFL && flags&_SigIgn != 0) { + return } // Reset the signal handler and raise the signal. diff --git a/contrib/go/_std_1.22/src/runtime/signal_windows.go b/contrib/go/_std_1.23/src/runtime/signal_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_windows.go rename to contrib/go/_std_1.23/src/runtime/signal_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/sigqueue.go b/contrib/go/_std_1.23/src/runtime/sigqueue.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sigqueue.go rename to contrib/go/_std_1.23/src/runtime/sigqueue.go index 51e424d55b64..62a8e8a70226 100644 --- a/contrib/go/_std_1.22/src/runtime/sigqueue.go +++ b/contrib/go/_std_1.23/src/runtime/sigqueue.go @@ -33,7 +33,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" _ "unsafe" // for go:linkname ) diff --git a/contrib/go/_std_1.22/src/runtime/sigqueue_note.go b/contrib/go/_std_1.23/src/runtime/sigqueue_note.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigqueue_note.go rename to contrib/go/_std_1.23/src/runtime/sigqueue_note.go diff --git a/contrib/go/_std_1.22/src/runtime/sigqueue_plan9.go b/contrib/go/_std_1.23/src/runtime/sigqueue_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigqueue_plan9.go rename to contrib/go/_std_1.23/src/runtime/sigqueue_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/sigtab_aix.go b/contrib/go/_std_1.23/src/runtime/sigtab_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigtab_aix.go rename to contrib/go/_std_1.23/src/runtime/sigtab_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/sigtab_linux_generic.go b/contrib/go/_std_1.23/src/runtime/sigtab_linux_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigtab_linux_generic.go rename to contrib/go/_std_1.23/src/runtime/sigtab_linux_generic.go diff --git a/contrib/go/_std_1.22/src/runtime/sigtab_linux_mipsx.go b/contrib/go/_std_1.23/src/runtime/sigtab_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigtab_linux_mipsx.go rename to contrib/go/_std_1.23/src/runtime/sigtab_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/sizeclasses.go b/contrib/go/_std_1.23/src/runtime/sizeclasses.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sizeclasses.go rename to contrib/go/_std_1.23/src/runtime/sizeclasses.go index 931462345311..bbcaa9e983fd 100644 --- a/contrib/go/_std_1.22/src/runtime/sizeclasses.go +++ b/contrib/go/_std_1.23/src/runtime/sizeclasses.go @@ -82,6 +82,7 @@ package runtime // 8192 13 32768 const ( + minHeapAlign = 8 _MaxSmallSize = 32768 smallSizeDiv = 8 smallSizeMax = 1024 diff --git a/contrib/go/_std_1.23/src/runtime/slice.go b/contrib/go/_std_1.23/src/runtime/slice.go new file mode 100644 index 000000000000..78475735af3d --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/slice.go @@ -0,0 +1,401 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/abi" + "internal/goarch" + "runtime/internal/math" + "runtime/internal/sys" + "unsafe" +) + +type slice struct { + array unsafe.Pointer + len int + cap int +} + +// A notInHeapSlice is a slice backed by runtime/internal/sys.NotInHeap memory. +type notInHeapSlice struct { + array *notInHeap + len int + cap int +} + +func panicmakeslicelen() { + panic(errorString("makeslice: len out of range")) +} + +func panicmakeslicecap() { + panic(errorString("makeslice: cap out of range")) +} + +// makeslicecopy allocates a slice of "tolen" elements of type "et", +// then copies "fromlen" elements of type "et" into that new allocation from "from". +func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer { + var tomem, copymem uintptr + if uintptr(tolen) > uintptr(fromlen) { + var overflow bool + tomem, overflow = math.MulUintptr(et.Size_, uintptr(tolen)) + if overflow || tomem > maxAlloc || tolen < 0 { + panicmakeslicelen() + } + copymem = et.Size_ * uintptr(fromlen) + } else { + // fromlen is a known good length providing and equal or greater than tolen, + // thereby making tolen a good slice length too as from and to slices have the + // same element width. + tomem = et.Size_ * uintptr(tolen) + copymem = tomem + } + + var to unsafe.Pointer + if !et.Pointers() { + to = mallocgc(tomem, nil, false) + if copymem < tomem { + memclrNoHeapPointers(add(to, copymem), tomem-copymem) + } + } else { + // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. + to = mallocgc(tomem, et, true) + if copymem > 0 && writeBarrier.enabled { + // Only shade the pointers in old.array since we know the destination slice to + // only contains nil pointers because it has been cleared during alloc. + // + // It's safe to pass a type to this function as an optimization because + // from and to only ever refer to memory representing whole values of + // type et. See the comment on bulkBarrierPreWrite. + bulkBarrierPreWriteSrcOnly(uintptr(to), uintptr(from), copymem, et) + } + } + + if raceenabled { + callerpc := getcallerpc() + pc := abi.FuncPCABIInternal(makeslicecopy) + racereadrangepc(from, copymem, callerpc, pc) + } + if msanenabled { + msanread(from, copymem) + } + if asanenabled { + asanread(from, copymem) + } + + memmove(to, from, copymem) + + return to +} + +// makeslice should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname makeslice +func makeslice(et *_type, len, cap int) unsafe.Pointer { + mem, overflow := math.MulUintptr(et.Size_, uintptr(cap)) + if overflow || mem > maxAlloc || len < 0 || len > cap { + // NOTE: Produce a 'len out of range' error instead of a + // 'cap out of range' error when someone does make([]T, bignumber). + // 'cap out of range' is true too, but since the cap is only being + // supplied implicitly, saying len is clearer. + // See golang.org/issue/4085. + mem, overflow := math.MulUintptr(et.Size_, uintptr(len)) + if overflow || mem > maxAlloc || len < 0 { + panicmakeslicelen() + } + panicmakeslicecap() + } + + return mallocgc(mem, et, true) +} + +func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer { + len := int(len64) + if int64(len) != len64 { + panicmakeslicelen() + } + + cap := int(cap64) + if int64(cap) != cap64 { + panicmakeslicecap() + } + + return makeslice(et, len, cap) +} + +// growslice allocates new backing store for a slice. +// +// arguments: +// +// oldPtr = pointer to the slice's backing array +// newLen = new length (= oldLen + num) +// oldCap = original slice's capacity. +// num = number of elements being added +// et = element type +// +// return values: +// +// newPtr = pointer to the new backing store +// newLen = same value as the argument +// newCap = capacity of the new backing store +// +// Requires that uint(newLen) > uint(oldCap). +// Assumes the original slice length is newLen - num +// +// A new backing store is allocated with space for at least newLen elements. +// Existing entries [0, oldLen) are copied over to the new backing store. +// Added entries [oldLen, newLen) are not initialized by growslice +// (although for pointer-containing element types, they are zeroed). They +// must be initialized by the caller. +// Trailing entries [newLen, newCap) are zeroed. +// +// growslice's odd calling convention makes the generated code that calls +// this function simpler. In particular, it accepts and returns the +// new length so that the old length is not live (does not need to be +// spilled/restored) and the new length is returned (also does not need +// to be spilled/restored). +// +// growslice should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/chenzhuoyu/iasm +// - github.com/cloudwego/dynamicgo +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname growslice +func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice { + oldLen := newLen - num + if raceenabled { + callerpc := getcallerpc() + racereadrangepc(oldPtr, uintptr(oldLen*int(et.Size_)), callerpc, abi.FuncPCABIInternal(growslice)) + } + if msanenabled { + msanread(oldPtr, uintptr(oldLen*int(et.Size_))) + } + if asanenabled { + asanread(oldPtr, uintptr(oldLen*int(et.Size_))) + } + + if newLen < 0 { + panic(errorString("growslice: len out of range")) + } + + if et.Size_ == 0 { + // append should not create a slice with nil pointer but non-zero len. + // We assume that append doesn't need to preserve oldPtr in this case. + return slice{unsafe.Pointer(&zerobase), newLen, newLen} + } + + newcap := nextslicecap(newLen, oldCap) + + var overflow bool + var lenmem, newlenmem, capmem uintptr + // Specialize for common values of et.Size. + // For 1 we don't need any division/multiplication. + // For goarch.PtrSize, compiler will optimize division/multiplication into a shift by a constant. + // For powers of 2, use a variable shift. + noscan := !et.Pointers() + switch { + case et.Size_ == 1: + lenmem = uintptr(oldLen) + newlenmem = uintptr(newLen) + capmem = roundupsize(uintptr(newcap), noscan) + overflow = uintptr(newcap) > maxAlloc + newcap = int(capmem) + case et.Size_ == goarch.PtrSize: + lenmem = uintptr(oldLen) * goarch.PtrSize + newlenmem = uintptr(newLen) * goarch.PtrSize + capmem = roundupsize(uintptr(newcap)*goarch.PtrSize, noscan) + overflow = uintptr(newcap) > maxAlloc/goarch.PtrSize + newcap = int(capmem / goarch.PtrSize) + case isPowerOfTwo(et.Size_): + var shift uintptr + if goarch.PtrSize == 8 { + // Mask shift for better code generation. + shift = uintptr(sys.TrailingZeros64(uint64(et.Size_))) & 63 + } else { + shift = uintptr(sys.TrailingZeros32(uint32(et.Size_))) & 31 + } + lenmem = uintptr(oldLen) << shift + newlenmem = uintptr(newLen) << shift + capmem = roundupsize(uintptr(newcap)< (maxAlloc >> shift) + newcap = int(capmem >> shift) + capmem = uintptr(newcap) << shift + default: + lenmem = uintptr(oldLen) * et.Size_ + newlenmem = uintptr(newLen) * et.Size_ + capmem, overflow = math.MulUintptr(et.Size_, uintptr(newcap)) + capmem = roundupsize(capmem, noscan) + newcap = int(capmem / et.Size_) + capmem = uintptr(newcap) * et.Size_ + } + + // The check of overflow in addition to capmem > maxAlloc is needed + // to prevent an overflow which can be used to trigger a segfault + // on 32bit architectures with this example program: + // + // type T [1<<27 + 1]int64 + // + // var d T + // var s []T + // + // func main() { + // s = append(s, d, d, d, d) + // print(len(s), "\n") + // } + if overflow || capmem > maxAlloc { + panic(errorString("growslice: len out of range")) + } + + var p unsafe.Pointer + if !et.Pointers() { + p = mallocgc(capmem, nil, false) + // The append() that calls growslice is going to overwrite from oldLen to newLen. + // Only clear the part that will not be overwritten. + // The reflect_growslice() that calls growslice will manually clear + // the region not cleared here. + memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem) + } else { + // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. + p = mallocgc(capmem, et, true) + if lenmem > 0 && writeBarrier.enabled { + // Only shade the pointers in oldPtr since we know the destination slice p + // only contains nil pointers because it has been cleared during alloc. + // + // It's safe to pass a type to this function as an optimization because + // from and to only ever refer to memory representing whole values of + // type et. See the comment on bulkBarrierPreWrite. + bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(oldPtr), lenmem-et.Size_+et.PtrBytes, et) + } + } + memmove(p, oldPtr, lenmem) + + return slice{p, newLen, newcap} +} + +// nextslicecap computes the next appropriate slice length. +func nextslicecap(newLen, oldCap int) int { + newcap := oldCap + doublecap := newcap + newcap + if newLen > doublecap { + return newLen + } + + const threshold = 256 + if oldCap < threshold { + return doublecap + } + for { + // Transition from growing 2x for small slices + // to growing 1.25x for large slices. This formula + // gives a smooth-ish transition between the two. + newcap += (newcap + 3*threshold) >> 2 + + // We need to check `newcap >= newLen` and whether `newcap` overflowed. + // newLen is guaranteed to be larger than zero, hence + // when newcap overflows then `uint(newcap) > uint(newLen)`. + // This allows to check for both with the same comparison. + if uint(newcap) >= uint(newLen) { + break + } + } + + // Set newcap to the requested cap when + // the newcap calculation overflowed. + if newcap <= 0 { + return newLen + } + return newcap +} + +// reflect_growslice should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/dynamicgo +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_growslice reflect.growslice +func reflect_growslice(et *_type, old slice, num int) slice { + // Semantically equivalent to slices.Grow, except that the caller + // is responsible for ensuring that old.len+num > old.cap. + num -= old.cap - old.len // preserve memory of old[old.len:old.cap] + new := growslice(old.array, old.cap+num, old.cap, num, et) + // growslice does not zero out new[old.cap:new.len] since it assumes that + // the memory will be overwritten by an append() that called growslice. + // Since the caller of reflect_growslice is not append(), + // zero out this region before returning the slice to the reflect package. + if !et.Pointers() { + oldcapmem := uintptr(old.cap) * et.Size_ + newlenmem := uintptr(new.len) * et.Size_ + memclrNoHeapPointers(add(new.array, oldcapmem), newlenmem-oldcapmem) + } + new.len = old.len // preserve the old length + return new +} + +func isPowerOfTwo(x uintptr) bool { + return x&(x-1) == 0 +} + +// slicecopy is used to copy from a string or slice of pointerless elements into a slice. +func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int { + if fromLen == 0 || toLen == 0 { + return 0 + } + + n := fromLen + if toLen < n { + n = toLen + } + + if width == 0 { + return n + } + + size := uintptr(n) * width + if raceenabled { + callerpc := getcallerpc() + pc := abi.FuncPCABIInternal(slicecopy) + racereadrangepc(fromPtr, size, callerpc, pc) + racewriterangepc(toPtr, size, callerpc, pc) + } + if msanenabled { + msanread(fromPtr, size) + msanwrite(toPtr, size) + } + if asanenabled { + asanread(fromPtr, size) + asanwrite(toPtr, size) + } + + if size == 1 { // common case worth about 2x to do here + // TODO: is this still worth it with new memmove impl? + *(*byte)(toPtr) = *(*byte)(fromPtr) // known to be a byte pointer + } else { + memmove(toPtr, fromPtr, size) + } + return n +} + +//go:linkname bytealg_MakeNoZero internal/bytealg.MakeNoZero +func bytealg_MakeNoZero(len int) []byte { + if uintptr(len) > maxAlloc { + panicmakeslicelen() + } + cap := roundupsize(uintptr(len), true) + return unsafe.Slice((*byte)(mallocgc(uintptr(cap), nil, false)), cap)[:len] +} diff --git a/contrib/go/_std_1.22/src/runtime/softfloat64.go b/contrib/go/_std_1.23/src/runtime/softfloat64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/softfloat64.go rename to contrib/go/_std_1.23/src/runtime/softfloat64.go diff --git a/contrib/go/_std_1.23/src/runtime/stack.go b/contrib/go/_std_1.23/src/runtime/stack.go new file mode 100644 index 000000000000..d43c6ace4ffc --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/stack.go @@ -0,0 +1,1376 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/abi" + "internal/cpu" + "internal/goarch" + "internal/goos" + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +/* +Stack layout parameters. +Included both by runtime (compiled via 6c) and linkers (compiled via gcc). + +The per-goroutine g->stackguard is set to point StackGuard bytes +above the bottom of the stack. Each function compares its stack +pointer against g->stackguard to check for overflow. To cut one +instruction from the check sequence for functions with tiny frames, +the stack is allowed to protrude StackSmall bytes below the stack +guard. Functions with large frames don't bother with the check and +always call morestack. The sequences are (for amd64, others are +similar): + + guard = g->stackguard + frame = function's stack frame size + argsize = size of function arguments (call + return) + + stack frame size <= StackSmall: + CMPQ guard, SP + JHI 3(PC) + MOVQ m->morearg, $(argsize << 32) + CALL morestack(SB) + + stack frame size > StackSmall but < StackBig + LEAQ (frame-StackSmall)(SP), R0 + CMPQ guard, R0 + JHI 3(PC) + MOVQ m->morearg, $(argsize << 32) + CALL morestack(SB) + + stack frame size >= StackBig: + MOVQ m->morearg, $((argsize << 32) | frame) + CALL morestack(SB) + +The bottom StackGuard - StackSmall bytes are important: there has +to be enough room to execute functions that refuse to check for +stack overflow, either because they need to be adjacent to the +actual caller's frame (deferproc) or because they handle the imminent +stack overflow (morestack). + +For example, deferproc might call malloc, which does one of the +above checks (without allocating a full frame), which might trigger +a call to morestack. This sequence needs to fit in the bottom +section of the stack. On amd64, morestack's frame is 40 bytes, and +deferproc's frame is 56 bytes. That fits well within the +StackGuard - StackSmall bytes at the bottom. +The linkers explore all possible call traces involving non-splitting +functions to make sure that this limit cannot be violated. +*/ + +const ( + // stackSystem is a number of additional bytes to add + // to each stack below the usual guard area for OS-specific + // purposes like signal handling. Used on Windows, Plan 9, + // and iOS because they do not use a separate stack. + stackSystem = goos.IsWindows*4096 + goos.IsPlan9*512 + goos.IsIos*goarch.IsArm64*1024 + + // The minimum size of stack used by Go code + stackMin = 2048 + + // The minimum stack size to allocate. + // The hackery here rounds fixedStack0 up to a power of 2. + fixedStack0 = stackMin + stackSystem + fixedStack1 = fixedStack0 - 1 + fixedStack2 = fixedStack1 | (fixedStack1 >> 1) + fixedStack3 = fixedStack2 | (fixedStack2 >> 2) + fixedStack4 = fixedStack3 | (fixedStack3 >> 4) + fixedStack5 = fixedStack4 | (fixedStack4 >> 8) + fixedStack6 = fixedStack5 | (fixedStack5 >> 16) + fixedStack = fixedStack6 + 1 + + // stackNosplit is the maximum number of bytes that a chain of NOSPLIT + // functions can use. + // This arithmetic must match that in cmd/internal/objabi/stack.go:StackNosplit. + stackNosplit = abi.StackNosplitBase * sys.StackGuardMultiplier + + // The stack guard is a pointer this many bytes above the + // bottom of the stack. + // + // The guard leaves enough room for a stackNosplit chain of NOSPLIT calls + // plus one stackSmall frame plus stackSystem bytes for the OS. + // This arithmetic must match that in cmd/internal/objabi/stack.go:StackLimit. + stackGuard = stackNosplit + stackSystem + abi.StackSmall +) + +const ( + // stackDebug == 0: no logging + // == 1: logging of per-stack operations + // == 2: logging of per-frame operations + // == 3: logging of per-word updates + // == 4: logging of per-word reads + stackDebug = 0 + stackFromSystem = 0 // allocate stacks from system memory instead of the heap + stackFaultOnFree = 0 // old stacks are mapped noaccess to detect use after free + stackNoCache = 0 // disable per-P small stack caches + + // check the BP links during traceback. + debugCheckBP = false +) + +var ( + stackPoisonCopy = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy +) + +const ( + uintptrMask = 1<<(8*goarch.PtrSize) - 1 + + // The values below can be stored to g.stackguard0 to force + // the next stack check to fail. + // These are all larger than any real SP. + + // Goroutine preemption request. + // 0xfffffade in hex. + stackPreempt = uintptrMask & -1314 + + // Thread is forking. Causes a split stack check failure. + // 0xfffffb2e in hex. + stackFork = uintptrMask & -1234 + + // Force a stack movement. Used for debugging. + // 0xfffffeed in hex. + stackForceMove = uintptrMask & -275 + + // stackPoisonMin is the lowest allowed stack poison value. + stackPoisonMin = uintptrMask & -4096 +) + +// Global pool of spans that have free stacks. +// Stacks are assigned an order according to size. +// +// order = log_2(size/FixedStack) +// +// There is a free list for each order. +var stackpool [_NumStackOrders]struct { + item stackpoolItem + _ [(cpu.CacheLinePadSize - unsafe.Sizeof(stackpoolItem{})%cpu.CacheLinePadSize) % cpu.CacheLinePadSize]byte +} + +type stackpoolItem struct { + _ sys.NotInHeap + mu mutex + span mSpanList +} + +// Global pool of large stack spans. +var stackLarge struct { + lock mutex + free [heapAddrBits - pageShift]mSpanList // free lists by log_2(s.npages) +} + +func stackinit() { + if _StackCacheSize&_PageMask != 0 { + throw("cache size must be a multiple of page size") + } + for i := range stackpool { + stackpool[i].item.span.init() + lockInit(&stackpool[i].item.mu, lockRankStackpool) + } + for i := range stackLarge.free { + stackLarge.free[i].init() + lockInit(&stackLarge.lock, lockRankStackLarge) + } +} + +// stacklog2 returns ⌊log_2(n)⌋. +func stacklog2(n uintptr) int { + log2 := 0 + for n > 1 { + n >>= 1 + log2++ + } + return log2 +} + +// Allocates a stack from the free pool. Must be called with +// stackpool[order].item.mu held. +func stackpoolalloc(order uint8) gclinkptr { + list := &stackpool[order].item.span + s := list.first + lockWithRankMayAcquire(&mheap_.lock, lockRankMheap) + if s == nil { + // no free stacks. Allocate another span worth. + s = mheap_.allocManual(_StackCacheSize>>_PageShift, spanAllocStack) + if s == nil { + throw("out of memory") + } + if s.allocCount != 0 { + throw("bad allocCount") + } + if s.manualFreeList.ptr() != nil { + throw("bad manualFreeList") + } + osStackAlloc(s) + s.elemsize = fixedStack << order + for i := uintptr(0); i < _StackCacheSize; i += s.elemsize { + x := gclinkptr(s.base() + i) + x.ptr().next = s.manualFreeList + s.manualFreeList = x + } + list.insert(s) + } + x := s.manualFreeList + if x.ptr() == nil { + throw("span has no free stacks") + } + s.manualFreeList = x.ptr().next + s.allocCount++ + if s.manualFreeList.ptr() == nil { + // all stacks in s are allocated. + list.remove(s) + } + return x +} + +// Adds stack x to the free pool. Must be called with stackpool[order].item.mu held. +func stackpoolfree(x gclinkptr, order uint8) { + s := spanOfUnchecked(uintptr(x)) + if s.state.get() != mSpanManual { + throw("freeing stack not in a stack span") + } + if s.manualFreeList.ptr() == nil { + // s will now have a free stack + stackpool[order].item.span.insert(s) + } + x.ptr().next = s.manualFreeList + s.manualFreeList = x + s.allocCount-- + if gcphase == _GCoff && s.allocCount == 0 { + // Span is completely free. Return it to the heap + // immediately if we're sweeping. + // + // If GC is active, we delay the free until the end of + // GC to avoid the following type of situation: + // + // 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer + // 2) The stack that pointer points to is copied + // 3) The old stack is freed + // 4) The containing span is marked free + // 5) GC attempts to mark the SudoG.elem pointer. The + // marking fails because the pointer looks like a + // pointer into a free span. + // + // By not freeing, we prevent step #4 until GC is done. + stackpool[order].item.span.remove(s) + s.manualFreeList = 0 + osStackFree(s) + mheap_.freeManual(s, spanAllocStack) + } +} + +// stackcacherefill/stackcacherelease implement a global pool of stack segments. +// The pool is required to prevent unlimited growth of per-thread caches. +// +//go:systemstack +func stackcacherefill(c *mcache, order uint8) { + if stackDebug >= 1 { + print("stackcacherefill order=", order, "\n") + } + + // Grab some stacks from the global cache. + // Grab half of the allowed capacity (to prevent thrashing). + var list gclinkptr + var size uintptr + lock(&stackpool[order].item.mu) + for size < _StackCacheSize/2 { + x := stackpoolalloc(order) + x.ptr().next = list + list = x + size += fixedStack << order + } + unlock(&stackpool[order].item.mu) + c.stackcache[order].list = list + c.stackcache[order].size = size +} + +//go:systemstack +func stackcacherelease(c *mcache, order uint8) { + if stackDebug >= 1 { + print("stackcacherelease order=", order, "\n") + } + x := c.stackcache[order].list + size := c.stackcache[order].size + lock(&stackpool[order].item.mu) + for size > _StackCacheSize/2 { + y := x.ptr().next + stackpoolfree(x, order) + x = y + size -= fixedStack << order + } + unlock(&stackpool[order].item.mu) + c.stackcache[order].list = x + c.stackcache[order].size = size +} + +//go:systemstack +func stackcache_clear(c *mcache) { + if stackDebug >= 1 { + print("stackcache clear\n") + } + for order := uint8(0); order < _NumStackOrders; order++ { + lock(&stackpool[order].item.mu) + x := c.stackcache[order].list + for x.ptr() != nil { + y := x.ptr().next + stackpoolfree(x, order) + x = y + } + c.stackcache[order].list = 0 + c.stackcache[order].size = 0 + unlock(&stackpool[order].item.mu) + } +} + +// stackalloc allocates an n byte stack. +// +// stackalloc must run on the system stack because it uses per-P +// resources and must not split the stack. +// +//go:systemstack +func stackalloc(n uint32) stack { + // Stackalloc must be called on scheduler stack, so that we + // never try to grow the stack during the code that stackalloc runs. + // Doing so would cause a deadlock (issue 1547). + thisg := getg() + if thisg != thisg.m.g0 { + throw("stackalloc not on scheduler stack") + } + if n&(n-1) != 0 { + throw("stack size not a power of 2") + } + if stackDebug >= 1 { + print("stackalloc ", n, "\n") + } + + if debug.efence != 0 || stackFromSystem != 0 { + n = uint32(alignUp(uintptr(n), physPageSize)) + v := sysAlloc(uintptr(n), &memstats.stacks_sys) + if v == nil { + throw("out of memory (stackalloc)") + } + return stack{uintptr(v), uintptr(v) + uintptr(n)} + } + + // Small stacks are allocated with a fixed-size free-list allocator. + // If we need a stack of a bigger size, we fall back on allocating + // a dedicated span. + var v unsafe.Pointer + if n < fixedStack<<_NumStackOrders && n < _StackCacheSize { + order := uint8(0) + n2 := n + for n2 > fixedStack { + order++ + n2 >>= 1 + } + var x gclinkptr + if stackNoCache != 0 || thisg.m.p == 0 || thisg.m.preemptoff != "" { + // thisg.m.p == 0 can happen in the guts of exitsyscall + // or procresize. Just get a stack from the global pool. + // Also don't touch stackcache during gc + // as it's flushed concurrently. + lock(&stackpool[order].item.mu) + x = stackpoolalloc(order) + unlock(&stackpool[order].item.mu) + } else { + c := thisg.m.p.ptr().mcache + x = c.stackcache[order].list + if x.ptr() == nil { + stackcacherefill(c, order) + x = c.stackcache[order].list + } + c.stackcache[order].list = x.ptr().next + c.stackcache[order].size -= uintptr(n) + } + v = unsafe.Pointer(x) + } else { + var s *mspan + npage := uintptr(n) >> _PageShift + log2npage := stacklog2(npage) + + // Try to get a stack from the large stack cache. + lock(&stackLarge.lock) + if !stackLarge.free[log2npage].isEmpty() { + s = stackLarge.free[log2npage].first + stackLarge.free[log2npage].remove(s) + } + unlock(&stackLarge.lock) + + lockWithRankMayAcquire(&mheap_.lock, lockRankMheap) + + if s == nil { + // Allocate a new stack from the heap. + s = mheap_.allocManual(npage, spanAllocStack) + if s == nil { + throw("out of memory") + } + osStackAlloc(s) + s.elemsize = uintptr(n) + } + v = unsafe.Pointer(s.base()) + } + + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.GoroutineStackAlloc(uintptr(v), uintptr(n)) + traceRelease(trace) + } + } + if raceenabled { + racemalloc(v, uintptr(n)) + } + if msanenabled { + msanmalloc(v, uintptr(n)) + } + if asanenabled { + asanunpoison(v, uintptr(n)) + } + if stackDebug >= 1 { + print(" allocated ", v, "\n") + } + return stack{uintptr(v), uintptr(v) + uintptr(n)} +} + +// stackfree frees an n byte stack allocation at stk. +// +// stackfree must run on the system stack because it uses per-P +// resources and must not split the stack. +// +//go:systemstack +func stackfree(stk stack) { + gp := getg() + v := unsafe.Pointer(stk.lo) + n := stk.hi - stk.lo + if n&(n-1) != 0 { + throw("stack not a power of 2") + } + if stk.lo+n < stk.hi { + throw("bad stack size") + } + if stackDebug >= 1 { + println("stackfree", v, n) + memclrNoHeapPointers(v, n) // for testing, clobber stack data + } + if debug.efence != 0 || stackFromSystem != 0 { + if debug.efence != 0 || stackFaultOnFree != 0 { + sysFault(v, n) + } else { + sysFree(v, n, &memstats.stacks_sys) + } + return + } + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.GoroutineStackFree(uintptr(v)) + traceRelease(trace) + } + } + if msanenabled { + msanfree(v, n) + } + if asanenabled { + asanpoison(v, n) + } + if n < fixedStack<<_NumStackOrders && n < _StackCacheSize { + order := uint8(0) + n2 := n + for n2 > fixedStack { + order++ + n2 >>= 1 + } + x := gclinkptr(v) + if stackNoCache != 0 || gp.m.p == 0 || gp.m.preemptoff != "" { + lock(&stackpool[order].item.mu) + stackpoolfree(x, order) + unlock(&stackpool[order].item.mu) + } else { + c := gp.m.p.ptr().mcache + if c.stackcache[order].size >= _StackCacheSize { + stackcacherelease(c, order) + } + x.ptr().next = c.stackcache[order].list + c.stackcache[order].list = x + c.stackcache[order].size += n + } + } else { + s := spanOfUnchecked(uintptr(v)) + if s.state.get() != mSpanManual { + println(hex(s.base()), v) + throw("bad span state") + } + if gcphase == _GCoff { + // Free the stack immediately if we're + // sweeping. + osStackFree(s) + mheap_.freeManual(s, spanAllocStack) + } else { + // If the GC is running, we can't return a + // stack span to the heap because it could be + // reused as a heap span, and this state + // change would race with GC. Add it to the + // large stack cache instead. + log2npage := stacklog2(s.npages) + lock(&stackLarge.lock) + stackLarge.free[log2npage].insert(s) + unlock(&stackLarge.lock) + } + } +} + +var maxstacksize uintptr = 1 << 20 // enough until runtime.main sets it for real + +var maxstackceiling = maxstacksize + +var ptrnames = []string{ + 0: "scalar", + 1: "ptr", +} + +// Stack frame layout +// +// (x86) +// +------------------+ +// | args from caller | +// +------------------+ <- frame->argp +// | return address | +// +------------------+ +// | caller's BP (*) | (*) if framepointer_enabled && varp > sp +// +------------------+ <- frame->varp +// | locals | +// +------------------+ +// | args to callee | +// +------------------+ <- frame->sp +// +// (arm) +// +------------------+ +// | args from caller | +// +------------------+ <- frame->argp +// | caller's retaddr | +// +------------------+ +// | caller's FP (*) | (*) on ARM64, if framepointer_enabled && varp > sp +// +------------------+ <- frame->varp +// | locals | +// +------------------+ +// | args to callee | +// +------------------+ +// | return address | +// +------------------+ <- frame->sp +// +// varp > sp means that the function has a frame; +// varp == sp means frameless function. + +type adjustinfo struct { + old stack + delta uintptr // ptr distance from old to new stack (newbase - oldbase) + + // sghi is the highest sudog.elem on the stack. + sghi uintptr +} + +// adjustpointer checks whether *vpp is in the old stack described by adjinfo. +// If so, it rewrites *vpp to point into the new stack. +func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) { + pp := (*uintptr)(vpp) + p := *pp + if stackDebug >= 4 { + print(" ", pp, ":", hex(p), "\n") + } + if adjinfo.old.lo <= p && p < adjinfo.old.hi { + *pp = p + adjinfo.delta + if stackDebug >= 3 { + print(" adjust ptr ", pp, ":", hex(p), " -> ", hex(*pp), "\n") + } + } +} + +// Information from the compiler about the layout of stack frames. +// Note: this type must agree with reflect.bitVector. +type bitvector struct { + n int32 // # of bits + bytedata *uint8 +} + +// ptrbit returns the i'th bit in bv. +// ptrbit is less efficient than iterating directly over bitvector bits, +// and should only be used in non-performance-critical code. +// See adjustpointers for an example of a high-efficiency walk of a bitvector. +func (bv *bitvector) ptrbit(i uintptr) uint8 { + b := *(addb(bv.bytedata, i/8)) + return (b >> (i % 8)) & 1 +} + +// bv describes the memory starting at address scanp. +// Adjust any pointers contained therein. +func adjustpointers(scanp unsafe.Pointer, bv *bitvector, adjinfo *adjustinfo, f funcInfo) { + minp := adjinfo.old.lo + maxp := adjinfo.old.hi + delta := adjinfo.delta + num := uintptr(bv.n) + // If this frame might contain channel receive slots, use CAS + // to adjust pointers. If the slot hasn't been received into + // yet, it may contain stack pointers and a concurrent send + // could race with adjusting those pointers. (The sent value + // itself can never contain stack pointers.) + useCAS := uintptr(scanp) < adjinfo.sghi + for i := uintptr(0); i < num; i += 8 { + if stackDebug >= 4 { + for j := uintptr(0); j < 8; j++ { + print(" ", add(scanp, (i+j)*goarch.PtrSize), ":", ptrnames[bv.ptrbit(i+j)], ":", hex(*(*uintptr)(add(scanp, (i+j)*goarch.PtrSize))), " # ", i, " ", *addb(bv.bytedata, i/8), "\n") + } + } + b := *(addb(bv.bytedata, i/8)) + for b != 0 { + j := uintptr(sys.TrailingZeros8(b)) + b &= b - 1 + pp := (*uintptr)(add(scanp, (i+j)*goarch.PtrSize)) + retry: + p := *pp + if f.valid() && 0 < p && p < minLegalPointer && debug.invalidptr != 0 { + // Looks like a junk value in a pointer slot. + // Live analysis wrong? + getg().m.traceback = 2 + print("runtime: bad pointer in frame ", funcname(f), " at ", pp, ": ", hex(p), "\n") + throw("invalid pointer found on stack") + } + if minp <= p && p < maxp { + if stackDebug >= 3 { + print("adjust ptr ", hex(p), " ", funcname(f), "\n") + } + if useCAS { + ppu := (*unsafe.Pointer)(unsafe.Pointer(pp)) + if !atomic.Casp1(ppu, unsafe.Pointer(p), unsafe.Pointer(p+delta)) { + goto retry + } + } else { + *pp = p + delta + } + } + } + } +} + +// Note: the argument/return area is adjusted by the callee. +func adjustframe(frame *stkframe, adjinfo *adjustinfo) { + if frame.continpc == 0 { + // Frame is dead. + return + } + f := frame.fn + if stackDebug >= 2 { + print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n") + } + + // Adjust saved frame pointer if there is one. + if (goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.ARM64) && frame.argp-frame.varp == 2*goarch.PtrSize { + if stackDebug >= 3 { + print(" saved bp\n") + } + if debugCheckBP { + // Frame pointers should always point to the next higher frame on + // the Go stack (or be nil, for the top frame on the stack). + bp := *(*uintptr)(unsafe.Pointer(frame.varp)) + if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) { + println("runtime: found invalid frame pointer") + print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n") + throw("bad frame pointer") + } + } + // On AMD64, this is the caller's frame pointer saved in the current + // frame. + // On ARM64, this is the frame pointer of the caller's caller saved + // by the caller in its frame (one word below its SP). + adjustpointer(adjinfo, unsafe.Pointer(frame.varp)) + } + + locals, args, objs := frame.getStackMap(true) + + // Adjust local variables if stack frame has been allocated. + if locals.n > 0 { + size := uintptr(locals.n) * goarch.PtrSize + adjustpointers(unsafe.Pointer(frame.varp-size), &locals, adjinfo, f) + } + + // Adjust arguments. + if args.n > 0 { + if stackDebug >= 3 { + print(" args\n") + } + adjustpointers(unsafe.Pointer(frame.argp), &args, adjinfo, funcInfo{}) + } + + // Adjust pointers in all stack objects (whether they are live or not). + // See comments in mgcmark.go:scanframeworker. + if frame.varp != 0 { + for i := range objs { + obj := &objs[i] + off := obj.off + base := frame.varp // locals base pointer + if off >= 0 { + base = frame.argp // arguments and return values base pointer + } + p := base + uintptr(off) + if p < frame.sp { + // Object hasn't been allocated in the frame yet. + // (Happens when the stack bounds check fails and + // we call into morestack.) + continue + } + ptrdata := obj.ptrdata() + gcdata := obj.gcdata() + var s *mspan + if obj.useGCProg() { + // See comments in mgcmark.go:scanstack + s = materializeGCProg(ptrdata, gcdata) + gcdata = (*byte)(unsafe.Pointer(s.startAddr)) + } + for i := uintptr(0); i < ptrdata; i += goarch.PtrSize { + if *addb(gcdata, i/(8*goarch.PtrSize))>>(i/goarch.PtrSize&7)&1 != 0 { + adjustpointer(adjinfo, unsafe.Pointer(p+i)) + } + } + if s != nil { + dematerializeGCProg(s) + } + } + } +} + +func adjustctxt(gp *g, adjinfo *adjustinfo) { + adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.ctxt)) + if !framepointer_enabled { + return + } + if debugCheckBP { + bp := gp.sched.bp + if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) { + println("runtime: found invalid top frame pointer") + print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n") + throw("bad top frame pointer") + } + } + oldfp := gp.sched.bp + adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.bp)) + if GOARCH == "arm64" { + // On ARM64, the frame pointer is saved one word *below* the SP, + // which is not copied or adjusted in any frame. Do it explicitly + // here. + if oldfp == gp.sched.sp-goarch.PtrSize { + memmove(unsafe.Pointer(gp.sched.bp), unsafe.Pointer(oldfp), goarch.PtrSize) + adjustpointer(adjinfo, unsafe.Pointer(gp.sched.bp)) + } + } +} + +func adjustdefers(gp *g, adjinfo *adjustinfo) { + // Adjust pointers in the Defer structs. + // We need to do this first because we need to adjust the + // defer.link fields so we always work on the new stack. + adjustpointer(adjinfo, unsafe.Pointer(&gp._defer)) + for d := gp._defer; d != nil; d = d.link { + adjustpointer(adjinfo, unsafe.Pointer(&d.fn)) + adjustpointer(adjinfo, unsafe.Pointer(&d.sp)) + adjustpointer(adjinfo, unsafe.Pointer(&d.link)) + } +} + +func adjustpanics(gp *g, adjinfo *adjustinfo) { + // Panics are on stack and already adjusted. + // Update pointer to head of list in G. + adjustpointer(adjinfo, unsafe.Pointer(&gp._panic)) +} + +func adjustsudogs(gp *g, adjinfo *adjustinfo) { + // the data elements pointed to by a SudoG structure + // might be in the stack. + for s := gp.waiting; s != nil; s = s.waitlink { + adjustpointer(adjinfo, unsafe.Pointer(&s.elem)) + } +} + +func fillstack(stk stack, b byte) { + for p := stk.lo; p < stk.hi; p++ { + *(*byte)(unsafe.Pointer(p)) = b + } +} + +func findsghi(gp *g, stk stack) uintptr { + var sghi uintptr + for sg := gp.waiting; sg != nil; sg = sg.waitlink { + p := uintptr(sg.elem) + uintptr(sg.c.elemsize) + if stk.lo <= p && p < stk.hi && p > sghi { + sghi = p + } + } + return sghi +} + +// syncadjustsudogs adjusts gp's sudogs and copies the part of gp's +// stack they refer to while synchronizing with concurrent channel +// operations. It returns the number of bytes of stack copied. +func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr { + if gp.waiting == nil { + return 0 + } + + // Lock channels to prevent concurrent send/receive. + var lastc *hchan + for sg := gp.waiting; sg != nil; sg = sg.waitlink { + if sg.c != lastc { + // There is a ranking cycle here between gscan bit and + // hchan locks. Normally, we only allow acquiring hchan + // locks and then getting a gscan bit. In this case, we + // already have the gscan bit. We allow acquiring hchan + // locks here as a special case, since a deadlock can't + // happen because the G involved must already be + // suspended. So, we get a special hchan lock rank here + // that is lower than gscan, but doesn't allow acquiring + // any other locks other than hchan. + lockWithRank(&sg.c.lock, lockRankHchanLeaf) + } + lastc = sg.c + } + + // Adjust sudogs. + adjustsudogs(gp, adjinfo) + + // Copy the part of the stack the sudogs point in to + // while holding the lock to prevent races on + // send/receive slots. + var sgsize uintptr + if adjinfo.sghi != 0 { + oldBot := adjinfo.old.hi - used + newBot := oldBot + adjinfo.delta + sgsize = adjinfo.sghi - oldBot + memmove(unsafe.Pointer(newBot), unsafe.Pointer(oldBot), sgsize) + } + + // Unlock channels. + lastc = nil + for sg := gp.waiting; sg != nil; sg = sg.waitlink { + if sg.c != lastc { + unlock(&sg.c.lock) + } + lastc = sg.c + } + + return sgsize +} + +// Copies gp's stack to a new stack of a different size. +// Caller must have changed gp status to Gcopystack. +func copystack(gp *g, newsize uintptr) { + if gp.syscallsp != 0 { + throw("stack growth not allowed in system call") + } + old := gp.stack + if old.lo == 0 { + throw("nil stackbase") + } + used := old.hi - gp.sched.sp + // Add just the difference to gcController.addScannableStack. + // g0 stacks never move, so this will never account for them. + // It's also fine if we have no P, addScannableStack can deal with + // that case. + gcController.addScannableStack(getg().m.p.ptr(), int64(newsize)-int64(old.hi-old.lo)) + + // allocate new stack + new := stackalloc(uint32(newsize)) + if stackPoisonCopy != 0 { + fillstack(new, 0xfd) + } + if stackDebug >= 1 { + print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]", " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n") + } + + // Compute adjustment. + var adjinfo adjustinfo + adjinfo.old = old + adjinfo.delta = new.hi - old.hi + + // Adjust sudogs, synchronizing with channel ops if necessary. + ncopy := used + if !gp.activeStackChans { + if newsize < old.hi-old.lo && gp.parkingOnChan.Load() { + // It's not safe for someone to shrink this stack while we're actively + // parking on a channel, but it is safe to grow since we do that + // ourselves and explicitly don't want to synchronize with channels + // since we could self-deadlock. + throw("racy sudog adjustment due to parking on channel") + } + adjustsudogs(gp, &adjinfo) + } else { + // sudogs may be pointing in to the stack and gp has + // released channel locks, so other goroutines could + // be writing to gp's stack. Find the highest such + // pointer so we can handle everything there and below + // carefully. (This shouldn't be far from the bottom + // of the stack, so there's little cost in handling + // everything below it carefully.) + adjinfo.sghi = findsghi(gp, old) + + // Synchronize with channel ops and copy the part of + // the stack they may interact with. + ncopy -= syncadjustsudogs(gp, used, &adjinfo) + } + + // Copy the stack (or the rest of it) to the new location + memmove(unsafe.Pointer(new.hi-ncopy), unsafe.Pointer(old.hi-ncopy), ncopy) + + // Adjust remaining structures that have pointers into stacks. + // We have to do most of these before we traceback the new + // stack because gentraceback uses them. + adjustctxt(gp, &adjinfo) + adjustdefers(gp, &adjinfo) + adjustpanics(gp, &adjinfo) + if adjinfo.sghi != 0 { + adjinfo.sghi += adjinfo.delta + } + + // Swap out old stack for new one + gp.stack = new + gp.stackguard0 = new.lo + stackGuard // NOTE: might clobber a preempt request + gp.sched.sp = new.hi - used + gp.stktopsp += adjinfo.delta + + // Adjust pointers in the new stack. + var u unwinder + for u.init(gp, 0); u.valid(); u.next() { + adjustframe(&u.frame, &adjinfo) + } + + // free old stack + if stackPoisonCopy != 0 { + fillstack(old, 0xfc) + } + stackfree(old) +} + +// round x up to a power of 2. +func round2(x int32) int32 { + s := uint(0) + for 1<atomicstatus will be Grunning or Gscanrunning upon entry. +// If the scheduler is trying to stop this g, then it will set preemptStop. +// +// This must be nowritebarrierrec because it can be called as part of +// stack growth from other nowritebarrierrec functions, but the +// compiler doesn't check this. +// +//go:nowritebarrierrec +func newstack() { + thisg := getg() + // TODO: double check all gp. shouldn't be getg(). + if thisg.m.morebuf.g.ptr().stackguard0 == stackFork { + throw("stack growth after fork") + } + if thisg.m.morebuf.g.ptr() != thisg.m.curg { + print("runtime: newstack called from g=", hex(thisg.m.morebuf.g), "\n"+"\tm=", thisg.m, " m->curg=", thisg.m.curg, " m->g0=", thisg.m.g0, " m->gsignal=", thisg.m.gsignal, "\n") + morebuf := thisg.m.morebuf + traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g.ptr()) + throw("runtime: wrong goroutine in newstack") + } + + gp := thisg.m.curg + + if thisg.m.curg.throwsplit { + // Update syscallsp, syscallpc in case traceback uses them. + morebuf := thisg.m.morebuf + gp.syscallsp = morebuf.sp + gp.syscallpc = morebuf.pc + pcname, pcoff := "(unknown)", uintptr(0) + f := findfunc(gp.sched.pc) + if f.valid() { + pcname = funcname(f) + pcoff = gp.sched.pc - f.entry() + } + print("runtime: newstack at ", pcname, "+", hex(pcoff), + " sp=", hex(gp.sched.sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n", + "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n", + "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n") + + thisg.m.traceback = 2 // Include runtime frames + traceback(morebuf.pc, morebuf.sp, morebuf.lr, gp) + throw("runtime: stack split at bad time") + } + + morebuf := thisg.m.morebuf + thisg.m.morebuf.pc = 0 + thisg.m.morebuf.lr = 0 + thisg.m.morebuf.sp = 0 + thisg.m.morebuf.g = 0 + + // NOTE: stackguard0 may change underfoot, if another thread + // is about to try to preempt gp. Read it just once and use that same + // value now and below. + stackguard0 := atomic.Loaduintptr(&gp.stackguard0) + + // Be conservative about where we preempt. + // We are interested in preempting user Go code, not runtime code. + // If we're holding locks, mallocing, or preemption is disabled, don't + // preempt. + // This check is very early in newstack so that even the status change + // from Grunning to Gwaiting and back doesn't happen in this case. + // That status change by itself can be viewed as a small preemption, + // because the GC might change Gwaiting to Gscanwaiting, and then + // this goroutine has to wait for the GC to finish before continuing. + // If the GC is in some way dependent on this goroutine (for example, + // it needs a lock held by the goroutine), that small preemption turns + // into a real deadlock. + preempt := stackguard0 == stackPreempt + if preempt { + if !canPreemptM(thisg.m) { + // Let the goroutine keep running for now. + // gp->preempt is set, so it will be preempted next time. + gp.stackguard0 = gp.stack.lo + stackGuard + gogo(&gp.sched) // never return + } + } + + if gp.stack.lo == 0 { + throw("missing stack in newstack") + } + sp := gp.sched.sp + if goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.I386 || goarch.ArchFamily == goarch.WASM { + // The call to morestack cost a word. + sp -= goarch.PtrSize + } + if stackDebug >= 1 || sp < gp.stack.lo { + print("runtime: newstack sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n", + "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n", + "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n") + } + if sp < gp.stack.lo { + print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->status=", hex(readgstatus(gp)), "\n ") + print("runtime: split stack overflow: ", hex(sp), " < ", hex(gp.stack.lo), "\n") + throw("runtime: split stack overflow") + } + + if preempt { + if gp == thisg.m.g0 { + throw("runtime: preempt g0") + } + if thisg.m.p == 0 && thisg.m.locks == 0 { + throw("runtime: g is running but p is not") + } + + if gp.preemptShrink { + // We're at a synchronous safe point now, so + // do the pending stack shrink. + gp.preemptShrink = false + shrinkstack(gp) + } + + if gp.preemptStop { + preemptPark(gp) // never returns + } + + // Act like goroutine called runtime.Gosched. + gopreempt_m(gp) // never return + } + + // Allocate a bigger segment and move the stack. + oldsize := gp.stack.hi - gp.stack.lo + newsize := oldsize * 2 + + // Make sure we grow at least as much as needed to fit the new frame. + // (This is just an optimization - the caller of morestack will + // recheck the bounds on return.) + if f := findfunc(gp.sched.pc); f.valid() { + max := uintptr(funcMaxSPDelta(f)) + needed := max + stackGuard + used := gp.stack.hi - gp.sched.sp + for newsize-used < needed { + newsize *= 2 + } + } + + if stackguard0 == stackForceMove { + // Forced stack movement used for debugging. + // Don't double the stack (or we may quickly run out + // if this is done repeatedly). + newsize = oldsize + } + + if newsize > maxstacksize || newsize > maxstackceiling { + if maxstacksize < maxstackceiling { + print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n") + } else { + print("runtime: goroutine stack exceeds ", maxstackceiling, "-byte limit\n") + } + print("runtime: sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n") + throw("stack overflow") + } + + // The goroutine must be executing in order to call newstack, + // so it must be Grunning (or Gscanrunning). + casgstatus(gp, _Grunning, _Gcopystack) + + // The concurrent GC will not scan the stack while we are doing the copy since + // the gp is in a Gcopystack status. + copystack(gp, newsize) + if stackDebug >= 1 { + print("stack grow done\n") + } + casgstatus(gp, _Gcopystack, _Grunning) + gogo(&gp.sched) +} + +//go:nosplit +func nilfunc() { + *(*uint8)(nil) = 0 +} + +// adjust Gobuf as if it executed a call to fn +// and then stopped before the first instruction in fn. +func gostartcallfn(gobuf *gobuf, fv *funcval) { + var fn unsafe.Pointer + if fv != nil { + fn = unsafe.Pointer(fv.fn) + } else { + fn = unsafe.Pointer(abi.FuncPCABIInternal(nilfunc)) + } + gostartcall(gobuf, fn, unsafe.Pointer(fv)) +} + +// isShrinkStackSafe returns whether it's safe to attempt to shrink +// gp's stack. Shrinking the stack is only safe when we have precise +// pointer maps for all frames on the stack. The caller must hold the +// _Gscan bit for gp or must be running gp itself. +func isShrinkStackSafe(gp *g) bool { + // We can't copy the stack if we're in a syscall. + // The syscall might have pointers into the stack and + // often we don't have precise pointer maps for the innermost + // frames. + if gp.syscallsp != 0 { + return false + } + // We also can't copy the stack if we're at an asynchronous + // safe-point because we don't have precise pointer maps for + // all frames. + if gp.asyncSafePoint { + return false + } + // We also can't *shrink* the stack in the window between the + // goroutine calling gopark to park on a channel and + // gp.activeStackChans being set. + if gp.parkingOnChan.Load() { + return false + } + // We also can't copy the stack while tracing is enabled, and + // gp is in _Gwaiting solely to make itself available to the GC. + // In these cases, the G is actually executing on the system + // stack, and the execution tracer may want to take a stack trace + // of the G's stack. Note: it's safe to access gp.waitreason here. + // We're only checking if this is true if we took ownership of the + // G with the _Gscan bit. This prevents the goroutine from transitioning, + // which prevents gp.waitreason from changing. + if traceEnabled() && readgstatus(gp)&^_Gscan == _Gwaiting && gp.waitreason.isWaitingForGC() { + return false + } + return true +} + +// Maybe shrink the stack being used by gp. +// +// gp must be stopped and we must own its stack. It may be in +// _Grunning, but only if this is our own user G. +func shrinkstack(gp *g) { + if gp.stack.lo == 0 { + throw("missing stack in shrinkstack") + } + if s := readgstatus(gp); s&_Gscan == 0 { + // We don't own the stack via _Gscan. We could still + // own it if this is our own user G and we're on the + // system stack. + if !(gp == getg().m.curg && getg() != getg().m.curg && s == _Grunning) { + // We don't own the stack. + throw("bad status in shrinkstack") + } + } + if !isShrinkStackSafe(gp) { + throw("shrinkstack at bad time") + } + // Check for self-shrinks while in a libcall. These may have + // pointers into the stack disguised as uintptrs, but these + // code paths should all be nosplit. + if gp == getg().m.curg && gp.m.libcallsp != 0 { + throw("shrinking stack in libcall") + } + + if debug.gcshrinkstackoff > 0 { + return + } + f := findfunc(gp.startpc) + if f.valid() && f.funcID == abi.FuncID_gcBgMarkWorker { + // We're not allowed to shrink the gcBgMarkWorker + // stack (see gcBgMarkWorker for explanation). + return + } + + oldsize := gp.stack.hi - gp.stack.lo + newsize := oldsize / 2 + // Don't shrink the allocation below the minimum-sized stack + // allocation. + if newsize < fixedStack { + return + } + // Compute how much of the stack is currently in use and only + // shrink the stack if gp is using less than a quarter of its + // current stack. The currently used stack includes everything + // down to the SP plus the stack guard space that ensures + // there's room for nosplit functions. + avail := gp.stack.hi - gp.stack.lo + if used := gp.stack.hi - gp.sched.sp + stackNosplit; used >= avail/4 { + return + } + + if stackDebug > 0 { + print("shrinking stack ", oldsize, "->", newsize, "\n") + } + + copystack(gp, newsize) +} + +// freeStackSpans frees unused stack spans at the end of GC. +func freeStackSpans() { + // Scan stack pools for empty stack spans. + for order := range stackpool { + lock(&stackpool[order].item.mu) + list := &stackpool[order].item.span + for s := list.first; s != nil; { + next := s.next + if s.allocCount == 0 { + list.remove(s) + s.manualFreeList = 0 + osStackFree(s) + mheap_.freeManual(s, spanAllocStack) + } + s = next + } + unlock(&stackpool[order].item.mu) + } + + // Free large stack spans. + lock(&stackLarge.lock) + for i := range stackLarge.free { + for s := stackLarge.free[i].first; s != nil; { + next := s.next + stackLarge.free[i].remove(s) + osStackFree(s) + mheap_.freeManual(s, spanAllocStack) + s = next + } + } + unlock(&stackLarge.lock) +} + +// A stackObjectRecord is generated by the compiler for each stack object in a stack frame. +// This record must match the generator code in cmd/compile/internal/liveness/plive.go:emitStackObjects. +type stackObjectRecord struct { + // offset in frame + // if negative, offset from varp + // if non-negative, offset from argp + off int32 + size int32 + _ptrdata int32 // ptrdata, or -ptrdata is GC prog is used + gcdataoff uint32 // offset to gcdata from moduledata.rodata +} + +func (r *stackObjectRecord) useGCProg() bool { + return r._ptrdata < 0 +} + +func (r *stackObjectRecord) ptrdata() uintptr { + x := r._ptrdata + if x < 0 { + return uintptr(-x) + } + return uintptr(x) +} + +// gcdata returns pointer map or GC prog of the type. +func (r *stackObjectRecord) gcdata() *byte { + ptr := uintptr(unsafe.Pointer(r)) + var mod *moduledata + for datap := &firstmoduledata; datap != nil; datap = datap.next { + if datap.gofunc <= ptr && ptr < datap.end { + mod = datap + break + } + } + // If you get a panic here due to a nil mod, + // you may have made a copy of a stackObjectRecord. + // You must use the original pointer. + res := mod.rodata + uintptr(r.gcdataoff) + return (*byte)(unsafe.Pointer(res)) +} + +// This is exported as ABI0 via linkname so obj can call it. +// +//go:nosplit +//go:linkname morestackc +func morestackc() { + throw("attempt to execute system stack code on user stack") +} + +// startingStackSize is the amount of stack that new goroutines start with. +// It is a power of 2, and between fixedStack and maxstacksize, inclusive. +// startingStackSize is updated every GC by tracking the average size of +// stacks scanned during the GC. +var startingStackSize uint32 = fixedStack + +func gcComputeStartingStackSize() { + if debug.adaptivestackstart == 0 { + return + } + // For details, see the design doc at + // https://docs.google.com/document/d/1YDlGIdVTPnmUiTAavlZxBI1d9pwGQgZT7IKFKlIXohQ/edit?usp=sharing + // The basic algorithm is to track the average size of stacks + // and start goroutines with stack equal to that average size. + // Starting at the average size uses at most 2x the space that + // an ideal algorithm would have used. + // This is just a heuristic to avoid excessive stack growth work + // early in a goroutine's lifetime. See issue 18138. Stacks that + // are allocated too small can still grow, and stacks allocated + // too large can still shrink. + var scannedStackSize uint64 + var scannedStacks uint64 + for _, p := range allp { + scannedStackSize += p.scannedStackSize + scannedStacks += p.scannedStacks + // Reset for next time + p.scannedStackSize = 0 + p.scannedStacks = 0 + } + if scannedStacks == 0 { + startingStackSize = fixedStack + return + } + avg := scannedStackSize/scannedStacks + stackGuard + // Note: we add stackGuard to ensure that a goroutine that + // uses the average space will not trigger a growth. + if avg > uint64(maxstacksize) { + avg = uint64(maxstacksize) + } + if avg < fixedStack { + avg = fixedStack + } + // Note: maxstacksize fits in 30 bits, so avg also does. + startingStackSize = uint32(round2(int32(avg))) +} diff --git a/contrib/go/_std_1.22/src/runtime/stkframe.go b/contrib/go/_std_1.23/src/runtime/stkframe.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/stkframe.go rename to contrib/go/_std_1.23/src/runtime/stkframe.go index becb729e598a..42b69477511d 100644 --- a/contrib/go/_std_1.22/src/runtime/stkframe.go +++ b/contrib/go/_std_1.23/src/runtime/stkframe.go @@ -264,7 +264,7 @@ var methodValueCallFrameObjs [1]stackObjectRecord // initialized in stackobjecti func stkobjinit() { var abiRegArgsEface any = abi.RegArgs{} abiRegArgsType := efaceOf(&abiRegArgsEface)._type - if abiRegArgsType.Kind_&kindGCProg != 0 { + if abiRegArgsType.Kind_&abi.KindGCProg != 0 { throw("abiRegArgsType needs GC Prog, update methodValueCallFrameObjs") } // Set methodValueCallFrameObjs[0].gcdataoff so that diff --git a/contrib/go/_std_1.22/src/runtime/string.go b/contrib/go/_std_1.23/src/runtime/string.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/string.go rename to contrib/go/_std_1.23/src/runtime/string.go index e01b7fc74448..5bdb25b9db7c 100644 --- a/contrib/go/_std_1.22/src/runtime/string.go +++ b/contrib/go/_std_1.23/src/runtime/string.go @@ -78,6 +78,16 @@ func concatstring5(buf *tmpBuf, a0, a1, a2, a3, a4 string) string { // n is the length of the slice. // Buf is a fixed-size buffer for the result, // it is not nil if the result does not escape. +// +// slicebytetostring should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname slicebytetostring func slicebytetostring(buf *tmpBuf, ptr *byte, n int) string { if n == 0 { // Turns out to be a relatively common case. @@ -312,7 +322,7 @@ func gobytes(p *byte, n int) (b []byte) { return } -// This is exported via linkname to assembly in syscall (for Plan9). +// This is exported via linkname to assembly in syscall (for Plan9) and cgo. // //go:linkname gostring func gostring(p *byte) string { @@ -341,14 +351,6 @@ func gostringn(p *byte, l int) string { return s } -func hasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[:len(prefix)] == prefix -} - -func hasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix -} - const ( maxUint64 = ^uint64(0) maxInt64 = int64(maxUint64 >> 1) diff --git a/contrib/go/_std_1.22/src/runtime/stubs.go b/contrib/go/_std_1.23/src/runtime/stubs.go similarity index 85% rename from contrib/go/_std_1.22/src/runtime/stubs.go rename to contrib/go/_std_1.23/src/runtime/stubs.go index 34984d86ffaf..2aeb4774b972 100644 --- a/contrib/go/_std_1.22/src/runtime/stubs.go +++ b/contrib/go/_std_1.23/src/runtime/stubs.go @@ -11,6 +11,15 @@ import ( // Should be a built-in for unsafe.Pointer? // +// add should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - fortio.org/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname add //go:nosplit func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { return unsafe.Pointer(uintptr(p) + x) @@ -83,6 +92,19 @@ func badsystemstack() { // // The (CPU-specific) implementations of this function are in memclr_*.s. // +// memclrNoHeapPointers should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/chenzhuoyu/iasm +// - github.com/cloudwego/frugal +// - github.com/dgraph-io/ristretto +// - github.com/outcaste-io/ristretto +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memclrNoHeapPointers //go:noescape func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) @@ -103,12 +125,26 @@ func reflect_memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) { // // Implementations are in memmove_*.s. // -//go:noescape -func memmove(to, from unsafe.Pointer, n uintptr) - -// Outside assembly calls memmove. Make sure it has ABI wrappers. +// Outside assembly calls memmove. +// +// memmove should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/dynamicgo +// - github.com/cloudwego/frugal +// - github.com/ebitengine/purego +// - github.com/tetratelabs/wazero +// - github.com/ugorji/go/codec +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. // //go:linkname memmove +//go:noescape +func memmove(to, from unsafe.Pointer, n uintptr) //go:linkname reflect_memmove reflect.memmove func reflect_memmove(to, from unsafe.Pointer, n uintptr) { @@ -120,6 +156,15 @@ const hashLoad = float32(loadFactorNum) / float32(loadFactorDen) // in internal/bytealg/equal_*.s // +// memequal should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memequal //go:noescape func memequal(a, b unsafe.Pointer, size uintptr) bool @@ -129,6 +174,19 @@ func memequal(a, b unsafe.Pointer, size uintptr) bool // compiles down to zero instructions. // USE CAREFULLY! // +// noescape should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/ebitengine/purego +// - github.com/hamba/avro/v2 +// - github.com/puzpuzpuz/xsync/v3 +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname noescape //go:nosplit func noescape(p unsafe.Pointer) unsafe.Pointer { x := uintptr(p) @@ -207,6 +265,17 @@ func breakpoint() //go:noescape func reflectcall(stackArgsType *_type, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +// procyield should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing-tun +// - github.com/slackhq/nebula +// - github.com/tailscale/wireguard-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname procyield func procyield(cycles uint32) type neverCallThisFunction struct{} @@ -295,7 +364,18 @@ func getclosureptr() uintptr func asmcgocall(fn, arg unsafe.Pointer) int32 func morestack() + +// morestack_noctxt should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname morestack_noctxt func morestack_noctxt() + func rt0_go() // return0 is a stub used to return 0 from deferproc. @@ -380,7 +460,19 @@ func abort() // Called from compiled code; declared for vet; do NOT call from Go. func gcWriteBarrier1() + +// gcWriteBarrier2 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname gcWriteBarrier2 func gcWriteBarrier2() + func gcWriteBarrier3() func gcWriteBarrier4() func gcWriteBarrier5() diff --git a/contrib/go/_std_1.22/src/runtime/stubs2.go b/contrib/go/_std_1.23/src/runtime/stubs2.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/stubs2.go rename to contrib/go/_std_1.23/src/runtime/stubs2.go index 9637347a3555..39bde15b1caa 100644 --- a/contrib/go/_std_1.22/src/runtime/stubs2.go +++ b/contrib/go/_std_1.23/src/runtime/stubs2.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/stubs3.go b/contrib/go/_std_1.23/src/runtime/stubs3.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs3.go rename to contrib/go/_std_1.23/src/runtime/stubs3.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_386.go b/contrib/go/_std_1.23/src/runtime/stubs_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_386.go rename to contrib/go/_std_1.23/src/runtime/stubs_386.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_amd64.go b/contrib/go/_std_1.23/src/runtime/stubs_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_amd64.go rename to contrib/go/_std_1.23/src/runtime/stubs_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_arm.go b/contrib/go/_std_1.23/src/runtime/stubs_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_arm.go rename to contrib/go/_std_1.23/src/runtime/stubs_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_arm64.go b/contrib/go/_std_1.23/src/runtime/stubs_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_arm64.go rename to contrib/go/_std_1.23/src/runtime/stubs_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_linux.go b/contrib/go/_std_1.23/src/runtime/stubs_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_linux.go rename to contrib/go/_std_1.23/src/runtime/stubs_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_loong64.go b/contrib/go/_std_1.23/src/runtime/stubs_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_loong64.go rename to contrib/go/_std_1.23/src/runtime/stubs_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_mips64x.go b/contrib/go/_std_1.23/src/runtime/stubs_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_mips64x.go rename to contrib/go/_std_1.23/src/runtime/stubs_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_mipsx.go b/contrib/go/_std_1.23/src/runtime/stubs_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_mipsx.go rename to contrib/go/_std_1.23/src/runtime/stubs_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_nonlinux.go b/contrib/go/_std_1.23/src/runtime/stubs_nonlinux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_nonlinux.go rename to contrib/go/_std_1.23/src/runtime/stubs_nonlinux.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_ppc64.go b/contrib/go/_std_1.23/src/runtime/stubs_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_ppc64.go rename to contrib/go/_std_1.23/src/runtime/stubs_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_ppc64x.go b/contrib/go/_std_1.23/src/runtime/stubs_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/stubs_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_riscv64.go b/contrib/go/_std_1.23/src/runtime/stubs_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_riscv64.go rename to contrib/go/_std_1.23/src/runtime/stubs_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_s390x.go b/contrib/go/_std_1.23/src/runtime/stubs_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_s390x.go rename to contrib/go/_std_1.23/src/runtime/stubs_s390x.go diff --git a/contrib/go/_std_1.23/src/runtime/symtab.go b/contrib/go/_std_1.23/src/runtime/symtab.go new file mode 100644 index 000000000000..10cdcf9c6ee8 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/symtab.go @@ -0,0 +1,1310 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/abi" + "internal/goarch" + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +// Frames may be used to get function/file/line information for a +// slice of PC values returned by [Callers]. +type Frames struct { + // callers is a slice of PCs that have not yet been expanded to frames. + callers []uintptr + + // nextPC is a next PC to expand ahead of processing callers. + nextPC uintptr + + // frames is a slice of Frames that have yet to be returned. + frames []Frame + frameStore [2]Frame +} + +// Frame is the information returned by [Frames] for each call frame. +type Frame struct { + // PC is the program counter for the location in this frame. + // For a frame that calls another frame, this will be the + // program counter of a call instruction. Because of inlining, + // multiple frames may have the same PC value, but different + // symbolic information. + PC uintptr + + // Func is the Func value of this call frame. This may be nil + // for non-Go code or fully inlined functions. + Func *Func + + // Function is the package path-qualified function name of + // this call frame. If non-empty, this string uniquely + // identifies a single function in the program. + // This may be the empty string if not known. + // If Func is not nil then Function == Func.Name(). + Function string + + // File and Line are the file name and line number of the + // location in this frame. For non-leaf frames, this will be + // the location of a call. These may be the empty string and + // zero, respectively, if not known. + File string + Line int + + // startLine is the line number of the beginning of the function in + // this frame. Specifically, it is the line number of the func keyword + // for Go functions. Note that //line directives can change the + // filename and/or line number arbitrarily within a function, meaning + // that the Line - startLine offset is not always meaningful. + // + // This may be zero if not known. + startLine int + + // Entry point program counter for the function; may be zero + // if not known. If Func is not nil then Entry == + // Func.Entry(). + Entry uintptr + + // The runtime's internal view of the function. This field + // is set (funcInfo.valid() returns true) only for Go functions, + // not for C functions. + funcInfo funcInfo +} + +// CallersFrames takes a slice of PC values returned by [Callers] and +// prepares to return function/file/line information. +// Do not change the slice until you are done with the [Frames]. +func CallersFrames(callers []uintptr) *Frames { + f := &Frames{callers: callers} + f.frames = f.frameStore[:0] + return f +} + +// Next returns a [Frame] representing the next call frame in the slice +// of PC values. If it has already returned all call frames, Next +// returns a zero [Frame]. +// +// The more result indicates whether the next call to Next will return +// a valid [Frame]. It does not necessarily indicate whether this call +// returned one. +// +// See the [Frames] example for idiomatic usage. +func (ci *Frames) Next() (frame Frame, more bool) { + for len(ci.frames) < 2 { + // Find the next frame. + // We need to look for 2 frames so we know what + // to return for the "more" result. + if len(ci.callers) == 0 { + break + } + var pc uintptr + if ci.nextPC != 0 { + pc, ci.nextPC = ci.nextPC, 0 + } else { + pc, ci.callers = ci.callers[0], ci.callers[1:] + } + funcInfo := findfunc(pc) + if !funcInfo.valid() { + if cgoSymbolizer != nil { + // Pre-expand cgo frames. We could do this + // incrementally, too, but there's no way to + // avoid allocation in this case anyway. + ci.frames = append(ci.frames, expandCgoFrames(pc)...) + } + continue + } + f := funcInfo._Func() + entry := f.Entry() + if pc > entry { + // We store the pc of the start of the instruction following + // the instruction in question (the call or the inline mark). + // This is done for historical reasons, and to make FuncForPC + // work correctly for entries in the result of runtime.Callers. + pc-- + } + // It's important that interpret pc non-strictly as cgoTraceback may + // have added bogus PCs with a valid funcInfo but invalid PCDATA. + u, uf := newInlineUnwinder(funcInfo, pc) + sf := u.srcFunc(uf) + if u.isInlined(uf) { + // Note: entry is not modified. It always refers to a real frame, not an inlined one. + // File/line from funcline1 below are already correct. + f = nil + + // When CallersFrame is invoked using the PC list returned by Callers, + // the PC list includes virtual PCs corresponding to each outer frame + // around an innermost real inlined PC. + // We also want to support code passing in a PC list extracted from a + // stack trace, and there only the real PCs are printed, not the virtual ones. + // So check to see if the implied virtual PC for this PC (obtained from the + // unwinder itself) is the next PC in ci.callers. If not, insert it. + // The +1 here correspond to the pc-- above: the output of Callers + // and therefore the input to CallersFrames is return PCs from the stack; + // The pc-- backs up into the CALL instruction (not the first byte of the CALL + // instruction, but good enough to find it nonetheless). + // There are no cycles in implied virtual PCs (some number of frames were + // inlined, but that number is finite), so this unpacking cannot cause an infinite loop. + for unext := u.next(uf); unext.valid() && len(ci.callers) > 0 && ci.callers[0] != unext.pc+1; unext = u.next(unext) { + snext := u.srcFunc(unext) + if snext.funcID == abi.FuncIDWrapper && elideWrapperCalling(sf.funcID) { + // Skip, because tracebackPCs (inside runtime.Callers) would too. + continue + } + ci.nextPC = unext.pc + 1 + break + } + } + ci.frames = append(ci.frames, Frame{ + PC: pc, + Func: f, + Function: funcNameForPrint(sf.name()), + Entry: entry, + startLine: int(sf.startLine), + funcInfo: funcInfo, + // Note: File,Line set below + }) + } + + // Pop one frame from the frame list. Keep the rest. + // Avoid allocation in the common case, which is 1 or 2 frames. + switch len(ci.frames) { + case 0: // In the rare case when there are no frames at all, we return Frame{}. + return + case 1: + frame = ci.frames[0] + ci.frames = ci.frameStore[:0] + case 2: + frame = ci.frames[0] + ci.frameStore[0] = ci.frames[1] + ci.frames = ci.frameStore[:1] + default: + frame = ci.frames[0] + ci.frames = ci.frames[1:] + } + more = len(ci.frames) > 0 + if frame.funcInfo.valid() { + // Compute file/line just before we need to return it, + // as it can be expensive. This avoids computing file/line + // for the Frame we find but don't return. See issue 32093. + file, line := funcline1(frame.funcInfo, frame.PC, false) + frame.File, frame.Line = file, int(line) + } + return +} + +// runtime_FrameStartLine returns the start line of the function in a Frame. +// +// runtime_FrameStartLine should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/grafana/pyroscope-go/godeltaprof +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname runtime_FrameStartLine runtime/pprof.runtime_FrameStartLine +func runtime_FrameStartLine(f *Frame) int { + return f.startLine +} + +// runtime_FrameSymbolName returns the full symbol name of the function in a Frame. +// For generic functions this differs from f.Function in that this doesn't replace +// the shape name to "...". +// +// runtime_FrameSymbolName should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/grafana/pyroscope-go/godeltaprof +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname runtime_FrameSymbolName runtime/pprof.runtime_FrameSymbolName +func runtime_FrameSymbolName(f *Frame) string { + if !f.funcInfo.valid() { + return f.Function + } + u, uf := newInlineUnwinder(f.funcInfo, f.PC) + sf := u.srcFunc(uf) + return sf.name() +} + +// runtime_expandFinalInlineFrame expands the final pc in stk to include all +// "callers" if pc is inline. +// +// runtime_expandFinalInlineFrame should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/grafana/pyroscope-go/godeltaprof +// - github.com/pyroscope-io/godeltaprof +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname runtime_expandFinalInlineFrame runtime/pprof.runtime_expandFinalInlineFrame +func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr { + // TODO: It would be more efficient to report only physical PCs to pprof and + // just expand the whole stack. + if len(stk) == 0 { + return stk + } + pc := stk[len(stk)-1] + tracepc := pc - 1 + + f := findfunc(tracepc) + if !f.valid() { + // Not a Go function. + return stk + } + + u, uf := newInlineUnwinder(f, tracepc) + if !u.isInlined(uf) { + // Nothing inline at tracepc. + return stk + } + + // Treat the previous func as normal. We haven't actually checked, but + // since this pc was included in the stack, we know it shouldn't be + // elided. + calleeID := abi.FuncIDNormal + + // Remove pc from stk; we'll re-add it below. + stk = stk[:len(stk)-1] + + for ; uf.valid(); uf = u.next(uf) { + funcID := u.srcFunc(uf).funcID + if funcID == abi.FuncIDWrapper && elideWrapperCalling(calleeID) { + // ignore wrappers + } else { + stk = append(stk, uf.pc+1) + } + calleeID = funcID + } + + return stk +} + +// expandCgoFrames expands frame information for pc, known to be +// a non-Go function, using the cgoSymbolizer hook. expandCgoFrames +// returns nil if pc could not be expanded. +func expandCgoFrames(pc uintptr) []Frame { + arg := cgoSymbolizerArg{pc: pc} + callCgoSymbolizer(&arg) + + if arg.file == nil && arg.funcName == nil { + // No useful information from symbolizer. + return nil + } + + var frames []Frame + for { + frames = append(frames, Frame{ + PC: pc, + Func: nil, + Function: gostring(arg.funcName), + File: gostring(arg.file), + Line: int(arg.lineno), + Entry: arg.entry, + // funcInfo is zero, which implies !funcInfo.valid(). + // That ensures that we use the File/Line info given here. + }) + if arg.more == 0 { + break + } + callCgoSymbolizer(&arg) + } + + // No more frames for this PC. Tell the symbolizer we are done. + // We don't try to maintain a single cgoSymbolizerArg for the + // whole use of Frames, because there would be no good way to tell + // the symbolizer when we are done. + arg.pc = 0 + callCgoSymbolizer(&arg) + + return frames +} + +// NOTE: Func does not expose the actual unexported fields, because we return *Func +// values to users, and we want to keep them from being able to overwrite the data +// with (say) *f = Func{}. +// All code operating on a *Func must call raw() to get the *_func +// or funcInfo() to get the funcInfo instead. + +// A Func represents a Go function in the running binary. +type Func struct { + opaque struct{} // unexported field to disallow conversions +} + +func (f *Func) raw() *_func { + return (*_func)(unsafe.Pointer(f)) +} + +func (f *Func) funcInfo() funcInfo { + return f.raw().funcInfo() +} + +func (f *_func) funcInfo() funcInfo { + // Find the module containing fn. fn is located in the pclntable. + // The unsafe.Pointer to uintptr conversions and arithmetic + // are safe because we are working with module addresses. + ptr := uintptr(unsafe.Pointer(f)) + var mod *moduledata + for datap := &firstmoduledata; datap != nil; datap = datap.next { + if len(datap.pclntable) == 0 { + continue + } + base := uintptr(unsafe.Pointer(&datap.pclntable[0])) + if base <= ptr && ptr < base+uintptr(len(datap.pclntable)) { + mod = datap + break + } + } + return funcInfo{f, mod} +} + +// pcHeader holds data used by the pclntab lookups. +type pcHeader struct { + magic uint32 // 0xFFFFFFF1 + pad1, pad2 uint8 // 0,0 + minLC uint8 // min instruction size + ptrSize uint8 // size of a ptr in bytes + nfunc int // number of functions in the module + nfiles uint // number of entries in the file tab + textStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text + funcnameOffset uintptr // offset to the funcnametab variable from pcHeader + cuOffset uintptr // offset to the cutab variable from pcHeader + filetabOffset uintptr // offset to the filetab variable from pcHeader + pctabOffset uintptr // offset to the pctab variable from pcHeader + pclnOffset uintptr // offset to the pclntab variable from pcHeader +} + +// moduledata records information about the layout of the executable +// image. It is written by the linker. Any changes here must be +// matched changes to the code in cmd/link/internal/ld/symtab.go:symtab. +// moduledata is stored in statically allocated non-pointer memory; +// none of the pointers here are visible to the garbage collector. +type moduledata struct { + sys.NotInHeap // Only in static data + + pcHeader *pcHeader + funcnametab []byte + cutab []uint32 + filetab []byte + pctab []byte + pclntable []byte + ftab []functab + findfunctab uintptr + minpc, maxpc uintptr + + text, etext uintptr + noptrdata, enoptrdata uintptr + data, edata uintptr + bss, ebss uintptr + noptrbss, enoptrbss uintptr + covctrs, ecovctrs uintptr + end, gcdata, gcbss uintptr + types, etypes uintptr + rodata uintptr + gofunc uintptr // go.func.* + + textsectmap []textsect + typelinks []int32 // offsets from types + itablinks []*itab + + ptab []ptabEntry + + pluginpath string + pkghashes []modulehash + + // This slice records the initializing tasks that need to be + // done to start up the program. It is built by the linker. + inittasks []*initTask + + modulename string + modulehashes []modulehash + + hasmain uint8 // 1 if module contains the main function, 0 otherwise + bad bool // module failed to load and should be ignored + + gcdatamask, gcbssmask bitvector + + typemap map[typeOff]*_type // offset to *_rtype in previous module + + next *moduledata +} + +// A modulehash is used to compare the ABI of a new module or a +// package in a new module with the loaded program. +// +// For each shared library a module links against, the linker creates an entry in the +// moduledata.modulehashes slice containing the name of the module, the abi hash seen +// at link time and a pointer to the runtime abi hash. These are checked in +// moduledataverify1 below. +// +// For each loaded plugin, the pkghashes slice has a modulehash of the +// newly loaded package that can be used to check the plugin's version of +// a package against any previously loaded version of the package. +// This is done in plugin.lastmoduleinit. +type modulehash struct { + modulename string + linktimehash string + runtimehash *string +} + +// pinnedTypemaps are the map[typeOff]*_type from the moduledata objects. +// +// These typemap objects are allocated at run time on the heap, but the +// only direct reference to them is in the moduledata, created by the +// linker and marked SNOPTRDATA so it is ignored by the GC. +// +// To make sure the map isn't collected, we keep a second reference here. +var pinnedTypemaps []map[typeOff]*_type + +var firstmoduledata moduledata // linker symbol + +// lastmoduledatap should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname lastmoduledatap +var lastmoduledatap *moduledata // linker symbol + +var modulesSlice *[]*moduledata // see activeModules + +// activeModules returns a slice of active modules. +// +// A module is active once its gcdatamask and gcbssmask have been +// assembled and it is usable by the GC. +// +// This is nosplit/nowritebarrier because it is called by the +// cgo pointer checking code. +// +//go:nosplit +//go:nowritebarrier +func activeModules() []*moduledata { + p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice))) + if p == nil { + return nil + } + return *p +} + +// modulesinit creates the active modules slice out of all loaded modules. +// +// When a module is first loaded by the dynamic linker, an .init_array +// function (written by cmd/link) is invoked to call addmoduledata, +// appending to the module to the linked list that starts with +// firstmoduledata. +// +// There are two times this can happen in the lifecycle of a Go +// program. First, if compiled with -linkshared, a number of modules +// built with -buildmode=shared can be loaded at program initialization. +// Second, a Go program can load a module while running that was built +// with -buildmode=plugin. +// +// After loading, this function is called which initializes the +// moduledata so it is usable by the GC and creates a new activeModules +// list. +// +// Only one goroutine may call modulesinit at a time. +func modulesinit() { + modules := new([]*moduledata) + for md := &firstmoduledata; md != nil; md = md.next { + if md.bad { + continue + } + *modules = append(*modules, md) + if md.gcdatamask == (bitvector{}) { + scanDataSize := md.edata - md.data + md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), scanDataSize) + scanBSSSize := md.ebss - md.bss + md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), scanBSSSize) + gcController.addGlobals(int64(scanDataSize + scanBSSSize)) + } + } + + // Modules appear in the moduledata linked list in the order they are + // loaded by the dynamic loader, with one exception: the + // firstmoduledata itself the module that contains the runtime. This + // is not always the first module (when using -buildmode=shared, it + // is typically libstd.so, the second module). The order matters for + // typelinksinit, so we swap the first module with whatever module + // contains the main function. + // + // See Issue #18729. + for i, md := range *modules { + if md.hasmain != 0 { + (*modules)[0] = md + (*modules)[i] = &firstmoduledata + break + } + } + + atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules)) +} + +type functab struct { + entryoff uint32 // relative to runtime.text + funcoff uint32 +} + +// Mapping information for secondary text sections + +type textsect struct { + vaddr uintptr // prelinked section vaddr + end uintptr // vaddr + section length + baseaddr uintptr // relocated section address +} + +// findfuncbucket is an array of these structures. +// Each bucket represents 4096 bytes of the text segment. +// Each subbucket represents 256 bytes of the text segment. +// To find a function given a pc, locate the bucket and subbucket for +// that pc. Add together the idx and subbucket value to obtain a +// function index. Then scan the functab array starting at that +// index to find the target function. +// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead. +type findfuncbucket struct { + idx uint32 + subbuckets [16]byte +} + +func moduledataverify() { + for datap := &firstmoduledata; datap != nil; datap = datap.next { + moduledataverify1(datap) + } +} + +const debugPcln = false + +// moduledataverify1 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname moduledataverify1 +func moduledataverify1(datap *moduledata) { + // Check that the pclntab's format is valid. + hdr := datap.pcHeader + if hdr.magic != 0xfffffff1 || hdr.pad1 != 0 || hdr.pad2 != 0 || + hdr.minLC != sys.PCQuantum || hdr.ptrSize != goarch.PtrSize || hdr.textStart != datap.text { + println("runtime: pcHeader: magic=", hex(hdr.magic), "pad1=", hdr.pad1, "pad2=", hdr.pad2, + "minLC=", hdr.minLC, "ptrSize=", hdr.ptrSize, "pcHeader.textStart=", hex(hdr.textStart), + "text=", hex(datap.text), "pluginpath=", datap.pluginpath) + throw("invalid function symbol table") + } + + // ftab is lookup table for function by program counter. + nftab := len(datap.ftab) - 1 + for i := 0; i < nftab; i++ { + // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function. + if datap.ftab[i].entryoff > datap.ftab[i+1].entryoff { + f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap} + f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap} + f2name := "end" + if i+1 < nftab { + f2name = funcname(f2) + } + println("function symbol table not sorted by PC offset:", hex(datap.ftab[i].entryoff), funcname(f1), ">", hex(datap.ftab[i+1].entryoff), f2name, ", plugin:", datap.pluginpath) + for j := 0; j <= i; j++ { + println("\t", hex(datap.ftab[j].entryoff), funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap})) + } + if GOOS == "aix" && isarchive { + println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive") + } + throw("invalid runtime symbol table") + } + } + + min := datap.textAddr(datap.ftab[0].entryoff) + max := datap.textAddr(datap.ftab[nftab].entryoff) + if datap.minpc != min || datap.maxpc != max { + println("minpc=", hex(datap.minpc), "min=", hex(min), "maxpc=", hex(datap.maxpc), "max=", hex(max)) + throw("minpc or maxpc invalid") + } + + for _, modulehash := range datap.modulehashes { + if modulehash.linktimehash != *modulehash.runtimehash { + println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename) + throw("abi mismatch") + } + } +} + +// textAddr returns md.text + off, with special handling for multiple text sections. +// off is a (virtual) offset computed at internal linking time, +// before the external linker adjusts the sections' base addresses. +// +// The text, or instruction stream is generated as one large buffer. +// The off (offset) for a function is its offset within this buffer. +// If the total text size gets too large, there can be issues on platforms like ppc64 +// if the target of calls are too far for the call instruction. +// To resolve the large text issue, the text is split into multiple text sections +// to allow the linker to generate long calls when necessary. +// When this happens, the vaddr for each text section is set to its offset within the text. +// Each function's offset is compared against the section vaddrs and ends to determine the containing section. +// Then the section relative offset is added to the section's +// relocated baseaddr to compute the function address. +// +// It is nosplit because it is part of the findfunc implementation. +// +//go:nosplit +func (md *moduledata) textAddr(off32 uint32) uintptr { + off := uintptr(off32) + res := md.text + off + if len(md.textsectmap) > 1 { + for i, sect := range md.textsectmap { + // For the last section, include the end address (etext), as it is included in the functab. + if off >= sect.vaddr && off < sect.end || (i == len(md.textsectmap)-1 && off == sect.end) { + res = sect.baseaddr + off - sect.vaddr + break + } + } + if res > md.etext && GOARCH != "wasm" { // on wasm, functions do not live in the same address space as the linear memory + println("runtime: textAddr", hex(res), "out of range", hex(md.text), "-", hex(md.etext)) + throw("runtime: text offset out of range") + } + } + return res +} + +// textOff is the opposite of textAddr. It converts a PC to a (virtual) offset +// to md.text, and returns if the PC is in any Go text section. +// +// It is nosplit because it is part of the findfunc implementation. +// +//go:nosplit +func (md *moduledata) textOff(pc uintptr) (uint32, bool) { + res := uint32(pc - md.text) + if len(md.textsectmap) > 1 { + for i, sect := range md.textsectmap { + if sect.baseaddr > pc { + // pc is not in any section. + return 0, false + } + end := sect.baseaddr + (sect.end - sect.vaddr) + // For the last section, include the end address (etext), as it is included in the functab. + if i == len(md.textsectmap)-1 { + end++ + } + if pc < end { + res = uint32(pc - sect.baseaddr + sect.vaddr) + break + } + } + } + return res, true +} + +// funcName returns the string at nameOff in the function name table. +func (md *moduledata) funcName(nameOff int32) string { + if nameOff == 0 { + return "" + } + return gostringnocopy(&md.funcnametab[nameOff]) +} + +// FuncForPC returns a *[Func] describing the function that contains the +// given program counter address, or else nil. +// +// If pc represents multiple functions because of inlining, it returns +// the *Func describing the innermost function, but with an entry of +// the outermost function. +// +// For completely unclear reasons, even though they can import runtime, +// some widely used packages access this using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname FuncForPC +func FuncForPC(pc uintptr) *Func { + f := findfunc(pc) + if !f.valid() { + return nil + } + // This must interpret PC non-strictly so bad PCs (those between functions) don't crash the runtime. + // We just report the preceding function in that situation. See issue 29735. + // TODO: Perhaps we should report no function at all in that case. + // The runtime currently doesn't have function end info, alas. + u, uf := newInlineUnwinder(f, pc) + if !u.isInlined(uf) { + return f._Func() + } + sf := u.srcFunc(uf) + file, line := u.fileLine(uf) + fi := &funcinl{ + ones: ^uint32(0), + entry: f.entry(), // entry of the real (the outermost) function. + name: sf.name(), + file: file, + line: int32(line), + startLine: sf.startLine, + } + return (*Func)(unsafe.Pointer(fi)) +} + +// Name returns the name of the function. +func (f *Func) Name() string { + if f == nil { + return "" + } + fn := f.raw() + if fn.isInlined() { // inlined version + fi := (*funcinl)(unsafe.Pointer(fn)) + return funcNameForPrint(fi.name) + } + return funcNameForPrint(funcname(f.funcInfo())) +} + +// Entry returns the entry address of the function. +func (f *Func) Entry() uintptr { + fn := f.raw() + if fn.isInlined() { // inlined version + fi := (*funcinl)(unsafe.Pointer(fn)) + return fi.entry + } + return fn.funcInfo().entry() +} + +// FileLine returns the file name and line number of the +// source code corresponding to the program counter pc. +// The result will not be accurate if pc is not a program +// counter within f. +func (f *Func) FileLine(pc uintptr) (file string, line int) { + fn := f.raw() + if fn.isInlined() { // inlined version + fi := (*funcinl)(unsafe.Pointer(fn)) + return fi.file, int(fi.line) + } + // Pass strict=false here, because anyone can call this function, + // and they might just be wrong about targetpc belonging to f. + file, line32 := funcline1(f.funcInfo(), pc, false) + return file, int(line32) +} + +// startLine returns the starting line number of the function. i.e., the line +// number of the func keyword. +func (f *Func) startLine() int32 { + fn := f.raw() + if fn.isInlined() { // inlined version + fi := (*funcinl)(unsafe.Pointer(fn)) + return fi.startLine + } + return fn.funcInfo().startLine +} + +// findmoduledatap looks up the moduledata for a PC. +// +// It is nosplit because it's part of the isgoexception +// implementation. +// +//go:nosplit +func findmoduledatap(pc uintptr) *moduledata { + for datap := &firstmoduledata; datap != nil; datap = datap.next { + if datap.minpc <= pc && pc < datap.maxpc { + return datap + } + } + return nil +} + +type funcInfo struct { + *_func + datap *moduledata +} + +func (f funcInfo) valid() bool { + return f._func != nil +} + +func (f funcInfo) _Func() *Func { + return (*Func)(unsafe.Pointer(f._func)) +} + +// isInlined reports whether f should be re-interpreted as a *funcinl. +func (f *_func) isInlined() bool { + return f.entryOff == ^uint32(0) // see comment for funcinl.ones +} + +// entry returns the entry PC for f. +// +// entry should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +func (f funcInfo) entry() uintptr { + return f.datap.textAddr(f.entryOff) +} + +//go:linkname badFuncInfoEntry runtime.funcInfo.entry +func badFuncInfoEntry(funcInfo) uintptr + +// findfunc looks up function metadata for a PC. +// +// It is nosplit because it's part of the isgoexception +// implementation. +// +// findfunc should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:nosplit +//go:linkname findfunc +func findfunc(pc uintptr) funcInfo { + datap := findmoduledatap(pc) + if datap == nil { + return funcInfo{} + } + const nsub = uintptr(len(findfuncbucket{}.subbuckets)) + + pcOff, ok := datap.textOff(pc) + if !ok { + return funcInfo{} + } + + x := uintptr(pcOff) + datap.text - datap.minpc // TODO: are datap.text and datap.minpc always equal? + b := x / abi.FuncTabBucketSize + i := x % abi.FuncTabBucketSize / (abi.FuncTabBucketSize / nsub) + + ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{}))) + idx := ffb.idx + uint32(ffb.subbuckets[i]) + + // Find the ftab entry. + for datap.ftab[idx+1].entryoff <= pcOff { + idx++ + } + + funcoff := datap.ftab[idx].funcoff + return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap} +} + +// A srcFunc represents a logical function in the source code. This may +// correspond to an actual symbol in the binary text, or it may correspond to a +// source function that has been inlined. +type srcFunc struct { + datap *moduledata + nameOff int32 + startLine int32 + funcID abi.FuncID +} + +func (f funcInfo) srcFunc() srcFunc { + if !f.valid() { + return srcFunc{} + } + return srcFunc{f.datap, f.nameOff, f.startLine, f.funcID} +} + +// name should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +func (s srcFunc) name() string { + if s.datap == nil { + return "" + } + return s.datap.funcName(s.nameOff) +} + +//go:linkname badSrcFuncName runtime.srcFunc.name +func badSrcFuncName(srcFunc) string + +type pcvalueCache struct { + entries [2][8]pcvalueCacheEnt + inUse int +} + +type pcvalueCacheEnt struct { + // targetpc and off together are the key of this cache entry. + targetpc uintptr + off uint32 + + val int32 // The value of this entry. + valPC uintptr // The PC at which val starts +} + +// pcvalueCacheKey returns the outermost index in a pcvalueCache to use for targetpc. +// It must be very cheap to calculate. +// For now, align to goarch.PtrSize and reduce mod the number of entries. +// In practice, this appears to be fairly randomly and evenly distributed. +func pcvalueCacheKey(targetpc uintptr) uintptr { + return (targetpc / goarch.PtrSize) % uintptr(len(pcvalueCache{}.entries)) +} + +// Returns the PCData value, and the PC where this value starts. +func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uintptr) { + // If true, when we get a cache hit, still look up the data and make sure it + // matches the cached contents. + const debugCheckCache = false + + if off == 0 { + return -1, 0 + } + + // Check the cache. This speeds up walks of deep stacks, which + // tend to have the same recursive functions over and over, + // or repetitive stacks between goroutines. + var checkVal int32 + var checkPC uintptr + ck := pcvalueCacheKey(targetpc) + { + mp := acquirem() + cache := &mp.pcvalueCache + // The cache can be used by the signal handler on this M. Avoid + // re-entrant use of the cache. The signal handler can also write inUse, + // but will always restore its value, so we can use a regular increment + // even if we get signaled in the middle of it. + cache.inUse++ + if cache.inUse == 1 { + for i := range cache.entries[ck] { + // We check off first because we're more + // likely to have multiple entries with + // different offsets for the same targetpc + // than the other way around, so we'll usually + // fail in the first clause. + ent := &cache.entries[ck][i] + if ent.off == off && ent.targetpc == targetpc { + val, pc := ent.val, ent.valPC + if debugCheckCache { + checkVal, checkPC = ent.val, ent.valPC + break + } else { + cache.inUse-- + releasem(mp) + return val, pc + } + } + } + } else if debugCheckCache && (cache.inUse < 1 || cache.inUse > 2) { + // Catch accounting errors or deeply reentrant use. In principle + // "inUse" should never exceed 2. + throw("cache.inUse out of range") + } + cache.inUse-- + releasem(mp) + } + + if !f.valid() { + if strict && panicking.Load() == 0 { + println("runtime: no module data for", hex(f.entry())) + throw("no module data") + } + return -1, 0 + } + datap := f.datap + p := datap.pctab[off:] + pc := f.entry() + prevpc := pc + val := int32(-1) + for { + var ok bool + p, ok = step(p, &pc, &val, pc == f.entry()) + if !ok { + break + } + if targetpc < pc { + // Replace a random entry in the cache. Random + // replacement prevents a performance cliff if + // a recursive stack's cycle is slightly + // larger than the cache. + // Put the new element at the beginning, + // since it is the most likely to be newly used. + if debugCheckCache && checkPC != 0 { + if checkVal != val || checkPC != prevpc { + print("runtime: table value ", val, "@", prevpc, " != cache value ", checkVal, "@", checkPC, " at PC ", targetpc, " off ", off, "\n") + throw("bad pcvalue cache") + } + } else { + mp := acquirem() + cache := &mp.pcvalueCache + cache.inUse++ + if cache.inUse == 1 { + e := &cache.entries[ck] + ci := cheaprandn(uint32(len(cache.entries[ck]))) + e[ci] = e[0] + e[0] = pcvalueCacheEnt{ + targetpc: targetpc, + off: off, + val: val, + valPC: prevpc, + } + } + cache.inUse-- + releasem(mp) + } + + return val, prevpc + } + prevpc = pc + } + + // If there was a table, it should have covered all program counters. + // If not, something is wrong. + if panicking.Load() != 0 || !strict { + return -1, 0 + } + + print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n") + + p = datap.pctab[off:] + pc = f.entry() + val = -1 + for { + var ok bool + p, ok = step(p, &pc, &val, pc == f.entry()) + if !ok { + break + } + print("\tvalue=", val, " until pc=", hex(pc), "\n") + } + + throw("invalid runtime symbol table") + return -1, 0 +} + +func funcname(f funcInfo) string { + if !f.valid() { + return "" + } + return f.datap.funcName(f.nameOff) +} + +func funcpkgpath(f funcInfo) string { + name := funcNameForPrint(funcname(f)) + i := len(name) - 1 + for ; i > 0; i-- { + if name[i] == '/' { + break + } + } + for ; i < len(name); i++ { + if name[i] == '.' { + break + } + } + return name[:i] +} + +func funcfile(f funcInfo, fileno int32) string { + datap := f.datap + if !f.valid() { + return "?" + } + // Make sure the cu index and file offset are valid + if fileoff := datap.cutab[f.cuOffset+uint32(fileno)]; fileoff != ^uint32(0) { + return gostringnocopy(&datap.filetab[fileoff]) + } + // pcln section is corrupt. + return "?" +} + +// funcline1 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname funcline1 +func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) { + datap := f.datap + if !f.valid() { + return "?", 0 + } + fileno, _ := pcvalue(f, f.pcfile, targetpc, strict) + line, _ = pcvalue(f, f.pcln, targetpc, strict) + if fileno == -1 || line == -1 || int(fileno) >= len(datap.filetab) { + // print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n") + return "?", 0 + } + file = funcfile(f, fileno) + return +} + +func funcline(f funcInfo, targetpc uintptr) (file string, line int32) { + return funcline1(f, targetpc, true) +} + +func funcspdelta(f funcInfo, targetpc uintptr) int32 { + x, _ := pcvalue(f, f.pcsp, targetpc, true) + if debugPcln && x&(goarch.PtrSize-1) != 0 { + print("invalid spdelta ", funcname(f), " ", hex(f.entry()), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n") + throw("bad spdelta") + } + return x +} + +// funcMaxSPDelta returns the maximum spdelta at any point in f. +func funcMaxSPDelta(f funcInfo) int32 { + datap := f.datap + p := datap.pctab[f.pcsp:] + pc := f.entry() + val := int32(-1) + most := int32(0) + for { + var ok bool + p, ok = step(p, &pc, &val, pc == f.entry()) + if !ok { + return most + } + most = max(most, val) + } +} + +func pcdatastart(f funcInfo, table uint32) uint32 { + return *(*uint32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4)) +} + +func pcdatavalue(f funcInfo, table uint32, targetpc uintptr) int32 { + if table >= f.npcdata { + return -1 + } + r, _ := pcvalue(f, pcdatastart(f, table), targetpc, true) + return r +} + +func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, strict bool) int32 { + if table >= f.npcdata { + return -1 + } + r, _ := pcvalue(f, pcdatastart(f, table), targetpc, strict) + return r +} + +// Like pcdatavalue, but also return the start PC of this PCData value. +// +// pcdatavalue2 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname pcdatavalue2 +func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) { + if table >= f.npcdata { + return -1, 0 + } + return pcvalue(f, pcdatastart(f, table), targetpc, true) +} + +// funcdata returns a pointer to the ith funcdata for f. +// funcdata should be kept in sync with cmd/link:writeFuncs. +func funcdata(f funcInfo, i uint8) unsafe.Pointer { + if i < 0 || i >= f.nfuncdata { + return nil + } + base := f.datap.gofunc // load gofunc address early so that we calculate during cache misses + p := uintptr(unsafe.Pointer(&f.nfuncdata)) + unsafe.Sizeof(f.nfuncdata) + uintptr(f.npcdata)*4 + uintptr(i)*4 + off := *(*uint32)(unsafe.Pointer(p)) + // Return off == ^uint32(0) ? 0 : f.datap.gofunc + uintptr(off), but without branches. + // The compiler calculates mask on most architectures using conditional assignment. + var mask uintptr + if off == ^uint32(0) { + mask = 1 + } + mask-- + raw := base + uintptr(off) + return unsafe.Pointer(raw & mask) +} + +// step advances to the next pc, value pair in the encoded table. +// +// step should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname step +func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) { + // For both uvdelta and pcdelta, the common case (~70%) + // is that they are a single byte. If so, avoid calling readvarint. + uvdelta := uint32(p[0]) + if uvdelta == 0 && !first { + return nil, false + } + n := uint32(1) + if uvdelta&0x80 != 0 { + n, uvdelta = readvarint(p) + } + *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1)) + p = p[n:] + + pcdelta := uint32(p[0]) + n = 1 + if pcdelta&0x80 != 0 { + n, pcdelta = readvarint(p) + } + p = p[n:] + *pc += uintptr(pcdelta * sys.PCQuantum) + return p, true +} + +// readvarint reads a varint from p. +func readvarint(p []byte) (read uint32, val uint32) { + var v, shift, n uint32 + for { + b := p[n] + n++ + v |= uint32(b&0x7F) << (shift & 31) + if b&0x80 == 0 { + break + } + shift += 7 + } + return n, v +} + +type stackmap struct { + n int32 // number of bitmaps + nbit int32 // number of bits in each bitmap + bytedata [1]byte // bitmaps, each starting on a byte boundary +} + +// stackmapdata should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname stackmapdata +//go:nowritebarrier +func stackmapdata(stkmap *stackmap, n int32) bitvector { + // Check this invariant only when stackDebug is on at all. + // The invariant is already checked by many of stackmapdata's callers, + // and disabling it by default allows stackmapdata to be inlined. + if stackDebug > 0 && (n < 0 || n >= stkmap.n) { + throw("stackmapdata: index out of range") + } + return bitvector{stkmap.nbit, addb(&stkmap.bytedata[0], uintptr(n*((stkmap.nbit+7)>>3)))} +} diff --git a/contrib/go/_std_1.22/src/runtime/symtabinl.go b/contrib/go/_std_1.23/src/runtime/symtabinl.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/symtabinl.go rename to contrib/go/_std_1.23/src/runtime/symtabinl.go index 9273b49b11e5..faa01decb9f7 100644 --- a/contrib/go/_std_1.22/src/runtime/symtabinl.go +++ b/contrib/go/_std_1.23/src/runtime/symtabinl.go @@ -4,7 +4,10 @@ package runtime -import "internal/abi" +import ( + "internal/abi" + _ "unsafe" // for linkname +) // inlinedCall is the encoding of entries in the FUNCDATA_InlTree table. type inlinedCall struct { @@ -51,6 +54,16 @@ type inlineFrame struct { // This unwinder uses non-strict handling of PC because it's assumed this is // only ever used for symbolic debugging. If things go really wrong, it'll just // fall back to the outermost frame. +// +// newInlineUnwinder should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname newInlineUnwinder func newInlineUnwinder(f funcInfo, pc uintptr) (inlineUnwinder, inlineFrame) { inldata := funcdata(f, abi.FUNCDATA_InlTree) if inldata == nil { @@ -90,6 +103,16 @@ func (u *inlineUnwinder) isInlined(uf inlineFrame) bool { } // srcFunc returns the srcFunc representing the given frame. +// +// srcFunc should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +// The go:linkname is below. func (u *inlineUnwinder) srcFunc(uf inlineFrame) srcFunc { if uf.index < 0 { return u.f.srcFunc() @@ -103,6 +126,9 @@ func (u *inlineUnwinder) srcFunc(uf inlineFrame) srcFunc { } } +//go:linkname badSrcFunc runtime.(*inlineUnwinder).srcFunc +func badSrcFunc(*inlineUnwinder, inlineFrame) srcFunc + // fileLine returns the file name and line number of the call within the given // frame. As a convenience, for the innermost frame, it returns the file and // line of the PC this unwinder was started at (often this is a call to another diff --git a/contrib/go/_std_1.22/src/runtime/sys_aix_ppc64.s b/contrib/go/_std_1.23/src/runtime/sys_aix_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_aix_ppc64.s rename to contrib/go/_std_1.23/src/runtime/sys_aix_ppc64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_arm.go b/contrib/go/_std_1.23/src/runtime/sys_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_arm.go rename to contrib/go/_std_1.23/src/runtime/sys_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_arm64.go b/contrib/go/_std_1.23/src/runtime/sys_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_arm64.go rename to contrib/go/_std_1.23/src/runtime/sys_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_darwin.go b/contrib/go/_std_1.23/src/runtime/sys_darwin.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/sys_darwin.go rename to contrib/go/_std_1.23/src/runtime/sys_darwin.go index 45175d86632a..1e4b2ac79efd 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_darwin.go +++ b/contrib/go/_std_1.23/src/runtime/sys_darwin.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -16,6 +16,10 @@ import ( // and we need to know whether to check 32 or 64 bits of the result. // (Some libc functions that return 32 bits put junk in the upper 32 bits of AX.) +// golang.org/x/sys linknames syscall_syscall +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall syscall.syscall //go:nosplit func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { @@ -38,6 +42,17 @@ func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { } func syscallX() +// golang.org/x/sys linknames syscall.syscall6 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// +// syscall.syscall6 is meant for package syscall (and x/sys), +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/tetratelabs/wazero +// +// See go.dev/issue/67401. +// //go:linkname syscall_syscall6 syscall.syscall6 //go:nosplit func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { @@ -49,6 +64,10 @@ func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) } func syscall6() +// golang.org/x/sys linknames syscall.syscall9 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall9 syscall.syscall9 //go:nosplit //go:cgo_unsafe_args @@ -71,6 +90,10 @@ func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) } func syscall6X() +// golang.org/x/sys linknames syscall.syscallPtr +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscallPtr syscall.syscallPtr //go:nosplit func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { @@ -82,6 +105,10 @@ func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { } func syscallPtr() +// golang.org/x/sys linknames syscall_rawSyscall +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_rawSyscall syscall.rawSyscall //go:nosplit func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { @@ -90,6 +117,10 @@ func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { return args.r1, args.r2, args.err } +// golang.org/x/sys linknames syscall_rawSyscall6 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_rawSyscall6 syscall.rawSyscall6 //go:nosplit func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { @@ -349,6 +380,15 @@ func nanotime1() int64 { } func nanotime_trampoline() +// walltime should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname walltime //go:nosplit //go:cgo_unsafe_args func walltime() (int64, int32) { diff --git a/contrib/go/_std_1.22/src/runtime/sys_darwin_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_darwin_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_darwin_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_darwin_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/sys_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/sys_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_darwin_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_darwin_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_darwin_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_darwin_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_dragonfly_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_dragonfly_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_dragonfly_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_dragonfly_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_386.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_386.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_arm.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_riscv64.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_riscv64.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_libc.go b/contrib/go/_std_1.23/src/runtime/sys_libc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_libc.go rename to contrib/go/_std_1.23/src/runtime/sys_libc.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_386.s b/contrib/go/_std_1.23/src/runtime/sys_linux_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_386.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_arm.s b/contrib/go/_std_1.23/src/runtime/sys_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_linux_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_loong64.s b/contrib/go/_std_1.23/src/runtime/sys_linux_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_loong64.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_mips64x.s b/contrib/go/_std_1.23/src/runtime/sys_linux_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_mips64x.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_mipsx.s b/contrib/go/_std_1.23/src/runtime/sys_linux_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_mipsx.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_ppc64x.s b/contrib/go/_std_1.23/src/runtime/sys_linux_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sys_linux_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_ppc64x.s index d105585b7e88..ba4988b72332 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_linux_ppc64x.s +++ b/contrib/go/_std_1.23/src/runtime/sys_linux_ppc64x.s @@ -211,7 +211,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$16-12 MOVD $0, R3 // CLOCK_REALTIME MOVD runtime·vdsoClockgettimeSym(SB), R12 // Check for VDSO availability - CMP R12, R0 + CMP R12, $0 BEQ fallback // Set vdsoPC and vdsoSP for SIGPROF traceback. @@ -305,7 +305,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$16-8 MOVD g_m(g), R21 // R21 = m MOVD runtime·vdsoClockgettimeSym(SB), R12 // Check for VDSO availability - CMP R12, R0 + CMP R12, $0 BEQ fallback // Set vdsoPC and vdsoSP for SIGPROF traceback. diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_riscv64.s b/contrib/go/_std_1.23/src/runtime/sys_linux_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_riscv64.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_s390x.s b/contrib/go/_std_1.23/src/runtime/sys_linux_s390x.s similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sys_linux_s390x.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_s390x.s index adf5612c3cfb..59e2f2ab31f2 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_linux_s390x.s +++ b/contrib/go/_std_1.23/src/runtime/sys_linux_s390x.s @@ -112,9 +112,10 @@ TEXT runtime·usleep(SB),NOSPLIT,$16-4 MOVW $1000000, R3 DIVD R3, R2 MOVD R2, 8(R15) - MOVW $1000, R3 - MULLD R2, R3 + MULLD R2, R3 // Convert sec to usec and subtract SUB R3, R4 + MOVW $1000, R3 + MULLD R3, R4 // Convert remaining usec into nsec. MOVD R4, 16(R15) // nanosleep(&ts, 0) diff --git a/contrib/go/_std_1.22/src/runtime/sys_loong64.go b/contrib/go/_std_1.23/src/runtime/sys_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_loong64.go rename to contrib/go/_std_1.23/src/runtime/sys_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_mips64x.go b/contrib/go/_std_1.23/src/runtime/sys_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_mips64x.go rename to contrib/go/_std_1.23/src/runtime/sys_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_mipsx.go b/contrib/go/_std_1.23/src/runtime/sys_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_mipsx.go rename to contrib/go/_std_1.23/src/runtime/sys_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_netbsd_386.s b/contrib/go/_std_1.23/src/runtime/sys_netbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_netbsd_386.s rename to contrib/go/_std_1.23/src/runtime/sys_netbsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_netbsd_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_netbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_netbsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_netbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_netbsd_arm.s b/contrib/go/_std_1.23/src/runtime/sys_netbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_netbsd_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_netbsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_netbsd_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_netbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_netbsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_netbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_nonppc64x.go b/contrib/go/_std_1.23/src/runtime/sys_nonppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_nonppc64x.go rename to contrib/go/_std_1.23/src/runtime/sys_nonppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd.go b/contrib/go/_std_1.23/src/runtime/sys_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd.go rename to contrib/go/_std_1.23/src/runtime/sys_openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd1.go b/contrib/go/_std_1.23/src/runtime/sys_openbsd1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd1.go rename to contrib/go/_std_1.23/src/runtime/sys_openbsd1.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd2.go b/contrib/go/_std_1.23/src/runtime/sys_openbsd2.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd2.go rename to contrib/go/_std_1.23/src/runtime/sys_openbsd2.go index b38e49ee6f59..8f5242018dd0 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_openbsd2.go +++ b/contrib/go/_std_1.23/src/runtime/sys_openbsd2.go @@ -8,7 +8,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd3.go b/contrib/go/_std_1.23/src/runtime/sys_openbsd3.go similarity index 82% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd3.go rename to contrib/go/_std_1.23/src/runtime/sys_openbsd3.go index 269bf86f10de..de09ec5e2581 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_openbsd3.go +++ b/contrib/go/_std_1.23/src/runtime/sys_openbsd3.go @@ -17,6 +17,10 @@ import ( // and we need to know whether to check 32 or 64 bits of the result. // (Some libc functions that return 32 bits put junk in the upper 32 bits of AX.) +// golang.org/x/sys linknames syscall_syscall +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall syscall.syscall //go:nosplit //go:cgo_unsafe_args @@ -39,6 +43,10 @@ func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { } func syscallX() +// golang.org/x/sys linknames syscall.syscall6 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall6 syscall.syscall6 //go:nosplit //go:cgo_unsafe_args @@ -61,6 +69,10 @@ func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) } func syscall6X() +// golang.org/x/sys linknames syscall.syscall10 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall10 syscall.syscall10 //go:nosplit //go:cgo_unsafe_args @@ -83,6 +95,10 @@ func syscall_syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1 } func syscall10X() +// golang.org/x/sys linknames syscall_rawSyscall +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_rawSyscall syscall.rawSyscall //go:nosplit //go:cgo_unsafe_args @@ -91,6 +107,10 @@ func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { return } +// golang.org/x/sys linknames syscall_rawSyscall6 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_rawSyscall6 syscall.rawSyscall6 //go:nosplit //go:cgo_unsafe_args diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_386.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_386.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_arm.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_mips64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_mips64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_mips64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_mips64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_ppc64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_ppc64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_ppc64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_riscv64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_riscv64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_plan9_386.s b/contrib/go/_std_1.23/src/runtime/sys_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_plan9_386.s rename to contrib/go/_std_1.23/src/runtime/sys_plan9_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_plan9_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_plan9_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_plan9_arm.s b/contrib/go/_std_1.23/src/runtime/sys_plan9_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_plan9_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_plan9_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_ppc64x.go b/contrib/go/_std_1.23/src/runtime/sys_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/sys_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_riscv64.go b/contrib/go/_std_1.23/src/runtime/sys_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_riscv64.go rename to contrib/go/_std_1.23/src/runtime/sys_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_s390x.go b/contrib/go/_std_1.23/src/runtime/sys_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_s390x.go rename to contrib/go/_std_1.23/src/runtime/sys_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_solaris_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_solaris_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_solaris_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_solaris_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_wasm.go b/contrib/go/_std_1.23/src/runtime/sys_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_wasm.go rename to contrib/go/_std_1.23/src/runtime/sys_wasm.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_wasm.s b/contrib/go/_std_1.23/src/runtime/sys_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_wasm.s rename to contrib/go/_std_1.23/src/runtime/sys_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_windows_386.s b/contrib/go/_std_1.23/src/runtime/sys_windows_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_windows_386.s rename to contrib/go/_std_1.23/src/runtime/sys_windows_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_windows_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_windows_amd64.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/sys_windows_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_windows_amd64.s index c1b78e39769e..56a2dc0bcf24 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_windows_amd64.s +++ b/contrib/go/_std_1.23/src/runtime/sys_windows_amd64.s @@ -33,14 +33,12 @@ TEXT runtime·asmstdcall(SB),NOSPLIT,$16 SUBQ $(const_maxArgs*8), SP // room for args - // Fast version, do not store args on the stack nor - // load them into registers. - CMPL CX, $0 - JE docall - // Fast version, do not store args on the stack. - CMPL CX, $4 - JLE loadregs + CMPL CX, $0; JE _0args + CMPL CX, $1; JE _1args + CMPL CX, $2; JE _2args + CMPL CX, $3; JE _3args + CMPL CX, $4; JE _4args // Check we have enough room for args. CMPL CX, $const_maxArgs @@ -53,22 +51,25 @@ TEXT runtime·asmstdcall(SB),NOSPLIT,$16 REP; MOVSQ MOVQ SP, SI -loadregs: // Load first 4 args into correspondent registers. - MOVQ 0(SI), CX - MOVQ 8(SI), DX - MOVQ 16(SI), R8 - MOVQ 24(SI), R9 // Floating point arguments are passed in the XMM // registers. Set them here in case any of the arguments // are floating point values. For details see // https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170 - MOVQ CX, X0 - MOVQ DX, X1 - MOVQ R8, X2 +_4args: + MOVQ 24(SI), R9 MOVQ R9, X3 +_3args: + MOVQ 16(SI), R8 + MOVQ R8, X2 +_2args: + MOVQ 8(SI), DX + MOVQ DX, X1 +_1args: + MOVQ 0(SI), CX + MOVQ CX, X0 +_0args: -docall: // Call stdcall function. CALL AX diff --git a/contrib/go/_std_1.22/src/runtime/sys_windows_arm.s b/contrib/go/_std_1.23/src/runtime/sys_windows_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_windows_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_windows_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_windows_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_windows_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_windows_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_windows_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_x86.go b/contrib/go/_std_1.23/src/runtime/sys_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_x86.go rename to contrib/go/_std_1.23/src/runtime/sys_x86.go diff --git a/contrib/go/_std_1.22/src/runtime/syscall2_solaris.go b/contrib/go/_std_1.23/src/runtime/syscall2_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/syscall2_solaris.go rename to contrib/go/_std_1.23/src/runtime/syscall2_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/syscall_aix.go b/contrib/go/_std_1.23/src/runtime/syscall_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/syscall_aix.go rename to contrib/go/_std_1.23/src/runtime/syscall_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/syscall_solaris.go b/contrib/go/_std_1.23/src/runtime/syscall_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/syscall_solaris.go rename to contrib/go/_std_1.23/src/runtime/syscall_solaris.go diff --git a/contrib/go/_std_1.23/src/runtime/syscall_windows.go b/contrib/go/_std_1.23/src/runtime/syscall_windows.go new file mode 100644 index 000000000000..85b1b8c9024a --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/syscall_windows.go @@ -0,0 +1,527 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/abi" + "internal/goarch" + "unsafe" +) + +// cbs stores all registered Go callbacks. +var cbs struct { + lock mutex // use cbsLock / cbsUnlock for race instrumentation. + ctxt [cb_max]winCallback + index map[winCallbackKey]int + n int +} + +func cbsLock() { + lock(&cbs.lock) + // compileCallback is used by goenvs prior to completion of schedinit. + // raceacquire involves a racecallback to get the proc, which is not + // safe prior to scheduler initialization. Thus avoid instrumentation + // until then. + if raceenabled && mainStarted { + raceacquire(unsafe.Pointer(&cbs.lock)) + } +} + +func cbsUnlock() { + if raceenabled && mainStarted { + racerelease(unsafe.Pointer(&cbs.lock)) + } + unlock(&cbs.lock) +} + +// winCallback records information about a registered Go callback. +type winCallback struct { + fn *funcval // Go function + retPop uintptr // For 386 cdecl, how many bytes to pop on return + abiMap abiDesc +} + +// abiPartKind is the action an abiPart should take. +type abiPartKind int + +const ( + abiPartBad abiPartKind = iota + abiPartStack // Move a value from memory to the stack. + abiPartReg // Move a value from memory to a register. +) + +// abiPart encodes a step in translating between calling ABIs. +type abiPart struct { + kind abiPartKind + srcStackOffset uintptr + dstStackOffset uintptr // used if kind == abiPartStack + dstRegister int // used if kind == abiPartReg + len uintptr +} + +func (a *abiPart) tryMerge(b abiPart) bool { + if a.kind != abiPartStack || b.kind != abiPartStack { + return false + } + if a.srcStackOffset+a.len == b.srcStackOffset && a.dstStackOffset+a.len == b.dstStackOffset { + a.len += b.len + return true + } + return false +} + +// abiDesc specifies how to translate from a C frame to a Go +// frame. This does not specify how to translate back because +// the result is always a uintptr. If the C ABI is fastcall, +// this assumes the four fastcall registers were first spilled +// to the shadow space. +type abiDesc struct { + parts []abiPart + + srcStackSize uintptr // stdcall/fastcall stack space tracking + dstStackSize uintptr // Go stack space used + dstSpill uintptr // Extra stack space for argument spill slots + dstRegisters int // Go ABI int argument registers used + + // retOffset is the offset of the uintptr-sized result in the Go + // frame. + retOffset uintptr +} + +func (p *abiDesc) assignArg(t *_type) { + if t.Size_ > goarch.PtrSize { + // We don't support this right now. In + // stdcall/cdecl, 64-bit ints and doubles are + // passed as two words (little endian); and + // structs are pushed on the stack. In + // fastcall, arguments larger than the word + // size are passed by reference. On arm, + // 8-byte aligned arguments round up to the + // next even register and can be split across + // registers and the stack. + panic("compileCallback: argument size is larger than uintptr") + } + if k := t.Kind_ & abi.KindMask; GOARCH != "386" && (k == abi.Float32 || k == abi.Float64) { + // In fastcall, floating-point arguments in + // the first four positions are passed in + // floating-point registers, which we don't + // currently spill. arm passes floating-point + // arguments in VFP registers, which we also + // don't support. + // So basically we only support 386. + panic("compileCallback: float arguments not supported") + } + + if t.Size_ == 0 { + // The Go ABI aligns for zero-sized types. + p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_)) + return + } + + // In the C ABI, we're already on a word boundary. + // Also, sub-word-sized fastcall register arguments + // are stored to the least-significant bytes of the + // argument word and all supported Windows + // architectures are little endian, so srcStackOffset + // is already pointing to the right place for smaller + // arguments. The same is true on arm. + + oldParts := p.parts + if p.tryRegAssignArg(t, 0) { + // Account for spill space. + // + // TODO(mknyszek): Remove this when we no longer have + // caller reserved spill space. + p.dstSpill = alignUp(p.dstSpill, uintptr(t.Align_)) + p.dstSpill += t.Size_ + } else { + // Register assignment failed. + // Undo the work and stack assign. + p.parts = oldParts + + // The Go ABI aligns arguments. + p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_)) + + // Copy just the size of the argument. Note that this + // could be a small by-value struct, but C and Go + // struct layouts are compatible, so we can copy these + // directly, too. + part := abiPart{ + kind: abiPartStack, + srcStackOffset: p.srcStackSize, + dstStackOffset: p.dstStackSize, + len: t.Size_, + } + // Add this step to the adapter. + if len(p.parts) == 0 || !p.parts[len(p.parts)-1].tryMerge(part) { + p.parts = append(p.parts, part) + } + // The Go ABI packs arguments. + p.dstStackSize += t.Size_ + } + + // cdecl, stdcall, fastcall, and arm pad arguments to word size. + // TODO(rsc): On arm and arm64 do we need to skip the caller's saved LR? + p.srcStackSize += goarch.PtrSize +} + +// tryRegAssignArg tries to register-assign a value of type t. +// If this type is nested in an aggregate type, then offset is the +// offset of this type within its parent type. +// Assumes t.size <= goarch.PtrSize and t.size != 0. +// +// Returns whether the assignment succeeded. +func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool { + switch k := t.Kind_ & abi.KindMask; k { + case abi.Bool, abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uintptr, abi.Pointer, abi.UnsafePointer: + // Assign a register for all these types. + return p.assignReg(t.Size_, offset) + case abi.Int64, abi.Uint64: + // Only register-assign if the registers are big enough. + if goarch.PtrSize == 8 { + return p.assignReg(t.Size_, offset) + } + case abi.Array: + at := (*arraytype)(unsafe.Pointer(t)) + if at.Len == 1 { + return p.tryRegAssignArg(at.Elem, offset) // TODO fix when runtime is fully commoned up w/ abi.Type + } + case abi.Struct: + st := (*structtype)(unsafe.Pointer(t)) + for i := range st.Fields { + f := &st.Fields[i] + if !p.tryRegAssignArg(f.Typ, offset+f.Offset) { + return false + } + } + return true + } + // Pointer-sized types such as maps and channels are currently + // not supported. + panic("compileCallback: type " + toRType(t).string() + " is currently not supported for use in system callbacks") +} + +// assignReg attempts to assign a single register for an +// argument with the given size, at the given offset into the +// value in the C ABI space. +// +// Returns whether the assignment was successful. +func (p *abiDesc) assignReg(size, offset uintptr) bool { + if p.dstRegisters >= intArgRegs { + return false + } + p.parts = append(p.parts, abiPart{ + kind: abiPartReg, + srcStackOffset: p.srcStackSize + offset, + dstRegister: p.dstRegisters, + len: size, + }) + p.dstRegisters++ + return true +} + +type winCallbackKey struct { + fn *funcval + cdecl bool +} + +func callbackasm() + +// callbackasmAddr returns address of runtime.callbackasm +// function adjusted by i. +// On x86 and amd64, runtime.callbackasm is a series of CALL instructions, +// and we want callback to arrive at +// correspondent call instruction instead of start of +// runtime.callbackasm. +// On ARM, runtime.callbackasm is a series of mov and branch instructions. +// R12 is loaded with the callback index. Each entry is two instructions, +// hence 8 bytes. +func callbackasmAddr(i int) uintptr { + var entrySize int + switch GOARCH { + default: + panic("unsupported architecture") + case "386", "amd64": + entrySize = 5 + case "arm", "arm64": + // On ARM and ARM64, each entry is a MOV instruction + // followed by a branch instruction + entrySize = 8 + } + return abi.FuncPCABI0(callbackasm) + uintptr(i*entrySize) +} + +const callbackMaxFrame = 64 * goarch.PtrSize + +// compileCallback converts a Go function fn into a C function pointer +// that can be passed to Windows APIs. +// +// On 386, if cdecl is true, the returned C function will use the +// cdecl calling convention; otherwise, it will use stdcall. On amd64, +// it always uses fastcall. On arm, it always uses the ARM convention. +// +//go:linkname compileCallback syscall.compileCallback +func compileCallback(fn eface, cdecl bool) (code uintptr) { + if GOARCH != "386" { + // cdecl is only meaningful on 386. + cdecl = false + } + + if fn._type == nil || (fn._type.Kind_&abi.KindMask) != abi.Func { + panic("compileCallback: expected function with one uintptr-sized result") + } + ft := (*functype)(unsafe.Pointer(fn._type)) + + // Check arguments and construct ABI translation. + var abiMap abiDesc + for _, t := range ft.InSlice() { + abiMap.assignArg(t) + } + // The Go ABI aligns the result to the word size. src is + // already aligned. + abiMap.dstStackSize = alignUp(abiMap.dstStackSize, goarch.PtrSize) + abiMap.retOffset = abiMap.dstStackSize + + if len(ft.OutSlice()) != 1 { + panic("compileCallback: expected function with one uintptr-sized result") + } + if ft.OutSlice()[0].Size_ != goarch.PtrSize { + panic("compileCallback: expected function with one uintptr-sized result") + } + if k := ft.OutSlice()[0].Kind_ & abi.KindMask; k == abi.Float32 || k == abi.Float64 { + // In cdecl and stdcall, float results are returned in + // ST(0). In fastcall, they're returned in XMM0. + // Either way, it's not AX. + panic("compileCallback: float results not supported") + } + if intArgRegs == 0 { + // Make room for the uintptr-sized result. + // If there are argument registers, the return value will + // be passed in the first register. + abiMap.dstStackSize += goarch.PtrSize + } + + // TODO(mknyszek): Remove dstSpill from this calculation when we no longer have + // caller reserved spill space. + frameSize := alignUp(abiMap.dstStackSize, goarch.PtrSize) + frameSize += abiMap.dstSpill + if frameSize > callbackMaxFrame { + panic("compileCallback: function argument frame too large") + } + + // For cdecl, the callee is responsible for popping its + // arguments from the C stack. + var retPop uintptr + if cdecl { + retPop = abiMap.srcStackSize + } + + key := winCallbackKey{(*funcval)(fn.data), cdecl} + + cbsLock() + + // Check if this callback is already registered. + if n, ok := cbs.index[key]; ok { + cbsUnlock() + return callbackasmAddr(n) + } + + // Register the callback. + if cbs.index == nil { + cbs.index = make(map[winCallbackKey]int) + } + n := cbs.n + if n >= len(cbs.ctxt) { + cbsUnlock() + throw("too many callback functions") + } + c := winCallback{key.fn, retPop, abiMap} + cbs.ctxt[n] = c + cbs.index[key] = n + cbs.n++ + + cbsUnlock() + return callbackasmAddr(n) +} + +type callbackArgs struct { + index uintptr + // args points to the argument block. + // + // For cdecl and stdcall, all arguments are on the stack. + // + // For fastcall, the trampoline spills register arguments to + // the reserved spill slots below the stack arguments, + // resulting in a layout equivalent to stdcall. + // + // For arm, the trampoline stores the register arguments just + // below the stack arguments, so again we can treat it as one + // big stack arguments frame. + args unsafe.Pointer + // Below are out-args from callbackWrap + result uintptr + retPop uintptr // For 386 cdecl, how many bytes to pop on return +} + +// callbackWrap is called by callbackasm to invoke a registered C callback. +func callbackWrap(a *callbackArgs) { + c := cbs.ctxt[a.index] + a.retPop = c.retPop + + // Convert from C to Go ABI. + var regs abi.RegArgs + var frame [callbackMaxFrame]byte + goArgs := unsafe.Pointer(&frame) + for _, part := range c.abiMap.parts { + switch part.kind { + case abiPartStack: + memmove(add(goArgs, part.dstStackOffset), add(a.args, part.srcStackOffset), part.len) + case abiPartReg: + goReg := unsafe.Pointer(®s.Ints[part.dstRegister]) + memmove(goReg, add(a.args, part.srcStackOffset), part.len) + default: + panic("bad ABI description") + } + } + + // TODO(mknyszek): Remove this when we no longer have + // caller reserved spill space. + frameSize := alignUp(c.abiMap.dstStackSize, goarch.PtrSize) + frameSize += c.abiMap.dstSpill + + // Even though this is copying back results, we can pass a nil + // type because those results must not require write barriers. + reflectcall(nil, unsafe.Pointer(c.fn), noescape(goArgs), uint32(c.abiMap.dstStackSize), uint32(c.abiMap.retOffset), uint32(frameSize), ®s) + + // Extract the result. + // + // There's always exactly one return value, one pointer in size. + // If it's on the stack, then we will have reserved space for it + // at the end of the frame, otherwise it was passed in a register. + if c.abiMap.dstStackSize != c.abiMap.retOffset { + a.result = *(*uintptr)(unsafe.Pointer(&frame[c.abiMap.retOffset])) + } else { + var zero int + // On architectures with no registers, Ints[0] would be a compile error, + // so we use a dynamic index. These architectures will never take this + // branch, so this won't cause a runtime panic. + a.result = regs.Ints[zero] + } +} + +const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 + +//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary +func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) { + handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryExW)), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) + KeepAlive(filename) + if handle != 0 { + err = 0 + } + return +} + +// golang.org/x/sys linknames syscall.loadlibrary +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// +//go:linkname syscall_loadlibrary syscall.loadlibrary +func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { + handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryW)), uintptr(unsafe.Pointer(filename))) + KeepAlive(filename) + if handle != 0 { + err = 0 + } + return +} + +// golang.org/x/sys linknames syscall.getprocaddress +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// +//go:linkname syscall_getprocaddress syscall.getprocaddress +func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) { + outhandle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_GetProcAddress)), handle, uintptr(unsafe.Pointer(procname))) + KeepAlive(procname) + if outhandle != 0 { + err = 0 + } + return +} + +//go:linkname syscall_Syscall syscall.Syscall +//go:nosplit +func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) { + return syscall_syscalln(fn, nargs, a1, a2, a3) +} + +//go:linkname syscall_Syscall6 syscall.Syscall6 +//go:nosplit +func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6) +} + +//go:linkname syscall_Syscall9 syscall.Syscall9 +//go:nosplit +func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) { + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9) +} + +//go:linkname syscall_Syscall12 syscall.Syscall12 +//go:nosplit +func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) { + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) +} + +//go:linkname syscall_Syscall15 syscall.Syscall15 +//go:nosplit +func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) { + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) +} + +//go:linkname syscall_Syscall18 syscall.Syscall18 +//go:nosplit +func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2, err uintptr) { + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) +} + +// maxArgs should be divisible by 2, as Windows stack +// must be kept 16-byte aligned on syscall entry. +// +// Although it only permits maximum 42 parameters, it +// is arguably large enough. +const maxArgs = 42 + +//go:linkname syscall_SyscallN syscall.SyscallN +//go:nosplit +func syscall_SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) { + return syscall_syscalln(fn, uintptr(len(args)), args...) +} + +//go:nosplit +func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) { + if n > uintptr(len(args)) { + panic("syscall: n > len(args)") // should not be reachable from user code + } + if n > maxArgs { + panic("runtime: SyscallN has too many arguments") + } + + // The cgocall parameters are stored in m instead of in + // the stack because the stack can move during fn if it + // calls back into Go. + c := &getg().m.winsyscall + c.fn = fn + c.n = n + if c.n != 0 { + c.args = uintptr(noescape(unsafe.Pointer(&args[0]))) + } + cgocall(asmstdcallAddr, unsafe.Pointer(c)) + // cgocall may reschedule us on to a different M, + // but it copies the return values into the new M's + // so we can read them from there. + c = &getg().m.winsyscall + return c.r1, c.r2, c.err +} diff --git a/contrib/go/_std_1.22/src/runtime/tagptr.go b/contrib/go/_std_1.23/src/runtime/tagptr.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tagptr.go rename to contrib/go/_std_1.23/src/runtime/tagptr.go diff --git a/contrib/go/_std_1.22/src/runtime/tagptr_32bit.go b/contrib/go/_std_1.23/src/runtime/tagptr_32bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tagptr_32bit.go rename to contrib/go/_std_1.23/src/runtime/tagptr_32bit.go diff --git a/contrib/go/_std_1.22/src/runtime/tagptr_64bit.go b/contrib/go/_std_1.23/src/runtime/tagptr_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tagptr_64bit.go rename to contrib/go/_std_1.23/src/runtime/tagptr_64bit.go diff --git a/contrib/go/_std_1.22/src/runtime/test_amd64.go b/contrib/go/_std_1.23/src/runtime/test_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/test_amd64.go rename to contrib/go/_std_1.23/src/runtime/test_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/test_amd64.s b/contrib/go/_std_1.23/src/runtime/test_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/test_amd64.s rename to contrib/go/_std_1.23/src/runtime/test_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/test_stubs.go b/contrib/go/_std_1.23/src/runtime/test_stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/test_stubs.go rename to contrib/go/_std_1.23/src/runtime/test_stubs.go diff --git a/contrib/go/_std_1.22/src/runtime/textflag.h b/contrib/go/_std_1.23/src/runtime/textflag.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/textflag.h rename to contrib/go/_std_1.23/src/runtime/textflag.h diff --git a/contrib/go/_std_1.23/src/runtime/time.go b/contrib/go/_std_1.23/src/runtime/time.go new file mode 100644 index 000000000000..7b344a349610 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/time.go @@ -0,0 +1,1377 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Time-related runtime and pieces of package time. + +package runtime + +import ( + "internal/abi" + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +// A timer is a potentially repeating trigger for calling t.f(t.arg, t.seq). +// Timers are allocated by client code, often as part of other data structures. +// Each P has a heap of pointers to timers that it manages. +// +// A timer is expected to be used by only one client goroutine at a time, +// but there will be concurrent access by the P managing that timer. +// Timer accesses are protected by the lock t.mu, with a snapshot of +// t's state bits published in t.astate to enable certain fast paths to make +// decisions about a timer without acquiring the lock. +type timer struct { + // mu protects reads and writes to all fields, with exceptions noted below. + mu mutex + + astate atomic.Uint8 // atomic copy of state bits at last unlock + state uint8 // state bits + isChan bool // timer has a channel; immutable; can be read without lock + + blocked uint32 // number of goroutines blocked on timer's channel + + // Timer wakes up at when, and then at when+period, ... (period > 0 only) + // each time calling f(arg, seq, delay) in the timer goroutine, so f must be + // a well-behaved function and not block. + // + // The arg and seq are client-specified opaque arguments passed back to f. + // When used from netpoll, arg and seq have meanings defined by netpoll + // and are completely opaque to this code; in that context, seq is a sequence + // number to recognize and squech stale function invocations. + // When used from package time, arg is a channel (for After, NewTicker) + // or the function to call (for AfterFunc) and seq is unused (0). + // + // Package time does not know about seq, but if this is a channel timer (t.isChan == true), + // this file uses t.seq as a sequence number to recognize and squelch + // sends that correspond to an earlier (stale) timer configuration, + // similar to its use in netpoll. In this usage (that is, when t.isChan == true), + // writes to seq are protected by both t.mu and t.sendLock, + // so reads are allowed when holding either of the two mutexes. + // + // The delay argument is nanotime() - t.when, meaning the delay in ns between + // when the timer should have gone off and now. Normally that amount is + // small enough not to matter, but for channel timers that are fed lazily, + // the delay can be arbitrarily long; package time subtracts it out to make + // it look like the send happened earlier than it actually did. + // (No one looked at the channel since then, or the send would have + // not happened so late, so no one can tell the difference.) + when int64 + period int64 + f func(arg any, seq uintptr, delay int64) + arg any + seq uintptr + + // If non-nil, the timers containing t. + ts *timers + + // sendLock protects sends on the timer's channel. + // Not used for async (pre-Go 1.23) behavior when debug.asynctimerchan.Load() != 0. + sendLock mutex + + // isSending is used to handle races between running a + // channel timer and stopping or resetting the timer. + // It is used only for channel timers (t.isChan == true). + // It is not used for tickers. + // The value is incremented when about to send a value on the channel, + // and decremented after sending the value. + // The stop/reset code uses this to detect whether it + // stopped the channel send. + // + // isSending is incremented only when t.mu is held. + // isSending is decremented only when t.sendLock is held. + // isSending is read only when both t.mu and t.sendLock are held. + isSending atomic.Int32 +} + +// init initializes a newly allocated timer t. +// Any code that allocates a timer must call t.init before using it. +// The arg and f can be set during init, or they can be nil in init +// and set by a future call to t.modify. +func (t *timer) init(f func(arg any, seq uintptr, delay int64), arg any) { + lockInit(&t.mu, lockRankTimer) + t.f = f + t.arg = arg +} + +// A timers is a per-P set of timers. +type timers struct { + // mu protects timers; timers are per-P, but the scheduler can + // access the timers of another P, so we have to lock. + mu mutex + + // heap is the set of timers, ordered by heap[i].when. + // Must hold lock to access. + heap []timerWhen + + // len is an atomic copy of len(heap). + len atomic.Uint32 + + // zombies is the number of timers in the heap + // that are marked for removal. + zombies atomic.Int32 + + // raceCtx is the race context used while executing timer functions. + raceCtx uintptr + + // minWhenHeap is the minimum heap[i].when value (= heap[0].when). + // The wakeTime method uses minWhenHeap and minWhenModified + // to determine the next wake time. + // If minWhenHeap = 0, it means there are no timers in the heap. + minWhenHeap atomic.Int64 + + // minWhenModified is a lower bound on the minimum + // heap[i].when over timers with the timerModified bit set. + // If minWhenModified = 0, it means there are no timerModified timers in the heap. + minWhenModified atomic.Int64 +} + +type timerWhen struct { + timer *timer + when int64 +} + +func (ts *timers) lock() { + lock(&ts.mu) +} + +func (ts *timers) unlock() { + // Update atomic copy of len(ts.heap). + // We only update at unlock so that the len is always + // the most recent unlocked length, not an ephemeral length. + // This matters if we lock ts, delete the only timer from the heap, + // add it back, and unlock. We want ts.len.Load to return 1 the + // entire time, never 0. This is important for pidleput deciding + // whether ts is empty. + ts.len.Store(uint32(len(ts.heap))) + + unlock(&ts.mu) +} + +// Timer state field. +const ( + // timerHeaped is set when the timer is stored in some P's heap. + timerHeaped uint8 = 1 << iota + + // timerModified is set when t.when has been modified + // but the heap's heap[i].when entry still needs to be updated. + // That change waits until the heap in which + // the timer appears can be locked and rearranged. + // timerModified is only set when timerHeaped is also set. + timerModified + + // timerZombie is set when the timer has been stopped + // but is still present in some P's heap. + // Only set when timerHeaped is also set. + // It is possible for timerModified and timerZombie to both + // be set, meaning that the timer was modified and then stopped. + // A timer sending to a channel may be placed in timerZombie + // to take it out of the heap even though the timer is not stopped, + // as long as nothing is reading from the channel. + timerZombie +) + +// timerDebug enables printing a textual debug trace of all timer operations to stderr. +const timerDebug = false + +func (t *timer) trace(op string) { + if timerDebug { + t.trace1(op) + } +} + +func (t *timer) trace1(op string) { + if !timerDebug { + return + } + bits := [4]string{"h", "m", "z", "c"} + for i := range 3 { + if t.state&(1< 0 { + // If timer should have triggered already (but nothing looked at it yet), + // trigger now, so that a receive after the stop sees the "old" value + // that should be there. + // (It is possible to have t.blocked > 0 if there is a racing receive + // in blockTimerChan, but timerHeaped not being set means + // it hasn't run t.maybeAdd yet; in that case, running the + // timer ourselves now is fine.) + if now := nanotime(); t.when <= now { + systemstack(func() { + t.unlockAndRun(now) // resets t.when + }) + t.lock() + } + } +} + +// stop stops the timer t. It may be on some other P, so we can't +// actually remove it from the timers heap. We can only mark it as stopped. +// It will be removed in due course by the P whose heap it is on. +// Reports whether the timer was stopped before it was run. +func (t *timer) stop() bool { + async := debug.asynctimerchan.Load() != 0 + if !async && t.isChan { + lock(&t.sendLock) + } + + t.lock() + t.trace("stop") + if async { + t.maybeRunAsync() + } + if t.state&timerHeaped != 0 { + t.state |= timerModified + if t.state&timerZombie == 0 { + t.state |= timerZombie + t.ts.zombies.Add(1) + } + } + pending := t.when > 0 + t.when = 0 + + if !async && t.isChan { + // Stop any future sends with stale values. + // See timer.unlockAndRun. + t.seq++ + + // If there is currently a send in progress, + // incrementing seq is going to prevent that + // send from actually happening. That means + // that we should return true: the timer was + // stopped, even though t.when may be zero. + if t.period == 0 && t.isSending.Load() > 0 { + pending = true + } + } + t.unlock() + if !async && t.isChan { + unlock(&t.sendLock) + if timerchandrain(t.hchan()) { + pending = true + } + } + + return pending +} + +// deleteMin removes timer 0 from ts. +// ts must be locked. +func (ts *timers) deleteMin() { + assertLockHeld(&ts.mu) + t := ts.heap[0].timer + if t.ts != ts { + throw("wrong timers") + } + t.ts = nil + last := len(ts.heap) - 1 + if last > 0 { + ts.heap[0] = ts.heap[last] + } + ts.heap[last] = timerWhen{} + ts.heap = ts.heap[:last] + if last > 0 { + ts.siftDown(0) + } + ts.updateMinWhenHeap() + if last == 0 { + // If there are no timers, then clearly there are no timerModified timers. + ts.minWhenModified.Store(0) + } +} + +// modify modifies an existing timer. +// This is called by the netpoll code or time.Ticker.Reset or time.Timer.Reset. +// Reports whether the timer was modified before it was run. +// If f == nil, then t.f, t.arg, and t.seq are not modified. +func (t *timer) modify(when, period int64, f func(arg any, seq uintptr, delay int64), arg any, seq uintptr) bool { + if when <= 0 { + throw("timer when must be positive") + } + if period < 0 { + throw("timer period must be non-negative") + } + async := debug.asynctimerchan.Load() != 0 + + if !async && t.isChan { + lock(&t.sendLock) + } + + t.lock() + if async { + t.maybeRunAsync() + } + t.trace("modify") + oldPeriod := t.period + t.period = period + if f != nil { + t.f = f + t.arg = arg + t.seq = seq + } + + wake := false + pending := t.when > 0 + t.when = when + if t.state&timerHeaped != 0 { + t.state |= timerModified + if t.state&timerZombie != 0 { + // In the heap but marked for removal (by a Stop). + // Unmark it, since it has been Reset and will be running again. + t.ts.zombies.Add(-1) + t.state &^= timerZombie + } + // The corresponding heap[i].when is updated later. + // See comment in type timer above and in timers.adjust below. + if min := t.ts.minWhenModified.Load(); min == 0 || when < min { + wake = true + // Force timerModified bit out to t.astate before updating t.minWhenModified, + // to synchronize with t.ts.adjust. See comment in adjust. + t.astate.Store(t.state) + t.ts.updateMinWhenModified(when) + } + } + + add := t.needsAdd() + + if !async && t.isChan { + // Stop any future sends with stale values. + // See timer.unlockAndRun. + t.seq++ + + // If there is currently a send in progress, + // incrementing seq is going to prevent that + // send from actually happening. That means + // that we should return true: the timer was + // stopped, even though t.when may be zero. + if oldPeriod == 0 && t.isSending.Load() > 0 { + pending = true + } + } + t.unlock() + if !async && t.isChan { + if timerchandrain(t.hchan()) { + pending = true + } + unlock(&t.sendLock) + } + + if add { + t.maybeAdd() + } + if wake { + wakeNetPoller(when) + } + + return pending +} + +// needsAdd reports whether t needs to be added to a timers heap. +// t must be locked. +func (t *timer) needsAdd() bool { + assertLockHeld(&t.mu) + need := t.state&timerHeaped == 0 && t.when > 0 && (!t.isChan || t.blocked > 0) + if need { + t.trace("needsAdd+") + } else { + t.trace("needsAdd-") + } + return need +} + +// maybeAdd adds t to the local timers heap if it needs to be in a heap. +// The caller must not hold t's lock nor any timers heap lock. +// The caller probably just unlocked t, but that lock must be dropped +// in order to acquire a ts.lock, to avoid lock inversions. +// (timers.adjust holds ts.lock while acquiring each t's lock, +// so we cannot hold any t's lock while acquiring ts.lock). +// +// Strictly speaking it *might* be okay to hold t.lock and +// acquire ts.lock at the same time, because we know that +// t is not in any ts.heap, so nothing holding a ts.lock would +// be acquiring the t.lock at the same time, meaning there +// isn't a possible deadlock. But it is easier and safer not to be +// too clever and respect the static ordering. +// (If we don't, we have to change the static lock checking of t and ts.) +// +// Concurrent calls to time.Timer.Reset or blockTimerChan +// may result in concurrent calls to t.maybeAdd, +// so we cannot assume that t is not in a heap on entry to t.maybeAdd. +func (t *timer) maybeAdd() { + // Note: Not holding any locks on entry to t.maybeAdd, + // so the current g can be rescheduled to a different M and P + // at any time, including between the ts := assignment and the + // call to ts.lock. If a reschedule happened then, we would be + // adding t to some other P's timers, perhaps even a P that the scheduler + // has marked as idle with no timers, in which case the timer could + // go unnoticed until long after t.when. + // Calling acquirem instead of using getg().m makes sure that + // we end up locking and inserting into the current P's timers. + mp := acquirem() + ts := &mp.p.ptr().timers + ts.lock() + ts.cleanHead() + t.lock() + t.trace("maybeAdd") + when := int64(0) + wake := false + if t.needsAdd() { + t.state |= timerHeaped + when = t.when + wakeTime := ts.wakeTime() + wake = wakeTime == 0 || when < wakeTime + ts.addHeap(t) + } + t.unlock() + ts.unlock() + releasem(mp) + if wake { + wakeNetPoller(when) + } +} + +// reset resets the time when a timer should fire. +// If used for an inactive timer, the timer will become active. +// Reports whether the timer was active and was stopped. +func (t *timer) reset(when, period int64) bool { + return t.modify(when, period, nil, nil, 0) +} + +// cleanHead cleans up the head of the timer queue. This speeds up +// programs that create and delete timers; leaving them in the heap +// slows down heap operations. +// The caller must have locked ts. +func (ts *timers) cleanHead() { + ts.trace("cleanHead") + assertLockHeld(&ts.mu) + gp := getg() + for { + if len(ts.heap) == 0 { + return + } + + // This loop can theoretically run for a while, and because + // it is holding timersLock it cannot be preempted. + // If someone is trying to preempt us, just return. + // We can clean the timers later. + if gp.preemptStop { + return + } + + // Delete zombies from tail of heap. It requires no heap adjustments at all, + // and doing so increases the chances that when we swap out a zombie + // in heap[0] for the tail of the heap, we'll get a non-zombie timer, + // shortening this loop. + n := len(ts.heap) + if t := ts.heap[n-1].timer; t.astate.Load()&timerZombie != 0 { + t.lock() + if t.state&timerZombie != 0 { + t.state &^= timerHeaped | timerZombie | timerModified + t.ts = nil + ts.zombies.Add(-1) + ts.heap[n-1] = timerWhen{} + ts.heap = ts.heap[:n-1] + } + t.unlock() + continue + } + + t := ts.heap[0].timer + if t.ts != ts { + throw("bad ts") + } + + if t.astate.Load()&(timerModified|timerZombie) == 0 { + // Fast path: head of timers does not need adjustment. + return + } + + t.lock() + updated := t.updateHeap() + t.unlock() + if !updated { + // Head of timers does not need adjustment. + return + } + } +} + +// take moves any timers from src into ts +// and then clears the timer state from src, +// because src is being destroyed. +// The caller must not have locked either timers. +// For now this is only called when the world is stopped. +func (ts *timers) take(src *timers) { + ts.trace("take") + assertWorldStopped() + if len(src.heap) > 0 { + // The world is stopped, so we ignore the locking of ts and src here. + // That would introduce a sched < timers lock ordering, + // which we'd rather avoid in the static ranking. + for _, tw := range src.heap { + t := tw.timer + t.ts = nil + if t.state&timerZombie != 0 { + t.state &^= timerHeaped | timerZombie | timerModified + } else { + t.state &^= timerModified + ts.addHeap(t) + } + } + src.heap = nil + src.zombies.Store(0) + src.minWhenHeap.Store(0) + src.minWhenModified.Store(0) + src.len.Store(0) + ts.len.Store(uint32(len(ts.heap))) + } +} + +// adjust looks through the timers in ts.heap for +// any timers that have been modified to run earlier, and puts them in +// the correct place in the heap. While looking for those timers, +// it also moves timers that have been modified to run later, +// and removes deleted timers. The caller must have locked ts. +func (ts *timers) adjust(now int64, force bool) { + ts.trace("adjust") + assertLockHeld(&ts.mu) + // If we haven't yet reached the time of the earliest modified + // timer, don't do anything. This speeds up programs that adjust + // a lot of timers back and forth if the timers rarely expire. + // We'll postpone looking through all the adjusted timers until + // one would actually expire. + if !force { + first := ts.minWhenModified.Load() + if first == 0 || first > now { + if verifyTimers { + ts.verify() + } + return + } + } + + // minWhenModified is a lower bound on the earliest t.when + // among the timerModified timers. We want to make it more precise: + // we are going to scan the heap and clean out all the timerModified bits, + // at which point minWhenModified can be set to 0 (indicating none at all). + // + // Other P's can be calling ts.wakeTime concurrently, and we'd like to + // keep ts.wakeTime returning an accurate value throughout this entire process. + // + // Setting minWhenModified = 0 *before* the scan could make wakeTime + // return an incorrect value: if minWhenModified < minWhenHeap, then clearing + // it to 0 will make wakeTime return minWhenHeap (too late) until the scan finishes. + // To avoid that, we want to set minWhenModified to 0 *after* the scan. + // + // Setting minWhenModified = 0 *after* the scan could result in missing + // concurrent timer modifications in other goroutines; those will lock + // the specific timer, set the timerModified bit, and set t.when. + // To avoid that, we want to set minWhenModified to 0 *before* the scan. + // + // The way out of this dilemma is to preserve wakeTime a different way. + // wakeTime is min(minWhenHeap, minWhenModified), and minWhenHeap + // is protected by ts.lock, which we hold, so we can modify it however we like + // in service of keeping wakeTime accurate. + // + // So we can: + // + // 1. Set minWhenHeap = min(minWhenHeap, minWhenModified) + // 2. Set minWhenModified = 0 + // (Other goroutines may modify timers and update minWhenModified now.) + // 3. Scan timers + // 4. Set minWhenHeap = heap[0].when + // + // That order preserves a correct value of wakeTime throughout the entire + // operation: + // Step 1 “locks in” an accurate wakeTime even with minWhenModified cleared. + // Step 2 makes sure concurrent t.when updates are not lost during the scan. + // Step 3 processes all modified timer values, justifying minWhenModified = 0. + // Step 4 corrects minWhenHeap to a precise value. + // + // The wakeTime method implementation reads minWhenModified *before* minWhenHeap, + // so that if the minWhenModified is observed to be 0, that means the minWhenHeap that + // follows will include the information that was zeroed out of it. + // + // Originally Step 3 locked every timer, which made sure any timer update that was + // already in progress during Steps 1+2 completed and was observed by Step 3. + // All that locking was too expensive, so now we do an atomic load of t.astate to + // decide whether we need to do a full lock. To make sure that we still observe any + // timer update already in progress during Steps 1+2, t.modify sets timerModified + // in t.astate *before* calling t.updateMinWhenModified. That ensures that the + // overwrite in Step 2 cannot lose an update: if it does overwrite an update, Step 3 + // will see the timerModified and do a full lock. + ts.minWhenHeap.Store(ts.wakeTime()) + ts.minWhenModified.Store(0) + + changed := false + for i := 0; i < len(ts.heap); i++ { + tw := &ts.heap[i] + t := tw.timer + if t.ts != ts { + throw("bad ts") + } + + if t.astate.Load()&(timerModified|timerZombie) == 0 { + // Does not need adjustment. + continue + } + + t.lock() + switch { + case t.state&timerHeaped == 0: + badTimer() + + case t.state&timerZombie != 0: + ts.zombies.Add(-1) + t.state &^= timerHeaped | timerZombie | timerModified + n := len(ts.heap) + ts.heap[i] = ts.heap[n-1] + ts.heap[n-1] = timerWhen{} + ts.heap = ts.heap[:n-1] + t.ts = nil + i-- + changed = true + + case t.state&timerModified != 0: + tw.when = t.when + t.state &^= timerModified + changed = true + } + t.unlock() + } + + if changed { + ts.initHeap() + } + ts.updateMinWhenHeap() + + if verifyTimers { + ts.verify() + } +} + +// wakeTime looks at ts's timers and returns the time when we +// should wake up the netpoller. It returns 0 if there are no timers. +// This function is invoked when dropping a P, so it must run without +// any write barriers. +// +//go:nowritebarrierrec +func (ts *timers) wakeTime() int64 { + // Note that the order of these two loads matters: + // adjust updates minWhen to make it safe to clear minNextWhen. + // We read minWhen after reading minNextWhen so that + // if we see a cleared minNextWhen, we are guaranteed to see + // the updated minWhen. + nextWhen := ts.minWhenModified.Load() + when := ts.minWhenHeap.Load() + if when == 0 || (nextWhen != 0 && nextWhen < when) { + when = nextWhen + } + return when +} + +// check runs any timers in ts that are ready. +// If now is not 0 it is the current time. +// It returns the passed time or the current time if now was passed as 0. +// and the time when the next timer should run or 0 if there is no next timer, +// and reports whether it ran any timers. +// If the time when the next timer should run is not 0, +// it is always larger than the returned time. +// We pass now in and out to avoid extra calls of nanotime. +// +//go:yeswritebarrierrec +func (ts *timers) check(now int64) (rnow, pollUntil int64, ran bool) { + ts.trace("check") + // If it's not yet time for the first timer, or the first adjusted + // timer, then there is nothing to do. + next := ts.wakeTime() + if next == 0 { + // No timers to run or adjust. + return now, 0, false + } + + if now == 0 { + now = nanotime() + } + + // If this is the local P, and there are a lot of deleted timers, + // clear them out. We only do this for the local P to reduce + // lock contention on timersLock. + zombies := ts.zombies.Load() + if zombies < 0 { + badTimer() + } + force := ts == &getg().m.p.ptr().timers && int(zombies) > int(ts.len.Load())/4 + + if now < next && !force { + // Next timer is not ready to run, and we don't need to clear deleted timers. + return now, next, false + } + + ts.lock() + if len(ts.heap) > 0 { + ts.adjust(now, false) + for len(ts.heap) > 0 { + // Note that runtimer may temporarily unlock ts. + if tw := ts.run(now); tw != 0 { + if tw > 0 { + pollUntil = tw + } + break + } + ran = true + } + + // Note: Delaying the forced adjustment until after the ts.run + // (as opposed to calling ts.adjust(now, force) above) + // is significantly faster under contention, such as in + // package time's BenchmarkTimerAdjust10000, + // though we do not fully understand why. + force = ts == &getg().m.p.ptr().timers && int(ts.zombies.Load()) > int(ts.len.Load())/4 + if force { + ts.adjust(now, true) + } + } + ts.unlock() + + return now, pollUntil, ran +} + +// run examines the first timer in ts. If it is ready based on now, +// it runs the timer and removes or updates it. +// Returns 0 if it ran a timer, -1 if there are no more timers, or the time +// when the first timer should run. +// The caller must have locked ts. +// If a timer is run, this will temporarily unlock ts. +// +//go:systemstack +func (ts *timers) run(now int64) int64 { + ts.trace("run") + assertLockHeld(&ts.mu) +Redo: + if len(ts.heap) == 0 { + return -1 + } + tw := ts.heap[0] + t := tw.timer + if t.ts != ts { + throw("bad ts") + } + + if t.astate.Load()&(timerModified|timerZombie) == 0 && tw.when > now { + // Fast path: not ready to run. + return tw.when + } + + t.lock() + if t.updateHeap() { + t.unlock() + goto Redo + } + + if t.state&timerHeaped == 0 || t.state&timerModified != 0 { + badTimer() + } + + if t.when > now { + // Not ready to run. + t.unlock() + return t.when + } + + t.unlockAndRun(now) + assertLockHeld(&ts.mu) // t is unlocked now, but not ts + return 0 +} + +// unlockAndRun unlocks and runs the timer t (which must be locked). +// If t is in a timer set (t.ts != nil), the caller must also have locked the timer set, +// and this call will temporarily unlock the timer set while running the timer function. +// unlockAndRun returns with t unlocked and t.ts (re-)locked. +// +//go:systemstack +func (t *timer) unlockAndRun(now int64) { + t.trace("unlockAndRun") + assertLockHeld(&t.mu) + if t.ts != nil { + assertLockHeld(&t.ts.mu) + } + if raceenabled { + // Note that we are running on a system stack, + // so there is no chance of getg().m being reassigned + // out from under us while this function executes. + tsLocal := &getg().m.p.ptr().timers + if tsLocal.raceCtx == 0 { + tsLocal.raceCtx = racegostart(abi.FuncPCABIInternal((*timers).run) + sys.PCQuantum) + } + raceacquirectx(tsLocal.raceCtx, unsafe.Pointer(t)) + } + + if t.state&(timerModified|timerZombie) != 0 { + badTimer() + } + + f := t.f + arg := t.arg + seq := t.seq + var next int64 + delay := now - t.when + if t.period > 0 { + // Leave in heap but adjust next time to fire. + next = t.when + t.period*(1+delay/t.period) + if next < 0 { // check for overflow. + next = maxWhen + } + } else { + next = 0 + } + ts := t.ts + t.when = next + if t.state&timerHeaped != 0 { + t.state |= timerModified + if next == 0 { + t.state |= timerZombie + t.ts.zombies.Add(1) + } + t.updateHeap() + } + + async := debug.asynctimerchan.Load() != 0 + if !async && t.isChan && t.period == 0 { + // Tell Stop/Reset that we are sending a value. + if t.isSending.Add(1) < 0 { + throw("too many concurrent timer firings") + } + } + + t.unlock() + + if raceenabled { + // Temporarily use the current P's racectx for g0. + gp := getg() + if gp.racectx != 0 { + throw("unexpected racectx") + } + gp.racectx = gp.m.p.ptr().timers.raceCtx + } + + if ts != nil { + ts.unlock() + } + + if !async && t.isChan { + // For a timer channel, we want to make sure that no stale sends + // happen after a t.stop or t.modify, but we cannot hold t.mu + // during the actual send (which f does) due to lock ordering. + // It can happen that we are holding t's lock above, we decide + // it's time to send a time value (by calling f), grab the parameters, + // unlock above, and then a t.stop or t.modify changes the timer + // and returns. At that point, the send needs not to happen after all. + // The way we arrange for it not to happen is that t.stop and t.modify + // both increment t.seq while holding both t.mu and t.sendLock. + // We copied the seq value above while holding t.mu. + // Now we can acquire t.sendLock (which will be held across the send) + // and double-check that t.seq is still the seq value we saw above. + // If not, the timer has been updated and we should skip the send. + // We skip the send by reassigning f to a no-op function. + // + // The isSending field tells t.stop or t.modify that we have + // started to send the value. That lets them correctly return + // true meaning that no value was sent. + lock(&t.sendLock) + + if t.period == 0 { + // We are committed to possibly sending a value + // based on seq, so no need to keep telling + // stop/modify that we are sending. + if t.isSending.Add(-1) < 0 { + throw("mismatched isSending updates") + } + } + + if t.seq != seq { + f = func(any, uintptr, int64) {} + } + } + + f(arg, seq, delay) + + if !async && t.isChan { + unlock(&t.sendLock) + } + + if ts != nil { + ts.lock() + } + + if raceenabled { + gp := getg() + gp.racectx = 0 + } +} + +// verifyTimerHeap verifies that the timers is in a valid state. +// This is only for debugging, and is only called if verifyTimers is true. +// The caller must have locked ts. +func (ts *timers) verify() { + assertLockHeld(&ts.mu) + for i, tw := range ts.heap { + if i == 0 { + // First timer has no parent. + continue + } + + // The heap is timerHeapN-ary. See siftupTimer and siftdownTimer. + p := int(uint(i-1) / timerHeapN) + if tw.when < ts.heap[p].when { + print("bad timer heap at ", i, ": ", p, ": ", ts.heap[p].when, ", ", i, ": ", tw.when, "\n") + throw("bad timer heap") + } + } + if n := int(ts.len.Load()); len(ts.heap) != n { + println("timer heap len", len(ts.heap), "!= atomic len", n) + throw("bad timer heap len") + } +} + +// updateMinWhenHeap sets ts.minWhenHeap to ts.heap[0].when. +// The caller must have locked ts or the world must be stopped. +func (ts *timers) updateMinWhenHeap() { + assertWorldStoppedOrLockHeld(&ts.mu) + if len(ts.heap) == 0 { + ts.minWhenHeap.Store(0) + } else { + ts.minWhenHeap.Store(ts.heap[0].when) + } +} + +// updateMinWhenModified updates ts.minWhenModified to be <= when. +// ts need not be (and usually is not) locked. +func (ts *timers) updateMinWhenModified(when int64) { + for { + old := ts.minWhenModified.Load() + if old != 0 && old < when { + return + } + if ts.minWhenModified.CompareAndSwap(old, when) { + return + } + } +} + +// timeSleepUntil returns the time when the next timer should fire. Returns +// maxWhen if there are no timers. +// This is only called by sysmon and checkdead. +func timeSleepUntil() int64 { + next := int64(maxWhen) + + // Prevent allp slice changes. This is like retake. + lock(&allpLock) + for _, pp := range allp { + if pp == nil { + // This can happen if procresize has grown + // allp but not yet created new Ps. + continue + } + + if w := pp.timers.wakeTime(); w != 0 { + next = min(next, w) + } + } + unlock(&allpLock) + + return next +} + +const timerHeapN = 4 + +// Heap maintenance algorithms. +// These algorithms check for slice index errors manually. +// Slice index error can happen if the program is using racy +// access to timers. We don't want to panic here, because +// it will cause the program to crash with a mysterious +// "panic holding locks" message. Instead, we panic while not +// holding a lock. + +// siftUp puts the timer at position i in the right place +// in the heap by moving it up toward the top of the heap. +func (ts *timers) siftUp(i int) { + heap := ts.heap + if i >= len(heap) { + badTimer() + } + tw := heap[i] + when := tw.when + if when <= 0 { + badTimer() + } + for i > 0 { + p := int(uint(i-1) / timerHeapN) // parent + if when >= heap[p].when { + break + } + heap[i] = heap[p] + i = p + } + if heap[i].timer != tw.timer { + heap[i] = tw + } +} + +// siftDown puts the timer at position i in the right place +// in the heap by moving it down toward the bottom of the heap. +func (ts *timers) siftDown(i int) { + heap := ts.heap + n := len(heap) + if i >= n { + badTimer() + } + if i*timerHeapN+1 >= n { + return + } + tw := heap[i] + when := tw.when + if when <= 0 { + badTimer() + } + for { + leftChild := i*timerHeapN + 1 + if leftChild >= n { + break + } + w := when + c := -1 + for j, tw := range heap[leftChild:min(leftChild+timerHeapN, n)] { + if tw.when < w { + w = tw.when + c = leftChild + j + } + } + if c < 0 { + break + } + heap[i] = heap[c] + i = c + } + if heap[i].timer != tw.timer { + heap[i] = tw + } +} + +// initHeap reestablishes the heap order in the slice ts.heap. +// It takes O(n) time for n=len(ts.heap), not the O(n log n) of n repeated add operations. +func (ts *timers) initHeap() { + // Last possible element that needs sifting down is parent of last element; + // last element is len(t)-1; parent of last element is (len(t)-1-1)/timerHeapN. + if len(ts.heap) <= 1 { + return + } + for i := int(uint(len(ts.heap)-1-1) / timerHeapN); i >= 0; i-- { + ts.siftDown(i) + } +} + +// badTimer is called if the timer data structures have been corrupted, +// presumably due to racy use by the program. We panic here rather than +// panicking due to invalid slice access while holding locks. +// See issue #25686. +func badTimer() { + throw("timer data corruption") +} + +// Timer channels. + +// maybeRunChan checks whether the timer needs to run +// to send a value to its associated channel. If so, it does. +// The timer must not be locked. +func (t *timer) maybeRunChan() { + if t.astate.Load()&timerHeaped != 0 { + // If the timer is in the heap, the ordinary timer code + // is in charge of sending when appropriate. + return + } + + t.lock() + now := nanotime() + if t.state&timerHeaped != 0 || t.when == 0 || t.when > now { + t.trace("maybeRunChan-") + // Timer in the heap, or not running at all, or not triggered. + t.unlock() + return + } + t.trace("maybeRunChan+") + systemstack(func() { + t.unlockAndRun(now) + }) +} + +// blockTimerChan is called when a channel op has decided to block on c. +// The caller holds the channel lock for c and possibly other channels. +// blockTimerChan makes sure that c is in a timer heap, +// adding it if needed. +func blockTimerChan(c *hchan) { + t := c.timer + t.lock() + t.trace("blockTimerChan") + if !t.isChan { + badTimer() + } + + t.blocked++ + + // If this is the first enqueue after a recent dequeue, + // the timer may still be in the heap but marked as a zombie. + // Unmark it in this case, if the timer is still pending. + if t.state&timerHeaped != 0 && t.state&timerZombie != 0 && t.when > 0 { + t.state &^= timerZombie + t.ts.zombies.Add(-1) + } + + // t.maybeAdd must be called with t unlocked, + // because it needs to lock t.ts before t. + // Then it will do nothing if t.needsAdd(state) is false. + // Check that now before the unlock, + // avoiding the extra lock-lock-unlock-unlock + // inside maybeAdd when t does not need to be added. + add := t.needsAdd() + t.unlock() + if add { + t.maybeAdd() + } +} + +// unblockTimerChan is called when a channel op that was blocked on c +// is no longer blocked. Every call to blockTimerChan must be paired with +// a call to unblockTimerChan. +// The caller holds the channel lock for c and possibly other channels. +// unblockTimerChan removes c from the timer heap when nothing is +// blocked on it anymore. +func unblockTimerChan(c *hchan) { + t := c.timer + t.lock() + t.trace("unblockTimerChan") + if !t.isChan || t.blocked == 0 { + badTimer() + } + t.blocked-- + if t.blocked == 0 && t.state&timerHeaped != 0 && t.state&timerZombie == 0 { + // Last goroutine that was blocked on this timer. + // Mark for removal from heap but do not clear t.when, + // so that we know what time it is still meant to trigger. + t.state |= timerZombie + t.ts.zombies.Add(1) + } + t.unlock() +} diff --git a/contrib/go/_std_1.22/src/runtime/time_fake.go b/contrib/go/_std_1.23/src/runtime/time_fake.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/time_fake.go rename to contrib/go/_std_1.23/src/runtime/time_fake.go index 9e24f7093105..aad1950c4837 100644 --- a/contrib/go/_std_1.22/src/runtime/time_fake.go +++ b/contrib/go/_std_1.23/src/runtime/time_fake.go @@ -31,6 +31,7 @@ var faketimeState struct { lastfd uintptr } +//go:linkname nanotime //go:nosplit func nanotime() int64 { return faketime diff --git a/contrib/go/_std_1.22/src/runtime/time_linux_amd64.s b/contrib/go/_std_1.23/src/runtime/time_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_linux_amd64.s rename to contrib/go/_std_1.23/src/runtime/time_linux_amd64.s diff --git a/contrib/go/_std_1.23/src/runtime/time_nofake.go b/contrib/go/_std_1.23/src/runtime/time_nofake.go new file mode 100644 index 000000000000..130ff1281662 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/time_nofake.go @@ -0,0 +1,58 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !faketime + +package runtime + +import "unsafe" + +// faketime is the simulated time in nanoseconds since 1970 for the +// playground. +// +// Zero means not to use faketime. +var faketime int64 + +// Exported via linkname for use by time and internal/poll. +// +// Many external packages also linkname nanotime for a fast monotonic time. +// Such code should be updated to use: +// +// var start = time.Now() // at init time +// +// and then replace nanotime() with time.Since(start), which is equally fast. +// +// However, all the code linknaming nanotime is never going to go away. +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname nanotime +//go:nosplit +func nanotime() int64 { + return nanotime1() +} + +// overrideWrite allows write to be redirected externally, by +// linkname'ing this and set it to a write function. +// +// overrideWrite should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - golang.zx2c4.com/wireguard/windows +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname overrideWrite +var overrideWrite func(fd uintptr, p unsafe.Pointer, n int32) int32 + +// write must be nosplit on Windows (see write1) +// +//go:nosplit +func write(fd uintptr, p unsafe.Pointer, n int32) int32 { + if overrideWrite != nil { + return overrideWrite(fd, noescape(p), n) + } + return write1(fd, p, n) +} diff --git a/contrib/go/_std_1.22/src/runtime/time_windows.h b/contrib/go/_std_1.23/src/runtime/time_windows.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows.h rename to contrib/go/_std_1.23/src/runtime/time_windows.h diff --git a/contrib/go/_std_1.22/src/runtime/time_windows_386.s b/contrib/go/_std_1.23/src/runtime/time_windows_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows_386.s rename to contrib/go/_std_1.23/src/runtime/time_windows_386.s diff --git a/contrib/go/_std_1.22/src/runtime/time_windows_amd64.s b/contrib/go/_std_1.23/src/runtime/time_windows_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows_amd64.s rename to contrib/go/_std_1.23/src/runtime/time_windows_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/time_windows_arm.s b/contrib/go/_std_1.23/src/runtime/time_windows_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows_arm.s rename to contrib/go/_std_1.23/src/runtime/time_windows_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/time_windows_arm64.s b/contrib/go/_std_1.23/src/runtime/time_windows_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows_arm64.s rename to contrib/go/_std_1.23/src/runtime/time_windows_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/timeasm.go b/contrib/go/_std_1.23/src/runtime/timeasm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/timeasm.go rename to contrib/go/_std_1.23/src/runtime/timeasm.go diff --git a/contrib/go/_std_1.23/src/runtime/timestub.go b/contrib/go/_std_1.23/src/runtime/timestub.go new file mode 100644 index 000000000000..da8699b5ee60 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/timestub.go @@ -0,0 +1,29 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Declarations for operating systems implementing time.now +// indirectly, in terms of walltime and nanotime assembly. + +//go:build !faketime && !windows && !(linux && amd64) + +package runtime + +import _ "unsafe" // for go:linkname + +// time_now should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/phuslu/log +// - github.com/sethvargo/go-limiter +// - github.com/ulule/limiter/v3 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname time_now time.now +func time_now() (sec int64, nsec int32, mono int64) { + sec, nsec = walltime() + return sec, nsec, nanotime() +} diff --git a/contrib/go/_std_1.22/src/runtime/timestub2.go b/contrib/go/_std_1.23/src/runtime/timestub2.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/timestub2.go rename to contrib/go/_std_1.23/src/runtime/timestub2.go diff --git a/contrib/go/_std_1.22/src/runtime/tls_arm.s b/contrib/go/_std_1.23/src/runtime/tls_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_arm.s rename to contrib/go/_std_1.23/src/runtime/tls_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_arm64.h b/contrib/go/_std_1.23/src/runtime/tls_arm64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_arm64.h rename to contrib/go/_std_1.23/src/runtime/tls_arm64.h diff --git a/contrib/go/_std_1.22/src/runtime/tls_arm64.s b/contrib/go/_std_1.23/src/runtime/tls_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_arm64.s rename to contrib/go/_std_1.23/src/runtime/tls_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_loong64.s b/contrib/go/_std_1.23/src/runtime/tls_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_loong64.s rename to contrib/go/_std_1.23/src/runtime/tls_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_mips64x.s b/contrib/go/_std_1.23/src/runtime/tls_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_mips64x.s rename to contrib/go/_std_1.23/src/runtime/tls_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_mipsx.s b/contrib/go/_std_1.23/src/runtime/tls_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_mipsx.s rename to contrib/go/_std_1.23/src/runtime/tls_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_ppc64x.s b/contrib/go/_std_1.23/src/runtime/tls_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/tls_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_riscv64.s b/contrib/go/_std_1.23/src/runtime/tls_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_riscv64.s rename to contrib/go/_std_1.23/src/runtime/tls_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_s390x.s b/contrib/go/_std_1.23/src/runtime/tls_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_s390x.s rename to contrib/go/_std_1.23/src/runtime/tls_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_stub.go b/contrib/go/_std_1.23/src/runtime/tls_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_stub.go rename to contrib/go/_std_1.23/src/runtime/tls_stub.go diff --git a/contrib/go/_std_1.22/src/runtime/tls_windows_amd64.go b/contrib/go/_std_1.23/src/runtime/tls_windows_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_windows_amd64.go rename to contrib/go/_std_1.23/src/runtime/tls_windows_amd64.go diff --git a/contrib/go/_std_1.23/src/runtime/trace.go b/contrib/go/_std_1.23/src/runtime/trace.go new file mode 100644 index 000000000000..adf7b0951dce --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/trace.go @@ -0,0 +1,1077 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Go execution tracer. +// The tracer captures a wide range of execution events like goroutine +// creation/blocking/unblocking, syscall enter/exit/block, GC-related events, +// changes of heap size, processor start/stop, etc and writes them to a buffer +// in a compact form. A precise nanosecond-precision timestamp and a stack +// trace is captured for most events. +// +// Tracer invariants (to keep the synchronization making sense): +// - An m that has a trace buffer must be on either the allm or sched.freem lists. +// - Any trace buffer mutation must either be happening in traceAdvance or between +// a traceAcquire and a subsequent traceRelease. +// - traceAdvance cannot return until the previous generation's buffers are all flushed. +// +// See https://go.dev/issue/60773 for a link to the full design. + +package runtime + +import ( + "internal/runtime/atomic" + "unsafe" +) + +// Trace state. + +// trace is global tracing context. +var trace struct { + // trace.lock must only be acquired on the system stack where + // stack splits cannot happen while it is held. + lock mutex + + // Trace buffer management. + // + // First we check the empty list for any free buffers. If not, buffers + // are allocated directly from the OS. Once they're filled up and/or + // flushed, they end up on the full queue for trace.gen%2. + // + // The trace reader takes buffers off the full list one-by-one and + // places them into reading until they're finished being read from. + // Then they're placed onto the empty list. + // + // Protected by trace.lock. + reading *traceBuf // buffer currently handed off to user + empty *traceBuf // stack of empty buffers + full [2]traceBufQueue + workAvailable atomic.Bool + + // State for the trace reader goroutine. + // + // Protected by trace.lock. + readerGen atomic.Uintptr // the generation the reader is currently reading for + flushedGen atomic.Uintptr // the last completed generation + headerWritten bool // whether ReadTrace has emitted trace header + + // doneSema is used to synchronize the reader and traceAdvance. Specifically, + // it notifies traceAdvance that the reader is done with a generation. + // Both semaphores are 0 by default (so, acquires block). traceAdvance + // attempts to acquire for gen%2 after flushing the last buffers for gen. + // Meanwhile the reader releases the sema for gen%2 when it has finished + // processing gen. + doneSema [2]uint32 + + // Trace data tables for deduplicating data going into the trace. + // There are 2 of each: one for gen%2, one for 1-gen%2. + stackTab [2]traceStackTable // maps stack traces to unique ids + stringTab [2]traceStringTable // maps strings to unique ids + typeTab [2]traceTypeTable // maps type pointers to unique ids + + // cpuLogRead accepts CPU profile samples from the signal handler where + // they're generated. There are two profBufs here: one for gen%2, one for + // 1-gen%2. These profBufs use a three-word header to hold the IDs of the P, G, + // and M (respectively) that were active at the time of the sample. Because + // profBuf uses a record with all zeros in its header to indicate overflow, + // we make sure to make the P field always non-zero: The ID of a real P will + // start at bit 1, and bit 0 will be set. Samples that arrive while no P is + // running (such as near syscalls) will set the first header field to 0b10. + // This careful handling of the first header field allows us to store ID of + // the active G directly in the second field, even though that will be 0 + // when sampling g0. + // + // Initialization and teardown of these fields is protected by traceAdvanceSema. + cpuLogRead [2]*profBuf + signalLock atomic.Uint32 // protects use of the following member, only usable in signal handlers + cpuLogWrite [2]atomic.Pointer[profBuf] // copy of cpuLogRead for use in signal handlers, set without signalLock + cpuSleep *wakeableSleep + cpuLogDone <-chan struct{} + cpuBuf [2]*traceBuf + + reader atomic.Pointer[g] // goroutine that called ReadTrace, or nil + + // Fast mappings from enumerations to string IDs that are prepopulated + // in the trace. + markWorkerLabels [2][len(gcMarkWorkerModeStrings)]traceArg + goStopReasons [2][len(traceGoStopReasonStrings)]traceArg + goBlockReasons [2][len(traceBlockReasonStrings)]traceArg + + // enabled indicates whether tracing is enabled, but it is only an optimization, + // NOT the source of truth on whether tracing is enabled. Tracing is only truly + // enabled if gen != 0. This is used as an optimistic fast path check. + // + // Transitioning this value from true -> false is easy (once gen is 0) + // because it's OK for enabled to have a stale "true" value. traceAcquire will + // always double-check gen. + // + // Transitioning this value from false -> true is harder. We need to make sure + // this is observable as true strictly before gen != 0. To maintain this invariant + // we only make this transition with the world stopped and use the store to gen + // as a publication barrier. + enabled bool + + // enabledWithAllocFree is set if debug.traceallocfree is != 0 when tracing begins. + // It follows the same synchronization protocol as enabled. + enabledWithAllocFree bool + + // Trace generation counter. + gen atomic.Uintptr + lastNonZeroGen uintptr // last non-zero value of gen + + // shutdown is set when we are waiting for trace reader to finish after setting gen to 0 + // + // Writes protected by trace.lock. + shutdown atomic.Bool + + // Number of goroutines in syscall exiting slow path. + exitingSyscall atomic.Int32 + + // seqGC is the sequence counter for GC begin/end. + // + // Mutated only during stop-the-world. + seqGC uint64 + + // minPageHeapAddr is the minimum address of the page heap when tracing started. + minPageHeapAddr uint64 + + // debugMalloc is the value of debug.malloc before tracing began. + debugMalloc bool +} + +// Trace public API. + +var ( + traceAdvanceSema uint32 = 1 + traceShutdownSema uint32 = 1 +) + +// StartTrace enables tracing for the current process. +// While tracing, the data will be buffered and available via [ReadTrace]. +// StartTrace returns an error if tracing is already enabled. +// Most clients should use the [runtime/trace] package or the [testing] package's +// -test.trace flag instead of calling StartTrace directly. +func StartTrace() error { + if traceEnabled() || traceShuttingDown() { + return errorString("tracing is already enabled") + } + // Block until cleanup of the last trace is done. + semacquire(&traceShutdownSema) + semrelease(&traceShutdownSema) + + // Hold traceAdvanceSema across trace start, since we'll want it on + // the other side of tracing being enabled globally. + semacquire(&traceAdvanceSema) + + // Initialize CPU profile -> trace ingestion. + traceInitReadCPU() + + // Compute the first generation for this StartTrace. + // + // Note: we start from the last non-zero generation rather than 1 so we + // can avoid resetting all the arrays indexed by gen%2 or gen%3. There's + // more than one of each per m, p, and goroutine. + firstGen := traceNextGen(trace.lastNonZeroGen) + + // Reset GC sequencer. + trace.seqGC = 1 + + // Reset trace reader state. + trace.headerWritten = false + trace.readerGen.Store(firstGen) + trace.flushedGen.Store(0) + + // Register some basic strings in the string tables. + traceRegisterLabelsAndReasons(firstGen) + + // Stop the world. + // + // The purpose of stopping the world is to make sure that no goroutine is in a + // context where it could emit an event by bringing all goroutines to a safe point + // with no opportunity to transition. + // + // The exception to this rule are goroutines that are concurrently exiting a syscall. + // Those will all be forced into the syscalling slow path, and we'll just make sure + // that we don't observe any goroutines in that critical section before starting + // the world again. + // + // A good follow-up question to this is why stopping the world is necessary at all + // given that we have traceAcquire and traceRelease. Unfortunately, those only help + // us when tracing is already active (for performance, so when tracing is off the + // tracing seqlock is left untouched). The main issue here is subtle: we're going to + // want to obtain a correct starting status for each goroutine, but there are windows + // of time in which we could read and emit an incorrect status. Specifically: + // + // trace := traceAcquire() + // // <----> problem window + // casgstatus(gp, _Gwaiting, _Grunnable) + // if trace.ok() { + // trace.GoUnpark(gp, 2) + // traceRelease(trace) + // } + // + // More precisely, if we readgstatus for a gp while another goroutine is in the problem + // window and that goroutine didn't observe that tracing had begun, then we might write + // a GoStatus(GoWaiting) event for that goroutine, but it won't trace an event marking + // the transition from GoWaiting to GoRunnable. The trace will then be broken, because + // future events will be emitted assuming the tracer sees GoRunnable. + // + // In short, what we really need here is to make sure that the next time *any goroutine* + // hits a traceAcquire, it sees that the trace is enabled. + // + // Note also that stopping the world is necessary to make sure sweep-related events are + // coherent. Since the world is stopped and sweeps are non-preemptible, we can never start + // the world and see an unpaired sweep 'end' event. Other parts of the tracer rely on this. + stw := stopTheWorld(stwStartTrace) + + // Prevent sysmon from running any code that could generate events. + lock(&sched.sysmonlock) + + // Grab the minimum page heap address. All Ps are stopped, so it's safe to read this since + // nothing can allocate heap memory. + trace.minPageHeapAddr = uint64(mheap_.pages.inUse.ranges[0].base.addr()) + + // Reset mSyscallID on all Ps while we have them stationary and the trace is disabled. + for _, pp := range allp { + pp.trace.mSyscallID = -1 + } + + // Start tracing. + // + // Set trace.enabled. This is *very* subtle. We need to maintain the invariant that if + // trace.gen != 0, then trace.enabled is always observed as true. Simultaneously, for + // performance, we need trace.enabled to be read without any synchronization. + // + // We ensure this is safe by stopping the world, which acts a global barrier on almost + // every M, and explicitly synchronize with any other Ms that could be running concurrently + // with us. Today, there are only two such cases: + // - sysmon, which we synchronized with by acquiring sysmonlock. + // - goroutines exiting syscalls, which we synchronize with via trace.exitingSyscall. + // + // After trace.gen is updated, other Ms may start creating trace buffers and emitting + // data into them. + trace.enabled = true + if debug.traceallocfree.Load() != 0 { + // Enable memory events since the GODEBUG is set. + trace.debugMalloc = debug.malloc + trace.enabledWithAllocFree = true + debug.malloc = true + } + trace.gen.Store(firstGen) + + // Wait for exitingSyscall to drain. + // + // It may not monotonically decrease to zero, but in the limit it will always become + // zero because the world is stopped and there are no available Ps for syscall-exited + // goroutines to run on. + // + // Because we set gen before checking this, and because exitingSyscall is always incremented + // *before* traceAcquire (which checks gen), we can be certain that when exitingSyscall is zero + // that any goroutine that goes to exit a syscall from then on *must* observe the new gen as + // well as trace.enabled being set to true. + // + // The critical section on each goroutine here is going to be quite short, so the likelihood + // that we observe a zero value is high. + for trace.exitingSyscall.Load() != 0 { + osyield() + } + + // Record some initial pieces of information. + // + // N.B. This will also emit a status event for this goroutine. + tl := traceAcquire() + tl.Gomaxprocs(gomaxprocs) // Get this as early in the trace as possible. See comment in traceAdvance. + tl.STWStart(stwStartTrace) // We didn't trace this above, so trace it now. + + // Record the fact that a GC is active, if applicable. + if gcphase == _GCmark || gcphase == _GCmarktermination { + tl.GCActive() + } + + // Dump a snapshot of memory, if enabled. + if trace.enabledWithAllocFree { + traceSnapshotMemory(firstGen) + } + + // Record the heap goal so we have it at the very beginning of the trace. + tl.HeapGoal() + + // Make sure a ProcStatus is emitted for every P, while we're here. + for _, pp := range allp { + tl.writer().writeProcStatusForP(pp, pp == tl.mp.p.ptr()).end() + } + traceRelease(tl) + + unlock(&sched.sysmonlock) + startTheWorld(stw) + + traceStartReadCPU() + traceAdvancer.start() + + semrelease(&traceAdvanceSema) + return nil +} + +// StopTrace stops tracing, if it was previously enabled. +// StopTrace only returns after all the reads for the trace have completed. +func StopTrace() { + traceAdvance(true) +} + +// traceAdvance moves tracing to the next generation, and cleans up the current generation, +// ensuring that it's flushed out before returning. If stopTrace is true, it disables tracing +// altogether instead of advancing to the next generation. +// +// traceAdvanceSema must not be held. +// +// traceAdvance is called by golang.org/x/exp/trace using linkname. +// +//go:linkname traceAdvance +func traceAdvance(stopTrace bool) { + semacquire(&traceAdvanceSema) + + // Get the gen that we're advancing from. In this function we don't really care much + // about the generation we're advancing _into_ since we'll do all the cleanup in this + // generation for the next advancement. + gen := trace.gen.Load() + if gen == 0 { + // We may end up here traceAdvance is called concurrently with StopTrace. + semrelease(&traceAdvanceSema) + return + } + + // Write an EvFrequency event for this generation. + // + // N.B. This may block for quite a while to get a good frequency estimate, so make sure we do + // this here and not e.g. on the trace reader. + traceFrequency(gen) + + // Collect all the untraced Gs. + type untracedG struct { + gp *g + goid uint64 + mid int64 + stackID uint64 + status uint32 + waitreason waitReason + inMarkAssist bool + } + var untracedGs []untracedG + forEachGRace(func(gp *g) { + // Make absolutely sure all Gs are ready for the next + // generation. We need to do this even for dead Gs because + // they may come alive with a new identity, and its status + // traced bookkeeping might end up being stale. + // We may miss totally new goroutines, but they'll always + // have clean bookkeeping. + gp.trace.readyNextGen(gen) + // If the status was traced, nothing else to do. + if gp.trace.statusWasTraced(gen) { + return + } + // Scribble down information about this goroutine. + ug := untracedG{gp: gp, mid: -1} + systemstack(func() { + me := getg().m.curg + // We don't have to handle this G status transition because we + // already eliminated ourselves from consideration above. + casGToWaitingForGC(me, _Grunning, waitReasonTraceGoroutineStatus) + // We need to suspend and take ownership of the G to safely read its + // goid. Note that we can't actually emit the event at this point + // because we might stop the G in a window where it's unsafe to write + // events based on the G's status. We need the global trace buffer flush + // coming up to make sure we're not racing with the G. + // + // It should be very unlikely that we try to preempt a running G here. + // The only situation that we might is that we're racing with a G + // that's running for the first time in this generation. Therefore, + // this should be relatively fast. + s := suspendG(gp) + if !s.dead { + ug.goid = s.g.goid + if s.g.m != nil { + ug.mid = int64(s.g.m.procid) + } + ug.status = readgstatus(s.g) &^ _Gscan + ug.waitreason = s.g.waitreason + ug.inMarkAssist = s.g.inMarkAssist + ug.stackID = traceStack(0, gp, gen) + } + resumeG(s) + casgstatus(me, _Gwaiting, _Grunning) + }) + if ug.goid != 0 { + untracedGs = append(untracedGs, ug) + } + }) + + if !stopTrace { + // Re-register runtime goroutine labels and stop/block reasons. + traceRegisterLabelsAndReasons(traceNextGen(gen)) + } + + // Now that we've done some of the heavy stuff, prevent the world from stopping. + // This is necessary to ensure the consistency of the STW events. If we're feeling + // adventurous we could lift this restriction and add a STWActive event, but the + // cost of maintaining this consistency is low. We're not going to hold this semaphore + // for very long and most STW periods are very short. + // Once we hold worldsema, prevent preemption as well so we're not interrupted partway + // through this. We want to get this done as soon as possible. + semacquire(&worldsema) + mp := acquirem() + + // Advance the generation or stop the trace. + trace.lastNonZeroGen = gen + if stopTrace { + systemstack(func() { + // Ordering is important here. Set shutdown first, then disable tracing, + // so that conditions like (traceEnabled() || traceShuttingDown()) have + // no opportunity to be false. Hold the trace lock so this update appears + // atomic to the trace reader. + lock(&trace.lock) + trace.shutdown.Store(true) + trace.gen.Store(0) + unlock(&trace.lock) + + // Clear trace.enabled. It is totally OK for this value to be stale, + // because traceAcquire will always double-check gen. + trace.enabled = false + }) + } else { + trace.gen.Store(traceNextGen(gen)) + } + + // Emit a ProcsChange event so we have one on record for each generation. + // Let's emit it as soon as possible so that downstream tools can rely on the value + // being there fairly soon in a generation. + // + // It's important that we do this before allowing stop-the-worlds again, + // because the procs count could change. + if !stopTrace { + tl := traceAcquire() + tl.Gomaxprocs(gomaxprocs) + traceRelease(tl) + } + + // Emit a GCActive event in the new generation if necessary. + // + // It's important that we do this before allowing stop-the-worlds again, + // because that could emit global GC-related events. + if !stopTrace && (gcphase == _GCmark || gcphase == _GCmarktermination) { + tl := traceAcquire() + tl.GCActive() + traceRelease(tl) + } + + // Preemption is OK again after this. If the world stops or whatever it's fine. + // We're just cleaning up the last generation after this point. + // + // We also don't care if the GC starts again after this for the same reasons. + releasem(mp) + semrelease(&worldsema) + + // Snapshot allm and freem. + // + // Snapshotting after the generation counter update is sufficient. + // Because an m must be on either allm or sched.freem if it has an active trace + // buffer, new threads added to allm after this point must necessarily observe + // the new generation number (sched.lock acts as a barrier). + // + // Threads that exit before this point and are on neither list explicitly + // flush their own buffers in traceThreadDestroy. + // + // Snapshotting freem is necessary because Ms can continue to emit events + // while they're still on that list. Removal from sched.freem is serialized with + // this snapshot, so either we'll capture an m on sched.freem and race with + // the removal to flush its buffers (resolved by traceThreadDestroy acquiring + // the thread's seqlock, which one of us must win, so at least its old gen buffer + // will be flushed in time for the new generation) or it will have flushed its + // buffers before we snapshotted it to begin with. + lock(&sched.lock) + mToFlush := allm + for mp := mToFlush; mp != nil; mp = mp.alllink { + mp.trace.link = mp.alllink + } + for mp := sched.freem; mp != nil; mp = mp.freelink { + mp.trace.link = mToFlush + mToFlush = mp + } + unlock(&sched.lock) + + // Iterate over our snapshot, flushing every buffer until we're done. + // + // Because trace writers read the generation while the seqlock is + // held, we can be certain that when there are no writers there are + // also no stale generation values left. Therefore, it's safe to flush + // any buffers that remain in that generation's slot. + const debugDeadlock = false + systemstack(func() { + // Track iterations for some rudimentary deadlock detection. + i := 0 + detectedDeadlock := false + + for mToFlush != nil { + prev := &mToFlush + for mp := *prev; mp != nil; { + if mp.trace.seqlock.Load()%2 != 0 { + // The M is writing. Come back to it later. + prev = &mp.trace.link + mp = mp.trace.link + continue + } + // Flush the trace buffer. + // + // trace.lock needed for traceBufFlush, but also to synchronize + // with traceThreadDestroy, which flushes both buffers unconditionally. + lock(&trace.lock) + bufp := &mp.trace.buf[gen%2] + if *bufp != nil { + traceBufFlush(*bufp, gen) + *bufp = nil + } + unlock(&trace.lock) + + // Remove the m from the flush list. + *prev = mp.trace.link + mp.trace.link = nil + mp = *prev + } + // Yield only if we're going to be going around the loop again. + if mToFlush != nil { + osyield() + } + + if debugDeadlock { + // Try to detect a deadlock. We probably shouldn't loop here + // this many times. + if i > 100000 && !detectedDeadlock { + detectedDeadlock = true + println("runtime: failing to flush") + for mp := mToFlush; mp != nil; mp = mp.trace.link { + print("runtime: m=", mp.id, "\n") + } + } + i++ + } + } + }) + + // At this point, the old generation is fully flushed minus stack and string + // tables, CPU samples, and goroutines that haven't run at all during the last + // generation. + + // Check to see if any Gs still haven't had events written out for them. + statusWriter := unsafeTraceWriter(gen, nil) + for _, ug := range untracedGs { + if ug.gp.trace.statusWasTraced(gen) { + // It was traced, we don't need to do anything. + continue + } + // It still wasn't traced. Because we ensured all Ms stopped writing trace + // events to the last generation, that must mean the G never had its status + // traced in gen between when we recorded it and now. If that's true, the goid + // and status we recorded then is exactly what we want right now. + status := goStatusToTraceGoStatus(ug.status, ug.waitreason) + statusWriter = statusWriter.writeGoStatus(ug.goid, ug.mid, status, ug.inMarkAssist, ug.stackID) + } + statusWriter.flush().end() + + // Read everything out of the last gen's CPU profile buffer. + traceReadCPU(gen) + + // Flush CPU samples, stacks, and strings for the last generation. This is safe, + // because we're now certain no M is writing to the last generation. + // + // Ordering is important here. traceCPUFlush may generate new stacks and dumping + // stacks may generate new strings. + traceCPUFlush(gen) + trace.stackTab[gen%2].dump(gen) + trace.typeTab[gen%2].dump(gen) + trace.stringTab[gen%2].reset(gen) + + // That's it. This generation is done producing buffers. + systemstack(func() { + lock(&trace.lock) + trace.flushedGen.Store(gen) + unlock(&trace.lock) + }) + + // Perform status reset on dead Ps because they just appear as idle. + // + // Preventing preemption is sufficient to access allp safely. allp is only + // mutated by GOMAXPROCS calls, which require a STW. + // + // TODO(mknyszek): Consider explicitly emitting ProcCreate and ProcDestroy + // events to indicate whether a P exists, rather than just making its + // existence implicit. + mp = acquirem() + for _, pp := range allp[len(allp):cap(allp)] { + pp.trace.readyNextGen(traceNextGen(gen)) + } + releasem(mp) + + if stopTrace { + // Acquire the shutdown sema to begin the shutdown process. + semacquire(&traceShutdownSema) + + // Finish off CPU profile reading. + traceStopReadCPU() + + // Reset debug.malloc if necessary. Note that this is set in a racy + // way; that's OK. Some mallocs may still enter into the debug.malloc + // block, but they won't generate events because tracing is disabled. + // That is, it's OK if mallocs read a stale debug.malloc or + // trace.enabledWithAllocFree value. + if trace.enabledWithAllocFree { + trace.enabledWithAllocFree = false + debug.malloc = trace.debugMalloc + } + } else { + // Go over each P and emit a status event for it if necessary. + // + // We do this at the beginning of the new generation instead of the + // end like we do for goroutines because forEachP doesn't give us a + // hook to skip Ps that have already been traced. Since we have to + // preempt all Ps anyway, might as well stay consistent with StartTrace + // which does this during the STW. + semacquire(&worldsema) + forEachP(waitReasonTraceProcStatus, func(pp *p) { + tl := traceAcquire() + if !pp.trace.statusWasTraced(tl.gen) { + tl.writer().writeProcStatusForP(pp, false).end() + } + traceRelease(tl) + }) + semrelease(&worldsema) + } + + // Block until the trace reader has finished processing the last generation. + semacquire(&trace.doneSema[gen%2]) + if raceenabled { + raceacquire(unsafe.Pointer(&trace.doneSema[gen%2])) + } + + // Double-check that things look as we expect after advancing and perform some + // final cleanup if the trace has fully stopped. + systemstack(func() { + lock(&trace.lock) + if !trace.full[gen%2].empty() { + throw("trace: non-empty full trace buffer for done generation") + } + if stopTrace { + if !trace.full[1-(gen%2)].empty() { + throw("trace: non-empty full trace buffer for next generation") + } + if trace.reading != nil || trace.reader.Load() != nil { + throw("trace: reading after shutdown") + } + // Free all the empty buffers. + for trace.empty != nil { + buf := trace.empty + trace.empty = buf.link + sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf), &memstats.other_sys) + } + // Clear trace.shutdown and other flags. + trace.headerWritten = false + trace.shutdown.Store(false) + } + unlock(&trace.lock) + }) + + if stopTrace { + // Clear the sweep state on every P for the next time tracing is enabled. + // + // It may be stale in the next trace because we may have ended tracing in + // the middle of a sweep on a P. + // + // It's fine not to call forEachP here because tracing is disabled and we + // know at this point that nothing is calling into the tracer, but we do + // need to look at dead Ps too just because GOMAXPROCS could have been called + // at any point since we stopped tracing, and we have to ensure there's no + // bad state on dead Ps too. Prevent a STW and a concurrent GOMAXPROCS that + // might mutate allp by making ourselves briefly non-preemptible. + mp := acquirem() + for _, pp := range allp[:cap(allp)] { + pp.trace.inSweep = false + pp.trace.maySweep = false + pp.trace.swept = 0 + pp.trace.reclaimed = 0 + } + releasem(mp) + } + + // Release the advance semaphore. If stopTrace is true we're still holding onto + // traceShutdownSema. + // + // Do a direct handoff. Don't let one caller of traceAdvance starve + // other calls to traceAdvance. + semrelease1(&traceAdvanceSema, true, 0) + + if stopTrace { + // Stop the traceAdvancer. We can't be holding traceAdvanceSema here because + // we'll deadlock (we're blocked on the advancer goroutine exiting, but it + // may be currently trying to acquire traceAdvanceSema). + traceAdvancer.stop() + semrelease(&traceShutdownSema) + } +} + +func traceNextGen(gen uintptr) uintptr { + if gen == ^uintptr(0) { + // gen is used both %2 and %3 and we want both patterns to continue when we loop around. + // ^uint32(0) and ^uint64(0) are both odd and multiples of 3. Therefore the next generation + // we want is even and one more than a multiple of 3. The smallest such number is 4. + return 4 + } + return gen + 1 +} + +// traceRegisterLabelsAndReasons re-registers mark worker labels and +// goroutine stop/block reasons in the string table for the provided +// generation. Note: the provided generation must not have started yet. +func traceRegisterLabelsAndReasons(gen uintptr) { + for i, label := range gcMarkWorkerModeStrings[:] { + trace.markWorkerLabels[gen%2][i] = traceArg(trace.stringTab[gen%2].put(gen, label)) + } + for i, str := range traceBlockReasonStrings[:] { + trace.goBlockReasons[gen%2][i] = traceArg(trace.stringTab[gen%2].put(gen, str)) + } + for i, str := range traceGoStopReasonStrings[:] { + trace.goStopReasons[gen%2][i] = traceArg(trace.stringTab[gen%2].put(gen, str)) + } +} + +// ReadTrace returns the next chunk of binary tracing data, blocking until data +// is available. If tracing is turned off and all the data accumulated while it +// was on has been returned, ReadTrace returns nil. The caller must copy the +// returned data before calling ReadTrace again. +// ReadTrace must be called from one goroutine at a time. +func ReadTrace() []byte { +top: + var buf []byte + var park bool + systemstack(func() { + buf, park = readTrace0() + }) + if park { + gopark(func(gp *g, _ unsafe.Pointer) bool { + if !trace.reader.CompareAndSwapNoWB(nil, gp) { + // We're racing with another reader. + // Wake up and handle this case. + return false + } + + if g2 := traceReader(); gp == g2 { + // New data arrived between unlocking + // and the CAS and we won the wake-up + // race, so wake up directly. + return false + } else if g2 != nil { + printlock() + println("runtime: got trace reader", g2, g2.goid) + throw("unexpected trace reader") + } + + return true + }, nil, waitReasonTraceReaderBlocked, traceBlockSystemGoroutine, 2) + goto top + } + + return buf +} + +// readTrace0 is ReadTrace's continuation on g0. This must run on the +// system stack because it acquires trace.lock. +// +//go:systemstack +func readTrace0() (buf []byte, park bool) { + if raceenabled { + // g0 doesn't have a race context. Borrow the user G's. + if getg().racectx != 0 { + throw("expected racectx == 0") + } + getg().racectx = getg().m.curg.racectx + // (This defer should get open-coded, which is safe on + // the system stack.) + defer func() { getg().racectx = 0 }() + } + + // This function must not allocate while holding trace.lock: + // allocation can call heap allocate, which will try to emit a trace + // event while holding heap lock. + lock(&trace.lock) + + if trace.reader.Load() != nil { + // More than one goroutine reads trace. This is bad. + // But we rather do not crash the program because of tracing, + // because tracing can be enabled at runtime on prod servers. + unlock(&trace.lock) + println("runtime: ReadTrace called from multiple goroutines simultaneously") + return nil, false + } + // Recycle the old buffer. + if buf := trace.reading; buf != nil { + buf.link = trace.empty + trace.empty = buf + trace.reading = nil + } + // Write trace header. + if !trace.headerWritten { + trace.headerWritten = true + unlock(&trace.lock) + return []byte("go 1.23 trace\x00\x00\x00"), false + } + + // Read the next buffer. + + if trace.readerGen.Load() == 0 { + trace.readerGen.Store(1) + } + var gen uintptr + for { + assertLockHeld(&trace.lock) + gen = trace.readerGen.Load() + + // Check to see if we need to block for more data in this generation + // or if we need to move our generation forward. + if !trace.full[gen%2].empty() { + break + } + // Most of the time readerGen is one generation ahead of flushedGen, as the + // current generation is being read from. Then, once the last buffer is flushed + // into readerGen, flushedGen will rise to meet it. At this point, the tracer + // is waiting on the reader to finish flushing the last generation so that it + // can continue to advance. + if trace.flushedGen.Load() == gen { + if trace.shutdown.Load() { + unlock(&trace.lock) + + // Wake up anyone waiting for us to be done with this generation. + // + // Do this after reading trace.shutdown, because the thread we're + // waking up is going to clear trace.shutdown. + if raceenabled { + // Model synchronization on trace.doneSema, which te race + // detector does not see. This is required to avoid false + // race reports on writer passed to trace.Start. + racerelease(unsafe.Pointer(&trace.doneSema[gen%2])) + } + semrelease(&trace.doneSema[gen%2]) + + // We're shutting down, and the last generation is fully + // read. We're done. + return nil, false + } + // The previous gen has had all of its buffers flushed, and + // there's nothing else for us to read. Advance the generation + // we're reading from and try again. + trace.readerGen.Store(trace.gen.Load()) + unlock(&trace.lock) + + // Wake up anyone waiting for us to be done with this generation. + // + // Do this after reading gen to make sure we can't have the trace + // advance until we've read it. + if raceenabled { + // See comment above in the shutdown case. + racerelease(unsafe.Pointer(&trace.doneSema[gen%2])) + } + semrelease(&trace.doneSema[gen%2]) + + // Reacquire the lock and go back to the top of the loop. + lock(&trace.lock) + continue + } + // Wait for new data. + // + // We don't simply use a note because the scheduler + // executes this goroutine directly when it wakes up + // (also a note would consume an M). + // + // Before we drop the lock, clear the workAvailable flag. Work can + // only be queued with trace.lock held, so this is at least true until + // we drop the lock. + trace.workAvailable.Store(false) + unlock(&trace.lock) + return nil, true + } + // Pull a buffer. + tbuf := trace.full[gen%2].pop() + trace.reading = tbuf + unlock(&trace.lock) + return tbuf.arr[:tbuf.pos], false +} + +// traceReader returns the trace reader that should be woken up, if any. +// Callers should first check (traceEnabled() || traceShuttingDown()). +// +// This must run on the system stack because it acquires trace.lock. +// +//go:systemstack +func traceReader() *g { + gp := traceReaderAvailable() + if gp == nil || !trace.reader.CompareAndSwapNoWB(gp, nil) { + return nil + } + return gp +} + +// traceReaderAvailable returns the trace reader if it is not currently +// scheduled and should be. Callers should first check that +// (traceEnabled() || traceShuttingDown()) is true. +func traceReaderAvailable() *g { + // There are three conditions under which we definitely want to schedule + // the reader: + // - The reader is lagging behind in finishing off the last generation. + // In this case, trace buffers could even be empty, but the trace + // advancer will be waiting on the reader, so we have to make sure + // to schedule the reader ASAP. + // - The reader has pending work to process for it's reader generation + // (assuming readerGen is not lagging behind). Note that we also want + // to be careful *not* to schedule the reader if there's no work to do. + // - The trace is shutting down. The trace stopper blocks on the reader + // to finish, much like trace advancement. + // + // We also want to be careful not to schedule the reader if there's no + // reason to. + if trace.flushedGen.Load() == trace.readerGen.Load() || trace.workAvailable.Load() || trace.shutdown.Load() { + return trace.reader.Load() + } + return nil +} + +// Trace advancer goroutine. +var traceAdvancer traceAdvancerState + +type traceAdvancerState struct { + timer *wakeableSleep + done chan struct{} +} + +// start starts a new traceAdvancer. +func (s *traceAdvancerState) start() { + // Start a goroutine to periodically advance the trace generation. + s.done = make(chan struct{}) + s.timer = newWakeableSleep() + go func() { + for traceEnabled() { + // Set a timer to wake us up + s.timer.sleep(int64(debug.traceadvanceperiod)) + + // Try to advance the trace. + traceAdvance(false) + } + s.done <- struct{}{} + }() +} + +// stop stops a traceAdvancer and blocks until it exits. +func (s *traceAdvancerState) stop() { + s.timer.wake() + <-s.done + close(s.done) + s.timer.close() +} + +// traceAdvancePeriod is the approximate period between +// new generations. +const defaultTraceAdvancePeriod = 1e9 // 1 second. + +// wakeableSleep manages a wakeable goroutine sleep. +// +// Users of this type must call init before first use and +// close to free up resources. Once close is called, init +// must be called before another use. +type wakeableSleep struct { + timer *timer + + // lock protects access to wakeup, but not send/recv on it. + lock mutex + wakeup chan struct{} +} + +// newWakeableSleep initializes a new wakeableSleep and returns it. +func newWakeableSleep() *wakeableSleep { + s := new(wakeableSleep) + lockInit(&s.lock, lockRankWakeableSleep) + s.wakeup = make(chan struct{}, 1) + s.timer = new(timer) + f := func(s any, _ uintptr, _ int64) { + s.(*wakeableSleep).wake() + } + s.timer.init(f, s) + return s +} + +// sleep sleeps for the provided duration in nanoseconds or until +// another goroutine calls wake. +// +// Must not be called by more than one goroutine at a time and +// must not be called concurrently with close. +func (s *wakeableSleep) sleep(ns int64) { + s.timer.reset(nanotime()+ns, 0) + lock(&s.lock) + if raceenabled { + raceacquire(unsafe.Pointer(&s.lock)) + } + wakeup := s.wakeup + if raceenabled { + racerelease(unsafe.Pointer(&s.lock)) + } + unlock(&s.lock) + <-wakeup + s.timer.stop() +} + +// wake awakens any goroutine sleeping on the timer. +// +// Safe for concurrent use with all other methods. +func (s *wakeableSleep) wake() { + // Grab the wakeup channel, which may be nil if we're + // racing with close. + lock(&s.lock) + if raceenabled { + raceacquire(unsafe.Pointer(&s.lock)) + } + if s.wakeup != nil { + // Non-blocking send. + // + // Others may also write to this channel and we don't + // want to block on the receiver waking up. This also + // effectively batches together wakeup notifications. + select { + case s.wakeup <- struct{}{}: + default: + } + } + if raceenabled { + racerelease(unsafe.Pointer(&s.lock)) + } + unlock(&s.lock) +} + +// close wakes any goroutine sleeping on the timer and prevents +// further sleeping on it. +// +// Once close is called, the wakeableSleep must no longer be used. +// +// It must only be called once no goroutine is sleeping on the +// timer *and* nothing else will call wake concurrently. +func (s *wakeableSleep) close() { + // Set wakeup to nil so that a late timer ends up being a no-op. + lock(&s.lock) + if raceenabled { + raceacquire(unsafe.Pointer(&s.lock)) + } + wakeup := s.wakeup + s.wakeup = nil + + // Close the channel. + close(wakeup) + + if raceenabled { + racerelease(unsafe.Pointer(&s.lock)) + } + unlock(&s.lock) + return +} diff --git a/contrib/go/_std_1.22/src/runtime/trace/annotation.go b/contrib/go/_std_1.23/src/runtime/trace/annotation.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/trace/annotation.go rename to contrib/go/_std_1.23/src/runtime/trace/annotation.go diff --git a/contrib/go/_std_1.22/src/runtime/trace/trace.go b/contrib/go/_std_1.23/src/runtime/trace/trace.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/trace/trace.go rename to contrib/go/_std_1.23/src/runtime/trace/trace.go diff --git a/contrib/go/_std_1.22/src/runtime/trace/ya.make b/contrib/go/_std_1.23/src/runtime/trace/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/trace/ya.make rename to contrib/go/_std_1.23/src/runtime/trace/ya.make diff --git a/contrib/go/_std_1.23/src/runtime/traceallocfree.go b/contrib/go/_std_1.23/src/runtime/traceallocfree.go new file mode 100644 index 000000000000..e6a2a79c691b --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/traceallocfree.go @@ -0,0 +1,162 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Runtime -> tracer API for memory events. + +package runtime + +import ( + "internal/abi" + "runtime/internal/sys" +) + +// Batch type values for the alloc/free experiment. +const ( + traceAllocFreeTypesBatch = iota // Contains types. [{id, address, size, ptrspan, name length, name string} ...] + traceAllocFreeInfoBatch // Contains info for interpreting events. [min heap addr, page size, min heap align, min stack align] +) + +// traceSnapshotMemory takes a snapshot of all runtime memory that there are events for +// (heap spans, heap objects, goroutine stacks, etc.) and writes out events for them. +// +// The world must be stopped and tracing must be enabled when this function is called. +func traceSnapshotMemory(gen uintptr) { + assertWorldStopped() + + // Write a batch containing information that'll be necessary to + // interpret the events. + var flushed bool + w := unsafeTraceExpWriter(gen, nil, traceExperimentAllocFree) + w, flushed = w.ensure(1 + 4*traceBytesPerNumber) + if flushed { + // Annotate the batch as containing additional info. + w.byte(byte(traceAllocFreeInfoBatch)) + } + + // Emit info. + w.varint(uint64(trace.minPageHeapAddr)) + w.varint(uint64(pageSize)) + w.varint(uint64(minHeapAlign)) + w.varint(uint64(fixedStack)) + + // Finish writing the batch. + w.flush().end() + + // Start tracing. + trace := traceAcquire() + if !trace.ok() { + throw("traceSnapshotMemory: tracing is not enabled") + } + + // Write out all the heap spans and heap objects. + for _, s := range mheap_.allspans { + if s.state.get() == mSpanDead { + continue + } + // It's some kind of span, so trace that it exists. + trace.SpanExists(s) + + // Write out allocated objects if it's a heap span. + if s.state.get() != mSpanInUse { + continue + } + + // Find all allocated objects. + abits := s.allocBitsForIndex(0) + for i := uintptr(0); i < uintptr(s.nelems); i++ { + if abits.index < uintptr(s.freeindex) || abits.isMarked() { + x := s.base() + i*s.elemsize + trace.HeapObjectExists(x, s.typePointersOfUnchecked(x).typ) + } + abits.advance() + } + } + + // Write out all the goroutine stacks. + forEachGRace(func(gp *g) { + trace.GoroutineStackExists(gp.stack.lo, gp.stack.hi-gp.stack.lo) + }) + traceRelease(trace) +} + +func traceSpanTypeAndClass(s *mspan) traceArg { + if s.state.get() == mSpanInUse { + return traceArg(s.spanclass) << 1 + } + return traceArg(1) +} + +// SpanExists records an event indicating that the span exists. +func (tl traceLocker) SpanExists(s *mspan) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSpan, traceSpanID(s), traceArg(s.npages), traceSpanTypeAndClass(s)) +} + +// SpanAlloc records an event indicating that the span has just been allocated. +func (tl traceLocker) SpanAlloc(s *mspan) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSpanAlloc, traceSpanID(s), traceArg(s.npages), traceSpanTypeAndClass(s)) +} + +// SpanFree records an event indicating that the span is about to be freed. +func (tl traceLocker) SpanFree(s *mspan) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSpanFree, traceSpanID(s)) +} + +// traceSpanID creates a trace ID for the span s for the trace. +func traceSpanID(s *mspan) traceArg { + return traceArg(uint64(s.base())-trace.minPageHeapAddr) / pageSize +} + +// HeapObjectExists records that an object already exists at addr with the provided type. +// The type is optional, and the size of the slot occupied the object is inferred from the +// span containing it. +func (tl traceLocker) HeapObjectExists(addr uintptr, typ *abi.Type) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapObject, traceHeapObjectID(addr), tl.rtype(typ)) +} + +// HeapObjectAlloc records that an object was newly allocated at addr with the provided type. +// The type is optional, and the size of the slot occupied the object is inferred from the +// span containing it. +func (tl traceLocker) HeapObjectAlloc(addr uintptr, typ *abi.Type) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapObjectAlloc, traceHeapObjectID(addr), tl.rtype(typ)) +} + +// HeapObjectFree records that an object at addr is about to be freed. +func (tl traceLocker) HeapObjectFree(addr uintptr) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapObjectFree, traceHeapObjectID(addr)) +} + +// traceHeapObjectID creates a trace ID for a heap object at address addr. +func traceHeapObjectID(addr uintptr) traceArg { + return traceArg(uint64(addr)-trace.minPageHeapAddr) / minHeapAlign +} + +// GoroutineStackExists records that a goroutine stack already exists at address base with the provided size. +func (tl traceLocker) GoroutineStackExists(base, size uintptr) { + order := traceCompressStackSize(size) + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoroutineStack, traceGoroutineStackID(base), order) +} + +// GoroutineStackAlloc records that a goroutine stack was newly allocated at address base with the provided size.. +func (tl traceLocker) GoroutineStackAlloc(base, size uintptr) { + order := traceCompressStackSize(size) + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoroutineStackAlloc, traceGoroutineStackID(base), order) +} + +// GoroutineStackFree records that a goroutine stack at address base is about to be freed. +func (tl traceLocker) GoroutineStackFree(base uintptr) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoroutineStackFree, traceGoroutineStackID(base)) +} + +// traceGoroutineStackID creates a trace ID for the goroutine stack from its base address. +func traceGoroutineStackID(base uintptr) traceArg { + return traceArg(uint64(base)-trace.minPageHeapAddr) / fixedStack +} + +// traceCompressStackSize assumes size is a power of 2 and returns log2(size). +func traceCompressStackSize(size uintptr) traceArg { + if size&(size-1) != 0 { + throw("goroutine stack size is not a power of 2") + } + return traceArg(sys.Len64(uint64(size))) +} diff --git a/contrib/go/_std_1.22/src/runtime/traceback.go b/contrib/go/_std_1.23/src/runtime/traceback.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/traceback.go rename to contrib/go/_std_1.23/src/runtime/traceback.go index 1e5afc6bdde6..03c02f77713a 100644 --- a/contrib/go/_std_1.22/src/runtime/traceback.go +++ b/contrib/go/_std_1.23/src/runtime/traceback.go @@ -8,6 +8,7 @@ import ( "internal/abi" "internal/bytealg" "internal/goarch" + "internal/stringslite" "runtime/internal/sys" "unsafe" ) @@ -182,8 +183,8 @@ func (u *unwinder) initAt(pc0, sp0, lr0 uintptr, gp *g, flags unwindFlags) { } } - // runtime/internal/atomic functions call into kernel helpers on - // arm < 7. See runtime/internal/atomic/sys_linux_arm.s. + // internal/runtime/atomic functions call into kernel helpers on + // arm < 7. See internal/runtime/atomic/sys_linux_arm.s. // // Start in the caller's frame. if GOARCH == "arm" && goarm < 7 && GOOS == "linux" && frame.pc&0xffff0000 == 0xffff0000 { @@ -632,8 +633,11 @@ func tracebackPCs(u *unwinder, skip int, pcBuf []uintptr) int { skip-- } else { // Callers expect the pc buffer to contain return addresses - // and do the -1 themselves, so we add 1 to the call PC to - // create a return PC. + // and do the -1 themselves, so we add 1 to the call pc to + // create a "return pc". Since there is no actual call, here + // "return pc" just means a pc you subtract 1 from to get + // the pc of the "call". The actual no-op we insert may or + // may not be 1 byte. pcBuf[n] = uf.pc + 1 n++ } @@ -650,25 +654,7 @@ func tracebackPCs(u *unwinder, skip int, pcBuf []uintptr) int { // printArgs prints function arguments in traceback. func printArgs(f funcInfo, argp unsafe.Pointer, pc uintptr) { - // The "instruction" of argument printing is encoded in _FUNCDATA_ArgInfo. - // See cmd/compile/internal/ssagen.emitArgInfo for the description of the - // encoding. - // These constants need to be in sync with the compiler. - const ( - _endSeq = 0xff - _startAgg = 0xfe - _endAgg = 0xfd - _dotdotdot = 0xfc - _offsetTooLarge = 0xfb - ) - - const ( - limit = 10 // print no more than 10 args/components - maxDepth = 5 // no more than 5 layers of nesting - maxLen = (maxDepth*3+2)*limit + 1 // max length of _FUNCDATA_ArgInfo (see the compiler side for reasoning) - ) - - p := (*[maxLen]uint8)(funcdata(f, abi.FUNCDATA_ArgInfo)) + p := (*[abi.TraceArgsMaxLen]uint8)(funcdata(f, abi.FUNCDATA_ArgInfo)) if p == nil { return } @@ -721,19 +707,19 @@ printloop: o := p[pi] pi++ switch o { - case _endSeq: + case abi.TraceArgsEndSeq: break printloop - case _startAgg: + case abi.TraceArgsStartAgg: printcomma() print("{") start = true continue - case _endAgg: + case abi.TraceArgsEndAgg: print("}") - case _dotdotdot: + case abi.TraceArgsDotdotdot: printcomma() print("...") - case _offsetTooLarge: + case abi.TraceArgsOffsetTooLarge: printcomma() print("_") default: @@ -1093,6 +1079,16 @@ func printAncestorTracebackFuncInfo(f funcInfo, pc uintptr) { print("\n") } +// callers should be an internal detail, +// (and is almost identical to Callers), +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname callers func callers(skip int, pcbuf []uintptr) int { sp := getcallersp() pc := getcallerpc() @@ -1146,15 +1142,37 @@ func showfuncinfo(sf srcFunc, firstFrame bool, calleeID abi.FuncID) bool { return true } - return bytealg.IndexByteString(name, '.') >= 0 && (!hasPrefix(name, "runtime.") || isExportedRuntime(name)) + return bytealg.IndexByteString(name, '.') >= 0 && (!stringslite.HasPrefix(name, "runtime.") || isExportedRuntime(name)) } // isExportedRuntime reports whether name is an exported runtime function. // It is only for runtime functions, so ASCII A-Z is fine. -// TODO: this handles exported functions but not exported methods. func isExportedRuntime(name string) bool { - const n = len("runtime.") - return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' + // Check and remove package qualifier. + n := len("runtime.") + if len(name) <= n || name[:n] != "runtime." { + return false + } + name = name[n:] + rcvr := "" + + // Extract receiver type, if any. + // For example, runtime.(*Func).Entry + i := len(name) - 1 + for i >= 0 && name[i] != '.' { + i-- + } + if i >= 0 { + rcvr = name[:i] + name = name[i+1:] + // Remove parentheses and star for pointer receivers. + if len(rcvr) >= 3 && rcvr[0] == '(' && rcvr[1] == '*' && rcvr[len(rcvr)-1] == ')' { + rcvr = rcvr[2 : len(rcvr)-1] + } + } + + // Exported functions and exported methods on exported types. + return len(name) > 0 && 'A' <= name[0] && name[0] <= 'Z' && (len(rcvr) == 0 || 'A' <= rcvr[0] && rcvr[0] <= 'Z') } // elideWrapperCalling reports whether a wrapper function that called @@ -1335,7 +1353,7 @@ func isSystemGoroutine(gp *g, fixed bool) bool { } return fingStatus.Load()&fingRunningFinalizer == 0 } - return hasPrefix(funcname(f), "runtime.") + return stringslite.HasPrefix(funcname(f), "runtime.") } // SetCgoTraceback records three C functions to use to gather diff --git a/contrib/go/_std_1.23/src/runtime/tracebuf.go b/contrib/go/_std_1.23/src/runtime/tracebuf.go new file mode 100644 index 000000000000..db4adf53e986 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracebuf.go @@ -0,0 +1,264 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Trace buffer management. + +package runtime + +import ( + "runtime/internal/sys" + "unsafe" +) + +// Maximum number of bytes required to encode uint64 in base-128. +const traceBytesPerNumber = 10 + +// traceWriter is the interface for writing all trace data. +// +// This type is passed around as a value, and all of its methods return +// a new traceWriter. This allows for chaining together calls in a fluent-style +// API. This is partly stylistic, and very slightly for performance, since +// the compiler can destructure this value and pass it between calls as +// just regular arguments. However, this style is not load-bearing, and +// we can change it if it's deemed too error-prone. +type traceWriter struct { + traceLocker + *traceBuf +} + +// write returns an a traceWriter that writes into the current M's stream. +func (tl traceLocker) writer() traceWriter { + return traceWriter{traceLocker: tl, traceBuf: tl.mp.trace.buf[tl.gen%2]} +} + +// unsafeTraceWriter produces a traceWriter that doesn't lock the trace. +// +// It should only be used in contexts where either: +// - Another traceLocker is held. +// - trace.gen is prevented from advancing. +// +// buf may be nil. +func unsafeTraceWriter(gen uintptr, buf *traceBuf) traceWriter { + return traceWriter{traceLocker: traceLocker{gen: gen}, traceBuf: buf} +} + +// end writes the buffer back into the m. +func (w traceWriter) end() { + if w.mp == nil { + // Tolerate a nil mp. It makes code that creates traceWriters directly + // less error-prone. + return + } + w.mp.trace.buf[w.gen%2] = w.traceBuf +} + +// ensure makes sure that at least maxSize bytes are available to write. +// +// Returns whether the buffer was flushed. +func (w traceWriter) ensure(maxSize int) (traceWriter, bool) { + refill := w.traceBuf == nil || !w.available(maxSize) + if refill { + w = w.refill(traceNoExperiment) + } + return w, refill +} + +// flush puts w.traceBuf on the queue of full buffers. +func (w traceWriter) flush() traceWriter { + systemstack(func() { + lock(&trace.lock) + if w.traceBuf != nil { + traceBufFlush(w.traceBuf, w.gen) + } + unlock(&trace.lock) + }) + w.traceBuf = nil + return w +} + +// refill puts w.traceBuf on the queue of full buffers and refresh's w's buffer. +// +// exp indicates whether the refilled batch should be EvExperimentalBatch. +func (w traceWriter) refill(exp traceExperiment) traceWriter { + systemstack(func() { + lock(&trace.lock) + if w.traceBuf != nil { + traceBufFlush(w.traceBuf, w.gen) + } + if trace.empty != nil { + w.traceBuf = trace.empty + trace.empty = w.traceBuf.link + unlock(&trace.lock) + } else { + unlock(&trace.lock) + w.traceBuf = (*traceBuf)(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys)) + if w.traceBuf == nil { + throw("trace: out of memory") + } + } + }) + // Initialize the buffer. + ts := traceClockNow() + if ts <= w.traceBuf.lastTime { + ts = w.traceBuf.lastTime + 1 + } + w.traceBuf.lastTime = ts + w.traceBuf.link = nil + w.traceBuf.pos = 0 + + // Tolerate a nil mp. + mID := ^uint64(0) + if w.mp != nil { + mID = uint64(w.mp.procid) + } + + // Write the buffer's header. + if exp == traceNoExperiment { + w.byte(byte(traceEvEventBatch)) + } else { + w.byte(byte(traceEvExperimentalBatch)) + w.byte(byte(exp)) + } + w.varint(uint64(w.gen)) + w.varint(uint64(mID)) + w.varint(uint64(ts)) + w.traceBuf.lenPos = w.varintReserve() + return w +} + +// traceBufQueue is a FIFO of traceBufs. +type traceBufQueue struct { + head, tail *traceBuf +} + +// push queues buf into queue of buffers. +func (q *traceBufQueue) push(buf *traceBuf) { + buf.link = nil + if q.head == nil { + q.head = buf + } else { + q.tail.link = buf + } + q.tail = buf +} + +// pop dequeues from the queue of buffers. +func (q *traceBufQueue) pop() *traceBuf { + buf := q.head + if buf == nil { + return nil + } + q.head = buf.link + if q.head == nil { + q.tail = nil + } + buf.link = nil + return buf +} + +func (q *traceBufQueue) empty() bool { + return q.head == nil +} + +// traceBufHeader is per-P tracing buffer. +type traceBufHeader struct { + link *traceBuf // in trace.empty/full + lastTime traceTime // when we wrote the last event + pos int // next write offset in arr + lenPos int // position of batch length value +} + +// traceBuf is per-M tracing buffer. +// +// TODO(mknyszek): Rename traceBuf to traceBatch, since they map 1:1 with event batches. +type traceBuf struct { + _ sys.NotInHeap + traceBufHeader + arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf +} + +// byte appends v to buf. +func (buf *traceBuf) byte(v byte) { + buf.arr[buf.pos] = v + buf.pos++ +} + +// varint appends v to buf in little-endian-base-128 encoding. +func (buf *traceBuf) varint(v uint64) { + pos := buf.pos + arr := buf.arr[pos : pos+traceBytesPerNumber] + for i := range arr { + if v < 0x80 { + pos += i + 1 + arr[i] = byte(v) + break + } + arr[i] = 0x80 | byte(v) + v >>= 7 + } + buf.pos = pos +} + +// varintReserve reserves enough space in buf to hold any varint. +// +// Space reserved this way can be filled in with the varintAt method. +func (buf *traceBuf) varintReserve() int { + p := buf.pos + buf.pos += traceBytesPerNumber + return p +} + +// stringData appends s's data directly to buf. +func (buf *traceBuf) stringData(s string) { + buf.pos += copy(buf.arr[buf.pos:], s) +} + +func (buf *traceBuf) available(size int) bool { + return len(buf.arr)-buf.pos >= size +} + +// varintAt writes varint v at byte position pos in buf. This always +// consumes traceBytesPerNumber bytes. This is intended for when the caller +// needs to reserve space for a varint but can't populate it until later. +// Use varintReserve to reserve this space. +func (buf *traceBuf) varintAt(pos int, v uint64) { + for i := 0; i < traceBytesPerNumber; i++ { + if i < traceBytesPerNumber-1 { + buf.arr[pos] = 0x80 | byte(v) + } else { + buf.arr[pos] = byte(v) + } + v >>= 7 + pos++ + } + if v != 0 { + throw("v could not fit in traceBytesPerNumber") + } +} + +// traceBufFlush flushes a trace buffer. +// +// Must run on the system stack because trace.lock must be held. +// +//go:systemstack +func traceBufFlush(buf *traceBuf, gen uintptr) { + assertLockHeld(&trace.lock) + + // Write out the non-header length of the batch in the header. + // + // Note: the length of the header is not included to make it easier + // to calculate this value when deserializing and reserializing the + // trace. Varints can have additional padding of zero bits that is + // quite difficult to preserve, and if we include the header we + // force serializers to do more work. Nothing else actually needs + // padding. + buf.varintAt(buf.lenPos, uint64(buf.pos-(buf.lenPos+traceBytesPerNumber))) + trace.full[gen%2].push(buf) + + // Notify the scheduler that there's work available and that the trace + // reader should be scheduled. + if !trace.workAvailable.Load() { + trace.workAvailable.Store(true) + } +} diff --git a/contrib/go/_std_1.23/src/runtime/tracecpu.go b/contrib/go/_std_1.23/src/runtime/tracecpu.go new file mode 100644 index 000000000000..c8a6f56ff2f6 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracecpu.go @@ -0,0 +1,280 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// CPU profile -> trace + +package runtime + +// traceInitReadCPU initializes CPU profile -> tracer state for tracing. +// +// Returns a profBuf for reading from. +func traceInitReadCPU() { + if traceEnabled() { + throw("traceInitReadCPU called with trace enabled") + } + // Create new profBuf for CPU samples that will be emitted as events. + // Format: after the timestamp, header is [pp.id, gp.goid, mp.procid]. + trace.cpuLogRead[0] = newProfBuf(3, profBufWordCount, profBufTagCount) + trace.cpuLogRead[1] = newProfBuf(3, profBufWordCount, profBufTagCount) + // We must not acquire trace.signalLock outside of a signal handler: a + // profiling signal may arrive at any time and try to acquire it, leading to + // deadlock. Because we can't use that lock to protect updates to + // trace.cpuLogWrite (only use of the structure it references), reads and + // writes of the pointer must be atomic. (And although this field is never + // the sole pointer to the profBuf value, it's best to allow a write barrier + // here.) + trace.cpuLogWrite[0].Store(trace.cpuLogRead[0]) + trace.cpuLogWrite[1].Store(trace.cpuLogRead[1]) +} + +// traceStartReadCPU creates a goroutine to start reading CPU profile +// data into an active trace. +// +// traceAdvanceSema must be held. +func traceStartReadCPU() { + if !traceEnabled() { + throw("traceStartReadCPU called with trace disabled") + } + // Spin up the logger goroutine. + trace.cpuSleep = newWakeableSleep() + done := make(chan struct{}, 1) + go func() { + for traceEnabled() { + // Sleep here because traceReadCPU is non-blocking. This mirrors + // how the runtime/pprof package obtains CPU profile data. + // + // We can't do a blocking read here because Darwin can't do a + // wakeup from a signal handler, so all CPU profiling is just + // non-blocking. See #61768 for more details. + // + // Like the runtime/pprof package, even if that bug didn't exist + // we would still want to do a goroutine-level sleep in between + // reads to avoid frequent wakeups. + trace.cpuSleep.sleep(100_000_000) + + tl := traceAcquire() + if !tl.ok() { + // Tracing disabled. + break + } + keepGoing := traceReadCPU(tl.gen) + traceRelease(tl) + if !keepGoing { + break + } + } + done <- struct{}{} + }() + trace.cpuLogDone = done +} + +// traceStopReadCPU blocks until the trace CPU reading goroutine exits. +// +// traceAdvanceSema must be held, and tracing must be disabled. +func traceStopReadCPU() { + if traceEnabled() { + throw("traceStopReadCPU called with trace enabled") + } + + // Once we close the profbuf, we'll be in one of two situations: + // - The logger goroutine has already exited because it observed + // that the trace is disabled. + // - The logger goroutine is asleep. + // + // Wake the goroutine so it can observe that their the buffer is + // closed an exit. + trace.cpuLogWrite[0].Store(nil) + trace.cpuLogWrite[1].Store(nil) + trace.cpuLogRead[0].close() + trace.cpuLogRead[1].close() + trace.cpuSleep.wake() + + // Wait until the logger goroutine exits. + <-trace.cpuLogDone + + // Clear state for the next trace. + trace.cpuLogDone = nil + trace.cpuLogRead[0] = nil + trace.cpuLogRead[1] = nil + trace.cpuSleep.close() +} + +// traceReadCPU attempts to read from the provided profBuf[gen%2] and write +// into the trace. Returns true if there might be more to read or false +// if the profBuf is closed or the caller should otherwise stop reading. +// +// The caller is responsible for ensuring that gen does not change. Either +// the caller must be in a traceAcquire/traceRelease block, or must be calling +// with traceAdvanceSema held. +// +// No more than one goroutine may be in traceReadCPU for the same +// profBuf at a time. +// +// Must not run on the system stack because profBuf.read performs race +// operations. +func traceReadCPU(gen uintptr) bool { + var pcBuf [traceStackSize]uintptr + + data, tags, eof := trace.cpuLogRead[gen%2].read(profBufNonBlocking) + for len(data) > 0 { + if len(data) < 4 || data[0] > uint64(len(data)) { + break // truncated profile + } + if data[0] < 4 || tags != nil && len(tags) < 1 { + break // malformed profile + } + if len(tags) < 1 { + break // mismatched profile records and tags + } + + // Deserialize the data in the profile buffer. + recordLen := data[0] + timestamp := data[1] + ppid := data[2] >> 1 + if hasP := (data[2] & 0b1) != 0; !hasP { + ppid = ^uint64(0) + } + goid := data[3] + mpid := data[4] + stk := data[5:recordLen] + + // Overflow records always have their headers contain + // all zeroes. + isOverflowRecord := len(stk) == 1 && data[2] == 0 && data[3] == 0 && data[4] == 0 + + // Move the data iterator forward. + data = data[recordLen:] + // No support here for reporting goroutine tags at the moment; if + // that information is to be part of the execution trace, we'd + // probably want to see when the tags are applied and when they + // change, instead of only seeing them when we get a CPU sample. + tags = tags[1:] + + if isOverflowRecord { + // Looks like an overflow record from the profBuf. Not much to + // do here, we only want to report full records. + continue + } + + // Construct the stack for insertion to the stack table. + nstk := 1 + pcBuf[0] = logicalStackSentinel + for ; nstk < len(pcBuf) && nstk-1 < len(stk); nstk++ { + pcBuf[nstk] = uintptr(stk[nstk-1]) + } + + // Write out a trace event. + w := unsafeTraceWriter(gen, trace.cpuBuf[gen%2]) + + // Ensure we have a place to write to. + var flushed bool + w, flushed = w.ensure(2 + 5*traceBytesPerNumber /* traceEvCPUSamples + traceEvCPUSample + timestamp + g + m + p + stack ID */) + if flushed { + // Annotate the batch as containing strings. + w.byte(byte(traceEvCPUSamples)) + } + + // Add the stack to the table. + stackID := trace.stackTab[gen%2].put(pcBuf[:nstk]) + + // Write out the CPU sample. + w.byte(byte(traceEvCPUSample)) + w.varint(timestamp) + w.varint(mpid) + w.varint(ppid) + w.varint(goid) + w.varint(stackID) + + trace.cpuBuf[gen%2] = w.traceBuf + } + return !eof +} + +// traceCPUFlush flushes trace.cpuBuf[gen%2]. The caller must be certain that gen +// has completed and that there are no more writers to it. +func traceCPUFlush(gen uintptr) { + // Flush any remaining trace buffers containing CPU samples. + if buf := trace.cpuBuf[gen%2]; buf != nil { + systemstack(func() { + lock(&trace.lock) + traceBufFlush(buf, gen) + unlock(&trace.lock) + trace.cpuBuf[gen%2] = nil + }) + } +} + +// traceCPUSample writes a CPU profile sample stack to the execution tracer's +// profiling buffer. It is called from a signal handler, so is limited in what +// it can do. mp must be the thread that is currently stopped in a signal. +func traceCPUSample(gp *g, mp *m, pp *p, stk []uintptr) { + if !traceEnabled() { + // Tracing is usually turned off; don't spend time acquiring the signal + // lock unless it's active. + return + } + if mp == nil { + // Drop samples that don't have an identifiable thread. We can't render + // this in any useful way anyway. + return + } + + // We're going to conditionally write to one of two buffers based on the + // generation. To make sure we write to the correct one, we need to make + // sure this thread's trace seqlock is held. If it already is, then we're + // in the tracer and we can just take advantage of that. If it isn't, then + // we need to acquire it and read the generation. + locked := false + if mp.trace.seqlock.Load()%2 == 0 { + mp.trace.seqlock.Add(1) + locked = true + } + gen := trace.gen.Load() + if gen == 0 { + // Tracing is disabled, as it turns out. Release the seqlock if necessary + // and exit. + if locked { + mp.trace.seqlock.Add(1) + } + return + } + + now := traceClockNow() + // The "header" here is the ID of the M that was running the profiled code, + // followed by the IDs of the P and goroutine. (For normal CPU profiling, it's + // usually the number of samples with the given stack.) Near syscalls, pp + // may be nil. Reporting goid of 0 is fine for either g0 or a nil gp. + var hdr [3]uint64 + if pp != nil { + // Overflow records in profBuf have all header values set to zero. Make + // sure that real headers have at least one bit set. + hdr[0] = uint64(pp.id)<<1 | 0b1 + } else { + hdr[0] = 0b10 + } + if gp != nil { + hdr[1] = gp.goid + } + hdr[2] = uint64(mp.procid) + + // Allow only one writer at a time + for !trace.signalLock.CompareAndSwap(0, 1) { + // TODO: Is it safe to osyield here? https://go.dev/issue/52672 + osyield() + } + + if log := trace.cpuLogWrite[gen%2].Load(); log != nil { + // Note: we don't pass a tag pointer here (how should profiling tags + // interact with the execution tracer?), but if we did we'd need to be + // careful about write barriers. See the long comment in profBuf.write. + log.write(nil, int64(now), hdr[:], stk) + } + + trace.signalLock.Store(0) + + // Release the seqlock if we acquired it earlier. + if locked { + mp.trace.seqlock.Add(1) + } +} diff --git a/contrib/go/_std_1.23/src/runtime/traceevent.go b/contrib/go/_std_1.23/src/runtime/traceevent.go new file mode 100644 index 000000000000..2a869fb51509 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/traceevent.go @@ -0,0 +1,209 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Trace event writing API for trace2runtime.go. + +package runtime + +import ( + "internal/abi" + "runtime/internal/sys" +) + +// Event types in the trace, args are given in square brackets. +// +// Naming scheme: +// - Time range event pairs have suffixes "Begin" and "End". +// - "Start", "Stop", "Create", "Destroy", "Block", "Unblock" +// are suffixes reserved for scheduling resources. +// +// NOTE: If you add an event type, make sure you also update all +// tables in this file! +type traceEv uint8 + +const ( + traceEvNone traceEv = iota // unused + + // Structural events. + traceEvEventBatch // start of per-M batch of events [generation, M ID, timestamp, batch length] + traceEvStacks // start of a section of the stack table [...traceEvStack] + traceEvStack // stack table entry [ID, ...{PC, func string ID, file string ID, line #}] + traceEvStrings // start of a section of the string dictionary [...traceEvString] + traceEvString // string dictionary entry [ID, length, string] + traceEvCPUSamples // start of a section of CPU samples [...traceEvCPUSample] + traceEvCPUSample // CPU profiling sample [timestamp, M ID, P ID, goroutine ID, stack ID] + traceEvFrequency // timestamp units per sec [freq] + + // Procs. + traceEvProcsChange // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack ID] + traceEvProcStart // start of P [timestamp, P ID, P seq] + traceEvProcStop // stop of P [timestamp] + traceEvProcSteal // P was stolen [timestamp, P ID, P seq, M ID] + traceEvProcStatus // P status at the start of a generation [timestamp, P ID, status] + + // Goroutines. + traceEvGoCreate // goroutine creation [timestamp, new goroutine ID, new stack ID, stack ID] + traceEvGoCreateSyscall // goroutine appears in syscall (cgo callback) [timestamp, new goroutine ID] + traceEvGoStart // goroutine starts running [timestamp, goroutine ID, goroutine seq] + traceEvGoDestroy // goroutine ends [timestamp] + traceEvGoDestroySyscall // goroutine ends in syscall (cgo callback) [timestamp] + traceEvGoStop // goroutine yields its time, but is runnable [timestamp, reason, stack ID] + traceEvGoBlock // goroutine blocks [timestamp, reason, stack ID] + traceEvGoUnblock // goroutine is unblocked [timestamp, goroutine ID, goroutine seq, stack ID] + traceEvGoSyscallBegin // syscall enter [timestamp, P seq, stack ID] + traceEvGoSyscallEnd // syscall exit [timestamp] + traceEvGoSyscallEndBlocked // syscall exit and it blocked at some point [timestamp] + traceEvGoStatus // goroutine status at the start of a generation [timestamp, goroutine ID, M ID, status] + + // STW. + traceEvSTWBegin // STW start [timestamp, kind] + traceEvSTWEnd // STW done [timestamp] + + // GC events. + traceEvGCActive // GC active [timestamp, seq] + traceEvGCBegin // GC start [timestamp, seq, stack ID] + traceEvGCEnd // GC done [timestamp, seq] + traceEvGCSweepActive // GC sweep active [timestamp, P ID] + traceEvGCSweepBegin // GC sweep start [timestamp, stack ID] + traceEvGCSweepEnd // GC sweep done [timestamp, swept bytes, reclaimed bytes] + traceEvGCMarkAssistActive // GC mark assist active [timestamp, goroutine ID] + traceEvGCMarkAssistBegin // GC mark assist start [timestamp, stack ID] + traceEvGCMarkAssistEnd // GC mark assist done [timestamp] + traceEvHeapAlloc // gcController.heapLive change [timestamp, heap alloc in bytes] + traceEvHeapGoal // gcController.heapGoal() change [timestamp, heap goal in bytes] + + // Annotations. + traceEvGoLabel // apply string label to current running goroutine [timestamp, label string ID] + traceEvUserTaskBegin // trace.NewTask [timestamp, internal task ID, internal parent task ID, name string ID, stack ID] + traceEvUserTaskEnd // end of a task [timestamp, internal task ID, stack ID] + traceEvUserRegionBegin // trace.{Start,With}Region [timestamp, internal task ID, name string ID, stack ID] + traceEvUserRegionEnd // trace.{End,With}Region [timestamp, internal task ID, name string ID, stack ID] + traceEvUserLog // trace.Log [timestamp, internal task ID, key string ID, stack, value string ID] + + // Coroutines. + traceEvGoSwitch // goroutine switch (coroswitch) [timestamp, goroutine ID, goroutine seq] + traceEvGoSwitchDestroy // goroutine switch and destroy [timestamp, goroutine ID, goroutine seq] + traceEvGoCreateBlocked // goroutine creation (starts blocked) [timestamp, new goroutine ID, new stack ID, stack ID] + + // GoStatus with stack. + traceEvGoStatusStack // goroutine status at the start of a generation, with a stack [timestamp, goroutine ID, M ID, status, stack ID] + + // Batch event for an experimental batch with a custom format. + traceEvExperimentalBatch // start of extra data [experiment ID, generation, M ID, timestamp, batch length, batch data...] +) + +// traceArg is a simple wrapper type to help ensure that arguments passed +// to traces are well-formed. +type traceArg uint64 + +// traceEventWriter is the high-level API for writing trace events. +// +// See the comment on traceWriter about style for more details as to why +// this type and its methods are structured the way they are. +type traceEventWriter struct { + w traceWriter +} + +// eventWriter creates a new traceEventWriter. It is the main entrypoint for writing trace events. +// +// Before creating the event writer, this method will emit a status for the current goroutine +// or proc if it exists, and if it hasn't had its status emitted yet. goStatus and procStatus indicate +// what the status of goroutine or P should be immediately *before* the events that are about to +// be written using the eventWriter (if they exist). No status will be written if there's no active +// goroutine or P. +// +// Callers can elect to pass a constant value here if the status is clear (e.g. a goroutine must have +// been Runnable before a GoStart). Otherwise, callers can query the status of either the goroutine +// or P and pass the appropriate status. +// +// In this case, the default status should be traceGoBad or traceProcBad to help identify bugs sooner. +func (tl traceLocker) eventWriter(goStatus traceGoStatus, procStatus traceProcStatus) traceEventWriter { + w := tl.writer() + if pp := tl.mp.p.ptr(); pp != nil && !pp.trace.statusWasTraced(tl.gen) && pp.trace.acquireStatus(tl.gen) { + w = w.writeProcStatus(uint64(pp.id), procStatus, pp.trace.inSweep) + } + if gp := tl.mp.curg; gp != nil && !gp.trace.statusWasTraced(tl.gen) && gp.trace.acquireStatus(tl.gen) { + w = w.writeGoStatus(uint64(gp.goid), int64(tl.mp.procid), goStatus, gp.inMarkAssist, 0 /* no stack */) + } + return traceEventWriter{w} +} + +// commit writes out a trace event and calls end. It's a helper to make the +// common case of writing out a single event less error-prone. +func (e traceEventWriter) commit(ev traceEv, args ...traceArg) { + e = e.write(ev, args...) + e.end() +} + +// write writes an event into the trace. +func (e traceEventWriter) write(ev traceEv, args ...traceArg) traceEventWriter { + e.w = e.w.event(ev, args...) + return e +} + +// end finishes writing to the trace. The traceEventWriter must not be used after this call. +func (e traceEventWriter) end() { + e.w.end() +} + +// traceEventWrite is the part of traceEvent that actually writes the event. +func (w traceWriter) event(ev traceEv, args ...traceArg) traceWriter { + // Make sure we have room. + w, _ = w.ensure(1 + (len(args)+1)*traceBytesPerNumber) + + // Compute the timestamp diff that we'll put in the trace. + ts := traceClockNow() + if ts <= w.traceBuf.lastTime { + ts = w.traceBuf.lastTime + 1 + } + tsDiff := uint64(ts - w.traceBuf.lastTime) + w.traceBuf.lastTime = ts + + // Write out event. + w.byte(byte(ev)) + w.varint(tsDiff) + for _, arg := range args { + w.varint(uint64(arg)) + } + return w +} + +// stack takes a stack trace skipping the provided number of frames. +// It then returns a traceArg representing that stack which may be +// passed to write. +func (tl traceLocker) stack(skip int) traceArg { + return traceArg(traceStack(skip, nil, tl.gen)) +} + +// startPC takes a start PC for a goroutine and produces a unique +// stack ID for it. +// +// It then returns a traceArg representing that stack which may be +// passed to write. +func (tl traceLocker) startPC(pc uintptr) traceArg { + // +PCQuantum because makeTraceFrame expects return PCs and subtracts PCQuantum. + return traceArg(trace.stackTab[tl.gen%2].put([]uintptr{ + logicalStackSentinel, + startPCForTrace(pc) + sys.PCQuantum, + })) +} + +// string returns a traceArg representing s which may be passed to write. +// The string is assumed to be relatively short and popular, so it may be +// stored for a while in the string dictionary. +func (tl traceLocker) string(s string) traceArg { + return traceArg(trace.stringTab[tl.gen%2].put(tl.gen, s)) +} + +// uniqueString returns a traceArg representing s which may be passed to write. +// The string is assumed to be unique or long, so it will be written out to +// the trace eagerly. +func (tl traceLocker) uniqueString(s string) traceArg { + return traceArg(trace.stringTab[tl.gen%2].emit(tl.gen, s)) +} + +// rtype returns a traceArg representing typ which may be passed to write. +func (tl traceLocker) rtype(typ *abi.Type) traceArg { + return traceArg(trace.typeTab[tl.gen%2].put(typ)) +} diff --git a/contrib/go/_std_1.23/src/runtime/traceexp.go b/contrib/go/_std_1.23/src/runtime/traceexp.go new file mode 100644 index 000000000000..9fc85df5a8e9 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/traceexp.go @@ -0,0 +1,68 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +// traceExpWriter is a wrapper around trace writer that produces traceEvExperimentalBatch +// batches. This means that the data written to the writer need not conform to the standard +// trace format. +type traceExpWriter struct { + traceWriter + exp traceExperiment +} + +// unsafeTraceExpWriter produces a traceExpWriter that doesn't lock the trace. +// +// It should only be used in contexts where either: +// - Another traceLocker is held. +// - trace.gen is prevented from advancing. +// +// buf may be nil. +func unsafeTraceExpWriter(gen uintptr, buf *traceBuf, exp traceExperiment) traceExpWriter { + return traceExpWriter{traceWriter{traceLocker: traceLocker{gen: gen}, traceBuf: buf}, exp} +} + +// ensure makes sure that at least maxSize bytes are available to write. +// +// Returns whether the buffer was flushed. +func (w traceExpWriter) ensure(maxSize int) (traceExpWriter, bool) { + refill := w.traceBuf == nil || !w.available(maxSize) + if refill { + w.traceWriter = w.traceWriter.refill(w.exp) + } + return w, refill +} + +// traceExperiment is an enumeration of the different kinds of experiments supported for tracing. +type traceExperiment uint8 + +const ( + // traceNoExperiment indicates no experiment. + traceNoExperiment traceExperiment = iota + + // traceExperimentAllocFree is an experiment to add alloc/free events to the trace. + traceExperimentAllocFree +) + +// Experimental events. +const ( + _ traceEv = 127 + iota + + // Experimental events for ExperimentAllocFree. + + // Experimental heap span events. IDs map reversibly to base addresses. + traceEvSpan // heap span exists [timestamp, id, npages, type/class] + traceEvSpanAlloc // heap span alloc [timestamp, id, npages, type/class] + traceEvSpanFree // heap span free [timestamp, id] + + // Experimental heap object events. IDs map reversibly to addresses. + traceEvHeapObject // heap object exists [timestamp, id, type] + traceEvHeapObjectAlloc // heap object alloc [timestamp, id, type] + traceEvHeapObjectFree // heap object free [timestamp, id] + + // Experimental goroutine stack events. IDs map reversibly to addresses. + traceEvGoroutineStack // stack exists [timestamp, id, order] + traceEvGoroutineStackAlloc // stack alloc [timestamp, id, order] + traceEvGoroutineStackFree // stack free [timestamp, id] +) diff --git a/contrib/go/_std_1.23/src/runtime/tracemap.go b/contrib/go/_std_1.23/src/runtime/tracemap.go new file mode 100644 index 000000000000..5b2718c8d685 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracemap.go @@ -0,0 +1,140 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Simple append-only thread-safe hash map for tracing. +// Provides a mapping between variable-length data and a +// unique ID. Subsequent puts of the same data will return +// the same ID. The zero value is ready to use. +// +// Uses a region-based allocation scheme internally, and +// reset clears the whole map. +// +// It avoids doing any high-level Go operations so it's safe +// to use even in sensitive contexts. + +package runtime + +import ( + "internal/cpu" + "internal/goarch" + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +type traceMap struct { + root atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap) + _ cpu.CacheLinePad + seq atomic.Uint64 + _ cpu.CacheLinePad + mem traceRegionAlloc +} + +// traceMapNode is an implementation of a lock-free append-only hash-trie +// (a trie of the hash bits). +// +// Key features: +// - 4-ary trie. Child nodes are indexed by the upper 2 (remaining) bits of the hash. +// For example, top level uses bits [63:62], next level uses [61:60] and so on. +// - New nodes are placed at the first empty level encountered. +// - When the first child is added to a node, the existing value is not moved into a child. +// This means that you must check the key at each level, not just at the leaf. +// - No deletion or rebalancing. +// - Intentionally devolves into a linked list on hash collisions (the hash bits will all +// get shifted out during iteration, and new nodes will just be appended to the 0th child). +type traceMapNode struct { + _ sys.NotInHeap + + children [4]atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap) + hash uintptr + id uint64 + data []byte +} + +// stealID steals an ID from the table, ensuring that it will not +// appear in the table anymore. +func (tab *traceMap) stealID() uint64 { + return tab.seq.Add(1) +} + +// put inserts the data into the table. +// +// It's always safe for callers to noescape data because put copies its bytes. +// +// Returns a unique ID for the data and whether this is the first time +// the data has been added to the map. +func (tab *traceMap) put(data unsafe.Pointer, size uintptr) (uint64, bool) { + if size == 0 { + return 0, false + } + hash := memhash(data, 0, size) + + var newNode *traceMapNode + m := &tab.root + hashIter := hash + for { + n := (*traceMapNode)(m.Load()) + if n == nil { + // Try to insert a new map node. We may end up discarding + // this node if we fail to insert because it turns out the + // value is already in the map. + // + // The discard will only happen if two threads race on inserting + // the same value. Both might create nodes, but only one will + // succeed on insertion. If two threads race to insert two + // different values, then both nodes will *always* get inserted, + // because the equality checking below will always fail. + // + // Performance note: contention on insertion is likely to be + // higher for small maps, but since this data structure is + // append-only, either the map stays small because there isn't + // much activity, or the map gets big and races to insert on + // the same node are much less likely. + if newNode == nil { + newNode = tab.newTraceMapNode(data, size, hash, tab.seq.Add(1)) + } + if m.CompareAndSwapNoWB(nil, unsafe.Pointer(newNode)) { + return newNode.id, true + } + // Reload n. Because pointers are only stored once, + // we must have lost the race, and therefore n is not nil + // anymore. + n = (*traceMapNode)(m.Load()) + } + if n.hash == hash && uintptr(len(n.data)) == size { + if memequal(unsafe.Pointer(&n.data[0]), data, size) { + return n.id, false + } + } + m = &n.children[hashIter>>(8*goarch.PtrSize-2)] + hashIter <<= 2 + } +} + +func (tab *traceMap) newTraceMapNode(data unsafe.Pointer, size, hash uintptr, id uint64) *traceMapNode { + // Create data array. + sl := notInHeapSlice{ + array: tab.mem.alloc(size), + len: int(size), + cap: int(size), + } + memmove(unsafe.Pointer(sl.array), data, size) + + // Create metadata structure. + meta := (*traceMapNode)(unsafe.Pointer(tab.mem.alloc(unsafe.Sizeof(traceMapNode{})))) + *(*notInHeapSlice)(unsafe.Pointer(&meta.data)) = sl + meta.id = id + meta.hash = hash + return meta +} + +// reset drops all allocated memory from the table and resets it. +// +// The caller must ensure that there are no put operations executing concurrently +// with this function. +func (tab *traceMap) reset() { + tab.root.Store(nil) + tab.seq.Store(0) + tab.mem.drop() +} diff --git a/contrib/go/_std_1.23/src/runtime/traceregion.go b/contrib/go/_std_1.23/src/runtime/traceregion.go new file mode 100644 index 000000000000..43eef9c92bb9 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/traceregion.go @@ -0,0 +1,112 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Simple not-in-heap bump-pointer traceRegion allocator. + +package runtime + +import ( + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +// traceRegionAlloc is a thread-safe region allocator. +// It holds a linked list of traceRegionAllocBlock. +type traceRegionAlloc struct { + lock mutex + dropping atomic.Bool // For checking invariants. + current atomic.UnsafePointer // *traceRegionAllocBlock + full *traceRegionAllocBlock +} + +// traceRegionAllocBlock is a block in traceRegionAlloc. +// +// traceRegionAllocBlock is allocated from non-GC'd memory, so it must not +// contain heap pointers. Writes to pointers to traceRegionAllocBlocks do +// not need write barriers. +type traceRegionAllocBlock struct { + _ sys.NotInHeap + traceRegionAllocBlockHeader + data [traceRegionAllocBlockData]byte +} + +type traceRegionAllocBlockHeader struct { + next *traceRegionAllocBlock + off atomic.Uintptr +} + +const traceRegionAllocBlockData = 64<<10 - unsafe.Sizeof(traceRegionAllocBlockHeader{}) + +// alloc allocates n-byte block. The block is always aligned to 8 bytes, regardless of platform. +func (a *traceRegionAlloc) alloc(n uintptr) *notInHeap { + n = alignUp(n, 8) + if n > traceRegionAllocBlockData { + throw("traceRegion: alloc too large") + } + if a.dropping.Load() { + throw("traceRegion: alloc with concurrent drop") + } + + // Try to bump-pointer allocate into the current block. + block := (*traceRegionAllocBlock)(a.current.Load()) + if block != nil { + r := block.off.Add(n) + if r <= uintptr(len(block.data)) { + return (*notInHeap)(unsafe.Pointer(&block.data[r-n])) + } + } + + // Try to install a new block. + lock(&a.lock) + + // Check block again under the lock. Someone may + // have gotten here first. + block = (*traceRegionAllocBlock)(a.current.Load()) + if block != nil { + r := block.off.Add(n) + if r <= uintptr(len(block.data)) { + unlock(&a.lock) + return (*notInHeap)(unsafe.Pointer(&block.data[r-n])) + } + + // Add the existing block to the full list. + block.next = a.full + a.full = block + } + + // Allocate a new block. + block = (*traceRegionAllocBlock)(sysAlloc(unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys)) + if block == nil { + throw("traceRegion: out of memory") + } + + // Allocate space for our current request, so we always make + // progress. + block.off.Store(n) + x := (*notInHeap)(unsafe.Pointer(&block.data[0])) + + // Publish the new block. + a.current.Store(unsafe.Pointer(block)) + unlock(&a.lock) + return x +} + +// drop frees all previously allocated memory and resets the allocator. +// +// drop is not safe to call concurrently with other calls to drop or with calls to alloc. The caller +// must ensure that it is not possible for anything else to be using the same structure. +func (a *traceRegionAlloc) drop() { + a.dropping.Store(true) + for a.full != nil { + block := a.full + a.full = block.next + sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys) + } + if current := a.current.Load(); current != nil { + sysFree(current, unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys) + a.current.Store(nil) + } + a.dropping.Store(false) +} diff --git a/contrib/go/_std_1.23/src/runtime/traceruntime.go b/contrib/go/_std_1.23/src/runtime/traceruntime.go new file mode 100644 index 000000000000..7c4cb5502377 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/traceruntime.go @@ -0,0 +1,740 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Runtime -> tracer API. + +package runtime + +import ( + "internal/runtime/atomic" + _ "unsafe" // for go:linkname +) + +// gTraceState is per-G state for the tracer. +type gTraceState struct { + traceSchedResourceState +} + +// reset resets the gTraceState for a new goroutine. +func (s *gTraceState) reset() { + s.seq = [2]uint64{} + // N.B. s.statusTraced is managed and cleared separately. +} + +// mTraceState is per-M state for the tracer. +type mTraceState struct { + seqlock atomic.Uintptr // seqlock indicating that this M is writing to a trace buffer. + buf [2]*traceBuf // Per-M traceBuf for writing. Indexed by trace.gen%2. + link *m // Snapshot of alllink or freelink. +} + +// pTraceState is per-P state for the tracer. +type pTraceState struct { + traceSchedResourceState + + // mSyscallID is the ID of the M this was bound to before entering a syscall. + mSyscallID int64 + + // maySweep indicates the sweep events should be traced. + // This is used to defer the sweep start event until a span + // has actually been swept. + maySweep bool + + // inSweep indicates that at least one sweep event has been traced. + inSweep bool + + // swept and reclaimed track the number of bytes swept and reclaimed + // by sweeping in the current sweep loop (while maySweep was true). + swept, reclaimed uintptr +} + +// traceLockInit initializes global trace locks. +func traceLockInit() { + // Sharing a lock rank here is fine because they should never be accessed + // together. If they are, we want to find out immediately. + lockInit(&trace.stringTab[0].lock, lockRankTraceStrings) + lockInit(&trace.stringTab[0].tab.mem.lock, lockRankTraceStrings) + lockInit(&trace.stringTab[1].lock, lockRankTraceStrings) + lockInit(&trace.stringTab[1].tab.mem.lock, lockRankTraceStrings) + lockInit(&trace.stackTab[0].tab.mem.lock, lockRankTraceStackTab) + lockInit(&trace.stackTab[1].tab.mem.lock, lockRankTraceStackTab) + lockInit(&trace.typeTab[0].tab.mem.lock, lockRankTraceTypeTab) + lockInit(&trace.typeTab[1].tab.mem.lock, lockRankTraceTypeTab) + lockInit(&trace.lock, lockRankTrace) +} + +// lockRankMayTraceFlush records the lock ranking effects of a +// potential call to traceFlush. +// +// nosplit because traceAcquire is nosplit. +// +//go:nosplit +func lockRankMayTraceFlush() { + lockWithRankMayAcquire(&trace.lock, getLockRank(&trace.lock)) +} + +// traceBlockReason is an enumeration of reasons a goroutine might block. +// This is the interface the rest of the runtime uses to tell the +// tracer why a goroutine blocked. The tracer then propagates this information +// into the trace however it sees fit. +// +// Note that traceBlockReasons should not be compared, since reasons that are +// distinct by name may *not* be distinct by value. +type traceBlockReason uint8 + +const ( + traceBlockGeneric traceBlockReason = iota + traceBlockForever + traceBlockNet + traceBlockSelect + traceBlockCondWait + traceBlockSync + traceBlockChanSend + traceBlockChanRecv + traceBlockGCMarkAssist + traceBlockGCSweep + traceBlockSystemGoroutine + traceBlockPreempted + traceBlockDebugCall + traceBlockUntilGCEnds + traceBlockSleep + traceBlockGCWeakToStrongWait +) + +var traceBlockReasonStrings = [...]string{ + traceBlockGeneric: "unspecified", + traceBlockForever: "forever", + traceBlockNet: "network", + traceBlockSelect: "select", + traceBlockCondWait: "sync.(*Cond).Wait", + traceBlockSync: "sync", + traceBlockChanSend: "chan send", + traceBlockChanRecv: "chan receive", + traceBlockGCMarkAssist: "GC mark assist wait for work", + traceBlockGCSweep: "GC background sweeper wait", + traceBlockSystemGoroutine: "system goroutine wait", + traceBlockPreempted: "preempted", + traceBlockDebugCall: "wait for debug call", + traceBlockUntilGCEnds: "wait until GC ends", + traceBlockSleep: "sleep", + traceBlockGCWeakToStrongWait: "GC weak to strong wait", +} + +// traceGoStopReason is an enumeration of reasons a goroutine might yield. +// +// Note that traceGoStopReasons should not be compared, since reasons that are +// distinct by name may *not* be distinct by value. +type traceGoStopReason uint8 + +const ( + traceGoStopGeneric traceGoStopReason = iota + traceGoStopGoSched + traceGoStopPreempted +) + +var traceGoStopReasonStrings = [...]string{ + traceGoStopGeneric: "unspecified", + traceGoStopGoSched: "runtime.Gosched", + traceGoStopPreempted: "preempted", +} + +// traceEnabled returns true if the trace is currently enabled. +// +//go:nosplit +func traceEnabled() bool { + return trace.enabled +} + +// traceAllocFreeEnabled returns true if the trace is currently enabled +// and alloc/free events are also enabled. +// +//go:nosplit +func traceAllocFreeEnabled() bool { + return trace.enabledWithAllocFree +} + +// traceShuttingDown returns true if the trace is currently shutting down. +func traceShuttingDown() bool { + return trace.shutdown.Load() +} + +// traceLocker represents an M writing trace events. While a traceLocker value +// is valid, the tracer observes all operations on the G/M/P or trace events being +// written as happening atomically. +type traceLocker struct { + mp *m + gen uintptr +} + +// debugTraceReentrancy checks if the trace is reentrant. +// +// This is optional because throwing in a function makes it instantly +// not inlineable, and we want traceAcquire to be inlineable for +// low overhead when the trace is disabled. +const debugTraceReentrancy = false + +// traceAcquire prepares this M for writing one or more trace events. +// +// nosplit because it's called on the syscall path when stack movement is forbidden. +// +//go:nosplit +func traceAcquire() traceLocker { + if !traceEnabled() { + return traceLocker{} + } + return traceAcquireEnabled() +} + +// traceTryAcquire is like traceAcquire, but may return an invalid traceLocker even +// if tracing is enabled. For example, it will return !ok if traceAcquire is being +// called with an active traceAcquire on the M (reentrant locking). This exists for +// optimistically emitting events in the few contexts where tracing is now allowed. +// +// nosplit for alignment with traceTryAcquire, so it can be used in the +// same contexts. +// +//go:nosplit +func traceTryAcquire() traceLocker { + if !traceEnabled() { + return traceLocker{} + } + return traceTryAcquireEnabled() +} + +// traceAcquireEnabled is the traceEnabled path for traceAcquire. It's explicitly +// broken out to make traceAcquire inlineable to keep the overhead of the tracer +// when it's disabled low. +// +// nosplit because it's called by traceAcquire, which is nosplit. +// +//go:nosplit +func traceAcquireEnabled() traceLocker { + // Any time we acquire a traceLocker, we may flush a trace buffer. But + // buffer flushes are rare. Record the lock edge even if it doesn't happen + // this time. + lockRankMayTraceFlush() + + // Prevent preemption. + mp := acquirem() + + // Acquire the trace seqlock. This prevents traceAdvance from moving forward + // until all Ms are observed to be outside of their seqlock critical section. + // + // Note: The seqlock is mutated here and also in traceCPUSample. If you update + // usage of the seqlock here, make sure to also look at what traceCPUSample is + // doing. + seq := mp.trace.seqlock.Add(1) + if debugTraceReentrancy && seq%2 != 1 { + throw("bad use of trace.seqlock or tracer is reentrant") + } + + // N.B. This load of gen appears redundant with the one in traceEnabled. + // However, it's very important that the gen we use for writing to the trace + // is acquired under a traceLocker so traceAdvance can make sure no stale + // gen values are being used. + // + // Because we're doing this load again, it also means that the trace + // might end up being disabled when we load it. In that case we need to undo + // what we did and bail. + gen := trace.gen.Load() + if gen == 0 { + mp.trace.seqlock.Add(1) + releasem(mp) + return traceLocker{} + } + return traceLocker{mp, gen} +} + +// traceTryAcquireEnabled is like traceAcquireEnabled but may return an invalid +// traceLocker under some conditions. See traceTryAcquire for more details. +// +// nosplit for alignment with traceAcquireEnabled, so it can be used in the +// same contexts. +// +//go:nosplit +func traceTryAcquireEnabled() traceLocker { + // Any time we acquire a traceLocker, we may flush a trace buffer. But + // buffer flushes are rare. Record the lock edge even if it doesn't happen + // this time. + lockRankMayTraceFlush() + + // Check if we're already locked. If so, return an invalid traceLocker. + if getg().m.trace.seqlock.Load()%2 == 1 { + return traceLocker{} + } + return traceAcquireEnabled() +} + +// ok returns true if the traceLocker is valid (i.e. tracing is enabled). +// +// nosplit because it's called on the syscall path when stack movement is forbidden. +// +//go:nosplit +func (tl traceLocker) ok() bool { + return tl.gen != 0 +} + +// traceRelease indicates that this M is done writing trace events. +// +// nosplit because it's called on the syscall path when stack movement is forbidden. +// +//go:nosplit +func traceRelease(tl traceLocker) { + seq := tl.mp.trace.seqlock.Add(1) + if debugTraceReentrancy && seq%2 != 0 { + print("runtime: seq=", seq, "\n") + throw("bad use of trace.seqlock") + } + releasem(tl.mp) +} + +// traceExitingSyscall marks a goroutine as exiting the syscall slow path. +// +// Must be paired with a traceExitedSyscall call. +func traceExitingSyscall() { + trace.exitingSyscall.Add(1) +} + +// traceExitedSyscall marks a goroutine as having exited the syscall slow path. +func traceExitedSyscall() { + trace.exitingSyscall.Add(-1) +} + +// Gomaxprocs emits a ProcsChange event. +func (tl traceLocker) Gomaxprocs(procs int32) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvProcsChange, traceArg(procs), tl.stack(1)) +} + +// ProcStart traces a ProcStart event. +// +// Must be called with a valid P. +func (tl traceLocker) ProcStart() { + pp := tl.mp.p.ptr() + // Procs are typically started within the scheduler when there is no user goroutine. If there is a user goroutine, + // it must be in _Gsyscall because the only time a goroutine is allowed to have its Proc moved around from under it + // is during a syscall. + tl.eventWriter(traceGoSyscall, traceProcIdle).commit(traceEvProcStart, traceArg(pp.id), pp.trace.nextSeq(tl.gen)) +} + +// ProcStop traces a ProcStop event. +func (tl traceLocker) ProcStop(pp *p) { + // The only time a goroutine is allowed to have its Proc moved around + // from under it is during a syscall. + tl.eventWriter(traceGoSyscall, traceProcRunning).commit(traceEvProcStop) +} + +// GCActive traces a GCActive event. +// +// Must be emitted by an actively running goroutine on an active P. This restriction can be changed +// easily and only depends on where it's currently called. +func (tl traceLocker) GCActive() { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCActive, traceArg(trace.seqGC)) + // N.B. Only one GC can be running at a time, so this is naturally + // serialized by the caller. + trace.seqGC++ +} + +// GCStart traces a GCBegin event. +// +// Must be emitted by an actively running goroutine on an active P. This restriction can be changed +// easily and only depends on where it's currently called. +func (tl traceLocker) GCStart() { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCBegin, traceArg(trace.seqGC), tl.stack(3)) + // N.B. Only one GC can be running at a time, so this is naturally + // serialized by the caller. + trace.seqGC++ +} + +// GCDone traces a GCEnd event. +// +// Must be emitted by an actively running goroutine on an active P. This restriction can be changed +// easily and only depends on where it's currently called. +func (tl traceLocker) GCDone() { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCEnd, traceArg(trace.seqGC)) + // N.B. Only one GC can be running at a time, so this is naturally + // serialized by the caller. + trace.seqGC++ +} + +// STWStart traces a STWBegin event. +func (tl traceLocker) STWStart(reason stwReason) { + // Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the + // runtime's state tracking, but it's more accurate and doesn't result in any loss of information. + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSTWBegin, tl.string(reason.String()), tl.stack(2)) +} + +// STWDone traces a STWEnd event. +func (tl traceLocker) STWDone() { + // Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the + // runtime's state tracking, but it's more accurate and doesn't result in any loss of information. + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSTWEnd) +} + +// GCSweepStart prepares to trace a sweep loop. This does not +// emit any events until traceGCSweepSpan is called. +// +// GCSweepStart must be paired with traceGCSweepDone and there +// must be no preemption points between these two calls. +// +// Must be called with a valid P. +func (tl traceLocker) GCSweepStart() { + // Delay the actual GCSweepBegin event until the first span + // sweep. If we don't sweep anything, don't emit any events. + pp := tl.mp.p.ptr() + if pp.trace.maySweep { + throw("double traceGCSweepStart") + } + pp.trace.maySweep, pp.trace.swept, pp.trace.reclaimed = true, 0, 0 +} + +// GCSweepSpan traces the sweep of a single span. If this is +// the first span swept since traceGCSweepStart was called, this +// will emit a GCSweepBegin event. +// +// This may be called outside a traceGCSweepStart/traceGCSweepDone +// pair; however, it will not emit any trace events in this case. +// +// Must be called with a valid P. +func (tl traceLocker) GCSweepSpan(bytesSwept uintptr) { + pp := tl.mp.p.ptr() + if pp.trace.maySweep { + if pp.trace.swept == 0 { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCSweepBegin, tl.stack(1)) + pp.trace.inSweep = true + } + pp.trace.swept += bytesSwept + } +} + +// GCSweepDone finishes tracing a sweep loop. If any memory was +// swept (i.e. traceGCSweepSpan emitted an event) then this will emit +// a GCSweepEnd event. +// +// Must be called with a valid P. +func (tl traceLocker) GCSweepDone() { + pp := tl.mp.p.ptr() + if !pp.trace.maySweep { + throw("missing traceGCSweepStart") + } + if pp.trace.inSweep { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCSweepEnd, traceArg(pp.trace.swept), traceArg(pp.trace.reclaimed)) + pp.trace.inSweep = false + } + pp.trace.maySweep = false +} + +// GCMarkAssistStart emits a MarkAssistBegin event. +func (tl traceLocker) GCMarkAssistStart() { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCMarkAssistBegin, tl.stack(1)) +} + +// GCMarkAssistDone emits a MarkAssistEnd event. +func (tl traceLocker) GCMarkAssistDone() { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCMarkAssistEnd) +} + +// GoCreate emits a GoCreate event. +func (tl traceLocker) GoCreate(newg *g, pc uintptr, blocked bool) { + newg.trace.setStatusTraced(tl.gen) + ev := traceEvGoCreate + if blocked { + ev = traceEvGoCreateBlocked + } + tl.eventWriter(traceGoRunning, traceProcRunning).commit(ev, traceArg(newg.goid), tl.startPC(pc), tl.stack(2)) +} + +// GoStart emits a GoStart event. +// +// Must be called with a valid P. +func (tl traceLocker) GoStart() { + gp := getg().m.curg + pp := gp.m.p + w := tl.eventWriter(traceGoRunnable, traceProcRunning) + w = w.write(traceEvGoStart, traceArg(gp.goid), gp.trace.nextSeq(tl.gen)) + if pp.ptr().gcMarkWorkerMode != gcMarkWorkerNotWorker { + w = w.write(traceEvGoLabel, trace.markWorkerLabels[tl.gen%2][pp.ptr().gcMarkWorkerMode]) + } + w.end() +} + +// GoEnd emits a GoDestroy event. +// +// TODO(mknyszek): Rename this to GoDestroy. +func (tl traceLocker) GoEnd() { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoDestroy) +} + +// GoSched emits a GoStop event with a GoSched reason. +func (tl traceLocker) GoSched() { + tl.GoStop(traceGoStopGoSched) +} + +// GoPreempt emits a GoStop event with a GoPreempted reason. +func (tl traceLocker) GoPreempt() { + tl.GoStop(traceGoStopPreempted) +} + +// GoStop emits a GoStop event with the provided reason. +func (tl traceLocker) GoStop(reason traceGoStopReason) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoStop, traceArg(trace.goStopReasons[tl.gen%2][reason]), tl.stack(1)) +} + +// GoPark emits a GoBlock event with the provided reason. +// +// TODO(mknyszek): Replace traceBlockReason with waitReason. It's silly +// that we have both, and waitReason is way more descriptive. +func (tl traceLocker) GoPark(reason traceBlockReason, skip int) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoBlock, traceArg(trace.goBlockReasons[tl.gen%2][reason]), tl.stack(skip)) +} + +// GoUnpark emits a GoUnblock event. +func (tl traceLocker) GoUnpark(gp *g, skip int) { + // Emit a GoWaiting status if necessary for the unblocked goroutine. + w := tl.eventWriter(traceGoRunning, traceProcRunning) + // Careful: don't use the event writer. We never want status or in-progress events + // to trigger more in-progress events. + w.w = emitUnblockStatus(w.w, gp, tl.gen) + w.commit(traceEvGoUnblock, traceArg(gp.goid), gp.trace.nextSeq(tl.gen), tl.stack(skip)) +} + +// GoCoroswitch emits a GoSwitch event. If destroy is true, the calling goroutine +// is simultaneously being destroyed. +func (tl traceLocker) GoSwitch(nextg *g, destroy bool) { + // Emit a GoWaiting status if necessary for the unblocked goroutine. + w := tl.eventWriter(traceGoRunning, traceProcRunning) + // Careful: don't use the event writer. We never want status or in-progress events + // to trigger more in-progress events. + w.w = emitUnblockStatus(w.w, nextg, tl.gen) + ev := traceEvGoSwitch + if destroy { + ev = traceEvGoSwitchDestroy + } + w.commit(ev, traceArg(nextg.goid), nextg.trace.nextSeq(tl.gen)) +} + +// emitUnblockStatus emits a GoStatus GoWaiting event for a goroutine about to be +// unblocked to the trace writer. +func emitUnblockStatus(w traceWriter, gp *g, gen uintptr) traceWriter { + if !gp.trace.statusWasTraced(gen) && gp.trace.acquireStatus(gen) { + // TODO(go.dev/issue/65634): Although it would be nice to add a stack trace here of gp, + // we cannot safely do so. gp is in _Gwaiting and so we don't have ownership of its stack. + // We can fix this by acquiring the goroutine's scan bit. + w = w.writeGoStatus(gp.goid, -1, traceGoWaiting, gp.inMarkAssist, 0) + } + return w +} + +// GoSysCall emits a GoSyscallBegin event. +// +// Must be called with a valid P. +func (tl traceLocker) GoSysCall() { + // Scribble down the M that the P is currently attached to. + pp := tl.mp.p.ptr() + pp.trace.mSyscallID = int64(tl.mp.procid) + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoSyscallBegin, pp.trace.nextSeq(tl.gen), tl.stack(1)) +} + +// GoSysExit emits a GoSyscallEnd event, possibly along with a GoSyscallBlocked event +// if lostP is true. +// +// lostP must be true in all cases that a goroutine loses its P during a syscall. +// This means it's not sufficient to check if it has no P. In particular, it needs to be +// true in the following cases: +// - The goroutine lost its P, it ran some other code, and then got it back. It's now running with that P. +// - The goroutine lost its P and was unable to reacquire it, and is now running without a P. +// - The goroutine lost its P and acquired a different one, and is now running with that P. +func (tl traceLocker) GoSysExit(lostP bool) { + ev := traceEvGoSyscallEnd + procStatus := traceProcSyscall // Procs implicitly enter traceProcSyscall on GoSyscallBegin. + if lostP { + ev = traceEvGoSyscallEndBlocked + procStatus = traceProcRunning // If a G has a P when emitting this event, it reacquired a P and is indeed running. + } else { + tl.mp.p.ptr().trace.mSyscallID = -1 + } + tl.eventWriter(traceGoSyscall, procStatus).commit(ev) +} + +// ProcSteal indicates that our current M stole a P from another M. +// +// inSyscall indicates that we're stealing the P from a syscall context. +// +// The caller must have ownership of pp. +func (tl traceLocker) ProcSteal(pp *p, inSyscall bool) { + // Grab the M ID we stole from. + mStolenFrom := pp.trace.mSyscallID + pp.trace.mSyscallID = -1 + + // The status of the proc and goroutine, if we need to emit one here, is not evident from the + // context of just emitting this event alone. There are two cases. Either we're trying to steal + // the P just to get its attention (e.g. STW or sysmon retake) or we're trying to steal a P for + // ourselves specifically to keep running. The two contexts look different, but can be summarized + // fairly succinctly. In the former, we're a regular running goroutine and proc, if we have either. + // In the latter, we're a goroutine in a syscall. + goStatus := traceGoRunning + procStatus := traceProcRunning + if inSyscall { + goStatus = traceGoSyscall + procStatus = traceProcSyscallAbandoned + } + w := tl.eventWriter(goStatus, procStatus) + + // Emit the status of the P we're stealing. We may have *just* done this when creating the event + // writer but it's not guaranteed, even if inSyscall is true. Although it might seem like from a + // syscall context we're always stealing a P for ourselves, we may have not wired it up yet (so + // it wouldn't be visible to eventWriter) or we may not even intend to wire it up to ourselves + // at all (e.g. entersyscall_gcwait). + if !pp.trace.statusWasTraced(tl.gen) && pp.trace.acquireStatus(tl.gen) { + // Careful: don't use the event writer. We never want status or in-progress events + // to trigger more in-progress events. + w.w = w.w.writeProcStatus(uint64(pp.id), traceProcSyscallAbandoned, pp.trace.inSweep) + } + w.commit(traceEvProcSteal, traceArg(pp.id), pp.trace.nextSeq(tl.gen), traceArg(mStolenFrom)) +} + +// HeapAlloc emits a HeapAlloc event. +func (tl traceLocker) HeapAlloc(live uint64) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapAlloc, traceArg(live)) +} + +// HeapGoal reads the current heap goal and emits a HeapGoal event. +func (tl traceLocker) HeapGoal() { + heapGoal := gcController.heapGoal() + if heapGoal == ^uint64(0) { + // Heap-based triggering is disabled. + heapGoal = 0 + } + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapGoal, traceArg(heapGoal)) +} + +// GoCreateSyscall indicates that a goroutine has transitioned from dead to GoSyscall. +// +// Unlike GoCreate, the caller must be running on gp. +// +// This occurs when C code calls into Go. On pthread platforms it occurs only when +// a C thread calls into Go code for the first time. +func (tl traceLocker) GoCreateSyscall(gp *g) { + // N.B. We should never trace a status for this goroutine (which we're currently running on), + // since we want this to appear like goroutine creation. + gp.trace.setStatusTraced(tl.gen) + tl.eventWriter(traceGoBad, traceProcBad).commit(traceEvGoCreateSyscall, traceArg(gp.goid)) +} + +// GoDestroySyscall indicates that a goroutine has transitioned from GoSyscall to dead. +// +// Must not have a P. +// +// This occurs when Go code returns back to C. On pthread platforms it occurs only when +// the C thread is destroyed. +func (tl traceLocker) GoDestroySyscall() { + // N.B. If we trace a status here, we must never have a P, and we must be on a goroutine + // that is in the syscall state. + tl.eventWriter(traceGoSyscall, traceProcBad).commit(traceEvGoDestroySyscall) +} + +// To access runtime functions from runtime/trace. +// See runtime/trace/annotation.go + +// trace_userTaskCreate emits a UserTaskCreate event. +// +//go:linkname trace_userTaskCreate runtime/trace.userTaskCreate +func trace_userTaskCreate(id, parentID uint64, taskType string) { + tl := traceAcquire() + if !tl.ok() { + // Need to do this check because the caller won't have it. + return + } + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserTaskBegin, traceArg(id), traceArg(parentID), tl.string(taskType), tl.stack(3)) + traceRelease(tl) +} + +// trace_userTaskEnd emits a UserTaskEnd event. +// +//go:linkname trace_userTaskEnd runtime/trace.userTaskEnd +func trace_userTaskEnd(id uint64) { + tl := traceAcquire() + if !tl.ok() { + // Need to do this check because the caller won't have it. + return + } + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserTaskEnd, traceArg(id), tl.stack(2)) + traceRelease(tl) +} + +// trace_userTaskEnd emits a UserRegionBegin or UserRegionEnd event, +// depending on mode (0 == Begin, 1 == End). +// +// TODO(mknyszek): Just make this two functions. +// +//go:linkname trace_userRegion runtime/trace.userRegion +func trace_userRegion(id, mode uint64, name string) { + tl := traceAcquire() + if !tl.ok() { + // Need to do this check because the caller won't have it. + return + } + var ev traceEv + switch mode { + case 0: + ev = traceEvUserRegionBegin + case 1: + ev = traceEvUserRegionEnd + default: + return + } + tl.eventWriter(traceGoRunning, traceProcRunning).commit(ev, traceArg(id), tl.string(name), tl.stack(3)) + traceRelease(tl) +} + +// trace_userTaskEnd emits a UserRegionBegin or UserRegionEnd event. +// +//go:linkname trace_userLog runtime/trace.userLog +func trace_userLog(id uint64, category, message string) { + tl := traceAcquire() + if !tl.ok() { + // Need to do this check because the caller won't have it. + return + } + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserLog, traceArg(id), tl.string(category), tl.uniqueString(message), tl.stack(3)) + traceRelease(tl) +} + +// traceThreadDestroy is called when a thread is removed from +// sched.freem. +// +// mp must not be able to emit trace events anymore. +// +// sched.lock must be held to synchronize with traceAdvance. +func traceThreadDestroy(mp *m) { + assertLockHeld(&sched.lock) + + // Flush all outstanding buffers to maintain the invariant + // that an M only has active buffers while on sched.freem + // or allm. + // + // Perform a traceAcquire/traceRelease on behalf of mp to + // synchronize with the tracer trying to flush our buffer + // as well. + seq := mp.trace.seqlock.Add(1) + if debugTraceReentrancy && seq%2 != 1 { + throw("bad use of trace.seqlock or tracer is reentrant") + } + systemstack(func() { + lock(&trace.lock) + for i := range mp.trace.buf { + if mp.trace.buf[i] != nil { + // N.B. traceBufFlush accepts a generation, but it + // really just cares about gen%2. + traceBufFlush(mp.trace.buf[i], uintptr(i)) + mp.trace.buf[i] = nil + } + } + unlock(&trace.lock) + }) + seq1 := mp.trace.seqlock.Add(1) + if seq1 != seq+1 { + print("runtime: seq1=", seq1, "\n") + throw("bad use of trace.seqlock") + } +} diff --git a/contrib/go/_std_1.23/src/runtime/tracestack.go b/contrib/go/_std_1.23/src/runtime/tracestack.go new file mode 100644 index 000000000000..225566d1020f --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracestack.go @@ -0,0 +1,345 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Trace stack table and acquisition. + +package runtime + +import ( + "internal/abi" + "internal/goarch" + "unsafe" +) + +const ( + // Maximum number of PCs in a single stack trace. + // Since events contain only stack id rather than whole stack trace, + // we can allow quite large values here. + traceStackSize = 128 + + // logicalStackSentinel is a sentinel value at pcBuf[0] signifying that + // pcBuf[1:] holds a logical stack requiring no further processing. Any other + // value at pcBuf[0] represents a skip value to apply to the physical stack in + // pcBuf[1:] after inline expansion. + logicalStackSentinel = ^uintptr(0) +) + +// traceStack captures a stack trace from a goroutine and registers it in the trace +// stack table. It then returns its unique ID. If gp == nil, then traceStack will +// attempt to use the current execution context. +// +// skip controls the number of leaf frames to omit in order to hide tracer internals +// from stack traces, see CL 5523. +// +// Avoid calling this function directly. gen needs to be the current generation +// that this stack trace is being written out for, which needs to be synchronized with +// generations moving forward. Prefer traceEventWriter.stack. +func traceStack(skip int, gp *g, gen uintptr) uint64 { + var pcBuf [traceStackSize]uintptr + + // Figure out gp and mp for the backtrace. + var mp *m + if gp == nil { + mp = getg().m + gp = mp.curg + } + + // Double-check that we own the stack we're about to trace. + if debug.traceCheckStackOwnership != 0 && gp != nil { + status := readgstatus(gp) + // If the scan bit is set, assume we're the ones that acquired it. + if status&_Gscan == 0 { + // Use the trace status to check this. There are a number of cases + // where a running goroutine might be in _Gwaiting, and these cases + // are totally fine for taking a stack trace. They're captured + // correctly in goStatusToTraceGoStatus. + switch goStatusToTraceGoStatus(status, gp.waitreason) { + case traceGoRunning, traceGoSyscall: + if getg() == gp || mp.curg == gp { + break + } + fallthrough + default: + print("runtime: gp=", unsafe.Pointer(gp), " gp.goid=", gp.goid, " status=", gStatusStrings[status], "\n") + throw("attempted to trace stack of a goroutine this thread does not own") + } + } + } + + if gp != nil && mp == nil { + // We're getting the backtrace for a G that's not currently executing. + // It may still have an M, if it's locked to some M. + mp = gp.lockedm.ptr() + } + nstk := 1 + if tracefpunwindoff() || (mp != nil && mp.hasCgoOnStack()) { + // Slow path: Unwind using default unwinder. Used when frame pointer + // unwinding is unavailable or disabled (tracefpunwindoff), or might + // produce incomplete results or crashes (hasCgoOnStack). Note that no + // cgo callback related crashes have been observed yet. The main + // motivation is to take advantage of a potentially registered cgo + // symbolizer. + pcBuf[0] = logicalStackSentinel + if getg() == gp { + nstk += callers(skip+1, pcBuf[1:]) + } else if gp != nil { + nstk += gcallers(gp, skip, pcBuf[1:]) + } + } else { + // Fast path: Unwind using frame pointers. + pcBuf[0] = uintptr(skip) + if getg() == gp { + nstk += fpTracebackPCs(unsafe.Pointer(getfp()), pcBuf[1:]) + } else if gp != nil { + // Three cases: + // + // (1) We're called on the g0 stack through mcall(fn) or systemstack(fn). To + // behave like gcallers above, we start unwinding from sched.bp, which + // points to the caller frame of the leaf frame on g's stack. The return + // address of the leaf frame is stored in sched.pc, which we manually + // capture here. + // + // (2) We're called against a gp that we're not currently executing on, but that isn't + // in a syscall, in which case it's currently not executing. gp.sched contains the most + // up-to-date information about where it stopped, and like case (1), we match gcallers + // here. + // + // (3) We're called against a gp that we're not currently executing on, but that is in + // a syscall, in which case gp.syscallsp != 0. gp.syscall* contains the most up-to-date + // information about where it stopped, and like case (1), we match gcallers here. + if gp.syscallsp != 0 { + pcBuf[1] = gp.syscallpc + nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.syscallbp), pcBuf[2:]) + } else { + pcBuf[1] = gp.sched.pc + nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.sched.bp), pcBuf[2:]) + } + } + } + if nstk > 0 { + nstk-- // skip runtime.goexit + } + if nstk > 0 && gp.goid == 1 { + nstk-- // skip runtime.main + } + id := trace.stackTab[gen%2].put(pcBuf[:nstk]) + return id +} + +// traceStackTable maps stack traces (arrays of PC's) to unique uint32 ids. +// It is lock-free for reading. +type traceStackTable struct { + tab traceMap +} + +// put returns a unique id for the stack trace pcs and caches it in the table, +// if it sees the trace for the first time. +func (t *traceStackTable) put(pcs []uintptr) uint64 { + if len(pcs) == 0 { + return 0 + } + id, _ := t.tab.put(noescape(unsafe.Pointer(&pcs[0])), uintptr(len(pcs))*unsafe.Sizeof(uintptr(0))) + return id +} + +// dump writes all previously cached stacks to trace buffers, +// releases all memory and resets state. It must only be called once the caller +// can guarantee that there are no more writers to the table. +func (t *traceStackTable) dump(gen uintptr) { + stackBuf := make([]uintptr, traceStackSize) + w := unsafeTraceWriter(gen, nil) + if root := (*traceMapNode)(t.tab.root.Load()); root != nil { + w = dumpStacksRec(root, w, stackBuf) + } + w.flush().end() + t.tab.reset() +} + +func dumpStacksRec(node *traceMapNode, w traceWriter, stackBuf []uintptr) traceWriter { + stack := unsafe.Slice((*uintptr)(unsafe.Pointer(&node.data[0])), uintptr(len(node.data))/unsafe.Sizeof(uintptr(0))) + + // N.B. This might allocate, but that's OK because we're not writing to the M's buffer, + // but one we're about to create (with ensure). + n := fpunwindExpand(stackBuf, stack) + frames := makeTraceFrames(w.gen, stackBuf[:n]) + + // The maximum number of bytes required to hold the encoded stack, given that + // it contains N frames. + maxBytes := 1 + (2+4*len(frames))*traceBytesPerNumber + + // Estimate the size of this record. This + // bound is pretty loose, but avoids counting + // lots of varint sizes. + // + // Add 1 because we might also write traceEvStacks. + var flushed bool + w, flushed = w.ensure(1 + maxBytes) + if flushed { + w.byte(byte(traceEvStacks)) + } + + // Emit stack event. + w.byte(byte(traceEvStack)) + w.varint(uint64(node.id)) + w.varint(uint64(len(frames))) + for _, frame := range frames { + w.varint(uint64(frame.PC)) + w.varint(frame.funcID) + w.varint(frame.fileID) + w.varint(frame.line) + } + + // Recursively walk all child nodes. + for i := range node.children { + child := node.children[i].Load() + if child == nil { + continue + } + w = dumpStacksRec((*traceMapNode)(child), w, stackBuf) + } + return w +} + +// makeTraceFrames returns the frames corresponding to pcs. It may +// allocate and may emit trace events. +func makeTraceFrames(gen uintptr, pcs []uintptr) []traceFrame { + frames := make([]traceFrame, 0, len(pcs)) + ci := CallersFrames(pcs) + for { + f, more := ci.Next() + frames = append(frames, makeTraceFrame(gen, f)) + if !more { + return frames + } + } +} + +type traceFrame struct { + PC uintptr + funcID uint64 + fileID uint64 + line uint64 +} + +// makeTraceFrame sets up a traceFrame for a frame. +func makeTraceFrame(gen uintptr, f Frame) traceFrame { + var frame traceFrame + frame.PC = f.PC + + fn := f.Function + const maxLen = 1 << 10 + if len(fn) > maxLen { + fn = fn[len(fn)-maxLen:] + } + frame.funcID = trace.stringTab[gen%2].put(gen, fn) + frame.line = uint64(f.Line) + file := f.File + if len(file) > maxLen { + file = file[len(file)-maxLen:] + } + frame.fileID = trace.stringTab[gen%2].put(gen, file) + return frame +} + +// tracefpunwindoff returns true if frame pointer unwinding for the tracer is +// disabled via GODEBUG or not supported by the architecture. +func tracefpunwindoff() bool { + return debug.tracefpunwindoff != 0 || (goarch.ArchFamily != goarch.AMD64 && goarch.ArchFamily != goarch.ARM64) +} + +// fpTracebackPCs populates pcBuf with the return addresses for each frame and +// returns the number of PCs written to pcBuf. The returned PCs correspond to +// "physical frames" rather than "logical frames"; that is if A is inlined into +// B, this will return a PC for only B. +func fpTracebackPCs(fp unsafe.Pointer, pcBuf []uintptr) (i int) { + for i = 0; i < len(pcBuf) && fp != nil; i++ { + // return addr sits one word above the frame pointer + pcBuf[i] = *(*uintptr)(unsafe.Pointer(uintptr(fp) + goarch.PtrSize)) + // follow the frame pointer to the next one + fp = unsafe.Pointer(*(*uintptr)(fp)) + } + return i +} + +//go:linkname pprof_fpunwindExpand +func pprof_fpunwindExpand(dst, src []uintptr) int { + return fpunwindExpand(dst, src) +} + +// fpunwindExpand expands a call stack from pcBuf into dst, +// returning the number of PCs written to dst. +// pcBuf and dst should not overlap. +// +// fpunwindExpand checks if pcBuf contains logical frames (which include inlined +// frames) or physical frames (produced by frame pointer unwinding) using a +// sentinel value in pcBuf[0]. Logical frames are simply returned without the +// sentinel. Physical frames are turned into logical frames via inline unwinding +// and by applying the skip value that's stored in pcBuf[0]. +func fpunwindExpand(dst, pcBuf []uintptr) int { + if len(pcBuf) == 0 { + return 0 + } else if len(pcBuf) > 0 && pcBuf[0] == logicalStackSentinel { + // pcBuf contains logical rather than inlined frames, skip has already been + // applied, just return it without the sentinel value in pcBuf[0]. + return copy(dst, pcBuf[1:]) + } + + var ( + n int + lastFuncID = abi.FuncIDNormal + skip = pcBuf[0] + // skipOrAdd skips or appends retPC to newPCBuf and returns true if more + // pcs can be added. + skipOrAdd = func(retPC uintptr) bool { + if skip > 0 { + skip-- + } else if n < len(dst) { + dst[n] = retPC + n++ + } + return n < len(dst) + } + ) + +outer: + for _, retPC := range pcBuf[1:] { + callPC := retPC - 1 + fi := findfunc(callPC) + if !fi.valid() { + // There is no funcInfo if callPC belongs to a C function. In this case + // we still keep the pc, but don't attempt to expand inlined frames. + if more := skipOrAdd(retPC); !more { + break outer + } + continue + } + + u, uf := newInlineUnwinder(fi, callPC) + for ; uf.valid(); uf = u.next(uf) { + sf := u.srcFunc(uf) + if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(lastFuncID) { + // ignore wrappers + } else if more := skipOrAdd(uf.pc + 1); !more { + break outer + } + lastFuncID = sf.funcID + } + } + return n +} + +// startPCForTrace returns the start PC of a goroutine for tracing purposes. +// If pc is a wrapper, it returns the PC of the wrapped function. Otherwise it +// returns pc. +func startPCForTrace(pc uintptr) uintptr { + f := findfunc(pc) + if !f.valid() { + return pc // may happen for locked g in extra M since its pc is 0. + } + w := funcdata(f, abi.FUNCDATA_WrapInfo) + if w == nil { + return pc // not a wrapper + } + return f.datap.textAddr(*(*uint32)(w)) +} diff --git a/contrib/go/_std_1.23/src/runtime/tracestatus.go b/contrib/go/_std_1.23/src/runtime/tracestatus.go new file mode 100644 index 000000000000..77ccdd139841 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracestatus.go @@ -0,0 +1,210 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Trace goroutine and P status management. + +package runtime + +import "internal/runtime/atomic" + +// traceGoStatus is the status of a goroutine. +// +// They correspond directly to the various goroutine +// statuses. +type traceGoStatus uint8 + +const ( + traceGoBad traceGoStatus = iota + traceGoRunnable + traceGoRunning + traceGoSyscall + traceGoWaiting +) + +// traceProcStatus is the status of a P. +// +// They mostly correspond to the various P statuses. +type traceProcStatus uint8 + +const ( + traceProcBad traceProcStatus = iota + traceProcRunning + traceProcIdle + traceProcSyscall + + // traceProcSyscallAbandoned is a special case of + // traceProcSyscall. It's used in the very specific case + // where the first a P is mentioned in a generation is + // part of a ProcSteal event. If that's the first time + // it's mentioned, then there's no GoSyscallBegin to + // connect the P stealing back to at that point. This + // special state indicates this to the parser, so it + // doesn't try to find a GoSyscallEndBlocked that + // corresponds with the ProcSteal. + traceProcSyscallAbandoned +) + +// writeGoStatus emits a GoStatus event as well as any active ranges on the goroutine. +func (w traceWriter) writeGoStatus(goid uint64, mid int64, status traceGoStatus, markAssist bool, stackID uint64) traceWriter { + // The status should never be bad. Some invariant must have been violated. + if status == traceGoBad { + print("runtime: goid=", goid, "\n") + throw("attempted to trace a bad status for a goroutine") + } + + // Trace the status. + if stackID == 0 { + w = w.event(traceEvGoStatus, traceArg(goid), traceArg(uint64(mid)), traceArg(status)) + } else { + w = w.event(traceEvGoStatusStack, traceArg(goid), traceArg(uint64(mid)), traceArg(status), traceArg(stackID)) + } + + // Trace any special ranges that are in-progress. + if markAssist { + w = w.event(traceEvGCMarkAssistActive, traceArg(goid)) + } + return w +} + +// writeProcStatusForP emits a ProcStatus event for the provided p based on its status. +// +// The caller must fully own pp and it must be prevented from transitioning (e.g. this can be +// called by a forEachP callback or from a STW). +func (w traceWriter) writeProcStatusForP(pp *p, inSTW bool) traceWriter { + if !pp.trace.acquireStatus(w.gen) { + return w + } + var status traceProcStatus + switch pp.status { + case _Pidle, _Pgcstop: + status = traceProcIdle + if pp.status == _Pgcstop && inSTW { + // N.B. a P that is running and currently has the world stopped will be + // in _Pgcstop, but we model it as running in the tracer. + status = traceProcRunning + } + case _Prunning: + status = traceProcRunning + // There's a short window wherein the goroutine may have entered _Gsyscall + // but it still owns the P (it's not in _Psyscall yet). The goroutine entering + // _Gsyscall is the tracer's signal that the P its bound to is also in a syscall, + // so we need to emit a status that matches. See #64318. + if w.mp.p.ptr() == pp && w.mp.curg != nil && readgstatus(w.mp.curg)&^_Gscan == _Gsyscall { + status = traceProcSyscall + } + case _Psyscall: + status = traceProcSyscall + default: + throw("attempt to trace invalid or unsupported P status") + } + w = w.writeProcStatus(uint64(pp.id), status, pp.trace.inSweep) + return w +} + +// writeProcStatus emits a ProcStatus event with all the provided information. +// +// The caller must have taken ownership of a P's status writing, and the P must be +// prevented from transitioning. +func (w traceWriter) writeProcStatus(pid uint64, status traceProcStatus, inSweep bool) traceWriter { + // The status should never be bad. Some invariant must have been violated. + if status == traceProcBad { + print("runtime: pid=", pid, "\n") + throw("attempted to trace a bad status for a proc") + } + + // Trace the status. + w = w.event(traceEvProcStatus, traceArg(pid), traceArg(status)) + + // Trace any special ranges that are in-progress. + if inSweep { + w = w.event(traceEvGCSweepActive, traceArg(pid)) + } + return w +} + +// goStatusToTraceGoStatus translates the internal status to tracGoStatus. +// +// status must not be _Gdead or any status whose name has the suffix "_unused." +func goStatusToTraceGoStatus(status uint32, wr waitReason) traceGoStatus { + // N.B. Ignore the _Gscan bit. We don't model it in the tracer. + var tgs traceGoStatus + switch status &^ _Gscan { + case _Grunnable: + tgs = traceGoRunnable + case _Grunning, _Gcopystack: + tgs = traceGoRunning + case _Gsyscall: + tgs = traceGoSyscall + case _Gwaiting, _Gpreempted: + // There are a number of cases where a G might end up in + // _Gwaiting but it's actually running in a non-preemptive + // state but needs to present itself as preempted to the + // garbage collector. In these cases, we're not going to + // emit an event, and we want these goroutines to appear in + // the final trace as if they're running, not blocked. + tgs = traceGoWaiting + if status == _Gwaiting && wr.isWaitingForGC() { + tgs = traceGoRunning + } + case _Gdead: + throw("tried to trace dead goroutine") + default: + throw("tried to trace goroutine with invalid or unsupported status") + } + return tgs +} + +// traceSchedResourceState is shared state for scheduling resources (i.e. fields common to +// both Gs and Ps). +type traceSchedResourceState struct { + // statusTraced indicates whether a status event was traced for this resource + // a particular generation. + // + // There are 3 of these because when transitioning across generations, traceAdvance + // needs to be able to reliably observe whether a status was traced for the previous + // generation, while we need to clear the value for the next generation. + statusTraced [3]atomic.Uint32 + + // seq is the sequence counter for this scheduling resource's events. + // The purpose of the sequence counter is to establish a partial order between + // events that don't obviously happen serially (same M) in the stream ofevents. + // + // There are two of these so that we can reset the counter on each generation. + // This saves space in the resulting trace by keeping the counter small and allows + // GoStatus and GoCreate events to omit a sequence number (implicitly 0). + seq [2]uint64 +} + +// acquireStatus acquires the right to emit a Status event for the scheduling resource. +func (r *traceSchedResourceState) acquireStatus(gen uintptr) bool { + if !r.statusTraced[gen%3].CompareAndSwap(0, 1) { + return false + } + r.readyNextGen(gen) + return true +} + +// readyNextGen readies r for the generation following gen. +func (r *traceSchedResourceState) readyNextGen(gen uintptr) { + nextGen := traceNextGen(gen) + r.seq[nextGen%2] = 0 + r.statusTraced[nextGen%3].Store(0) +} + +// statusWasTraced returns true if the sched resource's status was already acquired for tracing. +func (r *traceSchedResourceState) statusWasTraced(gen uintptr) bool { + return r.statusTraced[gen%3].Load() != 0 +} + +// setStatusTraced indicates that the resource's status was already traced, for example +// when a goroutine is created. +func (r *traceSchedResourceState) setStatusTraced(gen uintptr) { + r.statusTraced[gen%3].Store(1) +} + +// nextSeq returns the next sequence number for the resource. +func (r *traceSchedResourceState) nextSeq(gen uintptr) traceArg { + r.seq[gen%2]++ + return traceArg(r.seq[gen%2]) +} diff --git a/contrib/go/_std_1.23/src/runtime/tracestring.go b/contrib/go/_std_1.23/src/runtime/tracestring.go new file mode 100644 index 000000000000..2585c69cc0b7 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracestring.go @@ -0,0 +1,97 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Trace string management. + +package runtime + +// Trace strings. + +const maxTraceStringLen = 1024 + +// traceStringTable is map of string -> unique ID that also manages +// writing strings out into the trace. +type traceStringTable struct { + // lock protects buf. + lock mutex + buf *traceBuf // string batches to write out to the trace. + + // tab is a mapping of string -> unique ID. + tab traceMap +} + +// put adds a string to the table, emits it, and returns a unique ID for it. +func (t *traceStringTable) put(gen uintptr, s string) uint64 { + // Put the string in the table. + ss := stringStructOf(&s) + id, added := t.tab.put(ss.str, uintptr(ss.len)) + if added { + // Write the string to the buffer. + systemstack(func() { + t.writeString(gen, id, s) + }) + } + return id +} + +// emit emits a string and creates an ID for it, but doesn't add it to the table. Returns the ID. +func (t *traceStringTable) emit(gen uintptr, s string) uint64 { + // Grab an ID and write the string to the buffer. + id := t.tab.stealID() + systemstack(func() { + t.writeString(gen, id, s) + }) + return id +} + +// writeString writes the string to t.buf. +// +// Must run on the systemstack because it acquires t.lock. +// +//go:systemstack +func (t *traceStringTable) writeString(gen uintptr, id uint64, s string) { + // Truncate the string if necessary. + if len(s) > maxTraceStringLen { + s = s[:maxTraceStringLen] + } + + lock(&t.lock) + w := unsafeTraceWriter(gen, t.buf) + + // Ensure we have a place to write to. + var flushed bool + w, flushed = w.ensure(2 + 2*traceBytesPerNumber + len(s) /* traceEvStrings + traceEvString + ID + len + string data */) + if flushed { + // Annotate the batch as containing strings. + w.byte(byte(traceEvStrings)) + } + + // Write out the string. + w.byte(byte(traceEvString)) + w.varint(id) + w.varint(uint64(len(s))) + w.stringData(s) + + // Store back buf in case it was updated during ensure. + t.buf = w.traceBuf + unlock(&t.lock) +} + +// reset clears the string table and flushes any buffers it has. +// +// Must be called only once the caller is certain nothing else will be +// added to this table. +func (t *traceStringTable) reset(gen uintptr) { + if t.buf != nil { + systemstack(func() { + lock(&trace.lock) + traceBufFlush(t.buf, gen) + unlock(&trace.lock) + }) + t.buf = nil + } + + // Reset the table. + t.tab.reset() +} diff --git a/contrib/go/_std_1.23/src/runtime/tracetime.go b/contrib/go/_std_1.23/src/runtime/tracetime.go new file mode 100644 index 000000000000..571012413fff --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracetime.go @@ -0,0 +1,94 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Trace time and clock. + +package runtime + +import ( + "internal/goarch" + _ "unsafe" +) + +// Timestamps in trace are produced through either nanotime or cputicks +// and divided by traceTimeDiv. nanotime is used everywhere except on +// platforms where osHasLowResClock is true, because the system clock +// isn't granular enough to get useful information out of a trace in +// many cases. +// +// This makes absolute values of timestamp diffs smaller, and so they are +// encoded in fewer bytes. +// +// The target resolution in all cases is 64 nanoseconds. +// This is based on the fact that fundamentally the execution tracer won't emit +// events more frequently than roughly every 200 ns or so, because that's roughly +// how long it takes to call through the scheduler. +// We could be more aggressive and bump this up to 128 ns while still getting +// useful data, but the extra bit doesn't save us that much and the headroom is +// nice to have. +// +// Hitting this target resolution is easy in the nanotime case: just pick a +// division of 64. In the cputicks case it's a bit more complex. +// +// For x86, on a 3 GHz machine, we'd want to divide by 3*64 to hit our target. +// To keep the division operation efficient, we round that up to 4*64, or 256. +// Given what cputicks represents, we use this on all other platforms except +// for PowerPC. +// The suggested increment frequency for PowerPC's time base register is +// 512 MHz according to Power ISA v2.07 section 6.2, so we use 32 on ppc64 +// and ppc64le. +const traceTimeDiv = (1-osHasLowResClockInt)*64 + osHasLowResClockInt*(256-224*(goarch.IsPpc64|goarch.IsPpc64le)) + +// traceTime represents a timestamp for the trace. +type traceTime uint64 + +// traceClockNow returns a monotonic timestamp. The clock this function gets +// the timestamp from is specific to tracing, and shouldn't be mixed with other +// clock sources. +// +// nosplit because it's called from exitsyscall, which is nosplit. +// +// traceClockNow is called by golang.org/x/exp/trace using linkname. +// +//go:linkname traceClockNow +//go:nosplit +func traceClockNow() traceTime { + if osHasLowResClock { + return traceTime(cputicks() / traceTimeDiv) + } + return traceTime(nanotime() / traceTimeDiv) +} + +// traceClockUnitsPerSecond estimates the number of trace clock units per +// second that elapse. +func traceClockUnitsPerSecond() uint64 { + if osHasLowResClock { + // We're using cputicks as our clock, so we need a real estimate. + return uint64(ticksPerSecond() / traceTimeDiv) + } + // Our clock is nanotime, so it's just the constant time division. + // (trace clock units / nanoseconds) * (1e9 nanoseconds / 1 second) + return uint64(1.0 / float64(traceTimeDiv) * 1e9) +} + +// traceFrequency writes a batch with a single EvFrequency event. +// +// freq is the number of trace clock units per second. +func traceFrequency(gen uintptr) { + w := unsafeTraceWriter(gen, nil) + + // Ensure we have a place to write to. + w, _ = w.ensure(1 + traceBytesPerNumber /* traceEvFrequency + frequency */) + + // Write out the string. + w.byte(byte(traceEvFrequency)) + w.varint(traceClockUnitsPerSecond()) + + // Immediately flush the buffer. + systemstack(func() { + lock(&trace.lock) + traceBufFlush(w.traceBuf, gen) + unlock(&trace.lock) + }) +} diff --git a/contrib/go/_std_1.23/src/runtime/tracetype.go b/contrib/go/_std_1.23/src/runtime/tracetype.go new file mode 100644 index 000000000000..b27a6909168b --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracetype.go @@ -0,0 +1,82 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Trace stack table and acquisition. + +package runtime + +import ( + "internal/abi" + "internal/goarch" + "unsafe" +) + +// traceTypeTable maps stack traces (arrays of PC's) to unique uint32 ids. +// It is lock-free for reading. +type traceTypeTable struct { + tab traceMap +} + +// put returns a unique id for the type typ and caches it in the table, +// if it's seeing it for the first time. +// +// N.B. typ must be kept alive forever for this to work correctly. +func (t *traceTypeTable) put(typ *abi.Type) uint64 { + if typ == nil { + return 0 + } + // Insert the pointer to the type itself. + id, _ := t.tab.put(noescape(unsafe.Pointer(&typ)), goarch.PtrSize) + return id +} + +// dump writes all previously cached types to trace buffers and +// releases all memory and resets state. It must only be called once the caller +// can guarantee that there are no more writers to the table. +func (t *traceTypeTable) dump(gen uintptr) { + w := unsafeTraceExpWriter(gen, nil, traceExperimentAllocFree) + if root := (*traceMapNode)(t.tab.root.Load()); root != nil { + w = dumpTypesRec(root, w) + } + w.flush().end() + t.tab.reset() +} + +func dumpTypesRec(node *traceMapNode, w traceExpWriter) traceExpWriter { + typ := (*abi.Type)(*(*unsafe.Pointer)(unsafe.Pointer(&node.data[0]))) + typName := toRType(typ).string() + + // The maximum number of bytes required to hold the encoded type. + maxBytes := 1 + 5*traceBytesPerNumber + len(typName) + + // Estimate the size of this record. This + // bound is pretty loose, but avoids counting + // lots of varint sizes. + // + // Add 1 because we might also write a traceAllocFreeTypesBatch byte. + var flushed bool + w, flushed = w.ensure(1 + maxBytes) + if flushed { + // Annotate the batch as containing types. + w.byte(byte(traceAllocFreeTypesBatch)) + } + + // Emit type. + w.varint(uint64(node.id)) + w.varint(uint64(uintptr(unsafe.Pointer(typ)))) + w.varint(uint64(typ.Size())) + w.varint(uint64(typ.PtrBytes)) + w.varint(uint64(len(typName))) + w.stringData(typName) + + // Recursively walk all child nodes. + for i := range node.children { + child := node.children[i].Load() + if child == nil { + continue + } + w = dumpTypesRec((*traceMapNode)(child), w) + } + return w +} diff --git a/contrib/go/_std_1.23/src/runtime/type.go b/contrib/go/_std_1.23/src/runtime/type.go new file mode 100644 index 000000000000..201340752b81 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/type.go @@ -0,0 +1,487 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Runtime type representation. + +package runtime + +import ( + "internal/abi" + "unsafe" +) + +type nameOff = abi.NameOff +type typeOff = abi.TypeOff +type textOff = abi.TextOff + +type _type = abi.Type + +// rtype is a wrapper that allows us to define additional methods. +type rtype struct { + *abi.Type // embedding is okay here (unlike reflect) because none of this is public +} + +func (t rtype) string() string { + s := t.nameOff(t.Str).Name() + if t.TFlag&abi.TFlagExtraStar != 0 { + return s[1:] + } + return s +} + +func (t rtype) uncommon() *uncommontype { + return t.Uncommon() +} + +func (t rtype) name() string { + if t.TFlag&abi.TFlagNamed == 0 { + return "" + } + s := t.string() + i := len(s) - 1 + sqBrackets := 0 + for i >= 0 && (s[i] != '.' || sqBrackets != 0) { + switch s[i] { + case ']': + sqBrackets++ + case '[': + sqBrackets-- + } + i-- + } + return s[i+1:] +} + +// pkgpath returns the path of the package where t was defined, if +// available. This is not the same as the reflect package's PkgPath +// method, in that it returns the package path for struct and interface +// types, not just named types. +func (t rtype) pkgpath() string { + if u := t.uncommon(); u != nil { + return t.nameOff(u.PkgPath).Name() + } + switch t.Kind_ & abi.KindMask { + case abi.Struct: + st := (*structtype)(unsafe.Pointer(t.Type)) + return st.PkgPath.Name() + case abi.Interface: + it := (*interfacetype)(unsafe.Pointer(t.Type)) + return it.PkgPath.Name() + } + return "" +} + +// reflectOffs holds type offsets defined at run time by the reflect package. +// +// When a type is defined at run time, its *rtype data lives on the heap. +// There are a wide range of possible addresses the heap may use, that +// may not be representable as a 32-bit offset. Moreover the GC may +// one day start moving heap memory, in which case there is no stable +// offset that can be defined. +// +// To provide stable offsets, we add pin *rtype objects in a global map +// and treat the offset as an identifier. We use negative offsets that +// do not overlap with any compile-time module offsets. +// +// Entries are created by reflect.addReflectOff. +var reflectOffs struct { + lock mutex + next int32 + m map[int32]unsafe.Pointer + minv map[unsafe.Pointer]int32 +} + +func reflectOffsLock() { + lock(&reflectOffs.lock) + if raceenabled { + raceacquire(unsafe.Pointer(&reflectOffs.lock)) + } +} + +func reflectOffsUnlock() { + if raceenabled { + racerelease(unsafe.Pointer(&reflectOffs.lock)) + } + unlock(&reflectOffs.lock) +} + +// resolveNameOff should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname resolveNameOff +func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { + if off == 0 { + return name{} + } + base := uintptr(ptrInModule) + for md := &firstmoduledata; md != nil; md = md.next { + if base >= md.types && base < md.etypes { + res := md.types + uintptr(off) + if res > md.etypes { + println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) + throw("runtime: name offset out of range") + } + return name{Bytes: (*byte)(unsafe.Pointer(res))} + } + } + + // No module found. see if it is a run time name. + reflectOffsLock() + res, found := reflectOffs.m[int32(off)] + reflectOffsUnlock() + if !found { + println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:") + for next := &firstmoduledata; next != nil; next = next.next { + println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) + } + throw("runtime: name offset base pointer out of range") + } + return name{Bytes: (*byte)(res)} +} + +func (t rtype) nameOff(off nameOff) name { + return resolveNameOff(unsafe.Pointer(t.Type), off) +} + +// resolveTypeOff should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname resolveTypeOff +func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type { + if off == 0 || off == -1 { + // -1 is the sentinel value for unreachable code. + // See cmd/link/internal/ld/data.go:relocsym. + return nil + } + base := uintptr(ptrInModule) + var md *moduledata + for next := &firstmoduledata; next != nil; next = next.next { + if base >= next.types && base < next.etypes { + md = next + break + } + } + if md == nil { + reflectOffsLock() + res := reflectOffs.m[int32(off)] + reflectOffsUnlock() + if res == nil { + println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:") + for next := &firstmoduledata; next != nil; next = next.next { + println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) + } + throw("runtime: type offset base pointer out of range") + } + return (*_type)(res) + } + if t := md.typemap[off]; t != nil { + return t + } + res := md.types + uintptr(off) + if res > md.etypes { + println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) + throw("runtime: type offset out of range") + } + return (*_type)(unsafe.Pointer(res)) +} + +func (t rtype) typeOff(off typeOff) *_type { + return resolveTypeOff(unsafe.Pointer(t.Type), off) +} + +func (t rtype) textOff(off textOff) unsafe.Pointer { + if off == -1 { + // -1 is the sentinel value for unreachable code. + // See cmd/link/internal/ld/data.go:relocsym. + return unsafe.Pointer(abi.FuncPCABIInternal(unreachableMethod)) + } + base := uintptr(unsafe.Pointer(t.Type)) + var md *moduledata + for next := &firstmoduledata; next != nil; next = next.next { + if base >= next.types && base < next.etypes { + md = next + break + } + } + if md == nil { + reflectOffsLock() + res := reflectOffs.m[int32(off)] + reflectOffsUnlock() + if res == nil { + println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:") + for next := &firstmoduledata; next != nil; next = next.next { + println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) + } + throw("runtime: text offset base pointer out of range") + } + return res + } + res := md.textAddr(uint32(off)) + return unsafe.Pointer(res) +} + +type uncommontype = abi.UncommonType + +type interfacetype = abi.InterfaceType + +type maptype = abi.MapType + +type arraytype = abi.ArrayType + +type chantype = abi.ChanType + +type slicetype = abi.SliceType + +type functype = abi.FuncType + +type ptrtype = abi.PtrType + +type name = abi.Name + +type structtype = abi.StructType + +func pkgPath(n name) string { + if n.Bytes == nil || *n.Data(0)&(1<<2) == 0 { + return "" + } + i, l := n.ReadVarint(1) + off := 1 + i + l + if *n.Data(0)&(1<<1) != 0 { + i2, l2 := n.ReadVarint(off) + off += i2 + l2 + } + var nameOff nameOff + copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.Data(off)))[:]) + pkgPathName := resolveNameOff(unsafe.Pointer(n.Bytes), nameOff) + return pkgPathName.Name() +} + +// typelinksinit scans the types from extra modules and builds the +// moduledata typemap used to de-duplicate type pointers. +func typelinksinit() { + if firstmoduledata.next == nil { + return + } + typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks)) + + modules := activeModules() + prev := modules[0] + for _, md := range modules[1:] { + // Collect types from the previous module into typehash. + collect: + for _, tl := range prev.typelinks { + var t *_type + if prev.typemap == nil { + t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl))) + } else { + t = prev.typemap[typeOff(tl)] + } + // Add to typehash if not seen before. + tlist := typehash[t.Hash] + for _, tcur := range tlist { + if tcur == t { + continue collect + } + } + typehash[t.Hash] = append(tlist, t) + } + + if md.typemap == nil { + // If any of this module's typelinks match a type from a + // prior module, prefer that prior type by adding the offset + // to this module's typemap. + tm := make(map[typeOff]*_type, len(md.typelinks)) + pinnedTypemaps = append(pinnedTypemaps, tm) + md.typemap = tm + for _, tl := range md.typelinks { + t := (*_type)(unsafe.Pointer(md.types + uintptr(tl))) + for _, candidate := range typehash[t.Hash] { + seen := map[_typePair]struct{}{} + if typesEqual(t, candidate, seen) { + t = candidate + break + } + } + md.typemap[typeOff(tl)] = t + } + } + + prev = md + } +} + +type _typePair struct { + t1 *_type + t2 *_type +} + +func toRType(t *abi.Type) rtype { + return rtype{t} +} + +// typesEqual reports whether two types are equal. +// +// Everywhere in the runtime and reflect packages, it is assumed that +// there is exactly one *_type per Go type, so that pointer equality +// can be used to test if types are equal. There is one place that +// breaks this assumption: buildmode=shared. In this case a type can +// appear as two different pieces of memory. This is hidden from the +// runtime and reflect package by the per-module typemap built in +// typelinksinit. It uses typesEqual to map types from later modules +// back into earlier ones. +// +// Only typelinksinit needs this function. +func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool { + tp := _typePair{t, v} + if _, ok := seen[tp]; ok { + return true + } + + // mark these types as seen, and thus equivalent which prevents an infinite loop if + // the two types are identical, but recursively defined and loaded from + // different modules + seen[tp] = struct{}{} + + if t == v { + return true + } + kind := t.Kind_ & abi.KindMask + if kind != v.Kind_&abi.KindMask { + return false + } + rt, rv := toRType(t), toRType(v) + if rt.string() != rv.string() { + return false + } + ut := t.Uncommon() + uv := v.Uncommon() + if ut != nil || uv != nil { + if ut == nil || uv == nil { + return false + } + pkgpatht := rt.nameOff(ut.PkgPath).Name() + pkgpathv := rv.nameOff(uv.PkgPath).Name() + if pkgpatht != pkgpathv { + return false + } + } + if abi.Bool <= kind && kind <= abi.Complex128 { + return true + } + switch kind { + case abi.String, abi.UnsafePointer: + return true + case abi.Array: + at := (*arraytype)(unsafe.Pointer(t)) + av := (*arraytype)(unsafe.Pointer(v)) + return typesEqual(at.Elem, av.Elem, seen) && at.Len == av.Len + case abi.Chan: + ct := (*chantype)(unsafe.Pointer(t)) + cv := (*chantype)(unsafe.Pointer(v)) + return ct.Dir == cv.Dir && typesEqual(ct.Elem, cv.Elem, seen) + case abi.Func: + ft := (*functype)(unsafe.Pointer(t)) + fv := (*functype)(unsafe.Pointer(v)) + if ft.OutCount != fv.OutCount || ft.InCount != fv.InCount { + return false + } + tin, vin := ft.InSlice(), fv.InSlice() + for i := 0; i < len(tin); i++ { + if !typesEqual(tin[i], vin[i], seen) { + return false + } + } + tout, vout := ft.OutSlice(), fv.OutSlice() + for i := 0; i < len(tout); i++ { + if !typesEqual(tout[i], vout[i], seen) { + return false + } + } + return true + case abi.Interface: + it := (*interfacetype)(unsafe.Pointer(t)) + iv := (*interfacetype)(unsafe.Pointer(v)) + if it.PkgPath.Name() != iv.PkgPath.Name() { + return false + } + if len(it.Methods) != len(iv.Methods) { + return false + } + for i := range it.Methods { + tm := &it.Methods[i] + vm := &iv.Methods[i] + // Note the mhdr array can be relocated from + // another module. See #17724. + tname := resolveNameOff(unsafe.Pointer(tm), tm.Name) + vname := resolveNameOff(unsafe.Pointer(vm), vm.Name) + if tname.Name() != vname.Name() { + return false + } + if pkgPath(tname) != pkgPath(vname) { + return false + } + tityp := resolveTypeOff(unsafe.Pointer(tm), tm.Typ) + vityp := resolveTypeOff(unsafe.Pointer(vm), vm.Typ) + if !typesEqual(tityp, vityp, seen) { + return false + } + } + return true + case abi.Map: + mt := (*maptype)(unsafe.Pointer(t)) + mv := (*maptype)(unsafe.Pointer(v)) + return typesEqual(mt.Key, mv.Key, seen) && typesEqual(mt.Elem, mv.Elem, seen) + case abi.Pointer: + pt := (*ptrtype)(unsafe.Pointer(t)) + pv := (*ptrtype)(unsafe.Pointer(v)) + return typesEqual(pt.Elem, pv.Elem, seen) + case abi.Slice: + st := (*slicetype)(unsafe.Pointer(t)) + sv := (*slicetype)(unsafe.Pointer(v)) + return typesEqual(st.Elem, sv.Elem, seen) + case abi.Struct: + st := (*structtype)(unsafe.Pointer(t)) + sv := (*structtype)(unsafe.Pointer(v)) + if len(st.Fields) != len(sv.Fields) { + return false + } + if st.PkgPath.Name() != sv.PkgPath.Name() { + return false + } + for i := range st.Fields { + tf := &st.Fields[i] + vf := &sv.Fields[i] + if tf.Name.Name() != vf.Name.Name() { + return false + } + if !typesEqual(tf.Typ, vf.Typ, seen) { + return false + } + if tf.Name.Tag() != vf.Name.Tag() { + return false + } + if tf.Offset != vf.Offset { + return false + } + if tf.Name.IsEmbedded() != vf.Name.IsEmbedded() { + return false + } + } + return true + default: + println("runtime: impossible type kind", kind) + throw("runtime: impossible type kind") + return false + } +} diff --git a/contrib/go/_std_1.23/src/runtime/typekind.go b/contrib/go/_std_1.23/src/runtime/typekind.go new file mode 100644 index 000000000000..4920a7cf146c --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/typekind.go @@ -0,0 +1,12 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "internal/abi" + +// isDirectIface reports whether t is stored directly in an interface value. +func isDirectIface(t *_type) bool { + return t.Kind_&abi.KindDirectIface != 0 +} diff --git a/contrib/go/_std_1.23/src/runtime/unsafe.go b/contrib/go/_std_1.23/src/runtime/unsafe.go new file mode 100644 index 000000000000..ca428b56e079 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/unsafe.go @@ -0,0 +1,119 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "runtime/internal/math" + "unsafe" +) + +func unsafestring(ptr unsafe.Pointer, len int) { + if len < 0 { + panicunsafestringlen() + } + + if uintptr(len) > -uintptr(ptr) { + if ptr == nil { + panicunsafestringnilptr() + } + panicunsafestringlen() + } +} + +// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeString +func unsafestring64(ptr unsafe.Pointer, len64 int64) { + len := int(len64) + if int64(len) != len64 { + panicunsafestringlen() + } + unsafestring(ptr, len) +} + +func unsafestringcheckptr(ptr unsafe.Pointer, len64 int64) { + unsafestring64(ptr, len64) + + // Check that underlying array doesn't straddle multiple heap objects. + // unsafestring64 has already checked for overflow. + if checkptrStraddles(ptr, uintptr(len64)) { + throw("checkptr: unsafe.String result straddles multiple allocations") + } +} + +func panicunsafestringlen() { + panic(errorString("unsafe.String: len out of range")) +} + +func panicunsafestringnilptr() { + panic(errorString("unsafe.String: ptr is nil and len is not zero")) +} + +// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice +func unsafeslice(et *_type, ptr unsafe.Pointer, len int) { + if len < 0 { + panicunsafeslicelen1(getcallerpc()) + } + + if et.Size_ == 0 { + if ptr == nil && len > 0 { + panicunsafeslicenilptr1(getcallerpc()) + } + } + + mem, overflow := math.MulUintptr(et.Size_, uintptr(len)) + if overflow || mem > -uintptr(ptr) { + if ptr == nil { + panicunsafeslicenilptr1(getcallerpc()) + } + panicunsafeslicelen1(getcallerpc()) + } +} + +// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice +func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) { + len := int(len64) + if int64(len) != len64 { + panicunsafeslicelen1(getcallerpc()) + } + unsafeslice(et, ptr, len) +} + +func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) { + unsafeslice64(et, ptr, len64) + + // Check that underlying array doesn't straddle multiple heap objects. + // unsafeslice64 has already checked for overflow. + if checkptrStraddles(ptr, uintptr(len64)*et.Size_) { + throw("checkptr: unsafe.Slice result straddles multiple allocations") + } +} + +func panicunsafeslicelen() { + // This is called only from compiler-generated code, so we can get the + // source of the panic. + panicunsafeslicelen1(getcallerpc()) +} + +//go:yeswritebarrierrec +func panicunsafeslicelen1(pc uintptr) { + panicCheck1(pc, "unsafe.Slice: len out of range") + panic(errorString("unsafe.Slice: len out of range")) +} + +func panicunsafeslicenilptr() { + // This is called only from compiler-generated code, so we can get the + // source of the panic. + panicunsafeslicenilptr1(getcallerpc()) +} + +//go:yeswritebarrierrec +func panicunsafeslicenilptr1(pc uintptr) { + panicCheck1(pc, "unsafe.Slice: ptr is nil and len is not zero") + panic(errorString("unsafe.Slice: ptr is nil and len is not zero")) +} + +//go:linkname reflect_unsafeslice reflect.unsafeslice +func reflect_unsafeslice(et *_type, ptr unsafe.Pointer, len int) { + unsafeslice(et, ptr, len) +} diff --git a/contrib/go/_std_1.22/src/runtime/utf8.go b/contrib/go/_std_1.23/src/runtime/utf8.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/utf8.go rename to contrib/go/_std_1.23/src/runtime/utf8.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_elf32.go b/contrib/go/_std_1.23/src/runtime/vdso_elf32.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_elf32.go rename to contrib/go/_std_1.23/src/runtime/vdso_elf32.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_elf64.go b/contrib/go/_std_1.23/src/runtime/vdso_elf64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_elf64.go rename to contrib/go/_std_1.23/src/runtime/vdso_elf64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd.go index 0fe21cf64704..feecada03571 100644 --- a/contrib/go/_std_1.22/src/runtime/vdso_freebsd.go +++ b/contrib/go/_std_1.23/src/runtime/vdso_freebsd.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_arm.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd_arm.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_arm64.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_x86.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_x86.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd_x86.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd_x86.go index 66d1c654885a..7ac09cb9f19b 100644 --- a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_x86.go +++ b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_x86.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/vdso_in_none.go b/contrib/go/_std_1.23/src/runtime/vdso_in_none.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_in_none.go rename to contrib/go/_std_1.23/src/runtime/vdso_in_none.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux.go b/contrib/go/_std_1.23/src/runtime/vdso_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_386.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_386.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_386.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_amd64.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_amd64.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_amd64.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_amd64.go index 4e9f748f4a1a..9c564091377e 100644 --- a/contrib/go/_std_1.22/src/runtime/vdso_linux_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/vdso_linux_amd64.go @@ -4,6 +4,8 @@ package runtime +import _ "unsafe" // for linkname + const ( // vdsoArrayMax is the byte-size of a maximally sized array on this architecture. // See cmd/compile/internal/amd64/galign.go arch.MAXWIDTH initialization. @@ -21,3 +23,6 @@ var ( vdsoGettimeofdaySym uintptr vdsoClockgettimeSym uintptr ) + +// vdsoGettimeofdaySym is accessed from the syscall package. +//go:linkname vdsoGettimeofdaySym diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_arm.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_arm.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_arm64.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_arm64.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_loong64.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_loong64.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_mips64x.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_mips64x.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_ppc64x.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_riscv64.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_riscv64.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_s390x.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_s390x.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/vlop_386.s b/contrib/go/_std_1.23/src/runtime/vlop_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vlop_386.s rename to contrib/go/_std_1.23/src/runtime/vlop_386.s diff --git a/contrib/go/_std_1.22/src/runtime/vlop_arm.s b/contrib/go/_std_1.23/src/runtime/vlop_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vlop_arm.s rename to contrib/go/_std_1.23/src/runtime/vlop_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/vlrt.go b/contrib/go/_std_1.23/src/runtime/vlrt.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vlrt.go rename to contrib/go/_std_1.23/src/runtime/vlrt.go diff --git a/contrib/go/_std_1.22/src/runtime/wincallback.go b/contrib/go/_std_1.23/src/runtime/wincallback.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/wincallback.go rename to contrib/go/_std_1.23/src/runtime/wincallback.go diff --git a/contrib/go/_std_1.22/src/runtime/write_err.go b/contrib/go/_std_1.23/src/runtime/write_err.go similarity index 76% rename from contrib/go/_std_1.22/src/runtime/write_err.go rename to contrib/go/_std_1.23/src/runtime/write_err.go index 81ae872e9c03..11ca6bbb94d9 100644 --- a/contrib/go/_std_1.22/src/runtime/write_err.go +++ b/contrib/go/_std_1.23/src/runtime/write_err.go @@ -6,8 +6,9 @@ package runtime -import "unsafe" - +//go:nosplit func writeErr(b []byte) { - write(2, unsafe.Pointer(&b[0]), int32(len(b))) + if len(b) > 0 { + writeErrData(&b[0], int32(len(b))) + } } diff --git a/contrib/go/_std_1.22/src/runtime/write_err_android.go b/contrib/go/_std_1.23/src/runtime/write_err_android.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/write_err_android.go rename to contrib/go/_std_1.23/src/runtime/write_err_android.go index a876900c9548..34de106b5092 100644 --- a/contrib/go/_std_1.22/src/runtime/write_err_android.go +++ b/contrib/go/_std_1.23/src/runtime/write_err_android.go @@ -34,6 +34,10 @@ const ( var logger loggerType func writeErr(b []byte) { + if len(b) == 0 { + return + } + if logger == unknown { // Use logd if /dev/socket/logdw is available. if v := uintptr(access(&writeLogd[0], 0x02 /* W_OK */)); v == 0 { @@ -45,8 +49,9 @@ func writeErr(b []byte) { } } - // Write to stderr for command-line programs. - write(2, unsafe.Pointer(&b[0]), int32(len(b))) + // Write to stderr for command-line programs, + // and optionally to SetCrashOutput file. + writeErrData(&b[0], int32(len(b))) // Log format: "
\x00\x00" // @@ -75,9 +80,7 @@ func writeErr(b []byte) { if v == '\n' || writePos == len(dst)-1 { dst[writePos] = 0 write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(hlen+writePos)) - for i := range dst { - dst[i] = 0 - } + clear(dst) writePos = 0 } } diff --git a/contrib/go/_std_1.23/src/runtime/ya.make b/contrib/go/_std_1.23/src/runtime/ya.make new file mode 100644 index 000000000000..2061e2d2cf97 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/ya.make @@ -0,0 +1,2071 @@ +GO_LIBRARY() + +IF(SANITIZER_TYPE == "memory") + SRCS(msan.go msan_${GO_HOST_ARCH}.s) +ELSE() + SRCS(msan0.go) +ENDIF() + +IF(SANITIZER_TYPE == "address") + SRCS(asan.go asan_${GO_HOST_ARCH}.s) +ELSE() + SRCS(asan0.go) +ENDIF() + +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_arm64.s + atomic_arm64.s + atomic_pointer.go + badlinkname.go + cgo.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_arm64.go + cpuprof.go + create_file_unix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_darwin_arm64.go + duff_arm64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_sema.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_darwin.go + memclr_arm64.s + memmove_arm64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe.go + netpoll.go + netpoll_kqueue.go + netpoll_kqueue_event.go + nonwindows_stub.go + os_darwin.go + os_darwin_arm64.go + os_nonopenbsd.go + os_unix.go + os_unix_nonlinux.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_arm64.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race.go + race_arm64.s + rand.go + rdebug.go + retry.go + rt0_darwin_arm64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_issetugid.go + security_unix.go + select.go + sema.go + signal_arm64.go + signal_darwin.go + signal_darwin_arm64.go + signal_unix.go + sigqueue.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs_arm64.go + stubs_nonlinux.go + symtab.go + symtabinl.go + sys_arm64.go + sys_darwin.go + sys_darwin_arm64.go + sys_darwin_arm64.s + sys_libc.go + sys_nonppc64x.go + tagptr.go + tagptr_64bit.go + test_stubs.go + time.go + time_nofake.go + timestub.go + tls_arm64.s + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_in_none.go + write_err.go + ) +ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_arm64.s + atomic_arm64.s + atomic_pointer.go + badlinkname.go + cgo.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_arm64.go + cpuprof.go + create_file_unix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_darwin_arm64.go + duff_arm64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_sema.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_darwin.go + memclr_arm64.s + memmove_arm64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe.go + netpoll.go + netpoll_kqueue.go + netpoll_kqueue_event.go + nonwindows_stub.go + os_darwin.go + os_darwin_arm64.go + os_nonopenbsd.go + os_unix.go + os_unix_nonlinux.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_arm64.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race0.go + rand.go + rdebug.go + retry.go + rt0_darwin_arm64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_issetugid.go + security_unix.go + select.go + sema.go + signal_arm64.go + signal_darwin.go + signal_darwin_arm64.go + signal_unix.go + sigqueue.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs_arm64.go + stubs_nonlinux.go + symtab.go + symtabinl.go + sys_arm64.go + sys_darwin.go + sys_darwin_arm64.go + sys_darwin_arm64.s + sys_libc.go + sys_nonppc64x.go + tagptr.go + tagptr_64bit.go + test_stubs.go + time.go + time_nofake.go + timestub.go + tls_arm64.s + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_in_none.go + write_err.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_amd64.s + atomic_pointer.go + badlinkname.go + cgo.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_amd64.go + cpuprof.go + cputicks.go + create_file_unix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_darwin_amd64.go + duff_amd64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_sema.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_darwin.go + memclr_amd64.s + memmove_amd64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe.go + netpoll.go + netpoll_kqueue.go + netpoll_kqueue_event.go + nonwindows_stub.go + os_darwin.go + os_nonopenbsd.go + os_unix.go + os_unix_nonlinux.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_amd64.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race.go + race_amd64.s + rand.go + rdebug.go + retry.go + rt0_darwin_amd64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_issetugid.go + security_unix.go + select.go + sema.go + signal_amd64.go + signal_darwin.go + signal_darwin_amd64.go + signal_unix.go + sigqueue.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs_amd64.go + stubs_nonlinux.go + symtab.go + symtabinl.go + sys_darwin.go + sys_darwin_amd64.s + sys_libc.go + sys_nonppc64x.go + sys_x86.go + tagptr.go + tagptr_64bit.go + test_amd64.go + test_amd64.s + time.go + time_nofake.go + timestub.go + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_in_none.go + write_err.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_amd64.s + atomic_pointer.go + badlinkname.go + cgo.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_amd64.go + cpuprof.go + cputicks.go + create_file_unix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_darwin_amd64.go + duff_amd64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_sema.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_darwin.go + memclr_amd64.s + memmove_amd64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe.go + netpoll.go + netpoll_kqueue.go + netpoll_kqueue_event.go + nonwindows_stub.go + os_darwin.go + os_nonopenbsd.go + os_unix.go + os_unix_nonlinux.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_amd64.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race0.go + rand.go + rdebug.go + retry.go + rt0_darwin_amd64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_issetugid.go + security_unix.go + select.go + sema.go + signal_amd64.go + signal_darwin.go + signal_darwin_amd64.go + signal_unix.go + sigqueue.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs_amd64.go + stubs_nonlinux.go + symtab.go + symtabinl.go + sys_darwin.go + sys_darwin_amd64.s + sys_libc.go + sys_nonppc64x.go + sys_x86.go + tagptr.go + tagptr_64bit.go + test_amd64.go + test_amd64.s + time.go + time_nofake.go + timestub.go + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_in_none.go + write_err.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_arm64.s + atomic_arm64.s + atomic_pointer.go + badlinkname.go + badlinkname_linux.go + cgo.go + cgo_mmap.go + cgo_sigaction.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_arm64.go + cpuprof.go + create_file_unix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_linux_arm64.go + duff_arm64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_futex.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_linux.go + memclr_arm64.s + memmove_arm64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe2.go + netpoll.go + netpoll_epoll.go + nonwindows_stub.go + os_linux.go + os_linux_arm64.go + os_linux_generic.go + os_nonopenbsd.go + os_unix.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_arm64.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race.go + race_arm64.s + rand.go + rdebug.go + retry.go + rt0_linux_arm64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_linux.go + security_unix.go + select.go + sema.go + signal_arm64.go + signal_linux_arm64.go + signal_unix.go + sigqueue.go + sigqueue_note.go + sigtab_linux_generic.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs2.go + stubs3.go + stubs_arm64.go + stubs_linux.go + symtab.go + symtabinl.go + sys_arm64.go + sys_linux_arm64.s + sys_nonppc64x.go + tagptr.go + tagptr_64bit.go + test_stubs.go + time.go + time_nofake.go + timestub.go + timestub2.go + tls_arm64.s + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_elf64.go + vdso_linux.go + vdso_linux_arm64.go + write_err.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_arm64.s + atomic_arm64.s + atomic_pointer.go + badlinkname.go + badlinkname_linux.go + cgo.go + cgo_mmap.go + cgo_sigaction.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_arm64.go + cpuprof.go + create_file_unix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_linux_arm64.go + duff_arm64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_futex.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_linux.go + memclr_arm64.s + memmove_arm64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe2.go + netpoll.go + netpoll_epoll.go + nonwindows_stub.go + os_linux.go + os_linux_arm64.go + os_linux_generic.go + os_nonopenbsd.go + os_unix.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_arm64.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race0.go + rand.go + rdebug.go + retry.go + rt0_linux_arm64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_linux.go + security_unix.go + select.go + sema.go + signal_arm64.go + signal_linux_arm64.go + signal_unix.go + sigqueue.go + sigqueue_note.go + sigtab_linux_generic.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs2.go + stubs3.go + stubs_arm64.go + stubs_linux.go + symtab.go + symtabinl.go + sys_arm64.go + sys_linux_arm64.s + sys_nonppc64x.go + tagptr.go + tagptr_64bit.go + test_stubs.go + time.go + time_nofake.go + timestub.go + timestub2.go + tls_arm64.s + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_elf64.go + vdso_linux.go + vdso_linux_arm64.go + write_err.go + ) +ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_amd64.s + atomic_pointer.go + badlinkname.go + badlinkname_linux.go + cgo.go + cgo_mmap.go + cgo_sigaction.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_amd64.go + cpuprof.go + cputicks.go + create_file_unix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_linux_amd64.go + duff_amd64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_futex.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_linux.go + memclr_amd64.s + memmove_amd64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe2.go + netpoll.go + netpoll_epoll.go + nonwindows_stub.go + os_linux.go + os_linux_generic.go + os_linux_noauxv.go + os_linux_x86.go + os_nonopenbsd.go + os_unix.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_amd64.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race.go + race_amd64.s + rand.go + rdebug.go + retry.go + rt0_linux_amd64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_linux.go + security_unix.go + select.go + sema.go + signal_amd64.go + signal_linux_amd64.go + signal_unix.go + sigqueue.go + sigqueue_note.go + sigtab_linux_generic.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs2.go + stubs3.go + stubs_amd64.go + stubs_linux.go + symtab.go + symtabinl.go + sys_linux_amd64.s + sys_nonppc64x.go + sys_x86.go + tagptr.go + tagptr_64bit.go + test_amd64.go + test_amd64.s + time.go + time_linux_amd64.s + time_nofake.go + timeasm.go + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_elf64.go + vdso_linux.go + vdso_linux_amd64.go + write_err.go + ) +ELSEIF (OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_amd64.s + atomic_pointer.go + badlinkname.go + badlinkname_linux.go + cgo.go + cgo_mmap.go + cgo_sigaction.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_amd64.go + cpuprof.go + cputicks.go + create_file_unix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_linux_amd64.go + duff_amd64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_futex.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_linux.go + memclr_amd64.s + memmove_amd64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe2.go + netpoll.go + netpoll_epoll.go + nonwindows_stub.go + os_linux.go + os_linux_generic.go + os_linux_noauxv.go + os_linux_x86.go + os_nonopenbsd.go + os_unix.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_amd64.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race0.go + rand.go + rdebug.go + retry.go + rt0_linux_amd64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_linux.go + security_unix.go + select.go + sema.go + signal_amd64.go + signal_linux_amd64.go + signal_unix.go + sigqueue.go + sigqueue_note.go + sigtab_linux_generic.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs2.go + stubs3.go + stubs_amd64.go + stubs_linux.go + symtab.go + symtabinl.go + sys_linux_amd64.s + sys_nonppc64x.go + sys_x86.go + tagptr.go + tagptr_64bit.go + test_amd64.go + test_amd64.s + time.go + time_linux_amd64.s + time_nofake.go + timeasm.go + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_elf64.go + vdso_linux.go + vdso_linux_amd64.go + write_err.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_arm.s + atomic_pointer.go + badlinkname.go + cgo.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuprof.go + create_file_unix.go + debug.go + debuglog.go + debuglog_off.go + defs_linux_arm.go + duff_arm.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash32.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_futex.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_linux.go + memclr_arm.s + memmove_arm.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mmap.go + mpagealloc.go + mpagealloc_32bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe2.go + netpoll.go + netpoll_epoll.go + nonwindows_stub.go + os_linux.go + os_linux_arm.go + os_linux_generic.go + os_nonopenbsd.go + os_unix.go + panic.go + panic32.go + pinner.go + plugin.go + preempt.go + preempt_arm.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race.go + rand.go + rdebug.go + retry.go + rt0_linux_arm.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_linux.go + security_unix.go + select.go + sema.go + sigaction.go + signal_arm.go + signal_linux_arm.go + signal_unix.go + sigqueue.go + sigqueue_note.go + sigtab_linux_generic.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs2.go + stubs3.go + stubs_arm.go + stubs_linux.go + symtab.go + symtabinl.go + sys_arm.go + sys_linux_arm.s + sys_nonppc64x.go + tagptr.go + tagptr_32bit.go + test_stubs.go + time.go + time_nofake.go + timestub.go + timestub2.go + tls_arm.s + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_elf32.go + vdso_linux.go + vdso_linux_arm.go + vlop_arm.s + vlrt.go + write_err.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_arm.s + atomic_pointer.go + badlinkname.go + cgo.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuprof.go + create_file_unix.go + debug.go + debuglog.go + debuglog_off.go + defs_linux_arm.go + duff_arm.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_unix.go + float.go + hash32.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + linkname_unix.go + lock_futex.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_linux.go + memclr_arm.s + memmove_arm.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mmap.go + mpagealloc.go + mpagealloc_32bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + nbpipe_pipe2.go + netpoll.go + netpoll_epoll.go + nonwindows_stub.go + os_linux.go + os_linux_arm.go + os_linux_generic.go + os_nonopenbsd.go + os_unix.go + panic.go + panic32.go + pinner.go + plugin.go + preempt.go + preempt_arm.s + preempt_nonwindows.go + print.go + proc.go + profbuf.go + proflabel.go + race0.go + rand.go + rdebug.go + retry.go + rt0_linux_arm.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_linux.go + security_unix.go + select.go + sema.go + sigaction.go + signal_arm.go + signal_linux_arm.go + signal_unix.go + sigqueue.go + sigqueue_note.go + sigtab_linux_generic.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs2.go + stubs3.go + stubs_arm.go + stubs_linux.go + symtab.go + symtabinl.go + sys_arm.go + sys_linux_arm.s + sys_nonppc64x.go + tagptr.go + tagptr_32bit.go + test_stubs.go + time.go + time_nofake.go + timestub.go + timestub2.go + tls_arm.s + tls_stub.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_elf32.go + vdso_linux.go + vdso_linux_arm.go + vlop_arm.s + vlrt.go + write_err.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_amd64.s + atomic_pointer.go + auxv_none.go + badlinkname.go + cgo.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_amd64.go + cpuprof.go + cputicks.go + create_file_nounix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_windows.go + defs_windows_amd64.go + duff_amd64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_nonunix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + lock_sema.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_windows.go + memclr_amd64.s + memmove_amd64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + netpoll.go + netpoll_windows.go + os_nonopenbsd.go + os_windows.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_amd64.s + print.go + proc.go + profbuf.go + proflabel.go + race.go + race_amd64.s + rand.go + rdebug.go + rt0_windows_amd64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_nonunix.go + select.go + sema.go + signal_windows.go + sigqueue.go + sigqueue_note.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs3.go + stubs_amd64.go + stubs_nonlinux.go + symtab.go + symtabinl.go + sys_nonppc64x.go + sys_windows_amd64.s + sys_x86.go + syscall_windows.go + tagptr.go + tagptr_64bit.go + test_amd64.go + test_amd64.s + time.go + time_nofake.go + time_windows_amd64.s + timeasm.go + tls_windows_amd64.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_in_none.go + write_err.go + zcallback_windows.go + zcallback_windows.s + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + alg.go + arena.go + asm.s + asm_amd64.s + atomic_pointer.go + auxv_none.go + badlinkname.go + cgo.go + cgocall.go + cgocallback.go + cgocheck.go + chan.go + checkptr.go + compiler.go + complex.go + coro.go + covercounter.go + covermeta.go + cpuflags.go + cpuflags_amd64.go + cpuprof.go + cputicks.go + create_file_nounix.go + debug.go + debugcall.go + debuglog.go + debuglog_off.go + defs_windows.go + defs_windows_amd64.go + duff_amd64.s + env_posix.go + error.go + extern.go + fastlog2.go + fastlog2table.go + fds_nonunix.go + float.go + hash64.go + heapdump.go + histogram.go + iface.go + lfstack.go + linkname.go + lock_sema.go + lockrank.go + lockrank_off.go + malloc.go + map.go + map_fast32.go + map_fast64.go + map_faststr.go + mbarrier.go + mbitmap.go + mcache.go + mcentral.go + mcheckmark.go + mem.go + mem_windows.go + memclr_amd64.s + memmove_amd64.s + metrics.go + mfinal.go + mfixalloc.go + mgc.go + mgclimit.go + mgcmark.go + mgcpacer.go + mgcscavenge.go + mgcstack.go + mgcsweep.go + mgcwork.go + mheap.go + minmax.go + mpagealloc.go + mpagealloc_64bit.go + mpagecache.go + mpallocbits.go + mprof.go + mranges.go + msize.go + mspanset.go + mstats.go + mwbbuf.go + netpoll.go + netpoll_windows.go + os_nonopenbsd.go + os_windows.go + panic.go + pinner.go + plugin.go + preempt.go + preempt_amd64.s + print.go + proc.go + profbuf.go + proflabel.go + race0.go + rand.go + rdebug.go + rt0_windows_amd64.s + runtime.go + runtime1.go + runtime2.go + runtime_boring.go + rwmutex.go + security_nonunix.go + select.go + sema.go + signal_windows.go + sigqueue.go + sigqueue_note.go + sizeclasses.go + slice.go + softfloat64.go + stack.go + stkframe.go + string.go + stubs.go + stubs3.go + stubs_amd64.go + stubs_nonlinux.go + symtab.go + symtabinl.go + sys_nonppc64x.go + sys_windows_amd64.s + sys_x86.go + syscall_windows.go + tagptr.go + tagptr_64bit.go + test_amd64.go + test_amd64.s + time.go + time_nofake.go + time_windows_amd64.s + timeasm.go + tls_windows_amd64.go + trace.go + traceallocfree.go + traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go + type.go + typekind.go + unsafe.go + utf8.go + vdso_in_none.go + write_err.go + zcallback_windows.go + zcallback_windows.s + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/zcallback_windows.go b/contrib/go/_std_1.23/src/runtime/zcallback_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/zcallback_windows.go rename to contrib/go/_std_1.23/src/runtime/zcallback_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/zcallback_windows.s b/contrib/go/_std_1.23/src/runtime/zcallback_windows.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/zcallback_windows.s rename to contrib/go/_std_1.23/src/runtime/zcallback_windows.s diff --git a/contrib/go/_std_1.22/src/runtime/zcallback_windows_arm.s b/contrib/go/_std_1.23/src/runtime/zcallback_windows_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/zcallback_windows_arm.s rename to contrib/go/_std_1.23/src/runtime/zcallback_windows_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/zcallback_windows_arm64.s b/contrib/go/_std_1.23/src/runtime/zcallback_windows_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/zcallback_windows_arm64.s rename to contrib/go/_std_1.23/src/runtime/zcallback_windows_arm64.s diff --git a/contrib/go/_std_1.23/src/slices/iter.go b/contrib/go/_std_1.23/src/slices/iter.go new file mode 100644 index 000000000000..cd8f308ca08e --- /dev/null +++ b/contrib/go/_std_1.23/src/slices/iter.go @@ -0,0 +1,109 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package slices + +import ( + "cmp" + "iter" +) + +// All returns an iterator over index-value pairs in the slice +// in the usual order. +func All[Slice ~[]E, E any](s Slice) iter.Seq2[int, E] { + return func(yield func(int, E) bool) { + for i, v := range s { + if !yield(i, v) { + return + } + } + } +} + +// Backward returns an iterator over index-value pairs in the slice, +// traversing it backward with descending indices. +func Backward[Slice ~[]E, E any](s Slice) iter.Seq2[int, E] { + return func(yield func(int, E) bool) { + for i := len(s) - 1; i >= 0; i-- { + if !yield(i, s[i]) { + return + } + } + } +} + +// Values returns an iterator that yields the slice elements in order. +func Values[Slice ~[]E, E any](s Slice) iter.Seq[E] { + return func(yield func(E) bool) { + for _, v := range s { + if !yield(v) { + return + } + } + } +} + +// AppendSeq appends the values from seq to the slice and +// returns the extended slice. +func AppendSeq[Slice ~[]E, E any](s Slice, seq iter.Seq[E]) Slice { + for v := range seq { + s = append(s, v) + } + return s +} + +// Collect collects values from seq into a new slice and returns it. +func Collect[E any](seq iter.Seq[E]) []E { + return AppendSeq([]E(nil), seq) +} + +// Sorted collects values from seq into a new slice, sorts the slice, +// and returns it. +func Sorted[E cmp.Ordered](seq iter.Seq[E]) []E { + s := Collect(seq) + Sort(s) + return s +} + +// SortedFunc collects values from seq into a new slice, sorts the slice +// using the comparison function, and returns it. +func SortedFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E { + s := Collect(seq) + SortFunc(s, cmp) + return s +} + +// SortedStableFunc collects values from seq into a new slice. +// It then sorts the slice while keeping the original order of equal elements, +// using the comparison function to compare elements. +// It returns the new slice. +func SortedStableFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E { + s := Collect(seq) + SortStableFunc(s, cmp) + return s +} + +// Chunk returns an iterator over consecutive sub-slices of up to n elements of s. +// All but the last sub-slice will have size n. +// All sub-slices are clipped to have no capacity beyond the length. +// If s is empty, the sequence is empty: there is no empty slice in the sequence. +// Chunk panics if n is less than 1. +func Chunk[Slice ~[]E, E any](s Slice, n int) iter.Seq[Slice] { + if n < 1 { + panic("cannot be less than 1") + } + + return func(yield func(Slice) bool) { + for i := 0; i < len(s); i += n { + // Clamp the last chunk to the slice bound as necessary. + end := min(n, len(s[i:])) + + // Set the capacity of each chunk so that appending to a chunk does + // not modify the original slice. + if !yield(s[i : i+end : i+end]) { + return + } + } + } +} diff --git a/contrib/go/_std_1.22/src/slices/slices.go b/contrib/go/_std_1.23/src/slices/slices.go similarity index 89% rename from contrib/go/_std_1.22/src/slices/slices.go rename to contrib/go/_std_1.23/src/slices/slices.go index b0f048a65660..b3cd4e2c0540 100644 --- a/contrib/go/_std_1.22/src/slices/slices.go +++ b/contrib/go/_std_1.23/src/slices/slices.go @@ -7,6 +7,7 @@ package slices import ( "cmp" + "math/bits" "unsafe" ) @@ -14,6 +15,7 @@ import ( // elements equal. If the lengths are different, Equal returns false. // Otherwise, the elements are compared in increasing index order, and the // comparison stops at the first unequal pair. +// Empty and nil slices are considered equal. // Floating point NaNs are not considered equal. func Equal[S ~[]E, E comparable](s1, s2 S) bool { if len(s1) != len(s2) { @@ -258,7 +260,11 @@ func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { return Insert(s, i, v...) } if j == len(s) { - return append(s[:i], v...) + s2 := append(s[:i], v...) + if len(s2) < len(s) { + clear(s[len(s2):]) // zero/nil out the obsolete elements, for GC + } + return s2 } tot := len(s[:i]) + len(v) + len(s[j:]) @@ -338,6 +344,7 @@ func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { // Clone returns a copy of the slice. // The elements are copied using assignment, so this is a shallow clone. +// The result may have additional unused capacity. func Clone[S ~[]E, E any](s S) S { // The s[:0:0] preserves nil in case it matters. return append(s[:0:0], s...) @@ -352,17 +359,21 @@ func Compact[S ~[]E, E comparable](s S) S { if len(s) < 2 { return s } - i := 1 for k := 1; k < len(s); k++ { - if s[k] != s[k-1] { - if i != k { - s[i] = s[k] + if s[k] == s[k-1] { + s2 := s[k:] + for k2 := 1; k2 < len(s2); k2++ { + if s2[k2] != s2[k2-1] { + s[k] = s2[k2] + k++ + } } - i++ + + clear(s[k:]) // zero/nil out the obsolete elements, for GC + return s[:k] } } - clear(s[i:]) // zero/nil out the obsolete elements, for GC - return s[:i] + return s } // CompactFunc is like [Compact] but uses an equality function to compare elements. @@ -372,17 +383,21 @@ func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { if len(s) < 2 { return s } - i := 1 for k := 1; k < len(s); k++ { - if !eq(s[k], s[k-1]) { - if i != k { - s[i] = s[k] + if eq(s[k], s[k-1]) { + s2 := s[k:] + for k2 := 1; k2 < len(s2); k2++ { + if !eq(s2[k2], s2[k2-1]) { + s[k] = s2[k2] + k++ + } } - i++ + + clear(s[k:]) // zero/nil out the obsolete elements, for GC + return s[:k] } } - clear(s[i:]) // zero/nil out the obsolete elements, for GC - return s[:i] + return s } // Grow increases the slice's capacity, if necessary, to guarantee space for @@ -404,65 +419,21 @@ func Clip[S ~[]E, E any](s S) S { return s[:len(s):len(s)] } -// Rotation algorithm explanation: -// -// rotate left by 2 -// start with -// 0123456789 -// split up like this -// 01 234567 89 -// swap first 2 and last 2 -// 89 234567 01 -// join first parts -// 89234567 01 -// recursively rotate first left part by 2 -// 23456789 01 -// join at the end -// 2345678901 -// -// rotate left by 8 -// start with -// 0123456789 -// split up like this -// 01 234567 89 -// swap first 2 and last 2 -// 89 234567 01 -// join last parts -// 89 23456701 -// recursively rotate second part left by 6 -// 89 01234567 -// join at the end -// 8901234567 - // TODO: There are other rotate algorithms. -// This algorithm has the desirable property that it moves each element exactly twice. -// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes. +// This algorithm has the desirable property that it moves each element at most twice. // The follow-cycles algorithm can be 1-write but it is not very cache friendly. -// rotateLeft rotates b left by n spaces. +// rotateLeft rotates s left by r spaces. // s_final[i] = s_orig[i+r], wrapping around. func rotateLeft[E any](s []E, r int) { - for r != 0 && r != len(s) { - if r*2 <= len(s) { - swap(s[:r], s[len(s)-r:]) - s = s[:len(s)-r] - } else { - swap(s[:len(s)-r], s[r:]) - s, r = s[len(s)-r:], r*2-len(s) - } - } + Reverse(s[:r]) + Reverse(s[r:]) + Reverse(s) } func rotateRight[E any](s []E, r int) { rotateLeft(s, len(s)-r) } -// swap swaps the contents of x and y. x and y must be equal length and disjoint. -func swap[E any](x, y []E) { - for i := 0; i < len(x); i++ { - x[i], y[i] = y[i], x[i] - } -} - // overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap. func overlaps[E any](a, b []E) bool { if len(a) == 0 || len(b) == 0 { @@ -513,3 +484,26 @@ func Concat[S ~[]E, E any](slices ...S) S { } return newslice } + +// Repeat returns a new slice that repeats the provided slice the given number of times. +// The result has length and capacity (len(x) * count). +// The result is never nil. +// Repeat panics if count is negative or if the result of (len(x) * count) +// overflows. +func Repeat[S ~[]E, E any](x S, count int) S { + if count < 0 { + panic("cannot be negative") + } + + const maxInt = ^uint(0) >> 1 + if hi, lo := bits.Mul(uint(len(x)), uint(count)); hi > 0 || lo > maxInt { + panic("the result of (len(x) * count) overflows") + } + + newslice := make(S, len(x)*count) + n := copy(newslice, x) + for n < len(newslice) { + n += copy(newslice[n:], newslice[:n]) + } + return newslice +} diff --git a/contrib/go/_std_1.23/src/slices/sort.go b/contrib/go/_std_1.23/src/slices/sort.go new file mode 100644 index 000000000000..f713ffe09473 --- /dev/null +++ b/contrib/go/_std_1.23/src/slices/sort.go @@ -0,0 +1,196 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -generic + +package slices + +import ( + "cmp" + "math/bits" +) + +// Sort sorts a slice of any ordered type in ascending order. +// When sorting floating-point numbers, NaNs are ordered before other values. +func Sort[S ~[]E, E cmp.Ordered](x S) { + n := len(x) + pdqsortOrdered(x, 0, n, bits.Len(uint(n))) +} + +// SortFunc sorts the slice x in ascending order as determined by the cmp +// function. This sort is not guaranteed to be stable. +// cmp(a, b) should return a negative number when a < b, a positive number when +// a > b and zero when a == b or a and b are incomparable in the sense of +// a strict weak ordering. +// +// SortFunc requires that cmp is a strict weak ordering. +// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. +// The function should return 0 for incomparable items. +func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { + n := len(x) + pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp) +} + +// SortStableFunc sorts the slice x while keeping the original order of equal +// elements, using cmp to compare elements in the same way as [SortFunc]. +func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { + stableCmpFunc(x, len(x), cmp) +} + +// IsSorted reports whether x is sorted in ascending order. +func IsSorted[S ~[]E, E cmp.Ordered](x S) bool { + for i := len(x) - 1; i > 0; i-- { + if cmp.Less(x[i], x[i-1]) { + return false + } + } + return true +} + +// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the +// comparison function as defined by [SortFunc]. +func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool { + for i := len(x) - 1; i > 0; i-- { + if cmp(x[i], x[i-1]) < 0 { + return false + } + } + return true +} + +// Min returns the minimal value in x. It panics if x is empty. +// For floating-point numbers, Min propagates NaNs (any NaN value in x +// forces the output to be NaN). +func Min[S ~[]E, E cmp.Ordered](x S) E { + if len(x) < 1 { + panic("slices.Min: empty list") + } + m := x[0] + for i := 1; i < len(x); i++ { + m = min(m, x[i]) + } + return m +} + +// MinFunc returns the minimal value in x, using cmp to compare elements. +// It panics if x is empty. If there is more than one minimal element +// according to the cmp function, MinFunc returns the first one. +func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E { + if len(x) < 1 { + panic("slices.MinFunc: empty list") + } + m := x[0] + for i := 1; i < len(x); i++ { + if cmp(x[i], m) < 0 { + m = x[i] + } + } + return m +} + +// Max returns the maximal value in x. It panics if x is empty. +// For floating-point E, Max propagates NaNs (any NaN value in x +// forces the output to be NaN). +func Max[S ~[]E, E cmp.Ordered](x S) E { + if len(x) < 1 { + panic("slices.Max: empty list") + } + m := x[0] + for i := 1; i < len(x); i++ { + m = max(m, x[i]) + } + return m +} + +// MaxFunc returns the maximal value in x, using cmp to compare elements. +// It panics if x is empty. If there is more than one maximal element +// according to the cmp function, MaxFunc returns the first one. +func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E { + if len(x) < 1 { + panic("slices.MaxFunc: empty list") + } + m := x[0] + for i := 1; i < len(x); i++ { + if cmp(x[i], m) > 0 { + m = x[i] + } + } + return m +} + +// BinarySearch searches for target in a sorted slice and returns the earliest +// position where target is found, or the position where target would appear +// in the sort order; it also returns a bool saying whether the target is +// really found in the slice. The slice must be sorted in increasing order. +func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) { + // Inlining is faster than calling BinarySearchFunc with a lambda. + n := len(x) + // Define x[-1] < target and x[n] >= target. + // Invariant: x[i-1] < target, x[j] >= target. + i, j := 0, n + for i < j { + h := int(uint(i+j) >> 1) // avoid overflow when computing h + // i ≤ h < j + if cmp.Less(x[h], target) { + i = h + 1 // preserves x[i-1] < target + } else { + j = h // preserves x[j] >= target + } + } + // i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i. + return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target))) +} + +// BinarySearchFunc works like [BinarySearch], but uses a custom comparison +// function. The slice must be sorted in increasing order, where "increasing" +// is defined by cmp. cmp should return 0 if the slice element matches +// the target, a negative number if the slice element precedes the target, +// or a positive number if the slice element follows the target. +// cmp must implement the same ordering as the slice, such that if +// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice. +func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) { + n := len(x) + // Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 . + // Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0. + i, j := 0, n + for i < j { + h := int(uint(i+j) >> 1) // avoid overflow when computing h + // i ≤ h < j + if cmp(x[h], target) < 0 { + i = h + 1 // preserves cmp(x[i - 1], target) < 0 + } else { + j = h // preserves cmp(x[j], target) >= 0 + } + } + // i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i. + return i, i < n && cmp(x[i], target) == 0 +} + +type sortedHint int // hint for pdqsort when choosing the pivot + +const ( + unknownHint sortedHint = iota + increasingHint + decreasingHint +) + +// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf +type xorshift uint64 + +func (r *xorshift) Next() uint64 { + *r ^= *r << 13 + *r ^= *r >> 17 + *r ^= *r << 5 + return uint64(*r) +} + +func nextPowerOfTwo(length int) uint { + return 1 << bits.Len(uint(length)) +} + +// isNaN reports whether x is a NaN without requiring the math package. +// This will always return false if T is not floating-point. +func isNaN[T cmp.Ordered](x T) bool { + return x != x +} diff --git a/contrib/go/_std_1.23/src/slices/ya.make b/contrib/go/_std_1.23/src/slices/ya.make new file mode 100644 index 000000000000..f94289df8269 --- /dev/null +++ b/contrib/go/_std_1.23/src/slices/ya.make @@ -0,0 +1,11 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + iter.go + slices.go + sort.go + zsortanyfunc.go + zsortordered.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/slices/zsortanyfunc.go b/contrib/go/_std_1.23/src/slices/zsortanyfunc.go similarity index 100% rename from contrib/go/_std_1.22/src/slices/zsortanyfunc.go rename to contrib/go/_std_1.23/src/slices/zsortanyfunc.go diff --git a/contrib/go/_std_1.22/src/slices/zsortordered.go b/contrib/go/_std_1.23/src/slices/zsortordered.go similarity index 100% rename from contrib/go/_std_1.22/src/slices/zsortordered.go rename to contrib/go/_std_1.23/src/slices/zsortordered.go diff --git a/contrib/go/_std_1.22/src/sort/gen_sort_variants.go b/contrib/go/_std_1.23/src/sort/gen_sort_variants.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/gen_sort_variants.go rename to contrib/go/_std_1.23/src/sort/gen_sort_variants.go diff --git a/contrib/go/_std_1.22/src/sort/search.go b/contrib/go/_std_1.23/src/sort/search.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/search.go rename to contrib/go/_std_1.23/src/sort/search.go diff --git a/contrib/go/_std_1.22/src/sort/slice.go b/contrib/go/_std_1.23/src/sort/slice.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/slice.go rename to contrib/go/_std_1.23/src/sort/slice.go diff --git a/contrib/go/_std_1.22/src/sort/sort.go b/contrib/go/_std_1.23/src/sort/sort.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/sort.go rename to contrib/go/_std_1.23/src/sort/sort.go diff --git a/contrib/go/_std_1.22/src/sort/sort_impl_120.go b/contrib/go/_std_1.23/src/sort/sort_impl_120.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/sort_impl_120.go rename to contrib/go/_std_1.23/src/sort/sort_impl_120.go diff --git a/contrib/go/_std_1.22/src/sort/sort_impl_go121.go b/contrib/go/_std_1.23/src/sort/sort_impl_go121.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/sort_impl_go121.go rename to contrib/go/_std_1.23/src/sort/sort_impl_go121.go diff --git a/contrib/go/_std_1.22/src/sort/ya.make b/contrib/go/_std_1.23/src/sort/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/sort/ya.make rename to contrib/go/_std_1.23/src/sort/ya.make diff --git a/contrib/go/_std_1.22/src/sort/zsortfunc.go b/contrib/go/_std_1.23/src/sort/zsortfunc.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/zsortfunc.go rename to contrib/go/_std_1.23/src/sort/zsortfunc.go diff --git a/contrib/go/_std_1.22/src/sort/zsortinterface.go b/contrib/go/_std_1.23/src/sort/zsortinterface.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/zsortinterface.go rename to contrib/go/_std_1.23/src/sort/zsortinterface.go diff --git a/contrib/go/_std_1.22/src/strconv/atob.go b/contrib/go/_std_1.23/src/strconv/atob.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/atob.go rename to contrib/go/_std_1.23/src/strconv/atob.go diff --git a/contrib/go/_std_1.22/src/strconv/atoc.go b/contrib/go/_std_1.23/src/strconv/atoc.go similarity index 93% rename from contrib/go/_std_1.22/src/strconv/atoc.go rename to contrib/go/_std_1.23/src/strconv/atoc.go index f6fdd14e6496..560bd7920df0 100644 --- a/contrib/go/_std_1.22/src/strconv/atoc.go +++ b/contrib/go/_std_1.23/src/strconv/atoc.go @@ -4,6 +4,8 @@ package strconv +import "internal/stringslite" + const fnParseComplex = "ParseComplex" // convErr splits an error returned by parseFloatPrefix @@ -11,7 +13,7 @@ const fnParseComplex = "ParseComplex" func convErr(err error, s string) (syntax, range_ error) { if x, ok := err.(*NumError); ok { x.Func = fnParseComplex - x.Num = cloneString(s) + x.Num = stringslite.Clone(s) if x.Err == ErrRange { return nil, x } @@ -25,13 +27,13 @@ func convErr(err error, s string) (syntax, range_ error) { // convertible to complex64 without changing its value. // // The number represented by s must be of the form N, Ni, or N±Ni, where N stands -// for a floating-point number as recognized by ParseFloat, and i is the imaginary +// for a floating-point number as recognized by [ParseFloat], and i is the imaginary // component. If the second N is unsigned, a + sign is required between the two components // as indicated by the ±. If the second N is NaN, only a + sign is accepted. // The form may be parenthesized and cannot contain any spaces. // The resulting complex number consists of the two components converted by ParseFloat. // -// The errors that ParseComplex returns have concrete type *NumError +// The errors that ParseComplex returns have concrete type [*NumError] // and include err.Num = s. // // If s is not syntactically well-formed, ParseComplex returns err.Err = ErrSyntax. diff --git a/contrib/go/_std_1.22/src/strconv/atof.go b/contrib/go/_std_1.23/src/strconv/atof.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/atof.go rename to contrib/go/_std_1.23/src/strconv/atof.go diff --git a/contrib/go/_std_1.22/src/strconv/atoi.go b/contrib/go/_std_1.23/src/strconv/atoi.go similarity index 89% rename from contrib/go/_std_1.22/src/strconv/atoi.go rename to contrib/go/_std_1.23/src/strconv/atoi.go index 520d826323bf..599ad9b89508 100644 --- a/contrib/go/_std_1.22/src/strconv/atoi.go +++ b/contrib/go/_std_1.23/src/strconv/atoi.go @@ -4,7 +4,10 @@ package strconv -import "errors" +import ( + "errors" + "internal/stringslite" +) // lower(c) is a lower-case letter if and only if // c is either that lower-case letter or the equivalent upper-case letter. @@ -33,8 +36,6 @@ func (e *NumError) Error() string { func (e *NumError) Unwrap() error { return e.Err } -// cloneString returns a string copy of x. -// // All ParseXXX functions allow the input string to escape to the error value. // This hurts strconv.ParseXXX(string(b)) calls where b is []byte since // the conversion from []byte must allocate a string on the heap. @@ -42,27 +43,21 @@ func (e *NumError) Unwrap() error { return e.Err } // back to the output by copying it first. This allows the compiler to call // strconv.ParseXXX without a heap allocation for most []byte to string // conversions, since it can now prove that the string cannot escape Parse. -// -// TODO: Use strings.Clone instead? However, we cannot depend on "strings" -// since it incurs a transitive dependency on "unicode". -// Either move strings.Clone to an internal/bytealg or make the -// "strings" to "unicode" dependency lighter (see https://go.dev/issue/54098). -func cloneString(x string) string { return string([]byte(x)) } func syntaxError(fn, str string) *NumError { - return &NumError{fn, cloneString(str), ErrSyntax} + return &NumError{fn, stringslite.Clone(str), ErrSyntax} } func rangeError(fn, str string) *NumError { - return &NumError{fn, cloneString(str), ErrRange} + return &NumError{fn, stringslite.Clone(str), ErrRange} } func baseError(fn, str string, base int) *NumError { - return &NumError{fn, cloneString(str), errors.New("invalid base " + Itoa(base))} + return &NumError{fn, stringslite.Clone(str), errors.New("invalid base " + Itoa(base))} } func bitSizeError(fn, str string, bitSize int) *NumError { - return &NumError{fn, cloneString(str), errors.New("invalid bit size " + Itoa(bitSize))} + return &NumError{fn, stringslite.Clone(str), errors.New("invalid bit size " + Itoa(bitSize))} } const intSize = 32 << (^uint(0) >> 63) @@ -72,7 +67,7 @@ const IntSize = intSize const maxUint64 = 1<<64 - 1 -// ParseUint is like ParseInt but for unsigned numbers. +// ParseUint is like [ParseInt] but for unsigned numbers. // // A sign prefix is not permitted. func ParseUint(s string, base int, bitSize int) (uint64, error) { @@ -190,11 +185,11 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) { // correspond to int, int8, int16, int32, and int64. // If bitSize is below 0 or above 64, an error is returned. // -// The errors that ParseInt returns have concrete type *NumError +// The errors that ParseInt returns have concrete type [*NumError] // and include err.Num = s. If s is empty or contains invalid -// digits, err.Err = ErrSyntax and the returned value is 0; +// digits, err.Err = [ErrSyntax] and the returned value is 0; // if the value corresponding to s cannot be represented by a -// signed integer of the given size, err.Err = ErrRange and the +// signed integer of the given size, err.Err = [ErrRange] and the // returned value is the maximum magnitude integer of the // appropriate bitSize and sign. // @@ -221,7 +216,7 @@ func ParseInt(s string, base int, bitSize int) (i int64, err error) { un, err = ParseUint(s, base, bitSize) if err != nil && err.(*NumError).Err != ErrRange { err.(*NumError).Func = fnParseInt - err.(*NumError).Num = cloneString(s0) + err.(*NumError).Num = stringslite.Clone(s0) return 0, err } diff --git a/contrib/go/_std_1.22/src/strconv/bytealg.go b/contrib/go/_std_1.23/src/strconv/bytealg.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/bytealg.go rename to contrib/go/_std_1.23/src/strconv/bytealg.go diff --git a/contrib/go/_std_1.22/src/strconv/bytealg_bootstrap.go b/contrib/go/_std_1.23/src/strconv/bytealg_bootstrap.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/bytealg_bootstrap.go rename to contrib/go/_std_1.23/src/strconv/bytealg_bootstrap.go diff --git a/contrib/go/_std_1.22/src/strconv/ctoa.go b/contrib/go/_std_1.23/src/strconv/ctoa.go similarity index 98% rename from contrib/go/_std_1.22/src/strconv/ctoa.go rename to contrib/go/_std_1.23/src/strconv/ctoa.go index c16a2e579cf1..fd7f941d7034 100644 --- a/contrib/go/_std_1.22/src/strconv/ctoa.go +++ b/contrib/go/_std_1.23/src/strconv/ctoa.go @@ -8,7 +8,7 @@ package strconv // form (a+bi) where a and b are the real and imaginary parts, // formatted according to the format fmt and precision prec. // -// The format fmt and precision prec have the same meaning as in FormatFloat. +// The format fmt and precision prec have the same meaning as in [FormatFloat]. // It rounds the result assuming that the original was obtained from a complex // value of bitSize bits, which must be 64 for complex64 and 128 for complex128. func FormatComplex(c complex128, fmt byte, prec, bitSize int) string { diff --git a/contrib/go/_std_1.22/src/strconv/decimal.go b/contrib/go/_std_1.23/src/strconv/decimal.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/decimal.go rename to contrib/go/_std_1.23/src/strconv/decimal.go diff --git a/contrib/go/_std_1.23/src/strconv/doc.go b/contrib/go/_std_1.23/src/strconv/doc.go new file mode 100644 index 000000000000..51033a62f6a0 --- /dev/null +++ b/contrib/go/_std_1.23/src/strconv/doc.go @@ -0,0 +1,56 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package strconv implements conversions to and from string representations +// of basic data types. +// +// # Numeric Conversions +// +// The most common numeric conversions are [Atoi] (string to int) and [Itoa] (int to string). +// +// i, err := strconv.Atoi("-42") +// s := strconv.Itoa(-42) +// +// These assume decimal and the Go int type. +// +// [ParseBool], [ParseFloat], [ParseInt], and [ParseUint] convert strings to values: +// +// b, err := strconv.ParseBool("true") +// f, err := strconv.ParseFloat("3.1415", 64) +// i, err := strconv.ParseInt("-42", 10, 64) +// u, err := strconv.ParseUint("42", 10, 64) +// +// The parse functions return the widest type (float64, int64, and uint64), +// but if the size argument specifies a narrower width the result can be +// converted to that narrower type without data loss: +// +// s := "2147483647" // biggest int32 +// i64, err := strconv.ParseInt(s, 10, 32) +// ... +// i := int32(i64) +// +// [FormatBool], [FormatFloat], [FormatInt], and [FormatUint] convert values to strings: +// +// s := strconv.FormatBool(true) +// s := strconv.FormatFloat(3.1415, 'E', -1, 64) +// s := strconv.FormatInt(-42, 16) +// s := strconv.FormatUint(42, 16) +// +// [AppendBool], [AppendFloat], [AppendInt], and [AppendUint] are similar but +// append the formatted value to a destination slice. +// +// # String Conversions +// +// [Quote] and [QuoteToASCII] convert strings to quoted Go string literals. +// The latter guarantees that the result is an ASCII string, by escaping +// any non-ASCII Unicode with \u: +// +// q := strconv.Quote("Hello, 世界") +// q := strconv.QuoteToASCII("Hello, 世界") +// +// [QuoteRune] and [QuoteRuneToASCII] are similar but accept runes and +// return quoted Go rune literals. +// +// [Unquote] and [UnquoteChar] unquote Go string and rune literals. +package strconv diff --git a/contrib/go/_std_1.22/src/strconv/eisel_lemire.go b/contrib/go/_std_1.23/src/strconv/eisel_lemire.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/eisel_lemire.go rename to contrib/go/_std_1.23/src/strconv/eisel_lemire.go diff --git a/contrib/go/_std_1.22/src/strconv/ftoa.go b/contrib/go/_std_1.23/src/strconv/ftoa.go similarity index 99% rename from contrib/go/_std_1.22/src/strconv/ftoa.go rename to contrib/go/_std_1.23/src/strconv/ftoa.go index c514e663da19..220869898f83 100644 --- a/contrib/go/_std_1.22/src/strconv/ftoa.go +++ b/contrib/go/_std_1.23/src/strconv/ftoa.go @@ -49,7 +49,7 @@ func FormatFloat(f float64, fmt byte, prec, bitSize int) string { } // AppendFloat appends the string form of the floating-point number f, -// as generated by FormatFloat, to dst and returns the extended buffer. +// as generated by [FormatFloat], to dst and returns the extended buffer. func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte { return genericFtoa(dst, f, fmt, prec, bitSize) } diff --git a/contrib/go/_std_1.22/src/strconv/ftoaryu.go b/contrib/go/_std_1.23/src/strconv/ftoaryu.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/ftoaryu.go rename to contrib/go/_std_1.23/src/strconv/ftoaryu.go diff --git a/contrib/go/_std_1.22/src/strconv/isprint.go b/contrib/go/_std_1.23/src/strconv/isprint.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/isprint.go rename to contrib/go/_std_1.23/src/strconv/isprint.go diff --git a/contrib/go/_std_1.22/src/strconv/itoa.go b/contrib/go/_std_1.23/src/strconv/itoa.go similarity index 96% rename from contrib/go/_std_1.22/src/strconv/itoa.go rename to contrib/go/_std_1.23/src/strconv/itoa.go index b0c2666e7cb7..29fec41fe2e4 100644 --- a/contrib/go/_std_1.22/src/strconv/itoa.go +++ b/contrib/go/_std_1.23/src/strconv/itoa.go @@ -30,13 +30,13 @@ func FormatInt(i int64, base int) string { return s } -// Itoa is equivalent to FormatInt(int64(i), 10). +// Itoa is equivalent to [FormatInt](int64(i), 10). func Itoa(i int) string { return FormatInt(int64(i), 10) } // AppendInt appends the string form of the integer i, -// as generated by FormatInt, to dst and returns the extended buffer. +// as generated by [FormatInt], to dst and returns the extended buffer. func AppendInt(dst []byte, i int64, base int) []byte { if fastSmalls && 0 <= i && i < nSmalls && base == 10 { return append(dst, small(int(i))...) @@ -46,7 +46,7 @@ func AppendInt(dst []byte, i int64, base int) []byte { } // AppendUint appends the string form of the unsigned integer i, -// as generated by FormatUint, to dst and returns the extended buffer. +// as generated by [FormatUint], to dst and returns the extended buffer. func AppendUint(dst []byte, i uint64, base int) []byte { if fastSmalls && i < nSmalls && base == 10 { return append(dst, small(int(i))...) diff --git a/contrib/go/_std_1.22/src/strconv/makeisprint.go b/contrib/go/_std_1.23/src/strconv/makeisprint.go similarity index 84% rename from contrib/go/_std_1.22/src/strconv/makeisprint.go rename to contrib/go/_std_1.23/src/strconv/makeisprint.go index ff361e7b41fb..767448067b72 100644 --- a/contrib/go/_std_1.22/src/strconv/makeisprint.go +++ b/contrib/go/_std_1.23/src/strconv/makeisprint.go @@ -19,6 +19,7 @@ import ( "go/format" "log" "os" + "slices" "unicode" ) @@ -31,36 +32,6 @@ var ( except32 []uint32 ) -// bsearch16 returns the smallest i such that a[i] >= x. -// If there is no such i, bsearch16 returns len(a). -func bsearch16(a []uint16, x uint16) int { - i, j := 0, len(a) - for i < j { - h := i + (j-i)>>1 - if a[h] < x { - i = h + 1 - } else { - j = h - } - } - return i -} - -// bsearch32 returns the smallest i such that a[i] >= x. -// If there is no such i, bsearch32 returns len(a). -func bsearch32(a []uint32, x uint32) int { - i, j := 0, len(a) - for i < j { - h := i + (j-i)>>1 - if a[h] < x { - i = h + 1 - } else { - j = h - } - } - return i -} - func isPrint(r rune) bool { // Same algorithm, either on uint16 or uint32 value. // First, find first i such that rang[i] >= x. @@ -70,21 +41,21 @@ func isPrint(r rune) bool { if 0 <= r && r < 1<<16 { rr, rang, except := uint16(r), range16, except16 - i := bsearch16(rang, rr) + i, _ := slices.BinarySearch(rang, rr) if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr { return false } - j := bsearch16(except, rr) - return j >= len(except) || except[j] != rr + _, found := slices.BinarySearch(except, rr) + return !found } rr, rang, except := uint32(r), range32, except32 - i := bsearch32(rang, rr) + i, _ := slices.BinarySearch(rang, rr) if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr { return false } - j := bsearch32(except, rr) - return j >= len(except) || except[j] != rr + _, found := slices.BinarySearch(except, rr) + return !found } func scan(min, max rune) (rang, except []uint32) { diff --git a/contrib/go/_std_1.22/src/strconv/quote.go b/contrib/go/_std_1.23/src/strconv/quote.go similarity index 90% rename from contrib/go/_std_1.22/src/strconv/quote.go rename to contrib/go/_std_1.23/src/strconv/quote.go index 7c384336795f..d626cd0837aa 100644 --- a/contrib/go/_std_1.22/src/strconv/quote.go +++ b/contrib/go/_std_1.23/src/strconv/quote.go @@ -121,47 +121,47 @@ func appendEscapedRune(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bo // Quote returns a double-quoted Go string literal representing s. The // returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for // control characters and non-printable characters as defined by -// IsPrint. +// [IsPrint]. func Quote(s string) string { return quoteWith(s, '"', false, false) } // AppendQuote appends a double-quoted Go string literal representing s, -// as generated by Quote, to dst and returns the extended buffer. +// as generated by [Quote], to dst and returns the extended buffer. func AppendQuote(dst []byte, s string) []byte { return appendQuotedWith(dst, s, '"', false, false) } // QuoteToASCII returns a double-quoted Go string literal representing s. // The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for -// non-ASCII characters and non-printable characters as defined by IsPrint. +// non-ASCII characters and non-printable characters as defined by [IsPrint]. func QuoteToASCII(s string) string { return quoteWith(s, '"', true, false) } // AppendQuoteToASCII appends a double-quoted Go string literal representing s, -// as generated by QuoteToASCII, to dst and returns the extended buffer. +// as generated by [QuoteToASCII], to dst and returns the extended buffer. func AppendQuoteToASCII(dst []byte, s string) []byte { return appendQuotedWith(dst, s, '"', true, false) } // QuoteToGraphic returns a double-quoted Go string literal representing s. // The returned string leaves Unicode graphic characters, as defined by -// IsGraphic, unchanged and uses Go escape sequences (\t, \n, \xFF, \u0100) +// [IsGraphic], unchanged and uses Go escape sequences (\t, \n, \xFF, \u0100) // for non-graphic characters. func QuoteToGraphic(s string) string { return quoteWith(s, '"', false, true) } // AppendQuoteToGraphic appends a double-quoted Go string literal representing s, -// as generated by QuoteToGraphic, to dst and returns the extended buffer. +// as generated by [QuoteToGraphic], to dst and returns the extended buffer. func AppendQuoteToGraphic(dst []byte, s string) []byte { return appendQuotedWith(dst, s, '"', false, true) } // QuoteRune returns a single-quoted Go character literal representing the // rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) -// for control characters and non-printable characters as defined by IsPrint. +// for control characters and non-printable characters as defined by [IsPrint]. // If r is not a valid Unicode code point, it is interpreted as the Unicode // replacement character U+FFFD. func QuoteRune(r rune) string { @@ -169,7 +169,7 @@ func QuoteRune(r rune) string { } // AppendQuoteRune appends a single-quoted Go character literal representing the rune, -// as generated by QuoteRune, to dst and returns the extended buffer. +// as generated by [QuoteRune], to dst and returns the extended buffer. func AppendQuoteRune(dst []byte, r rune) []byte { return appendQuotedRuneWith(dst, r, '\'', false, false) } @@ -177,7 +177,7 @@ func AppendQuoteRune(dst []byte, r rune) []byte { // QuoteRuneToASCII returns a single-quoted Go character literal representing // the rune. The returned string uses Go escape sequences (\t, \n, \xFF, // \u0100) for non-ASCII characters and non-printable characters as defined -// by IsPrint. +// by [IsPrint]. // If r is not a valid Unicode code point, it is interpreted as the Unicode // replacement character U+FFFD. func QuoteRuneToASCII(r rune) string { @@ -185,14 +185,14 @@ func QuoteRuneToASCII(r rune) string { } // AppendQuoteRuneToASCII appends a single-quoted Go character literal representing the rune, -// as generated by QuoteRuneToASCII, to dst and returns the extended buffer. +// as generated by [QuoteRuneToASCII], to dst and returns the extended buffer. func AppendQuoteRuneToASCII(dst []byte, r rune) []byte { return appendQuotedRuneWith(dst, r, '\'', true, false) } // QuoteRuneToGraphic returns a single-quoted Go character literal representing // the rune. If the rune is not a Unicode graphic character, -// as defined by IsGraphic, the returned string will use a Go escape sequence +// as defined by [IsGraphic], the returned string will use a Go escape sequence // (\t, \n, \xFF, \u0100). // If r is not a valid Unicode code point, it is interpreted as the Unicode // replacement character U+FFFD. @@ -201,7 +201,7 @@ func QuoteRuneToGraphic(r rune) string { } // AppendQuoteRuneToGraphic appends a single-quoted Go character literal representing the rune, -// as generated by QuoteRuneToGraphic, to dst and returns the extended buffer. +// as generated by [QuoteRuneToGraphic], to dst and returns the extended buffer. func AppendQuoteRuneToGraphic(dst []byte, r rune) []byte { return appendQuotedRuneWith(dst, r, '\'', false, true) } @@ -367,7 +367,7 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, return } -// QuotedPrefix returns the quoted string (as understood by Unquote) at the prefix of s. +// QuotedPrefix returns the quoted string (as understood by [Unquote]) at the prefix of s. // If s does not start with a valid quoted string, QuotedPrefix returns an error. func QuotedPrefix(s string) (string, error) { out, _, err := unquote(s, false) @@ -493,34 +493,20 @@ func unquote(in string, unescape bool) (out, rem string, err error) { } } -// bsearch16 returns the smallest i such that a[i] >= x. -// If there is no such i, bsearch16 returns len(a). -func bsearch16(a []uint16, x uint16) int { - i, j := 0, len(a) +// bsearch is semantically the same as [slices.BinarySearch] (without NaN checks) +// We copied this function because we can not import "slices" here. +func bsearch[S ~[]E, E ~uint16 | ~uint32](s S, v E) (int, bool) { + n := len(s) + i, j := 0, n for i < j { h := i + (j-i)>>1 - if a[h] < x { + if s[h] < v { i = h + 1 } else { j = h } } - return i -} - -// bsearch32 returns the smallest i such that a[i] >= x. -// If there is no such i, bsearch32 returns len(a). -func bsearch32(a []uint32, x uint32) int { - i, j := 0, len(a) - for i < j { - h := i + (j-i)>>1 - if a[h] < x { - i = h + 1 - } else { - j = h - } - } - return i + return i, i < n && s[i] == v } // TODO: IsPrint is a local implementation of unicode.IsPrint, verified by the tests @@ -530,7 +516,7 @@ func bsearch32(a []uint32, x uint32) int { // That would be nice. // IsPrint reports whether the rune is defined as printable by Go, with -// the same definition as unicode.IsPrint: letters, numbers, punctuation, +// the same definition as [unicode.IsPrint]: letters, numbers, punctuation, // symbols and ASCII space. func IsPrint(r rune) bool { // Fast check for Latin-1 @@ -554,16 +540,16 @@ func IsPrint(r rune) bool { if 0 <= r && r < 1<<16 { rr, isPrint, isNotPrint := uint16(r), isPrint16, isNotPrint16 - i := bsearch16(isPrint, rr) + i, _ := bsearch(isPrint, rr) if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr { return false } - j := bsearch16(isNotPrint, rr) - return j >= len(isNotPrint) || isNotPrint[j] != rr + _, found := bsearch(isNotPrint, rr) + return !found } rr, isPrint, isNotPrint := uint32(r), isPrint32, isNotPrint32 - i := bsearch32(isPrint, rr) + i, _ := bsearch(isPrint, rr) if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr { return false } @@ -571,8 +557,8 @@ func IsPrint(r rune) bool { return true } r -= 0x10000 - j := bsearch16(isNotPrint, uint16(r)) - return j >= len(isNotPrint) || isNotPrint[j] != uint16(r) + _, found := bsearch(isNotPrint, uint16(r)) + return !found } // IsGraphic reports whether the rune is defined as a Graphic by Unicode. Such @@ -593,7 +579,6 @@ func isInGraphicList(r rune) bool { if r > 0xFFFF { return false } - rr := uint16(r) - i := bsearch16(isGraphic, rr) - return i < len(isGraphic) && rr == isGraphic[i] + _, found := bsearch(isGraphic, uint16(r)) + return found } diff --git a/contrib/go/_std_1.22/src/strconv/ya.make b/contrib/go/_std_1.23/src/strconv/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/strconv/ya.make rename to contrib/go/_std_1.23/src/strconv/ya.make diff --git a/contrib/go/_std_1.22/src/strings/builder.go b/contrib/go/_std_1.23/src/strings/builder.go similarity index 85% rename from contrib/go/_std_1.22/src/strings/builder.go rename to contrib/go/_std_1.23/src/strings/builder.go index 189dadb1e7f4..e6df08c6f479 100644 --- a/contrib/go/_std_1.22/src/strings/builder.go +++ b/contrib/go/_std_1.23/src/strings/builder.go @@ -5,6 +5,7 @@ package strings import ( + "internal/abi" "internal/bytealg" "unicode/utf8" "unsafe" @@ -15,20 +16,11 @@ import ( // Do not copy a non-zero Builder. type Builder struct { addr *Builder // of receiver, to detect copies by value - buf []byte -} -// noescape hides a pointer from escape analysis. It is the identity function -// but escape analysis doesn't think the output depends on the input. -// noescape is inlined and currently compiles down to zero instructions. -// USE CAREFULLY! -// This was copied from the runtime; see issues 23382 and 7921. -// -//go:nosplit -//go:nocheckptr -func noescape(p unsafe.Pointer) unsafe.Pointer { - x := uintptr(p) - return unsafe.Pointer(x ^ 0) + // External users should never get direct access to this buffer, since + // the slice at some point will be converted to a string using unsafe, also + // data between len(buf) and cap(buf) might be uninitialized. + buf []byte } func (b *Builder) copyCheck() { @@ -38,7 +30,7 @@ func (b *Builder) copyCheck() { // See issue 23382. // TODO: once issue 7921 is fixed, this should be reverted to // just "b.addr = b". - b.addr = (*Builder)(noescape(unsafe.Pointer(b))) + b.addr = (*Builder)(abi.NoEscape(unsafe.Pointer(b))) } else if b.addr != b { panic("strings: illegal use of non-zero Builder copied by value") } diff --git a/contrib/go/_std_1.23/src/strings/clone.go b/contrib/go/_std_1.23/src/strings/clone.go new file mode 100644 index 000000000000..f965b5963a3b --- /dev/null +++ b/contrib/go/_std_1.23/src/strings/clone.go @@ -0,0 +1,23 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings + +import ( + "internal/stringslite" +) + +// Clone returns a fresh copy of s. +// It guarantees to make a copy of s into a new allocation, +// which can be important when retaining only a small substring +// of a much larger string. Using Clone can help such programs +// use less memory. Of course, since using Clone makes a copy, +// overuse of Clone can make programs use more memory. +// Clone should typically be used only rarely, and only when +// profiling indicates that it is needed. +// For strings of length zero the string "" will be returned +// and no allocation is made. +func Clone(s string) string { + return stringslite.Clone(s) +} diff --git a/contrib/go/_std_1.23/src/strings/compare.go b/contrib/go/_std_1.23/src/strings/compare.go new file mode 100644 index 000000000000..dcf442471af6 --- /dev/null +++ b/contrib/go/_std_1.23/src/strings/compare.go @@ -0,0 +1,17 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings + +import "internal/bytealg" + +// Compare returns an integer comparing two strings lexicographically. +// The result will be 0 if a == b, -1 if a < b, and +1 if a > b. +// +// Use Compare when you need to perform a three-way comparison (with +// [slices.SortFunc], for example). It is usually clearer and always faster +// to use the built-in string comparison operators ==, <, >, and so on. +func Compare(a, b string) int { + return bytealg.CompareString(a, b) +} diff --git a/contrib/go/_std_1.22/src/strings/reader.go b/contrib/go/_std_1.23/src/strings/reader.go similarity index 100% rename from contrib/go/_std_1.22/src/strings/reader.go rename to contrib/go/_std_1.23/src/strings/reader.go diff --git a/contrib/go/_std_1.22/src/strings/replace.go b/contrib/go/_std_1.23/src/strings/replace.go similarity index 99% rename from contrib/go/_std_1.22/src/strings/replace.go rename to contrib/go/_std_1.23/src/strings/replace.go index 3b17a55b915d..ae127288003d 100644 --- a/contrib/go/_std_1.22/src/strings/replace.go +++ b/contrib/go/_std_1.23/src/strings/replace.go @@ -299,7 +299,7 @@ func makeGenericReplacer(oldnew []string) *genericReplacer { type appendSliceWriter []byte -// Write writes to the buffer to satisfy io.Writer. +// Write writes to the buffer to satisfy [io.Writer]. func (w *appendSliceWriter) Write(p []byte) (int, error) { *w = append(*w, p...) return len(p), nil diff --git a/contrib/go/_std_1.22/src/strings/search.go b/contrib/go/_std_1.23/src/strings/search.go similarity index 100% rename from contrib/go/_std_1.22/src/strings/search.go rename to contrib/go/_std_1.23/src/strings/search.go diff --git a/contrib/go/_std_1.23/src/strings/strings.go b/contrib/go/_std_1.23/src/strings/strings.go new file mode 100644 index 000000000000..0bd3c1c23378 --- /dev/null +++ b/contrib/go/_std_1.23/src/strings/strings.go @@ -0,0 +1,1246 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package strings implements simple functions to manipulate UTF-8 encoded strings. +// +// For information about UTF-8 strings in Go, see https://blog.golang.org/strings. +package strings + +import ( + "internal/bytealg" + "internal/stringslite" + "unicode" + "unicode/utf8" +) + +const maxInt = int(^uint(0) >> 1) + +// explode splits s into a slice of UTF-8 strings, +// one string per Unicode character up to a maximum of n (n < 0 means no limit). +// Invalid UTF-8 bytes are sliced individually. +func explode(s string, n int) []string { + l := utf8.RuneCountInString(s) + if n < 0 || n > l { + n = l + } + a := make([]string, n) + for i := 0; i < n-1; i++ { + _, size := utf8.DecodeRuneInString(s) + a[i] = s[:size] + s = s[size:] + } + if n > 0 { + a[n-1] = s + } + return a +} + +// Count counts the number of non-overlapping instances of substr in s. +// If substr is an empty string, Count returns 1 + the number of Unicode code points in s. +func Count(s, substr string) int { + // special case + if len(substr) == 0 { + return utf8.RuneCountInString(s) + 1 + } + if len(substr) == 1 { + return bytealg.CountString(s, substr[0]) + } + n := 0 + for { + i := Index(s, substr) + if i == -1 { + return n + } + n++ + s = s[i+len(substr):] + } +} + +// Contains reports whether substr is within s. +func Contains(s, substr string) bool { + return Index(s, substr) >= 0 +} + +// ContainsAny reports whether any Unicode code points in chars are within s. +func ContainsAny(s, chars string) bool { + return IndexAny(s, chars) >= 0 +} + +// ContainsRune reports whether the Unicode code point r is within s. +func ContainsRune(s string, r rune) bool { + return IndexRune(s, r) >= 0 +} + +// ContainsFunc reports whether any Unicode code points r within s satisfy f(r). +func ContainsFunc(s string, f func(rune) bool) bool { + return IndexFunc(s, f) >= 0 +} + +// LastIndex returns the index of the last instance of substr in s, or -1 if substr is not present in s. +func LastIndex(s, substr string) int { + n := len(substr) + switch { + case n == 0: + return len(s) + case n == 1: + return bytealg.LastIndexByteString(s, substr[0]) + case n == len(s): + if substr == s { + return 0 + } + return -1 + case n > len(s): + return -1 + } + // Rabin-Karp search from the end of the string + hashss, pow := bytealg.HashStrRev(substr) + last := len(s) - n + var h uint32 + for i := len(s) - 1; i >= last; i-- { + h = h*bytealg.PrimeRK + uint32(s[i]) + } + if h == hashss && s[last:] == substr { + return last + } + for i := last - 1; i >= 0; i-- { + h *= bytealg.PrimeRK + h += uint32(s[i]) + h -= pow * uint32(s[i+n]) + if h == hashss && s[i:i+n] == substr { + return i + } + } + return -1 +} + +// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s. +func IndexByte(s string, c byte) int { + return stringslite.IndexByte(s, c) +} + +// IndexRune returns the index of the first instance of the Unicode code point +// r, or -1 if rune is not present in s. +// If r is [utf8.RuneError], it returns the first instance of any +// invalid UTF-8 byte sequence. +func IndexRune(s string, r rune) int { + switch { + case 0 <= r && r < utf8.RuneSelf: + return IndexByte(s, byte(r)) + case r == utf8.RuneError: + for i, r := range s { + if r == utf8.RuneError { + return i + } + } + return -1 + case !utf8.ValidRune(r): + return -1 + default: + return Index(s, string(r)) + } +} + +// IndexAny returns the index of the first instance of any Unicode code point +// from chars in s, or -1 if no Unicode code point from chars is present in s. +func IndexAny(s, chars string) int { + if chars == "" { + // Avoid scanning all of s. + return -1 + } + if len(chars) == 1 { + // Avoid scanning all of s. + r := rune(chars[0]) + if r >= utf8.RuneSelf { + r = utf8.RuneError + } + return IndexRune(s, r) + } + if len(s) > 8 { + if as, isASCII := makeASCIISet(chars); isASCII { + for i := 0; i < len(s); i++ { + if as.contains(s[i]) { + return i + } + } + return -1 + } + } + for i, c := range s { + if IndexRune(chars, c) >= 0 { + return i + } + } + return -1 +} + +// LastIndexAny returns the index of the last instance of any Unicode code +// point from chars in s, or -1 if no Unicode code point from chars is +// present in s. +func LastIndexAny(s, chars string) int { + if chars == "" { + // Avoid scanning all of s. + return -1 + } + if len(s) == 1 { + rc := rune(s[0]) + if rc >= utf8.RuneSelf { + rc = utf8.RuneError + } + if IndexRune(chars, rc) >= 0 { + return 0 + } + return -1 + } + if len(s) > 8 { + if as, isASCII := makeASCIISet(chars); isASCII { + for i := len(s) - 1; i >= 0; i-- { + if as.contains(s[i]) { + return i + } + } + return -1 + } + } + if len(chars) == 1 { + rc := rune(chars[0]) + if rc >= utf8.RuneSelf { + rc = utf8.RuneError + } + for i := len(s); i > 0; { + r, size := utf8.DecodeLastRuneInString(s[:i]) + i -= size + if rc == r { + return i + } + } + return -1 + } + for i := len(s); i > 0; { + r, size := utf8.DecodeLastRuneInString(s[:i]) + i -= size + if IndexRune(chars, r) >= 0 { + return i + } + } + return -1 +} + +// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s. +func LastIndexByte(s string, c byte) int { + return bytealg.LastIndexByteString(s, c) +} + +// Generic split: splits after each instance of sep, +// including sepSave bytes of sep in the subarrays. +func genSplit(s, sep string, sepSave, n int) []string { + if n == 0 { + return nil + } + if sep == "" { + return explode(s, n) + } + if n < 0 { + n = Count(s, sep) + 1 + } + + if n > len(s)+1 { + n = len(s) + 1 + } + a := make([]string, n) + n-- + i := 0 + for i < n { + m := Index(s, sep) + if m < 0 { + break + } + a[i] = s[:m+sepSave] + s = s[m+len(sep):] + i++ + } + a[i] = s + return a[:i+1] +} + +// SplitN slices s into substrings separated by sep and returns a slice of +// the substrings between those separators. +// +// The count determines the number of substrings to return: +// - n > 0: at most n substrings; the last substring will be the unsplit remainder; +// - n == 0: the result is nil (zero substrings); +// - n < 0: all substrings. +// +// Edge cases for s and sep (for example, empty strings) are handled +// as described in the documentation for [Split]. +// +// To split around the first instance of a separator, see [Cut]. +func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) } + +// SplitAfterN slices s into substrings after each instance of sep and +// returns a slice of those substrings. +// +// The count determines the number of substrings to return: +// - n > 0: at most n substrings; the last substring will be the unsplit remainder; +// - n == 0: the result is nil (zero substrings); +// - n < 0: all substrings. +// +// Edge cases for s and sep (for example, empty strings) are handled +// as described in the documentation for [SplitAfter]. +func SplitAfterN(s, sep string, n int) []string { + return genSplit(s, sep, len(sep), n) +} + +// Split slices s into all substrings separated by sep and returns a slice of +// the substrings between those separators. +// +// If s does not contain sep and sep is not empty, Split returns a +// slice of length 1 whose only element is s. +// +// If sep is empty, Split splits after each UTF-8 sequence. If both s +// and sep are empty, Split returns an empty slice. +// +// It is equivalent to [SplitN] with a count of -1. +// +// To split around the first instance of a separator, see [Cut]. +func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) } + +// SplitAfter slices s into all substrings after each instance of sep and +// returns a slice of those substrings. +// +// If s does not contain sep and sep is not empty, SplitAfter returns +// a slice of length 1 whose only element is s. +// +// If sep is empty, SplitAfter splits after each UTF-8 sequence. If +// both s and sep are empty, SplitAfter returns an empty slice. +// +// It is equivalent to [SplitAfterN] with a count of -1. +func SplitAfter(s, sep string) []string { + return genSplit(s, sep, len(sep), -1) +} + +var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1} + +// Fields splits the string s around each instance of one or more consecutive white space +// characters, as defined by [unicode.IsSpace], returning a slice of substrings of s or an +// empty slice if s contains only white space. +func Fields(s string) []string { + // First count the fields. + // This is an exact count if s is ASCII, otherwise it is an approximation. + n := 0 + wasSpace := 1 + // setBits is used to track which bits are set in the bytes of s. + setBits := uint8(0) + for i := 0; i < len(s); i++ { + r := s[i] + setBits |= r + isSpace := int(asciiSpace[r]) + n += wasSpace & ^isSpace + wasSpace = isSpace + } + + if setBits >= utf8.RuneSelf { + // Some runes in the input string are not ASCII. + return FieldsFunc(s, unicode.IsSpace) + } + // ASCII fast path + a := make([]string, n) + na := 0 + fieldStart := 0 + i := 0 + // Skip spaces in the front of the input. + for i < len(s) && asciiSpace[s[i]] != 0 { + i++ + } + fieldStart = i + for i < len(s) { + if asciiSpace[s[i]] == 0 { + i++ + continue + } + a[na] = s[fieldStart:i] + na++ + i++ + // Skip spaces in between fields. + for i < len(s) && asciiSpace[s[i]] != 0 { + i++ + } + fieldStart = i + } + if fieldStart < len(s) { // Last field might end at EOF. + a[na] = s[fieldStart:] + } + return a +} + +// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c) +// and returns an array of slices of s. If all code points in s satisfy f(c) or the +// string is empty, an empty slice is returned. +// +// FieldsFunc makes no guarantees about the order in which it calls f(c) +// and assumes that f always returns the same value for a given c. +func FieldsFunc(s string, f func(rune) bool) []string { + // A span is used to record a slice of s of the form s[start:end]. + // The start index is inclusive and the end index is exclusive. + type span struct { + start int + end int + } + spans := make([]span, 0, 32) + + // Find the field start and end indices. + // Doing this in a separate pass (rather than slicing the string s + // and collecting the result substrings right away) is significantly + // more efficient, possibly due to cache effects. + start := -1 // valid span start if >= 0 + for end, rune := range s { + if f(rune) { + if start >= 0 { + spans = append(spans, span{start, end}) + // Set start to a negative value. + // Note: using -1 here consistently and reproducibly + // slows down this code by a several percent on amd64. + start = ^start + } + } else { + if start < 0 { + start = end + } + } + } + + // Last field might end at EOF. + if start >= 0 { + spans = append(spans, span{start, len(s)}) + } + + // Create strings from recorded field indices. + a := make([]string, len(spans)) + for i, span := range spans { + a[i] = s[span.start:span.end] + } + + return a +} + +// Join concatenates the elements of its first argument to create a single string. The separator +// string sep is placed between elements in the resulting string. +func Join(elems []string, sep string) string { + switch len(elems) { + case 0: + return "" + case 1: + return elems[0] + } + + var n int + if len(sep) > 0 { + if len(sep) >= maxInt/(len(elems)-1) { + panic("strings: Join output length overflow") + } + n += len(sep) * (len(elems) - 1) + } + for _, elem := range elems { + if len(elem) > maxInt-n { + panic("strings: Join output length overflow") + } + n += len(elem) + } + + var b Builder + b.Grow(n) + b.WriteString(elems[0]) + for _, s := range elems[1:] { + b.WriteString(sep) + b.WriteString(s) + } + return b.String() +} + +// HasPrefix reports whether the string s begins with prefix. +func HasPrefix(s, prefix string) bool { + return stringslite.HasPrefix(s, prefix) +} + +// HasSuffix reports whether the string s ends with suffix. +func HasSuffix(s, suffix string) bool { + return stringslite.HasSuffix(s, suffix) +} + +// Map returns a copy of the string s with all its characters modified +// according to the mapping function. If mapping returns a negative value, the character is +// dropped from the string with no replacement. +func Map(mapping func(rune) rune, s string) string { + // In the worst case, the string can grow when mapped, making + // things unpleasant. But it's so rare we barge in assuming it's + // fine. It could also shrink but that falls out naturally. + + // The output buffer b is initialized on demand, the first + // time a character differs. + var b Builder + + for i, c := range s { + r := mapping(c) + if r == c && c != utf8.RuneError { + continue + } + + var width int + if c == utf8.RuneError { + c, width = utf8.DecodeRuneInString(s[i:]) + if width != 1 && r == c { + continue + } + } else { + width = utf8.RuneLen(c) + } + + b.Grow(len(s) + utf8.UTFMax) + b.WriteString(s[:i]) + if r >= 0 { + b.WriteRune(r) + } + + s = s[i+width:] + break + } + + // Fast path for unchanged input + if b.Cap() == 0 { // didn't call b.Grow above + return s + } + + for _, c := range s { + r := mapping(c) + + if r >= 0 { + // common case + // Due to inlining, it is more performant to determine if WriteByte should be + // invoked rather than always call WriteRune + if r < utf8.RuneSelf { + b.WriteByte(byte(r)) + } else { + // r is not an ASCII rune. + b.WriteRune(r) + } + } + } + + return b.String() +} + +// According to static analysis, spaces, dashes, zeros, equals, and tabs +// are the most commonly repeated string literal, +// often used for display on fixed-width terminal windows. +// Pre-declare constants for these for O(1) repetition in the common-case. +const ( + repeatedSpaces = "" + + " " + + " " + repeatedDashes = "" + + "----------------------------------------------------------------" + + "----------------------------------------------------------------" + repeatedZeroes = "" + + "0000000000000000000000000000000000000000000000000000000000000000" + repeatedEquals = "" + + "================================================================" + + "================================================================" + repeatedTabs = "" + + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" + + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" +) + +// Repeat returns a new string consisting of count copies of the string s. +// +// It panics if count is negative or if the result of (len(s) * count) +// overflows. +func Repeat(s string, count int) string { + switch count { + case 0: + return "" + case 1: + return s + } + + // Since we cannot return an error on overflow, + // we should panic if the repeat will generate an overflow. + // See golang.org/issue/16237. + if count < 0 { + panic("strings: negative Repeat count") + } + if len(s) > maxInt/count { + panic("strings: Repeat output length overflow") + } + n := len(s) * count + + if len(s) == 0 { + return "" + } + + // Optimize for commonly repeated strings of relatively short length. + switch s[0] { + case ' ', '-', '0', '=', '\t': + switch { + case n <= len(repeatedSpaces) && HasPrefix(repeatedSpaces, s): + return repeatedSpaces[:n] + case n <= len(repeatedDashes) && HasPrefix(repeatedDashes, s): + return repeatedDashes[:n] + case n <= len(repeatedZeroes) && HasPrefix(repeatedZeroes, s): + return repeatedZeroes[:n] + case n <= len(repeatedEquals) && HasPrefix(repeatedEquals, s): + return repeatedEquals[:n] + case n <= len(repeatedTabs) && HasPrefix(repeatedTabs, s): + return repeatedTabs[:n] + } + } + + // Past a certain chunk size it is counterproductive to use + // larger chunks as the source of the write, as when the source + // is too large we are basically just thrashing the CPU D-cache. + // So if the result length is larger than an empirically-found + // limit (8KB), we stop growing the source string once the limit + // is reached and keep reusing the same source string - that + // should therefore be always resident in the L1 cache - until we + // have completed the construction of the result. + // This yields significant speedups (up to +100%) in cases where + // the result length is large (roughly, over L2 cache size). + const chunkLimit = 8 * 1024 + chunkMax := n + if n > chunkLimit { + chunkMax = chunkLimit / len(s) * len(s) + if chunkMax == 0 { + chunkMax = len(s) + } + } + + var b Builder + b.Grow(n) + b.WriteString(s) + for b.Len() < n { + chunk := n - b.Len() + if chunk > b.Len() { + chunk = b.Len() + } + if chunk > chunkMax { + chunk = chunkMax + } + b.WriteString(b.String()[:chunk]) + } + return b.String() +} + +// ToUpper returns s with all Unicode letters mapped to their upper case. +func ToUpper(s string) string { + isASCII, hasLower := true, false + for i := 0; i < len(s); i++ { + c := s[i] + if c >= utf8.RuneSelf { + isASCII = false + break + } + hasLower = hasLower || ('a' <= c && c <= 'z') + } + + if isASCII { // optimize for ASCII-only strings. + if !hasLower { + return s + } + var ( + b Builder + pos int + ) + b.Grow(len(s)) + for i := 0; i < len(s); i++ { + c := s[i] + if 'a' <= c && c <= 'z' { + c -= 'a' - 'A' + if pos < i { + b.WriteString(s[pos:i]) + } + b.WriteByte(c) + pos = i + 1 + } + } + if pos < len(s) { + b.WriteString(s[pos:]) + } + return b.String() + } + return Map(unicode.ToUpper, s) +} + +// ToLower returns s with all Unicode letters mapped to their lower case. +func ToLower(s string) string { + isASCII, hasUpper := true, false + for i := 0; i < len(s); i++ { + c := s[i] + if c >= utf8.RuneSelf { + isASCII = false + break + } + hasUpper = hasUpper || ('A' <= c && c <= 'Z') + } + + if isASCII { // optimize for ASCII-only strings. + if !hasUpper { + return s + } + var ( + b Builder + pos int + ) + b.Grow(len(s)) + for i := 0; i < len(s); i++ { + c := s[i] + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + if pos < i { + b.WriteString(s[pos:i]) + } + b.WriteByte(c) + pos = i + 1 + } + } + if pos < len(s) { + b.WriteString(s[pos:]) + } + return b.String() + } + return Map(unicode.ToLower, s) +} + +// ToTitle returns a copy of the string s with all Unicode letters mapped to +// their Unicode title case. +func ToTitle(s string) string { return Map(unicode.ToTitle, s) } + +// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their +// upper case using the case mapping specified by c. +func ToUpperSpecial(c unicode.SpecialCase, s string) string { + return Map(c.ToUpper, s) +} + +// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their +// lower case using the case mapping specified by c. +func ToLowerSpecial(c unicode.SpecialCase, s string) string { + return Map(c.ToLower, s) +} + +// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their +// Unicode title case, giving priority to the special casing rules. +func ToTitleSpecial(c unicode.SpecialCase, s string) string { + return Map(c.ToTitle, s) +} + +// ToValidUTF8 returns a copy of the string s with each run of invalid UTF-8 byte sequences +// replaced by the replacement string, which may be empty. +func ToValidUTF8(s, replacement string) string { + var b Builder + + for i, c := range s { + if c != utf8.RuneError { + continue + } + + _, wid := utf8.DecodeRuneInString(s[i:]) + if wid == 1 { + b.Grow(len(s) + len(replacement)) + b.WriteString(s[:i]) + s = s[i:] + break + } + } + + // Fast path for unchanged input + if b.Cap() == 0 { // didn't call b.Grow above + return s + } + + invalid := false // previous byte was from an invalid UTF-8 sequence + for i := 0; i < len(s); { + c := s[i] + if c < utf8.RuneSelf { + i++ + invalid = false + b.WriteByte(c) + continue + } + _, wid := utf8.DecodeRuneInString(s[i:]) + if wid == 1 { + i++ + if !invalid { + invalid = true + b.WriteString(replacement) + } + continue + } + invalid = false + b.WriteString(s[i : i+wid]) + i += wid + } + + return b.String() +} + +// isSeparator reports whether the rune could mark a word boundary. +// TODO: update when package unicode captures more of the properties. +func isSeparator(r rune) bool { + // ASCII alphanumerics and underscore are not separators + if r <= 0x7F { + switch { + case '0' <= r && r <= '9': + return false + case 'a' <= r && r <= 'z': + return false + case 'A' <= r && r <= 'Z': + return false + case r == '_': + return false + } + return true + } + // Letters and digits are not separators + if unicode.IsLetter(r) || unicode.IsDigit(r) { + return false + } + // Otherwise, all we can do for now is treat spaces as separators. + return unicode.IsSpace(r) +} + +// Title returns a copy of the string s with all Unicode letters that begin words +// mapped to their Unicode title case. +// +// Deprecated: The rule Title uses for word boundaries does not handle Unicode +// punctuation properly. Use golang.org/x/text/cases instead. +func Title(s string) string { + // Use a closure here to remember state. + // Hackish but effective. Depends on Map scanning in order and calling + // the closure once per rune. + prev := ' ' + return Map( + func(r rune) rune { + if isSeparator(prev) { + prev = r + return unicode.ToTitle(r) + } + prev = r + return r + }, + s) +} + +// TrimLeftFunc returns a slice of the string s with all leading +// Unicode code points c satisfying f(c) removed. +func TrimLeftFunc(s string, f func(rune) bool) string { + i := indexFunc(s, f, false) + if i == -1 { + return "" + } + return s[i:] +} + +// TrimRightFunc returns a slice of the string s with all trailing +// Unicode code points c satisfying f(c) removed. +func TrimRightFunc(s string, f func(rune) bool) string { + i := lastIndexFunc(s, f, false) + if i >= 0 && s[i] >= utf8.RuneSelf { + _, wid := utf8.DecodeRuneInString(s[i:]) + i += wid + } else { + i++ + } + return s[0:i] +} + +// TrimFunc returns a slice of the string s with all leading +// and trailing Unicode code points c satisfying f(c) removed. +func TrimFunc(s string, f func(rune) bool) string { + return TrimRightFunc(TrimLeftFunc(s, f), f) +} + +// IndexFunc returns the index into s of the first Unicode +// code point satisfying f(c), or -1 if none do. +func IndexFunc(s string, f func(rune) bool) int { + return indexFunc(s, f, true) +} + +// LastIndexFunc returns the index into s of the last +// Unicode code point satisfying f(c), or -1 if none do. +func LastIndexFunc(s string, f func(rune) bool) int { + return lastIndexFunc(s, f, true) +} + +// indexFunc is the same as IndexFunc except that if +// truth==false, the sense of the predicate function is +// inverted. +func indexFunc(s string, f func(rune) bool, truth bool) int { + for i, r := range s { + if f(r) == truth { + return i + } + } + return -1 +} + +// lastIndexFunc is the same as LastIndexFunc except that if +// truth==false, the sense of the predicate function is +// inverted. +func lastIndexFunc(s string, f func(rune) bool, truth bool) int { + for i := len(s); i > 0; { + r, size := utf8.DecodeLastRuneInString(s[0:i]) + i -= size + if f(r) == truth { + return i + } + } + return -1 +} + +// asciiSet is a 32-byte value, where each bit represents the presence of a +// given ASCII character in the set. The 128-bits of the lower 16 bytes, +// starting with the least-significant bit of the lowest word to the +// most-significant bit of the highest word, map to the full range of all +// 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed, +// ensuring that any non-ASCII character will be reported as not in the set. +// This allocates a total of 32 bytes even though the upper half +// is unused to avoid bounds checks in asciiSet.contains. +type asciiSet [8]uint32 + +// makeASCIISet creates a set of ASCII characters and reports whether all +// characters in chars are ASCII. +func makeASCIISet(chars string) (as asciiSet, ok bool) { + for i := 0; i < len(chars); i++ { + c := chars[i] + if c >= utf8.RuneSelf { + return as, false + } + as[c/32] |= 1 << (c % 32) + } + return as, true +} + +// contains reports whether c is inside the set. +func (as *asciiSet) contains(c byte) bool { + return (as[c/32] & (1 << (c % 32))) != 0 +} + +// Trim returns a slice of the string s with all leading and +// trailing Unicode code points contained in cutset removed. +func Trim(s, cutset string) string { + if s == "" || cutset == "" { + return s + } + if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { + return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0]) + } + if as, ok := makeASCIISet(cutset); ok { + return trimLeftASCII(trimRightASCII(s, &as), &as) + } + return trimLeftUnicode(trimRightUnicode(s, cutset), cutset) +} + +// TrimLeft returns a slice of the string s with all leading +// Unicode code points contained in cutset removed. +// +// To remove a prefix, use [TrimPrefix] instead. +func TrimLeft(s, cutset string) string { + if s == "" || cutset == "" { + return s + } + if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { + return trimLeftByte(s, cutset[0]) + } + if as, ok := makeASCIISet(cutset); ok { + return trimLeftASCII(s, &as) + } + return trimLeftUnicode(s, cutset) +} + +func trimLeftByte(s string, c byte) string { + for len(s) > 0 && s[0] == c { + s = s[1:] + } + return s +} + +func trimLeftASCII(s string, as *asciiSet) string { + for len(s) > 0 { + if !as.contains(s[0]) { + break + } + s = s[1:] + } + return s +} + +func trimLeftUnicode(s, cutset string) string { + for len(s) > 0 { + r, n := rune(s[0]), 1 + if r >= utf8.RuneSelf { + r, n = utf8.DecodeRuneInString(s) + } + if !ContainsRune(cutset, r) { + break + } + s = s[n:] + } + return s +} + +// TrimRight returns a slice of the string s, with all trailing +// Unicode code points contained in cutset removed. +// +// To remove a suffix, use [TrimSuffix] instead. +func TrimRight(s, cutset string) string { + if s == "" || cutset == "" { + return s + } + if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { + return trimRightByte(s, cutset[0]) + } + if as, ok := makeASCIISet(cutset); ok { + return trimRightASCII(s, &as) + } + return trimRightUnicode(s, cutset) +} + +func trimRightByte(s string, c byte) string { + for len(s) > 0 && s[len(s)-1] == c { + s = s[:len(s)-1] + } + return s +} + +func trimRightASCII(s string, as *asciiSet) string { + for len(s) > 0 { + if !as.contains(s[len(s)-1]) { + break + } + s = s[:len(s)-1] + } + return s +} + +func trimRightUnicode(s, cutset string) string { + for len(s) > 0 { + r, n := rune(s[len(s)-1]), 1 + if r >= utf8.RuneSelf { + r, n = utf8.DecodeLastRuneInString(s) + } + if !ContainsRune(cutset, r) { + break + } + s = s[:len(s)-n] + } + return s +} + +// TrimSpace returns a slice of the string s, with all leading +// and trailing white space removed, as defined by Unicode. +func TrimSpace(s string) string { + // Fast path for ASCII: look for the first ASCII non-space byte + start := 0 + for ; start < len(s); start++ { + c := s[start] + if c >= utf8.RuneSelf { + // If we run into a non-ASCII byte, fall back to the + // slower unicode-aware method on the remaining bytes + return TrimFunc(s[start:], unicode.IsSpace) + } + if asciiSpace[c] == 0 { + break + } + } + + // Now look for the first ASCII non-space byte from the end + stop := len(s) + for ; stop > start; stop-- { + c := s[stop-1] + if c >= utf8.RuneSelf { + // start has been already trimmed above, should trim end only + return TrimRightFunc(s[start:stop], unicode.IsSpace) + } + if asciiSpace[c] == 0 { + break + } + } + + // At this point s[start:stop] starts and ends with an ASCII + // non-space bytes, so we're done. Non-ASCII cases have already + // been handled above. + return s[start:stop] +} + +// TrimPrefix returns s without the provided leading prefix string. +// If s doesn't start with prefix, s is returned unchanged. +func TrimPrefix(s, prefix string) string { + return stringslite.TrimPrefix(s, prefix) +} + +// TrimSuffix returns s without the provided trailing suffix string. +// If s doesn't end with suffix, s is returned unchanged. +func TrimSuffix(s, suffix string) string { + return stringslite.TrimSuffix(s, suffix) +} + +// Replace returns a copy of the string s with the first n +// non-overlapping instances of old replaced by new. +// If old is empty, it matches at the beginning of the string +// and after each UTF-8 sequence, yielding up to k+1 replacements +// for a k-rune string. +// If n < 0, there is no limit on the number of replacements. +func Replace(s, old, new string, n int) string { + if old == new || n == 0 { + return s // avoid allocation + } + + // Compute number of replacements. + if m := Count(s, old); m == 0 { + return s // avoid allocation + } else if n < 0 || m < n { + n = m + } + + // Apply replacements to buffer. + var b Builder + b.Grow(len(s) + n*(len(new)-len(old))) + start := 0 + for i := 0; i < n; i++ { + j := start + if len(old) == 0 { + if i > 0 { + _, wid := utf8.DecodeRuneInString(s[start:]) + j += wid + } + } else { + j += Index(s[start:], old) + } + b.WriteString(s[start:j]) + b.WriteString(new) + start = j + len(old) + } + b.WriteString(s[start:]) + return b.String() +} + +// ReplaceAll returns a copy of the string s with all +// non-overlapping instances of old replaced by new. +// If old is empty, it matches at the beginning of the string +// and after each UTF-8 sequence, yielding up to k+1 replacements +// for a k-rune string. +func ReplaceAll(s, old, new string) string { + return Replace(s, old, new, -1) +} + +// EqualFold reports whether s and t, interpreted as UTF-8 strings, +// are equal under simple Unicode case-folding, which is a more general +// form of case-insensitivity. +func EqualFold(s, t string) bool { + // ASCII fast path + i := 0 + for ; i < len(s) && i < len(t); i++ { + sr := s[i] + tr := t[i] + if sr|tr >= utf8.RuneSelf { + goto hasUnicode + } + + // Easy case. + if tr == sr { + continue + } + + // Make sr < tr to simplify what follows. + if tr < sr { + tr, sr = sr, tr + } + // ASCII only, sr/tr must be upper/lower case + if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' { + continue + } + return false + } + // Check if we've exhausted both strings. + return len(s) == len(t) + +hasUnicode: + s = s[i:] + t = t[i:] + for _, sr := range s { + // If t is exhausted the strings are not equal. + if len(t) == 0 { + return false + } + + // Extract first rune from second string. + var tr rune + if t[0] < utf8.RuneSelf { + tr, t = rune(t[0]), t[1:] + } else { + r, size := utf8.DecodeRuneInString(t) + tr, t = r, t[size:] + } + + // If they match, keep going; if not, return false. + + // Easy case. + if tr == sr { + continue + } + + // Make sr < tr to simplify what follows. + if tr < sr { + tr, sr = sr, tr + } + // Fast check for ASCII. + if tr < utf8.RuneSelf { + // ASCII only, sr/tr must be upper/lower case + if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' { + continue + } + return false + } + + // General case. SimpleFold(x) returns the next equivalent rune > x + // or wraps around to smaller values. + r := unicode.SimpleFold(sr) + for r != sr && r < tr { + r = unicode.SimpleFold(r) + } + if r == tr { + continue + } + return false + } + + // First string is empty, so check if the second one is also empty. + return len(t) == 0 +} + +// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s. +func Index(s, substr string) int { + return stringslite.Index(s, substr) +} + +// Cut slices s around the first instance of sep, +// returning the text before and after sep. +// The found result reports whether sep appears in s. +// If sep does not appear in s, cut returns s, "", false. +func Cut(s, sep string) (before, after string, found bool) { + return stringslite.Cut(s, sep) +} + +// CutPrefix returns s without the provided leading prefix string +// and reports whether it found the prefix. +// If s doesn't start with prefix, CutPrefix returns s, false. +// If prefix is the empty string, CutPrefix returns s, true. +func CutPrefix(s, prefix string) (after string, found bool) { + return stringslite.CutPrefix(s, prefix) +} + +// CutSuffix returns s without the provided ending suffix string +// and reports whether it found the suffix. +// If s doesn't end with suffix, CutSuffix returns s, false. +// If suffix is the empty string, CutSuffix returns s, true. +func CutSuffix(s, suffix string) (before string, found bool) { + return stringslite.CutSuffix(s, suffix) +} diff --git a/contrib/go/_std_1.22/src/strings/ya.make b/contrib/go/_std_1.23/src/strings/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/strings/ya.make rename to contrib/go/_std_1.23/src/strings/ya.make diff --git a/contrib/go/_std_1.23/src/sync/atomic/asm.s b/contrib/go/_std_1.23/src/sync/atomic/asm.s new file mode 100644 index 000000000000..c46869ede7f4 --- /dev/null +++ b/contrib/go/_std_1.23/src/sync/atomic/asm.s @@ -0,0 +1,115 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !race + +#include "textflag.h" + +TEXT ·SwapInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchg(SB) + +TEXT ·SwapUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchg(SB) + +TEXT ·SwapInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchg64(SB) + +TEXT ·SwapUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchg64(SB) + +TEXT ·SwapUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchguintptr(SB) + +TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Cas(SB) + +TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Cas(SB) + +TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Casuintptr(SB) + +TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Cas64(SB) + +TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Cas64(SB) + +TEXT ·AddInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadd(SB) + +TEXT ·AddUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadd(SB) + +TEXT ·AddUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadduintptr(SB) + +TEXT ·AddInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadd64(SB) + +TEXT ·AddUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadd64(SB) + +TEXT ·LoadInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Load(SB) + +TEXT ·LoadUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Load(SB) + +TEXT ·LoadInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Load64(SB) + +TEXT ·LoadUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Load64(SB) + +TEXT ·LoadUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Loaduintptr(SB) + +TEXT ·LoadPointer(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Loadp(SB) + +TEXT ·StoreInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Store(SB) + +TEXT ·StoreUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Store(SB) + +TEXT ·StoreInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Store64(SB) + +TEXT ·StoreUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Store64(SB) + +TEXT ·StoreUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Storeuintptr(SB) + +TEXT ·AndInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·And32(SB) + +TEXT ·AndUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·And32(SB) + +TEXT ·AndUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Anduintptr(SB) + +TEXT ·AndInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·And64(SB) + +TEXT ·AndUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·And64(SB) + +TEXT ·OrInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Or32(SB) + +TEXT ·OrUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Or32(SB) + +TEXT ·OrUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Oruintptr(SB) + +TEXT ·OrInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Or64(SB) + +TEXT ·OrUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Or64(SB) diff --git a/contrib/go/_std_1.23/src/sync/atomic/doc.go b/contrib/go/_std_1.23/src/sync/atomic/doc.go new file mode 100644 index 000000000000..7f9d64b74e62 --- /dev/null +++ b/contrib/go/_std_1.23/src/sync/atomic/doc.go @@ -0,0 +1,244 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package atomic provides low-level atomic memory primitives +// useful for implementing synchronization algorithms. +// +// These functions require great care to be used correctly. +// Except for special, low-level applications, synchronization is better +// done with channels or the facilities of the [sync] package. +// Share memory by communicating; +// don't communicate by sharing memory. +// +// The swap operation, implemented by the SwapT functions, is the atomic +// equivalent of: +// +// old = *addr +// *addr = new +// return old +// +// The compare-and-swap operation, implemented by the CompareAndSwapT +// functions, is the atomic equivalent of: +// +// if *addr == old { +// *addr = new +// return true +// } +// return false +// +// The add operation, implemented by the AddT functions, is the atomic +// equivalent of: +// +// *addr += delta +// return *addr +// +// The load and store operations, implemented by the LoadT and StoreT +// functions, are the atomic equivalents of "return *addr" and +// "*addr = val". +// +// In the terminology of [the Go memory model], if the effect of +// an atomic operation A is observed by atomic operation B, +// then A “synchronizes before” B. +// Additionally, all the atomic operations executed in a program +// behave as though executed in some sequentially consistent order. +// This definition provides the same semantics as +// C++'s sequentially consistent atomics and Java's volatile variables. +// +// [the Go memory model]: https://go.dev/ref/mem +package atomic + +import ( + "unsafe" +) + +// BUG(rsc): On 386, the 64-bit functions use instructions unavailable before the Pentium MMX. +// +// On non-Linux ARM, the 64-bit functions use instructions unavailable before the ARMv6k core. +// +// On ARM, 386, and 32-bit MIPS, it is the caller's responsibility to arrange +// for 64-bit alignment of 64-bit words accessed atomically via the primitive +// atomic functions (types [Int64] and [Uint64] are automatically aligned). +// The first word in an allocated struct, array, or slice; in a global +// variable; or in a local variable (because the subject of all atomic operations +// will escape to the heap) can be relied upon to be 64-bit aligned. + +// SwapInt32 atomically stores new into *addr and returns the previous *addr value. +// Consider using the more ergonomic and less error-prone [Int32.Swap] instead. +func SwapInt32(addr *int32, new int32) (old int32) + +// SwapInt64 atomically stores new into *addr and returns the previous *addr value. +// Consider using the more ergonomic and less error-prone [Int64.Swap] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func SwapInt64(addr *int64, new int64) (old int64) + +// SwapUint32 atomically stores new into *addr and returns the previous *addr value. +// Consider using the more ergonomic and less error-prone [Uint32.Swap] instead. +func SwapUint32(addr *uint32, new uint32) (old uint32) + +// SwapUint64 atomically stores new into *addr and returns the previous *addr value. +// Consider using the more ergonomic and less error-prone [Uint64.Swap] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func SwapUint64(addr *uint64, new uint64) (old uint64) + +// SwapUintptr atomically stores new into *addr and returns the previous *addr value. +// Consider using the more ergonomic and less error-prone [Uintptr.Swap] instead. +func SwapUintptr(addr *uintptr, new uintptr) (old uintptr) + +// SwapPointer atomically stores new into *addr and returns the previous *addr value. +// Consider using the more ergonomic and less error-prone [Pointer.Swap] instead. +func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer) + +// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value. +// Consider using the more ergonomic and less error-prone [Int32.CompareAndSwap] instead. +func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool) + +// CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value. +// Consider using the more ergonomic and less error-prone [Int64.CompareAndSwap] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool) + +// CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value. +// Consider using the more ergonomic and less error-prone [Uint32.CompareAndSwap] instead. +func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool) + +// CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value. +// Consider using the more ergonomic and less error-prone [Uint64.CompareAndSwap] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool) + +// CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value. +// Consider using the more ergonomic and less error-prone [Uintptr.CompareAndSwap] instead. +func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool) + +// CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value. +// Consider using the more ergonomic and less error-prone [Pointer.CompareAndSwap] instead. +func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool) + +// AddInt32 atomically adds delta to *addr and returns the new value. +// Consider using the more ergonomic and less error-prone [Int32.Add] instead. +func AddInt32(addr *int32, delta int32) (new int32) + +// AddUint32 atomically adds delta to *addr and returns the new value. +// To subtract a signed positive constant value c from x, do AddUint32(&x, ^uint32(c-1)). +// In particular, to decrement x, do AddUint32(&x, ^uint32(0)). +// Consider using the more ergonomic and less error-prone [Uint32.Add] instead. +func AddUint32(addr *uint32, delta uint32) (new uint32) + +// AddInt64 atomically adds delta to *addr and returns the new value. +// Consider using the more ergonomic and less error-prone [Int64.Add] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func AddInt64(addr *int64, delta int64) (new int64) + +// AddUint64 atomically adds delta to *addr and returns the new value. +// To subtract a signed positive constant value c from x, do AddUint64(&x, ^uint64(c-1)). +// In particular, to decrement x, do AddUint64(&x, ^uint64(0)). +// Consider using the more ergonomic and less error-prone [Uint64.Add] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func AddUint64(addr *uint64, delta uint64) (new uint64) + +// AddUintptr atomically adds delta to *addr and returns the new value. +// Consider using the more ergonomic and less error-prone [Uintptr.Add] instead. +func AddUintptr(addr *uintptr, delta uintptr) (new uintptr) + +// AndInt32 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Int32.And] instead. +func AndInt32(addr *int32, mask int32) (old int32) + +// AndUint32 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uint32.And] instead. +func AndUint32(addr *uint32, mask uint32) (old uint32) + +// AndInt64 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Int64.And] instead. +func AndInt64(addr *int64, mask int64) (old int64) + +// AndUint64 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old. +// Consider using the more ergonomic and less error-prone [Uint64.And] instead. +func AndUint64(addr *uint64, mask uint64) (old uint64) + +// AndUintptr atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uintptr.And] instead. +func AndUintptr(addr *uintptr, mask uintptr) (old uintptr) + +// OrInt32 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Int32.Or] instead. +func OrInt32(addr *int32, mask int32) (old int32) + +// OrUint32 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uint32.Or] instead. +func OrUint32(addr *uint32, mask uint32) (old uint32) + +// OrInt64 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Int64.Or] instead. +func OrInt64(addr *int64, mask int64) (old int64) + +// OrUint64 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uint64.Or] instead. +func OrUint64(addr *uint64, mask uint64) (old uint64) + +// OrUintptr atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uintptr.Or] instead. +func OrUintptr(addr *uintptr, mask uintptr) (old uintptr) + +// LoadInt32 atomically loads *addr. +// Consider using the more ergonomic and less error-prone [Int32.Load] instead. +func LoadInt32(addr *int32) (val int32) + +// LoadInt64 atomically loads *addr. +// Consider using the more ergonomic and less error-prone [Int64.Load] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func LoadInt64(addr *int64) (val int64) + +// LoadUint32 atomically loads *addr. +// Consider using the more ergonomic and less error-prone [Uint32.Load] instead. +func LoadUint32(addr *uint32) (val uint32) + +// LoadUint64 atomically loads *addr. +// Consider using the more ergonomic and less error-prone [Uint64.Load] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func LoadUint64(addr *uint64) (val uint64) + +// LoadUintptr atomically loads *addr. +// Consider using the more ergonomic and less error-prone [Uintptr.Load] instead. +func LoadUintptr(addr *uintptr) (val uintptr) + +// LoadPointer atomically loads *addr. +// Consider using the more ergonomic and less error-prone [Pointer.Load] instead. +func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) + +// StoreInt32 atomically stores val into *addr. +// Consider using the more ergonomic and less error-prone [Int32.Store] instead. +func StoreInt32(addr *int32, val int32) + +// StoreInt64 atomically stores val into *addr. +// Consider using the more ergonomic and less error-prone [Int64.Store] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func StoreInt64(addr *int64, val int64) + +// StoreUint32 atomically stores val into *addr. +// Consider using the more ergonomic and less error-prone [Uint32.Store] instead. +func StoreUint32(addr *uint32, val uint32) + +// StoreUint64 atomically stores val into *addr. +// Consider using the more ergonomic and less error-prone [Uint64.Store] instead +// (particularly if you target 32-bit platforms; see the bugs section). +func StoreUint64(addr *uint64, val uint64) + +// StoreUintptr atomically stores val into *addr. +// Consider using the more ergonomic and less error-prone [Uintptr.Store] instead. +func StoreUintptr(addr *uintptr, val uintptr) + +// StorePointer atomically stores val into *addr. +// Consider using the more ergonomic and less error-prone [Pointer.Store] instead. +func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer) diff --git a/contrib/go/_std_1.22/src/sync/atomic/race.s b/contrib/go/_std_1.23/src/sync/atomic/race.s similarity index 100% rename from contrib/go/_std_1.22/src/sync/atomic/race.s rename to contrib/go/_std_1.23/src/sync/atomic/race.s diff --git a/contrib/go/_std_1.23/src/sync/atomic/type.go b/contrib/go/_std_1.23/src/sync/atomic/type.go new file mode 100644 index 000000000000..f487cb9c5f7e --- /dev/null +++ b/contrib/go/_std_1.23/src/sync/atomic/type.go @@ -0,0 +1,240 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package atomic + +import "unsafe" + +// A Bool is an atomic boolean value. +// The zero value is false. +type Bool struct { + _ noCopy + v uint32 +} + +// Load atomically loads and returns the value stored in x. +func (x *Bool) Load() bool { return LoadUint32(&x.v) != 0 } + +// Store atomically stores val into x. +func (x *Bool) Store(val bool) { StoreUint32(&x.v, b32(val)) } + +// Swap atomically stores new into x and returns the previous value. +func (x *Bool) Swap(new bool) (old bool) { return SwapUint32(&x.v, b32(new)) != 0 } + +// CompareAndSwap executes the compare-and-swap operation for the boolean value x. +func (x *Bool) CompareAndSwap(old, new bool) (swapped bool) { + return CompareAndSwapUint32(&x.v, b32(old), b32(new)) +} + +// b32 returns a uint32 0 or 1 representing b. +func b32(b bool) uint32 { + if b { + return 1 + } + return 0 +} + +// For testing *Pointer[T]'s methods can be inlined. +// Keep in sync with cmd/compile/internal/test/inl_test.go:TestIntendedInlining. +var _ = &Pointer[int]{} + +// A Pointer is an atomic pointer of type *T. The zero value is a nil *T. +type Pointer[T any] struct { + // Mention *T in a field to disallow conversion between Pointer types. + // See go.dev/issue/56603 for more details. + // Use *T, not T, to avoid spurious recursive type definition errors. + _ [0]*T + + _ noCopy + v unsafe.Pointer +} + +// Load atomically loads and returns the value stored in x. +func (x *Pointer[T]) Load() *T { return (*T)(LoadPointer(&x.v)) } + +// Store atomically stores val into x. +func (x *Pointer[T]) Store(val *T) { StorePointer(&x.v, unsafe.Pointer(val)) } + +// Swap atomically stores new into x and returns the previous value. +func (x *Pointer[T]) Swap(new *T) (old *T) { return (*T)(SwapPointer(&x.v, unsafe.Pointer(new))) } + +// CompareAndSwap executes the compare-and-swap operation for x. +func (x *Pointer[T]) CompareAndSwap(old, new *T) (swapped bool) { + return CompareAndSwapPointer(&x.v, unsafe.Pointer(old), unsafe.Pointer(new)) +} + +// An Int32 is an atomic int32. The zero value is zero. +type Int32 struct { + _ noCopy + v int32 +} + +// Load atomically loads and returns the value stored in x. +func (x *Int32) Load() int32 { return LoadInt32(&x.v) } + +// Store atomically stores val into x. +func (x *Int32) Store(val int32) { StoreInt32(&x.v, val) } + +// Swap atomically stores new into x and returns the previous value. +func (x *Int32) Swap(new int32) (old int32) { return SwapInt32(&x.v, new) } + +// CompareAndSwap executes the compare-and-swap operation for x. +func (x *Int32) CompareAndSwap(old, new int32) (swapped bool) { + return CompareAndSwapInt32(&x.v, old, new) +} + +// Add atomically adds delta to x and returns the new value. +func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) } + +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Int32) And(mask int32) (old int32) { return AndInt32(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Int32) Or(mask int32) (old int32) { return OrInt32(&x.v, mask) } + +// An Int64 is an atomic int64. The zero value is zero. +type Int64 struct { + _ noCopy + _ align64 + v int64 +} + +// Load atomically loads and returns the value stored in x. +func (x *Int64) Load() int64 { return LoadInt64(&x.v) } + +// Store atomically stores val into x. +func (x *Int64) Store(val int64) { StoreInt64(&x.v, val) } + +// Swap atomically stores new into x and returns the previous value. +func (x *Int64) Swap(new int64) (old int64) { return SwapInt64(&x.v, new) } + +// CompareAndSwap executes the compare-and-swap operation for x. +func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) { + return CompareAndSwapInt64(&x.v, old, new) +} + +// Add atomically adds delta to x and returns the new value. +func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) } + +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Int64) And(mask int64) (old int64) { return AndInt64(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Int64) Or(mask int64) (old int64) { return OrInt64(&x.v, mask) } + +// A Uint32 is an atomic uint32. The zero value is zero. +type Uint32 struct { + _ noCopy + v uint32 +} + +// Load atomically loads and returns the value stored in x. +func (x *Uint32) Load() uint32 { return LoadUint32(&x.v) } + +// Store atomically stores val into x. +func (x *Uint32) Store(val uint32) { StoreUint32(&x.v, val) } + +// Swap atomically stores new into x and returns the previous value. +func (x *Uint32) Swap(new uint32) (old uint32) { return SwapUint32(&x.v, new) } + +// CompareAndSwap executes the compare-and-swap operation for x. +func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) { + return CompareAndSwapUint32(&x.v, old, new) +} + +// Add atomically adds delta to x and returns the new value. +func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) } + +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uint32) And(mask uint32) (old uint32) { return AndUint32(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uint32) Or(mask uint32) (old uint32) { return OrUint32(&x.v, mask) } + +// A Uint64 is an atomic uint64. The zero value is zero. +type Uint64 struct { + _ noCopy + _ align64 + v uint64 +} + +// Load atomically loads and returns the value stored in x. +func (x *Uint64) Load() uint64 { return LoadUint64(&x.v) } + +// Store atomically stores val into x. +func (x *Uint64) Store(val uint64) { StoreUint64(&x.v, val) } + +// Swap atomically stores new into x and returns the previous value. +func (x *Uint64) Swap(new uint64) (old uint64) { return SwapUint64(&x.v, new) } + +// CompareAndSwap executes the compare-and-swap operation for x. +func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) { + return CompareAndSwapUint64(&x.v, old, new) +} + +// Add atomically adds delta to x and returns the new value. +func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) } + +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uint64) And(mask uint64) (old uint64) { return AndUint64(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uint64) Or(mask uint64) (old uint64) { return OrUint64(&x.v, mask) } + +// A Uintptr is an atomic uintptr. The zero value is zero. +type Uintptr struct { + _ noCopy + v uintptr +} + +// Load atomically loads and returns the value stored in x. +func (x *Uintptr) Load() uintptr { return LoadUintptr(&x.v) } + +// Store atomically stores val into x. +func (x *Uintptr) Store(val uintptr) { StoreUintptr(&x.v, val) } + +// Swap atomically stores new into x and returns the previous value. +func (x *Uintptr) Swap(new uintptr) (old uintptr) { return SwapUintptr(&x.v, new) } + +// CompareAndSwap executes the compare-and-swap operation for x. +func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool) { + return CompareAndSwapUintptr(&x.v, old, new) +} + +// Add atomically adds delta to x and returns the new value. +func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) } + +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uintptr) And(mask uintptr) (old uintptr) { return AndUintptr(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the updated value after the OR operation. +func (x *Uintptr) Or(mask uintptr) (old uintptr) { return OrUintptr(&x.v, mask) } + +// noCopy may be added to structs which must not be copied +// after the first use. +// +// See https://golang.org/issues/8005#issuecomment-190753527 +// for details. +// +// Note that it must not be embedded, due to the Lock and Unlock methods. +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} +func (*noCopy) Unlock() {} + +// align64 may be added to structs that must be 64-bit aligned. +// This struct is recognized by a special case in the compiler +// and will not work if copied to any other package. +type align64 struct{} diff --git a/contrib/go/_std_1.23/src/sync/atomic/value.go b/contrib/go/_std_1.23/src/sync/atomic/value.go new file mode 100644 index 000000000000..0cfc5f9496c8 --- /dev/null +++ b/contrib/go/_std_1.23/src/sync/atomic/value.go @@ -0,0 +1,194 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package atomic + +import ( + "unsafe" +) + +// A Value provides an atomic load and store of a consistently typed value. +// The zero value for a Value returns nil from [Value.Load]. +// Once [Value.Store] has been called, a Value must not be copied. +// +// A Value must not be copied after first use. +type Value struct { + v any +} + +// efaceWords is interface{} internal representation. +type efaceWords struct { + typ unsafe.Pointer + data unsafe.Pointer +} + +// Load returns the value set by the most recent Store. +// It returns nil if there has been no call to Store for this Value. +func (v *Value) Load() (val any) { + vp := (*efaceWords)(unsafe.Pointer(v)) + typ := LoadPointer(&vp.typ) + if typ == nil || typ == unsafe.Pointer(&firstStoreInProgress) { + // First store not yet completed. + return nil + } + data := LoadPointer(&vp.data) + vlp := (*efaceWords)(unsafe.Pointer(&val)) + vlp.typ = typ + vlp.data = data + return +} + +var firstStoreInProgress byte + +// Store sets the value of the [Value] v to val. +// All calls to Store for a given Value must use values of the same concrete type. +// Store of an inconsistent type panics, as does Store(nil). +func (v *Value) Store(val any) { + if val == nil { + panic("sync/atomic: store of nil value into Value") + } + vp := (*efaceWords)(unsafe.Pointer(v)) + vlp := (*efaceWords)(unsafe.Pointer(&val)) + for { + typ := LoadPointer(&vp.typ) + if typ == nil { + // Attempt to start first store. + // Disable preemption so that other goroutines can use + // active spin wait to wait for completion. + runtime_procPin() + if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { + runtime_procUnpin() + continue + } + // Complete first store. + StorePointer(&vp.data, vlp.data) + StorePointer(&vp.typ, vlp.typ) + runtime_procUnpin() + return + } + if typ == unsafe.Pointer(&firstStoreInProgress) { + // First store in progress. Wait. + // Since we disable preemption around the first store, + // we can wait with active spinning. + continue + } + // First store completed. Check type and overwrite data. + if typ != vlp.typ { + panic("sync/atomic: store of inconsistently typed value into Value") + } + StorePointer(&vp.data, vlp.data) + return + } +} + +// Swap stores new into Value and returns the previous value. It returns nil if +// the Value is empty. +// +// All calls to Swap for a given Value must use values of the same concrete +// type. Swap of an inconsistent type panics, as does Swap(nil). +func (v *Value) Swap(new any) (old any) { + if new == nil { + panic("sync/atomic: swap of nil value into Value") + } + vp := (*efaceWords)(unsafe.Pointer(v)) + np := (*efaceWords)(unsafe.Pointer(&new)) + for { + typ := LoadPointer(&vp.typ) + if typ == nil { + // Attempt to start first store. + // Disable preemption so that other goroutines can use + // active spin wait to wait for completion; and so that + // GC does not see the fake type accidentally. + runtime_procPin() + if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { + runtime_procUnpin() + continue + } + // Complete first store. + StorePointer(&vp.data, np.data) + StorePointer(&vp.typ, np.typ) + runtime_procUnpin() + return nil + } + if typ == unsafe.Pointer(&firstStoreInProgress) { + // First store in progress. Wait. + // Since we disable preemption around the first store, + // we can wait with active spinning. + continue + } + // First store completed. Check type and overwrite data. + if typ != np.typ { + panic("sync/atomic: swap of inconsistently typed value into Value") + } + op := (*efaceWords)(unsafe.Pointer(&old)) + op.typ, op.data = np.typ, SwapPointer(&vp.data, np.data) + return old + } +} + +// CompareAndSwap executes the compare-and-swap operation for the [Value]. +// +// All calls to CompareAndSwap for a given Value must use values of the same +// concrete type. CompareAndSwap of an inconsistent type panics, as does +// CompareAndSwap(old, nil). +func (v *Value) CompareAndSwap(old, new any) (swapped bool) { + if new == nil { + panic("sync/atomic: compare and swap of nil value into Value") + } + vp := (*efaceWords)(unsafe.Pointer(v)) + np := (*efaceWords)(unsafe.Pointer(&new)) + op := (*efaceWords)(unsafe.Pointer(&old)) + if op.typ != nil && np.typ != op.typ { + panic("sync/atomic: compare and swap of inconsistently typed values") + } + for { + typ := LoadPointer(&vp.typ) + if typ == nil { + if old != nil { + return false + } + // Attempt to start first store. + // Disable preemption so that other goroutines can use + // active spin wait to wait for completion; and so that + // GC does not see the fake type accidentally. + runtime_procPin() + if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { + runtime_procUnpin() + continue + } + // Complete first store. + StorePointer(&vp.data, np.data) + StorePointer(&vp.typ, np.typ) + runtime_procUnpin() + return true + } + if typ == unsafe.Pointer(&firstStoreInProgress) { + // First store in progress. Wait. + // Since we disable preemption around the first store, + // we can wait with active spinning. + continue + } + // First store completed. Check type and overwrite data. + if typ != np.typ { + panic("sync/atomic: compare and swap of inconsistently typed value into Value") + } + // Compare old and current via runtime equality check. + // This allows value types to be compared, something + // not offered by the package functions. + // CompareAndSwapPointer below only ensures vp.data + // has not changed since LoadPointer. + data := LoadPointer(&vp.data) + var i any + (*efaceWords)(unsafe.Pointer(&i)).typ = typ + (*efaceWords)(unsafe.Pointer(&i)).data = data + if i != old { + return false + } + return CompareAndSwapPointer(&vp.data, data, np.data) + } +} + +// Disable/enable preemption, implemented in runtime. +func runtime_procPin() int +func runtime_procUnpin() diff --git a/contrib/go/_std_1.23/src/sync/atomic/ya.make b/contrib/go/_std_1.23/src/sync/atomic/ya.make new file mode 100644 index 000000000000..fda89bfd24e2 --- /dev/null +++ b/contrib/go/_std_1.23/src/sync/atomic/ya.make @@ -0,0 +1,17 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + race.s + type.go + value.go + ) +ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + asm.s + doc.go + type.go + value.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/sync/cond.go b/contrib/go/_std_1.23/src/sync/cond.go similarity index 88% rename from contrib/go/_std_1.22/src/sync/cond.go rename to contrib/go/_std_1.23/src/sync/cond.go index 7ef3188a1ee8..2c53b6801a15 100644 --- a/contrib/go/_std_1.22/src/sync/cond.go +++ b/contrib/go/_std_1.23/src/sync/cond.go @@ -13,24 +13,25 @@ import ( // for goroutines waiting for or announcing the occurrence // of an event. // -// Each Cond has an associated Locker L (often a *Mutex or *RWMutex), +// Each Cond has an associated Locker L (often a [*Mutex] or [*RWMutex]), // which must be held when changing the condition and -// when calling the Wait method. +// when calling the [Cond.Wait] method. // // A Cond must not be copied after first use. // -// In the terminology of the Go memory model, Cond arranges that -// a call to Broadcast or Signal “synchronizes before” any Wait call +// In the terminology of [the Go memory model], Cond arranges that +// a call to [Cond.Broadcast] or [Cond.Signal] “synchronizes before” any Wait call // that it unblocks. // // For many simple use cases, users will be better off using channels than a // Cond (Broadcast corresponds to closing a channel, and Signal corresponds to // sending on a channel). // -// For more on replacements for sync.Cond, see [Roberto Clapis's series on +// For more on replacements for [sync.Cond], see [Roberto Clapis's series on // advanced concurrency patterns], as well as [Bryan Mills's talk on concurrency // patterns]. // +// [the Go memory model]: https://go.dev/ref/mem // [Roberto Clapis's series on advanced concurrency patterns]: https://blogtitle.github.io/categories/concurrency/ // [Bryan Mills's talk on concurrency patterns]: https://drive.google.com/file/d/1nPdvhB0PutEJzdCq5ms6UI58dp50fcAN/view type Cond struct { @@ -51,7 +52,7 @@ func NewCond(l Locker) *Cond { // Wait atomically unlocks c.L and suspends execution // of the calling goroutine. After later resuming execution, // Wait locks c.L before returning. Unlike in other systems, -// Wait cannot return unless awoken by Broadcast or Signal. +// Wait cannot return unless awoken by [Cond.Broadcast] or [Cond.Signal]. // // Because c.L is not locked while Wait is waiting, the caller // typically cannot assume that the condition is true when diff --git a/contrib/go/_std_1.23/src/sync/map.go b/contrib/go/_std_1.23/src/sync/map.go new file mode 100644 index 000000000000..33bc8141abd4 --- /dev/null +++ b/contrib/go/_std_1.23/src/sync/map.go @@ -0,0 +1,540 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sync + +import ( + "sync/atomic" +) + +// Map is like a Go map[any]any but is safe for concurrent use +// by multiple goroutines without additional locking or coordination. +// Loads, stores, and deletes run in amortized constant time. +// +// The Map type is specialized. Most code should use a plain Go map instead, +// with separate locking or coordination, for better type safety and to make it +// easier to maintain other invariants along with the map content. +// +// The Map type is optimized for two common use cases: (1) when the entry for a given +// key is only ever written once but read many times, as in caches that only grow, +// or (2) when multiple goroutines read, write, and overwrite entries for disjoint +// sets of keys. In these two cases, use of a Map may significantly reduce lock +// contention compared to a Go map paired with a separate [Mutex] or [RWMutex]. +// +// The zero Map is empty and ready for use. A Map must not be copied after first use. +// +// In the terminology of [the Go memory model], Map arranges that a write operation +// “synchronizes before” any read operation that observes the effect of the write, where +// read and write operations are defined as follows. +// [Map.Load], [Map.LoadAndDelete], [Map.LoadOrStore], [Map.Swap], [Map.CompareAndSwap], +// and [Map.CompareAndDelete] are read operations; +// [Map.Delete], [Map.LoadAndDelete], [Map.Store], and [Map.Swap] are write operations; +// [Map.LoadOrStore] is a write operation when it returns loaded set to false; +// [Map.CompareAndSwap] is a write operation when it returns swapped set to true; +// and [Map.CompareAndDelete] is a write operation when it returns deleted set to true. +// +// [the Go memory model]: https://go.dev/ref/mem +type Map struct { + mu Mutex + + // read contains the portion of the map's contents that are safe for + // concurrent access (with or without mu held). + // + // The read field itself is always safe to load, but must only be stored with + // mu held. + // + // Entries stored in read may be updated concurrently without mu, but updating + // a previously-expunged entry requires that the entry be copied to the dirty + // map and unexpunged with mu held. + read atomic.Pointer[readOnly] + + // dirty contains the portion of the map's contents that require mu to be + // held. To ensure that the dirty map can be promoted to the read map quickly, + // it also includes all of the non-expunged entries in the read map. + // + // Expunged entries are not stored in the dirty map. An expunged entry in the + // clean map must be unexpunged and added to the dirty map before a new value + // can be stored to it. + // + // If the dirty map is nil, the next write to the map will initialize it by + // making a shallow copy of the clean map, omitting stale entries. + dirty map[any]*entry + + // misses counts the number of loads since the read map was last updated that + // needed to lock mu to determine whether the key was present. + // + // Once enough misses have occurred to cover the cost of copying the dirty + // map, the dirty map will be promoted to the read map (in the unamended + // state) and the next store to the map will make a new dirty copy. + misses int +} + +// readOnly is an immutable struct stored atomically in the Map.read field. +type readOnly struct { + m map[any]*entry + amended bool // true if the dirty map contains some key not in m. +} + +// expunged is an arbitrary pointer that marks entries which have been deleted +// from the dirty map. +var expunged = new(any) + +// An entry is a slot in the map corresponding to a particular key. +type entry struct { + // p points to the interface{} value stored for the entry. + // + // If p == nil, the entry has been deleted, and either m.dirty == nil or + // m.dirty[key] is e. + // + // If p == expunged, the entry has been deleted, m.dirty != nil, and the entry + // is missing from m.dirty. + // + // Otherwise, the entry is valid and recorded in m.read.m[key] and, if m.dirty + // != nil, in m.dirty[key]. + // + // An entry can be deleted by atomic replacement with nil: when m.dirty is + // next created, it will atomically replace nil with expunged and leave + // m.dirty[key] unset. + // + // An entry's associated value can be updated by atomic replacement, provided + // p != expunged. If p == expunged, an entry's associated value can be updated + // only after first setting m.dirty[key] = e so that lookups using the dirty + // map find the entry. + p atomic.Pointer[any] +} + +func newEntry(i any) *entry { + e := &entry{} + e.p.Store(&i) + return e +} + +func (m *Map) loadReadOnly() readOnly { + if p := m.read.Load(); p != nil { + return *p + } + return readOnly{} +} + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (m *Map) Load(key any) (value any, ok bool) { + read := m.loadReadOnly() + e, ok := read.m[key] + if !ok && read.amended { + m.mu.Lock() + // Avoid reporting a spurious miss if m.dirty got promoted while we were + // blocked on m.mu. (If further loads of the same key will not miss, it's + // not worth copying the dirty map for this key.) + read = m.loadReadOnly() + e, ok = read.m[key] + if !ok && read.amended { + e, ok = m.dirty[key] + // Regardless of whether the entry was present, record a miss: this key + // will take the slow path until the dirty map is promoted to the read + // map. + m.missLocked() + } + m.mu.Unlock() + } + if !ok { + return nil, false + } + return e.load() +} + +func (e *entry) load() (value any, ok bool) { + p := e.p.Load() + if p == nil || p == expunged { + return nil, false + } + return *p, true +} + +// Store sets the value for a key. +func (m *Map) Store(key, value any) { + _, _ = m.Swap(key, value) +} + +// Clear deletes all the entries, resulting in an empty Map. +func (m *Map) Clear() { + read := m.loadReadOnly() + if len(read.m) == 0 && !read.amended { + // Avoid allocating a new readOnly when the map is already clear. + return + } + + m.mu.Lock() + defer m.mu.Unlock() + + read = m.loadReadOnly() + if len(read.m) > 0 || read.amended { + m.read.Store(&readOnly{}) + } + + clear(m.dirty) + // Don't immediately promote the newly-cleared dirty map on the next operation. + m.misses = 0 +} + +// tryCompareAndSwap compare the entry with the given old value and swaps +// it with a new value if the entry is equal to the old value, and the entry +// has not been expunged. +// +// If the entry is expunged, tryCompareAndSwap returns false and leaves +// the entry unchanged. +func (e *entry) tryCompareAndSwap(old, new any) bool { + p := e.p.Load() + if p == nil || p == expunged || *p != old { + return false + } + + // Copy the interface after the first load to make this method more amenable + // to escape analysis: if the comparison fails from the start, we shouldn't + // bother heap-allocating an interface value to store. + nc := new + for { + if e.p.CompareAndSwap(p, &nc) { + return true + } + p = e.p.Load() + if p == nil || p == expunged || *p != old { + return false + } + } +} + +// unexpungeLocked ensures that the entry is not marked as expunged. +// +// If the entry was previously expunged, it must be added to the dirty map +// before m.mu is unlocked. +func (e *entry) unexpungeLocked() (wasExpunged bool) { + return e.p.CompareAndSwap(expunged, nil) +} + +// swapLocked unconditionally swaps a value into the entry. +// +// The entry must be known not to be expunged. +func (e *entry) swapLocked(i *any) *any { + return e.p.Swap(i) +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (m *Map) LoadOrStore(key, value any) (actual any, loaded bool) { + // Avoid locking if it's a clean hit. + read := m.loadReadOnly() + if e, ok := read.m[key]; ok { + actual, loaded, ok := e.tryLoadOrStore(value) + if ok { + return actual, loaded + } + } + + m.mu.Lock() + read = m.loadReadOnly() + if e, ok := read.m[key]; ok { + if e.unexpungeLocked() { + m.dirty[key] = e + } + actual, loaded, _ = e.tryLoadOrStore(value) + } else if e, ok := m.dirty[key]; ok { + actual, loaded, _ = e.tryLoadOrStore(value) + m.missLocked() + } else { + if !read.amended { + // We're adding the first new key to the dirty map. + // Make sure it is allocated and mark the read-only map as incomplete. + m.dirtyLocked() + m.read.Store(&readOnly{m: read.m, amended: true}) + } + m.dirty[key] = newEntry(value) + actual, loaded = value, false + } + m.mu.Unlock() + + return actual, loaded +} + +// tryLoadOrStore atomically loads or stores a value if the entry is not +// expunged. +// +// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and +// returns with ok==false. +func (e *entry) tryLoadOrStore(i any) (actual any, loaded, ok bool) { + p := e.p.Load() + if p == expunged { + return nil, false, false + } + if p != nil { + return *p, true, true + } + + // Copy the interface after the first load to make this method more amenable + // to escape analysis: if we hit the "load" path or the entry is expunged, we + // shouldn't bother heap-allocating. + ic := i + for { + if e.p.CompareAndSwap(nil, &ic) { + return i, false, true + } + p = e.p.Load() + if p == expunged { + return nil, false, false + } + if p != nil { + return *p, true, true + } + } +} + +// LoadAndDelete deletes the value for a key, returning the previous value if any. +// The loaded result reports whether the key was present. +func (m *Map) LoadAndDelete(key any) (value any, loaded bool) { + read := m.loadReadOnly() + e, ok := read.m[key] + if !ok && read.amended { + m.mu.Lock() + read = m.loadReadOnly() + e, ok = read.m[key] + if !ok && read.amended { + e, ok = m.dirty[key] + delete(m.dirty, key) + // Regardless of whether the entry was present, record a miss: this key + // will take the slow path until the dirty map is promoted to the read + // map. + m.missLocked() + } + m.mu.Unlock() + } + if ok { + return e.delete() + } + return nil, false +} + +// Delete deletes the value for a key. +func (m *Map) Delete(key any) { + m.LoadAndDelete(key) +} + +func (e *entry) delete() (value any, ok bool) { + for { + p := e.p.Load() + if p == nil || p == expunged { + return nil, false + } + if e.p.CompareAndSwap(p, nil) { + return *p, true + } + } +} + +// trySwap swaps a value if the entry has not been expunged. +// +// If the entry is expunged, trySwap returns false and leaves the entry +// unchanged. +func (e *entry) trySwap(i *any) (*any, bool) { + for { + p := e.p.Load() + if p == expunged { + return nil, false + } + if e.p.CompareAndSwap(p, i) { + return p, true + } + } +} + +// Swap swaps the value for a key and returns the previous value if any. +// The loaded result reports whether the key was present. +func (m *Map) Swap(key, value any) (previous any, loaded bool) { + read := m.loadReadOnly() + if e, ok := read.m[key]; ok { + if v, ok := e.trySwap(&value); ok { + if v == nil { + return nil, false + } + return *v, true + } + } + + m.mu.Lock() + read = m.loadReadOnly() + if e, ok := read.m[key]; ok { + if e.unexpungeLocked() { + // The entry was previously expunged, which implies that there is a + // non-nil dirty map and this entry is not in it. + m.dirty[key] = e + } + if v := e.swapLocked(&value); v != nil { + loaded = true + previous = *v + } + } else if e, ok := m.dirty[key]; ok { + if v := e.swapLocked(&value); v != nil { + loaded = true + previous = *v + } + } else { + if !read.amended { + // We're adding the first new key to the dirty map. + // Make sure it is allocated and mark the read-only map as incomplete. + m.dirtyLocked() + m.read.Store(&readOnly{m: read.m, amended: true}) + } + m.dirty[key] = newEntry(value) + } + m.mu.Unlock() + return previous, loaded +} + +// CompareAndSwap swaps the old and new values for key +// if the value stored in the map is equal to old. +// The old value must be of a comparable type. +func (m *Map) CompareAndSwap(key, old, new any) (swapped bool) { + read := m.loadReadOnly() + if e, ok := read.m[key]; ok { + return e.tryCompareAndSwap(old, new) + } else if !read.amended { + return false // No existing value for key. + } + + m.mu.Lock() + defer m.mu.Unlock() + read = m.loadReadOnly() + swapped = false + if e, ok := read.m[key]; ok { + swapped = e.tryCompareAndSwap(old, new) + } else if e, ok := m.dirty[key]; ok { + swapped = e.tryCompareAndSwap(old, new) + // We needed to lock mu in order to load the entry for key, + // and the operation didn't change the set of keys in the map + // (so it would be made more efficient by promoting the dirty + // map to read-only). + // Count it as a miss so that we will eventually switch to the + // more efficient steady state. + m.missLocked() + } + return swapped +} + +// CompareAndDelete deletes the entry for key if its value is equal to old. +// The old value must be of a comparable type. +// +// If there is no current value for key in the map, CompareAndDelete +// returns false (even if the old value is the nil interface value). +func (m *Map) CompareAndDelete(key, old any) (deleted bool) { + read := m.loadReadOnly() + e, ok := read.m[key] + if !ok && read.amended { + m.mu.Lock() + read = m.loadReadOnly() + e, ok = read.m[key] + if !ok && read.amended { + e, ok = m.dirty[key] + // Don't delete key from m.dirty: we still need to do the “compare” part + // of the operation. The entry will eventually be expunged when the + // dirty map is promoted to the read map. + // + // Regardless of whether the entry was present, record a miss: this key + // will take the slow path until the dirty map is promoted to the read + // map. + m.missLocked() + } + m.mu.Unlock() + } + for ok { + p := e.p.Load() + if p == nil || p == expunged || *p != old { + return false + } + if e.p.CompareAndSwap(p, nil) { + return true + } + } + return false +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +// +// Range does not necessarily correspond to any consistent snapshot of the Map's +// contents: no key will be visited more than once, but if the value for any key +// is stored or deleted concurrently (including by f), Range may reflect any +// mapping for that key from any point during the Range call. Range does not +// block other methods on the receiver; even f itself may call any method on m. +// +// Range may be O(N) with the number of elements in the map even if f returns +// false after a constant number of calls. +func (m *Map) Range(f func(key, value any) bool) { + // We need to be able to iterate over all of the keys that were already + // present at the start of the call to Range. + // If read.amended is false, then read.m satisfies that property without + // requiring us to hold m.mu for a long time. + read := m.loadReadOnly() + if read.amended { + // m.dirty contains keys not in read.m. Fortunately, Range is already O(N) + // (assuming the caller does not break out early), so a call to Range + // amortizes an entire copy of the map: we can promote the dirty copy + // immediately! + m.mu.Lock() + read = m.loadReadOnly() + if read.amended { + read = readOnly{m: m.dirty} + copyRead := read + m.read.Store(©Read) + m.dirty = nil + m.misses = 0 + } + m.mu.Unlock() + } + + for k, e := range read.m { + v, ok := e.load() + if !ok { + continue + } + if !f(k, v) { + break + } + } +} + +func (m *Map) missLocked() { + m.misses++ + if m.misses < len(m.dirty) { + return + } + m.read.Store(&readOnly{m: m.dirty}) + m.dirty = nil + m.misses = 0 +} + +func (m *Map) dirtyLocked() { + if m.dirty != nil { + return + } + + read := m.loadReadOnly() + m.dirty = make(map[any]*entry, len(read.m)) + for k, e := range read.m { + if !e.tryExpungeLocked() { + m.dirty[k] = e + } + } +} + +func (e *entry) tryExpungeLocked() (isExpunged bool) { + p := e.p.Load() + for p == nil { + if e.p.CompareAndSwap(nil, expunged) { + return true + } + p = e.p.Load() + } + return p == expunged +} diff --git a/contrib/go/_std_1.22/src/sync/mutex.go b/contrib/go/_std_1.23/src/sync/mutex.go similarity index 95% rename from contrib/go/_std_1.22/src/sync/mutex.go rename to contrib/go/_std_1.23/src/sync/mutex.go index 2ea024e58564..e4ed47c75c2a 100644 --- a/contrib/go/_std_1.22/src/sync/mutex.go +++ b/contrib/go/_std_1.23/src/sync/mutex.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package sync provides basic synchronization primitives such as mutual -// exclusion locks. Other than the Once and WaitGroup types, most are intended +// exclusion locks. Other than the [Once] and [WaitGroup] types, most are intended // for use by low-level library routines. Higher-level synchronization is // better done via channels and communication. // @@ -25,12 +25,14 @@ func fatal(string) // // A Mutex must not be copied after first use. // -// In the terminology of the Go memory model, -// the n'th call to Unlock “synchronizes before” the m'th call to Lock +// In the terminology of [the Go memory model], +// the n'th call to [Mutex.Unlock] “synchronizes before” the m'th call to [Mutex.Lock] // for any n < m. -// A successful call to TryLock is equivalent to a call to Lock. +// A successful call to [Mutex.TryLock] is equivalent to a call to Lock. // A failed call to TryLock does not establish any “synchronizes before” // relation at all. +// +// [the Go memory model]: https://go.dev/ref/mem type Mutex struct { state int32 sema uint32 @@ -206,7 +208,7 @@ func (m *Mutex) lockSlow() { // Unlock unlocks m. // It is a run-time error if m is not locked on entry to Unlock. // -// A locked Mutex is not associated with a particular goroutine. +// A locked [Mutex] is not associated with a particular goroutine. // It is allowed for one goroutine to lock a Mutex and then // arrange for another goroutine to unlock it. func (m *Mutex) Unlock() { diff --git a/contrib/go/_std_1.22/src/sync/once.go b/contrib/go/_std_1.23/src/sync/once.go similarity index 93% rename from contrib/go/_std_1.22/src/sync/once.go rename to contrib/go/_std_1.23/src/sync/once.go index 3f58707e1cfc..168c7bbdd38f 100644 --- a/contrib/go/_std_1.22/src/sync/once.go +++ b/contrib/go/_std_1.23/src/sync/once.go @@ -12,9 +12,11 @@ import ( // // A Once must not be copied after first use. // -// In the terminology of the Go memory model, +// In the terminology of [the Go memory model], // the return from f “synchronizes before” // the return from any call of once.Do(f). +// +// [the Go memory model]: https://go.dev/ref/mem type Once struct { // done indicates whether the action has been performed. // It is first in the struct because it is used in the hot path. @@ -26,7 +28,7 @@ type Once struct { } // Do calls the function f if and only if Do is being called for the -// first time for this instance of Once. In other words, given +// first time for this instance of [Once]. In other words, given // // var once Once // diff --git a/contrib/go/_std_1.22/src/sync/oncefunc.go b/contrib/go/_std_1.23/src/sync/oncefunc.go similarity index 100% rename from contrib/go/_std_1.22/src/sync/oncefunc.go rename to contrib/go/_std_1.23/src/sync/oncefunc.go diff --git a/contrib/go/_std_1.22/src/sync/pool.go b/contrib/go/_std_1.23/src/sync/pool.go similarity index 91% rename from contrib/go/_std_1.22/src/sync/pool.go rename to contrib/go/_std_1.23/src/sync/pool.go index 3359aba57b31..0fa8f8cdaa02 100644 --- a/contrib/go/_std_1.22/src/sync/pool.go +++ b/contrib/go/_std_1.23/src/sync/pool.go @@ -42,10 +42,12 @@ import ( // // A Pool must not be copied after first use. // -// In the terminology of the Go memory model, a call to Put(x) “synchronizes before” -// a call to Get returning that same value x. +// In the terminology of [the Go memory model], a call to Put(x) “synchronizes before” +// a call to [Pool.Get] returning that same value x. // Similarly, a call to New returning x “synchronizes before” // a call to Get returning that same value x. +// +// [the Go memory model]: https://go.dev/ref/mem type Pool struct { noCopy noCopy @@ -76,6 +78,7 @@ type poolLocal struct { } // from runtime +// //go:linkname runtime_randn runtime.randn func runtime_randn(n uint32) uint32 @@ -117,10 +120,10 @@ func (p *Pool) Put(x any) { } } -// Get selects an arbitrary item from the Pool, removes it from the +// Get selects an arbitrary item from the [Pool], removes it from the // Pool, and returns it to the caller. // Get may choose to ignore the pool and treat it as empty. -// Callers should not assume any relation between values passed to Put and +// Callers should not assume any relation between values passed to [Pool.Put] and // the values returned by Get. // // If Get would otherwise return nil and p.New is non-nil, Get returns @@ -241,6 +244,16 @@ func (p *Pool) pinSlow() (*poolLocal, int) { return &local[pid], pid } +// poolCleanup should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname poolCleanup func poolCleanup() { // This function is called with the world stopped, at the beginning of a garbage collection. // It must not allocate and probably should not call any runtime functions. @@ -294,12 +307,12 @@ func runtime_registerPoolCleanup(cleanup func()) func runtime_procPin() int func runtime_procUnpin() -// The below are implemented in runtime/internal/atomic and the +// The below are implemented in internal/runtime/atomic and the // compiler also knows to intrinsify the symbol we linkname into this // package. -//go:linkname runtime_LoadAcquintptr runtime/internal/atomic.LoadAcquintptr +//go:linkname runtime_LoadAcquintptr internal/runtime/atomic.LoadAcquintptr func runtime_LoadAcquintptr(ptr *uintptr) uintptr -//go:linkname runtime_StoreReluintptr runtime/internal/atomic.StoreReluintptr +//go:linkname runtime_StoreReluintptr internal/runtime/atomic.StoreReluintptr func runtime_StoreReluintptr(ptr *uintptr, val uintptr) uintptr diff --git a/contrib/go/_std_1.22/src/sync/poolqueue.go b/contrib/go/_std_1.23/src/sync/poolqueue.go similarity index 92% rename from contrib/go/_std_1.22/src/sync/poolqueue.go rename to contrib/go/_std_1.23/src/sync/poolqueue.go index 5c640f988a39..e9593f8c4442 100644 --- a/contrib/go/_std_1.22/src/sync/poolqueue.go +++ b/contrib/go/_std_1.23/src/sync/poolqueue.go @@ -198,7 +198,7 @@ type poolChain struct { // tail is the poolDequeue to popTail from. This is accessed // by consumers, so reads and writes must be atomic. - tail *poolChainElt + tail atomic.Pointer[poolChainElt] } type poolChainElt struct { @@ -214,15 +214,7 @@ type poolChainElt struct { // prev is written atomically by the consumer and read // atomically by the producer. It only transitions from // non-nil to nil. - next, prev *poolChainElt -} - -func storePoolChainElt(pp **poolChainElt, v *poolChainElt) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(pp)), unsafe.Pointer(v)) -} - -func loadPoolChainElt(pp **poolChainElt) *poolChainElt { - return (*poolChainElt)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(pp)))) + next, prev atomic.Pointer[poolChainElt] } func (c *poolChain) pushHead(val any) { @@ -233,7 +225,7 @@ func (c *poolChain) pushHead(val any) { d = new(poolChainElt) d.vals = make([]eface, initSize) c.head = d - storePoolChainElt(&c.tail, d) + c.tail.Store(d) } if d.pushHead(val) { @@ -248,10 +240,11 @@ func (c *poolChain) pushHead(val any) { newSize = dequeueLimit } - d2 := &poolChainElt{prev: d} + d2 := &poolChainElt{} + d2.prev.Store(d) d2.vals = make([]eface, newSize) c.head = d2 - storePoolChainElt(&d.next, d2) + d.next.Store(d2) d2.pushHead(val) } @@ -263,13 +256,13 @@ func (c *poolChain) popHead() (any, bool) { } // There may still be unconsumed elements in the // previous dequeue, so try backing up. - d = loadPoolChainElt(&d.prev) + d = d.prev.Load() } return nil, false } func (c *poolChain) popTail() (any, bool) { - d := loadPoolChainElt(&c.tail) + d := c.tail.Load() if d == nil { return nil, false } @@ -281,7 +274,7 @@ func (c *poolChain) popTail() (any, bool) { // the pop and the pop fails, then d is permanently // empty, which is the only condition under which it's // safe to drop d from the chain. - d2 := loadPoolChainElt(&d.next) + d2 := d.next.Load() if val, ok := d.popTail(); ok { return val, ok @@ -297,12 +290,12 @@ func (c *poolChain) popTail() (any, bool) { // to the next dequeue. Try to drop it from the chain // so the next pop doesn't have to look at the empty // dequeue again. - if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.tail)), unsafe.Pointer(d), unsafe.Pointer(d2)) { + if c.tail.CompareAndSwap(d, d2) { // We won the race. Clear the prev pointer so // the garbage collector can collect the empty // dequeue and so popHead doesn't back up // further than necessary. - storePoolChainElt(&d2.prev, nil) + d2.prev.Store(nil) } d = d2 } diff --git a/contrib/go/_std_1.22/src/sync/runtime.go b/contrib/go/_std_1.23/src/sync/runtime.go similarity index 100% rename from contrib/go/_std_1.22/src/sync/runtime.go rename to contrib/go/_std_1.23/src/sync/runtime.go diff --git a/contrib/go/_std_1.22/src/sync/runtime2.go b/contrib/go/_std_1.23/src/sync/runtime2.go similarity index 100% rename from contrib/go/_std_1.22/src/sync/runtime2.go rename to contrib/go/_std_1.23/src/sync/runtime2.go diff --git a/contrib/go/_std_1.22/src/sync/runtime2_lockrank.go b/contrib/go/_std_1.23/src/sync/runtime2_lockrank.go similarity index 100% rename from contrib/go/_std_1.22/src/sync/runtime2_lockrank.go rename to contrib/go/_std_1.23/src/sync/runtime2_lockrank.go diff --git a/contrib/go/_std_1.23/src/sync/rwmutex.go b/contrib/go/_std_1.23/src/sync/rwmutex.go new file mode 100644 index 000000000000..1d5b8fde4a8c --- /dev/null +++ b/contrib/go/_std_1.23/src/sync/rwmutex.go @@ -0,0 +1,245 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sync + +import ( + "internal/race" + "sync/atomic" + "unsafe" +) + +// There is a modified copy of this file in runtime/rwmutex.go. +// If you make any changes here, see if you should make them there. + +// A RWMutex is a reader/writer mutual exclusion lock. +// The lock can be held by an arbitrary number of readers or a single writer. +// The zero value for a RWMutex is an unlocked mutex. +// +// A RWMutex must not be copied after first use. +// +// If any goroutine calls [RWMutex.Lock] while the lock is already held by +// one or more readers, concurrent calls to [RWMutex.RLock] will block until +// the writer has acquired (and released) the lock, to ensure that +// the lock eventually becomes available to the writer. +// Note that this prohibits recursive read-locking. +// +// In the terminology of [the Go memory model], +// the n'th call to [RWMutex.Unlock] “synchronizes before” the m'th call to Lock +// for any n < m, just as for [Mutex]. +// For any call to RLock, there exists an n such that +// the n'th call to Unlock “synchronizes before” that call to RLock, +// and the corresponding call to [RWMutex.RUnlock] “synchronizes before” +// the n+1'th call to Lock. +// +// [the Go memory model]: https://go.dev/ref/mem +type RWMutex struct { + w Mutex // held if there are pending writers + writerSem uint32 // semaphore for writers to wait for completing readers + readerSem uint32 // semaphore for readers to wait for completing writers + readerCount atomic.Int32 // number of pending readers + readerWait atomic.Int32 // number of departing readers +} + +const rwmutexMaxReaders = 1 << 30 + +// Happens-before relationships are indicated to the race detector via: +// - Unlock -> Lock: readerSem +// - Unlock -> RLock: readerSem +// - RUnlock -> Lock: writerSem +// +// The methods below temporarily disable handling of race synchronization +// events in order to provide the more precise model above to the race +// detector. +// +// For example, atomic.AddInt32 in RLock should not appear to provide +// acquire-release semantics, which would incorrectly synchronize racing +// readers, thus potentially missing races. + +// RLock locks rw for reading. +// +// It should not be used for recursive read locking; a blocked Lock +// call excludes new readers from acquiring the lock. See the +// documentation on the [RWMutex] type. +func (rw *RWMutex) RLock() { + if race.Enabled { + _ = rw.w.state + race.Disable() + } + if rw.readerCount.Add(1) < 0 { + // A writer is pending, wait for it. + runtime_SemacquireRWMutexR(&rw.readerSem, false, 0) + } + if race.Enabled { + race.Enable() + race.Acquire(unsafe.Pointer(&rw.readerSem)) + } +} + +// TryRLock tries to lock rw for reading and reports whether it succeeded. +// +// Note that while correct uses of TryRLock do exist, they are rare, +// and use of TryRLock is often a sign of a deeper problem +// in a particular use of mutexes. +func (rw *RWMutex) TryRLock() bool { + if race.Enabled { + _ = rw.w.state + race.Disable() + } + for { + c := rw.readerCount.Load() + if c < 0 { + if race.Enabled { + race.Enable() + } + return false + } + if rw.readerCount.CompareAndSwap(c, c+1) { + if race.Enabled { + race.Enable() + race.Acquire(unsafe.Pointer(&rw.readerSem)) + } + return true + } + } +} + +// RUnlock undoes a single [RWMutex.RLock] call; +// it does not affect other simultaneous readers. +// It is a run-time error if rw is not locked for reading +// on entry to RUnlock. +func (rw *RWMutex) RUnlock() { + if race.Enabled { + _ = rw.w.state + race.ReleaseMerge(unsafe.Pointer(&rw.writerSem)) + race.Disable() + } + if r := rw.readerCount.Add(-1); r < 0 { + // Outlined slow-path to allow the fast-path to be inlined + rw.rUnlockSlow(r) + } + if race.Enabled { + race.Enable() + } +} + +func (rw *RWMutex) rUnlockSlow(r int32) { + if r+1 == 0 || r+1 == -rwmutexMaxReaders { + race.Enable() + fatal("sync: RUnlock of unlocked RWMutex") + } + // A writer is pending. + if rw.readerWait.Add(-1) == 0 { + // The last reader unblocks the writer. + runtime_Semrelease(&rw.writerSem, false, 1) + } +} + +// Lock locks rw for writing. +// If the lock is already locked for reading or writing, +// Lock blocks until the lock is available. +func (rw *RWMutex) Lock() { + if race.Enabled { + _ = rw.w.state + race.Disable() + } + // First, resolve competition with other writers. + rw.w.Lock() + // Announce to readers there is a pending writer. + r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders + // Wait for active readers. + if r != 0 && rw.readerWait.Add(r) != 0 { + runtime_SemacquireRWMutex(&rw.writerSem, false, 0) + } + if race.Enabled { + race.Enable() + race.Acquire(unsafe.Pointer(&rw.readerSem)) + race.Acquire(unsafe.Pointer(&rw.writerSem)) + } +} + +// TryLock tries to lock rw for writing and reports whether it succeeded. +// +// Note that while correct uses of TryLock do exist, they are rare, +// and use of TryLock is often a sign of a deeper problem +// in a particular use of mutexes. +func (rw *RWMutex) TryLock() bool { + if race.Enabled { + _ = rw.w.state + race.Disable() + } + if !rw.w.TryLock() { + if race.Enabled { + race.Enable() + } + return false + } + if !rw.readerCount.CompareAndSwap(0, -rwmutexMaxReaders) { + rw.w.Unlock() + if race.Enabled { + race.Enable() + } + return false + } + if race.Enabled { + race.Enable() + race.Acquire(unsafe.Pointer(&rw.readerSem)) + race.Acquire(unsafe.Pointer(&rw.writerSem)) + } + return true +} + +// Unlock unlocks rw for writing. It is a run-time error if rw is +// not locked for writing on entry to Unlock. +// +// As with Mutexes, a locked [RWMutex] is not associated with a particular +// goroutine. One goroutine may [RWMutex.RLock] ([RWMutex.Lock]) a RWMutex and then +// arrange for another goroutine to [RWMutex.RUnlock] ([RWMutex.Unlock]) it. +func (rw *RWMutex) Unlock() { + if race.Enabled { + _ = rw.w.state + race.Release(unsafe.Pointer(&rw.readerSem)) + race.Disable() + } + + // Announce to readers there is no active writer. + r := rw.readerCount.Add(rwmutexMaxReaders) + if r >= rwmutexMaxReaders { + race.Enable() + fatal("sync: Unlock of unlocked RWMutex") + } + // Unblock blocked readers, if any. + for i := 0; i < int(r); i++ { + runtime_Semrelease(&rw.readerSem, false, 0) + } + // Allow other writers to proceed. + rw.w.Unlock() + if race.Enabled { + race.Enable() + } +} + +// syscall_hasWaitingReaders reports whether any goroutine is waiting +// to acquire a read lock on rw. This exists because syscall.ForkLock +// is an RWMutex, and we can't change that without breaking compatibility. +// We don't need or want RWMutex semantics for ForkLock, and we use +// this private API to avoid having to change the type of ForkLock. +// For more details see the syscall package. +// +//go:linkname syscall_hasWaitingReaders syscall.hasWaitingReaders +func syscall_hasWaitingReaders(rw *RWMutex) bool { + r := rw.readerCount.Load() + return r < 0 && r+rwmutexMaxReaders > 0 +} + +// RLocker returns a [Locker] interface that implements +// the [Locker.Lock] and [Locker.Unlock] methods by calling rw.RLock and rw.RUnlock. +func (rw *RWMutex) RLocker() Locker { + return (*rlocker)(rw) +} + +type rlocker RWMutex + +func (r *rlocker) Lock() { (*RWMutex)(r).RLock() } +func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() } diff --git a/contrib/go/_std_1.22/src/sync/waitgroup.go b/contrib/go/_std_1.23/src/sync/waitgroup.go similarity index 85% rename from contrib/go/_std_1.22/src/sync/waitgroup.go rename to contrib/go/_std_1.23/src/sync/waitgroup.go index be21417f9c22..872d6d87c0dd 100644 --- a/contrib/go/_std_1.22/src/sync/waitgroup.go +++ b/contrib/go/_std_1.23/src/sync/waitgroup.go @@ -11,15 +11,17 @@ import ( ) // A WaitGroup waits for a collection of goroutines to finish. -// The main goroutine calls Add to set the number of +// The main goroutine calls [WaitGroup.Add] to set the number of // goroutines to wait for. Then each of the goroutines -// runs and calls Done when finished. At the same time, -// Wait can be used to block until all goroutines have finished. +// runs and calls [WaitGroup.Done] when finished. At the same time, +// [WaitGroup.Wait] can be used to block until all goroutines have finished. // // A WaitGroup must not be copied after first use. // -// In the terminology of the Go memory model, a call to Done +// In the terminology of [the Go memory model], a call to [WaitGroup.Done] // “synchronizes before” the return of any Wait call that it unblocks. +// +// [the Go memory model]: https://go.dev/ref/mem type WaitGroup struct { noCopy noCopy @@ -27,8 +29,8 @@ type WaitGroup struct { sema uint32 } -// Add adds delta, which may be negative, to the WaitGroup counter. -// If the counter becomes zero, all goroutines blocked on Wait are released. +// Add adds delta, which may be negative, to the [WaitGroup] counter. +// If the counter becomes zero, all goroutines blocked on [WaitGroup.Wait] are released. // If the counter goes negative, Add panics. // // Note that calls with a positive delta that occur when the counter is zero @@ -82,12 +84,12 @@ func (wg *WaitGroup) Add(delta int) { } } -// Done decrements the WaitGroup counter by one. +// Done decrements the [WaitGroup] counter by one. func (wg *WaitGroup) Done() { wg.Add(-1) } -// Wait blocks until the WaitGroup counter is zero. +// Wait blocks until the [WaitGroup] counter is zero. func (wg *WaitGroup) Wait() { if race.Enabled { race.Disable() diff --git a/contrib/go/_std_1.22/src/sync/ya.make b/contrib/go/_std_1.23/src/sync/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/sync/ya.make rename to contrib/go/_std_1.23/src/sync/ya.make diff --git a/contrib/go/_std_1.22/src/syscall/asm9_unix2_amd64.s b/contrib/go/_std_1.23/src/syscall/asm9_unix2_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm9_unix2_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm9_unix2_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_aix_ppc64.s b/contrib/go/_std_1.23/src/syscall/asm_aix_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_aix_ppc64.s rename to contrib/go/_std_1.23/src/syscall/asm_aix_ppc64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_darwin_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_darwin_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_darwin_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_darwin_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_darwin_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_darwin_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_darwin_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_darwin_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_freebsd_arm.s b/contrib/go/_std_1.23/src/syscall/asm_freebsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_freebsd_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_freebsd_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_freebsd_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_freebsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_freebsd_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_freebsd_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_freebsd_riscv64.s b/contrib/go/_std_1.23/src/syscall/asm_freebsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_freebsd_riscv64.s rename to contrib/go/_std_1.23/src/syscall/asm_freebsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_386.s b/contrib/go/_std_1.23/src/syscall/asm_linux_386.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_386.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_386.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_arm.s b/contrib/go/_std_1.23/src/syscall/asm_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_linux_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_loong64.s b/contrib/go/_std_1.23/src/syscall/asm_linux_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_loong64.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_loong64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_mips64x.s b/contrib/go/_std_1.23/src/syscall/asm_linux_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_mips64x.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_mips64x.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_mipsx.s b/contrib/go/_std_1.23/src/syscall/asm_linux_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_mipsx.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_mipsx.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_ppc64x.s b/contrib/go/_std_1.23/src/syscall/asm_linux_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_ppc64x.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_ppc64x.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_riscv64.s b/contrib/go/_std_1.23/src/syscall/asm_linux_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_riscv64.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_riscv64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_s390x.s b/contrib/go/_std_1.23/src/syscall/asm_linux_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_s390x.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_s390x.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_netbsd_arm.s b/contrib/go/_std_1.23/src/syscall/asm_netbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_netbsd_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_netbsd_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_netbsd_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_netbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_netbsd_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_netbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_386.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_386.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_386.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_arm.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_mips64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_mips64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_mips64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_mips64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_ppc64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_ppc64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_ppc64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_riscv64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_riscv64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_plan9_386.s b/contrib/go/_std_1.23/src/syscall/asm_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_plan9_386.s rename to contrib/go/_std_1.23/src/syscall/asm_plan9_386.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_plan9_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_plan9_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_plan9_arm.s b/contrib/go/_std_1.23/src/syscall/asm_plan9_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_plan9_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_plan9_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_solaris_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_solaris_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_solaris_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_solaris_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_unix_386.s b/contrib/go/_std_1.23/src/syscall/asm_unix_386.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_unix_386.s rename to contrib/go/_std_1.23/src/syscall/asm_unix_386.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_unix_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_unix_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_unix_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_unix_amd64.s diff --git a/contrib/go/_std_1.23/src/syscall/badlinkname_unix.go b/contrib/go/_std_1.23/src/syscall/badlinkname_unix.go new file mode 100644 index 000000000000..4964a830b003 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/badlinkname_unix.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris + +package syscall + +import _ "unsafe" + +// As of Go 1.22, the symbols below are found to be pulled via +// linkname in the wild. We provide a push linkname here, to +// keep them accessible with pull linknames. +// This may change in the future. Please do not depend on them +// in new code. + +// golang.org/x/sys linknames getsockopt. +// Do not remove or change the type signature. +// +//go:linkname getsockopt + +//go:linkname setsockopt diff --git a/contrib/go/_std_1.22/src/syscall/bpf_bsd.go b/contrib/go/_std_1.23/src/syscall/bpf_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/bpf_bsd.go rename to contrib/go/_std_1.23/src/syscall/bpf_bsd.go diff --git a/contrib/go/_std_1.22/src/syscall/const_plan9.go b/contrib/go/_std_1.23/src/syscall/const_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/const_plan9.go rename to contrib/go/_std_1.23/src/syscall/const_plan9.go diff --git a/contrib/go/_std_1.23/src/syscall/dir_plan9.go b/contrib/go/_std_1.23/src/syscall/dir_plan9.go new file mode 100644 index 000000000000..34869b620915 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/dir_plan9.go @@ -0,0 +1,204 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Plan 9 directory marshaling. See intro(5). + +package syscall + +import ( + "errors" + "internal/byteorder" +) + +var ( + ErrShortStat = errors.New("stat buffer too short") + ErrBadStat = errors.New("malformed stat buffer") + ErrBadName = errors.New("bad character in file name") +) + +// A Qid represents a 9P server's unique identification for a file. +type Qid struct { + Path uint64 // the file server's unique identification for the file + Vers uint32 // version number for given Path + Type uint8 // the type of the file (syscall.QTDIR for example) +} + +// A Dir contains the metadata for a file. +type Dir struct { + // system-modified data + Type uint16 // server type + Dev uint32 // server subtype + + // file data + Qid Qid // unique id from server + Mode uint32 // permissions + Atime uint32 // last read time + Mtime uint32 // last write time + Length int64 // file length + Name string // last element of path + Uid string // owner name + Gid string // group name + Muid string // last modifier name +} + +var nullDir = Dir{ + Type: ^uint16(0), + Dev: ^uint32(0), + Qid: Qid{ + Path: ^uint64(0), + Vers: ^uint32(0), + Type: ^uint8(0), + }, + Mode: ^uint32(0), + Atime: ^uint32(0), + Mtime: ^uint32(0), + Length: ^int64(0), +} + +// Null assigns special "don't touch" values to members of d to +// avoid modifying them during [Wstat]. +func (d *Dir) Null() { *d = nullDir } + +// Marshal encodes a 9P stat message corresponding to d into b +// +// If there isn't enough space in b for a stat message, [ErrShortStat] is returned. +func (d *Dir) Marshal(b []byte) (n int, err error) { + n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid) + if n > len(b) { + return n, ErrShortStat + } + + for _, c := range d.Name { + if c == '/' { + return n, ErrBadName + } + } + + b = pbit16(b, uint16(n)-2) + b = pbit16(b, d.Type) + b = pbit32(b, d.Dev) + b = pbit8(b, d.Qid.Type) + b = pbit32(b, d.Qid.Vers) + b = pbit64(b, d.Qid.Path) + b = pbit32(b, d.Mode) + b = pbit32(b, d.Atime) + b = pbit32(b, d.Mtime) + b = pbit64(b, uint64(d.Length)) + b = pstring(b, d.Name) + b = pstring(b, d.Uid) + b = pstring(b, d.Gid) + b = pstring(b, d.Muid) + + return n, nil +} + +// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir. +// +// If b is too small to hold a valid stat message, [ErrShortStat] is returned. +// +// If the stat message itself is invalid, [ErrBadStat] is returned. +func UnmarshalDir(b []byte) (*Dir, error) { + if len(b) < STATFIXLEN { + return nil, ErrShortStat + } + size, buf := gbit16(b) + if len(b) != int(size)+2 { + return nil, ErrBadStat + } + b = buf + + var d Dir + d.Type, b = gbit16(b) + d.Dev, b = gbit32(b) + d.Qid.Type, b = gbit8(b) + d.Qid.Vers, b = gbit32(b) + d.Qid.Path, b = gbit64(b) + d.Mode, b = gbit32(b) + d.Atime, b = gbit32(b) + d.Mtime, b = gbit32(b) + + n, b := gbit64(b) + d.Length = int64(n) + + var ok bool + if d.Name, b, ok = gstring(b); !ok { + return nil, ErrBadStat + } + if d.Uid, b, ok = gstring(b); !ok { + return nil, ErrBadStat + } + if d.Gid, b, ok = gstring(b); !ok { + return nil, ErrBadStat + } + if d.Muid, b, ok = gstring(b); !ok { + return nil, ErrBadStat + } + + return &d, nil +} + +// pbit8 copies the 8-bit number v to b and returns the remaining slice of b. +func pbit8(b []byte, v uint8) []byte { + b[0] = byte(v) + return b[1:] +} + +// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b. +func pbit16(b []byte, v uint16) []byte { + byteorder.LePutUint16(b, v) + return b[2:] +} + +// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b. +func pbit32(b []byte, v uint32) []byte { + byteorder.LePutUint32(b, v) + return b[4:] +} + +// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b. +func pbit64(b []byte, v uint64) []byte { + byteorder.LePutUint64(b, v) + return b[8:] +} + +// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and +// returning the remaining slice of b.. +func pstring(b []byte, s string) []byte { + b = pbit16(b, uint16(len(s))) + n := copy(b, s) + return b[n:] +} + +// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b. +func gbit8(b []byte) (uint8, []byte) { + return uint8(b[0]), b[1:] +} + +// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b. +// +//go:nosplit +func gbit16(b []byte) (uint16, []byte) { + return byteorder.LeUint16(b), b[2:] +} + +// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b. +func gbit32(b []byte) (uint32, []byte) { + return byteorder.LeUint32(b), b[4:] +} + +// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b. +func gbit64(b []byte) (uint64, []byte) { + return byteorder.LeUint64(b), b[8:] +} + +// gstring reads a string from b, prefixed with a 16-bit length in little-endian order. +// It returns the string with the remaining slice of b and a boolean. If the length is +// greater than the number of bytes in b, the boolean will be false. +func gstring(b []byte) (string, []byte, bool) { + n, b := gbit16(b) + if int(n) > len(b) { + return "", b, false + } + return string(b[:n]), b[n:], true +} diff --git a/contrib/go/_std_1.23/src/syscall/dirent.go b/contrib/go/_std_1.23/src/syscall/dirent.go new file mode 100644 index 000000000000..e4f36a191bfa --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/dirent.go @@ -0,0 +1,101 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || (js && wasm) || wasip1 + +package syscall + +import ( + "internal/byteorder" + "internal/goarch" + "runtime" + "unsafe" +) + +// readInt returns the size-bytes unsigned integer in native byte order at offset off. +func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { + if len(b) < int(off+size) { + return 0, false + } + if goarch.BigEndian { + return readIntBE(b[off:], size), true + } + return readIntLE(b[off:], size), true +} + +func readIntBE(b []byte, size uintptr) uint64 { + switch size { + case 1: + return uint64(b[0]) + case 2: + return uint64(byteorder.BeUint16(b)) + case 4: + return uint64(byteorder.BeUint32(b)) + case 8: + return uint64(byteorder.BeUint64(b)) + default: + panic("syscall: readInt with unsupported size") + } +} + +func readIntLE(b []byte, size uintptr) uint64 { + switch size { + case 1: + return uint64(b[0]) + case 2: + return uint64(byteorder.LeUint16(b)) + case 4: + return uint64(byteorder.LeUint32(b)) + case 8: + return uint64(byteorder.LeUint64(b)) + default: + panic("syscall: readInt with unsupported size") + } +} + +// ParseDirent parses up to max directory entries in buf, +// appending the names to names. It returns the number of +// bytes consumed from buf, the number of entries added +// to names, and the new names slice. +func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { + origlen := len(buf) + count = 0 + for max != 0 && len(buf) > 0 { + reclen, ok := direntReclen(buf) + if !ok || reclen > uint64(len(buf)) { + return origlen, count, names + } + rec := buf[:reclen] + buf = buf[reclen:] + ino, ok := direntIno(rec) + if !ok { + break + } + // See src/os/dir_unix.go for the reason why this condition is + // excluded on wasip1. + if ino == 0 && runtime.GOOS != "wasip1" { // File absent in directory. + continue + } + const namoff = uint64(unsafe.Offsetof(Dirent{}.Name)) + namlen, ok := direntNamlen(rec) + if !ok || namoff+namlen > uint64(len(rec)) { + break + } + name := rec[namoff : namoff+namlen] + for i, c := range name { + if c == 0 { + name = name[:i] + break + } + } + // Check for useless names before allocating a string. + if string(name) == "." || string(name) == ".." { + continue + } + max-- + count++ + names = append(names, string(name)) + } + return origlen - len(buf), count, names +} diff --git a/contrib/go/_std_1.22/src/syscall/dll_windows.go b/contrib/go/_std_1.23/src/syscall/dll_windows.go similarity index 83% rename from contrib/go/_std_1.22/src/syscall/dll_windows.go rename to contrib/go/_std_1.23/src/syscall/dll_windows.go index 5f62b5512cad..a7873e6ad8c9 100644 --- a/contrib/go/_std_1.22/src/syscall/dll_windows.go +++ b/contrib/go/_std_1.23/src/syscall/dll_windows.go @@ -24,24 +24,25 @@ func (e *DLLError) Unwrap() error { return e.Err } // Implemented in ../runtime/syscall_windows.go. -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno) +//go:noescape func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno) func loadlibrary(filename *uint16) (handle uintptr, err Errno) func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno) @@ -59,7 +60,7 @@ type DLL struct { // Go, Windows will search for the named DLL in many locations, causing // potential DLL preloading attacks. // -// Use LazyDLL in golang.org/x/sys/windows for a secure way to +// Use [LazyDLL] in golang.org/x/sys/windows for a secure way to // load system DLLs. func LoadDLL(name string) (*DLL, error) { namep, err := UTF16PtrFromString(name) @@ -87,7 +88,7 @@ func LoadDLL(name string) (*DLL, error) { return d, nil } -// MustLoadDLL is like LoadDLL but panics if load operation fails. +// MustLoadDLL is like [LoadDLL] but panics if load operation fails. func MustLoadDLL(name string) *DLL { d, e := LoadDLL(name) if e != nil { @@ -96,7 +97,7 @@ func MustLoadDLL(name string) *DLL { return d } -// FindProc searches DLL d for procedure named name and returns *Proc +// FindProc searches [DLL] d for procedure named name and returns [*Proc] // if found. It returns an error if search fails. func (d *DLL) FindProc(name string) (proc *Proc, err error) { namep, err := BytePtrFromString(name) @@ -119,7 +120,7 @@ func (d *DLL) FindProc(name string) (proc *Proc, err error) { return p, nil } -// MustFindProc is like FindProc but panics if search fails. +// MustFindProc is like [DLL.FindProc] but panics if search fails. func (d *DLL) MustFindProc(name string) *Proc { p, e := d.FindProc(name) if e != nil { @@ -128,12 +129,12 @@ func (d *DLL) MustFindProc(name string) *Proc { return p } -// Release unloads DLL d from memory. +// Release unloads [DLL] d from memory. func (d *DLL) Release() (err error) { return FreeLibrary(d.Handle) } -// A Proc implements access to a procedure inside a DLL. +// A Proc implements access to a procedure inside a [DLL]. type Proc struct { Dll *DLL Name string @@ -151,28 +152,28 @@ func (p *Proc) Addr() uintptr { // The returned error is always non-nil, constructed from the result of GetLastError. // Callers must inspect the primary return value to decide whether an error occurred // (according to the semantics of the specific function being called) before consulting -// the error. The error always has type syscall.Errno. +// the error. The error always has type [Errno]. // // On amd64, Call can pass and return floating-point values. To pass // an argument x with C type "float", use // uintptr(math.Float32bits(x)). To pass an argument with C type // "double", use uintptr(math.Float64bits(x)). Floating-point return // values are returned in r2. The return value for C type "float" is -// math.Float32frombits(uint32(r2)). For C type "double", it is -// math.Float64frombits(uint64(r2)). +// [math.Float32frombits](uint32(r2)). For C type "double", it is +// [math.Float64frombits](uint64(r2)). // //go:uintptrescapes func (p *Proc) Call(a ...uintptr) (uintptr, uintptr, error) { return SyscallN(p.Addr(), a...) } -// A LazyDLL implements access to a single DLL. +// A LazyDLL implements access to a single [DLL]. // It will delay the load of the DLL until the first -// call to its Handle method or to one of its -// LazyProc's Addr method. +// call to its [LazyDLL.Handle] method or to one of its +// [LazyProc]'s Addr method. // // LazyDLL is subject to the same DLL preloading attacks as documented -// on LoadDLL. +// on [LoadDLL]. // // Use LazyDLL in golang.org/x/sys/windows for a secure way to // load system DLLs. @@ -217,18 +218,18 @@ func (d *LazyDLL) Handle() uintptr { return uintptr(d.dll.Handle) } -// NewProc returns a LazyProc for accessing the named procedure in the DLL d. +// NewProc returns a [LazyProc] for accessing the named procedure in the [DLL] d. func (d *LazyDLL) NewProc(name string) *LazyProc { return &LazyProc{l: d, Name: name} } -// NewLazyDLL creates new LazyDLL associated with DLL file. +// NewLazyDLL creates new [LazyDLL] associated with [DLL] file. func NewLazyDLL(name string) *LazyDLL { return &LazyDLL{Name: name} } -// A LazyProc implements access to a procedure inside a LazyDLL. -// It delays the lookup until the Addr, Call, or Find method is called. +// A LazyProc implements access to a procedure inside a [LazyDLL]. +// It delays the lookup until the [LazyProc.Addr], [LazyProc.Call], or [LazyProc.Find] method is called. type LazyProc struct { mu sync.Mutex Name string @@ -236,7 +237,7 @@ type LazyProc struct { proc *Proc } -// Find searches DLL for procedure named p.Name. It returns +// Find searches [DLL] for procedure named p.Name. It returns // an error if search fails. Find will not search procedure, // if it is already found and loaded into memory. func (p *LazyProc) Find() error { diff --git a/contrib/go/_std_1.22/src/syscall/env_unix.go b/contrib/go/_std_1.23/src/syscall/env_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/env_unix.go rename to contrib/go/_std_1.23/src/syscall/env_unix.go diff --git a/contrib/go/_std_1.22/src/syscall/env_windows.go b/contrib/go/_std_1.23/src/syscall/env_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/env_windows.go rename to contrib/go/_std_1.23/src/syscall/env_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/errors_plan9.go b/contrib/go/_std_1.23/src/syscall/errors_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/errors_plan9.go rename to contrib/go/_std_1.23/src/syscall/errors_plan9.go diff --git a/contrib/go/_std_1.22/src/syscall/exec_bsd.go b/contrib/go/_std_1.23/src/syscall/exec_bsd.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/exec_bsd.go rename to contrib/go/_std_1.23/src/syscall/exec_bsd.go index 149cc2f11c12..bbdab46de48c 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_bsd.go +++ b/contrib/go/_std_1.23/src/syscall/exec_bsd.go @@ -293,3 +293,8 @@ childerror: RawSyscall(SYS_EXIT, 253, 0, 0) } } + +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + // Nothing to do. +} diff --git a/contrib/go/_std_1.22/src/syscall/exec_freebsd.go b/contrib/go/_std_1.23/src/syscall/exec_freebsd.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/exec_freebsd.go rename to contrib/go/_std_1.23/src/syscall/exec_freebsd.go index 3226cb88cd99..686fd23bef43 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_freebsd.go +++ b/contrib/go/_std_1.23/src/syscall/exec_freebsd.go @@ -317,3 +317,8 @@ childerror: RawSyscall(SYS_EXIT, 253, 0, 0) } } + +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + // Nothing to do. +} diff --git a/contrib/go/_std_1.22/src/syscall/exec_libc.go b/contrib/go/_std_1.23/src/syscall/exec_libc.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/exec_libc.go rename to contrib/go/_std_1.23/src/syscall/exec_libc.go index 768e8c131c13..0e886508737d 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_libc.go +++ b/contrib/go/_std_1.23/src/syscall/exec_libc.go @@ -314,6 +314,11 @@ childerror: } } +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + // Nothing to do. +} + func ioctlPtr(fd, req uintptr, arg unsafe.Pointer) (err Errno) { return ioctl(fd, req, uintptr(arg)) } diff --git a/contrib/go/_std_1.22/src/syscall/exec_libc2.go b/contrib/go/_std_1.23/src/syscall/exec_libc2.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/exec_libc2.go rename to contrib/go/_std_1.23/src/syscall/exec_libc2.go index 7a6750084486..a0579627a300 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_libc2.go +++ b/contrib/go/_std_1.23/src/syscall/exec_libc2.go @@ -289,3 +289,8 @@ childerror: rawSyscall(abi.FuncPCABI0(libc_exit_trampoline), 253, 0, 0) } } + +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + // Nothing to do. +} diff --git a/contrib/go/_std_1.23/src/syscall/exec_linux.go b/contrib/go/_std_1.23/src/syscall/exec_linux.go new file mode 100644 index 000000000000..d03194884527 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/exec_linux.go @@ -0,0 +1,831 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux + +package syscall + +import ( + errpkg "errors" + "internal/itoa" + "runtime" + "unsafe" +) + +// Linux unshare/clone/clone2/clone3 flags, architecture-independent, +// copied from linux/sched.h. +const ( + CLONE_VM = 0x00000100 // set if VM shared between processes + CLONE_FS = 0x00000200 // set if fs info shared between processes + CLONE_FILES = 0x00000400 // set if open files shared between processes + CLONE_SIGHAND = 0x00000800 // set if signal handlers and blocked signals shared + CLONE_PIDFD = 0x00001000 // set if a pidfd should be placed in parent + CLONE_PTRACE = 0x00002000 // set if we want to let tracing continue on the child too + CLONE_VFORK = 0x00004000 // set if the parent wants the child to wake it up on mm_release + CLONE_PARENT = 0x00008000 // set if we want to have the same parent as the cloner + CLONE_THREAD = 0x00010000 // Same thread group? + CLONE_NEWNS = 0x00020000 // New mount namespace group + CLONE_SYSVSEM = 0x00040000 // share system V SEM_UNDO semantics + CLONE_SETTLS = 0x00080000 // create a new TLS for the child + CLONE_PARENT_SETTID = 0x00100000 // set the TID in the parent + CLONE_CHILD_CLEARTID = 0x00200000 // clear the TID in the child + CLONE_DETACHED = 0x00400000 // Unused, ignored + CLONE_UNTRACED = 0x00800000 // set if the tracing process can't force CLONE_PTRACE on this clone + CLONE_CHILD_SETTID = 0x01000000 // set the TID in the child + CLONE_NEWCGROUP = 0x02000000 // New cgroup namespace + CLONE_NEWUTS = 0x04000000 // New utsname namespace + CLONE_NEWIPC = 0x08000000 // New ipc namespace + CLONE_NEWUSER = 0x10000000 // New user namespace + CLONE_NEWPID = 0x20000000 // New pid namespace + CLONE_NEWNET = 0x40000000 // New network namespace + CLONE_IO = 0x80000000 // Clone io context + + // Flags for the clone3() syscall. + + CLONE_CLEAR_SIGHAND = 0x100000000 // Clear any signal handler and reset to SIG_DFL. + CLONE_INTO_CGROUP = 0x200000000 // Clone into a specific cgroup given the right permissions. + + // Cloning flags intersect with CSIGNAL so can be used with unshare and clone3 + // syscalls only: + + CLONE_NEWTIME = 0x00000080 // New time namespace +) + +// SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux. +// See user_namespaces(7). +// +// Note that User Namespaces are not available on a number of popular Linux +// versions (due to security issues), or are available but subject to AppArmor +// restrictions like in Ubuntu 24.04. +type SysProcIDMap struct { + ContainerID int // Container ID. + HostID int // Host ID. + Size int // Size. +} + +type SysProcAttr struct { + Chroot string // Chroot. + Credential *Credential // Credential. + // Ptrace tells the child to call ptrace(PTRACE_TRACEME). + // Call runtime.LockOSThread before starting a process with this set, + // and don't call UnlockOSThread until done with PtraceSyscall calls. + Ptrace bool + Setsid bool // Create session. + // Setpgid sets the process group ID of the child to Pgid, + // or, if Pgid == 0, to the new child's process ID. + Setpgid bool + // Setctty sets the controlling terminal of the child to + // file descriptor Ctty. Ctty must be a descriptor number + // in the child process: an index into ProcAttr.Files. + // This is only meaningful if Setsid is true. + Setctty bool + Noctty bool // Detach fd 0 from controlling terminal. + Ctty int // Controlling TTY fd. + // Foreground places the child process group in the foreground. + // This implies Setpgid. The Ctty field must be set to + // the descriptor of the controlling TTY. + // Unlike Setctty, in this case Ctty must be a descriptor + // number in the parent process. + Foreground bool + Pgid int // Child's process group ID if Setpgid. + // Pdeathsig, if non-zero, is a signal that the kernel will send to + // the child process when the creating thread dies. Note that the signal + // is sent on thread termination, which may happen before process termination. + // There are more details at https://go.dev/issue/27505. + Pdeathsig Signal + Cloneflags uintptr // Flags for clone calls. + Unshareflags uintptr // Flags for unshare calls. + UidMappings []SysProcIDMap // User ID mappings for user namespaces. + GidMappings []SysProcIDMap // Group ID mappings for user namespaces. + // GidMappingsEnableSetgroups enabling setgroups syscall. + // If false, then setgroups syscall will be disabled for the child process. + // This parameter is no-op if GidMappings == nil. Otherwise for unprivileged + // users this should be set to false for mappings work. + GidMappingsEnableSetgroups bool + AmbientCaps []uintptr // Ambient capabilities. + UseCgroupFD bool // Whether to make use of the CgroupFD field. + CgroupFD int // File descriptor of a cgroup to put the new process into. + // PidFD, if not nil, is used to store the pidfd of a child, if the + // functionality is supported by the kernel, or -1. Note *PidFD is + // changed only if the process starts successfully. + PidFD *int +} + +var ( + none = [...]byte{'n', 'o', 'n', 'e', 0} + slash = [...]byte{'/', 0} + + forceClone3 = false // Used by unit tests only. +) + +// Implemented in runtime package. +func runtime_BeforeFork() +func runtime_AfterFork() +func runtime_AfterForkInChild() + +// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. +// If a dup or exec fails, write the errno error to pipe. +// (Pipe is close-on-exec so if exec succeeds, it will be closed.) +// In the child, this function must not acquire any locks, because +// they might have been locked at the time of the fork. This means +// no rescheduling, no malloc calls, and no new stack segments. +// For the same reason compiler does not race instrument it. +// The calls to RawSyscall are okay because they are assembly +// functions that do not grow the stack. +// +//go:norace +func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { + // Set up and fork. This returns immediately in the parent or + // if there's an error. + upid, pidfd, err, mapPipe, locked := forkAndExecInChild1(argv0, argv, envv, chroot, dir, attr, sys, pipe) + if locked { + runtime_AfterFork() + } + if err != 0 { + return 0, err + } + + // parent; return PID + pid = int(upid) + if sys.PidFD != nil { + *sys.PidFD = int(pidfd) + } + + if sys.UidMappings != nil || sys.GidMappings != nil { + Close(mapPipe[0]) + var err2 Errno + // uid/gid mappings will be written after fork and unshare(2) for user + // namespaces. + if sys.Unshareflags&CLONE_NEWUSER == 0 { + if err := writeUidGidMappings(pid, sys); err != nil { + err2 = err.(Errno) + } + } + RawSyscall(SYS_WRITE, uintptr(mapPipe[1]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) + Close(mapPipe[1]) + } + + return pid, 0 +} + +const _LINUX_CAPABILITY_VERSION_3 = 0x20080522 + +type capHeader struct { + version uint32 + pid int32 +} + +type capData struct { + effective uint32 + permitted uint32 + inheritable uint32 +} +type caps struct { + hdr capHeader + data [2]capData +} + +// See CAP_TO_INDEX in linux/capability.h: +func capToIndex(cap uintptr) uintptr { return cap >> 5 } + +// See CAP_TO_MASK in linux/capability.h: +func capToMask(cap uintptr) uint32 { return 1 << uint(cap&31) } + +// cloneArgs holds arguments for clone3 Linux syscall. +type cloneArgs struct { + flags uint64 // Flags bit mask + pidFD uint64 // Where to store PID file descriptor (int *) + childTID uint64 // Where to store child TID, in child's memory (pid_t *) + parentTID uint64 // Where to store child TID, in parent's memory (pid_t *) + exitSignal uint64 // Signal to deliver to parent on child termination + stack uint64 // Pointer to lowest byte of stack + stackSize uint64 // Size of stack + tls uint64 // Location of new TLS + setTID uint64 // Pointer to a pid_t array (since Linux 5.5) + setTIDSize uint64 // Number of elements in set_tid (since Linux 5.5) + cgroup uint64 // File descriptor for target cgroup of child (since Linux 5.7) +} + +// forkAndExecInChild1 implements the body of forkAndExecInChild up to +// the parent's post-fork path. This is a separate function so we can +// separate the child's and parent's stack frames if we're using +// vfork. +// +// This is go:noinline because the point is to keep the stack frames +// of this and forkAndExecInChild separate. +// +//go:noinline +//go:norace +//go:nocheckptr +func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid uintptr, pidfd int32, err1 Errno, mapPipe [2]int, locked bool) { + // Defined in linux/prctl.h starting with Linux 4.3. + const ( + PR_CAP_AMBIENT = 0x2f + PR_CAP_AMBIENT_RAISE = 0x2 + ) + + // vfork requires that the child not touch any of the parent's + // active stack frames. Hence, the child does all post-fork + // processing in this stack frame and never returns, while the + // parent returns immediately from this frame and does all + // post-fork processing in the outer frame. + // + // Declare all variables at top in case any + // declarations require heap allocation (e.g., err2). + // ":=" should not be used to declare any variable after + // the call to runtime_BeforeFork. + // + // NOTE(bcmills): The allocation behavior described in the above comment + // seems to lack a corresponding test, and it may be rendered invalid + // by an otherwise-correct change in the compiler. + var ( + err2 Errno + nextfd int + i int + caps caps + fd1, flags uintptr + puid, psetgroups, pgid []byte + uidmap, setgroups, gidmap []byte + clone3 *cloneArgs + pgrp int32 + dirfd int + cred *Credential + ngroups, groups uintptr + c uintptr + ) + pidfd = -1 + + rlim := origRlimitNofile.Load() + + if sys.UidMappings != nil { + puid = []byte("/proc/self/uid_map\000") + uidmap = formatIDMappings(sys.UidMappings) + } + + if sys.GidMappings != nil { + psetgroups = []byte("/proc/self/setgroups\000") + pgid = []byte("/proc/self/gid_map\000") + + if sys.GidMappingsEnableSetgroups { + setgroups = []byte("allow\000") + } else { + setgroups = []byte("deny\000") + } + gidmap = formatIDMappings(sys.GidMappings) + } + + // Record parent PID so child can test if it has died. + ppid, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0) + + // Guard against side effects of shuffling fds below. + // Make sure that nextfd is beyond any currently open files so + // that we can't run the risk of overwriting any of them. + fd := make([]int, len(attr.Files)) + nextfd = len(attr.Files) + for i, ufd := range attr.Files { + if nextfd < int(ufd) { + nextfd = int(ufd) + } + fd[i] = int(ufd) + } + nextfd++ + + // Allocate another pipe for parent to child communication for + // synchronizing writing of User ID/Group ID mappings. + if sys.UidMappings != nil || sys.GidMappings != nil { + if err := forkExecPipe(mapPipe[:]); err != nil { + err1 = err.(Errno) + return + } + } + + flags = sys.Cloneflags + if sys.Cloneflags&CLONE_NEWUSER == 0 && sys.Unshareflags&CLONE_NEWUSER == 0 { + flags |= CLONE_VFORK | CLONE_VM + } + if sys.PidFD != nil { + flags |= CLONE_PIDFD + } + // Whether to use clone3. + if sys.UseCgroupFD || flags&CLONE_NEWTIME != 0 || forceClone3 { + clone3 = &cloneArgs{ + flags: uint64(flags), + exitSignal: uint64(SIGCHLD), + } + if sys.UseCgroupFD { + clone3.flags |= CLONE_INTO_CGROUP + clone3.cgroup = uint64(sys.CgroupFD) + } + if sys.PidFD != nil { + clone3.pidFD = uint64(uintptr(unsafe.Pointer(&pidfd))) + } + } + + // About to call fork. + // No more allocation or calls of non-assembly functions. + runtime_BeforeFork() + locked = true + if clone3 != nil { + pid, err1 = rawVforkSyscall(_SYS_clone3, uintptr(unsafe.Pointer(clone3)), unsafe.Sizeof(*clone3), 0) + } else { + // N.B. Keep in sync with doCheckClonePidfd. + flags |= uintptr(SIGCHLD) + if runtime.GOARCH == "s390x" { + // On Linux/s390, the first two arguments of clone(2) are swapped. + pid, err1 = rawVforkSyscall(SYS_CLONE, 0, flags, uintptr(unsafe.Pointer(&pidfd))) + } else { + pid, err1 = rawVforkSyscall(SYS_CLONE, flags, 0, uintptr(unsafe.Pointer(&pidfd))) + } + } + if err1 != 0 || pid != 0 { + // If we're in the parent, we must return immediately + // so we're not in the same stack frame as the child. + // This can at most use the return PC, which the child + // will not modify, and the results of + // rawVforkSyscall, which must have been written after + // the child was replaced. + return + } + + // Fork succeeded, now in child. + + // Enable the "keep capabilities" flag to set ambient capabilities later. + if len(sys.AmbientCaps) > 0 { + _, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_KEEPCAPS, 1, 0, 0, 0, 0) + if err1 != 0 { + goto childerror + } + } + + // Wait for User ID/Group ID mappings to be written. + if sys.UidMappings != nil || sys.GidMappings != nil { + if _, _, err1 = RawSyscall(SYS_CLOSE, uintptr(mapPipe[1]), 0, 0); err1 != 0 { + goto childerror + } + pid, _, err1 = RawSyscall(SYS_READ, uintptr(mapPipe[0]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) + if err1 != 0 { + goto childerror + } + if pid != unsafe.Sizeof(err2) { + err1 = EINVAL + goto childerror + } + if err2 != 0 { + err1 = err2 + goto childerror + } + } + + // Session ID + if sys.Setsid { + _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0) + if err1 != 0 { + goto childerror + } + } + + // Set process group + if sys.Setpgid || sys.Foreground { + // Place child in process group. + _, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0) + if err1 != 0 { + goto childerror + } + } + + if sys.Foreground { + pgrp = int32(sys.Pgid) + if pgrp == 0 { + pid, _ = rawSyscallNoError(SYS_GETPID, 0, 0, 0) + + pgrp = int32(pid) + } + + // Place process group in foreground. + _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp))) + if err1 != 0 { + goto childerror + } + } + + // Restore the signal mask. We do this after TIOCSPGRP to avoid + // having the kernel send a SIGTTOU signal to the process group. + runtime_AfterForkInChild() + + // Unshare + if sys.Unshareflags != 0 { + _, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshareflags, 0, 0) + if err1 != 0 { + goto childerror + } + + if sys.Unshareflags&CLONE_NEWUSER != 0 && sys.GidMappings != nil { + dirfd = int(_AT_FDCWD) + if fd1, _, err1 = RawSyscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(&psetgroups[0])), uintptr(O_WRONLY), 0, 0, 0); err1 != 0 { + goto childerror + } + pid, _, err1 = RawSyscall(SYS_WRITE, fd1, uintptr(unsafe.Pointer(&setgroups[0])), uintptr(len(setgroups))) + if err1 != 0 { + goto childerror + } + if _, _, err1 = RawSyscall(SYS_CLOSE, fd1, 0, 0); err1 != 0 { + goto childerror + } + + if fd1, _, err1 = RawSyscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(&pgid[0])), uintptr(O_WRONLY), 0, 0, 0); err1 != 0 { + goto childerror + } + pid, _, err1 = RawSyscall(SYS_WRITE, fd1, uintptr(unsafe.Pointer(&gidmap[0])), uintptr(len(gidmap))) + if err1 != 0 { + goto childerror + } + if _, _, err1 = RawSyscall(SYS_CLOSE, fd1, 0, 0); err1 != 0 { + goto childerror + } + } + + if sys.Unshareflags&CLONE_NEWUSER != 0 && sys.UidMappings != nil { + dirfd = int(_AT_FDCWD) + if fd1, _, err1 = RawSyscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(&puid[0])), uintptr(O_WRONLY), 0, 0, 0); err1 != 0 { + goto childerror + } + pid, _, err1 = RawSyscall(SYS_WRITE, fd1, uintptr(unsafe.Pointer(&uidmap[0])), uintptr(len(uidmap))) + if err1 != 0 { + goto childerror + } + if _, _, err1 = RawSyscall(SYS_CLOSE, fd1, 0, 0); err1 != 0 { + goto childerror + } + } + + // The unshare system call in Linux doesn't unshare mount points + // mounted with --shared. Systemd mounts / with --shared. For a + // long discussion of the pros and cons of this see debian bug 739593. + // The Go model of unsharing is more like Plan 9, where you ask + // to unshare and the namespaces are unconditionally unshared. + // To make this model work we must further mark / as MS_PRIVATE. + // This is what the standard unshare command does. + if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS { + _, _, err1 = RawSyscall6(SYS_MOUNT, uintptr(unsafe.Pointer(&none[0])), uintptr(unsafe.Pointer(&slash[0])), 0, MS_REC|MS_PRIVATE, 0, 0) + if err1 != 0 { + goto childerror + } + } + } + + // Chroot + if chroot != nil { + _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0) + if err1 != 0 { + goto childerror + } + } + + // User and groups + if cred = sys.Credential; cred != nil { + ngroups = uintptr(len(cred.Groups)) + groups = uintptr(0) + if ngroups > 0 { + groups = uintptr(unsafe.Pointer(&cred.Groups[0])) + } + if !(sys.GidMappings != nil && !sys.GidMappingsEnableSetgroups && ngroups == 0) && !cred.NoSetGroups { + _, _, err1 = RawSyscall(_SYS_setgroups, ngroups, groups, 0) + if err1 != 0 { + goto childerror + } + } + _, _, err1 = RawSyscall(sys_SETGID, uintptr(cred.Gid), 0, 0) + if err1 != 0 { + goto childerror + } + _, _, err1 = RawSyscall(sys_SETUID, uintptr(cred.Uid), 0, 0) + if err1 != 0 { + goto childerror + } + } + + if len(sys.AmbientCaps) != 0 { + // Ambient capabilities were added in the 4.3 kernel, + // so it is safe to always use _LINUX_CAPABILITY_VERSION_3. + caps.hdr.version = _LINUX_CAPABILITY_VERSION_3 + + if _, _, err1 = RawSyscall(SYS_CAPGET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); err1 != 0 { + goto childerror + } + + for _, c = range sys.AmbientCaps { + // Add the c capability to the permitted and inheritable capability mask, + // otherwise we will not be able to add it to the ambient capability mask. + caps.data[capToIndex(c)].permitted |= capToMask(c) + caps.data[capToIndex(c)].inheritable |= capToMask(c) + } + + if _, _, err1 = RawSyscall(SYS_CAPSET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); err1 != 0 { + goto childerror + } + + for _, c = range sys.AmbientCaps { + _, _, err1 = RawSyscall6(SYS_PRCTL, PR_CAP_AMBIENT, uintptr(PR_CAP_AMBIENT_RAISE), c, 0, 0, 0) + if err1 != 0 { + goto childerror + } + } + } + + // Chdir + if dir != nil { + _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0) + if err1 != 0 { + goto childerror + } + } + + // Parent death signal + if sys.Pdeathsig != 0 { + _, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0) + if err1 != 0 { + goto childerror + } + + // Signal self if parent is already dead. This might cause a + // duplicate signal in rare cases, but it won't matter when + // using SIGKILL. + pid, _ = rawSyscallNoError(SYS_GETPPID, 0, 0, 0) + if pid != ppid { + pid, _ = rawSyscallNoError(SYS_GETPID, 0, 0, 0) + _, _, err1 = RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0) + if err1 != 0 { + goto childerror + } + } + } + + // Pass 1: look for fd[i] < i and move those up above len(fd) + // so that pass 2 won't stomp on an fd it needs later. + if pipe < nextfd { + _, _, err1 = RawSyscall(SYS_DUP3, uintptr(pipe), uintptr(nextfd), O_CLOEXEC) + if err1 != 0 { + goto childerror + } + pipe = nextfd + nextfd++ + } + for i = 0; i < len(fd); i++ { + if fd[i] >= 0 && fd[i] < i { + if nextfd == pipe { // don't stomp on pipe + nextfd++ + } + _, _, err1 = RawSyscall(SYS_DUP3, uintptr(fd[i]), uintptr(nextfd), O_CLOEXEC) + if err1 != 0 { + goto childerror + } + fd[i] = nextfd + nextfd++ + } + } + + // Pass 2: dup fd[i] down onto i. + for i = 0; i < len(fd); i++ { + if fd[i] == -1 { + RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) + continue + } + if fd[i] == i { + // dup2(i, i) won't clear close-on-exec flag on Linux, + // probably not elsewhere either. + _, _, err1 = RawSyscall(fcntl64Syscall, uintptr(fd[i]), F_SETFD, 0) + if err1 != 0 { + goto childerror + } + continue + } + // The new fd is created NOT close-on-exec, + // which is exactly what we want. + _, _, err1 = RawSyscall(SYS_DUP3, uintptr(fd[i]), uintptr(i), 0) + if err1 != 0 { + goto childerror + } + } + + // By convention, we don't close-on-exec the fds we are + // started with, so if len(fd) < 3, close 0, 1, 2 as needed. + // Programs that know they inherit fds >= 3 will need + // to set them close-on-exec. + for i = len(fd); i < 3; i++ { + RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) + } + + // Detach fd 0 from tty + if sys.Noctty { + _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0) + if err1 != 0 { + goto childerror + } + } + + // Set the controlling TTY to Ctty + if sys.Setctty { + _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 1) + if err1 != 0 { + goto childerror + } + } + + // Restore original rlimit. + if rlim != nil { + rawSetrlimit(RLIMIT_NOFILE, rlim) + } + + // Enable tracing if requested. + // Do this right before exec so that we don't unnecessarily trace the runtime + // setting up after the fork. See issue #21428. + if sys.Ptrace { + _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0) + if err1 != 0 { + goto childerror + } + } + + // Time to exec. + _, _, err1 = RawSyscall(SYS_EXECVE, + uintptr(unsafe.Pointer(argv0)), + uintptr(unsafe.Pointer(&argv[0])), + uintptr(unsafe.Pointer(&envv[0]))) + +childerror: + // send error code on pipe + RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) + for { + RawSyscall(SYS_EXIT, 253, 0, 0) + } +} + +func formatIDMappings(idMap []SysProcIDMap) []byte { + var data []byte + for _, im := range idMap { + data = append(data, itoa.Itoa(im.ContainerID)+" "+itoa.Itoa(im.HostID)+" "+itoa.Itoa(im.Size)+"\n"...) + } + return data +} + +// writeIDMappings writes the user namespace User ID or Group ID mappings to the specified path. +func writeIDMappings(path string, idMap []SysProcIDMap) error { + fd, err := Open(path, O_RDWR, 0) + if err != nil { + return err + } + + if _, err := Write(fd, formatIDMappings(idMap)); err != nil { + Close(fd) + return err + } + + if err := Close(fd); err != nil { + return err + } + + return nil +} + +// writeSetgroups writes to /proc/PID/setgroups "deny" if enable is false +// and "allow" if enable is true. +// This is needed since kernel 3.19, because you can't write gid_map without +// disabling setgroups() system call. +func writeSetgroups(pid int, enable bool) error { + sgf := "/proc/" + itoa.Itoa(pid) + "/setgroups" + fd, err := Open(sgf, O_RDWR, 0) + if err != nil { + return err + } + + var data []byte + if enable { + data = []byte("allow") + } else { + data = []byte("deny") + } + + if _, err := Write(fd, data); err != nil { + Close(fd) + return err + } + + return Close(fd) +} + +// writeUidGidMappings writes User ID and Group ID mappings for user namespaces +// for a process and it is called from the parent process. +func writeUidGidMappings(pid int, sys *SysProcAttr) error { + if sys.UidMappings != nil { + uidf := "/proc/" + itoa.Itoa(pid) + "/uid_map" + if err := writeIDMappings(uidf, sys.UidMappings); err != nil { + return err + } + } + + if sys.GidMappings != nil { + // If the kernel is too old to support /proc/PID/setgroups, writeSetGroups will return ENOENT; this is OK. + if err := writeSetgroups(pid, sys.GidMappingsEnableSetgroups); err != nil && err != ENOENT { + return err + } + gidf := "/proc/" + itoa.Itoa(pid) + "/gid_map" + if err := writeIDMappings(gidf, sys.GidMappings); err != nil { + return err + } + } + + return nil +} + +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + if sys.PidFD != nil && *sys.PidFD != -1 { + Close(*sys.PidFD) + *sys.PidFD = -1 + } +} + +// checkClonePidfd verifies that clone(CLONE_PIDFD) works by actually doing a +// clone. +// +//go:linkname os_checkClonePidfd os.checkClonePidfd +func os_checkClonePidfd() error { + pidfd := int32(-1) + pid, errno := doCheckClonePidfd(&pidfd) + if errno != 0 { + return errno + } + + if pidfd == -1 { + // Bad: CLONE_PIDFD failed to provide a pidfd. Reap the process + // before returning. + + var err error + for { + var status WaitStatus + // WCLONE is an untyped constant that sets bit 31, so + // it cannot convert directly to int on 32-bit + // GOARCHes. We must convert through another type + // first. + flags := uint(WCLONE) + _, err = Wait4(int(pid), &status, int(flags), nil) + if err != EINTR { + break + } + } + if err != nil { + return err + } + + return errpkg.New("clone(CLONE_PIDFD) failed to return pidfd") + } + + // Good: CLONE_PIDFD provided a pidfd. Reap the process and close the + // pidfd. + defer Close(int(pidfd)) + + for { + const _P_PIDFD = 3 + _, _, errno = Syscall6(SYS_WAITID, _P_PIDFD, uintptr(pidfd), 0, WEXITED | WCLONE, 0, 0) + if errno != EINTR { + break + } + } + if errno != 0 { + return errno + } + + return nil +} + +// doCheckClonePidfd implements the actual clone call of os_checkClonePidfd and +// child execution. This is a separate function so we can separate the child's +// and parent's stack frames if we're using vfork. +// +// This is go:noinline because the point is to keep the stack frames of this +// and os_checkClonePidfd separate. +// +//go:noinline +func doCheckClonePidfd(pidfd *int32) (pid uintptr, errno Errno) { + flags := uintptr(CLONE_VFORK | CLONE_VM | CLONE_PIDFD) + if runtime.GOARCH == "s390x" { + // On Linux/s390, the first two arguments of clone(2) are swapped. + pid, errno = rawVforkSyscall(SYS_CLONE, 0, flags, uintptr(unsafe.Pointer(pidfd))) + } else { + pid, errno = rawVforkSyscall(SYS_CLONE, flags, 0, uintptr(unsafe.Pointer(pidfd))) + } + if errno != 0 || pid != 0 { + // If we're in the parent, we must return immediately + // so we're not in the same stack frame as the child. + // This can at most use the return PC, which the child + // will not modify, and the results of + // rawVforkSyscall, which must have been written after + // the child was replaced. + return + } + + for { + RawSyscall(SYS_EXIT_GROUP, 0, 0, 0) + } +} diff --git a/contrib/go/_std_1.23/src/syscall/exec_plan9.go b/contrib/go/_std_1.23/src/syscall/exec_plan9.go new file mode 100644 index 000000000000..91705e175edc --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/exec_plan9.go @@ -0,0 +1,611 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Fork, exec, wait, etc. + +package syscall + +import ( + "internal/itoa" + "runtime" + "sync" + "unsafe" +) + +// ForkLock is not used on plan9. +var ForkLock sync.RWMutex + +// gstringb reads a non-empty string from b, prefixed with a 16-bit length in little-endian order. +// It returns the string as a byte slice, or nil if b is too short to contain the length or +// the full string. +// +//go:nosplit +func gstringb(b []byte) []byte { + if len(b) < 2 { + return nil + } + n, b := gbit16(b) + if int(n) > len(b) { + return nil + } + return b[:n] +} + +// Offset of the name field in a 9P directory entry - see UnmarshalDir() in dir_plan9.go +const nameOffset = 39 + +// gdirname returns the first filename from a buffer of directory entries, +// and a slice containing the remaining directory entries. +// If the buffer doesn't start with a valid directory entry, the returned name is nil. +// +//go:nosplit +func gdirname(buf []byte) (name []byte, rest []byte) { + if len(buf) < 2 { + return + } + size, buf := gbit16(buf) + if size < STATFIXLEN || int(size) > len(buf) { + return + } + name = gstringb(buf[nameOffset:size]) + rest = buf[size:] + return +} + +// StringSlicePtr converts a slice of strings to a slice of pointers +// to NUL-terminated byte arrays. If any string contains a NUL byte +// this function panics instead of returning an error. +// +// Deprecated: Use SlicePtrFromStrings instead. +func StringSlicePtr(ss []string) []*byte { + bb := make([]*byte, len(ss)+1) + for i := 0; i < len(ss); i++ { + bb[i] = StringBytePtr(ss[i]) + } + bb[len(ss)] = nil + return bb +} + +// SlicePtrFromStrings converts a slice of strings to a slice of +// pointers to NUL-terminated byte arrays. If any string contains +// a NUL byte, it returns (nil, [EINVAL]). +func SlicePtrFromStrings(ss []string) ([]*byte, error) { + var err error + bb := make([]*byte, len(ss)+1) + for i := 0; i < len(ss); i++ { + bb[i], err = BytePtrFromString(ss[i]) + if err != nil { + return nil, err + } + } + bb[len(ss)] = nil + return bb, nil +} + +// readdirnames returns the names of files inside the directory represented by dirfd. +func readdirnames(dirfd int) (names []string, err error) { + names = make([]string, 0, 100) + var buf [STATMAX]byte + + for { + n, e := Read(dirfd, buf[:]) + if e != nil { + return nil, e + } + if n == 0 { + break + } + for b := buf[:n]; len(b) > 0; { + var s []byte + s, b = gdirname(b) + if s == nil { + return nil, ErrBadStat + } + names = append(names, string(s)) + } + } + return +} + +// name of the directory containing names and control files for all open file descriptors +var dupdev, _ = BytePtrFromString("#d") + +// forkAndExecInChild forks the process, calling dup onto 0..len(fd) +// and finally invoking exec(argv0, argvv, envv) in the child. +// If a dup or exec fails, it writes the error string to pipe. +// (The pipe write end is close-on-exec so if exec succeeds, it will be closed.) +// +// In the child, this function must not acquire any locks, because +// they might have been locked at the time of the fork. This means +// no rescheduling, no malloc calls, and no new stack segments. +// The calls to RawSyscall are okay because they are assembly +// functions that do not grow the stack. +// +//go:norace +func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, pipe int, rflag int) (pid int, err error) { + // Declare all variables at top in case any + // declarations require heap allocation (e.g., errbuf). + var ( + r1 uintptr + nextfd int + i int + clearenv int + envfd int + errbuf [ERRMAX]byte + statbuf [STATMAX]byte + dupdevfd int + n int + b []byte + ) + + // Guard against side effects of shuffling fds below. + // Make sure that nextfd is beyond any currently open files so + // that we can't run the risk of overwriting any of them. + fd := make([]int, len(attr.Files)) + nextfd = len(attr.Files) + for i, ufd := range attr.Files { + if nextfd < int(ufd) { + nextfd = int(ufd) + } + fd[i] = int(ufd) + } + nextfd++ + + if envv != nil { + clearenv = RFCENVG + } + + // About to call fork. + // No more allocation or calls of non-assembly functions. + r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv|rflag), 0, 0) + + if r1 != 0 { + if int32(r1) == -1 { + return 0, NewError(errstr()) + } + // parent; return PID + return int(r1), nil + } + + // Fork succeeded, now in child. + + // Close fds we don't need. + r1, _, _ = RawSyscall(SYS_OPEN, uintptr(unsafe.Pointer(dupdev)), uintptr(O_RDONLY), 0) + dupdevfd = int(r1) + if dupdevfd == -1 { + goto childerror + } +dirloop: + for { + r1, _, _ = RawSyscall6(SYS_PREAD, uintptr(dupdevfd), uintptr(unsafe.Pointer(&statbuf[0])), uintptr(len(statbuf)), ^uintptr(0), ^uintptr(0), 0) + n = int(r1) + switch n { + case -1: + goto childerror + case 0: + break dirloop + } + for b = statbuf[:n]; len(b) > 0; { + var s []byte + s, b = gdirname(b) + if s == nil { + copy(errbuf[:], ErrBadStat.Error()) + goto childerror1 + } + if s[len(s)-1] == 'l' { + // control file for descriptor is named ctl + continue + } + closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd) + } + } + RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0) + + // Write new environment variables. + if envv != nil { + for i = 0; i < len(envv); i++ { + r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666)) + + if int32(r1) == -1 { + goto childerror + } + + envfd = int(r1) + + r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintptr(unsafe.Pointer(envv[i].value)), uintptr(envv[i].nvalue), + ^uintptr(0), ^uintptr(0), 0) + + if int32(r1) == -1 || int(r1) != envv[i].nvalue { + goto childerror + } + + r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0) + + if int32(r1) == -1 { + goto childerror + } + } + } + + // Chdir + if dir != nil { + r1, _, _ = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0) + if int32(r1) == -1 { + goto childerror + } + } + + // Pass 1: look for fd[i] < i and move those up above len(fd) + // so that pass 2 won't stomp on an fd it needs later. + if pipe < nextfd { + r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0) + if int32(r1) == -1 { + goto childerror + } + pipe = nextfd + nextfd++ + } + for i = 0; i < len(fd); i++ { + if fd[i] >= 0 && fd[i] < i { + if nextfd == pipe { // don't stomp on pipe + nextfd++ + } + r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(nextfd), 0) + if int32(r1) == -1 { + goto childerror + } + + fd[i] = nextfd + nextfd++ + } + } + + // Pass 2: dup fd[i] down onto i. + for i = 0; i < len(fd); i++ { + if fd[i] == -1 { + RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) + continue + } + if fd[i] == i { + continue + } + r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(i), 0) + if int32(r1) == -1 { + goto childerror + } + } + + // Pass 3: close fd[i] if it was moved in the previous pass. + for i = 0; i < len(fd); i++ { + if fd[i] >= len(fd) { + RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0) + } + } + + // Time to exec. + r1, _, _ = RawSyscall(SYS_EXEC, + uintptr(unsafe.Pointer(argv0)), + uintptr(unsafe.Pointer(&argv[0])), 0) + +childerror: + // send error string on pipe + RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0) +childerror1: + errbuf[len(errbuf)-1] = 0 + i = 0 + for i < len(errbuf) && errbuf[i] != 0 { + i++ + } + + RawSyscall6(SYS_PWRITE, uintptr(pipe), uintptr(unsafe.Pointer(&errbuf[0])), uintptr(i), + ^uintptr(0), ^uintptr(0), 0) + + for { + RawSyscall(SYS_EXITS, 0, 0, 0) + } +} + +// close the numbered file descriptor, unless it is fd1, fd2, or a member of fds. +// +//go:nosplit +func closeFdExcept(n int, fd1 int, fd2 int, fds []int) { + if n == fd1 || n == fd2 { + return + } + for _, fd := range fds { + if n == fd { + return + } + } + RawSyscall(SYS_CLOSE, uintptr(n), 0, 0) +} + +func cexecPipe(p []int) error { + e := Pipe(p) + if e != nil { + return e + } + + fd, e := Open("#d/"+itoa.Itoa(p[1]), O_RDWR|O_CLOEXEC) + if e != nil { + Close(p[0]) + Close(p[1]) + return e + } + + Close(p[1]) + p[1] = fd + return nil +} + +type envItem struct { + name *byte + value *byte + nvalue int +} + +type ProcAttr struct { + Dir string // Current working directory. + Env []string // Environment. + Files []uintptr // File descriptors. + Sys *SysProcAttr +} + +type SysProcAttr struct { + Rfork int // additional flags to pass to rfork +} + +var zeroProcAttr ProcAttr +var zeroSysProcAttr SysProcAttr + +func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { + var ( + p [2]int + n int + errbuf [ERRMAX]byte + wmsg Waitmsg + ) + + if attr == nil { + attr = &zeroProcAttr + } + sys := attr.Sys + if sys == nil { + sys = &zeroSysProcAttr + } + + p[0] = -1 + p[1] = -1 + + // Convert args to C form. + argv0p, err := BytePtrFromString(argv0) + if err != nil { + return 0, err + } + argvp, err := SlicePtrFromStrings(argv) + if err != nil { + return 0, err + } + + destDir := attr.Dir + if destDir == "" { + wdmu.Lock() + destDir = wdStr + wdmu.Unlock() + } + var dir *byte + if destDir != "" { + dir, err = BytePtrFromString(destDir) + if err != nil { + return 0, err + } + } + var envvParsed []envItem + if attr.Env != nil { + envvParsed = make([]envItem, 0, len(attr.Env)) + for _, v := range attr.Env { + i := 0 + for i < len(v) && v[i] != '=' { + i++ + } + + envname, err := BytePtrFromString("/env/" + v[:i]) + if err != nil { + return 0, err + } + envvalue := make([]byte, len(v)-i) + copy(envvalue, v[i+1:]) + envvParsed = append(envvParsed, envItem{envname, &envvalue[0], len(v) - i}) + } + } + + // Allocate child status pipe close on exec. + e := cexecPipe(p[:]) + + if e != nil { + return 0, e + } + + // Kick off child. + pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, p[1], sys.Rfork) + + if err != nil { + if p[0] >= 0 { + Close(p[0]) + Close(p[1]) + } + return 0, err + } + + // Read child error status from pipe. + Close(p[1]) + n, err = Read(p[0], errbuf[:]) + Close(p[0]) + + if err != nil || n != 0 { + if n > 0 { + err = NewError(string(errbuf[:n])) + } else if err == nil { + err = NewError("failed to read exec status") + } + + // Child failed; wait for it to exit, to make sure + // the zombies don't accumulate. + for wmsg.Pid != pid { + Await(&wmsg) + } + return 0, err + } + + // Read got EOF, so pipe closed on exec, so exec succeeded. + return pid, nil +} + +type waitErr struct { + Waitmsg + err error +} + +var procs struct { + sync.Mutex + waits map[int]chan *waitErr +} + +// startProcess starts a new goroutine, tied to the OS +// thread, which runs the process and subsequently waits +// for it to finish, communicating the process stats back +// to any goroutines that may have been waiting on it. +// +// Such a dedicated goroutine is needed because on +// Plan 9, only the parent thread can wait for a child, +// whereas goroutines tend to jump OS threads (e.g., +// between starting a process and running Wait(), the +// goroutine may have been rescheduled). +func startProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { + type forkRet struct { + pid int + err error + } + + forkc := make(chan forkRet, 1) + go func() { + runtime.LockOSThread() + var ret forkRet + + ret.pid, ret.err = forkExec(argv0, argv, attr) + // If fork fails there is nothing to wait for. + if ret.err != nil || ret.pid == 0 { + forkc <- ret + return + } + + waitc := make(chan *waitErr, 1) + + // Mark that the process is running. + procs.Lock() + if procs.waits == nil { + procs.waits = make(map[int]chan *waitErr) + } + procs.waits[ret.pid] = waitc + procs.Unlock() + + forkc <- ret + + var w waitErr + for w.err == nil && w.Pid != ret.pid { + w.err = Await(&w.Waitmsg) + } + waitc <- &w + close(waitc) + }() + ret := <-forkc + return ret.pid, ret.err +} + +// Combination of fork and exec, careful to be thread safe. +func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { + return startProcess(argv0, argv, attr) +} + +// StartProcess wraps [ForkExec] for package os. +func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { + pid, err = startProcess(argv0, argv, attr) + return pid, 0, err +} + +// Ordinary exec. +func Exec(argv0 string, argv []string, envv []string) (err error) { + if envv != nil { + r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0) + if int32(r1) == -1 { + return NewError(errstr()) + } + + for _, v := range envv { + i := 0 + for i < len(v) && v[i] != '=' { + i++ + } + + fd, e := Create("/env/"+v[:i], O_WRONLY, 0666) + if e != nil { + return e + } + + _, e = Write(fd, []byte(v[i+1:])) + if e != nil { + Close(fd) + return e + } + Close(fd) + } + } + + argv0p, err := BytePtrFromString(argv0) + if err != nil { + return err + } + argvp, err := SlicePtrFromStrings(argv) + if err != nil { + return err + } + _, _, e1 := Syscall(SYS_EXEC, + uintptr(unsafe.Pointer(argv0p)), + uintptr(unsafe.Pointer(&argvp[0])), + 0) + + return e1 +} + +// WaitProcess waits until the pid of a +// running process is found in the queue of +// wait messages. It is used in conjunction +// with [ForkExec]/[StartProcess] to wait for a +// running process to exit. +func WaitProcess(pid int, w *Waitmsg) (err error) { + procs.Lock() + ch := procs.waits[pid] + procs.Unlock() + + var wmsg *waitErr + if ch != nil { + wmsg = <-ch + procs.Lock() + if procs.waits[pid] == ch { + delete(procs.waits, pid) + } + procs.Unlock() + } + if wmsg == nil { + // ch was missing or ch is closed + return NewError("process not found") + } + if wmsg.err != nil { + return wmsg.err + } + if w != nil { + *w = wmsg.Waitmsg + } + return nil +} diff --git a/contrib/go/_std_1.23/src/syscall/exec_unix.go b/contrib/go/_std_1.23/src/syscall/exec_unix.go new file mode 100644 index 000000000000..4747fa075834 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/exec_unix.go @@ -0,0 +1,314 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +// Fork, exec, wait, etc. + +package syscall + +import ( + errorspkg "errors" + "internal/bytealg" + "runtime" + "sync" + "unsafe" +) + +// ForkLock is used to synchronize creation of new file descriptors +// with fork. +// +// We want the child in a fork/exec sequence to inherit only the +// file descriptors we intend. To do that, we mark all file +// descriptors close-on-exec and then, in the child, explicitly +// unmark the ones we want the exec'ed program to keep. +// Unix doesn't make this easy: there is, in general, no way to +// allocate a new file descriptor close-on-exec. Instead you +// have to allocate the descriptor and then mark it close-on-exec. +// If a fork happens between those two events, the child's exec +// will inherit an unwanted file descriptor. +// +// This lock solves that race: the create new fd/mark close-on-exec +// operation is done holding ForkLock for reading, and the fork itself +// is done holding ForkLock for writing. At least, that's the idea. +// There are some complications. +// +// Some system calls that create new file descriptors can block +// for arbitrarily long times: open on a hung NFS server or named +// pipe, accept on a socket, and so on. We can't reasonably grab +// the lock across those operations. +// +// It is worse to inherit some file descriptors than others. +// If a non-malicious child accidentally inherits an open ordinary file, +// that's not a big deal. On the other hand, if a long-lived child +// accidentally inherits the write end of a pipe, then the reader +// of that pipe will not see EOF until that child exits, potentially +// causing the parent program to hang. This is a common problem +// in threaded C programs that use popen. +// +// Luckily, the file descriptors that are most important not to +// inherit are not the ones that can take an arbitrarily long time +// to create: pipe returns instantly, and the net package uses +// non-blocking I/O to accept on a listening socket. +// The rules for which file descriptor-creating operations use the +// ForkLock are as follows: +// +// - [Pipe]. Use pipe2 if available. Otherwise, does not block, +// so use ForkLock. +// - [Socket]. Use SOCK_CLOEXEC if available. Otherwise, does not +// block, so use ForkLock. +// - [Open]. Use [O_CLOEXEC] if available. Otherwise, may block, +// so live with the race. +// - [Dup]. Use [F_DUPFD_CLOEXEC] or dup3 if available. Otherwise, +// does not block, so use ForkLock. +var ForkLock sync.RWMutex + +// StringSlicePtr converts a slice of strings to a slice of pointers +// to NUL-terminated byte arrays. If any string contains a NUL byte +// this function panics instead of returning an error. +// +// Deprecated: Use [SlicePtrFromStrings] instead. +func StringSlicePtr(ss []string) []*byte { + bb := make([]*byte, len(ss)+1) + for i := 0; i < len(ss); i++ { + bb[i] = StringBytePtr(ss[i]) + } + bb[len(ss)] = nil + return bb +} + +// SlicePtrFromStrings converts a slice of strings to a slice of +// pointers to NUL-terminated byte arrays. If any string contains +// a NUL byte, it returns (nil, [EINVAL]). +func SlicePtrFromStrings(ss []string) ([]*byte, error) { + n := 0 + for _, s := range ss { + if bytealg.IndexByteString(s, 0) != -1 { + return nil, EINVAL + } + n += len(s) + 1 // +1 for NUL + } + bb := make([]*byte, len(ss)+1) + b := make([]byte, n) + n = 0 + for i, s := range ss { + bb[i] = &b[n] + copy(b[n:], s) + n += len(s) + 1 + } + return bb, nil +} + +func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) } + +func SetNonblock(fd int, nonblocking bool) (err error) { + flag, err := fcntl(fd, F_GETFL, 0) + if err != nil { + return err + } + if (flag&O_NONBLOCK != 0) == nonblocking { + return nil + } + if nonblocking { + flag |= O_NONBLOCK + } else { + flag &^= O_NONBLOCK + } + _, err = fcntl(fd, F_SETFL, flag) + return err +} + +// Credential holds user and group identities to be assumed +// by a child process started by [StartProcess]. +type Credential struct { + Uid uint32 // User ID. + Gid uint32 // Group ID. + Groups []uint32 // Supplementary group IDs. + NoSetGroups bool // If true, don't set supplementary groups +} + +// ProcAttr holds attributes that will be applied to a new process started +// by [StartProcess]. +type ProcAttr struct { + Dir string // Current working directory. + Env []string // Environment. + Files []uintptr // File descriptors. + Sys *SysProcAttr +} + +var zeroProcAttr ProcAttr +var zeroSysProcAttr SysProcAttr + +func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { + var p [2]int + var n int + var err1 Errno + var wstatus WaitStatus + + if attr == nil { + attr = &zeroProcAttr + } + sys := attr.Sys + if sys == nil { + sys = &zeroSysProcAttr + } + + // Convert args to C form. + argv0p, err := BytePtrFromString(argv0) + if err != nil { + return 0, err + } + argvp, err := SlicePtrFromStrings(argv) + if err != nil { + return 0, err + } + envvp, err := SlicePtrFromStrings(attr.Env) + if err != nil { + return 0, err + } + + if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv) > 0 && len(argv[0]) > len(argv0) { + argvp[0] = argv0p + } + + var chroot *byte + if sys.Chroot != "" { + chroot, err = BytePtrFromString(sys.Chroot) + if err != nil { + return 0, err + } + } + var dir *byte + if attr.Dir != "" { + dir, err = BytePtrFromString(attr.Dir) + if err != nil { + return 0, err + } + } + + // Both Setctty and Foreground use the Ctty field, + // but they give it slightly different meanings. + if sys.Setctty && sys.Foreground { + return 0, errorspkg.New("both Setctty and Foreground set in SysProcAttr") + } + if sys.Setctty && sys.Ctty >= len(attr.Files) { + return 0, errorspkg.New("Setctty set but Ctty not valid in child") + } + + acquireForkLock() + + // Allocate child status pipe close on exec. + if err = forkExecPipe(p[:]); err != nil { + releaseForkLock() + return 0, err + } + + // Kick off child. + pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1]) + if err1 != 0 { + Close(p[0]) + Close(p[1]) + releaseForkLock() + return 0, Errno(err1) + } + releaseForkLock() + + // Read child error status from pipe. + Close(p[1]) + for { + n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1))) + if err != EINTR { + break + } + } + Close(p[0]) + if err != nil || n != 0 { + if n == int(unsafe.Sizeof(err1)) { + err = Errno(err1) + } + if err == nil { + err = EPIPE + } + + // Child failed; wait for it to exit, to make sure + // the zombies don't accumulate. + _, err1 := Wait4(pid, &wstatus, 0, nil) + for err1 == EINTR { + _, err1 = Wait4(pid, &wstatus, 0, nil) + } + + // OS-specific cleanup on failure. + forkAndExecFailureCleanup(attr, sys) + + return 0, err + } + + // Read got EOF, so pipe closed on exec, so exec succeeded. + return pid, nil +} + +// Combination of fork and exec, careful to be thread safe. +func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { + return forkExec(argv0, argv, attr) +} + +// StartProcess wraps [ForkExec] for package os. +func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { + pid, err = forkExec(argv0, argv, attr) + return pid, 0, err +} + +// Implemented in runtime package. +func runtime_BeforeExec() +func runtime_AfterExec() + +// execveLibc is non-nil on OS using libc syscall, set to execve in exec_libc.go; this +// avoids a build dependency for other platforms. +var execveLibc func(path uintptr, argv uintptr, envp uintptr) Errno +var execveDarwin func(path *byte, argv **byte, envp **byte) error +var execveOpenBSD func(path *byte, argv **byte, envp **byte) error + +// Exec invokes the execve(2) system call. +func Exec(argv0 string, argv []string, envv []string) (err error) { + argv0p, err := BytePtrFromString(argv0) + if err != nil { + return err + } + argvp, err := SlicePtrFromStrings(argv) + if err != nil { + return err + } + envvp, err := SlicePtrFromStrings(envv) + if err != nil { + return err + } + runtime_BeforeExec() + + rlim := origRlimitNofile.Load() + if rlim != nil { + Setrlimit(RLIMIT_NOFILE, rlim) + } + + var err1 error + if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "aix" { + // RawSyscall should never be used on Solaris, illumos, or AIX. + err1 = execveLibc( + uintptr(unsafe.Pointer(argv0p)), + uintptr(unsafe.Pointer(&argvp[0])), + uintptr(unsafe.Pointer(&envvp[0]))) + } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { + // Similarly on Darwin. + err1 = execveDarwin(argv0p, &argvp[0], &envvp[0]) + } else if runtime.GOOS == "openbsd" && runtime.GOARCH != "mips64" { + // Similarly on OpenBSD. + err1 = execveOpenBSD(argv0p, &argvp[0], &envvp[0]) + } else { + _, _, err1 = RawSyscall(SYS_EXECVE, + uintptr(unsafe.Pointer(argv0p)), + uintptr(unsafe.Pointer(&argvp[0])), + uintptr(unsafe.Pointer(&envvp[0]))) + } + runtime_AfterExec() + return err1 +} diff --git a/contrib/go/_std_1.22/src/syscall/exec_windows.go b/contrib/go/_std_1.23/src/syscall/exec_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/exec_windows.go rename to contrib/go/_std_1.23/src/syscall/exec_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/flock_aix.go b/contrib/go/_std_1.23/src/syscall/flock_aix.go similarity index 84% rename from contrib/go/_std_1.22/src/syscall/flock_aix.go rename to contrib/go/_std_1.23/src/syscall/flock_aix.go index c9eab43b6bc2..d8be7ab504b1 100644 --- a/contrib/go/_std_1.22/src/syscall/flock_aix.go +++ b/contrib/go/_std_1.23/src/syscall/flock_aix.go @@ -8,7 +8,7 @@ import "unsafe" // On AIX, there is no flock() system call. -// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +// FcntlFlock performs a fcntl syscall for the [F_GETLK], [F_SETLK] or [F_SETLKW] command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) (err error) { _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0) if e1 != 0 { diff --git a/contrib/go/_std_1.22/src/syscall/flock_bsd.go b/contrib/go/_std_1.23/src/syscall/flock_bsd.go similarity index 80% rename from contrib/go/_std_1.22/src/syscall/flock_bsd.go rename to contrib/go/_std_1.23/src/syscall/flock_bsd.go index 68d34708483a..3be2656be7a9 100644 --- a/contrib/go/_std_1.22/src/syscall/flock_bsd.go +++ b/contrib/go/_std_1.23/src/syscall/flock_bsd.go @@ -8,7 +8,7 @@ package syscall import "unsafe" -// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +// FcntlFlock performs a fcntl syscall for the [F_GETLK], [F_SETLK] or [F_SETLKW] command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { _, err := fcntlPtr(int(fd), cmd, unsafe.Pointer(lk)) return err diff --git a/contrib/go/_std_1.22/src/syscall/flock_linux.go b/contrib/go/_std_1.23/src/syscall/flock_linux.go similarity index 85% rename from contrib/go/_std_1.22/src/syscall/flock_linux.go rename to contrib/go/_std_1.23/src/syscall/flock_linux.go index 7d1169b42862..2e87b2e0e432 100644 --- a/contrib/go/_std_1.22/src/syscall/flock_linux.go +++ b/contrib/go/_std_1.23/src/syscall/flock_linux.go @@ -10,7 +10,7 @@ import "unsafe" // systems by flock_linux_32bit.go to be SYS_FCNTL64. var fcntl64Syscall uintptr = SYS_FCNTL -// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +// FcntlFlock performs a fcntl syscall for the [F_GETLK], [F_SETLK] or [F_SETLKW] command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { _, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk))) if errno == 0 { diff --git a/contrib/go/_std_1.22/src/syscall/flock_linux_32bit.go b/contrib/go/_std_1.23/src/syscall/flock_linux_32bit.go similarity index 82% rename from contrib/go/_std_1.22/src/syscall/flock_linux_32bit.go rename to contrib/go/_std_1.23/src/syscall/flock_linux_32bit.go index 76a09fc47e3f..927c4dfffde8 100644 --- a/contrib/go/_std_1.22/src/syscall/flock_linux_32bit.go +++ b/contrib/go/_std_1.23/src/syscall/flock_linux_32bit.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// If you change the build tags here, see -// internal/syscall/unix/fcntl_linux_32bit.go. - //go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) package syscall diff --git a/contrib/go/_std_1.22/src/syscall/forkpipe.go b/contrib/go/_std_1.23/src/syscall/forkpipe.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/forkpipe.go rename to contrib/go/_std_1.23/src/syscall/forkpipe.go diff --git a/contrib/go/_std_1.22/src/syscall/forkpipe2.go b/contrib/go/_std_1.23/src/syscall/forkpipe2.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/forkpipe2.go rename to contrib/go/_std_1.23/src/syscall/forkpipe2.go diff --git a/contrib/go/_std_1.22/src/syscall/fs_js.go b/contrib/go/_std_1.23/src/syscall/fs_js.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/fs_js.go rename to contrib/go/_std_1.23/src/syscall/fs_js.go diff --git a/contrib/go/_std_1.22/src/syscall/fs_wasip1.go b/contrib/go/_std_1.23/src/syscall/fs_wasip1.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/fs_wasip1.go rename to contrib/go/_std_1.23/src/syscall/fs_wasip1.go index 4ad3f9610bcc..fc361ee89897 100644 --- a/contrib/go/_std_1.22/src/syscall/fs_wasip1.go +++ b/contrib/go/_std_1.23/src/syscall/fs_wasip1.go @@ -7,6 +7,7 @@ package syscall import ( + "internal/stringslite" "runtime" "unsafe" ) @@ -287,12 +288,18 @@ func fd_fdstat_get(fd int32, buf unsafe.Pointer) Errno //go:noescape func fd_fdstat_set_flags(fd int32, flags fdflags) Errno +// fd_fdstat_get_flags is accessed from internal/syscall/unix +//go:linkname fd_fdstat_get_flags + func fd_fdstat_get_flags(fd int) (uint32, error) { var stat fdstat errno := fd_fdstat_get(int32(fd), unsafe.Pointer(&stat)) return uint32(stat.fdflags), errnoErr(errno) } +// fd_fdstat_get_type is accessed from net +//go:linkname fd_fdstat_get_type + func fd_fdstat_get_type(fd int) (uint8, error) { var stat fdstat errno := fd_fdstat_get(int32(fd), unsafe.Pointer(&stat)) @@ -468,19 +475,11 @@ func joinPath(dir, file string) string { } func isAbs(path string) bool { - return hasPrefix(path, "/") + return stringslite.HasPrefix(path, "/") } func isDir(path string) bool { - return hasSuffix(path, "/") -} - -func hasPrefix(s, p string) bool { - return len(s) >= len(p) && s[:len(p)] == p -} - -func hasSuffix(s, x string) bool { - return len(s) >= len(x) && s[len(s)-len(x):] == x + return stringslite.HasSuffix(path, "/") } // preparePath returns the preopen file descriptor of the directory to perform @@ -500,7 +499,7 @@ func preparePath(path string) (int32, unsafe.Pointer, size) { path = joinPath(dir, path) for _, p := range preopens { - if len(p.name) > len(dirName) && hasPrefix(path, p.name) { + if len(p.name) > len(dirName) && stringslite.HasPrefix(path, p.name) { dirFd, dirName = p.fd, p.name } } @@ -566,7 +565,7 @@ func Open(path string, openmode int, perm uint32) (int, error) { if errno == EISDIR && oflags == 0 && fdflags == 0 && ((rights & writeRights) == 0) { // wasmtime and wasmedge will error if attempting to open a directory // because we are asking for too many rights. However, we cannot - // determine ahread of time if the path we are about to open is a + // determine ahead of time if the path we are about to open is a // directory, so instead we fallback to a second call to path_open with // a more limited set of rights. // diff --git a/contrib/go/_std_1.22/src/syscall/js/func.go b/contrib/go/_std_1.23/src/syscall/js/func.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/js/func.go rename to contrib/go/_std_1.23/src/syscall/js/func.go diff --git a/contrib/go/_std_1.23/src/syscall/js/js.go b/contrib/go/_std_1.23/src/syscall/js/js.go new file mode 100644 index 000000000000..74c02cdbe64a --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/js/js.go @@ -0,0 +1,687 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build js && wasm + +// Package js gives access to the WebAssembly host environment when using the js/wasm architecture. +// Its API is based on JavaScript semantics. +// +// This package is EXPERIMENTAL. Its current scope is only to allow tests to run, but not yet to provide a +// comprehensive API for users. It is exempt from the Go compatibility promise. +package js + +import ( + "runtime" + "unsafe" +) + +// ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly. +// +// The JavaScript value "undefined" is represented by the value 0. +// A JavaScript number (64-bit float, except 0 and NaN) is represented by its IEEE 754 binary representation. +// All other values are represented as an IEEE 754 binary representation of NaN with bits 0-31 used as +// an ID and bits 32-34 used to differentiate between string, symbol, function and object. +type ref uint64 + +// nanHead are the upper 32 bits of a ref which are set if the value is not encoded as an IEEE 754 number (see above). +const nanHead = 0x7FF80000 + +// Value represents a JavaScript value. The zero value is the JavaScript value "undefined". +// Values can be checked for equality with the Equal method. +type Value struct { + _ [0]func() // uncomparable; to make == not compile + ref ref // identifies a JavaScript value, see ref type + gcPtr *ref // used to trigger the finalizer when the Value is not referenced any more +} + +const ( + // the type flags need to be in sync with wasm_exec.js + typeFlagNone = iota + typeFlagObject + typeFlagString + typeFlagSymbol + typeFlagFunction +) + +func makeValue(r ref) Value { + var gcPtr *ref + typeFlag := (r >> 32) & 7 + if (r>>32)&nanHead == nanHead && typeFlag != typeFlagNone { + gcPtr = new(ref) + *gcPtr = r + runtime.SetFinalizer(gcPtr, func(p *ref) { + finalizeRef(*p) + }) + } + + return Value{ref: r, gcPtr: gcPtr} +} + +//go:wasmimport gojs syscall/js.finalizeRef +func finalizeRef(r ref) + +func predefValue(id uint32, typeFlag byte) Value { + return Value{ref: (nanHead|ref(typeFlag))<<32 | ref(id)} +} + +func floatValue(f float64) Value { + if f == 0 { + return valueZero + } + if f != f { + return valueNaN + } + return Value{ref: *(*ref)(unsafe.Pointer(&f))} +} + +// Error wraps a JavaScript error. +type Error struct { + // Value is the underlying JavaScript error value. + Value +} + +// Error implements the error interface. +func (e Error) Error() string { + return "JavaScript error: " + e.Get("message").String() +} + +var ( + valueUndefined = Value{ref: 0} + valueNaN = predefValue(0, typeFlagNone) + valueZero = predefValue(1, typeFlagNone) + valueNull = predefValue(2, typeFlagNone) + valueTrue = predefValue(3, typeFlagNone) + valueFalse = predefValue(4, typeFlagNone) + valueGlobal = predefValue(5, typeFlagObject) + jsGo = predefValue(6, typeFlagObject) // instance of the Go class in JavaScript + + objectConstructor = valueGlobal.Get("Object") + arrayConstructor = valueGlobal.Get("Array") +) + +// Equal reports whether v and w are equal according to JavaScript's === operator. +func (v Value) Equal(w Value) bool { + return v.ref == w.ref && v.ref != valueNaN.ref +} + +// Undefined returns the JavaScript value "undefined". +func Undefined() Value { + return valueUndefined +} + +// IsUndefined reports whether v is the JavaScript value "undefined". +func (v Value) IsUndefined() bool { + return v.ref == valueUndefined.ref +} + +// Null returns the JavaScript value "null". +func Null() Value { + return valueNull +} + +// IsNull reports whether v is the JavaScript value "null". +func (v Value) IsNull() bool { + return v.ref == valueNull.ref +} + +// IsNaN reports whether v is the JavaScript value "NaN". +func (v Value) IsNaN() bool { + return v.ref == valueNaN.ref +} + +// Global returns the JavaScript global object, usually "window" or "global". +func Global() Value { + return valueGlobal +} + +// ValueOf returns x as a JavaScript value: +// +// | Go | JavaScript | +// | ---------------------- | ---------------------- | +// | js.Value | [its value] | +// | js.Func | function | +// | nil | null | +// | bool | boolean | +// | integers and floats | number | +// | string | string | +// | []interface{} | new array | +// | map[string]interface{} | new object | +// +// Panics if x is not one of the expected types. +func ValueOf(x any) Value { + switch x := x.(type) { + case Value: + return x + case Func: + return x.Value + case nil: + return valueNull + case bool: + if x { + return valueTrue + } else { + return valueFalse + } + case int: + return floatValue(float64(x)) + case int8: + return floatValue(float64(x)) + case int16: + return floatValue(float64(x)) + case int32: + return floatValue(float64(x)) + case int64: + return floatValue(float64(x)) + case uint: + return floatValue(float64(x)) + case uint8: + return floatValue(float64(x)) + case uint16: + return floatValue(float64(x)) + case uint32: + return floatValue(float64(x)) + case uint64: + return floatValue(float64(x)) + case uintptr: + return floatValue(float64(x)) + case unsafe.Pointer: + return floatValue(float64(uintptr(x))) + case float32: + return floatValue(float64(x)) + case float64: + return floatValue(x) + case string: + return makeValue(stringVal(x)) + case []any: + a := arrayConstructor.New(len(x)) + for i, s := range x { + a.SetIndex(i, s) + } + return a + case map[string]any: + o := objectConstructor.New() + for k, v := range x { + o.Set(k, v) + } + return o + default: + panic("ValueOf: invalid value") + } +} + +// stringVal copies string x to Javascript and returns a ref. +// +// (noescape): This is safe because no references are maintained to the +// Go string x after the syscall returns. +// +//go:wasmimport gojs syscall/js.stringVal +//go:noescape +func stringVal(x string) ref + +// Type represents the JavaScript type of a Value. +type Type int + +const ( + TypeUndefined Type = iota + TypeNull + TypeBoolean + TypeNumber + TypeString + TypeSymbol + TypeObject + TypeFunction +) + +func (t Type) String() string { + switch t { + case TypeUndefined: + return "undefined" + case TypeNull: + return "null" + case TypeBoolean: + return "boolean" + case TypeNumber: + return "number" + case TypeString: + return "string" + case TypeSymbol: + return "symbol" + case TypeObject: + return "object" + case TypeFunction: + return "function" + default: + panic("bad type") + } +} + +func (t Type) isObject() bool { + return t == TypeObject || t == TypeFunction +} + +// Type returns the JavaScript type of the value v. It is similar to JavaScript's typeof operator, +// except that it returns TypeNull instead of TypeObject for null. +func (v Value) Type() Type { + switch v.ref { + case valueUndefined.ref: + return TypeUndefined + case valueNull.ref: + return TypeNull + case valueTrue.ref, valueFalse.ref: + return TypeBoolean + } + if v.isNumber() { + return TypeNumber + } + typeFlag := (v.ref >> 32) & 7 + switch typeFlag { + case typeFlagObject: + return TypeObject + case typeFlagString: + return TypeString + case typeFlagSymbol: + return TypeSymbol + case typeFlagFunction: + return TypeFunction + default: + panic("bad type flag") + } +} + +// Get returns the JavaScript property p of value v. +// It panics if v is not a JavaScript object. +func (v Value) Get(p string) Value { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.Get", vType}) + } + r := makeValue(valueGet(v.ref, p)) + runtime.KeepAlive(v) + return r +} + +// valueGet returns a ref to JavaScript property p of ref v. +// +// (noescape): This is safe because no references are maintained to the +// Go string p after the syscall returns. +// +//go:wasmimport gojs syscall/js.valueGet +//go:noescape +func valueGet(v ref, p string) ref + +// Set sets the JavaScript property p of value v to ValueOf(x). +// It panics if v is not a JavaScript object. +func (v Value) Set(p string, x any) { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.Set", vType}) + } + xv := ValueOf(x) + valueSet(v.ref, p, xv.ref) + runtime.KeepAlive(v) + runtime.KeepAlive(xv) +} + +// valueSet sets property p of ref v to ref x. +// +// (noescape): This is safe because no references are maintained to the +// Go string p after the syscall returns. +// +//go:wasmimport gojs syscall/js.valueSet +//go:noescape +func valueSet(v ref, p string, x ref) + +// Delete deletes the JavaScript property p of value v. +// It panics if v is not a JavaScript object. +func (v Value) Delete(p string) { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.Delete", vType}) + } + valueDelete(v.ref, p) + runtime.KeepAlive(v) +} + +// valueDelete deletes the JavaScript property p of ref v. +// +// (noescape): This is safe because no references are maintained to the +// Go string p after the syscall returns. +// +//go:wasmimport gojs syscall/js.valueDelete +//go:noescape +func valueDelete(v ref, p string) + +// Index returns JavaScript index i of value v. +// It panics if v is not a JavaScript object. +func (v Value) Index(i int) Value { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.Index", vType}) + } + r := makeValue(valueIndex(v.ref, i)) + runtime.KeepAlive(v) + return r +} + +//go:wasmimport gojs syscall/js.valueIndex +func valueIndex(v ref, i int) ref + +// SetIndex sets the JavaScript index i of value v to ValueOf(x). +// It panics if v is not a JavaScript object. +func (v Value) SetIndex(i int, x any) { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.SetIndex", vType}) + } + xv := ValueOf(x) + valueSetIndex(v.ref, i, xv.ref) + runtime.KeepAlive(v) + runtime.KeepAlive(xv) +} + +//go:wasmimport gojs syscall/js.valueSetIndex +func valueSetIndex(v ref, i int, x ref) + +// makeArgSlices makes two slices to hold JavaScript arg data. +// It can be paired with storeArgs to make-and-store JavaScript arg slices. +// However, the two functions are separated to ensure makeArgSlices is inlined +// which will prevent the slices from being heap allocated for small (<=16) +// numbers of args. +func makeArgSlices(size int) (argVals []Value, argRefs []ref) { + // value chosen for being power of two, and enough to handle all web APIs + // in particular, note that WebGL2's texImage2D takes up to 10 arguments + const maxStackArgs = 16 + if size <= maxStackArgs { + // as long as makeArgs is inlined, these will be stack-allocated + argVals = make([]Value, size, maxStackArgs) + argRefs = make([]ref, size, maxStackArgs) + } else { + // allocates on the heap, but exceeding maxStackArgs should be rare + argVals = make([]Value, size) + argRefs = make([]ref, size) + } + return +} + +// storeArgs maps input args onto respective Value and ref slices. +// It can be paired with makeArgSlices to make-and-store JavaScript arg slices. +func storeArgs(args []any, argValsDst []Value, argRefsDst []ref) { + // would go in makeArgs if the combined func was simple enough to inline + for i, arg := range args { + v := ValueOf(arg) + argValsDst[i] = v + argRefsDst[i] = v.ref + } +} + +// Length returns the JavaScript property "length" of v. +// It panics if v is not a JavaScript object. +func (v Value) Length() int { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.SetIndex", vType}) + } + r := valueLength(v.ref) + runtime.KeepAlive(v) + return r +} + +//go:wasmimport gojs syscall/js.valueLength +func valueLength(v ref) int + +// Call does a JavaScript call to the method m of value v with the given arguments. +// It panics if v has no method m. +// The arguments get mapped to JavaScript values according to the ValueOf function. +func (v Value) Call(m string, args ...any) Value { + argVals, argRefs := makeArgSlices(len(args)) + storeArgs(args, argVals, argRefs) + res, ok := valueCall(v.ref, m, argRefs) + runtime.KeepAlive(v) + runtime.KeepAlive(argVals) + if !ok { + if vType := v.Type(); !vType.isObject() { // check here to avoid overhead in success case + panic(&ValueError{"Value.Call", vType}) + } + if propType := v.Get(m).Type(); propType != TypeFunction { + panic("syscall/js: Value.Call: property " + m + " is not a function, got " + propType.String()) + } + panic(Error{makeValue(res)}) + } + return makeValue(res) +} + +// valueCall does a JavaScript call to the method name m of ref v with the given arguments. +// +// (noescape): This is safe because no references are maintained to the +// Go string m after the syscall returns. Additionally, the args slice +// is only used temporarily to collect the JavaScript objects for +// the JavaScript method invocation. +// +//go:wasmimport gojs syscall/js.valueCall +//go:nosplit +//go:noescape +func valueCall(v ref, m string, args []ref) (ref, bool) + +// Invoke does a JavaScript call of the value v with the given arguments. +// It panics if v is not a JavaScript function. +// The arguments get mapped to JavaScript values according to the ValueOf function. +func (v Value) Invoke(args ...any) Value { + argVals, argRefs := makeArgSlices(len(args)) + storeArgs(args, argVals, argRefs) + res, ok := valueInvoke(v.ref, argRefs) + runtime.KeepAlive(v) + runtime.KeepAlive(argVals) + if !ok { + if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case + panic(&ValueError{"Value.Invoke", vType}) + } + panic(Error{makeValue(res)}) + } + return makeValue(res) +} + +// valueInvoke does a JavaScript call to value v with the given arguments. +// +// (noescape): This is safe because the args slice is only used temporarily +// to collect the JavaScript objects for the JavaScript method +// invocation. +// +//go:wasmimport gojs syscall/js.valueInvoke +//go:noescape +func valueInvoke(v ref, args []ref) (ref, bool) + +// New uses JavaScript's "new" operator with value v as constructor and the given arguments. +// It panics if v is not a JavaScript function. +// The arguments get mapped to JavaScript values according to the ValueOf function. +func (v Value) New(args ...any) Value { + argVals, argRefs := makeArgSlices(len(args)) + storeArgs(args, argVals, argRefs) + res, ok := valueNew(v.ref, argRefs) + runtime.KeepAlive(v) + runtime.KeepAlive(argVals) + if !ok { + if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case + panic(&ValueError{"Value.Invoke", vType}) + } + panic(Error{makeValue(res)}) + } + return makeValue(res) +} + +// valueNew uses JavaScript's "new" operator with value v as a constructor and the given arguments. +// +// (noescape): This is safe because the args slice is only used temporarily +// to collect the JavaScript objects for the constructor execution. +// +//go:wasmimport gojs syscall/js.valueNew +//go:noescape +func valueNew(v ref, args []ref) (ref, bool) + +func (v Value) isNumber() bool { + return v.ref == valueZero.ref || + v.ref == valueNaN.ref || + (v.ref != valueUndefined.ref && (v.ref>>32)&nanHead != nanHead) +} + +func (v Value) float(method string) float64 { + if !v.isNumber() { + panic(&ValueError{method, v.Type()}) + } + if v.ref == valueZero.ref { + return 0 + } + return *(*float64)(unsafe.Pointer(&v.ref)) +} + +// Float returns the value v as a float64. +// It panics if v is not a JavaScript number. +func (v Value) Float() float64 { + return v.float("Value.Float") +} + +// Int returns the value v truncated to an int. +// It panics if v is not a JavaScript number. +func (v Value) Int() int { + return int(v.float("Value.Int")) +} + +// Bool returns the value v as a bool. +// It panics if v is not a JavaScript boolean. +func (v Value) Bool() bool { + switch v.ref { + case valueTrue.ref: + return true + case valueFalse.ref: + return false + default: + panic(&ValueError{"Value.Bool", v.Type()}) + } +} + +// Truthy returns the JavaScript "truthiness" of the value v. In JavaScript, +// false, 0, "", null, undefined, and NaN are "falsy", and everything else is +// "truthy". See https://developer.mozilla.org/en-US/docs/Glossary/Truthy. +func (v Value) Truthy() bool { + switch v.Type() { + case TypeUndefined, TypeNull: + return false + case TypeBoolean: + return v.Bool() + case TypeNumber: + return v.ref != valueNaN.ref && v.ref != valueZero.ref + case TypeString: + return v.String() != "" + case TypeSymbol, TypeFunction, TypeObject: + return true + default: + panic("bad type") + } +} + +// String returns the value v as a string. +// String is a special case because of Go's String method convention. Unlike the other getters, +// it does not panic if v's Type is not TypeString. Instead, it returns a string of the form "" +// or "" where T is v's type and V is a string representation of v's value. +func (v Value) String() string { + switch v.Type() { + case TypeString: + return jsString(v) + case TypeUndefined: + return "" + case TypeNull: + return "" + case TypeBoolean: + return "" + case TypeNumber: + return "" + case TypeSymbol: + return "" + case TypeObject: + return "" + case TypeFunction: + return "" + default: + panic("bad type") + } +} + +func jsString(v Value) string { + str, length := valuePrepareString(v.ref) + runtime.KeepAlive(v) + b := make([]byte, length) + valueLoadString(str, b) + finalizeRef(str) + return string(b) +} + +//go:wasmimport gojs syscall/js.valuePrepareString +func valuePrepareString(v ref) (ref, int) + +// valueLoadString loads string data located at ref v into byte slice b. +// +// (noescape): This is safe because the byte slice is only used as a destination +// for storing the string data and references to it are not maintained. +// +//go:wasmimport gojs syscall/js.valueLoadString +//go:noescape +func valueLoadString(v ref, b []byte) + +// InstanceOf reports whether v is an instance of type t according to JavaScript's instanceof operator. +func (v Value) InstanceOf(t Value) bool { + r := valueInstanceOf(v.ref, t.ref) + runtime.KeepAlive(v) + runtime.KeepAlive(t) + return r +} + +//go:wasmimport gojs syscall/js.valueInstanceOf +func valueInstanceOf(v ref, t ref) bool + +// A ValueError occurs when a Value method is invoked on +// a Value that does not support it. Such cases are documented +// in the description of each method. +type ValueError struct { + Method string + Type Type +} + +func (e *ValueError) Error() string { + return "syscall/js: call of " + e.Method + " on " + e.Type.String() +} + +// CopyBytesToGo copies bytes from src to dst. +// It panics if src is not a Uint8Array or Uint8ClampedArray. +// It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. +func CopyBytesToGo(dst []byte, src Value) int { + n, ok := copyBytesToGo(dst, src.ref) + runtime.KeepAlive(src) + if !ok { + panic("syscall/js: CopyBytesToGo: expected src to be a Uint8Array or Uint8ClampedArray") + } + return n +} + +// copyBytesToGo copies bytes from src to dst. +// +// (noescape): This is safe because the dst byte slice is only used as a dst +// copy buffer and no references to it are maintained. +// +//go:wasmimport gojs syscall/js.copyBytesToGo +//go:noescape +func copyBytesToGo(dst []byte, src ref) (int, bool) + +// CopyBytesToJS copies bytes from src to dst. +// It panics if dst is not a Uint8Array or Uint8ClampedArray. +// It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. +func CopyBytesToJS(dst Value, src []byte) int { + n, ok := copyBytesToJS(dst.ref, src) + runtime.KeepAlive(dst) + if !ok { + panic("syscall/js: CopyBytesToJS: expected dst to be a Uint8Array or Uint8ClampedArray") + } + return n +} + +// copyBytesToJs copies bytes from src to dst. +// +// (noescape): This is safe because the src byte slice is only used as a src +// copy buffer and no references to it are maintained. +// +//go:wasmimport gojs syscall/js.copyBytesToJS +//go:noescape +func copyBytesToJS(dst ref, src []byte) (int, bool) diff --git a/contrib/go/_std_1.22/src/syscall/js/js_js.s b/contrib/go/_std_1.23/src/syscall/js/js_js.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/js/js_js.s rename to contrib/go/_std_1.23/src/syscall/js/js_js.s diff --git a/contrib/go/_std_1.22/src/syscall/js/ya.make b/contrib/go/_std_1.23/src/syscall/js/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/syscall/js/ya.make rename to contrib/go/_std_1.23/src/syscall/js/ya.make diff --git a/contrib/go/_std_1.23/src/syscall/linkname_bsd.go b/contrib/go/_std_1.23/src/syscall/linkname_bsd.go new file mode 100644 index 000000000000..c3c6a5842028 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_bsd.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd || netbsd || openbsd + +package syscall + +import _ "unsafe" + +// used by internal/syscall/unix +//go:linkname ioctlPtr + +// golang.org/x/net linknames sysctl. +// Do not remove or change the type signature. +// +//go:linkname sysctl diff --git a/contrib/go/_std_1.23/src/syscall/linkname_darwin.go b/contrib/go/_std_1.23/src/syscall/linkname_darwin.go new file mode 100644 index 000000000000..2ed83a4fad2a --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_darwin.go @@ -0,0 +1,23 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +import _ "unsafe" + +// used by os +//go:linkname closedir +//go:linkname readdir_r + +// used by internal/poll +//go:linkname fdopendir + +// used by internal/syscall/unix +//go:linkname unlinkat +//go:linkname openat +//go:linkname fstatat + +// used by cmd/link +//go:linkname msync +//go:linkname fcntl diff --git a/contrib/go/_std_1.23/src/syscall/linkname_libc.go b/contrib/go/_std_1.23/src/syscall/linkname_libc.go new file mode 100644 index 000000000000..1e7b4880d6ed --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_libc.go @@ -0,0 +1,12 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix || darwin || (openbsd && !mips64) || solaris + +package syscall + +import _ "unsafe" + +// used by internal/poll +//go:linkname writev diff --git a/contrib/go/_std_1.23/src/syscall/linkname_openbsd.go b/contrib/go/_std_1.23/src/syscall/linkname_openbsd.go new file mode 100644 index 000000000000..5f5c517ab585 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_openbsd.go @@ -0,0 +1,15 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build openbsd && !mips64 + +package syscall + +import _ "unsafe" + +// used by internal/syscall/unix +//go:linkname unlinkat +//go:linkname openat +//go:linkname fstatat +//go:linkname getentropy diff --git a/contrib/go/_std_1.23/src/syscall/linkname_unix.go b/contrib/go/_std_1.23/src/syscall/linkname_unix.go new file mode 100644 index 000000000000..c4d187c01f20 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_unix.go @@ -0,0 +1,20 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package syscall + +import _ "unsafe" // for linkname + +// mmap should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - modernc.org/memory +// - github.com/ncruces/go-sqlite3 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mmap diff --git a/contrib/go/_std_1.22/src/syscall/lsf_linux.go b/contrib/go/_std_1.23/src/syscall/lsf_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/lsf_linux.go rename to contrib/go/_std_1.23/src/syscall/lsf_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/mkasm.go b/contrib/go/_std_1.23/src/syscall/mkasm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mkasm.go rename to contrib/go/_std_1.23/src/syscall/mkasm.go diff --git a/contrib/go/_std_1.22/src/syscall/mkpost.go b/contrib/go/_std_1.23/src/syscall/mkpost.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mkpost.go rename to contrib/go/_std_1.23/src/syscall/mkpost.go diff --git a/contrib/go/_std_1.22/src/syscall/mksyscall.pl b/contrib/go/_std_1.23/src/syscall/mksyscall.pl similarity index 98% rename from contrib/go/_std_1.22/src/syscall/mksyscall.pl rename to contrib/go/_std_1.23/src/syscall/mksyscall.pl index 47efbffcbcb1..b46a3f9438bd 100755 --- a/contrib/go/_std_1.22/src/syscall/mksyscall.pl +++ b/contrib/go/_std_1.23/src/syscall/mksyscall.pl @@ -33,6 +33,7 @@ my $libc = 0; my $tags = ""; # build tags my $newtags = ""; # new style build tags +my $stdimports = 'import "unsafe"'; my $extraimports = ""; if($ARGV[0] eq "-b32") { @@ -390,6 +391,10 @@ ($) exit 1; } +if($extraimports ne "") { + $stdimports .= "\n$extraimports"; +} + # TODO: this assumes tags are just simply comma separated. For now this is all the uses. $newtags = $tags =~ s/,/ && /r; @@ -401,8 +406,7 @@ ($) package syscall -import "unsafe" -$extraimports +$stdimports $text EOF diff --git a/contrib/go/_std_1.22/src/syscall/mksyscall_libc.pl b/contrib/go/_std_1.23/src/syscall/mksyscall_libc.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksyscall_libc.pl rename to contrib/go/_std_1.23/src/syscall/mksyscall_libc.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksyscall_windows.go b/contrib/go/_std_1.23/src/syscall/mksyscall_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksyscall_windows.go rename to contrib/go/_std_1.23/src/syscall/mksyscall_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/mksysctl_openbsd.pl b/contrib/go/_std_1.23/src/syscall/mksysctl_openbsd.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysctl_openbsd.pl rename to contrib/go/_std_1.23/src/syscall/mksysctl_openbsd.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_dragonfly.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_dragonfly.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_dragonfly.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_dragonfly.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_freebsd.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_freebsd.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_freebsd.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_freebsd.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_linux.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_linux.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_linux.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_linux.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_netbsd.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_netbsd.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_netbsd.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_netbsd.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_openbsd.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_openbsd.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_openbsd.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_openbsd.pl diff --git a/contrib/go/_std_1.22/src/syscall/net.go b/contrib/go/_std_1.23/src/syscall/net.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/net.go rename to contrib/go/_std_1.23/src/syscall/net.go diff --git a/contrib/go/_std_1.22/src/syscall/net_fake.go b/contrib/go/_std_1.23/src/syscall/net_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/net_fake.go rename to contrib/go/_std_1.23/src/syscall/net_fake.go diff --git a/contrib/go/_std_1.22/src/syscall/net_js.go b/contrib/go/_std_1.23/src/syscall/net_js.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/net_js.go rename to contrib/go/_std_1.23/src/syscall/net_js.go diff --git a/contrib/go/_std_1.22/src/syscall/net_wasip1.go b/contrib/go/_std_1.23/src/syscall/net_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/net_wasip1.go rename to contrib/go/_std_1.23/src/syscall/net_wasip1.go diff --git a/contrib/go/_std_1.22/src/syscall/netlink_linux.go b/contrib/go/_std_1.23/src/syscall/netlink_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/netlink_linux.go rename to contrib/go/_std_1.23/src/syscall/netlink_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/os_wasip1.go b/contrib/go/_std_1.23/src/syscall/os_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/os_wasip1.go rename to contrib/go/_std_1.23/src/syscall/os_wasip1.go diff --git a/contrib/go/_std_1.22/src/syscall/pwd_plan9.go b/contrib/go/_std_1.23/src/syscall/pwd_plan9.go similarity index 96% rename from contrib/go/_std_1.22/src/syscall/pwd_plan9.go rename to contrib/go/_std_1.23/src/syscall/pwd_plan9.go index 28e99565eed6..b81018873f9c 100644 --- a/contrib/go/_std_1.22/src/syscall/pwd_plan9.go +++ b/contrib/go/_std_1.23/src/syscall/pwd_plan9.go @@ -23,7 +23,7 @@ var ( ) // Ensure current working directory seen by this goroutine matches -// the most recent Chdir called in any goroutine. It's called internally +// the most recent [Chdir] called in any goroutine. It's called internally // before executing any syscall which uses a relative pathname. Must // be called with the goroutine locked to the OS thread, to prevent // rescheduling on a different thread (potentially with a different diff --git a/contrib/go/_std_1.22/src/syscall/rlimit.go b/contrib/go/_std_1.23/src/syscall/rlimit.go similarity index 94% rename from contrib/go/_std_1.22/src/syscall/rlimit.go rename to contrib/go/_std_1.23/src/syscall/rlimit.go index d77341bde9a5..8184f17ab68f 100644 --- a/contrib/go/_std_1.22/src/syscall/rlimit.go +++ b/contrib/go/_std_1.23/src/syscall/rlimit.go @@ -39,11 +39,10 @@ func init() { } func Setrlimit(resource int, rlim *Rlimit) error { - err := setrlimit(resource, rlim) - if err == nil && resource == RLIMIT_NOFILE { + if resource == RLIMIT_NOFILE { // Store nil in origRlimitNofile to tell StartProcess // to not adjust the rlimit in the child process. origRlimitNofile.Store(nil) } - return err + return setrlimit(resource, rlim) } diff --git a/contrib/go/_std_1.22/src/syscall/rlimit_darwin.go b/contrib/go/_std_1.23/src/syscall/rlimit_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/rlimit_darwin.go rename to contrib/go/_std_1.23/src/syscall/rlimit_darwin.go diff --git a/contrib/go/_std_1.22/src/syscall/rlimit_stub.go b/contrib/go/_std_1.23/src/syscall/rlimit_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/rlimit_stub.go rename to contrib/go/_std_1.23/src/syscall/rlimit_stub.go diff --git a/contrib/go/_std_1.22/src/syscall/route_bsd.go b/contrib/go/_std_1.23/src/syscall/route_bsd.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/route_bsd.go rename to contrib/go/_std_1.23/src/syscall/route_bsd.go index 8e47ff888e93..46680d645a6c 100644 --- a/contrib/go/_std_1.22/src/syscall/route_bsd.go +++ b/contrib/go/_std_1.23/src/syscall/route_bsd.go @@ -325,7 +325,7 @@ func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) { } // ParseRoutingMessage parses b as routing messages and returns the -// slice containing the RoutingMessage interfaces. +// slice containing the [RoutingMessage] interfaces. // // Deprecated: Use golang.org/x/net/route instead. func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { @@ -352,7 +352,7 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { } // ParseRoutingSockaddr parses msg's payload as raw sockaddrs and -// returns the slice containing the Sockaddr interfaces. +// returns the slice containing the [Sockaddr] interfaces. // // Deprecated: Use golang.org/x/net/route instead. func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { diff --git a/contrib/go/_std_1.22/src/syscall/route_darwin.go b/contrib/go/_std_1.23/src/syscall/route_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_darwin.go rename to contrib/go/_std_1.23/src/syscall/route_darwin.go diff --git a/contrib/go/_std_1.22/src/syscall/route_dragonfly.go b/contrib/go/_std_1.23/src/syscall/route_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_dragonfly.go rename to contrib/go/_std_1.23/src/syscall/route_dragonfly.go diff --git a/contrib/go/_std_1.22/src/syscall/route_freebsd.go b/contrib/go/_std_1.23/src/syscall/route_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_freebsd.go rename to contrib/go/_std_1.23/src/syscall/route_freebsd.go diff --git a/contrib/go/_std_1.22/src/syscall/route_freebsd_32bit.go b/contrib/go/_std_1.23/src/syscall/route_freebsd_32bit.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_freebsd_32bit.go rename to contrib/go/_std_1.23/src/syscall/route_freebsd_32bit.go diff --git a/contrib/go/_std_1.22/src/syscall/route_freebsd_64bit.go b/contrib/go/_std_1.23/src/syscall/route_freebsd_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_freebsd_64bit.go rename to contrib/go/_std_1.23/src/syscall/route_freebsd_64bit.go diff --git a/contrib/go/_std_1.22/src/syscall/route_netbsd.go b/contrib/go/_std_1.23/src/syscall/route_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_netbsd.go rename to contrib/go/_std_1.23/src/syscall/route_netbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/route_openbsd.go b/contrib/go/_std_1.23/src/syscall/route_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_openbsd.go rename to contrib/go/_std_1.23/src/syscall/route_openbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/security_windows.go b/contrib/go/_std_1.23/src/syscall/security_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/security_windows.go rename to contrib/go/_std_1.23/src/syscall/security_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/setuidgid_32_linux.go b/contrib/go/_std_1.23/src/syscall/setuidgid_32_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/setuidgid_32_linux.go rename to contrib/go/_std_1.23/src/syscall/setuidgid_32_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/setuidgid_linux.go b/contrib/go/_std_1.23/src/syscall/setuidgid_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/setuidgid_linux.go rename to contrib/go/_std_1.23/src/syscall/setuidgid_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/sockcmsg_dragonfly.go b/contrib/go/_std_1.23/src/syscall/sockcmsg_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/sockcmsg_dragonfly.go rename to contrib/go/_std_1.23/src/syscall/sockcmsg_dragonfly.go diff --git a/contrib/go/_std_1.22/src/syscall/sockcmsg_linux.go b/contrib/go/_std_1.23/src/syscall/sockcmsg_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/sockcmsg_linux.go rename to contrib/go/_std_1.23/src/syscall/sockcmsg_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/sockcmsg_unix.go b/contrib/go/_std_1.23/src/syscall/sockcmsg_unix.go similarity index 97% rename from contrib/go/_std_1.22/src/syscall/sockcmsg_unix.go rename to contrib/go/_std_1.23/src/syscall/sockcmsg_unix.go index 6ade73e87e0f..a4b45739b89d 100644 --- a/contrib/go/_std_1.22/src/syscall/sockcmsg_unix.go +++ b/contrib/go/_std_1.23/src/syscall/sockcmsg_unix.go @@ -12,7 +12,7 @@ import ( "unsafe" ) -// CmsgLen returns the value to store in the Len field of the Cmsghdr +// CmsgLen returns the value to store in the Len field of the [Cmsghdr] // structure, taking into account any necessary alignment. func CmsgLen(datalen int) int { return cmsgAlignOf(SizeofCmsghdr) + datalen diff --git a/contrib/go/_std_1.22/src/syscall/sockcmsg_unix_other.go b/contrib/go/_std_1.23/src/syscall/sockcmsg_unix_other.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/sockcmsg_unix_other.go rename to contrib/go/_std_1.23/src/syscall/sockcmsg_unix_other.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall.go b/contrib/go/_std_1.23/src/syscall/syscall.go similarity index 95% rename from contrib/go/_std_1.22/src/syscall/syscall.go rename to contrib/go/_std_1.23/src/syscall/syscall.go index f75ba31f5fb3..a46f22ddb53c 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall.go +++ b/contrib/go/_std_1.23/src/syscall/syscall.go @@ -16,7 +16,7 @@ // the manuals for the appropriate operating system. // These calls return err == nil to indicate success; otherwise // err is an operating system error describing the failure. -// On most systems, that error has type syscall.Errno. +// On most systems, that error has type [Errno]. // // NOTE: Most of the functions, types, and constants defined in // this package are also available in the [golang.org/x/sys] package. @@ -44,7 +44,7 @@ func StringByteSlice(s string) []byte { // ByteSliceFromString returns a NUL-terminated slice of bytes // containing the text of s. If s contains a NUL byte at any -// location, it returns (nil, EINVAL). +// location, it returns (nil, [EINVAL]). func ByteSliceFromString(s string) ([]byte, error) { if bytealg.IndexByteString(s, 0) != -1 { return nil, EINVAL @@ -58,12 +58,12 @@ func ByteSliceFromString(s string) ([]byte, error) { // If s contains a NUL byte this function panics instead of returning // an error. // -// Deprecated: Use BytePtrFromString instead. +// Deprecated: Use [BytePtrFromString] instead. func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] } // BytePtrFromString returns a pointer to a NUL-terminated array of // bytes containing the text of s. If s contains a NUL byte at any -// location, it returns (nil, EINVAL). +// location, it returns (nil, [EINVAL]). func BytePtrFromString(s string) (*byte, error) { a, err := ByteSliceFromString(s) if err != nil { diff --git a/contrib/go/_std_1.22/src/syscall/syscall_aix.go b/contrib/go/_std_1.23/src/syscall/syscall_aix.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/syscall_aix.go rename to contrib/go/_std_1.23/src/syscall/syscall_aix.go index 30e6887cce5f..a9bd7a37336d 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_aix.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_aix.go @@ -222,7 +222,7 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, var status _C_int var r _Pid_t err = ERESTART - // AIX wait4 may return with ERESTART errno, while the processus is still + // AIX wait4 may return with ERESTART errno, while the process is still // active. for err == ERESTART { r, err = wait4(_Pid_t(pid), &status, options, rusage) @@ -629,6 +629,7 @@ func PtraceDetach(pid int) (err error) { return ptrace64(PT_DETACH, int64(pid), //sysnb Setegid(egid int) (err error) //sysnb Seteuid(euid int) (err error) //sysnb Setgid(gid int) (err error) +//sysnb Setuid(uid int) (err error) //sysnb Setpgid(pid int, pgid int) (err error) //sys Setpriority(which int, who int, prio int) (err error) //sysnb Setregid(rgid int, egid int) (err error) diff --git a/contrib/go/_std_1.22/src/syscall/syscall_aix_ppc64.go b/contrib/go/_std_1.23/src/syscall/syscall_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_aix_ppc64.go rename to contrib/go/_std_1.23/src/syscall/syscall_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_bsd.go b/contrib/go/_std_1.23/src/syscall/syscall_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_bsd.go rename to contrib/go/_std_1.23/src/syscall/syscall_bsd.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_darwin.go b/contrib/go/_std_1.23/src/syscall/syscall_darwin.go similarity index 97% rename from contrib/go/_std_1.22/src/syscall/syscall_darwin.go rename to contrib/go/_std_1.23/src/syscall/syscall_darwin.go index 2e13b57cd32e..5b38aeae31a6 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_darwin.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_darwin.go @@ -113,6 +113,15 @@ func libc_getfsstat_trampoline() //go:cgo_import_dynamic libc_getfsstat getfsstat "/usr/lib/libSystem.B.dylib" +// utimensat should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/tetratelabs/wazero +// +// See go.dev/issue/67401. +// +//go:linkname utimensat + //sys utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) /* diff --git a/contrib/go/_std_1.22/src/syscall/syscall_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_dragonfly.go b/contrib/go/_std_1.23/src/syscall/syscall_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_dragonfly.go rename to contrib/go/_std_1.23/src/syscall/syscall_dragonfly.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_illumos.go b/contrib/go/_std_1.23/src/syscall/syscall_illumos.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_illumos.go rename to contrib/go/_std_1.23/src/syscall/syscall_illumos.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_js.go b/contrib/go/_std_1.23/src/syscall/syscall_js.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/syscall_js.go rename to contrib/go/_std_1.23/src/syscall/syscall_js.go index c1b28942e8e4..0e529e034373 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_js.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_js.go @@ -48,7 +48,7 @@ const PathMax = 256 // err = errno // } // -// Errno values can be tested against error values using errors.Is. +// Errno values can be tested against error values using [errors.Is]. // For example: // // _, _, err := syscall.Syscall(...) @@ -88,7 +88,7 @@ func (e Errno) Timeout() bool { } // A Signal is a number describing a process signal. -// It implements the os.Signal interface. +// It implements the [os.Signal] interface. type Signal int const ( diff --git a/contrib/go/_std_1.23/src/syscall/syscall_linux.go b/contrib/go/_std_1.23/src/syscall/syscall_linux.go new file mode 100644 index 000000000000..270697359665 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/syscall_linux.go @@ -0,0 +1,1300 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Linux system calls. +// This file is compiled as ordinary Go code, +// but it is also input to mksyscall, +// which parses the //sys lines and generates system call stubs. +// Note that sometimes we use a lowercase //sys name and +// wrap it in our own nicer implementation. + +package syscall + +import ( + "internal/itoa" + runtimesyscall "internal/runtime/syscall" + "runtime" + "unsafe" +) + +// Pull in entersyscall/exitsyscall for Syscall/Syscall6. +// +// Note that this can't be a push linkname because the runtime already has a +// nameless linkname to export to assembly here and in x/sys. Additionally, +// entersyscall fetches the caller PC and SP and thus can't have a wrapper +// inbetween. + +//go:linkname runtime_entersyscall runtime.entersyscall +func runtime_entersyscall() + +//go:linkname runtime_exitsyscall runtime.exitsyscall +func runtime_exitsyscall() + +// N.B. For the Syscall functions below: +// +// //go:uintptrkeepalive because the uintptr argument may be converted pointers +// that need to be kept alive in the caller. +// +// //go:nosplit because stack copying does not account for uintptrkeepalive, so +// the stack must not grow. Stack copying cannot blindly assume that all +// uintptr arguments are pointers, because some values may look like pointers, +// but not really be pointers, and adjusting their value would break the call. +// +// //go:norace, on RawSyscall, to avoid race instrumentation if RawSyscall is +// called after fork, or from a signal handler. +// +// //go:linkname to ensure ABI wrappers are generated for external callers +// (notably x/sys/unix assembly). + +//go:uintptrkeepalive +//go:nosplit +//go:norace +//go:linkname RawSyscall +func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { + return RawSyscall6(trap, a1, a2, a3, 0, 0, 0) +} + +//go:uintptrkeepalive +//go:nosplit +//go:norace +//go:linkname RawSyscall6 +func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { + var errno uintptr + r1, r2, errno = runtimesyscall.Syscall6(trap, a1, a2, a3, a4, a5, a6) + err = Errno(errno) + return +} + +//go:uintptrkeepalive +//go:nosplit +//go:linkname Syscall +func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { + runtime_entersyscall() + // N.B. Calling RawSyscall here is unsafe with atomic coverage + // instrumentation and race mode. + // + // Coverage instrumentation will add a sync/atomic call to RawSyscall. + // Race mode will add race instrumentation to sync/atomic. Race + // instrumentation requires a P, which we no longer have. + // + // RawSyscall6 is fine because it is implemented in assembly and thus + // has no coverage instrumentation. + // + // This is typically not a problem in the runtime because cmd/go avoids + // adding coverage instrumentation to the runtime in race mode. + r1, r2, err = RawSyscall6(trap, a1, a2, a3, 0, 0, 0) + runtime_exitsyscall() + return +} + +//go:uintptrkeepalive +//go:nosplit +//go:linkname Syscall6 +func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { + runtime_entersyscall() + r1, r2, err = RawSyscall6(trap, a1, a2, a3, a4, a5, a6) + runtime_exitsyscall() + return +} + +func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) +func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1 uintptr, err Errno) + +/* + * Wrapped + */ + +func Access(path string, mode uint32) (err error) { + return Faccessat(_AT_FDCWD, path, mode, 0) +} + +func Chmod(path string, mode uint32) (err error) { + return Fchmodat(_AT_FDCWD, path, mode, 0) +} + +func Chown(path string, uid int, gid int) (err error) { + return Fchownat(_AT_FDCWD, path, uid, gid, 0) +} + +func Creat(path string, mode uint32) (fd int, err error) { + return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) +} + +func EpollCreate(size int) (fd int, err error) { + if size <= 0 { + return -1, EINVAL + } + return EpollCreate1(0) +} + +func isGroupMember(gid int) bool { + groups, err := Getgroups() + if err != nil { + return false + } + + for _, g := range groups { + if g == gid { + return true + } + } + return false +} + +func isCapDacOverrideSet() bool { + const _CAP_DAC_OVERRIDE = 1 + var c caps + c.hdr.version = _LINUX_CAPABILITY_VERSION_3 + + _, _, err := RawSyscall(SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(&c.data[0])), 0) + + return err == 0 && c.data[0].effective&capToMask(_CAP_DAC_OVERRIDE) != 0 +} + +//sys faccessat(dirfd int, path string, mode uint32) (err error) +//sys faccessat2(dirfd int, path string, mode uint32, flags int) (err error) = _SYS_faccessat2 + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + if flags == 0 { + return faccessat(dirfd, path, mode) + } + + // Attempt to use the newer faccessat2, which supports flags directly, + // falling back if it doesn't exist. + // + // Don't attempt on Android, which does not allow faccessat2 through + // its seccomp policy [1] on any version of Android as of 2022-12-20. + // + // [1] https://cs.android.com/android/platform/superproject/+/master:bionic/libc/SECCOMP_BLOCKLIST_APP.TXT;l=4;drc=dbb8670dfdcc677f7e3b9262e93800fa14c4e417 + if runtime.GOOS != "android" { + if err := faccessat2(dirfd, path, mode, flags); err != ENOSYS && err != EPERM { + return err + } + } + + // The Linux kernel faccessat system call does not take any flags. + // The glibc faccessat implements the flags itself; see + // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/faccessat.c;hb=HEAD + // Because people naturally expect syscall.Faccessat to act + // like C faccessat, we do the same. + + if flags & ^(_AT_SYMLINK_NOFOLLOW|_AT_EACCESS) != 0 { + return EINVAL + } + + var st Stat_t + if err := fstatat(dirfd, path, &st, flags&_AT_SYMLINK_NOFOLLOW); err != nil { + return err + } + + mode &= 7 + if mode == 0 { + return nil + } + + // Fallback to checking permission bits. + var uid int + if flags&_AT_EACCESS != 0 { + uid = Geteuid() + if uid != 0 && isCapDacOverrideSet() { + // If CAP_DAC_OVERRIDE is set, file access check is + // done by the kernel in the same way as for root + // (see generic_permission() in the Linux sources). + uid = 0 + } + } else { + uid = Getuid() + } + + if uid == 0 { + if mode&1 == 0 { + // Root can read and write any file. + return nil + } + if st.Mode&0111 != 0 { + // Root can execute any file that anybody can execute. + return nil + } + return EACCES + } + + var fmode uint32 + if uint32(uid) == st.Uid { + fmode = (st.Mode >> 6) & 7 + } else { + var gid int + if flags&_AT_EACCESS != 0 { + gid = Getegid() + } else { + gid = Getgid() + } + + if uint32(gid) == st.Gid || isGroupMember(int(st.Gid)) { + fmode = (st.Mode >> 3) & 7 + } else { + fmode = st.Mode & 7 + } + } + + if fmode&mode == mode { + return nil + } + + return EACCES +} + +//sys fchmodat(dirfd int, path string, mode uint32) (err error) +//sys fchmodat2(dirfd int, path string, mode uint32, flags int) (err error) = _SYS_fchmodat2 + +func Fchmodat(dirfd int, path string, mode uint32, flags int) error { + // Linux fchmodat doesn't support the flags parameter, but fchmodat2 does. + // Try fchmodat2 if flags are specified. + if flags != 0 { + err := fchmodat2(dirfd, path, mode, flags) + if err == ENOSYS { + // fchmodat2 isn't available. If the flags are known to be valid, + // return EOPNOTSUPP to indicate that fchmodat doesn't support them. + if flags&^(_AT_SYMLINK_NOFOLLOW|_AT_EMPTY_PATH) != 0 { + return EINVAL + } else if flags&(_AT_SYMLINK_NOFOLLOW|_AT_EMPTY_PATH) != 0 { + return EOPNOTSUPP + } + } + return err + } + return fchmodat(dirfd, path, mode) +} + +//sys linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) + +func Link(oldpath string, newpath string) (err error) { + return linkat(_AT_FDCWD, oldpath, _AT_FDCWD, newpath, 0) +} + +func Mkdir(path string, mode uint32) (err error) { + return Mkdirat(_AT_FDCWD, path, mode) +} + +func Mknod(path string, mode uint32, dev int) (err error) { + return Mknodat(_AT_FDCWD, path, mode, dev) +} + +func Open(path string, mode int, perm uint32) (fd int, err error) { + return openat(_AT_FDCWD, path, mode|O_LARGEFILE, perm) +} + +//sys openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) + +func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) { + return openat(dirfd, path, flags|O_LARGEFILE, mode) +} + +func Pipe(p []int) error { + return Pipe2(p, 0) +} + +//sysnb pipe2(p *[2]_C_int, flags int) (err error) + +func Pipe2(p []int, flags int) error { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + err := pipe2(&pp, flags) + if err == nil { + p[0] = int(pp[0]) + p[1] = int(pp[1]) + } + return err +} + +//sys readlinkat(dirfd int, path string, buf []byte) (n int, err error) + +func Readlink(path string, buf []byte) (n int, err error) { + return readlinkat(_AT_FDCWD, path, buf) +} + +func Rename(oldpath string, newpath string) (err error) { + return Renameat(_AT_FDCWD, oldpath, _AT_FDCWD, newpath) +} + +func Rmdir(path string) error { + return unlinkat(_AT_FDCWD, path, _AT_REMOVEDIR) +} + +//sys symlinkat(oldpath string, newdirfd int, newpath string) (err error) + +func Symlink(oldpath string, newpath string) (err error) { + return symlinkat(oldpath, _AT_FDCWD, newpath) +} + +func Unlink(path string) error { + return unlinkat(_AT_FDCWD, path, 0) +} + +//sys unlinkat(dirfd int, path string, flags int) (err error) + +func Unlinkat(dirfd int, path string) error { + return unlinkat(dirfd, path, 0) +} + +func Utimes(path string, tv []Timeval) (err error) { + if len(tv) != 2 { + return EINVAL + } + return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) +} + +//sys utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) + +func UtimesNano(path string, ts []Timespec) (err error) { + if len(ts) != 2 { + return EINVAL + } + return utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) +} + +func Futimesat(dirfd int, path string, tv []Timeval) (err error) { + if len(tv) != 2 { + return EINVAL + } + return futimesat(dirfd, path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) +} + +func Futimes(fd int, tv []Timeval) (err error) { + // Believe it or not, this is the best we can do on Linux + // (and is what glibc does). + return Utimes("/proc/self/fd/"+itoa.Itoa(fd), tv) +} + +const ImplementsGetwd = true + +//sys Getcwd(buf []byte) (n int, err error) + +func Getwd() (wd string, err error) { + var buf [PathMax]byte + n, err := Getcwd(buf[0:]) + if err != nil { + return "", err + } + // Getcwd returns the number of bytes written to buf, including the NUL. + if n < 1 || n > len(buf) || buf[n-1] != 0 { + return "", EINVAL + } + // In some cases, Linux can return a path that starts with the + // "(unreachable)" prefix, which can potentially be a valid relative + // path. To work around that, return ENOENT if path is not absolute. + if buf[0] != '/' { + return "", ENOENT + } + + return string(buf[0 : n-1]), nil +} + +func Getgroups() (gids []int, err error) { + n, err := getgroups(0, nil) + if err != nil { + return nil, err + } + if n == 0 { + return nil, nil + } + + // Sanity check group count. Max is 1<<16 on Linux. + if n < 0 || n > 1<<20 { + return nil, EINVAL + } + + a := make([]_Gid_t, n) + n, err = getgroups(n, &a[0]) + if err != nil { + return nil, err + } + gids = make([]int, n) + for i, v := range a[0:n] { + gids[i] = int(v) + } + return +} + +var cgo_libc_setgroups unsafe.Pointer // non-nil if cgo linked. + +func Setgroups(gids []int) (err error) { + n := uintptr(len(gids)) + if n == 0 { + if cgo_libc_setgroups == nil { + if _, _, e1 := AllThreadsSyscall(_SYS_setgroups, 0, 0, 0); e1 != 0 { + err = errnoErr(e1) + } + return + } + if ret := cgocaller(cgo_libc_setgroups, 0, 0); ret != 0 { + err = errnoErr(Errno(ret)) + } + return + } + + a := make([]_Gid_t, len(gids)) + for i, v := range gids { + a[i] = _Gid_t(v) + } + if cgo_libc_setgroups == nil { + if _, _, e1 := AllThreadsSyscall(_SYS_setgroups, n, uintptr(unsafe.Pointer(&a[0])), 0); e1 != 0 { + err = errnoErr(e1) + } + return + } + if ret := cgocaller(cgo_libc_setgroups, n, uintptr(unsafe.Pointer(&a[0]))); ret != 0 { + err = errnoErr(Errno(ret)) + } + return +} + +type WaitStatus uint32 + +// Wait status is 7 bits at bottom, either 0 (exited), +// 0x7F (stopped), or a signal number that caused an exit. +// The 0x80 bit is whether there was a core dump. +// An extra number (exit code, signal causing a stop) +// is in the high bits. At least that's the idea. +// There are various irregularities. For example, the +// "continued" status is 0xFFFF, distinguishing itself +// from stopped via the core dump bit. + +const ( + mask = 0x7F + core = 0x80 + exited = 0x00 + stopped = 0x7F + shift = 8 +) + +func (w WaitStatus) Exited() bool { return w&mask == exited } + +func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != exited } + +func (w WaitStatus) Stopped() bool { return w&0xFF == stopped } + +func (w WaitStatus) Continued() bool { return w == 0xFFFF } + +func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 } + +func (w WaitStatus) ExitStatus() int { + if !w.Exited() { + return -1 + } + return int(w>>shift) & 0xFF +} + +func (w WaitStatus) Signal() Signal { + if !w.Signaled() { + return -1 + } + return Signal(w & mask) +} + +func (w WaitStatus) StopSignal() Signal { + if !w.Stopped() { + return -1 + } + return Signal(w>>shift) & 0xFF +} + +func (w WaitStatus) TrapCause() int { + if w.StopSignal() != SIGTRAP { + return -1 + } + return int(w>>shift) >> 8 +} + +//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) + +func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) { + var status _C_int + wpid, err = wait4(pid, &status, options, rusage) + if wstatus != nil { + *wstatus = WaitStatus(status) + } + return +} + +func Mkfifo(path string, mode uint32) (err error) { + return Mknod(path, mode|S_IFIFO, 0) +} + +func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, EINVAL + } + sa.raw.Family = AF_INET + p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + sa.raw.Addr = sa.Addr + return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil +} + +func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, EINVAL + } + sa.raw.Family = AF_INET6 + p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + sa.raw.Scope_id = sa.ZoneId + sa.raw.Addr = sa.Addr + return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil +} + +func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) { + name := sa.Name + n := len(name) + if n > len(sa.raw.Path) { + return nil, 0, EINVAL + } + if n == len(sa.raw.Path) && name[0] != '@' { + return nil, 0, EINVAL + } + sa.raw.Family = AF_UNIX + for i := 0; i < n; i++ { + sa.raw.Path[i] = int8(name[i]) + } + // length is family (uint16), name, NUL. + sl := _Socklen(2) + if n > 0 { + sl += _Socklen(n) + 1 + } + if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) { + // Check sl > 3 so we don't change unnamed socket behavior. + sa.raw.Path[0] = 0 + // Don't count trailing NUL for abstract address. + sl-- + } + + return unsafe.Pointer(&sa.raw), sl, nil +} + +type SockaddrLinklayer struct { + Protocol uint16 + Ifindex int + Hatype uint16 + Pkttype uint8 + Halen uint8 + Addr [8]byte + raw RawSockaddrLinklayer +} + +func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) { + if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff { + return nil, 0, EINVAL + } + sa.raw.Family = AF_PACKET + sa.raw.Protocol = sa.Protocol + sa.raw.Ifindex = int32(sa.Ifindex) + sa.raw.Hatype = sa.Hatype + sa.raw.Pkttype = sa.Pkttype + sa.raw.Halen = sa.Halen + sa.raw.Addr = sa.Addr + return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil +} + +type SockaddrNetlink struct { + Family uint16 + Pad uint16 + Pid uint32 + Groups uint32 + raw RawSockaddrNetlink +} + +func (sa *SockaddrNetlink) sockaddr() (unsafe.Pointer, _Socklen, error) { + sa.raw.Family = AF_NETLINK + sa.raw.Pad = sa.Pad + sa.raw.Pid = sa.Pid + sa.raw.Groups = sa.Groups + return unsafe.Pointer(&sa.raw), SizeofSockaddrNetlink, nil +} + +func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) { + switch rsa.Addr.Family { + case AF_NETLINK: + pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa)) + sa := new(SockaddrNetlink) + sa.Family = pp.Family + sa.Pad = pp.Pad + sa.Pid = pp.Pid + sa.Groups = pp.Groups + return sa, nil + + case AF_PACKET: + pp := (*RawSockaddrLinklayer)(unsafe.Pointer(rsa)) + sa := new(SockaddrLinklayer) + sa.Protocol = pp.Protocol + sa.Ifindex = int(pp.Ifindex) + sa.Hatype = pp.Hatype + sa.Pkttype = pp.Pkttype + sa.Halen = pp.Halen + sa.Addr = pp.Addr + return sa, nil + + case AF_UNIX: + pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa)) + sa := new(SockaddrUnix) + if pp.Path[0] == 0 { + // "Abstract" Unix domain socket. + // Rewrite leading NUL as @ for textual display. + // (This is the standard convention.) + // Not friendly to overwrite in place, + // but the callers below don't care. + pp.Path[0] = '@' + } + + // Assume path ends at NUL. + // This is not technically the Linux semantics for + // abstract Unix domain sockets--they are supposed + // to be uninterpreted fixed-size binary blobs--but + // everyone uses this convention. + n := 0 + for n < len(pp.Path) && pp.Path[n] != 0 { + n++ + } + sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n)) + return sa, nil + + case AF_INET: + pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) + sa := new(SockaddrInet4) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + sa.Addr = pp.Addr + return sa, nil + + case AF_INET6: + pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)) + sa := new(SockaddrInet6) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + sa.ZoneId = pp.Scope_id + sa.Addr = pp.Addr + return sa, nil + } + return nil, EAFNOSUPPORT +} + +func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) { + var rsa RawSockaddrAny + var len _Socklen = SizeofSockaddrAny + nfd, err = accept4(fd, &rsa, &len, flags) + if err != nil { + return + } + if len > SizeofSockaddrAny { + panic("RawSockaddrAny too small") + } + sa, err = anyToSockaddr(&rsa) + if err != nil { + Close(nfd) + nfd = 0 + } + return +} + +func Getsockname(fd int) (sa Sockaddr, err error) { + var rsa RawSockaddrAny + var len _Socklen = SizeofSockaddrAny + if err = getsockname(fd, &rsa, &len); err != nil { + return + } + return anyToSockaddr(&rsa) +} + +func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) { + vallen := _Socklen(4) + err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) + return value, err +} + +func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) { + var value IPMreq + vallen := _Socklen(SizeofIPMreq) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) { + var value IPMreqn + vallen := _Socklen(SizeofIPMreqn) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) { + var value IPv6Mreq + vallen := _Socklen(SizeofIPv6Mreq) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) { + var value IPv6MTUInfo + vallen := _Socklen(SizeofIPv6MTUInfo) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) { + var value ICMPv6Filter + vallen := _Socklen(SizeofICMPv6Filter) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptUcred(fd, level, opt int) (*Ucred, error) { + var value Ucred + vallen := _Socklen(SizeofUcred) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) { + return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) +} + +func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) { + var msg Msghdr + msg.Name = (*byte)(unsafe.Pointer(rsa)) + msg.Namelen = uint32(SizeofSockaddrAny) + var iov Iovec + if len(p) > 0 { + iov.Base = &p[0] + iov.SetLen(len(p)) + } + var dummy byte + if len(oob) > 0 { + if len(p) == 0 { + var sockType int + sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) + if err != nil { + return + } + // receive at least one normal byte + if sockType != SOCK_DGRAM { + iov.Base = &dummy + iov.SetLen(1) + } + } + msg.Control = &oob[0] + msg.SetControllen(len(oob)) + } + msg.Iov = &iov + msg.Iovlen = 1 + if n, err = recvmsg(fd, &msg, flags); err != nil { + return + } + oobn = int(msg.Controllen) + recvflags = int(msg.Flags) + return +} + +func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) { + var msg Msghdr + msg.Name = (*byte)(ptr) + msg.Namelen = uint32(salen) + var iov Iovec + if len(p) > 0 { + iov.Base = &p[0] + iov.SetLen(len(p)) + } + var dummy byte + if len(oob) > 0 { + if len(p) == 0 { + var sockType int + sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) + if err != nil { + return 0, err + } + // send at least one normal byte + if sockType != SOCK_DGRAM { + iov.Base = &dummy + iov.SetLen(1) + } + } + msg.Control = &oob[0] + msg.SetControllen(len(oob)) + } + msg.Iov = &iov + msg.Iovlen = 1 + if n, err = sendmsg(fd, &msg, flags); err != nil { + return 0, err + } + if len(oob) > 0 && len(p) == 0 { + n = 0 + } + return n, nil +} + +// BindToDevice binds the socket associated with fd to device. +func BindToDevice(fd int, device string) (err error) { + return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device) +} + +//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) +//sys ptracePtr(request int, pid int, addr uintptr, data unsafe.Pointer) (err error) = SYS_PTRACE + +func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err error) { + // The peek requests are machine-size oriented, so we wrap it + // to retrieve arbitrary-length data. + + // The ptrace syscall differs from glibc's ptrace. + // Peeks returns the word in *data, not as the return value. + + var buf [sizeofPtr]byte + + // Leading edge. PEEKTEXT/PEEKDATA don't require aligned + // access (PEEKUSER warns that it might), but if we don't + // align our reads, we might straddle an unmapped page + // boundary and not get the bytes leading up to the page + // boundary. + n := 0 + if addr%sizeofPtr != 0 { + err = ptracePtr(req, pid, addr-addr%sizeofPtr, unsafe.Pointer(&buf[0])) + if err != nil { + return 0, err + } + n += copy(out, buf[addr%sizeofPtr:]) + out = out[n:] + } + + // Remainder. + for len(out) > 0 { + // We use an internal buffer to guarantee alignment. + // It's not documented if this is necessary, but we're paranoid. + err = ptracePtr(req, pid, addr+uintptr(n), unsafe.Pointer(&buf[0])) + if err != nil { + return n, err + } + copied := copy(out, buf[0:]) + n += copied + out = out[copied:] + } + + return n, nil +} + +func PtracePeekText(pid int, addr uintptr, out []byte) (count int, err error) { + return ptracePeek(PTRACE_PEEKTEXT, pid, addr, out) +} + +func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) { + return ptracePeek(PTRACE_PEEKDATA, pid, addr, out) +} + +func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, err error) { + // As for ptracePeek, we need to align our accesses to deal + // with the possibility of straddling an invalid page. + + // Leading edge. + n := 0 + if addr%sizeofPtr != 0 { + var buf [sizeofPtr]byte + err = ptracePtr(peekReq, pid, addr-addr%sizeofPtr, unsafe.Pointer(&buf[0])) + if err != nil { + return 0, err + } + n += copy(buf[addr%sizeofPtr:], data) + word := *((*uintptr)(unsafe.Pointer(&buf[0]))) + err = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word) + if err != nil { + return 0, err + } + data = data[n:] + } + + // Interior. + for len(data) > sizeofPtr { + word := *((*uintptr)(unsafe.Pointer(&data[0]))) + err = ptrace(pokeReq, pid, addr+uintptr(n), word) + if err != nil { + return n, err + } + n += sizeofPtr + data = data[sizeofPtr:] + } + + // Trailing edge. + if len(data) > 0 { + var buf [sizeofPtr]byte + err = ptracePtr(peekReq, pid, addr+uintptr(n), unsafe.Pointer(&buf[0])) + if err != nil { + return n, err + } + copy(buf[0:], data) + word := *((*uintptr)(unsafe.Pointer(&buf[0]))) + err = ptrace(pokeReq, pid, addr+uintptr(n), word) + if err != nil { + return n, err + } + n += len(data) + } + + return n, nil +} + +func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) { + return ptracePoke(PTRACE_POKETEXT, PTRACE_PEEKTEXT, pid, addr, data) +} + +func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) { + return ptracePoke(PTRACE_POKEDATA, PTRACE_PEEKDATA, pid, addr, data) +} + +const ( + _NT_PRSTATUS = 1 +) + +func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) { + var iov Iovec + iov.Base = (*byte)(unsafe.Pointer(regsout)) + iov.SetLen(int(unsafe.Sizeof(*regsout))) + return ptracePtr(PTRACE_GETREGSET, pid, uintptr(_NT_PRSTATUS), unsafe.Pointer(&iov)) +} + +func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) { + var iov Iovec + iov.Base = (*byte)(unsafe.Pointer(regs)) + iov.SetLen(int(unsafe.Sizeof(*regs))) + return ptracePtr(PTRACE_SETREGSET, pid, uintptr(_NT_PRSTATUS), unsafe.Pointer(&iov)) +} + +func PtraceSetOptions(pid int, options int) (err error) { + return ptrace(PTRACE_SETOPTIONS, pid, 0, uintptr(options)) +} + +func PtraceGetEventMsg(pid int) (msg uint, err error) { + var data _C_long + err = ptracePtr(PTRACE_GETEVENTMSG, pid, 0, unsafe.Pointer(&data)) + msg = uint(data) + return +} + +func PtraceCont(pid int, signal int) (err error) { + return ptrace(PTRACE_CONT, pid, 0, uintptr(signal)) +} + +func PtraceSyscall(pid int, signal int) (err error) { + return ptrace(PTRACE_SYSCALL, pid, 0, uintptr(signal)) +} + +func PtraceSingleStep(pid int) (err error) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) } + +func PtraceAttach(pid int) (err error) { return ptrace(PTRACE_ATTACH, pid, 0, 0) } + +func PtraceDetach(pid int) (err error) { return ptrace(PTRACE_DETACH, pid, 0, 0) } + +//sys reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) + +func Reboot(cmd int) (err error) { + return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "") +} + +func ReadDirent(fd int, buf []byte) (n int, err error) { + return Getdents(fd, buf) +} + +func direntIno(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) +} + +func direntReclen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) +} + +func direntNamlen(buf []byte) (uint64, bool) { + reclen, ok := direntReclen(buf) + if !ok { + return 0, false + } + return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true +} + +//sys mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) + +func Mount(source string, target string, fstype string, flags uintptr, data string) (err error) { + // Certain file systems get rather angry and EINVAL if you give + // them an empty string of data, rather than NULL. + if data == "" { + return mount(source, target, fstype, flags, nil) + } + datap, err := BytePtrFromString(data) + if err != nil { + return err + } + return mount(source, target, fstype, flags, datap) +} + +// Sendto +// Recvfrom +// Socketpair + +/* + * Direct access + */ +//sys Acct(path string) (err error) +//sys Adjtimex(buf *Timex) (state int, err error) +//sys Chdir(path string) (err error) +//sys Chroot(path string) (err error) +//sys Close(fd int) (err error) +//sys Dup(oldfd int) (fd int, err error) +//sys Dup3(oldfd int, newfd int, flags int) (err error) +//sysnb EpollCreate1(flag int) (fd int, err error) +//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) +//sys Fallocate(fd int, mode uint32, off int64, len int64) (err error) +//sys Fchdir(fd int) (err error) +//sys Fchmod(fd int, mode uint32) (err error) +//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) +//sys fcntl(fd int, cmd int, arg int) (val int, err error) +//sys Fdatasync(fd int) (err error) +//sys Flock(fd int, how int) (err error) +//sys Fsync(fd int) (err error) +//sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64 +//sysnb Getpgid(pid int) (pgid int, err error) + +func Getpgrp() (pid int) { + pid, _ = Getpgid(0) + return +} + +//sysnb Getpid() (pid int) +//sysnb Getppid() (ppid int) +//sys Getpriority(which int, who int) (prio int, err error) +//sysnb Getrusage(who int, rusage *Rusage) (err error) +//sysnb Gettid() (tid int) +//sys Getxattr(path string, attr string, dest []byte) (sz int, err error) +//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) +//sysnb InotifyInit1(flags int) (fd int, err error) +//sysnb InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) +//sysnb Kill(pid int, sig Signal) (err error) +//sys Klogctl(typ int, buf []byte) (n int, err error) = SYS_SYSLOG +//sys Listxattr(path string, dest []byte) (sz int, err error) +//sys Mkdirat(dirfd int, path string, mode uint32) (err error) +//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error) +//sys Nanosleep(time *Timespec, leftover *Timespec) (err error) +//sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT +//sysnb prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64 +//sys read(fd int, p []byte) (n int, err error) +//sys Removexattr(path string, attr string) (err error) +//sys Setdomainname(p []byte) (err error) +//sys Sethostname(p []byte) (err error) +//sysnb Setpgid(pid int, pgid int) (err error) +//sysnb Setsid() (pid int, err error) +//sysnb Settimeofday(tv *Timeval) (err error) + +// Provided by runtime.syscall_runtime_doAllThreadsSyscall which stops the +// world and invokes the syscall on each OS thread. Once this function returns, +// all threads are in sync. +// +//go:uintptrescapes +func runtime_doAllThreadsSyscall(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) + +// AllThreadsSyscall performs a syscall on each OS thread of the Go +// runtime. It first invokes the syscall on one thread. Should that +// invocation fail, it returns immediately with the error status. +// Otherwise, it invokes the syscall on all of the remaining threads +// in parallel. It will terminate the program if it observes any +// invoked syscall's return value differs from that of the first +// invocation. +// +// AllThreadsSyscall is intended for emulating simultaneous +// process-wide state changes that require consistently modifying +// per-thread state of the Go runtime. +// +// AllThreadsSyscall is unaware of any threads that are launched +// explicitly by cgo linked code, so the function always returns +// [ENOTSUP] in binaries that use cgo. +// +//go:uintptrescapes +func AllThreadsSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { + if cgo_libc_setegid != nil { + return minus1, minus1, ENOTSUP + } + r1, r2, errno := runtime_doAllThreadsSyscall(trap, a1, a2, a3, 0, 0, 0) + return r1, r2, Errno(errno) +} + +// AllThreadsSyscall6 is like [AllThreadsSyscall], but extended to six +// arguments. +// +//go:uintptrescapes +func AllThreadsSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { + if cgo_libc_setegid != nil { + return minus1, minus1, ENOTSUP + } + r1, r2, errno := runtime_doAllThreadsSyscall(trap, a1, a2, a3, a4, a5, a6) + return r1, r2, Errno(errno) +} + +// linked by runtime.cgocall.go +// +//go:uintptrescapes +func cgocaller(unsafe.Pointer, ...uintptr) uintptr + +var cgo_libc_setegid unsafe.Pointer // non-nil if cgo linked. + +const minus1 = ^uintptr(0) + +func Setegid(egid int) (err error) { + if cgo_libc_setegid == nil { + if _, _, e1 := AllThreadsSyscall(SYS_SETRESGID, minus1, uintptr(egid), minus1); e1 != 0 { + err = errnoErr(e1) + } + } else if ret := cgocaller(cgo_libc_setegid, uintptr(egid)); ret != 0 { + err = errnoErr(Errno(ret)) + } + return +} + +var cgo_libc_seteuid unsafe.Pointer // non-nil if cgo linked. + +func Seteuid(euid int) (err error) { + if cgo_libc_seteuid == nil { + if _, _, e1 := AllThreadsSyscall(SYS_SETRESUID, minus1, uintptr(euid), minus1); e1 != 0 { + err = errnoErr(e1) + } + } else if ret := cgocaller(cgo_libc_seteuid, uintptr(euid)); ret != 0 { + err = errnoErr(Errno(ret)) + } + return +} + +var cgo_libc_setgid unsafe.Pointer // non-nil if cgo linked. + +func Setgid(gid int) (err error) { + if cgo_libc_setgid == nil { + if _, _, e1 := AllThreadsSyscall(sys_SETGID, uintptr(gid), 0, 0); e1 != 0 { + err = errnoErr(e1) + } + } else if ret := cgocaller(cgo_libc_setgid, uintptr(gid)); ret != 0 { + err = errnoErr(Errno(ret)) + } + return +} + +var cgo_libc_setregid unsafe.Pointer // non-nil if cgo linked. + +func Setregid(rgid, egid int) (err error) { + if cgo_libc_setregid == nil { + if _, _, e1 := AllThreadsSyscall(sys_SETREGID, uintptr(rgid), uintptr(egid), 0); e1 != 0 { + err = errnoErr(e1) + } + } else if ret := cgocaller(cgo_libc_setregid, uintptr(rgid), uintptr(egid)); ret != 0 { + err = errnoErr(Errno(ret)) + } + return +} + +var cgo_libc_setresgid unsafe.Pointer // non-nil if cgo linked. + +func Setresgid(rgid, egid, sgid int) (err error) { + if cgo_libc_setresgid == nil { + if _, _, e1 := AllThreadsSyscall(sys_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)); e1 != 0 { + err = errnoErr(e1) + } + } else if ret := cgocaller(cgo_libc_setresgid, uintptr(rgid), uintptr(egid), uintptr(sgid)); ret != 0 { + err = errnoErr(Errno(ret)) + } + return +} + +var cgo_libc_setresuid unsafe.Pointer // non-nil if cgo linked. + +func Setresuid(ruid, euid, suid int) (err error) { + if cgo_libc_setresuid == nil { + if _, _, e1 := AllThreadsSyscall(sys_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)); e1 != 0 { + err = errnoErr(e1) + } + } else if ret := cgocaller(cgo_libc_setresuid, uintptr(ruid), uintptr(euid), uintptr(suid)); ret != 0 { + err = errnoErr(Errno(ret)) + } + return +} + +var cgo_libc_setreuid unsafe.Pointer // non-nil if cgo linked. + +func Setreuid(ruid, euid int) (err error) { + if cgo_libc_setreuid == nil { + if _, _, e1 := AllThreadsSyscall(sys_SETREUID, uintptr(ruid), uintptr(euid), 0); e1 != 0 { + err = errnoErr(e1) + } + } else if ret := cgocaller(cgo_libc_setreuid, uintptr(ruid), uintptr(euid)); ret != 0 { + err = errnoErr(Errno(ret)) + } + return +} + +var cgo_libc_setuid unsafe.Pointer // non-nil if cgo linked. + +func Setuid(uid int) (err error) { + if cgo_libc_setuid == nil { + if _, _, e1 := AllThreadsSyscall(sys_SETUID, uintptr(uid), 0, 0); e1 != 0 { + err = errnoErr(e1) + } + } else if ret := cgocaller(cgo_libc_setuid, uintptr(uid)); ret != 0 { + err = errnoErr(Errno(ret)) + } + return +} + +//sys Setpriority(which int, who int, prio int) (err error) +//sys Setxattr(path string, attr string, data []byte, flags int) (err error) +//sys Sync() +//sysnb Sysinfo(info *Sysinfo_t) (err error) +//sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error) +//sysnb Tgkill(tgid int, tid int, sig Signal) (err error) +//sysnb Times(tms *Tms) (ticks uintptr, err error) +//sysnb Umask(mask int) (oldmask int) +//sysnb Uname(buf *Utsname) (err error) +//sys Unmount(target string, flags int) (err error) = SYS_UMOUNT2 +//sys Unshare(flags int) (err error) +//sys write(fd int, p []byte) (n int, err error) +//sys exitThread(code int) (err error) = SYS_EXIT +//sys readlen(fd int, p *byte, np int) (n int, err error) = SYS_READ + +// mmap varies by architecture; see syscall_linux_*.go. +//sys munmap(addr uintptr, length uintptr) (err error) + +var mapper = &mmapper{ + active: make(map[*byte][]byte), + mmap: mmap, + munmap: munmap, +} + +func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { + return mapper.Mmap(fd, offset, length, prot, flags) +} + +func Munmap(b []byte) (err error) { + return mapper.Munmap(b) +} + +//sys Madvise(b []byte, advice int) (err error) +//sys Mprotect(b []byte, prot int) (err error) +//sys Mlock(b []byte) (err error) +//sys Munlock(b []byte) (err error) +//sys Mlockall(flags int) (err error) +//sys Munlockall() (err error) + +// prlimit changes a resource limit. We use a single definition so that +// we can tell StartProcess to not restore the original NOFILE limit. +// +// golang.org/x/sys linknames prlimit. +// Do not remove or change the type signature. +// +//go:linkname prlimit +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + err = prlimit1(pid, resource, newlimit, old) + if err == nil && newlimit != nil && resource == RLIMIT_NOFILE && (pid == 0 || pid == Getpid()) { + origRlimitNofile.Store(nil) + } + return err +} diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_386.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_386.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_accept.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_accept.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_accept.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_accept.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_accept4.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_accept4.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_accept4.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_accept4.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_arm.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_mips64x.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_mips64x.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_mipsx.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_mipsx.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_ppc64x.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_ppc64x.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd1.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd1.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd1.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd1.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_arm64.go diff --git a/contrib/go/_std_1.23/src/syscall/syscall_openbsd_libc.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_libc.go new file mode 100644 index 000000000000..5dea268c3e42 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_libc.go @@ -0,0 +1,85 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build openbsd && !mips64 + +package syscall + +import ( + "internal/abi" +) + +var dupTrampoline = abi.FuncPCABI0(libc_dup3_trampoline) + +func init() { + execveOpenBSD = execve +} + +func syscallInternal(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { + // OpenBSD 7.5+ no longer supports indirect syscalls. A number of Go + // packages make use of syscall.Syscall with SYS_IOCTL since it is + // not well supported by golang.org/x/sys/unix. Reroute this system + // call number to the respective libc stub so that it continues to + // work for the time being. See #63900 for further details. + if trap == SYS_IOCTL { + return syscallX(abi.FuncPCABI0(libc_ioctl_trampoline), a1, a2, a3) + } + return 0, 0, ENOSYS +} + +func syscall6Internal(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { + // OpenBSD 7.5+ no longer supports indirect syscalls. A number of Go + // packages make use of syscall.Syscall with SYS___SYSCTL since it is + // not well supported by golang.org/x/sys/unix. Reroute this system + // call number to the respective libc stub so that it continues to + // work for the time being. See #63900 for further details. + if trap == SYS___SYSCTL { + return syscall6X(abi.FuncPCABI0(libc_sysctl_trampoline), a1, a2, a3, a4, a5, a6) + } + return 0, 0, ENOSYS +} + +func rawSyscallInternal(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { + return 0, 0, ENOSYS +} + +func rawSyscall6Internal(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { + return 0, 0, ENOSYS +} + +func syscall9Internal(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) { + return 0, 0, ENOSYS +} + +// Implemented in the runtime package (runtime/sys_openbsd3.go) +func syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) +func syscallX(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) +func syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) +func syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) +func syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno) +func syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno) +func rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) +func rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) +func rawSyscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) +func rawSyscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno) + +func syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) { + return syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, 0) +} +func syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) { + return syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, 0) +} + +//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_read +//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_lseek +//sys getcwd(buf []byte) (n int, err error) +//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) +//sysnb fork() (pid int, err error) +//sysnb execve(path *byte, argv **byte, envp **byte) (err error) +//sysnb exit(res int) (err error) +//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) +//sysnb getentropy(p []byte) (err error) +//sys fstatat(fd int, path string, stat *Stat_t, flags int) (err error) +//sys unlinkat(fd int, path string, flags int) (err error) +//sys openat(fd int, path string, flags int, perm uint32) (fdret int, err error) diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_plan9.go b/contrib/go/_std_1.23/src/syscall/syscall_plan9.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/syscall_plan9.go rename to contrib/go/_std_1.23/src/syscall/syscall_plan9.go index 7af10ba322a8..968782008d12 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_plan9.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_plan9.go @@ -23,7 +23,7 @@ const bitSize16 = 2 // ErrorString implements Error's String method by returning itself. // -// ErrorString values can be tested against error values using errors.Is. +// ErrorString values can be tested against error values using [errors.Is]. // For example: // // _, _, err := syscall.Syscall(...) @@ -99,7 +99,7 @@ var ( ) // For testing: clients can set this flag to force -// creation of IPv6 sockets to return EAFNOSUPPORT. +// creation of IPv6 sockets to return [EAFNOSUPPORT]. var SocketDisableIPv6 bool func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err ErrorString) diff --git a/contrib/go/_std_1.22/src/syscall/syscall_solaris.go b/contrib/go/_std_1.23/src/syscall/syscall_solaris.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/syscall_solaris.go rename to contrib/go/_std_1.23/src/syscall/syscall_solaris.go index 28d3727db66f..30400b4fac84 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_solaris.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_solaris.go @@ -299,7 +299,7 @@ func UtimesNano(path string, ts []Timespec) error { //sys fcntl(fd int, cmd int, arg int) (val int, err error) -// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +// FcntlFlock performs a fcntl syscall for the [F_GETLK], [F_SETLK] or [F_SETLKW] command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0) if e1 != 0 { diff --git a/contrib/go/_std_1.22/src/syscall/syscall_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_solarisonly.go b/contrib/go/_std_1.23/src/syscall/syscall_solarisonly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_solarisonly.go rename to contrib/go/_std_1.23/src/syscall/syscall_solarisonly.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_unix.go b/contrib/go/_std_1.23/src/syscall/syscall_unix.go similarity index 93% rename from contrib/go/_std_1.22/src/syscall/syscall_unix.go rename to contrib/go/_std_1.23/src/syscall/syscall_unix.go index 4c48f29744a7..ecd5952975a7 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_unix.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_unix.go @@ -8,8 +8,10 @@ package syscall import ( errorspkg "errors" + "internal/asan" "internal/bytealg" "internal/itoa" + "internal/msan" "internal/oserror" "internal/race" "runtime" @@ -98,7 +100,7 @@ func (m *mmapper) Munmap(data []byte) (err error) { // err = errno // } // -// Errno values can be tested against error values using errors.Is. +// Errno values can be tested against error values using [errors.Is]. // For example: // // _, _, err := syscall.Syscall(...) @@ -162,7 +164,7 @@ func errnoErr(e Errno) error { } // A Signal is a number describing a process signal. -// It implements the os.Signal interface. +// It implements the [os.Signal] interface. type Signal int func (s Signal) Signal() {} @@ -187,11 +189,11 @@ func Read(fd int, p []byte) (n int, err error) { race.Acquire(unsafe.Pointer(&ioSync)) } } - if msanenabled && n > 0 { - msanWrite(unsafe.Pointer(&p[0]), n) + if msan.Enabled && n > 0 { + msan.Write(unsafe.Pointer(&p[0]), uintptr(n)) } - if asanenabled && n > 0 { - asanWrite(unsafe.Pointer(&p[0]), n) + if asan.Enabled && n > 0 { + asan.Write(unsafe.Pointer(&p[0]), uintptr(n)) } return } @@ -211,11 +213,11 @@ func Write(fd int, p []byte) (n int, err error) { if race.Enabled && n > 0 { race.ReadRange(unsafe.Pointer(&p[0]), n) } - if msanenabled && n > 0 { - msanRead(unsafe.Pointer(&p[0]), n) + if msan.Enabled && n > 0 { + msan.Read(unsafe.Pointer(&p[0]), uintptr(n)) } - if asanenabled && n > 0 { - asanRead(unsafe.Pointer(&p[0]), n) + if asan.Enabled && n > 0 { + asan.Read(unsafe.Pointer(&p[0]), uintptr(n)) } return } @@ -230,11 +232,11 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { race.Acquire(unsafe.Pointer(&ioSync)) } } - if msanenabled && n > 0 { - msanWrite(unsafe.Pointer(&p[0]), n) + if msan.Enabled && n > 0 { + msan.Write(unsafe.Pointer(&p[0]), uintptr(n)) } - if asanenabled && n > 0 { - asanWrite(unsafe.Pointer(&p[0]), n) + if asan.Enabled && n > 0 { + asan.Write(unsafe.Pointer(&p[0]), uintptr(n)) } return } @@ -247,17 +249,17 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { if race.Enabled && n > 0 { race.ReadRange(unsafe.Pointer(&p[0]), n) } - if msanenabled && n > 0 { - msanRead(unsafe.Pointer(&p[0]), n) + if msan.Enabled && n > 0 { + msan.Read(unsafe.Pointer(&p[0]), uintptr(n)) } - if asanenabled && n > 0 { - asanRead(unsafe.Pointer(&p[0]), n) + if asan.Enabled && n > 0 { + asan.Read(unsafe.Pointer(&p[0]), uintptr(n)) } return } // For testing: clients can set this flag to force -// creation of IPv6 sockets to return EAFNOSUPPORT. +// creation of IPv6 sockets to return [EAFNOSUPPORT]. var SocketDisableIPv6 bool type Sockaddr interface { diff --git a/contrib/go/_std_1.22/src/syscall/syscall_wasip1.go b/contrib/go/_std_1.23/src/syscall/syscall_wasip1.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/syscall_wasip1.go rename to contrib/go/_std_1.23/src/syscall/syscall_wasip1.go index e66afee5e9ad..84c6bddc0897 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_wasip1.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_wasip1.go @@ -97,7 +97,7 @@ func (e Errno) Timeout() bool { } // A Signal is a number describing a process signal. -// It implements the os.Signal interface. +// It implements the [os.Signal] interface. type Signal uint8 const ( @@ -305,7 +305,7 @@ func (w WaitStatus) Continued() bool { return false } func (w WaitStatus) StopSignal() Signal { return 0 } func (w WaitStatus) TrapCause() int { return 0 } -// Rusage is a placeholder to allow compilation of the os/exec package +// Rusage is a placeholder to allow compilation of the [os/exec] package // because we need Go programs to be portable across platforms. WASI does // not have a mechanism to to spawn processes so there is no reason for an // application to take a dependency on this type. @@ -314,7 +314,7 @@ type Rusage struct { Stime Timeval } -// ProcAttr is a placeholder to allow compilation of the os/exec package +// ProcAttr is a placeholder to allow compilation of the [os/exec] package // because we need Go programs to be portable across platforms. WASI does // not have a mechanism to to spawn processes so there is no reason for an // application to take a dependency on this type. diff --git a/contrib/go/_std_1.23/src/syscall/syscall_windows.go b/contrib/go/_std_1.23/src/syscall/syscall_windows.go new file mode 100644 index 000000000000..d49ee522c4fe --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/syscall_windows.go @@ -0,0 +1,1455 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Windows system calls. + +package syscall + +import ( + errorspkg "errors" + "internal/asan" + "internal/bytealg" + "internal/itoa" + "internal/msan" + "internal/oserror" + "internal/race" + "runtime" + "sync" + "unsafe" +) + +type Handle uintptr + +const InvalidHandle = ^Handle(0) + +// StringToUTF16 returns the UTF-16 encoding of the UTF-8 string s, +// with a terminating NUL added. If s contains a NUL byte this +// function panics instead of returning an error. +// +// Deprecated: Use [UTF16FromString] instead. +func StringToUTF16(s string) []uint16 { + a, err := UTF16FromString(s) + if err != nil { + panic("syscall: string with NUL passed to StringToUTF16") + } + return a +} + +// UTF16FromString returns the UTF-16 encoding of the UTF-8 string +// s, with a terminating NUL added. If s contains a NUL byte at any +// location, it returns (nil, [EINVAL]). Unpaired surrogates +// are encoded using WTF-8. +func UTF16FromString(s string) ([]uint16, error) { + if bytealg.IndexByteString(s, 0) != -1 { + return nil, EINVAL + } + // Valid UTF-8 characters between 1 and 3 bytes require one uint16. + // Valid UTF-8 characters of 4 bytes require two uint16. + // Bytes with invalid UTF-8 encoding require maximum one uint16 per byte. + // So the number of UTF-8 code units (len(s)) is always greater or + // equal than the number of UTF-16 code units. + // Also account for the terminating NUL character. + buf := make([]uint16, 0, len(s)+1) + buf = encodeWTF16(s, buf) + return append(buf, 0), nil +} + +// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s, +// with a terminating NUL removed. Unpaired surrogates are decoded +// using WTF-8 instead of UTF-8 encoding. +func UTF16ToString(s []uint16) string { + maxLen := 0 + for i, v := range s { + if v == 0 { + s = s[0:i] + break + } + switch { + case v <= rune1Max: + maxLen += 1 + case v <= rune2Max: + maxLen += 2 + default: + // r is a non-surrogate that decodes to 3 bytes, + // or is an unpaired surrogate (also 3 bytes in WTF-8), + // or is one half of a valid surrogate pair. + // If it is half of a pair, we will add 3 for the second surrogate + // (total of 6) and overestimate by 2 bytes for the pair, + // since the resulting rune only requires 4 bytes. + maxLen += 3 + } + } + buf := decodeWTF16(s, make([]byte, 0, maxLen)) + return unsafe.String(unsafe.SliceData(buf), len(buf)) +} + +// utf16PtrToString is like UTF16ToString, but takes *uint16 +// as a parameter instead of []uint16. +func utf16PtrToString(p *uint16) string { + if p == nil { + return "" + } + end := unsafe.Pointer(p) + n := 0 + for *(*uint16)(end) != 0 { + end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p)) + n++ + } + return UTF16ToString(unsafe.Slice(p, n)) +} + +// StringToUTF16Ptr returns pointer to the UTF-16 encoding of +// the UTF-8 string s, with a terminating NUL added. If s +// contains a NUL byte this function panics instead of +// returning an error. +// +// Deprecated: Use [UTF16PtrFromString] instead. +func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] } + +// UTF16PtrFromString returns pointer to the UTF-16 encoding of +// the UTF-8 string s, with a terminating NUL added. If s +// contains a NUL byte at any location, it returns (nil, EINVAL). +// Unpaired surrogates are encoded using WTF-8. +func UTF16PtrFromString(s string) (*uint16, error) { + a, err := UTF16FromString(s) + if err != nil { + return nil, err + } + return &a[0], nil +} + +// Errno is the Windows error number. +// +// Errno values can be tested against error values using [errors.Is]. +// For example: +// +// _, _, err := syscall.Syscall(...) +// if errors.Is(err, fs.ErrNotExist) ... +type Errno uintptr + +func langid(pri, sub uint16) uint32 { return uint32(sub)<<10 | uint32(pri) } + +// FormatMessage is deprecated (msgsrc should be uintptr, not uint32, but can +// not be changed due to the Go 1 compatibility guarantee). +// +// Deprecated: Use FormatMessage from golang.org/x/sys/windows instead. +func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) { + return formatMessage(flags, uintptr(msgsrc), msgid, langid, buf, args) +} + +func (e Errno) Error() string { + // deal with special go errors + idx := int(e - APPLICATION_ERROR) + if 0 <= idx && idx < len(errors) { + return errors[idx] + } + // ask windows for the remaining errors + var flags uint32 = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_IGNORE_INSERTS + b := make([]uint16, 300) + n, err := formatMessage(flags, 0, uint32(e), langid(LANG_ENGLISH, SUBLANG_ENGLISH_US), b, nil) + if err != nil { + n, err = formatMessage(flags, 0, uint32(e), 0, b, nil) + if err != nil { + return "winapi error #" + itoa.Itoa(int(e)) + } + } + // trim terminating \r and \n + for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- { + } + return UTF16ToString(b[:n]) +} + +const ( + _ERROR_NOT_ENOUGH_MEMORY = Errno(8) + _ERROR_NOT_SUPPORTED = Errno(50) + _ERROR_BAD_NETPATH = Errno(53) + _ERROR_CALL_NOT_IMPLEMENTED = Errno(120) +) + +func (e Errno) Is(target error) bool { + switch target { + case oserror.ErrPermission: + return e == ERROR_ACCESS_DENIED || + e == EACCES || + e == EPERM + case oserror.ErrExist: + return e == ERROR_ALREADY_EXISTS || + e == ERROR_DIR_NOT_EMPTY || + e == ERROR_FILE_EXISTS || + e == EEXIST || + e == ENOTEMPTY + case oserror.ErrNotExist: + return e == ERROR_FILE_NOT_FOUND || + e == _ERROR_BAD_NETPATH || + e == ERROR_PATH_NOT_FOUND || + e == ENOENT + case errorspkg.ErrUnsupported: + return e == _ERROR_NOT_SUPPORTED || + e == _ERROR_CALL_NOT_IMPLEMENTED || + e == ENOSYS || + e == ENOTSUP || + e == EOPNOTSUPP || + e == EWINDOWS + } + return false +} + +func (e Errno) Temporary() bool { + return e == EINTR || e == EMFILE || e.Timeout() +} + +func (e Errno) Timeout() bool { + return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT +} + +// Implemented in runtime/syscall_windows.go. +func compileCallback(fn any, cleanstack bool) uintptr + +// NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention. +// This is useful when interoperating with Windows code requiring callbacks. +// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. +// Only a limited number of callbacks may be created in a single Go process, and any memory allocated +// for these callbacks is never released. +// Between NewCallback and NewCallbackCDecl, at least 1024 callbacks can always be created. +func NewCallback(fn any) uintptr { + return compileCallback(fn, true) +} + +// NewCallbackCDecl converts a Go function to a function pointer conforming to the cdecl calling convention. +// This is useful when interoperating with Windows code requiring callbacks. +// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. +// Only a limited number of callbacks may be created in a single Go process, and any memory allocated +// for these callbacks is never released. +// Between NewCallback and NewCallbackCDecl, at least 1024 callbacks can always be created. +func NewCallbackCDecl(fn any) uintptr { + return compileCallback(fn, false) +} + +// windows api calls + +//sys GetLastError() (lasterr error) +//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW +//sys FreeLibrary(handle Handle) (err error) +//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error) +//sys GetVersion() (ver uint32, err error) +//sys formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW +//sys ExitProcess(exitcode uint32) +//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW +//sys readFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) = ReadFile +//sys writeFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) = WriteFile +//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff] +//sys CloseHandle(handle Handle) (err error) +//sys GetStdHandle(stdhandle int) (handle Handle, err error) [failretval==InvalidHandle] +//sys findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstFileW +//sys findNextFile1(handle Handle, data *win32finddata1) (err error) = FindNextFileW +//sys FindClose(handle Handle) (err error) +//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) +//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW +//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW +//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW +//sys RemoveDirectory(path *uint16) (err error) = RemoveDirectoryW +//sys DeleteFile(path *uint16) (err error) = DeleteFileW +//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW +//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW +//sys SetEndOfFile(handle Handle) (err error) +//sys GetSystemTimeAsFileTime(time *Filetime) +//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] +//sys createIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) = CreateIoCompletionPort +//sys getQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) = GetQueuedCompletionStatus +//sys postQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) = PostQueuedCompletionStatus +//sys CancelIo(s Handle) (err error) +//sys CancelIoEx(s Handle, o *Overlapped) (err error) +//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW +//sys CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = advapi32.CreateProcessAsUserW +//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) +//sys TerminateProcess(handle Handle, exitcode uint32) (err error) +//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) +//sys getStartupInfo(startupInfo *StartupInfo) = GetStartupInfoW +//sys GetCurrentProcess() (pseudoHandle Handle, err error) +//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) +//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) +//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff] +//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW +//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) +//sys GetFileType(filehandle Handle) (n uint32, err error) +//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW +//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext +//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom +//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW +//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW +//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW +//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW +//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) +//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW +//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW +//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW +//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW +//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW +//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0] +//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) +//sys FlushFileBuffers(handle Handle) (err error) +//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW +//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW +//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW +//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW +//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) +//sys UnmapViewOfFile(addr uintptr) (err error) +//sys FlushViewOfFile(addr uintptr, length uintptr) (err error) +//sys VirtualLock(addr uintptr, length uintptr) (err error) +//sys VirtualUnlock(addr uintptr, length uintptr) (err error) +//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile +//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW +//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW +//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) = crypt32.CertOpenStore +//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore +//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore +//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore +//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain +//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain +//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext +//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext +//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy +//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW +//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey +//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW +//sys regEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW +//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW +//sys getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId +//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode +//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW +//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW +//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot +//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW +//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW +//sys DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) +// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL. +//sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW +//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW +//sys initializeProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, attrcount uint32, flags uint32, size *uintptr) (err error) = InitializeProcThreadAttributeList +//sys deleteProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST) = DeleteProcThreadAttributeList +//sys updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) = UpdateProcThreadAttribute +//sys getFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) [n == 0 || n >= filePathSize] = kernel32.GetFinalPathNameByHandleW + +// syscall interface implementation for other packages + +func makeInheritSa() *SecurityAttributes { + var sa SecurityAttributes + sa.Length = uint32(unsafe.Sizeof(sa)) + sa.InheritHandle = 1 + return &sa +} + +func Open(path string, mode int, perm uint32) (fd Handle, err error) { + if len(path) == 0 { + return InvalidHandle, ERROR_FILE_NOT_FOUND + } + pathp, err := UTF16PtrFromString(path) + if err != nil { + return InvalidHandle, err + } + var access uint32 + switch mode & (O_RDONLY | O_WRONLY | O_RDWR) { + case O_RDONLY: + access = GENERIC_READ + case O_WRONLY: + access = GENERIC_WRITE + case O_RDWR: + access = GENERIC_READ | GENERIC_WRITE + } + if mode&O_CREAT != 0 { + access |= GENERIC_WRITE + } + if mode&O_APPEND != 0 { + access &^= GENERIC_WRITE + access |= FILE_APPEND_DATA + } + sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE) + var sa *SecurityAttributes + if mode&O_CLOEXEC == 0 { + sa = makeInheritSa() + } + var createmode uint32 + switch { + case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL): + createmode = CREATE_NEW + case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC): + createmode = CREATE_ALWAYS + case mode&O_CREAT == O_CREAT: + createmode = OPEN_ALWAYS + case mode&O_TRUNC == O_TRUNC: + createmode = TRUNCATE_EXISTING + default: + createmode = OPEN_EXISTING + } + var attrs uint32 = FILE_ATTRIBUTE_NORMAL + if perm&S_IWRITE == 0 { + attrs = FILE_ATTRIBUTE_READONLY + if createmode == CREATE_ALWAYS { + // We have been asked to create a read-only file. + // If the file already exists, the semantics of + // the Unix open system call is to preserve the + // existing permissions. If we pass CREATE_ALWAYS + // and FILE_ATTRIBUTE_READONLY to CreateFile, + // and the file already exists, CreateFile will + // change the file permissions. + // Avoid that to preserve the Unix semantics. + h, e := CreateFile(pathp, access, sharemode, sa, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) + switch e { + case ERROR_FILE_NOT_FOUND, _ERROR_BAD_NETPATH, ERROR_PATH_NOT_FOUND: + // File does not exist. These are the same + // errors as Errno.Is checks for ErrNotExist. + // Carry on to create the file. + default: + // Success or some different error. + return h, e + } + } + } + if createmode == OPEN_EXISTING && access == GENERIC_READ { + // Necessary for opening directory handles. + attrs |= FILE_FLAG_BACKUP_SEMANTICS + } + if mode&O_SYNC != 0 { + const _FILE_FLAG_WRITE_THROUGH = 0x80000000 + attrs |= _FILE_FLAG_WRITE_THROUGH + } + return CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0) +} + +func Read(fd Handle, p []byte) (n int, err error) { + var done uint32 + e := ReadFile(fd, p, &done, nil) + if e != nil { + if e == ERROR_BROKEN_PIPE { + // NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin + return 0, nil + } + return 0, e + } + return int(done), nil +} + +func Write(fd Handle, p []byte) (n int, err error) { + var done uint32 + e := WriteFile(fd, p, &done, nil) + if e != nil { + return 0, e + } + return int(done), nil +} + +func ReadFile(fd Handle, p []byte, done *uint32, overlapped *Overlapped) error { + err := readFile(fd, p, done, overlapped) + if race.Enabled { + if *done > 0 { + race.WriteRange(unsafe.Pointer(&p[0]), int(*done)) + } + race.Acquire(unsafe.Pointer(&ioSync)) + } + if msan.Enabled && *done > 0 { + msan.Write(unsafe.Pointer(&p[0]), uintptr(*done)) + } + if asan.Enabled && *done > 0 { + asan.Write(unsafe.Pointer(&p[0]), uintptr(*done)) + } + return err +} + +func WriteFile(fd Handle, p []byte, done *uint32, overlapped *Overlapped) error { + if race.Enabled { + race.ReleaseMerge(unsafe.Pointer(&ioSync)) + } + err := writeFile(fd, p, done, overlapped) + if race.Enabled && *done > 0 { + race.ReadRange(unsafe.Pointer(&p[0]), int(*done)) + } + if msan.Enabled && *done > 0 { + msan.Read(unsafe.Pointer(&p[0]), uintptr(*done)) + } + if asan.Enabled && *done > 0 { + asan.Read(unsafe.Pointer(&p[0]), uintptr(*done)) + } + return err +} + +var ioSync int64 + +var procSetFilePointerEx = modkernel32.NewProc("SetFilePointerEx") + +const ptrSize = unsafe.Sizeof(uintptr(0)) + +// setFilePointerEx calls SetFilePointerEx. +// See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilepointerex +func setFilePointerEx(handle Handle, distToMove int64, newFilePointer *int64, whence uint32) error { + var e1 Errno + if unsafe.Sizeof(uintptr(0)) == 8 { + _, _, e1 = Syscall6(procSetFilePointerEx.Addr(), 4, uintptr(handle), uintptr(distToMove), uintptr(unsafe.Pointer(newFilePointer)), uintptr(whence), 0, 0) + } else { + // Different 32-bit systems disgaree about whether distToMove starts 8-byte aligned. + switch runtime.GOARCH { + default: + panic("unsupported 32-bit architecture") + case "386": + // distToMove is a LARGE_INTEGER, which is 64 bits. + _, _, e1 = Syscall6(procSetFilePointerEx.Addr(), 5, uintptr(handle), uintptr(distToMove), uintptr(distToMove>>32), uintptr(unsafe.Pointer(newFilePointer)), uintptr(whence), 0) + case "arm": + // distToMove must be 8-byte aligned per ARM calling convention + // https://docs.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions#stage-c-assignment-of-arguments-to-registers-and-stack + _, _, e1 = Syscall6(procSetFilePointerEx.Addr(), 6, uintptr(handle), 0, uintptr(distToMove), uintptr(distToMove>>32), uintptr(unsafe.Pointer(newFilePointer)), uintptr(whence)) + } + } + if e1 != 0 { + return errnoErr(e1) + } + return nil +} + +func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) { + var w uint32 + switch whence { + case 0: + w = FILE_BEGIN + case 1: + w = FILE_CURRENT + case 2: + w = FILE_END + } + err = setFilePointerEx(fd, offset, &newoffset, w) + return +} + +func Close(fd Handle) (err error) { + return CloseHandle(fd) +} + +var ( + Stdin = getStdHandle(STD_INPUT_HANDLE) + Stdout = getStdHandle(STD_OUTPUT_HANDLE) + Stderr = getStdHandle(STD_ERROR_HANDLE) +) + +func getStdHandle(h int) (fd Handle) { + r, _ := GetStdHandle(h) + return r +} + +const ImplementsGetwd = true + +func Getwd() (wd string, err error) { + b := make([]uint16, 300) + // The path of the current directory may not fit in the initial 300-word + // buffer when long path support is enabled. The current directory may also + // change between subsequent calls of GetCurrentDirectory. As a result, we + // need to retry the call in a loop until the current directory fits, each + // time with a bigger buffer. + for { + n, e := GetCurrentDirectory(uint32(len(b)), &b[0]) + if e != nil { + return "", e + } + if int(n) <= len(b) { + return UTF16ToString(b[:n]), nil + } + b = make([]uint16, n) + } +} + +func Chdir(path string) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return SetCurrentDirectory(pathp) +} + +func Mkdir(path string, mode uint32) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return CreateDirectory(pathp, nil) +} + +func Rmdir(path string) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return RemoveDirectory(pathp) +} + +func Unlink(path string) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return DeleteFile(pathp) +} + +func Rename(oldpath, newpath string) (err error) { + from, err := UTF16PtrFromString(oldpath) + if err != nil { + return err + } + to, err := UTF16PtrFromString(newpath) + if err != nil { + return err + } + return MoveFile(from, to) +} + +func ComputerName() (name string, err error) { + var n uint32 = MAX_COMPUTERNAME_LENGTH + 1 + b := make([]uint16, n) + e := GetComputerName(&b[0], &n) + if e != nil { + return "", e + } + return UTF16ToString(b[:n]), nil +} + +func Ftruncate(fd Handle, length int64) (err error) { + curoffset, e := Seek(fd, 0, 1) + if e != nil { + return e + } + defer Seek(fd, curoffset, 0) + _, e = Seek(fd, length, 0) + if e != nil { + return e + } + e = SetEndOfFile(fd) + if e != nil { + return e + } + return nil +} + +func Gettimeofday(tv *Timeval) (err error) { + var ft Filetime + GetSystemTimeAsFileTime(&ft) + *tv = NsecToTimeval(ft.Nanoseconds()) + return nil +} + +func Pipe(p []Handle) (err error) { + if len(p) != 2 { + return EINVAL + } + var r, w Handle + e := CreatePipe(&r, &w, makeInheritSa(), 0) + if e != nil { + return e + } + p[0] = r + p[1] = w + return nil +} + +func Utimes(path string, tv []Timeval) (err error) { + if len(tv) != 2 { + return EINVAL + } + pathp, e := UTF16PtrFromString(path) + if e != nil { + return e + } + h, e := CreateFile(pathp, + FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) + if e != nil { + return e + } + defer Close(h) + a := Filetime{} + w := Filetime{} + if tv[0].Nanoseconds() != 0 { + a = NsecToFiletime(tv[0].Nanoseconds()) + } + if tv[0].Nanoseconds() != 0 { + w = NsecToFiletime(tv[1].Nanoseconds()) + } + return SetFileTime(h, nil, &a, &w) +} + +// This matches the value in os/file_windows.go. +const _UTIME_OMIT = -1 + +func UtimesNano(path string, ts []Timespec) (err error) { + if len(ts) != 2 { + return EINVAL + } + pathp, e := UTF16PtrFromString(path) + if e != nil { + return e + } + h, e := CreateFile(pathp, + FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) + if e != nil { + return e + } + defer Close(h) + a := Filetime{} + w := Filetime{} + if ts[0].Nsec != _UTIME_OMIT { + a = NsecToFiletime(TimespecToNsec(ts[0])) + } + if ts[1].Nsec != _UTIME_OMIT { + w = NsecToFiletime(TimespecToNsec(ts[1])) + } + return SetFileTime(h, nil, &a, &w) +} + +func Fsync(fd Handle) (err error) { + return FlushFileBuffers(fd) +} + +func Chmod(path string, mode uint32) (err error) { + p, e := UTF16PtrFromString(path) + if e != nil { + return e + } + attrs, e := GetFileAttributes(p) + if e != nil { + return e + } + if mode&S_IWRITE != 0 { + attrs &^= FILE_ATTRIBUTE_READONLY + } else { + attrs |= FILE_ATTRIBUTE_READONLY + } + return SetFileAttributes(p, attrs) +} + +func LoadCancelIoEx() error { + return procCancelIoEx.Find() +} + +func LoadSetFileCompletionNotificationModes() error { + return procSetFileCompletionNotificationModes.Find() +} + +// net api calls + +const socket_error = uintptr(^uint32(0)) + +//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup +//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup +//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl +//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket +//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt +//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt +//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind +//sys connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect +//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname +//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername +//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen +//sys shutdown(s Handle, how int32) (err error) [failretval==socket_error] = ws2_32.shutdown +//sys Closesocket(s Handle) (err error) [failretval==socket_error] = ws2_32.closesocket +//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx +//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs +//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecv +//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASend +//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom +//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo +//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname +//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname +//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs +//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname +//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W +//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree +//sys DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) = dnsapi.DnsNameCompare_W +//sys GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW +//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW +//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry +//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo +//sys SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) = kernel32.SetFileCompletionNotificationModes +//sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW + +// For testing: clients can set this flag to force +// creation of IPv6 sockets to return [EAFNOSUPPORT]. +var SocketDisableIPv6 bool + +type RawSockaddrInet4 struct { + Family uint16 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]uint8 +} + +type RawSockaddrInet6 struct { + Family uint16 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddr struct { + Family uint16 + Data [14]int8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [100]int8 +} + +type Sockaddr interface { + sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs +} + +type SockaddrInet4 struct { + Port int + Addr [4]byte + raw RawSockaddrInet4 +} + +func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, EINVAL + } + sa.raw.Family = AF_INET + p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + sa.raw.Addr = sa.Addr + return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil +} + +type SockaddrInet6 struct { + Port int + ZoneId uint32 + Addr [16]byte + raw RawSockaddrInet6 +} + +func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, EINVAL + } + sa.raw.Family = AF_INET6 + p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + sa.raw.Scope_id = sa.ZoneId + sa.raw.Addr = sa.Addr + return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil +} + +type RawSockaddrUnix struct { + Family uint16 + Path [UNIX_PATH_MAX]int8 +} + +type SockaddrUnix struct { + Name string + raw RawSockaddrUnix +} + +func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) { + name := sa.Name + n := len(name) + if n > len(sa.raw.Path) { + return nil, 0, EINVAL + } + if n == len(sa.raw.Path) && name[0] != '@' { + return nil, 0, EINVAL + } + sa.raw.Family = AF_UNIX + for i := 0; i < n; i++ { + sa.raw.Path[i] = int8(name[i]) + } + // length is family (uint16), name, NUL. + sl := int32(2) + if n > 0 { + sl += int32(n) + 1 + } + if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) { + // Check sl > 3 so we don't change unnamed socket behavior. + sa.raw.Path[0] = 0 + // Don't count trailing NUL for abstract address. + sl-- + } + + return unsafe.Pointer(&sa.raw), sl, nil +} + +func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) { + switch rsa.Addr.Family { + case AF_UNIX: + pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa)) + sa := new(SockaddrUnix) + if pp.Path[0] == 0 { + // "Abstract" Unix domain socket. + // Rewrite leading NUL as @ for textual display. + // (This is the standard convention.) + // Not friendly to overwrite in place, + // but the callers below don't care. + pp.Path[0] = '@' + } + + // Assume path ends at NUL. + // This is not technically the Linux semantics for + // abstract Unix domain sockets--they are supposed + // to be uninterpreted fixed-size binary blobs--but + // everyone uses this convention. + n := 0 + for n < len(pp.Path) && pp.Path[n] != 0 { + n++ + } + sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n)) + return sa, nil + + case AF_INET: + pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) + sa := new(SockaddrInet4) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + sa.Addr = pp.Addr + return sa, nil + + case AF_INET6: + pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)) + sa := new(SockaddrInet6) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + sa.ZoneId = pp.Scope_id + sa.Addr = pp.Addr + return sa, nil + } + return nil, EAFNOSUPPORT +} + +func Socket(domain, typ, proto int) (fd Handle, err error) { + if domain == AF_INET6 && SocketDisableIPv6 { + return InvalidHandle, EAFNOSUPPORT + } + return socket(int32(domain), int32(typ), int32(proto)) +} + +func SetsockoptInt(fd Handle, level, opt int, value int) (err error) { + v := int32(value) + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))) +} + +func Bind(fd Handle, sa Sockaddr) (err error) { + ptr, n, err := sa.sockaddr() + if err != nil { + return err + } + return bind(fd, ptr, n) +} + +func Connect(fd Handle, sa Sockaddr) (err error) { + ptr, n, err := sa.sockaddr() + if err != nil { + return err + } + return connect(fd, ptr, n) +} + +func Getsockname(fd Handle) (sa Sockaddr, err error) { + var rsa RawSockaddrAny + l := int32(unsafe.Sizeof(rsa)) + if err = getsockname(fd, &rsa, &l); err != nil { + return + } + return rsa.Sockaddr() +} + +func Getpeername(fd Handle) (sa Sockaddr, err error) { + var rsa RawSockaddrAny + l := int32(unsafe.Sizeof(rsa)) + if err = getpeername(fd, &rsa, &l); err != nil { + return + } + return rsa.Sockaddr() +} + +func Listen(s Handle, n int) (err error) { + return listen(s, int32(n)) +} + +func Shutdown(fd Handle, how int) (err error) { + return shutdown(fd, int32(how)) +} + +func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (err error) { + var rsa unsafe.Pointer + var len int32 + if to != nil { + rsa, len, err = to.sockaddr() + if err != nil { + return err + } + } + r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = EINVAL + } + } + return err +} + +func wsaSendtoInet4(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *SockaddrInet4, overlapped *Overlapped, croutine *byte) (err error) { + rsa, len, err := to.sockaddr() + if err != nil { + return err + } + r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = EINVAL + } + } + return err +} + +func wsaSendtoInet6(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *SockaddrInet6, overlapped *Overlapped, croutine *byte) (err error) { + rsa, len, err := to.sockaddr() + if err != nil { + return err + } + r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = EINVAL + } + } + return err +} + +func LoadGetAddrInfo() error { + return procGetAddrInfoW.Find() +} + +var connectExFunc struct { + once sync.Once + addr uintptr + err error +} + +func LoadConnectEx() error { + connectExFunc.once.Do(func() { + var s Handle + s, connectExFunc.err = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) + if connectExFunc.err != nil { + return + } + defer CloseHandle(s) + var n uint32 + connectExFunc.err = WSAIoctl(s, + SIO_GET_EXTENSION_FUNCTION_POINTER, + (*byte)(unsafe.Pointer(&WSAID_CONNECTEX)), + uint32(unsafe.Sizeof(WSAID_CONNECTEX)), + (*byte)(unsafe.Pointer(&connectExFunc.addr)), + uint32(unsafe.Sizeof(connectExFunc.addr)), + &n, nil, 0) + }) + return connectExFunc.err +} + +func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = EINVAL + } + } + return +} + +func ConnectEx(fd Handle, sa Sockaddr, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) error { + err := LoadConnectEx() + if err != nil { + return errorspkg.New("failed to find ConnectEx: " + err.Error()) + } + ptr, n, err := sa.sockaddr() + if err != nil { + return err + } + return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped) +} + +// Invented structures to support what package os expects. +type Rusage struct { + CreationTime Filetime + ExitTime Filetime + KernelTime Filetime + UserTime Filetime +} + +type WaitStatus struct { + ExitCode uint32 +} + +func (w WaitStatus) Exited() bool { return true } + +func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) } + +func (w WaitStatus) Signal() Signal { return -1 } + +func (w WaitStatus) CoreDump() bool { return false } + +func (w WaitStatus) Stopped() bool { return false } + +func (w WaitStatus) Continued() bool { return false } + +func (w WaitStatus) StopSignal() Signal { return -1 } + +func (w WaitStatus) Signaled() bool { return false } + +func (w WaitStatus) TrapCause() int { return -1 } + +// Timespec is an invented structure on Windows, but here for +// consistency with the syscall package for other operating systems. +type Timespec struct { + Sec int64 + Nsec int64 +} + +func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } + +func NsecToTimespec(nsec int64) (ts Timespec) { + ts.Sec = nsec / 1e9 + ts.Nsec = nsec % 1e9 + return +} + +// TODO(brainman): fix all needed for net + +func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, EWINDOWS } +func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) { + return 0, nil, EWINDOWS +} +func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return EWINDOWS } +func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return EWINDOWS } + +// The Linger struct is wrong but we only noticed after Go 1. +// sysLinger is the real system call structure. + +// BUG(brainman): The definition of Linger is not appropriate for direct use +// with Setsockopt and Getsockopt. +// Use SetsockoptLinger instead. + +type Linger struct { + Onoff int32 + Linger int32 +} + +type sysLinger struct { + Onoff uint16 + Linger uint16 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +func GetsockoptInt(fd Handle, level, opt int) (int, error) { + optval := int32(0) + optlen := int32(unsafe.Sizeof(optval)) + err := Getsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&optval)), &optlen) + return int(optval), err +} + +func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { + sys := sysLinger{Onoff: uint16(l.Onoff), Linger: uint16(l.Linger)} + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&sys)), int32(unsafe.Sizeof(sys))) +} + +func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) { + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4) +} +func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) { + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq))) +} +func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) { return EWINDOWS } + +func Getpid() (pid int) { return int(getCurrentProcessId()) } + +func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) { + // NOTE(rsc): The Win32finddata struct is wrong for the system call: + // the two paths are each one uint16 short. Use the correct struct, + // a win32finddata1, and then copy the results out. + // There is no loss of expressivity here, because the final + // uint16, if it is used, is supposed to be a NUL, and Go doesn't need that. + // For Go 1.1, we might avoid the allocation of win32finddata1 here + // by adding a final Bug [2]uint16 field to the struct and then + // adjusting the fields in the result directly. + var data1 win32finddata1 + handle, err = findFirstFile1(name, &data1) + if err == nil { + copyFindData(data, &data1) + } + return +} + +func FindNextFile(handle Handle, data *Win32finddata) (err error) { + var data1 win32finddata1 + err = findNextFile1(handle, &data1) + if err == nil { + copyFindData(data, &data1) + } + return +} + +func getProcessEntry(pid int) (*ProcessEntry32, error) { + snapshot, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) + if err != nil { + return nil, err + } + defer CloseHandle(snapshot) + var procEntry ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + if err = Process32First(snapshot, &procEntry); err != nil { + return nil, err + } + for { + if procEntry.ProcessID == uint32(pid) { + return &procEntry, nil + } + err = Process32Next(snapshot, &procEntry) + if err != nil { + return nil, err + } + } +} + +func Getppid() (ppid int) { + pe, err := getProcessEntry(Getpid()) + if err != nil { + return -1 + } + return int(pe.ParentProcessID) +} + +func fdpath(fd Handle, buf []uint16) ([]uint16, error) { + const ( + FILE_NAME_NORMALIZED = 0 + VOLUME_NAME_DOS = 0 + ) + for { + n, err := getFinalPathNameByHandle(fd, &buf[0], uint32(len(buf)), FILE_NAME_NORMALIZED|VOLUME_NAME_DOS) + if err == nil { + buf = buf[:n] + break + } + if err != _ERROR_NOT_ENOUGH_MEMORY { + return nil, err + } + buf = append(buf, make([]uint16, n-uint32(len(buf)))...) + } + return buf, nil +} + +func Fchdir(fd Handle) (err error) { + var buf [MAX_PATH + 1]uint16 + path, err := fdpath(fd, buf[:]) + if err != nil { + return err + } + // When using VOLUME_NAME_DOS, the path is always prefixed by "\\?\". + // That prefix tells the Windows APIs to disable all string parsing and to send + // the string that follows it straight to the file system. + // Although SetCurrentDirectory and GetCurrentDirectory do support the "\\?\" prefix, + // some other Windows APIs don't. If the prefix is not removed here, it will leak + // to Getwd, and we don't want such a general-purpose function to always return a + // path with the "\\?\" prefix after Fchdir is called. + // The downside is that APIs that do support it will parse the path and try to normalize it, + // when it's already normalized. + if len(path) >= 4 && path[0] == '\\' && path[1] == '\\' && path[2] == '?' && path[3] == '\\' { + path = path[4:] + } + return SetCurrentDirectory(&path[0]) +} + +// TODO(brainman): fix all needed for os +func Link(oldpath, newpath string) (err error) { return EWINDOWS } +func Symlink(path, link string) (err error) { return EWINDOWS } + +func Fchmod(fd Handle, mode uint32) (err error) { return EWINDOWS } +func Chown(path string, uid int, gid int) (err error) { return EWINDOWS } +func Lchown(path string, uid int, gid int) (err error) { return EWINDOWS } +func Fchown(fd Handle, uid int, gid int) (err error) { return EWINDOWS } + +func Getuid() (uid int) { return -1 } +func Geteuid() (euid int) { return -1 } +func Getgid() (gid int) { return -1 } +func Getegid() (egid int) { return -1 } +func Getgroups() (gids []int, err error) { return nil, EWINDOWS } + +type Signal int + +func (s Signal) Signal() {} + +func (s Signal) String() string { + if 0 <= s && int(s) < len(signals) { + str := signals[s] + if str != "" { + return str + } + } + return "signal " + itoa.Itoa(int(s)) +} + +func LoadCreateSymbolicLink() error { + return procCreateSymbolicLinkW.Find() +} + +// Readlink returns the destination of the named symbolic link. +func Readlink(path string, buf []byte) (n int, err error) { + fd, err := CreateFile(StringToUTF16Ptr(path), GENERIC_READ, 0, nil, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0) + if err != nil { + return -1, err + } + defer CloseHandle(fd) + + rdbbuf := make([]byte, MAXIMUM_REPARSE_DATA_BUFFER_SIZE) + var bytesReturned uint32 + err = DeviceIoControl(fd, FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil) + if err != nil { + return -1, err + } + + rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0])) + var s string + switch rdb.ReparseTag { + case IO_REPARSE_TAG_SYMLINK: + data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) + p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) + s = UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) + if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 { + if len(s) >= 4 && s[:4] == `\??\` { + s = s[4:] + switch { + case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar + // do nothing + case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar + s = `\\` + s[4:] + default: + // unexpected; do nothing + } + } else { + // unexpected; do nothing + } + } + case _IO_REPARSE_TAG_MOUNT_POINT: + data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) + p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) + s = UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) + if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar + s = s[4:] + } else { + // unexpected; do nothing + } + default: + // the path is not a symlink or junction but another type of reparse + // point + return -1, ENOENT + } + n = copy(buf, []byte(s)) + + return n, nil +} + +// Deprecated: CreateIoCompletionPort has the wrong function signature. Use x/sys/windows.CreateIoCompletionPort. +func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (Handle, error) { + return createIoCompletionPort(filehandle, cphandle, uintptr(key), threadcnt) +} + +// Deprecated: GetQueuedCompletionStatus has the wrong function signature. Use x/sys/windows.GetQueuedCompletionStatus. +func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) error { + var ukey uintptr + var pukey *uintptr + if key != nil { + ukey = uintptr(*key) + pukey = &ukey + } + err := getQueuedCompletionStatus(cphandle, qty, pukey, overlapped, timeout) + if key != nil { + *key = uint32(ukey) + if uintptr(*key) != ukey && err == nil { + err = errorspkg.New("GetQueuedCompletionStatus returned key overflow") + } + } + return err +} + +// Deprecated: PostQueuedCompletionStatus has the wrong function signature. Use x/sys/windows.PostQueuedCompletionStatus. +func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) error { + return postQueuedCompletionStatus(cphandle, qty, uintptr(key), overlapped) +} + +// newProcThreadAttributeList allocates new PROC_THREAD_ATTRIBUTE_LIST, with +// the requested maximum number of attributes, which must be cleaned up by +// deleteProcThreadAttributeList. +func newProcThreadAttributeList(maxAttrCount uint32) (*_PROC_THREAD_ATTRIBUTE_LIST, error) { + var size uintptr + err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size) + if err != ERROR_INSUFFICIENT_BUFFER { + if err == nil { + return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList") + } + return nil, err + } + // size is guaranteed to be ≥1 by initializeProcThreadAttributeList. + al := (*_PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(&make([]byte, size)[0])) + err = initializeProcThreadAttributeList(al, maxAttrCount, 0, &size) + if err != nil { + return nil, err + } + return al, nil +} + +// RegEnumKeyEx enumerates the subkeys of an open registry key. +// Each call retrieves information about one subkey. name is +// a buffer that should be large enough to hold the name of the +// subkey plus a null terminating character. nameLen is its +// length. On return, nameLen will contain the actual length of the +// subkey. +// +// Should name not be large enough to hold the subkey, this function +// will return ERROR_MORE_DATA, and must be called again with an +// appropriately sized buffer. +// +// reserved must be nil. class and classLen behave like name and nameLen +// but for the class of the subkey, except that they are optional. +// lastWriteTime, if not nil, will be populated with the time the subkey +// was last written. +// +// The caller must enumerate all subkeys in order. That is +// RegEnumKeyEx must be called with index starting at 0, incrementing +// the index until the function returns ERROR_NO_MORE_ITEMS, or with +// the index of the last subkey (obtainable from RegQueryInfoKey), +// decrementing until index 0 is enumerated. +// +// Successive calls to this API must happen on the same OS thread, +// so call [runtime.LockOSThread] before calling this function. +func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) { + return regEnumKeyEx(key, index, name, nameLen, reserved, class, classLen, lastWriteTime) +} + +func GetStartupInfo(startupInfo *StartupInfo) error { + getStartupInfo(startupInfo) + return nil +} diff --git a/contrib/go/_std_1.22/src/syscall/tables_js.go b/contrib/go/_std_1.23/src/syscall/tables_js.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/tables_js.go rename to contrib/go/_std_1.23/src/syscall/tables_js.go diff --git a/contrib/go/_std_1.22/src/syscall/tables_wasip1.go b/contrib/go/_std_1.23/src/syscall/tables_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/tables_wasip1.go rename to contrib/go/_std_1.23/src/syscall/tables_wasip1.go diff --git a/contrib/go/_std_1.22/src/syscall/time_fake.go b/contrib/go/_std_1.23/src/syscall/time_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/time_fake.go rename to contrib/go/_std_1.23/src/syscall/time_fake.go diff --git a/contrib/go/_std_1.22/src/syscall/time_nofake.go b/contrib/go/_std_1.23/src/syscall/time_nofake.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/time_nofake.go rename to contrib/go/_std_1.23/src/syscall/time_nofake.go diff --git a/contrib/go/_std_1.22/src/syscall/timestruct.go b/contrib/go/_std_1.23/src/syscall/timestruct.go similarity index 85% rename from contrib/go/_std_1.22/src/syscall/timestruct.go rename to contrib/go/_std_1.23/src/syscall/timestruct.go index 4fca63cc40cc..b1d03ef25c48 100644 --- a/contrib/go/_std_1.22/src/syscall/timestruct.go +++ b/contrib/go/_std_1.23/src/syscall/timestruct.go @@ -9,7 +9,7 @@ package syscall // TimespecToNsec returns the time stored in ts as nanoseconds. func TimespecToNsec(ts Timespec) int64 { return ts.Nano() } -// NsecToTimespec converts a number of nanoseconds into a Timespec. +// NsecToTimespec converts a number of nanoseconds into a [Timespec]. func NsecToTimespec(nsec int64) Timespec { sec := nsec / 1e9 nsec = nsec % 1e9 @@ -23,7 +23,7 @@ func NsecToTimespec(nsec int64) Timespec { // TimevalToNsec returns the time stored in tv as nanoseconds. func TimevalToNsec(tv Timeval) int64 { return tv.Nano() } -// NsecToTimeval converts a number of nanoseconds into a Timeval. +// NsecToTimeval converts a number of nanoseconds into a [Timeval]. func NsecToTimeval(nsec int64) Timeval { nsec += 999 // round up to microsecond usec := nsec % 1e9 / 1e3 diff --git a/contrib/go/_std_1.22/src/syscall/types_aix.go b/contrib/go/_std_1.23/src/syscall/types_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_aix.go rename to contrib/go/_std_1.23/src/syscall/types_aix.go diff --git a/contrib/go/_std_1.22/src/syscall/types_darwin.go b/contrib/go/_std_1.23/src/syscall/types_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_darwin.go rename to contrib/go/_std_1.23/src/syscall/types_darwin.go diff --git a/contrib/go/_std_1.22/src/syscall/types_dragonfly.go b/contrib/go/_std_1.23/src/syscall/types_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_dragonfly.go rename to contrib/go/_std_1.23/src/syscall/types_dragonfly.go diff --git a/contrib/go/_std_1.22/src/syscall/types_freebsd.go b/contrib/go/_std_1.23/src/syscall/types_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_freebsd.go rename to contrib/go/_std_1.23/src/syscall/types_freebsd.go diff --git a/contrib/go/_std_1.22/src/syscall/types_illumos_amd64.go b/contrib/go/_std_1.23/src/syscall/types_illumos_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_illumos_amd64.go rename to contrib/go/_std_1.23/src/syscall/types_illumos_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/types_linux.go b/contrib/go/_std_1.23/src/syscall/types_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_linux.go rename to contrib/go/_std_1.23/src/syscall/types_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/types_netbsd.go b/contrib/go/_std_1.23/src/syscall/types_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_netbsd.go rename to contrib/go/_std_1.23/src/syscall/types_netbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/types_openbsd.go b/contrib/go/_std_1.23/src/syscall/types_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_openbsd.go rename to contrib/go/_std_1.23/src/syscall/types_openbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/types_solaris.go b/contrib/go/_std_1.23/src/syscall/types_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_solaris.go rename to contrib/go/_std_1.23/src/syscall/types_solaris.go diff --git a/contrib/go/_std_1.23/src/syscall/types_windows.go b/contrib/go/_std_1.23/src/syscall/types_windows.go new file mode 100644 index 000000000000..6743675b9590 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/types_windows.go @@ -0,0 +1,1171 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + // Windows errors. + ERROR_FILE_NOT_FOUND Errno = 2 + ERROR_PATH_NOT_FOUND Errno = 3 + ERROR_ACCESS_DENIED Errno = 5 + ERROR_NO_MORE_FILES Errno = 18 + ERROR_HANDLE_EOF Errno = 38 + ERROR_NETNAME_DELETED Errno = 64 + ERROR_FILE_EXISTS Errno = 80 + ERROR_BROKEN_PIPE Errno = 109 + ERROR_BUFFER_OVERFLOW Errno = 111 + ERROR_INSUFFICIENT_BUFFER Errno = 122 + ERROR_MOD_NOT_FOUND Errno = 126 + ERROR_PROC_NOT_FOUND Errno = 127 + ERROR_DIR_NOT_EMPTY Errno = 145 + ERROR_ALREADY_EXISTS Errno = 183 + ERROR_ENVVAR_NOT_FOUND Errno = 203 + ERROR_MORE_DATA Errno = 234 + ERROR_OPERATION_ABORTED Errno = 995 + ERROR_IO_PENDING Errno = 997 + ERROR_NOT_FOUND Errno = 1168 + ERROR_PRIVILEGE_NOT_HELD Errno = 1314 + WSAEACCES Errno = 10013 + WSAENOPROTOOPT Errno = 10042 + WSAECONNABORTED Errno = 10053 + WSAECONNRESET Errno = 10054 +) + +const ( + // Invented values to support what package os expects. + O_RDONLY = 0x00000 + O_WRONLY = 0x00001 + O_RDWR = 0x00002 + O_CREAT = 0x00040 + O_EXCL = 0x00080 + O_NOCTTY = 0x00100 + O_TRUNC = 0x00200 + O_NONBLOCK = 0x00800 + O_APPEND = 0x00400 + O_SYNC = 0x01000 + O_ASYNC = 0x02000 + O_CLOEXEC = 0x80000 +) + +const ( + // More invented values for signals + SIGHUP = Signal(0x1) + SIGINT = Signal(0x2) + SIGQUIT = Signal(0x3) + SIGILL = Signal(0x4) + SIGTRAP = Signal(0x5) + SIGABRT = Signal(0x6) + SIGBUS = Signal(0x7) + SIGFPE = Signal(0x8) + SIGKILL = Signal(0x9) + SIGSEGV = Signal(0xb) + SIGPIPE = Signal(0xd) + SIGALRM = Signal(0xe) + SIGTERM = Signal(0xf) +) + +var signals = [...]string{ + 1: "hangup", + 2: "interrupt", + 3: "quit", + 4: "illegal instruction", + 5: "trace/breakpoint trap", + 6: "aborted", + 7: "bus error", + 8: "floating point exception", + 9: "killed", + 10: "user defined signal 1", + 11: "segmentation fault", + 12: "user defined signal 2", + 13: "broken pipe", + 14: "alarm clock", + 15: "terminated", +} + +const ( + GENERIC_READ = 0x80000000 + GENERIC_WRITE = 0x40000000 + GENERIC_EXECUTE = 0x20000000 + GENERIC_ALL = 0x10000000 + + FILE_LIST_DIRECTORY = 0x00000001 + FILE_APPEND_DATA = 0x00000004 + FILE_WRITE_ATTRIBUTES = 0x00000100 + + FILE_SHARE_READ = 0x00000001 + FILE_SHARE_WRITE = 0x00000002 + FILE_SHARE_DELETE = 0x00000004 + FILE_ATTRIBUTE_READONLY = 0x00000001 + FILE_ATTRIBUTE_HIDDEN = 0x00000002 + FILE_ATTRIBUTE_SYSTEM = 0x00000004 + FILE_ATTRIBUTE_DIRECTORY = 0x00000010 + FILE_ATTRIBUTE_ARCHIVE = 0x00000020 + FILE_ATTRIBUTE_NORMAL = 0x00000080 + FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 + + INVALID_FILE_ATTRIBUTES = 0xffffffff + + CREATE_NEW = 1 + CREATE_ALWAYS = 2 + OPEN_EXISTING = 3 + OPEN_ALWAYS = 4 + TRUNCATE_EXISTING = 5 + + FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 + FILE_FLAG_OVERLAPPED = 0x40000000 + + HANDLE_FLAG_INHERIT = 0x00000001 + STARTF_USESTDHANDLES = 0x00000100 + STARTF_USESHOWWINDOW = 0x00000001 + DUPLICATE_CLOSE_SOURCE = 0x00000001 + DUPLICATE_SAME_ACCESS = 0x00000002 + + STD_INPUT_HANDLE = -10 + STD_OUTPUT_HANDLE = -11 + STD_ERROR_HANDLE = -12 + + FILE_BEGIN = 0 + FILE_CURRENT = 1 + FILE_END = 2 + + LANG_ENGLISH = 0x09 + SUBLANG_ENGLISH_US = 0x01 + + FORMAT_MESSAGE_ALLOCATE_BUFFER = 256 + FORMAT_MESSAGE_IGNORE_INSERTS = 512 + FORMAT_MESSAGE_FROM_STRING = 1024 + FORMAT_MESSAGE_FROM_HMODULE = 2048 + FORMAT_MESSAGE_FROM_SYSTEM = 4096 + FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192 + FORMAT_MESSAGE_MAX_WIDTH_MASK = 255 + + MAX_PATH = 260 + MAX_LONG_PATH = 32768 + + MAX_COMPUTERNAME_LENGTH = 15 + + TIME_ZONE_ID_UNKNOWN = 0 + TIME_ZONE_ID_STANDARD = 1 + + TIME_ZONE_ID_DAYLIGHT = 2 + IGNORE = 0 + INFINITE = 0xffffffff + + WAIT_TIMEOUT = 258 + WAIT_ABANDONED = 0x00000080 + WAIT_OBJECT_0 = 0x00000000 + WAIT_FAILED = 0xFFFFFFFF + + CREATE_NEW_PROCESS_GROUP = 0x00000200 + CREATE_UNICODE_ENVIRONMENT = 0x00000400 + + PROCESS_TERMINATE = 1 + PROCESS_QUERY_INFORMATION = 0x00000400 + SYNCHRONIZE = 0x00100000 + + PAGE_READONLY = 0x02 + PAGE_READWRITE = 0x04 + PAGE_WRITECOPY = 0x08 + PAGE_EXECUTE_READ = 0x20 + PAGE_EXECUTE_READWRITE = 0x40 + PAGE_EXECUTE_WRITECOPY = 0x80 + + FILE_MAP_COPY = 0x01 + FILE_MAP_WRITE = 0x02 + FILE_MAP_READ = 0x04 + FILE_MAP_EXECUTE = 0x20 + + CTRL_C_EVENT = 0 + CTRL_BREAK_EVENT = 1 + CTRL_CLOSE_EVENT = 2 + CTRL_LOGOFF_EVENT = 5 + CTRL_SHUTDOWN_EVENT = 6 +) + +const ( + // flags for CreateToolhelp32Snapshot + TH32CS_SNAPHEAPLIST = 0x01 + TH32CS_SNAPPROCESS = 0x02 + TH32CS_SNAPTHREAD = 0x04 + TH32CS_SNAPMODULE = 0x08 + TH32CS_SNAPMODULE32 = 0x10 + TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD + TH32CS_INHERIT = 0x80000000 +) + +const ( + // do not reorder + FILE_NOTIFY_CHANGE_FILE_NAME = 1 << iota + FILE_NOTIFY_CHANGE_DIR_NAME + FILE_NOTIFY_CHANGE_ATTRIBUTES + FILE_NOTIFY_CHANGE_SIZE + FILE_NOTIFY_CHANGE_LAST_WRITE + FILE_NOTIFY_CHANGE_LAST_ACCESS + FILE_NOTIFY_CHANGE_CREATION +) + +const ( + // do not reorder + FILE_ACTION_ADDED = iota + 1 + FILE_ACTION_REMOVED + FILE_ACTION_MODIFIED + FILE_ACTION_RENAMED_OLD_NAME + FILE_ACTION_RENAMED_NEW_NAME +) + +const ( + // wincrypt.h + PROV_RSA_FULL = 1 + PROV_RSA_SIG = 2 + PROV_DSS = 3 + PROV_FORTEZZA = 4 + PROV_MS_EXCHANGE = 5 + PROV_SSL = 6 + PROV_RSA_SCHANNEL = 12 + PROV_DSS_DH = 13 + PROV_EC_ECDSA_SIG = 14 + PROV_EC_ECNRA_SIG = 15 + PROV_EC_ECDSA_FULL = 16 + PROV_EC_ECNRA_FULL = 17 + PROV_DH_SCHANNEL = 18 + PROV_SPYRUS_LYNKS = 20 + PROV_RNG = 21 + PROV_INTEL_SEC = 22 + PROV_REPLACE_OWF = 23 + PROV_RSA_AES = 24 + CRYPT_VERIFYCONTEXT = 0xF0000000 + CRYPT_NEWKEYSET = 0x00000008 + CRYPT_DELETEKEYSET = 0x00000010 + CRYPT_MACHINE_KEYSET = 0x00000020 + CRYPT_SILENT = 0x00000040 + CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080 + + USAGE_MATCH_TYPE_AND = 0 + USAGE_MATCH_TYPE_OR = 1 + + X509_ASN_ENCODING = 0x00000001 + PKCS_7_ASN_ENCODING = 0x00010000 + + CERT_STORE_PROV_MEMORY = 2 + + CERT_STORE_ADD_ALWAYS = 4 + + CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004 + + CERT_TRUST_NO_ERROR = 0x00000000 + CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001 + CERT_TRUST_IS_REVOKED = 0x00000004 + CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008 + CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010 + CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020 + CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040 + CERT_TRUST_IS_CYCLIC = 0x00000080 + CERT_TRUST_INVALID_EXTENSION = 0x00000100 + CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200 + CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400 + CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800 + CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000 + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000 + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000 + CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000 + CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000 + CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000 + CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000 + CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000 + + CERT_CHAIN_POLICY_BASE = 1 + CERT_CHAIN_POLICY_AUTHENTICODE = 2 + CERT_CHAIN_POLICY_AUTHENTICODE_TS = 3 + CERT_CHAIN_POLICY_SSL = 4 + CERT_CHAIN_POLICY_BASIC_CONSTRAINTS = 5 + CERT_CHAIN_POLICY_NT_AUTH = 6 + CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7 + CERT_CHAIN_POLICY_EV = 8 + + CERT_E_EXPIRED = 0x800B0101 + CERT_E_ROLE = 0x800B0103 + CERT_E_PURPOSE = 0x800B0106 + CERT_E_UNTRUSTEDROOT = 0x800B0109 + CERT_E_CN_NO_MATCH = 0x800B010F + + AUTHTYPE_CLIENT = 1 + AUTHTYPE_SERVER = 2 +) + +var ( + OID_PKIX_KP_SERVER_AUTH = []byte("1.3.6.1.5.5.7.3.1\x00") + OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\x00") + OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\x00") +) + +// Pointer represents a pointer to an arbitrary Windows type. +// +// Pointer-typed fields may point to one of many different types. It's +// up to the caller to provide a pointer to the appropriate type, cast +// to Pointer. The caller must obey the unsafe.Pointer rules while +// doing so. +type Pointer *struct{} + +// Invented values to support what package os expects. +type Timeval struct { + Sec int32 + Usec int32 +} + +func (tv *Timeval) Nanoseconds() int64 { + return (int64(tv.Sec)*1e6 + int64(tv.Usec)) * 1e3 +} + +func NsecToTimeval(nsec int64) (tv Timeval) { + tv.Sec = int32(nsec / 1e9) + tv.Usec = int32(nsec % 1e9 / 1e3) + return +} + +type SecurityAttributes struct { + Length uint32 + SecurityDescriptor uintptr + InheritHandle uint32 +} + +type Overlapped struct { + Internal uintptr + InternalHigh uintptr + Offset uint32 + OffsetHigh uint32 + HEvent Handle +} + +type FileNotifyInformation struct { + NextEntryOffset uint32 + Action uint32 + FileNameLength uint32 + FileName uint16 +} + +type Filetime struct { + LowDateTime uint32 + HighDateTime uint32 +} + +// Nanoseconds returns Filetime ft in nanoseconds +// since Epoch (00:00:00 UTC, January 1, 1970). +func (ft *Filetime) Nanoseconds() int64 { + // 100-nanosecond intervals since January 1, 1601 + nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) + // change starting time to the Epoch (00:00:00 UTC, January 1, 1970) + nsec -= 116444736000000000 + // convert into nanoseconds + nsec *= 100 + return nsec +} + +func NsecToFiletime(nsec int64) (ft Filetime) { + // convert into 100-nanosecond + nsec /= 100 + // change starting time to January 1, 1601 + nsec += 116444736000000000 + // split into high / low + ft.LowDateTime = uint32(nsec & 0xffffffff) + ft.HighDateTime = uint32(nsec >> 32 & 0xffffffff) + return ft +} + +type Win32finddata struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + FileSizeHigh uint32 + FileSizeLow uint32 + Reserved0 uint32 + Reserved1 uint32 + FileName [MAX_PATH - 1]uint16 + AlternateFileName [13]uint16 +} + +// This is the actual system call structure. +// Win32finddata is what we committed to in Go 1. +type win32finddata1 struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + FileSizeHigh uint32 + FileSizeLow uint32 + Reserved0 uint32 + Reserved1 uint32 + FileName [MAX_PATH]uint16 + AlternateFileName [14]uint16 + + // The Microsoft documentation for this struct¹ describes three additional + // fields: dwFileType, dwCreatorType, and wFinderFlags. However, those fields + // are empirically only present in the macOS port of the Win32 API,² and thus + // not needed for binaries built for Windows. + // + // ¹ https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataw + // ² https://golang.org/issue/42637#issuecomment-760715755 +} + +func copyFindData(dst *Win32finddata, src *win32finddata1) { + dst.FileAttributes = src.FileAttributes + dst.CreationTime = src.CreationTime + dst.LastAccessTime = src.LastAccessTime + dst.LastWriteTime = src.LastWriteTime + dst.FileSizeHigh = src.FileSizeHigh + dst.FileSizeLow = src.FileSizeLow + dst.Reserved0 = src.Reserved0 + dst.Reserved1 = src.Reserved1 + + // The src is 1 element bigger than dst, but it must be NUL. + copy(dst.FileName[:], src.FileName[:]) + copy(dst.AlternateFileName[:], src.AlternateFileName[:]) +} + +type ByHandleFileInformation struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + VolumeSerialNumber uint32 + FileSizeHigh uint32 + FileSizeLow uint32 + NumberOfLinks uint32 + FileIndexHigh uint32 + FileIndexLow uint32 +} + +const ( + GetFileExInfoStandard = 0 + GetFileExMaxInfoLevel = 1 +) + +type Win32FileAttributeData struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + FileSizeHigh uint32 + FileSizeLow uint32 +} + +// ShowWindow constants +const ( + // winuser.h + SW_HIDE = 0 + SW_NORMAL = 1 + SW_SHOWNORMAL = 1 + SW_SHOWMINIMIZED = 2 + SW_SHOWMAXIMIZED = 3 + SW_MAXIMIZE = 3 + SW_SHOWNOACTIVATE = 4 + SW_SHOW = 5 + SW_MINIMIZE = 6 + SW_SHOWMINNOACTIVE = 7 + SW_SHOWNA = 8 + SW_RESTORE = 9 + SW_SHOWDEFAULT = 10 + SW_FORCEMINIMIZE = 11 +) + +type StartupInfo struct { + Cb uint32 + _ *uint16 + Desktop *uint16 + Title *uint16 + X uint32 + Y uint32 + XSize uint32 + YSize uint32 + XCountChars uint32 + YCountChars uint32 + FillAttribute uint32 + Flags uint32 + ShowWindow uint16 + _ uint16 + _ *byte + StdInput Handle + StdOutput Handle + StdErr Handle +} + +type _PROC_THREAD_ATTRIBUTE_LIST struct { + _ [1]byte +} + +const ( + _PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000 + _PROC_THREAD_ATTRIBUTE_HANDLE_LIST = 0x00020002 +) + +type _STARTUPINFOEXW struct { + StartupInfo + ProcThreadAttributeList *_PROC_THREAD_ATTRIBUTE_LIST +} + +const _EXTENDED_STARTUPINFO_PRESENT = 0x00080000 + +type ProcessInformation struct { + Process Handle + Thread Handle + ProcessId uint32 + ThreadId uint32 +} + +type ProcessEntry32 struct { + Size uint32 + Usage uint32 + ProcessID uint32 + DefaultHeapID uintptr + ModuleID uint32 + Threads uint32 + ParentProcessID uint32 + PriClassBase int32 + Flags uint32 + ExeFile [MAX_PATH]uint16 +} + +type Systemtime struct { + Year uint16 + Month uint16 + DayOfWeek uint16 + Day uint16 + Hour uint16 + Minute uint16 + Second uint16 + Milliseconds uint16 +} + +type Timezoneinformation struct { + Bias int32 + StandardName [32]uint16 + StandardDate Systemtime + StandardBias int32 + DaylightName [32]uint16 + DaylightDate Systemtime + DaylightBias int32 +} + +// Socket related. + +const ( + AF_UNSPEC = 0 + AF_UNIX = 1 + AF_INET = 2 + AF_INET6 = 23 + AF_NETBIOS = 17 + + SOCK_STREAM = 1 + SOCK_DGRAM = 2 + SOCK_RAW = 3 + SOCK_SEQPACKET = 5 + + IPPROTO_IP = 0 + IPPROTO_IPV6 = 0x29 + IPPROTO_TCP = 6 + IPPROTO_UDP = 17 + + SOL_SOCKET = 0xffff + SO_REUSEADDR = 4 + SO_KEEPALIVE = 8 + SO_DONTROUTE = 16 + SO_BROADCAST = 32 + SO_LINGER = 128 + SO_RCVBUF = 0x1002 + SO_SNDBUF = 0x1001 + SO_UPDATE_ACCEPT_CONTEXT = 0x700b + SO_UPDATE_CONNECT_CONTEXT = 0x7010 + + IOC_OUT = 0x40000000 + IOC_IN = 0x80000000 + IOC_VENDOR = 0x18000000 + IOC_INOUT = IOC_IN | IOC_OUT + IOC_WS2 = 0x08000000 + SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6 + SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4 + SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 + + // cf. https://learn.microsoft.com/en-US/troubleshoot/windows/win32/header-library-requirement-socket-ipproto-ip + + IP_TOS = 0x3 + IP_TTL = 0x4 + IP_MULTICAST_IF = 0x9 + IP_MULTICAST_TTL = 0xa + IP_MULTICAST_LOOP = 0xb + IP_ADD_MEMBERSHIP = 0xc + IP_DROP_MEMBERSHIP = 0xd + + IPV6_V6ONLY = 0x1b + IPV6_UNICAST_HOPS = 0x4 + IPV6_MULTICAST_IF = 0x9 + IPV6_MULTICAST_HOPS = 0xa + IPV6_MULTICAST_LOOP = 0xb + IPV6_JOIN_GROUP = 0xc + IPV6_LEAVE_GROUP = 0xd + + SOMAXCONN = 0x7fffffff + + TCP_NODELAY = 1 + + SHUT_RD = 0 + SHUT_WR = 1 + SHUT_RDWR = 2 + + WSADESCRIPTION_LEN = 256 + WSASYS_STATUS_LEN = 128 +) + +type WSABuf struct { + Len uint32 + Buf *byte +} + +// Invented values to support what package os expects. +const ( + S_IFMT = 0x1f000 + S_IFIFO = 0x1000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFBLK = 0x6000 + S_IFREG = 0x8000 + S_IFLNK = 0xa000 + S_IFSOCK = 0xc000 + S_ISUID = 0x800 + S_ISGID = 0x400 + S_ISVTX = 0x200 + S_IRUSR = 0x100 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXUSR = 0x40 +) + +const ( + FILE_TYPE_CHAR = 0x0002 + FILE_TYPE_DISK = 0x0001 + FILE_TYPE_PIPE = 0x0003 + FILE_TYPE_REMOTE = 0x8000 + FILE_TYPE_UNKNOWN = 0x0000 +) + +type Hostent struct { + Name *byte + Aliases **byte + AddrType uint16 + Length uint16 + AddrList **byte +} + +type Protoent struct { + Name *byte + Aliases **byte + Proto uint16 +} + +const ( + DNS_TYPE_A = 0x0001 + DNS_TYPE_NS = 0x0002 + DNS_TYPE_MD = 0x0003 + DNS_TYPE_MF = 0x0004 + DNS_TYPE_CNAME = 0x0005 + DNS_TYPE_SOA = 0x0006 + DNS_TYPE_MB = 0x0007 + DNS_TYPE_MG = 0x0008 + DNS_TYPE_MR = 0x0009 + DNS_TYPE_NULL = 0x000a + DNS_TYPE_WKS = 0x000b + DNS_TYPE_PTR = 0x000c + DNS_TYPE_HINFO = 0x000d + DNS_TYPE_MINFO = 0x000e + DNS_TYPE_MX = 0x000f + DNS_TYPE_TEXT = 0x0010 + DNS_TYPE_RP = 0x0011 + DNS_TYPE_AFSDB = 0x0012 + DNS_TYPE_X25 = 0x0013 + DNS_TYPE_ISDN = 0x0014 + DNS_TYPE_RT = 0x0015 + DNS_TYPE_NSAP = 0x0016 + DNS_TYPE_NSAPPTR = 0x0017 + DNS_TYPE_SIG = 0x0018 + DNS_TYPE_KEY = 0x0019 + DNS_TYPE_PX = 0x001a + DNS_TYPE_GPOS = 0x001b + DNS_TYPE_AAAA = 0x001c + DNS_TYPE_LOC = 0x001d + DNS_TYPE_NXT = 0x001e + DNS_TYPE_EID = 0x001f + DNS_TYPE_NIMLOC = 0x0020 + DNS_TYPE_SRV = 0x0021 + DNS_TYPE_ATMA = 0x0022 + DNS_TYPE_NAPTR = 0x0023 + DNS_TYPE_KX = 0x0024 + DNS_TYPE_CERT = 0x0025 + DNS_TYPE_A6 = 0x0026 + DNS_TYPE_DNAME = 0x0027 + DNS_TYPE_SINK = 0x0028 + DNS_TYPE_OPT = 0x0029 + DNS_TYPE_DS = 0x002B + DNS_TYPE_RRSIG = 0x002E + DNS_TYPE_NSEC = 0x002F + DNS_TYPE_DNSKEY = 0x0030 + DNS_TYPE_DHCID = 0x0031 + DNS_TYPE_UINFO = 0x0064 + DNS_TYPE_UID = 0x0065 + DNS_TYPE_GID = 0x0066 + DNS_TYPE_UNSPEC = 0x0067 + DNS_TYPE_ADDRS = 0x00f8 + DNS_TYPE_TKEY = 0x00f9 + DNS_TYPE_TSIG = 0x00fa + DNS_TYPE_IXFR = 0x00fb + DNS_TYPE_AXFR = 0x00fc + DNS_TYPE_MAILB = 0x00fd + DNS_TYPE_MAILA = 0x00fe + DNS_TYPE_ALL = 0x00ff + DNS_TYPE_ANY = 0x00ff + DNS_TYPE_WINS = 0xff01 + DNS_TYPE_WINSR = 0xff02 + DNS_TYPE_NBSTAT = 0xff01 +) + +const ( + DNS_INFO_NO_RECORDS = 0x251D +) + +const ( + // flags inside DNSRecord.Dw + DnsSectionQuestion = 0x0000 + DnsSectionAnswer = 0x0001 + DnsSectionAuthority = 0x0002 + DnsSectionAdditional = 0x0003 +) + +type DNSSRVData struct { + Target *uint16 + Priority uint16 + Weight uint16 + Port uint16 + Pad uint16 +} + +type DNSPTRData struct { + Host *uint16 +} + +type DNSMXData struct { + NameExchange *uint16 + Preference uint16 + Pad uint16 +} + +type DNSTXTData struct { + StringCount uint16 + StringArray [1]*uint16 +} + +type DNSRecord struct { + Next *DNSRecord + Name *uint16 + Type uint16 + Length uint16 + Dw uint32 + Ttl uint32 + Reserved uint32 + Data [40]byte +} + +const ( + TF_DISCONNECT = 1 + TF_REUSE_SOCKET = 2 + TF_WRITE_BEHIND = 4 + TF_USE_DEFAULT_WORKER = 0 + TF_USE_SYSTEM_THREAD = 16 + TF_USE_KERNEL_APC = 32 +) + +type TransmitFileBuffers struct { + Head uintptr + HeadLength uint32 + Tail uintptr + TailLength uint32 +} + +const ( + IFF_UP = 1 + IFF_BROADCAST = 2 + IFF_LOOPBACK = 4 + IFF_POINTTOPOINT = 8 + IFF_MULTICAST = 16 +) + +const SIO_GET_INTERFACE_LIST = 0x4004747F + +// TODO(mattn): SockaddrGen is union of sockaddr/sockaddr_in/sockaddr_in6_old. +// will be fixed to change variable type as suitable. + +type SockaddrGen [24]byte + +type InterfaceInfo struct { + Flags uint32 + Address SockaddrGen + BroadcastAddress SockaddrGen + Netmask SockaddrGen +} + +type IpAddressString struct { + String [16]byte +} + +type IpMaskString IpAddressString + +type IpAddrString struct { + Next *IpAddrString + IpAddress IpAddressString + IpMask IpMaskString + Context uint32 +} + +const MAX_ADAPTER_NAME_LENGTH = 256 +const MAX_ADAPTER_DESCRIPTION_LENGTH = 128 +const MAX_ADAPTER_ADDRESS_LENGTH = 8 + +type IpAdapterInfo struct { + Next *IpAdapterInfo + ComboIndex uint32 + AdapterName [MAX_ADAPTER_NAME_LENGTH + 4]byte + Description [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte + AddressLength uint32 + Address [MAX_ADAPTER_ADDRESS_LENGTH]byte + Index uint32 + Type uint32 + DhcpEnabled uint32 + CurrentIpAddress *IpAddrString + IpAddressList IpAddrString + GatewayList IpAddrString + DhcpServer IpAddrString + HaveWins bool + PrimaryWinsServer IpAddrString + SecondaryWinsServer IpAddrString + LeaseObtained int64 + LeaseExpires int64 +} + +const MAXLEN_PHYSADDR = 8 +const MAX_INTERFACE_NAME_LEN = 256 +const MAXLEN_IFDESCR = 256 + +type MibIfRow struct { + Name [MAX_INTERFACE_NAME_LEN]uint16 + Index uint32 + Type uint32 + Mtu uint32 + Speed uint32 + PhysAddrLen uint32 + PhysAddr [MAXLEN_PHYSADDR]byte + AdminStatus uint32 + OperStatus uint32 + LastChange uint32 + InOctets uint32 + InUcastPkts uint32 + InNUcastPkts uint32 + InDiscards uint32 + InErrors uint32 + InUnknownProtos uint32 + OutOctets uint32 + OutUcastPkts uint32 + OutNUcastPkts uint32 + OutDiscards uint32 + OutErrors uint32 + OutQLen uint32 + DescrLen uint32 + Descr [MAXLEN_IFDESCR]byte +} + +type CertInfo struct { + // Not implemented +} + +type CertContext struct { + EncodingType uint32 + EncodedCert *byte + Length uint32 + CertInfo *CertInfo + Store Handle +} + +type CertChainContext struct { + Size uint32 + TrustStatus CertTrustStatus + ChainCount uint32 + Chains **CertSimpleChain + LowerQualityChainCount uint32 + LowerQualityChains **CertChainContext + HasRevocationFreshnessTime uint32 + RevocationFreshnessTime uint32 +} + +type CertTrustListInfo struct { + // Not implemented +} + +type CertSimpleChain struct { + Size uint32 + TrustStatus CertTrustStatus + NumElements uint32 + Elements **CertChainElement + TrustListInfo *CertTrustListInfo + HasRevocationFreshnessTime uint32 + RevocationFreshnessTime uint32 +} + +type CertChainElement struct { + Size uint32 + CertContext *CertContext + TrustStatus CertTrustStatus + RevocationInfo *CertRevocationInfo + IssuanceUsage *CertEnhKeyUsage + ApplicationUsage *CertEnhKeyUsage + ExtendedErrorInfo *uint16 +} + +type CertRevocationCrlInfo struct { + // Not implemented +} + +type CertRevocationInfo struct { + Size uint32 + RevocationResult uint32 + RevocationOid *byte + OidSpecificInfo Pointer + HasFreshnessTime uint32 + FreshnessTime uint32 + CrlInfo *CertRevocationCrlInfo +} + +type CertTrustStatus struct { + ErrorStatus uint32 + InfoStatus uint32 +} + +type CertUsageMatch struct { + Type uint32 + Usage CertEnhKeyUsage +} + +type CertEnhKeyUsage struct { + Length uint32 + UsageIdentifiers **byte +} + +type CertChainPara struct { + Size uint32 + RequestedUsage CertUsageMatch + RequstedIssuancePolicy CertUsageMatch + URLRetrievalTimeout uint32 + CheckRevocationFreshnessTime uint32 + RevocationFreshnessTime uint32 + CacheResync *Filetime +} + +type CertChainPolicyPara struct { + Size uint32 + Flags uint32 + ExtraPolicyPara Pointer +} + +type SSLExtraCertChainPolicyPara struct { + Size uint32 + AuthType uint32 + Checks uint32 + ServerName *uint16 +} + +type CertChainPolicyStatus struct { + Size uint32 + Error uint32 + ChainIndex uint32 + ElementIndex uint32 + ExtraPolicyStatus Pointer +} + +const ( + // do not reorder + HKEY_CLASSES_ROOT = 0x80000000 + iota + HKEY_CURRENT_USER + HKEY_LOCAL_MACHINE + HKEY_USERS + HKEY_PERFORMANCE_DATA + HKEY_CURRENT_CONFIG + HKEY_DYN_DATA + + KEY_QUERY_VALUE = 1 + KEY_SET_VALUE = 2 + KEY_CREATE_SUB_KEY = 4 + KEY_ENUMERATE_SUB_KEYS = 8 + KEY_NOTIFY = 16 + KEY_CREATE_LINK = 32 + KEY_WRITE = 0x20006 + KEY_EXECUTE = 0x20019 + KEY_READ = 0x20019 + KEY_WOW64_64KEY = 0x0100 + KEY_WOW64_32KEY = 0x0200 + KEY_ALL_ACCESS = 0xf003f +) + +const ( + // do not reorder + REG_NONE = iota + REG_SZ + REG_EXPAND_SZ + REG_BINARY + REG_DWORD_LITTLE_ENDIAN + REG_DWORD_BIG_ENDIAN + REG_LINK + REG_MULTI_SZ + REG_RESOURCE_LIST + REG_FULL_RESOURCE_DESCRIPTOR + REG_RESOURCE_REQUIREMENTS_LIST + REG_QWORD_LITTLE_ENDIAN + REG_DWORD = REG_DWORD_LITTLE_ENDIAN + REG_QWORD = REG_QWORD_LITTLE_ENDIAN +) + +type AddrinfoW struct { + Flags int32 + Family int32 + Socktype int32 + Protocol int32 + Addrlen uintptr + Canonname *uint16 + Addr Pointer + Next *AddrinfoW +} + +const ( + AI_PASSIVE = 1 + AI_CANONNAME = 2 + AI_NUMERICHOST = 4 +) + +type GUID struct { + Data1 uint32 + Data2 uint16 + Data3 uint16 + Data4 [8]byte +} + +var WSAID_CONNECTEX = GUID{ + 0x25a207b9, + 0xddf3, + 0x4660, + [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}, +} + +const ( + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 + FILE_SKIP_SET_EVENT_ON_HANDLE = 2 +) + +const ( + WSAPROTOCOL_LEN = 255 + MAX_PROTOCOL_CHAIN = 7 + BASE_PROTOCOL = 1 + LAYERED_PROTOCOL = 0 + + XP1_CONNECTIONLESS = 0x00000001 + XP1_GUARANTEED_DELIVERY = 0x00000002 + XP1_GUARANTEED_ORDER = 0x00000004 + XP1_MESSAGE_ORIENTED = 0x00000008 + XP1_PSEUDO_STREAM = 0x00000010 + XP1_GRACEFUL_CLOSE = 0x00000020 + XP1_EXPEDITED_DATA = 0x00000040 + XP1_CONNECT_DATA = 0x00000080 + XP1_DISCONNECT_DATA = 0x00000100 + XP1_SUPPORT_BROADCAST = 0x00000200 + XP1_SUPPORT_MULTIPOINT = 0x00000400 + XP1_MULTIPOINT_CONTROL_PLANE = 0x00000800 + XP1_MULTIPOINT_DATA_PLANE = 0x00001000 + XP1_QOS_SUPPORTED = 0x00002000 + XP1_UNI_SEND = 0x00008000 + XP1_UNI_RECV = 0x00010000 + XP1_IFS_HANDLES = 0x00020000 + XP1_PARTIAL_MESSAGE = 0x00040000 + XP1_SAN_SUPPORT_SDP = 0x00080000 + + PFL_MULTIPLE_PROTO_ENTRIES = 0x00000001 + PFL_RECOMMENDED_PROTO_ENTRY = 0x00000002 + PFL_HIDDEN = 0x00000004 + PFL_MATCHES_PROTOCOL_ZERO = 0x00000008 + PFL_NETWORKDIRECT_PROVIDER = 0x00000010 +) + +type WSAProtocolInfo struct { + ServiceFlags1 uint32 + ServiceFlags2 uint32 + ServiceFlags3 uint32 + ServiceFlags4 uint32 + ProviderFlags uint32 + ProviderId GUID + CatalogEntryId uint32 + ProtocolChain WSAProtocolChain + Version int32 + AddressFamily int32 + MaxSockAddr int32 + MinSockAddr int32 + SocketType int32 + Protocol int32 + ProtocolMaxOffset int32 + NetworkByteOrder int32 + SecurityScheme int32 + MessageSize uint32 + ProviderReserved uint32 + ProtocolName [WSAPROTOCOL_LEN + 1]uint16 +} + +type WSAProtocolChain struct { + ChainLen int32 + ChainEntries [MAX_PROTOCOL_CHAIN]uint32 +} + +type TCPKeepalive struct { + OnOff uint32 + Time uint32 + Interval uint32 +} + +type symbolicLinkReparseBuffer struct { + SubstituteNameOffset uint16 + SubstituteNameLength uint16 + PrintNameOffset uint16 + PrintNameLength uint16 + Flags uint32 + PathBuffer [1]uint16 +} + +type mountPointReparseBuffer struct { + SubstituteNameOffset uint16 + SubstituteNameLength uint16 + PrintNameOffset uint16 + PrintNameLength uint16 + PathBuffer [1]uint16 +} + +type reparseDataBuffer struct { + ReparseTag uint32 + ReparseDataLength uint16 + Reserved uint16 + + // GenericReparseBuffer + reparseBuffer byte +} + +const ( + FSCTL_GET_REPARSE_POINT = 0x900A8 + MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024 + _IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 + IO_REPARSE_TAG_SYMLINK = 0xA000000C + SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1 + _SYMLINK_FLAG_RELATIVE = 1 +) + +const UNIX_PATH_MAX = 108 // defined in afunix.h diff --git a/contrib/go/_std_1.22/src/syscall/types_windows_386.go b/contrib/go/_std_1.23/src/syscall/types_windows_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_windows_386.go rename to contrib/go/_std_1.23/src/syscall/types_windows_386.go diff --git a/contrib/go/_std_1.22/src/syscall/types_windows_amd64.go b/contrib/go/_std_1.23/src/syscall/types_windows_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_windows_amd64.go rename to contrib/go/_std_1.23/src/syscall/types_windows_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/types_windows_arm.go b/contrib/go/_std_1.23/src/syscall/types_windows_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_windows_arm.go rename to contrib/go/_std_1.23/src/syscall/types_windows_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/types_windows_arm64.go b/contrib/go/_std_1.23/src/syscall/types_windows_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_windows_arm64.go rename to contrib/go/_std_1.23/src/syscall/types_windows_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/wtf8_windows.go b/contrib/go/_std_1.23/src/syscall/wtf8_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/wtf8_windows.go rename to contrib/go/_std_1.23/src/syscall/wtf8_windows.go diff --git a/contrib/go/_std_1.23/src/syscall/ya.make b/contrib/go/_std_1.23/src/syscall/ya.make new file mode 100644 index 000000000000..40fe1ee4e7cf --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/ya.make @@ -0,0 +1,186 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + asm_darwin_arm64.s + badlinkname_unix.go + bpf_bsd.go + dirent.go + env_unix.go + exec_libc2.go + exec_unix.go + flock_bsd.go + forkpipe.go + linkname_bsd.go + linkname_darwin.go + linkname_libc.go + linkname_unix.go + net.go + rlimit.go + rlimit_darwin.go + route_bsd.go + route_darwin.go + sockcmsg_unix.go + sockcmsg_unix_other.go + syscall.go + syscall_bsd.go + syscall_darwin.go + syscall_darwin_arm64.go + syscall_unix.go + time_nofake.go + timestruct.go + zerrors_darwin_arm64.go + zsyscall_darwin_arm64.go + zsyscall_darwin_arm64.s + zsysnum_darwin_arm64.go + ztypes_darwin_arm64.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + asm_darwin_amd64.s + badlinkname_unix.go + bpf_bsd.go + dirent.go + env_unix.go + exec_libc2.go + exec_unix.go + flock_bsd.go + forkpipe.go + linkname_bsd.go + linkname_darwin.go + linkname_libc.go + linkname_unix.go + net.go + rlimit.go + rlimit_darwin.go + route_bsd.go + route_darwin.go + sockcmsg_unix.go + sockcmsg_unix_other.go + syscall.go + syscall_bsd.go + syscall_darwin.go + syscall_darwin_amd64.go + syscall_unix.go + time_nofake.go + timestruct.go + zerrors_darwin_amd64.go + zsyscall_darwin_amd64.go + zsyscall_darwin_amd64.s + zsysnum_darwin_amd64.go + ztypes_darwin_amd64.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + asm_linux_arm64.s + badlinkname_unix.go + dirent.go + env_unix.go + exec_linux.go + exec_unix.go + flock_linux.go + forkpipe2.go + linkname_unix.go + lsf_linux.go + net.go + netlink_linux.go + rlimit.go + rlimit_stub.go + setuidgid_linux.go + sockcmsg_linux.go + sockcmsg_unix.go + sockcmsg_unix_other.go + syscall.go + syscall_linux.go + syscall_linux_accept4.go + syscall_linux_arm64.go + syscall_unix.go + time_nofake.go + timestruct.go + zerrors_linux_arm64.go + zsyscall_linux_arm64.go + zsysnum_linux_arm64.go + ztypes_linux_arm64.go + ) +ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + asm_linux_amd64.s + badlinkname_unix.go + dirent.go + env_unix.go + exec_linux.go + exec_unix.go + flock_linux.go + forkpipe2.go + linkname_unix.go + lsf_linux.go + net.go + netlink_linux.go + rlimit.go + rlimit_stub.go + setuidgid_linux.go + sockcmsg_linux.go + sockcmsg_unix.go + sockcmsg_unix_other.go + syscall.go + syscall_linux.go + syscall_linux_accept4.go + syscall_linux_amd64.go + syscall_unix.go + time_nofake.go + timestruct.go + zerrors_linux_amd64.go + zsyscall_linux_amd64.go + zsysnum_linux_amd64.go + ztypes_linux_amd64.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + asm_linux_arm.s + badlinkname_unix.go + dirent.go + env_unix.go + exec_linux.go + exec_unix.go + flock_linux.go + flock_linux_32bit.go + forkpipe2.go + linkname_unix.go + lsf_linux.go + net.go + netlink_linux.go + rlimit.go + rlimit_stub.go + setuidgid_32_linux.go + sockcmsg_linux.go + sockcmsg_unix.go + sockcmsg_unix_other.go + syscall.go + syscall_linux.go + syscall_linux_accept.go + syscall_linux_arm.go + syscall_unix.go + time_nofake.go + timestruct.go + zerrors_linux_arm.go + zsyscall_linux_arm.go + zsysnum_linux_arm.go + ztypes_linux_arm.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + dll_windows.go + env_windows.go + exec_windows.go + net.go + security_windows.go + syscall.go + syscall_windows.go + time_nofake.go + types_windows.go + types_windows_amd64.go + wtf8_windows.go + zerrors_windows.go + zsyscall_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_aix_ppc64.go b/contrib/go/_std_1.23/src/syscall/zerrors_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_aix_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_386.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_386.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_arm.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_mips.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_mips.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_mips.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_mips64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_mips64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_mips64le.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_mips64le.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_mips64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_mipsle.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_mipsle.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_mipsle.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_ppc64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_ppc64le.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_ppc64le.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/zerrors_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zerrors_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zerrors_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zerrors_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_386.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_386.go index d17ecb96e50c..a37d6d16346d 100644 --- a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_386.go +++ b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_386.go @@ -1330,6 +1330,7 @@ const ( EALREADY = Errno(0x25) EAUTH = Errno(0x50) EBADF = Errno(0x9) + EBADMSG = Errno(0x5c) EBADRPC = Errno(0x48) EBUSY = Errno(0x10) ECANCELED = Errno(0x58) @@ -1356,7 +1357,7 @@ const ( EIPSEC = Errno(0x52) EISCONN = Errno(0x38) EISDIR = Errno(0x15) - ELAST = Errno(0x5b) + ELAST = Errno(0x5f) ELOOP = Errno(0x3e) EMEDIUMTYPE = Errno(0x56) EMFILE = Errno(0x18) @@ -1384,12 +1385,14 @@ const ( ENOTCONN = Errno(0x39) ENOTDIR = Errno(0x14) ENOTEMPTY = Errno(0x42) + ENOTRECOVERABLE = Errno(0x5d) ENOTSOCK = Errno(0x26) ENOTSUP = Errno(0x5b) ENOTTY = Errno(0x19) ENXIO = Errno(0x6) EOPNOTSUPP = Errno(0x2d) EOVERFLOW = Errno(0x57) + EOWNERDEAD = Errno(0x5e) EPERM = Errno(0x1) EPFNOSUPPORT = Errno(0x2e) EPIPE = Errno(0x20) @@ -1397,6 +1400,7 @@ const ( EPROCUNAVAIL = Errno(0x4c) EPROGMISMATCH = Errno(0x4b) EPROGUNAVAIL = Errno(0x4a) + EPROTO = Errno(0x5f) EPROTONOSUPPORT = Errno(0x2b) EPROTOTYPE = Errno(0x29) ERANGE = Errno(0x22) @@ -1514,7 +1518,7 @@ var errors = [...]string{ 57: "socket is not connected", 58: "can't send after socket shutdown", 59: "too many references: can't splice", - 60: "connection timed out", + 60: "operation timed out", 61: "connection refused", 62: "too many levels of symbolic links", 63: "file name too long", @@ -1523,12 +1527,12 @@ var errors = [...]string{ 66: "directory not empty", 67: "too many processes", 68: "too many users", - 69: "disc quota exceeded", + 69: "disk quota exceeded", 70: "stale NFS file handle", 71: "too many levels of remote in path", 72: "RPC struct is bad", 73: "RPC version wrong", - 74: "RPC prog. not avail", + 74: "RPC program not available", 75: "program version wrong", 76: "bad procedure for program", 77: "no locks available", @@ -1546,6 +1550,10 @@ var errors = [...]string{ 89: "identifier removed", 90: "no message of desired type", 91: "not supported", + 92: "bad message", + 93: "state not recoverable", + 94: "previous owner died", + 95: "protocol error", } // Signal table @@ -1566,8 +1574,8 @@ var signals = [...]string{ 14: "alarm clock", 15: "terminated", 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", + 17: "suspended (signal)", + 18: "suspended", 19: "continued", 20: "child exited", 21: "stopped (tty input)", diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_amd64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_amd64.go index 4904e7614f3d..812fd950a7fc 100644 --- a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_amd64.go +++ b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_amd64.go @@ -1329,6 +1329,7 @@ const ( EALREADY = Errno(0x25) EAUTH = Errno(0x50) EBADF = Errno(0x9) + EBADMSG = Errno(0x5c) EBADRPC = Errno(0x48) EBUSY = Errno(0x10) ECANCELED = Errno(0x58) @@ -1355,7 +1356,7 @@ const ( EIPSEC = Errno(0x52) EISCONN = Errno(0x38) EISDIR = Errno(0x15) - ELAST = Errno(0x5b) + ELAST = Errno(0x5f) ELOOP = Errno(0x3e) EMEDIUMTYPE = Errno(0x56) EMFILE = Errno(0x18) @@ -1383,12 +1384,14 @@ const ( ENOTCONN = Errno(0x39) ENOTDIR = Errno(0x14) ENOTEMPTY = Errno(0x42) + ENOTRECOVERABLE = Errno(0x5d) ENOTSOCK = Errno(0x26) ENOTSUP = Errno(0x5b) ENOTTY = Errno(0x19) ENXIO = Errno(0x6) EOPNOTSUPP = Errno(0x2d) EOVERFLOW = Errno(0x57) + EOWNERDEAD = Errno(0x5e) EPERM = Errno(0x1) EPFNOSUPPORT = Errno(0x2e) EPIPE = Errno(0x20) @@ -1396,6 +1399,7 @@ const ( EPROCUNAVAIL = Errno(0x4c) EPROGMISMATCH = Errno(0x4b) EPROGUNAVAIL = Errno(0x4a) + EPROTO = Errno(0x5f) EPROTONOSUPPORT = Errno(0x2b) EPROTOTYPE = Errno(0x29) ERANGE = Errno(0x22) @@ -1513,7 +1517,7 @@ var errors = [...]string{ 57: "socket is not connected", 58: "can't send after socket shutdown", 59: "too many references: can't splice", - 60: "connection timed out", + 60: "operation timed out", 61: "connection refused", 62: "too many levels of symbolic links", 63: "file name too long", @@ -1522,12 +1526,12 @@ var errors = [...]string{ 66: "directory not empty", 67: "too many processes", 68: "too many users", - 69: "disc quota exceeded", + 69: "disk quota exceeded", 70: "stale NFS file handle", 71: "too many levels of remote in path", 72: "RPC struct is bad", 73: "RPC version wrong", - 74: "RPC prog. not avail", + 74: "RPC program not available", 75: "program version wrong", 76: "bad procedure for program", 77: "no locks available", @@ -1545,6 +1549,10 @@ var errors = [...]string{ 89: "identifier removed", 90: "no message of desired type", 91: "not supported", + 92: "bad message", + 93: "state not recoverable", + 94: "previous owner died", + 95: "protocol error", } // Signal table @@ -1565,8 +1573,8 @@ var signals = [...]string{ 14: "alarm clock", 15: "terminated", 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", + 17: "suspended (signal)", + 18: "suspended", 19: "continued", 20: "child exited", 21: "stopped (tty input)", diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm.go index 76ac9173a93f..2e19672b05a2 100644 --- a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm.go +++ b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm.go @@ -1329,6 +1329,7 @@ const ( EALREADY = Errno(0x25) EAUTH = Errno(0x50) EBADF = Errno(0x9) + EBADMSG = Errno(0x5c) EBADRPC = Errno(0x48) EBUSY = Errno(0x10) ECANCELED = Errno(0x58) @@ -1355,7 +1356,7 @@ const ( EIPSEC = Errno(0x52) EISCONN = Errno(0x38) EISDIR = Errno(0x15) - ELAST = Errno(0x5b) + ELAST = Errno(0x5f) ELOOP = Errno(0x3e) EMEDIUMTYPE = Errno(0x56) EMFILE = Errno(0x18) @@ -1383,12 +1384,14 @@ const ( ENOTCONN = Errno(0x39) ENOTDIR = Errno(0x14) ENOTEMPTY = Errno(0x42) + ENOTRECOVERABLE = Errno(0x5d) ENOTSOCK = Errno(0x26) ENOTSUP = Errno(0x5b) ENOTTY = Errno(0x19) ENXIO = Errno(0x6) EOPNOTSUPP = Errno(0x2d) EOVERFLOW = Errno(0x57) + EOWNERDEAD = Errno(0x5e) EPERM = Errno(0x1) EPFNOSUPPORT = Errno(0x2e) EPIPE = Errno(0x20) @@ -1396,6 +1399,7 @@ const ( EPROCUNAVAIL = Errno(0x4c) EPROGMISMATCH = Errno(0x4b) EPROGUNAVAIL = Errno(0x4a) + EPROTO = Errno(0x5f) EPROTONOSUPPORT = Errno(0x2b) EPROTOTYPE = Errno(0x29) ERANGE = Errno(0x22) @@ -1513,7 +1517,7 @@ var errors = [...]string{ 57: "socket is not connected", 58: "can't send after socket shutdown", 59: "too many references: can't splice", - 60: "connection timed out", + 60: "operation timed out", 61: "connection refused", 62: "too many levels of symbolic links", 63: "file name too long", @@ -1522,12 +1526,12 @@ var errors = [...]string{ 66: "directory not empty", 67: "too many processes", 68: "too many users", - 69: "disc quota exceeded", + 69: "disk quota exceeded", 70: "stale NFS file handle", 71: "too many levels of remote in path", 72: "RPC struct is bad", 73: "RPC version wrong", - 74: "RPC prog. not avail", + 74: "RPC program not available", 75: "program version wrong", 76: "bad procedure for program", 77: "no locks available", @@ -1545,6 +1549,10 @@ var errors = [...]string{ 89: "identifier removed", 90: "no message of desired type", 91: "not supported", + 92: "bad message", + 93: "state not recoverable", + 94: "previous owner died", + 95: "protocol error", } // Signal table @@ -1565,8 +1573,8 @@ var signals = [...]string{ 14: "alarm clock", 15: "terminated", 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", + 17: "suspended (signal)", + 18: "suspended", 19: "continued", 20: "child exited", 21: "stopped (tty input)", diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_windows.go b/contrib/go/_std_1.23/src/syscall/zerrors_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_windows.go rename to contrib/go/_std_1.23/src/syscall/zerrors_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_aix_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_aix_ppc64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_aix_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_aix_ppc64.go index 111e6711d7de..27657aa1e9ce 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_aix_ppc64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_aix_ppc64.go @@ -83,6 +83,7 @@ import "unsafe" //go:cgo_import_dynamic libc_Setegid setegid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Seteuid seteuid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Setgid setgid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_Setuid setuid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Setpgid setpgid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Setpriority setpriority "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Setregid setregid "libc.a/shr_64.o" @@ -177,6 +178,7 @@ import "unsafe" //go:linkname libc_Setegid libc_Setegid //go:linkname libc_Seteuid libc_Seteuid //go:linkname libc_Setgid libc_Setgid +//go:linkname libc_Setuid libc_Setuid //go:linkname libc_Setpgid libc_Setpgid //go:linkname libc_Setpriority libc_Setpriority //go:linkname libc_Setregid libc_Setregid @@ -274,6 +276,7 @@ var ( libc_Setegid, libc_Seteuid, libc_Setgid, + libc_Setuid, libc_Setpgid, libc_Setpriority, libc_Setregid, @@ -1231,6 +1234,16 @@ func Setgid(gid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Setuid(uid int) (err error) { + _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setuid)), 1, uintptr(uid), 0, 0, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setpgid(pid int, pgid int) (err error) { _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0) if e1 != 0 { diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_darwin_amd64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_darwin_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_darwin_amd64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_darwin_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_darwin_arm64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_darwin_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_darwin_arm64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_darwin_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips64le.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips64le.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_mipsle.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_mipsle.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_mipsle.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_ppc64le.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_ppc64le.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.go index 084b4b78e53a..d2bd3ea0125a 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.s index 319ad205c0ba..9a820e9f3eb9 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.go index 5a7b4c1122b4..170a74b457ba 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.s index c0e397728af3..9b70dc096e12 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.go index 66a322717523..e75bd0b443b9 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.s index 73b6a092ef3c..0333377b8b71 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.go index a90f14436905..bc027b44755f 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.s index 66656695d58e..654e6c69a353 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.go index 661c8959a631..6808092a5a27 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.s index 8f3ff9a28c4e..86a5745c0ae6 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.s @@ -319,9 +319,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 CALL libc_utimensat(SB) RET -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - CALL libc_syscall(SB) - RET TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 CALL libc_lseek(SB) RET diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.go index a24fcba11310..2979ff78c25b 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.s index 4f787ee2751e..c8728190e555 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_plan9_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_plan9_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_plan9_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_plan9_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_plan9_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_plan9_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_plan9_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_plan9_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_plan9_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_plan9_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_plan9_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_plan9_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_solaris_amd64.go diff --git a/contrib/go/_std_1.23/src/syscall/zsyscall_windows.go b/contrib/go/_std_1.23/src/syscall/zsyscall_windows.go new file mode 100644 index 000000000000..d8d8594a5561 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_windows.go @@ -0,0 +1,1468 @@ +// Code generated by 'go generate'; DO NOT EDIT. + +package syscall + +import ( + "internal/syscall/windows/sysdll" + "unsafe" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = Errno(errnoERROR_IO_PENDING) + errERROR_EINVAL error = EINVAL +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e Errno) error { + switch e { + case 0: + return errERROR_EINVAL + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modadvapi32 = NewLazyDLL(sysdll.Add("advapi32.dll")) + modcrypt32 = NewLazyDLL(sysdll.Add("crypt32.dll")) + moddnsapi = NewLazyDLL(sysdll.Add("dnsapi.dll")) + modiphlpapi = NewLazyDLL(sysdll.Add("iphlpapi.dll")) + modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll")) + modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll")) + modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll")) + modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll")) + modshell32 = NewLazyDLL(sysdll.Add("shell32.dll")) + moduserenv = NewLazyDLL(sysdll.Add("userenv.dll")) + modws2_32 = NewLazyDLL(sysdll.Add("ws2_32.dll")) + + procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") + procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW") + procCopySid = modadvapi32.NewProc("CopySid") + procCreateProcessAsUserW = modadvapi32.NewProc("CreateProcessAsUserW") + procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW") + procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom") + procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext") + procGetLengthSid = modadvapi32.NewProc("GetLengthSid") + procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation") + procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") + procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW") + procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken") + procRegCloseKey = modadvapi32.NewProc("RegCloseKey") + procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW") + procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW") + procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW") + procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW") + procCertAddCertificateContextToStore = modcrypt32.NewProc("CertAddCertificateContextToStore") + procCertCloseStore = modcrypt32.NewProc("CertCloseStore") + procCertCreateCertificateContext = modcrypt32.NewProc("CertCreateCertificateContext") + procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore") + procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain") + procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext") + procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain") + procCertOpenStore = modcrypt32.NewProc("CertOpenStore") + procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW") + procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy") + procDnsNameCompare_W = moddnsapi.NewProc("DnsNameCompare_W") + procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W") + procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree") + procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo") + procGetIfEntry = modiphlpapi.NewProc("GetIfEntry") + procCancelIo = modkernel32.NewProc("CancelIo") + procCancelIoEx = modkernel32.NewProc("CancelIoEx") + procCloseHandle = modkernel32.NewProc("CloseHandle") + procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW") + procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW") + procCreateFileW = modkernel32.NewProc("CreateFileW") + procCreateHardLinkW = modkernel32.NewProc("CreateHardLinkW") + procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") + procCreatePipe = modkernel32.NewProc("CreatePipe") + procCreateProcessW = modkernel32.NewProc("CreateProcessW") + procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW") + procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") + procDeleteFileW = modkernel32.NewProc("DeleteFileW") + procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList") + procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") + procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") + procExitProcess = modkernel32.NewProc("ExitProcess") + procFindClose = modkernel32.NewProc("FindClose") + procFindFirstFileW = modkernel32.NewProc("FindFirstFileW") + procFindNextFileW = modkernel32.NewProc("FindNextFileW") + procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers") + procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile") + procFormatMessageW = modkernel32.NewProc("FormatMessageW") + procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW") + procFreeLibrary = modkernel32.NewProc("FreeLibrary") + procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") + procGetComputerNameW = modkernel32.NewProc("GetComputerNameW") + procGetConsoleMode = modkernel32.NewProc("GetConsoleMode") + procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW") + procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess") + procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId") + procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW") + procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW") + procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess") + procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW") + procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW") + procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle") + procGetFileType = modkernel32.NewProc("GetFileType") + procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW") + procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW") + procGetLastError = modkernel32.NewProc("GetLastError") + procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW") + procGetProcAddress = modkernel32.NewProc("GetProcAddress") + procGetProcessTimes = modkernel32.NewProc("GetProcessTimes") + procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") + procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW") + procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW") + procGetStdHandle = modkernel32.NewProc("GetStdHandle") + procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime") + procGetTempPathW = modkernel32.NewProc("GetTempPathW") + procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation") + procGetVersion = modkernel32.NewProc("GetVersion") + procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList") + procLoadLibraryW = modkernel32.NewProc("LoadLibraryW") + procLocalFree = modkernel32.NewProc("LocalFree") + procMapViewOfFile = modkernel32.NewProc("MapViewOfFile") + procMoveFileW = modkernel32.NewProc("MoveFileW") + procOpenProcess = modkernel32.NewProc("OpenProcess") + procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus") + procProcess32FirstW = modkernel32.NewProc("Process32FirstW") + procProcess32NextW = modkernel32.NewProc("Process32NextW") + procReadConsoleW = modkernel32.NewProc("ReadConsoleW") + procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW") + procReadFile = modkernel32.NewProc("ReadFile") + procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW") + procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW") + procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") + procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") + procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW") + procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") + procSetFilePointer = modkernel32.NewProc("SetFilePointer") + procSetFileTime = modkernel32.NewProc("SetFileTime") + procSetHandleInformation = modkernel32.NewProc("SetHandleInformation") + procTerminateProcess = modkernel32.NewProc("TerminateProcess") + procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile") + procUpdateProcThreadAttribute = modkernel32.NewProc("UpdateProcThreadAttribute") + procVirtualLock = modkernel32.NewProc("VirtualLock") + procVirtualUnlock = modkernel32.NewProc("VirtualUnlock") + procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject") + procWriteConsoleW = modkernel32.NewProc("WriteConsoleW") + procWriteFile = modkernel32.NewProc("WriteFile") + procAcceptEx = modmswsock.NewProc("AcceptEx") + procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs") + procTransmitFile = modmswsock.NewProc("TransmitFile") + procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree") + procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation") + procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") + procGetUserNameExW = modsecur32.NewProc("GetUserNameExW") + procTranslateNameW = modsecur32.NewProc("TranslateNameW") + procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") + procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") + procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW") + procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW") + procWSACleanup = modws2_32.NewProc("WSACleanup") + procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW") + procWSAIoctl = modws2_32.NewProc("WSAIoctl") + procWSARecv = modws2_32.NewProc("WSARecv") + procWSARecvFrom = modws2_32.NewProc("WSARecvFrom") + procWSASend = modws2_32.NewProc("WSASend") + procWSASendTo = modws2_32.NewProc("WSASendTo") + procWSAStartup = modws2_32.NewProc("WSAStartup") + procbind = modws2_32.NewProc("bind") + procclosesocket = modws2_32.NewProc("closesocket") + procconnect = modws2_32.NewProc("connect") + procgethostbyname = modws2_32.NewProc("gethostbyname") + procgetpeername = modws2_32.NewProc("getpeername") + procgetprotobyname = modws2_32.NewProc("getprotobyname") + procgetservbyname = modws2_32.NewProc("getservbyname") + procgetsockname = modws2_32.NewProc("getsockname") + procgetsockopt = modws2_32.NewProc("getsockopt") + proclisten = modws2_32.NewProc("listen") + procntohs = modws2_32.NewProc("ntohs") + procsetsockopt = modws2_32.NewProc("setsockopt") + procshutdown = modws2_32.NewProc("shutdown") + procsocket = modws2_32.NewProc("socket") +) + +func ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) { + r1, _, e1 := Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) { + r1, _, e1 := Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) { + r1, _, e1 := Syscall(procCopySid.Addr(), 3, uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) { + var _p0 uint32 + if inheritHandles { + _p0 = 1 + } + r1, _, e1 := Syscall12(procCreateProcessAsUserW.Addr(), 11, uintptr(token), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) { + r1, _, e1 := Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) { + r1, _, e1 := Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CryptReleaseContext(provhandle Handle, flags uint32) (err error) { + r1, _, e1 := Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetLengthSid(sid *SID) (len uint32) { + r0, _, _ := Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + len = uint32(r0) + return +} + +func GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) { + r1, _, e1 := Syscall6(procGetTokenInformation.Addr(), 5, uintptr(t), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { + r1, _, e1 := Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { + r1, _, e1 := Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func OpenProcessToken(h Handle, access uint32, token *Token) (err error) { + r1, _, e1 := Syscall(procOpenProcessToken.Addr(), 3, uintptr(h), uintptr(access), uintptr(unsafe.Pointer(token))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func RegCloseKey(key Handle) (regerrno error) { + r0, _, _ := Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0) + if r0 != 0 { + regerrno = Errno(r0) + } + return +} + +func regEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) { + r0, _, _ := Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0) + if r0 != 0 { + regerrno = Errno(r0) + } + return +} + +func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) { + r0, _, _ := Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0) + if r0 != 0 { + regerrno = Errno(r0) + } + return +} + +func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) { + r0, _, _ := Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime))) + if r0 != 0 { + regerrno = Errno(r0) + } + return +} + +func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { + r0, _, _ := Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen))) + if r0 != 0 { + regerrno = Errno(r0) + } + return +} + +func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) { + r1, _, e1 := Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CertCloseStore(store Handle, flags uint32) (err error) { + r1, _, e1 := Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) { + r0, _, e1 := Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen)) + context = (*CertContext)(unsafe.Pointer(r0)) + if context == nil { + err = errnoErr(e1) + } + return +} + +func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) { + r0, _, e1 := Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0) + context = (*CertContext)(unsafe.Pointer(r0)) + if context == nil { + err = errnoErr(e1) + } + return +} + +func CertFreeCertificateChain(ctx *CertChainContext) { + Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) + return +} + +func CertFreeCertificateContext(ctx *CertContext) (err error) { + r1, _, e1 := Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) { + r1, _, e1 := Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) { + r0, _, e1 := Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0) + handle = Handle(r0) + if handle == 0 { + err = errnoErr(e1) + } + return +} + +func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) { + r0, _, e1 := Syscall(procCertOpenSystemStoreW.Addr(), 2, uintptr(hprov), uintptr(unsafe.Pointer(name)), 0) + store = Handle(r0) + if store == 0 { + err = errnoErr(e1) + } + return +} + +func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) { + r1, _, e1 := Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) { + r0, _, _ := Syscall(procDnsNameCompare_W.Addr(), 2, uintptr(unsafe.Pointer(name1)), uintptr(unsafe.Pointer(name2)), 0) + same = r0 != 0 + return +} + +func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { + var _p0 *uint16 + _p0, status = UTF16PtrFromString(name) + if status != nil { + return + } + return _DnsQuery(_p0, qtype, options, extra, qrs, pr) +} + +func _DnsQuery(name *uint16, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { + r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(name)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) + if r0 != 0 { + status = Errno(r0) + } + return +} + +func DnsRecordListFree(rl *DNSRecord, freetype uint32) { + Syscall(procDnsRecordListFree.Addr(), 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0) + return +} + +func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) { + r0, _, _ := Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0) + if r0 != 0 { + errcode = Errno(r0) + } + return +} + +func GetIfEntry(pIfRow *MibIfRow) (errcode error) { + r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0) + if r0 != 0 { + errcode = Errno(r0) + } + return +} + +func CancelIo(s Handle) (err error) { + r1, _, e1 := Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CancelIoEx(s Handle, o *Overlapped) (err error) { + r1, _, e1 := Syscall(procCancelIoEx.Addr(), 2, uintptr(s), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CloseHandle(handle Handle) (err error) { + r1, _, e1 := Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) { + r1, _, e1 := Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) { + r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name))) + handle = Handle(r0) + if handle == 0 { + err = errnoErr(e1) + } + return +} + +func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) { + r0, _, e1 := Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) + handle = Handle(r0) + if handle == InvalidHandle { + err = errnoErr(e1) + } + return +} + +func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) { + r1, _, e1 := Syscall(procCreateHardLinkW.Addr(), 3, uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(existingfilename)), uintptr(reserved)) + if r1&0xff == 0 { + err = errnoErr(e1) + } + return +} + +func createIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) { + r0, _, e1 := Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) + handle = Handle(r0) + if handle == 0 { + err = errnoErr(e1) + } + return +} + +func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) { + r1, _, e1 := Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) { + var _p0 uint32 + if inheritHandles { + _p0 = 1 + } + r1, _, e1 := Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) { + r1, _, e1 := Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags)) + if r1&0xff == 0 { + err = errnoErr(e1) + } + return +} + +func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) { + r0, _, e1 := Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0) + handle = Handle(r0) + if handle == InvalidHandle { + err = errnoErr(e1) + } + return +} + +func DeleteFile(path *uint16) (err error) { + r1, _, e1 := Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func deleteProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST) { + Syscall(procDeleteProcThreadAttributeList.Addr(), 1, uintptr(unsafe.Pointer(attrlist)), 0, 0) + return +} + +func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), uintptr(ioControlCode), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferSize), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferSize), uintptr(unsafe.Pointer(bytesReturned)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) { + var _p0 uint32 + if bInheritHandle { + _p0 = 1 + } + r1, _, e1 := Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func ExitProcess(exitcode uint32) { + Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0) + return +} + +func FindClose(handle Handle) (err error) { + r1, _, e1 := Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) { + r0, _, e1 := Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0) + handle = Handle(r0) + if handle == InvalidHandle { + err = errnoErr(e1) + } + return +} + +func findNextFile1(handle Handle, data *win32finddata1) (err error) { + r1, _, e1 := Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func FlushFileBuffers(handle Handle) (err error) { + r1, _, e1 := Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func FlushViewOfFile(addr uintptr, length uintptr) (err error) { + r1, _, e1 := Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) { + var _p0 *uint16 + if len(buf) > 0 { + _p0 = &buf[0] + } + r0, _, e1 := Syscall9(procFormatMessageW.Addr(), 7, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func FreeEnvironmentStrings(envs *uint16) (err error) { + r1, _, e1 := Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func FreeLibrary(handle Handle) (err error) { + r1, _, e1 := Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetCommandLine() (cmd *uint16) { + r0, _, _ := Syscall(procGetCommandLineW.Addr(), 0, 0, 0, 0) + cmd = (*uint16)(unsafe.Pointer(r0)) + return +} + +func GetComputerName(buf *uint16, n *uint32) (err error) { + r1, _, e1 := Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetConsoleMode(console Handle, mode *uint32) (err error) { + r1, _, e1 := Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) { + r0, _, e1 := Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func GetCurrentProcess() (pseudoHandle Handle, err error) { + r0, _, e1 := Syscall(procGetCurrentProcess.Addr(), 0, 0, 0, 0) + pseudoHandle = Handle(r0) + if pseudoHandle == 0 { + err = errnoErr(e1) + } + return +} + +func getCurrentProcessId() (pid uint32) { + r0, _, _ := Syscall(procGetCurrentProcessId.Addr(), 0, 0, 0, 0) + pid = uint32(r0) + return +} + +func GetEnvironmentStrings() (envs *uint16, err error) { + r0, _, e1 := Syscall(procGetEnvironmentStringsW.Addr(), 0, 0, 0, 0) + envs = (*uint16)(unsafe.Pointer(r0)) + if envs == nil { + err = errnoErr(e1) + } + return +} + +func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) { + r0, _, e1 := Syscall(procGetEnvironmentVariableW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size)) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) { + r1, _, e1 := Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) { + r1, _, e1 := Syscall(procGetFileAttributesExW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetFileAttributes(name *uint16) (attrs uint32, err error) { + r0, _, e1 := Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + attrs = uint32(r0) + if attrs == INVALID_FILE_ATTRIBUTES { + err = errnoErr(e1) + } + return +} + +func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) { + r1, _, e1 := Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetFileType(filehandle Handle) (n uint32, err error) { + r0, _, e1 := Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func getFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) { + r0, _, e1 := Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0) + n = uint32(r0) + if n == 0 || n >= filePathSize { + err = errnoErr(e1) + } + return +} + +func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) { + r0, _, e1 := Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func GetLastError() (lasterr error) { + r0, _, _ := Syscall(procGetLastError.Addr(), 0, 0, 0, 0) + if r0 != 0 { + lasterr = Errno(r0) + } + return +} + +func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) { + r0, _, e1 := Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen)) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func GetProcAddress(module Handle, procname string) (proc uintptr, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(procname) + if err != nil { + return + } + return _GetProcAddress(module, _p0) +} + +func _GetProcAddress(module Handle, procname *byte) (proc uintptr, err error) { + r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(procname)), 0) + proc = uintptr(r0) + if proc == 0 { + err = errnoErr(e1) + } + return +} + +func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) { + r1, _, e1 := Syscall6(procGetProcessTimes.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func getQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) { + r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) { + r0, _, e1 := Syscall(procGetShortPathNameW.Addr(), 3, uintptr(unsafe.Pointer(longpath)), uintptr(unsafe.Pointer(shortpath)), uintptr(buflen)) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func getStartupInfo(startupInfo *StartupInfo) { + Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0) + return +} + +func GetStdHandle(stdhandle int) (handle Handle, err error) { + r0, _, e1 := Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0) + handle = Handle(r0) + if handle == InvalidHandle { + err = errnoErr(e1) + } + return +} + +func GetSystemTimeAsFileTime(time *Filetime) { + Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0) + return +} + +func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) { + r0, _, e1 := Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + +func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) { + r0, _, e1 := Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0) + rc = uint32(r0) + if rc == 0xffffffff { + err = errnoErr(e1) + } + return +} + +func GetVersion() (ver uint32, err error) { + r0, _, e1 := Syscall(procGetVersion.Addr(), 0, 0, 0, 0) + ver = uint32(r0) + if ver == 0 { + err = errnoErr(e1) + } + return +} + +func initializeProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, attrcount uint32, flags uint32, size *uintptr) (err error) { + r1, _, e1 := Syscall6(procInitializeProcThreadAttributeList.Addr(), 4, uintptr(unsafe.Pointer(attrlist)), uintptr(attrcount), uintptr(flags), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func LoadLibrary(libname string) (handle Handle, err error) { + var _p0 *uint16 + _p0, err = UTF16PtrFromString(libname) + if err != nil { + return + } + return _LoadLibrary(_p0) +} + +func _LoadLibrary(libname *uint16) (handle Handle, err error) { + r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(libname)), 0, 0) + handle = Handle(r0) + if handle == 0 { + err = errnoErr(e1) + } + return +} + +func LocalFree(hmem Handle) (handle Handle, err error) { + r0, _, e1 := Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0) + handle = Handle(r0) + if handle != 0 { + err = errnoErr(e1) + } + return +} + +func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) { + r0, _, e1 := Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0) + addr = uintptr(r0) + if addr == 0 { + err = errnoErr(e1) + } + return +} + +func MoveFile(from *uint16, to *uint16) (err error) { + r1, _, e1 := Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) { + var _p0 uint32 + if inheritHandle { + _p0 = 1 + } + r0, _, e1 := Syscall(procOpenProcess.Addr(), 3, uintptr(da), uintptr(_p0), uintptr(pid)) + handle = Handle(r0) + if handle == 0 { + err = errnoErr(e1) + } + return +} + +func postQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) { + r1, _, e1 := Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) { + r1, _, e1 := Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) { + r1, _, e1 := Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) { + r1, _, e1 := Syscall6(procReadConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(toread), uintptr(unsafe.Pointer(read)), uintptr(unsafe.Pointer(inputControl)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { + var _p0 uint32 + if watchSubTree { + _p0 = 1 + } + r1, _, e1 := Syscall9(procReadDirectoryChangesW.Addr(), 8, uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func readFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + r1, _, e1 := Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func RemoveDirectory(path *uint16) (err error) { + r1, _, e1 := Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetCurrentDirectory(path *uint16) (err error) { + r1, _, e1 := Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetEndOfFile(handle Handle) (err error) { + r1, _, e1 := Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { + r1, _, e1 := Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetFileAttributes(name *uint16, attrs uint32) (err error) { + r1, _, e1 := Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) { + r1, _, e1 := Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(handle), uintptr(flags), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) { + r0, _, e1 := Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0) + newlowoffset = uint32(r0) + if newlowoffset == 0xffffffff { + err = errnoErr(e1) + } + return +} + +func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) { + r1, _, e1 := Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) { + r1, _, e1 := Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func TerminateProcess(handle Handle, exitcode uint32) (err error) { + r1, _, e1 := Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func UnmapViewOfFile(addr uintptr) (err error) { + r1, _, e1 := Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) { + r1, _, e1 := Syscall9(procUpdateProcThreadAttribute.Addr(), 7, uintptr(unsafe.Pointer(attrlist)), uintptr(flags), uintptr(attr), uintptr(value), uintptr(size), uintptr(prevvalue), uintptr(unsafe.Pointer(returnedsize)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func VirtualLock(addr uintptr, length uintptr) (err error) { + r1, _, e1 := Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func VirtualUnlock(addr uintptr, length uintptr) (err error) { + r1, _, e1 := Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) { + r0, _, e1 := Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0) + event = uint32(r0) + if event == 0xffffffff { + err = errnoErr(e1) + } + return +} + +func WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) { + r1, _, e1 := Syscall6(procWriteConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(towrite), uintptr(unsafe.Pointer(written)), uintptr(unsafe.Pointer(reserved)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func writeFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + r1, _, e1 := Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) { + Syscall9(procGetAcceptExSockaddrs.Addr(), 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0) + return +} + +func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) { + r1, _, e1 := Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func NetApiBufferFree(buf *byte) (neterr error) { + r0, _, _ := Syscall(procNetApiBufferFree.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0) + if r0 != 0 { + neterr = Errno(r0) + } + return +} + +func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) { + r0, _, _ := Syscall(procNetGetJoinInformation.Addr(), 3, uintptr(unsafe.Pointer(server)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bufType))) + if r0 != 0 { + neterr = Errno(r0) + } + return +} + +func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) { + r0, _, _ := Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0) + if r0 != 0 { + neterr = Errno(r0) + } + return +} + +func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) { + r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize))) + if r1&0xff == 0 { + err = errnoErr(e1) + } + return +} + +func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) { + r1, _, e1 := Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0) + if r1&0xff == 0 { + err = errnoErr(e1) + } + return +} + +func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) { + r0, _, e1 := Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0) + argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0)) + if argv == nil { + err = errnoErr(e1) + } + return +} + +func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) { + r1, _, e1 := Syscall(procGetUserProfileDirectoryW.Addr(), 3, uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func FreeAddrInfoW(addrinfo *AddrinfoW) { + Syscall(procFreeAddrInfoW.Addr(), 1, uintptr(unsafe.Pointer(addrinfo)), 0, 0) + return +} + +func GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) { + r0, _, _ := Syscall6(procGetAddrInfoW.Addr(), 4, uintptr(unsafe.Pointer(nodename)), uintptr(unsafe.Pointer(servicename)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(result)), 0, 0) + if r0 != 0 { + sockerr = Errno(r0) + } + return +} + +func WSACleanup() (err error) { + r1, _, e1 := Syscall(procWSACleanup.Addr(), 0, 0, 0, 0) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) { + r0, _, e1 := Syscall(procWSAEnumProtocolsW.Addr(), 3, uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength))) + n = int32(r0) + if n == -1 { + err = errnoErr(e1) + } + return +} + +func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { + r1, _, e1 := Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine)) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func WSAStartup(verreq uint32, data *WSAData) (sockerr error) { + r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) + if r0 != 0 { + sockerr = Errno(r0) + } + return +} + +func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) { + r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func Closesocket(s Handle) (err error) { + r1, _, e1 := Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) { + r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func GetHostByName(name string) (h *Hostent, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + return _GetHostByName(_p0) +} + +func _GetHostByName(name *byte) (h *Hostent, err error) { + r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + h = (*Hostent)(unsafe.Pointer(r0)) + if h == nil { + err = errnoErr(e1) + } + return +} + +func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { + r1, _, e1 := Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func GetProtoByName(name string) (p *Protoent, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + return _GetProtoByName(_p0) +} + +func _GetProtoByName(name *byte) (p *Protoent, err error) { + r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + p = (*Protoent)(unsafe.Pointer(r0)) + if p == nil { + err = errnoErr(e1) + } + return +} + +func GetServByName(name string, proto string) (s *Servent, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(proto) + if err != nil { + return + } + return _GetServByName(_p0, _p1) +} + +func _GetServByName(name *byte, proto *byte) (s *Servent, err error) { + r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(proto)), 0) + s = (*Servent)(unsafe.Pointer(r0)) + if s == nil { + err = errnoErr(e1) + } + return +} + +func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { + r1, _, e1 := Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) { + r1, _, e1 := Syscall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(unsafe.Pointer(optlen)), 0) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func listen(s Handle, backlog int32) (err error) { + r1, _, e1 := Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func Ntohs(netshort uint16) (u uint16) { + r0, _, _ := Syscall(procntohs.Addr(), 1, uintptr(netshort), 0, 0) + u = uint16(r0) + return +} + +func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) { + r1, _, e1 := Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func shutdown(s Handle, how int32) (err error) { + r1, _, e1 := Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0) + if r1 == socket_error { + err = errnoErr(e1) + } + return +} + +func socket(af int32, typ int32, protocol int32) (handle Handle, err error) { + r0, _, e1 := Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol)) + handle = Handle(r0) + if handle == InvalidHandle { + err = errnoErr(e1) + } + return +} diff --git a/contrib/go/_std_1.22/src/syscall/zsysctl_openbsd.go b/contrib/go/_std_1.23/src/syscall/zsysctl_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysctl_openbsd.go rename to contrib/go/_std_1.23/src/syscall/zsysctl_openbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_386.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_386.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_arm.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips64le.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips64le.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_mipsle.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_mipsle.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_mipsle.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_ppc64le.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_ppc64le.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_plan9.go b/contrib/go/_std_1.23/src/syscall/zsysnum_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_plan9.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_plan9.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_aix_ppc64.go b/contrib/go/_std_1.23/src/syscall/ztypes_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_aix_ppc64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_386.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_386.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_arm.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_mips.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_mips.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_mips.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_mips64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_mips64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_mips64le.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_mips64le.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_mips64le.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_mipsle.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_mipsle.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_mipsle.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_ppc64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_ppc64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_ppc64le.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_ppc64le.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/ztypes_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/ztypes_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/ztypes_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/ztypes_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/text/tabwriter/tabwriter.go b/contrib/go/_std_1.23/src/text/tabwriter/tabwriter.go similarity index 96% rename from contrib/go/_std_1.22/src/text/tabwriter/tabwriter.go rename to contrib/go/_std_1.23/src/text/tabwriter/tabwriter.go index d4cfcf556a40..976ad251aaea 100644 --- a/contrib/go/_std_1.22/src/text/tabwriter/tabwriter.go +++ b/contrib/go/_std_1.23/src/text/tabwriter/tabwriter.go @@ -12,6 +12,7 @@ package tabwriter import ( + "fmt" "io" "unicode/utf8" ) @@ -59,7 +60,7 @@ type cell struct { // this may not be true in some fonts or if the string contains combining // characters. // -// If DiscardEmptyColumns is set, empty columns that are terminated +// If [DiscardEmptyColumns] is set, empty columns that are terminated // entirely by vertical (or "soft") tabs are discarded. Columns // terminated by horizontal (or "hard") tabs are not affected by // this flag. @@ -68,24 +69,24 @@ type cell struct { // are passed through. The widths of tags and entities are // assumed to be zero (tags) and one (entities) for formatting purposes. // -// A segment of text may be escaped by bracketing it with Escape +// A segment of text may be escaped by bracketing it with [Escape] // characters. The tabwriter passes escaped text segments through // unchanged. In particular, it does not interpret any tabs or line -// breaks within the segment. If the StripEscape flag is set, the +// breaks within the segment. If the [StripEscape] flag is set, the // Escape characters are stripped from the output; otherwise they // are passed through as well. For the purpose of formatting, the // width of the escaped text is always computed excluding the Escape // characters. // // The formfeed character acts like a newline but it also terminates -// all columns in the current line (effectively calling Flush). Tab- +// all columns in the current line (effectively calling [Writer.Flush]). Tab- // terminated cells in the next line start new columns. Unless found // inside an HTML tag or inside an escaped text segment, formfeed // characters appear as newlines in the output. // // The Writer must buffer input internally, because proper spacing // of one line may depend on the cells in future lines. Clients must -// call Flush when done calling Write. +// call Flush when done calling [Writer.Write]. type Writer struct { // configuration output io.Writer @@ -192,7 +193,7 @@ const ( Debug ) -// A Writer must be initialized with a call to Init. The first parameter (output) +// A [Writer] must be initialized with a call to Init. The first parameter (output) // specifies the filter output. The remaining parameters control the formatting: // // minwidth minimal cell width including any padding @@ -476,12 +477,12 @@ func (b *Writer) handlePanic(err *error, op string) { *err = nerr.err return } - panic("tabwriter: panic during " + op) + panic(fmt.Sprintf("tabwriter: panic during %s (%v)", op, e)) } } -// Flush should be called after the last call to Write to ensure -// that any data buffered in the Writer is written to output. Any +// Flush should be called after the last call to [Writer.Write] to ensure +// that any data buffered in the [Writer] is written to output. Any // incomplete escape sequence at the end is considered // complete for formatting purposes. func (b *Writer) Flush() error { @@ -593,7 +594,7 @@ func (b *Writer) Write(buf []byte) (n int, err error) { return } -// NewWriter allocates and initializes a new tabwriter.Writer. +// NewWriter allocates and initializes a new [Writer]. // The parameters are the same as for the Init function. func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer { return new(Writer).Init(output, minwidth, tabwidth, padding, padchar, flags) diff --git a/contrib/go/_std_1.22/src/text/tabwriter/ya.make b/contrib/go/_std_1.23/src/text/tabwriter/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/text/tabwriter/ya.make rename to contrib/go/_std_1.23/src/text/tabwriter/ya.make diff --git a/contrib/go/_std_1.23/src/text/template/doc.go b/contrib/go/_std_1.23/src/text/template/doc.go new file mode 100644 index 000000000000..b3ffaabb153c --- /dev/null +++ b/contrib/go/_std_1.23/src/text/template/doc.go @@ -0,0 +1,471 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package template implements data-driven templates for generating textual output. + +To generate HTML output, see [html/template], which has the same interface +as this package but automatically secures HTML output against certain attacks. + +Templates are executed by applying them to a data structure. Annotations in the +template refer to elements of the data structure (typically a field of a struct +or a key in a map) to control execution and derive values to be displayed. +Execution of the template walks the structure and sets the cursor, represented +by a period '.' and called "dot", to the value at the current location in the +structure as execution proceeds. + +The input text for a template is UTF-8-encoded text in any format. +"Actions"--data evaluations or control structures--are delimited by +"{{" and "}}"; all text outside actions is copied to the output unchanged. + +Once parsed, a template may be executed safely in parallel, although if parallel +executions share a Writer the output may be interleaved. + +Here is a trivial example that prints "17 items are made of wool". + + type Inventory struct { + Material string + Count uint + } + sweaters := Inventory{"wool", 17} + tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}") + if err != nil { panic(err) } + err = tmpl.Execute(os.Stdout, sweaters) + if err != nil { panic(err) } + +More intricate examples appear below. + +Text and spaces + +By default, all text between actions is copied verbatim when the template is +executed. For example, the string " items are made of " in the example above +appears on standard output when the program is run. + +However, to aid in formatting template source code, if an action's left +delimiter (by default "{{") is followed immediately by a minus sign and white +space, all trailing white space is trimmed from the immediately preceding text. +Similarly, if the right delimiter ("}}") is preceded by white space and a minus +sign, all leading white space is trimmed from the immediately following text. +In these trim markers, the white space must be present: +"{{- 3}}" is like "{{3}}" but trims the immediately preceding text, while +"{{-3}}" parses as an action containing the number -3. + +For instance, when executing the template whose source is + + "{{23 -}} < {{- 45}}" + +the generated output would be + + "23<45" + +For this trimming, the definition of white space characters is the same as in Go: +space, horizontal tab, carriage return, and newline. + +Actions + +Here is the list of actions. "Arguments" and "pipelines" are evaluations of +data, defined in detail in the corresponding sections that follow. + +*/ +// {{/* a comment */}} +// {{- /* a comment with white space trimmed from preceding and following text */ -}} +// A comment; discarded. May contain newlines. +// Comments do not nest and must start and end at the +// delimiters, as shown here. +/* + + {{pipeline}} + The default textual representation (the same as would be + printed by fmt.Print) of the value of the pipeline is copied + to the output. + + {{if pipeline}} T1 {{end}} + If the value of the pipeline is empty, no output is generated; + otherwise, T1 is executed. The empty values are false, 0, any + nil pointer or interface value, and any array, slice, map, or + string of length zero. + Dot is unaffected. + + {{if pipeline}} T1 {{else}} T0 {{end}} + If the value of the pipeline is empty, T0 is executed; + otherwise, T1 is executed. Dot is unaffected. + + {{if pipeline}} T1 {{else if pipeline}} T0 {{end}} + To simplify the appearance of if-else chains, the else action + of an if may include another if directly; the effect is exactly + the same as writing + {{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}} + + {{range pipeline}} T1 {{end}} + The value of the pipeline must be an array, slice, map, or channel. + If the value of the pipeline has length zero, nothing is output; + otherwise, dot is set to the successive elements of the array, + slice, or map and T1 is executed. If the value is a map and the + keys are of basic type with a defined order, the elements will be + visited in sorted key order. + + {{range pipeline}} T1 {{else}} T0 {{end}} + The value of the pipeline must be an array, slice, map, or channel. + If the value of the pipeline has length zero, dot is unaffected and + T0 is executed; otherwise, dot is set to the successive elements + of the array, slice, or map and T1 is executed. + + {{break}} + The innermost {{range pipeline}} loop is ended early, stopping the + current iteration and bypassing all remaining iterations. + + {{continue}} + The current iteration of the innermost {{range pipeline}} loop is + stopped, and the loop starts the next iteration. + + {{template "name"}} + The template with the specified name is executed with nil data. + + {{template "name" pipeline}} + The template with the specified name is executed with dot set + to the value of the pipeline. + + {{block "name" pipeline}} T1 {{end}} + A block is shorthand for defining a template + {{define "name"}} T1 {{end}} + and then executing it in place + {{template "name" pipeline}} + The typical use is to define a set of root templates that are + then customized by redefining the block templates within. + + {{with pipeline}} T1 {{end}} + If the value of the pipeline is empty, no output is generated; + otherwise, dot is set to the value of the pipeline and T1 is + executed. + + {{with pipeline}} T1 {{else}} T0 {{end}} + If the value of the pipeline is empty, dot is unaffected and T0 + is executed; otherwise, dot is set to the value of the pipeline + and T1 is executed. + + {{with pipeline}} T1 {{else with pipeline}} T0 {{end}} + To simplify the appearance of with-else chains, the else action + of a with may include another with directly; the effect is exactly + the same as writing + {{with pipeline}} T1 {{else}}{{with pipeline}} T0 {{end}}{{end}} + + +Arguments + +An argument is a simple value, denoted by one of the following. + + - A boolean, string, character, integer, floating-point, imaginary + or complex constant in Go syntax. These behave like Go's untyped + constants. Note that, as in Go, whether a large integer constant + overflows when assigned or passed to a function can depend on whether + the host machine's ints are 32 or 64 bits. + - The keyword nil, representing an untyped Go nil. + - The character '.' (period): + . + The result is the value of dot. + - A variable name, which is a (possibly empty) alphanumeric string + preceded by a dollar sign, such as + $piOver2 + or + $ + The result is the value of the variable. + Variables are described below. + - The name of a field of the data, which must be a struct, preceded + by a period, such as + .Field + The result is the value of the field. Field invocations may be + chained: + .Field1.Field2 + Fields can also be evaluated on variables, including chaining: + $x.Field1.Field2 + - The name of a key of the data, which must be a map, preceded + by a period, such as + .Key + The result is the map element value indexed by the key. + Key invocations may be chained and combined with fields to any + depth: + .Field1.Key1.Field2.Key2 + Although the key must be an alphanumeric identifier, unlike with + field names they do not need to start with an upper case letter. + Keys can also be evaluated on variables, including chaining: + $x.key1.key2 + - The name of a niladic method of the data, preceded by a period, + such as + .Method + The result is the value of invoking the method with dot as the + receiver, dot.Method(). Such a method must have one return value (of + any type) or two return values, the second of which is an error. + If it has two and the returned error is non-nil, execution terminates + and an error is returned to the caller as the value of Execute. + Method invocations may be chained and combined with fields and keys + to any depth: + .Field1.Key1.Method1.Field2.Key2.Method2 + Methods can also be evaluated on variables, including chaining: + $x.Method1.Field + - The name of a niladic function, such as + fun + The result is the value of invoking the function, fun(). The return + types and values behave as in methods. Functions and function + names are described below. + - A parenthesized instance of one the above, for grouping. The result + may be accessed by a field or map key invocation. + print (.F1 arg1) (.F2 arg2) + (.StructValuedMethod "arg").Field + +Arguments may evaluate to any type; if they are pointers the implementation +automatically indirects to the base type when required. +If an evaluation yields a function value, such as a function-valued +field of a struct, the function is not invoked automatically, but it +can be used as a truth value for an if action and the like. To invoke +it, use the call function, defined below. + +Pipelines + +A pipeline is a possibly chained sequence of "commands". A command is a simple +value (argument) or a function or method call, possibly with multiple arguments: + + Argument + The result is the value of evaluating the argument. + .Method [Argument...] + The method can be alone or the last element of a chain but, + unlike methods in the middle of a chain, it can take arguments. + The result is the value of calling the method with the + arguments: + dot.Method(Argument1, etc.) + functionName [Argument...] + The result is the value of calling the function associated + with the name: + function(Argument1, etc.) + Functions and function names are described below. + +A pipeline may be "chained" by separating a sequence of commands with pipeline +characters '|'. In a chained pipeline, the result of each command is +passed as the last argument of the following command. The output of the final +command in the pipeline is the value of the pipeline. + +The output of a command will be either one value or two values, the second of +which has type error. If that second value is present and evaluates to +non-nil, execution terminates and the error is returned to the caller of +Execute. + +Variables + +A pipeline inside an action may initialize a variable to capture the result. +The initialization has syntax + + $variable := pipeline + +where $variable is the name of the variable. An action that declares a +variable produces no output. + +Variables previously declared can also be assigned, using the syntax + + $variable = pipeline + +If a "range" action initializes a variable, the variable is set to the +successive elements of the iteration. Also, a "range" may declare two +variables, separated by a comma: + + range $index, $element := pipeline + +in which case $index and $element are set to the successive values of the +array/slice index or map key and element, respectively. Note that if there is +only one variable, it is assigned the element; this is opposite to the +convention in Go range clauses. + +A variable's scope extends to the "end" action of the control structure ("if", +"with", or "range") in which it is declared, or to the end of the template if +there is no such control structure. A template invocation does not inherit +variables from the point of its invocation. + +When execution begins, $ is set to the data argument passed to Execute, that is, +to the starting value of dot. + +Examples + +Here are some example one-line templates demonstrating pipelines and variables. +All produce the quoted word "output": + + {{"\"output\""}} + A string constant. + {{`"output"`}} + A raw string constant. + {{printf "%q" "output"}} + A function call. + {{"output" | printf "%q"}} + A function call whose final argument comes from the previous + command. + {{printf "%q" (print "out" "put")}} + A parenthesized argument. + {{"put" | printf "%s%s" "out" | printf "%q"}} + A more elaborate call. + {{"output" | printf "%s" | printf "%q"}} + A longer chain. + {{with "output"}}{{printf "%q" .}}{{end}} + A with action using dot. + {{with $x := "output" | printf "%q"}}{{$x}}{{end}} + A with action that creates and uses a variable. + {{with $x := "output"}}{{printf "%q" $x}}{{end}} + A with action that uses the variable in another action. + {{with $x := "output"}}{{$x | printf "%q"}}{{end}} + The same, but pipelined. + +Functions + +During execution functions are found in two function maps: first in the +template, then in the global function map. By default, no functions are defined +in the template but the Funcs method can be used to add them. + +Predefined global functions are named as follows. + + and + Returns the boolean AND of its arguments by returning the + first empty argument or the last argument. That is, + "and x y" behaves as "if x then y else x." + Evaluation proceeds through the arguments left to right + and returns when the result is determined. + call + Returns the result of calling the first argument, which + must be a function, with the remaining arguments as parameters. + Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where + Y is a func-valued field, map entry, or the like. + The first argument must be the result of an evaluation + that yields a value of function type (as distinct from + a predefined function such as print). The function must + return either one or two result values, the second of which + is of type error. If the arguments don't match the function + or the returned error value is non-nil, execution stops. + html + Returns the escaped HTML equivalent of the textual + representation of its arguments. This function is unavailable + in html/template, with a few exceptions. + index + Returns the result of indexing its first argument by the + following arguments. Thus "index x 1 2 3" is, in Go syntax, + x[1][2][3]. Each indexed item must be a map, slice, or array. + slice + slice returns the result of slicing its first argument by the + remaining arguments. Thus "slice x 1 2" is, in Go syntax, x[1:2], + while "slice x" is x[:], "slice x 1" is x[1:], and "slice x 1 2 3" + is x[1:2:3]. The first argument must be a string, slice, or array. + js + Returns the escaped JavaScript equivalent of the textual + representation of its arguments. + len + Returns the integer length of its argument. + not + Returns the boolean negation of its single argument. + or + Returns the boolean OR of its arguments by returning the + first non-empty argument or the last argument, that is, + "or x y" behaves as "if x then x else y". + Evaluation proceeds through the arguments left to right + and returns when the result is determined. + print + An alias for fmt.Sprint + printf + An alias for fmt.Sprintf + println + An alias for fmt.Sprintln + urlquery + Returns the escaped value of the textual representation of + its arguments in a form suitable for embedding in a URL query. + This function is unavailable in html/template, with a few + exceptions. + +The boolean functions take any zero value to be false and a non-zero +value to be true. + +There is also a set of binary comparison operators defined as +functions: + + eq + Returns the boolean truth of arg1 == arg2 + ne + Returns the boolean truth of arg1 != arg2 + lt + Returns the boolean truth of arg1 < arg2 + le + Returns the boolean truth of arg1 <= arg2 + gt + Returns the boolean truth of arg1 > arg2 + ge + Returns the boolean truth of arg1 >= arg2 + +For simpler multi-way equality tests, eq (only) accepts two or more +arguments and compares the second and subsequent to the first, +returning in effect + + arg1==arg2 || arg1==arg3 || arg1==arg4 ... + +(Unlike with || in Go, however, eq is a function call and all the +arguments will be evaluated.) + +The comparison functions work on any values whose type Go defines as +comparable. For basic types such as integers, the rules are relaxed: +size and exact type are ignored, so any integer value, signed or unsigned, +may be compared with any other integer value. (The arithmetic value is compared, +not the bit pattern, so all negative integers are less than all unsigned integers.) +However, as usual, one may not compare an int with a float32 and so on. + +Associated templates + +Each template is named by a string specified when it is created. Also, each +template is associated with zero or more other templates that it may invoke by +name; such associations are transitive and form a name space of templates. + +A template may use a template invocation to instantiate another associated +template; see the explanation of the "template" action above. The name must be +that of a template associated with the template that contains the invocation. + +Nested template definitions + +When parsing a template, another template may be defined and associated with the +template being parsed. Template definitions must appear at the top level of the +template, much like global variables in a Go program. + +The syntax of such definitions is to surround each template declaration with a +"define" and "end" action. + +The define action names the template being created by providing a string +constant. Here is a simple example: + + {{define "T1"}}ONE{{end}} + {{define "T2"}}TWO{{end}} + {{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}} + {{template "T3"}} + +This defines two templates, T1 and T2, and a third T3 that invokes the other two +when it is executed. Finally it invokes T3. If executed this template will +produce the text + + ONE TWO + +By construction, a template may reside in only one association. If it's +necessary to have a template addressable from multiple associations, the +template definition must be parsed multiple times to create distinct *Template +values, or must be copied with [Template.Clone] or [Template.AddParseTree]. + +Parse may be called multiple times to assemble the various associated templates; +see [ParseFiles], [ParseGlob], [Template.ParseFiles] and [Template.ParseGlob] +for simple ways to parse related templates stored in files. + +A template may be executed directly or through [Template.ExecuteTemplate], which executes +an associated template identified by name. To invoke our example above, we +might write, + + err := tmpl.Execute(os.Stdout, "no data needed") + if err != nil { + log.Fatalf("execution failed: %s", err) + } + +or to invoke a particular template explicitly by name, + + err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed") + if err != nil { + log.Fatalf("execution failed: %s", err) + } + +*/ +package template diff --git a/contrib/go/_std_1.23/src/text/template/exec.go b/contrib/go/_std_1.23/src/text/template/exec.go new file mode 100644 index 000000000000..5b35b3e5a85b --- /dev/null +++ b/contrib/go/_std_1.23/src/text/template/exec.go @@ -0,0 +1,1075 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package template + +import ( + "errors" + "fmt" + "internal/fmtsort" + "io" + "reflect" + "runtime" + "strings" + "text/template/parse" +) + +// maxExecDepth specifies the maximum stack depth of templates within +// templates. This limit is only practically reached by accidentally +// recursive template invocations. This limit allows us to return +// an error instead of triggering a stack overflow. +var maxExecDepth = initMaxExecDepth() + +func initMaxExecDepth() int { + if runtime.GOARCH == "wasm" { + return 1000 + } + return 100000 +} + +// state represents the state of an execution. It's not part of the +// template so that multiple executions of the same template +// can execute in parallel. +type state struct { + tmpl *Template + wr io.Writer + node parse.Node // current node, for errors + vars []variable // push-down stack of variable values. + depth int // the height of the stack of executing templates. +} + +// variable holds the dynamic value of a variable such as $, $x etc. +type variable struct { + name string + value reflect.Value +} + +// push pushes a new variable on the stack. +func (s *state) push(name string, value reflect.Value) { + s.vars = append(s.vars, variable{name, value}) +} + +// mark returns the length of the variable stack. +func (s *state) mark() int { + return len(s.vars) +} + +// pop pops the variable stack up to the mark. +func (s *state) pop(mark int) { + s.vars = s.vars[0:mark] +} + +// setVar overwrites the last declared variable with the given name. +// Used by variable assignments. +func (s *state) setVar(name string, value reflect.Value) { + for i := s.mark() - 1; i >= 0; i-- { + if s.vars[i].name == name { + s.vars[i].value = value + return + } + } + s.errorf("undefined variable: %s", name) +} + +// setTopVar overwrites the top-nth variable on the stack. Used by range iterations. +func (s *state) setTopVar(n int, value reflect.Value) { + s.vars[len(s.vars)-n].value = value +} + +// varValue returns the value of the named variable. +func (s *state) varValue(name string) reflect.Value { + for i := s.mark() - 1; i >= 0; i-- { + if s.vars[i].name == name { + return s.vars[i].value + } + } + s.errorf("undefined variable: %s", name) + return zero +} + +var zero reflect.Value + +type missingValType struct{} + +var missingVal = reflect.ValueOf(missingValType{}) + +var missingValReflectType = reflect.TypeFor[missingValType]() + +func isMissing(v reflect.Value) bool { + return v.IsValid() && v.Type() == missingValReflectType +} + +// at marks the state to be on node n, for error reporting. +func (s *state) at(node parse.Node) { + s.node = node +} + +// doublePercent returns the string with %'s replaced by %%, if necessary, +// so it can be used safely inside a Printf format string. +func doublePercent(str string) string { + return strings.ReplaceAll(str, "%", "%%") +} + +// TODO: It would be nice if ExecError was more broken down, but +// the way ErrorContext embeds the template name makes the +// processing too clumsy. + +// ExecError is the custom error type returned when Execute has an +// error evaluating its template. (If a write error occurs, the actual +// error is returned; it will not be of type ExecError.) +type ExecError struct { + Name string // Name of template. + Err error // Pre-formatted error. +} + +func (e ExecError) Error() string { + return e.Err.Error() +} + +func (e ExecError) Unwrap() error { + return e.Err +} + +// errorf records an ExecError and terminates processing. +func (s *state) errorf(format string, args ...any) { + name := doublePercent(s.tmpl.Name()) + if s.node == nil { + format = fmt.Sprintf("template: %s: %s", name, format) + } else { + location, context := s.tmpl.ErrorContext(s.node) + format = fmt.Sprintf("template: %s: executing %q at <%s>: %s", location, name, doublePercent(context), format) + } + panic(ExecError{ + Name: s.tmpl.Name(), + Err: fmt.Errorf(format, args...), + }) +} + +// writeError is the wrapper type used internally when Execute has an +// error writing to its output. We strip the wrapper in errRecover. +// Note that this is not an implementation of error, so it cannot escape +// from the package as an error value. +type writeError struct { + Err error // Original error. +} + +func (s *state) writeError(err error) { + panic(writeError{ + Err: err, + }) +} + +// errRecover is the handler that turns panics into returns from the top +// level of Parse. +func errRecover(errp *error) { + e := recover() + if e != nil { + switch err := e.(type) { + case runtime.Error: + panic(e) + case writeError: + *errp = err.Err // Strip the wrapper. + case ExecError: + *errp = err // Keep the wrapper. + default: + panic(e) + } + } +} + +// ExecuteTemplate applies the template associated with t that has the given name +// to the specified data object and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. +func (t *Template) ExecuteTemplate(wr io.Writer, name string, data any) error { + tmpl := t.Lookup(name) + if tmpl == nil { + return fmt.Errorf("template: no template %q associated with template %q", name, t.name) + } + return tmpl.Execute(wr, data) +} + +// Execute applies a parsed template to the specified data object, +// and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. +// +// If data is a [reflect.Value], the template applies to the concrete +// value that the reflect.Value holds, as in [fmt.Print]. +func (t *Template) Execute(wr io.Writer, data any) error { + return t.execute(wr, data) +} + +func (t *Template) execute(wr io.Writer, data any) (err error) { + defer errRecover(&err) + value, ok := data.(reflect.Value) + if !ok { + value = reflect.ValueOf(data) + } + state := &state{ + tmpl: t, + wr: wr, + vars: []variable{{"$", value}}, + } + if t.Tree == nil || t.Root == nil { + state.errorf("%q is an incomplete or empty template", t.Name()) + } + state.walk(value, t.Root) + return +} + +// DefinedTemplates returns a string listing the defined templates, +// prefixed by the string "; defined templates are: ". If there are none, +// it returns the empty string. For generating an error message here +// and in [html/template]. +func (t *Template) DefinedTemplates() string { + if t.common == nil { + return "" + } + var b strings.Builder + t.muTmpl.RLock() + defer t.muTmpl.RUnlock() + for name, tmpl := range t.tmpl { + if tmpl.Tree == nil || tmpl.Root == nil { + continue + } + if b.Len() == 0 { + b.WriteString("; defined templates are: ") + } else { + b.WriteString(", ") + } + fmt.Fprintf(&b, "%q", name) + } + return b.String() +} + +// Sentinel errors for use with panic to signal early exits from range loops. +var ( + walkBreak = errors.New("break") + walkContinue = errors.New("continue") +) + +// Walk functions step through the major pieces of the template structure, +// generating output as they go. +func (s *state) walk(dot reflect.Value, node parse.Node) { + s.at(node) + switch node := node.(type) { + case *parse.ActionNode: + // Do not pop variables so they persist until next end. + // Also, if the action declares variables, don't print the result. + val := s.evalPipeline(dot, node.Pipe) + if len(node.Pipe.Decl) == 0 { + s.printValue(node, val) + } + case *parse.BreakNode: + panic(walkBreak) + case *parse.CommentNode: + case *parse.ContinueNode: + panic(walkContinue) + case *parse.IfNode: + s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) + case *parse.ListNode: + for _, node := range node.Nodes { + s.walk(dot, node) + } + case *parse.RangeNode: + s.walkRange(dot, node) + case *parse.TemplateNode: + s.walkTemplate(dot, node) + case *parse.TextNode: + if _, err := s.wr.Write(node.Text); err != nil { + s.writeError(err) + } + case *parse.WithNode: + s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList) + default: + s.errorf("unknown node: %s", node) + } +} + +// walkIfOrWith walks an 'if' or 'with' node. The two control structures +// are identical in behavior except that 'with' sets dot. +func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) { + defer s.pop(s.mark()) + val := s.evalPipeline(dot, pipe) + truth, ok := isTrue(indirectInterface(val)) + if !ok { + s.errorf("if/with can't use %v", val) + } + if truth { + if typ == parse.NodeWith { + s.walk(val, list) + } else { + s.walk(dot, list) + } + } else if elseList != nil { + s.walk(dot, elseList) + } +} + +// IsTrue reports whether the value is 'true', in the sense of not the zero of its type, +// and whether the value has a meaningful truth value. This is the definition of +// truth used by if and other such actions. +func IsTrue(val any) (truth, ok bool) { + return isTrue(reflect.ValueOf(val)) +} + +func isTrue(val reflect.Value) (truth, ok bool) { + if !val.IsValid() { + // Something like var x interface{}, never set. It's a form of nil. + return false, true + } + switch val.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + truth = val.Len() > 0 + case reflect.Bool: + truth = val.Bool() + case reflect.Complex64, reflect.Complex128: + truth = val.Complex() != 0 + case reflect.Chan, reflect.Func, reflect.Pointer, reflect.Interface: + truth = !val.IsNil() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + truth = val.Int() != 0 + case reflect.Float32, reflect.Float64: + truth = val.Float() != 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + truth = val.Uint() != 0 + case reflect.Struct: + truth = true // Struct values are always true. + default: + return + } + return truth, true +} + +func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { + s.at(r) + defer func() { + if r := recover(); r != nil && r != walkBreak { + panic(r) + } + }() + defer s.pop(s.mark()) + val, _ := indirect(s.evalPipeline(dot, r.Pipe)) + // mark top of stack before any variables in the body are pushed. + mark := s.mark() + oneIteration := func(index, elem reflect.Value) { + if len(r.Pipe.Decl) > 0 { + if r.Pipe.IsAssign { + // With two variables, index comes first. + // With one, we use the element. + if len(r.Pipe.Decl) > 1 { + s.setVar(r.Pipe.Decl[0].Ident[0], index) + } else { + s.setVar(r.Pipe.Decl[0].Ident[0], elem) + } + } else { + // Set top var (lexically the second if there + // are two) to the element. + s.setTopVar(1, elem) + } + } + if len(r.Pipe.Decl) > 1 { + if r.Pipe.IsAssign { + s.setVar(r.Pipe.Decl[1].Ident[0], elem) + } else { + // Set next var (lexically the first if there + // are two) to the index. + s.setTopVar(2, index) + } + } + defer s.pop(mark) + defer func() { + // Consume panic(walkContinue) + if r := recover(); r != nil && r != walkContinue { + panic(r) + } + }() + s.walk(elem, r.List) + } + switch val.Kind() { + case reflect.Array, reflect.Slice: + if val.Len() == 0 { + break + } + for i := 0; i < val.Len(); i++ { + oneIteration(reflect.ValueOf(i), val.Index(i)) + } + return + case reflect.Map: + if val.Len() == 0 { + break + } + om := fmtsort.Sort(val) + for _, m := range om { + oneIteration(m.Key, m.Value) + } + return + case reflect.Chan: + if val.IsNil() { + break + } + if val.Type().ChanDir() == reflect.SendDir { + s.errorf("range over send-only channel %v", val) + break + } + i := 0 + for ; ; i++ { + elem, ok := val.Recv() + if !ok { + break + } + oneIteration(reflect.ValueOf(i), elem) + } + if i == 0 { + break + } + return + case reflect.Invalid: + break // An invalid value is likely a nil map, etc. and acts like an empty map. + default: + s.errorf("range can't iterate over %v", val) + } + if r.ElseList != nil { + s.walk(dot, r.ElseList) + } +} + +func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) { + s.at(t) + tmpl := s.tmpl.Lookup(t.Name) + if tmpl == nil { + s.errorf("template %q not defined", t.Name) + } + if s.depth == maxExecDepth { + s.errorf("exceeded maximum template depth (%v)", maxExecDepth) + } + // Variables declared by the pipeline persist. + dot = s.evalPipeline(dot, t.Pipe) + newState := *s + newState.depth++ + newState.tmpl = tmpl + // No dynamic scoping: template invocations inherit no variables. + newState.vars = []variable{{"$", dot}} + newState.walk(dot, tmpl.Root) +} + +// Eval functions evaluate pipelines, commands, and their elements and extract +// values from the data structure by examining fields, calling methods, and so on. +// The printing of those values happens only through walk functions. + +// evalPipeline returns the value acquired by evaluating a pipeline. If the +// pipeline has a variable declaration, the variable will be pushed on the +// stack. Callers should therefore pop the stack after they are finished +// executing commands depending on the pipeline value. +func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value reflect.Value) { + if pipe == nil { + return + } + s.at(pipe) + value = missingVal + for _, cmd := range pipe.Cmds { + value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg. + // If the object has type interface{}, dig down one level to the thing inside. + if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 { + value = value.Elem() + } + } + for _, variable := range pipe.Decl { + if pipe.IsAssign { + s.setVar(variable.Ident[0], value) + } else { + s.push(variable.Ident[0], value) + } + } + return value +} + +func (s *state) notAFunction(args []parse.Node, final reflect.Value) { + if len(args) > 1 || !isMissing(final) { + s.errorf("can't give argument to non-function %s", args[0]) + } +} + +func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final reflect.Value) reflect.Value { + firstWord := cmd.Args[0] + switch n := firstWord.(type) { + case *parse.FieldNode: + return s.evalFieldNode(dot, n, cmd.Args, final) + case *parse.ChainNode: + return s.evalChainNode(dot, n, cmd.Args, final) + case *parse.IdentifierNode: + // Must be a function. + return s.evalFunction(dot, n, cmd, cmd.Args, final) + case *parse.PipeNode: + // Parenthesized pipeline. The arguments are all inside the pipeline; final must be absent. + s.notAFunction(cmd.Args, final) + return s.evalPipeline(dot, n) + case *parse.VariableNode: + return s.evalVariableNode(dot, n, cmd.Args, final) + } + s.at(firstWord) + s.notAFunction(cmd.Args, final) + switch word := firstWord.(type) { + case *parse.BoolNode: + return reflect.ValueOf(word.True) + case *parse.DotNode: + return dot + case *parse.NilNode: + s.errorf("nil is not a command") + case *parse.NumberNode: + return s.idealConstant(word) + case *parse.StringNode: + return reflect.ValueOf(word.Text) + } + s.errorf("can't evaluate command %q", firstWord) + panic("not reached") +} + +// idealConstant is called to return the value of a number in a context where +// we don't know the type. In that case, the syntax of the number tells us +// its type, and we use Go rules to resolve. Note there is no such thing as +// a uint ideal constant in this situation - the value must be of int type. +func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value { + // These are ideal constants but we don't know the type + // and we have no context. (If it was a method argument, + // we'd know what we need.) The syntax guides us to some extent. + s.at(constant) + switch { + case constant.IsComplex: + return reflect.ValueOf(constant.Complex128) // incontrovertible. + + case constant.IsFloat && + !isHexInt(constant.Text) && !isRuneInt(constant.Text) && + strings.ContainsAny(constant.Text, ".eEpP"): + return reflect.ValueOf(constant.Float64) + + case constant.IsInt: + n := int(constant.Int64) + if int64(n) != constant.Int64 { + s.errorf("%s overflows int", constant.Text) + } + return reflect.ValueOf(n) + + case constant.IsUint: + s.errorf("%s overflows int", constant.Text) + } + return zero +} + +func isRuneInt(s string) bool { + return len(s) > 0 && s[0] == '\'' +} + +func isHexInt(s string) bool { + return len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && !strings.ContainsAny(s, "pP") +} + +func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value { + s.at(field) + return s.evalFieldChain(dot, dot, field, field.Ident, args, final) +} + +func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value { + s.at(chain) + if len(chain.Field) == 0 { + s.errorf("internal error: no fields in evalChainNode") + } + if chain.Node.Type() == parse.NodeNil { + s.errorf("indirection through explicit nil in %s", chain) + } + // (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields. + pipe := s.evalArg(dot, nil, chain.Node) + return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final) +} + +func (s *state) evalVariableNode(dot reflect.Value, variable *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value { + // $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields. + s.at(variable) + value := s.varValue(variable.Ident[0]) + if len(variable.Ident) == 1 { + s.notAFunction(args, final) + return value + } + return s.evalFieldChain(dot, value, variable, variable.Ident[1:], args, final) +} + +// evalFieldChain evaluates .X.Y.Z possibly followed by arguments. +// dot is the environment in which to evaluate arguments, while +// receiver is the value being walked along the chain. +func (s *state) evalFieldChain(dot, receiver reflect.Value, node parse.Node, ident []string, args []parse.Node, final reflect.Value) reflect.Value { + n := len(ident) + for i := 0; i < n-1; i++ { + receiver = s.evalField(dot, ident[i], node, nil, missingVal, receiver) + } + // Now if it's a method, it gets the arguments. + return s.evalField(dot, ident[n-1], node, args, final, receiver) +} + +func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd parse.Node, args []parse.Node, final reflect.Value) reflect.Value { + s.at(node) + name := node.Ident + function, isBuiltin, ok := findFunction(name, s.tmpl) + if !ok { + s.errorf("%q is not a defined function", name) + } + return s.evalCall(dot, function, isBuiltin, cmd, name, args, final) +} + +// evalField evaluates an expression like (.Field) or (.Field arg1 arg2). +// The 'final' argument represents the return value from the preceding +// value of the pipeline, if any. +func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value { + if !receiver.IsValid() { + if s.tmpl.option.missingKey == mapError { // Treat invalid value as missing map key. + s.errorf("nil data; no entry for key %q", fieldName) + } + return zero + } + typ := receiver.Type() + receiver, isNil := indirect(receiver) + if receiver.Kind() == reflect.Interface && isNil { + // Calling a method on a nil interface can't work. The + // MethodByName method call below would panic. + s.errorf("nil pointer evaluating %s.%s", typ, fieldName) + return zero + } + + // Unless it's an interface, need to get to a value of type *T to guarantee + // we see all methods of T and *T. + ptr := receiver + if ptr.Kind() != reflect.Interface && ptr.Kind() != reflect.Pointer && ptr.CanAddr() { + ptr = ptr.Addr() + } + if method := ptr.MethodByName(fieldName); method.IsValid() { + return s.evalCall(dot, method, false, node, fieldName, args, final) + } + hasArgs := len(args) > 1 || !isMissing(final) + // It's not a method; must be a field of a struct or an element of a map. + switch receiver.Kind() { + case reflect.Struct: + tField, ok := receiver.Type().FieldByName(fieldName) + if ok { + field, err := receiver.FieldByIndexErr(tField.Index) + if !tField.IsExported() { + s.errorf("%s is an unexported field of struct type %s", fieldName, typ) + } + if err != nil { + s.errorf("%v", err) + } + // If it's a function, we must call it. + if hasArgs { + s.errorf("%s has arguments but cannot be invoked as function", fieldName) + } + return field + } + case reflect.Map: + // If it's a map, attempt to use the field name as a key. + nameVal := reflect.ValueOf(fieldName) + if nameVal.Type().AssignableTo(receiver.Type().Key()) { + if hasArgs { + s.errorf("%s is not a method but has arguments", fieldName) + } + result := receiver.MapIndex(nameVal) + if !result.IsValid() { + switch s.tmpl.option.missingKey { + case mapInvalid: + // Just use the invalid value. + case mapZeroValue: + result = reflect.Zero(receiver.Type().Elem()) + case mapError: + s.errorf("map has no entry for key %q", fieldName) + } + } + return result + } + case reflect.Pointer: + etyp := receiver.Type().Elem() + if etyp.Kind() == reflect.Struct { + if _, ok := etyp.FieldByName(fieldName); !ok { + // If there's no such field, say "can't evaluate" + // instead of "nil pointer evaluating". + break + } + } + if isNil { + s.errorf("nil pointer evaluating %s.%s", typ, fieldName) + } + } + s.errorf("can't evaluate field %s in type %s", fieldName, typ) + panic("not reached") +} + +var ( + errorType = reflect.TypeFor[error]() + fmtStringerType = reflect.TypeFor[fmt.Stringer]() + reflectValueType = reflect.TypeFor[reflect.Value]() +) + +// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so +// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0] +// as the function itself. +func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value { + if args != nil { + args = args[1:] // Zeroth arg is function name/node; not passed to function. + } + typ := fun.Type() + numIn := len(args) + if !isMissing(final) { + numIn++ + } + numFixed := len(args) + if typ.IsVariadic() { + numFixed = typ.NumIn() - 1 // last arg is the variadic one. + if numIn < numFixed { + s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args)) + } + } else if numIn != typ.NumIn() { + s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), numIn) + } + if err := goodFunc(name, typ); err != nil { + s.errorf("%v", err) + } + + unwrap := func(v reflect.Value) reflect.Value { + if v.Type() == reflectValueType { + v = v.Interface().(reflect.Value) + } + return v + } + + // Special case for builtin and/or, which short-circuit. + if isBuiltin && (name == "and" || name == "or") { + argType := typ.In(0) + var v reflect.Value + for _, arg := range args { + v = s.evalArg(dot, argType, arg).Interface().(reflect.Value) + if truth(v) == (name == "or") { + // This value was already unwrapped + // by the .Interface().(reflect.Value). + return v + } + } + if final != missingVal { + // The last argument to and/or is coming from + // the pipeline. We didn't short circuit on an earlier + // argument, so we are going to return this one. + // We don't have to evaluate final, but we do + // have to check its type. Then, since we are + // going to return it, we have to unwrap it. + v = unwrap(s.validateType(final, argType)) + } + return v + } + + // Build the arg list. + argv := make([]reflect.Value, numIn) + // Args must be evaluated. Fixed args first. + i := 0 + for ; i < numFixed && i < len(args); i++ { + argv[i] = s.evalArg(dot, typ.In(i), args[i]) + } + // Now the ... args. + if typ.IsVariadic() { + argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice. + for ; i < len(args); i++ { + argv[i] = s.evalArg(dot, argType, args[i]) + } + } + // Add final value if necessary. + if !isMissing(final) { + t := typ.In(typ.NumIn() - 1) + if typ.IsVariadic() { + if numIn-1 < numFixed { + // The added final argument corresponds to a fixed parameter of the function. + // Validate against the type of the actual parameter. + t = typ.In(numIn - 1) + } else { + // The added final argument corresponds to the variadic part. + // Validate against the type of the elements of the variadic slice. + t = t.Elem() + } + } + argv[i] = s.validateType(final, t) + } + + // Special case for the "call" builtin. + // Insert the name of the callee function as the first argument. + if isBuiltin && name == "call" { + calleeName := args[0].String() + argv = append([]reflect.Value{reflect.ValueOf(calleeName)}, argv...) + fun = reflect.ValueOf(call) + } + + v, err := safeCall(fun, argv) + // If we have an error that is not nil, stop execution and return that + // error to the caller. + if err != nil { + s.at(node) + s.errorf("error calling %s: %w", name, err) + } + return unwrap(v) +} + +// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero. +func canBeNil(typ reflect.Type) bool { + switch typ.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice: + return true + case reflect.Struct: + return typ == reflectValueType + } + return false +} + +// validateType guarantees that the value is valid and assignable to the type. +func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value { + if !value.IsValid() { + if typ == nil { + // An untyped nil interface{}. Accept as a proper nil value. + return reflect.ValueOf(nil) + } + if canBeNil(typ) { + // Like above, but use the zero value of the non-nil type. + return reflect.Zero(typ) + } + s.errorf("invalid value; expected %s", typ) + } + if typ == reflectValueType && value.Type() != typ { + return reflect.ValueOf(value) + } + if typ != nil && !value.Type().AssignableTo(typ) { + if value.Kind() == reflect.Interface && !value.IsNil() { + value = value.Elem() + if value.Type().AssignableTo(typ) { + return value + } + // fallthrough + } + // Does one dereference or indirection work? We could do more, as we + // do with method receivers, but that gets messy and method receivers + // are much more constrained, so it makes more sense there than here. + // Besides, one is almost always all you need. + switch { + case value.Kind() == reflect.Pointer && value.Type().Elem().AssignableTo(typ): + value = value.Elem() + if !value.IsValid() { + s.errorf("dereference of nil pointer of type %s", typ) + } + case reflect.PointerTo(value.Type()).AssignableTo(typ) && value.CanAddr(): + value = value.Addr() + default: + s.errorf("wrong type for value; expected %s; got %s", typ, value.Type()) + } + } + return value +} + +func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + switch arg := n.(type) { + case *parse.DotNode: + return s.validateType(dot, typ) + case *parse.NilNode: + if canBeNil(typ) { + return reflect.Zero(typ) + } + s.errorf("cannot assign nil to %s", typ) + case *parse.FieldNode: + return s.validateType(s.evalFieldNode(dot, arg, []parse.Node{n}, missingVal), typ) + case *parse.VariableNode: + return s.validateType(s.evalVariableNode(dot, arg, nil, missingVal), typ) + case *parse.PipeNode: + return s.validateType(s.evalPipeline(dot, arg), typ) + case *parse.IdentifierNode: + return s.validateType(s.evalFunction(dot, arg, arg, nil, missingVal), typ) + case *parse.ChainNode: + return s.validateType(s.evalChainNode(dot, arg, nil, missingVal), typ) + } + switch typ.Kind() { + case reflect.Bool: + return s.evalBool(typ, n) + case reflect.Complex64, reflect.Complex128: + return s.evalComplex(typ, n) + case reflect.Float32, reflect.Float64: + return s.evalFloat(typ, n) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return s.evalInteger(typ, n) + case reflect.Interface: + if typ.NumMethod() == 0 { + return s.evalEmptyInterface(dot, n) + } + case reflect.Struct: + if typ == reflectValueType { + return reflect.ValueOf(s.evalEmptyInterface(dot, n)) + } + case reflect.String: + return s.evalString(typ, n) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return s.evalUnsignedInteger(typ, n) + } + s.errorf("can't handle %s for arg of type %s", n, typ) + panic("not reached") +} + +func (s *state) evalBool(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.BoolNode); ok { + value := reflect.New(typ).Elem() + value.SetBool(n.True) + return value + } + s.errorf("expected bool; found %s", n) + panic("not reached") +} + +func (s *state) evalString(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.StringNode); ok { + value := reflect.New(typ).Elem() + value.SetString(n.Text) + return value + } + s.errorf("expected string; found %s", n) + panic("not reached") +} + +func (s *state) evalInteger(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.NumberNode); ok && n.IsInt { + value := reflect.New(typ).Elem() + value.SetInt(n.Int64) + return value + } + s.errorf("expected integer; found %s", n) + panic("not reached") +} + +func (s *state) evalUnsignedInteger(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.NumberNode); ok && n.IsUint { + value := reflect.New(typ).Elem() + value.SetUint(n.Uint64) + return value + } + s.errorf("expected unsigned integer; found %s", n) + panic("not reached") +} + +func (s *state) evalFloat(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.NumberNode); ok && n.IsFloat { + value := reflect.New(typ).Elem() + value.SetFloat(n.Float64) + return value + } + s.errorf("expected float; found %s", n) + panic("not reached") +} + +func (s *state) evalComplex(typ reflect.Type, n parse.Node) reflect.Value { + if n, ok := n.(*parse.NumberNode); ok && n.IsComplex { + value := reflect.New(typ).Elem() + value.SetComplex(n.Complex128) + return value + } + s.errorf("expected complex; found %s", n) + panic("not reached") +} + +func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Value { + s.at(n) + switch n := n.(type) { + case *parse.BoolNode: + return reflect.ValueOf(n.True) + case *parse.DotNode: + return dot + case *parse.FieldNode: + return s.evalFieldNode(dot, n, nil, missingVal) + case *parse.IdentifierNode: + return s.evalFunction(dot, n, n, nil, missingVal) + case *parse.NilNode: + // NilNode is handled in evalArg, the only place that calls here. + s.errorf("evalEmptyInterface: nil (can't happen)") + case *parse.NumberNode: + return s.idealConstant(n) + case *parse.StringNode: + return reflect.ValueOf(n.Text) + case *parse.VariableNode: + return s.evalVariableNode(dot, n, nil, missingVal) + case *parse.PipeNode: + return s.evalPipeline(dot, n) + } + s.errorf("can't handle assignment of %s to empty interface argument", n) + panic("not reached") +} + +// indirect returns the item at the end of indirection, and a bool to indicate +// if it's nil. If the returned bool is true, the returned value's kind will be +// either a pointer or interface. +func indirect(v reflect.Value) (rv reflect.Value, isNil bool) { + for ; v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface; v = v.Elem() { + if v.IsNil() { + return v, true + } + } + return v, false +} + +// indirectInterface returns the concrete value in an interface value, +// or else the zero reflect.Value. +// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x): +// the fact that x was an interface value is forgotten. +func indirectInterface(v reflect.Value) reflect.Value { + if v.Kind() != reflect.Interface { + return v + } + if v.IsNil() { + return reflect.Value{} + } + return v.Elem() +} + +// printValue writes the textual representation of the value to the output of +// the template. +func (s *state) printValue(n parse.Node, v reflect.Value) { + s.at(n) + iface, ok := printableValue(v) + if !ok { + s.errorf("can't print %s of type %s", n, v.Type()) + } + _, err := fmt.Fprint(s.wr, iface) + if err != nil { + s.writeError(err) + } +} + +// printableValue returns the, possibly indirected, interface value inside v that +// is best for a call to formatted printer. +func printableValue(v reflect.Value) (any, bool) { + if v.Kind() == reflect.Pointer { + v, _ = indirect(v) // fmt.Fprint handles nil. + } + if !v.IsValid() { + return "", true + } + + if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) { + if v.CanAddr() && (reflect.PointerTo(v.Type()).Implements(errorType) || reflect.PointerTo(v.Type()).Implements(fmtStringerType)) { + v = v.Addr() + } else { + switch v.Kind() { + case reflect.Chan, reflect.Func: + return nil, false + } + } + } + return v.Interface(), true +} diff --git a/contrib/go/_std_1.22/src/text/template/funcs.go b/contrib/go/_std_1.23/src/text/template/funcs.go similarity index 93% rename from contrib/go/_std_1.22/src/text/template/funcs.go rename to contrib/go/_std_1.23/src/text/template/funcs.go index a949f896fa3d..7d63cf8b7bb6 100644 --- a/contrib/go/_std_1.22/src/text/template/funcs.go +++ b/contrib/go/_std_1.23/src/text/template/funcs.go @@ -22,14 +22,14 @@ import ( // return value evaluates to non-nil during execution, execution terminates and // Execute returns that error. // -// Errors returned by Execute wrap the underlying error; call errors.As to +// Errors returned by Execute wrap the underlying error; call [errors.As] to // unwrap them. // // When template execution invokes a function with an argument list, that list // must be assignable to the function's parameter types. Functions meant to // apply to arguments of arbitrary type can use parameters of type interface{} or -// of type reflect.Value. Similarly, functions meant to return a result of arbitrary -// type can return interface{} or reflect.Value. +// of type [reflect.Value]. Similarly, functions meant to return a result of arbitrary +// type can return interface{} or [reflect.Value]. type FuncMap map[string]any // builtins returns the FuncMap. @@ -39,7 +39,7 @@ type FuncMap map[string]any func builtins() FuncMap { return FuncMap{ "and": and, - "call": call, + "call": emptyCall, "html": HTMLEscaper, "index": index, "slice": slice, @@ -93,8 +93,8 @@ func addValueFuncs(out map[string]reflect.Value, in FuncMap) { if v.Kind() != reflect.Func { panic("value for " + name + " not a function") } - if !goodFunc(v.Type()) { - panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut())) + if err := goodFunc(name, v.Type()); err != nil { + panic(err) } out[name] = v } @@ -109,15 +109,18 @@ func addFuncs(out, in FuncMap) { } // goodFunc reports whether the function or method has the right result signature. -func goodFunc(typ reflect.Type) bool { +func goodFunc(name string, typ reflect.Type) error { // We allow functions with 1 result or 2 results where the second is an error. - switch { - case typ.NumOut() == 1: - return true - case typ.NumOut() == 2 && typ.Out(1) == errorType: - return true + switch numOut := typ.NumOut(); { + case numOut == 1: + return nil + case numOut == 2 && typ.Out(1) == errorType: + return nil + case numOut == 2: + return fmt.Errorf("invalid function signature for %s: second return value should be error; is %s", name, typ.Out(1)) + default: + return fmt.Errorf("function %s has %d return values; should be 1 or 2", name, typ.NumOut()) } - return false } // goodName reports whether the function name is a valid identifier. @@ -309,30 +312,35 @@ func length(item reflect.Value) (int, error) { // Function invocation +func emptyCall(fn reflect.Value, args ...reflect.Value) reflect.Value { + panic("unreachable") // implemented as a special case in evalCall +} + // call returns the result of evaluating the first argument as a function. // The function must return 1 result, or 2 results, the second of which is an error. -func call(fn reflect.Value, args ...reflect.Value) (reflect.Value, error) { +func call(name string, fn reflect.Value, args ...reflect.Value) (reflect.Value, error) { fn = indirectInterface(fn) if !fn.IsValid() { return reflect.Value{}, fmt.Errorf("call of nil") } typ := fn.Type() if typ.Kind() != reflect.Func { - return reflect.Value{}, fmt.Errorf("non-function of type %s", typ) + return reflect.Value{}, fmt.Errorf("non-function %s of type %s", name, typ) } - if !goodFunc(typ) { - return reflect.Value{}, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut()) + + if err := goodFunc(name, typ); err != nil { + return reflect.Value{}, err } numIn := typ.NumIn() var dddType reflect.Type if typ.IsVariadic() { if len(args) < numIn-1 { - return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1) + return reflect.Value{}, fmt.Errorf("wrong number of args for %s: got %d want at least %d", name, len(args), numIn-1) } dddType = typ.In(numIn - 1).Elem() } else { if len(args) != numIn { - return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn) + return reflect.Value{}, fmt.Errorf("wrong number of args for %s: got %d want %d", name, len(args), numIn) } } argv := make([]reflect.Value, len(args)) diff --git a/contrib/go/_std_1.22/src/text/template/helper.go b/contrib/go/_std_1.23/src/text/template/helper.go similarity index 80% rename from contrib/go/_std_1.22/src/text/template/helper.go rename to contrib/go/_std_1.23/src/text/template/helper.go index 48af3928b39d..81b55538e57c 100644 --- a/contrib/go/_std_1.22/src/text/template/helper.go +++ b/contrib/go/_std_1.23/src/text/template/helper.go @@ -16,7 +16,7 @@ import ( // Functions and methods to parse templates. -// Must is a helper that wraps a call to a function returning (*Template, error) +// Must is a helper that wraps a call to a function returning ([*Template], error) // and panics if the error is non-nil. It is intended for use in variable // initializations such as // @@ -28,7 +28,7 @@ func Must(t *Template, err error) *Template { return t } -// ParseFiles creates a new Template and parses the template definitions from +// ParseFiles creates a new [Template] and parses the template definitions from // the named files. The returned template's name will have the base name and // parsed contents of the first file. There must be at least one file. // If an error occurs, parsing stops and the returned *Template is nil. @@ -45,9 +45,9 @@ func ParseFiles(filenames ...string) (*Template, error) { // t. If an error occurs, parsing stops and the returned template is nil; // otherwise it is t. There must be at least one file. // Since the templates created by ParseFiles are named by the base -// names of the argument files, t should usually have the name of one -// of the (base) names of the files. If it does not, depending on t's -// contents before calling ParseFiles, t.Execute may fail. In that +// (see [filepath.Base]) names of the argument files, t should usually have the +// name of one of the (base) names of the files. If it does not, depending on +// t's contents before calling ParseFiles, t.Execute may fail. In that // case use t.ExecuteTemplate to execute a valid template. // // When parsing multiple files with the same name in different directories, @@ -93,12 +93,12 @@ func parseFiles(t *Template, readFile func(string) (string, []byte, error), file return t, nil } -// ParseGlob creates a new Template and parses the template definitions from +// ParseGlob creates a new [Template] and parses the template definitions from // the files identified by the pattern. The files are matched according to the -// semantics of filepath.Match, and the pattern must match at least one file. -// The returned template will have the (base) name and (parsed) contents of the -// first file matched by the pattern. ParseGlob is equivalent to calling -// ParseFiles with the list of files matched by the pattern. +// semantics of [filepath.Match], and the pattern must match at least one file. +// The returned template will have the [filepath.Base] name and (parsed) +// contents of the first file matched by the pattern. ParseGlob is equivalent to +// calling [ParseFiles] with the list of files matched by the pattern. // // When parsing multiple files with the same name in different directories, // the last one mentioned will be the one that results. @@ -108,9 +108,9 @@ func ParseGlob(pattern string) (*Template, error) { // ParseGlob parses the template definitions in the files identified by the // pattern and associates the resulting templates with t. The files are matched -// according to the semantics of filepath.Match, and the pattern must match at -// least one file. ParseGlob is equivalent to calling t.ParseFiles with the -// list of files matched by the pattern. +// according to the semantics of [filepath.Match], and the pattern must match at +// least one file. ParseGlob is equivalent to calling [Template.ParseFiles] with +// the list of files matched by the pattern. // // When parsing multiple files with the same name in different directories, // the last one mentioned will be the one that results. @@ -131,17 +131,17 @@ func parseGlob(t *Template, pattern string) (*Template, error) { return parseFiles(t, readFileOS, filenames...) } -// ParseFS is like ParseFiles or ParseGlob but reads from the file system fsys +// ParseFS is like [Template.ParseFiles] or [Template.ParseGlob] but reads from the file system fsys // instead of the host operating system's file system. -// It accepts a list of glob patterns. +// It accepts a list of glob patterns (see [path.Match]). // (Note that most file names serve as glob patterns matching only themselves.) func ParseFS(fsys fs.FS, patterns ...string) (*Template, error) { return parseFS(nil, fsys, patterns) } -// ParseFS is like ParseFiles or ParseGlob but reads from the file system fsys +// ParseFS is like [Template.ParseFiles] or [Template.ParseGlob] but reads from the file system fsys // instead of the host operating system's file system. -// It accepts a list of glob patterns. +// It accepts a list of glob patterns (see [path.Match]). // (Note that most file names serve as glob patterns matching only themselves.) func (t *Template) ParseFS(fsys fs.FS, patterns ...string) (*Template, error) { t.init() diff --git a/contrib/go/_std_1.22/src/text/template/option.go b/contrib/go/_std_1.23/src/text/template/option.go similarity index 100% rename from contrib/go/_std_1.22/src/text/template/option.go rename to contrib/go/_std_1.23/src/text/template/option.go diff --git a/contrib/go/_std_1.22/src/text/template/parse/lex.go b/contrib/go/_std_1.23/src/text/template/parse/lex.go similarity index 100% rename from contrib/go/_std_1.22/src/text/template/parse/lex.go rename to contrib/go/_std_1.23/src/text/template/parse/lex.go diff --git a/contrib/go/_std_1.22/src/text/template/parse/node.go b/contrib/go/_std_1.23/src/text/template/parse/node.go similarity index 98% rename from contrib/go/_std_1.22/src/text/template/parse/node.go rename to contrib/go/_std_1.23/src/text/template/parse/node.go index c36688825c20..a31309874d9d 100644 --- a/contrib/go/_std_1.22/src/text/template/parse/node.go +++ b/contrib/go/_std_1.23/src/text/template/parse/node.go @@ -217,7 +217,11 @@ func (p *PipeNode) writeTo(sb *strings.Builder) { } v.writeTo(sb) } - sb.WriteString(" := ") + if p.IsAssign { + sb.WriteString(" = ") + } else { + sb.WriteString(" := ") + } } for i, c := range p.Cmds { if i > 0 { @@ -346,12 +350,12 @@ type IdentifierNode struct { Ident string // The identifier's name. } -// NewIdentifier returns a new IdentifierNode with the given identifier name. +// NewIdentifier returns a new [IdentifierNode] with the given identifier name. func NewIdentifier(ident string) *IdentifierNode { return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident} } -// SetPos sets the position. NewIdentifier is a public method so we can't modify its signature. +// SetPos sets the position. [NewIdentifier] is a public method so we can't modify its signature. // Chained for convenience. // TODO: fix one day? func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode { @@ -359,7 +363,7 @@ func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode { return i } -// SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature. +// SetTree sets the parent tree for the node. [NewIdentifier] is a public method so we can't modify its signature. // Chained for convenience. // TODO: fix one day? func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode { diff --git a/contrib/go/_std_1.23/src/text/template/parse/parse.go b/contrib/go/_std_1.23/src/text/template/parse/parse.go new file mode 100644 index 000000000000..27c84f31eb3a --- /dev/null +++ b/contrib/go/_std_1.23/src/text/template/parse/parse.go @@ -0,0 +1,831 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package parse builds parse trees for templates as defined by text/template +// and html/template. Clients should use those packages to construct templates +// rather than this one, which provides shared internal data structures not +// intended for general use. +package parse + +import ( + "bytes" + "fmt" + "runtime" + "strconv" + "strings" +) + +// Tree is the representation of a single parsed template. +type Tree struct { + Name string // name of the template represented by the tree. + ParseName string // name of the top-level template during parsing, for error messages. + Root *ListNode // top-level root of the tree. + Mode Mode // parsing mode. + text string // text parsed to create the template (or its parent) + // Parsing only; cleared after parse. + funcs []map[string]any + lex *lexer + token [3]item // three-token lookahead for parser. + peekCount int + vars []string // variables defined at the moment. + treeSet map[string]*Tree + actionLine int // line of left delim starting action + rangeDepth int +} + +// A mode value is a set of flags (or 0). Modes control parser behavior. +type Mode uint + +const ( + ParseComments Mode = 1 << iota // parse comments and add them to AST + SkipFuncCheck // do not check that functions are defined +) + +// Copy returns a copy of the [Tree]. Any parsing state is discarded. +func (t *Tree) Copy() *Tree { + if t == nil { + return nil + } + return &Tree{ + Name: t.Name, + ParseName: t.ParseName, + Root: t.Root.CopyList(), + text: t.text, + } +} + +// Parse returns a map from template name to [Tree], created by parsing the +// templates described in the argument string. The top-level template will be +// given the specified name. If an error is encountered, parsing stops and an +// empty map is returned with the error. +func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]any) (map[string]*Tree, error) { + treeSet := make(map[string]*Tree) + t := New(name) + t.text = text + _, err := t.Parse(text, leftDelim, rightDelim, treeSet, funcs...) + return treeSet, err +} + +// next returns the next token. +func (t *Tree) next() item { + if t.peekCount > 0 { + t.peekCount-- + } else { + t.token[0] = t.lex.nextItem() + } + return t.token[t.peekCount] +} + +// backup backs the input stream up one token. +func (t *Tree) backup() { + t.peekCount++ +} + +// backup2 backs the input stream up two tokens. +// The zeroth token is already there. +func (t *Tree) backup2(t1 item) { + t.token[1] = t1 + t.peekCount = 2 +} + +// backup3 backs the input stream up three tokens +// The zeroth token is already there. +func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back. + t.token[1] = t1 + t.token[2] = t2 + t.peekCount = 3 +} + +// peek returns but does not consume the next token. +func (t *Tree) peek() item { + if t.peekCount > 0 { + return t.token[t.peekCount-1] + } + t.peekCount = 1 + t.token[0] = t.lex.nextItem() + return t.token[0] +} + +// nextNonSpace returns the next non-space token. +func (t *Tree) nextNonSpace() (token item) { + for { + token = t.next() + if token.typ != itemSpace { + break + } + } + return token +} + +// peekNonSpace returns but does not consume the next non-space token. +func (t *Tree) peekNonSpace() item { + token := t.nextNonSpace() + t.backup() + return token +} + +// Parsing. + +// New allocates a new parse tree with the given name. +func New(name string, funcs ...map[string]any) *Tree { + return &Tree{ + Name: name, + funcs: funcs, + } +} + +// ErrorContext returns a textual representation of the location of the node in the input text. +// The receiver is only used when the node does not have a pointer to the tree inside, +// which can occur in old code. +func (t *Tree) ErrorContext(n Node) (location, context string) { + pos := int(n.Position()) + tree := n.tree() + if tree == nil { + tree = t + } + text := tree.text[:pos] + byteNum := strings.LastIndex(text, "\n") + if byteNum == -1 { + byteNum = pos // On first line. + } else { + byteNum++ // After the newline. + byteNum = pos - byteNum + } + lineNum := 1 + strings.Count(text, "\n") + context = n.String() + return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context +} + +// errorf formats the error and terminates processing. +func (t *Tree) errorf(format string, args ...any) { + t.Root = nil + format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format) + panic(fmt.Errorf(format, args...)) +} + +// error terminates processing. +func (t *Tree) error(err error) { + t.errorf("%s", err) +} + +// expect consumes the next token and guarantees it has the required type. +func (t *Tree) expect(expected itemType, context string) item { + token := t.nextNonSpace() + if token.typ != expected { + t.unexpected(token, context) + } + return token +} + +// expectOneOf consumes the next token and guarantees it has one of the required types. +func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item { + token := t.nextNonSpace() + if token.typ != expected1 && token.typ != expected2 { + t.unexpected(token, context) + } + return token +} + +// unexpected complains about the token and terminates processing. +func (t *Tree) unexpected(token item, context string) { + if token.typ == itemError { + extra := "" + if t.actionLine != 0 && t.actionLine != token.line { + extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine) + if strings.HasSuffix(token.val, " action") { + extra = extra[len(" in action"):] // avoid "action in action" + } + } + t.errorf("%s%s", token, extra) + } + t.errorf("unexpected %s in %s", token, context) +} + +// recover is the handler that turns panics into returns from the top level of Parse. +func (t *Tree) recover(errp *error) { + e := recover() + if e != nil { + if _, ok := e.(runtime.Error); ok { + panic(e) + } + if t != nil { + t.stopParse() + } + *errp = e.(error) + } +} + +// startParse initializes the parser, using the lexer. +func (t *Tree) startParse(funcs []map[string]any, lex *lexer, treeSet map[string]*Tree) { + t.Root = nil + t.lex = lex + t.vars = []string{"$"} + t.funcs = funcs + t.treeSet = treeSet + lex.options = lexOptions{ + emitComment: t.Mode&ParseComments != 0, + breakOK: !t.hasFunction("break"), + continueOK: !t.hasFunction("continue"), + } +} + +// stopParse terminates parsing. +func (t *Tree) stopParse() { + t.lex = nil + t.vars = nil + t.funcs = nil + t.treeSet = nil +} + +// Parse parses the template definition string to construct a representation of +// the template for execution. If either action delimiter string is empty, the +// default ("{{" or "}}") is used. Embedded template definitions are added to +// the treeSet map. +func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]any) (tree *Tree, err error) { + defer t.recover(&err) + t.ParseName = t.Name + lexer := lex(t.Name, text, leftDelim, rightDelim) + t.startParse(funcs, lexer, treeSet) + t.text = text + t.parse() + t.add() + t.stopParse() + return t, nil +} + +// add adds tree to t.treeSet. +func (t *Tree) add() { + tree := t.treeSet[t.Name] + if tree == nil || IsEmptyTree(tree.Root) { + t.treeSet[t.Name] = t + return + } + if !IsEmptyTree(t.Root) { + t.errorf("template: multiple definition of template %q", t.Name) + } +} + +// IsEmptyTree reports whether this tree (node) is empty of everything but space or comments. +func IsEmptyTree(n Node) bool { + switch n := n.(type) { + case nil: + return true + case *ActionNode: + case *CommentNode: + return true + case *IfNode: + case *ListNode: + for _, node := range n.Nodes { + if !IsEmptyTree(node) { + return false + } + } + return true + case *RangeNode: + case *TemplateNode: + case *TextNode: + return len(bytes.TrimSpace(n.Text)) == 0 + case *WithNode: + default: + panic("unknown node: " + n.String()) + } + return false +} + +// parse is the top-level parser for a template, essentially the same +// as itemList except it also parses {{define}} actions. +// It runs to EOF. +func (t *Tree) parse() { + t.Root = t.newList(t.peek().pos) + for t.peek().typ != itemEOF { + if t.peek().typ == itemLeftDelim { + delim := t.next() + if t.nextNonSpace().typ == itemDefine { + newT := New("definition") // name will be updated once we know it. + newT.text = t.text + newT.Mode = t.Mode + newT.ParseName = t.ParseName + newT.startParse(t.funcs, t.lex, t.treeSet) + newT.parseDefinition() + continue + } + t.backup2(delim) + } + switch n := t.textOrAction(); n.Type() { + case nodeEnd, nodeElse: + t.errorf("unexpected %s", n) + default: + t.Root.append(n) + } + } +} + +// parseDefinition parses a {{define}} ... {{end}} template definition and +// installs the definition in t.treeSet. The "define" keyword has already +// been scanned. +func (t *Tree) parseDefinition() { + const context = "define clause" + name := t.expectOneOf(itemString, itemRawString, context) + var err error + t.Name, err = strconv.Unquote(name.val) + if err != nil { + t.error(err) + } + t.expect(itemRightDelim, context) + var end Node + t.Root, end = t.itemList() + if end.Type() != nodeEnd { + t.errorf("unexpected %s in %s", end, context) + } + t.add() + t.stopParse() +} + +// itemList: +// +// textOrAction* +// +// Terminates at {{end}} or {{else}}, returned separately. +func (t *Tree) itemList() (list *ListNode, next Node) { + list = t.newList(t.peekNonSpace().pos) + for t.peekNonSpace().typ != itemEOF { + n := t.textOrAction() + switch n.Type() { + case nodeEnd, nodeElse: + return list, n + } + list.append(n) + } + t.errorf("unexpected EOF") + return +} + +// textOrAction: +// +// text | comment | action +func (t *Tree) textOrAction() Node { + switch token := t.nextNonSpace(); token.typ { + case itemText: + return t.newText(token.pos, token.val) + case itemLeftDelim: + t.actionLine = token.line + defer t.clearActionLine() + return t.action() + case itemComment: + return t.newComment(token.pos, token.val) + default: + t.unexpected(token, "input") + } + return nil +} + +func (t *Tree) clearActionLine() { + t.actionLine = 0 +} + +// Action: +// +// control +// command ("|" command)* +// +// Left delim is past. Now get actions. +// First word could be a keyword such as range. +func (t *Tree) action() (n Node) { + switch token := t.nextNonSpace(); token.typ { + case itemBlock: + return t.blockControl() + case itemBreak: + return t.breakControl(token.pos, token.line) + case itemContinue: + return t.continueControl(token.pos, token.line) + case itemElse: + return t.elseControl() + case itemEnd: + return t.endControl() + case itemIf: + return t.ifControl() + case itemRange: + return t.rangeControl() + case itemTemplate: + return t.templateControl() + case itemWith: + return t.withControl() + } + t.backup() + token := t.peek() + // Do not pop variables; they persist until "end". + return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim)) +} + +// Break: +// +// {{break}} +// +// Break keyword is past. +func (t *Tree) breakControl(pos Pos, line int) Node { + if token := t.nextNonSpace(); token.typ != itemRightDelim { + t.unexpected(token, "{{break}}") + } + if t.rangeDepth == 0 { + t.errorf("{{break}} outside {{range}}") + } + return t.newBreak(pos, line) +} + +// Continue: +// +// {{continue}} +// +// Continue keyword is past. +func (t *Tree) continueControl(pos Pos, line int) Node { + if token := t.nextNonSpace(); token.typ != itemRightDelim { + t.unexpected(token, "{{continue}}") + } + if t.rangeDepth == 0 { + t.errorf("{{continue}} outside {{range}}") + } + return t.newContinue(pos, line) +} + +// Pipeline: +// +// declarations? command ('|' command)* +func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) { + token := t.peekNonSpace() + pipe = t.newPipeline(token.pos, token.line, nil) + // Are there declarations or assignments? +decls: + if v := t.peekNonSpace(); v.typ == itemVariable { + t.next() + // Since space is a token, we need 3-token look-ahead here in the worst case: + // in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an + // argument variable rather than a declaration. So remember the token + // adjacent to the variable so we can push it back if necessary. + tokenAfterVariable := t.peek() + next := t.peekNonSpace() + switch { + case next.typ == itemAssign, next.typ == itemDeclare: + pipe.IsAssign = next.typ == itemAssign + t.nextNonSpace() + pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val)) + t.vars = append(t.vars, v.val) + case next.typ == itemChar && next.val == ",": + t.nextNonSpace() + pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val)) + t.vars = append(t.vars, v.val) + if context == "range" && len(pipe.Decl) < 2 { + switch t.peekNonSpace().typ { + case itemVariable, itemRightDelim, itemRightParen: + // second initialized variable in a range pipeline + goto decls + default: + t.errorf("range can only initialize variables") + } + } + t.errorf("too many declarations in %s", context) + case tokenAfterVariable.typ == itemSpace: + t.backup3(v, tokenAfterVariable) + default: + t.backup2(v) + } + } + for { + switch token := t.nextNonSpace(); token.typ { + case end: + // At this point, the pipeline is complete + t.checkPipeline(pipe, context) + return + case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, + itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: + t.backup() + pipe.append(t.command()) + default: + t.unexpected(token, context) + } + } +} + +func (t *Tree) checkPipeline(pipe *PipeNode, context string) { + // Reject empty pipelines + if len(pipe.Cmds) == 0 { + t.errorf("missing value for %s", context) + } + // Only the first command of a pipeline can start with a non executable operand + for i, c := range pipe.Cmds[1:] { + switch c.Args[0].Type() { + case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString: + // With A|B|C, pipeline stage 2 is B + t.errorf("non executable command in pipeline stage %d", i+2) + } + } +} + +func (t *Tree) parseControl(context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { + defer t.popVars(len(t.vars)) + pipe = t.pipeline(context, itemRightDelim) + if context == "range" { + t.rangeDepth++ + } + var next Node + list, next = t.itemList() + if context == "range" { + t.rangeDepth-- + } + switch next.Type() { + case nodeEnd: //done + case nodeElse: + // Special case for "else if" and "else with". + // If the "else" is followed immediately by an "if" or "with", + // the elseControl will have left the "if" or "with" token pending. Treat + // {{if a}}_{{else if b}}_{{end}} + // {{with a}}_{{else with b}}_{{end}} + // as + // {{if a}}_{{else}}{{if b}}_{{end}}{{end}} + // {{with a}}_{{else}}{{with b}}_{{end}}{{end}}. + // To do this, parse the "if" or "with" as usual and stop at it {{end}}; + // the subsequent{{end}} is assumed. This technique works even for long if-else-if chains. + if context == "if" && t.peek().typ == itemIf { + t.next() // Consume the "if" token. + elseList = t.newList(next.Position()) + elseList.append(t.ifControl()) + } else if context == "with" && t.peek().typ == itemWith { + t.next() + elseList = t.newList(next.Position()) + elseList.append(t.withControl()) + } else { + elseList, next = t.itemList() + if next.Type() != nodeEnd { + t.errorf("expected end; found %s", next) + } + } + } + return pipe.Position(), pipe.Line, pipe, list, elseList +} + +// If: +// +// {{if pipeline}} itemList {{end}} +// {{if pipeline}} itemList {{else}} itemList {{end}} +// +// If keyword is past. +func (t *Tree) ifControl() Node { + return t.newIf(t.parseControl("if")) +} + +// Range: +// +// {{range pipeline}} itemList {{end}} +// {{range pipeline}} itemList {{else}} itemList {{end}} +// +// Range keyword is past. +func (t *Tree) rangeControl() Node { + r := t.newRange(t.parseControl("range")) + return r +} + +// With: +// +// {{with pipeline}} itemList {{end}} +// {{with pipeline}} itemList {{else}} itemList {{end}} +// +// If keyword is past. +func (t *Tree) withControl() Node { + return t.newWith(t.parseControl("with")) +} + +// End: +// +// {{end}} +// +// End keyword is past. +func (t *Tree) endControl() Node { + return t.newEnd(t.expect(itemRightDelim, "end").pos) +} + +// Else: +// +// {{else}} +// +// Else keyword is past. +func (t *Tree) elseControl() Node { + peek := t.peekNonSpace() + // The "{{else if ... " and "{{else with ..." will be + // treated as "{{else}}{{if ..." and "{{else}}{{with ...". + // So return the else node here. + if peek.typ == itemIf || peek.typ == itemWith { + return t.newElse(peek.pos, peek.line) + } + token := t.expect(itemRightDelim, "else") + return t.newElse(token.pos, token.line) +} + +// Block: +// +// {{block stringValue pipeline}} +// +// Block keyword is past. +// The name must be something that can evaluate to a string. +// The pipeline is mandatory. +func (t *Tree) blockControl() Node { + const context = "block clause" + + token := t.nextNonSpace() + name := t.parseTemplateName(token, context) + pipe := t.pipeline(context, itemRightDelim) + + block := New(name) // name will be updated once we know it. + block.text = t.text + block.Mode = t.Mode + block.ParseName = t.ParseName + block.startParse(t.funcs, t.lex, t.treeSet) + var end Node + block.Root, end = block.itemList() + if end.Type() != nodeEnd { + t.errorf("unexpected %s in %s", end, context) + } + block.add() + block.stopParse() + + return t.newTemplate(token.pos, token.line, name, pipe) +} + +// Template: +// +// {{template stringValue pipeline}} +// +// Template keyword is past. The name must be something that can evaluate +// to a string. +func (t *Tree) templateControl() Node { + const context = "template clause" + token := t.nextNonSpace() + name := t.parseTemplateName(token, context) + var pipe *PipeNode + if t.nextNonSpace().typ != itemRightDelim { + t.backup() + // Do not pop variables; they persist until "end". + pipe = t.pipeline(context, itemRightDelim) + } + return t.newTemplate(token.pos, token.line, name, pipe) +} + +func (t *Tree) parseTemplateName(token item, context string) (name string) { + switch token.typ { + case itemString, itemRawString: + s, err := strconv.Unquote(token.val) + if err != nil { + t.error(err) + } + name = s + default: + t.unexpected(token, context) + } + return +} + +// command: +// +// operand (space operand)* +// +// space-separated arguments up to a pipeline character or right delimiter. +// we consume the pipe character but leave the right delim to terminate the action. +func (t *Tree) command() *CommandNode { + cmd := t.newCommand(t.peekNonSpace().pos) + for { + t.peekNonSpace() // skip leading spaces. + operand := t.operand() + if operand != nil { + cmd.append(operand) + } + switch token := t.next(); token.typ { + case itemSpace: + continue + case itemRightDelim, itemRightParen: + t.backup() + case itemPipe: + // nothing here; break loop below + default: + t.unexpected(token, "operand") + } + break + } + if len(cmd.Args) == 0 { + t.errorf("empty command") + } + return cmd +} + +// operand: +// +// term .Field* +// +// An operand is a space-separated component of a command, +// a term possibly followed by field accesses. +// A nil return means the next item is not an operand. +func (t *Tree) operand() Node { + node := t.term() + if node == nil { + return nil + } + if t.peek().typ == itemField { + chain := t.newChain(t.peek().pos, node) + for t.peek().typ == itemField { + chain.Add(t.next().val) + } + // Compatibility with original API: If the term is of type NodeField + // or NodeVariable, just put more fields on the original. + // Otherwise, keep the Chain node. + // Obvious parsing errors involving literal values are detected here. + // More complex error cases will have to be handled at execution time. + switch node.Type() { + case NodeField: + node = t.newField(chain.Position(), chain.String()) + case NodeVariable: + node = t.newVariable(chain.Position(), chain.String()) + case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot: + t.errorf("unexpected . after term %q", node.String()) + default: + node = chain + } + } + return node +} + +// term: +// +// literal (number, string, nil, boolean) +// function (identifier) +// . +// .Field +// $ +// '(' pipeline ')' +// +// A term is a simple "expression". +// A nil return means the next item is not a term. +func (t *Tree) term() Node { + switch token := t.nextNonSpace(); token.typ { + case itemIdentifier: + checkFunc := t.Mode&SkipFuncCheck == 0 + if checkFunc && !t.hasFunction(token.val) { + t.errorf("function %q not defined", token.val) + } + return NewIdentifier(token.val).SetTree(t).SetPos(token.pos) + case itemDot: + return t.newDot(token.pos) + case itemNil: + return t.newNil(token.pos) + case itemVariable: + return t.useVar(token.pos, token.val) + case itemField: + return t.newField(token.pos, token.val) + case itemBool: + return t.newBool(token.pos, token.val == "true") + case itemCharConstant, itemComplex, itemNumber: + number, err := t.newNumber(token.pos, token.val, token.typ) + if err != nil { + t.error(err) + } + return number + case itemLeftParen: + return t.pipeline("parenthesized pipeline", itemRightParen) + case itemString, itemRawString: + s, err := strconv.Unquote(token.val) + if err != nil { + t.error(err) + } + return t.newString(token.pos, token.val, s) + } + t.backup() + return nil +} + +// hasFunction reports if a function name exists in the Tree's maps. +func (t *Tree) hasFunction(name string) bool { + for _, funcMap := range t.funcs { + if funcMap == nil { + continue + } + if funcMap[name] != nil { + return true + } + } + return false +} + +// popVars trims the variable list to the specified length +func (t *Tree) popVars(n int) { + t.vars = t.vars[:n] +} + +// useVar returns a node for a variable reference. It errors if the +// variable is not defined. +func (t *Tree) useVar(pos Pos, name string) Node { + v := t.newVariable(pos, name) + for _, varName := range t.vars { + if varName == v.Ident[0] { + return v + } + } + t.errorf("undefined variable %q", v.Ident[0]) + return nil +} diff --git a/contrib/go/_std_1.22/src/text/template/parse/ya.make b/contrib/go/_std_1.23/src/text/template/parse/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/text/template/parse/ya.make rename to contrib/go/_std_1.23/src/text/template/parse/ya.make diff --git a/contrib/go/_std_1.23/src/text/template/template.go b/contrib/go/_std_1.23/src/text/template/template.go new file mode 100644 index 000000000000..86fd3f122a12 --- /dev/null +++ b/contrib/go/_std_1.23/src/text/template/template.go @@ -0,0 +1,238 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package template + +import ( + "reflect" + "sync" + "text/template/parse" +) + +// common holds the information shared by related templates. +type common struct { + tmpl map[string]*Template // Map from name to defined templates. + muTmpl sync.RWMutex // protects tmpl + option option + // We use two maps, one for parsing and one for execution. + // This separation makes the API cleaner since it doesn't + // expose reflection to the client. + muFuncs sync.RWMutex // protects parseFuncs and execFuncs + parseFuncs FuncMap + execFuncs map[string]reflect.Value +} + +// Template is the representation of a parsed template. The *parse.Tree +// field is exported only for use by [html/template] and should be treated +// as unexported by all other clients. +type Template struct { + name string + *parse.Tree + *common + leftDelim string + rightDelim string +} + +// New allocates a new, undefined template with the given name. +func New(name string) *Template { + t := &Template{ + name: name, + } + t.init() + return t +} + +// Name returns the name of the template. +func (t *Template) Name() string { + return t.name +} + +// New allocates a new, undefined template associated with the given one and with the same +// delimiters. The association, which is transitive, allows one template to +// invoke another with a {{template}} action. +// +// Because associated templates share underlying data, template construction +// cannot be done safely in parallel. Once the templates are constructed, they +// can be executed in parallel. +func (t *Template) New(name string) *Template { + t.init() + nt := &Template{ + name: name, + common: t.common, + leftDelim: t.leftDelim, + rightDelim: t.rightDelim, + } + return nt +} + +// init guarantees that t has a valid common structure. +func (t *Template) init() { + if t.common == nil { + c := new(common) + c.tmpl = make(map[string]*Template) + c.parseFuncs = make(FuncMap) + c.execFuncs = make(map[string]reflect.Value) + t.common = c + } +} + +// Clone returns a duplicate of the template, including all associated +// templates. The actual representation is not copied, but the name space of +// associated templates is, so further calls to [Template.Parse] in the copy will add +// templates to the copy but not to the original. Clone can be used to prepare +// common templates and use them with variant definitions for other templates +// by adding the variants after the clone is made. +func (t *Template) Clone() (*Template, error) { + nt := t.copy(nil) + nt.init() + if t.common == nil { + return nt, nil + } + t.muTmpl.RLock() + defer t.muTmpl.RUnlock() + for k, v := range t.tmpl { + if k == t.name { + nt.tmpl[t.name] = nt + continue + } + // The associated templates share nt's common structure. + tmpl := v.copy(nt.common) + nt.tmpl[k] = tmpl + } + t.muFuncs.RLock() + defer t.muFuncs.RUnlock() + for k, v := range t.parseFuncs { + nt.parseFuncs[k] = v + } + for k, v := range t.execFuncs { + nt.execFuncs[k] = v + } + return nt, nil +} + +// copy returns a shallow copy of t, with common set to the argument. +func (t *Template) copy(c *common) *Template { + return &Template{ + name: t.name, + Tree: t.Tree, + common: c, + leftDelim: t.leftDelim, + rightDelim: t.rightDelim, + } +} + +// AddParseTree associates the argument parse tree with the template t, giving +// it the specified name. If the template has not been defined, this tree becomes +// its definition. If it has been defined and already has that name, the existing +// definition is replaced; otherwise a new template is created, defined, and returned. +func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { + t.init() + t.muTmpl.Lock() + defer t.muTmpl.Unlock() + nt := t + if name != t.name { + nt = t.New(name) + } + // Even if nt == t, we need to install it in the common.tmpl map. + if t.associate(nt, tree) || nt.Tree == nil { + nt.Tree = tree + } + return nt, nil +} + +// Templates returns a slice of defined templates associated with t. +func (t *Template) Templates() []*Template { + if t.common == nil { + return nil + } + // Return a slice so we don't expose the map. + t.muTmpl.RLock() + defer t.muTmpl.RUnlock() + m := make([]*Template, 0, len(t.tmpl)) + for _, v := range t.tmpl { + m = append(m, v) + } + return m +} + +// Delims sets the action delimiters to the specified strings, to be used in +// subsequent calls to [Template.Parse], [Template.ParseFiles], or [Template.ParseGlob]. Nested template +// definitions will inherit the settings. An empty delimiter stands for the +// corresponding default: {{ or }}. +// The return value is the template, so calls can be chained. +func (t *Template) Delims(left, right string) *Template { + t.init() + t.leftDelim = left + t.rightDelim = right + return t +} + +// Funcs adds the elements of the argument map to the template's function map. +// It must be called before the template is parsed. +// It panics if a value in the map is not a function with appropriate return +// type or if the name cannot be used syntactically as a function in a template. +// It is legal to overwrite elements of the map. The return value is the template, +// so calls can be chained. +func (t *Template) Funcs(funcMap FuncMap) *Template { + t.init() + t.muFuncs.Lock() + defer t.muFuncs.Unlock() + addValueFuncs(t.execFuncs, funcMap) + addFuncs(t.parseFuncs, funcMap) + return t +} + +// Lookup returns the template with the given name that is associated with t. +// It returns nil if there is no such template or the template has no definition. +func (t *Template) Lookup(name string) *Template { + if t.common == nil { + return nil + } + t.muTmpl.RLock() + defer t.muTmpl.RUnlock() + return t.tmpl[name] +} + +// Parse parses text as a template body for t. +// Named template definitions ({{define ...}} or {{block ...}} statements) in text +// define additional templates associated with t and are removed from the +// definition of t itself. +// +// Templates can be redefined in successive calls to Parse. +// A template definition with a body containing only white space and comments +// is considered empty and will not replace an existing template's body. +// This allows using Parse to add new named template definitions without +// overwriting the main template body. +func (t *Template) Parse(text string) (*Template, error) { + t.init() + t.muFuncs.RLock() + trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins()) + t.muFuncs.RUnlock() + if err != nil { + return nil, err + } + // Add the newly parsed trees, including the one for t, into our common structure. + for name, tree := range trees { + if _, err := t.AddParseTree(name, tree); err != nil { + return nil, err + } + } + return t, nil +} + +// associate installs the new template into the group of templates associated +// with t. The two are already known to share the common structure. +// The boolean return value reports whether to store this tree as t.Tree. +func (t *Template) associate(new *Template, tree *parse.Tree) bool { + if new.common != t.common { + panic("internal error: associate not common") + } + if old := t.tmpl[new.name]; old != nil && parse.IsEmptyTree(tree.Root) && old.Tree != nil { + // If a template by that name exists, + // don't replace it with an empty template. + return false + } + t.tmpl[new.name] = new + return true +} diff --git a/contrib/go/_std_1.22/src/text/template/ya.make b/contrib/go/_std_1.23/src/text/template/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/text/template/ya.make rename to contrib/go/_std_1.23/src/text/template/ya.make diff --git a/contrib/go/_std_1.22/src/time/embed.go b/contrib/go/_std_1.23/src/time/embed.go similarity index 100% rename from contrib/go/_std_1.22/src/time/embed.go rename to contrib/go/_std_1.23/src/time/embed.go diff --git a/contrib/go/_std_1.23/src/time/format.go b/contrib/go/_std_1.23/src/time/format.go new file mode 100644 index 000000000000..c9e68b3eb254 --- /dev/null +++ b/contrib/go/_std_1.23/src/time/format.go @@ -0,0 +1,1714 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package time + +import ( + "errors" + "internal/stringslite" + _ "unsafe" // for linkname +) + +// These are predefined layouts for use in [Time.Format] and [time.Parse]. +// The reference time used in these layouts is the specific time stamp: +// +// 01/02 03:04:05PM '06 -0700 +// +// (January 2, 15:04:05, 2006, in time zone seven hours west of GMT). +// That value is recorded as the constant named [Layout], listed below. As a Unix +// time, this is 1136239445. Since MST is GMT-0700, the reference would be +// printed by the Unix date command as: +// +// Mon Jan 2 15:04:05 MST 2006 +// +// It is a regrettable historic error that the date uses the American convention +// of putting the numerical month before the day. +// +// The example for Time.Format demonstrates the working of the layout string +// in detail and is a good reference. +// +// Note that the [RFC822], [RFC850], and [RFC1123] formats should be applied +// only to local times. Applying them to UTC times will use "UTC" as the +// time zone abbreviation, while strictly speaking those RFCs require the +// use of "GMT" in that case. +// When using the [RFC1123] or [RFC1123Z] formats for parsing, note that these +// formats define a leading zero for the day-in-month portion, which is not +// strictly allowed by RFC 1123. This will result in an error when parsing +// date strings that occur in the first 9 days of a given month. +// In general [RFC1123Z] should be used instead of [RFC1123] for servers +// that insist on that format, and [RFC3339] should be preferred for new protocols. +// [RFC3339], [RFC822], [RFC822Z], [RFC1123], and [RFC1123Z] are useful for formatting; +// when used with time.Parse they do not accept all the time formats +// permitted by the RFCs and they do accept time formats not formally defined. +// The [RFC3339Nano] format removes trailing zeros from the seconds field +// and thus may not sort correctly once formatted. +// +// Most programs can use one of the defined constants as the layout passed to +// Format or Parse. The rest of this comment can be ignored unless you are +// creating a custom layout string. +// +// To define your own format, write down what the reference time would look like +// formatted your way; see the values of constants like [ANSIC], [StampMicro] or +// [Kitchen] for examples. The model is to demonstrate what the reference time +// looks like so that the Format and Parse methods can apply the same +// transformation to a general time value. +// +// Here is a summary of the components of a layout string. Each element shows by +// example the formatting of an element of the reference time. Only these values +// are recognized. Text in the layout string that is not recognized as part of +// the reference time is echoed verbatim during Format and expected to appear +// verbatim in the input to Parse. +// +// Year: "2006" "06" +// Month: "Jan" "January" "01" "1" +// Day of the week: "Mon" "Monday" +// Day of the month: "2" "_2" "02" +// Day of the year: "__2" "002" +// Hour: "15" "3" "03" (PM or AM) +// Minute: "4" "04" +// Second: "5" "05" +// AM/PM mark: "PM" +// +// Numeric time zone offsets format as follows: +// +// "-0700" ±hhmm +// "-07:00" ±hh:mm +// "-07" ±hh +// "-070000" ±hhmmss +// "-07:00:00" ±hh:mm:ss +// +// Replacing the sign in the format with a Z triggers +// the ISO 8601 behavior of printing Z instead of an +// offset for the UTC zone. Thus: +// +// "Z0700" Z or ±hhmm +// "Z07:00" Z or ±hh:mm +// "Z07" Z or ±hh +// "Z070000" Z or ±hhmmss +// "Z07:00:00" Z or ±hh:mm:ss +// +// Within the format string, the underscores in "_2" and "__2" represent spaces +// that may be replaced by digits if the following number has multiple digits, +// for compatibility with fixed-width Unix time formats. A leading zero represents +// a zero-padded value. +// +// The formats __2 and 002 are space-padded and zero-padded +// three-character day of year; there is no unpadded day of year format. +// +// A comma or decimal point followed by one or more zeros represents +// a fractional second, printed to the given number of decimal places. +// A comma or decimal point followed by one or more nines represents +// a fractional second, printed to the given number of decimal places, with +// trailing zeros removed. +// For example "15:04:05,000" or "15:04:05.000" formats or parses with +// millisecond precision. +// +// Some valid layouts are invalid time values for time.Parse, due to formats +// such as _ for space padding and Z for zone information. +const ( + Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order. + ANSIC = "Mon Jan _2 15:04:05 2006" + UnixDate = "Mon Jan _2 15:04:05 MST 2006" + RubyDate = "Mon Jan 02 15:04:05 -0700 2006" + RFC822 = "02 Jan 06 15:04 MST" + RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone + RFC850 = "Monday, 02-Jan-06 15:04:05 MST" + RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" + RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone + RFC3339 = "2006-01-02T15:04:05Z07:00" + RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" + Kitchen = "3:04PM" + // Handy time stamps. + Stamp = "Jan _2 15:04:05" + StampMilli = "Jan _2 15:04:05.000" + StampMicro = "Jan _2 15:04:05.000000" + StampNano = "Jan _2 15:04:05.000000000" + DateTime = "2006-01-02 15:04:05" + DateOnly = "2006-01-02" + TimeOnly = "15:04:05" +) + +const ( + _ = iota + stdLongMonth = iota + stdNeedDate // "January" + stdMonth // "Jan" + stdNumMonth // "1" + stdZeroMonth // "01" + stdLongWeekDay // "Monday" + stdWeekDay // "Mon" + stdDay // "2" + stdUnderDay // "_2" + stdZeroDay // "02" + stdUnderYearDay // "__2" + stdZeroYearDay // "002" + stdHour = iota + stdNeedClock // "15" + stdHour12 // "3" + stdZeroHour12 // "03" + stdMinute // "4" + stdZeroMinute // "04" + stdSecond // "5" + stdZeroSecond // "05" + stdLongYear = iota + stdNeedDate // "2006" + stdYear // "06" + stdPM = iota + stdNeedClock // "PM" + stdpm // "pm" + stdTZ = iota // "MST" + stdISO8601TZ // "Z0700" // prints Z for UTC + stdISO8601SecondsTZ // "Z070000" + stdISO8601ShortTZ // "Z07" + stdISO8601ColonTZ // "Z07:00" // prints Z for UTC + stdISO8601ColonSecondsTZ // "Z07:00:00" + stdNumTZ // "-0700" // always numeric + stdNumSecondsTz // "-070000" + stdNumShortTZ // "-07" // always numeric + stdNumColonTZ // "-07:00" // always numeric + stdNumColonSecondsTZ // "-07:00:00" + stdFracSecond0 // ".0", ".00", ... , trailing zeros included + stdFracSecond9 // ".9", ".99", ..., trailing zeros omitted + + stdNeedDate = 1 << 8 // need month, day, year + stdNeedClock = 2 << 8 // need hour, minute, second + stdArgShift = 16 // extra argument in high bits, above low stdArgShift + stdSeparatorShift = 28 // extra argument in high 4 bits for fractional second separators + stdMask = 1<= i+3 && layout[i:i+3] == "Jan" { + if len(layout) >= i+7 && layout[i:i+7] == "January" { + return layout[0:i], stdLongMonth, layout[i+7:] + } + if !startsWithLowerCase(layout[i+3:]) { + return layout[0:i], stdMonth, layout[i+3:] + } + } + + case 'M': // Monday, Mon, MST + if len(layout) >= i+3 { + if layout[i:i+3] == "Mon" { + if len(layout) >= i+6 && layout[i:i+6] == "Monday" { + return layout[0:i], stdLongWeekDay, layout[i+6:] + } + if !startsWithLowerCase(layout[i+3:]) { + return layout[0:i], stdWeekDay, layout[i+3:] + } + } + if layout[i:i+3] == "MST" { + return layout[0:i], stdTZ, layout[i+3:] + } + } + + case '0': // 01, 02, 03, 04, 05, 06, 002 + if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' { + return layout[0:i], std0x[layout[i+1]-'1'], layout[i+2:] + } + if len(layout) >= i+3 && layout[i+1] == '0' && layout[i+2] == '2' { + return layout[0:i], stdZeroYearDay, layout[i+3:] + } + + case '1': // 15, 1 + if len(layout) >= i+2 && layout[i+1] == '5' { + return layout[0:i], stdHour, layout[i+2:] + } + return layout[0:i], stdNumMonth, layout[i+1:] + + case '2': // 2006, 2 + if len(layout) >= i+4 && layout[i:i+4] == "2006" { + return layout[0:i], stdLongYear, layout[i+4:] + } + return layout[0:i], stdDay, layout[i+1:] + + case '_': // _2, _2006, __2 + if len(layout) >= i+2 && layout[i+1] == '2' { + //_2006 is really a literal _, followed by stdLongYear + if len(layout) >= i+5 && layout[i+1:i+5] == "2006" { + return layout[0 : i+1], stdLongYear, layout[i+5:] + } + return layout[0:i], stdUnderDay, layout[i+2:] + } + if len(layout) >= i+3 && layout[i+1] == '_' && layout[i+2] == '2' { + return layout[0:i], stdUnderYearDay, layout[i+3:] + } + + case '3': + return layout[0:i], stdHour12, layout[i+1:] + + case '4': + return layout[0:i], stdMinute, layout[i+1:] + + case '5': + return layout[0:i], stdSecond, layout[i+1:] + + case 'P': // PM + if len(layout) >= i+2 && layout[i+1] == 'M' { + return layout[0:i], stdPM, layout[i+2:] + } + + case 'p': // pm + if len(layout) >= i+2 && layout[i+1] == 'm' { + return layout[0:i], stdpm, layout[i+2:] + } + + case '-': // -070000, -07:00:00, -0700, -07:00, -07 + if len(layout) >= i+7 && layout[i:i+7] == "-070000" { + return layout[0:i], stdNumSecondsTz, layout[i+7:] + } + if len(layout) >= i+9 && layout[i:i+9] == "-07:00:00" { + return layout[0:i], stdNumColonSecondsTZ, layout[i+9:] + } + if len(layout) >= i+5 && layout[i:i+5] == "-0700" { + return layout[0:i], stdNumTZ, layout[i+5:] + } + if len(layout) >= i+6 && layout[i:i+6] == "-07:00" { + return layout[0:i], stdNumColonTZ, layout[i+6:] + } + if len(layout) >= i+3 && layout[i:i+3] == "-07" { + return layout[0:i], stdNumShortTZ, layout[i+3:] + } + + case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00, + if len(layout) >= i+7 && layout[i:i+7] == "Z070000" { + return layout[0:i], stdISO8601SecondsTZ, layout[i+7:] + } + if len(layout) >= i+9 && layout[i:i+9] == "Z07:00:00" { + return layout[0:i], stdISO8601ColonSecondsTZ, layout[i+9:] + } + if len(layout) >= i+5 && layout[i:i+5] == "Z0700" { + return layout[0:i], stdISO8601TZ, layout[i+5:] + } + if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" { + return layout[0:i], stdISO8601ColonTZ, layout[i+6:] + } + if len(layout) >= i+3 && layout[i:i+3] == "Z07" { + return layout[0:i], stdISO8601ShortTZ, layout[i+3:] + } + + case '.', ',': // ,000, or .000, or ,999, or .999 - repeated digits for fractional seconds. + if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') { + ch := layout[i+1] + j := i + 1 + for j < len(layout) && layout[j] == ch { + j++ + } + // String of digits must end here - only fractional second is all digits. + if !isDigit(layout, j) { + code := stdFracSecond0 + if layout[i+1] == '9' { + code = stdFracSecond9 + } + std := stdFracSecond(code, j-(i+1), c) + return layout[0:i], std, layout[j:] + } + } + } + } + return layout, 0, "" +} + +var longDayNames = []string{ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", +} + +var shortDayNames = []string{ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", +} + +var shortMonthNames = []string{ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +} + +var longMonthNames = []string{ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", +} + +// match reports whether s1 and s2 match ignoring case. +// It is assumed s1 and s2 are the same length. +func match(s1, s2 string) bool { + for i := 0; i < len(s1); i++ { + c1 := s1[i] + c2 := s2[i] + if c1 != c2 { + // Switch to lower-case; 'a'-'A' is known to be a single bit. + c1 |= 'a' - 'A' + c2 |= 'a' - 'A' + if c1 != c2 || c1 < 'a' || c1 > 'z' { + return false + } + } + } + return true +} + +func lookup(tab []string, val string) (int, string, error) { + for i, v := range tab { + if len(val) >= len(v) && match(val[0:len(v)], v) { + return i, val[len(v):], nil + } + } + return -1, val, errBad +} + +// appendInt appends the decimal form of x to b and returns the result. +// If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's. +// Duplicates functionality in strconv, but avoids dependency. +func appendInt(b []byte, x int, width int) []byte { + u := uint(x) + if x < 0 { + b = append(b, '-') + u = uint(-x) + } + + // 2-digit and 4-digit fields are the most common in time formats. + utod := func(u uint) byte { return '0' + byte(u) } + switch { + case width == 2 && u < 1e2: + return append(b, utod(u/1e1), utod(u%1e1)) + case width == 4 && u < 1e4: + return append(b, utod(u/1e3), utod(u/1e2%1e1), utod(u/1e1%1e1), utod(u%1e1)) + } + + // Compute the number of decimal digits. + var n int + if u == 0 { + n = 1 + } + for u2 := u; u2 > 0; u2 /= 10 { + n++ + } + + // Add 0-padding. + for pad := width - n; pad > 0; pad-- { + b = append(b, '0') + } + + // Ensure capacity. + if len(b)+n <= cap(b) { + b = b[:len(b)+n] + } else { + b = append(b, make([]byte, n)...) + } + + // Assemble decimal in reverse order. + i := len(b) - 1 + for u >= 10 && i > 0 { + q := u / 10 + b[i] = utod(u - q*10) + u = q + i-- + } + b[i] = utod(u) + return b +} + +// Never printed, just needs to be non-nil for return by atoi. +var errAtoi = errors.New("time: invalid number") + +// Duplicates functionality in strconv, but avoids dependency. +func atoi[bytes []byte | string](s bytes) (x int, err error) { + neg := false + if len(s) > 0 && (s[0] == '-' || s[0] == '+') { + neg = s[0] == '-' + s = s[1:] + } + q, rem, err := leadingInt(s) + x = int(q) + if err != nil || len(rem) > 0 { + return 0, errAtoi + } + if neg { + x = -x + } + return x, nil +} + +// The "std" value passed to appendNano contains two packed fields: the number of +// digits after the decimal and the separator character (period or comma). +// These functions pack and unpack that variable. +func stdFracSecond(code, n, c int) int { + // Use 0xfff to make the failure case even more absurd. + if c == '.' { + return code | ((n & 0xfff) << stdArgShift) + } + return code | ((n & 0xfff) << stdArgShift) | 1<> stdArgShift) & 0xfff +} + +func separator(std int) byte { + if (std >> stdSeparatorShift) == 0 { + return '.' + } + return ',' +} + +// appendNano appends a fractional second, as nanoseconds, to b +// and returns the result. The nanosec must be within [0, 999999999]. +func appendNano(b []byte, nanosec int, std int) []byte { + trim := std&stdMask == stdFracSecond9 + n := digitsLen(std) + if trim && (n == 0 || nanosec == 0) { + return b + } + dot := separator(std) + b = append(b, dot) + b = appendInt(b, nanosec, 9) + if n < 9 { + b = b[:len(b)-9+n] + } + if trim { + for len(b) > 0 && b[len(b)-1] == '0' { + b = b[:len(b)-1] + } + if len(b) > 0 && b[len(b)-1] == dot { + b = b[:len(b)-1] + } + } + return b +} + +// String returns the time formatted using the format string +// +// "2006-01-02 15:04:05.999999999 -0700 MST" +// +// If the time has a monotonic clock reading, the returned string +// includes a final field "m=±", where value is the monotonic +// clock reading formatted as a decimal number of seconds. +// +// The returned string is meant for debugging; for a stable serialized +// representation, use t.MarshalText, t.MarshalBinary, or t.Format +// with an explicit format string. +func (t Time) String() string { + s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST") + + // Format monotonic clock reading as m=±ddd.nnnnnnnnn. + if t.wall&hasMonotonic != 0 { + m2 := uint64(t.ext) + sign := byte('+') + if t.ext < 0 { + sign = '-' + m2 = -m2 + } + m1, m2 := m2/1e9, m2%1e9 + m0, m1 := m1/1e9, m1%1e9 + buf := make([]byte, 0, 24) + buf = append(buf, " m="...) + buf = append(buf, sign) + wid := 0 + if m0 != 0 { + buf = appendInt(buf, int(m0), 0) + wid = 9 + } + buf = appendInt(buf, int(m1), wid) + buf = append(buf, '.') + buf = appendInt(buf, int(m2), 9) + s += string(buf) + } + return s +} + +// GoString implements [fmt.GoStringer] and formats t to be printed in Go source +// code. +func (t Time) GoString() string { + abs := t.abs() + year, month, day, _ := absDate(abs, true) + hour, minute, second := absClock(abs) + + buf := make([]byte, 0, len("time.Date(9999, time.September, 31, 23, 59, 59, 999999999, time.Local)")) + buf = append(buf, "time.Date("...) + buf = appendInt(buf, year, 0) + if January <= month && month <= December { + buf = append(buf, ", time."...) + buf = append(buf, longMonthNames[month-1]...) + } else { + // It's difficult to construct a time.Time with a date outside the + // standard range but we might as well try to handle the case. + buf = appendInt(buf, int(month), 0) + } + buf = append(buf, ", "...) + buf = appendInt(buf, day, 0) + buf = append(buf, ", "...) + buf = appendInt(buf, hour, 0) + buf = append(buf, ", "...) + buf = appendInt(buf, minute, 0) + buf = append(buf, ", "...) + buf = appendInt(buf, second, 0) + buf = append(buf, ", "...) + buf = appendInt(buf, t.Nanosecond(), 0) + buf = append(buf, ", "...) + switch loc := t.Location(); loc { + case UTC, nil: + buf = append(buf, "time.UTC"...) + case Local: + buf = append(buf, "time.Local"...) + default: + // there are several options for how we could display this, none of + // which are great: + // + // - use Location(loc.name), which is not technically valid syntax + // - use LoadLocation(loc.name), which will cause a syntax error when + // embedded and also would require us to escape the string without + // importing fmt or strconv + // - try to use FixedZone, which would also require escaping the name + // and would represent e.g. "America/Los_Angeles" daylight saving time + // shifts inaccurately + // - use the pointer format, which is no worse than you'd get with the + // old fmt.Sprintf("%#v", t) format. + // + // Of these, Location(loc.name) is the least disruptive. This is an edge + // case we hope not to hit too often. + buf = append(buf, `time.Location(`...) + buf = append(buf, quote(loc.name)...) + buf = append(buf, ')') + } + buf = append(buf, ')') + return string(buf) +} + +// Format returns a textual representation of the time value formatted according +// to the layout defined by the argument. See the documentation for the +// constant called [Layout] to see how to represent the layout format. +// +// The executable example for [Time.Format] demonstrates the working +// of the layout string in detail and is a good reference. +func (t Time) Format(layout string) string { + const bufSize = 64 + var b []byte + max := len(layout) + 10 + if max < bufSize { + var buf [bufSize]byte + b = buf[:0] + } else { + b = make([]byte, 0, max) + } + b = t.AppendFormat(b, layout) + return string(b) +} + +// AppendFormat is like [Time.Format] but appends the textual +// representation to b and returns the extended buffer. +func (t Time) AppendFormat(b []byte, layout string) []byte { + // Optimize for RFC3339 as it accounts for over half of all representations. + switch layout { + case RFC3339: + return t.appendFormatRFC3339(b, false) + case RFC3339Nano: + return t.appendFormatRFC3339(b, true) + default: + return t.appendFormat(b, layout) + } +} + +func (t Time) appendFormat(b []byte, layout string) []byte { + var ( + name, offset, abs = t.locabs() + + year int = -1 + month Month + day int + yday int + hour int = -1 + min int + sec int + ) + + // Each iteration generates one std value. + for layout != "" { + prefix, std, suffix := nextStdChunk(layout) + if prefix != "" { + b = append(b, prefix...) + } + if std == 0 { + break + } + layout = suffix + + // Compute year, month, day if needed. + if year < 0 && std&stdNeedDate != 0 { + year, month, day, yday = absDate(abs, true) + yday++ + } + + // Compute hour, minute, second if needed. + if hour < 0 && std&stdNeedClock != 0 { + hour, min, sec = absClock(abs) + } + + switch std & stdMask { + case stdYear: + y := year + if y < 0 { + y = -y + } + b = appendInt(b, y%100, 2) + case stdLongYear: + b = appendInt(b, year, 4) + case stdMonth: + b = append(b, month.String()[:3]...) + case stdLongMonth: + m := month.String() + b = append(b, m...) + case stdNumMonth: + b = appendInt(b, int(month), 0) + case stdZeroMonth: + b = appendInt(b, int(month), 2) + case stdWeekDay: + b = append(b, absWeekday(abs).String()[:3]...) + case stdLongWeekDay: + s := absWeekday(abs).String() + b = append(b, s...) + case stdDay: + b = appendInt(b, day, 0) + case stdUnderDay: + if day < 10 { + b = append(b, ' ') + } + b = appendInt(b, day, 0) + case stdZeroDay: + b = appendInt(b, day, 2) + case stdUnderYearDay: + if yday < 100 { + b = append(b, ' ') + if yday < 10 { + b = append(b, ' ') + } + } + b = appendInt(b, yday, 0) + case stdZeroYearDay: + b = appendInt(b, yday, 3) + case stdHour: + b = appendInt(b, hour, 2) + case stdHour12: + // Noon is 12PM, midnight is 12AM. + hr := hour % 12 + if hr == 0 { + hr = 12 + } + b = appendInt(b, hr, 0) + case stdZeroHour12: + // Noon is 12PM, midnight is 12AM. + hr := hour % 12 + if hr == 0 { + hr = 12 + } + b = appendInt(b, hr, 2) + case stdMinute: + b = appendInt(b, min, 0) + case stdZeroMinute: + b = appendInt(b, min, 2) + case stdSecond: + b = appendInt(b, sec, 0) + case stdZeroSecond: + b = appendInt(b, sec, 2) + case stdPM: + if hour >= 12 { + b = append(b, "PM"...) + } else { + b = append(b, "AM"...) + } + case stdpm: + if hour >= 12 { + b = append(b, "pm"...) + } else { + b = append(b, "am"...) + } + case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ: + // Ugly special case. We cheat and take the "Z" variants + // to mean "the time zone as formatted for ISO 8601". + if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) { + b = append(b, 'Z') + break + } + zone := offset / 60 // convert to minutes + absoffset := offset + if zone < 0 { + b = append(b, '-') + zone = -zone + absoffset = -absoffset + } else { + b = append(b, '+') + } + b = appendInt(b, zone/60, 2) + if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { + b = append(b, ':') + } + if std != stdNumShortTZ && std != stdISO8601ShortTZ { + b = appendInt(b, zone%60, 2) + } + + // append seconds if appropriate + if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { + if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { + b = append(b, ':') + } + b = appendInt(b, absoffset%60, 2) + } + + case stdTZ: + if name != "" { + b = append(b, name...) + break + } + // No time zone known for this time, but we must print one. + // Use the -0700 format. + zone := offset / 60 // convert to minutes + if zone < 0 { + b = append(b, '-') + zone = -zone + } else { + b = append(b, '+') + } + b = appendInt(b, zone/60, 2) + b = appendInt(b, zone%60, 2) + case stdFracSecond0, stdFracSecond9: + b = appendNano(b, t.Nanosecond(), std) + } + } + return b +} + +var errBad = errors.New("bad value for field") // placeholder not passed to user + +// ParseError describes a problem parsing a time string. +type ParseError struct { + Layout string + Value string + LayoutElem string + ValueElem string + Message string +} + +// newParseError creates a new ParseError. +// The provided value and valueElem are cloned to avoid escaping their values. +func newParseError(layout, value, layoutElem, valueElem, message string) *ParseError { + valueCopy := stringslite.Clone(value) + valueElemCopy := stringslite.Clone(valueElem) + return &ParseError{layout, valueCopy, layoutElem, valueElemCopy, message} +} + +// These are borrowed from unicode/utf8 and strconv and replicate behavior in +// that package, since we can't take a dependency on either. +const ( + lowerhex = "0123456789abcdef" + runeSelf = 0x80 + runeError = '\uFFFD' +) + +func quote(s string) string { + buf := make([]byte, 1, len(s)+2) // slice will be at least len(s) + quotes + buf[0] = '"' + for i, c := range s { + if c >= runeSelf || c < ' ' { + // This means you are asking us to parse a time.Duration or + // time.Location with unprintable or non-ASCII characters in it. + // We don't expect to hit this case very often. We could try to + // reproduce strconv.Quote's behavior with full fidelity but + // given how rarely we expect to hit these edge cases, speed and + // conciseness are better. + var width int + if c == runeError { + width = 1 + if i+2 < len(s) && s[i:i+3] == string(runeError) { + width = 3 + } + } else { + width = len(string(c)) + } + for j := 0; j < width; j++ { + buf = append(buf, `\x`...) + buf = append(buf, lowerhex[s[i+j]>>4]) + buf = append(buf, lowerhex[s[i+j]&0xF]) + } + } else { + if c == '"' || c == '\\' { + buf = append(buf, '\\') + } + buf = append(buf, string(c)...) + } + } + buf = append(buf, '"') + return string(buf) +} + +// Error returns the string representation of a ParseError. +func (e *ParseError) Error() string { + if e.Message == "" { + return "parsing time " + + quote(e.Value) + " as " + + quote(e.Layout) + ": cannot parse " + + quote(e.ValueElem) + " as " + + quote(e.LayoutElem) + } + return "parsing time " + + quote(e.Value) + e.Message +} + +// isDigit reports whether s[i] is in range and is a decimal digit. +func isDigit[bytes []byte | string](s bytes, i int) bool { + if len(s) <= i { + return false + } + c := s[i] + return '0' <= c && c <= '9' +} + +// getnum parses s[0:1] or s[0:2] (fixed forces s[0:2]) +// as a decimal integer and returns the integer and the +// remainder of the string. +func getnum(s string, fixed bool) (int, string, error) { + if !isDigit(s, 0) { + return 0, s, errBad + } + if !isDigit(s, 1) { + if fixed { + return 0, s, errBad + } + return int(s[0] - '0'), s[1:], nil + } + return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil +} + +// getnum3 parses s[0:1], s[0:2], or s[0:3] (fixed forces s[0:3]) +// as a decimal integer and returns the integer and the remainder +// of the string. +func getnum3(s string, fixed bool) (int, string, error) { + var n, i int + for i = 0; i < 3 && isDigit(s, i); i++ { + n = n*10 + int(s[i]-'0') + } + if i == 0 || fixed && i != 3 { + return 0, s, errBad + } + return n, s[i:], nil +} + +func cutspace(s string) string { + for len(s) > 0 && s[0] == ' ' { + s = s[1:] + } + return s +} + +// skip removes the given prefix from value, +// treating runs of space characters as equivalent. +func skip(value, prefix string) (string, error) { + for len(prefix) > 0 { + if prefix[0] == ' ' { + if len(value) > 0 && value[0] != ' ' { + return value, errBad + } + prefix = cutspace(prefix) + value = cutspace(value) + continue + } + if len(value) == 0 || value[0] != prefix[0] { + return value, errBad + } + prefix = prefix[1:] + value = value[1:] + } + return value, nil +} + +// Parse parses a formatted string and returns the time value it represents. +// See the documentation for the constant called [Layout] to see how to +// represent the format. The second argument must be parseable using +// the format string (layout) provided as the first argument. +// +// The example for [Time.Format] demonstrates the working of the layout string +// in detail and is a good reference. +// +// When parsing (only), the input may contain a fractional second +// field immediately after the seconds field, even if the layout does not +// signify its presence. In that case either a comma or a decimal point +// followed by a maximal series of digits is parsed as a fractional second. +// Fractional seconds are truncated to nanosecond precision. +// +// Elements omitted from the layout are assumed to be zero or, when +// zero is impossible, one, so parsing "3:04pm" returns the time +// corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is +// 0, this time is before the zero Time). +// Years must be in the range 0000..9999. The day of the week is checked +// for syntax but it is otherwise ignored. +// +// For layouts specifying the two-digit year 06, a value NN >= 69 will be treated +// as 19NN and a value NN < 69 will be treated as 20NN. +// +// The remainder of this comment describes the handling of time zones. +// +// In the absence of a time zone indicator, Parse returns a time in UTC. +// +// When parsing a time with a zone offset like -0700, if the offset corresponds +// to a time zone used by the current location ([Local]), then Parse uses that +// location and zone in the returned time. Otherwise it records the time as +// being in a fabricated location with time fixed at the given zone offset. +// +// When parsing a time with a zone abbreviation like MST, if the zone abbreviation +// has a defined offset in the current location, then that offset is used. +// The zone abbreviation "UTC" is recognized as UTC regardless of location. +// If the zone abbreviation is unknown, Parse records the time as being +// in a fabricated location with the given zone abbreviation and a zero offset. +// This choice means that such a time can be parsed and reformatted with the +// same layout losslessly, but the exact instant used in the representation will +// differ by the actual zone offset. To avoid such problems, prefer time layouts +// that use a numeric zone offset, or use [ParseInLocation]. +func Parse(layout, value string) (Time, error) { + // Optimize for RFC3339 as it accounts for over half of all representations. + if layout == RFC3339 || layout == RFC3339Nano { + if t, ok := parseRFC3339(value, Local); ok { + return t, nil + } + } + return parse(layout, value, UTC, Local) +} + +// ParseInLocation is like Parse but differs in two important ways. +// First, in the absence of time zone information, Parse interprets a time as UTC; +// ParseInLocation interprets the time as in the given location. +// Second, when given a zone offset or abbreviation, Parse tries to match it +// against the Local location; ParseInLocation uses the given location. +func ParseInLocation(layout, value string, loc *Location) (Time, error) { + // Optimize for RFC3339 as it accounts for over half of all representations. + if layout == RFC3339 || layout == RFC3339Nano { + if t, ok := parseRFC3339(value, loc); ok { + return t, nil + } + } + return parse(layout, value, loc, loc) +} + +func parse(layout, value string, defaultLocation, local *Location) (Time, error) { + alayout, avalue := layout, value + rangeErrString := "" // set if a value is out of range + amSet := false // do we need to subtract 12 from the hour for midnight? + pmSet := false // do we need to add 12 to the hour? + + // Time being constructed. + var ( + year int + month int = -1 + day int = -1 + yday int = -1 + hour int + min int + sec int + nsec int + z *Location + zoneOffset int = -1 + zoneName string + ) + + // Each iteration processes one std value. + for { + var err error + prefix, std, suffix := nextStdChunk(layout) + stdstr := layout[len(prefix) : len(layout)-len(suffix)] + value, err = skip(value, prefix) + if err != nil { + return Time{}, newParseError(alayout, avalue, prefix, value, "") + } + if std == 0 { + if len(value) != 0 { + return Time{}, newParseError(alayout, avalue, "", value, ": extra text: "+quote(value)) + } + break + } + layout = suffix + var p string + hold := value + switch std & stdMask { + case stdYear: + if len(value) < 2 { + err = errBad + break + } + p, value = value[0:2], value[2:] + year, err = atoi(p) + if err != nil { + break + } + if year >= 69 { // Unix time starts Dec 31 1969 in some time zones + year += 1900 + } else { + year += 2000 + } + case stdLongYear: + if len(value) < 4 || !isDigit(value, 0) { + err = errBad + break + } + p, value = value[0:4], value[4:] + year, err = atoi(p) + case stdMonth: + month, value, err = lookup(shortMonthNames, value) + month++ + case stdLongMonth: + month, value, err = lookup(longMonthNames, value) + month++ + case stdNumMonth, stdZeroMonth: + month, value, err = getnum(value, std == stdZeroMonth) + if err == nil && (month <= 0 || 12 < month) { + rangeErrString = "month" + } + case stdWeekDay: + // Ignore weekday except for error checking. + _, value, err = lookup(shortDayNames, value) + case stdLongWeekDay: + _, value, err = lookup(longDayNames, value) + case stdDay, stdUnderDay, stdZeroDay: + if std == stdUnderDay && len(value) > 0 && value[0] == ' ' { + value = value[1:] + } + day, value, err = getnum(value, std == stdZeroDay) + // Note that we allow any one- or two-digit day here. + // The month, day, year combination is validated after we've completed parsing. + case stdUnderYearDay, stdZeroYearDay: + for i := 0; i < 2; i++ { + if std == stdUnderYearDay && len(value) > 0 && value[0] == ' ' { + value = value[1:] + } + } + yday, value, err = getnum3(value, std == stdZeroYearDay) + // Note that we allow any one-, two-, or three-digit year-day here. + // The year-day, year combination is validated after we've completed parsing. + case stdHour: + hour, value, err = getnum(value, false) + if hour < 0 || 24 <= hour { + rangeErrString = "hour" + } + case stdHour12, stdZeroHour12: + hour, value, err = getnum(value, std == stdZeroHour12) + if hour < 0 || 12 < hour { + rangeErrString = "hour" + } + case stdMinute, stdZeroMinute: + min, value, err = getnum(value, std == stdZeroMinute) + if min < 0 || 60 <= min { + rangeErrString = "minute" + } + case stdSecond, stdZeroSecond: + sec, value, err = getnum(value, std == stdZeroSecond) + if err != nil { + break + } + if sec < 0 || 60 <= sec { + rangeErrString = "second" + break + } + // Special case: do we have a fractional second but no + // fractional second in the format? + if len(value) >= 2 && commaOrPeriod(value[0]) && isDigit(value, 1) { + _, std, _ = nextStdChunk(layout) + std &= stdMask + if std == stdFracSecond0 || std == stdFracSecond9 { + // Fractional second in the layout; proceed normally + break + } + // No fractional second in the layout but we have one in the input. + n := 2 + for ; n < len(value) && isDigit(value, n); n++ { + } + nsec, rangeErrString, err = parseNanoseconds(value, n) + value = value[n:] + } + case stdPM: + if len(value) < 2 { + err = errBad + break + } + p, value = value[0:2], value[2:] + switch p { + case "PM": + pmSet = true + case "AM": + amSet = true + default: + err = errBad + } + case stdpm: + if len(value) < 2 { + err = errBad + break + } + p, value = value[0:2], value[2:] + switch p { + case "pm": + pmSet = true + case "am": + amSet = true + default: + err = errBad + } + case stdISO8601TZ, stdISO8601ShortTZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ: + if len(value) >= 1 && value[0] == 'Z' { + value = value[1:] + z = UTC + break + } + fallthrough + case stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ: + var sign, hour, min, seconds string + if std == stdISO8601ColonTZ || std == stdNumColonTZ { + if len(value) < 6 { + err = errBad + break + } + if value[3] != ':' { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:] + } else if std == stdNumShortTZ || std == stdISO8601ShortTZ { + if len(value) < 3 { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], "00", "00", value[3:] + } else if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { + if len(value) < 9 { + err = errBad + break + } + if value[3] != ':' || value[6] != ':' { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], value[7:9], value[9:] + } else if std == stdISO8601SecondsTZ || std == stdNumSecondsTz { + if len(value) < 7 { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], value[5:7], value[7:] + } else { + if len(value) < 5 { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], "00", value[5:] + } + var hr, mm, ss int + hr, _, err = getnum(hour, true) + if err == nil { + mm, _, err = getnum(min, true) + } + if err == nil { + ss, _, err = getnum(seconds, true) + } + + // The range test use > rather than >=, + // as some people do write offsets of 24 hours + // or 60 minutes or 60 seconds. + if hr > 24 { + rangeErrString = "time zone offset hour" + } + if mm > 60 { + rangeErrString = "time zone offset minute" + } + if ss > 60 { + rangeErrString = "time zone offset second" + } + + zoneOffset = (hr*60+mm)*60 + ss // offset is in seconds + switch sign[0] { + case '+': + case '-': + zoneOffset = -zoneOffset + default: + err = errBad + } + case stdTZ: + // Does it look like a time zone? + if len(value) >= 3 && value[0:3] == "UTC" { + z = UTC + value = value[3:] + break + } + n, ok := parseTimeZone(value) + if !ok { + err = errBad + break + } + zoneName, value = value[:n], value[n:] + + case stdFracSecond0: + // stdFracSecond0 requires the exact number of digits as specified in + // the layout. + ndigit := 1 + digitsLen(std) + if len(value) < ndigit { + err = errBad + break + } + nsec, rangeErrString, err = parseNanoseconds(value, ndigit) + value = value[ndigit:] + + case stdFracSecond9: + if len(value) < 2 || !commaOrPeriod(value[0]) || value[1] < '0' || '9' < value[1] { + // Fractional second omitted. + break + } + // Take any number of digits, even more than asked for, + // because it is what the stdSecond case would do. + i := 0 + for i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' { + i++ + } + nsec, rangeErrString, err = parseNanoseconds(value, 1+i) + value = value[1+i:] + } + if rangeErrString != "" { + return Time{}, newParseError(alayout, avalue, stdstr, value, ": "+rangeErrString+" out of range") + } + if err != nil { + return Time{}, newParseError(alayout, avalue, stdstr, hold, "") + } + } + if pmSet && hour < 12 { + hour += 12 + } else if amSet && hour == 12 { + hour = 0 + } + + // Convert yday to day, month. + if yday >= 0 { + var d int + var m int + if isLeap(year) { + if yday == 31+29 { + m = int(February) + d = 29 + } else if yday > 31+29 { + yday-- + } + } + if yday < 1 || yday > 365 { + return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year out of range") + } + if m == 0 { + m = (yday-1)/31 + 1 + if int(daysBefore[m]) < yday { + m++ + } + d = yday - int(daysBefore[m-1]) + } + // If month, day already seen, yday's m, d must match. + // Otherwise, set them from m, d. + if month >= 0 && month != m { + return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year does not match month") + } + month = m + if day >= 0 && day != d { + return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year does not match day") + } + day = d + } else { + if month < 0 { + month = int(January) + } + if day < 0 { + day = 1 + } + } + + // Validate the day of the month. + if day < 1 || day > daysIn(Month(month), year) { + return Time{}, newParseError(alayout, avalue, "", value, ": day out of range") + } + + if z != nil { + return Date(year, Month(month), day, hour, min, sec, nsec, z), nil + } + + if zoneOffset != -1 { + t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) + t.addSec(-int64(zoneOffset)) + + // Look for local zone with the given offset. + // If that zone was in effect at the given time, use it. + name, offset, _, _, _ := local.lookup(t.unixSec()) + if offset == zoneOffset && (zoneName == "" || name == zoneName) { + t.setLoc(local) + return t, nil + } + + // Otherwise create fake zone to record offset. + zoneNameCopy := stringslite.Clone(zoneName) // avoid leaking the input value + t.setLoc(FixedZone(zoneNameCopy, zoneOffset)) + return t, nil + } + + if zoneName != "" { + t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) + // Look for local zone with the given offset. + // If that zone was in effect at the given time, use it. + offset, ok := local.lookupName(zoneName, t.unixSec()) + if ok { + t.addSec(-int64(offset)) + t.setLoc(local) + return t, nil + } + + // Otherwise, create fake zone with unknown offset. + if len(zoneName) > 3 && zoneName[:3] == "GMT" { + offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT. + offset *= 3600 + } + zoneNameCopy := stringslite.Clone(zoneName) // avoid leaking the input value + t.setLoc(FixedZone(zoneNameCopy, offset)) + return t, nil + } + + // Otherwise, fall back to default. + return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil +} + +// parseTimeZone parses a time zone string and returns its length. Time zones +// are human-generated and unpredictable. We can't do precise error checking. +// On the other hand, for a correct parse there must be a time zone at the +// beginning of the string, so it's almost always true that there's one +// there. We look at the beginning of the string for a run of upper-case letters. +// If there are more than 5, it's an error. +// If there are 4 or 5 and the last is a T, it's a time zone. +// If there are 3, it's a time zone. +// Otherwise, other than special cases, it's not a time zone. +// GMT is special because it can have an hour offset. +func parseTimeZone(value string) (length int, ok bool) { + if len(value) < 3 { + return 0, false + } + // Special case 1: ChST and MeST are the only zones with a lower-case letter. + if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") { + return 4, true + } + // Special case 2: GMT may have an hour offset; treat it specially. + if value[:3] == "GMT" { + length = parseGMT(value) + return length, true + } + // Special Case 3: Some time zones are not named, but have +/-00 format + if value[0] == '+' || value[0] == '-' { + length = parseSignedOffset(value) + ok := length > 0 // parseSignedOffset returns 0 in case of bad input + return length, ok + } + // How many upper-case letters are there? Need at least three, at most five. + var nUpper int + for nUpper = 0; nUpper < 6; nUpper++ { + if nUpper >= len(value) { + break + } + if c := value[nUpper]; c < 'A' || 'Z' < c { + break + } + } + switch nUpper { + case 0, 1, 2, 6: + return 0, false + case 5: // Must end in T to match. + if value[4] == 'T' { + return 5, true + } + case 4: + // Must end in T, except one special case. + if value[3] == 'T' || value[:4] == "WITA" { + return 4, true + } + case 3: + return 3, true + } + return 0, false +} + +// parseGMT parses a GMT time zone. The input string is known to start "GMT". +// The function checks whether that is followed by a sign and a number in the +// range -23 through +23 excluding zero. +func parseGMT(value string) int { + value = value[3:] + if len(value) == 0 { + return 3 + } + + return 3 + parseSignedOffset(value) +} + +// parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04"). +// The function checks for a signed number in the range -23 through +23 excluding zero. +// Returns length of the found offset string or 0 otherwise. +func parseSignedOffset(value string) int { + sign := value[0] + if sign != '-' && sign != '+' { + return 0 + } + x, rem, err := leadingInt(value[1:]) + + // fail if nothing consumed by leadingInt + if err != nil || value[1:] == rem { + return 0 + } + if x > 23 { + return 0 + } + return len(value) - len(rem) +} + +func commaOrPeriod(b byte) bool { + return b == '.' || b == ',' +} + +func parseNanoseconds[bytes []byte | string](value bytes, nbytes int) (ns int, rangeErrString string, err error) { + if !commaOrPeriod(value[0]) { + err = errBad + return + } + if nbytes > 10 { + value = value[:10] + nbytes = 10 + } + if ns, err = atoi(value[1:nbytes]); err != nil { + return + } + if ns < 0 { + rangeErrString = "fractional second" + return + } + // We need nanoseconds, which means scaling by the number + // of missing digits in the format, maximum length 10. + scaleDigits := 10 - nbytes + for i := 0; i < scaleDigits; i++ { + ns *= 10 + } + return +} + +var errLeadingInt = errors.New("time: bad [0-9]*") // never printed + +// leadingInt consumes the leading [0-9]* from s. +func leadingInt[bytes []byte | string](s bytes) (x uint64, rem bytes, err error) { + i := 0 + for ; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + break + } + if x > 1<<63/10 { + // overflow + return 0, rem, errLeadingInt + } + x = x*10 + uint64(c) - '0' + if x > 1<<63 { + // overflow + return 0, rem, errLeadingInt + } + } + return x, s[i:], nil +} + +// leadingFraction consumes the leading [0-9]* from s. +// It is used only for fractions, so does not return an error on overflow, +// it just stops accumulating precision. +func leadingFraction(s string) (x uint64, scale float64, rem string) { + i := 0 + scale = 1 + overflow := false + for ; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + break + } + if overflow { + continue + } + if x > (1<<63-1)/10 { + // It's possible for overflow to give a positive number, so take care. + overflow = true + continue + } + y := x*10 + uint64(c) - '0' + if y > 1<<63 { + overflow = true + continue + } + x = y + scale *= 10 + } + return x, scale, s[i:] +} + +var unitMap = map[string]uint64{ + "ns": uint64(Nanosecond), + "us": uint64(Microsecond), + "µs": uint64(Microsecond), // U+00B5 = micro symbol + "μs": uint64(Microsecond), // U+03BC = Greek letter mu + "ms": uint64(Millisecond), + "s": uint64(Second), + "m": uint64(Minute), + "h": uint64(Hour), +} + +// ParseDuration parses a duration string. +// A duration string is a possibly signed sequence of +// decimal numbers, each with optional fraction and a unit suffix, +// such as "300ms", "-1.5h" or "2h45m". +// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". +func ParseDuration(s string) (Duration, error) { + // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ + orig := s + var d uint64 + neg := false + + // Consume [-+]? + if s != "" { + c := s[0] + if c == '-' || c == '+' { + neg = c == '-' + s = s[1:] + } + } + // Special case: if all that is left is "0", this is zero. + if s == "0" { + return 0, nil + } + if s == "" { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + for s != "" { + var ( + v, f uint64 // integers before, after decimal point + scale float64 = 1 // value = v + f/scale + ) + + var err error + + // The next character must be [0-9.] + if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + // Consume [0-9]* + pl := len(s) + v, s, err = leadingInt(s) + if err != nil { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + pre := pl != len(s) // whether we consumed anything before a period + + // Consume (\.[0-9]*)? + post := false + if s != "" && s[0] == '.' { + s = s[1:] + pl := len(s) + f, scale, s = leadingFraction(s) + post = pl != len(s) + } + if !pre && !post { + // no digits (e.g. ".s" or "-.s") + return 0, errors.New("time: invalid duration " + quote(orig)) + } + + // Consume unit. + i := 0 + for ; i < len(s); i++ { + c := s[i] + if c == '.' || '0' <= c && c <= '9' { + break + } + } + if i == 0 { + return 0, errors.New("time: missing unit in duration " + quote(orig)) + } + u := s[:i] + s = s[i:] + unit, ok := unitMap[u] + if !ok { + return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig)) + } + if v > 1<<63/unit { + // overflow + return 0, errors.New("time: invalid duration " + quote(orig)) + } + v *= unit + if f > 0 { + // float64 is needed to be nanosecond accurate for fractions of hours. + // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) + v += uint64(float64(f) * (float64(unit) / scale)) + if v > 1<<63 { + // overflow + return 0, errors.New("time: invalid duration " + quote(orig)) + } + } + d += v + if d > 1<<63 { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + } + if neg { + return -Duration(d), nil + } + if d > 1<<63-1 { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + return Duration(d), nil +} diff --git a/contrib/go/_std_1.22/src/time/format_rfc3339.go b/contrib/go/_std_1.23/src/time/format_rfc3339.go similarity index 100% rename from contrib/go/_std_1.22/src/time/format_rfc3339.go rename to contrib/go/_std_1.23/src/time/format_rfc3339.go diff --git a/contrib/go/_std_1.22/src/time/genzabbrs.go b/contrib/go/_std_1.23/src/time/genzabbrs.go similarity index 96% rename from contrib/go/_std_1.22/src/time/genzabbrs.go rename to contrib/go/_std_1.23/src/time/genzabbrs.go index 7dbd22f4ea3f..765771782551 100644 --- a/contrib/go/_std_1.22/src/time/genzabbrs.go +++ b/contrib/go/_std_1.23/src/time/genzabbrs.go @@ -21,7 +21,8 @@ import ( "log" "net/http" "os" - "sort" + "slices" + "strings" "text/template" "time" ) @@ -109,8 +110,8 @@ func main() { if err != nil { log.Fatal(err) } - sort.Slice(zs, func(i, j int) bool { - return zs[i].UnixName < zs[j].UnixName + slices.SortFunc(zs, func(a, b *zone) int { + return strings.Compare(a.UnixName, b.UnixName) }) var v = struct { URL string diff --git a/contrib/go/_std_1.23/src/time/sleep.go b/contrib/go/_std_1.23/src/time/sleep.go new file mode 100644 index 000000000000..7e2fa0c20af4 --- /dev/null +++ b/contrib/go/_std_1.23/src/time/sleep.go @@ -0,0 +1,216 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package time + +import ( + "internal/godebug" + "unsafe" +) + +// Sleep pauses the current goroutine for at least the duration d. +// A negative or zero duration causes Sleep to return immediately. +func Sleep(d Duration) + +var asynctimerchan = godebug.New("asynctimerchan") + +// syncTimer returns c as an unsafe.Pointer, for passing to newTimer. +// If the GODEBUG asynctimerchan has disabled the async timer chan +// code, then syncTimer always returns nil, to disable the special +// channel code paths in the runtime. +func syncTimer(c chan Time) unsafe.Pointer { + // If asynctimerchan=1, we don't even tell the runtime + // about channel timers, so that we get the pre-Go 1.23 code paths. + if asynctimerchan.Value() == "1" { + asynctimerchan.IncNonDefault() + return nil + } + + // Otherwise pass to runtime. + // This handles asynctimerchan=0, which is the default Go 1.23 behavior, + // as well as asynctimerchan=2, which is like asynctimerchan=1 + // but implemented entirely by the runtime. + // The only reason to use asynctimerchan=2 is for debugging + // a problem fixed by asynctimerchan=1: it enables the new + // GC-able timer channels (#61542) but not the sync channels (#37196). + // + // If we decide to roll back the sync channels, we will still have + // a fully tested async runtime implementation (asynctimerchan=2) + // and can make this function always return c. + // + // If we decide to keep the sync channels, we can delete all the + // handling of asynctimerchan in the runtime and keep just this + // function to handle asynctimerchan=1. + return *(*unsafe.Pointer)(unsafe.Pointer(&c)) +} + +// when is a helper function for setting the 'when' field of a runtimeTimer. +// It returns what the time will be, in nanoseconds, Duration d in the future. +// If d is negative, it is ignored. If the returned value would be less than +// zero because of an overflow, MaxInt64 is returned. +func when(d Duration) int64 { + if d <= 0 { + return runtimeNano() + } + t := runtimeNano() + int64(d) + if t < 0 { + // N.B. runtimeNano() and d are always positive, so addition + // (including overflow) will never result in t == 0. + t = 1<<63 - 1 // math.MaxInt64 + } + return t +} + +// These functions are pushed to package time from package runtime. + +// The arg cp is a chan Time, but the declaration in runtime uses a pointer, +// so we use a pointer here too. This keeps some tools that aggressively +// compare linknamed symbol definitions happier. +// +//go:linkname newTimer +func newTimer(when, period int64, f func(any, uintptr, int64), arg any, cp unsafe.Pointer) *Timer + +//go:linkname stopTimer +func stopTimer(*Timer) bool + +//go:linkname resetTimer +func resetTimer(t *Timer, when, period int64) bool + +// Note: The runtime knows the layout of struct Timer, since newTimer allocates it. +// The runtime also knows that Ticker and Timer have the same layout. +// There are extra fields after the channel, reserved for the runtime +// and inaccessible to users. + +// The Timer type represents a single event. +// When the Timer expires, the current time will be sent on C, +// unless the Timer was created by [AfterFunc]. +// A Timer must be created with [NewTimer] or AfterFunc. +type Timer struct { + C <-chan Time + initTimer bool +} + +// Stop prevents the [Timer] from firing. +// It returns true if the call stops the timer, false if the timer has already +// expired or been stopped. +// +// For a func-based timer created with [AfterFunc](d, f), +// if t.Stop returns false, then the timer has already expired +// and the function f has been started in its own goroutine; +// Stop does not wait for f to complete before returning. +// If the caller needs to know whether f is completed, +// it must coordinate with f explicitly. +// +// For a chan-based timer created with NewTimer(d), as of Go 1.23, +// any receive from t.C after Stop has returned is guaranteed to block +// rather than receive a stale time value from before the Stop; +// if the program has not received from t.C already and the timer is +// running, Stop is guaranteed to return true. +// Before Go 1.23, the only safe way to use Stop was insert an extra +// <-t.C if Stop returned false to drain a potential stale value. +// See the [NewTimer] documentation for more details. +func (t *Timer) Stop() bool { + if !t.initTimer { + panic("time: Stop called on uninitialized Timer") + } + return stopTimer(t) +} + +// NewTimer creates a new Timer that will send +// the current time on its channel after at least duration d. +// +// Before Go 1.23, the garbage collector did not recover +// timers that had not yet expired or been stopped, so code often +// immediately deferred t.Stop after calling NewTimer, to make +// the timer recoverable when it was no longer needed. +// As of Go 1.23, the garbage collector can recover unreferenced +// timers, even if they haven't expired or been stopped. +// The Stop method is no longer necessary to help the garbage collector. +// (Code may of course still want to call Stop to stop the timer for other reasons.) +// +// Before Go 1.23, the channel associated with a Timer was +// asynchronous (buffered, capacity 1), which meant that +// stale time values could be received even after [Timer.Stop] +// or [Timer.Reset] returned. +// As of Go 1.23, the channel is synchronous (unbuffered, capacity 0), +// eliminating the possibility of those stale values. +// +// The GODEBUG setting asynctimerchan=1 restores both pre-Go 1.23 +// behaviors: when set, unexpired timers won't be garbage collected, and +// channels will have buffered capacity. This setting may be removed +// in Go 1.27 or later. +func NewTimer(d Duration) *Timer { + c := make(chan Time, 1) + t := (*Timer)(newTimer(when(d), 0, sendTime, c, syncTimer(c))) + t.C = c + return t +} + +// Reset changes the timer to expire after duration d. +// It returns true if the timer had been active, false if the timer had +// expired or been stopped. +// +// For a func-based timer created with [AfterFunc](d, f), Reset either reschedules +// when f will run, in which case Reset returns true, or schedules f +// to run again, in which case it returns false. +// When Reset returns false, Reset neither waits for the prior f to +// complete before returning nor does it guarantee that the subsequent +// goroutine running f does not run concurrently with the prior +// one. If the caller needs to know whether the prior execution of +// f is completed, it must coordinate with f explicitly. +// +// For a chan-based timer created with NewTimer, as of Go 1.23, +// any receive from t.C after Reset has returned is guaranteed not +// to receive a time value corresponding to the previous timer settings; +// if the program has not received from t.C already and the timer is +// running, Reset is guaranteed to return true. +// Before Go 1.23, the only safe way to use Reset was to [Stop] and +// explicitly drain the timer first. +// See the [NewTimer] documentation for more details. +func (t *Timer) Reset(d Duration) bool { + if !t.initTimer { + panic("time: Reset called on uninitialized Timer") + } + w := when(d) + return resetTimer(t, w, 0) +} + +// sendTime does a non-blocking send of the current time on c. +func sendTime(c any, seq uintptr, delta int64) { + // delta is how long ago the channel send was supposed to happen. + // The current time can be arbitrarily far into the future, because the runtime + // can delay a sendTime call until a goroutines tries to receive from + // the channel. Subtract delta to go back to the old time that we + // used to send. + select { + case c.(chan Time) <- Now().Add(Duration(-delta)): + default: + } +} + +// After waits for the duration to elapse and then sends the current time +// on the returned channel. +// It is equivalent to [NewTimer](d).C. +// +// Before Go 1.23, this documentation warned that the underlying +// [Timer] would not be recovered by the garbage collector until the +// timer fired, and that if efficiency was a concern, code should use +// NewTimer instead and call [Timer.Stop] if the timer is no longer needed. +// As of Go 1.23, the garbage collector can recover unreferenced, +// unstopped timers. There is no reason to prefer NewTimer when After will do. +func After(d Duration) <-chan Time { + return NewTimer(d).C +} + +// AfterFunc waits for the duration to elapse and then calls f +// in its own goroutine. It returns a [Timer] that can +// be used to cancel the call using its Stop method. +// The returned Timer's C field is not used and will be nil. +func AfterFunc(d Duration, f func()) *Timer { + return (*Timer)(newTimer(when(d), 0, goFunc, f, nil)) +} + +func goFunc(arg any, seq uintptr, delta int64) { + go arg.(func())() +} diff --git a/contrib/go/_std_1.22/src/time/sys_plan9.go b/contrib/go/_std_1.23/src/time/sys_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/time/sys_plan9.go rename to contrib/go/_std_1.23/src/time/sys_plan9.go diff --git a/contrib/go/_std_1.22/src/time/sys_unix.go b/contrib/go/_std_1.23/src/time/sys_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/time/sys_unix.go rename to contrib/go/_std_1.23/src/time/sys_unix.go diff --git a/contrib/go/_std_1.22/src/time/sys_windows.go b/contrib/go/_std_1.23/src/time/sys_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/time/sys_windows.go rename to contrib/go/_std_1.23/src/time/sys_windows.go diff --git a/contrib/go/_std_1.23/src/time/tick.go b/contrib/go/_std_1.23/src/time/tick.go new file mode 100644 index 000000000000..057a9069ea51 --- /dev/null +++ b/contrib/go/_std_1.23/src/time/tick.go @@ -0,0 +1,91 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package time + +import "unsafe" + +// Note: The runtime knows the layout of struct Ticker, since newTimer allocates it. +// Note also that Ticker and Timer have the same layout, so that newTimer can handle both. +// The initTimer and initTicker fields are named differently so that +// users cannot convert between the two without unsafe. + +// A Ticker holds a channel that delivers “ticks” of a clock +// at intervals. +type Ticker struct { + C <-chan Time // The channel on which the ticks are delivered. + initTicker bool +} + +// NewTicker returns a new [Ticker] containing a channel that will send +// the current time on the channel after each tick. The period of the +// ticks is specified by the duration argument. The ticker will adjust +// the time interval or drop ticks to make up for slow receivers. +// The duration d must be greater than zero; if not, NewTicker will +// panic. +// +// Before Go 1.23, the garbage collector did not recover +// tickers that had not yet expired or been stopped, so code often +// immediately deferred t.Stop after calling NewTicker, to make +// the ticker recoverable when it was no longer needed. +// As of Go 1.23, the garbage collector can recover unreferenced +// tickers, even if they haven't been stopped. +// The Stop method is no longer necessary to help the garbage collector. +// (Code may of course still want to call Stop to stop the ticker for other reasons.) +func NewTicker(d Duration) *Ticker { + if d <= 0 { + panic("non-positive interval for NewTicker") + } + // Give the channel a 1-element time buffer. + // If the client falls behind while reading, we drop ticks + // on the floor until the client catches up. + c := make(chan Time, 1) + t := (*Ticker)(unsafe.Pointer(newTimer(when(d), int64(d), sendTime, c, syncTimer(c)))) + t.C = c + return t +} + +// Stop turns off a ticker. After Stop, no more ticks will be sent. +// Stop does not close the channel, to prevent a concurrent goroutine +// reading from the channel from seeing an erroneous "tick". +func (t *Ticker) Stop() { + if !t.initTicker { + // This is misuse, and the same for time.Timer would panic, + // but this didn't always panic, and we keep it not panicking + // to avoid breaking old programs. See issue 21874. + return + } + stopTimer((*Timer)(unsafe.Pointer(t))) +} + +// Reset stops a ticker and resets its period to the specified duration. +// The next tick will arrive after the new period elapses. The duration d +// must be greater than zero; if not, Reset will panic. +func (t *Ticker) Reset(d Duration) { + if d <= 0 { + panic("non-positive interval for Ticker.Reset") + } + if !t.initTicker { + panic("time: Reset called on uninitialized Ticker") + } + resetTimer((*Timer)(unsafe.Pointer(t)), when(d), int64(d)) +} + +// Tick is a convenience wrapper for [NewTicker] providing access to the ticking +// channel only. Unlike NewTicker, Tick will return nil if d <= 0. +// +// Before Go 1.23, this documentation warned that the underlying +// [Ticker] would never be recovered by the garbage collector, and that +// if efficiency was a concern, code should use NewTicker instead and +// call [Ticker.Stop] when the ticker is no longer needed. +// As of Go 1.23, the garbage collector can recover unreferenced +// tickers, even if they haven't been stopped. +// The Stop method is no longer necessary to help the garbage collector. +// There is no longer any reason to prefer NewTicker when Tick will do. +func Tick(d Duration) <-chan Time { + if d <= 0 { + return nil + } + return NewTicker(d).C +} diff --git a/contrib/go/_std_1.23/src/time/time.go b/contrib/go/_std_1.23/src/time/time.go new file mode 100644 index 000000000000..43efe4b11d0d --- /dev/null +++ b/contrib/go/_std_1.23/src/time/time.go @@ -0,0 +1,1695 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package time provides functionality for measuring and displaying time. +// +// The calendrical calculations always assume a Gregorian calendar, with +// no leap seconds. +// +// # Monotonic Clocks +// +// Operating systems provide both a “wall clock,” which is subject to +// changes for clock synchronization, and a “monotonic clock,” which is +// not. The general rule is that the wall clock is for telling time and +// the monotonic clock is for measuring time. Rather than split the API, +// in this package the Time returned by [time.Now] contains both a wall +// clock reading and a monotonic clock reading; later time-telling +// operations use the wall clock reading, but later time-measuring +// operations, specifically comparisons and subtractions, use the +// monotonic clock reading. +// +// For example, this code always computes a positive elapsed time of +// approximately 20 milliseconds, even if the wall clock is changed during +// the operation being timed: +// +// start := time.Now() +// ... operation that takes 20 milliseconds ... +// t := time.Now() +// elapsed := t.Sub(start) +// +// Other idioms, such as [time.Since](start), [time.Until](deadline), and +// time.Now().Before(deadline), are similarly robust against wall clock +// resets. +// +// The rest of this section gives the precise details of how operations +// use monotonic clocks, but understanding those details is not required +// to use this package. +// +// The Time returned by time.Now contains a monotonic clock reading. +// If Time t has a monotonic clock reading, t.Add adds the same duration to +// both the wall clock and monotonic clock readings to compute the result. +// Because t.AddDate(y, m, d), t.Round(d), and t.Truncate(d) are wall time +// computations, they always strip any monotonic clock reading from their results. +// Because t.In, t.Local, and t.UTC are used for their effect on the interpretation +// of the wall time, they also strip any monotonic clock reading from their results. +// The canonical way to strip a monotonic clock reading is to use t = t.Round(0). +// +// If Times t and u both contain monotonic clock readings, the operations +// t.After(u), t.Before(u), t.Equal(u), t.Compare(u), and t.Sub(u) are carried out +// using the monotonic clock readings alone, ignoring the wall clock +// readings. If either t or u contains no monotonic clock reading, these +// operations fall back to using the wall clock readings. +// +// On some systems the monotonic clock will stop if the computer goes to sleep. +// On such a system, t.Sub(u) may not accurately reflect the actual +// time that passed between t and u. The same applies to other functions and +// methods that subtract times, such as [Since], [Until], [Before], [After], +// [Add], [Sub], [Equal] and [Compare]. In some cases, you may need to strip +// the monotonic clock to get accurate results. +// +// Because the monotonic clock reading has no meaning outside +// the current process, the serialized forms generated by t.GobEncode, +// t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic +// clock reading, and t.Format provides no format for it. Similarly, the +// constructors [time.Date], [time.Parse], [time.ParseInLocation], and [time.Unix], +// as well as the unmarshalers t.GobDecode, t.UnmarshalBinary. +// t.UnmarshalJSON, and t.UnmarshalText always create times with +// no monotonic clock reading. +// +// The monotonic clock reading exists only in [Time] values. It is not +// a part of [Duration] values or the Unix times returned by t.Unix and +// friends. +// +// Note that the Go == operator compares not just the time instant but +// also the [Location] and the monotonic clock reading. See the +// documentation for the Time type for a discussion of equality +// testing for Time values. +// +// For debugging, the result of t.String does include the monotonic +// clock reading if present. If t != u because of different monotonic clock readings, +// that difference will be visible when printing t.String() and u.String(). +// +// # Timer Resolution +// +// [Timer] resolution varies depending on the Go runtime, the operating system +// and the underlying hardware. +// On Unix, the resolution is ~1ms. +// On Windows version 1803 and newer, the resolution is ~0.5ms. +// On older Windows versions, the default resolution is ~16ms, but +// a higher resolution may be requested using [golang.org/x/sys/windows.TimeBeginPeriod]. +package time + +import ( + "errors" + _ "unsafe" // for go:linkname +) + +// A Time represents an instant in time with nanosecond precision. +// +// Programs using times should typically store and pass them as values, +// not pointers. That is, time variables and struct fields should be of +// type [time.Time], not *time.Time. +// +// A Time value can be used by multiple goroutines simultaneously except +// that the methods [Time.GobDecode], [Time.UnmarshalBinary], [Time.UnmarshalJSON] and +// [Time.UnmarshalText] are not concurrency-safe. +// +// Time instants can be compared using the [Time.Before], [Time.After], and [Time.Equal] methods. +// The [Time.Sub] method subtracts two instants, producing a [Duration]. +// The [Time.Add] method adds a Time and a Duration, producing a Time. +// +// The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. +// As this time is unlikely to come up in practice, the [Time.IsZero] method gives +// a simple way of detecting a time that has not been initialized explicitly. +// +// Each time has an associated [Location]. The methods [Time.Local], [Time.UTC], and Time.In return a +// Time with a specific Location. Changing the Location of a Time value with +// these methods does not change the actual instant it represents, only the time +// zone in which to interpret it. +// +// Representations of a Time value saved by the [Time.GobEncode], [Time.MarshalBinary], +// [Time.MarshalJSON], and [Time.MarshalText] methods store the [Time.Location]'s offset, but not +// the location name. They therefore lose information about Daylight Saving Time. +// +// In addition to the required “wall clock” reading, a Time may contain an optional +// reading of the current process's monotonic clock, to provide additional precision +// for comparison or subtraction. +// See the “Monotonic Clocks” section in the package documentation for details. +// +// Note that the Go == operator compares not just the time instant but also the +// Location and the monotonic clock reading. Therefore, Time values should not +// be used as map or database keys without first guaranteeing that the +// identical Location has been set for all values, which can be achieved +// through use of the UTC or Local method, and that the monotonic clock reading +// has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u) +// to t == u, since t.Equal uses the most accurate comparison available and +// correctly handles the case when only one of its arguments has a monotonic +// clock reading. +type Time struct { + // wall and ext encode the wall time seconds, wall time nanoseconds, + // and optional monotonic clock reading in nanoseconds. + // + // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic), + // a 33-bit seconds field, and a 30-bit wall time nanoseconds field. + // The nanoseconds field is in the range [0, 999999999]. + // If the hasMonotonic bit is 0, then the 33-bit field must be zero + // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext. + // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit + // unsigned wall seconds since Jan 1 year 1885, and ext holds a + // signed 64-bit monotonic clock reading, nanoseconds since process start. + wall uint64 + ext int64 + + // loc specifies the Location that should be used to + // determine the minute, hour, month, day, and year + // that correspond to this Time. + // The nil location means UTC. + // All UTC times are represented with loc==nil, never loc==&utcLoc. + loc *Location +} + +const ( + hasMonotonic = 1 << 63 + maxWall = wallToInternal + (1<<33 - 1) // year 2157 + minWall = wallToInternal // year 1885 + nsecMask = 1<<30 - 1 + nsecShift = 30 +) + +// These helpers for manipulating the wall and monotonic clock readings +// take pointer receivers, even when they don't modify the time, +// to make them cheaper to call. + +// nsec returns the time's nanoseconds. +func (t *Time) nsec() int32 { + return int32(t.wall & nsecMask) +} + +// sec returns the time's seconds since Jan 1 year 1. +func (t *Time) sec() int64 { + if t.wall&hasMonotonic != 0 { + return wallToInternal + int64(t.wall<<1>>(nsecShift+1)) + } + return t.ext +} + +// unixSec returns the time's seconds since Jan 1 1970 (Unix time). +func (t *Time) unixSec() int64 { return t.sec() + internalToUnix } + +// addSec adds d seconds to the time. +func (t *Time) addSec(d int64) { + if t.wall&hasMonotonic != 0 { + sec := int64(t.wall << 1 >> (nsecShift + 1)) + dsec := sec + d + if 0 <= dsec && dsec <= 1<<33-1 { + t.wall = t.wall&nsecMask | uint64(dsec)< t.ext) == (d > 0) { + t.ext = sum + } else if d > 0 { + t.ext = 1<<63 - 1 + } else { + t.ext = -(1<<63 - 1) + } +} + +// setLoc sets the location associated with the time. +func (t *Time) setLoc(loc *Location) { + if loc == &utcLoc { + loc = nil + } + t.stripMono() + t.loc = loc +} + +// stripMono strips the monotonic clock reading in t. +func (t *Time) stripMono() { + if t.wall&hasMonotonic != 0 { + t.ext = t.sec() + t.wall &= nsecMask + } +} + +// setMono sets the monotonic clock reading in t. +// If t cannot hold a monotonic clock reading, +// because its wall time is too large, +// setMono is a no-op. +func (t *Time) setMono(m int64) { + if t.wall&hasMonotonic == 0 { + sec := t.ext + if sec < minWall || maxWall < sec { + return + } + t.wall |= hasMonotonic | uint64(sec-minWall)< u.ext + } + ts := t.sec() + us := u.sec() + return ts > us || ts == us && t.nsec() > u.nsec() +} + +// Before reports whether the time instant t is before u. +func (t Time) Before(u Time) bool { + if t.wall&u.wall&hasMonotonic != 0 { + return t.ext < u.ext + } + ts := t.sec() + us := u.sec() + return ts < us || ts == us && t.nsec() < u.nsec() +} + +// Compare compares the time instant t with u. If t is before u, it returns -1; +// if t is after u, it returns +1; if they're the same, it returns 0. +func (t Time) Compare(u Time) int { + var tc, uc int64 + if t.wall&u.wall&hasMonotonic != 0 { + tc, uc = t.ext, u.ext + } else { + tc, uc = t.sec(), u.sec() + if tc == uc { + tc, uc = int64(t.nsec()), int64(u.nsec()) + } + } + switch { + case tc < uc: + return -1 + case tc > uc: + return +1 + } + return 0 +} + +// Equal reports whether t and u represent the same time instant. +// Two times can be equal even if they are in different locations. +// For example, 6:00 +0200 and 4:00 UTC are Equal. +// See the documentation on the Time type for the pitfalls of using == with +// Time values; most code should use Equal instead. +func (t Time) Equal(u Time) bool { + if t.wall&u.wall&hasMonotonic != 0 { + return t.ext == u.ext + } + return t.sec() == u.sec() && t.nsec() == u.nsec() +} + +// A Month specifies a month of the year (January = 1, ...). +type Month int + +const ( + January Month = 1 + iota + February + March + April + May + June + July + August + September + October + November + December +) + +// String returns the English name of the month ("January", "February", ...). +func (m Month) String() string { + if January <= m && m <= December { + return longMonthNames[m-1] + } + buf := make([]byte, 20) + n := fmtInt(buf, uint64(m)) + return "%!Month(" + string(buf[n:]) + ")" +} + +// A Weekday specifies a day of the week (Sunday = 0, ...). +type Weekday int + +const ( + Sunday Weekday = iota + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday +) + +// String returns the English name of the day ("Sunday", "Monday", ...). +func (d Weekday) String() string { + if Sunday <= d && d <= Saturday { + return longDayNames[d] + } + buf := make([]byte, 20) + n := fmtInt(buf, uint64(d)) + return "%!Weekday(" + string(buf[n:]) + ")" +} + +// Computations on time. +// +// The zero value for a Time is defined to be +// January 1, year 1, 00:00:00.000000000 UTC +// which (1) looks like a zero, or as close as you can get in a date +// (1-1-1 00:00:00 UTC), (2) is unlikely enough to arise in practice to +// be a suitable "not set" sentinel, unlike Jan 1 1970, and (3) has a +// non-negative year even in time zones west of UTC, unlike 1-1-0 +// 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York. +// +// The zero Time value does not force a specific epoch for the time +// representation. For example, to use the Unix epoch internally, we +// could define that to distinguish a zero value from Jan 1 1970, that +// time would be represented by sec=-1, nsec=1e9. However, it does +// suggest a representation, namely using 1-1-1 00:00:00 UTC as the +// epoch, and that's what we do. +// +// The Add and Sub computations are oblivious to the choice of epoch. +// +// The presentation computations - year, month, minute, and so on - all +// rely heavily on division and modulus by positive constants. For +// calendrical calculations we want these divisions to round down, even +// for negative values, so that the remainder is always positive, but +// Go's division (like most hardware division instructions) rounds to +// zero. We can still do those computations and then adjust the result +// for a negative numerator, but it's annoying to write the adjustment +// over and over. Instead, we can change to a different epoch so long +// ago that all the times we care about will be positive, and then round +// to zero and round down coincide. These presentation routines already +// have to add the zone offset, so adding the translation to the +// alternate epoch is cheap. For example, having a non-negative time t +// means that we can write +// +// sec = t % 60 +// +// instead of +// +// sec = t % 60 +// if sec < 0 { +// sec += 60 +// } +// +// everywhere. +// +// The calendar runs on an exact 400 year cycle: a 400-year calendar +// printed for 1970-2369 will apply as well to 2370-2769. Even the days +// of the week match up. It simplifies the computations to choose the +// cycle boundaries so that the exceptional years are always delayed as +// long as possible. That means choosing a year equal to 1 mod 400, so +// that the first leap year is the 4th year, the first missed leap year +// is the 100th year, and the missed missed leap year is the 400th year. +// So we'd prefer instead to print a calendar for 2001-2400 and reuse it +// for 2401-2800. +// +// Finally, it's convenient if the delta between the Unix epoch and +// long-ago epoch is representable by an int64 constant. +// +// These three considerations—choose an epoch as early as possible, that +// uses a year equal to 1 mod 400, and that is no more than 2⁶³ seconds +// earlier than 1970—bring us to the year -292277022399. We refer to +// this year as the absolute zero year, and to times measured as a uint64 +// seconds since this year as absolute times. +// +// Times measured as an int64 seconds since the year 1—the representation +// used for Time's sec field—are called internal times. +// +// Times measured as an int64 seconds since the year 1970 are called Unix +// times. +// +// It is tempting to just use the year 1 as the absolute epoch, defining +// that the routines are only valid for years >= 1. However, the +// routines would then be invalid when displaying the epoch in time zones +// west of UTC, since it is year 0. It doesn't seem tenable to say that +// printing the zero time correctly isn't supported in half the time +// zones. By comparison, it's reasonable to mishandle some times in +// the year -292277022399. +// +// All this is opaque to clients of the API and can be changed if a +// better implementation presents itself. + +const ( + // The unsigned zero year for internal calculations. + // Must be 1 mod 400, and times before it will not compute correctly, + // but otherwise can be changed at will. + absoluteZeroYear = -292277022399 + + // The year of the zero Time. + // Assumed by the unixToInternal computation below. + internalYear = 1 + + // Offsets to convert between internal and absolute or Unix times. + absoluteToInternal int64 = (absoluteZeroYear - internalYear) * 365.2425 * secondsPerDay + internalToAbsolute = -absoluteToInternal + + unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay + internalToUnix int64 = -unixToInternal + + wallToInternal int64 = (1884*365 + 1884/4 - 1884/100 + 1884/400) * secondsPerDay +) + +// IsZero reports whether t represents the zero time instant, +// January 1, year 1, 00:00:00 UTC. +func (t Time) IsZero() bool { + return t.sec() == 0 && t.nsec() == 0 +} + +// abs returns the time t as an absolute time, adjusted by the zone offset. +// It is called when computing a presentation property like Month or Hour. +func (t Time) abs() uint64 { + l := t.loc + // Avoid function calls when possible. + if l == nil || l == &localLoc { + l = l.get() + } + sec := t.unixSec() + if l != &utcLoc { + if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd { + sec += int64(l.cacheZone.offset) + } else { + _, offset, _, _, _ := l.lookup(sec) + sec += int64(offset) + } + } + return uint64(sec + (unixToInternal + internalToAbsolute)) +} + +// locabs is a combination of the Zone and abs methods, +// extracting both return values from a single zone lookup. +func (t Time) locabs() (name string, offset int, abs uint64) { + l := t.loc + if l == nil || l == &localLoc { + l = l.get() + } + // Avoid function call if we hit the local time cache. + sec := t.unixSec() + if l != &utcLoc { + if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd { + name = l.cacheZone.name + offset = l.cacheZone.offset + } else { + name, offset, _, _, _ = l.lookup(sec) + } + sec += int64(offset) + } else { + name = "UTC" + } + abs = uint64(sec + (unixToInternal + internalToAbsolute)) + return +} + +// Date returns the year, month, and day in which t occurs. +func (t Time) Date() (year int, month Month, day int) { + year, month, day, _ = t.date(true) + return +} + +// Year returns the year in which t occurs. +func (t Time) Year() int { + year, _, _, _ := t.date(false) + return year +} + +// Month returns the month of the year specified by t. +func (t Time) Month() Month { + _, month, _, _ := t.date(true) + return month +} + +// Day returns the day of the month specified by t. +func (t Time) Day() int { + _, _, day, _ := t.date(true) + return day +} + +// Weekday returns the day of the week specified by t. +func (t Time) Weekday() Weekday { + return absWeekday(t.abs()) +} + +// absWeekday is like Weekday but operates on an absolute time. +func absWeekday(abs uint64) Weekday { + // January 1 of the absolute year, like January 1 of 2001, was a Monday. + sec := (abs + uint64(Monday)*secondsPerDay) % secondsPerWeek + return Weekday(int(sec) / secondsPerDay) +} + +// ISOWeek returns the ISO 8601 year and week number in which t occurs. +// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to +// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1 +// of year n+1. +func (t Time) ISOWeek() (year, week int) { + // According to the rule that the first calendar week of a calendar year is + // the week including the first Thursday of that year, and that the last one is + // the week immediately preceding the first calendar week of the next calendar year. + // See https://www.iso.org/obp/ui#iso:std:iso:8601:-1:ed-1:v1:en:term:3.1.1.23 for details. + + // weeks start with Monday + // Monday Tuesday Wednesday Thursday Friday Saturday Sunday + // 1 2 3 4 5 6 7 + // +3 +2 +1 0 -1 -2 -3 + // the offset to Thursday + abs := t.abs() + d := Thursday - absWeekday(abs) + // handle Sunday + if d == 4 { + d = -3 + } + // find the Thursday of the calendar week + abs += uint64(d) * secondsPerDay + year, _, _, yday := absDate(abs, false) + return year, yday/7 + 1 +} + +// Clock returns the hour, minute, and second within the day specified by t. +func (t Time) Clock() (hour, min, sec int) { + return absClock(t.abs()) +} + +// absClock is like clock but operates on an absolute time. +// +// absClock should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname absClock +func absClock(abs uint64) (hour, min, sec int) { + sec = int(abs % secondsPerDay) + hour = sec / secondsPerHour + sec -= hour * secondsPerHour + min = sec / secondsPerMinute + sec -= min * secondsPerMinute + return +} + +// Hour returns the hour within the day specified by t, in the range [0, 23]. +func (t Time) Hour() int { + return int(t.abs()%secondsPerDay) / secondsPerHour +} + +// Minute returns the minute offset within the hour specified by t, in the range [0, 59]. +func (t Time) Minute() int { + return int(t.abs()%secondsPerHour) / secondsPerMinute +} + +// Second returns the second offset within the minute specified by t, in the range [0, 59]. +func (t Time) Second() int { + return int(t.abs() % secondsPerMinute) +} + +// Nanosecond returns the nanosecond offset within the second specified by t, +// in the range [0, 999999999]. +func (t Time) Nanosecond() int { + return int(t.nsec()) +} + +// YearDay returns the day of the year specified by t, in the range [1,365] for non-leap years, +// and [1,366] in leap years. +func (t Time) YearDay() int { + _, _, _, yday := t.date(false) + return yday + 1 +} + +// A Duration represents the elapsed time between two instants +// as an int64 nanosecond count. The representation limits the +// largest representable duration to approximately 290 years. +type Duration int64 + +const ( + minDuration Duration = -1 << 63 + maxDuration Duration = 1<<63 - 1 +) + +// Common durations. There is no definition for units of Day or larger +// to avoid confusion across daylight savings time zone transitions. +// +// To count the number of units in a [Duration], divide: +// +// second := time.Second +// fmt.Print(int64(second/time.Millisecond)) // prints 1000 +// +// To convert an integer number of units to a Duration, multiply: +// +// seconds := 10 +// fmt.Print(time.Duration(seconds)*time.Second) // prints 10s +const ( + Nanosecond Duration = 1 + Microsecond = 1000 * Nanosecond + Millisecond = 1000 * Microsecond + Second = 1000 * Millisecond + Minute = 60 * Second + Hour = 60 * Minute +) + +// String returns a string representing the duration in the form "72h3m0.5s". +// Leading zero units are omitted. As a special case, durations less than one +// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure +// that the leading digit is non-zero. The zero duration formats as 0s. +func (d Duration) String() string { + // This is inlinable to take advantage of "function outlining". + // Thus, the caller can decide whether a string must be heap allocated. + var arr [32]byte + n := d.format(&arr) + return string(arr[n:]) +} + +// format formats the representation of d into the end of buf and +// returns the offset of the first character. +func (d Duration) format(buf *[32]byte) int { + // Largest time is 2540400h10m10.000000000s + w := len(buf) + + u := uint64(d) + neg := d < 0 + if neg { + u = -u + } + + if u < uint64(Second) { + // Special case: if duration is smaller than a second, + // use smaller units, like 1.2ms + var prec int + w-- + buf[w] = 's' + w-- + switch { + case u == 0: + buf[w] = '0' + return w + case u < uint64(Microsecond): + // print nanoseconds + prec = 0 + buf[w] = 'n' + case u < uint64(Millisecond): + // print microseconds + prec = 3 + // U+00B5 'µ' micro sign == 0xC2 0xB5 + w-- // Need room for two bytes. + copy(buf[w:], "µ") + default: + // print milliseconds + prec = 6 + buf[w] = 'm' + } + w, u = fmtFrac(buf[:w], u, prec) + w = fmtInt(buf[:w], u) + } else { + w-- + buf[w] = 's' + + w, u = fmtFrac(buf[:w], u, 9) + + // u is now integer seconds + w = fmtInt(buf[:w], u%60) + u /= 60 + + // u is now integer minutes + if u > 0 { + w-- + buf[w] = 'm' + w = fmtInt(buf[:w], u%60) + u /= 60 + + // u is now integer hours + // Stop at hours because days can be different lengths. + if u > 0 { + w-- + buf[w] = 'h' + w = fmtInt(buf[:w], u) + } + } + } + + if neg { + w-- + buf[w] = '-' + } + + return w +} + +// fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the +// tail of buf, omitting trailing zeros. It omits the decimal +// point too when the fraction is 0. It returns the index where the +// output bytes begin and the value v/10**prec. +func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) { + // Omit trailing zeros up to and including decimal point. + w := len(buf) + print := false + for i := 0; i < prec; i++ { + digit := v % 10 + print = print || digit != 0 + if print { + w-- + buf[w] = byte(digit) + '0' + } + v /= 10 + } + if print { + w-- + buf[w] = '.' + } + return w, v +} + +// fmtInt formats v into the tail of buf. +// It returns the index where the output begins. +func fmtInt(buf []byte, v uint64) int { + w := len(buf) + if v == 0 { + w-- + buf[w] = '0' + } else { + for v > 0 { + w-- + buf[w] = byte(v%10) + '0' + v /= 10 + } + } + return w +} + +// Nanoseconds returns the duration as an integer nanosecond count. +func (d Duration) Nanoseconds() int64 { return int64(d) } + +// Microseconds returns the duration as an integer microsecond count. +func (d Duration) Microseconds() int64 { return int64(d) / 1e3 } + +// Milliseconds returns the duration as an integer millisecond count. +func (d Duration) Milliseconds() int64 { return int64(d) / 1e6 } + +// These methods return float64 because the dominant +// use case is for printing a floating point number like 1.5s, and +// a truncation to integer would make them not useful in those cases. +// Splitting the integer and fraction ourselves guarantees that +// converting the returned float64 to an integer rounds the same +// way that a pure integer conversion would have, even in cases +// where, say, float64(d.Nanoseconds())/1e9 would have rounded +// differently. + +// Seconds returns the duration as a floating point number of seconds. +func (d Duration) Seconds() float64 { + sec := d / Second + nsec := d % Second + return float64(sec) + float64(nsec)/1e9 +} + +// Minutes returns the duration as a floating point number of minutes. +func (d Duration) Minutes() float64 { + min := d / Minute + nsec := d % Minute + return float64(min) + float64(nsec)/(60*1e9) +} + +// Hours returns the duration as a floating point number of hours. +func (d Duration) Hours() float64 { + hour := d / Hour + nsec := d % Hour + return float64(hour) + float64(nsec)/(60*60*1e9) +} + +// Truncate returns the result of rounding d toward zero to a multiple of m. +// If m <= 0, Truncate returns d unchanged. +func (d Duration) Truncate(m Duration) Duration { + if m <= 0 { + return d + } + return d - d%m +} + +// lessThanHalf reports whether x+x < y but avoids overflow, +// assuming x and y are both positive (Duration is signed). +func lessThanHalf(x, y Duration) bool { + return uint64(x)+uint64(x) < uint64(y) +} + +// Round returns the result of rounding d to the nearest multiple of m. +// The rounding behavior for halfway values is to round away from zero. +// If the result exceeds the maximum (or minimum) +// value that can be stored in a [Duration], +// Round returns the maximum (or minimum) duration. +// If m <= 0, Round returns d unchanged. +func (d Duration) Round(m Duration) Duration { + if m <= 0 { + return d + } + r := d % m + if d < 0 { + r = -r + if lessThanHalf(r, m) { + return d + r + } + if d1 := d - m + r; d1 < d { + return d1 + } + return minDuration // overflow + } + if lessThanHalf(r, m) { + return d - r + } + if d1 := d + m - r; d1 > d { + return d1 + } + return maxDuration // overflow +} + +// Abs returns the absolute value of d. +// As a special case, [math.MinInt64] is converted to [math.MaxInt64]. +func (d Duration) Abs() Duration { + switch { + case d >= 0: + return d + case d == minDuration: + return maxDuration + default: + return -d + } +} + +// Add returns the time t+d. +func (t Time) Add(d Duration) Time { + dsec := int64(d / 1e9) + nsec := t.nsec() + int32(d%1e9) + if nsec >= 1e9 { + dsec++ + nsec -= 1e9 + } else if nsec < 0 { + dsec-- + nsec += 1e9 + } + t.wall = t.wall&^nsecMask | uint64(nsec) // update nsec + t.addSec(dsec) + if t.wall&hasMonotonic != 0 { + te := t.ext + int64(d) + if d < 0 && te > t.ext || d > 0 && te < t.ext { + // Monotonic clock reading now out of range; degrade to wall-only. + t.stripMono() + } else { + t.ext = te + } + } + return t +} + +// Sub returns the duration t-u. If the result exceeds the maximum (or minimum) +// value that can be stored in a [Duration], the maximum (or minimum) duration +// will be returned. +// To compute t-d for a duration d, use t.Add(-d). +func (t Time) Sub(u Time) Duration { + if t.wall&u.wall&hasMonotonic != 0 { + return subMono(t.ext, u.ext) + } + d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec()) + // Check for overflow or underflow. + switch { + case u.Add(d).Equal(t): + return d // d is correct + case t.Before(u): + return minDuration // t - u is negative out of range + default: + return maxDuration // t - u is positive out of range + } +} + +func subMono(t, u int64) Duration { + d := Duration(t - u) + if d < 0 && t > u { + return maxDuration // t - u is positive out of range + } + if d > 0 && t < u { + return minDuration // t - u is negative out of range + } + return d +} + +// Since returns the time elapsed since t. +// It is shorthand for time.Now().Sub(t). +func Since(t Time) Duration { + if t.wall&hasMonotonic != 0 { + // Common case optimization: if t has monotonic time, then Sub will use only it. + return subMono(runtimeNano()-startNano, t.ext) + } + return Now().Sub(t) +} + +// Until returns the duration until t. +// It is shorthand for t.Sub(time.Now()). +func Until(t Time) Duration { + if t.wall&hasMonotonic != 0 { + // Common case optimization: if t has monotonic time, then Sub will use only it. + return subMono(t.ext, runtimeNano()-startNano) + } + return t.Sub(Now()) +} + +// AddDate returns the time corresponding to adding the +// given number of years, months, and days to t. +// For example, AddDate(-1, 2, 3) applied to January 1, 2011 +// returns March 4, 2010. +// +// Note that dates are fundamentally coupled to timezones, and calendrical +// periods like days don't have fixed durations. AddDate uses the Location of +// the Time value to determine these durations. That means that the same +// AddDate arguments can produce a different shift in absolute time depending on +// the base Time value and its Location. For example, AddDate(0, 0, 1) applied +// to 12:00 on March 27 always returns 12:00 on March 28. At some locations and +// in some years this is a 24 hour shift. In others it's a 23 hour shift due to +// daylight savings time transitions. +// +// AddDate normalizes its result in the same way that Date does, +// so, for example, adding one month to October 31 yields +// December 1, the normalized form for November 31. +func (t Time) AddDate(years int, months int, days int) Time { + year, month, day := t.Date() + hour, min, sec := t.Clock() + return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec()), t.Location()) +} + +const ( + secondsPerMinute = 60 + secondsPerHour = 60 * secondsPerMinute + secondsPerDay = 24 * secondsPerHour + secondsPerWeek = 7 * secondsPerDay + daysPer400Years = 365*400 + 97 + daysPer100Years = 365*100 + 24 + daysPer4Years = 365*4 + 1 +) + +// date computes the year, day of year, and when full=true, +// the month and day in which t occurs. +func (t Time) date(full bool) (year int, month Month, day int, yday int) { + return absDate(t.abs(), full) +} + +// absDate is like date but operates on an absolute time. +// +// absDate should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// - gitee.com/quant1x/gox +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname absDate +func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) { + // Split into time and day. + d := abs / secondsPerDay + + // Account for 400 year cycles. + n := d / daysPer400Years + y := 400 * n + d -= daysPer400Years * n + + // Cut off 100-year cycles. + // The last cycle has one extra leap year, so on the last day + // of that year, day / daysPer100Years will be 4 instead of 3. + // Cut it back down to 3 by subtracting n>>2. + n = d / daysPer100Years + n -= n >> 2 + y += 100 * n + d -= daysPer100Years * n + + // Cut off 4-year cycles. + // The last cycle has a missing leap year, which does not + // affect the computation. + n = d / daysPer4Years + y += 4 * n + d -= daysPer4Years * n + + // Cut off years within a 4-year cycle. + // The last year is a leap year, so on the last day of that year, + // day / 365 will be 4 instead of 3. Cut it back down to 3 + // by subtracting n>>2. + n = d / 365 + n -= n >> 2 + y += n + d -= 365 * n + + year = int(int64(y) + absoluteZeroYear) + yday = int(d) + + if !full { + return + } + + day = yday + if isLeap(year) { + // Leap year + switch { + case day > 31+29-1: + // After leap day; pretend it wasn't there. + day-- + case day == 31+29-1: + // Leap day. + month = February + day = 29 + return + } + } + + // Estimate month on assumption that every month has 31 days. + // The estimate may be too low by at most one month, so adjust. + month = Month(day / 31) + end := int(daysBefore[month+1]) + var begin int + if day >= end { + month++ + begin = end + } else { + begin = int(daysBefore[month]) + } + + month++ // because January is 1 + day = day - begin + 1 + return +} + +// daysBefore[m] counts the number of days in a non-leap year +// before month m begins. There is an entry for m=12, counting +// the number of days before January of next year (365). +var daysBefore = [...]int32{ + 0, + 31, + 31 + 28, + 31 + 28 + 31, + 31 + 28 + 31 + 30, + 31 + 28 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, +} + +func daysIn(m Month, year int) int { + if m == February && isLeap(year) { + return 29 + } + return int(daysBefore[m] - daysBefore[m-1]) +} + +// daysSinceEpoch takes a year and returns the number of days from +// the absolute epoch to the start of that year. +// This is basically (year - zeroYear) * 365, but accounting for leap days. +func daysSinceEpoch(year int) uint64 { + y := uint64(int64(year) - absoluteZeroYear) + + // Add in days from 400-year cycles. + n := y / 400 + y -= 400 * n + d := daysPer400Years * n + + // Add in 100-year cycles. + n = y / 100 + y -= 100 * n + d += daysPer100Years * n + + // Add in 4-year cycles. + n = y / 4 + y -= 4 * n + d += daysPer4Years * n + + // Add in non-leap years. + n = y + d += 365 * n + + return d +} + +// Provided by package runtime. +func now() (sec int64, nsec int32, mono int64) + +// runtimeNano returns the current value of the runtime clock in nanoseconds. +// +//go:linkname runtimeNano runtime.nanotime +func runtimeNano() int64 + +// Monotonic times are reported as offsets from startNano. +// We initialize startNano to runtimeNano() - 1 so that on systems where +// monotonic time resolution is fairly low (e.g. Windows 2008 +// which appears to have a default resolution of 15ms), +// we avoid ever reporting a monotonic time of 0. +// (Callers may want to use 0 as "time not set".) +var startNano int64 = runtimeNano() - 1 + +// x/tools uses a linkname of time.Now in its tests. No harm done. +//go:linkname Now + +// Now returns the current local time. +func Now() Time { + sec, nsec, mono := now() + mono -= startNano + sec += unixToInternal - minWall + if uint64(sec)>>33 != 0 { + // Seconds field overflowed the 33 bits available when + // storing a monotonic time. This will be true after + // March 16, 2157. + return Time{uint64(nsec), sec + minWall, Local} + } + return Time{hasMonotonic | uint64(sec)< 32767 { + return nil, errors.New("Time.MarshalBinary: unexpected zone offset") + } + offsetMin = int16(offset) + } + + sec := t.sec() + nsec := t.nsec() + enc := []byte{ + version, // byte 0 : version + byte(sec >> 56), // bytes 1-8: seconds + byte(sec >> 48), + byte(sec >> 40), + byte(sec >> 32), + byte(sec >> 24), + byte(sec >> 16), + byte(sec >> 8), + byte(sec), + byte(nsec >> 24), // bytes 9-12: nanoseconds + byte(nsec >> 16), + byte(nsec >> 8), + byte(nsec), + byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes + byte(offsetMin), + } + if version == timeBinaryVersionV2 { + enc = append(enc, byte(offsetSec)) + } + + return enc, nil +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +func (t *Time) UnmarshalBinary(data []byte) error { + buf := data + if len(buf) == 0 { + return errors.New("Time.UnmarshalBinary: no data") + } + + version := buf[0] + if version != timeBinaryVersionV1 && version != timeBinaryVersionV2 { + return errors.New("Time.UnmarshalBinary: unsupported version") + } + + wantLen := /*version*/ 1 + /*sec*/ 8 + /*nsec*/ 4 + /*zone offset*/ 2 + if version == timeBinaryVersionV2 { + wantLen++ + } + if len(buf) != wantLen { + return errors.New("Time.UnmarshalBinary: invalid length") + } + + buf = buf[1:] + sec := int64(buf[7]) | int64(buf[6])<<8 | int64(buf[5])<<16 | int64(buf[4])<<24 | + int64(buf[3])<<32 | int64(buf[2])<<40 | int64(buf[1])<<48 | int64(buf[0])<<56 + + buf = buf[8:] + nsec := int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24 + + buf = buf[4:] + offset := int(int16(buf[1])|int16(buf[0])<<8) * 60 + if version == timeBinaryVersionV2 { + offset += int(buf[2]) + } + + *t = Time{} + t.wall = uint64(nsec) + t.ext = sec + + if offset == -1*60 { + t.setLoc(&utcLoc) + } else if _, localoff, _, _, _ := Local.lookup(t.unixSec()); offset == localoff { + t.setLoc(Local) + } else { + t.setLoc(FixedZone("", offset)) + } + + return nil +} + +// TODO(rsc): Remove GobEncoder, GobDecoder, MarshalJSON, UnmarshalJSON in Go 2. +// The same semantics will be provided by the generic MarshalBinary, MarshalText, +// UnmarshalBinary, UnmarshalText. + +// GobEncode implements the gob.GobEncoder interface. +func (t Time) GobEncode() ([]byte, error) { + return t.MarshalBinary() +} + +// GobDecode implements the gob.GobDecoder interface. +func (t *Time) GobDecode(data []byte) error { + return t.UnmarshalBinary(data) +} + +// MarshalJSON implements the [json.Marshaler] interface. +// The time is a quoted string in the RFC 3339 format with sub-second precision. +// If the timestamp cannot be represented as valid RFC 3339 +// (e.g., the year is out of range), then an error is reported. +func (t Time) MarshalJSON() ([]byte, error) { + b := make([]byte, 0, len(RFC3339Nano)+len(`""`)) + b = append(b, '"') + b, err := t.appendStrictRFC3339(b) + b = append(b, '"') + if err != nil { + return nil, errors.New("Time.MarshalJSON: " + err.Error()) + } + return b, nil +} + +// UnmarshalJSON implements the [json.Unmarshaler] interface. +// The time must be a quoted string in the RFC 3339 format. +func (t *Time) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + return nil + } + // TODO(https://go.dev/issue/47353): Properly unescape a JSON string. + if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' { + return errors.New("Time.UnmarshalJSON: input is not a JSON string") + } + data = data[len(`"`) : len(data)-len(`"`)] + var err error + *t, err = parseStrictRFC3339(data) + return err +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +// The time is formatted in RFC 3339 format with sub-second precision. +// If the timestamp cannot be represented as valid RFC 3339 +// (e.g., the year is out of range), then an error is reported. +func (t Time) MarshalText() ([]byte, error) { + b := make([]byte, 0, len(RFC3339Nano)) + b, err := t.appendStrictRFC3339(b) + if err != nil { + return nil, errors.New("Time.MarshalText: " + err.Error()) + } + return b, nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +// The time must be in the RFC 3339 format. +func (t *Time) UnmarshalText(data []byte) error { + var err error + *t, err = parseStrictRFC3339(data) + return err +} + +// Unix returns the local Time corresponding to the given Unix time, +// sec seconds and nsec nanoseconds since January 1, 1970 UTC. +// It is valid to pass nsec outside the range [0, 999999999]. +// Not all sec values have a corresponding time value. One such +// value is 1<<63-1 (the largest int64 value). +func Unix(sec int64, nsec int64) Time { + if nsec < 0 || nsec >= 1e9 { + n := nsec / 1e9 + sec += n + nsec -= n * 1e9 + if nsec < 0 { + nsec += 1e9 + sec-- + } + } + return unixTime(sec, int32(nsec)) +} + +// UnixMilli returns the local Time corresponding to the given Unix time, +// msec milliseconds since January 1, 1970 UTC. +func UnixMilli(msec int64) Time { + return Unix(msec/1e3, (msec%1e3)*1e6) +} + +// UnixMicro returns the local Time corresponding to the given Unix time, +// usec microseconds since January 1, 1970 UTC. +func UnixMicro(usec int64) Time { + return Unix(usec/1e6, (usec%1e6)*1e3) +} + +// IsDST reports whether the time in the configured location is in Daylight Savings Time. +func (t Time) IsDST() bool { + _, _, _, _, isDST := t.loc.lookup(t.Unix()) + return isDST +} + +func isLeap(year int) bool { + return year%4 == 0 && (year%100 != 0 || year%400 == 0) +} + +// norm returns nhi, nlo such that +// +// hi * base + lo == nhi * base + nlo +// 0 <= nlo < base +func norm(hi, lo, base int) (nhi, nlo int) { + if lo < 0 { + n := (-lo-1)/base + 1 + hi -= n + lo += n * base + } + if lo >= base { + n := lo / base + hi += n + lo -= n * base + } + return hi, lo +} + +// Date returns the Time corresponding to +// +// yyyy-mm-dd hh:mm:ss + nsec nanoseconds +// +// in the appropriate zone for that time in the given location. +// +// The month, day, hour, min, sec, and nsec values may be outside +// their usual ranges and will be normalized during the conversion. +// For example, October 32 converts to November 1. +// +// A daylight savings time transition skips or repeats times. +// For example, in the United States, March 13, 2011 2:15am never occurred, +// while November 6, 2011 1:15am occurred twice. In such cases, the +// choice of time zone, and therefore the time, is not well-defined. +// Date returns a time that is correct in one of the two zones involved +// in the transition, but it does not guarantee which. +// +// Date panics if loc is nil. +func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time { + if loc == nil { + panic("time: missing Location in call to Date") + } + + // Normalize month, overflowing into year. + m := int(month) - 1 + year, m = norm(year, m, 12) + month = Month(m) + 1 + + // Normalize nsec, sec, min, hour, overflowing into day. + sec, nsec = norm(sec, nsec, 1e9) + min, sec = norm(min, sec, 60) + hour, min = norm(hour, min, 60) + day, hour = norm(day, hour, 24) + + // Compute days since the absolute epoch. + d := daysSinceEpoch(year) + + // Add in days before this month. + d += uint64(daysBefore[month-1]) + if isLeap(year) && month >= March { + d++ // February 29 + } + + // Add in days before today. + d += uint64(day - 1) + + // Add in time elapsed today. + abs := d * secondsPerDay + abs += uint64(hour*secondsPerHour + min*secondsPerMinute + sec) + + unix := int64(abs) + (absoluteToInternal + internalToUnix) + + // Look for zone offset for expected time, so we can adjust to UTC. + // The lookup function expects UTC, so first we pass unix in the + // hope that it will not be too close to a zone transition, + // and then adjust if it is. + _, offset, start, end, _ := loc.lookup(unix) + if offset != 0 { + utc := unix - int64(offset) + // If utc is valid for the time zone we found, then we have the right offset. + // If not, we get the correct offset by looking up utc in the location. + if utc < start || utc >= end { + _, offset, _, _, _ = loc.lookup(utc) + } + unix -= int64(offset) + } + + t := unixTime(unix, int32(nsec)) + t.setLoc(loc) + return t +} + +// Truncate returns the result of rounding t down to a multiple of d (since the zero time). +// If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged. +// +// Truncate operates on the time as an absolute duration since the +// zero time; it does not operate on the presentation form of the +// time. Thus, Truncate(Hour) may return a time with a non-zero +// minute, depending on the time's Location. +func (t Time) Truncate(d Duration) Time { + t.stripMono() + if d <= 0 { + return t + } + _, r := div(t, d) + return t.Add(-r) +} + +// Round returns the result of rounding t to the nearest multiple of d (since the zero time). +// The rounding behavior for halfway values is to round up. +// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged. +// +// Round operates on the time as an absolute duration since the +// zero time; it does not operate on the presentation form of the +// time. Thus, Round(Hour) may return a time with a non-zero +// minute, depending on the time's Location. +func (t Time) Round(d Duration) Time { + t.stripMono() + if d <= 0 { + return t + } + _, r := div(t, d) + if lessThanHalf(r, d) { + return t.Add(-r) + } + return t.Add(d - r) +} + +// div divides t by d and returns the quotient parity and remainder. +// We don't use the quotient parity anymore (round half up instead of round to even) +// but it's still here in case we change our minds. +func div(t Time, d Duration) (qmod2 int, r Duration) { + neg := false + nsec := t.nsec() + sec := t.sec() + if sec < 0 { + // Operate on absolute value. + neg = true + sec = -sec + nsec = -nsec + if nsec < 0 { + nsec += 1e9 + sec-- // sec >= 1 before the -- so safe + } + } + + switch { + // Special case: 2d divides 1 second. + case d < Second && Second%(d+d) == 0: + qmod2 = int(nsec/int32(d)) & 1 + r = Duration(nsec % int32(d)) + + // Special case: d is a multiple of 1 second. + case d%Second == 0: + d1 := int64(d / Second) + qmod2 = int(sec/d1) & 1 + r = Duration(sec%d1)*Second + Duration(nsec) + + // General case. + // This could be faster if more cleverness were applied, + // but it's really only here to avoid special case restrictions in the API. + // No one will care about these cases. + default: + // Compute nanoseconds as 128-bit number. + sec := uint64(sec) + tmp := (sec >> 32) * 1e9 + u1 := tmp >> 32 + u0 := tmp << 32 + tmp = (sec & 0xFFFFFFFF) * 1e9 + u0x, u0 := u0, u0+tmp + if u0 < u0x { + u1++ + } + u0x, u0 = u0, u0+uint64(nsec) + if u0 < u0x { + u1++ + } + + // Compute remainder by subtracting r<>63 != 1 { + d1 <<= 1 + } + d0 := uint64(0) + for { + qmod2 = 0 + if u1 > d1 || u1 == d1 && u0 >= d0 { + // subtract + qmod2 = 1 + u0x, u0 = u0, u0-d0 + if u0 > u0x { + u1-- + } + u1 -= d1 + } + if d1 == 0 && d0 == uint64(d) { + break + } + d0 >>= 1 + d0 |= (d1 & 1) << 63 + d1 >>= 1 + } + r = Duration(u0) + } + + if neg && r != 0 { + // If input was negative and not an exact multiple of d, we computed q, r such that + // q*d + r = -t + // But the right answers are given by -(q-1), d-r: + // q*d + r = -t + // -q*d - r = t + // -(q-1)*d + (d - r) = t + qmod2 ^= 1 + r = d - r + } + return +} diff --git a/contrib/go/_std_1.22/src/time/tzdata/tzdata.go b/contrib/go/_std_1.23/src/time/tzdata/tzdata.go similarity index 100% rename from contrib/go/_std_1.22/src/time/tzdata/tzdata.go rename to contrib/go/_std_1.23/src/time/tzdata/tzdata.go diff --git a/contrib/go/_std_1.22/src/time/tzdata/ya.make b/contrib/go/_std_1.23/src/time/tzdata/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/time/tzdata/ya.make rename to contrib/go/_std_1.23/src/time/tzdata/ya.make diff --git a/contrib/go/_std_1.22/src/time/tzdata/zzipdata.go b/contrib/go/_std_1.23/src/time/tzdata/zzipdata.go similarity index 99% rename from contrib/go/_std_1.22/src/time/tzdata/zzipdata.go rename to contrib/go/_std_1.23/src/time/tzdata/zzipdata.go index 43275ebae317..f13a3488f695 100644 --- a/contrib/go/_std_1.22/src/time/tzdata/zzipdata.go +++ b/contrib/go/_std_1.23/src/time/tzdata/zzipdata.go @@ -1,3 +1,5 @@ +// Code generated by go tool dist; DO NOT EDIT. + package tzdata const zipdata = "PK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0e\x00\x00\x00Africa/AbidjanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0c\x00\x00\x00Africa/AccraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x12\x00\x00\x00Africa/Addis_AbabaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\x8a\x0e\xc0\xd6\x01\x00\x00\xd6\x01\x00\x00\x0e\x00\x00\x00Africa/AlgiersTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xffk\xc9\x9b$\xff\xff\xff\xff\x91`PO\xff\xff\xff\xff\x9bGx\xf0\xff\xff\xff\xff\x9b\xd7,p\xff\xff\xff\xff\x9c\xbc\x91p\xff\xff\xff\xff\x9d\xc0H\xf0\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0*\xf0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1\x80\x0c\xf0\xff\xff\xff\xff\xa2.\x12\xf0\xff\xff\xff\xff\xa3zL\xf0\xff\xff\xff\xff\xa45\x81\xf0\xff\xff\xff\xff\xa4\xb8\x06p\xff\xff\xff\xff\xc6\xff\x06p\xff\xff\xff\xff\xc7X\xba\x80\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x8a\x00\x00\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N$p\xff\xff\xff\xff\xd4K\x07p\xff\xff\xff\xff\xe5\xce\xd3\x00\xff\xff\xff\xff\xf3\x5c\xb0\xf0\x00\x00\x00\x00\x02x\xc1\xf0\x00\x00\x00\x00\x03C\xc8\xf0\x00\x00\x00\x00\x0d\xcf\xd7\x00\x00\x00\x00\x00\x0e\xadD\xf0\x00\x00\x00\x00\x0fxZ\x00\x00\x00\x00\x00\x10hY\x10\x00\x00\x00\x00\x12vCp\x00\x00\x00\x00\x13fB\x80\x00\x00\x00\x00\x14_|\x10\x00\x00\x00\x00\x15O_\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x03\x05\x03\x02\x03\x02\x05\x04\x05\x03\x02\x03\x05\x00\x00\x02\xdc\x00\x00\x00\x00\x021\x00\x04\x00\x00\x0e\x10\x01\x08\x00\x00\x00\x00\x00\x0d\x00\x00\x1c \x01\x11\x00\x00\x0e\x10\x00\x16LMT\x00PMT\x00WEST\x00WET\x00CEST\x00CET\x00\x0aCET-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0d\x00\x00\x00Africa/AsmaraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0d\x00\x00\x00Africa/AsmeraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0d\x00\x00\x00Africa/BamakoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00Africa/BanguiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0d\x00\x00\x00Africa/BanjulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca>\xd5\xe0\x95\x00\x00\x00\x95\x00\x00\x00\x0d\x00\x00\x00Africa/BissauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x92\xe6\x9c\x90\x00\x00\x00\x00\x09ga\x10\x01\x02\xff\xff\xf1d\x00\x00\xff\xff\xf1\xf0\x00\x04\x00\x00\x00\x00\x00\x08LMT\x00-01\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0f\x00\x00\x00Africa/BlantyreTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x12\x00\x00\x00Africa/BrazzavilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x10\x00\x00\x00Africa/BujumburaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5#)\x16\x1d\x05\x00\x00\x1d\x05\x00\x00\x0c\x00\x00\x00Africa/CairoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff}\xbdM\xab\xff\xff\xff\xff\xc8\x93\xb4\xe0\xff\xff\xff\xff\xc8\xfa{\xd0\xff\xff\xff\xff\xc9\xfc\xef\xe0\xff\xff\xff\xff\xca\xc7\xe8\xd0\xff\xff\xff\xff\xcb\xcb\xae`\xff\xff\xff\xff\xcc\xdf)\xd0\xff\xff\xff\xff\xcd\xac\xe1\xe0\xff\xff\xff\xff\xce\xc6\xf4\xd0\xff\xff\xff\xff\xcf\x8ff\xe0\xff\xff\xff\xff\xd0\xa9y\xd0\xff\xff\xff\xff\xd1\x84`\xe0\xff\xff\xff\xff\xd2\x8a\xadP\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\x7f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xff\xef\xb0\xb3p\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb\xc2\xfd\x80\xff\xff\xff\xff\xfc\xdb\xbe\xf0\xff\xff\xff\xff\xfd\xa5\x82\x80\xff\xff\xff\xff\xfe\xbc\xf2p\xff\xff\xff\xff\xff\x86\xb6\x00\x00\x00\x00\x00\x00\x9e%\xf0\x00\x00\x00\x00\x01g\xe9\x80\x00\x00\x00\x00\x02\x7fYp\x00\x00\x00\x00\x03I\x1d\x00\x00\x00\x00\x00\x04a\xdep\x00\x00\x00\x00\x05+\xa2\x00\x00\x00\x00\x00\x06C\x11\xf0\x00\x00\x00\x00\x07\x0c\xd5\x80\x00\x00\x00\x00\x08$Ep\x00\x00\x00\x00\x08\xee\x09\x00\x00\x00\x00\x00\x0a\x05x\xf0\x00\x00\x00\x00\x0a\xcf<\x80\x00\x00\x00\x00\x0b\xe7\xfd\xf0\x00\x00\x00\x00\x0c\xb1\xc1\x80\x00\x00\x00\x00\x0d\xc91p\x00\x00\x00\x00\x0e\x92\xf5\x00\x00\x00\x00\x00\x0f\xaad\xf0\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11\x8b\x98p\x00\x00\x00\x00\x12U\x5c\x00\x00\x00\x00\x00\x13n\x1dp\x00\x00\x00\x00\x147\xe1\x00\x00\x00\x00\x00\x15OP\xf0\x00\x00\x00\x00\x16\x19\x14\x80\x00\x00\x00\x00\x17\xa0\x93\xf0\x00\x00\x00\x00\x17\xfaH\x00\x00\x00\x00\x00\x19p\xa3\xf0\x00\x00\x00\x00\x19\xdb{\x80\x00\x00\x00\x00\x1a\xf4<\xf0\x00\x00\x00\x00\x1b\xbe\x00\x80\x00\x00\x00\x00\x1c\xd5pp\x00\x00\x00\x00\x1d\x9f4\x00\x00\x00\x00\x00\x1e\xb6\xa3\xf0\x00\x00\x00\x00\x1f\x80g\x80\x00\x00\x00\x00 \x97\xd7p\x00\x00\x00\x00!a\x9b\x00\x00\x00\x00\x00\x22z\x5cp\x00\x00\x00\x00#D \x00\x00\x00\x00\x00$b'p\x00\x00\x00\x00%%S\x80\x00\x00\x00\x00&<\xc3p\x00\x00\x00\x00'\x06\x87\x00\x00\x00\x00\x00(\x1d\xf6\xf0\x00\x00\x00\x00(\xe7\xba\x80\x00\x00\x00\x00*\x00{\xf0\x00\x00\x00\x00*\xca?\x80\x00\x00\x00\x00+\xe1\xafp\x00\x00\x00\x00,\xabs\x00\x00\x00\x00\x00-\xc2\xe2\xf0\x00\x00\x00\x00.\x8c\xa6\x80\x00\x00\x00\x00/\xa0\x13\xe0\x00\x00\x00\x000k\x0c\xd0\x00\x00\x00\x001\x7f\xf5\xe0\x00\x00\x00\x002J\xee\xd0\x00\x00\x00\x003_\xd7\xe0\x00\x00\x00\x004*\xd0\xd0\x00\x00\x00\x005?\xb9\xe0\x00\x00\x00\x006\x0a\xb2\xd0\x00\x00\x00\x007(\xd6`\x00\x00\x00\x007\xf3\xcfP\x00\x00\x00\x009\x08\xb8`\x00\x00\x00\x009\xd3\xb1P\x00\x00\x00\x00:\xe8\x9a`\x00\x00\x00\x00;\xb3\x93P\x00\x00\x00\x00<\xc8|`\x00\x00\x00\x00=\x93uP\x00\x00\x00\x00>\xa8^`\x00\x00\x00\x00?sWP\x00\x00\x00\x00@\x91z\xe0\x00\x00\x00\x00A\x5cs\xd0\x00\x00\x00\x00Bq\x5c\xe0\x00\x00\x00\x00C\xe0\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F1 \xe0\x00\x00\x00\x00F\xe0jP\x00\x00\x00\x00H\x11\x02\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xf0\xe4\xe0\x00\x00\x00\x00J\x8d\xb9P\x00\x00\x00\x00K\xda\x01`\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00L\x89X\xe0\x00\x00\x00\x00L\xa4\xfaP\x00\x00\x00\x00Su8\xe0\x00\x00\x00\x00S\xac\x89\xd0\x00\x00\x00\x00S\xda\xbc`\x00\x00\x00\x00T$\x82P\x00\x00\x00\x00dJ\xf0`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x1dU\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M4.5.5/0,M10.5.4/24\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001B\xb0;\x7f\x07\x00\x00\x7f\x07\x00\x00\x11\x00\x00\x00Africa/CasablancaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x00\x00\x00\x05\x00\x00\x00\x0c\xff\xff\xff\xff\x96Q\xf9\x9c\xff\xff\xff\xff\xc6\xff\x14\x80\xff\xff\xff\xff\xc7X\xacp\xff\xff\xff\xff\xc7\xd9\xed\x80\xff\xff\xff\xff\xd2\xa12\xf0\xff\xff\xff\xff\xdb5\xa4\x00\xff\xff\xff\xff\xdb\xee'\xf0\xff\xff\xff\xff\xfb%r@\xff\xff\xff\xff\xfb\xc2\xefp\x00\x00\x00\x00\x08k\x84\x80\x00\x00\x00\x00\x08\xc6m\xf0\x00\x00\x00\x00\x0b\xe8\x0c\x00\x00\x00\x00\x00\x0caG\xf0\x00\x00\x00\x00\x0d\xc9?\x80\x00\x00\x00\x00\x0e\x8e\xf2p\x00\x00\x00\x00\x0f\xd3Q\x80\x00\x00\x00\x00\x10'\xa3p\x00\x00\x00\x00\x1a\xb7\xa6\x00\x00\x00\x00\x00\x1e\x18o\xf0\x00\x00\x00\x00HA\xe6\x80\x00\x00\x00\x00H\xbb\x22p\x00\x00\x00\x00J#\x1a\x00\x00\x00\x00\x00J\x8d\xd5p\x00\x00\x00\x00K\xdc\xc0\x80\x00\x00\x00\x00L]\xe5p\x00\x00\x00\x00M\x97\xb8\x80\x00\x00\x00\x00N4\x8c\xf0\x00\x00\x00\x00O\x9c\xa0\xa0\x00\x00\x00\x00P\x08\xbb\xa0\x00\x00\x00\x00P1\x9a \x00\x00\x00\x00Pg\xa7\xa0\x00\x00\x00\x00Q|\x82\xa0\x00\x00\x00\x00Q\xd8\xcb\xa0\x00\x00\x00\x00R\x05\x9e\xa0\x00\x00\x00\x00Rls\xa0\x00\x00\x00\x00S7z\xa0\x00\x00\x00\x00S\xae!\xa0\x00\x00\x00\x00S\xdcF \x00\x00\x00\x00TLU\xa0\x00\x00\x00\x00U\x17\x5c\xa0\x00\x00\x00\x00U|\xe0 \x00\x00\x00\x00U\xab\x04\xa0\x00\x00\x00\x00V,7\xa0\x00\x00\x00\x00V\xf7>\xa0\x00\x00\x00\x00WS\x87\xa0\x00\x00\x00\x00W\x81\xac \x00\x00\x00\x00X\x15T \x00\x00\x00\x00X\xd7 \xa0\x00\x00\x00\x00Y \xf4\xa0\x00\x00\x00\x00YXS\xa0\x00\x00\x00\x00Y\xf56 \x00\x00\x00\x00Z\xb7\x02\xa0\x00\x00\x00\x00Z\xf7\x9c \x00\x00\x00\x00[%\xc0\xa0\x00\x00\x00\x00[\xd5\x18 \x00\x00\x00\x00\x5c\xceC\xa0\x00\x00\x00\x00\x5c\xfch \x00\x00\x00\x00^\x9b\xb0\xa0\x00\x00\x00\x00^\xd3\x0f\xa0\x00\x00\x00\x00`rX \x00\x00\x00\x00`\xa0|\xa0\x00\x00\x00\x00b?\xc5 \x00\x00\x00\x00bw$ \x00\x00\x00\x00d\x16l\xa0\x00\x00\x00\x00dD\x91 \x00\x00\x00\x00e\xed\x14 \x00\x00\x00\x00f\x1b8\xa0\x00\x00\x00\x00g\xba\x81 \x00\x00\x00\x00g\xf1\xe0 \x00\x00\x00\x00i\x91(\xa0\x00\x00\x00\x00i\xbfM \x00\x00\x00\x00kg\xd0 \x00\x00\x00\x00k\x95\xf4\xa0\x00\x00\x00\x00m5= \x00\x00\x00\x00ml\x9c \x00\x00\x00\x00o\x0b\xe4\xa0\x00\x00\x00\x00o:\x09 \x00\x00\x00\x00p\xd9Q\xa0\x00\x00\x00\x00q\x10\xb0\xa0\x00\x00\x00\x00r\xaf\xf9 \x00\x00\x00\x00r\xde\x1d\xa0\x00\x00\x00\x00t\x86\xa0\xa0\x00\x00\x00\x00t\xb4\xc5 \x00\x00\x00\x00vT\x0d\xa0\x00\x00\x00\x00v\x8bl\xa0\x00\x00\x00\x00x*\xb5 \x00\x00\x00\x00xX\xd9\xa0\x00\x00\x00\x00y\xf8\x22 \x00\x00\x00\x00z/\x81 \x00\x00\x00\x00{\xce\xc9\xa0\x00\x00\x00\x00|\x06(\xa0\x00\x00\x00\x00}\xa5q \x00\x00\x00\x00}\xd3\x95\xa0\x00\x00\x00\x00\x7fr\xde \x00\x00\x00\x00\x7f\xaa= \x00\x00\x00\x00\x81I\x85\xa0\x00\x00\x00\x00\x81w\xaa \x00\x00\x00\x00\x83 - \x00\x00\x00\x00\x83NQ\xa0\x00\x00\x00\x00\x84\xed\x9a \x00\x00\x00\x00\x85$\xf9 \x00\x00\x00\x00\x86\xc4A\xa0\x00\x00\x00\x00\x86\xf2f \x00\x00\x00\x00\x88\x91\xae\xa0\x00\x00\x00\x00\x88\xc9\x0d\xa0\x00\x00\x00\x00\x8ahV \x00\x00\x00\x00\x8a\x9f\xb5 \x00\x00\x00\x00\x8c>\xfd\xa0\x00\x00\x00\x00\x8cm\x22 \x00\x00\x00\x00\x8e\x0cj\xa0\x00\x00\x00\x00\x8eC\xc9\xa0\x00\x00\x00\x00\x8f\xe3\x12 \x00\x00\x00\x00\x90\x116\xa0\x00\x00\x00\x00\x91\xb9\xb9\xa0\x00\x00\x00\x00\x91\xe7\xde \x00\x00\x00\x00\x93\x87&\xa0\x00\x00\x00\x00\x93\xbe\x85\xa0\x00\x00\x00\x00\x95]\xce \x00\x00\x00\x00\x95\x8b\xf2\xa0\x00\x00\x00\x00\x97+; \x00\x00\x00\x00\x97b\x9a \x00\x00\x00\x00\x99\x01\xe2\xa0\x00\x00\x00\x00\x999A\xa0\x00\x00\x00\x00\x9a\xd8\x8a \x00\x00\x00\x00\x9b\x06\xae\xa0\x00\x00\x00\x00\x9c\xa5\xf7 \x00\x00\x00\x00\x9c\xddV \x00\x00\x00\x00\x9e|\x9e\xa0\x00\x00\x00\x00\x9e\xaa\xc3 \x00\x00\x00\x00\xa0SF \x00\x00\x00\x00\xa0\x81j\xa0\x00\x00\x00\x00\xa2 \xb3 \x00\x00\x00\x00\xa2X\x12 \x00\x00\x00\x00\xa3\xf7Z\xa0\x00\x00\x00\x00\xa4%\x7f \x00\x00\x00\x00\xa5\xc4\xc7\xa0\x00\x00\x00\x00\xa5\xfc&\xa0\x00\x00\x00\x00\xa7\x9bo \x00\x00\x00\x00\xa7\xd2\xce \x00\x00\x00\x00\xa9r\x16\xa0\x00\x00\x00\x00\xa9\xa0; \x00\x00\x00\x00\xab?\x83\xa0\x00\x00\x00\x00\xabv\xe2\xa0\x00\x00\x00\x00\xad\x16+ \x00\x00\x00\x00\xadDO\xa0\x00\x00\x00\x00\xae\xec\xd2\xa0\x00\x00\x00\x00\xaf\x1a\xf7 \x00\x00\x00\x00\xb0\xba?\xa0\x00\x00\x00\x00\xb0\xf1\x9e\xa0\x00\x00\x00\x00\xb2\x90\xe7 \x00\x00\x00\x00\xb2\xbf\x0b\xa0\x00\x00\x00\x00\xb4^T \x00\x00\x00\x00\xb4\x95\xb3 \x00\x00\x00\x00\xb64\xfb\xa0\x00\x00\x00\x00\xb6lZ\xa0\x00\x00\x00\x00\xb8\x0b\xa3 \x00\x00\x00\x00\xb89\xc7\xa0\x00\x00\x00\x00\xb9\xd9\x10 \x00\x00\x00\x00\xba\x10o \x00\x00\x00\x00\xbb\xaf\xb7\xa0\x00\x00\x00\x00\xbb\xdd\xdc \x00\x00\x00\x00\xbd\x86_ \x00\x00\x00\x00\xbd\xb4\x83\xa0\x00\x00\x00\x00\xbfS\xcc \x00\x00\x00\x00\xbf\x8b+ \x00\x00\x00\x00\xc1*s\xa0\x00\x00\x00\x00\xc1X\x98 \x00\x00\x00\x00\xc2\xf7\xe0\xa0\x00\x00\x00\x00\xc3/?\xa0\x00\x00\x00\x00\xc4\xce\x88 \x00\x00\x00\x00\xc5\x05\xe7 \x00\x00\x00\x00\xc6\xa5/\xa0\x00\x00\x00\x00\xc6\xd3T \x00\x00\x00\x00\xc8r\x9c\xa0\x00\x00\x00\x00\xc8\xa9\xfb\xa0\x00\x00\x00\x00\xcaID \x00\x00\x00\x00\xcawh\xa0\x00\x00\x00\x00\xcc\x1f\xeb\xa0\x00\x00\x00\x00\xccN\x10 \x00\x00\x00\x00\xcd\xedX\xa0\x00\x00\x00\x00\xce$\xb7\xa0\x00\x00\x00\x00\xcf\xc4\x00 \x00\x00\x00\x00\xcf\xf2$\xa0\x00\x00\x00\x00\xd1\x91m \x00\x00\x00\x00\xd1\xc8\xcc \x00\x00\x00\x00\xd3h\x14\xa0\x00\x00\x00\x00\xd3\x969 \x00\x00\x00\x00\xd5>\xbc \x00\x00\x00\x00\xd5l\xe0\xa0\x00\x00\x00\x00\xd7\x0c) \x00\x00\x00\x00\xd7C\x88 \x00\x00\x00\x00\xd8\xe2\xd0\xa0\x00\x00\x00\x00\xd9\x10\xf5 \x00\x00\x00\x00\xda\xb9x \x00\x00\x00\x00\xda\xe7\x9c\xa0\x00\x00\x00\x00\xdc\x86\xe5 \x00\x00\x00\x00\xdc\xbeD \x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\xff\xff\xf8\xe4\x00\x00\x00\x00\x0e\x10\x01\x04\x00\x00\x00\x00\x00\x08\x00\x00\x0e\x10\x00\x04\x00\x00\x00\x00\x01\x08LMT\x00+01\x00+00\x00\x0a<+01>-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x1b\xeb\xdd2\x02\x00\x002\x02\x00\x00\x0c\x00\x00\x00Africa/CeutaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff~6\xb5\x00\xff\xff\xff\xff\x9e\xd6up\xff\xff\xff\xff\x9f\xa1n`\xff\xff\xff\xff\xaa\x05\xefp\xff\xff\xff\xff\xaa\xe7n\x00\xff\xff\xff\xff\xad\xc9\xa7\xf0\xff\xff\xff\xff\xae\xa72\x00\xff\xff\xff\xff\xaf\xa0Op\xff\xff\xff\xff\xb0\x87\x14\x00\xff\xff\xff\xff\xb1\x89z\x00\xff\xff\xff\xff\xb2p0\x80\xff\xff\xff\xff\xfb%r@\xff\xff\xff\xff\xfb\xc2\xefp\x00\x00\x00\x00\x08k\x84\x80\x00\x00\x00\x00\x08\xc6m\xf0\x00\x00\x00\x00\x0b\xe8\x0c\x00\x00\x00\x00\x00\x0caG\xf0\x00\x00\x00\x00\x0d\xc9?\x80\x00\x00\x00\x00\x0e\x8e\xf2p\x00\x00\x00\x00\x0f\xd3Q\x80\x00\x00\x00\x00\x10'\xa3p\x00\x00\x00\x00\x1a\xb7\xa6\x00\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xa0\x00\x00\x00\x00WS\x87\xa0\x00\x00\x00\x00W\x81\xac \x00\x00\x00\x00X\x15T \x00\x00\x00\x00X\xd7 \xa0\x00\x00\x00\x00Y \xf4\xa0\x00\x00\x00\x00YXS\xa0\x00\x00\x00\x00Y\xf56 \x00\x00\x00\x00Z\xb7\x02\xa0\x00\x00\x00\x00Z\xf7\x9c \x00\x00\x00\x00[%\xc0\xa0\x00\x00\x00\x00[\xd5\x18 \x00\x00\x00\x00\x5c\xceC\xa0\x00\x00\x00\x00\x5c\xfch \x00\x00\x00\x00^\x9b\xb0\xa0\x00\x00\x00\x00^\xd3\x0f\xa0\x00\x00\x00\x00`rX \x00\x00\x00\x00`\xa0|\xa0\x00\x00\x00\x00b?\xc5 \x00\x00\x00\x00bw$ \x00\x00\x00\x00d\x16l\xa0\x00\x00\x00\x00dD\x91 \x00\x00\x00\x00e\xed\x14 \x00\x00\x00\x00f\x1b8\xa0\x00\x00\x00\x00g\xba\x81 \x00\x00\x00\x00g\xf1\xe0 \x00\x00\x00\x00i\x91(\xa0\x00\x00\x00\x00i\xbfM \x00\x00\x00\x00kg\xd0 \x00\x00\x00\x00k\x95\xf4\xa0\x00\x00\x00\x00m5= \x00\x00\x00\x00ml\x9c \x00\x00\x00\x00o\x0b\xe4\xa0\x00\x00\x00\x00o:\x09 \x00\x00\x00\x00p\xd9Q\xa0\x00\x00\x00\x00q\x10\xb0\xa0\x00\x00\x00\x00r\xaf\xf9 \x00\x00\x00\x00r\xde\x1d\xa0\x00\x00\x00\x00t\x86\xa0\xa0\x00\x00\x00\x00t\xb4\xc5 \x00\x00\x00\x00vT\x0d\xa0\x00\x00\x00\x00v\x8bl\xa0\x00\x00\x00\x00x*\xb5 \x00\x00\x00\x00xX\xd9\xa0\x00\x00\x00\x00y\xf8\x22 \x00\x00\x00\x00z/\x81 \x00\x00\x00\x00{\xce\xc9\xa0\x00\x00\x00\x00|\x06(\xa0\x00\x00\x00\x00}\xa5q \x00\x00\x00\x00}\xd3\x95\xa0\x00\x00\x00\x00\x7fr\xde \x00\x00\x00\x00\x7f\xaa= \x00\x00\x00\x00\x81I\x85\xa0\x00\x00\x00\x00\x81w\xaa \x00\x00\x00\x00\x83 - \x00\x00\x00\x00\x83NQ\xa0\x00\x00\x00\x00\x84\xed\x9a \x00\x00\x00\x00\x85$\xf9 \x00\x00\x00\x00\x86\xc4A\xa0\x00\x00\x00\x00\x86\xf2f \x00\x00\x00\x00\x88\x91\xae\xa0\x00\x00\x00\x00\x88\xc9\x0d\xa0\x00\x00\x00\x00\x8ahV \x00\x00\x00\x00\x8a\x9f\xb5 \x00\x00\x00\x00\x8c>\xfd\xa0\x00\x00\x00\x00\x8cm\x22 \x00\x00\x00\x00\x8e\x0cj\xa0\x00\x00\x00\x00\x8eC\xc9\xa0\x00\x00\x00\x00\x8f\xe3\x12 \x00\x00\x00\x00\x90\x116\xa0\x00\x00\x00\x00\x91\xb9\xb9\xa0\x00\x00\x00\x00\x91\xe7\xde \x00\x00\x00\x00\x93\x87&\xa0\x00\x00\x00\x00\x93\xbe\x85\xa0\x00\x00\x00\x00\x95]\xce \x00\x00\x00\x00\x95\x8b\xf2\xa0\x00\x00\x00\x00\x97+; \x00\x00\x00\x00\x97b\x9a \x00\x00\x00\x00\x99\x01\xe2\xa0\x00\x00\x00\x00\x999A\xa0\x00\x00\x00\x00\x9a\xd8\x8a \x00\x00\x00\x00\x9b\x06\xae\xa0\x00\x00\x00\x00\x9c\xa5\xf7 \x00\x00\x00\x00\x9c\xddV \x00\x00\x00\x00\x9e|\x9e\xa0\x00\x00\x00\x00\x9e\xaa\xc3 \x00\x00\x00\x00\xa0SF \x00\x00\x00\x00\xa0\x81j\xa0\x00\x00\x00\x00\xa2 \xb3 \x00\x00\x00\x00\xa2X\x12 \x00\x00\x00\x00\xa3\xf7Z\xa0\x00\x00\x00\x00\xa4%\x7f \x00\x00\x00\x00\xa5\xc4\xc7\xa0\x00\x00\x00\x00\xa5\xfc&\xa0\x00\x00\x00\x00\xa7\x9bo \x00\x00\x00\x00\xa7\xd2\xce \x00\x00\x00\x00\xa9r\x16\xa0\x00\x00\x00\x00\xa9\xa0; \x00\x00\x00\x00\xab?\x83\xa0\x00\x00\x00\x00\xabv\xe2\xa0\x00\x00\x00\x00\xad\x16+ \x00\x00\x00\x00\xadDO\xa0\x00\x00\x00\x00\xae\xec\xd2\xa0\x00\x00\x00\x00\xaf\x1a\xf7 \x00\x00\x00\x00\xb0\xba?\xa0\x00\x00\x00\x00\xb0\xf1\x9e\xa0\x00\x00\x00\x00\xb2\x90\xe7 \x00\x00\x00\x00\xb2\xbf\x0b\xa0\x00\x00\x00\x00\xb4^T \x00\x00\x00\x00\xb4\x95\xb3 \x00\x00\x00\x00\xb64\xfb\xa0\x00\x00\x00\x00\xb6lZ\xa0\x00\x00\x00\x00\xb8\x0b\xa3 \x00\x00\x00\x00\xb89\xc7\xa0\x00\x00\x00\x00\xb9\xd9\x10 \x00\x00\x00\x00\xba\x10o \x00\x00\x00\x00\xbb\xaf\xb7\xa0\x00\x00\x00\x00\xbb\xdd\xdc \x00\x00\x00\x00\xbd\x86_ \x00\x00\x00\x00\xbd\xb4\x83\xa0\x00\x00\x00\x00\xbfS\xcc \x00\x00\x00\x00\xbf\x8b+ \x00\x00\x00\x00\xc1*s\xa0\x00\x00\x00\x00\xc1X\x98 \x00\x00\x00\x00\xc2\xf7\xe0\xa0\x00\x00\x00\x00\xc3/?\xa0\x00\x00\x00\x00\xc4\xce\x88 \x00\x00\x00\x00\xc5\x05\xe7 \x00\x00\x00\x00\xc6\xa5/\xa0\x00\x00\x00\x00\xc6\xd3T \x00\x00\x00\x00\xc8r\x9c\xa0\x00\x00\x00\x00\xc8\xa9\xfb\xa0\x00\x00\x00\x00\xcaID \x00\x00\x00\x00\xcawh\xa0\x00\x00\x00\x00\xcc\x1f\xeb\xa0\x00\x00\x00\x00\xccN\x10 \x00\x00\x00\x00\xcd\xedX\xa0\x00\x00\x00\x00\xce$\xb7\xa0\x00\x00\x00\x00\xcf\xc4\x00 \x00\x00\x00\x00\xcf\xf2$\xa0\x00\x00\x00\x00\xd1\x91m \x00\x00\x00\x00\xd1\xc8\xcc \x00\x00\x00\x00\xd3h\x14\xa0\x00\x00\x00\x00\xd3\x969 \x00\x00\x00\x00\xd5>\xbc \x00\x00\x00\x00\xd5l\xe0\xa0\x00\x00\x00\x00\xd7\x0c) \x00\x00\x00\x00\xd7C\x88 \x00\x00\x00\x00\xd8\xe2\xd0\xa0\x00\x00\x00\x00\xd9\x10\xf5 \x00\x00\x00\x00\xda\xb9x \x00\x00\x00\x00\xda\xe7\x9c\xa0\x00\x00\x00\x00\xdc\x86\xe5 \x00\x00\x00\x00\xdc\xbeD \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\xff\xff\xf3\xa0\x00\x00\xff\xff\xf1\xf0\x00\x04\x00\x00\x0e\x10\x01\x08\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x01\x0c\x00\x00\x0e\x10\x00\x08LMT\x00-01\x00+01\x00+00\x00\x0a<+01>-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0f\x00\x00\x00Africa/FreetownTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0f\x00\x00\x00Africa/GaboroneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00Africa/HarareTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x13\x00\x00\x00Africa/JohannesburgTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x09\xff\xff\xff\xffm{A@\xff\xff\xff\xff\x82F\xcfh\xff\xff\xff\xff\xcc\xae\x8c\x80\xff\xff\xff\xff\xcd\x9eop\xff\xff\xff\xff\xce\x8en\x80\xff\xff\xff\xff\xcf~Qp\x01\x03\x02\x03\x02\x03\x00\x00\x1a@\x00\x00\x00\x00\x15\x18\x00\x04\x00\x00*0\x01\x04\x00\x00\x1c \x00\x04LMT\x00SAST\x00\x0aSAST-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\xcf\x10n\xca\x01\x00\x00\xca\x01\x00\x00\x0b\x00\x00\x00Africa/JubaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xb6\xa3\xda\xdc\x00\x00\x00\x00\x00\x9e\x17\xe0\x00\x00\x00\x00\x01z4P\x00\x00\x00\x00\x02}\xf9\xe0\x00\x00\x00\x00\x03[g\xd0\x00\x00\x00\x00\x04`~\xe0\x00\x00\x00\x00\x05=\xec\xd0\x00\x00\x00\x00\x06@`\xe0\x00\x00\x00\x00\x07\x1f P\x00\x00\x00\x00\x08 B\xe0\x00\x00\x00\x00\x09\x00S\xd0\x00\x00\x00\x00\x0a\x00$\xe0\x00\x00\x00\x00\x0a\xe1\x87P\x00\x00\x00\x00\x0b\xe0\x06\xe0\x00\x00\x00\x00\x0c\xc4\x0cP\x00\x00\x00\x00\x0d\xbf\xe8\xe0\x00\x00\x00\x00\x0e\xa5?\xd0\x00\x00\x00\x00\x0f\xa9\x05`\x00\x00\x00\x00\x10\x86sP\x00\x00\x00\x00\x11\x88\xe7`\x00\x00\x00\x00\x12g\xa6\xd0\x00\x00\x00\x00\x13h\xc9`\x00\x00\x00\x00\x14J+\xd0\x00\x00\x00\x00\x15H\xab`\x00\x00\x00\x00\x16+_P\x00\x00\x00\x00\x17(\x8d`\x00\x00\x00\x00\x18\x0c\x92\xd0\x00\x00\x00\x00\x19\x08o`\x00\x00\x00\x00\x19\xed\xc6P\x00\x00\x00\x00\x1a\xf1\x8b\xe0\x00\x00\x00\x00\x1b\xd0KP\x00\x00\x00\x00\x1c\xd1m\xe0\x00\x00\x00\x00\x1d\xb1~\xd0\x00\x00\x00\x008\x80E \x00\x00\x00\x00`\x17\x1aP\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x00\x00\x1d\xa4\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x00\x0dLMT\x00CAST\x00CAT\x00EAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00Africa/KampalaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xadD\xef\xca\x01\x00\x00\xca\x01\x00\x00\x0f\x00\x00\x00Africa/KhartoumTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xb6\xa3\xda\x00\x00\x00\x00\x00\x00\x9e\x17\xe0\x00\x00\x00\x00\x01z4P\x00\x00\x00\x00\x02}\xf9\xe0\x00\x00\x00\x00\x03[g\xd0\x00\x00\x00\x00\x04`~\xe0\x00\x00\x00\x00\x05=\xec\xd0\x00\x00\x00\x00\x06@`\xe0\x00\x00\x00\x00\x07\x1f P\x00\x00\x00\x00\x08 B\xe0\x00\x00\x00\x00\x09\x00S\xd0\x00\x00\x00\x00\x0a\x00$\xe0\x00\x00\x00\x00\x0a\xe1\x87P\x00\x00\x00\x00\x0b\xe0\x06\xe0\x00\x00\x00\x00\x0c\xc4\x0cP\x00\x00\x00\x00\x0d\xbf\xe8\xe0\x00\x00\x00\x00\x0e\xa5?\xd0\x00\x00\x00\x00\x0f\xa9\x05`\x00\x00\x00\x00\x10\x86sP\x00\x00\x00\x00\x11\x88\xe7`\x00\x00\x00\x00\x12g\xa6\xd0\x00\x00\x00\x00\x13h\xc9`\x00\x00\x00\x00\x14J+\xd0\x00\x00\x00\x00\x15H\xab`\x00\x00\x00\x00\x16+_P\x00\x00\x00\x00\x17(\x8d`\x00\x00\x00\x00\x18\x0c\x92\xd0\x00\x00\x00\x00\x19\x08o`\x00\x00\x00\x00\x19\xed\xc6P\x00\x00\x00\x00\x1a\xf1\x8b\xe0\x00\x00\x00\x00\x1b\xd0KP\x00\x00\x00\x00\x1c\xd1m\xe0\x00\x00\x00\x00\x1d\xb1~\xd0\x00\x00\x00\x008\x80E \x00\x00\x00\x00Y\xf8\xe4P\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x00\x00\x1e\x80\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x00\x0dLMT\x00CAST\x00CAT\x00EAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00Africa/KigaliTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0f\x00\x00\x00Africa/KinshasaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0c\x00\x00\x00Africa/LagosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x11\x00\x00\x00Africa/LibrevilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0b\x00\x00\x00Africa/LomeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00Africa/LuandaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x11\x00\x00\x00Africa/LubumbashiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00Africa/LusakaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00Africa/MalaboTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00Africa/MaputoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x0d\x00\x00\x00Africa/MaseruTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x09\xff\xff\xff\xffm{A@\xff\xff\xff\xff\x82F\xcfh\xff\xff\xff\xff\xcc\xae\x8c\x80\xff\xff\xff\xff\xcd\x9eop\xff\xff\xff\xff\xce\x8en\x80\xff\xff\xff\xff\xcf~Qp\x01\x03\x02\x03\x02\x03\x00\x00\x1a@\x00\x00\x00\x00\x15\x18\x00\x04\x00\x00*0\x01\x04\x00\x00\x1c \x00\x04LMT\x00SAST\x00\x0aSAST-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x0e\x00\x00\x00Africa/MbabaneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x09\xff\xff\xff\xffm{A@\xff\xff\xff\xff\x82F\xcfh\xff\xff\xff\xff\xcc\xae\x8c\x80\xff\xff\xff\xff\xcd\x9eop\xff\xff\xff\xff\xce\x8en\x80\xff\xff\xff\xff\xcf~Qp\x01\x03\x02\x03\x02\x03\x00\x00\x1a@\x00\x00\x00\x00\x15\x18\x00\x04\x00\x00*0\x01\x04\x00\x00\x1c \x00\x04LMT\x00SAST\x00\x0aSAST-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x10\x00\x00\x00Africa/MogadishuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x99rU\xa4\x00\x00\x00\xa4\x00\x00\x00\x0f\x00\x00\x00Africa/MonroviaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xffZz\xa6\x9c\xff\xff\xff\xff\xa0_l\x9c\x00\x00\x00\x00\x03\xcaZn\x01\x02\x03\xff\xff\xf5\xe4\x00\x00\xff\xff\xf5\xe4\x00\x04\xff\xff\xf5\x92\x00\x04\x00\x00\x00\x00\x00\x08LMT\x00MMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00Africa/NairobiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\x81\x09\x03\xa0\x00\x00\x00\xa0\x00\x00\x00\x0f\x00\x00\x00Africa/NdjamenaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff\x92\xe6\x80d\x00\x00\x00\x00\x12fqp\x00\x00\x00\x00\x13&\xde`\x01\x02\x01\x00\x00\x0e\x1c\x00\x00\x00\x00\x0e\x10\x00\x04\x00\x00\x1c \x01\x08LMT\x00WAT\x00WAST\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00Africa/NiameyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x11\x00\x00\x00Africa/NouakchottTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00Africa/OuagadougouTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x11\x00\x00\x00Africa/Porto-NovoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc1\x0a\x8a\x84\xad\x00\x00\x00\xad\x00\x00\x00\x0f\x00\x00\x00Africa/Sao_TomeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff^<\xfd0\xff\xff\xff\xff\x92\xe6\x8e\x80\x00\x00\x00\x00ZI\x88\x10\x00\x00\x00\x00\x5c*\xbb\x90\x01\x02\x03\x02\x00\x00\x06P\x00\x00\xff\xff\xf7c\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x0e\x10\x00\x08LMT\x00GMT\x00WAT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0f\x00\x00\x00Africa/TimbuktuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x7f2[\xaf\x01\x00\x00\xaf\x01\x00\x00\x0e\x00\x00\x00Africa/TripoliTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa1\xf2\xc1$\xff\xff\xff\xff\xdd\xbb\xb1\x10\xff\xff\xff\xff\xde#\xad`\xff\xff\xff\xff\xe1x\xd2\x10\xff\xff\xff\xff\xe1\xe7e\xe0\xff\xff\xff\xff\xe5/?p\xff\xff\xff\xff\xe5\xa9\xcc\xe0\xff\xff\xff\xff\xebN\xc6\xf0\x00\x00\x00\x00\x16\x92B`\x00\x00\x00\x00\x17\x08\xf7p\x00\x00\x00\x00\x17\xfa+\xe0\x00\x00\x00\x00\x18\xea*\xf0\x00\x00\x00\x00\x19\xdb_`\x00\x00\x00\x00\x1a\xcc\xaf\xf0\x00\x00\x00\x00\x1b\xbd\xe4`\x00\x00\x00\x00\x1c\xb4z\xf0\x00\x00\x00\x00\x1d\x9f\x17\xe0\x00\x00\x00\x00\x1e\x93\x0bp\x00\x00\x00\x00\x1f\x82\xee`\x00\x00\x00\x00 pJp\x00\x00\x00\x00!a~\xe0\x00\x00\x00\x00\x22R\xcfp\x00\x00\x00\x00#D\x03\xe0\x00\x00\x00\x00$4\x02\xf0\x00\x00\x00\x00%%7`\x00\x00\x00\x00&@\xb7\xf0\x00\x00\x00\x002N\xf1`\x00\x00\x00\x003D6p\x00\x00\x00\x0045j\xe0\x00\x00\x00\x00P\x9d\x99\x00\x00\x00\x00\x00QT\xd9\x80\x00\x00\x00\x00Ri\xb4\x80\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x03\x02\x01\x03\x00\x00\x0c\x5c\x00\x00\x00\x00\x1c \x01\x04\x00\x00\x0e\x10\x00\x09\x00\x00\x1c \x00\x0dLMT\x00CEST\x00CET\x00EET\x00\x0aEET-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\xf4\x94\x0b\xc1\x01\x00\x00\xc1\x01\x00\x00\x0c\x00\x00\x00Africa/TunisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xffYF\x13\xf4\xff\xff\xff\xff\x91`PO\xff\xff\xff\xff\xc6:\x88\xe0\xff\xff\xff\xff\xc7X\x9e`\xff\xff\xff\xff\xc7\xdb\x22\xe0\xff\xff\xff\xff\xca\xe2T\xe0\xff\xff\xff\xff\xcb\xadi\xf0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xcd\xc2\x16\x00\xff\xff\xff\xff\xcd\xcc\xb0\x10\xff\xff\xff\xff\xce\xa25\x00\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x89\xe3\xe0\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N\x16`\x00\x00\x00\x00\x0d\xc7\xdf\xf0\x00\x00\x00\x00\x0e\x89\xacp\x00\x00\x00\x00\x0f\xaad\xf0\x00\x00\x00\x00\x10t\x1ap\x00\x00\x00\x00\x22\xa3:\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&<\xc3p\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00Bt\x0d\xf0\x00\x00\x00\x00C<\x80\x00\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x09\x8c\x00\x00\x00\x00\x021\x00\x04\x00\x00\x1c \x01\x08\x00\x00\x0e\x10\x00\x0dLMT\x00PMT\x00CEST\x00CET\x00\x0aCET-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00m)\xb8P~\x02\x00\x00~\x02\x00\x00\x0f\x00\x00\x00Africa/WindhoekTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x06\x00\x00\x00\x17\xff\xff\xff\xffm{Kx\xff\xff\xff\xff\x82F\xcfh\xff\xff\xff\xff\xcc\xae\x8c\x80\xff\xff\xff\xff\xcd\x9eop\x00\x00\x00\x00&\x06\xa7\xe0\x00\x00\x00\x00-\x8c\xc7`\x00\x00\x00\x00.i\x1c\x10\x00\x00\x00\x00/}\xe9\x00\x00\x00\x00\x000H\xfe\x10\x00\x00\x00\x001g\x05\x80\x00\x00\x00\x002(\xe0\x10\x00\x00\x00\x003F\xe7\x80\x00\x00\x00\x004\x11\xfc\x90\x00\x00\x00\x005&\xc9\x80\x00\x00\x00\x005\xf1\xde\x90\x00\x00\x00\x007\x06\xab\x80\x00\x00\x00\x007\xd1\xc0\x90\x00\x00\x00\x008\xe6\x8d\x80\x00\x00\x00\x009\xb1\xa2\x90\x00\x00\x00\x00:\xc6o\x80\x00\x00\x00\x00;\x91\x84\x90\x00\x00\x00\x00<\xaf\x8c\x00\x00\x00\x00\x00=qf\x90\x00\x00\x00\x00>\x8fn\x00\x00\x00\x00\x00?Z\x83\x10\x00\x00\x00\x00@oP\x00\x00\x00\x00\x00A:e\x10\x00\x00\x00\x00BO2\x00\x00\x00\x00\x00C\x1aG\x10\x00\x00\x00\x00D/\x14\x00\x00\x00\x00\x00D\xfa)\x10\x00\x00\x00\x00F\x0e\xf6\x00\x00\x00\x00\x00F\xda\x0b\x10\x00\x00\x00\x00G\xf8\x12\x80\x00\x00\x00\x00H\xc3'\x90\x00\x00\x00\x00I\xd7\xf4\x80\x00\x00\x00\x00J\xa3\x09\x90\x00\x00\x00\x00K\xb7\xd6\x80\x00\x00\x00\x00L\x82\xeb\x90\x00\x00\x00\x00M\x97\xb8\x80\x00\x00\x00\x00Nb\xcd\x90\x00\x00\x00\x00Ow\x9a\x80\x00\x00\x00\x00PB\xaf\x90\x00\x00\x00\x00Q`\xb7\x00\x00\x00\x00\x00R\x22\x91\x90\x00\x00\x00\x00S@\x99\x00\x00\x00\x00\x00T\x0b\xae\x10\x00\x00\x00\x00U {\x00\x00\x00\x00\x00U\xeb\x90\x10\x00\x00\x00\x00W\x00]\x00\x00\x00\x00\x00W\xcbr\x10\x00\x00\x00\x00X\xe0?\x00\x00\x00\x00\x00Y\xabT\x10\x01\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x00\x00\x10\x08\x00\x00\x00\x00\x15\x18\x00\x04\x00\x00\x1c \x00\x0a\x00\x00*0\x01\x0a\x00\x00\x0e\x10\x01\x0f\x00\x00\x1c \x00\x13LMT\x00+0130\x00SAST\x00WAT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0c\x00\x00\x00America/AdakTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00!\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87Z^\xff\xff\xff\xff\xcb\x89D\xd0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aP@\xff\xff\xff\xff\xfa\xd2U\xb0\xff\xff\xff\xff\xfe\xb8qP\xff\xff\xff\xff\xff\xa8T@\x00\x00\x00\x00\x00\x98SP\x00\x00\x00\x00\x01\x886@\x00\x00\x00\x00\x02x5P\x00\x00\x00\x00\x03qR\xc0\x00\x00\x00\x00\x04aQ\xd0\x00\x00\x00\x00\x05Q4\xc0\x00\x00\x00\x00\x06A3\xd0\x00\x00\x00\x00\x071\x16\xc0\x00\x00\x00\x00\x07\x8dm\xd0\x00\x00\x00\x00\x09\x10\xf8\xc0\x00\x00\x00\x00\x09\xad\xe9P\x00\x00\x00\x00\x0a\xf0\xda\xc0\x00\x00\x00\x00\x0b\xe0\xd9\xd0\x00\x00\x00\x00\x0c\xd9\xf7@\x00\x00\x00\x00\x0d\xc0\xbb\xd0\x00\x00\x00\x00\x0e\xb9\xd9@\x00\x00\x00\x00\x0f\xa9\xd8P\x00\x00\x00\x00\x10\x99\xbb@\x00\x00\x00\x00\x11\x89\xbaP\x00\x00\x00\x00\x12y\x9d@\x00\x00\x00\x00\x13i\x9cP\x00\x00\x00\x00\x14Y\x7f@\x00\x00\x00\x00\x15I~P\x00\x00\x00\x00\x169a@\x00\x00\x00\x00\x17)`P\x00\x00\x00\x00\x18\x22}\xc0\x00\x00\x00\x00\x19\x09BP\x00\x00\x00\x00\x1a\x02_\xc0\x00\x00\x00\x00\x1a+\x22 \x00\x00\x00\x00\x1a\xf2P\xc0\x00\x00\x00\x00\x1b\xe23\xb0\x00\x00\x00\x00\x1c\xd22\xc0\x00\x00\x00\x00\x1d\xc2\x15\xb0\x00\x00\x00\x00\x1e\xb2\x14\xc0\x00\x00\x00\x00\x1f\xa1\xf7\xb0\x00\x00\x00\x00 vG@\x00\x00\x00\x00!\x81\xd9\xb0\x00\x00\x00\x00\x22V)@\x00\x00\x00\x00#j\xf60\x00\x00\x00\x00$6\x0b@\x00\x00\x00\x00%J\xd80\x00\x00\x00\x00&\x15\xed@\x00\x00\x00\x00'*\xba0\x00\x00\x00\x00'\xff\x09\xc0\x00\x00\x00\x00)\x0a\x9c0\x00\x00\x00\x00)\xde\xeb\xc0\x00\x00\x00\x00*\xea~0\x00\x00\x00\x00+\xbe\xcd\xc0\x00\x00\x00\x00,\xd3\x9a\xb0\x00\x00\x00\x00-\x9e\xaf\xc0\x00\x00\x00\x00.\xb3|\xb0\x00\x00\x00\x00/~\x91\xc0\x00\x00\x00\x000\x93^\xb0\x00\x00\x00\x001g\xae@\x00\x00\x00\x002s@\xb0\x00\x00\x00\x003G\x90@\x00\x00\x00\x004S\x22\xb0\x00\x00\x00\x005'r@\x00\x00\x00\x0063\x04\xb0\x00\x00\x00\x007\x07T@\x00\x00\x00\x008\x1c!0\x00\x00\x00\x008\xe76@\x00\x00\x00\x009\xfc\x030\x00\x00\x00\x00:\xc7\x18@\x00\x00\x00\x00;\xdb\xe50\x00\x00\x00\x00<\xb04\xc0\x00\x00\x00\x00=\xbb\xc70\x00\x00\x00\x00>\x90\x16\xc0\x00\x00\x00\x00?\x9b\xa90\x00\x00\x00\x00@o\xf8\xc0\x00\x00\x00\x00A\x84\xc5\xb0\x00\x00\x00\x00BO\xda\xc0\x00\x00\x00\x00Cd\xa7\xb0\x00\x00\x00\x00D/\xbc\xc0\x00\x00\x00\x00ED\x89\xb0\x00\x00\x00\x00E\xf3\xef@\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xab\xe2\x00\x00\xff\xffZb\x00\x00\xff\xffeP\x00\x04\xff\xffs`\x01\x08\xff\xffs`\x01\x0c\xff\xffeP\x00\x10\xff\xffs`\x01\x14\xff\xffs`\x00\x18\xff\xff\x81p\x01\x1d\xff\xffs`\x00\x19LMT\x00NST\x00NWT\x00NPT\x00BST\x00BDT\x00AHST\x00HDT\x00\x0aHST10HDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x11Q\x06\xd1\x03\x00\x00\xd1\x03\x00\x00\x11\x00\x00\x00America/AnchorageTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00(\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87AH\xff\xff\xff\xff\xcb\x896\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aB0\xff\xff\xff\xff\xfa\xd2G\xa0\xff\xff\xff\xff\xfe\xb8c@\xff\xff\xff\xff\xff\xa8F0\x00\x00\x00\x00\x00\x98E@\x00\x00\x00\x00\x01\x88(0\x00\x00\x00\x00\x02x'@\x00\x00\x00\x00\x03qD\xb0\x00\x00\x00\x00\x04aC\xc0\x00\x00\x00\x00\x05Q&\xb0\x00\x00\x00\x00\x06A%\xc0\x00\x00\x00\x00\x071\x08\xb0\x00\x00\x00\x00\x07\x8d_\xc0\x00\x00\x00\x00\x09\x10\xea\xb0\x00\x00\x00\x00\x09\xad\xdb@\x00\x00\x00\x00\x0a\xf0\xcc\xb0\x00\x00\x00\x00\x0b\xe0\xcb\xc0\x00\x00\x00\x00\x0c\xd9\xe90\x00\x00\x00\x00\x0d\xc0\xad\xc0\x00\x00\x00\x00\x0e\xb9\xcb0\x00\x00\x00\x00\x0f\xa9\xca@\x00\x00\x00\x00\x10\x99\xad0\x00\x00\x00\x00\x11\x89\xac@\x00\x00\x00\x00\x12y\x8f0\x00\x00\x00\x00\x13i\x8e@\x00\x00\x00\x00\x14Yq0\x00\x00\x00\x00\x15Ip@\x00\x00\x00\x00\x169S0\x00\x00\x00\x00\x17)R@\x00\x00\x00\x00\x18\x22o\xb0\x00\x00\x00\x00\x19\x094@\x00\x00\x00\x00\x1a\x02Q\xb0\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xc4\xf8\x00\x00\xff\xffsx\x00\x00\xff\xffs`\x00\x04\xff\xff\x81p\x01\x08\xff\xff\x81p\x01\x0c\xff\xffs`\x00\x10\xff\xff\x81p\x01\x15\xff\xff\x81p\x00\x1a\xff\xff\x8f\x80\x01\x1e\xff\xff\x81p\x00#LMT\x00AST\x00AWT\x00APT\x00AHST\x00AHDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00America/AnguillaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00America/AntiguaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x01V\x0dP\x02\x00\x00P\x02\x00\x00\x11\x00\x00\x00America/AraguainaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaat0\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x002W \xb0\x00\x00\x00\x003\x06j \x00\x00\x00\x0048T0\x00\x00\x00\x004\xf8\xc1 \x00\x00\x00\x006 \x1f0\x00\x00\x00\x006\xcfh\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x00:\x8f,\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x00N\xf0\xa0\x00\x00\x00\x00P\x83e0\x00\x00\x00\x00Q 9\xa0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xd2\xd0\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xbf\xf5\xe5\xc4\x02\x00\x00\xc4\x02\x00\x00\x1e\x00\x00\x00America/Argentina/Buenos_AiresTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xa8L\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x04\x05\x04\x05\xff\xff\xc94\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00\x1b\x00\x00\x00America/Argentina/CatamarcaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xaf,\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xc2T\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00 \x00\x00\x00America/Argentina/ComodRivadaviaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xaf,\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xc2T\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00America/Argentina/CordobaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xad\xb0\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x04\x05\x04\x05\xff\xff\xc3\xd0\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00utZ\x1a\xb2\x02\x00\x00\xb2\x02\x00\x00\x17\x00\x00\x00America/Argentina/JujuyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xae\xb8\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'*W\xc0\x00\x00\x00\x00'\xe2\xdb\xb0\x00\x00\x00\x00(\xee\x8a@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x04\x05\x04\x05\x03\x05\x04\x05\xff\xff\xc2\xc8\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00m\x07D\x0e\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00America/Argentina/La_RiojaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb0,\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xcd\xb5\xa0\x00\x00\x00\x00(&&@\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x05\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xc1T\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x92Z\x8c\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00America/Argentina/MendozaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb2\x04\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'\x194@\x00\x00\x00\x00'\xcd\xc3\xb0\x00\x00\x00\x00(\xfag\xc0\x00\x00\x00\x00)\xb0H\xb0\x00\x00\x00\x00*\xe0\xe1@\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xb0\x13\xb0\x00\x00\x00\x00AV>\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x03\x02\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf|\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ep\xb4c\xc4\x02\x00\x00\xc4\x02\x00\x00\x1e\x00\x00\x00America/Argentina/Rio_GallegosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb2d\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf\x1c\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t*\x9b!\xb2\x02\x00\x00\xb2\x02\x00\x00\x17\x00\x00\x00America/Argentina/SaltaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xae\xd4\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x04\x05\xff\xff\xc2\xac\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcz=\xe1\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00America/Argentina/San_JuanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb1\xbc\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xcd\xb5\xa0\x00\x00\x00\x00(&&@\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xba\x9f\xb0\x00\x00\x00\x00A\x030@\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x05\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf\xc4\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x80\xb9\x5c\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00America/Argentina/San_LuisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xaf\xb4\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xfd\xa5\xa0\x00\x00\x00\x00'\x194@\x00\x00\x00\x00'\xcd\xc3\xb0\x00\x00\x00\x00(G\x1b\xc0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xba\x9f\xb0\x00\x00\x00\x00A\x030@\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\x93\xfc\xa0\x00\x00\x00\x00G\xd3R\xb0\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xb34\xb0\x00\x00\x00\x00J\xd1X@\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x05\x03\x05\x02\x05\x04\x03\x02\x03\x02\x05\xff\xff\xc1\xcc\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd8\xd6\xad\xd6\x02\x00\x00\xd6\x02\x00\x00\x19\x00\x00\x00America/Argentina/TucumanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xae\xa4\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xcb\xd1@\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\x04\x05\xff\xff\xc2\xdc\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b}\xb6\x1e\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00America/Argentina/UshuaiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb1\x88\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xb9N0\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf\xf8\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0d\x00\x00\x00America/ArubaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xa9y\x9at\x03\x00\x00t\x03\x00\x00\x10\x00\x00\x00America/AsuncionTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xffi\x87\x11\x90\xff\xff\xff\xff\xb8\x17\xf5\x90\x00\x00\x00\x00\x05+\xda@\x00\x00\x00\x00\x07\xfc\xf0\xb0\x00\x00\x00\x00\x0a\xcft\xc0\x00\x00\x00\x00\x0b\x97\xca\xb0\x00\x00\x00\x00\x0c\xb1\xf9\xc0\x00\x00\x00\x00\x0dx\xfe0\x00\x00\x00\x00\x0e\x93-@\x00\x00\x00\x00\x0fZ1\xb0\x00\x00\x00\x00\x10t`\xc0\x00\x00\x00\x00\x11dC\xb0\x00\x00\x00\x00\x12U\x94@\x00\x00\x00\x00\x13F\xc8\xb0\x00\x00\x00\x00\x148\x19@\x00\x00\x00\x00\x15'\xfc0\x00\x00\x00\x00\x16\x19L\xc0\x00\x00\x00\x00\x17\x09/\xb0\x00\x00\x00\x00\x17\xfa\x80@\x00\x00\x00\x00\x18\xeac0\x00\x00\x00\x00\x19\xdb\xb3\xc0\x00\x00\x00\x00\x1a\xcc\xe80\x00\x00\x00\x00\x1b\xbe8\xc0\x00\x00\x00\x00\x1c\xae\x1b\xb0\x00\x00\x00\x00\x1d\x9fl@\x00\x00\x00\x00\x1e\x8fO0\x00\x00\x00\x00\x1f\x80\x9f\xc0\x00\x00\x00\x00 p\x82\xb0\x00\x00\x00\x00!a\xd3@\x00\x00\x00\x00\x22S\x07\xb0\x00\x00\x00\x00#DX@\x00\x00\x00\x00$4;0\x00\x00\x00\x00%A;@\x00\x00\x00\x00&\x15n\xb0\x00\x00\x00\x00'\x06\xbf@\x00\x00\x00\x00'\xf6\xa20\x00\x00\x00\x00(\xee\x8a@\x00\x00\x00\x00)\xb0H\xb0\x00\x00\x00\x00*\xcf\xbd\xc0\x00\x00\x00\x00+\xb9\x090\x00\x00\x00\x00,\xab\xab@\x00\x00\x00\x00-p\x0c\xb0\x00\x00\x00\x00.\x8c\xde\xc0\x00\x00\x00\x00/O\xee\xb0\x00\x00\x00\x000n\x12@\x00\x00\x00\x0016h0\x00\x00\x00\x002W.\xc0\x00\x00\x00\x003\x0f\xb2\xb0\x00\x00\x00\x0047\x10\xc0\x00\x00\x00\x004\xf8\xcf0\x00\x00\x00\x006\x16\xf2\xc0\x00\x00\x00\x006\xe1\xeb\xb0\x00\x00\x00\x007\xf6\xd4\xc0\x00\x00\x00\x008\xc1\xcd\xb0\x00\x00\x00\x009\xd6\xb6\xc0\x00\x00\x00\x00:\xa1\xaf\xb0\x00\x00\x00\x00;\xbf\xd3@\x00\x00\x00\x00<\xaf\xb60\x00\x00\x00\x00=q\x90\xc0\x00\x00\x00\x00>\x8f\x980\x00\x00\x00\x00?Z\xad@\x00\x00\x00\x00@oz0\x00\x00\x00\x00Aq\xee@\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CQ\xd0@\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x1a\xce\xc0\x00\x00\x00\x00G\xd3R\xb0\x00\x00\x00\x00H\xfa\xb0\xc0\x00\x00\x00\x00I\xb34\xb0\x00\x00\x00\x00J\xda\x92\xc0\x00\x00\x00\x00K\xc1;0\x00\x00\x00\x00L\xa7\xff\xc0\x00\x00\x00\x00M\xa1\x1d0\x00\x00\x00\x00N\x87\xe1\xc0\x00\x00\x00\x00O\x80\xff0\x00\x00\x00\x00Pp\xfe@\x01\x02\x03\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\xff\xff\xc9\xf0\x00\x00\xff\xff\xc9\xf0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x00\x0c\xff\xff\xd5\xd0\x01\x0cLMT\x00AMT\x00-04\x00-03\x00\x0a<-04>4<-03>,M10.1.0/0,M3.4.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x10\x00\x00\x00America/AtikokanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffi\x87&\x10\xff\xff\xff\xff\x8b\xf4a\xe8\x01\x02\xff\xff\xb5p\x00\x00\xff\xff\xb5\x18\x00\x04\xff\xff\xb9\xb0\x00\x08LMT\x00CMT\x00EST\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0c\x00\x00\x00America/AtkaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00!\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87Z^\xff\xff\xff\xff\xcb\x89D\xd0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aP@\xff\xff\xff\xff\xfa\xd2U\xb0\xff\xff\xff\xff\xfe\xb8qP\xff\xff\xff\xff\xff\xa8T@\x00\x00\x00\x00\x00\x98SP\x00\x00\x00\x00\x01\x886@\x00\x00\x00\x00\x02x5P\x00\x00\x00\x00\x03qR\xc0\x00\x00\x00\x00\x04aQ\xd0\x00\x00\x00\x00\x05Q4\xc0\x00\x00\x00\x00\x06A3\xd0\x00\x00\x00\x00\x071\x16\xc0\x00\x00\x00\x00\x07\x8dm\xd0\x00\x00\x00\x00\x09\x10\xf8\xc0\x00\x00\x00\x00\x09\xad\xe9P\x00\x00\x00\x00\x0a\xf0\xda\xc0\x00\x00\x00\x00\x0b\xe0\xd9\xd0\x00\x00\x00\x00\x0c\xd9\xf7@\x00\x00\x00\x00\x0d\xc0\xbb\xd0\x00\x00\x00\x00\x0e\xb9\xd9@\x00\x00\x00\x00\x0f\xa9\xd8P\x00\x00\x00\x00\x10\x99\xbb@\x00\x00\x00\x00\x11\x89\xbaP\x00\x00\x00\x00\x12y\x9d@\x00\x00\x00\x00\x13i\x9cP\x00\x00\x00\x00\x14Y\x7f@\x00\x00\x00\x00\x15I~P\x00\x00\x00\x00\x169a@\x00\x00\x00\x00\x17)`P\x00\x00\x00\x00\x18\x22}\xc0\x00\x00\x00\x00\x19\x09BP\x00\x00\x00\x00\x1a\x02_\xc0\x00\x00\x00\x00\x1a+\x22 \x00\x00\x00\x00\x1a\xf2P\xc0\x00\x00\x00\x00\x1b\xe23\xb0\x00\x00\x00\x00\x1c\xd22\xc0\x00\x00\x00\x00\x1d\xc2\x15\xb0\x00\x00\x00\x00\x1e\xb2\x14\xc0\x00\x00\x00\x00\x1f\xa1\xf7\xb0\x00\x00\x00\x00 vG@\x00\x00\x00\x00!\x81\xd9\xb0\x00\x00\x00\x00\x22V)@\x00\x00\x00\x00#j\xf60\x00\x00\x00\x00$6\x0b@\x00\x00\x00\x00%J\xd80\x00\x00\x00\x00&\x15\xed@\x00\x00\x00\x00'*\xba0\x00\x00\x00\x00'\xff\x09\xc0\x00\x00\x00\x00)\x0a\x9c0\x00\x00\x00\x00)\xde\xeb\xc0\x00\x00\x00\x00*\xea~0\x00\x00\x00\x00+\xbe\xcd\xc0\x00\x00\x00\x00,\xd3\x9a\xb0\x00\x00\x00\x00-\x9e\xaf\xc0\x00\x00\x00\x00.\xb3|\xb0\x00\x00\x00\x00/~\x91\xc0\x00\x00\x00\x000\x93^\xb0\x00\x00\x00\x001g\xae@\x00\x00\x00\x002s@\xb0\x00\x00\x00\x003G\x90@\x00\x00\x00\x004S\x22\xb0\x00\x00\x00\x005'r@\x00\x00\x00\x0063\x04\xb0\x00\x00\x00\x007\x07T@\x00\x00\x00\x008\x1c!0\x00\x00\x00\x008\xe76@\x00\x00\x00\x009\xfc\x030\x00\x00\x00\x00:\xc7\x18@\x00\x00\x00\x00;\xdb\xe50\x00\x00\x00\x00<\xb04\xc0\x00\x00\x00\x00=\xbb\xc70\x00\x00\x00\x00>\x90\x16\xc0\x00\x00\x00\x00?\x9b\xa90\x00\x00\x00\x00@o\xf8\xc0\x00\x00\x00\x00A\x84\xc5\xb0\x00\x00\x00\x00BO\xda\xc0\x00\x00\x00\x00Cd\xa7\xb0\x00\x00\x00\x00D/\xbc\xc0\x00\x00\x00\x00ED\x89\xb0\x00\x00\x00\x00E\xf3\xef@\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xab\xe2\x00\x00\xff\xffZb\x00\x00\xff\xffeP\x00\x04\xff\xffs`\x01\x08\xff\xffs`\x01\x0c\xff\xffeP\x00\x10\xff\xffs`\x01\x14\xff\xffs`\x00\x18\xff\xff\x81p\x01\x1d\xff\xffs`\x00\x19LMT\x00NST\x00NWT\x00NPT\x00BST\x00BDT\x00AHST\x00HDT\x00\x0aHST10HDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00OKj\xc7\xaa\x02\x00\x00\xaa\x02\x00\x00\x0d\x00\x00\x00America/BahiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaak\x1c\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xbd\xe3\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\x94\x8b \x00\x00\x00\x00*\xea\x0d\xb0\x00\x00\x00\x00+k2\xa0\x00\x00\x00\x00,\xc0\xb50\x00\x00\x00\x00-f\xc4 \x00\x00\x00\x00.\xa0\x970\x00\x00\x00\x00/F\xa6 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x002W \xb0\x00\x00\x00\x003\x06j \x00\x00\x00\x0048T0\x00\x00\x00\x004\xf8\xc1 \x00\x00\x00\x006 \x1f0\x00\x00\x00\x006\xcfh\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x00:\x8f,\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x00N\xf0\xa0\x00\x00\x00\x00N\x9aH\xb0\x00\x00\x00\x00OI\x92 \x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xdb\xe4\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x0e\x01n\xd8\x02\x00\x00\xd8\x02\x00\x00\x16\x00\x00\x00America/Bahia_BanderasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xcb\xeaq`\xff\xff\xff\xff\xd8\x91\xb4\xf0\x00\x00\x00\x00\x00\x00p\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\xb8U\x10\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x03\x01\x02\x01\x04\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\xff\xff\x9dT\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\x8f\x80\x00\x10\xff\xff\xb9\xb0\x01\x14LMT\x00MST\x00CST\x00MDT\x00PST\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l=\xad\xbe\x16\x01\x00\x00\x16\x01\x00\x00\x10\x00\x00\x00America/BarbadosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x92@\xa9e\xff\xff\xff\xff\xcb\xe3\xcb\xd0\xff\xff\xff\xff\xcc\x94\x82\xe0\xff\xff\xff\xff\xcd\xd6\x22\xd0\xff\xff\xff\xff\xce|M\xe0\xff\xff\xff\xff\xcf\x9b\xa6\xd0\xff\xff\xff\xff\xd0ej`\x00\x00\x00\x00\x0e\x00\xf2\xe0\x00\x00\x00\x00\x0e\x94\x8c\xd0\x00\x00\x00\x00\x0f\x97\x00\xe0\x00\x00\x00\x00\x10tn\xd0\x00\x00\x00\x00\x11v\xe2\xe0\x00\x00\x00\x00\x12TP\xd0\x00\x00\x00\x00\x13_\xff`\x00\x00\x00\x00\x140>P\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc8\x1b\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xce\xc8\x01\x0cLMT\x00ADT\x00AST\x00-0330\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85-\xb9\xf8\x8a\x01\x00\x00\x8a\x01\x00\x00\x0d\x00\x00\x00America/BelemTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaatt\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xd2\x8c\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x89\xd8\xba\xee\x15\x04\x00\x00\x15\x04\x00\x00\x0e\x00\x00\x00America/BelizeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xff\x93^\xd9\xb0\xff\xff\xff\xff\x9f\x9f;\xe0\xff\xff\xff\xff\xa0EQ\xd8\xff\xff\xff\xff\xa1\x7f\x1d\xe0\xff\xff\xff\xff\xa2.nX\xff\xff\xff\xff\xa3^\xff\xe0\xff\xff\xff\xff\xa4\x0ePX\xff\xff\xff\xff\xa5>\xe1\xe0\xff\xff\xff\xff\xa5\xee2X\xff\xff\xff\xff\xa7'\xfe`\xff\xff\xff\xff\xa7\xce\x14X\xff\xff\xff\xff\xa9\x07\xe0`\xff\xff\xff\xff\xa9\xad\xf6X\xff\xff\xff\xff\xaa\xe7\xc2`\xff\xff\xff\xff\xab\x97\x12\xd8\xff\xff\xff\xff\xac\xc7\xa4`\xff\xff\xff\xff\xadv\xf4\xd8\xff\xff\xff\xff\xae\xa7\x86`\xff\xff\xff\xff\xafV\xd6\xd8\xff\xff\xff\xff\xb0\x87h`\xff\xff\xff\xff\xb16\xb8\xd8\xff\xff\xff\xff\xb2p\x84\xe0\xff\xff\xff\xff\xb3\x16\x9a\xd8\xff\xff\xff\xff\xb4Pf\xe0\xff\xff\xff\xff\xb4\xf6|\xd8\xff\xff\xff\xff\xb60H\xe0\xff\xff\xff\xff\xb6\xdf\x99X\xff\xff\xff\xff\xb8\x10*\xe0\xff\xff\xff\xff\xb8\xbf{X\xff\xff\xff\xff\xb9\xf0\x0c\xe0\xff\xff\xff\xff\xba\x9f]X\xff\xff\xff\xff\xbb\xd9)`\xff\xff\xff\xff\xbc\x7f?X\xff\xff\xff\xff\xbd\xb9\x0b`\xff\xff\xff\xff\xbe_!X\xff\xff\xff\xff\xbf\x98\xed`\xff\xff\xff\xff\xc0?\x03X\xff\xff\xff\xff\xc1x\xcf`\xff\xff\xff\xff\xc2(\x1f\xd8\xff\xff\xff\xff\xc3X\xb1`\xff\xff\xff\xff\xc4\x08\x01\xd8\xff\xff\xff\xff\xc58\x93`\xff\xff\xff\xff\xc5\xe7\xe3\xd8\xff\xff\xff\xff\xc7!\xaf\xe0\xff\xff\xff\xff\xc7\xc7\xc5\xd8\xff\xff\xff\xff\xc9\x01\x91\xe0\xff\xff\xff\xff\xc9\xa7\xa7\xd8\xff\xff\xff\xff\xca\xe1s\xe0\xff\xff\xff\xff\xcb\x90\xc4X\xff\xff\xff\xff\xcc@\x22\xe0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\xc6qP\xff\xff\xff\xff\xd6)\xfa`\xff\xff\xff\xff\xd6\xd9J\xd8\xff\xff\xff\xff\xd8\x09\xdc`\xff\xff\xff\xff\xd8\xb9,\xd8\xff\xff\xff\xff\xd9\xe9\xbe`\xff\xff\xff\xff\xda\x99\x0e\xd8\xff\xff\xff\xff\xdb\xd2\xda\xe0\xff\xff\xff\xff\xdcx\xf0\xd8\xff\xff\xff\xff\xdd\xb2\xbc\xe0\xff\xff\xff\xff\xdeX\xd2\xd8\xff\xff\xff\xff\xdf\x92\x9e\xe0\xff\xff\xff\xff\xe0A\xefX\xff\xff\xff\xff\xe1r\x80\xe0\xff\xff\xff\xff\xe2!\xd1X\xff\xff\xff\xff\xe3Rb\xe0\xff\xff\xff\xff\xe4\x01\xb3X\xff\xff\xff\xff\xe52D\xe0\xff\xff\xff\xff\xe5\xe1\x95X\xff\xff\xff\xff\xe7\x1ba`\xff\xff\xff\xff\xe7\xc1wX\xff\xff\xff\xff\xe8\xfbC`\xff\xff\xff\xff\xe9\xa1YX\xff\xff\xff\xff\xea\xdb%`\xff\xff\xff\xff\xeb\x8au\xd8\xff\xff\xff\xff\xec\xbb\x07`\xff\xff\xff\xff\xedjW\xd8\xff\xff\xff\xff\xee\x9a\xe9`\xff\xff\xff\xff\xefJ9\xd8\xff\xff\xff\xff\xf0\x84\x05\xe0\xff\xff\xff\xff\xf1*\x1b\xd8\xff\xff\xff\xff\xf2c\xe7\xe0\xff\xff\xff\xff\xf3\x09\xfd\xd8\xff\xff\xff\xff\xf4C\xc9\xe0\xff\xff\xff\xff\xf4\xe9\xdf\xd8\xff\xff\xff\xff\xf6#\xab\xe0\xff\xff\xff\xff\xf6\xd2\xfcX\xff\xff\xff\xff\xf8\x03\x8d\xe0\xff\xff\xff\xff\xf8\xb2\xdeX\xff\xff\xff\xff\xf9\xe3o\xe0\xff\xff\xff\xff\xfa\x92\xc0X\xff\xff\xff\xff\xfb\xcc\x8c`\xff\xff\xff\xff\xfcr\xa2X\x00\x00\x00\x00\x07b\xdb`\x00\x00\x00\x00\x07\xb9\xd0P\x00\x00\x00\x00\x18aq`\x00\x00\x00\x00\x18\xab7P\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x05\x02\xff\xff\xadP\x00\x00\xff\xff\xb2\xa8\x01\x04\xff\xff\xab\xa0\x00\x0a\xff\xff\xb9\xb0\x01\x0e\xff\xff\xb9\xb0\x01\x12\xff\xff\xb9\xb0\x01\x16LMT\x00-0530\x00CST\x00CWT\x00CPT\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x14\x00\x00\x00America/Blanc-SablonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8Dz\x97\xae\x01\x00\x00\xae\x01\x00\x00\x11\x00\x00\x00America/Boa_VistaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x7f\xe0\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x007\xf6\xd4\xc0\x00\x00\x00\x008\xb8\x930\x00\x00\x00\x009\xdf\xf1@\x00\x00\x00\x009\xe9\x1d\xb0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc7 \x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,g\xec\xec\xb3\x00\x00\x00\xb3\x00\x00\x00\x0e\x00\x00\x00America/BogotaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff^\x9c4\xf0\xff\xff\xff\xff\x98XUp\x00\x00\x00\x00*\x03sP\x00\x00\x00\x00+t\x89@\x01\x03\x02\x03\xff\xff\xba\x90\x00\x00\xff\xff\xba\x90\x00\x04\xff\xff\xc7\xc0\x01\x08\xff\xff\xb9\xb0\x00\x0cLMT\x00BMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\xbe\x1a>\xe7\x03\x00\x00\xe7\x03\x00\x00\x0d\x00\x00\x00America/BoiseTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Z\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x04\x1a\xc0\xff\xff\xff\xff\x9e\xa6H\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xa0\x86*\xa0\xff\xff\xff\xff\xa1\x9a\xf7\x90\xff\xff\xff\xff\xa8FL \xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\xb2\x1f\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x05\x03\x04\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\x93\x0f\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\x9d\x90\x00\x14\xff\xff\xab\xa0\x01\x18LMT\x00PDT\x00PST\x00MWT\x00MPT\x00MST\x00MDT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xbf\xf5\xe5\xc4\x02\x00\x00\xc4\x02\x00\x00\x14\x00\x00\x00America/Buenos_AiresTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xa8L\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x04\x05\x04\x05\xff\xff\xc94\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\xba\xb2\x94s\x03\x00\x00s\x03\x00\x00\x15\x00\x00\x00America/Cambridge_BayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L\x00\x00\x00\x08\x00\x00\x00 \xff\xff\xff\xff\xa1\xf2\xcd\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xdd\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xbf\x90\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\x04\xe9P\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x03\x01\x02\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x05\x07\x06\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x00\x00\x00\x00\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\xab\xa0\x01\x08\xff\xff\x9d\x90\x00\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xb9\xb0\x01\x14\xff\xff\xab\xa0\x00\x18\xff\xff\xb9\xb0\x00\x1c-00\x00MWT\x00MPT\x00MST\x00MDT\x00CDT\x00CST\x00EST\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\xfbn\xdb\xb8\x03\x00\x00\xb8\x03\x00\x00\x14\x00\x00\x00America/Campo_GrandeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaaz4\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00#X\x1e\xc0\x00\x00\x00\x00#\xe2~0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xd4\xd50\x00\x00\x00\x00'!\x1d@\x00\x00\x00\x00'\xbd\xf1\xb0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\x94\x990\x00\x00\x00\x00*\xea\x1b\xc0\x00\x00\x00\x00+k@\xb0\x00\x00\x00\x00,\xc0\xc3@\x00\x00\x00\x00-f\xd20\x00\x00\x00\x00.\xa0\xa5@\x00\x00\x00\x00/F\xb40\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001\x1d[\xb0\x00\x00\x00\x002W.\xc0\x00\x00\x00\x003\x06x0\x00\x00\x00\x0048b@\x00\x00\x00\x004\xf8\xcf0\x00\x00\x00\x006 -@\x00\x00\x00\x006\xcfv\xb0\x00\x00\x00\x007\xf6\xd4\xc0\x00\x00\x00\x008\xb8\x930\x00\x00\x00\x009\xdf\xf1@\x00\x00\x00\x00:\x8f:\xb0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00N\xfe\xb0\x00\x00\x00\x00?\x92\x0c@\x00\x00\x00\x00@.\xe0\xb0\x00\x00\x00\x00A\x87\x06@\x00\x00\x00\x00B\x17\xfd0\x00\x00\x00\x00CQ\xd0@\x00\x00\x00\x00C\xf7\xdf0\x00\x00\x00\x00EMa\xc0\x00\x00\x00\x00E\xe0\xfb\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xb7\xa30\x00\x00\x00\x00H\xfa\xb0\xc0\x00\x00\x00\x00I\x97\x850\x00\x00\x00\x00J\xda\x92\xc0\x00\x00\x00\x00K\x80\xa1\xb0\x00\x00\x00\x00L\xbat\xc0\x00\x00\x00\x00M`\x83\xb0\x00\x00\x00\x00N\x9aV\xc0\x00\x00\x00\x00OI\xa00\x00\x00\x00\x00P\x83s@\x00\x00\x00\x00Q G\xb0\x00\x00\x00\x00RcU@\x00\x00\x00\x00S\x00)\xb0\x00\x00\x00\x00TC7@\x00\x00\x00\x00T\xe9F0\x00\x00\x00\x00V#\x19@\x00\x00\x00\x00V\xc9(0\x00\x00\x00\x00X\x02\xfb@\x00\x00\x00\x00X\xa9\x0a0\x00\x00\x00\x00Y\xe2\xdd@\x00\x00\x00\x00Z\x88\xec0\x00\x00\x00\x00[\xden\xc0\x00\x00\x00\x00\x5ch\xce0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xcc\xcc\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf2\x04\xde\xdd\x11\x02\x00\x00\x11\x02\x00\x00\x0e\x00\x00\x00America/CancunTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xda`\x00\x00\x00\x00\x16\x86\xd5`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x005\xc4\x00`\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00T\xcd\xdd\x00\x01\x03\x02\x03\x02\x03\x02\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\xff\xff\xae\xa8\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xc7\xc0\x01\x08\xff\xff\xb9\xb0\x00\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00CST\x00EDT\x00EST\x00CDT\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x8e\xee\x13\xbe\x00\x00\x00\xbe\x00\x00\x00\x0f\x00\x00\x00America/CaracasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffi\x87\x1a@\xff\xff\xff\xff\x93\x1e,<\xff\xff\xff\xff\xf6\x98\xecH\x00\x00\x00\x00G[\x92p\x00\x00\x00\x00W%\xa9p\x01\x02\x03\x02\x03\xff\xff\xc1@\x00\x00\xff\xff\xc1D\x00\x04\xff\xff\xc0\xb8\x00\x08\xff\xff\xc7\xc0\x00\x0eLMT\x00CMT\x00-0430\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00\x11\x00\x00\x00America/CatamarcaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xaf,\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xc2T\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1'\x07\xbd\x97\x00\x00\x00\x97\x00\x00\x00\x0f\x00\x00\x00America/CayenneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x91\xf4+\x90\xff\xff\xff\xff\xfb\xc35\xc0\x01\x02\xff\xff\xce\xf0\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-04\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x0e\x00\x00\x00America/CaymanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffi\x87&\x10\xff\xff\xff\xff\x8b\xf4a\xe8\x01\x02\xff\xff\xb5p\x00\x00\xff\xff\xb5\x18\x00\x04\xff\xff\xb9\xb0\x00\x08LMT\x00CMT\x00EST\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xdc\xa9=\xda\x06\x00\x00\xda\x06\x00\x00\x0f\x00\x00\x00America/ChicagoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xa2\xcbt\x00\xff\xff\xff\xff\xa3\x83\xf7\xf0\xff\xff\xff\xff\xa4E\xd2\x80\xff\xff\xff\xff\xa5c\xd9\xf0\xff\xff\xff\xff\xa6S\xd9\x00\xff\xff\xff\xff\xa7\x15\x97p\xff\xff\xff\xff\xa83\xbb\x00\xff\xff\xff\xff\xa8\xfe\xb3\xf0\xff\xff\xff\xff\xaa\x13\x9d\x00\xff\xff\xff\xff\xaa\xde\x95\xf0\xff\xff\xff\xff\xab\xf3\x7f\x00\xff\xff\xff\xff\xac\xbew\xf0\xff\xff\xff\xff\xad\xd3a\x00\xff\xff\xff\xff\xae\x9eY\xf0\xff\xff\xff\xff\xaf\xb3C\x00\xff\xff\xff\xff\xb0~;\xf0\xff\xff\xff\xff\xb1\x9c_\x80\xff\xff\xff\xff\xb2gXp\xff\xff\xff\xff\xb3|A\x80\xff\xff\xff\xff\xb4G:p\xff\xff\xff\xff\xb5\x5c#\x80\xff\xff\xff\xff\xb6'\x1cp\xff\xff\xff\xff\xb7<\x05\x80\xff\xff\xff\xff\xb8\x06\xfep\xff\xff\xff\xff\xb9\x1b\xe7\x80\xff\xff\xff\xff\xb9\xe6\xe0p\xff\xff\xff\xff\xbb\x05\x04\x00\xff\xff\xff\xff\xbb\xc6\xc2p\xff\xff\xff\xff\xbc\xe4\xe6\x00\xff\xff\xff\xff\xbd\xaf\xde\xf0\xff\xff\xff\xff\xbe\xc4\xc8\x00\xff\xff\xff\xff\xbf\x8f\xc0\xf0\xff\xff\xff\xff\xc0Z\xd6\x00\xff\xff\xff\xff\xc1\xb0\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xad\xd4\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x01\x14LMT\x00CDT\x00CST\x00EST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x111\x04q\xb3\x02\x00\x00\xb3\x02\x00\x00\x11\x00\x00\x00America/ChihuahuaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\xb8U\x10\x00\x00\x00\x00L\xcd\x22\x00\x00\x00\x00\x00M\x987\x10\x00\x00\x00\x00N\xad\x04\x00\x00\x00\x00\x00Ox\x19\x10\x00\x00\x00\x00P\x8c\xe6\x00\x00\x00\x00\x00Qa5\x90\x00\x00\x00\x00Rl\xc8\x00\x00\x00\x00\x00SA\x17\x90\x00\x00\x00\x00TL\xaa\x00\x00\x00\x00\x00U \xf9\x90\x00\x00\x00\x00V,\x8c\x00\x00\x00\x00\x00W\x00\xdb\x90\x00\x00\x00\x00X\x15\xa8\x80\x00\x00\x00\x00X\xe0\xbd\x90\x00\x00\x00\x00Y\xf5\x8a\x80\x00\x00\x00\x00Z\xc0\x9f\x90\x00\x00\x00\x00[\xd5l\x80\x00\x00\x00\x00\x5c\xa9\xbc\x10\x00\x00\x00\x00]\xb5N\x80\x00\x00\x00\x00^\x89\x9e\x10\x00\x00\x00\x00_\x950\x80\x00\x00\x00\x00`i\x80\x10\x00\x00\x00\x00a~M\x00\x00\x00\x00\x00bIb\x10\x00\x00\x00\x00c^/\x00\x01\x02\x01\x03\x01\x02\x04\x02\x04\x02\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x02\xff\xff\x9c\x8c\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00MST\x00CST\x00MDT\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad\xf2L\x06\xce\x02\x00\x00\xce\x02\x00\x00\x15\x00\x00\x00America/Ciudad_JuarezTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\x9c\xa5\x90\x00\x00\x00\x00L\xd6\x5c\x80\x00\x00\x00\x00M|\x87\x90\x00\x00\x00\x00N\xb6>\x80\x00\x00\x00\x00O\x5ci\x90\x00\x00\x00\x00P\x96 \x80\x00\x00\x00\x00Q3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb1\xdd\x82x\xe8\x00\x00\x00\xe8\x00\x00\x00\x12\x00\x00\x00America/Costa_RicaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xffi\x87*M\xff\xff\xff\xff\xa3\xe8\x16M\x00\x00\x00\x00\x116I`\x00\x00\x00\x00\x11\xb7nP\x00\x00\x00\x00\x13\x16+`\x00\x00\x00\x00\x13\x97PP\x00\x00\x00\x00'\x97\xe0`\x00\x00\x00\x00(n\xb6\xd0\x00\x00\x00\x00)w\xc2`\x00\x00\x00\x00)\xc2\xd9\xd0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xb13\x00\x00\xff\xff\xb13\x00\x04\xff\xff\xb9\xb0\x01\x09\xff\xff\xab\xa0\x00\x0dLMT\x00SJMT\x00CDT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0f\x00\x00\x00America/CrestonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xcf\x17\xdf\x1c\xff\xff\xff\xff\xcf\x8f\xe5\xac\xff\xff\xff\xff\xd0\x81\x1a\x1c\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\x02\x01\x02\x01\x02\x03\x02\x03\x02\x01\x02\xff\xff\x96\xee\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0cLMT\x00MDT\x00MST\x00MWT\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f$*\xa0\xa6\x03\x00\x00\xa6\x03\x00\x00\x0e\x00\x00\x00America/CuiabaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa{\x94\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00#X\x1e\xc0\x00\x00\x00\x00#\xe2~0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xd4\xd50\x00\x00\x00\x00'!\x1d@\x00\x00\x00\x00'\xbd\xf1\xb0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\x94\x990\x00\x00\x00\x00*\xea\x1b\xc0\x00\x00\x00\x00+k@\xb0\x00\x00\x00\x00,\xc0\xc3@\x00\x00\x00\x00-f\xd20\x00\x00\x00\x00.\xa0\xa5@\x00\x00\x00\x00/F\xb40\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001\x1d[\xb0\x00\x00\x00\x002W.\xc0\x00\x00\x00\x003\x06x0\x00\x00\x00\x0048b@\x00\x00\x00\x004\xf8\xcf0\x00\x00\x00\x006 -@\x00\x00\x00\x006\xcfv\xb0\x00\x00\x00\x007\xf6\xd4\xc0\x00\x00\x00\x008\xb8\x930\x00\x00\x00\x009\xdf\xf1@\x00\x00\x00\x00:\x8f:\xb0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00N\xfe\xb0\x00\x00\x00\x00A\x87\x06@\x00\x00\x00\x00B\x17\xfd0\x00\x00\x00\x00CQ\xd0@\x00\x00\x00\x00C\xf7\xdf0\x00\x00\x00\x00EMa\xc0\x00\x00\x00\x00E\xe0\xfb\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xb7\xa30\x00\x00\x00\x00H\xfa\xb0\xc0\x00\x00\x00\x00I\x97\x850\x00\x00\x00\x00J\xda\x92\xc0\x00\x00\x00\x00K\x80\xa1\xb0\x00\x00\x00\x00L\xbat\xc0\x00\x00\x00\x00M`\x83\xb0\x00\x00\x00\x00N\x9aV\xc0\x00\x00\x00\x00OI\xa00\x00\x00\x00\x00P\x83s@\x00\x00\x00\x00Q G\xb0\x00\x00\x00\x00RcU@\x00\x00\x00\x00S\x00)\xb0\x00\x00\x00\x00TC7@\x00\x00\x00\x00T\xe9F0\x00\x00\x00\x00V#\x19@\x00\x00\x00\x00V\xc9(0\x00\x00\x00\x00X\x02\xfb@\x00\x00\x00\x00X\xa9\x0a0\x00\x00\x00\x00Y\xe2\xdd@\x00\x00\x00\x00Z\x88\xec0\x00\x00\x00\x00[\xden\xc0\x00\x00\x00\x00\x5ch\xce0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xcbl\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00America/CuracaoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k\xc2\x0dx\xbf\x01\x00\x00\xbf\x01\x00\x00\x14\x00\x00\x00America/DanmarkshavnTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x9b\x80I\x00\x00\x00\x00\x00\x13M|P\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x00\x00\x00\x00G-\x8a\x10\x00\x00\x00\x00G\xd3\xb5 \x00\x00\x00\x00I\x0dl\x10\x00\x00\x00\x00I\xb3\x97 \x00\x00\x00\x00J\xedN\x10\x00\x00\x00\x00K\x9c\xb3\xa0\x00\x00\x00\x00L\xd6j\x90\x00\x00\x00\x00M|\x95\xa0\x00\x00\x00\x00N\xb6L\x90\x00\x00\x00\x00O\x5cw\xa0\x00\x00\x00\x00P\x96.\x90\x00\x00\x00\x00Q\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x9d\x94\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x14\xe7\x03\x83\x03\x00\x00\x83\x03\x00\x00\x0f\x00\x00\x00America/DetroitTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x85\xbd\x22[\xff\xff\xff\xff\x99<\x94\x00\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xfb3\x90\x8c\xff\xff\xff\xff\xfb\xe8;\xe0\xff\xff\xff\xff\xfc\xd8:\xf0\xff\xff\xff\xff\xfd\xc8\x1d\xe0\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x0a\x00\xa3p\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\xff\xff\xb2%\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10\xff\xff\xc7\xc0\x01\x14LMT\x00CST\x00EST\x00EWT\x00EPT\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00America/DominicaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x10\x00\x00\x00America/EdmontonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x88\xde\xce\xe0\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x98\x91\x90\xff\xff\xff\xff\xa0\xd2\x85\x80\xff\xff\xff\xff\xa2\x8a\xe8\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4j\xca\x90\xff\xff\xff\xff\xa55\xc3\x80\xff\xff\xff\xff\xa6S\xe7\x10\xff\xff\xff\xff\xa7\x15\xa5\x80\xff\xff\xff\xff\xa83\xc9\x10\xff\xff\xff\xff\xa8\xfe\xc2\x00\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xdd\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xbf\x90\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x95\xa0\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\xb0\xeau\xb4\x01\x00\x00\xb4\x01\x00\x00\x10\x00\x00\x00America/EirunepeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x88\x80\xff\xff\xff\xff\xb8\x0ff\x00\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xf1PP\xff\xff\xff\xff\xba\xde\x90@\xff\xff\xff\xff\xda8\xcaP\xff\xff\xff\xff\xda\xec\x16P\xff\xff\xff\xff\xdc\x19\xfd\xd0\xff\xff\xff\xff\xdc\xb9u@\xff\xff\xff\xff\xdd\xfb1P\xff\xff\xff\xff\xde\x9b\xfa@\xff\xff\xff\xff\xdf\xdd\xb6P\xff\xff\xff\xff\xe0TO@\xff\xff\xff\xff\xf4\x98\x1b\xd0\xff\xff\xff\xff\xf5\x05z@\xff\xff\xff\xff\xf6\xc0\x80P\xff\xff\xff\xff\xf7\x0e:\xc0\xff\xff\xff\xff\xf8QHP\xff\xff\xff\xff\xf8\xc7\xe1@\xff\xff\xff\xff\xfa\x0a\xee\xd0\xff\xff\xff\xff\xfa\xa9\x14\xc0\xff\xff\xff\xff\xfb\xec\x22P\xff\xff\xff\xff\xfc\x8b\x99\xc0\x00\x00\x00\x00\x1d\xc9\xaaP\x00\x00\x00\x00\x1ex\xf3\xc0\x00\x00\x00\x00\x1f\xa0Q\xd0\x00\x00\x00\x00 3\xeb\xc0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22\x0b\xe4\xc0\x00\x00\x00\x00,\xc0\xd1P\x00\x00\x00\x00-f\xe0@\x00\x00\x00\x00H`\x7fP\x00\x00\x00\x00R\x7f\x04\xc0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\xff\xff\xbe\x80\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x04LMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea$\xc1\xbf\xb0\x00\x00\x00\xb0\x00\x00\x00\x13\x00\x00\x00America/El_SalvadorTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa3\xd5\xa6 \x00\x00\x00\x00 \x9a\xdc\xe0\x00\x00\x00\x00!\x5c\x9bP\x00\x00\x00\x00\x22z\xbe\xe0\x00\x00\x00\x00#<}P\x02\x01\x02\x01\x02\xff\xff\xac`\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08LMT\x00CDT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x10\x00\x00\x00America/EnsenadaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xa9yOp\xff\xff\xff\xff\xaf\xf2|\xf0\xff\xff\xff\xff\xb6fdp\xff\xff\xff\xff\xb7\x1b\x10\x00\xff\xff\xff\xff\xb8\x0a\xf2\xf0\xff\xff\xff\xff\xcb\xea\x8d\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\x99\xbap\xff\xff\xff\xff\xd7\x1bY\x00\xff\xff\xff\xff\xd8\x91\xb4\xf0\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00F\x0f\x82\xa0\x00\x00\x00\x00G$O\x90\x00\x00\x00\x00G\xf8\x9f \x00\x00\x00\x00I\x041\x90\x00\x00\x00\x00I\xd8\x81 \x00\x00\x00\x00J\xe4\x13\x90\x00\x00\x00\x00K=\xab\x80\x01\x02\x01\x02\x03\x02\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x02\xff\xff\x92L\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x9d\x90\x01\x14LMT\x00MST\x00PST\x00PDT\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6@\x0dm\xa8\x05\x00\x00\xa8\x05\x00\x00\x13\x00\x00\x00America/Fort_NelsonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^=v\x87\xff\xff\xff\xff\x9e\xb8\xbd\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd5U\xf1 \xff\xff\xff\xff\xd6 \xea\x10\xff\xff\xff\xff\xd75\xd3 \xff\xff\xff\xff\xd8\x00\xcc\x10\xff\xff\xff\xff\xd9\x15\xb5 \xff\xff\xff\xff\xd9\xe0\xae\x10\xff\xff\xff\xff\xda\xfe\xd1\xa0\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xb3\xa0\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x95\xa0\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ew\xa0\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~Y\xa0\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^;\xa0\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GX \xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8': \xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x1c \xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xfe \xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xe0 \xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xfc\xa0\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xde\xa0\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xc0\xa0\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\xa2\xa0\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/\x84\xa0\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0ff\xa0\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x08 \xeb\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x0a\x00\xcd\xa0\x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x00\x00\x00\x00G-\x8a\x10\x00\x00\x00\x00G\xd3\xb5 \x00\x00\x00\x00I\x0dl\x10\x00\x00\x00\x00I\xb3\x97 \x00\x00\x00\x00J\xedN\x10\x00\x00\x00\x00K\x9c\xb3\xa0\x00\x00\x00\x00L\xd6j\x90\x00\x00\x00\x00M|\x95\xa0\x00\x00\x00\x00N\xb6L\x90\x00\x00\x00\x00O\x5cw\xa0\x00\x00\x00\x00P\x96.\x90\x00\x00\x00\x00Q3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\x94\xc7Kp\x03\x00\x00p\x03\x00\x00\x11\x00\x00\x00America/Glace_BayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x80\xf1\xa84\xff\xff\xff\xff\x9e\xb8\x85`\xff\xff\xff\xff\x9f\xba\xddP\xff\xff\xff\xff\xcb\x88\xe2`\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\xff\xff\xff\xff\xe0\x9e?`\xff\xff\xff\xff\xe1i8P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x06@\xd1`\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xc7\xcc\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00ADT\x00AST\x00AWT\x00APT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xf9v\x14\xc5\x03\x00\x00\xc5\x03\x00\x00\x0f\x00\x00\x00America/GodthabTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x9b\x80h\x00\x00\x00\x00\x00\x13M|P\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7l\x90\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V,)\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00X\x15F\x10\x00\x00\x00\x00X\xd7\x12\x90\x00\x00\x00\x00Y\xf5(\x10\x00\x00\x00\x00Z\xb6\xf4\x90\x00\x00\x00\x00[\xd5\x0a\x10\x00\x00\x00\x00\x5c\xa0\x11\x10\x00\x00\x00\x00]\xb4\xec\x10\x00\x00\x00\x00^\x7f\xf3\x10\x00\x00\x00\x00_\x94\xce\x10\x00\x00\x00\x00`_\xd5\x10\x00\x00\x00\x00a}\xea\x90\x00\x00\x00\x00b?\xb7\x10\x00\x00\x00\x00c]\xcc\x90\x00\x00\x00\x00d\x1f\x99\x10\x00\x00\x00\x00e=\xae\x90\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x03\xff\xff\xcf\x80\x00\x00\xff\xff\xd5\xd0\x00\x04\xff\xff\xe3\xe0\x01\x08\xff\xff\xe3\xe0\x00\x08LMT\x00-03\x00-02\x00\x0a<-02>2<-01>,M3.5.0/-1,M10.5.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\x85\xf6\xd1,\x06\x00\x00,\x06\x00\x00\x11\x00\x00\x00America/Goose_BayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98\x00\x00\x00\x0a\x00\x00\x00!\xff\xff\xff\xff^=<$\xff\xff\xff\xff\x9e\xb8~\x8c\xff\xff\xff\xff\x9f\xba\xd6|\xff\xff\xff\xff\xbe\x9eMl\xff\xff\xff\xff\xc0\xb818\xff\xff\xff\xff\xc1y\xef\xa8\xff\xff\xff\xff\xc2\x98\x138\xff\xff\xff\xff\xc3Y\xd1\xa8\xff\xff\xff\xff\xc4w\xf58\xff\xff\xff\xff\xc59\xb3\xa8\xff\xff\xff\xff\xc6a\x11\xb8\xff\xff\xff\xff\xc7\x19\x95\xa8\xff\xff\xff\xff\xc8@\xf3\xb8\xff\xff\xff\xff\xc9\x02\xb2(\xff\xff\xff\xff\xca \xd5\xb8\xff\xff\xff\xff\xca\xe2\x94(\xff\xff\xff\xff\xcc\x00\xb7\xb8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xe6\xc8\xff\xff\xff\xff\xd3\x88D\xd8\xff\xff\xff\xff\xd4J\x03H\xff\xff\xff\xff\xd5h&\xd8\xff\xff\xff\xff\xd6)\xe5H\xff\xff\xff\xff\xd7H\x08\xd8\xff\xff\xff\xff\xd8\x09\xc7H\xff\xff\xff\xff\xd9'\xea\xd8\xff\xff\xff\xff\xd9\xe9\xa9H\xff\xff\xff\xff\xdb\x11\x07X\xff\xff\xff\xff\xdb\xd2\xc5\xc8\xff\xff\xff\xff\xdc\xdetX\xff\xff\xff\xff\xdd\xa9mH\xff\xff\xff\xff\xde\xbeVX\xff\xff\xff\xff\xdf\x89OH\xff\xff\xff\xff\xe0\x9e8X\xff\xff\xff\xff\xe1i1H\xff\xff\xff\xff\xe2~\x1aX\xff\xff\xff\xff\xe3I\x13H\xff\xff\xff\xff\xe4]\xfcX\xff\xff\xff\xff\xe5(\xf5H\xff\xff\xff\xff\xe6G\x18\xd8\xff\xff\xff\xff\xe7\x12\x11\xc8\xff\xff\xff\xff\xe8&\xfa\xd8\xff\xff\xff\xff\xe8\xf1\xf3\xc8\xff\xff\xff\xff\xea\x06\xdc\xd8\xff\xff\xff\xff\xea\xd1\xd5\xc8\xff\xff\xff\xff\xeb\xe6\xbe\xd8\xff\xff\xff\xff\xec\xb1\xb7\xc8\xff\xff\xff\xff\xed\xc6\xa0\xd8\xff\xff\xff\xff\xee\xbf\xbeH\xff\xff\xff\xff\xef\xaf\xbdX\xff\xff\xff\xff\xf0\x9f\xa0H\xff\xff\xff\xff\xf1\x8f\x9fX\xff\xff\xff\xff\xf2\x7f\x82H\xff\xff\xff\xff\xf3o\x81X\xff\xff\xff\xff\xf4_dH\xff\xff\xff\xff\xf5OcX\xff\xff\xff\xff\xf6?FH\xff\xff\xff\xff\xf7/EX\xff\xff\xff\xff\xf8(b\xc8\xff\xff\xff\xff\xf8\xdakX\xff\xff\xff\xff\xf9\x0f.`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xf8J\xe0\xff\xff\xff\xff\xfb\xe8-\xd0\xff\xff\xff\xff\xfc\xd8,\xe0\xff\xff\xff\xff\xfd\xc8\x0f\xd0\xff\xff\xff\xff\xfe\xb8\x0e\xe0\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00\x97\xf0\xe0\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x02w\xd2\xe0\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x06@\xd1`\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xd6\xfc\x00\x00\x00\x00!\x81il\x00\x00\x00\x00\x22U\xb8\xfc\x00\x00\x00\x00#jw\xdc\x00\x00\x00\x00$5\x9a\xfc\x00\x00\x00\x00%Jg\xec\x00\x00\x00\x00&\x15|\xfc\x00\x00\x00\x00'*I\xec\x00\x00\x00\x00'\xfe\x99|\x00\x00\x00\x00)\x0a+\xec\x00\x00\x00\x00)\xde{|\x00\x00\x00\x00*\xea\x0d\xec\x00\x00\x00\x00+\xbe]|\x00\x00\x00\x00,\xd3*l\x00\x00\x00\x00-\x9e?|\x00\x00\x00\x00.\xb3\x0cl\x00\x00\x00\x00/~!|\x00\x00\x00\x000\x92\xeel\x00\x00\x00\x001g=\xfc\x00\x00\x00\x002r\xd0l\x00\x00\x00\x003G\x1f\xfc\x00\x00\x00\x004R\xb2l\x00\x00\x00\x005'\x01\xfc\x00\x00\x00\x0062\x94l\x00\x00\x00\x007\x06\xe3\xfc\x00\x00\x00\x008\x1b\xb0\xec\x00\x00\x00\x008\xe6\xc5\xfc\x00\x00\x00\x009\xfb\x92\xec\x00\x00\x00\x00:\xc6\xa7\xfc\x00\x00\x00\x00;\xdbt\xec\x00\x00\x00\x00<\xaf\xc4|\x00\x00\x00\x00=\xbbV\xec\x00\x00\x00\x00>\x8f\xa6|\x00\x00\x00\x00?\x9b8\xec\x00\x00\x00\x00@o\x88|\x00\x00\x00\x00A\x84Ul\x00\x00\x00\x00BOj|\x00\x00\x00\x00Cd7l\x00\x00\x00\x00D/L|\x00\x00\x00\x00ED\x19l\x00\x00\x00\x00E\xf3~\xfc\x00\x00\x00\x00G-5\xec\x00\x00\x00\x00G\xd3`\xfc\x00\x00\x00\x00I\x0d\x17\xec\x00\x00\x00\x00I\xb3B\xfc\x00\x00\x00\x00J\xec\xf9\xec\x00\x00\x00\x00K\x9c_|\x00\x00\x00\x00L\xd6\x16l\x00\x00\x00\x00M|A|\x00\x00\x00\x00N\xaf`\xb0\x01\x02\x01\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x06\x05\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x09\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x07\xff\xff\xc7\x5c\x00\x00\xff\xff\xce\x94\x00\x04\xff\xff\xdc\xa4\x01\x08\xff\xff\xce\xc8\x00\x04\xff\xff\xdc\xd8\x01\x08\xff\xff\xdc\xd8\x01\x0c\xff\xff\xdc\xd8\x01\x10\xff\xff\xd5\xd0\x01\x14\xff\xff\xc7\xc0\x00\x18\xff\xff\xe3\xe0\x01\x1cLMT\x00NST\x00NDT\x00NPT\x00NWT\x00ADT\x00AST\x00ADDT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xc9I\xd0U\x03\x00\x00U\x03\x00\x00\x12\x00\x00\x00America/Grand_TurkTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x1e0\xff\xff\xff\xff\x93\x0f\xb4\xfe\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x00\x00\x00\x00G-_\xe0\x00\x00\x00\x00G\xd3\x8a\xf0\x00\x00\x00\x00I\x0dA\xe0\x00\x00\x00\x00I\xb3l\xf0\x00\x00\x00\x00J\xed#\xe0\x00\x00\x00\x00K\x9c\x89p\x00\x00\x00\x00L\xd6@`\x00\x00\x00\x00M|kp\x00\x00\x00\x00N\xb6\x22`\x00\x00\x00\x00O\x5cMp\x00\x00\x00\x00P\x96\x04`\x00\x00\x00\x00Q5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x05\xf3\x89\xb5\x00\x00\x00\xb5\x00\x00\x00\x0e\x00\x00\x00America/GuyanaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x92\x1d\x0f\x87\xff\xff\xff\xff\x98\xd9{@\x00\x00\x00\x00\x0a\x7f\x05\xbc\x00\x00\x00\x00)\xd5@\xc0\x01\x02\x03\x01\xff\xff\xc9y\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xcbD\x00\x08\xff\xff\xd5\xd0\x00\x0eLMT\x00-04\x00-0345\x00-03\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00):\x17-\x88\x06\x00\x00\x88\x06\x00\x00\x0f\x00\x00\x00America/HalifaxTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x80\xf1\xab\xa0\xff\xff\xff\xff\x9a\xe4\xde\xc0\xff\xff\xff\xff\x9b\xd6\x130\xff\xff\xff\xff\x9e\xb8\x85`\xff\xff\xff\xff\x9f\xba\xddP\xff\xff\xff\xff\xa2\x9d\x17@\xff\xff\xff\xff\xa30\xb10\xff\xff\xff\xff\xa4zV@\xff\xff\xff\xff\xa5\x1b\x1f0\xff\xff\xff\xff\xa6S\xa0\xc0\xff\xff\xff\xff\xa6\xfcR\xb0\xff\xff\xff\xff\xa8<\xbd@\xff\xff\xff\xff\xa8\xdc4\xb0\xff\xff\xff\xff\xaa\x1c\x9f@\xff\xff\xff\xff\xaa\xcd:0\xff\xff\xff\xff\xab\xfc\x81@\xff\xff\xff\xff\xac\xbf\x910\xff\xff\xff\xff\xad\xee\xd8@\xff\xff\xff\xff\xae\x8c\xfe0\xff\xff\xff\xff\xaf\xbcE@\xff\xff\xff\xff\xb0\x7fU0\xff\xff\xff\xff\xb1\xae\x9c@\xff\xff\xff\xff\xb2Kp\xb0\xff\xff\xff\xff\xb3\x8e~@\xff\xff\xff\xff\xb4$\xbb0\xff\xff\xff\xff\xb5n`@\xff\xff\xff\xff\xb6\x15\xc0\xb0\xff\xff\xff\xff\xb7NB@\xff\xff\xff\xff\xb8\x08\x17\xb0\xff\xff\xff\xff\xb9$\xe9\xc0\xff\xff\xff\xff\xb9\xe7\xf9\xb0\xff\xff\xff\xff\xbb\x04\xcb\xc0\xff\xff\xff\xff\xbb\xd1\x160\xff\xff\xff\xff\xbd\x00]@\xff\xff\xff\xff\xbd\x9d1\xb0\xff\xff\xff\xff\xbe\xf2\xb4@\xff\xff\xff\xff\xbf\x90\xda0\xff\xff\xff\xff\xc0\xd3\xe7\xc0\xff\xff\xff\xff\xc1^G0\xff\xff\xff\xff\xc2\x8d\x8e@\xff\xff\xff\xff\xc3P\x9e0\xff\xff\xff\xff\xc4mp@\xff\xff\xff\xff\xc50\x800\xff\xff\xff\xff\xc6r<@\xff\xff\xff\xff\xc7\x10b0\xff\xff\xff\xff\xc86n\xc0\xff\xff\xff\xff\xc8\xf9~\xb0\xff\xff\xff\xff\xca\x16P\xc0\xff\xff\xff\xff\xca\xd9`\xb0\xff\xff\xff\xff\xcb\x88\xe2`\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\xff\xff\xff\xff\xd3u\xd6\xe0\xff\xff\xff\xff\xd4@\xcf\xd0\xff\xff\xff\xff\xd5U\xb8\xe0\xff\xff\xff\xff\xd6 \xb1\xd0\xff\xff\xff\xff\xd75\x9a\xe0\xff\xff\xff\xff\xd8\x00\x93\xd0\xff\xff\xff\xff\xd9\x15|\xe0\xff\xff\xff\xff\xd9\xe0u\xd0\xff\xff\xff\xff\xdc\xde{`\xff\xff\xff\xff\xdd\xa9tP\xff\xff\xff\xff\xde\xbe]`\xff\xff\xff\xff\xdf\x89VP\xff\xff\xff\xff\xe0\x9e?`\xff\xff\xff\xff\xe1i8P\xff\xff\xff\xff\xe2~!`\xff\xff\xff\xff\xe3I\x1aP\xff\xff\xff\xff\xe6G\x1f\xe0\xff\xff\xff\xff\xe7\x12\x18\xd0\xff\xff\xff\xff\xe8'\x01\xe0\xff\xff\xff\xff\xe8\xf1\xfa\xd0\xff\xff\xff\xff\xea\x06\xe3\xe0\xff\xff\xff\xff\xea\xd1\xdc\xd0\xff\xff\xff\xff\xeb\xe6\xc5\xe0\xff\xff\xff\xff\xec\xb1\xbe\xd0\xff\xff\xff\xff\xf1\x8f\xa6`\xff\xff\xff\xff\xf2\x7f\x89P\xff\xff\xff\xff\xf3o\x88`\xff\xff\xff\xff\xf4_kP\xff\xff\xff\xff\xf5Oj`\xff\xff\xff\xff\xf6?MP\xff\xff\xff\xff\xf7/L`\xff\xff\xff\xff\xf8(i\xd0\xff\xff\xff\xff\xf9\x0f.`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xf8J\xe0\xff\xff\xff\xff\xfb\xe8-\xd0\xff\xff\xff\xff\xfc\xd8,\xe0\xff\xff\xff\xff\xfd\xc8\x0f\xd0\xff\xff\xff\xff\xfe\xb8\x0e\xe0\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00\x97\xf0\xe0\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x02w\xd2\xe0\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x06@\xd1`\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xc4`\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00ADT\x00AST\x00AWT\x00APT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x1c\x9e\x9a]\x04\x00\x00]\x04\x00\x00\x0e\x00\x00\x00America/HavanaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87(\xb8\xff\xff\xff\xff\xacb\xc2\x80\xff\xff\xff\xff\xb1\xd3\x94P\xff\xff\xff\xff\xb2t]@\xff\xff\xff\xff\xc8[f\xd0\xff\xff\xff\xff\xc8\xd3Q@\xff\xff\xff\xff\xca;H\xd0\xff\xff\xff\xff\xca\xbcm\xc0\xff\xff\xff\xff\xcc$eP\xff\xff\xff\xff\xcc\x9cO\xc0\xff\xff\xff\xff\xd1\xc4\x0bP\xff\xff\xff\xff\xd2;\xf5\xc0\xff\xff\xff\xff\xd3\xa3\xedP\xff\xff\xff\xff\xd4\x1b\xd7\xc0\xff\xff\xff\xff\xf7`\x05\xd0\xff\xff\xff\xff\xf7\xff}@\xff\xff\xff\xff\xf9=D\xd0\xff\xff\xff\xff\xf9\xe3S\xc0\xff\xff\xff\xff\xfa\xdb;\xd0\xff\xff\xff\xff\xfb\xa7\x86@\xff\xff\xff\xff\xfc\xc5\xa9\xd0\xff\xff\xff\xff\xfd\x87h@\xff\xff\xff\xff\xfe\xb8\x00\xd0\xff\xff\xff\xff\xff\xa7\xe3\xc0\x00\x00\x00\x00\x00\x97\xe2\xd0\x00\x00\x00\x00\x01\x87\xc5\xc0\x00\x00\x00\x00\x02w\xc4\xd0\x00\x00\x00\x00\x03p\xe2@\x00\x00\x00\x00\x04`\xe1P\x00\x00\x00\x00\x055\x14\xc0\x00\x00\x00\x00\x06@\xc3P\x00\x00\x00\x00\x07\x16H@\x00\x00\x00\x00\x08 \xa5P\x00\x00\x00\x00\x08\xf7{\xc0\x00\x00\x00\x00\x0a\x00\x87P\x00\x00\x00\x00\x0a\xf0j@\x00\x00\x00\x00\x0b\xe0iP\x00\x00\x00\x00\x0c\xd9\x86\xc0\x00\x00\x00\x00\x0d\xc0KP\x00\x00\x00\x00\x0e\xb9h\xc0\x00\x00\x00\x00\x0f\xb2\xa2P\x00\x00\x00\x00\x10}\x9b@\x00\x00\x00\x00\x11Q\xea\xd0\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x131\xcc\xd0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15[\x82\xd0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x17;d\xd0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x19\x1bF\xd0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xfb(\xd0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\xdb\x0a\xd0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ezSP\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 Z5P\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x22CQ\xd0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$#3\xd0\x00\x00\x00\x00%.\xc6@\x00\x00\x00\x00&\x15\x8a\xd0\x00\x00\x00\x00'\x17\xe2\xc0\x00\x00\x00\x00'\xfe\xa7P\x00\x00\x00\x00(\xf7\xd2\xd0\x00\x00\x00\x00)\xde\x89P\x00\x00\x00\x00*\xd7\xb4\xd0\x00\x00\x00\x00+\xbekP\x00\x00\x00\x00,\xb7\x96\xd0\x00\x00\x00\x00-\x9eMP\x00\x00\x00\x00.\x97x\xd0\x00\x00\x00\x00/~/P\x00\x00\x00\x000wZ\xd0\x00\x00\x00\x001gK\xd0\x00\x00\x00\x002W<\xd0\x00\x00\x00\x003G-\xd0\x00\x00\x00\x004@YP\x00\x00\x00\x005\x1d\xd5P\x00\x00\x00\x0062\xb0P\x00\x00\x00\x006\xfd\xb7P\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xd3\xd0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xb5\xd0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xd2P\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xb4P\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@f[\xd0\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x8c\xd0\x00\x00\x00\x00G$\x17P\x00\x00\x00\x00G\xdc\xa9P\x00\x00\x00\x00I\x03\xf9P\x00\x00\x00\x00I\xb3P\xd0\x00\x00\x00\x00J\xe3\xdbP\x00\x00\x00\x00K\x9cmP\x00\x00\x00\x00L\xcc\xf7\xd0\x00\x00\x00\x00M\x85\x89\xd0\x00\x00\x00\x00N\xbfN\xd0\x00\x00\x00\x00Ow\xe0\xd0\x00\x00\x00\x00P\x95\xf6P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xb2\xc8\x00\x00\xff\xff\xb2\xc0\x00\x04\xff\xff\xc7\xc0\x01\x08\xff\xff\xb9\xb0\x00\x0cLMT\x00HMT\x00CDT\x00CST\x00\x0aCST5CDT,M3.2.0/0,M11.1.0/1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4MS\x99\x1e\x01\x00\x00\x1e\x01\x00\x00\x12\x00\x00\x00America/HermosilloTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xcb\xeaq`\xff\xff\xff\xff\xd8\x91\xb4\xf0\x00\x00\x00\x00\x00\x00p\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x01\x02\x01\x03\x01\x02\x01\x04\x01\x03\x01\x03\x01\x03\x01\xff\xff\x97\xf8\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\x8f\x80\x00\x10LMT\x00MST\x00CST\x00MDT\x00PST\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x1c\x00\x00\x00America/Indiana/IndianapolisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcaW\x22\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf:\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x14\x00\x00\x00America/Indiana/KnoxTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5W<\xf0\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x01\x02\x01\xff\xff\xae\xca\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M/U\x9f7\x02\x00\x007\x02\x00\x00\x17\x00\x00\x00America/Indiana/MarengoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00\x02w\xe0\xf0\x00\x00\x00\x00\x03p\xfe`\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x01\x05\x06\x05\x06\x05\x06\xff\xff\xaf\x0d\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xd8N\x8c\xab\x02\x00\x00\xab\x02\x00\x00\x1a\x00\x00\x00America/Indiana/PetersburgTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xe4g=\xe0\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf2\x7f\xa5p\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xf5O\x86\x80\xff\xff\xff\xff\xf6?ip\xff\xff\xff\xff\xf7/h\x80\xff\xff\xff\xff\xfa\x08g\xf0\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x00\x00\x00\x00G-m\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x01\x02\x01\x05\xff\xff\xae-\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8\xb5K\xa6\x0a\x02\x00\x00\x0a\x02\x00\x00\x19\x00\x00\x00America/Indiana/Tell_CityTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xe4g=\xe0\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf2\x7f\xa5p\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xf5O\x86\x80\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x06\x05\x06\x05\x01\x02\x01\xff\xff\xae\xa9\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x17\x89}q\x01\x00\x00q\x01\x00\x00\x15\x00\x00\x00America/Indiana/VevayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00\x02w\xe0\xf0\x00\x00\x00\x00\x03p\xfe`\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xb0@\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\xedsp.\x02\x00\x00.\x02\x00\x00\x19\x00\x00\x00America/Indiana/VincennesTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4g=\xe0\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0q\x9e\xf0\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf2\x7f\xa5p\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xf5O\x86\x80\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x00\x00\x00\x00G-m\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x06\x05\x06\x05\x01\x02\x01\x05\xff\xff\xad\xf1\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfdH\xb79[\x02\x00\x00[\x02\x00\x00\x17\x00\x00\x00America/Indiana/WinamacTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5W<\xf0\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x06\x05\x06\x05\x01\x02\x06\xff\xff\xae\xcf\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x14\x00\x00\x00America/IndianapolisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcaW\x22\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf:\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xbc\x09o1\x03\x00\x001\x03\x00\x00\x0e\x00\x00\x00America/InuvikTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xe0\x06N\x80\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x08 \xeb\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x0a\x00\xcd\xa0\x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x00\x00\x00\x00\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x00\x0c\xff\xff\xab\xa0\x01\x10-00\x00PDT\x00PST\x00MST\x00MDT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xa0\xd6\x05W\x03\x00\x00W\x03\x00\x00\x0f\x00\x00\x00America/IqaluitTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00J\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff\xccl\xa1\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x08 \xc1p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x0a\x00\xa3p\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x04\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x06\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x00\x00\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10\xff\xff\xab\xa0\x00\x14\xff\xff\xb9\xb0\x01\x18-00\x00EPT\x00EST\x00EDT\x00EWT\x00CST\x00CDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%J\xd5\xebS\x01\x00\x00S\x01\x00\x00\x0f\x00\x00\x00America/JamaicaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87#~\xff\xff\xff\xff\x93\x0f\xb4\xfe\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\xff\xff\xb8\x02\x00\x00\xff\xff\xb8\x02\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0cLMT\x00KMT\x00EST\x00EDT\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00utZ\x1a\xb2\x02\x00\x00\xb2\x02\x00\x00\x0d\x00\x00\x00America/JujuyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xae\xb8\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'*W\xc0\x00\x00\x00\x00'\xe2\xdb\xb0\x00\x00\x00\x00(\xee\x8a@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x04\x05\x04\x05\x03\x05\x04\x05\xff\xff\xc2\xc8\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xc9\x1c\xd4\xc6\x03\x00\x00\xc6\x03\x00\x00\x0e\x00\x00\x00America/JuneauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x0a\x00\x00\x00&\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x872\xc5\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14Yc \x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x06\x02\x05\x02\x05\x02\x05\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xd3{\x00\x00\xff\xff\x81\xfb\x00\x00\xff\xff\x8f\x80\x00\x04\xff\xff\x9d\x90\x01\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x8f\x80\x01\x14\xff\xff\x81p\x00\x18\xff\xff\x8f\x80\x01\x1c\xff\xff\x81p\x00!LMT\x00PST\x00PWT\x00PPT\x00PDT\x00YDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdf\xe5\x8d\xc4\xda\x04\x00\x00\xda\x04\x00\x00\x1b\x00\x00\x00America/Kentucky/LouisvilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xa4s\xf7\x00\xff\xff\xff\xff\xa5\x16\x11p\xff\xff\xff\xff\xca\x0dN\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xd7\x1c\xff\xff\xff\xff\xd3\xa4\x09p\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe9\x17\x00\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xf6\xe2\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x1e\x90p\xff\xff\xff\xff\xfc\xd8:\xf0\xff\xff\xff\xff\xfd\xc8\x1d\xe0\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00\x02w\xe0\xf0\x00\x00\x00\x00\x03p\xfe`\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x01\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf\x9a\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x1a|J\xcc\x03\x00\x00\xcc\x03\x00\x00\x1b\x00\x00\x00America/Kentucky/MonticelloTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaE\xf0\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\xff\xff\xb0t\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xc7\xc0\x01\x14\xff\xff\xb9\xb0\x00\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EDT\x00EST\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x0f\x00\x00\x00America/Knox_INTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5W<\xf0\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x01\x02\x01\xff\xff\xae\xca\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00America/KralendijkTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad`\x12\xe9\xaa\x00\x00\x00\xaa\x00\x00\x00\x0e\x00\x00\x00America/La_PazTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87\x1bd\xff\xff\xff\xff\xb8\x1e\x96\xe4\xff\xff\xff\xff\xb8\xee\xd5\xd4\x01\x02\x03\xff\xff\xc0\x1c\x00\x00\xff\xff\xc0\x1c\x00\x04\xff\xff\xce,\x01\x08\xff\xff\xc7\xc0\x00\x0cLMT\x00CMT\x00BST\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe7\xa1\x87\x1b\x01\x00\x00\x1b\x01\x00\x00\x0c\x00\x00\x00America/LimaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xffi\x87#\xbc\xff\xff\xff\xff\x8ct@\xd4\xff\xff\xff\xff\xc3\xcfJP\xff\xff\xff\xff\xc4E\xe3@\xff\xff\xff\xff\xc5/J\xd0\xff\xff\xff\xff\xc6\x1f-\xc0\xff\xff\xff\xff\xc7\x0f,\xd0\xff\xff\xff\xff\xc7\xff\x0f\xc0\x00\x00\x00\x00\x1e\x18\xc4P\x00\x00\x00\x00\x1e\x8f]@\x00\x00\x00\x00\x1f\xf9\xf7\xd0\x00\x00\x00\x00 p\x90\xc0\x00\x00\x00\x00%\x9e\xe3\xd0\x00\x00\x00\x00&\x15|\xc0\x00\x00\x00\x00-%\x03P\x00\x00\x00\x00-\x9b\x9c@\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xb7\xc4\x00\x00\xff\xff\xb7\xac\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08LMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x22\x12\xfe\x0e\x05\x00\x00\x0e\x05\x00\x00\x13\x00\x00\x00America/Los_AngelesTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x1a\xc0\xff\xff\xff\xff\x9e\xa6H\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xa0\x86*\xa0\xff\xff\xff\xff\xa1\x9a\xf7\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd6\xfet\x5c\xff\xff\xff\xff\xd8\x80\xad\x90\xff\xff\xff\xff\xda\xfe\xc3\x90\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xa5\x90\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x87\x90\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ei\x90\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xee\x90\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xd0\x90\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xb2\x90\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\x94\x90\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x91&\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10LMT\x00PDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdf\xe5\x8d\xc4\xda\x04\x00\x00\xda\x04\x00\x00\x12\x00\x00\x00America/LouisvilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xa4s\xf7\x00\xff\xff\xff\xff\xa5\x16\x11p\xff\xff\xff\xff\xca\x0dN\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xd7\x1c\xff\xff\xff\xff\xd3\xa4\x09p\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe9\x17\x00\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xf6\xe2\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x1e\x90p\xff\xff\xff\xff\xfc\xd8:\xf0\xff\xff\xff\xff\xfd\xc8\x1d\xe0\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00\x02w\xe0\xf0\x00\x00\x00\x00\x03p\xfe`\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x01\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf\x9a\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00America/Lower_PrincesTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x8c\x8b\x92\xf6\x01\x00\x00\xf6\x01\x00\x00\x0e\x00\x00\x00America/MaceioTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaah|\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x009\xf2J \x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x003\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5s\xb3\x5c'\x01\x00\x00'\x01\x00\x00\x0f\x00\x00\x00America/ManaguaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffi\x87,d\xff\xff\xff\xff\xbd-H\xe8\x00\x00\x00\x00\x06Ct`\x00\x00\x00\x00\x09\xa4>P\x00\x00\x00\x00\x11Q\xf8\xe0\x00\x00\x00\x00\x11\xd4oP\x00\x00\x00\x00\x131\xda\xe0\x00\x00\x00\x00\x13\xb4QP\x00\x00\x00\x00)a\x91 \x00\x00\x00\x00*\xc1KP\x00\x00\x00\x00+C\xdd\xe0\x00\x00\x00\x002\xc9\xefP\x00\x00\x00\x00BX\xc0\xe0\x00\x00\x00\x00C?iP\x00\x00\x00\x00DTn\x80\x00\x00\x00\x00E\x1fY`\x01\x02\x03\x02\x04\x02\x04\x02\x03\x02\x03\x02\x04\x02\x04\x02\xff\xff\xaf\x1c\x00\x00\xff\xff\xaf\x18\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00MMT\x00CST\x00EST\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\xcb'\xe9\x9c\x01\x00\x00\x9c\x01\x00\x00\x0e\x00\x00\x00America/ManausTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x7fD\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00,\xc0\xc3@\x00\x00\x00\x00-f\xd20\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc7\xbc\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00America/MarigotTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x17j\xd2\xb2\x00\x00\x00\xb2\x00\x00\x00\x12\x00\x00\x00America/MartiniqueTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xffi\x87\x14\xc4\xff\xff\xff\xff\x91\xa3\xc8D\x00\x00\x00\x00\x13Mn@\x00\x00\x00\x00\x144\x16\xb0\x01\x02\x03\x02\xff\xff\xc6\xbc\x00\x00\xff\xff\xc6\xbc\x00\x04\xff\xff\xc7\xc0\x00\x09\xff\xff\xd5\xd0\x01\x0dLMT\x00FFMT\x00AST\x00ADT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\xb7\xe2]\xb5\x01\x00\x00\xb5\x01\x00\x00\x11\x00\x00\x00America/MatamorosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa5\xb6\xda`\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K=\x8f`\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x01\xff\xff\xa4\x98\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x01\x08LMT\x00CST\x00CDT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xad=\x98\xce\x02\x00\x00\xce\x02\x00\x00\x10\x00\x00\x00America/MazatlanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xcb\xeaq`\xff\xff\xff\xff\xd8\x91\xb4\xf0\x00\x00\x00\x00\x00\x00p\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\xb8U\x10\x00\x00\x00\x00L\xcd\x22\x00\x00\x00\x00\x00M\x987\x10\x00\x00\x00\x00N\xad\x04\x00\x00\x00\x00\x00Ox\x19\x10\x00\x00\x00\x00P\x8c\xe6\x00\x00\x00\x00\x00Qa5\x90\x00\x00\x00\x00Rl\xc8\x00\x00\x00\x00\x00SA\x17\x90\x00\x00\x00\x00TL\xaa\x00\x00\x00\x00\x00U \xf9\x90\x00\x00\x00\x00V,\x8c\x00\x00\x00\x00\x00W\x00\xdb\x90\x00\x00\x00\x00X\x15\xa8\x80\x00\x00\x00\x00X\xe0\xbd\x90\x00\x00\x00\x00Y\xf5\x8a\x80\x00\x00\x00\x00Z\xc0\x9f\x90\x00\x00\x00\x00[\xd5l\x80\x00\x00\x00\x00\x5c\xa9\xbc\x10\x00\x00\x00\x00]\xb5N\x80\x00\x00\x00\x00^\x89\x9e\x10\x00\x00\x00\x00_\x950\x80\x00\x00\x00\x00`i\x80\x10\x00\x00\x00\x00a~M\x00\x00\x00\x00\x00bIb\x10\x00\x00\x00\x00c^/\x00\x01\x02\x01\x03\x01\x02\x01\x04\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\xff\xff\x9c<\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\x8f\x80\x00\x10LMT\x00MST\x00CST\x00MDT\x00PST\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x92Z\x8c\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00America/MendozaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb2\x04\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'\x194@\x00\x00\x00\x00'\xcd\xc3\xb0\x00\x00\x00\x00(\xfag\xc0\x00\x00\x00\x00)\xb0H\xb0\x00\x00\x00\x00*\xe0\xe1@\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xb0\x13\xb0\x00\x00\x00\x00AV>\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x03\x02\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf|\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008O:\xbf\x95\x03\x00\x00\x95\x03\x00\x00\x11\x00\x00\x00America/MenomineeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xffawIc\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xf9\x0fJ\x80\xff\xff\xff\xff\xfa\x08g\xf0\xff\xff\xff\xff\xfe\xb8+\x00\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaE\xf0\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xac\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x05\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xad\xdd\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xbd\x809\x8e\x02\x00\x00\x8e\x02\x00\x00\x0e\x00\x00\x00America/MeridaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xa5\xb6\xda`\x00\x00\x00\x00\x16\x86\xd5`\x00\x00\x00\x00\x18LKP\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\xff\xff\xab\xfc\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xb9\xb0\x01\x0cLMT\x00CST\x00EST\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x87n\x14J\x02\x00\x00J\x02\x00\x00\x12\x00\x00\x00America/MetlakatlaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x08\x00\x00\x00\x1e\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x870\x1a\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00V5\xe2\xa0\x00\x00\x00\x00V\xe5H0\x00\x00\x00\x00X\x1e\xff \x00\x00\x00\x00X\xc5*0\x00\x00\x00\x00Y\xfe\xe1 \x00\x00\x00\x00Z\xa5\x0c0\x00\x00\x00\x00[\xde\xc3 \x00\x00\x00\x00\x5cDF\xa0\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x06\x07\x06\x07\x06\x07\x02\x06\x00\x00\xd6&\x00\x00\xff\xff\x84\xa6\x00\x00\xff\xff\x8f\x80\x00\x04\xff\xff\x9d\x90\x01\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x81p\x00\x14\xff\xff\x8f\x80\x01\x19LMT\x00PST\x00PWT\x00PPT\x00PDT\x00AKST\x00AKDT\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x08\x89\x8c\x05\x03\x00\x00\x05\x03\x00\x00\x13\x00\x00\x00America/Mexico_CityTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xc5\xde\xb0`\xff\xff\xff\xff\xc6\x974P\xff\xff\xff\xff\xc9U\xf1\xe0\xff\xff\xff\xff\xc9\xea\xddP\xff\xff\xff\xff\xcf\x02\xc6\xe0\xff\xff\xff\xff\xcf\xb7VP\xff\xff\xff\xff\xda\x99\x15\xe0\xff\xff\xff\xff\xdbv\x83\xd0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x03\x01\x02\x04\x02\x04\x02\x05\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\xff\xff\xa3\x0c\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x01\x14LMT\x00MST\x00CST\x00MDT\x00CDT\x00CWT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\xea\x94Y&\x02\x00\x00&\x02\x00\x00\x10\x00\x00\x00America/MiquelonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x91\xdf\x17(\x00\x00\x00\x00\x13nc\xc0\x00\x00\x00\x00 u\xe4\xd0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22U\xc6\xd0\x00\x00\x00\x00#j\x93\xc0\x00\x00\x00\x00$5\xa8\xd0\x00\x00\x00\x00%Ju\xc0\x00\x00\x00\x00&\x15\x8a\xd0\x00\x00\x00\x00'*W\xc0\x00\x00\x00\x00'\xfe\xa7P\x00\x00\x00\x00)\x0a9\xc0\x00\x00\x00\x00)\xde\x89P\x00\x00\x00\x00*\xea\x1b\xc0\x00\x00\x00\x00+\xbekP\x00\x00\x00\x00,\xd38@\x00\x00\x00\x00-\x9eMP\x00\x00\x00\x00.\xb3\x1a@\x00\x00\x00\x00/~/P\x00\x00\x00\x000\x92\xfc@\x00\x00\x00\x001gK\xd0\x00\x00\x00\x002r\xde@\x00\x00\x00\x003G-\xd0\x00\x00\x00\x004R\xc0@\x00\x00\x00\x005'\x0f\xd0\x00\x00\x00\x0062\xa2@\x00\x00\x00\x007\x06\xf1\xd0\x00\x00\x00\x008\x1b\xbe\xc0\x00\x00\x00\x008\xe6\xd3\xd0\x00\x00\x00\x009\xfb\xa0\xc0\x00\x00\x00\x00:\xc6\xb5\xd0\x00\x00\x00\x00;\xdb\x82\xc0\x00\x00\x00\x00<\xaf\xd2P\x00\x00\x00\x00=\xbbd\xc0\x00\x00\x00\x00>\x8f\xb4P\x00\x00\x00\x00?\x9bF\xc0\x00\x00\x00\x00@o\x96P\x00\x00\x00\x00A\x84c@\x00\x00\x00\x00BOxP\x00\x00\x00\x00CdE@\x00\x00\x00\x00D/ZP\x00\x00\x00\x00ED'@\x00\x00\x00\x00E\xf3\x8c\xd0\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xcbX\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x00\x08\xff\xff\xe3\xe0\x01\x0cLMT\x00AST\x00-03\x00-02\x00\x0a<-03>3<-02>,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad\x8a\xf3O\xd5\x05\x00\x00\xd5\x05\x00\x00\x0f\x00\x00\x00America/MonctonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x1e\xed\xbc\xff\xff\xff\xff\x80\xf1\xb6P\xff\xff\xff\xff\x9e\xb8\x85`\xff\xff\xff\xff\x9f\xba\xddP\xff\xff\xff\xff\xbb<8\xd0\xff\xff\xff\xff\xbb\xb4#@\xff\xff\xff\xff\xbd\x1c\x1a\xd0\xff\xff\xff\xff\xbd\x94\x05@\xff\xff\xff\xff\xbe\xfb\xfc\xd0\xff\xff\xff\xff\xbfs\xe7@\xff\xff\xff\xff\xc0\xdb\xde\xd0\xff\xff\xff\xff\xc1S\xc9@\xff\xff\xff\xff\xc2\xbb\xc0\xd0\xff\xff\xff\xff\xc33\xab@\xff\xff\xff\xff\xc4\x9b\xa2\xd0\xff\xff\xff\xff\xc5\x13\x8d@\xff\xff\xff\xff\xc6p\xf8\xd0\xff\xff\xff\xff\xc7\x0d\xcd@\xff\xff\xff\xff\xc8H\xf1\xd0\xff\xff\xff\xff\xc8\xed\xaf@\xff\xff\xff\xff\xca\x16^\xd0\xff\xff\xff\xff\xca\xd6\xcb\xc0\xff\xff\xff\xff\xcb\x88\xe2`\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\xff\xff\xff\xff\xd3u\xd6\xe0\xff\xff\xff\xff\xd4@\xcf\xd0\xff\xff\xff\xff\xd5U\xb8\xe0\xff\xff\xff\xff\xd6 \xb1\xd0\xff\xff\xff\xff\xd75\x9a\xe0\xff\xff\xff\xff\xd8\x00\x93\xd0\xff\xff\xff\xff\xd9\x15|\xe0\xff\xff\xff\xff\xd9\xe0u\xd0\xff\xff\xff\xff\xda\xfe\x99`\xff\xff\xff\xff\xdb\xc0W\xd0\xff\xff\xff\xff\xdc\xde{`\xff\xff\xff\xff\xdd\xa9tP\xff\xff\xff\xff\xde\xbe]`\xff\xff\xff\xff\xdf\x89VP\xff\xff\xff\xff\xe0\x9e?`\xff\xff\xff\xff\xe1i8P\xff\xff\xff\xff\xe2~!`\xff\xff\xff\xff\xe3I\x1aP\xff\xff\xff\xff\xe4^\x03`\xff\xff\xff\xff\xe5(\xfcP\xff\xff\xff\xff\xe6G\x1f\xe0\xff\xff\xff\xff\xe7\x12\x18\xd0\xff\xff\xff\xff\xe8'\x01\xe0\xff\xff\xff\xff\xe9\x16\xe4\xd0\xff\xff\xff\xff\xea\x06\xe3\xe0\xff\xff\xff\xff\xea\xf6\xc6\xd0\xff\xff\xff\xff\xeb\xe6\xc5\xe0\xff\xff\xff\xff\xec\xd6\xa8\xd0\xff\xff\xff\xff\xed\xc6\xa7\xe0\xff\xff\xff\xff\xee\xbf\xc5P\xff\xff\xff\xff\xef\xaf\xc4`\xff\xff\xff\xff\xf0\x9f\xa7P\xff\xff\xff\xff\xf1\x8f\xa6`\xff\xff\xff\xff\xf2\x7f\x89P\xff\xff\xff\xff\xf3o\x88`\xff\xff\xff\xff\xf4_kP\xff\xff\xff\xff\xf5Oj`\xff\xff\xff\xff\xf6?MP\xff\xff\xff\xff\xf7/L`\xff\xff\xff\xff\xf8(i\xd0\xff\xff\xff\xff\xf9\x0f.`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xf8J\xe0\xff\xff\xff\xff\xfb\xe8-\xd0\xff\xff\xff\xff\xfc\xd8,\xe0\xff\xff\xff\xff\xfd\xc8\x0f\xd0\xff\xff\xff\xff\xfe\xb8\x0e\xe0\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00\x97\xf0\xe0\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x02w\xd2\xe0\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbe]|\x00\x00\x00\x00,\xd3*l\x00\x00\x00\x00-\x9e?|\x00\x00\x00\x00.\xb3\x0cl\x00\x00\x00\x00/~!|\x00\x00\x00\x000\x92\xeel\x00\x00\x00\x001g=\xfc\x00\x00\x00\x002r\xd0l\x00\x00\x00\x003G\x1f\xfc\x00\x00\x00\x004R\xb2l\x00\x00\x00\x005'\x01\xfc\x00\x00\x00\x0062\x94l\x00\x00\x00\x007\x06\xe3\xfc\x00\x00\x00\x008\x1b\xb0\xec\x00\x00\x00\x008\xe6\xc5\xfc\x00\x00\x00\x009\xfb\x92\xec\x00\x00\x00\x00:\xc6\xa7\xfc\x00\x00\x00\x00;\xdbt\xec\x00\x00\x00\x00<\xaf\xc4|\x00\x00\x00\x00=\xbbV\xec\x00\x00\x00\x00>\x8f\xa6|\x00\x00\x00\x00?\x9b8\xec\x00\x00\x00\x00@o\x88|\x00\x00\x00\x00A\x84Ul\x00\x00\x00\x00BOj|\x00\x00\x00\x00Cd7l\x00\x00\x00\x00D/L|\x00\x00\x00\x00ED\x19l\x00\x00\x00\x00E\x98\x87@\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x05\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x03\xff\xff\xc3D\x00\x00\xff\xff\xb9\xb0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xd5\xd0\x01\x10\xff\xff\xd5\xd0\x01\x14LMT\x00EST\x00ADT\x00AST\x00AWT\x00APT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L+\xe3u\x84\x02\x00\x00\x84\x02\x00\x00\x11\x00\x00\x00America/MonterreyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa5\xb6\xda`\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xa1\xf4\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x01\x08LMT\x00CST\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x98\x00\x08\xc9\x03\x00\x00\xc9\x03\x00\x00\x12\x00\x00\x00America/MontevideoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x00\x00\x00\x09\x00\x00\x00&\xff\xff\xff\xff\x8c4\xe53\xff\xff\xff\xff\xa2\x92\x87\xb3\xff\xff\xff\xff\xa8\xff\xdb@\xff\xff\xff\xff\xa9\xf1\x0f\xb0\xff\xff\xff\xff\xaa\xe2Y8\xff\xff\xff\xff\xab\xd2C0\xff\xff\xff\xff\xac\xc3\x8c\xb8\xff\xff\xff\xff\xad\xb3v\xb0\xff\xff\xff\xff\xbb\xf4\xb5\xb8\xff\xff\xff\xff\xbc\xbf\xb5\xb0\xff\xff\xff\xff\xbd\xd4\x97\xb8\xff\xff\xff\xff\xbe\x9f\x97\xb0\xff\xff\xff\xff\xbf\xb4y\xb8\xff\xff\xff\xff\xc0\x7fy\xb0\xff\xff\xff\xff\xc1\x94[\xb8\xff\xff\xff\xff\xc2_[\xb0\xff\xff\xff\xff\xc3}x8\xff\xff\xff\xff\xc4?=\xb0\xff\xff\xff\xff\xc5]Z8\xff\xff\xff\xff\xc6\x1f\x1f\xb0\xff\xff\xff\xff\xc7\x18R8\xff\xff\xff\xff\xc8\x08<0\xff\xff\xff\xff\xc9\x1d\x1e8\xff\xff\xff\xff\xc9\xe8\x1e0\xff\xff\xff\xff\xca\x8b\x9f8\xff\xff\xff\xff\xcd\x1e\xc60\xff\xff\xff\xff\xcd\x95f(\xff\xff\xff\xff\xec\x0b\x85\xb0\xff\xff\xff\xff\xec\xf25(\xff\xff\xff\xff\xedEJ\xb0\xff\xff\xff\xff\xed\x85\xd6 \xff\xff\xff\xff\xf7\x13r\xb0\xff\xff\xff\xff\xf7\xfa\x1b \xff\xff\xff\xff\xfc\xfe>0\xff\xff\xff\xff\xfd\xf6\x11(\x00\x00\x00\x00\x00\x96u0\x00\x00\x00\x00\x00\xd8R \x00\x00\x00\x00\x04W\x8a\xb0\x00\x00\x00\x00\x04\xc6:\xa0\x00\x00\x00\x00\x07\x96\x1b\xb0\x00\x00\x00\x00\x07\xdf\xda\x98\x00\x00\x00\x00\x08\xc6\x9f(\x00\x00\x00\x00\x09ZN0\x00\x00\x00\x00\x09\xdbs \x00\x00\x00\x00\x0d\x1a\x120\x00\x00\x00\x00\x0d\x7f\x87\xa0\x00\x00\x00\x00\x0e\xe7\x7f0\x00\x00\x00\x00\x0f_i\xa0\x00\x00\x00\x00\x10\xd9\xd60\x00\x00\x00\x00\x11?K\xa0\x00\x00\x00\x00\x11\x89-\xb0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00!\xc3T0\x00\x00\x00\x00\x22'x \x00\x00\x00\x00#\xa1\xe4\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%Jg\xb0\x00\x00\x00\x00%\xe7< \x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x0a+\xb0\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x90\x1c\xa0\x00\x00\x00\x00AL\xf60\x00\x00\x00\x00BF/\xc0\x00\x00\x00\x00CH\xa3\xd0\x00\x00\x00\x00D\x13\x9c\xc0\x00\x00\x00\x00E\x1fKP\x00\x00\x00\x00E\xf3~\xc0\x00\x00\x00\x00G\x08g\xd0\x00\x00\x00\x00G\xd3`\xc0\x00\x00\x00\x00H\xe8I\xd0\x00\x00\x00\x00I\xb3B\xc0\x00\x00\x00\x00J\xc8+\xd0\x00\x00\x00\x00K\x9c_@\x00\x00\x00\x00L\xa8\x0d\xd0\x00\x00\x00\x00M|A@\x00\x00\x00\x00N\x87\xef\xd0\x00\x00\x00\x00O\x5c#@\x00\x00\x00\x00Pq\x0cP\x00\x00\x00\x00Q<\x05@\x00\x00\x00\x00RP\xeeP\x00\x00\x00\x00S\x1b\xe7@\x00\x00\x00\x00T0\xd0P\x00\x00\x00\x00T\xfb\xc9@\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x05\x06\x05\x07\x05\x07\x05\x06\x05\x07\x05\x07\x05\x08\x06\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\xff\xff\xcbM\x00\x00\xff\xff\xcbM\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xce\xc8\x00\x0c\xff\xff\xd5\xd0\x01\x12\xff\xff\xd5\xd0\x00\x12\xff\xff\xdc\xd8\x01\x16\xff\xff\xe3\xe0\x01\x1c\xff\xff\xea\xe8\x01 LMT\x00MMT\x00-04\x00-0330\x00-03\x00-0230\x00-02\x00-0130\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x10\x00\x00\x00America/MontrealTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00America/MontserratTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0e\x00\x00\x00America/NassauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x9aG\xc8\xd0\x06\x00\x00\xd0\x06\x00\x00\x10\x00\x00\x00America/New_YorkTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x03\xf0\x90\xff\xff\xff\xff\x9e\xa6\x1ep\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x86\x00p\xff\xff\xff\xff\xa1\x9a\xcd`\xff\xff\xff\xff\xa2e\xe2p\xff\xff\xff\xff\xa3\x83\xe9\xe0\xff\xff\xff\xff\xa4j\xaep\xff\xff\xff\xff\xa55\xa7`\xff\xff\xff\xff\xa6S\xca\xf0\xff\xff\xff\xff\xa7\x15\x89`\xff\xff\xff\xff\xa83\xac\xf0\xff\xff\xff\xff\xa8\xfe\xa5\xe0\xff\xff\xff\xff\xaa\x13\x8e\xf0\xff\xff\xff\xff\xaa\xde\x87\xe0\xff\xff\xff\xff\xab\xf3p\xf0\xff\xff\xff\xff\xac\xbei\xe0\xff\xff\xff\xff\xad\xd3R\xf0\xff\xff\xff\xff\xae\x9eK\xe0\xff\xff\xff\xff\xaf\xb34\xf0\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9\x1b\xd9p\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xc6\xb4`\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xc8\xf8W`\xff\xff\xff\xff\xca\x0d@p\xff\xff\xff\xff\xca\xd89`\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xd9\xe0\x83\xe0\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdb\xc0e\xe0\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5W.\xe0\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe77\x10\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xba\x9e\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0f\x00\x00\x00America/NipigonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\xab\xd5\xf9\xcf\x03\x00\x00\xcf\x03\x00\x00\x0c\x00\x00\x00America/NomeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00&\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87O\xd2\xff\xff\xff\xff\xcb\x89D\xd0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aP@\xff\xff\xff\xff\xfa\xd2U\xb0\xff\xff\xff\xff\xfe\xb8qP\xff\xff\xff\xff\xff\xa8T@\x00\x00\x00\x00\x00\x98SP\x00\x00\x00\x00\x01\x886@\x00\x00\x00\x00\x02x5P\x00\x00\x00\x00\x03qR\xc0\x00\x00\x00\x00\x04aQ\xd0\x00\x00\x00\x00\x05Q4\xc0\x00\x00\x00\x00\x06A3\xd0\x00\x00\x00\x00\x071\x16\xc0\x00\x00\x00\x00\x07\x8dm\xd0\x00\x00\x00\x00\x09\x10\xf8\xc0\x00\x00\x00\x00\x09\xad\xe9P\x00\x00\x00\x00\x0a\xf0\xda\xc0\x00\x00\x00\x00\x0b\xe0\xd9\xd0\x00\x00\x00\x00\x0c\xd9\xf7@\x00\x00\x00\x00\x0d\xc0\xbb\xd0\x00\x00\x00\x00\x0e\xb9\xd9@\x00\x00\x00\x00\x0f\xa9\xd8P\x00\x00\x00\x00\x10\x99\xbb@\x00\x00\x00\x00\x11\x89\xbaP\x00\x00\x00\x00\x12y\x9d@\x00\x00\x00\x00\x13i\x9cP\x00\x00\x00\x00\x14Y\x7f@\x00\x00\x00\x00\x15I~P\x00\x00\x00\x00\x169a@\x00\x00\x00\x00\x17)`P\x00\x00\x00\x00\x18\x22}\xc0\x00\x00\x00\x00\x19\x09BP\x00\x00\x00\x00\x1a\x02_\xc0\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xb6n\x00\x00\xff\xffd\xee\x00\x00\xff\xffeP\x00\x04\xff\xffs`\x01\x08\xff\xffs`\x01\x0c\xff\xffeP\x00\x10\xff\xffs`\x01\x14\xff\xff\x81p\x00\x18\xff\xff\x8f\x80\x01\x1c\xff\xff\x81p\x00!LMT\x00NST\x00NWT\x00NPT\x00BST\x00BDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7-2f\xe4\x01\x00\x00\xe4\x01\x00\x00\x0f\x00\x00\x00America/NoronhaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaaed\xff\xff\xff\xff\xb8\x0f;\xd0\xff\xff\xff\xff\xb8\xfd2\x90\xff\xff\xff\xff\xb9\xf1& \xff\xff\xff\xff\xba\xdef\x10\xff\xff\xff\xff\xda8\xa0 \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdc\x19\xd3\xa0\xff\xff\xff\xff\xdc\xb9K\x10\xff\xff\xff\xff\xdd\xfb\x07 \xff\xff\xff\xff\xde\x9b\xd0\x10\xff\xff\xff\xff\xdf\xdd\x8c \xff\xff\xff\xff\xe0T%\x10\xff\xff\xff\xff\xf4\x97\xf1\xa0\xff\xff\xff\xff\xf5\x05P\x10\xff\xff\xff\xff\xf6\xc0V \xff\xff\xff\xff\xf7\x0e\x10\x90\xff\xff\xff\xff\xf8Q\x1e \xff\xff\xff\xff\xf8\xc7\xb7\x10\xff\xff\xff\xff\xfa\x0a\xc4\xa0\xff\xff\xff\xff\xfa\xa8\xea\x90\xff\xff\xff\xff\xfb\xeb\xf8 \xff\xff\xff\xff\xfc\x8bo\x90\x00\x00\x00\x00\x1d\xc9\x80 \x00\x00\x00\x00\x1ex\xc9\x90\x00\x00\x00\x00\x1f\xa0'\xa0\x00\x00\x00\x00 3\xc1\x90\x00\x00\x00\x00!\x81[ \x00\x00\x00\x00\x22\x0b\xba\x90\x00\x00\x00\x00#X\x02\xa0\x00\x00\x00\x00#\xe2b\x10\x00\x00\x00\x00%7\xe4\xa0\x00\x00\x00\x00%\xd4\xb9\x10\x00\x00\x00\x007\xf6\xb8\xa0\x00\x00\x00\x008\xb8w\x10\x00\x00\x00\x009\xdf\xd5 \x00\x00\x00\x009\xe9\x01\x90\x00\x00\x00\x00;\xc8\xf1\xa0\x00\x00\x00\x002\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7.\xb6*\x13\x04\x00\x00\x13\x04\x00\x00\x1b\x00\x00\x00America/North_Dakota/BeulahTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x00\x00\x00\x00G-|\x00\x00\x00\x00\x00G\xd3\xa7\x10\x00\x00\x00\x00I\x0d^\x00\x00\x00\x00\x00I\xb3\x89\x10\x00\x00\x00\x00J\xed@\x00\x00\x00\x00\x00K\x9c\xa5\x90\x00\x00\x00\x00L\xd6\x5c\x80\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\xff\xff\xa0\x95\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xab\xa0\x00\x14LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\xeam\xef\xde\x03\x00\x00\xde\x03\x00\x00\x1b\x00\x00\x00America/North_Dakota/CenterTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xac\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\xff\xff\xa1\x08\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xb9\xb0\x01\x14\xff\xff\xab\xa0\x00\x18LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CDT\x00CST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x1b\x8b(\xde\x03\x00\x00\xde\x03\x00\x00\x1e\x00\x00\x00America/North_Dakota/New_SalemTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x06\x05\x06\x05\x06\x05\x06\x05\xff\xff\xa0\xed\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xb9\xb0\x01\x14\xff\xff\xab\xa0\x00\x18LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CDT\x00CST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xf9v\x14\xc5\x03\x00\x00\xc5\x03\x00\x00\x0c\x00\x00\x00America/NuukTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x9b\x80h\x00\x00\x00\x00\x00\x13M|P\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7l\x90\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V,)\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00X\x15F\x10\x00\x00\x00\x00X\xd7\x12\x90\x00\x00\x00\x00Y\xf5(\x10\x00\x00\x00\x00Z\xb6\xf4\x90\x00\x00\x00\x00[\xd5\x0a\x10\x00\x00\x00\x00\x5c\xa0\x11\x10\x00\x00\x00\x00]\xb4\xec\x10\x00\x00\x00\x00^\x7f\xf3\x10\x00\x00\x00\x00_\x94\xce\x10\x00\x00\x00\x00`_\xd5\x10\x00\x00\x00\x00a}\xea\x90\x00\x00\x00\x00b?\xb7\x10\x00\x00\x00\x00c]\xcc\x90\x00\x00\x00\x00d\x1f\x99\x10\x00\x00\x00\x00e=\xae\x90\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x03\xff\xff\xcf\x80\x00\x00\xff\xff\xd5\xd0\x00\x04\xff\xff\xe3\xe0\x01\x08\xff\xff\xe3\xe0\x00\x08LMT\x00-03\x00-02\x00\x0a<-02>2<-01>,M3.5.0/-1,M10.5.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1w\xb9\xca\xce\x02\x00\x00\xce\x02\x00\x00\x0f\x00\x00\x00America/OjinagaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\x9c\xa5\x90\x00\x00\x00\x00L\xd6\x5c\x80\x00\x00\x00\x00M|\x87\x90\x00\x00\x00\x00N\xb6>\x80\x00\x00\x00\x00O\x5ci\x90\x00\x00\x00\x00P\x96 \x80\x00\x00\x00\x00Q\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x04\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x06\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x00\x00\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10\xff\xff\xab\xa0\x00\x14\xff\xff\xb9\xb0\x01\x18-00\x00EPT\x00EST\x00EDT\x00EWT\x00CST\x00CDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xf9\x1d\xc9\xbb\x00\x00\x00\xbb\x00\x00\x00\x12\x00\x00\x00America/ParamariboTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x12\xff\xff\xff\xff\x91\x05\x8e\xb8\xff\xff\xff\xff\xbe*K\xc4\xff\xff\xff\xff\xd2b,\xb4\x00\x00\x00\x00\x1b\xbe1\xb8\x01\x02\x03\x04\xff\xff\xccH\x00\x00\xff\xff\xcc<\x00\x04\xff\xff\xccL\x00\x04\xff\xff\xce\xc8\x00\x08\xff\xff\xd5\xd0\x00\x0eLMT\x00PMT\x00-0330\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0f\x00\x00\x00America/PhoenixTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xcf\x17\xdf\x1c\xff\xff\xff\xff\xcf\x8f\xe5\xac\xff\xff\xff\xff\xd0\x81\x1a\x1c\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\x02\x01\x02\x01\x02\x03\x02\x03\x02\x01\x02\xff\xff\x96\xee\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0cLMT\x00MDT\x00MST\x00MWT\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4T\xbd\xeb5\x02\x00\x005\x02\x00\x00\x16\x00\x00\x00America/Port-au-PrinceTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xffi\x87\x1fP\xff\xff\xff\xff\x9cnq\xfc\x00\x00\x00\x00\x19\x1bF\xd0\x00\x00\x00\x00\x1a\x01\xef@\x00\x00\x00\x00\x1a\xf1\xeeP\x00\x00\x00\x00\x1b\xe1\xd1@\x00\x00\x00\x00\x1c\xd1\xd0P\x00\x00\x00\x00\x1d\xc1\xb3@\x00\x00\x00\x00\x1e\xb1\xb2P\x00\x00\x00\x00\x1f\xa1\x95@\x00\x00\x00\x00 \x91\x94P\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x00BOxP\x00\x00\x00\x00CdE@\x00\x00\x00\x00D/ZP\x00\x00\x00\x00ED'@\x00\x00\x00\x00O\x5cMp\x00\x00\x00\x00P\x96\x04`\x00\x00\x00\x00Q5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x81-\xa9\x8a\x01\x00\x00\x8a\x01\x00\x00\x13\x00\x00\x00America/Porto_VelhoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x82\xe8\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc4\x18\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x13\x00\x00\x00America/Puerto_RicoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x13\x9b\xb1\xc2\x04\x00\x00\xc2\x04\x00\x00\x14\x00\x00\x00America/Punta_ArenasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x1d\xfc\xff\xff\xff\xff\x8f0GE\xff\xff\xff\xff\x9b\x5c\xe5P\xff\xff\xff\xff\x9f|\xe2\xc5\xff\xff\xff\xff\xa1\x00q\xc0\xff\xff\xff\xff\xb0^w\xc5\xff\xff\xff\xff\xb1w=@\xff\xff\xff\xff\xb2A\x00\xd0\xff\xff\xff\xff\xb3Xp\xc0\xff\xff\xff\xff\xb4\x224P\xff\xff\xff\xff\xb59\xa4@\xff\xff\xff\xff\xb6\x03g\xd0\xff\xff\xff\xff\xb7\x1a\xd7\xc0\xff\xff\xff\xff\xb7\xe4\x9bP\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xc7 P\xff\xff\xff\xff\xcc\x1cn@\xff\xff\xff\xff\xccl\xe7\xd0\xff\xff\xff\xff\xd4\x17\xe3@\xff\xff\xff\xff\xd53U\xc0\xff\xff\xff\xff\xd5v\x92@\xff\xff\xff\xff\xfd\xd1<@\xff\xff\xff\xff\xfe\x92\xfa\xb0\xff\xff\xff\xff\xff\xcc\xcd\xc0\x00\x00\x00\x00\x00r\xdc\xb0\x00\x00\x00\x00\x01uP\xc0\x00\x00\x00\x00\x02@I\xb0\x00\x00\x00\x00\x03U2\xc0\x00\x00\x00\x00\x04 +\xb0\x00\x00\x00\x00\x05>O@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00XC\x86\xb0\x01\x02\x01\x03\x01\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x03\x02\x03\x04\x02\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x06\xff\xff\xbd\x84\x00\x00\xff\xff\xbd\xbb\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xc7\xc0\x01\x0c\xff\xff\xd5\xd0\x01\x10\xff\xff\xd5\xd0\x00\x10LMT\x00SMT\x00-05\x00-04\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x13\x00\x00\x00America/Rainy_RiverTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffd\xe4\xb0\x94\xff\xff\xff\xff\x9b\x01\xfb\xe0\xff\xff\xff\xff\x9b\xc3\xbaP\xff\xff\xff\xff\x9e\xb8\xa1\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xc2\xa0;\x80\xff\xff\xff\xff\xc3O\x84\xf0\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3\x88h\x00\xff\xff\xff\xff\xd4S`\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xdb\x00\x07\x00\xff\xff\xff\xff\xdb\xc8\x5c\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf41b\xf0\xff\xff\xff\xff\xf9\x0fJ\x80\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xcf\x80\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xb1\x80\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xa4\xec\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00CDT\x00CST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xdfH\x0d'\x03\x00\x00'\x03\x00\x00\x14\x00\x00\x00America/Rankin_InletTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xe7\x8cn\x00\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x08 \xcf\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x0a\x00\xb1\x80\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaE\xf0\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xac\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x00\x00\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c-00\x00CDT\x00CST\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x03u\xf3\xe4\x01\x00\x00\xe4\x01\x00\x00\x0e\x00\x00\x00America/RecifeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaag\xb8\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x009\xe9\x0f\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x003\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x96dK~\x02\x00\x00~\x02\x00\x00\x0e\x00\x00\x00America/ReginaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x86\xfd\x93\x1c\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xb5eO\xf0\xff\xff\xff\xff\xb60H\xe0\xff\xff\xff\xff\xb7E1\xf0\xff\xff\xff\xff\xb8\x10*\xe0\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xf0\x0c\xe0\xff\xff\xff\xff\xbb\x0e0p\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xee\x12p\xff\xff\xff\xff\xbd\xb9\x0b`\xff\xff\xff\xff\xc2r\x08\xf0\xff\xff\xff\xff\xc3a\xeb\xe0\xff\xff\xff\xff\xc4Q\xea\xf0\xff\xff\xff\xff\xc58\x93`\xff\xff\xff\xff\xc61\xcc\xf0\xff\xff\xff\xff\xc7!\xaf\xe0\xff\xff\xff\xff\xc8\x1a\xe9p\xff\xff\xff\xff\xc9\x0a\xcc`\xff\xff\xff\xff\xc9\xfa\xcbp\xff\xff\xff\xff\xca\xea\xae`\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd3c\x8c\x10\xff\xff\xff\xff\xd4So\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\xff\xff\xff\xff\xd75\xc5\x10\xff\xff\xff\xff\xd8\x00\xbe\x00\xff\xff\xff\xff\xd9\x15\xa7\x10\xff\xff\xff\xff\xd9\xe0\xa0\x00\xff\xff\xff\xff\xda\xfe\xc3\x90\xff\xff\xff\xff\xdb\xc0\x82\x00\xff\xff\xff\xff\xdc\xde\xa5\x90\xff\xff\xff\xff\xdd\xa9\x9e\x80\xff\xff\xff\xff\xde\xbe\x87\x90\xff\xff\xff\xff\xdf\x89\x80\x80\xff\xff\xff\xff\xe0\x9ei\x90\xff\xff\xff\xff\xe1ib\x80\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3ID\x80\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)&\x80\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12C\x00\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf2%\x00\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xd6\xd3\x00\xff\xff\xff\xff\xed\xc6\xd2\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\xff\xff\x9d\xe4\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xab\xa0\x00\x14LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0I~D'\x03\x00\x00'\x03\x00\x00\x10\x00\x00\x00America/ResoluteTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xd5\xfb\x81\x80\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x08 \xcf\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x0a\x00\xb1\x80\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaE\xf0\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xac\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x00\x00\x00\x00\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c-00\x00CDT\x00CST\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x12\x00\x00\x00America/Rio_BrancoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x86\x90\xff\xff\xff\xff\xb8\x0ff\x00\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xf1PP\xff\xff\xff\xff\xba\xde\x90@\xff\xff\xff\xff\xda8\xcaP\xff\xff\xff\xff\xda\xec\x16P\xff\xff\xff\xff\xdc\x19\xfd\xd0\xff\xff\xff\xff\xdc\xb9u@\xff\xff\xff\xff\xdd\xfb1P\xff\xff\xff\xff\xde\x9b\xfa@\xff\xff\xff\xff\xdf\xdd\xb6P\xff\xff\xff\xff\xe0TO@\xff\xff\xff\xff\xf4\x98\x1b\xd0\xff\xff\xff\xff\xf5\x05z@\xff\xff\xff\xff\xf6\xc0\x80P\xff\xff\xff\xff\xf7\x0e:\xc0\xff\xff\xff\xff\xf8QHP\xff\xff\xff\xff\xf8\xc7\xe1@\xff\xff\xff\xff\xfa\x0a\xee\xd0\xff\xff\xff\xff\xfa\xa9\x14\xc0\xff\xff\xff\xff\xfb\xec\x22P\xff\xff\xff\xff\xfc\x8b\x99\xc0\x00\x00\x00\x00\x1d\xc9\xaaP\x00\x00\x00\x00\x1ex\xf3\xc0\x00\x00\x00\x00\x1f\xa0Q\xd0\x00\x00\x00\x00 3\xeb\xc0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22\x0b\xe4\xc0\x00\x00\x00\x00H`\x7fP\x00\x00\x00\x00R\x7f\x04\xc0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\xff\xff\xc0p\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x04LMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00America/RosarioTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xad\xb0\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x04\x05\x04\x05\xff\xff\xc3\xd0\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x14\x00\x00\x00America/Santa_IsabelTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xa9yOp\xff\xff\xff\xff\xaf\xf2|\xf0\xff\xff\xff\xff\xb6fdp\xff\xff\xff\xff\xb7\x1b\x10\x00\xff\xff\xff\xff\xb8\x0a\xf2\xf0\xff\xff\xff\xff\xcb\xea\x8d\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\x99\xbap\xff\xff\xff\xff\xd7\x1bY\x00\xff\xff\xff\xff\xd8\x91\xb4\xf0\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00F\x0f\x82\xa0\x00\x00\x00\x00G$O\x90\x00\x00\x00\x00G\xf8\x9f \x00\x00\x00\x00I\x041\x90\x00\x00\x00\x00I\xd8\x81 \x00\x00\x00\x00J\xe4\x13\x90\x00\x00\x00\x00K=\xab\x80\x01\x02\x01\x02\x03\x02\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x02\xff\xff\x92L\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x9d\x90\x01\x14LMT\x00MST\x00PST\x00PDT\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04,2h\x99\x01\x00\x00\x99\x01\x00\x00\x10\x00\x00\x00America/SantaremTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaazH\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00H`q@\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\xff\xff\xcc\xb8\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x00\x04LMT\x00-03\x00-04\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x22_WJ\x05\x00\x00J\x05\x00\x00\x10\x00\x00\x00America/SantiagoTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x1d\xc5\xff\xff\xff\xff\x8f0GE\xff\xff\xff\xff\x9b\x5c\xe5P\xff\xff\xff\xff\x9f|\xe2\xc5\xff\xff\xff\xff\xa1\x00q\xc0\xff\xff\xff\xff\xb0^w\xc5\xff\xff\xff\xff\xb1w=@\xff\xff\xff\xff\xb2A\x00\xd0\xff\xff\xff\xff\xb3Xp\xc0\xff\xff\xff\xff\xb4\x224P\xff\xff\xff\xff\xb59\xa4@\xff\xff\xff\xff\xb6\x03g\xd0\xff\xff\xff\xff\xb7\x1a\xd7\xc0\xff\xff\xff\xff\xb7\xe4\x9bP\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xc7 P\xff\xff\xff\xff\xcc\x1cn@\xff\xff\xff\xff\xccl\xe7\xd0\xff\xff\xff\xff\xd3\xdc\x8f\xc0\xff\xff\xff\xff\xd4\x17\xd50\xff\xff\xff\xff\xd53U\xc0\xff\xff\xff\xff\xd5v\x92@\xff\xff\xff\xff\xfd\xd1<@\xff\xff\xff\xff\xfe\x92\xfa\xb0\xff\xff\xff\xff\xff\xcc\xcd\xc0\x00\x00\x00\x00\x00r\xdc\xb0\x00\x00\x00\x00\x01uP\xc0\x00\x00\x00\x00\x02@I\xb0\x00\x00\x00\x00\x03U2\xc0\x00\x00\x00\x00\x04 +\xb0\x00\x00\x00\x00\x05>O@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00Y\x17\xc80\x00\x00\x00\x00Y\x8f\xce\xc0\x00\x00\x00\x00Z\xf7\xaa0\x00\x00\x00\x00[o\xb0\xc0\x00\x00\x00\x00\x5c\xa9g\xb0\x00\x00\x00\x00]t|\xc0\x00\x00\x00\x00^\x89I\xb0\x00\x00\x00\x00_T^\xc0\x00\x00\x00\x00`i+\xb0\x00\x00\x00\x00a4@\xc0\x00\x00\x00\x00bI\x0d\xb0\x00\x00\x00\x00c\x1d]@\x00\x00\x00\x00d(\xef\xb0\x01\x02\x01\x03\x01\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x03\x02\x03\x05\x04\x02\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\xff\xff\xbd\xbb\x00\x00\xff\xff\xbd\xbb\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xc7\xc0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00SMT\x00-05\x00-04\x00-03\x00\x0a<-04>4<-03>,M9.1.6/24,M4.1.6/24\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x0f(\x08=\x01\x00\x00=\x01\x00\x00\x15\x00\x00\x00America/Santo_DomingoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x06\x00\x00\x00\x1b\xff\xff\xff\xffi\x87\x1d\x08\xff\xff\xff\xff\xba\xdfB`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xa7\xc3@\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00C{\xc8\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x01\xfa\x7fH\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x03\xdd\x04H\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x05\xbf\x89H\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x07\xa0\xbc\xc8\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:)\xe1`\x01\x03\x02\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x05\x03\x05\xff\xff\xbex\x00\x00\xff\xff\xbe`\x00\x04\xff\xff\xc7\xc0\x01\x09\xff\xff\xb9\xb0\x00\x0d\xff\xff\xc0\xb8\x01\x11\xff\xff\xc7\xc0\x00\x17LMT\x00SDMT\x00EDT\x00EST\x00-0430\x00AST\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d?\xdf\xda\xb8\x03\x00\x00\xb8\x03\x00\x00\x11\x00\x00\x00America/Sao_PauloTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaar\xb4\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4Z\x090\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xbd\xe3\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\x94\x8b \x00\x00\x00\x00*\xea\x0d\xb0\x00\x00\x00\x00+k2\xa0\x00\x00\x00\x00,\xc0\xb50\x00\x00\x00\x00-f\xc4 \x00\x00\x00\x00.\xa0\x970\x00\x00\x00\x00/F\xa6 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x002W \xb0\x00\x00\x00\x003\x06j \x00\x00\x00\x0048T0\x00\x00\x00\x004\xf8\xc1 \x00\x00\x00\x006 \x1f0\x00\x00\x00\x006\xcfh\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x00:\x8f,\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x00N\xf0\xa0\x00\x00\x00\x00?\x91\xfe0\x00\x00\x00\x00@.\xd2\xa0\x00\x00\x00\x00A\x86\xf80\x00\x00\x00\x00B\x17\xef \x00\x00\x00\x00CQ\xc20\x00\x00\x00\x00C\xf7\xd1 \x00\x00\x00\x00EMS\xb0\x00\x00\x00\x00E\xe0\xed\xa0\x00\x00\x00\x00G\x11\x860\x00\x00\x00\x00G\xb7\x95 \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\x97w \x00\x00\x00\x00J\xda\x84\xb0\x00\x00\x00\x00K\x80\x93\xa0\x00\x00\x00\x00L\xbaf\xb0\x00\x00\x00\x00M`u\xa0\x00\x00\x00\x00N\x9aH\xb0\x00\x00\x00\x00OI\x92 \x00\x00\x00\x00P\x83e0\x00\x00\x00\x00Q 9\xa0\x00\x00\x00\x00RcG0\x00\x00\x00\x00S\x00\x1b\xa0\x00\x00\x00\x00TC)0\x00\x00\x00\x00T\xe98 \x00\x00\x00\x00V#\x0b0\x00\x00\x00\x00V\xc9\x1a \x00\x00\x00\x00X\x02\xed0\x00\x00\x00\x00X\xa8\xfc \x00\x00\x00\x00Y\xe2\xcf0\x00\x00\x00\x00Z\x88\xde \x00\x00\x00\x00[\xde`\xb0\x00\x00\x00\x00\x5ch\xc0 \x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xd4L\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19a\x7f\x0a\xd8\x03\x00\x00\xd8\x03\x00\x00\x14\x00\x00\x00America/ScoresbysundTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Z\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\x9b\x80L\x18\x00\x00\x00\x00\x13Mn@\x00\x00\x00\x00\x144$\xc0\x00\x00\x00\x00\x15#\xf9\xa0\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7l\x90\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V,)\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00X\x15F\x10\x00\x00\x00\x00X\xd7\x12\x90\x00\x00\x00\x00Y\xf5(\x10\x00\x00\x00\x00Z\xb6\xf4\x90\x00\x00\x00\x00[\xd5\x0a\x10\x00\x00\x00\x00\x5c\xa0\x11\x10\x00\x00\x00\x00]\xb4\xec\x10\x00\x00\x00\x00^\x7f\xf3\x10\x00\x00\x00\x00_\x94\xce\x10\x00\x00\x00\x00`_\xd5\x10\x00\x00\x00\x00a}\xea\x90\x00\x00\x00\x00b?\xb7\x10\x00\x00\x00\x00c]\xcc\x90\x00\x00\x00\x00d\x1f\x99\x10\x00\x00\x00\x00e=\xae\x90\x00\x00\x00\x00f\x08\xb5\x90\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x02\xff\xff\xebh\x00\x00\xff\xff\xe3\xe0\x00\x04\xff\xff\xf1\xf0\x01\x08\xff\xff\xf1\xf0\x00\x08\x00\x00\x00\x00\x01\x0cLMT\x00-02\x00-01\x00+00\x00\x0a<-02>2<-01>,M3.5.0/-1,M10.5.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x10\x00\x00\x00America/ShiprockTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xa2e\xfe\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4E\xe0\x90\xff\xff\xff\xff\xa4\x8f\xa6\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\x94\x00\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x9d\x94\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81{\xc1\x92\xbc\x03\x00\x00\xbc\x03\x00\x00\x0d\x00\x00\x00America/SitkaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x09\x00\x00\x00\x22\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x873\x99\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x06\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x00\x00\xd2\xa7\x00\x00\xff\xff\x81'\x00\x00\xff\xff\x8f\x80\x00\x04\xff\xff\x9d\x90\x01\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x81p\x00\x14\xff\xff\x8f\x80\x01\x18\xff\xff\x81p\x00\x1dLMT\x00PST\x00PWT\x00PPT\x00PDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00America/St_BarthelemyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeah\x06\xd2V\x07\x00\x00V\x07\x00\x00\x10\x00\x00\x00America/St_JohnsTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\x00\x00\x00\x08\x00\x00\x00\x19\xff\xff\xff\xff^=4\xec\xff\xff\xff\xff\x9c\xcfb\x0c\xff\xff\xff\xff\x9d\xa4\xe6\xfc\xff\xff\xff\xff\x9e\xb8~\x8c\xff\xff\xff\xff\x9f\xba\xd6|\xff\xff\xff\xff\xa0\xb6\x88\xdc\xff\xff\xff\xff\xa18\xffL\xff\xff\xff\xff\xa2\x95\x19\x5c\xff\xff\xff\xff\xa3\x84\xfcL\xff\xff\xff\xff\xa4t\xfb\x5c\xff\xff\xff\xff\xa5d\xdeL\xff\xff\xff\xff\xa6^\x17\xdc\xff\xff\xff\xff\xa7D\xc0L\xff\xff\xff\xff\xa8=\xf9\xdc\xff\xff\xff\xff\xa9$\xa2L\xff\xff\xff\xff\xaa\x1d\xdb\xdc\xff\xff\xff\xff\xab\x04\x84L\xff\xff\xff\xff\xab\xfd\xbd\xdc\xff\xff\xff\xff\xac\xe4fL\xff\xff\xff\xff\xad\xdd\x9f\xdc\xff\xff\xff\xff\xae\xcd\x82\xcc\xff\xff\xff\xff\xaf\xbd\x81\xdc\xff\xff\xff\xff\xb0\xadd\xcc\xff\xff\xff\xff\xb1\xa6\x9e\x5c\xff\xff\xff\xff\xb2\x8dF\xcc\xff\xff\xff\xff\xb3\x86\x80\x5c\xff\xff\xff\xff\xb4m(\xcc\xff\xff\xff\xff\xb5fb\x5c\xff\xff\xff\xff\xb6M\x0a\xcc\xff\xff\xff\xff\xb7FD\x5c\xff\xff\xff\xff\xb8,\xec\xcc\xff\xff\xff\xff\xb9&&\x5c\xff\xff\xff\xff\xba\x16\x09L\xff\xff\xff\xff\xbb\x0fB\xdc\xff\xff\xff\xff\xbb\xf5\xebL\xff\xff\xff\xff\xbc\xef$\xdc\xff\xff\xff\xff\xbd\xd5\xcdL\xff\xff\xff\xff\xbe\x9eMl\xff\xff\xff\xff\xbe\xcf\x06\xa8\xff\xff\xff\xff\xbf\xb5\xaf\x18\xff\xff\xff\xff\xc0\xb818\xff\xff\xff\xff\xc1y\xef\xa8\xff\xff\xff\xff\xc2\x98\x138\xff\xff\xff\xff\xc3Y\xd1\xa8\xff\xff\xff\xff\xc4w\xf58\xff\xff\xff\xff\xc59\xb3\xa8\xff\xff\xff\xff\xc6a\x11\xb8\xff\xff\xff\xff\xc7\x19\x95\xa8\xff\xff\xff\xff\xc8@\xf3\xb8\xff\xff\xff\xff\xc9\x02\xb2(\xff\xff\xff\xff\xca \xd5\xb8\xff\xff\xff\xff\xca\xe2\x94(\xff\xff\xff\xff\xcc\x00\xb7\xb8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xe6\xc8\xff\xff\xff\xff\xd3\x88D\xd8\xff\xff\xff\xff\xd4J\x03H\xff\xff\xff\xff\xd5h&\xd8\xff\xff\xff\xff\xd6)\xe5H\xff\xff\xff\xff\xd7H\x08\xd8\xff\xff\xff\xff\xd8\x09\xc7H\xff\xff\xff\xff\xd9'\xea\xd8\xff\xff\xff\xff\xd9\xe9\xa9H\xff\xff\xff\xff\xdb\x11\x07X\xff\xff\xff\xff\xdb\xd2\xc5\xc8\xff\xff\xff\xff\xdc\xdetX\xff\xff\xff\xff\xdd\xa9mH\xff\xff\xff\xff\xde\xbeVX\xff\xff\xff\xff\xdf\x89OH\xff\xff\xff\xff\xe0\x9e8X\xff\xff\xff\xff\xe1i1H\xff\xff\xff\xff\xe2~\x1aX\xff\xff\xff\xff\xe3I\x13H\xff\xff\xff\xff\xe4]\xfcX\xff\xff\xff\xff\xe5(\xf5H\xff\xff\xff\xff\xe6G\x18\xd8\xff\xff\xff\xff\xe7\x12\x11\xc8\xff\xff\xff\xff\xe8&\xfa\xd8\xff\xff\xff\xff\xe8\xf1\xf3\xc8\xff\xff\xff\xff\xea\x06\xdc\xd8\xff\xff\xff\xff\xea\xd1\xd5\xc8\xff\xff\xff\xff\xeb\xe6\xbe\xd8\xff\xff\xff\xff\xec\xb1\xb7\xc8\xff\xff\xff\xff\xed\xc6\xa0\xd8\xff\xff\xff\xff\xee\xbf\xbeH\xff\xff\xff\xff\xef\xaf\xbdX\xff\xff\xff\xff\xf0\x9f\xa0H\xff\xff\xff\xff\xf1\x8f\x9fX\xff\xff\xff\xff\xf2\x7f\x82H\xff\xff\xff\xff\xf3o\x81X\xff\xff\xff\xff\xf4_dH\xff\xff\xff\xff\xf5OcX\xff\xff\xff\xff\xf6?FH\xff\xff\xff\xff\xf7/EX\xff\xff\xff\xff\xf8(b\xc8\xff\xff\xff\xff\xf9\x0f'X\xff\xff\xff\xff\xfa\x08D\xc8\xff\xff\xff\xff\xfa\xf8C\xd8\xff\xff\xff\xff\xfb\xe8&\xc8\xff\xff\xff\xff\xfc\xd8%\xd8\xff\xff\xff\xff\xfd\xc8\x08\xc8\xff\xff\xff\xff\xfe\xb8\x07\xd8\xff\xff\xff\xff\xff\xa7\xea\xc8\x00\x00\x00\x00\x00\x97\xe9\xd8\x00\x00\x00\x00\x01\x87\xcc\xc8\x00\x00\x00\x00\x02w\xcb\xd8\x00\x00\x00\x00\x03p\xe9H\x00\x00\x00\x00\x04`\xe8X\x00\x00\x00\x00\x05P\xcbH\x00\x00\x00\x00\x06@\xcaX\x00\x00\x00\x00\x070\xadH\x00\x00\x00\x00\x08 \xacX\x00\x00\x00\x00\x09\x10\x8fH\x00\x00\x00\x00\x0a\x00\x8eX\x00\x00\x00\x00\x0a\xf0qH\x00\x00\x00\x00\x0b\xe0pX\x00\x00\x00\x00\x0c\xd9\x8d\xc8\x00\x00\x00\x00\x0d\xc0RX\x00\x00\x00\x00\x0e\xb9o\xc8\x00\x00\x00\x00\x0f\xa9n\xd8\x00\x00\x00\x00\x10\x99Q\xc8\x00\x00\x00\x00\x11\x89P\xd8\x00\x00\x00\x00\x12y3\xc8\x00\x00\x00\x00\x13i2\xd8\x00\x00\x00\x00\x14Y\x15\xc8\x00\x00\x00\x00\x15I\x14\xd8\x00\x00\x00\x00\x168\xf7\xc8\x00\x00\x00\x00\x17(\xf6\xd8\x00\x00\x00\x00\x18\x22\x14H\x00\x00\x00\x00\x19\x08\xd8\xd8\x00\x00\x00\x00\x1a\x01\xf6H\x00\x00\x00\x00\x1a\xf1\xf5X\x00\x00\x00\x00\x1b\xe1\xd8H\x00\x00\x00\x00\x1c\xd1\xd7X\x00\x00\x00\x00\x1d\xc1\xbaH\x00\x00\x00\x00\x1e\xb1\xb9X\x00\x00\x00\x00\x1f\xa1\x9cH\x00\x00\x00\x00 u\xcf\xf4\x00\x00\x00\x00!\x81bd\x00\x00\x00\x00\x22U\xb1\xf4\x00\x00\x00\x00#jp\xd4\x00\x00\x00\x00$5\x93\xf4\x00\x00\x00\x00%J`\xe4\x00\x00\x00\x00&\x15u\xf4\x00\x00\x00\x00'*B\xe4\x00\x00\x00\x00'\xfe\x92t\x00\x00\x00\x00)\x0a$\xe4\x00\x00\x00\x00)\xdett\x00\x00\x00\x00*\xea\x06\xe4\x00\x00\x00\x00+\xbeVt\x00\x00\x00\x00,\xd3#d\x00\x00\x00\x00-\x9e8t\x00\x00\x00\x00.\xb3\x05d\x00\x00\x00\x00/~\x1at\x00\x00\x00\x000\x92\xe7d\x00\x00\x00\x001g6\xf4\x00\x00\x00\x002r\xc9d\x00\x00\x00\x003G\x18\xf4\x00\x00\x00\x004R\xabd\x00\x00\x00\x005&\xfa\xf4\x00\x00\x00\x0062\x8dd\x00\x00\x00\x007\x06\xdc\xf4\x00\x00\x00\x008\x1b\xa9\xe4\x00\x00\x00\x008\xe6\xbe\xf4\x00\x00\x00\x009\xfb\x8b\xe4\x00\x00\x00\x00:\xc6\xa0\xf4\x00\x00\x00\x00;\xdbm\xe4\x00\x00\x00\x00<\xaf\xbdt\x00\x00\x00\x00=\xbbO\xe4\x00\x00\x00\x00>\x8f\x9ft\x00\x00\x00\x00?\x9b1\xe4\x00\x00\x00\x00@o\x81t\x00\x00\x00\x00A\x84Nd\x00\x00\x00\x00BOct\x00\x00\x00\x00Cd0d\x00\x00\x00\x00D/Et\x00\x00\x00\x00ED\x12d\x00\x00\x00\x00E\xf3w\xf4\x00\x00\x00\x00G-.\xe4\x00\x00\x00\x00G\xd3Y\xf4\x00\x00\x00\x00I\x0d\x10\xe4\x00\x00\x00\x00I\xb3;\xf4\x00\x00\x00\x00J\xec\xf2\xe4\x00\x00\x00\x00K\x9cXt\x00\x00\x00\x00L\xd6\x0fd\x00\x00\x00\x00M|:t\x00\x00\x00\x00N\xafY\xa8\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x05\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x07\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x03\xff\xff\xce\x94\x00\x00\xff\xff\xdc\xa4\x01\x04\xff\xff\xce\x94\x00\x08\xff\xff\xdc\xd8\x01\x04\xff\xff\xce\xc8\x00\x08\xff\xff\xdc\xd8\x01\x0c\xff\xff\xdc\xd8\x01\x10\xff\xff\xea\xe8\x01\x14LMT\x00NDT\x00NST\x00NPT\x00NWT\x00NDDT\x00\x0aNST3:30NDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00America/St_KittsTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00America/St_LuciaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x11\x00\x00\x00America/St_ThomasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00America/St_VincentTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xd8\x19\x9dp\x01\x00\x00p\x01\x00\x00\x15\x00\x00\x00America/Swift_CurrentTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x86\xfd\x96\x18\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd3v\x01\x10\xff\xff\xff\xff\xd4So\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\xff\xff\xff\xff\xd75\xc5\x10\xff\xff\xff\xff\xd8\x00\xbe\x00\xff\xff\xff\xff\xd9\x15\xa7\x10\xff\xff\xff\xff\xd9\xe0\xa0\x00\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe9\x17\x0f\x00\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xd6\xd3\x00\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xcb\x00\xff\xff\xff\xff\xef\xaf\xee\x90\xff\xff\xff\xff\xf0q\xad\x00\x00\x00\x00\x00\x04a\x19\x90\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\xff\xff\x9a\xe8\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xab\xa0\x00\x14LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x13z\xe2\xc2\x00\x00\x00\xc2\x00\x00\x00\x13\x00\x00\x00America/TegucigalpaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa4LKD\x00\x00\x00\x00 \x9a\xdc\xe0\x00\x00\x00\x00!\x5c\x9bP\x00\x00\x00\x00\x22z\xbe\xe0\x00\x00\x00\x00#<}P\x00\x00\x00\x00D]\x8c\xe0\x00\x00\x00\x00D\xd6\xc8\xd0\x02\x01\x02\x01\x02\x01\x02\xff\xff\xae<\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08LMT\x00CDT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x0d\xf7\xd3\xc7\x01\x00\x00\xc7\x01\x00\x00\x0d\x00\x00\x00America/ThuleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x9b\x80w\xfc\x00\x00\x00\x00'\xf5z\xe0\x00\x00\x00\x00(\xe5]\xd0\x00\x00\x00\x00)\xd5\x5c\xe0\x00\x00\x00\x00*\xc5?\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xbf\x84\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00ADT\x00AST\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x13\x00\x00\x00America/Thunder_BayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x0f\x00\x00\x00America/TijuanaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xa9yOp\xff\xff\xff\xff\xaf\xf2|\xf0\xff\xff\xff\xff\xb6fdp\xff\xff\xff\xff\xb7\x1b\x10\x00\xff\xff\xff\xff\xb8\x0a\xf2\xf0\xff\xff\xff\xff\xcb\xea\x8d\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\x99\xbap\xff\xff\xff\xff\xd7\x1bY\x00\xff\xff\xff\xff\xd8\x91\xb4\xf0\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00F\x0f\x82\xa0\x00\x00\x00\x00G$O\x90\x00\x00\x00\x00G\xf8\x9f \x00\x00\x00\x00I\x041\x90\x00\x00\x00\x00I\xd8\x81 \x00\x00\x00\x00J\xe4\x13\x90\x00\x00\x00\x00K=\xab\x80\x01\x02\x01\x02\x03\x02\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x02\xff\xff\x92L\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x9d\x90\x01\x14LMT\x00MST\x00PST\x00PDT\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0f\x00\x00\x00America/TorontoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00America/TortolaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U9#\xbe2\x05\x00\x002\x05\x00\x00\x11\x00\x00\x00America/VancouverTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^=v\xec\xff\xff\xff\xff\x9e\xb8\xbd\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd3v\x0f \xff\xff\xff\xff\xd4A\x08\x10\xff\xff\xff\xff\xd5U\xf1 \xff\xff\xff\xff\xd6 \xea\x10\xff\xff\xff\xff\xd75\xd3 \xff\xff\xff\xff\xd8\x00\xcc\x10\xff\xff\xff\xff\xd9\x15\xb5 \xff\xff\xff\xff\xd9\xe0\xae\x10\xff\xff\xff\xff\xda\xfe\xd1\xa0\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xb3\xa0\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x95\xa0\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ew\xa0\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~Y\xa0\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^;\xa0\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GX \xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8': \xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x1c \xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xfe \xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xe0 \xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xfc\xa0\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xde\xa0\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xc0\xa0\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\xa2\xa0\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/\x84\xa0\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0ff\xa0\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x08 \xeb\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x0a\x00\xcd\xa0\x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x8c\x94\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10LMT\x00PDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0e\x00\x00\x00America/VirginTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x1d\xee\x91\x05\x04\x00\x00\x05\x04\x00\x00\x12\x00\x00\x00America/WhitehorseTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x09\x00\x00\x00%\xff\xff\xff\xff}\x86\x8a\x9c\xff\xff\xff\xff\x9e\xb8\xcb\xb0\xff\xff\xff\xff\x9f\xbb#\xa0\xff\xff\xff\xff\xa0\xd0\x0c\xb0\xff\xff\xff\xff\xa1\xa2\xd2\x80\xff\xff\xff\xff\xcb\x89(\xb0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a4 \xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf8\xc5\x84\x90\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x00\x00\x00\x00G-\x8a\x10\x00\x00\x00\x00G\xd3\xb5 \x00\x00\x00\x00I\x0dl\x10\x00\x00\x00\x00I\xb3\x97 \x00\x00\x00\x00J\xedN\x10\x00\x00\x00\x00K\x9c\xb3\xa0\x00\x00\x00\x00L\xd6j\x90\x00\x00\x00\x00M|\x95\xa0\x00\x00\x00\x00N\xb6L\x90\x00\x00\x00\x00O\x5cw\xa0\x00\x00\x00\x00P\x96.\x90\x00\x00\x00\x00Q\x8f\xde\x80\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xa4\xec\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00CDT\x00CST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\xdb~\xab\xb2\x03\x00\x00\xb2\x03\x00\x00\x0f\x00\x00\x00America/YakutatTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x08\x00\x00\x00\x1e\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x877\xbf\xff\xff\xff\xff\xcb\x89(\xb0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a4 \xff\xff\xff\xff\xfe\xb8U0\xff\xff\xff\xff\xff\xa88 \x00\x00\x00\x00\x00\x9870\x00\x00\x00\x00\x01\x88\x1a \x00\x00\x00\x00\x02x\x190\x00\x00\x00\x00\x03q6\xa0\x00\x00\x00\x00\x04a5\xb0\x00\x00\x00\x00\x05Q\x18\xa0\x00\x00\x00\x00\x06A\x17\xb0\x00\x00\x00\x00\x070\xfa\xa0\x00\x00\x00\x00\x07\x8dQ\xb0\x00\x00\x00\x00\x09\x10\xdc\xa0\x00\x00\x00\x00\x09\xad\xcd0\x00\x00\x00\x00\x0a\xf0\xbe\xa0\x00\x00\x00\x00\x0b\xe0\xbd\xb0\x00\x00\x00\x00\x0c\xd9\xdb \x00\x00\x00\x00\x0d\xc0\x9f\xb0\x00\x00\x00\x00\x0e\xb9\xbd \x00\x00\x00\x00\x0f\xa9\xbc0\x00\x00\x00\x00\x10\x99\x9f \x00\x00\x00\x00\x11\x89\x9e0\x00\x00\x00\x00\x12y\x81 \x00\x00\x00\x00\x13i\x800\x00\x00\x00\x00\x14Yc \x00\x00\x00\x00\x15Ib0\x00\x00\x00\x00\x169E \x00\x00\x00\x00\x17)D0\x00\x00\x00\x00\x18\x22a\xa0\x00\x00\x00\x00\x19\x09&0\x00\x00\x00\x00\x1a\x02C\xa0\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x00\x00\xce\x81\x00\x00\xff\xff}\x01\x00\x00\xff\xff\x81p\x00\x04\xff\xff\x8f\x80\x01\x08\xff\xff\x8f\x80\x01\x0c\xff\xff\x8f\x80\x01\x10\xff\xff\x8f\x80\x01\x14\xff\xff\x81p\x00\x19LMT\x00YST\x00YWT\x00YPT\x00YDT\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x13\x00\x00\x00America/YellowknifeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x88\xde\xce\xe0\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x98\x91\x90\xff\xff\xff\xff\xa0\xd2\x85\x80\xff\xff\xff\xff\xa2\x8a\xe8\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4j\xca\x90\xff\xff\xff\xff\xa55\xc3\x80\xff\xff\xff\xff\xa6S\xe7\x10\xff\xff\xff\xff\xa7\x15\xa5\x80\xff\xff\xff\xff\xa83\xc9\x10\xff\xff\xff\xff\xa8\xfe\xc2\x00\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xdd\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xbf\x90\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x95\xa0\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\x83\xf2b\x1f\x01\x00\x00\x1f\x01\x00\x00\x10\x00\x00\x00Antarctica/CaseyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xfe\x1e\xcc\x80\x00\x00\x00\x00J\xda\x06 \x00\x00\x00\x00K\x8f\xca\xf0\x00\x00\x00\x00N\xa9\x9c \x00\x00\x00\x00OC\xcd\x90\x00\x00\x00\x00X\x0a;\x80\x00\x00\x00\x00Z\xa4\x0f\x10\x00\x00\x00\x00[\xb9\x14@\x00\x00\x00\x00\x5c\x8d\x1d\x80\x00\x00\x00\x00]\x96E0\x00\x00\x00\x00^c\xc5\x00\x00\x00\x00\x00_x\xa0<\x00\x00\x00\x00`L\xb7P\x00\x00\x00\x00aX\x82<\x00\x00\x00\x00b,\x99P\x00\x00\x00\x00c8d<\x00\x00\x00\x00d\x08\xb1\x00\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x9a\xb0\x00\x08-00\x00+08\x00+11\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95\xea\x06\xd3\xc5\x00\x00\x00\xc5\x00\x00\x00\x10\x00\x00\x00Antarctica/DavisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xe7\x9c@\x00\xff\xff\xff\xff\xf6G\xdf\x10\xff\xff\xff\xff\xfeG\xab\x00\x00\x00\x00\x00J\xda\x140\x00\x00\x00\x00K\x97\xfa@\x00\x00\x00\x00N\xa9\xaa0\x00\x00\x00\x00OC\xf7\xc0\x01\x00\x01\x02\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00bp\x00\x04\x00\x00FP\x00\x08-00\x00+07\x00+05\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x19\x00\x00\x00Antarctica/DumontDUrvilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d?\xb2\x14\xd0\x03\x00\x00\xd0\x03\x00\x00\x14\x00\x00\x00Antarctica/MacquarieTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff|\x05\x16\x00\xff\xff\xff\xff\x9b\xd5x\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xa0\x87\xb4`\xff\xff\xff\xff\xd7\x0ch\x00\xff\xff\xff\xff\xfb\xc2\x8d\x00\xff\xff\xff\xff\xfc\xb2~\x00\xff\xff\xff\xff\xfd\xc7Y\x00\xff\xff\xff\xff\xfev\xb0\x80\xff\xff\xff\xff\xff\xa7;\x00\x00\x00\x00\x00\x00V\x92\x80\x00\x00\x00\x00\x01\x87\x1d\x00\x00\x00\x00\x00\x02?\xaf\x00\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x03O\x00\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xe31\x00\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1eg'\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xed\xe1\x80\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xcd\xc3\x80\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xad\xa5\x80\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x8d\x87\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000mi\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002V\x86\x00\x00\x00\x00\x003=<\x80\x00\x00\x00\x0046h\x00\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x16J\x00\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x007\xf6,\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xbf*\x80\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\x9f\x0c\x80\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?~\xee\x80\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A^\xd0\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00C>\xb2\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00E\x1e\x94\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G\x07\xb1\x00\x00\x00\x00\x00G\xf7\xa2\x00\x00\x00\x00\x00H\xe7\x93\x00\x00\x00\x00\x00I\xd7\x84\x00\x00\x00\x00\x00J\xc7u\x00\x00\x00\x00\x00M\x1d\xd3\xd0\x01\x02\x01\x00\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x02\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\x9a\xb0\x01\x09-00\x00AEST\x00AEDT\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7N\xab\x8b\x98\x00\x00\x00\x98\x00\x00\x00\x11\x00\x00\x00Antarctica/MawsonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xe2 2\x80\x00\x00\x00\x00J\xda\x22@\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00T`\x00\x04\x00\x00FP\x00\x08-00\x00+06\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x12\x00\x00\x00Antarctica/McMurdoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x13\xff\xff\xff\xffA\xb7L\xa8\xff\xff\xff\xff\xb0\xb4\xb2\xe8\xff\xff\xff\xff\xb1Q\x87X\xff\xff\xff\xff\xb2x\xe5h\xff\xff\xff\xff\xb3C\xe5`\xff\xff\xff\xff\xb4X\xc7h\xff\xff\xff\xff\xb5#\xc7`\xff\xff\xff\xff\xb68\xa9h\xff\xff\xff\xff\xb7\x03\xa9`\xff\xff\xff\xff\xb8\x18\x8bh\xff\xff\xff\xff\xb8\xec\xc5\xe0\xff\xff\xff\xff\xb9\xf8mh\xff\xff\xff\xff\xba\xcc\xa7\xe0\xff\xff\xff\xff\xbb\xd8Oh\xff\xff\xff\xff\xbc\xe3\xe8\xe0\xff\xff\xff\xff\xbd\xae\xf6\xe8\xff\xff\xff\xff\xbe\xc3\xca\xe0\xff\xff\xff\xff\xbf\x8e\xd8\xe8\xff\xff\xff\xff\xc0\xa3\xac\xe0\xff\xff\xff\xff\xc1n\xba\xe8\xff\xff\xff\xff\xc2\x83\x8e\xe0\xff\xff\xff\xff\xc3N\x9c\xe8\xff\xff\xff\xff\xc4cp\xe0\xff\xff\xff\xff\xc5.~\xe8\xff\xff\xff\xff\xc6L\x8d`\xff\xff\xff\xff\xc7\x0e`\xe8\xff\xff\xff\xff\xc8,o`\xff\xff\xff\xff\xc8\xf7}h\xff\xff\xff\xff\xd2\xda\x9a@\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x02\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x00\x00\xa3\xd8\x00\x00\x00\x00\xaf\xc8\x01\x04\x00\x00\xa1\xb8\x00\x09\x00\x00\xa8\xc0\x01\x04\x00\x00\xb6\xd0\x01\x0e\x00\x00\xa8\xc0\x00\x04LMT\x00NZST\x00NZMT\x00NZDT\x00\x0aNZST-12NZDT,M9.5.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95{\xf3\xa9w\x03\x00\x00w\x03\x00\x00\x11\x00\x00\x00Antarctica/PalmerTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xf6\x98\xad\x00\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00\x170\xbc\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00XC\x86\xb0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x00\x00\x00\x00\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xe3\xe0\x01\x0c\xff\xff\xd5\xd0\x00\x08-00\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6\x89\xf71\x84\x00\x00\x00\x84\x00\x00\x00\x12\x00\x00\x00Antarctica/RotheraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\x00\x00\x00\x00\x0d\x02-\x00\x01\x00\x00\x00\x00\x00\x00\xff\xff\xd5\xd0\x00\x04-00\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x15\x00\x00\x00Antarctica/South_PoleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x13\xff\xff\xff\xffA\xb7L\xa8\xff\xff\xff\xff\xb0\xb4\xb2\xe8\xff\xff\xff\xff\xb1Q\x87X\xff\xff\xff\xff\xb2x\xe5h\xff\xff\xff\xff\xb3C\xe5`\xff\xff\xff\xff\xb4X\xc7h\xff\xff\xff\xff\xb5#\xc7`\xff\xff\xff\xff\xb68\xa9h\xff\xff\xff\xff\xb7\x03\xa9`\xff\xff\xff\xff\xb8\x18\x8bh\xff\xff\xff\xff\xb8\xec\xc5\xe0\xff\xff\xff\xff\xb9\xf8mh\xff\xff\xff\xff\xba\xcc\xa7\xe0\xff\xff\xff\xff\xbb\xd8Oh\xff\xff\xff\xff\xbc\xe3\xe8\xe0\xff\xff\xff\xff\xbd\xae\xf6\xe8\xff\xff\xff\xff\xbe\xc3\xca\xe0\xff\xff\xff\xff\xbf\x8e\xd8\xe8\xff\xff\xff\xff\xc0\xa3\xac\xe0\xff\xff\xff\xff\xc1n\xba\xe8\xff\xff\xff\xff\xc2\x83\x8e\xe0\xff\xff\xff\xff\xc3N\x9c\xe8\xff\xff\xff\xff\xc4cp\xe0\xff\xff\xff\xff\xc5.~\xe8\xff\xff\xff\xff\xc6L\x8d`\xff\xff\xff\xff\xc7\x0e`\xe8\xff\xff\xff\xff\xc8,o`\xff\xff\xff\xff\xc8\xf7}h\xff\xff\xff\xff\xd2\xda\x9a@\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x02\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x00\x00\xa3\xd8\x00\x00\x00\x00\xaf\xc8\x01\x04\x00\x00\xa1\xb8\x00\x09\x00\x00\xa8\xc0\x01\x04\x00\x00\xb6\xd0\x01\x0e\x00\x00\xa8\xc0\x00\x04LMT\x00NZST\x00NZMT\x00NZDT\x00\x0aNZST-12NZDT,M9.5.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x10\x00\x00\x00Antarctica/SyowaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xd5\x1b6\xb4\x01\x00\x00+\xcc\x00\x00\x00\x00*0\x00\x04LMT\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf54\x89F\x9e\x00\x00\x00\x9e\x00\x00\x00\x10\x00\x00\x00Antarctica/TrollTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\x00\x00\x00\x00B\x0dG\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04-00\x00+00\x00\x0a<+00>0<+02>-2,M3.5.0/1,M10.5.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x16\xf4\xe0\xaa\x00\x00\x00\xaa\x00\x00\x00\x11\x00\x00\x00Antarctica/VostokTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xe9X\x89\x80\x00\x00\x00\x00-M9\x10\x00\x00\x00\x00.\xb5\x85\x00\x00\x00\x00\x00e\x7fE0\x01\x00\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00bp\x00\x04\x00\x00FP\x00\x08-00\x00+07\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x13\x00\x00\x00Arctic/LongyearbyenTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xb6\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xff\xd2\xa1O\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xff\xd5\xa8s\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c9f;j\x02\x00\x00j\x02\x00\x00\x0b\x00\x00\x00Asia/AlmatyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19{\xdc\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)x\x95P\x00\x00\x00\x00)\xd4\xd0@\x00\x00\x00\x00*\xc4\xc1@\x00\x00\x00\x00+\xb4\xb2@\x00\x00\x00\x00,\xa4\xa3@\x00\x00\x00\x00-\x94\x94@\x00\x00\x00\x00.\x84\x85@\x00\x00\x00\x00/tv@\x00\x00\x00\x000dg@\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x002rm\xc0\x00\x00\x00\x003=t\xc0\x00\x00\x00\x004RO\xc0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x00621\xc0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1bN@\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb0@\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x12@\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00e\xe0\xc6 \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x01\x00\x00H$\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0cLMT\x00+05\x00+07\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x0ds\xad\xa0\x03\x00\x00\xa0\x03\x00\x00\x0a\x00\x00\x00Asia/AmmanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xb6\xa3\xd6\xd0\x00\x00\x00\x00\x06ry\xe0\x00\x00\x00\x00\x07\x0c\xabP\x00\x00\x00\x00\x08$7`\x00\x00\x00\x00\x08\xed\xde\xd0\x00\x00\x00\x00\x0a\x05j\xe0\x00\x00\x00\x00\x0a\xcf\x12P\x00\x00\x00\x00\x0b\xe7\xef\xe0\x00\x00\x00\x00\x0c\xdau\xd0\x00\x00\x00\x00\x0d\xc9#`\x00\x00\x00\x00\x0e\x92\xca\xd0\x00\x00\x00\x00\x0f\xa9\x05`\x00\x00\x00\x00\x10r\xac\xd0\x00\x00\x00\x00\x1c\xad\xd5`\x00\x00\x00\x00\x1d\x9f\x09\xd0\x00\x00\x00\x00\x1e\x92\xfd`\x00\x00\x00\x00\x1f\x82\xe0P\x00\x00\x00\x00 r\xdf`\x00\x00\x00\x00!b\xc2P\x00\x00\x00\x00\x22R\xc1`\x00\x00\x00\x00#K\xde\xd0\x00\x00\x00\x00$d\xbc`\x00\x00\x00\x00%+\xc0\xd0\x00\x00\x00\x00&7o`\x00\x00\x00\x00'\x0b\xa2\xd0\x00\x00\x00\x00(\x0bs\xe0\x00\x00\x00\x00(\xe2JP\x00\x00\x00\x00)\xe4\xbe`\x00\x00\x00\x00*\xcbf\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\xabH\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00.x\xb5\xd0\x00\x00\x00\x00/\x84d`\x00\x00\x00\x000X\xa5\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\x0a`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007z\x93`\x00\x00\x00\x007\xea\xa2\xe0\x00\x00\x00\x008\xe2|\xe0\x00\x00\x00\x009\xd3\xbf`\x00\x00\x00\x00:\xc2^\xe0\x00\x00\x00\x00;\xb3\xa1`\x00\x00\x00\x00<\xa3\x92`\x00\x00\x00\x00=\x93\x83`\x00\x00\x00\x00>\x83t`\x00\x00\x00\x00?\x98O`\x00\x00\x00\x00@cV`\x00\x00\x00\x00An\xf6\xe0\x00\x00\x00\x00BLr\xe0\x00\x00\x00\x00C-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xe0\xe7!\xe7\x02\x00\x00\xe7\x02\x00\x00\x0b\x00\x00\x00Asia/AnadyrTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\xaa\x19\x1d\x9c\xff\xff\xff\xff\xb5\xa3\x8c\xc0\x00\x00\x00\x00\x15'\x1b0\x00\x00\x00\x00\x16\x18O\xa0\x00\x00\x00\x00\x17\x08N\xb0\x00\x00\x00\x00\x17\xf9\x910\x00\x00\x00\x00\x18\xe9\x90@\x00\x00\x00\x00\x19\xda\xc4\xb0\x00\x00\x00\x00\x1a\xcc\x15@\x00\x00\x00\x00\x1b\xbc\x22`\x00\x00\x00\x00\x1c\xac\x13`\x00\x00\x00\x00\x1d\x9c\x04`\x00\x00\x00\x00\x1e\x8b\xf5`\x00\x00\x00\x00\x1f{\xe6`\x00\x00\x00\x00 k\xd7`\x00\x00\x00\x00![\xc8`\x00\x00\x00\x00\x22K\xb9`\x00\x00\x00\x00#;\xaa`\x00\x00\x00\x00$+\x9b`\x00\x00\x00\x00%\x1b\x8c`\x00\x00\x00\x00&\x0b}`\x00\x00\x00\x00'\x04\xa8\xe0\x00\x00\x00\x00'\xf4\x99\xe0\x00\x00\x00\x00(\xe4\x98\xf0\x00\x00\x00\x00)x@\xf0\x00\x00\x00\x00)\xd4{\xe0\x00\x00\x00\x00*\xc4l\xe0\x00\x00\x00\x00+\xb4]\xe0\x00\x00\x00\x00,\xa4N\xe0\x00\x00\x00\x00-\x94?\xe0\x00\x00\x00\x00.\x840\xe0\x00\x00\x00\x00/t!\xe0\x00\x00\x00\x000d\x12\xe0\x00\x00\x00\x001]>`\x00\x00\x00\x002r\x19`\x00\x00\x00\x003= `\x00\x00\x00\x004Q\xfb`\x00\x00\x00\x005\x1d\x02`\x00\x00\x00\x0061\xdd`\x00\x00\x00\x006\xfc\xe4`\x00\x00\x00\x008\x1a\xf9\xe0\x00\x00\x00\x008\xdc\xc6`\x00\x00\x00\x009\xfa\xdb\xe0\x00\x00\x00\x00:\xbc\xa8`\x00\x00\x00\x00;\xda\xbd\xe0\x00\x00\x00\x00<\xa5\xc4\xe0\x00\x00\x00\x00=\xba\x9f\xe0\x00\x00\x00\x00>\x85\xa6\xe0\x00\x00\x00\x00?\x9a\x81\xe0\x00\x00\x00\x00@e\x88\xe0\x00\x00\x00\x00A\x83\x9e`\x00\x00\x00\x00BEj\xe0\x00\x00\x00\x00Cc\x80`\x00\x00\x00\x00D%L\xe0\x00\x00\x00\x00ECb`\x00\x00\x00\x00F\x05.\xe0\x00\x00\x00\x00G#D`\x00\x00\x00\x00G\xeeK`\x00\x00\x00\x00I\x03&`\x00\x00\x00\x00I\xce-`\x00\x00\x00\x00J\xe3\x08`\x00\x00\x00\x00K\xae\x0f`\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x01\x03\x02\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x05\x06\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x05\x06\x01\x00\x00\xa6d\x00\x00\x00\x00\xa8\xc0\x00\x04\x00\x00\xc4\xe0\x01\x08\x00\x00\xb6\xd0\x00\x0c\x00\x00\xb6\xd0\x01\x0c\x00\x00\xa8\xc0\x01\x04\x00\x00\x9a\xb0\x00\x10LMT\x00+12\x00+14\x00+13\x00+11\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x81\x18G^\x02\x00\x00^\x02\x00\x00\x0a\x00\x00\x00Asia/AqtauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x94\xe0\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000d\x83`\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r\x89\xe0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004Rk\xe0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x0062M\xe0\x00\x00\x00\x006\xfdT\xe0\x00\x00\x00\x008\x1bj`\x00\x00\x00\x008\xdd6\xe0\x00\x00\x00\x009\xfbL`\x00\x00\x00\x00:\xbd\x18\xe0\x00\x00\x00\x00;\xdb.`\x00\x00\x00\x00<\xa65`\x00\x00\x00\x00=\xbb\x10`\x00\x00\x00\x00>\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x01\x02\x03\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\x01\x02\x04\x02\x04\x02\x04\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x02\x00\x00/ \x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0c\x00\x00FP\x01\x08LMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\xfa\xb5\xbeg\x02\x00\x00g\x02\x00\x00\x0b\x00\x00\x00Asia/AqtobeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x8eh\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1b\x5cP\x00\x00\x00\x008\xdd(\xd0\x00\x00\x00\x009\xfb>P\x00\x00\x00\x00:\xbd\x0a\xd0\x00\x00\x00\x00;\xdb P\x00\x00\x00\x00<\xa6'P\x00\x00\x00\x00=\xbb\x02P\x00\x00\x00\x00>\x86\x09P\x00\x00\x00\x00?\x9a\xe4P\x00\x00\x00\x00@e\xebP\x00\x00\x00\x00A\x84\x00\xd0\x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x005\x98\x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0c\x00\x00FP\x01\x08LMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x1bb2w\x01\x00\x00w\x01\x00\x00\x0d\x00\x00\x00Asia/AshgabatTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x8dD\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xbf0\x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x00\x006\xbc\x00\x00\x00\x008@\x00\x04\x00\x00T`\x01\x08\x00\x00FP\x00\x0c\x00\x00FP\x01\x0cLMT\x00+04\x00+06\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x1bb2w\x01\x00\x00w\x01\x00\x00\x0e\x00\x00\x00Asia/AshkhabadTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x8dD\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xbf0\x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x00\x006\xbc\x00\x00\x00\x008@\x00\x04\x00\x00T`\x01\x08\x00\x00FP\x00\x0c\x00\x00FP\x01\x0cLMT\x00+04\x00+06\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xa7^\xfah\x02\x00\x00h\x02\x00\x00\x0b\x00\x00\x00Asia/AtyrauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\xaa\x19\x93P\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1bj`\x00\x00\x00\x008\xdd6\xe0\x00\x00\x00\x009\xfbL`\x00\x00\x00\x00:\xbd\x18\xe0\x00\x00\x00\x00;\xdb.`\x00\x00\x00\x00<\xa65`\x00\x00\x00\x00=\xbb\x10`\x00\x00\x00\x00>\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x01\x02\x03\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\x06\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x02\x00\x000\xb0\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0c\x00\x00FP\x01\x08\x00\x008@\x00\x10LMT\x00+03\x00+05\x00+06\x00+04\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7e&uv\x02\x00\x00v\x02\x00\x00\x0c\x00\x00\x00Asia/BaghdadTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x86\xb1\xdc\xff\xff\xff\xff\x9e0<\xe0\x00\x00\x00\x00\x170hP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xe8\xbdP\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbd\xc8@\x00\x00\x00\x00\x1c\xad\xc7P\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf6x\x00\x00\x00\x00\x00(\xe7\xba\x80\x00\x00\x00\x00)\xd8\xfd\x00\x00\x00\x00\x00*\xca?\x80\x00\x00\x00\x00+\xba0\x80\x00\x00\x00\x00,\xabs\x00\x00\x00\x00\x00-\x9bd\x00\x00\x00\x00\x00.\x8c\xa6\x80\x00\x00\x00\x00/|\x97\x80\x00\x00\x00\x000m\xda\x00\x00\x00\x00\x001_\x1c\x80\x00\x00\x00\x002P_\x00\x00\x00\x00\x003@P\x00\x00\x00\x00\x0041\x92\x80\x00\x00\x00\x005!\x83\x80\x00\x00\x00\x006\x12\xc6\x00\x00\x00\x00\x007\x02\xb7\x00\x00\x00\x00\x007\xf3\xf9\x80\x00\x00\x00\x008\xe5<\x00\x00\x00\x00\x009\xd6~\x80\x00\x00\x00\x00:\xc6o\x80\x00\x00\x00\x00;\xb7\xb2\x00\x00\x00\x00\x00<\xa7\xa3\x00\x00\x00\x00\x00=\x98\xe5\x80\x00\x00\x00\x00>\x88\xd6\x80\x00\x00\x00\x00?z\x19\x00\x00\x00\x00\x00@k[\x80\x00\x00\x00\x00A\x5c\x9e\x00\x00\x00\x00\x00BL\x8f\x00\x00\x00\x00\x00C=\xd1\x80\x00\x00\x00\x00D-\xc2\x80\x00\x00\x00\x00E\x1f\x05\x00\x00\x00\x00\x00F\x0e\xf6\x00\x00\x00\x00\x00G\x008\x80\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00)\xa4\x00\x00\x00\x00)\xa0\x00\x04\x00\x00*0\x00\x08\x00\x008@\x01\x0cLMT\x00BMT\x00+03\x00+04\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdav\x19z\x98\x00\x00\x00\x98\x00\x00\x00\x0c\x00\x00\x00Asia/BahrainTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa1\xf2\x9d0\x00\x00\x00\x00\x04\x8a\x92\xc0\x01\x02\x00\x000P\x00\x00\x00\x008@\x00\x04\x00\x00*0\x00\x08LMT\x00+04\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x87\xb3<\xe8\x02\x00\x00\xe8\x02\x00\x00\x09\x00\x00\x00Asia/BakuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x95D\xff\xff\xff\xff\xe7\xda\x0cP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x001]\xd9\x10\x00\x00\x00\x002r\xb4\x10\x00\x00\x00\x003=\xad\x00\x00\x00\x00\x004R\x88\x00\x00\x00\x00\x005\x1d\x8f\x00\x00\x00\x00\x0062j\x00\x00\x00\x00\x006\xfdq\x00\x00\x00\x00\x008\x1b\x86\x80\x00\x00\x00\x008\xddS\x00\x00\x00\x00\x009\xfbh\x80\x00\x00\x00\x00:\xbd5\x00\x00\x00\x00\x00;\xdbJ\x80\x00\x00\x00\x00<\xa6Q\x80\x00\x00\x00\x00=\xbb,\x80\x00\x00\x00\x00>\x863\x80\x00\x00\x00\x00?\x9b\x0e\x80\x00\x00\x00\x00@f\x15\x80\x00\x00\x00\x00A\x84+\x00\x00\x00\x00\x00BE\xf7\x80\x00\x00\x00\x00Cd\x0d\x00\x00\x00\x00\x00D%\xd9\x80\x00\x00\x00\x00EC\xef\x00\x00\x00\x00\x00F\x05\xbb\x80\x00\x00\x00\x00G#\xd1\x00\x00\x00\x00\x00G\xee\xd8\x00\x00\x00\x00\x00I\x03\xb3\x00\x00\x00\x00\x00I\xce\xba\x00\x00\x00\x00\x00J\xe3\x95\x00\x00\x00\x00\x00K\xae\x9c\x00\x00\x00\x00\x00L\xcc\xb1\x80\x00\x00\x00\x00M\x8e~\x00\x00\x00\x00\x00N\xac\x93\x80\x00\x00\x00\x00On`\x00\x00\x00\x00\x00P\x8cu\x80\x00\x00\x00\x00QW|\x80\x00\x00\x00\x00RlW\x80\x00\x00\x00\x00S7^\x80\x00\x00\x00\x00TL9\x80\x00\x00\x00\x00U\x17@\x80\x00\x00\x00\x00V,\x1b\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00.\xbc\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0cLMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0c\x00\x00\x00Asia/BangkokTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x85\xc4\xff\xff\xff\xff\xa2jg\xc4\x01\x02\x00\x00^<\x00\x00\x00\x00^<\x00\x04\x00\x00bp\x00\x08LMT\x00BMT\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\xbd\xedL\xf1\x02\x00\x00\xf1\x02\x00\x00\x0c\x00\x00\x00Asia/BarnaulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xd5}\xfc\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00,\xa4\x950\x00\x00\x00\x00-\x94\x860\x00\x00\x00\x00.\x84w0\x00\x00\x00\x00/th0\x00\x00\x00\x00/\xc7L\x80\x00\x00\x00\x000dg@\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x002rm\xc0\x00\x00\x00\x003=t\xc0\x00\x00\x00\x004RO\xc0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x00621\xc0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1bN@\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb0@\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x12@\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00BE\xbf@\x00\x00\x00\x00Cc\xd4\xc0\x00\x00\x00\x00D%\xa1@\x00\x00\x00\x00EC\xb6\xc0\x00\x00\x00\x00F\x05\x83@\x00\x00\x00\x00G#\x98\xc0\x00\x00\x00\x00G\xee\x9f\xc0\x00\x00\x00\x00I\x03z\xc0\x00\x00\x00\x00I\xce\x81\xc0\x00\x00\x00\x00J\xe3\x5c\xc0\x00\x00\x00\x00K\xaec\xc0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x00\x00\x00\x00TK\xf30\x00\x00\x00\x00V\xf6\xea@\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00N\x84\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\x11\xe1[\xdc\x02\x00\x00\xdc\x02\x00\x00\x0b\x00\x00\x00Asia/BeirutTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6\xc2\xb8\xff\xff\xff\xff\xa2ec\xe0\xff\xff\xff\xff\xa3{\x82P\xff\xff\xff\xff\xa4N\x80`\xff\xff\xff\xff\xa5?\xb4\xd0\xff\xff\xff\xff\xa6%'\xe0\xff\xff\xff\xff\xa7'\x7f\xd0\xff\xff\xff\xff\xa8)\xf3\xe0\xff\xff\xff\xff\xa8\xeb\xb2P\xff\xff\xff\xff\xe8*\x85\xe0\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xec\xe0\xff\xff\xff\xff\xec\xb6\x94P\xff\xff\xff\xff\xed\xcfq\xe0\xff\xff\xff\xff\xee\x99\x19P\xff\xff\xff\xff\xef\xb0\xa5`\xff\xff\xff\xff\xf0zL\xd0\x00\x00\x00\x00\x04\xa6^`\x00\x00\x00\x00\x05+w\xd0\x00\x00\x00\x00\x06C\x03\xe0\x00\x00\x00\x00\x07\x0c\xabP\x00\x00\x00\x00\x08$7`\x00\x00\x00\x00\x08\xed\xde\xd0\x00\x00\x00\x00\x0a\x05j\xe0\x00\x00\x00\x00\x0a\xcf\x12P\x00\x00\x00\x00\x0b\xe7\xef\xe0\x00\x00\x00\x00\x0c\xb1\x97P\x00\x00\x00\x00\x0d\xc9#`\x00\x00\x00\x00\x0e\x92\xca\xd0\x00\x00\x00\x00\x0f\xa9\x05`\x00\x00\x00\x00\x10r\xac\xd0\x00\x00\x00\x00\x1a\xf4.\xe0\x00\x00\x00\x00\x1b\xd1\x9c\xd0\x00\x00\x00\x00\x1c\xd5b`\x00\x00\x00\x00\x1d\xb2\xd0P\x00\x00\x00\x00\x1e\xb6\x95\xe0\x00\x00\x00\x00\x1f\x94\x03\xd0\x00\x00\x00\x00 \x97\xc9`\x00\x00\x00\x00!u7P\x00\x00\x00\x00\x22\xa3,\xe0\x00\x00\x00\x00#W\xbcP\x00\x00\x00\x00$g_`\x00\x00\x00\x00%8\xef\xd0\x00\x00\x00\x00&<\xb5`\x00\x00\x00\x00'\x1a#P\x00\x00\x00\x00(\x1d\xe8\xe0\x00\x00\x00\x00(\xfbV\xd0\x00\x00\x00\x00*\x00m\xe0\x00\x00\x00\x00*\xce\x09\xd0\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002M\x91\xd0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004-s\xd0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x006\x0dU\xd0\x00\x00\x00\x006\xfdT\xe0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00!H\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M3.5.0/0,M10.5.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000]*\x1bj\x02\x00\x00j\x02\x00\x00\x0c\x00\x00\x00Asia/BishkekTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19~\x10\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xbe\xa3\xc0\x00\x00\x00\x00)\xe770\x00\x00\x00\x00*\xc4\xa5 \x00\x00\x00\x00+\xc7\x190\x00\x00\x00\x00,\xa4\x87 \x00\x00\x00\x00-\xa6\xfb0\x00\x00\x00\x00.\x84i \x00\x00\x00\x00/\x86\xdd0\x00\x00\x00\x000dK \x00\x00\x00\x001f\xbf0\x00\x00\x00\x002Mg\xa0\x00\x00\x00\x003=\x89\xd8\x00\x00\x00\x004RV\xc8\x00\x00\x00\x005\x1dk\xd8\x00\x00\x00\x00628\xc8\x00\x00\x00\x006\xfdM\xd8\x00\x00\x00\x008\x1bUH\x00\x00\x00\x008\xdd/\xd8\x00\x00\x00\x009\xfb7H\x00\x00\x00\x00:\xbd\x11\xd8\x00\x00\x00\x00;\xdb\x19H\x00\x00\x00\x00<\xa6.X\x00\x00\x00\x00=\xba\xfbH\x00\x00\x00\x00>\x86\x10X\x00\x00\x00\x00?\x9a\xddH\x00\x00\x00\x00@e\xf2X\x00\x00\x00\x00A\x83\xf9\xc8\x00\x00\x00\x00BE\xd4X\x00\x00\x00\x00B\xfb\x92 \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x03\x00\x00E\xf0\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0cLMT\x00+05\x00+07\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7f^]@\x01\x00\x00@\x01\x00\x00\x0b\x00\x00\x00Asia/BruneiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x05\x00\x00\x00\x18\xff\xff\xff\xff\xad\x8a\x06\x90\xff\xff\xff\xff\xbagG\x88\xff\xff\xff\xff\xbf{'\x80\xff\xff\xff\xff\xbf\xf3\x1bP\xff\xff\xff\xff\xc1]\xac\x80\xff\xff\xff\xff\xc1\xd5\xa0P\xff\xff\xff\xff\xc3>\xe0\x00\xff\xff\xff\xff\xc3\xb6\xd3\xd0\xff\xff\xff\xff\xc5 \x13\x80\xff\xff\xff\xff\xc5\x98\x07P\xff\xff\xff\xff\xc7\x01G\x00\xff\xff\xff\xff\xc7y:\xd0\xff\xff\xff\xff\xc8\xe3\xcc\x00\xff\xff\xff\xff\xc9[\xbf\xd0\xff\xff\xff\xff\xca\xc4\xff\x80\xff\xff\xff\xff\xcb<\xf3P\xff\xff\xff\xff\xcb\x91X\x00\xff\xff\xff\xff\xd2Hm\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x03\x00\x00gp\x00\x00\x00\x00ix\x00\x04\x00\x00u0\x01\x0a\x00\x00p\x80\x00\x10\x00\x00~\x90\x00\x14LMT\x00+0730\x00+0820\x00+08\x00+09\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x1a\xdc\xca\xdc\x00\x00\x00\xdc\x00\x00\x00\x0d\x00\x00\x00Asia/CalcuttaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff&\xba\x18(\xff\xff\xff\xffC\xe7\xeb0\xff\xff\xff\xff\x87\x9d\xbc\xba\xff\xff\xff\xff\xca\xdb\x8c(\xff\xff\xff\xff\xcc\x05q\x18\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xd2t\x12\x98\x01\x02\x03\x04\x03\x04\x03\x00\x00R\xd8\x00\x00\x00\x00R\xd0\x00\x04\x00\x00KF\x00\x08\x00\x00MX\x00\x0c\x00\x00[h\x01\x10LMT\x00HMT\x00MMT\x00IST\x00+0630\x00\x0aIST-5:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\xcd\xdf\x05\xee\x02\x00\x00\xee\x02\x00\x00\x0a\x00\x00\x00Asia/ChitaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xdb\xf9\xa0\xff\xff\xff\xff\xb5\xa3\xc5\x00\x00\x00\x00\x00\x15'Sp\x00\x00\x00\x00\x16\x18\x87\xe0\x00\x00\x00\x00\x17\x08\x86\xf0\x00\x00\x00\x00\x17\xf9\xbb`\x00\x00\x00\x00\x18\xe9\xbap\x00\x00\x00\x00\x19\xda\xee\xe0\x00\x00\x00\x00\x1a\xcc?p\x00\x00\x00\x00\x1b\xbcL\x90\x00\x00\x00\x00\x1c\xac=\x90\x00\x00\x00\x00\x1d\x9c.\x90\x00\x00\x00\x00\x1e\x8c\x1f\x90\x00\x00\x00\x00\x1f|\x10\x90\x00\x00\x00\x00 l\x01\x90\x00\x00\x00\x00![\xf2\x90\x00\x00\x00\x00\x22K\xe3\x90\x00\x00\x00\x00#;\xd4\x90\x00\x00\x00\x00$+\xc5\x90\x00\x00\x00\x00%\x1b\xb6\x90\x00\x00\x00\x00&\x0b\xa7\x90\x00\x00\x00\x00'\x04\xd3\x10\x00\x00\x00\x00'\xf4\xc4\x10\x00\x00\x00\x00(\xe4\xc3 \x00\x00\x00\x00)xk \x00\x00\x00\x00)\xd4\xa6\x10\x00\x00\x00\x00*\xc4\x97\x10\x00\x00\x00\x00+\xb4\x88\x10\x00\x00\x00\x00,\xa4y\x10\x00\x00\x00\x00-\x94j\x10\x00\x00\x00\x00.\x84[\x10\x00\x00\x00\x00/tL\x10\x00\x00\x00\x000d=\x10\x00\x00\x00\x001]h\x90\x00\x00\x00\x002rC\x90\x00\x00\x00\x003=J\x90\x00\x00\x00\x004R%\x90\x00\x00\x00\x005\x1d,\x90\x00\x00\x00\x0062\x07\x90\x00\x00\x00\x006\xfd\x0e\x90\x00\x00\x00\x008\x1b$\x10\x00\x00\x00\x008\xdc\xf0\x90\x00\x00\x00\x009\xfb\x06\x10\x00\x00\x00\x00:\xbc\xd2\x90\x00\x00\x00\x00;\xda\xe8\x10\x00\x00\x00\x00<\xa5\xef\x10\x00\x00\x00\x00=\xba\xca\x10\x00\x00\x00\x00>\x85\xd1\x10\x00\x00\x00\x00?\x9a\xac\x10\x00\x00\x00\x00@e\xb3\x10\x00\x00\x00\x00A\x83\xc8\x90\x00\x00\x00\x00BE\x95\x10\x00\x00\x00\x00Cc\xaa\x90\x00\x00\x00\x00D%w\x10\x00\x00\x00\x00EC\x8c\x90\x00\x00\x00\x00F\x05Y\x10\x00\x00\x00\x00G#n\x90\x00\x00\x00\x00G\xeeu\x90\x00\x00\x00\x00I\x03P\x90\x00\x00\x00\x00I\xceW\x90\x00\x00\x00\x00J\xe32\x90\x00\x00\x00\x00K\xae9\x90\x00\x00\x00\x00L\xccO\x10\x00\x00\x00\x00M\x8e\x1b\x90\x00\x00\x00\x00TK\xc9\x00\x00\x00\x00\x00V\xf6\xce \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x01\x03\x00\x00j`\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x0c\x00\x00\x8c\xa0\x00\x08LMT\x00+08\x00+10\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81z&\x80k\x02\x00\x00k\x02\x00\x00\x0f\x00\x00\x00Asia/ChoibalsanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xff\x86\xd3\xe7(\x00\x00\x00\x00\x0f\x0b\xdc\x90\x00\x00\x00\x00\x18\xe9\xc8\x80\x00\x00\x00\x00\x19\xda\xee\xe0\x00\x00\x00\x00\x1a\xcc?p\x00\x00\x00\x00\x1b\xbc\x22`\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x04`\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xe6`\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xc8`\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xaa`\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x8c`\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xa8\xe0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\x8a\xe0\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4l\xe0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4N\xe0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x840\xe0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d\x12\xe0\x00\x00\x00\x001]Lp\x00\x00\x00\x002M/`\x00\x00\x00\x003=.p\x00\x00\x00\x004-\x11`\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x006\x0c\xf3`\x00\x00\x00\x00:\xe9\xa5\x90\x00\x00\x00\x00;\xb4\x9e\x80\x00\x00\x00\x00<\xa4\x9d\x90\x00\x00\x00\x00=\x94\x80\x80\x00\x00\x00\x00>\x84\x7f\x90\x00\x00\x00\x00?tb\x80\x00\x00\x00\x00@da\x90\x00\x00\x00\x00ATD\x80\x00\x00\x00\x00BDC\x90\x00\x00\x00\x00C4&\x80\x00\x00\x00\x00D$%\x90\x00\x00\x00\x00E\x1dC\x00\x00\x00\x00\x00G\xef\xaa\xf0\x00\x00\x00\x00U\x15\x9a\xa0\x00\x00\x00\x00V\x05ap\x00\x00\x00\x00V\xf5|\xa0\x00\x00\x00\x00W\xe5Cp\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x02\x05\x02\x05\x02\x00\x00kX\x00\x00\x00\x00bp\x00\x04\x00\x00p\x80\x00\x08\x00\x00~\x90\x00\x0c\x00\x00\x8c\xa0\x01\x10\x00\x00~\x90\x01\x0cLMT\x00+07\x00+08\x00+09\x00+10\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0e\x00\x00\x00Asia/ChongqingTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0e\x00\x00\x00Asia/ChungkingTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x91\x87\xbb\xf7\x00\x00\x00\xf7\x00\x00\x00\x0c\x00\x00\x00Asia/ColomboTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x07\x00\x00\x00\x18\xff\xff\xff\xffV\xb6\x99$\xff\xff\xff\xff\x87\x9d\xbd\x1c\xff\xff\xff\xff\xcbZ\x1c(\xff\xff\xff\xff\xcc\x95+\xa0\xff\xff\xff\xff\xd2u\x808\x00\x00\x00\x001\xa6\x00(\x00\x00\x00\x002q\x00 \x00\x00\x00\x00D?\xea(\x01\x02\x03\x04\x02\x05\x06\x02\x00\x00J\xdc\x00\x00\x00\x00J\xe4\x00\x04\x00\x00MX\x00\x08\x00\x00T`\x01\x0e\x00\x00[h\x01\x12\x00\x00[h\x00\x12\x00\x00T`\x00\x0eLMT\x00MMT\x00+0530\x00+06\x00+0630\x00\x0a<+0530>-5:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?Y\xaf\x19\xe7\x00\x00\x00\xe7\x00\x00\x00\x0a\x00\x00\x00Asia/DaccaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x1c\xff\xff\xff\xffi\x86\x86\xbc\xff\xff\xff\xff\xca\xdb\x86\xb0\xff\xff\xff\xff\xcc\x05q\x18\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xdd\xa8\xd2\x98\x00\x00\x00\x00J;\xc4\x10\x00\x00\x00\x00K<\xd8\x90\x01\x02\x03\x02\x04\x05\x04\x00\x00T\xc4\x00\x00\x00\x00R\xd0\x00\x04\x00\x00[h\x00\x08\x00\x00MX\x00\x0e\x00\x00T`\x00\x14\x00\x00bp\x01\x18LMT\x00HMT\x00+0630\x00+0530\x00+06\x00+07\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\x07\xeci\xd2\x04\x00\x00\xd2\x04\x00\x00\x0d\x00\x00\x00Asia/DamascusTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa1\xf2\xabx\xff\xff\xff\xff\xa2\x81/\x80\xff\xff\xff\xff\xa3^\x9dp\xff\xff\xff\xff\xa4a\x11\x80\xff\xff\xff\xff\xa5>\x7fp\xff\xff\xff\xff\xa6@\xf3\x80\xff\xff\xff\xff\xa7\x1eap\xff\xff\xff\xff\xa8 \xd5\x80\xff\xff\xff\xff\xa9\x07}\xf0\xff\xff\xff\xff\xf1\x8fR\x00\xff\xff\xff\xff\xf2[\x9cp\xff\xff\xff\xff\xf3s(\x80\xff\xff\xff\xff\xf4;~p\xff\xff\xff\xff\xf5U\xad\x80\xff\xff\xff\xff\xf6\x1fT\xf0\xff\xff\xff\xff\xf76\xe1\x00\xff\xff\xff\xff\xf7\xff6\xf0\xff\xff\xff\xff\xf9\x0e\xda\x00\xff\xff\xff\xff\xf9\xe1\xbb\xf0\xff\xff\xff\xff\xfa\xf9H\x00\xff\xff\xff\xff\xfb\xc2\xefp\xff\xff\xff\xff\xfc\xdb\xcd\x00\xff\xff\xff\xff\xfd\xa5tp\xff\xff\xff\xff\xfe\xbd\x00\x80\xff\xff\xff\xff\xff\x86\xa7\xf0\x00\x00\x00\x00\x00\x9e4\x00\x00\x00\x00\x00\x01g\xdbp\x00\x00\x00\x00\x02\x7fg\x80\x00\x00\x00\x00\x03I\x0e\xf0\x00\x00\x00\x00\x04a\xec\x80\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06C \x00\x00\x00\x00\x00\x07\x0c\xc7p\x00\x00\x00\x00\x08$S\x80\x00\x00\x00\x00\x08\xed\xfa\xf0\x00\x00\x00\x00\x0a\x05\x87\x00\x00\x00\x00\x00\x0a\xcf.p\x00\x00\x00\x00\x0b\xe8\x0c\x00\x00\x00\x00\x00\x0c\xb1\xb3p\x00\x00\x00\x00\x0d\xc9?\x80\x00\x00\x00\x00\x0ekY\xf0\x00\x00\x00\x00\x0f\xaas\x00\x00\x00\x00\x00\x10L\x8dp\x00\x00\x00\x00\x18\xf4\xc5\x00\x00\x00\x00\x00\x19\xdbmp\x00\x00\x00\x00\x1a\xd7J\x00\x00\x00\x00\x00\x1b\xbd\xf2p\x00\x00\x00\x00\x1eU#\x00\x00\x00\x00\x00\x1f\x8a\xe5p\x00\x00\x00\x00 Gz\x00\x00\x00\x00\x00!\x89\x19\xf0\x00\x00\x00\x00\x22\xe2`\x00\x00\x00\x0041hP\x00\x00\x00\x005\x1e\xc4`\x00\x00\x00\x006\x12\x9b\xd0\x00\x00\x00\x007\x02\x9a\xe0\x00\x00\x00\x007\xf3\xcfP\x00\x00\x00\x008\xe5\x1f\xe0\x00\x00\x00\x009\xd6TP\x00\x00\x00\x00:\xc6S`\x00\x00\x00\x00;\xb7\x87\xd0\x00\x00\x00\x00<\xa7\x86\xe0\x00\x00\x00\x00=\x98\xbbP\x00\x00\x00\x00>\x88\xba`\x00\x00\x00\x00?y\xee\xd0\x00\x00\x00\x00@k?`\x00\x00\x00\x00A\x5cs\xd0\x00\x00\x00\x00BLr\xe0\x00\x00\x00\x00C=\xa7P\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0c6\xe0\x00\x00\x00\x00G*>P\x00\x00\x00\x00G\xf5S`\x00\x00\x00\x00I\x0bq\xd0\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xea\x02P\x00\x00\x00\x00K\xb5\x17`\x00\x00\x00\x00L\xc9\xe4P\x00\x00\x00\x00M\x94\xf9`\x00\x00\x00\x00N\xa9\xc6P\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P\x89\xa8P\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00Ri\x8aP\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TR\xa6\xd0\x00\x00\x00\x00U\x14\x81`\x00\x00\x00\x00V2\x88\xd0\x00\x00\x00\x00V\xf4c`\x00\x00\x00\x00X\x12j\xd0\x00\x00\x00\x00X\xdd\x7f\xe0\x00\x00\x00\x00Y\xf2L\xd0\x00\x00\x00\x00Z\xbda\xe0\x00\x00\x00\x00[\xd2.\xd0\x00\x00\x00\x00\x5c\x9dC\xe0\x00\x00\x00\x00]\xb2\x10\xd0\x00\x00\x00\x00^}%\xe0\x00\x00\x00\x00_\x9b-P\x00\x00\x00\x00`]\x07\xe0\x00\x00\x00\x00a{\x0fP\x00\x00\x00\x00b<\xe9\xe0\x00\x00\x00\x00cZ\xf1P\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x00\x00\x22\x08\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x00\x0dLMT\x00EEST\x00EET\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?Y\xaf\x19\xe7\x00\x00\x00\xe7\x00\x00\x00\x0a\x00\x00\x00Asia/DhakaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x1c\xff\xff\xff\xffi\x86\x86\xbc\xff\xff\xff\xff\xca\xdb\x86\xb0\xff\xff\xff\xff\xcc\x05q\x18\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xdd\xa8\xd2\x98\x00\x00\x00\x00J;\xc4\x10\x00\x00\x00\x00K<\xd8\x90\x01\x02\x03\x02\x04\x05\x04\x00\x00T\xc4\x00\x00\x00\x00R\xd0\x00\x04\x00\x00[h\x00\x08\x00\x00MX\x00\x0e\x00\x00T`\x00\x14\x00\x00bp\x01\x18LMT\x00HMT\x00+0630\x00+0530\x00+06\x00+07\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x92\x1a\x8c\xaa\x00\x00\x00\xaa\x00\x00\x00\x09\x00\x00\x00Asia/DiliTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x92\xe6\x18\xc4\xff\xff\xff\xff\xcb\x992\xf0\x00\x00\x00\x00\x0b\xea0p\x00\x00\x00\x009\xc3\x99\x00\x01\x02\x01\x02\x00\x00u\xbc\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x00\x08LMT\x00+08\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0a\x00\x00\x00Asia/DubaiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xa1\xf2\x99\xa8\x01\x00\x003\xd8\x00\x00\x00\x008@\x00\x04LMT\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00's\x96\x1en\x01\x00\x00n\x01\x00\x00\x0d\x00\x00\x00Asia/DushanbeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x83\x80\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xca\x8fP\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x00\x00@\x80\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0cLMT\x00+05\x00+07\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]S\xbb\x12\xac\x03\x00\x00\xac\x03\x00\x00\x0e\x00\x00\x00Asia/FamagustaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa5w\x1e,\x00\x00\x00\x00\x09\xed\xaf\xe0\x00\x00\x00\x00\x0a\xdd\x92\xd0\x00\x00\x00\x00\x0b\xfad\xe0\x00\x00\x00\x00\x0c\xbe\xc6P\x00\x00\x00\x00\x0d\xa49`\x00\x00\x00\x00\x0e\x8a\xe1\xd0\x00\x00\x00\x00\x0f\x84\x1b`\x00\x00\x00\x00\x10uO\xd0\x00\x00\x00\x00\x11c\xfd`\x00\x00\x00\x00\x12S\xe0P\x00\x00\x00\x00\x13M\x19\xe0\x00\x00\x00\x00\x143\xc2P\x00\x00\x00\x00\x15#\xc1`\x00\x00\x00\x00\x16\x13\xa4P\x00\x00\x00\x00\x17\x03\xa3`\x00\x00\x00\x00\x17\xf3\x86P\x00\x00\x00\x00\x18\xe3\x85`\x00\x00\x00\x00\x19\xd3hP\x00\x00\x00\x00\x1a\xc3g`\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002M\x91\xd0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004-s\xd0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x0062x\x10\x00\x00\x00\x006\xfd\x7f\x10\x00\x00\x00\x008\x1b\x94\x90\x00\x00\x00\x008\xdda\x10\x00\x00\x00\x009\xfbv\x90\x00\x00\x00\x00:\xbdC\x10\x00\x00\x00\x00;\xdbX\x90\x00\x00\x00\x00<\xa6_\x90\x00\x00\x00\x00=\xbb:\x90\x00\x00\x00\x00>\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7l\x90\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V,)\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00W\xd0\x7f\xd0\x00\x00\x00\x00Y\xf5(\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x02\x00\x00\x1f\xd4\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x00\x0dLMT\x00EEST\x00EET\x00+03\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xae\xc2\xd6\x86\x0b\x00\x00\x86\x0b\x00\x00\x09\x00\x00\x00Asia/GazaTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x014\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff}\xbdJ\xb0\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\x7f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xff\xef\xb0\xb3p\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb'BP\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x000\xe7\x07\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\x0a`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007\x16a`\x00\x00\x00\x008\x06DP\x00\x00\x00\x008\xff}\xe0\x00\x00\x00\x009\xef`\xd0\x00\x00\x00\x00:\xdf_\xe0\x00\x00\x00\x00;\xcfB\xd0\x00\x00\x00\x00<\xbfA\xe0\x00\x00\x00\x00=\xaf$\xd0\x00\x00\x00\x00>\x9f#\xe0\x00\x00\x00\x00?\x8f\x06\xd0\x00\x00\x00\x00@\x7f\x05\xe0\x00\x00\x00\x00A\x5c\x81\xe0\x00\x00\x00\x00B^\xe7\xe0\x00\x00\x00\x00CA\xb7\xf0\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0e\xd9\xe0\x00\x00\x00\x00F\xe8op\x00\x00\x00\x00G\xec\x18\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xa0<`\x00\x00\x00\x00K\xad.\x9c\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00M\x94\xf9\x9c\x00\x00\x00\x00N5\xc2P\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P[\x91\xe0\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00RD\xa0P\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TIlP\x00\x00\x00\x00U\x15\xd2\xe0\x00\x00\x00\x00V)\x5c`\x00\x00\x00\x00V\xf5\xc2\xf0\x00\x00\x00\x00X\x13\xca`\x00\x00\x00\x00X\xd5\xa4\xf0\x00\x00\x00\x00Y\xf3\xac`\x00\x00\x00\x00Z\xb5\x86\xf0\x00\x00\x00\x00[\xd3\x8e`\x00\x00\x00\x00\x5c\x9dC\xe0\x00\x00\x00\x00]\xb3bP\x00\x00\x00\x00^~w`\x00\x00\x00\x00_\x93R`\x00\x00\x00\x00`^Y`\x00\x00\x00\x00a{\x1d`\x00\x00\x00\x00b?\x8c\xe0\x00\x00\x00\x00c\x5c^\xf0\x00\x00\x00\x00dL^\x00\x00\x00\x00\x00e<@\xf0\x00\x00\x00\x00f#\x05\x80\x00\x00\x00\x00g\x1c\x22\xf0\x00\x00\x00\x00g\xf9\xad\x00\x00\x00\x00\x00h\xfc\x04\xf0\x00\x00\x00\x00i\xc7\x1a\x00\x00\x00\x00\x00j\xdb\xe6\xf0\x00\x00\x00\x00k\xa6\xfc\x00\x00\x00\x00\x00l\xc5\x03p\x00\x00\x00\x00m\x86\xde\x00\x00\x00\x00\x00n\xa4\xe5p\x00\x00\x00\x00of\xc0\x00\x00\x00\x00\x00p\x84\xc7p\x00\x00\x00\x00qO\xdc\x80\x00\x00\x00\x00rd\xa9p\x00\x00\x00\x00s/\xbe\x80\x00\x00\x00\x00tD\x8bp\x00\x00\x00\x00u\x0f\xa0\x80\x00\x00\x00\x00v-\xa7\xf0\x00\x00\x00\x00v\xef\x82\x80\x00\x00\x00\x00x\x0d\x89\xf0\x00\x00\x00\x00x\xcfd\x80\x00\x00\x00\x00y\xedk\xf0\x00\x00\x00\x00z\xafF\x80\x00\x00\x00\x00{\xcdM\xf0\x00\x00\x00\x00|\x98c\x00\x00\x00\x00\x00}\xa3\xf5p\x00\x00\x00\x00~xE\x00\x00\x00\x00\x00\x7fz\x9c\xf0\x00\x00\x00\x00\x80X'\x00\x00\x00\x00\x00\x81H\x09\xf0\x00\x00\x00\x00\x828\x09\x00\x00\x00\x00\x00\x83\x1e\xb1p\x00\x00\x00\x00\x84\x17\xeb\x00\x00\x00\x00\x00\x84\xec\x1ep\x00\x00\x00\x00\x85,\xc6\x00\x00\x00\x00\x00\x855\xf2p\x00\x00\x00\x00\x86\x01\x07\x80\x00\x00\x00\x00\x86\xc2\xc5\xf0\x00\x00\x00\x00\x86\xfa3\x00\x00\x00\x00\x00\x87\x15\xd4p\x00\x00\x00\x00\x87\xe0\xe9\x80\x00\x00\x00\x00\x88\x99mp\x00\x00\x00\x00\x88\xd0\xda\x80\x00\x00\x00\x00\x88\xf5\xb6p\x00\x00\x00\x00\x89\xc0\xcb\x80\x00\x00\x00\x00\x8af\xdap\x00\x00\x00\x00\x8a\xa7\x82\x00\x00\x00\x00\x00\x8a\xd5\x98p\x00\x00\x00\x00\x8b\xa0\xad\x80\x00\x00\x00\x00\x8c=\x81\xf0\x00\x00\x00\x00\x8ct\xef\x00\x00\x00\x00\x00\x8c\xbe\xb4\xf0\x00\x00\x00\x00\x8d\x80\x8f\x80\x00\x00\x00\x00\x8e\x14)p\x00\x00\x00\x00\x8eK\x96\x80\x00\x00\x00\x00\x8e\x9e\x96\xf0\x00\x00\x00\x00\x8f`q\x80\x00\x00\x00\x00\x8f\xe1\x96p\x00\x00\x00\x00\x90\x22>\x00\x00\x00\x00\x00\x90~x\xf0\x00\x00\x00\x00\x91I\x8e\x00\x00\x00\x00\x00\x91\xb8=\xf0\x00\x00\x00\x00\x91\xef\xab\x00\x00\x00\x00\x00\x92^Z\xf0\x00\x00\x00\x00\x93)p\x00\x00\x00\x00\x00\x93\x85\xaa\xf0\x00\x00\x00\x00\x93\xc6R\x80\x00\x00\x00\x00\x94><\xf0\x00\x00\x00\x00\x95\x09R\x00\x00\x00\x00\x00\x95\x5cRp\x00\x00\x00\x00\x95\x93\xbf\x80\x00\x00\x00\x00\x96'Yp\x00\x00\x00\x00\x96\xe94\x00\x00\x00\x00\x00\x972\xf9\xf0\x00\x00\x00\x00\x97jg\x00\x00\x00\x00\x00\x98\x07;p\x00\x00\x00\x00\x98\xc9\x16\x00\x00\x00\x00\x00\x99\x00f\xf0\x00\x00\x00\x00\x99A\x0e\x80\x00\x00\x00\x00\x99\xe7\x1dp\x00\x00\x00\x00\x9a\xb22\x80\x00\x00\x00\x00\x9a\xd7\x0ep\x00\x00\x00\x00\x9b\x0e{\x80\x00\x00\x00\x00\x9b\xc6\xffp\x00\x00\x00\x00\x9c\x92\x14\x80\x00\x00\x00\x00\x9c\xa4{p\x00\x00\x00\x00\x9c\xe5#\x00\x00\x00\x00\x00\x9d\xa6\xe1p\x00\x00\x00\x00\x9eq\xf6\x80\x00\x00\x00\x00\x9e{\x22\xf0\x00\x00\x00\x00\x9e\xbb\xca\x80\x00\x00\x00\x00\x9f\x86\xc3p\x00\x00\x00\x00\xa0\x897\x80\x00\x00\x00\x00\xa1o\xdf\xf0\x00\x00\x00\x00\xa2_\xdf\x00\x00\x00\x00\x00\xa3O\xc1\xf0\x00\x00\x00\x00\xa4-L\x00\x00\x00\x00\x00\xa5/\xa3\xf0\x00\x00\x00\x00\xa6\x03\xf3\x80\x00\x00\x00\x00\xa7\x0f\x85\xf0\x00\x00\x00\x00\xa7\xda\x9b\x00\x00\x00\x00\x00\xa8\xefg\xf0\x00\x00\x00\x00\xa9\xba}\x00\x00\x00\x00\x00\xaa\xd8\x84p\x00\x00\x00\x00\xab\x9a_\x00\x00\x00\x00\x00\xac\xb8fp\x00\x00\x00\x00\xadzA\x00\x00\x00\x00\x00\xae\x98Hp\x00\x00\x00\x00\xafZ#\x00\x00\x00\x00\x00\xb0x*p\x00\x00\x00\x00\xb1C?\x80\x00\x00\x00\x00\xb2X\x0cp\x00\x00\x00\x00\xb3#!\x80\x00\x00\x00\x00\xb47\xeep\x00\x00\x00\x00\xb5\x03\x03\x80\x00\x00\x00\x00\xb6!\x0a\xf0\x00\x00\x00\x00\xb6\xe2\xe5\x80\x00\x00\x00\x00\xb8\x00\xec\xf0\x00\x00\x00\x00\xb8\xc2\xc7\x80\x00\x00\x00\x00\xb9\xd7\x94p\x00\x00\x00\x00\xba\xab\xe4\x00\x00\x00\x00\x00\xbb\xae;\xf0\x00\x00\x00\x00\xbc\x8b\xc6\x00\x00\x00\x00\x00\xbd\x84\xe3p\x00\x00\x00\x00\xbek\xa8\x00\x00\x00\x00\x00\xbfRPp\x00\x00\x00\x00\xc0K\x8a\x00\x00\x00\x00\x00\xc1(\xf7\xf0\x00\x00\x00\x00\xc1`e\x00\x00\x00\x00\x00\xc1i\x91p\x00\x00\x00\x00\xc2+l\x00\x00\x00\x00\x00\xc2\xff\x9fp\x00\x00\x00\x00\xc37\x0c\x80\x00\x00\x00\x00\xc3Isp\x00\x00\x00\x00\xc4\x0bN\x00\x00\x00\x00\x00\xc4\xcd\x0cp\x00\x00\x00\x00\xc5\x0d\xb4\x00\x00\x00\x00\x00\xc5)Up\x00\x00\x00\x00\xc5\xf4j\x80\x00\x00\x00\x00\xc6\xa3\xb3\xf0\x00\x00\x00\x00\xc6\xdb!\x00\x00\x00\x00\x00\xc7\x097p\x00\x00\x00\x00\xc7\xd4L\x80\x00\x00\x00\x00\xc8q \xf0\x00\x00\x00\x00\xc8\xb1\xc8\x80\x00\x00\x00\x00\xc8\xe9\x19p\x00\x00\x00\x00\xc9\xb4.\x80\x00\x00\x00\x00\xcaG\xc8p\x00\x00\x00\x00\xca\x88p\x00\x00\x00\x00\x00\xca\xd25\xf0\x00\x00\x00\x00\xcb\x94\x10\x80\x00\x00\x00\x00\xcc\x1eo\xf0\x00\x00\x00\x00\xccU\xdd\x00\x00\x00\x00\x00\xcc\xb2\x17\xf0\x00\x00\x00\x00\xcds\xf2\x80\x00\x00\x00\x00\xcd\xeb\xdc\xf0\x00\x00\x00\x00\xce,\x84\x80\x00\x00\x00\x00\xce\x91\xf9\xf0\x00\x00\x00\x00\xcf]\x0f\x00\x00\x00\x00\x00\xcf\xc2\x84p\x00\x00\x00\x00\xcf\xf9\xf1\x80\x00\x00\x00\x00\xd0q\xdb\xf0\x00\x00\x00\x00\xd1<\xf1\x00\x00\x00\x00\x00\xd1\x99+\xf0\x00\x00\x00\x00\xd1\xd0\x99\x00\x00\x00\x00\x00\xd2Q\xbd\xf0\x00\x00\x00\x00\xd3\x1c\xd3\x00\x00\x00\x00\x00\xd3f\x98\xf0\x00\x00\x00\x00\xd3\xa7@\x80\x00\x00\x00\x00\xd41\x9f\xf0\x00\x00\x00\x00\xd4\xfc\xb5\x00\x00\x00\x00\x00\xd5=@p\x00\x00\x00\x00\xd5t\xad\x80\x00\x00\x00\x00\xd6\x1a\xbcp\x00\x00\x00\x00\xd6\xdc\x97\x00\x00\x00\x00\x00\xd7\x0a\xadp\x00\x00\x00\x00\xd7KU\x00\x00\x00\x00\x00\xd7\xfa\x9ep\x00\x00\x00\x00\xd8\xbcy\x00\x00\x00\x00\x00\xd8\xe1T\xf0\x00\x00\x00\x00\xd9!\xfc\x80\x00\x00\x00\x00\xd9\xda\x80p\x00\x00\x00\x00\xda\xa5\x95\x80\x00\x00\x00\x00\xda\xb7\xfcp\x00\x00\x00\x00\xda\xefi\x80\x00\x00\x00\x00\xdb\xbabp\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00 P\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x01\x0d\x00\x00\x1c \x00\x11LMT\x00EEST\x00EET\x00IDT\x00IST\x00\x0aEET-2EEST,M3.4.4/50,M10.4.4/50\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0b\x00\x00\x00Asia/HarbinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d2\x08\xd6\x98\x0b\x00\x00\x98\x0b\x00\x00\x0b\x00\x00\x00Asia/HebronTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x016\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff}\xbdJ\x19\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\x7f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xff\xef\xb0\xb3p\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb'BP\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x000\xe7\x07\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\x0a`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007\x16a`\x00\x00\x00\x008\x06DP\x00\x00\x00\x008\xff}\xe0\x00\x00\x00\x009\xef`\xd0\x00\x00\x00\x00:\xdf_\xe0\x00\x00\x00\x00;\xcfB\xd0\x00\x00\x00\x00<\xbfA\xe0\x00\x00\x00\x00=\xaf$\xd0\x00\x00\x00\x00>\x9f#\xe0\x00\x00\x00\x00?\x8f\x06\xd0\x00\x00\x00\x00@\x7f\x05\xe0\x00\x00\x00\x00A\x5c\x81\xe0\x00\x00\x00\x00B^\xe7\xe0\x00\x00\x00\x00CA\xb7\xf0\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0e\xd9\xe0\x00\x00\x00\x00F\xe8op\x00\x00\x00\x00G\xec\x18\xe0\x00\x00\x00\x00H\xbb\x06P\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xa0<`\x00\x00\x00\x00K\xab\xdc\xe0\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00M\x94\xf9\x9c\x00\x00\x00\x00N5\xc2P\x00\x00\x00\x00N\x5c\x0b\xe0\x00\x00\x00\x00N\x84\xdcP\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P[\x91\xe0\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00RD\xa0P\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TIlP\x00\x00\x00\x00U\x15\xd2\xe0\x00\x00\x00\x00V)\x5c`\x00\x00\x00\x00V\xf5\xc2\xf0\x00\x00\x00\x00X\x13\xca`\x00\x00\x00\x00X\xd5\xa4\xf0\x00\x00\x00\x00Y\xf3\xac`\x00\x00\x00\x00Z\xb5\x86\xf0\x00\x00\x00\x00[\xd3\x8e`\x00\x00\x00\x00\x5c\x9dC\xe0\x00\x00\x00\x00]\xb3bP\x00\x00\x00\x00^~w`\x00\x00\x00\x00_\x93R`\x00\x00\x00\x00`^Y`\x00\x00\x00\x00a{\x1d`\x00\x00\x00\x00b?\x8c\xe0\x00\x00\x00\x00c\x5c^\xf0\x00\x00\x00\x00dL^\x00\x00\x00\x00\x00e<@\xf0\x00\x00\x00\x00f#\x05\x80\x00\x00\x00\x00g\x1c\x22\xf0\x00\x00\x00\x00g\xf9\xad\x00\x00\x00\x00\x00h\xfc\x04\xf0\x00\x00\x00\x00i\xc7\x1a\x00\x00\x00\x00\x00j\xdb\xe6\xf0\x00\x00\x00\x00k\xa6\xfc\x00\x00\x00\x00\x00l\xc5\x03p\x00\x00\x00\x00m\x86\xde\x00\x00\x00\x00\x00n\xa4\xe5p\x00\x00\x00\x00of\xc0\x00\x00\x00\x00\x00p\x84\xc7p\x00\x00\x00\x00qO\xdc\x80\x00\x00\x00\x00rd\xa9p\x00\x00\x00\x00s/\xbe\x80\x00\x00\x00\x00tD\x8bp\x00\x00\x00\x00u\x0f\xa0\x80\x00\x00\x00\x00v-\xa7\xf0\x00\x00\x00\x00v\xef\x82\x80\x00\x00\x00\x00x\x0d\x89\xf0\x00\x00\x00\x00x\xcfd\x80\x00\x00\x00\x00y\xedk\xf0\x00\x00\x00\x00z\xafF\x80\x00\x00\x00\x00{\xcdM\xf0\x00\x00\x00\x00|\x98c\x00\x00\x00\x00\x00}\xa3\xf5p\x00\x00\x00\x00~xE\x00\x00\x00\x00\x00\x7fz\x9c\xf0\x00\x00\x00\x00\x80X'\x00\x00\x00\x00\x00\x81H\x09\xf0\x00\x00\x00\x00\x828\x09\x00\x00\x00\x00\x00\x83\x1e\xb1p\x00\x00\x00\x00\x84\x17\xeb\x00\x00\x00\x00\x00\x84\xec\x1ep\x00\x00\x00\x00\x85,\xc6\x00\x00\x00\x00\x00\x855\xf2p\x00\x00\x00\x00\x86\x01\x07\x80\x00\x00\x00\x00\x86\xc2\xc5\xf0\x00\x00\x00\x00\x86\xfa3\x00\x00\x00\x00\x00\x87\x15\xd4p\x00\x00\x00\x00\x87\xe0\xe9\x80\x00\x00\x00\x00\x88\x99mp\x00\x00\x00\x00\x88\xd0\xda\x80\x00\x00\x00\x00\x88\xf5\xb6p\x00\x00\x00\x00\x89\xc0\xcb\x80\x00\x00\x00\x00\x8af\xdap\x00\x00\x00\x00\x8a\xa7\x82\x00\x00\x00\x00\x00\x8a\xd5\x98p\x00\x00\x00\x00\x8b\xa0\xad\x80\x00\x00\x00\x00\x8c=\x81\xf0\x00\x00\x00\x00\x8ct\xef\x00\x00\x00\x00\x00\x8c\xbe\xb4\xf0\x00\x00\x00\x00\x8d\x80\x8f\x80\x00\x00\x00\x00\x8e\x14)p\x00\x00\x00\x00\x8eK\x96\x80\x00\x00\x00\x00\x8e\x9e\x96\xf0\x00\x00\x00\x00\x8f`q\x80\x00\x00\x00\x00\x8f\xe1\x96p\x00\x00\x00\x00\x90\x22>\x00\x00\x00\x00\x00\x90~x\xf0\x00\x00\x00\x00\x91I\x8e\x00\x00\x00\x00\x00\x91\xb8=\xf0\x00\x00\x00\x00\x91\xef\xab\x00\x00\x00\x00\x00\x92^Z\xf0\x00\x00\x00\x00\x93)p\x00\x00\x00\x00\x00\x93\x85\xaa\xf0\x00\x00\x00\x00\x93\xc6R\x80\x00\x00\x00\x00\x94><\xf0\x00\x00\x00\x00\x95\x09R\x00\x00\x00\x00\x00\x95\x5cRp\x00\x00\x00\x00\x95\x93\xbf\x80\x00\x00\x00\x00\x96'Yp\x00\x00\x00\x00\x96\xe94\x00\x00\x00\x00\x00\x972\xf9\xf0\x00\x00\x00\x00\x97jg\x00\x00\x00\x00\x00\x98\x07;p\x00\x00\x00\x00\x98\xc9\x16\x00\x00\x00\x00\x00\x99\x00f\xf0\x00\x00\x00\x00\x99A\x0e\x80\x00\x00\x00\x00\x99\xe7\x1dp\x00\x00\x00\x00\x9a\xb22\x80\x00\x00\x00\x00\x9a\xd7\x0ep\x00\x00\x00\x00\x9b\x0e{\x80\x00\x00\x00\x00\x9b\xc6\xffp\x00\x00\x00\x00\x9c\x92\x14\x80\x00\x00\x00\x00\x9c\xa4{p\x00\x00\x00\x00\x9c\xe5#\x00\x00\x00\x00\x00\x9d\xa6\xe1p\x00\x00\x00\x00\x9eq\xf6\x80\x00\x00\x00\x00\x9e{\x22\xf0\x00\x00\x00\x00\x9e\xbb\xca\x80\x00\x00\x00\x00\x9f\x86\xc3p\x00\x00\x00\x00\xa0\x897\x80\x00\x00\x00\x00\xa1o\xdf\xf0\x00\x00\x00\x00\xa2_\xdf\x00\x00\x00\x00\x00\xa3O\xc1\xf0\x00\x00\x00\x00\xa4-L\x00\x00\x00\x00\x00\xa5/\xa3\xf0\x00\x00\x00\x00\xa6\x03\xf3\x80\x00\x00\x00\x00\xa7\x0f\x85\xf0\x00\x00\x00\x00\xa7\xda\x9b\x00\x00\x00\x00\x00\xa8\xefg\xf0\x00\x00\x00\x00\xa9\xba}\x00\x00\x00\x00\x00\xaa\xd8\x84p\x00\x00\x00\x00\xab\x9a_\x00\x00\x00\x00\x00\xac\xb8fp\x00\x00\x00\x00\xadzA\x00\x00\x00\x00\x00\xae\x98Hp\x00\x00\x00\x00\xafZ#\x00\x00\x00\x00\x00\xb0x*p\x00\x00\x00\x00\xb1C?\x80\x00\x00\x00\x00\xb2X\x0cp\x00\x00\x00\x00\xb3#!\x80\x00\x00\x00\x00\xb47\xeep\x00\x00\x00\x00\xb5\x03\x03\x80\x00\x00\x00\x00\xb6!\x0a\xf0\x00\x00\x00\x00\xb6\xe2\xe5\x80\x00\x00\x00\x00\xb8\x00\xec\xf0\x00\x00\x00\x00\xb8\xc2\xc7\x80\x00\x00\x00\x00\xb9\xd7\x94p\x00\x00\x00\x00\xba\xab\xe4\x00\x00\x00\x00\x00\xbb\xae;\xf0\x00\x00\x00\x00\xbc\x8b\xc6\x00\x00\x00\x00\x00\xbd\x84\xe3p\x00\x00\x00\x00\xbek\xa8\x00\x00\x00\x00\x00\xbfRPp\x00\x00\x00\x00\xc0K\x8a\x00\x00\x00\x00\x00\xc1(\xf7\xf0\x00\x00\x00\x00\xc1`e\x00\x00\x00\x00\x00\xc1i\x91p\x00\x00\x00\x00\xc2+l\x00\x00\x00\x00\x00\xc2\xff\x9fp\x00\x00\x00\x00\xc37\x0c\x80\x00\x00\x00\x00\xc3Isp\x00\x00\x00\x00\xc4\x0bN\x00\x00\x00\x00\x00\xc4\xcd\x0cp\x00\x00\x00\x00\xc5\x0d\xb4\x00\x00\x00\x00\x00\xc5)Up\x00\x00\x00\x00\xc5\xf4j\x80\x00\x00\x00\x00\xc6\xa3\xb3\xf0\x00\x00\x00\x00\xc6\xdb!\x00\x00\x00\x00\x00\xc7\x097p\x00\x00\x00\x00\xc7\xd4L\x80\x00\x00\x00\x00\xc8q \xf0\x00\x00\x00\x00\xc8\xb1\xc8\x80\x00\x00\x00\x00\xc8\xe9\x19p\x00\x00\x00\x00\xc9\xb4.\x80\x00\x00\x00\x00\xcaG\xc8p\x00\x00\x00\x00\xca\x88p\x00\x00\x00\x00\x00\xca\xd25\xf0\x00\x00\x00\x00\xcb\x94\x10\x80\x00\x00\x00\x00\xcc\x1eo\xf0\x00\x00\x00\x00\xccU\xdd\x00\x00\x00\x00\x00\xcc\xb2\x17\xf0\x00\x00\x00\x00\xcds\xf2\x80\x00\x00\x00\x00\xcd\xeb\xdc\xf0\x00\x00\x00\x00\xce,\x84\x80\x00\x00\x00\x00\xce\x91\xf9\xf0\x00\x00\x00\x00\xcf]\x0f\x00\x00\x00\x00\x00\xcf\xc2\x84p\x00\x00\x00\x00\xcf\xf9\xf1\x80\x00\x00\x00\x00\xd0q\xdb\xf0\x00\x00\x00\x00\xd1<\xf1\x00\x00\x00\x00\x00\xd1\x99+\xf0\x00\x00\x00\x00\xd1\xd0\x99\x00\x00\x00\x00\x00\xd2Q\xbd\xf0\x00\x00\x00\x00\xd3\x1c\xd3\x00\x00\x00\x00\x00\xd3f\x98\xf0\x00\x00\x00\x00\xd3\xa7@\x80\x00\x00\x00\x00\xd41\x9f\xf0\x00\x00\x00\x00\xd4\xfc\xb5\x00\x00\x00\x00\x00\xd5=@p\x00\x00\x00\x00\xd5t\xad\x80\x00\x00\x00\x00\xd6\x1a\xbcp\x00\x00\x00\x00\xd6\xdc\x97\x00\x00\x00\x00\x00\xd7\x0a\xadp\x00\x00\x00\x00\xd7KU\x00\x00\x00\x00\x00\xd7\xfa\x9ep\x00\x00\x00\x00\xd8\xbcy\x00\x00\x00\x00\x00\xd8\xe1T\xf0\x00\x00\x00\x00\xd9!\xfc\x80\x00\x00\x00\x00\xd9\xda\x80p\x00\x00\x00\x00\xda\xa5\x95\x80\x00\x00\x00\x00\xda\xb7\xfcp\x00\x00\x00\x00\xda\xefi\x80\x00\x00\x00\x00\xdb\xbabp\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00 \xe7\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x01\x0d\x00\x00\x1c \x00\x11LMT\x00EEST\x00EET\x00IDT\x00IST\x00\x0aEET-2EEST,M3.4.4/50,M10.4.4/50\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8!YF\xec\x00\x00\x00\xec\x00\x00\x00\x10\x00\x00\x00Asia/Ho_Chi_MinhTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff\x88\x8cC\x8a\xff\xff\xff\xff\x91\xa3+\x0a\xff\xff\xff\xff\xcd5\xe6\x80\xff\xff\xff\xff\xd1Y\xcep\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd52\xbb\x10\xff\xff\xff\xff\xe4\xb6\xf2\x90\xff\xff\xff\xff\xed/\x98\x00\x00\x00\x00\x00\x0a=\xc7\x00\x01\x02\x03\x04\x02\x03\x02\x03\x02\x00\x00c\xf6\x00\x00\x00\x00c\xf6\x00\x04\x00\x00bp\x00\x09\x00\x00p\x80\x00\x0d\x00\x00~\x90\x00\x11LMT\x00PLMT\x00+07\x00+08\x00+09\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x09\xfa-\x07\x03\x00\x00\x07\x03\x00\x00\x0e\x00\x00\x00Asia/Hong_KongTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff\x85ic\x90\xff\xff\xff\xff\xcaM10\xff\xff\xff\xff\xca\xdb\x930\xff\xff\xff\xff\xcbKqx\xff\xff\xff\xff\xd2\xa0\xde\x90\xff\xff\xff\xff\xd3k\xd7\x80\xff\xff\xff\xff\xd4\x93X\xb8\xff\xff\xff\xff\xd5B\xb08\xff\xff\xff\xff\xd6s:\xb8\xff\xff\xff\xff\xd7>A\xb8\xff\xff\xff\xff\xd8.2\xb8\xff\xff\xff\xff\xd8\xf99\xb8\xff\xff\xff\xff\xda\x0e\x14\xb8\xff\xff\xff\xff\xda\xd9\x1b\xb8\xff\xff\xff\xff\xdb\xed\xf6\xb8\xff\xff\xff\xff\xdc\xb8\xfd\xb8\xff\xff\xff\xff\xdd\xcd\xd8\xb8\xff\xff\xff\xff\xde\xa2\x1a8\xff\xff\xff\xff\xdf\xb6\xf58\xff\xff\xff\xff\xe0\x81\xfc8\xff\xff\xff\xff\xe1\x96\xc9(\xff\xff\xff\xff\xe2Oi8\xff\xff\xff\xff\xe3v\xab(\xff\xff\xff\xff\xe4/K8\xff\xff\xff\xff\xe5_\xc7\xa8\xff\xff\xff\xff\xe6\x0f-8\xff\xff\xff\xff\xe7?\xa9\xa8\xff\xff\xff\xff\xe7\xf8I\xb8\xff\xff\xff\xff\xe9\x1f\x8b\xa8\xff\xff\xff\xff\xe9\xd8+\xb8\xff\xff\xff\xff\xea\xffm\xa8\xff\xff\xff\xff\xeb\xb8\x0d\xb8\xff\xff\xff\xff\xec\xdfO\xa8\xff\xff\xff\xff\xed\x97\xef\xb8\xff\xff\xff\xff\xee\xc8l(\xff\xff\xff\xff\xefw\xd1\xb8\xff\xff\xff\xff\xf0\xa8N(\xff\xff\xff\xff\xf1W\xb3\xb8\xff\xff\xff\xff\xf2\x880(\xff\xff\xff\xff\xf3@\xd08\xff\xff\xff\xff\xf4h\x12(\xff\xff\xff\xff\xf5 \xb28\xff\xff\xff\xff\xf6G\xf4(\xff\xff\xff\xff\xf7%~8\xff\xff\xff\xff\xf8\x15a(\xff\xff\xff\xff\xf9\x05`8\xff\xff\xff\xff\xf9\xf5C(\xff\xff\xff\xff\xfa\xe5B8\xff\xff\xff\xff\xfb\xde_\xa8\xff\xff\xff\xff\xfc\xce^\xb8\xff\xff\xff\xff\xfd\xbeA\xa8\xff\xff\xff\xff\xfe\xae@\xb8\xff\xff\xff\xff\xff\x9e#\xa8\x00\x00\x00\x00\x00\x8e\x22\xb8\x00\x00\x00\x00\x01~\x05\xa8\x00\x00\x00\x00\x02n\x04\xb8\x00\x00\x00\x00\x03]\xe7\xa8\x00\x00\x00\x00\x04M\xe6\xb8\x00\x00\x00\x00\x05G\x04(\x00\x00\x00\x00\x067\x038\x00\x00\x00\x00\x07&\xe6(\x00\x00\x00\x00\x07\x83=8\x00\x00\x00\x00\x09\x06\xc8(\x00\x00\x00\x00\x09\xf6\xc78\x00\x00\x00\x00\x0a\xe6\xaa(\x00\x00\x00\x00\x0b\xd6\xa98\x00\x00\x00\x00\x0c\xc6\x8c(\x00\x00\x00\x00\x11\x9b98\x00\x00\x00\x00\x12ol\xa8\x01\x02\x03\x04\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00k\x0a\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x01\x08\x00\x00w\x88\x01\x0d\x00\x00~\x90\x00\x12LMT\x00HKT\x00HKST\x00HKWT\x00JST\x00\x0aHKT-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xba\xa3b\xc1R\x02\x00\x00R\x02\x00\x00\x09\x00\x00\x00Asia/HovdTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x86\xd3\xfc\x94\x00\x00\x00\x00\x0f\x0b\xea\xa0\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbc>\x80\x00\x00\x00\x00\x1c\xac=\x90\x00\x00\x00\x00\x1d\x9c \x80\x00\x00\x00\x00\x1e\x8c\x1f\x90\x00\x00\x00\x00\x1f|\x02\x80\x00\x00\x00\x00 l\x01\x90\x00\x00\x00\x00![\xe4\x80\x00\x00\x00\x00\x22K\xe3\x90\x00\x00\x00\x00#;\xc6\x80\x00\x00\x00\x00$+\xc5\x90\x00\x00\x00\x00%\x1b\xa8\x80\x00\x00\x00\x00&\x0b\xa7\x90\x00\x00\x00\x00'\x04\xc5\x00\x00\x00\x00\x00'\xf4\xc4\x10\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)\xd4\xa6\x10\x00\x00\x00\x00*\xc4\x89\x00\x00\x00\x00\x00+\xb4\x88\x10\x00\x00\x00\x00,\xa4k\x00\x00\x00\x00\x00-\x94j\x10\x00\x00\x00\x00.\x84M\x00\x00\x00\x00\x00/tL\x10\x00\x00\x00\x000d/\x00\x00\x00\x00\x001]h\x90\x00\x00\x00\x002MK\x80\x00\x00\x00\x003=J\x90\x00\x00\x00\x004--\x80\x00\x00\x00\x005\x1d,\x90\x00\x00\x00\x006\x0d\x0f\x80\x00\x00\x00\x00:\xe9\xc1\xb0\x00\x00\x00\x00;\xb4\xba\xa0\x00\x00\x00\x00<\xa4\xb9\xb0\x00\x00\x00\x00=\x94\x9c\xa0\x00\x00\x00\x00>\x84\x9b\xb0\x00\x00\x00\x00?t~\xa0\x00\x00\x00\x00@d}\xb0\x00\x00\x00\x00AT`\xa0\x00\x00\x00\x00BD_\xb0\x00\x00\x00\x00C4B\xa0\x00\x00\x00\x00D$A\xb0\x00\x00\x00\x00E\x1d_ \x00\x00\x00\x00U\x15\xa8\xb0\x00\x00\x00\x00V\x05o\x80\x00\x00\x00\x00V\xf5\x8a\xb0\x00\x00\x00\x00W\xe5Q\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00U\xec\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9l\x03\x12\xf8\x02\x00\x00\xf8\x02\x00\x00\x0c\x00\x00\x00Asia/IrkutskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xffV\xb6\x82?\xff\xff\xff\xff\xa2\x12\x0f\xbf\xff\xff\xff\xff\xb5\xa3\xd3\x10\x00\x00\x00\x00\x15'a\x80\x00\x00\x00\x00\x16\x18\x95\xf0\x00\x00\x00\x00\x17\x08\x95\x00\x00\x00\x00\x00\x17\xf9\xc9p\x00\x00\x00\x00\x18\xe9\xc8\x80\x00\x00\x00\x00\x19\xda\xfc\xf0\x00\x00\x00\x00\x1a\xccM\x80\x00\x00\x00\x00\x1b\xbcZ\xa0\x00\x00\x00\x00\x1c\xacK\xa0\x00\x00\x00\x00\x1d\x9c<\xa0\x00\x00\x00\x00\x1e\x8c-\xa0\x00\x00\x00\x00\x1f|\x1e\xa0\x00\x00\x00\x00 l\x0f\xa0\x00\x00\x00\x00!\x5c\x00\xa0\x00\x00\x00\x00\x22K\xf1\xa0\x00\x00\x00\x00#;\xe2\xa0\x00\x00\x00\x00$+\xd3\xa0\x00\x00\x00\x00%\x1b\xc4\xa0\x00\x00\x00\x00&\x0b\xb5\xa0\x00\x00\x00\x00'\x04\xe1 \x00\x00\x00\x00'\xf4\xd2 \x00\x00\x00\x00(\xe4\xd10\x00\x00\x00\x00)xy0\x00\x00\x00\x00)\xd4\xb4 \x00\x00\x00\x00*\xc4\xa5 \x00\x00\x00\x00+\xb4\x96 \x00\x00\x00\x00,\xa4\x87 \x00\x00\x00\x00-\x94x \x00\x00\x00\x00.\x84i \x00\x00\x00\x00/tZ \x00\x00\x00\x000dK \x00\x00\x00\x001]v\xa0\x00\x00\x00\x002rQ\xa0\x00\x00\x00\x003=X\xa0\x00\x00\x00\x004R3\xa0\x00\x00\x00\x005\x1d:\xa0\x00\x00\x00\x0062\x15\xa0\x00\x00\x00\x006\xfd\x1c\xa0\x00\x00\x00\x008\x1b2 \x00\x00\x00\x008\xdc\xfe\xa0\x00\x00\x00\x009\xfb\x14 \x00\x00\x00\x00:\xbc\xe0\xa0\x00\x00\x00\x00;\xda\xf6 \x00\x00\x00\x00<\xa5\xfd \x00\x00\x00\x00=\xba\xd8 \x00\x00\x00\x00>\x85\xdf \x00\x00\x00\x00?\x9a\xba \x00\x00\x00\x00@e\xc1 \x00\x00\x00\x00A\x83\xd6\xa0\x00\x00\x00\x00BE\xa3 \x00\x00\x00\x00Cc\xb8\xa0\x00\x00\x00\x00D%\x85 \x00\x00\x00\x00EC\x9a\xa0\x00\x00\x00\x00F\x05g \x00\x00\x00\x00G#|\xa0\x00\x00\x00\x00G\xee\x83\xa0\x00\x00\x00\x00I\x03^\xa0\x00\x00\x00\x00I\xcee\xa0\x00\x00\x00\x00J\xe3@\xa0\x00\x00\x00\x00K\xaeG\xa0\x00\x00\x00\x00L\xcc] \x00\x00\x00\x00M\x8e)\xa0\x00\x00\x00\x00TK\xd7\x10\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x04\x00\x00a\xc1\x00\x00\x00\x00a\xc1\x00\x04\x00\x00bp\x00\x08\x00\x00~\x90\x01\x0c\x00\x00p\x80\x00\x10\x00\x00p\x80\x01\x10\x00\x00~\x90\x00\x0cLMT\x00IMT\x00+07\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07W\x10\xd1\xb0\x04\x00\x00\xb0\x04\x00\x00\x0d\x00\x00\x00Asia/IstanbulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x06\x00\x00\x00\x19\xff\xff\xff\xffV\xb6\xc8\xd8\xff\xff\xff\xff\x90\x8b\xf5\x98\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xbe\xd0\xff\xff\xff\xff\xa2ec\xe0\xff\xff\xff\xff\xa3{\x82P\xff\xff\xff\xff\xa4N\x80`\xff\xff\xff\xff\xa5?\xb4\xd0\xff\xff\xff\xff\xa6%'\xe0\xff\xff\xff\xff\xa7'\x7f\xd0\xff\xff\xff\xff\xaa((`\xff\xff\xff\xff\xaa\xe1\xfd\xd0\xff\xff\xff\xff\xab\xf9\x89\xe0\xff\xff\xff\xff\xac\xc31P\xff\xff\xff\xff\xc8\x81?\xe0\xff\xff\xff\xff\xc9\x01\x13P\xff\xff\xff\xff\xc9J\xf5`\xff\xff\xff\xff\xca\xce\x80P\xff\xff\xff\xff\xcb\xcb\xae`\xff\xff\xff\xff\xd2k\x09P\xff\xff\xff\xff\xd3\xa29`\xff\xff\xff\xff\xd4C\x02P\xff\xff\xff\xff\xd5L\x0d\xe0\xff\xff\xff\xff\xd6){\xd0\xff\xff\xff\xff\xd7+\xef\xe0\xff\xff\xff\xff\xd8\x09]\xd0\xff\xff\xff\xff\xd9\x02\x97`\xff\xff\xff\xff\xd9\xe9?\xd0\xff\xff\xff\xff\xda\xeb\xb3\xe0\xff\xff\xff\xff\xdb\xd2\x5cP\xff\xff\xff\xff\xdc\xd4\xd0`\xff\xff\xff\xff\xdd\xb2>P\xff\xff\xff\xff\xf1\xf4\xb9`\xff\xff\xff\xff\xf4b\xefP\xff\xff\xff\xff\xf5h\x06`\xff\xff\xff\xff\xf6\x1f8\xd0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x079\x9ap\x00\x00\x00\x00\x07\xfbu\x00\x00\x00\x00\x00\x09\x19|p\x00\x00\x00\x00\x09\xd0\xcb\x00\x00\x00\x00\x00\x0a\xf9^p\x00\x00\x00\x00\x0b\xb1\xfe\x80\x00\x00\x00\x00\x0c\xd9@p\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\xa6\xadp\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x0f\xf8\x11P\x00\x00\x00\x00\x19\x89\xb0p\x00\x00\x00\x00\x19\xdc\xb0\xe0\x00\x00\x00\x00\x1b\xe6\xd0\xf0\x00\x00\x00\x00\x1c\xc6\xef\xf0\x00\x00\x00\x00\x1d\x9b1p\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x8b\x83\xf0\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8f\xdd\x90\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S8\xbe\x10\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V>\x9e\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00W\xcf.P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x00\x00\x1b(\x00\x00\x00\x00\x1bh\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0d\x00\x00*0\x00\x11\x00\x008@\x01\x15LMT\x00IMT\x00EEST\x00EET\x00+03\x00+04\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xad\xc5\xb1\xf8\x00\x00\x00\xf8\x00\x00\x00\x0c\x00\x00\x00Asia/JakartaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x07\x00\x00\x00 \xff\xff\xff\xff?fI`\xff\xff\xff\xff\xa9x\x85\xe0\xff\xff\xff\xff\xba\x16\xde`\xff\xff\xff\xff\xcb\xbf\x83\x88\xff\xff\xff\xff\xd2V\xeep\xff\xff\xff\xff\xd7<\xc6\x08\xff\xff\xff\xff\xda\xff&\x00\xff\xff\xff\xff\xf4\xb5\xbe\x88\x01\x02\x03\x04\x03\x05\x03\x06\x00\x00d \x00\x00\x00\x00d \x00\x04\x00\x00g \x00\x08\x00\x00ix\x00\x0e\x00\x00~\x90\x00\x14\x00\x00p\x80\x00\x18\x00\x00bp\x00\x1cLMT\x00BMT\x00+0720\x00+0730\x00+09\x00+08\x00WIB\x00\x0aWIB-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.>[K\xab\x00\x00\x00\xab\x00\x00\x00\x0d\x00\x00\x00Asia/JayapuraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\xba\x16\xc1\x98\xff\xff\xff\xff\xd0X\xb9\xf0\xff\xff\xff\xff\xf4\xb5\xa2h\x01\x02\x03\x00\x00\x83\xe8\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x85\x98\x00\x08\x00\x00~\x90\x00\x0eLMT\x00+09\x00+0930\x00WIT\x00\x0aWIT-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x0e\x00\x00\x00Asia/JerusalemTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xffV\xb6\xc2\xfa\xff\xff\xff\xff\x9e0E\x88\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xd7Z0\x80\xff\xff\xff\xff\xd7\xdfX\x00\xff\xff\xff\xff\xd8/\xc3\x80\xff\xff\xff\xff\xd9\x1ec\x00\xff\xff\xff\xff\xda\x10\xf7\x00\xff\xff\xff\xff\xda\xeb\xd0\x00\xff\xff\xff\xff\xdb\xb44\x00\xff\xff\xff\xff\xdc\xb9=\x00\xff\xff\xff\xff\xdd\xe0\x8d\x00\xff\xff\xff\xff\xde\xb4\xce\x80\xff\xff\xff\xff\xdf\xa4\xbf\x80\xff\xff\xff\xff\xe0\x8bv\x00\xff\xff\xff\xff\xe1V}\x00\xff\xff\xff\xff\xe2\xbef\x80\xff\xff\xff\xff\xe36_\x00\xff\xff\xff\xff\xe4\x9eH\x80\xff\xff\xff\xff\xe5\x16A\x00\xff\xff\xff\xff\xe6t\xf0\x00\xff\xff\xff\xff\xe7\x11\xd2\x80\xff\xff\xff\xff\xe8&\xad\x80\xff\xff\xff\xff\xe8\xe8z\x00\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x001H\x96\xe0\x00\x00\x00\x002\x83\x82p\x00\x00\x00\x00?|\x9f\xe0\x00\x00\x00\x00@s6p\x00\x00\x00\x00AP\xa4`\x00\x00\x00\x00BL\x8f\x00\x00\x00\x00\x00CHOp\x00\x00\x00\x00D,q\x00\x00\x00\x00\x00E\x1e\xf6\xf0\x00\x00\x00\x00F\x0cS\x00\x00\x00\x00\x00F\xecc\xf0\x00\x00\x00\x00G\xec5\x00\x00\x00\x00\x00H\xe7\xf5p\x00\x00\x00\x00I\xcc\x17\x00\x00\x00\x00\x00J\xbe\x9c\xf0\x00\x00\x00\x00K\xab\xf9\x00\x00\x00\x00\x00L\x8c\x09\xf0\x00\x00\x00\x00M\x95\x15\x80\x00\x00\x00\x00N\x87\x9bp\x00\x00\x00\x00Ot\xf7\x80\x00\x00\x00\x00P^B\xf0\x00\x00\x00\x00QT\xd9\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00!\x06\x00\x00\x00\x00 \xf8\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0c\x00\x008@\x01\x10LMT\x00JMT\x00IDT\x00IST\x00IDDT\x00\x0aIST-2IDT,M3.4.4/26,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\xe2\x5c\xff\x9f\x00\x00\x00\x9f\x00\x00\x00\x0a\x00\x00\x00Asia/KabulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffi\x86\x9a\xa0\xff\xff\xff\xff\xd0\xf9\xd7@\x01\x02\x00\x00@\xe0\x00\x00\x00\x008@\x00\x04\x00\x00?H\x00\x08LMT\x00+04\x00+0430\x00\x0a<+0430>-4:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x9cf>\xd7\x02\x00\x00\xd7\x02\x00\x00\x0e\x00\x00\x00Asia/KamchatkaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xa7R\x96\xc4\xff\xff\xff\xff\xb5\xa3\x9a\xd0\x00\x00\x00\x00\x15')@\x00\x00\x00\x00\x16\x18]\xb0\x00\x00\x00\x00\x17\x08\x5c\xc0\x00\x00\x00\x00\x17\xf9\x910\x00\x00\x00\x00\x18\xe9\x90@\x00\x00\x00\x00\x19\xda\xc4\xb0\x00\x00\x00\x00\x1a\xcc\x15@\x00\x00\x00\x00\x1b\xbc\x22`\x00\x00\x00\x00\x1c\xac\x13`\x00\x00\x00\x00\x1d\x9c\x04`\x00\x00\x00\x00\x1e\x8b\xf5`\x00\x00\x00\x00\x1f{\xe6`\x00\x00\x00\x00 k\xd7`\x00\x00\x00\x00![\xc8`\x00\x00\x00\x00\x22K\xb9`\x00\x00\x00\x00#;\xaa`\x00\x00\x00\x00$+\x9b`\x00\x00\x00\x00%\x1b\x8c`\x00\x00\x00\x00&\x0b}`\x00\x00\x00\x00'\x04\xa8\xe0\x00\x00\x00\x00'\xf4\x99\xe0\x00\x00\x00\x00(\xe4\x98\xf0\x00\x00\x00\x00)x@\xf0\x00\x00\x00\x00)\xd4{\xe0\x00\x00\x00\x00*\xc4l\xe0\x00\x00\x00\x00+\xb4]\xe0\x00\x00\x00\x00,\xa4N\xe0\x00\x00\x00\x00-\x94?\xe0\x00\x00\x00\x00.\x840\xe0\x00\x00\x00\x00/t!\xe0\x00\x00\x00\x000d\x12\xe0\x00\x00\x00\x001]>`\x00\x00\x00\x002r\x19`\x00\x00\x00\x003= `\x00\x00\x00\x004Q\xfb`\x00\x00\x00\x005\x1d\x02`\x00\x00\x00\x0061\xdd`\x00\x00\x00\x006\xfc\xe4`\x00\x00\x00\x008\x1a\xf9\xe0\x00\x00\x00\x008\xdc\xc6`\x00\x00\x00\x009\xfa\xdb\xe0\x00\x00\x00\x00:\xbc\xa8`\x00\x00\x00\x00;\xda\xbd\xe0\x00\x00\x00\x00<\xa5\xc4\xe0\x00\x00\x00\x00=\xba\x9f\xe0\x00\x00\x00\x00>\x85\xa6\xe0\x00\x00\x00\x00?\x9a\x81\xe0\x00\x00\x00\x00@e\x88\xe0\x00\x00\x00\x00A\x83\x9e`\x00\x00\x00\x00BEj\xe0\x00\x00\x00\x00Cc\x80`\x00\x00\x00\x00D%L\xe0\x00\x00\x00\x00ECb`\x00\x00\x00\x00F\x05.\xe0\x00\x00\x00\x00G#D`\x00\x00\x00\x00G\xeeK`\x00\x00\x00\x00I\x03&`\x00\x00\x00\x00I\xce-`\x00\x00\x00\x00J\xe3\x08`\x00\x00\x00\x00K\xae\x0f`\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x00\x00\x94\xbc\x00\x00\x00\x00\x9a\xb0\x00\x04\x00\x00\xb6\xd0\x01\x08\x00\x00\xa8\xc0\x00\x0c\x00\x00\xa8\xc0\x01\x0cLMT\x00+11\x00+13\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009Y\xb7\xf1\x0a\x01\x00\x00\x0a\x01\x00\x00\x0c\x00\x00\x00Asia/KarachiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x06\x00\x00\x00\x1d\xff\xff\xff\xff\x89~\xfc\xa4\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xd2t\x12\x98\xff\xff\xff\xff\xdd\xa8\xe0\xa8\x00\x00\x00\x00\x02O\xab0\x00\x00\x00\x00<\xafE\xb0\x00\x00\x00\x00=\x9f(\xa0\x00\x00\x00\x00HA\xa00\x00\x00\x00\x00I\x0bG\xa0\x00\x00\x00\x00I\xe4\xdd0\x00\x00\x00\x00J\xec{ \x01\x02\x01\x03\x05\x04\x05\x04\x05\x04\x05\x00\x00>\xdc\x00\x00\x00\x00MX\x00\x04\x00\x00[h\x01\x0a\x00\x00FP\x00\x10\x00\x00T`\x01\x14\x00\x00FP\x00\x19LMT\x00+0530\x00+0630\x00+05\x00PKST\x00PKT\x00\x0aPKT-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x1d\xc6\x1b\x85\x00\x00\x00\x85\x00\x00\x00\x0c\x00\x00\x00Asia/KashgarTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xb0\xfe\xbad\x01\x00\x00R\x1c\x00\x00\x00\x00T`\x00\x04LMT\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8bSnT\xa1\x00\x00\x00\xa1\x00\x00\x00\x0e\x00\x00\x00Asia/KathmanduTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xf2}\x84\x00\x00\x00\x00\x1e\x180\xa8\x01\x02\x00\x00O\xfc\x00\x00\x00\x00MX\x00\x04\x00\x00P\xdc\x00\x0aLMT\x00+0530\x00+0545\x00\x0a<+0545>-5:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8bSnT\xa1\x00\x00\x00\xa1\x00\x00\x00\x0d\x00\x00\x00Asia/KatmanduTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xf2}\x84\x00\x00\x00\x00\x1e\x180\xa8\x01\x02\x00\x00O\xfc\x00\x00\x00\x00MX\x00\x04\x00\x00P\xdc\x00\x0aLMT\x00+0530\x00+0545\x00\x0a<+0545>-5:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83g\x95M\x07\x03\x00\x00\x07\x03\x00\x00\x0d\x00\x00\x00Asia/KhandygaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x08\x00\x00\x00\x14\xff\xff\xff\xff\xa1\xdb\xe4\xeb\xff\xff\xff\xff\xb5\xa3\xc5\x00\x00\x00\x00\x00\x15'Sp\x00\x00\x00\x00\x16\x18\x87\xe0\x00\x00\x00\x00\x17\x08\x86\xf0\x00\x00\x00\x00\x17\xf9\xbb`\x00\x00\x00\x00\x18\xe9\xbap\x00\x00\x00\x00\x19\xda\xee\xe0\x00\x00\x00\x00\x1a\xcc?p\x00\x00\x00\x00\x1b\xbcL\x90\x00\x00\x00\x00\x1c\xac=\x90\x00\x00\x00\x00\x1d\x9c.\x90\x00\x00\x00\x00\x1e\x8c\x1f\x90\x00\x00\x00\x00\x1f|\x10\x90\x00\x00\x00\x00 l\x01\x90\x00\x00\x00\x00![\xf2\x90\x00\x00\x00\x00\x22K\xe3\x90\x00\x00\x00\x00#;\xd4\x90\x00\x00\x00\x00$+\xc5\x90\x00\x00\x00\x00%\x1b\xb6\x90\x00\x00\x00\x00&\x0b\xa7\x90\x00\x00\x00\x00'\x04\xd3\x10\x00\x00\x00\x00'\xf4\xc4\x10\x00\x00\x00\x00(\xe4\xc3 \x00\x00\x00\x00)xk \x00\x00\x00\x00)\xd4\xa6\x10\x00\x00\x00\x00*\xc4\x97\x10\x00\x00\x00\x00+\xb4\x88\x10\x00\x00\x00\x00,\xa4y\x10\x00\x00\x00\x00-\x94j\x10\x00\x00\x00\x00.\x84[\x10\x00\x00\x00\x00/tL\x10\x00\x00\x00\x000d=\x10\x00\x00\x00\x001]h\x90\x00\x00\x00\x002rC\x90\x00\x00\x00\x003=J\x90\x00\x00\x00\x004R%\x90\x00\x00\x00\x005\x1d,\x90\x00\x00\x00\x0062\x07\x90\x00\x00\x00\x006\xfd\x0e\x90\x00\x00\x00\x008\x1b$\x10\x00\x00\x00\x008\xdc\xf0\x90\x00\x00\x00\x009\xfb\x06\x10\x00\x00\x00\x00:\xbc\xd2\x90\x00\x00\x00\x00;\xda\xe8\x10\x00\x00\x00\x00<\xa5\xef\x10\x00\x00\x00\x00=\xba\xca\x10\x00\x00\x00\x00>\x85\xd1\x10\x00\x00\x00\x00?\x9a\xac\x10\x00\x00\x00\x00?\xf2\xe4p\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D%i\x00\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xeeg\x80\x00\x00\x00\x00I\x03B\x80\x00\x00\x00\x00I\xceI\x80\x00\x00\x00\x00J\xe3$\x80\x00\x00\x00\x00K\xae+\x80\x00\x00\x00\x00L\xccA\x00\x00\x00\x00\x00M\x8e\x0d\x80\x00\x00\x00\x00Nn\x02P\x00\x00\x00\x00TK\xc9\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x06\x03\x00\x00\x7f\x15\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x0c\x00\x00\x9a\xb0\x01\x10\x00\x00\x8c\xa0\x00\x08\x00\x00\x9a\xb0\x00\x10LMT\x00+08\x00+10\x00+09\x00+11\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x1a\xdc\xca\xdc\x00\x00\x00\xdc\x00\x00\x00\x0c\x00\x00\x00Asia/KolkataTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff&\xba\x18(\xff\xff\xff\xffC\xe7\xeb0\xff\xff\xff\xff\x87\x9d\xbc\xba\xff\xff\xff\xff\xca\xdb\x8c(\xff\xff\xff\xff\xcc\x05q\x18\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xd2t\x12\x98\x01\x02\x03\x04\x03\x04\x03\x00\x00R\xd8\x00\x00\x00\x00R\xd0\x00\x04\x00\x00KF\x00\x08\x00\x00MX\x00\x0c\x00\x00[h\x01\x10LMT\x00HMT\x00MMT\x00IST\x00+0630\x00\x0aIST-5:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L\xe0\x91y\xe5\x02\x00\x00\xe5\x02\x00\x00\x10\x00\x00\x00Asia/KrasnoyarskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xf9\x0d\xf2\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00,\xa4\x950\x00\x00\x00\x00-\x94\x860\x00\x00\x00\x00.\x84w0\x00\x00\x00\x00/th0\x00\x00\x00\x000dY0\x00\x00\x00\x001]\x84\xb0\x00\x00\x00\x002r_\xb0\x00\x00\x00\x003=f\xb0\x00\x00\x00\x004RA\xb0\x00\x00\x00\x005\x1dH\xb0\x00\x00\x00\x0062#\xb0\x00\x00\x00\x006\xfd*\xb0\x00\x00\x00\x008\x1b@0\x00\x00\x00\x008\xdd\x0c\xb0\x00\x00\x00\x009\xfb\x220\x00\x00\x00\x00:\xbc\xee\xb0\x00\x00\x00\x00;\xdb\x040\x00\x00\x00\x00<\xa6\x0b0\x00\x00\x00\x00=\xba\xe60\x00\x00\x00\x00>\x85\xed0\x00\x00\x00\x00?\x9a\xc80\x00\x00\x00\x00@e\xcf0\x00\x00\x00\x00A\x83\xe4\xb0\x00\x00\x00\x00BE\xb10\x00\x00\x00\x00Cc\xc6\xb0\x00\x00\x00\x00D%\x930\x00\x00\x00\x00EC\xa8\xb0\x00\x00\x00\x00F\x05u0\x00\x00\x00\x00G#\x8a\xb0\x00\x00\x00\x00G\xee\x91\xb0\x00\x00\x00\x00I\x03l\xb0\x00\x00\x00\x00I\xces\xb0\x00\x00\x00\x00J\xe3N\xb0\x00\x00\x00\x00K\xaeU\xb0\x00\x00\x00\x00L\xcck0\x00\x00\x00\x00M\x8e7\xb0\x00\x00\x00\x00TK\xe5 \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00W\x0e\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0c\x00\x00p\x80\x00\x08LMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x11\x00\x00\x00Asia/Kuala_LumpurTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00 \xff\xff\xff\xff~6S\xa3\xff\xff\xff\xff\x86\x83\x85\xa3\xff\xff\xff\xff\xbagN\x90\xff\xff\xff\xff\xc0\x0a\xe4`\xff\xff\xff\xff\xca\xb3\xe5`\xff\xff\xff\xff\xcb\x91_\x08\xff\xff\xff\xff\xd2Hm\xf0\x00\x00\x00\x00\x16\x91\xee\x00\x01\x02\x03\x04\x05\x06\x05\x07\x00\x00a]\x00\x00\x00\x00a]\x00\x04\x00\x00bp\x00\x08\x00\x00g \x01\x0c\x00\x00g \x00\x0c\x00\x00ix\x00\x12\x00\x00~\x90\x00\x18\x00\x00p\x80\x00\x1cLMT\x00SMT\x00+07\x00+0720\x00+0730\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7f^]@\x01\x00\x00@\x01\x00\x00\x0c\x00\x00\x00Asia/KuchingTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x05\x00\x00\x00\x18\xff\xff\xff\xff\xad\x8a\x06\x90\xff\xff\xff\xff\xbagG\x88\xff\xff\xff\xff\xbf{'\x80\xff\xff\xff\xff\xbf\xf3\x1bP\xff\xff\xff\xff\xc1]\xac\x80\xff\xff\xff\xff\xc1\xd5\xa0P\xff\xff\xff\xff\xc3>\xe0\x00\xff\xff\xff\xff\xc3\xb6\xd3\xd0\xff\xff\xff\xff\xc5 \x13\x80\xff\xff\xff\xff\xc5\x98\x07P\xff\xff\xff\xff\xc7\x01G\x00\xff\xff\xff\xff\xc7y:\xd0\xff\xff\xff\xff\xc8\xe3\xcc\x00\xff\xff\xff\xff\xc9[\xbf\xd0\xff\xff\xff\xff\xca\xc4\xff\x80\xff\xff\xff\xff\xcb<\xf3P\xff\xff\xff\xff\xcb\x91X\x00\xff\xff\xff\xff\xd2Hm\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x03\x00\x00gp\x00\x00\x00\x00ix\x00\x04\x00\x00u0\x01\x0a\x00\x00p\x80\x00\x10\x00\x00~\x90\x00\x14LMT\x00+0730\x00+0820\x00+08\x00+09\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Asia/KuwaitTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xd5\x1b6\xb4\x01\x00\x00+\xcc\x00\x00\x00\x00*0\x00\x04LMT\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d?v\x0c\x17\x03\x00\x00\x17\x03\x00\x00\x0a\x00\x00\x00Asia/MacaoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x85i[\x8e\xff\xff\xff\xff\xcbGu\xf0\xff\xff\xff\xff\xcb\xf2\xca\xe0\xff\xff\xff\xff\xcc\xfb\xbaP\xff\xff\xff\xff\xcd\xd3\xfe`\xff\xff\xff\xff\xce\x9d\xa5\xd0\xff\xff\xff\xff\xd2azp\xff\xff\xff\xff\xd3x\xf8p\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5K\xabp\xff\xff\xff\xff\xd6tL\xf0\xff\xff\xff\xff\xd7?S\xf0\xff\xff\xff\xff\xd8/D\xf0\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xda\x0d\xd5p\xff\xff\xff\xff\xda\xd8\xdcp\xff\xff\xff\xff\xdb\xed\xb7p\xff\xff\xff\xff\xdc\xb8\xbep\xff\xff\xff\xff\xdd\xce\xea\xf0\xff\xff\xff\xff\xde\xa1\xda\xf0\xff\xff\xff\xff\xdf\xb6\xb5\xf0\xff\xff\xff\xff\xe0\x81\xbc\xf0\xff\xff\xff\xff\xe1\x96\x97\xf0\xff\xff\xff\xff\xe2O)\xf0\xff\xff\xff\xff\xe3vy\xf0\xff\xff\xff\xff\xe4/\x0b\xf0\xff\xff\xff\xff\xe5_\x96p\xff\xff\xff\xff\xe6\x0e\xed\xf0\xff\xff\xff\xff\xe7?\xa9\xa8\xff\xff\xff\xff\xe7\xf8I\xb8\xff\xff\xff\xff\xe9\x1f\x8b\xa8\xff\xff\xff\xff\xe9\xd8+\xb8\xff\xff\xff\xff\xea\xffm\xa8\xff\xff\xff\xff\xeb\xb8\x0d\xb8\xff\xff\xff\xff\xec\xdfO\xa8\xff\xff\xff\xff\xed\x97\xef\xb8\xff\xff\xff\xff\xee\xc8l(\xff\xff\xff\xff\xefw\xd1\xb8\xff\xff\xff\xff\xf0\xa8N(\xff\xff\xff\xff\xf1W\xb3\xb8\xff\xff\xff\xff\xf2\x880(\xff\xff\xff\xff\xf3@\xd08\xff\xff\xff\xff\xf4h\x12(\xff\xff\xff\xff\xf5 \xb28\xff\xff\xff\xff\xf6G\xf4(\xff\xff\xff\xff\xf7%~8\xff\xff\xff\xff\xf8\x15S\x18\xff\xff\xff\xff\xf9\x05`8\xff\xff\xff\xff\xf9\xf55\x18\xff\xff\xff\xff\xfa\xe5B8\xff\xff\xff\xff\xfb\xde_\xa8\xff\xff\xff\xff\xfc\xce^\xb8\xff\xff\xff\xff\xfd\xbeA\xa8\xff\xff\xff\xff\xfe\xae@\xb8\xff\xff\xff\xff\xff\x9e#\xa8\x00\x00\x00\x00\x00\x8e\x22\xb8\x00\x00\x00\x00\x01~\x05\xa8\x00\x00\x00\x00\x02n\x04\xb8\x00\x00\x00\x00\x03]\xe7\xa8\x00\x00\x00\x00\x04M\xe6\xb8\x00\x00\x00\x00\x05G\x04(\x00\x00\x00\x00\x067\x038\x00\x00\x00\x00\x07&\xe6(\x00\x00\x00\x00\x07\x83=8\x00\x00\x00\x00\x09\x06\xc8(\x00\x00\x00\x00\x09\xf6\xc78\x00\x00\x00\x00\x0a\xe6\xaa(\x00\x00\x00\x00\x0b\xd6\xa98\x00\x00\x00\x00\x0c\xc6\x8c(\x00\x00\x00\x00\x11\x9b98\x00\x00\x00\x00\x12ol\xa8\x01\x03\x02\x03\x02\x03\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x00\x00jr\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x10LMT\x00CST\x00+10\x00+09\x00CDT\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d?v\x0c\x17\x03\x00\x00\x17\x03\x00\x00\x0a\x00\x00\x00Asia/MacauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x85i[\x8e\xff\xff\xff\xff\xcbGu\xf0\xff\xff\xff\xff\xcb\xf2\xca\xe0\xff\xff\xff\xff\xcc\xfb\xbaP\xff\xff\xff\xff\xcd\xd3\xfe`\xff\xff\xff\xff\xce\x9d\xa5\xd0\xff\xff\xff\xff\xd2azp\xff\xff\xff\xff\xd3x\xf8p\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5K\xabp\xff\xff\xff\xff\xd6tL\xf0\xff\xff\xff\xff\xd7?S\xf0\xff\xff\xff\xff\xd8/D\xf0\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xda\x0d\xd5p\xff\xff\xff\xff\xda\xd8\xdcp\xff\xff\xff\xff\xdb\xed\xb7p\xff\xff\xff\xff\xdc\xb8\xbep\xff\xff\xff\xff\xdd\xce\xea\xf0\xff\xff\xff\xff\xde\xa1\xda\xf0\xff\xff\xff\xff\xdf\xb6\xb5\xf0\xff\xff\xff\xff\xe0\x81\xbc\xf0\xff\xff\xff\xff\xe1\x96\x97\xf0\xff\xff\xff\xff\xe2O)\xf0\xff\xff\xff\xff\xe3vy\xf0\xff\xff\xff\xff\xe4/\x0b\xf0\xff\xff\xff\xff\xe5_\x96p\xff\xff\xff\xff\xe6\x0e\xed\xf0\xff\xff\xff\xff\xe7?\xa9\xa8\xff\xff\xff\xff\xe7\xf8I\xb8\xff\xff\xff\xff\xe9\x1f\x8b\xa8\xff\xff\xff\xff\xe9\xd8+\xb8\xff\xff\xff\xff\xea\xffm\xa8\xff\xff\xff\xff\xeb\xb8\x0d\xb8\xff\xff\xff\xff\xec\xdfO\xa8\xff\xff\xff\xff\xed\x97\xef\xb8\xff\xff\xff\xff\xee\xc8l(\xff\xff\xff\xff\xefw\xd1\xb8\xff\xff\xff\xff\xf0\xa8N(\xff\xff\xff\xff\xf1W\xb3\xb8\xff\xff\xff\xff\xf2\x880(\xff\xff\xff\xff\xf3@\xd08\xff\xff\xff\xff\xf4h\x12(\xff\xff\xff\xff\xf5 \xb28\xff\xff\xff\xff\xf6G\xf4(\xff\xff\xff\xff\xf7%~8\xff\xff\xff\xff\xf8\x15S\x18\xff\xff\xff\xff\xf9\x05`8\xff\xff\xff\xff\xf9\xf55\x18\xff\xff\xff\xff\xfa\xe5B8\xff\xff\xff\xff\xfb\xde_\xa8\xff\xff\xff\xff\xfc\xce^\xb8\xff\xff\xff\xff\xfd\xbeA\xa8\xff\xff\xff\xff\xfe\xae@\xb8\xff\xff\xff\xff\xff\x9e#\xa8\x00\x00\x00\x00\x00\x8e\x22\xb8\x00\x00\x00\x00\x01~\x05\xa8\x00\x00\x00\x00\x02n\x04\xb8\x00\x00\x00\x00\x03]\xe7\xa8\x00\x00\x00\x00\x04M\xe6\xb8\x00\x00\x00\x00\x05G\x04(\x00\x00\x00\x00\x067\x038\x00\x00\x00\x00\x07&\xe6(\x00\x00\x00\x00\x07\x83=8\x00\x00\x00\x00\x09\x06\xc8(\x00\x00\x00\x00\x09\xf6\xc78\x00\x00\x00\x00\x0a\xe6\xaa(\x00\x00\x00\x00\x0b\xd6\xa98\x00\x00\x00\x00\x0c\xc6\x8c(\x00\x00\x00\x00\x11\x9b98\x00\x00\x00\x00\x12ol\xa8\x01\x03\x02\x03\x02\x03\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x00\x00jr\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x10LMT\x00CST\x00+10\x00+09\x00CDT\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4_P\x18\xef\x02\x00\x00\xef\x02\x00\x00\x0c\x00\x00\x00Asia/MagadanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x196\xa0\xff\xff\xff\xff\xb5\xa3\xa8\xe0\x00\x00\x00\x00\x15'7P\x00\x00\x00\x00\x16\x18k\xc0\x00\x00\x00\x00\x17\x08j\xd0\x00\x00\x00\x00\x17\xf9\x9f@\x00\x00\x00\x00\x18\xe9\x9eP\x00\x00\x00\x00\x19\xda\xd2\xc0\x00\x00\x00\x00\x1a\xcc#P\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)xO\x00\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Lp\x00\x00\x00\x002r'p\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x09p\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xebp\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x07\xf0\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xfa\xe9\xf0\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xcb\xf0\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xad\xf0\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x8f\xf0\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xacp\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x8ep\x00\x00\x00\x00D%Z\xf0\x00\x00\x00\x00ECpp\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Rp\x00\x00\x00\x00G\xeeYp\x00\x00\x00\x00I\x034p\x00\x00\x00\x00I\xce;p\x00\x00\x00\x00J\xe3\x16p\x00\x00\x00\x00K\xae\x1dp\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x00\x00\x00\x00TK\xac\xe0\x00\x00\x00\x00W\x1b\x9c\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x01\x03\x00\x00\x8d`\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\xa8\xc0\x01\x08\x00\x00\x9a\xb0\x00\x0c\x00\x00\x9a\xb0\x01\x0c\x00\x00\xa8\xc0\x00\x08LMT\x00+10\x00+12\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xc9\xd4\x5c\xbe\x00\x00\x00\xbe\x00\x00\x00\x0d\x00\x00\x00Asia/MakassarTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff\xa1\xf2]\x90\xff\xff\xff\xff\xba\x16\xd5\x90\xff\xff\xff\xff\xcb\x88\x1d\x80\xff\xff\xff\xff\xd2V\xeep\x01\x02\x03\x04\x00\x00o\xf0\x00\x00\x00\x00o\xf0\x00\x04\x00\x00p\x80\x00\x08\x00\x00~\x90\x00\x0c\x00\x00p\x80\x00\x10LMT\x00MMT\x00+08\x00+09\x00WITA\x00\x0aWITA-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\xaf\xdf\x1c\xee\x00\x00\x00\xee\x00\x00\x00\x0b\x00\x00\x00Asia/ManilaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\x14\xe1\xdc\x10\xff\xff\xff\xff{\x1f?\x90\xff\xff\xff\xff\xc1\x9c\xf4\x80\xff\xff\xff\xff\xc2\x160p\xff\xff\xff\xff\xcb\xf2\xe7\x00\xff\xff\xff\xff\xd0\xa9%p\xff\xff\xff\xff\xe2l9\x00\xff\xff\xff\xff\xe2\xd5\xa2\xf0\x00\x00\x00\x00\x0fuF\x80\x00\x00\x00\x00\x10fz\xf0\x01\x03\x02\x03\x04\x03\x02\x03\x02\x03\xff\xff\x1f\xf0\x00\x00\x00\x00qp\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08\x00\x00~\x90\x00\x0cLMT\x00PDT\x00PST\x00JST\x00\x0aPST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Asia/MuscatTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xa1\xf2\x99\xa8\x01\x00\x003\xd8\x00\x00\x00\x008@\x00\x04LMT\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1eX\xc3aU\x02\x00\x00U\x02\x00\x00\x0c\x00\x00\x00Asia/NicosiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff\xa5w\x1e\xb8\x00\x00\x00\x00\x09\xed\xaf\xe0\x00\x00\x00\x00\x0a\xdd\x92\xd0\x00\x00\x00\x00\x0b\xfad\xe0\x00\x00\x00\x00\x0c\xbe\xc6P\x00\x00\x00\x00\x0d\xa49`\x00\x00\x00\x00\x0e\x8a\xe1\xd0\x00\x00\x00\x00\x0f\x84\x1b`\x00\x00\x00\x00\x10uO\xd0\x00\x00\x00\x00\x11c\xfd`\x00\x00\x00\x00\x12S\xe0P\x00\x00\x00\x00\x13M\x19\xe0\x00\x00\x00\x00\x143\xc2P\x00\x00\x00\x00\x15#\xc1`\x00\x00\x00\x00\x16\x13\xa4P\x00\x00\x00\x00\x17\x03\xa3`\x00\x00\x00\x00\x17\xf3\x86P\x00\x00\x00\x00\x18\xe3\x85`\x00\x00\x00\x00\x19\xd3hP\x00\x00\x00\x00\x1a\xc3g`\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002M\x91\xd0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004-s\xd0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x005\xeb\x0e\xd0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x01\x00\x00\x1fH\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\x9a\x90\xf7\xd6\x02\x00\x00\xd6\x02\x00\x00\x11\x00\x00\x00Asia/NovokuznetskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x18 \xc0\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00,\xa4\x950\x00\x00\x00\x00-\x94\x860\x00\x00\x00\x00.\x84w0\x00\x00\x00\x00/th0\x00\x00\x00\x000dY0\x00\x00\x00\x001]\x84\xb0\x00\x00\x00\x002r_\xb0\x00\x00\x00\x003=f\xb0\x00\x00\x00\x004RA\xb0\x00\x00\x00\x005\x1dH\xb0\x00\x00\x00\x0062#\xb0\x00\x00\x00\x006\xfd*\xb0\x00\x00\x00\x008\x1b@0\x00\x00\x00\x008\xdd\x0c\xb0\x00\x00\x00\x009\xfb\x220\x00\x00\x00\x00:\xbc\xee\xb0\x00\x00\x00\x00;\xdb\x040\x00\x00\x00\x00<\xa6\x0b0\x00\x00\x00\x00=\xba\xe60\x00\x00\x00\x00>\x85\xed0\x00\x00\x00\x00?\x9a\xc80\x00\x00\x00\x00@e\xcf0\x00\x00\x00\x00A\x83\xe4\xb0\x00\x00\x00\x00BE\xb10\x00\x00\x00\x00Cc\xc6\xb0\x00\x00\x00\x00D%\x930\x00\x00\x00\x00EC\xa8\xb0\x00\x00\x00\x00F\x05u0\x00\x00\x00\x00G#\x8a\xb0\x00\x00\x00\x00G\xee\x91\xb0\x00\x00\x00\x00I\x03l\xb0\x00\x00\x00\x00I\xces\xb0\x00\x00\x00\x00J\xe3N\xb0\x00\x00\x00\x00K\xaeU\xb0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x00\x00Q\xc0\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)p\x1cX\xf1\x02\x00\x00\xf1\x02\x00\x00\x10\x00\x00\x00Asia/NovosibirskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xdb\x19$\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00+\xfeN\x00\x00\x00\x00\x00,\xa4\xa3@\x00\x00\x00\x00-\x94\x94@\x00\x00\x00\x00.\x84\x85@\x00\x00\x00\x00/tv@\x00\x00\x00\x000dg@\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x002rm\xc0\x00\x00\x00\x003=t\xc0\x00\x00\x00\x004RO\xc0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x00621\xc0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1bN@\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb0@\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x12@\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00BE\xbf@\x00\x00\x00\x00Cc\xd4\xc0\x00\x00\x00\x00D%\xa1@\x00\x00\x00\x00EC\xb6\xc0\x00\x00\x00\x00F\x05\x83@\x00\x00\x00\x00G#\x98\xc0\x00\x00\x00\x00G\xee\x9f\xc0\x00\x00\x00\x00I\x03z\xc0\x00\x00\x00\x00I\xce\x81\xc0\x00\x00\x00\x00J\xe3\x5c\xc0\x00\x00\x00\x00K\xaec\xc0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x00\x00\x00\x00TK\xf30\x00\x00\x00\x00W\x93\xcc\xc0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00M\xbc\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\x11\xea\xa2\xe5\x02\x00\x00\xe5\x02\x00\x00\x09\x00\x00\x00Asia/OmskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xb3@\xb6\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)x\x95P\x00\x00\x00\x00)\xd4\xd0@\x00\x00\x00\x00*\xc4\xc1@\x00\x00\x00\x00+\xb4\xb2@\x00\x00\x00\x00,\xa4\xa3@\x00\x00\x00\x00-\x94\x94@\x00\x00\x00\x00.\x84\x85@\x00\x00\x00\x00/tv@\x00\x00\x00\x000dg@\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x002rm\xc0\x00\x00\x00\x003=t\xc0\x00\x00\x00\x004RO\xc0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x00621\xc0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1bN@\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb0@\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x12@\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00BE\xbf@\x00\x00\x00\x00Cc\xd4\xc0\x00\x00\x00\x00D%\xa1@\x00\x00\x00\x00EC\xb6\xc0\x00\x00\x00\x00F\x05\x83@\x00\x00\x00\x00G#\x98\xc0\x00\x00\x00\x00G\xee\x9f\xc0\x00\x00\x00\x00I\x03z\xc0\x00\x00\x00\x00I\xce\x81\xc0\x00\x00\x00\x00J\xe3\x5c\xc0\x00\x00\x00\x00K\xaec\xc0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x00\x00\x00\x00TK\xf30\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00D\xca\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0c\x00\x00bp\x00\x08LMT\x00+05\x00+07\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\xe9\xd1\xd8q\x02\x00\x00q\x02\x00\x00\x09\x00\x00\x00Asia/OralTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\xaa\x19\x93\xdc\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xdd`\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xbf`\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\xa1`\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000d\x83`\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r\x89\xe0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004Rk\xe0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x0062M\xe0\x00\x00\x00\x006\xfdT\xe0\x00\x00\x00\x008\x1bj`\x00\x00\x00\x008\xdd6\xe0\x00\x00\x00\x009\xfbL`\x00\x00\x00\x00:\xbd\x18\xe0\x00\x00\x00\x00;\xdb.`\x00\x00\x00\x00<\xa65`\x00\x00\x00\x00=\xbb\x10`\x00\x00\x00\x00>\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x06\x05\x06\x05\x06\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x02\x00\x000$\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0c\x00\x00FP\x01\x08\x00\x008@\x00\x10LMT\x00+03\x00+05\x00+06\x00+04\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0f\x00\x00\x00Asia/Phnom_PenhTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x85\xc4\xff\xff\xff\xff\xa2jg\xc4\x01\x02\x00\x00^<\x00\x00\x00\x00^<\x00\x04\x00\x00bp\x00\x08LMT\x00BMT\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\xa5\x81e\xf7\x00\x00\x00\xf7\x00\x00\x00\x0e\x00\x00\x00Asia/PontianakTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x07\x00\x00\x00\x1f\xff\xff\xff\xff\x8b\xff\x8e\x00\xff\xff\xff\xff\xba\x16\xdf\x00\xff\xff\xff\xff\xcby\xa4\x08\xff\xff\xff\xff\xd2V\xeep\xff\xff\xff\xff\xd7<\xc6\x08\xff\xff\xff\xff\xda\xff&\x00\xff\xff\xff\xff\xf4\xb5\xbe\x88\x00\x00\x00\x00!\xdat\x80\x01\x02\x03\x02\x04\x02\x05\x06\x00\x00f\x80\x00\x00\x00\x00f\x80\x00\x04\x00\x00ix\x00\x08\x00\x00~\x90\x00\x0e\x00\x00p\x80\x00\x12\x00\x00p\x80\x00\x16\x00\x00bp\x00\x1bLMT\x00PMT\x00+0730\x00+09\x00+08\x00WITA\x00WIB\x00\x0aWIB-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\xc1\x1eB\xb7\x00\x00\x00\xb7\x00\x00\x00\x0e\x00\x00\x00Asia/PyongyangTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x8b\xd7\xf1\x9c\xff\xff\xff\xff\x92\xe6\x16\xf8\xff\xff\xff\xff\xd2/ap\x00\x00\x00\x00U\xce\x02p\x00\x00\x00\x00Z\xecup\x01\x02\x03\x01\x03\x00\x00u\xe4\x00\x00\x00\x00w\x88\x00\x04\x00\x00~\x90\x00\x08\x00\x00~\x90\x00\x04LMT\x00KST\x00JST\x00\x0aKST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdav\x19z\x98\x00\x00\x00\x98\x00\x00\x00\x0a\x00\x00\x00Asia/QatarTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa1\xf2\x9d0\x00\x00\x00\x00\x04\x8a\x92\xc0\x01\x02\x00\x000P\x00\x00\x00\x008@\x00\x04\x00\x00*0\x00\x08LMT\x00+04\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb5\xc4\x8f\x9cp\x02\x00\x00p\x02\x00\x00\x0d\x00\x00\x00Asia/QostanayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x88\x5c\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1b\x5cP\x00\x00\x00\x008\xdd(\xd0\x00\x00\x00\x009\xfb>P\x00\x00\x00\x00:\xbd\x0a\xd0\x00\x00\x00\x00;\xdb P\x00\x00\x00\x00<\xa6'P\x00\x00\x00\x00=\xbb\x02P\x00\x00\x00\x00>\x86\x09P\x00\x00\x00\x00?\x9a\xe4P\x00\x00\x00\x00@e\xebP\x00\x00\x00\x00A\x84\x00\xd0\x00\x00\x00\x00e\xe0\xc6 \x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x00\x00;\xa4\x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0c\x00\x00FP\x01\x08LMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\xce\x9cGp\x02\x00\x00p\x02\x00\x00\x0e\x00\x00\x00Asia/QyzylordaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x86\xa0\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\x95P\x00\x00\x00\x00)\xd4\xd0@\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1b\x5cP\x00\x00\x00\x008\xdd(\xd0\x00\x00\x00\x009\xfb>P\x00\x00\x00\x00:\xbd\x0a\xd0\x00\x00\x00\x00;\xdb P\x00\x00\x00\x00<\xa6'P\x00\x00\x00\x00=\xbb\x02P\x00\x00\x00\x00>\x86\x09P\x00\x00\x00\x00?\x9a\xe4P\x00\x00\x00\x00@e\xebP\x00\x00\x00\x00A\x84\x00\xd0\x00\x00\x00\x00\x5c\x1b\xd8\xa0\x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x02\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x00\x00=`\x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0c\x00\x00FP\x01\x08LMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0c\x00\x00\x00Asia/RangoonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffV\xb6\x89\xd1\xff\xff\xff\xff\xa1\xf2sQ\xff\xff\xff\xff\xcb\xf2\xfc\x18\xff\xff\xff\xff\xd1\x9ag\xf0\x01\x02\x03\x02\x00\x00Z/\x00\x00\x00\x00Z/\x00\x04\x00\x00[h\x00\x08\x00\x00~\x90\x00\x0eLMT\x00RMT\x00+0630\x00+09\x00\x0a<+0630>-6:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Asia/RiyadhTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xd5\x1b6\xb4\x01\x00\x00+\xcc\x00\x00\x00\x00*0\x00\x04LMT\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8!YF\xec\x00\x00\x00\xec\x00\x00\x00\x0b\x00\x00\x00Asia/SaigonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff\x88\x8cC\x8a\xff\xff\xff\xff\x91\xa3+\x0a\xff\xff\xff\xff\xcd5\xe6\x80\xff\xff\xff\xff\xd1Y\xcep\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd52\xbb\x10\xff\xff\xff\xff\xe4\xb6\xf2\x90\xff\xff\xff\xff\xed/\x98\x00\x00\x00\x00\x00\x0a=\xc7\x00\x01\x02\x03\x04\x02\x03\x02\x03\x02\x00\x00c\xf6\x00\x00\x00\x00c\xf6\x00\x04\x00\x00bp\x00\x09\x00\x00p\x80\x00\x0d\x00\x00~\x90\x00\x11LMT\x00PLMT\x00+07\x00+08\x00+09\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x15II\xf3\x02\x00\x00\xf3\x02\x00\x00\x0d\x00\x00\x00Asia/SakhalinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xff\x86\xf0\xcd\xb8\xff\xff\xff\xff\xd20\xb2\xf0\x00\x00\x00\x00\x15'7P\x00\x00\x00\x00\x16\x18k\xc0\x00\x00\x00\x00\x17\x08j\xd0\x00\x00\x00\x00\x17\xf9\x9f@\x00\x00\x00\x00\x18\xe9\x9eP\x00\x00\x00\x00\x19\xda\xd2\xc0\x00\x00\x00\x00\x1a\xcc#P\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)xO\x00\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Lp\x00\x00\x00\x002r'p\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xfa\xf8\x00\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D%i\x00\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xeeg\x80\x00\x00\x00\x00I\x03B\x80\x00\x00\x00\x00I\xceI\x80\x00\x00\x00\x00J\xe3$\x80\x00\x00\x00\x00K\xae+\x80\x00\x00\x00\x00L\xccA\x00\x00\x00\x00\x00M\x8e\x0d\x80\x00\x00\x00\x00TK\xba\xf0\x00\x00\x00\x00V\xf6\xb2\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x05\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x03\x00\x00\x85\xc8\x00\x00\x00\x00~\x90\x00\x04\x00\x00\xa8\xc0\x01\x08\x00\x00\x9a\xb0\x00\x0c\x00\x00\x9a\xb0\x01\x0c\x00\x00\x8c\xa0\x00\x10LMT\x00+09\x00+12\x00+11\x00+10\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w\x0dD\x07n\x01\x00\x00n\x01\x00\x00\x0e\x00\x00\x00Asia/SamarkandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x857\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xedP\x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00>\xc9\x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0cLMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7X,Y\x9f\x01\x00\x00\x9f\x01\x00\x00\x0a\x00\x00\x00Asia/SeoulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\x8b\xd7\xf0x\xff\xff\xff\xff\x92\xe6\x16\xf8\xff\xff\xff\xff\xd2C'\xf0\xff\xff\xff\xff\xd7e\x8fp\xff\xff\xff\xff\xd7\xee\x9d`\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xd9\xcd-\xe0\xff\xff\xff\xff\xda\xd7\x8a\xf0\xff\xff\xff\xff\xdb\xad\x0f\xe0\xff\xff\xff\xff\xdc\xe6\xe2\xf0\xff\xff\xff\xff\xdd\x8c\xf1\xe0\xff\xff\xff\xff\xe2O)\xf0\xff\xff\xff\xff\xe4k\xb7\xf8\xff\xff\xff\xff\xe5\x13\x18h\xff\xff\xff\xff\xe6b\x03x\xff\xff\xff\xff\xe7\x11L\xe8\xff\xff\xff\xff\xe8/px\xff\xff\xff\xff\xe8\xe7\xf4h\xff\xff\xff\xff\xea\x0fRx\xff\xff\xff\xff\xea\xc7\xd6h\xff\xff\xff\xff\xeb\xef4x\xff\xff\xff\xff\xec\xa7\xb8h\xff\xff\xff\xff\xed\xcf\x16x\xff\xff\xff\xff\xee\x87\x9ah\xff\xff\xff\xff\xf05qx\x00\x00\x00\x00 \xa3`\x90\x00\x00\x00\x00!ng\x90\x00\x00\x00\x00\x22\x83B\x90\x00\x00\x00\x00#NI\x90\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x04\x03\x04\x03\x04\x00\x00w\x08\x00\x00\x00\x00w\x88\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x8c\xa0\x01\x0c\x00\x00~\x90\x00\x04\x00\x00\x85\x98\x01\x0cLMT\x00KST\x00JST\x00KDT\x00\x0aKST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0d\x00\x00\x00Asia/ShanghaiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x0e\x00\x00\x00Asia/SingaporeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00 \xff\xff\xff\xff~6S\xa3\xff\xff\xff\xff\x86\x83\x85\xa3\xff\xff\xff\xff\xbagN\x90\xff\xff\xff\xff\xc0\x0a\xe4`\xff\xff\xff\xff\xca\xb3\xe5`\xff\xff\xff\xff\xcb\x91_\x08\xff\xff\xff\xff\xd2Hm\xf0\x00\x00\x00\x00\x16\x91\xee\x00\x01\x02\x03\x04\x05\x06\x05\x07\x00\x00a]\x00\x00\x00\x00a]\x00\x04\x00\x00bp\x00\x08\x00\x00g \x01\x0c\x00\x00g \x00\x0c\x00\x00ix\x00\x12\x00\x00~\x90\x00\x18\x00\x00p\x80\x00\x1cLMT\x00SMT\x00+07\x00+0720\x00+0730\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4Z\xdf\x90\xe6\x02\x00\x00\xe6\x02\x00\x00\x12\x00\x00\x00Asia/SrednekolymskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x193\xe4\xff\xff\xff\xff\xb5\xa3\xa8\xe0\x00\x00\x00\x00\x15'7P\x00\x00\x00\x00\x16\x18k\xc0\x00\x00\x00\x00\x17\x08j\xd0\x00\x00\x00\x00\x17\xf9\x9f@\x00\x00\x00\x00\x18\xe9\x9eP\x00\x00\x00\x00\x19\xda\xd2\xc0\x00\x00\x00\x00\x1a\xcc#P\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)xO\x00\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Lp\x00\x00\x00\x002r'p\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x09p\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xebp\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x07\xf0\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xfa\xe9\xf0\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xcb\xf0\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xad\xf0\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x8f\xf0\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xacp\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x8ep\x00\x00\x00\x00D%Z\xf0\x00\x00\x00\x00ECpp\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Rp\x00\x00\x00\x00G\xeeYp\x00\x00\x00\x00I\x034p\x00\x00\x00\x00I\xce;p\x00\x00\x00\x00J\xe3\x16p\x00\x00\x00\x00K\xae\x1dp\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x00\x00\x00\x00TK\xac\xe0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00\x90\x1c\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\xa8\xc0\x01\x08\x00\x00\x9a\xb0\x00\x0c\x00\x00\x9a\xb0\x01\x0c\x00\x00\xa8\xc0\x00\x08LMT\x00+10\x00+12\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xf0BB\xff\x01\x00\x00\xff\x01\x00\x00\x0b\x00\x00\x00Asia/TaipeiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xfft\xce\xf0\x18\xff\xff\xff\xff\xc3UI\x80\xff\xff\xff\xff\xd2TY\x80\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9\xe7\x99\xf0\xff\xff\xff\xff\xda\xff&\x00\xff\xff\xff\xff\xdb\xc8\xcdp\xff\xff\xff\xff\xdc\xe0Y\x80\xff\xff\xff\xff\xdd\xaa\x00\xf0\xff\xff\xff\xff\xders\x00\xff\xff\xff\xff\xdf\xb5dp\xff\xff\xff\xff\xe0|\x85\x00\xff\xff\xff\xff\xe1\x96\x97\xf0\xff\xff\xff\xff\xe2]\xb8\x80\xff\xff\xff\xff\xe3w\xcbp\xff\xff\xff\xff\xe4>\xec\x00\xff\xff\xff\xff\xe50 p\xff\xff\xff\xff\xe6!q\x00\xff\xff\xff\xff\xe7\x12\xa5p\xff\xff\xff\xff\xe8\x02\xa4\x80\xff\xff\xff\xff\xe8\xf3\xd8\xf0\xff\xff\xff\xff\xe9\xe3\xd8\x00\xff\xff\xff\xff\xea\xd5\x0cp\xff\xff\xff\xff\xeb\xc5\x0b\x80\xff\xff\xff\xff\xec\xb6?\xf0\xff\xff\xff\xff\xed\xf7\xfc\x00\xff\xff\xff\xff\xee\x98\xc4\xf0\xff\xff\xff\xff\xef\xd9/\x80\xff\xff\xff\xff\xf0y\xf8p\x00\x00\x00\x00\x07\xfcV\x00\x00\x00\x00\x00\x08\xed\x8ap\x00\x00\x00\x00\x09\xdd\x89\x80\x00\x00\x00\x00\x0a\xce\xbd\xf0\x00\x00\x00\x00\x11\xdb\xa1\x80\x00\x00\x00\x00\x12T\xddp\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x00\x00q\xe8\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x00\x08\x00\x00~\x90\x01\x0cLMT\x00CST\x00JST\x00CDT\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xe27Yn\x01\x00\x00n\x01\x00\x00\x0d\x00\x00\x00Asia/TashkentTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x83\x09\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xe4\xedP\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x00\x00@\xf7\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0cLMT\x00+05\x00+07\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\xbe\xa8\xc7u\x02\x00\x00u\x02\x00\x00\x0c\x00\x00\x00Asia/TbilisiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x06\x00\x00\x00\x15\xff\xff\xff\xffV\xb6\xba\x01\xff\xff\xff\xff\xaa\x19\x9a\x01\xff\xff\xff\xff\xe7\xda\x0cP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xc1@\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xa3@\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x85@\x00\x00\x00\x00/tv@\x00\x00\x00\x000dY0\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x003=f\xb0\x00\x00\x00\x004RA\xb0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x0062#\xb0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1b@0\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb\x220\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x040\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xe60\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xc80\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00@\xdd\xc7\xb0\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x02\x05\x02\x05\x02\x05\x04\x03\x04\x03\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x05\x02\x04\x00\x00)\xff\x00\x00\x00\x00)\xff\x00\x04\x00\x00*0\x00\x09\x00\x00FP\x01\x0d\x00\x008@\x00\x11\x00\x008@\x01\x11LMT\x00TBMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xdb?\xec,\x03\x00\x00,\x03\x00\x00\x0b\x00\x00\x00Asia/TehranTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x06\x00\x00\x00\x1c\xff\xff\xff\xff\x9al}\xc8\xff\xff\xff\xff\xbf\x00\xccH\x00\x00\x00\x00\x0d\x94D8\x00\x00\x00\x00\x0e\xad\x13\xb8\x00\x00\x00\x00\x0fys@\x00\x00\x00\x00\x10(\xca\xc0\x00\x00\x00\x00\x10\xed:@\x00\x00\x00\x00\x11\xad\xbcH\x00\x00\x00\x00\x12EJ\xb8\x00\x00\x00\x00\x137\xec\xc8\x00\x00\x00\x00\x14-\x15\xb8\x00\x00\x00\x00( v\xc8\x00\x00\x00\x00(\xdb\x9d\xb8\x00\x00\x00\x00)\xcb\x9c\xc8\x00\x00\x00\x00*\xbe\x22\xb8\x00\x00\x00\x00+\xac\xd0H\x00\x00\x00\x00,\x9fV8\x00\x00\x00\x00-\x8e\x03\xc8\x00\x00\x00\x00.\x80\x89\xb8\x00\x00\x00\x00/o7H\x00\x00\x00\x000a\xbd8\x00\x00\x00\x001Pj\xc8\x00\x00\x00\x002B\xf0\xb8\x00\x00\x00\x0032\xef\xc8\x00\x00\x00\x004%u\xb8\x00\x00\x00\x005\x14#H\x00\x00\x00\x006\x06\xa98\x00\x00\x00\x006\xf5V\xc8\x00\x00\x00\x007\xe7\xdc\xb8\x00\x00\x00\x008\xd6\x8aH\x00\x00\x00\x009\xc9\x108\x00\x00\x00\x00:\xb9\x0fH\x00\x00\x00\x00;\xab\x958\x00\x00\x00\x00<\x9aB\xc8\x00\x00\x00\x00=\x8c\xc8\xb8\x00\x00\x00\x00>{vH\x00\x00\x00\x00?m\xfc8\x00\x00\x00\x00@\x5c\xa9\xc8\x00\x00\x00\x00AO/\xb8\x00\x00\x00\x00B?.\xc8\x00\x00\x00\x00C1\xb4\xb8\x00\x00\x00\x00G\xe2\xc9H\x00\x00\x00\x00H\xd5O8\x00\x00\x00\x00I\xc5NH\x00\x00\x00\x00J\xb7\xd48\x00\x00\x00\x00K\xa6\x81\xc8\x00\x00\x00\x00L\x99\x07\xb8\x00\x00\x00\x00M\x87\xb5H\x00\x00\x00\x00Nz;8\x00\x00\x00\x00Oh\xe8\xc8\x00\x00\x00\x00P[n\xb8\x00\x00\x00\x00QKm\xc8\x00\x00\x00\x00R=\xf3\xb8\x00\x00\x00\x00S,\xa1H\x00\x00\x00\x00T\x1f'8\x00\x00\x00\x00U\x0d\xd4\xc8\x00\x00\x00\x00V\x00Z\xb8\x00\x00\x00\x00V\xef\x08H\x00\x00\x00\x00W\xe1\x8e8\x00\x00\x00\x00X\xd1\x8dH\x00\x00\x00\x00Y\xc4\x138\x00\x00\x00\x00Z\xb2\xc0\xc8\x00\x00\x00\x00[\xa5F\xb8\x00\x00\x00\x00\x5c\x93\xf4H\x00\x00\x00\x00]\x86z8\x00\x00\x00\x00^u'\xc8\x00\x00\x00\x00_g\xad\xb8\x00\x00\x00\x00`W\xac\xc8\x00\x00\x00\x00aJ2\xb8\x00\x00\x00\x00b8\xe0H\x00\x00\x00\x00c+f8\x01\x03\x02\x05\x04\x05\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x0008\x00\x00\x00\x0008\x00\x04\x00\x00?H\x01\x08\x00\x0018\x00\x0e\x00\x00FP\x01\x14\x00\x008@\x00\x18LMT\x00TMT\x00+0430\x00+0330\x00+05\x00+04\x00\x0a<+0330>-3:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x0d\x00\x00\x00Asia/Tel_AvivTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xffV\xb6\xc2\xfa\xff\xff\xff\xff\x9e0E\x88\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xd7Z0\x80\xff\xff\xff\xff\xd7\xdfX\x00\xff\xff\xff\xff\xd8/\xc3\x80\xff\xff\xff\xff\xd9\x1ec\x00\xff\xff\xff\xff\xda\x10\xf7\x00\xff\xff\xff\xff\xda\xeb\xd0\x00\xff\xff\xff\xff\xdb\xb44\x00\xff\xff\xff\xff\xdc\xb9=\x00\xff\xff\xff\xff\xdd\xe0\x8d\x00\xff\xff\xff\xff\xde\xb4\xce\x80\xff\xff\xff\xff\xdf\xa4\xbf\x80\xff\xff\xff\xff\xe0\x8bv\x00\xff\xff\xff\xff\xe1V}\x00\xff\xff\xff\xff\xe2\xbef\x80\xff\xff\xff\xff\xe36_\x00\xff\xff\xff\xff\xe4\x9eH\x80\xff\xff\xff\xff\xe5\x16A\x00\xff\xff\xff\xff\xe6t\xf0\x00\xff\xff\xff\xff\xe7\x11\xd2\x80\xff\xff\xff\xff\xe8&\xad\x80\xff\xff\xff\xff\xe8\xe8z\x00\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x001H\x96\xe0\x00\x00\x00\x002\x83\x82p\x00\x00\x00\x00?|\x9f\xe0\x00\x00\x00\x00@s6p\x00\x00\x00\x00AP\xa4`\x00\x00\x00\x00BL\x8f\x00\x00\x00\x00\x00CHOp\x00\x00\x00\x00D,q\x00\x00\x00\x00\x00E\x1e\xf6\xf0\x00\x00\x00\x00F\x0cS\x00\x00\x00\x00\x00F\xecc\xf0\x00\x00\x00\x00G\xec5\x00\x00\x00\x00\x00H\xe7\xf5p\x00\x00\x00\x00I\xcc\x17\x00\x00\x00\x00\x00J\xbe\x9c\xf0\x00\x00\x00\x00K\xab\xf9\x00\x00\x00\x00\x00L\x8c\x09\xf0\x00\x00\x00\x00M\x95\x15\x80\x00\x00\x00\x00N\x87\x9bp\x00\x00\x00\x00Ot\xf7\x80\x00\x00\x00\x00P^B\xf0\x00\x00\x00\x00QT\xd9\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00!\x06\x00\x00\x00\x00 \xf8\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0c\x00\x008@\x01\x10LMT\x00JMT\x00IDT\x00IST\x00IDDT\x00\x0aIST-2IDT,M3.4.4/26,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j$\xcd\xf4\x9a\x00\x00\x00\x9a\x00\x00\x00\x0b\x00\x00\x00Asia/ThimbuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff\xd5\xe6\x15t\x00\x00\x00\x00!aM\xa8\x01\x02\x00\x00T\x0c\x00\x00\x00\x00MX\x00\x04\x00\x00T`\x00\x0aLMT\x00+0530\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j$\xcd\xf4\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00Asia/ThimphuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff\xd5\xe6\x15t\x00\x00\x00\x00!aM\xa8\x01\x02\x00\x00T\x0c\x00\x00\x00\x00MX\x00\x04\x00\x00T`\x00\x0aLMT\x00+0530\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xf4\xaeg\xd5\x00\x00\x00\xd5\x00\x00\x00\x0a\x00\x00\x00Asia/TokyoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffe\xc2\xa4p\xff\xff\xff\xff\xd7>\x02p\xff\xff\xff\xff\xd7\xedY\xf0\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xd9\xcd;\xf0\xff\xff\xff\xff\xdb\x07\x00\xf0\xff\xff\xff\xff\xdb\xad\x1d\xf0\xff\xff\xff\xff\xdc\xe6\xe2\xf0\xff\xff\xff\xff\xdd\x8c\xff\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x83\x03\x00\x00\x00\x00\x8c\xa0\x01\x04\x00\x00~\x90\x00\x08LMT\x00JDT\x00JST\x00\x0aJST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[u\x99q\xf1\x02\x00\x00\xf1\x02\x00\x00\x0a\x00\x00\x00Asia/TomskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xe5N\xd9\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00,\xa4\x950\x00\x00\x00\x00-\x94\x860\x00\x00\x00\x00.\x84w0\x00\x00\x00\x00/th0\x00\x00\x00\x000dY0\x00\x00\x00\x001]\x84\xb0\x00\x00\x00\x002r_\xb0\x00\x00\x00\x003=f\xb0\x00\x00\x00\x004RA\xb0\x00\x00\x00\x005\x1dH\xb0\x00\x00\x00\x0062#\xb0\x00\x00\x00\x006\xfd*\xb0\x00\x00\x00\x008\x1b@0\x00\x00\x00\x008\xdd\x0c\xb0\x00\x00\x00\x009\xfb\x220\x00\x00\x00\x00:\xbc\xee\xb0\x00\x00\x00\x00;\xdb\x040\x00\x00\x00\x00<\xa6\x0b0\x00\x00\x00\x00<\xce\xe9\xb0\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00BE\xbf@\x00\x00\x00\x00Cc\xd4\xc0\x00\x00\x00\x00D%\xa1@\x00\x00\x00\x00EC\xb6\xc0\x00\x00\x00\x00F\x05\x83@\x00\x00\x00\x00G#\x98\xc0\x00\x00\x00\x00G\xee\x9f\xc0\x00\x00\x00\x00I\x03z\xc0\x00\x00\x00\x00I\xce\x81\xc0\x00\x00\x00\x00J\xe3\x5c\xc0\x00\x00\x00\x00K\xaec\xc0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x00\x00\x00\x00TK\xf30\x00\x00\x00\x00WI\xf8\xc0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00O\xa7\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xc9\xd4\x5c\xbe\x00\x00\x00\xbe\x00\x00\x00\x12\x00\x00\x00Asia/Ujung_PandangTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff\xa1\xf2]\x90\xff\xff\xff\xff\xba\x16\xd5\x90\xff\xff\xff\xff\xcb\x88\x1d\x80\xff\xff\xff\xff\xd2V\xeep\x01\x02\x03\x04\x00\x00o\xf0\x00\x00\x00\x00o\xf0\x00\x04\x00\x00p\x80\x00\x08\x00\x00~\x90\x00\x0c\x00\x00p\x80\x00\x10LMT\x00MMT\x00+08\x00+09\x00WITA\x00\x0aWITA-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\xf4\xb6R\x02\x00\x00R\x02\x00\x00\x10\x00\x00\x00Asia/UlaanbaatarTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x86\xd3\xeeL\x00\x00\x00\x00\x0f\x0b\xdc\x90\x00\x00\x00\x00\x18\xe9\xc8\x80\x00\x00\x00\x00\x19\xda\xfc\xf0\x00\x00\x00\x00\x1a\xccM\x80\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac/\x80\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x11\x80\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xf3\x80\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xd5\x80\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xb7\x80\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x99\x80\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xe4\x98\xf0\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002M=p\x00\x00\x00\x003=<\x80\x00\x00\x00\x004-\x1fp\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x0d\x01p\x00\x00\x00\x00:\xe9\xb3\xa0\x00\x00\x00\x00;\xb4\xac\x90\x00\x00\x00\x00<\xa4\xab\xa0\x00\x00\x00\x00=\x94\x8e\x90\x00\x00\x00\x00>\x84\x8d\xa0\x00\x00\x00\x00?tp\x90\x00\x00\x00\x00@do\xa0\x00\x00\x00\x00ATR\x90\x00\x00\x00\x00BDQ\xa0\x00\x00\x00\x00C44\x90\x00\x00\x00\x00D$3\xa0\x00\x00\x00\x00E\x1dQ\x10\x00\x00\x00\x00U\x15\x9a\xa0\x00\x00\x00\x00V\x05ap\x00\x00\x00\x00V\xf5|\xa0\x00\x00\x00\x00W\xe5Cp\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00d4\x00\x00\x00\x00bp\x00\x04\x00\x00~\x90\x01\x08\x00\x00p\x80\x00\x0cLMT\x00+07\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\xf4\xb6R\x02\x00\x00R\x02\x00\x00\x0f\x00\x00\x00Asia/Ulan_BatorTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x86\xd3\xeeL\x00\x00\x00\x00\x0f\x0b\xdc\x90\x00\x00\x00\x00\x18\xe9\xc8\x80\x00\x00\x00\x00\x19\xda\xfc\xf0\x00\x00\x00\x00\x1a\xccM\x80\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac/\x80\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x11\x80\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xf3\x80\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xd5\x80\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xb7\x80\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x99\x80\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xe4\x98\xf0\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002M=p\x00\x00\x00\x003=<\x80\x00\x00\x00\x004-\x1fp\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x0d\x01p\x00\x00\x00\x00:\xe9\xb3\xa0\x00\x00\x00\x00;\xb4\xac\x90\x00\x00\x00\x00<\xa4\xab\xa0\x00\x00\x00\x00=\x94\x8e\x90\x00\x00\x00\x00>\x84\x8d\xa0\x00\x00\x00\x00?tp\x90\x00\x00\x00\x00@do\xa0\x00\x00\x00\x00ATR\x90\x00\x00\x00\x00BDQ\xa0\x00\x00\x00\x00C44\x90\x00\x00\x00\x00D$3\xa0\x00\x00\x00\x00E\x1dQ\x10\x00\x00\x00\x00U\x15\x9a\xa0\x00\x00\x00\x00V\x05ap\x00\x00\x00\x00V\xf5|\xa0\x00\x00\x00\x00W\xe5Cp\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00d4\x00\x00\x00\x00bp\x00\x04\x00\x00~\x90\x01\x08\x00\x00p\x80\x00\x0cLMT\x00+07\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x1d\xc6\x1b\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Asia/UrumqiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xb0\xfe\xbad\x01\x00\x00R\x1c\x00\x00\x00\x00T`\x00\x04LMT\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w\x86\x8d^\x03\x03\x00\x00\x03\x03\x00\x00\x0d\x00\x00\x00Asia/Ust-NeraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x08\x00\x00\x00\x18\xff\xff\xff\xff\xa1\xdb\xdd\xba\xff\xff\xff\xff\xb5\xa3\xc5\x00\x00\x00\x00\x00\x15'Sp\x00\x00\x00\x00\x16\x18k\xc0\x00\x00\x00\x00\x17\x08j\xd0\x00\x00\x00\x00\x17\xf9\x9f@\x00\x00\x00\x00\x18\xe9\x9eP\x00\x00\x00\x00\x19\xda\xd2\xc0\x00\x00\x00\x00\x1a\xcc#P\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)xO\x00\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Lp\x00\x00\x00\x002r'p\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x09p\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xebp\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x07\xf0\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xfa\xe9\xf0\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xcb\xf0\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xad\xf0\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x8f\xf0\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xacp\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x8ep\x00\x00\x00\x00D%Z\xf0\x00\x00\x00\x00ECpp\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Rp\x00\x00\x00\x00G\xeeYp\x00\x00\x00\x00I\x034p\x00\x00\x00\x00I\xce;p\x00\x00\x00\x00J\xe3\x16p\x00\x00\x00\x00K\xae\x1dp\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x00\x00\x00\x00Nm\xf4@\x00\x00\x00\x00TK\xba\xf0\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x05\x06\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x07\x03\x06\x00\x00\x86F\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x9a\xb0\x00\x0c\x00\x00\xa8\xc0\x01\x10\x00\x00\x9a\xb0\x01\x0c\x00\x00\x8c\xa0\x00\x14\x00\x00\xa8\xc0\x00\x10LMT\x00+08\x00+09\x00+11\x00+12\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0e\x00\x00\x00Asia/VientianeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x85\xc4\xff\xff\xff\xff\xa2jg\xc4\x01\x02\x00\x00^<\x00\x00\x00\x00^<\x00\x04\x00\x00bp\x00\x08LMT\x00BMT\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d%\x05\xd8\xe6\x02\x00\x00\xe6\x02\x00\x00\x10\x00\x00\x00Asia/VladivostokTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa7YG]\xff\xff\xff\xff\xb5\xa3\xb6\xf0\x00\x00\x00\x00\x15'E`\x00\x00\x00\x00\x16\x18y\xd0\x00\x00\x00\x00\x17\x08x\xe0\x00\x00\x00\x00\x17\xf9\xadP\x00\x00\x00\x00\x18\xe9\xac`\x00\x00\x00\x00\x19\xda\xe0\xd0\x00\x00\x00\x00\x1a\xcc1`\x00\x00\x00\x00\x1b\xbc>\x80\x00\x00\x00\x00\x1c\xac/\x80\x00\x00\x00\x00\x1d\x9c \x80\x00\x00\x00\x00\x1e\x8c\x11\x80\x00\x00\x00\x00\x1f|\x02\x80\x00\x00\x00\x00 k\xf3\x80\x00\x00\x00\x00![\xe4\x80\x00\x00\x00\x00\x22K\xd5\x80\x00\x00\x00\x00#;\xc6\x80\x00\x00\x00\x00$+\xb7\x80\x00\x00\x00\x00%\x1b\xa8\x80\x00\x00\x00\x00&\x0b\x99\x80\x00\x00\x00\x00'\x04\xc5\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xe4\xb5\x10\x00\x00\x00\x00)x]\x10\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xc4\x89\x00\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xa4k\x00\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x84M\x00\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000d/\x00\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xfa\xf8\x00\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D%i\x00\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xeeg\x80\x00\x00\x00\x00I\x03B\x80\x00\x00\x00\x00I\xceI\x80\x00\x00\x00\x00J\xe3$\x80\x00\x00\x00\x00K\xae+\x80\x00\x00\x00\x00L\xccA\x00\x00\x00\x00\x00M\x8e\x0d\x80\x00\x00\x00\x00TK\xba\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00{\xa3\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x9a\xb0\x01\x08\x00\x00\x8c\xa0\x00\x0c\x00\x00\x8c\xa0\x01\x0c\x00\x00\x9a\xb0\x00\x08LMT\x00+09\x00+11\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\xb0\x03\xe9\xe5\x02\x00\x00\xe5\x02\x00\x00\x0c\x00\x00\x00Asia/YakutskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xdb\xea^\xff\xff\xff\xff\xb5\xa3\xc5\x00\x00\x00\x00\x00\x15'Sp\x00\x00\x00\x00\x16\x18\x87\xe0\x00\x00\x00\x00\x17\x08\x86\xf0\x00\x00\x00\x00\x17\xf9\xbb`\x00\x00\x00\x00\x18\xe9\xbap\x00\x00\x00\x00\x19\xda\xee\xe0\x00\x00\x00\x00\x1a\xcc?p\x00\x00\x00\x00\x1b\xbcL\x90\x00\x00\x00\x00\x1c\xac=\x90\x00\x00\x00\x00\x1d\x9c.\x90\x00\x00\x00\x00\x1e\x8c\x1f\x90\x00\x00\x00\x00\x1f|\x10\x90\x00\x00\x00\x00 l\x01\x90\x00\x00\x00\x00![\xf2\x90\x00\x00\x00\x00\x22K\xe3\x90\x00\x00\x00\x00#;\xd4\x90\x00\x00\x00\x00$+\xc5\x90\x00\x00\x00\x00%\x1b\xb6\x90\x00\x00\x00\x00&\x0b\xa7\x90\x00\x00\x00\x00'\x04\xd3\x10\x00\x00\x00\x00'\xf4\xc4\x10\x00\x00\x00\x00(\xe4\xc3 \x00\x00\x00\x00)xk \x00\x00\x00\x00)\xd4\xa6\x10\x00\x00\x00\x00*\xc4\x97\x10\x00\x00\x00\x00+\xb4\x88\x10\x00\x00\x00\x00,\xa4y\x10\x00\x00\x00\x00-\x94j\x10\x00\x00\x00\x00.\x84[\x10\x00\x00\x00\x00/tL\x10\x00\x00\x00\x000d=\x10\x00\x00\x00\x001]h\x90\x00\x00\x00\x002rC\x90\x00\x00\x00\x003=J\x90\x00\x00\x00\x004R%\x90\x00\x00\x00\x005\x1d,\x90\x00\x00\x00\x0062\x07\x90\x00\x00\x00\x006\xfd\x0e\x90\x00\x00\x00\x008\x1b$\x10\x00\x00\x00\x008\xdc\xf0\x90\x00\x00\x00\x009\xfb\x06\x10\x00\x00\x00\x00:\xbc\xd2\x90\x00\x00\x00\x00;\xda\xe8\x10\x00\x00\x00\x00<\xa5\xef\x10\x00\x00\x00\x00=\xba\xca\x10\x00\x00\x00\x00>\x85\xd1\x10\x00\x00\x00\x00?\x9a\xac\x10\x00\x00\x00\x00@e\xb3\x10\x00\x00\x00\x00A\x83\xc8\x90\x00\x00\x00\x00BE\x95\x10\x00\x00\x00\x00Cc\xaa\x90\x00\x00\x00\x00D%w\x10\x00\x00\x00\x00EC\x8c\x90\x00\x00\x00\x00F\x05Y\x10\x00\x00\x00\x00G#n\x90\x00\x00\x00\x00G\xeeu\x90\x00\x00\x00\x00I\x03P\x90\x00\x00\x00\x00I\xceW\x90\x00\x00\x00\x00J\xe32\x90\x00\x00\x00\x00K\xae9\x90\x00\x00\x00\x00L\xccO\x10\x00\x00\x00\x00M\x8e\x1b\x90\x00\x00\x00\x00TK\xc9\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00y\xa2\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x0c\x00\x00\x8c\xa0\x00\x08LMT\x00+08\x00+10\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0b\x00\x00\x00Asia/YangonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffV\xb6\x89\xd1\xff\xff\xff\xff\xa1\xf2sQ\xff\xff\xff\xff\xcb\xf2\xfc\x18\xff\xff\xff\xff\xd1\x9ag\xf0\x01\x02\x03\x02\x00\x00Z/\x00\x00\x00\x00Z/\x00\x04\x00\x00[h\x00\x08\x00\x00~\x90\x00\x0eLMT\x00RMT\x00+0630\x00+09\x00\x0a<+0630>-6:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xea\x18\xd4\xf8\x02\x00\x00\xf8\x02\x00\x00\x12\x00\x00\x00Asia/YekaterinburgTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\x9b_\x09'\xff\xff\xff\xff\xa1\x12\xb1\xff\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xbf0\x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1b\x5cP\x00\x00\x00\x008\xdd(\xd0\x00\x00\x00\x009\xfb>P\x00\x00\x00\x00:\xbd\x0a\xd0\x00\x00\x00\x00;\xdb P\x00\x00\x00\x00<\xa6'P\x00\x00\x00\x00=\xbb\x02P\x00\x00\x00\x00>\x86\x09P\x00\x00\x00\x00?\x9a\xe4P\x00\x00\x00\x00@e\xebP\x00\x00\x00\x00A\x84\x00\xd0\x00\x00\x00\x00BE\xcdP\x00\x00\x00\x00Cc\xe2\xd0\x00\x00\x00\x00D%\xafP\x00\x00\x00\x00EC\xc4\xd0\x00\x00\x00\x00F\x05\x91P\x00\x00\x00\x00G#\xa6\xd0\x00\x00\x00\x00G\xee\xad\xd0\x00\x00\x00\x00I\x03\x88\xd0\x00\x00\x00\x00I\xce\x8f\xd0\x00\x00\x00\x00J\xe3j\xd0\x00\x00\x00\x00K\xaeq\xd0\x00\x00\x00\x00L\xcc\x87P\x00\x00\x00\x00M\x8eS\xd0\x00\x00\x00\x00TL\x01@\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x04\x00\x008\xd9\x00\x00\x00\x004\xc1\x00\x04\x00\x008@\x00\x08\x00\x00T`\x01\x0c\x00\x00FP\x00\x10\x00\x00FP\x01\x10\x00\x00T`\x00\x0cLMT\x00PMT\x00+04\x00+06\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x95-\xad\xc4\x02\x00\x00\xc4\x02\x00\x00\x0c\x00\x00\x00Asia/YerevanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x9aH\xff\xff\xff\xff\xe7\xda\x0cP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004Rk\xe0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x0062M\xe0\x00\x00\x00\x006\xfdT\xe0\x00\x00\x00\x008\x1bj`\x00\x00\x00\x008\xdd6\xe0\x00\x00\x00\x009\xfbL`\x00\x00\x00\x00:\xbd\x18\xe0\x00\x00\x00\x00;\xdb.`\x00\x00\x00\x00<\xa65`\x00\x00\x00\x00=\xbb\x10`\x00\x00\x00\x00>\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x00\x00\x00\x00BE\xdb`\x00\x00\x00\x00Cc\xf0\xe0\x00\x00\x00\x00D%\xbd`\x00\x00\x00\x00EC\xd2\xe0\x00\x00\x00\x00F\x05\x9f`\x00\x00\x00\x00G#\xb4\xe0\x00\x00\x00\x00G\xee\xbb\xe0\x00\x00\x00\x00I\x03\x96\xe0\x00\x00\x00\x00I\xce\x9d\xe0\x00\x00\x00\x00J\xe3x\xe0\x00\x00\x00\x00K\xae\x7f\xe0\x00\x00\x00\x00L\xcc\x95`\x00\x00\x00\x00M\x8ea\xe0\x00\x00\x00\x00N\xacw`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00)\xb8\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0cLMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x8dY\x80\xad\x05\x00\x00\xad\x05\x00\x00\x0f\x00\x00\x00Atlantic/AzoresTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x00\x00\x00\x07\x00\x00\x00\x18\xff\xff\xff\xff^=\x1b\x90\xff\xff\xff\xff\x92\xe6\xaa\xa0\xff\xff\xff\xff\x9bK\x89\x90\xff\xff\xff\xff\x9b\xfe\xe3\xa0\xff\xff\xff\xff\x9c\x9d\x09\x90\xff\xff\xff\xff\x9d\xc9\x9f\x90\xff\xff\xff\xff\x9e\x7f\x8e\x90\xff\xff\xff\xff\x9f\xaa\xd3\x10\xff\xff\xff\xff\xa0_p\x90\xff\xff\xff\xff\xa1\x8c\x06\x90\xff\xff\xff\xff\xa2A\xf5\x90\xff\xff\xff\xff\xa3n\x8b\x90\xff\xff\xff\xff\xa4#)\x10\xff\xff\xff\xff\xa5O\xbf\x10\xff\xff\xff\xff\xaa\x06\x0b\x90\xff\xff\xff\xff\xaa\xf4\xab\x10\xff\xff\xff\xff\xad\xc9\xc4\x10\xff\xff\xff\xff\xae\xa7@\x10\xff\xff\xff\xff\xaf\xa0k\x90\xff\xff\xff\xff\xb0\x87\x22\x10\xff\xff\xff\xff\xb1\x89\x88\x10\xff\xff\xff\xff\xb2p>\x90\xff\xff\xff\xff\xb3r\xa4\x90\xff\xff\xff\xff\xb4P \x90\xff\xff\xff\xff\xb72h\x90\xff\xff\xff\xff\xb8\x0f\xe4\x90\xff\xff\xff\xff\xb8\xff\xd5\x90\xff\xff\xff\xff\xb9\xef\xc6\x90\xff\xff\xff\xff\xbc\xc8\xd4\x10\xff\xff\xff\xff\xbd\xb8\xc5\x10\xff\xff\xff\xff\xbe\x9f{\x90\xff\xff\xff\xff\xbf\x98\xa7\x10\xff\xff\xff\xff\xc0\x9b\x0d\x10\xff\xff\xff\xff\xc1x\x89\x10\xff\xff\xff\xff\xc2hz\x10\xff\xff\xff\xff\xc3Xk\x10\xff\xff\xff\xff\xc4?!\x90\xff\xff\xff\xff\xc58M\x10\xff\xff\xff\xff\xc6:\xb3\x10\xff\xff\xff\xff\xc7X\xc8\x90\xff\xff\xff\xff\xc7\xd9\xfb\x90\xff\xff\xff\xff\xc9\x01K\x90\xff\xff\xff\xff\xc9\xf1<\x90\xff\xff\xff\xff\xca\xe2\x7f\x10\xff\xff\xff\xff\xcb\xb5o\x10\xff\xff\xff\xff\xcb\xec\xc0\x00\xff\xff\xff\xff\xcc\x80h\x00\xff\xff\xff\xff\xcc\xdc\xbf\x10\xff\xff\xff\xff\xcd\x95Q\x10\xff\xff\xff\xff\xcd\xc3g\x80\xff\xff\xff\xff\xcer\xbf\x00\xff\xff\xff\xff\xce\xc5\xdb\x90\xff\xff\xff\xff\xcfu3\x10\xff\xff\xff\xff\xcf\xac\x84\x00\xff\xff\xff\xff\xd0R\xa1\x00\xff\xff\xff\xff\xd0\xa5\xbd\x90\xff\xff\xff\xff\xd1U\x15\x10\xff\xff\xff\xff\xd1\x8cf\x00\xff\xff\xff\xff\xd22\x83\x00\xff\xff\xff\xff\xd2\x85\x9f\x90\xff\xff\xff\xff\xd3Y\xe1\x10\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd59\xed@\xff\xff\xff\xff\xd6)\xde@\xff\xff\xff\xff\xd7\x19\xcf@\xff\xff\xff\xff\xd8\x09\xc0@\xff\xff\xff\xff\xd8\xf9\xb1@\xff\xff\xff\xff\xd9\xe9\xa2@\xff\xff\xff\xff\xda\xd9\x93@\xff\xff\xff\xff\xdb\xc9\x84@\xff\xff\xff\xff\xdc\xb9u@\xff\xff\xff\xff\xdd\xb2\xa0\xc0\xff\xff\xff\xff\xde\xa2\x91\xc0\xff\xff\xff\xff\xdf\x92\x82\xc0\xff\xff\xff\xff\xe0\x82s\xc0\xff\xff\xff\xff\xe1rd\xc0\xff\xff\xff\xff\xe2bU\xc0\xff\xff\xff\xff\xe3RF\xc0\xff\xff\xff\xff\xe4B7\xc0\xff\xff\xff\xff\xe52(\xc0\xff\xff\xff\xff\xe6\x22\x19\xc0\xff\xff\xff\xff\xe7\x1bE@\xff\xff\xff\xff\xe8\x0b6@\xff\xff\xff\xff\xe8\xfb'@\xff\xff\xff\xff\xe9\xeb\x18@\xff\xff\xff\xff\xea\xdb\x09@\xff\xff\xff\xff\xeb\xca\xfa@\xff\xff\xff\xff\xec\xba\xeb@\xff\xff\xff\xff\xed\xaa\xdc@\xff\xff\xff\xff\xee\x9a\xcd@\xff\xff\xff\xff\xef\x8a\xbe@\xff\xff\xff\xff\xf0z\xaf@\xff\xff\xff\xff\xf1j\xa0@\xff\xff\xff\xff\xf2c\xcb\xc0\xff\xff\xff\xff\xf3S\xbc\xc0\xff\xff\xff\xff\xf4C\xad\xc0\xff\xff\xff\xff\xf53\x9e\xc0\xff\xff\xff\xff\xf6#\x8f\xc0\xff\xff\xff\xff\xf7\x13\x80\xc0\xff\xff\xff\xff\xf8\x03q\xc0\xff\xff\xff\xff\xf8\xf3b\xc0\x00\x00\x00\x00\x0d\x9b)\x10\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T&\xa0\x00\x00\x00\x00\x13D\x09\x90\x00\x00\x00\x00\x144\x08\xa0\x00\x00\x00\x00\x15#\xf9\xa0\x00\x00\x00\x00\x16\x13\xea\xa0\x00\x00\x00\x00\x17\x03\xdb\xa0\x00\x00\x00\x00\x17\xf3\xcc\xa0\x00\x00\x00\x00\x18\xe3\xcb\xb0\x00\x00\x00\x00\x19\xd3\xae\xa0\x00\x00\x00\x00\x1a\xc3\x9f\xa0\x00\x00\x00\x00\x1b\xbc\xcb \x00\x00\x00\x00\x1c\xac\xbc \x00\x00\x00\x00\x1d\x9c\xad \x00\x00\x00\x00\x1e\x8c\x9e \x00\x00\x00\x00\x1f|\x8f \x00\x00\x00\x00 l\x80 \x00\x00\x00\x00!\x5cq \x00\x00\x00\x00\x22Lb \x00\x00\x00\x00#1<+00>,M3.5.0/0,M10.5.0/1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l&\x04\x99\x00\x04\x00\x00\x00\x04\x00\x00\x10\x00\x00\x00Atlantic/BermudaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x18F\xff\xff\xff\xff\x9c\xcc\xaeF\xff\xff\xff\xff\x9d\xb7K6\xff\xff\xff\xff\x9e\xb8m\xc6\xff\xff\xff\xff\x9f\x84\xb86\xff\xff\xff\xff\xb4\xc3\x1d\xe6\xff\xff\xff\xff\xcbb\xa6\xe0\xff\xff\xff\xff\xcc\xd3\xbc\xd0\xff\xff\xff\xff\xcd\x9e\xd1\xe0\xff\xff\xff\xff\xce\xc6\x13\xd0\xff\xff\xff\xff\xcfuy`\xff\xff\xff\xff\xd0\xaf0P\xff\xff\xff\xff\xd1U[`\xff\xff\xff\xff\xd2\x8f\x12P\xff\xff\xff\xff\xd5qh`\xff\xff\xff\xff\xd6\x0e<\xd0\xff\xff\xff\xff\xd7Z\x84\xe0\xff\xff\xff\xff\xd7\xe4\xe4P\xff\xff\xff\xff\xd9:f\xe0\xff\xff\xff\xff\xd9\xc4\xc6P\xff\xff\xff\xff\xdb#\x83`\xff\xff\xff\xff\xdb\xa4\xa8P\xff\xff\xff\xff\xdd\x03e`\xff\xff\xff\xff\xdd\x84\x8aP\xff\xff\xff\xff\xde\xe3G`\xff\xff\xff\xff\xdfm\xa6\xd0\xff\xff\xff\xff\xe6l\x09\xe0\xff\xff\xff\xff\xe77\x02\xd0\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\xff\xff\xc3:\x00\x00\xff\xff\xd1J\x01\x04\xff\xff\xc3:\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xc7\xc0\x00\x10LMT\x00BST\x00BMT\x00ADT\x00AST\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf|7\xb3\xde\x01\x00\x00\xde\x01\x00\x00\x0f\x00\x00\x00Atlantic/CanaryTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa6\x04\x5c\xf0\xff\xff\xff\xff\xd4A\xf7 \x00\x00\x00\x00\x13M6\x00\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\x0e\xbdm\xb9\x01\x00\x00\xb9\x01\x00\x00\x0f\x00\x00\x00Atlantic/FaeroeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff\x8bm\xa4X\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00Atlantic/St_HelenaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\xcf^\xb0\x15\x03\x00\x00\x15\x03\x00\x00\x10\x00\x00\x00Atlantic/StanleyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x11\xbc\xff\xff\xff\xff\x93D_<\xff\xff\xff\xff\xc3OZ\xc0\xff\xff\xff\xff\xc46\x030\xff\xff\xff\xff\xc5/<\xc0\xff\xff\xff\xff\xc6\x15\xe50\xff\xff\xff\xff\xc7\x18Y@\xff\xff\xff\xff\xc7\xff\x01\xb0\xff\xff\xff\xff\xc8\xf8;@\xff\xff\xff\xff\xc9\xde\xe3\xb0\xff\xff\xff\xff\xca\xd8\x1d@\xff\xff\xff\xff\xcb\xbe\xc5\xb0\xff\xff\xff\xff\xcc\xb7\xff@\xff\xff\xff\xff\xcd6\x810\x00\x00\x00\x00\x19\x11\xfe@\x00\x00\x00\x00\x19\xd3\xbc\xb0\x00\x00\x00\x00\x1a\xf1\xc4 \x00\x00\x00\x00\x1b\xaad0\x00\x00\x00\x00\x1c\xd1\xa6 \x00\x00\x00\x00\x1d\x8aF0\x00\x00\x00\x00\x1e\xa8[\xb0\x00\x00\x00\x00\x1fj6@\x00\x00\x00\x00 \x88=\xb0\x00\x00\x00\x00!J\x18@\x00\x00\x00\x00\x22h\x1f\xb0\x00\x00\x00\x00#)\xfa@\x00\x00\x00\x00$H\x01\xb0\x00\x00\x00\x00%\x09\xdc@\x00\x00\x00\x00&1\x1e0\x00\x00\x00\x00&\xe9\xbe@\x00\x00\x00\x00(\x11\x000\x00\x00\x00\x00(\xd2\xda\xc0\x00\x00\x00\x00)\xf0\xe20\x00\x00\x00\x00*\xb2\xbc\xc0\x00\x00\x00\x00+\xd0\xc40\x00\x00\x00\x00,\x92\x9e\xc0\x00\x00\x00\x00-\xb0\xa60\x00\x00\x00\x00.r\x80\xc0\x00\x00\x00\x00/\x90\x880\x00\x00\x00\x000Rb\xc0\x00\x00\x00\x001y\xa4\xb0\x00\x00\x00\x002;\x7f@\x00\x00\x00\x003Y\x86\xb0\x00\x00\x00\x004\x1ba@\x00\x00\x00\x0059h\xb0\x00\x00\x00\x005\xfbC@\x00\x00\x00\x007\x19J\xb0\x00\x00\x00\x007\xdb%@\x00\x00\x00\x008\xf9,\xb0\x00\x00\x00\x009\xbb\x07@\x00\x00\x00\x00:\xd9*\xd0\x00\x00\x00\x00;\x91\xca\xe0\x00\x00\x00\x00<\xc2GP\x00\x00\x00\x00=q\xac\xe0\x00\x00\x00\x00>\xa2)P\x00\x00\x00\x00?Z\xc9`\x00\x00\x00\x00@\x82\x0bP\x00\x00\x00\x00A:\xab`\x00\x00\x00\x00Ba\xedP\x00\x00\x00\x00C\x1a\x8d`\x00\x00\x00\x00DA\xcfP\x00\x00\x00\x00D\xfao`\x00\x00\x00\x00F!\xb1P\x00\x00\x00\x00F\xdaQ`\x00\x00\x00\x00H\x0a\xcd\xd0\x00\x00\x00\x00H\xc3m\xe0\x00\x00\x00\x00I\xea\xaf\xd0\x00\x00\x00\x00J\xa3O\xe0\x00\x00\x00\x00K\xca\x91\xd0\x00\x00\x00\x00L\x831\xe0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\xff\xff\xc9\xc4\x00\x00\xff\xff\xc9\xc4\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x08LMT\x00SMT\x00-03\x00-04\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x0d\x00\x00\x00Australia/ACTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x7f<\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x0c\x89\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/X\x8e\x80\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8d\xc4\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ff~\xd5\x99\x03\x00\x00\x99\x03\x00\x00\x12\x00\x00\x00Australia/AdelaideTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x04\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x8b\x14\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x00\x00\x00\x00\x03p@\x88\x00\x00\x00\x00\x04\x0d#\x08\x00\x00\x00\x00\x05P\x22\x88\x00\x00\x00\x00\x05\xf6?\x88\x00\x00\x00\x00\x070\x04\x88\x00\x00\x00\x00\x07\xd6!\x88\x00\x00\x00\x00\x09\x0f\xe6\x88\x00\x00\x00\x00\x09\xb6\x03\x88\x00\x00\x00\x00\x0a\xef\xc8\x88\x00\x00\x00\x00\x0b\x9f \x08\x00\x00\x00\x00\x0c\xd8\xe5\x08\x00\x00\x00\x00\x0d\x7f\x02\x08\x00\x00\x00\x00\x0e\xb8\xc7\x08\x00\x00\x00\x00\x0f^\xe4\x08\x00\x00\x00\x00\x10\x98\xa9\x08\x00\x00\x00\x00\x11>\xc6\x08\x00\x00\x00\x00\x12x\x8b\x08\x00\x00\x00\x00\x13\x1e\xa8\x08\x00\x00\x00\x00\x14Xm\x08\x00\x00\x00\x00\x14\xfe\x8a\x08\x00\x00\x00\x00\x168O\x08\x00\x00\x00\x00\x16\xe7\xa6\x88\x00\x00\x00\x00\x18!k\x88\x00\x00\x00\x00\x18\xc7\x88\x88\x00\x00\x00\x00\x1a\x01M\x88\x00\x00\x00\x00\x1a\xa7j\x88\x00\x00\x00\x00\x1b\xe1/\x88\x00\x00\x00\x00\x1c\x87L\x88\x00\x00\x00\x00\x1d\xc1\x11\x88\x00\x00\x00\x00\x1ey\xa3\x88\x00\x00\x00\x00\x1f\x97\xb9\x08\x00\x00\x00\x00 Y\x85\x88\x00\x00\x00\x00!\x80\xd5\x88\x00\x00\x00\x00\x22B\xa2\x08\x00\x00\x00\x00#i\xf2\x08\x00\x00\x00\x00$\x22\x84\x08\x00\x00\x00\x00%I\xd4\x08\x00\x00\x00\x00&\x02f\x08\x00\x00\x00\x00')\xb6\x08\x00\x00\x00\x00'\xcf\xd3\x08\x00\x00\x00\x00)\x09\x98\x08\x00\x00\x00\x00)\xcbd\x88\x00\x00\x00\x00*\xe9z\x08\x00\x00\x00\x00+\x98\xd1\x88\x00\x00\x00\x00,\xd2\x96\x88\x00\x00\x00\x00-\x8b(\x88\x00\x00\x00\x00.\xb2x\x88\x00\x00\x00\x00/tE\x08\x00\x00\x00\x000\x92Z\x88\x00\x00\x00\x001]a\x88\x00\x00\x00\x002r<\x88\x00\x00\x00\x003=C\x88\x00\x00\x00\x004R\x1e\x88\x00\x00\x00\x005\x1d%\x88\x00\x00\x00\x0062\x00\x88\x00\x00\x00\x006\xfd\x07\x88\x00\x00\x00\x008\x1b\x1d\x08\x00\x00\x00\x008\xdc\xe9\x88\x00\x00\x00\x009\xfa\xff\x08\x00\x00\x00\x00:\xbc\xcb\x88\x00\x00\x00\x00;\xda\xe1\x08\x00\x00\x00\x00<\xa5\xe8\x08\x00\x00\x00\x00=\xba\xc3\x08\x00\x00\x00\x00>\x85\xca\x08\x00\x00\x00\x00?\x9a\xa5\x08\x00\x00\x00\x00@e\xac\x08\x00\x00\x00\x00A\x83\xc1\x88\x00\x00\x00\x00BE\x8e\x08\x00\x00\x00\x00Cc\xa3\x88\x00\x00\x00\x00D.\xaa\x88\x00\x00\x00\x00EC\x85\x88\x00\x00\x00\x00F\x05R\x08\x00\x00\x00\x00G#g\x88\x00\x00\x00\x00G\xf7\xa9\x08\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x81\xec\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x93\xa8\x01\x09\x00\x00\x85\x98\x00\x04LMT\x00ACST\x00ACDT\x00\x0aACST-9:30ACDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xba\xde\xd3!\x01\x00\x00!\x01\x00\x00\x12\x00\x00\x00Australia/BrisbaneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffr\xed\x9f\x08\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8fx\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xca#\x7f\xad\x03\x00\x00\xad\x03\x00\x00\x15\x00\x00\x00Australia/Broken_HillTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x00\x00\x00\x05\x00\x00\x00\x13\xff\xff\xff\xffs\x16\x88d\xff\xff\xff\xffv\x04\xa5\xe0\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x00\x00\x00\x00\x03p@\x88\x00\x00\x00\x00\x04\x0d#\x08\x00\x00\x00\x00\x05P\x22\x88\x00\x00\x00\x00\x05\xf6?\x88\x00\x00\x00\x00\x070\x04\x88\x00\x00\x00\x00\x07\xd6!\x88\x00\x00\x00\x00\x09\x0f\xe6\x88\x00\x00\x00\x00\x09\xb6\x03\x88\x00\x00\x00\x00\x0a\xef\xc8\x88\x00\x00\x00\x00\x0b\x9f \x08\x00\x00\x00\x00\x0c\xd8\xe5\x08\x00\x00\x00\x00\x0d\x7f\x02\x08\x00\x00\x00\x00\x0e\xb8\xc7\x08\x00\x00\x00\x00\x0f^\xe4\x08\x00\x00\x00\x00\x10\x98\xa9\x08\x00\x00\x00\x00\x11>\xc6\x08\x00\x00\x00\x00\x12x\x8b\x08\x00\x00\x00\x00\x13\x1e\xa8\x08\x00\x00\x00\x00\x14Xm\x08\x00\x00\x00\x00\x14\xfe\x8a\x08\x00\x00\x00\x00\x168O\x08\x00\x00\x00\x00\x17\x0c\x90\x88\x00\x00\x00\x00\x18!k\x88\x00\x00\x00\x00\x18\xc7\x88\x88\x00\x00\x00\x00\x1a\x01M\x88\x00\x00\x00\x00\x1a\xa7j\x88\x00\x00\x00\x00\x1b\xe1/\x88\x00\x00\x00\x00\x1c\x87L\x88\x00\x00\x00\x00\x1d\xc1\x11\x88\x00\x00\x00\x00\x1ey\xa3\x88\x00\x00\x00\x00\x1f\x97\xb9\x08\x00\x00\x00\x00 Y\x85\x88\x00\x00\x00\x00!\x80\xd5\x88\x00\x00\x00\x00\x22B\xa2\x08\x00\x00\x00\x00#i\xf2\x08\x00\x00\x00\x00$\x22\x84\x08\x00\x00\x00\x00%I\xd4\x08\x00\x00\x00\x00%\xef\xf1\x08\x00\x00\x00\x00')\xb6\x08\x00\x00\x00\x00'\xcf\xd3\x08\x00\x00\x00\x00)\x09\x98\x08\x00\x00\x00\x00)\xaf\xb5\x08\x00\x00\x00\x00*\xe9z\x08\x00\x00\x00\x00+\x98\xd1\x88\x00\x00\x00\x00,\xd2\x96\x88\x00\x00\x00\x00-x\xb3\x88\x00\x00\x00\x00.\xb2x\x88\x00\x00\x00\x00/X\x95\x88\x00\x00\x00\x000\x92Z\x88\x00\x00\x00\x001]a\x88\x00\x00\x00\x002r<\x88\x00\x00\x00\x003=C\x88\x00\x00\x00\x004R\x1e\x88\x00\x00\x00\x005\x1d%\x88\x00\x00\x00\x0062\x00\x88\x00\x00\x00\x006\xfd\x07\x88\x00\x00\x00\x008\x1b\x1d\x08\x00\x00\x00\x008\xdc\xe9\x88\x00\x00\x00\x009\xfa\xff\x08\x00\x00\x00\x00:\xbc\xcb\x88\x00\x00\x00\x00;\xda\xe1\x08\x00\x00\x00\x00<\xa5\xe8\x08\x00\x00\x00\x00=\xba\xc3\x08\x00\x00\x00\x00>\x85\xca\x08\x00\x00\x00\x00?\x9a\xa5\x08\x00\x00\x00\x00@e\xac\x08\x00\x00\x00\x00A\x83\xc1\x88\x00\x00\x00\x00BE\x8e\x08\x00\x00\x00\x00Cc\xa3\x88\x00\x00\x00\x00D.\xaa\x88\x00\x00\x00\x00EC\x85\x88\x00\x00\x00\x00F\x05R\x08\x00\x00\x00\x00G#g\x88\x00\x00\x00\x00G\xf7\xa9\x08\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x00\x00\x84\x9c\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00~\x90\x00\x09\x00\x00\x93\xa8\x01\x0e\x00\x00\x85\x98\x00\x09LMT\x00AEST\x00ACST\x00ACDT\x00\x0aACST-9:30ACDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00Australia/CanberraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x7f<\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x0c\x89\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/X\x8e\x80\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8d\xc4\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x10\x00\x00\x00Australia/CurrieTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft.\x00\xe4\xff\xff\xff\xff\x9b\xd5x\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\x9d\xdaD\x80\xff\xff\xff\xff\x9e\x80a\x80\xff\xff\xff\xff\x9f\xba&\x80\xff\xff\xff\xff\xa0`C\x80\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\xff\xff\xff\xff\xfb\xc2\x8d\x00\xff\xff\xff\xff\xfc\xb2~\x00\xff\xff\xff\xff\xfd\xc7Y\x00\xff\xff\xff\xff\xfev\xb0\x80\xff\xff\xff\xff\xff\xa7;\x00\x00\x00\x00\x00\x00V\x92\x80\x00\x00\x00\x00\x01\x87\x1d\x00\x00\x00\x00\x00\x02?\xaf\x00\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x03O\x00\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xe31\x00\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1eg'\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xed\xe1\x80\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xcd\xc3\x80\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xad\xa5\x80\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x8d\x87\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000mi\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002V\x86\x00\x00\x00\x00\x003=<\x80\x00\x00\x00\x0046h\x00\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x16J\x00\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x007\xf6,\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xbf*\x80\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\x9f\x0c\x80\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?~\xee\x80\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A^\xd0\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00C>\xb2\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00E\x1e\x94\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G\x07\xb1\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x8a\x1c\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8R\x1a\x1b\xea\x00\x00\x00\xea\x00\x00\x00\x10\x00\x00\x00Australia/DarwinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x04\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x92X\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00z\xa8\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x93\xa8\x01\x09\x00\x00\x85\x98\x00\x04LMT\x00ACST\x00ACDT\x00\x0aACST-9:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2\xdc\xba\xca:\x01\x00\x00:\x01\x00\x00\x0f\x00\x00\x00Australia/EuclaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x03\x00\x00\x00\x10\xff\xff\xff\xfft\xa6\x0a\xb0\xff\xff\xff\xff\x9cN\xd4\x14\xff\xff\xff\xff\x9c\xbc@\x94\xff\xff\xff\xff\xcbT\xc4\x94\xff\xff\xff\xff\xcb\xc7w\x14\xff\xff\xff\xff\xcc\xb7h\x14\xff\xff\xff\xff\xcd\xa7Y\x14\x00\x00\x00\x00\x09\x0f\xf1\x14\x00\x00\x00\x00\x09\xb6\x0e\x14\x00\x00\x00\x00\x1a\x01X\x14\x00\x00\x00\x00\x1a\xa7u\x14\x00\x00\x00\x00)%R\x14\x00\x00\x00\x00)\xaf\xbf\x94\x00\x00\x00\x00Eq\xb4\x94\x00\x00\x00\x00F\x05\x5c\x94\x00\x00\x00\x00G#r\x14\x00\x00\x00\x00G\xeey\x14\x00\x00\x00\x00I\x03T\x14\x00\x00\x00\x00I\xce[\x14\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00x\xd0\x00\x00\x00\x00\x89\x1c\x01\x04\x00\x00{\x0c\x00\x0aLMT\x00+0945\x00+0845\x00\x0a<+0845>-8:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x10\x00\x00\x00Australia/HobartTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft.\x00\xe4\xff\xff\xff\xff\x9b\xd5x\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\x9d\xdaD\x80\xff\xff\xff\xff\x9e\x80a\x80\xff\xff\xff\xff\x9f\xba&\x80\xff\xff\xff\xff\xa0`C\x80\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\xff\xff\xff\xff\xfb\xc2\x8d\x00\xff\xff\xff\xff\xfc\xb2~\x00\xff\xff\xff\xff\xfd\xc7Y\x00\xff\xff\xff\xff\xfev\xb0\x80\xff\xff\xff\xff\xff\xa7;\x00\x00\x00\x00\x00\x00V\x92\x80\x00\x00\x00\x00\x01\x87\x1d\x00\x00\x00\x00\x00\x02?\xaf\x00\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x03O\x00\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xe31\x00\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1eg'\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xed\xe1\x80\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xcd\xc3\x80\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xad\xa5\x80\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x8d\x87\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000mi\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002V\x86\x00\x00\x00\x00\x003=<\x80\x00\x00\x00\x0046h\x00\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x16J\x00\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x007\xf6,\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xbf*\x80\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\x9f\x0c\x80\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?~\xee\x80\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A^\xd0\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00C>\xb2\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00E\x1e\x94\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G\x07\xb1\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x8a\x1c\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o3\xdaR\xb4\x02\x00\x00\xb4\x02\x00\x00\x0d\x00\x00\x00Australia/LHITZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x05\x00\x00\x00\x19\xff\xff\xff\xffs\x16w\xdc\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168@\xf8\x00\x00\x00\x00\x16\xe7\x8ah\x00\x00\x00\x00\x18!]x\x00\x00\x00\x00\x18\xc7lh\x00\x00\x00\x00\x1a\x01?x\x00\x00\x00\x00\x1a\xa7Nh\x00\x00\x00\x00\x1b\xe1!x\x00\x00\x00\x00\x1c\x870h\x00\x00\x00\x00\x1d\xc1\x03x\x00\x00\x00\x00\x1ey\x8ep\x00\x00\x00\x00\x1f\x97\xaa\xf8\x00\x00\x00\x00 Ypp\x00\x00\x00\x00!\x80\xc7x\x00\x00\x00\x00\x22B\x8c\xf0\x00\x00\x00\x00#i\xe3\xf8\x00\x00\x00\x00$\x22n\xf0\x00\x00\x00\x00%I\xc5\xf8\x00\x00\x00\x00%\xef\xdb\xf0\x00\x00\x00\x00')\xa7\xf8\x00\x00\x00\x00'\xcf\xbd\xf0\x00\x00\x00\x00)\x09\x89\xf8\x00\x00\x00\x00)\xaf\x9f\xf0\x00\x00\x00\x00*\xe9k\xf8\x00\x00\x00\x00+\x98\xbcp\x00\x00\x00\x00,\xd2\x88x\x00\x00\x00\x00-x\x9ep\x00\x00\x00\x00.\xb2jx\x00\x00\x00\x00/X\x80p\x00\x00\x00\x000\x92Lx\x00\x00\x00\x001]Lp\x00\x00\x00\x002r.x\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x10x\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xf2x\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x0e\xf8\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xa7\xe2x\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xd2\xf8\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xb4\xf8\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x96\xf8\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xb3x\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x95x\x00\x00\x00\x00D.\x95p\x00\x00\x00\x00ECwx\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Yx\x00\x00\x00\x00G\xf7\x93\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x00\x00\x95$\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\xa1\xb8\x01\x09\x00\x00\x93\xa8\x00\x0f\x00\x00\x9a\xb0\x01\x15LMT\x00AEST\x00+1130\x00+1030\x00+11\x00\x0a<+1030>-10:30<+11>-11,M10.1.0,M4.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x95\xbd\x12E\x01\x00\x00E\x01\x00\x00\x12\x00\x00\x00Australia/LindemanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffr\xed\xa2\xd4\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8b\xac\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o3\xdaR\xb4\x02\x00\x00\xb4\x02\x00\x00\x13\x00\x00\x00Australia/Lord_HoweTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x05\x00\x00\x00\x19\xff\xff\xff\xffs\x16w\xdc\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168@\xf8\x00\x00\x00\x00\x16\xe7\x8ah\x00\x00\x00\x00\x18!]x\x00\x00\x00\x00\x18\xc7lh\x00\x00\x00\x00\x1a\x01?x\x00\x00\x00\x00\x1a\xa7Nh\x00\x00\x00\x00\x1b\xe1!x\x00\x00\x00\x00\x1c\x870h\x00\x00\x00\x00\x1d\xc1\x03x\x00\x00\x00\x00\x1ey\x8ep\x00\x00\x00\x00\x1f\x97\xaa\xf8\x00\x00\x00\x00 Ypp\x00\x00\x00\x00!\x80\xc7x\x00\x00\x00\x00\x22B\x8c\xf0\x00\x00\x00\x00#i\xe3\xf8\x00\x00\x00\x00$\x22n\xf0\x00\x00\x00\x00%I\xc5\xf8\x00\x00\x00\x00%\xef\xdb\xf0\x00\x00\x00\x00')\xa7\xf8\x00\x00\x00\x00'\xcf\xbd\xf0\x00\x00\x00\x00)\x09\x89\xf8\x00\x00\x00\x00)\xaf\x9f\xf0\x00\x00\x00\x00*\xe9k\xf8\x00\x00\x00\x00+\x98\xbcp\x00\x00\x00\x00,\xd2\x88x\x00\x00\x00\x00-x\x9ep\x00\x00\x00\x00.\xb2jx\x00\x00\x00\x00/X\x80p\x00\x00\x00\x000\x92Lx\x00\x00\x00\x001]Lp\x00\x00\x00\x002r.x\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x10x\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xf2x\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x0e\xf8\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xa7\xe2x\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xd2\xf8\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xb4\xf8\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x96\xf8\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xb3x\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x95x\x00\x00\x00\x00D.\x95p\x00\x00\x00\x00ECwx\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Yx\x00\x00\x00\x00G\xf7\x93\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x00\x00\x95$\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\xa1\xb8\x01\x09\x00\x00\x93\xa8\x00\x0f\x00\x00\x9a\xb0\x01\x15LMT\x00AEST\x00+1130\x00+1030\x00+11\x00\x0a<+1030>-10:30<+11>-11,M10.1.0,M4.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xe1\xc1\xa9\x88\x03\x00\x00\x88\x03\x00\x00\x13\x00\x00\x00Australia/MelbourneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x85\x18\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x16\xe7\x9f\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!w\x94\x00\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x87\xe8\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x0d\x00\x00\x00Australia/NSWTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x7f<\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x0c\x89\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/X\x8e\x80\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8d\xc4\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8R\x1a\x1b\xea\x00\x00\x00\xea\x00\x00\x00\x0f\x00\x00\x00Australia/NorthTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x04\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x92X\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00z\xa8\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x93\xa8\x01\x09\x00\x00\x85\x98\x00\x04LMT\x00ACST\x00ACDT\x00\x0aACST-9:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xbb\xca\x1a2\x01\x00\x002\x01\x00\x00\x0f\x00\x00\x00Australia/PerthTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft\xa6\x16\xe4\xff\xff\xff\xff\x9cN\xde\xa0\xff\xff\xff\xff\x9c\xbcK \xff\xff\xff\xff\xcbT\xcf \xff\xff\xff\xff\xcb\xc7\x81\xa0\xff\xff\xff\xff\xcc\xb7r\xa0\xff\xff\xff\xff\xcd\xa7c\xa0\x00\x00\x00\x00\x09\x0f\xfb\xa0\x00\x00\x00\x00\x09\xb6\x18\xa0\x00\x00\x00\x00\x1a\x01b\xa0\x00\x00\x00\x00\x1a\xa7\x7f\xa0\x00\x00\x00\x00)%\x5c\xa0\x00\x00\x00\x00)\xaf\xca \x00\x00\x00\x00Eq\xbf \x00\x00\x00\x00F\x05g \x00\x00\x00\x00G#|\xa0\x00\x00\x00\x00G\xee\x83\xa0\x00\x00\x00\x00I\x03^\xa0\x00\x00\x00\x00I\xcee\xa0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00l\x9c\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x09LMT\x00AWDT\x00AWST\x00\x0aAWST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xba\xde\xd3!\x01\x00\x00!\x01\x00\x00\x14\x00\x00\x00Australia/QueenslandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffr\xed\x9f\x08\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8fx\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ff~\xd5\x99\x03\x00\x00\x99\x03\x00\x00\x0f\x00\x00\x00Australia/SouthTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x04\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x8b\x14\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x00\x00\x00\x00\x03p@\x88\x00\x00\x00\x00\x04\x0d#\x08\x00\x00\x00\x00\x05P\x22\x88\x00\x00\x00\x00\x05\xf6?\x88\x00\x00\x00\x00\x070\x04\x88\x00\x00\x00\x00\x07\xd6!\x88\x00\x00\x00\x00\x09\x0f\xe6\x88\x00\x00\x00\x00\x09\xb6\x03\x88\x00\x00\x00\x00\x0a\xef\xc8\x88\x00\x00\x00\x00\x0b\x9f \x08\x00\x00\x00\x00\x0c\xd8\xe5\x08\x00\x00\x00\x00\x0d\x7f\x02\x08\x00\x00\x00\x00\x0e\xb8\xc7\x08\x00\x00\x00\x00\x0f^\xe4\x08\x00\x00\x00\x00\x10\x98\xa9\x08\x00\x00\x00\x00\x11>\xc6\x08\x00\x00\x00\x00\x12x\x8b\x08\x00\x00\x00\x00\x13\x1e\xa8\x08\x00\x00\x00\x00\x14Xm\x08\x00\x00\x00\x00\x14\xfe\x8a\x08\x00\x00\x00\x00\x168O\x08\x00\x00\x00\x00\x16\xe7\xa6\x88\x00\x00\x00\x00\x18!k\x88\x00\x00\x00\x00\x18\xc7\x88\x88\x00\x00\x00\x00\x1a\x01M\x88\x00\x00\x00\x00\x1a\xa7j\x88\x00\x00\x00\x00\x1b\xe1/\x88\x00\x00\x00\x00\x1c\x87L\x88\x00\x00\x00\x00\x1d\xc1\x11\x88\x00\x00\x00\x00\x1ey\xa3\x88\x00\x00\x00\x00\x1f\x97\xb9\x08\x00\x00\x00\x00 Y\x85\x88\x00\x00\x00\x00!\x80\xd5\x88\x00\x00\x00\x00\x22B\xa2\x08\x00\x00\x00\x00#i\xf2\x08\x00\x00\x00\x00$\x22\x84\x08\x00\x00\x00\x00%I\xd4\x08\x00\x00\x00\x00&\x02f\x08\x00\x00\x00\x00')\xb6\x08\x00\x00\x00\x00'\xcf\xd3\x08\x00\x00\x00\x00)\x09\x98\x08\x00\x00\x00\x00)\xcbd\x88\x00\x00\x00\x00*\xe9z\x08\x00\x00\x00\x00+\x98\xd1\x88\x00\x00\x00\x00,\xd2\x96\x88\x00\x00\x00\x00-\x8b(\x88\x00\x00\x00\x00.\xb2x\x88\x00\x00\x00\x00/tE\x08\x00\x00\x00\x000\x92Z\x88\x00\x00\x00\x001]a\x88\x00\x00\x00\x002r<\x88\x00\x00\x00\x003=C\x88\x00\x00\x00\x004R\x1e\x88\x00\x00\x00\x005\x1d%\x88\x00\x00\x00\x0062\x00\x88\x00\x00\x00\x006\xfd\x07\x88\x00\x00\x00\x008\x1b\x1d\x08\x00\x00\x00\x008\xdc\xe9\x88\x00\x00\x00\x009\xfa\xff\x08\x00\x00\x00\x00:\xbc\xcb\x88\x00\x00\x00\x00;\xda\xe1\x08\x00\x00\x00\x00<\xa5\xe8\x08\x00\x00\x00\x00=\xba\xc3\x08\x00\x00\x00\x00>\x85\xca\x08\x00\x00\x00\x00?\x9a\xa5\x08\x00\x00\x00\x00@e\xac\x08\x00\x00\x00\x00A\x83\xc1\x88\x00\x00\x00\x00BE\x8e\x08\x00\x00\x00\x00Cc\xa3\x88\x00\x00\x00\x00D.\xaa\x88\x00\x00\x00\x00EC\x85\x88\x00\x00\x00\x00F\x05R\x08\x00\x00\x00\x00G#g\x88\x00\x00\x00\x00G\xf7\xa9\x08\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x81\xec\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x93\xa8\x01\x09\x00\x00\x85\x98\x00\x04LMT\x00ACST\x00ACDT\x00\x0aACST-9:30ACDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x10\x00\x00\x00Australia/SydneyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x7f<\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x0c\x89\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/X\x8e\x80\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8d\xc4\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x12\x00\x00\x00Australia/TasmaniaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft.\x00\xe4\xff\xff\xff\xff\x9b\xd5x\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\x9d\xdaD\x80\xff\xff\xff\xff\x9e\x80a\x80\xff\xff\xff\xff\x9f\xba&\x80\xff\xff\xff\xff\xa0`C\x80\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\xff\xff\xff\xff\xfb\xc2\x8d\x00\xff\xff\xff\xff\xfc\xb2~\x00\xff\xff\xff\xff\xfd\xc7Y\x00\xff\xff\xff\xff\xfev\xb0\x80\xff\xff\xff\xff\xff\xa7;\x00\x00\x00\x00\x00\x00V\x92\x80\x00\x00\x00\x00\x01\x87\x1d\x00\x00\x00\x00\x00\x02?\xaf\x00\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x03O\x00\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xe31\x00\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1eg'\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xed\xe1\x80\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xcd\xc3\x80\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xad\xa5\x80\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x8d\x87\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000mi\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002V\x86\x00\x00\x00\x00\x003=<\x80\x00\x00\x00\x0046h\x00\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x16J\x00\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x007\xf6,\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xbf*\x80\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\x9f\x0c\x80\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?~\xee\x80\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A^\xd0\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00C>\xb2\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00E\x1e\x94\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G\x07\xb1\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x8a\x1c\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xe1\xc1\xa9\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00Australia/VictoriaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x85\x18\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x16\xe7\x9f\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!w\x94\x00\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x87\xe8\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xbb\xca\x1a2\x01\x00\x002\x01\x00\x00\x0e\x00\x00\x00Australia/WestTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft\xa6\x16\xe4\xff\xff\xff\xff\x9cN\xde\xa0\xff\xff\xff\xff\x9c\xbcK \xff\xff\xff\xff\xcbT\xcf \xff\xff\xff\xff\xcb\xc7\x81\xa0\xff\xff\xff\xff\xcc\xb7r\xa0\xff\xff\xff\xff\xcd\xa7c\xa0\x00\x00\x00\x00\x09\x0f\xfb\xa0\x00\x00\x00\x00\x09\xb6\x18\xa0\x00\x00\x00\x00\x1a\x01b\xa0\x00\x00\x00\x00\x1a\xa7\x7f\xa0\x00\x00\x00\x00)%\x5c\xa0\x00\x00\x00\x00)\xaf\xca \x00\x00\x00\x00Eq\xbf \x00\x00\x00\x00F\x05g \x00\x00\x00\x00G#|\xa0\x00\x00\x00\x00G\xee\x83\xa0\x00\x00\x00\x00I\x03^\xa0\x00\x00\x00\x00I\xcee\xa0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00l\x9c\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x09LMT\x00AWDT\x00AWST\x00\x0aAWST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xca#\x7f\xad\x03\x00\x00\xad\x03\x00\x00\x14\x00\x00\x00Australia/YancowinnaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x00\x00\x00\x05\x00\x00\x00\x13\xff\xff\xff\xffs\x16\x88d\xff\xff\xff\xffv\x04\xa5\xe0\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x00\x00\x00\x00\x03p@\x88\x00\x00\x00\x00\x04\x0d#\x08\x00\x00\x00\x00\x05P\x22\x88\x00\x00\x00\x00\x05\xf6?\x88\x00\x00\x00\x00\x070\x04\x88\x00\x00\x00\x00\x07\xd6!\x88\x00\x00\x00\x00\x09\x0f\xe6\x88\x00\x00\x00\x00\x09\xb6\x03\x88\x00\x00\x00\x00\x0a\xef\xc8\x88\x00\x00\x00\x00\x0b\x9f \x08\x00\x00\x00\x00\x0c\xd8\xe5\x08\x00\x00\x00\x00\x0d\x7f\x02\x08\x00\x00\x00\x00\x0e\xb8\xc7\x08\x00\x00\x00\x00\x0f^\xe4\x08\x00\x00\x00\x00\x10\x98\xa9\x08\x00\x00\x00\x00\x11>\xc6\x08\x00\x00\x00\x00\x12x\x8b\x08\x00\x00\x00\x00\x13\x1e\xa8\x08\x00\x00\x00\x00\x14Xm\x08\x00\x00\x00\x00\x14\xfe\x8a\x08\x00\x00\x00\x00\x168O\x08\x00\x00\x00\x00\x17\x0c\x90\x88\x00\x00\x00\x00\x18!k\x88\x00\x00\x00\x00\x18\xc7\x88\x88\x00\x00\x00\x00\x1a\x01M\x88\x00\x00\x00\x00\x1a\xa7j\x88\x00\x00\x00\x00\x1b\xe1/\x88\x00\x00\x00\x00\x1c\x87L\x88\x00\x00\x00\x00\x1d\xc1\x11\x88\x00\x00\x00\x00\x1ey\xa3\x88\x00\x00\x00\x00\x1f\x97\xb9\x08\x00\x00\x00\x00 Y\x85\x88\x00\x00\x00\x00!\x80\xd5\x88\x00\x00\x00\x00\x22B\xa2\x08\x00\x00\x00\x00#i\xf2\x08\x00\x00\x00\x00$\x22\x84\x08\x00\x00\x00\x00%I\xd4\x08\x00\x00\x00\x00%\xef\xf1\x08\x00\x00\x00\x00')\xb6\x08\x00\x00\x00\x00'\xcf\xd3\x08\x00\x00\x00\x00)\x09\x98\x08\x00\x00\x00\x00)\xaf\xb5\x08\x00\x00\x00\x00*\xe9z\x08\x00\x00\x00\x00+\x98\xd1\x88\x00\x00\x00\x00,\xd2\x96\x88\x00\x00\x00\x00-x\xb3\x88\x00\x00\x00\x00.\xb2x\x88\x00\x00\x00\x00/X\x95\x88\x00\x00\x00\x000\x92Z\x88\x00\x00\x00\x001]a\x88\x00\x00\x00\x002r<\x88\x00\x00\x00\x003=C\x88\x00\x00\x00\x004R\x1e\x88\x00\x00\x00\x005\x1d%\x88\x00\x00\x00\x0062\x00\x88\x00\x00\x00\x006\xfd\x07\x88\x00\x00\x00\x008\x1b\x1d\x08\x00\x00\x00\x008\xdc\xe9\x88\x00\x00\x00\x009\xfa\xff\x08\x00\x00\x00\x00:\xbc\xcb\x88\x00\x00\x00\x00;\xda\xe1\x08\x00\x00\x00\x00<\xa5\xe8\x08\x00\x00\x00\x00=\xba\xc3\x08\x00\x00\x00\x00>\x85\xca\x08\x00\x00\x00\x00?\x9a\xa5\x08\x00\x00\x00\x00@e\xac\x08\x00\x00\x00\x00A\x83\xc1\x88\x00\x00\x00\x00BE\x8e\x08\x00\x00\x00\x00Cc\xa3\x88\x00\x00\x00\x00D.\xaa\x88\x00\x00\x00\x00EC\x85\x88\x00\x00\x00\x00F\x05R\x08\x00\x00\x00\x00G#g\x88\x00\x00\x00\x00G\xf7\xa9\x08\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x00\x00\x84\x9c\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00~\x90\x00\x09\x00\x00\x93\xa8\x01\x0e\x00\x00\x85\x98\x00\x09LMT\x00AEST\x00ACST\x00ACDT\x00\x0aACST-9:30ACDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x0b\x00\x00\x00Brazil/AcreTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x86\x90\xff\xff\xff\xff\xb8\x0ff\x00\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xf1PP\xff\xff\xff\xff\xba\xde\x90@\xff\xff\xff\xff\xda8\xcaP\xff\xff\xff\xff\xda\xec\x16P\xff\xff\xff\xff\xdc\x19\xfd\xd0\xff\xff\xff\xff\xdc\xb9u@\xff\xff\xff\xff\xdd\xfb1P\xff\xff\xff\xff\xde\x9b\xfa@\xff\xff\xff\xff\xdf\xdd\xb6P\xff\xff\xff\xff\xe0TO@\xff\xff\xff\xff\xf4\x98\x1b\xd0\xff\xff\xff\xff\xf5\x05z@\xff\xff\xff\xff\xf6\xc0\x80P\xff\xff\xff\xff\xf7\x0e:\xc0\xff\xff\xff\xff\xf8QHP\xff\xff\xff\xff\xf8\xc7\xe1@\xff\xff\xff\xff\xfa\x0a\xee\xd0\xff\xff\xff\xff\xfa\xa9\x14\xc0\xff\xff\xff\xff\xfb\xec\x22P\xff\xff\xff\xff\xfc\x8b\x99\xc0\x00\x00\x00\x00\x1d\xc9\xaaP\x00\x00\x00\x00\x1ex\xf3\xc0\x00\x00\x00\x00\x1f\xa0Q\xd0\x00\x00\x00\x00 3\xeb\xc0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22\x0b\xe4\xc0\x00\x00\x00\x00H`\x7fP\x00\x00\x00\x00R\x7f\x04\xc0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\xff\xff\xc0p\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x04LMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7-2f\xe4\x01\x00\x00\xe4\x01\x00\x00\x10\x00\x00\x00Brazil/DeNoronhaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaaed\xff\xff\xff\xff\xb8\x0f;\xd0\xff\xff\xff\xff\xb8\xfd2\x90\xff\xff\xff\xff\xb9\xf1& \xff\xff\xff\xff\xba\xdef\x10\xff\xff\xff\xff\xda8\xa0 \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdc\x19\xd3\xa0\xff\xff\xff\xff\xdc\xb9K\x10\xff\xff\xff\xff\xdd\xfb\x07 \xff\xff\xff\xff\xde\x9b\xd0\x10\xff\xff\xff\xff\xdf\xdd\x8c \xff\xff\xff\xff\xe0T%\x10\xff\xff\xff\xff\xf4\x97\xf1\xa0\xff\xff\xff\xff\xf5\x05P\x10\xff\xff\xff\xff\xf6\xc0V \xff\xff\xff\xff\xf7\x0e\x10\x90\xff\xff\xff\xff\xf8Q\x1e \xff\xff\xff\xff\xf8\xc7\xb7\x10\xff\xff\xff\xff\xfa\x0a\xc4\xa0\xff\xff\xff\xff\xfa\xa8\xea\x90\xff\xff\xff\xff\xfb\xeb\xf8 \xff\xff\xff\xff\xfc\x8bo\x90\x00\x00\x00\x00\x1d\xc9\x80 \x00\x00\x00\x00\x1ex\xc9\x90\x00\x00\x00\x00\x1f\xa0'\xa0\x00\x00\x00\x00 3\xc1\x90\x00\x00\x00\x00!\x81[ \x00\x00\x00\x00\x22\x0b\xba\x90\x00\x00\x00\x00#X\x02\xa0\x00\x00\x00\x00#\xe2b\x10\x00\x00\x00\x00%7\xe4\xa0\x00\x00\x00\x00%\xd4\xb9\x10\x00\x00\x00\x007\xf6\xb8\xa0\x00\x00\x00\x008\xb8w\x10\x00\x00\x00\x009\xdf\xd5 \x00\x00\x00\x009\xe9\x01\x90\x00\x00\x00\x00;\xc8\xf1\xa0\x00\x00\x00\x002\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d?\xdf\xda\xb8\x03\x00\x00\xb8\x03\x00\x00\x0b\x00\x00\x00Brazil/EastTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaar\xb4\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4Z\x090\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xbd\xe3\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\x94\x8b \x00\x00\x00\x00*\xea\x0d\xb0\x00\x00\x00\x00+k2\xa0\x00\x00\x00\x00,\xc0\xb50\x00\x00\x00\x00-f\xc4 \x00\x00\x00\x00.\xa0\x970\x00\x00\x00\x00/F\xa6 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x002W \xb0\x00\x00\x00\x003\x06j \x00\x00\x00\x0048T0\x00\x00\x00\x004\xf8\xc1 \x00\x00\x00\x006 \x1f0\x00\x00\x00\x006\xcfh\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x00:\x8f,\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x00N\xf0\xa0\x00\x00\x00\x00?\x91\xfe0\x00\x00\x00\x00@.\xd2\xa0\x00\x00\x00\x00A\x86\xf80\x00\x00\x00\x00B\x17\xef \x00\x00\x00\x00CQ\xc20\x00\x00\x00\x00C\xf7\xd1 \x00\x00\x00\x00EMS\xb0\x00\x00\x00\x00E\xe0\xed\xa0\x00\x00\x00\x00G\x11\x860\x00\x00\x00\x00G\xb7\x95 \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\x97w \x00\x00\x00\x00J\xda\x84\xb0\x00\x00\x00\x00K\x80\x93\xa0\x00\x00\x00\x00L\xbaf\xb0\x00\x00\x00\x00M`u\xa0\x00\x00\x00\x00N\x9aH\xb0\x00\x00\x00\x00OI\x92 \x00\x00\x00\x00P\x83e0\x00\x00\x00\x00Q 9\xa0\x00\x00\x00\x00RcG0\x00\x00\x00\x00S\x00\x1b\xa0\x00\x00\x00\x00TC)0\x00\x00\x00\x00T\xe98 \x00\x00\x00\x00V#\x0b0\x00\x00\x00\x00V\xc9\x1a \x00\x00\x00\x00X\x02\xed0\x00\x00\x00\x00X\xa8\xfc \x00\x00\x00\x00Y\xe2\xcf0\x00\x00\x00\x00Z\x88\xde \x00\x00\x00\x00[\xde`\xb0\x00\x00\x00\x00\x5ch\xc0 \x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xd4L\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\xcb'\xe9\x9c\x01\x00\x00\x9c\x01\x00\x00\x0b\x00\x00\x00Brazil/WestTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x7fD\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00,\xc0\xc3@\x00\x00\x00\x00-f\xd20\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc7\xbc\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x9aM\xbem\x02\x00\x00m\x02\x00\x00\x03\x00\x00\x00CETTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x02\x00\x00\x00\x09\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N@\x90\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x01\x00\x01\x00\x02\x03\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x01\x00\xff\xff\xb9\xb0\x01\x08\xff\xff\xb9\xb0\x01\x0cCDT\x00CST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00):\x17-\x88\x06\x00\x00\x88\x06\x00\x00\x0f\x00\x00\x00Canada/AtlanticTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x80\xf1\xab\xa0\xff\xff\xff\xff\x9a\xe4\xde\xc0\xff\xff\xff\xff\x9b\xd6\x130\xff\xff\xff\xff\x9e\xb8\x85`\xff\xff\xff\xff\x9f\xba\xddP\xff\xff\xff\xff\xa2\x9d\x17@\xff\xff\xff\xff\xa30\xb10\xff\xff\xff\xff\xa4zV@\xff\xff\xff\xff\xa5\x1b\x1f0\xff\xff\xff\xff\xa6S\xa0\xc0\xff\xff\xff\xff\xa6\xfcR\xb0\xff\xff\xff\xff\xa8<\xbd@\xff\xff\xff\xff\xa8\xdc4\xb0\xff\xff\xff\xff\xaa\x1c\x9f@\xff\xff\xff\xff\xaa\xcd:0\xff\xff\xff\xff\xab\xfc\x81@\xff\xff\xff\xff\xac\xbf\x910\xff\xff\xff\xff\xad\xee\xd8@\xff\xff\xff\xff\xae\x8c\xfe0\xff\xff\xff\xff\xaf\xbcE@\xff\xff\xff\xff\xb0\x7fU0\xff\xff\xff\xff\xb1\xae\x9c@\xff\xff\xff\xff\xb2Kp\xb0\xff\xff\xff\xff\xb3\x8e~@\xff\xff\xff\xff\xb4$\xbb0\xff\xff\xff\xff\xb5n`@\xff\xff\xff\xff\xb6\x15\xc0\xb0\xff\xff\xff\xff\xb7NB@\xff\xff\xff\xff\xb8\x08\x17\xb0\xff\xff\xff\xff\xb9$\xe9\xc0\xff\xff\xff\xff\xb9\xe7\xf9\xb0\xff\xff\xff\xff\xbb\x04\xcb\xc0\xff\xff\xff\xff\xbb\xd1\x160\xff\xff\xff\xff\xbd\x00]@\xff\xff\xff\xff\xbd\x9d1\xb0\xff\xff\xff\xff\xbe\xf2\xb4@\xff\xff\xff\xff\xbf\x90\xda0\xff\xff\xff\xff\xc0\xd3\xe7\xc0\xff\xff\xff\xff\xc1^G0\xff\xff\xff\xff\xc2\x8d\x8e@\xff\xff\xff\xff\xc3P\x9e0\xff\xff\xff\xff\xc4mp@\xff\xff\xff\xff\xc50\x800\xff\xff\xff\xff\xc6r<@\xff\xff\xff\xff\xc7\x10b0\xff\xff\xff\xff\xc86n\xc0\xff\xff\xff\xff\xc8\xf9~\xb0\xff\xff\xff\xff\xca\x16P\xc0\xff\xff\xff\xff\xca\xd9`\xb0\xff\xff\xff\xff\xcb\x88\xe2`\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\xff\xff\xff\xff\xd3u\xd6\xe0\xff\xff\xff\xff\xd4@\xcf\xd0\xff\xff\xff\xff\xd5U\xb8\xe0\xff\xff\xff\xff\xd6 \xb1\xd0\xff\xff\xff\xff\xd75\x9a\xe0\xff\xff\xff\xff\xd8\x00\x93\xd0\xff\xff\xff\xff\xd9\x15|\xe0\xff\xff\xff\xff\xd9\xe0u\xd0\xff\xff\xff\xff\xdc\xde{`\xff\xff\xff\xff\xdd\xa9tP\xff\xff\xff\xff\xde\xbe]`\xff\xff\xff\xff\xdf\x89VP\xff\xff\xff\xff\xe0\x9e?`\xff\xff\xff\xff\xe1i8P\xff\xff\xff\xff\xe2~!`\xff\xff\xff\xff\xe3I\x1aP\xff\xff\xff\xff\xe6G\x1f\xe0\xff\xff\xff\xff\xe7\x12\x18\xd0\xff\xff\xff\xff\xe8'\x01\xe0\xff\xff\xff\xff\xe8\xf1\xfa\xd0\xff\xff\xff\xff\xea\x06\xe3\xe0\xff\xff\xff\xff\xea\xd1\xdc\xd0\xff\xff\xff\xff\xeb\xe6\xc5\xe0\xff\xff\xff\xff\xec\xb1\xbe\xd0\xff\xff\xff\xff\xf1\x8f\xa6`\xff\xff\xff\xff\xf2\x7f\x89P\xff\xff\xff\xff\xf3o\x88`\xff\xff\xff\xff\xf4_kP\xff\xff\xff\xff\xf5Oj`\xff\xff\xff\xff\xf6?MP\xff\xff\xff\xff\xf7/L`\xff\xff\xff\xff\xf8(i\xd0\xff\xff\xff\xff\xf9\x0f.`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xf8J\xe0\xff\xff\xff\xff\xfb\xe8-\xd0\xff\xff\xff\xff\xfc\xd8,\xe0\xff\xff\xff\xff\xfd\xc8\x0f\xd0\xff\xff\xff\xff\xfe\xb8\x0e\xe0\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00\x97\xf0\xe0\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x02w\xd2\xe0\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x06@\xd1`\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xc4`\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00ADT\x00AST\x00AWT\x00APT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x0e\x00\x00\x00Canada/CentralTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffd\xe4\xb0\x94\xff\xff\xff\xff\x9b\x01\xfb\xe0\xff\xff\xff\xff\x9b\xc3\xbaP\xff\xff\xff\xff\x9e\xb8\xa1\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xc2\xa0;\x80\xff\xff\xff\xff\xc3O\x84\xf0\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3\x88h\x00\xff\xff\xff\xff\xd4S`\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xdb\x00\x07\x00\xff\xff\xff\xff\xdb\xc8\x5c\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf41b\xf0\xff\xff\xff\xff\xf9\x0fJ\x80\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xcf\x80\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xb1\x80\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xa4\xec\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00CDT\x00CST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0e\x00\x00\x00Canada/EasternTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x0f\x00\x00\x00Canada/MountainTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x88\xde\xce\xe0\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x98\x91\x90\xff\xff\xff\xff\xa0\xd2\x85\x80\xff\xff\xff\xff\xa2\x8a\xe8\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4j\xca\x90\xff\xff\xff\xff\xa55\xc3\x80\xff\xff\xff\xff\xa6S\xe7\x10\xff\xff\xff\xff\xa7\x15\xa5\x80\xff\xff\xff\xff\xa83\xc9\x10\xff\xff\xff\xff\xa8\xfe\xc2\x00\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xdd\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xbf\x90\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x95\xa0\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeah\x06\xd2V\x07\x00\x00V\x07\x00\x00\x13\x00\x00\x00Canada/NewfoundlandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\x00\x00\x00\x08\x00\x00\x00\x19\xff\xff\xff\xff^=4\xec\xff\xff\xff\xff\x9c\xcfb\x0c\xff\xff\xff\xff\x9d\xa4\xe6\xfc\xff\xff\xff\xff\x9e\xb8~\x8c\xff\xff\xff\xff\x9f\xba\xd6|\xff\xff\xff\xff\xa0\xb6\x88\xdc\xff\xff\xff\xff\xa18\xffL\xff\xff\xff\xff\xa2\x95\x19\x5c\xff\xff\xff\xff\xa3\x84\xfcL\xff\xff\xff\xff\xa4t\xfb\x5c\xff\xff\xff\xff\xa5d\xdeL\xff\xff\xff\xff\xa6^\x17\xdc\xff\xff\xff\xff\xa7D\xc0L\xff\xff\xff\xff\xa8=\xf9\xdc\xff\xff\xff\xff\xa9$\xa2L\xff\xff\xff\xff\xaa\x1d\xdb\xdc\xff\xff\xff\xff\xab\x04\x84L\xff\xff\xff\xff\xab\xfd\xbd\xdc\xff\xff\xff\xff\xac\xe4fL\xff\xff\xff\xff\xad\xdd\x9f\xdc\xff\xff\xff\xff\xae\xcd\x82\xcc\xff\xff\xff\xff\xaf\xbd\x81\xdc\xff\xff\xff\xff\xb0\xadd\xcc\xff\xff\xff\xff\xb1\xa6\x9e\x5c\xff\xff\xff\xff\xb2\x8dF\xcc\xff\xff\xff\xff\xb3\x86\x80\x5c\xff\xff\xff\xff\xb4m(\xcc\xff\xff\xff\xff\xb5fb\x5c\xff\xff\xff\xff\xb6M\x0a\xcc\xff\xff\xff\xff\xb7FD\x5c\xff\xff\xff\xff\xb8,\xec\xcc\xff\xff\xff\xff\xb9&&\x5c\xff\xff\xff\xff\xba\x16\x09L\xff\xff\xff\xff\xbb\x0fB\xdc\xff\xff\xff\xff\xbb\xf5\xebL\xff\xff\xff\xff\xbc\xef$\xdc\xff\xff\xff\xff\xbd\xd5\xcdL\xff\xff\xff\xff\xbe\x9eMl\xff\xff\xff\xff\xbe\xcf\x06\xa8\xff\xff\xff\xff\xbf\xb5\xaf\x18\xff\xff\xff\xff\xc0\xb818\xff\xff\xff\xff\xc1y\xef\xa8\xff\xff\xff\xff\xc2\x98\x138\xff\xff\xff\xff\xc3Y\xd1\xa8\xff\xff\xff\xff\xc4w\xf58\xff\xff\xff\xff\xc59\xb3\xa8\xff\xff\xff\xff\xc6a\x11\xb8\xff\xff\xff\xff\xc7\x19\x95\xa8\xff\xff\xff\xff\xc8@\xf3\xb8\xff\xff\xff\xff\xc9\x02\xb2(\xff\xff\xff\xff\xca \xd5\xb8\xff\xff\xff\xff\xca\xe2\x94(\xff\xff\xff\xff\xcc\x00\xb7\xb8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xe6\xc8\xff\xff\xff\xff\xd3\x88D\xd8\xff\xff\xff\xff\xd4J\x03H\xff\xff\xff\xff\xd5h&\xd8\xff\xff\xff\xff\xd6)\xe5H\xff\xff\xff\xff\xd7H\x08\xd8\xff\xff\xff\xff\xd8\x09\xc7H\xff\xff\xff\xff\xd9'\xea\xd8\xff\xff\xff\xff\xd9\xe9\xa9H\xff\xff\xff\xff\xdb\x11\x07X\xff\xff\xff\xff\xdb\xd2\xc5\xc8\xff\xff\xff\xff\xdc\xdetX\xff\xff\xff\xff\xdd\xa9mH\xff\xff\xff\xff\xde\xbeVX\xff\xff\xff\xff\xdf\x89OH\xff\xff\xff\xff\xe0\x9e8X\xff\xff\xff\xff\xe1i1H\xff\xff\xff\xff\xe2~\x1aX\xff\xff\xff\xff\xe3I\x13H\xff\xff\xff\xff\xe4]\xfcX\xff\xff\xff\xff\xe5(\xf5H\xff\xff\xff\xff\xe6G\x18\xd8\xff\xff\xff\xff\xe7\x12\x11\xc8\xff\xff\xff\xff\xe8&\xfa\xd8\xff\xff\xff\xff\xe8\xf1\xf3\xc8\xff\xff\xff\xff\xea\x06\xdc\xd8\xff\xff\xff\xff\xea\xd1\xd5\xc8\xff\xff\xff\xff\xeb\xe6\xbe\xd8\xff\xff\xff\xff\xec\xb1\xb7\xc8\xff\xff\xff\xff\xed\xc6\xa0\xd8\xff\xff\xff\xff\xee\xbf\xbeH\xff\xff\xff\xff\xef\xaf\xbdX\xff\xff\xff\xff\xf0\x9f\xa0H\xff\xff\xff\xff\xf1\x8f\x9fX\xff\xff\xff\xff\xf2\x7f\x82H\xff\xff\xff\xff\xf3o\x81X\xff\xff\xff\xff\xf4_dH\xff\xff\xff\xff\xf5OcX\xff\xff\xff\xff\xf6?FH\xff\xff\xff\xff\xf7/EX\xff\xff\xff\xff\xf8(b\xc8\xff\xff\xff\xff\xf9\x0f'X\xff\xff\xff\xff\xfa\x08D\xc8\xff\xff\xff\xff\xfa\xf8C\xd8\xff\xff\xff\xff\xfb\xe8&\xc8\xff\xff\xff\xff\xfc\xd8%\xd8\xff\xff\xff\xff\xfd\xc8\x08\xc8\xff\xff\xff\xff\xfe\xb8\x07\xd8\xff\xff\xff\xff\xff\xa7\xea\xc8\x00\x00\x00\x00\x00\x97\xe9\xd8\x00\x00\x00\x00\x01\x87\xcc\xc8\x00\x00\x00\x00\x02w\xcb\xd8\x00\x00\x00\x00\x03p\xe9H\x00\x00\x00\x00\x04`\xe8X\x00\x00\x00\x00\x05P\xcbH\x00\x00\x00\x00\x06@\xcaX\x00\x00\x00\x00\x070\xadH\x00\x00\x00\x00\x08 \xacX\x00\x00\x00\x00\x09\x10\x8fH\x00\x00\x00\x00\x0a\x00\x8eX\x00\x00\x00\x00\x0a\xf0qH\x00\x00\x00\x00\x0b\xe0pX\x00\x00\x00\x00\x0c\xd9\x8d\xc8\x00\x00\x00\x00\x0d\xc0RX\x00\x00\x00\x00\x0e\xb9o\xc8\x00\x00\x00\x00\x0f\xa9n\xd8\x00\x00\x00\x00\x10\x99Q\xc8\x00\x00\x00\x00\x11\x89P\xd8\x00\x00\x00\x00\x12y3\xc8\x00\x00\x00\x00\x13i2\xd8\x00\x00\x00\x00\x14Y\x15\xc8\x00\x00\x00\x00\x15I\x14\xd8\x00\x00\x00\x00\x168\xf7\xc8\x00\x00\x00\x00\x17(\xf6\xd8\x00\x00\x00\x00\x18\x22\x14H\x00\x00\x00\x00\x19\x08\xd8\xd8\x00\x00\x00\x00\x1a\x01\xf6H\x00\x00\x00\x00\x1a\xf1\xf5X\x00\x00\x00\x00\x1b\xe1\xd8H\x00\x00\x00\x00\x1c\xd1\xd7X\x00\x00\x00\x00\x1d\xc1\xbaH\x00\x00\x00\x00\x1e\xb1\xb9X\x00\x00\x00\x00\x1f\xa1\x9cH\x00\x00\x00\x00 u\xcf\xf4\x00\x00\x00\x00!\x81bd\x00\x00\x00\x00\x22U\xb1\xf4\x00\x00\x00\x00#jp\xd4\x00\x00\x00\x00$5\x93\xf4\x00\x00\x00\x00%J`\xe4\x00\x00\x00\x00&\x15u\xf4\x00\x00\x00\x00'*B\xe4\x00\x00\x00\x00'\xfe\x92t\x00\x00\x00\x00)\x0a$\xe4\x00\x00\x00\x00)\xdett\x00\x00\x00\x00*\xea\x06\xe4\x00\x00\x00\x00+\xbeVt\x00\x00\x00\x00,\xd3#d\x00\x00\x00\x00-\x9e8t\x00\x00\x00\x00.\xb3\x05d\x00\x00\x00\x00/~\x1at\x00\x00\x00\x000\x92\xe7d\x00\x00\x00\x001g6\xf4\x00\x00\x00\x002r\xc9d\x00\x00\x00\x003G\x18\xf4\x00\x00\x00\x004R\xabd\x00\x00\x00\x005&\xfa\xf4\x00\x00\x00\x0062\x8dd\x00\x00\x00\x007\x06\xdc\xf4\x00\x00\x00\x008\x1b\xa9\xe4\x00\x00\x00\x008\xe6\xbe\xf4\x00\x00\x00\x009\xfb\x8b\xe4\x00\x00\x00\x00:\xc6\xa0\xf4\x00\x00\x00\x00;\xdbm\xe4\x00\x00\x00\x00<\xaf\xbdt\x00\x00\x00\x00=\xbbO\xe4\x00\x00\x00\x00>\x8f\x9ft\x00\x00\x00\x00?\x9b1\xe4\x00\x00\x00\x00@o\x81t\x00\x00\x00\x00A\x84Nd\x00\x00\x00\x00BOct\x00\x00\x00\x00Cd0d\x00\x00\x00\x00D/Et\x00\x00\x00\x00ED\x12d\x00\x00\x00\x00E\xf3w\xf4\x00\x00\x00\x00G-.\xe4\x00\x00\x00\x00G\xd3Y\xf4\x00\x00\x00\x00I\x0d\x10\xe4\x00\x00\x00\x00I\xb3;\xf4\x00\x00\x00\x00J\xec\xf2\xe4\x00\x00\x00\x00K\x9cXt\x00\x00\x00\x00L\xd6\x0fd\x00\x00\x00\x00M|:t\x00\x00\x00\x00N\xafY\xa8\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x05\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x07\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x03\xff\xff\xce\x94\x00\x00\xff\xff\xdc\xa4\x01\x04\xff\xff\xce\x94\x00\x08\xff\xff\xdc\xd8\x01\x04\xff\xff\xce\xc8\x00\x08\xff\xff\xdc\xd8\x01\x0c\xff\xff\xdc\xd8\x01\x10\xff\xff\xea\xe8\x01\x14LMT\x00NDT\x00NST\x00NPT\x00NWT\x00NDDT\x00\x0aNST3:30NDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U9#\xbe2\x05\x00\x002\x05\x00\x00\x0e\x00\x00\x00Canada/PacificTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^=v\xec\xff\xff\xff\xff\x9e\xb8\xbd\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd3v\x0f \xff\xff\xff\xff\xd4A\x08\x10\xff\xff\xff\xff\xd5U\xf1 \xff\xff\xff\xff\xd6 \xea\x10\xff\xff\xff\xff\xd75\xd3 \xff\xff\xff\xff\xd8\x00\xcc\x10\xff\xff\xff\xff\xd9\x15\xb5 \xff\xff\xff\xff\xd9\xe0\xae\x10\xff\xff\xff\xff\xda\xfe\xd1\xa0\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xb3\xa0\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x95\xa0\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ew\xa0\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~Y\xa0\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^;\xa0\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GX \xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8': \xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x1c \xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xfe \xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xe0 \xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xfc\xa0\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xde\xa0\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xc0\xa0\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\xa2\xa0\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/\x84\xa0\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0ff\xa0\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x08 \xeb\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x0a\x00\xcd\xa0\x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x8c\x94\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10LMT\x00PDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x96dK~\x02\x00\x00~\x02\x00\x00\x13\x00\x00\x00Canada/SaskatchewanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x86\xfd\x93\x1c\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xb5eO\xf0\xff\xff\xff\xff\xb60H\xe0\xff\xff\xff\xff\xb7E1\xf0\xff\xff\xff\xff\xb8\x10*\xe0\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xf0\x0c\xe0\xff\xff\xff\xff\xbb\x0e0p\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xee\x12p\xff\xff\xff\xff\xbd\xb9\x0b`\xff\xff\xff\xff\xc2r\x08\xf0\xff\xff\xff\xff\xc3a\xeb\xe0\xff\xff\xff\xff\xc4Q\xea\xf0\xff\xff\xff\xff\xc58\x93`\xff\xff\xff\xff\xc61\xcc\xf0\xff\xff\xff\xff\xc7!\xaf\xe0\xff\xff\xff\xff\xc8\x1a\xe9p\xff\xff\xff\xff\xc9\x0a\xcc`\xff\xff\xff\xff\xc9\xfa\xcbp\xff\xff\xff\xff\xca\xea\xae`\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd3c\x8c\x10\xff\xff\xff\xff\xd4So\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\xff\xff\xff\xff\xd75\xc5\x10\xff\xff\xff\xff\xd8\x00\xbe\x00\xff\xff\xff\xff\xd9\x15\xa7\x10\xff\xff\xff\xff\xd9\xe0\xa0\x00\xff\xff\xff\xff\xda\xfe\xc3\x90\xff\xff\xff\xff\xdb\xc0\x82\x00\xff\xff\xff\xff\xdc\xde\xa5\x90\xff\xff\xff\xff\xdd\xa9\x9e\x80\xff\xff\xff\xff\xde\xbe\x87\x90\xff\xff\xff\xff\xdf\x89\x80\x80\xff\xff\xff\xff\xe0\x9ei\x90\xff\xff\xff\xff\xe1ib\x80\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3ID\x80\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)&\x80\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12C\x00\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf2%\x00\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xd6\xd3\x00\xff\xff\xff\xff\xed\xc6\xd2\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\xff\xff\x9d\xe4\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xab\xa0\x00\x14LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x1d\xee\x91\x05\x04\x00\x00\x05\x04\x00\x00\x0c\x00\x00\x00Canada/YukonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x09\x00\x00\x00%\xff\xff\xff\xff}\x86\x8a\x9c\xff\xff\xff\xff\x9e\xb8\xcb\xb0\xff\xff\xff\xff\x9f\xbb#\xa0\xff\xff\xff\xff\xa0\xd0\x0c\xb0\xff\xff\xff\xff\xa1\xa2\xd2\x80\xff\xff\xff\xff\xcb\x89(\xb0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a4 \xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf8\xc5\x84\x90\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x00\x00\x00\x00G-\x8a\x10\x00\x00\x00\x00G\xd3\xb5 \x00\x00\x00\x00I\x0dl\x10\x00\x00\x00\x00I\xb3\x97 \x00\x00\x00\x00J\xedN\x10\x00\x00\x00\x00K\x9c\xb3\xa0\x00\x00\x00\x00L\xd6j\x90\x00\x00\x00\x00M|\x95\xa0\x00\x00\x00\x00N\xb6L\x90\x00\x00\x00\x00O\x5cw\xa0\x00\x00\x00\x00P\x96.\x90\x00\x00\x00\x00QO@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00Y\x17\xc80\x00\x00\x00\x00Y\x8f\xce\xc0\x00\x00\x00\x00Z\xf7\xaa0\x00\x00\x00\x00[o\xb0\xc0\x00\x00\x00\x00\x5c\xa9g\xb0\x00\x00\x00\x00]t|\xc0\x00\x00\x00\x00^\x89I\xb0\x00\x00\x00\x00_T^\xc0\x00\x00\x00\x00`i+\xb0\x00\x00\x00\x00a4@\xc0\x00\x00\x00\x00bI\x0d\xb0\x00\x00\x00\x00c\x1d]@\x00\x00\x00\x00d(\xef\xb0\x01\x02\x01\x03\x01\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x03\x02\x03\x05\x04\x02\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\xff\xff\xbd\xbb\x00\x00\xff\xff\xbd\xbb\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xc7\xc0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00SMT\x00-05\x00-04\x00-03\x00\x0a<-04>4<-03>,M9.1.6/24,M4.1.6/24\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?X'\x8e\x96\x04\x00\x00\x96\x04\x00\x00\x12\x00\x00\x00Chile/EasterIslandTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffi\x87B\x08\xff\xff\xff\xff\xb9\xc7@\x88\xff\xff\xff\xff\xfd\xd1<@\xff\xff\xff\xff\xfe\x92\xfa\xb0\xff\xff\xff\xff\xff\xcc\xcd\xc0\x00\x00\x00\x00\x00r\xdc\xb0\x00\x00\x00\x00\x01uP\xc0\x00\x00\x00\x00\x02@I\xb0\x00\x00\x00\x00\x03U2\xc0\x00\x00\x00\x00\x04 +\xb0\x00\x00\x00\x00\x05>O@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00Y\x17\xc80\x00\x00\x00\x00Y\x8f\xce\xc0\x00\x00\x00\x00Z\xf7\xaa0\x00\x00\x00\x00[o\xb0\xc0\x00\x00\x00\x00\x5c\xa9g\xb0\x00\x00\x00\x00]t|\xc0\x00\x00\x00\x00^\x89I\xb0\x00\x00\x00\x00_T^\xc0\x00\x00\x00\x00`i+\xb0\x00\x00\x00\x00a4@\xc0\x00\x00\x00\x00bI\x0d\xb0\x00\x00\x00\x00c\x1d]@\x00\x00\x00\x00d(\xef\xb0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\xff\xff\x99x\x00\x00\xff\xff\x99x\x00\x04\xff\xff\xab\xa0\x01\x08\xff\xff\x9d\x90\x00\x0c\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x10LMT\x00EMT\x00-06\x00-07\x00-05\x00\x0a<-06>6<-05>,M9.1.6/22,M4.1.6/22\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x1c\x9e\x9a]\x04\x00\x00]\x04\x00\x00\x04\x00\x00\x00CubaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87(\xb8\xff\xff\xff\xff\xacb\xc2\x80\xff\xff\xff\xff\xb1\xd3\x94P\xff\xff\xff\xff\xb2t]@\xff\xff\xff\xff\xc8[f\xd0\xff\xff\xff\xff\xc8\xd3Q@\xff\xff\xff\xff\xca;H\xd0\xff\xff\xff\xff\xca\xbcm\xc0\xff\xff\xff\xff\xcc$eP\xff\xff\xff\xff\xcc\x9cO\xc0\xff\xff\xff\xff\xd1\xc4\x0bP\xff\xff\xff\xff\xd2;\xf5\xc0\xff\xff\xff\xff\xd3\xa3\xedP\xff\xff\xff\xff\xd4\x1b\xd7\xc0\xff\xff\xff\xff\xf7`\x05\xd0\xff\xff\xff\xff\xf7\xff}@\xff\xff\xff\xff\xf9=D\xd0\xff\xff\xff\xff\xf9\xe3S\xc0\xff\xff\xff\xff\xfa\xdb;\xd0\xff\xff\xff\xff\xfb\xa7\x86@\xff\xff\xff\xff\xfc\xc5\xa9\xd0\xff\xff\xff\xff\xfd\x87h@\xff\xff\xff\xff\xfe\xb8\x00\xd0\xff\xff\xff\xff\xff\xa7\xe3\xc0\x00\x00\x00\x00\x00\x97\xe2\xd0\x00\x00\x00\x00\x01\x87\xc5\xc0\x00\x00\x00\x00\x02w\xc4\xd0\x00\x00\x00\x00\x03p\xe2@\x00\x00\x00\x00\x04`\xe1P\x00\x00\x00\x00\x055\x14\xc0\x00\x00\x00\x00\x06@\xc3P\x00\x00\x00\x00\x07\x16H@\x00\x00\x00\x00\x08 \xa5P\x00\x00\x00\x00\x08\xf7{\xc0\x00\x00\x00\x00\x0a\x00\x87P\x00\x00\x00\x00\x0a\xf0j@\x00\x00\x00\x00\x0b\xe0iP\x00\x00\x00\x00\x0c\xd9\x86\xc0\x00\x00\x00\x00\x0d\xc0KP\x00\x00\x00\x00\x0e\xb9h\xc0\x00\x00\x00\x00\x0f\xb2\xa2P\x00\x00\x00\x00\x10}\x9b@\x00\x00\x00\x00\x11Q\xea\xd0\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x131\xcc\xd0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15[\x82\xd0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x17;d\xd0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x19\x1bF\xd0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xfb(\xd0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\xdb\x0a\xd0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ezSP\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 Z5P\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x22CQ\xd0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$#3\xd0\x00\x00\x00\x00%.\xc6@\x00\x00\x00\x00&\x15\x8a\xd0\x00\x00\x00\x00'\x17\xe2\xc0\x00\x00\x00\x00'\xfe\xa7P\x00\x00\x00\x00(\xf7\xd2\xd0\x00\x00\x00\x00)\xde\x89P\x00\x00\x00\x00*\xd7\xb4\xd0\x00\x00\x00\x00+\xbekP\x00\x00\x00\x00,\xb7\x96\xd0\x00\x00\x00\x00-\x9eMP\x00\x00\x00\x00.\x97x\xd0\x00\x00\x00\x00/~/P\x00\x00\x00\x000wZ\xd0\x00\x00\x00\x001gK\xd0\x00\x00\x00\x002W<\xd0\x00\x00\x00\x003G-\xd0\x00\x00\x00\x004@YP\x00\x00\x00\x005\x1d\xd5P\x00\x00\x00\x0062\xb0P\x00\x00\x00\x006\xfd\xb7P\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xd3\xd0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xb5\xd0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xd2P\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xb4P\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@f[\xd0\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x8c\xd0\x00\x00\x00\x00G$\x17P\x00\x00\x00\x00G\xdc\xa9P\x00\x00\x00\x00I\x03\xf9P\x00\x00\x00\x00I\xb3P\xd0\x00\x00\x00\x00J\xe3\xdbP\x00\x00\x00\x00K\x9cmP\x00\x00\x00\x00L\xcc\xf7\xd0\x00\x00\x00\x00M\x85\x89\xd0\x00\x00\x00\x00N\xbfN\xd0\x00\x00\x00\x00Ow\xe0\xd0\x00\x00\x00\x00P\x95\xf6P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xb2\xc8\x00\x00\xff\xff\xb2\xc0\x00\x04\xff\xff\xc7\xc0\x01\x08\xff\xff\xb9\xb0\x00\x0cLMT\x00HMT\x00CDT\x00CST\x00\x0aCST5CDT,M3.2.0/0,M11.1.0/1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`l\x8d~\xf1\x01\x00\x00\xf1\x01\x00\x00\x03\x00\x00\x00EETTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x02\x00\x00\x00\x09\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x01\x00\x01\x00\x02\x03\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\xff\xff\xb9\xb0\x00\x04\xff\xff\xc7\xc0\x01\x00\xff\xff\xc7\xc0\x01\x08\xff\xff\xc7\xc0\x01\x0cEDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5#)\x16\x1d\x05\x00\x00\x1d\x05\x00\x00\x05\x00\x00\x00EgyptTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff}\xbdM\xab\xff\xff\xff\xff\xc8\x93\xb4\xe0\xff\xff\xff\xff\xc8\xfa{\xd0\xff\xff\xff\xff\xc9\xfc\xef\xe0\xff\xff\xff\xff\xca\xc7\xe8\xd0\xff\xff\xff\xff\xcb\xcb\xae`\xff\xff\xff\xff\xcc\xdf)\xd0\xff\xff\xff\xff\xcd\xac\xe1\xe0\xff\xff\xff\xff\xce\xc6\xf4\xd0\xff\xff\xff\xff\xcf\x8ff\xe0\xff\xff\xff\xff\xd0\xa9y\xd0\xff\xff\xff\xff\xd1\x84`\xe0\xff\xff\xff\xff\xd2\x8a\xadP\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\x7f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xff\xef\xb0\xb3p\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb\xc2\xfd\x80\xff\xff\xff\xff\xfc\xdb\xbe\xf0\xff\xff\xff\xff\xfd\xa5\x82\x80\xff\xff\xff\xff\xfe\xbc\xf2p\xff\xff\xff\xff\xff\x86\xb6\x00\x00\x00\x00\x00\x00\x9e%\xf0\x00\x00\x00\x00\x01g\xe9\x80\x00\x00\x00\x00\x02\x7fYp\x00\x00\x00\x00\x03I\x1d\x00\x00\x00\x00\x00\x04a\xdep\x00\x00\x00\x00\x05+\xa2\x00\x00\x00\x00\x00\x06C\x11\xf0\x00\x00\x00\x00\x07\x0c\xd5\x80\x00\x00\x00\x00\x08$Ep\x00\x00\x00\x00\x08\xee\x09\x00\x00\x00\x00\x00\x0a\x05x\xf0\x00\x00\x00\x00\x0a\xcf<\x80\x00\x00\x00\x00\x0b\xe7\xfd\xf0\x00\x00\x00\x00\x0c\xb1\xc1\x80\x00\x00\x00\x00\x0d\xc91p\x00\x00\x00\x00\x0e\x92\xf5\x00\x00\x00\x00\x00\x0f\xaad\xf0\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11\x8b\x98p\x00\x00\x00\x00\x12U\x5c\x00\x00\x00\x00\x00\x13n\x1dp\x00\x00\x00\x00\x147\xe1\x00\x00\x00\x00\x00\x15OP\xf0\x00\x00\x00\x00\x16\x19\x14\x80\x00\x00\x00\x00\x17\xa0\x93\xf0\x00\x00\x00\x00\x17\xfaH\x00\x00\x00\x00\x00\x19p\xa3\xf0\x00\x00\x00\x00\x19\xdb{\x80\x00\x00\x00\x00\x1a\xf4<\xf0\x00\x00\x00\x00\x1b\xbe\x00\x80\x00\x00\x00\x00\x1c\xd5pp\x00\x00\x00\x00\x1d\x9f4\x00\x00\x00\x00\x00\x1e\xb6\xa3\xf0\x00\x00\x00\x00\x1f\x80g\x80\x00\x00\x00\x00 \x97\xd7p\x00\x00\x00\x00!a\x9b\x00\x00\x00\x00\x00\x22z\x5cp\x00\x00\x00\x00#D \x00\x00\x00\x00\x00$b'p\x00\x00\x00\x00%%S\x80\x00\x00\x00\x00&<\xc3p\x00\x00\x00\x00'\x06\x87\x00\x00\x00\x00\x00(\x1d\xf6\xf0\x00\x00\x00\x00(\xe7\xba\x80\x00\x00\x00\x00*\x00{\xf0\x00\x00\x00\x00*\xca?\x80\x00\x00\x00\x00+\xe1\xafp\x00\x00\x00\x00,\xabs\x00\x00\x00\x00\x00-\xc2\xe2\xf0\x00\x00\x00\x00.\x8c\xa6\x80\x00\x00\x00\x00/\xa0\x13\xe0\x00\x00\x00\x000k\x0c\xd0\x00\x00\x00\x001\x7f\xf5\xe0\x00\x00\x00\x002J\xee\xd0\x00\x00\x00\x003_\xd7\xe0\x00\x00\x00\x004*\xd0\xd0\x00\x00\x00\x005?\xb9\xe0\x00\x00\x00\x006\x0a\xb2\xd0\x00\x00\x00\x007(\xd6`\x00\x00\x00\x007\xf3\xcfP\x00\x00\x00\x009\x08\xb8`\x00\x00\x00\x009\xd3\xb1P\x00\x00\x00\x00:\xe8\x9a`\x00\x00\x00\x00;\xb3\x93P\x00\x00\x00\x00<\xc8|`\x00\x00\x00\x00=\x93uP\x00\x00\x00\x00>\xa8^`\x00\x00\x00\x00?sWP\x00\x00\x00\x00@\x91z\xe0\x00\x00\x00\x00A\x5cs\xd0\x00\x00\x00\x00Bq\x5c\xe0\x00\x00\x00\x00C\xe0\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F1 \xe0\x00\x00\x00\x00F\xe0jP\x00\x00\x00\x00H\x11\x02\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xf0\xe4\xe0\x00\x00\x00\x00J\x8d\xb9P\x00\x00\x00\x00K\xda\x01`\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00L\x89X\xe0\x00\x00\x00\x00L\xa4\xfaP\x00\x00\x00\x00Su8\xe0\x00\x00\x00\x00S\xac\x89\xd0\x00\x00\x00\x00S\xda\xbc`\x00\x00\x00\x00T$\x82P\x00\x00\x00\x00dJ\xf0`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x1dU\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M4.5.5/0,M10.5.4/24\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\xd6jL\xd8\x05\x00\x00\xd8\x05\x00\x00\x04\x00\x00\x00EireTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\x00\x00\x00\x08\x00\x00\x00\x14\xff\xff\xff\xffW\xd1\x0a\xf1\xff\xff\xff\xff\x9b&\xb3\x91\xff\xff\xff\xff\x9b\xd6\x0b\x11\xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba \xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c \xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb \xff\xff\xff\xff\xa6%` \xff\xff\xff\xff\xa7'\xc6 \xff\xff\xff\xff\xa8*, \xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15 \xff\xff\xff\xff\xab\xe9\xf0 \xff\xff\xff\xff\xac\xc7l \xff\xff\xff\xff\xad\xc9\xd2 \xff\xff\xff\xff\xae\xa7N \xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870 \xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00 \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xdbW \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2z\xfd \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xd4I\xe0 \xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd6N\xac \xff\xff\xff\xff\xd7,( \xff\xff\xff\xff\xd8.\x8e \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xda\x0ep \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce \xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16 \xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt \xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad \xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xfdq \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xddS \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f} \xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_ \xff\xff\xff\xff\xf3Jf \xff\xff\xff\xff\xf4_A \xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?# \xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05 \xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7 \xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6 \x00\x00\x00\x00\x04)X \x00\x00\x00\x00\x05P\xa8 \x00\x00\x00\x00\x06\x09: \x00\x00\x00\x00\x070\x8a \x00\x00\x00\x00\x07\xe9\x1c \x00\x00\x00\x00\x09\x10l \x00\x00\x00\x00\x09\xc8\xfe \x00\x00\x00\x00\x0a\xf0N \x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00 \x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12 \x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\x0a\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x001]\xd9\x10\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\xff\xff\xfa\x0f\x00\x00\xff\xff\xfa\x0f\x00\x04\x00\x00\x08\x1f\x01\x08\x00\x00\x0e\x10\x01\x0c\x00\x00\x00\x00\x00\x10\x00\x00\x0e\x10\x01\x08\x00\x00\x00\x00\x01\x10\x00\x00\x0e\x10\x00\x08LMT\x00DMT\x00IST\x00BST\x00GMT\x00\x0aIST-1GMT0,M10.5.0,M3.5.0/1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x07\x00\x00\x00Etc/GMTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00Etc/GMT+0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\xb8\xe8\x86q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+1TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xf1\xf0\x00\x00-01\x00\x0a<-01>1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8e\x1569r\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00Etc/GMT+10TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xffs`\x00\x00-10\x00\x0a<-10>10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\xb9\xbe\x9dr\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00Etc/GMT+11TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xffeP\x00\x00-11\x00\x0a<-11>11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\xf38cr\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00Etc/GMT+12TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xffW@\x00\x00-12\x00\x0a<-12>12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9{\xa2qq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+2TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xe3\xe0\x00\x00-02\x00\x0a<-02>2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\xcb\xe9Qq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+3TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xd5\xd0\x00\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\xfaFDq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+4TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xc7\xc0\x00\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4X\x9b\xf3q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+5TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xb9\xb0\x00\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x9b\xd1\x04q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+6TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xab\xa0\x00\x00-06\x00\x0a<-06>6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84+\x9a$q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+7TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\x9d\x90\x00\x00-07\x00\x0a<-07>7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\xf8\x8f/q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+8TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\x8f\x80\x00\x00-08\x00\x0a<-08>8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84\x19\xb3\x09q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+9TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\x81p\x00\x00-09\x00\x0a<-09>9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00Etc/GMT-0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\x1ac\xc3r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-1TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x0e\x10\x00\x00+01\x00\x0a<+01>-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9|\xbd7s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-10TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x8c\xa0\x00\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xab\xd1Is\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-11TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x9a\xb0\x00\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\x19s\x81s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-12TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\xa8\xc0\x00\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90`N\xe8s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-13TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\xb6\xd0\x00\x00+13\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,{\xdc;s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-14TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\xc4\xe0\x00\x00+14\x00\x0a<+14>-14\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbc\x19y\x04r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-2TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x1c \x00\x00+02\x00\x0a<+02>-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9c\xfcm\x99r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-3TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00*0\x00\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k\x19-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xd6~wr\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-5TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00FP\x00\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j\xd5d\xb0r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-6TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00T`\x00\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00J0p-r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-7TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00bp\x00\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x18\xb6\xfbr\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-8TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00p\x80\x00\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc\x19@\xb9r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-9TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00~\x90\x00\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x08\x00\x00\x00Etc/GMT0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x0d\x00\x00\x00Etc/GreenwichTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x07\x00\x00\x00Etc/UCTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x07\x00\x00\x00Etc/UTCTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x0d\x00\x00\x00Etc/UniversalTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x08\x00\x00\x00Etc/ZuluTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o\xbc\x831O\x04\x00\x00O\x04\x00\x00\x10\x00\x00\x00Europe/AmsterdamTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xffV\xb6\xdf\xe6\xff\xff\xff\xffm\xe8\xc8\x00\xff\xff\xff\xff\x98DI\x80\xff\xff\xff\xff\x9b\x0c%p\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\x9f\xce\xf80\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1~\xbbp\xff\xff\xff\xff\xa2.\x12\xf0\xff\xff\xff\xff\xa3zL\xf0\xff\xff\xff\xff\xa45\x81\xf0\xff\xff\xff\xff\xa5^#p\xff\xff\xff\xff\xa6%5\xf0\xff\xff\xff\xff\xa7'\x9b\xf0\xff\xff\xff\xff\xa8*\x01\xf0\xff\xff\xff\xff\xa9\x07}\xf0\xff\xff\xff\xff\xa9\xee4p\xff\xff\xff\xff\xaa\xe7_\xf0\xff\xff\xff\xff\xab\xd7P\xf0\xff\xff\xff\xff\xac\xc7A\xf0\xff\xff\xff\xff\xad\xc9\xa7\xf0\xff\xff\xff\xff\xae\xa7#\xf0\xff\xff\xff\xff\xaf\xa0Op\xff\xff\xff\xff\xb0\x87\x05\xf0\xff\xff\xff\xff\xb1\x89k\xf0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb8\xff\xe3\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xd6\x8b \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xc8\xe2 \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\x9f\x89\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2h\x88 \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4?/\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xc8J\x19 \xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N@\x90\xff\xff\xff\xff\xd3\x91@\x10\xff\xff\xff\xff\xd4K#\x90\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x00\x00\x00\x00V\xf7\x14p\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00-\x0c\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0cLMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcb*j\x8f\xaa\x02\x00\x00\xaa\x02\x00\x00\x0d\x00\x00\x00Europe/AthensTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xfft?\x98D\xff\xff\xff\xff\x9b\x80!\x80\xff\xff\xff\xff\xb9|\xe9\xe0\xff\xff\xff\xff\xb9\xc6\xaf\xd0\xff\xff\xff\xff\xc9\xf2c\xe0\xff\xff\xff\xff\xca\x10\xa8P\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xaaL\xf0\xff\xff\xff\xff\xce\xa2\x18\xe0\xff\xff\xff\xff\xcf\x93ip\xff\xff\xff\xff\xdf\x13\x9e`\xff\xff\xff\xff\xdf\xb7\x0aP\x00\x00\x00\x00\x09\xec^`\x00\x00\x00\x00\x0b\x18\xf4`\x00\x00\x00\x00\x0b\xcd\xae\x00\x00\x00\x00\x00\x0c\xbd\x9f\x00\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\x8c]\x80\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x10j\xfc\x10\x00\x00\x00\x00\x11d{\xf0\x00\x00\x00\x00\x12R\xaa\xf0\x00\x00\x00\x00\x13F\x82`\x00\x00\x00\x00\x143\xc2P\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xf3`\xff\xff\xff\xff\xb9\xef\x9c`\xff\xff\xff\xff\xba\xdf\x8d`\xff\xff\xff\xff\xbb\xcf~`\xff\xff\xff\xff\xbc\xc8\xa9\xe0\xff\xff\xff\xff\xbd\xb8\x9a\xe0\xff\xff\xff\xff\xbe\xa8\x8b\xe0\xff\xff\xff\xff\xbf\x98|\xe0\xff\xff\xff\xff\xc0\x88m\xe0\xff\xff\xff\xff\xc1x^\xe0\xff\xff\xff\xff\xc2hO\xe0\xff\xff\xff\xff\xc3X@\xe0\xff\xff\xff\xff\xc4H1\xe0\xff\xff\xff\xff\xc58\x22\xe0\xff\xff\xff\xff\xc6(\x13\xe0\xff\xff\xff\xff\xc7\x18\x04\xe0\x00\x00\x00\x00\x11\xad\xd1`\x00\x00\x00\x00\x12S\xe0P\x00\x00\x00\x00\x13M\x0b\xd0\x00\x00\x00\x00\x143\xd0`\x00\x00\x00\x00\x15#\xdd\x80\x00\x00\x00\x00\x16\x13\xce\x80\x00\x00\x00\x00\x17\x03\xbf\x80\x00\x00\x00\x00\x17\xf3\xb0\x80\x00\x00\x00\x00\x18\xe3\xa1\x80\x00\x00\x00\x00\x19\xd3\x92\x80\x00\x00\x00\x00\x1a\xc3\x83\x80\x00\x00\x00\x00\x1b\xbc\xaf\x00\x00\x00\x00\x00\x1c\xac\xa0\x00\x00\x00\x00\x00\x1d\x9c\x91\x00\x00\x00\x00\x00\x1e\x8c\x82\x00\x00\x00\x00\x00\x1f|s\x00\x00\x00\x00\x00 ld\x00\x00\x00\x00\x00!\x5cU\x00\x00\x00\x00\x00\x22LF\x00\x00\x00\x00\x00#<7\x00\x00\x00\x00\x00$,(\x00\x00\x00\x00\x00%\x1c\x19\x00\x00\x00\x00\x00&\x0c\x0a\x00\x00\x00\x00\x00'\x055\x80\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xdd`\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xbf`\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x002\xc9\x8c\xe0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x03\x00\x00\x18x\x00\x00\x00\x00\x18x\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0dLMT\x00BMT\x00EEST\x00EET\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6Kf\xab\xfe\x02\x00\x00\xfe\x02\x00\x00\x0f\x00\x00\x00Europe/BudapestTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffk\x17\x91\x9c\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xa0\x9a\xc4\x10\xff\xff\xff\xff\xa1dy\x90\xff\xff\xff\xff\xa2p\x1a\x10\xff\xff\xff\xff\xa3M\x96\x10\xff\xff\xff\xff\xc9\xf3\xb5`\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1\x99x\xe0\xff\xff\xff\xff\xd2\x8a\xc9p\xff\xff\xff\xff\xd3P\xa6\x90\xff\xff\xff\xff\xd4K\x15\x80\xff\xff\xff\xff\xd59\xc3\x10\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7\x19\xa5\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\xff\xff\xff\xff\xe2\xa2\xa8\xf0\xff\xff\xff\xff\xe3Q\xf2`\xff\xff\xff\xff\xe4\x82\xa7\x10\xff\xff\xff\xff\xe51\xfe\x90\xff\xff\xff\xff\xe6t\xfe\x10\xff\xff\xff\xff\xe7\x11\xe0\x90\xff\xff\xff\xff\xe8T\xe0\x10\xff\xff\xff\xff\xe8\xf1\xc2\x90\x00\x00\x00\x00\x13M'\xf0\x00\x00\x00\x00\x143\xdep\x00\x00\x00\x00\x15#\xcfp\x00\x00\x00\x00\x16\x13\xc0p\x00\x00\x00\x00\x17\x03\xb1p\x00\x00\x00\x00\x17\xf3\xa2p\x00\x00\x00\x00\x18\xe3\x93p\x00\x00\x00\x00\x19\xd3\x84p\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xf3`\xff\xff\xff\xff\xb9\xef\x9c`\xff\xff\xff\xff\xba\xdf\x8d`\xff\xff\xff\xff\xbb\xcf~`\xff\xff\xff\xff\xbc\xc8\xa9\xe0\xff\xff\xff\xff\xbd\xb8\x9a\xe0\xff\xff\xff\xff\xbe\xa8\x8b\xe0\xff\xff\xff\xff\xbf\x98|\xe0\xff\xff\xff\xff\xc0\x88m\xe0\xff\xff\xff\xff\xc1x^\xe0\xff\xff\xff\xff\xc2hO\xe0\xff\xff\xff\xff\xc3X@\xe0\xff\xff\xff\xff\xc4H1\xe0\xff\xff\xff\xff\xc58\x22\xe0\xff\xff\xff\xff\xc6(\x13\xe0\xff\xff\xff\xff\xc7\x18\x04\xe0\xff\xff\xff\xff\xc8\xbc\x93`\xff\xff\xff\xff\xcaw}P\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0N\x90`\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&CL\xe0\x00\x00\x00\x00'\x055\x80\x00\x00\x00\x00'\xf5&\x80\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x002\xc9\x8c\xe0\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x06\x05\x06\x05\x06\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x04\x00\x00\x1b\x08\x00\x00\x00\x00\x1a\xf4\x00\x04\x00\x00\x18x\x00\x08\x00\x00*0\x01\x0c\x00\x00\x1c \x00\x11\x00\x00\x0e\x10\x00\x15\x00\x00\x1c \x01\x19\x00\x008@\x01\x1e\x00\x00*0\x00\x22LMT\x00CMT\x00BMT\x00EEST\x00EET\x00CET\x00CEST\x00MSD\x00MSK\x00\x0aEET-2EEST,M3.5.0,M10.5.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x11\x00\x00\x00Europe/CopenhagenTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xb6\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xff\xd2\xa1O\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xff\xd5\xa8s\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#P\xff\xff\xff\xff\xf1\xf4\xb9`\xff\xff\xff\xff\xf4b\xefP\xff\xff\xff\xff\xf5h\x06`\xff\xff\xff\xff\xf6\x1f8\xd0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x079\x9ap\x00\x00\x00\x00\x07\xfbu\x00\x00\x00\x00\x00\x09\x19|p\x00\x00\x00\x00\x09\xd0\xcb\x00\x00\x00\x00\x00\x0a\xf9^p\x00\x00\x00\x00\x0b\xb1\xfe\x80\x00\x00\x00\x00\x0c\xd9@p\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\xa6\xadp\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x0f\xf8\x11P\x00\x00\x00\x00\x19\x89\xb0p\x00\x00\x00\x00\x19\xdc\xb0\xe0\x00\x00\x00\x00\x1b\xe6\xd0\xf0\x00\x00\x00\x00\x1c\xc6\xef\xf0\x00\x00\x00\x00\x1d\x9b1p\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x8b\x83\xf0\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8f\xdd\x90\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S8\xbe\x10\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V>\x9e\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00W\xcf.P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x00\x00\x1b(\x00\x00\x00\x00\x1bh\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0d\x00\x00*0\x00\x11\x00\x008@\x01\x15LMT\x00IMT\x00EEST\x00EET\x00+03\x00+04\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x0d\x00\x00\x00Europe/JerseyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x00\x00\x00\x05\x00\x00\x00\x11\xff\xff\xff\xff\x1a]\x09\xcb\xff\xff\xff\xff\x9b&\xad\xa0\xff\xff\xff\xff\x9b\xd6\x05 \xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba \xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c \xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb \xff\xff\xff\xff\xa6%` \xff\xff\xff\xff\xa7'\xc6 \xff\xff\xff\xff\xa8*, \xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15 \xff\xff\xff\xff\xab\xe9\xf0 \xff\xff\xff\xff\xac\xc7l \xff\xff\xff\xff\xad\xc9\xd2 \xff\xff\xff\xff\xae\xa7N \xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870 \xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00 \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xdbW \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2z\xfd \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xca\x16&\x90\xff\xff\xff\xff\xca\x97Y\x90\xff\xff\xff\xff\xcb\xd1\x1e\x90\xff\xff\xff\xff\xccw;\x90\xff\xff\xff\xff\xcd\xb1\x00\x90\xff\xff\xff\xff\xce`X\x10\xff\xff\xff\xff\xcf\x90\xe2\x90\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xfb2\x10\xff\xff\xff\xff\xd2i\xfe \xff\xff\xff\xff\xd3c)\xa0\xff\xff\xff\xff\xd4I\xe0 \xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd5B\xfd\x90\xff\xff\xff\xff\xd5\xdf\xe0\x10\xff\xff\xff\xff\xd6N\xac \xff\xff\xff\xff\xd6\xfe\x03\xa0\xff\xff\xff\xff\xd8.\x8e \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xda\x0ep \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce \xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16 \xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt \xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad \xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xfdq \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xddS \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f} \xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_ \xff\xff\xff\xff\xf3Jf \xff\xff\xff\xff\xf4_A \xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?# \xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05 \xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7 \xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6 \x00\x00\x00\x00\x04)X \x00\x00\x00\x00\x05P\xa8 \x00\x00\x00\x00\x06\x09: \x00\x00\x00\x00\x070\x8a \x00\x00\x00\x00\x07\xe9\x1c \x00\x00\x00\x00\x09\x10l \x00\x00\x00\x00\x09\xc8\xfe \x00\x00\x00\x00\x0a\xf0N \x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00 \x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12 \x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\x0a\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x000\xe7$\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x02\xff\xff\xff\xb5\x00\x00\x00\x00\x0e\x10\x01\x04\x00\x00\x00\x00\x00\x08\x00\x00\x1c \x01\x0c\x00\x00\x0e\x10\x00\x04LMT\x00BST\x00GMT\x00BDST\x00\x0aGMT0BST,M3.5.0/1,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O+j\x94\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00Europe/KaliningradTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x08\x00\x00\x00\x22\xff\xff\xff\xffo\xa2[H\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1|w\xe0\xff\xff\xff\xff\xd1\x95\x84`\xff\xff\xff\xff\xd2\x8a\xadP\xff\xff\xff\xff\xd3Y\xb6\xe0\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x19\x00\x00\x00\x00\x00&\x0c\x0a\x00\x00\x00\x00\x00'\x055\x80\x00\x00\x00\x00'\xf5&\x80\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00.\x84\xbd\x80\x00\x00\x00\x00/t\xae\x80\x00\x00\x00\x000d\x9f\x80\x00\x00\x00\x001]\xcb\x00\x00\x00\x00\x002r\xa6\x00\x00\x00\x00\x003=\xad\x00\x00\x00\x00\x004R\x88\x00\x00\x00\x00\x005\x1d\x8f\x00\x00\x00\x00\x0062j\x00\x00\x00\x00\x006\xfdq\x00\x00\x00\x00\x008\x1b\x86\x80\x00\x00\x00\x008\xddS\x00\x00\x00\x00\x009\xfbh\x80\x00\x00\x00\x00:\xbd5\x00\x00\x00\x00\x00;\xdbJ\x80\x00\x00\x00\x00<\xa6Q\x80\x00\x00\x00\x00=\xbb,\x80\x00\x00\x00\x00>\x863\x80\x00\x00\x00\x00?\x9b\x0e\x80\x00\x00\x00\x00@f\x15\x80\x00\x00\x00\x00A\x84+\x00\x00\x00\x00\x00BE\xf7\x80\x00\x00\x00\x00Cd\x0d\x00\x00\x00\x00\x00D%\xd9\x80\x00\x00\x00\x00EC\xef\x00\x00\x00\x00\x00F\x05\xbb\x80\x00\x00\x00\x00G#\xd1\x00\x00\x00\x00\x00G\xee\xd8\x00\x00\x00\x00\x00I\x03\xb3\x00\x00\x00\x00\x00I\xce\xba\x00\x00\x00\x00\x00J\xe3\x95\x00\x00\x00\x00\x00K\xae\x9c\x00\x00\x00\x00\x00L\xcc\xb1\x80\x00\x00\x00\x00M\x8e~\x00\x00\x00\x00\x00TL+p\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x07\x04\x00\x00\x138\x00\x00\x00\x00\x1c \x01\x04\x00\x00\x0e\x10\x00\x09\x00\x00*0\x01\x0d\x00\x00\x1c \x00\x12\x00\x008@\x01\x16\x00\x00*0\x00\x1a\x00\x00*0\x00\x1eLMT\x00CEST\x00CET\x00EEST\x00EET\x00MSD\x00MSK\x00+03\x00\x0aEET-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x81\xbf~.\x02\x00\x00.\x02\x00\x00\x0b\x00\x00\x00Europe/KievTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x08\x00\x00\x00\x22\xff\xff\xff\xffV\xb6\xc7d\xff\xff\xff\xff\xaa\x19\xa7d\xff\xff\xff\xff\xb5\xa4\x19`\xff\xff\xff\xff\xca\xcd.\xd0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xce\xcd\xa8p\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&\x8d \xe0\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00.\x84\xbd\x80\x00\x00\x00\x00/t\xae\x80\x00\x00\x00\x000d\x9f\x80\x00\x00\x00\x001]\xcb\x00\x00\x00\x00\x001\x96QP\x01\x02\x03\x05\x04\x05\x04\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x07\x00\x00\x1c\x9c\x00\x00\x00\x00\x1c\x9c\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1dLMT\x00KMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f(NN\xdf\x02\x00\x00\xdf\x02\x00\x00\x0c\x00\x00\x00Europe/KirovTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x07\x00\x00\x00\x18\xff\xff\xff\xff\xa1\x009\x80\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x05\x04\x05\x03\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x06\x05\x00\x00.\x98\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x10\x00\x00*0\x00\x14\x00\x008@\x00\x14LMT\x00+03\x00+05\x00+04\x00MSD\x00MSK\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x81\xbf~.\x02\x00\x00.\x02\x00\x00\x0b\x00\x00\x00Europe/KyivTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x08\x00\x00\x00\x22\xff\xff\xff\xffV\xb6\xc7d\xff\xff\xff\xff\xaa\x19\xa7d\xff\xff\xff\xff\xb5\xa4\x19`\xff\xff\xff\xff\xca\xcd.\xd0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xce\xcd\xa8p\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&\x8d \xe0\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00.\x84\xbd\x80\x00\x00\x00\x00/t\xae\x80\x00\x00\x00\x000d\x9f\x80\x00\x00\x00\x001]\xcb\x00\x00\x00\x00\x001\x96QP\x01\x02\x03\x05\x04\x05\x04\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x07\x00\x00\x1c\x9c\x00\x00\x00\x00\x1c\x9c\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1dLMT\x00KMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&S\x03\x09\xae\x05\x00\x00\xae\x05\x00\x00\x0d\x00\x00\x00Europe/LisbonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8d\x00\x00\x00\x06\x00\x00\x00\x1b\xff\xff\xff\xff^=\x0c\x1d\xff\xff\xff\xff\x92\xe6\x8e\x80\xff\xff\xff\xff\x9bKmp\xff\xff\xff\xff\x9b\xfe\xc7\x80\xff\xff\xff\xff\x9c\x9c\xedp\xff\xff\xff\xff\x9d\xc9\x83p\xff\xff\xff\xff\x9e\x7frp\xff\xff\xff\xff\x9f\xaa\xb6\xf0\xff\xff\xff\xff\xa0_Tp\xff\xff\xff\xff\xa1\x8b\xeap\xff\xff\xff\xff\xa2A\xd9p\xff\xff\xff\xff\xa3nop\xff\xff\xff\xff\xa4#\x0c\xf0\xff\xff\xff\xff\xa5O\xa2\xf0\xff\xff\xff\xff\xaa\x05\xefp\xff\xff\xff\xff\xaa\xf4\x8e\xf0\xff\xff\xff\xff\xad\xc9\xa7\xf0\xff\xff\xff\xff\xae\xa7#\xf0\xff\xff\xff\xff\xaf\xa0Op\xff\xff\xff\xff\xb0\x87\x05\xf0\xff\xff\xff\xff\xb1\x89k\xf0\xff\xff\xff\xff\xb2p\x22p\xff\xff\xff\xff\xb3r\x88p\xff\xff\xff\xff\xb4P\x04p\xff\xff\xff\xff\xb72Lp\xff\xff\xff\xff\xb8\x0f\xc8p\xff\xff\xff\xff\xb8\xff\xb9p\xff\xff\xff\xff\xb9\xef\xaap\xff\xff\xff\xff\xbc\xc8\xb7\xf0\xff\xff\xff\xff\xbd\xb8\xa8\xf0\xff\xff\xff\xff\xbe\x9f_p\xff\xff\xff\xff\xbf\x98\x8a\xf0\xff\xff\xff\xff\xc0\x9a\xf0\xf0\xff\xff\xff\xff\xc1xl\xf0\xff\xff\xff\xff\xc2h]\xf0\xff\xff\xff\xff\xc3XN\xf0\xff\xff\xff\xff\xc4?\x05p\xff\xff\xff\xff\xc580\xf0\xff\xff\xff\xff\xc6:\x96\xf0\xff\xff\xff\xff\xc7X\xacp\xff\xff\xff\xff\xc7\xd9\xdfp\xff\xff\xff\xff\xc9\x01/p\xff\xff\xff\xff\xc9\xf1 p\xff\xff\xff\xff\xca\xe2b\xf0\xff\xff\xff\xff\xcb\xb5R\xf0\xff\xff\xff\xff\xcb\xec\xa3\xe0\xff\xff\xff\xff\xcc\x80K\xe0\xff\xff\xff\xff\xcc\xdc\xa2\xf0\xff\xff\xff\xff\xcd\x954\xf0\xff\xff\xff\xff\xcd\xc3K`\xff\xff\xff\xff\xcer\xa2\xe0\xff\xff\xff\xff\xce\xc5\xbfp\xff\xff\xff\xff\xcfu\x16\xf0\xff\xff\xff\xff\xcf\xacg\xe0\xff\xff\xff\xff\xd0R\x84\xe0\xff\xff\xff\xff\xd0\xa5\xa1p\xff\xff\xff\xff\xd1T\xf8\xf0\xff\xff\xff\xff\xd1\x8cI\xe0\xff\xff\xff\xff\xd22f\xe0\xff\xff\xff\xff\xd2\x85\x83p\xff\xff\xff\xff\xd3Y\xc4\xf0\xff\xff\xff\xff\xd4I\xb5\xf0\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd6)\xc2 \xff\xff\xff\xff\xd7\x19\xb3 \xff\xff\xff\xff\xd8\x09\xa4 \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xd9\xe9\x86 \xff\xff\xff\xff\xda\xd9w \xff\xff\xff\xff\xdb\xc9h \xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xb2\x84\xa0\xff\xff\xff\xff\xde\xa2u\xa0\xff\xff\xff\xff\xdf\x92f\xa0\xff\xff\xff\xff\xe0\x82W\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2b9\xa0\xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4B\x1b\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6!\xfd\xa0\xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x0b\x1a \xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xea\xfc \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xca\xde \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xaa\xc0 \xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x8a\xa2 \xff\xff\xff\xff\xf0z\x93 \xff\xff\xff\xff\xf1j\x84 \xff\xff\xff\xff\xf2c\xaf\xa0\xff\xff\xff\xff\xf3S\xa0\xa0\xff\xff\xff\xff\xf4C\x91\xa0\xff\xff\xff\xff\xf53\x82\xa0\xff\xff\xff\xff\xf6#s\xa0\xff\xff\xff\xff\xf7\x13d\xa0\xff\xff\xff\xff\xf8\x03U\xa0\xff\xff\xff\xff\xf8\xf3F\xa0\x00\x00\x00\x00\x0c\xab*\x00\x00\x00\x00\x00\x0d\x9b\x1b\x00\x00\x00\x00\x00\x0e\x8b\x0c\x00\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11d\x19\x80\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13C\xfb\x80\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xbd\xa0\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#1\x90\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd5\x1d\xf7p\xff\xff\xff\xff\xd6)\x97\xf0\xff\xff\xff\xff\xd6\xeb\x80\x90\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xf93\xb5\xf0\xff\xff\xff\xff\xf9\xd9\xc4\xe0\xff\xff\xff\xff\xfb\x1c\xd2p\xff\xff\xff\xff\xfb\xb9\xb4\xf0\xff\xff\xff\xff\xfc\xfc\xb4p\xff\xff\xff\xff\xfd\x99\x96\xf0\xff\xff\xff\xff\xfe\xe5\xd0\xf0\xff\xff\xff\xff\xff\x82\xb3p\x00\x00\x00\x00\x00\xc5\xb2\xf0\x00\x00\x00\x00\x01b\x95p\x00\x00\x00\x00\x02\x9cZp\x00\x00\x00\x00\x03Bwp\x00\x00\x00\x00\x04\x85v\xf0\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06\x1a3p\x00\x00\x00\x00\x07\x0a$p\x00\x00\x00\x00\x08\x17\x16p\x00\x00\x00\x00\x08\xda4p\x00\x00\x00\x00\x09\xf7\x14\x90\x00\x00\x00\x00\x0a\xc2\x0d\x80\x00\x00\x00\x00\x0b\xd6\xf6\x90\x00\x00\x00\x00\x0c\xa1\xef\x80\x00\x00\x00\x00\x0d\xb6\xd8\x90\x00\x00\x00\x00\x0e\x81\xd1\x80\x00\x00\x00\x00\x0f\x96\xba\x90\x00\x00\x00\x00\x10a\xb3\x80\x00\x00\x00\x00\x11v\x9c\x90\x00\x00\x00\x00\x12A\x95\x80\x00\x00\x00\x00\x13E[\x10\x00\x00\x00\x00\x14*\xb2\x00\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x863\x80\x00\x00\x00\x00?\x9b\x0e\x80\x00\x00\x00\x00@f\x15\x80\x00\x00\x00\x00A\x84+\x00\x00\x00\x00\x00BE\xf7\x80\x00\x00\x00\x00Cd\x0d\x00\x00\x00\x00\x00D%\xd9\x80\x00\x00\x00\x00EC\xef\x00\x00\x00\x00\x00F\x05\xbb\x80\x00\x00\x00\x00G#\xd1\x00\x00\x00\x00\x00G\xee\xd8\x00\x00\x00\x00\x00I\x03\xb3\x00\x00\x00\x00\x00I\xce\xba\x00\x00\x00\x00\x00J\xe3\x95\x00\x00\x00\x00\x00K\xae\x9c\x00\x00\x00\x00\x00L\xcc\xb1\x80\x00\x00\x00\x00M\x8e~\x00\x01\x02\x03\x05\x04\x05\x04\x05\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x08\x00\x00\x19\xd8\x00\x00\x00\x00\x19\xc8\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1d\x00\x00*0\x00\x22LMT\x00MMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\xf5\x94\xdaQ\x04\x00\x00Q\x04\x00\x00\x0d\x00\x00\x00Europe/MonacoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x00\x00\x00\x07\x00\x00\x00\x1f\xff\xff\xff\xffk\xc9\x9b\xcf\xff\xff\xff\xff\x91`PO\xff\xff\xff\xff\x9bGx\xf0\xff\xff\xff\xff\x9b\xd7,p\xff\xff\xff\xff\x9c\xbc\x91p\xff\xff\xff\xff\x9d\xc0H\xf0\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0*\xf0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1\x80\x0c\xf0\xff\xff\xff\xff\xa2.\x12\xf0\xff\xff\xff\xff\xa3zL\xf0\xff\xff\xff\xff\xa45\x81\xf0\xff\xff\xff\xff\xa5^#p\xff\xff\xff\xff\xa6%5\xf0\xff\xff\xff\xff\xa7'\x9b\xf0\xff\xff\xff\xff\xa8X&p\xff\xff\xff\xff\xa9\x07}\xf0\xff\xff\xff\xff\xa9\xee4p\xff\xff\xff\xff\xaa\xe7_\xf0\xff\xff\xff\xff\xab\xd7P\xf0\xff\xff\xff\xff\xac\xc7A\xf0\xff\xff\xff\xff\xad\xc9\xa7\xf0\xff\xff\xff\xff\xae\xa7#\xf0\xff\xff\xff\xff\xaf\xa0Op\xff\xff\xff\xff\xb0\x87\x05\xf0\xff\xff\xff\xff\xb1\x89k\xf0\xff\xff\xff\xff\xb2p\x22p\xff\xff\xff\xff\xb3r\x88p\xff\xff\xff\xff\xb4P\x04p\xff\xff\xff\xff\xb5I/\xf0\xff\xff\xff\xff\xb6/\xe6p\xff\xff\xff\xff\xb72Lp\xff\xff\xff\xff\xb8\x0f\xc8p\xff\xff\xff\xff\xb8\xff\xb9p\xff\xff\xff\xff\xb9\xef\xaap\xff\xff\xff\xff\xba\xd6`\xf0\xff\xff\xff\xff\xbb\xd8\xc6\xf0\xff\xff\xff\xff\xbc\xc8\xb7\xf0\xff\xff\xff\xff\xbd\xb8\xa8\xf0\xff\xff\xff\xff\xbe\x9f_p\xff\xff\xff\xff\xbf\x98\x8a\xf0\xff\xff\xff\xff\xc0\x9a\xf0\xf0\xff\xff\xff\xff\xc1xl\xf0\xff\xff\xff\xff\xc2h]\xf0\xff\xff\xff\xff\xc3XN\xf0\xff\xff\xff\xff\xc4?\x05p\xff\xff\xff\xff\xc580\xf0\xff\xff\xff\xff\xc6:\x96\xf0\xff\xff\xff\xff\xc7X\xacp\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xc8l'\xe0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0O\xe1\xe0\xff\xff\xff\xff\xd0\x89\xf1\xf0\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N@\x90\x00\x00\x00\x00\x0b\xbb9\x00\x00\x00\x00\x00\x0c\xab\x1b\xf0\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xf2y\xff\xff\xff\xff\x9e*\xee\xf9\xff\xff\xff\xff\x9e\xf79i\xff\xff\xff\xff\x9f\x84W\xf9\xff\xff\xff\xff\xa0\xd8l\xe9\xff\xff\xff\xff\xa1\x009\x80\xff\xff\xff\xff\xa1<\xa6@\xff\xff\xff\xff\xa4\x10m\xc0\xff\xff\xff\xff\xa4=2\xb0\xff\xff\xff\xff\xa5\x15h\xb0\xff\xff\xff\xff\xa5=\x03\xc0\xff\xff\xff\xff\xa7\x1eEP\xff\xff\xff\xff\xb5\xa4\x19`\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)x\xbf\x80\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x01\x03\x02\x03\x04\x02\x04\x05\x06\x05\x07\x05\x06\x08\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x09\x08\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x0a\x06\x00\x00#9\x00\x00\x00\x00#9\x00\x04\x00\x001\x87\x01\x08\x00\x00#w\x00\x04\x00\x00?\x97\x01\x0c\x00\x008@\x01\x11\x00\x00*0\x00\x15\x00\x00FP\x01\x19\x00\x00\x1c \x00\x1d\x00\x00*0\x01!\x00\x008@\x00\x15LMT\x00MMT\x00MST\x00MDST\x00MSD\x00MSK\x00+05\x00EET\x00EEST\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1eX\xc3aU\x02\x00\x00U\x02\x00\x00\x0e\x00\x00\x00Europe/NicosiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff\xa5w\x1e\xb8\x00\x00\x00\x00\x09\xed\xaf\xe0\x00\x00\x00\x00\x0a\xdd\x92\xd0\x00\x00\x00\x00\x0b\xfad\xe0\x00\x00\x00\x00\x0c\xbe\xc6P\x00\x00\x00\x00\x0d\xa49`\x00\x00\x00\x00\x0e\x8a\xe1\xd0\x00\x00\x00\x00\x0f\x84\x1b`\x00\x00\x00\x00\x10uO\xd0\x00\x00\x00\x00\x11c\xfd`\x00\x00\x00\x00\x12S\xe0P\x00\x00\x00\x00\x13M\x19\xe0\x00\x00\x00\x00\x143\xc2P\x00\x00\x00\x00\x15#\xc1`\x00\x00\x00\x00\x16\x13\xa4P\x00\x00\x00\x00\x17\x03\xa3`\x00\x00\x00\x00\x17\xf3\x86P\x00\x00\x00\x00\x18\xe3\x85`\x00\x00\x00\x00\x19\xd3hP\x00\x00\x00\x00\x1a\xc3g`\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002M\x91\xd0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004-s\xd0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x005\xeb\x0e\xd0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x01\x00\x00\x1fH\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x0b\x00\x00\x00Europe/OsloTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xb6\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xff\xd2\xa1O\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xff\xd5\xa8s\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#(\xe8L\xff\xff\xff\xffp\xbc\x81p\xff\xff\xff\xff\x9b8\xf8p\xff\xff\xff\xff\x9b\xd5\xcc\xe0\xff\xff\xff\xff\x9c\xc5\xcb\xf0\xff\xff\xff\xff\x9d\xb7\x00`\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0\x1c\xe0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1~\xad`\xff\xff\xff\xff\xa2\x5c7p\xff\xff\xff\xff\xa3L\x1a`\xff\xff\xff\xff\xc8l5\xf0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2L\xd2\xf0\xff\xff\xff\xff\xd3>1\x90\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd5\x1d\xf7p\xff\xff\xff\xff\xd6)\x97\xf0\xff\xff\xff\xff\xd6\xeb\x80\x90\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xf93\xb5\xf0\xff\xff\xff\xff\xf9\xd9\xc4\xe0\xff\xff\xff\xff\xfb\x1c\xd2p\xff\xff\xff\xff\xfb\xb9\xb4\xf0\xff\xff\xff\xff\xfc\xfc\xb4p\xff\xff\xff\xff\xfd\x99\x96\xf0\xff\xff\xff\xff\xfe\xe5\xd0\xf0\xff\xff\xff\xff\xff\x82\xb3p\x00\x00\x00\x00\x00\xc5\xb2\xf0\x00\x00\x00\x00\x01b\x95p\x00\x00\x00\x00\x02\x9cZp\x00\x00\x00\x00\x03Bwp\x00\x00\x00\x00\x04\x85v\xf0\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x07\x0bu\xf0\x00\x00\x00\x00\x08E:\xf0\x00\x00\x00\x00\x08\xebW\xf0\x00\x00\x00\x00\x0a.Wp\x00\x00\x00\x00\x0a\xcb9\xf0\x00\x00\x00\x00\x0c\x0e9p\x00\x00\x00\x00\x0c\xab\x1b\xf0\x00\x00\x00\x00\x0d\xe4\xe0\xf0\x00\x00\x00\x00\x0e\x8a\xfd\xf0\x00\x00\x00\x00\x0f\xcd\xfdp\x00\x00\x00\x00\x10t\x1ap\x00\x00\x00\x00\x11\xad\xdfp\x00\x00\x00\x00\x12S\xfcp\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x00\x00\x00\x00BE\xdb`\x00\x00\x00\x00Cc\xf0\xe0\x00\x00\x00\x00D%\xbd`\x00\x00\x00\x00EC\xd2\xe0\x00\x00\x00\x00F\x05\x9f`\x00\x00\x00\x00G#\xb4\xe0\x00\x00\x00\x00G\xee\xbb\xe0\x00\x00\x00\x00I\x03\x96\xe0\x00\x00\x00\x00I\xce\x9d\xe0\x00\x00\x00\x00J\xe3x\xe0\x00\x00\x00\x00K\xae\x7f\xe0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x01\x04\x01\x05\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x01\x02\x00\x00.\xf4\x00\x00\x00\x00*0\x00\x04\x00\x008@\x00\x08\x00\x00FP\x01\x0c\x00\x008@\x01\x08\x00\x00*0\x01\x04LMT\x00+03\x00+04\x00+05\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95\xb4\x9e\xe7\xb3\x03\x00\x00\xb3\x03\x00\x00\x11\x00\x00\x00Europe/San_MarinoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff>(\xe8L\xff\xff\xff\xffp\xbc\x81p\xff\xff\xff\xff\x9b8\xf8p\xff\xff\xff\xff\x9b\xd5\xcc\xe0\xff\xff\xff\xff\x9c\xc5\xcb\xf0\xff\xff\xff\xff\x9d\xb7\x00`\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0\x1c\xe0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1~\xad`\xff\xff\xff\xff\xa2\x5c7p\xff\xff\xff\xff\xa3L\x1a`\xff\xff\xff\xff\xc8l5\xf0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2L\xd2\xf0\xff\xff\xff\xff\xd3>1\x90\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd5\x1d\xf7p\xff\xff\xff\xff\xd6)\x97\xf0\xff\xff\xff\xff\xd6\xeb\x80\x90\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xf93\xb5\xf0\xff\xff\xff\xff\xf9\xd9\xc4\xe0\xff\xff\xff\xff\xfb\x1c\xd2p\xff\xff\xff\xff\xfb\xb9\xb4\xf0\xff\xff\xff\xff\xfc\xfc\xb4p\xff\xff\xff\xff\xfd\x99\x96\xf0\xff\xff\xff\xff\xfe\xe5\xd0\xf0\xff\xff\xff\xff\xff\x82\xb3p\x00\x00\x00\x00\x00\xc5\xb2\xf0\x00\x00\x00\x00\x01b\x95p\x00\x00\x00\x00\x02\x9cZp\x00\x00\x00\x00\x03Bwp\x00\x00\x00\x00\x04\x85v\xf0\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x07\x0bu\xf0\x00\x00\x00\x00\x08E:\xf0\x00\x00\x00\x00\x08\xebW\xf0\x00\x00\x00\x00\x0a.Wp\x00\x00\x00\x00\x0a\xcb9\xf0\x00\x00\x00\x00\x0c\x0e9p\x00\x00\x00\x00\x0c\xab\x1b\xf0\x00\x00\x00\x00\x0d\xe4\xe0\xf0\x00\x00\x00\x00\x0e\x8a\xfd\xf0\x00\x00\x00\x00\x0f\xcd\xfdp\x00\x00\x00\x00\x10t\x1ap\x00\x00\x00\x00\x11\xad\xdfp\x00\x00\x00\x00\x12S\xfcp\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x00\x00\x00\x00XCNp\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x04\x01\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00+2\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0cLMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xb4N\xb8a\x03\x00\x00a\x03\x00\x00\x11\x00\x00\x00Europe/SimferopolTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00K\x00\x00\x00\x09\x00\x00\x00\x22\xff\xff\xff\xffV\xb6\xc4\x08\xff\xff\xff\xff\xaa\x19\xa4 \xff\xff\xff\xff\xb5\xa4\x19`\xff\xff\xff\xff\xcb\x04\x8d\xd0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xcf\x9f8\xe0\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x8d.\xf0\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00-\xc2\xc6\xd0\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r\xa6\x00\x00\x00\x00\x003=\xbb\x10\x00\x00\x00\x004R\x96\x10\x00\x00\x00\x005\x1d\x9d\x10\x00\x00\x00\x0062x\x10\x00\x00\x00\x006\xfd\x7f\x10\x00\x00\x00\x008\x1b\x94\x90\x00\x00\x00\x008\xdda\x10\x00\x00\x00\x009\xfbv\x90\x00\x00\x00\x00:\xbdC\x10\x00\x00\x00\x00;\xdbX\x90\x00\x00\x00\x00<\xa6_\x90\x00\x00\x00\x00=\xbb:\x90\x00\x00\x00\x00>\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7^\x80\x00\x00\x00\x00TL\x1d`\x01\x02\x03\x05\x04\x05\x04\x05\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x02\x07\x02\x07\x02\x07\x06\x03\x06\x03\x06\x03\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x08\x03\x00\x00\x1f\xf8\x00\x00\x00\x00\x1f\xe0\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1d\x00\x008@\x00\x0cLMT\x00SMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1C\xf9\xa1\xde\x01\x00\x00\xde\x01\x00\x00\x0d\x00\x00\x00Europe/SkopjeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff^<\xf0H\xff\xff\xff\xff\xca\x025\xe0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1\xa1\x8c\x10\xff\xff\xff\xff\xd2N@\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#`\x00\x00\x00\x00\x0a\x05x\xf0\x00\x00\x00\x00\x0a\xd0q\xe0\x00\x00\x00\x00\x0b\xe9Op\x00\x00\x00\x00\x0c\xb4H`\x00\x00\x00\x00\x0d\xd2k\xf0\x00\x00\x00\x00\x0e\x94*`\x00\x00\x00\x00\x0f\xb0\xfcp\x00\x00\x00\x00\x10t\x0c`\x00\x00\x00\x00\x11\x90\xdep\x00\x00\x00\x00\x12S\xee`\x00\x00\x00\x00\x13p\xc0p\x00\x00\x00\x00\x14;\xb9`\x00\x00\x00\x00\x15H\xb9p\x00\x00\x00\x00\x16\x13\xb2`\x00\x00\x00\x00\x171\xd5\xf0\x00\x00\x00\x00\x17\xfc\xce\xe0\x00\x00\x00\x00\x19\x00\x94p\x00\x00\x00\x00\x19\xdb_`\x00\x00\x00\x00\x1a\xcc\xaf\xf0\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xf3`\xff\xff\xff\xff\xb9\xef\x9c`\xff\xff\xff\xff\xba\xdf\x8d`\xff\xff\xff\xff\xbb\xcf~`\xff\xff\xff\xff\xbc\xc8\xa9\xe0\xff\xff\xff\xff\xbd\xb8\x9a\xe0\xff\xff\xff\xff\xbe\xa8\x8b\xe0\xff\xff\xff\xff\xbf\x98|\xe0\xff\xff\xff\xff\xc0\x88m\xe0\xff\xff\xff\xff\xc1x^\xe0\xff\xff\xff\xff\xc2hO\xe0\xff\xff\xff\xff\xc3X@\xe0\xff\xff\xff\xff\xc4H1\xe0\xff\xff\xff\xff\xc58\x22\xe0\xff\xff\xff\xff\xc6(\x13\xe0\xff\xff\xff\xff\xc7\x18\x04\xe0\xff\xff\xff\xff\xc8\xbc\x93`\xff\xff\xff\xff\xcaw}P\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0N\x90`\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&CL\xe0\x00\x00\x00\x00'\x055\x80\x00\x00\x00\x00'\xf5&\x80\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x002\xc9\x8c\xe0\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x06\x05\x06\x05\x06\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x04\x00\x00\x1b\x08\x00\x00\x00\x00\x1a\xf4\x00\x04\x00\x00\x18x\x00\x08\x00\x00*0\x01\x0c\x00\x00\x1c \x00\x11\x00\x00\x0e\x10\x00\x15\x00\x00\x1c \x01\x19\x00\x008@\x01\x1e\x00\x00*0\x00\x22LMT\x00CMT\x00BMT\x00EEST\x00EET\x00CET\x00CEST\x00MSD\x00MSK\x00\x0aEET-2EEST,M3.5.0,M10.5.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u\xb0\xcd\xfc\xf8\x02\x00\x00\xf8\x02\x00\x00\x10\x00\x00\x00Europe/UlyanovskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\xa1\x009\x80\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)x\xbf\x80\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x00\x00\x00\x00V\xf7\x14p\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x05\x06\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00-`\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0c\x00\x00*0\x01\x04\x00\x00\x1c \x00\x10LMT\x00+03\x00+05\x00+04\x00+02\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x81\xbf~.\x02\x00\x00.\x02\x00\x00\x0f\x00\x00\x00Europe/UzhgorodTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x08\x00\x00\x00\x22\xff\xff\xff\xffV\xb6\xc7d\xff\xff\xff\xff\xaa\x19\xa7d\xff\xff\xff\xff\xb5\xa4\x19`\xff\xff\xff\xff\xca\xcd.\xd0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xce\xcd\xa8p\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&\x8d \xe0\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00.\x84\xbd\x80\x00\x00\x00\x00/t\xae\x80\x00\x00\x00\x000d\x9f\x80\x00\x00\x00\x001]\xcb\x00\x00\x00\x00\x001\x96QP\x01\x02\x03\x05\x04\x05\x04\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x07\x00\x00\x1c\x9c\x00\x00\x00\x00\x1c\x9c\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1dLMT\x00KMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Dd#\xc4\xf1\x01\x00\x00\xf1\x01\x00\x00\x0c\x00\x00\x00Europe/VaduzTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff$\xf0\xea\x80\xff\xff\xff\xffq\xd4\x06\x86\xff\xff\xff\xff\xca\x17j\x00\xff\xff\xff\xff\xca\xe2q\x00\xff\xff\xff\xff\xcb\xf7L\x00\xff\xff\xff\xff\xcc\xc2S\x00\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#(\xe8L\xff\xff\xff\xffp\xbc\x81p\xff\xff\xff\xff\x9b8\xf8p\xff\xff\xff\xff\x9b\xd5\xcc\xe0\xff\xff\xff\xff\x9c\xc5\xcb\xf0\xff\xff\xff\xff\x9d\xb7\x00`\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0\x1c\xe0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1~\xad`\xff\xff\xff\xff\xa2\x5c7p\xff\xff\xff\xff\xa3L\x1a`\xff\xff\xff\xff\xc8l5\xf0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2L\xd2\xf0\xff\xff\xff\xff\xd3>1\x90\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd5\x1d\xf7p\xff\xff\xff\xff\xd6)\x97\xf0\xff\xff\xff\xff\xd6\xeb\x80\x90\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xf93\xb5\xf0\xff\xff\xff\xff\xf9\xd9\xc4\xe0\xff\xff\xff\xff\xfb\x1c\xd2p\xff\xff\xff\xff\xfb\xb9\xb4\xf0\xff\xff\xff\xff\xfc\xfc\xb4p\xff\xff\xff\xff\xfd\x99\x96\xf0\xff\xff\xff\xff\xfe\xe5\xd0\xf0\xff\xff\xff\xff\xff\x82\xb3p\x00\x00\x00\x00\x00\xc5\xb2\xf0\x00\x00\x00\x00\x01b\x95p\x00\x00\x00\x00\x02\x9cZp\x00\x00\x00\x00\x03Bwp\x00\x00\x00\x00\x04\x85v\xf0\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x07\x0bu\xf0\x00\x00\x00\x00\x08E:\xf0\x00\x00\x00\x00\x08\xebW\xf0\x00\x00\x00\x00\x0a.Wp\x00\x00\x00\x00\x0a\xcb9\xf0\x00\x00\x00\x00\x0c\x0e9p\x00\x00\x00\x00\x0c\xab\x1b\xf0\x00\x00\x00\x00\x0d\xe4\xe0\xf0\x00\x00\x00\x00\x0e\x8a\xfd\xf0\x00\x00\x00\x00\x0f\xcd\xfdp\x00\x00\x00\x00\x10t\x1ap\x00\x00\x00\x00\x11\xad\xdfp\x00\x00\x00\x00\x12S\xfcp\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x12\x13`\x01\x02\x03\x04\x03\x05\x06\x03\x06\x03\x06\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x06\x03\x06\x04\x04\x00\x00\x17\xbc\x00\x00\x00\x00\x13\xb0\x00\x04\x00\x00\x16h\x00\x08\x00\x00\x0e\x10\x00\x0c\x00\x00\x1c \x00\x10\x00\x00*0\x00\x14\x00\x00\x1c \x01\x18\x00\x008@\x01\x1d\x00\x00*0\x01!LMT\x00WMT\x00KMT\x00CET\x00EET\x00MSK\x00CEST\x00MSD\x00EEST\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xec\xa0%\xf1\x02\x00\x00\xf1\x02\x00\x00\x10\x00\x00\x00Europe/VolgogradTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x07\x00\x00\x00\x18\xff\xff\xff\xff\xa1\xf5F\xdc\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x00\x00\x00\x00[\xd4\xed\xf0\x00\x00\x00\x00_\xe7\xb2`\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x05\x04\x05\x02\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x06\x05\x02\x05\x00\x00)\xa4\x00\x00\x00\x00*0\x00\x04\x00\x008@\x00\x08\x00\x00FP\x01\x0c\x00\x008@\x01\x10\x00\x00*0\x00\x14\x00\x008@\x00\x14LMT\x00+03\x00+04\x00+05\x00MSD\x00MSK\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xfe\xe5\x9e\x9b\x03\x00\x00\x9b\x03\x00\x00\x0d\x00\x00\x00Europe/WarsawTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xffV\xb6\xd0P\xff\xff\xff\xff\x99\xa8*\xd0\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xa0\x9a\xb6\x00\xff\xff\xff\xff\xa1e\xbd\x00\xff\xff\xff\xff\xa6}|`\xff\xff\xff\xff\xc8v\xde\x10\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x84\xba\x00\xff\xff\xff\xff\xd1\x95\x92p\xff\xff\xff\xff\xd2\x8a\xbb`\xff\xff\xff\xff\xd3b\xffp\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd5^\xad\x10\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\xff\xff\xff\xff\xe8T\xd2\x00\xff\xff\xff\xff\xe8\xf1\xb4\x80\xff\xff\xff\xff\xe9\xe1\xa5\x80\xff\xff\xff\xff\xea\xd1\x96\x80\xff\xff\xff\xff\xec\x14\x96\x00\xff\xff\xff\xff\xec\xba\xb3\x00\xff\xff\xff\xff\xed\xaa\xa4\x00\xff\xff\xff\xff\xee\x9a\x95\x00\xff\xff\xff\xff\xef\xd4Z\x00\xff\xff\xff\xff\xf0zw\x00\xff\xff\xff\xff\xf1\xb4<\x00\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3\x94\x1e\x00\xff\xff\xff\xff\xf4:;\x00\xff\xff\xff\xff\xf5}:\x80\xff\xff\xff\xff\xf6\x1a\x1d\x00\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\x8b\x0c\x00\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11d\x19\x80\x00\x00\x00\x00\x12T\x0a\x80\x00\x00\x00\x00\x13M6\x00\x00\x00\x00\x00\x143\xec\x80\x00\x00\x00\x00\x15#\xdd\x80\x00\x00\x00\x00\x16\x13\xce\x80\x00\x00\x00\x00\x17\x03\xbf\x80\x00\x00\x00\x00\x17\xf3\xb0\x80\x00\x00\x00\x00\x18\xe3\xa1\x80\x00\x00\x00\x00\x19\xd3\x92\x80\x00\x00\x00\x00\x1a\xc3\x83\x80\x00\x00\x00\x00\x1b\xbc\xaf\x00\x00\x00\x00\x00\x1c\xac\xa0\x00\x00\x00\x00\x00\x1d\x9c\x91\x00\x00\x00\x00\x00\x1e\x8c\x82\x00\x00\x00\x00\x00\x1f|s\x00\x00\x00\x00\x00 ld\x00\x00\x00\x00\x00!\x5cU\x00\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x02\x00\x00\x00GBTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x00\x00\x00\x05\x00\x00\x00\x11\xff\xff\xff\xff\x1a]\x09\xcb\xff\xff\xff\xff\x9b&\xad\xa0\xff\xff\xff\xff\x9b\xd6\x05 \xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba \xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c \xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb \xff\xff\xff\xff\xa6%` \xff\xff\xff\xff\xa7'\xc6 \xff\xff\xff\xff\xa8*, \xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15 \xff\xff\xff\xff\xab\xe9\xf0 \xff\xff\xff\xff\xac\xc7l \xff\xff\xff\xff\xad\xc9\xd2 \xff\xff\xff\xff\xae\xa7N \xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870 \xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00 \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xdbW \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2z\xfd \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xca\x16&\x90\xff\xff\xff\xff\xca\x97Y\x90\xff\xff\xff\xff\xcb\xd1\x1e\x90\xff\xff\xff\xff\xccw;\x90\xff\xff\xff\xff\xcd\xb1\x00\x90\xff\xff\xff\xff\xce`X\x10\xff\xff\xff\xff\xcf\x90\xe2\x90\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xfb2\x10\xff\xff\xff\xff\xd2i\xfe \xff\xff\xff\xff\xd3c)\xa0\xff\xff\xff\xff\xd4I\xe0 \xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd5B\xfd\x90\xff\xff\xff\xff\xd5\xdf\xe0\x10\xff\xff\xff\xff\xd6N\xac \xff\xff\xff\xff\xd6\xfe\x03\xa0\xff\xff\xff\xff\xd8.\x8e \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xda\x0ep \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce \xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16 \xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt \xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad \xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xfdq \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xddS \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f} \xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_ \xff\xff\xff\xff\xf3Jf \xff\xff\xff\xff\xf4_A \xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?# \xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05 \xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7 \xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6 \x00\x00\x00\x00\x04)X \x00\x00\x00\x00\x05P\xa8 \x00\x00\x00\x00\x06\x09: \x00\x00\x00\x00\x070\x8a \x00\x00\x00\x00\x07\xe9\x1c \x00\x00\x00\x00\x09\x10l \x00\x00\x00\x00\x09\xc8\xfe \x00\x00\x00\x00\x0a\xf0N \x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00 \x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12 \x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\x0a\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x000\xe7$\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x02\xff\xff\xff\xb5\x00\x00\x00\x00\x0e\x10\x01\x04\x00\x00\x00\x00\x00\x08\x00\x00\x1c \x01\x0c\x00\x00\x0e\x10\x00\x04LMT\x00BST\x00GMT\x00BDST\x00\x0aGMT0BST,M3.5.0/1,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x07\x00\x00\x00GB-EireTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x00\x00\x00\x05\x00\x00\x00\x11\xff\xff\xff\xff\x1a]\x09\xcb\xff\xff\xff\xff\x9b&\xad\xa0\xff\xff\xff\xff\x9b\xd6\x05 \xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba \xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c \xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb \xff\xff\xff\xff\xa6%` \xff\xff\xff\xff\xa7'\xc6 \xff\xff\xff\xff\xa8*, \xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15 \xff\xff\xff\xff\xab\xe9\xf0 \xff\xff\xff\xff\xac\xc7l \xff\xff\xff\xff\xad\xc9\xd2 \xff\xff\xff\xff\xae\xa7N \xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870 \xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00 \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xdbW \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2z\xfd \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xca\x16&\x90\xff\xff\xff\xff\xca\x97Y\x90\xff\xff\xff\xff\xcb\xd1\x1e\x90\xff\xff\xff\xff\xccw;\x90\xff\xff\xff\xff\xcd\xb1\x00\x90\xff\xff\xff\xff\xce`X\x10\xff\xff\xff\xff\xcf\x90\xe2\x90\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xfb2\x10\xff\xff\xff\xff\xd2i\xfe \xff\xff\xff\xff\xd3c)\xa0\xff\xff\xff\xff\xd4I\xe0 \xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd5B\xfd\x90\xff\xff\xff\xff\xd5\xdf\xe0\x10\xff\xff\xff\xff\xd6N\xac \xff\xff\xff\xff\xd6\xfe\x03\xa0\xff\xff\xff\xff\xd8.\x8e \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xda\x0ep \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce \xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16 \xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt \xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad \xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xfdq \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xddS \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f} \xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_ \xff\xff\xff\xff\xf3Jf \xff\xff\xff\xff\xf4_A \xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?# \xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05 \xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7 \xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6 \x00\x00\x00\x00\x04)X \x00\x00\x00\x00\x05P\xa8 \x00\x00\x00\x00\x06\x09: \x00\x00\x00\x00\x070\x8a \x00\x00\x00\x00\x07\xe9\x1c \x00\x00\x00\x00\x09\x10l \x00\x00\x00\x00\x09\xc8\xfe \x00\x00\x00\x00\x0a\xf0N \x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00 \x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12 \x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\x0a\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x000\xe7$\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x02\xff\xff\xff\xb5\x00\x00\x00\x00\x0e\x10\x01\x04\x00\x00\x00\x00\x00\x08\x00\x00\x1c \x01\x0c\x00\x00\x0e\x10\x00\x04LMT\x00BST\x00GMT\x00BDST\x00\x0aGMT0BST,M3.5.0/1,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00GMTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x05\x00\x00\x00GMT+0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x05\x00\x00\x00GMT-0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x04\x00\x00\x00GMT0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00GreenwichTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xf7\xfawp\x00\x00\x00p\x00\x00\x00\x03\x00\x00\x00HSTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xffs`\x00\x00HST\x00\x0aHST10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x09\xfa-\x07\x03\x00\x00\x07\x03\x00\x00\x08\x00\x00\x00HongkongTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff\x85ic\x90\xff\xff\xff\xff\xcaM10\xff\xff\xff\xff\xca\xdb\x930\xff\xff\xff\xff\xcbKqx\xff\xff\xff\xff\xd2\xa0\xde\x90\xff\xff\xff\xff\xd3k\xd7\x80\xff\xff\xff\xff\xd4\x93X\xb8\xff\xff\xff\xff\xd5B\xb08\xff\xff\xff\xff\xd6s:\xb8\xff\xff\xff\xff\xd7>A\xb8\xff\xff\xff\xff\xd8.2\xb8\xff\xff\xff\xff\xd8\xf99\xb8\xff\xff\xff\xff\xda\x0e\x14\xb8\xff\xff\xff\xff\xda\xd9\x1b\xb8\xff\xff\xff\xff\xdb\xed\xf6\xb8\xff\xff\xff\xff\xdc\xb8\xfd\xb8\xff\xff\xff\xff\xdd\xcd\xd8\xb8\xff\xff\xff\xff\xde\xa2\x1a8\xff\xff\xff\xff\xdf\xb6\xf58\xff\xff\xff\xff\xe0\x81\xfc8\xff\xff\xff\xff\xe1\x96\xc9(\xff\xff\xff\xff\xe2Oi8\xff\xff\xff\xff\xe3v\xab(\xff\xff\xff\xff\xe4/K8\xff\xff\xff\xff\xe5_\xc7\xa8\xff\xff\xff\xff\xe6\x0f-8\xff\xff\xff\xff\xe7?\xa9\xa8\xff\xff\xff\xff\xe7\xf8I\xb8\xff\xff\xff\xff\xe9\x1f\x8b\xa8\xff\xff\xff\xff\xe9\xd8+\xb8\xff\xff\xff\xff\xea\xffm\xa8\xff\xff\xff\xff\xeb\xb8\x0d\xb8\xff\xff\xff\xff\xec\xdfO\xa8\xff\xff\xff\xff\xed\x97\xef\xb8\xff\xff\xff\xff\xee\xc8l(\xff\xff\xff\xff\xefw\xd1\xb8\xff\xff\xff\xff\xf0\xa8N(\xff\xff\xff\xff\xf1W\xb3\xb8\xff\xff\xff\xff\xf2\x880(\xff\xff\xff\xff\xf3@\xd08\xff\xff\xff\xff\xf4h\x12(\xff\xff\xff\xff\xf5 \xb28\xff\xff\xff\xff\xf6G\xf4(\xff\xff\xff\xff\xf7%~8\xff\xff\xff\xff\xf8\x15a(\xff\xff\xff\xff\xf9\x05`8\xff\xff\xff\xff\xf9\xf5C(\xff\xff\xff\xff\xfa\xe5B8\xff\xff\xff\xff\xfb\xde_\xa8\xff\xff\xff\xff\xfc\xce^\xb8\xff\xff\xff\xff\xfd\xbeA\xa8\xff\xff\xff\xff\xfe\xae@\xb8\xff\xff\xff\xff\xff\x9e#\xa8\x00\x00\x00\x00\x00\x8e\x22\xb8\x00\x00\x00\x00\x01~\x05\xa8\x00\x00\x00\x00\x02n\x04\xb8\x00\x00\x00\x00\x03]\xe7\xa8\x00\x00\x00\x00\x04M\xe6\xb8\x00\x00\x00\x00\x05G\x04(\x00\x00\x00\x00\x067\x038\x00\x00\x00\x00\x07&\xe6(\x00\x00\x00\x00\x07\x83=8\x00\x00\x00\x00\x09\x06\xc8(\x00\x00\x00\x00\x09\xf6\xc78\x00\x00\x00\x00\x0a\xe6\xaa(\x00\x00\x00\x00\x0b\xd6\xa98\x00\x00\x00\x00\x0c\xc6\x8c(\x00\x00\x00\x00\x11\x9b98\x00\x00\x00\x00\x12ol\xa8\x01\x02\x03\x04\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00k\x0a\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x01\x08\x00\x00w\x88\x01\x0d\x00\x00~\x90\x00\x12LMT\x00HKT\x00HKST\x00HKWT\x00JST\x00\x0aHKT-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x07\x00\x00\x00IcelandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x13\x00\x00\x00Indian/AntananarivoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\xb0W\x14\x98\x00\x00\x00\x98\x00\x00\x00\x0d\x00\x00\x00Indian/ChagosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x89~\xf7\x9c\x00\x00\x00\x000\xe6\xdd\xb0\x01\x02\x00\x00C\xe4\x00\x00\x00\x00FP\x00\x04\x00\x00T`\x00\x08LMT\x00+05\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x10\x00\x00\x00Indian/ChristmasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x85\xc4\xff\xff\xff\xff\xa2jg\xc4\x01\x02\x00\x00^<\x00\x00\x00\x00^<\x00\x04\x00\x00bp\x00\x08LMT\x00BMT\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0c\x00\x00\x00Indian/CocosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffV\xb6\x89\xd1\xff\xff\xff\xff\xa1\xf2sQ\xff\xff\xff\xff\xcb\xf2\xfc\x18\xff\xff\xff\xff\xd1\x9ag\xf0\x01\x02\x03\x02\x00\x00Z/\x00\x00\x00\x00Z/\x00\x04\x00\x00[h\x00\x08\x00\x00~\x90\x00\x0eLMT\x00RMT\x00+0630\x00+09\x00\x0a<+0630>-6:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0d\x00\x00\x00Indian/ComoroTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb9\xb2Z\xac\x98\x00\x00\x00\x98\x00\x00\x00\x10\x00\x00\x00Indian/KerguelenTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x9f\x18\xff\xff\xff\xff\xed/\xc3\x98\x01\x02\x00\x00D\xe8\x00\x00\x00\x00D\xe8\x00\x04\x00\x00FP\x00\x08LMT\x00MMT\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Indian/MaheTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xa1\xf2\x99\xa8\x01\x00\x003\xd8\x00\x00\x00\x008@\x00\x04LMT\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb9\xb2Z\xac\x98\x00\x00\x00\x98\x00\x00\x00\x0f\x00\x00\x00Indian/MaldivesTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x9f\x18\xff\xff\xff\xff\xed/\xc3\x98\x01\x02\x00\x00D\xe8\x00\x00\x00\x00D\xe8\x00\x04\x00\x00FP\x00\x08LMT\x00MMT\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xed=\x98\xb3\x00\x00\x00\xb3\x00\x00\x00\x10\x00\x00\x00Indian/MauritiusTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x89\x7f\x05\x98\x00\x00\x00\x00\x18\x05\xed@\x00\x00\x00\x00\x18\xdbr0\x00\x00\x00\x00I\x03\x96\xe0\x00\x00\x00\x00I\xce\x8f\xd0\x02\x01\x02\x01\x02\x00\x005\xe8\x00\x00\x00\x00FP\x01\x04\x00\x008@\x00\x08LMT\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00Indian/MayotteTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0e\x00\x00\x00Indian/ReunionTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xa1\xf2\x99\xa8\x01\x00\x003\xd8\x00\x00\x00\x008@\x00\x04LMT\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xdb?\xec,\x03\x00\x00,\x03\x00\x00\x04\x00\x00\x00IranTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x06\x00\x00\x00\x1c\xff\xff\xff\xff\x9al}\xc8\xff\xff\xff\xff\xbf\x00\xccH\x00\x00\x00\x00\x0d\x94D8\x00\x00\x00\x00\x0e\xad\x13\xb8\x00\x00\x00\x00\x0fys@\x00\x00\x00\x00\x10(\xca\xc0\x00\x00\x00\x00\x10\xed:@\x00\x00\x00\x00\x11\xad\xbcH\x00\x00\x00\x00\x12EJ\xb8\x00\x00\x00\x00\x137\xec\xc8\x00\x00\x00\x00\x14-\x15\xb8\x00\x00\x00\x00( v\xc8\x00\x00\x00\x00(\xdb\x9d\xb8\x00\x00\x00\x00)\xcb\x9c\xc8\x00\x00\x00\x00*\xbe\x22\xb8\x00\x00\x00\x00+\xac\xd0H\x00\x00\x00\x00,\x9fV8\x00\x00\x00\x00-\x8e\x03\xc8\x00\x00\x00\x00.\x80\x89\xb8\x00\x00\x00\x00/o7H\x00\x00\x00\x000a\xbd8\x00\x00\x00\x001Pj\xc8\x00\x00\x00\x002B\xf0\xb8\x00\x00\x00\x0032\xef\xc8\x00\x00\x00\x004%u\xb8\x00\x00\x00\x005\x14#H\x00\x00\x00\x006\x06\xa98\x00\x00\x00\x006\xf5V\xc8\x00\x00\x00\x007\xe7\xdc\xb8\x00\x00\x00\x008\xd6\x8aH\x00\x00\x00\x009\xc9\x108\x00\x00\x00\x00:\xb9\x0fH\x00\x00\x00\x00;\xab\x958\x00\x00\x00\x00<\x9aB\xc8\x00\x00\x00\x00=\x8c\xc8\xb8\x00\x00\x00\x00>{vH\x00\x00\x00\x00?m\xfc8\x00\x00\x00\x00@\x5c\xa9\xc8\x00\x00\x00\x00AO/\xb8\x00\x00\x00\x00B?.\xc8\x00\x00\x00\x00C1\xb4\xb8\x00\x00\x00\x00G\xe2\xc9H\x00\x00\x00\x00H\xd5O8\x00\x00\x00\x00I\xc5NH\x00\x00\x00\x00J\xb7\xd48\x00\x00\x00\x00K\xa6\x81\xc8\x00\x00\x00\x00L\x99\x07\xb8\x00\x00\x00\x00M\x87\xb5H\x00\x00\x00\x00Nz;8\x00\x00\x00\x00Oh\xe8\xc8\x00\x00\x00\x00P[n\xb8\x00\x00\x00\x00QKm\xc8\x00\x00\x00\x00R=\xf3\xb8\x00\x00\x00\x00S,\xa1H\x00\x00\x00\x00T\x1f'8\x00\x00\x00\x00U\x0d\xd4\xc8\x00\x00\x00\x00V\x00Z\xb8\x00\x00\x00\x00V\xef\x08H\x00\x00\x00\x00W\xe1\x8e8\x00\x00\x00\x00X\xd1\x8dH\x00\x00\x00\x00Y\xc4\x138\x00\x00\x00\x00Z\xb2\xc0\xc8\x00\x00\x00\x00[\xa5F\xb8\x00\x00\x00\x00\x5c\x93\xf4H\x00\x00\x00\x00]\x86z8\x00\x00\x00\x00^u'\xc8\x00\x00\x00\x00_g\xad\xb8\x00\x00\x00\x00`W\xac\xc8\x00\x00\x00\x00aJ2\xb8\x00\x00\x00\x00b8\xe0H\x00\x00\x00\x00c+f8\x01\x03\x02\x05\x04\x05\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x0008\x00\x00\x00\x0008\x00\x04\x00\x00?H\x01\x08\x00\x0018\x00\x0e\x00\x00FP\x01\x14\x00\x008@\x00\x18LMT\x00TMT\x00+0430\x00+0330\x00+05\x00+04\x00\x0a<+0330>-3:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x06\x00\x00\x00IsraelTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xffV\xb6\xc2\xfa\xff\xff\xff\xff\x9e0E\x88\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xd7Z0\x80\xff\xff\xff\xff\xd7\xdfX\x00\xff\xff\xff\xff\xd8/\xc3\x80\xff\xff\xff\xff\xd9\x1ec\x00\xff\xff\xff\xff\xda\x10\xf7\x00\xff\xff\xff\xff\xda\xeb\xd0\x00\xff\xff\xff\xff\xdb\xb44\x00\xff\xff\xff\xff\xdc\xb9=\x00\xff\xff\xff\xff\xdd\xe0\x8d\x00\xff\xff\xff\xff\xde\xb4\xce\x80\xff\xff\xff\xff\xdf\xa4\xbf\x80\xff\xff\xff\xff\xe0\x8bv\x00\xff\xff\xff\xff\xe1V}\x00\xff\xff\xff\xff\xe2\xbef\x80\xff\xff\xff\xff\xe36_\x00\xff\xff\xff\xff\xe4\x9eH\x80\xff\xff\xff\xff\xe5\x16A\x00\xff\xff\xff\xff\xe6t\xf0\x00\xff\xff\xff\xff\xe7\x11\xd2\x80\xff\xff\xff\xff\xe8&\xad\x80\xff\xff\xff\xff\xe8\xe8z\x00\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x001H\x96\xe0\x00\x00\x00\x002\x83\x82p\x00\x00\x00\x00?|\x9f\xe0\x00\x00\x00\x00@s6p\x00\x00\x00\x00AP\xa4`\x00\x00\x00\x00BL\x8f\x00\x00\x00\x00\x00CHOp\x00\x00\x00\x00D,q\x00\x00\x00\x00\x00E\x1e\xf6\xf0\x00\x00\x00\x00F\x0cS\x00\x00\x00\x00\x00F\xecc\xf0\x00\x00\x00\x00G\xec5\x00\x00\x00\x00\x00H\xe7\xf5p\x00\x00\x00\x00I\xcc\x17\x00\x00\x00\x00\x00J\xbe\x9c\xf0\x00\x00\x00\x00K\xab\xf9\x00\x00\x00\x00\x00L\x8c\x09\xf0\x00\x00\x00\x00M\x95\x15\x80\x00\x00\x00\x00N\x87\x9bp\x00\x00\x00\x00Ot\xf7\x80\x00\x00\x00\x00P^B\xf0\x00\x00\x00\x00QT\xd9\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00!\x06\x00\x00\x00\x00 \xf8\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0c\x00\x008@\x01\x10LMT\x00JMT\x00IDT\x00IST\x00IDDT\x00\x0aIST-2IDT,M3.4.4/26,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%J\xd5\xebS\x01\x00\x00S\x01\x00\x00\x07\x00\x00\x00JamaicaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87#~\xff\xff\xff\xff\x93\x0f\xb4\xfe\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\xff\xff\xb8\x02\x00\x00\xff\xff\xb8\x02\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0cLMT\x00KMT\x00EST\x00EDT\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xf4\xaeg\xd5\x00\x00\x00\xd5\x00\x00\x00\x05\x00\x00\x00JapanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffe\xc2\xa4p\xff\xff\xff\xff\xd7>\x02p\xff\xff\xff\xff\xd7\xedY\xf0\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xd9\xcd;\xf0\xff\xff\xff\xff\xdb\x07\x00\xf0\xff\xff\xff\xff\xdb\xad\x1d\xf0\xff\xff\xff\xff\xdc\xe6\xe2\xf0\xff\xff\xff\xff\xdd\x8c\xff\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x83\x03\x00\x00\x00\x00\x8c\xa0\x01\x04\x00\x00~\x90\x00\x08LMT\x00JDT\x00JST\x00\x0aJST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe8]*\xdb\x00\x00\x00\xdb\x00\x00\x00\x09\x00\x00\x00KwajaleinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff~6\x18 \xff\xff\xff\xff\xc1\xed5\xd0\xff\xff\xff\xff\xc9\xea\x0a`\xff\xff\xff\xff\xcfF\x81\xf0\xff\xff\xff\xff\xff\x86\x1bP\x00\x00\x00\x00,v\x0e@\x01\x02\x03\x01\x04\x05\x00\x00\x9c\xe0\x00\x00\x00\x00\x9a\xb0\x00\x04\x00\x00\x8c\xa0\x00\x08\x00\x00~\x90\x00\x0c\xff\xffW@\x00\x10\x00\x00\xa8\xc0\x00\x14LMT\x00+11\x00+10\x00+09\x00-12\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x7f2[\xaf\x01\x00\x00\xaf\x01\x00\x00\x05\x00\x00\x00LibyaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa1\xf2\xc1$\xff\xff\xff\xff\xdd\xbb\xb1\x10\xff\xff\xff\xff\xde#\xad`\xff\xff\xff\xff\xe1x\xd2\x10\xff\xff\xff\xff\xe1\xe7e\xe0\xff\xff\xff\xff\xe5/?p\xff\xff\xff\xff\xe5\xa9\xcc\xe0\xff\xff\xff\xff\xebN\xc6\xf0\x00\x00\x00\x00\x16\x92B`\x00\x00\x00\x00\x17\x08\xf7p\x00\x00\x00\x00\x17\xfa+\xe0\x00\x00\x00\x00\x18\xea*\xf0\x00\x00\x00\x00\x19\xdb_`\x00\x00\x00\x00\x1a\xcc\xaf\xf0\x00\x00\x00\x00\x1b\xbd\xe4`\x00\x00\x00\x00\x1c\xb4z\xf0\x00\x00\x00\x00\x1d\x9f\x17\xe0\x00\x00\x00\x00\x1e\x93\x0bp\x00\x00\x00\x00\x1f\x82\xee`\x00\x00\x00\x00 pJp\x00\x00\x00\x00!a~\xe0\x00\x00\x00\x00\x22R\xcfp\x00\x00\x00\x00#D\x03\xe0\x00\x00\x00\x00$4\x02\xf0\x00\x00\x00\x00%%7`\x00\x00\x00\x00&@\xb7\xf0\x00\x00\x00\x002N\xf1`\x00\x00\x00\x003D6p\x00\x00\x00\x0045j\xe0\x00\x00\x00\x00P\x9d\x99\x00\x00\x00\x00\x00QT\xd9\x80\x00\x00\x00\x00Ri\xb4\x80\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x03\x02\x01\x03\x00\x00\x0c\x5c\x00\x00\x00\x00\x1c \x01\x04\x00\x00\x0e\x10\x00\x09\x00\x00\x1c \x00\x0dLMT\x00CEST\x00CET\x00EET\x00\x0aEET-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\x9d\x1b\xc9m\x02\x00\x00m\x02\x00\x00\x03\x00\x00\x00METTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x02\x00\x00\x00\x09\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N@\x90\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x01\x00\x01\x00\x02\x03\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x01\x00\xff\xff\xab\xa0\x01\x08\xff\xff\xab\xa0\x01\x0cMDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x10\x00\x00\x00Mexico/BajaNorteTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xa9yOp\xff\xff\xff\xff\xaf\xf2|\xf0\xff\xff\xff\xff\xb6fdp\xff\xff\xff\xff\xb7\x1b\x10\x00\xff\xff\xff\xff\xb8\x0a\xf2\xf0\xff\xff\xff\xff\xcb\xea\x8d\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\x99\xbap\xff\xff\xff\xff\xd7\x1bY\x00\xff\xff\xff\xff\xd8\x91\xb4\xf0\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00F\x0f\x82\xa0\x00\x00\x00\x00G$O\x90\x00\x00\x00\x00G\xf8\x9f \x00\x00\x00\x00I\x041\x90\x00\x00\x00\x00I\xd8\x81 \x00\x00\x00\x00J\xe4\x13\x90\x00\x00\x00\x00K=\xab\x80\x01\x02\x01\x02\x03\x02\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x02\xff\xff\x92L\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x9d\x90\x01\x14LMT\x00MST\x00PST\x00PDT\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xad=\x98\xce\x02\x00\x00\xce\x02\x00\x00\x0e\x00\x00\x00Mexico/BajaSurTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xcb\xeaq`\xff\xff\xff\xff\xd8\x91\xb4\xf0\x00\x00\x00\x00\x00\x00p\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\xb8U\x10\x00\x00\x00\x00L\xcd\x22\x00\x00\x00\x00\x00M\x987\x10\x00\x00\x00\x00N\xad\x04\x00\x00\x00\x00\x00Ox\x19\x10\x00\x00\x00\x00P\x8c\xe6\x00\x00\x00\x00\x00Qa5\x90\x00\x00\x00\x00Rl\xc8\x00\x00\x00\x00\x00SA\x17\x90\x00\x00\x00\x00TL\xaa\x00\x00\x00\x00\x00U \xf9\x90\x00\x00\x00\x00V,\x8c\x00\x00\x00\x00\x00W\x00\xdb\x90\x00\x00\x00\x00X\x15\xa8\x80\x00\x00\x00\x00X\xe0\xbd\x90\x00\x00\x00\x00Y\xf5\x8a\x80\x00\x00\x00\x00Z\xc0\x9f\x90\x00\x00\x00\x00[\xd5l\x80\x00\x00\x00\x00\x5c\xa9\xbc\x10\x00\x00\x00\x00]\xb5N\x80\x00\x00\x00\x00^\x89\x9e\x10\x00\x00\x00\x00_\x950\x80\x00\x00\x00\x00`i\x80\x10\x00\x00\x00\x00a~M\x00\x00\x00\x00\x00bIb\x10\x00\x00\x00\x00c^/\x00\x01\x02\x01\x03\x01\x02\x01\x04\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\xff\xff\x9c<\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\x8f\x80\x00\x10LMT\x00MST\x00CST\x00MDT\x00PST\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x08\x89\x8c\x05\x03\x00\x00\x05\x03\x00\x00\x0e\x00\x00\x00Mexico/GeneralTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xc5\xde\xb0`\xff\xff\xff\xff\xc6\x974P\xff\xff\xff\xff\xc9U\xf1\xe0\xff\xff\xff\xff\xc9\xea\xddP\xff\xff\xff\xff\xcf\x02\xc6\xe0\xff\xff\xff\xff\xcf\xb7VP\xff\xff\xff\xff\xda\x99\x15\xe0\xff\xff\xff\xff\xdbv\x83\xd0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x03\x01\x02\x04\x02\x04\x02\x05\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\xff\xff\xa3\x0c\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x01\x14LMT\x00MST\x00CST\x00MDT\x00CDT\x00CWT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x02\x00\x00\x00NZTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x13\xff\xff\xff\xffA\xb7L\xa8\xff\xff\xff\xff\xb0\xb4\xb2\xe8\xff\xff\xff\xff\xb1Q\x87X\xff\xff\xff\xff\xb2x\xe5h\xff\xff\xff\xff\xb3C\xe5`\xff\xff\xff\xff\xb4X\xc7h\xff\xff\xff\xff\xb5#\xc7`\xff\xff\xff\xff\xb68\xa9h\xff\xff\xff\xff\xb7\x03\xa9`\xff\xff\xff\xff\xb8\x18\x8bh\xff\xff\xff\xff\xb8\xec\xc5\xe0\xff\xff\xff\xff\xb9\xf8mh\xff\xff\xff\xff\xba\xcc\xa7\xe0\xff\xff\xff\xff\xbb\xd8Oh\xff\xff\xff\xff\xbc\xe3\xe8\xe0\xff\xff\xff\xff\xbd\xae\xf6\xe8\xff\xff\xff\xff\xbe\xc3\xca\xe0\xff\xff\xff\xff\xbf\x8e\xd8\xe8\xff\xff\xff\xff\xc0\xa3\xac\xe0\xff\xff\xff\xff\xc1n\xba\xe8\xff\xff\xff\xff\xc2\x83\x8e\xe0\xff\xff\xff\xff\xc3N\x9c\xe8\xff\xff\xff\xff\xc4cp\xe0\xff\xff\xff\xff\xc5.~\xe8\xff\xff\xff\xff\xc6L\x8d`\xff\xff\xff\xff\xc7\x0e`\xe8\xff\xff\xff\xff\xc8,o`\xff\xff\xff\xff\xc8\xf7}h\xff\xff\xff\xff\xd2\xda\x9a@\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x02\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x00\x00\xa3\xd8\x00\x00\x00\x00\xaf\xc8\x01\x04\x00\x00\xa1\xb8\x00\x09\x00\x00\xa8\xc0\x01\x04\x00\x00\xb6\xd0\x01\x0e\x00\x00\xa8\xc0\x00\x04LMT\x00NZST\x00NZMT\x00NZDT\x00\x0aNZST-12NZDT,M9.5.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xc5FF(\x03\x00\x00(\x03\x00\x00\x07\x00\x00\x00NZ-CHATTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x04\x00\x00\x00\x16\xff\xff\xff\xffA\xb7D\x84\xff\xff\xff\xff\xd2\xda\x96\xbc\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00\xab\xfc\x00\x00\x00\x00\xacD\x00\x04\x00\x00\xc1\x5c\x01\x0a\x00\x00\xb3L\x00\x10LMT\x00+1215\x00+1345\x00+1245\x00\x0a<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x06\x00\x00\x00NavajoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xa2e\xfe\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4E\xe0\x90\xff\xff\xff\xff\xa4\x8f\xa6\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\x94\x00\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x9d\x94\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x03\x00\x00\x00PRCTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xadV\xad\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00PST8PDTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x9e\xa6H\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xa0\x86*\xa0\xff\xff\xff\xff\xa1\x9a\xf7\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x01\x00\x01\x00\x02\x03\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\xff\xff\x8f\x80\x00\x04\xff\xff\x9d\x90\x01\x00\xff\xff\x9d\x90\x01\x08\xff\xff\x9d\x90\x01\x0cPDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8A\x15\xfe\x97\x01\x00\x00\x97\x01\x00\x00\x0c\x00\x00\x00Pacific/ApiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x07\x00\x00\x00\x1a\xff\xff\xff\xffn=\xc9\x00\xff\xff\xff\xff\x91\x05\xfc\x00\xff\xff\xff\xff\xdab\x048\x00\x00\x00\x00L\x9f'\xb0\x00\x00\x00\x00M\x97+\xe0\x00\x00\x00\x00N}\xe2`\x00\x00\x00\x00N\xfd\x8b\xa0\x00\x00\x00\x00Ow\x0d\xe0\x00\x00\x00\x00Pf\xfe\xe0\x00\x00\x00\x00Q`*`\x00\x00\x00\x00RF\xe0\xe0\x00\x00\x00\x00S@\x0c`\x00\x00\x00\x00T&\xc2\xe0\x00\x00\x00\x00U\x1f\xee`\x00\x00\x00\x00V\x06\xa4\xe0\x00\x00\x00\x00V\xff\xd0`\x00\x00\x00\x00W\xe6\x86\xe0\x00\x00\x00\x00X\xdf\xb2`\x00\x00\x00\x00Y\xc6h\xe0\x00\x00\x00\x00Z\xbf\x94`\x00\x00\x00\x00[\xaf\x85`\x00\x00\x00\x00\x5c\xa8\xb0\xe0\x00\x00\x00\x00]\x8fg`\x00\x00\x00\x00^\x88\x92\xe0\x00\x00\x00\x00_oI`\x00\x00\x00\x00`ht\xe0\x01\x02\x04\x03\x04\x03\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x00\x00\xb0\x80\x00\x00\xff\xff_\x00\x00\x00\xff\xff^H\x00\x04\xff\xffs`\x01\x0a\xff\xffeP\x00\x0e\x00\x00\xb6\xd0\x00\x12\x00\x00\xc4\xe0\x01\x16LMT\x00-1130\x00-10\x00-11\x00+13\x00+14\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x10\x00\x00\x00Pacific/AucklandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x13\xff\xff\xff\xffA\xb7L\xa8\xff\xff\xff\xff\xb0\xb4\xb2\xe8\xff\xff\xff\xff\xb1Q\x87X\xff\xff\xff\xff\xb2x\xe5h\xff\xff\xff\xff\xb3C\xe5`\xff\xff\xff\xff\xb4X\xc7h\xff\xff\xff\xff\xb5#\xc7`\xff\xff\xff\xff\xb68\xa9h\xff\xff\xff\xff\xb7\x03\xa9`\xff\xff\xff\xff\xb8\x18\x8bh\xff\xff\xff\xff\xb8\xec\xc5\xe0\xff\xff\xff\xff\xb9\xf8mh\xff\xff\xff\xff\xba\xcc\xa7\xe0\xff\xff\xff\xff\xbb\xd8Oh\xff\xff\xff\xff\xbc\xe3\xe8\xe0\xff\xff\xff\xff\xbd\xae\xf6\xe8\xff\xff\xff\xff\xbe\xc3\xca\xe0\xff\xff\xff\xff\xbf\x8e\xd8\xe8\xff\xff\xff\xff\xc0\xa3\xac\xe0\xff\xff\xff\xff\xc1n\xba\xe8\xff\xff\xff\xff\xc2\x83\x8e\xe0\xff\xff\xff\xff\xc3N\x9c\xe8\xff\xff\xff\xff\xc4cp\xe0\xff\xff\xff\xff\xc5.~\xe8\xff\xff\xff\xff\xc6L\x8d`\xff\xff\xff\xff\xc7\x0e`\xe8\xff\xff\xff\xff\xc8,o`\xff\xff\xff\xff\xc8\xf7}h\xff\xff\xff\xff\xd2\xda\x9a@\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x02\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x00\x00\xa3\xd8\x00\x00\x00\x00\xaf\xc8\x01\x04\x00\x00\xa1\xb8\x00\x09\x00\x00\xa8\xc0\x01\x04\x00\x00\xb6\xd0\x01\x0e\x00\x00\xa8\xc0\x00\x04LMT\x00NZST\x00NZMT\x00NZDT\x00\x0aNZST-12NZDT,M9.5.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xf2:F\xc9\x00\x00\x00\xc9\x00\x00\x00\x14\x00\x00\x00Pacific/BougainvilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xffV\xb6R(\xff\xff\xff\xffr\xed\xa4\x90\xff\xff\xff\xff\xccC6`\xff\xff\xff\xff\xd2+l\xf0\x00\x00\x00\x00T\x9e\xd7\x80\x01\x02\x03\x02\x04\x00\x00\x91\xd8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09\x00\x00~\x90\x00\x0d\x00\x00\x9a\xb0\x00\x11LMT\x00PMMT\x00+10\x00+09\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xc5FF(\x03\x00\x00(\x03\x00\x00\x0f\x00\x00\x00Pacific/ChathamTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x04\x00\x00\x00\x16\xff\xff\xff\xffA\xb7D\x84\xff\xff\xff\xff\xd2\xda\x96\xbc\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00\xab\xfc\x00\x00\x00\x00\xacD\x00\x04\x00\x00\xc1\x5c\x01\x0a\x00\x00\xb3L\x00\x10LMT\x00+1215\x00+1345\x00+1245\x00\x0a<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0d\x00\x00\x00Pacific/ChuukTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?X'\x8e\x96\x04\x00\x00\x96\x04\x00\x00\x0e\x00\x00\x00Pacific/EasterTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffi\x87B\x08\xff\xff\xff\xff\xb9\xc7@\x88\xff\xff\xff\xff\xfd\xd1<@\xff\xff\xff\xff\xfe\x92\xfa\xb0\xff\xff\xff\xff\xff\xcc\xcd\xc0\x00\x00\x00\x00\x00r\xdc\xb0\x00\x00\x00\x00\x01uP\xc0\x00\x00\x00\x00\x02@I\xb0\x00\x00\x00\x00\x03U2\xc0\x00\x00\x00\x00\x04 +\xb0\x00\x00\x00\x00\x05>O@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00Y\x17\xc80\x00\x00\x00\x00Y\x8f\xce\xc0\x00\x00\x00\x00Z\xf7\xaa0\x00\x00\x00\x00[o\xb0\xc0\x00\x00\x00\x00\x5c\xa9g\xb0\x00\x00\x00\x00]t|\xc0\x00\x00\x00\x00^\x89I\xb0\x00\x00\x00\x00_T^\xc0\x00\x00\x00\x00`i+\xb0\x00\x00\x00\x00a4@\xc0\x00\x00\x00\x00bI\x0d\xb0\x00\x00\x00\x00c\x1d]@\x00\x00\x00\x00d(\xef\xb0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\xff\xff\x99x\x00\x00\xff\xff\x99x\x00\x04\xff\xff\xab\xa0\x01\x08\xff\xff\x9d\x90\x00\x0c\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x10LMT\x00EMT\x00-06\x00-07\x00-05\x00\x0a<-06>6<-05>,M9.1.6/22,M4.1.6/22\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9e\x7f\xab\x95V\x01\x00\x00V\x01\x00\x00\x0d\x00\x00\x00Pacific/EfateTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x92\xf5\xc2\xb4\x00\x00\x00\x00\x07y\x99@\x00\x00\x00\x00\x07\xfa\xcc@\x00\x00\x00\x00\x19\xd2\xf7\xd0\x00\x00\x00\x00\x1a\xc2\xda\xc0\x00\x00\x00\x00\x1b\xb2\xd9\xd0\x00\x00\x00\x00\x1c\xa2\xbc\xc0\x00\x00\x00\x00\x1d\x9b\xf6P\x00\x00\x00\x00\x1e\x82\x9e\xc0\x00\x00\x00\x00\x1f{\xd8P\x00\x00\x00\x00 k\xbb@\x00\x00\x00\x00![\xbaP\x00\x00\x00\x00\x22K\x9d@\x00\x00\x00\x00#;\x9cP\x00\x00\x00\x00$+\x7f@\x00\x00\x00\x00%\x1b~P\x00\x00\x00\x00&\x0ba@\x00\x00\x00\x00&\xfb`P\x00\x00\x00\x00'\xebC@\x00\x00\x00\x00(\xe4|\xd0\x00\x00\x00\x00)\x81Q@\x00\x00\x00\x00*\xe9H\xd0\x00\x00\x00\x00+a3@\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x9d\xcc\x00\x00\x00\x00\xa8\xc0\x01\x04\x00\x00\x9a\xb0\x00\x08LMT\x00+12\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xec =\x89\xac\x00\x00\x00\xac\x00\x00\x00\x11\x00\x00\x00Pacific/EnderburyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xc3,\xdb\x80\x00\x00\x00\x00\x12V\x04\xc0\x00\x00\x00\x00/\x059\xb0\x01\x02\x03\x00\x00\x00\x00\x00\x00\xff\xffW@\x00\x04\xff\xffeP\x00\x08\x00\x00\xb6\xd0\x00\x0c-00\x00-12\x00-11\x00+13\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a|\xdcU\x99\x00\x00\x00\x99\x00\x00\x00\x0f\x00\x00\x00Pacific/FakaofoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~7U\x88\x00\x00\x00\x00N\xfd\x99\xb0\x01\x02\xff\xff_x\x00\x00\xff\xffeP\x00\x04\x00\x00\xb6\xd0\x00\x08LMT\x00-11\x00+13\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd_yl\x8c\x01\x00\x00\x8c\x01\x00\x00\x0c\x00\x00\x00Pacific/FijiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x9a\x13\xb1\xc0\x00\x00\x00\x006;\x17\xe0\x00\x00\x00\x006\xd7\xfa`\x00\x00\x00\x008$4`\x00\x00\x00\x008\xb7\xdc`\x00\x00\x00\x00K\x11,\xe0\x00\x00\x00\x00K\xae\x0f`\x00\x00\x00\x00L\xc2\xea`\x00\x00\x00\x00MrA\xe0\x00\x00\x00\x00N\xa2\xcc`\x00\x00\x00\x00O\x1a\xc4\xe0\x00\x00\x00\x00P\x82\xae`\x00\x00\x00\x00P\xfa\xa6\xe0\x00\x00\x00\x00Rk\xca\xe0\x00\x00\x00\x00R\xdaz\xd0\x00\x00\x00\x00TT\xe7`\x00\x00\x00\x00T\xbaj\xe0\x00\x00\x00\x00V4\xc9`\x00\x00\x00\x00V\x9aL\xe0\x00\x00\x00\x00X\x1d\xe5\xe0\x00\x00\x00\x00Xz.\xe0\x00\x00\x00\x00Y\xfd\xc7\xe0\x00\x00\x00\x00ZZ\x10\xe0\x00\x00\x00\x00[\xdd\xa9\xe0\x00\x00\x00\x00\x5c9\xf2\xe0\x00\x00\x00\x00]\xc6\xc6`\x00\x00\x00\x00^\x19\xd4\xe0\x00\x00\x00\x00_\xde\x07`\x00\x00\x00\x00`\x02\xf1`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\xa7\xc0\x00\x00\x00\x00\xb6\xd0\x01\x04\x00\x00\xa8\xc0\x00\x08LMT\x00+13\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x10\x00\x00\x00Pacific/FunafutiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xe3w\x0a\xaf\x00\x00\x00\xaf\x00\x00\x00\x11\x00\x00\x00Pacific/GalapagosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\xb6\xa4L\x80\x00\x00\x00\x00\x1e\x18\xc4P\x00\x00\x00\x00+\x17\x0a\xe0\x00\x00\x00\x00+q\xf4P\x01\x03\x02\x03\xff\xff\xac\x00\x00\x00\xff\xff\xb9\xb0\x00\x04\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08LMT\x00-05\x00-06\x00\x0a<-06>6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc23\xa0\xbc\x84\x00\x00\x00\x84\x00\x00\x00\x0f\x00\x00\x00Pacific/GambierTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94PH\x04\x01\xff\xff\x81|\x00\x00\xff\xff\x81p\x00\x04LMT\x00-09\x00\x0a<-09>9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x13\x00\x00\x00Pacific/GuadalcanalTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94O3\x8c\x01\x00\x00\x95\xf4\x00\x00\x00\x00\x9a\xb0\x00\x04LMT\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FI\xfe\x14^\x01\x00\x00^\x01\x00\x00\x0c\x00\x00\x00Pacific/GuamTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x06\x00\x00\x00\x15\xff\xff\xff\xff\x14\xe1\xc5\xcc\xff\xff\xff\xff~6-L\xff\xff\xff\xff\xcb7\x95\xe0\xff\xff\xff\xff\xd0.\x89\xf0\xff\xff\xff\xff\xec7\xbe\x00\xff\xff\xff\xff\xef6\xf8\xf0\xff\xff\xff\xff\xfb\x9b\x00\x00\xff\xff\xff\xff\xfe?'\x8c\xff\xff\xff\xff\xff\x01\x1e\x00\xff\xff\xff\xff\xff]X\xf0\x00\x00\x00\x00\x00\x97,\x00\x00\x00\x00\x00\x01Fup\x00\x00\x00\x00\x02w\x0e\x00\x00\x00\x00\x00\x03&Wp\x00\x00\x00\x00\x07p\x97\x00\x00\x00\x00\x00\x07\xcc\xd1\xf0\x00\x00\x00\x00\x0c\x08\x91\x00\x00\x00\x00\x00\x0c|\x87,\x00\x00\x00\x00\x0d\xbf\x94\x80\x00\x00\x00\x00\x0ee\xa3p\x00\x00\x00\x00:C^`\x01\x02\x03\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\xff\xff64\x00\x00\x00\x00\x87\xb4\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x9a\xb0\x01\x0c\x00\x00\x8c\xa0\x00\x10LMT\x00GST\x00+09\x00GDT\x00ChST\x00\x0aChST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x10\x00\x00\x00Pacific/HonoluluTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xfft\xe0p\xbe\xff\xff\xff\xff\xbb\x05CH\xff\xff\xff\xff\xbb!qX\xff\xff\xff\xff\xcb\x89=\xc8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aI8\xff\xff\xff\xff\xd5\x8dsH\x01\x02\x01\x03\x04\x01\x05\xff\xffl\x02\x00\x00\xff\xfflX\x00\x04\xff\xffzh\x01\x08\xff\xffzh\x01\x0c\xff\xffzh\x01\x10\xff\xffs`\x00\x04LMT\x00HST\x00HDT\x00HWT\x00HPT\x00\x0aHST10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x10\x00\x00\x00Pacific/JohnstonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xfft\xe0p\xbe\xff\xff\xff\xff\xbb\x05CH\xff\xff\xff\xff\xbb!qX\xff\xff\xff\xff\xcb\x89=\xc8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aI8\xff\xff\xff\xff\xd5\x8dsH\x01\x02\x01\x03\x04\x01\x05\xff\xffl\x02\x00\x00\xff\xfflX\x00\x04\xff\xffzh\x01\x08\xff\xffzh\x01\x0c\xff\xffzh\x01\x10\xff\xffs`\x00\x04LMT\x00HST\x00HDT\x00HWT\x00HPT\x00\x0aHST10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xec =\x89\xac\x00\x00\x00\xac\x00\x00\x00\x0e\x00\x00\x00Pacific/KantonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xc3,\xdb\x80\x00\x00\x00\x00\x12V\x04\xc0\x00\x00\x00\x00/\x059\xb0\x01\x02\x03\x00\x00\x00\x00\x00\x00\xff\xffW@\x00\x04\xff\xffeP\x00\x08\x00\x00\xb6\xd0\x00\x0c-00\x00-12\x00-11\x00+13\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8=ku\xae\x00\x00\x00\xae\x00\x00\x00\x12\x00\x00\x00Pacific/KiritimatiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff~7H\x80\x00\x00\x00\x00\x12U\xf2\x00\x00\x00\x00\x00/\x05+\xa0\x01\x02\x03\xff\xffl\x80\x00\x00\xff\xffj\x00\x00\x04\xff\xffs`\x00\x0a\x00\x00\xc4\xe0\x00\x0eLMT\x00-1040\x00-10\x00+14\x00\x0a<+14>-14\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97n7\x1a\xf2\x00\x00\x00\xf2\x00\x00\x00\x0e\x00\x00\x00Pacific/KosraeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xff\x14\xe1\xb4\xb4\xff\xff\xff\xff~6\x1c4\xff\xff\xff\xff\x98\x11\x95\xd0\xff\xff\xff\xff\xa09\xf9\xf0\xff\xff\xff\xff\xc1\xed5\xd0\xff\xff\xff\xff\xc9\xea\x0a`\xff\xff\xff\xff\xd2\x11\x0e\xf0\xff\xff\xff\xff\xff\x86\x1bP\x00\x00\x00\x006\x8bg@\x01\x02\x03\x02\x04\x03\x02\x05\x02\xff\xffGL\x00\x00\x00\x00\x98\xcc\x00\x00\x00\x00\x9a\xb0\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x8c\xa0\x00\x0c\x00\x00\xa8\xc0\x00\x10LMT\x00+11\x00+09\x00+10\x00+12\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe8]*\xdb\x00\x00\x00\xdb\x00\x00\x00\x11\x00\x00\x00Pacific/KwajaleinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff~6\x18 \xff\xff\xff\xff\xc1\xed5\xd0\xff\xff\xff\xff\xc9\xea\x0a`\xff\xff\xff\xff\xcfF\x81\xf0\xff\xff\xff\xff\xff\x86\x1bP\x00\x00\x00\x00,v\x0e@\x01\x02\x03\x01\x04\x05\x00\x00\x9c\xe0\x00\x00\x00\x00\x9a\xb0\x00\x04\x00\x00\x8c\xa0\x00\x08\x00\x00~\x90\x00\x0c\xff\xffW@\x00\x10\x00\x00\xa8\xc0\x00\x14LMT\x00+11\x00+10\x00+09\x00-12\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00Pacific/MajuroTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D6\x83\xa1\x8b\x00\x00\x00\x8b\x00\x00\x00\x11\x00\x00\x00Pacific/MarquesasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x0a\xff\xff\xff\xff\x94PLH\x01\xff\xff}8\x00\x00\xff\xffzh\x00\x04LMT\x00-0930\x00\x0a<-0930>9:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x0e\x00\x00\x00Pacific/MidwayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xffn=\xc8\x08\xff\xff\xff\xff\x91\x05\xfb\x08\x01\x02\x00\x00\xb1x\x00\x00\xff\xff_\xf8\x00\x00\xff\xffeP\x00\x04LMT\x00SST\x00\x0aSST11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe2;Z\xf7\xb7\x00\x00\x00\xb7\x00\x00\x00\x0d\x00\x00\x00Pacific/NauruTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\xa3\xe7+\x04\xff\xff\xff\xff\xcc\x90\xe9\xc8\xff\xff\xff\xff\xd2C'\xf0\x00\x00\x00\x00\x11!\xa8\xe8\x01\x02\x01\x03\x00\x00\x9c|\x00\x00\x00\x00\xa1\xb8\x00\x04\x00\x00~\x90\x00\x0a\x00\x00\xa8\xc0\x00\x0eLMT\x00+1130\x00+09\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\xd60\x0c\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00Pacific/NiueTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff\xdf\xa1jL\xff\xff\xff\xff\xf5\xa6\xb8`\x01\x02\xff\xff`\xb4\x00\x00\xff\xff`\xa0\x00\x04\xff\xffeP\x00\x0aLMT\x00-1120\x00-11\x00\x0a<-11>11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xc2$\x92\xed\x00\x00\x00\xed\x00\x00\x00\x0f\x00\x00\x00Pacific/NorfolkTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x05\x00\x00\x00\x1a\xff\xff\xff\xff~6\x17\x88\xff\xff\xff\xff\xdcA\xf8\x80\x00\x00\x00\x00\x09\x0f\xcah\x00\x00\x00\x00\x09\xb5\xe7h\x00\x00\x00\x00V\x0f\xe6h\x00\x00\x00\x00]\x18\xb2P\x01\x02\x03\x02\x04\x04\x00\x00\x9dx\x00\x00\x00\x00\x9d\x80\x00\x04\x00\x00\xa1\xb8\x00\x0a\x00\x00\xaf\xc8\x01\x10\x00\x00\x9a\xb0\x00\x16LMT\x00+1112\x00+1130\x00+1230\x00+11\x00\x0a<+11>-11<+12>,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\xef\x97\xc6\xc6\x00\x00\x00\xc6\x00\x00\x00\x0e\x00\x00\x00Pacific/NoumeaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x92\xf5\xc4t\x00\x00\x00\x00\x0e\xe6\xbaP\x00\x00\x00\x00\x0fV\xbb\xc0\x00\x00\x00\x00\x10\xc6\x9cP\x00\x00\x00\x00\x117\xef@\x00\x00\x00\x002\xa0K\xf0\x00\x00\x00\x003\x18Dp\x02\x01\x02\x01\x02\x01\x02\x00\x00\x9c\x0c\x00\x00\x00\x00\xa8\xc0\x01\x04\x00\x00\x9a\xb0\x00\x08LMT\x00+12\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x11\x00\x00\x00Pacific/Pago_PagoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xffn=\xc8\x08\xff\xff\xff\xff\x91\x05\xfb\x08\x01\x02\x00\x00\xb1x\x00\x00\xff\xff_\xf8\x00\x00\xff\xffeP\x00\x04LMT\x00SST\x00\x0aSST11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xf8v\xdc\x94\x00\x00\x00\x94\x00\x00\x00\x0d\x00\x00\x00Pacific/PalauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xff\x14\xe1\xcfl\xff\xff\xff\xff~66\xec\x01\x02\xff\xff,\x94\x00\x00\x00\x00~\x14\x00\x00\x00\x00~\x90\x00\x04LMT\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfa\x0fA\x05\x99\x00\x00\x00\x99\x00\x00\x00\x10\x00\x00\x00Pacific/PitcairnTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff~7.\xf4\x00\x00\x00\x005DB\x08\x01\x02\xff\xff\x86\x0c\x00\x00\xff\xff\x88x\x00\x04\xff\xff\x8f\x80\x00\x0aLMT\x00-0830\x00-08\x00\x0a<-08>8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x0f\x00\x00\x00Pacific/PohnpeiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94O3\x8c\x01\x00\x00\x95\xf4\x00\x00\x00\x00\x9a\xb0\x00\x04LMT\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00Pacific/PonapeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94O3\x8c\x01\x00\x00\x95\xf4\x00\x00\x00\x00\x9a\xb0\x00\x04LMT\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x14\x00\x00\x00Pacific/Port_MoresbyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xe3\xa3S\x96\x01\x00\x00\x96\x01\x00\x00\x11\x00\x00\x00Pacific/RarotongaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff|L\xdc\xc8\xff\xff\xff\xff\xdf\xa1`\xc8\x00\x00\x00\x00\x10\xac\x1b(\x00\x00\x00\x00\x11?\xb5\x18\x00\x00\x00\x00\x12y\x81 \x00\x00\x00\x00\x13\x1f\x97\x18\x00\x00\x00\x00\x14Yc \x00\x00\x00\x00\x14\xffy\x18\x00\x00\x00\x00\x169E \x00\x00\x00\x00\x16\xe8\x95\x98\x00\x00\x00\x00\x18\x22a\xa0\x00\x00\x00\x00\x18\xc8w\x98\x00\x00\x00\x00\x1a\x02C\xa0\x00\x00\x00\x00\x1a\xa8Y\x98\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\x88;\x98\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1eh\x1d\x98\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 G\xff\x98\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x221\x1c\x18\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$\x10\xfe\x18\x00\x00\x00\x00%J\xca \x00\x00\x00\x00%\xf0\xe0\x18\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xd0\xc2\x18\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x00\x00\xbb\xb8\x00\x00\xff\xffj8\x00\x00\xff\xfflX\x00\x04\xff\xffs`\x00\x0a\xff\xffzh\x01\x0eLMT\x00-1030\x00-10\x00-0930\x00\x0a<-10>10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FI\xfe\x14^\x01\x00\x00^\x01\x00\x00\x0e\x00\x00\x00Pacific/SaipanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x06\x00\x00\x00\x15\xff\xff\xff\xff\x14\xe1\xc5\xcc\xff\xff\xff\xff~6-L\xff\xff\xff\xff\xcb7\x95\xe0\xff\xff\xff\xff\xd0.\x89\xf0\xff\xff\xff\xff\xec7\xbe\x00\xff\xff\xff\xff\xef6\xf8\xf0\xff\xff\xff\xff\xfb\x9b\x00\x00\xff\xff\xff\xff\xfe?'\x8c\xff\xff\xff\xff\xff\x01\x1e\x00\xff\xff\xff\xff\xff]X\xf0\x00\x00\x00\x00\x00\x97,\x00\x00\x00\x00\x00\x01Fup\x00\x00\x00\x00\x02w\x0e\x00\x00\x00\x00\x00\x03&Wp\x00\x00\x00\x00\x07p\x97\x00\x00\x00\x00\x00\x07\xcc\xd1\xf0\x00\x00\x00\x00\x0c\x08\x91\x00\x00\x00\x00\x00\x0c|\x87,\x00\x00\x00\x00\x0d\xbf\x94\x80\x00\x00\x00\x00\x0ee\xa3p\x00\x00\x00\x00:C^`\x01\x02\x03\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\xff\xff64\x00\x00\x00\x00\x87\xb4\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x9a\xb0\x01\x0c\x00\x00\x8c\xa0\x00\x10LMT\x00GST\x00+09\x00GDT\x00ChST\x00\x0aChST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x0d\x00\x00\x00Pacific/SamoaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xffn=\xc8\x08\xff\xff\xff\xff\x91\x05\xfb\x08\x01\x02\x00\x00\xb1x\x00\x00\xff\xff_\xf8\x00\x00\xff\xffeP\x00\x04LMT\x00SST\x00\x0aSST11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\xc1\xda\xcf\x85\x00\x00\x00\x85\x00\x00\x00\x0e\x00\x00\x00Pacific/TahitiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94PU\xb8\x01\xff\xffs\xc8\x00\x00\xff\xffs`\x00\x04LMT\x00-10\x00\x0a<-10>10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00Pacific/TarawaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97F\x91\xb3\xed\x00\x00\x00\xed\x00\x00\x00\x11\x00\x00\x00Pacific/TongatapuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\xd2E\x9c@\xff\xff\xff\xff\xef\x11\xe0\x10\x00\x00\x00\x007\xfbG\xd0\x00\x00\x00\x008\xd3}\xd0\x00\x00\x00\x00:\x04\x08P\x00\x00\x00\x00:r\xb8@\x00\x00\x00\x00;\xe3\xeaP\x00\x00\x00\x00-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00Pacific/TrukTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0c\x00\x00\x00Pacific/WakeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00Pacific/WallisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0b\x00\x00\x00Pacific/YapTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xfe\xe5\x9e\x9b\x03\x00\x00\x9b\x03\x00\x00\x06\x00\x00\x00PolandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xffV\xb6\xd0P\xff\xff\xff\xff\x99\xa8*\xd0\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xa0\x9a\xb6\x00\xff\xff\xff\xff\xa1e\xbd\x00\xff\xff\xff\xff\xa6}|`\xff\xff\xff\xff\xc8v\xde\x10\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x84\xba\x00\xff\xff\xff\xff\xd1\x95\x92p\xff\xff\xff\xff\xd2\x8a\xbb`\xff\xff\xff\xff\xd3b\xffp\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd5^\xad\x10\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\xff\xff\xff\xff\xe8T\xd2\x00\xff\xff\xff\xff\xe8\xf1\xb4\x80\xff\xff\xff\xff\xe9\xe1\xa5\x80\xff\xff\xff\xff\xea\xd1\x96\x80\xff\xff\xff\xff\xec\x14\x96\x00\xff\xff\xff\xff\xec\xba\xb3\x00\xff\xff\xff\xff\xed\xaa\xa4\x00\xff\xff\xff\xff\xee\x9a\x95\x00\xff\xff\xff\xff\xef\xd4Z\x00\xff\xff\xff\xff\xf0zw\x00\xff\xff\xff\xff\xf1\xb4<\x00\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3\x94\x1e\x00\xff\xff\xff\xff\xf4:;\x00\xff\xff\xff\xff\xf5}:\x80\xff\xff\xff\xff\xf6\x1a\x1d\x00\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\x8b\x0c\x00\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11d\x19\x80\x00\x00\x00\x00\x12T\x0a\x80\x00\x00\x00\x00\x13M6\x00\x00\x00\x00\x00\x143\xec\x80\x00\x00\x00\x00\x15#\xdd\x80\x00\x00\x00\x00\x16\x13\xce\x80\x00\x00\x00\x00\x17\x03\xbf\x80\x00\x00\x00\x00\x17\xf3\xb0\x80\x00\x00\x00\x00\x18\xe3\xa1\x80\x00\x00\x00\x00\x19\xd3\x92\x80\x00\x00\x00\x00\x1a\xc3\x83\x80\x00\x00\x00\x00\x1b\xbc\xaf\x00\x00\x00\x00\x00\x1c\xac\xa0\x00\x00\x00\x00\x00\x1d\x9c\x91\x00\x00\x00\x00\x00\x1e\x8c\x82\x00\x00\x00\x00\x00\x1f|s\x00\x00\x00\x00\x00 ld\x00\x00\x00\x00\x00!\x5cU\x00\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xec\x00\xff\xff\xff\xff\xe50 p\xff\xff\xff\xff\xe6!q\x00\xff\xff\xff\xff\xe7\x12\xa5p\xff\xff\xff\xff\xe8\x02\xa4\x80\xff\xff\xff\xff\xe8\xf3\xd8\xf0\xff\xff\xff\xff\xe9\xe3\xd8\x00\xff\xff\xff\xff\xea\xd5\x0cp\xff\xff\xff\xff\xeb\xc5\x0b\x80\xff\xff\xff\xff\xec\xb6?\xf0\xff\xff\xff\xff\xed\xf7\xfc\x00\xff\xff\xff\xff\xee\x98\xc4\xf0\xff\xff\xff\xff\xef\xd9/\x80\xff\xff\xff\xff\xf0y\xf8p\x00\x00\x00\x00\x07\xfcV\x00\x00\x00\x00\x00\x08\xed\x8ap\x00\x00\x00\x00\x09\xdd\x89\x80\x00\x00\x00\x00\x0a\xce\xbd\xf0\x00\x00\x00\x00\x11\xdb\xa1\x80\x00\x00\x00\x00\x12T\xddp\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x00\x00q\xe8\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x00\x08\x00\x00~\x90\x01\x0cLMT\x00CST\x00JST\x00CDT\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7X,Y\x9f\x01\x00\x00\x9f\x01\x00\x00\x03\x00\x00\x00ROKTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\x8b\xd7\xf0x\xff\xff\xff\xff\x92\xe6\x16\xf8\xff\xff\xff\xff\xd2C'\xf0\xff\xff\xff\xff\xd7e\x8fp\xff\xff\xff\xff\xd7\xee\x9d`\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xd9\xcd-\xe0\xff\xff\xff\xff\xda\xd7\x8a\xf0\xff\xff\xff\xff\xdb\xad\x0f\xe0\xff\xff\xff\xff\xdc\xe6\xe2\xf0\xff\xff\xff\xff\xdd\x8c\xf1\xe0\xff\xff\xff\xff\xe2O)\xf0\xff\xff\xff\xff\xe4k\xb7\xf8\xff\xff\xff\xff\xe5\x13\x18h\xff\xff\xff\xff\xe6b\x03x\xff\xff\xff\xff\xe7\x11L\xe8\xff\xff\xff\xff\xe8/px\xff\xff\xff\xff\xe8\xe7\xf4h\xff\xff\xff\xff\xea\x0fRx\xff\xff\xff\xff\xea\xc7\xd6h\xff\xff\xff\xff\xeb\xef4x\xff\xff\xff\xff\xec\xa7\xb8h\xff\xff\xff\xff\xed\xcf\x16x\xff\xff\xff\xff\xee\x87\x9ah\xff\xff\xff\xff\xf05qx\x00\x00\x00\x00 \xa3`\x90\x00\x00\x00\x00!ng\x90\x00\x00\x00\x00\x22\x83B\x90\x00\x00\x00\x00#NI\x90\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x04\x03\x04\x03\x04\x00\x00w\x08\x00\x00\x00\x00w\x88\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x8c\xa0\x01\x0c\x00\x00~\x90\x00\x04\x00\x00\x85\x98\x01\x0cLMT\x00KST\x00JST\x00KDT\x00\x0aKST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x09\x00\x00\x00SingaporeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00 \xff\xff\xff\xff~6S\xa3\xff\xff\xff\xff\x86\x83\x85\xa3\xff\xff\xff\xff\xbagN\x90\xff\xff\xff\xff\xc0\x0a\xe4`\xff\xff\xff\xff\xca\xb3\xe5`\xff\xff\xff\xff\xcb\x91_\x08\xff\xff\xff\xff\xd2Hm\xf0\x00\x00\x00\x00\x16\x91\xee\x00\x01\x02\x03\x04\x05\x06\x05\x07\x00\x00a]\x00\x00\x00\x00a]\x00\x04\x00\x00bp\x00\x08\x00\x00g \x01\x0c\x00\x00g \x00\x0c\x00\x00ix\x00\x12\x00\x00~\x90\x00\x18\x00\x00p\x80\x00\x1cLMT\x00SMT\x00+07\x00+0720\x00+0730\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07W\x10\xd1\xb0\x04\x00\x00\xb0\x04\x00\x00\x06\x00\x00\x00TurkeyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x06\x00\x00\x00\x19\xff\xff\xff\xffV\xb6\xc8\xd8\xff\xff\xff\xff\x90\x8b\xf5\x98\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xbe\xd0\xff\xff\xff\xff\xa2ec\xe0\xff\xff\xff\xff\xa3{\x82P\xff\xff\xff\xff\xa4N\x80`\xff\xff\xff\xff\xa5?\xb4\xd0\xff\xff\xff\xff\xa6%'\xe0\xff\xff\xff\xff\xa7'\x7f\xd0\xff\xff\xff\xff\xaa((`\xff\xff\xff\xff\xaa\xe1\xfd\xd0\xff\xff\xff\xff\xab\xf9\x89\xe0\xff\xff\xff\xff\xac\xc31P\xff\xff\xff\xff\xc8\x81?\xe0\xff\xff\xff\xff\xc9\x01\x13P\xff\xff\xff\xff\xc9J\xf5`\xff\xff\xff\xff\xca\xce\x80P\xff\xff\xff\xff\xcb\xcb\xae`\xff\xff\xff\xff\xd2k\x09P\xff\xff\xff\xff\xd3\xa29`\xff\xff\xff\xff\xd4C\x02P\xff\xff\xff\xff\xd5L\x0d\xe0\xff\xff\xff\xff\xd6){\xd0\xff\xff\xff\xff\xd7+\xef\xe0\xff\xff\xff\xff\xd8\x09]\xd0\xff\xff\xff\xff\xd9\x02\x97`\xff\xff\xff\xff\xd9\xe9?\xd0\xff\xff\xff\xff\xda\xeb\xb3\xe0\xff\xff\xff\xff\xdb\xd2\x5cP\xff\xff\xff\xff\xdc\xd4\xd0`\xff\xff\xff\xff\xdd\xb2>P\xff\xff\xff\xff\xf1\xf4\xb9`\xff\xff\xff\xff\xf4b\xefP\xff\xff\xff\xff\xf5h\x06`\xff\xff\xff\xff\xf6\x1f8\xd0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x079\x9ap\x00\x00\x00\x00\x07\xfbu\x00\x00\x00\x00\x00\x09\x19|p\x00\x00\x00\x00\x09\xd0\xcb\x00\x00\x00\x00\x00\x0a\xf9^p\x00\x00\x00\x00\x0b\xb1\xfe\x80\x00\x00\x00\x00\x0c\xd9@p\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\xa6\xadp\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x0f\xf8\x11P\x00\x00\x00\x00\x19\x89\xb0p\x00\x00\x00\x00\x19\xdc\xb0\xe0\x00\x00\x00\x00\x1b\xe6\xd0\xf0\x00\x00\x00\x00\x1c\xc6\xef\xf0\x00\x00\x00\x00\x1d\x9b1p\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x8b\x83\xf0\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8f\xdd\x90\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S8\xbe\x10\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V>\x9e\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00W\xcf.P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x00\x00\x1b(\x00\x00\x00\x00\x1bh\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0d\x00\x00*0\x00\x11\x00\x008@\x01\x15LMT\x00IMT\x00EEST\x00EET\x00+03\x00+04\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00UCTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x11Q\x06\xd1\x03\x00\x00\xd1\x03\x00\x00\x09\x00\x00\x00US/AlaskaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00(\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87AH\xff\xff\xff\xff\xcb\x896\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aB0\xff\xff\xff\xff\xfa\xd2G\xa0\xff\xff\xff\xff\xfe\xb8c@\xff\xff\xff\xff\xff\xa8F0\x00\x00\x00\x00\x00\x98E@\x00\x00\x00\x00\x01\x88(0\x00\x00\x00\x00\x02x'@\x00\x00\x00\x00\x03qD\xb0\x00\x00\x00\x00\x04aC\xc0\x00\x00\x00\x00\x05Q&\xb0\x00\x00\x00\x00\x06A%\xc0\x00\x00\x00\x00\x071\x08\xb0\x00\x00\x00\x00\x07\x8d_\xc0\x00\x00\x00\x00\x09\x10\xea\xb0\x00\x00\x00\x00\x09\xad\xdb@\x00\x00\x00\x00\x0a\xf0\xcc\xb0\x00\x00\x00\x00\x0b\xe0\xcb\xc0\x00\x00\x00\x00\x0c\xd9\xe90\x00\x00\x00\x00\x0d\xc0\xad\xc0\x00\x00\x00\x00\x0e\xb9\xcb0\x00\x00\x00\x00\x0f\xa9\xca@\x00\x00\x00\x00\x10\x99\xad0\x00\x00\x00\x00\x11\x89\xac@\x00\x00\x00\x00\x12y\x8f0\x00\x00\x00\x00\x13i\x8e@\x00\x00\x00\x00\x14Yq0\x00\x00\x00\x00\x15Ip@\x00\x00\x00\x00\x169S0\x00\x00\x00\x00\x17)R@\x00\x00\x00\x00\x18\x22o\xb0\x00\x00\x00\x00\x19\x094@\x00\x00\x00\x00\x1a\x02Q\xb0\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xc4\xf8\x00\x00\xff\xffsx\x00\x00\xff\xffs`\x00\x04\xff\xff\x81p\x01\x08\xff\xff\x81p\x01\x0c\xff\xffs`\x00\x10\xff\xff\x81p\x01\x15\xff\xff\x81p\x00\x1a\xff\xff\x8f\x80\x01\x1e\xff\xff\x81p\x00#LMT\x00AST\x00AWT\x00APT\x00AHST\x00AHDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0b\x00\x00\x00US/AleutianTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00!\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87Z^\xff\xff\xff\xff\xcb\x89D\xd0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aP@\xff\xff\xff\xff\xfa\xd2U\xb0\xff\xff\xff\xff\xfe\xb8qP\xff\xff\xff\xff\xff\xa8T@\x00\x00\x00\x00\x00\x98SP\x00\x00\x00\x00\x01\x886@\x00\x00\x00\x00\x02x5P\x00\x00\x00\x00\x03qR\xc0\x00\x00\x00\x00\x04aQ\xd0\x00\x00\x00\x00\x05Q4\xc0\x00\x00\x00\x00\x06A3\xd0\x00\x00\x00\x00\x071\x16\xc0\x00\x00\x00\x00\x07\x8dm\xd0\x00\x00\x00\x00\x09\x10\xf8\xc0\x00\x00\x00\x00\x09\xad\xe9P\x00\x00\x00\x00\x0a\xf0\xda\xc0\x00\x00\x00\x00\x0b\xe0\xd9\xd0\x00\x00\x00\x00\x0c\xd9\xf7@\x00\x00\x00\x00\x0d\xc0\xbb\xd0\x00\x00\x00\x00\x0e\xb9\xd9@\x00\x00\x00\x00\x0f\xa9\xd8P\x00\x00\x00\x00\x10\x99\xbb@\x00\x00\x00\x00\x11\x89\xbaP\x00\x00\x00\x00\x12y\x9d@\x00\x00\x00\x00\x13i\x9cP\x00\x00\x00\x00\x14Y\x7f@\x00\x00\x00\x00\x15I~P\x00\x00\x00\x00\x169a@\x00\x00\x00\x00\x17)`P\x00\x00\x00\x00\x18\x22}\xc0\x00\x00\x00\x00\x19\x09BP\x00\x00\x00\x00\x1a\x02_\xc0\x00\x00\x00\x00\x1a+\x22 \x00\x00\x00\x00\x1a\xf2P\xc0\x00\x00\x00\x00\x1b\xe23\xb0\x00\x00\x00\x00\x1c\xd22\xc0\x00\x00\x00\x00\x1d\xc2\x15\xb0\x00\x00\x00\x00\x1e\xb2\x14\xc0\x00\x00\x00\x00\x1f\xa1\xf7\xb0\x00\x00\x00\x00 vG@\x00\x00\x00\x00!\x81\xd9\xb0\x00\x00\x00\x00\x22V)@\x00\x00\x00\x00#j\xf60\x00\x00\x00\x00$6\x0b@\x00\x00\x00\x00%J\xd80\x00\x00\x00\x00&\x15\xed@\x00\x00\x00\x00'*\xba0\x00\x00\x00\x00'\xff\x09\xc0\x00\x00\x00\x00)\x0a\x9c0\x00\x00\x00\x00)\xde\xeb\xc0\x00\x00\x00\x00*\xea~0\x00\x00\x00\x00+\xbe\xcd\xc0\x00\x00\x00\x00,\xd3\x9a\xb0\x00\x00\x00\x00-\x9e\xaf\xc0\x00\x00\x00\x00.\xb3|\xb0\x00\x00\x00\x00/~\x91\xc0\x00\x00\x00\x000\x93^\xb0\x00\x00\x00\x001g\xae@\x00\x00\x00\x002s@\xb0\x00\x00\x00\x003G\x90@\x00\x00\x00\x004S\x22\xb0\x00\x00\x00\x005'r@\x00\x00\x00\x0063\x04\xb0\x00\x00\x00\x007\x07T@\x00\x00\x00\x008\x1c!0\x00\x00\x00\x008\xe76@\x00\x00\x00\x009\xfc\x030\x00\x00\x00\x00:\xc7\x18@\x00\x00\x00\x00;\xdb\xe50\x00\x00\x00\x00<\xb04\xc0\x00\x00\x00\x00=\xbb\xc70\x00\x00\x00\x00>\x90\x16\xc0\x00\x00\x00\x00?\x9b\xa90\x00\x00\x00\x00@o\xf8\xc0\x00\x00\x00\x00A\x84\xc5\xb0\x00\x00\x00\x00BO\xda\xc0\x00\x00\x00\x00Cd\xa7\xb0\x00\x00\x00\x00D/\xbc\xc0\x00\x00\x00\x00ED\x89\xb0\x00\x00\x00\x00E\xf3\xef@\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xab\xe2\x00\x00\xff\xffZb\x00\x00\xff\xffeP\x00\x04\xff\xffs`\x01\x08\xff\xffs`\x01\x0c\xff\xffeP\x00\x10\xff\xffs`\x01\x14\xff\xffs`\x00\x18\xff\xff\x81p\x01\x1d\xff\xffs`\x00\x19LMT\x00NST\x00NWT\x00NPT\x00BST\x00BDT\x00AHST\x00HDT\x00\x0aHST10HDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0a\x00\x00\x00US/ArizonaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xcf\x17\xdf\x1c\xff\xff\xff\xff\xcf\x8f\xe5\xac\xff\xff\xff\xff\xd0\x81\x1a\x1c\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\x02\x01\x02\x01\x02\x03\x02\x03\x02\x01\x02\xff\xff\x96\xee\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0cLMT\x00MDT\x00MST\x00MWT\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xdc\xa9=\xda\x06\x00\x00\xda\x06\x00\x00\x0a\x00\x00\x00US/CentralTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xa2\xcbt\x00\xff\xff\xff\xff\xa3\x83\xf7\xf0\xff\xff\xff\xff\xa4E\xd2\x80\xff\xff\xff\xff\xa5c\xd9\xf0\xff\xff\xff\xff\xa6S\xd9\x00\xff\xff\xff\xff\xa7\x15\x97p\xff\xff\xff\xff\xa83\xbb\x00\xff\xff\xff\xff\xa8\xfe\xb3\xf0\xff\xff\xff\xff\xaa\x13\x9d\x00\xff\xff\xff\xff\xaa\xde\x95\xf0\xff\xff\xff\xff\xab\xf3\x7f\x00\xff\xff\xff\xff\xac\xbew\xf0\xff\xff\xff\xff\xad\xd3a\x00\xff\xff\xff\xff\xae\x9eY\xf0\xff\xff\xff\xff\xaf\xb3C\x00\xff\xff\xff\xff\xb0~;\xf0\xff\xff\xff\xff\xb1\x9c_\x80\xff\xff\xff\xff\xb2gXp\xff\xff\xff\xff\xb3|A\x80\xff\xff\xff\xff\xb4G:p\xff\xff\xff\xff\xb5\x5c#\x80\xff\xff\xff\xff\xb6'\x1cp\xff\xff\xff\xff\xb7<\x05\x80\xff\xff\xff\xff\xb8\x06\xfep\xff\xff\xff\xff\xb9\x1b\xe7\x80\xff\xff\xff\xff\xb9\xe6\xe0p\xff\xff\xff\xff\xbb\x05\x04\x00\xff\xff\xff\xff\xbb\xc6\xc2p\xff\xff\xff\xff\xbc\xe4\xe6\x00\xff\xff\xff\xff\xbd\xaf\xde\xf0\xff\xff\xff\xff\xbe\xc4\xc8\x00\xff\xff\xff\xff\xbf\x8f\xc0\xf0\xff\xff\xff\xff\xc0Z\xd6\x00\xff\xff\xff\xff\xc1\xb0\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xad\xd4\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x01\x14LMT\x00CDT\x00CST\x00EST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x0f\x00\x00\x00US/East-IndianaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcaW\x22\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf:\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x9aG\xc8\xd0\x06\x00\x00\xd0\x06\x00\x00\x0a\x00\x00\x00US/EasternTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x03\xf0\x90\xff\xff\xff\xff\x9e\xa6\x1ep\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x86\x00p\xff\xff\xff\xff\xa1\x9a\xcd`\xff\xff\xff\xff\xa2e\xe2p\xff\xff\xff\xff\xa3\x83\xe9\xe0\xff\xff\xff\xff\xa4j\xaep\xff\xff\xff\xff\xa55\xa7`\xff\xff\xff\xff\xa6S\xca\xf0\xff\xff\xff\xff\xa7\x15\x89`\xff\xff\xff\xff\xa83\xac\xf0\xff\xff\xff\xff\xa8\xfe\xa5\xe0\xff\xff\xff\xff\xaa\x13\x8e\xf0\xff\xff\xff\xff\xaa\xde\x87\xe0\xff\xff\xff\xff\xab\xf3p\xf0\xff\xff\xff\xff\xac\xbei\xe0\xff\xff\xff\xff\xad\xd3R\xf0\xff\xff\xff\xff\xae\x9eK\xe0\xff\xff\xff\xff\xaf\xb34\xf0\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9\x1b\xd9p\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xc6\xb4`\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xc8\xf8W`\xff\xff\xff\xff\xca\x0d@p\xff\xff\xff\xff\xca\xd89`\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xd9\xe0\x83\xe0\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdb\xc0e\xe0\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5W.\xe0\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe77\x10\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xba\x9e\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x09\x00\x00\x00US/HawaiiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xfft\xe0p\xbe\xff\xff\xff\xff\xbb\x05CH\xff\xff\xff\xff\xbb!qX\xff\xff\xff\xff\xcb\x89=\xc8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aI8\xff\xff\xff\xff\xd5\x8dsH\x01\x02\x01\x03\x04\x01\x05\xff\xffl\x02\x00\x00\xff\xfflX\x00\x04\xff\xffzh\x01\x08\xff\xffzh\x01\x0c\xff\xffzh\x01\x10\xff\xffs`\x00\x04LMT\x00HST\x00HDT\x00HWT\x00HPT\x00\x0aHST10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x11\x00\x00\x00US/Indiana-StarkeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5W<\xf0\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x01\x02\x01\xff\xff\xae\xca\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x14\xe7\x03\x83\x03\x00\x00\x83\x03\x00\x00\x0b\x00\x00\x00US/MichiganTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x85\xbd\x22[\xff\xff\xff\xff\x99<\x94\x00\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xfb3\x90\x8c\xff\xff\xff\xff\xfb\xe8;\xe0\xff\xff\xff\xff\xfc\xd8:\xf0\xff\xff\xff\xff\xfd\xc8\x1d\xe0\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x0a\x00\xa3p\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\xff\xff\xb2%\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10\xff\xff\xc7\xc0\x01\x14LMT\x00CST\x00EST\x00EWT\x00EPT\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x0b\x00\x00\x00US/MountainTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xa2e\xfe\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4E\xe0\x90\xff\xff\xff\xff\xa4\x8f\xa6\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\x94\x00\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x9d\x94\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x22\x12\xfe\x0e\x05\x00\x00\x0e\x05\x00\x00\x0a\x00\x00\x00US/PacificTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x1a\xc0\xff\xff\xff\xff\x9e\xa6H\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xa0\x86*\xa0\xff\xff\xff\xff\xa1\x9a\xf7\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd6\xfet\x5c\xff\xff\xff\xff\xd8\x80\xad\x90\xff\xff\xff\xff\xda\xfe\xc3\x90\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xa5\x90\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x87\x90\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ei\x90\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xee\x90\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xd0\x90\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xb2\x90\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\x94\x90\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x91&\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10LMT\x00PDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x08\x00\x00\x00US/SamoaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xffn=\xc8\x08\xff\xff\xff\xff\x91\x05\xfb\x08\x01\x02\x00\x00\xb1x\x00\x00\xff\xff_\xf8\x00\x00\xff\xffeP\x00\x04LMT\x00SST\x00\x0aSST11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00UTCTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00UniversalTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1\xc1\xeb\x05\x8c\x03\x00\x00\x8c\x03\x00\x00\x04\x00\x00\x00W-SUTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00N\x00\x00\x00\x0b\x00\x00\x00&\xff\xff\xff\xffV\xb6\xc0\xc7\xff\xff\xff\xff\x9b_\x1e\xc7\xff\xff\xff\xff\x9d>\xf2y\xff\xff\xff\xff\x9e*\xee\xf9\xff\xff\xff\xff\x9e\xf79i\xff\xff\xff\xff\x9f\x84W\xf9\xff\xff\xff\xff\xa0\xd8l\xe9\xff\xff\xff\xff\xa1\x009\x80\xff\xff\xff\xff\xa1<\xa6@\xff\xff\xff\xff\xa4\x10m\xc0\xff\xff\xff\xff\xa4=2\xb0\xff\xff\xff\xff\xa5\x15h\xb0\xff\xff\xff\xff\xa5=\x03\xc0\xff\xff\xff\xff\xa7\x1eEP\xff\xff\xff\xff\xb5\xa4\x19`\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)x\xbf\x80\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x01\x03\x02\x03\x04\x02\x04\x05\x06\x05\x07\x05\x06\x08\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x09\x08\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x0a\x06\x00\x00#9\x00\x00\x00\x00#9\x00\x04\x00\x001\x87\x01\x08\x00\x00#w\x00\x04\x00\x00?\x97\x01\x0c\x00\x008@\x01\x11\x00\x00*0\x00\x15\x00\x00FP\x01\x19\x00\x00\x1c \x00\x1d\x00\x00*0\x01!\x00\x008@\x00\x15LMT\x00MMT\x00MST\x00MDST\x00MSD\x00MSK\x00+05\x00EET\x00EEST\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x91B\xc0\xee\x01\x00\x00\xee\x01\x00\x00\x03\x00\x00\x00WETTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x02\x00\x00\x00\x09\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xd5\xe0\x95\x00\x00\x00\x95\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x08\x00\x00Africa/BissauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x09\x00\x00Africa/BlantyrePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x09\x00\x00Africa/BrazzavillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x0a\x00\x00Africa/BujumburaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5#)\x16\x1d\x05\x00\x00\x1d\x05\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x0b\x00\x00Africa/CairoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001B\xb0;\x7f\x07\x00\x00\x7f\x07\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x10\x00\x00Africa/CasablancaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x1b\xeb\xdd2\x02\x00\x002\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x18\x00\x00Africa/CeutaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae\x1a\x00\x00Africa/ConakryPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x1b\x00\x00Africa/DakarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x1c\x00\x00Africa/Dar_es_SalaamPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9\x1c\x00\x00Africa/DjiboutiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\x1d\x00\x00Africa/DoualaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\xd3\xc6g&\x07\x00\x00&\x07\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\x1e\x00\x00Africa/El_AaiunPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17&\x00\x00Africa/FreetownPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6&\x00\x00Africa/GaboronePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00v'\x00\x00Africa/HararePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$(\x00\x00Africa/JohannesburgPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\xcf\x10n\xca\x01\x00\x00\xca\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13)\x00\x00Africa/JubaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06+\x00\x00Africa/KampalaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xadD\xef\xca\x01\x00\x00\xca\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1+\x00\x00Africa/KhartoumPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8-\x00\x00Africa/KigaliPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96.\x00\x00Africa/KinshasaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w/\x00\x00Africa/LagosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U0\x00\x00Africa/LibrevillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0081\x00\x00Africa/LomePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe31\x00\x00Africa/LuandaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc22\x00\x00Africa/LubumbashiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t3\x00\x00Africa/LusakaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x224\x00\x00Africa/MalaboPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x015\x00\x00Africa/MaputoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf5\x00\x00Africa/MaseruPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x986\x00\x00Africa/MbabanePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x827\x00\x00Africa/MogadishuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x99rU\xa4\x00\x00\x00\xa4\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o8\x00\x00Africa/MonroviaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@9\x00\x00Africa/NairobiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\x81\x09\x03\xa0\x00\x00\x00\xa0\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+:\x00\x00Africa/NdjamenaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8:\x00\x00Africa/NiameyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7;\x00\x00Africa/NouakchottPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88<\x00\x00Africa/OuagadougouPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:=\x00\x00Africa/Porto-NovoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc1\x0a\x8a\x84\xad\x00\x00\x00\xad\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d>\x00\x00Africa/Sao_TomePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7>\x00\x00Africa/TimbuktuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x7f2[\xaf\x01\x00\x00\xaf\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6?\x00\x00Africa/TripoliPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\xf4\x94\x0b\xc1\x01\x00\x00\xc1\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81A\x00\x00Africa/TunisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00m)\xb8P~\x02\x00\x00~\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00lC\x00\x00Africa/WindhoekPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17F\x00\x00America/AdakPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x11Q\x06\xd1\x03\x00\x00\xd1\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0aJ\x00\x00America/AnchoragePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0aN\x00\x00America/AnguillaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe9N\x00\x00America/AntiguaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x01V\x0dP\x02\x00\x00P\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7O\x00\x00America/AraguainaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xbf\xf5\xe5\xc4\x02\x00\x00\xc4\x02\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FR\x00\x00America/Argentina/Buenos_AiresPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FU\x00\x00America/Argentina/CatamarcaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00CX\x00\x00America/Argentina/ComodRivadaviaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E[\x00\x00America/Argentina/CordobaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00utZ\x1a\xb2\x02\x00\x00\xb2\x02\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@^\x00\x00America/Argentina/JujuyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00m\x07D\x0e\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'a\x00\x00America/Argentina/La_RiojaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x92Z\x8c\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,d\x00\x00America/Argentina/MendozaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ep\xb4c\xc4\x02\x00\x00\xc4\x02\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'g\x00\x00America/Argentina/Rio_GallegosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t*\x9b!\xb2\x02\x00\x00\xb2\x02\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'j\x00\x00America/Argentina/SaltaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcz=\xe1\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0em\x00\x00America/Argentina/San_JuanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x80\xb9\x5c\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13p\x00\x00America/Argentina/San_LuisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd8\xd6\xad\xd6\x02\x00\x00\xd6\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18s\x00\x00America/Argentina/TucumanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b}\xb6\x1e\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%v\x00\x00America/Argentina/UshuaiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 y\x00\x00America/ArubaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xa9y\x9at\x03\x00\x00t\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcy\x00\x00America/AsuncionPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9e}\x00\x00America/AtikokanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a~\x00\x00America/AtkaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00OKj\xc7\xaa\x02\x00\x00\xaa\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x82\x00\x00America/BahiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x0e\x01n\xd8\x02\x00\x00\xd8\x02\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x85\x00\x00America/Bahia_BanderasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l=\xad\xbe\x16\x01\x00\x00\x16\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x88\x00\x00America/BarbadosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85-\xb9\xf8\x8a\x01\x00\x00\x8a\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\x89\x00\x00America/BelemPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x89\xd8\xba\xee\x15\x04\x00\x00\x15\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\x8b\x00\x00America/BelizePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o\x8f\x00\x00America/Blanc-SablonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8Dz\x97\xae\x01\x00\x00\xae\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x90\x00\x00America/Boa_VistaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,g\xec\xec\xb3\x00\x00\x00\xb3\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/\x92\x00\x00America/BogotaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\xbe\x1a>\xe7\x03\x00\x00\xe7\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x93\x00\x00America/BoisePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xbf\xf5\xe5\xc4\x02\x00\x00\xc4\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x97\x00\x00America/Buenos_AiresPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\xba\xb2\x94s\x03\x00\x00s\x03\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x9a\x00\x00America/Cambridge_BayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\xfbn\xdb\xb8\x03\x00\x00\xb8\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbc\x9d\x00\x00America/Campo_GrandePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf2\x04\xde\xdd\x11\x02\x00\x00\x11\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\xa1\x00\x00America/CancunPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x8e\xee\x13\xbe\x00\x00\x00\xbe\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xa3\x00\x00America/CaracasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\xa4\x00\x00America/CatamarcaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1'\x07\xbd\x97\x00\x00\x00\x97\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc1\xa7\x00\x00America/CayennePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\xa8\x00\x00America/CaymanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xdc\xa9=\xda\x06\x00\x00\xda\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F\xa9\x00\x00America/ChicagoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x111\x04q\xb3\x02\x00\x00\xb3\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\xb0\x00\x00America/ChihuahuaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad\xf2L\x06\xce\x02\x00\x00\xce\x02\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/\xb3\x00\x00America/Ciudad_JuarezPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000\xb6\x00\x00America/Coral_HarbourPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\xb6\x00\x00America/CordobaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb1\xdd\x82x\xe8\x00\x00\x00\xe8\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe9\xb9\x00\x00America/Costa_RicaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xbb\x00\x00America/CrestonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f$*\xa0\xa6\x03\x00\x00\xa6\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\xbc\x00\x00America/CuiabaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xbf\x00\x00America/CuracaoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k\xc2\x0dx\xbf\x01\x00\x00\xbf\x01\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\xc0\x00\x00America/DanmarkshavnPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xe6\xf5J\x05\x04\x00\x00\x05\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\xc2\x00\x00America/DawsonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x10`\xc8\xab\x02\x00\x00\xab\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xc6\x00\x00America/Dawson_CreekPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xc9\x00\x00America/DenverPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x14\xe7\x03\x83\x03\x00\x00\x83\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\xce\x00\x00America/DetroitPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\xd1\x00\x00America/DominicaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xd2\x00\x00America/EdmontonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\xb0\xeau\xb4\x01\x00\x00\xb4\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92\xd6\x00\x00America/EirunepePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea$\xc1\xbf\xb0\x00\x00\x00\xb0\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xd8\x00\x00America/El_SalvadorPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\xd9\x00\x00America/EnsenadaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6@\x0dm\xa8\x05\x00\x00\xa8\x05\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84\xdd\x00\x00America/Fort_NelsonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xe3\x00\x00America/Fort_WaynePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x11Z\xde\xe4\x01\x00\x00\xe4\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\xe5\x00\x00America/FortalezaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\x94\xc7Kp\x03\x00\x00p\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb3\xe7\x00\x00America/Glace_BayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xf9v\x14\xc5\x03\x00\x00\xc5\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xeb\x00\x00America/GodthabPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\x85\xf6\xd1,\x06\x00\x00,\x06\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\xef\x00\x00America/Goose_BayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xc9I\xd0U\x03\x00\x00U\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\xf5\x00\x00America/Grand_TurkPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\xf9\x00\x00America/GrenadaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xfa\x00\x00America/GuadeloupePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x8a\x83S\xd4\x00\x00\x00\xd4\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xfa\x00\x00America/GuatemalaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xc3v\xe3\xb3\x00\x00\x00\xb3\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\xfb\x00\x00America/GuayaquilPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x05\xf3\x89\xb5\x00\x00\x00\xb5\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\xfc\x00\x00America/GuyanaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00):\x17-\x88\x06\x00\x00\x88\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9\xfd\x00\x00America/HalifaxPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x1c\x9e\x9a]\x04\x00\x00]\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x04\x01\x00America/HavanaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4MS\x99\x1e\x01\x00\x00\x1e\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\x08\x01\x00America/HermosilloPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x0a\x01\x00America/Indiana/IndianapolisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x0c\x01\x00America/Indiana/KnoxPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M/U\x9f7\x02\x00\x007\x02\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x10\x01\x00America/Indiana/MarengoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xd8N\x8c\xab\x02\x00\x00\xab\x02\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x13\x01\x00America/Indiana/PetersburgPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8\xb5K\xa6\x0a\x02\x00\x00\x0a\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfb\x15\x01\x00America/Indiana/Tell_CityPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x17\x89}q\x01\x00\x00q\x01\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x18\x01\x00America/Indiana/VevayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\xedsp.\x02\x00\x00.\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x19\x01\x00America/Indiana/VincennesPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfdH\xb79[\x02\x00\x00[\x02\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x1c\x01\x00America/Indiana/WinamacPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x1e\x01\x00America/IndianapolisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xbc\x09o1\x03\x00\x001\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a!\x01\x00America/InuvikPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xa0\xd6\x05W\x03\x00\x00W\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w$\x01\x00America/IqaluitPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%J\xd5\xebS\x01\x00\x00S\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfb'\x01\x00America/JamaicaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00utZ\x1a\xb2\x02\x00\x00\xb2\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{)\x01\x00America/JujuyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xc9\x1c\xd4\xc6\x03\x00\x00\xc6\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X,\x01\x00America/JuneauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdf\xe5\x8d\xc4\xda\x04\x00\x00\xda\x04\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00J0\x01\x00America/Kentucky/LouisvillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x1a|J\xcc\x03\x00\x00\xcc\x03\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]5\x01\x00America/Kentucky/MonticelloPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b9\x01\x00America/Knox_INPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87=\x01\x00America/KralendijkPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad`\x12\xe9\xaa\x00\x00\x00\xaa\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h>\x01\x00America/La_PazPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe7\xa1\x87\x1b\x01\x00\x00\x1b\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>?\x01\x00America/LimaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x22\x12\xfe\x0e\x05\x00\x00\x0e\x05\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83@\x01\x00America/Los_AngelesPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdf\xe5\x8d\xc4\xda\x04\x00\x00\xda\x04\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2E\x01\x00America/LouisvillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xccJ\x01\x00America/Lower_PrincesPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x8c\x8b\x92\xf6\x01\x00\x00\xf6\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0K\x01\x00America/MaceioPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5s\xb3\x5c'\x01\x00\x00'\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd2M\x01\x00America/ManaguaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\xcb'\xe9\x9c\x01\x00\x00\x9c\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&O\x01\x00America/ManausPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeeP\x01\x00America/MarigotPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x17j\xd2\xb2\x00\x00\x00\xb2\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xccQ\x01\x00America/MartiniquePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\xb7\xe2]\xb5\x01\x00\x00\xb5\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaeR\x01\x00America/MatamorosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xad=\x98\xce\x02\x00\x00\xce\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92T\x01\x00America/MazatlanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x92Z\x8c\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8eW\x01\x00America/MendozaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008O:\xbf\x95\x03\x00\x00\x95\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7fZ\x01\x00America/MenomineePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xbd\x809\x8e\x02\x00\x00\x8e\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C^\x01\x00America/MeridaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x87n\x14J\x02\x00\x00J\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd`\x01\x00America/MetlakatlaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x08\x89\x8c\x05\x03\x00\x00\x05\x03\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00wc\x01\x00America/Mexico_CityPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\xea\x94Y&\x02\x00\x00&\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xadf\x01\x00America/MiquelonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad\x8a\xf3O\xd5\x05\x00\x00\xd5\x05\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01i\x01\x00America/MonctonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L+\xe3u\x84\x02\x00\x00\x84\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03o\x01\x00America/MonterreyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x98\x00\x08\xc9\x03\x00\x00\xc9\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6q\x01\x00America/MontevideoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xafu\x01\x00America/MontrealPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92|\x01\x00America/MontserratPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s}\x01\x00America/NassauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x9aG\xc8\xd0\x06\x00\x00\xd0\x06\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x84\x01\x00America/New_YorkPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x8b\x01\x00America/NipigonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\xab\xd5\xf9\xcf\x03\x00\x00\xcf\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x92\x01\x00America/NomePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7-2f\xe4\x01\x00\x00\xe4\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-\x96\x01\x00America/NoronhaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7.\xb6*\x13\x04\x00\x00\x13\x04\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x98\x01\x00America/North_Dakota/BeulahPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\xeam\xef\xde\x03\x00\x00\xde\x03\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\x9c\x01\x00America/North_Dakota/CenterPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x1b\x8b(\xde\x03\x00\x00\xde\x03\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\xa0\x01\x00America/North_Dakota/New_SalemPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xf9v\x14\xc5\x03\x00\x00\xc5\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\xa4\x01\x00America/NuukPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1w\xb9\xca\xce\x02\x00\x00\xce\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\xa8\x01\x00America/OjinagaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xab\x01\x00America/PanamaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xa0\xd6\x05W\x03\x00\x00W\x03\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\xac\x01\x00America/PangnirtungPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xf9\x1d\xc9\xbb\x00\x00\x00\xbb\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xaf\x01\x00America/ParamariboPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xb0\x01\x00America/PhoenixPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4T\xbd\xeb5\x02\x00\x005\x02\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xb1\x01\x00America/Port-au-PrincePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\xb4\x01\x00America/Port_of_SpainPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\xb5\x01\x00America/Porto_AcrePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x81-\xa9\x8a\x01\x00\x00\x8a\x01\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\xb7\x01\x00America/Porto_VelhoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\xb8\x01\x00America/Puerto_RicoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x13\x9b\xb1\xc2\x04\x00\x00\xc2\x04\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\x01\x00America/Punta_ArenasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\xbe\x01\x00America/Rainy_RiverPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xdfH\x0d'\x03\x00\x00'\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\xc3\x01\x00America/Rankin_InletPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x03u\xf3\xe4\x01\x00\x00\xe4\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xc7\x01\x00America/RecifePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x96dK~\x02\x00\x00~\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00N\xc9\x01\x00America/ReginaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0I~D'\x03\x00\x00'\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\xcb\x01\x00America/ResolutePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\xcf\x01\x00America/Rio_BrancoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\xd1\x01\x00America/RosarioPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\xd4\x01\x00America/Santa_IsabelPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04,2h\x99\x01\x00\x00\x99\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\xd8\x01\x00America/SantaremPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x22_WJ\x05\x00\x00J\x05\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\xda\x01\x00America/SantiagoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x0f(\x08=\x01\x00\x00=\x01\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\xdf\x01\x00America/Santo_DomingoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d?\xdf\xda\xb8\x03\x00\x00\xb8\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf2\xe0\x01\x00America/Sao_PauloPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19a\x7f\x0a\xd8\x03\x00\x00\xd8\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xe4\x01\x00America/ScoresbysundPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xe8\x01\x00America/ShiprockPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81{\xc1\x92\xbc\x03\x00\x00\xbc\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\xed\x01\x00America/SitkaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\xf1\x01\x00America/St_BarthelemyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeah\x06\xd2V\x07\x00\x00V\x07\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xf1\x01\x00America/St_JohnsPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00r\xf9\x01\x00America/St_KittsPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Q\xfa\x01\x00America/St_LuciaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000\xfb\x01\x00America/St_ThomasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\xfc\x01\x00America/St_VincentPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xd8\x19\x9dp\x01\x00\x00p\x01\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xfc\x01\x00America/Swift_CurrentPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x13z\xe2\xc2\x00\x00\x00\xc2\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94\xfe\x01\x00America/TegucigalpaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x0d\xf7\xd3\xc7\x01\x00\x00\xc7\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\xff\x01\x00America/ThulePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\x01\x02\x00America/Thunder_BayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x08\x02\x00America/TijuanaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8d\x0c\x02\x00America/TorontoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o\x13\x02\x00America/TortolaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U9#\xbe2\x05\x00\x002\x05\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\x14\x02\x00America/VancouverPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae\x19\x02\x00America/VirginPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x1d\xee\x91\x05\x04\x00\x00\x05\x04\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b\x1a\x02\x00America/WhitehorsePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x1e\x02\x00America/WinnipegPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\xdb~\xab\xb2\x03\x00\x00\xb2\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc#\x02\x00America/YakutatPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb'\x02\x00America/YellowknifePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\x83\xf2b\x1f\x01\x00\x00\x1f\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd6+\x02\x00Antarctica/CaseyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95\xea\x06\xd3\xc5\x00\x00\x00\xc5\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#-\x02\x00Antarctica/DavisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16.\x02\x00Antarctica/DumontDUrvillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d?\xb2\x14\xd0\x03\x00\x00\xd0\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7.\x02\x00Antarctica/MacquariePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7N\xab\x8b\x98\x00\x00\x00\x98\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe92\x02\x00Antarctica/MawsonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb03\x02\x00Antarctica/McMurdoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95{\xf3\xa9w\x03\x00\x00w\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf37\x02\x00Antarctica/PalmerPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6\x89\xf71\x84\x00\x00\x00\x84\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99;\x02\x00Antarctica/RotheraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M<\x02\x00Antarctica/South_PolePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93@\x02\x00Antarctica/SyowaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf54\x89F\x9e\x00\x00\x00\x9e\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FA\x02\x00Antarctica/TrollPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x16\xf4\xe0\xaa\x00\x00\x00\xaa\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12B\x02\x00Antarctica/VostokPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xebB\x02\x00Arctic/LongyearbyenPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xddE\x02\x00Asia/AdenPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c9f;j\x02\x00\x00j\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x89F\x02\x00Asia/AlmatyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x0ds\xad\xa0\x03\x00\x00\xa0\x03\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1cI\x02\x00Asia/AmmanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xe0\xe7!\xe7\x02\x00\x00\xe7\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4L\x02\x00Asia/AnadyrPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x81\x18G^\x02\x00\x00^\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4O\x02\x00Asia/AqtauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\xfa\xb5\xbeg\x02\x00\x00g\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00zR\x02\x00Asia/AqtobePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x1bb2w\x01\x00\x00w\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0aU\x02\x00Asia/AshgabatPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x1bb2w\x01\x00\x00w\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xacV\x02\x00Asia/AshkhabadPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xa7^\xfah\x02\x00\x00h\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00OX\x02\x00Asia/AtyrauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7e&uv\x02\x00\x00v\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0Z\x02\x00Asia/BaghdadPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdav\x19z\x98\x00\x00\x00\x98\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80]\x02\x00Asia/BahrainPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x87\xb3<\xe8\x02\x00\x00\xe8\x02\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B^\x02\x00Asia/BakuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Qa\x02\x00Asia/BangkokPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\xbd\xedL\xf1\x02\x00\x00\xf1\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13b\x02\x00Asia/BarnaulPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\x11\xe1[\xdc\x02\x00\x00\xdc\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.e\x02\x00Asia/BeirutPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000]*\x1bj\x02\x00\x00j\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003h\x02\x00Asia/BishkekPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7f^]@\x01\x00\x00@\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7j\x02\x00Asia/BruneiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x1a\xdc\xca\xdc\x00\x00\x00\xdc\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000l\x02\x00Asia/CalcuttaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\xcd\xdf\x05\xee\x02\x00\x00\xee\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007m\x02\x00Asia/ChitaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81z&\x80k\x02\x00\x00k\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Mp\x02\x00Asia/ChoibalsanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5r\x02\x00Asia/ChongqingPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9at\x02\x00Asia/ChungkingPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x91\x87\xbb\xf7\x00\x00\x00\xf7\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Ov\x02\x00Asia/ColomboPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?Y\xaf\x19\xe7\x00\x00\x00\xe7\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00pw\x02\x00Asia/DaccaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\x07\xeci\xd2\x04\x00\x00\xd2\x04\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7fx\x02\x00Asia/DamascusPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?Y\xaf\x19\xe7\x00\x00\x00\xe7\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00|}\x02\x00Asia/DhakaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x92\x1a\x8c\xaa\x00\x00\x00\xaa\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b~\x02\x00Asia/DiliPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x7f\x02\x00Asia/DubaiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00's\x96\x1en\x01\x00\x00n\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x80\x02\x00Asia/DushanbePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]S\xbb\x12\xac\x03\x00\x00\xac\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2\x81\x02\x00Asia/FamagustaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xae\xc2\xd6\x86\x0b\x00\x00\x86\x0b\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\x85\x02\x00Asia/GazaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x91\x02\x00Asia/HarbinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d2\x08\xd6\x98\x0b\x00\x00\x98\x0b\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\x92\x02\x00Asia/HebronPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8!YF\xec\x00\x00\x00\xec\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x9e\x02\x00Asia/Ho_Chi_MinhPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x09\xfa-\x07\x03\x00\x00\x07\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x9f\x02\x00Asia/Hong_KongPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xba\xa3b\xc1R\x02\x00\x00R\x02\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\xa2\x02\x00Asia/HovdPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9l\x03\x12\xf8\x02\x00\x00\xf8\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xa5\x02\x00Asia/IrkutskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07W\x10\xd1\xb0\x04\x00\x00\xb0\x04\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\xa8\x02\x00Asia/IstanbulPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xad\xc5\xb1\xf8\x00\x00\x00\xf8\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xad\x02\x00Asia/JakartaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.>[K\xab\x00\x00\x00\xab\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xae\x02\x00Asia/JayapuraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\xaf\x02\x00Asia/JerusalemPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\xe2\x5c\xff\x9f\x00\x00\x00\x9f\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb3\xb3\x02\x00Asia/KabulPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x9cf>\xd7\x02\x00\x00\xd7\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\xb4\x02\x00Asia/KamchatkaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009Y\xb7\xf1\x0a\x01\x00\x00\x0a\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xb7\x02\x00Asia/KarachiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x1d\xc6\x1b\x85\x00\x00\x00\x85\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb1\xb8\x02\x00Asia/KashgarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8bSnT\xa1\x00\x00\x00\xa1\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xb9\x02\x00Asia/KathmanduPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8bSnT\xa1\x00\x00\x00\xa1\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-\xba\x02\x00Asia/KatmanduPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83g\x95M\x07\x03\x00\x00\x07\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9\xba\x02\x00Asia/KhandygaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x1a\xdc\xca\xdc\x00\x00\x00\xdc\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\xbe\x02\x00Asia/KolkataPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L\xe0\x91y\xe5\x02\x00\x00\xe5\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\xbf\x02\x00Asia/KrasnoyarskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\xc2\x02\x00Asia/Kuala_LumpurPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7f^]@\x01\x00\x00@\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\xc3\x02\x00Asia/KuchingPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdd\xc4\x02\x00Asia/KuwaitPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d?v\x0c\x17\x03\x00\x00\x17\x03\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b\xc5\x02\x00Asia/MacaoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d?v\x0c\x17\x03\x00\x00\x17\x03\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xc8\x02\x00Asia/MacauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4_P\x18\xef\x02\x00\x00\xef\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\xcc\x02\x00Asia/MagadanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xc9\xd4\x5c\xbe\x00\x00\x00\xbe\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\xcf\x02\x00Asia/MakassarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\xaf\xdf\x1c\xee\x00\x00\x00\xee\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\xd0\x02\x00Asia/ManilaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\xd1\x02\x00Asia/MuscatPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1eX\xc3aU\x02\x00\x00U\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\xd1\x02\x00Asia/NicosiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\x9a\x90\xf7\xd6\x02\x00\x00\xd6\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\xd4\x02\x00Asia/NovokuznetskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)p\x1cX\xf1\x02\x00\x00\xf1\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\xd7\x02\x00Asia/NovosibirskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\x11\xea\xa2\xe5\x02\x00\x00\xe5\x02\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\xda\x02\x00Asia/OmskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\xe9\xd1\xd8q\x02\x00\x00q\x02\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xdd\x02\x00Asia/OralPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe0\x02\x00Asia/Phnom_PenhPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\xa5\x81e\xf7\x00\x00\x00\xf7\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdc\xe0\x02\x00Asia/PontianakPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\xc1\x1eB\xb7\x00\x00\x00\xb7\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xe1\x02\x00Asia/PyongyangPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdav\x19z\x98\x00\x00\x00\x98\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe2\xe2\x02\x00Asia/QatarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb5\xc4\x8f\x9cp\x02\x00\x00p\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2\xe3\x02\x00Asia/QostanayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\xce\x9cGp\x02\x00\x00p\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xe6\x02\x00Asia/QyzylordaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xe8\x02\x00Asia/RangoonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe\xe9\x02\x00Asia/RiyadhPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8!YF\xec\x00\x00\x00\xec\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l\xea\x02\x00Asia/SaigonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x15II\xf3\x02\x00\x00\xf3\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xeb\x02\x00Asia/SakhalinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w\x0dD\x07n\x01\x00\x00n\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\xee\x02\x00Asia/SamarkandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7X,Y\x9f\x01\x00\x00\x9f\x01\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\xf0\x02\x00Asia/SeoulPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf2\x02\x00Asia/ShanghaiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\xf3\x02\x00Asia/SingaporePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4Z\xdf\x90\xe6\x02\x00\x00\xe6\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xf4\x02\x00Asia/SrednekolymskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xf0BB\xff\x01\x00\x00\xff\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xf7\x02\x00Asia/TaipeiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xe27Yn\x01\x00\x00n\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\xfa\x02\x00Asia/TashkentPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\xbe\xa8\xc7u\x02\x00\x00u\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\xfb\x02\x00Asia/TbilisiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xdb?\xec,\x03\x00\x00,\x03\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xfe\x02\x00Asia/TehranPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\x01\x03\x00Asia/Tel_AvivPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j$\xcd\xf4\x9a\x00\x00\x00\x9a\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x06\x03\x00Asia/ThimbuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j$\xcd\xf4\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcb\x06\x03\x00Asia/ThimphuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xf4\xaeg\xd5\x00\x00\x00\xd5\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\x07\x03\x00Asia/TokyoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[u\x99q\xf1\x02\x00\x00\xf1\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x08\x03\x00Asia/TomskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xc9\xd4\x5c\xbe\x00\x00\x00\xbe\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\x0b\x03\x00Asia/Ujung_PandangPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\xf4\xb6R\x02\x00\x00R\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\x0c\x03\x00Asia/UlaanbaatarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\xf4\xb6R\x02\x00\x00R\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x0f\x03\x00Asia/Ulan_BatorPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x1d\xc6\x1b\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92\x11\x03\x00Asia/UrumqiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w\x86\x8d^\x03\x03\x00\x00\x03\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x12\x03\x00Asia/Ust-NeraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x15\x03\x00Asia/VientianePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d%\x05\xd8\xe6\x02\x00\x00\xe6\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x16\x03\x00Asia/VladivostokPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\xb0\x03\xe9\xe5\x02\x00\x00\xe5\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F\x19\x03\x00Asia/YakutskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x1c\x03\x00Asia/YangonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xea\x18\xd4\xf8\x02\x00\x00\xf8\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\x1d\x03\x00Asia/YekaterinburgPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x95-\xad\xc4\x02\x00\x00\xc4\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a \x03\x00Asia/YerevanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x8dY\x80\xad\x05\x00\x00\xad\x05\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O#\x03\x00Atlantic/AzoresPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l&\x04\x99\x00\x04\x00\x00\x00\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00))\x03\x00Atlantic/BermudaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf|7\xb3\xde\x01\x00\x00\xde\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W-\x03\x00Atlantic/CanaryPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x97N\xad\xaf\x00\x00\x00\xaf\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b/\x03\x00Atlantic/Cape_VerdePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\x0e\xbdm\xb9\x01\x00\x00\xb9\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B0\x03\x00Atlantic/FaeroePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\x0e\xbdm\xb9\x01\x00\x00\xb9\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(2\x03\x00Atlantic/FaroePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d4\x03\x00Atlantic/Jan_MayenPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001)7\xad\xad\x05\x00\x00\xad\x05\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe6\x03\x00Atlantic/MadeiraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9<\x03\x00Atlantic/ReykjavikPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f-\xad\xd7\x84\x00\x00\x00\x84\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b=\x03\x00Atlantic/South_GeorgiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C>\x03\x00Atlantic/St_HelenaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\xcf^\xb0\x15\x03\x00\x00\x15\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf5>\x03\x00Atlantic/StanleyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008B\x03\x00Australia/ACTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ff~\xd5\x99\x03\x00\x00\x99\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xebE\x03\x00Australia/AdelaidePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xba\xde\xd3!\x01\x00\x00!\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4I\x03\x00Australia/BrisbanePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xca#\x7f\xad\x03\x00\x00\xad\x03\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05K\x03\x00Australia/Broken_HillPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5N\x03\x00Australia/CanberraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9dR\x03\x00Australia/CurriePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8R\x1a\x1b\xea\x00\x00\x00\xea\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6V\x03\x00Australia/DarwinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2\xdc\xba\xca:\x01\x00\x00:\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xceW\x03\x00Australia/EuclaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005Y\x03\x00Australia/HobartPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o3\xdaR\xb4\x02\x00\x00\xb4\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00N]\x03\x00Australia/LHIPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x95\xbd\x12E\x01\x00\x00E\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-`\x03\x00Australia/LindemanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o3\xdaR\xb4\x02\x00\x00\xb4\x02\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2a\x03\x00Australia/Lord_HowePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xe1\xc1\xa9\x88\x03\x00\x00\x88\x03\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87d\x03\x00Australia/MelbournePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@h\x03\x00Australia/NSWPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8R\x1a\x1b\xea\x00\x00\x00\xea\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf3k\x03\x00Australia/NorthPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xbb\xca\x1a2\x01\x00\x002\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0am\x03\x00Australia/PerthPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xba\xde\xd3!\x01\x00\x00!\x01\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00in\x03\x00Australia/QueenslandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ff~\xd5\x99\x03\x00\x00\x99\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbco\x03\x00Australia/SouthPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82s\x03\x00Australia/SydneyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008w\x03\x00Australia/TasmaniaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xe1\xc1\xa9\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S{\x03\x00Australia/VictoriaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xbb\xca\x1a2\x01\x00\x002\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x7f\x03\x00Australia/WestPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xca#\x7f\xad\x03\x00\x00\xad\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00i\x80\x03\x00Australia/YancowinnaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x84\x03\x00Brazil/AcrePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7-2f\xe4\x01\x00\x00\xe4\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x86\x03\x00Brazil/DeNoronhaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d?\xdf\xda\xb8\x03\x00\x00\xb8\x03\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x88\x03\x00Brazil/EastPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\xcb'\xe9\x9c\x01\x00\x00\x9c\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x8c\x03\x00Brazil/WestPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x9aM\xbem\x02\x00\x00m\x02\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcb\x8d\x03\x00CETPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x8b\x99\x1e\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x90\x03\x00CST6CDTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00):\x17-\x88\x06\x00\x00\x88\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x94\x03\x00Canada/AtlanticPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\x9a\x03\x00Canada/CentralPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\xa0\x03\x00Canada/EasternPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\xa7\x03\x00Canada/MountainPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeah\x06\xd2V\x07\x00\x00V\x07\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc\xaa\x03\x00Canada/NewfoundlandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U9#\xbe2\x05\x00\x002\x05\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83\xb2\x03\x00Canada/PacificPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x96dK~\x02\x00\x00~\x02\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1\xb7\x03\x00Canada/SaskatchewanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x1d\xee\x91\x05\x04\x00\x00\x05\x04\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\xba\x03\x00Canada/YukonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x22_WJ\x05\x00\x00J\x05\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\xbe\x03\x00Chile/ContinentalPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?X'\x8e\x96\x04\x00\x00\x96\x04\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\xc4\x03\x00Chile/EasterIslandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x1c\x9e\x9a]\x04\x00\x00]\x04\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xc8\x03\x00CubaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`l\x8d~\xf1\x01\x00\x00\xf1\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xcd\x03\x00EETPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00tX\xbe\xe4o\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\xcf\x03\x00ESTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7/\xebT\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\xd0\x03\x00EST5EDTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5#)\x16\x1d\x05\x00\x00\x1d\x05\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfb\xd3\x03\x00EgyptPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\xd6jL\xd8\x05\x00\x00\xd8\x05\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\xd9\x03\x00EirePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\xdf\x03\x00Etc/GMTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc9\xdf\x03\x00Etc/GMT+0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\xb8\xe8\x86q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\xe0\x03\x00Etc/GMT+1PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8e\x1569r\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\xe0\x03\x00Etc/GMT+10PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\xb9\xbe\x9dr\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\xe1\x03\x00Etc/GMT+11PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\xf38cr\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\xe2\x03\x00Etc/GMT+12PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9{\xa2qq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xe2\x03\x00Etc/GMT+2PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\xcb\xe9Qq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xe3\x03\x00Etc/GMT+3PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\xfaFDq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf5\xe3\x03\x00Etc/GMT+4PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4X\x9b\xf3q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8d\xe4\x03\x00Etc/GMT+5PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x9b\xd1\x04q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\xe5\x03\x00Etc/GMT+6PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84+\x9a$q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xe5\x03\x00Etc/GMT+7PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\xf8\x8f/q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\xe6\x03\x00Etc/GMT+8PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84\x19\xb3\x09q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\xe6\x03\x00Etc/GMT+9PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\xe7\x03\x00Etc/GMT-0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\x1ac\xc3r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xe8\x03\x00Etc/GMT-1PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9|\xbd7s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\xe8\x03\x00Etc/GMT-10PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xab\xd1Is\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\xe9\x03\x00Etc/GMT-11PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\x19s\x81s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\xe9\x03\x00Etc/GMT-12PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90`N\xe8s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\xea\x03\x00Etc/GMT-13PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,{\xdc;s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \xeb\x03\x00Etc/GMT-14PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbc\x19y\x04r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\xeb\x03\x00Etc/GMT-2PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9c\xfcm\x99r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\xec\x03\x00Etc/GMT-3PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k\x19\xfe\xe5\x9e\x9b\x03\x00\x00\x9b\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\xc2\x04\x00Europe/WarsawPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1C\xf9\xa1\xde\x01\x00\x00\xde\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xc6\x04\x00Europe/ZagrebPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x81\xbf~.\x02\x00\x00.\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x86\xc8\x04\x00Europe/ZaporozhyePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Dd#\xc4\xf1\x01\x00\x00\xf1\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xca\x04\x00Europe/ZurichPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\x80c$q\x00\x00\x00q\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xcc\x04\x00FactoryPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95\xcd\x04\x00GBPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4\xd3\x04\x00GB-EirePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xda\x04\x00GMTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\xda\x04\x00GMT+0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\xdb\x04\x00GMT-0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\xdc\x04\x00GMT0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d\xdc\x04\x00GreenwichPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xf7\xfawp\x00\x00\x00p\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xdd\x04\x00HSTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x09\xfa-\x07\x03\x00\x00\x07\x03\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\xdd\x04\x00HongkongPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xe0\x04\x00IcelandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98\xe1\x04\x00Indian/AntananarivoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\xb0W\x14\x98\x00\x00\x00\x98\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xe2\x04\x00Indian/ChagosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00K\xe3\x04\x00Indian/ChristmasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\xe4\x04\x00Indian/CocosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe4\x04\x00Indian/ComoroPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb9\xb2Z\xac\x98\x00\x00\x00\x98\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xe5\x04\x00Indian/KerguelenPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\xe6\x04\x00Indian/MahePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb9\xb2Z\xac\x98\x00\x00\x00\x98\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\xe7\x04\x00Indian/MaldivesPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xed=\x98\xb3\x00\x00\x00\xb3\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\xe8\x04\x00Indian/MauritiusPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfa\xe8\x04\x00Indian/MayottePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\xe9\x04\x00Indian/ReunionPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xdb?\xec,\x03\x00\x00,\x03\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xea\x04\x00IranPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\xed\x04\x00IsraelPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%J\xd5\xebS\x01\x00\x00S\x01\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\xf2\x04\x00JamaicaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xf4\xaeg\xd5\x00\x00\x00\xd5\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xf3\x04\x00JapanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe8]*\xdb\x00\x00\x00\xdb\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\xf4\x04\x00KwajaleinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x7f2[\xaf\x01\x00\x00\xaf\x01\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\xf5\x04\x00LibyaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\x9d\x1b\xc9m\x02\x00\x00m\x02\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00~\xf7\x04\x00METPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf5\x8d\x99\x92o\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\xfa\x04\x00MSTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6h\xcac\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9c\xfa\x04\x00MST7MDTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\xfe\x04\x00Mexico/BajaNortePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xad=\x98\xce\x02\x00\x00\xce\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x02\x05\x00Mexico/BajaSurPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x08\x89\x8c\x05\x03\x00\x00\x05\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\x05\x05\x00Mexico/GeneralPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd2\x08\x05\x00NZPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xc5FF(\x03\x00\x00(\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x0d\x05\x00NZ-CHATPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x10\x05\x00NavajoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\x14\x05\x00PRCPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xadV\xad\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x16\x05\x00PST8PDTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8A\x15\xfe\x97\x01\x00\x00\x97\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x1a\x05\x00Pacific/ApiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\x1b\x05\x00Pacific/AucklandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xf2:F\xc9\x00\x00\x00\xc9\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10 \x05\x00Pacific/BougainvillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xc5FF(\x03\x00\x00(\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b!\x05\x00Pacific/ChathamPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`$\x05\x00Pacific/ChuukPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?X'\x8e\x96\x04\x00\x00\x96\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%%\x05\x00Pacific/EasterPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9e\x7f\xab\x95V\x01\x00\x00V\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7)\x05\x00Pacific/EfatePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xec =\x89\xac\x00\x00\x00\xac\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h+\x05\x00Pacific/EnderburyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a|\xdcU\x99\x00\x00\x00\x99\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C,\x05\x00Pacific/FakaofoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd_yl\x8c\x01\x00\x00\x8c\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09-\x05\x00Pacific/FijiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf.\x05\x00Pacific/FunafutiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xe3w\x0a\xaf\x00\x00\x00\xaf\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s/\x05\x00Pacific/GalapagosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc23\xa0\xbc\x84\x00\x00\x00\x84\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Q0\x05\x00Pacific/GambierPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x021\x05\x00Pacific/GuadalcanalPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FI\xfe\x14^\x01\x00\x00^\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb91\x05\x00Pacific/GuamPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A3\x05\x00Pacific/HonoluluPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L4\x05\x00Pacific/JohnstonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xec =\x89\xac\x00\x00\x00\xac\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W5\x05\x00Pacific/KantonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8=ku\xae\x00\x00\x00\xae\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/6\x05\x00Pacific/KiritimatiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97n7\x1a\xf2\x00\x00\x00\xf2\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d7\x05\x00Pacific/KosraePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe8]*\xdb\x00\x00\x00\xdb\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+8\x05\x00Pacific/KwajaleinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0059\x05\x00Pacific/MajuroPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D6\x83\xa1\x8b\x00\x00\x00\x8b\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe79\x05\x00Pacific/MarquesasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1:\x05\x00Pacific/MidwayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe2;Z\xf7\xb7\x00\x00\x00\xb7\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_;\x05\x00Pacific/NauruPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\xd60\x0c\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A<\x05\x00Pacific/NiuePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xc2$\x92\xed\x00\x00\x00\xed\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05=\x05\x00Pacific/NorfolkPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\xef\x97\xc6\xc6\x00\x00\x00\xc6\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f>\x05\x00Pacific/NoumeaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11?\x05\x00Pacific/Pago_PagoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xf8v\xdc\x94\x00\x00\x00\x94\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd2?\x05\x00Pacific/PalauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfa\x0fA\x05\x99\x00\x00\x00\x99\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91@\x05\x00Pacific/PitcairnPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00XA\x05\x00Pacific/PohnpeiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0bB\x05\x00Pacific/PonapePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbdB\x05\x00Pacific/Port_MoresbyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xe3\xa3S\x96\x01\x00\x00\x96\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x89C\x05\x00Pacific/RarotongaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FI\xfe\x14^\x01\x00\x00^\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00NE\x05\x00Pacific/SaipanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8F\x05\x00Pacific/SamoaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\xc1\xda\xcf\x85\x00\x00\x00\x85\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95G\x05\x00Pacific/TahitiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FH\x05\x00Pacific/TarawaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97F\x91\xb3\xed\x00\x00\x00\xed\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8H\x05\x00Pacific/TongatapuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14J\x05\x00Pacific/TrukPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8J\x05\x00Pacific/WakePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88K\x05\x00Pacific/WallisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:L\x05\x00Pacific/YapPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xfe\xe5\x9e\x9b\x03\x00\x00\x9b\x03\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfdL\x05\x00PolandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&S\x03\x09\xae\x05\x00\x00\xae\x05\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbcP\x05\x00PortugalPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xf0BB\xff\x01\x00\x00\xff\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90V\x05\x00ROCPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7X,Y\x9f\x01\x00\x00\x9f\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0X\x05\x00ROKPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00pZ\x05\x00SingaporePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07W\x10\xd1\xb0\x04\x00\x00\xb0\x04\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97[\x05\x00TurkeyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k`\x05\x00UCTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x11Q\x06\xd1\x03\x00\x00\xd1\x03\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfb`\x05\x00US/AlaskaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf3d\x05\x00US/AleutianPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5h\x05\x00US/ArizonaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xdc\xa9=\xda\x06\x00\x00\xda\x06\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfdi\x05\x00US/CentralPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xffp\x05\x00US/East-IndianaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x9aG\xc8\xd0\x06\x00\x00\xd0\x06\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?s\x05\x00US/EasternPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007z\x05\x00US/HawaiiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;{\x05\x00US/Indiana-StarkePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x14\xe7\x03\x83\x03\x00\x00\x83\x03\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\x7f\x05\x00US/MichiganPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x83\x05\x00US/MountainPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x22\x12\xfe\x0e\x05\x00\x00\x0e\x05\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00I\x87\x05\x00US/PacificPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\x8c\x05\x00US/SamoaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007\x8d\x05\x00UTCPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\x8d\x05\x00UniversalPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1\xc1\xeb\x05\x8c\x03\x00\x00\x8c\x03\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x8e\x05\x00W-SUPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x91B\xc0\xee\x01\x00\x00\xee\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x92\x05\x00WETPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x94\x05\x00ZuluPK\x05\x06\x00\x00\x00\x00U\x02U\x02m\x8c\x00\x00\xab\x94\x05\x00\x00\x00" diff --git a/contrib/go/_std_1.23/src/time/ya.make b/contrib/go/_std_1.23/src/time/ya.make new file mode 100644 index 000000000000..d47a9760d07e --- /dev/null +++ b/contrib/go/_std_1.23/src/time/ya.make @@ -0,0 +1,30 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + format.go + format_rfc3339.go + sleep.go + sys_unix.go + tick.go + time.go + zoneinfo.go + zoneinfo_goroot.go + zoneinfo_read.go + zoneinfo_unix.go + ) +ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + format.go + format_rfc3339.go + sleep.go + sys_windows.go + tick.go + time.go + zoneinfo.go + zoneinfo_abbrs_windows.go + zoneinfo_goroot.go + zoneinfo_read.go + zoneinfo_windows.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/time/zoneinfo.go b/contrib/go/_std_1.23/src/time/zoneinfo.go similarity index 99% rename from contrib/go/_std_1.22/src/time/zoneinfo.go rename to contrib/go/_std_1.23/src/time/zoneinfo.go index c8d176230293..0fe13630e9a2 100644 --- a/contrib/go/_std_1.22/src/time/zoneinfo.go +++ b/contrib/go/_std_1.23/src/time/zoneinfo.go @@ -99,7 +99,7 @@ func (l *Location) get() *Location { } // String returns a descriptive name for the time zone information, -// corresponding to the name argument to LoadLocation or FixedZone. +// corresponding to the name argument to [LoadLocation] or [FixedZone]. func (l *Location) String() string { return l.get().name } @@ -107,7 +107,7 @@ func (l *Location) String() string { var unnamedFixedZones []*Location var unnamedFixedZonesOnce sync.Once -// FixedZone returns a Location that always uses +// FixedZone returns a [Location] that always uses // the given zone name and offset (seconds east of UTC). func FixedZone(name string, offset int) *Location { // Most calls to FixedZone have an unnamed zone with an offset by the hour. diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_abbrs_windows.go b/contrib/go/_std_1.23/src/time/zoneinfo_abbrs_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_abbrs_windows.go rename to contrib/go/_std_1.23/src/time/zoneinfo_abbrs_windows.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_android.go b/contrib/go/_std_1.23/src/time/zoneinfo_android.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_android.go rename to contrib/go/_std_1.23/src/time/zoneinfo_android.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_goroot.go b/contrib/go/_std_1.23/src/time/zoneinfo_goroot.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_goroot.go rename to contrib/go/_std_1.23/src/time/zoneinfo_goroot.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_ios.go b/contrib/go/_std_1.23/src/time/zoneinfo_ios.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_ios.go rename to contrib/go/_std_1.23/src/time/zoneinfo_ios.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_js.go b/contrib/go/_std_1.23/src/time/zoneinfo_js.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_js.go rename to contrib/go/_std_1.23/src/time/zoneinfo_js.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_plan9.go b/contrib/go/_std_1.23/src/time/zoneinfo_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_plan9.go rename to contrib/go/_std_1.23/src/time/zoneinfo_plan9.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_read.go b/contrib/go/_std_1.23/src/time/zoneinfo_read.go similarity index 98% rename from contrib/go/_std_1.22/src/time/zoneinfo_read.go rename to contrib/go/_std_1.23/src/time/zoneinfo_read.go index 707dd1189d03..5314b6ff9a16 100644 --- a/contrib/go/_std_1.22/src/time/zoneinfo_read.go +++ b/contrib/go/_std_1.23/src/time/zoneinfo_read.go @@ -11,12 +11,16 @@ package time import ( "errors" + "internal/bytealg" "runtime" "syscall" + _ "unsafe" // for linkname ) // registerLoadFromEmbeddedTZData is called by the time/tzdata package, // if it is imported. +// +//go:linkname registerLoadFromEmbeddedTZData func registerLoadFromEmbeddedTZData(f func(string) (string, error)) { loadFromEmbeddedTZData = f } @@ -99,10 +103,8 @@ func (d *dataIO) rest() []byte { // Make a string by stopping at the first NUL func byteString(p []byte) string { - for i := 0; i < len(p); i++ { - if p[i] == 0 { - return string(p[0:i]) - } + if i := bytealg.IndexByte(p, 0); i != -1 { + p = p[:i] } return string(p) } diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_unix.go b/contrib/go/_std_1.23/src/time/zoneinfo_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_unix.go rename to contrib/go/_std_1.23/src/time/zoneinfo_unix.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_wasip1.go b/contrib/go/_std_1.23/src/time/zoneinfo_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_wasip1.go rename to contrib/go/_std_1.23/src/time/zoneinfo_wasip1.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_windows.go b/contrib/go/_std_1.23/src/time/zoneinfo_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_windows.go rename to contrib/go/_std_1.23/src/time/zoneinfo_windows.go diff --git a/contrib/go/_std_1.22/src/unicode/casetables.go b/contrib/go/_std_1.23/src/unicode/casetables.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/casetables.go rename to contrib/go/_std_1.23/src/unicode/casetables.go diff --git a/contrib/go/_std_1.22/src/unicode/digit.go b/contrib/go/_std_1.23/src/unicode/digit.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/digit.go rename to contrib/go/_std_1.23/src/unicode/digit.go diff --git a/contrib/go/_std_1.22/src/unicode/graphic.go b/contrib/go/_std_1.23/src/unicode/graphic.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/graphic.go rename to contrib/go/_std_1.23/src/unicode/graphic.go diff --git a/contrib/go/_std_1.22/src/unicode/letter.go b/contrib/go/_std_1.23/src/unicode/letter.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/letter.go rename to contrib/go/_std_1.23/src/unicode/letter.go diff --git a/contrib/go/_std_1.22/src/unicode/tables.go b/contrib/go/_std_1.23/src/unicode/tables.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/tables.go rename to contrib/go/_std_1.23/src/unicode/tables.go diff --git a/contrib/go/_std_1.22/src/unicode/utf16/utf16.go b/contrib/go/_std_1.23/src/unicode/utf16/utf16.go similarity index 89% rename from contrib/go/_std_1.22/src/unicode/utf16/utf16.go rename to contrib/go/_std_1.23/src/unicode/utf16/utf16.go index 1c6d2c66c30c..0293bbf639bc 100644 --- a/contrib/go/_std_1.22/src/unicode/utf16/utf16.go +++ b/contrib/go/_std_1.23/src/unicode/utf16/utf16.go @@ -52,6 +52,19 @@ func EncodeRune(r rune) (r1, r2 rune) { return surr1 + (r>>10)&0x3ff, surr2 + r&0x3ff } +// RuneLen returns the number of 16-bit words in the UTF-16 encoding of the rune. +// It returns -1 if the rune is not a valid value to encode in UTF-16. +func RuneLen(r rune) int { + switch { + case 0 <= r && r < surr1, surr3 <= r && r < surrSelf: + return 1 + case surrSelf <= r && r <= maxRune: + return 2 + default: + return -1 + } +} + // Encode returns the UTF-16 encoding of the Unicode code point sequence s. func Encode(s []rune) []uint16 { n := len(s) @@ -64,13 +77,11 @@ func Encode(s []rune) []uint16 { a := make([]uint16, n) n = 0 for _, v := range s { - switch { - case 0 <= v && v < surr1, surr3 <= v && v < surrSelf: - // normal rune + switch RuneLen(v) { + case 1: // normal rune a[n] = uint16(v) n++ - case surrSelf <= v && v <= maxRune: - // needs surrogate sequence + case 2: // needs surrogate sequence r1, r2 := EncodeRune(v) a[n] = uint16(r1) a[n+1] = uint16(r2) diff --git a/contrib/go/_std_1.22/src/unicode/utf16/ya.make b/contrib/go/_std_1.23/src/unicode/utf16/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/unicode/utf16/ya.make rename to contrib/go/_std_1.23/src/unicode/utf16/ya.make diff --git a/contrib/go/_std_1.22/src/unicode/utf8/utf8.go b/contrib/go/_std_1.23/src/unicode/utf8/utf8.go similarity index 99% rename from contrib/go/_std_1.22/src/unicode/utf8/utf8.go rename to contrib/go/_std_1.23/src/unicode/utf8/utf8.go index 71d6bf18d01b..c7389d4d6f58 100644 --- a/contrib/go/_std_1.22/src/unicode/utf8/utf8.go +++ b/contrib/go/_std_1.23/src/unicode/utf8/utf8.go @@ -316,7 +316,7 @@ func DecodeLastRuneInString(s string) (r rune, size int) { return r, size } -// RuneLen returns the number of bytes required to encode the rune. +// RuneLen returns the number of bytes in the UTF-8 encoding of the rune. // It returns -1 if the rune is not a valid value to encode in UTF-8. func RuneLen(r rune) int { switch { diff --git a/contrib/go/_std_1.22/src/unicode/utf8/ya.make b/contrib/go/_std_1.23/src/unicode/utf8/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/unicode/utf8/ya.make rename to contrib/go/_std_1.23/src/unicode/utf8/ya.make diff --git a/contrib/go/_std_1.22/src/unicode/ya.make b/contrib/go/_std_1.23/src/unicode/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/unicode/ya.make rename to contrib/go/_std_1.23/src/unicode/ya.make diff --git a/contrib/go/_std_1.23/src/unique/clone.go b/contrib/go/_std_1.23/src/unique/clone.go new file mode 100644 index 000000000000..36ced14ecea0 --- /dev/null +++ b/contrib/go/_std_1.23/src/unique/clone.go @@ -0,0 +1,89 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unique + +import ( + "internal/abi" + "internal/stringslite" + "unsafe" +) + +// clone makes a copy of value, and may update string values found in value +// with a cloned version of those strings. The purpose of explicitly cloning +// strings is to avoid accidentally giving a large string a long lifetime. +// +// Note that this will clone strings in structs and arrays found in value, +// and will clone value if it itself is a string. It will not, however, clone +// strings if value is of interface or slice type (that is, found via an +// indirection). +func clone[T comparable](value T, seq *cloneSeq) T { + for _, offset := range seq.stringOffsets { + ps := (*string)(unsafe.Pointer(uintptr(unsafe.Pointer(&value)) + offset)) + *ps = stringslite.Clone(*ps) + } + return value +} + +// singleStringClone describes how to clone a single string. +var singleStringClone = cloneSeq{stringOffsets: []uintptr{0}} + +// cloneSeq describes how to clone a value of a particular type. +type cloneSeq struct { + stringOffsets []uintptr +} + +// makeCloneSeq creates a cloneSeq for a type. +func makeCloneSeq(typ *abi.Type) cloneSeq { + if typ == nil { + return cloneSeq{} + } + if typ.Kind() == abi.String { + return singleStringClone + } + var seq cloneSeq + switch typ.Kind() { + case abi.Struct: + buildStructCloneSeq(typ, &seq, 0) + case abi.Array: + buildArrayCloneSeq(typ, &seq, 0) + } + return seq +} + +// buildStructCloneSeq populates a cloneSeq for an abi.Type that has Kind abi.Struct. +func buildStructCloneSeq(typ *abi.Type, seq *cloneSeq, baseOffset uintptr) { + styp := typ.StructType() + for i := range styp.Fields { + f := &styp.Fields[i] + switch f.Typ.Kind() { + case abi.String: + seq.stringOffsets = append(seq.stringOffsets, baseOffset+f.Offset) + case abi.Struct: + buildStructCloneSeq(f.Typ, seq, baseOffset+f.Offset) + case abi.Array: + buildArrayCloneSeq(f.Typ, seq, baseOffset+f.Offset) + } + } +} + +// buildArrayCloneSeq populates a cloneSeq for an abi.Type that has Kind abi.Array. +func buildArrayCloneSeq(typ *abi.Type, seq *cloneSeq, baseOffset uintptr) { + atyp := typ.ArrayType() + etyp := atyp.Elem + offset := baseOffset + for range atyp.Len { + switch etyp.Kind() { + case abi.String: + seq.stringOffsets = append(seq.stringOffsets, offset) + case abi.Struct: + buildStructCloneSeq(etyp, seq, offset) + case abi.Array: + buildArrayCloneSeq(etyp, seq, offset) + } + offset += etyp.Size() + align := uintptr(etyp.FieldAlign()) + offset = (offset + align - 1) &^ (align - 1) + } +} diff --git a/contrib/go/_std_1.23/src/unique/doc.go b/contrib/go/_std_1.23/src/unique/doc.go new file mode 100644 index 000000000000..01337893c40a --- /dev/null +++ b/contrib/go/_std_1.23/src/unique/doc.go @@ -0,0 +1,9 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +The unique package provides facilities for canonicalizing ("interning") +comparable values. +*/ +package unique diff --git a/contrib/go/_std_1.23/src/unique/handle.go b/contrib/go/_std_1.23/src/unique/handle.go new file mode 100644 index 000000000000..abc620f60fe1 --- /dev/null +++ b/contrib/go/_std_1.23/src/unique/handle.go @@ -0,0 +1,175 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unique + +import ( + "internal/abi" + "internal/concurrent" + "internal/weak" + "runtime" + "sync" + _ "unsafe" +) + +// Handle is a globally unique identity for some value of type T. +// +// Two handles compare equal exactly if the two values used to create the handles +// would have also compared equal. The comparison of two handles is trivial and +// typically much more efficient than comparing the values used to create them. +type Handle[T comparable] struct { + value *T +} + +// Value returns a shallow copy of the T value that produced the Handle. +func (h Handle[T]) Value() T { + return *h.value +} + +// Make returns a globally unique handle for a value of type T. Handles +// are equal if and only if the values used to produce them are equal. +func Make[T comparable](value T) Handle[T] { + // Find the map for type T. + typ := abi.TypeFor[T]() + ma, ok := uniqueMaps.Load(typ) + if !ok { + // This is a good time to initialize cleanup, since we must go through + // this path on the first use of Make, and it's not on the hot path. + setupMake.Do(registerCleanup) + ma = addUniqueMap[T](typ) + } + m := ma.(*uniqueMap[T]) + + // Keep around any values we allocate for insertion. There + // are a few different ways we can race with other threads + // and create values that we might discard. By keeping + // the first one we make around, we can avoid generating + // more than one per racing thread. + var ( + toInsert *T // Keep this around to keep it alive. + toInsertWeak weak.Pointer[T] + ) + newValue := func() (T, weak.Pointer[T]) { + if toInsert == nil { + toInsert = new(T) + *toInsert = clone(value, &m.cloneSeq) + toInsertWeak = weak.Make(toInsert) + } + return *toInsert, toInsertWeak + } + var ptr *T + for { + // Check the map. + wp, ok := m.Load(value) + if !ok { + // Try to insert a new value into the map. + k, v := newValue() + wp, _ = m.LoadOrStore(k, v) + } + // Now that we're sure there's a value in the map, let's + // try to get the pointer we need out of it. + ptr = wp.Strong() + if ptr != nil { + break + } + // The weak pointer is nil, so the old value is truly dead. + // Try to remove it and start over. + m.CompareAndDelete(value, wp) + } + runtime.KeepAlive(toInsert) + return Handle[T]{ptr} +} + +var ( + // uniqueMaps is an index of type-specific concurrent maps used for unique.Make. + // + // The two-level map might seem odd at first since the HashTrieMap could have "any" + // as its key type, but the issue is escape analysis. We do not want to force lookups + // to escape the argument, and using a type-specific map allows us to avoid that where + // possible (for example, for strings and plain-ol'-data structs). We also get the + // benefit of not cramming every different type into a single map, but that's certainly + // not enough to outweigh the cost of two map lookups. What is worth it though, is saving + // on those allocations. + uniqueMaps = concurrent.NewHashTrieMap[*abi.Type, any]() // any is always a *uniqueMap[T]. + + // cleanupFuncs are functions that clean up dead weak pointers in type-specific + // maps in uniqueMaps. We express cleanup this way because there's no way to iterate + // over the sync.Map and call functions on the type-specific data structures otherwise. + // These cleanup funcs each close over one of these type-specific maps. + // + // cleanupMu protects cleanupNotify and is held across the entire cleanup. Used for testing. + // cleanupNotify is a test-only mechanism that allow tests to wait for the cleanup to run. + cleanupMu sync.Mutex + cleanupFuncsMu sync.Mutex + cleanupFuncs []func() + cleanupNotify []func() // One-time notifications when cleanups finish. +) + +type uniqueMap[T comparable] struct { + *concurrent.HashTrieMap[T, weak.Pointer[T]] + cloneSeq +} + +func addUniqueMap[T comparable](typ *abi.Type) *uniqueMap[T] { + // Create a map for T and try to register it. We could + // race with someone else, but that's fine; it's one + // small, stray allocation. The number of allocations + // this can create is bounded by a small constant. + m := &uniqueMap[T]{ + HashTrieMap: concurrent.NewHashTrieMap[T, weak.Pointer[T]](), + cloneSeq: makeCloneSeq(typ), + } + a, loaded := uniqueMaps.LoadOrStore(typ, m) + if !loaded { + // Add a cleanup function for the new map. + cleanupFuncsMu.Lock() + cleanupFuncs = append(cleanupFuncs, func() { + // Delete all the entries whose weak references are nil and clean up + // deleted entries. + m.All()(func(key T, wp weak.Pointer[T]) bool { + if wp.Strong() == nil { + m.CompareAndDelete(key, wp) + } + return true + }) + }) + cleanupFuncsMu.Unlock() + } + return a.(*uniqueMap[T]) +} + +// setupMake is used to perform initial setup for unique.Make. +var setupMake sync.Once + +// startBackgroundCleanup sets up a background goroutine to occasionally call cleanupFuncs. +func registerCleanup() { + runtime_registerUniqueMapCleanup(func() { + // Lock for cleanup. + cleanupMu.Lock() + + // Grab funcs to run. + cleanupFuncsMu.Lock() + cf := cleanupFuncs + cleanupFuncsMu.Unlock() + + // Run cleanup. + for _, f := range cf { + f() + } + + // Run cleanup notifications. + for _, f := range cleanupNotify { + f() + } + cleanupNotify = nil + + // Finished. + cleanupMu.Unlock() + }) +} + +// Implemented in runtime. + +//go:linkname runtime_registerUniqueMapCleanup +func runtime_registerUniqueMapCleanup(cleanup func()) diff --git a/contrib/go/_std_1.23/src/unique/ya.make b/contrib/go/_std_1.23/src/unique/ya.make new file mode 100644 index 000000000000..9f3174c8742d --- /dev/null +++ b/contrib/go/_std_1.23/src/unique/ya.make @@ -0,0 +1,9 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + clone.go + doc.go + handle.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s similarity index 85% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s index 66aebae25885..c672ccf6986b 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s @@ -33,6 +33,9 @@ #define CONSTBASE R16 #define BLOCKS R17 +// for VPERMXOR +#define MASK R18 + DATA consts<>+0x00(SB)/8, $0x3320646e61707865 DATA consts<>+0x08(SB)/8, $0x6b20657479622d32 DATA consts<>+0x10(SB)/8, $0x0000000000000001 @@ -53,7 +56,11 @@ DATA consts<>+0x80(SB)/8, $0x6b2065746b206574 DATA consts<>+0x88(SB)/8, $0x6b2065746b206574 DATA consts<>+0x90(SB)/8, $0x0000000100000000 DATA consts<>+0x98(SB)/8, $0x0000000300000002 -GLOBL consts<>(SB), RODATA, $0xa0 +DATA consts<>+0xa0(SB)/8, $0x5566774411223300 +DATA consts<>+0xa8(SB)/8, $0xddeeffcc99aabb88 +DATA consts<>+0xb0(SB)/8, $0x6677445522330011 +DATA consts<>+0xb8(SB)/8, $0xeeffccddaabb8899 +GLOBL consts<>(SB), RODATA, $0xc0 //func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 @@ -70,6 +77,9 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 MOVD $48, R10 MOVD $64, R11 SRD $6, LEN, BLOCKS + // for VPERMXOR + MOVD $consts<>+0xa0(SB), MASK + MOVD $16, R20 // V16 LXVW4X (CONSTBASE)(R0), VS48 ADD $80,CONSTBASE @@ -87,6 +97,10 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 // V28 LXVW4X (CONSTBASE)(R11), VS60 + // Load mask constants for VPERMXOR + LXVW4X (MASK)(R0), V20 + LXVW4X (MASK)(R20), V21 + // splat slot from V19 -> V26 VSPLTW $0, V19, V26 @@ -97,7 +111,7 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 MOVD $10, R14 MOVD R14, CTR - + PCALIGN $16 loop_outer_vsx: // V0, V1, V2, V3 LXVW4X (R0)(CONSTBASE), VS32 @@ -128,22 +142,17 @@ loop_outer_vsx: VSPLTISW $12, V28 VSPLTISW $8, V29 VSPLTISW $7, V30 - + PCALIGN $16 loop_vsx: VADDUWM V0, V4, V0 VADDUWM V1, V5, V1 VADDUWM V2, V6, V2 VADDUWM V3, V7, V3 - VXOR V12, V0, V12 - VXOR V13, V1, V13 - VXOR V14, V2, V14 - VXOR V15, V3, V15 - - VRLW V12, V27, V12 - VRLW V13, V27, V13 - VRLW V14, V27, V14 - VRLW V15, V27, V15 + VPERMXOR V12, V0, V21, V12 + VPERMXOR V13, V1, V21, V13 + VPERMXOR V14, V2, V21, V14 + VPERMXOR V15, V3, V21, V15 VADDUWM V8, V12, V8 VADDUWM V9, V13, V9 @@ -165,15 +174,10 @@ loop_vsx: VADDUWM V2, V6, V2 VADDUWM V3, V7, V3 - VXOR V12, V0, V12 - VXOR V13, V1, V13 - VXOR V14, V2, V14 - VXOR V15, V3, V15 - - VRLW V12, V29, V12 - VRLW V13, V29, V13 - VRLW V14, V29, V14 - VRLW V15, V29, V15 + VPERMXOR V12, V0, V20, V12 + VPERMXOR V13, V1, V20, V13 + VPERMXOR V14, V2, V20, V14 + VPERMXOR V15, V3, V20, V15 VADDUWM V8, V12, V8 VADDUWM V9, V13, V9 @@ -195,15 +199,10 @@ loop_vsx: VADDUWM V2, V7, V2 VADDUWM V3, V4, V3 - VXOR V15, V0, V15 - VXOR V12, V1, V12 - VXOR V13, V2, V13 - VXOR V14, V3, V14 - - VRLW V15, V27, V15 - VRLW V12, V27, V12 - VRLW V13, V27, V13 - VRLW V14, V27, V14 + VPERMXOR V15, V0, V21, V15 + VPERMXOR V12, V1, V21, V12 + VPERMXOR V13, V2, V21, V13 + VPERMXOR V14, V3, V21, V14 VADDUWM V10, V15, V10 VADDUWM V11, V12, V11 @@ -225,15 +224,10 @@ loop_vsx: VADDUWM V2, V7, V2 VADDUWM V3, V4, V3 - VXOR V15, V0, V15 - VXOR V12, V1, V12 - VXOR V13, V2, V13 - VXOR V14, V3, V14 - - VRLW V15, V29, V15 - VRLW V12, V29, V12 - VRLW V13, V29, V13 - VRLW V14, V29, V14 + VPERMXOR V15, V0, V20, V15 + VPERMXOR V12, V1, V20, V12 + VPERMXOR V13, V2, V20, V13 + VPERMXOR V14, V3, V20, V14 VADDUWM V10, V15, V10 VADDUWM V11, V12, V11 @@ -249,48 +243,48 @@ loop_vsx: VRLW V6, V30, V6 VRLW V7, V30, V7 VRLW V4, V30, V4 - BC 16, LT, loop_vsx + BDNZ loop_vsx VADDUWM V12, V26, V12 - WORD $0x13600F8C // VMRGEW V0, V1, V27 - WORD $0x13821F8C // VMRGEW V2, V3, V28 + VMRGEW V0, V1, V27 + VMRGEW V2, V3, V28 - WORD $0x10000E8C // VMRGOW V0, V1, V0 - WORD $0x10421E8C // VMRGOW V2, V3, V2 + VMRGOW V0, V1, V0 + VMRGOW V2, V3, V2 - WORD $0x13A42F8C // VMRGEW V4, V5, V29 - WORD $0x13C63F8C // VMRGEW V6, V7, V30 + VMRGEW V4, V5, V29 + VMRGEW V6, V7, V30 XXPERMDI VS32, VS34, $0, VS33 XXPERMDI VS32, VS34, $3, VS35 XXPERMDI VS59, VS60, $0, VS32 XXPERMDI VS59, VS60, $3, VS34 - WORD $0x10842E8C // VMRGOW V4, V5, V4 - WORD $0x10C63E8C // VMRGOW V6, V7, V6 + VMRGOW V4, V5, V4 + VMRGOW V6, V7, V6 - WORD $0x13684F8C // VMRGEW V8, V9, V27 - WORD $0x138A5F8C // VMRGEW V10, V11, V28 + VMRGEW V8, V9, V27 + VMRGEW V10, V11, V28 XXPERMDI VS36, VS38, $0, VS37 XXPERMDI VS36, VS38, $3, VS39 XXPERMDI VS61, VS62, $0, VS36 XXPERMDI VS61, VS62, $3, VS38 - WORD $0x11084E8C // VMRGOW V8, V9, V8 - WORD $0x114A5E8C // VMRGOW V10, V11, V10 + VMRGOW V8, V9, V8 + VMRGOW V10, V11, V10 - WORD $0x13AC6F8C // VMRGEW V12, V13, V29 - WORD $0x13CE7F8C // VMRGEW V14, V15, V30 + VMRGEW V12, V13, V29 + VMRGEW V14, V15, V30 XXPERMDI VS40, VS42, $0, VS41 XXPERMDI VS40, VS42, $3, VS43 XXPERMDI VS59, VS60, $0, VS40 XXPERMDI VS59, VS60, $3, VS42 - WORD $0x118C6E8C // VMRGOW V12, V13, V12 - WORD $0x11CE7E8C // VMRGOW V14, V15, V14 + VMRGOW V12, V13, V12 + VMRGOW V14, V15, V14 VSPLTISW $4, V27 VADDUWM V26, V27, V26 @@ -431,7 +425,7 @@ tail_vsx: ADD $-1, R11, R12 ADD $-1, INP ADD $-1, OUT - + PCALIGN $16 looptail_vsx: // Copying the result to OUT // in bytes. @@ -439,7 +433,7 @@ looptail_vsx: MOVBZU 1(INP), TMP XOR KEY, TMP, KEY MOVBU KEY, 1(OUT) - BC 16, LT, looptail_vsx + BDNZ looptail_vsx // Clear the stack values STXVW4X VS48, (R11)(R0) diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/xor.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/xor.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/xor.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/xor.go diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/ya.make new file mode 100644 index 000000000000..27b67128baf3 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/ya.make @@ -0,0 +1,16 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + chacha_arm64.go + chacha_arm64.s + chacha_generic.go + xor.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + chacha_generic.go + chacha_noasm.go + xor.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make new file mode 100644 index 000000000000..ca7705d7e9a6 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make @@ -0,0 +1,18 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + chacha20poly1305.go + chacha20poly1305_generic.go + chacha20poly1305_noasm.go + xchacha20poly1305.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + chacha20poly1305.go + chacha20poly1305_amd64.go + chacha20poly1305_amd64.s + chacha20poly1305_generic.go + xchacha20poly1305.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/builder.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/builder.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/builder.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/builder.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/string.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/string.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/string.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/string.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/hkdf/hkdf.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/hkdf/hkdf.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/hkdf/hkdf.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/hkdf/hkdf.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/hkdf/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/hkdf/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/hkdf/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/hkdf/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/alias.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/alias.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/alias.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/alias.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/alias_purego.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/alias_purego.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/alias_purego.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/alias_purego.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go similarity index 91% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go index e041da5ea3e7..ec2202bd7d5f 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go @@ -7,7 +7,10 @@ package poly1305 -import "encoding/binary" +import ( + "encoding/binary" + "math/bits" +) // Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag // for a 64 bytes message is approximately @@ -114,13 +117,13 @@ type uint128 struct { } func mul64(a, b uint64) uint128 { - hi, lo := bitsMul64(a, b) + hi, lo := bits.Mul64(a, b) return uint128{lo, hi} } func add128(a, b uint128) uint128 { - lo, c := bitsAdd64(a.lo, b.lo, 0) - hi, c := bitsAdd64(a.hi, b.hi, c) + lo, c := bits.Add64(a.lo, b.lo, 0) + hi, c := bits.Add64(a.hi, b.hi, c) if c != 0 { panic("poly1305: unexpected overflow") } @@ -155,8 +158,8 @@ func updateGeneric(state *macState, msg []byte) { // hide leading zeroes. For full chunks, that's 1 << 128, so we can just // add 1 to the most significant (2¹²⁸) limb, h2. if len(msg) >= TagSize { - h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) - h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) + h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) + h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) h2 += c + 1 msg = msg[TagSize:] @@ -165,8 +168,8 @@ func updateGeneric(state *macState, msg []byte) { copy(buf[:], msg) buf[len(msg)] = 1 - h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) - h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) + h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) + h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) h2 += c msg = nil @@ -219,9 +222,9 @@ func updateGeneric(state *macState, msg []byte) { m3 := h2r1 t0 := m0.lo - t1, c := bitsAdd64(m1.lo, m0.hi, 0) - t2, c := bitsAdd64(m2.lo, m1.hi, c) - t3, _ := bitsAdd64(m3.lo, m2.hi, c) + t1, c := bits.Add64(m1.lo, m0.hi, 0) + t2, c := bits.Add64(m2.lo, m1.hi, c) + t3, _ := bits.Add64(m3.lo, m2.hi, c) // Now we have the result as 4 64-bit limbs, and we need to reduce it // modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do @@ -243,14 +246,14 @@ func updateGeneric(state *macState, msg []byte) { // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c. - h0, c = bitsAdd64(h0, cc.lo, 0) - h1, c = bitsAdd64(h1, cc.hi, c) + h0, c = bits.Add64(h0, cc.lo, 0) + h1, c = bits.Add64(h1, cc.hi, c) h2 += c cc = shiftRightBy2(cc) - h0, c = bitsAdd64(h0, cc.lo, 0) - h1, c = bitsAdd64(h1, cc.hi, c) + h0, c = bits.Add64(h0, cc.lo, 0) + h1, c = bits.Add64(h1, cc.hi, c) h2 += c // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most @@ -287,9 +290,9 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { // in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the // result if the subtraction underflows, and t otherwise. - hMinusP0, b := bitsSub64(h0, p0, 0) - hMinusP1, b := bitsSub64(h1, p1, b) - _, b = bitsSub64(h2, p2, b) + hMinusP0, b := bits.Sub64(h0, p0, 0) + hMinusP1, b := bits.Sub64(h1, p1, b) + _, b = bits.Sub64(h2, p2, b) // h = h if h < p else h - p h0 = select64(b, h0, hMinusP0) @@ -301,8 +304,8 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { // // by just doing a wide addition with the 128 low bits of h and discarding // the overflow. - h0, c := bitsAdd64(h0, s[0], 0) - h1, _ = bitsAdd64(h1, s[1], c) + h0, c := bits.Add64(h0, s[0], 0) + h1, _ = bits.Add64(h1, s[1], c) binary.LittleEndian.PutUint64(out[0:8], h0) binary.LittleEndian.PutUint64(out[8:16], h1) diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s similarity index 95% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s index d2ca5deeb9f5..b3c1699bff51 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s @@ -19,15 +19,14 @@ #define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \ MULLD r0, h0, t0; \ - MULLD r0, h1, t4; \ MULHDU r0, h0, t1; \ + MULLD r0, h1, t4; \ MULHDU r0, h1, t5; \ ADDC t4, t1, t1; \ MULLD r0, h2, t2; \ - ADDZE t5; \ MULHDU r1, h0, t4; \ MULLD r1, h0, h0; \ - ADD t5, t2, t2; \ + ADDE t5, t2, t2; \ ADDC h0, t1, t1; \ MULLD h2, r1, t3; \ ADDZE t4, h0; \ @@ -37,13 +36,11 @@ ADDE t5, t3, t3; \ ADDC h0, t2, t2; \ MOVD $-4, t4; \ - MOVD t0, h0; \ - MOVD t1, h1; \ ADDZE t3; \ - ANDCC $3, t2, h2; \ - AND t2, t4, t0; \ + RLDICL $0, t2, $62, h2; \ + AND t2, t4, h0; \ ADDC t0, h0, h0; \ - ADDE t3, h1, h1; \ + ADDE t3, t1, h1; \ SLD $62, t3, t4; \ SRD $2, t2; \ ADDZE h2; \ @@ -75,6 +72,7 @@ TEXT ·update(SB), $0-32 loop: POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22) + PCALIGN $16 multiply: POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21) ADD $-16, R5 diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make new file mode 100644 index 000000000000..936a0a0198ab --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make @@ -0,0 +1,16 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + mac_noasm.go + poly1305.go + sum_generic.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + poly1305.go + sum_amd64.go + sum_amd64.s + sum_generic.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/doc.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/doc.go new file mode 100644 index 000000000000..decd8cf9bf74 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/doc.go @@ -0,0 +1,62 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sha3 implements the SHA-3 fixed-output-length hash functions and +// the SHAKE variable-output-length hash functions defined by FIPS-202. +// +// Both types of hash function use the "sponge" construction and the Keccak +// permutation. For a detailed specification see http://keccak.noekeon.org/ +// +// # Guidance +// +// If you aren't sure what function you need, use SHAKE256 with at least 64 +// bytes of output. The SHAKE instances are faster than the SHA3 instances; +// the latter have to allocate memory to conform to the hash.Hash interface. +// +// If you need a secret-key MAC (message authentication code), prepend the +// secret key to the input, hash with SHAKE256 and read at least 32 bytes of +// output. +// +// # Security strengths +// +// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security +// strength against preimage attacks of x bits. Since they only produce "x" +// bits of output, their collision-resistance is only "x/2" bits. +// +// The SHAKE-256 and -128 functions have a generic security strength of 256 and +// 128 bits against all attacks, provided that at least 2x bits of their output +// is used. Requesting more than 64 or 32 bytes of output, respectively, does +// not increase the collision-resistance of the SHAKE functions. +// +// # The sponge construction +// +// A sponge builds a pseudo-random function from a public pseudo-random +// permutation, by applying the permutation to a state of "rate + capacity" +// bytes, but hiding "capacity" of the bytes. +// +// A sponge starts out with a zero state. To hash an input using a sponge, up +// to "rate" bytes of the input are XORed into the sponge's state. The sponge +// is then "full" and the permutation is applied to "empty" it. This process is +// repeated until all the input has been "absorbed". The input is then padded. +// The digest is "squeezed" from the sponge in the same way, except that output +// is copied out instead of input being XORed in. +// +// A sponge is parameterized by its generic security strength, which is equal +// to half its capacity; capacity + rate is equal to the permutation's width. +// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means +// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2. +// +// # Recommendations +// +// The SHAKE functions are recommended for most new uses. They can produce +// output of arbitrary length. SHAKE256, with an output length of at least +// 64 bytes, provides 256-bit security against all attacks. The Keccak team +// recommends it for most applications upgrading from SHA2-512. (NIST chose a +// much stronger, but much slower, sponge instance for SHA3-512.) +// +// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions. +// They produce output of the same length, with the same security strengths +// against all attacks. This means, in particular, that SHA3-256 only has +// 128-bit collision resistance, because its output length is 32 bytes. +package sha3 // import "golang.org/x/crypto/sha3" diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes.go new file mode 100644 index 000000000000..5eae6cb922fb --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes.go @@ -0,0 +1,101 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +// This file provides functions for creating instances of the SHA-3 +// and SHAKE hash functions, as well as utility functions for hashing +// bytes. + +import ( + "hash" +) + +// New224 creates a new SHA3-224 hash. +// Its generic security strength is 224 bits against preimage attacks, +// and 112 bits against collision attacks. +func New224() hash.Hash { + return new224() +} + +// New256 creates a new SHA3-256 hash. +// Its generic security strength is 256 bits against preimage attacks, +// and 128 bits against collision attacks. +func New256() hash.Hash { + return new256() +} + +// New384 creates a new SHA3-384 hash. +// Its generic security strength is 384 bits against preimage attacks, +// and 192 bits against collision attacks. +func New384() hash.Hash { + return new384() +} + +// New512 creates a new SHA3-512 hash. +// Its generic security strength is 512 bits against preimage attacks, +// and 256 bits against collision attacks. +func New512() hash.Hash { + return new512() +} + +func new224Generic() *state { + return &state{rate: 144, outputLen: 28, dsbyte: 0x06} +} + +func new256Generic() *state { + return &state{rate: 136, outputLen: 32, dsbyte: 0x06} +} + +func new384Generic() *state { + return &state{rate: 104, outputLen: 48, dsbyte: 0x06} +} + +func new512Generic() *state { + return &state{rate: 72, outputLen: 64, dsbyte: 0x06} +} + +// NewLegacyKeccak256 creates a new Keccak-256 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New256 instead. +func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} } + +// NewLegacyKeccak512 creates a new Keccak-512 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New512 instead. +func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} } + +// Sum224 returns the SHA3-224 digest of the data. +func Sum224(data []byte) (digest [28]byte) { + h := New224() + h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum256 returns the SHA3-256 digest of the data. +func Sum256(data []byte) (digest [32]byte) { + h := New256() + h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum384 returns the SHA3-384 digest of the data. +func Sum384(data []byte) (digest [48]byte) { + h := New384() + h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum512 returns the SHA3-512 digest of the data. +func Sum512(data []byte) (digest [64]byte) { + h := New512() + h.Write(data) + h.Sum(digest[:0]) + return +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes_noasm.go new file mode 100644 index 000000000000..9d85fb621446 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes_noasm.go @@ -0,0 +1,23 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !gc || purego || !s390x + +package sha3 + +func new224() *state { + return new224Generic() +} + +func new256() *state { + return new256Generic() +} + +func new384() *state { + return new384Generic() +} + +func new512() *state { + return new512Generic() +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf.go new file mode 100644 index 000000000000..ce48b1dd3edd --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf.go @@ -0,0 +1,414 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !amd64 || purego || !gc + +package sha3 + +import "math/bits" + +// rc stores the round constants for use in the ι step. +var rc = [24]uint64{ + 0x0000000000000001, + 0x0000000000008082, + 0x800000000000808A, + 0x8000000080008000, + 0x000000000000808B, + 0x0000000080000001, + 0x8000000080008081, + 0x8000000000008009, + 0x000000000000008A, + 0x0000000000000088, + 0x0000000080008009, + 0x000000008000000A, + 0x000000008000808B, + 0x800000000000008B, + 0x8000000000008089, + 0x8000000000008003, + 0x8000000000008002, + 0x8000000000000080, + 0x000000000000800A, + 0x800000008000000A, + 0x8000000080008081, + 0x8000000000008080, + 0x0000000080000001, + 0x8000000080008008, +} + +// keccakF1600 applies the Keccak permutation to a 1600b-wide +// state represented as a slice of 25 uint64s. +func keccakF1600(a *[25]uint64) { + // Implementation translated from Keccak-inplace.c + // in the keccak reference code. + var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64 + + for i := 0; i < 24; i += 4 { + // Combines the 5 steps in each round into 2 steps. + // Unrolls 4 rounds per loop and spreads some steps across rounds. + + // Round 1 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[6] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[12] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[18] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[24] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i] + a[6] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[16] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[22] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[3] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[10] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[1] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[7] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[19] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[20] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[11] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[23] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[4] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[5] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[2] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[8] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[14] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[15] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + // Round 2 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[16] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[7] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[23] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[14] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1] + a[16] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[11] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[2] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[18] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[20] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[6] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[22] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[4] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[15] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[1] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[8] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[24] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[10] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[12] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[3] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[19] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[5] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + // Round 3 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[11] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[22] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[8] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[19] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2] + a[11] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[1] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[12] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[23] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[15] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[16] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[2] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[24] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[5] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[6] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[3] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[14] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[20] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[7] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[18] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[4] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[10] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + // Round 4 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[1] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[2] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[3] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[4] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3] + a[1] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[6] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[7] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[8] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[5] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[11] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[12] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[14] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[10] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[16] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[18] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[19] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[15] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[22] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[23] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[24] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[20] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + } +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go new file mode 100644 index 000000000000..b908696be58f --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && !purego && gc + +package sha3 + +// This function is implemented in keccakf_amd64.s. + +//go:noescape + +func keccakF1600(a *[25]uint64) diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s new file mode 100644 index 000000000000..1f5393886197 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s @@ -0,0 +1,390 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && !purego && gc + +// This code was translated into a form compatible with 6a from the public +// domain sources at https://github.com/gvanas/KeccakCodePackage + +// Offsets in state +#define _ba (0*8) +#define _be (1*8) +#define _bi (2*8) +#define _bo (3*8) +#define _bu (4*8) +#define _ga (5*8) +#define _ge (6*8) +#define _gi (7*8) +#define _go (8*8) +#define _gu (9*8) +#define _ka (10*8) +#define _ke (11*8) +#define _ki (12*8) +#define _ko (13*8) +#define _ku (14*8) +#define _ma (15*8) +#define _me (16*8) +#define _mi (17*8) +#define _mo (18*8) +#define _mu (19*8) +#define _sa (20*8) +#define _se (21*8) +#define _si (22*8) +#define _so (23*8) +#define _su (24*8) + +// Temporary registers +#define rT1 AX + +// Round vars +#define rpState DI +#define rpStack SP + +#define rDa BX +#define rDe CX +#define rDi DX +#define rDo R8 +#define rDu R9 + +#define rBa R10 +#define rBe R11 +#define rBi R12 +#define rBo R13 +#define rBu R14 + +#define rCa SI +#define rCe BP +#define rCi rBi +#define rCo rBo +#define rCu R15 + +#define MOVQ_RBI_RCE MOVQ rBi, rCe +#define XORQ_RT1_RCA XORQ rT1, rCa +#define XORQ_RT1_RCE XORQ rT1, rCe +#define XORQ_RBA_RCU XORQ rBa, rCu +#define XORQ_RBE_RCU XORQ rBe, rCu +#define XORQ_RDU_RCU XORQ rDu, rCu +#define XORQ_RDA_RCA XORQ rDa, rCa +#define XORQ_RDE_RCE XORQ rDe, rCe + +#define mKeccakRound(iState, oState, rc, B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU, K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA, M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA, S_RDE_RCE) \ + /* Prepare round */ \ + MOVQ rCe, rDa; \ + ROLQ $1, rDa; \ + \ + MOVQ _bi(iState), rCi; \ + XORQ _gi(iState), rDi; \ + XORQ rCu, rDa; \ + XORQ _ki(iState), rCi; \ + XORQ _mi(iState), rDi; \ + XORQ rDi, rCi; \ + \ + MOVQ rCi, rDe; \ + ROLQ $1, rDe; \ + \ + MOVQ _bo(iState), rCo; \ + XORQ _go(iState), rDo; \ + XORQ rCa, rDe; \ + XORQ _ko(iState), rCo; \ + XORQ _mo(iState), rDo; \ + XORQ rDo, rCo; \ + \ + MOVQ rCo, rDi; \ + ROLQ $1, rDi; \ + \ + MOVQ rCu, rDo; \ + XORQ rCe, rDi; \ + ROLQ $1, rDo; \ + \ + MOVQ rCa, rDu; \ + XORQ rCi, rDo; \ + ROLQ $1, rDu; \ + \ + /* Result b */ \ + MOVQ _ba(iState), rBa; \ + MOVQ _ge(iState), rBe; \ + XORQ rCo, rDu; \ + MOVQ _ki(iState), rBi; \ + MOVQ _mo(iState), rBo; \ + MOVQ _su(iState), rBu; \ + XORQ rDe, rBe; \ + ROLQ $44, rBe; \ + XORQ rDi, rBi; \ + XORQ rDa, rBa; \ + ROLQ $43, rBi; \ + \ + MOVQ rBe, rCa; \ + MOVQ rc, rT1; \ + ORQ rBi, rCa; \ + XORQ rBa, rT1; \ + XORQ rT1, rCa; \ + MOVQ rCa, _ba(oState); \ + \ + XORQ rDu, rBu; \ + ROLQ $14, rBu; \ + MOVQ rBa, rCu; \ + ANDQ rBe, rCu; \ + XORQ rBu, rCu; \ + MOVQ rCu, _bu(oState); \ + \ + XORQ rDo, rBo; \ + ROLQ $21, rBo; \ + MOVQ rBo, rT1; \ + ANDQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _bi(oState); \ + \ + NOTQ rBi; \ + ORQ rBa, rBu; \ + ORQ rBo, rBi; \ + XORQ rBo, rBu; \ + XORQ rBe, rBi; \ + MOVQ rBu, _bo(oState); \ + MOVQ rBi, _be(oState); \ + B_RBI_RCE; \ + \ + /* Result g */ \ + MOVQ _gu(iState), rBe; \ + XORQ rDu, rBe; \ + MOVQ _ka(iState), rBi; \ + ROLQ $20, rBe; \ + XORQ rDa, rBi; \ + ROLQ $3, rBi; \ + MOVQ _bo(iState), rBa; \ + MOVQ rBe, rT1; \ + ORQ rBi, rT1; \ + XORQ rDo, rBa; \ + MOVQ _me(iState), rBo; \ + MOVQ _si(iState), rBu; \ + ROLQ $28, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ga(oState); \ + G_RT1_RCA; \ + \ + XORQ rDe, rBo; \ + ROLQ $45, rBo; \ + MOVQ rBi, rT1; \ + ANDQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _ge(oState); \ + G_RT1_RCE; \ + \ + XORQ rDi, rBu; \ + ROLQ $61, rBu; \ + MOVQ rBu, rT1; \ + ORQ rBa, rT1; \ + XORQ rBo, rT1; \ + MOVQ rT1, _go(oState); \ + \ + ANDQ rBe, rBa; \ + XORQ rBu, rBa; \ + MOVQ rBa, _gu(oState); \ + NOTQ rBu; \ + G_RBA_RCU; \ + \ + ORQ rBu, rBo; \ + XORQ rBi, rBo; \ + MOVQ rBo, _gi(oState); \ + \ + /* Result k */ \ + MOVQ _be(iState), rBa; \ + MOVQ _gi(iState), rBe; \ + MOVQ _ko(iState), rBi; \ + MOVQ _mu(iState), rBo; \ + MOVQ _sa(iState), rBu; \ + XORQ rDi, rBe; \ + ROLQ $6, rBe; \ + XORQ rDo, rBi; \ + ROLQ $25, rBi; \ + MOVQ rBe, rT1; \ + ORQ rBi, rT1; \ + XORQ rDe, rBa; \ + ROLQ $1, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ka(oState); \ + K_RT1_RCA; \ + \ + XORQ rDu, rBo; \ + ROLQ $8, rBo; \ + MOVQ rBi, rT1; \ + ANDQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _ke(oState); \ + K_RT1_RCE; \ + \ + XORQ rDa, rBu; \ + ROLQ $18, rBu; \ + NOTQ rBo; \ + MOVQ rBo, rT1; \ + ANDQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _ki(oState); \ + \ + MOVQ rBu, rT1; \ + ORQ rBa, rT1; \ + XORQ rBo, rT1; \ + MOVQ rT1, _ko(oState); \ + \ + ANDQ rBe, rBa; \ + XORQ rBu, rBa; \ + MOVQ rBa, _ku(oState); \ + K_RBA_RCU; \ + \ + /* Result m */ \ + MOVQ _ga(iState), rBe; \ + XORQ rDa, rBe; \ + MOVQ _ke(iState), rBi; \ + ROLQ $36, rBe; \ + XORQ rDe, rBi; \ + MOVQ _bu(iState), rBa; \ + ROLQ $10, rBi; \ + MOVQ rBe, rT1; \ + MOVQ _mi(iState), rBo; \ + ANDQ rBi, rT1; \ + XORQ rDu, rBa; \ + MOVQ _so(iState), rBu; \ + ROLQ $27, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ma(oState); \ + M_RT1_RCA; \ + \ + XORQ rDi, rBo; \ + ROLQ $15, rBo; \ + MOVQ rBi, rT1; \ + ORQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _me(oState); \ + M_RT1_RCE; \ + \ + XORQ rDo, rBu; \ + ROLQ $56, rBu; \ + NOTQ rBo; \ + MOVQ rBo, rT1; \ + ORQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _mi(oState); \ + \ + ORQ rBa, rBe; \ + XORQ rBu, rBe; \ + MOVQ rBe, _mu(oState); \ + \ + ANDQ rBa, rBu; \ + XORQ rBo, rBu; \ + MOVQ rBu, _mo(oState); \ + M_RBE_RCU; \ + \ + /* Result s */ \ + MOVQ _bi(iState), rBa; \ + MOVQ _go(iState), rBe; \ + MOVQ _ku(iState), rBi; \ + XORQ rDi, rBa; \ + MOVQ _ma(iState), rBo; \ + ROLQ $62, rBa; \ + XORQ rDo, rBe; \ + MOVQ _se(iState), rBu; \ + ROLQ $55, rBe; \ + \ + XORQ rDu, rBi; \ + MOVQ rBa, rDu; \ + XORQ rDe, rBu; \ + ROLQ $2, rBu; \ + ANDQ rBe, rDu; \ + XORQ rBu, rDu; \ + MOVQ rDu, _su(oState); \ + \ + ROLQ $39, rBi; \ + S_RDU_RCU; \ + NOTQ rBe; \ + XORQ rDa, rBo; \ + MOVQ rBe, rDa; \ + ANDQ rBi, rDa; \ + XORQ rBa, rDa; \ + MOVQ rDa, _sa(oState); \ + S_RDA_RCA; \ + \ + ROLQ $41, rBo; \ + MOVQ rBi, rDe; \ + ORQ rBo, rDe; \ + XORQ rBe, rDe; \ + MOVQ rDe, _se(oState); \ + S_RDE_RCE; \ + \ + MOVQ rBo, rDi; \ + MOVQ rBu, rDo; \ + ANDQ rBu, rDi; \ + ORQ rBa, rDo; \ + XORQ rBi, rDi; \ + XORQ rBo, rDo; \ + MOVQ rDi, _si(oState); \ + MOVQ rDo, _so(oState) \ + +// func keccakF1600(a *[25]uint64) +TEXT ·keccakF1600(SB), 0, $200-8 + MOVQ a+0(FP), rpState + + // Convert the user state into an internal state + NOTQ _be(rpState) + NOTQ _bi(rpState) + NOTQ _go(rpState) + NOTQ _ki(rpState) + NOTQ _mi(rpState) + NOTQ _sa(rpState) + + // Execute the KeccakF permutation + MOVQ _ba(rpState), rCa + MOVQ _be(rpState), rCe + MOVQ _bu(rpState), rCu + + XORQ _ga(rpState), rCa + XORQ _ge(rpState), rCe + XORQ _gu(rpState), rCu + + XORQ _ka(rpState), rCa + XORQ _ke(rpState), rCe + XORQ _ku(rpState), rCu + + XORQ _ma(rpState), rCa + XORQ _me(rpState), rCe + XORQ _mu(rpState), rCu + + XORQ _sa(rpState), rCa + XORQ _se(rpState), rCe + MOVQ _si(rpState), rDi + MOVQ _so(rpState), rDo + XORQ _su(rpState), rCu + + mKeccakRound(rpState, rpStack, $0x0000000000000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000000008082, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x800000000000808a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000080008000, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000008a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000000000088, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x0000000080008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x000000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000008000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x800000000000008b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000000008089, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008003, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000000008002, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000000080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000800a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x800000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000080008008, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP) + + // Revert the internal state to the user state + NOTQ _be(rpState) + NOTQ _bi(rpState) + NOTQ _go(rpState) + NOTQ _ki(rpState) + NOTQ _mi(rpState) + NOTQ _sa(rpState) + + RET diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/register.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/register.go new file mode 100644 index 000000000000..addfd5049bb9 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/register.go @@ -0,0 +1,18 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.4 + +package sha3 + +import ( + "crypto" +) + +func init() { + crypto.RegisterHash(crypto.SHA3_224, New224) + crypto.RegisterHash(crypto.SHA3_256, New256) + crypto.RegisterHash(crypto.SHA3_384, New384) + crypto.RegisterHash(crypto.SHA3_512, New512) +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3.go new file mode 100644 index 000000000000..afedde5abf1f --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3.go @@ -0,0 +1,185 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +// spongeDirection indicates the direction bytes are flowing through the sponge. +type spongeDirection int + +const ( + // spongeAbsorbing indicates that the sponge is absorbing input. + spongeAbsorbing spongeDirection = iota + // spongeSqueezing indicates that the sponge is being squeezed. + spongeSqueezing +) + +const ( + // maxRate is the maximum size of the internal buffer. SHAKE-256 + // currently needs the largest buffer. + maxRate = 168 +) + +type state struct { + // Generic sponge components. + a [25]uint64 // main state of the hash + rate int // the number of bytes of state to use + + // dsbyte contains the "domain separation" bits and the first bit of + // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the + // SHA-3 and SHAKE functions by appending bitstrings to the message. + // Using a little-endian bit-ordering convention, these are "01" for SHA-3 + // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the + // padding rule from section 5.1 is applied to pad the message to a multiple + // of the rate, which involves adding a "1" bit, zero or more "0" bits, and + // a final "1" bit. We merge the first "1" bit from the padding into dsbyte, + // giving 00000110b (0x06) and 00011111b (0x1f). + // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf + // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and + // Extendable-Output Functions (May 2014)" + dsbyte byte + + i, n int // storage[i:n] is the buffer, i is only used while squeezing + storage [maxRate]byte + + // Specific to SHA-3 and SHAKE. + outputLen int // the default output size in bytes + state spongeDirection // whether the sponge is absorbing or squeezing +} + +// BlockSize returns the rate of sponge underlying this hash function. +func (d *state) BlockSize() int { return d.rate } + +// Size returns the output size of the hash function in bytes. +func (d *state) Size() int { return d.outputLen } + +// Reset clears the internal state by zeroing the sponge state and +// the buffer indexes, and setting Sponge.state to absorbing. +func (d *state) Reset() { + // Zero the permutation's state. + for i := range d.a { + d.a[i] = 0 + } + d.state = spongeAbsorbing + d.i, d.n = 0, 0 +} + +func (d *state) clone() *state { + ret := *d + return &ret +} + +// permute applies the KeccakF-1600 permutation. It handles +// any input-output buffering. +func (d *state) permute() { + switch d.state { + case spongeAbsorbing: + // If we're absorbing, we need to xor the input into the state + // before applying the permutation. + xorIn(d, d.storage[:d.rate]) + d.n = 0 + keccakF1600(&d.a) + case spongeSqueezing: + // If we're squeezing, we need to apply the permutation before + // copying more output. + keccakF1600(&d.a) + d.i = 0 + copyOut(d, d.storage[:d.rate]) + } +} + +// pads appends the domain separation bits in dsbyte, applies +// the multi-bitrate 10..1 padding rule, and permutes the state. +func (d *state) padAndPermute() { + // Pad with this instance's domain-separator bits. We know that there's + // at least one byte of space in d.buf because, if it were full, + // permute would have been called to empty it. dsbyte also contains the + // first one bit for the padding. See the comment in the state struct. + d.storage[d.n] = d.dsbyte + d.n++ + for d.n < d.rate { + d.storage[d.n] = 0 + d.n++ + } + // This adds the final one bit for the padding. Because of the way that + // bits are numbered from the LSB upwards, the final bit is the MSB of + // the last byte. + d.storage[d.rate-1] ^= 0x80 + // Apply the permutation + d.permute() + d.state = spongeSqueezing + d.n = d.rate + copyOut(d, d.storage[:d.rate]) +} + +// Write absorbs more data into the hash's state. It panics if any +// output has already been read. +func (d *state) Write(p []byte) (written int, err error) { + if d.state != spongeAbsorbing { + panic("sha3: Write after Read") + } + written = len(p) + + for len(p) > 0 { + if d.n == 0 && len(p) >= d.rate { + // The fast path; absorb a full "rate" bytes of input and apply the permutation. + xorIn(d, p[:d.rate]) + p = p[d.rate:] + keccakF1600(&d.a) + } else { + // The slow path; buffer the input until we can fill the sponge, and then xor it in. + todo := d.rate - d.n + if todo > len(p) { + todo = len(p) + } + d.n += copy(d.storage[d.n:], p[:todo]) + p = p[todo:] + + // If the sponge is full, apply the permutation. + if d.n == d.rate { + d.permute() + } + } + } + + return +} + +// Read squeezes an arbitrary number of bytes from the sponge. +func (d *state) Read(out []byte) (n int, err error) { + // If we're still absorbing, pad and apply the permutation. + if d.state == spongeAbsorbing { + d.padAndPermute() + } + + n = len(out) + + // Now, do the squeezing. + for len(out) > 0 { + n := copy(out, d.storage[d.i:d.n]) + d.i += n + out = out[n:] + + // Apply the permutation if we've squeezed the sponge dry. + if d.i == d.rate { + d.permute() + } + } + + return +} + +// Sum applies padding to the hash state and then squeezes out the desired +// number of output bytes. It panics if any output has already been read. +func (d *state) Sum(in []byte) []byte { + if d.state != spongeAbsorbing { + panic("sha3: Sum after Read") + } + + // Make a copy of the original hash so that caller can keep writing + // and summing. + dup := d.clone() + hash := make([]byte, dup.outputLen, 64) // explicit cap to allow stack allocation + dup.Read(hash) + return append(in, hash...) +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.go new file mode 100644 index 000000000000..00d8034ae627 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.go @@ -0,0 +1,303 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego + +package sha3 + +// This file contains code for using the 'compute intermediate +// message digest' (KIMD) and 'compute last message digest' (KLMD) +// instructions to compute SHA-3 and SHAKE hashes on IBM Z. + +import ( + "hash" + + "golang.org/x/sys/cpu" +) + +// codes represent 7-bit KIMD/KLMD function codes as defined in +// the Principles of Operation. +type code uint64 + +const ( + // function codes for KIMD/KLMD + sha3_224 code = 32 + sha3_256 = 33 + sha3_384 = 34 + sha3_512 = 35 + shake_128 = 36 + shake_256 = 37 + nopad = 0x100 +) + +// kimd is a wrapper for the 'compute intermediate message digest' instruction. +// src must be a multiple of the rate for the given function code. +// +//go:noescape +func kimd(function code, chain *[200]byte, src []byte) + +// klmd is a wrapper for the 'compute last message digest' instruction. +// src padding is handled by the instruction. +// +//go:noescape +func klmd(function code, chain *[200]byte, dst, src []byte) + +type asmState struct { + a [200]byte // 1600 bit state + buf []byte // care must be taken to ensure cap(buf) is a multiple of rate + rate int // equivalent to block size + storage [3072]byte // underlying storage for buf + outputLen int // output length for full security + function code // KIMD/KLMD function code + state spongeDirection // whether the sponge is absorbing or squeezing +} + +func newAsmState(function code) *asmState { + var s asmState + s.function = function + switch function { + case sha3_224: + s.rate = 144 + s.outputLen = 28 + case sha3_256: + s.rate = 136 + s.outputLen = 32 + case sha3_384: + s.rate = 104 + s.outputLen = 48 + case sha3_512: + s.rate = 72 + s.outputLen = 64 + case shake_128: + s.rate = 168 + s.outputLen = 32 + case shake_256: + s.rate = 136 + s.outputLen = 64 + default: + panic("sha3: unrecognized function code") + } + + // limit s.buf size to a multiple of s.rate + s.resetBuf() + return &s +} + +func (s *asmState) clone() *asmState { + c := *s + c.buf = c.storage[:len(s.buf):cap(s.buf)] + return &c +} + +// copyIntoBuf copies b into buf. It will panic if there is not enough space to +// store all of b. +func (s *asmState) copyIntoBuf(b []byte) { + bufLen := len(s.buf) + s.buf = s.buf[:len(s.buf)+len(b)] + copy(s.buf[bufLen:], b) +} + +// resetBuf points buf at storage, sets the length to 0 and sets cap to be a +// multiple of the rate. +func (s *asmState) resetBuf() { + max := (cap(s.storage) / s.rate) * s.rate + s.buf = s.storage[:0:max] +} + +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (s *asmState) Write(b []byte) (int, error) { + if s.state != spongeAbsorbing { + panic("sha3: Write after Read") + } + length := len(b) + for len(b) > 0 { + if len(s.buf) == 0 && len(b) >= cap(s.buf) { + // Hash the data directly and push any remaining bytes + // into the buffer. + remainder := len(b) % s.rate + kimd(s.function, &s.a, b[:len(b)-remainder]) + if remainder != 0 { + s.copyIntoBuf(b[len(b)-remainder:]) + } + return length, nil + } + + if len(s.buf) == cap(s.buf) { + // flush the buffer + kimd(s.function, &s.a, s.buf) + s.buf = s.buf[:0] + } + + // copy as much as we can into the buffer + n := len(b) + if len(b) > cap(s.buf)-len(s.buf) { + n = cap(s.buf) - len(s.buf) + } + s.copyIntoBuf(b[:n]) + b = b[n:] + } + return length, nil +} + +// Read squeezes an arbitrary number of bytes from the sponge. +func (s *asmState) Read(out []byte) (n int, err error) { + // The 'compute last message digest' instruction only stores the digest + // at the first operand (dst) for SHAKE functions. + if s.function != shake_128 && s.function != shake_256 { + panic("sha3: can only call Read for SHAKE functions") + } + + n = len(out) + + // need to pad if we were absorbing + if s.state == spongeAbsorbing { + s.state = spongeSqueezing + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function, &s.a, out, s.buf) // len(out) may be 0 + s.buf = s.buf[:0] + return + } + + // write hash into buffer + max := cap(s.buf) + if max > len(out) { + max = (len(out)/s.rate)*s.rate + s.rate + } + klmd(s.function, &s.a, s.buf[:max], s.buf) + s.buf = s.buf[:max] + } + + for len(out) > 0 { + // flush the buffer + if len(s.buf) != 0 { + c := copy(out, s.buf) + out = out[c:] + s.buf = s.buf[c:] + continue + } + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function|nopad, &s.a, out, nil) + return + } + + // write hash into buffer + s.resetBuf() + if cap(s.buf) > len(out) { + s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate] + } + klmd(s.function|nopad, &s.a, s.buf, nil) + } + return +} + +// Sum appends the current hash to b and returns the resulting slice. +// It does not change the underlying hash state. +func (s *asmState) Sum(b []byte) []byte { + if s.state != spongeAbsorbing { + panic("sha3: Sum after Read") + } + + // Copy the state to preserve the original. + a := s.a + + // Hash the buffer. Note that we don't clear it because we + // aren't updating the state. + switch s.function { + case sha3_224, sha3_256, sha3_384, sha3_512: + klmd(s.function, &a, nil, s.buf) + return append(b, a[:s.outputLen]...) + case shake_128, shake_256: + d := make([]byte, s.outputLen, 64) + klmd(s.function, &a, d, s.buf) + return append(b, d[:s.outputLen]...) + default: + panic("sha3: unknown function") + } +} + +// Reset resets the Hash to its initial state. +func (s *asmState) Reset() { + for i := range s.a { + s.a[i] = 0 + } + s.resetBuf() + s.state = spongeAbsorbing +} + +// Size returns the number of bytes Sum will return. +func (s *asmState) Size() int { + return s.outputLen +} + +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (s *asmState) BlockSize() int { + return s.rate +} + +// Clone returns a copy of the ShakeHash in its current state. +func (s *asmState) Clone() ShakeHash { + return s.clone() +} + +// new224 returns an assembly implementation of SHA3-224 if available, +// otherwise it returns a generic implementation. +func new224() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_224) + } + return new224Generic() +} + +// new256 returns an assembly implementation of SHA3-256 if available, +// otherwise it returns a generic implementation. +func new256() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_256) + } + return new256Generic() +} + +// new384 returns an assembly implementation of SHA3-384 if available, +// otherwise it returns a generic implementation. +func new384() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_384) + } + return new384Generic() +} + +// new512 returns an assembly implementation of SHA3-512 if available, +// otherwise it returns a generic implementation. +func new512() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_512) + } + return new512Generic() +} + +// newShake128 returns an assembly implementation of SHAKE-128 if available, +// otherwise it returns a generic implementation. +func newShake128() ShakeHash { + if cpu.S390X.HasSHA3 { + return newAsmState(shake_128) + } + return newShake128Generic() +} + +// newShake256 returns an assembly implementation of SHAKE-256 if available, +// otherwise it returns a generic implementation. +func newShake256() ShakeHash { + if cpu.S390X.HasSHA3 { + return newAsmState(shake_256) + } + return newShake256Generic() +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.s new file mode 100644 index 000000000000..826b862c7796 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.s @@ -0,0 +1,33 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego + +#include "textflag.h" + +// func kimd(function code, chain *[200]byte, src []byte) +TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 + MOVD function+0(FP), R0 + MOVD chain+8(FP), R1 + LMG src+16(FP), R2, R3 // R2=base, R3=len + +continue: + WORD $0xB93E0002 // KIMD --, R2 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET + +// func klmd(function code, chain *[200]byte, dst, src []byte) +TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 + // TODO: SHAKE support + MOVD function+0(FP), R0 + MOVD chain+8(FP), R1 + LMG dst+16(FP), R2, R3 // R2=base, R3=len + LMG src+40(FP), R4, R5 // R4=base, R5=len + +continue: + WORD $0xB93F0024 // KLMD R2, R4 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake.go new file mode 100644 index 000000000000..1ea9275b8b7a --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake.go @@ -0,0 +1,174 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +// This file defines the ShakeHash interface, and provides +// functions for creating SHAKE and cSHAKE instances, as well as utility +// functions for hashing bytes to arbitrary-length output. +// +// +// SHAKE implementation is based on FIPS PUB 202 [1] +// cSHAKE implementations is based on NIST SP 800-185 [2] +// +// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf +// [2] https://doi.org/10.6028/NIST.SP.800-185 + +import ( + "encoding/binary" + "hash" + "io" +) + +// ShakeHash defines the interface to hash functions that support +// arbitrary-length output. When used as a plain [hash.Hash], it +// produces minimum-length outputs that provide full-strength generic +// security. +type ShakeHash interface { + hash.Hash + + // Read reads more output from the hash; reading affects the hash's + // state. (ShakeHash.Read is thus very different from Hash.Sum) + // It never returns an error, but subsequent calls to Write or Sum + // will panic. + io.Reader + + // Clone returns a copy of the ShakeHash in its current state. + Clone() ShakeHash +} + +// cSHAKE specific context +type cshakeState struct { + *state // SHA-3 state context and Read/Write operations + + // initBlock is the cSHAKE specific initialization set of bytes. It is initialized + // by newCShake function and stores concatenation of N followed by S, encoded + // by the method specified in 3.3 of [1]. + // It is stored here in order for Reset() to be able to put context into + // initial state. + initBlock []byte +} + +// Consts for configuring initial SHA-3 state +const ( + dsbyteShake = 0x1f + dsbyteCShake = 0x04 + rate128 = 168 + rate256 = 136 +) + +func bytepad(input []byte, w int) []byte { + // leftEncode always returns max 9 bytes + buf := make([]byte, 0, 9+len(input)+w) + buf = append(buf, leftEncode(uint64(w))...) + buf = append(buf, input...) + padlen := w - (len(buf) % w) + return append(buf, make([]byte, padlen)...) +} + +func leftEncode(value uint64) []byte { + var b [9]byte + binary.BigEndian.PutUint64(b[1:], value) + // Trim all but last leading zero bytes + i := byte(1) + for i < 8 && b[i] == 0 { + i++ + } + // Prepend number of encoded bytes + b[i-1] = 9 - i + return b[i-1:] +} + +func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash { + c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}} + + // leftEncode returns max 9 bytes + c.initBlock = make([]byte, 0, 9*2+len(N)+len(S)) + c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...) + c.initBlock = append(c.initBlock, N...) + c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...) + c.initBlock = append(c.initBlock, S...) + c.Write(bytepad(c.initBlock, c.rate)) + return &c +} + +// Reset resets the hash to initial state. +func (c *cshakeState) Reset() { + c.state.Reset() + c.Write(bytepad(c.initBlock, c.rate)) +} + +// Clone returns copy of a cSHAKE context within its current state. +func (c *cshakeState) Clone() ShakeHash { + b := make([]byte, len(c.initBlock)) + copy(b, c.initBlock) + return &cshakeState{state: c.clone(), initBlock: b} +} + +// Clone returns copy of SHAKE context within its current state. +func (c *state) Clone() ShakeHash { + return c.clone() +} + +// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. +// Its generic security strength is 128 bits against all attacks if at +// least 32 bytes of its output are used. +func NewShake128() ShakeHash { + return newShake128() +} + +// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. +// Its generic security strength is 256 bits against all attacks if +// at least 64 bytes of its output are used. +func NewShake256() ShakeHash { + return newShake256() +} + +func newShake128Generic() *state { + return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake} +} + +func newShake256Generic() *state { + return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake} +} + +// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, +// a customizable variant of SHAKE128. +// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is +// desired. S is a customization byte string used for domain separation - two cSHAKE +// computations on same input with different S yield unrelated outputs. +// When N and S are both empty, this is equivalent to NewShake128. +func NewCShake128(N, S []byte) ShakeHash { + if len(N) == 0 && len(S) == 0 { + return NewShake128() + } + return newCShake(N, S, rate128, 32, dsbyteCShake) +} + +// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, +// a customizable variant of SHAKE256. +// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is +// desired. S is a customization byte string used for domain separation - two cSHAKE +// computations on same input with different S yield unrelated outputs. +// When N and S are both empty, this is equivalent to NewShake256. +func NewCShake256(N, S []byte) ShakeHash { + if len(N) == 0 && len(S) == 0 { + return NewShake256() + } + return newCShake(N, S, rate256, 64, dsbyteCShake) +} + +// ShakeSum128 writes an arbitrary-length digest of data into hash. +func ShakeSum128(hash, data []byte) { + h := NewShake128() + h.Write(data) + h.Read(hash) +} + +// ShakeSum256 writes an arbitrary-length digest of data into hash. +func ShakeSum256(hash, data []byte) { + h := NewShake256() + h.Write(data) + h.Read(hash) +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake_noasm.go new file mode 100644 index 000000000000..4276ba4ab2c4 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake_noasm.go @@ -0,0 +1,15 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !gc || purego || !s390x + +package sha3 + +func newShake128() *state { + return newShake128Generic() +} + +func newShake256() *state { + return newShake256Generic() +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/xor.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/xor.go new file mode 100644 index 000000000000..6ada5c9574e2 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/xor.go @@ -0,0 +1,40 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +import ( + "crypto/subtle" + "encoding/binary" + "unsafe" + + "golang.org/x/sys/cpu" +) + +// xorIn xors the bytes in buf into the state. +func xorIn(d *state, buf []byte) { + if cpu.IsBigEndian { + for i := 0; len(buf) >= 8; i++ { + a := binary.LittleEndian.Uint64(buf) + d.a[i] ^= a + buf = buf[8:] + } + } else { + ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a)) + subtle.XORBytes(ab[:], ab[:], buf) + } +} + +// copyOut copies uint64s to a byte buffer. +func copyOut(d *state, b []byte) { + if cpu.IsBigEndian { + for i := 0; len(b) >= 8; i++ { + binary.LittleEndian.PutUint64(b, d.a[i]) + b = b[8:] + } + } else { + ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a)) + copy(b, ab[:]) + } +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/ya.make new file mode 100644 index 000000000000..9fe025ba24ec --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/ya.make @@ -0,0 +1,28 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + hashes.go + hashes_noasm.go + keccakf.go + register.go + sha3.go + shake.go + shake_noasm.go + xor.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + hashes.go + hashes_noasm.go + keccakf_amd64.go + keccakf_amd64.s + register.go + sha3.go + shake.go + shake_noasm.go + xor.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/message.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/message.go new file mode 100644 index 000000000000..a656efc128a6 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/message.go @@ -0,0 +1,2712 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package dnsmessage provides a mostly RFC 1035 compliant implementation of +// DNS message packing and unpacking. +// +// The package also supports messages with Extension Mechanisms for DNS +// (EDNS(0)) as defined in RFC 6891. +// +// This implementation is designed to minimize heap allocations and avoid +// unnecessary packing and unpacking as much as possible. +package dnsmessage + +import ( + "errors" +) + +// Message formats + +// A Type is a type of DNS request and response. +type Type uint16 + +const ( + // ResourceHeader.Type and Question.Type + TypeA Type = 1 + TypeNS Type = 2 + TypeCNAME Type = 5 + TypeSOA Type = 6 + TypePTR Type = 12 + TypeMX Type = 15 + TypeTXT Type = 16 + TypeAAAA Type = 28 + TypeSRV Type = 33 + TypeOPT Type = 41 + + // Question.Type + TypeWKS Type = 11 + TypeHINFO Type = 13 + TypeMINFO Type = 14 + TypeAXFR Type = 252 + TypeALL Type = 255 +) + +var typeNames = map[Type]string{ + TypeA: "TypeA", + TypeNS: "TypeNS", + TypeCNAME: "TypeCNAME", + TypeSOA: "TypeSOA", + TypePTR: "TypePTR", + TypeMX: "TypeMX", + TypeTXT: "TypeTXT", + TypeAAAA: "TypeAAAA", + TypeSRV: "TypeSRV", + TypeOPT: "TypeOPT", + TypeWKS: "TypeWKS", + TypeHINFO: "TypeHINFO", + TypeMINFO: "TypeMINFO", + TypeAXFR: "TypeAXFR", + TypeALL: "TypeALL", +} + +// String implements fmt.Stringer.String. +func (t Type) String() string { + if n, ok := typeNames[t]; ok { + return n + } + return printUint16(uint16(t)) +} + +// GoString implements fmt.GoStringer.GoString. +func (t Type) GoString() string { + if n, ok := typeNames[t]; ok { + return "dnsmessage." + n + } + return printUint16(uint16(t)) +} + +// A Class is a type of network. +type Class uint16 + +const ( + // ResourceHeader.Class and Question.Class + ClassINET Class = 1 + ClassCSNET Class = 2 + ClassCHAOS Class = 3 + ClassHESIOD Class = 4 + + // Question.Class + ClassANY Class = 255 +) + +var classNames = map[Class]string{ + ClassINET: "ClassINET", + ClassCSNET: "ClassCSNET", + ClassCHAOS: "ClassCHAOS", + ClassHESIOD: "ClassHESIOD", + ClassANY: "ClassANY", +} + +// String implements fmt.Stringer.String. +func (c Class) String() string { + if n, ok := classNames[c]; ok { + return n + } + return printUint16(uint16(c)) +} + +// GoString implements fmt.GoStringer.GoString. +func (c Class) GoString() string { + if n, ok := classNames[c]; ok { + return "dnsmessage." + n + } + return printUint16(uint16(c)) +} + +// An OpCode is a DNS operation code. +type OpCode uint16 + +// GoString implements fmt.GoStringer.GoString. +func (o OpCode) GoString() string { + return printUint16(uint16(o)) +} + +// An RCode is a DNS response status code. +type RCode uint16 + +// Header.RCode values. +const ( + RCodeSuccess RCode = 0 // NoError + RCodeFormatError RCode = 1 // FormErr + RCodeServerFailure RCode = 2 // ServFail + RCodeNameError RCode = 3 // NXDomain + RCodeNotImplemented RCode = 4 // NotImp + RCodeRefused RCode = 5 // Refused +) + +var rCodeNames = map[RCode]string{ + RCodeSuccess: "RCodeSuccess", + RCodeFormatError: "RCodeFormatError", + RCodeServerFailure: "RCodeServerFailure", + RCodeNameError: "RCodeNameError", + RCodeNotImplemented: "RCodeNotImplemented", + RCodeRefused: "RCodeRefused", +} + +// String implements fmt.Stringer.String. +func (r RCode) String() string { + if n, ok := rCodeNames[r]; ok { + return n + } + return printUint16(uint16(r)) +} + +// GoString implements fmt.GoStringer.GoString. +func (r RCode) GoString() string { + if n, ok := rCodeNames[r]; ok { + return "dnsmessage." + n + } + return printUint16(uint16(r)) +} + +func printPaddedUint8(i uint8) string { + b := byte(i) + return string([]byte{ + b/100 + '0', + b/10%10 + '0', + b%10 + '0', + }) +} + +func printUint8Bytes(buf []byte, i uint8) []byte { + b := byte(i) + if i >= 100 { + buf = append(buf, b/100+'0') + } + if i >= 10 { + buf = append(buf, b/10%10+'0') + } + return append(buf, b%10+'0') +} + +func printByteSlice(b []byte) string { + if len(b) == 0 { + return "" + } + buf := make([]byte, 0, 5*len(b)) + buf = printUint8Bytes(buf, uint8(b[0])) + for _, n := range b[1:] { + buf = append(buf, ',', ' ') + buf = printUint8Bytes(buf, uint8(n)) + } + return string(buf) +} + +const hexDigits = "0123456789abcdef" + +func printString(str []byte) string { + buf := make([]byte, 0, len(str)) + for i := 0; i < len(str); i++ { + c := str[i] + if c == '.' || c == '-' || c == ' ' || + 'A' <= c && c <= 'Z' || + 'a' <= c && c <= 'z' || + '0' <= c && c <= '9' { + buf = append(buf, c) + continue + } + + upper := c >> 4 + lower := (c << 4) >> 4 + buf = append( + buf, + '\\', + 'x', + hexDigits[upper], + hexDigits[lower], + ) + } + return string(buf) +} + +func printUint16(i uint16) string { + return printUint32(uint32(i)) +} + +func printUint32(i uint32) string { + // Max value is 4294967295. + buf := make([]byte, 10) + for b, d := buf, uint32(1000000000); d > 0; d /= 10 { + b[0] = byte(i/d%10 + '0') + if b[0] == '0' && len(b) == len(buf) && len(buf) > 1 { + buf = buf[1:] + } + b = b[1:] + i %= d + } + return string(buf) +} + +func printBool(b bool) string { + if b { + return "true" + } + return "false" +} + +var ( + // ErrNotStarted indicates that the prerequisite information isn't + // available yet because the previous records haven't been appropriately + // parsed, skipped or finished. + ErrNotStarted = errors.New("parsing/packing of this type isn't available yet") + + // ErrSectionDone indicated that all records in the section have been + // parsed or finished. + ErrSectionDone = errors.New("parsing/packing of this section has completed") + + errBaseLen = errors.New("insufficient data for base length type") + errCalcLen = errors.New("insufficient data for calculated length type") + errReserved = errors.New("segment prefix is reserved") + errTooManyPtr = errors.New("too many pointers (>10)") + errInvalidPtr = errors.New("invalid pointer") + errInvalidName = errors.New("invalid dns name") + errNilResouceBody = errors.New("nil resource body") + errResourceLen = errors.New("insufficient data for resource body length") + errSegTooLong = errors.New("segment length too long") + errNameTooLong = errors.New("name too long") + errZeroSegLen = errors.New("zero length segment") + errResTooLong = errors.New("resource length too long") + errTooManyQuestions = errors.New("too many Questions to pack (>65535)") + errTooManyAnswers = errors.New("too many Answers to pack (>65535)") + errTooManyAuthorities = errors.New("too many Authorities to pack (>65535)") + errTooManyAdditionals = errors.New("too many Additionals to pack (>65535)") + errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)") + errStringTooLong = errors.New("character string exceeds maximum length (255)") +) + +// Internal constants. +const ( + // packStartingCap is the default initial buffer size allocated during + // packing. + // + // The starting capacity doesn't matter too much, but most DNS responses + // Will be <= 512 bytes as it is the limit for DNS over UDP. + packStartingCap = 512 + + // uint16Len is the length (in bytes) of a uint16. + uint16Len = 2 + + // uint32Len is the length (in bytes) of a uint32. + uint32Len = 4 + + // headerLen is the length (in bytes) of a DNS header. + // + // A header is comprised of 6 uint16s and no padding. + headerLen = 6 * uint16Len +) + +type nestedError struct { + // s is the current level's error message. + s string + + // err is the nested error. + err error +} + +// nestedError implements error.Error. +func (e *nestedError) Error() string { + return e.s + ": " + e.err.Error() +} + +// Header is a representation of a DNS message header. +type Header struct { + ID uint16 + Response bool + OpCode OpCode + Authoritative bool + Truncated bool + RecursionDesired bool + RecursionAvailable bool + AuthenticData bool + CheckingDisabled bool + RCode RCode +} + +func (m *Header) pack() (id uint16, bits uint16) { + id = m.ID + bits = uint16(m.OpCode)<<11 | uint16(m.RCode) + if m.RecursionAvailable { + bits |= headerBitRA + } + if m.RecursionDesired { + bits |= headerBitRD + } + if m.Truncated { + bits |= headerBitTC + } + if m.Authoritative { + bits |= headerBitAA + } + if m.Response { + bits |= headerBitQR + } + if m.AuthenticData { + bits |= headerBitAD + } + if m.CheckingDisabled { + bits |= headerBitCD + } + return +} + +// GoString implements fmt.GoStringer.GoString. +func (m *Header) GoString() string { + return "dnsmessage.Header{" + + "ID: " + printUint16(m.ID) + ", " + + "Response: " + printBool(m.Response) + ", " + + "OpCode: " + m.OpCode.GoString() + ", " + + "Authoritative: " + printBool(m.Authoritative) + ", " + + "Truncated: " + printBool(m.Truncated) + ", " + + "RecursionDesired: " + printBool(m.RecursionDesired) + ", " + + "RecursionAvailable: " + printBool(m.RecursionAvailable) + ", " + + "AuthenticData: " + printBool(m.AuthenticData) + ", " + + "CheckingDisabled: " + printBool(m.CheckingDisabled) + ", " + + "RCode: " + m.RCode.GoString() + "}" +} + +// Message is a representation of a DNS message. +type Message struct { + Header + Questions []Question + Answers []Resource + Authorities []Resource + Additionals []Resource +} + +type section uint8 + +const ( + sectionNotStarted section = iota + sectionHeader + sectionQuestions + sectionAnswers + sectionAuthorities + sectionAdditionals + sectionDone + + headerBitQR = 1 << 15 // query/response (response=1) + headerBitAA = 1 << 10 // authoritative + headerBitTC = 1 << 9 // truncated + headerBitRD = 1 << 8 // recursion desired + headerBitRA = 1 << 7 // recursion available + headerBitAD = 1 << 5 // authentic data + headerBitCD = 1 << 4 // checking disabled +) + +var sectionNames = map[section]string{ + sectionHeader: "header", + sectionQuestions: "Question", + sectionAnswers: "Answer", + sectionAuthorities: "Authority", + sectionAdditionals: "Additional", +} + +// header is the wire format for a DNS message header. +type header struct { + id uint16 + bits uint16 + questions uint16 + answers uint16 + authorities uint16 + additionals uint16 +} + +func (h *header) count(sec section) uint16 { + switch sec { + case sectionQuestions: + return h.questions + case sectionAnswers: + return h.answers + case sectionAuthorities: + return h.authorities + case sectionAdditionals: + return h.additionals + } + return 0 +} + +// pack appends the wire format of the header to msg. +func (h *header) pack(msg []byte) []byte { + msg = packUint16(msg, h.id) + msg = packUint16(msg, h.bits) + msg = packUint16(msg, h.questions) + msg = packUint16(msg, h.answers) + msg = packUint16(msg, h.authorities) + return packUint16(msg, h.additionals) +} + +func (h *header) unpack(msg []byte, off int) (int, error) { + newOff := off + var err error + if h.id, newOff, err = unpackUint16(msg, newOff); err != nil { + return off, &nestedError{"id", err} + } + if h.bits, newOff, err = unpackUint16(msg, newOff); err != nil { + return off, &nestedError{"bits", err} + } + if h.questions, newOff, err = unpackUint16(msg, newOff); err != nil { + return off, &nestedError{"questions", err} + } + if h.answers, newOff, err = unpackUint16(msg, newOff); err != nil { + return off, &nestedError{"answers", err} + } + if h.authorities, newOff, err = unpackUint16(msg, newOff); err != nil { + return off, &nestedError{"authorities", err} + } + if h.additionals, newOff, err = unpackUint16(msg, newOff); err != nil { + return off, &nestedError{"additionals", err} + } + return newOff, nil +} + +func (h *header) header() Header { + return Header{ + ID: h.id, + Response: (h.bits & headerBitQR) != 0, + OpCode: OpCode(h.bits>>11) & 0xF, + Authoritative: (h.bits & headerBitAA) != 0, + Truncated: (h.bits & headerBitTC) != 0, + RecursionDesired: (h.bits & headerBitRD) != 0, + RecursionAvailable: (h.bits & headerBitRA) != 0, + AuthenticData: (h.bits & headerBitAD) != 0, + CheckingDisabled: (h.bits & headerBitCD) != 0, + RCode: RCode(h.bits & 0xF), + } +} + +// A Resource is a DNS resource record. +type Resource struct { + Header ResourceHeader + Body ResourceBody +} + +func (r *Resource) GoString() string { + return "dnsmessage.Resource{" + + "Header: " + r.Header.GoString() + + ", Body: &" + r.Body.GoString() + + "}" +} + +// A ResourceBody is a DNS resource record minus the header. +type ResourceBody interface { + // pack packs a Resource except for its header. + pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) + + // realType returns the actual type of the Resource. This is used to + // fill in the header Type field. + realType() Type + + // GoString implements fmt.GoStringer.GoString. + GoString() string +} + +// pack appends the wire format of the Resource to msg. +func (r *Resource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + if r.Body == nil { + return msg, errNilResouceBody + } + oldMsg := msg + r.Header.Type = r.Body.realType() + msg, lenOff, err := r.Header.pack(msg, compression, compressionOff) + if err != nil { + return msg, &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + msg, err = r.Body.pack(msg, compression, compressionOff) + if err != nil { + return msg, &nestedError{"content", err} + } + if err := r.Header.fixLen(msg, lenOff, preLen); err != nil { + return oldMsg, err + } + return msg, nil +} + +// A Parser allows incrementally parsing a DNS message. +// +// When parsing is started, the Header is parsed. Next, each Question can be +// either parsed or skipped. Alternatively, all Questions can be skipped at +// once. When all Questions have been parsed, attempting to parse Questions +// will return the [ErrSectionDone] error. +// After all Questions have been either parsed or skipped, all +// Answers, Authorities and Additionals can be either parsed or skipped in the +// same way, and each type of Resource must be fully parsed or skipped before +// proceeding to the next type of Resource. +// +// Parser is safe to copy to preserve the parsing state. +// +// Note that there is no requirement to fully skip or parse the message. +type Parser struct { + msg []byte + header header + + section section + off int + index int + resHeaderValid bool + resHeaderOffset int + resHeaderType Type + resHeaderLength uint16 +} + +// Start parses the header and enables the parsing of Questions. +func (p *Parser) Start(msg []byte) (Header, error) { + if p.msg != nil { + *p = Parser{} + } + p.msg = msg + var err error + if p.off, err = p.header.unpack(msg, 0); err != nil { + return Header{}, &nestedError{"unpacking header", err} + } + p.section = sectionQuestions + return p.header.header(), nil +} + +func (p *Parser) checkAdvance(sec section) error { + if p.section < sec { + return ErrNotStarted + } + if p.section > sec { + return ErrSectionDone + } + p.resHeaderValid = false + if p.index == int(p.header.count(sec)) { + p.index = 0 + p.section++ + return ErrSectionDone + } + return nil +} + +func (p *Parser) resource(sec section) (Resource, error) { + var r Resource + var err error + r.Header, err = p.resourceHeader(sec) + if err != nil { + return r, err + } + p.resHeaderValid = false + r.Body, p.off, err = unpackResourceBody(p.msg, p.off, r.Header) + if err != nil { + return Resource{}, &nestedError{"unpacking " + sectionNames[sec], err} + } + p.index++ + return r, nil +} + +func (p *Parser) resourceHeader(sec section) (ResourceHeader, error) { + if p.resHeaderValid { + p.off = p.resHeaderOffset + } + + if err := p.checkAdvance(sec); err != nil { + return ResourceHeader{}, err + } + var hdr ResourceHeader + off, err := hdr.unpack(p.msg, p.off) + if err != nil { + return ResourceHeader{}, err + } + p.resHeaderValid = true + p.resHeaderOffset = p.off + p.resHeaderType = hdr.Type + p.resHeaderLength = hdr.Length + p.off = off + return hdr, nil +} + +func (p *Parser) skipResource(sec section) error { + if p.resHeaderValid && p.section == sec { + newOff := p.off + int(p.resHeaderLength) + if newOff > len(p.msg) { + return errResourceLen + } + p.off = newOff + p.resHeaderValid = false + p.index++ + return nil + } + if err := p.checkAdvance(sec); err != nil { + return err + } + var err error + p.off, err = skipResource(p.msg, p.off) + if err != nil { + return &nestedError{"skipping: " + sectionNames[sec], err} + } + p.index++ + return nil +} + +// Question parses a single Question. +func (p *Parser) Question() (Question, error) { + if err := p.checkAdvance(sectionQuestions); err != nil { + return Question{}, err + } + var name Name + off, err := name.unpack(p.msg, p.off) + if err != nil { + return Question{}, &nestedError{"unpacking Question.Name", err} + } + typ, off, err := unpackType(p.msg, off) + if err != nil { + return Question{}, &nestedError{"unpacking Question.Type", err} + } + class, off, err := unpackClass(p.msg, off) + if err != nil { + return Question{}, &nestedError{"unpacking Question.Class", err} + } + p.off = off + p.index++ + return Question{name, typ, class}, nil +} + +// AllQuestions parses all Questions. +func (p *Parser) AllQuestions() ([]Question, error) { + // Multiple questions are valid according to the spec, + // but servers don't actually support them. There will + // be at most one question here. + // + // Do not pre-allocate based on info in p.header, since + // the data is untrusted. + qs := []Question{} + for { + q, err := p.Question() + if err == ErrSectionDone { + return qs, nil + } + if err != nil { + return nil, err + } + qs = append(qs, q) + } +} + +// SkipQuestion skips a single Question. +func (p *Parser) SkipQuestion() error { + if err := p.checkAdvance(sectionQuestions); err != nil { + return err + } + off, err := skipName(p.msg, p.off) + if err != nil { + return &nestedError{"skipping Question Name", err} + } + if off, err = skipType(p.msg, off); err != nil { + return &nestedError{"skipping Question Type", err} + } + if off, err = skipClass(p.msg, off); err != nil { + return &nestedError{"skipping Question Class", err} + } + p.off = off + p.index++ + return nil +} + +// SkipAllQuestions skips all Questions. +func (p *Parser) SkipAllQuestions() error { + for { + if err := p.SkipQuestion(); err == ErrSectionDone { + return nil + } else if err != nil { + return err + } + } +} + +// AnswerHeader parses a single Answer ResourceHeader. +func (p *Parser) AnswerHeader() (ResourceHeader, error) { + return p.resourceHeader(sectionAnswers) +} + +// Answer parses a single Answer Resource. +func (p *Parser) Answer() (Resource, error) { + return p.resource(sectionAnswers) +} + +// AllAnswers parses all Answer Resources. +func (p *Parser) AllAnswers() ([]Resource, error) { + // The most common query is for A/AAAA, which usually returns + // a handful of IPs. + // + // Pre-allocate up to a certain limit, since p.header is + // untrusted data. + n := int(p.header.answers) + if n > 20 { + n = 20 + } + as := make([]Resource, 0, n) + for { + a, err := p.Answer() + if err == ErrSectionDone { + return as, nil + } + if err != nil { + return nil, err + } + as = append(as, a) + } +} + +// SkipAnswer skips a single Answer Resource. +// +// It does not perform a complete validation of the resource header, which means +// it may return a nil error when the [AnswerHeader] would actually return an error. +func (p *Parser) SkipAnswer() error { + return p.skipResource(sectionAnswers) +} + +// SkipAllAnswers skips all Answer Resources. +func (p *Parser) SkipAllAnswers() error { + for { + if err := p.SkipAnswer(); err == ErrSectionDone { + return nil + } else if err != nil { + return err + } + } +} + +// AuthorityHeader parses a single Authority ResourceHeader. +func (p *Parser) AuthorityHeader() (ResourceHeader, error) { + return p.resourceHeader(sectionAuthorities) +} + +// Authority parses a single Authority Resource. +func (p *Parser) Authority() (Resource, error) { + return p.resource(sectionAuthorities) +} + +// AllAuthorities parses all Authority Resources. +func (p *Parser) AllAuthorities() ([]Resource, error) { + // Authorities contains SOA in case of NXDOMAIN and friends, + // otherwise it is empty. + // + // Pre-allocate up to a certain limit, since p.header is + // untrusted data. + n := int(p.header.authorities) + if n > 10 { + n = 10 + } + as := make([]Resource, 0, n) + for { + a, err := p.Authority() + if err == ErrSectionDone { + return as, nil + } + if err != nil { + return nil, err + } + as = append(as, a) + } +} + +// SkipAuthority skips a single Authority Resource. +// +// It does not perform a complete validation of the resource header, which means +// it may return a nil error when the [AuthorityHeader] would actually return an error. +func (p *Parser) SkipAuthority() error { + return p.skipResource(sectionAuthorities) +} + +// SkipAllAuthorities skips all Authority Resources. +func (p *Parser) SkipAllAuthorities() error { + for { + if err := p.SkipAuthority(); err == ErrSectionDone { + return nil + } else if err != nil { + return err + } + } +} + +// AdditionalHeader parses a single Additional ResourceHeader. +func (p *Parser) AdditionalHeader() (ResourceHeader, error) { + return p.resourceHeader(sectionAdditionals) +} + +// Additional parses a single Additional Resource. +func (p *Parser) Additional() (Resource, error) { + return p.resource(sectionAdditionals) +} + +// AllAdditionals parses all Additional Resources. +func (p *Parser) AllAdditionals() ([]Resource, error) { + // Additionals usually contain OPT, and sometimes A/AAAA + // glue records. + // + // Pre-allocate up to a certain limit, since p.header is + // untrusted data. + n := int(p.header.additionals) + if n > 10 { + n = 10 + } + as := make([]Resource, 0, n) + for { + a, err := p.Additional() + if err == ErrSectionDone { + return as, nil + } + if err != nil { + return nil, err + } + as = append(as, a) + } +} + +// SkipAdditional skips a single Additional Resource. +// +// It does not perform a complete validation of the resource header, which means +// it may return a nil error when the [AdditionalHeader] would actually return an error. +func (p *Parser) SkipAdditional() error { + return p.skipResource(sectionAdditionals) +} + +// SkipAllAdditionals skips all Additional Resources. +func (p *Parser) SkipAllAdditionals() error { + for { + if err := p.SkipAdditional(); err == ErrSectionDone { + return nil + } else if err != nil { + return err + } + } +} + +// CNAMEResource parses a single CNAMEResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) CNAMEResource() (CNAMEResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypeCNAME { + return CNAMEResource{}, ErrNotStarted + } + r, err := unpackCNAMEResource(p.msg, p.off) + if err != nil { + return CNAMEResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// MXResource parses a single MXResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) MXResource() (MXResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypeMX { + return MXResource{}, ErrNotStarted + } + r, err := unpackMXResource(p.msg, p.off) + if err != nil { + return MXResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// NSResource parses a single NSResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) NSResource() (NSResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypeNS { + return NSResource{}, ErrNotStarted + } + r, err := unpackNSResource(p.msg, p.off) + if err != nil { + return NSResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// PTRResource parses a single PTRResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) PTRResource() (PTRResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypePTR { + return PTRResource{}, ErrNotStarted + } + r, err := unpackPTRResource(p.msg, p.off) + if err != nil { + return PTRResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// SOAResource parses a single SOAResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) SOAResource() (SOAResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypeSOA { + return SOAResource{}, ErrNotStarted + } + r, err := unpackSOAResource(p.msg, p.off) + if err != nil { + return SOAResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// TXTResource parses a single TXTResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) TXTResource() (TXTResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypeTXT { + return TXTResource{}, ErrNotStarted + } + r, err := unpackTXTResource(p.msg, p.off, p.resHeaderLength) + if err != nil { + return TXTResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// SRVResource parses a single SRVResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) SRVResource() (SRVResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypeSRV { + return SRVResource{}, ErrNotStarted + } + r, err := unpackSRVResource(p.msg, p.off) + if err != nil { + return SRVResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// AResource parses a single AResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) AResource() (AResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypeA { + return AResource{}, ErrNotStarted + } + r, err := unpackAResource(p.msg, p.off) + if err != nil { + return AResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// AAAAResource parses a single AAAAResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) AAAAResource() (AAAAResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypeAAAA { + return AAAAResource{}, ErrNotStarted + } + r, err := unpackAAAAResource(p.msg, p.off) + if err != nil { + return AAAAResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// OPTResource parses a single OPTResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) OPTResource() (OPTResource, error) { + if !p.resHeaderValid || p.resHeaderType != TypeOPT { + return OPTResource{}, ErrNotStarted + } + r, err := unpackOPTResource(p.msg, p.off, p.resHeaderLength) + if err != nil { + return OPTResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// UnknownResource parses a single UnknownResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) UnknownResource() (UnknownResource, error) { + if !p.resHeaderValid { + return UnknownResource{}, ErrNotStarted + } + r, err := unpackUnknownResource(p.resHeaderType, p.msg, p.off, p.resHeaderLength) + if err != nil { + return UnknownResource{}, err + } + p.off += int(p.resHeaderLength) + p.resHeaderValid = false + p.index++ + return r, nil +} + +// Unpack parses a full Message. +func (m *Message) Unpack(msg []byte) error { + var p Parser + var err error + if m.Header, err = p.Start(msg); err != nil { + return err + } + if m.Questions, err = p.AllQuestions(); err != nil { + return err + } + if m.Answers, err = p.AllAnswers(); err != nil { + return err + } + if m.Authorities, err = p.AllAuthorities(); err != nil { + return err + } + if m.Additionals, err = p.AllAdditionals(); err != nil { + return err + } + return nil +} + +// Pack packs a full Message. +func (m *Message) Pack() ([]byte, error) { + return m.AppendPack(make([]byte, 0, packStartingCap)) +} + +// AppendPack is like Pack but appends the full Message to b and returns the +// extended buffer. +func (m *Message) AppendPack(b []byte) ([]byte, error) { + // Validate the lengths. It is very unlikely that anyone will try to + // pack more than 65535 of any particular type, but it is possible and + // we should fail gracefully. + if len(m.Questions) > int(^uint16(0)) { + return nil, errTooManyQuestions + } + if len(m.Answers) > int(^uint16(0)) { + return nil, errTooManyAnswers + } + if len(m.Authorities) > int(^uint16(0)) { + return nil, errTooManyAuthorities + } + if len(m.Additionals) > int(^uint16(0)) { + return nil, errTooManyAdditionals + } + + var h header + h.id, h.bits = m.Header.pack() + + h.questions = uint16(len(m.Questions)) + h.answers = uint16(len(m.Answers)) + h.authorities = uint16(len(m.Authorities)) + h.additionals = uint16(len(m.Additionals)) + + compressionOff := len(b) + msg := h.pack(b) + + // RFC 1035 allows (but does not require) compression for packing. RFC + // 1035 requires unpacking implementations to support compression, so + // unconditionally enabling it is fine. + // + // DNS lookups are typically done over UDP, and RFC 1035 states that UDP + // DNS messages can be a maximum of 512 bytes long. Without compression, + // many DNS response messages are over this limit, so enabling + // compression will help ensure compliance. + compression := map[string]uint16{} + + for i := range m.Questions { + var err error + if msg, err = m.Questions[i].pack(msg, compression, compressionOff); err != nil { + return nil, &nestedError{"packing Question", err} + } + } + for i := range m.Answers { + var err error + if msg, err = m.Answers[i].pack(msg, compression, compressionOff); err != nil { + return nil, &nestedError{"packing Answer", err} + } + } + for i := range m.Authorities { + var err error + if msg, err = m.Authorities[i].pack(msg, compression, compressionOff); err != nil { + return nil, &nestedError{"packing Authority", err} + } + } + for i := range m.Additionals { + var err error + if msg, err = m.Additionals[i].pack(msg, compression, compressionOff); err != nil { + return nil, &nestedError{"packing Additional", err} + } + } + + return msg, nil +} + +// GoString implements fmt.GoStringer.GoString. +func (m *Message) GoString() string { + s := "dnsmessage.Message{Header: " + m.Header.GoString() + ", " + + "Questions: []dnsmessage.Question{" + if len(m.Questions) > 0 { + s += m.Questions[0].GoString() + for _, q := range m.Questions[1:] { + s += ", " + q.GoString() + } + } + s += "}, Answers: []dnsmessage.Resource{" + if len(m.Answers) > 0 { + s += m.Answers[0].GoString() + for _, a := range m.Answers[1:] { + s += ", " + a.GoString() + } + } + s += "}, Authorities: []dnsmessage.Resource{" + if len(m.Authorities) > 0 { + s += m.Authorities[0].GoString() + for _, a := range m.Authorities[1:] { + s += ", " + a.GoString() + } + } + s += "}, Additionals: []dnsmessage.Resource{" + if len(m.Additionals) > 0 { + s += m.Additionals[0].GoString() + for _, a := range m.Additionals[1:] { + s += ", " + a.GoString() + } + } + return s + "}}" +} + +// A Builder allows incrementally packing a DNS message. +// +// Example usage: +// +// buf := make([]byte, 2, 514) +// b := NewBuilder(buf, Header{...}) +// b.EnableCompression() +// // Optionally start a section and add things to that section. +// // Repeat adding sections as necessary. +// buf, err := b.Finish() +// // If err is nil, buf[2:] will contain the built bytes. +type Builder struct { + // msg is the storage for the message being built. + msg []byte + + // section keeps track of the current section being built. + section section + + // header keeps track of what should go in the header when Finish is + // called. + header header + + // start is the starting index of the bytes allocated in msg for header. + start int + + // compression is a mapping from name suffixes to their starting index + // in msg. + compression map[string]uint16 +} + +// NewBuilder creates a new builder with compression disabled. +// +// Note: Most users will want to immediately enable compression with the +// EnableCompression method. See that method's comment for why you may or may +// not want to enable compression. +// +// The DNS message is appended to the provided initial buffer buf (which may be +// nil) as it is built. The final message is returned by the (*Builder).Finish +// method, which includes buf[:len(buf)] and may return the same underlying +// array if there was sufficient capacity in the slice. +func NewBuilder(buf []byte, h Header) Builder { + if buf == nil { + buf = make([]byte, 0, packStartingCap) + } + b := Builder{msg: buf, start: len(buf)} + b.header.id, b.header.bits = h.pack() + var hb [headerLen]byte + b.msg = append(b.msg, hb[:]...) + b.section = sectionHeader + return b +} + +// EnableCompression enables compression in the Builder. +// +// Leaving compression disabled avoids compression related allocations, but can +// result in larger message sizes. Be careful with this mode as it can cause +// messages to exceed the UDP size limit. +// +// According to RFC 1035, section 4.1.4, the use of compression is optional, but +// all implementations must accept both compressed and uncompressed DNS +// messages. +// +// Compression should be enabled before any sections are added for best results. +func (b *Builder) EnableCompression() { + b.compression = map[string]uint16{} +} + +func (b *Builder) startCheck(s section) error { + if b.section <= sectionNotStarted { + return ErrNotStarted + } + if b.section > s { + return ErrSectionDone + } + return nil +} + +// StartQuestions prepares the builder for packing Questions. +func (b *Builder) StartQuestions() error { + if err := b.startCheck(sectionQuestions); err != nil { + return err + } + b.section = sectionQuestions + return nil +} + +// StartAnswers prepares the builder for packing Answers. +func (b *Builder) StartAnswers() error { + if err := b.startCheck(sectionAnswers); err != nil { + return err + } + b.section = sectionAnswers + return nil +} + +// StartAuthorities prepares the builder for packing Authorities. +func (b *Builder) StartAuthorities() error { + if err := b.startCheck(sectionAuthorities); err != nil { + return err + } + b.section = sectionAuthorities + return nil +} + +// StartAdditionals prepares the builder for packing Additionals. +func (b *Builder) StartAdditionals() error { + if err := b.startCheck(sectionAdditionals); err != nil { + return err + } + b.section = sectionAdditionals + return nil +} + +func (b *Builder) incrementSectionCount() error { + var count *uint16 + var err error + switch b.section { + case sectionQuestions: + count = &b.header.questions + err = errTooManyQuestions + case sectionAnswers: + count = &b.header.answers + err = errTooManyAnswers + case sectionAuthorities: + count = &b.header.authorities + err = errTooManyAuthorities + case sectionAdditionals: + count = &b.header.additionals + err = errTooManyAdditionals + } + if *count == ^uint16(0) { + return err + } + *count++ + return nil +} + +// Question adds a single Question. +func (b *Builder) Question(q Question) error { + if b.section < sectionQuestions { + return ErrNotStarted + } + if b.section > sectionQuestions { + return ErrSectionDone + } + msg, err := q.pack(b.msg, b.compression, b.start) + if err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +func (b *Builder) checkResourceSection() error { + if b.section < sectionAnswers { + return ErrNotStarted + } + if b.section > sectionAdditionals { + return ErrSectionDone + } + return nil +} + +// CNAMEResource adds a single CNAMEResource. +func (b *Builder) CNAMEResource(h ResourceHeader, r CNAMEResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"CNAMEResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// MXResource adds a single MXResource. +func (b *Builder) MXResource(h ResourceHeader, r MXResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"MXResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// NSResource adds a single NSResource. +func (b *Builder) NSResource(h ResourceHeader, r NSResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"NSResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// PTRResource adds a single PTRResource. +func (b *Builder) PTRResource(h ResourceHeader, r PTRResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"PTRResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// SOAResource adds a single SOAResource. +func (b *Builder) SOAResource(h ResourceHeader, r SOAResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"SOAResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// TXTResource adds a single TXTResource. +func (b *Builder) TXTResource(h ResourceHeader, r TXTResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"TXTResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// SRVResource adds a single SRVResource. +func (b *Builder) SRVResource(h ResourceHeader, r SRVResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"SRVResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// AResource adds a single AResource. +func (b *Builder) AResource(h ResourceHeader, r AResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"AResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// AAAAResource adds a single AAAAResource. +func (b *Builder) AAAAResource(h ResourceHeader, r AAAAResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"AAAAResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// OPTResource adds a single OPTResource. +func (b *Builder) OPTResource(h ResourceHeader, r OPTResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"OPTResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// UnknownResource adds a single UnknownResource. +func (b *Builder) UnknownResource(h ResourceHeader, r UnknownResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"UnknownResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// Finish ends message building and generates a binary message. +func (b *Builder) Finish() ([]byte, error) { + if b.section < sectionHeader { + return nil, ErrNotStarted + } + b.section = sectionDone + // Space for the header was allocated in NewBuilder. + b.header.pack(b.msg[b.start:b.start]) + return b.msg, nil +} + +// A ResourceHeader is the header of a DNS resource record. There are +// many types of DNS resource records, but they all share the same header. +type ResourceHeader struct { + // Name is the domain name for which this resource record pertains. + Name Name + + // Type is the type of DNS resource record. + // + // This field will be set automatically during packing. + Type Type + + // Class is the class of network to which this DNS resource record + // pertains. + Class Class + + // TTL is the length of time (measured in seconds) which this resource + // record is valid for (time to live). All Resources in a set should + // have the same TTL (RFC 2181 Section 5.2). + TTL uint32 + + // Length is the length of data in the resource record after the header. + // + // This field will be set automatically during packing. + Length uint16 +} + +// GoString implements fmt.GoStringer.GoString. +func (h *ResourceHeader) GoString() string { + return "dnsmessage.ResourceHeader{" + + "Name: " + h.Name.GoString() + ", " + + "Type: " + h.Type.GoString() + ", " + + "Class: " + h.Class.GoString() + ", " + + "TTL: " + printUint32(h.TTL) + ", " + + "Length: " + printUint16(h.Length) + "}" +} + +// pack appends the wire format of the ResourceHeader to oldMsg. +// +// lenOff is the offset in msg where the Length field was packed. +func (h *ResourceHeader) pack(oldMsg []byte, compression map[string]uint16, compressionOff int) (msg []byte, lenOff int, err error) { + msg = oldMsg + if msg, err = h.Name.pack(msg, compression, compressionOff); err != nil { + return oldMsg, 0, &nestedError{"Name", err} + } + msg = packType(msg, h.Type) + msg = packClass(msg, h.Class) + msg = packUint32(msg, h.TTL) + lenOff = len(msg) + msg = packUint16(msg, h.Length) + return msg, lenOff, nil +} + +func (h *ResourceHeader) unpack(msg []byte, off int) (int, error) { + newOff := off + var err error + if newOff, err = h.Name.unpack(msg, newOff); err != nil { + return off, &nestedError{"Name", err} + } + if h.Type, newOff, err = unpackType(msg, newOff); err != nil { + return off, &nestedError{"Type", err} + } + if h.Class, newOff, err = unpackClass(msg, newOff); err != nil { + return off, &nestedError{"Class", err} + } + if h.TTL, newOff, err = unpackUint32(msg, newOff); err != nil { + return off, &nestedError{"TTL", err} + } + if h.Length, newOff, err = unpackUint16(msg, newOff); err != nil { + return off, &nestedError{"Length", err} + } + return newOff, nil +} + +// fixLen updates a packed ResourceHeader to include the length of the +// ResourceBody. +// +// lenOff is the offset of the ResourceHeader.Length field in msg. +// +// preLen is the length that msg was before the ResourceBody was packed. +func (h *ResourceHeader) fixLen(msg []byte, lenOff int, preLen int) error { + conLen := len(msg) - preLen + if conLen > int(^uint16(0)) { + return errResTooLong + } + + // Fill in the length now that we know how long the content is. + packUint16(msg[lenOff:lenOff], uint16(conLen)) + h.Length = uint16(conLen) + + return nil +} + +// EDNS(0) wire constants. +const ( + edns0Version = 0 + + edns0DNSSECOK = 0x00008000 + ednsVersionMask = 0x00ff0000 + edns0DNSSECOKMask = 0x00ff8000 +) + +// SetEDNS0 configures h for EDNS(0). +// +// The provided extRCode must be an extended RCode. +func (h *ResourceHeader) SetEDNS0(udpPayloadLen int, extRCode RCode, dnssecOK bool) error { + h.Name = Name{Data: [255]byte{'.'}, Length: 1} // RFC 6891 section 6.1.2 + h.Type = TypeOPT + h.Class = Class(udpPayloadLen) + h.TTL = uint32(extRCode) >> 4 << 24 + if dnssecOK { + h.TTL |= edns0DNSSECOK + } + return nil +} + +// DNSSECAllowed reports whether the DNSSEC OK bit is set. +func (h *ResourceHeader) DNSSECAllowed() bool { + return h.TTL&edns0DNSSECOKMask == edns0DNSSECOK // RFC 6891 section 6.1.3 +} + +// ExtendedRCode returns an extended RCode. +// +// The provided rcode must be the RCode in DNS message header. +func (h *ResourceHeader) ExtendedRCode(rcode RCode) RCode { + if h.TTL&ednsVersionMask == edns0Version { // RFC 6891 section 6.1.3 + return RCode(h.TTL>>24<<4) | rcode + } + return rcode +} + +func skipResource(msg []byte, off int) (int, error) { + newOff, err := skipName(msg, off) + if err != nil { + return off, &nestedError{"Name", err} + } + if newOff, err = skipType(msg, newOff); err != nil { + return off, &nestedError{"Type", err} + } + if newOff, err = skipClass(msg, newOff); err != nil { + return off, &nestedError{"Class", err} + } + if newOff, err = skipUint32(msg, newOff); err != nil { + return off, &nestedError{"TTL", err} + } + length, newOff, err := unpackUint16(msg, newOff) + if err != nil { + return off, &nestedError{"Length", err} + } + if newOff += int(length); newOff > len(msg) { + return off, errResourceLen + } + return newOff, nil +} + +// packUint16 appends the wire format of field to msg. +func packUint16(msg []byte, field uint16) []byte { + return append(msg, byte(field>>8), byte(field)) +} + +func unpackUint16(msg []byte, off int) (uint16, int, error) { + if off+uint16Len > len(msg) { + return 0, off, errBaseLen + } + return uint16(msg[off])<<8 | uint16(msg[off+1]), off + uint16Len, nil +} + +func skipUint16(msg []byte, off int) (int, error) { + if off+uint16Len > len(msg) { + return off, errBaseLen + } + return off + uint16Len, nil +} + +// packType appends the wire format of field to msg. +func packType(msg []byte, field Type) []byte { + return packUint16(msg, uint16(field)) +} + +func unpackType(msg []byte, off int) (Type, int, error) { + t, o, err := unpackUint16(msg, off) + return Type(t), o, err +} + +func skipType(msg []byte, off int) (int, error) { + return skipUint16(msg, off) +} + +// packClass appends the wire format of field to msg. +func packClass(msg []byte, field Class) []byte { + return packUint16(msg, uint16(field)) +} + +func unpackClass(msg []byte, off int) (Class, int, error) { + c, o, err := unpackUint16(msg, off) + return Class(c), o, err +} + +func skipClass(msg []byte, off int) (int, error) { + return skipUint16(msg, off) +} + +// packUint32 appends the wire format of field to msg. +func packUint32(msg []byte, field uint32) []byte { + return append( + msg, + byte(field>>24), + byte(field>>16), + byte(field>>8), + byte(field), + ) +} + +func unpackUint32(msg []byte, off int) (uint32, int, error) { + if off+uint32Len > len(msg) { + return 0, off, errBaseLen + } + v := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]) + return v, off + uint32Len, nil +} + +func skipUint32(msg []byte, off int) (int, error) { + if off+uint32Len > len(msg) { + return off, errBaseLen + } + return off + uint32Len, nil +} + +// packText appends the wire format of field to msg. +func packText(msg []byte, field string) ([]byte, error) { + l := len(field) + if l > 255 { + return nil, errStringTooLong + } + msg = append(msg, byte(l)) + msg = append(msg, field...) + + return msg, nil +} + +func unpackText(msg []byte, off int) (string, int, error) { + if off >= len(msg) { + return "", off, errBaseLen + } + beginOff := off + 1 + endOff := beginOff + int(msg[off]) + if endOff > len(msg) { + return "", off, errCalcLen + } + return string(msg[beginOff:endOff]), endOff, nil +} + +// packBytes appends the wire format of field to msg. +func packBytes(msg []byte, field []byte) []byte { + return append(msg, field...) +} + +func unpackBytes(msg []byte, off int, field []byte) (int, error) { + newOff := off + len(field) + if newOff > len(msg) { + return off, errBaseLen + } + copy(field, msg[off:newOff]) + return newOff, nil +} + +const nonEncodedNameMax = 254 + +// A Name is a non-encoded and non-escaped domain name. It is used instead of strings to avoid +// allocations. +type Name struct { + Data [255]byte + Length uint8 +} + +// NewName creates a new Name from a string. +func NewName(name string) (Name, error) { + n := Name{Length: uint8(len(name))} + if len(name) > len(n.Data) { + return Name{}, errCalcLen + } + copy(n.Data[:], name) + return n, nil +} + +// MustNewName creates a new Name from a string and panics on error. +func MustNewName(name string) Name { + n, err := NewName(name) + if err != nil { + panic("creating name: " + err.Error()) + } + return n +} + +// String implements fmt.Stringer.String. +// +// Note: characters inside the labels are not escaped in any way. +func (n Name) String() string { + return string(n.Data[:n.Length]) +} + +// GoString implements fmt.GoStringer.GoString. +func (n *Name) GoString() string { + return `dnsmessage.MustNewName("` + printString(n.Data[:n.Length]) + `")` +} + +// pack appends the wire format of the Name to msg. +// +// Domain names are a sequence of counted strings split at the dots. They end +// with a zero-length string. Compression can be used to reuse domain suffixes. +// +// The compression map will be updated with new domain suffixes. If compression +// is nil, compression will not be used. +func (n *Name) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + oldMsg := msg + + if n.Length > nonEncodedNameMax { + return nil, errNameTooLong + } + + // Add a trailing dot to canonicalize name. + if n.Length == 0 || n.Data[n.Length-1] != '.' { + return oldMsg, errNonCanonicalName + } + + // Allow root domain. + if n.Data[0] == '.' && n.Length == 1 { + return append(msg, 0), nil + } + + var nameAsStr string + + // Emit sequence of counted strings, chopping at dots. + for i, begin := 0, 0; i < int(n.Length); i++ { + // Check for the end of the segment. + if n.Data[i] == '.' { + // The two most significant bits have special meaning. + // It isn't allowed for segments to be long enough to + // need them. + if i-begin >= 1<<6 { + return oldMsg, errSegTooLong + } + + // Segments must have a non-zero length. + if i-begin == 0 { + return oldMsg, errZeroSegLen + } + + msg = append(msg, byte(i-begin)) + + for j := begin; j < i; j++ { + msg = append(msg, n.Data[j]) + } + + begin = i + 1 + continue + } + + // We can only compress domain suffixes starting with a new + // segment. A pointer is two bytes with the two most significant + // bits set to 1 to indicate that it is a pointer. + if (i == 0 || n.Data[i-1] == '.') && compression != nil { + if ptr, ok := compression[string(n.Data[i:n.Length])]; ok { + // Hit. Emit a pointer instead of the rest of + // the domain. + return append(msg, byte(ptr>>8|0xC0), byte(ptr)), nil + } + + // Miss. Add the suffix to the compression table if the + // offset can be stored in the available 14 bits. + newPtr := len(msg) - compressionOff + if newPtr <= int(^uint16(0)>>2) { + if nameAsStr == "" { + // allocate n.Data on the heap once, to avoid allocating it + // multiple times (for next labels). + nameAsStr = string(n.Data[:n.Length]) + } + compression[nameAsStr[i:]] = uint16(newPtr) + } + } + } + return append(msg, 0), nil +} + +// unpack unpacks a domain name. +func (n *Name) unpack(msg []byte, off int) (int, error) { + // currOff is the current working offset. + currOff := off + + // newOff is the offset where the next record will start. Pointers lead + // to data that belongs to other names and thus doesn't count towards to + // the usage of this name. + newOff := off + + // ptr is the number of pointers followed. + var ptr int + + // Name is a slice representation of the name data. + name := n.Data[:0] + +Loop: + for { + if currOff >= len(msg) { + return off, errBaseLen + } + c := int(msg[currOff]) + currOff++ + switch c & 0xC0 { + case 0x00: // String segment + if c == 0x00 { + // A zero length signals the end of the name. + break Loop + } + endOff := currOff + c + if endOff > len(msg) { + return off, errCalcLen + } + + // Reject names containing dots. + // See issue golang/go#56246 + for _, v := range msg[currOff:endOff] { + if v == '.' { + return off, errInvalidName + } + } + + name = append(name, msg[currOff:endOff]...) + name = append(name, '.') + currOff = endOff + case 0xC0: // Pointer + if currOff >= len(msg) { + return off, errInvalidPtr + } + c1 := msg[currOff] + currOff++ + if ptr == 0 { + newOff = currOff + } + // Don't follow too many pointers, maybe there's a loop. + if ptr++; ptr > 10 { + return off, errTooManyPtr + } + currOff = (c^0xC0)<<8 | int(c1) + default: + // Prefixes 0x80 and 0x40 are reserved. + return off, errReserved + } + } + if len(name) == 0 { + name = append(name, '.') + } + if len(name) > nonEncodedNameMax { + return off, errNameTooLong + } + n.Length = uint8(len(name)) + if ptr == 0 { + newOff = currOff + } + return newOff, nil +} + +func skipName(msg []byte, off int) (int, error) { + // newOff is the offset where the next record will start. Pointers lead + // to data that belongs to other names and thus doesn't count towards to + // the usage of this name. + newOff := off + +Loop: + for { + if newOff >= len(msg) { + return off, errBaseLen + } + c := int(msg[newOff]) + newOff++ + switch c & 0xC0 { + case 0x00: + if c == 0x00 { + // A zero length signals the end of the name. + break Loop + } + // literal string + newOff += c + if newOff > len(msg) { + return off, errCalcLen + } + case 0xC0: + // Pointer to somewhere else in msg. + + // Pointers are two bytes. + newOff++ + + // Don't follow the pointer as the data here has ended. + break Loop + default: + // Prefixes 0x80 and 0x40 are reserved. + return off, errReserved + } + } + + return newOff, nil +} + +// A Question is a DNS query. +type Question struct { + Name Name + Type Type + Class Class +} + +// pack appends the wire format of the Question to msg. +func (q *Question) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + msg, err := q.Name.pack(msg, compression, compressionOff) + if err != nil { + return msg, &nestedError{"Name", err} + } + msg = packType(msg, q.Type) + return packClass(msg, q.Class), nil +} + +// GoString implements fmt.GoStringer.GoString. +func (q *Question) GoString() string { + return "dnsmessage.Question{" + + "Name: " + q.Name.GoString() + ", " + + "Type: " + q.Type.GoString() + ", " + + "Class: " + q.Class.GoString() + "}" +} + +func unpackResourceBody(msg []byte, off int, hdr ResourceHeader) (ResourceBody, int, error) { + var ( + r ResourceBody + err error + name string + ) + switch hdr.Type { + case TypeA: + var rb AResource + rb, err = unpackAResource(msg, off) + r = &rb + name = "A" + case TypeNS: + var rb NSResource + rb, err = unpackNSResource(msg, off) + r = &rb + name = "NS" + case TypeCNAME: + var rb CNAMEResource + rb, err = unpackCNAMEResource(msg, off) + r = &rb + name = "CNAME" + case TypeSOA: + var rb SOAResource + rb, err = unpackSOAResource(msg, off) + r = &rb + name = "SOA" + case TypePTR: + var rb PTRResource + rb, err = unpackPTRResource(msg, off) + r = &rb + name = "PTR" + case TypeMX: + var rb MXResource + rb, err = unpackMXResource(msg, off) + r = &rb + name = "MX" + case TypeTXT: + var rb TXTResource + rb, err = unpackTXTResource(msg, off, hdr.Length) + r = &rb + name = "TXT" + case TypeAAAA: + var rb AAAAResource + rb, err = unpackAAAAResource(msg, off) + r = &rb + name = "AAAA" + case TypeSRV: + var rb SRVResource + rb, err = unpackSRVResource(msg, off) + r = &rb + name = "SRV" + case TypeOPT: + var rb OPTResource + rb, err = unpackOPTResource(msg, off, hdr.Length) + r = &rb + name = "OPT" + default: + var rb UnknownResource + rb, err = unpackUnknownResource(hdr.Type, msg, off, hdr.Length) + r = &rb + name = "Unknown" + } + if err != nil { + return nil, off, &nestedError{name + " record", err} + } + return r, off + int(hdr.Length), nil +} + +// A CNAMEResource is a CNAME Resource record. +type CNAMEResource struct { + CNAME Name +} + +func (r *CNAMEResource) realType() Type { + return TypeCNAME +} + +// pack appends the wire format of the CNAMEResource to msg. +func (r *CNAMEResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + return r.CNAME.pack(msg, compression, compressionOff) +} + +// GoString implements fmt.GoStringer.GoString. +func (r *CNAMEResource) GoString() string { + return "dnsmessage.CNAMEResource{CNAME: " + r.CNAME.GoString() + "}" +} + +func unpackCNAMEResource(msg []byte, off int) (CNAMEResource, error) { + var cname Name + if _, err := cname.unpack(msg, off); err != nil { + return CNAMEResource{}, err + } + return CNAMEResource{cname}, nil +} + +// An MXResource is an MX Resource record. +type MXResource struct { + Pref uint16 + MX Name +} + +func (r *MXResource) realType() Type { + return TypeMX +} + +// pack appends the wire format of the MXResource to msg. +func (r *MXResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + oldMsg := msg + msg = packUint16(msg, r.Pref) + msg, err := r.MX.pack(msg, compression, compressionOff) + if err != nil { + return oldMsg, &nestedError{"MXResource.MX", err} + } + return msg, nil +} + +// GoString implements fmt.GoStringer.GoString. +func (r *MXResource) GoString() string { + return "dnsmessage.MXResource{" + + "Pref: " + printUint16(r.Pref) + ", " + + "MX: " + r.MX.GoString() + "}" +} + +func unpackMXResource(msg []byte, off int) (MXResource, error) { + pref, off, err := unpackUint16(msg, off) + if err != nil { + return MXResource{}, &nestedError{"Pref", err} + } + var mx Name + if _, err := mx.unpack(msg, off); err != nil { + return MXResource{}, &nestedError{"MX", err} + } + return MXResource{pref, mx}, nil +} + +// An NSResource is an NS Resource record. +type NSResource struct { + NS Name +} + +func (r *NSResource) realType() Type { + return TypeNS +} + +// pack appends the wire format of the NSResource to msg. +func (r *NSResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + return r.NS.pack(msg, compression, compressionOff) +} + +// GoString implements fmt.GoStringer.GoString. +func (r *NSResource) GoString() string { + return "dnsmessage.NSResource{NS: " + r.NS.GoString() + "}" +} + +func unpackNSResource(msg []byte, off int) (NSResource, error) { + var ns Name + if _, err := ns.unpack(msg, off); err != nil { + return NSResource{}, err + } + return NSResource{ns}, nil +} + +// A PTRResource is a PTR Resource record. +type PTRResource struct { + PTR Name +} + +func (r *PTRResource) realType() Type { + return TypePTR +} + +// pack appends the wire format of the PTRResource to msg. +func (r *PTRResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + return r.PTR.pack(msg, compression, compressionOff) +} + +// GoString implements fmt.GoStringer.GoString. +func (r *PTRResource) GoString() string { + return "dnsmessage.PTRResource{PTR: " + r.PTR.GoString() + "}" +} + +func unpackPTRResource(msg []byte, off int) (PTRResource, error) { + var ptr Name + if _, err := ptr.unpack(msg, off); err != nil { + return PTRResource{}, err + } + return PTRResource{ptr}, nil +} + +// An SOAResource is an SOA Resource record. +type SOAResource struct { + NS Name + MBox Name + Serial uint32 + Refresh uint32 + Retry uint32 + Expire uint32 + + // MinTTL the is the default TTL of Resources records which did not + // contain a TTL value and the TTL of negative responses. (RFC 2308 + // Section 4) + MinTTL uint32 +} + +func (r *SOAResource) realType() Type { + return TypeSOA +} + +// pack appends the wire format of the SOAResource to msg. +func (r *SOAResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + oldMsg := msg + msg, err := r.NS.pack(msg, compression, compressionOff) + if err != nil { + return oldMsg, &nestedError{"SOAResource.NS", err} + } + msg, err = r.MBox.pack(msg, compression, compressionOff) + if err != nil { + return oldMsg, &nestedError{"SOAResource.MBox", err} + } + msg = packUint32(msg, r.Serial) + msg = packUint32(msg, r.Refresh) + msg = packUint32(msg, r.Retry) + msg = packUint32(msg, r.Expire) + return packUint32(msg, r.MinTTL), nil +} + +// GoString implements fmt.GoStringer.GoString. +func (r *SOAResource) GoString() string { + return "dnsmessage.SOAResource{" + + "NS: " + r.NS.GoString() + ", " + + "MBox: " + r.MBox.GoString() + ", " + + "Serial: " + printUint32(r.Serial) + ", " + + "Refresh: " + printUint32(r.Refresh) + ", " + + "Retry: " + printUint32(r.Retry) + ", " + + "Expire: " + printUint32(r.Expire) + ", " + + "MinTTL: " + printUint32(r.MinTTL) + "}" +} + +func unpackSOAResource(msg []byte, off int) (SOAResource, error) { + var ns Name + off, err := ns.unpack(msg, off) + if err != nil { + return SOAResource{}, &nestedError{"NS", err} + } + var mbox Name + if off, err = mbox.unpack(msg, off); err != nil { + return SOAResource{}, &nestedError{"MBox", err} + } + serial, off, err := unpackUint32(msg, off) + if err != nil { + return SOAResource{}, &nestedError{"Serial", err} + } + refresh, off, err := unpackUint32(msg, off) + if err != nil { + return SOAResource{}, &nestedError{"Refresh", err} + } + retry, off, err := unpackUint32(msg, off) + if err != nil { + return SOAResource{}, &nestedError{"Retry", err} + } + expire, off, err := unpackUint32(msg, off) + if err != nil { + return SOAResource{}, &nestedError{"Expire", err} + } + minTTL, _, err := unpackUint32(msg, off) + if err != nil { + return SOAResource{}, &nestedError{"MinTTL", err} + } + return SOAResource{ns, mbox, serial, refresh, retry, expire, minTTL}, nil +} + +// A TXTResource is a TXT Resource record. +type TXTResource struct { + TXT []string +} + +func (r *TXTResource) realType() Type { + return TypeTXT +} + +// pack appends the wire format of the TXTResource to msg. +func (r *TXTResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + oldMsg := msg + for _, s := range r.TXT { + var err error + msg, err = packText(msg, s) + if err != nil { + return oldMsg, err + } + } + return msg, nil +} + +// GoString implements fmt.GoStringer.GoString. +func (r *TXTResource) GoString() string { + s := "dnsmessage.TXTResource{TXT: []string{" + if len(r.TXT) == 0 { + return s + "}}" + } + s += `"` + printString([]byte(r.TXT[0])) + for _, t := range r.TXT[1:] { + s += `", "` + printString([]byte(t)) + } + return s + `"}}` +} + +func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error) { + txts := make([]string, 0, 1) + for n := uint16(0); n < length; { + var t string + var err error + if t, off, err = unpackText(msg, off); err != nil { + return TXTResource{}, &nestedError{"text", err} + } + // Check if we got too many bytes. + if length-n < uint16(len(t))+1 { + return TXTResource{}, errCalcLen + } + n += uint16(len(t)) + 1 + txts = append(txts, t) + } + return TXTResource{txts}, nil +} + +// An SRVResource is an SRV Resource record. +type SRVResource struct { + Priority uint16 + Weight uint16 + Port uint16 + Target Name // Not compressed as per RFC 2782. +} + +func (r *SRVResource) realType() Type { + return TypeSRV +} + +// pack appends the wire format of the SRVResource to msg. +func (r *SRVResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + oldMsg := msg + msg = packUint16(msg, r.Priority) + msg = packUint16(msg, r.Weight) + msg = packUint16(msg, r.Port) + msg, err := r.Target.pack(msg, nil, compressionOff) + if err != nil { + return oldMsg, &nestedError{"SRVResource.Target", err} + } + return msg, nil +} + +// GoString implements fmt.GoStringer.GoString. +func (r *SRVResource) GoString() string { + return "dnsmessage.SRVResource{" + + "Priority: " + printUint16(r.Priority) + ", " + + "Weight: " + printUint16(r.Weight) + ", " + + "Port: " + printUint16(r.Port) + ", " + + "Target: " + r.Target.GoString() + "}" +} + +func unpackSRVResource(msg []byte, off int) (SRVResource, error) { + priority, off, err := unpackUint16(msg, off) + if err != nil { + return SRVResource{}, &nestedError{"Priority", err} + } + weight, off, err := unpackUint16(msg, off) + if err != nil { + return SRVResource{}, &nestedError{"Weight", err} + } + port, off, err := unpackUint16(msg, off) + if err != nil { + return SRVResource{}, &nestedError{"Port", err} + } + var target Name + if _, err := target.unpack(msg, off); err != nil { + return SRVResource{}, &nestedError{"Target", err} + } + return SRVResource{priority, weight, port, target}, nil +} + +// An AResource is an A Resource record. +type AResource struct { + A [4]byte +} + +func (r *AResource) realType() Type { + return TypeA +} + +// pack appends the wire format of the AResource to msg. +func (r *AResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + return packBytes(msg, r.A[:]), nil +} + +// GoString implements fmt.GoStringer.GoString. +func (r *AResource) GoString() string { + return "dnsmessage.AResource{" + + "A: [4]byte{" + printByteSlice(r.A[:]) + "}}" +} + +func unpackAResource(msg []byte, off int) (AResource, error) { + var a [4]byte + if _, err := unpackBytes(msg, off, a[:]); err != nil { + return AResource{}, err + } + return AResource{a}, nil +} + +// An AAAAResource is an AAAA Resource record. +type AAAAResource struct { + AAAA [16]byte +} + +func (r *AAAAResource) realType() Type { + return TypeAAAA +} + +// GoString implements fmt.GoStringer.GoString. +func (r *AAAAResource) GoString() string { + return "dnsmessage.AAAAResource{" + + "AAAA: [16]byte{" + printByteSlice(r.AAAA[:]) + "}}" +} + +// pack appends the wire format of the AAAAResource to msg. +func (r *AAAAResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + return packBytes(msg, r.AAAA[:]), nil +} + +func unpackAAAAResource(msg []byte, off int) (AAAAResource, error) { + var aaaa [16]byte + if _, err := unpackBytes(msg, off, aaaa[:]); err != nil { + return AAAAResource{}, err + } + return AAAAResource{aaaa}, nil +} + +// An OPTResource is an OPT pseudo Resource record. +// +// The pseudo resource record is part of the extension mechanisms for DNS +// as defined in RFC 6891. +type OPTResource struct { + Options []Option +} + +// An Option represents a DNS message option within OPTResource. +// +// The message option is part of the extension mechanisms for DNS as +// defined in RFC 6891. +type Option struct { + Code uint16 // option code + Data []byte +} + +// GoString implements fmt.GoStringer.GoString. +func (o *Option) GoString() string { + return "dnsmessage.Option{" + + "Code: " + printUint16(o.Code) + ", " + + "Data: []byte{" + printByteSlice(o.Data) + "}}" +} + +func (r *OPTResource) realType() Type { + return TypeOPT +} + +func (r *OPTResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + for _, opt := range r.Options { + msg = packUint16(msg, opt.Code) + l := uint16(len(opt.Data)) + msg = packUint16(msg, l) + msg = packBytes(msg, opt.Data) + } + return msg, nil +} + +// GoString implements fmt.GoStringer.GoString. +func (r *OPTResource) GoString() string { + s := "dnsmessage.OPTResource{Options: []dnsmessage.Option{" + if len(r.Options) == 0 { + return s + "}}" + } + s += r.Options[0].GoString() + for _, o := range r.Options[1:] { + s += ", " + o.GoString() + } + return s + "}}" +} + +func unpackOPTResource(msg []byte, off int, length uint16) (OPTResource, error) { + var opts []Option + for oldOff := off; off < oldOff+int(length); { + var err error + var o Option + o.Code, off, err = unpackUint16(msg, off) + if err != nil { + return OPTResource{}, &nestedError{"Code", err} + } + var l uint16 + l, off, err = unpackUint16(msg, off) + if err != nil { + return OPTResource{}, &nestedError{"Data", err} + } + o.Data = make([]byte, l) + if copy(o.Data, msg[off:]) != int(l) { + return OPTResource{}, &nestedError{"Data", errCalcLen} + } + off += int(l) + opts = append(opts, o) + } + return OPTResource{opts}, nil +} + +// An UnknownResource is a catch-all container for unknown record types. +type UnknownResource struct { + Type Type + Data []byte +} + +func (r *UnknownResource) realType() Type { + return r.Type +} + +// pack appends the wire format of the UnknownResource to msg. +func (r *UnknownResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) { + return packBytes(msg, r.Data[:]), nil +} + +// GoString implements fmt.GoStringer.GoString. +func (r *UnknownResource) GoString() string { + return "dnsmessage.UnknownResource{" + + "Type: " + r.Type.GoString() + ", " + + "Data: []byte{" + printByteSlice(r.Data) + "}}" +} + +func unpackUnknownResource(recordType Type, msg []byte, off int, length uint16) (UnknownResource, error) { + parsed := UnknownResource{ + Type: recordType, + Data: make([]byte, length), + } + if _, err := unpackBytes(msg, off, parsed.Data); err != nil { + return UnknownResource{}, err + } + return parsed, nil +} diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/guts.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/guts.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/guts.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/guts.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/httplex.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/httplex.go similarity index 97% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/httplex.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/httplex.go index 6e071e852432..9b4de94019b4 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/httplex.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/httplex.go @@ -12,7 +12,7 @@ import ( "golang.org/x/net/idna" ) -var isTokenTable = [127]bool{ +var isTokenTable = [256]bool{ '!': true, '#': true, '$': true, @@ -93,12 +93,7 @@ var isTokenTable = [127]bool{ } func IsTokenRune(r rune) bool { - i := int(r) - return i < len(isTokenTable) && isTokenTable[i] -} - -func isNotToken(r rune) bool { - return !IsTokenRune(r) + return r < utf8.RuneSelf && isTokenTable[byte(r)] } // HeaderValuesContainsToken reports whether any string in values @@ -202,8 +197,8 @@ func ValidHeaderFieldName(v string) bool { if len(v) == 0 { return false } - for _, r := range v { - if !IsTokenRune(r) { + for i := 0; i < len(v); i++ { + if !isTokenTable[v[i]] { return false } } diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/proxy.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/proxy.go similarity index 98% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/proxy.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/proxy.go index c3bd9a1eeb55..d89c257ae723 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/proxy.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/proxy.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" "net" + "net/netip" "net/url" "os" "strings" @@ -149,10 +150,7 @@ func parseProxy(proxy string) (*url.URL, error) { } proxyURL, err := url.Parse(proxy) - if err != nil || - (proxyURL.Scheme != "http" && - proxyURL.Scheme != "https" && - proxyURL.Scheme != "socks5") { + if err != nil || proxyURL.Scheme == "" || proxyURL.Host == "" { // proxy was bogus. Try prepending "http://" to it and // see if that parses correctly. If not, we fall // through and complain about the original one. @@ -180,8 +178,10 @@ func (cfg *config) useProxy(addr string) bool { if host == "localhost" { return false } - ip := net.ParseIP(host) - if ip != nil { + nip, err := netip.ParseAddr(host) + var ip net.IP + if err == nil { + ip = net.IP(nip.AsSlice()) if ip.IsLoopback() { return false } @@ -363,6 +363,9 @@ type domainMatch struct { } func (m domainMatch) match(host, port string, ip net.IP) bool { + if ip != nil { + return false + } if strings.HasSuffix(host, m.host) || (m.matchHost && host == m.host[1:]) { return m.port == "" || m.port == port } diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/encode.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/encode.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/encode.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/encode.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/hpack.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/hpack.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/hpack.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/hpack.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/huffman.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/huffman.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/huffman.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/huffman.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/static_table.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/static_table.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/static_table.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/static_table.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/tables.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/tables.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/tables.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/tables.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/go118.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/go118.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/go118.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/go118.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/idna10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/idna10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/idna10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/idna10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/idna9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/idna9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/idna9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/idna9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/pre_go118.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/pre_go118.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/pre_go118.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/pre_go118.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/punycode.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/punycode.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/punycode.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/punycode.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables11.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables11.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables11.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables11.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables12.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables12.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables12.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables12.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables13.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables13.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables13.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables13.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables15.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables15.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables15.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables15.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie12.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie12.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie12.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie12.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie13.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie13.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie13.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie13.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trieval.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trieval.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trieval.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trieval.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/address.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/address.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/address.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/address.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/binary.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/binary.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/binary.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/binary.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/empty.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/empty.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/empty.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/empty.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_announce.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_announce.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_announce.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_announce.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_classic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_classic.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_classic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_classic.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_freebsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_freebsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_freebsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_multicast.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_multicast.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_multicast.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_multicast.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_openbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_openbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_openbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/message.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/message.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/message.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/message.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route_classic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route_classic.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route_classic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route_classic.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route_openbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route_openbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route_openbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_darwin.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_darwin.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_darwin.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_dragonfly.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_dragonfly.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_dragonfly.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_freebsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_freebsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_freebsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_netbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_netbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_netbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_openbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_openbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_openbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/syscall.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/syscall.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/syscall.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_darwin.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_darwin.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_darwin.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_dragonfly.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_dragonfly.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_dragonfly.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_netbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_netbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_netbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_openbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_openbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_openbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/byteorder.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/byteorder.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/byteorder.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/byteorder.go diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu.go new file mode 100644 index 000000000000..8fa707aa4ba9 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu.go @@ -0,0 +1,291 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cpu implements processor feature detection for +// various CPU architectures. +package cpu + +import ( + "os" + "strings" +) + +// Initialized reports whether the CPU features were initialized. +// +// For some GOOS/GOARCH combinations initialization of the CPU features depends +// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm +// Initialized will report false if reading the file fails. +var Initialized bool + +// CacheLinePad is used to pad structs to avoid false sharing. +type CacheLinePad struct{ _ [cacheLineSize]byte } + +// X86 contains the supported CPU features of the +// current X86/AMD64 platform. If the current platform +// is not X86/AMD64 then all feature flags are false. +// +// X86 is padded to avoid false sharing. Further the HasAVX +// and HasAVX2 are only set if the OS supports XMM and YMM +// registers in addition to the CPUID feature bit being set. +var X86 struct { + _ CacheLinePad + HasAES bool // AES hardware implementation (AES NI) + HasADX bool // Multi-precision add-carry instruction extensions + HasAVX bool // Advanced vector extension + HasAVX2 bool // Advanced vector extension 2 + HasAVX512 bool // Advanced vector extension 512 + HasAVX512F bool // Advanced vector extension 512 Foundation Instructions + HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions + HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions + HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions + HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions + HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions + HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions + HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add + HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions + HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision + HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision + HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions + HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations + HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions + HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions + HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions + HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2 + HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms + HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions + HasAMXTile bool // Advanced Matrix Extension Tile instructions + HasAMXInt8 bool // Advanced Matrix Extension Int8 instructions + HasAMXBF16 bool // Advanced Matrix Extension BFloat16 instructions + HasBMI1 bool // Bit manipulation instruction set 1 + HasBMI2 bool // Bit manipulation instruction set 2 + HasCX16 bool // Compare and exchange 16 Bytes + HasERMS bool // Enhanced REP for MOVSB and STOSB + HasFMA bool // Fused-multiply-add instructions + HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. + HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM + HasPOPCNT bool // Hamming weight instruction POPCNT. + HasRDRAND bool // RDRAND instruction (on-chip random number generator) + HasRDSEED bool // RDSEED instruction (on-chip random number generator) + HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) + HasSSE3 bool // Streaming SIMD extension 3 + HasSSSE3 bool // Supplemental streaming SIMD extension 3 + HasSSE41 bool // Streaming SIMD extension 4 and 4.1 + HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + _ CacheLinePad +} + +// ARM64 contains the supported CPU features of the +// current ARMv8(aarch64) platform. If the current platform +// is not arm64 then all feature flags are false. +var ARM64 struct { + _ CacheLinePad + HasFP bool // Floating-point instruction set (always available) + HasASIMD bool // Advanced SIMD (always available) + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + HasATOMICS bool // Atomic memory operation instruction set + HasFPHP bool // Half precision floating-point instruction set + HasASIMDHP bool // Advanced SIMD half precision instruction set + HasCPUID bool // CPUID identification scheme registers + HasASIMDRDM bool // Rounding double multiply add/subtract instruction set + HasJSCVT bool // Javascript conversion from floating-point to integer + HasFCMA bool // Floating-point multiplication and addition of complex numbers + HasLRCPC bool // Release Consistent processor consistent support + HasDCPOP bool // Persistent memory support + HasSHA3 bool // SHA3 hardware implementation + HasSM3 bool // SM3 hardware implementation + HasSM4 bool // SM4 hardware implementation + HasASIMDDP bool // Advanced SIMD double precision instruction set + HasSHA512 bool // SHA512 hardware implementation + HasSVE bool // Scalable Vector Extensions + HasSVE2 bool // Scalable Vector Extensions 2 + HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 + _ CacheLinePad +} + +// ARM contains the supported CPU features of the current ARM (32-bit) platform. +// All feature flags are false if: +// 1. the current platform is not arm, or +// 2. the current operating system is not Linux. +var ARM struct { + _ CacheLinePad + HasSWP bool // SWP instruction support + HasHALF bool // Half-word load and store support + HasTHUMB bool // ARM Thumb instruction set + Has26BIT bool // Address space limited to 26-bits + HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support + HasFPA bool // Floating point arithmetic support + HasVFP bool // Vector floating point support + HasEDSP bool // DSP Extensions support + HasJAVA bool // Java instruction set + HasIWMMXT bool // Intel Wireless MMX technology support + HasCRUNCH bool // MaverickCrunch context switching and handling + HasTHUMBEE bool // Thumb EE instruction set + HasNEON bool // NEON instruction set + HasVFPv3 bool // Vector floating point version 3 support + HasVFPv3D16 bool // Vector floating point version 3 D8-D15 + HasTLS bool // Thread local storage support + HasVFPv4 bool // Vector floating point version 4 support + HasIDIVA bool // Integer divide instruction support in ARM mode + HasIDIVT bool // Integer divide instruction support in Thumb mode + HasVFPD32 bool // Vector floating point version 3 D15-D31 + HasLPAE bool // Large Physical Address Extensions + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + _ CacheLinePad +} + +// MIPS64X contains the supported CPU features of the current mips64/mips64le +// platforms. If the current platform is not mips64/mips64le or the current +// operating system is not Linux then all feature flags are false. +var MIPS64X struct { + _ CacheLinePad + HasMSA bool // MIPS SIMD architecture + _ CacheLinePad +} + +// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. +// If the current platform is not ppc64/ppc64le then all feature flags are false. +// +// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (DARN, SCV), so there are feature bits for +// those as well. The struct is padded to avoid false sharing. +var PPC64 struct { + _ CacheLinePad + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8 + _ CacheLinePad +} + +// S390X contains the supported CPU features of the current IBM Z +// (s390x) platform. If the current platform is not IBM Z then all +// feature flags are false. +// +// S390X is padded to avoid false sharing. Further HasVX is only set +// if the OS supports vector registers in addition to the STFLE +// feature bit being set. +var S390X struct { + _ CacheLinePad + HasZARCH bool // z/Architecture mode is active [mandatory] + HasSTFLE bool // store facility list extended + HasLDISP bool // long (20-bit) displacements + HasEIMM bool // 32-bit immediates + HasDFP bool // decimal floating point + HasETF3EH bool // ETF-3 enhanced + HasMSA bool // message security assist (CPACF) + HasAES bool // KM-AES{128,192,256} functions + HasAESCBC bool // KMC-AES{128,192,256} functions + HasAESCTR bool // KMCTR-AES{128,192,256} functions + HasAESGCM bool // KMA-GCM-AES{128,192,256} functions + HasGHASH bool // KIMD-GHASH function + HasSHA1 bool // K{I,L}MD-SHA-1 functions + HasSHA256 bool // K{I,L}MD-SHA-256 functions + HasSHA512 bool // K{I,L}MD-SHA-512 functions + HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions + HasVX bool // vector facility + HasVXE bool // vector-enhancements facility 1 + _ CacheLinePad +} + +func init() { + archInit() + initOptions() + processOptions() +} + +// options contains the cpu debug options that can be used in GODEBUG. +// Options are arch dependent and are added by the arch specific initOptions functions. +// Features that are mandatory for the specific GOARCH should have the Required field set +// (e.g. SSE2 on amd64). +var options []option + +// Option names should be lower case. e.g. avx instead of AVX. +type option struct { + Name string + Feature *bool + Specified bool // whether feature value was specified in GODEBUG + Enable bool // whether feature should be enabled + Required bool // whether feature is mandatory and can not be disabled +} + +func processOptions() { + env := os.Getenv("GODEBUG") +field: + for env != "" { + field := "" + i := strings.IndexByte(env, ',') + if i < 0 { + field, env = env, "" + } else { + field, env = env[:i], env[i+1:] + } + if len(field) < 4 || field[:4] != "cpu." { + continue + } + i = strings.IndexByte(field, '=') + if i < 0 { + print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n") + continue + } + key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" + + var enable bool + switch value { + case "on": + enable = true + case "off": + enable = false + default: + print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n") + continue field + } + + if key == "all" { + for i := range options { + options[i].Specified = true + options[i].Enable = enable || options[i].Required + } + continue field + } + + for i := range options { + if options[i].Name == key { + options[i].Specified = true + options[i].Enable = enable + continue field + } + } + + print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n") + } + + for _, o := range options { + if !o.Specified { + continue + } + + if o.Enable && !*o.Feature { + print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n") + continue + } + + if !o.Enable && o.Required { + print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n") + continue + } + + *o.Feature = o.Enable + } +} diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_aix.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_aix.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_aix.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go similarity index 95% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go index f3eb993bf24b..0e27a21e1f82 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go @@ -28,6 +28,7 @@ func initOptions() { {Name: "sm3", Feature: &ARM64.HasSM3}, {Name: "sm4", Feature: &ARM64.HasSM4}, {Name: "sve", Feature: &ARM64.HasSVE}, + {Name: "sve2", Feature: &ARM64.HasSVE2}, {Name: "crc32", Feature: &ARM64.HasCRC32}, {Name: "atomics", Feature: &ARM64.HasATOMICS}, {Name: "asimdhp", Feature: &ARM64.HasASIMDHP}, @@ -164,6 +165,15 @@ func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) { switch extractBits(pfr0, 32, 35) { case 1: ARM64.HasSVE = true + + parseARM64SVERegister(getzfr0()) + } +} + +func parseARM64SVERegister(zfr0 uint64) { + switch extractBits(zfr0, 0, 3) { + case 1: + ARM64.HasSVE2 = true } } diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s similarity index 80% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s index fcb9a3888205..22cc99844a75 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s @@ -29,3 +29,11 @@ TEXT ·getpfr0(SB),NOSPLIT,$0-8 WORD $0xd5380400 MOVD R0, ret+0(FP) RET + +// func getzfr0() uint64 +TEXT ·getzfr0(SB),NOSPLIT,$0-8 + // get SVE Feature Register 0 into x0 + // mrs x0, ID_AA64ZFR0_EL1 = d5380480 + WORD $0xd5380480 + MOVD R0, ret+0(FP) + RET diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go similarity index 92% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go index a8acd3e3285d..6ac6e1efb208 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go @@ -9,3 +9,4 @@ package cpu func getisar0() uint64 func getisar1() uint64 func getpfr0() uint64 +func getzfr0() uint64 diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go similarity index 97% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go index a968b80fa6ab..3d386d0fc218 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go @@ -35,6 +35,8 @@ const ( hwcap_SHA512 = 1 << 21 hwcap_SVE = 1 << 22 hwcap_ASIMDFHM = 1 << 23 + + hwcap2_SVE2 = 1 << 1 ) // linuxKernelCanEmulateCPUID reports whether we're running @@ -104,6 +106,9 @@ func doinit() { ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512) ARM64.HasSVE = isSet(hwCap, hwcap_SVE) ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) + + // HWCAP2 feature bits + ARM64.HasSVE2 = isSet(hwCap2, hwcap2_SVE2) } func isSet(hwc uint, value uint) bool { diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_loong64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_loong64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_loong64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_mips64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_mips64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_arm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_arm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_arm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_riscv64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_riscv64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_riscv64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_s390x.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_s390x.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_s390x.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_wasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_wasm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_wasm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_x86.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_x86.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_x86.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_x86.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_x86.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_x86.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_x86.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_zos.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_zos.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_zos.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_zos.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/endian_big.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/endian_big.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/endian_big.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/endian_big.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/endian_little.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/endian_little.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/endian_little.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/endian_little.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/hwcap_linux.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/hwcap_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/hwcap_linux.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/hwcap_linux.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/parse.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/parse.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/parse.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/parse.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/runtime_auxv.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/runtime_auxv.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/runtime_auxv.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/runtime_auxv.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/ya.make new file mode 100644 index 000000000000..37aa8413d2d1 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/ya.make @@ -0,0 +1,70 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + byteorder.go + cpu.go + cpu_arm64.go + cpu_arm64.s + cpu_gc_arm64.go + cpu_other_arm64.go + endian_little.go + parse.go + runtime_auxv.go + runtime_auxv_go121.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + byteorder.go + cpu.go + cpu_gc_x86.go + cpu_x86.go + cpu_x86.s + endian_little.go + parse.go + runtime_auxv.go + runtime_auxv_go121.go + ) +ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + byteorder.go + cpu.go + cpu_arm64.go + cpu_arm64.s + cpu_gc_arm64.go + cpu_linux_arm64.go + endian_little.go + hwcap_linux.go + parse.go + proc_cpuinfo_linux.go + runtime_auxv.go + runtime_auxv_go121.go + ) +ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + byteorder.go + cpu.go + cpu_gc_x86.go + cpu_linux_noinit.go + cpu_x86.go + cpu_x86.s + endian_little.go + hwcap_linux.go + parse.go + runtime_auxv.go + runtime_auxv_go121.go + ) +ELSEIF (OS_LINUX AND ARCH_ARM7 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ARM7 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + byteorder.go + cpu.go + cpu_arm.go + cpu_linux.go + cpu_linux_arm.go + endian_little.go + hwcap_linux.go + parse.go + runtime_auxv.go + runtime_auxv_go121.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/transform/transform.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/transform/transform.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/transform/transform.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/transform/transform.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/transform/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/transform/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/transform/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/transform/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/bidi.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/bidi.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/bidi.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/bidi.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/bracket.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/bracket.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/bracket.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/bracket.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/core.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/core.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/core.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/core.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/prop.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/prop.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/prop.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/prop.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/trieval.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/trieval.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/trieval.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/trieval.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/composition.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/composition.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/composition.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/composition.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/forminfo.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/forminfo.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/forminfo.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/forminfo.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/input.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/input.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/input.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/input.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/iter.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/iter.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/iter.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/iter.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/normalize.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/normalize.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/normalize.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/normalize.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/readwriter.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/readwriter.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/readwriter.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/readwriter.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/transform.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/transform.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/transform.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/transform.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/trie.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/trie.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/trie.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/trie.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/ya.make diff --git a/contrib/libs/c-ares/.yandex_meta/override.nix b/contrib/libs/c-ares/.yandex_meta/override.nix index 64407f85a0f5..c7309f5cd928 100644 --- a/contrib/libs/c-ares/.yandex_meta/override.nix +++ b/contrib/libs/c-ares/.yandex_meta/override.nix @@ -1,11 +1,11 @@ pkgs: attrs: with pkgs; with attrs; rec { - version = "1.34.4"; + version = "1.34.5"; src = fetchFromGitHub { owner = "c-ares"; repo = "c-ares"; rev= "v${version}"; - hash = "sha256-6xJSo4ptXAKFwCUBRAji8DSqkxoIL6lpWvnDOM1NQNg="; + hash = "sha256-MeQ4eqt7QyRD7YVomXR+fwBzraiYe2s2Eozz0sE8Xgo="; }; patches = []; diff --git a/contrib/libs/c-ares/RELEASE-NOTES.md b/contrib/libs/c-ares/RELEASE-NOTES.md index 19a204b3ea96..1a8d8d223335 100644 --- a/contrib/libs/c-ares/RELEASE-NOTES.md +++ b/contrib/libs/c-ares/RELEASE-NOTES.md @@ -1,25 +1,28 @@ -## c-ares version 1.34.4 - December 14 2024 +## c-ares version 1.34.5 - April 8 2025 -This is a bugfix release. +This is a security release. + +Security: +* CVE-2025-31498. A use-after-free bug has been uncovered in read_answers() that + was introduced in v1.32.3. Please see https://github.com/c-ares/c-ares/security/advisories/GHSA-6hxc-62jh-p29v Changes: -* QNX Port: Port to QNX 8, add primary config reading support, add CI build. [PR #934](https://github.com/c-ares/c-ares/pull/934), [PR #937](https://github.com/c-ares/c-ares/pull/937), [PR #938](https://github.com/c-ares/c-ares/pull/938) +* Restore Windows XP support. [PR #958](https://github.com/c-ares/c-ares/pull/958) Bugfixes: -* Empty TXT records were not being preserved. [PR #922](https://github.com/c-ares/c-ares/pull/922) -* docs: update deprecation notices for `ares_create_query()` and `ares_mkquery()`. [PR #910](https://github.com/c-ares/c-ares/pull/910) -* license: some files weren't properly updated. [PR #920](https://github.com/c-ares/c-ares/pull/920) -* Fix bind local device regression from 1.34.0. [PR #929](https://github.com/c-ares/c-ares/pull/929), [PR #931](https://github.com/c-ares/c-ares/pull/931), [PR #935](https://github.com/c-ares/c-ares/pull/935) -* CMake: set policy version to prevent deprecation warnings. [PR #932](https://github.com/c-ares/c-ares/pull/932) -* CMake: shared and static library names should be the same on unix platforms like autotools uses. [PR #933](https://github.com/c-ares/c-ares/pull/933) -* Update to latest autoconf archive macros for enhanced system compatibility. [PR #936](https://github.com/c-ares/c-ares/pull/936) +* A missing mutex initialization would make busy polling for configuration + changes (platforms other than Windows, Linux, MacOS) eat too much CPU + [PR #974](https://github.com/c-ares/c-ares/pull/974) +* Pkgconfig may be generated wrong for static builds in relation to `-pthread` + [PR #965](https://github.com/c-ares/c-ares/pull/965) +* Localhost resolution can fail if only one address family is in `/etc/hosts` + [PR #947](https://github.com/c-ares/c-ares/pull/947) Thanks go to these friendly people for their efforts and contributions for this release: * Brad House (@bradh352) -* Daniel Stenberg (@bagder) -* Gregor Jasny (@gjasny) -* @marcovsz -* Nikolaos Chatzikonstantinou (@createyourpersonalaccount) -* @vlasovsoft1979 +* Erik Lax (@eriklax) +* Florian Pfisterer (@FlorianPfisterer) +* Kai Pastor (@dg0yt) + diff --git a/contrib/libs/c-ares/include/ares_dns_record.h b/contrib/libs/c-ares/include/ares_dns_record.h index 2896eab24b34..cec9f47f63d8 100644 --- a/contrib/libs/c-ares/include/ares_dns_record.h +++ b/contrib/libs/c-ares/include/ares_dns_record.h @@ -1104,7 +1104,7 @@ CARES_EXTERN ares_status_t ares_dns_write(const ares_dns_record_t *dnsrec, * (such as the ttl decrement capability). * * \param[in] dnsrec Pointer to initialized and filled DNS record object. - * \return duplicted DNS record object, or NULL on out of memory. + * \return duplicated DNS record object, or NULL on out of memory. */ CARES_EXTERN ares_dns_record_t * ares_dns_record_duplicate(const ares_dns_record_t *dnsrec); diff --git a/contrib/libs/c-ares/include/ares_version.h b/contrib/libs/c-ares/include/ares_version.h index 782046bd79d8..7da82f2a15b5 100644 --- a/contrib/libs/c-ares/include/ares_version.h +++ b/contrib/libs/c-ares/include/ares_version.h @@ -32,8 +32,8 @@ #define ARES_VERSION_MAJOR 1 #define ARES_VERSION_MINOR 34 -#define ARES_VERSION_PATCH 4 -#define ARES_VERSION_STR "1.34.4" +#define ARES_VERSION_PATCH 5 +#define ARES_VERSION_STR "1.34.5" /* NOTE: We cannot make the version string a C preprocessor stringify operation * due to assumptions made by integrators that aren't properly using diff --git a/contrib/libs/c-ares/src/lib/ares_addrinfo2hostent.c b/contrib/libs/c-ares/src/lib/ares_addrinfo2hostent.c index 2bbc791157b0..239ca5bce7da 100644 --- a/contrib/libs/c-ares/src/lib/ares_addrinfo2hostent.c +++ b/contrib/libs/c-ares/src/lib/ares_addrinfo2hostent.c @@ -47,119 +47,154 @@ # include #endif +static size_t hostent_nalias(const struct hostent *host) +{ + size_t i; + for (i=0; host->h_aliases != NULL && host->h_aliases[i] != NULL; i++) + ; + + return i; +} + +static size_t ai_nalias(const struct ares_addrinfo *ai) +{ + const struct ares_addrinfo_cname *cname; + size_t i = 0; + + for (cname = ai->cnames; cname != NULL; cname=cname->next) { + i++; + } + + return i; +} + +static size_t hostent_naddr(const struct hostent *host) +{ + size_t i; + for (i=0; host->h_addr_list != NULL && host->h_addr_list[i] != NULL; i++) + ; + + return i; +} + +static size_t ai_naddr(const struct ares_addrinfo *ai, int af) +{ + const struct ares_addrinfo_node *node; + size_t i = 0; + + for (node = ai->nodes; node != NULL; node=node->ai_next) { + if (af != AF_UNSPEC && af != node->ai_family) + continue; + i++; + } + + return i; +} ares_status_t ares_addrinfo2hostent(const struct ares_addrinfo *ai, int family, struct hostent **host) { struct ares_addrinfo_node *next; - struct ares_addrinfo_cname *next_cname; char **aliases = NULL; - char *addrs = NULL; + char **addrs = NULL; size_t naliases = 0; size_t naddrs = 0; - size_t alias = 0; size_t i; + size_t ealiases = 0; + size_t eaddrs = 0; if (ai == NULL || host == NULL) { return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ } - /* Use the first node of the response as the family, since hostent can only + /* Use either the host set in the passed in hosts to be filled in, or the + * first node of the response as the family, since hostent can only * represent one family. We assume getaddrinfo() returned a sorted list if * the user requested AF_UNSPEC. */ - if (family == AF_UNSPEC && ai->nodes) { - family = ai->nodes->ai_family; + if (family == AF_UNSPEC) { + if (*host != NULL && (*host)->h_addrtype != AF_UNSPEC) { + family = (*host)->h_addrtype; + } else if (ai->nodes != NULL) { + family = ai->nodes->ai_family; + } } if (family != AF_INET && family != AF_INET6) { return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ } - *host = ares_malloc(sizeof(**host)); - if (!(*host)) { - goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ + if (*host == NULL) { + *host = ares_malloc_zero(sizeof(**host)); + if (!(*host)) { + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ + } } - memset(*host, 0, sizeof(**host)); - next = ai->nodes; - while (next) { - if (next->ai_family == family) { - ++naddrs; - } - next = next->ai_next; + (*host)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family; + if (family == AF_INET) { + (*host)->h_length = sizeof(struct in_addr); + } else if (family == AF_INET6) { + (*host)->h_length = sizeof(struct ares_in6_addr); } - next_cname = ai->cnames; - while (next_cname) { - if (next_cname->alias) { - ++naliases; + if ((*host)->h_name == NULL) { + if (ai->cnames) { + (*host)->h_name = ares_strdup(ai->cnames->name); + if ((*host)->h_name == NULL && ai->cnames->name) { + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ + } + } else { + (*host)->h_name = ares_strdup(ai->name); + if ((*host)->h_name == NULL && ai->name) { + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ + } } - next_cname = next_cname->next; } - aliases = ares_malloc((naliases + 1) * sizeof(char *)); + naliases = ai_nalias(ai); + ealiases = hostent_nalias(*host); + aliases = ares_realloc_zero((*host)->h_aliases, + ealiases * sizeof(char *), + (naliases + ealiases + 1) * sizeof(char *)); if (!aliases) { goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } (*host)->h_aliases = aliases; - memset(aliases, 0, (naliases + 1) * sizeof(char *)); if (naliases) { - for (next_cname = ai->cnames; next_cname != NULL; - next_cname = next_cname->next) { - if (next_cname->alias == NULL) { + const struct ares_addrinfo_cname *cname; + i = ealiases; + for (cname = ai->cnames; cname != NULL; cname = cname->next) { + if (cname->alias == NULL) { continue; } - aliases[alias] = ares_strdup(next_cname->alias); - if (!aliases[alias]) { + (*host)->h_aliases[i] = ares_strdup(cname->alias); + if ((*host)->h_aliases[i] == NULL) { goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } - alias++; + i++; } } - - (*host)->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *)); - if (!(*host)->h_addr_list) { + naddrs = ai_naddr(ai, family); + eaddrs = hostent_naddr(*host); + addrs = ares_realloc_zero((*host)->h_addr_list, eaddrs * sizeof(char *), + (naddrs + eaddrs + 1) * sizeof(char *)); + if (addrs == NULL) { goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } - - memset((*host)->h_addr_list, 0, (naddrs + 1) * sizeof(char *)); - - if (ai->cnames) { - (*host)->h_name = ares_strdup(ai->cnames->name); - if ((*host)->h_name == NULL && ai->cnames->name) { - goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ - } - } else { - (*host)->h_name = ares_strdup(ai->name); - if ((*host)->h_name == NULL && ai->name) { - goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ - } - } - - (*host)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family; - - if (family == AF_INET) { - (*host)->h_length = sizeof(struct in_addr); - } - - if (family == AF_INET6) { - (*host)->h_length = sizeof(struct ares_in6_addr); - } + (*host)->h_addr_list = addrs; if (naddrs) { - addrs = ares_malloc(naddrs * (size_t)(*host)->h_length); - if (!addrs) { - goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ - } - - i = 0; + i = eaddrs; for (next = ai->nodes; next != NULL; next = next->ai_next) { if (next->ai_family != family) { continue; } - (*host)->h_addr_list[i] = addrs + (i * (size_t)(*host)->h_length); + (*host)->h_addr_list[i] = ares_malloc_zero((size_t)(*host)->h_length); + if ((*host)->h_addr_list[i] == NULL) { + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ + } if (family == AF_INET6) { memcpy((*host)->h_addr_list[i], &(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr) @@ -172,15 +207,11 @@ ares_status_t ares_addrinfo2hostent(const struct ares_addrinfo *ai, int family, ->sin_addr), (size_t)(*host)->h_length); } - ++i; - } - - if (i == 0) { - ares_free(addrs); + i++; } } - if (naddrs == 0 && naliases == 0) { + if (naddrs + eaddrs == 0 && naliases + ealiases == 0) { ares_free_hostent(*host); *host = NULL; return ARES_ENODATA; diff --git a/contrib/libs/c-ares/src/lib/ares_addrinfo_localhost.c b/contrib/libs/c-ares/src/lib/ares_addrinfo_localhost.c index 6f4f2a373b3f..2abb0c48a6f6 100644 --- a/contrib/libs/c-ares/src/lib/ares_addrinfo_localhost.c +++ b/contrib/libs/c-ares/src/lib/ares_addrinfo_localhost.c @@ -49,6 +49,19 @@ # endif #endif +static ares_bool_t ares_ai_has_family(int aftype, + const struct ares_addrinfo_node *nodes) +{ + const struct ares_addrinfo_node *node; + + for (node = nodes; node != NULL; node = node->ai_next) { + if (node->ai_family == aftype) + return ARES_TRUE; + } + + return ARES_FALSE; +} + ares_status_t ares_append_ai_node(int aftype, unsigned short port, unsigned int ttl, const void *adata, struct ares_addrinfo_node **nodes) @@ -107,7 +120,8 @@ static ares_status_t { ares_status_t status = ARES_SUCCESS; - if (aftype == AF_UNSPEC || aftype == AF_INET6) { + if ((aftype == AF_UNSPEC || aftype == AF_INET6) && + !ares_ai_has_family(AF_INET6, *nodes)) { struct ares_in6_addr addr6; ares_inet_pton(AF_INET6, "::1", &addr6); status = ares_append_ai_node(AF_INET6, port, 0, &addr6, nodes); @@ -116,7 +130,8 @@ static ares_status_t } } - if (aftype == AF_UNSPEC || aftype == AF_INET) { + if ((aftype == AF_UNSPEC || aftype == AF_INET) && + !ares_ai_has_family(AF_INET, *nodes)) { struct in_addr addr4; ares_inet_pton(AF_INET, "127.0.0.1", &addr4); status = ares_append_ai_node(AF_INET, port, 0, &addr4, nodes); @@ -150,11 +165,13 @@ static ares_status_t continue; } - if (table->Table[i].Address.si_family == AF_INET) { + if (table->Table[i].Address.si_family == AF_INET && + !ares_ai_has_family(AF_INET, *nodes)) { status = ares_append_ai_node(table->Table[i].Address.si_family, port, 0, &table->Table[i].Address.Ipv4.sin_addr, nodes); - } else if (table->Table[i].Address.si_family == AF_INET6) { + } else if (table->Table[i].Address.si_family == AF_INET6 && + !ares_ai_has_family(AF_INET6, *nodes)) { status = ares_append_ai_node(table->Table[i].Address.si_family, port, 0, &table->Table[i].Address.Ipv6.sin6_addr, nodes); @@ -195,8 +212,7 @@ ares_status_t ares_addrinfo_localhost(const char *name, unsigned short port, const struct ares_addrinfo_hints *hints, struct ares_addrinfo *ai) { - struct ares_addrinfo_node *nodes = NULL; - ares_status_t status; + ares_status_t status; /* Validate family */ switch (hints->ai_family) { @@ -208,26 +224,22 @@ ares_status_t ares_addrinfo_localhost(const char *name, unsigned short port, return ARES_EBADFAMILY; /* LCOV_EXCL_LINE: DefensiveCoding */ } + if (ai->name != NULL) { + ares_free(ai->name); + } ai->name = ares_strdup(name); - if (!ai->name) { - goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ + if (ai->name == NULL) { + status = ARES_ENOMEM; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } - status = ares_system_loopback_addrs(hints->ai_family, port, &nodes); - - if (status == ARES_ENOTFOUND) { - status = ares_default_loopback_addrs(hints->ai_family, port, &nodes); + status = ares_system_loopback_addrs(hints->ai_family, port, &ai->nodes); + if (status != ARES_SUCCESS && status != ARES_ENOTFOUND) { + goto done; } - ares_addrinfo_cat_nodes(&ai->nodes, nodes); + status = ares_default_loopback_addrs(hints->ai_family, port, &ai->nodes); +done: return status; - -/* LCOV_EXCL_START: OutOfMemory */ -enomem: - ares_freeaddrinfo_nodes(nodes); - ares_free(ai->name); - ai->name = NULL; - return ARES_ENOMEM; - /* LCOV_EXCL_STOP */ } diff --git a/contrib/libs/c-ares/src/lib/ares_close_sockets.c b/contrib/libs/c-ares/src/lib/ares_close_sockets.c index fd3bf3c4b1e0..347f43e6fcd8 100644 --- a/contrib/libs/c-ares/src/lib/ares_close_sockets.c +++ b/contrib/libs/c-ares/src/lib/ares_close_sockets.c @@ -37,7 +37,7 @@ static void ares_requeue_queries(ares_conn_t *conn, ares_tvnow(&now); while ((query = ares_llist_first_val(conn->queries_to_conn)) != NULL) { - ares_requeue_query(query, &now, requeue_status, ARES_TRUE, NULL); + ares_requeue_query(query, &now, requeue_status, ARES_TRUE, NULL, NULL); } } diff --git a/contrib/libs/c-ares/src/lib/ares_config-linux.h b/contrib/libs/c-ares/src/lib/ares_config-linux.h index 778bf91eeda1..e0e7bd6c5fac 100644 --- a/contrib/libs/c-ares/src/lib/ares_config-linux.h +++ b/contrib/libs/c-ares/src/lib/ares_config-linux.h @@ -145,6 +145,9 @@ /* Define to 1 if you have the `if_nametoindex' function. */ #define HAVE_IF_NAMETOINDEX 1 +/* Define to 1 if you have the `GetBestRoute2' function. */ +/* #undef HAVE_GETBESTROUTE2 */ + /* Define to 1 if you have the `ConvertInterfaceIndexToLuid' function. */ /* #undef HAVE_CONVERTINTERFACEINDEXTOLUID */ diff --git a/contrib/libs/c-ares/src/lib/ares_cookie.c b/contrib/libs/c-ares/src/lib/ares_cookie.c index f31c74e748d9..509e12050e0c 100644 --- a/contrib/libs/c-ares/src/lib/ares_cookie.c +++ b/contrib/libs/c-ares/src/lib/ares_cookie.c @@ -115,7 +115,7 @@ * - If `cookie.unsupported_ts` evaluates less than * `COOKIE_UNSUPPORTED_TIMEOUT` * - Ensure there is no EDNS cookie opt (10) set (shouldn't be unless - * requestor had put this themselves), then **skip any remaining + * requester had put this themselves), then **skip any remaining * processing** as we don't want to try to send cookies. * - Otherwise: * - clear all cookie settings, set `cookie.state = INITIAL`. @@ -369,7 +369,8 @@ ares_status_t ares_cookie_apply(ares_dns_record_t *dnsrec, ares_conn_t *conn, ares_status_t ares_cookie_validate(ares_query_t *query, const ares_dns_record_t *dnsresp, - ares_conn_t *conn, const ares_timeval_t *now) + ares_conn_t *conn, const ares_timeval_t *now, + ares_array_t **requeue) { ares_server_t *server = conn->server; ares_cookie_t *cookie = &server->cookie; @@ -427,7 +428,8 @@ ares_status_t ares_cookie_validate(ares_query_t *query, /* Resend the request, hopefully it will work the next time as we should * have recorded a server cookie */ ares_requeue_query(query, now, ARES_SUCCESS, - ARES_FALSE /* Don't increment try count */, NULL); + ARES_FALSE /* Don't increment try count */, NULL, + requeue); /* Parent needs to drop this response */ return ARES_EBADRESP; diff --git a/contrib/libs/c-ares/src/lib/ares_free_hostent.c b/contrib/libs/c-ares/src/lib/ares_free_hostent.c index bf2037238b55..dfcbdf4910b6 100644 --- a/contrib/libs/c-ares/src/lib/ares_free_hostent.c +++ b/contrib/libs/c-ares/src/lib/ares_free_hostent.c @@ -44,9 +44,10 @@ void ares_free_hostent(struct hostent *host) } ares_free(host->h_aliases); if (host->h_addr_list) { - ares_free( - host->h_addr_list[0]); /* no matter if there is one or many entries, - there is only one malloc for all of them */ + size_t i; + for (i=0; host->h_addr_list[i] != NULL; i++) { + ares_free(host->h_addr_list[i]); + } ares_free(host->h_addr_list); } ares_free(host); diff --git a/contrib/libs/c-ares/src/lib/ares_getaddrinfo.c b/contrib/libs/c-ares/src/lib/ares_getaddrinfo.c index 32791dc37dcd..eabd17fcbac3 100644 --- a/contrib/libs/c-ares/src/lib/ares_getaddrinfo.c +++ b/contrib/libs/c-ares/src/lib/ares_getaddrinfo.c @@ -418,9 +418,13 @@ static ares_status_t file_lookup(struct host_query *hquery) * SHOULD recognize localhost names as special and SHOULD always return the * IP loopback address for address queries". * We will also ignore ALL errors when trying to resolve localhost, such - * as permissions errors reading /etc/hosts or a malformed /etc/hosts */ - if (status != ARES_SUCCESS && status != ARES_ENOMEM && - ares_is_localhost(hquery->name)) { + * as permissions errors reading /etc/hosts or a malformed /etc/hosts. + * + * Also, just because the query itself returned success from /etc/hosts + * lookup doesn't mean it returned everything it needed to for all requested + * address families. As long as we're not on a critical out of memory + * condition pass it through to fill in any other address classes. */ + if (status != ARES_ENOMEM && ares_is_localhost(hquery->name)) { return ares_addrinfo_localhost(hquery->name, hquery->port, &hquery->hints, hquery->ai); } diff --git a/contrib/libs/c-ares/src/lib/ares_gethostbyaddr.c b/contrib/libs/c-ares/src/lib/ares_gethostbyaddr.c index a7acf3c45c9e..69c509ab11b9 100644 --- a/contrib/libs/c-ares/src/lib/ares_gethostbyaddr.c +++ b/contrib/libs/c-ares/src/lib/ares_gethostbyaddr.c @@ -120,7 +120,7 @@ static void next_lookup(struct addr_query *aquery) { const char *p; ares_status_t status; - struct hostent *host; + struct hostent *host = NULL; char *name; for (p = aquery->remaining_lookups; *p; p++) { diff --git a/contrib/libs/c-ares/src/lib/ares_gethostbyname.c b/contrib/libs/c-ares/src/lib/ares_gethostbyname.c index 56de729526af..d451b4685110 100644 --- a/contrib/libs/c-ares/src/lib/ares_gethostbyname.c +++ b/contrib/libs/c-ares/src/lib/ares_gethostbyname.c @@ -287,6 +287,8 @@ static ares_status_t ares_gethostbyname_file_int(ares_channel_t *channel, return ARES_ENOTFOUND; } + *host = NULL; + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ if (ares_is_onion_domain(name)) { return ARES_ENOTFOUND; @@ -307,9 +309,13 @@ static ares_status_t ares_gethostbyname_file_int(ares_channel_t *channel, * SHOULD recognize localhost names as special and SHOULD always return the * IP loopback address for address queries". * We will also ignore ALL errors when trying to resolve localhost, such - * as permissions errors reading /etc/hosts or a malformed /etc/hosts */ - if (status != ARES_SUCCESS && status != ARES_ENOMEM && - ares_is_localhost(name)) { + * as permissions errors reading /etc/hosts or a malformed /etc/hosts. + * + * Also, just because the query itself returned success from /etc/hosts + * lookup doesn't mean it returned everything it needed to for all requested + * address families. As long as we're not on a critical out of memory + * condition pass it through to fill in any other address classes. */ + if (status != ARES_ENOMEM && ares_is_localhost(name)) { return ares_hostent_localhost(name, family, host); } diff --git a/contrib/libs/c-ares/src/lib/ares_hosts_file.c b/contrib/libs/c-ares/src/lib/ares_hosts_file.c index 0439b8e1d476..d18863b8f668 100644 --- a/contrib/libs/c-ares/src/lib/ares_hosts_file.c +++ b/contrib/libs/c-ares/src/lib/ares_hosts_file.c @@ -845,7 +845,7 @@ ares_status_t ares_hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry, ares_bool_t want_cnames, struct ares_addrinfo *ai) { - ares_status_t status; + ares_status_t status = ARES_ENOTFOUND; struct ares_addrinfo_cname *cnames = NULL; struct ares_addrinfo_node *ainodes = NULL; ares_llist_node_t *node; @@ -860,6 +860,7 @@ ares_status_t ares_hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry, } if (name != NULL) { + ares_free(ai->name); ai->name = ares_strdup(name); if (ai->name == NULL) { status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ @@ -888,6 +889,11 @@ ares_status_t ares_hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry, } } + /* Might be ARES_ENOTFOUND here if no ips matched requested address family */ + if (status != ARES_SUCCESS) { + goto done; + } + if (want_cnames) { status = ares_hosts_ai_append_cnames(entry, &cnames); if (status != ARES_SUCCESS) { diff --git a/contrib/libs/c-ares/src/lib/ares_ipv6.h b/contrib/libs/c-ares/src/lib/ares_ipv6.h index 5da341b01060..d2007cc29ec4 100644 --- a/contrib/libs/c-ares/src/lib/ares_ipv6.h +++ b/contrib/libs/c-ares/src/lib/ares_ipv6.h @@ -90,6 +90,16 @@ struct addrinfo { # define NS_INT16SZ 2 #endif +/* Windows XP Compatibility with later MSVC/Mingw versions */ +#if defined(_WIN32) +# if !defined(IF_MAX_STRING_SIZE) +# define IF_MAX_STRING_SIZE 256 /* =256 in */ +# endif +# if !defined(NDIS_IF_MAX_STRING_SIZE) +# define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE /* =256 in */ +# endif +#endif + #ifndef IF_NAMESIZE # ifdef IFNAMSIZ # define IF_NAMESIZE IFNAMSIZ diff --git a/contrib/libs/c-ares/src/lib/ares_metrics.c b/contrib/libs/c-ares/src/lib/ares_metrics.c index 13e34decc06a..deb3b7febcc4 100644 --- a/contrib/libs/c-ares/src/lib/ares_metrics.c +++ b/contrib/libs/c-ares/src/lib/ares_metrics.c @@ -197,7 +197,7 @@ void ares_metrics_record(const ares_query_t *query, ares_server_t *server, } if (query_ms > server->metrics[i].latency_max_ms) { - server->metrics[i].latency_min_ms = query_ms; + server->metrics[i].latency_max_ms = query_ms; } server->metrics[i].total_count++; diff --git a/contrib/libs/c-ares/src/lib/ares_private.h b/contrib/libs/c-ares/src/lib/ares_private.h index e6d44e8b8640..3d7cea3d3a03 100644 --- a/contrib/libs/c-ares/src/lib/ares_private.h +++ b/contrib/libs/c-ares/src/lib/ares_private.h @@ -321,7 +321,8 @@ ares_status_t ares_send_query(ares_server_t *requested_server /* Optional */, ares_status_t ares_requeue_query(ares_query_t *query, const ares_timeval_t *now, ares_status_t status, ares_bool_t inc_try_count, - const ares_dns_record_t *dnsrec); + const ares_dns_record_t *dnsrec, + ares_array_t **requeue); /*! Count the number of labels (dots+1) in a domain */ size_t ares_name_label_cnt(const char *name); @@ -455,8 +456,10 @@ ares_status_t ares_parse_ptr_reply_dnsrec(const ares_dns_record_t *dnsrec, const void *addr, int addrlen, int family, struct hostent **host); +/* host address must be valid or NULL as will create or append */ ares_status_t ares_addrinfo2hostent(const struct ares_addrinfo *ai, int family, struct hostent **host); + ares_status_t ares_addrinfo2addrttl(const struct ares_addrinfo *ai, int family, size_t req_naddrttls, struct ares_addrttl *addrttls, @@ -610,7 +613,8 @@ ares_status_t ares_cookie_apply(ares_dns_record_t *dnsrec, ares_conn_t *conn, ares_status_t ares_cookie_validate(ares_query_t *query, const ares_dns_record_t *dnsresp, ares_conn_t *conn, - const ares_timeval_t *now); + const ares_timeval_t *now, + ares_array_t **requeue); ares_status_t ares_channel_threading_init(ares_channel_t *channel); void ares_channel_threading_destroy(ares_channel_t *channel); diff --git a/contrib/libs/c-ares/src/lib/ares_process.c b/contrib/libs/c-ares/src/lib/ares_process.c index 3d186ea9d58b..c5834fa100e8 100644 --- a/contrib/libs/c-ares/src/lib/ares_process.c +++ b/contrib/libs/c-ares/src/lib/ares_process.c @@ -56,7 +56,8 @@ static ares_status_t process_timeouts(ares_channel_t *channel, static ares_status_t process_answer(ares_channel_t *channel, const unsigned char *abuf, size_t alen, ares_conn_t *conn, - const ares_timeval_t *now); + const ares_timeval_t *now, + ares_array_t **requeue); static void handle_conn_error(ares_conn_t *conn, ares_bool_t critical_failure, ares_status_t failure_status); static ares_bool_t same_questions(const ares_query_t *query, @@ -510,10 +511,38 @@ static ares_status_t read_conn_packets(ares_conn_t *conn) return ARES_SUCCESS; } +/* Simple data structure to store a query that needs to be requeued with + * optional server */ +typedef struct { + unsigned short qid; + ares_server_t *server; /* optional */ +} ares_requeue_t; + +static ares_status_t ares_append_requeue(ares_array_t **requeue, + ares_query_t *query, + ares_server_t *server) +{ + ares_requeue_t entry; + + if (*requeue == NULL) { + *requeue = ares_array_create(sizeof(ares_requeue_t), NULL); + if (*requeue == NULL) { + return ARES_ENOMEM; + } + } + + ares_query_remove_from_conn(query); + + entry.qid = query->qid; + entry.server = server; + return ares_array_insertdata_last(*requeue, &entry); +} + static ares_status_t read_answers(ares_conn_t *conn, const ares_timeval_t *now) { ares_status_t status; ares_channel_t *channel = conn->server->channel; + ares_array_t *requeue = NULL; /* Process all queued answers */ while (1) { @@ -550,15 +579,43 @@ static ares_status_t read_answers(ares_conn_t *conn, const ares_timeval_t *now) data_len -= 2; /* We finished reading this answer; process it */ - status = process_answer(channel, data, data_len, conn, now); + status = process_answer(channel, data, data_len, conn, now, &requeue); if (status != ARES_SUCCESS) { handle_conn_error(conn, ARES_TRUE, status); - return status; + goto cleanup; } /* Since we processed the answer, clear the tag so space can be reclaimed */ ares_buf_tag_clear(conn->in_buf); } + +cleanup: + + /* Flush requeue */ + while (ares_array_len(requeue) > 0) { + ares_query_t *query; + ares_requeue_t entry; + ares_status_t internal_status; + + internal_status = ares_array_claim_at(&entry, sizeof(entry), requeue, 0); + if (internal_status != ARES_SUCCESS) { + break; + } + + /* Query disappeared */ + query = ares_htable_szvp_get_direct(channel->queries_by_qid, entry.qid); + if (query == NULL) { + continue; + } + + internal_status = ares_send_query(entry.server, query, now); + /* We only care about ARES_ENOMEM */ + if (internal_status == ARES_ENOMEM) { + status = ARES_ENOMEM; + } + } + ares_array_destroy(requeue); + return status; } @@ -611,7 +668,8 @@ static ares_status_t process_timeouts(ares_channel_t *channel, conn = query->conn; server_increment_failures(conn->server, query->using_tcp); - status = ares_requeue_query(query, now, ARES_ETIMEOUT, ARES_TRUE, NULL); + status = ares_requeue_query(query, now, ARES_ETIMEOUT, ARES_TRUE, NULL, + NULL); if (status == ARES_ENOMEM) { goto done; } @@ -701,7 +759,8 @@ static ares_bool_t issue_might_be_edns(const ares_dns_record_t *req, static ares_status_t process_answer(ares_channel_t *channel, const unsigned char *abuf, size_t alen, ares_conn_t *conn, - const ares_timeval_t *now) + const ares_timeval_t *now, + ares_array_t **requeue) { ares_query_t *query; /* Cache these as once ares_send_query() gets called, it may end up @@ -745,7 +804,8 @@ static ares_status_t process_answer(ares_channel_t *channel, /* Validate DNS cookie in response. This function may need to requeue the * query. */ - if (ares_cookie_validate(query, rdnsrec, conn, now) != ARES_SUCCESS) { + if (ares_cookie_validate(query, rdnsrec, conn, now, requeue) + != ARES_SUCCESS) { /* Drop response and return */ status = ARES_SUCCESS; goto cleanup; @@ -768,9 +828,8 @@ static ares_status_t process_answer(ares_channel_t *channel, goto cleanup; } - /* Send to same server */ - ares_send_query(server, query, now); - status = ARES_SUCCESS; + /* Requeue to same server */ + status = ares_append_requeue(requeue, query, server); goto cleanup; } @@ -782,8 +841,9 @@ static ares_status_t process_answer(ares_channel_t *channel, !(conn->flags & ARES_CONN_FLAG_TCP) && !(channel->flags & ARES_FLAG_IGNTC)) { query->using_tcp = ARES_TRUE; - ares_send_query(NULL, query, now); - status = ARES_SUCCESS; /* Switched to TCP is ok */ + status = ares_append_requeue(requeue, query, NULL); + /* Status will reflect success except on memory error, which is good since + * requeuing to TCP is ok */ goto cleanup; } @@ -809,11 +869,13 @@ static ares_status_t process_answer(ares_channel_t *channel, } server_increment_failures(server, query->using_tcp); - ares_requeue_query(query, now, status, ARES_TRUE, rdnsrec); + status = ares_requeue_query(query, now, status, ARES_TRUE, rdnsrec, requeue); - /* Should any of these cause a connection termination? - * Maybe SERVER_FAILURE? */ - status = ARES_SUCCESS; + if (status != ARES_ENOMEM) { + /* Should any of these cause a connection termination? + * Maybe SERVER_FAILURE? */ + status = ARES_SUCCESS; + } goto cleanup; } } @@ -854,10 +916,14 @@ static void handle_conn_error(ares_conn_t *conn, ares_bool_t critical_failure, ares_close_connection(conn, failure_status); } +/* Requeue query will normally call ares_send_query() but in some circumstances + * this needs to be delayed, so if requeue is not NULL, it will add the query + * to the queue instead */ ares_status_t ares_requeue_query(ares_query_t *query, const ares_timeval_t *now, ares_status_t status, ares_bool_t inc_try_count, - const ares_dns_record_t *dnsrec) + const ares_dns_record_t *dnsrec, + ares_array_t **requeue) { ares_channel_t *channel = query->channel; size_t max_tries = ares_slist_len(channel->servers) * channel->tries; @@ -873,6 +939,9 @@ ares_status_t ares_requeue_query(ares_query_t *query, const ares_timeval_t *now, } if (query->try_count < max_tries && !query->no_retries) { + if (requeue != NULL) { + return ares_append_requeue(requeue, query, NULL); + } return ares_send_query(NULL, query, now); } @@ -1187,7 +1256,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server, case ARES_ECONNREFUSED: case ARES_EBADFAMILY: server_increment_failures(server, query->using_tcp); - return ares_requeue_query(query, now, status, ARES_TRUE, NULL); + return ares_requeue_query(query, now, status, ARES_TRUE, NULL, NULL); /* Anything else is not retryable, likely ENOMEM */ default: @@ -1213,7 +1282,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server, case ARES_ECONNREFUSED: case ARES_EBADFAMILY: handle_conn_error(conn, ARES_TRUE, status); - status = ares_requeue_query(query, now, status, ARES_TRUE, NULL); + status = ares_requeue_query(query, now, status, ARES_TRUE, NULL, NULL); if (status == ARES_ETIMEOUT) { status = ARES_ECONNREFUSED; } @@ -1221,7 +1290,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server, default: server_increment_failures(server, query->using_tcp); - status = ares_requeue_query(query, now, status, ARES_TRUE, NULL); + status = ares_requeue_query(query, now, status, ARES_TRUE, NULL, NULL); return status; } diff --git a/contrib/libs/c-ares/src/lib/ares_sysconfig_win.c b/contrib/libs/c-ares/src/lib/ares_sysconfig_win.c index f6e07f92e473..01109a89ba40 100644 --- a/contrib/libs/c-ares/src/lib/ares_sysconfig_win.c +++ b/contrib/libs/c-ares/src/lib/ares_sysconfig_win.c @@ -176,6 +176,7 @@ static int compareAddresses(const void *arg1, const void *arg2) return 0; } +#if defined(HAVE_GETBESTROUTE2) && !defined(__WATCOMC__) /* There can be multiple routes to "the Internet". And there can be different * DNS servers associated with each of the interfaces that offer those routes. * We have to assume that any DNS server can serve any request. But, some DNS @@ -213,18 +214,6 @@ static ULONG getBestRouteMetric(IF_LUID * const luid, /* Can't be const :( */ const SOCKADDR_INET * const dest, const ULONG interfaceMetric) { - /* On this interface, get the best route to that destination. */ -# if defined(__WATCOMC__) - /* OpenWatcom's builtin Windows SDK does not have a definition for - * MIB_IPFORWARD_ROW2, and also does not allow the usage of SOCKADDR_INET - * as a variable. Let's work around this by returning the worst possible - * metric, but only when using the OpenWatcom compiler. - * It may be worth investigating using a different version of the Windows - * SDK with OpenWatcom in the future, though this may be fixed in OpenWatcom - * 2.0. - */ - return (ULONG)-1; -# else MIB_IPFORWARD_ROW2 row; SOCKADDR_INET ignored; if (GetBestRoute2(/* The interface to use. The index is ignored since we are @@ -257,8 +246,8 @@ static ULONG getBestRouteMetric(IF_LUID * const luid, /* Can't be const :( */ * which describes the combination as a "sum". */ return row.Metric + interfaceMetric; -# endif /* __WATCOMC__ */ } +#endif /* * get_DNS_Windows() @@ -379,9 +368,21 @@ static ares_bool_t get_DNS_Windows(char **outptr) addressesSize = newSize; } +# if defined(HAVE_GETBESTROUTE2) && !defined(__WATCOMC__) + /* OpenWatcom's builtin Windows SDK does not have a definition for + * MIB_IPFORWARD_ROW2, and also does not allow the usage of SOCKADDR_INET + * as a variable. Let's work around this by returning the worst possible + * metric, but only when using the OpenWatcom compiler. + * It may be worth investigating using a different version of the Windows + * SDK with OpenWatcom in the future, though this may be fixed in OpenWatcom + * 2.0. + */ addresses[addressesIndex].metric = getBestRouteMetric( &ipaaEntry->Luid, (SOCKADDR_INET *)((void *)(namesrvr.sa)), ipaaEntry->Ipv4Metric); +# else + addresses[addressesIndex].metric = (ULONG)-1; +# endif /* Record insertion index to make qsort stable */ addresses[addressesIndex].orig_idx = addressesIndex; @@ -423,9 +424,13 @@ static ares_bool_t get_DNS_Windows(char **outptr) ll_scope = ipaaEntry->Ipv6IfIndex; } +# if defined(HAVE_GETBESTROUTE2) && !defined(__WATCOMC__) addresses[addressesIndex].metric = getBestRouteMetric( &ipaaEntry->Luid, (SOCKADDR_INET *)((void *)(namesrvr.sa)), ipaaEntry->Ipv6Metric); +# else + addresses[addressesIndex].metric = (ULONG)-1; +# endif /* Record insertion index to make qsort stable */ addresses[addressesIndex].orig_idx = addressesIndex; diff --git a/contrib/libs/c-ares/src/lib/config-win32.h b/contrib/libs/c-ares/src/lib/config-win32.h index 62f8f6f2679e..f3da8e62b8e8 100644 --- a/contrib/libs/c-ares/src/lib/config-win32.h +++ b/contrib/libs/c-ares/src/lib/config-win32.h @@ -243,8 +243,10 @@ # undef HAVE_NETIOAPI_H #endif -/* Threading support enabled */ -#define CARES_THREADS 1 +/* Threading support enabled for Vista+ */ +#if !defined(_WIN32_WINNT) || _WIN32_WINNT >= 0x0600 +# define CARES_THREADS 1 +#endif /* ---------------------------------------------------------------- */ /* TYPEDEF REPLACEMENTS */ @@ -376,6 +378,8 @@ # define HAVE_CONVERTINTERFACELUIDTONAMEA 1 /* Define to 1 if you have the `NotifyIpInterfaceChange' function. */ # define HAVE_NOTIFYIPINTERFACECHANGE 1 +/* Define to 1 if you have the `GetBestRoute2` function */ +# define HAVE_GETBESTROUTE2 1 #endif /* ---------------------------------------------------------------- */ diff --git a/contrib/libs/c-ares/src/lib/event/ares_event.h b/contrib/libs/c-ares/src/lib/event/ares_event.h index 36cd10dcf891..bf298dfb6196 100644 --- a/contrib/libs/c-ares/src/lib/event/ares_event.h +++ b/contrib/libs/c-ares/src/lib/event/ares_event.h @@ -159,30 +159,33 @@ ares_status_t ares_event_update(ares_event_t **event, ares_event_thread_t *e, ares_event_signal_cb_t signal_cb); -#ifdef HAVE_PIPE +#ifdef CARES_THREADS +# ifdef HAVE_PIPE ares_event_t *ares_pipeevent_create(ares_event_thread_t *e); -#endif +# endif -#ifdef HAVE_POLL +# ifdef HAVE_POLL extern const ares_event_sys_t ares_evsys_poll; -#endif +# endif -#ifdef HAVE_KQUEUE +# ifdef HAVE_KQUEUE extern const ares_event_sys_t ares_evsys_kqueue; -#endif +# endif -#ifdef HAVE_EPOLL +# ifdef HAVE_EPOLL extern const ares_event_sys_t ares_evsys_epoll; -#endif +# endif -#ifdef _WIN32 +# ifdef _WIN32 extern const ares_event_sys_t ares_evsys_win32; -#endif +# endif /* All systems have select(), but not all have a way to wake, so we require * pipe() to wake the select() */ -#ifdef HAVE_PIPE +# ifdef HAVE_PIPE extern const ares_event_sys_t ares_evsys_select; +# endif + #endif #endif diff --git a/contrib/libs/c-ares/src/lib/event/ares_event_configchg.c b/contrib/libs/c-ares/src/lib/event/ares_event_configchg.c index 5ecc6888ab71..2a8c780c2ccb 100644 --- a/contrib/libs/c-ares/src/lib/event/ares_event_configchg.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_configchg.c @@ -26,7 +26,7 @@ #include "ares_private.h" #include "ares_event.h" -#ifdef __ANDROID__ +#if defined(__ANDROID__) && defined(CARES_THREADS) ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, ares_event_thread_t *e) @@ -43,7 +43,7 @@ void ares_event_configchg_destroy(ares_event_configchg_t *configchg) (void)configchg; } -#elif defined(__linux__) +#elif defined(__linux__) && defined(CARES_THREADS) # include @@ -174,7 +174,7 @@ ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, return status; } -#elif defined(USE_WINSOCK) +#elif defined(USE_WINSOCK) && defined(CARES_THREADS) # include # include @@ -379,7 +379,7 @@ ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, return status; } -#elif defined(__APPLE__) +#elif defined(__APPLE__) && defined(CARES_THREADS) # include # include @@ -531,7 +531,7 @@ ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, return status; } -#elif defined(HAVE_STAT) && !defined(_WIN32) +#elif defined(HAVE_STAT) && !defined(_WIN32) && defined(CARES_THREADS) # ifdef HAVE_SYS_TYPES_H # include # endif @@ -665,6 +665,12 @@ ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, goto done; } + c->lock = ares_thread_mutex_create(); + if (c->lock == NULL) { + status = ARES_ENOMEM; + goto done; + } + c->resolvconf_path = c->e->channel->resolvconf_path; if (c->resolvconf_path == NULL) { c->resolvconf_path = PATH_RESOLV_CONF; @@ -722,6 +728,8 @@ void ares_event_configchg_destroy(ares_event_configchg_t *configchg) ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, ares_event_thread_t *e) { + (void)configchg; + (void)e; /* No ability */ return ARES_ENOTIMP; } @@ -729,6 +737,7 @@ ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, void ares_event_configchg_destroy(ares_event_configchg_t *configchg) { /* No-op */ + (void)configchg; } #endif diff --git a/contrib/libs/c-ares/src/lib/event/ares_event_epoll.c b/contrib/libs/c-ares/src/lib/event/ares_event_epoll.c index 538c38b4f94a..d451c86a3d57 100644 --- a/contrib/libs/c-ares/src/lib/event/ares_event_epoll.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_epoll.c @@ -26,6 +26,8 @@ #include "ares_private.h" #include "ares_event.h" +#if defined(HAVE_EPOLL) && defined(CARES_THREADS) + #ifdef HAVE_SYS_EPOLL_H # include #endif @@ -33,8 +35,6 @@ # include #endif -#ifdef HAVE_EPOLL - typedef struct { int epoll_fd; } ares_evsys_epoll_t; diff --git a/contrib/libs/c-ares/src/lib/event/ares_event_kqueue.c b/contrib/libs/c-ares/src/lib/event/ares_event_kqueue.c index dbbd0dbd9f76..00cdcbe9c2a9 100644 --- a/contrib/libs/c-ares/src/lib/event/ares_event_kqueue.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_kqueue.c @@ -26,6 +26,8 @@ #include "ares_private.h" #include "ares_event.h" +#if defined(HAVE_KQUEUE) && defined(CARES_THREADS) + #ifdef HAVE_SYS_TYPES_H # include #endif @@ -39,8 +41,6 @@ # include #endif -#ifdef HAVE_KQUEUE - typedef struct { int kqueue_fd; struct kevent *changelist; diff --git a/contrib/libs/c-ares/src/lib/event/ares_event_poll.c b/contrib/libs/c-ares/src/lib/event/ares_event_poll.c index c6ab4b62072b..28e3c0965767 100644 --- a/contrib/libs/c-ares/src/lib/event/ares_event_poll.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_poll.c @@ -25,12 +25,13 @@ */ #include "ares_private.h" #include "ares_event.h" + +#if defined(HAVE_POLL) && defined(CARES_THREADS) + #ifdef HAVE_POLL_H # include #endif -#if defined(HAVE_POLL) - static ares_bool_t ares_evsys_poll_init(ares_event_thread_t *e) { e->ev_signal = ares_pipeevent_create(e); diff --git a/contrib/libs/c-ares/src/lib/event/ares_event_select.c b/contrib/libs/c-ares/src/lib/event/ares_event_select.c index 4d7c085d8720..df758b5a1e51 100644 --- a/contrib/libs/c-ares/src/lib/event/ares_event_select.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_select.c @@ -31,13 +31,14 @@ #include "ares_private.h" #include "ares_event.h" -#ifdef HAVE_SYS_SELECT_H -# include -#endif /* All systems have select(), but not all have a way to wake, so we require * pipe() to wake the select() */ -#if defined(HAVE_PIPE) +#if defined(HAVE_PIPE) && defined(CARES_THREADS) + +#ifdef HAVE_SYS_SELECT_H +# include +#endif static ares_bool_t ares_evsys_select_init(ares_event_thread_t *e) { diff --git a/contrib/libs/c-ares/src/lib/event/ares_event_thread.c b/contrib/libs/c-ares/src/lib/event/ares_event_thread.c index d59b7880a411..c77514e02c18 100644 --- a/contrib/libs/c-ares/src/lib/event/ares_event_thread.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_thread.c @@ -26,6 +26,7 @@ #include "ares_private.h" #include "ares_event.h" +#ifdef CARES_THREADS static void ares_event_destroy_cb(void *arg) { ares_event_t *event = arg; @@ -549,3 +550,18 @@ ares_status_t ares_event_thread_init(ares_channel_t *channel) return ARES_SUCCESS; } + +#else + +ares_status_t ares_event_thread_init(ares_channel_t *channel) +{ + (void)channel; + return ARES_ENOTIMP; +} + +void ares_event_thread_destroy(ares_channel_t *channel) +{ + (void)channel; +} + +#endif diff --git a/contrib/libs/c-ares/src/lib/event/ares_event_wake_pipe.c b/contrib/libs/c-ares/src/lib/event/ares_event_wake_pipe.c index d3b166a3d6cb..cd1534bbbd58 100644 --- a/contrib/libs/c-ares/src/lib/event/ares_event_wake_pipe.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_wake_pipe.c @@ -25,14 +25,16 @@ */ #include "ares_private.h" #include "ares_event.h" -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_FCNTL_H -# include -#endif -#ifdef HAVE_PIPE +#if defined(HAVE_PIPE) && defined(CARES_THREADS) + +# ifdef HAVE_UNISTD_H +# include +# endif +# ifdef HAVE_FCNTL_H +# include +# endif + typedef struct { int filedes[2]; } ares_pipeevent_t; diff --git a/contrib/libs/c-ares/src/lib/event/ares_event_win32.c b/contrib/libs/c-ares/src/lib/event/ares_event_win32.c index 1531b6d81ddc..d7d1d6573508 100644 --- a/contrib/libs/c-ares/src/lib/event/ares_event_win32.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_win32.c @@ -37,12 +37,14 @@ #include "ares_private.h" #include "ares_event.h" #include "ares_event_win32.h" + + +#if defined(USE_WINSOCK) && defined(CARES_THREADS) + #ifdef HAVE_LIMITS_H # include #endif -#if defined(USE_WINSOCK) - /* IMPLEMENTATION NOTES * ==================== * @@ -667,7 +669,7 @@ static ares_bool_t ares_evsys_win32_afd_cancel(ares_evsys_win32_eventdata_t *ed) /* NtCancelIoFileEx() may return STATUS_NOT_FOUND if the operation completed * just before calling NtCancelIoFileEx(), but we have not yet received the - * notifiction (but it should be queued for the next IOCP event). */ + * notification (but it should be queued for the next IOCP event). */ if (status == STATUS_SUCCESS || status == STATUS_NOT_FOUND) { return ARES_TRUE; } diff --git a/contrib/libs/c-ares/src/lib/legacy/ares_parse_a_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_a_reply.c index 870aaccf76c0..9fd4a07ac0fc 100644 --- a/contrib/libs/c-ares/src/lib/legacy/ares_parse_a_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_a_reply.c @@ -77,6 +77,7 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen, } if (host != NULL) { + *host = NULL; status = ares_addrinfo2hostent(&ai, AF_INET, host); if (status != ARES_SUCCESS && status != ARES_ENODATA) { goto fail; /* LCOV_EXCL_LINE: DefensiveCoding */ diff --git a/contrib/libs/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c index 278642f0b3e0..4c177ec9cbbe 100644 --- a/contrib/libs/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c @@ -80,6 +80,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, } if (host != NULL) { + *host = NULL; status = ares_addrinfo2hostent(&ai, AF_INET6, host); if (status != ARES_SUCCESS && status != ARES_ENODATA) { goto fail; /* LCOV_EXCL_LINE: DefensiveCoding */ diff --git a/contrib/libs/c-ares/src/lib/util/ares_iface_ips.c b/contrib/libs/c-ares/src/lib/util/ares_iface_ips.c index 46cb291e300e..c5f507f87e14 100644 --- a/contrib/libs/c-ares/src/lib/util/ares_iface_ips.c +++ b/contrib/libs/c-ares/src/lib/util/ares_iface_ips.c @@ -431,8 +431,14 @@ static ares_status_t ares_iface_ips_enumerate(ares_iface_ips_t *ips, } status = ares_iface_ips_add(ips, addrflag, ifname, &addr, +#if _WIN32_WINNT >= 0x0600 ipaddr->OnLinkPrefixLength /* netmask */, - address->Ipv6IfIndex /* ll_scope */); +#else + ipaddr->Address.lpSockaddr->sa_family + == AF_INET?32:128, +#endif + address->Ipv6IfIndex /* ll_scope */ + ); if (status != ARES_SUCCESS) { goto done; diff --git a/contrib/libs/c-ares/src/lib/util/ares_uri.h b/contrib/libs/c-ares/src/lib/util/ares_uri.h index 6a703cba5b53..2d8138fdc3e3 100644 --- a/contrib/libs/c-ares/src/lib/util/ares_uri.h +++ b/contrib/libs/c-ares/src/lib/util/ares_uri.h @@ -175,7 +175,7 @@ ares_status_t ares_uri_set_query_key(ares_uri_t *uri, const char *key, */ ares_status_t ares_uri_del_query_key(ares_uri_t *uri, const char *key); -/*! Retrieve the value associted with a query key. Keys are case-insensitive. +/*! Retrieve the value associated with a query key. Keys are case-insensitive. * * \param[in] uri Initialized URI object * \param[in] key Key to retrieve. diff --git a/contrib/libs/c-ares/ya.make b/contrib/libs/c-ares/ya.make index a49eb6942f6b..9ead6c9763dd 100644 --- a/contrib/libs/c-ares/ya.make +++ b/contrib/libs/c-ares/ya.make @@ -12,9 +12,9 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(1.34.4) +VERSION(1.34.5) -ORIGINAL_SOURCE(https://github.com/c-ares/c-ares/archive/v1.34.4.tar.gz) +ORIGINAL_SOURCE(https://github.com/c-ares/c-ares/archive/v1.34.5.tar.gz) PEERDIR( contrib/libs/libc_compat diff --git a/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym b/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym index cecee81a03f0..d437597c8d3f 100644 --- a/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym +++ b/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym @@ -1,6 +1,6 @@ {% extends '//builtin/bag.ym' %} -{% block current_version %}20.1.1{% endblock %} +{% block current_version %}20.1.2{% endblock %} {% block current_url %} https://github.com/llvm/llvm-project/releases/download/llvmorg-{{self.version().strip()}}/compiler-rt-{{self.version().strip()}}.src.tar.xz diff --git a/contrib/libs/cxxsupp/builtins/ya.make b/contrib/libs/cxxsupp/builtins/ya.make index 67e47b1a65b8..c6c546c34136 100644 --- a/contrib/libs/cxxsupp/builtins/ya.make +++ b/contrib/libs/cxxsupp/builtins/ya.make @@ -12,9 +12,9 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(20.1.1) +VERSION(20.1.2) -ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.1/compiler-rt-20.1.1.src.tar.xz) +ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.2/compiler-rt-20.1.2.src.tar.xz) NO_COMPILER_WARNINGS() diff --git a/contrib/libs/expat/.yandex_meta/devtools.copyrights.report b/contrib/libs/expat/.yandex_meta/devtools.copyrights.report index 57cb69b65e83..62bd8e460f26 100644 --- a/contrib/libs/expat/.yandex_meta/devtools.copyrights.report +++ b/contrib/libs/expat/.yandex_meta/devtools.copyrights.report @@ -29,18 +29,6 @@ # FILE_INCLUDE - include all file data into licenses text file # ======================= -KEEP COPYRIGHT_SERVICE_LABEL 007454c8100a75981ead0fc679fb038f -BELONGS ya.make - License text: - Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper - Copyright (c) 2001-2022 Expat maintainers - Scancode info: - Original SPDX id: COPYRIGHT_SERVICE_LABEL - Score : 100.00 - Match type : COPYRIGHT - Files with this license: - COPYING [1:2] - KEEP COPYRIGHT_SERVICE_LABEL 05014a3c04ec6fa887b93f5ee617cd76 BELONGS ya.make Note: matched license text is too long. Read it in the source files. @@ -272,7 +260,7 @@ KEEP COPYRIGHT_SERVICE_LABEL 581b53ae6f0fb8a0cc30c73b46bc3441 BELONGS ya.make License text: Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper - Copyright (c) 2001-2022 Expat maintainers + Copyright (c) 2001-2025 Expat maintainers Scancode info: Original SPDX id: COPYRIGHT_SERVICE_LABEL Score : 100.00 @@ -341,6 +329,7 @@ BELONGS ya.make Match type : COPYRIGHT Files with this license: expat.h [9:22] + lib/internal.h [28:36] lib/xmlparse.c [9:44] KEEP COPYRIGHT_SERVICE_LABEL 61052a80fd00eeac5fb41a5ab5fdeff7 @@ -403,6 +392,18 @@ BELONGS ya.make Files with this license: lib/xmltok.c [9:27] +KEEP COPYRIGHT_SERVICE_LABEL 868bf74335c8c4c3a6c576a3120e708c +BELONGS ya.make + License text: + Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper + Copyright (c) 2001-2025 Expat maintainers + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + COPYING [1:2] + KEEP COPYRIGHT_SERVICE_LABEL 8cba36e37749b7d96d8bc8a7b47d0f6f BELONGS ya.make Note: matched license text is too long. Read it in the source files. @@ -802,7 +803,6 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - lib/internal.h [28:36] lib/xmltok.c [9:27] lib/xmltok.h [9:15] diff --git a/contrib/libs/expat/.yandex_meta/devtools.licenses.report b/contrib/libs/expat/.yandex_meta/devtools.licenses.report index f11728285fce..c79ad13859e2 100644 --- a/contrib/libs/expat/.yandex_meta/devtools.licenses.report +++ b/contrib/libs/expat/.yandex_meta/devtools.licenses.report @@ -38,7 +38,7 @@ BELONGS ya.make Match type : NOTICE Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT Files with this license: - README.md [37:41] + README.md [38:42] KEEP MIT 6bb6514a1d779748b76a73215a89ae66 BELONGS ya.make diff --git a/contrib/libs/expat/.yandex_meta/licenses.list.txt b/contrib/libs/expat/.yandex_meta/licenses.list.txt index 34ffa1ea4e50..c7bc6c771231 100644 --- a/contrib/libs/expat/.yandex_meta/licenses.list.txt +++ b/contrib/libs/expat/.yandex_meta/licenses.list.txt @@ -180,7 +180,7 @@ Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein - Copyright (c) 2016-2024 Sebastian Pipping + Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow @@ -190,7 +190,7 @@ ====================COPYRIGHT==================== Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2022 Expat maintainers +Copyright (c) 2001-2025 Expat maintainers ====================File: AUTHORS==================== diff --git a/contrib/libs/expat/.yandex_meta/override.nix b/contrib/libs/expat/.yandex_meta/override.nix index 01e7ca5b3c7b..8ca5ea46b88a 100644 --- a/contrib/libs/expat/.yandex_meta/override.nix +++ b/contrib/libs/expat/.yandex_meta/override.nix @@ -1,12 +1,12 @@ pkgs: attrs: with pkgs; with attrs; rec { - version = "2.7.0"; + version = "2.7.1"; versionTag = "R_${lib.replaceStrings ["."] ["_"] version}"; src = fetchFromGitHub { owner = "libexpat"; repo = "libexpat"; rev = "${versionTag}"; - hash = "sha256-5is+ZwHM+tmKaVzDgO20wCJKJafnwxxRjNMDsv2qnYY="; + hash = "sha256-fAJgHW3KIe5qtQ0ymRiyB8WBt05bMz8b3+JBibCpzQw="; }; nativeBuildInputs = [ autoreconfHook ]; diff --git a/contrib/libs/expat/COPYING b/contrib/libs/expat/COPYING index ce9e5939291e..c6d184a8aae8 100644 --- a/contrib/libs/expat/COPYING +++ b/contrib/libs/expat/COPYING @@ -1,5 +1,5 @@ Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2022 Expat maintainers +Copyright (c) 2001-2025 Expat maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/contrib/libs/expat/Changes b/contrib/libs/expat/Changes index 1f5ba0a02823..9d6c64b6a460 100644 --- a/contrib/libs/expat/Changes +++ b/contrib/libs/expat/Changes @@ -37,6 +37,44 @@ !! THANK YOU! Sebastian Pipping -- Berlin, 2024-03-09 !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Release 2.7.1 Thu March 27 2025 + Bug fixes: + #980 #989 Restore event pointer behavior from Expat 2.6.4 + (that the fix to CVE-2024-8176 changed in 2.7.0); + affected API functions are: + - XML_GetCurrentByteCount + - XML_GetCurrentByteIndex + - XML_GetCurrentColumnNumber + - XML_GetCurrentLineNumber + - XML_GetInputContext + + Other changes: + #976 #977 Autotools: Integrate files "fuzz/xml_lpm_fuzzer.{cpp,proto}" + with Automake that were missing from 2.7.0 release tarballs + #983 #984 Fix printf format specifiers for 32bit Emscripten + #992 docs: Promote OpenSSF Best Practices self-certification + #978 tests/benchmark: Resolve mistaken double close + #986 Address compiler warnings + #990 #993 Version info bumped from 11:1:10 (libexpat*.so.1.10.1) + to 11:2:10 (libexpat*.so.1.10.2); see https://verbump.de/ + for what these numbers do + + Infrastructure: + #982 CI: Start running Perl XML::Parser integration tests + #987 CI: Enforce Clang Static Analyzer clean code + #991 CI: Re-enable warning clang-analyzer-valist.Uninitialized + for clang-tidy + #981 CI: Cover compilation with musl + #983 #984 CI: Cover compilation with 32bit Emscripten + #976 #977 CI: Protect against fuzzer files missing from future + release archives + + Special thanks to: + Berkay Eren Ürün + Matthew Fernandez + and + Perl XML::Parser + Release 2.7.0 Thu March 13 2025 Security fixes: #893 #973 CVE-2024-8176 -- Fix crash from chaining a large number diff --git a/contrib/libs/expat/README.md b/contrib/libs/expat/README.md index 04db8299099c..77c6bf27d307 100644 --- a/contrib/libs/expat/README.md +++ b/contrib/libs/expat/README.md @@ -3,6 +3,7 @@ [![Packaging status](https://repology.org/badge/tiny-repos/expat.svg)](https://repology.org/metapackage/expat/versions) [![Downloads SourceForge](https://img.shields.io/sourceforge/dt/expat?label=Downloads%20SourceForge)](https://sourceforge.net/projects/expat/files/) [![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases) +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/10205/badge)](https://www.bestpractices.dev/projects/10205) > [!CAUTION] > @@ -11,7 +12,7 @@ > at the top of the `Changes` file. -# Expat, Release 2.7.0 +# Expat, Release 2.7.1 This is Expat, a C99 library for parsing [XML 1.0 Fourth Edition](https://www.w3.org/TR/2006/REC-xml-20060816/), started by diff --git a/contrib/libs/expat/expat.h b/contrib/libs/expat/expat.h index 192cfd3f07eb..610e1ddc0e94 100644 --- a/contrib/libs/expat/expat.h +++ b/contrib/libs/expat/expat.h @@ -1068,7 +1068,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled); */ #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 7 -#define XML_MICRO_VERSION 0 +#define XML_MICRO_VERSION 1 #ifdef __cplusplus } diff --git a/contrib/libs/expat/expat_config.h b/contrib/libs/expat/expat_config.h index 4bb2d079bda8..5ccd768606c0 100644 --- a/contrib/libs/expat/expat_config.h +++ b/contrib/libs/expat/expat_config.h @@ -83,7 +83,7 @@ #define PACKAGE_NAME "expat" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "expat 2.7.0" +#define PACKAGE_STRING "expat 2.7.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "expat" @@ -92,7 +92,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "2.7.0" +#define PACKAGE_VERSION "2.7.1" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for @@ -100,7 +100,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "2.7.0" +#define VERSION "2.7.1" /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ diff --git a/contrib/libs/expat/lib/internal.h b/contrib/libs/expat/lib/internal.h index 167ec36804a4..6bde6ae6b31d 100644 --- a/contrib/libs/expat/lib/internal.h +++ b/contrib/libs/expat/lib/internal.h @@ -28,7 +28,7 @@ Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein - Copyright (c) 2016-2024 Sebastian Pipping + Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow @@ -127,6 +127,9 @@ # elif ULONG_MAX == 18446744073709551615u // 2^64-1 # define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld" # define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu" +# elif defined(EMSCRIPTEN) // 32bit mode Emscripten +# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld" +# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "zu" # else # define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d" # define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u" diff --git a/contrib/libs/expat/lib/xmlparse.c b/contrib/libs/expat/lib/xmlparse.c index 1dca1c03970f..803ead9220ba 100644 --- a/contrib/libs/expat/lib/xmlparse.c +++ b/contrib/libs/expat/lib/xmlparse.c @@ -1,4 +1,4 @@ -/* 7d6840a33c250b74adb0ba295d6ec818dccebebaffc8c3ed27d0b29c28adbeb3 (2.7.0+) +/* d19ae032c224863c1527ba44d228cc34b99192c3a4c5a27af1f4e054d45ee031 (2.7.1+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -3402,12 +3402,13 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, break; /* LCOV_EXCL_STOP */ } - *eventPP = s = next; switch (parser->m_parsingStatus.parsing) { case XML_SUSPENDED: + *eventPP = next; *nextPtr = next; return XML_ERROR_NONE; case XML_FINISHED: + *eventPP = next; return XML_ERROR_ABORTED; case XML_PARSING: if (parser->m_reenter) { @@ -3416,6 +3417,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, } /* Fall through */ default:; + *eventPP = s = next; } } /* not reached */ @@ -4332,12 +4334,13 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, /* LCOV_EXCL_STOP */ } - *eventPP = s = next; switch (parser->m_parsingStatus.parsing) { case XML_SUSPENDED: + *eventPP = next; *nextPtr = next; return XML_ERROR_NONE; case XML_FINISHED: + *eventPP = next; return XML_ERROR_ABORTED; case XML_PARSING: if (parser->m_reenter) { @@ -4345,6 +4348,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, } /* Fall through */ default:; + *eventPP = s = next; } } /* not reached */ @@ -5951,12 +5955,13 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end, default: return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; } - parser->m_eventPtr = s = next; switch (parser->m_parsingStatus.parsing) { case XML_SUSPENDED: + parser->m_eventPtr = next; *nextPtr = next; return XML_ERROR_NONE; case XML_FINISHED: + parser->m_eventPtr = next; return XML_ERROR_ABORTED; case XML_PARSING: if (parser->m_reenter) { @@ -5964,6 +5969,7 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end, } /* Fall through */ default:; + parser->m_eventPtr = s = next; } } } @@ -8245,7 +8251,7 @@ entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity, (void *)rootParser, rootParser->m_entity_stats.countEverOpened, rootParser->m_entity_stats.currentDepth, rootParser->m_entity_stats.maximumDepthSeen, - (rootParser->m_entity_stats.currentDepth - 1) * 2, "", + ((int)rootParser->m_entity_stats.currentDepth - 1) * 2, "", entity->is_param ? "%" : "&", entityName, action, entity->textLen, sourceLine); } diff --git a/contrib/libs/expat/ya.make b/contrib/libs/expat/ya.make index b41c7311e2c4..81ab2c6e28e5 100644 --- a/contrib/libs/expat/ya.make +++ b/contrib/libs/expat/ya.make @@ -10,9 +10,9 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(2.7.0) +VERSION(2.7.1) -ORIGINAL_SOURCE(https://github.com/libexpat/libexpat/archive/R_2_7_0.tar.gz) +ORIGINAL_SOURCE(https://github.com/libexpat/libexpat/archive/R_2_7_1.tar.gz) ADDINCL( contrib/libs/expat diff --git a/contrib/libs/libc_compat/ya.make b/contrib/libs/libc_compat/ya.make index 537ecdb9c584..266ffcd5ffcd 100644 --- a/contrib/libs/libc_compat/ya.make +++ b/contrib/libs/libc_compat/ya.make @@ -23,8 +23,8 @@ IF (NOT OS_WINDOWS) ) ENDIF() -DISABLE(PROVIDE_GETRANDOM_GETENTROPY) -DISABLE(PROVIDE_REALLOCARRAY) +DEFAULT(PROVIDE_GETRANDOM_GETENTROPY "no") +DEFAULT(PROVIDE_REALLOCARRAY "no") # Android libc function appearance is documented here: # https://android.googlesource.com/platform/bionic/+/master/docs/status.md @@ -115,7 +115,7 @@ IF (OS_LINUX AND NOT MUSL) explicit_bzero.c ) ENDIF() - IF (OS_SDK != "ubuntu-20" AND OS_SDK != "ubuntu-22") + IF (OS_SDK != "ubuntu-20" AND OS_SDK != "ubuntu-22" AND OS_SDK != "local") # reallocarray was added in glibc=2.29 ENABLE(PROVIDE_REALLOCARRAY) ENDIF() diff --git a/contrib/libs/lzma/.yandex_meta/__init__.py b/contrib/libs/lzma/.yandex_meta/__init__.py index 29e2a09e7e93..3705027de73c 100644 --- a/contrib/libs/lzma/.yandex_meta/__init__.py +++ b/contrib/libs/lzma/.yandex_meta/__init__.py @@ -13,6 +13,7 @@ def post_install(self): flags=["--localedir=/var/empty"], disable_includes=[ "crc32_arm64.h", + "crc32_loongarch.h", "crc32_table_be.h", "crc64_table_be.h", "dpmi.h", diff --git a/contrib/libs/lzma/.yandex_meta/devtools.copyrights.report b/contrib/libs/lzma/.yandex_meta/devtools.copyrights.report index f182796fbda8..4b168d8f34a9 100644 --- a/contrib/libs/lzma/.yandex_meta/devtools.copyrights.report +++ b/contrib/libs/lzma/.yandex_meta/devtools.copyrights.report @@ -55,7 +55,7 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - COPYING [46:46] + COPYING [52:52] KEEP COPYRIGHT_SERVICE_LABEL 8cf91579d8cb4087b6bd775cd2b2bbed BELONGS ya.make diff --git a/contrib/libs/lzma/.yandex_meta/devtools.licenses.report b/contrib/libs/lzma/.yandex_meta/devtools.licenses.report index aed215387039..ac3196e2aa9e 100644 --- a/contrib/libs/lzma/.yandex_meta/devtools.licenses.report +++ b/contrib/libs/lzma/.yandex_meta/devtools.licenses.report @@ -46,24 +46,11 @@ BELONGS ya.make Match type : TAG Links : http://landley.net/toybox/license.html, https://spdx.org/licenses/0BSD Files with this license: - COPYING [43:43] - -SKIP 0BSD 14de854251593dd36ab8a222793a5b8f -BELONGS ya.make - # Not a license - License text: - domain; 0BSD-licensed code is copyrighted but available under - Scancode info: - Original SPDX id: 0BSD - Score : 50.00 - Match type : REFERENCE - Links : http://landley.net/toybox/license.html, https://spdx.org/licenses/0BSD - Files with this license: - COPYING [74:74] + COPYING [49:49] SKIP LGPL-2.1-only 181bd2f3201dc6ff4c508cb04d170817 BELONGS ya.make -FILE_INCLUDE COPYING.LGPLv2.1 found in files: README at line 81 +FILE_INCLUDE COPYING.LGPLv2.1 found in files: README at line 82 # Not a license by itself License text: COPYING.LGPLv2.1 GNU Lesser General Public License version 2.1 @@ -73,20 +60,7 @@ FILE_INCLUDE COPYING.LGPLv2.1 found in files: README at line 81 Match type : REFERENCE Links : http://www.gnu.org/licenses/lgpl-2.1.html, http://www.gnu.org/licenses/lgpl-2.1.txt, https://spdx.org/licenses/LGPL-2.1-only Files with this license: - README [81:81] - -KEEP Public-Domain 19d6afb7fb41001fbab2151dd27a7fb9 -BELONGS ya.make - License text: - There is very little *practical* difference between public - domain and 0BSD. The main difference likely is that one - Scancode info: - Original SPDX id: LicenseRef-scancode-public-domain - Score : 70.00 - Match type : REFERENCE - Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE - Files with this license: - COPYING [71:72] + README [82:82] SKIP 0BSD 1a459a2067895b8576617d7b67fe52ca BELONGS ya.make @@ -112,19 +86,7 @@ BELONGS ya.make Match type : REFERENCE Links : http://landley.net/toybox/license.html, https://spdx.org/licenses/0BSD Files with this license: - COPYING [48:48] - -KEEP 0BSD 21b027dd1b59c23a56e34a32360d0c10 -BELONGS ya.make - License text: - 0BSD for newer releases was made in Febrary 2024 because - Scancode info: - Original SPDX id: 0BSD - Score : 50.00 - Match type : REFERENCE - Links : http://landley.net/toybox/license.html, https://spdx.org/licenses/0BSD - Files with this license: - COPYING [67:67] + COPYING [54:54] SKIP LGPL-2.1-only 23c2a5e0106b99d75238986559bb5fc6 BELONGS ya.make @@ -141,7 +103,7 @@ FILE_INCLUDE COPYING found in files: COPYING.LGPLv2.1 at line 116 SKIP GPL-2.0-only 3220ce24cf5698918173f671259bb375 BELONGS ya.make -FILE_INCLUDE COPYING.GPLv2 found in files: README at line 79 +FILE_INCLUDE COPYING.GPLv2 found in files: README at line 80 # Not a license by itself License text: COPYING.GPLv2 GNU General Public License version 2 @@ -151,7 +113,7 @@ FILE_INCLUDE COPYING.GPLv2 found in files: README at line 79 Match type : REFERENCE Links : http://www.gnu.org/licenses/gpl-2.0.html, http://www.gnu.org/licenses/gpl-2.0.txt, https://spdx.org/licenses/GPL-2.0-only Files with this license: - README [79:79] + README [80:80] KEEP 0BSD 327b128c3f16957fab69efc9b095e368 BELONGS ya.make @@ -221,7 +183,7 @@ BELONGS ya.make Match type : REFERENCE Links : http://landley.net/toybox/license.html, https://spdx.org/licenses/0BSD Files with this license: - COPYING [57:57] + COPYING [63:63] SKIP LGPL-2.0-only AND LGPL-2.1-or-later 493b7c38175021ac13d1589215e13989 BELONGS ya.make @@ -282,18 +244,6 @@ BELONGS ya.make liblzma/api/lzma/vli.h [1:1] liblzma/liblzma_linux.map [1:1] -KEEP Public-Domain 65b77ffe5d577fa84afe9f017beede5c -BELONGS ya.make - License text: - public domain has (real or perceived) legal ambiguities in - Scancode info: - Original SPDX id: LicenseRef-scancode-public-domain - Score : 70.00 - Match type : REFERENCE - Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE - Files with this license: - COPYING [68:68] - SKIP GPL-3.0-only 6dbb0879a53d93955d47d50ed23aa325 BELONGS ya.make # This is a reference to the file with GPL-3.0 license @@ -305,7 +255,7 @@ BELONGS ya.make Match type : REFERENCE Links : http://www.gnu.org/licenses/gpl-3.0-standalone.html, http://www.gnu.org/licenses/gpl-3.0.html, https://spdx.org/licenses/GPL-3.0-only Files with this license: - COPYING [60:60] + COPYING [66:66] KEEP Public-Domain 702cbf9589b30951b6a2b94913b66332 BELONGS ya.make @@ -330,7 +280,7 @@ BELONGS ya.make Match type : REFERENCE Links : http://www.gnu.org/licenses/gpl-2.0.html, http://www.gnu.org/licenses/gpl-2.0.txt, https://spdx.org/licenses/GPL-2.0-only Files with this license: - COPYING [59:59] + COPYING [65:65] KEEP 0BSD 79430bd4c5e1b494780b3fb35b24fd7d BELONGS ya.make @@ -364,37 +314,6 @@ BELONGS ya.make Files with this license: COPYING [25:25] -KEEP 0BSD AND Public-Domain 83aabd12f73b5065603bf2054fb6d54f -BELONGS ya.make - License text: - an extremely permissive license. Neither 0BSD nor public domain - Scancode info: - Original SPDX id: 0BSD - Score : 50.00 - Match type : REFERENCE - Links : http://landley.net/toybox/license.html, https://spdx.org/licenses/0BSD - Files with this license: - COPYING [75:75] - Scancode info: - Original SPDX id: LicenseRef-scancode-public-domain - Score : 70.00 - Match type : REFERENCE - Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE - Files with this license: - COPYING [75:75] - -KEEP Public-Domain 90705824d045bd99f4cb1ef6f42a57ae -BELONGS ya.make - License text: - significant amount of code put into the public domain and - Scancode info: - Original SPDX id: LicenseRef-scancode-public-domain - Score : 100.00 - Match type : TEXT - Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE - Files with this license: - COPYING [65:65] - KEEP BSD-3-Clause AND 0BSD a675dbcfcecb36b880f01b1c31049149 BELONGS ya.make License text: @@ -414,33 +333,9 @@ BELONGS ya.make Files with this license: liblzma/api/lzma.h [23:23] -KEEP Public-Domain a7c077779fe1982e666c1f33e396f1b5 -BELONGS ya.make - License text: - that obviously remains so. The switch from public domain to - Scancode info: - Original SPDX id: LicenseRef-scancode-public-domain - Score : 70.00 - Match type : REFERENCE - Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE - Files with this license: - COPYING [66:66] - -KEEP 0BSD a8a6073ae588092bed4e746ed49b52f5 -BELONGS ya.make - License text: - domain and 0BSD. The main difference likely is that one - Scancode info: - Original SPDX id: 0BSD - Score : 50.00 - Match type : REFERENCE - Links : http://landley.net/toybox/license.html, https://spdx.org/licenses/0BSD - Files with this license: - COPYING [72:72] - SKIP GPL-3.0-only ad3e81fa9e595e378d10023b1bf20d51 BELONGS ya.make -FILE_INCLUDE COPYING.GPLv3 found in files: README at line 80 +FILE_INCLUDE COPYING.GPLv3 found in files: README at line 81 # Not a license by itself License text: COPYING.GPLv3 GNU General Public License version 3 @@ -450,31 +345,7 @@ FILE_INCLUDE COPYING.GPLv3 found in files: README at line 80 Match type : REFERENCE Links : http://www.gnu.org/licenses/gpl-3.0-standalone.html, http://www.gnu.org/licenses/gpl-3.0.html, https://spdx.org/licenses/GPL-3.0-only Files with this license: - README [80:80] - -KEEP BSD-2-Clause b3129c96ef9c28cff49bffaf9d804a88 -BELONGS ya.make - License text: - for example, BSD 2-Clause "Simplified" License which does have - Scancode info: - Original SPDX id: BSD-2-Clause - Score : 100.00 - Match type : NOTICE - Links : http://opensource.org/licenses/bsd-license.php, http://www.opensource.org/licenses/BSD-2-Clause, https://spdx.org/licenses/BSD-2-Clause - Files with this license: - COPYING [78:78] - -KEEP Public-Domain c1a07f044cdb7e843b741e6236100ea3 -BELONGS ya.make - License text: - /// and the public domain code from https://github.com/rawrunprotected/crc - Scancode info: - Original SPDX id: LicenseRef-scancode-public-domain - Score : 100.00 - Match type : NOTICE - Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE - Files with this license: - liblzma/check/crc_x86_clmul.h [13:13] + README [81:81] KEEP Public-Domain cc574f0a684665d6c5ae08f28aec98dd BELONGS ya.make @@ -511,20 +382,7 @@ BELONGS ya.make Match type : REFERENCE Links : http://www.gnu.org/licenses/lgpl-2.1.html, http://www.gnu.org/licenses/lgpl-2.1.txt, https://spdx.org/licenses/LGPL-2.1-only Files with this license: - COPYING [58:58] - -KEEP Public-Domain d2d5f589792b8c7a8679d6c69614d2e9 -BELONGS ya.make - License text: - shouldn't claim that 0BSD-licensed code is in the public - domain; 0BSD-licensed code is copyrighted but available under - Scancode info: - Original SPDX id: LicenseRef-scancode-public-domain - Score : 100.00 - Match type : TEXT - Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE - Files with this license: - COPYING [73:74] + COPYING [64:64] KEEP 0BSD deae85a8d274ed0cce9af4ffbf7f1265 BELONGS ya.make @@ -552,7 +410,7 @@ BELONGS ya.make KEEP 0BSD e5a555c3368d6625b4f901cafe6caf46 BELONGS ya.make -FILE_INCLUDE COPYING.0BSD found in files: README at line 78 +FILE_INCLUDE COPYING.0BSD found in files: README at line 79 License text: COPYING.0BSD BSD Zero Clause License Scancode info: @@ -561,7 +419,7 @@ FILE_INCLUDE COPYING.0BSD found in files: README at line 78 Match type : REFERENCE Links : http://landley.net/toybox/license.html, https://spdx.org/licenses/0BSD Files with this license: - README [78:78] + README [79:79] KEEP 0BSD e7ecdbf411fbdc32d3df058d1c7bf661 BELONGS ya.make @@ -585,10 +443,8 @@ BELONGS ya.make liblzma/check/check.c [1:1] liblzma/check/check.h [1:1] liblzma/check/crc32_fast.c [1:1] - liblzma/check/crc32_table.c [1:1] liblzma/check/crc32_table_le.h [1:1] liblzma/check/crc64_fast.c [1:1] - liblzma/check/crc64_table.c [1:1] liblzma/check/crc64_table_le.h [1:1] liblzma/check/crc_common.h [1:1] liblzma/check/crc_x86_clmul.h [1:1] @@ -706,18 +562,6 @@ BELONGS ya.make liblzma/simple/sparc.c [1:1] liblzma/simple/x86.c [1:1] -KEEP 0BSD f3ff7259b99521ac278b6ea15c6f179f -BELONGS ya.make - License text: - shouldn't claim that 0BSD-licensed code is in the public - Scancode info: - Original SPDX id: 0BSD - Score : 50.00 - Match type : REFERENCE - Links : http://landley.net/toybox/license.html, https://spdx.org/licenses/0BSD - Files with this license: - COPYING [73:73] - KEEP 0BSD f6a343d8de811f538c36fa8681cb7078 BELONGS ya.make License text: diff --git a/contrib/libs/lzma/.yandex_meta/licenses.list.txt b/contrib/libs/lzma/.yandex_meta/licenses.list.txt index e1c02738279d..3120ceffdf18 100644 --- a/contrib/libs/lzma/.yandex_meta/licenses.list.txt +++ b/contrib/libs/lzma/.yandex_meta/licenses.list.txt @@ -1,7 +1,3 @@ -====================0BSD==================== - 0BSD for newer releases was made in Febrary 2024 because - - ====================0BSD==================== and ChangeLog) are under 0BSD unless stated otherwise in @@ -10,14 +6,6 @@ are under 0BSD; they aren't based on the man pages of GNU gzip. -====================0BSD==================== - domain and 0BSD. The main difference likely is that one - - -====================0BSD==================== - shouldn't claim that 0BSD-licensed code is in the public - - ====================0BSD==================== the BSD Zero Clause License (0BSD). @@ -59,14 +47,6 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -====================0BSD AND Public-Domain==================== - an extremely permissive license. Neither 0BSD nor public domain - - -====================BSD-2-Clause==================== - for example, BSD 2-Clause "Simplified" License which does have - - ====================BSD-3-Clause AND 0BSD==================== * liblzma is distributed under the BSD Zero Clause License (0BSD). @@ -116,39 +96,13 @@ NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -====================Public-Domain==================== - There is very little *practical* difference between public - domain and 0BSD. The main difference likely is that one - - ====================Public-Domain==================== lzma-file-format.xt are in the public domain but may -====================Public-Domain==================== - public domain has (real or perceived) legal ambiguities in - - -====================Public-Domain==================== - shouldn't claim that 0BSD-licensed code is in the public - domain; 0BSD-licensed code is copyrighted but available under - - -====================Public-Domain==================== - significant amount of code put into the public domain and - - ====================Public-Domain==================== some old translations are in the public domain. -====================Public-Domain==================== - that obviously remains so. The switch from public domain to - - ====================Public-Domain==================== // The C code is based on the public domain SHA-256 code found from - - -====================Public-Domain==================== -/// and the public domain code from https://github.com/rawrunprotected/crc diff --git a/contrib/libs/lzma/.yandex_meta/override.nix b/contrib/libs/lzma/.yandex_meta/override.nix index 32dfe8f429c9..3acfc4095797 100644 --- a/contrib/libs/lzma/.yandex_meta/override.nix +++ b/contrib/libs/lzma/.yandex_meta/override.nix @@ -1,12 +1,16 @@ pkgs: attrs: with pkgs; with attrs; rec { - version = "5.6.4"; + version = "5.8.1"; src = fetchFromGitHub { owner = "tukaani-project"; repo = "xz"; rev = "v${version}"; - hash = "sha256-Xp1uLtQIoOG/qVLpq5D/KFmTOJ0+mNkNclyuJsvlUbE="; + hash = "sha256-vGUNoX5VTM0aQ5GmBPXip97WGN9vaVrQLE9msToZyKs="; }; nativeBuildInputs = [ autoreconfHook ]; + + configureFlags = [ + "--build=x86_64-pc-linux-gnu" + ]; } diff --git a/contrib/libs/lzma/AUTHORS b/contrib/libs/lzma/AUTHORS index 5eff238ae413..f805a204ecb7 100644 --- a/contrib/libs/lzma/AUTHORS +++ b/contrib/libs/lzma/AUTHORS @@ -24,7 +24,7 @@ Authors of XZ Utils by Michał Górny. Architecture-specific CRC optimizations were contributed by - Ilya Kurdyukov, Hans Jansen, and Chenxi Mao. + Ilya Kurdyukov, Chenxi Mao, and Xi Ruoyao. Other authors: - Jonathan Nieder diff --git a/contrib/libs/lzma/COPYING b/contrib/libs/lzma/COPYING index aed21531497c..ef3371389d7d 100644 --- a/contrib/libs/lzma/COPYING +++ b/contrib/libs/lzma/COPYING @@ -40,6 +40,12 @@ XZ Utils Licensing free software licenses. These aren't built or installed as part of XZ Utils. + The following command may be helpful in finding per-file license + information. It works on xz.git and on a clean file tree extracted + from a release tarball. + + sh build-aux/license-check.sh -v + For the files under the BSD Zero Clause License (0BSD), if a copyright notice is needed, the following is sufficient: @@ -59,25 +65,6 @@ XZ Utils Licensing - COPYING.GPLv2: GNU General Public License version 2 - COPYING.GPLv3: GNU General Public License version 3 - A note about old XZ Utils releases: - - XZ Utils releases 5.4.6 and older and 5.5.1alpha have a - significant amount of code put into the public domain and - that obviously remains so. The switch from public domain to - 0BSD for newer releases was made in Febrary 2024 because - public domain has (real or perceived) legal ambiguities in - some jurisdictions. - - There is very little *practical* difference between public - domain and 0BSD. The main difference likely is that one - shouldn't claim that 0BSD-licensed code is in the public - domain; 0BSD-licensed code is copyrighted but available under - an extremely permissive license. Neither 0BSD nor public domain - require retaining or reproducing author, copyright holder, or - license notices when distributing the software. (Compare to, - for example, BSD 2-Clause "Simplified" License which does have - such requirements.) - If you have questions, don't hesitate to ask for more information. The contact information is in the README file. diff --git a/contrib/libs/lzma/INSTALL b/contrib/libs/lzma/INSTALL index f74228177166..ec8904727465 100644 --- a/contrib/libs/lzma/INSTALL +++ b/contrib/libs/lzma/INSTALL @@ -16,7 +16,7 @@ XZ Utils Installation 1.2.8. DOS 1.2.9. z/OS 1.3. Adding support for new platforms - 2. configure options + 2. configure and CMake options 2.1. Static vs. dynamic linking of liblzma 2.2. Optimizing xzdec and lzmadec 3. xzgrep and other scripts @@ -76,6 +76,11 @@ XZ Utils Installation you use CC=xlc instead, you must disable threading support with --disable-threads (usually not recommended). + If building a 32-bit executable, the address space available to xz + might be limited to 256 MiB by default. To increase the address + space to 2 GiB, pass LDFLAGS=-Wl,-bmaxdata:0x80000000 as an argument + to configure. + 1.2.2. IRIX @@ -213,19 +218,53 @@ XZ Utils Installation in C89 or C++. -2. configure options --------------------- +2. configure and CMake options +------------------------------ In most cases, the defaults are what you want. Many of the options below are useful only when building a size-optimized version of liblzma or command line tools. + configure options are those that begin with two dashes "--" + or "gl_". + + CMake options begin with "XZ_", "TUKLIB_", or "CMAKE_". To use + them on the command line, prefix them with "-D", for example, + "cmake -DCMAKE_COMPILE_WARNING_AS_ERROR=ON". + + CMAKE_BUILD_TYPE=TYPE + CMake only: + + For release builds, CMAKE_BUILD_TYPE=Release is fine. + On targets where CMake defaults to -O3, the default + value is overridden to -O2. + + Empty value (CMAKE_BUILD_TYPE=) is fine if using custom + optimization options. *In this package* the empty build + type also disables debugging code just like "Release" + does. To enable debugging code with empty build type, + use -UNDEBUG in the CFLAGS environment variable or in + the CMAKE_C_FLAGS CMake variable to override -DNDEBUG. + + Non-standard build types like "None" do NOT disable + debugging code! Such non-standard build types should + be avoided for production builds! + --enable-encoders=LIST --disable-encoders - Specify a comma-separated LIST of filter encoders to - build. See "./configure --help" for exact list of - available filter encoders. The default is to build all - supported encoders. + XZ_ENCODERS=LIST + Specify a LIST of filter encoders to build. In the + configure option the list is comma separated. + CMake lists are semicolon separated. + + To see the exact list of available filter encoders: + + - Autotools: ./configure --help + + - CMake: Configure the tree normally first, then use + "cmake -LH ." to list the cache variables. + + The default is to build all supported encoders. If LIST is empty or --disable-encoders is used, no filter encoders will be built and also the code shared between @@ -237,10 +276,12 @@ XZ Utils Installation --enable-decoders=LIST --disable-decoders + XZ_DECODERS=LIST This is like --enable-encoders but for decoders. The default is to build all supported decoders. --enable-match-finders=LIST + XZ_MATCH_FINDERS=LIST liblzma includes two categories of match finders: hash chains and binary trees. Hash chains (hc3 and hc4) are quite fast but they don't provide the best compression @@ -257,9 +298,11 @@ XZ Utils Installation or LZMA2 filter encoders are being built. --enable-checks=LIST + XZ_CHECKS=LIST liblzma support multiple integrity checks. CRC32 is - mandatory, and cannot be omitted. See "./configure --help" - for exact list of available integrity check types. + mandatory, and cannot be omitted. Supported check + types are "crc32", "crc64", and "sha256". By default + all supported check types are enabled. liblzma and the command line tools can decompress files which use unsupported integrity check type, but naturally @@ -270,6 +313,7 @@ XZ Utils Installation it is known to not cause problems. --enable-external-sha256 + XZ_EXTERNAL_SHA256=ON Try to use SHA-256 code from the operating system libc or similar base system libraries. This doesn't try to use OpenSSL or libgcrypt or such libraries. @@ -306,6 +350,8 @@ XZ Utils Installation time xz --test foo.xz --disable-microlzma + XZ_MICROLZMA_ENCODER=OFF + XZ_MICROLZMA_DECODER=OFF Don't build MicroLZMA encoder and decoder. This omits lzma_microlzma_encoder() and lzma_microlzma_decoder() API functions from liblzma. These functions are needed @@ -313,6 +359,7 @@ XZ Utils Installation erofs-utils but they may be used by others too. --disable-lzip-decoder + XZ_LZIP_DECODER=OFF Disable decompression support for .lz (lzip) files. This omits the API function lzma_lzip_decoder() from liblzma and .lz support from the xz tool. @@ -321,6 +368,10 @@ XZ Utils Installation --disable-xzdec --disable-lzmadec --disable-lzmainfo + XZ_TOOL_XZ=OFF + XZ_TOOL_XZDEC=OFF + XZ_TOOL_LZMADEC=OFF + XZ_TOOL_LZMAINFO=OFF Don't build and install the command line tool mentioned in the option name. @@ -330,29 +381,40 @@ XZ Utils Installation a dangling man page symlink lzmadec.1 -> xzdec.1 is created. + XZ_TOOL_SYMLINKS=OFF + Don't create the unxz and xzcat symlinks. (There is + no "configure" option to disable these symlinks.) + --disable-lzma-links + XZ_TOOL_SYMLINKS_LZMA=OFF Don't create symlinks for LZMA Utils compatibility. This includes lzma, unlzma, and lzcat. If scripts are installed, also lzdiff, lzcmp, lzgrep, lzegrep, lzfgrep, lzmore, and lzless will be omitted if this option is used. --disable-scripts + XZ_TOOL_SCRIPTS=OFF Don't install the scripts xzdiff, xzgrep, xzmore, xzless, and their symlinks. --disable-doc + XZ_DOC=OFF Don't install the documentation files to $docdir (often /usr/doc/xz or /usr/local/doc/xz). Man pages will still be installed. The $docdir can be changed with --docdir=DIR. --enable-doxygen + XZ_DOXYGEN=ON Enable generation of the HTML version of the liblzma API documentation using Doxygen. The resulting files are installed to $docdir/api. This option assumes that the 'doxygen' tool is available. + NOTE: --disable-doc or XZ_DOC=OFF don't affect this. + --disable-assembler + XZ_ASM_I386=OFF This disables CRC32 and CRC64 assembly code on 32-bit x86. This option currently does nothing on other architectures (not even on x86-64). @@ -365,7 +427,16 @@ XZ Utils Installation pre-i686 systems, you may want to disable the assembler code. + The assembly code is compatible with only certain OSes + and toolchains (it's not compatible with MSVC). + + Since XZ Utils 5.7.1alpha, the 32-bit x86 assembly code + co-exists with the modern CLMUL code: CLMUL is used if + support for it is detected at runtime. On old processors + the assembly code is used. + --disable-clmul-crc + XZ_CLMUL_CRC=OFF Disable the use of carryless multiplication for CRC calculation even if compiler support for it is detected. The code uses runtime detection of SSSE3, SSE4.1, and @@ -378,6 +449,7 @@ XZ Utils Installation detection isn't used and the generic code is omitted. --disable-arm64-crc32 + XZ_ARM64_CRC32=OFF Disable the use of the ARM64 CRC32 instruction extension even if compiler support for it is detected. The code will detect support for the instruction at runtime. @@ -387,7 +459,16 @@ XZ Utils Installation and later) then runtime detection isn't used and the generic code is omitted. + --disable-loongarch-crc32 + XZ_LOONGARCH_CRC32=OFF + Disable the use of the 64-bit LoongArch CRC32 + instruction extension even if compiler support for + it is detected. There is no runtime detection because + all 64-bit LoongArch processors should support + the CRC32 instructions. + --enable-unaligned-access + TUKLIB_FAST_UNALIGNED_ACCESS=ON Allow liblzma to use unaligned memory access for 16-bit, 32-bit, and 64-bit loads and stores. This should be enabled only when the hardware supports this, that is, @@ -435,6 +516,7 @@ XZ Utils Installation how unaligned access is done in the C code. --enable-unsafe-type-punning + TUKLIB_USE_UNSAFE_TYPE_PUNNING=ON This enables use of code like uint8_t *buf8 = ...; @@ -451,6 +533,7 @@ XZ Utils Installation GCC 3 and early 4.x on x86, GCC < 6 on ARMv6 and ARMv7). --enable-small + XZ_SMALL=ON Reduce the size of liblzma by selecting smaller but semantically equivalent version of some functions, and omit precomputed lookup tables. This option tends to @@ -467,6 +550,7 @@ XZ Utils Installation flag(s) to CFLAGS manually. --enable-assume-ram=SIZE + XZ_ASSUME_RAM=SIZE On the most common operating systems, XZ Utils is able to detect the amount of physical memory on the system. This information is used by the options --memlimit-compress, @@ -483,6 +567,7 @@ XZ Utils Installation src/common/tuklib_physmem.c for details. --enable-threads=METHOD + XZ_THREADS=METHOD Threading support is enabled by default so normally there is no need to specify this option. @@ -519,6 +604,7 @@ XZ Utils Installation one thread, something bad may happen. --enable-sandbox=METHOD + XZ_SANDBOX=METHOD There is limited sandboxing support in the xz and xzdec tools. If built with sandbox support, xz uses it automatically when (de)compressing exactly one file to @@ -554,6 +640,7 @@ XZ Utils Installation is found, configure will give an error. --enable-symbol-versions[=VARIANT] + XZ_SYMBOL_VERSIONING=VARIANT Use symbol versioning for liblzma shared library. This is enabled by default on GNU/Linux (glibc only), other GNU-based systems, and FreeBSD. @@ -598,13 +685,25 @@ XZ Utils Installation run-time consistency checks. It makes the code slower, so you normally don't want to have this enabled. + In CMake, the build type (CMAKE_BUILD_TYPE) controls if + -DNDEBUG is passed to the compiler. *In this package*, + an empty build type disables debugging code too. + Non-standard build types like "None" do NOT disable + debugging code! + + To enable debugging code with empty build type in CMake, + use -UNDEBUG in the CFLAGS environment variable or in + the CMAKE_C_FLAGS CMake variable to override -DNDEBUG. + --enable-werror + CMAKE_COMPILE_WARNING_AS_ERROR=ON (CMake >= 3.24) If building with GCC, make all compiler warnings an error, that abort the compilation. This may help catching bugs, and should work on most systems. This has no effect on the resulting binaries. --enable-path-for-scripts=PREFIX + (CMake determines this from the path of XZ_POSIX_SHELL) If PREFIX isn't empty, PATH=PREFIX:$PATH will be set in the beginning of the scripts (xzgrep and others). The default is empty except on Solaris the default is @@ -621,6 +720,36 @@ XZ Utils Installation the PATH for the scripts. It is described in section 3.2 and is supported in this xz version too. + gl_cv_posix_shell=/path/to/bin/sh + XZ_POSIX_SHELL=/path/to/bin/sh + POSIX shell to use for xzgrep and other scripts. + + - configure should autodetect this well enough. + Typically it's /bin/sh but in some cases, like + Solaris, something else is used. + + - CMake build uses /bin/sh except on Solaris the + default is /usr/xpg4/bin/sh. + + CMAKE_DLL_NAME_WITH_SOVERSION=ON + CMake on native Windows (not Cygwin) only: + + This changes the filename liblzma.dll to liblzma-5.dll. + + The unversioned filename liblzma.dll has been used + since XZ Utils 5.0.0 when creating binary packages + using the included windows/build.bash. The same + unversioned filename is the default with CMake. + However, there are popular builds that, very + understandably and reasonably, use the versioned + filename produced by GNU Libtool. + + This option should usually be left to its default value + (OFF). It can be set to ON if the liblzma DLL filename + must be compatible with the versioned filename + produced by GNU Libtool. For example, binaries + distributed in MSYS2 use a versioned DLL filename. + 2.1. Static vs. dynamic linking of liblzma diff --git a/contrib/libs/lzma/NEWS b/contrib/libs/lzma/NEWS index f260a332f77a..978ef54b915f 100644 --- a/contrib/libs/lzma/NEWS +++ b/contrib/libs/lzma/NEWS @@ -2,6 +2,240 @@ XZ Utils Release Notes ====================== +5.8.1 (2025-04-03) + + IMPORTANT: This includes a security fix for CVE-2025-31115 which + affects XZ Utils from 5.3.3alpha to 5.8.0. No new 5.4.x or 5.6.x + releases will be made, but the fix is in the v5.4 and v5.6 branches + in the xz Git repository. A standalone patch for all affected + versions is available as well. + + * Multithreaded .xz decoder (lzma_stream_decoder_mt()): + + - Fix a bug that could at least result in a crash with + invalid input. (CVE-2025-31115) + + - Fix a performance bug: Only one thread was used if the whole + input file was provided at once to lzma_code(), the output + buffer was big enough, timeout was disabled, and LZMA_FINISH + was used. There are no bug reports about this, thus it's + possible that no real-world application was affected. + + * Avoid even with C11/C17 compilers. This fixes the + build with Oracle Developer Studio 12.6 on Solaris 10 when the + compiler is in C11 mode (the header doesn't exist). + + * Autotools: Restore compatibility with GNU make versions older + than 4.0 by creating the package using GNU gettext 0.23.1 + infrastructure instead of 0.24. + + * Update Croatian translation. + + +5.8.0 (2025-03-25) + + This bumps the minor version of liblzma because new features were + added. The API and ABI are still backward compatible with liblzma + 5.6.x, 5.4.x, 5.2.x, and 5.0.x. + + * liblzma on 32/64-bit x86: When possible, use SSE2 intrinsics + instead of memcpy() in the LZMA/LZMA2 decoder. In typical cases, + this may reduce decompression time by 0-5 %. However, when built + against musl libc, over 15 % time reduction was observed with + highly compressed files. + + * CMake: Make the feature test macros match the Autotools-based + build on NetBSD, Darwin, and mingw-w64. + + * Update the Croatian, Italian, Portuguese, and Romanian + translations. + + * Update the German, Italian, Korean, Romanian, Serbian, and + Ukrainian man page translations. + + Summary of changes in the 5.7.x development releases: + + * Mark the following LZMA Utils script aliases as deprecated: + lzcmp, lzdiff, lzless, lzmore, lzgrep, lzegrep, and lzfgrep. + + * liblzma: + + - Improve LZMA/LZMA2 encoder speed on 64-bit PowerPC (both + endiannesses) and those 64-bit RISC-V processors that + support fast unaligned access. + + - Add low-level APIs for RISC-V, ARM64, and x86 BCJ filters + to lzma/bcj.h. These are primarily for erofs-utils. + + - x86/x86-64/E2K CLMUL CRC code was rewritten. + + - Use the CRC32 instructions on LoongArch. + + * xz: + + - Synchronize the output file and its directory using fsync() + before deleting the input file. No syncing is done when xz + isn't going to delete the input file. + + - Add --no-sync to disable the sync-before-delete behavior. + + - Make --single-stream imply --keep. + + * xz, xzdec, lzmainfo: When printing messages, replace + non-printable characters with question marks. + + * xz and xzdec on Linux: Support Landlock ABI versions 5 and 6. + + * CMake: Revise the configuration variables and some of their + options, and document them in the file INSTALL. CMake support + is no longer experimental. (It was already not experimental + when building for native Windows.) + + * Add build-aux/license-check.sh. + + +5.7.2beta (2025-03-08) + + * On the man pages, mark the following LZMA Utils script aliases as + deprecated: lzcmp, lzdiff, lzless, lzmore, lzgrep, lzegrep, and + lzfgrep. The commands that start with xz* instead of lz* have + identical behavior. + + The LZMA Utils aliases lzma, unlzma, and lzcat aren't deprecated + because some of these aliases are still in common use. lzmadec + and lzmainfo aren't deprecated either. + + * xz: In the ENVIRONMENT section of the man page, warn about + problems that some uses of XZ_DEFAULTS and XZ_OPT may create. + + * Windows (native builds, not Cygwin): In xz, xzdec, and lzmadec, + avoid an error message on broken pipe. + + * Autotools: Fix out-of-tree builds when using the bundled + getopt_long. + + * Translations: + + - Updated: Chinese (traditional), Croatian, Finnish, Georgian, + German, Korean, Polish, Romanian, Serbian, Spanish, Swedish, + Turkish, and Ukrainian + + - Added: Dutch + + * Man page translations: + + - Updated: German, Korean, Romanian, and Ukrainian + + - Added: Italian and Serbian + + +5.7.1alpha (2025-01-23) + + * All fixes from 5.6.4. + + * liblzma: + + - Improve LZMA/LZMA2 encoder speed on 64-bit PowerPC (both + endiannesses) and those 64-bit RISC-V processors that + support fast unaligned access. + + - x86/x86-64/E2K CLMUL CRC code was rewritten. It's faster and + doesn't cause false positives from sanitizers. Attributes + like __attribute__((__no_sanitize_address__)) are no longer + present. + + - On 32-bit x86, CLMUL CRC and the old (but still good) + assembly versions now co-exist with runtime detection. + Both Autotools and CMake build systems handle this + automatically now. + + - Use the CRC32 instructions on LoongArch to make CRC32 + calculation faster. + + - Add low-level APIs for RISC-V, ARM64, and x86 BCJ filters + to lzma/bcj.h. These are primarily for erofs-utils. + + - Minor tweaks to ARM64 CRC32 code and BCJ filters were made. + + * xz: + + - Synchronize the output file and its directory before deleting + the input file using fsync(). This reduces the probability of + data loss after a system crash. However, it can be a major + performance hit if processing many small files. + + NOTE: No syncing is done when xz isn't going to delete + the input file. + + - Add a new option --no-sync to disable the sync-before-delete + behavior. It's useful when compressing many small files and + one doesn't worry about data loss in case of a system crash. + + - Make --single-stream imply --keep. + + - Use automatic word wrapping for the text in --help and + similar situations to hopefully make the strings easier for + majority of translators (no need to count spaces anymore). + + * xz, xzdec, lzmainfo: When printing messages, replace + non-printable characters with question marks. This way + malicious filenames cannot be used to send escape sequences + to a terminal. This change is also applied to filenames shown + in "xz --robot --list". + + * xz and xzdec on Linux: Add support for Landlock ABI versions 5 + and 6. + + * CMake updates: + + - Increase the minimum required CMake version to 3.20. + + - Revise the configuration variables and some of their options. + Document them in the file INSTALL. + + - Attempt to produce liblzma.pc so that the paths are based on + ${prefix}, which makes it simpler to override the paths + if the liblzma files have been moved. + + - To enable translations, gettext-tools is now required. The + CMake build no longer supports installing pre-compiled + message catalog binary files (po/*.gmo). + + - Apple: Use Mach-O shared library versioning that is + compatible with GNU Libtool. This should make it easier to + switch between the build systems on Apple OSes that enforce + the correct compatibility_version (macOS >= 12 doesn't?). + This change is backward compatible: binaries linked against + old CMake-built liblzma will run with liblzma that uses + Libtool style versioning. + + - Windows (not Cygwin): Document CMAKE_DLL_NAME_WITH_SOVERSION + (CMake >= 3.27) in the file INSTALL. This option should + usually be left to its default value (OFF). It can be set + to ON if the liblzma DLL filename must be compatible with + the versioned filename produced by GNU Libtool. For example, + binaries distributed in MSYS2 use a versioned DLL filename. + + - CMake support is no longer experimental. (It was already + not experimental when building for native Windows.) + + * Windows: Building liblzma with Visual Studio 2013 is no longer + supported. Visual Studio 2015 or later (with CMake) can be used + to build liblzma and the command line tools. + + * Add preliminary Georgian translation. This already contains + translations of most of the strings that are now automatically + word wrapped. + + * Add build-aux/license-check.sh. Without arguments, it checks that + no license information has been forgotten. With the -v argument, + it shows the license info (or the lack of it) for each file. + + If the .git directory is available, only the files in the + repository are checked. Without the .git directory, a clean tree + from an extracted release tarball is expected. + + 5.6.4 (2025-01-23) * liblzma: Fix LZMA/LZMA2 encoder on big endian ARM64. diff --git a/contrib/libs/lzma/README b/contrib/libs/lzma/README index 9d097deff371..41671676a516 100644 --- a/contrib/libs/lzma/README +++ b/contrib/libs/lzma/README @@ -10,6 +10,7 @@ XZ Utils 2. Version numbering 3. Reporting bugs 4. Translations + 4.1. Testing translations 5. Other implementations of the .xz format 6. Contact information @@ -203,77 +204,47 @@ XZ Utils https://translationproject.org/html/translators.html - Below are notes and testing instructions specific to xz - translations. + Updates to translations won't be accepted by methods that bypass + the Translation Project because there is a risk of duplicate work: + translation updates made in the xz repository aren't seen by the + translators in the Translation Project. If you have found bugs in + a translation, please report them to the Language-Team address + which can be found near the beginning of the PO file. - Testing can be done by installing xz into a temporary directory: + If you find language problems in the original English strings, + feel free to suggest improvements. Ask if something is unclear. + + +4.1. Testing translations + + Testing can be done by installing xz into a temporary directory. + + If building from Git repository (not tarball), generate the + Autotools files: + + ./autogen.sh + + Create a subdirectory for the build files. The tmp-build directory + can be deleted after testing. + + mkdir tmp-build + cd tmp-build + ../configure --disable-shared --enable-debug --prefix=$PWD/inst + + Edit the .po file in the po directory. Then build and install to + the "tmp-build/inst" directory, and use translations.bash to see + how some of the messages look. Repeat these steps if needed: - ./configure --disable-shared --prefix=/tmp/xz-test - # make -C po update-po - make install - bash debug/translation.bash | less - bash debug/translation.bash | less -S # For --list outputs - - Repeat the above as needed (no need to re-run configure though). - - Note especially the following: - - - The output of --help and --long-help must look nice on - an 80-column terminal. It's OK to add extra lines if needed. - - - In contrast, don't add extra lines to error messages and such. - They are often preceded with e.g. a filename on the same line, - so you have no way to predict where to put a \n. Let the terminal - do the wrapping even if it looks ugly. Adding new lines will be - even uglier in the generic case even if it looks nice in a few - limited examples. - - - Be careful with column alignment in tables and table-like output - (--list, --list --verbose --verbose, --info-memory, --help, and - --long-help): - - * All descriptions of options in --help should start in the - same column (but it doesn't need to be the same column as - in the English messages; just be consistent if you change it). - Check that both --help and --long-help look OK, since they - share several strings. - - * --list --verbose and --info-memory print lines that have - the format "Description: %s". If you need a longer - description, you can put extra space between the colon - and %s. Then you may need to add extra space to other - strings too so that the result as a whole looks good (all - values start at the same column). - - * The columns of the actual tables in --list --verbose --verbose - should be aligned properly. Abbreviate if necessary. It might - be good to keep at least 2 or 3 spaces between column headings - and avoid spaces in the headings so that the columns stand out - better, but this is a matter of opinion. Do what you think - looks best. - - - Be careful to put a period at the end of a sentence when the - original version has it, and don't put it when the original - doesn't have it. Similarly, be careful with \n characters - at the beginning and end of the strings. - - - Read the TRANSLATORS comments that have been extracted from the - source code and included in xz.pot. Some comments suggest - testing with a specific command which needs an .xz file. You - may use e.g. any tests/files/good-*.xz. However, these test - commands are included in translations.bash output, so reading - translations.bash output carefully can be enough. - - - If you find language problems in the original English strings, - feel free to suggest improvements. Ask if something is unclear. - - - The translated messages should be understandable (sometimes this - may be a problem with the original English messages too). Don't - make a direct word-by-word translation from English especially if - the result doesn't sound good in your language. - - Thanks for your help! + make -j"$(nproc)" install + bash ../debug/translation.bash | less + bash ../debug/translation.bash | less -S # For --list outputs + + To test other languages, set the LANGUAGE environment variable + before running translations.bash. The value should match the PO file + name without the .po suffix. Example: + + export LANGUAGE=fi 5. Other implementations of the .xz format diff --git a/contrib/libs/lzma/THANKS b/contrib/libs/lzma/THANKS index 3326e9712e0c..a6a7a6721079 100644 --- a/contrib/libs/lzma/THANKS +++ b/contrib/libs/lzma/THANKS @@ -20,6 +20,7 @@ has been important. :-) In alphabetical order: - Jakub Bogusz - Adam Borowski - Maarten Bosmans + - Roel Bouckaert - Lukas Braune - Benjamin Buch - Trent W. Buck @@ -29,13 +30,18 @@ has been important. :-) In alphabetical order: - Frank Busse - Daniel Mealha Cabrita - Milo Casagrande + - Cristiano Ceglia - Marek Černocký - Tomer Chachamu - Vitaly Chikunov - Antoine Cœur + - Elijah Almeida Coimbra - Felix Collin + - Ryan Colyer - Marcus Comstedt + - Vincent Cruz - Gabi Davar + - Ron Desmond - İhsan Doğan - Chris Donawa - Andrew Dudman @@ -48,9 +54,11 @@ has been important. :-) In alphabetical order: - Denis Excoffier - Vincent Fazio - Michael Felt + - Sean Fenian - Michael Fox - Andres Freund - Mike Frysinger + - Collin Funk - Daniel Richard G. - Tomasz Gajc - Bjarni Ingi Gislason @@ -59,10 +67,14 @@ has been important. :-) In alphabetical order: - Matthew Good - Michał Górny - Jason Gorski + - Alexander M. Greenham - Juan Manuel Guerrero - Gabriela Gutierrez - Diederik de Haas + - Jan Terje Hansen + - Tobias Lahrmann Hansen - Joachim Henke + - Lizandro Heredia - Christian Hesse - Vincenzo Innocente - Peter Ivanov @@ -78,9 +90,11 @@ has been important. :-) In alphabetical order: - Per Øyvind Karlsen - Firas Khalil Khana - Iouri Kharon + - Kim Jinyeong - Thomas Klausner - Richard Koch - Anton Kochkov + - Harri K. Koskinen - Ville Koskinen - Sergey Kosukhin - Marcin Kowalczyk @@ -105,14 +119,20 @@ has been important. :-) In alphabetical order: - Chenxi Mao - Gregory Margo - Julien Marrec + - Pierre-Yves Martin - Ed Maste - Martin Matuška + - Scott McAllister + - Chris McCrohan + - Derwin McGeary - Ivan A. Melnikov - Jim Meyering - Arkadiusz Miskiewicz - Nathan Moinvaziri - Étienne Mollier - Conley Moorhous + - Dirk Müller + - Rainer Müller - Andrew Murray - Rafał Mużyło - Adrien Nader @@ -122,6 +142,7 @@ has been important. :-) In alphabetical order: - Jonathan Nieder - Asgeir Storesund Nilsen - Andre Noll + - Ruarí Ødegaard - Peter O'Gorman - Dimitri Papadopoulos Orfanos - Daniel Packard @@ -133,17 +154,20 @@ has been important. :-) In alphabetical order: - Igor Pavlov - Diego Elio Pettenò - Elbert Pol + - Guiorgy Potskhishvili - Mikko Pouru - Frank Prochnow - Rich Prohaska - Trần Ngọc Quân - Pavel Raiskup + - Matthieu Rakotojaona - Ole André Vadla Ravnås - Eric S. Raymond - Robert Readman - Bernhard Reutner-Fischer - Markus Rickert - Cristian Rodríguez + - Jeroen Roovers - Christian von Roques - Boud Roukema - Torsten Rupp @@ -160,6 +184,7 @@ has been important. :-) In alphabetical order: - Dan Shechter - Stuart Shelton - Sebastian Andrzej Siewior + - Andrej Skenderija - Ville Skyttä - Brad Smith - Bruce Stark @@ -191,15 +216,22 @@ has been important. :-) In alphabetical order: - Ralf Wildenhues - Charles Wilson - Lars Wirzenius + - Vincent Wixsom - Pilorz Wojciech - Chien Wong + - Xi Ruoyao - Ryan Young - Andreas Zieringer + - 榆柳松 (ZhengSen Wang) Companies: - Google - Sandfly Security +Other credits: + - cleemy desu wayo working with Trend Micro Zero Day Initiative + - Orange Tsai and splitline from DEVCORE Research Team + Also thanks to all the people who have participated in the Tukaani project. I have probably forgot to add some names to the above list. Sorry about diff --git a/contrib/libs/lzma/TODO b/contrib/libs/lzma/TODO index ad37f3f559aa..7a0bf16ed86e 100644 --- a/contrib/libs/lzma/TODO +++ b/contrib/libs/lzma/TODO @@ -5,12 +5,7 @@ XZ Utils To-Do List Known bugs ---------- - The test suite is too incomplete. - - If the memory usage limit is less than about 13 MiB, xz is unable to - automatically scale down the compression settings enough even though - it would be possible by switching from BT2/BT3/BT4 match finder to - HC3/HC4. + The test suite is incomplete. XZ Utils compress some files significantly worse than LZMA Utils. This is due to faster compression presets used by XZ Utils, and @@ -19,9 +14,6 @@ Known bugs compress extremely well, so going from compression ratio of 0.003 to 0.004 means big relative increase in the compressed file size. - xz doesn't quote unprintable characters when it displays file names - given on the command line. - tuklib_exit() doesn't block signals => EINTR is possible. If liblzma has created threads and fork() gets called, liblzma @@ -41,9 +33,6 @@ Missing features be mostly useful when using a preset dictionary in LZMA2, but it may have other uses too. Compare to deflateCopy() in zlib. - Support LZMA_FINISH in raw decoder to indicate end of LZMA1 and - other streams that don't have an end of payload marker. - Adjust dictionary size when the input file size is known. Maybe do this only if an option is given. @@ -67,9 +56,9 @@ Missing features Support LZMA_FULL_FLUSH for lzma_stream_decoder() to stop at Block and Stream boundaries. - lzma_strerror() to convert lzma_ret to human readable form? - This is tricky, because the same error codes are used with - slightly different meanings, and this cannot be fixed anymore. + Error codes from lzma_code() aren't very specific. A more detailed + error message (string) could be provided too. It could be returned + by a new function or use a currently-reserved member of lzma_stream. Make it possible to adjust LZMA2 options in the middle of a Block so that the encoding speed vs. compression ratio can be optimized @@ -97,9 +86,3 @@ Documentation Document the LZMA1 and LZMA2 algorithms. - -Miscellaneous ------------- - - Try to get the media type for .xz registered at IANA. - diff --git a/contrib/libs/lzma/common/sysdefs.h b/contrib/libs/lzma/common/sysdefs.h index 1c2405dcd837..b10ffa7c3b18 100644 --- a/contrib/libs/lzma/common/sysdefs.h +++ b/contrib/libs/lzma/common/sysdefs.h @@ -168,17 +168,26 @@ typedef unsigned char _Bool; # define __bool_true_false_are_defined 1 #endif +// We may need alignas from C11/C17/C23. +#if __STDC_VERSION__ >= 202311 + // alignas is a keyword in C23. Do nothing. +#elif __STDC_VERSION__ >= 201112 + // Oracle Developer Studio 12.6 lacks . + // For simplicity, avoid the header with all C11/C17 compilers. +# define alignas _Alignas +#elif defined(__GNUC__) || defined(__clang__) +# define alignas(n) __attribute__((__aligned__(n))) +#else +# define alignas(n) +#endif + #include -// Visual Studio 2013 update 2 supports only __inline, not inline. -// MSVC v19.0 / VS 2015 and newer support both. +// MSVC v19.00 (VS 2015 version 14.0) and later should work. // // MSVC v19.27 (VS 2019 version 16.7) added support for restrict. // Older ones support only __restrict. #ifdef _MSC_VER -# if _MSC_VER < 1900 && !defined(inline) -# define inline __inline -# endif # if _MSC_VER < 1927 && !defined(restrict) # define restrict __restrict # endif @@ -208,4 +217,13 @@ typedef unsigned char _Bool; # define lzma_attr_alloc_size(x) #endif +#if __STDC_VERSION__ >= 202311 +# define FALLTHROUGH [[__fallthrough__]] +#elif (defined(__GNUC__) && __GNUC__ >= 7) \ + || (defined(__clang_major__) && __clang_major__ >= 10) +# define FALLTHROUGH __attribute__((__fallthrough__)) +#else +# define FALLTHROUGH ((void)0) +#endif + #endif diff --git a/contrib/libs/lzma/common/tuklib_common.h b/contrib/libs/lzma/common/tuklib_common.h index 7554dfc86fb6..d73f07255e4d 100644 --- a/contrib/libs/lzma/common/tuklib_common.h +++ b/contrib/libs/lzma/common/tuklib_common.h @@ -56,6 +56,13 @@ # define TUKLIB_GNUC_REQ(major, minor) 0 #endif +#if defined(__GNUC__) || defined(__clang__) +# define tuklib_attr_format_printf(fmt_index, args_index) \ + __attribute__((__format__(__printf__, fmt_index, args_index))) +#else +# define tuklib_attr_format_printf(fmt_index, args_index) +#endif + // tuklib_attr_noreturn attribute is used to mark functions as non-returning. // We cannot use "noreturn" as the macro name because then C23 code that // uses [[noreturn]] would break as it would expand to [[ [[noreturn]] ]]. @@ -68,9 +75,7 @@ // __attribute__((nonnull(1))) // extern void foo(const char *s); // -// FIXME: Update __STDC_VERSION__ for the final C23 version. 202000 is used -// by GCC 13 and Clang 15 with -std=c2x. -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000 +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311 # define tuklib_attr_noreturn [[noreturn]] #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 # define tuklib_attr_noreturn _Noreturn diff --git a/contrib/libs/lzma/common/tuklib_physmem.c b/contrib/libs/lzma/common/tuklib_physmem.c index 0a4fcb3871ae..2b686d865885 100644 --- a/contrib/libs/lzma/common/tuklib_physmem.c +++ b/contrib/libs/lzma/common/tuklib_physmem.c @@ -91,18 +91,11 @@ tuklib_physmem(void) // supports reporting values greater than 4 GiB. To keep the // code working also on older Windows versions, use // GlobalMemoryStatusEx() conditionally. - HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll")); + HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); if (kernel32 != NULL) { typedef BOOL (WINAPI *gmse_type)(LPMEMORYSTATUSEX); -#ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-function-type" -#endif gmse_type gmse = (gmse_type)GetProcAddress( kernel32, "GlobalMemoryStatusEx"); -#ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE -# pragma GCC diagnostic pop -#endif if (gmse != NULL) { MEMORYSTATUSEX meminfo; meminfo.dwLength = sizeof(meminfo); @@ -155,7 +148,7 @@ tuklib_physmem(void) ret += entries[i].end - entries[i].start + 1; #elif defined(TUKLIB_PHYSMEM_AIX) - ret = _system_configuration.physmem; + ret = (uint64_t)_system_configuration.physmem; #elif defined(TUKLIB_PHYSMEM_SYSCONF) const long pagesize = sysconf(_SC_PAGESIZE); diff --git a/contrib/libs/lzma/liblzma/api/lzma/bcj.h b/contrib/libs/lzma/liblzma/api/lzma/bcj.h index 7f6611feb325..fb737cbba49c 100644 --- a/contrib/libs/lzma/liblzma/api/lzma/bcj.h +++ b/contrib/libs/lzma/liblzma/api/lzma/bcj.h @@ -96,3 +96,100 @@ typedef struct { uint32_t start_offset; } lzma_options_bcj; + + +/** + * \brief Raw ARM64 BCJ encoder + * + * This is for special use cases only. + * + * \param start_offset The lowest 32 bits of the offset in the + * executable being filtered. For the ARM64 + * filter, this must be a multiple of four. + * For the very best results, this should also + * be in sync with 4096-byte page boundaries + * in the executable due to how ARM64's ADRP + * instruction works. + * \param buf Buffer to be filtered in place + * \param size Size of the buffer + * + * \return Number of bytes that were processed in `buf`. This is at most + * `size`. With the ARM64 filter, the return value is always + * a multiple of 4, and at most 3 bytes are left unfiltered. + * + * \since 5.7.1alpha + */ +extern LZMA_API(size_t) lzma_bcj_arm64_encode( + uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow; + +/** + * \brief Raw ARM64 BCJ decoder + * + * See lzma_bcj_arm64_encode(). + * + * \since 5.7.1alpha + */ +extern LZMA_API(size_t) lzma_bcj_arm64_decode( + uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow; + + +/** + * \brief Raw RISC-V BCJ encoder + * + * This is for special use cases only. + * + * \param start_offset The lowest 32 bits of the offset in the + * executable being filtered. For the RISC-V + * filter, this must be a multiple of 2. + * \param buf Buffer to be filtered in place + * \param size Size of the buffer + * + * \return Number of bytes that were processed in `buf`. This is at most + * `size`. With the RISC-V filter, the return value is always + * a multiple of 2, and at most 7 bytes are left unfiltered. + * + * \since 5.7.1alpha + */ +extern LZMA_API(size_t) lzma_bcj_riscv_encode( + uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow; + +/** + * \brief Raw RISC-V BCJ decoder + * + * See lzma_bcj_riscv_encode(). + * + * \since 5.7.1alpha + */ +extern LZMA_API(size_t) lzma_bcj_riscv_decode( + uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow; + + +/** + * \brief Raw x86 BCJ encoder + * + * This is for special use cases only. + * + * \param start_offset The lowest 32 bits of the offset in the + * executable being filtered. For the x86 + * filter, all values are valid. + * \param buf Buffer to be filtered in place + * \param size Size of the buffer + * + * \return Number of bytes that were processed in `buf`. This is at most + * `size`. For the x86 filter, the return value is always + * a multiple of 1, and at most 4 bytes are left unfiltered. + * + * \since 5.7.1alpha + */ +extern LZMA_API(size_t) lzma_bcj_x86_encode( + uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow; + +/** + * \brief Raw x86 BCJ decoder + * + * See lzma_bcj_x86_encode(). + * + * \since 5.7.1alpha + */ +extern LZMA_API(size_t) lzma_bcj_x86_decode( + uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow; diff --git a/contrib/libs/lzma/liblzma/api/lzma/container.h b/contrib/libs/lzma/liblzma/api/lzma/container.h index ee5d77e4f1af..dbd414cbf8c0 100644 --- a/contrib/libs/lzma/liblzma/api/lzma/container.h +++ b/contrib/libs/lzma/liblzma/api/lzma/container.h @@ -573,7 +573,7 @@ extern LZMA_API(lzma_ret) lzma_stream_buffer_encode( * The action argument must be LZMA_FINISH and the return value will never be * LZMA_OK. Thus the encoding is always done with a single lzma_code() after * the initialization. The benefit of the combination of initialization - * function and lzma_code() is that memory allocations can be re-used for + * function and lzma_code() is that memory allocations can be reused for * better performance. * * lzma_code() will try to encode as much input as is possible to fit into diff --git a/contrib/libs/lzma/liblzma/api/lzma/version.h b/contrib/libs/lzma/liblzma/api/lzma/version.h index 86c8b199f55b..86b355635961 100644 --- a/contrib/libs/lzma/liblzma/api/lzma/version.h +++ b/contrib/libs/lzma/liblzma/api/lzma/version.h @@ -19,10 +19,10 @@ #define LZMA_VERSION_MAJOR 5 /** \brief Minor version number of the liblzma release. */ -#define LZMA_VERSION_MINOR 6 +#define LZMA_VERSION_MINOR 8 /** \brief Patch version number of the liblzma release. */ -#define LZMA_VERSION_PATCH 4 +#define LZMA_VERSION_PATCH 1 /** * \brief Version stability marker diff --git a/contrib/libs/lzma/liblzma/check/check.h b/contrib/libs/lzma/liblzma/check/check.h index 08627e783a6c..724246570c68 100644 --- a/contrib/libs/lzma/liblzma/check/check.h +++ b/contrib/libs/lzma/liblzma/check/check.h @@ -95,24 +95,6 @@ typedef struct { } lzma_check_state; -/// lzma_crc32_table[0] is needed by LZ encoder so we need to keep -/// the array two-dimensional. -#ifdef HAVE_SMALL -lzma_attr_visibility_hidden -extern uint32_t lzma_crc32_table[1][256]; - -extern void lzma_crc32_init(void); - -#else - -lzma_attr_visibility_hidden -extern const uint32_t lzma_crc32_table[8][256]; - -lzma_attr_visibility_hidden -extern const uint64_t lzma_crc64_table[4][256]; -#endif - - /// \brief Initialize *check depending on type extern void lzma_check_init(lzma_check_state *check, lzma_check type); diff --git a/contrib/libs/lzma/liblzma/check/crc32_fast.c b/contrib/libs/lzma/liblzma/check/crc32_fast.c index fce1af6119b1..caaa4710afda 100644 --- a/contrib/libs/lzma/liblzma/check/crc32_fast.c +++ b/contrib/libs/lzma/liblzma/check/crc32_fast.c @@ -7,7 +7,6 @@ // // Authors: Lasse Collin // Ilya Kurdyukov -// Hans Jansen // /////////////////////////////////////////////////////////////////////////////// @@ -15,10 +14,12 @@ #include "crc_common.h" #if defined(CRC_X86_CLMUL) -# define BUILDING_CRC32_CLMUL +# define BUILDING_CRC_CLMUL 32 # include "crc_x86_clmul.h" #elif defined(CRC32_ARM64) # error #include "crc32_arm64.h" +#elif defined(CRC32_LOONGARCH) +# error #include "crc32_loongarch.h" #endif @@ -28,8 +29,19 @@ // Generic CRC32 // /////////////////// +#ifdef WORDS_BIGENDIAN +# error #include "crc32_table_be.h" +#else +# include "crc32_table_le.h" +#endif + + +#ifdef HAVE_CRC_X86_ASM +extern uint32_t lzma_crc32_generic( + const uint8_t *buf, size_t size, uint32_t crc); +#else static uint32_t -crc32_generic(const uint8_t *buf, size_t size, uint32_t crc) +lzma_crc32_generic(const uint8_t *buf, size_t size, uint32_t crc) { crc = ~crc; @@ -85,7 +97,8 @@ crc32_generic(const uint8_t *buf, size_t size, uint32_t crc) return ~crc; } -#endif +#endif // HAVE_CRC_X86_ASM +#endif // CRC32_GENERIC #if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED) @@ -119,7 +132,7 @@ static crc32_func_type crc32_resolve(void) { return is_arch_extension_supported() - ? &crc32_arch_optimized : &crc32_generic; + ? &crc32_arch_optimized : &lzma_crc32_generic; } @@ -164,27 +177,6 @@ extern LZMA_API(uint32_t) lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc) { #if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED) - // On x86-64, if CLMUL is available, it is the best for non-tiny - // inputs, being over twice as fast as the generic slice-by-four - // version. However, for size <= 16 it's different. In the extreme - // case of size == 1 the generic version can be five times faster. - // At size >= 8 the CLMUL starts to become reasonable. It - // varies depending on the alignment of buf too. - // - // The above doesn't include the overhead of mythread_once(). - // At least on x86-64 GNU/Linux, pthread_once() is very fast but - // it still makes lzma_crc32(buf, 1, crc) 50-100 % slower. When - // size reaches 12-16 bytes the overhead becomes negligible. - // - // So using the generic version for size <= 16 may give better - // performance with tiny inputs but if such inputs happen rarely - // it's not so obvious because then the lookup table of the - // generic version may not be in the processor cache. -#ifdef CRC_USE_GENERIC_FOR_SMALL_INPUTS - if (size <= 16) - return crc32_generic(buf, size, crc); -#endif - /* #ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR // See crc32_dispatch(). This would be the alternative which uses @@ -199,6 +191,6 @@ lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc) return crc32_arch_optimized(buf, size, crc); #else - return crc32_generic(buf, size, crc); + return lzma_crc32_generic(buf, size, crc); #endif } diff --git a/contrib/libs/lzma/liblzma/check/crc32_table.c b/contrib/libs/lzma/liblzma/check/crc32_table.c deleted file mode 100644 index db8d9d583129..000000000000 --- a/contrib/libs/lzma/liblzma/check/crc32_table.c +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: 0BSD - -/////////////////////////////////////////////////////////////////////////////// -// -/// \file crc32_table.c -/// \brief Precalculated CRC32 table with correct endianness -// -// Author: Lasse Collin -// -/////////////////////////////////////////////////////////////////////////////// - -#include "common.h" - - -// FIXME: Compared to crc_common.h this has to check for __x86_64__ too -// so that in 32-bit builds crc32_x86.S won't break due to a missing table. -#if defined(HAVE_USABLE_CLMUL) && ((defined(__x86_64__) && defined(__SSSE3__) \ - && defined(__SSE4_1__) && defined(__PCLMUL__)) \ - || (defined(__e2k__) && __iset__ >= 6)) -# define NO_CRC32_TABLE - -#elif defined(HAVE_ARM64_CRC32) \ - && !defined(WORDS_BIGENDIAN) \ - && defined(__ARM_FEATURE_CRC32) -# define NO_CRC32_TABLE -#endif - - -#if !defined(HAVE_ENCODERS) && defined(NO_CRC32_TABLE) -// No table needed. Use a typedef to avoid an empty translation unit. -typedef void lzma_crc32_dummy; - -#else -// Having the declaration here silences clang -Wmissing-variable-declarations. -extern const uint32_t lzma_crc32_table[8][256]; - -# ifdef WORDS_BIGENDIAN -# error #include "crc32_table_be.h" -# else -# include "crc32_table_le.h" -# endif -#endif diff --git a/contrib/libs/lzma/liblzma/check/crc64_fast.c b/contrib/libs/lzma/liblzma/check/crc64_fast.c index 0ce83fe4ad36..2c767bdcfde8 100644 --- a/contrib/libs/lzma/liblzma/check/crc64_fast.c +++ b/contrib/libs/lzma/liblzma/check/crc64_fast.c @@ -14,7 +14,7 @@ #include "crc_common.h" #if defined(CRC_X86_CLMUL) -# define BUILDING_CRC64_CLMUL +# define BUILDING_CRC_CLMUL 64 # include "crc_x86_clmul.h" #endif @@ -25,6 +25,18 @@ // Generic slice-by-four CRC64 // ///////////////////////////////// +#if defined(WORDS_BIGENDIAN) +# error #include "crc64_table_be.h" +#else +# include "crc64_table_le.h" +#endif + + +#ifdef HAVE_CRC_X86_ASM +extern uint64_t lzma_crc64_generic( + const uint8_t *buf, size_t size, uint64_t crc); +#else + #ifdef WORDS_BIGENDIAN # define A1(x) ((x) >> 56) #else @@ -34,7 +46,7 @@ // See the comments in crc32_fast.c. They aren't duplicated here. static uint64_t -crc64_generic(const uint8_t *buf, size_t size, uint64_t crc) +lzma_crc64_generic(const uint8_t *buf, size_t size, uint64_t crc) { crc = ~crc; @@ -78,7 +90,8 @@ crc64_generic(const uint8_t *buf, size_t size, uint64_t crc) return ~crc; } -#endif +#endif // HAVE_CRC_X86_ASM +#endif // CRC64_GENERIC #if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED) @@ -97,7 +110,7 @@ static crc64_func_type crc64_resolve(void) { return is_arch_extension_supported() - ? &crc64_arch_optimized : &crc64_generic; + ? &crc64_arch_optimized : &lzma_crc64_generic; } #ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR @@ -133,24 +146,24 @@ crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc) extern LZMA_API(uint64_t) lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc) { -#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED) - -#ifdef CRC_USE_GENERIC_FOR_SMALL_INPUTS - if (size <= 16) - return crc64_generic(buf, size, crc); +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \ + && defined(_M_IX86) && defined(CRC64_ARCH_OPTIMIZED) + // VS2015-2022 might corrupt the ebx register on 32-bit x86 when + // the CLMUL code is enabled. This hack forces MSVC to store and + // restore ebx. This is only needed here, not in lzma_crc32(). + __asm mov ebx, ebx #endif + +#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED) return crc64_func(buf, size, crc); #elif defined(CRC64_ARCH_OPTIMIZED) // If arch-optimized version is used unconditionally without runtime // CPU detection then omitting the generic version and its 8 KiB // lookup table makes the library smaller. - // - // FIXME: Lookup table isn't currently omitted on 32-bit x86, - // see crc64_table.c. return crc64_arch_optimized(buf, size, crc); #else - return crc64_generic(buf, size, crc); + return lzma_crc64_generic(buf, size, crc); #endif } diff --git a/contrib/libs/lzma/liblzma/check/crc64_table.c b/contrib/libs/lzma/liblzma/check/crc64_table.c deleted file mode 100644 index e7ceb0276fa8..000000000000 --- a/contrib/libs/lzma/liblzma/check/crc64_table.c +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: 0BSD - -/////////////////////////////////////////////////////////////////////////////// -// -/// \file crc64_table.c -/// \brief Precalculated CRC64 table with correct endianness -// -// Author: Lasse Collin -// -/////////////////////////////////////////////////////////////////////////////// - -#include "common.h" - - -// FIXME: Compared to crc_common.h this has to check for __x86_64__ too -// so that in 32-bit builds crc64_x86.S won't break due to a missing table. -#if defined(HAVE_USABLE_CLMUL) && ((defined(__x86_64__) && defined(__SSSE3__) \ - && defined(__SSE4_1__) && defined(__PCLMUL__)) \ - || (defined(__e2k__) && __iset__ >= 6)) -# define NO_CRC64_TABLE -#endif - - -#ifdef NO_CRC64_TABLE -// No table needed. Use a typedef to avoid an empty translation unit. -typedef void lzma_crc64_dummy; - -#else -// Having the declaration here silences clang -Wmissing-variable-declarations. -extern const uint64_t lzma_crc64_table[4][256]; - -# if defined(WORDS_BIGENDIAN) -# error #include "crc64_table_be.h" -# else -# include "crc64_table_le.h" -# endif -#endif diff --git a/contrib/libs/lzma/liblzma/check/crc_common.h b/contrib/libs/lzma/liblzma/check/crc_common.h index c15d4c675c8f..7ea1e60b043b 100644 --- a/contrib/libs/lzma/liblzma/check/crc_common.h +++ b/contrib/libs/lzma/liblzma/check/crc_common.h @@ -3,11 +3,10 @@ /////////////////////////////////////////////////////////////////////////////// // /// \file crc_common.h -/// \brief Some functions and macros for CRC32 and CRC64 +/// \brief Macros and declarations for CRC32 and CRC64 // // Authors: Lasse Collin // Ilya Kurdyukov -// Hans Jansen // Jia Tan // /////////////////////////////////////////////////////////////////////////////// @@ -18,6 +17,10 @@ #include "common.h" +///////////// +// Generic // +///////////// + #ifdef WORDS_BIGENDIAN # define A(x) ((x) >> 24) # define B(x) (((x) >> 16) & 0xFF) @@ -38,43 +41,63 @@ #endif -// CRC CLMUL code needs this because accessing input buffers that aren't -// aligned to the vector size will inherently trip the address sanitizer. -#if lzma_has_attribute(__no_sanitize_address__) -# define crc_attr_no_sanitize_address \ - __attribute__((__no_sanitize_address__)) +/// lzma_crc32_table[0] is needed by LZ encoder so we need to keep +/// the array two-dimensional. +#ifdef HAVE_SMALL +lzma_attr_visibility_hidden +extern uint32_t lzma_crc32_table[1][256]; + +extern void lzma_crc32_init(void); + #else -# define crc_attr_no_sanitize_address -#endif -// Keep this in sync with changes to crc32_arm64.h -#if defined(_WIN32) || defined(HAVE_GETAUXVAL) \ - || defined(HAVE_ELF_AUX_INFO) \ - || (defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME)) -# define ARM64_RUNTIME_DETECTION 1 +lzma_attr_visibility_hidden +extern const uint32_t lzma_crc32_table[8][256]; + +lzma_attr_visibility_hidden +extern const uint64_t lzma_crc64_table[4][256]; #endif +/////////////////// +// Configuration // +/////////////////// + +// NOTE: This config isn't used if HAVE_SMALL is defined! + +// These are defined if the generic slicing-by-n implementations and their +// lookup tables are built. #undef CRC32_GENERIC #undef CRC64_GENERIC +// These are defined if an arch-specific version is built. If both this +// and matching _GENERIC is defined then runtime detection must be used. #undef CRC32_ARCH_OPTIMIZED #undef CRC64_ARCH_OPTIMIZED // The x86 CLMUL is used for both CRC32 and CRC64. #undef CRC_X86_CLMUL +// Many ARM64 processor have CRC32 instructions. +// CRC64 could be done with CLMUL but it's not implemented yet. #undef CRC32_ARM64 -#undef CRC64_ARM64_CLMUL -#undef CRC_USE_GENERIC_FOR_SMALL_INPUTS +// 64-bit LoongArch has CRC32 instructions. +#undef CRC32_LOONGARCH + + +// ARM64 +// +// Keep this in sync with changes to crc32_arm64.h +#if defined(_WIN32) || defined(HAVE_GETAUXVAL) \ + || defined(HAVE_ELF_AUX_INFO) \ + || (defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME)) +# define CRC_ARM64_RUNTIME_DETECTION 1 +#endif // ARM64 CRC32 instruction is only useful for CRC32. Currently, only // little endian is supported since we were unable to test on a big // endian machine. -// -// NOTE: Keep this and the next check in sync with the macro -// NO_CRC32_TABLE in crc32_table.c #if defined(HAVE_ARM64_CRC32) && !defined(WORDS_BIGENDIAN) // Allow ARM64 CRC32 instruction without a runtime check if // __ARM_FEATURE_CRC32 is defined. GCC and Clang only define @@ -82,21 +105,40 @@ # if defined(__ARM_FEATURE_CRC32) # define CRC32_ARCH_OPTIMIZED 1 # define CRC32_ARM64 1 -# elif defined(ARM64_RUNTIME_DETECTION) +# elif defined(CRC_ARM64_RUNTIME_DETECTION) # define CRC32_ARCH_OPTIMIZED 1 # define CRC32_ARM64 1 # define CRC32_GENERIC 1 # endif #endif -#if defined(HAVE_USABLE_CLMUL) -// If CLMUL is allowed unconditionally in the compiler options then the -// generic version can be omitted. Note that this doesn't work with MSVC -// as I don't know how to detect the features here. + +// LoongArch // -// NOTE: Keep this in sync with the NO_CRC32_TABLE macro in crc32_table.c -// and NO_CRC64_TABLE in crc64_table.c. -# if (defined(__SSSE3__) && defined(__SSE4_1__) && defined(__PCLMUL__)) \ +// Only 64-bit LoongArch is supported for now. No runtime detection +// is needed because the LoongArch specification says that the CRC32 +// instructions are a part of the Basic Integer Instructions and +// they shall be implemented by 64-bit LoongArch implementations. +#ifdef HAVE_LOONGARCH_CRC32 +# define CRC32_ARCH_OPTIMIZED 1 +# define CRC32_LOONGARCH 1 +#endif + + +// x86 and E2K +#if defined(HAVE_USABLE_CLMUL) + // If CLMUL is allowed unconditionally in the compiler options then + // the generic version and the tables can be omitted. Exceptions: + // + // - If 32-bit x86 assembly files are enabled then those are always + // built and runtime detection is used even if compiler flags + // were set to allow CLMUL unconditionally. + // + // - This doesn't work with MSVC as I don't know how to detect + // the features here. + // +# if (defined(__SSSE3__) && defined(__SSE4_1__) && defined(__PCLMUL__) \ + && !defined(HAVE_CRC_X86_ASM)) \ || (defined(__e2k__) && __iset__ >= 6) # define CRC32_ARCH_OPTIMIZED 1 # define CRC64_ARCH_OPTIMIZED 1 @@ -107,21 +149,12 @@ # define CRC32_ARCH_OPTIMIZED 1 # define CRC64_ARCH_OPTIMIZED 1 # define CRC_X86_CLMUL 1 - -/* - // The generic code is much faster with 1-8-byte inputs and - // has similar performance up to 16 bytes at least in - // microbenchmarks (it depends on input buffer alignment - // too). If both versions are built, this #define will use - // the generic version for inputs up to 16 bytes and CLMUL - // for bigger inputs. It saves a little in code size since - // the special cases for 0-16-byte inputs will be omitted - // from the CLMUL code. -# define CRC_USE_GENERIC_FOR_SMALL_INPUTS 1 -*/ # endif #endif + +// Fallback configuration +// // For CRC32 use the generic slice-by-eight implementation if no optimized // version is available. #if !defined(CRC32_ARCH_OPTIMIZED) && !defined(CRC32_GENERIC) diff --git a/contrib/libs/lzma/liblzma/check/crc_x86_clmul.h b/contrib/libs/lzma/liblzma/check/crc_x86_clmul.h index 50306e49a72a..b302d6cf7f51 100644 --- a/contrib/libs/lzma/liblzma/check/crc_x86_clmul.h +++ b/contrib/libs/lzma/liblzma/check/crc_x86_clmul.h @@ -8,26 +8,20 @@ /// The CRC32 and CRC64 implementations use 32/64-bit x86 SSSE3, SSE4.1, and /// CLMUL instructions. This is compatible with Elbrus 2000 (E2K) too. /// -/// They were derived from +/// See the Intel white paper "Fast CRC Computation for Generic Polynomials +/// Using PCLMULQDQ Instruction" from 2009. The original file seems to be +/// gone from Intel's website but a version is available here: /// https://www.researchgate.net/publication/263424619_Fast_CRC_computation -/// and the public domain code from https://github.com/rawrunprotected/crc -/// (URLs were checked on 2023-10-14). +/// (The link was checked on 2024-06-11.) /// /// While this file has both CRC32 and CRC64 implementations, only one -/// should be built at a time to ensure that crc_simd_body() is inlined -/// even with compilers with which lzma_always_inline expands to plain inline. -/// The version to build is selected by defining BUILDING_CRC32_CLMUL or -/// BUILDING_CRC64_CLMUL before including this file. +/// can be built at a time. The version to build is selected by defining +/// BUILDING_CRC_CLMUL to 32 or 64 before including this file. /// -/// FIXME: Builds for 32-bit x86 use the assembly .S files by default -/// unless configured with --disable-assembler. Even then the lookup table -/// isn't omitted in crc64_table.c since it doesn't know that assembly -/// code has been disabled. +/// NOTE: The x86 CLMUL CRC implementation was rewritten for XZ Utils 5.8.0. // -// Authors: Ilya Kurdyukov -// Hans Jansen -// Lasse Collin -// Jia Tan +// Authors: Lasse Collin +// Ilya Kurdyukov // /////////////////////////////////////////////////////////////////////////////// @@ -37,6 +31,10 @@ #endif #define LZMA_CRC_X86_CLMUL_H +#if BUILDING_CRC_CLMUL != 32 && BUILDING_CRC_CLMUL != 64 +# error BUILDING_CRC_CLMUL is undefined or has an invalid value +#endif + #include #if defined(_MSC_VER) @@ -59,330 +57,277 @@ #endif -#define MASK_L(in, mask, r) r = _mm_shuffle_epi8(in, mask) +// GCC and Clang would produce good code with _mm_set_epi64x +// but MSVC needs _mm_cvtsi64_si128 on x86-64. +#if defined(__i386__) || defined(_M_IX86) +# define my_set_low64(a) _mm_set_epi64x(0, (a)) +#else +# define my_set_low64(a) _mm_cvtsi64_si128(a) +#endif -#define MASK_H(in, mask, r) \ - r = _mm_shuffle_epi8(in, _mm_xor_si128(mask, vsign)) -#define MASK_LH(in, mask, low, high) \ - MASK_L(in, mask, low); \ - MASK_H(in, mask, high) +// Align it so that the whole array is within the same cache line. +// More than one unaligned load can be done from this during the +// same CRC function call. +// +// The bytes [0] to [31] are used with AND to clear the low bytes. (With ANDN +// those could be used to clear the high bytes too but it's not needed here.) +// +// The bytes [16] to [47] are for left shifts. +// The bytes [32] to [63] are for right shifts. +alignas(64) +static uint8_t vmasks[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + + +// *Unaligned* 128-bit load +crc_attr_target +static inline __m128i +my_load128(const uint8_t *p) +{ + return _mm_loadu_si128((const __m128i *)p); +} +// Keep the highest "count" bytes as is and clear the remaining low bytes. crc_attr_target -crc_attr_no_sanitize_address -static lzma_always_inline void -crc_simd_body(const uint8_t *buf, const size_t size, __m128i *v0, __m128i *v1, - const __m128i vfold16, const __m128i initial_crc) +static inline __m128i +keep_high_bytes(__m128i v, size_t count) { - // Create a vector with 8-bit values 0 to 15. This is used to - // construct control masks for _mm_blendv_epi8 and _mm_shuffle_epi8. - const __m128i vramp = _mm_setr_epi32( - 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c); - - // This is used to inverse the control mask of _mm_shuffle_epi8 - // so that bytes that wouldn't be picked with the original mask - // will be picked and vice versa. - const __m128i vsign = _mm_set1_epi8(-0x80); + return _mm_and_si128(my_load128((vmasks + count)), v); +} - // Memory addresses A to D and the distances between them: - // - // A B C D - // [skip_start][size][skip_end] - // [ size2 ] - // - // A and D are 16-byte aligned. B and C are 1-byte aligned. - // skip_start and skip_end are 0-15 bytes. size is at least 1 byte. - // - // A = aligned_buf will initially point to this address. - // B = The address pointed by the caller-supplied buf. - // C = buf + size == aligned_buf + size2 - // D = buf + size + skip_end == aligned_buf + size2 + skip_end - const size_t skip_start = (size_t)((uintptr_t)buf & 15); - const size_t skip_end = (size_t)((0U - (uintptr_t)(buf + size)) & 15); - const __m128i *aligned_buf = (const __m128i *)( - (uintptr_t)buf & ~(uintptr_t)15); - - // If size2 <= 16 then the whole input fits into a single 16-byte - // vector. If size2 > 16 then at least two 16-byte vectors must - // be processed. If size2 > 16 && size <= 16 then there is only - // one 16-byte vector's worth of input but it is unaligned in memory. - // - // NOTE: There is no integer overflow here if the arguments - // are valid. If this overflowed, buf + size would too. - const size_t size2 = skip_start + size; - - // Masks to be used with _mm_blendv_epi8 and _mm_shuffle_epi8: - // The first skip_start or skip_end bytes in the vectors will have - // the high bit (0x80) set. _mm_blendv_epi8 and _mm_shuffle_epi8 - // will produce zeros for these positions. (Bitwise-xor of these - // masks with vsign will produce the opposite behavior.) - const __m128i mask_start - = _mm_sub_epi8(vramp, _mm_set1_epi8((char)skip_start)); - const __m128i mask_end - = _mm_sub_epi8(vramp, _mm_set1_epi8((char)skip_end)); - - // Get the first 1-16 bytes into data0. If loading less than 16 - // bytes, the bytes are loaded to the high bits of the vector and - // the least significant positions are filled with zeros. - const __m128i data0 = _mm_blendv_epi8(_mm_load_si128(aligned_buf), - _mm_setzero_si128(), mask_start); - aligned_buf++; - - __m128i v2, v3; - -#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS - if (size <= 16) { - // Right-shift initial_crc by 1-16 bytes based on "size" - // and store the result in v1 (high bytes) and v0 (low bytes). - // - // NOTE: The highest 8 bytes of initial_crc are zeros so - // v1 will be filled with zeros if size >= 8. The highest - // 8 bytes of v1 will always become zeros. - // - // [ v1 ][ v0 ] - // [ initial_crc ] size == 1 - // [ initial_crc ] size == 2 - // [ initial_crc ] size == 15 - // [ initial_crc ] size == 16 (all in v0) - const __m128i mask_low = _mm_add_epi8( - vramp, _mm_set1_epi8((char)(size - 16))); - MASK_LH(initial_crc, mask_low, *v0, *v1); - - if (size2 <= 16) { - // There are 1-16 bytes of input and it is all - // in data0. Copy the input bytes to v3. If there - // are fewer than 16 bytes, the low bytes in v3 - // will be filled with zeros. That is, the input - // bytes are stored to the same position as - // (part of) initial_crc is in v0. - MASK_L(data0, mask_end, v3); - } else { - // There are 2-16 bytes of input but not all bytes - // are in data0. - const __m128i data1 = _mm_load_si128(aligned_buf); - - // Collect the 2-16 input bytes from data0 and data1 - // to v2 and v3, and bitwise-xor them with the - // low bits of initial_crc in v0. Note that the - // the second xor is below this else-block as it - // is shared with the other branch. - MASK_H(data0, mask_end, v2); - MASK_L(data1, mask_end, v3); - *v0 = _mm_xor_si128(*v0, v2); - } - *v0 = _mm_xor_si128(*v0, v3); - *v1 = _mm_alignr_epi8(*v1, *v0, 8); - } else -#endif - { - // There is more than 16 bytes of input. - const __m128i data1 = _mm_load_si128(aligned_buf); - const __m128i *end = (const __m128i*)( - (const char *)aligned_buf - 16 + size2); - aligned_buf++; - - MASK_LH(initial_crc, mask_start, *v0, *v1); - *v0 = _mm_xor_si128(*v0, data0); - *v1 = _mm_xor_si128(*v1, data1); - - while (aligned_buf < end) { - *v1 = _mm_xor_si128(*v1, _mm_clmulepi64_si128( - *v0, vfold16, 0x00)); - *v0 = _mm_xor_si128(*v1, _mm_clmulepi64_si128( - *v0, vfold16, 0x11)); - *v1 = _mm_load_si128(aligned_buf++); - } +// Shift the 128-bit value left by "amount" bytes (not bits). +crc_attr_target +static inline __m128i +shift_left(__m128i v, size_t amount) +{ + return _mm_shuffle_epi8(v, my_load128((vmasks + 32 - amount))); +} - if (aligned_buf != end) { - MASK_H(*v0, mask_end, v2); - MASK_L(*v0, mask_end, *v0); - MASK_L(*v1, mask_end, v3); - *v1 = _mm_or_si128(v2, v3); - } - *v1 = _mm_xor_si128(*v1, _mm_clmulepi64_si128( - *v0, vfold16, 0x00)); - *v0 = _mm_xor_si128(*v1, _mm_clmulepi64_si128( - *v0, vfold16, 0x11)); - *v1 = _mm_srli_si128(*v0, 8); - } +// Shift the 128-bit value right by "amount" bytes (not bits). +crc_attr_target +static inline __m128i +shift_right(__m128i v, size_t amount) +{ + return _mm_shuffle_epi8(v, my_load128((vmasks + 32 + amount))); } -///////////////////// -// x86 CLMUL CRC32 // -///////////////////// - -/* -// These functions were used to generate the constants -// at the top of crc32_arch_optimized(). -static uint64_t -calc_lo(uint64_t p, uint64_t a, int n) +crc_attr_target +static inline __m128i +fold(__m128i v, __m128i k) { - uint64_t b = 0; int i; - for (i = 0; i < n; i++) { - b = b >> 1 | (a & 1) << (n - 1); - a = (a >> 1) ^ ((0 - (a & 1)) & p); - } - return b; + __m128i a = _mm_clmulepi64_si128(v, k, 0x00); + __m128i b = _mm_clmulepi64_si128(v, k, 0x11); + return _mm_xor_si128(a, b); } -// same as ~crc(&a, sizeof(a), ~0) -static uint64_t -calc_hi(uint64_t p, uint64_t a, int n) + +crc_attr_target +static inline __m128i +fold_xor(__m128i v, __m128i k, const uint8_t *buf) { - int i; - for (i = 0; i < n; i++) - a = (a >> 1) ^ ((0 - (a & 1)) & p); - return a; + return _mm_xor_si128(my_load128(buf), fold(v, k)); } -*/ -#ifdef BUILDING_CRC32_CLMUL +#if BUILDING_CRC_CLMUL == 32 crc_attr_target -crc_attr_no_sanitize_address static uint32_t crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc) +#else +crc_attr_target +static uint64_t +crc64_arch_optimized(const uint8_t *buf, size_t size, uint64_t crc) +#endif { -#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS - // The code assumes that there is at least one byte of input. + // We will assume that there is at least one byte of input. if (size == 0) return crc; -#endif - // uint32_t poly = 0xedb88320; - const int64_t p = 0x1db710640; // p << 1 - const int64_t mu = 0x1f7011641; // calc_lo(p, p, 32) << 1 | 1 - const int64_t k5 = 0x163cd6124; // calc_hi(p, p, 32) << 1 - const int64_t k4 = 0x0ccaa009e; // calc_hi(p, p, 64) << 1 - const int64_t k3 = 0x1751997d0; // calc_hi(p, p, 128) << 1 - - const __m128i vfold4 = _mm_set_epi64x(mu, p); - const __m128i vfold8 = _mm_set_epi64x(0, k5); - const __m128i vfold16 = _mm_set_epi64x(k4, k3); - - __m128i v0, v1, v2; - - crc_simd_body(buf, size, &v0, &v1, vfold16, - _mm_cvtsi32_si128((int32_t)~crc)); - - v1 = _mm_xor_si128( - _mm_clmulepi64_si128(v0, vfold16, 0x10), v1); // xxx0 - v2 = _mm_shuffle_epi32(v1, 0xe7); // 0xx0 - v0 = _mm_slli_epi64(v1, 32); // [0] - v0 = _mm_clmulepi64_si128(v0, vfold8, 0x00); - v0 = _mm_xor_si128(v0, v2); // [1] [2] - v2 = _mm_clmulepi64_si128(v0, vfold4, 0x10); - v2 = _mm_clmulepi64_si128(v2, vfold4, 0x00); - v0 = _mm_xor_si128(v0, v2); // [2] - return ~(uint32_t)_mm_extract_epi32(v0, 2); -} -#endif // BUILDING_CRC32_CLMUL + // See crc_clmul_consts_gen.c. +#if BUILDING_CRC_CLMUL == 32 + const __m128i fold512 = _mm_set_epi64x(0x1d9513d7, 0x8f352d95); + const __m128i fold128 = _mm_set_epi64x(0xccaa009e, 0xae689191); + const __m128i mu_p = _mm_set_epi64x( + (int64_t)0xb4e5b025f7011641, 0x1db710640); +#else + const __m128i fold512 = _mm_set_epi64x( + (int64_t)0x081f6054a7842df4, (int64_t)0x6ae3efbb9dd441f3); + const __m128i fold128 = _mm_set_epi64x( + (int64_t)0xdabe95afc7875f40, (int64_t)0xe05dd497ca393ae4); -///////////////////// -// x86 CLMUL CRC64 // -///////////////////// + const __m128i mu_p = _mm_set_epi64x( + (int64_t)0x9c3e466c172963d5, (int64_t)0x92d8af2baf0e1e84); +#endif -/* -// These functions were used to generate the constants -// at the top of crc64_arch_optimized(). -static uint64_t -calc_lo(uint64_t poly) -{ - uint64_t a = poly; - uint64_t b = 0; + __m128i v0, v1, v2, v3; - for (unsigned i = 0; i < 64; ++i) { - b = (b >> 1) | (a << 63); - a = (a >> 1) ^ (a & 1 ? poly : 0); - } + crc = ~crc; - return b; -} + if (size < 8) { + uint64_t x = crc; + size_t i = 0; -static uint64_t -calc_hi(uint64_t poly, uint64_t a) -{ - for (unsigned i = 0; i < 64; ++i) - a = (a >> 1) ^ (a & 1 ? poly : 0); + // Checking the bit instead of comparing the size means + // that we don't need to update the size between the steps. + if (size & 4) { + x ^= read32le(buf); + buf += 4; + i = 32; + } - return a; -} -*/ + if (size & 2) { + x ^= (uint64_t)read16le(buf) << i; + buf += 2; + i += 16; + } -#ifdef BUILDING_CRC64_CLMUL + if (size & 1) + x ^= (uint64_t)*buf << i; -// MSVC (VS2015 - VS2022) produces bad 32-bit x86 code from the CLMUL CRC -// code when optimizations are enabled (release build). According to the bug -// report, the ebx register is corrupted and the calculated result is wrong. -// Trying to workaround the problem with "__asm mov ebx, ebx" didn't help. -// The following pragma works and performance is still good. x86-64 builds -// and CRC32 CLMUL aren't affected by this problem. The problem does not -// happen in crc_simd_body() either (which is shared with CRC32 CLMUL anyway). -// -// NOTE: Another pragma after crc64_arch_optimized() restores -// the optimizations. If the #if condition here is updated, -// the other one must be updated too. -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \ - && defined(_M_IX86) -# pragma optimize("g", off) -#endif + v0 = my_set_low64((int64_t)x); + v0 = shift_left(v0, 8 - size); -crc_attr_target -crc_attr_no_sanitize_address -static uint64_t -crc64_arch_optimized(const uint8_t *buf, size_t size, uint64_t crc) -{ -#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS - // The code assumes that there is at least one byte of input. - if (size == 0) - return crc; -#endif - - // const uint64_t poly = 0xc96c5795d7870f42; // CRC polynomial - const uint64_t p = 0x92d8af2baf0e1e85; // (poly << 1) | 1 - const uint64_t mu = 0x9c3e466c172963d5; // (calc_lo(poly) << 1) | 1 - const uint64_t k2 = 0xdabe95afc7875f40; // calc_hi(poly, 1) - const uint64_t k1 = 0xe05dd497ca393ae4; // calc_hi(poly, k2) + } else if (size < 16) { + v0 = my_set_low64((int64_t)(crc ^ read64le(buf))); - const __m128i vfold8 = _mm_set_epi64x((int64_t)p, (int64_t)mu); - const __m128i vfold16 = _mm_set_epi64x((int64_t)k2, (int64_t)k1); + // NOTE: buf is intentionally left 8 bytes behind so that + // we can read the last 1-7 bytes with read64le(buf + size). + size -= 8; - __m128i v0, v1, v2; + // Handling 8-byte input specially is a speed optimization + // as the clmul can be skipped. A branch is also needed to + // avoid a too high shift amount. + if (size > 0) { + const size_t padding = 8 - size; + uint64_t high = read64le(buf + size) >> (padding * 8); #if defined(__i386__) || defined(_M_IX86) - crc_simd_body(buf, size, &v0, &v1, vfold16, - _mm_set_epi64x(0, (int64_t)~crc)); + // Simple but likely not the best code for 32-bit x86. + v0 = _mm_insert_epi32(v0, (int32_t)high, 2); + v0 = _mm_insert_epi32(v0, (int32_t)(high >> 32), 3); #else - // GCC and Clang would produce good code with _mm_set_epi64x - // but MSVC needs _mm_cvtsi64_si128 on x86-64. - crc_simd_body(buf, size, &v0, &v1, vfold16, - _mm_cvtsi64_si128((int64_t)~crc)); + v0 = _mm_insert_epi64(v0, (int64_t)high, 1); #endif - v1 = _mm_xor_si128(_mm_clmulepi64_si128(v0, vfold16, 0x10), v1); - v0 = _mm_clmulepi64_si128(v1, vfold8, 0x00); - v2 = _mm_clmulepi64_si128(v0, vfold8, 0x10); - v0 = _mm_xor_si128(_mm_xor_si128(v1, _mm_slli_si128(v0, 8)), v2); + v0 = shift_left(v0, padding); + + v1 = _mm_srli_si128(v0, 8); + v0 = _mm_clmulepi64_si128(v0, fold128, 0x10); + v0 = _mm_xor_si128(v0, v1); + } + } else { + v0 = my_set_low64((int64_t)crc); + + // To align or not to align the buf pointer? If the end of + // the buffer isn't aligned, aligning the pointer here would + // make us do an extra folding step with the associated byte + // shuffling overhead. The cost of that would need to be + // lower than the benefit of aligned reads. Testing on an old + // Intel Ivy Bridge processor suggested that aligning isn't + // worth the cost but it likely depends on the processor and + // buffer size. Unaligned loads (MOVDQU) should be fast on + // x86 processors that support PCLMULQDQ, so we don't align + // the buf pointer here. + + // Read the first (and possibly the only) full 16 bytes. + v0 = _mm_xor_si128(v0, my_load128(buf)); + buf += 16; + size -= 16; + + if (size >= 48) { + v1 = my_load128(buf); + v2 = my_load128(buf + 16); + v3 = my_load128(buf + 32); + buf += 48; + size -= 48; + + while (size >= 64) { + v0 = fold_xor(v0, fold512, buf); + v1 = fold_xor(v1, fold512, buf + 16); + v2 = fold_xor(v2, fold512, buf + 32); + v3 = fold_xor(v3, fold512, buf + 48); + buf += 64; + size -= 64; + } + + v0 = _mm_xor_si128(v1, fold(v0, fold128)); + v0 = _mm_xor_si128(v2, fold(v0, fold128)); + v0 = _mm_xor_si128(v3, fold(v0, fold128)); + } + + while (size >= 16) { + v0 = fold_xor(v0, fold128, buf); + buf += 16; + size -= 16; + } + + if (size > 0) { + // We want the last "size" number of input bytes to + // be at the high bits of v1. First do a full 16-byte + // load and then mask the low bytes to zeros. + v1 = my_load128(buf + size - 16); + v1 = keep_high_bytes(v1, size); + + // Shift high bytes from v0 to the low bytes of v1. + // + // Alternatively we could replace the combination + // keep_high_bytes + shift_right + _mm_or_si128 with + // _mm_shuffle_epi8 + _mm_blendv_epi8 but that would + // require larger tables for the masks. Now there are + // three loads (instead of two) from the mask tables + // but they all are from the same cache line. + v1 = _mm_or_si128(v1, shift_right(v0, size)); + + // Shift high bytes of v0 away, padding the + // low bytes with zeros. + v0 = shift_left(v0, 16 - size); + + v0 = _mm_xor_si128(v1, fold(v0, fold128)); + } + v1 = _mm_srli_si128(v0, 8); + v0 = _mm_clmulepi64_si128(v0, fold128, 0x10); + v0 = _mm_xor_si128(v0, v1); + } + + // Barrett reduction + +#if BUILDING_CRC_CLMUL == 32 + v1 = _mm_clmulepi64_si128(v0, mu_p, 0x10); // v0 * mu + v1 = _mm_clmulepi64_si128(v1, mu_p, 0x00); // v1 * p + v0 = _mm_xor_si128(v0, v1); + return ~(uint32_t)_mm_extract_epi32(v0, 2); +#else + // Because p is 65 bits but one bit doesn't fit into the 64-bit + // half of __m128i, finish the second clmul by shifting v1 left + // by 64 bits and xorring it to the final result. + v1 = _mm_clmulepi64_si128(v0, mu_p, 0x10); // v0 * mu + v2 = _mm_slli_si128(v1, 8); + v1 = _mm_clmulepi64_si128(v1, mu_p, 0x00); // v1 * p + v0 = _mm_xor_si128(v0, v2); + v0 = _mm_xor_si128(v0, v1); #if defined(__i386__) || defined(_M_IX86) return ~(((uint64_t)(uint32_t)_mm_extract_epi32(v0, 3) << 32) | (uint64_t)(uint32_t)_mm_extract_epi32(v0, 2)); #else return ~(uint64_t)_mm_extract_epi64(v0, 1); #endif -} - -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \ - && defined(_M_IX86) -# pragma optimize("", on) #endif - -#endif // BUILDING_CRC64_CLMUL +} // Even though this is an inline function, compile it only when needed. diff --git a/contrib/libs/lzma/liblzma/common/alone_decoder.c b/contrib/libs/lzma/liblzma/common/alone_decoder.c index 78af651578fc..e2b58e1f3758 100644 --- a/contrib/libs/lzma/liblzma/common/alone_decoder.c +++ b/contrib/libs/lzma/liblzma/common/alone_decoder.c @@ -134,8 +134,7 @@ alone_decode(void *coder_ptr, const lzma_allocator *allocator, coder->pos = 0; coder->sequence = SEQ_CODER_INIT; - - // Fall through + FALLTHROUGH; case SEQ_CODER_INIT: { if (coder->memusage > coder->memlimit) diff --git a/contrib/libs/lzma/liblzma/common/auto_decoder.c b/contrib/libs/lzma/liblzma/common/auto_decoder.c index fdd520f905c5..da49345f909d 100644 --- a/contrib/libs/lzma/liblzma/common/auto_decoder.c +++ b/contrib/libs/lzma/liblzma/common/auto_decoder.c @@ -79,7 +79,7 @@ auto_decode(void *coder_ptr, const lzma_allocator *allocator, return LZMA_GET_CHECK; } - // Fall through + FALLTHROUGH; case SEQ_CODE: { const lzma_ret ret = coder->next.code( @@ -91,10 +91,9 @@ auto_decode(void *coder_ptr, const lzma_allocator *allocator, return ret; coder->sequence = SEQ_FINISH; + FALLTHROUGH; } - // Fall through - case SEQ_FINISH: // When LZMA_CONCATENATED was used and we were decoding // a LZMA_Alone file, we need to check that there is no diff --git a/contrib/libs/lzma/liblzma/common/block_decoder.c b/contrib/libs/lzma/liblzma/common/block_decoder.c index 2e369d316bdf..bbc9f5566c8b 100644 --- a/contrib/libs/lzma/liblzma/common/block_decoder.c +++ b/contrib/libs/lzma/liblzma/common/block_decoder.c @@ -146,10 +146,9 @@ block_decode(void *coder_ptr, const lzma_allocator *allocator, coder->block->uncompressed_size = coder->uncompressed_size; coder->sequence = SEQ_PADDING; + FALLTHROUGH; } - // Fall through - case SEQ_PADDING: // Compressed Data is padded to a multiple of four bytes. while (coder->compressed_size & 3) { @@ -173,8 +172,7 @@ block_decode(void *coder_ptr, const lzma_allocator *allocator, lzma_check_finish(&coder->check, coder->block->check); coder->sequence = SEQ_CHECK; - - // Fall through + FALLTHROUGH; case SEQ_CHECK: { const size_t check_size = lzma_check_size(coder->block->check); diff --git a/contrib/libs/lzma/liblzma/common/block_encoder.c b/contrib/libs/lzma/liblzma/common/block_encoder.c index ce8c1de69442..eb7997a72aeb 100644 --- a/contrib/libs/lzma/liblzma/common/block_encoder.c +++ b/contrib/libs/lzma/liblzma/common/block_encoder.c @@ -94,10 +94,9 @@ block_encode(void *coder_ptr, const lzma_allocator *allocator, coder->block->uncompressed_size = coder->uncompressed_size; coder->sequence = SEQ_PADDING; + FALLTHROUGH; } - // Fall through - case SEQ_PADDING: // Pad Compressed Data to a multiple of four bytes. We can // use coder->compressed_size for this since we don't need @@ -117,8 +116,7 @@ block_encode(void *coder_ptr, const lzma_allocator *allocator, lzma_check_finish(&coder->check, coder->block->check); coder->sequence = SEQ_CHECK; - - // Fall through + FALLTHROUGH; case SEQ_CHECK: { const size_t check_size = lzma_check_size(coder->block->check); diff --git a/contrib/libs/lzma/liblzma/common/common.c b/contrib/libs/lzma/liblzma/common/common.c index cc0e06a51bee..6e031a56c888 100644 --- a/contrib/libs/lzma/liblzma/common/common.c +++ b/contrib/libs/lzma/liblzma/common/common.c @@ -96,6 +96,12 @@ lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size) { + assert(in != NULL || *in_pos == in_size); + assert(out != NULL || *out_pos == out_size); + + assert(*in_pos <= in_size); + assert(*out_pos <= out_size); + const size_t in_avail = in_size - *in_pos; const size_t out_avail = out_size - *out_pos; const size_t copy_size = my_min(in_avail, out_avail); @@ -348,7 +354,7 @@ lzma_code(lzma_stream *strm, lzma_action action) else strm->internal->sequence = ISEQ_END; - // Fall through + FALLTHROUGH; case LZMA_NO_CHECK: case LZMA_UNSUPPORTED_CHECK: diff --git a/contrib/libs/lzma/liblzma/common/file_info.c b/contrib/libs/lzma/liblzma/common/file_info.c index 7c85084a706e..4b2eb5d0400b 100644 --- a/contrib/libs/lzma/liblzma/common/file_info.c +++ b/contrib/libs/lzma/liblzma/common/file_info.c @@ -298,15 +298,13 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator, // Start looking for Stream Padding and Stream Footer // at the end of the file. coder->file_target_pos = coder->file_size; - - // Fall through + FALLTHROUGH; case SEQ_PADDING_SEEK: coder->sequence = SEQ_PADDING_DECODE; return_if_error(reverse_seek( coder, in_start, in_pos, in_size)); - - // Fall through + FALLTHROUGH; case SEQ_PADDING_DECODE: { // Copy to coder->temp first. This keeps the code simpler if @@ -356,9 +354,9 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator, if (coder->temp_size < LZMA_STREAM_HEADER_SIZE) return_if_error(reverse_seek( coder, in_start, in_pos, in_size)); - } - // Fall through + FALLTHROUGH; + } case SEQ_FOOTER: // Copy the Stream Footer field into coder->temp. @@ -414,7 +412,7 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator, return LZMA_SEEK_NEEDED; } - // Fall through + FALLTHROUGH; case SEQ_INDEX_INIT: { // Calculate the amount of memory already used by the earlier @@ -444,10 +442,9 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator, coder->index_remaining = coder->footer_flags.backward_size; coder->sequence = SEQ_INDEX_DECODE; + FALLTHROUGH; } - // Fall through - case SEQ_INDEX_DECODE: { // Decode (a part of) the Index. If the whole Index is already // in coder->temp, read it from there. Otherwise read from @@ -574,9 +571,9 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator, return_if_error(reverse_seek(coder, in_start, in_pos, in_size)); } - } - // Fall through + FALLTHROUGH; + } case SEQ_HEADER_DECODE: // Copy the Stream Header field into coder->temp. @@ -596,8 +593,7 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator, coder->temp + coder->temp_size))); coder->sequence = SEQ_HEADER_COMPARE; - - // Fall through + FALLTHROUGH; case SEQ_HEADER_COMPARE: // Compare Stream Header against Stream Footer. They must diff --git a/contrib/libs/lzma/liblzma/common/index_decoder.c b/contrib/libs/lzma/liblzma/common/index_decoder.c index 4bcb30692115..4eab56d942e1 100644 --- a/contrib/libs/lzma/liblzma/common/index_decoder.c +++ b/contrib/libs/lzma/liblzma/common/index_decoder.c @@ -93,8 +93,7 @@ index_decode(void *coder_ptr, const lzma_allocator *allocator, coder->pos = 0; coder->sequence = SEQ_MEMUSAGE; - - // Fall through + FALLTHROUGH; case SEQ_MEMUSAGE: if (lzma_index_memusage(1, coder->count) > coder->memlimit) { @@ -153,8 +152,7 @@ index_decode(void *coder_ptr, const lzma_allocator *allocator, case SEQ_PADDING_INIT: coder->pos = lzma_index_padding_size(coder->index); coder->sequence = SEQ_PADDING; - - // Fall through + FALLTHROUGH; case SEQ_PADDING: if (coder->pos > 0) { @@ -170,8 +168,7 @@ index_decode(void *coder_ptr, const lzma_allocator *allocator, *in_pos - in_start, coder->crc32); coder->sequence = SEQ_CRC32; - - // Fall through + FALLTHROUGH; case SEQ_CRC32: do { diff --git a/contrib/libs/lzma/liblzma/common/index_encoder.c b/contrib/libs/lzma/liblzma/common/index_encoder.c index ecc299c0159f..80f1be1e3aea 100644 --- a/contrib/libs/lzma/liblzma/common/index_encoder.c +++ b/contrib/libs/lzma/liblzma/common/index_encoder.c @@ -93,8 +93,7 @@ index_encode(void *coder_ptr, } coder->sequence = SEQ_UNPADDED; - - // Fall through + FALLTHROUGH; case SEQ_UNPADDED: case SEQ_UNCOMPRESSED: { @@ -127,8 +126,7 @@ index_encode(void *coder_ptr, *out_pos - out_start, coder->crc32); coder->sequence = SEQ_CRC32; - - // Fall through + FALLTHROUGH; case SEQ_CRC32: // We don't use the main loop, because we don't want diff --git a/contrib/libs/lzma/liblzma/common/index_hash.c b/contrib/libs/lzma/liblzma/common/index_hash.c index caa5967ca496..b7f1b6b58d1a 100644 --- a/contrib/libs/lzma/liblzma/common/index_hash.c +++ b/contrib/libs/lzma/liblzma/common/index_hash.c @@ -267,9 +267,9 @@ lzma_index_hash_decode(lzma_index_hash *index_hash, const uint8_t *in, index_hash->pos = (LZMA_VLI_C(4) - index_size_unpadded( index_hash->records.count, index_hash->records.index_list_size)) & 3; - index_hash->sequence = SEQ_PADDING; - // Fall through + index_hash->sequence = SEQ_PADDING; + FALLTHROUGH; case SEQ_PADDING: if (index_hash->pos > 0) { @@ -302,8 +302,7 @@ lzma_index_hash_decode(lzma_index_hash *index_hash, const uint8_t *in, *in_pos - in_start, index_hash->crc32); index_hash->sequence = SEQ_CRC32; - - // Fall through + FALLTHROUGH; case SEQ_CRC32: do { diff --git a/contrib/libs/lzma/liblzma/common/lzip_decoder.c b/contrib/libs/lzma/liblzma/common/lzip_decoder.c index 651a0ae712c8..4dff2d5889ea 100644 --- a/contrib/libs/lzma/liblzma/common/lzip_decoder.c +++ b/contrib/libs/lzma/liblzma/common/lzip_decoder.c @@ -150,10 +150,9 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator, coder->member_size = sizeof(lzip_id_string); coder->sequence = SEQ_VERSION; + FALLTHROUGH; } - // Fall through - case SEQ_VERSION: if (*in_pos >= in_size) return LZMA_OK; @@ -173,7 +172,7 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator, if (coder->tell_any_check) return LZMA_GET_CHECK; - // Fall through + FALLTHROUGH; case SEQ_DICT_SIZE: { if (*in_pos >= in_size) @@ -220,10 +219,9 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator, // LZMA_MEMLIMIT_ERROR we need to be able to restart after // the memlimit has been increased. coder->sequence = SEQ_CODER_INIT; + FALLTHROUGH; } - // Fall through - case SEQ_CODER_INIT: { if (coder->memusage > coder->memlimit) return LZMA_MEMLIMIT_ERROR; @@ -243,10 +241,9 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator, coder->crc32 = 0; coder->sequence = SEQ_LZMA_STREAM; + FALLTHROUGH; } - // Fall through - case SEQ_LZMA_STREAM: { const size_t in_start = *in_pos; const size_t out_start = *out_pos; @@ -273,10 +270,9 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator, return ret; coder->sequence = SEQ_MEMBER_FOOTER; + FALLTHROUGH; } - // Fall through - case SEQ_MEMBER_FOOTER: { // The footer of .lz version 0 lacks the Member size field. // This is the only difference between version 0 and diff --git a/contrib/libs/lzma/liblzma/common/memcmplen.h b/contrib/libs/lzma/liblzma/common/memcmplen.h index 86b5d6f37eb3..82e908542295 100644 --- a/contrib/libs/lzma/liblzma/common/memcmplen.h +++ b/contrib/libs/lzma/liblzma/common/memcmplen.h @@ -58,8 +58,7 @@ lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2, #if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \ && (((TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) \ - && (defined(__x86_64__) \ - || defined(__aarch64__))) \ + && SIZE_MAX == UINT64_MAX) \ || (defined(__INTEL_COMPILER) && defined(__x86_64__)) \ || (defined(__INTEL_COMPILER) && defined(_M_X64)) \ || (defined(_MSC_VER) && (defined(_M_X64) \ diff --git a/contrib/libs/lzma/liblzma/common/stream_decoder.c b/contrib/libs/lzma/liblzma/common/stream_decoder.c index 7f426841366a..94004b74a165 100644 --- a/contrib/libs/lzma/liblzma/common/stream_decoder.c +++ b/contrib/libs/lzma/liblzma/common/stream_decoder.c @@ -154,9 +154,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator, if (coder->tell_any_check) return LZMA_GET_CHECK; - } - // Fall through + FALLTHROUGH; + } case SEQ_BLOCK_HEADER: { if (*in_pos >= in_size) @@ -187,10 +187,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator, coder->pos = 0; coder->sequence = SEQ_BLOCK_INIT; + FALLTHROUGH; } - // Fall through - case SEQ_BLOCK_INIT: { // Checking memusage and doing the initialization needs // its own sequence point because we need to be able to @@ -252,10 +251,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator, return ret; coder->sequence = SEQ_BLOCK_RUN; + FALLTHROUGH; } - // Fall through - case SEQ_BLOCK_RUN: { const lzma_ret ret = coder->block_decoder.code( coder->block_decoder.coder, allocator, @@ -291,10 +289,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator, return ret; coder->sequence = SEQ_STREAM_FOOTER; + FALLTHROUGH; } - // Fall through - case SEQ_STREAM_FOOTER: { // Copy the Stream Footer to the internal buffer. lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, @@ -331,10 +328,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator, return LZMA_STREAM_END; coder->sequence = SEQ_STREAM_PADDING; + FALLTHROUGH; } - // Fall through - case SEQ_STREAM_PADDING: assert(coder->concatenated); diff --git a/contrib/libs/lzma/liblzma/common/stream_decoder_mt.c b/contrib/libs/lzma/liblzma/common/stream_decoder_mt.c index 244624a47900..271f9b07c4b8 100644 --- a/contrib/libs/lzma/liblzma/common/stream_decoder_mt.c +++ b/contrib/libs/lzma/liblzma/common/stream_decoder_mt.c @@ -23,15 +23,10 @@ typedef enum { THR_IDLE, /// Decoding is in progress. - /// Main thread may change this to THR_STOP or THR_EXIT. + /// Main thread may change this to THR_IDLE or THR_EXIT. /// The worker thread may change this to THR_IDLE. THR_RUN, - /// The main thread wants the thread to stop whatever it was doing - /// but not exit. Main thread may change this to THR_EXIT. - /// The worker thread may change this to THR_IDLE. - THR_STOP, - /// The main thread wants the thread to exit. THR_EXIT, @@ -346,27 +341,6 @@ worker_enable_partial_update(void *thr_ptr) } -/// Things do to at THR_STOP or when finishing a Block. -/// This is called with thr->mutex locked. -static void -worker_stop(struct worker_thread *thr) -{ - // Update memory usage counters. - thr->coder->mem_in_use -= thr->in_size; - thr->in_size = 0; // thr->in was freed above. - - thr->coder->mem_in_use -= thr->mem_filters; - thr->coder->mem_cached += thr->mem_filters; - - // Put this thread to the stack of free threads. - thr->next = thr->coder->threads_free; - thr->coder->threads_free = thr; - - mythread_cond_signal(&thr->coder->cond); - return; -} - - static MYTHREAD_RET_TYPE worker_decoder(void *thr_ptr) { @@ -397,17 +371,6 @@ worker_decoder(void *thr_ptr) return MYTHREAD_RET_VALUE; } - if (thr->state == THR_STOP) { - thr->state = THR_IDLE; - mythread_mutex_unlock(&thr->mutex); - - mythread_sync(thr->coder->mutex) { - worker_stop(thr); - } - - goto next_loop_lock; - } - assert(thr->state == THR_RUN); // Update progress info for get_progress(). @@ -472,8 +435,7 @@ worker_decoder(void *thr_ptr) } // Either we finished successfully (LZMA_STREAM_END) or an error - // occurred. Both cases are handled almost identically. The error - // case requires updating thr->coder->thread_error. + // occurred. // // The sizes are in the Block Header and the Block decoder // checks that they match, thus we know these: @@ -481,16 +443,30 @@ worker_decoder(void *thr_ptr) assert(ret != LZMA_STREAM_END || thr->out_pos == thr->block_options.uncompressed_size); - // Free the input buffer. Don't update in_size as we need - // it later to update thr->coder->mem_in_use. - lzma_free(thr->in, thr->allocator); - thr->in = NULL; - mythread_sync(thr->mutex) { + // Block decoder ensures this, but do a sanity check anyway + // because thr->in_filled < thr->in_size means that the main + // thread is still writing to thr->in. + if (ret == LZMA_STREAM_END && thr->in_filled != thr->in_size) { + assert(0); + ret = LZMA_PROG_ERROR; + } + if (thr->state != THR_EXIT) thr->state = THR_IDLE; } + // Free the input buffer. Don't update in_size as we need + // it later to update thr->coder->mem_in_use. + // + // This step is skipped if an error occurred because the main thread + // might still be writing to thr->in. The memory will be freed after + // threads_end() sets thr->state = THR_EXIT. + if (ret == LZMA_STREAM_END) { + lzma_free(thr->in, thr->allocator); + thr->in = NULL; + } + mythread_sync(thr->coder->mutex) { // Move our progress info to the main thread. thr->coder->progress_in += thr->in_pos; @@ -510,7 +486,20 @@ worker_decoder(void *thr_ptr) && thr->coder->thread_error == LZMA_OK) thr->coder->thread_error = ret; - worker_stop(thr); + // Return the worker thread to the stack of available + // threads only if no errors occurred. + if (ret == LZMA_STREAM_END) { + // Update memory usage counters. + thr->coder->mem_in_use -= thr->in_size; + thr->coder->mem_in_use -= thr->mem_filters; + thr->coder->mem_cached += thr->mem_filters; + + // Put this thread to the stack of free threads. + thr->next = thr->coder->threads_free; + thr->coder->threads_free = thr; + } + + mythread_cond_signal(&thr->coder->cond); } goto next_loop_lock; @@ -544,17 +533,22 @@ threads_end(struct lzma_stream_coder *coder, const lzma_allocator *allocator) } +/// Tell worker threads to stop without doing any cleaning up. +/// The clean up will be done when threads_exit() is called; +/// it's not possible to reuse the threads after threads_stop(). +/// +/// This is called before returning an unrecoverable error code +/// to the application. It would be waste of processor time +/// to keep the threads running in such a situation. static void threads_stop(struct lzma_stream_coder *coder) { for (uint32_t i = 0; i < coder->threads_initialized; ++i) { + // The threads that are in the THR_RUN state will stop + // when they check the state the next time. There's no + // need to signal coder->threads[i].cond. mythread_sync(coder->threads[i].mutex) { - // The state must be changed conditionally because - // THR_IDLE -> THR_STOP is not a valid state change. - if (coder->threads[i].state != THR_IDLE) { - coder->threads[i].state = THR_STOP; - mythread_cond_signal(&coder->threads[i].cond); - } + coder->threads[i].state = THR_IDLE; } } @@ -1077,9 +1071,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, if (coder->tell_any_check) return LZMA_GET_CHECK; - } - // Fall through + FALLTHROUGH; + } case SEQ_BLOCK_HEADER: { const size_t in_old = *in_pos; @@ -1214,10 +1208,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, } coder->sequence = SEQ_BLOCK_INIT; + FALLTHROUGH; } - // Fall through - case SEQ_BLOCK_INIT: { // Check if decoding is possible at all with the current // memlimit_stop which we must never exceed. @@ -1303,10 +1296,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, } coder->sequence = SEQ_BLOCK_THR_INIT; + FALLTHROUGH; } - // Fall through - case SEQ_BLOCK_THR_INIT: { // We need to wait for a multiple conditions to become true // until we can initialize the Block decoder and let a worker @@ -1508,10 +1500,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, } coder->sequence = SEQ_BLOCK_THR_RUN; + FALLTHROUGH; } - // Fall through - case SEQ_BLOCK_THR_RUN: { if (action == LZMA_FINISH && coder->fail_fast) { // We know that we won't get more input and that @@ -1549,10 +1540,17 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, // Read output from the output queue. Just like in // SEQ_BLOCK_HEADER, we wait to fill the output buffer // only if waiting_allowed was set to true in the beginning - // of this function (see the comment there). + // of this function (see the comment there) and there is + // no input available. In SEQ_BLOCK_HEADER, there is never + // input available when read_output_and_wait() is called, + // but here there can be when LZMA_FINISH is used, thus we + // need to check if *in_pos == in_size. Otherwise we would + // wait here instead of using the available input to start + // a new thread. return_if_error(read_output_and_wait(coder, allocator, out, out_pos, out_size, - NULL, waiting_allowed, + NULL, + waiting_allowed && *in_pos == in_size, &wait_abs, &has_blocked)); if (coder->pending_error != LZMA_OK) { @@ -1561,6 +1559,10 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, } // Return if the input didn't contain the whole Block. + // + // NOTE: When we updated coder->thr->in_filled a few lines + // above, the worker thread might by now have finished its + // work and returned itself back to the stack of free threads. if (coder->thr->in_filled < coder->thr->in_size) { assert(*in_pos == in_size); return LZMA_OK; @@ -1613,10 +1615,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, coder->mem_direct_mode = coder->mem_next_filters; coder->sequence = SEQ_BLOCK_DIRECT_RUN; + FALLTHROUGH; } - // Fall through - case SEQ_BLOCK_DIRECT_RUN: { const size_t in_old = *in_pos; const size_t out_old = *out_pos; @@ -1652,8 +1653,7 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, return LZMA_OK; coder->sequence = SEQ_INDEX_DECODE; - - // Fall through + FALLTHROUGH; case SEQ_INDEX_DECODE: { // If we don't have any input, don't call @@ -1672,10 +1672,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, return ret; coder->sequence = SEQ_STREAM_FOOTER; + FALLTHROUGH; } - // Fall through - case SEQ_STREAM_FOOTER: { // Copy the Stream Footer to the internal buffer. const size_t in_old = *in_pos; @@ -1714,10 +1713,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator, return LZMA_STREAM_END; coder->sequence = SEQ_STREAM_PADDING; + FALLTHROUGH; } - // Fall through - case SEQ_STREAM_PADDING: assert(coder->concatenated); @@ -1948,7 +1946,7 @@ stream_decoder_mt_init(lzma_next_coder *next, const lzma_allocator *allocator, // accounting from scratch, too. Changes in filter and block sizes may // affect number of threads. // - // FIXME? Reusing should be easy but unlike the single-threaded + // Reusing threads doesn't seem worth it. Unlike the single-threaded // decoder, with some types of input file combinations reusing // could leave quite a lot of memory allocated but unused (first // file could allocate a lot, the next files could use fewer diff --git a/contrib/libs/lzma/liblzma/common/stream_encoder_mt.c b/contrib/libs/lzma/liblzma/common/stream_encoder_mt.c index f0fef1523318..fd0eb98df682 100644 --- a/contrib/libs/lzma/liblzma/common/stream_encoder_mt.c +++ b/contrib/libs/lzma/liblzma/common/stream_encoder_mt.c @@ -731,8 +731,7 @@ stream_encode_mt(void *coder_ptr, const lzma_allocator *allocator, coder->header_pos = 0; coder->sequence = SEQ_BLOCK; - - // Fall through + FALLTHROUGH; case SEQ_BLOCK: { // Initialized to silence warnings. @@ -851,9 +850,9 @@ stream_encode_mt(void *coder_ptr, const lzma_allocator *allocator, // to be ready to be copied out. coder->progress_out += lzma_index_size(coder->index) + LZMA_STREAM_HEADER_SIZE; - } - // Fall through + FALLTHROUGH; + } case SEQ_INDEX: { // Call the Index encoder. It doesn't take any input, so @@ -873,10 +872,9 @@ stream_encode_mt(void *coder_ptr, const lzma_allocator *allocator, return LZMA_PROG_ERROR; coder->sequence = SEQ_STREAM_FOOTER; + FALLTHROUGH; } - // Fall through - case SEQ_STREAM_FOOTER: lzma_bufcpy(coder->header, &coder->header_pos, sizeof(coder->header), diff --git a/contrib/libs/lzma/liblzma/common/string_conversion.c b/contrib/libs/lzma/liblzma/common/string_conversion.c index 3a08486a1f62..015acf225856 100644 --- a/contrib/libs/lzma/liblzma/common/string_conversion.c +++ b/contrib/libs/lzma/liblzma/common/string_conversion.c @@ -12,6 +12,11 @@ #include "filter_common.h" +// liblzma itself doesn't use gettext to translate messages. +// Mark the strings still so that xz can translate them. +#define N_(msgid) msgid + + ///////////////////// // String building // ///////////////////// @@ -319,7 +324,7 @@ parse_lzma12_preset(const char **const str, const char *str_end, assert(*str < str_end); if (!(**str >= '0' && **str <= '9')) - return "Unsupported preset"; + return N_("Unsupported preset"); *preset = (uint32_t)(**str - '0'); @@ -331,7 +336,7 @@ parse_lzma12_preset(const char **const str, const char *str_end, break; default: - return "Unsupported preset flag"; + return N_("Unsupported flag in the preset"); } } @@ -350,7 +355,7 @@ set_lzma12_preset(const char **const str, const char *str_end, lzma_options_lzma *opts = filter_options; if (lzma_lzma_preset(opts, preset)) - return "Unsupported preset"; + return N_("Unsupported preset"); return NULL; } @@ -442,7 +447,7 @@ parse_lzma12(const char **const str, const char *str_end, void *filter_options) return errmsg; if (opts->lc + opts->lp > LZMA_LCLP_MAX) - return "The sum of lc and lp must not exceed 4"; + return N_("The sum of lc and lp must not exceed 4"); return NULL; } @@ -578,21 +583,21 @@ parse_options(const char **const str, const char *str_end, // Fail if the '=' wasn't found or the option name is missing // (the first char is '='). if (equals_sign == NULL || **str == '=') - return "Options must be 'name=value' pairs separated " - "with commas"; + return N_("Options must be 'name=value' pairs " + "separated with commas"); // Reject a too long option name so that the memcmp() // in the loop below won't read past the end of the // string in optmap[i].name. const size_t name_len = (size_t)(equals_sign - *str); if (name_len > NAME_LEN_MAX) - return "Unknown option name"; + return N_("Unknown option name"); // Find the option name from optmap[]. size_t i = 0; while (true) { if (i == optmap_size) - return "Unknown option name"; + return N_("Unknown option name"); if (memcmp(*str, optmap[i].name, name_len) == 0 && optmap[i].name[name_len] == '\0') @@ -609,7 +614,7 @@ parse_options(const char **const str, const char *str_end, // string so check it here. const size_t value_len = (size_t)(name_eq_value_end - *str); if (value_len == 0) - return "Option value cannot be empty"; + return N_("Option value cannot be empty"); // LZMA1/2 preset has its own parsing function. if (optmap[i].type == OPTMAP_TYPE_LZMA_PRESET) { @@ -630,14 +635,14 @@ parse_options(const char **const str, const char *str_end, // in the loop below won't read past the end of the // string in optmap[i].u.map[j].name. if (value_len > NAME_LEN_MAX) - return "Invalid option value"; + return N_("Invalid option value"); const name_value_map *map = optmap[i].u.map; size_t j = 0; while (true) { // The array is terminated with an empty name. if (map[j].name[0] == '\0') - return "Invalid option value"; + return N_("Invalid option value"); if (memcmp(*str, map[j].name, value_len) == 0 && map[j].name[value_len] @@ -651,7 +656,8 @@ parse_options(const char **const str, const char *str_end, } else if (**str < '0' || **str > '9') { // Note that "max" isn't supported while it is // supported in xz. It's not useful here. - return "Value is not a non-negative decimal integer"; + return N_("Value is not a non-negative " + "decimal integer"); } else { // strtoul() has locale-specific behavior so it cannot // be relied on to get reproducible results since we @@ -665,13 +671,13 @@ parse_options(const char **const str, const char *str_end, v = 0; do { if (v > UINT32_MAX / 10) - return "Value out of range"; + return N_("Value out of range"); v *= 10; const uint32_t add = (uint32_t)(*p - '0'); if (UINT32_MAX - add < v) - return "Value out of range"; + return N_("Value out of range"); v += add; ++p; @@ -696,8 +702,9 @@ parse_options(const char **const str, const char *str_end, if ((optmap[i].flags & OPTMAP_USE_BYTE_SUFFIX) == 0) { *str = multiplier_start; - return "This option does not support " - "any integer suffixes"; + return N_("This option does not " + "support any multiplier " + "suffixes"); } uint32_t shift; @@ -720,8 +727,13 @@ parse_options(const char **const str, const char *str_end, default: *str = multiplier_start; - return "Invalid multiplier suffix " - "(KiB, MiB, or GiB)"; + + // TRANSLATORS: Don't translate the + // suffixes "KiB", "MiB", or "GiB" + // because a user can only specify + // untranslated suffixes. + return N_("Invalid multiplier suffix " + "(KiB, MiB, or GiB)"); } ++p; @@ -740,19 +752,19 @@ parse_options(const char **const str, const char *str_end, // Now we must have no chars remaining. if (p < name_eq_value_end) { *str = multiplier_start; - return "Invalid multiplier suffix " - "(KiB, MiB, or GiB)"; + return N_("Invalid multiplier suffix " + "(KiB, MiB, or GiB)"); } if (v > (UINT32_MAX >> shift)) - return "Value out of range"; + return N_("Value out of range"); v <<= shift; } if (v < optmap[i].u.range.min || v > optmap[i].u.range.max) - return "Value out of range"; + return N_("Value out of range"); } // Set the value in filter_options. Enums are handled @@ -814,15 +826,15 @@ parse_filter(const char **const str, const char *str_end, lzma_filter *filter, // string in filter_name_map[i].name. const size_t name_len = (size_t)(name_end - *str); if (name_len > NAME_LEN_MAX) - return "Unknown filter name"; + return N_("Unknown filter name"); for (size_t i = 0; i < ARRAY_SIZE(filter_name_map); ++i) { if (memcmp(*str, filter_name_map[i].name, name_len) == 0 && filter_name_map[i].name[name_len] == '\0') { if (only_xz && filter_name_map[i].id >= LZMA_FILTER_RESERVED_START) - return "This filter cannot be used in " - "the .xz format"; + return N_("This filter cannot be used in " + "the .xz format"); // Allocate the filter-specific options and // initialize the memory with zeros. @@ -830,7 +842,7 @@ parse_filter(const char **const str, const char *str_end, lzma_filter *filter, filter_name_map[i].opts_size, allocator); if (options == NULL) - return "Memory allocation failed"; + return N_("Memory allocation failed"); // Filter name was found so the input string is good // at least this far. @@ -850,7 +862,7 @@ parse_filter(const char **const str, const char *str_end, lzma_filter *filter, } } - return "Unknown filter name"; + return N_("Unknown filter name"); } @@ -869,8 +881,8 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags, ++*str; if (**str == '\0') - return "Empty string is not allowed, " - "try \"6\" if a default value is needed"; + return N_("Empty string is not allowed, " + "try '6' if a default value is needed"); // Detect the type of the string. // @@ -893,7 +905,7 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags, // there are no chars other than spaces. for (size_t i = 1; str_end[i] != '\0'; ++i) if (str_end[i] != ' ') - return "Unsupported preset"; + return N_("Unsupported preset"); } else { // There are no trailing spaces. Use the whole string. str_end = *str + str_len; @@ -906,11 +918,11 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags, lzma_options_lzma *opts = lzma_alloc(sizeof(*opts), allocator); if (opts == NULL) - return "Memory allocation failed"; + return N_("Memory allocation failed"); if (lzma_lzma_preset(opts, preset)) { lzma_free(opts, allocator); - return "Unsupported preset"; + return N_("Unsupported preset"); } filters[0].id = LZMA_FILTER_LZMA2; @@ -934,7 +946,7 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags, size_t i = 0; do { if (i == LZMA_FILTERS_MAX) { - errmsg = "The maximum number of filters is four"; + errmsg = N_("The maximum number of filters is four"); goto error; } @@ -956,7 +968,7 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags, // Inputs that have "--" at the end or "-- " in the middle // will result in an empty filter name. if (filter_end == *str) { - errmsg = "Filter name is missing"; + errmsg = N_("Filter name is missing"); goto error; } @@ -983,8 +995,8 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags, const lzma_ret ret = lzma_validate_chain(temp_filters, &dummy); assert(ret == LZMA_OK || ret == LZMA_OPTIONS_ERROR); if (ret != LZMA_OK) { - errmsg = "Invalid filter chain " - "('lzma2' missing at the end?)"; + errmsg = N_("Invalid filter chain " + "('lzma2' missing at the end?)"); goto error; } } @@ -1012,17 +1024,26 @@ lzma_str_to_filters(const char *str, int *error_pos, lzma_filter *filters, if (error_pos != NULL) *error_pos = 0; - if (str == NULL || filters == NULL) + if (str == NULL || filters == NULL) { + // Don't translate this because it's only shown in case of + // a programming error. return "Unexpected NULL pointer argument(s) " "to lzma_str_to_filters()"; + } // Validate the flags. const uint32_t supported_flags = LZMA_STR_ALL_FILTERS | LZMA_STR_NO_VALIDATION; - if (flags & ~supported_flags) + if (flags & ~supported_flags) { + // This message is possible only if the caller uses flags + // that are only supported in a newer liblzma version (or + // the flags are simply buggy). Don't translate this at least + // when liblzma itself doesn't use gettext; xz and liblzma + // are usually upgraded at the same time. return "Unsupported flags to lzma_str_to_filters()"; + } const char *used = str; const char *errmsg = str_to_filters(&used, filters, flags, allocator); diff --git a/contrib/libs/lzma/liblzma/liblzma_linux.map b/contrib/libs/lzma/liblzma/liblzma_linux.map index 7e4b25e17620..50f1571de219 100644 --- a/contrib/libs/lzma/liblzma/liblzma_linux.map +++ b/contrib/libs/lzma/liblzma/liblzma_linux.map @@ -141,3 +141,13 @@ XZ_5.6.0 { global: lzma_mt_block_size; } XZ_5.4; + +XZ_5.8 { +global: + lzma_bcj_arm64_encode; + lzma_bcj_arm64_decode; + lzma_bcj_riscv_encode; + lzma_bcj_riscv_decode; + lzma_bcj_x86_encode; + lzma_bcj_x86_decode; +} XZ_5.6.0; diff --git a/contrib/libs/lzma/liblzma/lz/lz_decoder.c b/contrib/libs/lzma/liblzma/lz/lz_decoder.c index 92913f225a0d..1cb120ab3b09 100644 --- a/contrib/libs/lzma/liblzma/lz/lz_decoder.c +++ b/contrib/libs/lzma/liblzma/lz/lz_decoder.c @@ -53,9 +53,9 @@ typedef struct { static void lz_decoder_reset(lzma_coder *coder) { - coder->dict.pos = 2 * LZ_DICT_REPEAT_MAX; + coder->dict.pos = LZ_DICT_INIT_POS; coder->dict.full = 0; - coder->dict.buf[2 * LZ_DICT_REPEAT_MAX - 1] = '\0'; + coder->dict.buf[LZ_DICT_INIT_POS - 1] = '\0'; coder->dict.has_wrapped = false; coder->dict.need_reset = false; return; @@ -261,10 +261,12 @@ lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, // recommended to give aligned buffers to liblzma. // // Reserve 2 * LZ_DICT_REPEAT_MAX bytes of extra space which is - // needed for alloc_size. + // needed for alloc_size. Reserve also LZ_DICT_EXTRA bytes of extra + // space which is *not* counted in alloc_size or coder->dict.size. // // Avoid integer overflow. - if (lz_options.dict_size > SIZE_MAX - 15 - 2 * LZ_DICT_REPEAT_MAX) + if (lz_options.dict_size > SIZE_MAX - 15 - 2 * LZ_DICT_REPEAT_MAX + - LZ_DICT_EXTRA) return LZMA_MEM_ERROR; lz_options.dict_size = (lz_options.dict_size + 15) & ~((size_t)(15)); @@ -277,7 +279,13 @@ lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, // Allocate and initialize the dictionary. if (coder->dict.size != alloc_size) { lzma_free(coder->dict.buf, allocator); - coder->dict.buf = lzma_alloc(alloc_size, allocator); + + // The LZ_DICT_EXTRA bytes at the end of the buffer aren't + // included in alloc_size. These extra bytes allow + // dict_repeat() to read and write more data than requested. + // Otherwise this extra space is ignored. + coder->dict.buf = lzma_alloc(alloc_size + LZ_DICT_EXTRA, + allocator); if (coder->dict.buf == NULL) return LZMA_MEM_ERROR; @@ -320,5 +328,6 @@ lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, extern uint64_t lzma_lz_decoder_memusage(size_t dictionary_size) { - return sizeof(lzma_coder) + (uint64_t)(dictionary_size); + return sizeof(lzma_coder) + (uint64_t)(dictionary_size) + + 2 * LZ_DICT_REPEAT_MAX + LZ_DICT_EXTRA; } diff --git a/contrib/libs/lzma/liblzma/lz/lz_decoder.h b/contrib/libs/lzma/liblzma/lz/lz_decoder.h index cb61b6e24c78..2698e0167fcc 100644 --- a/contrib/libs/lzma/liblzma/lz/lz_decoder.h +++ b/contrib/libs/lzma/liblzma/lz/lz_decoder.h @@ -15,10 +15,40 @@ #include "common.h" +#ifdef HAVE_IMMINTRIN_H +# include +#endif + + +// dict_repeat() implementation variant: +// 0 = Byte-by-byte copying only. +// 1 = Use memcpy() for non-overlapping copies. +// 2 = Use x86 SSE2 for non-overlapping copies. +#ifndef LZMA_LZ_DECODER_CONFIG +# if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \ + && defined(HAVE_IMMINTRIN_H) \ + && (defined(__SSE2__) || defined(_M_X64) \ + || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) +# define LZMA_LZ_DECODER_CONFIG 2 +# else +# define LZMA_LZ_DECODER_CONFIG 1 +# endif +#endif -/// Maximum length of a match rounded up to a nice power of 2 which is -/// a good size for aligned memcpy(). The allocated dictionary buffer will -/// be 2 * LZ_DICT_REPEAT_MAX bytes larger than the actual dictionary size: +/// Byte-by-byte and memcpy() copy exactly the amount needed. Other methods +/// can copy up to LZ_DICT_EXTRA bytes more than requested, and this amount +/// of extra space is needed at the end of the allocated dictionary buffer. +/// +/// NOTE: If this is increased, update LZMA_DICT_REPEAT_MAX too. +#if LZMA_LZ_DECODER_CONFIG >= 2 +# define LZ_DICT_EXTRA 32 +#else +# define LZ_DICT_EXTRA 0 +#endif + +/// Maximum number of bytes that dict_repeat() may copy. The allocated +/// dictionary buffer will be 2 * LZ_DICT_REPEAT_MAX + LZMA_DICT_EXTRA bytes +/// larger than the actual dictionary size: /// /// (1) Every time the decoder reaches the end of the dictionary buffer, /// the last LZ_DICT_REPEAT_MAX bytes will be copied to the beginning. @@ -27,14 +57,26 @@ /// /// (2) The other LZ_DICT_REPEAT_MAX bytes is kept as a buffer between /// the oldest byte still in the dictionary and the current write -/// position. This way dict_repeat(dict, dict->size - 1, &len) +/// position. This way dict_repeat() with the maximum valid distance /// won't need memmove() as the copying cannot overlap. /// +/// (3) LZ_DICT_EXTRA bytes are required at the end of the dictionary buffer +/// so that extra copying done by dict_repeat() won't write or read past +/// the end of the allocated buffer. This amount is *not* counted as part +/// of lzma_dict.size. +/// /// Note that memcpy() still cannot be used if distance < len. /// -/// LZMA's longest match length is 273 so pick a multiple of 16 above that. +/// LZMA's longest match length is 273 bytes. The LZMA decoder looks at +/// the lowest four bits of the dictionary position, thus 273 must be +/// rounded up to the next multiple of 16 (288). In addition, optimized +/// dict_repeat() copies 32 bytes at a time, thus this must also be +/// a multiple of 32. #define LZ_DICT_REPEAT_MAX 288 +/// Initial position in lzma_dict.buf when the dictionary is empty. +#define LZ_DICT_INIT_POS (2 * LZ_DICT_REPEAT_MAX) + typedef struct { /// Pointer to the dictionary buffer. @@ -158,7 +200,8 @@ dict_is_distance_valid(const lzma_dict *const dict, const size_t distance) /// Repeat *len bytes at distance. static inline bool -dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len) +dict_repeat(lzma_dict *restrict dict, + uint32_t distance, uint32_t *restrict len) { // Don't write past the end of the dictionary. const size_t dict_avail = dict->limit - dict->pos; @@ -169,9 +212,17 @@ dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len) if (distance >= dict->pos) back += dict->size - LZ_DICT_REPEAT_MAX; - // Repeat a block of data from the history. Because memcpy() is faster - // than copying byte by byte in a loop, the copying process gets split - // into two cases. +#if LZMA_LZ_DECODER_CONFIG == 0 + // Minimal byte-by-byte method. This might be the least bad choice + // if memcpy() isn't fast and there's no replacement for it below. + while (left-- > 0) { + dict->buf[dict->pos++] = dict->buf[back++]; + } + +#else + // Because memcpy() or a similar method can be faster than copying + // byte by byte in a loop, the copying process is split into + // two cases. if (distance < left) { // Source and target areas overlap, thus we can't use // memcpy() nor even memmove() safely. @@ -179,32 +230,56 @@ dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len) dict->buf[dict->pos++] = dict->buf[back++]; } while (--left > 0); } else { +# if LZMA_LZ_DECODER_CONFIG == 1 memcpy(dict->buf + dict->pos, dict->buf + back, left); dict->pos += left; + +# elif LZMA_LZ_DECODER_CONFIG == 2 + // This can copy up to 32 bytes more than required. + // (If left == 0, we still copy 32 bytes.) + size_t pos = dict->pos; + dict->pos += left; + do { + const __m128i x0 = _mm_loadu_si128( + (__m128i *)(dict->buf + back)); + const __m128i x1 = _mm_loadu_si128( + (__m128i *)(dict->buf + back + 16)); + back += 32; + _mm_storeu_si128( + (__m128i *)(dict->buf + pos), x0); + _mm_storeu_si128( + (__m128i *)(dict->buf + pos + 16), x1); + pos += 32; + } while (pos < dict->pos); + +# else +# error "Invalid LZMA_LZ_DECODER_CONFIG value" +# endif } +#endif // Update how full the dictionary is. if (!dict->has_wrapped) - dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX; + dict->full = dict->pos - LZ_DICT_INIT_POS; return *len != 0; } static inline void -dict_put(lzma_dict *dict, uint8_t byte) +dict_put(lzma_dict *restrict dict, uint8_t byte) { dict->buf[dict->pos++] = byte; if (!dict->has_wrapped) - dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX; + dict->full = dict->pos - LZ_DICT_INIT_POS; } /// Puts one byte into the dictionary. Returns true if the dictionary was /// already full and the byte couldn't be added. static inline bool -dict_put_safe(lzma_dict *dict, uint8_t byte) +dict_put_safe(lzma_dict *restrict dict, uint8_t byte) { if (unlikely(dict->pos == dict->limit)) return true; @@ -234,7 +309,7 @@ dict_write(lzma_dict *restrict dict, const uint8_t *restrict in, dict->buf, &dict->pos, dict->limit); if (!dict->has_wrapped) - dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX; + dict->full = dict->pos - LZ_DICT_INIT_POS; return; } diff --git a/contrib/libs/lzma/liblzma/lz/lz_encoder.c b/contrib/libs/lzma/liblzma/lz/lz_encoder.c index 9e34ab4cd7f0..d2c179d9ec61 100644 --- a/contrib/libs/lzma/liblzma/lz/lz_encoder.c +++ b/contrib/libs/lzma/liblzma/lz/lz_encoder.c @@ -15,7 +15,7 @@ // See lz_encoder_hash.h. This is a bit hackish but avoids making // endianness a conditional in makefiles. -#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL) +#ifdef LZMA_LZ_HASH_TABLE_IS_NEEDED # error #include "lz_encoder_hash_table.h" #endif diff --git a/contrib/libs/lzma/liblzma/lz/lz_encoder_hash.h b/contrib/libs/lzma/liblzma/lz/lz_encoder_hash.h index 8ace82b04c51..6d4bf837fd16 100644 --- a/contrib/libs/lzma/liblzma/lz/lz_encoder_hash.h +++ b/contrib/libs/lzma/liblzma/lz/lz_encoder_hash.h @@ -5,23 +5,37 @@ /// \file lz_encoder_hash.h /// \brief Hash macros for match finders // -// Author: Igor Pavlov +// Authors: Igor Pavlov +// Lasse Collin // /////////////////////////////////////////////////////////////////////////////// #ifndef LZMA_LZ_ENCODER_HASH_H #define LZMA_LZ_ENCODER_HASH_H -#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL) - // This is to make liblzma produce the same output on big endian - // systems that it does on little endian systems. lz_encoder.c - // takes care of including the actual table. +// We need to know if CRC32_GENERIC is defined and we may need the declaration +// of lzma_crc32_table[][]. +#include "crc_common.h" + +// If HAVE_SMALL is defined, then lzma_crc32_table[][] exists and +// it's little endian even on big endian systems. +// +// If HAVE_SMALL isn't defined, lzma_crc32_table[][] is in native endian +// but we want a little endian one so that the compressed output won't +// depend on the processor endianness. Big endian systems are less common +// so those get the burden of an extra 1 KiB table. +// +// If HAVE_SMALL isn't defined and CRC32_GENERIC isn't defined either, +// then lzma_crc32_table[][] doesn't exist. +#if defined(HAVE_SMALL) \ + || (defined(CRC32_GENERIC) && !defined(WORDS_BIGENDIAN)) +# define hash_table lzma_crc32_table[0] +#else + // lz_encoder.c takes care of including the actual table. lzma_attr_visibility_hidden extern const uint32_t lzma_lz_hash_table[256]; # define hash_table lzma_lz_hash_table -#else -# include "check.h" -# define hash_table lzma_crc32_table[0] +# define LZMA_LZ_HASH_TABLE_IS_NEEDED 1 #endif #define HASH_2_SIZE (UINT32_C(1) << 10) diff --git a/contrib/libs/lzma/liblzma/lzma/lzma2_encoder.c b/contrib/libs/lzma/liblzma/lzma/lzma2_encoder.c index e20b75b30037..71cfd9b4114e 100644 --- a/contrib/libs/lzma/liblzma/lzma/lzma2_encoder.c +++ b/contrib/libs/lzma/liblzma/lzma/lzma2_encoder.c @@ -159,8 +159,7 @@ lzma2_encode(void *coder_ptr, lzma_mf *restrict mf, coder->uncompressed_size = 0; coder->compressed_size = 0; coder->sequence = SEQ_LZMA_ENCODE; - - // Fall through + FALLTHROUGH; case SEQ_LZMA_ENCODE: { // Calculate how much more uncompressed data this chunk @@ -219,10 +218,9 @@ lzma2_encode(void *coder_ptr, lzma_mf *restrict mf, lzma2_header_lzma(coder); coder->sequence = SEQ_LZMA_COPY; + FALLTHROUGH; } - // Fall through - case SEQ_LZMA_COPY: // Copy the compressed chunk along its headers to the // output buffer. @@ -244,8 +242,7 @@ lzma2_encode(void *coder_ptr, lzma_mf *restrict mf, return LZMA_OK; coder->sequence = SEQ_UNCOMPRESSED_COPY; - - // Fall through + FALLTHROUGH; case SEQ_UNCOMPRESSED_COPY: // Copy the uncompressed data as is from the dictionary diff --git a/contrib/libs/lzma/liblzma/simple/arm.c b/contrib/libs/lzma/liblzma/simple/arm.c index 58acb2d11adf..f9d9c08b3c42 100644 --- a/contrib/libs/lzma/liblzma/simple/arm.c +++ b/contrib/libs/lzma/liblzma/simple/arm.c @@ -18,8 +18,10 @@ arm_code(void *simple lzma_attribute((__unused__)), uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) { + size &= ~(size_t)3; + size_t i; - for (i = 0; i + 4 <= size; i += 4) { + for (i = 0; i < size; i += 4) { if (buffer[i + 3] == 0xEB) { uint32_t src = ((uint32_t)(buffer[i + 2]) << 16) | ((uint32_t)(buffer[i + 1]) << 8) diff --git a/contrib/libs/lzma/liblzma/simple/arm64.c b/contrib/libs/lzma/liblzma/simple/arm64.c index 16c2f565f73d..2ec10d937fbd 100644 --- a/contrib/libs/lzma/liblzma/simple/arm64.c +++ b/contrib/libs/lzma/liblzma/simple/arm64.c @@ -28,6 +28,8 @@ arm64_code(void *simple lzma_attribute((__unused__)), uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) { + size &= ~(size_t)3; + size_t i; // Clang 14.0.6 on x86-64 makes this four times bigger and 40 % slower @@ -37,7 +39,7 @@ arm64_code(void *simple lzma_attribute((__unused__)), #ifdef __clang__ # pragma clang loop vectorize(disable) #endif - for (i = 0; i + 4 <= size; i += 4) { + for (i = 0; i < size; i += 4) { uint32_t pc = (uint32_t)(now_pos + i); uint32_t instr = read32le(buffer + i); @@ -122,6 +124,15 @@ lzma_simple_arm64_encoder_init(lzma_next_coder *next, { return arm64_coder_init(next, allocator, filters, true); } + + +extern LZMA_API(size_t) +lzma_bcj_arm64_encode(uint32_t start_offset, uint8_t *buf, size_t size) +{ + // start_offset must be a multiple of four. + start_offset &= ~UINT32_C(3); + return arm64_code(NULL, start_offset, true, buf, size); +} #endif @@ -133,4 +144,13 @@ lzma_simple_arm64_decoder_init(lzma_next_coder *next, { return arm64_coder_init(next, allocator, filters, false); } + + +extern LZMA_API(size_t) +lzma_bcj_arm64_decode(uint32_t start_offset, uint8_t *buf, size_t size) +{ + // start_offset must be a multiple of four. + start_offset &= ~UINT32_C(3); + return arm64_code(NULL, start_offset, false, buf, size); +} #endif diff --git a/contrib/libs/lzma/liblzma/simple/armthumb.c b/contrib/libs/lzma/liblzma/simple/armthumb.c index f1eeca9b80f1..368b51c7fea9 100644 --- a/contrib/libs/lzma/liblzma/simple/armthumb.c +++ b/contrib/libs/lzma/liblzma/simple/armthumb.c @@ -18,8 +18,13 @@ armthumb_code(void *simple lzma_attribute((__unused__)), uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) { + if (size < 4) + return 0; + + size -= 4; + size_t i; - for (i = 0; i + 4 <= size; i += 2) { + for (i = 0; i <= size; i += 2) { if ((buffer[i + 1] & 0xF8) == 0xF0 && (buffer[i + 3] & 0xF8) == 0xF8) { uint32_t src = (((uint32_t)(buffer[i + 1]) & 7) << 19) diff --git a/contrib/libs/lzma/liblzma/simple/ia64.c b/contrib/libs/lzma/liblzma/simple/ia64.c index 502501409977..2a4aaebb4720 100644 --- a/contrib/libs/lzma/liblzma/simple/ia64.c +++ b/contrib/libs/lzma/liblzma/simple/ia64.c @@ -25,8 +25,10 @@ ia64_code(void *simple lzma_attribute((__unused__)), 4, 4, 0, 0, 4, 4, 0, 0 }; + size &= ~(size_t)15; + size_t i; - for (i = 0; i + 16 <= size; i += 16) { + for (i = 0; i < size; i += 16) { const uint32_t instr_template = buffer[i] & 0x1F; const uint32_t mask = BRANCH_TABLE[instr_template]; uint32_t bit_pos = 5; diff --git a/contrib/libs/lzma/liblzma/simple/powerpc.c b/contrib/libs/lzma/liblzma/simple/powerpc.c index ba6cfbef3ab6..ea47d14d4c3f 100644 --- a/contrib/libs/lzma/liblzma/simple/powerpc.c +++ b/contrib/libs/lzma/liblzma/simple/powerpc.c @@ -18,8 +18,10 @@ powerpc_code(void *simple lzma_attribute((__unused__)), uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) { + size &= ~(size_t)3; + size_t i; - for (i = 0; i + 4 <= size; i += 4) { + for (i = 0; i < size; i += 4) { // PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link) if ((buffer[i] >> 2) == 0x12 && ((buffer[i + 3] & 3) == 1)) { diff --git a/contrib/libs/lzma/liblzma/simple/riscv.c b/contrib/libs/lzma/liblzma/simple/riscv.c index b18df8b637d0..bc97ebdbb0fb 100644 --- a/contrib/libs/lzma/liblzma/simple/riscv.c +++ b/contrib/libs/lzma/liblzma/simple/riscv.c @@ -617,6 +617,15 @@ lzma_simple_riscv_encoder_init(lzma_next_coder *next, return lzma_simple_coder_init(next, allocator, filters, &riscv_encode, 0, 8, 2, true); } + + +extern LZMA_API(size_t) +lzma_bcj_riscv_encode(uint32_t start_offset, uint8_t *buf, size_t size) +{ + // start_offset must be a multiple of two. + start_offset &= ~UINT32_C(1); + return riscv_encode(NULL, start_offset, true, buf, size); +} #endif @@ -752,4 +761,13 @@ lzma_simple_riscv_decoder_init(lzma_next_coder *next, return lzma_simple_coder_init(next, allocator, filters, &riscv_decode, 0, 8, 2, false); } + + +extern LZMA_API(size_t) +lzma_bcj_riscv_decode(uint32_t start_offset, uint8_t *buf, size_t size) +{ + // start_offset must be a multiple of two. + start_offset &= ~UINT32_C(1); + return riscv_decode(NULL, start_offset, false, buf, size); +} #endif diff --git a/contrib/libs/lzma/liblzma/simple/sparc.c b/contrib/libs/lzma/liblzma/simple/sparc.c index e8ad285a1927..1fa4850458e8 100644 --- a/contrib/libs/lzma/liblzma/simple/sparc.c +++ b/contrib/libs/lzma/liblzma/simple/sparc.c @@ -18,9 +18,10 @@ sparc_code(void *simple lzma_attribute((__unused__)), uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) { - size_t i; - for (i = 0; i + 4 <= size; i += 4) { + size &= ~(size_t)3; + size_t i; + for (i = 0; i < size; i += 4) { if ((buffer[i] == 0x40 && (buffer[i + 1] & 0xC0) == 0x00) || (buffer[i] == 0x7F && (buffer[i + 1] & 0xC0) == 0xC0)) { diff --git a/contrib/libs/lzma/liblzma/simple/x86.c b/contrib/libs/lzma/liblzma/simple/x86.c index f216231f2d12..dffa7863131a 100644 --- a/contrib/libs/lzma/liblzma/simple/x86.c +++ b/contrib/libs/lzma/liblzma/simple/x86.c @@ -143,6 +143,18 @@ lzma_simple_x86_encoder_init(lzma_next_coder *next, { return x86_coder_init(next, allocator, filters, true); } + + +extern LZMA_API(size_t) +lzma_bcj_x86_encode(uint32_t start_offset, uint8_t *buf, size_t size) +{ + lzma_simple_x86 simple = { + .prev_mask = 0, + .prev_pos = (uint32_t)(-5), + }; + + return x86_code(&simple, start_offset, true, buf, size); +} #endif @@ -154,4 +166,16 @@ lzma_simple_x86_decoder_init(lzma_next_coder *next, { return x86_coder_init(next, allocator, filters, false); } + + +extern LZMA_API(size_t) +lzma_bcj_x86_decode(uint32_t start_offset, uint8_t *buf, size_t size) +{ + lzma_simple_x86 simple = { + .prev_mask = 0, + .prev_pos = (uint32_t)(-5), + }; + + return x86_code(&simple, start_offset, false, buf, size); +} #endif diff --git a/contrib/libs/lzma/ya.make b/contrib/libs/lzma/ya.make index 60d612bae155..b49400efaa5d 100644 --- a/contrib/libs/lzma/ya.make +++ b/contrib/libs/lzma/ya.make @@ -1,19 +1,18 @@ -# Generated by devtools/yamaker from nixpkgs 22.11. +# Generated by devtools/yamaker from nixpkgs 24.05. LIBRARY() LICENSE( 0BSD AND - BSD-2-Clause AND BSD-3-Clause AND Public-Domain ) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(5.6.4) +VERSION(5.8.1) -ORIGINAL_SOURCE(https://github.com/tukaani-project/xz/archive/v5.6.4.tar.gz) +ORIGINAL_SOURCE(https://github.com/tukaani-project/xz/archive/v5.8.1.tar.gz) ADDINCL( GLOBAL contrib/libs/lzma/liblzma/api @@ -43,9 +42,7 @@ SRCS( common/tuklib_physmem.c liblzma/check/check.c liblzma/check/crc32_fast.c - liblzma/check/crc32_table.c liblzma/check/crc64_fast.c - liblzma/check/crc64_table.c liblzma/check/sha256.c liblzma/common/alone_decoder.c liblzma/common/alone_encoder.c diff --git a/contrib/libs/snappy/.yandex_meta/override.nix b/contrib/libs/snappy/.yandex_meta/override.nix index 4ec7e2a3fce1..45b24b0a1a6c 100644 --- a/contrib/libs/snappy/.yandex_meta/override.nix +++ b/contrib/libs/snappy/.yandex_meta/override.nix @@ -1,11 +1,11 @@ pkgs: attrs: with pkgs; with attrs; rec { - version = "1.2.1"; + version = "1.2.2"; src = fetchFromGitHub { owner = "google"; repo = "snappy"; rev = version; - hash = "sha256-IzKzrMDjh+Weor+OrKdX62cAKYTdDXgldxCgNE2/8vk="; + hash = "sha256-bMZD8EI9dvDGupfos4hi/0ShBkrJlI5Np9FxE6FfrNE="; }; patches = []; diff --git a/contrib/libs/snappy/NEWS b/contrib/libs/snappy/NEWS index 792a578001df..ef935ba52fa2 100644 --- a/contrib/libs/snappy/NEWS +++ b/contrib/libs/snappy/NEWS @@ -1,3 +1,18 @@ +Snappy v1.2.2, Mar 26th 2025: + + * We added a new compression level in v1.2.1 which compresses a bit + denser but slower. Decompression speed should be even faster with it. + + * We fixed a very old issue of data corruption when compressed size + exceeds 4GB. This can happen when you compress data close to 4GB + and it's incompressible, for example, random data. + + * Started to use minimum CMake 3.10 because older ones are not + planned to be supported. + + * Various other small fixes and performance improvements (especially + for clang). + Snappy v1.1.10, Mar 8th 2023: * Performance improvements diff --git a/contrib/libs/snappy/README.md b/contrib/libs/snappy/README.md index 398be7d58a6d..9b4a49405c50 100644 --- a/contrib/libs/snappy/README.md +++ b/contrib/libs/snappy/README.md @@ -140,10 +140,10 @@ explicitly supports the following: 1. C++11 2. Clang (gcc and MSVC are best-effort). 3. Low level optimizations (e.g. assembly or equivalent intrinsics) for: - 1. [x86](https://en.wikipedia.org/wiki/X86) - 2. [x86-64](https://en.wikipedia.org/wiki/X86-64) - 3. ARMv7 (32-bit) - 4. ARMv8 (AArch64) + - [x86](https://en.wikipedia.org/wiki/X86) + - [x86-64](https://en.wikipedia.org/wiki/X86-64) + - ARMv7 (32-bit) + - ARMv8 (AArch64) 4. Supports only the Snappy compression scheme as described in [format_description.txt](format_description.txt). 5. CMake for building diff --git a/contrib/libs/snappy/snappy-stubs-public.h b/contrib/libs/snappy/snappy-stubs-public.h index bc2a26a56c4b..a2dec74dcc2c 100644 --- a/contrib/libs/snappy/snappy-stubs-public.h +++ b/contrib/libs/snappy/snappy-stubs-public.h @@ -44,7 +44,7 @@ #define SNAPPY_MAJOR 1 #define SNAPPY_MINOR 2 -#define SNAPPY_PATCHLEVEL 1 +#define SNAPPY_PATCHLEVEL 2 #define SNAPPY_VERSION \ ((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL) diff --git a/contrib/libs/snappy/snappy.cc b/contrib/libs/snappy/snappy.cc index a7b93f0f78e2..5a326eb40855 100644 --- a/contrib/libs/snappy/snappy.cc +++ b/contrib/libs/snappy/snappy.cc @@ -74,6 +74,7 @@ #include #include #include +#include #include #include #include @@ -1499,7 +1500,7 @@ class SnappyDecompressor { // If ip < ip_limit_min_maxtaglen_ it's safe to read kMaxTagLength from // buffer. const char* ip_limit_min_maxtaglen_; - uint32_t peeked_; // Bytes peeked from reader (need to skip) + uint64_t peeked_; // Bytes peeked from reader (need to skip) bool eof_; // Hit end of input without an error? char scratch_[kMaximumTagLength]; // See RefillTag(). @@ -1690,7 +1691,8 @@ constexpr uint32_t CalculateNeeded(uint8_t tag) { #if __cplusplus >= 201402L constexpr bool VerifyCalculateNeeded() { for (int i = 0; i < 1; i++) { - if (CalculateNeeded(i) != (char_table[i] >> 11) + 1) return false; + if (CalculateNeeded(i) != static_cast((char_table[i] >> 11)) + 1) + return false; } return true; } @@ -1726,7 +1728,7 @@ bool SnappyDecompressor::RefillTag() { assert(needed <= sizeof(scratch_)); // Read more bytes from reader if needed - uint32_t nbuf = ip_limit_ - ip; + uint64_t nbuf = ip_limit_ - ip; if (nbuf < needed) { // Stitch together bytes from ip and reader to form the word // contents. We store the needed bytes in "scratch_". They @@ -1739,7 +1741,7 @@ bool SnappyDecompressor::RefillTag() { size_t length; const char* src = reader_->Peek(&length); if (length == 0) return false; - uint32_t to_add = std::min(needed - nbuf, length); + uint64_t to_add = std::min(needed - nbuf, length); std::memcpy(scratch_ + nbuf, src, to_add); nbuf += to_add; reader_->Skip(to_add); @@ -1802,6 +1804,7 @@ size_t Compress(Source* reader, Sink* writer, CompressionOptions options) { int token = 0; size_t written = 0; size_t N = reader->Available(); + assert(N <= 0xFFFFFFFFu); const size_t uncompressed_size = N; char ulength[Varint::kMax32]; char* p = Varint::Encode32(ulength, N); diff --git a/contrib/libs/snappy/ya.make b/contrib/libs/snappy/ya.make index f2bc4c7f1ab5..ff6546925f40 100644 --- a/contrib/libs/snappy/ya.make +++ b/contrib/libs/snappy/ya.make @@ -6,9 +6,9 @@ LICENSE(BSD-3-Clause) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(1.2.1) +VERSION(1.2.2) -ORIGINAL_SOURCE(https://github.com/google/snappy/archive/1.2.1.tar.gz) +ORIGINAL_SOURCE(https://github.com/google/snappy/archive/1.2.2.tar.gz) PEERDIR( library/cpp/sanitizer/include diff --git a/contrib/python/allure-pytest/.dist-info/METADATA b/contrib/python/allure-pytest/.dist-info/METADATA index 475b85808756..069d5d6901ed 100644 --- a/contrib/python/allure-pytest/.dist-info/METADATA +++ b/contrib/python/allure-pytest/.dist-info/METADATA @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.4 Name: allure-pytest -Version: 2.13.5 +Version: 2.14.0 Summary: Allure pytest integration Home-page: https://allurereport.org/ Author: Qameta Software Inc., Stanislav Seliverstov @@ -17,15 +17,26 @@ Classifier: Topic :: Software Development :: Quality Assurance Classifier: Topic :: Software Development :: Testing Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 Description-Content-Type: text/markdown -Requires-Dist: pytest >=4.5.0 -Requires-Dist: allure-python-commons ==2.13.5 +Requires-Dist: pytest>=4.5.0 +Requires-Dist: allure-python-commons==2.14.0 +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: description-content-type +Dynamic: home-page +Dynamic: keywords +Dynamic: license +Dynamic: project-url +Dynamic: requires-dist +Dynamic: summary ## Allure Pytest Plugin diff --git a/contrib/python/allure-pytest/ya.make b/contrib/python/allure-pytest/ya.make index 68c2880e5d2d..f3530d056748 100644 --- a/contrib/python/allure-pytest/ya.make +++ b/contrib/python/allure-pytest/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(2.13.5) +VERSION(2.14.0) LICENSE(Apache-2.0) diff --git a/contrib/python/allure-python-commons/.dist-info/METADATA b/contrib/python/allure-python-commons/.dist-info/METADATA index 94cd97681a84..b79879133e79 100644 --- a/contrib/python/allure-python-commons/.dist-info/METADATA +++ b/contrib/python/allure-python-commons/.dist-info/METADATA @@ -1,7 +1,7 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.4 Name: allure-python-commons -Version: 2.13.5 -Summary: ('Contains the API for end users as well as helper functions and classes to build Allure adapters for Python test frameworks',) +Version: 2.14.0 +Summary: Contains the API for end users as well as helper functions and classes to build Allure adapters for Python test frameworks Home-page: https://allurereport.org/ Author: Qameta Software Inc., Stanislav Seliverstov Author-email: sseliverstov@qameta.io @@ -15,16 +15,28 @@ Classifier: Topic :: Software Development :: Quality Assurance Classifier: Topic :: Software Development :: Testing Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 Requires-Python: >=3.6 Description-Content-Type: text/markdown -Requires-Dist: attrs >=16.0.0 -Requires-Dist: pluggy >=0.4.0 +Requires-Dist: attrs>=16.0.0 +Requires-Dist: pluggy>=0.4.0 +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: description-content-type +Dynamic: home-page +Dynamic: keywords +Dynamic: license +Dynamic: project-url +Dynamic: requires-dist +Dynamic: requires-python +Dynamic: summary ## Allure Common API diff --git a/contrib/python/allure-python-commons/allure.py b/contrib/python/allure-python-commons/allure.py deleted file mode 100644 index 4acb83e37a3d..000000000000 --- a/contrib/python/allure-python-commons/allure.py +++ /dev/null @@ -1,43 +0,0 @@ -from allure_commons._allure import title -from allure_commons._allure import description, description_html -from allure_commons._allure import label -from allure_commons._allure import severity -from allure_commons._allure import tag -from allure_commons._allure import id -from allure_commons._allure import suite, parent_suite, sub_suite -from allure_commons._allure import epic, feature, story -from allure_commons._allure import link, issue, testcase -from allure_commons._allure import Dynamic as dynamic -from allure_commons._allure import step -from allure_commons._allure import attach -from allure_commons._allure import manual -from allure_commons.types import Severity as severity_level -from allure_commons.types import AttachmentType as attachment_type -from allure_commons.types import ParameterMode as parameter_mode - - -__all__ = [ - 'title', - 'description', - 'description_html', - 'label', - 'severity', - 'suite', - 'parent_suite', - 'sub_suite', - 'tag', - 'id', - 'epic', - 'feature', - 'story', - 'link', - 'issue', - 'testcase', - 'manual', - 'step', - 'dynamic', - 'severity_level', - 'attach', - 'attachment_type', - 'parameter_mode' -] diff --git a/contrib/python/allure-python-commons/allure/__init__.py b/contrib/python/allure-python-commons/allure/__init__.py new file mode 100644 index 000000000000..c30329a6e8ad --- /dev/null +++ b/contrib/python/allure-python-commons/allure/__init__.py @@ -0,0 +1,43 @@ +from allure_commons._allure import title +from allure_commons._allure import description, description_html +from allure_commons._allure import label +from allure_commons._allure import severity +from allure_commons._allure import tag +from allure_commons._allure import id # noqa: A004 +from allure_commons._allure import suite, parent_suite, sub_suite +from allure_commons._allure import epic, feature, story +from allure_commons._allure import link, issue, testcase +from allure_commons._allure import Dynamic as dynamic +from allure_commons._allure import step +from allure_commons._allure import attach +from allure_commons._allure import manual +from allure_commons.types import Severity as severity_level +from allure_commons.types import AttachmentType as attachment_type +from allure_commons.types import ParameterMode as parameter_mode + + +__all__ = [ + 'title', + 'description', + 'description_html', + 'label', + 'severity', + 'suite', + 'parent_suite', + 'sub_suite', + 'tag', + 'id', + 'epic', + 'feature', + 'story', + 'link', + 'issue', + 'testcase', + 'manual', + 'step', + 'dynamic', + 'severity_level', + 'attach', + 'attachment_type', + 'parameter_mode' +] diff --git a/contrib/python/allure-python-commons/allure/py.typed b/contrib/python/allure-python-commons/allure/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/python/allure-python-commons/allure_commons/_allure.py b/contrib/python/allure-python-commons/allure_commons/_allure.py index 05e01dbd4be9..b7bbe2a5e079 100644 --- a/contrib/python/allure-python-commons/allure_commons/_allure.py +++ b/contrib/python/allure-python-commons/allure_commons/_allure.py @@ -1,5 +1,5 @@ from functools import wraps -from typing import Any, Callable, TypeVar +from typing import Any, Callable, TypeVar, Union, overload from allure_commons._core import plugin_manager from allure_commons.types import LabelType, LinkType, ParameterMode @@ -133,7 +133,7 @@ def link(url, link_type=LinkType.LINK, name=None): plugin_manager.hook.add_link(url=url, link_type=link_type, name=name) @staticmethod - def parameter(name, value, excluded=None, mode: ParameterMode = None): + def parameter(name, value, excluded=None, mode: Union[ParameterMode, None] = None): plugin_manager.hook.add_parameter(name=name, value=value, excluded=excluded, mode=mode) @staticmethod @@ -161,6 +161,16 @@ def manual(): return Dynamic.label(LabelType.MANUAL, True) +@overload +def step(title: str) -> "StepContext": + ... + + +@overload +def step(title: _TFunc) -> _TFunc: + ... + + def step(title): if callable(title): return StepContext(title.__name__, {})(title) @@ -191,7 +201,7 @@ def impl(*a, **kw): with StepContext(self.title.format(*args, **params), params): return func(*a, **kw) - return impl + return impl # type: ignore class Attach: diff --git a/contrib/python/allure-python-commons/allure_commons/logger.py b/contrib/python/allure-python-commons/allure_commons/logger.py index d0ac1e2491b5..55f956f25071 100644 --- a/contrib/python/allure-python-commons/allure_commons/logger.py +++ b/contrib/python/allure-python-commons/allure_commons/logger.py @@ -15,7 +15,7 @@ class AllureFileLogger: def __init__(self, report_dir, clean=False): self._report_dir = Path(report_dir).absolute() if self._report_dir.is_dir() and clean: - shutil.rmtree(self._report_dir) + shutil.rmtree(self._report_dir, ignore_errors=True) self._report_dir.mkdir(parents=True, exist_ok=True) def _report_item(self, item): diff --git a/contrib/python/allure-python-commons/allure_commons/model2.py b/contrib/python/allure-python-commons/allure_commons/model2.py index e8fd330a0b09..ccaf4459d6a7 100644 --- a/contrib/python/allure-python-commons/allure_commons/model2.py +++ b/contrib/python/allure-python-commons/allure_commons/model2.py @@ -53,7 +53,7 @@ class TestResult(ExecutableItem): @attrs class TestStepResult(ExecutableItem): - id = attrib(default=None) + id = attrib(default=None) # noqa: A003 @attrs @@ -82,7 +82,7 @@ class Label: @attrs class Link: - type = attrib(default=None) + type = attrib(default=None) # noqa: A003 url = attrib(default=None) name = attrib(default=None) @@ -99,7 +99,7 @@ class StatusDetails: class Attachment: name = attrib(default=None) source = attrib(default=None) - type = attrib(default=None) + type = attrib(default=None) # noqa: A003 class Status: diff --git a/contrib/python/allure-python-commons/allure_commons/py.typed b/contrib/python/allure-python-commons/allure_commons/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/python/allure-python-commons/allure_commons/types.py b/contrib/python/allure-python-commons/allure_commons/types.py index 06b77dfa151c..e631e427c60a 100644 --- a/contrib/python/allure-python-commons/allure_commons/types.py +++ b/contrib/python/allure-python-commons/allure_commons/types.py @@ -53,7 +53,7 @@ def __init__(self, mime_type, extension): PNG = ("image/png", "png") JPG = ("image/jpg", "jpg") - SVG = ("image/svg-xml", "svg") + SVG = ("image/svg+xml", "svg") GIF = ("image/gif", "gif") BMP = ("image/bmp", "bmp") TIFF = ("image/tiff", "tiff") diff --git a/contrib/python/allure-python-commons/ya.make b/contrib/python/allure-python-commons/ya.make index 7f3ae9bda734..65be7572db6f 100644 --- a/contrib/python/allure-python-commons/ya.make +++ b/contrib/python/allure-python-commons/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(2.13.5) +VERSION(2.14.0) LICENSE(Apache-2.0) @@ -15,7 +15,7 @@ NO_LINT() PY_SRCS( TOP_LEVEL - allure.py + allure/__init__.py allure_commons/__init__.py allure_commons/_allure.py allure_commons/_core.py @@ -33,6 +33,8 @@ RESOURCE_FILES( PREFIX contrib/python/allure-python-commons/ .dist-info/METADATA .dist-info/top_level.txt + allure/py.typed + allure_commons/py.typed ) END() diff --git a/contrib/python/argcomplete/py3/.dist-info/METADATA b/contrib/python/argcomplete/py3/.dist-info/METADATA index 8eff29ade2e6..c8d45d5d1524 100644 --- a/contrib/python/argcomplete/py3/.dist-info/METADATA +++ b/contrib/python/argcomplete/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: argcomplete -Version: 3.6.1 +Version: 3.6.2 Summary: Bash tab completion for argparse Project-URL: Homepage, https://github.com/kislyuk/argcomplete Project-URL: Documentation, https://kislyuk.github.io/argcomplete diff --git a/contrib/python/argcomplete/py3/argcomplete/bash_completion.d/_python-argcomplete b/contrib/python/argcomplete/py3/argcomplete/bash_completion.d/_python-argcomplete index 8a91272dea4d..81c9d41f803d 100644 --- a/contrib/python/argcomplete/py3/argcomplete/bash_completion.d/_python-argcomplete +++ b/contrib/python/argcomplete/py3/argcomplete/bash_completion.d/_python-argcomplete @@ -124,12 +124,6 @@ __python_argcomplete_which() { _python_argcomplete_global() { if [[ -n "${ZSH_VERSION-}" ]]; then - if [[ "${_matcher_num-}" -gt 1 ]]; then - # Return early if the completer is called multiple times in the same completion run. - # Currently the only known occurrence of this is in zsh when a matcher-list zstyle is declared. - # When this happens, _matcher_num is incremented past 1. - return - fi # Store result of a regex match in the # BASH_REMATCH variable rather than MATCH setopt local_options BASH_REMATCH diff --git a/contrib/python/argcomplete/py3/argcomplete/scripts/activate_global_python_argcomplete.py b/contrib/python/argcomplete/py3/argcomplete/scripts/activate_global_python_argcomplete.py index 299d081c0ea8..8e7d27de6cdb 100644 --- a/contrib/python/argcomplete/py3/argcomplete/scripts/activate_global_python_argcomplete.py +++ b/contrib/python/argcomplete/py3/argcomplete/scripts/activate_global_python_argcomplete.py @@ -121,10 +121,12 @@ def append_to_config_file(path, shellcode): fh.write(shellcode) print("Added.", file=sys.stderr) + def link_zsh_user_rcfile(zsh_fpath=None): zsh_rcfile = os.path.join(os.path.expanduser(os.environ.get("ZDOTDIR", "~")), ".zshenv") append_to_config_file(zsh_rcfile, zsh_shellcode.format(zsh_fpath=zsh_fpath or get_activator_dir())) + def link_bash_user_rcfile(): bash_completion_user_file = os.path.expanduser("~/.bash_completion") append_to_config_file(bash_completion_user_file, bash_shellcode.format(activator=get_activator_path())) @@ -135,6 +137,7 @@ def link_user_rcfiles(): link_zsh_user_rcfile() link_bash_user_rcfile() + def add_zsh_system_dir_to_fpath_for_user(): if "zsh" not in os.environ.get("SHELL", ""): return @@ -148,6 +151,7 @@ def add_zsh_system_dir_to_fpath_for_user(): except (FileNotFoundError, subprocess.CalledProcessError): pass + def main(): global args args = parser.parse_args() diff --git a/contrib/python/argcomplete/py3/argcomplete/shell_integration.py b/contrib/python/argcomplete/py3/argcomplete/shell_integration.py index cac48902fa7a..3d592dc0ab84 100644 --- a/contrib/python/argcomplete/py3/argcomplete/shell_integration.py +++ b/contrib/python/argcomplete/py3/argcomplete/shell_integration.py @@ -34,12 +34,6 @@ local IFS=$'\013' local script="%(argcomplete_script)s" if [[ -n "${ZSH_VERSION-}" ]]; then - if [[ "${_matcher_num-}" -gt 1 ]]; then - # Return early if the completer is called multiple times in the same completion run. - # Currently the only known occurrence of this is in zsh when a matcher-list zstyle is declared. - # When this happens, _matcher_num is incremented past 1. - return - fi local completions completions=($(IFS="$IFS" \ COMP_LINE="$BUFFER" \ diff --git a/contrib/python/argcomplete/py3/ya.make b/contrib/python/argcomplete/py3/ya.make index 327bc4e34ede..6d1fd0844717 100644 --- a/contrib/python/argcomplete/py3/ya.make +++ b/contrib/python/argcomplete/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(3.6.1) +VERSION(3.6.2) LICENSE(Apache-2.0) diff --git a/contrib/python/lz4/py3/.dist-info/METADATA b/contrib/python/lz4/py3/.dist-info/METADATA index ff7ade455933..a57e6022a3fd 100644 --- a/contrib/python/lz4/py3/.dist-info/METADATA +++ b/contrib/python/lz4/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ -Metadata-Version: 2.2 +Metadata-Version: 2.4 Name: lz4 -Version: 4.4.3 +Version: 4.4.4 Summary: LZ4 Bindings for Python Home-page: https://github.com/python-lz4/python-lz4 Author: Jonathan Underwood @@ -31,6 +31,7 @@ Dynamic: author-email Dynamic: classifier Dynamic: description Dynamic: home-page +Dynamic: license-file Dynamic: provides-extra Dynamic: requires-python Dynamic: summary diff --git a/contrib/python/lz4/py3/lz4/version.py b/contrib/python/lz4/py3/lz4/version.py index a6ed78c6c3e4..2808f61053d7 100644 --- a/contrib/python/lz4/py3/lz4/version.py +++ b/contrib/python/lz4/py3/lz4/version.py @@ -1,8 +1,13 @@ -# file generated by setuptools_scm +# file generated by setuptools-scm # don't change, don't track in version control + +__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"] + TYPE_CHECKING = False if TYPE_CHECKING: - from typing import Tuple, Union + from typing import Tuple + from typing import Union + VERSION_TUPLE = Tuple[Union[int, str], ...] else: VERSION_TUPLE = object @@ -12,5 +17,5 @@ __version_tuple__: VERSION_TUPLE version_tuple: VERSION_TUPLE -__version__ = version = '4.4.3' -__version_tuple__ = version_tuple = (4, 4, 3) +__version__ = version = '4.4.4' +__version_tuple__ = version_tuple = (4, 4, 4) diff --git a/contrib/python/lz4/py3/ya.make b/contrib/python/lz4/py3/ya.make index c25e89eb0004..90442055a368 100644 --- a/contrib/python/lz4/py3/ya.make +++ b/contrib/python/lz4/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(4.4.3) +VERSION(4.4.4) LICENSE(BSD-3-Clause) diff --git a/contrib/python/multidict/.dist-info/METADATA b/contrib/python/multidict/.dist-info/METADATA index b5c6dad90ba6..9ee0987b9db0 100644 --- a/contrib/python/multidict/.dist-info/METADATA +++ b/contrib/python/multidict/.dist-info/METADATA @@ -1,6 +1,6 @@ -Metadata-Version: 2.2 +Metadata-Version: 2.4 Name: multidict -Version: 6.2.0 +Version: 6.4.3 Summary: multidict implementation Home-page: https://github.com/aio-libs/multidict Author: Andrew Svetlov @@ -29,6 +29,7 @@ Requires-Python: >=3.9 Description-Content-Type: text/x-rst License-File: LICENSE Requires-Dist: typing-extensions>=4.1.0; python_version < "3.11" +Dynamic: license-file ========= multidict @@ -38,8 +39,8 @@ multidict :target: https://github.com/aio-libs/multidict/actions :alt: GitHub status for master branch -.. image:: https://codecov.io/gh/aio-libs/multidict/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/multidict +.. image:: https://codecov.io/gh/aio-libs/multidict/branch/master/graph/badge.svg?flag=pytest + :target: https://codecov.io/gh/aio-libs/multidict?flags[]=pytest :alt: Coverage metrics .. image:: https://img.shields.io/pypi/v/multidict.svg @@ -50,6 +51,10 @@ multidict :target: https://multidict.aio-libs.org :alt: Read The Docs build status badge +.. image:: https://img.shields.io/endpoint?url=https://codspeed.io/badge.json + :target: https://codspeed.io/aio-libs/multidict + :alt: CodSpeed + .. image:: https://img.shields.io/pypi/pyversions/multidict.svg :target: https://pypi.org/project/multidict :alt: Python versions @@ -132,7 +137,12 @@ e.g.: Please note, the pure Python (uncompiled) version is about 20-50 times slower depending on the usage scenario!!! +For extension development, set the ``MULTIDICT_DEBUG_BUILD`` environment variable to compile +the extensions in debug mode: + +.. code-block:: console + $ MULTIDICT_DEBUG_BUILD=1 pip install multidict Changelog --------- diff --git a/contrib/python/multidict/README.rst b/contrib/python/multidict/README.rst index 40d84b858510..50a7f041b596 100644 --- a/contrib/python/multidict/README.rst +++ b/contrib/python/multidict/README.rst @@ -6,8 +6,8 @@ multidict :target: https://github.com/aio-libs/multidict/actions :alt: GitHub status for master branch -.. image:: https://codecov.io/gh/aio-libs/multidict/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/multidict +.. image:: https://codecov.io/gh/aio-libs/multidict/branch/master/graph/badge.svg?flag=pytest + :target: https://codecov.io/gh/aio-libs/multidict?flags[]=pytest :alt: Coverage metrics .. image:: https://img.shields.io/pypi/v/multidict.svg @@ -18,6 +18,10 @@ multidict :target: https://multidict.aio-libs.org :alt: Read The Docs build status badge +.. image:: https://img.shields.io/endpoint?url=https://codspeed.io/badge.json + :target: https://codspeed.io/aio-libs/multidict + :alt: CodSpeed + .. image:: https://img.shields.io/pypi/pyversions/multidict.svg :target: https://pypi.org/project/multidict :alt: Python versions @@ -100,7 +104,12 @@ e.g.: Please note, the pure Python (uncompiled) version is about 20-50 times slower depending on the usage scenario!!! +For extension development, set the ``MULTIDICT_DEBUG_BUILD`` environment variable to compile +the extensions in debug mode: + +.. code-block:: console + $ MULTIDICT_DEBUG_BUILD=1 pip install multidict Changelog --------- diff --git a/contrib/python/multidict/multidict/__init__.py b/contrib/python/multidict/multidict/__init__.py index b6b532a1f25b..31b077f58c0b 100644 --- a/contrib/python/multidict/multidict/__init__.py +++ b/contrib/python/multidict/multidict/__init__.py @@ -22,7 +22,7 @@ "getversion", ) -__version__ = "6.2.0" +__version__ = "6.4.3" if TYPE_CHECKING or not USE_EXTENSIONS: @@ -35,14 +35,25 @@ istr, ) else: + from collections.abc import ItemsView, KeysView, ValuesView + from ._multidict import ( CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy, + _ItemsView, + _KeysView, + _ValuesView, getversion, istr, ) + MultiMapping.register(MultiDictProxy) + MutableMultiMapping.register(MultiDict) + KeysView.register(_KeysView) + ItemsView.register(_ItemsView) + ValuesView.register(_ValuesView) + upstr = istr diff --git a/contrib/python/multidict/multidict/_compat.py b/contrib/python/multidict/multidict/_compat.py index 4713da2ceac6..264d327e6a92 100644 --- a/contrib/python/multidict/multidict/_compat.py +++ b/contrib/python/multidict/multidict/_compat.py @@ -10,5 +10,6 @@ if USE_EXTENSIONS: try: from . import _multidict # type: ignore[attr-defined] # noqa: F401 - except ImportError: + except ImportError: # pragma: no cover + # FIXME: Refactor for coverage. See #837. USE_EXTENSIONS = False diff --git a/contrib/python/multidict/multidict/_multidict.c b/contrib/python/multidict/multidict/_multidict.c index ebb1949f0a7b..04af12cc4166 100644 --- a/contrib/python/multidict/multidict/_multidict.c +++ b/contrib/python/multidict/multidict/_multidict.c @@ -3,443 +3,221 @@ #include "_multilib/pythoncapi_compat.h" -// Include order important -#include "_multilib/defs.h" -#include "_multilib/istr.h" -#include "_multilib/pair_list.h" #include "_multilib/dict.h" +#include "_multilib/istr.h" #include "_multilib/iter.h" +#include "_multilib/pair_list.h" +#include "_multilib/parser.h" +#include "_multilib/state.h" #include "_multilib/views.h" -#if PY_MINOR_VERSION < 12 -#ifndef _PyArg_UnpackKeywords -#define FASTCALL_OLD -#endif -#endif - - -static PyObject *collections_abc_mapping; -static PyObject *collections_abc_mut_mapping; -static PyObject *collections_abc_mut_multi_mapping; -static PyObject *repr_func; - -static PyTypeObject multidict_type; -static PyTypeObject cimultidict_type; -static PyTypeObject multidict_proxy_type; -static PyTypeObject cimultidict_proxy_type; -#define MultiDict_CheckExact(o) (Py_TYPE(o) == &multidict_type) -#define CIMultiDict_CheckExact(o) (Py_TYPE(o) == &cimultidict_type) -#define MultiDictProxy_CheckExact(o) (Py_TYPE(o) == &multidict_proxy_type) -#define CIMultiDictProxy_CheckExact(o) (Py_TYPE(o) == &cimultidict_proxy_type) - -/* Helper macro for something like isinstance(obj, Base) */ -#define _MultiDict_Check(o) \ - ((MultiDict_CheckExact(o)) || \ - (CIMultiDict_CheckExact(o)) || \ - (MultiDictProxy_CheckExact(o)) || \ - (CIMultiDictProxy_CheckExact(o))) +#define MultiDict_CheckExact(state, obj) Py_IS_TYPE(obj, state->MultiDictType) +#define MultiDict_Check(state, obj) \ + (MultiDict_CheckExact(state, obj) \ + || PyObject_TypeCheck(obj, state->MultiDictType)) +#define CIMultiDict_CheckExact(state, obj) Py_IS_TYPE(obj, state->CIMultiDictType) +#define CIMultiDict_Check(state, obj) \ + (CIMultiDict_CheckExact(state, obj) \ + || PyObject_TypeCheck(obj, state->CIMultiDictType)) +#define AnyMultiDict_Check(state, obj) \ + (MultiDict_CheckExact(state, obj) \ + || CIMultiDict_CheckExact(state, obj) \ + || PyObject_TypeCheck(obj, state->MultiDictType)) +#define MultiDictProxy_CheckExact(state, obj) Py_IS_TYPE(obj, state->MultiDictProxyType) +#define MultiDictProxy_Check(state, obj) \ + (MultiDictProxy_CheckExact(state, obj) \ + || PyObject_TypeCheck(obj, state->MultiDictProxyType)) +#define CIMultiDictProxy_CheckExact(state, obj) \ + Py_IS_TYPE(obj, state->CIMultiDictProxyType) +#define CIMultiDictProxy_Check(state, obj) \ + (CIMultiDictProxy_CheckExact(state, obj) \ + || PyObject_TypeCheck(obj, state->CIMultiDictProxyType)) +#define AnyMultiDictProxy_Check(state, obj) \ + (MultiDictProxy_CheckExact(state, obj) \ + || CIMultiDictProxy_CheckExact(state, obj) \ + || PyObject_TypeCheck(obj, state->MultiDictProxyType)) /******************** Internal Methods ********************/ -/* Forward declaration */ -static PyObject *multidict_items(MultiDictObject *self); - static inline PyObject * _multidict_getone(MultiDictObject *self, PyObject *key, PyObject *_default) { - PyObject *val = pair_list_get_one(&self->pairs, key); - - if (val == NULL && - PyErr_ExceptionMatches(PyExc_KeyError) && - _default != NULL) - { - PyErr_Clear(); - Py_INCREF(_default); - return _default; - } - - return val; -} - -static inline int -_multidict_eq(MultiDictObject *self, MultiDictObject *other) -{ - Py_ssize_t pos1 = 0, - pos2 = 0; - - Py_hash_t h1 = 0, - h2 = 0; - - PyObject *identity1 = NULL, - *identity2 = NULL, - *value1 = NULL, - *value2 = NULL; + PyObject *val = NULL; - int cmp_identity = 0, - cmp_value = 0; - - if (self == other) { - return 1; - } - - if (pair_list_len(&self->pairs) != pair_list_len(&other->pairs)) { - return 0; + if (pair_list_get_one(&self->pairs, key, &val) <0) { + return NULL; } - while (_pair_list_next(&self->pairs, &pos1, &identity1, NULL, &value1, &h1) && - _pair_list_next(&other->pairs, &pos2, &identity2, NULL, &value2, &h2)) - { - if (h1 != h2) { - return 0; - } - cmp_identity = PyObject_RichCompareBool(identity1, identity2, Py_NE); - if (cmp_identity < 0) { - return -1; - } - cmp_value = PyObject_RichCompareBool(value1, value2, Py_NE); - if (cmp_value < 0) { - return -1; - } - if (cmp_identity || cmp_value) { - return 0; + if (val == NULL) { + if (_default != NULL) { + Py_INCREF(_default); + return _default; + } else { + PyErr_SetObject(PyExc_KeyError, key); + return NULL; } + } else { + return val; } - - return 1; } -static inline int -_multidict_update_items(MultiDictObject *self, pair_list_t *pairs) -{ - return pair_list_update(&self->pairs, pairs); -} static inline int -_multidict_append_items(MultiDictObject *self, pair_list_t *pairs) +_multidict_extend(MultiDictObject *self, PyObject *arg, + PyObject *kwds, const char *name, int do_add) { - PyObject *key = NULL, - *value = NULL; - - Py_ssize_t pos = 0; + mod_state *state = self->pairs.state; + PyObject *used = NULL; + PyObject *seq = NULL; + pair_list_t *list; - while (_pair_list_next(pairs, &pos, NULL, &key, &value, NULL)) { - if (pair_list_add(&self->pairs, key, value) < 0) { - return -1; + if (!do_add) { + used = PyDict_New(); + if (used == NULL) { + goto fail; } } - return 0; -} - -static inline int -_multidict_append_items_seq(MultiDictObject *self, PyObject *arg, - const char *name) -{ - PyObject *key = NULL, - *value = NULL, - *item = NULL, - *iter = PyObject_GetIter(arg); - - if (iter == NULL) { - return -1; + if (kwds && !PyArg_ValidateKeywordArguments(kwds)) { + goto fail; } - while ((item = PyIter_Next(iter)) != NULL) { - if (PyTuple_CheckExact(item)) { - if (PyTuple_GET_SIZE(item) != 2) { - goto invalid_type; + if (arg != NULL) { + if (AnyMultiDict_Check(state, arg)) { + list = &((MultiDictObject*)arg)->pairs; + if (pair_list_update_from_pair_list(&self->pairs, used, list) < 0) { + goto fail; } - key = PyTuple_GET_ITEM(item, 0); - Py_INCREF(key); - value = PyTuple_GET_ITEM(item, 1); - Py_INCREF(value); - } - else if (PyList_CheckExact(item)) { - if (PyList_Size(item) != 2) { - goto invalid_type; + } else if (AnyMultiDictProxy_Check(state, arg)) { + list = &((MultiDictProxyObject*)arg)->md->pairs; + if (pair_list_update_from_pair_list(&self->pairs, used, list) < 0) { + goto fail; } - key = PyList_GetItemRef(item, 0); - if (key == NULL) { - goto invalid_type; + } else if (PyDict_CheckExact(arg)) { + if (pair_list_update_from_dict(&self->pairs, used, arg) < 0) { + goto fail; } - value = PyList_GetItemRef(item, 1); - if (value == NULL) { - goto invalid_type; + } else { + seq = PyMapping_Items(arg); + if (seq == NULL) { + PyErr_Clear(); + seq = Py_NewRef(arg); } - } - else if (PySequence_Check(item)) { - if (PySequence_Size(item) != 2) { - goto invalid_type; + + if (pair_list_update_from_seq(&self->pairs, used, seq) < 0) { + goto fail; } - key = PySequence_GetItem(item, 0); - value = PySequence_GetItem(item, 1); - } else { - goto invalid_type; } + } - if (pair_list_add(&self->pairs, key, value) < 0) { + if (kwds != NULL) { + if (pair_list_update_from_dict(&self->pairs, used, kwds) < 0) { goto fail; } - Py_CLEAR(key); - Py_CLEAR(value); - Py_CLEAR(item); } - Py_DECREF(iter); - - if (PyErr_Occurred()) { - return -1; + if (!do_add) { + if (pair_list_post_update(&self->pairs, used) < 0) { + goto fail; + } } - + Py_CLEAR(seq); + Py_CLEAR(used); return 0; -invalid_type: - PyErr_Format( - PyExc_TypeError, - "%s takes either dict or list of (key, value) pairs", - name, - NULL - ); - goto fail; fail: - Py_XDECREF(key); - Py_XDECREF(value); - Py_XDECREF(item); - Py_DECREF(iter); + Py_CLEAR(seq); + Py_CLEAR(used); return -1; } -static inline int -_multidict_list_extend(PyObject *list, PyObject *target_list) -{ - PyObject *item = NULL, - *iter = PyObject_GetIter(target_list); - - if (iter == NULL) { - return -1; - } - while ((item = PyIter_Next(iter)) != NULL) { - if (PyList_Append(list, item) < 0) { - Py_DECREF(item); - Py_DECREF(iter); +static inline Py_ssize_t +_multidict_extend_parse_args(PyObject *args, PyObject *kwds, + const char *name, PyObject **parg) +{ + Py_ssize_t size = 0; + Py_ssize_t s; + if (args) { + size = PyTuple_GET_SIZE(args); + if (size > 1) { + PyErr_Format( + PyExc_TypeError, + "%s takes from 1 to 2 positional arguments but %zd were given", + name, size + 1, NULL + ); + *parg = NULL; return -1; } - Py_DECREF(item); - } - - Py_DECREF(iter); - - if (PyErr_Occurred()) { - return -1; - } - - return 0; -} - -static inline int -_multidict_extend_with_args(MultiDictObject *self, PyObject *arg, - PyObject *kwds, const char *name, int do_add) -{ - PyObject *arg_items = NULL, /* tracked by GC */ - *kwds_items = NULL; /* new reference */ - pair_list_t *pairs = NULL; - - int err = 0; - - if (kwds && !PyArg_ValidateKeywordArguments(kwds)) { - return -1; - } - - // TODO: mb can be refactored more clear - if (_MultiDict_Check(arg) && kwds == NULL) { - if (MultiDict_CheckExact(arg) || CIMultiDict_CheckExact(arg)) { - pairs = &((MultiDictObject*)arg)->pairs; - } else if (MultiDictProxy_CheckExact(arg) || CIMultiDictProxy_CheckExact(arg)) { - pairs = &((MultiDictProxyObject*)arg)->md->pairs; - } - - if (do_add) { - return _multidict_append_items(self, pairs); - } - - return _multidict_update_items(self, pairs); } - if (PyObject_HasAttrString(arg, "items")) { - if (_MultiDict_Check(arg)) { - arg_items = multidict_items((MultiDictObject*)arg); + if (size == 1) { + *parg = Py_NewRef(PyTuple_GET_ITEM(args, 0)); + s = PyObject_Length(*parg); + if (s < 0) { + // e.g. cannot calc size of generator object + PyErr_Clear(); } else { - arg_items = PyMapping_Items(arg); - } - if (arg_items == NULL) { - return -1; - } - } else { - arg_items = arg; - Py_INCREF(arg_items); - } - - if (kwds) { - PyObject *tmp = PySequence_List(arg_items); - Py_DECREF(arg_items); - arg_items = tmp; - if (arg_items == NULL) { - return -1; + size += s; } - - kwds_items = PyDict_Items(kwds); - if (kwds_items == NULL) { - Py_DECREF(arg_items); - return -1; - } - err = _multidict_list_extend(arg_items, kwds_items); - Py_DECREF(kwds_items); - if (err < 0) { - Py_DECREF(arg_items); - return -1; - } - } - - if (do_add) { - err = _multidict_append_items_seq(self, arg_items, name); - } else { - err = pair_list_update_from_seq(&self->pairs, arg_items); - } - - Py_DECREF(arg_items); - - return err; -} - -static inline int -_multidict_extend_with_kwds(MultiDictObject *self, PyObject *kwds, - const char *name, int do_add) -{ - PyObject *arg = NULL; - - int err = 0; - - if (!PyArg_ValidateKeywordArguments(kwds)) { - return -1; - } - - arg = PyDict_Items(kwds); - if (do_add) { - err = _multidict_append_items_seq(self, arg, name); } else { - err = pair_list_update_from_seq(&self->pairs, arg); - } - - Py_DECREF(arg); - return err; -} - -static inline int -_multidict_extend(MultiDictObject *self, PyObject *args, PyObject *kwds, - const char *name, int do_add) -{ - PyObject *arg = NULL; - - if (args && PyObject_Length(args) > 1) { - PyErr_Format( - PyExc_TypeError, - "%s takes from 1 to 2 positional arguments but %zd were given", - name, PyObject_Length(args) + 1, NULL - ); - return -1; + *parg = NULL; } - if (args && PyObject_Length(args) > 0) { - if (!PyArg_UnpackTuple(args, name, 0, 1, &arg)) { - return -1; - } - if (_multidict_extend_with_args(self, arg, kwds, name, do_add) < 0) { - return -1; - } - } else if (kwds && PyObject_Length(kwds) > 0) { - if (_multidict_extend_with_kwds(self, kwds, name, do_add) < 0) { + if (kwds != NULL) { + s = PyDict_Size(kwds); + if (s < 0) { return -1; } + size += s; } - return 0; + return size; } static inline PyObject * -_multidict_copy(MultiDictObject *self, PyTypeObject *multidict_tp_object) +multidict_copy(MultiDictObject *self) { MultiDictObject *new_multidict = NULL; - PyObject *arg_items = NULL, - *items = NULL; - new_multidict = (MultiDictObject*)PyType_GenericNew( - multidict_tp_object, NULL, NULL); + Py_TYPE(self), NULL, NULL); if (new_multidict == NULL) { - return NULL; - } - - if (multidict_tp_object->tp_init( - (PyObject*)new_multidict, NULL, NULL) < 0) - { - return NULL; - } - - items = multidict_items(self); - if (items == NULL) { goto fail; } - // TODO: "Implementation looks as slow as possible ..." - arg_items = PyTuple_New(1); - if (arg_items == NULL) { + if (Py_TYPE(self)->tp_init((PyObject*)new_multidict, NULL, NULL) < 0) { goto fail; } - Py_INCREF(items); - PyTuple_SET_ITEM(arg_items, 0, items); - - if (_multidict_extend( - new_multidict, arg_items, NULL, "copy", 1) < 0) - { + if (pair_list_update_from_pair_list(&new_multidict->pairs, + NULL, &self->pairs) < 0) { goto fail; } - - Py_DECREF(items); - Py_DECREF(arg_items); - return (PyObject*)new_multidict; - fail: - Py_XDECREF(items); - Py_XDECREF(arg_items); - - Py_DECREF(new_multidict); - + Py_CLEAR(new_multidict); return NULL; } static inline PyObject * _multidict_proxy_copy(MultiDictProxyObject *self, PyTypeObject *type) { - PyObject *new_multidict = PyType_GenericNew(type, NULL, NULL); + MultiDictObject *new_multidict = NULL; + new_multidict = (MultiDictObject*)PyType_GenericNew(type, NULL, NULL); if (new_multidict == NULL) { goto fail; } - if (type->tp_init(new_multidict, NULL, NULL) < 0) { + if (type->tp_init((PyObject*)new_multidict, NULL, NULL) < 0) { goto fail; } - if (_multidict_extend_with_args( - (MultiDictObject*)new_multidict, (PyObject*)self, NULL, "copy", 1) < 0) - { + if (pair_list_update_from_pair_list(&new_multidict->pairs, + NULL, &self->md->pairs) < 0) { goto fail; } - - return new_multidict; - + return (PyObject*)new_multidict; fail: - Py_XDECREF(new_multidict); + Py_CLEAR(new_multidict); return NULL; } @@ -447,175 +225,64 @@ _multidict_proxy_copy(MultiDictProxyObject *self, PyTypeObject *type) /******************** Base Methods ********************/ static inline PyObject * -multidict_getall( - MultiDictObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +multidict_getall(MultiDictObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { PyObject *list = NULL, *key = NULL, *_default = NULL; -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - static char *getall_keywords[] = {"key", "default", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getall", - getall_keywords, &key, &_default)) - { + if (parse2("getall", args, nargs, kwnames, 1, + "key", &key, "default", &_default) < 0) { return NULL; } -#else - static const char * const _keywords[] = {"key", "default", NULL}; -#ifdef FASTCALL_OLD - static _PyArg_Parser _parser = {"O|O:getall", _keywords, 0}; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &_default)) { + if (pair_list_get_all(&self->pairs, key, &list) <0) { return NULL; } -#else - static _PyArg_Parser _parser = {NULL, _keywords, "getall", 0}; - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, - &_parser, 1, 2, 0, argsbuf); - if (!args) { - return NULL; - } - key = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - _default = args[1]; -skip_optional_pos: -#endif -#endif - list = pair_list_get_all(&self->pairs, key); - - if (list == NULL && - PyErr_ExceptionMatches(PyExc_KeyError) && - _default != NULL) - { - PyErr_Clear(); - Py_INCREF(_default); - return _default; + if (list == NULL) { + if (_default != NULL) { + Py_INCREF(_default); + return _default; + } else { + PyErr_SetObject(PyExc_KeyError, key); + return NULL; + } + } else { + return list; } - - return list; } static inline PyObject * -multidict_getone( - MultiDictObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +multidict_getone(MultiDictObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { PyObject *key = NULL, *_default = NULL; -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - static char *getone_keywords[] = {"key", "default", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone", - getone_keywords, &key, &_default)) - { - return NULL; - } - -#else - static const char * const _keywords[] = {"key", "default", NULL}; -#ifdef FASTCALL_OLD - static _PyArg_Parser _parser = {"O|O:getone", _keywords, 0}; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &_default)) { + if (parse2("getone", args, nargs, kwnames, 1, + "key", &key, "default", &_default) < 0) { return NULL; } -#else - static _PyArg_Parser _parser = {NULL, _keywords, "getone", 0}; - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, - &_parser, 1, 2, 0, argsbuf); - if (!args) { - return NULL; - } - key = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - - _default = args[1]; -skip_optional_pos: -#endif -#endif return _multidict_getone(self, key, _default); } static inline PyObject * -multidict_get( - MultiDictObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +multidict_get(MultiDictObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { PyObject *key = NULL, - *_default = Py_None, + *_default = NULL, *ret; -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - static char *getone_keywords[] = {"key", "default", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone", - getone_keywords, &key, &_default)) - { + if (parse2("get", args, nargs, kwnames, 1, + "key", &key, "default", &_default) < 0) { return NULL; } -#else - static const char * const _keywords[] = {"key", "default", NULL}; -#ifdef FASTCALL_OLD - static _PyArg_Parser _parser = {"O|O:get", _keywords, 0}; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &_default)) { - return NULL; - } -#else - static _PyArg_Parser _parser = {NULL, _keywords, "get", 0}; - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, - &_parser, 1, 2, 0, argsbuf); - if (!args) { - return NULL; + if (_default == NULL) { + // fixme, _default is potentially dangerous borrowed ref here + _default = Py_None; } - key = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - - _default = args[1]; -skip_optional_pos: -#endif -#endif ret = _multidict_getone(self, key, _default); return ret; } @@ -623,19 +290,19 @@ multidict_get( static inline PyObject * multidict_keys(MultiDictObject *self) { - return multidict_keysview_new((PyObject*)self); + return multidict_keysview_new(self); } static inline PyObject * multidict_items(MultiDictObject *self) { - return multidict_itemsview_new((PyObject*)self); + return multidict_itemsview_new(self); } static inline PyObject * multidict_values(MultiDictObject *self) { - return multidict_valuesview_new((PyObject*)self); + return multidict_valuesview_new(self); } static inline PyObject * @@ -646,7 +313,7 @@ multidict_reduce(MultiDictObject *self) *args = NULL, *result = NULL; - items = multidict_items(self); + items = multidict_itemsview_new(self); if (items == NULL) { goto ret; } @@ -662,7 +329,6 @@ multidict_reduce(MultiDictObject *self) } result = PyTuple_Pack(2, Py_TYPE(self), args); - ret: Py_XDECREF(args); Py_XDECREF(items_list); @@ -672,10 +338,24 @@ multidict_reduce(MultiDictObject *self) } static inline PyObject * -multidict_repr(PyObject *self) +multidict_repr(MultiDictObject *self) { - return PyObject_CallFunctionObjArgs( - repr_func, self, NULL); + int tmp = Py_ReprEnter((PyObject *)self); + if (tmp < 0) { + return NULL; + } + if (tmp > 0) { + return PyUnicode_FromString("..."); + } + PyObject *name = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__"); + if (name == NULL) { + Py_ReprLeave((PyObject *)self); + return NULL; + } + PyObject *ret = pair_list_repr(&self->pairs, name, true, true); + Py_ReprLeave((PyObject *)self); + Py_CLEAR(name); + return ret; } static inline Py_ssize_t @@ -703,7 +383,7 @@ multidict_mp_as_subscript(MultiDictObject *self, PyObject *key, PyObject *val) static inline int multidict_sq_contains(MultiDictObject *self, PyObject *key) { - return pair_list_contains(&self->pairs, key); + return pair_list_contains(&self->pairs, key, NULL); } static inline PyObject * @@ -715,59 +395,58 @@ multidict_tp_iter(MultiDictObject *self) static inline PyObject * multidict_tp_richcompare(PyObject *self, PyObject *other, int op) { - // TODO: refactoring me with love - - int cmp = 0; + int cmp; if (op != Py_EQ && op != Py_NE) { Py_RETURN_NOTIMPLEMENTED; } - if (MultiDict_CheckExact(other) || CIMultiDict_CheckExact(other)) { - cmp = _multidict_eq( - (MultiDictObject*)self, - (MultiDictObject*)other - ); - if (cmp < 0) { - return NULL; - } + if (self == other) { + cmp = 1; if (op == Py_NE) { cmp = !cmp; } return PyBool_FromLong(cmp); } - if (MultiDictProxy_CheckExact(other) || CIMultiDictProxy_CheckExact(other)) { - cmp = _multidict_eq( - (MultiDictObject*)self, - ((MultiDictProxyObject*)other)->md + mod_state *state = ((MultiDictObject*)self)->pairs.state; + if (AnyMultiDict_Check(state, other)) { + cmp = pair_list_eq( + &((MultiDictObject*)self)->pairs, + &((MultiDictObject*)other)->pairs ); - if (cmp < 0) { - return NULL; + } else if (AnyMultiDictProxy_Check(state, other)) { + cmp = pair_list_eq( + &((MultiDictObject*)self)->pairs, + &((MultiDictProxyObject*)other)->md->pairs + ); + } else { + bool fits = false; + fits = PyDict_Check(other); + if (!fits) { + PyObject *keys = PyMapping_Keys(other); + if (keys != NULL) { + fits = true; + } else { + // reset AttributeError exception + PyErr_Clear(); + } + Py_CLEAR(keys); } - if (op == Py_NE) { - cmp = !cmp; + if (fits) { + cmp = pair_list_eq_to_mapping(&((MultiDictObject*)self)->pairs, + other); + } else { + cmp = 0; // e.g., multidict is not equal to a list } - return PyBool_FromLong(cmp); } - - cmp = PyObject_IsInstance(other, (PyObject*)collections_abc_mapping); if (cmp < 0) { return NULL; } - - if (cmp) { - cmp = pair_list_eq_to_mapping(&((MultiDictObject*)self)->pairs, other); - if (cmp < 0) { - return NULL; - } - if (op == Py_NE) { - cmp = !cmp; - } - return PyBool_FromLong(cmp); + if (op == Py_NE) { + cmp = !cmp; } - - Py_RETURN_NOTIMPLEMENTED; + return PyBool_FromLong(cmp); } static inline void @@ -775,9 +454,7 @@ multidict_tp_dealloc(MultiDictObject *self) { PyObject_GC_UnTrack(self); Py_TRASHCAN_BEGIN(self, multidict_tp_dealloc) - if (self->weaklist != NULL) { - PyObject_ClearWeakRefs((PyObject *)self); - }; + PyObject_ClearWeakRefs((PyObject *)self); pair_list_dealloc(&self->pairs); Py_TYPE(self)->tp_free((PyObject *)self); Py_TRASHCAN_END // there should be no code after this @@ -786,6 +463,7 @@ multidict_tp_dealloc(MultiDictObject *self) static inline int multidict_tp_traverse(MultiDictObject *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); return pair_list_traverse(&self->pairs, visit, arg); } @@ -818,62 +496,36 @@ PyDoc_STRVAR(multidict_values_doc, static inline int multidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds) { - if (pair_list_init(&self->pairs) < 0) { - return -1; + mod_state *state = get_mod_state_by_def((PyObject *)self); + PyObject *arg = NULL; + Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "MultiDict", &arg); + if (size < 0) { + goto fail; } - if (_multidict_extend(self, args, kwds, "MultiDict", 1) < 0) { - return -1; + if (pair_list_init(&self->pairs, state, size) < 0) { + goto fail; + } + if (_multidict_extend(self, arg, kwds, "MultiDict", 1) < 0) { + goto fail; } + Py_CLEAR(arg); return 0; +fail: + Py_CLEAR(arg); + return -1; } static inline PyObject * -multidict_add( - MultiDictObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +multidict_add(MultiDictObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { PyObject *key = NULL, *val = NULL; -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - static char *kwlist[] = {"key", "value", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:add", - kwlist, &key, &val)) - { + if (parse2("add", args, nargs, kwnames, 2, + "key", &key, "value", &val) < 0) { return NULL; } -#else - static const char * const _keywords[] = {"key", "value", NULL}; -#ifdef FASTCALL_OLD - static _PyArg_Parser _parser = {"OO:add", _keywords, 0}; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &val)) { - return NULL; - } -#else - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "add", - .kwtuple = NULL, - }; - PyObject *argsbuf[2]; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, - &_parser, 2, 2, 0, argsbuf); - if (!args) { - return NULL; - } - key = args[0]; - val = args[1]; -#endif -#endif if (pair_list_add(&self->pairs, key, val) < 0) { return NULL; } @@ -881,20 +533,23 @@ multidict_add( Py_RETURN_NONE; } -static inline PyObject * -multidict_copy(MultiDictObject *self) -{ - return _multidict_copy(self, &multidict_type); -} - static inline PyObject * multidict_extend(MultiDictObject *self, PyObject *args, PyObject *kwds) { - if (_multidict_extend(self, args, kwds, "extend", 1) < 0) { - return NULL; + PyObject *arg = NULL; + Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "extend", &arg); + if (size < 0) { + goto fail; } - + pair_list_grow(&self->pairs, size); + if (_multidict_extend(self, arg, kwds, "extend", 1) < 0) { + goto fail; + } + Py_CLEAR(arg); Py_RETURN_NONE; +fail: + Py_CLEAR(arg); + return NULL; } static inline PyObject * @@ -907,271 +562,109 @@ multidict_clear(MultiDictObject *self) Py_RETURN_NONE; } -static inline PyObject * -multidict_setdefault( - MultiDictObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +static inline PyObject * +multidict_setdefault(MultiDictObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { PyObject *key = NULL, *_default = NULL; -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - static char *setdefault_keywords[] = {"key", "default", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:setdefault", - setdefault_keywords, &key, &_default)) - { - return NULL; - } -#else - static const char * const _keywords[] = {"key", "default", NULL}; -#ifdef FASTCALL_OLD - static _PyArg_Parser _parser = {"O|O:setdefault", _keywords, 0}; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &_default)) { - return NULL; - } -#else - static _PyArg_Parser _parser = {NULL, _keywords, "setdefault", 0}; - PyObject *argsbuf[3]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, - &_parser, 1, 2, 0, argsbuf); - if (!args) { + if (parse2("setdefault", args, nargs, kwnames, 1, + "key", &key, "default", &_default) < 0) { return NULL; } - key = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - _default = args[1]; - -skip_optional_pos: -#endif -#endif return pair_list_set_default(&self->pairs, key, _default); } static inline PyObject * -multidict_popone( - MultiDictObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +multidict_popone(MultiDictObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { PyObject *key = NULL, *_default = NULL, *ret_val = NULL; -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - static char *popone_keywords[] = {"key", "default", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popone", - popone_keywords, &key, &_default)) - { - return NULL; - } - - ret_val = pair_list_pop_one(&self->pairs, key); - - if (ret_val == NULL && - PyErr_ExceptionMatches(PyExc_KeyError) && - _default != NULL) - { - PyErr_Clear(); - Py_INCREF(_default); - return _default; - } - - return ret_val; -#else - static const char * const _keywords[] = {"key", "default", NULL}; -#ifdef FASTCALL_OLD - static _PyArg_Parser _parser = {"O|O:popone", _keywords, 0}; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &_default)) { + if (parse2("popone", args, nargs, kwnames, 1, + "key", &key, "default", &_default) < 0) { return NULL; } -#else - static _PyArg_Parser _parser = {NULL, _keywords, "popone", 0}; - PyObject *argsbuf[3]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, - &_parser, 1, 2, 0, argsbuf); - if (!args) { + if (pair_list_pop_one(&self->pairs, key, &ret_val) < 0) { return NULL; } - key = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - _default = args[1]; - -skip_optional_pos: -#endif - ret_val = pair_list_pop_one(&self->pairs, key); - if (ret_val == NULL && - PyErr_ExceptionMatches(PyExc_KeyError) && - _default != NULL) - { - PyErr_Clear(); - Py_INCREF(_default); - return _default; + if (ret_val == NULL) { + if (_default != NULL) { + Py_INCREF(_default); + return _default; + } else { + PyErr_SetObject(PyExc_KeyError, key); + return NULL; + } + } else { + return ret_val; } - - return ret_val; -#endif } static inline PyObject * multidict_pop( MultiDictObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames -#endif ) { PyObject *key = NULL, *_default = NULL, *ret_val = NULL; -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - static char *pop_keywords[] = {"key", "default", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popone", - pop_keywords, &key, &_default)) - { - return NULL; - } - -#else - static const char * const _keywords[] = {"key", "default", NULL}; -#ifdef FASTCALL_OLD - static _PyArg_Parser _parser = {"O|O:pop", _keywords, 0}; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &_default)) { + if (parse2("pop", args, nargs, kwnames, 1, + "key", &key, "default", &_default) < 0) { return NULL; } -#else - static _PyArg_Parser _parser = {NULL, _keywords, "pop", 0}; - PyObject *argsbuf[3]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, - &_parser, 1, 2, 0, argsbuf); - if (!args) { + if (pair_list_pop_one(&self->pairs, key, &ret_val) < 0) { return NULL; } - key = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - _default = args[1]; -skip_optional_pos: -#endif -#endif - ret_val = pair_list_pop_one(&self->pairs, key); - - if (ret_val == NULL && - PyErr_ExceptionMatches(PyExc_KeyError) && - _default != NULL) - { - PyErr_Clear(); - Py_INCREF(_default); - return _default; + if (ret_val == NULL) { + if (_default != NULL) { + Py_INCREF(_default); + return _default; + } else { + PyErr_SetObject(PyExc_KeyError, key); + return NULL; + } + } else { + return ret_val; } - - return ret_val; } static inline PyObject * -multidict_popall( - MultiDictObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +multidict_popall(MultiDictObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { PyObject *key = NULL, *_default = NULL, *ret_val = NULL; - -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - static char *popall_keywords[] = {"key", "default", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popall", - popall_keywords, &key, &_default)) - { - return NULL; - } -#else - static const char * const _keywords[] = {"key", "default", NULL}; -#ifdef FASTCALL_OLD - static _PyArg_Parser _parser = {"O|O:popall", _keywords, 0}; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &_default)) { + if (parse2("popall", args, nargs, kwnames, 1, + "key", &key, "default", &_default) < 0) { return NULL; } -#else - static _PyArg_Parser _parser = {NULL, _keywords, "popall", 0}; - PyObject *argsbuf[3]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, - &_parser, 1, 2, 0, argsbuf); - if (!args) { + if (pair_list_pop_all(&self->pairs, key, &ret_val) < 0) { return NULL; } - key = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - _default = args[1]; - -skip_optional_pos: -#endif -#endif - ret_val = pair_list_pop_all(&self->pairs, key); - if (ret_val == NULL && - PyErr_ExceptionMatches(PyExc_KeyError) && - _default != NULL) - { - PyErr_Clear(); - Py_INCREF(_default); - return _default; + if (ret_val == NULL) { + if (_default != NULL) { + Py_INCREF(_default); + return _default; + } else { + PyErr_SetObject(PyExc_KeyError, key); + return NULL; + } + } else { + return ret_val; } - - return ret_val; } static inline PyObject * @@ -1183,10 +676,18 @@ multidict_popitem(MultiDictObject *self) static inline PyObject * multidict_update(MultiDictObject *self, PyObject *args, PyObject *kwds) { - if (_multidict_extend(self, args, kwds, "update", 0) < 0) { - return NULL; + PyObject *arg = NULL; + if (_multidict_extend_parse_args(args, kwds, "update", &arg) < 0) { + goto fail; + } + if (_multidict_extend(self, arg, kwds, "update", 0) < 0) { + goto fail; } + Py_CLEAR(arg); Py_RETURN_NONE; +fail: + Py_CLEAR(arg); + return NULL; } PyDoc_STRVAR(multidict_add_doc, @@ -1226,10 +727,6 @@ PyDoc_STRVAR(multidict_popitem_doc, PyDoc_STRVAR(multidict_update_doc, "Update the dictionary from *other*, overwriting existing keys."); - -#define multidict_class_getitem Py_GenericAlias - - PyDoc_STRVAR(sizeof__doc__, "D.__sizeof__() -> size of D in memory, in bytes"); @@ -1244,48 +741,23 @@ _multidict_sizeof(MultiDictObject *self) } -static PySequenceMethods multidict_sequence = { - .sq_contains = (objobjproc)multidict_sq_contains, -}; - -static PyMappingMethods multidict_mapping = { - .mp_length = (lenfunc)multidict_mp_len, - .mp_subscript = (binaryfunc)multidict_mp_subscript, - .mp_ass_subscript = (objobjargproc)multidict_mp_as_subscript, -}; - static PyMethodDef multidict_methods[] = { { "getall", (PyCFunction)multidict_getall, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_getall_doc }, { "getone", (PyCFunction)multidict_getone, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_getone_doc }, { "get", (PyCFunction)multidict_get, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_get_doc }, { @@ -1309,12 +781,7 @@ static PyMethodDef multidict_methods[] = { { "add", (PyCFunction)multidict_add, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_add_doc }, { @@ -1338,45 +805,25 @@ static PyMethodDef multidict_methods[] = { { "setdefault", (PyCFunction)multidict_setdefault, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_setdefault_doc }, { "popone", (PyCFunction)multidict_popone, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_popone_doc }, { "pop", (PyCFunction)multidict_pop, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_pop_doc }, { "popall", (PyCFunction)multidict_popall, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_popall_doc }, { @@ -1399,7 +846,7 @@ static PyMethodDef multidict_methods[] = { }, { "__class_getitem__", - (PyCFunction)multidict_class_getitem, + (PyCFunction)Py_GenericAlias, METH_O | METH_CLASS, NULL }, @@ -1419,85 +866,100 @@ static PyMethodDef multidict_methods[] = { PyDoc_STRVAR(MultDict_doc, "Dictionary with the support for duplicate keys."); +#ifndef MANAGED_WEAKREFS +static PyMemberDef multidict_members[] = { + {"__weaklistoffset__", Py_T_PYSSIZET, + offsetof(MultiDictObject, weaklist), Py_READONLY}, + {NULL} /* Sentinel */ +}; +#endif + +static PyType_Slot multidict_slots[] = { + {Py_tp_dealloc, multidict_tp_dealloc}, + {Py_tp_repr, multidict_repr}, + {Py_tp_doc, (void *)MultDict_doc}, + + {Py_sq_contains, multidict_sq_contains}, + {Py_mp_length, multidict_mp_len}, + {Py_mp_subscript, multidict_mp_subscript}, + {Py_mp_ass_subscript, multidict_mp_as_subscript}, + + {Py_tp_traverse, multidict_tp_traverse}, + {Py_tp_clear, multidict_tp_clear}, + {Py_tp_richcompare, multidict_tp_richcompare}, + {Py_tp_iter, multidict_tp_iter}, + {Py_tp_methods, multidict_methods}, + {Py_tp_init, multidict_tp_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, PyType_GenericNew}, + {Py_tp_free, PyObject_GC_Del}, + +#ifndef MANAGED_WEAKREFS + {Py_tp_members, multidict_members}, +#endif + {0, NULL}, +}; -static PyTypeObject multidict_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "multidict._multidict.MultiDict", /* tp_name */ - sizeof(MultiDictObject), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_tp_dealloc, - .tp_repr = (reprfunc)multidict_repr, - .tp_as_sequence = &multidict_sequence, - .tp_as_mapping = &multidict_mapping, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_doc = MultDict_doc, - .tp_traverse = (traverseproc)multidict_tp_traverse, - .tp_clear = (inquiry)multidict_tp_clear, - .tp_richcompare = (richcmpfunc)multidict_tp_richcompare, - .tp_weaklistoffset = offsetof(MultiDictObject, weaklist), - .tp_iter = (getiterfunc)multidict_tp_iter, - .tp_methods = multidict_methods, - .tp_init = (initproc)multidict_tp_init, - .tp_alloc = PyType_GenericAlloc, - .tp_new = PyType_GenericNew, - .tp_free = PyObject_GC_Del, +static PyType_Spec multidict_spec = { + .name = "multidict._multidict.MultiDict", + .basicsize = sizeof(MultiDictObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE +#if PY_VERSION_HEX >= 0x030a00f0 + | Py_TPFLAGS_IMMUTABLETYPE +#endif +#ifdef MANAGED_WEAKREFS + | Py_TPFLAGS_MANAGED_WEAKREF +#endif + | Py_TPFLAGS_HAVE_GC), + .slots = multidict_slots, }; + /******************** CIMultiDict ********************/ static inline int cimultidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds) { - if (ci_pair_list_init(&self->pairs) < 0) { - return -1; + mod_state *state = get_mod_state_by_def((PyObject *)self); + PyObject *arg = NULL; + Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "CIMultiDict", &arg); + if (size < 0) { + goto fail; } - if (_multidict_extend(self, args, kwds, "CIMultiDict", 1) < 0) { - return -1; + + if (ci_pair_list_init(&self->pairs, state, size) < 0) { + goto fail; } - return 0; -} -static inline PyObject * -cimultidict_copy(MultiDictObject *self) -{ - return _multidict_copy(self, &cimultidict_type); + if (_multidict_extend(self, arg, kwds, "CIMultiDict", 1) < 0) { + goto fail; + } + Py_CLEAR(arg); + return 0; +fail: + Py_CLEAR(arg); + return -1; } -PyDoc_STRVAR(cimultidict_copy_doc, -"Return a copy of itself."); - -static PyMethodDef cimultidict_methods[] = { - { - "copy", - (PyCFunction)cimultidict_copy, - METH_NOARGS, - cimultidict_copy_doc - }, - { - NULL, - NULL - } /* sentinel */ -}; PyDoc_STRVAR(CIMultDict_doc, "Dictionary with the support for duplicate case-insensitive keys."); +static PyType_Slot cimultidict_slots[] = { + {Py_tp_doc, (void *)CIMultDict_doc}, + {Py_tp_init, cimultidict_tp_init}, + {0, NULL}, +}; -static PyTypeObject cimultidict_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "multidict._multidict.CIMultiDict", /* tp_name */ - sizeof(MultiDictObject), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_tp_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_doc = CIMultDict_doc, - .tp_traverse = (traverseproc)multidict_tp_traverse, - .tp_clear = (inquiry)multidict_tp_clear, - .tp_weaklistoffset = offsetof(MultiDictObject, weaklist), - .tp_methods = cimultidict_methods, - .tp_base = &multidict_type, - .tp_init = (initproc)cimultidict_tp_init, - .tp_alloc = PyType_GenericAlloc, - .tp_new = PyType_GenericNew, - .tp_free = PyObject_GC_Del, +static PyType_Spec cimultidict_spec = { + .name = "multidict._multidict.CIMultiDict", + .basicsize = sizeof(MultiDictObject), + .flags = (Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX >= 0x030a00f0 + | Py_TPFLAGS_IMMUTABLETYPE +#endif + | Py_TPFLAGS_BASETYPE), + .slots = cimultidict_slots, }; /******************** MultiDictProxy ********************/ @@ -1506,6 +968,7 @@ static inline int multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args, PyObject *kwds) { + mod_state *state = get_mod_state_by_def((PyObject *)self); PyObject *arg = NULL; MultiDictObject *md = NULL; @@ -1521,9 +984,8 @@ multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args, ); return -1; } - if (!MultiDictProxy_CheckExact(arg) && - !CIMultiDict_CheckExact(arg) && - !MultiDict_CheckExact(arg)) + if (!AnyMultiDictProxy_Check(state, arg) && + !AnyMultiDict_Check(state, arg)) { PyErr_Format( PyExc_TypeError, @@ -1534,9 +996,10 @@ multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args, return -1; } - md = (MultiDictObject*)arg; - if (MultiDictProxy_CheckExact(arg)) { + if (AnyMultiDictProxy_Check(state, arg)) { md = ((MultiDictProxyObject*)arg)->md; + } else { + md = (MultiDictObject*)arg; } Py_INCREF(md); self->md = md; @@ -1545,76 +1008,24 @@ multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args, } static inline PyObject * -multidict_proxy_getall( - MultiDictProxyObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +multidict_proxy_getall(MultiDictProxyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { - return multidict_getall( - self->md, - args, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - kwds -#else - nargs, - kwnames -#endif - ); + return multidict_getall(self->md, args, nargs, kwnames); } static inline PyObject * -multidict_proxy_getone( - MultiDictProxyObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +multidict_proxy_getone(MultiDictProxyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { - return multidict_getone( - self->md, args, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - kwds -#else - nargs, kwnames -#endif - ); + return multidict_getone(self->md, args, nargs, kwnames); } static inline PyObject * -multidict_proxy_get( - MultiDictProxyObject *self, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - PyObject *args, - PyObject *kwds -#else - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames -#endif -) +multidict_proxy_get(MultiDictProxyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) { - return multidict_get( - self->md, - args, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - kwds -#else - nargs, - kwnames -#endif - ); + return multidict_get(self->md, args, nargs, kwnames); } static inline PyObject * @@ -1638,7 +1049,7 @@ multidict_proxy_values(MultiDictProxyObject *self) static inline PyObject * multidict_proxy_copy(MultiDictProxyObject *self) { - return _multidict_proxy_copy(self, &multidict_type); + return _multidict_proxy_copy(self, self->md->pairs.state->MultiDictType); } static inline PyObject * @@ -1687,9 +1098,7 @@ static inline void multidict_proxy_tp_dealloc(MultiDictProxyObject *self) { PyObject_GC_UnTrack(self); - if (self->weaklist != NULL) { - PyObject_ClearWeakRefs((PyObject *)self); - }; + PyObject_ClearWeakRefs((PyObject *)self); Py_XDECREF(self->md); Py_TYPE(self)->tp_free((PyObject *)self); } @@ -1698,6 +1107,7 @@ static inline int multidict_proxy_tp_traverse(MultiDictProxyObject *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->md); return 0; } @@ -1709,47 +1119,35 @@ multidict_proxy_tp_clear(MultiDictProxyObject *self) return 0; } -static PySequenceMethods multidict_proxy_sequence = { - .sq_contains = (objobjproc)multidict_proxy_sq_contains, -}; +static inline PyObject * +multidict_proxy_repr(MultiDictProxyObject *self) +{ + PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__"); + if (name == NULL) + return NULL; + PyObject *ret = pair_list_repr(&self->md->pairs, name, true, true); + Py_CLEAR(name); + return ret; +} -static PyMappingMethods multidict_proxy_mapping = { - .mp_length = (lenfunc)multidict_proxy_mp_len, - .mp_subscript = (binaryfunc)multidict_proxy_mp_subscript, -}; static PyMethodDef multidict_proxy_methods[] = { { "getall", (PyCFunction)multidict_proxy_getall, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_getall_doc }, { "getone", (PyCFunction)multidict_proxy_getone, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_getone_doc }, { "get", (PyCFunction)multidict_proxy_get, -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12 - METH_VARARGS -#else - METH_FASTCALL -#endif - | METH_KEYWORDS, + METH_FASTCALL | METH_KEYWORDS, multidict_get_doc }, { @@ -1784,7 +1182,7 @@ static PyMethodDef multidict_proxy_methods[] = { }, { "__class_getitem__", - (PyCFunction)multidict_class_getitem, + (PyCFunction)Py_GenericAlias, METH_O | METH_CLASS, NULL }, @@ -1798,27 +1196,51 @@ static PyMethodDef multidict_proxy_methods[] = { PyDoc_STRVAR(MultDictProxy_doc, "Read-only proxy for MultiDict instance."); +#ifndef MANAGED_WEAKREFS +static PyMemberDef multidict_proxy_members[] = { + {"__weaklistoffset__", Py_T_PYSSIZET, + offsetof(MultiDictProxyObject, weaklist), Py_READONLY}, + {NULL} /* Sentinel */ +}; +#endif + +static PyType_Slot multidict_proxy_slots[] = { + {Py_tp_dealloc, multidict_proxy_tp_dealloc}, + {Py_tp_repr, multidict_proxy_repr}, + {Py_tp_doc, (void *)MultDictProxy_doc}, + + {Py_sq_contains, multidict_proxy_sq_contains}, + {Py_mp_length, multidict_proxy_mp_len}, + {Py_mp_subscript, multidict_proxy_mp_subscript}, + + {Py_tp_traverse, multidict_proxy_tp_traverse}, + {Py_tp_clear, multidict_proxy_tp_clear}, + {Py_tp_richcompare, multidict_proxy_tp_richcompare}, + {Py_tp_iter, multidict_proxy_tp_iter}, + {Py_tp_methods, multidict_proxy_methods}, + {Py_tp_init, multidict_proxy_tp_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, PyType_GenericNew}, + {Py_tp_free, PyObject_GC_Del}, + +#ifndef MANAGED_WEAKREFS + {Py_tp_members, multidict_proxy_members}, +#endif + {0, NULL}, +}; -static PyTypeObject multidict_proxy_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "multidict._multidict.MultiDictProxy", /* tp_name */ - sizeof(MultiDictProxyObject), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_proxy_tp_dealloc, - .tp_repr = (reprfunc)multidict_repr, - .tp_as_sequence = &multidict_proxy_sequence, - .tp_as_mapping = &multidict_proxy_mapping, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_doc = MultDictProxy_doc, - .tp_traverse = (traverseproc)multidict_proxy_tp_traverse, - .tp_clear = (inquiry)multidict_proxy_tp_clear, - .tp_richcompare = (richcmpfunc)multidict_proxy_tp_richcompare, - .tp_weaklistoffset = offsetof(MultiDictProxyObject, weaklist), - .tp_iter = (getiterfunc)multidict_proxy_tp_iter, - .tp_methods = multidict_proxy_methods, - .tp_init = (initproc)multidict_proxy_tp_init, - .tp_alloc = PyType_GenericAlloc, - .tp_new = PyType_GenericNew, - .tp_free = PyObject_GC_Del, +static PyType_Spec multidict_proxy_spec = { + .name = "multidict._multidict.MultiDictProxy", + .basicsize = sizeof(MultiDictProxyObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE +#if PY_VERSION_HEX >= 0x030a00f0 + | Py_TPFLAGS_IMMUTABLETYPE +#endif +#ifdef MANAGED_WEAKREFS + | Py_TPFLAGS_MANAGED_WEAKREF +#endif + | Py_TPFLAGS_HAVE_GC), + .slots = multidict_proxy_slots, }; /******************** CIMultiDictProxy ********************/ @@ -1827,6 +1249,7 @@ static inline int cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args, PyObject *kwds) { + mod_state *state = get_mod_state_by_def((PyObject *)self); PyObject *arg = NULL; MultiDictObject *md = NULL; @@ -1842,7 +1265,8 @@ cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args, ); return -1; } - if (!CIMultiDictProxy_CheckExact(arg) && !CIMultiDict_CheckExact(arg)) { + if (!CIMultiDictProxy_Check(state, arg) + && !CIMultiDict_Check(state, arg)) { PyErr_Format( PyExc_TypeError, "ctor requires CIMultiDict or CIMultiDictProxy instance, " @@ -1852,9 +1276,10 @@ cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args, return -1; } - md = (MultiDictObject*)arg; - if (CIMultiDictProxy_CheckExact(arg)) { + if (CIMultiDictProxy_Check(state, arg)) { md = ((MultiDictProxyObject*)arg)->md; + } else { + md = (MultiDictObject*)arg; } Py_INCREF(md); self->md = md; @@ -1865,7 +1290,7 @@ cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args, static inline PyObject * cimultidict_proxy_copy(MultiDictProxyObject *self) { - return _multidict_proxy_copy(self, &cimultidict_type); + return _multidict_proxy_copy(self, self->md->pairs.state->CIMultiDictType); } @@ -1888,23 +1313,22 @@ static PyMethodDef cimultidict_proxy_methods[] = { } /* sentinel */ }; -static PyTypeObject cimultidict_proxy_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "multidict._multidict.CIMultiDictProxy", /* tp_name */ - sizeof(MultiDictProxyObject), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_proxy_tp_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_doc = CIMultDictProxy_doc, - .tp_traverse = (traverseproc)multidict_proxy_tp_traverse, - .tp_clear = (inquiry)multidict_proxy_tp_clear, - .tp_richcompare = (richcmpfunc)multidict_proxy_tp_richcompare, - .tp_weaklistoffset = offsetof(MultiDictProxyObject, weaklist), - .tp_methods = cimultidict_proxy_methods, - .tp_base = &multidict_proxy_type, - .tp_init = (initproc)cimultidict_proxy_tp_init, - .tp_alloc = PyType_GenericAlloc, - .tp_new = PyType_GenericNew, - .tp_free = PyObject_GC_Del, +static PyType_Slot cimultidict_proxy_slots[] = { + {Py_tp_doc, (void *)CIMultDictProxy_doc}, + {Py_tp_methods, cimultidict_proxy_methods}, + {Py_tp_init, cimultidict_proxy_tp_init}, + {0, NULL}, +}; + +static PyType_Spec cimultidict_proxy_spec = { + .name = "multidict._multidict.CIMultiDictProxy", + .basicsize = sizeof(MultiDictProxyObject), + .flags = (Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX >= 0x030a00f0 + | Py_TPFLAGS_IMMUTABLETYPE +#endif + | Py_TPFLAGS_BASETYPE), + .slots = cimultidict_proxy_slots, }; /******************** Other functions ********************/ @@ -1912,10 +1336,11 @@ static PyTypeObject cimultidict_proxy_type = { static inline PyObject * getversion(PyObject *self, PyObject *md) { + mod_state *state = get_mod_state(self); pair_list_t *pairs = NULL; - if (MultiDict_CheckExact(md) || CIMultiDict_CheckExact(md)) { + if (AnyMultiDict_Check(state, md)) { pairs = &((MultiDictObject*)md)->pairs; - } else if (MultiDictProxy_CheckExact(md) || CIMultiDictProxy_CheckExact(md)) { + } else if (AnyMultiDictProxy_Check(state, md)) { pairs = &((MultiDictProxyObject*)md)->md->pairs; } else { PyErr_Format(PyExc_TypeError, "unexpected type"); @@ -1926,187 +1351,189 @@ getversion(PyObject *self, PyObject *md) /******************** Module ********************/ +static int +module_traverse(PyObject *mod, visitproc visit, void *arg) +{ + mod_state *state = get_mod_state(mod); + + Py_VISIT(state->IStrType); + + Py_VISIT(state->MultiDictType); + Py_VISIT(state->CIMultiDictType); + Py_VISIT(state->MultiDictProxyType); + Py_VISIT(state->CIMultiDictProxyType); + + Py_VISIT(state->KeysViewType); + Py_VISIT(state->ItemsViewType); + Py_VISIT(state->ValuesViewType); + + Py_VISIT(state->KeysIterType); + Py_VISIT(state->ItemsIterType); + Py_VISIT(state->ValuesIterType); + + Py_VISIT(state->str_lower); + Py_VISIT(state->str_canonical); + + return 0; +} + +static int +module_clear(PyObject *mod) +{ + mod_state *state = get_mod_state(mod); + + Py_CLEAR(state->IStrType); + + Py_CLEAR(state->MultiDictType); + Py_CLEAR(state->CIMultiDictType); + Py_CLEAR(state->MultiDictProxyType); + Py_CLEAR(state->CIMultiDictProxyType); + + Py_CLEAR(state->KeysViewType); + Py_CLEAR(state->ItemsViewType); + Py_CLEAR(state->ValuesViewType); + + Py_CLEAR(state->KeysIterType); + Py_CLEAR(state->ItemsIterType); + Py_CLEAR(state->ValuesIterType); + + Py_CLEAR(state->str_lower); + Py_CLEAR(state->str_canonical); + + return 0; +} + static inline void -module_free(void *m) +module_free(void *mod) { - Py_CLEAR(multidict_str_lower); - Py_CLEAR(collections_abc_mapping); - Py_CLEAR(collections_abc_mut_mapping); - Py_CLEAR(collections_abc_mut_multi_mapping); + (void)module_clear((PyObject *)mod); } -static PyMethodDef multidict_module_methods[] = { - { - "getversion", - (PyCFunction)getversion, - METH_O - }, - { - NULL, - NULL - } /* sentinel */ +static PyMethodDef module_methods[] = { + {"getversion", (PyCFunction)getversion, METH_O}, + {NULL, NULL} /* sentinel */ }; -static PyModuleDef multidict_module = { - PyModuleDef_HEAD_INIT, /* m_base */ - "_multidict", /* m_name */ - .m_size = -1, - .m_methods = multidict_module_methods, - .m_free = (freefunc)module_free, -}; -PyMODINIT_FUNC -PyInit__multidict(void) +static int +module_exec(PyObject *mod) { - multidict_str_lower = PyUnicode_InternFromString("lower"); - if (multidict_str_lower == NULL) { + mod_state *state = get_mod_state(mod); + PyObject *tmp; + PyObject *tpl = NULL; + + state->str_lower = PyUnicode_InternFromString("lower"); + if (state->str_lower == NULL) { goto fail; } - - PyObject *module = NULL, - *reg_func_call_result = NULL; - - if (multidict_views_init() < 0) { + state->str_canonical = PyUnicode_InternFromString("_canonical"); + if (state->str_canonical == NULL) { goto fail; } - if (multidict_iter_init() < 0) { + if (multidict_views_init(mod, state) < 0) { goto fail; } - if (istr_init() < 0) { + if (multidict_iter_init(mod, state) < 0) { goto fail; } - if (PyType_Ready(&multidict_type) < 0 || - PyType_Ready(&cimultidict_type) < 0 || - PyType_Ready(&multidict_proxy_type) < 0 || - PyType_Ready(&cimultidict_proxy_type) < 0) - { + if (istr_init(mod, state) < 0) { goto fail; } -#define WITH_MOD(NAME) \ - Py_CLEAR(module); \ - module = PyImport_ImportModule(NAME); \ - if (module == NULL) { \ - goto fail; \ + tmp = PyType_FromModuleAndSpec(mod, &multidict_spec, NULL); + if (tmp == NULL) { + goto fail; } + state->MultiDictType = (PyTypeObject *)tmp; -#define GET_MOD_ATTR(VAR, NAME) \ - VAR = PyObject_GetAttrString(module, NAME); \ - if (VAR == NULL) { \ - goto fail; \ + tpl = PyTuple_Pack(1, (PyObject *)state->MultiDictType); + if (tpl == NULL) { + goto fail; } - - WITH_MOD("collections.abc"); - GET_MOD_ATTR(collections_abc_mapping, "Mapping"); - - WITH_MOD("multidict._abc"); - GET_MOD_ATTR(collections_abc_mut_mapping, "MultiMapping"); - GET_MOD_ATTR(collections_abc_mut_multi_mapping, "MutableMultiMapping"); - - WITH_MOD("multidict._multidict_base"); - GET_MOD_ATTR(repr_func, "_mdrepr"); - - Py_CLEAR(module); \ - - /* Register in _abc mappings (CI)MultiDict and (CI)MultiDictProxy */ - reg_func_call_result = PyObject_CallMethod( - collections_abc_mut_mapping, - "register", "O", - (PyObject*)&multidict_proxy_type - ); - if (reg_func_call_result == NULL) { + tmp = PyType_FromModuleAndSpec(mod, &cimultidict_spec, tpl); + if (tmp == NULL) { goto fail; } - Py_DECREF(reg_func_call_result); + state->CIMultiDictType = (PyTypeObject *)tmp; + Py_CLEAR(tpl); - reg_func_call_result = PyObject_CallMethod( - collections_abc_mut_mapping, - "register", "O", - (PyObject*)&cimultidict_proxy_type - ); - if (reg_func_call_result == NULL) { + tmp = PyType_FromModuleAndSpec(mod, &multidict_proxy_spec, NULL); + if (tmp == NULL) { goto fail; } - Py_DECREF(reg_func_call_result); + state->MultiDictProxyType = (PyTypeObject *)tmp; - reg_func_call_result = PyObject_CallMethod( - collections_abc_mut_multi_mapping, - "register", "O", - (PyObject*)&multidict_type - ); - if (reg_func_call_result == NULL) { + tpl = PyTuple_Pack(1, (PyObject *)state->MultiDictProxyType); + if (tpl == NULL) { goto fail; } - Py_DECREF(reg_func_call_result); - - reg_func_call_result = PyObject_CallMethod( - collections_abc_mut_multi_mapping, - "register", "O", - (PyObject*)&cimultidict_type - ); - if (reg_func_call_result == NULL) { + tmp = PyType_FromModuleAndSpec(mod, &cimultidict_proxy_spec, tpl); + if (tmp == NULL) { goto fail; } - Py_DECREF(reg_func_call_result); + state->CIMultiDictProxyType = (PyTypeObject *)tmp; + Py_CLEAR(tpl); - /* Instantiate this module */ - module = PyModule_Create(&multidict_module); - if (module == NULL) { + if (PyModule_AddType(mod, state->IStrType) < 0) { goto fail; } - -#ifdef Py_GIL_DISABLED - PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED); -#endif - - Py_INCREF(&istr_type); - if (PyModule_AddObject( - module, "istr", (PyObject*)&istr_type) < 0) - { + if (PyModule_AddType(mod, state->MultiDictType) < 0) { goto fail; } - - Py_INCREF(&multidict_type); - if (PyModule_AddObject( - module, "MultiDict", (PyObject*)&multidict_type) < 0) - { + if (PyModule_AddType(mod, state->CIMultiDictType) < 0) { goto fail; } - - Py_INCREF(&cimultidict_type); - if (PyModule_AddObject( - module, "CIMultiDict", (PyObject*)&cimultidict_type) < 0) - { + if (PyModule_AddType(mod, state->MultiDictProxyType) < 0) { goto fail; } - - Py_INCREF(&multidict_proxy_type); - if (PyModule_AddObject( - module, "MultiDictProxy", (PyObject*)&multidict_proxy_type) < 0) - { + if (PyModule_AddType(mod, state->CIMultiDictProxyType) < 0) { goto fail; } - - Py_INCREF(&cimultidict_proxy_type); - if (PyModule_AddObject( - module, "CIMultiDictProxy", (PyObject*)&cimultidict_proxy_type) < 0) - { + if (PyModule_AddType(mod, state->ItemsViewType) < 0) { + goto fail; + } + if (PyModule_AddType(mod, state->KeysViewType) < 0) { + goto fail; + } + if (PyModule_AddType(mod, state->ValuesViewType) < 0) { goto fail; } - return module; - + return 0; fail: - Py_XDECREF(multidict_str_lower); - Py_XDECREF(collections_abc_mapping); - Py_XDECREF(collections_abc_mut_mapping); - Py_XDECREF(collections_abc_mut_multi_mapping); + Py_CLEAR(tpl); + return -1; +} - return NULL; -#undef WITH_MOD -#undef GET_MOD_ATTR +static struct PyModuleDef_Slot module_slots[] = { + {Py_mod_exec, module_exec}, +#if PY_VERSION_HEX >= 0x030c00f0 + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, +#endif +#if PY_VERSION_HEX >= 0x030d00f0 + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, +#endif + {0, NULL}, +}; + + +static PyModuleDef multidict_module = { + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "_multidict", + .m_size = sizeof(mod_state), + .m_methods = module_methods, + .m_slots = module_slots, + .m_traverse = module_traverse, + .m_clear = module_clear, + .m_free = (freefunc)module_free, +}; + +PyMODINIT_FUNC +PyInit__multidict(void) +{ + return PyModuleDef_Init(&multidict_module); } diff --git a/contrib/python/multidict/multidict/_multidict_base.py b/contrib/python/multidict/multidict/_multidict_base.py deleted file mode 100644 index df0d70097a10..000000000000 --- a/contrib/python/multidict/multidict/_multidict_base.py +++ /dev/null @@ -1,176 +0,0 @@ -import sys -from collections.abc import ( - Container, - ItemsView, - Iterable, - KeysView, - Mapping, - Set, - ValuesView, -) -from typing import Literal, Union - -if sys.version_info >= (3, 10): - from types import NotImplementedType -else: - from typing import Any as NotImplementedType - -if sys.version_info >= (3, 11): - from typing import assert_never -else: - from typing_extensions import assert_never - - -def _abc_itemsview_register(view_cls: type[object]) -> None: - ItemsView.register(view_cls) - - -def _abc_keysview_register(view_cls: type[object]) -> None: - KeysView.register(view_cls) - - -def _abc_valuesview_register(view_cls: type[object]) -> None: - ValuesView.register(view_cls) - - -def _viewbaseset_richcmp( - view: set[object], other: object, op: Literal[0, 1, 2, 3, 4, 5] -) -> Union[bool, NotImplementedType]: - if op == 0: # < - if not isinstance(other, Set): - return NotImplemented # type: ignore[no-any-return] - return len(view) < len(other) and view <= other - elif op == 1: # <= - if not isinstance(other, Set): - return NotImplemented # type: ignore[no-any-return] - if len(view) > len(other): - return False - for elem in view: - if elem not in other: - return False - return True - elif op == 2: # == - if not isinstance(other, Set): - return NotImplemented # type: ignore[no-any-return] - return len(view) == len(other) and view <= other - elif op == 3: # != - return not view == other - elif op == 4: # > - if not isinstance(other, Set): - return NotImplemented # type: ignore[no-any-return] - return len(view) > len(other) and view >= other - elif op == 5: # >= - if not isinstance(other, Set): - return NotImplemented # type: ignore[no-any-return] - if len(view) < len(other): - return False - for elem in other: - if elem not in view: - return False - return True - else: # pragma: no cover - assert_never(op) - - -def _viewbaseset_and( - view: set[object], other: object -) -> Union[set[object], NotImplementedType]: - if not isinstance(other, Iterable): - return NotImplemented # type: ignore[no-any-return] - if isinstance(view, Set): - view = set(iter(view)) - if isinstance(other, Set): - other = set(iter(other)) - if not isinstance(other, Set): - other = set(iter(other)) - return view & other - - -def _viewbaseset_or( - view: set[object], other: object -) -> Union[set[object], NotImplementedType]: - if not isinstance(other, Iterable): - return NotImplemented # type: ignore[no-any-return] - if isinstance(view, Set): - view = set(iter(view)) - if isinstance(other, Set): - other = set(iter(other)) - if not isinstance(other, Set): - other = set(iter(other)) - return view | other - - -def _viewbaseset_sub( - view: set[object], other: object -) -> Union[set[object], NotImplementedType]: - if not isinstance(other, Iterable): - return NotImplemented # type: ignore[no-any-return] - if isinstance(view, Set): - view = set(iter(view)) - if isinstance(other, Set): - other = set(iter(other)) - if not isinstance(other, Set): - other = set(iter(other)) - return view - other - - -def _viewbaseset_xor( - view: set[object], other: object -) -> Union[set[object], NotImplementedType]: - if not isinstance(other, Iterable): - return NotImplemented # type: ignore[no-any-return] - if isinstance(view, Set): - view = set(iter(view)) - if isinstance(other, Set): - other = set(iter(other)) - if not isinstance(other, Set): - other = set(iter(other)) - return view ^ other - - -def _itemsview_isdisjoint(view: Container[object], other: Iterable[object]) -> bool: - "Return True if two sets have a null intersection." - for v in other: - if v in view: - return False - return True - - -def _itemsview_repr(view: Iterable[tuple[object, object]]) -> str: - lst = [] - for k, v in view: - lst.append("{!r}: {!r}".format(k, v)) - body = ", ".join(lst) - return "{}({})".format(view.__class__.__name__, body) - - -def _keysview_isdisjoint(view: Container[object], other: Iterable[object]) -> bool: - "Return True if two sets have a null intersection." - for k in other: - if k in view: - return False - return True - - -def _keysview_repr(view: Iterable[object]) -> str: - lst = [] - for k in view: - lst.append("{!r}".format(k)) - body = ", ".join(lst) - return "{}({})".format(view.__class__.__name__, body) - - -def _valuesview_repr(view: Iterable[object]) -> str: - lst = [] - for v in view: - lst.append("{!r}".format(v)) - body = ", ".join(lst) - return "{}({})".format(view.__class__.__name__, body) - - -def _mdrepr(md: Mapping[object, object]) -> str: - lst = [] - for k, v in md.items(): - lst.append("'{}': {!r}".format(k, v)) - body = ", ".join(lst) - return "<{}({})>".format(md.__class__.__name__, body) diff --git a/contrib/python/multidict/multidict/_multidict_py.py b/contrib/python/multidict/multidict/_multidict_py.py index b8ecb8b96236..3176861e787a 100644 --- a/contrib/python/multidict/multidict/_multidict_py.py +++ b/contrib/python/multidict/multidict/_multidict_py.py @@ -1,5 +1,7 @@ import enum +import reprlib import sys +from abc import abstractmethod from array import array from collections.abc import ( Callable, @@ -12,8 +14,10 @@ ) from typing import ( TYPE_CHECKING, + Any, Generic, NoReturn, + Optional, TypeVar, Union, cast, @@ -32,6 +36,7 @@ class istr(str): """Case insensitive str.""" __is_istr__ = True + __istr_title__: Optional[str] = None _V = TypeVar("_V") @@ -51,7 +56,6 @@ def __init__(self) -> None: self.incr_version() def incr_version(self) -> None: - global _version v = _version v[0] += 1 self._version = v[0] @@ -80,8 +84,15 @@ def __length_hint__(self) -> int: class _ViewBase(Generic[_V]): - def __init__(self, impl: _Impl[_V]): + def __init__( + self, + impl: _Impl[_V], + identfunc: Callable[[str], str], + keyfunc: Callable[[str], str], + ): self._impl = impl + self._identfunc = identfunc + self._keyfunc = keyfunc def __len__(self) -> int: return len(self._impl._items) @@ -91,8 +102,13 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]): def __contains__(self, item: object) -> bool: if not isinstance(item, (tuple, list)) or len(item) != 2: return False + key, value = item + try: + ident = self._identfunc(key) + except TypeError: + return False for i, k, v in self._impl._items: - if item[0] == k and item[1] == v: + if ident == i and value == v: return True return False @@ -103,20 +119,164 @@ def _iter(self, version: int) -> Iterator[tuple[str, _V]]: for i, k, v in self._impl._items: if version != self._impl._version: raise RuntimeError("Dictionary changed during iteration") - yield k, v + yield self._keyfunc(k), v + @reprlib.recursive_repr() def __repr__(self) -> str: lst = [] - for item in self._impl._items: - lst.append("{!r}: {!r}".format(item[1], item[2])) + for i, k, v in self._impl._items: + lst.append(f"'{k}': {v!r}") body = ", ".join(lst) - return "{}({})".format(self.__class__.__name__, body) + return f"<{self.__class__.__name__}({body})>" + + def _parse_item( + self, arg: Union[tuple[str, _V], _T] + ) -> Optional[tuple[str, str, _V]]: + if not isinstance(arg, tuple): + return None + if len(arg) != 2: + return None + try: + return (self._identfunc(arg[0]), arg[0], arg[1]) + except TypeError: + return None + + def _tmp_set(self, it: Iterable[_T]) -> set[tuple[str, _V]]: + tmp = set() + for arg in it: + item = self._parse_item(arg) + if item is None: + continue + else: + tmp.add((item[0], item[2])) + return tmp + + def __and__(self, other: Iterable[Any]) -> set[tuple[str, _V]]: + ret = set() + try: + it = iter(other) + except TypeError: + return NotImplemented + for arg in it: + item = self._parse_item(arg) + if item is None: + continue + identity, key, value = item + for i, k, v in self._impl._items: + if i == identity and v == value: + ret.add((k, v)) + return ret + + def __rand__(self, other: Iterable[_T]) -> set[_T]: + ret = set() + try: + it = iter(other) + except TypeError: + return NotImplemented + for arg in it: + item = self._parse_item(arg) + if item is None: + continue + identity, key, value = item + for i, k, v in self._impl._items: + if i == identity and v == value: + ret.add(arg) + break + return ret + + def __or__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]: + ret: set[Union[tuple[str, _V], _T]] = set(self) + try: + it = iter(other) + except TypeError: + return NotImplemented + for arg in it: + item: Optional[tuple[str, str, _V]] = self._parse_item(arg) + if item is None: + ret.add(arg) + continue + identity, key, value = item + for i, k, v in self._impl._items: + if i == identity and v == value: + break + else: + ret.add(arg) + return ret + + def __ror__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]: + try: + ret: set[Union[tuple[str, _V], _T]] = set(other) + except TypeError: + return NotImplemented + tmp = self._tmp_set(ret) + + for i, k, v in self._impl._items: + if (i, v) not in tmp: + ret.add((k, v)) + return ret + + def __sub__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]: + ret: set[Union[tuple[str, _V], _T]] = set() + try: + it = iter(other) + except TypeError: + return NotImplemented + tmp = self._tmp_set(it) + + for i, k, v in self._impl._items: + if (i, v) not in tmp: + ret.add((k, v)) + + return ret + + def __rsub__(self, other: Iterable[_T]) -> set[_T]: + ret: set[_T] = set() + try: + it = iter(other) + except TypeError: + return NotImplemented + for arg in it: + item = self._parse_item(arg) + if item is None: + ret.add(arg) + continue + + identity, key, value = item + for i, k, v in self._impl._items: + if i == identity and v == value: + break + else: + ret.add(arg) + return ret + + def __xor__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]: + try: + rgt = set(other) + except TypeError: + return NotImplemented + ret: set[Union[tuple[str, _V], _T]] = self - rgt + ret |= rgt - self + return ret + + __rxor__ = __xor__ + + def isdisjoint(self, other: Iterable[tuple[str, _V]]) -> bool: + for arg in other: + item = self._parse_item(arg) + if item is None: + continue + + identity, key, value = item + for i, k, v in self._impl._items: + if i == identity and v == value: + return False + return True class _ValuesView(_ViewBase[_V], ValuesView[_V]): def __contains__(self, value: object) -> bool: - for item in self._impl._items: - if item[2] == value: + for i, k, v in self._impl._items: + if v == value: return True return False @@ -124,23 +284,27 @@ def __iter__(self) -> _Iter[_V]: return _Iter(len(self), self._iter(self._impl._version)) def _iter(self, version: int) -> Iterator[_V]: - for item in self._impl._items: + for i, k, v in self._impl._items: if version != self._impl._version: raise RuntimeError("Dictionary changed during iteration") - yield item[2] + yield v + @reprlib.recursive_repr() def __repr__(self) -> str: lst = [] - for item in self._impl._items: - lst.append("{!r}".format(item[2])) + for i, k, v in self._impl._items: + lst.append(repr(v)) body = ", ".join(lst) - return "{}({})".format(self.__class__.__name__, body) + return f"<{self.__class__.__name__}({body})>" class _KeysView(_ViewBase[_V], KeysView[str]): def __contains__(self, key: object) -> bool: - for item in self._impl._items: - if item[1] == key: + if not isinstance(key, str): + return False + identity = self._identfunc(key) + for i, k, v in self._impl._items: + if i == identity: return True return False @@ -148,24 +312,179 @@ def __iter__(self) -> _Iter[str]: return _Iter(len(self), self._iter(self._impl._version)) def _iter(self, version: int) -> Iterator[str]: - for item in self._impl._items: + for i, k, v in self._impl._items: if version != self._impl._version: raise RuntimeError("Dictionary changed during iteration") - yield item[1] + yield self._keyfunc(k) def __repr__(self) -> str: lst = [] - for item in self._impl._items: - lst.append("{!r}".format(item[1])) + for i, k, v in self._impl._items: + lst.append(f"'{k}'") body = ", ".join(lst) - return "{}({})".format(self.__class__.__name__, body) + return f"<{self.__class__.__name__}({body})>" + + def __and__(self, other: Iterable[object]) -> set[str]: + ret = set() + try: + it = iter(other) + except TypeError: + return NotImplemented + for key in it: + if not isinstance(key, str): + continue + identity = self._identfunc(key) + for i, k, v in self._impl._items: + if i == identity: + ret.add(k) + return ret + + def __rand__(self, other: Iterable[_T]) -> set[_T]: + ret = set() + try: + it = iter(other) + except TypeError: + return NotImplemented + for key in it: + if not isinstance(key, str): + continue + identity = self._identfunc(key) + for i, k, v in self._impl._items: + if i == identity: + ret.add(key) + return cast(set[_T], ret) + + def __or__(self, other: Iterable[_T]) -> set[Union[str, _T]]: + ret: set[Union[str, _T]] = set(self) + try: + it = iter(other) + except TypeError: + return NotImplemented + for key in it: + if not isinstance(key, str): + ret.add(key) + continue + identity = self._identfunc(key) + for i, k, v in self._impl._items: + if i == identity: + break + else: + ret.add(key) + return ret + + def __ror__(self, other: Iterable[_T]) -> set[Union[str, _T]]: + try: + ret: set[Union[str, _T]] = set(other) + except TypeError: + return NotImplemented + + tmp = set() + for key in ret: + if not isinstance(key, str): + continue + identity = self._identfunc(key) + tmp.add(identity) + + for i, k, v in self._impl._items: + if i not in tmp: + ret.add(k) + return ret + + def __sub__(self, other: Iterable[object]) -> set[str]: + ret = set(self) + try: + it = iter(other) + except TypeError: + return NotImplemented + for key in it: + if not isinstance(key, str): + continue + identity = self._identfunc(key) + for i, k, v in self._impl._items: + if i == identity: + ret.discard(k) + break + return ret + + def __rsub__(self, other: Iterable[_T]) -> set[_T]: + try: + ret: set[_T] = set(other) + except TypeError: + return NotImplemented + for key in other: + if not isinstance(key, str): + continue + identity = self._identfunc(key) + for i, k, v in self._impl._items: + if i == identity: + ret.discard(key) # type: ignore[arg-type] + break + return ret + + def __xor__(self, other: Iterable[_T]) -> set[Union[str, _T]]: + try: + rgt = set(other) + except TypeError: + return NotImplemented + ret: set[Union[str, _T]] = self - rgt # type: ignore[assignment] + ret |= rgt - self + return ret + + __rxor__ = __xor__ + + def isdisjoint(self, other: Iterable[object]) -> bool: + for key in other: + if not isinstance(key, str): + continue + identity = self._identfunc(key) + for i, k, v in self._impl._items: + if i == identity: + return False + return True + + +class _CSMixin: + def _key(self, key: str) -> str: + return key + + def _title(self, key: str) -> str: + if isinstance(key, str): + return key + else: + raise TypeError("MultiDict keys should be either str or subclasses of str") + + +class _CIMixin: + _ci: bool = True + + def _key(self, key: str) -> str: + if type(key) is istr: + return key + else: + return istr(key) + + def _title(self, key: str) -> str: + if isinstance(key, istr): + ret = key.__istr_title__ + if ret is None: + ret = key.title() + key.__istr_title__ = ret + return ret + if isinstance(key, str): + return key.title() + else: + raise TypeError("MultiDict keys should be either str or subclasses of str") class _Base(MultiMapping[_V]): _impl: _Impl[_V] + _ci: bool = False - def _title(self, key: str) -> str: - return key + @abstractmethod + def _key(self, key: str) -> str: ... + + @abstractmethod + def _title(self, key: str) -> str: ... @overload def getall(self, key: str) -> list[_V]: ... @@ -226,15 +545,15 @@ def __len__(self) -> int: def keys(self) -> KeysView[str]: """Return a new view of the dictionary's keys.""" - return _KeysView(self._impl) + return _KeysView(self._impl, self._title, self._key) def items(self) -> ItemsView[str, _V]: """Return a new view of the dictionary's items *(key, value) pairs).""" - return _ItemsView(self._impl) + return _ItemsView(self._impl, self._title, self._key) def values(self) -> _ValuesView[_V]: """Return a new view of the dictionary's values.""" - return _ValuesView(self._impl) + return _ValuesView(self._impl, self._title, self._key) def __eq__(self, other: object) -> bool: if not isinstance(other, Mapping): @@ -265,12 +584,13 @@ def __contains__(self, key: object) -> bool: return True return False + @reprlib.recursive_repr() def __repr__(self) -> str: - body = ", ".join("'{}': {!r}".format(k, v) for k, v in self.items()) - return "<{}({})>".format(self.__class__.__name__, body) + body = ", ".join(f"'{k}': {v!r}" for i, k, v in self._impl._items) + return f"<{self.__class__.__name__}({body})>" -class MultiDict(_Base[_V], MutableMultiMapping[_V]): +class MultiDict(_CSMixin, _Base[_V], MutableMultiMapping[_V]): """Dictionary with the support for duplicate keys.""" def __init__(self, arg: MDArg[_V] = None, /, **kwargs: _V): @@ -286,18 +606,9 @@ def __sizeof__(self) -> int: def __reduce__(self) -> tuple[type[Self], tuple[list[tuple[str, _V]]]]: return (self.__class__, (list(self.items()),)) - def _title(self, key: str) -> str: - return key - - def _key(self, key: str) -> str: - if isinstance(key, str): - return key - else: - raise TypeError("MultiDict keys should be either str or subclasses of str") - def add(self, key: str, value: _V) -> None: identity = self._title(key) - self._impl._items.append((identity, self._key(key), value)) + self._impl._items.append((identity, key, value)) self._impl.incr_version() def copy(self) -> Self: @@ -322,8 +633,16 @@ def _extend( method: Callable[[list[tuple[str, str, _V]]], None], ) -> None: if arg: - if isinstance(arg, (MultiDict, MultiDictProxy)) and not kwargs: - items = arg._impl._items + if isinstance(arg, (MultiDict, MultiDictProxy)): + if self._ci is not arg._ci: + items = [(self._title(k), k, v) for _, k, v in arg._impl._items] + else: + items = arg._impl._items + if kwargs: + items = items.copy() + if kwargs: + for key, value in kwargs.items(): + items.append((self._title(key), key, value)) else: if hasattr(arg, "keys"): arg = cast(SupportsKeys[_V], arg) @@ -332,26 +651,22 @@ def _extend( arg = list(arg) arg.extend(list(kwargs.items())) items = [] - for item in arg: + for pos, item in enumerate(arg): if not len(item) == 2: - raise TypeError( - "{} takes either dict or list of (key, value) " - "tuples".format(name) + raise ValueError( + f"multidict update sequence element #{pos}" + f"has length {len(item)}; 2 is required" ) - items.append((self._title(item[0]), self._key(item[0]), item[1])) + items.append((self._title(item[0]), item[0], item[1])) method(items) else: - method( - [ - (self._title(key), self._key(key), value) - for key, value in kwargs.items() - ] - ) + method([(self._title(key), key, value) for key, value in kwargs.items()]) def _extend_items(self, items: Iterable[tuple[str, str, _V]]) -> None: for identity, key, value in items: - self.add(key, value) + self._impl._items.append((identity, key, value)) + self._impl.incr_version() def clear(self) -> None: """Remove all items from MultiDict.""" @@ -456,9 +771,9 @@ def popall( def popitem(self) -> tuple[str, _V]: """Remove and return an arbitrary (key, value) pair.""" if self._impl._items: - i = self._impl._items.pop(0) + i, k, v = self._impl._items.pop() self._impl.incr_version() - return i[1], i[2] + return self._key(k), v else: raise KeyError("empty multidict") @@ -499,7 +814,6 @@ def _update_items(self, items: list[tuple[str, str, _V]]) -> None: self._impl.incr_version() def _replace(self, key: str, value: _V) -> None: - key = self._key(key) identity = self._title(key) items = self._impl._items @@ -527,48 +841,42 @@ def _replace(self, key: str, value: _V) -> None: i += 1 -class CIMultiDict(MultiDict[_V]): +class CIMultiDict(_CIMixin, MultiDict[_V]): """Dictionary with the support for duplicate case-insensitive keys.""" - def _title(self, key: str) -> str: - return key.title() - -class MultiDictProxy(_Base[_V]): +class MultiDictProxy(_CSMixin, _Base[_V]): """Read-only proxy for MultiDict instance.""" def __init__(self, arg: Union[MultiDict[_V], "MultiDictProxy[_V]"]): if not isinstance(arg, (MultiDict, MultiDictProxy)): raise TypeError( "ctor requires MultiDict or MultiDictProxy instance" - ", not {}".format(type(arg)) + f", not {type(arg)}" ) self._impl = arg._impl def __reduce__(self) -> NoReturn: - raise TypeError("can't pickle {} objects".format(self.__class__.__name__)) + raise TypeError(f"can't pickle {self.__class__.__name__} objects") def copy(self) -> MultiDict[_V]: """Return a copy of itself.""" return MultiDict(self.items()) -class CIMultiDictProxy(MultiDictProxy[_V]): +class CIMultiDictProxy(_CIMixin, MultiDictProxy[_V]): """Read-only proxy for CIMultiDict instance.""" def __init__(self, arg: Union[MultiDict[_V], MultiDictProxy[_V]]): if not isinstance(arg, (CIMultiDict, CIMultiDictProxy)): raise TypeError( "ctor requires CIMultiDict or CIMultiDictProxy instance" - ", not {}".format(type(arg)) + f", not {type(arg)}" ) self._impl = arg._impl - def _title(self, key: str) -> str: - return key.title() - def copy(self) -> CIMultiDict[_V]: """Return a copy of itself.""" return CIMultiDict(self.items()) diff --git a/contrib/python/multidict/multidict/_multilib/defs.h b/contrib/python/multidict/multidict/_multilib/defs.h deleted file mode 100644 index 51a6639c4286..000000000000 --- a/contrib/python/multidict/multidict/_multilib/defs.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _MULTIDICT_DEFS_H -#define _MULTIDICT_DEFS_H - -#ifdef __cplusplus -extern "C" { -#endif - -static PyObject *multidict_str_lower = NULL; - -/* We link this module statically for convenience. If compiled as a shared - library instead, some compilers don't allow addresses of Python objects - defined in other libraries to be used in static initializers here. The - DEFERRED_ADDRESS macro is used to tag the slots where such addresses - appear; the module init function must fill in the tagged slots at runtime. - The argument is for documentation -- the macro ignores it. -*/ -#define DEFERRED_ADDRESS(ADDR) 0 - -#ifdef __cplusplus -} -#endif -#endif diff --git a/contrib/python/multidict/multidict/_multilib/dict.h b/contrib/python/multidict/multidict/_multilib/dict.h index 3caf83e5b4c0..fa07fdf4ac39 100644 --- a/contrib/python/multidict/multidict/_multilib/dict.h +++ b/contrib/python/multidict/multidict/_multilib/dict.h @@ -5,18 +5,31 @@ extern "C" { #endif +#include "pythoncapi_compat.h" +#include "pair_list.h" + +#if PY_VERSION_HEX >= 0x030c00f0 +#define MANAGED_WEAKREFS +#endif + + typedef struct { // 16 or 24 for GC prefix PyObject_HEAD // 16 +#ifndef MANAGED_WEAKREFS PyObject *weaklist; +#endif pair_list_t pairs; } MultiDictObject; typedef struct { PyObject_HEAD +#ifndef MANAGED_WEAKREFS PyObject *weaklist; +#endif MultiDictObject *md; } MultiDictProxyObject; + #ifdef __cplusplus } #endif diff --git a/contrib/python/multidict/multidict/_multilib/istr.h b/contrib/python/multidict/multidict/_multilib/istr.h index 8454f78b88bb..156b0dc04a38 100644 --- a/contrib/python/multidict/multidict/_multilib/istr.h +++ b/contrib/python/multidict/multidict/_multilib/istr.h @@ -5,14 +5,19 @@ extern "C" { #endif +#include "state.h" + typedef struct { PyUnicodeObject str; PyObject * canonical; + mod_state *state; } istrobject; -PyDoc_STRVAR(istr__doc__, "istr class implementation"); +#define IStr_CheckExact(state, obj) Py_IS_TYPE(obj, state->IStrType) +#define IStr_Check(state, obj) \ + (IStr_CheckExact(state, obj) || PyObject_TypeCheck(obj, state->IStrType)) -static PyTypeObject istr_type; +PyDoc_STRVAR(istr__doc__, "istr class implementation"); static inline void istr_dealloc(istrobject *self) @@ -24,18 +29,24 @@ istr_dealloc(istrobject *self) static inline PyObject * istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + PyObject *mod = PyType_GetModuleByDef(type, &multidict_module); + if (mod == NULL) { + return NULL; + } + mod_state *state = get_mod_state(mod); + PyObject *x = NULL; static char *kwlist[] = {"object", "encoding", "errors", 0}; PyObject *encoding = NULL; PyObject *errors = NULL; - PyObject *s = NULL; - PyObject * ret = NULL; + PyObject *canonical = NULL; + PyObject *ret = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO:str", kwlist, &x, &encoding, &errors)) { return NULL; } - if (x != NULL && Py_TYPE(x) == &istr_type) { + if (x != NULL && IStr_Check(state, x)) { Py_INCREF(x); return x; } @@ -43,39 +54,101 @@ istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (!ret) { goto fail; } - s = PyObject_CallMethodNoArgs(ret, multidict_str_lower); - if (!s) { + canonical = PyObject_CallMethodNoArgs(ret, state->str_lower); + if (!canonical) { goto fail; } - ((istrobject*)ret)->canonical = s; - s = NULL; /* the reference is stollen by .canonical */ + ((istrobject*)ret)->canonical = canonical; + ((istrobject*)ret)->state = state; return ret; fail: Py_XDECREF(ret); return NULL; } -static PyTypeObject istr_type = { - PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) - "multidict._multidict.istr", - sizeof(istrobject), - .tp_dealloc = (destructor)istr_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT +static inline PyObject * +istr_reduce(PyObject *self) +{ + PyObject *str = NULL; + PyObject *args = NULL; + PyObject *result = NULL; + + str = PyUnicode_FromObject(self); + if (str == NULL) { + goto ret; + } + args = PyTuple_Pack(1, str); + if (args == NULL) { + goto ret; + } + result = PyTuple_Pack(2, Py_TYPE(self), args); +ret: + Py_CLEAR(str); + Py_CLEAR(args); + return result; +} + + +static PyMethodDef istr_methods[] = { + {"__reduce__", (PyCFunction)istr_reduce, METH_NOARGS, NULL}, + {NULL, NULL} /* sentinel */ +}; + +static PyType_Slot istr_slots[] = { + {Py_tp_dealloc, istr_dealloc}, + {Py_tp_doc, (void *)istr__doc__}, + {Py_tp_methods, istr_methods}, + {Py_tp_new, istr_new}, + {0, NULL}, +}; + +static PyType_Spec istr_spec = { + .name = "multidict._multidict.istr", + .basicsize = sizeof(istrobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_UNICODE_SUBCLASS, - .tp_doc = istr__doc__, - .tp_base = DEFERRED_ADDRESS(&PyUnicode_Type), - .tp_new = (newfunc)istr_new, +#if PY_VERSION_HEX >= 0x030a00f0 + | Py_TPFLAGS_IMMUTABLETYPE +#endif + | Py_TPFLAGS_UNICODE_SUBCLASS), + .slots = istr_slots, }; +static inline PyObject * +IStr_New(mod_state *state, PyObject *str, PyObject *canonical) +{ + PyObject *args = NULL; + PyObject *res = NULL; + args = PyTuple_Pack(1, str); + if (args == NULL) { + goto ret; + } + res = PyUnicode_Type.tp_new(state->IStrType, args, NULL); + if (!res) { + goto ret; + } + Py_INCREF(canonical); + ((istrobject*)res)->canonical = canonical; + ((istrobject*)res)->state = state; +ret: + Py_CLEAR(args); + return res; +} + static inline int -istr_init(void) +istr_init(PyObject *module, mod_state *state) { - istr_type.tp_base = &PyUnicode_Type; - if (PyType_Ready(&istr_type) < 0) { + PyObject *tpl = PyTuple_Pack(1, (PyObject *)&PyUnicode_Type); + if (tpl == NULL) { + return -1; + } + PyObject *tmp = PyType_FromModuleAndSpec(module, &istr_spec, tpl); + Py_DECREF(tpl); + if (tmp == NULL) { return -1; } + state->IStrType = (PyTypeObject *)tmp; return 0; } diff --git a/contrib/python/multidict/multidict/_multilib/iter.h b/contrib/python/multidict/multidict/_multilib/iter.h index 9ee337538261..2f3ca9de84cc 100644 --- a/contrib/python/multidict/multidict/_multilib/iter.h +++ b/contrib/python/multidict/multidict/_multilib/iter.h @@ -5,15 +5,14 @@ extern "C" { #endif -static PyTypeObject multidict_items_iter_type; -static PyTypeObject multidict_values_iter_type; -static PyTypeObject multidict_keys_iter_type; +#include "dict.h" +#include "pair_list.h" +#include "state.h" typedef struct multidict_iter { PyObject_HEAD MultiDictObject *md; // MultiDict or CIMultiDict - Py_ssize_t current; - uint64_t version; + pair_list_pos_t current; } MultidictIter; static inline void @@ -22,15 +21,14 @@ _init_iter(MultidictIter *it, MultiDictObject *md) Py_INCREF(md); it->md = md; - it->current = 0; - it->version = pair_list_version(&md->pairs); + pair_list_init_pos(&md->pairs, &it->current); } static inline PyObject * multidict_items_iter_new(MultiDictObject *md) { MultidictIter *it = PyObject_GC_New( - MultidictIter, &multidict_items_iter_type); + MultidictIter, md->pairs.state->ItemsIterType); if (it == NULL) { return NULL; } @@ -45,7 +43,7 @@ static inline PyObject * multidict_keys_iter_new(MultiDictObject *md) { MultidictIter *it = PyObject_GC_New( - MultidictIter, &multidict_keys_iter_type); + MultidictIter, md->pairs.state->KeysIterType); if (it == NULL) { return NULL; } @@ -60,7 +58,7 @@ static inline PyObject * multidict_values_iter_new(MultiDictObject *md) { MultidictIter *it = PyObject_GC_New( - MultidictIter, &multidict_values_iter_type); + MultidictIter, md->pairs.state->ValuesIterType); if (it == NULL) { return NULL; } @@ -78,17 +76,21 @@ multidict_items_iter_iternext(MultidictIter *self) PyObject *value = NULL; PyObject *ret = NULL; - if (self->version != pair_list_version(&self->md->pairs)) { - PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration"); + int res = pair_list_next(&self->md->pairs, &self->current, + NULL, &key, &value); + if (res < 0) { return NULL; } - - if (!_pair_list_next(&self->md->pairs, &self->current, NULL, &key, &value, NULL)) { + if (res == 0) { + Py_CLEAR(key); + Py_CLEAR(value); PyErr_SetNone(PyExc_StopIteration); return NULL; } ret = PyTuple_Pack(2, key, value); + Py_CLEAR(key); + Py_CLEAR(value); if (ret == NULL) { return NULL; } @@ -101,18 +103,16 @@ multidict_values_iter_iternext(MultidictIter *self) { PyObject *value = NULL; - if (self->version != pair_list_version(&self->md->pairs)) { - PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration"); + int res = pair_list_next(&self->md->pairs, &self->current, + NULL, NULL, &value); + if (res < 0) { return NULL; } - - if (!pair_list_next(&self->md->pairs, &self->current, NULL, NULL, &value)) { + if (res == 0) { PyErr_SetNone(PyExc_StopIteration); return NULL; } - Py_INCREF(value); - return value; } @@ -121,18 +121,16 @@ multidict_keys_iter_iternext(MultidictIter *self) { PyObject *key = NULL; - if (self->version != pair_list_version(&self->md->pairs)) { - PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration"); + int res = pair_list_next(&self->md->pairs, &self->current, + NULL, &key, NULL); + if (res < 0) { return NULL; } - - if (!pair_list_next(&self->md->pairs, &self->current, NULL, &key, NULL)) { + if (res == 0) { PyErr_SetNone(PyExc_StopIteration); return NULL; } - Py_INCREF(key); - return key; } @@ -182,53 +180,92 @@ static PyMethodDef multidict_iter_methods[] = { /***********************************************************************/ -static PyTypeObject multidict_items_iter_type = { - PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) - "multidict._multidict._itemsiter", /* tp_name */ - sizeof(MultidictIter), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_iter_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_traverse = (traverseproc)multidict_iter_traverse, - .tp_clear = (inquiry)multidict_iter_clear, - .tp_iter = PyObject_SelfIter, - .tp_iternext = (iternextfunc)multidict_items_iter_iternext, - .tp_methods = multidict_iter_methods, +static PyType_Slot multidict_items_iter_slots[] = { + {Py_tp_dealloc, multidict_iter_dealloc}, + {Py_tp_methods, multidict_iter_methods}, + {Py_tp_traverse, multidict_iter_traverse}, + {Py_tp_clear, multidict_iter_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, multidict_items_iter_iternext}, + {0, NULL}, +}; + +static PyType_Spec multidict_items_iter_spec = { + .name = "multidict._multidict._itemsiter", + .basicsize = sizeof(MultidictIter), + .flags = (Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX >= 0x030a00f0 + | Py_TPFLAGS_IMMUTABLETYPE +#endif + | Py_TPFLAGS_HAVE_GC), + .slots = multidict_items_iter_slots, +}; + +static PyType_Slot multidict_values_iter_slots[] = { + {Py_tp_dealloc, multidict_iter_dealloc}, + {Py_tp_methods, multidict_iter_methods}, + {Py_tp_traverse, multidict_iter_traverse}, + {Py_tp_clear, multidict_iter_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, multidict_values_iter_iternext}, + {0, NULL}, +}; + +static PyType_Spec multidict_values_iter_spec = { + .name = "multidict._multidict._valuesiter", + .basicsize = sizeof(MultidictIter), + .flags = (Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX >= 0x030a00f0 + | Py_TPFLAGS_IMMUTABLETYPE +#endif + | Py_TPFLAGS_HAVE_GC), + .slots = multidict_values_iter_slots, }; -static PyTypeObject multidict_values_iter_type = { - PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) - "multidict._multidict._valuesiter", /* tp_name */ - sizeof(MultidictIter), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_iter_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_traverse = (traverseproc)multidict_iter_traverse, - .tp_clear = (inquiry)multidict_iter_clear, - .tp_iter = PyObject_SelfIter, - .tp_iternext = (iternextfunc)multidict_values_iter_iternext, - .tp_methods = multidict_iter_methods, + +static PyType_Slot multidict_keys_iter_slots[] = { + {Py_tp_dealloc, multidict_iter_dealloc}, + {Py_tp_methods, multidict_iter_methods}, + {Py_tp_traverse, multidict_iter_traverse}, + {Py_tp_clear, multidict_iter_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, multidict_keys_iter_iternext}, + {0, NULL}, }; -static PyTypeObject multidict_keys_iter_type = { - PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) - "multidict._multidict._keysiter", /* tp_name */ - sizeof(MultidictIter), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_iter_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_traverse = (traverseproc)multidict_iter_traverse, - .tp_clear = (inquiry)multidict_iter_clear, - .tp_iter = PyObject_SelfIter, - .tp_iternext = (iternextfunc)multidict_keys_iter_iternext, - .tp_methods = multidict_iter_methods, +static PyType_Spec multidict_keys_iter_spec = { + .name = "multidict._multidict._keysiter", + .basicsize = sizeof(MultidictIter), + .flags = (Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX >= 0x030a00f0 + | Py_TPFLAGS_IMMUTABLETYPE +#endif + | Py_TPFLAGS_HAVE_GC), + .slots = multidict_keys_iter_slots, }; static inline int -multidict_iter_init(void) +multidict_iter_init(PyObject *module, mod_state *state) { - if (PyType_Ready(&multidict_items_iter_type) < 0 || - PyType_Ready(&multidict_values_iter_type) < 0 || - PyType_Ready(&multidict_keys_iter_type) < 0) { + PyObject * tmp; + tmp = PyType_FromModuleAndSpec(module, &multidict_items_iter_spec, NULL); + if (tmp == NULL) { return -1; } + state->ItemsIterType = (PyTypeObject *)tmp; + + tmp = PyType_FromModuleAndSpec(module, &multidict_values_iter_spec, NULL); + if (tmp == NULL) { + return -1; + } + state->ValuesIterType = (PyTypeObject *)tmp; + + tmp = PyType_FromModuleAndSpec(module, &multidict_keys_iter_spec, NULL); + if (tmp == NULL) { + return -1; + } + state->KeysIterType = (PyTypeObject *)tmp; + return 0; } diff --git a/contrib/python/multidict/multidict/_multilib/pair_list.h b/contrib/python/multidict/multidict/_multilib/pair_list.h index b23150dfad73..6c45673b73f3 100644 --- a/contrib/python/multidict/multidict/_multilib/pair_list.h +++ b/contrib/python/multidict/multidict/_multilib/pair_list.h @@ -1,3 +1,5 @@ +#include "pythoncapi_compat.h" + #ifndef _MULTIDICT_PAIR_LIST_H #define _MULTIDICT_PAIR_LIST_H @@ -10,6 +12,21 @@ extern "C" { #include #include +#include "istr.h" +#include "state.h" + +/* Implementation note. +identity always has exact PyUnicode_Type type, not a subclass. +It guarantees that identity hashing and comparison never calls +Python code back, and these operations has no weird side effects, +e.g. deletion the key from multidict. + +Taking into account the fact that all multidict operations except +repr(md), repr(md_proxy), or repr(view) never access to the key +itself but identity instead, borrowed references during iteration +over pair_list for, e.g., md.get() or md.pop() is safe. +*/ + typedef struct pair { PyObject *identity; // 8 PyObject *key; // 8 @@ -18,10 +35,7 @@ typedef struct pair { } pair_t; /* Note about the structure size -With 29 pairs the MultiDict object size is slightly less than 1KiB -(1000-1008 bytes depending on Python version, -plus extra 12 bytes for memory allocator internal structures). -As the result the max reserved size is 1020 bytes at most. +With 28 pairs the MultiDict object size is slightly less than 1KiB To fit into 512 bytes, the structure can contain only 13 pairs which is too small, e.g. https://www.python.org returns 16 headers @@ -31,9 +45,10 @@ The embedded buffer intention is to fit the vast majority of possible HTTP headers into the buffer without allocating an extra memory block. */ -#define EMBEDDED_CAPACITY 29 +#define EMBEDDED_CAPACITY 28 typedef struct pair_list { + mod_state *state; Py_ssize_t capacity; Py_ssize_t size; uint64_t version; @@ -42,8 +57,8 @@ typedef struct pair_list { pair_t buffer[EMBEDDED_CAPACITY]; } pair_list_t; -#define MIN_CAPACITY 63 -#define CAPACITY_STEP 64 +#define MIN_CAPACITY 64 +#define CAPACITY_STEP MIN_CAPACITY /* Global counter used to set ma_version_tag field of dictionary. * It is incremented each time that a dictionary is created and each @@ -53,11 +68,17 @@ static uint64_t pair_list_global_version = 0; #define NEXT_VERSION() (++pair_list_global_version) +typedef struct pair_list_pos { + Py_ssize_t pos; + uint64_t version; +} pair_list_pos_t; + + static inline int str_cmp(PyObject *s1, PyObject *s2) { PyObject *ret = PyUnicode_RichCompare(s1, s2, Py_EQ); - if (ret == Py_True) { + if (Py_IsTrue(ret)) { Py_DECREF(ret); return 1; } @@ -72,21 +93,16 @@ str_cmp(PyObject *s1, PyObject *s2) static inline PyObject * -key_to_str(PyObject *key) +_key_to_ident(mod_state *state, PyObject *key) { - PyObject *ret; - PyTypeObject *type = Py_TYPE(key); - if (type == &istr_type) { - ret = ((istrobject*)key)->canonical; - Py_INCREF(ret); - return ret; + if (IStr_Check(state, key)) { + return Py_NewRef(((istrobject*)key)->canonical); } if (PyUnicode_CheckExact(key)) { - Py_INCREF(key); - return key; + return Py_NewRef(key); } if (PyUnicode_Check(key)) { - return PyObject_Str(key); + return PyUnicode_FromObject(key); } PyErr_SetString(PyExc_TypeError, "MultiDict keys should be either str " @@ -96,17 +112,22 @@ key_to_str(PyObject *key) static inline PyObject * -ci_key_to_str(PyObject *key) +_ci_key_to_ident(mod_state *state, PyObject *key) { - PyObject *ret; - PyTypeObject *type = Py_TYPE(key); - if (type == &istr_type) { - ret = ((istrobject*)key)->canonical; - Py_INCREF(ret); - return ret; + if (IStr_Check(state, key)) { + return Py_NewRef(((istrobject*)key)->canonical); } if (PyUnicode_Check(key)) { - return PyObject_CallMethodNoArgs(key, multidict_str_lower); + PyObject *ret = PyObject_CallMethodNoArgs(key, state->str_lower); + if (!PyUnicode_CheckExact(ret)) { + PyObject *tmp = PyUnicode_FromObject(ret); + Py_CLEAR(ret); + if (tmp == NULL) { + return NULL; + } + ret = tmp; + } + return ret; } PyErr_SetString(PyExc_TypeError, "CIMultiDict keys should be either str " @@ -114,35 +135,58 @@ ci_key_to_str(PyObject *key) return NULL; } -static inline pair_t * -pair_list_get(pair_list_t *list, Py_ssize_t i) + +static inline PyObject * +_arg_to_key(mod_state *state, PyObject *key, PyObject *ident) { - pair_t *item = list->pairs + i; - return item; + if (PyUnicode_Check(key)) { + return Py_NewRef(key); + } + PyErr_SetString(PyExc_TypeError, + "MultiDict keys should be either str " + "or subclasses of str"); + return NULL; +} + + +static inline PyObject * +_ci_arg_to_key(mod_state *state, PyObject *key, PyObject *ident) +{ + if (IStr_Check(state, key)) { + return Py_NewRef(key); + } + if (PyUnicode_Check(key)) { + return IStr_New(state, key, ident); + } + PyErr_SetString(PyExc_TypeError, + "CIMultiDict keys should be either str " + "or subclasses of str"); + return NULL; } static inline int -pair_list_grow(pair_list_t *list) +pair_list_grow(pair_list_t *list, Py_ssize_t amount) { // Grow by one element if needed - Py_ssize_t new_capacity; + Py_ssize_t capacity = ((Py_ssize_t)((list->size + amount) + / CAPACITY_STEP) + 1) * CAPACITY_STEP; + pair_t *new_pairs; - if (list->size < list->capacity) { + if (list->size + amount -1 < list->capacity) { return 0; } if (list->pairs == list->buffer) { - new_pairs = PyMem_New(pair_t, MIN_CAPACITY); + new_pairs = PyMem_New(pair_t, (size_t)capacity); memcpy(new_pairs, list->buffer, (size_t)list->capacity * sizeof(pair_t)); list->pairs = new_pairs; - list->capacity = MIN_CAPACITY; + list->capacity = capacity; return 0; } else { - new_capacity = list->capacity + CAPACITY_STEP; - new_pairs = PyMem_Resize(list->pairs, pair_t, (size_t)new_capacity); + new_pairs = PyMem_Resize(list->pairs, pair_t, (size_t)capacity); if (NULL == new_pairs) { // Resizing error @@ -150,7 +194,7 @@ pair_list_grow(pair_list_t *list) } list->pairs = new_pairs; - list->capacity = new_capacity; + list->capacity = capacity; return 0; } } @@ -194,27 +238,35 @@ pair_list_shrink(pair_list_t *list) static inline int -_pair_list_init(pair_list_t *list, bool calc_ci_identity) +_pair_list_init(pair_list_t *list, mod_state *state, + bool calc_ci_identity, Py_ssize_t preallocate) { + list->state = state; list->calc_ci_indentity = calc_ci_identity; - list->pairs = list->buffer; - list->capacity = EMBEDDED_CAPACITY; + Py_ssize_t capacity = EMBEDDED_CAPACITY; + if (preallocate >= capacity) { + capacity = ((Py_ssize_t)(preallocate / CAPACITY_STEP) + 1) * CAPACITY_STEP; + list->pairs = PyMem_New(pair_t, (size_t)capacity); + } else { + list->pairs = list->buffer; + } + list->capacity = capacity; list->size = 0; list->version = NEXT_VERSION(); return 0; } static inline int -pair_list_init(pair_list_t *list) +pair_list_init(pair_list_t *list, mod_state *state, Py_ssize_t size) { - return _pair_list_init(list, /* calc_ci_identity = */ false); + return _pair_list_init(list, state, /* calc_ci_identity = */ false, size); } static inline int -ci_pair_list_init(pair_list_t *list) +ci_pair_list_init(pair_list_t *list, mod_state *state, Py_ssize_t size) { - return _pair_list_init(list, /* calc_ci_identity = */ true); + return _pair_list_init(list, state, /* calc_ci_identity = */ true, size); } @@ -222,22 +274,29 @@ static inline PyObject * pair_list_calc_identity(pair_list_t *list, PyObject *key) { if (list->calc_ci_indentity) - return ci_key_to_str(key); - return key_to_str(key); + return _ci_key_to_ident(list->state, key); + return _key_to_ident(list->state, key); +} + +static inline PyObject * +pair_list_calc_key(pair_list_t *list, PyObject *key, PyObject *ident) +{ + if (list->calc_ci_indentity) + return _ci_arg_to_key(list->state, key, ident); + return _arg_to_key(list->state, key, ident); } static inline void pair_list_dealloc(pair_list_t *list) { - pair_t *pair; Py_ssize_t pos; for (pos = 0; pos < list->size; pos++) { - pair = pair_list_get(list, pos); + pair_t *pair = list->pairs + pos; - Py_XDECREF(pair->identity); - Py_XDECREF(pair->key); - Py_XDECREF(pair->value); + Py_CLEAR(pair->identity); + Py_CLEAR(pair->key); + Py_CLEAR(pair->value); } /* @@ -251,7 +310,7 @@ pair_list_dealloc(pair_list_t *list) */ list->size = 0; if (list->pairs != list->buffer) { - PyMem_Del(list->pairs); + PyMem_Free(list->pairs); list->pairs = list->buffer; list->capacity = EMBEDDED_CAPACITY; } @@ -266,29 +325,21 @@ pair_list_len(pair_list_t *list) static inline int -_pair_list_add_with_hash(pair_list_t *list, - PyObject *identity, - PyObject *key, - PyObject *value, - Py_hash_t hash) +_pair_list_add_with_hash_steal_refs(pair_list_t *list, + PyObject *identity, + PyObject *key, + PyObject *value, + Py_hash_t hash) { - pair_t *pair; - - if (pair_list_grow(list) < 0) { + if (pair_list_grow(list, 1) < 0) { return -1; } - pair = pair_list_get(list, list->size); + pair_t *pair = list->pairs + list->size; - Py_INCREF(identity); pair->identity = identity; - - Py_INCREF(key); pair->key = key; - - Py_INCREF(value); pair->value = value; - pair->hash = hash; list->version = NEXT_VERSION(); @@ -297,25 +348,32 @@ _pair_list_add_with_hash(pair_list_t *list, return 0; } - static inline int -pair_list_add(pair_list_t *list, - PyObject *key, - PyObject *value) +_pair_list_add_with_hash(pair_list_t *list, + PyObject *identity, + PyObject *key, + PyObject *value, + Py_hash_t hash) { - Py_hash_t hash; - PyObject *identity = NULL; - int ret; + Py_INCREF(identity); + Py_INCREF(key); + Py_INCREF(value); + return _pair_list_add_with_hash_steal_refs(list, identity, key, value, hash); +} + - identity = pair_list_calc_identity(list, key); +static inline int +pair_list_add(pair_list_t *list, PyObject *key, PyObject *value) +{ + PyObject *identity = pair_list_calc_identity(list, key); if (identity == NULL) { goto fail; } - hash = PyObject_Hash(identity); + Py_hash_t hash = PyObject_Hash(identity); if (hash == -1) { goto fail; } - ret = _pair_list_add_with_hash(list, identity, key, value, hash); + int ret = _pair_list_add_with_hash(list, identity, key, value, hash); Py_DECREF(identity); return ret; fail: @@ -328,10 +386,7 @@ static inline int pair_list_del_at(pair_list_t *list, Py_ssize_t pos) { // return 1 on success, -1 on failure - Py_ssize_t tail; - pair_t *pair; - - pair = pair_list_get(list, pos); + pair_t *pair = list->pairs + pos; Py_DECREF(pair->identity); Py_DECREF(pair->key); Py_DECREF(pair->value); @@ -344,10 +399,10 @@ pair_list_del_at(pair_list_t *list, Py_ssize_t pos) return 0; } - tail = list->size - pos; + Py_ssize_t tail = list->size - pos; // TODO: raise an error if tail < 0 - memmove((void *)pair_list_get(list, pos), - (void *)pair_list_get(list, pos + 1), + memmove((void *)(list->pairs + pos), + (void *)(list->pairs + pos + 1), sizeof(pair_t) * (size_t)tail); return pair_list_shrink(list); @@ -359,8 +414,6 @@ _pair_list_drop_tail(pair_list_t *list, PyObject *identity, Py_hash_t hash, Py_ssize_t pos) { // return 1 if deleted, 0 if not found - pair_t *pair; - int ret; int found = 0; if (pos >= list->size) { @@ -368,11 +421,11 @@ _pair_list_drop_tail(pair_list_t *list, PyObject *identity, Py_hash_t hash, } for (; pos < list->size; pos++) { - pair = pair_list_get(list, pos); + pair_t *pair = list->pairs + pos; if (pair->hash != hash) { continue; } - ret = str_cmp(pair->identity, identity); + int ret = str_cmp(pair->identity, identity); if (ret > 0) { if (pair_list_del_at(list, pos) < 0) { return -1; @@ -388,46 +441,34 @@ _pair_list_drop_tail(pair_list_t *list, PyObject *identity, Py_hash_t hash, return found; } -static inline int -_pair_list_del_hash(pair_list_t *list, PyObject *identity, - PyObject *key, Py_hash_t hash) -{ - int ret = _pair_list_drop_tail(list, identity, hash, 0); - - if (ret < 0) { - return -1; - } - else if (ret == 0) { - PyErr_SetObject(PyExc_KeyError, key); - return -1; - } - else { - list->version = NEXT_VERSION(); - return 0; - } -} - static inline int pair_list_del(pair_list_t *list, PyObject *key) { - PyObject *identity = NULL; - Py_hash_t hash; - int ret; - - identity = pair_list_calc_identity(list, key); + PyObject *identity = pair_list_calc_identity(list, key); if (identity == NULL) { goto fail; } - hash = PyObject_Hash(identity); + Py_hash_t hash = PyObject_Hash(identity); if (hash == -1) { goto fail; } - ret = _pair_list_del_hash(list, identity, key, hash); + int ret = _pair_list_drop_tail(list, identity, hash, 0); + + if (ret < 0) { + goto fail; + } + else if (ret == 0) { + PyErr_SetObject(PyExc_KeyError, key); + goto fail; + } + else { + list->version = NEXT_VERSION(); + } Py_DECREF(identity); - return ret; + return 0; fail: Py_XDECREF(identity); return -1; @@ -441,75 +482,173 @@ pair_list_version(pair_list_t *list) } -static inline int -_pair_list_next(pair_list_t *list, Py_ssize_t *ppos, PyObject **pidentity, - PyObject **pkey, PyObject **pvalue, Py_hash_t *phash) +static inline void +pair_list_init_pos(pair_list_t *list, pair_list_pos_t *pos) { - pair_t *pair; + pos->pos = 0; + pos->version = list->version; +} - if (*ppos >= list->size) { +static inline int +pair_list_next(pair_list_t *list, pair_list_pos_t *pos, + PyObject **pidentity, + PyObject **pkey, PyObject **pvalue) +{ + if (pos->pos >= list->size) { + if (pidentity) { + *pidentity = NULL; + } + if (pkey) { + *pkey = NULL; + } + if (pvalue) { + *pvalue = NULL; + } return 0; } - pair = pair_list_get(list, *ppos); + if (pos->version != list->version) { + if (pidentity) { + *pidentity = NULL; + } + if (pkey) { + *pkey = NULL; + } + if (pvalue) { + *pvalue = NULL; + } + PyErr_SetString(PyExc_RuntimeError, "MultiDict changed during iteration"); + return -1; + } + + + pair_t *pair = list->pairs + pos->pos; if (pidentity) { - *pidentity = pair->identity; + *pidentity = Py_NewRef(pair->identity);; } + if (pkey) { - *pkey = pair->key; + PyObject *key = pair_list_calc_key(list, pair->key, pair->identity); + if (key == NULL) { + return -1; + } + if (key != pair->key) { + Py_SETREF(pair->key, key); + } else { + Py_CLEAR(key); + } + *pkey = Py_NewRef(pair->key); } if (pvalue) { - *pvalue = pair->value; - } - if (phash) { - *phash = pair->hash; + *pvalue = Py_NewRef(pair->value); } - *ppos += 1; + ++pos->pos; return 1; } static inline int -pair_list_next(pair_list_t *list, Py_ssize_t *ppos, PyObject **pidentity, - PyObject **pkey, PyObject **pvalue) +pair_list_next_by_identity(pair_list_t *list, pair_list_pos_t *pos, + PyObject *identity, + PyObject **pkey, PyObject **pvalue) { - Py_hash_t hash; - return _pair_list_next(list, ppos, pidentity, pkey, pvalue, &hash); + if (pos->pos >= list->size) { + if (pkey) { + *pkey = NULL; + } + if (pvalue) { + *pvalue = NULL; + } + return 0; + } + + if (pos->version != list->version) { + if (pkey) { + *pkey = NULL; + } + if (pvalue) { + *pvalue = NULL; + } + PyErr_SetString(PyExc_RuntimeError, "MultiDict changed during iteration"); + return -1; + } + + + for (; pos->pos < list->size; ++pos->pos) { + pair_t *pair = list->pairs + pos->pos; + PyObject *ret = PyUnicode_RichCompare(identity, pair->identity, Py_EQ); + if (Py_IsFalse(ret)) { + Py_DECREF(ret); + continue; + } else if (ret == NULL) { + return -1; + } else { + // equals + Py_DECREF(ret); + } + + if (pkey) { + PyObject *key = pair_list_calc_key(list, pair->key, pair->identity); + if (key == NULL) { + return -1; + } + if (key != pair->key) { + Py_SETREF(pair->key, key); + } else { + Py_CLEAR(key); + } + *pkey = Py_NewRef(pair->key); + } + if (pvalue) { + *pvalue = Py_NewRef(pair->value); + } + ++pos->pos; + return 1; + } + if (pkey) { + *pkey = NULL; + } + if (pvalue) { + *pvalue = NULL; + } + return 0; } static inline int -pair_list_contains(pair_list_t *list, PyObject *key) +pair_list_contains(pair_list_t *list, PyObject *key, PyObject **pret) { - Py_hash_t hash1, hash2; - Py_ssize_t pos = 0; - PyObject *ident = NULL; - PyObject *identity = NULL; - int tmp; + Py_ssize_t pos; if (!PyUnicode_Check(key)) { return 0; } - ident = pair_list_calc_identity(list, key); + PyObject *ident = pair_list_calc_identity(list, key); if (ident == NULL) { goto fail; } - hash1 = PyObject_Hash(ident); - if (hash1 == -1) { + Py_hash_t hash = PyObject_Hash(ident); + if (hash == -1) { goto fail; } - while (_pair_list_next(list, &pos, &identity, NULL, NULL, &hash2)) { - if (hash1 != hash2) { + Py_ssize_t size = pair_list_len(list); + + for(pos = 0; pos < size; ++pos) { + pair_t * pair = list->pairs + pos; + if (hash != pair->hash) { continue; } - tmp = str_cmp(ident, identity); + int tmp = str_cmp(ident, pair->identity); if (tmp > 0) { Py_DECREF(ident); + if (pret != NULL) { + *pret = Py_NewRef(pair->key); + } return 1; } else if (tmp < 0) { @@ -518,42 +657,46 @@ pair_list_contains(pair_list_t *list, PyObject *key) } Py_DECREF(ident); + if (pret != NULL) { + *pret = NULL; + } return 0; fail: Py_XDECREF(ident); + if (pret != NULL) { + *pret = NULL; + } return -1; } -static inline PyObject * -pair_list_get_one(pair_list_t *list, PyObject *key) +static inline int +pair_list_get_one(pair_list_t *list, PyObject *key, PyObject **ret) { - Py_hash_t hash1, hash2; - Py_ssize_t pos = 0; - PyObject *ident = NULL; - PyObject *identity = NULL; - PyObject *value = NULL; - int tmp; + Py_ssize_t pos; - ident = pair_list_calc_identity(list, key); + PyObject *ident = pair_list_calc_identity(list, key); if (ident == NULL) { goto fail; } - hash1 = PyObject_Hash(ident); - if (hash1 == -1) { + Py_hash_t hash = PyObject_Hash(ident); + if (hash == -1) { goto fail; } - while (_pair_list_next(list, &pos, &identity, NULL, &value, &hash2)) { - if (hash1 != hash2) { + Py_ssize_t size = pair_list_len(list); + + for(pos = 0; pos < size; ++pos) { + pair_t *pair = list->pairs + pos; + if (hash != pair->hash) { continue; } - tmp = str_cmp(ident, identity); + int tmp = str_cmp(ident, pair->identity); if (tmp > 0) { - Py_INCREF(value); Py_DECREF(ident); - return value; + *ret = Py_NewRef(pair->value); + return 0; } else if (tmp < 0) { goto fail; @@ -561,52 +704,48 @@ pair_list_get_one(pair_list_t *list, PyObject *key) } Py_DECREF(ident); - PyErr_SetObject(PyExc_KeyError, key); - return NULL; + return 0; fail: Py_XDECREF(ident); - return NULL; + return -1; } -static inline PyObject * -pair_list_get_all(pair_list_t *list, PyObject *key) +static inline int +pair_list_get_all(pair_list_t *list, PyObject *key, PyObject **ret) { - Py_hash_t hash1, hash2; - Py_ssize_t pos = 0; - PyObject *ident = NULL; - PyObject *identity = NULL; - PyObject *value = NULL; + Py_ssize_t pos; PyObject *res = NULL; - int tmp; - ident = pair_list_calc_identity(list, key); + PyObject *ident = pair_list_calc_identity(list, key); if (ident == NULL) { goto fail; } - hash1 = PyObject_Hash(ident); - if (hash1 == -1) { + Py_hash_t hash = PyObject_Hash(ident); + if (hash == -1) { goto fail; } - while (_pair_list_next(list, &pos, &identity, NULL, &value, &hash2)) { - if (hash1 != hash2) { + Py_ssize_t size = pair_list_len(list); + for(pos = 0; pos < size; ++pos) { + pair_t *pair = list->pairs + pos; + + if (hash != pair->hash) { continue; } - tmp = str_cmp(ident, identity); + int tmp = str_cmp(ident, pair->identity); if (tmp > 0) { if (res == NULL) { res = PyList_New(1); if (res == NULL) { goto fail; } - if (PyList_SetItem(res, 0, value) < 0) { + if (PyList_SetItem(res, 0, Py_NewRef(pair->value)) < 0) { goto fail; } - Py_INCREF(value); } - else if (PyList_Append(res, value) < 0) { + else if (PyList_Append(res, pair->value) < 0) { goto fail; } } @@ -615,160 +754,144 @@ pair_list_get_all(pair_list_t *list, PyObject *key) } } - if (res == NULL) { - PyErr_SetObject(PyExc_KeyError, key); + if (res != NULL) { + *ret = res; } Py_DECREF(ident); - return res; + return 0; fail: Py_XDECREF(ident); Py_XDECREF(res); - return NULL; + return -1; } static inline PyObject * pair_list_set_default(pair_list_t *list, PyObject *key, PyObject *value) { - Py_hash_t hash1, hash2; - Py_ssize_t pos = 0; - PyObject *ident = NULL; - PyObject *identity = NULL; - PyObject *value2 = NULL; - int tmp; + Py_ssize_t pos; - ident = pair_list_calc_identity(list, key); + PyObject *ident = pair_list_calc_identity(list, key); if (ident == NULL) { goto fail; } - hash1 = PyObject_Hash(ident); - if (hash1 == -1) { + Py_hash_t hash = PyObject_Hash(ident); + if (hash == -1) { goto fail; } + Py_ssize_t size = pair_list_len(list); - while (_pair_list_next(list, &pos, &identity, NULL, &value2, &hash2)) { - if (hash1 != hash2) { + for(pos = 0; pos < size; ++pos) { + pair_t * pair = list->pairs + pos; + + if (hash != pair->hash) { continue; } - tmp = str_cmp(ident, identity); + int tmp = str_cmp(ident, pair->identity); if (tmp > 0) { - Py_INCREF(value2); Py_DECREF(ident); - return value2; + return Py_NewRef(pair->value); } else if (tmp < 0) { goto fail; } } - if (_pair_list_add_with_hash(list, ident, key, value, hash1) < 0) { + if (_pair_list_add_with_hash(list, ident, key, value, hash) < 0) { goto fail; } - Py_INCREF(value); Py_DECREF(ident); - return value; + return Py_NewRef(value); fail: Py_XDECREF(ident); return NULL; } -static inline PyObject * -pair_list_pop_one(pair_list_t *list, PyObject *key) +static inline int +pair_list_pop_one(pair_list_t *list, PyObject *key, PyObject **ret) { - pair_t *pair; - - Py_hash_t hash; Py_ssize_t pos; PyObject *value = NULL; - int tmp; - PyObject *ident = NULL; - ident = pair_list_calc_identity(list, key); + PyObject *ident = pair_list_calc_identity(list, key); if (ident == NULL) { goto fail; } - hash = PyObject_Hash(ident); + Py_hash_t hash = PyObject_Hash(ident); if (hash == -1) { goto fail; } for (pos=0; pos < list->size; pos++) { - pair = pair_list_get(list, pos); + pair_t *pair = list->pairs + pos; if (pair->hash != hash) { continue; } - tmp = str_cmp(ident, pair->identity); + int tmp = str_cmp(ident, pair->identity); if (tmp > 0) { - value = pair->value; - Py_INCREF(value); + value = Py_NewRef(pair->value); if (pair_list_del_at(list, pos) < 0) { goto fail; } Py_DECREF(ident); - return value; + *ret = value; + return 0; } else if (tmp < 0) { goto fail; } } - PyErr_SetObject(PyExc_KeyError, key); - goto fail; - + return 0; fail: Py_XDECREF(value); Py_XDECREF(ident); - return NULL; + return -1; } -static inline PyObject * -pair_list_pop_all(pair_list_t *list, PyObject *key) +static inline int +pair_list_pop_all(pair_list_t *list, PyObject *key, PyObject ** ret) { - Py_hash_t hash; Py_ssize_t pos; - pair_t *pair; - int tmp; - PyObject *res = NULL; - PyObject *ident = NULL; + PyObject *lst = NULL; - ident = pair_list_calc_identity(list, key); + PyObject *ident = pair_list_calc_identity(list, key); if (ident == NULL) { goto fail; } - hash = PyObject_Hash(ident); + Py_hash_t hash = PyObject_Hash(ident); if (hash == -1) { goto fail; } if (list->size == 0) { - PyErr_SetObject(PyExc_KeyError, ident); - goto fail; + Py_DECREF(ident); + return 0; } for (pos = list->size - 1; pos >= 0; pos--) { - pair = pair_list_get(list, pos); + pair_t *pair = list->pairs + pos; if (hash != pair->hash) { continue; } - tmp = str_cmp(ident, pair->identity); + int tmp = str_cmp(ident, pair->identity); if (tmp > 0) { - if (res == NULL) { - res = PyList_New(1); - if (res == NULL) { + if (lst == NULL) { + lst = PyList_New(1); + if (lst == NULL) { goto fail; } - if (PyList_SetItem(res, 0, pair->value) < 0) { + if (PyList_SetItem(lst, 0, Py_NewRef(pair->value)) < 0) { goto fail; } - Py_INCREF(pair->value); - } else if (PyList_Append(res, pair->value) < 0) { + } else if (PyList_Append(lst, pair->value) < 0) { goto fail; } if (pair_list_del_at(list, pos) < 0) { @@ -780,39 +903,42 @@ pair_list_pop_all(pair_list_t *list, PyObject *key) } } - if (res == NULL) { - PyErr_SetObject(PyExc_KeyError, key); - } else if (PyList_Reverse(res) < 0) { - goto fail; + if (lst != NULL) { + if (PyList_Reverse(lst) < 0) { + goto fail; + } } + *ret = lst; Py_DECREF(ident); - return res; - + return 0; fail: Py_XDECREF(ident); - Py_XDECREF(res); - return NULL; + Py_XDECREF(lst); + return -1; } static inline PyObject * pair_list_pop_item(pair_list_t *list) { - PyObject *ret; - pair_t *pair; - if (list->size == 0) { PyErr_SetString(PyExc_KeyError, "empty multidict"); return NULL; } - pair = pair_list_get(list, 0); - ret = PyTuple_Pack(2, pair->key, pair->value); + Py_ssize_t pos = list->size - 1; + pair_t *pair = list->pairs + pos; + PyObject *key = pair_list_calc_key(list, pair->key, pair->identity); + if (key == NULL) { + return NULL; + } + PyObject *ret = PyTuple_Pack(2, key, pair->value); + Py_CLEAR(key); if (ret == NULL) { return NULL; } - if (pair_list_del_at(list, 0) < 0) { + if (pair_list_del_at(list, pos) < 0) { Py_DECREF(ret); return NULL; } @@ -824,40 +950,30 @@ pair_list_pop_item(pair_list_t *list) static inline int pair_list_replace(pair_list_t *list, PyObject * key, PyObject *value) { - pair_t *pair; - Py_ssize_t pos; - int tmp; int found = 0; - PyObject *identity = NULL; - Py_hash_t hash; - - identity = pair_list_calc_identity(list, key); + PyObject *identity = pair_list_calc_identity(list, key); if (identity == NULL) { goto fail; } - hash = PyObject_Hash(identity); + Py_hash_t hash = PyObject_Hash(identity); if (hash == -1) { goto fail; } for (pos = 0; pos < list->size; pos++) { - pair = pair_list_get(list, pos); + pair_t *pair = list->pairs + pos; if (hash != pair->hash) { continue; } - tmp = str_cmp(identity, pair->identity); + int tmp = str_cmp(identity, pair->identity); if (tmp > 0) { found = 1; - Py_INCREF(key); - Py_DECREF(pair->key); - pair->key = key; - Py_INCREF(value); - Py_DECREF(pair->value); - pair->value = value; + Py_SETREF(pair->key, Py_NewRef(key)); + Py_SETREF(pair->value, Py_NewRef(value)); break; } else if (tmp < 0) { @@ -899,20 +1015,20 @@ _dict_set_number(PyObject *dict, PyObject *key, Py_ssize_t num) return -1; } + Py_DECREF(tmp); return 0; } static inline int -_pair_list_post_update(pair_list_t *list, PyObject* used_keys, Py_ssize_t pos) +pair_list_post_update(pair_list_t *list, PyObject* used) { - pair_t *pair; - PyObject *tmp; - Py_ssize_t num; + PyObject *tmp = NULL; + Py_ssize_t pos; - for (; pos < list->size; pos++) { - pair = pair_list_get(list, pos); - int status = PyDict_GetItemRef(used_keys, pair->identity, &tmp); + for (pos = 0; pos < list->size; pos++) { + pair_t *pair = list->pairs + pos; + int status = PyDict_GetItemRef(used, pair->identity, &tmp); if (status == -1) { // exception set return -1; @@ -922,7 +1038,7 @@ _pair_list_post_update(pair_list_t *list, PyObject* used_keys, Py_ssize_t pos) continue; } - num = PyLong_AsSsize_t(tmp); + Py_ssize_t num = PyLong_AsSsize_t(tmp); Py_DECREF(tmp); if (num == -1) { if (!PyErr_Occurred()) { @@ -947,16 +1063,14 @@ _pair_list_post_update(pair_list_t *list, PyObject* used_keys, Py_ssize_t pos) // TODO: need refactoring function name static inline int _pair_list_update(pair_list_t *list, PyObject *key, - PyObject *value, PyObject *used_keys, + PyObject *value, PyObject *used, PyObject *identity, Py_hash_t hash) { PyObject *item = NULL; - pair_t *pair = NULL; Py_ssize_t pos; int found; - int ident_cmp_res; - int status = PyDict_GetItemRef(used_keys, identity, &item); + int status = PyDict_GetItemRef(used, identity, &item); if (status == -1) { // exception set return -1; @@ -978,22 +1092,17 @@ _pair_list_update(pair_list_t *list, PyObject *key, found = 0; for (; pos < list->size; pos++) { - pair = pair_list_get(list, pos); + pair_t *pair = list->pairs + pos; if (pair->hash != hash) { continue; } - ident_cmp_res = str_cmp(pair->identity, identity); + int ident_cmp_res = str_cmp(pair->identity, identity); if (ident_cmp_res > 0) { - Py_INCREF(key); - Py_DECREF(pair->key); - pair->key = key; - - Py_INCREF(value); - Py_DECREF(pair->value); - pair->value = value; + Py_SETREF(pair->key, Py_NewRef(key)); + Py_SETREF(pair->value, Py_NewRef(value)); - if (_dict_set_number(used_keys, pair->identity, pos + 1) < 0) { + if (_dict_set_number(used, pair->identity, pos + 1) < 0) { return -1; } @@ -1009,7 +1118,7 @@ _pair_list_update(pair_list_t *list, PyObject *key, if (_pair_list_add_with_hash(list, identity, key, value, hash) < 0) { return -1; } - if (_dict_set_number(used_keys, identity, list->size) < 0) { + if (_dict_set_number(used, identity, list->size) < 0) { return -1; } } @@ -1019,175 +1128,321 @@ _pair_list_update(pair_list_t *list, PyObject *key, static inline int -pair_list_update(pair_list_t *list, pair_list_t *other) +pair_list_update_from_pair_list(pair_list_t *list, + PyObject* used, pair_list_t *other) { - PyObject *used_keys = NULL; - pair_t *pair = NULL; - Py_ssize_t pos; + Py_hash_t hash; + PyObject *identity = NULL; + PyObject *key = NULL; + bool recalc_identity = list->calc_ci_indentity != other->calc_ci_indentity; - if (other->size == 0) { - return 0; + for (pos = 0; pos < other->size; pos++) { + pair_t *pair = other->pairs + pos; + if (recalc_identity) { + identity = pair_list_calc_identity(list, pair->key); + if (identity == NULL) { + goto fail; + } + hash = PyObject_Hash(identity); + if (hash == -1) { + goto fail; + } + /* materialize key */ + key = pair_list_calc_key(other, pair->key, identity); + if (key == NULL) { + goto fail; + } + } else { + identity = pair->identity; + hash = pair->hash; + key = pair->key; + } + if (used != NULL) { + if (_pair_list_update(list, key, pair->value, used, + identity, hash) < 0) { + goto fail; + } + } else { + if (_pair_list_add_with_hash(list, identity, key, + pair->value, hash) < 0) { + goto fail; + } + } + if (recalc_identity) { + Py_CLEAR(identity); + Py_CLEAR(key); + } } - - used_keys = PyDict_New(); - if (used_keys == NULL) { - return -1; + return 0; +fail: + if (recalc_identity) { + Py_CLEAR(identity); + Py_CLEAR(key); } + return -1; +} - for (pos = 0; pos < other->size; pos++) { - pair = pair_list_get(other, pos); - if (_pair_list_update(list, pair->key, pair->value, used_keys, - pair->identity, pair->hash) < 0) { +static inline int +pair_list_update_from_dict(pair_list_t *list, PyObject* used, PyObject *kwds) +{ + Py_ssize_t pos = 0; + PyObject *identity = NULL; + PyObject *key = NULL; + PyObject *value = NULL; + + while(PyDict_Next(kwds, &pos, &key, &value)) { + Py_INCREF(key); + identity = pair_list_calc_identity(list, key); + if (identity == NULL) { goto fail; } + Py_hash_t hash = PyObject_Hash(identity); + if (hash == -1) { + goto fail; + } + if (used != NULL) { + if (_pair_list_update(list, key, value, used, identity, hash) < 0) { + goto fail; + } + } else { + if (_pair_list_add_with_hash(list, identity, key, value, hash) < 0) { + goto fail; + } + } + Py_CLEAR(identity); + Py_CLEAR(key); } + return 0; +fail: + Py_CLEAR(identity); + Py_CLEAR(key); + return -1; +} - if (_pair_list_post_update(list, used_keys, 0) < 0) { - goto fail; - } +static inline void _err_not_sequence(Py_ssize_t i) +{ + PyErr_Format(PyExc_TypeError, + "multidict cannot convert sequence element #%zd" + " to a sequence", + i); +} - Py_DECREF(used_keys); - return 0; +static inline void _err_bad_length(Py_ssize_t i, Py_ssize_t n) +{ + PyErr_Format(PyExc_ValueError, + "multidict update sequence element #%zd " + "has length %zd; 2 is required", + i, n); +} + +static inline void _err_cannot_fetch(Py_ssize_t i, const char * name) +{ + PyErr_Format(PyExc_ValueError, + "multidict update sequence element #%zd's " + "%s could not be fetched", name, i); +} + +static int _pair_list_parse_item(Py_ssize_t i, PyObject *item, + PyObject **pkey, PyObject **pvalue) +{ + Py_ssize_t n; + + if (PyList_CheckExact(item)) { + n = PyList_GET_SIZE(item); + if (n != 2) { + _err_bad_length(i, n); + goto fail; + } + *pkey = Py_NewRef(PyList_GET_ITEM(item, 0)); + *pvalue = Py_NewRef(PyList_GET_ITEM(item, 1)); + } else if (PyTuple_CheckExact(item)) { + n = PyTuple_GET_SIZE(item); + if (n != 2) { + _err_bad_length(i, n); + goto fail; + } + *pkey = Py_NewRef(PyTuple_GET_ITEM(item, 0)); + *pvalue = Py_NewRef(PyTuple_GET_ITEM(item, 1)); + } else { + if (!PySequence_Check(item)) { + _err_not_sequence(i); + goto fail; + } + n = PySequence_Size(item); + if (n != 2) { + _err_bad_length(i, n); + goto fail; + } + *pkey = PySequence_ITEM(item, 0); + *pvalue = PySequence_ITEM(item, 1); + if (*pkey == NULL) { + _err_cannot_fetch(i, "key"); + goto fail; + } + if (*pvalue == NULL) { + _err_cannot_fetch(i, "value"); + goto fail; + } + } + return 0; fail: - Py_XDECREF(used_keys); + Py_CLEAR(*pkey); + Py_CLEAR(*pvalue); return -1; } static inline int -pair_list_update_from_seq(pair_list_t *list, PyObject *seq) +pair_list_update_from_seq(pair_list_t *list, PyObject *used, PyObject *seq) { - PyObject *it = NULL; // iter(seq) - PyObject *fast = NULL; // item as a 2-tuple or 2-list + PyObject *it = NULL; PyObject *item = NULL; // seq[i] - PyObject *used_keys = NULL; // dict() PyObject *key = NULL; PyObject *value = NULL; PyObject *identity = NULL; - Py_hash_t hash; - Py_ssize_t i; - Py_ssize_t n; + Py_ssize_t size = -1; - it = PyObject_GetIter(seq); - if (it == NULL) { - return -1; - } + enum {LIST, TUPLE, ITER} kind; - used_keys = PyDict_New(); - if (used_keys == NULL) { - goto fail_1; + if (PyList_CheckExact(seq)) { + kind = LIST; + size = PyList_GET_SIZE(seq); + } else if (PyTuple_CheckExact(seq)) { + kind = TUPLE; + size = PyTuple_GET_SIZE(seq); + } else { + kind = ITER; + it = PyObject_GetIter(seq); + if (it == NULL) { + goto fail; + } } for (i = 0; ; ++i) { // i - index into seq of current element - fast = NULL; - item = PyIter_Next(it); - if (item == NULL) { - if (PyErr_Occurred()) { - goto fail_1; + switch (kind) { + case LIST: + if (i >= size) { + goto exit; + } + item = PyList_GET_ITEM(seq, i); + if (item == NULL) { + goto fail; } + Py_INCREF(item); break; - } - - // Convert item to sequence, and verify length 2. -#ifdef Py_GIL_DISABLED - if (!PySequence_Check(item)) { -#else - fast = PySequence_Fast(item, ""); - if (fast == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) { -#endif - PyErr_Format(PyExc_TypeError, - "multidict cannot convert sequence element #%zd" - " to a sequence", - i); -#ifndef Py_GIL_DISABLED + case TUPLE: + if (i >= size) { + goto exit; + } + item = PyTuple_GET_ITEM(seq, i); + if (item == NULL) { + goto fail; + } + Py_INCREF(item); + break; + case ITER: + item = PyIter_Next(it); + if (item == NULL) { + if (PyErr_Occurred()) { + goto fail; + } + goto exit; } -#endif - goto fail_1; } -#ifdef Py_GIL_DISABLED - n = PySequence_Size(item); -#else - n = PySequence_Fast_GET_SIZE(fast); -#endif - if (n != 2) { - PyErr_Format(PyExc_ValueError, - "multidict update sequence element #%zd " - "has length %zd; 2 is required", - i, n); - goto fail_1; + if (_pair_list_parse_item(i, item, &key, &value) < 0) { + goto fail; } -#ifdef Py_GIL_DISABLED - key = PySequence_ITEM(item, 0); - if (key == NULL) { - PyErr_Format(PyExc_ValueError, - "multidict update sequence element #%zd's " - "key could not be fetched", i); - goto fail_1; - } - value = PySequence_ITEM(item, 1); - if (value == NULL) { - PyErr_Format(PyExc_ValueError, - "multidict update sequence element #%zd's " - "value could not be fetched", i); - goto fail_1; - } -#else - key = PySequence_Fast_GET_ITEM(fast, 0); - value = PySequence_Fast_GET_ITEM(fast, 1); - Py_INCREF(key); - Py_INCREF(value); -#endif - identity = pair_list_calc_identity(list, key); if (identity == NULL) { - goto fail_1; + goto fail; } - hash = PyObject_Hash(identity); + Py_hash_t hash = PyObject_Hash(identity); if (hash == -1) { - goto fail_1; + goto fail; } - if (_pair_list_update(list, key, value, used_keys, identity, hash) < 0) { - goto fail_1; + if (used) { + if (_pair_list_update(list, key, value, used, identity, hash) < 0) { + goto fail; + } + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + } else { + if (_pair_list_add_with_hash_steal_refs(list, identity, + key, value, hash) < 0) { + goto fail; + } + identity = NULL; + key = NULL; + value = NULL; } + Py_CLEAR(item); + } - Py_DECREF(key); - Py_DECREF(value); -#ifndef Py_GIL_DISABLED - Py_DECREF(fast); -#endif - Py_DECREF(item); - Py_DECREF(identity); +exit: + Py_CLEAR(it); + return 0; + +fail: + Py_CLEAR(identity); + Py_CLEAR(it); + Py_CLEAR(item); + Py_CLEAR(key); + Py_CLEAR(value); + return -1; +} + + +static inline int +pair_list_eq(pair_list_t *list, pair_list_t *other) +{ + Py_ssize_t pos; + + if (list == other) { + return 1; } - if (_pair_list_post_update(list, used_keys, 0) < 0) { - goto fail_2; + Py_ssize_t size = pair_list_len(list); + + if (size != pair_list_len(other)) { + return 0; } - Py_DECREF(it); - Py_DECREF(used_keys); - return 0; + for(pos = 0; pos < size; ++pos) { + pair_t *pair1 = list->pairs + pos; + pair_t *pair2 = other->pairs +pos; -fail_1: - Py_XDECREF(key); - Py_XDECREF(value); - Py_XDECREF(fast); - Py_XDECREF(item); - Py_XDECREF(identity); + if (pair1->hash != pair2->hash) { + return 0; + } -fail_2: - Py_XDECREF(it); - Py_XDECREF(used_keys); - return -1; + int cmp = PyObject_RichCompareBool(pair1->identity, pair2->identity, Py_EQ); + if (cmp < 0) { + return -1; + }; + if (cmp == 0) { + return 0; + } + + cmp = PyObject_RichCompareBool(pair1->value, pair2->value, Py_EQ); + if (cmp < 0) { + return -1; + }; + if (cmp == 0) { + return 0; + } + } + + return 1; } static inline int @@ -1197,9 +1452,7 @@ pair_list_eq_to_mapping(pair_list_t *list, PyObject *other) PyObject *avalue = NULL; PyObject *bvalue; - Py_ssize_t pos, other_len; - - int eq; + Py_ssize_t other_len; if (!PyMapping_Check(other)) { PyErr_Format(PyExc_TypeError, @@ -1216,19 +1469,32 @@ pair_list_eq_to_mapping(pair_list_t *list, PyObject *other) return 0; } - pos = 0; - while (pair_list_next(list, &pos, NULL, &key, &avalue)) { - bvalue = PyObject_GetItem(other, key); - if (bvalue == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); - return 0; - } + pair_list_pos_t pos; + pair_list_init_pos(list, &pos); + + for(;;) { + int ret = pair_list_next(list, &pos, NULL, &key, &avalue); + if (ret < 0) { + return -1; + } + if (ret == 0) { + break; + } + ret = PyMapping_GetOptionalItem(other, key, &bvalue); + Py_CLEAR(key); + if (ret < 0) { + Py_CLEAR(avalue); return -1; } - eq = PyObject_RichCompareBool(avalue, bvalue, Py_EQ); - Py_DECREF(bvalue); + if (bvalue == NULL) { + Py_CLEAR(avalue); + return 0; + } + + int eq = PyObject_RichCompareBool(avalue, bvalue, Py_EQ); + Py_CLEAR(bvalue); + Py_CLEAR(avalue); if (eq <= 0) { return eq; @@ -1239,6 +1505,82 @@ pair_list_eq_to_mapping(pair_list_t *list, PyObject *other) } +static inline PyObject * +pair_list_repr(pair_list_t *list, PyObject *name, + bool show_keys, bool show_values) +{ + PyObject *key = NULL; + PyObject *value = NULL; + + bool comma = false; + Py_ssize_t pos; + uint64_t version = list->version; + + PyUnicodeWriter *writer = PyUnicodeWriter_Create(1024); + if (writer == NULL) + return NULL; + + if (PyUnicodeWriter_WriteChar(writer, '<') <0) + goto fail; + if (PyUnicodeWriter_WriteStr(writer, name) <0) + goto fail; + if (PyUnicodeWriter_WriteChar(writer, '(') <0) + goto fail; + + for (pos = 0; pos < list->size; ++pos) { + if (version != list->version) { + PyErr_SetString(PyExc_RuntimeError, "MultiDict changed during iteration"); + return NULL; + } + pair_t *pair = list->pairs + pos; + key = Py_NewRef(pair->key); + value = Py_NewRef(pair->value); + + if (comma) { + if (PyUnicodeWriter_WriteChar(writer, ',') <0) + goto fail; + if (PyUnicodeWriter_WriteChar(writer, ' ') <0) + goto fail; + } + if (show_keys) { + if (PyUnicodeWriter_WriteChar(writer, '\'') <0) + goto fail; + /* Don't need to convert key to istr, the text is the same*/ + if (PyUnicodeWriter_WriteStr(writer, key) <0) + goto fail; + if (PyUnicodeWriter_WriteChar(writer, '\'') <0) + goto fail; + } + if (show_keys && show_values) { + if (PyUnicodeWriter_WriteChar(writer, ':') <0) + goto fail; + if (PyUnicodeWriter_WriteChar(writer, ' ') <0) + goto fail; + } + if (show_values) { + if (PyUnicodeWriter_WriteRepr(writer, value) <0) + goto fail; + } + + comma = true; + Py_CLEAR(key); + Py_CLEAR(value); + } + + if (PyUnicodeWriter_WriteChar(writer, ')') <0) + goto fail; + if (PyUnicodeWriter_WriteChar(writer, '>') <0) + goto fail; + return PyUnicodeWriter_Finish(writer); +fail: + Py_CLEAR(key); + Py_CLEAR(value); + PyUnicodeWriter_Discard(writer); + return NULL; +} + + + /***********************************************************************/ static inline int @@ -1248,7 +1590,7 @@ pair_list_traverse(pair_list_t *list, visitproc visit, void *arg) Py_ssize_t pos; for (pos = 0; pos < list->size; pos++) { - pair = pair_list_get(list, pos); + pair = list->pairs + pos; // Don't need traverse the identity: it is a terminal Py_VISIT(pair->key); Py_VISIT(pair->value); @@ -1270,14 +1612,14 @@ pair_list_clear(pair_list_t *list) list->version = NEXT_VERSION(); for (pos = 0; pos < list->size; pos++) { - pair = pair_list_get(list, pos); + pair = list->pairs + pos; Py_CLEAR(pair->key); Py_CLEAR(pair->identity); Py_CLEAR(pair->value); } list->size = 0; if (list->pairs != list->buffer) { - PyMem_Del(list->pairs); + PyMem_Free(list->pairs); list->pairs = list->buffer; } diff --git a/contrib/python/multidict/multidict/_multilib/parser.h b/contrib/python/multidict/multidict/_multilib/parser.h new file mode 100644 index 000000000000..074f6fa7d9ef --- /dev/null +++ b/contrib/python/multidict/multidict/_multilib/parser.h @@ -0,0 +1,146 @@ +#ifndef _MULTIDICT_PARSER_H +#define _MULTIDICT_PARSER_H + +#ifdef __cplusplus +extern "C" { +#endif + +static int raise_unexpected_kwarg(const char *fname, PyObject* argname) +{ + PyErr_Format(PyExc_TypeError, + "%.150s() got an unexpected keyword argument '%.150U'", + fname, argname); + return -1; +} + +static int raise_missing_posarg(const char *fname, const char* argname) +{ + PyErr_Format(PyExc_TypeError, + "%.150s() missing 1 required positional argument: '%.150s'", + fname, argname); + return -1; +} + + +/* Parse FASTCALL|METH_KEYWORDS arguments as two args, +the first arg is mandatory and the second one is optional. +If the second arg is not passed it remains NULL pointer. + +The parser accepts three forms: +1. all positional args, +2. fist positional, second keyword-arg +3. all named keyword args. +*/ + +static int parse2(const char* fname, + PyObject*const *args, + Py_ssize_t nargs, + PyObject *kwnames, + Py_ssize_t minargs, + const char* arg1name, + PyObject **arg1, + const char* arg2name, + PyObject **arg2 +) +{ + assert(minargs>=1); + assert(minargs<=2); + + if (kwnames != NULL) { + Py_ssize_t kwsize = PyTuple_Size(kwnames); + if (kwsize < 0) { + return -1; + } + PyObject *argname; // borrowed ref + if (kwsize == 2) { + /* All args are passed by keyword, possible combinations: + arg1, arg2 and arg2, arg1 */ + argname = PyTuple_GetItem(kwnames, 0); + if (argname == NULL) { + return -1; + } + if (PyUnicode_CompareWithASCIIString(argname, arg1name) == 0) { + argname = PyTuple_GetItem(kwnames, 1); + if (argname == NULL) { + return -1; + } + if (PyUnicode_CompareWithASCIIString(argname, arg2name) == 0) { + *arg1 = args[0]; + *arg2 = args[1]; + return 0; + } else { + return raise_unexpected_kwarg(fname, argname); + } + } else if (PyUnicode_CompareWithASCIIString(argname, arg2name) == 0) { + argname = PyTuple_GetItem(kwnames, 1); + if (argname == NULL) { + return -1; + } + if (PyUnicode_CompareWithASCIIString(argname, arg1name) == 0) { + *arg1 = args[1]; + *arg2 = args[0]; + return 0; + } else { + return raise_unexpected_kwarg(fname, argname); + } + } else { + return raise_unexpected_kwarg(fname, argname); + } + } else { + // kwsize == 1 + argname = PyTuple_GetItem(kwnames, 0); + if (argname == NULL) { + return -1; + } + if (nargs == 1) { + if (PyUnicode_CompareWithASCIIString(argname, arg2name) == 0) { + *arg1 = args[0]; + *arg2 = args[1]; + return 0; + } else { + return raise_unexpected_kwarg(fname, argname); + } + } else { + // nargs == 0 + if (PyUnicode_CompareWithASCIIString(argname, arg1name) == 0) { + *arg1 = args[0]; + *arg2 = NULL; + return 0; + } else { + return raise_missing_posarg(fname, arg1name); + } + } + } + } else { + if (nargs < 1) { + PyErr_Format(PyExc_TypeError, + "%.150s() missing 1 required positional argument: '%s'", + fname, arg1name); + return -1; + } + if (nargs < minargs || nargs > 2) { + const char* txt; + if (minargs == 2) { + txt = "from 1 to 2 positional arguments"; + } else { + txt = "exactly 1 positional argument"; + } + PyErr_Format(PyExc_TypeError, + "%.150s() takes %s but %zd were given", + fname, txt, nargs); + return -1; + } + *arg1 = args[0]; + if (nargs == 2) { + *arg2 = args[1]; + } else { + *arg2 = NULL; + } + return 0; + } +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/contrib/python/multidict/multidict/_multilib/pythoncapi_compat.h b/contrib/python/multidict/multidict/_multilib/pythoncapi_compat.h index 971981993ba3..4b179e49319a 100644 --- a/contrib/python/multidict/multidict/_multilib/pythoncapi_compat.h +++ b/contrib/python/multidict/multidict/_multilib/pythoncapi_compat.h @@ -7,10 +7,7 @@ // https://github.com/python/pythoncapi_compat // // Latest version: -// https://raw.githubusercontent.com/python/pythoncapi_compat/master/pythoncapi_compat.h -// -// The vendored version comes from commit: -// https://raw.githubusercontent.com/python/pythoncapi-compat/2d18aecd7b2f549d38a13e27b682ea4966f37bd8/pythoncapi_compat.h +// https://raw.githubusercontent.com/python/pythoncapi-compat/main/pythoncapi_compat.h // // SPDX-License-Identifier: 0BSD @@ -22,11 +19,15 @@ extern "C" { #endif #include +#include // offsetof() // Python 3.11.0b4 added PyFrame_Back() to Python.h #if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION) # include "frameobject.h" // PyFrameObject, PyFrame_GetBack() #endif +#if PY_VERSION_HEX < 0x030C00A3 +# include // T_SHORT, READONLY +#endif #ifndef _Py_CAST @@ -36,11 +37,13 @@ extern "C" { // Static inline functions should use _Py_NULL rather than using directly NULL // to prevent C++ compiler warnings. On C23 and newer and on C++11 and newer, // _Py_NULL is defined as nullptr. -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L) \ - || (defined(__cplusplus) && __cplusplus >= 201103) -# define _Py_NULL nullptr -#else -# define _Py_NULL NULL +#ifndef _Py_NULL +# if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L) \ + || (defined(__cplusplus) && __cplusplus >= 201103) +# define _Py_NULL nullptr +# else +# define _Py_NULL NULL +# endif #endif // Cast argument to PyObject* type. @@ -48,6 +51,13 @@ extern "C" { # define _PyObject_CAST(op) _Py_CAST(PyObject*, op) #endif +#ifndef Py_BUILD_ASSERT +# define Py_BUILD_ASSERT(cond) \ + do { \ + (void)sizeof(char [1 - 2 * !(cond)]); \ + } while(0) +#endif + // bpo-42262 added Py_NewRef() to Python 3.10.0a3 #if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef) @@ -71,6 +81,37 @@ static inline PyObject* _Py_XNewRef(PyObject *obj) #endif +// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT) +static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) +{ + ob->ob_refcnt = refcnt; +} +#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt) +#endif + + +// Py_SETREF() and Py_XSETREF() were added to Python 3.5.2. +// It is excluded from the limited C API. +#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && !defined(Py_LIMITED_API) +#define Py_SETREF(dst, src) \ + do { \ + PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \ + PyObject *_tmp_dst = (*_tmp_dst_ptr); \ + *_tmp_dst_ptr = _PyObject_CAST(src); \ + Py_DECREF(_tmp_dst); \ + } while (0) + +#define Py_XSETREF(dst, src) \ + do { \ + PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \ + PyObject *_tmp_dst = (*_tmp_dst_ptr); \ + *_tmp_dst_ptr = _PyObject_CAST(src); \ + Py_XDECREF(_tmp_dst); \ + } while (0) +#endif + + // bpo-43753 added Py_Is(), Py_IsNone(), Py_IsTrue() and Py_IsFalse() // to Python 3.10.0b1. #if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_Is) @@ -87,7 +128,28 @@ static inline PyObject* _Py_XNewRef(PyObject *obj) #endif -#if defined(PYPY_VERSION) +// bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE) +static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type) +{ + ob->ob_type = type; +} +#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type) +#endif + + +// bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE) +static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) +{ + ob->ob_size = size; +} +#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size) +#endif + + +// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 || defined(PYPY_VERSION) static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame) { assert(frame != _Py_NULL); @@ -103,6 +165,16 @@ static inline PyCodeObject* _PyFrame_GetCodeBorrow(PyFrameObject *frame) return code; } + +// bpo-40421 added PyFrame_GetBack() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) +static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame) +{ + assert(frame != _Py_NULL); + return _Py_CAST(PyFrameObject*, Py_XNewRef(frame->f_back)); +} +#endif + #if !defined(PYPY_VERSION) static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame) { @@ -117,9 +189,13 @@ static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame) #if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION) static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame) { +#if PY_VERSION_HEX >= 0x030400B1 if (PyFrame_FastToLocalsWithError(frame) < 0) { return NULL; } +#else + PyFrame_FastToLocals(frame); +#endif return Py_NewRef(frame->f_locals); } #endif @@ -172,14 +248,22 @@ static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *name) if (locals == NULL) { return NULL; } +#if PY_VERSION_HEX >= 0x03000000 value = PyDict_GetItemWithError(locals, name); +#else + value = _PyDict_GetItemWithError(locals, name); +#endif Py_DECREF(locals); if (value == NULL) { if (PyErr_Occurred()) { return NULL; } +#if PY_VERSION_HEX >= 0x03000000 PyErr_Format(PyExc_NameError, "variable %R does not exist", name); +#else + PyErr_SetString(PyExc_NameError, "variable does not exist"); +#endif return NULL; } return Py_NewRef(value); @@ -193,7 +277,11 @@ static inline PyObject* PyFrame_GetVarString(PyFrameObject *frame, const char *name) { PyObject *name_obj, *value; +#if PY_VERSION_HEX >= 0x03000000 name_obj = PyUnicode_FromString(name); +#else + name_obj = PyString_FromString(name); +#endif if (name_obj == NULL) { return NULL; } @@ -204,7 +292,8 @@ PyFrame_GetVarString(PyFrameObject *frame, const char *name) #endif -#if defined(PYPY_VERSION) +// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 || (defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030B0000) static inline PyInterpreterState * PyThreadState_GetInterpreter(PyThreadState *tstate) { @@ -213,6 +302,16 @@ PyThreadState_GetInterpreter(PyThreadState *tstate) } #endif + +// bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) +static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate) +{ + assert(tstate != _Py_NULL); + return _Py_CAST(PyFrameObject *, Py_XNewRef(tstate->frame)); +} +#endif + #if !defined(PYPY_VERSION) static inline PyFrameObject* _PyThreadState_GetFrameBorrow(PyThreadState *tstate) @@ -224,7 +323,8 @@ _PyThreadState_GetFrameBorrow(PyThreadState *tstate) #endif -#if defined(PYPY_VERSION) +// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION) static inline PyInterpreterState* PyInterpreterState_Get(void) { PyThreadState *tstate; @@ -242,6 +342,16 @@ static inline PyInterpreterState* PyInterpreterState_Get(void) } #endif + +// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a6 +#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION) +static inline uint64_t PyThreadState_GetID(PyThreadState *tstate) +{ + assert(tstate != _Py_NULL); + return tstate->id; +} +#endif + // bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2 #if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) static inline void PyThreadState_EnterTracing(PyThreadState *tstate) @@ -271,6 +381,27 @@ static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) #endif +// bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1 +// PyObject_CallNoArgs() added to PyPy 3.9.16-v7.3.11 +#if !defined(PyObject_CallNoArgs) && PY_VERSION_HEX < 0x030900A1 +static inline PyObject* PyObject_CallNoArgs(PyObject *func) +{ + return PyObject_CallFunctionObjArgs(func, NULL); +} +#endif + + +// bpo-39245 made PyObject_CallOneArg() public (previously called +// _PyObject_CallOneArg) in Python 3.9.0a4 +// PyObject_CallOneArg() added to PyPy 3.9.16-v7.3.11 +#if !defined(PyObject_CallOneArg) && PY_VERSION_HEX < 0x030900A4 +static inline PyObject* PyObject_CallOneArg(PyObject *func, PyObject *arg) +{ + return PyObject_CallFunctionObjArgs(func, arg, NULL); +} +#endif + + // bpo-1635741 added PyModule_AddObjectRef() to Python 3.10.0a3 #if PY_VERSION_HEX < 0x030A00A3 static inline int @@ -296,10 +427,63 @@ PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value) #endif +// bpo-40024 added PyModule_AddType() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 +static inline int PyModule_AddType(PyObject *module, PyTypeObject *type) +{ + const char *name, *dot; + + if (PyType_Ready(type) < 0) { + return -1; + } + + // inline _PyType_Name() + name = type->tp_name; + assert(name != _Py_NULL); + dot = strrchr(name, '.'); + if (dot != _Py_NULL) { + name = dot + 1; + } + + return PyModule_AddObjectRef(module, name, _PyObject_CAST(type)); +} +#endif + + +// bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6. +// bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2. +#if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION) +static inline int PyObject_GC_IsTracked(PyObject* obj) +{ + return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)); +} +#endif + +// bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6. +// bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final. +#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && !defined(PYPY_VERSION) +static inline int PyObject_GC_IsFinalized(PyObject *obj) +{ + PyGC_Head *gc = _Py_CAST(PyGC_Head*, obj) - 1; + return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(gc)); +} +#endif + + +// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE) +static inline int _Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { + return Py_TYPE(ob) == type; +} +#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST(ob), type) +#endif + + // bpo-46906 added PyFloat_Pack2() and PyFloat_Unpack2() to Python 3.11a7. +// bpo-11734 added _PyFloat_Pack2() and _PyFloat_Unpack2() to Python 3.6.0b1. // Python 3.11a2 moved _PyFloat_Pack2() and _PyFloat_Unpack2() to the internal // C API: Python 3.11a2-3.11a6 versions are not supported. -#if PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION) +#if 0x030600B1 <= PY_VERSION_HEX && PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION) static inline int PyFloat_Pack2(double x, char *p, int le) { return _PyFloat_Pack2(x, (unsigned char*)p, le); } @@ -362,6 +546,16 @@ static inline PyObject* PyCode_GetCellvars(PyCodeObject *code) #endif +// Py_UNUSED() was added to Python 3.4.0b2. +#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED) +# if defined(__GNUC__) || defined(__clang__) +# define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) +# else +# define Py_UNUSED(name) _unused_ ## name +# endif +#endif + + // gh-105922 added PyImport_AddModuleRef() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A0 static inline PyObject* PyImport_AddModuleRef(const char *name) @@ -392,7 +586,96 @@ static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj) return 0; } *pobj = Py_NewRef(obj); - return (*pobj != NULL); + return 1; +} +#endif + + +// bpo-36974 added PY_VECTORCALL_ARGUMENTS_OFFSET to Python 3.8b1 +#ifndef PY_VECTORCALL_ARGUMENTS_OFFSET +# define PY_VECTORCALL_ARGUMENTS_OFFSET (_Py_CAST(size_t, 1) << (8 * sizeof(size_t) - 1)) +#endif + +// bpo-36974 added PyVectorcall_NARGS() to Python 3.8b1 +#if PY_VERSION_HEX < 0x030800B1 +static inline Py_ssize_t PyVectorcall_NARGS(size_t n) +{ + return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET; +} +#endif + + +// gh-105922 added PyObject_Vectorcall() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 +static inline PyObject* +PyObject_Vectorcall(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ +#if PY_VERSION_HEX >= 0x030800B1 && !defined(PYPY_VERSION) + // bpo-36974 added _PyObject_Vectorcall() to Python 3.8.0b1 + return _PyObject_Vectorcall(callable, args, nargsf, kwnames); +#else + PyObject *posargs = NULL, *kwargs = NULL; + PyObject *res; + Py_ssize_t nposargs, nkwargs, i; + + if (nargsf != 0 && args == NULL) { + PyErr_BadInternalCall(); + goto error; + } + if (kwnames != NULL && !PyTuple_Check(kwnames)) { + PyErr_BadInternalCall(); + goto error; + } + + nposargs = (Py_ssize_t)PyVectorcall_NARGS(nargsf); + if (kwnames) { + nkwargs = PyTuple_GET_SIZE(kwnames); + } + else { + nkwargs = 0; + } + + posargs = PyTuple_New(nposargs); + if (posargs == NULL) { + goto error; + } + if (nposargs) { + for (i=0; i < nposargs; i++) { + PyTuple_SET_ITEM(posargs, i, Py_NewRef(*args)); + args++; + } + } + + if (nkwargs) { + kwargs = PyDict_New(); + if (kwargs == NULL) { + goto error; + } + + for (i = 0; i < nkwargs; i++) { + PyObject *key = PyTuple_GET_ITEM(kwnames, i); + PyObject *value = *args; + args++; + if (PyDict_SetItem(kwargs, key, value) < 0) { + goto error; + } + } + } + else { + kwargs = NULL; + } + + res = PyObject_Call(callable, posargs, kwargs); + Py_DECREF(posargs); + Py_XDECREF(kwargs); + return res; + +error: + Py_DECREF(posargs); + Py_XDECREF(kwargs); + return NULL; +#endif } #endif @@ -403,7 +686,23 @@ static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj) static inline int PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result) { + // bpo-32571 added _PyObject_LookupAttr() to Python 3.7.0b1 +#if PY_VERSION_HEX >= 0x030700B1 && !defined(PYPY_VERSION) return _PyObject_LookupAttr(obj, attr_name, result); +#else + *result = PyObject_GetAttr(obj, attr_name); + if (*result != NULL) { + return 1; + } + if (!PyErr_Occurred()) { + return 0; + } + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + return 0; + } + return -1; +#endif } static inline int @@ -411,7 +710,11 @@ PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject ** { PyObject *name_obj; int rc; +#if PY_VERSION_HEX >= 0x03000000 name_obj = PyUnicode_FromString(attr_name); +#else + name_obj = PyString_FromString(attr_name); +#endif if (name_obj == NULL) { *result = NULL; return -1; @@ -445,7 +748,11 @@ PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **resul { PyObject *key_obj; int rc; +#if PY_VERSION_HEX >= 0x03000000 key_obj = PyUnicode_FromString(key); +#else + key_obj = PyString_FromString(key); +#endif if (key_obj == NULL) { *result = NULL; return -1; @@ -508,7 +815,11 @@ PyObject_HasAttrStringWithError(PyObject *obj, const char *attr) static inline int PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result) { +#if PY_VERSION_HEX >= 0x03000000 PyObject *item = PyDict_GetItemWithError(mp, key); +#else + PyObject *item = _PyDict_GetItemWithError(mp, key); +#endif if (item != NULL) { *result = Py_NewRef(item); return 1; // found @@ -525,7 +836,11 @@ static inline int PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result) { int res; +#if PY_VERSION_HEX >= 0x03000000 PyObject *key_obj = PyUnicode_FromString(key); +#else + PyObject *key_obj = PyString_FromString(key); +#endif if (key_obj == NULL) { *result = NULL; return -1; @@ -552,11 +867,16 @@ PyModule_Add(PyObject *mod, const char *name, PyObject *value) // gh-108014 added Py_IsFinalizing() to Python 3.13.0a1 // bpo-1856 added _Py_Finalizing to Python 3.2.1b1. // _Py_IsFinalizing() was added to PyPy 7.3.0. -#if (PY_VERSION_HEX < 0x030D00A1) \ - && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x7030000) +#if (0x030201B1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030D00A1) \ + && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x7030000) static inline int Py_IsFinalizing(void) { +#if PY_VERSION_HEX >= 0x030700A1 + // _Py_IsFinalizing() was added to Python 3.7.0a1. return _Py_IsFinalizing(); +#else + return (_Py_Finalizing != NULL); +#endif } #endif @@ -604,7 +924,7 @@ static inline int PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg) { PyObject **dict = _PyObject_GetDictPtr(obj); - if (*dict == NULL) { + if (dict == NULL || *dict == NULL) { return -1; } Py_VISIT(*dict); @@ -615,15 +935,16 @@ static inline void PyObject_ClearManagedDict(PyObject *obj) { PyObject **dict = _PyObject_GetDictPtr(obj); - if (*dict == NULL) { + if (dict == NULL || *dict == NULL) { return; } Py_CLEAR(*dict); } #endif -// gh-108867 added PyThreadState_GetUnchecked() to Python 3.13.0a1. -#if PY_VERSION_HEX < 0x030D00A1 +// gh-108867 added PyThreadState_GetUnchecked() to Python 3.13.0a1 +// Python 3.5.2 added _PyThreadState_UncheckedGet(). +#if PY_VERSION_HEX >= 0x03050200 && PY_VERSION_HEX < 0x030D00A1 static inline PyThreadState* PyThreadState_GetUnchecked(void) { @@ -645,6 +966,8 @@ PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_ // API cannot report errors so save/restore the exception PyErr_Fetch(&exc_type, &exc_value, &exc_tb); + // Python 3.3.0a1 added PyUnicode_AsUTF8AndSize() +#if PY_VERSION_HEX >= 0x030300A1 if (PyUnicode_IS_ASCII(unicode)) { utf8 = PyUnicode_DATA(unicode); len = PyUnicode_GET_LENGTH(unicode); @@ -664,6 +987,31 @@ PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_ goto done; } res = (memcmp(utf8, str, (size_t)len) == 0); +#else + PyObject *bytes = PyUnicode_AsUTF8String(unicode); + if (bytes == NULL) { + // Memory allocation failure. The API cannot report error, + // so ignore the exception and return 0. + res = 0; + goto done; + } + +#if PY_VERSION_HEX >= 0x03000000 + len = PyBytes_GET_SIZE(bytes); + utf8 = PyBytes_AS_STRING(bytes); +#else + len = PyString_GET_SIZE(bytes); + utf8 = PyString_AS_STRING(bytes); +#endif + if (len != str_len) { + Py_DECREF(bytes); + res = 0; + goto done; + } + + res = (memcmp(utf8, str, (size_t)len) == 0); + Py_DECREF(bytes); +#endif done: PyErr_Restore(exc_type, exc_value, exc_tb); @@ -708,9 +1056,13 @@ PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result) return -1; } + // bpo-16991 added _PyDict_Pop() to Python 3.5.0b2. + // Python 3.6.0b3 changed _PyDict_Pop() first argument type to PyObject*. // Python 3.13.0a1 removed _PyDict_Pop(). -#if defined(PYPY_VERSION) || PY_VERSION_HEX >= 0x030D0000 +#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x030500b2 || PY_VERSION_HEX >= 0x030D0000 value = PyObject_CallMethod(dict, "pop", "O", key); +#elif PY_VERSION_HEX < 0x030600b3 + value = _PyDict_Pop(_Py_CAST(PyDictObject*, dict), key, NULL); #else value = _PyDict_Pop(dict, key, NULL); #endif @@ -751,11 +1103,17 @@ PyDict_PopString(PyObject *dict, const char *key, PyObject **result) #endif +#if PY_VERSION_HEX < 0x030200A4 +// Python 3.2.0a4 added Py_hash_t type +typedef Py_ssize_t Py_hash_t; +#endif + + // gh-111545 added Py_HashPointer() to Python 3.13.0a3 #if PY_VERSION_HEX < 0x030D00A3 static inline Py_hash_t Py_HashPointer(const void *ptr) { -#if !defined(PYPY_VERSION) +#if PY_VERSION_HEX >= 0x030900A4 && !defined(PYPY_VERSION) return _Py_HashPointer(ptr); #else return _Py_HashPointer(_Py_CAST(void*, ptr)); @@ -765,7 +1123,8 @@ static inline Py_hash_t Py_HashPointer(const void *ptr) // Python 3.13a4 added a PyTime API. -#if PY_VERSION_HEX < 0x030D00A4 +// Use the private API added to Python 3.5. +#if PY_VERSION_HEX < 0x030D00A4 && PY_VERSION_HEX >= 0x03050000 typedef _PyTime_t PyTime_t; #define PyTime_MIN _PyTime_MIN #define PyTime_MAX _PyTime_MAX @@ -781,9 +1140,9 @@ static inline int PyTime_Time(PyTime_t *result) static inline int PyTime_PerfCounter(PyTime_t *result) { -#if !defined(PYPY_VERSION) +#if PY_VERSION_HEX >= 0x03070000 && !defined(PYPY_VERSION) return _PyTime_GetPerfCounterWithInfo(result, NULL); -#else +#elif PY_VERSION_HEX >= 0x03070000 // Call time.perf_counter_ns() and convert Python int object to PyTime_t. // Cache time.perf_counter_ns() function for best performance. static PyObject *func = NULL; @@ -814,16 +1173,48 @@ static inline int PyTime_PerfCounter(PyTime_t *result) Py_BUILD_ASSERT(sizeof(value) >= sizeof(PyTime_t)); *result = (PyTime_t)value; return 0; +#else + // Call time.perf_counter() and convert C double to PyTime_t. + // Cache time.perf_counter() function for best performance. + static PyObject *func = NULL; + if (func == NULL) { + PyObject *mod = PyImport_ImportModule("time"); + if (mod == NULL) { + return -1; + } + + func = PyObject_GetAttrString(mod, "perf_counter"); + Py_DECREF(mod); + if (func == NULL) { + return -1; + } + } + + PyObject *res = PyObject_CallNoArgs(func); + if (res == NULL) { + return -1; + } + double d = PyFloat_AsDouble(res); + Py_DECREF(res); + + if (d == -1.0 && PyErr_Occurred()) { + return -1; + } + + // Avoid floor() to avoid having to link to libm + *result = (PyTime_t)(d * 1e9); + return 0; #endif } #endif // gh-111389 added hash constants to Python 3.13.0a5. These constants were -// added first as private macros to Python 3.4.0b1 and PyPy 7.3.9. +// added first as private macros to Python 3.4.0b1 and PyPy 7.3.8. #if (!defined(PyHASH_BITS) \ - && (!defined(PYPY_VERSION) \ - || (defined(PYPY_VERSION) && PYPY_VERSION_NUM >= 0x07090000))) + && ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) \ + || (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 \ + && PYPY_VERSION_NUM >= 0x07030800))) # define PyHASH_BITS _PyHASH_BITS # define PyHASH_MODULUS _PyHASH_MODULUS # define PyHASH_INF _PyHASH_INF @@ -967,7 +1358,7 @@ PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value, # define Py_END_CRITICAL_SECTION2() } #endif -#if PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION) +#if PY_VERSION_HEX < 0x030E0000 && PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION) typedef struct PyUnicodeWriter PyUnicodeWriter; static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer) @@ -1135,6 +1526,678 @@ static inline int PyLong_GetSign(PyObject *obj, int *sign) } #endif +// gh-126061 added PyLong_IsPositive/Negative/Zero() to Python in 3.14.0a2 +#if PY_VERSION_HEX < 0x030E00A2 +static inline int PyLong_IsPositive(PyObject *obj) +{ + if (!PyLong_Check(obj)) { + PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name); + return -1; + } + return _PyLong_Sign(obj) == 1; +} + +static inline int PyLong_IsNegative(PyObject *obj) +{ + if (!PyLong_Check(obj)) { + PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name); + return -1; + } + return _PyLong_Sign(obj) == -1; +} + +static inline int PyLong_IsZero(PyObject *obj) +{ + if (!PyLong_Check(obj)) { + PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name); + return -1; + } + return _PyLong_Sign(obj) == 0; +} +#endif + + +// gh-124502 added PyUnicode_Equal() to Python 3.14.0a0 +#if PY_VERSION_HEX < 0x030E00A0 +static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2) +{ + if (!PyUnicode_Check(str1)) { + PyErr_Format(PyExc_TypeError, "first argument must be str, not %s", + Py_TYPE(str1)->tp_name); + return -1; + } + if (!PyUnicode_Check(str2)) { + PyErr_Format(PyExc_TypeError, "second argument must be str, not %s", + Py_TYPE(str2)->tp_name); + return -1; + } + +#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION) + PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2); + + return _PyUnicode_Equal(str1, str2); +#elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION) + return _PyUnicode_EQ(str1, str2); +#elif PY_VERSION_HEX >= 0x03090000 && defined(PYPY_VERSION) + return _PyUnicode_EQ(str1, str2); +#else + return (PyUnicode_Compare(str1, str2) == 0); +#endif +} +#endif + + +// gh-121645 added PyBytes_Join() to Python 3.14.0a0 +#if PY_VERSION_HEX < 0x030E00A0 +static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable) +{ + return _PyBytes_Join(sep, iterable); +} +#endif + + +#if PY_VERSION_HEX < 0x030E00A0 +static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len) +{ +#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) + PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len); + + return _Py_HashBytes(ptr, len); +#else + Py_hash_t hash; + PyObject *bytes = PyBytes_FromStringAndSize((const char*)ptr, len); + if (bytes == NULL) { + return -1; + } + hash = PyObject_Hash(bytes); + Py_DECREF(bytes); + return hash; +#endif +} +#endif + + +#if PY_VERSION_HEX < 0x030E00A0 +static inline int PyIter_NextItem(PyObject *iter, PyObject **item) +{ + iternextfunc tp_iternext; + + assert(iter != NULL); + assert(item != NULL); + + tp_iternext = Py_TYPE(iter)->tp_iternext; + if (tp_iternext == NULL) { + *item = NULL; + PyErr_Format(PyExc_TypeError, "expected an iterator, got '%s'", + Py_TYPE(iter)->tp_name); + return -1; + } + + if ((*item = tp_iternext(iter))) { + return 1; + } + if (!PyErr_Occurred()) { + return 0; + } + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + PyErr_Clear(); + return 0; + } + return -1; +} +#endif + + +#if PY_VERSION_HEX < 0x030E00A0 +static inline PyObject* PyLong_FromInt32(int32_t value) +{ + Py_BUILD_ASSERT(sizeof(long) >= 4); + return PyLong_FromLong(value); +} + +static inline PyObject* PyLong_FromInt64(int64_t value) +{ + Py_BUILD_ASSERT(sizeof(long long) >= 8); + return PyLong_FromLongLong(value); +} + +static inline PyObject* PyLong_FromUInt32(uint32_t value) +{ + Py_BUILD_ASSERT(sizeof(unsigned long) >= 4); + return PyLong_FromUnsignedLong(value); +} + +static inline PyObject* PyLong_FromUInt64(uint64_t value) +{ + Py_BUILD_ASSERT(sizeof(unsigned long long) >= 8); + return PyLong_FromUnsignedLongLong(value); +} + +static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue) +{ + Py_BUILD_ASSERT(sizeof(int) == 4); + int value = PyLong_AsInt(obj); + if (value == -1 && PyErr_Occurred()) { + return -1; + } + *pvalue = (int32_t)value; + return 0; +} + +static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue) +{ + Py_BUILD_ASSERT(sizeof(long long) == 8); + long long value = PyLong_AsLongLong(obj); + if (value == -1 && PyErr_Occurred()) { + return -1; + } + *pvalue = (int64_t)value; + return 0; +} + +static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue) +{ + Py_BUILD_ASSERT(sizeof(long) >= 4); + unsigned long value = PyLong_AsUnsignedLong(obj); + if (value == (unsigned long)-1 && PyErr_Occurred()) { + return -1; + } +#if SIZEOF_LONG > 4 + if ((unsigned long)UINT32_MAX < value) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint32_t"); + return -1; + } +#endif + *pvalue = (uint32_t)value; + return 0; +} + +static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue) +{ + Py_BUILD_ASSERT(sizeof(long long) == 8); + unsigned long long value = PyLong_AsUnsignedLongLong(obj); + if (value == (unsigned long long)-1 && PyErr_Occurred()) { + return -1; + } + *pvalue = (uint64_t)value; + return 0; +} +#endif + + +// gh-102471 added import and export API for integers to 3.14.0a2. +#if PY_VERSION_HEX < 0x030E00A2 && PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) +// Helpers to access PyLongObject internals. +static inline void +_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size) +{ +#if PY_VERSION_HEX >= 0x030C0000 + op->long_value.lv_tag = (uintptr_t)(1 - sign) | ((uintptr_t)(size) << 3); +#elif PY_VERSION_HEX >= 0x030900A4 + Py_SET_SIZE(op, sign * size); +#else + Py_SIZE(op) = sign * size; +#endif +} + +static inline Py_ssize_t +_PyLong_DigitCount(const PyLongObject *op) +{ +#if PY_VERSION_HEX >= 0x030C0000 + return (Py_ssize_t)(op->long_value.lv_tag >> 3); +#else + return _PyLong_Sign((PyObject*)op) < 0 ? -Py_SIZE(op) : Py_SIZE(op); +#endif +} + +static inline digit* +_PyLong_GetDigits(const PyLongObject *op) +{ +#if PY_VERSION_HEX >= 0x030C0000 + return (digit*)(op->long_value.ob_digit); +#else + return (digit*)(op->ob_digit); +#endif +} + +typedef struct PyLongLayout { + uint8_t bits_per_digit; + uint8_t digit_size; + int8_t digits_order; + int8_t digit_endianness; +} PyLongLayout; + +typedef struct PyLongExport { + int64_t value; + uint8_t negative; + Py_ssize_t ndigits; + const void *digits; + Py_uintptr_t _reserved; +} PyLongExport; + +typedef struct PyLongWriter PyLongWriter; + +static inline const PyLongLayout* +PyLong_GetNativeLayout(void) +{ + static const PyLongLayout PyLong_LAYOUT = { + PyLong_SHIFT, + sizeof(digit), + -1, // least significant first + PY_LITTLE_ENDIAN ? -1 : 1, + }; + + return &PyLong_LAYOUT; +} + +static inline int +PyLong_Export(PyObject *obj, PyLongExport *export_long) +{ + if (!PyLong_Check(obj)) { + memset(export_long, 0, sizeof(*export_long)); + PyErr_Format(PyExc_TypeError, "expected int, got %s", + Py_TYPE(obj)->tp_name); + return -1; + } + + // Fast-path: try to convert to a int64_t + PyLongObject *self = (PyLongObject*)obj; + int overflow; +#if SIZEOF_LONG == 8 + long value = PyLong_AsLongAndOverflow(obj, &overflow); +#else + // Windows has 32-bit long, so use 64-bit long long instead + long long value = PyLong_AsLongLongAndOverflow(obj, &overflow); +#endif + Py_BUILD_ASSERT(sizeof(value) == sizeof(int64_t)); + // the function cannot fail since obj is a PyLongObject + assert(!(value == -1 && PyErr_Occurred())); + + if (!overflow) { + export_long->value = value; + export_long->negative = 0; + export_long->ndigits = 0; + export_long->digits = 0; + export_long->_reserved = 0; + } + else { + export_long->value = 0; + export_long->negative = _PyLong_Sign(obj) < 0; + export_long->ndigits = _PyLong_DigitCount(self); + if (export_long->ndigits == 0) { + export_long->ndigits = 1; + } + export_long->digits = _PyLong_GetDigits(self); + export_long->_reserved = (Py_uintptr_t)Py_NewRef(obj); + } + return 0; +} + +static inline void +PyLong_FreeExport(PyLongExport *export_long) +{ + PyObject *obj = (PyObject*)export_long->_reserved; + + if (obj) { + export_long->_reserved = 0; + Py_DECREF(obj); + } +} + +static inline PyLongWriter* +PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits) +{ + if (ndigits <= 0) { + PyErr_SetString(PyExc_ValueError, "ndigits must be positive"); + return NULL; + } + assert(digits != NULL); + + PyLongObject *obj = _PyLong_New(ndigits); + if (obj == NULL) { + return NULL; + } + _PyLong_SetSignAndDigitCount(obj, negative?-1:1, ndigits); + + *digits = _PyLong_GetDigits(obj); + return (PyLongWriter*)obj; +} + +static inline void +PyLongWriter_Discard(PyLongWriter *writer) +{ + PyLongObject *obj = (PyLongObject *)writer; + + assert(Py_REFCNT(obj) == 1); + Py_DECREF(obj); +} + +static inline PyObject* +PyLongWriter_Finish(PyLongWriter *writer) +{ + PyObject *obj = (PyObject *)writer; + PyLongObject *self = (PyLongObject*)obj; + Py_ssize_t j = _PyLong_DigitCount(self); + Py_ssize_t i = j; + int sign = _PyLong_Sign(obj); + + assert(Py_REFCNT(obj) == 1); + + // Normalize and get singleton if possible + while (i > 0 && _PyLong_GetDigits(self)[i-1] == 0) { + --i; + } + if (i != j) { + if (i == 0) { + sign = 0; + } + _PyLong_SetSignAndDigitCount(self, sign, i); + } + if (i <= 1) { + long val = sign * (long)(_PyLong_GetDigits(self)[0]); + Py_DECREF(obj); + return PyLong_FromLong(val); + } + + return obj; +} +#endif + + +#if PY_VERSION_HEX < 0x030C00A3 +# define Py_T_SHORT T_SHORT +# define Py_T_INT T_INT +# define Py_T_LONG T_LONG +# define Py_T_FLOAT T_FLOAT +# define Py_T_DOUBLE T_DOUBLE +# define Py_T_STRING T_STRING +# define _Py_T_OBJECT T_OBJECT +# define Py_T_CHAR T_CHAR +# define Py_T_BYTE T_BYTE +# define Py_T_UBYTE T_UBYTE +# define Py_T_USHORT T_USHORT +# define Py_T_UINT T_UINT +# define Py_T_ULONG T_ULONG +# define Py_T_STRING_INPLACE T_STRING_INPLACE +# define Py_T_BOOL T_BOOL +# define Py_T_OBJECT_EX T_OBJECT_EX +# define Py_T_LONGLONG T_LONGLONG +# define Py_T_ULONGLONG T_ULONGLONG +# define Py_T_PYSSIZET T_PYSSIZET + +# if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) +# define _Py_T_NONE T_NONE +# endif + +# define Py_READONLY READONLY +# define Py_AUDIT_READ READ_RESTRICTED +# define _Py_WRITE_RESTRICTED PY_WRITE_RESTRICTED +#endif + + +// gh-127350 added Py_fopen() and Py_fclose() to Python 3.14a4 +#if PY_VERSION_HEX < 0x030E00A4 +static inline FILE* Py_fopen(PyObject *path, const char *mode) +{ +#if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION) + PyAPI_FUNC(FILE*) _Py_fopen_obj(PyObject *path, const char *mode); + + return _Py_fopen_obj(path, mode); +#else + FILE *f; + PyObject *bytes; +#if PY_VERSION_HEX >= 0x03000000 + if (!PyUnicode_FSConverter(path, &bytes)) { + return NULL; + } +#else + if (!PyString_Check(path)) { + PyErr_SetString(PyExc_TypeError, "except str"); + return NULL; + } + bytes = Py_NewRef(path); +#endif + const char *path_bytes = PyBytes_AS_STRING(bytes); + + f = fopen(path_bytes, mode); + Py_DECREF(bytes); + + if (f == NULL) { + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); + return NULL; + } + return f; +#endif +} + +static inline int Py_fclose(FILE *file) +{ + return fclose(file); +} +#endif + + +#if 0x03090000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION) +static inline PyObject* +PyConfig_Get(const char *name) +{ + typedef enum { + _PyConfig_MEMBER_INT, + _PyConfig_MEMBER_UINT, + _PyConfig_MEMBER_ULONG, + _PyConfig_MEMBER_BOOL, + _PyConfig_MEMBER_WSTR, + _PyConfig_MEMBER_WSTR_OPT, + _PyConfig_MEMBER_WSTR_LIST, + } PyConfigMemberType; + + typedef struct { + const char *name; + size_t offset; + PyConfigMemberType type; + const char *sys_attr; + } PyConfigSpec; + +#define PYTHONCAPI_COMPAT_SPEC(MEMBER, TYPE, sys_attr) \ + {#MEMBER, offsetof(PyConfig, MEMBER), \ + _PyConfig_MEMBER_##TYPE, sys_attr} + + static const PyConfigSpec config_spec[] = { + PYTHONCAPI_COMPAT_SPEC(argv, WSTR_LIST, "argv"), + PYTHONCAPI_COMPAT_SPEC(base_exec_prefix, WSTR_OPT, "base_exec_prefix"), + PYTHONCAPI_COMPAT_SPEC(base_executable, WSTR_OPT, "_base_executable"), + PYTHONCAPI_COMPAT_SPEC(base_prefix, WSTR_OPT, "base_prefix"), + PYTHONCAPI_COMPAT_SPEC(bytes_warning, UINT, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(exec_prefix, WSTR_OPT, "exec_prefix"), + PYTHONCAPI_COMPAT_SPEC(executable, WSTR_OPT, "executable"), + PYTHONCAPI_COMPAT_SPEC(inspect, BOOL, _Py_NULL), +#if 0x030C0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(int_max_str_digits, UINT, _Py_NULL), +#endif + PYTHONCAPI_COMPAT_SPEC(interactive, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(module_search_paths, WSTR_LIST, "path"), + PYTHONCAPI_COMPAT_SPEC(optimization_level, UINT, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(parser_debug, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(platlibdir, WSTR, "platlibdir"), + PYTHONCAPI_COMPAT_SPEC(prefix, WSTR_OPT, "prefix"), + PYTHONCAPI_COMPAT_SPEC(pycache_prefix, WSTR_OPT, "pycache_prefix"), + PYTHONCAPI_COMPAT_SPEC(quiet, BOOL, _Py_NULL), +#if 0x030B0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(stdlib_dir, WSTR_OPT, "_stdlib_dir"), +#endif + PYTHONCAPI_COMPAT_SPEC(use_environment, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(verbose, UINT, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(warnoptions, WSTR_LIST, "warnoptions"), + PYTHONCAPI_COMPAT_SPEC(write_bytecode, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(xoptions, WSTR_LIST, "_xoptions"), + PYTHONCAPI_COMPAT_SPEC(buffered_stdio, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(check_hash_pycs_mode, WSTR, _Py_NULL), +#if 0x030B0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(code_debug_ranges, BOOL, _Py_NULL), +#endif + PYTHONCAPI_COMPAT_SPEC(configure_c_stdio, BOOL, _Py_NULL), +#if 0x030D0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(cpu_count, INT, _Py_NULL), +#endif + PYTHONCAPI_COMPAT_SPEC(dev_mode, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(dump_refs, BOOL, _Py_NULL), +#if 0x030B0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(dump_refs_file, WSTR_OPT, _Py_NULL), +#endif +#ifdef Py_GIL_DISABLED + PYTHONCAPI_COMPAT_SPEC(enable_gil, INT, _Py_NULL), +#endif + PYTHONCAPI_COMPAT_SPEC(faulthandler, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(filesystem_encoding, WSTR, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(filesystem_errors, WSTR, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(hash_seed, ULONG, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(home, WSTR_OPT, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(import_time, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(install_signal_handlers, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(isolated, BOOL, _Py_NULL), +#ifdef MS_WINDOWS + PYTHONCAPI_COMPAT_SPEC(legacy_windows_stdio, BOOL, _Py_NULL), +#endif + PYTHONCAPI_COMPAT_SPEC(malloc_stats, BOOL, _Py_NULL), +#if 0x030A0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(orig_argv, WSTR_LIST, "orig_argv"), +#endif + PYTHONCAPI_COMPAT_SPEC(parse_argv, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(pathconfig_warnings, BOOL, _Py_NULL), +#if 0x030C0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(perf_profiling, UINT, _Py_NULL), +#endif + PYTHONCAPI_COMPAT_SPEC(program_name, WSTR, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(run_command, WSTR_OPT, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(run_filename, WSTR_OPT, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(run_module, WSTR_OPT, _Py_NULL), +#if 0x030B0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(safe_path, BOOL, _Py_NULL), +#endif + PYTHONCAPI_COMPAT_SPEC(show_ref_count, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(site_import, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(skip_source_first_line, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(stdio_encoding, WSTR, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(stdio_errors, WSTR, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(tracemalloc, UINT, _Py_NULL), +#if 0x030B0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(use_frozen_modules, BOOL, _Py_NULL), +#endif + PYTHONCAPI_COMPAT_SPEC(use_hash_seed, BOOL, _Py_NULL), + PYTHONCAPI_COMPAT_SPEC(user_site_directory, BOOL, _Py_NULL), +#if 0x030A0000 <= PY_VERSION_HEX + PYTHONCAPI_COMPAT_SPEC(warn_default_encoding, BOOL, _Py_NULL), +#endif + }; + +#undef PYTHONCAPI_COMPAT_SPEC + + const PyConfigSpec *spec; + int found = 0; + for (size_t i=0; i < sizeof(config_spec) / sizeof(config_spec[0]); i++) { + spec = &config_spec[i]; + if (strcmp(spec->name, name) == 0) { + found = 1; + break; + } + } + if (found) { + if (spec->sys_attr != NULL) { + PyObject *value = PySys_GetObject(spec->sys_attr); + if (value == NULL) { + PyErr_Format(PyExc_RuntimeError, "lost sys.%s", spec->sys_attr); + return NULL; + } + return Py_NewRef(value); + } + + PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); + + const PyConfig *config = _Py_GetConfig(); + void *member = (char *)config + spec->offset; + switch (spec->type) { + case _PyConfig_MEMBER_INT: + case _PyConfig_MEMBER_UINT: + { + int value = *(int *)member; + return PyLong_FromLong(value); + } + case _PyConfig_MEMBER_BOOL: + { + int value = *(int *)member; + return PyBool_FromLong(value != 0); + } + case _PyConfig_MEMBER_ULONG: + { + unsigned long value = *(unsigned long *)member; + return PyLong_FromUnsignedLong(value); + } + case _PyConfig_MEMBER_WSTR: + case _PyConfig_MEMBER_WSTR_OPT: + { + wchar_t *wstr = *(wchar_t **)member; + if (wstr != NULL) { + return PyUnicode_FromWideChar(wstr, -1); + } + else { + return Py_NewRef(Py_None); + } + } + case _PyConfig_MEMBER_WSTR_LIST: + { + const PyWideStringList *list = (const PyWideStringList *)member; + PyObject *tuple = PyTuple_New(list->length); + if (tuple == NULL) { + return NULL; + } + + for (Py_ssize_t i = 0; i < list->length; i++) { + PyObject *item = PyUnicode_FromWideChar(list->items[i], -1); + if (item == NULL) { + Py_DECREF(tuple); + return NULL; + } + PyTuple_SET_ITEM(tuple, i, item); + } + return tuple; + } + default: + Py_UNREACHABLE(); + } + } + + PyErr_Format(PyExc_ValueError, "unknown config option name: %s", name); + return NULL; +} + +static inline int +PyConfig_GetInt(const char *name, int *value) +{ + PyObject *obj = PyConfig_Get(name); + if (obj == NULL) { + return -1; + } + + if (!PyLong_Check(obj)) { + Py_DECREF(obj); + PyErr_Format(PyExc_TypeError, "config option %s is not an int", name); + return -1; + } + + int as_int = PyLong_AsInt(obj); + Py_DECREF(obj); + if (as_int == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_OverflowError, + "config option %s value does not fit into a C int", name); + return -1; + } + + *value = as_int; + return 0; +} +#endif // PY_VERSION_HEX > 0x03090000 && !defined(PYPY_VERSION) + #ifdef __cplusplus } diff --git a/contrib/python/multidict/multidict/_multilib/state.h b/contrib/python/multidict/multidict/_multilib/state.h new file mode 100644 index 000000000000..58110d973a7f --- /dev/null +++ b/contrib/python/multidict/multidict/_multilib/state.h @@ -0,0 +1,132 @@ +#ifndef _MULTIDICT_STATE_H +#define _MULTIDICT_STATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* State of the _multidict module */ +typedef struct { + PyTypeObject *IStrType; + + PyTypeObject *MultiDictType; + PyTypeObject *CIMultiDictType; + PyTypeObject *MultiDictProxyType; + PyTypeObject *CIMultiDictProxyType; + + PyTypeObject *KeysViewType; + PyTypeObject *ItemsViewType; + PyTypeObject *ValuesViewType; + + PyTypeObject *KeysIterType; + PyTypeObject *ItemsIterType; + PyTypeObject *ValuesIterType; + + PyObject *str_lower; + PyObject *str_canonical; +} mod_state; + +static inline mod_state * +get_mod_state(PyObject *mod) +{ + mod_state *state = (mod_state *)PyModule_GetState(mod); + assert(state != NULL); + return state; +} + +static inline mod_state * +get_mod_state_by_cls(PyTypeObject *cls) +{ + mod_state *state = (mod_state *)PyType_GetModuleState(cls); + assert(state != NULL); + return state; +} + + +#if PY_VERSION_HEX < 0x030b0000 +PyObject * +PyType_GetModuleByDef(PyTypeObject *tp, PyModuleDef *def) +{ + PyModuleDef * mod_def; + if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { + goto err; + } + PyObject *mod = NULL; + + mod = PyType_GetModule(tp); + if (mod == NULL) { + PyErr_Clear(); + } else { + mod_def = PyModule_GetDef(mod); + if (mod_def == def) { + return mod; + } + } + + PyObject *mro = tp->tp_mro; + assert(mro != NULL); + assert(PyTuple_Check(mro)); + assert(PyTuple_GET_SIZE(mro) >= 1); + assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)tp); + + Py_ssize_t n = PyTuple_GET_SIZE(mro); + for (Py_ssize_t i = 1; i < n; i++) { + PyObject *super = PyTuple_GET_ITEM(mro, i); + if (!PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) { + continue; + } + mod = PyType_GetModule((PyTypeObject*)super); + if (mod == NULL) { + PyErr_Clear(); + } else { + mod_def = PyModule_GetDef(mod); + if (mod_def == def) { + return mod; + } + } + } + +err: + PyErr_Format( + PyExc_TypeError, + "PyType_GetModuleByDef: No superclass of '%s' has the given module", + tp->tp_name); + return NULL; + +} +#endif + +static PyModuleDef multidict_module; + +static inline int +get_mod_state_by_def_checked(PyObject *self, mod_state **ret) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject *mod = PyType_GetModuleByDef(tp, &multidict_module); + if (mod == NULL) { + *ret = NULL; + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + return 0; + } + return -1; + } + *ret = get_mod_state(mod); + return 1; +} + + +static inline mod_state * +get_mod_state_by_def(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject *mod = PyType_GetModuleByDef(tp, &multidict_module); + assert(mod != NULL); + return get_mod_state(mod); +} + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/contrib/python/multidict/multidict/_multilib/views.h b/contrib/python/multidict/multidict/_multilib/views.h index ec80e07aeb03..3e195f4d5b2a 100644 --- a/contrib/python/multidict/multidict/_multilib/views.h +++ b/contrib/python/multidict/multidict/_multilib/views.h @@ -5,38 +5,25 @@ extern "C" { #endif -static PyTypeObject multidict_itemsview_type; -static PyTypeObject multidict_valuesview_type; -static PyTypeObject multidict_keysview_type; - -static PyObject *viewbaseset_richcmp_func; -static PyObject *viewbaseset_and_func; -static PyObject *viewbaseset_or_func; -static PyObject *viewbaseset_sub_func; -static PyObject *viewbaseset_xor_func; - -static PyObject *abc_itemsview_register_func; -static PyObject *abc_keysview_register_func; -static PyObject *abc_valuesview_register_func; - -static PyObject *itemsview_isdisjoint_func; -static PyObject *itemsview_repr_func; - -static PyObject *keysview_repr_func; -static PyObject *keysview_isdisjoint_func; - -static PyObject *valuesview_repr_func; +#include "dict.h" +#include "pair_list.h" +#include "state.h" typedef struct { PyObject_HEAD - PyObject *md; + MultiDictObject *md; } _Multidict_ViewObject; +#define Items_CheckExact(state, obj) Py_IS_TYPE(obj, state->ItemsViewType) +#define Keys_CheckExact(state, obj) Py_IS_TYPE(obj, state->KeysViewType) +#define Values_CheckExact(state, obj) Py_IS_TYPE(obj, state->ValuesViewType) + + /********** Base **********/ static inline void -_init_view(_Multidict_ViewObject *self, PyObject *md) +_init_view(_Multidict_ViewObject *self, MultiDictObject *md) { Py_INCREF(md); self->md = md; @@ -67,110 +54,822 @@ multidict_view_clear(_Multidict_ViewObject *self) static inline Py_ssize_t multidict_view_len(_Multidict_ViewObject *self) { - return pair_list_len(&((MultiDictObject*)self->md)->pairs); + return pair_list_len(&self->md->pairs); } static inline PyObject * multidict_view_richcompare(PyObject *self, PyObject *other, int op) { - PyObject *ret; - PyObject *op_obj = PyLong_FromLong(op); - if (op_obj == NULL) { + int tmp; + Py_ssize_t self_size = PyObject_Length(self); + if (self_size < 0) { return NULL; } - ret = PyObject_CallFunctionObjArgs( - viewbaseset_richcmp_func, self, other, op_obj, NULL); - Py_DECREF(op_obj); - return ret; + Py_ssize_t size = PyObject_Length(other); + if (size < 0) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + PyObject *iter = NULL; + PyObject *item = NULL; + switch(op) { + case Py_LT: + if (self_size >= size) + Py_RETURN_FALSE; + return PyObject_RichCompare(self, other, Py_LE); + case Py_LE: + if (self_size > size) { + Py_RETURN_FALSE; + } + iter = PyObject_GetIter(self); + if (iter == NULL) { + goto fail; + } + while ((item = PyIter_Next(iter))) { + tmp = PySequence_Contains(other, item); + if (tmp < 0) { + goto fail; + } + Py_CLEAR(item); + if (tmp == 0) { + Py_CLEAR(iter); + Py_RETURN_FALSE; + } + } + Py_CLEAR(iter); + if (PyErr_Occurred()) { + goto fail; + } + Py_RETURN_TRUE; + case Py_EQ: + if (self_size != size) + Py_RETURN_FALSE; + return PyObject_RichCompare(self, other, Py_LE); + case Py_NE: + tmp = PyObject_RichCompareBool(self, other, Py_EQ); + if (tmp < 0) + goto fail; + return PyBool_FromLong(!tmp); + case Py_GT: + if (self_size <= size) + Py_RETURN_FALSE; + return PyObject_RichCompare(self, other, Py_GE); + case Py_GE: + if (self_size < size) { + Py_RETURN_FALSE; + } + iter = PyObject_GetIter(other); + if (iter == NULL) { + goto fail; + } + while ((item = PyIter_Next(iter))) { + tmp = PySequence_Contains(self, item); + if (tmp < 0) { + goto fail; + } + Py_CLEAR(item); + if (tmp == 0) { + Py_CLEAR(iter); + Py_RETURN_FALSE; + } + } + Py_CLEAR(iter); + if (PyErr_Occurred()) { + goto fail; + } + Py_RETURN_TRUE; + } +fail: + Py_CLEAR(item); + Py_CLEAR(iter); + return NULL; } + +/********** Items **********/ + static inline PyObject * -multidict_view_and(PyObject *self, PyObject *other) +multidict_itemsview_new(MultiDictObject *md) { - return PyObject_CallFunctionObjArgs( - viewbaseset_and_func, self, other, NULL); + _Multidict_ViewObject *mv = PyObject_GC_New( + _Multidict_ViewObject, md->pairs.state->ItemsViewType); + if (mv == NULL) { + return NULL; + } + + _init_view(mv, md); + + PyObject_GC_Track(mv); + return (PyObject *)mv; } static inline PyObject * -multidict_view_or(PyObject *self, PyObject *other) +multidict_itemsview_iter(_Multidict_ViewObject *self) { - return PyObject_CallFunctionObjArgs( - viewbaseset_or_func, self, other, NULL); + return multidict_items_iter_new(self->md); } static inline PyObject * -multidict_view_sub(PyObject *self, PyObject *other) +multidict_itemsview_repr(_Multidict_ViewObject *self) +{ + int tmp = Py_ReprEnter((PyObject *)self); + if (tmp < 0) { + return NULL; + } + if (tmp > 0) { + return PyUnicode_FromString("..."); + } + PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__"); + if (name == NULL) { + Py_ReprLeave((PyObject *)self); + return NULL; + } + PyObject *ret = pair_list_repr(&self->md->pairs, name, true, true); + Py_ReprLeave((PyObject *)self); + Py_CLEAR(name); + return ret; +} + +static inline int +_multidict_itemsview_parse_item(_Multidict_ViewObject *self, PyObject *arg, + PyObject **pidentity, PyObject **pkey, + PyObject **pvalue) { - return PyObject_CallFunctionObjArgs( - viewbaseset_sub_func, self, other, NULL); + assert(pidentity != NULL); + if (!PyTuple_Check(arg)) { + return 0; + } + + Py_ssize_t size = PyTuple_Size(arg); + if (size != 2) { + return 0; + } + + PyObject *key = Py_NewRef(PyTuple_GET_ITEM(arg, 0)); + + if (pkey != NULL) { + *pkey = Py_NewRef(key); + } + if (pvalue != NULL) { + *pvalue = Py_NewRef(PyTuple_GET_ITEM(arg, 1)); + } + + *pidentity = pair_list_calc_identity(&self->md->pairs, key); + Py_DECREF(key); + if (*pidentity == NULL) { + if (pkey != NULL) { + Py_CLEAR(*pkey); + } + if (pvalue != NULL) { + Py_CLEAR(*pvalue); + } + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + return 0; + } else { + return -1; + } + } + return 1; +} + +static int +_set_add(PyObject *set, PyObject *key, PyObject * value) +{ + PyObject *tpl = PyTuple_Pack(2, key, value); + if (tpl == NULL) { + return -1; + } + int tmp = PySet_Add(set, tpl); + Py_DECREF(tpl); + return tmp; } static inline PyObject * -multidict_view_xor(PyObject *self, PyObject *other) +multidict_itemsview_and1(_Multidict_ViewObject *self, PyObject *other) { - return PyObject_CallFunctionObjArgs( - viewbaseset_xor_func, self, other, NULL); + PyObject *identity = NULL; + PyObject *key = NULL; + PyObject *key2 = NULL; + PyObject *value = NULL; + PyObject *value2 = NULL; + PyObject *arg = NULL; + PyObject *ret = NULL; + + pair_list_pos_t pos; + + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New(NULL); + if (ret == NULL) { + goto fail; + } + while ((arg = PyIter_Next(iter))) { + int tmp = _multidict_itemsview_parse_item(self, arg, + &identity, &key, &value); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + Py_CLEAR(arg); + continue; + } + + pair_list_init_pos(&self->md->pairs, &pos); + + while (true) { + tmp = pair_list_next_by_identity(&self->md->pairs, &pos, + identity, &key2, &value2); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + break; + } else { + tmp = PyObject_RichCompareBool(value, value2, Py_EQ); + if (tmp < 0) { + goto fail; + } + if (tmp > 0) { + if (_set_add(ret, key2, value2) < 0) { + goto fail; + } + } + } + Py_CLEAR(key2); + Py_CLEAR(value2); + } + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + return ret; +fail: + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(key2); + Py_CLEAR(value); + Py_CLEAR(value2); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; } -static PyNumberMethods multidict_view_as_number = { - .nb_subtract = (binaryfunc)multidict_view_sub, - .nb_and = (binaryfunc)multidict_view_and, - .nb_xor = (binaryfunc)multidict_view_xor, - .nb_or = (binaryfunc)multidict_view_or, -}; +static inline PyObject * +multidict_itemsview_and2(_Multidict_ViewObject *self, PyObject *other) +{ + PyObject *identity = NULL; + PyObject *key = NULL; + PyObject *value = NULL; + PyObject *value2 = NULL; + PyObject *arg = NULL; + PyObject *ret = NULL; -/********** Items **********/ + pair_list_pos_t pos; + + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New(NULL); + if (ret == NULL) { + goto fail; + } + while ((arg = PyIter_Next(iter))) { + int tmp = _multidict_itemsview_parse_item(self, arg, + &identity, &key, &value); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + Py_CLEAR(arg); + continue; + } + + pair_list_init_pos(&self->md->pairs, &pos); + + while (true) { + tmp = pair_list_next_by_identity(&self->md->pairs, &pos, + identity, NULL, &value2); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + break; + } else { + tmp = PyObject_RichCompareBool(value, value2, Py_EQ); + if (tmp < 0) { + goto fail; + } + if (tmp > 0) { + if (_set_add(ret, key, value2) < 0) { + goto fail; + } + } + } + Py_CLEAR(value2); + } + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + return ret; +fail: + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + Py_CLEAR(value2); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; +} static inline PyObject * -multidict_itemsview_new(PyObject *md) +multidict_itemsview_and(PyObject *lft, PyObject *rht) { - _Multidict_ViewObject *mv = PyObject_GC_New( - _Multidict_ViewObject, &multidict_itemsview_type); - if (mv == NULL) { + mod_state * state; + int tmp = get_mod_state_by_def_checked(lft, &state); + if (tmp < 0) { return NULL; + } else if (tmp == 0) { + tmp = get_mod_state_by_def_checked(rht, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + Py_RETURN_NOTIMPLEMENTED; + } + } + assert(state != NULL); + if (Items_CheckExact(state, lft)) { + return multidict_itemsview_and1((_Multidict_ViewObject *)lft, rht); + } else if (Items_CheckExact(state, rht)) { + return multidict_itemsview_and2((_Multidict_ViewObject *)rht, lft); } + Py_RETURN_NOTIMPLEMENTED; +} - _init_view(mv, md); +static inline PyObject * +multidict_itemsview_or1(_Multidict_ViewObject *self, PyObject *other) +{ + PyObject *identity = NULL; + PyObject *key = NULL; + PyObject *value = NULL; + PyObject *value2 = NULL; + PyObject *arg = NULL; + PyObject *ret = NULL; - PyObject_GC_Track(mv); - return (PyObject *)mv; + pair_list_pos_t pos; + + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New((PyObject *)self); + if (ret == NULL) { + goto fail; + } + while ((arg = PyIter_Next(iter))) { + int tmp = _multidict_itemsview_parse_item(self, arg, + &identity, &key, &value); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + if (PySet_Add(ret, arg) < 0) { + goto fail; + } + Py_CLEAR(arg); + continue; + } + + pair_list_init_pos(&self->md->pairs, &pos); + + while (true) { + tmp = pair_list_next_by_identity(&self->md->pairs, &pos, + identity, NULL, &value2); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + if (PySet_Add(ret, arg) < 0) { + goto fail; + } + break; + } else { + tmp = PyObject_RichCompareBool(value, value2, Py_EQ); + if (tmp < 0) { + goto fail; + } + if (tmp > 0) { + Py_CLEAR(value2); + break; + } + } + Py_CLEAR(value2); + } + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + return ret; +fail: + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + Py_CLEAR(value2); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; } static inline PyObject * -multidict_itemsview_iter(_Multidict_ViewObject *self) +multidict_itemsview_or2(_Multidict_ViewObject *self, PyObject *other) { - return multidict_items_iter_new((MultiDictObject*)self->md); + PyObject *identity = NULL; + PyObject *iter = NULL; + PyObject *key = NULL; + PyObject *value = NULL; + PyObject *arg = NULL; + PyObject *tmp_set = NULL; + + pair_list_pos_t pos; + + PyObject *ret = PySet_New(other); + if (ret == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + iter = PyObject_GetIter(other); + if (iter == NULL) { + goto fail; + } + tmp_set = PySet_New(NULL); + if (tmp_set == NULL) { + goto fail; + } + while ((arg = PyIter_Next(iter))) { + int tmp = _multidict_itemsview_parse_item(self, arg, + &identity, NULL, &value); + if (tmp < 0) { + goto fail; + } else if (tmp > 0) { + if (_set_add(tmp_set, identity, value) < 0) { + goto fail; + } + } + Py_CLEAR(arg); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + + pair_list_init_pos(&self->md->pairs, &pos); + + while (true) { + int tmp = pair_list_next(&self->md->pairs, &pos, + &identity, &key, &value); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + break; + } else { + PyObject *tpl = PyTuple_Pack(2, identity, value); + if (tpl == NULL) { + goto fail; + } + tmp = PySet_Contains(tmp_set, tpl); + if (tmp < 0) { + goto fail; + } + if (tmp == 0) { + if (_set_add(ret, key, value) < 0) { + goto fail; + } + } + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + } + } + Py_CLEAR(tmp_set); + return ret; +fail: + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + Py_CLEAR(iter); + Py_CLEAR(ret); + Py_CLEAR(tmp_set); + return NULL; } static inline PyObject * -multidict_itemsview_repr(_Multidict_ViewObject *self) +multidict_itemsview_or(PyObject *lft, PyObject *rht) { - return PyObject_CallFunctionObjArgs( - itemsview_repr_func, self, NULL); + mod_state * state; + int tmp = get_mod_state_by_def_checked(lft, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + tmp = get_mod_state_by_def_checked(rht, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + Py_RETURN_NOTIMPLEMENTED; + } + } + assert(state != NULL); + if (Items_CheckExact(state, lft)) { + return multidict_itemsview_or1((_Multidict_ViewObject *)lft, rht); + } else if (Items_CheckExact(state, rht)) { + return multidict_itemsview_or2((_Multidict_ViewObject *)rht, lft); + } + Py_RETURN_NOTIMPLEMENTED; } + static inline PyObject * -multidict_itemsview_isdisjoint(_Multidict_ViewObject *self, PyObject *other) +multidict_itemsview_sub1(_Multidict_ViewObject *self, PyObject *other) { - return PyObject_CallFunctionObjArgs( - itemsview_isdisjoint_func, self, other, NULL); + PyObject *arg = NULL; + PyObject *identity = NULL; + PyObject *key = NULL; + PyObject *value = NULL; + PyObject *ret = NULL; + PyObject *tmp_set = NULL; + + pair_list_pos_t pos; + + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New(NULL); + if (ret == NULL) { + goto fail; + } + tmp_set = PySet_New(NULL); + if (tmp_set == NULL) { + goto fail; + } + while ((arg = PyIter_Next(iter))) { + int tmp = _multidict_itemsview_parse_item(self, arg, + &identity, NULL, &value); + if (tmp < 0) { + goto fail; + } else if (tmp > 0) { + if (_set_add(tmp_set, identity, value) < 0) { + goto fail; + } + } + Py_CLEAR(arg); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + + pair_list_init_pos(&self->md->pairs, &pos); + + while (true) { + int tmp = pair_list_next(&self->md->pairs, &pos, + &identity, &key, &value); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + break; + } else { + PyObject *tpl = PyTuple_Pack(2, identity, value); + if (tpl == NULL) { + goto fail; + } + tmp = PySet_Contains(tmp_set, tpl); + if (tmp < 0) { + goto fail; + } + if (tmp == 0) { + if (_set_add(ret, key, value) < 0) { + goto fail; + } + } + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + } + } + Py_CLEAR(tmp_set); + return ret; +fail: + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + Py_CLEAR(ret); + Py_CLEAR(tmp_set); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; } -PyDoc_STRVAR(itemsview_isdisjoint_doc, - "Return True if two sets have a null intersection."); +static inline PyObject * +multidict_itemsview_sub2(_Multidict_ViewObject *self, PyObject *other) +{ + PyObject *arg = NULL; + PyObject *identity = NULL; + PyObject *key = NULL; + PyObject *value = NULL; + PyObject *value2 = NULL; + PyObject *ret = NULL; + PyObject *iter = PyObject_GetIter(other); -static PyMethodDef multidict_itemsview_methods[] = { - { - "isdisjoint", - (PyCFunction)multidict_itemsview_isdisjoint, - METH_O, - itemsview_isdisjoint_doc - }, - { - NULL, - NULL - } /* sentinel */ -}; + pair_list_pos_t pos; + + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New(NULL); + if (ret == NULL) { + goto fail; + } + while ((arg = PyIter_Next(iter))) { + int tmp = _multidict_itemsview_parse_item(self, arg, + &identity, NULL, &value); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + if (PySet_Add(ret, arg) < 0) { + goto fail; + } + Py_CLEAR(arg); + continue; + } + + pair_list_init_pos(&self->md->pairs, &pos); + + while (true) { + tmp = pair_list_next_by_identity(&self->md->pairs, &pos, + identity, NULL, &value2); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + if (PySet_Add(ret, arg) < 0) { + goto fail; + } + break; + } else { + tmp = PyObject_RichCompareBool(value, value2, Py_EQ); + if (tmp < 0) { + goto fail; + } + if (tmp > 0) { + Py_CLEAR(value2); + break; + } + } + Py_CLEAR(value2); + } + + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + return ret; +fail: + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(value); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; +} + +static inline PyObject * +multidict_itemsview_sub(PyObject *lft, PyObject *rht) +{ + mod_state * state; + int tmp = get_mod_state_by_def_checked(lft, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + tmp = get_mod_state_by_def_checked(rht, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + Py_RETURN_NOTIMPLEMENTED; + } + } + assert(state != NULL); + if (Items_CheckExact(state, lft)) { + return multidict_itemsview_sub1((_Multidict_ViewObject *)lft, rht); + } else if (Items_CheckExact(state, rht)) { + return multidict_itemsview_sub2((_Multidict_ViewObject *)rht, lft); + } + Py_RETURN_NOTIMPLEMENTED; +} + +static inline PyObject * +multidict_itemsview_xor(_Multidict_ViewObject *self, PyObject *other) +{ + mod_state * state; + int tmp = get_mod_state_by_def_checked((PyObject *)self, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + tmp = get_mod_state_by_def_checked(other, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + Py_RETURN_NOTIMPLEMENTED; + } + } + assert(state != NULL); + if (!Items_CheckExact(state, self)) { + if (Items_CheckExact(state, other)) { + return multidict_itemsview_xor((_Multidict_ViewObject *)other, + (PyObject *)self); + } else { + Py_RETURN_NOTIMPLEMENTED; + } + } + + PyObject *ret = NULL; + PyObject *tmp1 = NULL; + PyObject *tmp2 = NULL; + PyObject *rht = PySet_New(other); + if (rht == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + tmp1 = PyNumber_Subtract((PyObject *)self, rht); + if (tmp1 == NULL) { + goto fail; + } + tmp2 = PyNumber_Subtract(rht, (PyObject *)self); + if (tmp2 == NULL) { + goto fail; + } + ret = PyNumber_InPlaceOr(tmp1, tmp2); + if (ret == NULL) { + goto fail; + } + Py_CLEAR(tmp1); + Py_CLEAR(tmp2); + Py_CLEAR(rht); + return ret; +fail: + Py_CLEAR(tmp1); + Py_CLEAR(tmp2); + Py_CLEAR(rht); + Py_CLEAR(ret); + return NULL; +} static inline int multidict_itemsview_contains(_Multidict_ViewObject *self, PyObject *obj) @@ -230,36 +929,121 @@ multidict_itemsview_contains(_Multidict_ViewObject *self, PyObject *obj) return 0; } -static PySequenceMethods multidict_itemsview_as_sequence = { - .sq_length = (lenfunc)multidict_view_len, - .sq_contains = (objobjproc)multidict_itemsview_contains, +static inline PyObject * +multidict_itemsview_isdisjoint(_Multidict_ViewObject *self, PyObject *other) +{ + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + return NULL; + } + PyObject *arg = NULL; + PyObject *identity = NULL; + PyObject *value = NULL; + PyObject *value2 = NULL; + + pair_list_pos_t pos; + + while ((arg = PyIter_Next(iter))) { + int tmp = _multidict_itemsview_parse_item(self, arg, + &identity, NULL, &value); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + Py_CLEAR(arg); + continue; + } + + pair_list_init_pos(&self->md->pairs, &pos); + + while (true) { + tmp = pair_list_next_by_identity(&self->md->pairs, &pos, + identity, NULL, &value2); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + Py_CLEAR(value2); + break; + } else { + tmp = PyObject_RichCompareBool(value, value2, Py_EQ); + Py_CLEAR(value2); + if (tmp < 0) { + goto fail; + } + if (tmp > 0) { + Py_CLEAR(iter); + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(value); + Py_RETURN_FALSE; + } + } + } + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(value); + } + Py_CLEAR(iter); + if (PyErr_Occurred()) { + return NULL; + } + Py_RETURN_TRUE; +fail: + Py_CLEAR(iter); + Py_CLEAR(arg); + Py_CLEAR(identity); + Py_CLEAR(value); + Py_CLEAR(value2); + return NULL; +} + +PyDoc_STRVAR(itemsview_isdisjoint_doc, + "Return True if two sets have a null intersection."); + + +static PyMethodDef multidict_itemsview_methods[] = { + {"isdisjoint", (PyCFunction)multidict_itemsview_isdisjoint, + METH_O, itemsview_isdisjoint_doc}, + {NULL, NULL} /* sentinel */ }; -static PyTypeObject multidict_itemsview_type = { - PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) - "multidict._multidict._ItemsView", /* tp_name */ - sizeof(_Multidict_ViewObject), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_view_dealloc, - .tp_repr = (reprfunc)multidict_itemsview_repr, - .tp_as_number = &multidict_view_as_number, - .tp_as_sequence = &multidict_itemsview_as_sequence, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_traverse = (traverseproc)multidict_view_traverse, - .tp_clear = (inquiry)multidict_view_clear, - .tp_richcompare = multidict_view_richcompare, - .tp_iter = (getiterfunc)multidict_itemsview_iter, - .tp_methods = multidict_itemsview_methods, +static PyType_Slot multidict_itemsview_slots[] = { + {Py_tp_dealloc, multidict_view_dealloc}, + {Py_tp_repr, multidict_itemsview_repr}, + + {Py_nb_subtract, multidict_itemsview_sub}, + {Py_nb_and, multidict_itemsview_and}, + {Py_nb_xor, multidict_itemsview_xor}, + {Py_nb_or, multidict_itemsview_or}, + {Py_sq_length, multidict_view_len}, + {Py_sq_contains, multidict_itemsview_contains}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, multidict_view_traverse}, + {Py_tp_clear, multidict_view_clear}, + {Py_tp_richcompare, multidict_view_richcompare}, + {Py_tp_iter, multidict_itemsview_iter}, + {Py_tp_methods, multidict_itemsview_methods}, + {0, NULL}, +}; + +static PyType_Spec multidict_itemsview_spec = { + .name = "multidict._multidict._ItemsView", + .basicsize = sizeof(_Multidict_ViewObject), + .flags = (Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX >= 0x030a0000 + | Py_TPFLAGS_IMMUTABLETYPE +#endif + | Py_TPFLAGS_HAVE_GC), + .slots = multidict_itemsview_slots, }; /********** Keys **********/ static inline PyObject * -multidict_keysview_new(PyObject *md) +multidict_keysview_new(MultiDictObject *md) { _Multidict_ViewObject *mv = PyObject_GC_New( - _Multidict_ViewObject, &multidict_keysview_type); + _Multidict_ViewObject, md->pairs.state->KeysViewType); if (mv == NULL) { return NULL; } @@ -273,75 +1057,546 @@ multidict_keysview_new(PyObject *md) static inline PyObject * multidict_keysview_iter(_Multidict_ViewObject *self) { - return multidict_keys_iter_new(((MultiDictObject*)self->md)); + return multidict_keys_iter_new(self->md); } static inline PyObject * multidict_keysview_repr(_Multidict_ViewObject *self) { - return PyObject_CallFunctionObjArgs( - keysview_repr_func, self, NULL); + PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__"); + if (name == NULL) { + return NULL; + } + PyObject *ret = pair_list_repr(&self->md->pairs, name, true, false); + Py_CLEAR(name); + return ret; } static inline PyObject * -multidict_keysview_isdisjoint(_Multidict_ViewObject *self, PyObject *other) +multidict_keysview_and1(_Multidict_ViewObject *self, PyObject *other) { - return PyObject_CallFunctionObjArgs( - keysview_isdisjoint_func, self, other, NULL); + PyObject *key = NULL; + PyObject *key2 = NULL; + PyObject *ret = NULL; + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New(NULL); + if (ret == NULL) { + goto fail; + } + while ((key = PyIter_Next(iter))) { + if (!PyUnicode_Check(key)) { + Py_CLEAR(key); + continue; + } + int tmp = pair_list_contains(&self->md->pairs, key, &key2); + if (tmp < 0) { + goto fail; + } + if (tmp > 0) { + if (PySet_Add(ret, key2) < 0) { + goto fail; + } + } + Py_CLEAR(key); + Py_CLEAR(key2); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + return ret; +fail: + Py_CLEAR(key); + Py_CLEAR(key2); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; } -PyDoc_STRVAR(keysview_isdisjoint_doc, - "Return True if two sets have a null intersection."); +static inline PyObject * +multidict_keysview_and2(_Multidict_ViewObject *self, PyObject *other) +{ + PyObject *key = NULL; + PyObject *ret = NULL; + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New(NULL); + if (ret == NULL) { + goto fail; + } + while ((key = PyIter_Next(iter))) { + if (!PyUnicode_Check(key)) { + Py_CLEAR(key); + continue; + } + int tmp = pair_list_contains(&self->md->pairs, key, NULL); + if (tmp < 0) { + goto fail; + } + if (tmp > 0) { + if (PySet_Add(ret, key) < 0) { + goto fail; + } + } + Py_CLEAR(key); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + return ret; +fail: + Py_CLEAR(key); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; +} -static PyMethodDef multidict_keysview_methods[] = { - { - "isdisjoint", - (PyCFunction)multidict_keysview_isdisjoint, - METH_O, - keysview_isdisjoint_doc - }, - { - NULL, - NULL - } /* sentinel */ -}; +static inline PyObject * +multidict_keysview_and(PyObject *lft, PyObject *rht) +{ + mod_state * state; + int tmp = get_mod_state_by_def_checked(lft, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + tmp = get_mod_state_by_def_checked(rht, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + Py_RETURN_NOTIMPLEMENTED; + } + } + assert(state != NULL); + if (Keys_CheckExact(state, lft)) { + return multidict_keysview_and1((_Multidict_ViewObject *)lft, rht); + } else if (Keys_CheckExact(state, rht)) { + return multidict_keysview_and2((_Multidict_ViewObject *)rht, lft); + } + Py_RETURN_NOTIMPLEMENTED; +} + +static inline PyObject * +multidict_keysview_or1(_Multidict_ViewObject *self, PyObject *other) +{ + PyObject *key = NULL; + PyObject *ret = NULL; + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New((PyObject *)self); + if (ret == NULL) { + goto fail; + } + while ((key = PyIter_Next(iter))) { + if (!PyUnicode_Check(key)) { + if (PySet_Add(ret, key) < 0) { + goto fail; + } + Py_CLEAR(key); + continue; + } + int tmp = pair_list_contains(&self->md->pairs, key, NULL); + if (tmp < 0) { + goto fail; + } + if (tmp == 0) { + if (PySet_Add(ret, key) < 0) { + goto fail; + } + } + Py_CLEAR(key); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + return ret; +fail: + Py_CLEAR(key); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; +} + +static inline PyObject * +multidict_keysview_or2(_Multidict_ViewObject *self, PyObject *other) +{ + PyObject *iter = NULL; + PyObject *identity = NULL; + PyObject *key = NULL; + PyObject *tmp_set = NULL; + PyObject *ret = PySet_New(other); + if (ret == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + iter = PyObject_GetIter(ret); + if (iter == NULL) { + goto fail; + } + tmp_set = PySet_New(NULL); + if (tmp_set == NULL) { + goto fail; + } + while ((key = PyIter_Next(iter))) { + if (!PyUnicode_Check(key)) { + Py_CLEAR(key); + continue; + } + identity = pair_list_calc_identity(&self->md->pairs, key); + if (identity == NULL) { + goto fail; + } + if (PySet_Add(tmp_set, identity) < 0) { + goto fail; + } + Py_CLEAR(identity); + Py_CLEAR(key); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + + pair_list_pos_t pos; + pair_list_init_pos(&self->md->pairs, &pos); + + while (true) { + int tmp = pair_list_next(&self->md->pairs, &pos, &identity, &key, NULL); + if (tmp < 0) { + goto fail; + } else if (tmp == 0) { + break; + } + + tmp = PySet_Contains(tmp_set, identity); + if (tmp < 0) { + goto fail; + } + if (tmp == 0) { + if (PySet_Add(ret, key) < 0) { + goto fail; + } + } + Py_CLEAR(identity); + Py_CLEAR(key); + } + Py_CLEAR(tmp_set); + return ret; +fail: + Py_CLEAR(identity); + Py_CLEAR(key); + Py_CLEAR(iter); + Py_CLEAR(ret); + Py_CLEAR(tmp_set); + return NULL; +} + +static inline PyObject * +multidict_keysview_or(PyObject *lft, PyObject *rht) +{ + mod_state * state; + int tmp = get_mod_state_by_def_checked(lft, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + tmp = get_mod_state_by_def_checked(rht, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + Py_RETURN_NOTIMPLEMENTED; + } + } + assert(state != NULL); + if (Keys_CheckExact(state, lft)) { + return multidict_keysview_or1((_Multidict_ViewObject *)lft, rht); + } else if (Keys_CheckExact(state, rht)) { + return multidict_keysview_or2((_Multidict_ViewObject *)rht, lft); + } + Py_RETURN_NOTIMPLEMENTED; +} + +static inline PyObject * +multidict_keysview_sub1(_Multidict_ViewObject *self, PyObject *other) +{ + int tmp; + PyObject *key = NULL; + PyObject *key2 = NULL; + PyObject *ret = NULL; + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New((PyObject *)self); + if (ret == NULL) { + goto fail; + } + while ((key = PyIter_Next(iter))) { + if (!PyUnicode_Check(key)) { + Py_CLEAR(key); + continue; + } + tmp = pair_list_contains(&self->md->pairs, key, &key2); + if (tmp < 0) { + goto fail; + } + if (tmp > 0) { + if (PySet_Discard(ret, key2) < 0) { + goto fail; + } + } + Py_CLEAR(key); + Py_CLEAR(key2); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + return ret; +fail: + Py_CLEAR(key); + Py_CLEAR(key2); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; +} + +static inline PyObject * +multidict_keysview_sub2(_Multidict_ViewObject *self, PyObject *other) +{ + int tmp; + PyObject *key = NULL; + PyObject *ret = NULL; + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + ret = PySet_New(other); + if (ret == NULL) { + goto fail; + } + while ((key = PyIter_Next(iter))) { + if (!PyUnicode_Check(key)) { + Py_CLEAR(key); + continue; + } + tmp = pair_list_contains(&self->md->pairs, key, NULL); + if (tmp < 0) { + goto fail; + } + if (tmp > 0) { + if (PySet_Discard(ret, key) < 0) { + goto fail; + } + } + Py_CLEAR(key); + } + if (PyErr_Occurred()) { + goto fail; + } + Py_CLEAR(iter); + return ret; +fail: + Py_CLEAR(key); + Py_CLEAR(iter); + Py_CLEAR(ret); + return NULL; +} + +static inline PyObject * +multidict_keysview_sub(PyObject *lft, PyObject *rht) +{ + mod_state * state; + int tmp = get_mod_state_by_def_checked(lft, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + tmp = get_mod_state_by_def_checked(rht, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + Py_RETURN_NOTIMPLEMENTED; + } + } + assert(state != NULL); + if (Keys_CheckExact(state, lft)) { + return multidict_keysview_sub1((_Multidict_ViewObject *)lft, rht); + } else if (Keys_CheckExact(state, rht)) { + return multidict_keysview_sub2((_Multidict_ViewObject *)rht, lft); + } + Py_RETURN_NOTIMPLEMENTED; +} + +static inline PyObject * +multidict_keysview_xor(_Multidict_ViewObject *self, PyObject *other) +{ + mod_state * state; + int tmp = get_mod_state_by_def_checked((PyObject *)self, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + tmp = get_mod_state_by_def_checked(other, &state); + if (tmp < 0) { + return NULL; + } else if (tmp == 0) { + Py_RETURN_NOTIMPLEMENTED; + } + } + assert(state != NULL); + if (!Keys_CheckExact(state, self)) { + if (Keys_CheckExact(state, other)) { + return multidict_keysview_xor((_Multidict_ViewObject *)other, + (PyObject *)self); + } else { + Py_RETURN_NOTIMPLEMENTED; + } + } + + PyObject *ret = NULL; + PyObject *tmp1 = NULL; + PyObject *tmp2 = NULL; + PyObject *rht = PySet_New(other); + if (rht == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + goto fail; + } + tmp1 = PyNumber_Subtract((PyObject *)self, rht); + if (tmp1 == NULL) { + goto fail; + } + tmp2 = PyNumber_Subtract(rht, (PyObject *)self); + if (tmp2 == NULL) { + goto fail; + } + ret = PyNumber_InPlaceOr(tmp1, tmp2); + if (ret == NULL) { + goto fail; + } + Py_CLEAR(tmp1); + Py_CLEAR(tmp2); + Py_CLEAR(rht); + return ret; +fail: + Py_CLEAR(tmp1); + Py_CLEAR(tmp2); + Py_CLEAR(rht); + Py_CLEAR(ret); + return NULL; +} static inline int multidict_keysview_contains(_Multidict_ViewObject *self, PyObject *key) { - return pair_list_contains(&((MultiDictObject*)self->md)->pairs, key); + return pair_list_contains(&self->md->pairs, key, NULL); } -static PySequenceMethods multidict_keysview_as_sequence = { - .sq_length = (lenfunc)multidict_view_len, - .sq_contains = (objobjproc)multidict_keysview_contains, +static inline PyObject * +multidict_keysview_isdisjoint(_Multidict_ViewObject *self, PyObject *other) +{ + PyObject *iter = PyObject_GetIter(other); + if (iter == NULL) { + return NULL; + } + PyObject *key = NULL; + while ((key = PyIter_Next(iter))) { + int tmp = pair_list_contains(&self->md->pairs, key, NULL); + Py_CLEAR(key); + if (tmp < 0) { + Py_CLEAR(iter); + return NULL; + } + if (tmp > 0) { + Py_CLEAR(iter); + Py_RETURN_FALSE; + } + } + Py_CLEAR(iter); + if (PyErr_Occurred()) { + return NULL; + } + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(keysview_isdisjoint_doc, + "Return True if two sets have a null intersection."); + + +static PyMethodDef multidict_keysview_methods[] = { + {"isdisjoint", (PyCFunction)multidict_keysview_isdisjoint, + METH_O, keysview_isdisjoint_doc}, + {NULL, NULL} /* sentinel */ }; -static PyTypeObject multidict_keysview_type = { - PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) - "multidict._multidict._KeysView", /* tp_name */ - sizeof(_Multidict_ViewObject), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_view_dealloc, - .tp_repr = (reprfunc)multidict_keysview_repr, - .tp_as_number = &multidict_view_as_number, - .tp_as_sequence = &multidict_keysview_as_sequence, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_traverse = (traverseproc)multidict_view_traverse, - .tp_clear = (inquiry)multidict_view_clear, - .tp_richcompare = multidict_view_richcompare, - .tp_iter = (getiterfunc)multidict_keysview_iter, - .tp_methods = multidict_keysview_methods, +static PyType_Slot multidict_keysview_slots[] = { + {Py_tp_dealloc, multidict_view_dealloc}, + {Py_tp_repr, multidict_keysview_repr}, + + {Py_nb_subtract, multidict_keysview_sub}, + {Py_nb_and, multidict_keysview_and}, + {Py_nb_xor, multidict_keysview_xor}, + {Py_nb_or, multidict_keysview_or}, + {Py_sq_length, multidict_view_len}, + {Py_sq_contains, multidict_keysview_contains}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, multidict_view_traverse}, + {Py_tp_clear, multidict_view_clear}, + {Py_tp_richcompare, multidict_view_richcompare}, + {Py_tp_iter, multidict_keysview_iter}, + {Py_tp_methods, multidict_keysview_methods}, + {0, NULL}, }; +static PyType_Spec multidict_keysview_spec = { + .name = "multidict._multidict._KeysView", + .basicsize = sizeof(_Multidict_ViewObject), + .flags = (Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX >= 0x030a0000 + | Py_TPFLAGS_IMMUTABLETYPE +#endif + | Py_TPFLAGS_HAVE_GC), + .slots = multidict_keysview_slots, +}; /********** Values **********/ static inline PyObject * -multidict_valuesview_new(PyObject *md) +multidict_valuesview_new(MultiDictObject *md) { _Multidict_ViewObject *mv = PyObject_GC_New( - _Multidict_ViewObject, &multidict_valuesview_type); + _Multidict_ViewObject, md->pairs.state->ValuesViewType); if (mv == NULL) { return NULL; } @@ -355,107 +1610,77 @@ multidict_valuesview_new(PyObject *md) static inline PyObject * multidict_valuesview_iter(_Multidict_ViewObject *self) { - return multidict_values_iter_new(((MultiDictObject*)self->md)); + return multidict_values_iter_new(self->md); } static inline PyObject * multidict_valuesview_repr(_Multidict_ViewObject *self) { - return PyObject_CallFunctionObjArgs( - valuesview_repr_func, self, NULL); + int tmp = Py_ReprEnter((PyObject *)self); + if (tmp < 0) { + return NULL; + } + if (tmp > 0) { + return PyUnicode_FromString("..."); + } + PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__"); + if (name == NULL) { + Py_ReprLeave((PyObject *)self); + return NULL; + } + PyObject *ret = pair_list_repr(&self->md->pairs, name, false, true); + Py_ReprLeave((PyObject *)self); + Py_CLEAR(name); + return ret; } -static PySequenceMethods multidict_valuesview_as_sequence = { - .sq_length = (lenfunc)multidict_view_len, +static PyType_Slot multidict_valuesview_slots[] = { + {Py_tp_dealloc, multidict_view_dealloc}, + {Py_tp_repr, multidict_valuesview_repr}, + + {Py_sq_length, multidict_view_len}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, multidict_view_traverse}, + {Py_tp_clear, multidict_view_clear}, + {Py_tp_iter, multidict_valuesview_iter}, + {0, NULL}, }; -static PyTypeObject multidict_valuesview_type = { - PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) - "multidict._multidict._ValuesView", /* tp_name */ - sizeof(_Multidict_ViewObject), /* tp_basicsize */ - .tp_dealloc = (destructor)multidict_view_dealloc, - .tp_repr = (reprfunc)multidict_valuesview_repr, - .tp_as_sequence = &multidict_valuesview_as_sequence, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_traverse = (traverseproc)multidict_view_traverse, - .tp_clear = (inquiry)multidict_view_clear, - .tp_iter = (getiterfunc)multidict_valuesview_iter, +static PyType_Spec multidict_valuesview_spec = { + .name = "multidict._multidict._ValuesView", + .basicsize = sizeof(_Multidict_ViewObject), + .flags = (Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX >= 0x030a0000 + | Py_TPFLAGS_IMMUTABLETYPE +#endif + | Py_TPFLAGS_HAVE_GC), + .slots = multidict_valuesview_slots, }; static inline int -multidict_views_init(void) +multidict_views_init(PyObject *module, mod_state *state) { - PyObject *reg_func_call_result = NULL; - PyObject *module = PyImport_ImportModule("multidict._multidict_base"); - if (module == NULL) { - goto fail; - } - -#define GET_MOD_ATTR(VAR, NAME) \ - VAR = PyObject_GetAttrString(module, NAME); \ - if (VAR == NULL) { \ - goto fail; \ - } - - GET_MOD_ATTR(viewbaseset_richcmp_func, "_viewbaseset_richcmp"); - GET_MOD_ATTR(viewbaseset_and_func, "_viewbaseset_and"); - GET_MOD_ATTR(viewbaseset_or_func, "_viewbaseset_or"); - GET_MOD_ATTR(viewbaseset_sub_func, "_viewbaseset_sub"); - GET_MOD_ATTR(viewbaseset_xor_func, "_viewbaseset_xor"); - - GET_MOD_ATTR(abc_itemsview_register_func, "_abc_itemsview_register"); - GET_MOD_ATTR(abc_keysview_register_func, "_abc_keysview_register"); - GET_MOD_ATTR(abc_valuesview_register_func, "_abc_valuesview_register"); - - GET_MOD_ATTR(itemsview_isdisjoint_func, "_itemsview_isdisjoint"); - GET_MOD_ATTR(itemsview_repr_func, "_itemsview_repr"); - - GET_MOD_ATTR(keysview_repr_func, "_keysview_repr"); - GET_MOD_ATTR(keysview_isdisjoint_func, "_keysview_isdisjoint"); - - GET_MOD_ATTR(valuesview_repr_func, "_valuesview_repr"); - - if (PyType_Ready(&multidict_itemsview_type) < 0 || - PyType_Ready(&multidict_valuesview_type) < 0 || - PyType_Ready(&multidict_keysview_type) < 0) - { - goto fail; - } - - // abc.ItemsView.register(_ItemsView) - reg_func_call_result = PyObject_CallFunctionObjArgs( - abc_itemsview_register_func, (PyObject*)&multidict_itemsview_type, NULL); - if (reg_func_call_result == NULL) { - goto fail; + PyObject * tmp; + tmp = PyType_FromModuleAndSpec(module, &multidict_itemsview_spec, NULL); + if (tmp == NULL) { + return -1; } - Py_DECREF(reg_func_call_result); + state->ItemsViewType = (PyTypeObject *)tmp; - // abc.KeysView.register(_KeysView) - reg_func_call_result = PyObject_CallFunctionObjArgs( - abc_keysview_register_func, (PyObject*)&multidict_keysview_type, NULL); - if (reg_func_call_result == NULL) { - goto fail; + tmp = PyType_FromModuleAndSpec(module, &multidict_valuesview_spec, NULL); + if (tmp == NULL) { + return -1; } - Py_DECREF(reg_func_call_result); + state->ValuesViewType = (PyTypeObject *)tmp; - // abc.ValuesView.register(_KeysView) - reg_func_call_result = PyObject_CallFunctionObjArgs( - abc_valuesview_register_func, (PyObject*)&multidict_valuesview_type, NULL); - if (reg_func_call_result == NULL) { - goto fail; + tmp = PyType_FromModuleAndSpec(module, &multidict_keysview_spec, NULL); + if (tmp == NULL) { + return -1; } - Py_DECREF(reg_func_call_result); + state->KeysViewType = (PyTypeObject *)tmp; - Py_DECREF(module); return 0; - -fail: - Py_CLEAR(module); - return -1; - -#undef GET_MOD_ATTR } #ifdef __cplusplus diff --git a/contrib/python/multidict/tests/gen_pickles.py b/contrib/python/multidict/tests/gen_pickles.py index 72f41b7565fb..618ce5b4d7a2 100644 --- a/contrib/python/multidict/tests/gen_pickles.py +++ b/contrib/python/multidict/tests/gen_pickles.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Union -from multidict import CIMultiDict, MultiDict +from multidict import CIMultiDict, MultiDict, istr TESTS_DIR = Path(__file__).parent.resolve() _MD_Classes = Union[type[MultiDict[int]], type[CIMultiDict[int]]] @@ -16,6 +16,13 @@ def write(tag: str, cls: _MD_Classes, proto: int) -> None: pickle.dump(d, f, proto) +def write_istr(tag: str, cls: type[istr], proto: int) -> None: + s = cls("str") + file_basename = f"{cls.__name__.lower()}-{tag}" + with (TESTS_DIR / f"{file_basename}.pickle.{proto}").open("wb") as f: + pickle.dump(s, f, proto) + + def generate() -> None: _impl_map = { "c-extension": "_multidict", @@ -26,6 +33,7 @@ def generate() -> None: impl = import_module(f"multidict.{impl_name}") for cls in impl.CIMultiDict, impl.MultiDict: write(tag, cls, proto) + write_istr(tag, impl.istr, proto) if __name__ == "__main__": diff --git a/contrib/python/multidict/tests/isolated/multidict_extend_dict.py b/contrib/python/multidict/tests/isolated/multidict_extend_dict.py new file mode 100644 index 000000000000..c7fc86d237f5 --- /dev/null +++ b/contrib/python/multidict/tests/isolated/multidict_extend_dict.py @@ -0,0 +1,27 @@ +import gc +import sys +from typing import Any + +import objgraph # type: ignore[import-untyped] + +from multidict import MultiDict + + +class NoLeakDict(dict[str, Any]): + """A subclassed dict to make it easier to test for leaks.""" + + +def _run_isolated_case() -> None: + md: MultiDict[str] = MultiDict() + for _ in range(100): + md.update(NoLeakDict()) + del md + gc.collect() + + leaked = len(objgraph.by_type("NoLeakDict")) + print(f"{leaked} instances of NoLeakDict not collected by GC") + sys.exit(1 if leaked else 0) + + +if __name__ == "__main__": + _run_isolated_case() diff --git a/contrib/python/multidict/tests/isolated/multidict_extend_multidict.py b/contrib/python/multidict/tests/isolated/multidict_extend_multidict.py new file mode 100644 index 000000000000..4c98972bf428 --- /dev/null +++ b/contrib/python/multidict/tests/isolated/multidict_extend_multidict.py @@ -0,0 +1,21 @@ +import gc +import sys + +import objgraph # type: ignore[import-untyped] + +from multidict import MultiDict + + +def _run_isolated_case() -> None: + md: MultiDict[str] = MultiDict() + for _ in range(100): + md.extend(MultiDict()) + del md + gc.collect() + leaked = len(objgraph.by_type("MultiDict")) + print(f"{leaked} instances of MultiDict not collected by GC") + sys.exit(1 if leaked else 0) + + +if __name__ == "__main__": + _run_isolated_case() diff --git a/contrib/python/multidict/tests/isolated/multidict_extend_tuple.py b/contrib/python/multidict/tests/isolated/multidict_extend_tuple.py new file mode 100644 index 000000000000..d96e922c3166 --- /dev/null +++ b/contrib/python/multidict/tests/isolated/multidict_extend_tuple.py @@ -0,0 +1,27 @@ +import gc +import sys +from typing import Any + +import objgraph # type: ignore[import-untyped] + +from multidict import MultiDict + + +class NotLeakTuple(tuple[Any, ...]): + """A subclassed tuple to make it easier to test for leaks.""" + + +def _run_isolated_case() -> None: + md: MultiDict[str] = MultiDict() + for _ in range(100): + md.extend(NotLeakTuple()) + del md + gc.collect() + + leaked = len(objgraph.by_type("NotLeakTuple")) + print(f"{leaked} instances of NotLeakTuple not collected by GC") + sys.exit(1 if leaked else 0) + + +if __name__ == "__main__": + _run_isolated_case() diff --git a/contrib/python/multidict/tests/isolated/multidict_update_multidict.py b/contrib/python/multidict/tests/isolated/multidict_update_multidict.py new file mode 100644 index 000000000000..4c98972bf428 --- /dev/null +++ b/contrib/python/multidict/tests/isolated/multidict_update_multidict.py @@ -0,0 +1,21 @@ +import gc +import sys + +import objgraph # type: ignore[import-untyped] + +from multidict import MultiDict + + +def _run_isolated_case() -> None: + md: MultiDict[str] = MultiDict() + for _ in range(100): + md.extend(MultiDict()) + del md + gc.collect() + leaked = len(objgraph.by_type("MultiDict")) + print(f"{leaked} instances of MultiDict not collected by GC") + sys.exit(1 if leaked else 0) + + +if __name__ == "__main__": + _run_isolated_case() diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.0 b/contrib/python/multidict/tests/istr-c-extension.pickle.0 new file mode 100644 index 000000000000..2be573802a56 --- /dev/null +++ b/contrib/python/multidict/tests/istr-c-extension.pickle.0 @@ -0,0 +1,8 @@ +cmultidict._multidict +istr +p0 +(Vstr +p1 +tp2 +Rp3 +. \ No newline at end of file diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.1 b/contrib/python/multidict/tests/istr-c-extension.pickle.1 new file mode 100644 index 000000000000..206775444b5b Binary files /dev/null and b/contrib/python/multidict/tests/istr-c-extension.pickle.1 differ diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.2 b/contrib/python/multidict/tests/istr-c-extension.pickle.2 new file mode 100644 index 000000000000..5c038d23fafd Binary files /dev/null and b/contrib/python/multidict/tests/istr-c-extension.pickle.2 differ diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.3 b/contrib/python/multidict/tests/istr-c-extension.pickle.3 new file mode 100644 index 000000000000..a9184bb4c32e Binary files /dev/null and b/contrib/python/multidict/tests/istr-c-extension.pickle.3 differ diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.4 b/contrib/python/multidict/tests/istr-c-extension.pickle.4 new file mode 100644 index 000000000000..d6c52d244919 Binary files /dev/null and b/contrib/python/multidict/tests/istr-c-extension.pickle.4 differ diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.5 b/contrib/python/multidict/tests/istr-c-extension.pickle.5 new file mode 100644 index 000000000000..fce4bc01efcb Binary files /dev/null and b/contrib/python/multidict/tests/istr-c-extension.pickle.5 differ diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.0 b/contrib/python/multidict/tests/istr-pure-python.pickle.0 new file mode 100644 index 000000000000..9e3f0a2a6b70 --- /dev/null +++ b/contrib/python/multidict/tests/istr-pure-python.pickle.0 @@ -0,0 +1,14 @@ +ccopy_reg +_reconstructor +p0 +(cmultidict._multidict_py +istr +p1 +c__builtin__ +unicode +p2 +Vstr +p3 +tp4 +Rp5 +. \ No newline at end of file diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.1 b/contrib/python/multidict/tests/istr-pure-python.pickle.1 new file mode 100644 index 000000000000..88b7a9d434a6 Binary files /dev/null and b/contrib/python/multidict/tests/istr-pure-python.pickle.1 differ diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.2 b/contrib/python/multidict/tests/istr-pure-python.pickle.2 new file mode 100644 index 000000000000..9f17e5997e73 Binary files /dev/null and b/contrib/python/multidict/tests/istr-pure-python.pickle.2 differ diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.3 b/contrib/python/multidict/tests/istr-pure-python.pickle.3 new file mode 100644 index 000000000000..09f70c0ae818 Binary files /dev/null and b/contrib/python/multidict/tests/istr-pure-python.pickle.3 differ diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.4 b/contrib/python/multidict/tests/istr-pure-python.pickle.4 new file mode 100644 index 000000000000..d092a4eb550d Binary files /dev/null and b/contrib/python/multidict/tests/istr-pure-python.pickle.4 differ diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.5 b/contrib/python/multidict/tests/istr-pure-python.pickle.5 new file mode 100644 index 000000000000..b8f03af65625 Binary files /dev/null and b/contrib/python/multidict/tests/istr-pure-python.pickle.5 differ diff --git a/contrib/python/multidict/tests/test_circular_imports.py b/contrib/python/multidict/tests/test_circular_imports.py index 00f6ae4f582c..f6ea323ee22c 100644 --- a/contrib/python/multidict/tests/test_circular_imports.py +++ b/contrib/python/multidict/tests/test_circular_imports.py @@ -51,9 +51,6 @@ def _discover_path_importables( if pkg_dir_path.parts[-1] == "__pycache__": continue - if all(Path(_).suffix != ".py" for _ in file_names): - continue - rel_pt = pkg_dir_path.relative_to(pkg_pth) pkg_pref = ".".join((pkg_name,) + rel_pt.parts) yield from ( diff --git a/contrib/python/multidict/tests/test_incorrect_args.py b/contrib/python/multidict/tests/test_incorrect_args.py new file mode 100644 index 000000000000..280204c8d097 --- /dev/null +++ b/contrib/python/multidict/tests/test_incorrect_args.py @@ -0,0 +1,126 @@ +"""Test passing invalid arguments to the methods of the MultiDict class.""" + +from dataclasses import dataclass +from typing import cast + +import pytest + +from multidict import MultiDict + + +@dataclass(frozen=True) +class InvalidTestedMethodArgs: + """A set of arguments passed to methods under test.""" + + test_id: str + positional: tuple[object, ...] + keyword: dict[str, object] + + def __str__(self) -> str: + """Render a test identifier as a string.""" + return self.test_id + + +@pytest.fixture( + scope="module", + params=( + InvalidTestedMethodArgs("no_args", (), {}), + InvalidTestedMethodArgs("too_many_args", ("a", "b", "c"), {}), + InvalidTestedMethodArgs("wrong_kwarg", (), {"wrong": 1}), + InvalidTestedMethodArgs( + "wrong_kwarg_and_too_many_args", + ("a",), + {"wrong": 1}, + ), + ), + ids=str, +) +def tested_method_args( + request: pytest.FixtureRequest, +) -> InvalidTestedMethodArgs: + """Return an instance of a parameter set.""" + return cast(InvalidTestedMethodArgs, request.param) + + +@pytest.fixture(scope="module") +def multidict_object( + any_multidict_class: type[MultiDict[int]], +) -> MultiDict[int]: + return any_multidict_class([("a", 1), ("a", 2)]) + + +def test_getall_args( + multidict_object: MultiDict[int], + tested_method_args: InvalidTestedMethodArgs, +) -> None: + with pytest.raises(TypeError, match=r".*argument.*"): + multidict_object.getall( + *tested_method_args.positional, + **tested_method_args.keyword, + ) + + +def test_getone_args( + multidict_object: MultiDict[int], + tested_method_args: InvalidTestedMethodArgs, +) -> None: + with pytest.raises(TypeError, match=r".*argument.*"): + multidict_object.getone( + *tested_method_args.positional, + **tested_method_args.keyword, + ) + + +def test_get_args( + multidict_object: MultiDict[int], + tested_method_args: InvalidTestedMethodArgs, +) -> None: + with pytest.raises(TypeError, match=r".*argument.*"): + multidict_object.get( + *tested_method_args.positional, + **tested_method_args.keyword, + ) + + +def test_setdefault_args( + multidict_object: MultiDict[int], + tested_method_args: InvalidTestedMethodArgs, +) -> None: + with pytest.raises(TypeError, match=r".*argument.*"): + multidict_object.setdefault( + *tested_method_args.positional, + **tested_method_args.keyword, + ) + + +def test_popone_args( + multidict_object: MultiDict[int], + tested_method_args: InvalidTestedMethodArgs, +) -> None: + with pytest.raises(TypeError, match=r".*argument.*"): + multidict_object.popone( + *tested_method_args.positional, + **tested_method_args.keyword, + ) + + +def test_pop_args( + multidict_object: MultiDict[int], + tested_method_args: InvalidTestedMethodArgs, +) -> None: + with pytest.raises(TypeError, match=r".*argument.*"): + multidict_object.pop( + *tested_method_args.positional, + **tested_method_args.keyword, + ) + + +def test_popall_args( + multidict_object: MultiDict[int], + tested_method_args: InvalidTestedMethodArgs, +) -> None: + with pytest.raises(TypeError, match=r".*argument.*"): + multidict_object.popall( + *tested_method_args.positional, + **tested_method_args.keyword, + ) diff --git a/contrib/python/multidict/tests/test_istr.py b/contrib/python/multidict/tests/test_istr.py index 101f5fe8e5d3..f02a23593334 100644 --- a/contrib/python/multidict/tests/test_istr.py +++ b/contrib/python/multidict/tests/test_istr.py @@ -5,6 +5,7 @@ import pytest IMPLEMENTATION = getattr(sys, "implementation") # to suppress mypy error +GIL_ENABLED = getattr(sys, "_is_gil_enabled", lambda: True)() def test_ctor(case_insensitive_str_class: Type[str]) -> None: @@ -63,6 +64,10 @@ def _create_strs() -> None: IMPLEMENTATION.name != "cpython", reason="PyPy has different GC implementation", ) +@pytest.mark.skipif( + not GIL_ENABLED, + reason="free threading has different GC implementation", +) def test_leak(create_istrs: Callable[[], None]) -> None: gc.collect() cnt = len(gc.get_objects()) @@ -71,4 +76,4 @@ def test_leak(create_istrs: Callable[[], None]) -> None: gc.collect() cnt2 = len(gc.get_objects()) - assert abs(cnt - cnt2) < 50 # on PyPy these numbers are not equal + assert abs(cnt - cnt2) < 10 # on other GC impls these numbers are not equal diff --git a/contrib/python/multidict/tests/test_leaks.py b/contrib/python/multidict/tests/test_leaks.py new file mode 100644 index 000000000000..ded7cf065b01 --- /dev/null +++ b/contrib/python/multidict/tests/test_leaks.py @@ -0,0 +1,31 @@ +import pathlib +import platform +import subprocess +import sys + +import pytest + +IS_PYPY = platform.python_implementation() == "PyPy" + + +@pytest.mark.parametrize( + ("script"), + ( + "multidict_extend_dict.py", + "multidict_extend_multidict.py", + "multidict_extend_tuple.py", + "multidict_update_multidict.py", + ), +) +@pytest.mark.leaks +@pytest.mark.skipif(IS_PYPY, reason="leak testing is not supported on PyPy") +def test_leak(script: str) -> None: + """Run isolated leak test script and check for leaks.""" + leak_test_script = pathlib.Path(__file__).parent.joinpath("isolated", script) + + subprocess.run( + [sys.executable, "-u", str(leak_test_script)], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=True, + ) diff --git a/contrib/python/multidict/tests/test_multidict.py b/contrib/python/multidict/tests/test_multidict.py index d144130a41f9..aa59d6adef4e 100644 --- a/contrib/python/multidict/tests/test_multidict.py +++ b/contrib/python/multidict/tests/test_multidict.py @@ -2,12 +2,13 @@ import gc import operator +import platform import sys import weakref from collections import deque from collections.abc import Callable, Iterable, Iterator, KeysView, Mapping from types import ModuleType -from typing import Union, cast +from typing import TypeVar, Union, cast import pytest @@ -18,8 +19,12 @@ MultiDictProxy, MultiMapping, MutableMultiMapping, + istr, ) +_T = TypeVar("_T") +IS_PYPY = platform.python_implementation() == "PyPy" + def chained_callable( module: ModuleType, @@ -34,8 +39,6 @@ def chained_call( *args: object, **kwargs: object, ) -> MultiMapping[int | str] | MutableMultiMapping[int | str]: - nonlocal callables - callable_chain = (getattr(module, name) for name in callables) first_callable = next(callable_chain) @@ -291,7 +294,7 @@ def test_cannot_create_from_unaccepted( self, cls: type[MutableMultiMapping[str]], ) -> None: - with pytest.raises(TypeError): + with pytest.raises(ValueError, match="multidict update sequence element"): cls([(1, 2, 3)]) # type: ignore[call-arg] def test_keys_is_set_less(self, cls: type[MultiDict[str]]) -> None: @@ -723,6 +726,17 @@ def test__repr__(self, cls: type[MultiDict[str]]) -> None: assert str(d) == "<%s('key': 'one', 'key': 'two')>" % _cls.__name__ + def test__repr___recursive( + self, any_multidict_class: type[MultiDict[object]] + ) -> None: + d = any_multidict_class() + _cls = type(d) + + d = any_multidict_class() + d["key"] = d + + assert str(d) == "<%s('key': ...)>" % _cls.__name__ + def test_getall(self, cls: type[MultiDict[str]]) -> None: d = cls([("key", "value1")], key="value2") @@ -752,16 +766,31 @@ def test_get(self, cls: type[MultiDict[int]]) -> None: def test_items__repr__(self, cls: type[MultiDict[str]]) -> None: d = cls([("key", "value1")], key="value2") - expected = "_ItemsView('key': 'value1', 'key': 'value2')" + expected = "<_ItemsView('key': 'value1', 'key': 'value2')>" + assert repr(d.items()) == expected + + def test_items__repr__recursive( + self, any_multidict_class: type[MultiDict[object]] + ) -> None: + d = any_multidict_class() + d["key"] = d.items() + expected = "<_ItemsView('key': <_ItemsView('key': ...)>)>" assert repr(d.items()) == expected def test_keys__repr__(self, cls: type[MultiDict[str]]) -> None: d = cls([("key", "value1")], key="value2") - assert repr(d.keys()) == "_KeysView('key', 'key')" + assert repr(d.keys()) == "<_KeysView('key', 'key')>" def test_values__repr__(self, cls: type[MultiDict[str]]) -> None: d = cls([("key", "value1")], key="value2") - assert repr(d.values()) == "_ValuesView('value1', 'value2')" + assert repr(d.values()) == "<_ValuesView('value1', 'value2')>" + + def test_values__repr__recursive( + self, any_multidict_class: type[MultiDict[object]] + ) -> None: + d = any_multidict_class() + d["key"] = d.values() + assert repr(d.values()) == "<_ValuesView(<_ValuesView(...)>)>" class TestCIMultiDict(BaseMultiDictTest): @@ -793,6 +822,12 @@ def test_basics(self, cls: type[CIMultiDict[str]]) -> None: with pytest.raises(KeyError, match="key2"): d.getone("key2") + def test_from_md_and_kwds(self, cls: type[CIMultiDict[str]]) -> None: + d = cls([("KEY", "value1")]) + d2 = cls(d, KEY="value2") + + assert list(d2.items()) == [("KEY", "value1"), ("KEY", "value2")] + def test_getall(self, cls: type[CIMultiDict[str]]) -> None: d = cls([("KEY", "value1")], KEY="value2") @@ -817,13 +852,474 @@ def test__repr__(self, cls: type[CIMultiDict[str]]) -> None: def test_items__repr__(self, cls: type[CIMultiDict[str]]) -> None: d = cls([("KEY", "value1")], key="value2") - expected = "_ItemsView('KEY': 'value1', 'key': 'value2')" + expected = "<_ItemsView('KEY': 'value1', 'key': 'value2')>" assert repr(d.items()) == expected def test_keys__repr__(self, cls: type[CIMultiDict[str]]) -> None: d = cls([("KEY", "value1")], key="value2") - assert repr(d.keys()) == "_KeysView('KEY', 'key')" + assert repr(d.keys()) == "<_KeysView('KEY', 'key')>" def test_values__repr__(self, cls: type[CIMultiDict[str]]) -> None: d = cls([("KEY", "value1")], key="value2") - assert repr(d.values()) == "_ValuesView('value1', 'value2')" + assert repr(d.values()) == "<_ValuesView('value1', 'value2')>" + + def test_items_iter_of_iter(self, cls: type[CIMultiDict[str]]) -> None: + d = cls([("KEY", "value1")], key="value2") + it = iter(d.items()) + assert iter(it) is it + + def test_keys_iter_of_iter(self, cls: type[CIMultiDict[str]]) -> None: + d = cls([("KEY", "value1")], key="value2") + it = iter(d.keys()) + assert iter(it) is it + + def test_values_iter_of_iter(self, cls: type[CIMultiDict[str]]) -> None: + d = cls([("KEY", "value1")], key="value2") + it = iter(d.values()) + assert iter(it) is it + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param({"key"}, {"KEY"}, id="ok"), + pytest.param({"key", 123}, {"KEY"}, id="non-str"), + ), + ) + def test_keys_case_insensitive_and( + self, cls: type[CIMultiDict[str]], arg: set[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one")]) + assert d.keys() & arg == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param(["key"], {"key"}, id="ok"), + pytest.param(["key", 123], {"key"}, id="non-str"), + ), + ) + def test_keys_case_insensitive_rand( + self, cls: type[CIMultiDict[str]], arg: list[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one")]) + assert type(arg) is list + assert arg & d.keys() == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param({"key", "other"}, {"KEY", "other"}, id="ok"), + pytest.param({"key", "other", 123}, {"KEY", "other", 123}, id="non-str"), + ), + ) + def test_keys_case_insensitive_or( + self, cls: type[CIMultiDict[str]], arg: set[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one")]) + + assert d.keys() | arg == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param(["key", "other"], {"key", "other"}, id="ok"), + pytest.param(["key", "other", 123], {"key", "other", 123}, id="non-str"), + ), + ) + def test_keys_case_insensitive_ror( + self, cls: type[CIMultiDict[str]], arg: list[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one")]) + assert type(arg) is list + + assert arg | d.keys() == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param({"key", "other"}, {"KEY2"}, id="ok"), + pytest.param({"key", "other", 123}, {"KEY2"}, id="non-str"), + ), + ) + def test_keys_case_insensitive_sub( + self, cls: type[CIMultiDict[str]], arg: set[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one"), ("KEY2", "two")]) + + assert d.keys() - arg == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param(["key", "other"], {"other"}, id="ok"), + pytest.param(["key", "other", 123], {"other", 123}, id="non-str"), + ), + ) + def test_keys_case_insensitive_rsub( + self, cls: type[CIMultiDict[str]], arg: list[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one"), ("KEY2", "two")]) + assert type(arg) is list + + assert arg - d.keys() == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param(["key", "other"], {"KEY2", "other"}, id="ok"), + pytest.param(["key", "other", 123], {"KEY2", "other", 123}, id="non-str"), + ), + ) + def test_keys_case_insensitive_xor( + self, cls: type[CIMultiDict[str]], arg: list[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one"), ("KEY2", "two")]) + + assert d.keys() ^ arg == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param(["key", "other"], {"KEY2", "other"}, id="ok"), + pytest.param(["key", "other", 123], {"KEY2", "other", 123}, id="non-str"), + ), + ) + def test_keys_case_insensitive_rxor( + self, cls: type[CIMultiDict[str]], arg: list[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one"), ("KEY2", "two")]) + + assert arg ^ d.keys() == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param({"key"}, False, id="ok"), + pytest.param({123}, True, id="non-str"), + ), + ) + def test_keys_case_insensitive_isdisjoint( + self, cls: type[CIMultiDict[str]], arg: set[_T], expected: bool + ) -> None: + d = cls([("KEY", "one")]) + assert d.keys().isdisjoint(arg) == expected + + def test_keys_case_insensitive_not_iterable( + self, cls: type[CIMultiDict[str]] + ) -> None: + d = cls([("KEY", "one"), ("KEY2", "two")]) + + with pytest.raises(TypeError): + 123 & d.keys() # type: ignore[operator] + + with pytest.raises(TypeError): + d.keys() & 123 # type: ignore[operator] + + with pytest.raises(TypeError): + 123 | d.keys() # type: ignore[operator] + + with pytest.raises(TypeError): + d.keys() | 123 # type: ignore[operator] + + with pytest.raises(TypeError): + 123 ^ d.keys() # type: ignore[operator] + + with pytest.raises(TypeError): + d.keys() ^ 123 # type: ignore[operator] + + with pytest.raises(TypeError): + d.keys() - 123 # type: ignore[operator] + + with pytest.raises(TypeError): + 123 - d.keys() # type: ignore[operator] + + @pytest.mark.parametrize( + "param", + ( + pytest.param("non-tuple", id="not-tuple"), + pytest.param(("key2", "two", "three"), id="not-2-elems"), + pytest.param((123, "two"), id="not-str"), + ), + ) + def test_items_case_insensitive_parse_item( + self, cls: type[CIMultiDict[str]], param: _T + ) -> None: + d = cls([("KEY", "one")]) + assert d.items() | {param} == {("KEY", "one"), param} + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param({("key", "one")}, {("KEY", "one")}, id="ok"), + pytest.param( + {("key", "one"), (123, "two")}, + {("KEY", "one")}, + id="non-str", + ), + pytest.param( + {("key", "one"), ("key", "two")}, + {("KEY", "one")}, + id="nonequal-value", + ), + ), + ) + def test_items_case_insensitive_and( + self, cls: type[CIMultiDict[str]], arg: set[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one")]) + assert d.items() & arg == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param([("key", "one")], {("key", "one")}, id="ok"), + pytest.param( + [("key", "one"), (123, "two")], + {("key", "one")}, + id="non-str", + ), + pytest.param( + [("key", "one"), ("key", "two")], + {("key", "one")}, + id="nonequal-value", + ), + ), + ) + def test_items_case_insensitive_rand( + self, cls: type[CIMultiDict[str]], arg: list[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one")]) + assert type(arg) is list + assert arg & d.items() == expected + + def test_items_case_insensitive_or(self, cls: type[CIMultiDict[str]]) -> None: + d = cls([("KEY", "one")]) + + assert d.items() | {("key", "one"), ("other", "two")} == { + ("KEY", "one"), + ("other", "two"), + } + + def test_items_case_insensitive_ror(self, cls: type[CIMultiDict[str]]) -> None: + d = cls([("KEY", "one"), ("KEY2", "three")]) + + assert [("key", "one"), ("other", "two")] | d.items() == { + ("key", "one"), + ("other", "two"), + ("KEY2", "three"), + } + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param( + {("key", "one"), ("other", "three")}, {("KEY2", "two")}, id="ok" + ), + pytest.param( + {("key", "one"), (123, "three")}, {("KEY2", "two")}, id="non-str" + ), + ), + ) + def test_items_case_insensitive_sub( + self, cls: type[CIMultiDict[str]], arg: set[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one"), ("KEY2", "two")]) + + assert d.items() - arg == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param( + [("key", "one"), ("other", "three")], {("other", "three")}, id="ok" + ), + pytest.param( + [("key", "one"), (123, "three")], {(123, "three")}, id="non-str" + ), + ), + ) + def test_items_case_insensitive_rsub( + self, cls: type[CIMultiDict[str]], arg: set[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one"), ("KEY2", "two")]) + + assert arg - d.items() == expected + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param( + {("key", "one"), ("other", "three")}, + {("KEY2", "two"), ("other", "three")}, + id="ok", + ), + pytest.param( + {("key", "one"), (123, "three")}, + {("KEY2", "two"), (123, "three")}, + id="non-str", + ), + ), + ) + def test_items_case_insensitive_xor( + self, cls: type[CIMultiDict[str]], arg: set[_T], expected: set[_T] + ) -> None: + d = cls([("KEY", "one"), ("KEY2", "two")]) + + assert d.items() ^ arg == expected + + def test_items_case_insensitive_rxor(self, cls: type[CIMultiDict[str]]) -> None: + d = cls([("KEY", "one"), ("KEY2", "two")]) + + assert [("key", "one"), ("other", "three")] ^ d.items() == { + ("KEY2", "two"), + ("other", "three"), + } + + def test_items_case_insensitive_non_iterable( + self, cls: type[CIMultiDict[str]] + ) -> None: + d = cls([("KEY", "one")]) + + with pytest.raises(TypeError): + d.items() & None # type: ignore[operator] + + with pytest.raises(TypeError): + None & d.items() # type: ignore[operator] + + with pytest.raises(TypeError): + d.items() | None # type: ignore[operator] + + with pytest.raises(TypeError): + None | d.items() # type: ignore[operator] + + with pytest.raises(TypeError): + d.items() ^ None # type: ignore[operator] + + with pytest.raises(TypeError): + None ^ d.items() # type: ignore[operator] + + with pytest.raises(TypeError): + d.items() - None # type: ignore[operator] + + with pytest.raises(TypeError): + None - d.items() # type: ignore[operator] + + @pytest.mark.parametrize( + ("arg", "expected"), + ( + pytest.param({("key", "one")}, False, id="ok"), + pytest.param({(123, "one")}, True, id="non-str"), + ), + ) + def test_items_case_insensitive_isdisjoint( + self, cls: type[CIMultiDict[str]], arg: set[_T], expected: bool + ) -> None: + d = cls([("KEY", "one")]) + assert d.items().isdisjoint(arg) == expected + + +def test_create_multidict_from_existing_multidict_new_pairs() -> None: + """Test creating a MultiDict from an existing one does not mutate the original.""" + original = MultiDict([("h1", "header1"), ("h2", "header2"), ("h3", "header3")]) + new = MultiDict(original, h4="header4") + assert "h4" in new + assert "h4" not in original + + +def test_convert_multidict_to_cimultidict_and_back( + case_sensitive_multidict_class: type[MultiDict[str]], + case_insensitive_multidict_class: type[CIMultiDict[str]], + case_insensitive_str_class: type[istr], +) -> None: + """Test conversion from MultiDict to CIMultiDict.""" + start_as_md = case_sensitive_multidict_class( + [("KEY", "value1"), ("key2", "value2")] + ) + assert start_as_md.get("KEY") == "value1" + assert start_as_md["KEY"] == "value1" + assert start_as_md.get("key2") == "value2" + assert start_as_md["key2"] == "value2" + start_as_cimd = case_insensitive_multidict_class( + [("KEY", "value1"), ("key2", "value2")] + ) + assert start_as_cimd.get("key") == "value1" + assert start_as_cimd["key"] == "value1" + assert start_as_cimd.get("key2") == "value2" + assert start_as_cimd["key2"] == "value2" + converted_to_ci = case_insensitive_multidict_class(start_as_md) + assert converted_to_ci.get("key") == "value1" + assert converted_to_ci["key"] == "value1" + assert converted_to_ci.get("key2") == "value2" + assert converted_to_ci["key2"] == "value2" + converted_to_md = case_sensitive_multidict_class(converted_to_ci) + assert all(type(k) is case_insensitive_str_class for k in converted_to_ci.keys()) + assert converted_to_md.get("KEY") == "value1" + assert converted_to_md["KEY"] == "value1" + assert converted_to_md.get("key2") == "value2" + assert converted_to_md["key2"] == "value2" + + +def test_convert_multidict_to_cimultidict_eq( + case_sensitive_multidict_class: type[MultiDict[str]], + case_insensitive_multidict_class: type[CIMultiDict[str]], +) -> None: + """Test compare after conversion from MultiDict to CIMultiDict.""" + original = case_sensitive_multidict_class( + [("h1", "header1"), ("h2", "header2"), ("h3", "header3")] + ) + assert case_insensitive_multidict_class( + original + ) == case_insensitive_multidict_class( + [("H1", "header1"), ("H2", "header2"), ("H3", "header3")] + ) + + +@pytest.mark.skipif(IS_PYPY, reason="getrefcount is not supported on PyPy") +def test_extend_does_not_alter_refcount( + case_sensitive_multidict_class: type[MultiDict[str]], +) -> None: + """Test that extending a MultiDict with a MultiDict does not alter the refcount of the original.""" + original = case_sensitive_multidict_class([("h1", "header1")]) + new = case_sensitive_multidict_class([("h2", "header2")]) + original_refcount = sys.getrefcount(original) + new.extend(original) + assert sys.getrefcount(original) == original_refcount + + +@pytest.mark.skipif(IS_PYPY, reason="getrefcount is not supported on PyPy") +def test_update_does_not_alter_refcount( + case_sensitive_multidict_class: type[MultiDict[str]], +) -> None: + """Test that updating a MultiDict with a MultiDict does not alter the refcount of the original.""" + original = case_sensitive_multidict_class([("h1", "header1")]) + new = case_sensitive_multidict_class([("h2", "header2")]) + original_refcount = sys.getrefcount(original) + new.update(original) + assert sys.getrefcount(original) == original_refcount + + +@pytest.mark.skipif(IS_PYPY, reason="getrefcount is not supported on PyPy") +def test_init_does_not_alter_refcount( + case_sensitive_multidict_class: type[MultiDict[str]], +) -> None: + """Test that initializing a MultiDict with a MultiDict does not alter the refcount of the original.""" + original = case_sensitive_multidict_class([("h1", "header1")]) + original_refcount = sys.getrefcount(original) + case_sensitive_multidict_class(original) + assert sys.getrefcount(original) == original_refcount + + +def test_subclassed_multidict( + any_multidict_class: type[MultiDict[str]], +) -> None: + """Test that subclassed MultiDicts work as expected.""" + class SubclassedMultiDict(any_multidict_class): # type: ignore[valid-type, misc] + """Subclassed MultiDict.""" + + d1 = SubclassedMultiDict([("key", "value1")]) + d2 = SubclassedMultiDict([("key", "value2")]) + d3 = SubclassedMultiDict([("key", "value1")]) + assert d1 != d2 + assert d1 == d3 + assert d1 == SubclassedMultiDict([("key", "value1")]) + assert d1 != SubclassedMultiDict([("key", "value2")]) diff --git a/contrib/python/multidict/tests/test_multidict_benchmarks.py b/contrib/python/multidict/tests/test_multidict_benchmarks.py index e6a538f3ccf4..a7a6a76e7287 100644 --- a/contrib/python/multidict/tests/test_multidict_benchmarks.py +++ b/contrib/python/multidict/tests/test_multidict_benchmarks.py @@ -1,10 +1,16 @@ """codspeed benchmarks for multidict.""" -from typing import Dict, Union +from typing import Dict, Type, Union from pytest_codspeed import BenchmarkFixture -from multidict import CIMultiDict, MultiDict, istr +from multidict import ( + CIMultiDict, + CIMultiDictProxy, + MultiDict, + MultiDictProxy, + istr, +) # Note that this benchmark should not be refactored to use pytest.mark.parametrize # since each benchmark name should be unique. @@ -12,18 +18,10 @@ _SENTINEL = object() -def test_multidict_insert_str(benchmark: BenchmarkFixture) -> None: - md: MultiDict[str] = MultiDict() - items = [str(i) for i in range(100)] - - @benchmark - def _run() -> None: - for i in items: - md[i] = i - - -def test_cimultidict_insert_str(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict() +def test_multidict_insert_str( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class() items = [str(i) for i in range(100)] @benchmark @@ -32,8 +30,11 @@ def _run() -> None: md[i] = i -def test_cimultidict_insert_istr(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[istr] = CIMultiDict() +def test_cimultidict_insert_istr( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + md = case_insensitive_multidict_class() items = [istr(i) for i in range(100)] @benchmark @@ -42,49 +43,39 @@ def _run() -> None: md[i] = i -def test_multidict_add_str(benchmark: BenchmarkFixture) -> None: - md: MultiDict[str] = MultiDict() - items = [str(i) for i in range(100)] - - @benchmark - def _run() -> None: - for i in items: - md.add(i, i) - - -def test_cimultidict_add_str(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict() +def test_multidict_add_str( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + base_md = any_multidict_class() items = [str(i) for i in range(100)] @benchmark def _run() -> None: - for i in items: - md.add(i, i) + for _ in range(100): + md = base_md.copy() + for i in items: + md.add(i, i) -def test_cimultidict_add_istr(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[istr] = CIMultiDict() +def test_cimultidict_add_istr( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + base_md = case_insensitive_multidict_class() items = [istr(i) for i in range(100)] @benchmark def _run() -> None: - for i in items: - md.add(i, i) + for j in range(100): + md = base_md.copy() + for i in items: + md.add(i, i) -def test_multidict_pop_str(benchmark: BenchmarkFixture) -> None: - md_base: MultiDict[str] = MultiDict((str(i), str(i)) for i in range(100)) - items = [str(i) for i in range(100)] - - @benchmark - def _run() -> None: - md = md_base.copy() - for i in items: - md.pop(i) - - -def test_cimultidict_pop_str(benchmark: BenchmarkFixture) -> None: - md_base: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_pop_str( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md_base = any_multidict_class((str(i), str(i)) for i in range(100)) items = [str(i) for i in range(100)] @benchmark @@ -94,8 +85,11 @@ def _run() -> None: md.pop(i) -def test_cimultidict_pop_istr(benchmark: BenchmarkFixture) -> None: - md_base: CIMultiDict[istr] = CIMultiDict((istr(i), istr(i)) for i in range(100)) +def test_cimultidict_pop_istr( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + md_base = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) items = [istr(i) for i in range(100)] @benchmark @@ -105,18 +99,10 @@ def _run() -> None: md.pop(i) -def test_multidict_popitem_str(benchmark: BenchmarkFixture) -> None: - md_base: MultiDict[str] = MultiDict((str(i), str(i)) for i in range(100)) - - @benchmark - def _run() -> None: - md = md_base.copy() - for _ in range(100): - md.popitem() - - -def test_cimultidict_popitem_str(benchmark: BenchmarkFixture) -> None: - md_base: MultiDict[str] = MultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_popitem_str( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md_base = any_multidict_class((str(i), str(i)) for i in range(100)) @benchmark def _run() -> None: @@ -125,89 +111,124 @@ def _run() -> None: md.popitem() -def test_multidict_clear_str(benchmark: BenchmarkFixture) -> None: - md: MultiDict[str] = MultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_clear_str( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class((str(i), str(i)) for i in range(100)) @benchmark def _run() -> None: md.clear() -def test_cimultidict_clear_str(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_update_str( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class((str(i), str(i)) for i in range(100)) + items = {str(i): str(i) for i in range(100, 200)} @benchmark def _run() -> None: - md.clear() + md.update(items) -def test_multidict_update_str(benchmark: BenchmarkFixture) -> None: - md: MultiDict[str] = MultiDict((str(i), str(i)) for i in range(100)) - items = {str(i): str(i) for i in range(100, 200)} +def test_cimultidict_update_istr( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) + items: Dict[Union[str, istr], istr] = {istr(i): istr(i) for i in range(100, 200)} @benchmark def _run() -> None: md.update(items) -def test_cimultidict_update_str(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_update_str_with_kwargs( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class((str(i), str(i)) for i in range(100)) items = {str(i): str(i) for i in range(100, 200)} + kwargs = {str(i): str(i) for i in range(200, 300)} @benchmark def _run() -> None: - md.update(items) + md.update(items, **kwargs) -def test_cimultidict_update_istr(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[istr] = CIMultiDict((istr(i), istr(i)) for i in range(100)) +def test_cimultidict_update_istr_with_kwargs( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) items: Dict[Union[str, istr], istr] = {istr(i): istr(i) for i in range(100, 200)} + kwargs = {str(i): istr(i) for i in range(200, 300)} @benchmark def _run() -> None: - md.update(items) + md.update(items, **kwargs) -def test_multidict_extend_str(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_extend_str( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + base_md = any_multidict_class((str(i), str(i)) for i in range(100)) items = {str(i): str(i) for i in range(200)} @benchmark def _run() -> None: - md.extend(items) + for j in range(100): + md = base_md.copy() + md.extend(items) -def test_cimultidict_extend_str(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) - items = {str(i): str(i) for i in range(200)} +def test_cimultidict_extend_istr( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + base_md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) + items = {istr(i): istr(i) for i in range(200)} @benchmark def _run() -> None: - md.extend(items) + for _ in range(100): + md = base_md.copy() + md.extend(items) -def test_cimultidict_extend_istr(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[istr] = CIMultiDict((istr(i), istr(i)) for i in range(100)) - items = {istr(i): istr(i) for i in range(200)} +def test_multidict_extend_str_with_kwargs( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + base_md = any_multidict_class((str(i), str(i)) for i in range(100)) + items = {str(i): str(i) for i in range(200)} + kwargs = {str(i): str(i) for i in range(200, 300)} @benchmark def _run() -> None: - md.extend(items) + for j in range(100): + md = base_md.copy() + md.extend(items, **kwargs) -def test_multidict_delitem_str(benchmark: BenchmarkFixture) -> None: - md_base: MultiDict[str] = MultiDict((str(i), str(i)) for i in range(100)) - items = [str(i) for i in range(100)] +def test_cimultidict_extend_istr_with_kwargs( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + base_md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) + items = {istr(i): istr(i) for i in range(200)} + kwargs = {str(i): istr(i) for i in range(200, 300)} @benchmark def _run() -> None: - md = md_base.copy() - for i in items: - del md[i] + for _ in range(100): + md = base_md.copy() + md.extend(items, **kwargs) -def test_cimultidict_delitem_str(benchmark: BenchmarkFixture) -> None: - md_base: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_delitem_str( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md_base = any_multidict_class((str(i), str(i)) for i in range(100)) items = [str(i) for i in range(100)] @benchmark @@ -217,8 +238,11 @@ def _run() -> None: del md[i] -def test_cimultidict_delitem_istr(benchmark: BenchmarkFixture) -> None: - md_base: CIMultiDict[istr] = CIMultiDict((istr(i), istr(i)) for i in range(100)) +def test_cimultidict_delitem_istr( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + md_base = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) items = [istr(i) for i in range(100)] @benchmark @@ -228,43 +252,58 @@ def _run() -> None: del md[i] -def test_multidict_getall_str_hit(benchmark: BenchmarkFixture) -> None: - md: MultiDict[str] = MultiDict(("all", str(i)) for i in range(100)) +def test_multidict_getall_str_hit( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class((f"key{j}", str(f"{i}-{j}")) + for i in range(20) for j in range(5)) @benchmark def _run() -> None: - md.getall("all") + md.getall("key0") -def test_cimultidict_getall_str_hit(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict(("all", str(i)) for i in range(100)) +def test_multidict_getall_str_miss( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class((f"key{j}", str(f"{i}-{j}")) + for i in range(20) for j in range(5)) @benchmark def _run() -> None: - md.getall("all") + md.getall("miss", ()) -def test_cimultidict_getall_istr_hit(benchmark: BenchmarkFixture) -> None: - all_istr = istr("all") - md: CIMultiDict[istr] = CIMultiDict((all_istr, istr(i)) for i in range(100)) +def test_cimultidict_getall_istr_hit( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + all_istr = istr("key0") + md = case_insensitive_multidict_class((f"key{j}", istr(f"{i}-{j}")) + for i in range(20) for j in range(5)) @benchmark def _run() -> None: md.getall(all_istr) -def test_multidict_fetch(benchmark: BenchmarkFixture) -> None: - md: MultiDict[str] = MultiDict((str(i), str(i)) for i in range(100)) - items = [str(i) for i in range(100)] +def test_cimultidict_getall_istr_miss( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + miss_istr = istr("miss") + md = case_insensitive_multidict_class((istr(f"key{j}"), istr(f"{i}-{j}")) + for i in range(20) for j in range(5)) @benchmark def _run() -> None: - for i in items: - md[i] + md.getall(miss_istr, ()) -def test_cimultidict_fetch_str(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_fetch( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class((str(i), str(i)) for i in range(100)) items = [str(i) for i in range(100)] @benchmark @@ -273,8 +312,11 @@ def _run() -> None: md[i] -def test_cimultidict_fetch_istr(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[istr] = CIMultiDict((istr(i), istr(i)) for i in range(100)) +def test_cimultidict_fetch_istr( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) items = [istr(i) for i in range(100)] @benchmark @@ -283,8 +325,10 @@ def _run() -> None: md[i] -def test_multidict_get_hit(benchmark: BenchmarkFixture) -> None: - md: MultiDict[str] = MultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_get_hit( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class((str(i), str(i)) for i in range(100)) items = [str(i) for i in range(100)] @benchmark @@ -293,8 +337,10 @@ def _run() -> None: md.get(i) -def test_multidict_get_miss(benchmark: BenchmarkFixture) -> None: - md: MultiDict[str] = MultiDict((str(i), str(i)) for i in range(100)) +def test_multidict_get_miss( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class((str(i), str(i)) for i in range(100)) items = [str(i) for i in range(100, 200)] @benchmark @@ -303,9 +349,12 @@ def _run() -> None: md.get(i) -def test_cimultidict_get_hit(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) - items = [str(i) for i in range(100)] +def test_cimultidict_get_istr_hit( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) + items = [istr(i) for i in range(100)] @benchmark def _run() -> None: @@ -313,9 +362,12 @@ def _run() -> None: md.get(i) -def test_cimultidict_get_miss(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) - items = [str(i) for i in range(100, 200)] +def test_cimultidict_get_istr_miss( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) + items = [istr(i) for i in range(100, 200)] @benchmark def _run() -> None: @@ -323,31 +375,37 @@ def _run() -> None: md.get(i) -def test_cimultidict_get_istr_hit(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[istr] = CIMultiDict((istr(i), istr(i)) for i in range(100)) - items = [istr(i) for i in range(100)] +def test_multidict_get_hit_with_default( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md = any_multidict_class((str(i), str(i)) for i in range(100)) + items = [str(i) for i in range(100)] @benchmark def _run() -> None: for i in items: - md.get(i) + md.get(i, _SENTINEL) -def test_cimultidict_get_istr_miss(benchmark: BenchmarkFixture) -> None: - md: CIMultiDict[istr] = CIMultiDict((istr(i), istr(i)) for i in range(100)) - items = [istr(i) for i in range(100, 200)] +def test_cimultidict_get_istr_hit_with_default( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) + items = [istr(i) for i in range(100)] @benchmark def _run() -> None: for i in items: - md.get(i) + md.get(i, _SENTINEL) -def test_cimultidict_get_hit_with_default( +def test_cimultidict_get_istr_with_default_miss( benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], ) -> None: - md: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) - items = [str(i) for i in range(100)] + md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100)) + items = [istr(i) for i in range(100, 200)] @benchmark def _run() -> None: @@ -355,37 +413,193 @@ def _run() -> None: md.get(i, _SENTINEL) -def test_cimultidict_get_miss_with_default( +def test_multidict_repr( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + items = [str(i) for i in range(100)] + md = any_multidict_class([(i, i) for i in items]) + + @benchmark + def _run() -> None: + repr(md) + + +def test_create_empty_multidict( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + @benchmark + def _run() -> None: + any_multidict_class() + + +def test_create_multidict_with_items( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + items = [(str(i), str(i)) for i in range(100)] + + @benchmark + def _run() -> None: + any_multidict_class(items) + + +def test_create_cimultidict_with_items_istr( benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], ) -> None: - md: CIMultiDict[str] = CIMultiDict((str(i), str(i)) for i in range(100)) - items = [str(i) for i in range(100, 200)] + items = [(istr(i), istr(i)) for i in range(100)] @benchmark def _run() -> None: - for i in items: - md.get(i, _SENTINEL) + case_insensitive_multidict_class(items) -def test_cimultidict_get_istr_hit_with_default( +def test_create_multidict_with_dict( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + dct = {str(i): str(i) for i in range(100)} + + @benchmark + def _run() -> None: + any_multidict_class(dct) + + +def test_create_cimultidict_with_dict_istr( benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], ) -> None: - md: CIMultiDict[istr] = CIMultiDict((istr(i), istr(i)) for i in range(100)) - items = [istr(i) for i in range(100)] + dct = {istr(i): istr(i) for i in range(100)} @benchmark def _run() -> None: - for i in items: - md.get(i, _SENTINEL) + case_insensitive_multidict_class(dct) -def test_cimultidict_get_istr_with_default_miss( +def test_create_multidict_with_items_with_kwargs( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + items = [(str(i), str(i)) for i in range(100)] + kwargs = {str(i): str(i) for i in range(100)} + + @benchmark + def _run() -> None: + any_multidict_class(items, **kwargs) + + +def test_create_cimultidict_with_items_istr_with_kwargs( benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], ) -> None: - md: CIMultiDict[istr] = CIMultiDict((istr(i), istr(i)) for i in range(100)) - items = [istr(i) for i in range(100, 200)] + items = [(istr(i), istr(i)) for i in range(100)] + kwargs = {str(i): istr(i) for i in range(100)} @benchmark def _run() -> None: - for i in items: - md.get(i, _SENTINEL) + case_insensitive_multidict_class(items, **kwargs) + + +def test_create_empty_multidictproxy(benchmark: BenchmarkFixture) -> None: + md: MultiDict[str] = MultiDict() + + @benchmark + def _run() -> None: + MultiDictProxy(md) + + +def test_create_multidictproxy(benchmark: BenchmarkFixture) -> None: + items = [(str(i), str(i)) for i in range(100)] + md: MultiDict[str] = MultiDict(items) + + @benchmark + def _run() -> None: + MultiDictProxy(md) + + +def test_create_empty_cimultidictproxy( + benchmark: BenchmarkFixture, +) -> None: + md: CIMultiDict[istr] = CIMultiDict() + + @benchmark + def _run() -> None: + CIMultiDictProxy(md) + + +def test_create_cimultidictproxy( + benchmark: BenchmarkFixture, +) -> None: + items = [(istr(i), istr(i)) for i in range(100)] + md = CIMultiDict(items) + + @benchmark + def _run() -> None: + CIMultiDictProxy(md) + + +def test_create_from_existing_cimultidict( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + existing = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(5)) + + @benchmark + def _run() -> None: + case_insensitive_multidict_class(existing) + + +def test_copy_from_existing_cimultidict( + benchmark: BenchmarkFixture, + case_insensitive_multidict_class: Type[CIMultiDict[istr]], +) -> None: + existing = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(5)) + + @benchmark + def _run() -> None: + existing.copy() + + +def test_iterate_multidict( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + items = [(str(i), str(i)) for i in range(100)] + md = any_multidict_class(items) + + @benchmark + def _run() -> None: + for _ in md: + pass + + +def test_iterate_multidict_keys( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + items = [(str(i), str(i)) for i in range(100)] + md = any_multidict_class(items) + + @benchmark + def _run() -> None: + for _ in md.keys(): + pass + + +def test_iterate_multidict_values( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + items = [(str(i), str(i)) for i in range(100)] + md = any_multidict_class(items) + + @benchmark + def _run() -> None: + for _ in md.values(): + pass + + +def test_iterate_multidict_items( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + items = [(str(i), str(i)) for i in range(100)] + md = any_multidict_class(items) + + @benchmark + def _run() -> None: + for _, _ in md.items(): + pass diff --git a/contrib/python/multidict/tests/test_mutable_multidict.py b/contrib/python/multidict/tests/test_mutable_multidict.py index 45f1cdf5f67d..085999fb21c0 100644 --- a/contrib/python/multidict/tests/test_mutable_multidict.py +++ b/contrib/python/multidict/tests/test_mutable_multidict.py @@ -158,8 +158,8 @@ def test_popitem( d.add("key", "val1") d.add("key", "val2") - assert ("key", "val1") == d.popitem() - assert [("key", "val2")] == list(d.items()) + assert ("key", "val2") == d.popitem() + assert [("key", "val1")] == list(d.items()) def test_popitem_empty_multidict( self, @@ -318,6 +318,38 @@ def test_large_multidict_resizing( assert {"key" + str(SIZE - 1): SIZE - 1} == d + def test_update( + self, + case_sensitive_multidict_class: type[CIMultiDict[Union[str, int]]], + ) -> None: + d = case_sensitive_multidict_class() + assert d == {} + + d.update([("key", "one"), ("key", "two")], key=3, foo="bar") + assert d != {"key": "one", "foo": "bar"} + assert 4 == len(d) + itms = d.items() + # we can't guarantee order of kwargs + assert ("key", "one") in itms + assert ("key", "two") in itms + assert ("key", 3) in itms + assert ("foo", "bar") in itms + + other = case_sensitive_multidict_class(bar="baz") + assert other == {"bar": "baz"} + + d.update(other) + assert ("bar", "baz") in d.items() + + d.update({"foo": "moo"}) + assert ("foo", "moo") in d.items() + + d.update() + assert 5 == len(d) + + with pytest.raises(TypeError): + d.update("foo", "bar") # type: ignore[arg-type, call-arg] + class TestCIMutableMultiDict: def test_getall( @@ -514,9 +546,9 @@ def test_popitem( d.add("key", "val2") pair = d.popitem() - assert ("KEY", "val1") == pair + assert ("key", "val2") == pair assert isinstance(pair[0], str) - assert [("key", "val2")] == list(d.items()) + assert [("KEY", "val1")] == list(d.items()) def test_popitem_empty_multidict( self, @@ -658,3 +690,28 @@ def test_issue_620_values( d["c"] = "000" # This causes an error on pypy. list(before_mutation_values) + + def test_keys_type( + self, + case_insensitive_multidict_class: type[CIMultiDict[str]], + case_insensitive_str_class: type[istr], + ) -> None: + d = case_insensitive_multidict_class( + [ + ("KEY", "one"), + ] + ) + d["k2"] = "2" + d.extend(k3="3") + + for k in d: + assert type(k) is case_insensitive_str_class + + for k in d.keys(): + assert type(k) is case_insensitive_str_class + + for k, v in d.items(): + assert type(k) is case_insensitive_str_class + + k, v = d.popitem() + assert type(k) is case_insensitive_str_class diff --git a/contrib/python/multidict/tests/test_pickle.py b/contrib/python/multidict/tests/test_pickle.py index 3159ea45c647..08b85b21f99c 100644 --- a/contrib/python/multidict/tests/test_pickle.py +++ b/contrib/python/multidict/tests/test_pickle.py @@ -4,7 +4,7 @@ import pytest -from multidict import MultiDict, MultiDictProxy +from multidict import MultiDict, MultiDictProxy, istr if TYPE_CHECKING: from conftest import MultidictImplementation @@ -33,6 +33,16 @@ def test_pickle_proxy( pickle.dumps(proxy) +def test_pickle_istr( + case_insensitive_str_class: type[istr], pickle_protocol: int +) -> None: + s = case_insensitive_str_class("str") + pbytes = pickle.dumps(s, pickle_protocol) + obj = pickle.loads(pbytes) + assert s == obj + assert isinstance(obj, case_insensitive_str_class) + + def test_load_from_file( any_multidict_class: type[MultiDict[int]], multidict_implementation: "MultidictImplementation", @@ -52,3 +62,24 @@ def test_load_from_file( obj = pickle.load(f) assert d == obj assert isinstance(obj, any_multidict_class) + + +def test_load_istr_from_file( + case_insensitive_str_class: type[istr], + multidict_implementation: "MultidictImplementation", + pickle_protocol: int, +) -> None: + istr_class_name = case_insensitive_str_class.__name__ + pickle_file_basename = "-".join( + ( + istr_class_name.lower(), + multidict_implementation.tag, + ) + ) + s = case_insensitive_str_class("str") + fname = f"{pickle_file_basename}.pickle.{pickle_protocol}" + p = here / fname + with p.open("rb") as f: + obj = pickle.load(f) + assert s == obj + assert isinstance(obj, case_insensitive_str_class) diff --git a/contrib/python/multidict/tests/test_views_benchmarks.py b/contrib/python/multidict/tests/test_views_benchmarks.py new file mode 100644 index 000000000000..7f1b9fff995a --- /dev/null +++ b/contrib/python/multidict/tests/test_views_benchmarks.py @@ -0,0 +1,279 @@ +"""codspeed benchmarks for multidict views.""" + +from typing import Type + +from pytest_codspeed import BenchmarkFixture + +from multidict import MultiDict + + +def test_keys_view_equals( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + + @benchmark + def _run() -> None: + assert md1.keys() == md2.keys() + + +def test_keys_view_not_equals( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(20, 120)}) + + @benchmark + def _run() -> None: + assert md1.keys() != md2.keys() + + +def test_keys_view_more( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + s = {str(i) for i in range(50)} + + @benchmark + def _run() -> None: + assert md.keys() > s + + +def test_keys_view_more_or_equal( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + s = {str(i) for i in range(100)} + + @benchmark + def _run() -> None: + assert md.keys() >= s + + +def test_keys_view_less( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + s = {str(i) for i in range(150)} + + @benchmark + def _run() -> None: + assert md.keys() < s + + +def test_keys_view_less_or_equal( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + s = {str(i) for i in range(100)} + + @benchmark + def _run() -> None: + assert md.keys() <= s + + +def test_keys_view_and( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)}) + + @benchmark + def _run() -> None: + assert len(md1.keys() & md2.keys()) == 50 + + +def test_keys_view_or( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)}) + + @benchmark + def _run() -> None: + assert len(md1.keys() | md2.keys()) == 150 + + +def test_keys_view_sub( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)}) + + @benchmark + def _run() -> None: + assert len(md1.keys() - md2.keys()) == 50 + + +def test_keys_view_xor( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)}) + + @benchmark + def _run() -> None: + assert len(md1.keys() ^ md2.keys()) == 100 + + +def test_keys_view_is_disjoint( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100, 200)}) + + @benchmark + def _run() -> None: + assert md1.keys().isdisjoint(md2.keys()) + + +def test_keys_view_repr( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + + @benchmark + def _run() -> None: + repr(md.keys()) + + +def test_items_view_equals( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + + @benchmark + def _run() -> None: + assert md1.items() == md2.items() + + +def test_items_view_not_equals( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(20, 120)}) + + @benchmark + def _run() -> None: + assert md1.items() != md2.items() + + +def test_items_view_more( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + s = {(str(i), str(i)) for i in range(50)} + + @benchmark + def _run() -> None: + assert md.items() > s + + +def test_items_view_more_or_equal( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + s = {(str(i), str(i)) for i in range(100)} + + @benchmark + def _run() -> None: + assert md.items() >= s + + +def test_items_view_less( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + s = {(str(i), str(i)) for i in range(150)} + + @benchmark + def _run() -> None: + assert md.items() < s + + +def test_items_view_less_or_equal( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + s = {(str(i), str(i)) for i in range(100)} + + @benchmark + def _run() -> None: + assert md.items() <= s + + +def test_items_view_and( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)}) + + @benchmark + def _run() -> None: + assert len(md1.items() & md2.items()) == 50 + + +def test_items_view_or( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)}) + + @benchmark + def _run() -> None: + assert len(md1.items() | md2.items()) == 150 + + +def test_items_view_sub( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)}) + + @benchmark + def _run() -> None: + assert len(md1.items() - md2.items()) == 50 + + +def test_items_view_xor( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)}) + + @benchmark + def _run() -> None: + assert len(md1.items() ^ md2.items()) == 100 + + +def test_items_view_is_disjoint( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100, 200)}) + + @benchmark + def _run() -> None: + assert md1.items().isdisjoint(md2.items()) + + +def test_items_view_repr( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + + @benchmark + def _run() -> None: + repr(md.items()) + + +def test_values_view_repr( + benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]] +) -> None: + md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)}) + + @benchmark + def _run() -> None: + repr(md.values()) diff --git a/contrib/python/multidict/ya.make b/contrib/python/multidict/ya.make index 626036249b8f..ad0d3d0777c9 100644 --- a/contrib/python/multidict/ya.make +++ b/contrib/python/multidict/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(6.2.0) +VERSION(6.4.3) LICENSE(Apache-2.0) @@ -27,7 +27,6 @@ PY_SRCS( multidict/__init__.py multidict/_abc.py multidict/_compat.py - multidict/_multidict_base.py multidict/_multidict_py.py ) diff --git a/contrib/python/pyasn1-modules/py3/.dist-info/METADATA b/contrib/python/pyasn1-modules/py3/.dist-info/METADATA index 40fc8b89b307..55fc9058fb77 100644 --- a/contrib/python/pyasn1-modules/py3/.dist-info/METADATA +++ b/contrib/python/pyasn1-modules/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.4 Name: pyasn1_modules -Version: 0.4.1 +Version: 0.4.2 Summary: A collection of ASN.1-based protocols modules Home-page: https://github.com/pyasn1/pyasn1-modules Author: Ilya Etingof @@ -36,7 +36,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.8 Description-Content-Type: text/markdown License-File: LICENSE.txt -Requires-Dist: pyasn1 <0.7.0,>=0.4.6 +Requires-Dist: pyasn1<0.7.0,>=0.6.1 +Dynamic: license-file ASN.1 modules for Python diff --git a/contrib/python/pyasn1-modules/py3/patches/01-pr22-stop-using-pyasn1-compat-octets.patch b/contrib/python/pyasn1-modules/py3/patches/01-pr22-stop-using-pyasn1-compat-octets.patch deleted file mode 100644 index 979e5f8d9c78..000000000000 --- a/contrib/python/pyasn1-modules/py3/patches/01-pr22-stop-using-pyasn1-compat-octets.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 079c176eb00ed7352c9696efa12a0577beeecd71 Mon Sep 17 00:00:00 2001 -From: Heiko Becker -Date: Wed, 25 Sep 2024 22:38:42 +0200 -Subject: [PATCH] Stop using pyasn1.compat.octets - -It was removed from pyasn1 in -https://github.com/pyasn1/pyasn1/commit/6f770ba886a8931c35cb090a5c3a6d67f5a41bd9 - -Fixes #19. ---- - tests/test_pem.py | 3 +-- - tests/test_rfc3770.py | 3 +-- - tests/test_rfc4073.py | 3 +-- - tests/test_rfc4334.py | 3 +-- - tests/test_rfc5755.py | 3 +-- - tests/test_rfc6032.py | 7 +++---- - tests/test_rfc6120.py | 1 - - 7 files changed, 8 insertions(+), 15 deletions(-) - -diff --git a/tests/test_pem.py b/tests/test_pem.py -index dbcca5a7..e0fe334d 100644 ---- a/tests/test_pem.py -+++ b/tests/test_pem.py -@@ -7,7 +7,6 @@ - import sys - import unittest - --from pyasn1.compat.octets import ints2octs - from pyasn1_modules import pem - - -@@ -93,7 +92,7 @@ def testReadBase64fromText(self): - 24, 102, 241, 236, 50 - ] - -- self.assertEqual(ints2octs(expected), binary) -+ self.assertEqual(bytes(expected), binary) - - - suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) -diff --git a/tests/test_rfc3770.py b/tests/test_rfc3770.py -index 667ab249..93d40932 100644 ---- a/tests/test_rfc3770.py -+++ b/tests/test_rfc3770.py -@@ -10,7 +10,6 @@ - - from pyasn1.codec.der.decoder import decode as der_decoder - from pyasn1.codec.der.encoder import encode as der_encoder --from pyasn1.compat.octets import str2octs - - from pyasn1_modules import pem - from pyasn1_modules import rfc5480 -@@ -79,7 +78,7 @@ def testOpenTypes(self): - self.assertEqual(extn['extnValue'], der_encoder(extnValue)) - - if extn['extnID'] == rfc3770.id_pe_wlanSSID: -- self.assertIn(str2octs('Example'), extnValue) -+ self.assertIn(b'Example', extnValue) - - if extn['extnID'] == rfc5280.id_ce_extKeyUsage: - self.assertIn(rfc3770.id_kp_eapOverLAN, extnValue) -diff --git a/tests/test_rfc4073.py b/tests/test_rfc4073.py -index 4bd5e5f7..3b516ccb 100644 ---- a/tests/test_rfc4073.py -+++ b/tests/test_rfc4073.py -@@ -10,7 +10,6 @@ - - from pyasn1.codec.der.decoder import decode as der_decoder - from pyasn1.codec.der.encoder import encode as der_encoder --from pyasn1.compat.octets import str2octs - - from pyasn1_modules import pem - from pyasn1_modules import rfc2634 -@@ -131,7 +130,7 @@ def testOpenTypes(self): - - self.assertIn(next_ci['contentType'], rfc5652.cmsContentTypesMap) - self.assertEqual(rfc5652.id_data, next_ci['contentType']) -- self.assertIn(str2octs('Content-Type: text'), next_ci['content']) -+ self.assertIn(b'Content-Type: text', next_ci['content']) - - for attr in ci['content']['attrs']: - self.assertIn(attr['attrType'], rfc5652.cmsAttributesMap) -diff --git a/tests/test_rfc4334.py b/tests/test_rfc4334.py -index 9ba5fdf3..e180d676 100644 ---- a/tests/test_rfc4334.py -+++ b/tests/test_rfc4334.py -@@ -10,7 +10,6 @@ - - from pyasn1.codec.der.decoder import decode as der_decoder - from pyasn1.codec.der.encoder import encode as der_encoder --from pyasn1.compat.octets import str2octs - - from pyasn1_modules import pem - from pyasn1_modules import rfc5280 -@@ -67,7 +66,7 @@ def testOpenTypes(self): - self.assertEqual(extn['extnValue'], der_encoder(extnValue)) - - if extn['extnID'] == rfc4334.id_pe_wlanSSID: -- self.assertIn( str2octs('Example'), extnValue) -+ self.assertIn(b'Example', extnValue) - - if extn['extnID'] == rfc5280.id_ce_extKeyUsage: - self.assertIn(rfc4334.id_kp_eapOverLAN, extnValue) -diff --git a/tests/test_rfc5755.py b/tests/test_rfc5755.py -index cf4a05fa..46908e23 100644 ---- a/tests/test_rfc5755.py -+++ b/tests/test_rfc5755.py -@@ -10,7 +10,6 @@ - - from pyasn1.codec.der.decoder import decode as der_decoder - from pyasn1.codec.der.encoder import encode as der_encoder --from pyasn1.compat.octets import str2octs - - from pyasn1_modules import pem - from pyasn1_modules import rfc5280 -@@ -85,7 +84,7 @@ def testOpenTypes(self): - count += 1 - if attr['type'] == rfc5755.id_aca_authenticationInfo: - self.assertEqual( -- str2octs('password'), attr['values'][0]['authInfo']) -+ b'password', attr['values'][0]['authInfo']) - - self.assertEqual(5, count) - -diff --git a/tests/test_rfc6032.py b/tests/test_rfc6032.py -index 287bad89..2327416d 100644 ---- a/tests/test_rfc6032.py -+++ b/tests/test_rfc6032.py -@@ -10,7 +10,6 @@ - - from pyasn1.codec.der.decoder import decode as der_decoder - from pyasn1.codec.der.encoder import encode as der_encoder --from pyasn1.compat.octets import str2octs - - from pyasn1_modules import pem - from pyasn1_modules import rfc5652 -@@ -64,7 +63,7 @@ def testDerCodec(self): - self.assertFalse(rest) - self.assertTrue(keyid.prettyPrint()) - self.assertEqual(attrVal0, der_encoder(keyid)) -- self.assertEqual(str2octs('ptf-kdc-812374'), keyid) -+ self.assertEqual(b'ptf-kdc-812374', keyid) - - def testOpenTypes(self): - substrate = pem.readBase64fromText(self.encrypted_key_pkg_pem_text) -@@ -86,8 +85,8 @@ def testOpenTypes(self): - self.assertNotEqual('0x', attr['attrValues'][0].prettyPrint()[:2]) - - if attr['attrType'] == rfc6032.id_aa_KP_contentDecryptKeyID: -- self.assertEqual(str2octs( -- 'ptf-kdc-812374'), attr['attrValues'][0]) -+ self.assertEqual( -+ b'ptf-kdc-812374', attr['attrValues'][0]) - - - suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) -diff --git a/tests/test_rfc6120.py b/tests/test_rfc6120.py -index bdedab8c..a6217454 100644 ---- a/tests/test_rfc6120.py -+++ b/tests/test_rfc6120.py -@@ -10,7 +10,6 @@ - - from pyasn1.codec.der.decoder import decode as der_decoder - from pyasn1.codec.der.encoder import encode as der_encoder --from pyasn1.compat.octets import str2octs - - from pyasn1_modules import pem - from pyasn1_modules import rfc5280 diff --git a/contrib/python/pyasn1-modules/py3/pyasn1_modules/__init__.py b/contrib/python/pyasn1-modules/py3/pyasn1_modules/__init__.py index ae0ff01d7be7..5b90010d7a08 100644 --- a/contrib/python/pyasn1-modules/py3/pyasn1_modules/__init__.py +++ b/contrib/python/pyasn1-modules/py3/pyasn1_modules/__init__.py @@ -1,2 +1,2 @@ # http://www.python.org/dev/peps/pep-0396/ -__version__ = '0.4.1' +__version__ = '0.4.2' diff --git a/contrib/python/pyasn1-modules/py3/ya.make b/contrib/python/pyasn1-modules/py3/ya.make index d244d3e2d2f7..71e3e2c0eef2 100644 --- a/contrib/python/pyasn1-modules/py3/ya.make +++ b/contrib/python/pyasn1-modules/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(0.4.1) +VERSION(0.4.2) LICENSE(BSD-2-Clause) diff --git a/contrib/python/pyparsing/py3/.dist-info/METADATA b/contrib/python/pyparsing/py3/.dist-info/METADATA index 6b5fbefef606..d03671b61301 100644 --- a/contrib/python/pyparsing/py3/.dist-info/METADATA +++ b/contrib/python/pyparsing/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pyparsing -Version: 3.2.1 +Version: 3.2.3 Summary: pyparsing module - Classes and methods to define and execute parsing grammars Author-email: Paul McGuire Requires-Python: >=3.9 @@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy @@ -56,7 +57,7 @@ Here is a program to parse ``"Hello, World!"`` (or any greeting of the form from pyparsing import Word, alphas greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" - print(hello, "->", greet.parseString(hello)) + print(hello, "->", greet.parse_string(hello)) The program outputs the following:: @@ -66,7 +67,7 @@ The Python representation of the grammar is quite readable, owing to the self-explanatory class names, and the use of '+', '|' and '^' operator definitions. -The parsed results returned from ``parseString()`` is a collection of type +The parsed results returned from ``parse_string()`` is a collection of type ``ParseResults``, which can be accessed as a nested list, a dictionary, or an object with named attributes. diff --git a/contrib/python/pyparsing/py3/README.rst b/contrib/python/pyparsing/py3/README.rst index 24d603c7bc40..cfb9889f8540 100644 --- a/contrib/python/pyparsing/py3/README.rst +++ b/contrib/python/pyparsing/py3/README.rst @@ -26,7 +26,7 @@ Here is a program to parse ``"Hello, World!"`` (or any greeting of the form from pyparsing import Word, alphas greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" - print(hello, "->", greet.parseString(hello)) + print(hello, "->", greet.parse_string(hello)) The program outputs the following:: @@ -36,7 +36,7 @@ The Python representation of the grammar is quite readable, owing to the self-explanatory class names, and the use of '+', '|' and '^' operator definitions. -The parsed results returned from ``parseString()`` is a collection of type +The parsed results returned from ``parse_string()`` is a collection of type ``ParseResults``, which can be accessed as a nested list, a dictionary, or an object with named attributes. diff --git a/contrib/python/pyparsing/py3/pyparsing/__init__.py b/contrib/python/pyparsing/py3/pyparsing/__init__.py index 726c76cb2449..d839fd253756 100644 --- a/contrib/python/pyparsing/py3/pyparsing/__init__.py +++ b/contrib/python/pyparsing/py3/pyparsing/__init__.py @@ -120,8 +120,8 @@ def __repr__(self): return f"{__name__}.{type(self).__name__}({', '.join('{}={!r}'.format(*nv) for nv in zip(self._fields, self))})" -__version_info__ = version_info(3, 2, 1, "final", 1) -__version_time__ = "31 Dec 2024 20:41 UTC" +__version_info__ = version_info(3, 2, 3, "final", 1) +__version_time__ = "25 Mar 2025 01:38 UTC" __version__ = __version_info__.__version__ __versionTime__ = __version_time__ __author__ = "Paul McGuire " diff --git a/contrib/python/pyparsing/py3/pyparsing/actions.py b/contrib/python/pyparsing/py3/pyparsing/actions.py index f491aab986e9..0153cc7132ab 100644 --- a/contrib/python/pyparsing/py3/pyparsing/actions.py +++ b/contrib/python/pyparsing/py3/pyparsing/actions.py @@ -22,7 +22,7 @@ class OnlyOnce: Note: parse action signature must include all 3 arguments. """ - def __init__(self, method_call: Callable[[str, int, ParseResults], Any]): + def __init__(self, method_call: Callable[[str, int, ParseResults], Any]) -> None: from .core import _trim_arity self.callable = _trim_arity(method_call) diff --git a/contrib/python/pyparsing/py3/pyparsing/core.py b/contrib/python/pyparsing/py3/pyparsing/core.py index b884e2d4a40b..86be949ad473 100644 --- a/contrib/python/pyparsing/py3/pyparsing/core.py +++ b/contrib/python/pyparsing/py3/pyparsing/core.py @@ -38,7 +38,6 @@ __config_flags, _collapse_string_to_ranges, _escape_regex_range_chars, - _bslash, _flatten, LRUMemo as _LRUMemo, UnboundedMemo as _UnboundedMemo, @@ -246,7 +245,7 @@ class _ParseActionIndexError(Exception): ParserElement parseImpl methods. """ - def __init__(self, msg: str, exc: BaseException): + def __init__(self, msg: str, exc: BaseException) -> None: self.msg: str = msg self.exc: BaseException = exc @@ -355,7 +354,7 @@ def _default_start_debug_action( ( f"{cache_hit_str}Match {expr} at loc {loc}({lineno(loc, instring)},{col(loc, instring)})\n" f" {line(loc, instring)}\n" - f" {' ' * (col(loc, instring) - 1)}^" + f" {'^':>{col(loc, instring)}}" ) ) @@ -454,7 +453,7 @@ class DebugActions(NamedTuple): debug_match: typing.Optional[DebugSuccessAction] debug_fail: typing.Optional[DebugExceptionAction] - def __init__(self, savelist: bool = False): + def __init__(self, savelist: bool = False) -> None: self.parseAction: list[ParseAction] = list() self.failAction: typing.Optional[ParseFailAction] = None self.customName: str = None # type: ignore[assignment] @@ -465,7 +464,7 @@ def __init__(self, savelist: bool = False): self.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS) self.copyDefaultWhiteChars = True # used when checking for left-recursion - self.mayReturnEmpty = False + self._may_return_empty = False self.keepTabs = False self.ignoreExprs: list[ParserElement] = list() self.debug = False @@ -483,6 +482,14 @@ def __init__(self, savelist: bool = False): self.suppress_warnings_: list[Diagnostics] = [] self.show_in_diagram = True + @property + def mayReturnEmpty(self): + return self._may_return_empty + + @mayReturnEmpty.setter + def mayReturnEmpty(self, value): + self._may_return_empty = value + def suppress_warning(self, warning_type: Diagnostics) -> ParserElement: """ Suppress warnings emitted for a particular diagnostic on this expression. @@ -2264,6 +2271,7 @@ def create_diagram( show_results_names: bool = False, show_groups: bool = False, embed: bool = False, + show_hidden: bool = False, **kwargs, ) -> None: """ @@ -2278,6 +2286,7 @@ def create_diagram( - ``show_results_names`` - bool flag whether diagram should show annotations for defined results names - ``show_groups`` - bool flag whether groups should be highlighted with an unlabeled surrounding box + - ``show_hidden`` - bool flag to show diagram elements for internal elements that are usually hidden - ``embed`` - bool flag whether generated HTML should omit , , and tags to embed the resulting HTML in an enclosing HTML source - ``head`` - str containing additional HTML to insert into the section of the generated code; @@ -2303,6 +2312,7 @@ def create_diagram( vertical=vertical, show_results_names=show_results_names, show_groups=show_groups, + show_hidden=show_hidden, diagram_kwargs=kwargs, ) if not isinstance(output_html, (str, Path)): @@ -2352,7 +2362,7 @@ def create_diagram( class _PendingSkip(ParserElement): # internal placeholder class to hold a place were '...' is added to a parser element, # once another ParserElement is added, this placeholder will be replaced with a SkipTo - def __init__(self, expr: ParserElement, must_skip: bool = False): + def __init__(self, expr: ParserElement, must_skip: bool = False) -> None: super().__init__() self.anchor = expr self.must_skip = must_skip @@ -2395,7 +2405,7 @@ class Token(ParserElement): matching patterns. """ - def __init__(self): + def __init__(self) -> None: super().__init__(savelist=False) def _generateDefaultName(self) -> str: @@ -2407,9 +2417,9 @@ class NoMatch(Token): A token that will never match. """ - def __init__(self): + def __init__(self) -> None: super().__init__() - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False self.errmsg = "Unmatchable token" @@ -2449,14 +2459,14 @@ def __new__(cls, match_string: str = "", *, matchString: str = ""): def __getnewargs__(self): return (self.match,) - def __init__(self, match_string: str = "", *, matchString: str = ""): + def __init__(self, match_string: str = "", *, matchString: str = "") -> None: super().__init__() match_string = matchString or match_string self.match = match_string self.matchLen = len(match_string) self.firstMatchChar = match_string[:1] self.errmsg = f"Expected {self.name}" - self.mayReturnEmpty = False + self._may_return_empty = False self.mayIndexError = False def _generateDefaultName(self) -> str: @@ -2475,9 +2485,9 @@ class Empty(Literal): An empty token, will always match. """ - def __init__(self, match_string="", *, matchString=""): + def __init__(self, match_string="", *, matchString="") -> None: super().__init__("") - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False def _generateDefaultName(self) -> str: @@ -2534,7 +2544,7 @@ def __init__( *, matchString: str = "", identChars: typing.Optional[str] = None, - ): + ) -> None: super().__init__() identChars = identChars or ident_chars if identChars is None: @@ -2546,7 +2556,7 @@ def __init__( if not self.firstMatchChar: raise ValueError("null string passed to Keyword; use Empty() instead") self.errmsg = f"Expected {type(self).__name__} {self.name}" - self.mayReturnEmpty = False + self._may_return_empty = False self.mayIndexError = False self.caseless = caseless if caseless: @@ -2628,7 +2638,7 @@ class CaselessLiteral(Literal): (Contrast with example for :class:`CaselessKeyword`.) """ - def __init__(self, match_string: str = "", *, matchString: str = ""): + def __init__(self, match_string: str = "", *, matchString: str = "") -> None: match_string = matchString or match_string super().__init__(match_string.upper()) # Preserve the defining literal. @@ -2660,7 +2670,7 @@ def __init__( *, matchString: str = "", identChars: typing.Optional[str] = None, - ): + ) -> None: identChars = identChars or ident_chars match_string = matchString or match_string super().__init__(match_string, identChars, caseless=True) @@ -2708,7 +2718,7 @@ def __init__( *, maxMismatches: int = 1, caseless=False, - ): + ) -> None: maxMismatches = max_mismatches if max_mismatches is not None else maxMismatches super().__init__() self.match_string = match_string @@ -2716,7 +2726,7 @@ def __init__( self.errmsg = f"Expected {self.match_string!r} (with up to {self.maxMismatches} mismatches)" self.caseless = caseless self.mayIndexError = False - self.mayReturnEmpty = False + self._may_return_empty = False def _generateDefaultName(self) -> str: return f"{type(self).__name__}:{self.match_string!r}" @@ -2834,7 +2844,7 @@ def __init__( bodyChars: typing.Optional[str] = None, asKeyword: bool = False, excludeChars: typing.Optional[str] = None, - ): + ) -> None: initChars = initChars or init_chars bodyChars = bodyChars or body_chars asKeyword = asKeyword or as_keyword @@ -3018,7 +3028,7 @@ def __init__( *, asKeyword: bool = False, excludeChars: typing.Optional[str] = None, - ): + ) -> None: asKeyword = asKeyword or as_keyword excludeChars = excludeChars or exclude_chars super().__init__( @@ -3060,7 +3070,7 @@ def __init__( *, asGroupList: bool = False, asMatch: bool = False, - ): + ) -> None: """The parameters ``pattern`` and ``flags`` are passed to the ``re.compile()`` function as-is. See the Python `re module `_ module for an @@ -3075,15 +3085,18 @@ def __init__( raise ValueError("null string passed to Regex; use Empty() instead") self._re = None + self._may_return_empty = None # type: ignore [assignment] self.reString = self.pattern = pattern elif hasattr(pattern, "pattern") and hasattr(pattern, "match"): self._re = pattern + self._may_return_empty = None # type: ignore [assignment] self.pattern = self.reString = pattern.pattern elif callable(pattern): # defer creating this pattern until we really need it self.pattern = pattern + self._may_return_empty = None # type: ignore [assignment] self._re = None else: @@ -3120,23 +3133,38 @@ def re(self) -> re.Pattern: try: self._re = re.compile(self.pattern, self.flags) - return self._re except re.error: raise ValueError(f"invalid pattern ({self.pattern!r}) passed to Regex") + else: + self._may_return_empty = self.re.match("", pos=0) is not None + return self._re @cached_property def re_match(self) -> Callable[[str, int], Any]: return self.re.match - @cached_property - def mayReturnEmpty(self) -> bool: # type: ignore[override] - return self.re_match("", 0) is not None + @property + def mayReturnEmpty(self): + if self._may_return_empty is None: + # force compile of regex pattern, to set may_return_empty flag + self.re # noqa + return self._may_return_empty + + @mayReturnEmpty.setter + def mayReturnEmpty(self, value): + self._may_return_empty = value def _generateDefaultName(self) -> str: unescaped = repr(self.pattern).replace("\\\\", "\\") return f"Re:({unescaped})" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: + # explicit check for matching past the length of the string; + # this is done because the re module will not complain about + # a match with `pos > len(instring)`, it will just return "" + if loc > len(instring) and self.mayReturnEmpty: + raise ParseException(instring, loc, self.errmsg, self) + result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3151,6 +3179,9 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: return loc, ret def parseImplAsGroupList(self, instring, loc, do_actions=True): + if loc > len(instring) and self.mayReturnEmpty: + raise ParseException(instring, loc, self.errmsg, self) + result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3160,6 +3191,9 @@ def parseImplAsGroupList(self, instring, loc, do_actions=True): return loc, ret def parseImplAsMatch(self, instring, loc, do_actions=True): + if loc > len(instring) and self.mayReturnEmpty: + raise ParseException(instring, loc, self.errmsg, self) + result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3258,7 +3292,7 @@ def __init__( unquoteResults: bool = True, endQuoteChar: typing.Optional[str] = None, convertWhitespaceEscapes: bool = True, - ): + ) -> None: super().__init__() esc_char = escChar or esc_char esc_quote = escQuote or esc_quote @@ -3362,7 +3396,7 @@ def __init__( self.errmsg = f"Expected {self.name}" self.mayIndexError = False - self.mayReturnEmpty = True + self._may_return_empty = True def _generateDefaultName(self) -> str: if self.quote_char == self.end_quote_char and isinstance( @@ -3465,7 +3499,7 @@ def __init__( exact: int = 0, *, notChars: str = "", - ): + ) -> None: super().__init__() self.skipWhitespace = False self.notChars = not_chars or notChars @@ -3489,7 +3523,7 @@ def __init__( self.minLen = exact self.errmsg = f"Expected {self.name}" - self.mayReturnEmpty = self.minLen == 0 + self._may_return_empty = self.minLen == 0 self.mayIndexError = False def _generateDefaultName(self) -> str: @@ -3552,7 +3586,9 @@ class White(Token): "\u3000": "", } - def __init__(self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = 0): + def __init__( + self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = 0 + ) -> None: super().__init__() self.matchWhite = ws self.set_whitespace_chars( @@ -3560,7 +3596,7 @@ def __init__(self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = copy_defaults=True, ) # self.leave_whitespace() - self.mayReturnEmpty = True + self._may_return_empty = True self.errmsg = f"Expected {self.name}" self.minLen = min @@ -3594,9 +3630,9 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: class PositionToken(Token): - def __init__(self): + def __init__(self) -> None: super().__init__() - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False @@ -3605,7 +3641,7 @@ class GoToColumn(PositionToken): tabular report scraping. """ - def __init__(self, colno: int): + def __init__(self, colno: int) -> None: super().__init__() self.col = colno @@ -3657,7 +3693,7 @@ class LineStart(PositionToken): """ - def __init__(self): + def __init__(self) -> None: super().__init__() self.leave_whitespace() self.orig_whiteChars = set() | self.whiteChars @@ -3688,7 +3724,7 @@ class LineEnd(PositionToken): parse string """ - def __init__(self): + def __init__(self) -> None: super().__init__() self.whiteChars.discard("\n") self.set_whitespace_chars(self.whiteChars, copy_defaults=False) @@ -3711,7 +3747,7 @@ class StringStart(PositionToken): string """ - def __init__(self): + def __init__(self) -> None: super().__init__() self.set_name("start of text") @@ -3728,7 +3764,7 @@ class StringEnd(PositionToken): Matches if current position is at the end of the parse string """ - def __init__(self): + def __init__(self) -> None: super().__init__() self.set_name("end of text") @@ -3753,7 +3789,9 @@ class WordStart(PositionToken): a line. """ - def __init__(self, word_chars: str = printables, *, wordChars: str = printables): + def __init__( + self, word_chars: str = printables, *, wordChars: str = printables + ) -> None: wordChars = word_chars if wordChars == printables else wordChars super().__init__() self.wordChars = set(wordChars) @@ -3778,7 +3816,9 @@ class WordEnd(PositionToken): of a line. """ - def __init__(self, word_chars: str = printables, *, wordChars: str = printables): + def __init__( + self, word_chars: str = printables, *, wordChars: str = printables + ) -> None: wordChars = word_chars if wordChars == printables else wordChars super().__init__() self.wordChars = set(wordChars) @@ -3822,14 +3862,15 @@ class Tag(Token): - enthusiastic: True """ - def __init__(self, tag_name: str, value: Any = True): + def __init__(self, tag_name: str, value: Any = True) -> None: super().__init__() - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False self.leave_whitespace() self.tag_name = tag_name self.tag_value = value self.add_parse_action(self._add_tag) + self.show_in_diagram = False def _add_tag(self, tokens: ParseResults): tokens[self.tag_name] = self.tag_value @@ -3843,7 +3884,9 @@ class ParseExpression(ParserElement): post-processing parsed tokens. """ - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): + def __init__( + self, exprs: typing.Iterable[ParserElement], savelist: bool = False + ) -> None: super().__init__(savelist) self.exprs: list[ParserElement] if isinstance(exprs, _generatorType): @@ -3939,7 +3982,7 @@ def streamline(self) -> ParserElement: ): self.exprs = other.exprs[:] + [self.exprs[1]] self._defaultName = None - self.mayReturnEmpty |= other.mayReturnEmpty + self._may_return_empty |= other.mayReturnEmpty self.mayIndexError |= other.mayIndexError other = self.exprs[-1] @@ -3951,7 +3994,7 @@ def streamline(self) -> ParserElement: ): self.exprs = self.exprs[:-1] + other.exprs[:] self._defaultName = None - self.mayReturnEmpty |= other.mayReturnEmpty + self._may_return_empty |= other.mayReturnEmpty self.mayIndexError |= other.mayIndexError self.errmsg = f"Expected {self}" @@ -4028,7 +4071,7 @@ class And(ParseExpression): """ class _ErrorStop(Empty): - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.leave_whitespace() @@ -4036,28 +4079,34 @@ def _generateDefaultName(self) -> str: return "-" def __init__( - self, exprs_arg: typing.Iterable[ParserElement], savelist: bool = True - ): - exprs: list[ParserElement] = list(exprs_arg) - if exprs and Ellipsis in exprs: - tmp: list[ParserElement] = [] - for i, expr in enumerate(exprs): - if expr is not Ellipsis: - tmp.append(expr) - continue + self, + exprs_arg: typing.Iterable[Union[ParserElement, str]], + savelist: bool = True, + ) -> None: + # instantiate exprs as a list, converting strs to ParserElements + exprs: list[ParserElement] = [ + self._literalStringClass(e) if isinstance(e, str) else e for e in exprs_arg + ] - if i < len(exprs) - 1: - skipto_arg: ParserElement = typing.cast( - ParseExpression, (Empty() + exprs[i + 1]) - ).exprs[-1] - tmp.append(SkipTo(skipto_arg)("_skipped*")) - continue + # convert any Ellipsis elements to SkipTo + if Ellipsis in exprs: + # Ellipsis cannot be the last element + if exprs[-1] is Ellipsis: raise Exception("cannot construct And with sequence ending in ...") - exprs[:] = tmp + + tmp: list[ParserElement] = [] + for cur_expr, next_expr in zip(exprs, exprs[1:]): + if cur_expr is Ellipsis: + tmp.append(SkipTo(next_expr)("_skipped*")) + else: + tmp.append(cur_expr) + + exprs[:-1] = tmp + super().__init__(exprs, savelist) if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) if not isinstance(self.exprs[0], White): self.set_whitespace_chars( self.exprs[0].whiteChars, @@ -4067,7 +4116,7 @@ def __init__( else: self.skipWhitespace = False else: - self.mayReturnEmpty = True + self._may_return_empty = True self.callPreparse = True def streamline(self) -> ParserElement: @@ -4117,7 +4166,7 @@ def streamline(self) -> ParserElement: break cur = typing.cast(ParserElement, next_first) - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) return self def parseImpl(self, instring, loc, do_actions=True): @@ -4189,18 +4238,20 @@ class Or(ParseExpression): [['123'], ['3.1416'], ['789']] """ - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): + def __init__( + self, exprs: typing.Iterable[ParserElement], savelist: bool = False + ) -> None: super().__init__(exprs, savelist) if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) else: - self.mayReturnEmpty = True + self._may_return_empty = True def streamline(self) -> ParserElement: super().streamline() if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.saveAsList = any(e.saveAsList for e in self.exprs) self.skipWhitespace = all( e.skipWhitespace and not isinstance(e, White) for e in self.exprs @@ -4286,7 +4337,8 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if maxException is not None: # infer from this check that all alternatives failed at the current position # so emit this collective error message instead of any single error message - if maxExcLoc == loc: + parse_start_loc = self.preParse(instring, loc) + if maxExcLoc == parse_start_loc: maxException.msg = self.errmsg or "" raise maxException @@ -4344,13 +4396,15 @@ class MatchFirst(ParseExpression): print(number.search_string("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] """ - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): + def __init__( + self, exprs: typing.Iterable[ParserElement], savelist: bool = False + ) -> None: super().__init__(exprs, savelist) if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) else: - self.mayReturnEmpty = True + self._may_return_empty = True def streamline(self) -> ParserElement: if self.streamlined: @@ -4359,13 +4413,13 @@ def streamline(self) -> ParserElement: super().streamline() if self.exprs: self.saveAsList = any(e.saveAsList for e in self.exprs) - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = all( e.skipWhitespace and not isinstance(e, White) for e in self.exprs ) else: self.saveAsList = False - self.mayReturnEmpty = True + self._may_return_empty = True return self def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: @@ -4393,7 +4447,8 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if maxException is not None: # infer from this check that all alternatives failed at the current position # so emit this collective error message instead of any individual error message - if maxExcLoc == loc: + parse_start_loc = self.preParse(instring, loc) + if maxExcLoc == parse_start_loc: maxException.msg = self.errmsg or "" raise maxException @@ -4491,12 +4546,14 @@ class Each(ParseExpression): - size: 20 """ - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = True): + def __init__( + self, exprs: typing.Iterable[ParserElement], savelist: bool = True + ) -> None: super().__init__(exprs, savelist) if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) else: - self.mayReturnEmpty = True + self._may_return_empty = True self.skipWhitespace = True self.initExprGroups = True self.saveAsList = True @@ -4511,9 +4568,9 @@ def __iand__(self, other): def streamline(self) -> ParserElement: super().streamline() if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) else: - self.mayReturnEmpty = True + self._may_return_empty = True return self def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: @@ -4612,7 +4669,7 @@ class ParseElementEnhance(ParserElement): post-processing parsed tokens. """ - def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): + def __init__(self, expr: Union[ParserElement, str], savelist: bool = False) -> None: super().__init__(savelist) if isinstance(expr, str_type): expr_str = typing.cast(str, expr) @@ -4626,7 +4683,7 @@ def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): self.expr = expr if expr is not None: self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty + self._may_return_empty = expr.mayReturnEmpty self.set_whitespace_chars( expr.whiteChars, copy_defaults=expr.copyDefaultWhiteChars ) @@ -4724,20 +4781,20 @@ class IndentedBlock(ParseElementEnhance): """ class _Indent(Empty): - def __init__(self, ref_col: int): + def __init__(self, ref_col: int) -> None: super().__init__() self.errmsg = f"expected indent at column {ref_col}" self.add_condition(lambda s, l, t: col(l, s) == ref_col) class _IndentGreater(Empty): - def __init__(self, ref_col: int): + def __init__(self, ref_col: int) -> None: super().__init__() self.errmsg = f"expected indent at column greater than {ref_col}" self.add_condition(lambda s, l, t: col(l, s) > ref_col) def __init__( self, expr: ParserElement, *, recursive: bool = False, grouped: bool = True - ): + ) -> None: super().__init__(expr, savelist=True) # if recursive: # raise NotImplementedError("IndentedBlock with recursive is not implemented") @@ -4792,7 +4849,7 @@ class AtStringStart(ParseElementEnhance): # raises ParseException """ - def __init__(self, expr: Union[ParserElement, str]): + def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) self.callPreparse = False @@ -4825,7 +4882,7 @@ class AtLineStart(ParseElementEnhance): """ - def __init__(self, expr: Union[ParserElement, str]): + def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) self.callPreparse = False @@ -4858,9 +4915,9 @@ class FollowedBy(ParseElementEnhance): [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] """ - def __init__(self, expr: Union[ParserElement, str]): + def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) - self.mayReturnEmpty = True + self._may_return_empty = True def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # by using self._expr.parse and deleting the contents of the returned ParseResults list @@ -4901,10 +4958,10 @@ class PrecededBy(ParseElementEnhance): """ - def __init__(self, expr: Union[ParserElement, str], retreat: int = 0): + def __init__(self, expr: Union[ParserElement, str], retreat: int = 0) -> None: super().__init__(expr) self.expr = self.expr().leave_whitespace() - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False self.exact = False if isinstance(expr, str_type): @@ -5019,13 +5076,13 @@ class NotAny(ParseElementEnhance): integer = Word(nums) + ~Char(".") """ - def __init__(self, expr: Union[ParserElement, str]): + def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) # do NOT use self.leave_whitespace(), don't want to propagate to exprs # self.leave_whitespace() self.skipWhitespace = False - self.mayReturnEmpty = True + self._may_return_empty = True self.errmsg = f"Found unwanted token, {self.expr}" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: @@ -5044,7 +5101,7 @@ def __init__( stop_on: typing.Optional[Union[ParserElement, str]] = None, *, stopOn: typing.Optional[Union[ParserElement, str]] = None, - ): + ) -> None: super().__init__(expr) stopOn = stopOn or stop_on self.saveAsList = True @@ -5062,9 +5119,10 @@ def stopOn(self, ender) -> ParserElement: def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: self_expr_parse = self.expr._parse self_skip_ignorables = self._skipIgnorables - check_ender = self.not_ender is not None - if check_ender: + check_ender = False + if self.not_ender is not None: try_not_ender = self.not_ender.try_parse + check_ender = True # must be at least one (but first see if we are the stopOn sentinel; # if so, fail) @@ -5165,9 +5223,9 @@ def __init__( stop_on: typing.Optional[Union[ParserElement, str]] = None, *, stopOn: typing.Optional[Union[ParserElement, str]] = None, - ): + ) -> None: super().__init__(expr, stopOn=stopOn or stop_on) - self.mayReturnEmpty = True + self._may_return_empty = True def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: try: @@ -5189,7 +5247,7 @@ def __init__( max: typing.Optional[int] = None, *, allow_trailing_delim: bool = False, - ): + ) -> None: """Helper to define a delimited list of expressions - the delimiter defaults to ','. By default, the list elements and delimiters can have intervening whitespace, and comments, but this can be @@ -5296,11 +5354,11 @@ class Opt(ParseElementEnhance): def __init__( self, expr: Union[ParserElement, str], default: Any = __optionalNotMatched - ): + ) -> None: super().__init__(expr, savelist=False) self.saveAsList = self.expr.saveAsList self.defaultValue = default - self.mayReturnEmpty = True + self._may_return_empty = True def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: self_expr = self.expr @@ -5401,11 +5459,11 @@ def __init__( fail_on: typing.Optional[Union[ParserElement, str]] = None, *, failOn: typing.Optional[Union[ParserElement, str]] = None, - ): + ) -> None: super().__init__(other) failOn = failOn or fail_on self.ignoreExpr = ignore - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False self.includeMatch = include self.saveAsList = False @@ -5512,7 +5570,9 @@ class Forward(ParseElementEnhance): parser created using ``Forward``. """ - def __init__(self, other: typing.Optional[Union[ParserElement, str]] = None): + def __init__( + self, other: typing.Optional[Union[ParserElement, str]] = None + ) -> None: self.caller_frame = traceback.extract_stack(limit=2)[0] super().__init__(other, savelist=False) # type: ignore[arg-type] self.lshift_line = None @@ -5529,7 +5589,7 @@ def __lshift__(self, other) -> Forward: self.expr = other self.streamlined = other.streamlined self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty + self._may_return_empty = self.expr.mayReturnEmpty self.set_whitespace_chars( self.expr.whiteChars, copy_defaults=self.expr.copyDefaultWhiteChars ) @@ -5648,7 +5708,7 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: try: new_loc, new_peek = super().parseImpl(instring, loc, False) except ParseException: - # we failed before getting any match – do not hide the error + # we failed before getting any match - do not hide the error if isinstance(prev_peek, Exception): raise new_loc, new_peek = prev_loc, prev_peek @@ -5703,17 +5763,20 @@ def validate(self, validateTrace=None) -> None: def _generateDefaultName(self) -> str: # Avoid infinite recursion by setting a temporary _defaultName + save_default_name = self._defaultName self._defaultName = ": ..." # Use the string representation of main expression. - retString = "..." try: if self.expr is not None: - retString = str(self.expr)[:1000] + ret_string = str(self.expr)[:1000] else: - retString = "None" - finally: - return f"{type(self).__name__}: {retString}" + ret_string = "None" + except Exception: + ret_string = "..." + + self._defaultName = save_default_name + return f"{type(self).__name__}: {ret_string}" def copy(self) -> ParserElement: if self.expr is not None: @@ -5752,7 +5815,7 @@ class TokenConverter(ParseElementEnhance): Abstract subclass of :class:`ParseElementEnhance`, for converting parsed results. """ - def __init__(self, expr: Union[ParserElement, str], savelist=False): + def __init__(self, expr: Union[ParserElement, str], savelist=False) -> None: super().__init__(expr) # , savelist) self.saveAsList = False @@ -5783,7 +5846,7 @@ def __init__( adjacent: bool = True, *, joinString: typing.Optional[str] = None, - ): + ) -> None: super().__init__(expr) joinString = joinString if joinString is not None else join_string # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself @@ -5835,7 +5898,7 @@ class Group(TokenConverter): # -> ['fn', ['a', 'b', '100']] """ - def __init__(self, expr: ParserElement, aslist: bool = False): + def __init__(self, expr: ParserElement, aslist: bool = False) -> None: super().__init__(expr) self.saveAsList = True self._asPythonList = aslist @@ -5893,7 +5956,7 @@ class Dict(TokenConverter): See more examples at :class:`ParseResults` of accessing fields by results name. """ - def __init__(self, expr: ParserElement, asdict: bool = False): + def __init__(self, expr: ParserElement, asdict: bool = False) -> None: super().__init__(expr) self.saveAsList = True self._asPythonDict = asdict @@ -5969,7 +6032,7 @@ class Suppress(TokenConverter): (See also :class:`DelimitedList`.) """ - def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): + def __init__(self, expr: Union[ParserElement, str], savelist: bool = False) -> None: if expr is ...: expr = _PendingSkip(NoMatch()) super().__init__(expr) @@ -6094,13 +6157,17 @@ def srange(s: str) -> str: - any combination of the above (``'aeiouy'``, ``'a-zA-Z0-9_$'``, etc.) """ - _expanded = lambda p: ( - p - if not isinstance(p, ParseResults) - else "".join(chr(c) for c in range(ord(p[0]), ord(p[1]) + 1)) - ) + + def _expanded(p): + if isinstance(p, ParseResults): + yield from (chr(c) for c in range(ord(p[0]), ord(p[1]) + 1)) + else: + yield p + try: - return "".join(_expanded(part) for part in _reBracketExpr.parse_string(s).body) + return "".join( + [c for part in _reBracketExpr.parse_string(s).body for c in _expanded(part)] + ) except Exception as e: return "" @@ -6156,11 +6223,17 @@ def autoname_elements() -> None: Utility to simplify mass-naming of parser elements, for generating railroad diagram with named subdiagrams. """ - calling_frame = sys._getframe(1) + + # guard against _getframe not being implemented in the current Python + getframe_fn = getattr(sys, "_getframe", lambda _: None) + calling_frame = getframe_fn(1) if calling_frame is None: return + + # find all locals in the calling frame that are ParserElements calling_frame = typing.cast(types.FrameType, calling_frame) for name, var in calling_frame.f_locals.items(): + # if no custom name defined, set the name to the var name if isinstance(var, ParserElement) and not var.customName: var.set_name(name) diff --git a/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py b/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py index 56526b741b87..526cf3862a47 100644 --- a/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py +++ b/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py @@ -120,7 +120,7 @@ class EachItem(railroad.Group): all_label = "[ALL]" - def __init__(self, *items): + def __init__(self, *items) -> None: choice_item = railroad.Choice(len(items) - 1, *items) one_or_more_item = railroad.OneOrMore(item=choice_item) super().__init__(one_or_more_item, label=self.all_label) @@ -131,7 +131,7 @@ class AnnotatedItem(railroad.Group): Simple subclass of Group that creates an annotation label """ - def __init__(self, label: str, item): + def __init__(self, label: str, item) -> None: super().__init__(item=item, label=f"[{label}]" if label else "") @@ -144,7 +144,7 @@ class EditablePartial(Generic[T]): # We need this here because the railroad constructors actually transform the data, so can't be called until the # entire tree is assembled - def __init__(self, func: Callable[..., T], args: list, kwargs: dict): + def __init__(self, func: Callable[..., T], args: list, kwargs: dict) -> None: self.func = func self.args = args self.kwargs = kwargs @@ -226,6 +226,7 @@ def to_railroad( vertical: int = 3, show_results_names: bool = False, show_groups: bool = False, + show_hidden: bool = False, ) -> list[NamedDiagram]: """ Convert a pyparsing element tree into a list of diagrams. This is the recommended entrypoint to diagram @@ -238,6 +239,8 @@ def to_railroad( included in the diagram :param show_groups - bool to indicate whether groups should be highlighted with an unlabeled surrounding box + :param show_hidden - bool to indicate whether internal elements that are typically hidden + should be shown """ # Convert the whole tree underneath the root lookup = ConverterState(diagram_kwargs=diagram_kwargs or {}) @@ -248,6 +251,7 @@ def to_railroad( vertical=vertical, show_results_names=show_results_names, show_groups=show_groups, + show_hidden=show_hidden, ) root_id = id(element) @@ -348,7 +352,7 @@ class ConverterState: Stores some state that persists between recursions into the element tree """ - def __init__(self, diagram_kwargs: typing.Optional[dict] = None): + def __init__(self, diagram_kwargs: typing.Optional[dict] = None) -> None: #: A dictionary mapping ParserElements to state relating to them self._element_diagram_states: dict[int, ElementState] = {} #: A dictionary mapping ParserElement IDs to subdiagrams generated from them @@ -453,6 +457,7 @@ def _inner( name_hint: str = None, show_results_names: bool = False, show_groups: bool = False, + show_hidden: bool = False, ) -> typing.Optional[EditablePartial]: ret = fn( element, @@ -463,6 +468,7 @@ def _inner( name_hint, show_results_names, show_groups, + show_hidden, ) # apply annotation for results name, if present @@ -555,6 +561,7 @@ def _to_diagram_element( name_hint=propagated_name, show_results_names=show_results_names, show_groups=show_groups, + show_hidden=show_hidden, ) # If the element isn't worth extracting, we always treat it as the first time we say it @@ -641,6 +648,7 @@ def _to_diagram_element( name_hint, show_results_names, show_groups, + show_hidden, ] return _to_diagram_element( (~element.not_ender.expr + element.expr)[1, ...].set_name(element.name), @@ -657,6 +665,7 @@ def _to_diagram_element( name_hint, show_results_names, show_groups, + show_hidden, ] return _to_diagram_element( (~element.not_ender.expr + element.expr)[...].set_name(element.name), @@ -707,6 +716,7 @@ def _to_diagram_element( index=i, show_results_names=show_results_names, show_groups=show_groups, + show_hidden=show_hidden, ) # Some elements don't need to be shown in the diagram diff --git a/contrib/python/pyparsing/py3/pyparsing/exceptions.py b/contrib/python/pyparsing/py3/pyparsing/exceptions.py index 57a1579d121e..fe07a8558561 100644 --- a/contrib/python/pyparsing/py3/pyparsing/exceptions.py +++ b/contrib/python/pyparsing/py3/pyparsing/exceptions.py @@ -52,7 +52,7 @@ def __init__( loc: int = 0, msg: typing.Optional[str] = None, elem=None, - ): + ) -> None: if msg is None: msg, pstr = pstr, "" @@ -87,7 +87,7 @@ def explain_exception(exc: Exception, depth: int = 16) -> str: ret: list[str] = [] if isinstance(exc, ParseBaseException): ret.append(exc.line) - ret.append(f"{' ' * (exc.column - 1)}^") + ret.append(f"{'^':>{exc.column}}") ret.append(f"{type(exc).__name__}: {exc}") if depth <= 0 or exc.__traceback__ is None: @@ -272,12 +272,11 @@ class ParseException(ParseBaseException): try: integer.parse_string("ABC") except ParseException as pe: - print(pe) - print(f"column: {pe.column}") + print(pe, f"column: {pe.column}") prints:: - Expected integer (at char 0), (line:1, col:1) column: 1 + Expected integer, found 'ABC' (at char 0), (line:1, col:1) column: 1 """ @@ -307,7 +306,7 @@ class RecursiveGrammarException(Exception): Deprecated: only used by deprecated method ParserElement.validate. """ - def __init__(self, parseElementList): + def __init__(self, parseElementList) -> None: self.parseElementTrace = parseElementList def __str__(self) -> str: diff --git a/contrib/python/pyparsing/py3/pyparsing/helpers.py b/contrib/python/pyparsing/py3/pyparsing/helpers.py index f781e8713271..2badd68d64f6 100644 --- a/contrib/python/pyparsing/py3/pyparsing/helpers.py +++ b/contrib/python/pyparsing/py3/pyparsing/helpers.py @@ -208,11 +208,9 @@ def one_of( if caseless: is_equal = lambda a, b: a.upper() == b.upper() masks = lambda a, b: b.upper().startswith(a.upper()) - parse_element_class = CaselessKeyword if asKeyword else CaselessLiteral else: is_equal = operator.eq masks = lambda a, b: b.startswith(a) - parse_element_class = Keyword if asKeyword else Literal symbols: list[str] if isinstance(strs, str_type): @@ -255,7 +253,8 @@ def one_of( if asKeyword: patt = rf"\b(?:{patt})\b" - ret = Regex(patt, flags=re_flags).set_name(" | ".join(symbols)) + ret = Regex(patt, flags=re_flags) + ret.set_name(" | ".join(re.escape(s) for s in symbols)) if caseless: # add parse action to return symbols as specified, not in random @@ -270,13 +269,21 @@ def one_of( "Exception creating Regex for one_of, building MatchFirst", stacklevel=2 ) - # last resort, just use MatchFirst + # last resort, just use MatchFirst of Token class corresponding to caseless + # and asKeyword settings + CASELESS = KEYWORD = True + parse_element_class = { + (CASELESS, KEYWORD): CaselessKeyword, + (CASELESS, not KEYWORD): CaselessLiteral, + (not CASELESS, KEYWORD): Keyword, + (not CASELESS, not KEYWORD): Literal, + }[(caseless, asKeyword)] return MatchFirst(parse_element_class(sym) for sym in symbols).set_name( " | ".join(symbols) ) -def dict_of(key: ParserElement, value: ParserElement) -> ParserElement: +def dict_of(key: ParserElement, value: ParserElement) -> Dict: """Helper to easily and clearly define a dictionary by specifying the respective patterns for the key and value. Takes care of defining the :class:`Dict`, :class:`ZeroOrMore`, and @@ -411,13 +418,18 @@ def locatedExpr(expr: ParserElement) -> ParserElement: ) +# define special default value to permit None as a significant value for +# ignore_expr +_NO_IGNORE_EXPR_GIVEN = NoMatch() + + def nested_expr( opener: Union[str, ParserElement] = "(", closer: Union[str, ParserElement] = ")", content: typing.Optional[ParserElement] = None, - ignore_expr: ParserElement = quoted_string(), + ignore_expr: ParserElement = _NO_IGNORE_EXPR_GIVEN, *, - ignoreExpr: ParserElement = quoted_string(), + ignoreExpr: ParserElement = _NO_IGNORE_EXPR_GIVEN, ) -> ParserElement: """Helper method for defining nested lists enclosed in opening and closing delimiters (``"("`` and ``")"`` are the default). @@ -487,9 +499,14 @@ def nested_expr( dec_to_hex (int) args: [['char', 'hchar']] """ if ignoreExpr != ignore_expr: - ignoreExpr = ignore_expr if ignoreExpr == quoted_string() else ignoreExpr + ignoreExpr = ignore_expr if ignoreExpr is _NO_IGNORE_EXPR_GIVEN else ignoreExpr + + if ignoreExpr is _NO_IGNORE_EXPR_GIVEN: + ignoreExpr = quoted_string() + if opener == closer: raise ValueError("opening and closing strings cannot be the same") + if content is None: if isinstance(opener, str_type) and isinstance(closer, str_type): opener = typing.cast(str, opener) @@ -504,11 +521,14 @@ def nested_expr( exact=1, ) ) - ).set_parse_action(lambda t: t[0].strip()) + ) else: - content = empty.copy() + CharsNotIn( - opener + closer + ParserElement.DEFAULT_WHITE_CHARS - ).set_parse_action(lambda t: t[0].strip()) + content = Combine( + Empty() + + CharsNotIn( + opener + closer + ParserElement.DEFAULT_WHITE_CHARS + ) + ) else: if ignoreExpr is not None: content = Combine( @@ -518,7 +538,7 @@ def nested_expr( + ~Literal(closer) + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) ) - ).set_parse_action(lambda t: t[0].strip()) + ) else: content = Combine( OneOrMore( @@ -526,11 +546,18 @@ def nested_expr( + ~Literal(closer) + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) ) - ).set_parse_action(lambda t: t[0].strip()) + ) else: raise ValueError( "opening and closing arguments must be strings if no content expression is given" ) + + # for these internally-created context expressions, simulate whitespace-skipping + if ParserElement.DEFAULT_WHITE_CHARS: + content.set_parse_action( + lambda t: t[0].strip(ParserElement.DEFAULT_WHITE_CHARS) + ) + ret = Forward() if ignoreExpr is not None: ret <<= Group( @@ -538,7 +565,9 @@ def nested_expr( ) else: ret <<= Group(Suppress(opener) + ZeroOrMore(ret | content) + Suppress(closer)) + ret.set_name(f"nested {opener}{closer} expression") + # don't override error message from content expressions ret.errmsg = None return ret @@ -603,7 +632,7 @@ def _makeTags(tagStr, xml, suppress_LT=Suppress("<"), suppress_GT=Suppress(">")) def make_html_tags( - tag_str: Union[str, ParserElement] + tag_str: Union[str, ParserElement], ) -> tuple[ParserElement, ParserElement]: """Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches tags in either upper or lower case, @@ -630,7 +659,7 @@ def make_html_tags( def make_xml_tags( - tag_str: Union[str, ParserElement] + tag_str: Union[str, ParserElement], ) -> tuple[ParserElement, ParserElement]: """Helper to construct opening and closing tag expressions for XML, given a tag name. Matches tags only in the given upper/lower case. @@ -691,7 +720,7 @@ def infix_notation( op_list: list[InfixNotationOperatorSpec], lpar: Union[str, ParserElement] = Suppress("("), rpar: Union[str, ParserElement] = Suppress(")"), -) -> ParserElement: +) -> Forward: """Helper method for constructing grammars of expressions made up of operators working in a precedence hierarchy. Operators may be unary or binary, left- or right-associative. Parse actions can also be diff --git a/contrib/python/pyparsing/py3/pyparsing/results.py b/contrib/python/pyparsing/py3/pyparsing/results.py index be834b7e6077..956230352c84 100644 --- a/contrib/python/pyparsing/py3/pyparsing/results.py +++ b/contrib/python/pyparsing/py3/pyparsing/results.py @@ -23,7 +23,7 @@ class _ParseResultsWithOffset: tup: tuple[ParseResults, int] __slots__ = ["tup"] - def __init__(self, p1: ParseResults, p2: int): + def __init__(self, p1: ParseResults, p2: int) -> None: self.tup: tuple[ParseResults, int] = (p1, p2) def __getitem__(self, i): diff --git a/contrib/python/pyparsing/py3/pyparsing/tools/__init__.py b/contrib/python/pyparsing/py3/pyparsing/tools/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/python/pyparsing/py3/pyparsing/tools/cvt_pyparsing_pep8_names.py b/contrib/python/pyparsing/py3/pyparsing/tools/cvt_pyparsing_pep8_names.py new file mode 100644 index 000000000000..f4a8bd9f5169 --- /dev/null +++ b/contrib/python/pyparsing/py3/pyparsing/tools/cvt_pyparsing_pep8_names.py @@ -0,0 +1,116 @@ +from functools import lru_cache +import pyparsing as pp + + +@lru_cache(maxsize=None) +def camel_to_snake(s: str) -> str: + """ + Convert CamelCase to snake_case. + """ + return "".join("_" + c.lower() if c.isupper() else c for c in s).lstrip("_") + + +pre_pep8_method_names = """ +addCondition addParseAction anyCloseTag anyOpenTag asDict asList cStyleComment canParseNext conditionAsParseAction +convertToDate convertToDatetime convertToFloat convertToInteger countedArray cppStyleComment dblQuotedString +dblSlashComment defaultName dictOf disableMemoization downcaseTokens enableLeftRecursion enablePackrat getName +htmlComment ignoreWhitespace indentedBlock infixNotation inlineLiteralsUsing javaStyleComment leaveWhitespace +lineEnd lineStart locatedExpr matchOnlyAtCol matchPreviousExpr matchPreviousLiteral nestedExpr nullDebugAction oneOf +originalTextFor parseFile parseString parseWithTabs pythonStyleComment quotedString removeQuotes replaceWith +resetCache restOfLine runTests scanString searchString setBreak setDebug setDebugActions setDefaultWhitespaceChars +setFailAction setName setParseAction setResultsName setWhitespaceChars sglQuotedString stringEnd stringStart tokenMap +traceParseAction transformString tryParse unicodeString upcaseTokens withAttribute withClass +""".split() + +special_changes = { + "opAssoc": "OpAssoc", + "delimitedList": "DelimitedList", + "delimited_list": "DelimitedList", + "replaceHTMLEntity": "replace_html_entity", + "makeHTMLTags": "make_html_tags", + "makeXMLTags": "make_xml_tags", + "commonHTMLEntity": "common_html_entity", + "stripHTMLTags": "strip_html_tags", +} + +pre_pep8_arg_names = """parseAll maxMatches listAllMatches callDuringTry includeSeparators fullDump printResults +failureTests postParse matchString identChars maxMismatches initChars bodyChars asKeyword excludeChars asGroupList +asMatch quoteChar escChar escQuote unquoteResults endQuoteChar convertWhitespaceEscapes notChars wordChars stopOn +failOn joinString markerString intExpr useRegex asString ignoreExpr""".split() + +pre_pep8_method_name = pp.one_of(pre_pep8_method_names, as_keyword=True) +pre_pep8_method_name.set_parse_action(lambda t: camel_to_snake(t[0])) +special_pre_pep8_name = pp.one_of(special_changes, as_keyword=True) +special_pre_pep8_name.set_parse_action(lambda t: special_changes[t[0]]) +# only replace arg names if part of an arg list +pre_pep8_arg_name = pp.Regex( + rf"{pp.util.make_compressed_re(pre_pep8_arg_names)}\s*=" +) +pre_pep8_arg_name.set_parse_action(lambda t: camel_to_snake(t[0])) + +pep8_converter = pre_pep8_method_name | special_pre_pep8_name | pre_pep8_arg_name + +if __name__ == "__main__": + import argparse + from pathlib import Path + import sys + + argparser = argparse.ArgumentParser( + description = ( + "Utility to convert Python pyparsing scripts using legacy" + " camelCase names to use PEP8 snake_case names." + "\nBy default, this script will only show whether this script would make any changes." + ) + ) + argparser.add_argument("--verbose", "-v", action="store_true", help="Show unified diff for each source file") + argparser.add_argument("-vv", action="store_true", dest="verbose2", help="Show unified diff for each source file, plus names of scanned files with no changes") + argparser.add_argument("--update", "-u", action="store_true", help="Update source files in-place") + argparser.add_argument("--encoding", type=str, default="utf-8", help="Encoding of source files (default: utf-8)") + argparser.add_argument("--exit-zero-even-if-changed", "-exit0", action="store_true", help="Exit with status code 0 even if changes were made") + argparser.add_argument("source_filename", nargs="+", help="Source filenames or filename patterns of Python files to be converted") + args = argparser.parse_args() + + + def show_diffs(original, modified): + import difflib + + diff = difflib.unified_diff( + original.splitlines(), modified.splitlines(), lineterm="" + ) + sys.stdout.writelines(f"{diff_line}\n" for diff_line in diff) + + exit_status = 0 + + for filename_pattern in args.source_filename: + + for filename in Path().glob(filename_pattern): + if not Path(filename).is_file(): + continue + + try: + original_contents = Path(filename).read_text(encoding=args.encoding) + modified_contents = pep8_converter.transform_string( + original_contents + ) + + if modified_contents != original_contents: + if args.update: + Path(filename).write_text(modified_contents, encoding=args.encoding) + print(f"Converted {filename}") + else: + print(f"Found required changes in {filename}") + + if args.verbose: + show_diffs(original_contents, modified_contents) + print() + + exit_status = 1 + + else: + if args.verbose2: + print(f"No required changes in {filename}") + + except Exception as e: + print(f"Failed to convert {filename}: {type(e).__name__}: {e}") + + sys.exit(exit_status if not args.exit_zero_even_if_changed else 0) diff --git a/contrib/python/pyparsing/py3/pyparsing/util.py b/contrib/python/pyparsing/py3/pyparsing/util.py index 03a60d4fddc2..1cb16e2e6205 100644 --- a/contrib/python/pyparsing/py3/pyparsing/util.py +++ b/contrib/python/pyparsing/py3/pyparsing/util.py @@ -1,5 +1,6 @@ # util.py import contextlib +import re from functools import lru_cache, wraps import inspect import itertools @@ -193,7 +194,7 @@ class _GroupConsecutive: (3, iter(['p', 'q', 'r', 's'])) """ - def __init__(self): + def __init__(self) -> None: self.prev = 0 self.counter = itertools.count() self.value = -1 @@ -303,7 +304,11 @@ def _flatten(ll: Iterable) -> list: def make_compressed_re( - word_list: Iterable[str], max_level: int = 2, _level: int = 1 + word_list: Iterable[str], + max_level: int = 2, + *, + non_capturing_groups: bool = True, + _level: int = 1, ) -> str: """ Create a regular expression string from a list of words, collapsing by common @@ -320,15 +325,38 @@ def get_suffixes_from_common_prefixes(namelist: list[str]): else: yield namelist[0][0], [namelist[0][1:]] + if _level == 1: + if not word_list: + raise ValueError("no words given to make_compressed_re()") + + if "" in word_list: + raise ValueError("word list cannot contain empty string") + else: + # internal recursive call, just return empty string if no words + if not word_list: + return "" + + # dedupe the word list + word_list = list({}.fromkeys(word_list)) + if max_level == 0: - return "|".join(sorted(word_list, key=len, reverse=True)) + if any(len(wd) > 1 for wd in word_list): + return "|".join( + sorted([re.escape(wd) for wd in word_list], key=len, reverse=True) + ) + else: + return f"[{''.join(_escape_regex_range_chars(wd) for wd in word_list)}]" ret = [] sep = "" + ncgroup = "?:" if non_capturing_groups else "" + for initial, suffixes in get_suffixes_from_common_prefixes(sorted(word_list)): ret.append(sep) sep = "|" + initial = re.escape(initial) + trailing = "" if "" in suffixes: trailing = "?" @@ -336,21 +364,33 @@ def get_suffixes_from_common_prefixes(namelist: list[str]): if len(suffixes) > 1: if all(len(s) == 1 for s in suffixes): - ret.append(f"{initial}[{''.join(suffixes)}]{trailing}") + ret.append( + f"{initial}[{''.join(_escape_regex_range_chars(s) for s in suffixes)}]{trailing}" + ) else: if _level < max_level: suffix_re = make_compressed_re( - sorted(suffixes), max_level, _level + 1 + sorted(suffixes), + max_level, + non_capturing_groups=non_capturing_groups, + _level=_level + 1, ) - ret.append(f"{initial}({suffix_re}){trailing}") + ret.append(f"{initial}({ncgroup}{suffix_re}){trailing}") else: - suffixes.sort(key=len, reverse=True) - ret.append(f"{initial}({'|'.join(suffixes)}){trailing}") + if all(len(s) == 1 for s in suffixes): + ret.append( + f"{initial}[{''.join(_escape_regex_range_chars(s) for s in suffixes)}]{trailing}" + ) + else: + suffixes.sort(key=len, reverse=True) + ret.append( + f"{initial}({ncgroup}{'|'.join(re.escape(s) for s in suffixes)}){trailing}" + ) else: if suffixes: - suffix = suffixes[0] + suffix = re.escape(suffixes[0]) if len(suffix) > 1 and trailing: - ret.append(f"{initial}({suffix}){trailing}") + ret.append(f"{initial}({ncgroup}{suffix}){trailing}") else: ret.append(f"{initial}{suffix}{trailing}") else: diff --git a/contrib/python/pyparsing/py3/ya.make b/contrib/python/pyparsing/py3/ya.make index e229986ca672..13dd585e164a 100644 --- a/contrib/python/pyparsing/py3/ya.make +++ b/contrib/python/pyparsing/py3/ya.make @@ -4,7 +4,7 @@ PY3_LIBRARY() PROVIDES(pyparsing) -VERSION(3.2.1) +VERSION(3.2.3) LICENSE(MIT) @@ -25,6 +25,8 @@ PY_SRCS( pyparsing/helpers.py pyparsing/results.py pyparsing/testing.py + pyparsing/tools/__init__.py + pyparsing/tools/cvt_pyparsing_pep8_names.py pyparsing/unicode.py pyparsing/util.py ) diff --git a/contrib/python/pytz/py2/.dist-info/METADATA b/contrib/python/pytz/py2/.dist-info/METADATA index 879a28cf7a1c..6ecc5a3e468a 100644 --- a/contrib/python/pytz/py2/.dist-info/METADATA +++ b/contrib/python/pytz/py2/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytz -Version: 2025.1 +Version: 2025.2 Summary: World timezone definitions, modern and historical Home-page: http://pythonhosted.org/pytz Download-URL: https://pypi.org/project/pytz/ diff --git a/contrib/python/pytz/py2/pytz/__init__.py b/contrib/python/pytz/py2/pytz/__init__.py index 1f0194634ca1..c7ee5efd2f08 100644 --- a/contrib/python/pytz/py2/pytz/__init__.py +++ b/contrib/python/pytz/py2/pytz/__init__.py @@ -22,8 +22,8 @@ # The IANA (nee Olson) database is updated several times a year. -OLSON_VERSION = '2025a' -VERSION = '2025.1' # pip compatible version number. +OLSON_VERSION = '2025b' +VERSION = '2025.2' # pip compatible version number. __version__ = VERSION OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling @@ -617,6 +617,7 @@ def _test(): 'America/Coral_Harbour', 'America/Cordoba', 'America/Costa_Rica', + 'America/Coyhaique', 'America/Creston', 'America/Cuiaba', 'America/Curacao', @@ -1210,6 +1211,7 @@ def _test(): 'America/Chihuahua', 'America/Ciudad_Juarez', 'America/Costa_Rica', + 'America/Coyhaique', 'America/Creston', 'America/Cuiaba', 'America/Curacao', diff --git a/contrib/python/pytz/py2/pytz/tests/test_tzinfo.py b/contrib/python/pytz/py2/pytz/tests/test_tzinfo.py index 3195a1fde36a..6d1cadaf2dbe 100644 --- a/contrib/python/pytz/py2/pytz/tests/test_tzinfo.py +++ b/contrib/python/pytz/py2/pytz/tests/test_tzinfo.py @@ -27,8 +27,8 @@ # I test for expected version to ensure the correct version of pytz is # actually being tested. -EXPECTED_VERSION = '2025.1' -EXPECTED_OLSON_VERSION = '2025a' +EXPECTED_VERSION = '2025.2' +EXPECTED_OLSON_VERSION = '2025b' fmt = '%Y-%m-%d %H:%M:%S %Z%z' diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/America/Coyhaique b/contrib/python/pytz/py2/pytz/zoneinfo/America/Coyhaique new file mode 100644 index 000000000000..e0c6832bb36b Binary files /dev/null and b/contrib/python/pytz/py2/pytz/zoneinfo/America/Coyhaique differ diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/Asia/Tehran b/contrib/python/pytz/py2/pytz/zoneinfo/Asia/Tehran index cc2a2c219b0c..78f28cc40202 100644 Binary files a/contrib/python/pytz/py2/pytz/zoneinfo/Asia/Tehran and b/contrib/python/pytz/py2/pytz/zoneinfo/Asia/Tehran differ diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/Iran b/contrib/python/pytz/py2/pytz/zoneinfo/Iran index cc2a2c219b0c..78f28cc40202 100644 Binary files a/contrib/python/pytz/py2/pytz/zoneinfo/Iran and b/contrib/python/pytz/py2/pytz/zoneinfo/Iran differ diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/tzdata.zi b/contrib/python/pytz/py2/pytz/zoneinfo/tzdata.zi index a2fcd5449632..0bcae52e5efa 100644 --- a/contrib/python/pytz/py2/pytz/zoneinfo/tzdata.zi +++ b/contrib/python/pytz/py2/pytz/zoneinfo/tzdata.zi @@ -2432,6 +2432,20 @@ Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u Z America/Costa_Rica -5:36:13 - LMT 1890 -5:36:13 - SJMT 1921 Ja 15 -6 CR C%sT +Z America/Coyhaique -4:48:16 - LMT 1890 +-4:42:45 - SMT 1910 Ja 10 +-5 - %z 1916 Jul +-4:42:45 - SMT 1918 S 10 +-4 - %z 1919 Jul +-4:42:45 - SMT 1927 S +-5 x %z 1932 S +-4 - %z 1942 Jun +-5 - %z 1942 Au +-4 - %z 1946 Au 28 24 +-5 1 %z 1947 Mar 31 24 +-5 - %z 1947 May 21 23 +-4 x %z 2025 Mar 20 +-3 - %z Z America/Cuiaba -3:44:20 - LMT 1914 -4 B %z 2003 S 24 -4 - %z 2004 O @@ -3420,7 +3434,7 @@ Z Asia/Tbilisi 2:59:11 - LMT 1880 Z Asia/Tehran 3:25:44 - LMT 1916 3:25:44 - TMT 1935 Jun 13 3:30 i %z 1977 O 20 24 -4 i %z 1979 +4 i %z 1978 N 10 24 3:30 i %z Z Asia/Thimphu 5:58:36 - LMT 1947 Au 15 5:30 - %z 1987 O diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/zone.tab b/contrib/python/pytz/py2/pytz/zoneinfo/zone.tab index d2be66359f3b..2626b0550341 100644 --- a/contrib/python/pytz/py2/pytz/zoneinfo/zone.tab +++ b/contrib/python/pytz/py2/pytz/zoneinfo/zone.tab @@ -139,7 +139,8 @@ CH +4723+00832 Europe/Zurich CI +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago most of Chile -CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -4534-07204 America/Coyhaique Aysen Region +CL -5309-07055 America/Punta_Arenas Magallanes Region CL -2709-10926 Pacific/Easter Easter Island CM +0403+00942 Africa/Douala CN +3114+12128 Asia/Shanghai Beijing Time diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/zone1970.tab b/contrib/python/pytz/py2/pytz/zoneinfo/zone1970.tab index 5ded0565ebf3..36535bdf5cfb 100644 --- a/contrib/python/pytz/py2/pytz/zoneinfo/zone1970.tab +++ b/contrib/python/pytz/py2/pytz/zoneinfo/zone1970.tab @@ -124,7 +124,8 @@ CH,DE,LI +4723+00832 Europe/Zurich Büsingen CI,BF,GH,GM,GN,IS,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago most of Chile -CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -4534-07204 America/Coyhaique Aysén Region +CL -5309-07055 America/Punta_Arenas Magallanes Region CL -2709-10926 Pacific/Easter Easter Island CN +3114+12128 Asia/Shanghai Beijing Time CN +4348+08735 Asia/Urumqi Xinjiang Time diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/zonenow.tab b/contrib/python/pytz/py2/pytz/zoneinfo/zonenow.tab index d2c1e48584f8..093f0a0cb749 100644 --- a/contrib/python/pytz/py2/pytz/zoneinfo/zonenow.tab +++ b/contrib/python/pytz/py2/pytz/zoneinfo/zonenow.tab @@ -104,7 +104,7 @@ XX +4439-06336 America/Halifax Atlantic ("AST/ADT") - Canada; Bermuda XX +4734-05243 America/St_Johns Newfoundland ("NST/NDT") # # -03 -XX -2332-04637 America/Sao_Paulo eastern South America +XX -2332-04637 America/Sao_Paulo eastern and southern South America # # -03/-02 (North America DST) XX +4703-05620 America/Miquelon St Pierre & Miquelon diff --git a/contrib/python/pytz/py2/ya.make b/contrib/python/pytz/py2/ya.make index ea9dc82c568e..b893dc7f05d3 100644 --- a/contrib/python/pytz/py2/ya.make +++ b/contrib/python/pytz/py2/ya.make @@ -2,7 +2,7 @@ PY2_LIBRARY() -VERSION(2025.1) +VERSION(2025.2) LICENSE(MIT) @@ -125,6 +125,7 @@ RESOURCE_FILES( pytz/zoneinfo/America/Coral_Harbour pytz/zoneinfo/America/Cordoba pytz/zoneinfo/America/Costa_Rica + pytz/zoneinfo/America/Coyhaique pytz/zoneinfo/America/Creston pytz/zoneinfo/America/Cuiaba pytz/zoneinfo/America/Curacao diff --git a/contrib/python/pytz/py3/.dist-info/METADATA b/contrib/python/pytz/py3/.dist-info/METADATA index 879a28cf7a1c..6ecc5a3e468a 100644 --- a/contrib/python/pytz/py3/.dist-info/METADATA +++ b/contrib/python/pytz/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytz -Version: 2025.1 +Version: 2025.2 Summary: World timezone definitions, modern and historical Home-page: http://pythonhosted.org/pytz Download-URL: https://pypi.org/project/pytz/ diff --git a/contrib/python/pytz/py3/pytz/__init__.py b/contrib/python/pytz/py3/pytz/__init__.py index 1f0194634ca1..c7ee5efd2f08 100644 --- a/contrib/python/pytz/py3/pytz/__init__.py +++ b/contrib/python/pytz/py3/pytz/__init__.py @@ -22,8 +22,8 @@ # The IANA (nee Olson) database is updated several times a year. -OLSON_VERSION = '2025a' -VERSION = '2025.1' # pip compatible version number. +OLSON_VERSION = '2025b' +VERSION = '2025.2' # pip compatible version number. __version__ = VERSION OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling @@ -617,6 +617,7 @@ def _test(): 'America/Coral_Harbour', 'America/Cordoba', 'America/Costa_Rica', + 'America/Coyhaique', 'America/Creston', 'America/Cuiaba', 'America/Curacao', @@ -1210,6 +1211,7 @@ def _test(): 'America/Chihuahua', 'America/Ciudad_Juarez', 'America/Costa_Rica', + 'America/Coyhaique', 'America/Creston', 'America/Cuiaba', 'America/Curacao', diff --git a/contrib/python/pytz/py3/pytz/tests/test_tzinfo.py b/contrib/python/pytz/py3/pytz/tests/test_tzinfo.py index 3195a1fde36a..6d1cadaf2dbe 100644 --- a/contrib/python/pytz/py3/pytz/tests/test_tzinfo.py +++ b/contrib/python/pytz/py3/pytz/tests/test_tzinfo.py @@ -27,8 +27,8 @@ # I test for expected version to ensure the correct version of pytz is # actually being tested. -EXPECTED_VERSION = '2025.1' -EXPECTED_OLSON_VERSION = '2025a' +EXPECTED_VERSION = '2025.2' +EXPECTED_OLSON_VERSION = '2025b' fmt = '%Y-%m-%d %H:%M:%S %Z%z' diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/America/Coyhaique b/contrib/python/pytz/py3/pytz/zoneinfo/America/Coyhaique new file mode 100644 index 000000000000..e0c6832bb36b Binary files /dev/null and b/contrib/python/pytz/py3/pytz/zoneinfo/America/Coyhaique differ diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/Asia/Tehran b/contrib/python/pytz/py3/pytz/zoneinfo/Asia/Tehran index cc2a2c219b0c..78f28cc40202 100644 Binary files a/contrib/python/pytz/py3/pytz/zoneinfo/Asia/Tehran and b/contrib/python/pytz/py3/pytz/zoneinfo/Asia/Tehran differ diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/Iran b/contrib/python/pytz/py3/pytz/zoneinfo/Iran index cc2a2c219b0c..78f28cc40202 100644 Binary files a/contrib/python/pytz/py3/pytz/zoneinfo/Iran and b/contrib/python/pytz/py3/pytz/zoneinfo/Iran differ diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/tzdata.zi b/contrib/python/pytz/py3/pytz/zoneinfo/tzdata.zi index a2fcd5449632..0bcae52e5efa 100644 --- a/contrib/python/pytz/py3/pytz/zoneinfo/tzdata.zi +++ b/contrib/python/pytz/py3/pytz/zoneinfo/tzdata.zi @@ -2432,6 +2432,20 @@ Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u Z America/Costa_Rica -5:36:13 - LMT 1890 -5:36:13 - SJMT 1921 Ja 15 -6 CR C%sT +Z America/Coyhaique -4:48:16 - LMT 1890 +-4:42:45 - SMT 1910 Ja 10 +-5 - %z 1916 Jul +-4:42:45 - SMT 1918 S 10 +-4 - %z 1919 Jul +-4:42:45 - SMT 1927 S +-5 x %z 1932 S +-4 - %z 1942 Jun +-5 - %z 1942 Au +-4 - %z 1946 Au 28 24 +-5 1 %z 1947 Mar 31 24 +-5 - %z 1947 May 21 23 +-4 x %z 2025 Mar 20 +-3 - %z Z America/Cuiaba -3:44:20 - LMT 1914 -4 B %z 2003 S 24 -4 - %z 2004 O @@ -3420,7 +3434,7 @@ Z Asia/Tbilisi 2:59:11 - LMT 1880 Z Asia/Tehran 3:25:44 - LMT 1916 3:25:44 - TMT 1935 Jun 13 3:30 i %z 1977 O 20 24 -4 i %z 1979 +4 i %z 1978 N 10 24 3:30 i %z Z Asia/Thimphu 5:58:36 - LMT 1947 Au 15 5:30 - %z 1987 O diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/zone.tab b/contrib/python/pytz/py3/pytz/zoneinfo/zone.tab index d2be66359f3b..2626b0550341 100644 --- a/contrib/python/pytz/py3/pytz/zoneinfo/zone.tab +++ b/contrib/python/pytz/py3/pytz/zoneinfo/zone.tab @@ -139,7 +139,8 @@ CH +4723+00832 Europe/Zurich CI +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago most of Chile -CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -4534-07204 America/Coyhaique Aysen Region +CL -5309-07055 America/Punta_Arenas Magallanes Region CL -2709-10926 Pacific/Easter Easter Island CM +0403+00942 Africa/Douala CN +3114+12128 Asia/Shanghai Beijing Time diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/zone1970.tab b/contrib/python/pytz/py3/pytz/zoneinfo/zone1970.tab index 5ded0565ebf3..36535bdf5cfb 100644 --- a/contrib/python/pytz/py3/pytz/zoneinfo/zone1970.tab +++ b/contrib/python/pytz/py3/pytz/zoneinfo/zone1970.tab @@ -124,7 +124,8 @@ CH,DE,LI +4723+00832 Europe/Zurich Büsingen CI,BF,GH,GM,GN,IS,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago most of Chile -CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -4534-07204 America/Coyhaique Aysén Region +CL -5309-07055 America/Punta_Arenas Magallanes Region CL -2709-10926 Pacific/Easter Easter Island CN +3114+12128 Asia/Shanghai Beijing Time CN +4348+08735 Asia/Urumqi Xinjiang Time diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/zonenow.tab b/contrib/python/pytz/py3/pytz/zoneinfo/zonenow.tab index d2c1e48584f8..093f0a0cb749 100644 --- a/contrib/python/pytz/py3/pytz/zoneinfo/zonenow.tab +++ b/contrib/python/pytz/py3/pytz/zoneinfo/zonenow.tab @@ -104,7 +104,7 @@ XX +4439-06336 America/Halifax Atlantic ("AST/ADT") - Canada; Bermuda XX +4734-05243 America/St_Johns Newfoundland ("NST/NDT") # # -03 -XX -2332-04637 America/Sao_Paulo eastern South America +XX -2332-04637 America/Sao_Paulo eastern and southern South America # # -03/-02 (North America DST) XX +4703-05620 America/Miquelon St Pierre & Miquelon diff --git a/contrib/python/pytz/py3/ya.make b/contrib/python/pytz/py3/ya.make index 7686a5866163..60909b6a6b88 100644 --- a/contrib/python/pytz/py3/ya.make +++ b/contrib/python/pytz/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(2025.1) +VERSION(2025.2) LICENSE(MIT) @@ -125,6 +125,7 @@ RESOURCE_FILES( pytz/zoneinfo/America/Coral_Harbour pytz/zoneinfo/America/Cordoba pytz/zoneinfo/America/Costa_Rica + pytz/zoneinfo/America/Coyhaique pytz/zoneinfo/America/Creston pytz/zoneinfo/America/Cuiaba pytz/zoneinfo/America/Curacao diff --git a/contrib/python/ydb/py3/.dist-info/METADATA b/contrib/python/ydb/py3/.dist-info/METADATA index b6911ce75e8f..904414722eff 100644 --- a/contrib/python/ydb/py3/.dist-info/METADATA +++ b/contrib/python/ydb/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: ydb -Version: 3.19.3 +Version: 3.20.1 Summary: YDB Python SDK Home-page: http://github.com/ydb-platform/ydb-python-sdk Author: Yandex LLC diff --git a/contrib/python/ydb/py3/ya.make b/contrib/python/ydb/py3/ya.make index 71cfb8fa720b..fbc5d148f8a6 100644 --- a/contrib/python/ydb/py3/ya.make +++ b/contrib/python/ydb/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(3.19.3) +VERSION(3.20.1) LICENSE(Apache-2.0) diff --git a/contrib/python/ydb/py3/ydb/_apis.py b/contrib/python/ydb/py3/ydb/_apis.py index fc28d0ceb294..fc6f16e287c9 100644 --- a/contrib/python/ydb/py3/ydb/_apis.py +++ b/contrib/python/ydb/py3/ydb/_apis.py @@ -115,6 +115,7 @@ class TopicService(object): DropTopic = "DropTopic" StreamRead = "StreamRead" StreamWrite = "StreamWrite" + UpdateOffsetsInTransaction = "UpdateOffsetsInTransaction" class QueryService(object): diff --git a/contrib/python/ydb/py3/ydb/_errors.py b/contrib/python/ydb/py3/ydb/_errors.py index 17002d257499..1e2308ef394d 100644 --- a/contrib/python/ydb/py3/ydb/_errors.py +++ b/contrib/python/ydb/py3/ydb/_errors.py @@ -5,6 +5,7 @@ _errors_retriable_fast_backoff_types = [ issues.Unavailable, + issues.ClientInternalError, ] _errors_retriable_slow_backoff_types = [ issues.Aborted, diff --git a/contrib/python/ydb/py3/ydb/_grpc/grpcwrapper/ydb_topic.py b/contrib/python/ydb/py3/ydb/_grpc/grpcwrapper/ydb_topic.py index 5b22c7cf862b..0f8a0f03a7a0 100644 --- a/contrib/python/ydb/py3/ydb/_grpc/grpcwrapper/ydb_topic.py +++ b/contrib/python/ydb/py3/ydb/_grpc/grpcwrapper/ydb_topic.py @@ -141,6 +141,18 @@ def from_proto(msg: ydb_topic_pb2.UpdateTokenResponse) -> typing.Any: ######################################################################################################################## +@dataclass +class TransactionIdentity(IToProto): + tx_id: str + session_id: str + + def to_proto(self) -> ydb_topic_pb2.TransactionIdentity: + return ydb_topic_pb2.TransactionIdentity( + id=self.tx_id, + session=self.session_id, + ) + + class StreamWriteMessage: @dataclass() class InitRequest(IToProto): @@ -199,6 +211,7 @@ def from_proto( class WriteRequest(IToProto): messages: typing.List["StreamWriteMessage.WriteRequest.MessageData"] codec: int + tx_identity: Optional[TransactionIdentity] @dataclass class MessageData(IToProto): @@ -237,6 +250,9 @@ def to_proto(self) -> ydb_topic_pb2.StreamWriteMessage.WriteRequest: proto = ydb_topic_pb2.StreamWriteMessage.WriteRequest() proto.codec = self.codec + if self.tx_identity is not None: + proto.tx.CopyFrom(self.tx_identity.to_proto()) + for message in self.messages: proto_mess = proto.messages.add() proto_mess.CopyFrom(message.to_proto()) @@ -297,6 +313,8 @@ def from_proto(cls, proto_ack: ydb_topic_pb2.StreamWriteMessage.WriteResponse.Wr ) except ValueError: message_write_status = reason + elif proto_ack.HasField("written_in_tx"): + message_write_status = StreamWriteMessage.WriteResponse.WriteAck.StatusWrittenInTx() else: raise NotImplementedError("unexpected ack status") @@ -309,6 +327,9 @@ def from_proto(cls, proto_ack: ydb_topic_pb2.StreamWriteMessage.WriteResponse.Wr class StatusWritten: offset: int + class StatusWrittenInTx: + pass + @dataclass class StatusSkipped: reason: "StreamWriteMessage.WriteResponse.WriteAck.StatusSkipped.Reason" @@ -1196,6 +1217,52 @@ def to_public(self) -> ydb_topic_public_types.PublicMeteringMode: return ydb_topic_public_types.PublicMeteringMode.UNSPECIFIED +@dataclass +class UpdateOffsetsInTransactionRequest(IToProto): + tx: TransactionIdentity + topics: List[UpdateOffsetsInTransactionRequest.TopicOffsets] + consumer: str + + def to_proto(self): + return ydb_topic_pb2.UpdateOffsetsInTransactionRequest( + tx=self.tx.to_proto(), + consumer=self.consumer, + topics=list( + map( + UpdateOffsetsInTransactionRequest.TopicOffsets.to_proto, + self.topics, + ) + ), + ) + + @dataclass + class TopicOffsets(IToProto): + path: str + partitions: List[UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets] + + def to_proto(self): + return ydb_topic_pb2.UpdateOffsetsInTransactionRequest.TopicOffsets( + path=self.path, + partitions=list( + map( + UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets.to_proto, + self.partitions, + ) + ), + ) + + @dataclass + class PartitionOffsets(IToProto): + partition_id: int + partition_offsets: List[OffsetsRange] + + def to_proto(self) -> ydb_topic_pb2.UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets: + return ydb_topic_pb2.UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets( + partition_id=self.partition_id, + partition_offsets=list(map(OffsetsRange.to_proto, self.partition_offsets)), + ) + + @dataclass class CreateTopicRequest(IToProto, IFromPublic): path: str diff --git a/contrib/python/ydb/py3/ydb/_topic_reader/datatypes.py b/contrib/python/ydb/py3/ydb/_topic_reader/datatypes.py index b48501aff2f3..74f06a086fc2 100644 --- a/contrib/python/ydb/py3/ydb/_topic_reader/datatypes.py +++ b/contrib/python/ydb/py3/ydb/_topic_reader/datatypes.py @@ -108,6 +108,9 @@ def ack_notify(self, offset: int): waiter = self._ack_waiters.popleft() waiter._finish_ok() + def _update_last_commited_offset_if_needed(self, offset: int): + self.committed_offset = max(self.committed_offset, offset) + def close(self): if self.closed: return @@ -211,3 +214,9 @@ def _pop_batch(self, message_count: int) -> PublicBatch: self._bytes_size = self._bytes_size - new_batch._bytes_size return new_batch + + def _update_partition_offsets(self, tx, exc=None): + if exc is not None: + return + offsets = self._commit_get_offsets_range() + self._partition_session._update_last_commited_offset_if_needed(offsets.end) diff --git a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_asyncio.py b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_asyncio.py index 7061b4e449c3..87012554ef59 100644 --- a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_asyncio.py +++ b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_asyncio.py @@ -5,7 +5,7 @@ import gzip import typing from asyncio import Task -from collections import OrderedDict +from collections import defaultdict, OrderedDict from typing import Optional, Set, Dict, Union, Callable import ydb @@ -19,17 +19,24 @@ from .._grpc.grpcwrapper.common_utils import ( IGrpcWrapperAsyncIO, SupportedDriverType, + to_thread, GrpcWrapperAsyncIO, ) from .._grpc.grpcwrapper.ydb_topic import ( StreamReadMessage, UpdateTokenRequest, UpdateTokenResponse, + UpdateOffsetsInTransactionRequest, Codec, ) from .._errors import check_retriable_error import logging +from ..query.base import TxEvent + +if typing.TYPE_CHECKING: + from ..query.transaction import BaseQueryTxContext + logger = logging.getLogger(__name__) @@ -77,7 +84,7 @@ def __init__( ): self._loop = asyncio.get_running_loop() self._closed = False - self._reconnector = ReaderReconnector(driver, settings) + self._reconnector = ReaderReconnector(driver, settings, self._loop) self._parent = _parent async def __aenter__(self): @@ -88,8 +95,12 @@ async def __aexit__(self, exc_type, exc_val, exc_tb): def __del__(self): if not self._closed: - task = self._loop.create_task(self.close(flush=False)) - topic_common.wrap_set_name_for_asyncio_task(task, task_name="close reader") + try: + logger.warning("Topic reader was not closed properly. Consider using method close().") + task = self._loop.create_task(self.close(flush=False)) + topic_common.wrap_set_name_for_asyncio_task(task, task_name="close reader") + except BaseException: + logger.warning("Something went wrong during reader close in __del__") async def wait_message(self): """ @@ -112,6 +123,23 @@ async def receive_batch( max_messages=max_messages, ) + async def receive_batch_with_tx( + self, + tx: "BaseQueryTxContext", + max_messages: typing.Union[int, None] = None, + ) -> typing.Union[datatypes.PublicBatch, None]: + """ + Get one messages batch with tx from reader. + All messages in a batch from same partition. + + use asyncio.wait_for for wait with timeout. + """ + await self._reconnector.wait_message() + return self._reconnector.receive_batch_with_tx_nowait( + tx=tx, + max_messages=max_messages, + ) + async def receive_message(self) -> typing.Optional[datatypes.PublicMessage]: """ Block until receive new message @@ -165,11 +193,18 @@ class ReaderReconnector: _state_changed: asyncio.Event _stream_reader: Optional["ReaderStream"] _first_error: asyncio.Future[YdbError] + _tx_to_batches_map: Dict[str, typing.List[datatypes.PublicBatch]] - def __init__(self, driver: Driver, settings: topic_reader.PublicReaderSettings): + def __init__( + self, + driver: Driver, + settings: topic_reader.PublicReaderSettings, + loop: Optional[asyncio.AbstractEventLoop] = None, + ): self._id = self._static_reader_reconnector_counter.inc_and_get() self._settings = settings self._driver = driver + self._loop = loop if loop is not None else asyncio.get_running_loop() self._background_tasks = set() self._state_changed = asyncio.Event() @@ -177,6 +212,8 @@ def __init__(self, driver: Driver, settings: topic_reader.PublicReaderSettings): self._background_tasks.add(asyncio.create_task(self._connection_loop())) self._first_error = asyncio.get_running_loop().create_future() + self._tx_to_batches_map = dict() + async def _connection_loop(self): attempt = 0 while True: @@ -190,6 +227,7 @@ async def _connection_loop(self): if not retry_info.is_retriable: self._set_first_error(err) return + await asyncio.sleep(retry_info.sleep_timeout_seconds) attempt += 1 @@ -222,9 +260,87 @@ def receive_batch_nowait(self, max_messages: Optional[int] = None): max_messages=max_messages, ) + def receive_batch_with_tx_nowait(self, tx: "BaseQueryTxContext", max_messages: Optional[int] = None): + batch = self._stream_reader.receive_batch_nowait( + max_messages=max_messages, + ) + + self._init_tx(tx) + + self._tx_to_batches_map[tx.tx_id].append(batch) + + tx._add_callback(TxEvent.AFTER_COMMIT, batch._update_partition_offsets, self._loop) + + return batch + def receive_message_nowait(self): return self._stream_reader.receive_message_nowait() + def _init_tx(self, tx: "BaseQueryTxContext"): + if tx.tx_id not in self._tx_to_batches_map: # Init tx callbacks + self._tx_to_batches_map[tx.tx_id] = [] + tx._add_callback(TxEvent.BEFORE_COMMIT, self._commit_batches_with_tx, self._loop) + tx._add_callback(TxEvent.AFTER_COMMIT, self._handle_after_tx_commit, self._loop) + tx._add_callback(TxEvent.AFTER_ROLLBACK, self._handle_after_tx_rollback, self._loop) + + async def _commit_batches_with_tx(self, tx: "BaseQueryTxContext"): + grouped_batches = defaultdict(lambda: defaultdict(list)) + for batch in self._tx_to_batches_map[tx.tx_id]: + grouped_batches[batch._partition_session.topic_path][batch._partition_session.partition_id].append(batch) + + request = UpdateOffsetsInTransactionRequest(tx=tx._tx_identity(), consumer=self._settings.consumer, topics=[]) + + for topic_path in grouped_batches: + topic_offsets = UpdateOffsetsInTransactionRequest.TopicOffsets(path=topic_path, partitions=[]) + for partition_id in grouped_batches[topic_path]: + partition_offsets = UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets( + partition_id=partition_id, + partition_offsets=[ + batch._commit_get_offsets_range() for batch in grouped_batches[topic_path][partition_id] + ], + ) + topic_offsets.partitions.append(partition_offsets) + request.topics.append(topic_offsets) + + try: + return await self._do_commit_batches_with_tx_call(request) + except BaseException: + exc = issues.ClientInternalError("Failed to update offsets in tx.") + tx._set_external_error(exc) + self._stream_reader._set_first_error(exc) + finally: + del self._tx_to_batches_map[tx.tx_id] + + async def _do_commit_batches_with_tx_call(self, request: UpdateOffsetsInTransactionRequest): + args = [ + request.to_proto(), + _apis.TopicService.Stub, + _apis.TopicService.UpdateOffsetsInTransaction, + topic_common.wrap_operation, + ] + + if asyncio.iscoroutinefunction(self._driver.__call__): + res = await self._driver(*args) + else: + res = await to_thread(self._driver, *args, executor=None) + + return res + + async def _handle_after_tx_rollback(self, tx: "BaseQueryTxContext", exc: Optional[BaseException]) -> None: + if tx.tx_id in self._tx_to_batches_map: + del self._tx_to_batches_map[tx.tx_id] + exc = issues.ClientInternalError("Reconnect due to transaction rollback") + self._stream_reader._set_first_error(exc) + + async def _handle_after_tx_commit(self, tx: "BaseQueryTxContext", exc: Optional[BaseException]) -> None: + if tx.tx_id in self._tx_to_batches_map: + del self._tx_to_batches_map[tx.tx_id] + + if exc is not None: + self._stream_reader._set_first_error( + issues.ClientInternalError("Reconnect due to transaction commit failed") + ) + def commit(self, batch: datatypes.ICommittable) -> datatypes.PartitionSession.CommitAckWaiter: return self._stream_reader.commit(batch) diff --git a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py index eda1d374fc3a..31f28899271b 100644 --- a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py +++ b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py @@ -1,5 +1,6 @@ import asyncio import concurrent.futures +import logging import typing from typing import List, Union, Optional @@ -20,6 +21,11 @@ TopicReaderClosedError, ) +if typing.TYPE_CHECKING: + from ..query.transaction import BaseQueryTxContext + +logger = logging.getLogger(__name__) + class TopicReaderSync: _caller: CallFromSyncToAsync @@ -52,7 +58,12 @@ async def create_reader(): self._parent = _parent def __del__(self): - self.close(flush=False) + if not self._closed: + try: + logger.warning("Topic reader was not closed properly. Consider using method close().") + self.close(flush=False) + except BaseException: + logger.warning("Something went wrong during reader close in __del__") def __enter__(self): return self @@ -109,6 +120,31 @@ def receive_batch( timeout, ) + def receive_batch_with_tx( + self, + tx: "BaseQueryTxContext", + *, + max_messages: typing.Union[int, None] = None, + max_bytes: typing.Union[int, None] = None, + timeout: Union[float, None] = None, + ) -> Union[PublicBatch, None]: + """ + Get one messages batch with tx from reader + It has no async_ version for prevent lost messages, use async_wait_message as signal for new batches available. + + if no new message in timeout seconds (default - infinite): raise TimeoutError() + if timeout <= 0 - it will fast wait only one event loop cycle - without wait any i/o operations or pauses, get messages from internal buffer only. + """ + self._check_closed() + + return self._caller.safe_call_with_result( + self._async_reader.receive_batch_with_tx( + tx=tx, + max_messages=max_messages, + ), + timeout, + ) + def commit(self, mess: typing.Union[datatypes.PublicMessage, datatypes.PublicBatch]): """ Put commit message to internal buffer. diff --git a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer.py b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer.py index aa5fe9749a7f..a3e407ed86de 100644 --- a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer.py +++ b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer.py @@ -11,6 +11,7 @@ import ydb.aio from .._grpc.grpcwrapper.ydb_topic import StreamWriteMessage +from .._grpc.grpcwrapper.ydb_topic import TransactionIdentity from .._grpc.grpcwrapper.common_utils import IToProto from .._grpc.grpcwrapper.ydb_topic_public_types import PublicCodec from .. import connection @@ -53,8 +54,12 @@ class Written: class Skipped: pass + @dataclass(eq=True) + class WrittenInTx: + pass + -PublicWriteResultTypes = Union[PublicWriteResult.Written, PublicWriteResult.Skipped] +PublicWriteResultTypes = Union[PublicWriteResult.Written, PublicWriteResult.Skipped, PublicWriteResult.WrittenInTx] class WriterSettings(PublicWriterSettings): @@ -205,6 +210,7 @@ def default_serializer_message_content(data: Any) -> bytes: def messages_to_proto_requests( messages: List[InternalMessage], + tx_identity: Optional[TransactionIdentity], ) -> List[StreamWriteMessage.FromClient]: gropus = _slit_messages_for_send(messages) @@ -215,6 +221,7 @@ def messages_to_proto_requests( StreamWriteMessage.WriteRequest( messages=list(map(InternalMessage.to_message_data, group)), codec=group[0].codec, + tx_identity=tx_identity, ) ) res.append(req) @@ -239,6 +246,7 @@ def messages_to_proto_requests( ), ], codec=20000, + tx_identity=None, ) ) .to_proto() diff --git a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_asyncio.py b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_asyncio.py index 32d8fefe51c2..ec5b21661d43 100644 --- a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_asyncio.py +++ b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_asyncio.py @@ -1,7 +1,6 @@ import asyncio import concurrent.futures import datetime -import functools import gzip import typing from collections import deque @@ -35,6 +34,7 @@ UpdateTokenRequest, UpdateTokenResponse, StreamWriteMessage, + TransactionIdentity, WriterMessagesFromServerToClient, ) from .._grpc.grpcwrapper.common_utils import ( @@ -43,6 +43,11 @@ GrpcWrapperAsyncIO, ) +from ..query.base import TxEvent + +if typing.TYPE_CHECKING: + from ..query.transaction import BaseQueryTxContext + logger = logging.getLogger(__name__) @@ -76,8 +81,12 @@ async def __aexit__(self, exc_type, exc_val, exc_tb): def __del__(self): if self._closed or self._loop.is_closed(): return - - self._loop.call_soon(functools.partial(self.close, flush=False)) + try: + logger.warning("Topic writer was not closed properly. Consider using method close().") + task = self._loop.create_task(self.close(flush=False)) + topic_common.wrap_set_name_for_asyncio_task(task, task_name="close writer") + except BaseException: + logger.warning("Something went wrong during writer close in __del__") async def close(self, *, flush: bool = True): if self._closed: @@ -164,6 +173,57 @@ async def wait_init(self) -> PublicWriterInitInfo: return await self._reconnector.wait_init() +class TxWriterAsyncIO(WriterAsyncIO): + _tx: "BaseQueryTxContext" + + def __init__( + self, + tx: "BaseQueryTxContext", + driver: SupportedDriverType, + settings: PublicWriterSettings, + _client=None, + _is_implicit=False, + ): + self._tx = tx + self._loop = asyncio.get_running_loop() + self._closed = False + self._reconnector = WriterAsyncIOReconnector(driver=driver, settings=WriterSettings(settings), tx=self._tx) + self._parent = _client + self._is_implicit = _is_implicit + + # For some reason, creating partition could conflict with other session operations. + # Could be removed later. + self._first_write = True + + tx._add_callback(TxEvent.BEFORE_COMMIT, self._on_before_commit, self._loop) + tx._add_callback(TxEvent.BEFORE_ROLLBACK, self._on_before_rollback, self._loop) + + async def write( + self, + messages: Union[Message, List[Message]], + ): + """ + send one or number of messages to server. + it put message to internal buffer + + For wait with timeout use asyncio.wait_for. + """ + if self._first_write: + self._first_write = False + return await super().write_with_ack(messages) + return await super().write(messages) + + async def _on_before_commit(self, tx: "BaseQueryTxContext"): + if self._is_implicit: + return + await self.close() + + async def _on_before_rollback(self, tx: "BaseQueryTxContext"): + if self._is_implicit: + return + await self.close(flush=False) + + class WriterAsyncIOReconnector: _closed: bool _loop: asyncio.AbstractEventLoop @@ -178,6 +238,7 @@ class WriterAsyncIOReconnector: _codec_selector_batch_num: int _codec_selector_last_codec: Optional[PublicCodec] _codec_selector_check_batches_interval: int + _tx: Optional["BaseQueryTxContext"] if typing.TYPE_CHECKING: _messages_for_encode: asyncio.Queue[List[InternalMessage]] @@ -195,7 +256,9 @@ class WriterAsyncIOReconnector: _stop_reason: asyncio.Future _init_info: Optional[PublicWriterInitInfo] - def __init__(self, driver: SupportedDriverType, settings: WriterSettings): + def __init__( + self, driver: SupportedDriverType, settings: WriterSettings, tx: Optional["BaseQueryTxContext"] = None + ): self._closed = False self._loop = asyncio.get_running_loop() self._driver = driver @@ -205,6 +268,7 @@ def __init__(self, driver: SupportedDriverType, settings: WriterSettings): self._init_info = None self._stream_connected = asyncio.Event() self._settings = settings + self._tx = tx self._codec_functions = { PublicCodec.RAW: lambda data: data, @@ -354,10 +418,12 @@ async def _connection_loop(self): # noinspection PyBroadException stream_writer = None try: + tx_identity = None if self._tx is None else self._tx._tx_identity() stream_writer = await WriterAsyncIOStream.create( self._driver, self._init_message, self._settings.update_token_interval, + tx_identity=tx_identity, ) try: if self._init_info is None: @@ -387,7 +453,7 @@ async def _connection_loop(self): done.pop().result() # need for raise exception - reason of stop task except issues.Error as err: err_info = check_retriable_error(err, retry_settings, attempt) - if not err_info.is_retriable: + if not err_info.is_retriable or self._tx is not None: # no retries in tx writer self._stop(err) return @@ -533,6 +599,8 @@ def _handle_receive_ack(self, ack): result = PublicWriteResult.Skipped() elif isinstance(status, write_ack_msg.StatusWritten): result = PublicWriteResult.Written(offset=status.offset) + elif isinstance(status, write_ack_msg.StatusWrittenInTx): + result = PublicWriteResult.WrittenInTx() else: raise TopicWriterError("internal error - receive unexpected ack message.") message_future.set_result(result) @@ -597,10 +665,13 @@ class WriterAsyncIOStream: _update_token_event: asyncio.Event _get_token_function: Optional[Callable[[], str]] + _tx_identity: Optional[TransactionIdentity] + def __init__( self, update_token_interval: Optional[Union[int, float]] = None, get_token_function: Optional[Callable[[], str]] = None, + tx_identity: Optional[TransactionIdentity] = None, ): self._closed = False @@ -609,6 +680,8 @@ def __init__( self._update_token_event = asyncio.Event() self._update_token_task = None + self._tx_identity = tx_identity + async def close(self): if self._closed: return @@ -625,6 +698,7 @@ async def create( driver: SupportedDriverType, init_request: StreamWriteMessage.InitRequest, update_token_interval: Optional[Union[int, float]] = None, + tx_identity: Optional[TransactionIdentity] = None, ) -> "WriterAsyncIOStream": stream = GrpcWrapperAsyncIO(StreamWriteMessage.FromServer.from_proto) @@ -634,6 +708,7 @@ async def create( writer = WriterAsyncIOStream( update_token_interval=update_token_interval, get_token_function=creds.get_auth_token if creds else lambda: "", + tx_identity=tx_identity, ) await writer._start(stream, init_request) return writer @@ -680,7 +755,7 @@ def write(self, messages: List[InternalMessage]): if self._closed: raise RuntimeError("Can not write on closed stream.") - for request in messages_to_proto_requests(messages): + for request in messages_to_proto_requests(messages, self._tx_identity): self._stream.write(request) async def _update_token_loop(self): diff --git a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_sync.py b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_sync.py index a5193caf7c55..954864c96822 100644 --- a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_sync.py +++ b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_sync.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import logging import typing from concurrent.futures import Future from typing import Union, List, Optional @@ -14,13 +15,23 @@ TopicWriterClosedError, ) -from .topic_writer_asyncio import WriterAsyncIO +from ..query.base import TxEvent + +from .topic_writer_asyncio import ( + TxWriterAsyncIO, + WriterAsyncIO, +) from .._topic_common.common import ( _get_shared_event_loop, TimeoutType, CallFromSyncToAsync, ) +if typing.TYPE_CHECKING: + from ..query.transaction import BaseQueryTxContext + +logger = logging.getLogger(__name__) + class WriterSync: _caller: CallFromSyncToAsync @@ -63,7 +74,12 @@ def __exit__(self, exc_type, exc_val, exc_tb): raise def __del__(self): - self.close(flush=False) + if not self._closed: + try: + logger.warning("Topic writer was not closed properly. Consider using method close().") + self.close(flush=False) + except BaseException: + logger.warning("Something went wrong during writer close in __del__") def close(self, *, flush: bool = True, timeout: TimeoutType = None): if self._closed: @@ -122,3 +138,39 @@ def write_with_ack( self._check_closed() return self._caller.unsafe_call_with_result(self._async_writer.write_with_ack(messages), timeout=timeout) + + +class TxWriterSync(WriterSync): + def __init__( + self, + tx: "BaseQueryTxContext", + driver: SupportedDriverType, + settings: PublicWriterSettings, + *, + eventloop: Optional[asyncio.AbstractEventLoop] = None, + _parent=None, + ): + + self._closed = False + + if eventloop: + loop = eventloop + else: + loop = _get_shared_event_loop() + + self._caller = CallFromSyncToAsync(loop) + + async def create_async_writer(): + return TxWriterAsyncIO(tx, driver, settings, _is_implicit=True) + + self._async_writer = self._caller.safe_call_with_result(create_async_writer(), None) + self._parent = _parent + + tx._add_callback(TxEvent.BEFORE_COMMIT, self._on_before_commit, None) + tx._add_callback(TxEvent.BEFORE_ROLLBACK, self._on_before_rollback, None) + + def _on_before_commit(self, tx: "BaseQueryTxContext"): + self.close() + + def _on_before_rollback(self, tx: "BaseQueryTxContext"): + self.close(flush=False) diff --git a/contrib/python/ydb/py3/ydb/aio/driver.py b/contrib/python/ydb/py3/ydb/aio/driver.py index 9cd6fd2b74d6..267997fbcc3e 100644 --- a/contrib/python/ydb/py3/ydb/aio/driver.py +++ b/contrib/python/ydb/py3/ydb/aio/driver.py @@ -62,4 +62,5 @@ def __init__( async def stop(self, timeout=10): await self.table_client._stop_pool_if_needed(timeout=timeout) + self.topic_client.close() await super().stop(timeout=timeout) diff --git a/contrib/python/ydb/py3/ydb/aio/query/pool.py b/contrib/python/ydb/py3/ydb/aio/query/pool.py index 947db658726c..f1ca68d1cf05 100644 --- a/contrib/python/ydb/py3/ydb/aio/query/pool.py +++ b/contrib/python/ydb/py3/ydb/aio/query/pool.py @@ -158,6 +158,8 @@ async def retry_tx_async( async def wrapped_callee(): async with self.checkout() as session: async with session.transaction(tx_mode=tx_mode) as tx: + if tx_mode.name in ["serializable_read_write", "snapshot_read_only"]: + await tx.begin() result = await callee(tx, *args, **kwargs) await tx.commit() return result @@ -213,12 +215,6 @@ async def __aenter__(self): async def __aexit__(self, exc_type, exc_val, exc_tb): await self.stop() - def __del__(self): - if self._should_stop.is_set() or self._loop.is_closed(): - return - - self._loop.call_soon(self.stop) - class SimpleQuerySessionCheckoutAsync: def __init__(self, pool: QuerySessionPool): diff --git a/contrib/python/ydb/py3/ydb/aio/query/transaction.py b/contrib/python/ydb/py3/ydb/aio/query/transaction.py index 5b63a32b489d..f0547e5f01fe 100644 --- a/contrib/python/ydb/py3/ydb/aio/query/transaction.py +++ b/contrib/python/ydb/py3/ydb/aio/query/transaction.py @@ -16,6 +16,28 @@ class QueryTxContext(BaseQueryTxContext): + def __init__(self, driver, session_state, session, tx_mode): + """ + An object that provides a simple transaction context manager that allows statements execution + in a transaction. You don't have to open transaction explicitly, because context manager encapsulates + transaction control logic, and opens new transaction if: + + 1) By explicit .begin() method; + 2) On execution of a first statement, which is strictly recommended method, because that avoids useless round trip + + This context manager is not thread-safe, so you should not manipulate on it concurrently. + + :param driver: A driver instance + :param session_state: A state of session + :param tx_mode: Transaction mode, which is a one from the following choises: + 1) QuerySerializableReadWrite() which is default mode; + 2) QueryOnlineReadOnly(allow_inconsistent_reads=False); + 3) QuerySnapshotReadOnly(); + 4) QueryStaleReadOnly(). + """ + super().__init__(driver, session_state, session, tx_mode) + self._init_callback_handler(base.CallbackHandlerMode.ASYNC) + async def __aenter__(self) -> "QueryTxContext": """ Enters a context manager and returns a transaction @@ -30,7 +52,7 @@ async def __aexit__(self, *args, **kwargs): it is not finished explicitly """ await self._ensure_prev_stream_finished() - if self._tx_state._state == QueryTxStateEnum.BEGINED: + if self._tx_state._state == QueryTxStateEnum.BEGINED and self._external_error is None: # It's strictly recommended to close transactions directly # by using commit_tx=True flag while executing statement or by # .commit() or .rollback() methods, but here we trying to do best @@ -65,7 +87,9 @@ async def commit(self, settings: Optional[BaseRequestSettings] = None) -> None: :return: A committed transaction or exception if commit is failed """ - if self._tx_state._already_in(QueryTxStateEnum.COMMITTED): + self._check_external_error_set() + + if self._tx_state._should_skip(QueryTxStateEnum.COMMITTED): return if self._tx_state._state == QueryTxStateEnum.NOT_INITIALIZED: @@ -74,7 +98,13 @@ async def commit(self, settings: Optional[BaseRequestSettings] = None) -> None: await self._ensure_prev_stream_finished() - await self._commit_call(settings) + try: + await self._execute_callbacks_async(base.TxEvent.BEFORE_COMMIT) + await self._commit_call(settings) + await self._execute_callbacks_async(base.TxEvent.AFTER_COMMIT, exc=None) + except BaseException as e: + await self._execute_callbacks_async(base.TxEvent.AFTER_COMMIT, exc=e) + raise e async def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None: """Calls rollback on a transaction if it is open otherwise is no-op. If transaction execution @@ -84,7 +114,9 @@ async def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None :return: A committed transaction or exception if commit is failed """ - if self._tx_state._already_in(QueryTxStateEnum.ROLLBACKED): + self._check_external_error_set() + + if self._tx_state._should_skip(QueryTxStateEnum.ROLLBACKED): return if self._tx_state._state == QueryTxStateEnum.NOT_INITIALIZED: @@ -93,7 +125,13 @@ async def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None await self._ensure_prev_stream_finished() - await self._rollback_call(settings) + try: + await self._execute_callbacks_async(base.TxEvent.BEFORE_ROLLBACK) + await self._rollback_call(settings) + await self._execute_callbacks_async(base.TxEvent.AFTER_ROLLBACK, exc=None) + except BaseException as e: + await self._execute_callbacks_async(base.TxEvent.AFTER_ROLLBACK, exc=e) + raise e async def execute( self, diff --git a/contrib/python/ydb/py3/ydb/driver.py b/contrib/python/ydb/py3/ydb/driver.py index 49bd223c9018..3998aeeef5ff 100644 --- a/contrib/python/ydb/py3/ydb/driver.py +++ b/contrib/python/ydb/py3/ydb/driver.py @@ -288,4 +288,5 @@ def __init__( def stop(self, timeout=10): self.table_client._stop_pool_if_needed(timeout=timeout) + self.topic_client.close() super().stop(timeout=timeout) diff --git a/contrib/python/ydb/py3/ydb/issues.py b/contrib/python/ydb/py3/ydb/issues.py index f38f99f92578..4e76f5ed2b02 100644 --- a/contrib/python/ydb/py3/ydb/issues.py +++ b/contrib/python/ydb/py3/ydb/issues.py @@ -178,6 +178,10 @@ class SessionPoolEmpty(Error, queue.Empty): status = StatusCode.SESSION_POOL_EMPTY +class ClientInternalError(Error): + status = StatusCode.CLIENT_INTERNAL_ERROR + + class UnexpectedGrpcMessage(Error): def __init__(self, message: str): super().__init__(message) diff --git a/contrib/python/ydb/py3/ydb/query/base.py b/contrib/python/ydb/py3/ydb/query/base.py index 57a769bb1a12..a5ebedd95b37 100644 --- a/contrib/python/ydb/py3/ydb/query/base.py +++ b/contrib/python/ydb/py3/ydb/query/base.py @@ -1,6 +1,8 @@ import abc +import asyncio import enum import functools +from collections import defaultdict import typing from typing import ( @@ -17,6 +19,10 @@ from .. import _utilities from .. import _apis +from ydb._topic_common.common import CallFromSyncToAsync, _get_shared_event_loop +from ydb._grpc.grpcwrapper.common_utils import to_thread + + if typing.TYPE_CHECKING: from .transaction import BaseQueryTxContext @@ -196,3 +202,64 @@ def wrap_execute_query_response( return convert.ResultSet.from_message(response_pb.result_set, settings) return None + + +class TxEvent(enum.Enum): + BEFORE_COMMIT = "BEFORE_COMMIT" + AFTER_COMMIT = "AFTER_COMMIT" + BEFORE_ROLLBACK = "BEFORE_ROLLBACK" + AFTER_ROLLBACK = "AFTER_ROLLBACK" + + +class CallbackHandlerMode(enum.Enum): + SYNC = "SYNC" + ASYNC = "ASYNC" + + +def _get_sync_callback(method: typing.Callable, loop: Optional[asyncio.AbstractEventLoop]): + if asyncio.iscoroutinefunction(method): + if loop is None: + loop = _get_shared_event_loop() + + def async_to_sync_callback(*args, **kwargs): + caller = CallFromSyncToAsync(loop) + return caller.safe_call_with_result(method(*args, **kwargs), 10) + + return async_to_sync_callback + return method + + +def _get_async_callback(method: typing.Callable): + if asyncio.iscoroutinefunction(method): + return method + + async def sync_to_async_callback(*args, **kwargs): + return await to_thread(method, *args, **kwargs, executor=None) + + return sync_to_async_callback + + +class CallbackHandler: + def _init_callback_handler(self, mode: CallbackHandlerMode) -> None: + self._callbacks = defaultdict(list) + self._callback_mode = mode + + def _execute_callbacks_sync(self, event_name: str, *args, **kwargs) -> None: + for callback in self._callbacks[event_name]: + callback(self, *args, **kwargs) + + async def _execute_callbacks_async(self, event_name: str, *args, **kwargs) -> None: + tasks = [asyncio.create_task(callback(self, *args, **kwargs)) for callback in self._callbacks[event_name]] + if not tasks: + return + await asyncio.gather(*tasks) + + def _prepare_callback( + self, callback: typing.Callable, loop: Optional[asyncio.AbstractEventLoop] + ) -> typing.Callable: + if self._callback_mode == CallbackHandlerMode.SYNC: + return _get_sync_callback(callback, loop) + return _get_async_callback(callback) + + def _add_callback(self, event_name: str, callback: typing.Callable, loop: Optional[asyncio.AbstractEventLoop]): + self._callbacks[event_name].append(self._prepare_callback(callback, loop)) diff --git a/contrib/python/ydb/py3/ydb/query/pool.py b/contrib/python/ydb/py3/ydb/query/pool.py index e3775c4dd121..b25f7db855cf 100644 --- a/contrib/python/ydb/py3/ydb/query/pool.py +++ b/contrib/python/ydb/py3/ydb/query/pool.py @@ -167,6 +167,8 @@ def retry_tx_sync( def wrapped_callee(): with self.checkout(timeout=retry_settings.max_session_acquire_timeout) as session: with session.transaction(tx_mode=tx_mode) as tx: + if tx_mode.name in ["serializable_read_write", "snapshot_read_only"]: + tx.begin() result = callee(tx, *args, **kwargs) tx.commit() return result @@ -224,9 +226,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_val, exc_tb): self.stop() - def __del__(self): - self.stop() - class SimpleQuerySessionCheckout: def __init__(self, pool: QuerySessionPool, timeout: Optional[float]): diff --git a/contrib/python/ydb/py3/ydb/query/transaction.py b/contrib/python/ydb/py3/ydb/query/transaction.py index 414401da4d1e..ae7642dbe216 100644 --- a/contrib/python/ydb/py3/ydb/query/transaction.py +++ b/contrib/python/ydb/py3/ydb/query/transaction.py @@ -11,6 +11,7 @@ _apis, issues, ) +from .._grpc.grpcwrapper import ydb_topic as _ydb_topic from .._grpc.grpcwrapper import ydb_query as _ydb_query from ..connection import _RpcState as RpcState @@ -42,10 +43,22 @@ class QueryTxStateHelper(abc.ABC): QueryTxStateEnum.DEAD: [], } + _SKIP_TRANSITIONS = { + QueryTxStateEnum.NOT_INITIALIZED: [], + QueryTxStateEnum.BEGINED: [], + QueryTxStateEnum.COMMITTED: [QueryTxStateEnum.COMMITTED, QueryTxStateEnum.ROLLBACKED], + QueryTxStateEnum.ROLLBACKED: [QueryTxStateEnum.COMMITTED, QueryTxStateEnum.ROLLBACKED], + QueryTxStateEnum.DEAD: [], + } + @classmethod def valid_transition(cls, before: QueryTxStateEnum, after: QueryTxStateEnum) -> bool: return after in cls._VALID_TRANSITIONS[before] + @classmethod + def should_skip(cls, before: QueryTxStateEnum, after: QueryTxStateEnum) -> bool: + return after in cls._SKIP_TRANSITIONS[before] + @classmethod def terminal(cls, state: QueryTxStateEnum) -> bool: return len(cls._VALID_TRANSITIONS[state]) == 0 @@ -88,8 +101,8 @@ def _check_tx_ready_to_use(self) -> None: if QueryTxStateHelper.terminal(self._state): raise RuntimeError(f"Transaction is in terminal state: {self._state.value}") - def _already_in(self, target: QueryTxStateEnum) -> bool: - return self._state == target + def _should_skip(self, target: QueryTxStateEnum) -> bool: + return QueryTxStateHelper.should_skip(self._state, target) def _construct_tx_settings(tx_state: QueryTxState) -> _ydb_query.TransactionSettings: @@ -170,7 +183,7 @@ def wrap_tx_rollback_response( return tx -class BaseQueryTxContext: +class BaseQueryTxContext(base.CallbackHandler): def __init__(self, driver, session_state, session, tx_mode): """ An object that provides a simple transaction context manager that allows statements execution @@ -196,6 +209,7 @@ def __init__(self, driver, session_state, session, tx_mode): self._session_state = session_state self.session = session self._prev_stream = None + self._external_error = None @property def session_id(self) -> str: @@ -215,6 +229,19 @@ def tx_id(self) -> Optional[str]: """ return self._tx_state.tx_id + def _tx_identity(self) -> _ydb_topic.TransactionIdentity: + if not self.tx_id: + raise RuntimeError("Unable to get tx identity without started tx.") + return _ydb_topic.TransactionIdentity(self.tx_id, self.session_id) + + def _set_external_error(self, exc: BaseException) -> None: + self._external_error = exc + + def _check_external_error_set(self): + if self._external_error is None: + return + raise issues.ClientInternalError("Transaction was failed by external error.") from self._external_error + def _begin_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxContext": self._tx_state._check_invalid_transition(QueryTxStateEnum.BEGINED) @@ -228,6 +255,7 @@ def _begin_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxCo ) def _commit_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxContext": + self._check_external_error_set() self._tx_state._check_invalid_transition(QueryTxStateEnum.COMMITTED) return self._driver( @@ -240,6 +268,7 @@ def _commit_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxC ) def _rollback_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxContext": + self._check_external_error_set() self._tx_state._check_invalid_transition(QueryTxStateEnum.ROLLBACKED) return self._driver( @@ -262,6 +291,7 @@ def _execute_call( settings: Optional[BaseRequestSettings], ) -> Iterable[_apis.ydb_query.ExecuteQueryResponsePart]: self._tx_state._check_tx_ready_to_use() + self._check_external_error_set() request = base.create_execute_query_request( query=query, @@ -283,18 +313,41 @@ def _execute_call( ) def _move_to_beginned(self, tx_id: str) -> None: - if self._tx_state._already_in(QueryTxStateEnum.BEGINED) or not tx_id: + if self._tx_state._should_skip(QueryTxStateEnum.BEGINED) or not tx_id: return self._tx_state._change_state(QueryTxStateEnum.BEGINED) self._tx_state.tx_id = tx_id def _move_to_commited(self) -> None: - if self._tx_state._already_in(QueryTxStateEnum.COMMITTED): + if self._tx_state._should_skip(QueryTxStateEnum.COMMITTED): return self._tx_state._change_state(QueryTxStateEnum.COMMITTED) class QueryTxContext(BaseQueryTxContext): + def __init__(self, driver, session_state, session, tx_mode): + """ + An object that provides a simple transaction context manager that allows statements execution + in a transaction. You don't have to open transaction explicitly, because context manager encapsulates + transaction control logic, and opens new transaction if: + + 1) By explicit .begin() method; + 2) On execution of a first statement, which is strictly recommended method, because that avoids useless round trip + + This context manager is not thread-safe, so you should not manipulate on it concurrently. + + :param driver: A driver instance + :param session_state: A state of session + :param tx_mode: Transaction mode, which is a one from the following choises: + 1) QuerySerializableReadWrite() which is default mode; + 2) QueryOnlineReadOnly(allow_inconsistent_reads=False); + 3) QuerySnapshotReadOnly(); + 4) QueryStaleReadOnly(). + """ + + super().__init__(driver, session_state, session, tx_mode) + self._init_callback_handler(base.CallbackHandlerMode.SYNC) + def __enter__(self) -> "BaseQueryTxContext": """ Enters a context manager and returns a transaction @@ -309,7 +362,7 @@ def __exit__(self, *args, **kwargs): it is not finished explicitly """ self._ensure_prev_stream_finished() - if self._tx_state._state == QueryTxStateEnum.BEGINED: + if self._tx_state._state == QueryTxStateEnum.BEGINED and self._external_error is None: # It's strictly recommended to close transactions directly # by using commit_tx=True flag while executing statement or by # .commit() or .rollback() methods, but here we trying to do best @@ -345,7 +398,8 @@ def commit(self, settings: Optional[BaseRequestSettings] = None) -> None: :return: A committed transaction or exception if commit is failed """ - if self._tx_state._already_in(QueryTxStateEnum.COMMITTED): + self._check_external_error_set() + if self._tx_state._should_skip(QueryTxStateEnum.COMMITTED): return if self._tx_state._state == QueryTxStateEnum.NOT_INITIALIZED: @@ -354,7 +408,13 @@ def commit(self, settings: Optional[BaseRequestSettings] = None) -> None: self._ensure_prev_stream_finished() - self._commit_call(settings) + try: + self._execute_callbacks_sync(base.TxEvent.BEFORE_COMMIT) + self._commit_call(settings) + self._execute_callbacks_sync(base.TxEvent.AFTER_COMMIT, exc=None) + except BaseException as e: # TODO: probably should be less wide + self._execute_callbacks_sync(base.TxEvent.AFTER_COMMIT, exc=e) + raise e def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None: """Calls rollback on a transaction if it is open otherwise is no-op. If transaction execution @@ -364,7 +424,8 @@ def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None: :return: A committed transaction or exception if commit is failed """ - if self._tx_state._already_in(QueryTxStateEnum.ROLLBACKED): + self._check_external_error_set() + if self._tx_state._should_skip(QueryTxStateEnum.ROLLBACKED): return if self._tx_state._state == QueryTxStateEnum.NOT_INITIALIZED: @@ -373,7 +434,13 @@ def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None: self._ensure_prev_stream_finished() - self._rollback_call(settings) + try: + self._execute_callbacks_sync(base.TxEvent.BEFORE_ROLLBACK) + self._rollback_call(settings) + self._execute_callbacks_sync(base.TxEvent.AFTER_ROLLBACK, exc=None) + except BaseException as e: # TODO: probably should be less wide + self._execute_callbacks_sync(base.TxEvent.AFTER_ROLLBACK, exc=e) + raise e def execute( self, diff --git a/contrib/python/ydb/py3/ydb/table.py b/contrib/python/ydb/py3/ydb/table.py index 945e91876771..ac73902f3cf7 100644 --- a/contrib/python/ydb/py3/ydb/table.py +++ b/contrib/python/ydb/py3/ydb/table.py @@ -545,6 +545,9 @@ class TableStats(object): def __init__(self): self.partitions = None self.store_size = 0 + self.rows_estimate = 0 + self.creation_time = None + self.modification_time = None def with_store_size(self, store_size): self.store_size = store_size @@ -554,6 +557,18 @@ def with_partitions(self, partitions): self.partitions = partitions return self + def with_rows_estimate(self, rows_estimate): + self.rows_estimate = rows_estimate + return self + + def with_creation_time(self, creation_time): + self.creation_time = creation_time + return self + + def with_modification_time(self, modification_time): + self.modification_time = modification_time + return self + class ReadReplicasSettings(object): def __init__(self): @@ -1577,7 +1592,22 @@ def __init__( self.table_stats = None if table_stats is not None: + from ._grpc.grpcwrapper.common_utils import datetime_from_proto_timestamp + self.table_stats = TableStats() + if table_stats.creation_time: + self.table_stats = self.table_stats.with_creation_time( + datetime_from_proto_timestamp(table_stats.creation_time) + ) + + if table_stats.modification_time: + self.table_stats = self.table_stats.with_modification_time( + datetime_from_proto_timestamp(table_stats.modification_time) + ) + + if table_stats.rows_estimate != 0: + self.table_stats = self.table_stats.with_rows_estimate(table_stats.rows_estimate) + if table_stats.partitions != 0: self.table_stats = self.table_stats.with_partitions(table_stats.partitions) diff --git a/contrib/python/ydb/py3/ydb/topic.py b/contrib/python/ydb/py3/ydb/topic.py index 55f4ea04c5ca..a501f9d2750a 100644 --- a/contrib/python/ydb/py3/ydb/topic.py +++ b/contrib/python/ydb/py3/ydb/topic.py @@ -25,6 +25,8 @@ "TopicWriteResult", "TopicWriter", "TopicWriterAsyncIO", + "TopicTxWriter", + "TopicTxWriterAsyncIO", "TopicWriterInitInfo", "TopicWriterMessage", "TopicWriterSettings", @@ -33,6 +35,7 @@ import concurrent.futures import datetime from dataclasses import dataclass +import logging from typing import List, Union, Mapping, Optional, Dict, Callable from . import aio, Credentials, _apis, issues @@ -65,8 +68,10 @@ PublicWriteResult as TopicWriteResult, ) +from ydb._topic_writer.topic_writer_asyncio import TxWriterAsyncIO as TopicTxWriterAsyncIO from ydb._topic_writer.topic_writer_asyncio import WriterAsyncIO as TopicWriterAsyncIO from ._topic_writer.topic_writer_sync import WriterSync as TopicWriter +from ._topic_writer.topic_writer_sync import TxWriterSync as TopicTxWriter from ._topic_common.common import ( wrap_operation as _wrap_operation, @@ -88,6 +93,8 @@ PublicAlterAutoPartitioningSettings as TopicAlterAutoPartitioningSettings, ) +logger = logging.getLogger(__name__) + class TopicClientAsyncIO: _closed: bool @@ -108,7 +115,12 @@ def __init__(self, driver: aio.Driver, settings: Optional[TopicClientSettings] = ) def __del__(self): - self.close() + if not self._closed: + try: + logger.warning("Topic client was not closed properly. Consider using method close().") + self.close() + except BaseException: + logger.warning("Something went wrong during topic client close in __del__") async def create_topic( self, @@ -276,6 +288,35 @@ def writer( return TopicWriterAsyncIO(self._driver, settings, _client=self) + def tx_writer( + self, + tx, + topic, + *, + producer_id: Optional[str] = None, # default - random + session_metadata: Mapping[str, str] = None, + partition_id: Union[int, None] = None, + auto_seqno: bool = True, + auto_created_at: bool = True, + codec: Optional[TopicCodec] = None, # default mean auto-select + # encoders: map[codec_code] func(encoded_bytes)->decoded_bytes + # the func will be called from multiply threads in parallel. + encoders: Optional[Mapping[_ydb_topic_public_types.PublicCodec, Callable[[bytes], bytes]]] = None, + # custom encoder executor for call builtin and custom decoders. If None - use shared executor pool. + # If max_worker in the executor is 1 - then encoders will be called from the thread without parallel. + encoder_executor: Optional[concurrent.futures.Executor] = None, + ) -> TopicTxWriterAsyncIO: + args = locals().copy() + del args["self"] + del args["tx"] + + settings = TopicWriterSettings(**args) + + if not settings.encoder_executor: + settings.encoder_executor = self._executor + + return TopicTxWriterAsyncIO(tx=tx, driver=self._driver, settings=settings, _client=self) + def close(self): if self._closed: return @@ -287,7 +328,7 @@ def _check_closed(self): if not self._closed: return - raise RuntimeError("Topic client closed") + raise issues.Error("Topic client closed") class TopicClient: @@ -310,7 +351,12 @@ def __init__(self, driver: driver.Driver, settings: Optional[TopicClientSettings ) def __del__(self): - self.close() + if not self._closed: + try: + logger.warning("Topic client was not closed properly. Consider using method close().") + self.close() + except BaseException: + logger.warning("Something went wrong during topic client close in __del__") def create_topic( self, @@ -487,6 +533,36 @@ def writer( return TopicWriter(self._driver, settings, _parent=self) + def tx_writer( + self, + tx, + topic, + *, + producer_id: Optional[str] = None, # default - random + session_metadata: Mapping[str, str] = None, + partition_id: Union[int, None] = None, + auto_seqno: bool = True, + auto_created_at: bool = True, + codec: Optional[TopicCodec] = None, # default mean auto-select + # encoders: map[codec_code] func(encoded_bytes)->decoded_bytes + # the func will be called from multiply threads in parallel. + encoders: Optional[Mapping[_ydb_topic_public_types.PublicCodec, Callable[[bytes], bytes]]] = None, + # custom encoder executor for call builtin and custom decoders. If None - use shared executor pool. + # If max_worker in the executor is 1 - then encoders will be called from the thread without parallel. + encoder_executor: Optional[concurrent.futures.Executor] = None, # default shared client executor pool + ) -> TopicWriter: + args = locals().copy() + del args["self"] + del args["tx"] + self._check_closed() + + settings = TopicWriterSettings(**args) + + if not settings.encoder_executor: + settings.encoder_executor = self._executor + + return TopicTxWriter(tx, self._driver, settings, _parent=self) + def close(self): if self._closed: return @@ -498,7 +574,7 @@ def _check_closed(self): if not self._closed: return - raise RuntimeError("Topic client closed") + raise issues.Error("Topic client closed") @dataclass diff --git a/contrib/python/ydb/py3/ydb/ydb_version.py b/contrib/python/ydb/py3/ydb/ydb_version.py index 8bd658d49e45..4a5c580f99f0 100644 --- a/contrib/python/ydb/py3/ydb/ydb_version.py +++ b/contrib/python/ydb/py3/ydb/ydb_version.py @@ -1 +1 @@ -VERSION = "3.19.3" +VERSION = "3.20.1" diff --git a/library/cpp/containers/dense_hash/dense_hash.h b/library/cpp/containers/dense_hash/dense_hash.h index 739479c25a36..b5feb16eefb7 100644 --- a/library/cpp/containers/dense_hash/dense_hash.h +++ b/library/cpp/containers/dense_hash/dense_hash.h @@ -168,14 +168,10 @@ class TDenseHash : public TMapOps tmp; - for (size_type i = 0; i < initSize; ++i) { - tmp.emplace_back(EmptyMarker, mapped_type{}); - } - tmp.swap(Buckets); - GrowThreshold = Max(1, initSize * MaxLoadFactor / 100) - 1; + Grow(initSize); } template diff --git a/library/cpp/getopt/small/last_getopt_opt.h b/library/cpp/getopt/small/last_getopt_opt.h index 8754ebb7eeb8..de3b10badec0 100644 --- a/library/cpp/getopt/small/last_getopt_opt.h +++ b/library/cpp/getopt/small/last_getopt_opt.h @@ -13,7 +13,6 @@ #include #include -#include namespace NLastGetopt { enum EHasArg { diff --git a/library/cpp/lwtrace/mon/analytics/util.h b/library/cpp/lwtrace/mon/analytics/util.h index e07d06cc43f9..fd2ec572af9b 100644 --- a/library/cpp/lwtrace/mon/analytics/util.h +++ b/library/cpp/lwtrace/mon/analytics/util.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace NAnalytics { diff --git a/library/cpp/monlib/consumers/collecting_consumer.h b/library/cpp/monlib/consumers/collecting_consumer.h index 0b061fce0bcb..9f9631bef0cd 100644 --- a/library/cpp/monlib/consumers/collecting_consumer.h +++ b/library/cpp/monlib/consumers/collecting_consumer.h @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -26,6 +27,7 @@ namespace NMonitoring { // TODO(ivanzhukov@): rename to Type NMonitoring::EMetricType Kind{NMonitoring::EMetricType::UNKNOWN}; THolder Values; + NMonitoring::TMetricOpts Opts; }; template @@ -96,6 +98,10 @@ namespace NMonitoring { val->Add(time, snapshot.Get()); } + virtual void OnMemOnly(bool isMemOnly) override{ + Metrics.back().Opts.MemOnly = isMemOnly; + } + bool DoMergeCommonLabels{false}; TVector Metrics; TLabelsImpl CommonLabels; diff --git a/library/cpp/monlib/dynamic_counters/page.cpp b/library/cpp/monlib/dynamic_counters/page.cpp index 5cd750026fb0..73b1309d814a 100644 --- a/library/cpp/monlib/dynamic_counters/page.cpp +++ b/library/cpp/monlib/dynamic_counters/page.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -26,6 +27,19 @@ TMaybe ParseFormat(TStringBuf str) { } } +namespace { + +TStringBuf GetParams(NMonitoring::IMonHttpRequest& request) { + TStringBuf uri = request.GetUri(); + TStringBuf params = uri.After('?'); + if (params.Size() == uri.Size()) { + params.Clear(); + } + return params; +} + +} + void TDynamicCountersPage::Output(NMonitoring::IMonHttpRequest& request) { if (OutputCallback) { OutputCallback(); @@ -37,28 +51,51 @@ void TDynamicCountersPage::Output(NMonitoring::IMonHttpRequest& request) { }; TVector parts; - StringSplitter(request.GetPathInfo()) - .Split('/') - .SkipEmpty() - .Collect(&parts); - - TMaybe format = !parts.empty() ? ParseFormat(parts.back()) : Nothing(); - if (format) { - parts.pop_back(); - } + TMaybe format; + TStringBuf params = GetParams(request); + + if (request.GetPathInfo().empty() && !params.empty()) { + StringSplitter(params).Split('&').SkipEmpty().Consume([&](TStringBuf part) { + TStringBuf name; + TStringBuf value; + part.Split('=', name, value); + if (name.StartsWith("@")) { + if (name == "@format") { + format = ParseFormat(value); + } else if (name == "@name_label") { + nameLabel = value; + } else if (name == "@private") { + visibility = TCountableBase::EVisibility::Private; + } + } else { + parts.push_back(part); + } + return true; + }); + } else { + StringSplitter(request.GetPathInfo()) + .Split('/') + .SkipEmpty() + .Collect(&parts); + + format = !parts.empty() ? ParseFormat(parts.back()) : Nothing(); + if (format) { + parts.pop_back(); + } - if (!parts.empty() && parts.back().StartsWith(TStringBuf("name_label="))) { - TVector labels; - StringSplitter(parts.back()).Split('=').SkipEmpty().Collect(&labels); - if (labels.size() == 2U) { - nameLabel = labels.back(); + if (!parts.empty() && parts.back().StartsWith(TStringBuf("name_label="))) { + TVector labels; + StringSplitter(parts.back()).Split('=').SkipEmpty().Collect(&labels); + if (labels.size() == 2U) { + nameLabel = labels.back(); + } + parts.pop_back(); } - parts.pop_back(); - } - if (!parts.empty() && parts.back() == TStringBuf("private")) { - visibility = TCountableBase::EVisibility::Private; - parts.pop_back(); + if (!parts.empty() && parts.back() == TStringBuf("private")) { + visibility = TCountableBase::EVisibility::Private; + parts.pop_back(); + } } auto counters = Counters; @@ -121,9 +158,15 @@ void TDynamicCountersPage::HandleAbsentSubgroup(IMonHttpRequest& request) { void TDynamicCountersPage::BeforePre(IMonHttpRequest& request) { IOutputStream& out = request.Output(); + TStringBuf params = GetParams(request); + TStringBuilder base; + base << Path << '?'; + if (!params.empty()) { + base << params << '&'; + } HTML(out) { DIV() { - out << "Counters as JSON"; + out << "Counters as JSON"; out << " for Solomon"; } @@ -133,9 +176,11 @@ void TDynamicCountersPage::BeforePre(IMonHttpRequest& request) { UL() { currentCounters->EnumerateSubgroups([&](const TString& name, const TString& value) { LI() { - TString pathPart = name + "=" + value; - Quote(pathPart, ""); - out << "\n" << name << " " << value << ""; + auto escName = name; + auto escValue = value; + Quote(escName); + Quote(escValue); + out << "\n" << name << " " << value << ""; } }); } diff --git a/library/cpp/monlib/metrics/fake.h b/library/cpp/monlib/metrics/fake.h index b01ff2505ad9..a058e1d99a10 100644 --- a/library/cpp/monlib/metrics/fake.h +++ b/library/cpp/monlib/metrics/fake.h @@ -82,6 +82,8 @@ namespace NMonitoring { i64 Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; struct TFakeRate final: public TFakeAcceptor { @@ -102,6 +104,8 @@ namespace NMonitoring { ui64 Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; struct TFakeGauge final: public TFakeAcceptor { @@ -117,12 +121,16 @@ namespace NMonitoring { double Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; struct TFakeLazyGauge final: public TFakeAcceptor { double Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; struct TFakeHistogram final: public IHistogram { @@ -169,5 +177,7 @@ namespace NMonitoring { ui64 Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; } // namespace NMonitoring diff --git a/library/cpp/monlib/metrics/metric.h b/library/cpp/monlib/metrics/metric.h index 2f7d9de687f6..bb5fda322ea5 100644 --- a/library/cpp/monlib/metrics/metric.h +++ b/library/cpp/monlib/metrics/metric.h @@ -15,6 +15,7 @@ namespace NMonitoring { virtual EMetricType Type() const noexcept = 0; virtual void Accept(TInstant time, IMetricConsumer* consumer) const = 0; + virtual void Reset() noexcept = 0; }; using IMetricPtr = TIntrusivePtr; @@ -28,7 +29,7 @@ namespace NMonitoring { virtual double Add(double n) noexcept = 0; virtual void Set(double n) noexcept = 0; virtual double Get() const noexcept = 0; - virtual void Reset() noexcept { + void Reset() noexcept override { Set(0); } }; @@ -58,7 +59,7 @@ namespace NMonitoring { virtual void Set(i64 value) noexcept = 0; virtual i64 Get() const noexcept = 0; - virtual void Reset() noexcept { + void Reset() noexcept override { Set(0); } }; @@ -84,7 +85,6 @@ namespace NMonitoring { virtual ui64 Add(ui64 n) noexcept = 0; virtual ui64 Get() const noexcept = 0; - virtual void Reset() noexcept = 0; }; class ILazyCounter: public IMetric { @@ -108,7 +108,6 @@ namespace NMonitoring { virtual ui64 Add(ui64 n) noexcept = 0; virtual ui64 Get() const noexcept = 0; - virtual void Reset() noexcept = 0; }; class ILazyRate: public IMetric { @@ -134,7 +133,6 @@ namespace NMonitoring { virtual void Record(double value) noexcept = 0; virtual void Record(double value, ui32 count) noexcept = 0; virtual IHistogramSnapshotPtr TakeSnapshot() const = 0; - virtual void Reset() noexcept = 0; protected: const bool IsRate_; @@ -194,6 +192,8 @@ namespace NMonitoring { consumer->OnDouble(time, Get()); } + void Reset() noexcept override {} + private: std::function Supplier_; }; @@ -245,6 +245,8 @@ namespace NMonitoring { consumer->OnInt64(time, Get()); } + void Reset() noexcept override {} + private: std::function Supplier_; }; @@ -296,6 +298,8 @@ namespace NMonitoring { consumer->OnUint64(time, Get()); } + void Reset() noexcept override {} + private: std::function Supplier_; }; @@ -347,6 +351,8 @@ namespace NMonitoring { consumer->OnUint64(time, Get()); } + void Reset() noexcept override {} + private: std::function Supplier_; }; diff --git a/library/cpp/monlib/metrics/metric_registry.cpp b/library/cpp/monlib/metrics/metric_registry.cpp index 245f65702d1d..dbbea603c164 100644 --- a/library/cpp/monlib/metrics/metric_registry.cpp +++ b/library/cpp/monlib/metrics/metric_registry.cpp @@ -226,29 +226,7 @@ namespace NMonitoring { void TMetricRegistry::Reset() { TWriteGuard g{*Lock_}; for (auto& [label, metricValue] : Metrics_) { - auto metric = metricValue.Metric; - switch (metric->Type()) { - case EMetricType::GAUGE: - static_cast(metric.Get())->Set(.0); - break; - case EMetricType::IGAUGE: - static_cast(metric.Get())->Set(0); - break; - case EMetricType::COUNTER: - static_cast(metric.Get())->Reset(); - break; - case EMetricType::RATE: - static_cast(metric.Get())->Reset(); - break; - case EMetricType::HIST: - case EMetricType::HIST_RATE: - static_cast(metric.Get())->Reset(); - break; - case EMetricType::UNKNOWN: - case EMetricType::DSUMMARY: - case EMetricType::LOGHIST: - break; - } + metricValue.Metric->Reset(); } } @@ -257,40 +235,6 @@ namespace NMonitoring { Metrics_.clear(); } - template - TMetric* TMetricRegistry::Metric(TLabelsType&& labels, TMetricOpts&& opts, Args&&... args) { - { - TReadGuard g{*Lock_}; - - auto it = Metrics_.find(labels); - if (it != Metrics_.end()) { - Y_ENSURE(it->second.Metric->Type() == type, "cannot create metric " << labels - << " with type " << MetricTypeToStr(type) - << ", because registry already has same metric with type " << MetricTypeToStr(it->second.Metric->Type())); - Y_ENSURE(it->second.Opts.MemOnly == opts.MemOnly,"cannot create metric " << labels - << " with memOnly=" << opts.MemOnly - << ", because registry already has same metric with memOnly=" << it->second.Opts.MemOnly); - return static_cast(it->second.Metric.Get()); - } - } - - { - IMetricPtr metric = MakeIntrusive(std::forward(args)...); - - TWriteGuard g{*Lock_}; - // decltype(Metrics_)::iterator breaks build on windows - THashMap::iterator it; - TMetricValue metricValue = {metric, opts}; - if constexpr (!std::is_convertible_v) { - it = Metrics_.emplace(new TLabels{std::forward(labels)}, std::move(metricValue)).first; - } else { - it = Metrics_.emplace(std::forward(labels), std::move(metricValue)).first; - } - - return static_cast(it->second.Metric.Get()); - } - } - void TMetricRegistry::RemoveMetric(const ILabels& labels) noexcept { TWriteGuard g{*Lock_}; Metrics_.erase(labels); diff --git a/library/cpp/monlib/metrics/metric_registry.h b/library/cpp/monlib/metrics/metric_registry.h index f60467cf9122..7669a8c08862 100644 --- a/library/cpp/monlib/metrics/metric_registry.h +++ b/library/cpp/monlib/metrics/metric_registry.h @@ -274,13 +274,45 @@ namespace NMonitoring { TMetricOpts Opts; }; + protected: + template + TMetric* Metric(TLabelsType&& labels, TMetricOpts&& opts, Args&&... args) { + { + TReadGuard g{*Lock_}; + + auto it = Metrics_.find(labels); + if (it != Metrics_.end()) { + Y_ENSURE(it->second.Metric->Type() == type, "cannot create metric " << labels + << " with type " << MetricTypeToStr(type) + << ", because registry already has same metric with type " << MetricTypeToStr(it->second.Metric->Type())); + Y_ENSURE(it->second.Opts.MemOnly == opts.MemOnly,"cannot create metric " << labels + << " with memOnly=" << opts.MemOnly + << ", because registry already has same metric with memOnly=" << it->second.Opts.MemOnly); + return static_cast(it->second.Metric.Get()); + } + } + + { + IMetricPtr metric = MakeIntrusive(std::forward(args)...); + + TWriteGuard g{*Lock_}; + // decltype(Metrics_)::iterator breaks build on windows + THashMap::iterator it; + TMetricValue metricValue = {metric, opts}; + if constexpr (!std::is_convertible_v) { + it = Metrics_.emplace(new TLabels{std::forward(labels)}, std::move(metricValue)).first; + } else { + it = Metrics_.emplace(std::forward(labels), std::move(metricValue)).first; + } + + return static_cast(it->second.Metric.Get()); + } + } + private: THolder Lock_ = MakeHolder(); THashMap Metrics_; - template - TMetric* Metric(TLabelsType&& labels, TMetricOpts&& opts, Args&&... args); - TLabels CommonLabels_; }; diff --git a/library/cpp/protobuf/json/proto2json_printer.cpp b/library/cpp/protobuf/json/proto2json_printer.cpp index a9f8c3fce991..706b3b8c6286 100644 --- a/library/cpp/protobuf/json/proto2json_printer.cpp +++ b/library/cpp/protobuf/json/proto2json_printer.cpp @@ -253,7 +253,7 @@ namespace NProtobufJson { bool inProtoMap) { Y_ABORT_UNLESS(!field.is_repeated(), "field is repeated."); - if (!key) { + if (!key && !inProtoMap) { key = MakeKey(field); } diff --git a/library/cpp/protobuf/json/ut/proto2json_ut.cpp b/library/cpp/protobuf/json/ut/proto2json_ut.cpp index f5bcfac49dbe..ce7d119be725 100644 --- a/library/cpp/protobuf/json/ut/proto2json_ut.cpp +++ b/library/cpp/protobuf/json/ut/proto2json_ut.cpp @@ -968,10 +968,10 @@ Y_UNIT_TEST(TestMapAsObject) { auto& items = *proto.MutableItems(); items["key1"] = "value1"; - items["key2"] = "value2"; + items[""] = "value2"; items["key3"] = "value3"; - TString modelStr(R"_({"Items":{"key3":"value3","key2":"value2","key1":"value1"}})_"); + TString modelStr(R"_({"Items":{"key3":"value3","":"value2","key1":"value1"}})_"); TStringStream jsonStr; TProto2JsonConfig config; diff --git a/library/cpp/protobuf/yql/descriptor.cpp b/library/cpp/protobuf/yql/descriptor.cpp index e5e1c8e28bdd..3a0d0d8b47c2 100644 --- a/library/cpp/protobuf/yql/descriptor.cpp +++ b/library/cpp/protobuf/yql/descriptor.cpp @@ -232,6 +232,9 @@ TString GenerateProtobufTypeConfig( case ERecursionTraits::Bytes: ret["view"]["recursion"] = "bytes"; break; + case ERecursionTraits::BytesV2: + ret["view"]["recursion"] = "bytesV2"; + break; } if (options.YtMode) { @@ -314,6 +317,8 @@ TProtoTypeConfig ParseTypeConfig(const TStringBuf& config) { result.Recursion = ERecursionTraits::Ignore; } else if (recursion == "bytes") { result.Recursion = ERecursionTraits::Bytes; + } else if (recursion == "bytesV2") { + result.Recursion = ERecursionTraits::BytesV2; } else { ythrow yexception() << "unsupported recursion trait " << recursion; diff --git a/library/cpp/protobuf/yql/descriptor.h b/library/cpp/protobuf/yql/descriptor.h index f5f51add0bcb..3a864f202670 100644 --- a/library/cpp/protobuf/yql/descriptor.h +++ b/library/cpp/protobuf/yql/descriptor.h @@ -27,6 +27,10 @@ enum class ERecursionTraits { Ignore = 1, //! Возвращать поля с рекурсивным типом в виде сериализованной строки Bytes = 2, + //! Возвращать поля с рекурсивным типом в виде сериализованной строки. + //! В этом режиме пофиксен баг, в котором + //! |optional RecursiveMessage field = 1| превращалось в байтовую строку, а не в опциональную байтовую строку. + BytesV2 = 3, }; struct TProtoTypeConfig { diff --git a/library/cpp/testing/common/env.cpp b/library/cpp/testing/common/env.cpp index 1440186d789e..41bf2b20aba1 100644 --- a/library/cpp/testing/common/env.cpp +++ b/library/cpp/testing/common/env.cpp @@ -141,7 +141,6 @@ namespace NPrivate { void TTestEnv::ReInitialize() { IsRunningFromTest = false; - ArcadiaTestsDataDir = ""; SourceRoot = ""; BuildRoot = ""; WorkPath = ""; @@ -171,11 +170,6 @@ namespace NPrivate { BuildRoot = value->GetStringSafe(""); } - value = context.GetValueByPath("runtime.atd_root"); - if (value) { - ArcadiaTestsDataDir = value->GetStringSafe(""); - } - value = context.GetValueByPath("runtime.work_path"); if (value) { WorkPath = value->GetStringSafe(""); @@ -249,10 +243,6 @@ namespace NPrivate { BuildRoot = GetEnv("ARCADIA_BUILD_ROOT"); } - if (!ArcadiaTestsDataDir) { - ArcadiaTestsDataDir = GetEnv("ARCADIA_TESTS_DATA_DIR"); - } - if (!WorkPath) { WorkPath = GetEnv("TEST_WORK_PATH"); } diff --git a/library/cpp/testing/common/env.h b/library/cpp/testing/common/env.h index 6cd840442f86..f9a5aff5d338 100644 --- a/library/cpp/testing/common/env.h +++ b/library/cpp/testing/common/env.h @@ -69,7 +69,6 @@ namespace NPrivate { void AddTestParam(TStringBuf name, TStringBuf value); bool IsRunningFromTest; - TString ArcadiaTestsDataDir; TString SourceRoot; TString BuildRoot; TString WorkPath; diff --git a/library/cpp/testing/unittest/registar.cpp b/library/cpp/testing/unittest/registar.cpp index d48f13813e33..5c2e9343f99b 100644 --- a/library/cpp/testing/unittest/registar.cpp +++ b/library/cpp/testing/unittest/registar.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -134,8 +133,8 @@ struct TTraceDiffFormatter { } }; -TString NUnitTest::GetFormatTag(const char* name) { - return Sprintf("[[%s]]", name); +TString NUnitTest::GetFormatTag(TStringBuf name) { + return TString::Join("[[", name, "]]"); } TString NUnitTest::GetResetTag() { @@ -156,7 +155,7 @@ TString NUnitTest::ColoredDiff(TStringBuf s1, TStringBuf s2, const TString& deli } static TString MakeTestName(const NUnitTest::ITestSuiteProcessor::TTest& test) { - return TStringBuilder() << test.unit->name << "::" << test.name; + return TString::Join(test.unit->name, "::", test.name); } static size_t CountTests(const TMap& testErrors, bool succeeded) { diff --git a/library/cpp/testing/unittest/registar.h b/library/cpp/testing/unittest/registar.h index c65c79e79f40..c6c1281b4dba 100644 --- a/library/cpp/testing/unittest/registar.h +++ b/library/cpp/testing/unittest/registar.h @@ -42,7 +42,7 @@ namespace NUnitTest { extern bool ShouldColorizeDiff; TString ColoredDiff(TStringBuf s1, TStringBuf s2, const TString& delims = TString(), bool reverse = false); - TString GetFormatTag(const char* name); + TString GetFormatTag(TStringBuf name); TString GetResetTag(); // Raise error handler diff --git a/library/cpp/threading/local_executor/README.md b/library/cpp/threading/local_executor/README.md index aaad2e2986c0..9a2831815f1a 100644 --- a/library/cpp/threading/local_executor/README.md +++ b/library/cpp/threading/local_executor/README.md @@ -1,37 +1,39 @@ -# Library for parallel task execution in thread pool +# Library for parallel task execution in a thread pool -This library allows easy parallelization of existing code and cycles. +This library allows easy parallelization of the existing code, particularly loops. It provides `NPar::TLocalExecutor` class and `NPar::LocalExecutor()` singleton accessor. -At start, `TLocalExecutor` has no threads in thread pool and all async tasks will be queued for later execution when extra threads appear. -All tasks should be `NPar::ILocallyExecutable` child class or function equal to `std::function` +At the start, `TLocalExecutor` has no threads in the thread pool and all async tasks will be queued for later execution when extra threads appear. +All tasks should be either derived from `NPar::ILocallyExecutable` or be of type `std::function`. ## TLocalExecutor methods -`TLocalExecutor::Run(int threadcount)` - add threads to thread pool (**WARNING!** `Run(threadcount)` will *add* `threadcount` threads to pool) +`TLocalExecutor::Run(int threadcount)` - add threads to the thread pool (**WARNING!** `Run(threadcount)` will *add* `threadcount` threads to pool) -`void TLocalExecutor::Exec(TLocallyExecutableFunction exec, int id, int flags)` - run one task and pass id as task function input, flags - bitmask composition of: +`void TLocalExecutor::Exec(TLocallyExecutableFunction exec, int id, int flags)` - run a single task and pass `id` as a task function argument, flags - bitmask that can contain: -- `TLocalExecutor::HIGH_PRIORITY = 0` - put task in high priority queue -- `TLocalExecutor::MED_PRIORITY = 1` - put task in medium priority queue -- `TLocalExecutor::LOW_PRIORITY = 2` - put task in low priority queue -- `TLocalExecutor::WAIT_COMPLETE = 4` - wait for task completion +- `TLocalExecutor::HIGH_PRIORITY = 0` - put the task in the high priority queue +- `TLocalExecutor::MED_PRIORITY = 1` - put the task in the medium priority queue +- `TLocalExecutor::LOW_PRIORITY = 2` - put the task in the low priority queue +- `TLocalExecutor::WAIT_COMPLETE = 4` - wait for the task completion -`void TLocalExecutor::ExecRange(TLocallyExecutableFunction exec, TExecRangeParams blockParams, int flags);` - run range of tasks `[TExecRangeParams::FirstId, TExecRangeParams::LastId).` +`void TLocalExecutor::ExecRange(TLocallyExecutableFunction exec, TExecRangeParams blockParams, int flags);` - run a range of tasks with ids `[TExecRangeParams::FirstId, TExecRangeParams::LastId).` `flags` is the same as for `TLocalExecutor::Exec`. -`TExecRangeParams` is a structure that describes the range. -By default each task is executed separately. Threads from thread pool are taking -the tasks in the manner first come first serve. +By default each task for each `id` is executed separately. Threads from the thread pool are taking the tasks in the FIFO manner. -It is also possible to partition range of tasks in consequtive blocks and execute each block as a bigger task. -`TExecRangeParams::SetBlockCountToThreadCount()` will result in thread count tasks, - where thread count is the count of threads in thread pool. - each thread will execute approximately equal count of tasks from range. +It is also possible to partition a range of tasks to consecutive blocks and execute each block as a bigger task. -`TExecRangeParams::SetBlockSize()` and `TExecRangeParams::SetBlockCount()` will partition -the range of tasks into consequtive blocks of approximately given size, or of size calculated - by partitioning the range into approximately equal size blocks of given count. +`TExecRangeParams` is a structure that is used for that. + +`TExecRangeParams::SetBlockCountToThreadCount()` will partition +the range of tasks into consecutive blocks with the number of tasks equivalent to the number of threads in the execution pool. The intent is that each thread will take an exactly single block from this partition, although it is not guaranteed, especially if the thread pool is already busy. + +`TExecRangeParams::SetBlockSize(TBlockSize blockSize)` will partition +the range of tasks into consecutive blocks of the size approximately equal to `blockSize`. + +`TExecRangeParams::SetBlockCount(TBlockCount blockCount)` will partition +the range of tasks into consecutive `blockCount` blocks with the approximately equal size. ## Examples @@ -51,7 +53,7 @@ SomeOtherCode(); event.WaitI(); ``` -### Execute task range and wait completion +### Execute a task range and wait for completion ```cpp using namespace NPar; @@ -64,11 +66,11 @@ LocalExecutor().ExecRange([](int id) { ### Exception handling -By default if a not caught exception arise in a task which runs through the Local Executor, then std::terminate() will be called immediately. The exception will be printed to stderr before the termination. Best practice is to handle exception within a task, or avoid throwing exceptions at all for performance reasons. +By default if an uncaught exception is thrown in a task that runs through the Local Executor, then `std::terminate()` will be called immediately. Best practice is to handle exception within a task, or avoid throwing exceptions at all for performance reasons. -However, if you'd like to handle and/or rethrow exceptions outside of a range, you can use ExecRangeWithFuture(). -It returns vector [0 .. LastId-FirstId] elements, where i-th element is a TFuture corresponding to task with id = (FirstId + i). -Use method .HasValue() of the element to check in Async mode if the corresponding task is complete. -Use .GetValue() or .GetValueSync() to wait for completion of the corresponding task. GetValue() and GetValueSync() will also rethrow an exception if it appears during execution of the task. +However, if you'd like to get exceptions that might have occured during the tasks execution instead, you can use `ExecRangeWithFutures()`. +It returns a vector of [0 .. LastId-FirstId] elements, where i-th element is a `TFuture` corresponding to the task with `id = (FirstId + i)`. +Use a method `.HasValue()` of the element to check in Async mode if the corresponding task is complete. +Use `.GetValue()` or `.GetValueSync()` to wait for completion of the corresponding task. `GetValue()` and `GetValueSync()` will also rethrow an exception if it has been thrown during the execution of the task. -You may also use ExecRangeWithThrow() to just receive an exception from a range if it appears. It rethrows an exception from a task with minimal id if such an exception exists, and guarantees normal flow if no exception arise. +You may also use `ExecRangeWithThrow()` to just receive an exception from a range if it has been thrown from at least one task. It rethrows an exception from a task with the minimal `id` from all the tasks where exceptions have been thrown or just continues as normal of there were no exceptions. diff --git a/library/cpp/threading/local_executor/local_executor.cpp b/library/cpp/threading/local_executor/local_executor.cpp index 4b4f69c0cbeb..107f981ff70f 100644 --- a/library/cpp/threading/local_executor/local_executor.cpp +++ b/library/cpp/threading/local_executor/local_executor.cpp @@ -57,7 +57,7 @@ namespace { void LocalExec(int id) override { Y_ASSERT(FirstId <= id && id < LastId); - NThreading::NImpl::SetValue(Promises[id - FirstId], [=] { Exec(id); }); + NThreading::NImpl::SetValue(Promises[id - FirstId], [this, id] { Exec(id); }); } TVector> GetFutures() const { diff --git a/library/cpp/threading/local_executor/tbb_local_executor.cpp b/library/cpp/threading/local_executor/tbb_local_executor.cpp index 91a8460b0eb4..cad425a1a625 100644 --- a/library/cpp/threading/local_executor/tbb_local_executor.cpp +++ b/library/cpp/threading/local_executor/tbb_local_executor.cpp @@ -36,7 +36,7 @@ void NPar::TTbbLocalExecutor::Exec(TIntrusivePtr if (flags & WAIT_COMPLETE) { exec->LocalExec(id); } else { - TbbArena.execute([=] { + TbbArena.execute([this, exec, id] { SubmitAsyncTasks([=] (int id) { exec->LocalExec(id); }, id, id + 1); }); } @@ -55,8 +55,8 @@ void NPar::TTbbLocalExecutor::ExecRange(TIntrusivePtrLocalExec(id); }, firstId, lastId); + TbbArena.execute([this, exec, firstId, lastId] { + SubmitAsyncTasks([exec] (int id) { exec->LocalExec(id); }, firstId, lastId); }); } } diff --git a/library/cpp/tld/tlds-alpha-by-domain.txt b/library/cpp/tld/tlds-alpha-by-domain.txt index 51c6ed810af6..88d9cd720d3a 100644 --- a/library/cpp/tld/tlds-alpha-by-domain.txt +++ b/library/cpp/tld/tlds-alpha-by-domain.txt @@ -1,4 +1,4 @@ -# Version 2025040400, Last Updated Fri Apr 4 07:07:02 2025 UTC +# Version 2025041502, Last Updated Wed Apr 16 07:07:01 2025 UTC AAA AARP ABB diff --git a/library/cpp/yt/logging/logger-inl.h b/library/cpp/yt/logging/logger-inl.h index 958ede8cda05..c9a98cb3b449 100644 --- a/library/cpp/yt/logging/logger-inl.h +++ b/library/cpp/yt/logging/logger-inl.h @@ -35,21 +35,35 @@ void TLogger::AddStructuredTag(TStringBuf key, TType value) } template -TLogger TLogger::WithTag(const char* format, TArgs&&... args) const +TLogger TLogger::WithTag(const char* format, TArgs&&... args) const & { auto result = *this; result.AddTag(format, std::forward(args)...); return result; } +template +TLogger TLogger::WithTag(const char* format, TArgs&&... args) && +{ + AddTag(format, std::forward(args)...); + return std::move(*this); +} + template -TLogger TLogger::WithStructuredTag(TStringBuf key, TType value) const +TLogger TLogger::WithStructuredTag(TStringBuf key, TType value) const & { auto result = *this; result.AddStructuredTag(key, value); return result; } +template +TLogger TLogger::WithStructuredTag(TStringBuf key, TType value) && +{ + AddStructuredTag(key, value); + return std::move(*this); +} + Y_FORCE_INLINE ELogLevel TLogger::GetEffectiveLoggingLevel(ELogLevel level, const TLoggingAnchor& anchor) { // Check if anchor is suppressed. diff --git a/library/cpp/yt/logging/logger.cpp b/library/cpp/yt/logging/logger.cpp index 682231d48958..38fd5b6e1349 100644 --- a/library/cpp/yt/logging/logger.cpp +++ b/library/cpp/yt/logging/logger.cpp @@ -226,34 +226,52 @@ void TLogger::AddRawTag(const std::string& tag) state->Tag += tag; } -TLogger TLogger::WithRawTag(const std::string& tag) const +TLogger TLogger::WithRawTag(const std::string& tag) const & { auto result = *this; result.AddRawTag(tag); return result; } -TLogger TLogger::WithEssential(bool essential) const +TLogger TLogger::WithRawTag(const std::string& tag) && +{ + AddRawTag(tag); + return std::move(*this); +} + +TLogger TLogger::WithEssential(bool essential) const & { auto result = *this; result.Essential_ = essential; return result; } +TLogger TLogger::WithEssential(bool essential) && +{ + Essential_ = essential; + return std::move(*this); +} + void TLogger::AddStructuredValidator(TStructuredValidator validator) { auto* state = GetMutableCoWState(); state->StructuredValidators.push_back(std::move(validator)); } -TLogger TLogger::WithStructuredValidator(TStructuredValidator validator) const +TLogger TLogger::WithStructuredValidator(TStructuredValidator validator) const & { auto result = *this; result.AddStructuredValidator(std::move(validator)); return result; } -TLogger TLogger::WithMinLevel(ELogLevel minLevel) const +TLogger TLogger::WithStructuredValidator(TStructuredValidator validator) && +{ + AddStructuredValidator(std::move(validator)); + return std::move(*this); +} + +TLogger TLogger::WithMinLevel(ELogLevel minLevel) const & { auto result = *this; if (result) { @@ -262,6 +280,14 @@ TLogger TLogger::WithMinLevel(ELogLevel minLevel) const return result; } +TLogger TLogger::WithMinLevel(ELogLevel minLevel) && +{ + if (*this) { + MinLevel_ = minLevel; + } + return std::move(*this); +} + const std::string& TLogger::GetTag() const { static const std::string emptyResult; diff --git a/library/cpp/yt/logging/logger.h b/library/cpp/yt/logging/logger.h index 53bb13e70545..dfa1b79bac8f 100644 --- a/library/cpp/yt/logging/logger.h +++ b/library/cpp/yt/logging/logger.h @@ -181,7 +181,9 @@ class TLogger TLogger() = default; TLogger(const TLogger& other) = default; + TLogger(TLogger&& other) = default; TLogger& operator=(const TLogger& other) = default; + TLogger& operator=(TLogger&& other) = default; TLogger(ILogManager* logManager, TStringBuf categoryName); explicit TLogger(TStringBuf categoryName); @@ -224,18 +226,26 @@ class TLogger void AddStructuredValidator(TStructuredValidator validator); - TLogger WithRawTag(const std::string& tag) const; + TLogger WithRawTag(const std::string& tag) const &; + TLogger WithRawTag(const std::string& tag) &&; template - TLogger WithTag(const char* format, TArgs&&... args) const; + TLogger WithTag(const char* format, TArgs&&... args) const &; + template + TLogger WithTag(const char* format, TArgs&&... args) &&; template - TLogger WithStructuredTag(TStringBuf key, TType value) const; + TLogger WithStructuredTag(TStringBuf key, TType value) const &; + template + TLogger WithStructuredTag(TStringBuf key, TType value) &&; - TLogger WithStructuredValidator(TStructuredValidator validator) const; + TLogger WithStructuredValidator(TStructuredValidator validator) const &; + TLogger WithStructuredValidator(TStructuredValidator validator) &&; - TLogger WithMinLevel(ELogLevel minLevel) const; + TLogger WithMinLevel(ELogLevel minLevel) const &; + TLogger WithMinLevel(ELogLevel minLevel) &&; - TLogger WithEssential(bool essential = true) const; + TLogger WithEssential(bool essential = true) const &; + TLogger WithEssential(bool essential = true) &&; const std::string& GetTag() const; const TStructuredTags& GetStructuredTags() const; diff --git a/library/cpp/yt/memory/chunked_memory_pool.cpp b/library/cpp/yt/memory/chunked_memory_pool.cpp index d8673f5d6c3d..69794dcee19b 100644 --- a/library/cpp/yt/memory/chunked_memory_pool.cpp +++ b/library/cpp/yt/memory/chunked_memory_pool.cpp @@ -58,6 +58,7 @@ TChunkedMemoryPool::TChunkedMemoryPool( , ChunkProviderHolder_(std::move(chunkProvider)) , ChunkProvider_(ChunkProviderHolder_.Get()) { + YT_VERIFY(ChunkProviderHolder_); Initialize(startChunkSize); } diff --git a/library/cpp/yt/string/format-inl.h b/library/cpp/yt/string/format-inl.h index 22da423f8932..5b49fc5925c7 100644 --- a/library/cpp/yt/string/format-inl.h +++ b/library/cpp/yt/string/format-inl.h @@ -253,7 +253,7 @@ void FormatCompactIntervalRange( auto first = range.begin(); auto last = first; - auto current = first + 1; + auto current = std::next(first); while (current != range.end()) { if (valueGetter(current) != valueGetter(last) + 1) { @@ -316,7 +316,7 @@ typename TFormattableView::TEnd TFormattableView -TFormattableView MakeFormattableView( +TFormattableView> MakeFormattableView( const TRange& range, TFormatter&& formatter) { @@ -324,7 +324,7 @@ TFormattableView MakeFormattableView( } template -TFormattableView MakeShrunkFormattableView( +TFormattableView> MakeShrunkFormattableView( const TRange& range, TFormatter&& formatter, size_t limit) diff --git a/library/cpp/yt/string/format.h b/library/cpp/yt/string/format.h index d15127fae056..fa45f39e5ac1 100644 --- a/library/cpp/yt/string/format.h +++ b/library/cpp/yt/string/format.h @@ -91,12 +91,12 @@ struct TFormattableView //! Annotates a given #range with #formatter to be applied to each item. template -TFormattableView MakeFormattableView( +TFormattableView> MakeFormattableView( const TRange& range, TFormatter&& formatter); template -TFormattableView MakeShrunkFormattableView( +TFormattableView> MakeShrunkFormattableView( const TRange& range, TFormatter&& formatter, size_t limit); diff --git a/library/cpp/yt/string/unittests/format_ut.cpp b/library/cpp/yt/string/unittests/format_ut.cpp index e2e23c737c2c..a6c5ef6837f5 100644 --- a/library/cpp/yt/string/unittests/format_ut.cpp +++ b/library/cpp/yt/string/unittests/format_ut.cpp @@ -267,6 +267,19 @@ TEST(TFormatTest, LazyMultiValueFormatter) EXPECT_EQ("int: 1, string: hello, range: [1, 2, 3]", Format("%v", lazyFormatter)); } +TEST(TFormatTest, ReusableLambdaFormatter) +{ + auto formatter = [&] (auto* builder, int value) { + builder->AppendFormat("%v", value); + }; + + std::vector range1{1, 2, 3}; + EXPECT_EQ("[1, 2, 3]", Format("%v", MakeFormattableView(range1, formatter))); + + std::vector range2{4, 5, 6}; + EXPECT_EQ("[4, 5, 6]", Format("%v", MakeFormattableView(range2, formatter))); +} + TEST(TFormatTest, VectorArg) { std::vector params = {"a", "b", "c"}; diff --git a/library/cpp/yt/threading/atomic_object.h b/library/cpp/yt/threading/atomic_object.h index 8b642c0f4fb6..a77ade0a00d6 100644 --- a/library/cpp/yt/threading/atomic_object.h +++ b/library/cpp/yt/threading/atomic_object.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include diff --git a/library/cpp/yt/threading/rw_spin_lock-inl.h b/library/cpp/yt/threading/rw_spin_lock-inl.h index 779de1b64a80..0a31b1d9deca 100644 --- a/library/cpp/yt/threading/rw_spin_lock-inl.h +++ b/library/cpp/yt/threading/rw_spin_lock-inl.h @@ -31,7 +31,7 @@ inline void TReaderWriterSpinLock::AcquireReaderForkFriendly() noexcept inline void TReaderWriterSpinLock::ReleaseReader() noexcept { auto prevValue = Value_.fetch_sub(ReaderDelta, std::memory_order::release); - Y_ASSERT((prevValue & ~WriterMask) != 0); + Y_ASSERT((prevValue & ~(WriterMask | WriterReadyMask)) != 0); NDetail::RecordSpinLockReleased(); } @@ -45,14 +45,14 @@ inline void TReaderWriterSpinLock::AcquireWriter() noexcept inline void TReaderWriterSpinLock::ReleaseWriter() noexcept { - auto prevValue = Value_.fetch_and(~WriterMask, std::memory_order::release); + auto prevValue = Value_.fetch_and(~(WriterMask | WriterReadyMask), std::memory_order::release); Y_ASSERT(prevValue & WriterMask); NDetail::RecordSpinLockReleased(); } inline bool TReaderWriterSpinLock::IsLocked() const noexcept { - return Value_.load() != UnlockedValue; + return (Value_.load() & ~WriterReadyMask) != 0; } inline bool TReaderWriterSpinLock::IsLockedByReader() const noexcept @@ -68,7 +68,7 @@ inline bool TReaderWriterSpinLock::IsLockedByWriter() const noexcept inline bool TReaderWriterSpinLock::TryAcquireReader() noexcept { auto oldValue = Value_.fetch_add(ReaderDelta, std::memory_order::acquire); - if ((oldValue & WriterMask) != 0) { + if ((oldValue & (WriterMask | WriterReadyMask)) != 0) { Value_.fetch_sub(ReaderDelta, std::memory_order::relaxed); return false; } @@ -79,7 +79,7 @@ inline bool TReaderWriterSpinLock::TryAcquireReader() noexcept inline bool TReaderWriterSpinLock::TryAndTryAcquireReader() noexcept { auto oldValue = Value_.load(std::memory_order::relaxed); - if ((oldValue & WriterMask) != 0) { + if ((oldValue & (WriterMask | WriterReadyMask)) != 0) { return false; } return TryAcquireReader(); @@ -88,7 +88,7 @@ inline bool TReaderWriterSpinLock::TryAndTryAcquireReader() noexcept inline bool TReaderWriterSpinLock::TryAcquireReaderForkFriendly() noexcept { auto oldValue = Value_.load(std::memory_order::relaxed); - if ((oldValue & WriterMask) != 0) { + if ((oldValue & (WriterMask | WriterReadyMask)) != 0) { return false; } auto newValue = oldValue + ReaderDelta; @@ -98,22 +98,35 @@ inline bool TReaderWriterSpinLock::TryAcquireReaderForkFriendly() noexcept return acquired; } -inline bool TReaderWriterSpinLock::TryAcquireWriter() noexcept +inline bool TReaderWriterSpinLock::TryAcquireWriterWithExpectedValue(TValue expected) noexcept { - auto expected = UnlockedValue; - - bool acquired = Value_.compare_exchange_weak(expected, WriterMask, std::memory_order::acquire); + bool acquired = Value_.compare_exchange_weak(expected, WriterMask, std::memory_order::acquire); NDetail::RecordSpinLockAcquired(acquired); return acquired; } +inline bool TReaderWriterSpinLock::TryAcquireWriter() noexcept +{ + // NB(pavook): we cannot expect writer ready to be set, as this method + // might be called without indicating writer readiness and we cannot + // indicate readiness on the hot path. This means that code calling + // TryAcquireWriter will spin against code calling AcquireWriter. + return TryAcquireWriterWithExpectedValue(UnlockedValue); +} + inline bool TReaderWriterSpinLock::TryAndTryAcquireWriter() noexcept { auto oldValue = Value_.load(std::memory_order::relaxed); - if (oldValue != UnlockedValue) { + + if ((oldValue & WriterReadyMask) == 0) { + oldValue = Value_.fetch_or(WriterReadyMask, std::memory_order::relaxed); + } + + if ((oldValue & (~WriterReadyMask)) != 0) { return false; } - return TryAcquireWriter(); + + return TryAcquireWriterWithExpectedValue(WriterReadyMask); } //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/threading/rw_spin_lock.h b/library/cpp/yt/threading/rw_spin_lock.h index a915e677e82a..64a241bb6b47 100644 --- a/library/cpp/yt/threading/rw_spin_lock.h +++ b/library/cpp/yt/threading/rw_spin_lock.h @@ -16,8 +16,23 @@ namespace NYT::NThreading { //! Single-writer multiple-readers spin lock. /*! - * Reader-side calls are pretty cheap. - * The lock is unfair. + * Reader-side acquires are pretty cheap, and readers don't spin unless writers + * are present. + * + * The lock is unfair, but writers are prioritized over readers, that is, + * if AcquireWriter() is called at some time, then some writer + * (not necessarily the same one that called AcquireWriter) will succeed + * in the next time. This is implemented by an additional flag "WriterReady", + * that writers set on arrival. No readers can proceed until this flag is reset. + * + * WARNING: You probably should not use this lock if forks are possible: see + * fork_aware_rw_spin_lock.h for a proper fork-safe lock which does the housekeeping for you. + * + * WARNING: This lock is not recursive: you can't call AcquireReader() twice in the same + * thread, as that may lead to a deadlock. For the same reason you shouldn't do WaitFor or any + * other context switch under lock. + * + * See tla+/spinlock.tla for the formally verified lock's properties. */ class TReaderWriterSpinLock : public TSpinLockBase @@ -29,18 +44,26 @@ class TReaderWriterSpinLock /*! * Optimized for the case of read-intensive workloads. * Cheap (just one atomic increment and no spinning if no writers are present). - * Don't use this call if forks are possible: forking at some + * + * WARNING: Don't use this call if forks are possible: forking at some * intermediate point inside #AcquireReader may corrupt the lock state and - * leave lock forever stuck for the child process. + * leave the lock stuck forever for the child process. + * + * WARNING: The lock is not recursive/reentrant, i.e. it assumes that no thread calls + * AcquireReader() if the reader is already acquired for it. */ void AcquireReader() noexcept; //! Acquires the reader lock. /*! * A more expensive version of #AcquireReader (includes at least * one atomic load and CAS; also may spin even if just readers are present). + * * In contrast to #AcquireReader, this method can be used in the presence of forks. - * Note that fork-friendliness alone does not provide fork-safety: additional - * actions must be performed to release the lock after a fork. + * + * WARNING: fork-friendliness alone does not provide fork-safety: additional + * actions must be performed to release the lock after a fork. This means you + * probably should NOT use this lock in the presence of forks, consider + * fork_aware_rw_spin_lock.h instead as a proper fork-safe lock. */ void AcquireReaderForkFriendly() noexcept; //! Tries acquiring the reader lock; see #AcquireReader. @@ -94,10 +117,12 @@ class TReaderWriterSpinLock using TValue = ui32; static constexpr TValue UnlockedValue = 0; static constexpr TValue WriterMask = 1; - static constexpr TValue ReaderDelta = 2; + static constexpr TValue WriterReadyMask = 2; + static constexpr TValue ReaderDelta = 4; std::atomic Value_ = UnlockedValue; + bool TryAcquireWriterWithExpectedValue(TValue expected) noexcept; bool TryAndTryAcquireReader() noexcept; bool TryAndTryAcquireWriter() noexcept; diff --git a/library/cpp/yt/threading/unittests/rw_spin_lock_ut.cpp b/library/cpp/yt/threading/unittests/rw_spin_lock_ut.cpp new file mode 100644 index 000000000000..653772604cea --- /dev/null +++ b/library/cpp/yt/threading/unittests/rw_spin_lock_ut.cpp @@ -0,0 +1,56 @@ +#include + +#include + +#include + +#include +#include + +namespace NYT::NThreading { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TReaderWriterSpinLockTest, WriterPriority) +{ + int readerThreads = 10; + std::latch latch(readerThreads + 1); + std::atomic finishedCount = {0}; + + TReaderWriterSpinLock lock; + + volatile std::atomic x = {0}; + + auto readerTask = [&latch, &lock, &finishedCount, &x] () { + latch.arrive_and_wait(); + while (true) { + { + auto guard = ReaderGuard(lock); + // do some stuff + for (ui32 i = 0; i < 10'000u; ++i) { + x.fetch_add(i); + } + } + if (finishedCount.fetch_add(1) > 20'000) { + break; + } + } + }; + + auto readerPool = CreateThreadPool(readerThreads); + for (int i = 0; i < readerThreads; ++i) { + readerPool->SafeAddFunc(readerTask); + } + + latch.arrive_and_wait(); + while (finishedCount.load() == 0); + auto guard = WriterGuard(lock); + EXPECT_LE(finishedCount.load(), 1'000u); + DoNotOptimizeAway(x); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT::NConcurrency diff --git a/library/cpp/yt/threading/unittests/spin_lock_fork_ut.cpp b/library/cpp/yt/threading/unittests/spin_lock_fork_ut.cpp new file mode 100644 index 000000000000..26e58fff7453 --- /dev/null +++ b/library/cpp/yt/threading/unittests/spin_lock_fork_ut.cpp @@ -0,0 +1,160 @@ +#include + +#include +#include + +#include + +#include + +namespace NYT::NThreading { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TReaderWriterSpinLockTest, ForkFriendlyness) +{ + std::atomic stopped = {false}; + YT_DECLARE_SPIN_LOCK(TReaderWriterSpinLock, lock); + + auto readerTask = [&lock, &stopped] () { + while (!stopped.load()) { + ForkFriendlyReaderGuard(lock); + } + }; + + auto tryReaderTask = [&lock, &stopped] () { + while (!stopped.load()) { + // NB(pavook): TryAcquire instead of Acquire to minimize checks. + bool acquired = lock.TryAcquireReaderForkFriendly(); + if (acquired) { + lock.ReleaseReader(); + } + } + }; + + auto tryWriterTask = [&lock, &stopped] () { + while (!stopped.load()) { + Sleep(TDuration::MicroSeconds(1)); + bool acquired = lock.TryAcquireWriter(); + if (acquired) { + lock.ReleaseWriter(); + } + } + }; + + auto writerTask = [&lock, &stopped] () { + while (!stopped.load()) { + Sleep(TDuration::MicroSeconds(1)); + WriterGuard(lock); + } + }; + + int readerCount = 20; + int writerCount = 10; + + auto reader = CreateThreadPool(readerCount); + auto writer = CreateThreadPool(writerCount); + + for (int i = 0; i < readerCount / 2; ++i) { + reader->SafeAddFunc(readerTask); + reader->SafeAddFunc(tryReaderTask); + } + for (int i = 0; i < writerCount / 2; ++i) { + writer->SafeAddFunc(writerTask); + writer->SafeAddFunc(tryWriterTask); + } + + // And let the chaos begin! + int forkCount = 2000; + for (int iter = 1; iter <= forkCount; ++iter) { + pid_t pid; + { + auto guard = WriterGuard(lock); + pid = fork(); + } + + YT_VERIFY(pid >= 0); + + // NB(pavook): check different orders to maximize chaos. + if (iter % 2 == 0) { + ReaderGuard(lock); + } + WriterGuard(lock); + ReaderGuard(lock); + if (pid == 0) { + // NB(pavook): thread pools are no longer with us. + _exit(0); + } + } + + for (int i = 1; i <= forkCount; ++i) { + int status; + YT_VERIFY(waitpid(0, &status, 0) > 0); + YT_VERIFY(WIFEXITED(status) && WEXITSTATUS(status) == 0); + } + + stopped.store(true); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TForkAwareSpinLockTest, ForkSafety) +{ + std::atomic stopped = {false}; + YT_DECLARE_SPIN_LOCK(TForkAwareSpinLock, lock); + + auto acquireTask = [&lock, &stopped] () { + while (!stopped.load()) { + Guard(lock); + } + }; + + // NB(pavook): TryAcquire instead of Acquire to minimize checks. + auto tryAcquireTask = [&lock, &stopped] () { + while (!stopped.load()) { + bool acquired = lock.TryAcquire(); + if (acquired) { + lock.Release(); + } + } + }; + + int workerCount = 20; + + auto worker = CreateThreadPool(workerCount); + + for (int i = 0; i < workerCount / 2; ++i) { + worker->SafeAddFunc(acquireTask); + worker->SafeAddFunc(tryAcquireTask); + } + + // And let the chaos begin! + int forkCount = 2000; + for (int iter = 1; iter <= forkCount; ++iter) { + pid_t pid = fork(); + + YT_VERIFY(pid >= 0); + + Guard(lock); + Guard(lock); + + if (pid == 0) { + // NB(pavook): thread pools are no longer with us. + _exit(0); + } + } + + for (int i = 1; i <= forkCount; ++i) { + int status; + YT_VERIFY(waitpid(0, &status, 0) > 0); + YT_VERIFY(WIFEXITED(status) && WEXITSTATUS(status) == 0); + } + + stopped.store(true); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT::NConcurrency diff --git a/library/cpp/yt/threading/unittests/ya.make b/library/cpp/yt/threading/unittests/ya.make index ef9b5d29951b..da006012c004 100644 --- a/library/cpp/yt/threading/unittests/ya.make +++ b/library/cpp/yt/threading/unittests/ya.make @@ -5,9 +5,14 @@ INCLUDE(${ARCADIA_ROOT}/library/cpp/yt/ya_cpp.make.inc) SRCS( count_down_latch_ut.cpp recursive_spin_lock_ut.cpp + rw_spin_lock_ut.cpp spin_wait_ut.cpp ) +IF (NOT OS_WINDOWS) + SRC(spin_lock_fork_ut.cpp) +ENDIF() + PEERDIR( library/cpp/yt/assert library/cpp/yt/threading diff --git a/library/cpp/yt/threading/writer_starving_rw_spin_lock-inl.h b/library/cpp/yt/threading/writer_starving_rw_spin_lock-inl.h new file mode 100644 index 000000000000..cf8bde715cc3 --- /dev/null +++ b/library/cpp/yt/threading/writer_starving_rw_spin_lock-inl.h @@ -0,0 +1,101 @@ +#pragma once +#ifndef WRITER_STARVING_RW_SPIN_LOCK_INL_H_ +#error "Direct inclusion of this file is not allowed, include rw_spin_lock.h" +// For the sake of sane code completion. +#include "writer_starving_rw_spin_lock.h" +#endif +#undef WRITER_STARVING_RW_SPIN_LOCK_INL_H_ + +#include "spin_wait.h" + +namespace NYT::NThreading { + +//////////////////////////////////////////////////////////////////////////////// + +inline void TWriterStarvingRWSpinLock::AcquireReader() noexcept +{ + if (TryAcquireReader()) { + return; + } + AcquireReaderSlow(); +} + +inline void TWriterStarvingRWSpinLock::ReleaseReader() noexcept +{ + auto prevValue = Value_.fetch_sub(ReaderDelta, std::memory_order::release); + Y_ASSERT((prevValue & ~WriterMask) != 0); + NDetail::RecordSpinLockReleased(); +} + +inline void TWriterStarvingRWSpinLock::AcquireWriter() noexcept +{ + if (TryAcquireWriter()) { + return; + } + AcquireWriterSlow(); +} + +inline void TWriterStarvingRWSpinLock::ReleaseWriter() noexcept +{ + auto prevValue = Value_.fetch_and(~WriterMask, std::memory_order::release); + Y_ASSERT(prevValue & WriterMask); + NDetail::RecordSpinLockReleased(); +} + +inline bool TWriterStarvingRWSpinLock::IsLocked() const noexcept +{ + return Value_.load() != UnlockedValue; +} + +inline bool TWriterStarvingRWSpinLock::IsLockedByReader() const noexcept +{ + return Value_.load() >= ReaderDelta; +} + +inline bool TWriterStarvingRWSpinLock::IsLockedByWriter() const noexcept +{ + return (Value_.load() & WriterMask) != 0; +} + +inline bool TWriterStarvingRWSpinLock::TryAcquireReader() noexcept +{ + auto oldValue = Value_.fetch_add(ReaderDelta, std::memory_order::acquire); + if ((oldValue & WriterMask) != 0) { + Value_.fetch_sub(ReaderDelta, std::memory_order::relaxed); + return false; + } + NDetail::RecordSpinLockAcquired(); + return true; +} + +inline bool TWriterStarvingRWSpinLock::TryAndTryAcquireReader() noexcept +{ + auto oldValue = Value_.load(std::memory_order::relaxed); + if ((oldValue & WriterMask) != 0) { + return false; + } + return TryAcquireReader(); +} + +inline bool TWriterStarvingRWSpinLock::TryAcquireWriter() noexcept +{ + auto expected = UnlockedValue; + + bool acquired = Value_.compare_exchange_weak(expected, WriterMask, std::memory_order::acquire); + NDetail::RecordSpinLockAcquired(acquired); + return acquired; +} + +inline bool TWriterStarvingRWSpinLock::TryAndTryAcquireWriter() noexcept +{ + auto oldValue = Value_.load(std::memory_order::relaxed); + if (oldValue != UnlockedValue) { + return false; + } + return TryAcquireWriter(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NThreading + diff --git a/library/cpp/yt/threading/writer_starving_rw_spin_lock.cpp b/library/cpp/yt/threading/writer_starving_rw_spin_lock.cpp new file mode 100644 index 000000000000..74c9f59db135 --- /dev/null +++ b/library/cpp/yt/threading/writer_starving_rw_spin_lock.cpp @@ -0,0 +1,25 @@ +#include "writer_starving_rw_spin_lock.h" + +namespace NYT::NThreading { + +//////////////////////////////////////////////////////////////////////////////// + +void TWriterStarvingRWSpinLock::AcquireReaderSlow() noexcept +{ + TSpinWait spinWait(Location_, ESpinLockActivityKind::Read); + while (!TryAndTryAcquireReader()) { + spinWait.Wait(); + } +} + +void TWriterStarvingRWSpinLock::AcquireWriterSlow() noexcept +{ + TSpinWait spinWait(Location_, ESpinLockActivityKind::Write); + while (!TryAndTryAcquireWriter()) { + spinWait.Wait(); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NThreading diff --git a/library/cpp/yt/threading/writer_starving_rw_spin_lock.h b/library/cpp/yt/threading/writer_starving_rw_spin_lock.h new file mode 100644 index 000000000000..8a456afe21b5 --- /dev/null +++ b/library/cpp/yt/threading/writer_starving_rw_spin_lock.h @@ -0,0 +1,115 @@ +#pragma once + +#include "public.h" +#include "rw_spin_lock.h" +#include "spin_lock_base.h" +#include "spin_lock_count.h" + +#include + +#include + +#include + +namespace NYT::NThreading { + +//////////////////////////////////////////////////////////////////////////////// + +// TODO(pavook): deprecate it. + +//! Single-writer multiple-readers spin lock. +/*! + * Reader-side calls are pretty cheap. + * WARNING: The lock is unfair, and readers can starve writers. See rw_spin_lock.h for a writer-prioritized lock. + * WARNING: Never use the bare lock if forks are possible: see fork_aware_rw_spin_lock.h for a fork-safe lock. + * Unlike rw_spin_lock.h, reader-side is reentrant here: it is possible to acquire the **reader** lock multiple times + * even in the single thread. + * This doesn't mean you should do it: in fact, you shouldn't: use separate locks for separate entities. + * If you see this class in your code, try migrating to the proper rw_spin_lock.h after ensuring you don't rely on + * reentrant locking. + */ +class TWriterStarvingRWSpinLock + : public TSpinLockBase +{ +public: + using TSpinLockBase::TSpinLockBase; + + //! Acquires the reader lock. + /*! + * Optimized for the case of read-intensive workloads. + * Cheap (just one atomic increment and no spinning if no writers are present). + * Don't use this call if forks are possible: forking at some + * intermediate point inside #AcquireReader may corrupt the lock state and + * leave lock forever stuck for the child process. + */ + void AcquireReader() noexcept; + //! Tries acquiring the reader lock; see #AcquireReader. + //! Returns |true| on success. + bool TryAcquireReader() noexcept; + //! Releases the reader lock. + /*! + * Cheap (just one atomic decrement). + */ + void ReleaseReader() noexcept; + + //! Acquires the writer lock. + /*! + * Rather cheap (just one CAS). + */ + void AcquireWriter() noexcept; + //! Tries acquiring the writer lock; see #AcquireWriter. + //! Returns |true| on success. + bool TryAcquireWriter() noexcept; + //! Releases the writer lock. + /*! + * Cheap (just one atomic store). + */ + void ReleaseWriter() noexcept; + + //! Returns true if the lock is taken (either by a reader or writer). + /*! + * This is inherently racy. + * Only use for debugging and diagnostic purposes. + */ + bool IsLocked() const noexcept; + + //! Returns true if the lock is taken by reader. + /*! + * This is inherently racy. + * Only use for debugging and diagnostic purposes. + */ + bool IsLockedByReader() const noexcept; + + //! Returns true if the lock is taken by writer. + /*! + * This is inherently racy. + * Only use for debugging and diagnostic purposes. + */ + bool IsLockedByWriter() const noexcept; + +private: + using TValue = ui32; + static constexpr TValue UnlockedValue = 0; + static constexpr TValue WriterMask = 1; + static constexpr TValue ReaderDelta = 2; + + std::atomic Value_ = UnlockedValue; + + + bool TryAndTryAcquireReader() noexcept; + bool TryAndTryAcquireWriter() noexcept; + + void AcquireReaderSlow() noexcept; + void AcquireWriterSlow() noexcept; +}; + +REGISTER_TRACKED_SPIN_LOCK_CLASS(TWriterStarvingRWSpinLock) + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NThreading + +#define WRITER_STARVING_RW_SPIN_LOCK_INL_H_ +#include "writer_starving_rw_spin_lock-inl.h" +#undef WRITER_STARVING_RW_SPIN_LOCK_INL_H_ + diff --git a/library/cpp/yt/threading/ya.make b/library/cpp/yt/threading/ya.make index cc11e7974efd..d25f0a70681b 100644 --- a/library/cpp/yt/threading/ya.make +++ b/library/cpp/yt/threading/ya.make @@ -18,6 +18,7 @@ SRCS( spin_lock.cpp spin_wait.cpp spin_wait_hook.cpp + writer_starving_rw_spin_lock.cpp ) PEERDIR( diff --git a/library/cpp/yt/ya_cpp.make.inc b/library/cpp/yt/ya_cpp.make.inc index 81c522e0d61c..59dfb6e1c0dc 100644 --- a/library/cpp/yt/ya_cpp.make.inc +++ b/library/cpp/yt/ya_cpp.make.inc @@ -1,8 +1,18 @@ # This file should be included in all YT projects (including YT ORM installations). -IF (NOT MSVC) +IF (CLANG) CXXFLAGS( -Wdeprecated-this-capture -Wimplicit-fallthrough + -Wparentheses + -Wno-logical-op-parentheses + -Wno-bitwise-op-parentheses ) + + IF (MUSL) + CXXFLAGS( + --system-header-prefix=endian.h + --system-header-prefix=byteswap.h + ) + ENDIF() ENDIF() diff --git a/library/python/filelock/ut/ya.make b/library/python/filelock/ut/ya.make index 60108f73c654..62910fd33148 100644 --- a/library/python/filelock/ut/ya.make +++ b/library/python/filelock/ut/ya.make @@ -13,12 +13,14 @@ IF (OS_DARWIN) TAG( ya:fat ya:exotic_platform + ya:large_tests_on_single_slots ) ELSEIF (OS_WINDOWS) SIZE(LARGE) TAG( ya:fat - sb:ssd&~MULTISLOT&WINDOWS + sb:ssd&WINDOWS + ya:large_tests_on_single_slots ) ENDIF() diff --git a/util/system/ut/ya.make b/util/system/ut/ya.make index 1a80772a8ad8..d8063766d727 100644 --- a/util/system/ut/ya.make +++ b/util/system/ut/ya.make @@ -14,7 +14,12 @@ EXPLICIT_DATA() IF (OS_DARWIN) SIZE(LARGE) - TAG(ya:fat ya:force_sandbox ya:exotic_platform) + TAG( + ya:fat + ya:force_sandbox + ya:exotic_platform + ya:large_tests_on_single_slots + ) TIMEOUT(3600) ENDIF() diff --git a/util/tests/ya_util_tests.inc b/util/tests/ya_util_tests.inc index 57855aee6bd5..eb060e18341a 100644 --- a/util/tests/ya_util_tests.inc +++ b/util/tests/ya_util_tests.inc @@ -1,4 +1,9 @@ IF (OS_DARWIN) SIZE(LARGE) - TAG(ya:fat ya:force_sandbox ya:exotic_platform) + TAG( + ya:fat + ya:force_sandbox + ya:exotic_platform + ya:large_tests_on_single_slots + ) ENDIF() diff --git a/vendor/github.com/envoyproxy/protoc-gen-validate/validate/ya.make b/vendor/github.com/envoyproxy/protoc-gen-validate/validate/ya.make index fa44507e4d55..4e81538bfedb 100644 --- a/vendor/github.com/envoyproxy/protoc-gen-validate/validate/ya.make +++ b/vendor/github.com/envoyproxy/protoc-gen-validate/validate/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(Apache-2.0) -VERSION(v1.1.0) +VERSION(v1.2.1) SRCS( validate.pb.go diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index 6444f4b7f6f3..71757151c333 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -1,4 +1,5 @@ -![cobra logo](assets/CobraMain.png) + +![cobra logo](https://github.com/user-attachments/assets/cbc3adf8-0dff-46e9-a88d-5e2d971c169e) Cobra is a library for creating powerful modern CLI applications. @@ -105,7 +106,7 @@ go install github.com/spf13/cobra-cli@latest For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md) -For complete details on using the Cobra library, please read the [The Cobra User Guide](site/content/user_guide.md). +For complete details on using the Cobra library, please read [The Cobra User Guide](site/content/user_guide.md). # License diff --git a/vendor/github.com/spf13/cobra/active_help.go b/vendor/github.com/spf13/cobra/active_help.go index 25c30e3ccc3c..b3e2dadfed65 100644 --- a/vendor/github.com/spf13/cobra/active_help.go +++ b/vendor/github.com/spf13/cobra/active_help.go @@ -35,7 +35,7 @@ const ( // This function can be called multiple times before and/or after completions are added to // the array. Each time this function is called with the same array, the new // ActiveHelp line will be shown below the previous ones when completion is triggered. -func AppendActiveHelp(compArray []string, activeHelpStr string) []string { +func AppendActiveHelp(compArray []Completion, activeHelpStr string) []Completion { return append(compArray, fmt.Sprintf("%s%s", activeHelpMarker, activeHelpStr)) } diff --git a/vendor/github.com/spf13/cobra/bash_completionsV2.go b/vendor/github.com/spf13/cobra/bash_completionsV2.go index 1cce5c329c20..d2397aa3668c 100644 --- a/vendor/github.com/spf13/cobra/bash_completionsV2.go +++ b/vendor/github.com/spf13/cobra/bash_completionsV2.go @@ -146,7 +146,7 @@ __%[1]s_process_completion_results() { if (((directive & shellCompDirectiveFilterFileExt) != 0)); then # File extension filtering - local fullFilter filter filteringCmd + local fullFilter="" filter filteringCmd # Do not use quotes around the $completions variable or else newline # characters will be kept. @@ -177,20 +177,71 @@ __%[1]s_process_completion_results() { __%[1]s_handle_special_char "$cur" = # Print the activeHelp statements before we finish + __%[1]s_handle_activeHelp +} + +__%[1]s_handle_activeHelp() { + # Print the activeHelp statements if ((${#activeHelp[*]} != 0)); then - printf "\n"; - printf "%%s\n" "${activeHelp[@]}" - printf "\n" - - # The prompt format is only available from bash 4.4. - # We test if it is available before using it. - if (x=${PS1@P}) 2> /dev/null; then - printf "%%s" "${PS1@P}${COMP_LINE[@]}" - else - # Can't print the prompt. Just print the - # text the user had typed, it is workable enough. - printf "%%s" "${COMP_LINE[@]}" + if [ -z $COMP_TYPE ]; then + # Bash v3 does not set the COMP_TYPE variable. + printf "\n"; + printf "%%s\n" "${activeHelp[@]}" + printf "\n" + __%[1]s_reprint_commandLine + return fi + + # Only print ActiveHelp on the second TAB press + if [ $COMP_TYPE -eq 63 ]; then + printf "\n" + printf "%%s\n" "${activeHelp[@]}" + + if ((${#COMPREPLY[*]} == 0)); then + # When there are no completion choices from the program, file completion + # may kick in if the program has not disabled it; in such a case, we want + # to know if any files will match what the user typed, so that we know if + # there will be completions presented, so that we know how to handle ActiveHelp. + # To find out, we actually trigger the file completion ourselves; + # the call to _filedir will fill COMPREPLY if files match. + if (((directive & shellCompDirectiveNoFileComp) == 0)); then + __%[1]s_debug "Listing files" + _filedir + fi + fi + + if ((${#COMPREPLY[*]} != 0)); then + # If there are completion choices to be shown, print a delimiter. + # Re-printing the command-line will automatically be done + # by the shell when it prints the completion choices. + printf -- "--" + else + # When there are no completion choices at all, we need + # to re-print the command-line since the shell will + # not be doing it itself. + __%[1]s_reprint_commandLine + fi + elif [ $COMP_TYPE -eq 37 ] || [ $COMP_TYPE -eq 42 ]; then + # For completion type: menu-complete/menu-complete-backward and insert-completions + # the completions are immediately inserted into the command-line, so we first + # print the activeHelp message and reprint the command-line since the shell won't. + printf "\n" + printf "%%s\n" "${activeHelp[@]}" + + __%[1]s_reprint_commandLine + fi + fi +} + +__%[1]s_reprint_commandLine() { + # The prompt format is only available from bash 4.4. + # We test if it is available before using it. + if (x=${PS1@P}) 2> /dev/null; then + printf "%%s" "${PS1@P}${COMP_LINE[@]}" + else + # Can't print the prompt. Just print the + # text the user had typed, it is workable enough. + printf "%%s" "${COMP_LINE[@]}" fi } @@ -201,6 +252,8 @@ __%[1]s_extract_activeHelp() { local endIndex=${#activeHelpMarker} while IFS='' read -r comp; do + [[ -z $comp ]] && continue + if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then comp=${comp:endIndex} __%[1]s_debug "ActiveHelp found: $comp" @@ -223,16 +276,21 @@ __%[1]s_handle_completion_types() { # If the user requested inserting one completion at a time, or all # completions at once on the command-line we must remove the descriptions. # https://github.com/spf13/cobra/issues/1508 - local tab=$'\t' comp - while IFS='' read -r comp; do - [[ -z $comp ]] && continue - # Strip any description - comp=${comp%%%%$tab*} - # Only consider the completions that match - if [[ $comp == "$cur"* ]]; then - COMPREPLY+=("$comp") - fi - done < <(printf "%%s\n" "${completions[@]}") + + # If there are no completions, we don't need to do anything + (( ${#completions[@]} == 0 )) && return 0 + + local tab=$'\t' + + # Strip any description and escape the completion to handled special characters + IFS=$'\n' read -ra completions -d '' < <(printf "%%q\n" "${completions[@]%%%%$tab*}") + + # Only consider the completions that match + IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}") + + # compgen looses the escaping so we need to escape all completions again since they will + # all be inserted on the command-line. + IFS=$'\n' read -ra COMPREPLY -d '' < <(printf "%%q\n" "${COMPREPLY[@]}") ;; *) @@ -243,11 +301,25 @@ __%[1]s_handle_completion_types() { } __%[1]s_handle_standard_completion_case() { - local tab=$'\t' comp + local tab=$'\t' + + # If there are no completions, we don't need to do anything + (( ${#completions[@]} == 0 )) && return 0 # Short circuit to optimize if we don't have descriptions if [[ "${completions[*]}" != *$tab* ]]; then - IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur") + # First, escape the completions to handle special characters + IFS=$'\n' read -ra completions -d '' < <(printf "%%q\n" "${completions[@]}") + # Only consider the completions that match what the user typed + IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}") + + # compgen looses the escaping so, if there is only a single completion, we need to + # escape it again because it will be inserted on the command-line. If there are multiple + # completions, we don't want to escape them because they will be printed in a list + # and we don't want to show escape characters in that list. + if (( ${#COMPREPLY[@]} == 1 )); then + COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]}") + fi return 0 fi @@ -256,23 +328,39 @@ __%[1]s_handle_standard_completion_case() { # Look for the longest completion so that we can format things nicely while IFS='' read -r compline; do [[ -z $compline ]] && continue - # Strip any description before checking the length - comp=${compline%%%%$tab*} + + # Before checking if the completion matches what the user typed, + # we need to strip any description and escape the completion to handle special + # characters because those escape characters are part of what the user typed. + # Don't call "printf" in a sub-shell because it will be much slower + # since we are in a loop. + printf -v comp "%%q" "${compline%%%%$tab*}" &>/dev/null || comp=$(printf "%%q" "${compline%%%%$tab*}") + # Only consider the completions that match [[ $comp == "$cur"* ]] || continue + + # The completions matches. Add it to the list of full completions including + # its description. We don't escape the completion because it may get printed + # in a list if there are more than one and we don't want show escape characters + # in that list. COMPREPLY+=("$compline") + + # Strip any description before checking the length, and again, don't escape + # the completion because this length is only used when printing the completions + # in a list and we don't want show escape characters in that list. + comp=${compline%%%%$tab*} if ((${#comp}>longest)); then longest=${#comp} fi done < <(printf "%%s\n" "${completions[@]}") - # If there is a single completion left, remove the description text + # If there is a single completion left, remove the description text and escape any special characters if ((${#COMPREPLY[*]} == 1)); then __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" - comp="${COMPREPLY[0]%%%%$tab*}" - __%[1]s_debug "Removed description from single completion, which is now: ${comp}" - COMPREPLY[0]=$comp - else # Format the descriptions + COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]%%%%$tab*}") + __%[1]s_debug "Removed description from single completion, which is now: ${COMPREPLY[0]}" + else + # Format the descriptions __%[1]s_format_comp_descriptions $longest fi } diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go index e0b0947b04c9..d9cd2414e237 100644 --- a/vendor/github.com/spf13/cobra/cobra.go +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -176,12 +176,16 @@ func rpad(s string, padding int) string { return fmt.Sprintf(formattedString, s) } -// tmpl executes the given template text on data, writing the result to w. -func tmpl(w io.Writer, text string, data interface{}) error { - t := template.New("top") - t.Funcs(templateFuncs) - template.Must(t.Parse(text)) - return t.Execute(w, data) +func tmpl(text string) *tmplFunc { + return &tmplFunc{ + tmpl: text, + fn: func(w io.Writer, data interface{}) error { + t := template.New("top") + t.Funcs(templateFuncs) + template.Must(t.Parse(text)) + return t.Execute(w, data) + }, + } } // ld compares two strings and returns the levenshtein distance between them. diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index 54748fc67ebd..dbb2c298ba08 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -33,6 +33,9 @@ import ( const ( FlagSetByCobraAnnotation = "cobra_annotation_flag_set_by_cobra" CommandDisplayNameAnnotation = "cobra_annotation_command_display_name" + + helpFlagName = "help" + helpCommandName = "help" ) // FParseErrWhitelist configures Flag parse errors to be ignored @@ -80,11 +83,11 @@ type Command struct { Example string // ValidArgs is list of all valid non-flag arguments that are accepted in shell completions - ValidArgs []string + ValidArgs []Completion // ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion. // It is a dynamic version of using ValidArgs. // Only one of ValidArgs and ValidArgsFunction can be used for a command. - ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) + ValidArgsFunction CompletionFunc // Expected arguments Args PositionalArgs @@ -168,12 +171,12 @@ type Command struct { // usageFunc is usage func defined by user. usageFunc func(*Command) error // usageTemplate is usage template defined by user. - usageTemplate string + usageTemplate *tmplFunc // flagErrorFunc is func defined by user and it's called when the parsing of // flags returns an error. flagErrorFunc func(*Command, error) error // helpTemplate is help template defined by user. - helpTemplate string + helpTemplate *tmplFunc // helpFunc is help func defined by user. helpFunc func(*Command, []string) // helpCommand is command with usage 'help'. If it's not defined by user, @@ -186,7 +189,7 @@ type Command struct { completionCommandGroupID string // versionTemplate is the version template defined by user. - versionTemplate string + versionTemplate *tmplFunc // errPrefix is the error message prefix defined by user. errPrefix string @@ -281,6 +284,7 @@ func (c *Command) SetArgs(a []string) { // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. +// // Deprecated: Use SetOut and/or SetErr instead func (c *Command) SetOutput(output io.Writer) { c.outWriter = output @@ -312,7 +316,11 @@ func (c *Command) SetUsageFunc(f func(*Command) error) { // SetUsageTemplate sets usage template. Can be defined by Application. func (c *Command) SetUsageTemplate(s string) { - c.usageTemplate = s + if s == "" { + c.usageTemplate = nil + return + } + c.usageTemplate = tmpl(s) } // SetFlagErrorFunc sets a function to generate an error when flag parsing @@ -348,12 +356,20 @@ func (c *Command) SetCompletionCommandGroupID(groupID string) { // SetHelpTemplate sets help template to be used. Application can use it to set custom template. func (c *Command) SetHelpTemplate(s string) { - c.helpTemplate = s + if s == "" { + c.helpTemplate = nil + return + } + c.helpTemplate = tmpl(s) } // SetVersionTemplate sets version template to be used. Application can use it to set custom template. func (c *Command) SetVersionTemplate(s string) { - c.versionTemplate = s + if s == "" { + c.versionTemplate = nil + return + } + c.versionTemplate = tmpl(s) } // SetErrPrefix sets error message prefix to be used. Application can use it to set custom prefix. @@ -434,7 +450,8 @@ func (c *Command) UsageFunc() (f func(*Command) error) { } return func(c *Command) error { c.mergePersistentFlags() - err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) + fn := c.getUsageTemplateFunc() + err := fn(c.OutOrStderr(), c) if err != nil { c.PrintErrln(err) } @@ -442,6 +459,19 @@ func (c *Command) UsageFunc() (f func(*Command) error) { } } +// getUsageTemplateFunc returns the usage template function for the command +// going up the command tree if necessary. +func (c *Command) getUsageTemplateFunc() func(w io.Writer, data interface{}) error { + if c.usageTemplate != nil { + return c.usageTemplate.fn + } + + if c.HasParent() { + return c.parent.getUsageTemplateFunc() + } + return defaultUsageFunc +} + // Usage puts out the usage for the command. // Used when a user provides invalid input. // Can be defined by user by overriding UsageFunc. @@ -460,15 +490,30 @@ func (c *Command) HelpFunc() func(*Command, []string) { } return func(c *Command, a []string) { c.mergePersistentFlags() + fn := c.getHelpTemplateFunc() // The help should be sent to stdout // See https://github.com/spf13/cobra/issues/1002 - err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) + err := fn(c.OutOrStdout(), c) if err != nil { c.PrintErrln(err) } } } +// getHelpTemplateFunc returns the help template function for the command +// going up the command tree if necessary. +func (c *Command) getHelpTemplateFunc() func(w io.Writer, data interface{}) error { + if c.helpTemplate != nil { + return c.helpTemplate.fn + } + + if c.HasParent() { + return c.parent.getHelpTemplateFunc() + } + + return defaultHelpFunc +} + // Help puts out the help for the command. // Used when a user calls help [command]. // Can be defined by user by overriding HelpFunc. @@ -543,71 +588,55 @@ func (c *Command) NamePadding() int { } // UsageTemplate returns usage template for the command. +// This function is kept for backwards-compatibility reasons. func (c *Command) UsageTemplate() string { - if c.usageTemplate != "" { - return c.usageTemplate + if c.usageTemplate != nil { + return c.usageTemplate.tmpl } if c.HasParent() { return c.parent.UsageTemplate() } - return `Usage:{{if .Runnable}} - {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} - {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} - -Aliases: - {{.NameAndAliases}}{{end}}{{if .HasExample}} - -Examples: -{{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}} - -Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}} - -{{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}} - -Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - -Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} -` + return defaultUsageTemplate } // HelpTemplate return help template for the command. +// This function is kept for backwards-compatibility reasons. func (c *Command) HelpTemplate() string { - if c.helpTemplate != "" { - return c.helpTemplate + if c.helpTemplate != nil { + return c.helpTemplate.tmpl } if c.HasParent() { return c.parent.HelpTemplate() } - return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} - -{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` + return defaultHelpTemplate } // VersionTemplate return version template for the command. +// This function is kept for backwards-compatibility reasons. func (c *Command) VersionTemplate() string { - if c.versionTemplate != "" { - return c.versionTemplate + if c.versionTemplate != nil { + return c.versionTemplate.tmpl } if c.HasParent() { return c.parent.VersionTemplate() } - return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}} -` + return defaultVersionTemplate +} + +// getVersionTemplateFunc returns the version template function for the command +// going up the command tree if necessary. +func (c *Command) getVersionTemplateFunc() func(w io.Writer, data interface{}) error { + if c.versionTemplate != nil { + return c.versionTemplate.fn + } + + if c.HasParent() { + return c.parent.getVersionTemplateFunc() + } + return defaultVersionFunc } // ErrPrefix return error message prefix for the command @@ -894,7 +923,7 @@ func (c *Command) execute(a []string) (err error) { // If help is called, regardless of other flags, return we want help. // Also say we need help if the command isn't runnable. - helpVal, err := c.Flags().GetBool("help") + helpVal, err := c.Flags().GetBool(helpFlagName) if err != nil { // should be impossible to get here as we always declare a help // flag in InitDefaultHelpFlag() @@ -914,7 +943,8 @@ func (c *Command) execute(a []string) (err error) { return err } if versionVal { - err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c) + fn := c.getVersionTemplateFunc() + err := fn(c.OutOrStdout(), c) if err != nil { c.Println(err) } @@ -1068,12 +1098,6 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { // initialize help at the last point to allow for user overriding c.InitDefaultHelpCmd() - // initialize completion at the last point to allow for user overriding - c.InitDefaultCompletionCmd() - - // Now that all commands have been created, let's make sure all groups - // are properly created also - c.checkCommandGroups() args := c.args @@ -1082,9 +1106,16 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { args = os.Args[1:] } - // initialize the hidden command to be used for shell completion + // initialize the __complete command to be used for shell completion c.initCompleteCmd(args) + // initialize the default completion command + c.InitDefaultCompletionCmd(args...) + + // Now that all commands have been created, let's make sure all groups + // are properly created also + c.checkCommandGroups() + var flags []string if c.TraverseChildren { cmd, flags, err = c.Traverse(args) @@ -1187,16 +1218,16 @@ func (c *Command) checkCommandGroups() { // If c already has help flag, it will do nothing. func (c *Command) InitDefaultHelpFlag() { c.mergePersistentFlags() - if c.Flags().Lookup("help") == nil { + if c.Flags().Lookup(helpFlagName) == nil { usage := "help for " - name := c.displayName() + name := c.DisplayName() if name == "" { usage += "this command" } else { usage += name } - c.Flags().BoolP("help", "h", false, usage) - _ = c.Flags().SetAnnotation("help", FlagSetByCobraAnnotation, []string{"true"}) + c.Flags().BoolP(helpFlagName, "h", false, usage) + _ = c.Flags().SetAnnotation(helpFlagName, FlagSetByCobraAnnotation, []string{"true"}) } } @@ -1215,7 +1246,7 @@ func (c *Command) InitDefaultVersionFlag() { if c.Name() == "" { usage += "this command" } else { - usage += c.Name() + usage += c.DisplayName() } if c.Flags().ShorthandLookup("v") == nil { c.Flags().BoolP("version", "v", false, usage) @@ -1239,9 +1270,9 @@ func (c *Command) InitDefaultHelpCmd() { Use: "help [command]", Short: "Help about any command", Long: `Help provides help for any command in the application. -Simply type ` + c.displayName() + ` help [path to command] for full details.`, - ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]string, ShellCompDirective) { - var completions []string +Simply type ` + c.DisplayName() + ` help [path to command] for full details.`, + ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) { + var completions []Completion cmd, _, e := c.Root().Find(args) if e != nil { return nil, ShellCompDirectiveNoFileComp @@ -1253,7 +1284,7 @@ Simply type ` + c.displayName() + ` help [path to command] for full details.`, for _, subCmd := range cmd.Commands() { if subCmd.IsAvailableCommand() || subCmd == cmd.helpCommand { if strings.HasPrefix(subCmd.Name(), toComplete) { - completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) + completions = append(completions, CompletionWithDesc(subCmd.Name(), subCmd.Short)) } } } @@ -1430,10 +1461,12 @@ func (c *Command) CommandPath() string { if c.HasParent() { return c.Parent().CommandPath() + " " + c.Name() } - return c.displayName() + return c.DisplayName() } -func (c *Command) displayName() string { +// DisplayName returns the name to display in help text. Returns command Name() +// If CommandDisplayNameAnnoation is not set +func (c *Command) DisplayName() string { if displayName, ok := c.Annotations[CommandDisplayNameAnnotation]; ok { return displayName } @@ -1443,7 +1476,7 @@ func (c *Command) displayName() string { // UseLine puts out the full usage for a given command (including parents). func (c *Command) UseLine() string { var useline string - use := strings.Replace(c.Use, c.Name(), c.displayName(), 1) + use := strings.Replace(c.Use, c.Name(), c.DisplayName(), 1) if c.HasParent() { useline = c.parent.CommandPath() + " " + use } else { @@ -1649,7 +1682,7 @@ func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) f // to this command (local and persistent declared here and by all parents). func (c *Command) Flags() *flag.FlagSet { if c.flags == nil { - c.flags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.flags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } @@ -1664,7 +1697,7 @@ func (c *Command) Flags() *flag.FlagSet { func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { persistentFlags := c.PersistentFlags() - out := flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + out := flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) c.LocalFlags().VisitAll(func(f *flag.Flag) { if persistentFlags.Lookup(f.Name) == nil { out.AddFlag(f) @@ -1679,7 +1712,7 @@ func (c *Command) LocalFlags() *flag.FlagSet { c.mergePersistentFlags() if c.lflags == nil { - c.lflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.lflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } @@ -1707,7 +1740,7 @@ func (c *Command) InheritedFlags() *flag.FlagSet { c.mergePersistentFlags() if c.iflags == nil { - c.iflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.iflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } @@ -1736,7 +1769,7 @@ func (c *Command) NonInheritedFlags() *flag.FlagSet { // PersistentFlags returns the persistent FlagSet specifically set in the current command. func (c *Command) PersistentFlags() *flag.FlagSet { if c.pflags == nil { - c.pflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.pflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } @@ -1749,9 +1782,9 @@ func (c *Command) PersistentFlags() *flag.FlagSet { func (c *Command) ResetFlags() { c.flagErrorBuf = new(bytes.Buffer) c.flagErrorBuf.Reset() - c.flags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.flags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) c.flags.SetOutput(c.flagErrorBuf) - c.pflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.pflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) c.pflags.SetOutput(c.flagErrorBuf) c.lflags = nil @@ -1868,7 +1901,7 @@ func (c *Command) mergePersistentFlags() { // If c.parentsPflags == nil, it makes new. func (c *Command) updateParentsPflags() { if c.parentsPflags == nil { - c.parentsPflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.parentsPflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) c.parentsPflags.SetOutput(c.flagErrorBuf) c.parentsPflags.SortFlags = false } @@ -1894,3 +1927,141 @@ func commandNameMatches(s string, t string) bool { return s == t } + +// tmplFunc holds a template and a function that will execute said template. +type tmplFunc struct { + tmpl string + fn func(io.Writer, interface{}) error +} + +var defaultUsageTemplate = `Usage:{{if .Runnable}} + {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} + {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} + +Aliases: + {{.NameAndAliases}}{{end}}{{if .HasExample}} + +Examples: +{{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}} + +Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}} + +{{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}} + +Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} + +Flags: +{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} + +Global Flags: +{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} + +Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + +Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} +` + +// defaultUsageFunc is equivalent to executing defaultUsageTemplate. The two should be changed in sync. +func defaultUsageFunc(w io.Writer, in interface{}) error { + c := in.(*Command) + fmt.Fprint(w, "Usage:") + if c.Runnable() { + fmt.Fprintf(w, "\n %s", c.UseLine()) + } + if c.HasAvailableSubCommands() { + fmt.Fprintf(w, "\n %s [command]", c.CommandPath()) + } + if len(c.Aliases) > 0 { + fmt.Fprintf(w, "\n\nAliases:\n") + fmt.Fprintf(w, " %s", c.NameAndAliases()) + } + if c.HasExample() { + fmt.Fprintf(w, "\n\nExamples:\n") + fmt.Fprintf(w, "%s", c.Example) + } + if c.HasAvailableSubCommands() { + cmds := c.Commands() + if len(c.Groups()) == 0 { + fmt.Fprintf(w, "\n\nAvailable Commands:") + for _, subcmd := range cmds { + if subcmd.IsAvailableCommand() || subcmd.Name() == helpCommandName { + fmt.Fprintf(w, "\n %s %s", rpad(subcmd.Name(), subcmd.NamePadding()), subcmd.Short) + } + } + } else { + for _, group := range c.Groups() { + fmt.Fprintf(w, "\n\n%s", group.Title) + for _, subcmd := range cmds { + if subcmd.GroupID == group.ID && (subcmd.IsAvailableCommand() || subcmd.Name() == helpCommandName) { + fmt.Fprintf(w, "\n %s %s", rpad(subcmd.Name(), subcmd.NamePadding()), subcmd.Short) + } + } + } + if !c.AllChildCommandsHaveGroup() { + fmt.Fprintf(w, "\n\nAdditional Commands:") + for _, subcmd := range cmds { + if subcmd.GroupID == "" && (subcmd.IsAvailableCommand() || subcmd.Name() == helpCommandName) { + fmt.Fprintf(w, "\n %s %s", rpad(subcmd.Name(), subcmd.NamePadding()), subcmd.Short) + } + } + } + } + } + if c.HasAvailableLocalFlags() { + fmt.Fprintf(w, "\n\nFlags:\n") + fmt.Fprint(w, trimRightSpace(c.LocalFlags().FlagUsages())) + } + if c.HasAvailableInheritedFlags() { + fmt.Fprintf(w, "\n\nGlobal Flags:\n") + fmt.Fprint(w, trimRightSpace(c.InheritedFlags().FlagUsages())) + } + if c.HasHelpSubCommands() { + fmt.Fprintf(w, "\n\nAdditional help topcis:") + for _, subcmd := range c.Commands() { + if subcmd.IsAdditionalHelpTopicCommand() { + fmt.Fprintf(w, "\n %s %s", rpad(subcmd.CommandPath(), subcmd.CommandPathPadding()), subcmd.Short) + } + } + } + if c.HasAvailableSubCommands() { + fmt.Fprintf(w, "\n\nUse \"%s [command] --help\" for more information about a command.", c.CommandPath()) + } + fmt.Fprintln(w) + return nil +} + +var defaultHelpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} + +{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` + +// defaultHelpFunc is equivalent to executing defaultHelpTemplate. The two should be changed in sync. +func defaultHelpFunc(w io.Writer, in interface{}) error { + c := in.(*Command) + usage := c.Long + if usage == "" { + usage = c.Short + } + usage = trimRightSpace(usage) + if usage != "" { + fmt.Fprintln(w, usage) + fmt.Fprintln(w) + } + if c.Runnable() || c.HasSubCommands() { + fmt.Fprint(w, c.UsageString()) + } + return nil +} + +var defaultVersionTemplate = `{{with .DisplayName}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}} +` + +// defaultVersionFunc is equivalent to executing defaultVersionTemplate. The two should be changed in sync. +func defaultVersionFunc(w io.Writer, in interface{}) error { + c := in.(*Command) + _, err := fmt.Fprintf(w, "%s version %s\n", c.DisplayName(), c.Version) + return err +} diff --git a/vendor/github.com/spf13/cobra/completions.go b/vendor/github.com/spf13/cobra/completions.go index c0c08b05721e..a1752f763175 100644 --- a/vendor/github.com/spf13/cobra/completions.go +++ b/vendor/github.com/spf13/cobra/completions.go @@ -35,7 +35,7 @@ const ( ) // Global map of flag completion functions. Make sure to use flagCompletionMutex before you try to read and write from it. -var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){} +var flagCompletionFunctions = map[*pflag.Flag]CompletionFunc{} // lock for reading and writing from flagCompletionFunctions var flagCompletionMutex = &sync.RWMutex{} @@ -117,22 +117,50 @@ type CompletionOptions struct { HiddenDefaultCmd bool } +// Completion is a string that can be used for completions +// +// two formats are supported: +// - the completion choice +// - the completion choice with a textual description (separated by a TAB). +// +// [CompletionWithDesc] can be used to create a completion string with a textual description. +// +// Note: Go type alias is used to provide a more descriptive name in the documentation, but any string can be used. +type Completion = string + +// CompletionFunc is a function that provides completion results. +type CompletionFunc = func(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) + +// CompletionWithDesc returns a [Completion] with a description by using the TAB delimited format. +func CompletionWithDesc(choice string, description string) Completion { + return choice + "\t" + description +} + // NoFileCompletions can be used to disable file completion for commands that should // not trigger file completions. -func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { +// +// This method satisfies [CompletionFunc]. +// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction]. +func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) { return nil, ShellCompDirectiveNoFileComp } // FixedCompletions can be used to create a completion function which always // returns the same results. -func FixedCompletions(choices []string, directive ShellCompDirective) func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { - return func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { +// +// This method returns a function that satisfies [CompletionFunc] +// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction]. +func FixedCompletions(choices []Completion, directive ShellCompDirective) CompletionFunc { + return func(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) { return choices, directive } } // RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag. -func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error { +// +// You can use pre-defined completion functions such as [FixedCompletions] or [NoFileCompletions], +// or you can define your own. +func (c *Command) RegisterFlagCompletionFunc(flagName string, f CompletionFunc) error { flag := c.Flag(flagName) if flag == nil { return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName) @@ -148,7 +176,7 @@ func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Comman } // GetFlagCompletionFunc returns the completion function for the given flag of the command, if available. -func (c *Command) GetFlagCompletionFunc(flagName string) (func(*Command, []string, string) ([]string, ShellCompDirective), bool) { +func (c *Command) GetFlagCompletionFunc(flagName string) (CompletionFunc, bool) { flag := c.Flag(flagName) if flag == nil { return nil, false @@ -270,7 +298,15 @@ func (c *Command) initCompleteCmd(args []string) { } } -func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDirective, error) { +// SliceValue is a reduced version of [pflag.SliceValue]. It is used to detect +// flags that accept multiple values and therefore can provide completion +// multiple times. +type SliceValue interface { + // GetSlice returns the flag value list as an array of strings. + GetSlice() []string +} + +func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCompDirective, error) { // The last argument, which is not completely typed by the user, // should not be part of the list of arguments toComplete := args[len(args)-1] @@ -298,7 +334,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi } if err != nil { // Unable to find the real command. E.g., someInvalidCmd - return c, []string{}, ShellCompDirectiveDefault, fmt.Errorf("unable to find a command for arguments: %v", trimmedArgs) + return c, []Completion{}, ShellCompDirectiveDefault, fmt.Errorf("unable to find a command for arguments: %v", trimmedArgs) } finalCmd.ctx = c.ctx @@ -328,7 +364,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi // Parse the flags early so we can check if required flags are set if err = finalCmd.ParseFlags(finalArgs); err != nil { - return finalCmd, []string{}, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error()) + return finalCmd, []Completion{}, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error()) } realArgCount := finalCmd.Flags().NArg() @@ -340,14 +376,14 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi if flagErr != nil { // If error type is flagCompError and we don't want flagCompletion we should ignore the error if _, ok := flagErr.(*flagCompError); !(ok && !flagCompletion) { - return finalCmd, []string{}, ShellCompDirectiveDefault, flagErr + return finalCmd, []Completion{}, ShellCompDirectiveDefault, flagErr } } // Look for the --help or --version flags. If they are present, // there should be no further completions. if helpOrVersionFlagPresent(finalCmd) { - return finalCmd, []string{}, ShellCompDirectiveNoFileComp, nil + return finalCmd, []Completion{}, ShellCompDirectiveNoFileComp, nil } // We only remove the flags from the arguments if DisableFlagParsing is not set. @@ -376,11 +412,11 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi return finalCmd, subDir, ShellCompDirectiveFilterDirs, nil } // Directory completion - return finalCmd, []string{}, ShellCompDirectiveFilterDirs, nil + return finalCmd, []Completion{}, ShellCompDirectiveFilterDirs, nil } } - var completions []string + var completions []Completion var directive ShellCompDirective // Enforce flag groups before doing flag completions @@ -399,10 +435,14 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi // If we have not found any required flags, only then can we show regular flags if len(completions) == 0 { doCompleteFlags := func(flag *pflag.Flag) { - if !flag.Changed || + _, acceptsMultiple := flag.Value.(SliceValue) + acceptsMultiple = acceptsMultiple || strings.Contains(flag.Value.Type(), "Slice") || - strings.Contains(flag.Value.Type(), "Array") { - // If the flag is not already present, or if it can be specified multiple times (Array or Slice) + strings.Contains(flag.Value.Type(), "Array") || + strings.HasPrefix(flag.Value.Type(), "stringTo") + + if !flag.Changed || acceptsMultiple { + // If the flag is not already present, or if it can be specified multiple times (Array, Slice, or stringTo) // we suggest it as a completion completions = append(completions, getFlagNameCompletions(flag, toComplete)...) } @@ -462,7 +502,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi for _, subCmd := range finalCmd.Commands() { if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand { if strings.HasPrefix(subCmd.Name(), toComplete) { - completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) + completions = append(completions, CompletionWithDesc(subCmd.Name(), subCmd.Short)) } directive = ShellCompDirectiveNoFileComp } @@ -507,7 +547,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi } // Find the completion function for the flag or command - var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) + var completionFn CompletionFunc if flag != nil && flagCompletion { flagCompletionMutex.RLock() completionFn = flagCompletionFunctions[flag] @@ -518,7 +558,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi if completionFn != nil { // Go custom completion defined for this flag or command. // Call the registered completion function to get the completions. - var comps []string + var comps []Completion comps, directive = completionFn(finalCmd, finalArgs, toComplete) completions = append(completions, comps...) } @@ -531,23 +571,23 @@ func helpOrVersionFlagPresent(cmd *Command) bool { len(versionFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && versionFlag.Changed { return true } - if helpFlag := cmd.Flags().Lookup("help"); helpFlag != nil && + if helpFlag := cmd.Flags().Lookup(helpFlagName); helpFlag != nil && len(helpFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && helpFlag.Changed { return true } return false } -func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string { +func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []Completion { if nonCompletableFlag(flag) { - return []string{} + return []Completion{} } - var completions []string + var completions []Completion flagName := "--" + flag.Name if strings.HasPrefix(flagName, toComplete) { // Flag without the = - completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) + completions = append(completions, CompletionWithDesc(flagName, flag.Usage)) // Why suggest both long forms: --flag and --flag= ? // This forces the user to *always* have to type either an = or a space after the flag name. @@ -559,20 +599,20 @@ func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string { // if len(flag.NoOptDefVal) == 0 { // // Flag requires a value, so it can be suffixed with = // flagName += "=" - // completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) + // completions = append(completions, CompletionWithDesc(flagName, flag.Usage)) // } } flagName = "-" + flag.Shorthand if len(flag.Shorthand) > 0 && strings.HasPrefix(flagName, toComplete) { - completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) + completions = append(completions, CompletionWithDesc(flagName, flag.Usage)) } return completions } -func completeRequireFlags(finalCmd *Command, toComplete string) []string { - var completions []string +func completeRequireFlags(finalCmd *Command, toComplete string) []Completion { + var completions []Completion doCompleteRequiredFlags := func(flag *pflag.Flag) { if _, present := flag.Annotations[BashCompOneRequiredFlag]; present { @@ -687,8 +727,8 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p // 1- the feature has been explicitly disabled by the program, // 2- c has no subcommands (to avoid creating one), // 3- c already has a 'completion' command provided by the program. -func (c *Command) InitDefaultCompletionCmd() { - if c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() { +func (c *Command) InitDefaultCompletionCmd(args ...string) { + if c.CompletionOptions.DisableDefaultCmd { return } @@ -701,6 +741,16 @@ func (c *Command) InitDefaultCompletionCmd() { haveNoDescFlag := !c.CompletionOptions.DisableNoDescFlag && !c.CompletionOptions.DisableDescriptions + // Special case to know if there are sub-commands or not. + hasSubCommands := false + for _, cmd := range c.commands { + if cmd.Name() != ShellCompRequestCmd && cmd.Name() != helpCommandName { + // We found a real sub-command (not 'help' or '__complete') + hasSubCommands = true + break + } + } + completionCmd := &Command{ Use: compCmdName, Short: "Generate the autocompletion script for the specified shell", @@ -714,6 +764,22 @@ See each sub-command's help for details on how to use the generated script. } c.AddCommand(completionCmd) + if !hasSubCommands { + // If the 'completion' command will be the only sub-command, + // we only create it if it is actually being called. + // This avoids breaking programs that would suddenly find themselves with + // a subcommand, which would prevent them from accepting arguments. + // We also create the 'completion' command if the user is triggering + // shell completion for it (prog __complete completion '') + subCmd, cmdArgs, err := c.Find(args) + if err != nil || subCmd.Name() != compCmdName && + !(subCmd.Name() == ShellCompRequestCmd && len(cmdArgs) > 1 && cmdArgs[0] == compCmdName) { + // The completion command is not being called or being completed so we remove it. + c.RemoveCommand(completionCmd) + return + } + } + out := c.OutOrStdout() noDesc := c.CompletionOptions.DisableDescriptions shortDesc := "Generate the autocompletion script for %s" diff --git a/vendor/github.com/spf13/cobra/powershell_completions.go b/vendor/github.com/spf13/cobra/powershell_completions.go index a830b7bcad2e..746dcb92e3ef 100644 --- a/vendor/github.com/spf13/cobra/powershell_completions.go +++ b/vendor/github.com/spf13/cobra/powershell_completions.go @@ -162,7 +162,10 @@ filter __%[1]s_escapeStringWithSpecialChars { if (-Not $Description) { $Description = " " } - @{Name="$Name";Description="$Description"} + New-Object -TypeName PSCustomObject -Property @{ + Name = "$Name" + Description = "$Description" + } } @@ -240,7 +243,12 @@ filter __%[1]s_escapeStringWithSpecialChars { __%[1]s_debug "Only one completion left" # insert space after value - [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + $CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space + if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){ + [System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + } else { + $CompletionText + } } else { # Add the proper number of spaces to align the descriptions @@ -255,7 +263,12 @@ filter __%[1]s_escapeStringWithSpecialChars { $Description = " ($($comp.Description))" } - [System.Management.Automation.CompletionResult]::new("$($comp.Name)$Description", "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)") + $CompletionText = "$($comp.Name)$Description" + if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){ + [System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)") + } else { + $CompletionText + } } } @@ -264,7 +277,13 @@ filter __%[1]s_escapeStringWithSpecialChars { # insert space after value # MenuComplete will automatically show the ToolTip of # the highlighted value at the bottom of the suggestions. - [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + + $CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space + if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){ + [System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + } else { + $CompletionText + } } # TabCompleteNext and in case we get something unknown @@ -272,7 +291,13 @@ filter __%[1]s_escapeStringWithSpecialChars { # Like MenuComplete but we don't want to add a space here because # the user need to press space anyway to get the completion. # Description will not be shown because that's not possible with TabCompleteNext - [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + + $CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){ + [System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + } else { + $CompletionText + } } } diff --git a/vendor/github.com/spf13/cobra/ya.make b/vendor/github.com/spf13/cobra/ya.make index 2d15e11c9bfd..58aedc1bf36e 100644 --- a/vendor/github.com/spf13/cobra/ya.make +++ b/vendor/github.com/spf13/cobra/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(Apache-2.0) -VERSION(v1.8.1) +VERSION(v1.9.1) SRCS( active_help.go diff --git a/vendor/github.com/spf13/pflag/ip.go b/vendor/github.com/spf13/pflag/ip.go index 3d414ba69fe1..06b8bcb57215 100644 --- a/vendor/github.com/spf13/pflag/ip.go +++ b/vendor/github.com/spf13/pflag/ip.go @@ -16,6 +16,9 @@ func newIPValue(val net.IP, p *net.IP) *ipValue { func (i *ipValue) String() string { return net.IP(*i).String() } func (i *ipValue) Set(s string) error { + if s == "" { + return nil + } ip := net.ParseIP(strings.TrimSpace(s)) if ip == nil { return fmt.Errorf("failed to parse IP: %q", s) diff --git a/vendor/github.com/spf13/pflag/ya.make b/vendor/github.com/spf13/pflag/ya.make index c40c23cce934..bef4b61d6b7e 100644 --- a/vendor/github.com/spf13/pflag/ya.make +++ b/vendor/github.com/spf13/pflag/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(BSD-3-Clause) -VERSION(v1.0.6-0.20201009195203-85dd5c8bc61c) +VERSION(v1.0.6) SRCS( bool.go diff --git a/vendor/golang.org/x/crypto/pbkdf2/ya.make b/vendor/golang.org/x/crypto/pbkdf2/ya.make index 0c1ba119c459..707da3616c75 100644 --- a/vendor/golang.org/x/crypto/pbkdf2/ya.make +++ b/vendor/golang.org/x/crypto/pbkdf2/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(BSD-3-Clause) -VERSION(v0.32.0) +VERSION(v0.33.0) SRCS( pbkdf2.go diff --git a/vendor/golang.org/x/crypto/scrypt/ya.make b/vendor/golang.org/x/crypto/scrypt/ya.make index 5e20fa7c1759..5ba22b0c2d17 100644 --- a/vendor/golang.org/x/crypto/scrypt/ya.make +++ b/vendor/golang.org/x/crypto/scrypt/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(BSD-3-Clause) -VERSION(v0.32.0) +VERSION(v0.33.0) SRCS( scrypt.go diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go index aa69fb4d509f..db7806cb9945 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go @@ -180,6 +180,8 @@ type CommonLanguageSettings struct { ReferenceDocsUri string `protobuf:"bytes,1,opt,name=reference_docs_uri,json=referenceDocsUri,proto3" json:"reference_docs_uri,omitempty"` // The destination where API teams want this client library to be published. Destinations []ClientLibraryDestination `protobuf:"varint,2,rep,packed,name=destinations,proto3,enum=google.api.ClientLibraryDestination" json:"destinations,omitempty"` + // Configuration for which RPCs should be generated in the GAPIC client. + SelectiveGapicGeneration *SelectiveGapicGeneration `protobuf:"bytes,3,opt,name=selective_gapic_generation,json=selectiveGapicGeneration,proto3" json:"selective_gapic_generation,omitempty"` } func (x *CommonLanguageSettings) Reset() { @@ -229,6 +231,13 @@ func (x *CommonLanguageSettings) GetDestinations() []ClientLibraryDestination { return nil } +func (x *CommonLanguageSettings) GetSelectiveGapicGeneration() *SelectiveGapicGeneration { + if x != nil { + return x.SelectiveGapicGeneration + } + return nil +} + // Details about how and where to publish client libraries. type ClientLibrarySettings struct { state protoimpl.MessageState @@ -984,6 +993,16 @@ type GoSettings struct { // Some settings. Common *CommonLanguageSettings `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"` + // Map of service names to renamed services. Keys are the package relative + // service names and values are the name to be used for the service client + // and call options. + // + // publishing: + // + // go_settings: + // renamed_services: + // Publisher: TopicAdmin + RenamedServices map[string]string `protobuf:"bytes,2,rep,name=renamed_services,json=renamedServices,proto3" json:"renamed_services,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *GoSettings) Reset() { @@ -1025,6 +1044,13 @@ func (x *GoSettings) GetCommon() *CommonLanguageSettings { return nil } +func (x *GoSettings) GetRenamedServices() map[string]string { + if x != nil { + return x.RenamedServices + } + return nil +} + // Describes the generator configuration for a method. type MethodSettings struct { state protoimpl.MessageState @@ -1123,6 +1149,71 @@ func (x *MethodSettings) GetAutoPopulatedFields() []string { return nil } +// This message is used to configure the generation of a subset of the RPCs in +// a service for client libraries. +type SelectiveGapicGeneration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // An allowlist of the fully qualified names of RPCs that should be included + // on public client surfaces. + Methods []string `protobuf:"bytes,1,rep,name=methods,proto3" json:"methods,omitempty"` + // Setting this to true indicates to the client generators that methods + // that would be excluded from the generation should instead be generated + // in a way that indicates these methods should not be consumed by + // end users. How this is expressed is up to individual language + // implementations to decide. Some examples may be: added annotations, + // obfuscated identifiers, or other language idiomatic patterns. + GenerateOmittedAsInternal bool `protobuf:"varint,2,opt,name=generate_omitted_as_internal,json=generateOmittedAsInternal,proto3" json:"generate_omitted_as_internal,omitempty"` +} + +func (x *SelectiveGapicGeneration) Reset() { + *x = SelectiveGapicGeneration{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SelectiveGapicGeneration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SelectiveGapicGeneration) ProtoMessage() {} + +func (x *SelectiveGapicGeneration) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SelectiveGapicGeneration.ProtoReflect.Descriptor instead. +func (*SelectiveGapicGeneration) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{12} +} + +func (x *SelectiveGapicGeneration) GetMethods() []string { + if x != nil { + return x.Methods + } + return nil +} + +func (x *SelectiveGapicGeneration) GetGenerateOmittedAsInternal() bool { + if x != nil { + return x.GenerateOmittedAsInternal + } + return false +} + // Experimental features to be included during client library generation. // These fields will be deprecated once the feature graduates and is enabled // by default. @@ -1136,12 +1227,22 @@ type PythonSettings_ExperimentalFeatures struct { // This feature will be enabled by default 1 month after launching the // feature in preview packages. RestAsyncIoEnabled bool `protobuf:"varint,1,opt,name=rest_async_io_enabled,json=restAsyncIoEnabled,proto3" json:"rest_async_io_enabled,omitempty"` + // Enables generation of protobuf code using new types that are more + // Pythonic which are included in `protobuf>=5.29.x`. This feature will be + // enabled by default 1 month after launching the feature in preview + // packages. + ProtobufPythonicTypesEnabled bool `protobuf:"varint,2,opt,name=protobuf_pythonic_types_enabled,json=protobufPythonicTypesEnabled,proto3" json:"protobuf_pythonic_types_enabled,omitempty"` + // Disables generation of an unversioned Python package for this client + // library. This means that the module names will need to be versioned in + // import statements. For example `import google.cloud.library_v2` instead + // of `import google.cloud.library`. + UnversionedPackageDisabled bool `protobuf:"varint,3,opt,name=unversioned_package_disabled,json=unversionedPackageDisabled,proto3" json:"unversioned_package_disabled,omitempty"` } func (x *PythonSettings_ExperimentalFeatures) Reset() { *x = PythonSettings_ExperimentalFeatures{} if protoimpl.UnsafeEnabled { - mi := &file_google_api_client_proto_msgTypes[13] + mi := &file_google_api_client_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1154,7 +1255,7 @@ func (x *PythonSettings_ExperimentalFeatures) String() string { func (*PythonSettings_ExperimentalFeatures) ProtoMessage() {} func (x *PythonSettings_ExperimentalFeatures) ProtoReflect() protoreflect.Message { - mi := &file_google_api_client_proto_msgTypes[13] + mi := &file_google_api_client_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1177,6 +1278,20 @@ func (x *PythonSettings_ExperimentalFeatures) GetRestAsyncIoEnabled() bool { return false } +func (x *PythonSettings_ExperimentalFeatures) GetProtobufPythonicTypesEnabled() bool { + if x != nil { + return x.ProtobufPythonicTypesEnabled + } + return false +} + +func (x *PythonSettings_ExperimentalFeatures) GetUnversionedPackageDisabled() bool { + if x != nil { + return x.UnversionedPackageDisabled + } + return false +} + // Describes settings to use when generating API methods that use the // long-running operation pattern. // All default values below are from those used in the client library @@ -1205,7 +1320,7 @@ type MethodSettings_LongRunning struct { func (x *MethodSettings_LongRunning) Reset() { *x = MethodSettings_LongRunning{} if protoimpl.UnsafeEnabled { - mi := &file_google_api_client_proto_msgTypes[16] + mi := &file_google_api_client_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1218,7 +1333,7 @@ func (x *MethodSettings_LongRunning) String() string { func (*MethodSettings_LongRunning) ProtoMessage() {} func (x *MethodSettings_LongRunning) ProtoReflect() protoreflect.Message { - mi := &file_google_api_client_proto_msgTypes[16] + mi := &file_google_api_client_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1406,7 +1521,7 @@ var file_google_api_client_proto_rawDesc = []byte{ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x94, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf8, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x30, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, @@ -1415,251 +1530,283 @@ var file_google_api_client_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x93, 0x05, - 0x0a, 0x15, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x3a, 0x0a, 0x0c, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x67, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x53, 0x74, 0x61, 0x67, 0x65, - 0x52, 0x0b, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, - 0x12, 0x72, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x65, 0x6e, - 0x75, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x65, 0x73, 0x74, 0x4e, - 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x45, 0x6e, 0x75, 0x6d, 0x73, 0x12, 0x3d, 0x0a, 0x0d, 0x6a, - 0x61, 0x76, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x15, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x4a, 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x6a, 0x61, - 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x0c, 0x63, 0x70, - 0x70, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x70, - 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0b, 0x63, 0x70, 0x70, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x0c, 0x70, 0x68, 0x70, 0x5f, 0x73, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x68, 0x70, 0x53, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0b, 0x70, 0x68, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3d, 0x0a, 0x0d, 0x6e, 0x6f, 0x64, 0x65, 0x5f, - 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x6f, 0x64, 0x65, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x64, 0x6f, 0x74, 0x6e, 0x65, 0x74, - 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x74, - 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x64, 0x6f, 0x74, - 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3d, 0x0a, 0x0d, 0x72, - 0x75, 0x62, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x1b, 0x20, 0x01, + 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x62, 0x0a, + 0x1a, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x67, 0x61, 0x70, 0x69, 0x63, + 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x61, 0x70, 0x69, 0x63, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x18, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x76, 0x65, 0x47, 0x61, 0x70, 0x69, 0x63, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x93, 0x05, 0x0a, 0x15, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, + 0x61, 0x72, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x0c, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, + 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x53, + 0x74, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x53, 0x74, 0x61, 0x67, + 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, + 0x63, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, + 0x65, 0x73, 0x74, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x45, 0x6e, 0x75, 0x6d, 0x73, 0x12, + 0x3d, 0x0a, 0x0d, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x52, 0x0c, 0x6a, 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, + 0x0a, 0x0c, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x16, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x43, 0x70, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0b, 0x63, + 0x70, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x0c, 0x70, 0x68, + 0x70, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x68, + 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0b, 0x70, 0x68, 0x70, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, + 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x79, 0x74, + 0x68, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x70, 0x79, 0x74, + 0x68, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3d, 0x0a, 0x0d, 0x6e, + 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x52, 0x75, 0x62, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x72, 0x75, - 0x62, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x37, 0x0a, 0x0b, 0x67, 0x6f, - 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x6f, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0a, 0x67, 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x22, 0xf4, 0x04, 0x0a, 0x0a, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, - 0x6e, 0x67, 0x12, 0x43, 0x0a, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x77, 0x5f, 0x69, - 0x73, 0x73, 0x75, 0x65, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x65, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x6e, 0x65, 0x77, 0x49, 0x73, 0x73, 0x75, 0x65, 0x55, 0x72, 0x69, 0x12, 0x2b, 0x0a, 0x11, 0x64, - 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x69, - 0x18, 0x66, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x70, 0x69, 0x5f, - 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x67, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x61, 0x70, 0x69, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, - 0x0a, 0x0c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x68, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x12, 0x34, 0x0a, 0x16, 0x63, 0x6f, 0x64, 0x65, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x69, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x14, 0x63, 0x6f, 0x64, 0x65, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x47, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x64, 0x6f, 0x63, 0x5f, 0x74, - 0x61, 0x67, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x6a, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x64, 0x6f, 0x63, 0x54, 0x61, 0x67, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x49, 0x0a, - 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x6b, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4f, 0x72, - 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, - 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4c, 0x0a, 0x10, 0x6c, 0x69, 0x62, 0x72, - 0x61, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x6d, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x53, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x49, 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, - 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x6e, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x1e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, - 0x69, 0x12, 0x47, 0x0a, 0x20, 0x72, 0x65, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x5f, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x6f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x72, 0x65, 0x73, - 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, - 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x22, 0x9a, 0x02, 0x0a, 0x0c, 0x4a, - 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6c, - 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x12, 0x5f, 0x0a, 0x13, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, - 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4a, - 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, - 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x1a, 0x44, 0x0a, 0x16, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, - 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x49, 0x0a, 0x0b, 0x43, 0x70, 0x70, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, - 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x22, 0x49, 0x0a, 0x0b, 0x50, 0x68, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xfd, 0x01, - 0x0a, 0x0e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x64, 0x0a, 0x15, - 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, - 0x6e, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x14, 0x65, 0x78, - 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x73, 0x1a, 0x49, 0x0a, 0x14, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, - 0x61, 0x6c, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x15, 0x72, 0x65, - 0x73, 0x74, 0x5f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x69, 0x6f, 0x5f, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x72, 0x65, 0x73, 0x74, 0x41, - 0x73, 0x79, 0x6e, 0x63, 0x49, 0x6f, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x4a, 0x0a, - 0x0c, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, - 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xae, 0x04, 0x0a, 0x0e, 0x44, 0x6f, - 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x10, 0x72, 0x65, 0x6e, 0x61, - 0x6d, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x44, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, - 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x12, 0x5d, 0x0a, 0x11, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x74, - 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6e, 0x61, - 0x6d, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, - 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x12, 0x38, 0x0a, 0x18, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x16, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x16, 0x68, 0x61, - 0x6e, 0x64, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, 0x68, 0x61, 0x6e, 0x64, - 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x73, 0x1a, 0x42, 0x0a, 0x14, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4a, 0x0a, 0x0c, 0x52, 0x75, - 0x62, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, + 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x6e, 0x6f, + 0x64, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x64, 0x6f, + 0x74, 0x6e, 0x65, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x1a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x44, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, + 0x0e, 0x64, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, + 0x3d, 0x0a, 0x0d, 0x72, 0x75, 0x62, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x52, 0x75, 0x62, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x52, 0x0c, 0x72, 0x75, 0x62, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x37, + 0x0a, 0x0b, 0x67, 0x6f, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x1c, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x47, 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0a, 0x67, 0x6f, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xf4, 0x04, 0x0a, 0x0a, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x12, 0x43, 0x0a, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6e, + 0x65, 0x77, 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x65, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x49, 0x73, 0x73, 0x75, 0x65, 0x55, 0x72, 0x69, 0x12, + 0x2b, 0x0a, 0x11, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x75, 0x72, 0x69, 0x18, 0x66, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x64, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x12, 0x24, 0x0a, 0x0e, + 0x61, 0x70, 0x69, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x67, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x70, 0x69, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x18, 0x68, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x34, 0x0a, 0x16, 0x63, 0x6f, 0x64, 0x65, 0x6f, 0x77, 0x6e, + 0x65, 0x72, 0x5f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x18, + 0x69, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x63, 0x6f, 0x64, 0x65, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x64, + 0x6f, 0x63, 0x5f, 0x74, 0x61, 0x67, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x6a, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x6f, 0x63, 0x54, 0x61, 0x67, 0x50, 0x72, 0x65, 0x66, 0x69, + 0x78, 0x12, 0x49, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x6b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, + 0x72, 0x79, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, + 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4c, 0x0a, 0x10, + 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x18, 0x6d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0f, 0x6c, 0x69, 0x62, 0x72, 0x61, + 0x72, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x49, 0x0a, 0x21, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x64, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x69, 0x18, + 0x6e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x12, 0x47, 0x0a, 0x20, 0x72, 0x65, 0x73, 0x74, 0x5f, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x6f, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x1d, 0x72, 0x65, 0x73, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x44, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x22, 0x9a, + 0x02, 0x0a, 0x0c, 0x4a, 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, + 0x27, 0x0a, 0x0f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x79, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x5f, 0x0a, 0x13, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, + 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x1a, 0x44, 0x0a, 0x16, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x49, 0x0a, 0x0b, 0x43, + 0x70, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0x48, 0x0a, 0x0a, 0x47, 0x6f, 0x53, 0x65, 0x74, 0x74, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0x49, 0x0a, 0x0b, 0x50, 0x68, 0x70, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, + 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x22, 0x87, 0x03, 0x0a, 0x0e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x22, 0xc2, 0x03, 0x0a, 0x0e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, - 0x49, 0x0a, 0x0c, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x2e, 0x4c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x6c, - 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x32, 0x0a, 0x15, 0x61, 0x75, - 0x74, 0x6f, 0x5f, 0x70, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x50, - 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x94, - 0x02, 0x0a, 0x0b, 0x4c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x47, - 0x0a, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x6f, - 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x13, 0x70, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, - 0x79, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x0e, 0x6d, - 0x61, 0x78, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, + 0x12, 0x64, 0x0a, 0x15, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, + 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x79, 0x74, + 0x68, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x65, + 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x52, 0x14, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x46, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0xd2, 0x01, 0x0a, 0x14, 0x45, 0x78, 0x70, 0x65, 0x72, + 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, + 0x31, 0x0a, 0x15, 0x72, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x69, 0x6f, + 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, + 0x72, 0x65, 0x73, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x49, 0x6f, 0x45, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x12, 0x45, 0x0a, 0x1f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x5f, 0x70, + 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x69, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5f, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x69, 0x63, 0x54, 0x79, 0x70, + 0x65, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x40, 0x0a, 0x1c, 0x75, 0x6e, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, + 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x1a, 0x75, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, + 0x61, 0x67, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x4a, 0x0a, 0x0c, 0x4e, + 0x6f, 0x64, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, + 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, + 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xae, 0x04, 0x0a, 0x0e, 0x44, 0x6f, 0x74, 0x6e, + 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, + 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, + 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, + 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6e, + 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x12, 0x5d, 0x0a, 0x11, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x74, 0x6e, 0x65, + 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x69, 0x67, + 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x38, + 0x0a, 0x18, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x16, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x16, 0x68, 0x61, 0x6e, 0x64, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, 0x68, 0x61, 0x6e, 0x64, 0x77, 0x72, + 0x69, 0x74, 0x74, 0x65, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, + 0x42, 0x0a, 0x14, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4a, 0x0a, 0x0c, 0x52, 0x75, 0x62, 0x79, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, + 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xe4, 0x01, 0x0a, 0x0a, 0x47, 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, + 0x56, 0x0a, 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0x42, 0x0a, 0x14, 0x52, 0x65, 0x6e, 0x61, 0x6d, + 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc2, 0x03, 0x0a, 0x0e, + 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x49, 0x0a, 0x0c, 0x6c, 0x6f, + 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x6f, 0x6e, + 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, + 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x32, 0x0a, 0x15, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x70, 0x6f, + 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x50, 0x6f, 0x70, 0x75, 0x6c, 0x61, + 0x74, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x94, 0x02, 0x0a, 0x0b, 0x4c, 0x6f, + 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x47, 0x0a, 0x12, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x10, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, + 0x61, 0x79, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, + 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x02, 0x52, 0x13, 0x70, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x75, 0x6c, 0x74, + 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x6f, + 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x50, 0x6f, + 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x47, 0x0a, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, - 0x6d, 0x61, 0x78, 0x50, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x47, 0x0a, 0x12, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, - 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x6f, 0x6c, 0x6c, 0x54, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x2a, 0xa3, 0x01, 0x0a, 0x19, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x27, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x4c, 0x49, - 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x52, 0x47, 0x41, 0x4e, 0x49, 0x5a, 0x41, 0x54, 0x49, - 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x4f, 0x55, 0x44, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, - 0x44, 0x53, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x48, 0x4f, 0x54, 0x4f, 0x53, 0x10, 0x03, - 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x52, 0x45, 0x45, 0x54, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x10, - 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x48, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, - 0x07, 0x0a, 0x03, 0x47, 0x45, 0x4f, 0x10, 0x06, 0x12, 0x11, 0x0a, 0x0d, 0x47, 0x45, 0x4e, 0x45, - 0x52, 0x41, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x49, 0x10, 0x07, 0x2a, 0x67, 0x0a, 0x18, 0x43, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x44, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x26, 0x43, 0x4c, 0x49, 0x45, 0x4e, - 0x54, 0x5f, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x54, 0x49, 0x4e, - 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x10, 0x0a, 0x12, - 0x13, 0x0a, 0x0f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x5f, 0x4d, 0x41, 0x4e, 0x41, 0x47, - 0x45, 0x52, 0x10, 0x14, 0x3a, 0x4a, 0x0a, 0x10, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9b, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x3a, 0x43, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, - 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x43, 0x0a, 0x0c, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x73, - 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, - 0x61, 0x75, 0x74, 0x68, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x3a, 0x44, 0x0a, 0x0b, 0x61, 0x70, - 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xc1, 0xba, 0xab, 0xfa, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x42, 0x69, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, - 0x70, 0x69, 0x42, 0x0b, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, - 0x01, 0x5a, 0x41, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, - 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x6f, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x22, 0x75, 0x0a, 0x18, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x61, 0x70, + 0x69, 0x63, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x5f, 0x6f, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x73, 0x5f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4f, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x41, 0x73, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2a, 0xa3, 0x01, 0x0a, 0x19, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x27, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x52, 0x47, 0x41, 0x4e, 0x49, 0x5a, 0x41, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x4f, 0x55, 0x44, 0x10, 0x01, 0x12, 0x07, 0x0a, + 0x03, 0x41, 0x44, 0x53, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x48, 0x4f, 0x54, 0x4f, 0x53, + 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x52, 0x45, 0x45, 0x54, 0x5f, 0x56, 0x49, 0x45, + 0x57, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x48, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, + 0x05, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x45, 0x4f, 0x10, 0x06, 0x12, 0x11, 0x0a, 0x0d, 0x47, 0x45, + 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x49, 0x10, 0x07, 0x2a, 0x67, 0x0a, + 0x18, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x44, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x26, 0x43, 0x4c, 0x49, + 0x45, 0x4e, 0x54, 0x5f, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x54, + 0x49, 0x4e, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x10, + 0x0a, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x5f, 0x4d, 0x41, 0x4e, + 0x41, 0x47, 0x45, 0x52, 0x10, 0x14, 0x3a, 0x4a, 0x0a, 0x10, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9b, 0x08, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x3a, 0x43, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x68, 0x6f, + 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x43, 0x0a, 0x0c, 0x6f, 0x61, 0x75, 0x74, 0x68, + 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x3a, 0x44, 0x0a, 0x0b, + 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xc1, 0xba, 0xab, + 0xfa, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x42, 0x69, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0b, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, + 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, + 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1675,7 +1822,7 @@ func file_google_api_client_proto_rawDescGZIP() []byte { } var file_google_api_client_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_google_api_client_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_google_api_client_proto_msgTypes = make([]protoimpl.MessageInfo, 19) var file_google_api_client_proto_goTypes = []interface{}{ (ClientLibraryOrganization)(0), // 0: google.api.ClientLibraryOrganization (ClientLibraryDestination)(0), // 1: google.api.ClientLibraryDestination @@ -1691,55 +1838,59 @@ var file_google_api_client_proto_goTypes = []interface{}{ (*RubySettings)(nil), // 11: google.api.RubySettings (*GoSettings)(nil), // 12: google.api.GoSettings (*MethodSettings)(nil), // 13: google.api.MethodSettings - nil, // 14: google.api.JavaSettings.ServiceClassNamesEntry - (*PythonSettings_ExperimentalFeatures)(nil), // 15: google.api.PythonSettings.ExperimentalFeatures - nil, // 16: google.api.DotnetSettings.RenamedServicesEntry - nil, // 17: google.api.DotnetSettings.RenamedResourcesEntry - (*MethodSettings_LongRunning)(nil), // 18: google.api.MethodSettings.LongRunning - (api.LaunchStage)(0), // 19: google.api.LaunchStage - (*durationpb.Duration)(nil), // 20: google.protobuf.Duration - (*descriptorpb.MethodOptions)(nil), // 21: google.protobuf.MethodOptions - (*descriptorpb.ServiceOptions)(nil), // 22: google.protobuf.ServiceOptions + (*SelectiveGapicGeneration)(nil), // 14: google.api.SelectiveGapicGeneration + nil, // 15: google.api.JavaSettings.ServiceClassNamesEntry + (*PythonSettings_ExperimentalFeatures)(nil), // 16: google.api.PythonSettings.ExperimentalFeatures + nil, // 17: google.api.DotnetSettings.RenamedServicesEntry + nil, // 18: google.api.DotnetSettings.RenamedResourcesEntry + nil, // 19: google.api.GoSettings.RenamedServicesEntry + (*MethodSettings_LongRunning)(nil), // 20: google.api.MethodSettings.LongRunning + (api.LaunchStage)(0), // 21: google.api.LaunchStage + (*durationpb.Duration)(nil), // 22: google.protobuf.Duration + (*descriptorpb.MethodOptions)(nil), // 23: google.protobuf.MethodOptions + (*descriptorpb.ServiceOptions)(nil), // 24: google.protobuf.ServiceOptions } var file_google_api_client_proto_depIdxs = []int32{ 1, // 0: google.api.CommonLanguageSettings.destinations:type_name -> google.api.ClientLibraryDestination - 19, // 1: google.api.ClientLibrarySettings.launch_stage:type_name -> google.api.LaunchStage - 5, // 2: google.api.ClientLibrarySettings.java_settings:type_name -> google.api.JavaSettings - 6, // 3: google.api.ClientLibrarySettings.cpp_settings:type_name -> google.api.CppSettings - 7, // 4: google.api.ClientLibrarySettings.php_settings:type_name -> google.api.PhpSettings - 8, // 5: google.api.ClientLibrarySettings.python_settings:type_name -> google.api.PythonSettings - 9, // 6: google.api.ClientLibrarySettings.node_settings:type_name -> google.api.NodeSettings - 10, // 7: google.api.ClientLibrarySettings.dotnet_settings:type_name -> google.api.DotnetSettings - 11, // 8: google.api.ClientLibrarySettings.ruby_settings:type_name -> google.api.RubySettings - 12, // 9: google.api.ClientLibrarySettings.go_settings:type_name -> google.api.GoSettings - 13, // 10: google.api.Publishing.method_settings:type_name -> google.api.MethodSettings - 0, // 11: google.api.Publishing.organization:type_name -> google.api.ClientLibraryOrganization - 3, // 12: google.api.Publishing.library_settings:type_name -> google.api.ClientLibrarySettings - 14, // 13: google.api.JavaSettings.service_class_names:type_name -> google.api.JavaSettings.ServiceClassNamesEntry - 2, // 14: google.api.JavaSettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 15: google.api.CppSettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 16: google.api.PhpSettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 17: google.api.PythonSettings.common:type_name -> google.api.CommonLanguageSettings - 15, // 18: google.api.PythonSettings.experimental_features:type_name -> google.api.PythonSettings.ExperimentalFeatures - 2, // 19: google.api.NodeSettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 20: google.api.DotnetSettings.common:type_name -> google.api.CommonLanguageSettings - 16, // 21: google.api.DotnetSettings.renamed_services:type_name -> google.api.DotnetSettings.RenamedServicesEntry - 17, // 22: google.api.DotnetSettings.renamed_resources:type_name -> google.api.DotnetSettings.RenamedResourcesEntry - 2, // 23: google.api.RubySettings.common:type_name -> google.api.CommonLanguageSettings - 2, // 24: google.api.GoSettings.common:type_name -> google.api.CommonLanguageSettings - 18, // 25: google.api.MethodSettings.long_running:type_name -> google.api.MethodSettings.LongRunning - 20, // 26: google.api.MethodSettings.LongRunning.initial_poll_delay:type_name -> google.protobuf.Duration - 20, // 27: google.api.MethodSettings.LongRunning.max_poll_delay:type_name -> google.protobuf.Duration - 20, // 28: google.api.MethodSettings.LongRunning.total_poll_timeout:type_name -> google.protobuf.Duration - 21, // 29: google.api.method_signature:extendee -> google.protobuf.MethodOptions - 22, // 30: google.api.default_host:extendee -> google.protobuf.ServiceOptions - 22, // 31: google.api.oauth_scopes:extendee -> google.protobuf.ServiceOptions - 22, // 32: google.api.api_version:extendee -> google.protobuf.ServiceOptions - 33, // [33:33] is the sub-list for method output_type - 33, // [33:33] is the sub-list for method input_type - 33, // [33:33] is the sub-list for extension type_name - 29, // [29:33] is the sub-list for extension extendee - 0, // [0:29] is the sub-list for field type_name + 14, // 1: google.api.CommonLanguageSettings.selective_gapic_generation:type_name -> google.api.SelectiveGapicGeneration + 21, // 2: google.api.ClientLibrarySettings.launch_stage:type_name -> google.api.LaunchStage + 5, // 3: google.api.ClientLibrarySettings.java_settings:type_name -> google.api.JavaSettings + 6, // 4: google.api.ClientLibrarySettings.cpp_settings:type_name -> google.api.CppSettings + 7, // 5: google.api.ClientLibrarySettings.php_settings:type_name -> google.api.PhpSettings + 8, // 6: google.api.ClientLibrarySettings.python_settings:type_name -> google.api.PythonSettings + 9, // 7: google.api.ClientLibrarySettings.node_settings:type_name -> google.api.NodeSettings + 10, // 8: google.api.ClientLibrarySettings.dotnet_settings:type_name -> google.api.DotnetSettings + 11, // 9: google.api.ClientLibrarySettings.ruby_settings:type_name -> google.api.RubySettings + 12, // 10: google.api.ClientLibrarySettings.go_settings:type_name -> google.api.GoSettings + 13, // 11: google.api.Publishing.method_settings:type_name -> google.api.MethodSettings + 0, // 12: google.api.Publishing.organization:type_name -> google.api.ClientLibraryOrganization + 3, // 13: google.api.Publishing.library_settings:type_name -> google.api.ClientLibrarySettings + 15, // 14: google.api.JavaSettings.service_class_names:type_name -> google.api.JavaSettings.ServiceClassNamesEntry + 2, // 15: google.api.JavaSettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 16: google.api.CppSettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 17: google.api.PhpSettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 18: google.api.PythonSettings.common:type_name -> google.api.CommonLanguageSettings + 16, // 19: google.api.PythonSettings.experimental_features:type_name -> google.api.PythonSettings.ExperimentalFeatures + 2, // 20: google.api.NodeSettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 21: google.api.DotnetSettings.common:type_name -> google.api.CommonLanguageSettings + 17, // 22: google.api.DotnetSettings.renamed_services:type_name -> google.api.DotnetSettings.RenamedServicesEntry + 18, // 23: google.api.DotnetSettings.renamed_resources:type_name -> google.api.DotnetSettings.RenamedResourcesEntry + 2, // 24: google.api.RubySettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 25: google.api.GoSettings.common:type_name -> google.api.CommonLanguageSettings + 19, // 26: google.api.GoSettings.renamed_services:type_name -> google.api.GoSettings.RenamedServicesEntry + 20, // 27: google.api.MethodSettings.long_running:type_name -> google.api.MethodSettings.LongRunning + 22, // 28: google.api.MethodSettings.LongRunning.initial_poll_delay:type_name -> google.protobuf.Duration + 22, // 29: google.api.MethodSettings.LongRunning.max_poll_delay:type_name -> google.protobuf.Duration + 22, // 30: google.api.MethodSettings.LongRunning.total_poll_timeout:type_name -> google.protobuf.Duration + 23, // 31: google.api.method_signature:extendee -> google.protobuf.MethodOptions + 24, // 32: google.api.default_host:extendee -> google.protobuf.ServiceOptions + 24, // 33: google.api.oauth_scopes:extendee -> google.protobuf.ServiceOptions + 24, // 34: google.api.api_version:extendee -> google.protobuf.ServiceOptions + 35, // [35:35] is the sub-list for method output_type + 35, // [35:35] is the sub-list for method input_type + 35, // [35:35] is the sub-list for extension type_name + 31, // [31:35] is the sub-list for extension extendee + 0, // [0:31] is the sub-list for field type_name } func init() { file_google_api_client_proto_init() } @@ -1892,7 +2043,19 @@ func file_google_api_client_proto_init() { return nil } } - file_google_api_client_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_google_api_client_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SelectiveGapicGeneration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PythonSettings_ExperimentalFeatures); i { case 0: return &v.state @@ -1904,7 +2067,7 @@ func file_google_api_client_proto_init() { return nil } } - file_google_api_client_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_google_api_client_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MethodSettings_LongRunning); i { case 0: return &v.state @@ -1923,7 +2086,7 @@ func file_google_api_client_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_google_api_client_proto_rawDesc, NumEnums: 2, - NumMessages: 17, + NumMessages: 19, NumExtensions: 4, NumServices: 0, }, diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go index ffb5838cb18b..c93b4f524876 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go @@ -663,14 +663,14 @@ var file_google_api_http_proto_rawDesc = []byte{ 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x48, 0x74, 0x74, 0x70, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x42, 0x6a, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, + 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x42, 0x67, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x09, 0x48, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x61, - 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x04, - 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, + 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go index b5db279aebf6..a1c543a94873 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go @@ -556,15 +556,14 @@ var file_google_api_resource_proto_rawDesc = []byte{ 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, - 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x6e, 0x0a, 0x0e, 0x63, 0x6f, + 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x6b, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go index 1d8397b02b45..2b54db304567 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go @@ -69,7 +69,7 @@ const ( // The routing header consists of one or multiple key-value pairs. Every key // and value must be percent-encoded, and joined together in the format of // `key1=value1&key2=value2`. -// In the examples below I am skipping the percent-encoding for readablity. +// The examples below skip the percent-encoding for readability. // // # Example 1 // diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/ya.make b/vendor/google.golang.org/genproto/googleapis/api/annotations/ya.make index 6b72eb083103..ff92710ad46d 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/ya.make +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(Apache-2.0) -VERSION(v0.0.0-20241015192408-796eee8c2d53) +VERSION(v0.0.0-20250218202821-56aae31c358a) SRCS( annotations.pb.go diff --git a/vendor/google.golang.org/genproto/googleapis/api/ya.make b/vendor/google.golang.org/genproto/googleapis/api/ya.make index 0fcc57d08c32..e3c4ed47dfda 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/ya.make +++ b/vendor/google.golang.org/genproto/googleapis/api/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(Apache-2.0) -VERSION(v0.0.0-20241015192408-796eee8c2d53) +VERSION(v0.0.0-20250218202821-56aae31c358a) SRCS( launch_stage.pb.go diff --git a/ya b/ya index e5e2e43d06a0..181c1ebe8625 100755 --- a/ya +++ b/ya @@ -39,33 +39,33 @@ REGISTRY_ENDPOINT = os.environ.get("YA_REGISTRY_ENDPOINT", "https://devtools-reg PLATFORM_MAP = { "data": { "win32": { - "md5": "a37a12e8dfd75366674a4e0867e1bdcf", + "md5": "3452c1706f37bf62d994367bd7f8aafc", "urls": [ - f"{REGISTRY_ENDPOINT}/8330123223" + f"{REGISTRY_ENDPOINT}/8533019849" ] }, "darwin": { - "md5": "81d284479554c704db2c83d894a12ec4", + "md5": "36940fce519b798318789559b417f42a", "urls": [ - f"{REGISTRY_ENDPOINT}/8330122613" + f"{REGISTRY_ENDPOINT}/8533017016" ] }, "darwin-arm64": { - "md5": "ee214d7fbe2750cf06d6c813c1dd4a6a", + "md5": "bd7edc55492f139ed39555e1a7a56be7", "urls": [ - f"{REGISTRY_ENDPOINT}/8330121658" + f"{REGISTRY_ENDPOINT}/8533014682" ] }, "linux-aarch64": { - "md5": "23da764827fbfdacdb4620d3182572b7", + "md5": "236ab9d8eb2f2fa3e115ef73af768973", "urls": [ - f"{REGISTRY_ENDPOINT}/8330121109" + f"{REGISTRY_ENDPOINT}/8533012028" ] }, "linux": { - "md5": "a8a2eea8357637d746b3b3acfc9f6bbf", + "md5": "e098353fa2ec7baa39d956e3f1d23c7e", "urls": [ - f"{REGISTRY_ENDPOINT}/8330124139" + f"{REGISTRY_ENDPOINT}/8533022295" ] } } diff --git a/ydb/apps/dstool/lib/dstool_cmd_group_virtual_create.py b/ydb/apps/dstool/lib/dstool_cmd_group_virtual_create.py index 54bc3aca8acb..b96993d1b2ef 100644 --- a/ydb/apps/dstool/lib/dstool_cmd_group_virtual_create.py +++ b/ydb/apps/dstool/lib/dstool_cmd_group_virtual_create.py @@ -53,9 +53,9 @@ def do(args): if s3_settings is not None: pb_json.Parse(s3_settings, cmd.S3BackendSettings) - cmd.ChannelProfiles.add(StoragePoolName=args.log_channel_sp, ChannelKind=blob_depot_config.TChannelKind.System) + cmd.ChannelProfiles.add(StoragePoolName=args.log_channel_sp, ChannelKind=blob_depot_config.TChannelKind.System, Count=1) chan1 = args.snapshot_channel_sp if args.snapshot_channel_sp is not None else args.log_channel_sp - cmd.ChannelProfiles.add(StoragePoolName=chan1, ChannelKind=blob_depot_config.TChannelKind.System) + cmd.ChannelProfiles.add(StoragePoolName=chan1, ChannelKind=blob_depot_config.TChannelKind.System, Count=1) for data_sp in args.data_channel_sp: pool_name, sep, count = data_sp.rpartition('*') if sep == '*': diff --git a/ydb/apps/etcd_proxy/proxy.cpp b/ydb/apps/etcd_proxy/proxy.cpp index 9f2fc4420f7b..f08b4a8dd004 100644 --- a/ydb/apps/etcd_proxy/proxy.cpp +++ b/ydb/apps/etcd_proxy/proxy.cpp @@ -61,7 +61,7 @@ int TProxy::Discovery() { } int TProxy::StartServer() { - if (const auto res = Stuff->Client->ExecuteQuery(NEtcd::GetLastRevisionSQL(), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); res.IsSuccess()) { + if (const auto res = Stuff->Client->ExecuteQuery(NEtcd::GetLastRevisionSQL(Stuff->TablePrefix), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); res.IsSuccess()) { if (auto result = res.GetResultSetParser(0); result.TryNextRow()) { Stuff->Revision.store(NYdb::TValueParser(result.GetValue(0)).GetInt64()); } else { @@ -129,7 +129,7 @@ int TProxy::Run() { } int TProxy::InitDatabase() { - if (const auto res = Stuff->Client->ExecuteQuery(NEtcd::GetCreateTablesSQL(), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); res.IsSuccess()) { + if (const auto res = Stuff->Client->ExecuteQuery(NEtcd::GetCreateTablesSQL(Stuff->TablePrefix), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); res.IsSuccess()) { std::cout << "Database " << Database << " on " << Endpoint << " was initialized." << std::endl; return 0; } else { @@ -210,7 +210,13 @@ int TProxy::ImportDatabase() { const auto driver = NYdb::TDriver(config); auto client = NYdb::NTable::TTableClient(driver); - if (const auto res = client.BulkUpsert(Database + "/content", std::move(value)).ExtractValueSync(); !res.IsSuccess()) { + if (const auto res = client.BulkUpsert(Database + Folder + "/current", std::move(value)).ExtractValueSync(); !res.IsSuccess()) { + std::cout << res.GetIssues().ToString() << std::endl; + return 1; + } + + const auto& param = NYdb::TParamsBuilder().AddParam("$Prefix").String(ImportPrefix_).Build().Build(); + if (const auto res = Stuff->Client->ExecuteQuery("insert into `history` select * from `current` where startswith(`key`,$Prefix);", NYdb::NQuery::TTxControl::NoTx(), param).ExtractValueSync(); !res.IsSuccess()) { std::cout << res.GetIssues().ToString() << std::endl; return 1; } @@ -235,6 +241,7 @@ TProxy::TProxy(int argc, char** argv) opts.AddLongOption("database", "YDB etcd databse").Required().RequiredArgument("DATABASE").StoreResult(&Database); opts.AddLongOption("endpoint", "YDB endpoint to connect").Required().RequiredArgument("ENDPOINT").StoreResult(&Endpoint); + opts.AddLongOption("folder", "YDB etcd root folder").Optional().RequiredArgument("FOLDER").StoreResult(&Folder); opts.AddLongOption("token", "YDB token for connection").Optional().RequiredArgument("TOKEN").StoreResult(&Token); opts.AddLongOption("ydbca", "YDB CA for connection").Optional().RequiredArgument("CA").StoreResult(&CA); @@ -256,6 +263,12 @@ TProxy::TProxy(int argc, char** argv) LockAllMemory(LockCurrentMemory); } + if (!Folder.empty()) { + std::ostringstream prefix; + prefix << "pragma TablePathPrefix = '" << Database << Folder << "';" << std::endl; + Stuff->TablePrefix = prefix.str(); + } + THolder actorSystemSetup = BuildActorSystemSetup(); TIntrusivePtr loggerSettings = BuildLoggerSettings(); diff --git a/ydb/apps/etcd_proxy/proxy.h b/ydb/apps/etcd_proxy/proxy.h index a539ea3a135d..aeb84602ba51 100644 --- a/ydb/apps/etcd_proxy/proxy.h +++ b/ydb/apps/etcd_proxy/proxy.h @@ -45,7 +45,7 @@ class TProxy { std::unique_ptr GRpcServer; bool Initialize_ = false; - std::string Database, Endpoint, Token, CA; + std::string Database, Endpoint, Token, CA, Folder; ui16 ListeningPort = 2379U; std::string Root, Cert, Key; std::string ImportFrom_, ImportPrefix_; diff --git a/ydb/apps/etcd_proxy/readme.txt b/ydb/apps/etcd_proxy/readme.txt index e4745faceace..6ba25734de2a 100644 --- a/ydb/apps/etcd_proxy/readme.txt +++ b/ydb/apps/etcd_proxy/readme.txt @@ -9,7 +9,7 @@ To remove the restriction two tasks must be done: And other todo's: - Add merics. - Add logging. -- Implement retries on "Transaction lock invslideted" error. +- Add retry policies. - Implement compaction with control of a requested revision. - Implement the watches for ranges. (Now the watches work only with a single key or a prefix.) - Add unit tests for watches. diff --git a/ydb/apps/etcd_proxy/service/create.sql b/ydb/apps/etcd_proxy/service/create.sql index 284d782fe957..dba80ea67c6f 100644 --- a/ydb/apps/etcd_proxy/service/create.sql +++ b/ydb/apps/etcd_proxy/service/create.sql @@ -1,4 +1,16 @@ -CREATE TABLE content +CREATE TABLE current +( + `key` Bytes NOT NULL, + `created` Int64 NOT NULL, + `modified` Int64 NOT NULL, + `version` Int64 NOT NULL, + `value` Bytes NOT NULL, + `lease` Int64 NOT NULL, + PRIMARY KEY (`key`) +) +WITH (AUTO_PARTITIONING_BY_LOAD = ENABLED, AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 23, AUTO_PARTITIONING_PARTITION_SIZE_MB = 11); + +CREATE TABLE history ( `key` Bytes NOT NULL, `created` Int64 NOT NULL, @@ -7,7 +19,8 @@ CREATE TABLE content `value` Bytes NOT NULL, `lease` Int64 NOT NULL, PRIMARY KEY (`key`, `modified`) -); +) +WITH (AUTO_PARTITIONING_BY_LOAD = ENABLED, AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 23, AUTO_PARTITIONING_PARTITION_SIZE_MB = 101); CREATE TABLE leases ( @@ -16,6 +29,7 @@ CREATE TABLE leases `created` Datetime NOT NULL, `updated` Datetime NOT NULL, PRIMARY KEY (`id`) -); +) +WITH (AUTO_PARTITIONING_BY_LOAD = ENABLED, AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 23, AUTO_PARTITIONING_PARTITION_SIZE_MB = 11); -ALTER TABLE content ADD CHANGEFEED changes WITH (format="JSON", mode="UPDATES"); +ALTER TABLE history ADD CHANGEFEED changes WITH (format="JSON", mode="UPDATES"); diff --git a/ydb/apps/etcd_proxy/service/etcd_base_init.cpp b/ydb/apps/etcd_proxy/service/etcd_base_init.cpp index f60939247cb2..d591cc87d548 100644 --- a/ydb/apps/etcd_proxy/service/etcd_base_init.cpp +++ b/ydb/apps/etcd_proxy/service/etcd_base_init.cpp @@ -4,12 +4,12 @@ namespace NEtcd { -std::string GetCreateTablesSQL() { - return NResource::Find("create.sql"sv); +std::string GetCreateTablesSQL(const std::string& prefix) { + return prefix + NResource::Find("create.sql"sv); } -std::string GetLastRevisionSQL() { - return "select nvl(max(`modified`), 1L) from `content`; select nvl(max(`id`), 1L) from `leases`;"; +std::string GetLastRevisionSQL(const std::string& prefix) { + return prefix + "select nvl(max(`modified`), 1L) from `history`; select nvl(max(`id`), 1L) from `leases`;"; } } diff --git a/ydb/apps/etcd_proxy/service/etcd_base_init.h b/ydb/apps/etcd_proxy/service/etcd_base_init.h index a43c300bd706..6e82372eee30 100644 --- a/ydb/apps/etcd_proxy/service/etcd_base_init.h +++ b/ydb/apps/etcd_proxy/service/etcd_base_init.h @@ -4,9 +4,9 @@ namespace NEtcd { -std::string GetCreateTablesSQL(); +std::string GetCreateTablesSQL(const std::string& prefix); -std::string GetLastRevisionSQL(); +std::string GetLastRevisionSQL(const std::string& prefix); } diff --git a/ydb/apps/etcd_proxy/service/etcd_grpc.h b/ydb/apps/etcd_proxy/service/etcd_grpc.h index 7170f634d2c3..b18d6b670ca0 100644 --- a/ydb/apps/etcd_proxy/service/etcd_grpc.h +++ b/ydb/apps/etcd_proxy/service/etcd_grpc.h @@ -17,7 +17,10 @@ class TEtcdServiceBase public: TEtcdServiceBase(NActors::TActorSystem* actorSystem, TIntrusivePtr counters, NActors::TActorId watchtower, TSharedStuff::TPtr stuff) : ActorSystem(actorSystem), Counters(std::move(counters)), Watchtower(std::move(watchtower)), Stuff(std::move(stuff)) - {} + { + if (!Stuff->ActorSystem) + Stuff->ActorSystem = ActorSystem; + } void InitService(grpc::ServerCompletionQueue* cq, NYdbGrpc::TLoggerPtr logger) { CQ = cq; diff --git a/ydb/apps/etcd_proxy/service/etcd_impl.cpp b/ydb/apps/etcd_proxy/service/etcd_impl.cpp index 59adbc029c67..a72f2200504b 100644 --- a/ydb/apps/etcd_proxy/service/etcd_impl.cpp +++ b/ydb/apps/etcd_proxy/service/etcd_impl.cpp @@ -12,6 +12,8 @@ namespace NEtcd { +using namespace NYdb::NQuery; + namespace { std::string GetNameWithIndex(const std::string_view& name, const size_t* counter) { @@ -33,10 +35,13 @@ struct TOperation { }; void MakeSlice(const std::string_view& where, std::ostream& sql, NYdb::TParamsBuilder& params, size_t* paramsCounter = nullptr, const i64 revision = 0LL) { - sql << "select * from (select max_by(TableRow(), `modified`) from `content`" << where; - if (revision) + if (revision) { + sql << "select * from (select max_by(TableRow(), `modified`) from `history`" << where; sql << " and " << AddParam("Rev", params, revision, paramsCounter) << " >= `modified`"; - sql << " group by `key`) flatten columns where 0L < `version`"; + sql << " group by `key`) flatten columns where 0L < `version`"; + } else { + sql << "select * from `current`" << where; + } } void MakeSlice(const std::string_view& key, const std::string_view& rangeEnd, std::ostream& sql, NYdb::TParamsBuilder& params, size_t* paramsCounter, const i64 revision = 0LL) { @@ -250,7 +255,7 @@ struct TPut : public TOperation { const auto& oldResultSetName = GetNameWithIndex("Old", resultsCounter); const auto& newResultSetName = GetNameWithIndex("New", resultsCounter); - sql << oldResultSetName << " = select * from (select * from `content`" << keyFilter << " order by `modified` desc limit 1UL) where 0L < `version`;" << std::endl; + sql << oldResultSetName << " = select * from `current` " << keyFilter << ';' << std::endl; sql << newResultSetName << " = select" << std::endl; sql << '\t' << keyParamName << " as `key`," << std::endl; sql << '\t' << "if(`version` > 0L, `created`, $Revision) as `created`," << std::endl; @@ -272,7 +277,8 @@ struct TPut : public TOperation { sql << " where " << txnFilter << ')'; sql << ';' << std::endl; - sql << "insert into `content` select * from " << newResultSetName << ';' << std::endl; + sql << (update ? "update `current` on" : "upsert into `current`") << " select * from " << newResultSetName << ';' << std::endl; + sql << "insert into `history` select * from " << newResultSetName << ';' << std::endl; if (GetPrevious || NotifyWatchtower || update) { if (resultsCounter) @@ -374,7 +380,7 @@ struct TDeleteRange : public TOperation { sql << " where " << txnFilter; sql << ';' << std::endl; - sql << "insert into `content`" << std::endl; + sql << "insert into `history`" << std::endl; sql << "select `key`, `created`, $Revision as `modified`, 0L as `version`, `value`, `lease` from " << oldResultSetName << ';' << std::endl; sql << "select count(*) from " << oldResultSetName << ';' << std::endl; @@ -383,6 +389,10 @@ struct TDeleteRange : public TOperation { ++(*resultsCounter); sql << "select `key`, `value`, `created`, `modified`, `version`, `lease` from " << oldResultSetName << ';' << std::endl; } + sql << "delete from `current`" << keyFilter; + if (!txnFilter.empty()) + sql << " and " << txnFilter; + sql << ';' << std::endl; } void MakeQueryWithParams(std::ostream& sql, NYdb::TParamsBuilder& params, size_t* paramsCounter = nullptr, size_t* resultsCounter = nullptr, const std::string_view& txnFilter = {}) { @@ -816,16 +826,21 @@ class TEtcdRequestGrpc std::ostringstream sql; NYdb::TParamsBuilder params; sql << "-- " << GetRequestName() << " >>>>" << std::endl; + sql << Stuff->TablePrefix; this->MakeQueryWithParams(sql, params); sql << "-- " << GetRequestName() << " <<<<" << std::endl; // std::cout << std::endl << sql.view() << std::endl; - const auto my = this->SelfId(); - const auto ass = NActors::TlsActivationContext->ExecutorThread.ActorSystem; - Stuff->Client->ExecuteQuery(sql.str(), NYdb::NQuery::TTxControl::BeginTx().CommitTx(), params.Build()).Subscribe([my, ass](const auto& future) { - if (const auto res = future.GetValueSync(); res.IsSuccess()) - ass->Send(my, new NEtcd::TEvQueryResult(res.GetResultSets())); - else - ass->Send(my, new NEtcd::TEvQueryError(res.GetIssues())); + + TQueryClient::TQueryResultFunc callback = [query = sql.str(), args = params.Build()](TQueryClient::TSession session) -> TAsyncExecuteQueryResult { + return session.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), args); + }; + Stuff->Client->RetryQuery(std::move(callback)).Subscribe([my = this->SelfId(), stuff = TSharedStuff::TWeakPtr(Stuff)](const auto& future) { + if (const auto lock = stuff.lock()) { + if (const auto res = future.GetValueSync(); res.IsSuccess()) + lock->ActorSystem->Send(my, new NEtcd::TEvQueryResult(res.GetResultSets())); + else + lock->ActorSystem->Send(my, new NEtcd::TEvQueryError(res.GetIssues())); + } }); } @@ -1067,12 +1082,12 @@ class TCompactRequest } void MakeQueryWithParams(std::ostream& sql, NYdb::TParamsBuilder& params) final { - sql << "$Trash = select c.key as key, c.modified as modified from `content` as c inner join (" << std::endl; - sql << "select max_by((`key`, `modified`), `modified`) as pair from `content`" << std::endl; + sql << "$Trash = select c.key as key, c.modified as modified from `history` as c inner join (" << std::endl; + sql << "select max_by((`key`, `modified`), `modified`) as pair from `history`" << std::endl; sql << "where `modified` < " << AddParam("Revision", params, KeyRevision) << " and 0L = `version` group by `key`" << std::endl; sql << ") as keys on keys.pair.0 = c.key where c.modified <= keys.pair.1;" << std::endl; sql << "select count(*) from $Trash;" << std::endl; - sql << "delete from `content` on select * from $Trash;" << std::endl; + sql << "delete from `history` on select * from $Trash;" << std::endl; } void ReplyWith(const NYdb::TResultSets& results, const TActorContext& ctx) final { @@ -1156,16 +1171,15 @@ class TLeaseRevokeRequest sql << "select count(*) > 0UL from `leases` where " << leaseParamName << " = `id`;" << std::endl; - sql << "$Victims = "; - MakeSimpleSlice(sql, params); - sql << " and " << leaseParamName << " = `lease`;" << std::endl; - - sql << "insert into `content`" << std::endl; - sql << "select `key`, `created`, " << revisionParamName << " as `modified`, 0L as `version`, `value`, `lease` from $Victims;" << std::endl; + sql << "$Victims = select `key`, `value`, `created`, `modified`, `version`, `lease` from `current` where " << leaseParamName << " = `lease`;" << std::endl; if constexpr (NotifyWatchtower) { sql << "select `key`, `value`, `created`, `modified`, `version`, `lease` from $Victims;" << std::endl; } + + sql << "insert into `history`" << std::endl; + sql << "select `key`, `created`, " << revisionParamName << " as `modified`, 0L as `version`, `value`, `lease` from $Victims;" << std::endl; + sql << "delete from `current` on select `key` from $Victims;" << std::endl; sql << "delete from `leases` where " << leaseParamName << " = `id`;" << std::endl; } @@ -1230,9 +1244,7 @@ class TLeaseTimeToLiveRequest sql << "select `ttl`, `ttl` - unwrap(cast(CurrentUtcDatetime(`id`) - `updated` as Int64) / 1000000L) as `granted` from `leases` where " << leaseParamName << " = `id`;" << std::endl; if (Keys) { - sql << "select `key` from ("; - MakeSimpleSlice(sql, params); - sql << " and " << leaseParamName << " = `lease`);" << std::endl; + sql << "select `key` from `current` where " << leaseParamName << " = `lease`;" << std::endl; } } @@ -1336,10 +1348,6 @@ std::string MakeSimplePredicate(const std::string_view& key, const std::string_v return keyParamName; } -void MakeSimpleSlice(std::ostream& sql, NYdb::TParamsBuilder& params) { - MakeSlice(std::string_view(), sql, params); -} - NActors::IActor* MakeRange(std::unique_ptr p, TSharedStuff::TPtr stuff) { return new TRangeRequest(std::move(p), std::move(stuff)); } diff --git a/ydb/apps/etcd_proxy/service/etcd_impl.h b/ydb/apps/etcd_proxy/service/etcd_impl.h index 4449d4b4007f..36e1407c4ee9 100644 --- a/ydb/apps/etcd_proxy/service/etcd_impl.h +++ b/ydb/apps/etcd_proxy/service/etcd_impl.h @@ -20,7 +20,5 @@ namespace NEtcd { template std::string AddParam(const std::string_view& name, NYdb::TParamsBuilder& params, const TValueType& value, size_t* counter = nullptr); - void MakeSimpleSlice(std::ostream& sql, NYdb::TParamsBuilder& params); - std::string MakeSimplePredicate(const std::string_view& key, const std::string_view& rangeEnd, std::ostream& sql, NYdb::TParamsBuilder& params, size_t* paramsCounter = nullptr); } diff --git a/ydb/apps/etcd_proxy/service/etcd_shared.h b/ydb/apps/etcd_proxy/service/etcd_shared.h index b42af880964f..ba77afb23af3 100644 --- a/ydb/apps/etcd_proxy/service/etcd_shared.h +++ b/ydb/apps/etcd_proxy/service/etcd_shared.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include @@ -13,10 +13,13 @@ constexpr auto Endless = "\0"sv; struct TSharedStuff { using TPtr = std::shared_ptr; + using TWeakPtr = std::weak_ptr; std::unique_ptr Client; std::atomic Revision = 0LL, Lease = 0LL; + NActors::TActorSystem* ActorSystem = nullptr; NActors::TActorId Watchtower; + std::string TablePrefix; }; std::string IncrementKey(std::string key); diff --git a/ydb/apps/etcd_proxy/service/etcd_watch.cpp b/ydb/apps/etcd_proxy/service/etcd_watch.cpp index 6970fd24011a..9f5d35adf179 100644 --- a/ydb/apps/etcd_proxy/service/etcd_watch.cpp +++ b/ydb/apps/etcd_proxy/service/etcd_watch.cpp @@ -9,6 +9,7 @@ namespace NEtcd { using namespace NActors; +using namespace NYdb::NQuery; namespace { @@ -65,16 +66,20 @@ class TKeysKeeper : public TActorBootstrapped { const auto& leasePraramName = AddParam("Lease", params, ev->Get()->Record.id()); std::ostringstream sql; + sql << Stuff->TablePrefix; sql << "update `leases` set `updated` = CurrentUtcDatetime(`id`) where " << leasePraramName << " = `id`;" << std::endl; sql << "select `id`, `ttl` - unwrap(cast(CurrentUtcDatetime(`id`) - `updated` as Int64) / 1000000L) as `granted` from `leases` where " << leasePraramName << " = `id`;" << std::endl; - const auto my = this->SelfId(); - const auto ass = NActors::TlsActivationContext->ExecutorThread.ActorSystem; - Stuff->Client->ExecuteQuery(sql.str(), NYdb::NQuery::TTxControl::BeginTx().CommitTx(), params.Build()).Subscribe([my, ass](const auto& future) { - if (const auto res = future.GetValueSync(); res.IsSuccess()) - ass->Send(my, new TEvQueryResult(res.GetResultSets())); - else - ass->Send(my, new TEvQueryError(res.GetIssues())); + TQueryClient::TQueryResultFunc callback = [query = sql.str(), args = params.Build()](TQueryClient::TSession session) -> TAsyncExecuteQueryResult { + return session.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), args); + }; + Stuff->Client->RetryQuery(std::move(callback)).Subscribe([my = this->SelfId(), stuff = TSharedStuff::TWeakPtr(Stuff)](const auto& future) { + if (const auto lock = stuff.lock()) { + if (const auto res = future.GetValueSync(); res.IsSuccess()) + lock->ActorSystem->Send(my, new NEtcd::TEvQueryResult(res.GetResultSets())); + else + lock->ActorSystem->Send(my, new NEtcd::TEvQueryError(res.GetIssues())); + } }); if (!Ctx->Read()) @@ -165,19 +170,23 @@ class TWatch : public TActorBootstrapped { MakeSimplePredicate(Key, RangeEnd, where, params); std::ostringstream sql; + sql << Stuff->TablePrefix; if (WithPrevious) { - sql << "select * from (select max_by(TableRow(), `modified`) from `content` where " << revName << " > `modified` and " << where.view() << " group by `key`) flatten columns union all" << std::endl; + sql << "select * from (select max_by(TableRow(), `modified`) from `history` where " << revName << " > `modified` and " << where.view() << " group by `key`) flatten columns union all" << std::endl; } - sql << "select * from `content` where " << revName << " <= `modified` and " << where.view() << " order by `modified` asc;" << std::endl; + sql << "select * from `history` where " << revName << " <= `modified` and " << where.view() << " order by `modified` asc;" << std::endl; // std::cout << std::endl << sql.view() << std::endl; - const auto my = this->SelfId(); - const auto ass = NActors::TlsActivationContext->ExecutorThread.ActorSystem; - Stuff->Client->ExecuteQuery(sql.str(), NYdb::NQuery::TTxControl::BeginTx().CommitTx(), params.Build()).Subscribe([my, ass](const auto& future) { - if (const auto res = future.GetValueSync(); res.IsSuccess()) - ass->Send(my, new TEvQueryResult(res.GetResultSets())); - else - ass->Send(my, new TEvQueryError(res.GetIssues())); + TQueryClient::TQueryResultFunc callback = [query = sql.str(), args = params.Build()](TQueryClient::TSession session) -> TAsyncExecuteQueryResult { + return session.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), args); + }; + Stuff->Client->RetryQuery(std::move(callback)).Subscribe([my = this->SelfId(), stuff = TSharedStuff::TWeakPtr(Stuff)](const auto& future) { + if (const auto lock = stuff.lock()) { + if (const auto res = future.GetValueSync(); res.IsSuccess()) + lock->ActorSystem->Send(my, new NEtcd::TEvQueryResult(res.GetResultSets())); + else + lock->ActorSystem->Send(my, new NEtcd::TEvQueryError(res.GetIssues())); + } }); } @@ -586,16 +595,16 @@ class TWatchtower : public TActorBootstrapped { Revision = Stuff->Revision.fetch_add(1LL) + 1LL; std::ostringstream sql; + sql << Stuff->TablePrefix; NYdb::TParamsBuilder params; const auto& revName = AddParam("Revision", params, Revision); sql << "$Leases = select 0L as `lease` union all select `id` as `lease` from `leases` where unwrap(interval('PT1S') * `ttl` + `updated`) > CurrentUtcDatetime(`id`);" << std::endl; - sql << "$Victims = select `key`, `value`, `created`, `modified`, `version`, `lease` from ("; - MakeSimpleSlice(sql, params); - sql << ") as h left only join $Leases as l using(`lease`);" << std::endl; + sql << "$Victims = select `key`, `value`, `created`, `modified`, `version`, `lease` from `current` as h left only join $Leases as l using(`lease`);" << std::endl; sql << "insert into `content`" << std::endl; sql << "select `key`, `created`, " << revName << " as `modified`, 0L as `version`, `value`, `lease` from $Victims;" << std::endl; + sql << "delete from `current` on select `key` from $Victims;" << std::endl; if constexpr (NotifyWatchtower) { sql << "select `key`, `value`, `created`, `modified`, `version`, `lease` from $Victims;" << std::endl; @@ -605,13 +614,13 @@ class TWatchtower : public TActorBootstrapped { sql << "delete from `leases` where `id` not in $Leases;" << std::endl; - const auto my = this->SelfId(); - const auto ass = NActors::TlsActivationContext->ExecutorThread.ActorSystem; - Stuff->Client->ExecuteQuery(sql.str(), NYdb::NQuery::TTxControl::BeginTx().CommitTx(), params.Build()).Subscribe([my, ass](const auto& future) { - if (const auto res = future.GetValueSync(); res.IsSuccess()) - ass->Send(my, new TEvQueryResult(res.GetResultSets())); - else - ass->Send(my, new TEvQueryError(res.GetIssues())); + Stuff->Client->ExecuteQuery(sql.str(), TTxControl::BeginTx().CommitTx(), params.Build()).Subscribe([my = this->SelfId(), stuff = TSharedStuff::TWeakPtr(Stuff)](const auto& future) { + if (const auto lock = stuff.lock()) { + if (const auto res = future.GetValueSync(); res.IsSuccess()) + lock->ActorSystem->Send(my, new NEtcd::TEvQueryResult(res.GetResultSets())); + else + lock->ActorSystem->Send(my, new NEtcd::TEvQueryError(res.GetIssues())); + } }); } diff --git a/ydb/apps/etcd_proxy/service/ut/etcd_service_ut.cpp b/ydb/apps/etcd_proxy/service/ut/etcd_service_ut.cpp index d9b8b11f7389..b0444837113f 100644 --- a/ydb/apps/etcd_proxy/service/ut/etcd_service_ut.cpp +++ b/ydb/apps/etcd_proxy/service/ut/etcd_service_ut.cpp @@ -105,7 +105,7 @@ void MakeTables(auto &channel) { const auto stub = Ydb::Query::V1::QueryService::NewStub(channel); Ydb::Query::ExecuteQueryRequest request; request.set_exec_mode(Ydb::Query::EXEC_MODE_EXECUTE); - request.mutable_query_content()->set_text(std::string("PRAGMA TablePathPrefix='/Root';\n") + NEtcd::GetCreateTablesSQL()); + request.mutable_query_content()->set_text(NEtcd::GetCreateTablesSQL(std::string("PRAGMA TablePathPrefix='/Root';\n"))); grpc::ClientContext executeCtx; Ydb::Query::ExecuteQueryResponsePart response; diff --git a/ydb/apps/ydb/CHANGELOG.md b/ydb/apps/ydb/CHANGELOG.md index d017326187a0..8fe9b9c2cddb 100644 --- a/ydb/apps/ydb/CHANGELOG.md +++ b/ydb/apps/ydb/CHANGELOG.md @@ -1,3 +1,4 @@ +* Added `--scale` option to `ydb workload tpch init` and `ydb workload tpcds init` commands. Sets the percentage of the benchmark's data size and workload to use, relative to full scale. * Added "--no-discovery" option. It allows to skip discovery and use user provided endpoint to connect to YDB cluster. * Added `--retries` to `ydb workload run` command. * Added `--partition-size` param to `ydb workload init`. @@ -5,6 +6,8 @@ * YDB CLI help message improvements. Different display for detailed help and brief help. * Support coordination nodes in `ydb scheme rmdir --recursive`. * Fixed return code of command `ydb workload * run --check-canonical` for the case when benchmark query results differ from canonical ones. +* Fixed scheme error in `ydb admin cluster dump` when specifying a domain database. +* Fixed unauthorized error in `ydb admin database restore` when multiple database admins are in dump. ## 2.20.0 ## diff --git a/ydb/apps/ydbd/ya.make b/ydb/apps/ydbd/ya.make index 51323ee07c3e..46ad9ac608cf 100644 --- a/ydb/apps/ydbd/ya.make +++ b/ydb/apps/ydbd/ya.make @@ -69,7 +69,7 @@ PEERDIR( yql/essentials/udfs/common/url_base yql/essentials/udfs/common/yson2 yql/essentials/udfs/logs/dsv -# ydb/library/breakpad + ydb/library/breakpad ydb/public/sdk/cpp/client/ydb_persqueue_public/codecs ) diff --git a/ydb/ci/rightlib.txt b/ydb/ci/rightlib.txt index 9bc7611bed3a..f3d205180f54 100644 --- a/ydb/ci/rightlib.txt +++ b/ydb/ci/rightlib.txt @@ -1 +1 @@ -28a80e63c3c727d8309a041bde8da045b41f4fda +605a8a3075d2116bf0c742d7ae889ba14b801a8e diff --git a/ydb/core/base/appdata.cpp b/ydb/core/base/appdata.cpp index 38a8f5bb8aaa..3836995a50a3 100644 --- a/ydb/core/base/appdata.cpp +++ b/ydb/core/base/appdata.cpp @@ -15,20 +15,21 @@ #include #include #include -#include #include +#include #include #include #include +#include +#include #include #include +#include #include #include -#include -#include -#include #include -#include +#include +#include #include #include @@ -71,6 +72,7 @@ struct TAppData::TImpl { NKikimrProto::TDataIntegrityTrailsConfig DataIntegrityTrailsConfig; NKikimrConfig::TDataErasureConfig DataErasureConfig; NKikimrConfig::THealthCheckConfig HealthCheckConfig; + NKikimrConfig::TWorkloadManagerConfig WorkloadManagerConfig; }; TAppData::TAppData( @@ -129,6 +131,7 @@ TAppData::TAppData( , DataIntegrityTrailsConfig(Impl->DataIntegrityTrailsConfig) , DataErasureConfig(Impl->DataErasureConfig) , HealthCheckConfig(Impl->HealthCheckConfig) + , WorkloadManagerConfig(Impl->WorkloadManagerConfig) , KikimrShouldContinue(kikimrShouldContinue) , TracingConfigurator(MakeIntrusive(TimeProvider, RandomProvider)) {} diff --git a/ydb/core/base/appdata_fwd.h b/ydb/core/base/appdata_fwd.h index 11b425c9ff27..2e50e26bee62 100644 --- a/ydb/core/base/appdata_fwd.h +++ b/ydb/core/base/appdata_fwd.h @@ -74,6 +74,7 @@ namespace NKikimrConfig { class TMemoryControllerConfig; class TFeatureFlags; class THealthCheckConfig; + class TWorkloadManagerConfig; } namespace NKikimrReplication { @@ -249,6 +250,7 @@ struct TAppData { NKikimrProto::TDataIntegrityTrailsConfig& DataIntegrityTrailsConfig; NKikimrConfig::TDataErasureConfig& DataErasureConfig; NKikimrConfig::THealthCheckConfig& HealthCheckConfig; + NKikimrConfig::TWorkloadManagerConfig& WorkloadManagerConfig; bool EnforceUserTokenRequirement = false; bool EnforceUserTokenCheckRequirement = false; // check token if it was specified bool AllowHugeKeyValueDeletes = true; // delete when all clients limit deletes per request diff --git a/ydb/core/blob_depot/agent/query.cpp b/ydb/core/blob_depot/agent/query.cpp index 7d3567177e81..2db57bd6e56e 100644 --- a/ydb/core/blob_depot/agent/query.cpp +++ b/ydb/core/blob_depot/agent/query.cpp @@ -29,6 +29,10 @@ namespace NKikimr::NBlobDepot { doForward = ev->Get()->Decommission; Y_ABORT_UNLESS(!doForward || !ev->Get()->MustRestoreFirst); break; + + case TEvBlobStorage::EvCollectGarbage: + doForward = ev->Get()->Decommission; + break; } if (doForward) { diff --git a/ydb/core/blob_depot/assimilator.cpp b/ydb/core/blob_depot/assimilator.cpp index 1e7dd63bb724..c1fe44841f21 100644 --- a/ydb/core/blob_depot/assimilator.cpp +++ b/ydb/core/blob_depot/assimilator.cpp @@ -70,11 +70,51 @@ namespace NKikimr::NBlobDepot { } }; + class TBlobDepot::TData::TTxHardCollectAssimilatedBlobs : public NTabletFlatExecutor::TTransactionBase { + const ui64 TabletId; + const ui8 Channel; + const TGenStep Barrier; + const TActorId ParentId; + + ui32 PerGenerationCounter = 0; + + public: + TTxType GetTxType() const override { return NKikimrBlobDepot::TXTYPE_HARD_COLLECT_ASSIMILATED_BLOBS; } + + TTxHardCollectAssimilatedBlobs(TBlobDepot *self, ui64 tabletId, ui8 channel, TGenStep barrier, TActorId parentId) + : TTransactionBase(self) + , TabletId(tabletId) + , Channel(channel) + , Barrier(barrier) + , ParentId(parentId) + {} + + bool Execute(TTransactionContext& txc, const TActorContext&) override { + NIceDb::TNiceDb db(txc.DB); + using T = Schema::Config; + PerGenerationCounter = Self->PerGenerationCounter++; + db.Table().Key(T::Key::Value).Update(Self->PerGenerationCounter); + return true; + } + + void Complete(const TActorContext&) override { + const bool del = Barrier.Generation() == Max() && Barrier.Step() == Max(); + auto ev = std::make_unique( + TabletId, Max(), del ? Max() : PerGenerationCounter, Channel, true, Barrier.Generation(), + Barrier.Step(), nullptr, nullptr, TInstant::Max(), false, /*hard=*/ true + ); + ev->Decommission = true; + TActivationContext::Send(ParentId, std::move(ev), 0, PerGenerationCounter); + } + }; + void TAssimilator::Bootstrap() { if (Token.expired()) { return PassAway(); } + ExpectedPerGenerationCounter = Self->PerGenerationCounter; + const std::optional& state = Self->AssimilatorState; if (state) { TStringInput stream(*state); @@ -113,6 +153,8 @@ namespace NKikimr::NBlobDepot { hFunc(TEvBlobStorage::TEvAssimilateResult, Handle); hFunc(TEvBlobStorage::TEvGetResult, Handle); hFunc(TEvBlobStorage::TEvPutResult, Handle); + hFunc(TEvBlobStorage::TEvCollectGarbage, Handle); + hFunc(TEvBlobStorage::TEvCollectGarbageResult, Handle); hFunc(TEvTabletPipe::TEvClientConnected, Handle); hFunc(TEvTabletPipe::TEvClientDestroyed, Handle); hFunc(TEvBlobStorage::TEvControllerGroupDecommittedResponse, Handle); @@ -315,8 +357,12 @@ namespace NKikimr::NBlobDepot { }; Self->Data->ScanRange(range, nullptr, nullptr, [&](const TData::TKey& key, const TData::TValue& value) { + const TLogoBlobID& id = key.GetBlobId(); + const auto blobQueueKey = std::make_tuple(id.TabletID(), id.Channel()); + auto& queue = LeastBlobQueue[blobQueueKey]; if (value.GoingToAssimilate) { - Self->AsStats.BytesToCopy += key.GetBlobId().BlobSize(); + queue.emplace_back(TGenStep(id), id.Cookie(), id.BlobSize()); + Self->AsStats.BytesToCopy += id.BlobSize(); invalidate = true; } LastPlanScannedKey.emplace(key.GetBlobId()); @@ -338,6 +384,14 @@ namespace NKikimr::NBlobDepot { return; } + for (const auto& [key, value] : LeastBlobQueue) { + if (value.empty()) { + const auto& [tabletId, channel] = key; + Self->Data->ExecuteTxHardCollectAssimilatedBlobs(tabletId, channel, TGenStep(Max(), Max()), + SelfId()); + } + } + ActionInProgress = false; PlanningComplete = true; Action(); @@ -421,6 +475,7 @@ namespace NKikimr::NBlobDepot { LastScannedKey.reset(); LastPlanScannedKey.reset(); EntriesToProcess = PlanningComplete = ActionInProgress = false; + LeastBlobQueue.clear(); Action(); } break; @@ -471,6 +526,7 @@ namespace NKikimr::NBlobDepot { ++Self->AsStats.BlobsReadNoData; Self->AsStats.BytesToCopy -= resp.Id.BlobSize(); + get.BlobIds.push_back(resp.Id); get.AssimilatedBlobs.push_back({TData::TKey(resp.Id), TData::TAssimilatedBlobInfo::TDrop{}}); break; @@ -493,6 +549,45 @@ namespace NKikimr::NBlobDepot { void TAssimilator::HandleTxComplete(TAutoPtr ev) { const auto it = Gets.find(ev->Cookie); Y_ABORT_UNLESS(it != Gets.end()); + TGetBatch& get = it->second; + + for (const TLogoBlobID& id : get.BlobIds) { + const auto qIt = LeastBlobQueue.find(std::make_tuple(id.TabletID(), id.Channel())); + Y_ABORT_UNLESS(qIt != LeastBlobQueue.end()); + auto& items = qIt->second; + Y_ABORT_UNLESS(!items.empty()); + + const auto value = std::make_tuple(TGenStep(id), id.Cookie(), id.BlobSize()); + auto it = items.front() == value ? items.begin() : std::ranges::lower_bound(items, value); + Y_ABORT_UNLESS(it != items.end() && *it == value); + + if (it == items.begin()) { + const TGenStep beginGenStep = std::get<0>(items.front()); + + // remove front item and trim any pending items + items.pop_front(); + while (!items.empty() && !std::get<2>(items.front())) { + items.pop_front(); + } + + std::optional barrier; + if (items.empty()) { + // we have processed all the data from this tablet/channel pair + barrier.emplace(Max(), Max()); + } else if (std::get<0>(items.front()) != beginGenStep) { + // gen/step has been changed + barrier.emplace(std::get<0>(items.front()).Previous()); + } + if (barrier) { + // issue hard barrier cmd + Self->Data->ExecuteTxHardCollectAssimilatedBlobs(id.TabletID(), id.Channel(), *barrier, SelfId()); + } + } else { + auto& [genStep, cookie, blobSize] = *it; + blobSize = 0; // mark this item as already processed + } + } + Gets.erase(it); ScanDataForCopying(); } @@ -526,6 +621,7 @@ namespace NKikimr::NBlobDepot { Y_ABORT_UNLESS(jt != Gets.end()); TGetBatch& get = jt->second; if (msg.Status == NKikimrProto::OK) { // mark blob assimilated only in case of success + get.BlobIds.push_back(key.GetBlobId()); get.AssimilatedBlobs.push_back({std::move(key), TData::TAssimilatedBlobInfo::TUpdate{ TBlobSeqId::FromLogoBlobId(msg.Id)}}); } @@ -535,6 +631,42 @@ namespace NKikimr::NBlobDepot { } } + void TAssimilator::Handle(TEvBlobStorage::TEvCollectGarbage::TPtr ev) { + CollectGarbageQ.emplace(ev->Cookie, ev->Release().Release()); + ProcessCollectGarbageQ(); + } + + void TAssimilator::Handle(TEvBlobStorage::TEvCollectGarbageResult::TPtr ev) { + auto& msg = *ev->Get(); + STLOG(PRI_DEBUG, BLOB_DEPOT, BDT93, "got TEvCollectGarbageResult", (Id, Self->GetLogId()), (Msg, msg)); + ++(msg.Status == NKikimrProto::OK ? Self->AsStats.CollectGarbageOK : Self->AsStats.CollectGarbageError); + + Y_ABORT_UNLESS(CollectGarbageInFlight); + --CollectGarbageInFlight; + ProcessCollectGarbageQ(); + } + + void TAssimilator::ProcessCollectGarbageQ() { + const ui32 maxInFlight = CollectGarbageQ.size() >= 1000 ? 4 : + CollectGarbageQ.size() >= 100 ? 3 : + CollectGarbageQ.size() >= 10 ? 2 : 1; + while (!CollectGarbageQ.empty() && CollectGarbageInFlight < maxInFlight) { + auto& [counter, ev] = *CollectGarbageQ.begin(); + if (counter == ExpectedPerGenerationCounter) { + SendToBSProxy(SelfId(), Self->Config.GetVirtualGroupId(), ev.release()); + CollectGarbageQ.erase(CollectGarbageQ.begin()); + ++CollectGarbageInFlight; + ++ExpectedPerGenerationCounter; + } else { + break; + } + } + + Self->AsStats.CollectGarbageInFlight = CollectGarbageInFlight; + Self->AsStats.CollectGarbageQueue = CollectGarbageQ.size(); + Self->JsonHandler.Invalidate(); + } + void TAssimilator::OnCopyDone() { STLOG(PRI_DEBUG, BLOB_DEPOT, BDT38, "data copying is done", (Id, Self->GetLogId())); Y_ABORT_UNLESS(Gets.empty()); @@ -714,6 +846,10 @@ namespace NKikimr::NBlobDepot { json["d.blobs_put_ok"] = ToString(BlobsPutOk); json["d.blobs_put_error"] = ToString(BlobsPutError); json["d.copy_iteration"] = ToString(CopyIteration); + json["d.collect_garbage_in_flight"] = ToString(CollectGarbageInFlight); + json["d.collect_garbage_queue"] = ToString(CollectGarbageQueue); + json["d.collect_garbage_ok"] = ToString(CollectGarbageOK); + json["d.collect_garbage_error"] = ToString(CollectGarbageError); } void TBlobDepot::TData::ExecuteTxCommitAssimilatedBlob(std::vector&& blobs, ui32 notifyEventType, @@ -721,6 +857,10 @@ namespace NKikimr::NBlobDepot { Self->Execute(std::make_unique(Self, std::move(blobs), notifyEventType, parentId, cookie)); } + void TBlobDepot::TData::ExecuteTxHardCollectAssimilatedBlobs(ui64 tabletId, ui8 channel, TGenStep barrier, TActorId parentId) { + Self->Execute(std::make_unique(Self, tabletId, channel, barrier, parentId)); + } + void TBlobDepot::StartGroupAssimilator() { if (Config.GetIsDecommittingGroup() && DecommitState != EDecommitState::Done) { Y_ABORT_UNLESS(!GroupAssimilatorId); diff --git a/ydb/core/blob_depot/assimilator.h b/ydb/core/blob_depot/assimilator.h index 90b1e6899bdc..f76075da6c30 100644 --- a/ydb/core/blob_depot/assimilator.h +++ b/ydb/core/blob_depot/assimilator.h @@ -32,6 +32,7 @@ namespace NKikimr::NBlobDepot { struct TGetBatch { ui32 PutsPending = 0; std::vector AssimilatedBlobs; + std::vector BlobIds; }; static constexpr ui32 MaxGetsUnprocessed = 5; ui64 NextGetId = 1; @@ -54,6 +55,11 @@ namespace NKikimr::NBlobDepot { std::deque> BytesCopiedQ; + ui32 ExpectedPerGenerationCounter = 0; + THashMap, std::deque>> LeastBlobQueue; + std::map> CollectGarbageQ; + ui32 CollectGarbageInFlight = 0; + public: static constexpr NKikimrServices::TActivity::EType ActorActivityType() { return NKikimrServices::TActivity::BLOB_DEPOT_ASSIMILATOR_ACTOR; @@ -81,6 +87,9 @@ namespace NKikimr::NBlobDepot { void Handle(TEvBlobStorage::TEvGetResult::TPtr ev); void HandleTxComplete(TAutoPtr ev); void Handle(TEvBlobStorage::TEvPutResult::TPtr ev); + void Handle(TEvBlobStorage::TEvCollectGarbage::TPtr ev); + void Handle(TEvBlobStorage::TEvCollectGarbageResult::TPtr ev); + void ProcessCollectGarbageQ(); void OnCopyDone(); void CreatePipe(); void Handle(TEvTabletPipe::TEvClientConnected::TPtr ev); diff --git a/ydb/core/blob_depot/blob_depot_tablet.h b/ydb/core/blob_depot/blob_depot_tablet.h index a51b7f0708ca..4f3fd13489df 100644 --- a/ydb/core/blob_depot/blob_depot_tablet.h +++ b/ydb/core/blob_depot/blob_depot_tablet.h @@ -335,6 +335,10 @@ namespace NKikimr::NBlobDepot { ui64 BlobsPutOk = 0; ui64 BlobsPutError = 0; ui32 CopyIteration = 0; + ui32 CollectGarbageInFlight = 0; + ui32 CollectGarbageQueue = 0; + ui32 CollectGarbageOK = 0; + ui32 CollectGarbageError = 0; void ToJson(NJson::TJsonValue& json, bool pretty) const; } AsStats; @@ -344,6 +348,8 @@ namespace NKikimr::NBlobDepot { void StartGroupAssimilator(); void OnUpdateDecommitState(); + ui32 PerGenerationCounter = 1; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Group metrics exchange diff --git a/ydb/core/blob_depot/data.h b/ydb/core/blob_depot/data.h index e1e2649d935a..8fbe684e54f1 100644 --- a/ydb/core/blob_depot/data.h +++ b/ydb/core/blob_depot/data.h @@ -761,6 +761,9 @@ namespace NKikimr::NBlobDepot { void ExecuteTxCommitAssimilatedBlob(std::vector&& blobs, ui32 notifyEventType, TActorId parentId, ui64 cookie); + class TTxHardCollectAssimilatedBlobs; + void ExecuteTxHardCollectAssimilatedBlobs(ui64 tabletId, ui8 channel, TGenStep barrier, TActorId parentId); + class TTxResolve; void ExecuteTxResolve(TEvBlobDepot::TEvResolve::TPtr ev, THashSet&& resolutionErrors = {}); diff --git a/ydb/core/blob_depot/mon_main.cpp b/ydb/core/blob_depot/mon_main.cpp index 7c9257d1240e..c5543bc21c6c 100644 --- a/ydb/core/blob_depot/mon_main.cpp +++ b/ydb/core/blob_depot/mon_main.cpp @@ -538,6 +538,10 @@ document.addEventListener("DOMContentLoaded", ready); KEYVALUE_UP("Blobs read with error", "d.blobs_read_error", AsStats.BlobsReadError); KEYVALUE_UP("Blobs put with OK", "d.blobs_put_ok", AsStats.BlobsPutOk); KEYVALUE_UP("Blobs put with error", "d.blobs_put_error", AsStats.BlobsPutError); + KEYVALUE_UP("CollectGarbage in flight", "d.collect_garbage_in_flight", AsStats.CollectGarbageInFlight); + KEYVALUE_UP("CollectGarbage queue", "d.collect_garbage_queue", AsStats.CollectGarbageQueue); + KEYVALUE_UP("CollectGarbage OK", "d.collect_garbage_ok", AsStats.CollectGarbageOK); + KEYVALUE_UP("CollectGarbage error", "d.collect_garbage_error", AsStats.CollectGarbageError); }) } } diff --git a/ydb/core/blob_depot/op_load.cpp b/ydb/core/blob_depot/op_load.cpp index db5fa18a31e8..1d88e7d7b49d 100644 --- a/ydb/core/blob_depot/op_load.cpp +++ b/ydb/core/blob_depot/op_load.cpp @@ -38,6 +38,9 @@ namespace NKikimr::NBlobDepot { if (table.HaveValue()) { Self->AssimilatorState.emplace(table.GetValue()); } + if (table.HaveValue()) { + Self->PerGenerationCounter = table.GetValue(); + } } } diff --git a/ydb/core/blob_depot/schema.h b/ydb/core/blob_depot/schema.h index 2e655bc1d73b..11825b1618b7 100644 --- a/ydb/core/blob_depot/schema.h +++ b/ydb/core/blob_depot/schema.h @@ -20,13 +20,15 @@ namespace NKikimr::NBlobDepot { struct ConfigProtobuf : Column<2, NScheme::NTypeIds::String> {}; struct DecommitState : Column<3, NScheme::NTypeIds::Uint32> { using Type = EDecommitState; static constexpr Type Default = EDecommitState::Default; }; struct AssimilatorState : Column<4, NScheme::NTypeIds::String> {}; + struct PerGenerationCounter : Column<5, NScheme::NTypeIds::Uint32> {}; using TKey = TableKey; using TColumns = TableColumns< Key, ConfigProtobuf, DecommitState, - AssimilatorState + AssimilatorState, + PerGenerationCounter >; }; diff --git a/ydb/core/blobstorage/base/blobstorage_console_events.h b/ydb/core/blobstorage/base/blobstorage_console_events.h index eb6798f35d68..bfda92029842 100644 --- a/ydb/core/blobstorage/base/blobstorage_console_events.h +++ b/ydb/core/blobstorage/base/blobstorage_console_events.h @@ -79,7 +79,7 @@ namespace NKikimr { TEvControllerReplaceConfigRequest(std::optional clusterYaml, std::optional storageYaml, std::optional switchDedicatedStorageSection, bool dedicatedConfigMode, bool allowUnknownFields, - bool bypassMetadataChecks, bool enableConfigV2, bool disableConfigV2) { + bool bypassMetadataChecks, bool enableConfigV2, bool disableConfigV2, TString peerName, TString userToken) { if (clusterYaml) { Record.SetClusterYaml(*clusterYaml); } @@ -97,6 +97,8 @@ namespace NKikimr { } else if (disableConfigV2) { Record.SetSwitchEnableConfigV2(false); } + Record.SetPeerName(peerName); + Record.SetUserToken(userToken); } TString ToString() const override { diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_get_block.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_get_block.cpp index d04f67f74bce..551f494b6977 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_get_block.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_get_block.cpp @@ -11,7 +11,7 @@ namespace NKikimr { class TBlobStorageGroupGetBlockRequest : public TBlobStorageGroupRequestActor { const ui64 TabletId; - ui64 Generation; + ui64 Generation = 0; const TInstant Deadline; ui64 Requests = 0; ui64 Responses = 0; diff --git a/ydb/core/blobstorage/nodewarden/distconf_audit.cpp b/ydb/core/blobstorage/nodewarden/distconf_audit.cpp new file mode 100644 index 000000000000..92b26108435a --- /dev/null +++ b/ydb/core/blobstorage/nodewarden/distconf_audit.cpp @@ -0,0 +1,35 @@ +#include "distconf_audit.h" + +#include +#include + +namespace NKikimr::NStorage { + +static const TString COMPONENT_NAME = "distconf"; +static const TString EMPTY_VALUE = "{none}"; + +void AuditLogReplaceConfig( + const TString& peer, + const TString& userSID, + const TString& sanitizedToken, + const TString& oldConfig, + const TString& newConfig, + const TString& reason, + bool success) +{ + auto peerName = NKikimr::NAddressClassifier::ExtractAddress(peer); + + AUDIT_LOG( + AUDIT_PART("component", COMPONENT_NAME) + AUDIT_PART("remote_address", (!peerName.empty() ? peerName : EMPTY_VALUE)) + AUDIT_PART("subject", (!userSID.empty() ? userSID : EMPTY_VALUE)) + AUDIT_PART("sanitized_token", (!sanitizedToken.empty() ? sanitizedToken : EMPTY_VALUE)) + AUDIT_PART("status", TString(success ? "SUCCESS" : "ERROR")) + AUDIT_PART("reason", reason, !reason.empty()) + AUDIT_PART("operation", TString("REPLACE CONFIG")) + AUDIT_PART("old_config", oldConfig) + AUDIT_PART("new_config", newConfig) + ); +} + +} // namespace NKikimr::NStorage diff --git a/ydb/core/blobstorage/nodewarden/distconf_audit.h b/ydb/core/blobstorage/nodewarden/distconf_audit.h new file mode 100644 index 000000000000..efe6d2117963 --- /dev/null +++ b/ydb/core/blobstorage/nodewarden/distconf_audit.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace NKikimr::NStorage { + +void AuditLogReplaceConfig( + const TString& peer, + const TString& userSID, + const TString& sanitizedToken, + const TString& oldConfig, + const TString& newConfig, + const TString& reason, + bool success); + +} // namespace NKikimr::NStorage diff --git a/ydb/core/blobstorage/nodewarden/distconf_invoke.h b/ydb/core/blobstorage/nodewarden/distconf_invoke.h index 97b2630237c4..eaaf854a7183 100644 --- a/ydb/core/blobstorage/nodewarden/distconf_invoke.h +++ b/ydb/core/blobstorage/nodewarden/distconf_invoke.h @@ -121,6 +121,7 @@ namespace NKikimr::NStorage { void AdvanceGeneration(); void StartProposition(NKikimrBlobStorage::TStorageConfig *config, bool updateFields = true); + bool CheckConfigUpdate(const NKikimrBlobStorage::TStorageConfig& proposed); //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Query termination and result delivery diff --git a/ydb/core/blobstorage/nodewarden/distconf_invoke_common.cpp b/ydb/core/blobstorage/nodewarden/distconf_invoke_common.cpp index 26a934cfb61c..5247815ba67b 100644 --- a/ydb/core/blobstorage/nodewarden/distconf_invoke_common.cpp +++ b/ydb/core/blobstorage/nodewarden/distconf_invoke_common.cpp @@ -1,3 +1,4 @@ +#include "distconf_audit.h" #include "distconf_invoke.h" namespace NKikimr::NStorage { @@ -186,13 +187,25 @@ namespace NKikimr::NStorage { UpdateFingerprint(config); } - if (auto error = ValidateConfigUpdate(*Self->StorageConfig, *config)) { - STLOG(PRI_DEBUG, BS_NODE, NWDC78, "StartProposition config validation failed", (SelfId, SelfId()), - (Error, *error), (Config, config)); - return FinishWithError(TResult::ERROR, TStringBuilder() - << "StartProposition config validation failed: " << *error); + if (!CheckConfigUpdate(*config)) { + return; } + const auto& replaceConfig = Event->Get()->Record.GetReplaceStorageConfig(); + TStringBuilder oldConfig; + oldConfig << Self->MainConfigYaml << (Self->StorageConfigYaml ? *Self->StorageConfigYaml : ""); + TStringBuilder newConfig; + newConfig << *NewYaml << (NewStorageYaml ? *NewStorageYaml : ""); + NACLib::TUserToken userToken = NACLib::TUserToken{replaceConfig.GetUserToken()}; + AuditLogReplaceConfig( + /* peer = */ replaceConfig.GetPeerName(), + /* userSID = */ userToken.GetUserSID(), + /* sanitizedToken = */ userToken.GetSanitizedToken(), + /* oldConfig = */ oldConfig, + /* newConfig = */ newConfig, + /* reason = */ {}, + /* success = */ true); + Self->CurrentProposedStorageConfig.emplace(std::move(*config)); auto done = [&](TEvGather *res) -> std::optional { @@ -217,6 +230,16 @@ namespace NKikimr::NStorage { Self->RootState = ERootState::IN_PROGRESS; // forbid any concurrent activity } + bool TInvokeRequestHandlerActor::CheckConfigUpdate(const NKikimrBlobStorage::TStorageConfig& proposed) { + if (auto error = ValidateConfigUpdate(*Self->StorageConfig, proposed)) { + STLOG(PRI_DEBUG, BS_NODE, NWDC78, "Config update validation failed", (SelfId, SelfId()), + (Error, *error), (ProposedConfig, proposed)); + FinishWithError(TResult::ERROR, TStringBuilder() << "Config update validation failed: " << *error); + return false; + } + return true; + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Query termination and result delivery diff --git a/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp b/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp index 8d3ce407cd36..a2f4dd611b77 100644 --- a/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp +++ b/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp @@ -339,6 +339,8 @@ namespace NKikimr::NStorage { record.SetOperation(NKikimrBlobStorage::TEvControllerDistconfRequest::DisableDistconf); if (ProposedStorageConfig.HasExpectedStorageYamlVersion()) { record.SetExpectedStorageConfigVersion(ProposedStorageConfig.GetExpectedStorageYamlVersion()); + record.SetPeerName(replaceStorageConfig.GetPeerName()); + record.SetUserToken(replaceStorageConfig.GetUserToken()); } break; diff --git a/ydb/core/blobstorage/nodewarden/ya.make b/ydb/core/blobstorage/nodewarden/ya.make index 4e47edae2b76..8a2d2ae96764 100644 --- a/ydb/core/blobstorage/nodewarden/ya.make +++ b/ydb/core/blobstorage/nodewarden/ya.make @@ -5,6 +5,8 @@ SRCS( group_stat_aggregator.h distconf.cpp distconf.h + distconf_audit.h + distconf_audit.cpp distconf_binding.cpp distconf_console.cpp distconf_dynamic.cpp diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_data.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_data.h index 508784e48ba2..2f6ce6ffe033 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_data.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_data.h @@ -428,14 +428,28 @@ struct TMetadataHeader { *this = header; } - bool CheckHash() const { + bool CheckHash(ui64 *magic) const { TPDiskHashCalculator hasher; +#ifdef DISABLE_PDISK_ENCRYPTION + if (magic) { + hasher.Hash(magic, sizeof(ui64)); + } +#else + Y_UNUSED(magic); +#endif hasher.Hash(this, sizeof(TMetadataHeader) - sizeof(THash)); return hasher.GetHashResult() == HeaderHash; } - void SetHash() { + void SetHash(const ui64 *magic) { TPDiskHashCalculator hasher; +#ifdef DISABLE_PDISK_ENCRYPTION + if (magic) { + hasher.Hash(magic, sizeof(ui64)); + } +#else + Y_UNUSED(magic); +#endif hasher.Hash(this, sizeof(TMetadataHeader) - sizeof(THash)); HeaderHash = hasher.GetHashResult(); } diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h index 553923f87596..7c2a10b2d3bc 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h @@ -425,7 +425,7 @@ class TPDisk : public IPDisk { void DropAllMetadataRequests(); TRcBuf CreateMetadataPayload(TRcBuf& metadata, size_t offset, size_t payloadSize, ui32 sectorSize, bool encryption, - const TKey& key, ui64 sequenceNumber, ui32 recordIndex, ui32 totalRecords); + const TKey& key, ui64 sequenceNumber, ui32 recordIndex, ui32 totalRecords, const ui64 *magic); bool WriteMetadataSync(TRcBuf&& metadata, const TDiskFormat& format); static std::optional CheckMetadataFormatSector(const ui8 *data, size_t len, diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_metadata.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_metadata.cpp index f10e61dfdbf5..189fada436a5 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_metadata.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_metadata.cpp @@ -41,7 +41,7 @@ namespace NKikimr::NPDisk { // obtain the header and decrypt its encrypted part, then validate the hash TMetadataHeader *header = reinterpret_cast(GetBuffer()); header->Encrypt(cypher); - if (header->CheckHash()) { + if (header->CheckHash((ui64*)(void*)&PDisk->Format.ChunkKey)) { // check we have read it all const ui32 total = sizeof(TMetadataHeader) + header->Length; if (total <= Buffer.size()) { @@ -167,7 +167,7 @@ namespace NKikimr::NPDisk { auto *header = reinterpret_cast(Buffer.GetDataMut()); header->Encrypt(cypher); - if (!header->CheckHash()) { + if (!header->CheckHash((ui64*)(void*)&Format.DataKey)) { req->ErrorReason = "header has is not valid"; } else if (header->TotalRecords != 1 || header->RecordIndex != 0 || header->SequenceNumber != 0) { req->ErrorReason = "header fields are filled incorrectly"; @@ -593,7 +593,7 @@ namespace NKikimr::NPDisk { const size_t payloadSize = Min(slotSize, metadataSize - offset); TRcBuf payload = CreateMetadataPayload(write.Metadata, offset, payloadSize, Format.SectorSize, - Cfg->EnableSectorEncryption, Format.ChunkKey, Meta.NextSequenceNumber, i, numSlotsRequired); + Cfg->EnableSectorEncryption, Format.ChunkKey, Meta.NextSequenceNumber, i, numSlotsRequired, (ui64*)(void*)&Format.ChunkKey); completion->AddQuery(key, std::move(payload)); completion->CostNs += DriveModel.TimeForSizeNs(payload.size(), key.ChunkIdx, TDriveModel::OP_TYPE_WRITE); @@ -617,7 +617,7 @@ namespace NKikimr::NPDisk { } TRcBuf payload = CreateMetadataPayload(write.Metadata, 0, write.Metadata.size(), DefaultSectorSize, - true, fmt.DataKey, 0, 0, 1); + true, fmt.DataKey, 0, 0, 1, (ui64*)(void*)&fmt.DataKey); const size_t bytesToWrite = payload.size(); ui64 rawDeviceSize = 0; @@ -718,7 +718,7 @@ namespace NKikimr::NPDisk { } TRcBuf TPDisk::CreateMetadataPayload(TRcBuf& metadata, size_t offset, size_t payloadSize, ui32 sectorSize, - bool encryption, const TKey& key, ui64 sequenceNumber, ui32 recordIndex, ui32 totalRecords) { + bool encryption, const TKey& key, ui64 sequenceNumber, ui32 recordIndex, ui32 totalRecords, const ui64 *magic) { Y_VERIFY_S(offset + payloadSize <= metadata.size(), PCtx->PDiskLogPrefix); Y_VERIFY_DEBUG_S(IsPowerOf2(sectorSize), PCtx->PDiskLogPrefix); @@ -749,7 +749,7 @@ namespace NKikimr::NPDisk { .DataHash = dataHasher.GetHashResult(), }; - header->SetHash(); + header->SetHash(magic); header->EncryptData(cypher); header->Encrypt(cypher); @@ -791,7 +791,7 @@ namespace NKikimr::NPDisk { const NMeta::TSlotKey key = freeSlotKeys[i]; const size_t payloadSize = Min(slotSize, metadataSize - offset); TRcBuf payload = CreateMetadataPayload(metadata, offset, payloadSize, format.SectorSize, - Cfg->EnableSectorEncryption, format.ChunkKey, 1, i, numSlotsRequired); + Cfg->EnableSectorEncryption, format.ChunkKey, 1, i, numSlotsRequired, (ui64*)(void*)&format.ChunkKey); BlockDevice->PwriteSync(payload.data(), payload.size(), format.Offset(key.ChunkIdx, key.OffsetInSectors), {}, nullptr); } diff --git a/ydb/core/blobstorage/ut_blobstorage/donor.cpp b/ydb/core/blobstorage/ut_blobstorage/donor.cpp index de62dc03cd15..dce76e1a6e9a 100644 --- a/ydb/core/blobstorage/ut_blobstorage/donor.cpp +++ b/ydb/core/blobstorage/ut_blobstorage/donor.cpp @@ -483,4 +483,146 @@ Y_UNIT_TEST_SUITE(Donor) { } // env.Sim(TDuration::Seconds(10)); } + + TVector GetDonors(TEnvironmentSetup& env, const TVDiskID& vdiskId) { + TVector result; + const auto& baseConfig = env.FetchBaseConfig(); + for (const auto& slot : baseConfig.GetVSlot()) { + for (size_t donorId = 0; donorId < slot.DonorsSize(); ++donorId) { + const auto& donor = slot.GetDonors(donorId); + if (VDiskIDFromVDiskID(donor.GetVDiskId()) == vdiskId) { + result.push_back(donor); + } + } + } + return result; + } + + Y_UNIT_TEST(CheckOnlineReadRequestToDonor) { + TEnvironmentSetup env{{ + .NodeCount = 8, + .VDiskReplPausedAtStart = true, + .Erasure = TBlobStorageGroupType::Erasure4Plus2Block, + .ReplMaxQuantumBytes = 1 << 20, + .ReplMaxDonorNotReadyCount = 2 + }}; + auto& runtime = env.Runtime; + + env.EnableDonorMode(); + env.CreateBoxAndPool(2, 1); + env.CommenceReplication(); + env.Sim(TDuration::Seconds(30)); + + const ui32 groupId = env.GetGroups().front(); + + const TActorId edge = runtime->AllocateEdgeActor(1, __FILE__, __LINE__); + const TString buffer = TString(2_MB, 'b'); + TLogoBlobID logoBlobId(1, 1, 0, 0, buffer.size(), 0); + TVDiskID vdiskId; + bool vdiskIdWithBlobSet = false; + TLogoBlobID vdiskLogoBlobId; + + // Put blob and find vdisk with it and partId = 1 + { + env.Runtime->FilterFunction = [&](ui32 nodeId, std::unique_ptr& ev) { + if (ev->GetTypeRewrite() == TEvBlobStorage::EvVPut) { + Y_UNUSED(nodeId); + auto* msg = ev->Get(); + const auto& blobId = LogoBlobIDFromLogoBlobID(msg->Record.GetBlobID()); + if (blobId.IsSameBlob(logoBlobId) && blobId.PartId() == 1 && !vdiskIdWithBlobSet) { + vdiskId = VDiskIDFromVDiskID(msg->Record.GetVDiskID()); + vdiskLogoBlobId = blobId; + vdiskIdWithBlobSet = true; + } else { + } + } + return true; + }; + + runtime->WrapInActorContext(edge, [&] { + SendToBSProxy(edge, groupId, new TEvBlobStorage::TEvPut(logoBlobId, buffer, TInstant::Max())); + }); + auto res = env.WaitForEdgeActorEvent(edge, false); + UNIT_ASSERT_VALUES_EQUAL(res->Get()->Status, NKikimrProto::OK); + UNIT_ASSERT(vdiskIdWithBlobSet); + } + + auto info = env.GetGroupInfo(groupId); + const TActorId& vdiskActorId = info->GetActorId(vdiskId); + + // Move slot out from disk and finf donor + env.SettlePDisk(vdiskActorId); + CheckHasDonor(env, vdiskActorId, vdiskId); + const auto& donors = GetDonors(env, vdiskId); + UNIT_ASSERT_VALUES_EQUAL(donors.size(), 1); + const auto& donor = donors.front(); + + bool requestVdiskNotYet = false; + bool fastRequestToDonor = false; + bool asyncRequestToDonor = false; + + const auto& checkRequestToDonor = [&](std::unique_ptr& ev, const NKikimrBlobStorage::EGetHandleClass& handleClass, bool& requestExist) { + auto* msg = ev->Get(); + if (msg->Record.ExtremeQueriesSize() != 1) { + return; + } + const auto& query = msg->Record.GetExtremeQueries(0); + const auto& blobId = LogoBlobIDFromLogoBlobID(query.GetId()); + const auto& slotId = donor.GetVSlotId(); + const auto& donorActorId = MakeBlobStorageVDiskID(slotId.GetNodeId(), slotId.GetPDiskId(), slotId.GetVSlotId()); + + if (blobId == vdiskLogoBlobId && + ev->Recipient == donorActorId && + msg->Record.GetHandleClass() == handleClass) { + UNIT_ASSERT(!requestExist); + requestExist = true; + } + return; + }; + + // Check disk answer TEvEnrichNotYet and request FastRead from donor for online read + env.Runtime->FilterFunction = [&](ui32 nodeId, std::unique_ptr& ev) { + Y_UNUSED(nodeId); + if (ev->GetTypeRewrite() == TEvBlobStorage::EvEnrichNotYet) { + UNIT_ASSERT(!requestVdiskNotYet); + auto msg = ev->Get()->Query.Get()->Get(); + UNIT_ASSERT_VALUES_EQUAL(msg->Record.ExtremeQueriesSize(), 1); + const auto& query = msg->Record.GetExtremeQueries(0); + const auto& vdid = VDiskIDFromVDiskID(msg->Record.GetVDiskID()); + const auto& blobId = LogoBlobIDFromLogoBlobID(query.GetId()); + UNIT_ASSERT(vdid.SameExceptGeneration(vdiskId)); + UNIT_ASSERT_VALUES_EQUAL(vdid.GroupGeneration, 2); + UNIT_ASSERT_VALUES_EQUAL(blobId, vdiskLogoBlobId); + requestVdiskNotYet = true; + } + + if (ev->GetTypeRewrite() == TEvBlobStorage::EvVGet) { + checkRequestToDonor(ev, NKikimrBlobStorage::EGetHandleClass::FastRead, fastRequestToDonor); + } + return true; + }; + + // Get blob + { + auto ev = new TEvBlobStorage::TEvGet(logoBlobId, 0, 0, TInstant::Max(), NKikimrBlobStorage::EGetHandleClass::FastRead); + runtime->WrapInActorContext(edge, [&] {SendToBSProxy(edge, groupId, ev);}); + auto res = env.WaitForEdgeActorEvent(edge, false); + UNIT_ASSERT_VALUES_EQUAL(res->Get()->Status, NKikimrProto::OK); + UNIT_ASSERT(requestVdiskNotYet); + UNIT_ASSERT(fastRequestToDonor); + } + + // Check disk request AsyncRead from donor for replication + env.Runtime->FilterFunction = [&](ui32 nodeId, std::unique_ptr& ev) { + Y_UNUSED(nodeId); + if (ev->GetTypeRewrite() == TEvBlobStorage::EvVGet) { + checkRequestToDonor(ev, NKikimrBlobStorage::EGetHandleClass::AsyncRead, asyncRequestToDonor); + } + return true; + }; + + // Start replication + env.CommenceReplication(); + UNIT_ASSERT(asyncRequestToDonor); + } } diff --git a/ydb/core/blobstorage/ut_blobstorage/lib/env.h b/ydb/core/blobstorage/ut_blobstorage/lib/env.h index 87b89da68f6f..58aed6c51477 100644 --- a/ydb/core/blobstorage/ut_blobstorage/lib/env.h +++ b/ydb/core/blobstorage/ut_blobstorage/lib/env.h @@ -1000,8 +1000,9 @@ struct TEnvironmentSetup { return SyncQueryFactory(actorId, [&] { return std::make_unique(args...); }); } - ui64 AggregateVDiskCounters(TString storagePool, ui32 nodesCount, ui32 groupSize, ui32 groupId, - const std::vector& pdiskLayout, TString subsystem, TString counter, bool derivative = false) { + ui64 AggregateVDiskCountersBase(TString storagePool, ui32 nodesCount, ui32 groupSize, ui32 groupId, + const std::vector& pdiskLayout, TString subsgroupName, TString subgroupValue, + TString counter, bool derivative = false) { ui64 ctr = 0; for (ui32 nodeId = 1; nodeId <= nodesCount; ++nodeId) { @@ -1019,12 +1020,24 @@ struct TEnvironmentSetup { GetSubgroup("orderNumber", orderNumber)-> GetSubgroup("pdisk", pdisk)-> GetSubgroup("media", "rot")-> - GetSubgroup("subsystem", subsystem)-> + GetSubgroup(subsgroupName, subgroupValue)-> GetCounter(counter, derivative)->Val(); } } return ctr; - }; + } + + ui64 AggregateVDiskCounters(TString storagePool, ui32 nodesCount, ui32 groupSize, ui32 groupId, + const std::vector& pdiskLayout, TString subsystem, TString counter, bool derivative = false) { + return AggregateVDiskCountersBase(storagePool, nodesCount, groupSize, groupId, pdiskLayout, + "subsystem", subsystem, counter, derivative); + } + + ui64 AggregateVDiskCountersWithHandleClass(TString storagePool, ui32 nodesCount, ui32 groupSize, ui32 groupId, + const std::vector& pdiskLayout, TString handleclass, TString counter) { + return AggregateVDiskCountersBase(storagePool, nodesCount, groupSize, groupId, pdiskLayout, + "handleclass", handleclass, counter); + } void SetIcbControl(ui32 nodeId, TString controlName, ui64 value) { if (nodeId == 0) { diff --git a/ydb/core/blobstorage/ut_blobstorage/monitoring.cpp b/ydb/core/blobstorage/ut_blobstorage/monitoring.cpp index 0a4b844e8e3f..a1ed53615fc3 100644 --- a/ydb/core/blobstorage/ut_blobstorage/monitoring.cpp +++ b/ydb/core/blobstorage/ut_blobstorage/monitoring.cpp @@ -106,19 +106,10 @@ void TestDSProxyAndVDiskEqualCost(const TBlobStorageGroupInfo::TTopology& topolo if (dsproxyCost == vdiskCost) { return; } + UNIT_ASSERT(queuePut != 0); UNIT_ASSERT_C(oks != actor->RequestsSent || queuePut != queueSent, str.Str()); } -#define MAKE_TEST(erasure, requestType, requests, inflight) \ -Y_UNIT_TEST(Test##requestType##erasure##Requests##requests##Inflight##inflight) { \ - auto groupType = TBlobStorageGroupType::Erasure##erasure; \ - ui32 realms = (groupType == TBlobStorageGroupType::ErasureMirror3dc) ? 3 : 1; \ - ui32 domains = (groupType == TBlobStorageGroupType::ErasureMirror3dc) ? 3 : 8; \ - TBlobStorageGroupInfo::TTopology topology(groupType, realms, domains, 1, true); \ - auto actor = new TInflightActor##requestType({requests, inflight}); \ - TestDSProxyAndVDiskEqualCost(topology, actor); \ -} - #define MAKE_TEST_W_DATASIZE(erasure, requestType, requests, inflight, dataSize) \ Y_UNIT_TEST(Test##requestType##erasure##Requests##requests##Inflight##inflight##BlobSize##dataSize) { \ auto groupType = TBlobStorageGroupType::Erasure##erasure; \ @@ -283,4 +274,54 @@ Y_UNIT_TEST_SUITE(DiskTimeAvailable) { } } +template +void TestDSProxyAndVDiskEqualByteCounters(TInflightActor* actor) { + std::unique_ptr env; + ui32 groupSize; + TBlobStorageGroupType groupType; + ui32 groupId; + std::vector pdiskLayout; + TBlobStorageGroupInfo::TTopology topology(TBlobStorageGroupType::ErasureMirror3dc, 3, 3, 1, true); + SetupEnv(topology, env, groupSize, groupType, groupId, pdiskLayout); + actor->SetGroupId(TGroupId::FromValue(groupId)); + env->Runtime->Register(actor, 1); + env->Sim(TDuration::Minutes(10)); + ui64 dsproxyCounter = 0; + ui64 vdiskCounter = 0; + + for (ui32 nodeId = 1; nodeId <= groupSize; ++nodeId) { + auto* appData = env->Runtime->GetNode(nodeId)->AppData.get(); + for(auto sizeClass : {"256", "4096", "262144", "1048576", "16777216", "4194304"}) + dsproxyCounter += GetServiceCounters(appData->Counters, "dsproxynode")-> + GetSubgroup("subsystem", "request")-> + GetSubgroup("storagePool", env->StoragePoolName)-> + GetSubgroup("handleClass", "PutTabletLog")-> + GetSubgroup("sizeClass", sizeClass)-> + GetCounter("generatedSubrequestBytes")->Val(); + } + vdiskCounter = env->AggregateVDiskCountersWithHandleClass(env->StoragePoolName, groupSize, groupSize, groupId, pdiskLayout, + "PutTabletLog", "requestBytes"); + if constexpr(VERBOSE) { + for (ui32 i = 1; i <= groupSize; ++i) { + Cerr << " ##################### Node " << i << " ##################### " << Endl; + env->Runtime->GetNode(i)->AppData->Counters->OutputPlainText(Cerr); + } + } + UNIT_ASSERT(dsproxyCounter != 0); + UNIT_ASSERT_VALUES_EQUAL(dsproxyCounter, vdiskCounter); +} + + +Y_UNIT_TEST_SUITE(TestDSProxyAndVDiskEqualByteCounters) { + Y_UNIT_TEST(MultiPut) { + auto actor = new TInflightActorPut({10, 10}, 1000, 10); + TestDSProxyAndVDiskEqualByteCounters(actor); + } + + Y_UNIT_TEST(SinglePut) { + auto actor = new TInflightActorPut({1, 1}, 1000); + TestDSProxyAndVDiskEqualByteCounters(actor); + } +} + #undef MAKE_BURST_TEST diff --git a/ydb/core/blobstorage/ut_blobstorage/ut_helpers.h b/ydb/core/blobstorage/ut_blobstorage/ut_helpers.h index 4e02f66b26ce..b93c702c0ada 100644 --- a/ydb/core/blobstorage/ut_blobstorage/ut_helpers.h +++ b/ydb/core/blobstorage/ut_blobstorage/ut_helpers.h @@ -96,9 +96,10 @@ class TInflightActor : public TActorBootstrapped { class TInflightActorPut : public TInflightActor { public: - TInflightActorPut(TSettings settings, ui32 dataSize = 1024) + TInflightActorPut(TSettings settings, ui32 dataSize = 1024, ui32 putsInBatch = 1) : TInflightActor(settings) , DataSize(dataSize) + , PutsInBatch(putsInBatch) {} STRICT_STFUNC(StateWork, @@ -116,10 +117,12 @@ class TInflightActorPut : public TInflightActor { protected: void SendRequest() override { - TString data = MakeData(DataSize); - auto ev = new TEvBlobStorage::TEvPut(TLogoBlobID(1, 1, 1, 10, DataSize, Cookie++), - data, TInstant::Max(), NKikimrBlobStorage::UserData); - SendToBSProxy(SelfId(), GroupId, ev, 0); + for (ui32 i = 0; i < PutsInBatch; ++i) { + TString data = MakeData(DataSize); + auto ev = new TEvBlobStorage::TEvPut(TLogoBlobID(1, 1, 1, 10, DataSize, Cookie++), + data, TInstant::Max(), NKikimrBlobStorage::TabletLog); + SendToBSProxy(SelfId(), GroupId, ev, 0); + } } void Handle(TEvBlobStorage::TEvPutResult::TPtr res) { @@ -129,6 +132,7 @@ class TInflightActorPut : public TInflightActor { private: std::string Data; ui32 DataSize; + ui32 PutsInBatch; }; /////////////////////////////////// TInflightActorGet /////////////////////////////////// diff --git a/ydb/core/blobstorage/vdisk/common/vdisk_mongroups.h b/ydb/core/blobstorage/vdisk/common/vdisk_mongroups.h index b443c38e151e..986309c13beb 100644 --- a/ydb/core/blobstorage/vdisk/common/vdisk_mongroups.h +++ b/ydb/core/blobstorage/vdisk/common/vdisk_mongroups.h @@ -914,9 +914,11 @@ public: COUNTER_INIT(BlobsSqueeze, true); COUNTER_INIT(BlocksPromoteSsts, true); + COUNTER_INIT(BlocksExplicit, true); COUNTER_INIT(BlocksBalance, true); COUNTER_INIT(BarriersPromoteSsts, true); + COUNTER_INIT(BarriersExplicit, true); COUNTER_INIT(BarriersBalance, true); } @@ -928,9 +930,11 @@ public: COUNTER_DEF(BlobsSqueeze); COUNTER_DEF(BlocksPromoteSsts); + COUNTER_DEF(BlocksExplicit); COUNTER_DEF(BlocksBalance); COUNTER_DEF(BarriersPromoteSsts); + COUNTER_DEF(BarriersExplicit); COUNTER_DEF(BarriersBalance); }; diff --git a/ydb/core/blobstorage/vdisk/hulldb/compstrat/hulldb_compstrat_selector.cpp b/ydb/core/blobstorage/vdisk/hulldb/compstrat/hulldb_compstrat_selector.cpp index 484187736463..291cc3084d91 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/compstrat/hulldb_compstrat_selector.cpp +++ b/ydb/core/blobstorage/vdisk/hulldb/compstrat/hulldb_compstrat_selector.cpp @@ -99,6 +99,13 @@ namespace NKikimr { return action; } + // compact explicitly defined SST's, if set + action = TStrategyExplicit(HullCtx, Params, LevelSnap, Task).Select(); + if (action != ActNothing) { + ++HullCtx->CompactionStrategyGroup.BlocksExplicit(); + return action; + } + // try to find what to compact based on levels balance action = TStrategyBalance(HullCtx, Params, LevelSnap, Task).Select(); if (action != ActNothing) { @@ -129,6 +136,13 @@ namespace NKikimr { return action; } + // compact explicitly defined SST's, if set + action = TStrategyExplicit(HullCtx, Params, LevelSnap, Task).Select(); + if (action != ActNothing) { + ++HullCtx->CompactionStrategyGroup.BarriersExplicit(); + return action; + } + // try to find what to compact based on levels balance action = TStrategyBalance(HullCtx, Params, LevelSnap, Task).Select(); if (action != ActNothing) { diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/blobstorage_hullwritesst.h b/ydb/core/blobstorage/vdisk/hulldb/generic/blobstorage_hullwritesst.h index b0f9608fb33f..c7d14ce26f91 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/blobstorage_hullwritesst.h +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/blobstorage_hullwritesst.h @@ -412,6 +412,8 @@ namespace NKikimr { static_assert((SuffixSize >> 2 << 2) == SuffixSize, "expect (SuffixSize >> 2 << 2) == SuffixSize"); static_assert(sizeof(TIdxDiskLinker) <= sizeof(TIdxDiskPlaceHolder), "expect sizeof(TIdxDiskLinker) <= sizeof(TIdxDiskPlaceHolder)"); + typedef TRecIndexBase::TRec TRec; + public: TIndexBuilder(TVDiskContextPtr vctx, EWriterDataType type, ui8 owner, ui64 ownerRound, ui32 chunkSize, ui32 appendBlockSize, ui32 writeBlockSize, ui64 sstId, bool createdByRepl, @@ -654,10 +656,17 @@ namespace NKikimr { } info.CTime = TAppData::TimeProvider->Now(); - // move Recs/Outbound into LevelSegment we are going to use - Recs.shrink_to_fit(); + if constexpr (std::is_same_v) { + // load optimized SST index + LevelSegment->LoadLinearIndex(Recs); + } else { + // move Recs into LevelSegment we are going to use + Recs.shrink_to_fit(); + LevelSegment->LoadedIndex = std::move(Recs); + } + + // move Outbound into LevelSegment we are going to use Outbound.shrink_to_fit(); - LevelSegment->LoadedIndex = std::move(Recs); LevelSegment->LoadedOutbound = std::move(Outbound); // fill in all chunks vector used in the sst diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.cpp b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.cpp index 85583f55488e..e7951b3490ab 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.cpp +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.cpp @@ -8,7 +8,7 @@ namespace NKikimr { template void TLevelSegment::OutputHtml(ui32 &index, ui32 level, IOutputStream &str, TIdxDiskPlaceHolder::TInfo &sum) const { HTML(str) { - if (IsLoaded()) { + if (this->IsLoaded()) { TABLER() { TABLED() {SMALL() {str << index;}} TABLED() {SMALL() {str << level;}} @@ -22,6 +22,9 @@ namespace NKikimr { TABLED() {SMALL() {str << StorageRatio.MonSummary();}} TABLED() {SMALL() {str << (Info.IsCreatedByRepl() ? "REPL" : "COMP");}} TABLED() {SMALL() {str << ToStringLocalTimeUpToSeconds(Info.CTime);}} + TABLED() {SMALL() { + str << AssignedSstId << '/' << VolatileOrderId << '@' << FormatList(AllChunks); + }} ++index; } } @@ -31,7 +34,7 @@ namespace NKikimr { template void TLevelSegment::OutputProto(ui32 level, google::protobuf::RepeatedPtrField *rows) const { - if (IsLoaded()) { + if (this->IsLoaded()) { NKikimrVDisk::LevelStat *row = rows->Add(); row->set_level(level); row->set_first_lsn(Info.FirstLsn); diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.h b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.h index 6b9717a849d4..65ff20e1ab73 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.h +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.h @@ -11,11 +11,269 @@ namespace NKikimr { + template + struct TRecIndexBase : public TThrRefBase { +#pragma pack(push, 4) + struct TRec { + TKey Key; + TMemRec MemRec; + + TRec() = default; + + TRec(const TKey &key) + : Key(key) + , MemRec() + {} + + TRec(const TKey &key, const TMemRec &memRec) + : Key(key) + , MemRec(memRec) + {} + + struct TLess { + bool operator ()(const TRec &x, const TKey &key) const { + return x.Key < key; + } + }; + }; +#pragma pack(pop) + }; + + template + struct TRecIndex + : public TRecIndexBase + { + typedef TRecIndexBase::TRec TRec; + + TTrackableVector LoadedIndex; + + TRecIndex(TVDiskContextPtr vctx) + : LoadedIndex(TMemoryConsumer(vctx->SstIndex)) + {} + + bool IsLoaded() const { + return !LoadedIndex.empty(); + } + + ui64 Elements() const { + Y_DEBUG_ABORT_UNLESS(IsLoaded()); + return LoadedIndex.size(); + } + }; + + template <> + struct TRecIndex + : public TRecIndexBase + { +#pragma pack(push, 4) + struct TLogoBlobIdHigh { + union { + struct { + ui64 TabletId; // 8 bytes + ui64 StepR1 : 24; // 8 bytes + ui64 Generation : 32; + ui64 Channel : 8; + } N; + + ui64 X[2]; + } Raw; + + TLogoBlobIdHigh() { + Raw.X[0] = Raw.X[1] = 0; + } + + explicit TLogoBlobIdHigh(const TLogoBlobID& id) { + Raw.X[0] = id.GetRaw()[0]; + Raw.X[1] = id.GetRaw()[1]; + } + + TLogoBlobIdHigh(ui64 tabletId, ui32 generation, ui32 step, ui8 channel) { + Raw.N.TabletId = tabletId; + Raw.N.Channel = channel; + Raw.N.Generation = generation; + Raw.N.StepR1 = (step & 0xFFFFFF00ull) >> 8; + } + + bool operator == (const TLogoBlobIdHigh& r) const { + return Raw.X[0] == r.Raw.X[0] && Raw.X[1] == r.Raw.X[1]; + } + + bool operator != (const TLogoBlobIdHigh& r) const { + return !(operator == (r)); + } + + bool operator < (const TLogoBlobIdHigh& r) const { + return Raw.X[0] != r.Raw.X[0] ? Raw.X[0] < r.Raw.X[0] : Raw.X[1] < r.Raw.X[1]; + } + }; + + static_assert(sizeof(TLogoBlobIdHigh) == 16, "expect sizeof(TLogoBlobIdHigh) == 16"); + + struct TLogoBlobIdLow { + union { + struct { + ui64 PartId : 4; // 8 bytes + ui64 BlobSize : 26; + ui64 CrcMode : 2; + ui64 Cookie : 24; + ui64 StepR2 : 8; + } N; + + ui64 X; + } Raw; + + explicit TLogoBlobIdLow(const TLogoBlobID& id) { + Raw.X = id.GetRaw()[2]; + } + + TLogoBlobIdLow(ui32 step, ui32 cookie, ui32 crcMode, ui32 blobSize, ui32 partId) { + Raw.N.StepR2 = step & 0x000000FFull; + Raw.N.Cookie = cookie; + Raw.N.CrcMode = crcMode; + Raw.N.BlobSize = blobSize; + Raw.N.PartId = partId; + } + + bool operator == (const TLogoBlobIdLow& r) const { + return Raw.X == r.Raw.X; + } + + bool operator != (const TLogoBlobIdLow& r) const { + return !(operator == (r)); + } + + bool operator < (const TLogoBlobIdLow& r) const { + return Raw.X < r.Raw.X; + } + }; + + static_assert(sizeof(TLogoBlobIdLow) == 8, "expect sizeof(TLogoBlobIdLow) == 8"); + + struct TRecHigh { + TLogoBlobIdHigh Key; + ui32 LowRangeEndIndex; + + TRecHigh(TLogoBlobIdHigh key) + : Key(key) + {} + + struct TLess { + bool operator ()(const TRecHigh& l, const TLogoBlobIdHigh& r) const { + return l.Key < r; + } + }; + }; + + static_assert(sizeof(TRecHigh) == 20, "expect sizeof(TRecHigh) == 20"); + + struct TRecLow { + TLogoBlobIdLow Key; + TMemRecLogoBlob MemRec; + + TRecLow(TLogoBlobIdLow key, TMemRecLogoBlob memRec) + : Key(key) + , MemRec(memRec) + {} + + struct TLess { + bool operator ()(const TRecLow& l, const TLogoBlobIdLow& r) const { + return l.Key < r; + } + }; + }; + + static_assert(sizeof(TRecLow) == 28, "expect sizeof(TRecLow) == 28"); +#pragma pack(pop) + + TTrackableVector IndexHigh; + TTrackableVector IndexLow; + + TRecIndex(TVDiskContextPtr vctx) + : IndexHigh(TMemoryConsumer(vctx->SstIndex)) + , IndexLow(TMemoryConsumer(vctx->SstIndex)) + {} + + bool IsLoaded() const { + return !IndexLow.empty(); + } + + ui64 Elements() const { + Y_DEBUG_ABORT_UNLESS(IsLoaded()); + return IndexLow.size(); + } + + void LoadLinearIndex(const TTrackableVector& linearIndex) { + if (linearIndex.empty()) { + return; + } + + IndexHigh.clear(); + IndexHigh.reserve(linearIndex.size()); + IndexLow.clear(); + IndexLow.reserve(linearIndex.size()); + + const TRec* rec = linearIndex.begin(); + + auto blobId = rec->Key.LogoBlobID(); + TLogoBlobIdHigh high(blobId); + TLogoBlobIdLow low(blobId); + TLogoBlobIdHigh highPrev = high; + + IndexHigh.emplace_back(high); + IndexLow.emplace_back(low, rec->MemRec); + ++rec; + + for (; rec != linearIndex.end(); ++rec) { + auto blobId = rec->Key.LogoBlobID(); + TLogoBlobIdHigh high(blobId); + TLogoBlobIdLow low(blobId); + + if (Y_UNLIKELY(high != highPrev)) { + IndexHigh.back().LowRangeEndIndex = IndexLow.size(); + IndexHigh.emplace_back(high); + highPrev = high; + } + + IndexLow.emplace_back(low, rec->MemRec); + } + + IndexHigh.back().LowRangeEndIndex = IndexLow.size(); + IndexHigh.shrink_to_fit(); + } + + void SaveLinearIndex(TTrackableVector* linearIndex) const { + if (IndexLow.empty()) { + return; + } + + linearIndex->clear(); + linearIndex->reserve(IndexLow.size()); + + const TRecHigh* high = IndexHigh.begin(); + const TRecLow* low = IndexLow.begin(); + const TRecLow* lowRangeEnd = low + high->LowRangeEndIndex; + + while (low != IndexLow.end()) { + auto& highKey = high->Key; + TLogoBlobID blobId(highKey.Raw.X[0], highKey.Raw.X[1], low->Key.Raw.X); + linearIndex->emplace_back(TKeyLogoBlob(blobId), low->MemRec); + + ++low; + if (Y_UNLIKELY(low == lowRangeEnd)) { + ++high; + if (high != IndexHigh.end()) { + lowRangeEnd = IndexLow.begin() + high->LowRangeEndIndex; + } + } + } + } + }; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TLevelSegment //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - struct TLevelSegment : public TThrRefBase { + struct TLevelSegment : public TRecIndex { typedef TLevelSegment TThis; using TKeyType = TKey; using TMemRecType = TMemRec; @@ -56,34 +314,7 @@ namespace NKikimr { } }; - // records stored in the index -#pragma pack(push, 4) - struct TRec { - TKey Key; - TMemRec MemRec; - - TRec() = default; - - TRec(const TKey &key) - : Key(key) - , MemRec() - {} - - TRec(const TKey &key, const TMemRec &memRec) - : Key(key) - , MemRec(memRec) - {} - - struct TLess { - bool operator () (const TRec &x, const TKey &key) const { - return x.Key < key; - } - }; - }; -#pragma pack(pop) - TDiskPart LastPartAddr; // tail of reverted list of parts (on disk) - TTrackableVector LoadedIndex; // the whole index loaded into memory TTrackableVector LoadedOutbound; TIdxDiskPlaceHolder::TInfo Info; TVector AllChunks; // all chunk ids that store index and data for this segment @@ -95,8 +326,8 @@ namespace NKikimr { ui64 VolatileOrderId = 0; TLevelSegment(TVDiskContextPtr vctx) - : LastPartAddr() - , LoadedIndex(TMemoryConsumer(vctx->SstIndex)) + : TRecIndex(vctx) + , LastPartAddr() , LoadedOutbound(TMemoryConsumer(vctx->SstIndex)) , Info() , AllChunks() @@ -104,8 +335,8 @@ namespace NKikimr { {} TLevelSegment(TVDiskContextPtr vctx, const TDiskPart &addr) - : LastPartAddr(addr) - , LoadedIndex(TMemoryConsumer(vctx->SstIndex)) + : TRecIndex(vctx) + , LastPartAddr(addr) , LoadedOutbound(TMemoryConsumer(vctx->SstIndex)) , Info() , AllChunks() @@ -115,8 +346,8 @@ namespace NKikimr { } TLevelSegment(TVDiskContextPtr vctx, const NKikimrVDiskData::TDiskPart &pb) - : LastPartAddr(pb) - , LoadedIndex(TMemoryConsumer(vctx->SstIndex)) + : TRecIndex(vctx) + , LastPartAddr(pb) , LoadedOutbound(TMemoryConsumer(vctx->SstIndex)) , Info() , AllChunks() @@ -127,10 +358,6 @@ namespace NKikimr { return LastPartAddr; } - bool IsLoaded() const { - return !LoadedIndex.empty(); - } - void SetAddr(const TDiskPart &addr) { LastPartAddr = addr; } @@ -163,7 +390,7 @@ namespace NKikimr { TMemIterator it(this); it.SeekToFirst(); while (it.Valid()) { - const TMemRec& memRec = it->MemRec; + const TMemRec& memRec = it.GetMemRec(); switch (memRec.GetType()) { case TBlobType::HugeBlob: case TBlobType::ManyHugeBlobs: @@ -189,13 +416,9 @@ namespace NKikimr { ui64 GetFirstLsn() const { return Info.FirstLsn; } ui64 GetLastLsn() const { return Info.LastLsn; } - const TKey &FirstKey() const; - const TKey &LastKey() const; - // number of elements in the sst - ui64 Elements() const { - Y_DEBUG_ABORT_UNLESS(IsLoaded()); - return LoadedIndex.size(); - } + TKey FirstKey() const; + TKey LastKey() const; + // append cur seg chunk ids (index and data) to the vector void FillInChunkIds(TVector &vec) const { // copy chunks ids @@ -218,9 +441,7 @@ namespace NKikimr { class TWriter; }; - extern template struct TLevelSegment; extern template struct TLevelSegment; extern template struct TLevelSegment; } // NKikimr - diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it.h b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it.h index 3f44caf5937b..39b71735e15e 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it.h +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it.h @@ -13,18 +13,9 @@ namespace NKikimr { typedef ::NKikimr::TLevelSegment TLevelSegment; typedef typename TLevelSegment::TRec TRec; - typedef ptrdiff_t difference_type; - typedef TRec value_type; - typedef const TRec * pointer; - typedef const TRec & reference; - - typedef std::bidirectional_iterator_tag iterator_category; - - const TLevelSegment *Segment; const TRec *Ptr; - const TRec *Begin() const { return Segment->LoadedIndex.data(); } @@ -82,6 +73,11 @@ namespace NKikimr { return Ptr->Key; } + const TMemRec& GetMemRec() const { + Y_DEBUG_ABORT_UNLESS(Valid()); + return Ptr->MemRec; + } + void SeekToFirst() { Ptr = Begin(); } @@ -96,14 +92,6 @@ namespace NKikimr { Ptr = ::LowerBound(Begin(), End(), key, typename TRec::TLess()); } - const TRec &operator*() const { - return *Ptr; - } - - const TRec *operator->() const { - return Ptr; - } - template void PutToMerger(TRecordMerger *merger) { merger->AddFromSegment(Ptr->MemRec, Segment->GetOutbound(), GetCurKey(), Segment->Info.LastLsn, Segment); @@ -136,21 +124,166 @@ namespace NKikimr { } }; + template <> + class TLevelSegment::TMemIterator { + protected: + typedef ::NKikimr::TLevelSegment TLevelSegment; + + const TLevelSegment* Segment = nullptr; + + const TLevelSegment::TRecHigh* High = nullptr; + const TLevelSegment::TRecLow* Low = nullptr; + const TLevelSegment::TRecLow* LowRangeBegin = nullptr; + + public: + TMemIterator(const TLevelSegment* segment) + : Segment(segment) + {} + + TMemIterator() = default; + + TMemIterator(const TMemIterator& i) { + Segment = i.Segment; + High = i.High; + Low = i.Low; + LowRangeBegin = i.LowRangeBegin; + } + + TMemIterator& operator=(const TMemIterator& i) { + Segment = i.Segment; + High = i.High; + Low = i.Low; + LowRangeBegin = i.LowRangeBegin; + return *this; + } + + bool Valid() const { + return Segment && Low && Low >= Segment->IndexLow.begin() && Low < Segment->IndexLow.end(); + } + + void Next() { + Y_DEBUG_ABORT_UNLESS(Valid()); + ++Low; + if (Y_UNLIKELY(Low == Segment->IndexLow.begin() + High->LowRangeEndIndex)) { + ++High; + LowRangeBegin = Low; + } + } + + void Prev() { + Y_DEBUG_ABORT_UNLESS(Segment && Low + && Low >= Segment->IndexLow.begin() && Low <= Segment->IndexLow.end()); + + if (Y_UNLIKELY(Low == LowRangeBegin)) { + --High; + LowRangeBegin = Segment->IndexLow.begin() + + (High <= Segment->IndexHigh.begin() ? 0 : (High - 1)->LowRangeEndIndex); + } + --Low; + } + + TKeyLogoBlob GetCurKey() const { + Y_DEBUG_ABORT_UNLESS(Valid()); + const auto& high = High->Key; + const auto& low = Low->Key; + return TKeyLogoBlob(TLogoBlobID(high.Raw.X[0], high.Raw.X[1], low.Raw.X)); + } + + const TMemRecLogoBlob& GetMemRec() const { + Y_DEBUG_ABORT_UNLESS(Valid()); + return Low->MemRec; + } + + void SeekToFirst() { + High = Segment->IndexHigh.begin(); + Low = LowRangeBegin = Segment->IndexLow.begin(); + } + + void SeekToLast() { + High = Segment->IndexHigh.end(); + Low = LowRangeBegin = Segment->IndexLow.end(); + Prev(); + } + + void Seek(const TKeyLogoBlob& key) { + TLevelSegment::TLogoBlobIdHigh keyHigh(key.LogoBlobID()); + TLevelSegment::TLogoBlobIdLow keyLow(key.LogoBlobID()); + + High = std::lower_bound(Segment->IndexHigh.begin(), Segment->IndexHigh.end(), + keyHigh, TLevelSegment::TRecHigh::TLess()); + + if (High == Segment->IndexHigh.end()) { + Low = LowRangeBegin = Segment->IndexLow.end(); + return; + } + + auto rangeBegin = Segment->IndexLow.begin() + + (High == Segment->IndexHigh.begin() ? 0 : (High - 1)->LowRangeEndIndex); + + if (High->Key != keyHigh) { + Low = LowRangeBegin = rangeBegin; + return; + } + + auto rangeEnd = Segment->IndexLow.begin() + High->LowRangeEndIndex; + + Low = std::lower_bound(rangeBegin, rangeEnd, keyLow, TLevelSegment::TRecLow::TLess()); + + if (Low == rangeEnd) { + LowRangeBegin = rangeEnd; + ++High; + } else { + LowRangeBegin = rangeBegin; + } + } + + template + void PutToMerger(TRecordMerger* merger) { + merger->AddFromSegment(GetMemRec(), Segment->GetOutbound(), GetCurKey(), Segment->Info.LastLsn, Segment); + } + + template + void PutToHeap(Heap& heap) { + heap.Add(this); + } + + bool operator == (const TMemIterator& it) const { + Y_ABORT_UNLESS(Segment == it.Segment); + return High == it.High && Low == it.Low; + } + + bool operator != (const TMemIterator& it) const { + return !(operator == (it)); + } + + TDiskDataExtractor* GetDiskData(TDiskDataExtractor* extr) const { + return GetMemRec().GetDiskData(extr, Segment->GetOutbound()); + } + + const TLevelSegment* GetSstPtr() const { + return Segment; + } + + const TDiskPart* GetOutbound() const { + return Segment->GetOutbound(); + } + }; + //////////////////////////////////////////////////////////////////////////// // TLevelSegment methods //////////////////////////////////////////////////////////////////////////// template - const TKey &TLevelSegment::FirstKey() const { + TKey TLevelSegment::FirstKey() const { TMemIterator it(this); it.SeekToFirst(); - return it->Key; + return it.GetCurKey(); } template - const TKey &TLevelSegment::LastKey() const { + TKey TLevelSegment::LastKey() const { TMemIterator it(this); it.SeekToLast(); - return it->Key; + return it.GetCurKey(); } } // NKikimr diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it_all_ut.cpp b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it_all_ut.cpp index eb478ab51fc5..b7b6bb2f4227 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it_all_ut.cpp +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it_all_ut.cpp @@ -115,6 +115,151 @@ namespace NKikimr { it.Seek(id); UNIT_ASSERT(it.GetCurKey().ToString() == "[0:0:16:0:0:0:0]"); } + + Y_UNIT_TEST(TestSstIndexSeekAndIterate) { + TTestContexts ctxs; + TTrackableVector index(TMemoryConsumer(ctxs.GetVCtx()->SstIndex)); + + auto addRecord = [&index](ui64 tabletId, ui32 step) { + TLogoBlobID id(tabletId, 0, step, 0, 0, 0); + index.emplace_back(TKeyLogoBlob(id), TMemRecLogoBlob()); + }; + + addRecord(10, 0); + addRecord(10, 10); + addRecord(20, 0); + addRecord(20, 10); + addRecord(20, 300); + + TLogoBlobSstPtr ptr(new TLogoBlobSst(ctxs.GetVCtx())); + ptr->LoadLinearIndex(index); + + TMemIterator it(ptr.Get()); + + it.Seek(TLogoBlobID(5, 0, 0, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[10:0:0:0:0:0:0]"); + + it.Seek(TLogoBlobID(10, 0, 0, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[10:0:0:0:0:0:0]"); + + it.Seek(TLogoBlobID(10, 0, 5, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[10:0:10:0:0:0:0]"); + + it.Seek(TLogoBlobID(10, 0, 10, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[10:0:10:0:0:0:0]"); + + it.Seek(TLogoBlobID(10, 0, 15, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[20:0:0:0:0:0:0]"); + + it.Seek(TLogoBlobID(15, 0, 0, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[20:0:0:0:0:0:0]"); + + it.Seek(TLogoBlobID(20, 0, 0, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[20:0:0:0:0:0:0]"); + + it.Seek(TLogoBlobID(20, 0, 5, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[20:0:10:0:0:0:0]"); + + it.Seek(TLogoBlobID(20, 0, 10, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[20:0:10:0:0:0:0]"); + + it.Seek(TLogoBlobID(20, 0, 15, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[20:0:300:0:0:0:0]"); + + it.Seek(TLogoBlobID(20, 0, 300, 0, 0, 0)); + UNIT_ASSERT(it.GetCurKey().ToString() == "[20:0:300:0:0:0:0]"); + + it.Seek(TLogoBlobID(20, 0, 400, 0, 0, 0)); + UNIT_ASSERT(!it.Valid()); + + it.Seek(TLogoBlobID(25, 0, 0, 0, 0, 0)); + UNIT_ASSERT(!it.Valid()); + + it.SeekToFirst(); + it.Prev(); + UNIT_ASSERT(!it.Valid()); + + it.SeekToLast(); + it.Next(); + UNIT_ASSERT(!it.Valid()); + + it.SeekToFirst(); + TStringStream str1; + while (it.Valid()) { + str1 << it.GetCurKey().ToString(); + it.Next(); + } + UNIT_ASSERT(str1.Str() + == "[10:0:0:0:0:0:0][10:0:10:0:0:0:0][20:0:0:0:0:0:0][20:0:10:0:0:0:0][20:0:300:0:0:0:0]"); + + it.SeekToLast(); + TStringStream str2; + while (it.Valid()) { + str2 << it.GetCurKey().ToString(); + it.Prev(); + } + UNIT_ASSERT(str2.Str() + == "[20:0:300:0:0:0:0][20:0:10:0:0:0:0][20:0:0:0:0:0:0][10:0:10:0:0:0:0][10:0:0:0:0:0:0]"); + } + + Y_UNIT_TEST(TestSstIndexSaveLoad) { + TTestContexts ctxs; + TTrackableVector index(TMemoryConsumer(ctxs.GetVCtx()->SstIndex)); + + auto addRecord = [&index](ui64 tabletId, ui32 step, ui32 blobSize) { + TLogoBlobID id(tabletId, 0, step, 0, blobSize, 0); + index.emplace_back(TKeyLogoBlob(id), TMemRecLogoBlob()); + }; + + addRecord(10, 0, 1); + addRecord(10, 10, 2); + addRecord(20, 0, 3); + addRecord(20, 10, 4); + addRecord(20, 300, 5); + + TLogoBlobSstPtr ptr(new TLogoBlobSst(ctxs.GetVCtx())); + ptr->LoadLinearIndex(index); + + const auto& indexHigh = ptr->IndexHigh; + auto high = indexHigh.begin(); + + using TLogoBlobIdHigh = TRecIndex::TLogoBlobIdHigh; + + UNIT_ASSERT(high->Key == TLogoBlobIdHigh(10, 0, 0, 0)); + UNIT_ASSERT(high->LowRangeEndIndex == 2); + ++high; + UNIT_ASSERT(high->Key == TLogoBlobIdHigh(20, 0, 0, 0)); + UNIT_ASSERT(high->LowRangeEndIndex == 4); + ++high; + UNIT_ASSERT(high->Key == TLogoBlobIdHigh(20, 0, 300, 0)); + UNIT_ASSERT(high->LowRangeEndIndex == 5); + ++high; + UNIT_ASSERT(high == indexHigh.end()); + + const auto& indexLow = ptr->IndexLow; + auto low = indexLow.begin(); + + using TLogoBlobIdLow = TRecIndex::TLogoBlobIdLow; + + UNIT_ASSERT(low->Key == TLogoBlobIdLow(0, 0, 0, 1, 0)); + ++low; + UNIT_ASSERT(low->Key == TLogoBlobIdLow(10, 0, 0, 2, 0)); + ++low; + UNIT_ASSERT(low->Key == TLogoBlobIdLow(0, 0, 0, 3, 0)); + ++low; + UNIT_ASSERT(low->Key == TLogoBlobIdLow(10, 0, 0, 4, 0)); + ++low; + UNIT_ASSERT(low->Key == TLogoBlobIdLow(300, 0, 0, 5, 0)); + ++low; + UNIT_ASSERT(low == indexLow.end()); + + TTrackableVector checkIndex(TMemoryConsumer(ctxs.GetVCtx()->SstIndex)); + ptr->SaveLinearIndex(&checkIndex); + + for (auto i = index.begin(), c = checkIndex.begin(); i != index.end(); ++i, ++c) { + UNIT_ASSERT(i->Key == c->Key); + } + } } // TBlobStorageHullSstIt Y_UNIT_TEST_SUITE(TBlobStorageHullOrderedSstsIt) { diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it_all_ut.h b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it_all_ut.h index 802195a74a36..b48ff0470282 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it_all_ut.h +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it_all_ut.h @@ -19,12 +19,14 @@ namespace NKikimr { ui32 channel = 0, ui32 cookie = 0) { using TRec = TLogoBlobSst::TRec; Y_UNUSED(step); + TTrackableVector linearIndex(TMemoryConsumer(TTestContexts().GetVCtx()->SstIndex)); TLogoBlobSstPtr ptr(new TLogoBlobSst(TTestContexts().GetVCtx())); for (ui32 i = 0; i < recs; i++) { TLogoBlobID id(tabletId, generation, step + i * plus, channel, 0, cookie); TRec rec {TKeyLogoBlob(id), TMemRecLogoBlob()}; - ptr->LoadedIndex.push_back(rec); + linearIndex.push_back(rec); } + ptr->LoadLinearIndex(linearIndex); return ptr; } @@ -42,4 +44,4 @@ namespace NKikimr { } // NBlobStorageHullSstItHelpers -} // NKikimr \ No newline at end of file +} // NKikimr diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstslice.cpp b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstslice.cpp index 6ffe1a49021d..b535b82f7617 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstslice.cpp +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstslice.cpp @@ -20,6 +20,7 @@ namespace NKikimr { TABLEH() {str << NHullComp::TSstRatio::MonHeader();} TABLEH() {str << "Origin";} TABLEH() {str << "CTime";} + TABLEH() {str << "Location";} } } TABLEBODY() { @@ -39,7 +40,7 @@ namespace NKikimr { // total TABLER() { TABLED() {SMALL() {str << "index";}} - TABLED() {SMALL() {str << "total";}} + TABLED() {SMALL() {str << "level";}} TABLED() {SMALL() {str << "lsns";}} TABLED() {SMALL() {str << sum.IdxTotalSize << " / " << sum.InplaceDataTotalSize << " / " << sum.HugeDataTotalSize;}} @@ -48,7 +49,9 @@ namespace NKikimr { << sum.ItemsWithHugeData;}} TABLED() {SMALL() {str << "keys";}} TABLED() {SMALL() {str << "ratio";}} + TABLED() {SMALL() {str << "origin";}} TABLED() {SMALL() {str << "time";}} + TABLED() {SMALL() {str << "chunks";}} } } } diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstvec_it.h b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstvec_it.h index cedeb449bb9c..cd251558019d 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstvec_it.h +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstvec_it.h @@ -127,14 +127,6 @@ namespace NKikimr { return CurSegIt.GetSstPtr(); } - const TRec &operator*() const { - return CurSegIt.operator*(); - } - - const TRec *operator->() const { - return CurSegIt.operator->(); - } - bool operator ==(const TReadIterator &it) const { return CrossSegIt == it.CrossSegIt && CurSegIt == it.CurSegIt; } diff --git a/ydb/core/blobstorage/vdisk/hulldb/test/testhull_index.cpp b/ydb/core/blobstorage/vdisk/hulldb/test/testhull_index.cpp index c358ed23a963..5759e7df8425 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/test/testhull_index.cpp +++ b/ydb/core/blobstorage/vdisk/hulldb/test/testhull_index.cpp @@ -126,12 +126,20 @@ namespace NTest { TIntrusivePtr sst(new TSst(TestCtx->GetVCtx())); sst->Info.CTime = TAppData::TimeProvider->Now(); + TTrackableVector linearIndex(TMemoryConsumer(TestCtx->GetVCtx()->SstIndex)); + while (it != end && totalBytes < requiredBytes) { - sst->LoadedIndex.emplace_back(it->Key, it->MemRec); + linearIndex.emplace_back(it->Key, it->MemRec); totalBytes += sizeof(TKey) + sizeof(TMemRec) + DataSize(it->Key); ++it; } + if constexpr (std::is_same_v) { + sst->LoadLinearIndex(linearIndex); + } else { + sst->LoadedIndex.swap(linearIndex); + } + return sst; } @@ -303,4 +311,3 @@ namespace NTest { } // NTest } // NKikimr - diff --git a/ydb/core/blobstorage/vdisk/hullop/blobstorage_buildslice.h b/ydb/core/blobstorage/vdisk/hullop/blobstorage_buildslice.h index 64538923a514..f1fbc9bdb86c 100644 --- a/ydb/core/blobstorage/vdisk/hullop/blobstorage_buildslice.h +++ b/ydb/core/blobstorage/vdisk/hullop/blobstorage_buildslice.h @@ -276,10 +276,10 @@ namespace NKikimr { TMemIterator c(p.SstPtr.Get()); c.SeekToFirst(); while (c.Valid()) { - TBlobType::EType type = c->MemRec.GetType(); + TBlobType::EType type = c.GetMemRec().GetType(); if (type == TBlobType::HugeBlob || type == TBlobType::ManyHugeBlobs) { TDiskDataExtractor extr; - c->MemRec.GetDiskData(&extr, p.SstPtr->GetOutbound()); + c.GetMemRec().GetDiskData(&extr, p.SstPtr->GetOutbound()); for (const TDiskPart *hb = extr.Begin; hb != extr.End; ++hb) { func(*hb); } @@ -338,10 +338,10 @@ namespace NKikimr { TMemIterator c(seg.Get()); c.SeekToFirst(); while (c.Valid()) { - TBlobType::EType type = c->MemRec.GetType(); + TBlobType::EType type = c.GetMemRec().GetType(); if (type == TBlobType::HugeBlob || type == TBlobType::ManyHugeBlobs) { TDiskDataExtractor extr; - c->MemRec.GetDiskData(&extr, seg->GetOutbound()); + c.GetMemRec().GetDiskData(&extr, seg->GetOutbound()); for (const TDiskPart *hb = extr.Begin; hb != extr.End; ++hb) { func(*hb); } diff --git a/ydb/core/blobstorage/vdisk/hullop/blobstorage_hullload.h b/ydb/core/blobstorage/vdisk/hullop/blobstorage_hullload.h index 998806c7ae80..1f173aeed713 100644 --- a/ydb/core/blobstorage/vdisk/hullop/blobstorage_hullload.h +++ b/ydb/core/blobstorage/vdisk/hullop/blobstorage_hullload.h @@ -21,7 +21,7 @@ namespace NKikimr { struct TSmallBlobChunkIdxExtractor { template TMaybe ExtractChunkIdx(TIterator& it) { - if (it->MemRec.GetType() == TBlobType::DiskBlob) { + if (it.GetMemRec().GetType() == TBlobType::DiskBlob) { TDiskDataExtractor extr; it.GetDiskData(&extr); const TDiskPart& part = extr.SwearOne(); @@ -112,6 +112,7 @@ namespace NKikimr { ui32 RestToReadIndex; ui32 RestToReadOutbound; TAllChunksBuilder Chunks; + TTrackableVector LinearIndex; friend class TActorBootstrapped; @@ -130,14 +131,11 @@ namespace NKikimr { TString ToString() const { TStringStream str; { - typedef typename TLevelSegment::TRec TRec; - const char *b = LevelSegment->LoadedIndex.Data(); - const char *e = b + LevelSegment->LoadedIndex.Size(); - const TRec *begin = (const TRec *)b; - const TRec *end = (const TRec *)e; - str << "LOADER(" << (const void*)this << "): INDEX: "; - for (const TRec *i = begin; i != end; i++) { - str << " " << i->ToString(); + str << "LOADER(" << (const void*)this << "): INDEX:"; + typename TLevelSegment::TMemIterator it(LevelSegment); + it.SeekToFirst(); + while (it.IsValid()) { + str << " " << it.GetKey().ToString(); } } { @@ -160,6 +158,12 @@ namespace NKikimr { void Finish(const TActorContext &ctx) { Y_VERIFY_S(RestToReadIndex == 0 && RestToReadOutbound == 0, VCtx->VDiskLogPrefix); + if constexpr (std::is_same_v) { + LevelSegment->LoadLinearIndex(LinearIndex); + } else { + LevelSegment->LoadedIndex.swap(LinearIndex); + } + // add data chunks to ChunksBuilder typedef typename TLevelSegment::TMemIterator TMemIterator; TSmallBlobChunkIdxExtractor chunkIdxExtr; @@ -193,7 +197,7 @@ namespace NKikimr { Y_VERIFY_DEBUG_S(data && size && RestToReadIndex >= size, VCtx->VDiskLogPrefix); RestToReadIndex -= size; - memcpy(reinterpret_cast(LevelSegment->LoadedIndex.data()) + RestToReadIndex, data, size); + memcpy(reinterpret_cast(LinearIndex.data()) + RestToReadIndex, data, size); } void AppendData(const char *data, size_t size) { @@ -236,7 +240,7 @@ namespace NKikimr { Y_VERIFY_S(placeHolder.MagicNumber == TIdxDiskPlaceHolder::Signature, VCtx->VDiskLogPrefix); RestToReadIndex = placeHolder.Info.IdxTotalSize; RestToReadOutbound = placeHolder.Info.OutboundItems * sizeof(TDiskPart); - LevelSegment->LoadedIndex.resize(placeHolder.Info.Items); + LinearIndex.resize(placeHolder.Info.Items); LevelSegment->LoadedOutbound.resize(placeHolder.Info.OutboundItems); LevelSegment->Info = placeHolder.Info; LevelSegment->AssignedSstId = placeHolder.SstId; @@ -308,6 +312,7 @@ namespace NKikimr { , RestToReadIndex(0) , RestToReadOutbound(0) , Chunks() + , LinearIndex(TMemoryConsumer(vctx->SstIndex)) { const TDiskPart& entry = LevelSegment->GetEntryPoint(); Y_DEBUG_ABORT_UNLESS(!entry.Empty()); diff --git a/ydb/core/blobstorage/vdisk/query/query_statalgo.h b/ydb/core/blobstorage/vdisk/query/query_statalgo.h index a08b5fa1b06f..861080a02a95 100644 --- a/ydb/core/blobstorage/vdisk/query/query_statalgo.h +++ b/ydb/core/blobstorage/vdisk/query/query_statalgo.h @@ -50,7 +50,7 @@ namespace NKikimr { TMemIterator c(p.SstPtr.Get()); c.SeekToFirst(); while (c.Valid()) { - aggr->UpdateLevel(p, c->Key, c->MemRec); + aggr->UpdateLevel(p, c.GetCurKey(), c.GetMemRec()); c.Next(); } it.Next(); @@ -204,14 +204,14 @@ namespace NKikimr { return; } const auto& c = *MemIt; - if (!Constraint || Constraint->Check(c->Key)) { - auto mr = c->MemRec.ToString(HullCtx->IngressCache.Get(), c.GetSstPtr()->GetOutbound()); + if (!Constraint || Constraint->Check(c.GetCurKey())) { + auto mr = c.GetMemRec().ToString(HullCtx->IngressCache.Get(), c.GetSstPtr()->GetOutbound()); auto ing = IngressToString(HullCtx->VCtx->Top.get(), HullCtx->VCtx->ShortSelfVDisk, - c->Key, c->MemRec); + c.GetCurKey(), c.GetMemRec()); str << Prefix << "L: " << p.Level << " ID: " << p.SstPtr->AssignedSstId - << " Key: " << c->Key.ToString() + << " Key: " << c.GetCurKey().ToString() << " Ingress: " << ing << " MemRec: " << mr << "\n"; diff --git a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp index d6bd0f90da1c..a92996f5a084 100644 --- a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp +++ b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp @@ -151,7 +151,7 @@ namespace NKikimr { struct TDonorQueueItem { TVDiskID VDiskId; - TActorId QueueActorId; + TDonorQueueActors QueueActors; ui32 NodeId; ui32 PDiskId; ui32 VSlotId; @@ -176,7 +176,7 @@ namespace NKikimr { TMilestoneQueue MilestoneQueue; TActorId ReplJobActorId; std::list> DonorQueue; - std::deque> Donors; + std::deque> Donors; std::set ConnectedPeerDisks, ConnectedDonorDisks; TEvResumeForce *ResumeForceToken = nullptr; TInstant ReplicationEndTime; @@ -223,23 +223,32 @@ namespace NKikimr { for (const auto& [vdiskId, vdiskActorId] : ReplCtx->VDiskCfg->BaseInfo.DonorDiskIds) { TIntrusivePtr flowRecord(new NBackpressure::TFlowRecord); auto info = MakeIntrusive(ReplCtx->GInfo, vdiskId, vdiskActorId); - const TActorId queueActorId = Register(CreateVDiskBackpressureClient(info, vdiskId, + const TActorId asyncReadQueueActorId = Register(CreateVDiskBackpressureClient(info, vdiskId, NKikimrBlobStorage::EVDiskQueueId::GetAsyncRead, ReplCtx->MonGroup.GetGroup(), ReplCtx->VCtx, - NBackpressure::TQueueClientId(NBackpressure::EQueueClientType::ReplJob, 0), "Donor", + NBackpressure::TQueueClientId(NBackpressure::EQueueClientType::ReplJob, 0), "ReplicationDonor", + ReplCtx->VDiskCfg->ReplInterconnectChannel, vdiskActorId.NodeId() == SelfId().NodeId(), + TDuration::Minutes(1), flowRecord, NMonitoring::TCountableBase::EVisibility::Private)); + + const TActorId fastReadQueueActorId = Register(CreateVDiskBackpressureClient(info, vdiskId, + NKikimrBlobStorage::EVDiskQueueId::GetFastRead, ReplCtx->MonGroup.GetGroup(), ReplCtx->VCtx, + NBackpressure::TQueueClientId(NBackpressure::EQueueClientType::ReplJob, 0), "OnlineReadDonor", ReplCtx->VDiskCfg->ReplInterconnectChannel, vdiskActorId.NodeId() == SelfId().NodeId(), TDuration::Minutes(1), flowRecord, NMonitoring::TCountableBase::EVisibility::Private)); ui32 nodeId, pdiskId, vslotId; std::tie(nodeId, pdiskId, vslotId) = DecomposeVDiskServiceId(vdiskActorId); DonorQueue.emplace_back(TDonorQueueItem{ .VDiskId = vdiskId, - .QueueActorId = queueActorId, + .QueueActors = TDonorQueueActors{ + .AsyncReadQueueActorId = asyncReadQueueActorId, + .FastReadQueueActorId = fastReadQueueActorId + }, .NodeId = nodeId, .PDiskId = pdiskId, .VSlotId = vslotId, .NotReady = false, .NotReadyCount = 0 }); - Donors.emplace_back(vdiskId, queueActorId); + Donors.emplace_back(vdiskId, TDonorQueueActors(asyncReadQueueActorId, fastReadQueueActorId)); } DonorQueue.emplace_back(std::nullopt); // disks from group @@ -359,8 +368,10 @@ namespace NKikimr { } void DropDonor(const TDonorQueueItem& donor) { - Donors.erase(std::find(Donors.begin(), Donors.end(), std::make_pair(donor.VDiskId, donor.QueueActorId))); - Send(donor.QueueActorId, new TEvents::TEvPoison); // kill the queue actor + Donors.erase(std::find(Donors.begin(), Donors.end(), std::make_pair(donor.VDiskId, + TDonorQueueActors(donor.QueueActors.AsyncReadQueueActorId, donor.QueueActors.FastReadQueueActorId)))); + Send(donor.QueueActors.AsyncReadQueueActorId, new TEvents::TEvPoison); // kill the queue actor + Send(donor.QueueActors.FastReadQueueActorId, new TEvents::TEvPoison); // kill the queue actor Send(MakeBlobStorageNodeWardenID(SelfId().NodeId()), new TEvBlobStorage::TEvDropDonor(donor.NodeId, donor.PDiskId, donor.VSlotId, donor.VDiskId)); } @@ -522,7 +533,7 @@ namespace NKikimr { donor->NodeId << ":" << donor->PDiskId << ":" << donor->VSlotId << "}") : "generic")); ReplJobActorId = Register(CreateReplJobActor(ReplCtx, SelfId(), from, QueueActorMapPtr, BlobsToReplicatePtr, UnreplicatedBlobsPtr, donor ? std::make_optional(std::make_pair( - donor->VDiskId, donor->QueueActorId)) : std::nullopt, std::move(UnreplicatedBlobRecords), + donor->VDiskId, donor->QueueActors.AsyncReadQueueActorId)) : std::nullopt, std::move(UnreplicatedBlobRecords), std::move(MilestoneQueue))); } @@ -696,7 +707,8 @@ namespace NKikimr { } for (const auto& donor : DonorQueue) { if (donor) { - Send(donor->QueueActorId, new TEvents::TEvPoison); + Send(donor->QueueActors.AsyncReadQueueActorId, new TEvents::TEvPoison); + Send(donor->QueueActors.FastReadQueueActorId, new TEvents::TEvPoison); } } for (const TActorId& actorId : DonorQueryActors) { diff --git a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.h b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.h index 8a7fb888dfb6..1f15622965ee 100644 --- a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.h +++ b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.h @@ -250,6 +250,15 @@ namespace NKikimr { struct TEvReplCheckProgress : TEventLocal {}; + struct TDonorQueueActors { + TActorId AsyncReadQueueActorId; + TActorId FastReadQueueActorId; + + bool operator==(const TDonorQueueActors &other) const { + return AsyncReadQueueActorId == other.AsyncReadQueueActorId && FastReadQueueActorId == other.FastReadQueueActorId; + } + }; + //////////////////////////////////////////////////////////////////////////// // REPL ACTOR CREATOR //////////////////////////////////////////////////////////////////////////// diff --git a/ydb/core/blobstorage/vdisk/repl/query_donor.h b/ydb/core/blobstorage/vdisk/repl/query_donor.h index 41ba61551d46..3c34246b386d 100644 --- a/ydb/core/blobstorage/vdisk/repl/query_donor.h +++ b/ydb/core/blobstorage/vdisk/repl/query_donor.h @@ -10,12 +10,12 @@ namespace NKikimr { const ui64 Cookie; std::unique_ptr Result; TActorId ParentId; - std::deque> Donors; + std::deque> Donors; TDynBitMap UnresolvedItems; TIntrusivePtr VCtx; public: - TDonorQueryActor(TEvBlobStorage::TEvEnrichNotYet& msg, std::deque> donors, const TIntrusivePtr& vCtx) + TDonorQueryActor(TEvBlobStorage::TEvEnrichNotYet& msg, std::deque> donors, const TIntrusivePtr& vCtx) : Query(msg.Query->Release().Release()) , Sender(msg.Query->Sender) , Cookie(msg.Query->Cookie) @@ -45,7 +45,7 @@ namespace NKikimr { return PassAway(); } - auto [vdiskId, actorId] = Donors.back(); + auto [vdiskId, actors] = Donors.back(); Donors.pop_back(); // we use AsyncRead priority as we are going to use the replication queue for the VDisk; also this doesn't @@ -57,7 +57,13 @@ namespace NKikimr { const auto flags = record.GetShowInternals() ? TEvBlobStorage::TEvVGet::EFlags::ShowInternals : TEvBlobStorage::TEvVGet::EFlags::None; - auto query = fun(vdiskId, TInstant::Max(), NKikimrBlobStorage::EGetHandleClass::AsyncRead, flags, {}, {}, std::nullopt); + const auto handleClass = record.GetHandleClass() == NKikimrBlobStorage::EGetHandleClass::FastRead + ? NKikimrBlobStorage::EGetHandleClass::FastRead + : NKikimrBlobStorage::EGetHandleClass::AsyncRead; + const auto queueActorId = record.GetHandleClass() == NKikimrBlobStorage::EGetHandleClass::FastRead + ? actors.FastReadQueueActorId + : actors.AsyncReadQueueActorId; + auto query = fun(vdiskId, TInstant::Max(), handleClass, flags, {}, {}, std::nullopt); bool action = false; Y_FOR_EACH_BIT(i, UnresolvedItems) { @@ -69,8 +75,8 @@ namespace NKikimr { if (action) { LOG_DEBUG_S(*TlsActivationContext, NKikimrServices::BS_VDISK_GET, SelfId() << " sending " << query->ToString() - << " to " << actorId); - Send(actorId, query.release(), IEventHandle::FlagTrackDelivery); + << " to " << queueActorId); + Send(queueActorId, query.release(), IEventHandle::FlagTrackDelivery); } else { PassAway(); } diff --git a/ydb/core/blobstorage/vdisk/scrub/scrub_actor_sst.cpp b/ydb/core/blobstorage/vdisk/scrub/scrub_actor_sst.cpp index 32ed05d7d0a5..d62b38c07723 100644 --- a/ydb/core/blobstorage/vdisk/scrub/scrub_actor_sst.cpp +++ b/ydb/core/blobstorage/vdisk/scrub/scrub_actor_sst.cpp @@ -31,10 +31,13 @@ namespace NKikimr { } void TScrubCoroImpl::ReadOutAndResilverIndex(TLevelSegmentPtr sst) { + TTrackableVector linearIndex(TMemoryConsumer(VCtx->SstIndex)); + sst->SaveLinearIndex(&linearIndex); + TDiskPart prevPart; bool first = true; ui32 remainOutboundSize = sst->LoadedOutbound.size() * sizeof(TDiskPart); - ui32 remainIndexSize = sst->LoadedIndex.size() * sizeof(TLevelSegment::TRec); + ui32 remainIndexSize = linearIndex.size() * sizeof(TLevelSegment::TRec); for (TDiskPart part : sst->IndexParts) { TString regen = TString::Uninitialized(part.Size); ui32 destLen = regen.size(); @@ -72,7 +75,7 @@ namespace NKikimr { // third step: the index const ui32 isize = Min(remainIndexSize, destLen); remainIndexSize -= isize; - prepend(reinterpret_cast(sst->LoadedIndex.data()) + remainIndexSize, isize); + prepend(reinterpret_cast(linearIndex.data()) + remainIndexSize, isize); // fourth step: sanity check Y_VERIFY_S(!destLen, LogPrefix); diff --git a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp index ccb5968b7fb2..9f31b51c07b9 100644 --- a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp +++ b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp @@ -143,10 +143,20 @@ namespace NKikimr { ReplyError(NKikimrProto::RACE, "group generation mismatch", ev, ctx, TAppData::TimeProvider->Now()); } else if (Config->BaseInfo.DonorMode) { ReplyError(NKikimrProto::ERROR, "disk is in donor mode", ev, ctx, TAppData::TimeProvider->Now()); - } else if (BlockWrites(GInfo->DecommitStatus)) { - ReplyError(NKikimrProto::ERROR, "group is being decommitted", ev, ctx, TAppData::TimeProvider->Now()); } else if (Config->BaseInfo.ReadOnly) { ReplyError(NKikimrProto::ERROR, "disk is in readonly mode", ev, ctx, TAppData::TimeProvider->Now()); + } else if (BlockWrites(GInfo->DecommitStatus)) { + if constexpr (std::is_same_v) { + if (const auto& r = ev->Get()->Record; r.GetHard() && r.GetRecordGeneration() == Max()) { + return true; // part of an assimilation process + } + } + if constexpr (std::is_same_v) { + if (ev->Get()->RewriteBlob) { + return true; // part of an defragmentation process + } + } + ReplyError(NKikimrProto::ERROR, "group is being decommitted", ev, ctx, TAppData::TimeProvider->Now()); } else { return true; } @@ -2476,6 +2486,9 @@ namespace NKikimr { void Handle(TEvents::TEvGone::TPtr &ev, const TActorContext &ctx) { Y_UNUSED(ctx); + if (ev->Sender == ShredActorId) { + ShredActorId = {}; + } ActiveActors.Erase(ev->Sender); } diff --git a/ydb/core/blobstorage/vdisk/skeleton/skeleton_shred.cpp b/ydb/core/blobstorage/vdisk/skeleton/skeleton_shred.cpp index b31e603799c9..cece3117e213 100644 --- a/ydb/core/blobstorage/vdisk/skeleton/skeleton_shred.cpp +++ b/ydb/core/blobstorage/vdisk/skeleton/skeleton_shred.cpp @@ -24,11 +24,12 @@ namespace NKikimr { THashMap ChunkTypes; THashSet ChunksShredded; - THashSet TablesToCompact; + THashSet TablesToCompactLogoBlobs; + THashSet TablesToCompactBlocks; + THashSet TablesToCompactBarriers; ui32 RepliesPending = 0; bool SnapshotProcessed = false; bool DefragCompleted = false; - bool FoundAnyChunks = false; public: TSkeletonShredActor(NPDisk::TEvShredVDisk::TPtr ev, TShredCtxPtr shredCtx) @@ -71,7 +72,6 @@ namespace NKikimr { RepliesPending = 2; SnapshotProcessed = false; DefragCompleted = false; - FoundAnyChunks = false; } void Handle(TEvListChunksResult::TPtr ev) { @@ -84,7 +84,6 @@ namespace NKikimr { for (const TChunkIdx chunkId : set) { if (const auto it = ChunkTypes.find(chunkId); it != ChunkTypes.end()) { it->second = type; - FoundAnyChunks = true; Y_VERIFY_DEBUG_S(ChunksToShred.contains(chunkId), ShredCtx->VCtx->VDiskLogPrefix); } else { Y_VERIFY_DEBUG_S(!ChunksToShred.contains(chunkId), ShredCtx->VCtx->VDiskLogPrefix); @@ -104,15 +103,20 @@ namespace NKikimr { (ActorId, SelfId())); auto& snap = ev->Get()->Snap; - TablesToCompact.clear(); - Scan(snap.HullCtx, snap.LogoBlobsSnap, TablesToCompact); - Scan(snap.HullCtx, snap.BlocksSnap, TablesToCompact); - Scan(snap.HullCtx, snap.BarriersSnap, TablesToCompact); + TablesToCompactLogoBlobs.clear(); + TablesToCompactBlocks.clear(); + TablesToCompactBarriers.clear(); + Scan(snap.HullCtx, snap.LogoBlobsSnap, TablesToCompactLogoBlobs); + Scan(snap.HullCtx, snap.BlocksSnap, TablesToCompactBlocks); + Scan(snap.HullCtx, snap.BarriersSnap, TablesToCompactBarriers); SnapshotProcessed = true; + DropUnknownChunks(); + CheckIfDone(); CheckDefragStage(); STLOG(PRI_DEBUG, BS_SHRED, BSSV09, ShredCtx->VCtx->VDiskLogPrefix << "TEvTakeHullSnapshotResult processed", - (ActorId, SelfId()), (TablesToCompact, TablesToCompact)); + (ActorId, SelfId()), (TablesToCompactLogoBlobs, TablesToCompactLogoBlobs), + (TablesToCompactBlocks, TablesToCompactBlocks), (TablesToCompactBarriers, TablesToCompactBarriers)); } template @@ -128,7 +132,6 @@ namespace NKikimr { } if (const auto it = ChunkTypes.find(p->ChunkIdx); it != ChunkTypes.end()) { it->second = EChunkType::HUGE_CHUNK; - FoundAnyChunks = true; } } } @@ -155,7 +158,6 @@ namespace NKikimr { tablesToCompact.insert(seg.AssignedSstId); STLOG(PRI_DEBUG, BS_SHRED, BSSV13, ShredCtx->VCtx->VDiskLogPrefix << "going to compact SST", (SstId, seg.AssignedSstId), (AllChunks, seg.AllChunks)); - FoundAnyChunks = true; Y_VERIFY_DEBUG_S(ChunksToShred.contains(chunkId), ShredCtx->VCtx->VDiskLogPrefix); } else { Y_VERIFY_DEBUG_S(!ChunksToShred.contains(chunkId), ShredCtx->VCtx->VDiskLogPrefix); @@ -166,12 +168,25 @@ namespace NKikimr { const TDiskPart *outbound = seg.GetOutbound(); typename TLevelSegment::TMemIterator memIt(&seg); for (memIt.SeekToFirst(); memIt.Valid(); memIt.Next()) { - scanHuge(memIt->MemRec, outbound); + scanHuge(memIt.GetMemRec(), outbound); } } } } + void DropUnknownChunks() { + for (auto it = ChunkTypes.begin(); it != ChunkTypes.end(); ) { + if (it->second == EChunkType::UNKNOWN) { + const size_t num = ChunksToShred.erase(it->first); + Y_VERIFY_DEBUG_S(num == 1, ShredCtx->VCtx->VDiskLogPrefix); + ChunksShredded.insert(it->first); + ChunkTypes.erase(it++); + } else { + ++it; + } + } + } + void HandleHullShredDefragResult() { STLOG(PRI_DEBUG, BS_SHRED, BSSV14, ShredCtx->VCtx->VDiskLogPrefix << "EvHullShredDefragResult received", (ActorId, SelfId())); @@ -184,8 +199,15 @@ namespace NKikimr { return; } - if (!TablesToCompact.empty()) { - Send(ShredCtx->SkeletonId, TEvCompactVDisk::Create(EHullDbType::LogoBlobs, std::move(TablesToCompact))); + if (!TablesToCompactLogoBlobs.empty()) { + Send(ShredCtx->SkeletonId, TEvCompactVDisk::Create(EHullDbType::LogoBlobs, + std::exchange(TablesToCompactLogoBlobs, {}))); + } else if (!TablesToCompactBlocks.empty()) { + Send(ShredCtx->SkeletonId, TEvCompactVDisk::Create(EHullDbType::Blocks, + std::exchange(TablesToCompactBlocks, {}))); + } else if (!TablesToCompactBarriers.empty()) { + Send(ShredCtx->SkeletonId, TEvCompactVDisk::Create(EHullDbType::Barriers, + std::exchange(TablesToCompactBarriers, {}))); } else { TActivationContext::Schedule(TDuration::Minutes(1), new IEventHandle(TEvents::TSystem::Wakeup, 0, SelfId(), TActorId(), nullptr, 0)); @@ -195,8 +217,7 @@ namespace NKikimr { void Handle(TEvCompactVDiskResult::TPtr /*ev*/) { STLOG(PRI_DEBUG, BS_SHRED, BSSV11, ShredCtx->VCtx->VDiskLogPrefix << "TEvCompactVDiskResult received", (ActorId, SelfId())); - TActivationContext::Schedule(TDuration::Minutes(1), new IEventHandle(TEvents::TSystem::Wakeup, 0, SelfId(), - TActorId(), nullptr, 0)); + CheckDefragStage(); } void Handle(TEvNotifyChunksDeleted::TPtr ev) { diff --git a/ydb/core/blobstorage/vdisk/skeleton/skeleton_vmultiput_actor.cpp b/ydb/core/blobstorage/vdisk/skeleton/skeleton_vmultiput_actor.cpp index 4b8c4e951482..edd240f52d3f 100644 --- a/ydb/core/blobstorage/vdisk/skeleton/skeleton_vmultiput_actor.cpp +++ b/ydb/core/blobstorage/vdisk/skeleton/skeleton_vmultiput_actor.cpp @@ -82,10 +82,12 @@ namespace NKikimr { } TInstant now = TAppData::TimeProvider->Now(); + auto handleClass = Event->Get()->Record.GetHandleClass(); + const NVDiskMon::TLtcHistoPtr &histoPtr = VCtx->Histograms.GetHistogram(handleClass); const ui64 bufferSizeBytes = Event->Get()->GetBufferBytes(); auto vMultiPutResult = std::make_unique(NKikimrProto::OK, vdisk, cookie, now, Event->Get()->GetCachedByteSize(), &vMultiPutRecord, SkeletonFrontIDPtr, MultiPutResMsgsPtr, - nullptr, bufferSizeBytes, IncarnationGuid, TString()); + histoPtr, bufferSizeBytes, IncarnationGuid, TString()); for (ui64 idx = 0; idx < Items.size(); ++idx) { TItem &result = Items[idx]; diff --git a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogkeeper_state.cpp b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogkeeper_state.cpp index b4892f8355e9..df1c7ea8bbc4 100644 --- a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogkeeper_state.cpp +++ b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogkeeper_state.cpp @@ -87,8 +87,8 @@ namespace NKikimr { ui32 len = TSerializeRoutines::SetLogoBlob(VCtx->Top->GType, buffer, lsn, - it->Key.LogoBlobID(), - it->MemRec.GetIngress()); + it.GetCurKey().LogoBlobID(), + it.GetMemRec().GetIngress()); Y_DEBUG_ABORT_UNLESS(len <= sizeof(buffer)); SyncLogPtr->PutOne(reinterpret_cast(buffer), len); it.Next(); diff --git a/ydb/core/cms/console/configs_dispatcher.cpp b/ydb/core/cms/console/configs_dispatcher.cpp index 6377b34180db..2b542cfdf9d0 100644 --- a/ydb/core/cms/console/configs_dispatcher.cpp +++ b/ydb/core/cms/console/configs_dispatcher.cpp @@ -68,6 +68,7 @@ const THashSet DYNAMIC_KINDS({ (ui32)NKikimrConsole::TConfigItem::MetadataCacheConfigItem, (ui32)NKikimrConsole::TConfigItem::MemoryControllerConfigItem, (ui32)NKikimrConsole::TConfigItem::HealthCheckConfigItem, + (ui32)NKikimrConsole::TConfigItem::WorkloadManagerConfigItem, }); const THashSet NON_YAML_KINDS({ diff --git a/ydb/core/cms/console/console__drop_yaml_config.cpp b/ydb/core/cms/console/console__drop_yaml_config.cpp index 5ef86f0d45f5..177e945ea391 100644 --- a/ydb/core/cms/console/console__drop_yaml_config.cpp +++ b/ydb/core/cms/console/console__drop_yaml_config.cpp @@ -32,11 +32,15 @@ class TConfigsManager::TTxDropYamlConfig : public TTransactionBaseClusterName != cluster) { - ythrow yexception() << "ClusterName mismatch"; + ythrow yexception() << "ClusterName mismatch" + << " expected " << Self->ClusterName + << " but got " << cluster; } if (Version != Self->YamlVersion) { - ythrow yexception() << "Version mismatch"; + ythrow yexception() << "Version mismatch" + << " expected " << Self->YamlVersion + << " but got " << Version; } } catch (const yexception& ex) { Error = true; diff --git a/ydb/core/cms/console/console__replace_yaml_config.cpp b/ydb/core/cms/console/console__replace_yaml_config.cpp index a05210d836da..78ac3937cbbd 100644 --- a/ydb/core/cms/console/console__replace_yaml_config.cpp +++ b/ydb/core/cms/console/console__replace_yaml_config.cpp @@ -30,6 +30,7 @@ class TConfigsManager::TTxReplaceYamlConfigBase , AllowUnknownFields(ev->Get()->Record.GetRequest().allow_unknown_fields()) , DryRun(ev->Get()->Record.GetRequest().dry_run()) , IngressDatabase(ev->Get()->Record.HasIngressDatabase() ? TMaybe{ev->Get()->Record.GetIngressDatabase()} : TMaybe{}) + , SkipAuditLog(ev->Get()->Record.GetSkipAuditLog() ? true : false) { } @@ -90,6 +91,7 @@ class TConfigsManager::TTxReplaceYamlConfigBase TSimpleSharedPtr UnknownFieldsCollector = nullptr; TMaybe IngressDatabase; bool WarnDatabaseBypass = false; + bool SkipAuditLog = false; }; class TConfigsManager::TTxReplaceMainYamlConfig @@ -177,14 +179,16 @@ class TConfigsManager::TTxReplaceMainYamlConfig ctx.Send(Response.Release()); if (!Error && Modify && !DryRun) { - AuditLogReplaceConfigTransaction( - /* peer = */ Peer, - /* userSID = */ UserToken.GetUserSID(), - /* sanitizedToken = */ UserToken.GetSanitizedToken(), - /* oldConfig = */ Self->MainYamlConfig, - /* newConfig = */ Config, - /* reason = */ {}, - /* success = */ true); + if (!SkipAuditLog) { + AuditLogReplaceConfigTransaction( + /* peer = */ Peer, + /* userSID = */ UserToken.GetUserSID(), + /* sanitizedToken = */ UserToken.GetSanitizedToken(), + /* oldConfig = */ Self->MainYamlConfig, + /* newConfig = */ Config, + /* reason = */ {}, + /* success = */ true); + } Self->YamlVersion = Version + 1; Self->MainYamlConfig = UpdatedMainConfig; @@ -195,14 +199,16 @@ class TConfigsManager::TTxReplaceMainYamlConfig auto resp = MakeHolder(Self->MainYamlConfig, Self->DatabaseYamlConfigs); ctx.Send(Self->ConfigsProvider, resp.Release()); } else if (Error && !DryRun) { - AuditLogReplaceConfigTransaction( - /* peer = */ Peer, - /* userSID = */ UserToken.GetUserSID(), - /* sanitizedToken = */ UserToken.GetSanitizedToken(), - /* oldConfig = */ Self->MainYamlConfig, - /* newConfig = */ Config, - /* reason = */ ErrorReason, - /* success = */ false); + if (!SkipAuditLog) { + AuditLogReplaceConfigTransaction( + /* peer = */ Peer, + /* userSID = */ UserToken.GetUserSID(), + /* sanitizedToken = */ UserToken.GetSanitizedToken(), + /* oldConfig = */ Self->MainYamlConfig, + /* newConfig = */ Config, + /* reason = */ ErrorReason, + /* success = */ false); + } } Self->TxProcessor->TxCompleted(this, ctx); @@ -360,15 +366,17 @@ class TConfigsManager::TTxReplaceDatabaseYamlConfig } if (!Error && Modify && !DryRun) { - AuditLogReplaceDatabaseConfigTransaction( - /* peer = */ Peer, - /* userSID = */ UserToken.GetUserSID(), - /* sanitizedToken = */ UserToken.GetSanitizedToken(), - /* database = */ TargetDatabase, - /* oldConfig = */ oldConfig, - /* newConfig = */ Config, - /* reason = */ {}, - /* success = */ true); + if (!SkipAuditLog) { + AuditLogReplaceDatabaseConfigTransaction( + /* peer = */ Peer, + /* userSID = */ UserToken.GetUserSID(), + /* sanitizedToken = */ UserToken.GetSanitizedToken(), + /* database = */ TargetDatabase, + /* oldConfig = */ oldConfig, + /* newConfig = */ Config, + /* reason = */ {}, + /* success = */ true); + } Self->DatabaseYamlConfigs[TargetDatabase] = TDatabaseYamlConfig { .Config = UpdatedDatabaseConfig, @@ -383,15 +391,17 @@ class TConfigsManager::TTxReplaceDatabaseYamlConfig ctx.Send(Self->ConfigsProvider, resp.Release()); } else if (Error && !DryRun) { - AuditLogReplaceDatabaseConfigTransaction( - /* peer = */ Peer, - /* userSID = */ UserToken.GetUserSID(), - /* sanitizedToken = */ UserToken.GetSanitizedToken(), - /* database = */ TargetDatabase, - /* oldConfig = */ oldConfig, - /* newConfig = */ Config, - /* reason = */ ErrorReason, - /* success = */ false); + if (!SkipAuditLog) { + AuditLogReplaceDatabaseConfigTransaction( + /* peer = */ Peer, + /* userSID = */ UserToken.GetUserSID(), + /* sanitizedToken = */ UserToken.GetSanitizedToken(), + /* database = */ TargetDatabase, + /* oldConfig = */ oldConfig, + /* newConfig = */ Config, + /* reason = */ ErrorReason, + /* success = */ false); + } } Self->TxProcessor->TxCompleted(this, ctx); diff --git a/ydb/core/cms/console/console_configs_manager.cpp b/ydb/core/cms/console/console_configs_manager.cpp index 77fa7fb019a9..e561520785b0 100644 --- a/ydb/core/cms/console/console_configs_manager.cpp +++ b/ydb/core/cms/console/console_configs_manager.cpp @@ -79,11 +79,15 @@ void TConfigsManager::ValidateMainConfig(TUpdateConfigOpContext& opCtx) { auto resolved = NYamlConfig::ResolveAll(tree); if (ClusterName != opCtx.Cluster) { - ythrow yexception() << "ClusterName mismatch"; + ythrow yexception() << "ClusterName mismatch" + << " expected " << ClusterName + << " but got " << opCtx.Cluster; } if (opCtx.Version != YamlVersion) { - ythrow yexception() << "Version mismatch"; + ythrow yexception() << "Version mismatch" + << " expected " << YamlVersion + << " but got " << opCtx.Version; } TSimpleSharedPtr unknownFieldsCollector = new NYamlConfig::TBasicUnknownFieldsCollector; @@ -1073,11 +1077,15 @@ void TConfigsManager::Handle(TEvConsole::TEvAddVolatileConfigRequest::TPtr &ev, } if (ClusterName != clusterName) { - ythrow yexception() << "ClusterName mismatch"; + ythrow yexception() << "ClusterName mismatch" + << " expected " << ClusterName + << " but got " << clusterName; } if (YamlVersion != version) { - ythrow yexception() << "Version mismatch"; + ythrow yexception() << "Version mismatch" + << " expected " << YamlVersion + << " but got " << version; } VolatileYamlConfigs.try_emplace(id, cfg); @@ -1108,11 +1116,15 @@ void TConfigsManager::Handle(TEvConsole::TEvRemoveVolatileConfigRequest::TPtr &e try { if (!rec.force()) { if (ClusterName != rec.identity().cluster()) { - ythrow yexception() << "ClusterName mismatch"; + ythrow yexception() << "ClusterName mismatch" + << " expected " << ClusterName + << " but got " << rec.identity().cluster(); } if (YamlVersion != rec.identity().version()) { - ythrow yexception() << "Version mismatch"; + ythrow yexception() << "Version mismatch" + << " expected " << YamlVersion + << " but got " << rec.identity().version(); } } diff --git a/ydb/core/cms/console/console_handshake.cpp b/ydb/core/cms/console/console_handshake.cpp index 7fac6fb9601d..b5b59ea530fc 100644 --- a/ydb/core/cms/console/console_handshake.cpp +++ b/ydb/core/cms/console/console_handshake.cpp @@ -30,6 +30,7 @@ class TConfigsManager::TConsoleCommitActor : public TActorBootstrapped(); request->Record.SetBypassAuth(true); + request->Record.SetSkipAuditLog(true); request->Record.MutableRequest()->set_config(MainYamlConfig); request->Record.MutableRequest()->set_allow_unknown_fields(true); Send(consoleId, request.release()); diff --git a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp index ad58b78ab02b..aec59e9b4f0f 100644 --- a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp +++ b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp @@ -145,6 +145,7 @@ #include #include #include +#include #include #include #include @@ -1114,6 +1115,19 @@ void TSharedCacheInitializer::InitializeServices( TActorSetupCmd(actor, TMailboxType::ReadAsFilled, appData->UserPoolId)); } +// TSharedMetadaCacheInitializer +TSharedMetadaCacheInitializer::TSharedMetadaCacheInitializer(const TKikimrRunConfig& runConfig) + : IKikimrServicesInitializer(runConfig) +{} + +void TSharedMetadaCacheInitializer::InitializeServices( NActors::TActorSystemSetup *setup, const NKikimr::TAppData *appData) { + if (appData->FeatureFlags.GetEnableSharedMetadataCache()) { + auto* actor = NKikimr::NOlap::NDataAccessorControl::TNodeActor::CreateActor(); + setup->LocalServices.emplace_back(NKikimr::NOlap::NDataAccessorControl::TNodeActor::MakeActorId(NodeId), + TActorSetupCmd(actor, TMailboxType::HTSwap, appData->UserPoolId)); + } +} + // TBlobCacheInitializer TBlobCacheInitializer::TBlobCacheInitializer(const TKikimrRunConfig& runConfig) diff --git a/ydb/core/driver_lib/run/kikimr_services_initializers.h b/ydb/core/driver_lib/run/kikimr_services_initializers.h index cadb077a875e..9eb12c177899 100644 --- a/ydb/core/driver_lib/run/kikimr_services_initializers.h +++ b/ydb/core/driver_lib/run/kikimr_services_initializers.h @@ -95,6 +95,13 @@ class TSharedCacheInitializer : public IKikimrServicesInitializer { void InitializeServices(NActors::TActorSystemSetup *setup, const NKikimr::TAppData *appData) override; }; +class TSharedMetadaCacheInitializer : public IKikimrServicesInitializer { +public: +TSharedMetadaCacheInitializer(const TKikimrRunConfig& runConfig); + + void InitializeServices(NActors::TActorSystemSetup *setup, const NKikimr::TAppData *appData) override; +}; + class TBlobCacheInitializer : public IKikimrServicesInitializer { public: TBlobCacheInitializer(const TKikimrRunConfig& runConfig); diff --git a/ydb/core/driver_lib/run/run.cpp b/ydb/core/driver_lib/run/run.cpp index 9b28f65eab71..c78d9dd52482 100644 --- a/ydb/core/driver_lib/run/run.cpp +++ b/ydb/core/driver_lib/run/run.cpp @@ -55,13 +55,14 @@ #include #include #include -#include -#include -#include #include -#include #include +#include +#include +#include #include +#include +#include #include #include @@ -1247,6 +1248,10 @@ void TKikimrRunner::InitializeAppData(const TKikimrRunConfig& runConfig) AppData->HealthCheckConfig = runConfig.AppConfig.GetHealthCheckConfig(); } + if (runConfig.AppConfig.HasWorkloadManagerConfig()) { + AppData->WorkloadManagerConfig = runConfig.AppConfig.GetWorkloadManagerConfig(); + } + // setup resource profiles AppData->ResourceProfiles = new TResourceProfiles; if (runConfig.AppConfig.GetBootstrapConfig().ResourceProfilesSize()) @@ -1559,7 +1564,7 @@ TIntrusivePtr TKikimrRunner::CreateServiceInitializers } if (serviceMask.EnableBlobCache) { sil->AddServiceInitializer(new TBlobCacheInitializer(runConfig)); - } + } if (serviceMask.EnableLogger) { sil->AddServiceInitializer(new TLoggerInitializer(runConfig, LogSettings, LogBackend)); } @@ -1658,6 +1663,8 @@ TIntrusivePtr TKikimrRunner::CreateServiceInitializers sil->AddServiceInitializer(new TMemProfMonitorInitializer(runConfig, ProcessMemoryInfoProvider)); + sil->AddServiceInitializer(new TSharedMetadaCacheInitializer(runConfig)); + #if defined(ENABLE_MEMORY_TRACKING) if (serviceMask.EnableMemoryTracker) { sil->AddServiceInitializer(new TMemoryTrackerInitializer(runConfig)); diff --git a/ydb/core/driver_lib/version/version.cpp b/ydb/core/driver_lib/version/version.cpp index adc22dfeeca6..f88d1d814e72 100644 --- a/ydb/core/driver_lib/version/version.cpp +++ b/ydb/core/driver_lib/version/version.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include "version.h" @@ -730,6 +731,10 @@ TString TCompatibilityInfo::PrintHumanReadable(const NKikimrConfig::TCurrentComp } str << "\n"; + if (NResource::Has("internal_breakpad_about")) { + str << " HasInternalBreakpad: true" << Endl; + } + // print common rule if (current->HasVersion() && current->GetVersion().HasYear() && current->GetVersion().HasMajor()) { const auto& version = current->GetVersion(); diff --git a/ydb/core/driver_lib/version/ya.make b/ydb/core/driver_lib/version/ya.make index c2161f1ee4b9..2fbac636c072 100644 --- a/ydb/core/driver_lib/version/ya.make +++ b/ydb/core/driver_lib/version/ya.make @@ -10,6 +10,7 @@ PEERDIR( ydb/library/actors/interconnect library/cpp/monlib/service/pages library/cpp/svnversion + library/cpp/resource ydb/core/protos ydb/core/viewer/json ) diff --git a/ydb/core/external_sources/external_data_source.cpp b/ydb/core/external_sources/external_data_source.cpp index f2ce2fbab49e..46c58a11081c 100644 --- a/ydb/core/external_sources/external_data_source.cpp +++ b/ydb/core/external_sources/external_data_source.cpp @@ -37,7 +37,7 @@ struct TExternalDataSource : public IExternalSource { } bool DataSourceMustHaveDataBaseName(const TProtoStringType& sourceType) const { - return IsIn({"Greenplum", "PostgreSQL", "MySQL", "MsSQLServer", "ClickHouse"}, sourceType); + return IsIn({"Greenplum", "PostgreSQL", "MySQL", "MsSQLServer", "ClickHouse", "MongoDB"}, sourceType); } virtual void ValidateExternalDataSource(const TString& externalDataSourceDescription) const override { diff --git a/ydb/core/external_sources/external_source_builder.cpp b/ydb/core/external_sources/external_source_builder.cpp new file mode 100644 index 000000000000..e773f052cc58 --- /dev/null +++ b/ydb/core/external_sources/external_source_builder.cpp @@ -0,0 +1,205 @@ +#include "external_source_builder.h" +#include "validation_functions.h" + +#include +#include + +namespace NKikimr::NExternalSource { +namespace { + +class TValidatedExternalDataSource final : public IExternalSource { +public: + TValidatedExternalDataSource( + const TString& name, + const std::vector& authMethods, + const std::unordered_map& availableProperties, + const std::vector& hostnamePatterns) + : Name_(name) + , AuthMethodsForCheck_(authMethods) + , AvailableProperties_(availableProperties) + , HostnamePatterns_(hostnamePatterns) + { + + } + + virtual TString Pack(const NKikimrExternalSources::TSchema&, + const NKikimrExternalSources::TGeneral&) const override { + ythrow TExternalSourceException() << "Internal error. Only external table supports pack operation"; + } + + virtual TString GetName() const override { + return Name_; + } + + virtual bool HasExternalTable() const override { + return false; + } + + virtual TVector GetAuthMethods() const override { + TVector result; + + for (auto a : AuthMethodsForCheck_) { + result.push_back(a.Auth); + } + + return result; + } + + TVector GetAuthMethods(const TString& externalDataSourceDescription) const { + NKikimrSchemeOp::TExternalDataSourceDescription proto; + + if (!proto.ParseFromString(externalDataSourceDescription)) { + ythrow TExternalSourceException() + << "Internal error. " + << "Couldn't parse protobuf with external data source description"; + } + + TVector result; + + for (auto a : AuthMethodsForCheck_) { + if (a.UseCondition(proto.GetProperties().GetProperties())) { + result.push_back(a.Auth); + } + } + + return result; + } + + virtual TMap> GetParameters(const TString&) const override { + ythrow TExternalSourceException() << "Internal error. Only external table supports parameters"; + } + + virtual void ValidateExternalDataSource(const TString& externalDataSourceDescription) const override { + NKikimrSchemeOp::TExternalDataSourceDescription proto; + + if (!proto.ParseFromString(externalDataSourceDescription)) { + ythrow TExternalSourceException() + << "Internal error. " + << "Couldn't parse protobuf with external data source description"; + } + + auto properties = proto.GetProperties().GetProperties(); + std::unordered_set validatedProperties; + + for (const auto& [key, value] : properties) { + auto p = AvailableProperties_.find(key); + + if (AvailableProperties_.end() == p) { + throw TExternalSourceException() << "Unsupported property: " << key; + } + + // validate property value + if (p->second.ApplyCondition(properties)) { + p->second.Validator(key, value); + } + + validatedProperties.emplace(key); + } + + // validate properties that has been left + for (const auto& [property, validator] : AvailableProperties_) { + if (validatedProperties.contains(property)) { + continue; + } + + if (validator.ApplyCondition(properties)) { + validator.Validator(property, ""); + } + } + + ValidateHostname(HostnamePatterns_, proto.GetLocation()); + } + + virtual NThreading::TFuture> LoadDynamicMetadata(std::shared_ptr meta) override { + return NThreading::MakeFuture(std::move(meta)); + } + + virtual bool CanLoadDynamicMetadata() const override { + return false; + } + +private: + const TString Name_; + const std::vector AuthMethodsForCheck_; + const std::unordered_map AvailableProperties_; + const std::vector HostnamePatterns_; +}; + +} // unnamed + +TExternalSourceBuilder::TExternalSourceBuilder(const TString& name) + : Name_(name) +{ +} + +TExternalSourceBuilder& TExternalSourceBuilder::Auth(const TVector& authMethods, TCondition condition) { + for (auto a : authMethods) { + AuthMethodsForCheck_.push_back(TExternalSourceBuilder::TAuthHolder{a, condition}); + } + + return *this; +} + +TExternalSourceBuilder& TExternalSourceBuilder::Property(TString name, TValidator validator, TCondition condition) { + AvailableProperties_.emplace(name, TExternalSourceBuilder::TConditionalValidator{validator, condition}); + return *this; +} + +TExternalSourceBuilder& TExternalSourceBuilder::Properties(const TSet& availableProperties, TValidator validator, TCondition condition) { + for (auto p : availableProperties) { + Property(p, validator, condition); + } + + return *this; +} + +TExternalSourceBuilder& TExternalSourceBuilder::HostnamePatterns(const std::vector& patterns) { + HostnamePatterns_.insert( + HostnamePatterns_.end(), patterns.begin(), patterns.end()); + return *this; +} + +IExternalSource::TPtr TExternalSourceBuilder::Build() { + return MakeIntrusive( + std::move(Name_), std::move(AuthMethodsForCheck_), std::move(AvailableProperties_), std::move(HostnamePatterns_)); +} + +TCondition GetHasSettingCondition(const TString& property, const TString& value) { + return [property, value](const ::google::protobuf::Map& properties) -> bool { + auto it = properties.find(property); + return properties.end() != it && value == it->second; + }; +} + +TValidator GetRequiredValidator() { + return [](const TString& property, const TString& value){ + if (!value.empty()) { + return; + } + + throw TExternalSourceException() << "required property: " << property << " is not set"; + }; +} + +TValidator GetIsInListValidator(const std::unordered_set& values, bool required) { + auto joinedValues = JoinSeq(", ", values); + + return [values, required, joinedValues](const TString& property, const TString& value){ + if (value.empty() && required) { + throw TExternalSourceException() << " required property: " << property << " is not set"; + } + + if (value.empty()) { + return; + } + + if (!values.contains(value)) { + throw TExternalSourceException() + << " property: " << property + << " has wrong value: " << value + << " allowed values: " << joinedValues; + } + }; +} + +} // NKikimr::NExternalSource diff --git a/ydb/core/external_sources/external_source_builder.h b/ydb/core/external_sources/external_source_builder.h new file mode 100644 index 000000000000..2da604086e69 --- /dev/null +++ b/ydb/core/external_sources/external_source_builder.h @@ -0,0 +1,118 @@ +#pragma once + +#include "external_source.h" + +#include +#include + +namespace NKikimr::NExternalSource { + +typedef std::function TValidator; +typedef std::function&)> TCondition; + +/// +/// Builder to create an external data source with validations +/// +class TExternalSourceBuilder { +public: + struct TAuthHolder { + TString Auth; + + // When auth has to be used + TCondition UseCondition; + }; + + struct TConditionalValidator { + TValidator Validator; + + // When validator has to be applied + TCondition ApplyCondition; + }; + +public: + explicit TExternalSourceBuilder(const TString& name); + + ~TExternalSourceBuilder() = default; + + /// + /// Add auth methods which are returned from the "source" only if a condition is true. + /// A condition is applied to source's ddl in @sa IExternalSource::GetAuthMethods + /// call. + /// + TExternalSourceBuilder& Auth(const TVector& authMethods, TCondition condition); + + TExternalSourceBuilder& Auth(const TVector& authMethods) { + return Auth(authMethods, [](const ::google::protobuf::Map&){ + return true; + }); + } + + /// + /// Add property which can be in a "source". + /// + /// @param name name of a property + /// @param validator validator which is applied to a property from a source's ddl + /// in @sa IExternalSource::ValidateExternalDataSource call + /// @param condition condition that defines to use validator or not, if condition returns true + /// for source's ddl then validator is applied; otherwise, validator is skiped; + /// condition is executed in @sa IExternalSource::ValidateExternalDataSource call + /// before validator + /// + TExternalSourceBuilder& Property(const TString name, TValidator validator, TCondition condition); + + TExternalSourceBuilder& Properties(const TSet& properties, TValidator validator, TCondition condition); + + TExternalSourceBuilder& HostnamePatterns(const std::vector& patterns); + + /// + /// Create external data source + /// + IExternalSource::TPtr Build(); + + TExternalSourceBuilder& Property(const TString name, TValidator validator) { + return Property(name, validator, [](const ::google::protobuf::Map&){ + return true; + }); + } + + TExternalSourceBuilder& Property(const TString name) { + return Property(name, [](const TString&, const TString&){}); + } + + TExternalSourceBuilder& Properties(const TSet& properties, TValidator validator) { + return Properties(properties, validator, [](const ::google::protobuf::Map&){ + return true; + }); + } + + TExternalSourceBuilder& Properties(const TSet& properties) { + return Properties(properties, [](const TString&, const TString&){}); + } + + private: + TString Name_; + std::vector AuthMethodsForCheck_; + std::unordered_map AvailableProperties_; + std::vector HostnamePatterns_; +}; + +/// +/// Create a condition that returns "true" if a source's ddl has +/// property "p" with value equals to "v" +/// +TCondition GetHasSettingCondition(const TString& p, const TString& v); + +/// +/// Create a validator which check that source's ddl has a property with non empty value +/// +TValidator GetRequiredValidator(); + +/// +/// Create a validator which check that source's ddl has a property with a value from list +/// +/// @param values list of allowed values +/// @param required allow property without value +/// +TValidator GetIsInListValidator(const std::unordered_set& values, bool required); + +} // NKikimr::NExternalSource diff --git a/ydb/core/external_sources/external_source_builder_ut.cpp b/ydb/core/external_sources/external_source_builder_ut.cpp new file mode 100644 index 000000000000..0242e6f8273e --- /dev/null +++ b/ydb/core/external_sources/external_source_builder_ut.cpp @@ -0,0 +1,207 @@ +#include "external_source_builder.h" + +#include +#include +#include +#include + +namespace NKikimr { + +namespace { + +class TTestFixture : public NUnitTest::TBaseFixture { +public: + TTestFixture() + : Builder("Test") + , Props(*Proto.MutableProperties()->MutableProperties()) + { + } + +public: + void SetUp(NUnitTest::TTestContext& context) override { + NUnitTest::TBaseFixture::SetUp(context); + } + +protected: + NExternalSource::TExternalSourceBuilder Builder; + NKikimrSchemeOp::TExternalDataSourceDescription Proto; + ::google::protobuf::Map& Props; +}; + +} + +Y_UNIT_TEST_SUITE(ExternalSourceBuilderTest) { + + Y_UNIT_TEST_F(ValidateName, TTestFixture) { + auto source = Builder.Build(); + UNIT_ASSERT_VALUES_EQUAL(source->GetName(), "Test"); + } + + // Test returned auth methods when conditions are not set + Y_UNIT_TEST_F(ValidateAuthWithoutCondition, TTestFixture) { + auto source = Builder + .Auth({"auth1", "auth2"}) + .Build(); + + const auto authMethods = source->GetAuthMethods(); + + UNIT_ASSERT_VALUES_EQUAL(authMethods.size(), 2); + UNIT_ASSERT_VALUES_EQUAL(authMethods[0], "auth1"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[1], "auth2"); + } + + // Test returned auth methods when conditions are set + Y_UNIT_TEST_F(ValidateAuthWithCondition, TTestFixture) { + auto source = Builder + .Auth( + {"auth1", "auth2"}, + // check that ddl has "property1" equals to "value" + NExternalSource::GetHasSettingCondition("property1", "value") + ) + .Auth( + {"auth3", "auth4"}, + // check that ddl has "property2" equals to "value" + NExternalSource::GetHasSettingCondition("property2", "value") + ) + .Build(); + + // ddl without any value + auto authMethods = source->GetAuthMethods(); + + UNIT_ASSERT_VALUES_EQUAL(authMethods.size(), 4); + UNIT_ASSERT_VALUES_EQUAL(authMethods[0], "auth1"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[1], "auth2"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[2], "auth3"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[3], "auth4"); + } + + // Test validation when ddl has property which is not supported by source + // i.e. source does not contain this property in a list of available properties + Y_UNIT_TEST_F(ValidateUnsupportedField, TTestFixture) { + // source has property "field" + auto source = Builder + .Property("field") + .Build(); + + // ddl with "field1" + Props["field1"] = "value"; + + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "Unsupported property: field1" + ); + + // ddl with "field" + Props.clear(); + Props["field"] = "value"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } + + // Test validation for non required property + Y_UNIT_TEST_F(ValidateNonRequiredField, TTestFixture) { + auto source = Builder + .Property("field") + .Build(); + + // ddl without "field" + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + + // ddl with "field" + Props["field"] = "value"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } + + // Test validation for required property + Y_UNIT_TEST_F(ValidateRequiredField, TTestFixture) { + auto source = Builder + .Property("field", NExternalSource::GetRequiredValidator()) + .Build(); + + // ddl without "field" + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "required property: field is not set" + ); + + // ddl with "field" + Props["field"] = "value"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } + + // Test validation for non required property with allowed list of values + Y_UNIT_TEST_F(ValidateNonRequiredFieldValues, TTestFixture) { + auto source = Builder + .Property("field", NExternalSource::GetIsInListValidator({"v1", "v2", "v3"}, false)) + .Build(); + + // ddl without "field" + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource("")); + } + + // Test validation for required property with allowed list of values + Y_UNIT_TEST_F(ValidateRequiredFieldValues, TTestFixture) { + auto source = Builder + .Property("field", NExternalSource::GetIsInListValidator({"v1", "v2", "v3"}, true)) + .Build(); + + // ddl without "field" + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "required property: field is not set" + ); + + // ddl with "field" equals to value not in allowed list + Props["field"] = "value"; + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "property: field has wrong value: value allowed values: v3, v2, v1" + ); + + // ddl with "field" equals to "v1" + Props["field"] = "v1"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + + // ddl with "field" equals to "v2" + Props["field"] = "v2"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + + // ddl with "field" equals to "v3" + Props["field"] = "v3"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } + + // Test validation for required property with condition + Y_UNIT_TEST_F(ValidateRequiredFieldOnCondition, TTestFixture) { + auto source = Builder + .Property("field1") + .Property( + "field", + NExternalSource::GetRequiredValidator(), + // apply validator if ddl has "field1" equals to "v" + NExternalSource::GetHasSettingCondition("field1", "v") + ) + .Build(); + + // ddl without "field1" + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + + // ddl with "field1" but without "field" + Props["field1"] = "v"; + + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "required property: field is not set" + ); + + // ddl with "field1" and "field" + Props["field"] = "q"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } +} + +} // NKikimr diff --git a/ydb/core/external_sources/external_source_factory.cpp b/ydb/core/external_sources/external_source_factory.cpp index 72814eda6b10..787b6470c034 100644 --- a/ydb/core/external_sources/external_source_factory.cpp +++ b/ydb/core/external_sources/external_source_factory.cpp @@ -1,6 +1,8 @@ #include "external_source_factory.h" #include "object_storage.h" #include "external_data_source.h" +#include "iceberg_fields.h" +#include "external_source_builder.h" #include #include @@ -8,7 +10,6 @@ #include #include - namespace NKikimr::NExternalSource { namespace { @@ -39,6 +40,50 @@ struct TExternalSourceFactory : public IExternalSourceFactory { } + +IExternalSource::TPtr BuildIcebergSource(const std::vector& hostnamePatternsRegEx) { + using namespace NKikimr::NExternalSource::NIceberg; + + return TExternalSourceBuilder(TString{NYql::GenericProviderName}) + // Basic, Token and SA Auth are available only if warehouse type is set to s3 + .Auth( + {"BASIC", "TOKEN", "SERVICE_ACCOUNT"}, + GetHasSettingCondition(WAREHOUSE_TYPE, VALUE_S3) + ) + // DataBase is a required field + .Property(WAREHOUSE_DB, GetRequiredValidator()) + // Tls is an optional field + .Property(WAREHOUSE_TLS) + // Warehouse type is a required field and can be equal only to "s3" + .Property( + WAREHOUSE_TYPE, + GetIsInListValidator({VALUE_S3}, true) + ) + // If a warehouse type is equal to "s3", fields "s3_endpoint", "s3_region" and "s3_uri" are required + .Properties( + { + WAREHOUSE_S3_ENDPOINT, + WAREHOUSE_S3_REGION, + WAREHOUSE_S3_URI + }, + GetRequiredValidator(), + GetHasSettingCondition(WAREHOUSE_TYPE, VALUE_S3) + ) + // Catalog type is a required field and can be equal only to "hive" or "hadoop" + .Property( + CATALOG_TYPE, + GetIsInListValidator({VALUE_HIVE, VALUE_HADOOP}, true) + ) + // If catalog type is equal to "hive" the field "hive_uri" is required + .Property( + CATALOG_HIVE_URI, + GetRequiredValidator(), + GetHasSettingCondition(CATALOG_TYPE,VALUE_HIVE) + ) + .HostnamePatterns(hostnamePatternsRegEx) + .Build(); +} + IExternalSourceFactory::TPtr CreateExternalSourceFactory(const std::vector& hostnamePatterns, NActors::TActorSystem* actorSystem, size_t pathsLimit, @@ -91,6 +136,22 @@ IExternalSourceFactory::TPtr CreateExternalSourceFactory(const std::vector +#include +#include +#include +#include + +namespace NKikimr { + +namespace { + +class TTestFixture : public NUnitTest::TBaseFixture { +public: + TTestFixture() + : Props(*Proto.MutableProperties()->MutableProperties()) + { + using namespace NKikimr::NExternalSource::NIceberg; + + auto type = ToString(NYql::EDatabaseType::Iceberg); + auto factory = NExternalSource::CreateExternalSourceFactory( + {}, nullptr, 50000, nullptr, false, false, {type}); + + Source = factory->GetOrCreate(type); + + Props[WAREHOUSE_TYPE] = VALUE_S3; + Props[WAREHOUSE_DB] = "db"; + Props[WAREHOUSE_S3_REGION] = "region"; + Props[WAREHOUSE_S3_ENDPOINT] = "endpoint"; + Props[WAREHOUSE_S3_URI] = "uri"; + } + +public: + void SetUp(NUnitTest::TTestContext& context) override { + NUnitTest::TBaseFixture::SetUp(context); + } + +protected: + NExternalSource::IExternalSource::TPtr Source; + NKikimrSchemeOp::TExternalDataSourceDescription Proto; + ::google::protobuf::Map& Props; +}; + +} // unnamed + +Y_UNIT_TEST_SUITE(IcebergDdlTest) { + + // Test ddl for an iceberg table in s3 storage with the hive catalog + Y_UNIT_TEST_F(HiveCatalogWithS3Test, TTestFixture) { + using namespace NKikimr::NExternalSource::NIceberg; + + Props[CATALOG_TYPE] = VALUE_HIVE; + Props[CATALOG_HIVE_URI] = "hive_uri"; + + UNIT_ASSERT_NO_EXCEPTION(Source->ValidateExternalDataSource(Proto.SerializeAsString())); + + auto authMethods = Source->GetAuthMethods(); + + UNIT_ASSERT_VALUES_EQUAL(authMethods.size(), 3); + UNIT_ASSERT_VALUES_EQUAL(authMethods[0], "BASIC"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[1], "TOKEN"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[2], "SERVICE_ACCOUNT"); + } + + // Test ddl for an iceberg table in s3 storage with the hadoop catalog + Y_UNIT_TEST_F(HadoopCatalogWithS3Test, TTestFixture) { + using namespace NKikimr::NExternalSource::NIceberg; + + Props[CATALOG_TYPE] = VALUE_HADOOP; + + UNIT_ASSERT_NO_EXCEPTION(Source->ValidateExternalDataSource(Proto.SerializeAsString())); + + auto authMethods = Source->GetAuthMethods(); + + UNIT_ASSERT_VALUES_EQUAL(authMethods.size(), 3); + UNIT_ASSERT_VALUES_EQUAL(authMethods[0], "BASIC"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[1], "TOKEN"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[2], "SERVICE_ACCOUNT"); + } + +} + +} // NKikimr diff --git a/ydb/core/external_sources/iceberg_fields.h b/ydb/core/external_sources/iceberg_fields.h new file mode 100644 index 000000000000..5a00f8e607f5 --- /dev/null +++ b/ydb/core/external_sources/iceberg_fields.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +namespace NKikimr::NExternalSource::NIceberg { + +// Fields that belongs to a warehouse +constexpr char WAREHOUSE_TYPE[] = "warehouse_type"; +constexpr char WAREHOUSE_S3_ENDPOINT[] = "warehouse_s3_endpoint"; +constexpr char WAREHOUSE_S3_URI[] = "warehouse_s3_uri"; +constexpr char WAREHOUSE_S3_REGION[] = "warehouse_s3_region"; +constexpr char WAREHOUSE_TLS[] = "use_tls"; +constexpr char WAREHOUSE_DB[] = "database_name"; + +// Fields that belongs to a catalog +constexpr char CATALOG_TYPE[] = "catalog_type"; +constexpr char CATALOG_HIVE_URI[] = "catalog_hive_uri"; + +// Some values +constexpr char VALUE_S3[] = "s3"; +constexpr char VALUE_HIVE[] = "hive"; +constexpr char VALUE_HADOOP[] = "hadoop"; + +// List of fields which is pass to a connector +constexpr std::array FieldsToConnector = { + WAREHOUSE_TYPE, + WAREHOUSE_S3_ENDPOINT, + WAREHOUSE_S3_REGION, + WAREHOUSE_S3_URI, + CATALOG_TYPE, + CATALOG_HIVE_URI +}; + +} // NKikimr::NExternalSource::NIceberg diff --git a/ydb/core/external_sources/object_storage/inference/arrow_fetcher.cpp b/ydb/core/external_sources/object_storage/inference/arrow_fetcher.cpp index e642007bcd4e..2684e2bebc80 100644 --- a/ydb/core/external_sources/object_storage/inference/arrow_fetcher.cpp +++ b/ydb/core/external_sources/object_storage/inference/arrow_fetcher.cpp @@ -217,7 +217,7 @@ class TArrowFileFetcher : public NActors::TActorBootstrapped decompressedData << decompressedChunk; } return std::move(decompressedData); - } catch (const yexception& error) { + } catch (const std::exception& error) { auto errorEv = MakeError( request.Path, NFq::TIssuesIds::INTERNAL_ERROR, diff --git a/ydb/core/external_sources/object_storage/inference/arrow_inferencinator.cpp b/ydb/core/external_sources/object_storage/inference/arrow_inferencinator.cpp index ab162b61552e..dadee4572214 100644 --- a/ydb/core/external_sources/object_storage/inference/arrow_inferencinator.cpp +++ b/ydb/core/external_sources/object_storage/inference/arrow_inferencinator.cpp @@ -169,8 +169,12 @@ using ArrowFields = std::vector; std::variant InferCsvTypes(std::shared_ptr file, std::shared_ptr config) { int64_t fileSize; + constexpr auto errorHeader = "couldn't open csv/tsv file, check format and compression parameters: "sv; if (auto sizeStatus = file->GetSize().Value(&fileSize); !sizeStatus.ok()) { - return TStringBuilder{} << "coudn't get file size: " << sizeStatus.ToString(); + return TStringBuilder{} << errorHeader << "coudn't get file size: " << sizeStatus.ToString(); + } + if (fileSize <= 0 || fileSize > INT32_MAX) { + return TStringBuilder{} << errorHeader << "empty file"; } std::shared_ptr reader; @@ -184,48 +188,52 @@ std::variant InferCsvTypes(std::shared_ptr table; auto tableRes = reader->Read().Value(&table); if (!tableRes.ok()) { - return TStringBuilder{} << "couldn't parse csv/tsv file, check format and compression parameters: " << tableRes.ToString(); + return TStringBuilder{} << errorHeader << tableRes.ToString(); } return table->fields(); } std::variant InferParquetTypes(std::shared_ptr file) { + constexpr auto errorHeader = "couldn't open parquet file, check format parameters: "sv; parquet::arrow::FileReaderBuilder builder; builder.properties(parquet::ArrowReaderProperties(false)); auto openStatus = builder.Open(std::move(file)); if (!openStatus.ok()) { - return TStringBuilder{} << "couldn't open parquet file, check format parameters: " << openStatus.ToString(); + return TStringBuilder{} << errorHeader << openStatus.ToString(); } std::unique_ptr reader; auto readerStatus = builder.Build(&reader); if (!readerStatus.ok()) { - return TStringBuilder{} << "couldn't read parquet file, check format parameters: " << readerStatus.ToString(); + return TStringBuilder{} << errorHeader << readerStatus.ToString(); } std::shared_ptr schema; auto schemaRes = reader->GetSchema(&schema); if (!schemaRes.ok()) { - return TStringBuilder{} << "couldn't parse parquet file, check format parameters: " << schemaRes.ToString(); + return TStringBuilder{} << errorHeader << schemaRes.ToString(); } return schema->fields(); } std::variant InferJsonTypes(std::shared_ptr file, std::shared_ptr config) { + constexpr auto errorHeader = "couldn't open json file, check format and compression parameters: "sv; int64_t fileSize; if (auto sizeStatus = file->GetSize().Value(&fileSize); !sizeStatus.ok()) { - return TStringBuilder{} << "coudn't get file size: " << sizeStatus.ToString(); + return TStringBuilder{} << errorHeader << "coudn't get file size: " << sizeStatus.ToString(); + } + if (fileSize <= 0 || fileSize > INT32_MAX) { + return TStringBuilder{} << errorHeader << "empty file"; } - std::shared_ptr reader; auto readerStatus = arrow::json::TableReader::Make( arrow::default_memory_pool(), @@ -235,14 +243,14 @@ std::variant InferJsonTypes(std::shared_ptr table; auto tableRes = reader->Read().Value(&table); if (!tableRes.ok()) { - return TString{TStringBuilder{} << "couldn't parse json file, check format and compression parameters: " << tableRes.ToString()}; + return TString{TStringBuilder{} << errorHeader << tableRes.ToString()}; } return table->fields(); diff --git a/ydb/core/external_sources/object_storage/inference/ut/arrow_inference_ut.cpp b/ydb/core/external_sources/object_storage/inference/ut/arrow_inference_ut.cpp index a196d3c26cbe..677494705856 100644 --- a/ydb/core/external_sources/object_storage/inference/ut/arrow_inference_ut.cpp +++ b/ydb/core/external_sources/object_storage/inference/ut/arrow_inference_ut.cpp @@ -93,6 +93,7 @@ TEST_F(ArrowInferenceTest, csv_simple) { auto response = event->CastAsLocal(); ASSERT_NE(response, nullptr); + ASSERT_TRUE(response->Status.IsSuccess()); auto& fields = response->Fields; ASSERT_TRUE(fields[0].type().optional_type().item().has_type_id()); ASSERT_EQ(fields[0].type().optional_type().item().type_id(), Ydb::Type::INT64); @@ -143,4 +144,125 @@ TEST_F(ArrowInferenceTest, tsv_simple) { ASSERT_EQ(fields[2].name(), "C"); } +TEST_F(ArrowInferenceTest, tsv_empty) { + TString s3Data = + "this part should not matter because it will be omitted as a partial row,,"; + + Gateway->AddDefaultResponse([=, this](TString url, NYql::IHTTPGateway::THeaders, TString data) -> NYql::IHTTPGateway::TResult { + EXPECT_EQ(url, BaseUrl + Path); + EXPECT_EQ(data, ""); + + NYql::IHTTPGateway::TResult result(NYql::IHTTPGateway::TContent(s3Data, 200));; + return result; + }); + + auto inferencinatorId = RegisterInferencinator("tsv_with_names"); + ActorSystem.WrapInActorContext(EdgeActorId, [this, inferencinatorId] { + NActors::TActivationContext::AsActorContext().Send(inferencinatorId, new TEvInferFileSchema(TString{Path}, 0)); + }); + + std::unique_ptr event = ActorSystem.WaitForEdgeActorEvent({EdgeActorId}); + auto response = event->CastAsLocal(); + ASSERT_NE(response, nullptr); + ASSERT_FALSE(response->Status.IsSuccess()); + Cerr << response->Status.GetIssues().ToOneLineString() << Endl; +} + +TEST_F(ArrowInferenceTest, broken_json) { + TString s3Data = "A,B,C\n"; + + Gateway->AddDefaultResponse([=, this](TString url, NYql::IHTTPGateway::THeaders, TString data) -> NYql::IHTTPGateway::TResult { + EXPECT_EQ(url, BaseUrl + Path); + EXPECT_EQ(data, ""); + + NYql::IHTTPGateway::TResult result(NYql::IHTTPGateway::TContent(s3Data, 200));; + return result; + }); + + auto inferencinatorId = RegisterInferencinator("json_each_row"); + ActorSystem.WrapInActorContext(EdgeActorId, [this, inferencinatorId] { + NActors::TActivationContext::AsActorContext().Send(inferencinatorId, new TEvInferFileSchema(TString{Path}, 0)); + }); + + std::unique_ptr event = ActorSystem.WaitForEdgeActorEvent({EdgeActorId}); + auto response = event->CastAsLocal(); + ASSERT_NE(response, nullptr); + ASSERT_FALSE(response->Status.IsSuccess()); + Cerr << response->Status.GetIssues().ToOneLineString() << Endl; + // ASSERT_EQ(...) +} + +TEST_F(ArrowInferenceTest, empty_json_each_row) { + TString s3Data = ""; + + Gateway->AddDefaultResponse([=, this](TString url, NYql::IHTTPGateway::THeaders, TString data) -> NYql::IHTTPGateway::TResult { + EXPECT_EQ(url, BaseUrl + Path); + EXPECT_EQ(data, ""); + + NYql::IHTTPGateway::TResult result(NYql::IHTTPGateway::TContent(s3Data, 200));; + return result; + }); + + auto inferencinatorId = RegisterInferencinator("json_each_row"); + ActorSystem.WrapInActorContext(EdgeActorId, [this, inferencinatorId] { + NActors::TActivationContext::AsActorContext().Send(inferencinatorId, new TEvInferFileSchema(TString{Path}, 0)); + }); + + std::unique_ptr event = ActorSystem.WaitForEdgeActorEvent({EdgeActorId}); + auto response = event->CastAsLocal(); + ASSERT_NE(response, nullptr); + ASSERT_FALSE(response->Status.IsSuccess()); + Cerr << response->Status.GetIssues().ToOneLineString() << Endl; + // ASSERT_EQ(...) +} + +TEST_F(ArrowInferenceTest, empty_json_list) { + TString s3Data = ""; + + Gateway->AddDefaultResponse([=, this](TString url, NYql::IHTTPGateway::THeaders, TString data) -> NYql::IHTTPGateway::TResult { + EXPECT_EQ(url, BaseUrl + Path); + EXPECT_EQ(data, ""); + + NYql::IHTTPGateway::TResult result(NYql::IHTTPGateway::TContent(s3Data, 200));; + return result; + }); + + auto inferencinatorId = RegisterInferencinator("json_list"); + ActorSystem.WrapInActorContext(EdgeActorId, [this, inferencinatorId] { + NActors::TActivationContext::AsActorContext().Send(inferencinatorId, new TEvInferFileSchema(TString{Path}, 0)); + }); + + std::unique_ptr event = ActorSystem.WaitForEdgeActorEvent({EdgeActorId}); + auto response = event->CastAsLocal(); + ASSERT_NE(response, nullptr); + ASSERT_FALSE(response->Status.IsSuccess()); + Cerr << response->Status.GetIssues().ToOneLineString() << Endl; + // ASSERT_EQ(...) +} + +TEST_F(ArrowInferenceTest, broken_json_list) { + TString s3Data = "\nfoobar\n"; + + Gateway->AddDefaultResponse([=, this](TString url, NYql::IHTTPGateway::THeaders, TString data) -> NYql::IHTTPGateway::TResult { + EXPECT_EQ(url, BaseUrl + Path); + EXPECT_EQ(data, ""); + + NYql::IHTTPGateway::TResult result(NYql::IHTTPGateway::TContent(s3Data, 200));; + return result; + }); + + auto inferencinatorId = RegisterInferencinator("json_list"); + ActorSystem.WrapInActorContext(EdgeActorId, [this, inferencinatorId] { + NActors::TActivationContext::AsActorContext().Send(inferencinatorId, new TEvInferFileSchema(TString{Path}, 0)); + }); + + std::unique_ptr event = ActorSystem.WaitForEdgeActorEvent({EdgeActorId}); + auto response = event->CastAsLocal(); + ASSERT_NE(response, nullptr); + ASSERT_FALSE(response->Status.IsSuccess()); + Cerr << response->Status.GetIssues().ToOneLineString() << Endl; + // ASSERT_EQ(...) +} +// TODO: broken_compression, unrecognized_compression, broken_csv, broken_tsv (is there?), mock errors inside arrow::BufferBuilder,... + } // namespace diff --git a/ydb/core/external_sources/ut/ya.make b/ydb/core/external_sources/ut/ya.make index b21cd87b1144..8503f40abd48 100644 --- a/ydb/core/external_sources/ut/ya.make +++ b/ydb/core/external_sources/ut/ya.make @@ -6,8 +6,10 @@ PEERDIR( ) SRCS( - object_storage_ut.cpp external_data_source_ut.cpp + external_source_builder_ut.cpp + iceberg_ddl_ut.cpp + object_storage_ut.cpp ) END() diff --git a/ydb/core/external_sources/ya.make b/ydb/core/external_sources/ya.make index 9a93b7bb484e..3a764cd08f8c 100644 --- a/ydb/core/external_sources/ya.make +++ b/ydb/core/external_sources/ya.make @@ -2,6 +2,7 @@ LIBRARY() SRCS( external_data_source.cpp + external_source_builder.cpp external_source_factory.cpp object_storage.cpp validation_functions.cpp diff --git a/ydb/core/formats/arrow/accessor/abstract/accessor.cpp b/ydb/core/formats/arrow/accessor/abstract/accessor.cpp index 82e7bafd87ee..152bae082d2e 100644 --- a/ydb/core/formats/arrow/accessor/abstract/accessor.cpp +++ b/ydb/core/formats/arrow/accessor/abstract/accessor.cpp @@ -131,12 +131,12 @@ std::shared_ptr IChunkedArray::GetChunkedArray(const TColum const ui32 start = context.GetStartIndex().value_or(0); const ui32 count = context.GetRecordsCount().value_or(GetRecordsCount() - start); auto slice = ISlice(start, count); - if (context.GetFilter()) { - return ApplyFilter(*context.GetFilter(), nullptr)->GetChunkedArrayTrivial(); + if (context.GetFilter() && !context.GetFilter()->IsTotalAllowFilter()) { + return slice->ApplyFilter(context.GetFilter()->Slice(start, count), slice)->GetChunkedArrayTrivial(); } else { return slice->GetChunkedArrayTrivial(); } - } else if (context.GetFilter()) { + } else if (context.GetFilter() && !context.GetFilter()->IsTotalAllowFilter()) { return ApplyFilter(*context.GetFilter(), nullptr)->GetChunkedArrayTrivial(); } else { return GetChunkedArrayTrivial(); diff --git a/ydb/core/formats/arrow/accessor/abstract/common.cpp b/ydb/core/formats/arrow/accessor/abstract/common.cpp index 7b27b6898566..04fc014e1ee0 100644 --- a/ydb/core/formats/arrow/accessor/abstract/common.cpp +++ b/ydb/core/formats/arrow/accessor/abstract/common.cpp @@ -15,20 +15,12 @@ TColumnConstructionContext& TColumnConstructionContext::SetFilter(const std::sha std::optional TColumnConstructionContext::Slice(const ui32 offset, const ui32 count) const { std::optional result; - if (StartIndex && RecordsCount) { - const ui32 start = std::max(offset, *StartIndex); - const ui32 finish = std::min(offset + count, *StartIndex + *RecordsCount); - if (finish <= start) { - result = std::nullopt; - } else { - result = TColumnConstructionContext().SetStartIndex(start - offset).SetRecordsCount(finish - start, count); - } - } else if (StartIndex && !RecordsCount) { - result = TColumnConstructionContext().SetStartIndex(std::max(offset, *StartIndex) - offset); - } else if (!StartIndex && RecordsCount) { - result = TColumnConstructionContext().SetRecordsCount(std::min(count, *RecordsCount), count); + const ui32 start = std::max(offset, StartIndex.value_or(0)); + const ui32 finish = std::min(offset + count, StartIndex.value_or(0) + RecordsCount.value_or(offset + count)); + if (finish <= start) { + result = std::nullopt; } else { - result = TColumnConstructionContext(); + result = TColumnConstructionContext().SetStartIndex(start - offset).SetRecordsCount(finish - start, count); } if (result && Filter) { result->SetFilter(std::make_shared(Filter->Slice(offset, count))); diff --git a/ydb/core/formats/arrow/accessor/composite/accessor.cpp b/ydb/core/formats/arrow/accessor/composite/accessor.cpp index e5f445254947..eef73d9970d2 100644 --- a/ydb/core/formats/arrow/accessor/composite/accessor.cpp +++ b/ydb/core/formats/arrow/accessor/composite/accessor.cpp @@ -119,6 +119,7 @@ std::shared_ptr TCompositeChunkedArray::GetChunkedArray(con if (chunks.size()) { break; } else { + pos += i->GetRecordsCount(); continue; } } diff --git a/ydb/core/formats/arrow/accessor/composite_serial/accessor.cpp b/ydb/core/formats/arrow/accessor/composite_serial/accessor.cpp index bf388d2ef731..bcebf9136f2a 100644 --- a/ydb/core/formats/arrow/accessor/composite_serial/accessor.cpp +++ b/ydb/core/formats/arrow/accessor/composite_serial/accessor.cpp @@ -2,6 +2,7 @@ #include +#include #include namespace NKikimr::NArrow::NAccessor { @@ -11,6 +12,10 @@ IChunkedArray::TLocalChunkedArrayAddress TDeserializeChunkedArray::DoGetLocalChu if (PredefinedArray) { return TLocalChunkedArrayAddress(PredefinedArray, 0, 0); } + if (Counter.Inc() > 1) { + AFL_WARN(NKikimrServices::ARROW_HELPER)("event", "many_deserializations")("counter", Counter.Val())("size", Data.size())( + "buffer", DataBuffer.size()); + } if (!!Data) { return TLocalChunkedArrayAddress(Loader->ApplyVerified(Data, GetRecordsCount()), 0, 0); } else { diff --git a/ydb/core/formats/arrow/accessor/composite_serial/accessor.h b/ydb/core/formats/arrow/accessor/composite_serial/accessor.h index 8353a238603d..81c9828fb4a3 100644 --- a/ydb/core/formats/arrow/accessor/composite_serial/accessor.h +++ b/ydb/core/formats/arrow/accessor/composite_serial/accessor.h @@ -13,6 +13,7 @@ class TDeserializeChunkedArray: public IChunkedArray { const TString Data; const TStringBuf DataBuffer; const bool ForLazyInitialization; + mutable TAtomicCounter Counter = 0; protected: virtual std::shared_ptr DoISlice(const ui32 offset, const ui32 count) const override { diff --git a/ydb/core/formats/arrow/accessor/sub_columns/accessor.cpp b/ydb/core/formats/arrow/accessor/sub_columns/accessor.cpp index b46ae64aaa98..f33a04785e61 100644 --- a/ydb/core/formats/arrow/accessor/sub_columns/accessor.cpp +++ b/ydb/core/formats/arrow/accessor/sub_columns/accessor.cpp @@ -1,5 +1,6 @@ #include "accessor.h" #include "direct_builder.h" +#include "signals.h" #include #include @@ -67,18 +68,26 @@ TString TSubColumnsArray::SerializeToString(const TChunkConstructionData& extern proto.SetOtherStatsSize(0); } ui32 columnIdx = 0; + TMonotonic pred = TMonotonic::Now(); for (auto&& i : ColumnsData.GetRecords()->GetColumns()) { TChunkConstructionData cData(GetRecordsCount(), nullptr, arrow::utf8(), externalInfo.GetDefaultSerializer()); blobRanges.emplace_back(ColumnsData.GetStats().GetAccessorConstructor(columnIdx).SerializeToString(i, cData)); auto* cInfo = proto.AddKeyColumns(); cInfo->SetSize(blobRanges.back().size()); + TMonotonic next = TMonotonic::Now(); + NSubColumns::TSignals::GetColumnSignals().OnBlobSize(ColumnsData.GetStats().GetColumnSize(columnIdx), blobRanges.back().size(), next - pred); + pred = next; ++columnIdx; } if (OthersData.GetRecords()->GetRecordsCount()) { + TMonotonic pred = TMonotonic::Now(); for (auto&& i : OthersData.GetRecords()->GetColumns()) { TChunkConstructionData cData(i->GetRecordsCount(), nullptr, i->GetDataType(), externalInfo.GetDefaultSerializer()); blobRanges.emplace_back(NPlain::TConstructor().SerializeToString(i, cData)); + TMonotonic next = TMonotonic::Now(); + NSubColumns::TSignals::GetOtherSignals().OnBlobSize(i->GetRawSizeVerified(), blobRanges.back().size(), next - pred); + pred = next; auto* cInfo = proto.AddOtherColumns(); cInfo->SetSize(blobRanges.back().size()); } diff --git a/ydb/core/formats/arrow/accessor/sub_columns/accessor.h b/ydb/core/formats/arrow/accessor/sub_columns/accessor.h index 74430d04ed5b..2fd9f60329f3 100644 --- a/ydb/core/formats/arrow/accessor/sub_columns/accessor.h +++ b/ydb/core/formats/arrow/accessor/sub_columns/accessor.h @@ -101,7 +101,8 @@ class TSubColumnsArray: public IChunkedArray { TSubColumnsArray(NSubColumns::TColumnsData&& columns, NSubColumns::TOthersData&& others, const std::shared_ptr& type, const ui32 recordsCount, const NSubColumns::TSettings& settings); - static TConclusion> Make(const std::shared_ptr& sourceArray, const NSubColumns::TSettings& settings); + static TConclusion> Make( + const std::shared_ptr& sourceArray, const NSubColumns::TSettings& settings); TSubColumnsArray(const std::shared_ptr& type, const ui32 recordsCount, const NSubColumns::TSettings& settings); diff --git a/ydb/core/formats/arrow/accessor/sub_columns/columns_storage.h b/ydb/core/formats/arrow/accessor/sub_columns/columns_storage.h index a3f3e85e813c..9c7f4ac609e3 100644 --- a/ydb/core/formats/arrow/accessor/sub_columns/columns_storage.h +++ b/ydb/core/formats/arrow/accessor/sub_columns/columns_storage.h @@ -29,7 +29,7 @@ class TColumnsData { NJson::TJsonValue DebugJson() const { NJson::TJsonValue result = NJson::JSON_MAP; result.InsertValue("stats", Stats.DebugJson()); - result.InsertValue("records", Records->DebugJson(true)); + result.InsertValue("records", Records->DebugJson()); return result; } diff --git a/ydb/core/formats/arrow/accessor/sub_columns/signals.cpp b/ydb/core/formats/arrow/accessor/sub_columns/signals.cpp new file mode 100644 index 000000000000..b8e60c8c8793 --- /dev/null +++ b/ydb/core/formats/arrow/accessor/sub_columns/signals.cpp @@ -0,0 +1,5 @@ +#include "signals.h" + +namespace NKikimr::NArrow::NAccessor ::NSubColumns{ + +} // namespace NKikimr::NArrow::NAccessor diff --git a/ydb/core/formats/arrow/accessor/sub_columns/signals.h b/ydb/core/formats/arrow/accessor/sub_columns/signals.h new file mode 100644 index 000000000000..51c27b05af3d --- /dev/null +++ b/ydb/core/formats/arrow/accessor/sub_columns/signals.h @@ -0,0 +1,73 @@ +#pragma once +#include + +#include + +namespace NKikimr::NArrow::NAccessor::NSubColumns { + +class TCategorySignals: public NColumnShard::TCommonCountersOwner { +private: + using TBase = NColumnShard::TCommonCountersOwner; + + NMonitoring::THistogramPtr HistogramRawDataSizeBytes; + NMonitoring::THistogramPtr HistogramRawDataSizeCount; + NMonitoring::THistogramPtr HistogramRawDataSizeDuration; + + NMonitoring::THistogramPtr HistogramBlobDataSizeBytes; + NMonitoring::THistogramPtr HistogramBlobDataSizeCount; + NMonitoring::THistogramPtr HistogramBlobDataSizeDuration; + +public: + TCategorySignals(NColumnShard::TCommonCountersOwner& owner, const TString& categoryName) + : TBase(owner, "category", categoryName) + , HistogramRawDataSizeBytes(TBase::GetHistogram("RawData/BySize/Bytes", NMonitoring::ExponentialHistogram(15, 2, 100))) + , HistogramRawDataSizeCount(TBase::GetHistogram("RawData/BySize/Count", NMonitoring::ExponentialHistogram(15, 2, 100))) + , HistogramRawDataSizeDuration(TBase::GetHistogram("RawData/BySize/Duration/Us", NMonitoring::ExponentialHistogram(15, 2, 100))) + , HistogramBlobDataSizeBytes(TBase::GetHistogram("BlobData/BySize/Bytes", NMonitoring::ExponentialHistogram(15, 2, 100))) + , HistogramBlobDataSizeCount(TBase::GetHistogram("BlobData/BySize/Count", NMonitoring::ExponentialHistogram(15, 2, 100))) + , HistogramBlobDataSizeDuration(TBase::GetHistogram("BlobData/BySize/Duration/Us", NMonitoring::ExponentialHistogram(15, 2, 100))) { + } + + void OnBlobSize(const i64 rawDataSize, const i64 blobDataSize, const TDuration d) const { + HistogramBlobDataSizeBytes->Collect(blobDataSize, blobDataSize); + HistogramBlobDataSizeCount->Collect(blobDataSize); + HistogramBlobDataSizeDuration->Collect(blobDataSize, d.MicroSeconds()); + + HistogramRawDataSizeBytes->Collect(rawDataSize, rawDataSize); + HistogramRawDataSizeCount->Collect(rawDataSize); + HistogramRawDataSizeDuration->Collect(rawDataSize, d.MicroSeconds()); + } +}; + +class TSignalsImpl: public NColumnShard::TCommonCountersOwner { +private: + using TBase = NColumnShard::TCommonCountersOwner; + + TCategorySignals ColumnSignals; + TCategorySignals OtherSignals; + +public: + TSignalsImpl() + : TBase("sub_columns") + , ColumnSignals(*this, "columns") + , OtherSignals(*this, "other") { + } + + const TCategorySignals& GetColumnSignals() const { + return ColumnSignals; + } + const TCategorySignals& GetOtherSignals() const { + return OtherSignals; + } +}; + +class TSignals { +public: + static const TCategorySignals& GetColumnSignals() { + return Singleton()->GetColumnSignals(); + } + static const TCategorySignals& GetOtherSignals() { + return Singleton()->GetOtherSignals(); + } +}; +} // namespace NKikimr::NArrow::NAccessor::NSubColumns diff --git a/ydb/core/formats/arrow/accessor/sub_columns/ya.make b/ydb/core/formats/arrow/accessor/sub_columns/ya.make index 0ce5e597be3d..13a710f8f96a 100644 --- a/ydb/core/formats/arrow/accessor/sub_columns/ya.make +++ b/ydb/core/formats/arrow/accessor/sub_columns/ya.make @@ -7,6 +7,7 @@ PEERDIR( ydb/core/formats/arrow/accessor/composite_serial ydb/core/formats/arrow/save_load ydb/core/formats/arrow/common + ydb/library/signals ydb/library/formats/arrow ydb/library/formats/arrow/protos yql/essentials/types/binary_json @@ -26,6 +27,7 @@ SRCS( others_storage.cpp columns_storage.cpp iterators.cpp + signals.cpp ) YQL_LAST_ABI_VERSION() diff --git a/ydb/core/formats/arrow/arrow_filter.cpp b/ydb/core/formats/arrow/arrow_filter.cpp index 885899884165..7be4883bea85 100644 --- a/ydb/core/formats/arrow/arrow_filter.cpp +++ b/ydb/core/formats/arrow/arrow_filter.cpp @@ -16,127 +16,6 @@ namespace NKikimr::NArrow { #define Y_VERIFY_OK(status) Y_ABORT_UNLESS(status.ok(), "%s", status.ToString().c_str()) -namespace { -enum class ECompareResult : i8 { - LESS = -1, - BORDER = 0, - GREATER = 1 -}; - -template -inline auto GetValue(const std::shared_ptr& array, int pos) { - return array->GetView(pos); -} - -template -inline void UpdateCompare(const T& value, const T& border, ECompareResult& res) { - if (res == ECompareResult::BORDER) { - if constexpr (std::is_same_v) { - size_t minSize = (value.size() < border.size()) ? value.size() : border.size(); - int cmp = memcmp(value.data(), border.data(), minSize); - if (cmp < 0) { - res = ECompareResult::LESS; - } else if (cmp > 0) { - res = ECompareResult::GREATER; - } else { - UpdateCompare(value.size(), border.size(), res); - } - } else { - if (value < border) { - res = ECompareResult::LESS; - } else if (value > border) { - res = ECompareResult::GREATER; - } - } - } -} - -template -bool CompareImpl(const std::shared_ptr& column, const T& border, std::vector& rowsCmp) { - bool hasBorder = false; - ECompareResult* res = &rowsCmp[0]; - auto array = std::static_pointer_cast(column); - - for (int i = 0; i < array->length(); ++i, ++res) { - UpdateCompare(GetValue(array, i), border, *res); - hasBorder = hasBorder || (*res == ECompareResult::BORDER); - } - return !hasBorder; -} - -template -bool CompareImpl(const std::shared_ptr& column, const T& border, std::vector& rowsCmp) { - bool hasBorder = false; - ECompareResult* res = &rowsCmp[0]; - - for (auto& chunk : column->chunks()) { - auto array = std::static_pointer_cast(chunk); - - for (int i = 0; i < chunk->length(); ++i, ++res) { - UpdateCompare(GetValue(array, i), border, *res); - hasBorder = hasBorder || (*res == ECompareResult::BORDER); - } - } - return !hasBorder; -} - -/// @return true in case we have no borders in compare: no need for future keys, allow early exit -template -bool Compare(const arrow::Datum& column, const std::shared_ptr& borderArray, std::vector& rowsCmp) { - auto border = GetValue(std::static_pointer_cast(borderArray), 0); - - switch (column.kind()) { - case arrow::Datum::ARRAY: - return CompareImpl(column.make_array(), border, rowsCmp); - case arrow::Datum::CHUNKED_ARRAY: - return CompareImpl(column.chunked_array(), border, rowsCmp); - default: - break; - } - Y_ABORT_UNLESS(false); - return false; -} - -bool SwitchCompare(const arrow::Datum& column, const std::shared_ptr& border, std::vector& rowsCmp) { - Y_ABORT_UNLESS(border->length() == 1); - - // first time it's empty - if (rowsCmp.empty()) { - rowsCmp.resize(column.length(), ECompareResult::BORDER); - } - - return SwitchArrayType(column, [&](const auto& type) -> bool { - using TWrap = std::decay_t; - using TArray = typename arrow::TypeTraits::ArrayType; - return Compare(column, border, rowsCmp); - }); -} - -template -void CompositeCompare(std::shared_ptr some, std::shared_ptr borderBatch, std::vector& rowsCmp) { - AFL_VERIFY(some); - AFL_VERIFY(borderBatch); - auto key = borderBatch->schema()->fields(); - AFL_VERIFY(key.size()); - - for (size_t i = 0; i < key.size(); ++i) { - auto& field = key[i]; - auto typeId = field->type()->id(); - auto column = some->GetColumnByName(field->name()); - std::shared_ptr border = borderBatch->GetColumnByName(field->name()); - AFL_VERIFY(column)("schema1", some->schema()->ToString())("schema2", borderBatch->schema()->ToString())("f", field->name()); - AFL_VERIFY(border)("schema1", some->schema()->ToString())("schema2", borderBatch->schema()->ToString())("f", field->name()); - AFL_VERIFY(some->schema()->GetFieldByName(field->name())->type()->id() == typeId)("schema1", some->schema()->ToString())( - "schema2", borderBatch->schema()->ToString())("f", field->name()); - - if (SwitchCompare(column, border, rowsCmp)) { - break; // early exit in case we have all rows compared: no borders, can omit key tail - } - } -} - -} // namespace - TColumnFilter::TSlicesIterator::TSlicesIterator(const TColumnFilter& owner, const std::optional start, const std::optional count) : Owner(owner) , StartIndex(start) @@ -307,61 +186,6 @@ ui32 TColumnFilter::CrossSize(const ui32 s1, const ui32 f1, const ui32 s2, const return f - s; } -NKikimr::NArrow::TColumnFilter TColumnFilter::MakePredicateFilter( - const arrow::Datum& datum, const arrow::Datum& border, ECompareType compareType) { - std::vector cmps; - - switch (datum.kind()) { - case arrow::Datum::ARRAY: - Y_ABORT_UNLESS(border.kind() == arrow::Datum::ARRAY); - SwitchCompare(datum, border.make_array(), cmps); - break; - case arrow::Datum::CHUNKED_ARRAY: - Y_ABORT_UNLESS(border.kind() == arrow::Datum::ARRAY); - SwitchCompare(datum, border.make_array(), cmps); - break; - case arrow::Datum::RECORD_BATCH: - Y_ABORT_UNLESS(border.kind() == arrow::Datum::RECORD_BATCH); - CompositeCompare(datum.record_batch(), border.record_batch(), cmps); - break; - case arrow::Datum::TABLE: - Y_ABORT_UNLESS(border.kind() == arrow::Datum::RECORD_BATCH); - CompositeCompare(datum.table(), border.record_batch(), cmps); - break; - default: - Y_ABORT_UNLESS(false); - break; - } - - std::vector bits; - bits.reserve(cmps.size()); - - switch (compareType) { - case ECompareType::LESS: - for (size_t i = 0; i < cmps.size(); ++i) { - bits.emplace_back(cmps[i] < ECompareResult::BORDER); - } - break; - case ECompareType::LESS_OR_EQUAL: - for (size_t i = 0; i < cmps.size(); ++i) { - bits.emplace_back(cmps[i] <= ECompareResult::BORDER); - } - break; - case ECompareType::GREATER: - for (size_t i = 0; i < cmps.size(); ++i) { - bits.emplace_back(cmps[i] > ECompareResult::BORDER); - } - break; - case ECompareType::GREATER_OR_EQUAL: - for (size_t i = 0; i < cmps.size(); ++i) { - bits.emplace_back(cmps[i] >= ECompareResult::BORDER); - } - break; - } - - return NArrow::TColumnFilter(std::move(bits)); -} - template void ApplyImpl(const TColumnFilter& filter, std::shared_ptr& batch, const TColumnFilter::TApplyContext& context) { if (!batch || !batch->num_rows()) { @@ -784,25 +608,24 @@ TString TColumnFilter::DebugString() const { return sb; } -TColumnFilter TColumnFilter::Cut(const ui32 filteredRecordsCount, const ui32 limit, const bool reverse) const { +TColumnFilter TColumnFilter::Cut(const ui32 totalRecordsCount, const ui32 limit, const bool reverse) const { if (IsTotalDenyFilter()) { return TColumnFilter::BuildDenyFilter(); } TColumnFilter result = TColumnFilter::BuildAllowFilter(); if (IsTotalAllowFilter()) { - if (filteredRecordsCount <= limit) { + if (totalRecordsCount <= limit) { return result; } if (reverse) { - result.Add(false, filteredRecordsCount - limit); + result.Add(false, totalRecordsCount - limit); result.Add(true, limit); } else { result.Add(true, limit); - result.Add(false, filteredRecordsCount - limit); + result.Add(false, totalRecordsCount - limit); } } else { - AFL_VERIFY_DEBUG(GetFilteredCountVerified() == filteredRecordsCount) - ("filter", GetFilteredCountVerified())("total", GetRecordsCountVerified())("ext", filteredRecordsCount); + AFL_VERIFY(GetRecordsCountVerified() == totalRecordsCount)("total", GetRecordsCountVerified())("ext", totalRecordsCount); ui32 cutCount = 0; bool currentValue = reverse ? LastValue : GetStartValue(); const auto scan = [&](auto begin, auto end) { diff --git a/ydb/core/formats/arrow/arrow_filter.h b/ydb/core/formats/arrow/arrow_filter.h index 8d4b1afad42b..9a135f5961ae 100644 --- a/ydb/core/formats/arrow/arrow_filter.h +++ b/ydb/core/formats/arrow/arrow_filter.h @@ -86,7 +86,7 @@ class TColumnFilter { bool Next(); }; - TColumnFilter Cut(const ui32 filteredRecordsCount, const ui32 limit, const bool reverse) const; + TColumnFilter Cut(const ui32 totalRecordsCount, const ui32 limit, const bool reverse) const; TSlicesIterator BuildSlicesIterator(const std::optional startIndex, const std::optional count) const { return TSlicesIterator(*this, startIndex, count); @@ -266,9 +266,6 @@ class TColumnFilter { TColumnFilter And(const TColumnFilter& extFilter) const Y_WARN_UNUSED_RESULT; TColumnFilter Or(const TColumnFilter& extFilter) const Y_WARN_UNUSED_RESULT; - // It makes a filter using composite predicate - static TColumnFilter MakePredicateFilter(const arrow::Datum& datum, const arrow::Datum& border, ECompareType compareType); - class TApplyContext { private: YDB_READONLY_DEF(std::optional, StartPos); diff --git a/ydb/core/formats/arrow/program/abstract.h b/ydb/core/formats/arrow/program/abstract.h index 9ca8a96f9089..32e73482e962 100644 --- a/ydb/core/formats/arrow/program/abstract.h +++ b/ydb/core/formats/arrow/program/abstract.h @@ -13,6 +13,47 @@ class TAccessorsCollection; namespace NKikimr::NArrow::NSSA { +class IMemoryCalculationPolicy { +public: + enum class EStage { + Accessors = 0 /* "ACCESSORS" */, + Filter = 1 /* "FILTER" */, + Fetching = 2 /* "FETCHING" */, + Merge = 3 /* "MERGE" */ + }; + + virtual ~IMemoryCalculationPolicy() = default; + + virtual EStage GetStage() const = 0; + virtual ui64 GetReserveMemorySize( + const ui64 blobsSize, const ui64 rawSize, const std::optional limit, const ui32 recordsCount) const = 0; +}; + +class TFilterCalculationPolicy: public IMemoryCalculationPolicy { +public: + virtual EStage GetStage() const override { + return EStage::Filter; + } + virtual ui64 GetReserveMemorySize( + const ui64 blobsSize, const ui64 /*rawSize*/, const std::optional /*limit*/, const ui32 /*recordsCount*/) const override { + return blobsSize; + } +}; + +class TFetchingCalculationPolicy: public IMemoryCalculationPolicy { +public: + virtual EStage GetStage() const override { + return EStage::Fetching; + } + virtual ui64 GetReserveMemorySize(const ui64 blobsSize, const ui64 rawSize, const std::optional limit, const ui32 recordsCount) const override { + if (limit) { + return std::max(blobsSize, rawSize * (1.0 * *limit) / recordsCount); + } else { + return std::max(blobsSize, rawSize); + } + } +}; + class TIndexCheckOperation { public: enum class EOperation : ui32 { @@ -214,7 +255,8 @@ enum class EProcessorType { AssembleOriginalData, CheckIndexData, CheckHeaderData, - StreamLogic + StreamLogic, + ReserveMemory }; class TFetchingInfo { @@ -303,6 +345,13 @@ class IResourceProcessor { Input.emplace_back(TColumnChainInfo(resourceId)); } + void AddOutput(const ui32 resourceId) { + for (auto&& i : Output) { + AFL_VERIFY(i.GetColumnId() != resourceId); + } + Output.emplace_back(TColumnChainInfo(resourceId)); + } + void RemoveInput(const ui32 resourceId) { for (ui32 idx = 0; idx < Input.size(); ++idx) { if (Input[idx].GetColumnId() == resourceId) { diff --git a/ydb/core/formats/arrow/program/collection.h b/ydb/core/formats/arrow/program/collection.h index d4aa90fe575c..5d1f6a5b2996 100644 --- a/ydb/core/formats/arrow/program/collection.h +++ b/ydb/core/formats/arrow/program/collection.h @@ -59,12 +59,19 @@ class TAccessorsCollection { AFL_VERIFY(Markers.erase(marker)); } - bool IsEmptyFiltered() const { + bool IsEmptyFilter() const { return Filter->IsTotalDenyFilter(); } - bool HasAccessors() const { - return Accessors.size(); + bool HasData() const { + return Accessors.size() || !!RecordsCountActual; + } + + bool HasDataAndResultIsEmpty() const { + if (!HasData()) { + return false; + } + return !GetRecordsCountActualVerified() || IsEmptyFilter(); } std::optional GetRecordsCountActualOptional() const { @@ -373,15 +380,14 @@ class TAccessorsCollection { } void CutFilter(const ui32 recordsCount, const ui32 limit, const bool reverse) { - const ui32 recordsCountImpl = Filter->GetFilteredCount().value_or(recordsCount); - if (recordsCountImpl < limit) { + if (recordsCount < limit) { return; } if (UseFilter) { - auto filter = NArrow::TColumnFilter::BuildAllowFilter().Cut(recordsCountImpl, limit, reverse); + auto filter = NArrow::TColumnFilter::BuildAllowFilter().Cut(recordsCount, limit, reverse); AddFilter(filter); } else { - *Filter = Filter->Cut(recordsCountImpl, limit, reverse); + *Filter = Filter->Cut(recordsCount, limit, reverse); } } diff --git a/ydb/core/formats/arrow/program/execution.h b/ydb/core/formats/arrow/program/execution.h index 4be60989c848..48b454f052a2 100644 --- a/ydb/core/formats/arrow/program/execution.h +++ b/ydb/core/formats/arrow/program/execution.h @@ -276,9 +276,23 @@ class IDataSource { virtual TConclusion DoStartFetch( const NArrow::NSSA::TProcessorContext& context, const std::vector>& fetchers) = 0; + virtual TConclusion DoStartReserveMemory(const NArrow::NSSA::TProcessorContext& /*context*/, + const THashMap& /*columns*/, const THashMap& /*indexes*/, + const THashMap& /*headers*/, + const std::shared_ptr& /*policy*/) { + return false; + } + public: virtual ~IDataSource() = default; + TConclusion StartReserveMemory(const NArrow::NSSA::TProcessorContext& context, + const THashMap& columns, const THashMap& indexes, + const THashMap& headers, const std::shared_ptr& policy) { + AFL_VERIFY(policy); + return DoStartReserveMemory(context, columns, indexes, headers, policy); + } + TConclusion StartFetch( const NArrow::NSSA::TProcessorContext& context, const std::vector>& fetchers) { return DoStartFetch(context, fetchers); diff --git a/ydb/core/formats/arrow/program/graph_execute.cpp b/ydb/core/formats/arrow/program/graph_execute.cpp index 0bd1f099f1a8..8628efe74738 100644 --- a/ydb/core/formats/arrow/program/graph_execute.cpp +++ b/ydb/core/formats/arrow/program/graph_execute.cpp @@ -3,6 +3,8 @@ #include "graph_optimization.h" #include "visitor.h" +#include + namespace NKikimr::NArrow::NSSA::NGraph::NExecution { class TResourceUsageInfo { @@ -102,7 +104,7 @@ TCompiledGraph::TCompiledGraph(const NOptimization::TGraph& original, const ICol if (i.second->GetProcessor()->GetProcessorType() == EProcessorType::Filter) { AFL_VERIFY(!IsFilterRoot(i.second->GetIdentifier())); FilterRoot.emplace_back(i.second); - } else if (i.second->GetProcessor()->GetProcessorType() != EProcessorType::Const) { + } else if (i.second->GetProcessor()->GetProcessorType() == EProcessorType::Projection) { AFL_VERIFY(!ResultRoot)("debug", DebugDOT()); ResultRoot = i.second; } else { @@ -122,6 +124,9 @@ TCompiledGraph::TCompiledGraph(const NOptimization::TGraph& original, const ICol for (; it->IsValid(); it->Next()) { it->MutableCurrentNode().SetSequentialIdx(currentIndex); for (auto&& i : it->GetProcessorVerified()->GetInput()) { + if (!i.GetColumnId()) { + continue; + } if (resolver.HasColumn(i.GetColumnId())) { if (IsFilterRoot(it->GetCurrentGraphNode()->GetIdentifier())) { FilterColumns.emplace(i.GetColumnId()); @@ -131,6 +136,9 @@ TCompiledGraph::TCompiledGraph(const NOptimization::TGraph& original, const ICol usage[i.GetColumnId()].InUsage(currentIndex); } for (auto&& i : it->GetProcessorVerified()->GetOutput()) { + if (!i.GetColumnId()) { + continue; + } usage[i.GetColumnId()].Constructed(currentIndex); } sortedNodes.emplace_back(&it->MutableCurrentNode()); @@ -152,12 +160,13 @@ TCompiledGraph::TCompiledGraph(const NOptimization::TGraph& original, const ICol } } AFL_TRACE(NKikimrServices::SSA_GRAPH_EXECUTION)("graph_constructed", DebugDOT()); -// Cerr << DebugDOT() << Endl; + // Cerr << DebugDOT() << Endl; } TConclusionStatus TCompiledGraph::Apply( const std::shared_ptr& source, const std::shared_ptr& resources) const { TProcessorContext context(source, resources, std::nullopt, false); + NMiniKQL::TThrowingBindTerminator bind; std::shared_ptr visitor = std::make_shared(context); for (auto it = BuildIterator(visitor); it->IsValid();) { { @@ -168,7 +177,7 @@ TConclusionStatus TCompiledGraph::Apply( AFL_VERIFY(*conclusion != IResourceProcessor::EExecutionResult::InBackground); } } - if (resources->IsEmptyFiltered()) { + if (resources->HasDataAndResultIsEmpty()) { resources->Clear(); return TConclusionStatus::Success(); } diff --git a/ydb/core/formats/arrow/program/graph_optimization.cpp b/ydb/core/formats/arrow/program/graph_optimization.cpp index 56f9cbbb51c6..43e547b17973 100644 --- a/ydb/core/formats/arrow/program/graph_optimization.cpp +++ b/ydb/core/formats/arrow/program/graph_optimization.cpp @@ -5,6 +5,7 @@ #include "header.h" #include "index.h" #include "original.h" +#include "reserve.h" #include "stream_logic.h" #include @@ -206,7 +207,8 @@ TConclusion TGraph::OptimizeMergeFetching(TGraphNode* baseNode) { } if (i.second->GetProcessorAs()->GetDataAddresses().size() + i.second->GetProcessorAs()->GetIndexContext().size() + - i.second->GetProcessorAs()->GetHeaderContext().size() > 1) { + i.second->GetProcessorAs()->GetHeaderContext().size() > + 1) { continue; } if (i.second->GetProcessorAs()->GetDataAddresses().size()) { @@ -220,6 +222,7 @@ TConclusion TGraph::OptimizeMergeFetching(TGraphNode* baseNode) { } } bool changed = false; + TGraphNode* nodeFetch = nullptr; if (dataAddresses.size() > 1) { THashSet columnIds; for (auto&& i : dataAddresses) { @@ -231,16 +234,32 @@ TConclusion TGraph::OptimizeMergeFetching(TGraphNode* baseNode) { proc->Add(addr.second); } } - auto nodeFetch = AddNode(proc); + nodeFetch = AddNode(proc).get(); FetchersMerged.emplace(nodeFetch->GetIdentifier()); for (auto&& i : dataAddresses) { for (auto&& to : i->GetOutputEdges()) { - AddEdge(nodeFetch.get(), to.second, to.first.GetResourceId()); + AddEdge(nodeFetch, to.second, to.first.GetResourceId()); } RemoveNode(i->GetIdentifier()); } changed = true; + } else if (dataAddresses.size() == 1) { + nodeFetch = dataAddresses.front(); } + if (nodeFetch) { + std::shared_ptr policy; + if (baseNode->Is(EProcessorType::Filter)) { + policy = std::make_shared(); + } else if (baseNode->Is(EProcessorType::Projection)) { + policy = std::make_shared(); + } + auto reserveMemory = std::make_shared(*nodeFetch->GetProcessorAs(), policy); + auto nodeReserve = AddNode(reserveMemory); + nodeReserve->GetProcessor()->AddOutput(0); + nodeFetch->GetProcessor()->AddInput(0); + AddEdge(nodeReserve.get(), nodeFetch, 0); + } + if (indexes.size() + headers.size() > 1) { THashSet columnIds; for (auto&& i : indexes) { diff --git a/ydb/core/formats/arrow/program/reserve.cpp b/ydb/core/formats/arrow/program/reserve.cpp new file mode 100644 index 000000000000..f10c87602003 --- /dev/null +++ b/ydb/core/formats/arrow/program/reserve.cpp @@ -0,0 +1,6 @@ +#include "execution.h" +#include "original.h" + +namespace NKikimr::NArrow::NSSA { + +} // namespace NKikimr::NArrow::NSSA diff --git a/ydb/core/formats/arrow/program/reserve.h b/ydb/core/formats/arrow/program/reserve.h new file mode 100644 index 000000000000..0ecadb8b3003 --- /dev/null +++ b/ydb/core/formats/arrow/program/reserve.h @@ -0,0 +1,74 @@ +#pragma once +#include "abstract.h" +#include "original.h" + +namespace NKikimr::NArrow::NSSA { + +class TReserveMemoryProcessor: public IResourceProcessor { +private: + using TBase = IResourceProcessor; + + THashMap DataAddresses; + THashMap IndexContext; + THashMap HeaderContext; + std::shared_ptr Policy; + + virtual NJson::TJsonValue DoDebugJson() const override { + NJson::TJsonValue result = NJson::JSON_MAP; + if (DataAddresses.size()) { + auto& arrAddr = result.InsertValue("data", NJson::JSON_ARRAY); + for (auto&& i : DataAddresses) { + arrAddr.AppendValue(i.second.DebugJson()); + } + } + if (IndexContext.size()) { + auto& indexesArr = result.InsertValue("indexes", NJson::JSON_ARRAY); + for (auto&& i : IndexContext) { + indexesArr.AppendValue(i.second.DebugJson()); + } + } + if (HeaderContext.size()) { + auto& headersArr = result.InsertValue("headers", NJson::JSON_ARRAY); + for (auto&& i : HeaderContext) { + headersArr.AppendValue(i.second.DebugJson()); + } + } + return result; + } + + virtual TConclusion DoExecute(const TProcessorContext& context, const TExecutionNodeContext& /*nodeContext*/) const override { + auto source = context.GetDataSource().lock(); + if (!source) { + return TConclusionStatus::Fail("source was destroyed before (original fetch start)"); + } + auto conclusion = source->StartReserveMemory(context, DataAddresses, IndexContext, HeaderContext, Policy); + if (conclusion.IsFail()) { + return conclusion; + } else if (conclusion.GetResult()) { + return EExecutionResult::InBackground; + } else { + return EExecutionResult::Success; + } + } + + virtual bool IsAggregation() const override { + return false; + } + + virtual ui64 DoGetWeight() const override { + return 0; + } + +public: + TReserveMemoryProcessor(const TOriginalColumnDataProcessor& original, const std::shared_ptr& policy) + : TBase({}, {}, EProcessorType::ReserveMemory) + , DataAddresses(original.GetDataAddresses()) + , IndexContext(original.GetIndexContext()) + , HeaderContext(original.GetHeaderContext()) + , Policy(policy) + { + AFL_VERIFY(policy); + } +}; + +} // namespace NKikimr::NArrow::NSSA diff --git a/ydb/core/formats/arrow/program/ya.make b/ydb/core/formats/arrow/program/ya.make index 114660d3251e..720b0f0b3180 100644 --- a/ydb/core/formats/arrow/program/ya.make +++ b/ydb/core/formats/arrow/program/ya.make @@ -48,6 +48,7 @@ SRCS( assign_internal.cpp custom_registry.cpp GLOBAL kernel_logic.cpp + reserve.cpp ) GENERATE_ENUM_SERIALIZATION(abstract.h) diff --git a/ydb/core/formats/arrow/reader/position.cpp b/ydb/core/formats/arrow/reader/position.cpp index 81e576d9fa26..5476975998e0 100644 --- a/ydb/core/formats/arrow/reader/position.cpp +++ b/ydb/core/formats/arrow/reader/position.cpp @@ -125,6 +125,12 @@ TSortableScanData::TSortableScanData( BuildPosition(position); } +TSortableScanData::TSortableScanData(const ui64 position, const std::shared_ptr& batch) { + Fields = batch->GetSchema()->GetFields(); + Columns = batch->GetColumns(); + BuildPosition(position); +} + TSortableScanData::TSortableScanData( const ui64 position, const std::shared_ptr& batch, const std::vector& columns) { for (auto&& i : columns) { diff --git a/ydb/core/formats/arrow/reader/position.h b/ydb/core/formats/arrow/reader/position.h index 4f5278029dde..a902744fe6e8 100644 --- a/ydb/core/formats/arrow/reader/position.h +++ b/ydb/core/formats/arrow/reader/position.h @@ -73,11 +73,47 @@ class TSortableScanData { return StartPosition <= position && position < FinishPosition; } + std::partial_ordering CompareImpl(const ui64 position, const TSortableScanData& item, const ui64 itemPosition, const ui32 size) const { + AFL_VERIFY(size <= PositionAddress.size() && size <= item.PositionAddress.size()); + AFL_VERIFY(size); + if (Contains(position) && item.Contains(itemPosition)) { + for (ui32 idx = 0; idx < size; ++idx) { + std::partial_ordering cmp = PositionAddress[idx].Compare(position, item.PositionAddress[idx], itemPosition); + if (cmp != std::partial_ordering::equivalent) { + return cmp; + } + } + } else { + for (ui32 idx = 0; idx < size; ++idx) { + std::partial_ordering cmp = std::partial_ordering::equivalent; + const bool containsSelf = PositionAddress[idx].GetAddress().Contains(position); + const bool containsItem = item.PositionAddress[idx].GetAddress().Contains(itemPosition); + if (containsSelf && containsItem) { + cmp = PositionAddress[idx].Compare(position, item.PositionAddress[idx], itemPosition); + } else if (containsSelf) { + auto temporaryAddress = item.Columns[idx]->GetChunk(item.PositionAddress[idx].GetAddress(), itemPosition); + cmp = PositionAddress[idx].Compare(position, temporaryAddress, itemPosition); + } else if (containsItem) { + auto temporaryAddress = Columns[idx]->GetChunk(PositionAddress[idx].GetAddress(), position); + cmp = temporaryAddress.Compare(position, item.PositionAddress[idx], itemPosition); + } else { + AFL_VERIFY(false); + } + if (cmp != std::partial_ordering::equivalent) { + return cmp; + } + } + } + + return std::partial_ordering::equivalent; + } + public: TSortableScanData(const ui64 position, const std::shared_ptr& batch); TSortableScanData(const ui64 position, const std::shared_ptr& batch, const std::vector& columns); TSortableScanData(const ui64 position, const std::shared_ptr& batch, const std::vector& columns); TSortableScanData(const ui64 position, const std::shared_ptr& batch, const std::vector& columns); + TSortableScanData(const ui64 position, const std::shared_ptr& batch); TSortableScanData(const ui64 position, const ui64 recordsCount, const std::vector>& columns, const std::vector>& fields) : RecordsCount(recordsCount) @@ -117,36 +153,11 @@ class TSortableScanData { std::partial_ordering Compare(const ui64 position, const TSortableScanData& item, const ui64 itemPosition) const { AFL_VERIFY(PositionAddress.size() == item.PositionAddress.size()); - if (Contains(position) && item.Contains(itemPosition)) { - for (ui32 idx = 0; idx < PositionAddress.size(); ++idx) { - std::partial_ordering cmp = PositionAddress[idx].Compare(position, item.PositionAddress[idx], itemPosition); - if (cmp != std::partial_ordering::equivalent) { - return cmp; - } - } - } else { - for (ui32 idx = 0; idx < PositionAddress.size(); ++idx) { - std::partial_ordering cmp = std::partial_ordering::equivalent; - const bool containsSelf = PositionAddress[idx].GetAddress().Contains(position); - const bool containsItem = item.PositionAddress[idx].GetAddress().Contains(itemPosition); - if (containsSelf && containsItem) { - cmp = PositionAddress[idx].Compare(position, item.PositionAddress[idx], itemPosition); - } else if (containsSelf) { - auto temporaryAddress = item.Columns[idx]->GetChunk(item.PositionAddress[idx].GetAddress(), itemPosition); - cmp = PositionAddress[idx].Compare(position, temporaryAddress, itemPosition); - } else if (containsItem) { - auto temporaryAddress = Columns[idx]->GetChunk(PositionAddress[idx].GetAddress(), position); - cmp = temporaryAddress.Compare(position, item.PositionAddress[idx], itemPosition); - } else { - AFL_VERIFY(false); - } - if (cmp != std::partial_ordering::equivalent) { - return cmp; - } - } - } + return CompareImpl(position, item, itemPosition, item.PositionAddress.size()); + } - return std::partial_ordering::equivalent; + std::partial_ordering ComparePartial(const ui64 position, const TSortableScanData& item, const ui64 itemPosition) const { + return CompareImpl(position, item, itemPosition, std::min(PositionAddress.size(), item.PositionAddress.size())); } void AppendPositionTo(const std::vector>& builders, const ui64 position, ui64* recordSize) const; @@ -414,6 +425,12 @@ class TSortableBatchPosition { return ApplyOptionalReverseForCompareResult(directResult); } + std::partial_ordering ComparePartial(const TSortableBatchPosition& item) const { + Y_ABORT_UNLESS(item.ReverseSort == ReverseSort); + const auto directResult = Sorting->ComparePartial(Position, *item.Sorting, item.GetPosition()); + return ApplyOptionalReverseForCompareResult(directResult); + } + std::partial_ordering Compare(const TSortableScanData& data, const ui64 dataPosition) const { return Sorting->Compare(Position, data, dataPosition); } diff --git a/ydb/core/formats/arrow/ut/ut_arrow.cpp b/ydb/core/formats/arrow/ut/ut_arrow.cpp index 6f12504187e9..bc46b4f329f7 100644 --- a/ydb/core/formats/arrow/ut/ut_arrow.cpp +++ b/ydb/core/formats/arrow/ut/ut_arrow.cpp @@ -480,21 +480,6 @@ std::vector TestRows() { return rows; } -bool CheckFilter(const std::vector& f, size_t count, bool value) { - for (size_t i = 0; i < f.size(); ++i) { - if (i < count) { - if (f[i] != value) { - return false; - } - } else { - if (f[i] == value) { - return false; - } - } - } - return true; -} - std::shared_ptr MakeTable1000() { TDataRowTableBuilder builder; @@ -672,38 +657,6 @@ Y_UNIT_TEST_SUITE(ArrowTest) { } } - Y_UNIT_TEST(KeyComparison) { - auto table = MakeTable1000(); - - std::shared_ptr border; // {2, 3, 4} - { - arrow::ScalarVector scalars{ - std::make_shared(2), - std::make_shared(3), - std::make_shared(4), - }; - - std::vector> columns; - for (auto scalar : scalars) { - auto res = arrow::MakeArrayFromScalar(*scalar, 1); - UNIT_ASSERT(res.ok()); - columns.push_back(*res); - } - - border = arrow::RecordBatch::Make(table->schema(), 1, columns); - } - - const NArrow::TColumnFilter lt = NArrow::TColumnFilter::MakePredicateFilter(table, border, NArrow::ECompareType::LESS); - const NArrow::TColumnFilter le = NArrow::TColumnFilter::MakePredicateFilter(table, border, NArrow::ECompareType::LESS_OR_EQUAL); - const NArrow::TColumnFilter gt = NArrow::TColumnFilter::MakePredicateFilter(table, border, NArrow::ECompareType::GREATER); - const NArrow::TColumnFilter ge = NArrow::TColumnFilter::MakePredicateFilter(table, border, NArrow::ECompareType::GREATER_OR_EQUAL); - - UNIT_ASSERT(CheckFilter(lt.BuildSimpleFilter(), 234, true)); - UNIT_ASSERT(CheckFilter(le.BuildSimpleFilter(), 235, true)); - UNIT_ASSERT(CheckFilter(gt.BuildSimpleFilter(), 235, false)); - UNIT_ASSERT(CheckFilter(ge.BuildSimpleFilter(), 234, false)); - } - Y_UNIT_TEST(SortWithCompositeKey) { std::shared_ptr table = Shuffle(MakeTable1000()); diff --git a/ydb/core/formats/arrow/ut/ut_column_filter.cpp b/ydb/core/formats/arrow/ut/ut_column_filter.cpp index f12fe1898b65..5994e8c45ce6 100644 --- a/ydb/core/formats/arrow/ut/ut_column_filter.cpp +++ b/ydb/core/formats/arrow/ut/ut_column_filter.cpp @@ -82,15 +82,15 @@ Y_UNIT_TEST_SUITE(ColumnFilter) { { auto cut = filter.Cut(100, 10, false); AFL_VERIFY(cut.DebugString() == "{1}[10,90]")("val", cut.DebugString()); - auto cut1 = cut.Cut(10, 3, false); + auto cut1 = cut.Cut(100, 3, false); AFL_VERIFY(cut1.DebugString() == "{1}[3,97]")("val", cut1.DebugString()); - auto cut2 = cut.Cut(10, 3, true); + auto cut2 = cut.Cut(100, 3, true); AFL_VERIFY(cut2.DebugString() == "{0}[7,3,90]")("val", cut2.DebugString()); } { auto cut = filter.Cut(100, 10, true); AFL_VERIFY(cut.DebugString() == "{0}[90,10]")("val", cut.DebugString()); - auto cut1 = cut.Cut(10, 0, true); + auto cut1 = cut.Cut(100, 0, true); AFL_VERIFY(cut1.DebugString() == "{0}[100]")("val", cut1.DebugString()); } } @@ -108,27 +108,27 @@ Y_UNIT_TEST_SUITE(ColumnFilter) { filter.Add(true, 3); filter.Add(false, 2); { - auto cut = filter.Cut(filter.GetFilteredCountVerified(), 10, false); + auto cut = filter.Cut(filter.GetRecordsCountVerified(), 10, false); AFL_VERIFY(cut.DebugString() == "{1}[4,3,2,1,4,18]")("val", cut.DebugString()); AFL_VERIFY(cut.GetRecordsCountVerified() == filter.GetRecordsCountVerified()); } { - auto cut = filter.Cut(filter.GetFilteredCountVerified(), 1, false); + auto cut = filter.Cut(filter.GetRecordsCountVerified(), 1, false); AFL_VERIFY(cut.DebugString() == "{1}[1,31]")("val", cut.DebugString()); AFL_VERIFY(cut.GetRecordsCountVerified() == filter.GetRecordsCountVerified()); } { - auto cut = filter.Cut(filter.GetFilteredCountVerified(), 8, false); + auto cut = filter.Cut(filter.GetRecordsCountVerified(), 8, false); AFL_VERIFY(cut.DebugString() == "{1}[4,3,2,1,2,20]")("val", cut.DebugString()); AFL_VERIFY(cut.GetRecordsCountVerified() == filter.GetRecordsCountVerified()); } { - auto cut = filter.Cut(filter.GetFilteredCountVerified(), 10, true); + auto cut = filter.Cut(filter.GetRecordsCountVerified(), 10, true); AFL_VERIFY(cut.DebugString() == "{0}[13,1,6,6,1,3,2]")("val", cut.DebugString()); AFL_VERIFY(cut.GetRecordsCountVerified() == filter.GetRecordsCountVerified()); } { - auto cut = filter.Cut(filter.GetFilteredCountVerified(), 1000, true); + auto cut = filter.Cut(filter.GetRecordsCountVerified(), 1000, true); AFL_VERIFY(cut.DebugString() == "{1}[4,3,2,1,4,6,6,1,3,2]")("val", cut.DebugString()); AFL_VERIFY(cut.GetRecordsCountVerified() == filter.GetRecordsCountVerified()); } diff --git a/ydb/core/formats/arrow/ut/ut_program_step.cpp b/ydb/core/formats/arrow/ut/ut_program_step.cpp index 951cc57bfb05..8f3f403a2af2 100644 --- a/ydb/core/formats/arrow/ut/ut_program_step.cpp +++ b/ydb/core/formats/arrow/ut/ut_program_step.cpp @@ -149,7 +149,13 @@ struct TSumData { } static void CheckResult(ETest test, const std::shared_ptr& batch, ui32 numKeys, bool nullable) { - AFL_VERIFY(batch->GetColumnsCount() == numKeys + 2); + if (test == ETest::EMPTY) { + UNIT_ASSERT(!batch->HasData()); + return; + } else { + AFL_VERIFY(batch->GetColumnsCount() == numKeys + 2); + } + auto aggXOriginal = batch->GetArrayVerified(3); auto aggYOriginal = batch->GetArrayVerified(4); auto colXOriginal = batch->GetArrayVerified(1); @@ -588,7 +594,7 @@ Y_UNIT_TEST_SUITE(ProgramStep) { builder.Add(std::make_shared(TColumnChainInfo::BuildVector({ 1, 2 }))); auto chain = builder.Finish().DetachResult(); Cerr << chain->DebugDOT() << Endl; - AFL_VERIFY(chain->DebugStats() == "[TOTAL:Const:2;Calculation:4;Projection:1;Filter:1;FetchOriginalData:2;AssembleOriginalData:3;CheckIndexData:1;StreamLogic:1;];SUB:[AssembleOriginalData:1;];")("debug", chain->DebugStats()); + AFL_VERIFY(chain->DebugStats() == "[TOTAL:Const:2;Calculation:4;Projection:1;Filter:1;FetchOriginalData:2;AssembleOriginalData:3;CheckIndexData:1;StreamLogic:1;ReserveMemory:1;];SUB:[AssembleOriginalData:1;];")("debug", chain->DebugStats()); } Y_UNIT_TEST(Projection) { diff --git a/ydb/core/fq/libs/actors/clusters_from_connections.cpp b/ydb/core/fq/libs/actors/clusters_from_connections.cpp index 274a6bac02dd..fa4ad7c8fe4f 100644 --- a/ydb/core/fq/libs/actors/clusters_from_connections.cpp +++ b/ydb/core/fq/libs/actors/clusters_from_connections.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -156,6 +157,9 @@ void FillGenericClusterConfigBase( case NYql::EGenericDataSourceKind::POSTGRESQL: clusterCfg.SetProtocol(NYql::EGenericProtocol::NATIVE); break; + case NYql::EGenericDataSourceKind::ICEBERG: + clusterCfg.SetProtocol(NYql::EGenericProtocol::NATIVE); + break; default: ythrow yexception() << "Unexpected data source kind: '" << NYql::EGenericDataSourceKind_Name(dataSourceKind) << "'"; @@ -342,6 +346,17 @@ void AddClustersFromConnections( break; } + case FederatedQuery::ConnectionSetting::kIceberg: { + const auto& db = conn.content().setting().iceberg(); + auto& clusterConfig = *gatewaysConfig.MutableGeneric()->AddClusterMapping(); + + clusterConfig.SetName(connectionName); + NFq::FillIcebergGenericClusterConfig(common, db, clusterConfig); + FillClusterAuth(clusterConfig, db.warehouse_auth(), authToken, accountIdSignatures); + clusters.emplace(connectionName, GenericProviderName); + break; + } + // Do not replace with default. Adding a new connection should cause a compilation error case FederatedQuery::ConnectionSetting::CONNECTION_NOT_SET: break; diff --git a/ydb/core/fq/libs/actors/pending_fetcher.cpp b/ydb/core/fq/libs/actors/pending_fetcher.cpp index 29a00f322453..39c61f02ba69 100644 --- a/ydb/core/fq/libs/actors/pending_fetcher.cpp +++ b/ydb/core/fq/libs/actors/pending_fetcher.cpp @@ -1,8 +1,6 @@ #include "proxy.h" #include "nodes_manager.h" -#include "database_resolver.h" - #include #include #include @@ -52,6 +50,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/ydb/core/fq/libs/actors/proxy.cpp b/ydb/core/fq/libs/actors/proxy.cpp deleted file mode 100644 index ca6da139c00d..000000000000 --- a/ydb/core/fq/libs/actors/proxy.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "proxy.h" - -namespace NFq { - -using namespace NActors; - -NActors::TActorId MakeYqlAnalyticsHttpProxyId() { - constexpr TStringBuf name = "YQLHTTPROXY"; - return NActors::TActorId(0, name); -} - -} // namespace NFq diff --git a/ydb/core/fq/libs/actors/proxy.h b/ydb/core/fq/libs/actors/proxy.h index 7ebe1f378bf6..df6f3b10f4ff 100644 --- a/ydb/core/fq/libs/actors/proxy.h +++ b/ydb/core/fq/libs/actors/proxy.h @@ -35,7 +35,6 @@ namespace NKikimr { namespace NFq { -NActors::TActorId MakeYqlAnalyticsHttpProxyId(); NActors::TActorId MakePendingFetcherId(ui32 nodeId); NActors::IActor* CreatePendingFetcher( diff --git a/ydb/core/fq/libs/actors/run_actor.cpp b/ydb/core/fq/libs/actors/run_actor.cpp index cd518c31b873..1fe451e4bc2b 100644 --- a/ydb/core/fq/libs/actors/run_actor.cpp +++ b/ydb/core/fq/libs/actors/run_actor.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include @@ -958,6 +959,7 @@ class TRunActor : public NActors::TActorBootstrapped { Fq::Private::PingTaskRequest request; if (proto.issues_size()) { *request.mutable_transient_issues() = proto.issues(); + NKikimr::NKqp::TruncateIssues(request.mutable_transient_issues()); } if (proto.metric_size()) { TString statistics; @@ -972,7 +974,7 @@ class TRunActor : public NActors::TActorBootstrapped { void SendTransientIssues(const NYql::TIssues& issues) { Fq::Private::PingTaskRequest request; - NYql::IssuesToMessage(issues, request.mutable_transient_issues()); + NYql::IssuesToMessage(NKikimr::NKqp::TruncateIssues(issues), request.mutable_transient_issues()); Send(Pinger, new TEvents::TEvForwardPingRequest(request), 0, RaiseTransientIssuesCookie); } @@ -1018,6 +1020,12 @@ class TRunActor : public NActors::TActorBootstrapped { const auto emptyResultSet = builder.BuildResultSet({}); auto* header = QueryStateUpdateRequest.add_result_set_meta(); (*header->mutable_column()) = emptyResultSet.columns(); + + if (const auto& issues = NKikimr::NKqp::ValidateResultSetColumns(header->column())) { + header->clear_column(); + Abort("Invalid result set columns, please contact internal support", FederatedQuery::QueryMeta::FAILED, issues); + return; + } } } *request.mutable_result_set_meta() = QueryStateUpdateRequest.result_set_meta(); @@ -1191,7 +1199,7 @@ class TRunActor : public NActors::TActorBootstrapped { } TIssue WrapInternalIssues(const TIssues& issues) { - NYql::IssuesToMessage(issues, QueryStateUpdateRequest.mutable_internal_issues()); + NYql::IssuesToMessage(NKikimr::NKqp::TruncateIssues(issues), QueryStateUpdateRequest.mutable_internal_issues()); TString referenceId = GetEntityIdAsString(Params.Config.GetCommon().GetIdsPrefix(), EEntityType::UNDEFINED); LOG_E(referenceId << ": " << issues.ToOneLineString()); return TIssue("Contact technical support and provide query information and this id: " + referenceId + "_" + Now().ToStringUpToSeconds()); @@ -1571,6 +1579,18 @@ class TRunActor : public NActors::TActorBootstrapped { ClearResultFormatSettings(); } + TDuration pingPeriod = TDuration::Seconds(3); + TDuration aggrPeriod = TDuration::Seconds(1); + { + const auto& taskControllerConfig = Params.Config.GetTaskController(); + if (taskControllerConfig.GetPingPeriod()) { + Y_ABORT_UNLESS(TDuration::TryParse(taskControllerConfig.GetPingPeriod(), pingPeriod)); + } + if (taskControllerConfig.GetAggrPeriod()) { + Y_ABORT_UNLESS(TDuration::TryParse(taskControllerConfig.GetAggrPeriod(), aggrPeriod)); + } + } + if (enableCheckpointCoordinator) { ControlId = Register(MakeCheckpointCoordinator( ::NFq::TCoordinatorId(Params.QueryId + "-" + ToString(DqGraphIndex), Params.PreviousQueryRevision), @@ -1587,8 +1607,8 @@ class TRunActor : public NActors::TActorBootstrapped { resultId, dqConfiguration, QueryCounters, - TDuration::Seconds(3), - TDuration::Seconds(1) + pingPeriod, + aggrPeriod ).Release()); } else { ControlId = Register(NYql::MakeTaskController( @@ -1597,7 +1617,8 @@ class TRunActor : public NActors::TActorBootstrapped { resultId, dqConfiguration, QueryCounters, - TDuration::Seconds(3) + pingPeriod, + aggrPeriod ).Release()); } @@ -1878,8 +1899,8 @@ class TRunActor : public NActors::TActorBootstrapped { Issues.Clear(); } - NYql::IssuesToMessage(TransientIssues, QueryStateUpdateRequest.mutable_transient_issues()); - NYql::IssuesToMessage(Issues, QueryStateUpdateRequest.mutable_issues()); + NYql::IssuesToMessage(NKikimr::NKqp::TruncateIssues(TransientIssues), QueryStateUpdateRequest.mutable_transient_issues()); + NYql::IssuesToMessage(NKikimr::NKqp::TruncateIssues(Issues), QueryStateUpdateRequest.mutable_issues()); /* 1. If the execution has already started then the issue will be put through TEvAbortExecution 2. If execution hasn't started then the issue will be put in this place diff --git a/ydb/core/fq/libs/actors/ut/database_resolver_ut.cpp b/ydb/core/fq/libs/actors/ut/database_resolver_ut.cpp index 59a4cb47ae07..d9a81685a2dd 100644 --- a/ydb/core/fq/libs/actors/ut/database_resolver_ut.cpp +++ b/ydb/core/fq/libs/actors/ut/database_resolver_ut.cpp @@ -1,7 +1,7 @@ -#include -#include -#include #include +#include +#include +#include #include #include diff --git a/ydb/core/fq/libs/actors/ya.make b/ydb/core/fq/libs/actors/ya.make index 80da96cdb259..8379bbc4e7d0 100644 --- a/ydb/core/fq/libs/actors/ya.make +++ b/ydb/core/fq/libs/actors/ya.make @@ -2,12 +2,10 @@ LIBRARY() SRCS( clusters_from_connections.cpp - database_resolver.cpp error.cpp nodes_health_check.cpp nodes_manager.cpp pending_fetcher.cpp - proxy.cpp proxy_private.cpp rate_limiter.cpp rate_limiter_resources.cpp @@ -50,6 +48,7 @@ PEERDIR( ydb/core/fq/libs/result_formatter ydb/core/fq/libs/shared_resources ydb/core/fq/libs/signer + ydb/core/kqp/federated_query ydb/core/protos ydb/core/util ydb/library/mkql_proto diff --git a/ydb/core/fq/libs/cloud_audit/yq_cloud_audit_service.cpp b/ydb/core/fq/libs/cloud_audit/yq_cloud_audit_service.cpp index bba6e0ab75ec..0e8b2842d559 100644 --- a/ydb/core/fq/libs/cloud_audit/yq_cloud_audit_service.cpp +++ b/ydb/core/fq/libs/cloud_audit/yq_cloud_audit_service.cpp @@ -71,6 +71,8 @@ std::string MapConnectionType(const FederatedQuery::ConnectionSetting::Connectio return "MySQLCluster"; case FederatedQuery::ConnectionSetting::ConnectionCase::kLogging: return "Logging"; + case FederatedQuery::ConnectionSetting::ConnectionCase::kIceberg: + return "Iceberg"; case FederatedQuery::ConnectionSetting::ConnectionCase::CONNECTION_NOT_SET: Y_ENSURE(false, "Invalid connection case " << i32(connectionCase)); } diff --git a/ydb/core/fq/libs/common/iceberg_processor.cpp b/ydb/core/fq/libs/common/iceberg_processor.cpp new file mode 100644 index 000000000000..9fac5ef5f391 --- /dev/null +++ b/ydb/core/fq/libs/common/iceberg_processor.cpp @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include +#include + +#include "iceberg_processor.h" + +namespace NFq { + +constexpr char VALUE_DEFAULT_REGION[] = "ru-central1"; + +TString RemoveTrailingSlashes(const TString& str) { + if (str.empty()) { + return ""; + } + + const auto first = str.find_first_not_of('/'); + + if (TString::npos == first) { + return ""; + } + + const auto last = str.find_last_not_of('/'); + return str.substr(first, last - first + 1); +} + +TIcebergProcessor::TIcebergProcessor(const FederatedQuery::Iceberg& config, NYql::TIssues& issues) + : Config_(config) + , Issues_(&issues) +{ } + +TIcebergProcessor::TIcebergProcessor(const FederatedQuery::Iceberg& config) + : Config_(config) + , Issues_(nullptr) +{ } + +void TIcebergProcessor::TIcebergProcessor::Process() { + if (!Config_.has_warehouse_auth() + || Config_.warehouse_auth().identity_case() == FederatedQuery::IamAuth::IDENTITY_NOT_SET) { + DoOnPropertyRequiredError("warehouse.auth"); + } + + ProcessSkipAuth(); +} + +void TIcebergProcessor::ProcessSkipAuth() { + if (!Config_.has_warehouse()) { + DoOnPropertyRequiredError("warehouse"); + } else { + ProcessWarehouse(Config_.warehouse()); + } + + if (!Config_.has_catalog()) { + DoOnPropertyRequiredError("catalog"); + } else { + ProcessCatalog(Config_.catalog()); + } +} + +void TIcebergProcessor::DoOnPropertyRequiredError(const TString& property) { + DoOnError(property, "has to be set"); +} + +void TIcebergProcessor::DoOnError(const TString& property, const TString& msg) { + if (!Issues_) { + throw yexception() << property << ": " << msg; + } + + auto m = TStringBuilder() + << "content.setting.iceberg." + << property << " " + << msg; + + Issues_->AddIssue(MakeErrorIssue(TIssuesIds::BAD_REQUEST, m)); +} + +void TIcebergProcessor::ProcessWarehouse(const FederatedQuery::IcebergWarehouse& warehouse) { + if (warehouse.has_s3()) { + ProcessWarehouseS3(warehouse.s3()); + } else { + DoOnPropertyRequiredError("warehouse.type"); + } +} + +void TIcebergProcessor::ProcessWarehouseS3(const FederatedQuery::IcebergWarehouse_S3& s3) { + TString bucket; + + if (!s3.has_bucket() + || (bucket = RemoveTrailingSlashes(s3.bucket())).empty()) { + DoOnPropertyRequiredError("warehouse.s3.bucket"); + } + + if (OnS3Callback_ && !HasErrors()) { + auto uri = TStringBuilder() << bucket; + auto path = RemoveTrailingSlashes(s3.path()); + + if (!path.empty()) { + uri << "/" << path; + } + + OnS3Callback_(s3, uri); + } +} + +void TIcebergProcessor::ProcessCatalogHadoop(const FederatedQuery::IcebergCatalog_Hadoop& hadoop) { + if (!hadoop.has_directory() + || hadoop.directory().empty()) { + DoOnPropertyRequiredError("hadoop.directory"); + } + + if (OnHadoopCallback_ && !HasErrors()) { + OnHadoopCallback_(hadoop); + } +} + +void TIcebergProcessor::ProcessCatalogHiveMetastore(const FederatedQuery::IcebergCatalog_HiveMetastore& hive) { + if (!hive.has_uri() + || hive.uri().empty()) { + DoOnPropertyRequiredError("hive_metastore.uri"); + } + + if (!hive.has_database_name() + || hive.database_name().empty()) { + DoOnPropertyRequiredError("hive_metastore.database_name"); + } + + if (OnHiveCallback_ && !HasErrors()) { + OnHiveCallback_(hive); + } +} + +void TIcebergProcessor::ProcessCatalog(const FederatedQuery::IcebergCatalog& catalog) { + if (catalog.has_hive_metastore()) { + ProcessCatalogHiveMetastore(catalog.hive_metastore()); + } else if (catalog.has_hadoop()) { + ProcessCatalogHadoop(catalog.hadoop()); + } else { + DoOnPropertyRequiredError("catalog.type"); + } +} + +TString MakeIcebergCreateExternalDataSourceProperties(const NConfig::TCommonConfig& yqConfig, const FederatedQuery::Iceberg& config) { + using namespace fmt::literals; + using namespace NKikimr::NExternalSource::NIceberg; + + TIcebergProcessor processor(config); + + // warehouse configuration + TString warehouseSection; + + processor.SetDoOnWarehouseS3([&warehouseSection, &yqConfig](const FederatedQuery::IcebergWarehouse_S3&, const TString& uri) { + warehouseSection = fmt::format( + R"( + {warehouse_type}={warehouse_type_value}, + {warehouse_s3_region}={warehouse_s3_region_value}, + {warehouse_s3_endpoint}={warehouse_s3_endpoint_value}, + {warehouse_s3_uri}={warehouse_s3_uri_value} + )", + "warehouse_type"_a = WAREHOUSE_TYPE, + "warehouse_type_value"_a = EncloseAndEscapeString(VALUE_S3, '"'), + "warehouse_s3_region"_a = WAREHOUSE_S3_REGION, + "warehouse_s3_region_value"_a = EncloseAndEscapeString(VALUE_DEFAULT_REGION, '"'), + "warehouse_s3_endpoint"_a = WAREHOUSE_S3_ENDPOINT, + "warehouse_s3_endpoint_value"_a = EncloseAndEscapeString(yqConfig.GetObjectStorageEndpoint(), '"'), + "warehouse_s3_uri"_a = WAREHOUSE_S3_URI, + "warehouse_s3_uri_value"_a = EncloseAndEscapeString(uri, '"') + ); + }); + + // catalog configuration + TString catalogSection; + + processor.SetDoOnCatalogHive([&catalogSection](const FederatedQuery::IcebergCatalog_HiveMetastore& hiveMetastore) { + catalogSection = fmt::format( + R"( + {catalog_type}={catalog_type_value}, + {catalog_hive_uri}={catalog_hive_uri_value}, + database_name={database_name} + )", + "catalog_type"_a = CATALOG_TYPE, + "catalog_type_value"_a = EncloseAndEscapeString(VALUE_HIVE, '"'), + "catalog_hive_uri"_a = CATALOG_HIVE_URI, + "catalog_hive_uri_value"_a = EncloseAndEscapeString(hiveMetastore.uri(), '"'), + "database_name"_a = EncloseAndEscapeString(hiveMetastore.database_name(), '"') + ); + }); + + processor.SetDoOnCatalogHadoop([&catalogSection](const FederatedQuery::IcebergCatalog_Hadoop& hadoop) { + catalogSection = fmt::format( + R"( + {catalog_type}={catalog_type_value}, + database_name={database_name} + )", + "catalog_type"_a = CATALOG_TYPE, + "catalog_type_value"_a = EncloseAndEscapeString(VALUE_HADOOP, '"'), + "database_name"_a = EncloseAndEscapeString(hadoop.directory(), '"') + ); + }); + + processor.Process(); + + // common configuration for all warehouses and catalogs + TString commonSection = fmt::format( + R"( + source_type="Iceberg", + use_tls="{use_tls}" + )", + "use_tls"_a = !yqConfig.GetDisableSslForGenericDataSources() ? "true" : "false" + ); + + // merge config + auto r = fmt::format( + R"( + {common_section}, + {warehouse_section}, + {catalog_section} + )", + "common_section"_a = commonSection, + "warehouse_section"_a = warehouseSection, + "catalog_section"_a = catalogSection + ); + + return r; +} + +void FillIcebergGenericClusterConfig(const NConfig::TCommonConfig& yqConfig, const FederatedQuery::Iceberg& config, ::NYql::TGenericClusterConfig& cluster) { + using namespace NKikimr::NExternalSource::NIceberg; + + TIcebergProcessor processor(config); + cluster.SetKind(NYql::EGenericDataSourceKind::ICEBERG); + + auto& options = *cluster.MutableDataSourceOptions(); + + processor.SetDoOnWarehouseS3([&options, &yqConfig](const FederatedQuery::IcebergWarehouse_S3&, const TString& uri) { + options[WAREHOUSE_TYPE] = VALUE_S3; + options[WAREHOUSE_S3_ENDPOINT] = yqConfig.GetObjectStorageEndpoint(); + options[WAREHOUSE_S3_REGION] = VALUE_DEFAULT_REGION; + options[WAREHOUSE_S3_URI] = uri; + }); + + processor.SetDoOnCatalogHive([&options, &cluster](const FederatedQuery::IcebergCatalog_HiveMetastore& hiveMetastore) { + options[CATALOG_TYPE] = VALUE_HIVE; + options[CATALOG_HIVE_URI] = hiveMetastore.uri(); + + cluster.SetDatabaseName(hiveMetastore.database_name()); + }); + + processor.SetDoOnCatalogHadoop([&options, &cluster](const FederatedQuery::IcebergCatalog_Hadoop& hadoop) { + options[CATALOG_TYPE] = VALUE_HADOOP; + + cluster.SetDatabaseName(hadoop.directory()); + }); + + processor.ProcessSkipAuth(); +} + +} // NFq diff --git a/ydb/core/fq/libs/common/iceberg_processor.h b/ydb/core/fq/libs/common/iceberg_processor.h new file mode 100644 index 000000000000..8446eb27cd37 --- /dev/null +++ b/ydb/core/fq/libs/common/iceberg_processor.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include +#include + +namespace NFq { + +class TIcebergProcessor { +public: + explicit TIcebergProcessor(const FederatedQuery::Iceberg& config); + + TIcebergProcessor(const FederatedQuery::Iceberg& config, NYql::TIssues& issues); + + ~TIcebergProcessor() = default; + + void Process(); + + void ProcessSkipAuth(); + + void SetDoOnWarehouseS3(std::function< + void(const FederatedQuery::IcebergWarehouse_S3&, const TString&)> callback) { + OnS3Callback_ = callback; + } + + void SetDoOnCatalogHive(std::function< + void(const FederatedQuery::IcebergCatalog_HiveMetastore&)> callback) { + OnHiveCallback_ = callback; + } + + void SetDoOnCatalogHadoop(std::function< + void(const FederatedQuery::IcebergCatalog_Hadoop&)> callback) { + OnHadoopCallback_ = callback; + } + +private: + void DoOnPropertyRequiredError(const TString& property); + + void DoOnError(const TString& property, const TString& msg); + + void ProcessWarehouse(const FederatedQuery::IcebergWarehouse& warehouse); + + void ProcessWarehouseS3(const FederatedQuery::IcebergWarehouse_S3& s3); + + void ProcessCatalog(const FederatedQuery::IcebergCatalog& catalog); + + void ProcessCatalogHadoop(const FederatedQuery::IcebergCatalog_Hadoop& hadoop); + + void ProcessCatalogHiveMetastore(const FederatedQuery::IcebergCatalog_HiveMetastore& hive); + + bool HasErrors() const { + return Issues_ && !Issues_->Empty(); + } + +private: + const FederatedQuery::Iceberg& Config_; + NYql::TIssues* Issues_; + std::function OnS3Callback_; + std::function OnHiveCallback_; + std::function OnHadoopCallback_; +}; + +TString MakeIcebergCreateExternalDataSourceProperties(const NConfig::TCommonConfig& yqConfig, + const FederatedQuery::Iceberg& config); + +void FillIcebergGenericClusterConfig(const NConfig::TCommonConfig& yqConfig, + const FederatedQuery::Iceberg& config, + NYql::TGenericClusterConfig& cluster); + +} // NFq diff --git a/ydb/core/fq/libs/common/iceberg_processor_ut.cpp b/ydb/core/fq/libs/common/iceberg_processor_ut.cpp new file mode 100644 index 000000000000..2b4a0f5e3bee --- /dev/null +++ b/ydb/core/fq/libs/common/iceberg_processor_ut.cpp @@ -0,0 +1,269 @@ +#include "iceberg_processor.h" + +#include +#include +#include + +namespace NFq { + +namespace { + +struct TClusterConfigBuilder { + TString Token; + TString S3Path; + TString S3Bucket; + TString HiveMetastoreUri; + TString HiveMetastoreDb; + TString HadoopDir; + + TClusterConfigBuilder& FillWarehouseWithS3() { + S3Bucket = "//bucket//"; + S3Path = "//path//"; + return *this; + } + + TClusterConfigBuilder& FillAuthToken() { + Token = "token"; + return *this; + } + + TClusterConfigBuilder& FillHadoopCatalog() { + HadoopDir = "hadoop_dir"; + return *this; + } + + TClusterConfigBuilder& FillHiveMetastoreCatalog() { + HiveMetastoreUri = "hive_metastore_uri"; + HiveMetastoreDb = "hive_metastore_db"; + return *this; + } + + FederatedQuery::Iceberg Build() { + FederatedQuery::Iceberg cluster; + + if (!Token.empty()) { + cluster.mutable_warehouse_auth() + ->mutable_token() + ->set_token(Token); + } + + if (!S3Path.empty()) { + cluster.mutable_warehouse() + ->mutable_s3() + ->set_path(S3Path); + } + + if (!S3Bucket.empty()) { + cluster.mutable_warehouse() + ->mutable_s3() + ->set_bucket(S3Bucket); + } + + if (!HadoopDir.empty()) { + cluster.mutable_catalog() + ->mutable_hadoop() + ->set_directory(HadoopDir); + } + + if (!HiveMetastoreUri.empty()) { + cluster.mutable_catalog() + ->mutable_hive_metastore() + ->set_uri(HiveMetastoreUri); + } + + if (!HiveMetastoreDb.empty()) { + cluster.mutable_catalog() + ->mutable_hive_metastore() + ->set_database_name(HiveMetastoreDb); + } + + return cluster; + } + + TClusterConfigBuilder clone() { + TClusterConfigBuilder bld(*this); + return bld; + } + + TClusterConfigBuilder& SetToken(const TString& token) { + Token = token; + return *this; + } + + TClusterConfigBuilder& SetS3Bucket(const TString& bucket) { + S3Bucket = bucket; + return *this; + } + + TClusterConfigBuilder& SetS3Path(const TString& path) { + S3Path = path; + return *this; + } + + TClusterConfigBuilder& SetHiveMetastoreUri(const TString& uri) { + HiveMetastoreUri = uri; + return *this; + } + + TClusterConfigBuilder& SetHiveMetastoreDb(const TString& db) { + HiveMetastoreDb = db; + return *this; + } + + TClusterConfigBuilder& SetHadoopDir(const TString& dir) { + HadoopDir = dir; + return *this; + } +}; + +std::vector GetErrorsFromIssues(const NYql::TIssues& issues) { + std::vector result; + + std::transform( + issues.begin(), + issues.end(), + std::back_inserter(result), + [](const NYql::TIssue& issue)-> TString { return issue.GetMessage(); } + ); + + return result; +} + +} // unnamed + +Y_UNIT_TEST_SUITE(IcebergClusterProcessor) { + + // Test ddl creation for a hadoop catalog with s3 warehouse + Y_UNIT_TEST(ValidateDdlCreationForHadoopWithS3) { + auto cluster = TClusterConfigBuilder() + .FillWarehouseWithS3() + .FillAuthToken() + .FillHadoopCatalog() + .Build(); + + NConfig::TCommonConfig common; + common.SetDisableSslForGenericDataSources(true); + common.SetObjectStorageEndpoint("s3endpoint"); + + auto ddlProperties = MakeIcebergCreateExternalDataSourceProperties(common, cluster); + SubstGlobal(ddlProperties, " ", ""); + SubstGlobal(ddlProperties, "\n", ""); + + UNIT_ASSERT_VALUES_EQUAL(ddlProperties, "source_type=\"Iceberg\",use_tls=\"false\",warehouse_type=\"s3\",warehouse_s3_region=\"ru-central1\",warehouse_s3_endpoint=\"s3endpoint\",warehouse_s3_uri=\"bucket/path\",catalog_type=\"hadoop\",database_name=\"hadoop_dir\""); + } + + // Test ddl creation for a hive catalog with s3 warehouse + Y_UNIT_TEST(ValidateDdlCreationForHiveWithS3) { + auto cluster = TClusterConfigBuilder() + .SetS3Bucket("s3a://iceberg-bucket/") + .SetS3Path("/storage/") + .FillAuthToken() + .FillHiveMetastoreCatalog() + .Build(); + + NConfig::TCommonConfig common; + common.SetDisableSslForGenericDataSources(false); + common.SetObjectStorageEndpoint("s3endpoint"); + + auto ddlProperties = MakeIcebergCreateExternalDataSourceProperties(common, cluster); + SubstGlobal(ddlProperties, " ", ""); + SubstGlobal(ddlProperties, "\n", ""); + + UNIT_ASSERT_VALUES_EQUAL(ddlProperties, "source_type=\"Iceberg\",use_tls=\"true\",warehouse_type=\"s3\",warehouse_s3_region=\"ru-central1\",warehouse_s3_endpoint=\"s3endpoint\",warehouse_s3_uri=\"s3a://iceberg-bucket/storage\",catalog_type=\"hive\",catalog_hive_uri=\"hive_metastore_uri\",database_name=\"hive_metastore_db\""); + } + + // Test parsing for FederatedQuery::IcebergCluster without warehouse + Y_UNIT_TEST(ValidateConfigurationWithoutWarehouse) { + NYql::TIssues issues; + auto cluster = TClusterConfigBuilder() + .FillAuthToken() + .FillHiveMetastoreCatalog() + .Build(); + + TIcebergProcessor processor(cluster, issues); + processor.Process(); + auto r = GetErrorsFromIssues(issues); + + UNIT_ASSERT_VALUES_EQUAL(r.size(), 1); + UNIT_ASSERT_STRING_CONTAINS(r[0], "warehouse"); + } + + // Test parsing for FederatedQuery::IcebergCluster without catalog + Y_UNIT_TEST(ValidateConfigurationWithoutCatalog) { + NYql::TIssues issues; + auto cluster = TClusterConfigBuilder() + .FillWarehouseWithS3() + .FillAuthToken() + .Build(); + + TIcebergProcessor processor(cluster, issues); + processor.Process(); + auto r = GetErrorsFromIssues(issues); + + UNIT_ASSERT_VALUES_EQUAL(r.size(), 1); + UNIT_ASSERT_STRING_CONTAINS(r[0], "catalog"); + } + + // + // Test parsing for FederatedQuery::Iceberg + // + // NB: For such test it's better to use parameterized test + // Unittest does not support it yet, switch to gtest ? + // + Y_UNIT_TEST(ValidateRiseErrors) { + // initially fill all params, in test cases + // remove some params and expect error + NFq::TClusterConfigBuilder params = { + .Token = "token", + .S3Path = "path", + .S3Bucket = "bucket", + .HiveMetastoreUri = "hive_metastore_uri", + .HiveMetastoreDb = "hive_metastore db", + .HadoopDir = "hadoop_dir" + }; + + // Defines which errors to expect if param is not set + std::vector>> cases = { + // token is required expect error + {params.clone().SetToken(""), {"warehouse.auth"}}, + // s3.path is non required + {params.clone().SetS3Path(""), {}}, + // s3.bucket is required + {params.clone().SetS3Bucket(""), {"s3.bucket"}}, + // s3.bucket is required, slashes has to be removed + {params.clone().SetS3Bucket("///"), {"s3.bucket"}}, + // warehouse is required + {params.clone().SetS3Bucket("").SetS3Path(""), {"warehouse"}}, + // hive_metastore.uri is required when hadoop is not set + {params.clone().SetHadoopDir("").SetHiveMetastoreUri(""), {"hive_metastore.uri"}}, + // hive_metastore.db is required when hadoop is not set + {params.clone().SetHadoopDir("").SetHiveMetastoreDb(""), {"hive_metastore.database_name"}}, + // catalog is required + {params.clone().SetHadoopDir("").SetHiveMetastoreUri("").SetHiveMetastoreDb(""), {"catalog"}}, + // hadoop.dir is set, hive_metastore is empty, no errors + {params.clone().SetHiveMetastoreUri("").SetHiveMetastoreDb(""), {}} + }; + + int count = 1; + + // process params and expect errors + for (auto [params, waitErrors] : cases) { + auto cluster = params.Build(); + NYql::TIssues issues; + TIcebergProcessor processor(cluster, issues); + + processor.Process(); + auto r = GetErrorsFromIssues(issues); + Cerr << "test case: " << count++ << "\n"; + + UNIT_ASSERT_VALUES_EQUAL(r.size(), waitErrors.size()); + + for (size_t i = 0; i < waitErrors.size(); ++i) { + UNIT_ASSERT_STRING_CONTAINS(r[i], waitErrors[i]); + } + } + } +} + + +} // NFq diff --git a/ydb/core/fq/libs/common/ut/ya.make b/ydb/core/fq/libs/common/ut/ya.make index 807076990300..c690ba31d168 100644 --- a/ydb/core/fq/libs/common/ut/ya.make +++ b/ydb/core/fq/libs/common/ut/ya.make @@ -9,6 +9,7 @@ ENDIF() SRCS( cache_ut.cpp entity_id_ut.cpp + iceberg_processor_ut.cpp rows_proto_splitter_ut.cpp util_ut.cpp ) diff --git a/ydb/core/fq/libs/common/util.cpp b/ydb/core/fq/libs/common/util.cpp index 415277c30844..4aedd57763c1 100644 --- a/ydb/core/fq/libs/common/util.cpp +++ b/ydb/core/fq/libs/common/util.cpp @@ -143,6 +143,9 @@ TString ExtractServiceAccountId(const FederatedQuery::ConnectionSetting& setting case FederatedQuery::ConnectionSetting::kLogging: { return GetServiceAccountId(setting.logging().auth()); } + case FederatedQuery::ConnectionSetting::kIceberg: { + return GetServiceAccountId(setting.iceberg().warehouse_auth()); + } // Do not replace with default. Adding a new connection should cause a compilation error case FederatedQuery::ConnectionSetting::CONNECTION_NOT_SET: break; @@ -180,6 +183,8 @@ TMaybe GetLogin(const FederatedQuery::ConnectionSetting& setting) { return setting.mysql_cluster().login(); case FederatedQuery::ConnectionSetting::kLogging: return {}; + case FederatedQuery::ConnectionSetting::kIceberg: + return {}; } } @@ -205,6 +210,8 @@ TMaybe GetPassword(const FederatedQuery::ConnectionSetting& setting) { return setting.mysql_cluster().password(); case FederatedQuery::ConnectionSetting::kLogging: return {}; + case FederatedQuery::ConnectionSetting::kIceberg: + return {}; } } @@ -230,6 +237,9 @@ EYdbComputeAuth GetYdbComputeAuthMethod(const FederatedQuery::ConnectionSetting& return GetBasicAuthMethod(setting.mysql_cluster().auth()); case FederatedQuery::ConnectionSetting::kLogging: return GetIamAuthMethod(setting.logging().auth()); + case FederatedQuery::ConnectionSetting::kIceberg: + return GetIamAuthMethod(setting.iceberg().warehouse_auth()); + } } @@ -253,6 +263,8 @@ FederatedQuery::IamAuth GetAuth(const FederatedQuery::Connection& connection) { return connection.content().setting().mysql_cluster().auth(); case FederatedQuery::ConnectionSetting::kLogging: return connection.content().setting().logging().auth(); + case FederatedQuery::ConnectionSetting::kIceberg: + return connection.content().setting().iceberg().warehouse_auth(); case FederatedQuery::ConnectionSetting::CONNECTION_NOT_SET: return FederatedQuery::IamAuth{}; } @@ -278,6 +290,8 @@ FederatedQuery::IamAuth* GetMutableAuth(FederatedQuery::ConnectionSetting& setti return setting.mutable_mysql_cluster()->mutable_auth(); case FederatedQuery::ConnectionSetting::kLogging: return setting.mutable_logging()->mutable_auth(); + case FederatedQuery::ConnectionSetting::kIceberg: + return setting.mutable_iceberg()->mutable_warehouse_auth(); case FederatedQuery::ConnectionSetting::CONNECTION_NOT_SET: return nullptr; } diff --git a/ydb/core/fq/libs/common/ya.make b/ydb/core/fq/libs/common/ya.make index ab8b621282fd..a42f1dd1c0cd 100644 --- a/ydb/core/fq/libs/common/ya.make +++ b/ydb/core/fq/libs/common/ya.make @@ -9,9 +9,11 @@ SRCS( debug_info.cpp entity_id.cpp entity_id.h - util.cpp + iceberg_processor.cpp + iceberg_processor.h rows_proto_splitter.cpp rows_proto_splitter.h + util.cpp ) PEERDIR( diff --git a/ydb/core/fq/libs/compute/common/config.h b/ydb/core/fq/libs/compute/common/config.h index 579869553e12..9961e1882940 100644 --- a/ydb/core/fq/libs/compute/common/config.h +++ b/ydb/core/fq/libs/compute/common/config.h @@ -159,7 +159,10 @@ class TComputeConfig { case NConfig::TYdbComputeControlPlane::TYPE_NOT_SET: return {}; case NConfig::TYdbComputeControlPlane::kSingle: - return controlPlane.GetSingle().GetWorkloadManagerConfig(); + if (controlPlane.GetSingle().HasWorkloadManagerConfig()) { + return controlPlane.GetSingle().GetWorkloadManagerConfig(); + } + return controlPlane.GetDefaultWorkloadManagerConfig(); case NConfig::TYdbComputeControlPlane::kCms: return GetWorkloadManagerConfig(scope, controlPlane.GetCms().GetDatabaseMapping()); case NConfig::TYdbComputeControlPlane::kYdbcp: @@ -169,7 +172,10 @@ class TComputeConfig { NFq::NConfig::TWorkloadManagerConfig GetWorkloadManagerConfig(const TString& scope, const ::NFq::NConfig::TDatabaseMapping& databaseMapping) const { auto computeDatabaseConfig = GetComputeDatabaseConfig(scope, databaseMapping); - return computeDatabaseConfig.GetWorkloadManagerConfig(); + if (computeDatabaseConfig.HasWorkloadManagerConfig()) { + return computeDatabaseConfig.GetWorkloadManagerConfig(); + } + return ComputeConfig.GetYdb().GetControlPlane().GetDefaultWorkloadManagerConfig(); } NFq::NConfig::TComputeDatabaseConfig GetComputeDatabaseConfig(const TString& scope, const ::NFq::NConfig::TDatabaseMapping& databaseMapping) const { @@ -238,6 +244,7 @@ class TComputeConfig { case FederatedQuery::ConnectionSetting::kMysqlCluster: case FederatedQuery::ConnectionSetting::kYdbDatabase: case FederatedQuery::ConnectionSetting::kLogging: + case FederatedQuery::ConnectionSetting::kIceberg: return true; case FederatedQuery::ConnectionSetting::kDataStreams: case FederatedQuery::ConnectionSetting::kMonitoring: diff --git a/ydb/core/fq/libs/compute/ydb/control_plane/compute_database_control_plane_service.cpp b/ydb/core/fq/libs/compute/ydb/control_plane/compute_database_control_plane_service.cpp index 7326b1845b14..64ea30faeb36 100644 --- a/ydb/core/fq/libs/compute/ydb/control_plane/compute_database_control_plane_service.cpp +++ b/ydb/core/fq/libs/compute/ydb/control_plane/compute_database_control_plane_service.cpp @@ -89,7 +89,7 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrappedGet()->CloudId, Request.Get()->Get()->Scope, singleConfig.GetConnection(), singleConfig.GetWorkloadManagerConfig()}); + Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, singleConfig.GetConnection(), GetWorkloadManagerConfig(singleConfig)}); } break; case NConfig::TYdbComputeControlPlane::kCms: @@ -163,7 +163,7 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrappedGet()->CloudId, Request.Get()->Get()->Scope, Result.connection(), client->Config.GetWorkloadManagerConfig()}); + Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, Result.connection(), GetWorkloadManagerConfig(client->Config)}); } else { auto invalidateSynchronizationEvent = std::make_unique(Request->Get()->CloudId, Scope); invalidateSynchronizationEvent->Synchronized = false; @@ -199,7 +199,7 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrappedCookie == OnlyDatabaseCreateCookie) { - Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, Result.connection(), client->Config.GetWorkloadManagerConfig()}); + Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, Result.connection(), GetWorkloadManagerConfig(client->Config)}); return; } Send(ControlPlaneStorageServiceActorId(), new TEvControlPlaneStorage::TEvCreateDatabaseRequest{Request->Get()->CloudId, Scope, Result}); @@ -266,7 +266,7 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrappedGet()->CloudId, Request.Get()->Get()->Scope, Result.connection(), client->Config.GetWorkloadManagerConfig()}); + Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, Result.connection(), GetWorkloadManagerConfig(client->Config)}); } void Handle(TEvYdbCompute::TEvSynchronizeResponse::TPtr& ev) { @@ -298,11 +298,20 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrapped + NConfig::TWorkloadManagerConfig GetWorkloadManagerConfig(const TComputeConfig& config) const { + if (config.HasWorkloadManagerConfig()) { + return config.GetWorkloadManagerConfig(); + } + return Config.GetYdb().GetControlPlane().GetDefaultWorkloadManagerConfig(); + } + private: TString Scope; std::shared_ptr Clients; TActorId SynchronizationServiceActorId; - NFq::NConfig::TComputeConfig Config; + NConfig::TComputeConfig Config; TEvYdbCompute::TEvCreateDatabaseRequest::TPtr Request; FederatedQuery::Internal::ComputeDatabaseInternal Result; diff --git a/ydb/core/fq/libs/config/protos/compute.proto b/ydb/core/fq/libs/config/protos/compute.proto index 172a6092b1cc..e6bfcf08e02e 100644 --- a/ydb/core/fq/libs/config/protos/compute.proto +++ b/ydb/core/fq/libs/config/protos/compute.proto @@ -86,6 +86,7 @@ message TYdbComputeControlPlane { } string DatabasePrefix = 5; string DatabasesCacheReloadPeriod = 6; + TWorkloadManagerConfig DefaultWorkloadManagerConfig = 7; } message TYdbCompute { diff --git a/ydb/core/fq/libs/config/protos/fq_config.proto b/ydb/core/fq/libs/config/protos/fq_config.proto index edbf50b40b65..7c819561792b 100644 --- a/ydb/core/fq/libs/config/protos/fq_config.proto +++ b/ydb/core/fq/libs/config/protos/fq_config.proto @@ -23,6 +23,7 @@ import "ydb/core/fq/libs/config/protos/rate_limiter.proto"; import "ydb/core/fq/libs/config/protos/read_actors_factory.proto"; import "ydb/core/fq/libs/config/protos/resource_manager.proto"; import "ydb/core/fq/libs/config/protos/row_dispatcher.proto"; +import "ydb/core/fq/libs/config/protos/task_controller.proto"; import "ydb/core/fq/libs/config/protos/test_connection.proto"; import "ydb/core/fq/libs/config/protos/token_accessor.proto"; import "ydb/library/folder_service/proto/config.proto"; @@ -55,4 +56,5 @@ message TConfig { bool EnableTaskCounters = 23; TComputeConfig Compute = 24; TRowDispatcherConfig RowDispatcher = 25; + TTaskControllerConfig TaskController = 26; } diff --git a/ydb/core/fq/libs/config/protos/task_controller.proto b/ydb/core/fq/libs/config/protos/task_controller.proto new file mode 100644 index 000000000000..1d97ae640826 --- /dev/null +++ b/ydb/core/fq/libs/config/protos/task_controller.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +option cc_enable_arenas = true; + +package NFq.NConfig; +option java_package = "ru.yandex.kikimr.proto"; + +//////////////////////////////////////////////////////////// + +message TTaskControllerConfig { + string PingPeriod = 1; + string AggrPeriod = 2; +} diff --git a/ydb/core/fq/libs/config/protos/ya.make b/ydb/core/fq/libs/config/protos/ya.make index a8abe477a6f5..9b693a72297c 100644 --- a/ydb/core/fq/libs/config/protos/ya.make +++ b/ydb/core/fq/libs/config/protos/ya.make @@ -24,6 +24,7 @@ SRCS( resource_manager.proto row_dispatcher.proto storage.proto + task_controller.proto test_connection.proto token_accessor.proto ) diff --git a/ydb/core/fq/libs/control_plane_proxy/actors/query_utils.cpp b/ydb/core/fq/libs/control_plane_proxy/actors/query_utils.cpp index 08891b3da47a..7d310eb0a6d8 100644 --- a/ydb/core/fq/libs/control_plane_proxy/actors/query_utils.cpp +++ b/ydb/core/fq/libs/control_plane_proxy/actors/query_utils.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace NFq { namespace NPrivate { @@ -293,8 +294,8 @@ TString MakeCreateExternalDataSourceQuery( "database_name"_a = EncloseAndEscapeString(connectionContent.setting().postgresql_cluster().database_name(), '"'), "use_tls"_a = common.GetDisableSslForGenericDataSources() ? "false" : "true", "schema"_a = pgschema ? ", SCHEMA=" + EncloseAndEscapeString(pgschema, '"') : TString{}); + break; } - break; case FederatedQuery::ConnectionSetting::kGreenplumCluster: { const auto gpschema = connectionContent.setting().greenplum_cluster().schema(); properties = fmt::format( @@ -309,8 +310,13 @@ TString MakeCreateExternalDataSourceQuery( "database_name"_a = EncloseAndEscapeString(connectionContent.setting().greenplum_cluster().database_name(), '"'), "use_tls"_a = common.GetDisableSslForGenericDataSources() ? "false" : "true", "schema"_a = gpschema ? ", SCHEMA=" + EncloseAndEscapeString(gpschema, '"') : TString{}); + break; + } + case FederatedQuery::ConnectionSetting::kIceberg: { + auto settings = connectionContent.setting().iceberg(); + properties = NFq::MakeIcebergCreateExternalDataSourceProperties(common, settings); + break; } - break; case FederatedQuery::ConnectionSetting::kMysqlCluster: { properties = fmt::format( R"( @@ -333,7 +339,6 @@ TString MakeCreateExternalDataSourceQuery( "folder_id"_a = EncloseAndEscapeString(connectionContent.setting().logging().folder_id(), '"')); break; } - break; } auto sourceName = connectionContent.name(); diff --git a/ydb/core/fq/libs/control_plane_proxy/utils/utils.h b/ydb/core/fq/libs/control_plane_proxy/utils/utils.h index cfe0f7edd7c1..ae11c0fb8abb 100644 --- a/ydb/core/fq/libs/control_plane_proxy/utils/utils.h +++ b/ydb/core/fq/libs/control_plane_proxy/utils/utils.h @@ -40,6 +40,9 @@ TString ExtractServiceAccountIdWithConnection(const T& setting) { case FederatedQuery::ConnectionSetting::kLogging: { return GetServiceAccountId(setting.logging().auth()); } + case FederatedQuery::ConnectionSetting::kIceberg: { + return GetServiceAccountId(setting.iceberg().warehouse_auth()); + } // Do not replace with default. Adding a new connection should cause a compilation error case FederatedQuery::ConnectionSetting::CONNECTION_NOT_SET: break; diff --git a/ydb/core/fq/libs/control_plane_storage/events/events.h b/ydb/core/fq/libs/control_plane_storage/events/events.h index d5b83f58da3d..1cf6244f6670 100644 --- a/ydb/core/fq/libs/control_plane_storage/events/events.h +++ b/ydb/core/fq/libs/control_plane_storage/events/events.h @@ -680,31 +680,36 @@ struct TEvControlPlaneStorage { }; struct TEvCreateDatabaseRequest : NActors::TEventLocal { + using TProto = FederatedQuery::Internal::ComputeDatabaseInternal; + TEvCreateDatabaseRequest() = default; explicit TEvCreateDatabaseRequest(const TString& cloudId, const TString& scope, const FederatedQuery::Internal::ComputeDatabaseInternal& record) : CloudId(cloudId) , Scope(scope) - , Record(record) + , Request(record) {} size_t GetByteSize() const { return sizeof(*this) + CloudId.size() + Scope.size() - + Record.ByteSizeLong(); + + Request.ByteSizeLong(); } TString CloudId; TString Scope; - FederatedQuery::Internal::ComputeDatabaseInternal Record; + FederatedQuery::Internal::ComputeDatabaseInternal Request; }; struct TEvCreateDatabaseResponse : NActors::TEventLocal { + using TProto = google::protobuf::Empty; + static constexpr bool Auditable = false; - explicit TEvCreateDatabaseResponse() - {} + explicit TEvCreateDatabaseResponse(const google::protobuf::Empty& response = {}) { + Y_UNUSED(response); + } explicit TEvCreateDatabaseResponse(const NYql::TIssues& issues) : Issues(issues) @@ -721,6 +726,7 @@ struct TEvControlPlaneStorage { }; struct TEvDescribeDatabaseRequest : NActors::TEventLocal { + using TProto = google::protobuf::Empty; TEvDescribeDatabaseRequest() = default; @@ -744,6 +750,8 @@ struct TEvControlPlaneStorage { struct TEvDescribeDatabaseResponse : NActors::TEventLocal { static constexpr bool Auditable = false; + using TProto = FederatedQuery::Internal::ComputeDatabaseInternal; + explicit TEvDescribeDatabaseResponse(const FederatedQuery::Internal::ComputeDatabaseInternal& record) : Record(record) {} @@ -767,6 +775,8 @@ struct TEvControlPlaneStorage { }; struct TEvModifyDatabaseRequest : NActors::TEventLocal { + using TProto = google::protobuf::Empty; + TEvModifyDatabaseRequest() = default; explicit TEvModifyDatabaseRequest(const TString& cloudId, const TString& scope) @@ -776,10 +786,12 @@ struct TEvControlPlaneStorage { size_t GetByteSize() const { return sizeof(*this) + + Request.ByteSizeLong() + CloudId.size() + Scope.size(); } + google::protobuf::Empty Request; TString CloudId; TString Scope; TMaybe Synchronized; @@ -788,10 +800,13 @@ struct TEvControlPlaneStorage { }; struct TEvModifyDatabaseResponse : NActors::TEventLocal { + using TProto = google::protobuf::Empty; + static constexpr bool Auditable = false; - explicit TEvModifyDatabaseResponse() - {} + explicit TEvModifyDatabaseResponse(const google::protobuf::Empty& response = {}) { + Y_UNUSED(response); + } explicit TEvModifyDatabaseResponse(const NYql::TIssues& issues) : Issues(issues) diff --git a/ydb/core/fq/libs/control_plane_storage/in_memory_control_plane_storage.cpp b/ydb/core/fq/libs/control_plane_storage/in_memory_control_plane_storage.cpp index 55e67b1f1908..ea10988aa31f 100644 --- a/ydb/core/fq/libs/control_plane_storage/in_memory_control_plane_storage.cpp +++ b/ydb/core/fq/libs/control_plane_storage/in_memory_control_plane_storage.cpp @@ -146,6 +146,21 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor Values; }; + struct TComputeDatabases { + struct TKey { + TString Scope; + + std::strong_ordering operator<=>(const TKey& other) const = default; + }; + + struct TValue { + FederatedQuery::Internal::ComputeDatabaseInternal Database; + TInstant LastAccessAt; + }; + + TMap Values; + }; + using TBase = TControlPlaneStorageBase; TQueries Queries; @@ -156,6 +171,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor + template class TCommonRequestContext { public: using TResultType = TPrepareResponseResultType; @@ -232,9 +256,11 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(EventPtr->Sender, issues, EventPtr->Cookie, TInstant::Now() - StartTime, RequestCounters); } @@ -286,9 +314,9 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor - class TRequestContext : public TCommonRequestContext { - using TBase = TCommonRequestContext; + template + class TRequestContext : public TCommonRequestContext { + using TBase = TCommonRequestContext; Y_HAS_MEMBER(idempotency_key); static constexpr bool HasIdempotencyKey = THasidempotency_key::value; @@ -360,26 +388,26 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor; \ - void Handle(TEvControlPlaneStorage::TEvRequest::TPtr& ev) { \ - TContext##TEvRequest ctx(*this, ev, #TEvRequest, #TEvResponse); \ - if (!ctx.Validate()) { \ - return; \ - } \ - try { \ - Process##TRequest(ctx); \ - } catch (...) { \ - const auto& backtrace = TBackTrace::FromCurrentException().PrintToString(); \ - const auto logError = TStringBuilder() << "pocess "#TEvRequest" call, back trace:\n" << backtrace; \ - ctx.Fail(logError, {NYql::TIssue(CurrentExceptionMessage())}); \ - } \ - } \ +#define HANDLE_CPS_REQUEST_IMPL(TEvRequest, TEvResponse, TContext, RTS_COUNTERS_ENUM, RTC_COUNTERS_ENUM, VALIDATE_REQUEST) \ + using TContext##TEvRequest = TContext< \ + TEvControlPlaneStorage::TEvRequest, TEvControlPlaneStorage::TEvResponse, \ + RTS_COUNTERS_ENUM, RTC_COUNTERS_ENUM, VALIDATE_REQUEST>; \ + void Handle(TEvControlPlaneStorage::TEvRequest::TPtr& ev) { \ + TContext##TEvRequest ctx(*this, ev, #TEvRequest, #TEvResponse); \ + if (!ctx.Validate()) { \ + return; \ + } \ + try { \ + Process##TRequest(ctx); \ + } catch (...) { \ + const auto& backtrace = TBackTrace::FromCurrentException().PrintToString(); \ + const auto logError = TStringBuilder() << "pocess "#TEvRequest" call, back trace:\n" << backtrace; \ + ctx.Fail(logError, {NYql::TIssue(CurrentExceptionMessage())}); \ + } \ + } \ void Process##TRequest(TContext##TEvRequest& ctx) -#define HANDLE_CPS_REQUEST(TEvRequest, TEvResponse, COUNTERS_ENUM) HANDLE_CPS_REQUEST_IMPL(TEvRequest, TEvResponse, TRequestContext, RTS_##COUNTERS_ENUM, RTC_##COUNTERS_ENUM) +#define HANDLE_CPS_REQUEST(TEvRequest, TEvResponse, COUNTERS_ENUM) HANDLE_CPS_REQUEST_IMPL(TEvRequest, TEvResponse, TRequestContext, RTS_##COUNTERS_ENUM, RTC_##COUNTERS_ENUM, true) HANDLE_CPS_REQUEST(TEvCreateQueryRequest, TEvCreateQueryResponse, CREATE_QUERY) { const auto& [query, job] = GetCreateQueryProtos(ctx.Request, ctx.User, ctx.StartTime); @@ -548,20 +576,56 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(ev, "ListConnectionsRequest"); + HANDLE_CPS_REQUEST(TEvListConnectionsRequest, TEvListConnectionsResponse, LIST_CONNECTIONS) { + auto connections = GetEntities(Connections, ctx.Scope, ctx.User); + auto& resultConnections = *ctx.Response.mutable_connection(); + const auto& filter = ctx.Request.filter(); + + auto it = std::lower_bound(connections.begin(), connections.end(), ctx.Request.page_token(), [](const auto& l, const auto& r) { + return l.meta().id() < r; + }); + for (; it != connections.end(); ++it) { + const auto& content = it->content(); + if (const auto& nameFilter = filter.name()) { + const auto& name = content.name(); + if (ctx.Event.IsExactNameMatch ? name != nameFilter : !name.Contains(nameFilter)) { + continue; + } + } + + if (filter.created_by_me() && it->meta().created_by() != ctx.User) { + continue; + } + + if (filter.connection_type() != FederatedQuery::ConnectionSetting::CONNECTION_TYPE_UNSPECIFIED && content.setting().connection_case() != static_cast(filter.connection_type())) { + continue; + } + + if (filter.visibility() != FederatedQuery::Acl::VISIBILITY_UNSPECIFIED && content.acl().visibility() != filter.visibility()) { + continue; + } + + *resultConnections.Add() = *it; + if (resultConnections.size() == ctx.Request.limit() + 1) { + ctx.Response.set_next_page_token(ctx.Response.connection(ctx.Response.connection_size() - 1).meta().id()); + resultConnections.RemoveLast(); + break; + } + } } - void Handle(TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr& ev) { - LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); - SendEmptyResponse< - TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr, - FederatedQuery::DescribeConnectionResult, - TEvControlPlaneStorage::TEvDescribeConnectionResponse>(ev, "DescribeConnectionRequest"); + HANDLE_CPS_REQUEST(TEvDescribeConnectionRequest, TEvDescribeConnectionResponse, DESCRIBE_CONNECTION) { + const auto& connection = GetEntity(Connections, {ctx.Scope, ctx.Request.connection_id()}); + if (!connection) { + return ctx.Fail("find connection", {NYql::TIssue("Connection does not exist")}); + } + + const auto& connectionProto = connection->Connection; + if (!HasViewAccess(GetPermissions(ctx.Permissions, ctx.User), connectionProto.content().acl().visibility(), connectionProto.meta().created_by(), ctx.User)) { + return ctx.Fail("check permissions", {NYql::TIssue("Permission denied")}); + } + + *ctx.Response.mutable_connection() = connectionProto; } void Handle(TEvControlPlaneStorage::TEvModifyConnectionRequest::TPtr& ev) { @@ -622,12 +686,61 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(ev, "ListBindingsRequest"); + HANDLE_CPS_REQUEST(TEvListBindingsRequest, TEvListBindingsResponse, LIST_BINDINGS) { + auto bindings = GetEntities(Bindings, ctx.Scope, ctx.User); + auto& resultBindings = *ctx.Response.mutable_binding(); + const auto& filter = ctx.Request.filter(); + + auto it = std::lower_bound(bindings.begin(), bindings.end(), ctx.Request.page_token(), [](const auto& l, const auto& r) { + return l.meta().id() < r; + }); + for (; it != bindings.end(); ++it) { + const auto& content = it->content(); + const auto& connectionId = content.connection_id(); + if (filter.connection_id() && connectionId != filter.connection_id()) { + continue; + } + + const auto& name = content.name(); + if (const auto& nameFilter = filter.name()) { + if (ctx.Event.IsExactNameMatch ? name != nameFilter : !name.Contains(nameFilter)) { + continue; + } + } + + const auto& meta = it->meta(); + if (filter.created_by_me() && meta.created_by() != ctx.User) { + continue; + } + + const auto visibility = content.acl().visibility(); + if (filter.visibility() != FederatedQuery::Acl::VISIBILITY_UNSPECIFIED && visibility != filter.visibility()) { + continue; + } + + auto& resultBinding = *resultBindings.Add(); + resultBinding.set_name(name); + resultBinding.set_connection_id(connectionId); + resultBinding.set_visibility(visibility); + *resultBinding.mutable_meta() = meta; + + switch (content.setting().binding_case()) { + case FederatedQuery::BindingSetting::kDataStreams: + resultBinding.set_type(FederatedQuery::BindingSetting::DATA_STREAMS); + break; + case FederatedQuery::BindingSetting::kObjectStorage: + resultBinding.set_type(FederatedQuery::BindingSetting::OBJECT_STORAGE); + break; + case FederatedQuery::BindingSetting::BINDING_NOT_SET: + break; + } + + if (resultBindings.size() == ctx.Request.limit() + 1) { + ctx.Response.set_next_page_token(ctx.Response.binding(ctx.Response.binding_size() - 1).meta().id()); + resultBindings.RemoveLast(); + break; + } + } } void Handle(TEvControlPlaneStorage::TEvDescribeBindingRequest::TPtr& ev) { @@ -664,7 +777,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(ev, "DescribeJobRequest"); } - HANDLE_CPS_REQUEST_IMPL(TEvWriteResultDataRequest, TEvWriteResultDataResponse, TCommonRequestContext, RTS_MAX, RTC_WRITE_RESULT_DATA) { + HANDLE_CPS_REQUEST_IMPL(TEvWriteResultDataRequest, TEvWriteResultDataResponse, TCommonRequestContext, RTS_MAX, RTC_WRITE_RESULT_DATA, true) { ctx.Response.set_request_id(ctx.Request.request_id()); const auto offset = ctx.Request.offset(); @@ -679,7 +792,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor tasks; @@ -696,7 +809,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActorStatus, finalStatus->StatusCode, finalStatus->QueryType, finalStatus->Issues, finalStatus->TransientIssues)); } - HANDLE_CPS_REQUEST_IMPL(TEvNodesHealthCheckRequest, TEvNodesHealthCheckResponse, TCommonRequestContext, RTS_MAX, RTC_NODES_HEALTH_CHECK) { + HANDLE_CPS_REQUEST_IMPL(TEvNodesHealthCheckRequest, TEvNodesHealthCheckResponse, TCommonRequestContext, RTS_MAX, RTC_NODES_HEALTH_CHECK, true) { const auto& tenant = ctx.Request.tenant(); const auto& node = ctx.Request.node(); @@ -747,6 +860,83 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(ev, "GetQueryStatusRequest"); + } + + void Handle(TEvControlPlaneStorage::TEvCreateRateLimiterResourceRequest::TPtr& ev) { + LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); + SendEmptyResponse< + TEvControlPlaneStorage::TEvCreateRateLimiterResourceRequest::TPtr, + Fq::Private::CreateRateLimiterResourceResult, + TEvControlPlaneStorage::TEvCreateRateLimiterResourceResponse>(ev, "CreateRateLimiterResourceRequest"); + } + + void Handle(TEvControlPlaneStorage::TEvDeleteRateLimiterResourceRequest::TPtr& ev) { + LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); + SendEmptyResponse< + TEvControlPlaneStorage::TEvDeleteRateLimiterResourceRequest::TPtr, + Fq::Private::DeleteRateLimiterResourceResult, + TEvControlPlaneStorage::TEvDeleteRateLimiterResourceResponse>(ev, "DeleteRateLimiterResourceRequest"); + } + + void Handle(TEvQuotaService::TQuotaUsageRequest::TPtr& ev) { + LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); + Send(ev->Sender, new TEvQuotaService::TQuotaUsageResponse(ev->Get()->SubjectType, ev->Get()->SubjectId, ev->Get()->MetricName, 0)); + } + + void Handle(TEvQuotaService::TQuotaLimitChangeRequest::TPtr& ev) { + LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); + Send(ev->Sender, new TEvQuotaService::TQuotaLimitChangeResponse(ev->Get()->SubjectType, ev->Get()->SubjectId, ev->Get()->MetricName, ev->Get()->Limit, ev->Get()->LimitRequested)); + } + + HANDLE_CPS_REQUEST_IMPL(TEvCreateDatabaseRequest, TEvCreateDatabaseResponse, TCommonRequestContext, RTS_CREATE_DATABASE, RTC_CREATE_DATABASE, false) { + AddEntity(ComputeDatabases, {ctx.Event.Scope}, { + .Database = ctx.Request, + .LastAccessAt = TInstant::Now() + }); + } + + HANDLE_CPS_REQUEST_IMPL(TEvDescribeDatabaseRequest, TEvDescribeDatabaseResponse, TCommonRequestContext, RTS_DESCRIBE_DATABASE, RTC_DESCRIBE_DATABASE, false) { + const auto& database = GetEntity(ComputeDatabases, {ctx.Event.Scope}); + if (!database) { + NYql::TIssue issue(TStringBuilder() << "Compute database does not exist for scope " << ctx.Event.Scope); + issue.SetCode(TIssuesIds::ACCESS_DENIED, NYql::TSeverityIds::S_ERROR); + return ctx.Fail("find compute database", {issue}); + } + + ctx.Response = database->Database; + } + + HANDLE_CPS_REQUEST_IMPL(TEvModifyDatabaseRequest, TEvModifyDatabaseResponse, TCommonRequestContext, RTS_MODIFY_DATABASE, RTC_MODIFY_DATABASE, false) { + const auto it = ComputeDatabases.Values.find({ctx.Event.Scope}); + + if (const auto lastAccessAt = ctx.Event.LastAccessAt) { + if (it != ComputeDatabases.Values.end()) { + it->second.LastAccessAt = *lastAccessAt; + } + return; + } + + if (it == ComputeDatabases.Values.end()) { + NYql::TIssue issue(TStringBuilder() << "Compute database does not exist for scope " << ctx.Event.Scope); + issue.SetCode(TIssuesIds::ACCESS_DENIED, NYql::TSeverityIds::S_ERROR); + return ctx.Fail("update compute database", {issue}); + } + + if (const auto synchronized = ctx.Event.Synchronized) { + it->second.Database.set_synchronized(*synchronized); + } + + if (const auto wmSynchronized = ctx.Event.WorkloadManagerSynchronized) { + it->second.Database.set_workload_manager_synchronized(*wmSynchronized); + } + } + #undef HANDLE_CPS_REQUEST #undef HANDLE_CPS_REQUEST_IMPL @@ -857,6 +1047,16 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActorProto.GetEnablePermissions() + ? requestPermissions + : TPermissions{TPermissions::VIEW_PUBLIC}; + if (IsSuperUser(user)) { + permissions.SetAll(); + } + return permissions; + } + private: void Cleanup() { CleanupTable(Queries); @@ -926,7 +1126,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor AssignTask(const TCommonRequestContextTEvGetTaskRequest& ctx, TTaskInternal taskInternal) { + std::optional AssignTask(TCommonRequestContextTEvGetTaskRequest& ctx, TTaskInternal taskInternal) { auto& task = taskInternal.Task; const auto& query = GetEntity(Queries, {task.Scope, task.QueryId}); diff --git a/ydb/core/fq/libs/control_plane_storage/internal/task_ping.cpp b/ydb/core/fq/libs/control_plane_storage/internal/task_ping.cpp index 0ea26139ce77..b852d663ca75 100644 --- a/ydb/core/fq/libs/control_plane_storage/internal/task_ping.cpp +++ b/ydb/core/fq/libs/control_plane_storage/internal/task_ping.cpp @@ -65,7 +65,7 @@ TYdbControlPlaneStorageActor::TPingTaskParams TYdbControlPlaneStorageActor::Cons " WHERE `" SCOPE_COLUMN_NAME "` = $scope AND `" QUERY_ID_COLUMN_NAME "` = $query_id;\n" "SELECT `" JOB_ID_COLUMN_NAME "`, `" JOB_COLUMN_NAME "` FROM `" JOBS_TABLE_NAME "`\n" " WHERE `" SCOPE_COLUMN_NAME "` = $scope AND `" QUERY_ID_COLUMN_NAME "` = $query_id AND `" JOB_ID_COLUMN_NAME "` = $last_job_id;\n" - "SELECT `" OWNER_COLUMN_NAME "`, `" RETRY_COUNTER_COLUMN_NAME "`, `" RETRY_COUNTER_UPDATE_COLUMN_NAME "`, `" RETRY_RATE_COLUMN_NAME "`\n" + "SELECT `" OWNER_COLUMN_NAME "`, `" RETRY_COUNTER_COLUMN_NAME "`, `" RETRY_COUNTER_UPDATE_COLUMN_NAME "`, `" RETRY_RATE_COLUMN_NAME "`, `" ASSIGNED_UNTIL_COLUMN_NAME "`\n" "FROM `" PENDING_SMALL_TABLE_NAME "` WHERE `" TENANT_COLUMN_NAME "` = $tenant AND `" SCOPE_COLUMN_NAME "` = $scope AND `" QUERY_ID_COLUMN_NAME "` = $query_id;\n" ); @@ -119,6 +119,8 @@ TYdbControlPlaneStorageActor::TPingTaskParams TYdbControlPlaneStorageActor::Cons if (owner != request.owner_id()) { ythrow NYql::TCodeLineException(TIssuesIds::BAD_REQUEST) << "OWNER of QUERY ID = \"" << request.query_id().value() << "\" MISMATCHED: \"" << request.owner_id() << "\" (received) != \"" << owner << "\" (selected)"; } + auto assignedUntil = parser.ColumnParser(ASSIGNED_UNTIL_COLUMN_NAME).GetOptionalTimestamp().value_or(TInstant::Now()); + Counters.LeaseLeftMs->Collect((assignedUntil - TInstant::Now()).MilliSeconds()); retryLimiter.Assign( parser.ColumnParser(RETRY_COUNTER_COLUMN_NAME).GetOptionalUint64().value_or(0), parser.ColumnParser(RETRY_COUNTER_UPDATE_COLUMN_NAME).GetOptionalTimestamp().value_or(TInstant::Zero()), @@ -252,7 +254,7 @@ TYdbControlPlaneStorageActor::TPingTaskParams TYdbControlPlaneStorageActor::Cons readQueryBuilder.AddText( "SELECT `" INTERNAL_COLUMN_NAME "`\n" "FROM `" QUERIES_TABLE_NAME "` WHERE `" QUERY_ID_COLUMN_NAME "` = $query_id AND `" SCOPE_COLUMN_NAME "` = $scope;\n" - "SELECT `" OWNER_COLUMN_NAME "`\n" + "SELECT `" OWNER_COLUMN_NAME "`, `" ASSIGNED_UNTIL_COLUMN_NAME "`\n" "FROM `" PENDING_SMALL_TABLE_NAME "` WHERE `" TENANT_COLUMN_NAME "` = $tenant AND `" SCOPE_COLUMN_NAME "` = $scope AND `" QUERY_ID_COLUMN_NAME "` = $query_id;\n" ); @@ -285,6 +287,8 @@ TYdbControlPlaneStorageActor::TPingTaskParams TYdbControlPlaneStorageActor::Cons if (owner != request.owner_id()) { ythrow NYql::TCodeLineException(TIssuesIds::BAD_REQUEST) << "OWNER of QUERY ID = \"" << request.query_id().value() << "\" MISMATCHED: \"" << request.owner_id() << "\" (received) != \"" << owner << "\" (selected)"; } + auto assignedUntil = parser.ColumnParser(ASSIGNED_UNTIL_COLUMN_NAME).GetOptionalTimestamp().value_or(TInstant::Now()); + Counters.LeaseLeftMs->Collect((assignedUntil - TInstant::Now()).MilliSeconds()); } TInstant ttl = TInstant::Now() + Config->TaskLeaseTtl; @@ -657,7 +661,9 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvPingTaskReq std::shared_ptr response = std::make_shared(); std::shared_ptr finalStatus = std::make_shared(); - auto pingTaskParams = DoesPingTaskUpdateQueriesTable(request) ? + bool isHard = DoesPingTaskUpdateQueriesTable(request); + Counters.Counters->GetCounter(isHard ? "HardPing" : "SoftPing", true)->Inc(); + auto pingTaskParams = isHard ? ConstructHardPingTask(request, response, finalStatus, requestCounters.Common) : ConstructSoftPingTask(request, response, requestCounters.Common); auto debugInfo = Config->Proto.GetEnableDebugMode() ? std::make_shared() : TDebugInfoPtr{}; diff --git a/ydb/core/fq/libs/control_plane_storage/request_validators.cpp b/ydb/core/fq/libs/control_plane_storage/request_validators.cpp index 5e0d7abeb9bf..397488b09e03 100644 --- a/ydb/core/fq/libs/control_plane_storage/request_validators.cpp +++ b/ydb/core/fq/libs/control_plane_storage/request_validators.cpp @@ -1,3 +1,5 @@ +#include + #include "request_validators.h" namespace NFq { @@ -147,6 +149,11 @@ NYql::TIssues ValidateConnectionSetting( break; } + case FederatedQuery::ConnectionSetting::kIceberg: { + TIcebergProcessor p(setting.iceberg(), issues); + p.Process(); + break; + } case FederatedQuery::ConnectionSetting::CONNECTION_NOT_SET: { issues.AddIssue(MakeErrorIssue(TIssuesIds::BAD_REQUEST, "connection is not set")); break; diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_bindings.cpp b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_bindings.cpp index a643a520f32e..5619ea8833c8 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_bindings.cpp +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_bindings.cpp @@ -179,6 +179,10 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvCreateBindi }); } +NYql::TIssues TControlPlaneStorageBase::ValidateRequest(TEvControlPlaneStorage::TEvListBindingsRequest::TPtr& ev) const { + return ValidateEvent(ev); +} + void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListBindingsRequest::TPtr& ev) { TInstant startTime = TInstant::Now(); @@ -205,8 +209,7 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListBinding << NKikimr::MaskTicket(token) << " " << request.DebugString()); - NYql::TIssues issues = ValidateEvent(ev); - if (issues) { + if (const auto& issues = ValidateRequest(ev)) { CPS_LOG_D(MakeLogPrefix(scope, user) << "ListBindingsRequest, validation failed: " << NKikimr::MaskTicket(token) << " " diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_compute_database.cpp b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_compute_database.cpp index c0e796bb5a0a..9a446f6875c3 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_compute_database.cpp +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_compute_database.cpp @@ -19,7 +19,7 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvCreateDatab TRequestCounters requestCounters = Counters.GetCounters(cloudId, scope, RTS_CREATE_DATABASE, RTC_CREATE_DATABASE); requestCounters.IncInFly(); requestCounters.Common->RequestBytes->Add(event.GetByteSize()); - const FederatedQuery::Internal::ComputeDatabaseInternal& request = event.Record; + const FederatedQuery::Internal::ComputeDatabaseInternal& request = event.Request; const int byteSize = request.ByteSize(); CPS_LOG_T(MakeLogPrefix(scope, "internal", request.id()) diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_connections.cpp b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_connections.cpp index 79be5ca2f107..2aa676a4f368 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_connections.cpp +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_connections.cpp @@ -43,6 +43,8 @@ void PrepareSensitiveFields(::FederatedQuery::Connection& connection, bool extra break; case FederatedQuery::ConnectionSetting::kLogging: break; + case FederatedQuery::ConnectionSetting::kIceberg: + break; case FederatedQuery::ConnectionSetting::CONNECTION_NOT_SET: break; } @@ -217,6 +219,10 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvCreateConne }); } +NYql::TIssues TControlPlaneStorageBase::ValidateRequest(TEvControlPlaneStorage::TEvListConnectionsRequest::TPtr& ev) const { + return ValidateEvent(ev); +} + void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListConnectionsRequest::TPtr& ev) { TInstant startTime = TInstant::Now(); @@ -245,8 +251,7 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListConnect << NKikimr::MaskTicket(token) << " " << request.DebugString()); - NYql::TIssues issues = ValidateEvent(ev); - if (issues) { + if (const auto& issues = ValidateRequest(ev)) { CPS_LOG_D(MakeLogPrefix(scope, user) << "ListConnectionsRequest, validation failed: " << NKikimr::MaskTicket(token) << " " @@ -352,6 +357,10 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListConnect }); } +NYql::TIssues TControlPlaneStorageBase::ValidateRequest(TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr& ev) const { + return ValidateEvent(ev); +} + void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr& ev) { TInstant startTime = TInstant::Now(); @@ -379,8 +388,7 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvDescribeCon << NKikimr::MaskTicket(token) << " " << request.DebugString()); - NYql::TIssues issues = ValidateEvent(ev); - if (issues) { + if (const auto& issues = ValidateRequest(ev)) { CPS_LOG_D(MakeLogPrefix(scope, user, connectionId) << "DescribeConnectionRequest, validation failed: " << NKikimr::MaskTicket(token)<< " " diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h index c8d102ee920b..7072c57815dc 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h @@ -522,11 +522,13 @@ class TControlPlaneStorageBase : public TControlPlaneStorageUtils { public: ::NMonitoring::TDynamicCounterPtr Counters; + ::NMonitoring::THistogramPtr LeaseLeftMs; explicit TCounters(const ::NMonitoring::TDynamicCounterPtr& counters, const ::NFq::TControlPlaneStorageConfig& config) : ScopeCounters{TTtlCacheSettings{}.SetTtl(config.MetricsTtl)} , FinalStatusCounters{TTtlCacheSettings{}.SetTtl(config.MetricsTtl)} , Counters(counters) + , LeaseLeftMs(Counters->GetHistogram("LeaseLeftMs", ::NMonitoring::ExplicitHistogram({100, 1000, 5000, 10000, 20000}))) { for (auto& request: CommonRequests) { request->Register(Counters); @@ -639,6 +641,14 @@ class TControlPlaneStorageBase : public TControlPlaneStorageUtils { std::pair GetCreateConnectionProtos( const FederatedQuery::CreateConnectionRequest& request, const TString& cloudId, const TString& user, TInstant startTime) const; + // List connections request + + NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvListConnectionsRequest::TPtr& ev) const; + + // Describe connections request + + NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr& ev) const; + // Create binding request NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvCreateBindingRequest::TPtr& ev) const; @@ -648,6 +658,10 @@ class TControlPlaneStorageBase : public TControlPlaneStorageUtils { std::pair GetCreateBindingProtos( const FederatedQuery::CreateBindingRequest& request, const TString& cloudId, const TString& user, TInstant startTime) const; + // List bindings request + + NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvListBindingsRequest::TPtr& ev) const; + // Write result data request NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvWriteResultDataRequest::TPtr& ev) const; diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_queries.cpp b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_queries.cpp index 26137ffebab2..bc7a00a1aa3e 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_queries.cpp +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_queries.cpp @@ -45,6 +45,8 @@ FederatedQuery::IamAuth::IdentityCase GetIamAuth(const FederatedQuery::Connectio return setting.mysql_cluster().auth().identity_case(); case FederatedQuery::ConnectionSetting::kLogging: return setting.logging().auth().identity_case(); + case FederatedQuery::ConnectionSetting::kIceberg: + return setting.iceberg().warehouse_auth().identity_case(); case FederatedQuery::ConnectionSetting::CONNECTION_NOT_SET: return FederatedQuery::IamAuth::IDENTITY_NOT_SET; } diff --git a/ydb/core/fq/libs/actors/database_resolver.cpp b/ydb/core/fq/libs/db_id_async_resolver_impl/database_resolver.cpp similarity index 100% rename from ydb/core/fq/libs/actors/database_resolver.cpp rename to ydb/core/fq/libs/db_id_async_resolver_impl/database_resolver.cpp diff --git a/ydb/core/fq/libs/actors/database_resolver.h b/ydb/core/fq/libs/db_id_async_resolver_impl/database_resolver.h similarity index 100% rename from ydb/core/fq/libs/actors/database_resolver.h rename to ydb/core/fq/libs/db_id_async_resolver_impl/database_resolver.h diff --git a/ydb/core/fq/libs/db_id_async_resolver_impl/http_proxy.cpp b/ydb/core/fq/libs/db_id_async_resolver_impl/http_proxy.cpp new file mode 100644 index 000000000000..ab49bd86f595 --- /dev/null +++ b/ydb/core/fq/libs/db_id_async_resolver_impl/http_proxy.cpp @@ -0,0 +1,10 @@ +#include "http_proxy.h" + +namespace NFq { + +NActors::TActorId MakeYqlAnalyticsHttpProxyId() { + constexpr TStringBuf name = "YQLHTTPROXY"; + return NActors::TActorId(0, name); +} + +} // namespace NFq diff --git a/ydb/core/fq/libs/db_id_async_resolver_impl/http_proxy.h b/ydb/core/fq/libs/db_id_async_resolver_impl/http_proxy.h new file mode 100644 index 000000000000..ab713401cd29 --- /dev/null +++ b/ydb/core/fq/libs/db_id_async_resolver_impl/http_proxy.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace NFq { + +NActors::TActorId MakeYqlAnalyticsHttpProxyId(); + +} // namespace NFq diff --git a/ydb/core/fq/libs/db_id_async_resolver_impl/ya.make b/ydb/core/fq/libs/db_id_async_resolver_impl/ya.make index 97b9ea6f273b..7a3bf5dbf79a 100644 --- a/ydb/core/fq/libs/db_id_async_resolver_impl/ya.make +++ b/ydb/core/fq/libs/db_id_async_resolver_impl/ya.make @@ -1,15 +1,26 @@ LIBRARY() SRCS( + database_resolver.cpp db_async_resolver_impl.cpp + http_proxy.cpp mdb_endpoint_generator.cpp ) PEERDIR( + library/cpp/json library/cpp/threading/future + ydb/core/fq/libs/common + ydb/core/fq/libs/config/protos ydb/core/fq/libs/events + ydb/core/util + ydb/library/actors/core + ydb/library/actors/http + ydb/library/services ydb/library/yql/providers/common/db_id_async_resolver + ydb/library/yql/providers/common/token_accessor/client ydb/library/yql/providers/dq/actors + yql/essentials/utils ) YQL_LAST_ABI_VERSION() diff --git a/ydb/core/fq/libs/init/init.cpp b/ydb/core/fq/libs/init/init.cpp index 8495e7ffe3e2..f965ee6bf19d 100644 --- a/ydb/core/fq/libs/init/init.cpp +++ b/ydb/core/fq/libs/init/init.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/ydb/core/fq/libs/init/ya.make b/ydb/core/fq/libs/init/ya.make index c4ad1e08b544..caaeb50b8b43 100644 --- a/ydb/core/fq/libs/init/ya.make +++ b/ydb/core/fq/libs/init/ya.make @@ -16,6 +16,7 @@ PEERDIR( ydb/core/fq/libs/control_plane_config ydb/core/fq/libs/control_plane_proxy ydb/core/fq/libs/control_plane_storage + ydb/core/fq/libs/db_id_async_resolver_impl ydb/core/fq/libs/events ydb/core/fq/libs/gateway ydb/core/fq/libs/health diff --git a/ydb/core/fq/libs/mock/ya.make b/ydb/core/fq/libs/mock/ya.make index 219773f916e7..9d918a5fac36 100644 --- a/ydb/core/fq/libs/mock/ya.make +++ b/ydb/core/fq/libs/mock/ya.make @@ -15,6 +15,7 @@ PEERDIR( ydb/core/base ydb/core/fq/libs/actors ydb/core/fq/libs/common + ydb/core/fq/libs/db_id_async_resolver_impl ydb/core/fq/libs/db_schema ydb/core/fq/libs/shared_resources/interface ydb/core/protos diff --git a/ydb/core/fq/libs/mock/yql_mock.cpp b/ydb/core/fq/libs/mock/yql_mock.cpp index 50b8e8af6244..60f4bcc22e41 100644 --- a/ydb/core/fq/libs/mock/yql_mock.cpp +++ b/ydb/core/fq/libs/mock/yql_mock.cpp @@ -2,6 +2,7 @@ #include #include +#include #include diff --git a/ydb/core/fq/libs/test_connection/test_connection.cpp b/ydb/core/fq/libs/test_connection/test_connection.cpp index 89993c8fdaa9..92739ad0ea80 100644 --- a/ydb/core/fq/libs/test_connection/test_connection.cpp +++ b/ydb/core/fq/libs/test_connection/test_connection.cpp @@ -4,11 +4,12 @@ #include "request_validators.h" #include -#include #include #include #include +#include #include +#include #include #include diff --git a/ydb/core/grpc_services/rpc_config.cpp b/ydb/core/grpc_services/rpc_config.cpp index e1ea3a19eec4..17d22f1fd1ae 100644 --- a/ydb/core/grpc_services/rpc_config.cpp +++ b/ydb/core/grpc_services/rpc_config.cpp @@ -201,6 +201,8 @@ class TReplaceStorageConfigRequest : public TBSConfigRequestGrpcSetSwitchDedicatedStorageSection(*shim.SwitchDedicatedStorageSection); } cmd->SetDedicatedStorageSectionConfigMode(shim.DedicatedConfigMode); + cmd->SetUserToken(Request_->GetSerializedToken()); + cmd->SetPeerName(Request_->GetPeerName()); } void FillDistconfResult(NKikimrBlobStorage::TEvNodeConfigInvokeOnRootResult& /*record*/, @@ -236,7 +238,9 @@ class TReplaceStorageConfigRequest : public TBSConfigRequestGrpcallow_unknown_fields() || request->bypass_checks(), request->bypass_checks(), /*enableConfigV2=*/ ff.GetSwitchToConfigV2(), - /*disableConfigV2=*/ ff.GetSwitchToConfigV1()); + /*disableConfigV2=*/ ff.GetSwitchToConfigV1(), + Request_->GetPeerName(), + Request_->GetSerializedToken()); } private: diff --git a/ydb/core/grpc_services/rpc_rate_limiter_api.cpp b/ydb/core/grpc_services/rpc_rate_limiter_api.cpp index 3aeb8271ff64..fe9ad87cfc50 100644 --- a/ydb/core/grpc_services/rpc_rate_limiter_api.cpp +++ b/ydb/core/grpc_services/rpc_rate_limiter_api.cpp @@ -178,7 +178,7 @@ class TRateLimiterControlRequest : public TRateLimiterRequest navigate = std::move(ev->Get()->Request); if (navigate->ResultSet.size() != 1 || navigate->ErrorCount > 0) { - this->Reply(StatusIds::INTERNAL_ERROR, this->ActorContext()); + this->Reply(StatusIds::SCHEME_ERROR, this->ActorContext()); return; } @@ -548,7 +548,7 @@ class TDescribeRateLimiterResourceRPC : public TRateLimiterControlRequestGet()->Record.ResourcesSize() == 0) { - this->Reply(StatusIds::INTERNAL_ERROR, "No resource properties found.", NKikimrIssues::TIssuesIds::DEFAULT_ERROR, this->ActorContext()); + this->Reply(StatusIds::SCHEME_ERROR, "No resource properties found.", NKikimrIssues::TIssuesIds::DEFAULT_ERROR, this->ActorContext()); return; } CopyProps(ev->Get()->Record.GetResources(0), *result.mutable_resource()); diff --git a/ydb/core/health_check/health_check.cpp b/ydb/core/health_check/health_check.cpp index bda11c4ece98..0b7e7a1ecaa0 100644 --- a/ydb/core/health_check/health_check.cpp +++ b/ydb/core/health_check/health_check.cpp @@ -2162,7 +2162,12 @@ class TSelfCheckRequest : public TActorBootstrapped { context.ReportStatus(Ydb::Monitoring::StatusFlag::GREEN); break; } - case NKikimrBlobStorage::FAULTY: + case NKikimrBlobStorage::FAULTY: { + context.ReportStatus(Ydb::Monitoring::StatusFlag::YELLOW, + TStringBuilder() << "PDisk state is " << statusString, + ETags::PDiskState); + break; + } case NKikimrBlobStorage::BROKEN: case NKikimrBlobStorage::TO_BE_REMOVED: { context.ReportStatus(Ydb::Monitoring::StatusFlag::RED, @@ -2293,10 +2298,6 @@ class TSelfCheckRequest : public TActorBootstrapped { break; } - context.ReportWithMaxChildStatus("VDisk have space issue", - ETags::VDiskState, - {ETags::PDiskSpace}); - storageVDiskStatus.set_overall(context.GetOverallStatus()); } @@ -2562,8 +2563,6 @@ class TSelfCheckRequest : public TActorBootstrapped { if (ErasureSpecies == NONE) { if (FailedDisks > 0) { context.ReportStatus(Ydb::Monitoring::StatusFlag::RED, "Group failed", ETags::GroupState, {ETags::VDiskState}); - } else if (DisksColors[Ydb::Monitoring::StatusFlag::YELLOW] > 0 || DisksColors[Ydb::Monitoring::StatusFlag::ORANGE] > 0) { - context.ReportStatus(Ydb::Monitoring::StatusFlag::YELLOW, "Group degraded", ETags::GroupState, {ETags::VDiskState}); } } else if (ErasureSpecies == BLOCK_4_2) { if (FailedDisks > 2) { @@ -2576,8 +2575,6 @@ class TSelfCheckRequest : public TActorBootstrapped { } else { context.ReportStatus(Ydb::Monitoring::StatusFlag::YELLOW, "Group degraded", ETags::GroupState, {ETags::VDiskState}); } - } else if (DisksColors[Ydb::Monitoring::StatusFlag::YELLOW] > 0 || DisksColors[Ydb::Monitoring::StatusFlag::ORANGE] > 0) { - context.ReportStatus(Ydb::Monitoring::StatusFlag::YELLOW, "Group degraded", ETags::GroupState, {ETags::VDiskState}); } } else if (ErasureSpecies == MIRROR_3_DC) { if (FailedRealms.size() > 2 || (FailedRealms.size() == 2 && FailedRealms[0].second > 1 && FailedRealms[1].second > 1)) { @@ -2590,8 +2587,6 @@ class TSelfCheckRequest : public TActorBootstrapped { } else { context.ReportStatus(Ydb::Monitoring::StatusFlag::YELLOW, "Group degraded", ETags::GroupState, {ETags::VDiskState}); } - } else if (DisksColors[Ydb::Monitoring::StatusFlag::YELLOW] > 0 || DisksColors[Ydb::Monitoring::StatusFlag::ORANGE] > 0) { - context.ReportStatus(Ydb::Monitoring::StatusFlag::YELLOW, "Group degraded", ETags::GroupState, {ETags::VDiskState}); } } } diff --git a/ydb/core/health_check/health_check_ut.cpp b/ydb/core/health_check/health_check_ut.cpp index eeacd66866eb..144a75d859a2 100644 --- a/ydb/core/health_check/health_check_ut.cpp +++ b/ydb/core/health_check/health_check_ut.cpp @@ -719,25 +719,21 @@ Y_UNIT_TEST_SUITE(THealthCheckTest) { UNIT_ASSERT_VALUES_EQUAL(result.self_check_result(), Ydb::Monitoring::SelfCheck::GOOD); } - Y_UNIT_TEST(YellowGroupIssueOnYellowSpace) { + Y_UNIT_TEST(OnlyDiskIssueOnSpaceIssues) { auto result = RequestHcWithVdisks(NKikimrBlobStorage::TGroupStatus::PARTIAL, TVDisks{3, NKikimrBlobStorage::READY}, false, 0.9); Cerr << result.ShortDebugString() << Endl; - CheckHcResultHasIssuesWithStatus(result, "STORAGE_GROUP", Ydb::Monitoring::StatusFlag::YELLOW, 1); + CheckHcResultHasIssuesWithStatus(result, "STORAGE_GROUP", Ydb::Monitoring::StatusFlag::YELLOW, 0); CheckHcResultHasIssuesWithStatus(result, "STORAGE_GROUP", Ydb::Monitoring::StatusFlag::RED, 0); + CheckHcResultHasIssuesWithStatus(result, "PDISK", Ydb::Monitoring::StatusFlag::YELLOW, 3, ""); } - Y_UNIT_TEST(RedGroupIssueOnRedSpace) { - auto result = RequestHcWithVdisks(NKikimrBlobStorage::TGroupStatus::PARTIAL, TVDisks{3, NKikimrBlobStorage::READY}, false, 0.95); - Cerr << result.ShortDebugString() << Endl; - CheckHcResultHasIssuesWithStatus(result, "STORAGE_GROUP", Ydb::Monitoring::StatusFlag::RED, 1); - } - - Y_UNIT_TEST(YellowIssueReadyVDisksOnFaultyPDisks) { + Y_UNIT_TEST(OnlyDiskIssueOnFaultyPDisks) { auto result = RequestHcWithVdisks(NKikimrBlobStorage::TGroupStatus::PARTIAL, TVDisks{3, {NKikimrBlobStorage::READY, NKikimrBlobStorage::FAULTY}}); Cerr << result.ShortDebugString() << Endl; - CheckHcResultHasIssuesWithStatus(result, "STORAGE_GROUP", Ydb::Monitoring::StatusFlag::YELLOW, 1); + CheckHcResultHasIssuesWithStatus(result, "STORAGE_GROUP", Ydb::Monitoring::StatusFlag::YELLOW, 0); CheckHcResultHasIssuesWithStatus(result, "STORAGE_GROUP", Ydb::Monitoring::StatusFlag::ORANGE, 0); CheckHcResultHasIssuesWithStatus(result, "STORAGE_GROUP", Ydb::Monitoring::StatusFlag::RED, 0); + CheckHcResultHasIssuesWithStatus(result, "PDISK", Ydb::Monitoring::StatusFlag::YELLOW, 3, ""); } /* HC currently infers group status on its own, so it's never unknown @@ -2219,7 +2215,7 @@ Y_UNIT_TEST_SUITE(THealthCheckTest) { TestConfigUpdateNodeRestartsPerPeriod(runtime, sender, nodeRestarts / 5, nodeRestarts / 2, nodeId, Ydb::Monitoring::StatusFlag::ORANGE); } - Y_UNIT_TEST(LayoutIncorrect) { + void LayoutCorrectTest(bool layoutCorrect) { TPortManager tp; ui16 port = tp.GetPort(2134); ui16 grpcPort = tp.GetPort(2135); @@ -2241,13 +2237,11 @@ Y_UNIT_TEST_SUITE(THealthCheckTest) { auto* x = reinterpret_cast(&ev); auto& record = (*x)->Get()->Record; for (auto& entry : *record.mutable_entries()) { - entry.mutable_info()->set_layoutcorrect(false); + entry.mutable_info()->set_layoutcorrect(layoutCorrect); } - break; } } - return TTestActorRuntime::EEventAction::PROCESS; }; runtime.SetObserverFunc(observerFunc); @@ -2258,32 +2252,51 @@ Y_UNIT_TEST_SUITE(THealthCheckTest) { runtime.Send(new IEventHandle(NHealthCheck::MakeHealthCheckID(), sender, request, 0)); auto result = runtime.GrabEdgeEvent(handle)->Result; - UNIT_ASSERT_VALUES_EQUAL(result.self_check_result(), Ydb::Monitoring::SelfCheck::MAINTENANCE_REQUIRED); - UNIT_ASSERT_VALUES_EQUAL(result.database_status_size(), 1); - const auto &database_status = result.database_status(0); + if (layoutCorrect) { + UNIT_ASSERT_VALUES_EQUAL(result.self_check_result(), Ydb::Monitoring::SelfCheck::GOOD); + UNIT_ASSERT_VALUES_EQUAL(result.database_status_size(), 1); + const auto &database_status = result.database_status(0); - UNIT_ASSERT_VALUES_EQUAL(database_status.overall(), Ydb::Monitoring::StatusFlag::ORANGE); - UNIT_ASSERT_VALUES_EQUAL(database_status.storage().overall(), Ydb::Monitoring::StatusFlag::ORANGE); - UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools().size(), 1); - UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools()[0].overall(), Ydb::Monitoring::StatusFlag::ORANGE); - UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools()[0].groups().size(), 1); - UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools()[0].groups()[0].overall(), Ydb::Monitoring::StatusFlag::ORANGE); - - for (const auto &issue_log : result.issue_log()) { - if (issue_log.level() == 1 && issue_log.type() == "DATABASE") { - UNIT_ASSERT_VALUES_EQUAL(issue_log.location().database().name(), "/Root"); - UNIT_ASSERT_VALUES_EQUAL(issue_log.message(), "Database has storage issues"); - } else if (issue_log.level() == 2 && issue_log.type() == "STORAGE") { - UNIT_ASSERT_VALUES_EQUAL(issue_log.location().database().name(), "/Root"); - UNIT_ASSERT_VALUES_EQUAL(issue_log.message(), "Storage has no redundancy"); - } else if (issue_log.level() == 3 && issue_log.type() == "STORAGE_POOL") { - UNIT_ASSERT_VALUES_EQUAL(issue_log.location().storage().pool().name(), "static"); - UNIT_ASSERT_VALUES_EQUAL(issue_log.message(), "Pool has no redundancy"); - } else if (issue_log.level() == 4 && issue_log.type() == "STORAGE_GROUP") { - UNIT_ASSERT_VALUES_EQUAL(issue_log.location().storage().pool().name(), "static"); - UNIT_ASSERT_VALUES_EQUAL(issue_log.message(), "Group layout is incorrect"); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().overall(), Ydb::Monitoring::StatusFlag::GREEN); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools().size(), 1); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools()[0].overall(), Ydb::Monitoring::StatusFlag::GREEN); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools()[0].groups().size(), 1); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools()[0].groups()[0].overall(), Ydb::Monitoring::StatusFlag::GREEN); + } else { + UNIT_ASSERT_VALUES_EQUAL(result.self_check_result(), Ydb::Monitoring::SelfCheck::MAINTENANCE_REQUIRED); + UNIT_ASSERT_VALUES_EQUAL(result.database_status_size(), 1); + const auto &database_status = result.database_status(0); + + UNIT_ASSERT_VALUES_EQUAL(database_status.overall(), Ydb::Monitoring::StatusFlag::ORANGE); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().overall(), Ydb::Monitoring::StatusFlag::ORANGE); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools().size(), 1); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools()[0].overall(), Ydb::Monitoring::StatusFlag::ORANGE); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools()[0].groups().size(), 1); + UNIT_ASSERT_VALUES_EQUAL(database_status.storage().pools()[0].groups()[0].overall(), Ydb::Monitoring::StatusFlag::ORANGE); + + for (const auto &issue_log : result.issue_log()) { + if (issue_log.level() == 1 && issue_log.type() == "DATABASE") { + UNIT_ASSERT_VALUES_EQUAL(issue_log.location().database().name(), "/Root"); + } else if (issue_log.level() == 2 && issue_log.type() == "STORAGE") { + UNIT_ASSERT_VALUES_EQUAL(issue_log.location().database().name(), "/Root"); + UNIT_ASSERT_VALUES_EQUAL(issue_log.message(), "Storage has no redundancy"); + } else if (issue_log.level() == 3 && issue_log.type() == "STORAGE_POOL") { + UNIT_ASSERT_VALUES_EQUAL(issue_log.location().storage().pool().name(), "static"); + UNIT_ASSERT_VALUES_EQUAL(issue_log.message(), "Pool has no redundancy"); + } else if (issue_log.level() == 4 && issue_log.type() == "STORAGE_GROUP") { + UNIT_ASSERT_VALUES_EQUAL(issue_log.location().storage().pool().name(), "static"); + UNIT_ASSERT_VALUES_EQUAL(issue_log.message(), "Group layout is incorrect"); + } } } } + + Y_UNIT_TEST(LayoutIncorrect) { + LayoutCorrectTest(false); + } + + Y_UNIT_TEST(LayoutCorrect) { + LayoutCorrectTest(true); + } } } diff --git a/ydb/core/kafka_proxy/actors/actors.h b/ydb/core/kafka_proxy/actors/actors.h index 727ab4ad2e49..643467f7ceeb 100644 --- a/ydb/core/kafka_proxy/actors/actors.h +++ b/ydb/core/kafka_proxy/actors/actors.h @@ -52,9 +52,9 @@ struct TContext { NKikimr::NPQ::TRlContext RlContext; bool Authenticated() { - + return !RequireAuthentication || AuthenticationStep == SUCCESS; - + } }; @@ -184,6 +184,7 @@ NActors::IActor* CreateKafkaOffsetCommitActor(const TContext::TPtr context, cons NActors::IActor* CreateKafkaOffsetFetchActor(const TContext::TPtr context, const ui64 correlationId, const TMessagePtr& message); NActors::IActor* CreateKafkaCreateTopicsActor(const TContext::TPtr context, const ui64 correlationId, const TMessagePtr& message); NActors::IActor* CreateKafkaCreatePartitionsActor(const TContext::TPtr context, const ui64 correlationId, const TMessagePtr& message); +NActors::IActor* CreateKafkaDescribeConfigsActor(const TContext::TPtr context, const ui64 correlationId, const TMessagePtr& message); NActors::IActor* CreateKafkaAlterConfigsActor(const TContext::TPtr context, const ui64 correlationId, const TMessagePtr& message); } // namespace NKafka diff --git a/ydb/core/kafka_proxy/actors/control_plane_common.h b/ydb/core/kafka_proxy/actors/control_plane_common.h index fcc534ecc52c..f92bba2cc08c 100644 --- a/ydb/core/kafka_proxy/actors/control_plane_common.h +++ b/ydb/core/kafka_proxy/actors/control_plane_common.h @@ -63,13 +63,13 @@ inline TRetentionsConversionResult ConvertRetentions(std::optional rete RETENTION_MS_CONFIG_NAME, [&result](std::optional retention) -> void { result.Ms = retention; } ); - + convertRetention( retentionBytes, RETENTION_BYTES_CONFIG_NAME, [&result](std::optional retention) -> void { result.Bytes = retention; } ); - + return result; } @@ -107,7 +107,7 @@ inline std::optional> ValidateTo } else { return std::optional>(); } -} +} template inline std::unordered_set ExtractDuplicates( @@ -134,7 +134,7 @@ class TAlterTopicActor : public NKikimr::NGRpcProxy::V1::TUpdateSchemeActor userToken, TString topicPath, TString databaseName) @@ -142,7 +142,7 @@ class TAlterTopicActor : public NKikimr::NGRpcProxy::V1::TUpdateSchemeActorSendResult(status,TString{message}); }) ) @@ -176,15 +176,15 @@ class TAlterTopicActor : public NKikimr::NGRpcProxy::V1::TUpdateSchemeActor SerializedToken; }; -class TKafkaTopicModificationRequest : public NKikimr::NGRpcService::IRequestOpCtx { +class TKafkaTopicRequestCtx : public NKikimr::NGRpcService::IRequestOpCtx { public: - using TRequest = TKafkaTopicModificationRequest; + using TRequest = TKafkaTopicRequestCtx; - TKafkaTopicModificationRequest( + TKafkaTopicRequestCtx( TIntrusiveConstPtr userToken, TString topicPath, TString databaseName, - const std::function sendResultCallback) + const std::function sendResultCallback) : UserToken(userToken) , TopicPath(topicPath) , DatabaseName(databaseName) @@ -239,7 +239,7 @@ class TKafkaTopicModificationRequest : public NKikimr::NGRpcService::IRequestOpC }; void ReplyWithYdbStatus(Ydb::StatusIds::StatusCode status) override { - ProcessYdbStatusCode(status); + ProcessYdbStatusCode(status, google::protobuf::Empty{}); }; void ReplyWithRpcStatus(grpc::StatusCode code, const TString& msg = "", const TString& details = "") override { @@ -334,8 +334,7 @@ class TKafkaTopicModificationRequest : public NKikimr::NGRpcService::IRequestOpC } void SendResult(const google::protobuf::Message& result, Ydb::StatusIds::StatusCode status) override { - Y_UNUSED(result); - ProcessYdbStatusCode(status); + ProcessYdbStatusCode(status, result); }; void SendResult( @@ -343,17 +342,16 @@ class TKafkaTopicModificationRequest : public NKikimr::NGRpcService::IRequestOpC Ydb::StatusIds::StatusCode status, const google::protobuf::RepeatedPtrField& message) override { - Y_UNUSED(result); Y_UNUSED(message); - ProcessYdbStatusCode(status); + ProcessYdbStatusCode(status, result); }; const Ydb::Operations::OperationParams& operation_params() const { return DummyParams; } - static TKafkaTopicModificationRequest* GetProtoRequest(std::shared_ptr request) { - return static_cast(&(*request)); + static TKafkaTopicRequestCtx* GetProtoRequest(std::shared_ptr request) { + return static_cast(&(*request)); } protected: @@ -371,11 +369,12 @@ class TKafkaTopicModificationRequest : public NKikimr::NGRpcService::IRequestOpC const NKikimr::NGRpcService::TAuditLogParts DummyAuditLogParts; const TString TopicPath; const TString DatabaseName; - const std::function SendResultCallback; + const std::function SendResultCallback; NYql::TIssue Issue; - void ProcessYdbStatusCode(Ydb::StatusIds::StatusCode& status) { - SendResultCallback(Convert(status), Issue.GetMessage()); + void ProcessYdbStatusCode(Ydb::StatusIds::StatusCode& status, const google::protobuf::Message& result) { + SendResultCallback(Convert(status), Issue.GetMessage(), result); } }; -} + +} //namespace NKafka diff --git a/ydb/core/kafka_proxy/actors/kafka_alter_configs_actor.cpp b/ydb/core/kafka_proxy/actors/kafka_alter_configs_actor.cpp index 4bdca062a829..6b7c86c99950 100644 --- a/ydb/core/kafka_proxy/actors/kafka_alter_configs_actor.cpp +++ b/ydb/core/kafka_proxy/actors/kafka_alter_configs_actor.cpp @@ -11,14 +11,14 @@ namespace NKafka { -class TKafkaAlterConfigsRequest: public TKafkaTopicModificationRequest { +class TKafkaAlterConfigsRequest: public TKafkaTopicRequestCtx { public: TKafkaAlterConfigsRequest( TIntrusiveConstPtr userToken, TString topicPath, TString databaseName, - const std::function sendResultCallback) - : TKafkaTopicModificationRequest(userToken, topicPath, databaseName, sendResultCallback) + const std::function sendResultCallback) + : TKafkaTopicRequestCtx(userToken, topicPath, databaseName, sendResultCallback) { }; @@ -26,7 +26,7 @@ class TKafkaAlterConfigsRequest: public TKafkaTopicModificationRequest { EKafkaErrors Convert(Ydb::StatusIds::StatusCode& status) override { return status == Ydb::StatusIds::BAD_REQUEST ? INVALID_CONFIG - : TKafkaTopicModificationRequest::Convert(status); + : TKafkaTopicRequestCtx::Convert(status); } }; diff --git a/ydb/core/kafka_proxy/actors/kafka_create_partitions_actor.cpp b/ydb/core/kafka_proxy/actors/kafka_create_partitions_actor.cpp index 4150e3ecd27a..cfe1360802e8 100644 --- a/ydb/core/kafka_proxy/actors/kafka_create_partitions_actor.cpp +++ b/ydb/core/kafka_proxy/actors/kafka_create_partitions_actor.cpp @@ -207,7 +207,7 @@ class TKafkaCreatePartitionsRequest : public NKikimr::NGRpcService::IRequestOpCt } }; -class TCreatePartitionsActor : public TAlterTopicActor { +class TCreatePartitionsActor : public TAlterTopicActor { public: TCreatePartitionsActor( @@ -216,7 +216,7 @@ class TCreatePartitionsActor : public TAlterTopicActor( + : TAlterTopicActor( requester, userToken, topicPath, diff --git a/ydb/core/kafka_proxy/actors/kafka_create_topics_actor.cpp b/ydb/core/kafka_proxy/actors/kafka_create_topics_actor.cpp index 606332f51314..cb6062d351b4 100644 --- a/ydb/core/kafka_proxy/actors/kafka_create_topics_actor.cpp +++ b/ydb/core/kafka_proxy/actors/kafka_create_topics_actor.cpp @@ -11,8 +11,8 @@ namespace NKafka { -class TCreateTopicActor : public NKikimr::NGRpcProxy::V1::TPQGrpcSchemaBase { - using TBase = NKikimr::NGRpcProxy::V1::TPQGrpcSchemaBase; +class TCreateTopicActor : public NKikimr::NGRpcProxy::V1::TPQGrpcSchemaBase { + using TBase = NKikimr::NGRpcProxy::V1::TPQGrpcSchemaBase; public: TCreateTopicActor( @@ -23,11 +23,11 @@ class TCreateTopicActor : public NKikimr::NGRpcProxy::V1::TPQGrpcSchemaBase retentionMs, std::optional retentionBytes) - : TBase(new TKafkaTopicModificationRequest( + : TBase(new TKafkaTopicRequestCtx( userToken, topicPath, databaseName, - [this](EKafkaErrors status, const std::string& message) { + [this](EKafkaErrors status, const std::string& message, const google::protobuf::Message&) { this->SendResult(status, TString{message}); }) ) diff --git a/ydb/core/kafka_proxy/actors/kafka_describe_configs_actor.cpp b/ydb/core/kafka_proxy/actors/kafka_describe_configs_actor.cpp new file mode 100644 index 000000000000..824a40569d6a --- /dev/null +++ b/ydb/core/kafka_proxy/actors/kafka_describe_configs_actor.cpp @@ -0,0 +1,262 @@ +#include "kafka_describe_configs_actor.h" + +#include +#include +#include +#include + + +namespace NKafka { + +NActors::IActor* CreateKafkaDescribeConfigsActor( + const TContext::TPtr context, + const ui64 correlationId, + const TMessagePtr& message +) { + return new TKafkaDescribeConfigsActor(context, correlationId, message); +} + +// https://github.com/apache/kafka/blob/b9774c0b025d4eef025c12af9c264eff1e98410c/clients/src/main/java/org/apache/kafka/common/requests/DescribeConfigsResponse.java#L150 +enum class EKafkaConfigType { + UNKNOWN = 0, + BOOLEAN = 1, + STRING = 2, + INT = 3, + SHORT = 4, + LONG = 5, + DOUBLE = 6, + LIST = 7, + CLASS = 8, + PASSWORD = 9 +}; + +TKafkaDescribeTopicActor::TKafkaDescribeTopicActor( + TActorId requester, + TIntrusiveConstPtr userToken, + TString topicPath, + TString databaseName) + : TBase(new TDescribeConfigsRequest( + userToken, + topicPath, + databaseName, + [this](const EKafkaErrors status, const std::string& message, const google::protobuf::Message& result) { + this->SendResult(status,TString{message}, result); + }) + ) + , TopicPath(topicPath) + , Requester(requester) +{ +}; + +void TKafkaDescribeTopicActor::SendResult(const EKafkaErrors status, const TString& message, const google::protobuf::Message& result) { + THolder response(new TEvKafka::TEvTopicDescribeResponse()); + response->Status = status; + response->TopicPath = TopicPath; + response->Message = message; + if (status == EKafkaErrors::NONE_ERROR) { + const auto* protoResponse = dynamic_cast(&result); + response->Response = *protoResponse; + } + TBase::Send(Requester, response.Release()); + TBase::Send(TBase::SelfId(), new TEvents::TEvPoison()); +} + +void TKafkaDescribeTopicActor::StateWork(TAutoPtr& ev) { + return TThis::TActorBase::StateWork(ev); +} + +void TKafkaDescribeTopicActor::Bootstrap(const NActors::TActorContext& ctx) { + TBase::Bootstrap(ctx); + TBase::SendDescribeProposeRequest(ctx); + TBase::Become(&TThis::StateWork); +}; + +void TKafkaDescribeTopicActor::HandleCacheNavigateResponse(NKikimr::TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev) { + Y_ABORT_UNLESS(ev->Get()->Request.Get()->ResultSet.size() == 1); // describe for only one topic + if (ReplyIfNotTopic(ev)) { + return; + } + Ydb::Topic::DescribeTopicResult result; + const auto& response = ev->Get()->Request.Get()->ResultSet.front(); + + const TString path = JoinSeq("/", response.Path); + + if (response.PQGroupInfo) { + const auto& pqDescr = response.PQGroupInfo->Description; + Ydb::StatusIds::StatusCode status; + TString error; + if (!NKikimr::FillTopicDescription(result, pqDescr, response.Self->Info, GetCdcStreamName(), status, error)) { + this->Request_->RaiseIssue(NKikimr::NGRpcProxy::V1::FillIssue(error, Ydb::PersQueue::ErrorCode::ERROR)); + TBase::Reply(status, ActorContext()); + return; + } + + } else { + Ydb::Scheme::Entry *selfEntry = result.mutable_self(); + NKikimr::ConvertDirectoryEntry(response.Self->Info, selfEntry, true); + if (const auto& name = GetCdcStreamName()) { + selfEntry->set_name(*name); + } + } + return ReplyWithResult(Ydb::StatusIds::SUCCESS, result, ActorContext()); +} + +void TKafkaDescribeConfigsActor::Bootstrap(const NActors::TActorContext& ctx) { + + KAFKA_LOG_D(InputLogMessage()); + + + THashSet requestedTopics{}; + for (auto& resource : Message->Resources) { + auto& topicName = resource.ResourceName.value(); + if (requestedTopics.contains(topicName)) { + continue; + } + requestedTopics.insert(topicName); + if (resource.ResourceType != TOPIC_RESOURCE_TYPE) { + auto result = MakeHolder(); + result->TopicPath = topicName; + result->Status = EKafkaErrors::INVALID_REQUEST; + result->Message = "Only TOPIC resource type is supported."; + this->TopicNamesToResponses[resource.ResourceName.value()] = TAutoPtr(result.Release()); + continue; + } + + ctx.Register(new TKafkaDescribeTopicActor( + SelfId(), + Context->UserToken, + resource.ResourceName.value(), + Context->DatabasePath + )); + InflyTopics++; + } + + if (InflyTopics > 0) { + Become(&TKafkaDescribeConfigsActor::StateWork); + } else { + Reply(); + } +}; + +void TKafkaDescribeConfigsActor::Handle(const TEvKafka::TEvTopicDescribeResponse::TPtr& ev) { + auto eventPtr = ev->Release(); + TopicNamesToResponses[eventPtr->TopicPath] = eventPtr; + InflyTopics--; + if (InflyTopics == 0) { + Reply(); + } +}; + +void AddConfigEntry( + TDescribeConfigsResponseData::TDescribeConfigsResult& descrResult, const TString& name, const TString& value, + EKafkaConfigType type +) { + TDescribeConfigsResponseData::TDescribeConfigsResult::ConfigsMeta::ItemType configEntry; + configEntry.Name = name; + configEntry.Value = value; + configEntry.ConfigType = (ui32)type; + descrResult.Configs.emplace_back(std::move(configEntry)); +} + + +void TKafkaDescribeConfigsActor::AddDescribeResponse( + TDescribeConfigsResponseData::TPtr& response, TEvKafka::TEvTopicDescribeResponse* ev, + const TString& topicName, EKafkaErrors status, const TString& message +) { + // https://kafka.apache.org/documentation/#configuration + //TDescribeConfigsResponseData::TDescribeConfigsResult result; + TDescribeConfigsResponseData::ResultsMeta::ItemType singleConfig; + singleConfig.ResourceType = TOPIC_RESOURCE_TYPE; + singleConfig.ResourceName = topicName; + singleConfig.ErrorCode = status; + singleConfig.ErrorMessage = message; + + if (status != EKafkaErrors::NONE_ERROR) { + response->Results.emplace_back(std::move(singleConfig)); + return; + } + Y_ENSURE(ev != nullptr); + AddConfigEntry(singleConfig, "compression.type", "producer", EKafkaConfigType::STRING); + + // these are default + AddConfigEntry(singleConfig, "leader.replication.throttled.replicas", "", EKafkaConfigType::LIST); + AddConfigEntry(singleConfig, "remote.storage.enable", "false", EKafkaConfigType::BOOLEAN); + AddConfigEntry(singleConfig, "segment.jitter.ms", "0", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "local.retention.ms", "-2", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "cleanup.policy", "delete", EKafkaConfigType::LIST); + AddConfigEntry(singleConfig, "flush.ms", "9223372036854775807", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "follower.replication.throttled.replicas", "", EKafkaConfigType::LIST); + AddConfigEntry(singleConfig, "compression.lz4.level", "9", EKafkaConfigType::INT); + AddConfigEntry(singleConfig, "compression.gzip.level", "-1", EKafkaConfigType::INT); + AddConfigEntry(singleConfig, "compression.zstd.level", "3", EKafkaConfigType::INT); + AddConfigEntry(singleConfig, "max.compaction.lag.ms", "9223372036854775807", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "min.compaction.lag.ms", "0", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "local.retention.bytes", "-2", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "preallocate", "false", EKafkaConfigType::BOOLEAN); + AddConfigEntry(singleConfig, "min.cleanable.dirty.ratio", "0.5", EKafkaConfigType::DOUBLE); + AddConfigEntry(singleConfig, "index.interval.bytes", "4096", EKafkaConfigType::INT); + AddConfigEntry(singleConfig, "unclean.leader.election.enable", "false", EKafkaConfigType::BOOLEAN); + AddConfigEntry(singleConfig, "delete.retention.ms", "86400000", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "segment.ms", "604800000", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "message.timestamp.before.max.ms", "9223372036854775807", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "segment.index.bytes", "10485760", EKafkaConfigType::INT); + // !: non-default + AddConfigEntry(singleConfig, "message.downconversion.enable", "false", EKafkaConfigType::BOOLEAN); + AddConfigEntry(singleConfig, "min.insync.replicas", "3", EKafkaConfigType::INT); + AddConfigEntry(singleConfig, "segment.bytes", "8388608" /*8_MB*/, EKafkaConfigType::INT); + AddConfigEntry(singleConfig, "flush.messages", "1", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "message.format.version", "9", EKafkaConfigType::STRING); + AddConfigEntry(singleConfig, "file.delete.delay.ms", "0", EKafkaConfigType::LONG); + AddConfigEntry(singleConfig, "max.message.bytes", ToString(Context->Config.GetMaxMessageSize()), EKafkaConfigType::INT); + AddConfigEntry(singleConfig, "message.timestamp.type", "CreateTime", EKafkaConfigType::STRING); + AddConfigEntry(singleConfig, "message.timestamp.after.max.ms", "9223372036854775807", EKafkaConfigType::LONG); + + + auto retentionTime = ev->Response.retention_period().seconds(); + if (retentionTime > 0) { + AddConfigEntry(singleConfig, "retention.ms", ToString(retentionTime * 1000), EKafkaConfigType::LONG); + } else { + AddConfigEntry(singleConfig, "retention.ms", "-1", EKafkaConfigType::LONG); + } + auto retentionBytes = ev->Response.retention_storage_mb(); + if (retentionBytes > 0) { + AddConfigEntry(singleConfig, "retention.bytes", ToString(retentionBytes * 1024 * 1024), EKafkaConfigType::LONG); + } else { + AddConfigEntry(singleConfig, "retention.bytes", "-1", EKafkaConfigType::LONG); + } + response->Results.emplace_back(std::move(singleConfig)); +} + +void TKafkaDescribeConfigsActor::Reply() { + TDescribeConfigsResponseData::TPtr response = std::make_shared(); + EKafkaErrors responseStatus = NONE_ERROR; + for (auto& requestResource : Message->Resources) { + auto resourceName = requestResource.ResourceName.value(); + + auto topicRespIter = TopicNamesToResponses.find(resourceName); + if (topicRespIter == TopicNamesToResponses.end()) { + continue; + } + + auto& topicResult = topicRespIter->second; + EKafkaErrors status = topicResult->Status; + AddDescribeResponse(response, topicResult.Get(), resourceName, status, topicResult->Message); + responseStatus = status; + TopicNamesToResponses.erase(topicRespIter); + } + + Send(Context->ConnectionId, new TEvKafka::TEvResponse(CorrelationId, response, responseStatus)); + Die(ActorContext()); +}; + +TStringBuilder TKafkaDescribeConfigsActor::InputLogMessage() { + return InputLogMessage( + "Describe configs actor", + Message->Resources, + false, + [](TDescribeConfigsRequestData::TDescribeConfigsResource resource) -> TString { + return resource.ResourceName.value(); + }); +}; + +} diff --git a/ydb/core/kafka_proxy/actors/kafka_describe_configs_actor.h b/ydb/core/kafka_proxy/actors/kafka_describe_configs_actor.h new file mode 100644 index 000000000000..a0683c8d3a50 --- /dev/null +++ b/ydb/core/kafka_proxy/actors/kafka_describe_configs_actor.h @@ -0,0 +1,84 @@ +#include "actors.h" +#include "control_plane_common.h" +#include +#include + +#include + +namespace NKafka { + +class TDescribeConfigsRequest: public TKafkaTopicRequestCtx { +public: + using TKafkaTopicRequestCtx::TKafkaTopicRequestCtx; + + static TDescribeConfigsRequest* GetProtoRequest(std::shared_ptr request) { + return static_cast(&(*request)); + } + +}; + +class TKafkaDescribeConfigsActor: public NActors::TActorBootstrapped { +public: + TKafkaDescribeConfigsActor( + const TContext::TPtr context, + const ui64 correlationId, + const TMessagePtr& message) + : Context(context) + , CorrelationId(correlationId) + , Message(message) { + } + + void Bootstrap(const NActors::TActorContext& ctx); + void Handle(const TEvKafka::TEvTopicDescribeResponse::TPtr& ev); + void Reply(); + + STATEFN(StateWork) { + switch (ev->GetTypeRewrite()) { + hFunc(TEvKafka::TEvTopicDescribeResponse, Handle); + } + } + +private: + void AddDescribeResponse(TDescribeConfigsResponseData::TPtr& response, TEvKafka::TEvTopicDescribeResponse* ev, + const TString& topicName, EKafkaErrors status, const TString& message); + TStringBuilder InputLogMessage(); + + const TContext::TPtr Context; + const ui64 CorrelationId; + const TMessagePtr Message; + ui32 InflyTopics = 0; + std::unordered_map> TopicNamesToResponses; +}; + + + +class TKafkaDescribeTopicActor : public NKikimr::NGRpcProxy::V1::TPQGrpcSchemaBase + , public NKikimr::NGRpcProxy::V1::TCdcStreamCompatible { + using TBase = NKikimr::NGRpcProxy::V1::TPQGrpcSchemaBase; + +public: + TKafkaDescribeTopicActor( + TActorId requester, + TIntrusiveConstPtr userToken, + TString topicPath, + TString databaseName); + + ~TKafkaDescribeTopicActor() = default; + + void SendResult(const EKafkaErrors status, const TString& message, const google::protobuf::Message& result); + void StateWork(TAutoPtr& ev); + + void Bootstrap(const NActors::TActorContext& ctx); + + void HandleCacheNavigateResponse(NKikimr::TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev); + +protected: + const TString TopicPath; + +private: + const TActorId Requester; + const std::shared_ptr SerializedToken; +}; + + +} // NKafka diff --git a/ydb/core/kafka_proxy/kafka_connection.cpp b/ydb/core/kafka_proxy/kafka_connection.cpp index eee2872f102b..c98f2086e48b 100644 --- a/ydb/core/kafka_proxy/kafka_connection.cpp +++ b/ydb/core/kafka_proxy/kafka_connection.cpp @@ -296,6 +296,10 @@ class TKafkaConnection: public TActorBootstrapped, public TNet Register(CreateKafkaMetadataActor(Context, header->CorrelationId, message, NKafka::MakeKafkaDiscoveryCacheID())); } + void HandleMessage(TRequestHeaderData* header, const TMessagePtr& message) { + Register(CreateKafkaDescribeConfigsActor(Context, header->CorrelationId, message)); + } + void HandleMessage(const TRequestHeaderData* header, const TMessagePtr& message) { Register(CreateKafkaSaslAuthActor(Context, header->CorrelationId, Address, message)); } @@ -427,6 +431,10 @@ class TKafkaConnection: public TActorBootstrapped, public TNet HandleMessage(&Request->Header, Cast(Request)); break; + case DESCRIBE_CONFIGS: + HandleMessage(&Request->Header, Cast(Request)); + break; + case CREATE_PARTITIONS: HandleMessage(&Request->Header, Cast(Request)); break; diff --git a/ydb/core/kafka_proxy/kafka_events.h b/ydb/core/kafka_proxy/kafka_events.h index 1d15cddc6e42..fb8a304cedca 100644 --- a/ydb/core/kafka_proxy/kafka_events.h +++ b/ydb/core/kafka_proxy/kafka_events.h @@ -29,6 +29,7 @@ struct TEvKafka { EvKillReadSession, EvCommitedOffsetsResponse, EvCreateTopicsResponse, + EvDescribeTopicsResponse, EvReadSessionInfo, EvSaveTxnProducerRequest, EvSaveTxnProducerResponse, @@ -265,6 +266,25 @@ struct TEvAddPartitionsToTxnRequest : public TEventLocal + , public NKikimr::NGRpcProxy::V1::TLocalResponseBase +{ + enum EStatus { + OK, + BAD_REQUEST, + TOPIC_DOES_NOT_EXIST, + }; + + TEvTopicDescribeResponse() + {} + + TString TopicPath; + EKafkaErrors Status; + TString Message; + Ydb::Topic::DescribeTopicResult Response; + +}; + struct TEvAddOffsetsToTxnRequest : public TEventLocal { TEvAddOffsetsToTxnRequest(const ui64 correlationId, const TMessagePtr& request, const TActorId connectionId) : CorrelationId(correlationId) diff --git a/ydb/core/kafka_proxy/kafka_messages.cpp b/ydb/core/kafka_proxy/kafka_messages.cpp index 69e830f8c51a..c90be1165569 100644 --- a/ydb/core/kafka_proxy/kafka_messages.cpp +++ b/ydb/core/kafka_proxy/kafka_messages.cpp @@ -434,7 +434,7 @@ const TRequestHeaderData::RequestApiVersionMeta::Type TRequestHeaderData::Reques const TRequestHeaderData::CorrelationIdMeta::Type TRequestHeaderData::CorrelationIdMeta::Default = 0; const TRequestHeaderData::ClientIdMeta::Type TRequestHeaderData::ClientIdMeta::Default = {""}; -TRequestHeaderData::TRequestHeaderData() +TRequestHeaderData::TRequestHeaderData() : RequestApiKey(RequestApiKeyMeta::Default) , RequestApiVersion(RequestApiVersionMeta::Default) , CorrelationId(CorrelationIdMeta::Default) @@ -449,7 +449,7 @@ void TRequestHeaderData::Read(TKafkaReadable& _readable, TKafkaVersion _version) NPrivate::Read(_readable, _version, RequestApiVersion); NPrivate::Read(_readable, _version, CorrelationId); NPrivate::Read(_readable, _version, ClientId); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -473,10 +473,10 @@ void TRequestHeaderData::Write(TKafkaWritable& _writable, TKafkaVersion _version NPrivate::Write(_collector, _writable, _version, RequestApiVersion); NPrivate::Write(_collector, _writable, _version, CorrelationId); NPrivate::Write(_collector, _writable, _version, ClientId); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -486,7 +486,7 @@ i32 TRequestHeaderData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, RequestApiVersion); NPrivate::Size(_collector, _version, CorrelationId); NPrivate::Size(_collector, _version, ClientId); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -499,7 +499,7 @@ i32 TRequestHeaderData::Size(TKafkaVersion _version) const { // const TResponseHeaderData::CorrelationIdMeta::Type TResponseHeaderData::CorrelationIdMeta::Default = 0; -TResponseHeaderData::TResponseHeaderData() +TResponseHeaderData::TResponseHeaderData() : CorrelationId(CorrelationIdMeta::Default) {} @@ -508,7 +508,7 @@ void TResponseHeaderData::Read(TKafkaReadable& _readable, TKafkaVersion _version ythrow yexception() << "Can't read version " << _version << " of TResponseHeaderData"; } NPrivate::Read(_readable, _version, CorrelationId); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -529,17 +529,17 @@ void TResponseHeaderData::Write(TKafkaWritable& _writable, TKafkaVersion _versio } NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, CorrelationId); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } i32 TResponseHeaderData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, CorrelationId); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -554,7 +554,7 @@ const TProduceRequestData::TransactionalIdMeta::Type TProduceRequestData::Transa const TProduceRequestData::AcksMeta::Type TProduceRequestData::AcksMeta::Default = 0; const TProduceRequestData::TimeoutMsMeta::Type TProduceRequestData::TimeoutMsMeta::Default = 0; -TProduceRequestData::TProduceRequestData() +TProduceRequestData::TProduceRequestData() : TransactionalId(TransactionalIdMeta::Default) , Acks(AcksMeta::Default) , TimeoutMs(TimeoutMsMeta::Default) @@ -568,7 +568,7 @@ void TProduceRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _version NPrivate::Read(_readable, _version, Acks); NPrivate::Read(_readable, _version, TimeoutMs); NPrivate::Read(_readable, _version, TopicData); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -592,10 +592,10 @@ void TProduceRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _versio NPrivate::Write(_collector, _writable, _version, Acks); NPrivate::Write(_collector, _writable, _version, TimeoutMs); NPrivate::Write(_collector, _writable, _version, TopicData); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -605,7 +605,7 @@ i32 TProduceRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Acks); NPrivate::Size(_collector, _version, TimeoutMs); NPrivate::Size(_collector, _version, TopicData); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -618,7 +618,7 @@ i32 TProduceRequestData::Size(TKafkaVersion _version) const { // const TProduceRequestData::TTopicProduceData::NameMeta::Type TProduceRequestData::TTopicProduceData::NameMeta::Default = {""}; -TProduceRequestData::TTopicProduceData::TTopicProduceData() +TProduceRequestData::TTopicProduceData::TTopicProduceData() : Name(NameMeta::Default) {} @@ -628,7 +628,7 @@ void TProduceRequestData::TTopicProduceData::Read(TKafkaReadable& _readable, TKa } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, PartitionData); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -650,10 +650,10 @@ void TProduceRequestData::TTopicProduceData::Write(TKafkaWritable& _writable, TK NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, PartitionData); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -661,7 +661,7 @@ i32 TProduceRequestData::TTopicProduceData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, PartitionData); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -674,7 +674,7 @@ i32 TProduceRequestData::TTopicProduceData::Size(TKafkaVersion _version) const { // const TProduceRequestData::TTopicProduceData::TPartitionProduceData::IndexMeta::Type TProduceRequestData::TTopicProduceData::TPartitionProduceData::IndexMeta::Default = 0; -TProduceRequestData::TTopicProduceData::TPartitionProduceData::TPartitionProduceData() +TProduceRequestData::TTopicProduceData::TPartitionProduceData::TPartitionProduceData() : Index(IndexMeta::Default) {} @@ -684,7 +684,7 @@ void TProduceRequestData::TTopicProduceData::TPartitionProduceData::Read(TKafkaR } NPrivate::Read(_readable, _version, Index); NPrivate::Read(_readable, _version, Records); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -706,10 +706,10 @@ void TProduceRequestData::TTopicProduceData::TPartitionProduceData::Write(TKafka NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Index); NPrivate::Write(_collector, _writable, _version, Records); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -717,7 +717,7 @@ i32 TProduceRequestData::TTopicProduceData::TPartitionProduceData::Size(TKafkaVe NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Index); NPrivate::Size(_collector, _version, Records); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -730,7 +730,7 @@ i32 TProduceRequestData::TTopicProduceData::TPartitionProduceData::Size(TKafkaVe // const TProduceResponseData::ThrottleTimeMsMeta::Type TProduceResponseData::ThrottleTimeMsMeta::Default = 0; -TProduceResponseData::TProduceResponseData() +TProduceResponseData::TProduceResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) {} @@ -740,7 +740,7 @@ void TProduceResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _versio } NPrivate::Read(_readable, _version, Responses); NPrivate::Read(_readable, _version, ThrottleTimeMs); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -762,10 +762,10 @@ void TProduceResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _versi NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Responses); NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -773,7 +773,7 @@ i32 TProduceResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Responses); NPrivate::Size(_collector, _version, ThrottleTimeMs); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -786,7 +786,7 @@ i32 TProduceResponseData::Size(TKafkaVersion _version) const { // const TProduceResponseData::TTopicProduceResponse::NameMeta::Type TProduceResponseData::TTopicProduceResponse::NameMeta::Default = {""}; -TProduceResponseData::TTopicProduceResponse::TTopicProduceResponse() +TProduceResponseData::TTopicProduceResponse::TTopicProduceResponse() : Name(NameMeta::Default) {} @@ -796,7 +796,7 @@ void TProduceResponseData::TTopicProduceResponse::Read(TKafkaReadable& _readable } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, PartitionResponses); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -818,10 +818,10 @@ void TProduceResponseData::TTopicProduceResponse::Write(TKafkaWritable& _writabl NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, PartitionResponses); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -829,7 +829,7 @@ i32 TProduceResponseData::TTopicProduceResponse::Size(TKafkaVersion _version) co NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, PartitionResponses); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -847,7 +847,7 @@ const TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::Lo const TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::LogStartOffsetMeta::Type TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::LogStartOffsetMeta::Default = -1; const TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::ErrorMessageMeta::Type TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::ErrorMessageMeta::Default = std::nullopt; -TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TPartitionProduceResponse() +TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TPartitionProduceResponse() : Index(IndexMeta::Default) , ErrorCode(ErrorCodeMeta::Default) , BaseOffset(BaseOffsetMeta::Default) @@ -867,7 +867,7 @@ void TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::Rea NPrivate::Read(_readable, _version, LogStartOffset); NPrivate::Read(_readable, _version, RecordErrors); NPrivate::Read(_readable, _version, ErrorMessage); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -894,10 +894,10 @@ void TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::Wri NPrivate::Write(_collector, _writable, _version, LogStartOffset); NPrivate::Write(_collector, _writable, _version, RecordErrors); NPrivate::Write(_collector, _writable, _version, ErrorMessage); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -910,7 +910,7 @@ i32 TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::Size NPrivate::Size(_collector, _version, LogStartOffset); NPrivate::Size(_collector, _version, RecordErrors); NPrivate::Size(_collector, _version, ErrorMessage); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -924,7 +924,7 @@ i32 TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::Size const TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TBatchIndexAndErrorMessage::BatchIndexMeta::Type TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TBatchIndexAndErrorMessage::BatchIndexMeta::Default = 0; const TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TBatchIndexAndErrorMessage::BatchIndexErrorMessageMeta::Type TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TBatchIndexAndErrorMessage::BatchIndexErrorMessageMeta::Default = std::nullopt; -TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TBatchIndexAndErrorMessage::TBatchIndexAndErrorMessage() +TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TBatchIndexAndErrorMessage::TBatchIndexAndErrorMessage() : BatchIndex(BatchIndexMeta::Default) , BatchIndexErrorMessage(BatchIndexErrorMessageMeta::Default) {} @@ -935,7 +935,7 @@ void TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TBa } NPrivate::Read(_readable, _version, BatchIndex); NPrivate::Read(_readable, _version, BatchIndexErrorMessage); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -957,10 +957,10 @@ void TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TBa NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, BatchIndex); NPrivate::Write(_collector, _writable, _version, BatchIndexErrorMessage); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -968,7 +968,7 @@ i32 TProduceResponseData::TTopicProduceResponse::TPartitionProduceResponse::TBat NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, BatchIndex); NPrivate::Size(_collector, _version, BatchIndexErrorMessage); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -989,7 +989,7 @@ const TFetchRequestData::SessionIdMeta::Type TFetchRequestData::SessionIdMeta::D const TFetchRequestData::SessionEpochMeta::Type TFetchRequestData::SessionEpochMeta::Default = -1; const TFetchRequestData::RackIdMeta::Type TFetchRequestData::RackIdMeta::Default = {""}; -TFetchRequestData::TFetchRequestData() +TFetchRequestData::TFetchRequestData() : ClusterId(ClusterIdMeta::Default) , ReplicaId(ReplicaIdMeta::Default) , MaxWaitMs(MaxWaitMsMeta::Default) @@ -1016,7 +1016,7 @@ void TFetchRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _version) NPrivate::Read(_readable, _version, Topics); NPrivate::Read(_readable, _version, ForgottenTopicsData); NPrivate::Read(_readable, _version, RackId); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1050,10 +1050,10 @@ void TFetchRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _version) NPrivate::Write(_collector, _writable, _version, Topics); NPrivate::Write(_collector, _writable, _version, ForgottenTopicsData); NPrivate::Write(_collector, _writable, _version, RackId); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + NPrivate::WriteTag(_writable, _version, ClusterId); } } @@ -1071,7 +1071,7 @@ i32 TFetchRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Topics); NPrivate::Size(_collector, _version, ForgottenTopicsData); NPrivate::Size(_collector, _version, RackId); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1085,7 +1085,7 @@ i32 TFetchRequestData::Size(TKafkaVersion _version) const { const TFetchRequestData::TFetchTopic::TopicMeta::Type TFetchRequestData::TFetchTopic::TopicMeta::Default = {""}; const TFetchRequestData::TFetchTopic::TopicIdMeta::Type TFetchRequestData::TFetchTopic::TopicIdMeta::Default = TKafkaUuid(0, 0); -TFetchRequestData::TFetchTopic::TFetchTopic() +TFetchRequestData::TFetchTopic::TFetchTopic() : Topic(TopicMeta::Default) , TopicId(TopicIdMeta::Default) {} @@ -1097,7 +1097,7 @@ void TFetchRequestData::TFetchTopic::Read(TKafkaReadable& _readable, TKafkaVersi NPrivate::Read(_readable, _version, Topic); NPrivate::Read(_readable, _version, TopicId); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1120,10 +1120,10 @@ void TFetchRequestData::TFetchTopic::Write(TKafkaWritable& _writable, TKafkaVers NPrivate::Write(_collector, _writable, _version, Topic); NPrivate::Write(_collector, _writable, _version, TopicId); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1132,7 +1132,7 @@ i32 TFetchRequestData::TFetchTopic::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Topic); NPrivate::Size(_collector, _version, TopicId); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1150,7 +1150,7 @@ const TFetchRequestData::TFetchTopic::TFetchPartition::LastFetchedEpochMeta::Typ const TFetchRequestData::TFetchTopic::TFetchPartition::LogStartOffsetMeta::Type TFetchRequestData::TFetchTopic::TFetchPartition::LogStartOffsetMeta::Default = -1; const TFetchRequestData::TFetchTopic::TFetchPartition::PartitionMaxBytesMeta::Type TFetchRequestData::TFetchTopic::TFetchPartition::PartitionMaxBytesMeta::Default = 0; -TFetchRequestData::TFetchTopic::TFetchPartition::TFetchPartition() +TFetchRequestData::TFetchTopic::TFetchPartition::TFetchPartition() : Partition(PartitionMeta::Default) , CurrentLeaderEpoch(CurrentLeaderEpochMeta::Default) , FetchOffset(FetchOffsetMeta::Default) @@ -1169,7 +1169,7 @@ void TFetchRequestData::TFetchTopic::TFetchPartition::Read(TKafkaReadable& _read NPrivate::Read(_readable, _version, LastFetchedEpoch); NPrivate::Read(_readable, _version, LogStartOffset); NPrivate::Read(_readable, _version, PartitionMaxBytes); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1195,10 +1195,10 @@ void TFetchRequestData::TFetchTopic::TFetchPartition::Write(TKafkaWritable& _wri NPrivate::Write(_collector, _writable, _version, LastFetchedEpoch); NPrivate::Write(_collector, _writable, _version, LogStartOffset); NPrivate::Write(_collector, _writable, _version, PartitionMaxBytes); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1210,7 +1210,7 @@ i32 TFetchRequestData::TFetchTopic::TFetchPartition::Size(TKafkaVersion _version NPrivate::Size(_collector, _version, LastFetchedEpoch); NPrivate::Size(_collector, _version, LogStartOffset); NPrivate::Size(_collector, _version, PartitionMaxBytes); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1224,7 +1224,7 @@ i32 TFetchRequestData::TFetchTopic::TFetchPartition::Size(TKafkaVersion _version const TFetchRequestData::TForgottenTopic::TopicMeta::Type TFetchRequestData::TForgottenTopic::TopicMeta::Default = {""}; const TFetchRequestData::TForgottenTopic::TopicIdMeta::Type TFetchRequestData::TForgottenTopic::TopicIdMeta::Default = TKafkaUuid(0, 0); -TFetchRequestData::TForgottenTopic::TForgottenTopic() +TFetchRequestData::TForgottenTopic::TForgottenTopic() : Topic(TopicMeta::Default) , TopicId(TopicIdMeta::Default) {} @@ -1236,7 +1236,7 @@ void TFetchRequestData::TForgottenTopic::Read(TKafkaReadable& _readable, TKafkaV NPrivate::Read(_readable, _version, Topic); NPrivate::Read(_readable, _version, TopicId); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1259,10 +1259,10 @@ void TFetchRequestData::TForgottenTopic::Write(TKafkaWritable& _writable, TKafka NPrivate::Write(_collector, _writable, _version, Topic); NPrivate::Write(_collector, _writable, _version, TopicId); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1271,7 +1271,7 @@ i32 TFetchRequestData::TForgottenTopic::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Topic); NPrivate::Size(_collector, _version, TopicId); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1286,7 +1286,7 @@ const TFetchResponseData::ThrottleTimeMsMeta::Type TFetchResponseData::ThrottleT const TFetchResponseData::ErrorCodeMeta::Type TFetchResponseData::ErrorCodeMeta::Default = 0; const TFetchResponseData::SessionIdMeta::Type TFetchResponseData::SessionIdMeta::Default = 0; -TFetchResponseData::TFetchResponseData() +TFetchResponseData::TFetchResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) , SessionId(SessionIdMeta::Default) @@ -1300,7 +1300,7 @@ void TFetchResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _version) NPrivate::Read(_readable, _version, ErrorCode); NPrivate::Read(_readable, _version, SessionId); NPrivate::Read(_readable, _version, Responses); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1324,10 +1324,10 @@ void TFetchResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _version NPrivate::Write(_collector, _writable, _version, ErrorCode); NPrivate::Write(_collector, _writable, _version, SessionId); NPrivate::Write(_collector, _writable, _version, Responses); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1337,7 +1337,7 @@ i32 TFetchResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ErrorCode); NPrivate::Size(_collector, _version, SessionId); NPrivate::Size(_collector, _version, Responses); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1351,7 +1351,7 @@ i32 TFetchResponseData::Size(TKafkaVersion _version) const { const TFetchResponseData::TFetchableTopicResponse::TopicMeta::Type TFetchResponseData::TFetchableTopicResponse::TopicMeta::Default = {""}; const TFetchResponseData::TFetchableTopicResponse::TopicIdMeta::Type TFetchResponseData::TFetchableTopicResponse::TopicIdMeta::Default = TKafkaUuid(0, 0); -TFetchResponseData::TFetchableTopicResponse::TFetchableTopicResponse() +TFetchResponseData::TFetchableTopicResponse::TFetchableTopicResponse() : Topic(TopicMeta::Default) , TopicId(TopicIdMeta::Default) {} @@ -1363,7 +1363,7 @@ void TFetchResponseData::TFetchableTopicResponse::Read(TKafkaReadable& _readable NPrivate::Read(_readable, _version, Topic); NPrivate::Read(_readable, _version, TopicId); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1386,10 +1386,10 @@ void TFetchResponseData::TFetchableTopicResponse::Write(TKafkaWritable& _writabl NPrivate::Write(_collector, _writable, _version, Topic); NPrivate::Write(_collector, _writable, _version, TopicId); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1398,7 +1398,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::Size(TKafkaVersion _version) co NPrivate::Size(_collector, _version, Topic); NPrivate::Size(_collector, _version, TopicId); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1416,7 +1416,7 @@ const TFetchResponseData::TFetchableTopicResponse::TPartitionData::LastStableOff const TFetchResponseData::TFetchableTopicResponse::TPartitionData::LogStartOffsetMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::LogStartOffsetMeta::Default = -1; const TFetchResponseData::TFetchableTopicResponse::TPartitionData::PreferredReadReplicaMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::PreferredReadReplicaMeta::Default = -1; -TFetchResponseData::TFetchableTopicResponse::TPartitionData::TPartitionData() +TFetchResponseData::TFetchableTopicResponse::TPartitionData::TPartitionData() : PartitionIndex(PartitionIndexMeta::Default) , ErrorCode(ErrorCodeMeta::Default) , HighWatermark(HighWatermarkMeta::Default) @@ -1440,7 +1440,7 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::Read(TKafkaRea NPrivate::Read(_readable, _version, AbortedTransactions); NPrivate::Read(_readable, _version, PreferredReadReplica); NPrivate::Read(_readable, _version, Records); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1480,10 +1480,10 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::Write(TKafkaWr NPrivate::Write(_collector, _writable, _version, AbortedTransactions); NPrivate::Write(_collector, _writable, _version, PreferredReadReplica); NPrivate::Write(_collector, _writable, _version, Records); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + NPrivate::WriteTag(_writable, _version, DivergingEpoch); NPrivate::WriteTag(_writable, _version, CurrentLeader); NPrivate::WriteTag(_writable, _version, SnapshotId); @@ -1503,7 +1503,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::Size(TKafkaVers NPrivate::Size(_collector, _version, AbortedTransactions); NPrivate::Size(_collector, _version, PreferredReadReplica); NPrivate::Size(_collector, _version, Records); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1517,7 +1517,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::Size(TKafkaVers const TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffset::EpochMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffset::EpochMeta::Default = -1; const TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffset::EndOffsetMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffset::EndOffsetMeta::Default = -1; -TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffset::TEpochEndOffset() +TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffset::TEpochEndOffset() : Epoch(EpochMeta::Default) , EndOffset(EndOffsetMeta::Default) {} @@ -1528,7 +1528,7 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffse } NPrivate::Read(_readable, _version, Epoch); NPrivate::Read(_readable, _version, EndOffset); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1550,10 +1550,10 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffse NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Epoch); NPrivate::Write(_collector, _writable, _version, EndOffset); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1561,7 +1561,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffset NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Epoch); NPrivate::Size(_collector, _version, EndOffset); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1575,7 +1575,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::TEpochEndOffset const TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEpoch::LeaderIdMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEpoch::LeaderIdMeta::Default = -1; const TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEpoch::LeaderEpochMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEpoch::LeaderEpochMeta::Default = -1; -TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEpoch::TLeaderIdAndEpoch() +TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEpoch::TLeaderIdAndEpoch() : LeaderId(LeaderIdMeta::Default) , LeaderEpoch(LeaderEpochMeta::Default) {} @@ -1586,7 +1586,7 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEp } NPrivate::Read(_readable, _version, LeaderId); NPrivate::Read(_readable, _version, LeaderEpoch); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1608,10 +1608,10 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEp NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, LeaderId); NPrivate::Write(_collector, _writable, _version, LeaderEpoch); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1619,7 +1619,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEpo NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, LeaderId); NPrivate::Size(_collector, _version, LeaderEpoch); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1633,7 +1633,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::TLeaderIdAndEpo const TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::EndOffsetMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::EndOffsetMeta::Default = -1; const TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::EpochMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::EpochMeta::Default = -1; -TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::TSnapshotId() +TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::TSnapshotId() : EndOffset(EndOffsetMeta::Default) , Epoch(EpochMeta::Default) {} @@ -1644,7 +1644,7 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::R } NPrivate::Read(_readable, _version, EndOffset); NPrivate::Read(_readable, _version, Epoch); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1666,10 +1666,10 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::W NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, EndOffset); NPrivate::Write(_collector, _writable, _version, Epoch); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1677,7 +1677,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::Si NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, EndOffset); NPrivate::Size(_collector, _version, Epoch); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1691,7 +1691,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::TSnapshotId::Si const TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransaction::ProducerIdMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransaction::ProducerIdMeta::Default = 0; const TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransaction::FirstOffsetMeta::Type TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransaction::FirstOffsetMeta::Default = 0; -TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransaction::TAbortedTransaction() +TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransaction::TAbortedTransaction() : ProducerId(ProducerIdMeta::Default) , FirstOffset(FirstOffsetMeta::Default) {} @@ -1702,7 +1702,7 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransa } NPrivate::Read(_readable, _version, ProducerId); NPrivate::Read(_readable, _version, FirstOffset); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1724,10 +1724,10 @@ void TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransa NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ProducerId); NPrivate::Write(_collector, _writable, _version, FirstOffset); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1735,7 +1735,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransac NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ProducerId); NPrivate::Size(_collector, _version, FirstOffset); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1749,7 +1749,7 @@ i32 TFetchResponseData::TFetchableTopicResponse::TPartitionData::TAbortedTransac const TListOffsetsRequestData::ReplicaIdMeta::Type TListOffsetsRequestData::ReplicaIdMeta::Default = 0; const TListOffsetsRequestData::IsolationLevelMeta::Type TListOffsetsRequestData::IsolationLevelMeta::Default = 0; -TListOffsetsRequestData::TListOffsetsRequestData() +TListOffsetsRequestData::TListOffsetsRequestData() : ReplicaId(ReplicaIdMeta::Default) , IsolationLevel(IsolationLevelMeta::Default) {} @@ -1761,7 +1761,7 @@ void TListOffsetsRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _ver NPrivate::Read(_readable, _version, ReplicaId); NPrivate::Read(_readable, _version, IsolationLevel); NPrivate::Read(_readable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1784,10 +1784,10 @@ void TListOffsetsRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _ve NPrivate::Write(_collector, _writable, _version, ReplicaId); NPrivate::Write(_collector, _writable, _version, IsolationLevel); NPrivate::Write(_collector, _writable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1796,7 +1796,7 @@ i32 TListOffsetsRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ReplicaId); NPrivate::Size(_collector, _version, IsolationLevel); NPrivate::Size(_collector, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1809,7 +1809,7 @@ i32 TListOffsetsRequestData::Size(TKafkaVersion _version) const { // const TListOffsetsRequestData::TListOffsetsTopic::NameMeta::Type TListOffsetsRequestData::TListOffsetsTopic::NameMeta::Default = {""}; -TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsTopic() +TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsTopic() : Name(NameMeta::Default) {} @@ -1819,7 +1819,7 @@ void TListOffsetsRequestData::TListOffsetsTopic::Read(TKafkaReadable& _readable, } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1841,10 +1841,10 @@ void TListOffsetsRequestData::TListOffsetsTopic::Write(TKafkaWritable& _writable NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1852,7 +1852,7 @@ i32 TListOffsetsRequestData::TListOffsetsTopic::Size(TKafkaVersion _version) con NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1868,7 +1868,7 @@ const TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::Current const TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::TimestampMeta::Type TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::TimestampMeta::Default = 0; const TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::MaxNumOffsetsMeta::Type TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::MaxNumOffsetsMeta::Default = 1; -TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::TListOffsetsPartition() +TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::TListOffsetsPartition() : PartitionIndex(PartitionIndexMeta::Default) , CurrentLeaderEpoch(CurrentLeaderEpochMeta::Default) , Timestamp(TimestampMeta::Default) @@ -1883,7 +1883,7 @@ void TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::Read(TKa NPrivate::Read(_readable, _version, CurrentLeaderEpoch); NPrivate::Read(_readable, _version, Timestamp); NPrivate::Read(_readable, _version, MaxNumOffsets); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1907,10 +1907,10 @@ void TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::Write(TK NPrivate::Write(_collector, _writable, _version, CurrentLeaderEpoch); NPrivate::Write(_collector, _writable, _version, Timestamp); NPrivate::Write(_collector, _writable, _version, MaxNumOffsets); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1920,7 +1920,7 @@ i32 TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::Size(TKaf NPrivate::Size(_collector, _version, CurrentLeaderEpoch); NPrivate::Size(_collector, _version, Timestamp); NPrivate::Size(_collector, _version, MaxNumOffsets); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1933,7 +1933,7 @@ i32 TListOffsetsRequestData::TListOffsetsTopic::TListOffsetsPartition::Size(TKaf // const TListOffsetsResponseData::ThrottleTimeMsMeta::Type TListOffsetsResponseData::ThrottleTimeMsMeta::Default = 0; -TListOffsetsResponseData::TListOffsetsResponseData() +TListOffsetsResponseData::TListOffsetsResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) {} @@ -1943,7 +1943,7 @@ void TListOffsetsResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _ve } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -1965,10 +1965,10 @@ void TListOffsetsResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _v NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -1976,7 +1976,7 @@ i32 TListOffsetsResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -1989,7 +1989,7 @@ i32 TListOffsetsResponseData::Size(TKafkaVersion _version) const { // const TListOffsetsResponseData::TListOffsetsTopicResponse::NameMeta::Type TListOffsetsResponseData::TListOffsetsTopicResponse::NameMeta::Default = {""}; -TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsTopicResponse() +TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsTopicResponse() : Name(NameMeta::Default) {} @@ -1999,7 +1999,7 @@ void TListOffsetsResponseData::TListOffsetsTopicResponse::Read(TKafkaReadable& _ } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2021,10 +2021,10 @@ void TListOffsetsResponseData::TListOffsetsTopicResponse::Write(TKafkaWritable& NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2032,7 +2032,7 @@ i32 TListOffsetsResponseData::TListOffsetsTopicResponse::Size(TKafkaVersion _ver NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2049,7 +2049,7 @@ const TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartition const TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartitionResponse::OffsetMeta::Type TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartitionResponse::OffsetMeta::Default = -1; const TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartitionResponse::LeaderEpochMeta::Type TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartitionResponse::LeaderEpochMeta::Default = -1; -TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartitionResponse::TListOffsetsPartitionResponse() +TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartitionResponse::TListOffsetsPartitionResponse() : PartitionIndex(PartitionIndexMeta::Default) , ErrorCode(ErrorCodeMeta::Default) , Timestamp(TimestampMeta::Default) @@ -2067,7 +2067,7 @@ void TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartitionR NPrivate::Read(_readable, _version, Timestamp); NPrivate::Read(_readable, _version, Offset); NPrivate::Read(_readable, _version, LeaderEpoch); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2093,10 +2093,10 @@ void TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartitionR NPrivate::Write(_collector, _writable, _version, Timestamp); NPrivate::Write(_collector, _writable, _version, Offset); NPrivate::Write(_collector, _writable, _version, LeaderEpoch); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2108,7 +2108,7 @@ i32 TListOffsetsResponseData::TListOffsetsTopicResponse::TListOffsetsPartitionRe NPrivate::Size(_collector, _version, Timestamp); NPrivate::Size(_collector, _version, Offset); NPrivate::Size(_collector, _version, LeaderEpoch); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2123,7 +2123,7 @@ const TMetadataRequestData::AllowAutoTopicCreationMeta::Type TMetadataRequestDat const TMetadataRequestData::IncludeClusterAuthorizedOperationsMeta::Type TMetadataRequestData::IncludeClusterAuthorizedOperationsMeta::Default = false; const TMetadataRequestData::IncludeTopicAuthorizedOperationsMeta::Type TMetadataRequestData::IncludeTopicAuthorizedOperationsMeta::Default = false; -TMetadataRequestData::TMetadataRequestData() +TMetadataRequestData::TMetadataRequestData() : AllowAutoTopicCreation(AllowAutoTopicCreationMeta::Default) , IncludeClusterAuthorizedOperations(IncludeClusterAuthorizedOperationsMeta::Default) , IncludeTopicAuthorizedOperations(IncludeTopicAuthorizedOperationsMeta::Default) @@ -2137,7 +2137,7 @@ void TMetadataRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _versio NPrivate::Read(_readable, _version, AllowAutoTopicCreation); NPrivate::Read(_readable, _version, IncludeClusterAuthorizedOperations); NPrivate::Read(_readable, _version, IncludeTopicAuthorizedOperations); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2161,10 +2161,10 @@ void TMetadataRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _versi NPrivate::Write(_collector, _writable, _version, AllowAutoTopicCreation); NPrivate::Write(_collector, _writable, _version, IncludeClusterAuthorizedOperations); NPrivate::Write(_collector, _writable, _version, IncludeTopicAuthorizedOperations); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2174,7 +2174,7 @@ i32 TMetadataRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, AllowAutoTopicCreation); NPrivate::Size(_collector, _version, IncludeClusterAuthorizedOperations); NPrivate::Size(_collector, _version, IncludeTopicAuthorizedOperations); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2188,7 +2188,7 @@ i32 TMetadataRequestData::Size(TKafkaVersion _version) const { const TMetadataRequestData::TMetadataRequestTopic::TopicIdMeta::Type TMetadataRequestData::TMetadataRequestTopic::TopicIdMeta::Default = TKafkaUuid(0, 0); const TMetadataRequestData::TMetadataRequestTopic::NameMeta::Type TMetadataRequestData::TMetadataRequestTopic::NameMeta::Default = {""}; -TMetadataRequestData::TMetadataRequestTopic::TMetadataRequestTopic() +TMetadataRequestData::TMetadataRequestTopic::TMetadataRequestTopic() : TopicId(TopicIdMeta::Default) , Name(NameMeta::Default) {} @@ -2199,7 +2199,7 @@ void TMetadataRequestData::TMetadataRequestTopic::Read(TKafkaReadable& _readable } NPrivate::Read(_readable, _version, TopicId); NPrivate::Read(_readable, _version, Name); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2221,10 +2221,10 @@ void TMetadataRequestData::TMetadataRequestTopic::Write(TKafkaWritable& _writabl NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, TopicId); NPrivate::Write(_collector, _writable, _version, Name); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2232,7 +2232,7 @@ i32 TMetadataRequestData::TMetadataRequestTopic::Size(TKafkaVersion _version) co NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, TopicId); NPrivate::Size(_collector, _version, Name); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2248,7 +2248,7 @@ const TMetadataResponseData::ClusterIdMeta::Type TMetadataResponseData::ClusterI const TMetadataResponseData::ControllerIdMeta::Type TMetadataResponseData::ControllerIdMeta::Default = -1; const TMetadataResponseData::ClusterAuthorizedOperationsMeta::Type TMetadataResponseData::ClusterAuthorizedOperationsMeta::Default = -2147483648; -TMetadataResponseData::TMetadataResponseData() +TMetadataResponseData::TMetadataResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ClusterId(ClusterIdMeta::Default) , ControllerId(ControllerIdMeta::Default) @@ -2265,7 +2265,7 @@ void TMetadataResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _versi NPrivate::Read(_readable, _version, ControllerId); NPrivate::Read(_readable, _version, Topics); NPrivate::Read(_readable, _version, ClusterAuthorizedOperations); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2291,10 +2291,10 @@ void TMetadataResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _vers NPrivate::Write(_collector, _writable, _version, ControllerId); NPrivate::Write(_collector, _writable, _version, Topics); NPrivate::Write(_collector, _writable, _version, ClusterAuthorizedOperations); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2306,7 +2306,7 @@ i32 TMetadataResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ControllerId); NPrivate::Size(_collector, _version, Topics); NPrivate::Size(_collector, _version, ClusterAuthorizedOperations); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2322,7 +2322,7 @@ const TMetadataResponseData::TMetadataResponseBroker::HostMeta::Type TMetadataRe const TMetadataResponseData::TMetadataResponseBroker::PortMeta::Type TMetadataResponseData::TMetadataResponseBroker::PortMeta::Default = 0; const TMetadataResponseData::TMetadataResponseBroker::RackMeta::Type TMetadataResponseData::TMetadataResponseBroker::RackMeta::Default = std::nullopt; -TMetadataResponseData::TMetadataResponseBroker::TMetadataResponseBroker() +TMetadataResponseData::TMetadataResponseBroker::TMetadataResponseBroker() : NodeId(NodeIdMeta::Default) , Host(HostMeta::Default) , Port(PortMeta::Default) @@ -2337,7 +2337,7 @@ void TMetadataResponseData::TMetadataResponseBroker::Read(TKafkaReadable& _reada NPrivate::Read(_readable, _version, Host); NPrivate::Read(_readable, _version, Port); NPrivate::Read(_readable, _version, Rack); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2361,10 +2361,10 @@ void TMetadataResponseData::TMetadataResponseBroker::Write(TKafkaWritable& _writ NPrivate::Write(_collector, _writable, _version, Host); NPrivate::Write(_collector, _writable, _version, Port); NPrivate::Write(_collector, _writable, _version, Rack); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2374,7 +2374,7 @@ i32 TMetadataResponseData::TMetadataResponseBroker::Size(TKafkaVersion _version) NPrivate::Size(_collector, _version, Host); NPrivate::Size(_collector, _version, Port); NPrivate::Size(_collector, _version, Rack); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2391,7 +2391,7 @@ const TMetadataResponseData::TMetadataResponseTopic::TopicIdMeta::Type TMetadata const TMetadataResponseData::TMetadataResponseTopic::IsInternalMeta::Type TMetadataResponseData::TMetadataResponseTopic::IsInternalMeta::Default = false; const TMetadataResponseData::TMetadataResponseTopic::TopicAuthorizedOperationsMeta::Type TMetadataResponseData::TMetadataResponseTopic::TopicAuthorizedOperationsMeta::Default = -2147483648; -TMetadataResponseData::TMetadataResponseTopic::TMetadataResponseTopic() +TMetadataResponseData::TMetadataResponseTopic::TMetadataResponseTopic() : ErrorCode(ErrorCodeMeta::Default) , Name(NameMeta::Default) , TopicId(TopicIdMeta::Default) @@ -2409,7 +2409,7 @@ void TMetadataResponseData::TMetadataResponseTopic::Read(TKafkaReadable& _readab NPrivate::Read(_readable, _version, IsInternal); NPrivate::Read(_readable, _version, Partitions); NPrivate::Read(_readable, _version, TopicAuthorizedOperations); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2435,10 +2435,10 @@ void TMetadataResponseData::TMetadataResponseTopic::Write(TKafkaWritable& _writa NPrivate::Write(_collector, _writable, _version, IsInternal); NPrivate::Write(_collector, _writable, _version, Partitions); NPrivate::Write(_collector, _writable, _version, TopicAuthorizedOperations); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2450,7 +2450,7 @@ i32 TMetadataResponseData::TMetadataResponseTopic::Size(TKafkaVersion _version) NPrivate::Size(_collector, _version, IsInternal); NPrivate::Size(_collector, _version, Partitions); NPrivate::Size(_collector, _version, TopicAuthorizedOperations); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2466,7 +2466,7 @@ const TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition: const TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition::LeaderIdMeta::Type TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition::LeaderIdMeta::Default = 0; const TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition::LeaderEpochMeta::Type TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition::LeaderEpochMeta::Default = -1; -TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition::TMetadataResponsePartition() +TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition::TMetadataResponsePartition() : ErrorCode(ErrorCodeMeta::Default) , PartitionIndex(PartitionIndexMeta::Default) , LeaderId(LeaderIdMeta::Default) @@ -2484,7 +2484,7 @@ void TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition:: NPrivate::Read(_readable, _version, ReplicaNodes); NPrivate::Read(_readable, _version, IsrNodes); NPrivate::Read(_readable, _version, OfflineReplicas); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2511,10 +2511,10 @@ void TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition:: NPrivate::Write(_collector, _writable, _version, ReplicaNodes); NPrivate::Write(_collector, _writable, _version, IsrNodes); NPrivate::Write(_collector, _writable, _version, OfflineReplicas); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2527,7 +2527,7 @@ i32 TMetadataResponseData::TMetadataResponseTopic::TMetadataResponsePartition::S NPrivate::Size(_collector, _version, ReplicaNodes); NPrivate::Size(_collector, _version, IsrNodes); NPrivate::Size(_collector, _version, OfflineReplicas); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2544,7 +2544,7 @@ const TOffsetCommitRequestData::MemberIdMeta::Type TOffsetCommitRequestData::Mem const TOffsetCommitRequestData::GroupInstanceIdMeta::Type TOffsetCommitRequestData::GroupInstanceIdMeta::Default = std::nullopt; const TOffsetCommitRequestData::RetentionTimeMsMeta::Type TOffsetCommitRequestData::RetentionTimeMsMeta::Default = -1; -TOffsetCommitRequestData::TOffsetCommitRequestData() +TOffsetCommitRequestData::TOffsetCommitRequestData() : GroupId(GroupIdMeta::Default) , GenerationId(GenerationIdMeta::Default) , MemberId(MemberIdMeta::Default) @@ -2562,7 +2562,7 @@ void TOffsetCommitRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _ve NPrivate::Read(_readable, _version, GroupInstanceId); NPrivate::Read(_readable, _version, RetentionTimeMs); NPrivate::Read(_readable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2588,10 +2588,10 @@ void TOffsetCommitRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _v NPrivate::Write(_collector, _writable, _version, GroupInstanceId); NPrivate::Write(_collector, _writable, _version, RetentionTimeMs); NPrivate::Write(_collector, _writable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2603,7 +2603,7 @@ i32 TOffsetCommitRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, GroupInstanceId); NPrivate::Size(_collector, _version, RetentionTimeMs); NPrivate::Size(_collector, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2616,7 +2616,7 @@ i32 TOffsetCommitRequestData::Size(TKafkaVersion _version) const { // const TOffsetCommitRequestData::TOffsetCommitRequestTopic::NameMeta::Type TOffsetCommitRequestData::TOffsetCommitRequestTopic::NameMeta::Default = {""}; -TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestTopic() +TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestTopic() : Name(NameMeta::Default) {} @@ -2626,7 +2626,7 @@ void TOffsetCommitRequestData::TOffsetCommitRequestTopic::Read(TKafkaReadable& _ } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2648,10 +2648,10 @@ void TOffsetCommitRequestData::TOffsetCommitRequestTopic::Write(TKafkaWritable& NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2659,7 +2659,7 @@ i32 TOffsetCommitRequestData::TOffsetCommitRequestTopic::Size(TKafkaVersion _ver NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2676,7 +2676,7 @@ const TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestP const TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPartition::CommitTimestampMeta::Type TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPartition::CommitTimestampMeta::Default = -1; const TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPartition::CommittedMetadataMeta::Type TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPartition::CommittedMetadataMeta::Default = {""}; -TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPartition::TOffsetCommitRequestPartition() +TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPartition::TOffsetCommitRequestPartition() : PartitionIndex(PartitionIndexMeta::Default) , CommittedOffset(CommittedOffsetMeta::Default) , CommittedLeaderEpoch(CommittedLeaderEpochMeta::Default) @@ -2693,7 +2693,7 @@ void TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPa NPrivate::Read(_readable, _version, CommittedLeaderEpoch); NPrivate::Read(_readable, _version, CommitTimestamp); NPrivate::Read(_readable, _version, CommittedMetadata); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2718,10 +2718,10 @@ void TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPa NPrivate::Write(_collector, _writable, _version, CommittedLeaderEpoch); NPrivate::Write(_collector, _writable, _version, CommitTimestamp); NPrivate::Write(_collector, _writable, _version, CommittedMetadata); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2732,7 +2732,7 @@ i32 TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPar NPrivate::Size(_collector, _version, CommittedLeaderEpoch); NPrivate::Size(_collector, _version, CommitTimestamp); NPrivate::Size(_collector, _version, CommittedMetadata); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2745,7 +2745,7 @@ i32 TOffsetCommitRequestData::TOffsetCommitRequestTopic::TOffsetCommitRequestPar // const TOffsetCommitResponseData::ThrottleTimeMsMeta::Type TOffsetCommitResponseData::ThrottleTimeMsMeta::Default = 0; -TOffsetCommitResponseData::TOffsetCommitResponseData() +TOffsetCommitResponseData::TOffsetCommitResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) {} @@ -2755,7 +2755,7 @@ void TOffsetCommitResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _v } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2777,10 +2777,10 @@ void TOffsetCommitResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _ NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2788,7 +2788,7 @@ i32 TOffsetCommitResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2801,7 +2801,7 @@ i32 TOffsetCommitResponseData::Size(TKafkaVersion _version) const { // const TOffsetCommitResponseData::TOffsetCommitResponseTopic::NameMeta::Type TOffsetCommitResponseData::TOffsetCommitResponseTopic::NameMeta::Default = {""}; -TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponseTopic() +TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponseTopic() : Name(NameMeta::Default) {} @@ -2811,7 +2811,7 @@ void TOffsetCommitResponseData::TOffsetCommitResponseTopic::Read(TKafkaReadable& } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2833,10 +2833,10 @@ void TOffsetCommitResponseData::TOffsetCommitResponseTopic::Write(TKafkaWritable NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2844,7 +2844,7 @@ i32 TOffsetCommitResponseData::TOffsetCommitResponseTopic::Size(TKafkaVersion _v NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2858,7 +2858,7 @@ i32 TOffsetCommitResponseData::TOffsetCommitResponseTopic::Size(TKafkaVersion _v const TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponsePartition::PartitionIndexMeta::Type TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponsePartition::PartitionIndexMeta::Default = 0; const TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponsePartition::ErrorCodeMeta::Type TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponsePartition::ErrorCodeMeta::Default = 0; -TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponsePartition::TOffsetCommitResponsePartition() +TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponsePartition::TOffsetCommitResponsePartition() : PartitionIndex(PartitionIndexMeta::Default) , ErrorCode(ErrorCodeMeta::Default) {} @@ -2869,7 +2869,7 @@ void TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitRespons } NPrivate::Read(_readable, _version, PartitionIndex); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2891,10 +2891,10 @@ void TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitRespons NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, PartitionIndex); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2902,7 +2902,7 @@ i32 TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponse NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, PartitionIndex); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2916,7 +2916,7 @@ i32 TOffsetCommitResponseData::TOffsetCommitResponseTopic::TOffsetCommitResponse const TOffsetFetchRequestData::GroupIdMeta::Type TOffsetFetchRequestData::GroupIdMeta::Default = {""}; const TOffsetFetchRequestData::RequireStableMeta::Type TOffsetFetchRequestData::RequireStableMeta::Default = false; -TOffsetFetchRequestData::TOffsetFetchRequestData() +TOffsetFetchRequestData::TOffsetFetchRequestData() : GroupId(GroupIdMeta::Default) , RequireStable(RequireStableMeta::Default) {} @@ -2929,7 +2929,7 @@ void TOffsetFetchRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _ver NPrivate::Read(_readable, _version, Topics); NPrivate::Read(_readable, _version, Groups); NPrivate::Read(_readable, _version, RequireStable); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -2953,10 +2953,10 @@ void TOffsetFetchRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _ve NPrivate::Write(_collector, _writable, _version, Topics); NPrivate::Write(_collector, _writable, _version, Groups); NPrivate::Write(_collector, _writable, _version, RequireStable); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -2966,7 +2966,7 @@ i32 TOffsetFetchRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Topics); NPrivate::Size(_collector, _version, Groups); NPrivate::Size(_collector, _version, RequireStable); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -2979,7 +2979,7 @@ i32 TOffsetFetchRequestData::Size(TKafkaVersion _version) const { // const TOffsetFetchRequestData::TOffsetFetchRequestTopic::NameMeta::Type TOffsetFetchRequestData::TOffsetFetchRequestTopic::NameMeta::Default = {""}; -TOffsetFetchRequestData::TOffsetFetchRequestTopic::TOffsetFetchRequestTopic() +TOffsetFetchRequestData::TOffsetFetchRequestTopic::TOffsetFetchRequestTopic() : Name(NameMeta::Default) {} @@ -2989,7 +2989,7 @@ void TOffsetFetchRequestData::TOffsetFetchRequestTopic::Read(TKafkaReadable& _re } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, PartitionIndexes); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3011,10 +3011,10 @@ void TOffsetFetchRequestData::TOffsetFetchRequestTopic::Write(TKafkaWritable& _w NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, PartitionIndexes); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3022,7 +3022,7 @@ i32 TOffsetFetchRequestData::TOffsetFetchRequestTopic::Size(TKafkaVersion _versi NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, PartitionIndexes); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3035,7 +3035,7 @@ i32 TOffsetFetchRequestData::TOffsetFetchRequestTopic::Size(TKafkaVersion _versi // const TOffsetFetchRequestData::TOffsetFetchRequestGroup::GroupIdMeta::Type TOffsetFetchRequestData::TOffsetFetchRequestGroup::GroupIdMeta::Default = {""}; -TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestGroup() +TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestGroup() : GroupId(GroupIdMeta::Default) {} @@ -3045,7 +3045,7 @@ void TOffsetFetchRequestData::TOffsetFetchRequestGroup::Read(TKafkaReadable& _re } NPrivate::Read(_readable, _version, GroupId); NPrivate::Read(_readable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3067,10 +3067,10 @@ void TOffsetFetchRequestData::TOffsetFetchRequestGroup::Write(TKafkaWritable& _w NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, GroupId); NPrivate::Write(_collector, _writable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3078,7 +3078,7 @@ i32 TOffsetFetchRequestData::TOffsetFetchRequestGroup::Size(TKafkaVersion _versi NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, GroupId); NPrivate::Size(_collector, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3091,7 +3091,7 @@ i32 TOffsetFetchRequestData::TOffsetFetchRequestGroup::Size(TKafkaVersion _versi // const TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestTopics::NameMeta::Type TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestTopics::NameMeta::Default = {""}; -TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestTopics::TOffsetFetchRequestTopics() +TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestTopics::TOffsetFetchRequestTopics() : Name(NameMeta::Default) {} @@ -3101,7 +3101,7 @@ void TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestTopic } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, PartitionIndexes); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3123,10 +3123,10 @@ void TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestTopic NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, PartitionIndexes); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3134,7 +3134,7 @@ i32 TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestTopics NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, PartitionIndexes); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3148,7 +3148,7 @@ i32 TOffsetFetchRequestData::TOffsetFetchRequestGroup::TOffsetFetchRequestTopics const TOffsetFetchResponseData::ThrottleTimeMsMeta::Type TOffsetFetchResponseData::ThrottleTimeMsMeta::Default = 0; const TOffsetFetchResponseData::ErrorCodeMeta::Type TOffsetFetchResponseData::ErrorCodeMeta::Default = 0; -TOffsetFetchResponseData::TOffsetFetchResponseData() +TOffsetFetchResponseData::TOffsetFetchResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) {} @@ -3161,7 +3161,7 @@ void TOffsetFetchResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _ve NPrivate::Read(_readable, _version, Topics); NPrivate::Read(_readable, _version, ErrorCode); NPrivate::Read(_readable, _version, Groups); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3185,10 +3185,10 @@ void TOffsetFetchResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _v NPrivate::Write(_collector, _writable, _version, Topics); NPrivate::Write(_collector, _writable, _version, ErrorCode); NPrivate::Write(_collector, _writable, _version, Groups); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3198,7 +3198,7 @@ i32 TOffsetFetchResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Topics); NPrivate::Size(_collector, _version, ErrorCode); NPrivate::Size(_collector, _version, Groups); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3211,7 +3211,7 @@ i32 TOffsetFetchResponseData::Size(TKafkaVersion _version) const { // const TOffsetFetchResponseData::TOffsetFetchResponseTopic::NameMeta::Type TOffsetFetchResponseData::TOffsetFetchResponseTopic::NameMeta::Default = {""}; -TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponseTopic() +TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponseTopic() : Name(NameMeta::Default) {} @@ -3221,7 +3221,7 @@ void TOffsetFetchResponseData::TOffsetFetchResponseTopic::Read(TKafkaReadable& _ } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3243,10 +3243,10 @@ void TOffsetFetchResponseData::TOffsetFetchResponseTopic::Write(TKafkaWritable& NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3254,7 +3254,7 @@ i32 TOffsetFetchResponseData::TOffsetFetchResponseTopic::Size(TKafkaVersion _ver NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3271,7 +3271,7 @@ const TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponseP const TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePartition::MetadataMeta::Type TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePartition::MetadataMeta::Default = {""}; const TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePartition::ErrorCodeMeta::Type TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePartition::ErrorCodeMeta::Default = 0; -TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePartition::TOffsetFetchResponsePartition() +TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePartition::TOffsetFetchResponsePartition() : PartitionIndex(PartitionIndexMeta::Default) , CommittedOffset(CommittedOffsetMeta::Default) , CommittedLeaderEpoch(CommittedLeaderEpochMeta::Default) @@ -3288,7 +3288,7 @@ void TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePa NPrivate::Read(_readable, _version, CommittedLeaderEpoch); NPrivate::Read(_readable, _version, Metadata); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3313,10 +3313,10 @@ void TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePa NPrivate::Write(_collector, _writable, _version, CommittedLeaderEpoch); NPrivate::Write(_collector, _writable, _version, Metadata); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3327,7 +3327,7 @@ i32 TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePar NPrivate::Size(_collector, _version, CommittedLeaderEpoch); NPrivate::Size(_collector, _version, Metadata); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3341,7 +3341,7 @@ i32 TOffsetFetchResponseData::TOffsetFetchResponseTopic::TOffsetFetchResponsePar const TOffsetFetchResponseData::TOffsetFetchResponseGroup::GroupIdMeta::Type TOffsetFetchResponseData::TOffsetFetchResponseGroup::GroupIdMeta::Default = {""}; const TOffsetFetchResponseData::TOffsetFetchResponseGroup::ErrorCodeMeta::Type TOffsetFetchResponseData::TOffsetFetchResponseGroup::ErrorCodeMeta::Default = 0; -TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseGroup() +TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseGroup() : GroupId(GroupIdMeta::Default) , ErrorCode(ErrorCodeMeta::Default) {} @@ -3353,7 +3353,7 @@ void TOffsetFetchResponseData::TOffsetFetchResponseGroup::Read(TKafkaReadable& _ NPrivate::Read(_readable, _version, GroupId); NPrivate::Read(_readable, _version, Topics); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3376,10 +3376,10 @@ void TOffsetFetchResponseData::TOffsetFetchResponseGroup::Write(TKafkaWritable& NPrivate::Write(_collector, _writable, _version, GroupId); NPrivate::Write(_collector, _writable, _version, Topics); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3388,7 +3388,7 @@ i32 TOffsetFetchResponseData::TOffsetFetchResponseGroup::Size(TKafkaVersion _ver NPrivate::Size(_collector, _version, GroupId); NPrivate::Size(_collector, _version, Topics); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3401,7 +3401,7 @@ i32 TOffsetFetchResponseData::TOffsetFetchResponseGroup::Size(TKafkaVersion _ver // const TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::NameMeta::Type TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::NameMeta::Default = {""}; -TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::TOffsetFetchResponseTopics() +TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::TOffsetFetchResponseTopics() : Name(NameMeta::Default) {} @@ -3411,7 +3411,7 @@ void TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTo } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3433,10 +3433,10 @@ void TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTo NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3444,7 +3444,7 @@ i32 TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTop NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3461,7 +3461,7 @@ const TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseT const TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::TOffsetFetchResponsePartitions::MetadataMeta::Type TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::TOffsetFetchResponsePartitions::MetadataMeta::Default = {""}; const TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::TOffsetFetchResponsePartitions::ErrorCodeMeta::Type TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::TOffsetFetchResponsePartitions::ErrorCodeMeta::Default = 0; -TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::TOffsetFetchResponsePartitions::TOffsetFetchResponsePartitions() +TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTopics::TOffsetFetchResponsePartitions::TOffsetFetchResponsePartitions() : PartitionIndex(PartitionIndexMeta::Default) , CommittedOffset(CommittedOffsetMeta::Default) , CommittedLeaderEpoch(CommittedLeaderEpochMeta::Default) @@ -3478,7 +3478,7 @@ void TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTo NPrivate::Read(_readable, _version, CommittedLeaderEpoch); NPrivate::Read(_readable, _version, Metadata); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3503,10 +3503,10 @@ void TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTo NPrivate::Write(_collector, _writable, _version, CommittedLeaderEpoch); NPrivate::Write(_collector, _writable, _version, Metadata); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3517,7 +3517,7 @@ i32 TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTop NPrivate::Size(_collector, _version, CommittedLeaderEpoch); NPrivate::Size(_collector, _version, Metadata); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3531,7 +3531,7 @@ i32 TOffsetFetchResponseData::TOffsetFetchResponseGroup::TOffsetFetchResponseTop const TFindCoordinatorRequestData::KeyMeta::Type TFindCoordinatorRequestData::KeyMeta::Default = {""}; const TFindCoordinatorRequestData::KeyTypeMeta::Type TFindCoordinatorRequestData::KeyTypeMeta::Default = 0; -TFindCoordinatorRequestData::TFindCoordinatorRequestData() +TFindCoordinatorRequestData::TFindCoordinatorRequestData() : Key(KeyMeta::Default) , KeyType(KeyTypeMeta::Default) {} @@ -3543,7 +3543,7 @@ void TFindCoordinatorRequestData::Read(TKafkaReadable& _readable, TKafkaVersion NPrivate::Read(_readable, _version, Key); NPrivate::Read(_readable, _version, KeyType); NPrivate::Read(_readable, _version, CoordinatorKeys); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3566,10 +3566,10 @@ void TFindCoordinatorRequestData::Write(TKafkaWritable& _writable, TKafkaVersion NPrivate::Write(_collector, _writable, _version, Key); NPrivate::Write(_collector, _writable, _version, KeyType); NPrivate::Write(_collector, _writable, _version, CoordinatorKeys); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3578,7 +3578,7 @@ i32 TFindCoordinatorRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Key); NPrivate::Size(_collector, _version, KeyType); NPrivate::Size(_collector, _version, CoordinatorKeys); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3596,7 +3596,7 @@ const TFindCoordinatorResponseData::NodeIdMeta::Type TFindCoordinatorResponseDat const TFindCoordinatorResponseData::HostMeta::Type TFindCoordinatorResponseData::HostMeta::Default = {""}; const TFindCoordinatorResponseData::PortMeta::Type TFindCoordinatorResponseData::PortMeta::Default = 0; -TFindCoordinatorResponseData::TFindCoordinatorResponseData() +TFindCoordinatorResponseData::TFindCoordinatorResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) , ErrorMessage(ErrorMessageMeta::Default) @@ -3616,7 +3616,7 @@ void TFindCoordinatorResponseData::Read(TKafkaReadable& _readable, TKafkaVersion NPrivate::Read(_readable, _version, Host); NPrivate::Read(_readable, _version, Port); NPrivate::Read(_readable, _version, Coordinators); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3643,10 +3643,10 @@ void TFindCoordinatorResponseData::Write(TKafkaWritable& _writable, TKafkaVersio NPrivate::Write(_collector, _writable, _version, Host); NPrivate::Write(_collector, _writable, _version, Port); NPrivate::Write(_collector, _writable, _version, Coordinators); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3659,7 +3659,7 @@ i32 TFindCoordinatorResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Host); NPrivate::Size(_collector, _version, Port); NPrivate::Size(_collector, _version, Coordinators); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3677,7 +3677,7 @@ const TFindCoordinatorResponseData::TCoordinator::PortMeta::Type TFindCoordinato const TFindCoordinatorResponseData::TCoordinator::ErrorCodeMeta::Type TFindCoordinatorResponseData::TCoordinator::ErrorCodeMeta::Default = 0; const TFindCoordinatorResponseData::TCoordinator::ErrorMessageMeta::Type TFindCoordinatorResponseData::TCoordinator::ErrorMessageMeta::Default = {""}; -TFindCoordinatorResponseData::TCoordinator::TCoordinator() +TFindCoordinatorResponseData::TCoordinator::TCoordinator() : Key(KeyMeta::Default) , NodeId(NodeIdMeta::Default) , Host(HostMeta::Default) @@ -3696,7 +3696,7 @@ void TFindCoordinatorResponseData::TCoordinator::Read(TKafkaReadable& _readable, NPrivate::Read(_readable, _version, Port); NPrivate::Read(_readable, _version, ErrorCode); NPrivate::Read(_readable, _version, ErrorMessage); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3722,10 +3722,10 @@ void TFindCoordinatorResponseData::TCoordinator::Write(TKafkaWritable& _writable NPrivate::Write(_collector, _writable, _version, Port); NPrivate::Write(_collector, _writable, _version, ErrorCode); NPrivate::Write(_collector, _writable, _version, ErrorMessage); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3737,7 +3737,7 @@ i32 TFindCoordinatorResponseData::TCoordinator::Size(TKafkaVersion _version) con NPrivate::Size(_collector, _version, Port); NPrivate::Size(_collector, _version, ErrorCode); NPrivate::Size(_collector, _version, ErrorMessage); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3756,7 +3756,7 @@ const TJoinGroupRequestData::GroupInstanceIdMeta::Type TJoinGroupRequestData::Gr const TJoinGroupRequestData::ProtocolTypeMeta::Type TJoinGroupRequestData::ProtocolTypeMeta::Default = {""}; const TJoinGroupRequestData::ReasonMeta::Type TJoinGroupRequestData::ReasonMeta::Default = std::nullopt; -TJoinGroupRequestData::TJoinGroupRequestData() +TJoinGroupRequestData::TJoinGroupRequestData() : GroupId(GroupIdMeta::Default) , SessionTimeoutMs(SessionTimeoutMsMeta::Default) , RebalanceTimeoutMs(RebalanceTimeoutMsMeta::Default) @@ -3778,7 +3778,7 @@ void TJoinGroupRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _versi NPrivate::Read(_readable, _version, ProtocolType); NPrivate::Read(_readable, _version, Protocols); NPrivate::Read(_readable, _version, Reason); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3806,10 +3806,10 @@ void TJoinGroupRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _vers NPrivate::Write(_collector, _writable, _version, ProtocolType); NPrivate::Write(_collector, _writable, _version, Protocols); NPrivate::Write(_collector, _writable, _version, Reason); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3823,7 +3823,7 @@ i32 TJoinGroupRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ProtocolType); NPrivate::Size(_collector, _version, Protocols); NPrivate::Size(_collector, _version, Reason); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3836,7 +3836,7 @@ i32 TJoinGroupRequestData::Size(TKafkaVersion _version) const { // const TJoinGroupRequestData::TJoinGroupRequestProtocol::NameMeta::Type TJoinGroupRequestData::TJoinGroupRequestProtocol::NameMeta::Default = {""}; -TJoinGroupRequestData::TJoinGroupRequestProtocol::TJoinGroupRequestProtocol() +TJoinGroupRequestData::TJoinGroupRequestProtocol::TJoinGroupRequestProtocol() : Name(NameMeta::Default) {} @@ -3846,7 +3846,7 @@ void TJoinGroupRequestData::TJoinGroupRequestProtocol::Read(TKafkaReadable& _rea } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Metadata); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3868,10 +3868,10 @@ void TJoinGroupRequestData::TJoinGroupRequestProtocol::Write(TKafkaWritable& _wr NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Metadata); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3879,7 +3879,7 @@ i32 TJoinGroupRequestData::TJoinGroupRequestProtocol::Size(TKafkaVersion _versio NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Metadata); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3899,7 +3899,7 @@ const TJoinGroupResponseData::LeaderMeta::Type TJoinGroupResponseData::LeaderMet const TJoinGroupResponseData::SkipAssignmentMeta::Type TJoinGroupResponseData::SkipAssignmentMeta::Default = false; const TJoinGroupResponseData::MemberIdMeta::Type TJoinGroupResponseData::MemberIdMeta::Default = {""}; -TJoinGroupResponseData::TJoinGroupResponseData() +TJoinGroupResponseData::TJoinGroupResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) , GenerationId(GenerationIdMeta::Default) @@ -3923,7 +3923,7 @@ void TJoinGroupResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _vers NPrivate::Read(_readable, _version, SkipAssignment); NPrivate::Read(_readable, _version, MemberId); NPrivate::Read(_readable, _version, Members); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -3952,10 +3952,10 @@ void TJoinGroupResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _ver NPrivate::Write(_collector, _writable, _version, SkipAssignment); NPrivate::Write(_collector, _writable, _version, MemberId); NPrivate::Write(_collector, _writable, _version, Members); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -3970,7 +3970,7 @@ i32 TJoinGroupResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, SkipAssignment); NPrivate::Size(_collector, _version, MemberId); NPrivate::Size(_collector, _version, Members); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -3984,7 +3984,7 @@ i32 TJoinGroupResponseData::Size(TKafkaVersion _version) const { const TJoinGroupResponseData::TJoinGroupResponseMember::MemberIdMeta::Type TJoinGroupResponseData::TJoinGroupResponseMember::MemberIdMeta::Default = {""}; const TJoinGroupResponseData::TJoinGroupResponseMember::GroupInstanceIdMeta::Type TJoinGroupResponseData::TJoinGroupResponseMember::GroupInstanceIdMeta::Default = std::nullopt; -TJoinGroupResponseData::TJoinGroupResponseMember::TJoinGroupResponseMember() +TJoinGroupResponseData::TJoinGroupResponseMember::TJoinGroupResponseMember() : MemberId(MemberIdMeta::Default) , GroupInstanceId(GroupInstanceIdMeta::Default) {} @@ -3996,7 +3996,7 @@ void TJoinGroupResponseData::TJoinGroupResponseMember::Read(TKafkaReadable& _rea NPrivate::Read(_readable, _version, MemberId); NPrivate::Read(_readable, _version, GroupInstanceId); NPrivate::Read(_readable, _version, Metadata); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4019,10 +4019,10 @@ void TJoinGroupResponseData::TJoinGroupResponseMember::Write(TKafkaWritable& _wr NPrivate::Write(_collector, _writable, _version, MemberId); NPrivate::Write(_collector, _writable, _version, GroupInstanceId); NPrivate::Write(_collector, _writable, _version, Metadata); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4031,7 +4031,7 @@ i32 TJoinGroupResponseData::TJoinGroupResponseMember::Size(TKafkaVersion _versio NPrivate::Size(_collector, _version, MemberId); NPrivate::Size(_collector, _version, GroupInstanceId); NPrivate::Size(_collector, _version, Metadata); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4047,7 +4047,7 @@ const THeartbeatRequestData::GenerationIdMeta::Type THeartbeatRequestData::Gener const THeartbeatRequestData::MemberIdMeta::Type THeartbeatRequestData::MemberIdMeta::Default = {""}; const THeartbeatRequestData::GroupInstanceIdMeta::Type THeartbeatRequestData::GroupInstanceIdMeta::Default = std::nullopt; -THeartbeatRequestData::THeartbeatRequestData() +THeartbeatRequestData::THeartbeatRequestData() : GroupId(GroupIdMeta::Default) , GenerationId(GenerationIdMeta::Default) , MemberId(MemberIdMeta::Default) @@ -4062,7 +4062,7 @@ void THeartbeatRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _versi NPrivate::Read(_readable, _version, GenerationId); NPrivate::Read(_readable, _version, MemberId); NPrivate::Read(_readable, _version, GroupInstanceId); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4086,10 +4086,10 @@ void THeartbeatRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _vers NPrivate::Write(_collector, _writable, _version, GenerationId); NPrivate::Write(_collector, _writable, _version, MemberId); NPrivate::Write(_collector, _writable, _version, GroupInstanceId); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4099,7 +4099,7 @@ i32 THeartbeatRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, GenerationId); NPrivate::Size(_collector, _version, MemberId); NPrivate::Size(_collector, _version, GroupInstanceId); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4113,7 +4113,7 @@ i32 THeartbeatRequestData::Size(TKafkaVersion _version) const { const THeartbeatResponseData::ThrottleTimeMsMeta::Type THeartbeatResponseData::ThrottleTimeMsMeta::Default = 0; const THeartbeatResponseData::ErrorCodeMeta::Type THeartbeatResponseData::ErrorCodeMeta::Default = 0; -THeartbeatResponseData::THeartbeatResponseData() +THeartbeatResponseData::THeartbeatResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) {} @@ -4124,7 +4124,7 @@ void THeartbeatResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _vers } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4146,10 +4146,10 @@ void THeartbeatResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _ver NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4157,7 +4157,7 @@ i32 THeartbeatResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4171,7 +4171,7 @@ i32 THeartbeatResponseData::Size(TKafkaVersion _version) const { const TLeaveGroupRequestData::GroupIdMeta::Type TLeaveGroupRequestData::GroupIdMeta::Default = {""}; const TLeaveGroupRequestData::MemberIdMeta::Type TLeaveGroupRequestData::MemberIdMeta::Default = {""}; -TLeaveGroupRequestData::TLeaveGroupRequestData() +TLeaveGroupRequestData::TLeaveGroupRequestData() : GroupId(GroupIdMeta::Default) , MemberId(MemberIdMeta::Default) {} @@ -4183,7 +4183,7 @@ void TLeaveGroupRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _vers NPrivate::Read(_readable, _version, GroupId); NPrivate::Read(_readable, _version, MemberId); NPrivate::Read(_readable, _version, Members); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4206,10 +4206,10 @@ void TLeaveGroupRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _ver NPrivate::Write(_collector, _writable, _version, GroupId); NPrivate::Write(_collector, _writable, _version, MemberId); NPrivate::Write(_collector, _writable, _version, Members); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4218,7 +4218,7 @@ i32 TLeaveGroupRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, GroupId); NPrivate::Size(_collector, _version, MemberId); NPrivate::Size(_collector, _version, Members); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4233,7 +4233,7 @@ const TLeaveGroupRequestData::TMemberIdentity::MemberIdMeta::Type TLeaveGroupReq const TLeaveGroupRequestData::TMemberIdentity::GroupInstanceIdMeta::Type TLeaveGroupRequestData::TMemberIdentity::GroupInstanceIdMeta::Default = std::nullopt; const TLeaveGroupRequestData::TMemberIdentity::ReasonMeta::Type TLeaveGroupRequestData::TMemberIdentity::ReasonMeta::Default = std::nullopt; -TLeaveGroupRequestData::TMemberIdentity::TMemberIdentity() +TLeaveGroupRequestData::TMemberIdentity::TMemberIdentity() : MemberId(MemberIdMeta::Default) , GroupInstanceId(GroupInstanceIdMeta::Default) , Reason(ReasonMeta::Default) @@ -4246,7 +4246,7 @@ void TLeaveGroupRequestData::TMemberIdentity::Read(TKafkaReadable& _readable, TK NPrivate::Read(_readable, _version, MemberId); NPrivate::Read(_readable, _version, GroupInstanceId); NPrivate::Read(_readable, _version, Reason); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4269,10 +4269,10 @@ void TLeaveGroupRequestData::TMemberIdentity::Write(TKafkaWritable& _writable, T NPrivate::Write(_collector, _writable, _version, MemberId); NPrivate::Write(_collector, _writable, _version, GroupInstanceId); NPrivate::Write(_collector, _writable, _version, Reason); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4281,7 +4281,7 @@ i32 TLeaveGroupRequestData::TMemberIdentity::Size(TKafkaVersion _version) const NPrivate::Size(_collector, _version, MemberId); NPrivate::Size(_collector, _version, GroupInstanceId); NPrivate::Size(_collector, _version, Reason); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4295,7 +4295,7 @@ i32 TLeaveGroupRequestData::TMemberIdentity::Size(TKafkaVersion _version) const const TLeaveGroupResponseData::ThrottleTimeMsMeta::Type TLeaveGroupResponseData::ThrottleTimeMsMeta::Default = 0; const TLeaveGroupResponseData::ErrorCodeMeta::Type TLeaveGroupResponseData::ErrorCodeMeta::Default = 0; -TLeaveGroupResponseData::TLeaveGroupResponseData() +TLeaveGroupResponseData::TLeaveGroupResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) {} @@ -4307,7 +4307,7 @@ void TLeaveGroupResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _ver NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, ErrorCode); NPrivate::Read(_readable, _version, Members); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4330,10 +4330,10 @@ void TLeaveGroupResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _ve NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, ErrorCode); NPrivate::Write(_collector, _writable, _version, Members); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4342,7 +4342,7 @@ i32 TLeaveGroupResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, ErrorCode); NPrivate::Size(_collector, _version, Members); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4357,7 +4357,7 @@ const TLeaveGroupResponseData::TMemberResponse::MemberIdMeta::Type TLeaveGroupRe const TLeaveGroupResponseData::TMemberResponse::GroupInstanceIdMeta::Type TLeaveGroupResponseData::TMemberResponse::GroupInstanceIdMeta::Default = {""}; const TLeaveGroupResponseData::TMemberResponse::ErrorCodeMeta::Type TLeaveGroupResponseData::TMemberResponse::ErrorCodeMeta::Default = 0; -TLeaveGroupResponseData::TMemberResponse::TMemberResponse() +TLeaveGroupResponseData::TMemberResponse::TMemberResponse() : MemberId(MemberIdMeta::Default) , GroupInstanceId(GroupInstanceIdMeta::Default) , ErrorCode(ErrorCodeMeta::Default) @@ -4370,7 +4370,7 @@ void TLeaveGroupResponseData::TMemberResponse::Read(TKafkaReadable& _readable, T NPrivate::Read(_readable, _version, MemberId); NPrivate::Read(_readable, _version, GroupInstanceId); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4393,10 +4393,10 @@ void TLeaveGroupResponseData::TMemberResponse::Write(TKafkaWritable& _writable, NPrivate::Write(_collector, _writable, _version, MemberId); NPrivate::Write(_collector, _writable, _version, GroupInstanceId); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4405,7 +4405,7 @@ i32 TLeaveGroupResponseData::TMemberResponse::Size(TKafkaVersion _version) const NPrivate::Size(_collector, _version, MemberId); NPrivate::Size(_collector, _version, GroupInstanceId); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4423,7 +4423,7 @@ const TSyncGroupRequestData::GroupInstanceIdMeta::Type TSyncGroupRequestData::Gr const TSyncGroupRequestData::ProtocolTypeMeta::Type TSyncGroupRequestData::ProtocolTypeMeta::Default = std::nullopt; const TSyncGroupRequestData::ProtocolNameMeta::Type TSyncGroupRequestData::ProtocolNameMeta::Default = std::nullopt; -TSyncGroupRequestData::TSyncGroupRequestData() +TSyncGroupRequestData::TSyncGroupRequestData() : GroupId(GroupIdMeta::Default) , GenerationId(GenerationIdMeta::Default) , MemberId(MemberIdMeta::Default) @@ -4443,7 +4443,7 @@ void TSyncGroupRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _versi NPrivate::Read(_readable, _version, ProtocolType); NPrivate::Read(_readable, _version, ProtocolName); NPrivate::Read(_readable, _version, Assignments); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4470,10 +4470,10 @@ void TSyncGroupRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _vers NPrivate::Write(_collector, _writable, _version, ProtocolType); NPrivate::Write(_collector, _writable, _version, ProtocolName); NPrivate::Write(_collector, _writable, _version, Assignments); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4486,7 +4486,7 @@ i32 TSyncGroupRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ProtocolType); NPrivate::Size(_collector, _version, ProtocolName); NPrivate::Size(_collector, _version, Assignments); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4499,7 +4499,7 @@ i32 TSyncGroupRequestData::Size(TKafkaVersion _version) const { // const TSyncGroupRequestData::TSyncGroupRequestAssignment::MemberIdMeta::Type TSyncGroupRequestData::TSyncGroupRequestAssignment::MemberIdMeta::Default = {""}; -TSyncGroupRequestData::TSyncGroupRequestAssignment::TSyncGroupRequestAssignment() +TSyncGroupRequestData::TSyncGroupRequestAssignment::TSyncGroupRequestAssignment() : MemberId(MemberIdMeta::Default) {} @@ -4509,7 +4509,7 @@ void TSyncGroupRequestData::TSyncGroupRequestAssignment::Read(TKafkaReadable& _r } NPrivate::Read(_readable, _version, MemberId); NPrivate::Read(_readable, _version, Assignment); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4531,10 +4531,10 @@ void TSyncGroupRequestData::TSyncGroupRequestAssignment::Write(TKafkaWritable& _ NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, MemberId); NPrivate::Write(_collector, _writable, _version, Assignment); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4542,7 +4542,7 @@ i32 TSyncGroupRequestData::TSyncGroupRequestAssignment::Size(TKafkaVersion _vers NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, MemberId); NPrivate::Size(_collector, _version, Assignment); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4558,7 +4558,7 @@ const TSyncGroupResponseData::ErrorCodeMeta::Type TSyncGroupResponseData::ErrorC const TSyncGroupResponseData::ProtocolTypeMeta::Type TSyncGroupResponseData::ProtocolTypeMeta::Default = std::nullopt; const TSyncGroupResponseData::ProtocolNameMeta::Type TSyncGroupResponseData::ProtocolNameMeta::Default = std::nullopt; -TSyncGroupResponseData::TSyncGroupResponseData() +TSyncGroupResponseData::TSyncGroupResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) , ProtocolType(ProtocolTypeMeta::Default) @@ -4574,7 +4574,7 @@ void TSyncGroupResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _vers NPrivate::Read(_readable, _version, ProtocolType); NPrivate::Read(_readable, _version, ProtocolName); NPrivate::Read(_readable, _version, Assignment); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4599,10 +4599,10 @@ void TSyncGroupResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _ver NPrivate::Write(_collector, _writable, _version, ProtocolType); NPrivate::Write(_collector, _writable, _version, ProtocolName); NPrivate::Write(_collector, _writable, _version, Assignment); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4613,7 +4613,7 @@ i32 TSyncGroupResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ProtocolType); NPrivate::Size(_collector, _version, ProtocolName); NPrivate::Size(_collector, _version, Assignment); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4626,7 +4626,7 @@ i32 TSyncGroupResponseData::Size(TKafkaVersion _version) const { // const TSaslHandshakeRequestData::MechanismMeta::Type TSaslHandshakeRequestData::MechanismMeta::Default = {""}; -TSaslHandshakeRequestData::TSaslHandshakeRequestData() +TSaslHandshakeRequestData::TSaslHandshakeRequestData() : Mechanism(MechanismMeta::Default) {} @@ -4635,7 +4635,7 @@ void TSaslHandshakeRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _v ythrow yexception() << "Can't read version " << _version << " of TSaslHandshakeRequestData"; } NPrivate::Read(_readable, _version, Mechanism); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4656,17 +4656,17 @@ void TSaslHandshakeRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _ } NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Mechanism); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } i32 TSaslHandshakeRequestData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Mechanism); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4679,7 +4679,7 @@ i32 TSaslHandshakeRequestData::Size(TKafkaVersion _version) const { // const TSaslHandshakeResponseData::ErrorCodeMeta::Type TSaslHandshakeResponseData::ErrorCodeMeta::Default = 0; -TSaslHandshakeResponseData::TSaslHandshakeResponseData() +TSaslHandshakeResponseData::TSaslHandshakeResponseData() : ErrorCode(ErrorCodeMeta::Default) {} @@ -4689,7 +4689,7 @@ void TSaslHandshakeResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _ } NPrivate::Read(_readable, _version, ErrorCode); NPrivate::Read(_readable, _version, Mechanisms); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4711,10 +4711,10 @@ void TSaslHandshakeResponseData::Write(TKafkaWritable& _writable, TKafkaVersion NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ErrorCode); NPrivate::Write(_collector, _writable, _version, Mechanisms); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4722,7 +4722,7 @@ i32 TSaslHandshakeResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ErrorCode); NPrivate::Size(_collector, _version, Mechanisms); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4736,7 +4736,7 @@ i32 TSaslHandshakeResponseData::Size(TKafkaVersion _version) const { const TApiVersionsRequestData::ClientSoftwareNameMeta::Type TApiVersionsRequestData::ClientSoftwareNameMeta::Default = {""}; const TApiVersionsRequestData::ClientSoftwareVersionMeta::Type TApiVersionsRequestData::ClientSoftwareVersionMeta::Default = {""}; -TApiVersionsRequestData::TApiVersionsRequestData() +TApiVersionsRequestData::TApiVersionsRequestData() : ClientSoftwareName(ClientSoftwareNameMeta::Default) , ClientSoftwareVersion(ClientSoftwareVersionMeta::Default) {} @@ -4747,7 +4747,7 @@ void TApiVersionsRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _ver } NPrivate::Read(_readable, _version, ClientSoftwareName); NPrivate::Read(_readable, _version, ClientSoftwareVersion); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4769,10 +4769,10 @@ void TApiVersionsRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _ve NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ClientSoftwareName); NPrivate::Write(_collector, _writable, _version, ClientSoftwareVersion); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4780,7 +4780,7 @@ i32 TApiVersionsRequestData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ClientSoftwareName); NPrivate::Size(_collector, _version, ClientSoftwareVersion); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4796,7 +4796,7 @@ const TApiVersionsResponseData::ThrottleTimeMsMeta::Type TApiVersionsResponseDat const TApiVersionsResponseData::FinalizedFeaturesEpochMeta::Type TApiVersionsResponseData::FinalizedFeaturesEpochMeta::Default = -1; const TApiVersionsResponseData::ZkMigrationReadyMeta::Type TApiVersionsResponseData::ZkMigrationReadyMeta::Default = false; -TApiVersionsResponseData::TApiVersionsResponseData() +TApiVersionsResponseData::TApiVersionsResponseData() : ErrorCode(ErrorCodeMeta::Default) , ThrottleTimeMs(ThrottleTimeMsMeta::Default) , FinalizedFeaturesEpoch(FinalizedFeaturesEpochMeta::Default) @@ -4814,7 +4814,7 @@ void TApiVersionsResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _ve NPrivate::Read(_readable, _version, FinalizedFeaturesEpoch); NPrivate::Read(_readable, _version, FinalizedFeatures); NPrivate::Read(_readable, _version, ZkMigrationReady); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4853,10 +4853,10 @@ void TApiVersionsResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _v NPrivate::Write(_collector, _writable, _version, FinalizedFeaturesEpoch); NPrivate::Write(_collector, _writable, _version, FinalizedFeatures); NPrivate::Write(_collector, _writable, _version, ZkMigrationReady); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + NPrivate::WriteTag(_writable, _version, SupportedFeatures); NPrivate::WriteTag(_writable, _version, FinalizedFeaturesEpoch); NPrivate::WriteTag(_writable, _version, FinalizedFeatures); @@ -4873,7 +4873,7 @@ i32 TApiVersionsResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, FinalizedFeaturesEpoch); NPrivate::Size(_collector, _version, FinalizedFeatures); NPrivate::Size(_collector, _version, ZkMigrationReady); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4888,7 +4888,7 @@ const TApiVersionsResponseData::TApiVersion::ApiKeyMeta::Type TApiVersionsRespon const TApiVersionsResponseData::TApiVersion::MinVersionMeta::Type TApiVersionsResponseData::TApiVersion::MinVersionMeta::Default = 0; const TApiVersionsResponseData::TApiVersion::MaxVersionMeta::Type TApiVersionsResponseData::TApiVersion::MaxVersionMeta::Default = 0; -TApiVersionsResponseData::TApiVersion::TApiVersion() +TApiVersionsResponseData::TApiVersion::TApiVersion() : ApiKey(ApiKeyMeta::Default) , MinVersion(MinVersionMeta::Default) , MaxVersion(MaxVersionMeta::Default) @@ -4901,7 +4901,7 @@ void TApiVersionsResponseData::TApiVersion::Read(TKafkaReadable& _readable, TKaf NPrivate::Read(_readable, _version, ApiKey); NPrivate::Read(_readable, _version, MinVersion); NPrivate::Read(_readable, _version, MaxVersion); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4924,10 +4924,10 @@ void TApiVersionsResponseData::TApiVersion::Write(TKafkaWritable& _writable, TKa NPrivate::Write(_collector, _writable, _version, ApiKey); NPrivate::Write(_collector, _writable, _version, MinVersion); NPrivate::Write(_collector, _writable, _version, MaxVersion); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4936,7 +4936,7 @@ i32 TApiVersionsResponseData::TApiVersion::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ApiKey); NPrivate::Size(_collector, _version, MinVersion); NPrivate::Size(_collector, _version, MaxVersion); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -4951,7 +4951,7 @@ const TApiVersionsResponseData::TSupportedFeatureKey::NameMeta::Type TApiVersion const TApiVersionsResponseData::TSupportedFeatureKey::MinVersionMeta::Type TApiVersionsResponseData::TSupportedFeatureKey::MinVersionMeta::Default = 0; const TApiVersionsResponseData::TSupportedFeatureKey::MaxVersionMeta::Type TApiVersionsResponseData::TSupportedFeatureKey::MaxVersionMeta::Default = 0; -TApiVersionsResponseData::TSupportedFeatureKey::TSupportedFeatureKey() +TApiVersionsResponseData::TSupportedFeatureKey::TSupportedFeatureKey() : Name(NameMeta::Default) , MinVersion(MinVersionMeta::Default) , MaxVersion(MaxVersionMeta::Default) @@ -4964,7 +4964,7 @@ void TApiVersionsResponseData::TSupportedFeatureKey::Read(TKafkaReadable& _reada NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, MinVersion); NPrivate::Read(_readable, _version, MaxVersion); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -4987,10 +4987,10 @@ void TApiVersionsResponseData::TSupportedFeatureKey::Write(TKafkaWritable& _writ NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, MinVersion); NPrivate::Write(_collector, _writable, _version, MaxVersion); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -4999,7 +4999,7 @@ i32 TApiVersionsResponseData::TSupportedFeatureKey::Size(TKafkaVersion _version) NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, MinVersion); NPrivate::Size(_collector, _version, MaxVersion); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5014,7 +5014,7 @@ const TApiVersionsResponseData::TFinalizedFeatureKey::NameMeta::Type TApiVersion const TApiVersionsResponseData::TFinalizedFeatureKey::MaxVersionLevelMeta::Type TApiVersionsResponseData::TFinalizedFeatureKey::MaxVersionLevelMeta::Default = 0; const TApiVersionsResponseData::TFinalizedFeatureKey::MinVersionLevelMeta::Type TApiVersionsResponseData::TFinalizedFeatureKey::MinVersionLevelMeta::Default = 0; -TApiVersionsResponseData::TFinalizedFeatureKey::TFinalizedFeatureKey() +TApiVersionsResponseData::TFinalizedFeatureKey::TFinalizedFeatureKey() : Name(NameMeta::Default) , MaxVersionLevel(MaxVersionLevelMeta::Default) , MinVersionLevel(MinVersionLevelMeta::Default) @@ -5027,7 +5027,7 @@ void TApiVersionsResponseData::TFinalizedFeatureKey::Read(TKafkaReadable& _reada NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, MaxVersionLevel); NPrivate::Read(_readable, _version, MinVersionLevel); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5050,10 +5050,10 @@ void TApiVersionsResponseData::TFinalizedFeatureKey::Write(TKafkaWritable& _writ NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, MaxVersionLevel); NPrivate::Write(_collector, _writable, _version, MinVersionLevel); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5062,7 +5062,7 @@ i32 TApiVersionsResponseData::TFinalizedFeatureKey::Size(TKafkaVersion _version) NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, MaxVersionLevel); NPrivate::Size(_collector, _version, MinVersionLevel); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5076,7 +5076,7 @@ i32 TApiVersionsResponseData::TFinalizedFeatureKey::Size(TKafkaVersion _version) const TCreateTopicsRequestData::TimeoutMsMeta::Type TCreateTopicsRequestData::TimeoutMsMeta::Default = 60000; const TCreateTopicsRequestData::ValidateOnlyMeta::Type TCreateTopicsRequestData::ValidateOnlyMeta::Default = false; -TCreateTopicsRequestData::TCreateTopicsRequestData() +TCreateTopicsRequestData::TCreateTopicsRequestData() : TimeoutMs(TimeoutMsMeta::Default) , ValidateOnly(ValidateOnlyMeta::Default) {} @@ -5088,7 +5088,7 @@ void TCreateTopicsRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _ve NPrivate::Read(_readable, _version, Topics); NPrivate::Read(_readable, _version, TimeoutMs); NPrivate::Read(_readable, _version, ValidateOnly); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5111,10 +5111,10 @@ void TCreateTopicsRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _v NPrivate::Write(_collector, _writable, _version, Topics); NPrivate::Write(_collector, _writable, _version, TimeoutMs); NPrivate::Write(_collector, _writable, _version, ValidateOnly); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5123,7 +5123,7 @@ i32 TCreateTopicsRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Topics); NPrivate::Size(_collector, _version, TimeoutMs); NPrivate::Size(_collector, _version, ValidateOnly); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5138,7 +5138,7 @@ const TCreateTopicsRequestData::TCreatableTopic::NameMeta::Type TCreateTopicsReq const TCreateTopicsRequestData::TCreatableTopic::NumPartitionsMeta::Type TCreateTopicsRequestData::TCreatableTopic::NumPartitionsMeta::Default = 0; const TCreateTopicsRequestData::TCreatableTopic::ReplicationFactorMeta::Type TCreateTopicsRequestData::TCreatableTopic::ReplicationFactorMeta::Default = 0; -TCreateTopicsRequestData::TCreatableTopic::TCreatableTopic() +TCreateTopicsRequestData::TCreatableTopic::TCreatableTopic() : Name(NameMeta::Default) , NumPartitions(NumPartitionsMeta::Default) , ReplicationFactor(ReplicationFactorMeta::Default) @@ -5153,7 +5153,7 @@ void TCreateTopicsRequestData::TCreatableTopic::Read(TKafkaReadable& _readable, NPrivate::Read(_readable, _version, ReplicationFactor); NPrivate::Read(_readable, _version, Assignments); NPrivate::Read(_readable, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5178,10 +5178,10 @@ void TCreateTopicsRequestData::TCreatableTopic::Write(TKafkaWritable& _writable, NPrivate::Write(_collector, _writable, _version, ReplicationFactor); NPrivate::Write(_collector, _writable, _version, Assignments); NPrivate::Write(_collector, _writable, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5192,7 +5192,7 @@ i32 TCreateTopicsRequestData::TCreatableTopic::Size(TKafkaVersion _version) cons NPrivate::Size(_collector, _version, ReplicationFactor); NPrivate::Size(_collector, _version, Assignments); NPrivate::Size(_collector, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5205,7 +5205,7 @@ i32 TCreateTopicsRequestData::TCreatableTopic::Size(TKafkaVersion _version) cons // const TCreateTopicsRequestData::TCreatableTopic::TCreatableReplicaAssignment::PartitionIndexMeta::Type TCreateTopicsRequestData::TCreatableTopic::TCreatableReplicaAssignment::PartitionIndexMeta::Default = 0; -TCreateTopicsRequestData::TCreatableTopic::TCreatableReplicaAssignment::TCreatableReplicaAssignment() +TCreateTopicsRequestData::TCreatableTopic::TCreatableReplicaAssignment::TCreatableReplicaAssignment() : PartitionIndex(PartitionIndexMeta::Default) {} @@ -5215,7 +5215,7 @@ void TCreateTopicsRequestData::TCreatableTopic::TCreatableReplicaAssignment::Rea } NPrivate::Read(_readable, _version, PartitionIndex); NPrivate::Read(_readable, _version, BrokerIds); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5237,10 +5237,10 @@ void TCreateTopicsRequestData::TCreatableTopic::TCreatableReplicaAssignment::Wri NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, PartitionIndex); NPrivate::Write(_collector, _writable, _version, BrokerIds); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5248,7 +5248,7 @@ i32 TCreateTopicsRequestData::TCreatableTopic::TCreatableReplicaAssignment::Size NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, PartitionIndex); NPrivate::Size(_collector, _version, BrokerIds); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5262,7 +5262,7 @@ i32 TCreateTopicsRequestData::TCreatableTopic::TCreatableReplicaAssignment::Size const TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::NameMeta::Type TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::NameMeta::Default = {""}; const TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::ValueMeta::Type TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::ValueMeta::Default = {""}; -TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::TCreateableTopicConfig() +TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::TCreateableTopicConfig() : Name(NameMeta::Default) , Value(ValueMeta::Default) {} @@ -5273,7 +5273,7 @@ void TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::Read(TKa } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Value); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5295,10 +5295,10 @@ void TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::Write(TK NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Value); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5306,7 +5306,7 @@ i32 TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::Size(TKaf NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Value); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5319,7 +5319,7 @@ i32 TCreateTopicsRequestData::TCreatableTopic::TCreateableTopicConfig::Size(TKaf // const TCreateTopicsResponseData::ThrottleTimeMsMeta::Type TCreateTopicsResponseData::ThrottleTimeMsMeta::Default = 0; -TCreateTopicsResponseData::TCreateTopicsResponseData() +TCreateTopicsResponseData::TCreateTopicsResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) {} @@ -5329,7 +5329,7 @@ void TCreateTopicsResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _v } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5351,10 +5351,10 @@ void TCreateTopicsResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _ NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5362,7 +5362,7 @@ i32 TCreateTopicsResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5381,7 +5381,7 @@ const TCreateTopicsResponseData::TCreatableTopicResult::TopicConfigErrorCodeMeta const TCreateTopicsResponseData::TCreatableTopicResult::NumPartitionsMeta::Type TCreateTopicsResponseData::TCreatableTopicResult::NumPartitionsMeta::Default = -1; const TCreateTopicsResponseData::TCreatableTopicResult::ReplicationFactorMeta::Type TCreateTopicsResponseData::TCreatableTopicResult::ReplicationFactorMeta::Default = -1; -TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicResult() +TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicResult() : Name(NameMeta::Default) , TopicId(TopicIdMeta::Default) , ErrorCode(ErrorCodeMeta::Default) @@ -5403,7 +5403,7 @@ void TCreateTopicsResponseData::TCreatableTopicResult::Read(TKafkaReadable& _rea NPrivate::Read(_readable, _version, NumPartitions); NPrivate::Read(_readable, _version, ReplicationFactor); NPrivate::Read(_readable, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5434,10 +5434,10 @@ void TCreateTopicsResponseData::TCreatableTopicResult::Write(TKafkaWritable& _wr NPrivate::Write(_collector, _writable, _version, NumPartitions); NPrivate::Write(_collector, _writable, _version, ReplicationFactor); NPrivate::Write(_collector, _writable, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + NPrivate::WriteTag(_writable, _version, TopicConfigErrorCode); } } @@ -5452,7 +5452,7 @@ i32 TCreateTopicsResponseData::TCreatableTopicResult::Size(TKafkaVersion _versio NPrivate::Size(_collector, _version, NumPartitions); NPrivate::Size(_collector, _version, ReplicationFactor); NPrivate::Size(_collector, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5469,7 +5469,7 @@ const TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs:: const TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs::ConfigSourceMeta::Type TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs::ConfigSourceMeta::Default = -1; const TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs::IsSensitiveMeta::Type TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs::IsSensitiveMeta::Default = false; -TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs::TCreatableTopicConfigs() +TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs::TCreatableTopicConfigs() : Name(NameMeta::Default) , Value(ValueMeta::Default) , ReadOnly(ReadOnlyMeta::Default) @@ -5486,7 +5486,7 @@ void TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs::R NPrivate::Read(_readable, _version, ReadOnly); NPrivate::Read(_readable, _version, ConfigSource); NPrivate::Read(_readable, _version, IsSensitive); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5511,10 +5511,10 @@ void TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs::W NPrivate::Write(_collector, _writable, _version, ReadOnly); NPrivate::Write(_collector, _writable, _version, ConfigSource); NPrivate::Write(_collector, _writable, _version, IsSensitive); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5525,7 +5525,7 @@ i32 TCreateTopicsResponseData::TCreatableTopicResult::TCreatableTopicConfigs::Si NPrivate::Size(_collector, _version, ReadOnly); NPrivate::Size(_collector, _version, ConfigSource); NPrivate::Size(_collector, _version, IsSensitive); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5541,7 +5541,7 @@ const TInitProducerIdRequestData::TransactionTimeoutMsMeta::Type TInitProducerId const TInitProducerIdRequestData::ProducerIdMeta::Type TInitProducerIdRequestData::ProducerIdMeta::Default = -1; const TInitProducerIdRequestData::ProducerEpochMeta::Type TInitProducerIdRequestData::ProducerEpochMeta::Default = -1; -TInitProducerIdRequestData::TInitProducerIdRequestData() +TInitProducerIdRequestData::TInitProducerIdRequestData() : TransactionalId(TransactionalIdMeta::Default) , TransactionTimeoutMs(TransactionTimeoutMsMeta::Default) , ProducerId(ProducerIdMeta::Default) @@ -5556,7 +5556,7 @@ void TInitProducerIdRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _ NPrivate::Read(_readable, _version, TransactionTimeoutMs); NPrivate::Read(_readable, _version, ProducerId); NPrivate::Read(_readable, _version, ProducerEpoch); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5580,10 +5580,10 @@ void TInitProducerIdRequestData::Write(TKafkaWritable& _writable, TKafkaVersion NPrivate::Write(_collector, _writable, _version, TransactionTimeoutMs); NPrivate::Write(_collector, _writable, _version, ProducerId); NPrivate::Write(_collector, _writable, _version, ProducerEpoch); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5593,7 +5593,7 @@ i32 TInitProducerIdRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, TransactionTimeoutMs); NPrivate::Size(_collector, _version, ProducerId); NPrivate::Size(_collector, _version, ProducerEpoch); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5609,7 +5609,7 @@ const TInitProducerIdResponseData::ErrorCodeMeta::Type TInitProducerIdResponseDa const TInitProducerIdResponseData::ProducerIdMeta::Type TInitProducerIdResponseData::ProducerIdMeta::Default = -1; const TInitProducerIdResponseData::ProducerEpochMeta::Type TInitProducerIdResponseData::ProducerEpochMeta::Default = 0; -TInitProducerIdResponseData::TInitProducerIdResponseData() +TInitProducerIdResponseData::TInitProducerIdResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) , ProducerId(ProducerIdMeta::Default) @@ -5624,7 +5624,7 @@ void TInitProducerIdResponseData::Read(TKafkaReadable& _readable, TKafkaVersion NPrivate::Read(_readable, _version, ErrorCode); NPrivate::Read(_readable, _version, ProducerId); NPrivate::Read(_readable, _version, ProducerEpoch); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5648,10 +5648,10 @@ void TInitProducerIdResponseData::Write(TKafkaWritable& _writable, TKafkaVersion NPrivate::Write(_collector, _writable, _version, ErrorCode); NPrivate::Write(_collector, _writable, _version, ProducerId); NPrivate::Write(_collector, _writable, _version, ProducerEpoch); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5661,7 +5661,7 @@ i32 TInitProducerIdResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ErrorCode); NPrivate::Size(_collector, _version, ProducerId); NPrivate::Size(_collector, _version, ProducerEpoch); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5676,7 +5676,7 @@ const TAddPartitionsToTxnRequestData::TransactionalIdMeta::Type TAddPartitionsTo const TAddPartitionsToTxnRequestData::ProducerIdMeta::Type TAddPartitionsToTxnRequestData::ProducerIdMeta::Default = 0; const TAddPartitionsToTxnRequestData::ProducerEpochMeta::Type TAddPartitionsToTxnRequestData::ProducerEpochMeta::Default = 0; -TAddPartitionsToTxnRequestData::TAddPartitionsToTxnRequestData() +TAddPartitionsToTxnRequestData::TAddPartitionsToTxnRequestData() : TransactionalId(TransactionalIdMeta::Default) , ProducerId(ProducerIdMeta::Default) , ProducerEpoch(ProducerEpochMeta::Default) @@ -5690,7 +5690,7 @@ void TAddPartitionsToTxnRequestData::Read(TKafkaReadable& _readable, TKafkaVersi NPrivate::Read(_readable, _version, ProducerId); NPrivate::Read(_readable, _version, ProducerEpoch); NPrivate::Read(_readable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5714,10 +5714,10 @@ void TAddPartitionsToTxnRequestData::Write(TKafkaWritable& _writable, TKafkaVers NPrivate::Write(_collector, _writable, _version, ProducerId); NPrivate::Write(_collector, _writable, _version, ProducerEpoch); NPrivate::Write(_collector, _writable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5727,7 +5727,7 @@ i32 TAddPartitionsToTxnRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ProducerId); NPrivate::Size(_collector, _version, ProducerEpoch); NPrivate::Size(_collector, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5740,7 +5740,7 @@ i32 TAddPartitionsToTxnRequestData::Size(TKafkaVersion _version) const { // const TAddPartitionsToTxnRequestData::TAddPartitionsToTxnTopic::NameMeta::Type TAddPartitionsToTxnRequestData::TAddPartitionsToTxnTopic::NameMeta::Default = {""}; -TAddPartitionsToTxnRequestData::TAddPartitionsToTxnTopic::TAddPartitionsToTxnTopic() +TAddPartitionsToTxnRequestData::TAddPartitionsToTxnTopic::TAddPartitionsToTxnTopic() : Name(NameMeta::Default) {} @@ -5750,7 +5750,7 @@ void TAddPartitionsToTxnRequestData::TAddPartitionsToTxnTopic::Read(TKafkaReadab } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5772,10 +5772,10 @@ void TAddPartitionsToTxnRequestData::TAddPartitionsToTxnTopic::Write(TKafkaWrita NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5783,7 +5783,7 @@ i32 TAddPartitionsToTxnRequestData::TAddPartitionsToTxnTopic::Size(TKafkaVersion NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5796,7 +5796,7 @@ i32 TAddPartitionsToTxnRequestData::TAddPartitionsToTxnTopic::Size(TKafkaVersion // const TAddPartitionsToTxnResponseData::ThrottleTimeMsMeta::Type TAddPartitionsToTxnResponseData::ThrottleTimeMsMeta::Default = 0; -TAddPartitionsToTxnResponseData::TAddPartitionsToTxnResponseData() +TAddPartitionsToTxnResponseData::TAddPartitionsToTxnResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) {} @@ -5806,7 +5806,7 @@ void TAddPartitionsToTxnResponseData::Read(TKafkaReadable& _readable, TKafkaVers } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, Results); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5828,10 +5828,10 @@ void TAddPartitionsToTxnResponseData::Write(TKafkaWritable& _writable, TKafkaVer NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, Results); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5839,7 +5839,7 @@ i32 TAddPartitionsToTxnResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, Results); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5852,7 +5852,7 @@ i32 TAddPartitionsToTxnResponseData::Size(TKafkaVersion _version) const { // const TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::NameMeta::Type TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::NameMeta::Default = {""}; -TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartitionsToTxnTopicResult() +TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartitionsToTxnTopicResult() : Name(NameMeta::Default) {} @@ -5862,7 +5862,7 @@ void TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::Read(TKafk } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Results); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5884,10 +5884,10 @@ void TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::Write(TKaf NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Results); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5895,7 +5895,7 @@ i32 TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::Size(TKafka NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Results); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5909,7 +5909,7 @@ i32 TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::Size(TKafka const TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartitionsToTxnPartitionResult::PartitionIndexMeta::Type TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartitionsToTxnPartitionResult::PartitionIndexMeta::Default = 0; const TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartitionsToTxnPartitionResult::ErrorCodeMeta::Type TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartitionsToTxnPartitionResult::ErrorCodeMeta::Default = 0; -TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartitionsToTxnPartitionResult::TAddPartitionsToTxnPartitionResult() +TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartitionsToTxnPartitionResult::TAddPartitionsToTxnPartitionResult() : PartitionIndex(PartitionIndexMeta::Default) , ErrorCode(ErrorCodeMeta::Default) {} @@ -5920,7 +5920,7 @@ void TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartit } NPrivate::Read(_readable, _version, PartitionIndex); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -5942,10 +5942,10 @@ void TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartit NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, PartitionIndex); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -5953,7 +5953,7 @@ i32 TAddPartitionsToTxnResponseData::TAddPartitionsToTxnTopicResult::TAddPartiti NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, PartitionIndex); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -5969,7 +5969,7 @@ const TAddOffsetsToTxnRequestData::ProducerIdMeta::Type TAddOffsetsToTxnRequestD const TAddOffsetsToTxnRequestData::ProducerEpochMeta::Type TAddOffsetsToTxnRequestData::ProducerEpochMeta::Default = 0; const TAddOffsetsToTxnRequestData::GroupIdMeta::Type TAddOffsetsToTxnRequestData::GroupIdMeta::Default = {""}; -TAddOffsetsToTxnRequestData::TAddOffsetsToTxnRequestData() +TAddOffsetsToTxnRequestData::TAddOffsetsToTxnRequestData() : TransactionalId(TransactionalIdMeta::Default) , ProducerId(ProducerIdMeta::Default) , ProducerEpoch(ProducerEpochMeta::Default) @@ -5984,7 +5984,7 @@ void TAddOffsetsToTxnRequestData::Read(TKafkaReadable& _readable, TKafkaVersion NPrivate::Read(_readable, _version, ProducerId); NPrivate::Read(_readable, _version, ProducerEpoch); NPrivate::Read(_readable, _version, GroupId); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6008,10 +6008,10 @@ void TAddOffsetsToTxnRequestData::Write(TKafkaWritable& _writable, TKafkaVersion NPrivate::Write(_collector, _writable, _version, ProducerId); NPrivate::Write(_collector, _writable, _version, ProducerEpoch); NPrivate::Write(_collector, _writable, _version, GroupId); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6021,7 +6021,7 @@ i32 TAddOffsetsToTxnRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ProducerId); NPrivate::Size(_collector, _version, ProducerEpoch); NPrivate::Size(_collector, _version, GroupId); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6035,7 +6035,7 @@ i32 TAddOffsetsToTxnRequestData::Size(TKafkaVersion _version) const { const TAddOffsetsToTxnResponseData::ThrottleTimeMsMeta::Type TAddOffsetsToTxnResponseData::ThrottleTimeMsMeta::Default = 0; const TAddOffsetsToTxnResponseData::ErrorCodeMeta::Type TAddOffsetsToTxnResponseData::ErrorCodeMeta::Default = 0; -TAddOffsetsToTxnResponseData::TAddOffsetsToTxnResponseData() +TAddOffsetsToTxnResponseData::TAddOffsetsToTxnResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) {} @@ -6046,7 +6046,7 @@ void TAddOffsetsToTxnResponseData::Read(TKafkaReadable& _readable, TKafkaVersion } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6068,10 +6068,10 @@ void TAddOffsetsToTxnResponseData::Write(TKafkaWritable& _writable, TKafkaVersio NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6079,7 +6079,7 @@ i32 TAddOffsetsToTxnResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6095,7 +6095,7 @@ const TEndTxnRequestData::ProducerIdMeta::Type TEndTxnRequestData::ProducerIdMet const TEndTxnRequestData::ProducerEpochMeta::Type TEndTxnRequestData::ProducerEpochMeta::Default = 0; const TEndTxnRequestData::CommittedMeta::Type TEndTxnRequestData::CommittedMeta::Default = false; -TEndTxnRequestData::TEndTxnRequestData() +TEndTxnRequestData::TEndTxnRequestData() : TransactionalId(TransactionalIdMeta::Default) , ProducerId(ProducerIdMeta::Default) , ProducerEpoch(ProducerEpochMeta::Default) @@ -6110,7 +6110,7 @@ void TEndTxnRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _version) NPrivate::Read(_readable, _version, ProducerId); NPrivate::Read(_readable, _version, ProducerEpoch); NPrivate::Read(_readable, _version, Committed); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6134,10 +6134,10 @@ void TEndTxnRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _version NPrivate::Write(_collector, _writable, _version, ProducerId); NPrivate::Write(_collector, _writable, _version, ProducerEpoch); NPrivate::Write(_collector, _writable, _version, Committed); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6147,7 +6147,7 @@ i32 TEndTxnRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ProducerId); NPrivate::Size(_collector, _version, ProducerEpoch); NPrivate::Size(_collector, _version, Committed); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6161,7 +6161,7 @@ i32 TEndTxnRequestData::Size(TKafkaVersion _version) const { const TEndTxnResponseData::ThrottleTimeMsMeta::Type TEndTxnResponseData::ThrottleTimeMsMeta::Default = 0; const TEndTxnResponseData::ErrorCodeMeta::Type TEndTxnResponseData::ErrorCodeMeta::Default = 0; -TEndTxnResponseData::TEndTxnResponseData() +TEndTxnResponseData::TEndTxnResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) , ErrorCode(ErrorCodeMeta::Default) {} @@ -6172,7 +6172,7 @@ void TEndTxnResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _version } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6194,10 +6194,10 @@ void TEndTxnResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _versio NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6205,7 +6205,7 @@ i32 TEndTxnResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6224,7 +6224,7 @@ const TTxnOffsetCommitRequestData::GenerationIdMeta::Type TTxnOffsetCommitReques const TTxnOffsetCommitRequestData::MemberIdMeta::Type TTxnOffsetCommitRequestData::MemberIdMeta::Default = {""}; const TTxnOffsetCommitRequestData::GroupInstanceIdMeta::Type TTxnOffsetCommitRequestData::GroupInstanceIdMeta::Default = std::nullopt; -TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestData() +TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestData() : TransactionalId(TransactionalIdMeta::Default) , GroupId(GroupIdMeta::Default) , ProducerId(ProducerIdMeta::Default) @@ -6246,7 +6246,7 @@ void TTxnOffsetCommitRequestData::Read(TKafkaReadable& _readable, TKafkaVersion NPrivate::Read(_readable, _version, MemberId); NPrivate::Read(_readable, _version, GroupInstanceId); NPrivate::Read(_readable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6274,10 +6274,10 @@ void TTxnOffsetCommitRequestData::Write(TKafkaWritable& _writable, TKafkaVersion NPrivate::Write(_collector, _writable, _version, MemberId); NPrivate::Write(_collector, _writable, _version, GroupInstanceId); NPrivate::Write(_collector, _writable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6291,7 +6291,7 @@ i32 TTxnOffsetCommitRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, MemberId); NPrivate::Size(_collector, _version, GroupInstanceId); NPrivate::Size(_collector, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6304,7 +6304,7 @@ i32 TTxnOffsetCommitRequestData::Size(TKafkaVersion _version) const { // const TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::NameMeta::Type TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::NameMeta::Default = {""}; -TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitRequestTopic() +TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitRequestTopic() : Name(NameMeta::Default) {} @@ -6314,7 +6314,7 @@ void TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::Read(TKafkaReada } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6336,10 +6336,10 @@ void TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::Write(TKafkaWrit NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6347,7 +6347,7 @@ i32 TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::Size(TKafkaVersio NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6363,7 +6363,7 @@ const TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommi const TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitRequestPartition::CommittedLeaderEpochMeta::Type TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitRequestPartition::CommittedLeaderEpochMeta::Default = -1; const TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitRequestPartition::CommittedMetadataMeta::Type TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitRequestPartition::CommittedMetadataMeta::Default = {""}; -TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitRequestPartition::TTxnOffsetCommitRequestPartition() +TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitRequestPartition::TTxnOffsetCommitRequestPartition() : PartitionIndex(PartitionIndexMeta::Default) , CommittedOffset(CommittedOffsetMeta::Default) , CommittedLeaderEpoch(CommittedLeaderEpochMeta::Default) @@ -6378,7 +6378,7 @@ void TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommit NPrivate::Read(_readable, _version, CommittedOffset); NPrivate::Read(_readable, _version, CommittedLeaderEpoch); NPrivate::Read(_readable, _version, CommittedMetadata); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6402,10 +6402,10 @@ void TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommit NPrivate::Write(_collector, _writable, _version, CommittedOffset); NPrivate::Write(_collector, _writable, _version, CommittedLeaderEpoch); NPrivate::Write(_collector, _writable, _version, CommittedMetadata); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6415,7 +6415,7 @@ i32 TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitR NPrivate::Size(_collector, _version, CommittedOffset); NPrivate::Size(_collector, _version, CommittedLeaderEpoch); NPrivate::Size(_collector, _version, CommittedMetadata); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6428,7 +6428,7 @@ i32 TTxnOffsetCommitRequestData::TTxnOffsetCommitRequestTopic::TTxnOffsetCommitR // const TTxnOffsetCommitResponseData::ThrottleTimeMsMeta::Type TTxnOffsetCommitResponseData::ThrottleTimeMsMeta::Default = 0; -TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseData() +TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) {} @@ -6438,7 +6438,7 @@ void TTxnOffsetCommitResponseData::Read(TKafkaReadable& _readable, TKafkaVersion } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6460,10 +6460,10 @@ void TTxnOffsetCommitResponseData::Write(TKafkaWritable& _writable, TKafkaVersio NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6471,7 +6471,7 @@ i32 TTxnOffsetCommitResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, Topics); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6484,7 +6484,7 @@ i32 TTxnOffsetCommitResponseData::Size(TKafkaVersion _version) const { // const TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::NameMeta::Type TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::NameMeta::Default = {""}; -TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommitResponseTopic() +TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommitResponseTopic() : Name(NameMeta::Default) {} @@ -6494,7 +6494,7 @@ void TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::Read(TKafkaRea } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6516,10 +6516,10 @@ void TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::Write(TKafkaWr NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6527,7 +6527,7 @@ i32 TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::Size(TKafkaVers NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Partitions); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6541,7 +6541,7 @@ i32 TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::Size(TKafkaVers const TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommitResponsePartition::PartitionIndexMeta::Type TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommitResponsePartition::PartitionIndexMeta::Default = 0; const TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommitResponsePartition::ErrorCodeMeta::Type TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommitResponsePartition::ErrorCodeMeta::Default = 0; -TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommitResponsePartition::TTxnOffsetCommitResponsePartition() +TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommitResponsePartition::TTxnOffsetCommitResponsePartition() : PartitionIndex(PartitionIndexMeta::Default) , ErrorCode(ErrorCodeMeta::Default) {} @@ -6552,7 +6552,7 @@ void TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetComm } NPrivate::Read(_readable, _version, PartitionIndex); NPrivate::Read(_readable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6574,10 +6574,10 @@ void TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetComm NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, PartitionIndex); NPrivate::Write(_collector, _writable, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6585,7 +6585,7 @@ i32 TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommi NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, PartitionIndex); NPrivate::Size(_collector, _version, ErrorCode); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6599,7 +6599,7 @@ i32 TTxnOffsetCommitResponseData::TTxnOffsetCommitResponseTopic::TTxnOffsetCommi const TDescribeConfigsRequestData::IncludeSynonymsMeta::Type TDescribeConfigsRequestData::IncludeSynonymsMeta::Default = false; const TDescribeConfigsRequestData::IncludeDocumentationMeta::Type TDescribeConfigsRequestData::IncludeDocumentationMeta::Default = false; -TDescribeConfigsRequestData::TDescribeConfigsRequestData() +TDescribeConfigsRequestData::TDescribeConfigsRequestData() : IncludeSynonyms(IncludeSynonymsMeta::Default) , IncludeDocumentation(IncludeDocumentationMeta::Default) {} @@ -6611,7 +6611,7 @@ void TDescribeConfigsRequestData::Read(TKafkaReadable& _readable, TKafkaVersion NPrivate::Read(_readable, _version, Resources); NPrivate::Read(_readable, _version, IncludeSynonyms); NPrivate::Read(_readable, _version, IncludeDocumentation); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6634,10 +6634,10 @@ void TDescribeConfigsRequestData::Write(TKafkaWritable& _writable, TKafkaVersion NPrivate::Write(_collector, _writable, _version, Resources); NPrivate::Write(_collector, _writable, _version, IncludeSynonyms); NPrivate::Write(_collector, _writable, _version, IncludeDocumentation); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6646,7 +6646,7 @@ i32 TDescribeConfigsRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Resources); NPrivate::Size(_collector, _version, IncludeSynonyms); NPrivate::Size(_collector, _version, IncludeDocumentation); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6660,7 +6660,7 @@ i32 TDescribeConfigsRequestData::Size(TKafkaVersion _version) const { const TDescribeConfigsRequestData::TDescribeConfigsResource::ResourceTypeMeta::Type TDescribeConfigsRequestData::TDescribeConfigsResource::ResourceTypeMeta::Default = 0; const TDescribeConfigsRequestData::TDescribeConfigsResource::ResourceNameMeta::Type TDescribeConfigsRequestData::TDescribeConfigsResource::ResourceNameMeta::Default = {""}; -TDescribeConfigsRequestData::TDescribeConfigsResource::TDescribeConfigsResource() +TDescribeConfigsRequestData::TDescribeConfigsResource::TDescribeConfigsResource() : ResourceType(ResourceTypeMeta::Default) , ResourceName(ResourceNameMeta::Default) {} @@ -6672,7 +6672,7 @@ void TDescribeConfigsRequestData::TDescribeConfigsResource::Read(TKafkaReadable& NPrivate::Read(_readable, _version, ResourceType); NPrivate::Read(_readable, _version, ResourceName); NPrivate::Read(_readable, _version, ConfigurationKeys); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6695,10 +6695,10 @@ void TDescribeConfigsRequestData::TDescribeConfigsResource::Write(TKafkaWritable NPrivate::Write(_collector, _writable, _version, ResourceType); NPrivate::Write(_collector, _writable, _version, ResourceName); NPrivate::Write(_collector, _writable, _version, ConfigurationKeys); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6707,7 +6707,7 @@ i32 TDescribeConfigsRequestData::TDescribeConfigsResource::Size(TKafkaVersion _v NPrivate::Size(_collector, _version, ResourceType); NPrivate::Size(_collector, _version, ResourceName); NPrivate::Size(_collector, _version, ConfigurationKeys); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6720,7 +6720,7 @@ i32 TDescribeConfigsRequestData::TDescribeConfigsResource::Size(TKafkaVersion _v // const TDescribeConfigsResponseData::ThrottleTimeMsMeta::Type TDescribeConfigsResponseData::ThrottleTimeMsMeta::Default = 0; -TDescribeConfigsResponseData::TDescribeConfigsResponseData() +TDescribeConfigsResponseData::TDescribeConfigsResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) {} @@ -6730,7 +6730,7 @@ void TDescribeConfigsResponseData::Read(TKafkaReadable& _readable, TKafkaVersion } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, Results); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6752,10 +6752,10 @@ void TDescribeConfigsResponseData::Write(TKafkaWritable& _writable, TKafkaVersio NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, Results); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6763,7 +6763,7 @@ i32 TDescribeConfigsResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, Results); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6779,7 +6779,7 @@ const TDescribeConfigsResponseData::TDescribeConfigsResult::ErrorMessageMeta::Ty const TDescribeConfigsResponseData::TDescribeConfigsResult::ResourceTypeMeta::Type TDescribeConfigsResponseData::TDescribeConfigsResult::ResourceTypeMeta::Default = 0; const TDescribeConfigsResponseData::TDescribeConfigsResult::ResourceNameMeta::Type TDescribeConfigsResponseData::TDescribeConfigsResult::ResourceNameMeta::Default = {""}; -TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResult() +TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResult() : ErrorCode(ErrorCodeMeta::Default) , ErrorMessage(ErrorMessageMeta::Default) , ResourceType(ResourceTypeMeta::Default) @@ -6795,7 +6795,7 @@ void TDescribeConfigsResponseData::TDescribeConfigsResult::Read(TKafkaReadable& NPrivate::Read(_readable, _version, ResourceType); NPrivate::Read(_readable, _version, ResourceName); NPrivate::Read(_readable, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6820,10 +6820,10 @@ void TDescribeConfigsResponseData::TDescribeConfigsResult::Write(TKafkaWritable& NPrivate::Write(_collector, _writable, _version, ResourceType); NPrivate::Write(_collector, _writable, _version, ResourceName); NPrivate::Write(_collector, _writable, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6834,7 +6834,7 @@ i32 TDescribeConfigsResponseData::TDescribeConfigsResult::Size(TKafkaVersion _ve NPrivate::Size(_collector, _version, ResourceType); NPrivate::Size(_collector, _version, ResourceName); NPrivate::Size(_collector, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6854,7 +6854,7 @@ const TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsReso const TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::ConfigTypeMeta::Type TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::ConfigTypeMeta::Default = 0; const TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::DocumentationMeta::Type TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::DocumentationMeta::Default = {""}; -TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::TDescribeConfigsResourceResult() +TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::TDescribeConfigsResourceResult() : Name(NameMeta::Default) , Value(ValueMeta::Default) , ReadOnly(ReadOnlyMeta::Default) @@ -6878,7 +6878,7 @@ void TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResou NPrivate::Read(_readable, _version, Synonyms); NPrivate::Read(_readable, _version, ConfigType); NPrivate::Read(_readable, _version, Documentation); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6907,10 +6907,10 @@ void TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResou NPrivate::Write(_collector, _writable, _version, Synonyms); NPrivate::Write(_collector, _writable, _version, ConfigType); NPrivate::Write(_collector, _writable, _version, Documentation); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6925,7 +6925,7 @@ i32 TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResour NPrivate::Size(_collector, _version, Synonyms); NPrivate::Size(_collector, _version, ConfigType); NPrivate::Size(_collector, _version, Documentation); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -6940,7 +6940,7 @@ const TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsReso const TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::TDescribeConfigsSynonym::ValueMeta::Type TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::TDescribeConfigsSynonym::ValueMeta::Default = {""}; const TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::TDescribeConfigsSynonym::SourceMeta::Type TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::TDescribeConfigsSynonym::SourceMeta::Default = 0; -TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::TDescribeConfigsSynonym::TDescribeConfigsSynonym() +TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResourceResult::TDescribeConfigsSynonym::TDescribeConfigsSynonym() : Name(NameMeta::Default) , Value(ValueMeta::Default) , Source(SourceMeta::Default) @@ -6953,7 +6953,7 @@ void TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResou NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Value); NPrivate::Read(_readable, _version, Source); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -6976,10 +6976,10 @@ void TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResou NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Value); NPrivate::Write(_collector, _writable, _version, Source); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -6988,7 +6988,7 @@ i32 TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResour NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Value); NPrivate::Size(_collector, _version, Source); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7001,7 +7001,7 @@ i32 TDescribeConfigsResponseData::TDescribeConfigsResult::TDescribeConfigsResour // const TAlterConfigsRequestData::ValidateOnlyMeta::Type TAlterConfigsRequestData::ValidateOnlyMeta::Default = false; -TAlterConfigsRequestData::TAlterConfigsRequestData() +TAlterConfigsRequestData::TAlterConfigsRequestData() : ValidateOnly(ValidateOnlyMeta::Default) {} @@ -7011,7 +7011,7 @@ void TAlterConfigsRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _ve } NPrivate::Read(_readable, _version, Resources); NPrivate::Read(_readable, _version, ValidateOnly); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7033,10 +7033,10 @@ void TAlterConfigsRequestData::Write(TKafkaWritable& _writable, TKafkaVersion _v NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Resources); NPrivate::Write(_collector, _writable, _version, ValidateOnly); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7044,7 +7044,7 @@ i32 TAlterConfigsRequestData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Resources); NPrivate::Size(_collector, _version, ValidateOnly); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7058,7 +7058,7 @@ i32 TAlterConfigsRequestData::Size(TKafkaVersion _version) const { const TAlterConfigsRequestData::TAlterConfigsResource::ResourceTypeMeta::Type TAlterConfigsRequestData::TAlterConfigsResource::ResourceTypeMeta::Default = 0; const TAlterConfigsRequestData::TAlterConfigsResource::ResourceNameMeta::Type TAlterConfigsRequestData::TAlterConfigsResource::ResourceNameMeta::Default = {""}; -TAlterConfigsRequestData::TAlterConfigsResource::TAlterConfigsResource() +TAlterConfigsRequestData::TAlterConfigsResource::TAlterConfigsResource() : ResourceType(ResourceTypeMeta::Default) , ResourceName(ResourceNameMeta::Default) {} @@ -7070,7 +7070,7 @@ void TAlterConfigsRequestData::TAlterConfigsResource::Read(TKafkaReadable& _read NPrivate::Read(_readable, _version, ResourceType); NPrivate::Read(_readable, _version, ResourceName); NPrivate::Read(_readable, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7093,10 +7093,10 @@ void TAlterConfigsRequestData::TAlterConfigsResource::Write(TKafkaWritable& _wri NPrivate::Write(_collector, _writable, _version, ResourceType); NPrivate::Write(_collector, _writable, _version, ResourceName); NPrivate::Write(_collector, _writable, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7105,7 +7105,7 @@ i32 TAlterConfigsRequestData::TAlterConfigsResource::Size(TKafkaVersion _version NPrivate::Size(_collector, _version, ResourceType); NPrivate::Size(_collector, _version, ResourceName); NPrivate::Size(_collector, _version, Configs); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7119,7 +7119,7 @@ i32 TAlterConfigsRequestData::TAlterConfigsResource::Size(TKafkaVersion _version const TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::NameMeta::Type TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::NameMeta::Default = {""}; const TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::ValueMeta::Type TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::ValueMeta::Default = {""}; -TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::TAlterableConfig() +TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::TAlterableConfig() : Name(NameMeta::Default) , Value(ValueMeta::Default) {} @@ -7130,7 +7130,7 @@ void TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::Read(TKa } NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Value); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7152,10 +7152,10 @@ void TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::Write(TK NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Value); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7163,7 +7163,7 @@ i32 TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::Size(TKaf NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Value); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7176,7 +7176,7 @@ i32 TAlterConfigsRequestData::TAlterConfigsResource::TAlterableConfig::Size(TKaf // const TAlterConfigsResponseData::ThrottleTimeMsMeta::Type TAlterConfigsResponseData::ThrottleTimeMsMeta::Default = 0; -TAlterConfigsResponseData::TAlterConfigsResponseData() +TAlterConfigsResponseData::TAlterConfigsResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) {} @@ -7186,7 +7186,7 @@ void TAlterConfigsResponseData::Read(TKafkaReadable& _readable, TKafkaVersion _v } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, Responses); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7208,10 +7208,10 @@ void TAlterConfigsResponseData::Write(TKafkaWritable& _writable, TKafkaVersion _ NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, Responses); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7219,7 +7219,7 @@ i32 TAlterConfigsResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, Responses); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7235,7 +7235,7 @@ const TAlterConfigsResponseData::TAlterConfigsResourceResponse::ErrorMessageMeta const TAlterConfigsResponseData::TAlterConfigsResourceResponse::ResourceTypeMeta::Type TAlterConfigsResponseData::TAlterConfigsResourceResponse::ResourceTypeMeta::Default = 0; const TAlterConfigsResponseData::TAlterConfigsResourceResponse::ResourceNameMeta::Type TAlterConfigsResponseData::TAlterConfigsResourceResponse::ResourceNameMeta::Default = {""}; -TAlterConfigsResponseData::TAlterConfigsResourceResponse::TAlterConfigsResourceResponse() +TAlterConfigsResponseData::TAlterConfigsResourceResponse::TAlterConfigsResourceResponse() : ErrorCode(ErrorCodeMeta::Default) , ErrorMessage(ErrorMessageMeta::Default) , ResourceType(ResourceTypeMeta::Default) @@ -7250,7 +7250,7 @@ void TAlterConfigsResponseData::TAlterConfigsResourceResponse::Read(TKafkaReadab NPrivate::Read(_readable, _version, ErrorMessage); NPrivate::Read(_readable, _version, ResourceType); NPrivate::Read(_readable, _version, ResourceName); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7274,10 +7274,10 @@ void TAlterConfigsResponseData::TAlterConfigsResourceResponse::Write(TKafkaWrita NPrivate::Write(_collector, _writable, _version, ErrorMessage); NPrivate::Write(_collector, _writable, _version, ResourceType); NPrivate::Write(_collector, _writable, _version, ResourceName); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7287,7 +7287,7 @@ i32 TAlterConfigsResponseData::TAlterConfigsResourceResponse::Size(TKafkaVersion NPrivate::Size(_collector, _version, ErrorMessage); NPrivate::Size(_collector, _version, ResourceType); NPrivate::Size(_collector, _version, ResourceName); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7299,7 +7299,7 @@ i32 TAlterConfigsResponseData::TAlterConfigsResourceResponse::Size(TKafkaVersion // TSaslAuthenticateRequestData // -TSaslAuthenticateRequestData::TSaslAuthenticateRequestData() +TSaslAuthenticateRequestData::TSaslAuthenticateRequestData() {} void TSaslAuthenticateRequestData::Read(TKafkaReadable& _readable, TKafkaVersion _version) { @@ -7307,7 +7307,7 @@ void TSaslAuthenticateRequestData::Read(TKafkaReadable& _readable, TKafkaVersion ythrow yexception() << "Can't read version " << _version << " of TSaslAuthenticateRequestData"; } NPrivate::Read(_readable, _version, AuthBytes); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7328,17 +7328,17 @@ void TSaslAuthenticateRequestData::Write(TKafkaWritable& _writable, TKafkaVersio } NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, AuthBytes); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } i32 TSaslAuthenticateRequestData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, AuthBytes); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7353,7 +7353,7 @@ const TSaslAuthenticateResponseData::ErrorCodeMeta::Type TSaslAuthenticateRespon const TSaslAuthenticateResponseData::ErrorMessageMeta::Type TSaslAuthenticateResponseData::ErrorMessageMeta::Default = {""}; const TSaslAuthenticateResponseData::SessionLifetimeMsMeta::Type TSaslAuthenticateResponseData::SessionLifetimeMsMeta::Default = 0; -TSaslAuthenticateResponseData::TSaslAuthenticateResponseData() +TSaslAuthenticateResponseData::TSaslAuthenticateResponseData() : ErrorCode(ErrorCodeMeta::Default) , ErrorMessage(ErrorMessageMeta::Default) , SessionLifetimeMs(SessionLifetimeMsMeta::Default) @@ -7367,7 +7367,7 @@ void TSaslAuthenticateResponseData::Read(TKafkaReadable& _readable, TKafkaVersio NPrivate::Read(_readable, _version, ErrorMessage); NPrivate::Read(_readable, _version, AuthBytes); NPrivate::Read(_readable, _version, SessionLifetimeMs); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7391,10 +7391,10 @@ void TSaslAuthenticateResponseData::Write(TKafkaWritable& _writable, TKafkaVersi NPrivate::Write(_collector, _writable, _version, ErrorMessage); NPrivate::Write(_collector, _writable, _version, AuthBytes); NPrivate::Write(_collector, _writable, _version, SessionLifetimeMs); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7404,7 +7404,7 @@ i32 TSaslAuthenticateResponseData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, ErrorMessage); NPrivate::Size(_collector, _version, AuthBytes); NPrivate::Size(_collector, _version, SessionLifetimeMs); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7418,7 +7418,7 @@ i32 TSaslAuthenticateResponseData::Size(TKafkaVersion _version) const { const TCreatePartitionsRequestData::TimeoutMsMeta::Type TCreatePartitionsRequestData::TimeoutMsMeta::Default = 0; const TCreatePartitionsRequestData::ValidateOnlyMeta::Type TCreatePartitionsRequestData::ValidateOnlyMeta::Default = false; -TCreatePartitionsRequestData::TCreatePartitionsRequestData() +TCreatePartitionsRequestData::TCreatePartitionsRequestData() : TimeoutMs(TimeoutMsMeta::Default) , ValidateOnly(ValidateOnlyMeta::Default) {} @@ -7430,7 +7430,7 @@ void TCreatePartitionsRequestData::Read(TKafkaReadable& _readable, TKafkaVersion NPrivate::Read(_readable, _version, Topics); NPrivate::Read(_readable, _version, TimeoutMs); NPrivate::Read(_readable, _version, ValidateOnly); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7453,10 +7453,10 @@ void TCreatePartitionsRequestData::Write(TKafkaWritable& _writable, TKafkaVersio NPrivate::Write(_collector, _writable, _version, Topics); NPrivate::Write(_collector, _writable, _version, TimeoutMs); NPrivate::Write(_collector, _writable, _version, ValidateOnly); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7465,7 +7465,7 @@ i32 TCreatePartitionsRequestData::Size(TKafkaVersion _version) const { NPrivate::Size(_collector, _version, Topics); NPrivate::Size(_collector, _version, TimeoutMs); NPrivate::Size(_collector, _version, ValidateOnly); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7479,7 +7479,7 @@ i32 TCreatePartitionsRequestData::Size(TKafkaVersion _version) const { const TCreatePartitionsRequestData::TCreatePartitionsTopic::NameMeta::Type TCreatePartitionsRequestData::TCreatePartitionsTopic::NameMeta::Default = {""}; const TCreatePartitionsRequestData::TCreatePartitionsTopic::CountMeta::Type TCreatePartitionsRequestData::TCreatePartitionsTopic::CountMeta::Default = 0; -TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsTopic() +TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsTopic() : Name(NameMeta::Default) , Count(CountMeta::Default) {} @@ -7491,7 +7491,7 @@ void TCreatePartitionsRequestData::TCreatePartitionsTopic::Read(TKafkaReadable& NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, Count); NPrivate::Read(_readable, _version, Assignments); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7514,10 +7514,10 @@ void TCreatePartitionsRequestData::TCreatePartitionsTopic::Write(TKafkaWritable& NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, Count); NPrivate::Write(_collector, _writable, _version, Assignments); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7526,7 +7526,7 @@ i32 TCreatePartitionsRequestData::TCreatePartitionsTopic::Size(TKafkaVersion _ve NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, Count); NPrivate::Size(_collector, _version, Assignments); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7538,7 +7538,7 @@ i32 TCreatePartitionsRequestData::TCreatePartitionsTopic::Size(TKafkaVersion _ve // TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsAssignment // -TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsAssignment::TCreatePartitionsAssignment() +TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsAssignment::TCreatePartitionsAssignment() {} void TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsAssignment::Read(TKafkaReadable& _readable, TKafkaVersion _version) { @@ -7546,7 +7546,7 @@ void TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsAssi ythrow yexception() << "Can't read version " << _version << " of TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsAssignment"; } NPrivate::Read(_readable, _version, BrokerIds); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7567,17 +7567,17 @@ void TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsAssi } NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, BrokerIds); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } i32 TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsAssignment::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, BrokerIds); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7590,7 +7590,7 @@ i32 TCreatePartitionsRequestData::TCreatePartitionsTopic::TCreatePartitionsAssig // const TCreatePartitionsResponseData::ThrottleTimeMsMeta::Type TCreatePartitionsResponseData::ThrottleTimeMsMeta::Default = 0; -TCreatePartitionsResponseData::TCreatePartitionsResponseData() +TCreatePartitionsResponseData::TCreatePartitionsResponseData() : ThrottleTimeMs(ThrottleTimeMsMeta::Default) {} @@ -7600,7 +7600,7 @@ void TCreatePartitionsResponseData::Read(TKafkaReadable& _readable, TKafkaVersio } NPrivate::Read(_readable, _version, ThrottleTimeMs); NPrivate::Read(_readable, _version, Results); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7622,10 +7622,10 @@ void TCreatePartitionsResponseData::Write(TKafkaWritable& _writable, TKafkaVersi NPrivate::TWriteCollector _collector; NPrivate::Write(_collector, _writable, _version, ThrottleTimeMs); NPrivate::Write(_collector, _writable, _version, Results); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7633,7 +7633,7 @@ i32 TCreatePartitionsResponseData::Size(TKafkaVersion _version) const { NPrivate::TSizeCollector _collector; NPrivate::Size(_collector, _version, ThrottleTimeMs); NPrivate::Size(_collector, _version, Results); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } @@ -7648,7 +7648,7 @@ const TCreatePartitionsResponseData::TCreatePartitionsTopicResult::NameMeta::Typ const TCreatePartitionsResponseData::TCreatePartitionsTopicResult::ErrorCodeMeta::Type TCreatePartitionsResponseData::TCreatePartitionsTopicResult::ErrorCodeMeta::Default = 0; const TCreatePartitionsResponseData::TCreatePartitionsTopicResult::ErrorMessageMeta::Type TCreatePartitionsResponseData::TCreatePartitionsTopicResult::ErrorMessageMeta::Default = std::nullopt; -TCreatePartitionsResponseData::TCreatePartitionsTopicResult::TCreatePartitionsTopicResult() +TCreatePartitionsResponseData::TCreatePartitionsTopicResult::TCreatePartitionsTopicResult() : Name(NameMeta::Default) , ErrorCode(ErrorCodeMeta::Default) , ErrorMessage(ErrorMessageMeta::Default) @@ -7661,7 +7661,7 @@ void TCreatePartitionsResponseData::TCreatePartitionsTopicResult::Read(TKafkaRea NPrivate::Read(_readable, _version, Name); NPrivate::Read(_readable, _version, ErrorCode); NPrivate::Read(_readable, _version, ErrorMessage); - + if (NPrivate::VersionCheck(_version)) { ui32 _numTaggedFields = _readable.readUnsignedVarint(); for (ui32 _i = 0; _i < _numTaggedFields; ++_i) { @@ -7684,10 +7684,10 @@ void TCreatePartitionsResponseData::TCreatePartitionsTopicResult::Write(TKafkaWr NPrivate::Write(_collector, _writable, _version, Name); NPrivate::Write(_collector, _writable, _version, ErrorCode); NPrivate::Write(_collector, _writable, _version, ErrorMessage); - + if (NPrivate::VersionCheck(_version)) { _writable.writeUnsignedVarint(_collector.NumTaggedFields); - + } } @@ -7696,7 +7696,7 @@ i32 TCreatePartitionsResponseData::TCreatePartitionsTopicResult::Size(TKafkaVers NPrivate::Size(_collector, _version, Name); NPrivate::Size(_collector, _version, ErrorCode); NPrivate::Size(_collector, _version, ErrorMessage); - + if (NPrivate::VersionCheck(_version)) { _collector.Size += NPrivate::SizeOfUnsignedVarint(_collector.NumTaggedFields); } diff --git a/ydb/core/kafka_proxy/kafka_messages.h b/ydb/core/kafka_proxy/kafka_messages.h index dfb837f40900..2231e95c3c25 100644 --- a/ydb/core/kafka_proxy/kafka_messages.h +++ b/ydb/core/kafka_proxy/kafka_messages.h @@ -15,30 +15,30 @@ enum EListenerType { }; enum EApiKey { - HEADER = -1, // [] - PRODUCE = 0, // [ZK_BROKER, BROKER] - FETCH = 1, // [ZK_BROKER, BROKER, CONTROLLER] - LIST_OFFSETS = 2, // [ZK_BROKER, BROKER] - METADATA = 3, // [ZK_BROKER, BROKER] - OFFSET_COMMIT = 8, // [ZK_BROKER, BROKER] - OFFSET_FETCH = 9, // [ZK_BROKER, BROKER] - FIND_COORDINATOR = 10, // [ZK_BROKER, BROKER] - JOIN_GROUP = 11, // [ZK_BROKER, BROKER] - HEARTBEAT = 12, // [ZK_BROKER, BROKER] - LEAVE_GROUP = 13, // [ZK_BROKER, BROKER] - SYNC_GROUP = 14, // [ZK_BROKER, BROKER] - SASL_HANDSHAKE = 17, // [ZK_BROKER, BROKER, CONTROLLER] - API_VERSIONS = 18, // [ZK_BROKER, BROKER, CONTROLLER] - CREATE_TOPICS = 19, // [ZK_BROKER, BROKER, CONTROLLER] - INIT_PRODUCER_ID = 22, // [ZK_BROKER, BROKER] - ADD_PARTITIONS_TO_TXN = 24, // [ZK_BROKER, BROKER] - ADD_OFFSETS_TO_TXN = 25, // [ZK_BROKER, BROKER] - END_TXN = 26, // [ZK_BROKER, BROKER] - TXN_OFFSET_COMMIT = 28, // [ZK_BROKER, BROKER] - DESCRIBE_CONFIGS = 32, // [ZK_BROKER, BROKER] - ALTER_CONFIGS = 33, // [ZK_BROKER, BROKER, CONTROLLER] - SASL_AUTHENTICATE = 36, // [ZK_BROKER, BROKER, CONTROLLER] - CREATE_PARTITIONS = 37, // [ZK_BROKER, BROKER, CONTROLLER] + HEADER = -1, // [] + PRODUCE = 0, // [ZK_BROKER, BROKER] + FETCH = 1, // [ZK_BROKER, BROKER, CONTROLLER] + LIST_OFFSETS = 2, // [ZK_BROKER, BROKER] + METADATA = 3, // [ZK_BROKER, BROKER] + OFFSET_COMMIT = 8, // [ZK_BROKER, BROKER] + OFFSET_FETCH = 9, // [ZK_BROKER, BROKER] + FIND_COORDINATOR = 10, // [ZK_BROKER, BROKER] + JOIN_GROUP = 11, // [ZK_BROKER, BROKER] + HEARTBEAT = 12, // [ZK_BROKER, BROKER] + LEAVE_GROUP = 13, // [ZK_BROKER, BROKER] + SYNC_GROUP = 14, // [ZK_BROKER, BROKER] + SASL_HANDSHAKE = 17, // [ZK_BROKER, BROKER, CONTROLLER] + API_VERSIONS = 18, // [ZK_BROKER, BROKER, CONTROLLER] + CREATE_TOPICS = 19, // [ZK_BROKER, BROKER, CONTROLLER] + INIT_PRODUCER_ID = 22, // [ZK_BROKER, BROKER] + ADD_PARTITIONS_TO_TXN = 24, // [ZK_BROKER, BROKER] + ADD_OFFSETS_TO_TXN = 25, // [ZK_BROKER, BROKER] + END_TXN = 26, // [ZK_BROKER, BROKER] + TXN_OFFSET_COMMIT = 28, // [ZK_BROKER, BROKER] + DESCRIBE_CONFIGS = 32, // [ZK_BROKER, BROKER] + ALTER_CONFIGS = 33, // [ZK_BROKER, BROKER, CONTROLLER] + SASL_AUTHENTICATE = 36, // [ZK_BROKER, BROKER, CONTROLLER] + CREATE_PARTITIONS = 37, // [ZK_BROKER, BROKER, CONTROLLER] }; extern const std::unordered_map EApiKeyNames; @@ -49,80 +49,80 @@ extern const std::unordered_map EApiKeyNames; class TRequestHeaderData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 2}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TRequestHeaderData(); ~TRequestHeaderData() = default; - + struct RequestApiKeyMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "requestApiKey"; static constexpr const char* About = "The API key of this request."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; RequestApiKeyMeta::Type RequestApiKey; - + struct RequestApiVersionMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "requestApiVersion"; static constexpr const char* About = "The API version of this request."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; RequestApiVersionMeta::Type RequestApiVersion; - + struct CorrelationIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "correlationId"; static constexpr const char* About = "The correlation ID of this request."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; CorrelationIdMeta::Type CorrelationId; - + struct ClientIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "clientId"; static constexpr const char* About = "The client ID string."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsNever; }; ClientIdMeta::Type ClientId; - + i16 ApiKey() const override { return HEADER; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TRequestHeaderData& other) const = default; }; @@ -130,35 +130,35 @@ class TRequestHeaderData : public TApiMessage { class TResponseHeaderData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 1}; static constexpr TKafkaVersions FlexibleVersions = {1, Max()}; }; - + TResponseHeaderData(); ~TResponseHeaderData() = default; - + struct CorrelationIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "correlationId"; static constexpr const char* About = "The correlation ID of this response."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {1, Max()}; }; CorrelationIdMeta::Type CorrelationId; - + i16 ApiKey() const override { return HEADER; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TResponseHeaderData& other) const = default; }; @@ -166,175 +166,175 @@ class TResponseHeaderData : public TApiMessage { class TProduceRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TProduceRequestData(); ~TProduceRequestData() = default; - + class TTopicProduceData : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TTopicProduceData(); ~TTopicProduceData() = default; - + class TPartitionProduceData : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TPartitionProduceData(); ~TPartitionProduceData() = default; - + struct IndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "index"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; IndexMeta::Type Index; - + struct RecordsMeta { using Type = TKafkaRecords; using TypeDesc = NPrivate::TKafkaRecordsDesc; - + static constexpr const char* Name = "records"; static constexpr const char* About = "The record data to be produced."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; RecordsMeta::Type Records; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TPartitionProduceData& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; NameMeta::Type Name; - + struct PartitionDataMeta { using ItemType = TPartitionProduceData; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitionData"; static constexpr const char* About = "Each partition to produce to."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; PartitionDataMeta::Type PartitionData; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TTopicProduceData& other) const = default; }; - + struct TransactionalIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "transactionalId"; static constexpr const char* About = "The transactional ID, or null if the producer is not transactional."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; TransactionalIdMeta::Type TransactionalId; - + struct AcksMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "acks"; static constexpr const char* About = "The number of acknowledgments the producer requires the leader to have received before considering a request complete. Allowed values: 0 for no acknowledgments, 1 for only the leader and -1 for the full ISR."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; AcksMeta::Type Acks; - + struct TimeoutMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "timeoutMs"; static constexpr const char* About = "The timeout to await a response in milliseconds."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; TimeoutMsMeta::Type TimeoutMs; - + struct TopicDataMeta { using ItemType = TTopicProduceData; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topicData"; static constexpr const char* About = "Each topic to produce to."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; TopicDataMeta::Type TopicData; - + i16 ApiKey() const override { return PRODUCE; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TProduceRequestData& other) const = default; }; @@ -342,269 +342,269 @@ class TProduceRequestData : public TApiMessage { class TProduceResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TProduceResponseData(); ~TProduceResponseData() = default; - + class TTopicProduceResponse : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TTopicProduceResponse(); ~TTopicProduceResponse() = default; - + class TPartitionProduceResponse : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TPartitionProduceResponse(); ~TPartitionProduceResponse() = default; - + class TBatchIndexAndErrorMessage : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {8, 9}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TBatchIndexAndErrorMessage(); ~TBatchIndexAndErrorMessage() = default; - + struct BatchIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "batchIndex"; static constexpr const char* About = "The batch index of the record that cause the batch to be dropped"; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; BatchIndexMeta::Type BatchIndex; - + struct BatchIndexErrorMessageMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "batchIndexErrorMessage"; static constexpr const char* About = "The error message of the record that caused the batch to be dropped"; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; BatchIndexErrorMessageMeta::Type BatchIndexErrorMessage; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TBatchIndexAndErrorMessage& other) const = default; }; - + struct IndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "index"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; IndexMeta::Type Index; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct BaseOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "baseOffset"; static constexpr const char* About = "The base offset."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; BaseOffsetMeta::Type BaseOffset; - + struct LogAppendTimeMsMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "logAppendTimeMs"; static constexpr const char* About = "The timestamp returned by broker after appending the messages. If CreateTime is used for the topic, the timestamp will be -1. If LogAppendTime is used for the topic, the timestamp will be the broker local time when the messages are appended."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {2, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; LogAppendTimeMsMeta::Type LogAppendTimeMs; - + struct LogStartOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "logStartOffset"; static constexpr const char* About = "The log start offset."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; LogStartOffsetMeta::Type LogStartOffset; - + struct RecordErrorsMeta { using ItemType = TBatchIndexAndErrorMessage; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "recordErrors"; static constexpr const char* About = "The batch indices of records that caused the batch to be dropped"; - + static constexpr TKafkaVersions PresentVersions = {8, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; RecordErrorsMeta::Type RecordErrors; - + struct ErrorMessageMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "errorMessage"; static constexpr const char* About = "The global error message summarizing the common root cause of the records that caused the batch to be dropped"; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {8, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ErrorMessageMeta::Type ErrorMessage; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TPartitionProduceResponse& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name"; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; NameMeta::Type Name; - + struct PartitionResponsesMeta { using ItemType = TPartitionProduceResponse; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitionResponses"; static constexpr const char* About = "Each partition that we produced to within the topic."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; PartitionResponsesMeta::Type PartitionResponses; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TTopicProduceResponse& other) const = default; }; - + struct ResponsesMeta { using ItemType = TTopicProduceResponse; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "responses"; static constexpr const char* About = "Each produce response"; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ResponsesMeta::Type Responses; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + i16 ApiKey() const override { return PRODUCE; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TProduceResponseData& other) const = default; }; @@ -612,421 +612,421 @@ class TProduceResponseData : public TApiMessage { class TFetchRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 13}; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; - + TFetchRequestData(); ~TFetchRequestData() = default; - + class TFetchTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 13}; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; - + TFetchTopic(); ~TFetchTopic() = default; - + class TFetchPartition : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 13}; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; - + TFetchPartition(); ~TFetchPartition() = default; - + struct PartitionMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partition"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; PartitionMeta::Type Partition; - + struct CurrentLeaderEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "currentLeaderEpoch"; static constexpr const char* About = "The current leader epoch of the partition."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {9, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; CurrentLeaderEpochMeta::Type CurrentLeaderEpoch; - + struct FetchOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "fetchOffset"; static constexpr const char* About = "The message offset."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; FetchOffsetMeta::Type FetchOffset; - + struct LastFetchedEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "lastFetchedEpoch"; static constexpr const char* About = "The epoch of the last fetched record or -1 if there is none"; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {12, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; LastFetchedEpochMeta::Type LastFetchedEpoch; - + struct LogStartOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "logStartOffset"; static constexpr const char* About = "The earliest available offset of the follower replica. The field is only used when the request is sent by the follower."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; LogStartOffsetMeta::Type LogStartOffset; - + struct PartitionMaxBytesMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionMaxBytes"; static constexpr const char* About = "The maximum bytes to fetch from this partition. See KIP-74 for cases where this limit may not be honored."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; PartitionMaxBytesMeta::Type PartitionMaxBytes; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TFetchPartition& other) const = default; }; - + struct TopicMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "topic"; static constexpr const char* About = "The name of the topic to fetch."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {0, 12}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; TopicMeta::Type Topic; - + struct TopicIdMeta { using Type = TKafkaUuid; using TypeDesc = NPrivate::TKafkaUuidDesc; - + static constexpr const char* Name = "topicId"; static constexpr const char* About = "The unique topic ID"; static const Type Default; // = TKafkaUuid(0, 0); - + static constexpr TKafkaVersions PresentVersions = {13, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; TopicIdMeta::Type TopicId; - + struct PartitionsMeta { using ItemType = TFetchPartition; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "The partitions to fetch."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TFetchTopic& other) const = default; }; - + class TForgottenTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {7, 13}; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; - + TForgottenTopic(); ~TForgottenTopic() = default; - + struct TopicMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "topic"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {0, 12}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; TopicMeta::Type Topic; - + struct TopicIdMeta { using Type = TKafkaUuid; using TypeDesc = NPrivate::TKafkaUuidDesc; - + static constexpr const char* Name = "topicId"; static constexpr const char* About = "The unique topic ID"; static const Type Default; // = TKafkaUuid(0, 0); - + static constexpr TKafkaVersions PresentVersions = {13, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; TopicIdMeta::Type TopicId; - + struct PartitionsMeta { using ItemType = TKafkaInt32; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "The partitions indexes to forget."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TForgottenTopic& other) const = default; }; - + struct ClusterIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "clusterId"; static constexpr const char* About = "The clusterId if known. This is used to validate metadata fetches prior to broker registration."; static constexpr const TKafkaInt32 Tag = 0; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {12, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsAlways; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ClusterIdMeta::Type ClusterId; - + struct ReplicaIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "replicaId"; static constexpr const char* About = "The broker ID of the follower, of -1 if this request is from a consumer."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; ReplicaIdMeta::Type ReplicaId; - + struct MaxWaitMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "maxWaitMs"; static constexpr const char* About = "The maximum time in milliseconds to wait for the response."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; MaxWaitMsMeta::Type MaxWaitMs; - + struct MinBytesMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "minBytes"; static constexpr const char* About = "The minimum bytes to accumulate in the response."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; MinBytesMeta::Type MinBytes; - + struct MaxBytesMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "maxBytes"; static constexpr const char* About = "The maximum bytes to fetch. See KIP-74 for cases where this limit may not be honored."; static const Type Default; // = 0x7fffffff; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; MaxBytesMeta::Type MaxBytes; - + struct IsolationLevelMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "isolationLevel"; static constexpr const char* About = "This setting controls the visibility of transactional records. Using READ_UNCOMMITTED (isolation_level = 0) makes all records visible. With READ_COMMITTED (isolation_level = 1), non-transactional and COMMITTED transactional records are visible. To be more concrete, READ_COMMITTED returns all data from offsets smaller than the current LSO (last stable offset), and enables the inclusion of the list of aborted transactions in the result, which allows consumers to discard ABORTED transactional records"; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {4, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; IsolationLevelMeta::Type IsolationLevel; - + struct SessionIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "sessionId"; static constexpr const char* About = "The fetch session ID."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; SessionIdMeta::Type SessionId; - + struct SessionEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "sessionEpoch"; static constexpr const char* About = "The fetch session epoch, which is used for ordering requests in a session."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; SessionEpochMeta::Type SessionEpoch; - + struct TopicsMeta { using ItemType = TFetchTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "The topics to fetch."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; TopicsMeta::Type Topics; - + struct ForgottenTopicsDataMeta { using ItemType = TForgottenTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "forgottenTopicsData"; static constexpr const char* About = "In an incremental fetch request, the partitions to remove."; - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; ForgottenTopicsDataMeta::Type ForgottenTopicsData; - + struct RackIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "rackId"; static constexpr const char* About = "Rack ID of the consumer making this request"; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {11, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; RackIdMeta::Type RackId; - + i16 ApiKey() const override { return FETCH; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TFetchRequestData& other) const = default; }; @@ -1034,514 +1034,514 @@ class TFetchRequestData : public TApiMessage { class TFetchResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 13}; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; - + TFetchResponseData(); ~TFetchResponseData() = default; - + class TFetchableTopicResponse : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 13}; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; - + TFetchableTopicResponse(); ~TFetchableTopicResponse() = default; - + class TPartitionData : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 13}; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; - + TPartitionData(); ~TPartitionData() = default; - + class TEpochEndOffset : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {12, 13}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TEpochEndOffset(); ~TEpochEndOffset() = default; - + struct EpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "epoch"; static constexpr const char* About = ""; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; EpochMeta::Type Epoch; - + struct EndOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "endOffset"; static constexpr const char* About = ""; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; EndOffsetMeta::Type EndOffset; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TEpochEndOffset& other) const = default; }; - + class TLeaderIdAndEpoch : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {12, 13}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TLeaderIdAndEpoch(); ~TLeaderIdAndEpoch() = default; - + struct LeaderIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "leaderId"; static constexpr const char* About = "The ID of the current leader or -1 if the leader is unknown."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; LeaderIdMeta::Type LeaderId; - + struct LeaderEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "leaderEpoch"; static constexpr const char* About = "The latest known leader epoch"; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; LeaderEpochMeta::Type LeaderEpoch; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TLeaderIdAndEpoch& other) const = default; }; - + class TSnapshotId : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {12, 13}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TSnapshotId(); ~TSnapshotId() = default; - + struct EndOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "endOffset"; static constexpr const char* About = ""; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; EndOffsetMeta::Type EndOffset; - + struct EpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "epoch"; static constexpr const char* About = ""; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; EpochMeta::Type Epoch; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TSnapshotId& other) const = default; }; - + class TAbortedTransaction : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {4, 13}; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; - + TAbortedTransaction(); ~TAbortedTransaction() = default; - + struct ProducerIdMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerId"; static constexpr const char* About = "The producer id associated with the aborted transaction."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; ProducerIdMeta::Type ProducerId; - + struct FirstOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "firstOffset"; static constexpr const char* About = "The first offset in the aborted transaction."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; FirstOffsetMeta::Type FirstOffset; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAbortedTransaction& other) const = default; }; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no fetch error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct HighWatermarkMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "highWatermark"; static constexpr const char* About = "The current high water mark."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; HighWatermarkMeta::Type HighWatermark; - + struct LastStableOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "lastStableOffset"; static constexpr const char* About = "The last stable offset (or LSO) of the partition. This is the last offset such that the state of all transactional records prior to this offset have been decided (ABORTED or COMMITTED)"; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {4, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; LastStableOffsetMeta::Type LastStableOffset; - + struct LogStartOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "logStartOffset"; static constexpr const char* About = "The current log start offset."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; LogStartOffsetMeta::Type LogStartOffset; - + struct DivergingEpochMeta { using Type = TEpochEndOffset; using TypeDesc = NPrivate::TKafkaStructDesc; - + static constexpr const char* Name = "divergingEpoch"; static constexpr const char* About = "In case divergence is detected based on the `LastFetchedEpoch` and `FetchOffset` in the request, this field indicates the largest epoch and its end offset such that subsequent records are known to diverge"; static constexpr const TKafkaInt32 Tag = 0; - + static constexpr TKafkaVersions PresentVersions = {12, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsAlways; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; DivergingEpochMeta::Type DivergingEpoch; - + struct CurrentLeaderMeta { using Type = TLeaderIdAndEpoch; using TypeDesc = NPrivate::TKafkaStructDesc; - + static constexpr const char* Name = "currentLeader"; static constexpr const char* About = ""; static constexpr const TKafkaInt32 Tag = 1; - + static constexpr TKafkaVersions PresentVersions = {12, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsAlways; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; CurrentLeaderMeta::Type CurrentLeader; - + struct SnapshotIdMeta { using Type = TSnapshotId; using TypeDesc = NPrivate::TKafkaStructDesc; - + static constexpr const char* Name = "snapshotId"; static constexpr const char* About = "In the case of fetching an offset less than the LogStartOffset, this is the end offset and epoch that should be used in the FetchSnapshot request."; static constexpr const TKafkaInt32 Tag = 2; - + static constexpr TKafkaVersions PresentVersions = {12, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsAlways; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; SnapshotIdMeta::Type SnapshotId; - + struct AbortedTransactionsMeta { using ItemType = TAbortedTransaction; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "abortedTransactions"; static constexpr const char* About = "The aborted transactions."; - + static constexpr TKafkaVersions PresentVersions = {4, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; AbortedTransactionsMeta::Type AbortedTransactions; - + struct PreferredReadReplicaMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "preferredReadReplica"; static constexpr const char* About = "The preferred read replica for the consumer to use on its next fetch request"; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {11, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; PreferredReadReplicaMeta::Type PreferredReadReplica; - + struct RecordsMeta { using Type = TKafkaRecords; using TypeDesc = NPrivate::TKafkaRecordsDesc; - + static constexpr const char* Name = "records"; static constexpr const char* About = "The record data."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; RecordsMeta::Type Records; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TPartitionData& other) const = default; }; - + struct TopicMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "topic"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {0, 12}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; TopicMeta::Type Topic; - + struct TopicIdMeta { using Type = TKafkaUuid; using TypeDesc = NPrivate::TKafkaUuidDesc; - + static constexpr const char* Name = "topicId"; static constexpr const char* About = "The unique topic ID"; static const Type Default; // = TKafkaUuid(0, 0); - + static constexpr TKafkaVersions PresentVersions = {13, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; TopicIdMeta::Type TopicId; - + struct PartitionsMeta { using ItemType = TPartitionData; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "The topic partitions."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TFetchableTopicResponse& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The top level response error code."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct SessionIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "sessionId"; static constexpr const char* About = "The fetch session ID, or 0 if this is not part of a fetch session."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; SessionIdMeta::Type SessionId; - + struct ResponsesMeta { using ItemType = TFetchableTopicResponse; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "responses"; static constexpr const char* About = "The response topics."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {12, Max()}; }; ResponsesMeta::Type Responses; - + i16 ApiKey() const override { return FETCH; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TFetchResponseData& other) const = default; }; @@ -1549,191 +1549,191 @@ class TFetchResponseData : public TApiMessage { class TListOffsetsRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TListOffsetsRequestData(); ~TListOffsetsRequestData() = default; - + class TListOffsetsTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TListOffsetsTopic(); ~TListOffsetsTopic() = default; - + class TListOffsetsPartition : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TListOffsetsPartition(); ~TListOffsetsPartition() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct CurrentLeaderEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "currentLeaderEpoch"; static constexpr const char* About = "The current leader epoch."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {4, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; CurrentLeaderEpochMeta::Type CurrentLeaderEpoch; - + struct TimestampMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "timestamp"; static constexpr const char* About = "The current timestamp."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; TimestampMeta::Type Timestamp; - + struct MaxNumOffsetsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "maxNumOffsets"; static constexpr const char* About = "The maximum number of offsets to report."; static const Type Default; // = 1; - + static constexpr TKafkaVersions PresentVersions = {0, 0}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; MaxNumOffsetsMeta::Type MaxNumOffsets; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TListOffsetsPartition& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; NameMeta::Type Name; - + struct PartitionsMeta { using ItemType = TListOffsetsPartition; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "Each partition in the request."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TListOffsetsTopic& other) const = default; }; - + struct ReplicaIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "replicaId"; static constexpr const char* About = "The broker ID of the requestor, or -1 if this request is being made by a normal consumer."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ReplicaIdMeta::Type ReplicaId; - + struct IsolationLevelMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "isolationLevel"; static constexpr const char* About = "This setting controls the visibility of transactional records. Using READ_UNCOMMITTED (isolation_level = 0) makes all records visible. With READ_COMMITTED (isolation_level = 1), non-transactional and COMMITTED transactional records are visible. To be more concrete, READ_COMMITTED returns all data from offsets smaller than the current LSO (last stable offset), and enables the inclusion of the list of aborted transactions in the result, which allows consumers to discard ABORTED transactional records"; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {2, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; IsolationLevelMeta::Type IsolationLevel; - + struct TopicsMeta { using ItemType = TListOffsetsTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "Each topic in the request."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; TopicsMeta::Type Topics; - + i16 ApiKey() const override { return LIST_OFFSETS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TListOffsetsRequestData& other) const = default; }; @@ -1741,207 +1741,207 @@ class TListOffsetsRequestData : public TApiMessage { class TListOffsetsResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TListOffsetsResponseData(); ~TListOffsetsResponseData() = default; - + class TListOffsetsTopicResponse : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TListOffsetsTopicResponse(); ~TListOffsetsTopicResponse() = default; - + class TListOffsetsPartitionResponse : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TListOffsetsPartitionResponse(); ~TListOffsetsPartitionResponse() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The partition error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct OldStyleOffsetsMeta { using ItemType = TKafkaInt64; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "oldStyleOffsets"; static constexpr const char* About = "The result offsets."; - + static constexpr TKafkaVersions PresentVersions = {0, 0}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; OldStyleOffsetsMeta::Type OldStyleOffsets; - + struct TimestampMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "timestamp"; static constexpr const char* About = "The timestamp associated with the returned offset."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; TimestampMeta::Type Timestamp; - + struct OffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "offset"; static constexpr const char* About = "The returned offset."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; OffsetMeta::Type Offset; - + struct LeaderEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "leaderEpoch"; static constexpr const char* About = ""; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {4, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; LeaderEpochMeta::Type LeaderEpoch; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TListOffsetsPartitionResponse& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name"; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; NameMeta::Type Name; - + struct PartitionsMeta { using ItemType = TListOffsetsPartitionResponse; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "Each partition in the response."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TListOffsetsTopicResponse& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {2, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct TopicsMeta { using ItemType = TListOffsetsTopicResponse; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "Each topic in the response."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; TopicsMeta::Type Topics; - + i16 ApiKey() const override { return LIST_OFFSETS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TListOffsetsResponseData& other) const = default; }; @@ -1949,128 +1949,128 @@ class TListOffsetsResponseData : public TApiMessage { class TMetadataRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 12}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TMetadataRequestData(); ~TMetadataRequestData() = default; - + class TMetadataRequestTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 12}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TMetadataRequestTopic(); ~TMetadataRequestTopic() = default; - + struct TopicIdMeta { using Type = TKafkaUuid; using TypeDesc = NPrivate::TKafkaUuidDesc; - + static constexpr const char* Name = "topicId"; static constexpr const char* About = "The topic id."; static const Type Default; // = TKafkaUuid(0, 0); - + static constexpr TKafkaVersions PresentVersions = {10, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; TopicIdMeta::Type TopicId; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = {10, Max()}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; NameMeta::Type Name; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TMetadataRequestTopic& other) const = default; }; - + struct TopicsMeta { using ItemType = TMetadataRequestTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "The topics to fetch metadata for."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = {1, Max()}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; TopicsMeta::Type Topics; - + struct AllowAutoTopicCreationMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "allowAutoTopicCreation"; static constexpr const char* About = "If this is true, the broker may auto-create topics that we requested which do not already exist, if it is configured to do so."; static const Type Default; // = true; - + static constexpr TKafkaVersions PresentVersions = {4, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; AllowAutoTopicCreationMeta::Type AllowAutoTopicCreation; - + struct IncludeClusterAuthorizedOperationsMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "includeClusterAuthorizedOperations"; static constexpr const char* About = "Whether to include cluster authorized operations."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {8, 10}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; IncludeClusterAuthorizedOperationsMeta::Type IncludeClusterAuthorizedOperations; - + struct IncludeTopicAuthorizedOperationsMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "includeTopicAuthorizedOperations"; static constexpr const char* About = "Whether to include topic authorized operations."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {8, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; IncludeTopicAuthorizedOperationsMeta::Type IncludeTopicAuthorizedOperations; - + i16 ApiKey() const override { return METADATA; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TMetadataRequestData& other) const = default; }; @@ -2078,422 +2078,422 @@ class TMetadataRequestData : public TApiMessage { class TMetadataResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 12}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TMetadataResponseData(); ~TMetadataResponseData() = default; - + class TMetadataResponseBroker : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 12}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TMetadataResponseBroker(); ~TMetadataResponseBroker() = default; - + struct NodeIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "nodeId"; static constexpr const char* About = "The broker ID."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; NodeIdMeta::Type NodeId; - + struct HostMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "host"; static constexpr const char* About = "The broker hostname."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; HostMeta::Type Host; - + struct PortMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "port"; static constexpr const char* About = "The broker port."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; PortMeta::Type Port; - + struct RackMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "rack"; static constexpr const char* About = "The rack of the broker, or null if it has not been assigned to a rack."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; RackMeta::Type Rack; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TMetadataResponseBroker& other) const = default; }; - + class TMetadataResponseTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 12}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TMetadataResponseTopic(); ~TMetadataResponseTopic() = default; - + class TMetadataResponsePartition : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 12}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; - + TMetadataResponsePartition(); ~TMetadataResponsePartition() = default; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The partition error, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct LeaderIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "leaderId"; static constexpr const char* About = "The ID of the leader broker."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; LeaderIdMeta::Type LeaderId; - + struct LeaderEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "leaderEpoch"; static constexpr const char* About = "The leader epoch of this partition."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; LeaderEpochMeta::Type LeaderEpoch; - + struct ReplicaNodesMeta { using ItemType = TKafkaInt32; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "replicaNodes"; static constexpr const char* About = "The set of all nodes that host this partition."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ReplicaNodesMeta::Type ReplicaNodes; - + struct IsrNodesMeta { using ItemType = TKafkaInt32; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "isrNodes"; static constexpr const char* About = "The set of nodes that are in sync with the leader for this partition."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; IsrNodesMeta::Type IsrNodes; - + struct OfflineReplicasMeta { using ItemType = TKafkaInt32; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "offlineReplicas"; static constexpr const char* About = "The set of offline replicas of this partition."; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; OfflineReplicasMeta::Type OfflineReplicas; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TMetadataResponsePartition& other) const = default; }; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The topic error, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = {12, Max()}; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; NameMeta::Type Name; - + struct TopicIdMeta { using Type = TKafkaUuid; using TypeDesc = NPrivate::TKafkaUuidDesc; - + static constexpr const char* Name = "topicId"; static constexpr const char* About = "The topic id."; static const Type Default; // = TKafkaUuid(0, 0); - + static constexpr TKafkaVersions PresentVersions = {10, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; TopicIdMeta::Type TopicId; - + struct IsInternalMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "isInternal"; static constexpr const char* About = "True if the topic is internal."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; IsInternalMeta::Type IsInternal; - + struct PartitionsMeta { using ItemType = TMetadataResponsePartition; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "Each partition in the topic."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; PartitionsMeta::Type Partitions; - + struct TopicAuthorizedOperationsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "topicAuthorizedOperations"; static constexpr const char* About = "32-bit bitfield to represent authorized operations for this topic."; static const Type Default; // = -2147483648; - + static constexpr TKafkaVersions PresentVersions = {8, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; TopicAuthorizedOperationsMeta::Type TopicAuthorizedOperations; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TMetadataResponseTopic& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct BrokersMeta { using ItemType = TMetadataResponseBroker; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "brokers"; static constexpr const char* About = "Each broker in the response."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; BrokersMeta::Type Brokers; - + struct ClusterIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "clusterId"; static constexpr const char* About = "The cluster ID that responding broker belongs to."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {2, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ClusterIdMeta::Type ClusterId; - + struct ControllerIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "controllerId"; static constexpr const char* About = "The ID of the controller broker."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ControllerIdMeta::Type ControllerId; - + struct TopicsMeta { using ItemType = TMetadataResponseTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "Each topic in the response."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; TopicsMeta::Type Topics; - + struct ClusterAuthorizedOperationsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "clusterAuthorizedOperations"; static constexpr const char* About = "32-bit bitfield to represent authorized operations for this cluster."; static const Type Default; // = -2147483648; - + static constexpr TKafkaVersions PresentVersions = {8, 10}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {9, Max()}; }; ClusterAuthorizedOperationsMeta::Type ClusterAuthorizedOperations; - + i16 ApiKey() const override { return METADATA; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TMetadataResponseData& other) const = default; }; @@ -2501,251 +2501,251 @@ class TMetadataResponseData : public TApiMessage { class TOffsetCommitRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 8}; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; - + TOffsetCommitRequestData(); ~TOffsetCommitRequestData() = default; - + class TOffsetCommitRequestTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 8}; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; - + TOffsetCommitRequestTopic(); ~TOffsetCommitRequestTopic() = default; - + class TOffsetCommitRequestPartition : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 8}; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; - + TOffsetCommitRequestPartition(); ~TOffsetCommitRequestPartition() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct CommittedOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "committedOffset"; static constexpr const char* About = "The message offset to be committed."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; CommittedOffsetMeta::Type CommittedOffset; - + struct CommittedLeaderEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "committedLeaderEpoch"; static constexpr const char* About = "The leader epoch of this partition."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {6, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; CommittedLeaderEpochMeta::Type CommittedLeaderEpoch; - + struct CommitTimestampMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "commitTimestamp"; static constexpr const char* About = "The timestamp of the commit."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {1, 1}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; CommitTimestampMeta::Type CommitTimestamp; - + struct CommittedMetadataMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "committedMetadata"; static constexpr const char* About = "Any associated metadata the client wants to keep."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; CommittedMetadataMeta::Type CommittedMetadata; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetCommitRequestPartition& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; NameMeta::Type Name; - + struct PartitionsMeta { using ItemType = TOffsetCommitRequestPartition; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "Each partition to commit offsets for."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetCommitRequestTopic& other) const = default; }; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The unique group identifier."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; GroupIdMeta::Type GroupId; - + struct GenerationIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "generationId"; static constexpr const char* About = "The generation of the group."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; GenerationIdMeta::Type GenerationId; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The member ID assigned by the group coordinator."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; MemberIdMeta::Type MemberId; - + struct GroupInstanceIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupInstanceId"; static constexpr const char* About = "The unique identifier of the consumer instance provided by end user."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; GroupInstanceIdMeta::Type GroupInstanceId; - + struct RetentionTimeMsMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "retentionTimeMs"; static constexpr const char* About = "The time period in ms to retain the offset."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {2, 4}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; RetentionTimeMsMeta::Type RetentionTimeMs; - + struct TopicsMeta { using ItemType = TOffsetCommitRequestTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "The topics to commit offsets for."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; TopicsMeta::Type Topics; - + i16 ApiKey() const override { return OFFSET_COMMIT; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetCommitRequestData& other) const = default; }; @@ -2753,146 +2753,146 @@ class TOffsetCommitRequestData : public TApiMessage { class TOffsetCommitResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 8}; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; - + TOffsetCommitResponseData(); ~TOffsetCommitResponseData() = default; - + class TOffsetCommitResponseTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 8}; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; - + TOffsetCommitResponseTopic(); ~TOffsetCommitResponseTopic() = default; - + class TOffsetCommitResponsePartition : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 8}; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; - + TOffsetCommitResponsePartition(); ~TOffsetCommitResponsePartition() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetCommitResponsePartition& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; NameMeta::Type Name; - + struct PartitionsMeta { using ItemType = TOffsetCommitResponsePartition; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "The responses for each partition in the topic."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetCommitResponseTopic& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct TopicsMeta { using ItemType = TOffsetCommitResponseTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "The responses for each topic."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {8, Max()}; }; TopicsMeta::Type Topics; - + i16 ApiKey() const override { return OFFSET_COMMIT; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetCommitResponseData& other) const = default; }; @@ -2900,226 +2900,226 @@ class TOffsetCommitResponseData : public TApiMessage { class TOffsetFetchRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 8}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TOffsetFetchRequestData(); ~TOffsetFetchRequestData() = default; - + class TOffsetFetchRequestTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TOffsetFetchRequestTopic(); ~TOffsetFetchRequestTopic() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; NameMeta::Type Name; - + struct PartitionIndexesMeta { using ItemType = TKafkaInt32; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitionIndexes"; static constexpr const char* About = "The partition indexes we would like to fetch offsets for."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; PartitionIndexesMeta::Type PartitionIndexes; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchRequestTopic& other) const = default; }; - + class TOffsetFetchRequestGroup : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {8, 8}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TOffsetFetchRequestGroup(); ~TOffsetFetchRequestGroup() = default; - + class TOffsetFetchRequestTopics : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {8, 8}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TOffsetFetchRequestTopics(); ~TOffsetFetchRequestTopics() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; NameMeta::Type Name; - + struct PartitionIndexesMeta { using ItemType = TKafkaInt32; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitionIndexes"; static constexpr const char* About = "The partition indexes we would like to fetch offsets for."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; PartitionIndexesMeta::Type PartitionIndexes; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchRequestTopics& other) const = default; }; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The group ID."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; GroupIdMeta::Type GroupId; - + struct TopicsMeta { using ItemType = TOffsetFetchRequestTopics; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "Each topic we would like to fetch offsets for, or null to fetch offsets for all topics."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; TopicsMeta::Type Topics; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchRequestGroup& other) const = default; }; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The group to fetch offsets for."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; GroupIdMeta::Type GroupId; - + struct TopicsMeta { using ItemType = TOffsetFetchRequestTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "Each topic we would like to fetch offsets for, or null to fetch offsets for all topics."; - + static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = {2, Max()}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; TopicsMeta::Type Topics; - + struct GroupsMeta { using ItemType = TOffsetFetchRequestGroup; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "groups"; static constexpr const char* About = "Each group we would like to fetch offsets for"; - + static constexpr TKafkaVersions PresentVersions = {8, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; GroupsMeta::Type Groups; - + struct RequireStableMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "requireStable"; static constexpr const char* About = "Whether broker should hold on returning unstable offsets but set a retriable error code for the partitions."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; RequireStableMeta::Type RequireStable; - + i16 ApiKey() const override { return OFFSET_FETCH; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchRequestData& other) const = default; }; @@ -3127,425 +3127,425 @@ class TOffsetFetchRequestData : public TApiMessage { class TOffsetFetchResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 8}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TOffsetFetchResponseData(); ~TOffsetFetchResponseData() = default; - + class TOffsetFetchResponseTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TOffsetFetchResponseTopic(); ~TOffsetFetchResponseTopic() = default; - + class TOffsetFetchResponsePartition : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TOffsetFetchResponsePartition(); ~TOffsetFetchResponsePartition() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct CommittedOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "committedOffset"; static constexpr const char* About = "The committed message offset."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; CommittedOffsetMeta::Type CommittedOffset; - + struct CommittedLeaderEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "committedLeaderEpoch"; static constexpr const char* About = "The leader epoch."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; CommittedLeaderEpochMeta::Type CommittedLeaderEpoch; - + struct MetadataMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "metadata"; static constexpr const char* About = "The partition metadata."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; MetadataMeta::Type Metadata; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchResponsePartition& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; NameMeta::Type Name; - + struct PartitionsMeta { using ItemType = TOffsetFetchResponsePartition; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "The responses per partition"; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchResponseTopic& other) const = default; }; - + class TOffsetFetchResponseGroup : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {8, 8}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TOffsetFetchResponseGroup(); ~TOffsetFetchResponseGroup() = default; - + class TOffsetFetchResponseTopics : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {8, 8}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TOffsetFetchResponseTopics(); ~TOffsetFetchResponseTopics() = default; - + class TOffsetFetchResponsePartitions : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {8, 8}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TOffsetFetchResponsePartitions(); ~TOffsetFetchResponsePartitions() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; PartitionIndexMeta::Type PartitionIndex; - + struct CommittedOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "committedOffset"; static constexpr const char* About = "The committed message offset."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; CommittedOffsetMeta::Type CommittedOffset; - + struct CommittedLeaderEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "committedLeaderEpoch"; static constexpr const char* About = "The leader epoch."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; CommittedLeaderEpochMeta::Type CommittedLeaderEpoch; - + struct MetadataMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "metadata"; static constexpr const char* About = "The partition metadata."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; MetadataMeta::Type Metadata; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The partition-level error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ErrorCodeMeta::Type ErrorCode; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchResponsePartitions& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; NameMeta::Type Name; - + struct PartitionsMeta { using ItemType = TOffsetFetchResponsePartitions; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "The responses per partition"; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchResponseTopics& other) const = default; }; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The group ID."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; GroupIdMeta::Type GroupId; - + struct TopicsMeta { using ItemType = TOffsetFetchResponseTopics; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "The responses per topic."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; TopicsMeta::Type Topics; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The group-level error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ErrorCodeMeta::Type ErrorCode; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchResponseGroup& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct TopicsMeta { using ItemType = TOffsetFetchResponseTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "The responses per topic."; - + static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; TopicsMeta::Type Topics; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The top-level error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {2, 7}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct GroupsMeta { using ItemType = TOffsetFetchResponseGroup; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "groups"; static constexpr const char* About = "The responses per group id."; - + static constexpr TKafkaVersions PresentVersions = {8, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; GroupsMeta::Type Groups; - + i16 ApiKey() const override { return OFFSET_FETCH; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TOffsetFetchResponseData& other) const = default; }; @@ -3553,66 +3553,66 @@ class TOffsetFetchResponseData : public TApiMessage { class TFindCoordinatorRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TFindCoordinatorRequestData(); ~TFindCoordinatorRequestData() = default; - + struct KeyMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "key"; static constexpr const char* About = "The coordinator key."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; KeyMeta::Type Key; - + struct KeyTypeMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "keyType"; static constexpr const char* About = "The coordinator key type. (Group, transaction, etc.)"; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; KeyTypeMeta::Type KeyType; - + struct CoordinatorKeysMeta { using ItemType = TKafkaString; using ItemTypeDesc = NPrivate::TKafkaStringDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "coordinatorKeys"; static constexpr const char* About = "The coordinator keys."; - + static constexpr TKafkaVersions PresentVersions = {4, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; CoordinatorKeysMeta::Type CoordinatorKeys; - + i16 ApiKey() const override { return FIND_COORDINATOR; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TFindCoordinatorRequestData& other) const = default; }; @@ -3620,233 +3620,233 @@ class TFindCoordinatorRequestData : public TApiMessage { class TFindCoordinatorResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TFindCoordinatorResponseData(); ~TFindCoordinatorResponseData() = default; - + class TCoordinator : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {4, 4}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TCoordinator(); ~TCoordinator() = default; - + struct KeyMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "key"; static constexpr const char* About = "The coordinator key."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; KeyMeta::Type Key; - + struct NodeIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "nodeId"; static constexpr const char* About = "The node id."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; NodeIdMeta::Type NodeId; - + struct HostMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "host"; static constexpr const char* About = "The host name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; HostMeta::Type Host; - + struct PortMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "port"; static constexpr const char* About = "The port."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; PortMeta::Type Port; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ErrorCodeMeta::Type ErrorCode; - + struct ErrorMessageMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "errorMessage"; static constexpr const char* About = "The error message, or null if there was no error."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ErrorMessageMeta::Type ErrorMessage; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCoordinator& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct ErrorMessageMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "errorMessage"; static constexpr const char* About = "The error message, or null if there was no error."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {1, 3}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ErrorMessageMeta::Type ErrorMessage; - + struct NodeIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "nodeId"; static constexpr const char* About = "The node id."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; NodeIdMeta::Type NodeId; - + struct HostMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "host"; static constexpr const char* About = "The host name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; HostMeta::Type Host; - + struct PortMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "port"; static constexpr const char* About = "The port."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; PortMeta::Type Port; - + struct CoordinatorsMeta { using ItemType = TCoordinator; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "coordinators"; static constexpr const char* About = "Each coordinator result in the response"; - + static constexpr TKafkaVersions PresentVersions = {4, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; CoordinatorsMeta::Type Coordinators; - + i16 ApiKey() const override { return FIND_COORDINATOR; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TFindCoordinatorResponseData& other) const = default; }; @@ -3854,187 +3854,187 @@ class TFindCoordinatorResponseData : public TApiMessage { class TJoinGroupRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TJoinGroupRequestData(); ~TJoinGroupRequestData() = default; - + class TJoinGroupRequestProtocol : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TJoinGroupRequestProtocol(); ~TJoinGroupRequestProtocol() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The protocol name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; NameMeta::Type Name; - + struct MetadataMeta { using Type = TKafkaBytes; using TypeDesc = NPrivate::TKafkaBytesDesc; - + static constexpr const char* Name = "metadata"; static constexpr const char* About = "The protocol metadata."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; MetadataMeta::Type Metadata; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TJoinGroupRequestProtocol& other) const = default; }; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The group identifier."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; GroupIdMeta::Type GroupId; - + struct SessionTimeoutMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "sessionTimeoutMs"; static constexpr const char* About = "The coordinator considers the consumer dead if it receives no heartbeat after this timeout in milliseconds."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; SessionTimeoutMsMeta::Type SessionTimeoutMs; - + struct RebalanceTimeoutMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "rebalanceTimeoutMs"; static constexpr const char* About = "The maximum time in milliseconds that the coordinator will wait for each member to rejoin when rebalancing the group."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; RebalanceTimeoutMsMeta::Type RebalanceTimeoutMs; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The member id assigned by the group coordinator."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; MemberIdMeta::Type MemberId; - + struct GroupInstanceIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupInstanceId"; static constexpr const char* About = "The unique identifier of the consumer instance provided by end user."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; GroupInstanceIdMeta::Type GroupInstanceId; - + struct ProtocolTypeMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "protocolType"; static constexpr const char* About = "The unique name the for class of protocols implemented by the group we want to join."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ProtocolTypeMeta::Type ProtocolType; - + struct ProtocolsMeta { using ItemType = TJoinGroupRequestProtocol; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "protocols"; static constexpr const char* About = "The list of protocols that the member supports."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ProtocolsMeta::Type Protocols; - + struct ReasonMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "reason"; static constexpr const char* About = "The reason why the member (re-)joins the group."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {8, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ReasonMeta::Type Reason; - + i16 ApiKey() const override { return JOIN_GROUP; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TJoinGroupRequestData& other) const = default; }; @@ -4042,219 +4042,219 @@ class TJoinGroupRequestData : public TApiMessage { class TJoinGroupResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TJoinGroupResponseData(); ~TJoinGroupResponseData() = default; - + class TJoinGroupResponseMember : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 9}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; - + TJoinGroupResponseMember(); ~TJoinGroupResponseMember() = default; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The group member ID."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; MemberIdMeta::Type MemberId; - + struct GroupInstanceIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupInstanceId"; static constexpr const char* About = "The unique identifier of the consumer instance provided by end user."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; GroupInstanceIdMeta::Type GroupInstanceId; - + struct MetadataMeta { using Type = TKafkaBytes; using TypeDesc = NPrivate::TKafkaBytesDesc; - + static constexpr const char* Name = "metadata"; static constexpr const char* About = "The group member metadata."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; MetadataMeta::Type Metadata; - + TString MetaStr; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TJoinGroupResponseMember& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {2, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct GenerationIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "generationId"; static constexpr const char* About = "The generation ID of the group."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; GenerationIdMeta::Type GenerationId; - + struct ProtocolTypeMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "protocolType"; static constexpr const char* About = "The group protocol name."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ProtocolTypeMeta::Type ProtocolType; - + struct ProtocolNameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "protocolName"; static constexpr const char* About = "The group protocol selected by the coordinator."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = {7, Max()}; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; ProtocolNameMeta::Type ProtocolName; - + struct LeaderMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "leader"; static constexpr const char* About = "The leader of the group."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; LeaderMeta::Type Leader; - + struct SkipAssignmentMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "skipAssignment"; static constexpr const char* About = "True if the leader must skip running the assignment."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {9, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; SkipAssignmentMeta::Type SkipAssignment; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The member ID assigned by the group coordinator."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; MemberIdMeta::Type MemberId; - + struct MembersMeta { using ItemType = TJoinGroupResponseMember; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "members"; static constexpr const char* About = ""; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {6, Max()}; }; MembersMeta::Type Members; - + i16 ApiKey() const override { return JOIN_GROUP; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TJoinGroupResponseData& other) const = default; }; @@ -4262,80 +4262,80 @@ class TJoinGroupResponseData : public TApiMessage { class THeartbeatRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + THeartbeatRequestData(); ~THeartbeatRequestData() = default; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The group id."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; GroupIdMeta::Type GroupId; - + struct GenerationIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "generationId"; static constexpr const char* About = "The generation of the group."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; GenerationIdMeta::Type GenerationId; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The member ID."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; MemberIdMeta::Type MemberId; - + struct GroupInstanceIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupInstanceId"; static constexpr const char* About = "The unique identifier of the consumer instance provided by end user."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; GroupInstanceIdMeta::Type GroupInstanceId; - + i16 ApiKey() const override { return HEARTBEAT; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const THeartbeatRequestData& other) const = default; }; @@ -4343,50 +4343,50 @@ class THeartbeatRequestData : public TApiMessage { class THeartbeatResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + THeartbeatResponseData(); ~THeartbeatResponseData() = default; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + i16 ApiKey() const override { return HEARTBEAT; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const THeartbeatResponseData& other) const = default; }; @@ -4394,128 +4394,128 @@ class THeartbeatResponseData : public TApiMessage { class TLeaveGroupRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 5}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TLeaveGroupRequestData(); ~TLeaveGroupRequestData() = default; - + class TMemberIdentity : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {3, 5}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TMemberIdentity(); ~TMemberIdentity() = default; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The member ID to remove from the group."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; MemberIdMeta::Type MemberId; - + struct GroupInstanceIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupInstanceId"; static constexpr const char* About = "The group instance ID to remove from the group."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; GroupInstanceIdMeta::Type GroupInstanceId; - + struct ReasonMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "reason"; static constexpr const char* About = "The reason why the member left the group."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ReasonMeta::Type Reason; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TMemberIdentity& other) const = default; }; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The ID of the group to leave."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; GroupIdMeta::Type GroupId; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The member ID to remove from the group."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {0, 2}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; MemberIdMeta::Type MemberId; - + struct MembersMeta { using ItemType = TMemberIdentity; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "members"; static constexpr const char* About = "List of leaving member identities."; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; MembersMeta::Type Members; - + i16 ApiKey() const override { return LEAVE_GROUP; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TLeaveGroupRequestData& other) const = default; }; @@ -4523,128 +4523,128 @@ class TLeaveGroupRequestData : public TApiMessage { class TLeaveGroupResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 5}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TLeaveGroupResponseData(); ~TLeaveGroupResponseData() = default; - + class TMemberResponse : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {3, 5}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TMemberResponse(); ~TMemberResponse() = default; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The member ID to remove from the group."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; MemberIdMeta::Type MemberId; - + struct GroupInstanceIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupInstanceId"; static constexpr const char* About = "The group instance ID to remove from the group."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; GroupInstanceIdMeta::Type GroupInstanceId; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TMemberResponse& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct MembersMeta { using ItemType = TMemberResponse; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "members"; static constexpr const char* About = "List of leaving member responses."; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; MembersMeta::Type Members; - + i16 ApiKey() const override { return LEAVE_GROUP; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TLeaveGroupResponseData& other) const = default; }; @@ -4652,174 +4652,174 @@ class TLeaveGroupResponseData : public TApiMessage { class TSyncGroupRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 5}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TSyncGroupRequestData(); ~TSyncGroupRequestData() = default; - + class TSyncGroupRequestAssignment : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 5}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TSyncGroupRequestAssignment(); ~TSyncGroupRequestAssignment() = default; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The ID of the member to assign."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; MemberIdMeta::Type MemberId; - + struct AssignmentMeta { using Type = TKafkaBytes; using TypeDesc = NPrivate::TKafkaBytesDesc; - + static constexpr const char* Name = "assignment"; static constexpr const char* About = "The member assignment."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; AssignmentMeta::Type Assignment; - + TString AssignmentStr; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TSyncGroupRequestAssignment& other) const = default; }; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The unique group identifier."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; GroupIdMeta::Type GroupId; - + struct GenerationIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "generationId"; static constexpr const char* About = "The generation of the group."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; GenerationIdMeta::Type GenerationId; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The member ID assigned by the group."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; MemberIdMeta::Type MemberId; - + struct GroupInstanceIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupInstanceId"; static constexpr const char* About = "The unique identifier of the consumer instance provided by end user."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; GroupInstanceIdMeta::Type GroupInstanceId; - + struct ProtocolTypeMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "protocolType"; static constexpr const char* About = "The group protocol type."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ProtocolTypeMeta::Type ProtocolType; - + struct ProtocolNameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "protocolName"; static constexpr const char* About = "The group protocol name."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ProtocolNameMeta::Type ProtocolName; - + struct AssignmentsMeta { using ItemType = TSyncGroupRequestAssignment; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "assignments"; static constexpr const char* About = "Each assignment."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; AssignmentsMeta::Type Assignments; - + i16 ApiKey() const override { return SYNC_GROUP; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TSyncGroupRequestData& other) const = default; }; @@ -4827,96 +4827,96 @@ class TSyncGroupRequestData : public TApiMessage { class TSyncGroupResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 5}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TSyncGroupResponseData(); ~TSyncGroupResponseData() = default; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct ProtocolTypeMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "protocolType"; static constexpr const char* About = "The group protocol type."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ProtocolTypeMeta::Type ProtocolType; - + struct ProtocolNameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "protocolName"; static constexpr const char* About = "The group protocol name."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ProtocolNameMeta::Type ProtocolName; - + struct AssignmentMeta { using Type = TKafkaBytes; using TypeDesc = NPrivate::TKafkaBytesDesc; - + static constexpr const char* Name = "assignment"; static constexpr const char* About = "The member assignment."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; AssignmentMeta::Type Assignment; - + TString AssignmentStr; - + i16 ApiKey() const override { return SYNC_GROUP; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TSyncGroupResponseData& other) const = default; }; @@ -4924,35 +4924,35 @@ class TSyncGroupResponseData : public TApiMessage { class TSaslHandshakeRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 1}; static constexpr TKafkaVersions FlexibleVersions = VersionsNever; }; - + TSaslHandshakeRequestData(); ~TSaslHandshakeRequestData() = default; - + struct MechanismMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "mechanism"; static constexpr const char* About = "The SASL mechanism chosen by the client."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsNever; }; MechanismMeta::Type Mechanism; - + i16 ApiKey() const override { return SASL_HANDSHAKE; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TSaslHandshakeRequestData& other) const = default; }; @@ -4960,51 +4960,51 @@ class TSaslHandshakeRequestData : public TApiMessage { class TSaslHandshakeResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 1}; static constexpr TKafkaVersions FlexibleVersions = VersionsNever; }; - + TSaslHandshakeResponseData(); ~TSaslHandshakeResponseData() = default; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsNever; }; ErrorCodeMeta::Type ErrorCode; - + struct MechanismsMeta { using ItemType = TKafkaString; using ItemTypeDesc = NPrivate::TKafkaStringDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "mechanisms"; static constexpr const char* About = "The mechanisms enabled in the server."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsNever; }; MechanismsMeta::Type Mechanisms; - + i16 ApiKey() const override { return SASL_HANDSHAKE; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TSaslHandshakeResponseData& other) const = default; }; @@ -5012,50 +5012,50 @@ class TSaslHandshakeResponseData : public TApiMessage { class TApiVersionsRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TApiVersionsRequestData(); ~TApiVersionsRequestData() = default; - + struct ClientSoftwareNameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "clientSoftwareName"; static constexpr const char* About = "The name of the client."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ClientSoftwareNameMeta::Type ClientSoftwareName; - + struct ClientSoftwareVersionMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "clientSoftwareVersion"; static constexpr const char* About = "The version of the client."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ClientSoftwareVersionMeta::Type ClientSoftwareVersion; - + i16 ApiKey() const override { return API_VERSIONS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TApiVersionsRequestData& other) const = default; }; @@ -5063,318 +5063,318 @@ class TApiVersionsRequestData : public TApiMessage { class TApiVersionsResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TApiVersionsResponseData(); ~TApiVersionsResponseData() = default; - + class TApiVersion : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TApiVersion(); ~TApiVersion() = default; - + struct ApiKeyMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "apiKey"; static constexpr const char* About = "The API index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ApiKeyMeta::Type ApiKey; - + struct MinVersionMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "minVersion"; static constexpr const char* About = "The minimum supported version, inclusive."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; MinVersionMeta::Type MinVersion; - + struct MaxVersionMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "maxVersion"; static constexpr const char* About = "The maximum supported version, inclusive."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; MaxVersionMeta::Type MaxVersion; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TApiVersion& other) const = default; }; - + class TSupportedFeatureKey : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {3, 3}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TSupportedFeatureKey(); ~TSupportedFeatureKey() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The name of the feature."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; NameMeta::Type Name; - + struct MinVersionMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "minVersion"; static constexpr const char* About = "The minimum supported version for the feature."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; MinVersionMeta::Type MinVersion; - + struct MaxVersionMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "maxVersion"; static constexpr const char* About = "The maximum supported version for the feature."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; MaxVersionMeta::Type MaxVersion; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TSupportedFeatureKey& other) const = default; }; - + class TFinalizedFeatureKey : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {3, 3}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TFinalizedFeatureKey(); ~TFinalizedFeatureKey() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The name of the feature."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; NameMeta::Type Name; - + struct MaxVersionLevelMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "maxVersionLevel"; static constexpr const char* About = "The cluster-wide finalized max version level for the feature."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; MaxVersionLevelMeta::Type MaxVersionLevel; - + struct MinVersionLevelMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "minVersionLevel"; static constexpr const char* About = "The cluster-wide finalized min version level for the feature."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; MinVersionLevelMeta::Type MinVersionLevel; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TFinalizedFeatureKey& other) const = default; }; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The top-level error code."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct ApiKeysMeta { using ItemType = TApiVersion; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "apiKeys"; static constexpr const char* About = "The APIs supported by the broker."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ApiKeysMeta::Type ApiKeys; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct SupportedFeaturesMeta { using ItemType = TSupportedFeatureKey; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "supportedFeatures"; static constexpr const char* About = "Features supported by the broker."; static constexpr const TKafkaInt32 Tag = 0; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsAlways; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; SupportedFeaturesMeta::Type SupportedFeatures; - + struct FinalizedFeaturesEpochMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "finalizedFeaturesEpoch"; static constexpr const char* About = "The monotonically increasing epoch for the finalized features information. Valid values are >= 0. A value of -1 is special and represents unknown epoch."; static constexpr const TKafkaInt32 Tag = 1; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsAlways; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; FinalizedFeaturesEpochMeta::Type FinalizedFeaturesEpoch; - + struct FinalizedFeaturesMeta { using ItemType = TFinalizedFeatureKey; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "finalizedFeatures"; static constexpr const char* About = "List of cluster-wide finalized features. The information is valid only if FinalizedFeaturesEpoch >= 0."; static constexpr const TKafkaInt32 Tag = 2; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsAlways; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; FinalizedFeaturesMeta::Type FinalizedFeatures; - + struct ZkMigrationReadyMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "zkMigrationReady"; static constexpr const char* About = "Set by a KRaft controller if the required configurations for ZK migration are present"; static constexpr const TKafkaInt32 Tag = 3; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsAlways; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ZkMigrationReadyMeta::Type ZkMigrationReady; - + i16 ApiKey() const override { return API_VERSIONS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TApiVersionsResponseData& other) const = default; }; @@ -5382,255 +5382,255 @@ class TApiVersionsResponseData : public TApiMessage { class TCreateTopicsRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; - + TCreateTopicsRequestData(); ~TCreateTopicsRequestData() = default; - + class TCreatableTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; - + TCreatableTopic(); ~TCreatableTopic() = default; - + class TCreatableReplicaAssignment : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; - + TCreatableReplicaAssignment(); ~TCreatableReplicaAssignment() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct BrokerIdsMeta { using ItemType = TKafkaInt32; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "brokerIds"; static constexpr const char* About = "The brokers to place the partition on."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; BrokerIdsMeta::Type BrokerIds; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreatableReplicaAssignment& other) const = default; }; - + class TCreateableTopicConfig : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; - + TCreateableTopicConfig(); ~TCreateableTopicConfig() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The configuration name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; NameMeta::Type Name; - + struct ValueMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "value"; static constexpr const char* About = "The configuration value."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; ValueMeta::Type Value; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreateableTopicConfig& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; NameMeta::Type Name; - + struct NumPartitionsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "numPartitions"; static constexpr const char* About = "The number of partitions to create in the topic, or -1 if we are either specifying a manual partition assignment or using the default partitions."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; NumPartitionsMeta::Type NumPartitions; - + struct ReplicationFactorMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "replicationFactor"; static constexpr const char* About = "The number of replicas to create for each partition in the topic, or -1 if we are either specifying a manual partition assignment or using the default replication factor."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; ReplicationFactorMeta::Type ReplicationFactor; - + struct AssignmentsMeta { using ItemType = TCreatableReplicaAssignment; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "assignments"; static constexpr const char* About = "The manual partition assignment, or the empty array if we are using automatic assignment."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; AssignmentsMeta::Type Assignments; - + struct ConfigsMeta { using ItemType = TCreateableTopicConfig; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "configs"; static constexpr const char* About = "The custom topic configurations to set."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; ConfigsMeta::Type Configs; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreatableTopic& other) const = default; }; - + struct TopicsMeta { using ItemType = TCreatableTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "The topics to create."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; TopicsMeta::Type Topics; - + struct TimeoutMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "timeoutMs"; static constexpr const char* About = "How long to wait in milliseconds before timing out the request."; static const Type Default; // = 60000; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; TimeoutMsMeta::Type TimeoutMs; - + struct ValidateOnlyMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "validateOnly"; static constexpr const char* About = "If true, check that the topics can be created as specified, but don't create anything."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; ValidateOnlyMeta::Type ValidateOnly; - + i16 ApiKey() const override { return CREATE_TOPICS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreateTopicsRequestData& other) const = default; }; @@ -5638,282 +5638,282 @@ class TCreateTopicsRequestData : public TApiMessage { class TCreateTopicsResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; - + TCreateTopicsResponseData(); ~TCreateTopicsResponseData() = default; - + class TCreatableTopicResult : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 7}; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; - + TCreatableTopicResult(); ~TCreatableTopicResult() = default; - + class TCreatableTopicConfigs : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {5, 7}; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; - + TCreatableTopicConfigs(); ~TCreatableTopicConfigs() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The configuration name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; NameMeta::Type Name; - + struct ValueMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "value"; static constexpr const char* About = "The configuration value."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ValueMeta::Type Value; - + struct ReadOnlyMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "readOnly"; static constexpr const char* About = "True if the configuration is read-only."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ReadOnlyMeta::Type ReadOnly; - + struct ConfigSourceMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "configSource"; static constexpr const char* About = "The configuration source."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ConfigSourceMeta::Type ConfigSource; - + struct IsSensitiveMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "isSensitive"; static constexpr const char* About = "True if this configuration is sensitive."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; IsSensitiveMeta::Type IsSensitive; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreatableTopicConfigs& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; NameMeta::Type Name; - + struct TopicIdMeta { using Type = TKafkaUuid; using TypeDesc = NPrivate::TKafkaUuidDesc; - + static constexpr const char* Name = "topicId"; static constexpr const char* About = "The unique topic ID"; static const Type Default; // = TKafkaUuid(0, 0); - + static constexpr TKafkaVersions PresentVersions = {7, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; TopicIdMeta::Type TopicId; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct ErrorMessageMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "errorMessage"; static constexpr const char* About = "The error message, or null if there was no error."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; ErrorMessageMeta::Type ErrorMessage; - + struct TopicConfigErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "topicConfigErrorCode"; static constexpr const char* About = "Optional topic config error returned if configs are not returned in the response."; static constexpr const TKafkaInt32 Tag = 0; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsAlways; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; TopicConfigErrorCodeMeta::Type TopicConfigErrorCode; - + struct NumPartitionsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "numPartitions"; static constexpr const char* About = "Number of partitions of the topic."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; NumPartitionsMeta::Type NumPartitions; - + struct ReplicationFactorMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "replicationFactor"; static constexpr const char* About = "Replication factor of the topic."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ReplicationFactorMeta::Type ReplicationFactor; - + struct ConfigsMeta { using ItemType = TCreatableTopicConfigs; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "configs"; static constexpr const char* About = "Configuration of the topic."; - + static constexpr TKafkaVersions PresentVersions = {5, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ConfigsMeta::Type Configs; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreatableTopicResult& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {2, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct TopicsMeta { using ItemType = TCreatableTopicResult; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "Results for each topic we tried to create."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {5, Max()}; }; TopicsMeta::Type Topics; - + i16 ApiKey() const override { return CREATE_TOPICS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreateTopicsResponseData& other) const = default; }; @@ -5921,80 +5921,80 @@ class TCreateTopicsResponseData : public TApiMessage { class TInitProducerIdRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TInitProducerIdRequestData(); ~TInitProducerIdRequestData() = default; - + struct TransactionalIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "transactionalId"; static constexpr const char* About = "The transactional id, or null if the producer is not transactional."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; TransactionalIdMeta::Type TransactionalId; - + struct TransactionTimeoutMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "transactionTimeoutMs"; static constexpr const char* About = "The time in ms to wait before aborting idle transactions sent by this producer. This is only relevant if a TransactionalId has been defined."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; TransactionTimeoutMsMeta::Type TransactionTimeoutMs; - + struct ProducerIdMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerId"; static constexpr const char* About = "The producer id. This is used to disambiguate requests if a transactional id is reused following its expiration."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ProducerIdMeta::Type ProducerId; - + struct ProducerEpochMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerEpoch"; static constexpr const char* About = "The producer's current epoch. This will be checked against the producer epoch on the broker, and the request will return an error if they do not match."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; ProducerEpochMeta::Type ProducerEpoch; - + i16 ApiKey() const override { return INIT_PRODUCER_ID; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TInitProducerIdRequestData& other) const = default; }; @@ -6002,80 +6002,80 @@ class TInitProducerIdRequestData : public TApiMessage { class TInitProducerIdResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TInitProducerIdResponseData(); ~TInitProducerIdResponseData() = default; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct ProducerIdMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerId"; static constexpr const char* About = "The current producer id."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ProducerIdMeta::Type ProducerId; - + struct ProducerEpochMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerEpoch"; static constexpr const char* About = "The current epoch associated with the producer id."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ProducerEpochMeta::Type ProducerEpoch; - + i16 ApiKey() const override { return INIT_PRODUCER_ID; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TInitProducerIdResponseData& other) const = default; }; @@ -6083,129 +6083,129 @@ class TInitProducerIdResponseData : public TApiMessage { class TAddPartitionsToTxnRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TAddPartitionsToTxnRequestData(); ~TAddPartitionsToTxnRequestData() = default; - + class TAddPartitionsToTxnTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TAddPartitionsToTxnTopic(); ~TAddPartitionsToTxnTopic() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The name of the topic."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; NameMeta::Type Name; - + struct PartitionsMeta { using ItemType = TKafkaInt32; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "The partition indexes to add to the transaction"; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAddPartitionsToTxnTopic& other) const = default; }; - + struct TransactionalIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "transactionalId"; static constexpr const char* About = "The transactional id corresponding to the transaction."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; TransactionalIdMeta::Type TransactionalId; - + struct ProducerIdMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerId"; static constexpr const char* About = "Current producer id in use by the transactional id."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ProducerIdMeta::Type ProducerId; - + struct ProducerEpochMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerEpoch"; static constexpr const char* About = "Current epoch associated with the producer id."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ProducerEpochMeta::Type ProducerEpoch; - + struct TopicsMeta { using ItemType = TAddPartitionsToTxnTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "The partitions to add to the transaction."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; TopicsMeta::Type Topics; - + i16 ApiKey() const override { return ADD_PARTITIONS_TO_TXN; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAddPartitionsToTxnRequestData& other) const = default; }; @@ -6213,146 +6213,146 @@ class TAddPartitionsToTxnRequestData : public TApiMessage { class TAddPartitionsToTxnResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TAddPartitionsToTxnResponseData(); ~TAddPartitionsToTxnResponseData() = default; - + class TAddPartitionsToTxnTopicResult : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TAddPartitionsToTxnTopicResult(); ~TAddPartitionsToTxnTopicResult() = default; - + class TAddPartitionsToTxnPartitionResult : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TAddPartitionsToTxnPartitionResult(); ~TAddPartitionsToTxnPartitionResult() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition indexes."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The response error code."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAddPartitionsToTxnPartitionResult& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; NameMeta::Type Name; - + struct ResultsMeta { using ItemType = TAddPartitionsToTxnPartitionResult; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "results"; static constexpr const char* About = "The results for each partition"; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ResultsMeta::Type Results; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAddPartitionsToTxnTopicResult& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "Duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ResultsMeta { using ItemType = TAddPartitionsToTxnTopicResult; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "results"; static constexpr const char* About = "The results for each topic."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ResultsMeta::Type Results; - + i16 ApiKey() const override { return ADD_PARTITIONS_TO_TXN; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAddPartitionsToTxnResponseData& other) const = default; }; @@ -6360,80 +6360,80 @@ class TAddPartitionsToTxnResponseData : public TApiMessage { class TAddOffsetsToTxnRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TAddOffsetsToTxnRequestData(); ~TAddOffsetsToTxnRequestData() = default; - + struct TransactionalIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "transactionalId"; static constexpr const char* About = "The transactional id corresponding to the transaction."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; TransactionalIdMeta::Type TransactionalId; - + struct ProducerIdMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerId"; static constexpr const char* About = "Current producer id in use by the transactional id."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ProducerIdMeta::Type ProducerId; - + struct ProducerEpochMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerEpoch"; static constexpr const char* About = "Current epoch associated with the producer id."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ProducerEpochMeta::Type ProducerEpoch; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The unique group identifier."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; GroupIdMeta::Type GroupId; - + i16 ApiKey() const override { return ADD_OFFSETS_TO_TXN; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAddOffsetsToTxnRequestData& other) const = default; }; @@ -6441,50 +6441,50 @@ class TAddOffsetsToTxnRequestData : public TApiMessage { class TAddOffsetsToTxnResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TAddOffsetsToTxnResponseData(); ~TAddOffsetsToTxnResponseData() = default; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "Duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The response error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + i16 ApiKey() const override { return ADD_OFFSETS_TO_TXN; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAddOffsetsToTxnResponseData& other) const = default; }; @@ -6492,80 +6492,80 @@ class TAddOffsetsToTxnResponseData : public TApiMessage { class TEndTxnRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TEndTxnRequestData(); ~TEndTxnRequestData() = default; - + struct TransactionalIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "transactionalId"; static constexpr const char* About = "The ID of the transaction to end."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; TransactionalIdMeta::Type TransactionalId; - + struct ProducerIdMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerId"; static constexpr const char* About = "The producer ID."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ProducerIdMeta::Type ProducerId; - + struct ProducerEpochMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerEpoch"; static constexpr const char* About = "The current epoch associated with the producer."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ProducerEpochMeta::Type ProducerEpoch; - + struct CommittedMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "committed"; static constexpr const char* About = "True if the transaction was committed, false if it was aborted."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; CommittedMeta::Type Committed; - + i16 ApiKey() const override { return END_TXN; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TEndTxnRequestData& other) const = default; }; @@ -6573,50 +6573,50 @@ class TEndTxnRequestData : public TApiMessage { class TEndTxnResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TEndTxnResponseData(); ~TEndTxnResponseData() = default; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + i16 ApiKey() const override { return END_TXN; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TEndTxnResponseData& other) const = default; }; @@ -6624,266 +6624,266 @@ class TEndTxnResponseData : public TApiMessage { class TTxnOffsetCommitRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TTxnOffsetCommitRequestData(); ~TTxnOffsetCommitRequestData() = default; - + class TTxnOffsetCommitRequestTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TTxnOffsetCommitRequestTopic(); ~TTxnOffsetCommitRequestTopic() = default; - + class TTxnOffsetCommitRequestPartition : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TTxnOffsetCommitRequestPartition(); ~TTxnOffsetCommitRequestPartition() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The index of the partition within the topic."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct CommittedOffsetMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "committedOffset"; static constexpr const char* About = "The message offset to be committed."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; CommittedOffsetMeta::Type CommittedOffset; - + struct CommittedLeaderEpochMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "committedLeaderEpoch"; static constexpr const char* About = "The leader epoch of the last consumed record."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {2, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; CommittedLeaderEpochMeta::Type CommittedLeaderEpoch; - + struct CommittedMetadataMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "committedMetadata"; static constexpr const char* About = "Any associated metadata the client wants to keep."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; CommittedMetadataMeta::Type CommittedMetadata; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TTxnOffsetCommitRequestPartition& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; NameMeta::Type Name; - + struct PartitionsMeta { using ItemType = TTxnOffsetCommitRequestPartition; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "The partitions inside the topic that we want to committ offsets for."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TTxnOffsetCommitRequestTopic& other) const = default; }; - + struct TransactionalIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "transactionalId"; static constexpr const char* About = "The ID of the transaction."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; TransactionalIdMeta::Type TransactionalId; - + struct GroupIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupId"; static constexpr const char* About = "The ID of the group."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; GroupIdMeta::Type GroupId; - + struct ProducerIdMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerId"; static constexpr const char* About = "The current producer ID in use by the transactional ID."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ProducerIdMeta::Type ProducerId; - + struct ProducerEpochMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "producerEpoch"; static constexpr const char* About = "The current epoch associated with the producer ID."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ProducerEpochMeta::Type ProducerEpoch; - + struct GenerationIdMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "generationId"; static constexpr const char* About = "The generation of the consumer."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; GenerationIdMeta::Type GenerationId; - + struct MemberIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "memberId"; static constexpr const char* About = "The member ID assigned by the group coordinator."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; MemberIdMeta::Type MemberId; - + struct GroupInstanceIdMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "groupInstanceId"; static constexpr const char* About = "The unique identifier of the consumer instance provided by end user."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = VersionsAlways; }; GroupInstanceIdMeta::Type GroupInstanceId; - + struct TopicsMeta { using ItemType = TTxnOffsetCommitRequestTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "Each topic that we want to commit offsets for."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; TopicsMeta::Type Topics; - + i16 ApiKey() const override { return TXN_OFFSET_COMMIT; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TTxnOffsetCommitRequestData& other) const = default; }; @@ -6891,146 +6891,146 @@ class TTxnOffsetCommitRequestData : public TApiMessage { class TTxnOffsetCommitResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TTxnOffsetCommitResponseData(); ~TTxnOffsetCommitResponseData() = default; - + class TTxnOffsetCommitResponseTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TTxnOffsetCommitResponseTopic(); ~TTxnOffsetCommitResponseTopic() = default; - + class TTxnOffsetCommitResponsePartition : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; - + TTxnOffsetCommitResponsePartition(); ~TTxnOffsetCommitResponsePartition() = default; - + struct PartitionIndexMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "partitionIndex"; static constexpr const char* About = "The partition index."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; PartitionIndexMeta::Type PartitionIndex; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TTxnOffsetCommitResponsePartition& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; NameMeta::Type Name; - + struct PartitionsMeta { using ItemType = TTxnOffsetCommitResponsePartition; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "partitions"; static constexpr const char* About = "The responses for each partition in the topic."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; PartitionsMeta::Type Partitions; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TTxnOffsetCommitResponseTopic& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct TopicsMeta { using ItemType = TTxnOffsetCommitResponseTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "The responses for each topic."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {3, Max()}; }; TopicsMeta::Type Topics; - + i16 ApiKey() const override { return TXN_OFFSET_COMMIT; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TTxnOffsetCommitResponseData& other) const = default; }; @@ -7038,129 +7038,129 @@ class TTxnOffsetCommitResponseData : public TApiMessage { class TDescribeConfigsRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TDescribeConfigsRequestData(); ~TDescribeConfigsRequestData() = default; - + class TDescribeConfigsResource : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TDescribeConfigsResource(); ~TDescribeConfigsResource() = default; - + struct ResourceTypeMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "resourceType"; static constexpr const char* About = "The resource type."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ResourceTypeMeta::Type ResourceType; - + struct ResourceNameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "resourceName"; static constexpr const char* About = "The resource name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ResourceNameMeta::Type ResourceName; - + struct ConfigurationKeysMeta { using ItemType = TKafkaString; using ItemTypeDesc = NPrivate::TKafkaStringDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "configurationKeys"; static constexpr const char* About = "The configuration keys to list, or null to list all configuration keys."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ConfigurationKeysMeta::Type ConfigurationKeys; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TDescribeConfigsResource& other) const = default; }; - + struct ResourcesMeta { using ItemType = TDescribeConfigsResource; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "resources"; static constexpr const char* About = "The resources whose configurations we want to describe."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ResourcesMeta::Type Resources; - + struct IncludeSynonymsMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "includeSynonyms"; static constexpr const char* About = "True if we should include all synonyms."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; IncludeSynonymsMeta::Type IncludeSynonyms; - + struct IncludeDocumentationMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "includeDocumentation"; static constexpr const char* About = "True if we should include configuration documentation."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; IncludeDocumentationMeta::Type IncludeDocumentation; - + i16 ApiKey() const override { return DESCRIBE_CONFIGS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TDescribeConfigsRequestData& other) const = default; }; @@ -7168,359 +7168,359 @@ class TDescribeConfigsRequestData : public TApiMessage { class TDescribeConfigsResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TDescribeConfigsResponseData(); ~TDescribeConfigsResponseData() = default; - + class TDescribeConfigsResult : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TDescribeConfigsResult(); ~TDescribeConfigsResult() = default; - + class TDescribeConfigsResourceResult : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 4}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TDescribeConfigsResourceResult(); ~TDescribeConfigsResourceResult() = default; - + class TDescribeConfigsSynonym : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {1, 4}; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; - + TDescribeConfigsSynonym(); ~TDescribeConfigsSynonym() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The synonym name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; NameMeta::Type Name; - + struct ValueMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "value"; static constexpr const char* About = "The synonym value."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ValueMeta::Type Value; - + struct SourceMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "source"; static constexpr const char* About = "The synonym source."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; SourceMeta::Type Source; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TDescribeConfigsSynonym& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The configuration name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; NameMeta::Type Name; - + struct ValueMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "value"; static constexpr const char* About = "The configuration value."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ValueMeta::Type Value; - + struct ReadOnlyMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "readOnly"; static constexpr const char* About = "True if the configuration is read-only."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ReadOnlyMeta::Type ReadOnly; - + struct IsDefaultMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "isDefault"; static constexpr const char* About = "True if the configuration is not set."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = {0, 0}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; IsDefaultMeta::Type IsDefault; - + struct ConfigSourceMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "configSource"; static constexpr const char* About = "The configuration source."; static const Type Default; // = -1; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ConfigSourceMeta::Type ConfigSource; - + struct IsSensitiveMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "isSensitive"; static constexpr const char* About = "True if this configuration is sensitive."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; IsSensitiveMeta::Type IsSensitive; - + struct SynonymsMeta { using ItemType = TDescribeConfigsSynonym; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "synonyms"; static constexpr const char* About = "The synonyms for this configuration key."; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; SynonymsMeta::Type Synonyms; - + struct ConfigTypeMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "configType"; static constexpr const char* About = "The configuration data type. Type can be one of the following values - BOOLEAN, STRING, INT, SHORT, LONG, DOUBLE, LIST, CLASS, PASSWORD"; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ConfigTypeMeta::Type ConfigType; - + struct DocumentationMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "documentation"; static constexpr const char* About = "The configuration documentation."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = {3, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; DocumentationMeta::Type Documentation; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TDescribeConfigsResourceResult& other) const = default; }; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if we were able to successfully describe the configurations."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct ErrorMessageMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "errorMessage"; static constexpr const char* About = "The error message, or null if we were able to successfully describe the configurations."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ErrorMessageMeta::Type ErrorMessage; - + struct ResourceTypeMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "resourceType"; static constexpr const char* About = "The resource type."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ResourceTypeMeta::Type ResourceType; - + struct ResourceNameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "resourceName"; static constexpr const char* About = "The resource name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ResourceNameMeta::Type ResourceName; - + struct ConfigsMeta { using ItemType = TDescribeConfigsResourceResult; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "configs"; static constexpr const char* About = "Each listed configuration."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ConfigsMeta::Type Configs; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TDescribeConfigsResult& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ResultsMeta { using ItemType = TDescribeConfigsResult; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "results"; static constexpr const char* About = "The results for each resource."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {4, Max()}; }; ResultsMeta::Type Results; - + i16 ApiKey() const override { return DESCRIBE_CONFIGS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TDescribeConfigsResponseData& other) const = default; }; @@ -7528,161 +7528,161 @@ class TDescribeConfigsResponseData : public TApiMessage { class TAlterConfigsRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 2}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TAlterConfigsRequestData(); ~TAlterConfigsRequestData() = default; - + class TAlterConfigsResource : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 2}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TAlterConfigsResource(); ~TAlterConfigsResource() = default; - + class TAlterableConfig : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 2}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TAlterableConfig(); ~TAlterableConfig() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The configuration key name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; NameMeta::Type Name; - + struct ValueMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "value"; static constexpr const char* About = "The value to set for the configuration key."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ValueMeta::Type Value; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAlterableConfig& other) const = default; }; - + struct ResourceTypeMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "resourceType"; static constexpr const char* About = "The resource type."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ResourceTypeMeta::Type ResourceType; - + struct ResourceNameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "resourceName"; static constexpr const char* About = "The resource name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ResourceNameMeta::Type ResourceName; - + struct ConfigsMeta { using ItemType = TAlterableConfig; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "configs"; static constexpr const char* About = "The configurations."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ConfigsMeta::Type Configs; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAlterConfigsResource& other) const = default; }; - + struct ResourcesMeta { using ItemType = TAlterConfigsResource; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "resources"; static constexpr const char* About = "The updates for each resource."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ResourcesMeta::Type Resources; - + struct ValidateOnlyMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "validateOnly"; static constexpr const char* About = "True if we should validate the request, but not change the configurations."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ValidateOnlyMeta::Type ValidateOnly; - + i16 ApiKey() const override { return ALTER_CONFIGS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAlterConfigsRequestData& other) const = default; }; @@ -7690,128 +7690,128 @@ class TAlterConfigsRequestData : public TApiMessage { class TAlterConfigsResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 2}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TAlterConfigsResponseData(); ~TAlterConfigsResponseData() = default; - + class TAlterConfigsResourceResponse : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 2}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TAlterConfigsResourceResponse(); ~TAlterConfigsResourceResponse() = default; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The resource error code."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct ErrorMessageMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "errorMessage"; static constexpr const char* About = "The resource error message, or null if there was no error."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ErrorMessageMeta::Type ErrorMessage; - + struct ResourceTypeMeta { using Type = TKafkaInt8; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "resourceType"; static constexpr const char* About = "The resource type."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ResourceTypeMeta::Type ResourceType; - + struct ResourceNameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "resourceName"; static constexpr const char* About = "The resource name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ResourceNameMeta::Type ResourceName; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAlterConfigsResourceResponse& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "Duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ResponsesMeta { using ItemType = TAlterConfigsResourceResponse; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "responses"; static constexpr const char* About = "The responses for each resource."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ResponsesMeta::Type Responses; - + i16 ApiKey() const override { return ALTER_CONFIGS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TAlterConfigsResponseData& other) const = default; }; @@ -7819,34 +7819,34 @@ class TAlterConfigsResponseData : public TApiMessage { class TSaslAuthenticateRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 2}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TSaslAuthenticateRequestData(); ~TSaslAuthenticateRequestData() = default; - + struct AuthBytesMeta { using Type = TKafkaBytes; using TypeDesc = NPrivate::TKafkaBytesDesc; - + static constexpr const char* Name = "authBytes"; static constexpr const char* About = "The SASL authentication bytes from the client, as defined by the SASL mechanism."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; AuthBytesMeta::Type AuthBytes; - + i16 ApiKey() const override { return SASL_AUTHENTICATE; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TSaslAuthenticateRequestData& other) const = default; }; @@ -7854,79 +7854,79 @@ class TSaslAuthenticateRequestData : public TApiMessage { class TSaslAuthenticateResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 2}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TSaslAuthenticateResponseData(); ~TSaslAuthenticateResponseData() = default; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The error code, or 0 if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct ErrorMessageMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "errorMessage"; static constexpr const char* About = "The error message, or null if there was no error."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ErrorMessageMeta::Type ErrorMessage; - + struct AuthBytesMeta { using Type = TKafkaBytes; using TypeDesc = NPrivate::TKafkaBytesDesc; - + static constexpr const char* Name = "authBytes"; static constexpr const char* About = "The SASL authentication bytes from the server, as defined by the SASL mechanism."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; AuthBytesMeta::Type AuthBytes; - + struct SessionLifetimeMsMeta { using Type = TKafkaInt64; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "sessionLifetimeMs"; static constexpr const char* About = "The SASL authentication bytes from the server, as defined by the SASL mechanism."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = {1, Max()}; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; SessionLifetimeMsMeta::Type SessionLifetimeMs; - + i16 ApiKey() const override { return SASL_AUTHENTICATE; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TSaslAuthenticateResponseData& other) const = default; }; @@ -7934,162 +7934,162 @@ class TSaslAuthenticateResponseData : public TApiMessage { class TCreatePartitionsRequestData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TCreatePartitionsRequestData(); ~TCreatePartitionsRequestData() = default; - + class TCreatePartitionsTopic : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TCreatePartitionsTopic(); ~TCreatePartitionsTopic() = default; - + class TCreatePartitionsAssignment : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TCreatePartitionsAssignment(); ~TCreatePartitionsAssignment() = default; - + struct BrokerIdsMeta { using ItemType = TKafkaInt32; using ItemTypeDesc = NPrivate::TKafkaIntDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "brokerIds"; static constexpr const char* About = "The assigned broker IDs."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; BrokerIdsMeta::Type BrokerIds; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreatePartitionsAssignment& other) const = default; }; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; NameMeta::Type Name; - + struct CountMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "count"; static constexpr const char* About = "The new partition count."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; CountMeta::Type Count; - + struct AssignmentsMeta { using ItemType = TCreatePartitionsAssignment; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "assignments"; static constexpr const char* About = "The new partition assignments."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; AssignmentsMeta::Type Assignments; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreatePartitionsTopic& other) const = default; }; - + struct TopicsMeta { using ItemType = TCreatePartitionsTopic; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "topics"; static constexpr const char* About = "Each topic that we want to create new partitions inside."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; TopicsMeta::Type Topics; - + struct TimeoutMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "timeoutMs"; static constexpr const char* About = "The time in ms to wait for the partitions to be created."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; TimeoutMsMeta::Type TimeoutMs; - + struct ValidateOnlyMeta { using Type = TKafkaBool; using TypeDesc = NPrivate::TKafkaBoolDesc; - + static constexpr const char* Name = "validateOnly"; static constexpr const char* About = "If true, then validate the request, but don't actually increase the number of partitions."; static const Type Default; // = false; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ValidateOnlyMeta::Type ValidateOnly; - + i16 ApiKey() const override { return CREATE_PARTITIONS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreatePartitionsRequestData& other) const = default; }; @@ -8097,114 +8097,114 @@ class TCreatePartitionsRequestData : public TApiMessage { class TCreatePartitionsResponseData : public TApiMessage { public: typedef std::shared_ptr TPtr; - + struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TCreatePartitionsResponseData(); ~TCreatePartitionsResponseData() = default; - + class TCreatePartitionsTopicResult : public TMessage { public: struct MessageMeta { static constexpr TKafkaVersions PresentVersions = {0, 3}; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; - + TCreatePartitionsTopicResult(); ~TCreatePartitionsTopicResult() = default; - + struct NameMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "name"; static constexpr const char* About = "The topic name."; static const Type Default; // = {""}; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; NameMeta::Type Name; - + struct ErrorCodeMeta { using Type = TKafkaInt16; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "errorCode"; static constexpr const char* About = "The result error, or zero if there was no error."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ErrorCodeMeta::Type ErrorCode; - + struct ErrorMessageMeta { using Type = TKafkaString; using TypeDesc = NPrivate::TKafkaStringDesc; - + static constexpr const char* Name = "errorMessage"; static constexpr const char* About = "The result message, or null if there was no error."; static const Type Default; // = std::nullopt; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsAlways; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ErrorMessageMeta::Type ErrorMessage; - + i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreatePartitionsTopicResult& other) const = default; }; - + struct ThrottleTimeMsMeta { using Type = TKafkaInt32; using TypeDesc = NPrivate::TKafkaIntDesc; - + static constexpr const char* Name = "throttleTimeMs"; static constexpr const char* About = "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota."; static const Type Default; // = 0; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ThrottleTimeMsMeta::Type ThrottleTimeMs; - + struct ResultsMeta { using ItemType = TCreatePartitionsTopicResult; using ItemTypeDesc = NPrivate::TKafkaStructDesc; using Type = std::vector; using TypeDesc = NPrivate::TKafkaArrayDesc; - + static constexpr const char* Name = "results"; static constexpr const char* About = "The partition creation results for each topic."; - + static constexpr TKafkaVersions PresentVersions = VersionsAlways; static constexpr TKafkaVersions TaggedVersions = VersionsNever; static constexpr TKafkaVersions NullableVersions = VersionsNever; static constexpr TKafkaVersions FlexibleVersions = {2, Max()}; }; ResultsMeta::Type Results; - + i16 ApiKey() const override { return CREATE_PARTITIONS; }; i32 Size(TKafkaVersion version) const override; void Read(TKafkaReadable& readable, TKafkaVersion version) override; void Write(TKafkaWritable& writable, TKafkaVersion version) const override; - + bool operator==(const TCreatePartitionsResponseData& other) const = default; }; -} // namespace NKafka +} // namespace NKafka diff --git a/ydb/core/kafka_proxy/ut/actors_ut.cpp b/ydb/core/kafka_proxy/ut/actors_ut.cpp new file mode 100644 index 000000000000..01808338d74a --- /dev/null +++ b/ydb/core/kafka_proxy/ut/actors_ut.cpp @@ -0,0 +1,343 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace NKikimr; + +auto UnpackDiscoveryData(const TString& data) { + Ydb::Discovery::ListEndpointsResponse leResponse; + Ydb::Discovery::ListEndpointsResult leResult; + auto ok = leResponse.ParseFromString(data); + UNIT_ASSERT(ok); + ok = leResponse.operation().result().UnpackTo(&leResult); + UNIT_ASSERT(ok); + return leResult; +} + +class TFakeDiscoveryCache: public TActorBootstrapped { + std::shared_ptr CachedMessage; + +public: + TFakeDiscoveryCache(const Ydb::Discovery::ListEndpointsResult& leResult, bool triggerError) + { + if (!triggerError) { + Ydb::Discovery::ListEndpointsResponse response; + TString out; + auto deferred = response.mutable_operation(); + deferred->set_ready(true); + deferred->set_status(Ydb::StatusIds::SUCCESS); + + auto data = deferred->mutable_result(); + data->PackFrom(leResult); + + Y_PROTOBUF_SUPPRESS_NODISCARD response.SerializeToString(&out); + + TMap infoEntries; + infoEntries.insert(std::make_pair(SelfId(), TEvStateStorage::TBoardInfoEntry("/Root"))); + CachedMessage.reset(new NDiscovery::TCachedMessageData(out, "b", std::move(infoEntries))); + + } else { + CachedMessage.reset(new NDiscovery::TCachedMessageData("", "", {})); + } + } + + void Bootstrap() { + Become(&TFakeDiscoveryCache::StateWork); + } + + STATEFN(StateWork) { + Handle(ev); + } + void Handle(TAutoPtr& ev) { + Cerr << "Fake discovery cache: handle request\n"; + Send(ev->Sender, new TEvDiscovery::TEvDiscoveryData(CachedMessage), 0, ev->Cookie); + } +}; + +struct TMetarequestTestParams { + NPersQueue::TTestServer Server; + ui64 KafkaPort; + NKikimrConfig::TKafkaProxyConfig KafkaConfig; + TString FullTopicName; +}; + +TMetarequestTestParams SetupServer(const TString shortTopicName) { + TStringBuilder fullTopicName; + fullTopicName << "rt3.dc1--" << shortTopicName; + auto pm = MakeSimpleShared(); + ui16 kafkaPort = pm->GetPort(); + auto serverSettings = NPersQueueTests::PQSettings(0).SetDomainName("Root").SetNodeCount(1); + serverSettings.AppConfig->MutableKafkaProxyConfig()->SetEnableKafkaProxy(true); + + serverSettings.AppConfig->MutableKafkaProxyConfig()->SetListeningPort(kafkaPort); + NPersQueue::TTestServer server(serverSettings, true, {}, NActors::NLog::PRI_INFO, pm); + + server.AnnoyingClient->CreateTopic(fullTopicName, 1); + server.WaitInit(shortTopicName); + + return {std::move(server), kafkaPort, serverSettings.AppConfig->GetKafkaProxyConfig(), fullTopicName}; +} + +namespace NKafka::NTests { + Y_UNIT_TEST_SUITE(DiscoveryIsNotBroken) { + void CheckEndpointsInDiscovery(bool withSsl, bool expectKafkaEndpoints) { + auto pm = MakeSimpleShared(); + ui16 kafkaPort = pm->GetPort(); + auto serverSettings = NPersQueueTests::PQSettings(0).SetDomainName("Root").SetNodeCount(1); + serverSettings.AppConfig->MutableKafkaProxyConfig()->SetEnableKafkaProxy(true); + serverSettings.AppConfig->MutableKafkaProxyConfig()->SetListeningPort(kafkaPort); + if (withSsl) { + serverSettings.AppConfig->MutableKafkaProxyConfig()->SetSslCertificate("12345"); + } + NPersQueue::TTestServer server(serverSettings, true, {}, NActors::NLog::PRI_INFO, pm); + auto port = server.GrpcPort; + Cerr << "Run with port = " << port << ", kafka port = " << kafkaPort << Endl; + auto* runtime = server.GetRuntime(); + auto edge = runtime->AllocateEdgeActor(); + + TActorId discoveryCacheActorID; + if (expectKafkaEndpoints) { + discoveryCacheActorID = runtime->Register(CreateDiscoveryCache(NGRpcService::KafkaEndpointId)); + } else { + discoveryCacheActorID = runtime->Register(CreateDiscoveryCache()); + } + auto discoverer = runtime->Register(CreateDiscoverer(&MakeEndpointsBoardPath, "/Root", edge, discoveryCacheActorID)); + Y_UNUSED(discoverer); + TAutoPtr handle; + auto* ev = runtime->GrabEdgeEvent(handle); + UNIT_ASSERT(ev); + auto discoveryData = UnpackDiscoveryData(ev->CachedMessageData->CachedMessage); + auto discoverySslData = UnpackDiscoveryData(ev->CachedMessageData->CachedMessageSsl); + + auto checkEnpoints = [&] (ui32 port, ui32 sslPort) { + if (port) { + UNIT_ASSERT_VALUES_EQUAL(discoveryData.endpoints_size(), 1); + UNIT_ASSERT_VALUES_EQUAL(discoveryData.endpoints(0).port(), port); + UNIT_ASSERT_VALUES_EQUAL(discoverySslData.endpoints_size(), 0); + } + if (sslPort) { + UNIT_ASSERT_VALUES_EQUAL(discoverySslData.endpoints_size(), 1); + UNIT_ASSERT_VALUES_EQUAL(discoverySslData.endpoints(0).port(), sslPort); + UNIT_ASSERT_VALUES_EQUAL(discoveryData.endpoints_size(), 0); + } + }; + if (expectKafkaEndpoints) { + if (withSsl) { + checkEnpoints(0, kafkaPort); + } else { + checkEnpoints(kafkaPort, 0); + } + } else { + checkEnpoints(port, 0); + } + } + + Y_UNIT_TEST(NoKafkaEndpointInDiscovery) { + CheckEndpointsInDiscovery(false, false); + } + + Y_UNIT_TEST(NoKafkaSslEndpointInDiscovery) { + CheckEndpointsInDiscovery(true, false); + } + + Y_UNIT_TEST(HaveKafkaEndpointInDiscovery) { + CheckEndpointsInDiscovery(false, true); + } + Y_UNIT_TEST(HaveKafkaSslEndpointInDiscovery) { + CheckEndpointsInDiscovery(true, true); + } + } + + Y_UNIT_TEST_SUITE(PublishKafkaEndpoints) { + Y_UNIT_TEST(HaveEndpointInLookup) { + auto pm = MakeSimpleShared(); + ui16 kafkaPort = pm->GetPort(); + auto serverSettings = NPersQueueTests::PQSettings(0).SetDomainName("Root").SetNodeCount(1); + serverSettings.AppConfig->MutableKafkaProxyConfig()->SetEnableKafkaProxy(true); + serverSettings.AppConfig->MutableKafkaProxyConfig()->SetListeningPort(kafkaPort); + NPersQueue::TTestServer server(serverSettings, true, {}, NActors::NLog::PRI_INFO, pm); + + auto* runtime = server.GetRuntime(); + auto edge = runtime->AllocateEdgeActor(); + runtime->Register(CreateBoardLookupActor(MakeEndpointsBoardPath("/Root"), edge, EBoardLookupMode::Second)); + TAutoPtr handle; + auto* ev = runtime->GrabEdgeEvent(handle); + UNIT_ASSERT(ev); + Cerr << "ev for path: " << ev->Path << ", is unknown: " << (ev->Status == TEvStateStorage::TEvBoardInfo::EStatus::Unknown) + << ", is unavalable: " << (ev->Status == TEvStateStorage::TEvBoardInfo::EStatus::NotAvailable) << Endl; + UNIT_ASSERT(ev->Status == TEvStateStorage::TEvBoardInfo::EStatus::Ok); + UNIT_ASSERT_VALUES_EQUAL(ev->InfoEntries.size(), 2); + bool hasKafkaPort = false; + for (const auto& [k, v] : ev->InfoEntries) { + NKikimrStateStorage::TEndpointBoardEntry entry; + UNIT_ASSERT(entry.ParseFromString(v.Payload)); + Cerr << "Got entry, actor: " << k.ToString() << ", entry: " << entry.DebugString() << Endl; + if (entry.GetPort() == kafkaPort) { + UNIT_ASSERT_STRINGS_EQUAL(entry.GetEndpointId(), NGRpcService::KafkaEndpointId); + hasKafkaPort = true; + } + } + UNIT_ASSERT(hasKafkaPort); + } + + void CreateMetarequestActor( + const TActorId& edge, const TVector& topics, auto* runtime, const auto& kafkaConfig, const TActorId& fakeCacheId = {} + ) { + TMetadataRequestData::TPtr metaRequest = std::make_shared(); + for (const auto& topicPath : topics) { + metaRequest->Topics.emplace_back(); + auto& topic = metaRequest->Topics.back(); + topic.Name = topicPath; + } + + auto context = std::make_shared(kafkaConfig); + context->ConnectionId = edge; + context->DatabasePath = "/Root"; + context->UserToken = new NACLib::TUserToken("root@builtin", {}); + + TActorId actorId; + if (fakeCacheId) { + actorId = runtime->Register(new NKafka::TKafkaMetadataActor( + context, 1, TMessagePtr(std::make_shared(), metaRequest), fakeCacheId + )); + } else { + actorId = runtime->Register(new NKafka::TKafkaMetadataActor( + context, 1, TMessagePtr(std::make_shared(), metaRequest), + NKafka::MakeKafkaDiscoveryCacheID() + )); + } + runtime->EnableScheduleForActor(actorId); + } + + void CheckKafkaMetaResponse(TTestActorRuntime* runtime, ui64 kafkaPort, bool error = false, ui64 expectedCount = 1) { + TAutoPtr handle; + auto* ev = runtime->GrabEdgeEvent(handle); + UNIT_ASSERT(ev); + auto response = dynamic_cast(ev->Response.get()); + UNIT_ASSERT_VALUES_EQUAL(response->Topics.size(), expectedCount); + if (!error) { + for (const auto& topic : response->Topics) { + UNIT_ASSERT(topic.ErrorCode == EKafkaErrors::NONE_ERROR); + } + } else { + UNIT_ASSERT(response->Topics[0].ErrorCode == EKafkaErrors::LISTENER_NOT_FOUND); + UNIT_ASSERT(ev->ErrorCode == EKafkaErrors::LISTENER_NOT_FOUND); + return; + } + UNIT_ASSERT_VALUES_EQUAL(response->Brokers.size(), 1); + Cerr << "Broker " << response->Brokers[0].NodeId << " - " << response->Brokers[0].Host << ":" << response->Brokers[0].Port << Endl; + UNIT_ASSERT_VALUES_EQUAL(response->Brokers[0].Port, kafkaPort); + } + + Y_UNIT_TEST(MetadataActorGetsEndpoint) { + auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); + + auto* runtime = server.GetRuntime(); + auto edge = runtime->AllocateEdgeActor(); + + CreateMetarequestActor(edge, {NKikimr::JoinPath({"/Root/PQ/", topicName})}, runtime, + config); + + CheckKafkaMetaResponse(runtime, kafkaPort); + } + + Y_UNIT_TEST(DiscoveryResponsesWithNoNode) { + auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); + + auto* runtime = server.GetRuntime(); + auto edge = runtime->AllocateEdgeActor(); + + Ydb::Discovery::ListEndpointsResult leResult; + auto* ep = leResult.add_endpoints(); + ep->set_address("wrong.host"); + ep->set_port(1); + ep->set_node_id(9999); + ep = leResult.add_endpoints(); + ep->set_address("wrong.host2"); + ep->set_port(2); + ep->set_node_id(9998); + auto fakeCache = runtime->Register(new TFakeDiscoveryCache(leResult, false)); + runtime->EnableScheduleForActor(fakeCache); + CreateMetarequestActor(edge, {NKikimr::JoinPath({"/Root/PQ/", topicName})}, runtime, + config, fakeCache); + + CheckKafkaMetaResponse(runtime, kafkaPort); + } + + Y_UNIT_TEST(DiscoveryResponsesWithError) { + auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); + + auto* runtime = server.GetRuntime(); + auto edge = runtime->AllocateEdgeActor(); + + Ydb::Discovery::ListEndpointsResult leResult; + auto fakeCache = runtime->Register(new TFakeDiscoveryCache(leResult, true)); + runtime->EnableScheduleForActor(fakeCache); + CreateMetarequestActor(edge, {NKikimr::JoinPath({"/Root/PQ/", topicName})}, runtime, + config, fakeCache); + + CheckKafkaMetaResponse(runtime, kafkaPort, true); + } + + Y_UNIT_TEST(DiscoveryResponsesWithOtherPort) { + auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); + + auto* runtime = server.GetRuntime(); + auto edge = runtime->AllocateEdgeActor(); + + Ydb::Discovery::ListEndpointsResult leResult; + auto* ep = leResult.add_endpoints(); + ep->set_address("localhost"); + ep->set_port(12345); + ep->set_node_id(runtime->GetNodeId(0)); + auto fakeCache = runtime->Register(new TFakeDiscoveryCache(leResult, false)); + runtime->EnableScheduleForActor(fakeCache); + CreateMetarequestActor(edge, {NKikimr::JoinPath({"/Root/PQ/", topicName})}, runtime, + config, fakeCache); + + CheckKafkaMetaResponse(runtime, 12345); + } + + + Y_UNIT_TEST(MetadataActorDoubleTopic) { + auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); + + auto* runtime = server.GetRuntime(); + auto edge = runtime->AllocateEdgeActor(); + + auto path = NKikimr::JoinPath({"/Root/PQ/", topicName}); + CreateMetarequestActor(edge, {path, path}, runtime, config); + + CheckKafkaMetaResponse(runtime, kafkaPort, false, 2); + } + } + + Y_UNIT_TEST_SUITE(RequestUtilityActors) { + Y_UNIT_TEST(DescribeConfigs) { + auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); + + auto* runtime = server.GetRuntime(); + auto edge = runtime->AllocateEdgeActor(); + + auto path = NKikimr::JoinPath({"/Root/PQ/", topicName}); + auto actor = new TKafkaDescribeTopicActor(edge, nullptr, path, "/Root"); + auto actorId = runtime->Register(actor); + runtime->EnableScheduleForActor(actorId); + auto ev = runtime->GrabEdgeEvent(); + UNIT_ASSERT(ev); + Cerr << "Response: " << ev->Response.DebugString() << Endl; + UNIT_ASSERT(ev->Status == EKafkaErrors::NONE_ERROR); + UNIT_ASSERT_VALUES_EQUAL(ev->Response.partitioning_settings().min_active_partitions(), 1); + } + } +} diff --git a/ydb/core/kafka_proxy/ut/kafka_test_client.cpp b/ydb/core/kafka_proxy/ut/kafka_test_client.cpp index 1307d85e278a..c13409d4f95b 100644 --- a/ydb/core/kafka_proxy/ut/kafka_test_client.cpp +++ b/ydb/core/kafka_proxy/ut/kafka_test_client.cpp @@ -509,6 +509,22 @@ TMessagePtr TKafkaTestClient::AlterConfigs(std::vecto return WriteAndRead(header, request); } +TMessagePtr TKafkaTestClient::DescribeConfigs(std::vector topics) { + Cerr << ">>>>> TDescribeConfigsRequestData\n"; + + TRequestHeaderData header = Header(NKafka::EApiKey::DESCRIBE_CONFIGS, 2); + TDescribeConfigsRequestData request; + + for (auto& topic : topics) { + NKafka::TDescribeConfigsRequestData::TDescribeConfigsResource resource; + resource.ResourceType = TOPIC_RESOURCE_TYPE; + resource.ResourceName = topic; + request.Resources.push_back(resource); + } + + return WriteAndRead(header, request); +} + void TKafkaTestClient::UnknownApiKey() { Cerr << ">>>>> Unknown apiKey\n"; diff --git a/ydb/core/kafka_proxy/ut/kafka_test_client.h b/ydb/core/kafka_proxy/ut/kafka_test_client.h index 8234898e4f13..531c86b4b968 100644 --- a/ydb/core/kafka_proxy/ut/kafka_test_client.h +++ b/ydb/core/kafka_proxy/ut/kafka_test_client.h @@ -40,7 +40,7 @@ struct TReadInfo { class TKafkaTestClient { public: TKafkaTestClient(ui16 port, const TString clientName = "TestClient"); - + template T> void WriteToSocket(TRequestHeaderData& header, T& request) { Write(So, &header, &request); @@ -50,37 +50,37 @@ class TKafkaTestClient { TMessagePtr ReadResponse(TRequestHeaderData& header) { return Read(Si, &header); } - + TMessagePtr ApiVersions(); - + TMessagePtr Metadata(const TVector& topics = {}); - + TMessagePtr SaslHandshake(const TString& mechanism = "PLAIN"); - + TMessagePtr SaslAuthenticate(const TString& user, const TString& password); - + TMessagePtr InitProducerId(const TString& transactionalId = ""); - + TMessagePtr OffsetCommit(TString groupId, std::unordered_map>> topicsToPartions); - + TMessagePtr Produce(const TString& topicName, ui32 partition, const TKafkaRecordBatch& batch); - + TMessagePtr Produce(const TString& topicName, const std::vector> msgs); - + TMessagePtr ListOffsets(std::vector>& partitions, const TString& topic); - + TMessagePtr JoinGroup(std::vector& topics, TString& groupId, TString protocolName, i32 heartbeatTimeout = 1000000); - + TMessagePtr SyncGroup(TString& memberId, ui64 generationId, TString& groupId, std::vector assignments, TString& protocolName); - + TReadInfo JoinAndSyncGroup(std::vector& topics, TString& groupId, TString& protocolName, i32 heartbeatTimeout = 1000000, ui32 totalPartitionsCount = 0); - + TMessagePtr Heartbeat(TString& memberId, ui64 generationId, TString& groupId); void WaitRebalance(TString& memberId, ui64 generationId, TString& groupId); - + TReadInfo JoinAndSyncGroupAndWaitPartitions(std::vector& topics, TString& groupId, ui32 expectedPartitionsCount, TString& protocolName, ui32 totalPartitionsCount = 0, ui32 hartbeatTimeout = 1000000); - + TMessagePtr LeaveGroup(TString& memberId, TString& groupId); TConsumerProtocolAssignment GetAssignments(NKafka::TSyncGroupResponseData::AssignmentMeta::Type metadata); @@ -88,25 +88,26 @@ class TKafkaTestClient { std::vector MakeRangeAssignment( TMessagePtr& joinResponse, int totalPartitionsCount); - + TMessagePtr OffsetFetch(TString groupId, std::map> topicsToPartions); - + TMessagePtr OffsetFetch(TOffsetFetchRequestData request); - + TMessagePtr Fetch(const std::vector>>& topics, i64 offset = 0); - + TMessagePtr CreateTopics(std::vector topicsToCreate, bool validateOnly = false); - + TMessagePtr CreatePartitions(std::vector topicsToCreate, bool validateOnly = false); - + TMessagePtr AlterConfigs(std::vector topicsToModify, bool validateOnly = false); - + TMessagePtr DescribeConfigs(std::vector topics); + void UnknownApiKey(); - + void AuthenticateToKafka(); - + TRequestHeaderData Header(NKafka::EApiKey apiKey, TKafkaVersion version); - + protected: ui32 NextCorrelation(); template T> @@ -118,13 +119,13 @@ class TKafkaTestClient { void Print(const TBuffer& buffer); char Hex0(const unsigned char c); void FillTopicsFromJoinGroupMetadata(TKafkaBytes& metadata, THashSet& topics); - + private: TNetworkAddress Addr; TSocket Socket; TSocketOutput So; TSocketInput Si; - + ui32 Correlation; TString ClientName; }; \ No newline at end of file diff --git a/ydb/core/kafka_proxy/ut/port_discovery_ut.cpp b/ydb/core/kafka_proxy/ut/port_discovery_ut.cpp deleted file mode 100644 index 99f22f3addb3..000000000000 --- a/ydb/core/kafka_proxy/ut/port_discovery_ut.cpp +++ /dev/null @@ -1,322 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace NKikimr; - -auto UnpackDiscoveryData(const TString& data) { - Ydb::Discovery::ListEndpointsResponse leResponse; - Ydb::Discovery::ListEndpointsResult leResult; - auto ok = leResponse.ParseFromString(data); - UNIT_ASSERT(ok); - ok = leResponse.operation().result().UnpackTo(&leResult); - UNIT_ASSERT(ok); - return leResult; -} - -class TFakeDiscoveryCache: public TActorBootstrapped { - std::shared_ptr CachedMessage; - -public: - TFakeDiscoveryCache(const Ydb::Discovery::ListEndpointsResult& leResult, bool triggerError) - { - if (!triggerError) { - Ydb::Discovery::ListEndpointsResponse response; - TString out; - auto deferred = response.mutable_operation(); - deferred->set_ready(true); - deferred->set_status(Ydb::StatusIds::SUCCESS); - - auto data = deferred->mutable_result(); - data->PackFrom(leResult); - - Y_PROTOBUF_SUPPRESS_NODISCARD response.SerializeToString(&out); - - TMap infoEntries; - infoEntries.insert(std::make_pair(SelfId(), TEvStateStorage::TBoardInfoEntry("/Root"))); - CachedMessage.reset(new NDiscovery::TCachedMessageData(out, "b", std::move(infoEntries))); - - } else { - CachedMessage.reset(new NDiscovery::TCachedMessageData("", "", {})); - } - } - - void Bootstrap() { - Become(&TFakeDiscoveryCache::StateWork); - } - - STATEFN(StateWork) { - Handle(ev); - } - void Handle(TAutoPtr& ev) { - Cerr << "Fake discovery cache: handle request\n"; - Send(ev->Sender, new TEvDiscovery::TEvDiscoveryData(CachedMessage), 0, ev->Cookie); - } -}; - -namespace NKafka::NTests { - Y_UNIT_TEST_SUITE(DiscoveryIsNotBroken) { - void CheckEndpointsInDiscovery(bool withSsl, bool expectKafkaEndpoints) { - auto pm = MakeSimpleShared(); - ui16 kafkaPort = pm->GetPort(); - auto serverSettings = NPersQueueTests::PQSettings(0).SetDomainName("Root").SetNodeCount(1); - serverSettings.AppConfig->MutableKafkaProxyConfig()->SetEnableKafkaProxy(true); - serverSettings.AppConfig->MutableKafkaProxyConfig()->SetListeningPort(kafkaPort); - if (withSsl) { - serverSettings.AppConfig->MutableKafkaProxyConfig()->SetSslCertificate("12345"); - } - NPersQueue::TTestServer server(serverSettings, true, {}, NActors::NLog::PRI_INFO, pm); - auto port = server.GrpcPort; - Cerr << "Run with port = " << port << ", kafka port = " << kafkaPort << Endl; - auto* runtime = server.GetRuntime(); - auto edge = runtime->AllocateEdgeActor(); - - TActorId discoveryCacheActorID; - if (expectKafkaEndpoints) { - discoveryCacheActorID = runtime->Register(CreateDiscoveryCache(NGRpcService::KafkaEndpointId)); - } else { - discoveryCacheActorID = runtime->Register(CreateDiscoveryCache()); - } - auto discoverer = runtime->Register(CreateDiscoverer(&MakeEndpointsBoardPath, "/Root", edge, discoveryCacheActorID)); - Y_UNUSED(discoverer); - TAutoPtr handle; - auto* ev = runtime->GrabEdgeEvent(handle); - UNIT_ASSERT(ev); - auto discoveryData = UnpackDiscoveryData(ev->CachedMessageData->CachedMessage); - auto discoverySslData = UnpackDiscoveryData(ev->CachedMessageData->CachedMessageSsl); - - auto checkEnpoints = [&] (ui32 port, ui32 sslPort) { - if (port) { - UNIT_ASSERT_VALUES_EQUAL(discoveryData.endpoints_size(), 1); - UNIT_ASSERT_VALUES_EQUAL(discoveryData.endpoints(0).port(), port); - UNIT_ASSERT_VALUES_EQUAL(discoverySslData.endpoints_size(), 0); - } - if (sslPort) { - UNIT_ASSERT_VALUES_EQUAL(discoverySslData.endpoints_size(), 1); - UNIT_ASSERT_VALUES_EQUAL(discoverySslData.endpoints(0).port(), sslPort); - UNIT_ASSERT_VALUES_EQUAL(discoveryData.endpoints_size(), 0); - } - }; - if (expectKafkaEndpoints) { - if (withSsl) { - checkEnpoints(0, kafkaPort); - } else { - checkEnpoints(kafkaPort, 0); - } - } else { - checkEnpoints(port, 0); - } - } - - Y_UNIT_TEST(NoKafkaEndpointInDiscovery) { - CheckEndpointsInDiscovery(false, false); - } - - Y_UNIT_TEST(NoKafkaSslEndpointInDiscovery) { - CheckEndpointsInDiscovery(true, false); - } - - Y_UNIT_TEST(HaveKafkaEndpointInDiscovery) { - CheckEndpointsInDiscovery(false, true); - } - Y_UNIT_TEST(HaveKafkaSslEndpointInDiscovery) { - CheckEndpointsInDiscovery(true, true); - } - } - - Y_UNIT_TEST_SUITE(PublishKafkaEndpoints) { - Y_UNIT_TEST(HaveEndpointInLookup) { - auto pm = MakeSimpleShared(); - ui16 kafkaPort = pm->GetPort(); - auto serverSettings = NPersQueueTests::PQSettings(0).SetDomainName("Root").SetNodeCount(1); - serverSettings.AppConfig->MutableKafkaProxyConfig()->SetEnableKafkaProxy(true); - serverSettings.AppConfig->MutableKafkaProxyConfig()->SetListeningPort(kafkaPort); - NPersQueue::TTestServer server(serverSettings, true, {}, NActors::NLog::PRI_INFO, pm); - - auto* runtime = server.GetRuntime(); - auto edge = runtime->AllocateEdgeActor(); - runtime->Register(CreateBoardLookupActor(MakeEndpointsBoardPath("/Root"), edge, EBoardLookupMode::Second)); - TAutoPtr handle; - auto* ev = runtime->GrabEdgeEvent(handle); - UNIT_ASSERT(ev); - Cerr << "ev for path: " << ev->Path << ", is unknown: " << (ev->Status == TEvStateStorage::TEvBoardInfo::EStatus::Unknown) - << ", is unavalable: " << (ev->Status == TEvStateStorage::TEvBoardInfo::EStatus::NotAvailable) << Endl; - UNIT_ASSERT(ev->Status == TEvStateStorage::TEvBoardInfo::EStatus::Ok); - UNIT_ASSERT_VALUES_EQUAL(ev->InfoEntries.size(), 2); - bool hasKafkaPort = false; - for (const auto& [k, v] : ev->InfoEntries) { - NKikimrStateStorage::TEndpointBoardEntry entry; - UNIT_ASSERT(entry.ParseFromString(v.Payload)); - Cerr << "Got entry, actor: " << k.ToString() << ", entry: " << entry.DebugString() << Endl; - if (entry.GetPort() == kafkaPort) { - UNIT_ASSERT_STRINGS_EQUAL(entry.GetEndpointId(), NGRpcService::KafkaEndpointId); - hasKafkaPort = true; - } - } - UNIT_ASSERT(hasKafkaPort); - } - struct TMetarequestTestParams { - NPersQueue::TTestServer Server; - ui64 KafkaPort; - NKikimrConfig::TKafkaProxyConfig KafkaConfig; - TString FullTopicName; - }; - - TMetarequestTestParams SetupServer(const TString shortTopicName) { - TStringBuilder fullTopicName; - fullTopicName << "rt3.dc1--" << shortTopicName; - auto pm = MakeSimpleShared(); - ui16 kafkaPort = pm->GetPort(); - auto serverSettings = NPersQueueTests::PQSettings(0).SetDomainName("Root").SetNodeCount(1); - serverSettings.AppConfig->MutableKafkaProxyConfig()->SetEnableKafkaProxy(true); - - serverSettings.AppConfig->MutableKafkaProxyConfig()->SetListeningPort(kafkaPort); - NPersQueue::TTestServer server(serverSettings, true, {}, NActors::NLog::PRI_INFO, pm); - - server.AnnoyingClient->CreateTopic(fullTopicName, 1); - server.WaitInit(shortTopicName); - - return {std::move(server), kafkaPort, serverSettings.AppConfig->GetKafkaProxyConfig(), fullTopicName}; - } - - void CreateMetarequestActor( - const TActorId& edge, const TVector& topics, auto* runtime, const auto& kafkaConfig, const TActorId& fakeCacheId = {} - ) { - TMetadataRequestData::TPtr metaRequest = std::make_shared(); - for (const auto& topicPath : topics) { - metaRequest->Topics.emplace_back(); - auto& topic = metaRequest->Topics.back(); - topic.Name = topicPath; - } - - auto context = std::make_shared(kafkaConfig); - context->ConnectionId = edge; - context->DatabasePath = "/Root"; - context->UserToken = new NACLib::TUserToken("root@builtin", {}); - - TActorId actorId; - if (fakeCacheId) { - actorId = runtime->Register(new NKafka::TKafkaMetadataActor( - context, 1, TMessagePtr(std::make_shared(), metaRequest), fakeCacheId - )); - } else { - actorId = runtime->Register(new NKafka::TKafkaMetadataActor( - context, 1, TMessagePtr(std::make_shared(), metaRequest), - NKafka::MakeKafkaDiscoveryCacheID() - )); - } - runtime->EnableScheduleForActor(actorId); - } - - void CheckKafkaMetaResponse(TTestActorRuntime* runtime, ui64 kafkaPort, bool error = false, ui64 expectedCount = 1) { - TAutoPtr handle; - auto* ev = runtime->GrabEdgeEvent(handle); - UNIT_ASSERT(ev); - auto response = dynamic_cast(ev->Response.get()); - UNIT_ASSERT_VALUES_EQUAL(response->Topics.size(), expectedCount); - if (!error) { - for (const auto& topic : response->Topics) { - UNIT_ASSERT(topic.ErrorCode == EKafkaErrors::NONE_ERROR); - } - } else { - UNIT_ASSERT(response->Topics[0].ErrorCode == EKafkaErrors::LISTENER_NOT_FOUND); - UNIT_ASSERT(ev->ErrorCode == EKafkaErrors::LISTENER_NOT_FOUND); - return; - } - UNIT_ASSERT_VALUES_EQUAL(response->Brokers.size(), 1); - Cerr << "Broker " << response->Brokers[0].NodeId << " - " << response->Brokers[0].Host << ":" << response->Brokers[0].Port << Endl; - UNIT_ASSERT_VALUES_EQUAL(response->Brokers[0].Port, kafkaPort); - } - - Y_UNIT_TEST(MetadataActorGetsEndpoint) { - auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); - - auto* runtime = server.GetRuntime(); - auto edge = runtime->AllocateEdgeActor(); - - CreateMetarequestActor(edge, {NKikimr::JoinPath({"/Root/PQ/", topicName})}, runtime, - config); - - CheckKafkaMetaResponse(runtime, kafkaPort); - } - - Y_UNIT_TEST(DiscoveryResponsesWithNoNode) { - auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); - - auto* runtime = server.GetRuntime(); - auto edge = runtime->AllocateEdgeActor(); - - Ydb::Discovery::ListEndpointsResult leResult; - auto* ep = leResult.add_endpoints(); - ep->set_address("wrong.host"); - ep->set_port(1); - ep->set_node_id(9999); - ep = leResult.add_endpoints(); - ep->set_address("wrong.host2"); - ep->set_port(2); - ep->set_node_id(9998); - auto fakeCache = runtime->Register(new TFakeDiscoveryCache(leResult, false)); - runtime->EnableScheduleForActor(fakeCache); - CreateMetarequestActor(edge, {NKikimr::JoinPath({"/Root/PQ/", topicName})}, runtime, - config, fakeCache); - - CheckKafkaMetaResponse(runtime, kafkaPort); - } - - Y_UNIT_TEST(DiscoveryResponsesWithError) { - auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); - - auto* runtime = server.GetRuntime(); - auto edge = runtime->AllocateEdgeActor(); - - Ydb::Discovery::ListEndpointsResult leResult; - auto fakeCache = runtime->Register(new TFakeDiscoveryCache(leResult, true)); - runtime->EnableScheduleForActor(fakeCache); - CreateMetarequestActor(edge, {NKikimr::JoinPath({"/Root/PQ/", topicName})}, runtime, - config, fakeCache); - - CheckKafkaMetaResponse(runtime, kafkaPort, true); - } - - Y_UNIT_TEST(DiscoveryResponsesWithOtherPort) { - auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); - - auto* runtime = server.GetRuntime(); - auto edge = runtime->AllocateEdgeActor(); - - Ydb::Discovery::ListEndpointsResult leResult; - auto* ep = leResult.add_endpoints(); - ep->set_address("localhost"); - ep->set_port(12345); - ep->set_node_id(runtime->GetNodeId(0)); - auto fakeCache = runtime->Register(new TFakeDiscoveryCache(leResult, false)); - runtime->EnableScheduleForActor(fakeCache); - CreateMetarequestActor(edge, {NKikimr::JoinPath({"/Root/PQ/", topicName})}, runtime, - config, fakeCache); - - CheckKafkaMetaResponse(runtime, 12345); - } - - - Y_UNIT_TEST(MetadataActorDoubleTopic) { - auto [server, kafkaPort, config, topicName] = SetupServer("topic1"); - - auto* runtime = server.GetRuntime(); - auto edge = runtime->AllocateEdgeActor(); - - auto path = NKikimr::JoinPath({"/Root/PQ/", topicName}); - CreateMetarequestActor(edge, {path, path}, runtime, config); - - CheckKafkaMetaResponse(runtime, kafkaPort, false, 2); - } - } -} diff --git a/ydb/core/kafka_proxy/ut/ut_protocol.cpp b/ydb/core/kafka_proxy/ut/ut_protocol.cpp index 6770f9b7beda..64d1b7ab3c79 100644 --- a/ydb/core/kafka_proxy/ut/ut_protocol.cpp +++ b/ydb/core/kafka_proxy/ut/ut_protocol.cpp @@ -1492,6 +1492,72 @@ Y_UNIT_TEST_SUITE(KafkaProtocol) { } } // Y_UNIT_TEST(CreatePartitionsScenario) + Y_UNIT_TEST(DescribeConfigsScenario) { + TInsecureTestServer testServer("2"); + + TString topic0Name = "/Root/topic-0-test"; + TString shortTopic0Name = "topic-0-test"; + TString topic1Name = "/Root/topic-1-test"; + TString shortTopic1Name = "topic-1-test"; + TString notExistsTopicName = "/Root/not-exists"; + //ui64 minActivePartitions = 10; + + NYdb::NTopic::TTopicClient pqClient(*testServer.Driver); + { + auto result0 = pqClient.CreateTopic( + topic0Name, + NYdb::NTopic::TCreateTopicSettings().PartitioningSettings(5, 5).RetentionPeriod(TDuration::Hours(10)) + ).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result0.IsTransportError(), false); + UNIT_ASSERT_VALUES_EQUAL_C(result0.GetStatus(), EStatus::SUCCESS, result0.GetIssues().ToString()); + + auto result1 = pqClient.CreateTopic( + topic1Name, + NYdb::NTopic::TCreateTopicSettings().PartitioningSettings(10, 10).RetentionStorageMb(51200) + ).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result1.IsTransportError(), false); + UNIT_ASSERT_VALUES_EQUAL_C(result1.GetStatus(), EStatus::SUCCESS, result1.GetIssues().ToString()); + } + + TKafkaTestClient client(testServer.Port); + + client.AuthenticateToKafka(); + + auto getConfigsMap = [&](const auto& describeResult) { + THashMap configs; + for (const auto& config : describeResult.Configs) { + configs[TString(config.Name->data())] = config; + } + return configs; + }; + { + auto msg = client.DescribeConfigs({ shortTopic0Name, notExistsTopicName, shortTopic1Name}); + const auto& res0 = msg->Results[0]; + UNIT_ASSERT_VALUES_EQUAL(res0.ResourceName.value(), shortTopic0Name); + UNIT_ASSERT_VALUES_EQUAL(res0.ErrorCode, NONE_ERROR); + auto configs0 = getConfigsMap(res0); + UNIT_ASSERT_VALUES_EQUAL(configs0.size(), 33); + UNIT_ASSERT_VALUES_EQUAL(FromString(configs0.find("retention.ms")->second.Value->data()), TDuration::Hours(10).MilliSeconds()); + UNIT_ASSERT_VALUES_EQUAL(configs0.find("cleanup.policy")->second.Value->data(), "delete"); + + UNIT_ASSERT_VALUES_EQUAL(msg->Results[1].ResourceName.value(), notExistsTopicName); + UNIT_ASSERT_VALUES_EQUAL(msg->Results[1].ErrorCode, UNKNOWN_TOPIC_OR_PARTITION); + + UNIT_ASSERT_VALUES_EQUAL(msg->Results[2].ResourceName.value(), shortTopic1Name); + UNIT_ASSERT_VALUES_EQUAL(msg->Results[2].ErrorCode, NONE_ERROR); + auto configs1 = getConfigsMap(msg->Results[2]); + UNIT_ASSERT_VALUES_EQUAL(FromString(configs1.find("retention.bytes")->second.Value->data()), 51200 * 1_MB); + UNIT_ASSERT_VALUES_EQUAL(FromString(configs1.find("max.message.bytes")->second.Value->data()), 1_KB); + } + { + auto msg = client.DescribeConfigs({ shortTopic0Name, shortTopic0Name}); + UNIT_ASSERT_VALUES_EQUAL(msg->Results.size(), 1); + const auto& res0 = msg->Results[0]; + UNIT_ASSERT_VALUES_EQUAL(res0.ResourceName.value(), shortTopic0Name); + UNIT_ASSERT_VALUES_EQUAL(res0.ErrorCode, NONE_ERROR); + } + } + Y_UNIT_TEST(AlterConfigsScenario) { TInsecureTestServer testServer("2"); @@ -2126,8 +2192,10 @@ Y_UNIT_TEST_SUITE(KafkaProtocol) { UNIT_ASSERT_VALUES_EQUAL(resp1->ProducerEpoch, 0); // validate second response UNIT_ASSERT_VALUES_EQUAL(resp2->ErrorCode, EKafkaErrors::NONE_ERROR); - UNIT_ASSERT_GT(resp2->ProducerId, resp1->ProducerId); + UNIT_ASSERT_GT(resp2->ProducerId, 0); UNIT_ASSERT_VALUES_EQUAL(resp2->ProducerEpoch, 0); + // validate different values for different responses + UNIT_ASSERT_VALUES_UNEQUAL(resp1->ProducerId, resp2->ProducerId); } Y_UNIT_TEST(InitProducerId_forSqlInjectionShouldReturnWithoutDropingDatabase) { @@ -2169,7 +2237,7 @@ Y_UNIT_TEST_SUITE(KafkaProtocol) { TKafkaTestClient kafkaClient(testServer.Port); // use random transactional id for each request top avoid parallel execution problems auto transactionalId = TStringBuilder() << "my-tx-producer-" << RandomNumber(); - + // this first request will init table auto resp1 = kafkaClient.InitProducerId(transactionalId); // update epoch to be last available @@ -2187,7 +2255,7 @@ Y_UNIT_TEST_SUITE(KafkaProtocol) { rows.EndList(); auto upsertResult = tableClient.BulkUpsert("//Root/.metadata/kafka_transactional_producers", rows.Build()).GetValueSync(); UNIT_ASSERT_EQUAL(upsertResult.GetStatus(), EStatus::SUCCESS); - + auto resp2 = kafkaClient.InitProducerId(transactionalId); // validate first response diff --git a/ydb/core/kafka_proxy/ut/ya.make b/ydb/core/kafka_proxy/ut/ya.make index f16ee9f9bd95..799550cfe59f 100644 --- a/ydb/core/kafka_proxy/ut/ya.make +++ b/ydb/core/kafka_proxy/ut/ya.make @@ -12,8 +12,8 @@ SRCS( ut_protocol.cpp ut_serialization.cpp metarequest_ut.cpp - port_discovery_ut.cpp ut_transaction_coordinator.cpp + actors_ut.cpp ) PEERDIR( diff --git a/ydb/core/kafka_proxy/ya.make b/ydb/core/kafka_proxy/ya.make index c84a57e542f2..a7dee4ff78a0 100644 --- a/ydb/core/kafka_proxy/ya.make +++ b/ydb/core/kafka_proxy/ya.make @@ -18,6 +18,7 @@ SRCS( actors/kafka_create_topics_actor.cpp actors/kafka_create_partitions_actor.cpp actors/kafka_alter_configs_actor.cpp + actors/kafka_describe_configs_actor.cpp actors/kafka_balance_actor_sql.cpp actors/kafka_balancer_actor.cpp kafka_connection.cpp diff --git a/ydb/core/kqp/common/batch/batch_operation_settings.cpp b/ydb/core/kqp/common/batch/batch_operation_settings.cpp new file mode 100644 index 000000000000..412c0ebd8a22 --- /dev/null +++ b/ydb/core/kqp/common/batch/batch_operation_settings.cpp @@ -0,0 +1,17 @@ +#include "batch_operation_settings.h" + +namespace NKikimr::NKqp { + +TBatchOperationSettings SetBatchOperationSettings(const NKikimrConfig::TTableServiceConfig::TBatchOperationSettings& settings) { + TBatchOperationSettings res; + + res.MaxBatchSize = settings.GetMaxBatchSize(); + res.MinBatchSize = settings.GetMinBatchSize(); + res.MaxRetryDelayMs = settings.GetMaxRetryDelayMs(); + res.StartRetryDelayMs = settings.GetStartRetryDelayMs(); + res.PartitionExecutionLimit = settings.GetPartitionExecutionLimit(); + + return res; +} + +} // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/common/batch/batch_operation_settings.h b/ydb/core/kqp/common/batch/batch_operation_settings.h new file mode 100644 index 000000000000..751483075ea3 --- /dev/null +++ b/ydb/core/kqp/common/batch/batch_operation_settings.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +namespace NKikimr::NKqp { + +struct TBatchOperationSettings { + ui64 MaxBatchSize = 10000; + ui64 MinBatchSize = 1; + ui64 MaxRetryDelayMs = 30000; + ui64 StartRetryDelayMs = 50; + ui64 PartitionExecutionLimit = 10; +}; + +TBatchOperationSettings SetBatchOperationSettings(const NKikimrConfig::TTableServiceConfig::TBatchOperationSettings& settings); + +} // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/common/batch/params.h b/ydb/core/kqp/common/batch/params.h index 266e17a0ab12..f27b6f1a1d99 100644 --- a/ydb/core/kqp/common/batch/params.h +++ b/ydb/core/kqp/common/batch/params.h @@ -4,12 +4,12 @@ namespace NKikimr::NKqp::NBatchParams { -const TString Header = "$_kqp_batch_"; -const TString IsFirstQuery = Header + "is_first_query"; -const TString IsLastQuery = Header + "is_last_query"; +const TString Header = "%kqp%batch_"; const TString IsInclusiveLeft = Header + "is_inclusive_left"; const TString IsInclusiveRight = Header + "is_inclusive_right"; const TString Begin = Header + "begin_"; // begin_N const TString End = Header + "end_"; // end_N +const TString BeginPrefixSize = Begin + "prefix_size"; +const TString EndPrefixSize = End + "prefix_size"; -} // namespace NKikimr::NKqp::NPartitionedExecuter +} // namespace NKikimr::NKqp::NBatchParams diff --git a/ydb/core/kqp/common/batch/ya.make b/ydb/core/kqp/common/batch/ya.make new file mode 100644 index 000000000000..74d5d87b714e --- /dev/null +++ b/ydb/core/kqp/common/batch/ya.make @@ -0,0 +1,13 @@ +LIBRARY() + +SRCS( + batch_operation_settings.cpp +) + +PEERDIR( + ydb/core/protos +) + +YQL_LAST_ABI_VERSION() + +END() diff --git a/ydb/core/kqp/common/kqp_tx_manager.cpp b/ydb/core/kqp/common/kqp_tx_manager.cpp index 2d973deea186..8006d8283015 100644 --- a/ydb/core/kqp/common/kqp_tx_manager.cpp +++ b/ydb/core/kqp/common/kqp_tx_manager.cpp @@ -336,7 +336,7 @@ class TKqpTransactionManager : public IKqpTransactionManager { SendingShards.insert(shardId); } } - if (!shardInfo.Locks.empty()) { + if (!shardInfo.Locks.empty() || (shardInfo.Flags & EAction::READ)) { SendingShards.insert(shardId); if (shardInfo.IsOlap) { sendingColumnShardsSet.insert(shardId); diff --git a/ydb/core/kqp/common/simple/kqp_event_ids.h b/ydb/core/kqp/common/simple/kqp_event_ids.h index b9ad1addb195..627607dc09f4 100644 --- a/ydb/core/kqp/common/simple/kqp_event_ids.h +++ b/ydb/core/kqp/common/simple/kqp_event_ids.h @@ -65,7 +65,8 @@ struct TKqpExecuterEvents { EvProgress, EvStreamDataAck, EvTableResolveStatus, - EvShardsResolveStatus + EvShardsResolveStatus, + EvDelayedExecution }; }; diff --git a/ydb/core/kqp/common/ya.make b/ydb/core/kqp/common/ya.make index 992571fe4a77..938dc883ee02 100644 --- a/ydb/core/kqp/common/ya.make +++ b/ydb/core/kqp/common/ya.make @@ -29,6 +29,7 @@ PEERDIR( ydb/core/engine ydb/core/kqp/expr_nodes ydb/core/kqp/common/simple + ydb/core/kqp/common/batch ydb/core/kqp/common/compilation ydb/core/kqp/common/events ydb/core/kqp/common/shutdown @@ -58,6 +59,7 @@ GENERATE_ENUM_SERIALIZATION(kqp_yql.h) END() RECURSE( + batch compilation events simple diff --git a/ydb/core/kqp/compute_actor/kqp_scan_fetcher_actor.cpp b/ydb/core/kqp/compute_actor/kqp_scan_fetcher_actor.cpp index 605a7e26139e..45064976e208 100644 --- a/ydb/core/kqp/compute_actor/kqp_scan_fetcher_actor.cpp +++ b/ydb/core/kqp/compute_actor/kqp_scan_fetcher_actor.cpp @@ -1,11 +1,12 @@ #include "kqp_scan_fetcher_actor.h" -#include + +#include #include #include -#include -#include #include +#include +#include #include namespace NKikimr::NKqp::NScanPrivate { @@ -16,18 +17,16 @@ using namespace NYql; using namespace NYql::NDq; using namespace NKikimr::NKqp::NComputeActor; -static constexpr ui64 MAX_SHARD_RETRIES = 5; // retry after: 0, 250, 500, 1000, 2000 +static constexpr ui64 MAX_SHARD_RETRIES = 5; // retry after: 0, 250, 500, 1000, 2000 static constexpr ui64 MAX_TOTAL_SHARD_RETRIES = 20; static constexpr ui64 MAX_SHARD_RESOLVES = 3; -} // anonymous namespace - +} // anonymous namespace -TKqpScanFetcherActor::TKqpScanFetcherActor(const NKikimrKqp::TKqpSnapshot& snapshot, - const TComputeRuntimeSettings& settings, std::vector&& computeActors, - const ui64 txId, const TMaybe lockTxId, const ui32 lockNodeId, const TMaybe lockMode, - const NKikimrTxDataShard::TKqpTransaction_TScanTaskMeta& meta, const TShardsScanningPolicy& shardsScanningPolicy, - TIntrusivePtr counters, NWilson::TTraceId traceId) +TKqpScanFetcherActor::TKqpScanFetcherActor(const NKikimrKqp::TKqpSnapshot& snapshot, const TComputeRuntimeSettings& settings, + std::vector&& computeActors, const ui64 txId, const TMaybe lockTxId, const ui32 lockNodeId, + const TMaybe lockMode, const NKikimrTxDataShard::TKqpTransaction_TScanTaskMeta& meta, + const TShardsScanningPolicy& shardsScanningPolicy, TIntrusivePtr counters, NWilson::TTraceId traceId) : Meta(meta) , ScanDataMeta(Meta) , RuntimeSettings(settings) @@ -48,14 +47,15 @@ TKqpScanFetcherActor::TKqpScanFetcherActor(const NKikimrKqp::TKqpSnapshot& snaps KeyColumnTypes.reserve(Meta.GetKeyColumnTypes().size()); for (size_t i = 0; i < Meta.KeyColumnTypesSize(); i++) { NScheme::TTypeId typeId = Meta.GetKeyColumnTypes().at(i); - NScheme::TTypeInfo typeInfo = NScheme::NTypeIds::IsParametrizedType(typeId) ? - NScheme::TypeInfoFromProto(typeId, Meta.GetKeyColumnTypeInfos().at(i)) : - NScheme::TTypeInfo(typeId); + NScheme::TTypeInfo typeInfo = NScheme::NTypeIds::IsParametrizedType(typeId) + ? NScheme::TypeInfoFromProto(typeId, Meta.GetKeyColumnTypeInfos().at(i)) + : NScheme::TTypeInfo(typeId); KeyColumnTypes.push_back(typeInfo); } } -TVector TKqpScanFetcherActor::BuildSerializedTableRanges(const NKikimrTxDataShard::TKqpTransaction::TScanTaskMeta::TReadOpMeta& readData) { +TVector TKqpScanFetcherActor::BuildSerializedTableRanges( + const NKikimrTxDataShard::TKqpTransaction::TScanTaskMeta::TReadOpMeta& readData) { TVector resultLocal; resultLocal.reserve(readData.GetKeyRanges().size()); for (const auto& range : readData.GetKeyRanges()) { @@ -88,17 +88,16 @@ void TKqpScanFetcherActor::Bootstrap() { void TKqpScanFetcherActor::HandleExecute(TEvScanExchange::TEvAckData::TPtr& ev) { AFL_ENSURE(ev->Get()->GetFreeSpace()); - AFL_DEBUG(NKikimrServices::KQP_COMPUTE)("event", "AckDataFromCompute")("self_id", SelfId())("scan_id", ScanId) - ("packs_to_send", InFlightComputes.GetPacksToSendCount()) - ("from", ev->Sender)("shards remain", PendingShards.size()) - ("in flight scans", InFlightShards.GetScansCount()) - ("in flight shards", InFlightShards.GetShardsCount()); + AFL_DEBUG(NKikimrServices::KQP_COMPUTE)("event", "AckDataFromCompute")("self_id", SelfId())("scan_id", ScanId)( + "packs_to_send", InFlightComputes.GetPacksToSendCount())("from", ev->Sender)("shards remain", PendingShards.size())( + "in flight scans", InFlightShards.GetScansCount())("in flight shards", InFlightShards.GetShardsCount()); InFlightComputes.OnComputeAck(ev->Sender, ev->Get()->GetFreeSpace()); CheckFinish(); } void TKqpScanFetcherActor::HandleExecute(TEvScanExchange::TEvTerminateFromCompute::TPtr& ev) { - AFL_DEBUG(NKikimrServices::KQP_COMPUTE)("event", "TEvTerminateFromCompute")("sender", ev->Sender)("info", ev->Get()->GetIssues().ToOneLineString()); + AFL_DEBUG(NKikimrServices::KQP_COMPUTE)("event", "TEvTerminateFromCompute")("sender", ev->Sender)( + "info", ev->Get()->GetIssues().ToOneLineString()); TStringBuilder sb; sb << "Send abort execution from compute actor, message: " << ev->Get()->GetIssues().ToOneLineString(); @@ -126,17 +125,13 @@ void TKqpScanFetcherActor::HandleExecute(TEvKqpCompute::TEvScanData::TPtr& ev) { AFL_ENSURE(state->State == EShardState::Running)("state", state->State)("actor_id", state->ActorId)("ev_sender", ev->Sender); AFL_DEBUG(NKikimrServices::KQP_COMPUTE) - ("Recv TEvScanData from ShardID=", ev->Sender) - ("ScanId", ev->Get()->ScanId) - ("Finished", ev->Get()->Finished) - ("Lock", [&]() { + ("Recv TEvScanData from ShardID=", ev->Sender)("ScanId", ev->Get()->ScanId)("Finished", ev->Get()->Finished)("Lock", [&]() { TStringBuilder builder; for (const auto& lock : ev->Get()->LocksInfo.Locks) { builder << lock.ShortDebugString(); } return builder; - }()) - ("BrokenLocks", [&]() { + }())("BrokenLocks", [&]() { TStringBuilder builder; for (const auto& lock : ev->Get()->LocksInfo.BrokenLocks) { builder << lock.ShortDebugString(); @@ -164,10 +159,8 @@ void TKqpScanFetcherActor::HandleExecute(TEvKqpCompute::TEvScanError::TPtr& ev) TIssues issues; IssuesFromMessage(msg.GetIssues(), issues); - CA_LOG_W("Got EvScanError scan state: " - << ", status: " << Ydb::StatusIds_StatusCode_Name(status) - << ", reason: " << issues.ToString() - << ", tablet id: " << msg.GetTabletId() << ", actor_id: " << ev->Sender); + CA_LOG_W("Got EvScanError scan state: " << ", status: " << Ydb::StatusIds_StatusCode_Name(status) << ", reason: " << issues.ToString() + << ", tablet id: " << msg.GetTabletId() << ", actor_id: " << ev->Sender); auto state = InFlightShards.GetShardStateByActorId(ev->Sender); if (!state) { @@ -184,8 +177,8 @@ void TKqpScanFetcherActor::HandleExecute(TEvKqpCompute::TEvScanError::TPtr& ev) if (state->State == EShardState::Starting) { ++TotalRetries; if (TotalRetries >= MAX_TOTAL_SHARD_RETRIES) { - CA_LOG_E("TKqpScanFetcherActor: broken tablet for this request " << state->TabletId - << ", retries limit exceeded (" << state->TotalRetries << "/" << TotalRetries << ")"); + CA_LOG_E("TKqpScanFetcherActor: broken tablet for this request " << state->TabletId << ", retries limit exceeded (" + << state->TotalRetries << "/" << TotalRetries << ")"); SendGlobalFail(NDqProto::COMPUTE_STATE_FAILURE, YdbStatusToDqStatus(status), issues); return PassAway(); } @@ -205,8 +198,8 @@ void TKqpScanFetcherActor::HandleExecute(TEvKqpCompute::TEvScanError::TPtr& ev) } if (state->State == EShardState::PostRunning || state->State == EShardState::Running) { - CA_LOG_E("TKqpScanFetcherActor: broken tablet for this request " << state->TabletId - << ", retries limit exceeded (" << state->TotalRetries << "/" << TotalRetries << ")"); + CA_LOG_E("TKqpScanFetcherActor: broken tablet for this request " << state->TabletId << ", retries limit exceeded (" + << state->TotalRetries << "/" << TotalRetries << ")"); SendGlobalFail(NDqProto::COMPUTE_STATE_FAILURE, YdbStatusToDqStatus(status), issues); return PassAway(); } @@ -301,68 +294,82 @@ void TKqpScanFetcherActor::HandleExecute(TEvTxProxySchemeCache::TEvResolveKeySet } const auto& tr = *AppData()->TypeRegistry; - - TVector newShards; - newShards.reserve(keyDesc->GetPartitions().size()); - - for (ui64 idx = 0, i = 0; idx < keyDesc->GetPartitions().size(); ++idx) { - const auto& partition = keyDesc->GetPartitions()[idx]; - - TTableRange partitionRange{ - idx == 0 ? state.Ranges.front().From.GetCells() : keyDesc->GetPartitions()[idx - 1].Range->EndKeyPrefix.GetCells(), - idx == 0 ? state.Ranges.front().FromInclusive : !keyDesc->GetPartitions()[idx - 1].Range->IsInclusive, - keyDesc->GetPartitions()[idx].Range->EndKeyPrefix.GetCells(), - keyDesc->GetPartitions()[idx].Range->IsInclusive - }; - - CA_LOG_D("Processing resolved ShardId# " << partition.ShardId - << ", partition range: " << DebugPrintRange(KeyColumnTypes, partitionRange, tr) - << ", i: " << i << ", state ranges: " << state.Ranges.size()); - - auto newShard = TShardState(partition.ShardId); - - for (ui64 j = i; j < state.Ranges.size(); ++j) { - auto comparison = CompareRanges(partitionRange, state.Ranges[j].ToTableRange(), KeyColumnTypes); - CA_LOG_D("Compare range #" << j << " " << DebugPrintRange(KeyColumnTypes, state.Ranges[j].ToTableRange(), tr) - << " with partition range " << DebugPrintRange(KeyColumnTypes, partitionRange, tr) - << " : " << comparison); - - if (comparison > 0) { + if (Meta.HasOlapProgram()) { + bool found = false; + for (auto&& partition : keyDesc->GetPartitions()) { + if (partition.ShardId != state.TabletId) { continue; - } else if (comparison == 0) { - auto intersection = Intersect(KeyColumnTypes, partitionRange, state.Ranges[j].ToTableRange()); - CA_LOG_D("Add range to new shardId: " << partition.ShardId - << ", range: " << DebugPrintRange(KeyColumnTypes, intersection, tr)); - - newShard.Ranges.emplace_back(TSerializedTableRange(intersection)); - } else { - break; } - i = j; + auto newShard = TShardState(partition.ShardId); + AFL_ENSURE(!found); + newShard.LastKey = std::move(state.LastKey); + newShard.LastCursorProto = std::move(state.LastCursorProto); + newShard.Ranges = state.Ranges; + PendingShards.emplace_front(std::move(newShard)); + found = true; } + AFL_ENSURE(found); + } else { + TVector newShards; + newShards.reserve(keyDesc->GetPartitions().size()); + + for (ui64 idx = 0, i = 0; idx < keyDesc->GetPartitions().size(); ++idx) { + const auto& partition = keyDesc->GetPartitions()[idx]; + + TTableRange partitionRange{ idx == 0 ? state.Ranges.front().From.GetCells() + : keyDesc->GetPartitions()[idx - 1].Range->EndKeyPrefix.GetCells(), + idx == 0 ? state.Ranges.front().FromInclusive : !keyDesc->GetPartitions()[idx - 1].Range->IsInclusive, + keyDesc->GetPartitions()[idx].Range->EndKeyPrefix.GetCells(), keyDesc->GetPartitions()[idx].Range->IsInclusive }; + + CA_LOG_D("Processing resolved ShardId# " + << partition.ShardId << ", partition range: " << DebugPrintRange(KeyColumnTypes, partitionRange, tr) << ", i: " << i + << ", state ranges: " << state.Ranges.size()); + + auto newShard = TShardState(partition.ShardId); + + for (ui64 j = i; j < state.Ranges.size(); ++j) { + auto comparison = CompareRanges(partitionRange, state.Ranges[j].ToTableRange(), KeyColumnTypes); + CA_LOG_D("Compare range #" << j << " " << DebugPrintRange(KeyColumnTypes, state.Ranges[j].ToTableRange(), tr) + << " with partition range " << DebugPrintRange(KeyColumnTypes, partitionRange, tr) << " : " + << comparison); + + if (comparison > 0) { + continue; + } else if (comparison == 0) { + auto intersection = Intersect(KeyColumnTypes, partitionRange, state.Ranges[j].ToTableRange()); + CA_LOG_D( + "Add range to new shardId: " << partition.ShardId << ", range: " << DebugPrintRange(KeyColumnTypes, intersection, tr)); + + newShard.Ranges.emplace_back(TSerializedTableRange(intersection)); + } else { + break; + } + i = j; + } - if (!newShard.Ranges.empty()) { - newShards.emplace_back(std::move(newShard)); + if (!newShard.Ranges.empty()) { + newShards.emplace_back(std::move(newShard)); + } } - } - AFL_ENSURE(!newShards.empty()); - - for (int i = newShards.ysize() - 1; i >= 0; --i) { - PendingShards.emplace_front(std::move(newShards[i])); - } + AFL_ENSURE(!newShards.empty()); - if (!state.LastKey.empty()) { - PendingShards.front().LastKey = std::move(state.LastKey); - while (!PendingShards.empty() && PendingShards.front().GetScanRanges(KeyColumnTypes).empty()) { - CA_LOG_D("Nothing to read " << PendingShards.front().ToString(KeyColumnTypes)); - auto readShard = std::move(PendingShards.front()); - PendingShards.pop_front(); - PendingShards.front().LastKey = std::move(readShard.LastKey); - PendingShards.front().LastCursorProto = std::move(readShard.LastCursorProto); + for (int i = newShards.ysize() - 1; i >= 0; --i) { + PendingShards.emplace_front(std::move(newShards[i])); } - AFL_ENSURE(!PendingShards.empty()); + if (!state.LastKey.empty()) { + PendingShards.front().LastKey = std::move(state.LastKey); + while (!PendingShards.empty() && PendingShards.front().GetScanRanges(KeyColumnTypes).empty()) { + CA_LOG_D("Nothing to read " << PendingShards.front().ToString(KeyColumnTypes)); + auto readShard = std::move(PendingShards.front()); + PendingShards.pop_front(); + PendingShards.front().LastKey = std::move(readShard.LastKey); + PendingShards.front().LastCursorProto = std::move(readShard.LastCursorProto); + } + + AFL_ENSURE(!PendingShards.empty()); + } } StartTableScan(); } @@ -376,8 +383,8 @@ void TKqpScanFetcherActor::HandleExecute(TEvents::TEvUndelivered::TPtr& ev) { auto info = InFlightShards.GetShardScanner(ev->Cookie); if (!!info) { auto state = InFlightShards.GetShardStateVerified(info->GetTabletId()); - AFL_WARN(NKikimrServices::KQP_COMPUTE)("event", "TEvents::TEvUndelivered")("from_tablet", info->GetTabletId()) - ("state", state->State)("details", info->ToString())("node", SelfId().NodeId()); + AFL_WARN(NKikimrServices::KQP_COMPUTE)("event", "TEvents::TEvUndelivered")("from_tablet", info->GetTabletId())( + "state", state->State)("details", info->ToString())("node", SelfId().NodeId()); AFL_ENSURE(state->State == EShardState::Running || state->State == EShardState::Starting)("state", state->State); RetryDeliveryProblem(state); } @@ -392,18 +399,20 @@ void TKqpScanFetcherActor::HandleExecute(TEvInterconnect::TEvNodeDisconnected::T CA_LOG_N("Disconnected node " << nodeId); TrackingNodes.erase(nodeId); - SendGlobalFail(NDqProto::StatusIds::UNAVAILABLE, TIssuesIds::DEFAULT_ERROR, - TStringBuilder() << "Connection with node " << nodeId << " lost."); + SendGlobalFail( + NDqProto::StatusIds::UNAVAILABLE, TIssuesIds::DEFAULT_ERROR, TStringBuilder() << "Connection with node " << nodeId << " lost."); } -bool TKqpScanFetcherActor::SendGlobalFail(const NYql::NDqProto::StatusIds::StatusCode statusCode, const TIssuesIds::EIssueCode issueCode, const TString& message) const { +bool TKqpScanFetcherActor::SendGlobalFail( + const NYql::NDqProto::StatusIds::StatusCode statusCode, const TIssuesIds::EIssueCode issueCode, const TString& message) const { for (auto&& i : ComputeActorIds) { Send(i, new TEvScanExchange::TEvTerminateFromFetcher(statusCode, issueCode, message)); } return true; } -bool TKqpScanFetcherActor::SendGlobalFail(const NDqProto::EComputeState state, NYql::NDqProto::StatusIds::StatusCode statusCode, const TIssues& issues) const { +bool TKqpScanFetcherActor::SendGlobalFail( + const NDqProto::EComputeState state, NYql::NDqProto::StatusIds::StatusCode statusCode, const TIssues& issues) const { for (auto&& i : ComputeActorIds) { Send(i, new TEvScanExchange::TEvTerminateFromFetcher(state, statusCode, issues)); } @@ -486,9 +495,7 @@ std::unique_ptr TKqpScanFetcherActor::BuildEv TStringOutput stream(programBytes); Meta.GetOlapProgram().SerializeToArcadiaStream(&stream); ev->Record.SetOlapProgram(programBytes); - ev->Record.SetOlapProgramType( - NKikimrSchemeOp::EOlapProgramType::OLAP_PROGRAM_SSA_PROGRAM_WITH_PARAMETERS - ); + ev->Record.SetOlapProgramType(NKikimrSchemeOp::EOlapProgramType::OLAP_PROGRAM_SSA_PROGRAM_WITH_PARAMETERS); } ev->Record.SetDataFormat(Meta.GetDataFormat()); @@ -514,18 +521,15 @@ void TKqpScanFetcherActor::ProcessPendingScanDataItem(TEvKqpCompute::TEvScanData state->LastKey = std::move(msg.LastKey); state->LastCursorProto = std::move(msg.LastCursorProto); const ui64 rowsCount = msg.GetRowsCount(); - AFL_DEBUG(NKikimrServices::KQP_COMPUTE)("action", "got EvScanData")("rows", rowsCount)("finished", msg.Finished)("exceeded", msg.RequestedBytesLimitReached) - ("scan", ScanId)("packs_to_send", InFlightComputes.GetPacksToSendCount()) - ("from", ev->Sender)("shards remain", PendingShards.size()) - ("in flight scans", InFlightShards.GetScansCount()) - ("in flight shards", InFlightShards.GetShardsCount()) - ("delayed_for_seconds_by_ratelimiter", latency.SecondsFloat()) - ("tablet_id", state->TabletId) - ("locks", msg.LocksInfo.Locks.size()) - ("broken locks", msg.LocksInfo.BrokenLocks.size()); + AFL_DEBUG(NKikimrServices::KQP_COMPUTE)("action", "got EvScanData")("rows", rowsCount)("finished", msg.Finished)( + "exceeded", msg.RequestedBytesLimitReached)("scan", ScanId)("packs_to_send", InFlightComputes.GetPacksToSendCount())("from", ev->Sender)( + "shards remain", PendingShards.size())("in flight scans", InFlightShards.GetScansCount())( + "in flight shards", InFlightShards.GetShardsCount())("delayed_for_seconds_by_ratelimiter", latency.SecondsFloat())( + "tablet_id", state->TabletId)("locks", msg.LocksInfo.Locks.size())("broken locks", msg.LocksInfo.BrokenLocks.size()); auto shardScanner = InFlightShards.GetShardScannerVerified(state->TabletId); auto tasksForCompute = shardScanner->OnReceiveData(msg, shardScanner); - AFL_ENSURE(tasksForCompute.size() == 1 || tasksForCompute.size() == 0 || tasksForCompute.size() == ComputeActorIds.size())("size", tasksForCompute.size())("compute_size", ComputeActorIds.size()); + AFL_ENSURE(tasksForCompute.size() == 1 || tasksForCompute.size() == 0 || tasksForCompute.size() == ComputeActorIds.size())( + "size", tasksForCompute.size())("compute_size", ComputeActorIds.size()); for (auto&& i : tasksForCompute) { const std::optional computeShardId = i->GetComputeShardId(); InFlightComputes.OnReceiveData(computeShardId, std::move(i)); @@ -535,7 +539,8 @@ void TKqpScanFetcherActor::ProcessPendingScanDataItem(TEvKqpCompute::TEvScanData InFlightShards.MutableStatistics(state->TabletId).AddPack(rowsCount, 0); Stats.AddReadStat(state->TabletId, rowsCount, 0); - CA_LOG_D("EVLOGKQP:" << IsAggregationRequest << "/" << Meta.GetItemsLimit() << "/" << InFlightShards.GetTotalRowsCount() << "/" << rowsCount); + CA_LOG_D( + "EVLOGKQP:" << IsAggregationRequest << "/" << Meta.GetItemsLimit() << "/" << InFlightShards.GetTotalRowsCount() << "/" << rowsCount); if (msg.Finished) { Stats.CompleteShard(state); InFlightShards.StopScanner(state->TabletId); @@ -551,8 +556,9 @@ void TKqpScanFetcherActor::ProcessScanData() { PendingScanData.pop_front(); auto state = InFlightShards.GetShardStateByActorId(ev->Sender); - if (!state) + if (!state) { return; + } AFL_ENSURE(state->State == EShardState::Running || state->State == EShardState::PostRunning)("state", state->State); ProcessPendingScanDataItem(ev, enqueuedAt); @@ -575,11 +581,10 @@ void TKqpScanFetcherActor::StartTableScan() { } CA_LOG_D("Scheduled table scans, in flight: " << InFlightShards.GetScansCount() << " shards. " - << "pending shards to read: " << PendingShards.size() << ", " - << "pending resolve shards: " << PendingResolveShards.size() << ", " - << "average read rows: " << Stats.AverageReadRows() << ", " - << "average read bytes: " << Stats.AverageReadBytes() << ", "); - + << "pending shards to read: " << PendingShards.size() << ", " + << "pending resolve shards: " << PendingResolveShards.size() << ", " + << "average read rows: " << Stats.AverageReadRows() << ", " + << "average read bytes: " << Stats.AverageReadBytes() << ", "); } void TKqpScanFetcherActor::RetryDeliveryProblem(TShardState::TPtr state) { @@ -587,8 +592,8 @@ void TKqpScanFetcherActor::RetryDeliveryProblem(TShardState::TPtr state) { Counters->ScanQueryShardDisconnect->Inc(); if (state->TotalRetries >= MAX_TOTAL_SHARD_RETRIES) { - CA_LOG_E("TKqpScanFetcherActor: broken pipe with tablet " << state->TabletId - << ", retries limit exceeded (" << state->TotalRetries << ")"); + CA_LOG_E( + "TKqpScanFetcherActor: broken pipe with tablet " << state->TabletId << ", retries limit exceeded (" << state->TotalRetries << ")"); SendGlobalFail(NDqProto::StatusIds::UNAVAILABLE, TIssuesIds::KIKIMR_TEMPORARILY_UNAVAILABLE, TStringBuilder() << "Retries limit with shard " << state->TabletId << " exceeded."); return; @@ -606,10 +611,10 @@ void TKqpScanFetcherActor::RetryDeliveryProblem(TShardState::TPtr state) { ++TotalRetries; auto retryDelay = state->CalcRetryDelay(); - CA_LOG_W("TKqpScanFetcherActor: broken pipe with tablet " << state->TabletId - << ", restarting scan from last received key " << state->PrintLastKey(KeyColumnTypes) - << ", attempt #" << state->RetryAttempt << " (total " << state->TotalRetries << ")" - << " schedule after " << retryDelay); + CA_LOG_W("TKqpScanFetcherActor: broken pipe with tablet " << state->TabletId << ", restarting scan from last received key " + << state->PrintLastKey(KeyColumnTypes) << ", attempt #" << state->RetryAttempt + << " (total " << state->TotalRetries << ")" + << " schedule after " << retryDelay); state->RetryTimer = CreateLongTimer(TlsActivationContext->AsActorContext(), retryDelay, new IEventHandle(SelfId(), SelfId(), new TEvPrivate::TEvRetryShard(state->TabletId, state->Generation))); @@ -627,9 +632,10 @@ void TKqpScanFetcherActor::ResolveShard(TShardState& state) { state.State = EShardState::Resolving; state.ResolveAttempt++; state.SubscribedOnTablet = false; + AFL_ENSURE(state.Ranges.size()); - auto range = TTableRange(state.Ranges.front().From.GetCells(), state.Ranges.front().FromInclusive, - state.Ranges.back().To.GetCells(), state.Ranges.back().ToInclusive); + auto range = TTableRange(state.Ranges.front().From.GetCells(), state.Ranges.front().FromInclusive, state.Ranges.back().To.GetCells(), + state.Ranges.back().ToInclusive); TVector columns; columns.reserve(ScanDataMeta.GetColumns().size()); @@ -641,12 +647,11 @@ void TKqpScanFetcherActor::ResolveShard(TShardState& state) { columns.emplace_back(std::move(op)); } - auto keyDesc = MakeHolder(ScanDataMeta.TableId, range, TKeyDesc::ERowOperation::Read, - KeyColumnTypes, columns); + auto keyDesc = MakeHolder(ScanDataMeta.TableId, range, TKeyDesc::ERowOperation::Read, KeyColumnTypes, columns); CA_LOG_D("Sending TEvResolveKeySet update for table '" << ScanDataMeta.TablePath << "'" - << ", range: " << DebugPrintRange(KeyColumnTypes, range, *AppData()->TypeRegistry) - << ", attempt #" << state.ResolveAttempt); + << ", range: " << DebugPrintRange(KeyColumnTypes, range, *AppData()->TypeRegistry) + << ", attempt #" << state.ResolveAttempt); auto request = MakeHolder(); request->ResultSet.emplace_back(std::move(keyDesc)); @@ -678,10 +683,8 @@ void TKqpScanFetcherActor::CheckFinish() { if (GetShardsInProgressCount() == 0 && InFlightComputes.GetPacksToSendCount() == 0) { SendScanFinished(); InFlightShards.Stop(); - CA_LOG_D("EVLOGKQP(max_in_flight:" << MaxInFlight << ")" - << Endl << InFlightShards.GetDurationStats() - << Endl << InFlightShards.StatisticsToString() - ); + CA_LOG_D("EVLOGKQP(max_in_flight:" << MaxInFlight << ")" << Endl << InFlightShards.GetDurationStats() << Endl + << InFlightShards.StatisticsToString()); PassAway(); } } @@ -691,4 +694,4 @@ void TKqpScanFetcherActor::HandleExecute(NActors::TEvents::TEvWakeup::TPtr&) { Schedule(TDuration::Seconds(30), new NActors::TEvents::TEvWakeup()); } -} +} // namespace NKikimr::NKqp::NScanPrivate diff --git a/ydb/core/kqp/counters/kqp_counters.cpp b/ydb/core/kqp/counters/kqp_counters.cpp index a04a993eaa53..5df537be35f4 100644 --- a/ydb/core/kqp/counters/kqp_counters.cpp +++ b/ydb/core/kqp/counters/kqp_counters.cpp @@ -325,27 +325,27 @@ void TKqpCountersBase::ReportQueryWithFullScan() { } void TKqpCountersBase::ReportQueryAffectedShards(ui64 shardsCount) { - QueryAffectedShardsCount->Collect(shardsCount > Max() ? Max() : static_cast(shardsCount)); + QueryAffectedShardsCount->Collect(shardsCount); } void TKqpCountersBase::ReportQueryReadSets(ui64 readSetsCount) { - QueryReadSetsCount->Collect(readSetsCount > Max() ? Max() : static_cast(readSetsCount)); + QueryReadSetsCount->Collect(readSetsCount); } void TKqpCountersBase::ReportQueryReadBytes(ui64 bytesCount) { - QueryReadBytes->Collect(bytesCount > Max() ? Max() : static_cast(bytesCount)); + QueryReadBytes->Collect(bytesCount); } void TKqpCountersBase::ReportQueryReadRows(ui64 rowsCount) { - QueryReadRows->Collect(rowsCount > Max() ? Max() : static_cast(rowsCount)); + QueryReadRows->Collect(rowsCount); } void TKqpCountersBase::ReportQueryMaxShardReplySize(ui64 replySize) { - QueryMaxShardReplySize->Collect(replySize > Max() ? Max() : static_cast(replySize)); + QueryMaxShardReplySize->Collect(replySize); } void TKqpCountersBase::ReportQueryMaxShardProgramSize(ui64 programSize) { - QueryMaxShardProgramSize->Collect(programSize > Max() ? Max() : static_cast(programSize)); + QueryMaxShardProgramSize->Collect(programSize); } void TKqpCountersBase::ReportResponseStatus(ui64 responseSize, Ydb::StatusIds::StatusCode ydbStatus) { @@ -888,6 +888,14 @@ TKqpCounters::TKqpCounters(const ::NMonitoring::TDynamicCounterPtr& counters, co QueryStatMemFinishBytes = KqpGroup->GetCounter("Query/Stat/MemFinishBytes", true); QueryStatMemConvertBytes = KqpGroup->GetCounter("Query/Stat/MemConvertBytes", true); + /* Statistics batch operations */ + BatchOperationUpdateRows = KqpGroup->GetCounter("BatchOperation/Update/Rows", true); + BatchOperationUpdateBytes = KqpGroup->GetCounter("BatchOperation/Update/Bytes", true); + + BatchOperationDeleteRows = KqpGroup->GetCounter("BatchOperation/Delete/Rows", true); + BatchOperationDeleteBytes = KqpGroup->GetCounter("BatchOperation/Delete/Bytes", true); + + BatchOperationRetries = KqpGroup->GetCounter("BatchOperation/Retries", true); } ::NMonitoring::TDynamicCounterPtr TKqpCounters::GetKqpCounters() const { diff --git a/ydb/core/kqp/counters/kqp_counters.h b/ydb/core/kqp/counters/kqp_counters.h index e4c69f193503..ba88e8839d2b 100644 --- a/ydb/core/kqp/counters/kqp_counters.h +++ b/ydb/core/kqp/counters/kqp_counters.h @@ -479,6 +479,12 @@ class TKqpCounters : public TKqpCountersBase, public NYql::NDq::TSpillingCounter ::NMonitoring::TDynamicCounters::TCounterPtr QueryStatMemFinishBytes; ::NMonitoring::TDynamicCounters::TCounterPtr QueryStatMemConvertBytes; + // Statistics batch operations + ::NMonitoring::TDynamicCounters::TCounterPtr BatchOperationUpdateRows; + ::NMonitoring::TDynamicCounters::TCounterPtr BatchOperationUpdateBytes; + ::NMonitoring::TDynamicCounters::TCounterPtr BatchOperationDeleteRows; + ::NMonitoring::TDynamicCounters::TCounterPtr BatchOperationDeleteBytes; + ::NMonitoring::TDynamicCounters::TCounterPtr BatchOperationRetries; }; struct TKqpRequestCounters : public TThrRefBase { diff --git a/ydb/core/kqp/executer_actor/kqp_data_executer.cpp b/ydb/core/kqp/executer_actor/kqp_data_executer.cpp index 8937cd378bf7..3279c4015dde 100644 --- a/ydb/core/kqp/executer_actor/kqp_data_executer.cpp +++ b/ydb/core/kqp/executer_actor/kqp_data_executer.cpp @@ -104,10 +104,11 @@ class TKqpDataExecuter : public TKqpExecuterBase batchOperationSettings = Nothing()) : TBase(std::move(request), std::move(asyncIoFactory), federatedQuerySetup, GUCSettings, database, userToken, counters, tableServiceConfig, userRequestContext, statementResultIndex, TWilsonKqp::DataExecuter, - "DataExecuter", streamResult, bufferActorId, txManager) + "DataExecuter", streamResult, bufferActorId, txManager, std::move(batchOperationSettings)) , ShardIdToTableInfo(shardIdToTableInfo) , AllowOlapDataQuery(tableServiceConfig.GetAllowOlapDataQuery()) , WaitCAStatsTimeout(TDuration::MilliSeconds(tableServiceConfig.GetQueryLimits().GetWaitCAStatsTimeoutMs())) @@ -214,6 +215,16 @@ class TKqpDataExecuter : public TKqpExecuterBaseAddLock(lock.GetDataShard(), lock); } } + + if (info.HasBatchOperationMaxKey()) { + if (ResponseEv->BatchOperationMaxKeys.empty()) { + for (auto keyId : info.GetBatchOperationKeyIds()) { + ResponseEv->BatchOperationKeyIds.push_back(keyId); + } + } + + ResponseEv->BatchOperationMaxKeys.emplace_back(info.GetBatchOperationMaxKey()); + } } else if (data.GetData().template Is()) { NKikimrKqp::TEvKqpOutputActorResultInfo info; YQL_ENSURE(data.GetData().UnpackTo(&info), "Failed to unpack settings"); @@ -1626,7 +1637,7 @@ class TKqpDataExecuter : public TKqpExecuterBaseAsActorContext()); ResponseEv->Orbit.Fork(evData->Orbit); @@ -1878,7 +1889,7 @@ class TKqpDataExecuter : public TKqpExecuterBaseRecord.GetLocks().ShortDebugString(), + NDataIntegrity::LogIntegrityTrails("EvWriteTx", evWriteTransaction->Record.GetLocks().ShortDebugString(), Request.UserTraceId, TxId, shardId, TlsActivationContext->AsActorContext()); auto shardsToString = [](const auto& shards) { @@ -2101,6 +2112,10 @@ class TKqpDataExecuter : public TKqpExecuterBasePrepare(); + } + THashMap> datashardTasks; // shardId -> [task] THashMap> remoteComputeTasks; // shardId -> [task] TVector computeTasks; @@ -2162,6 +2177,7 @@ class TKqpDataExecuter : public TKqpExecuterBase& userRequestContext, ui32 statementResultIndex, const std::optional& federatedQuerySetup, const TGUCSettings::TPtr& GUCSettings, - const TShardIdToTableInfoPtr& shardIdToTableInfo, const IKqpTransactionManagerPtr& txManager, const TActorId bufferActorId) + const TShardIdToTableInfoPtr& shardIdToTableInfo, const IKqpTransactionManagerPtr& txManager, const TActorId bufferActorId, + TMaybe batchOperationSettings) { return new TKqpDataExecuter(std::move(request), database, userToken, counters, streamResult, tableServiceConfig, std::move(asyncIoFactory), creator, userRequestContext, statementResultIndex, federatedQuerySetup, GUCSettings, - shardIdToTableInfo, txManager, bufferActorId); + shardIdToTableInfo, txManager, bufferActorId, std::move(batchOperationSettings)); } } // namespace NKqp diff --git a/ydb/core/kqp/executer_actor/kqp_executer.h b/ydb/core/kqp/executer_actor/kqp_executer.h index 14714df5500a..dba5e00b92ae 100644 --- a/ydb/core/kqp/executer_actor/kqp_executer.h +++ b/ydb/core/kqp/executer_actor/kqp_executer.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -36,6 +37,9 @@ struct TEvKqpExecuter { THashSet ParticipantNodes; + TVector BatchOperationMaxKeys; + TVector BatchOperationKeyIds; + enum class EExecutionType { Data, Scan, @@ -105,6 +109,16 @@ struct TEvKqpExecuter { NYql::TIssues Issues; TDuration CpuTime; }; + + struct TEvTxDelayedExecution : public TEventLocal + { + TEvTxDelayedExecution(size_t partitionIdx) + : PartitionIdx(partitionIdx) + {} + + size_t PartitionIdx; + }; }; struct TKqpFederatedQuerySetup; @@ -115,7 +129,8 @@ IActor* CreateKqpExecuter(IKqpGateway::TExecPhysicalRequest&& request, const TSt NYql::NDq::IDqAsyncIoFactory::TPtr asyncIoFactory, TPreparedQueryHolder::TConstPtr preparedQuery, const TActorId& creator, const TIntrusivePtr& userRequestContext, ui32 statementResultIndex, const std::optional& federatedQuerySetup, const TGUCSettings::TPtr& GUCSettings, - const TShardIdToTableInfoPtr& shardIdToTableInfo, const IKqpTransactionManagerPtr& txManager, const TActorId bufferActorId); + const TShardIdToTableInfoPtr& shardIdToTableInfo, const IKqpTransactionManagerPtr& txManager, const TActorId bufferActorId, + TMaybe batchOperationSettings = Nothing()); IActor* CreateKqpSchemeExecuter( TKqpPhyTxHolder::TConstPtr phyTx, NKikimrKqp::EQueryType queryType, const TActorId& target, diff --git a/ydb/core/kqp/executer_actor/kqp_executer_impl.cpp b/ydb/core/kqp/executer_actor/kqp_executer_impl.cpp index 58f7d16aeab8..d042a193cc97 100644 --- a/ydb/core/kqp/executer_actor/kqp_executer_impl.cpp +++ b/ydb/core/kqp/executer_actor/kqp_executer_impl.cpp @@ -82,7 +82,8 @@ IActor* CreateKqpExecuter(IKqpGateway::TExecPhysicalRequest&& request, const TSt TPreparedQueryHolder::TConstPtr preparedQuery, const TActorId& creator, const TIntrusivePtr& userRequestContext, ui32 statementResultIndex, const std::optional& federatedQuerySetup, const TGUCSettings::TPtr& GUCSettings, - const TShardIdToTableInfoPtr& shardIdToTableInfo, const IKqpTransactionManagerPtr& txManager, const TActorId bufferActorId) + const TShardIdToTableInfoPtr& shardIdToTableInfo, const IKqpTransactionManagerPtr& txManager, const TActorId bufferActorId, + TMaybe batchOperationSettings) { if (request.Transactions.empty()) { // commit-only or rollback-only data transaction @@ -91,7 +92,7 @@ IActor* CreateKqpExecuter(IKqpGateway::TExecPhysicalRequest&& request, const TSt std::move(asyncIoFactory), creator, userRequestContext, statementResultIndex, federatedQuerySetup, /*GUCSettings*/nullptr, - shardIdToTableInfo, txManager, bufferActorId + shardIdToTableInfo, txManager, bufferActorId, std::move(batchOperationSettings) ); } @@ -115,7 +116,7 @@ IActor* CreateKqpExecuter(IKqpGateway::TExecPhysicalRequest&& request, const TSt std::move(asyncIoFactory), creator, userRequestContext, statementResultIndex, federatedQuerySetup, /*GUCSettings*/nullptr, - shardIdToTableInfo, txManager, bufferActorId + shardIdToTableInfo, txManager, bufferActorId, std::move(batchOperationSettings) ); case NKqpProto::TKqpPhyTx::TYPE_SCAN: @@ -131,7 +132,7 @@ IActor* CreateKqpExecuter(IKqpGateway::TExecPhysicalRequest&& request, const TSt tableServiceConfig, std::move(asyncIoFactory), creator, userRequestContext, statementResultIndex, federatedQuerySetup, GUCSettings, - shardIdToTableInfo, txManager, bufferActorId + shardIdToTableInfo, txManager, bufferActorId, std::move(batchOperationSettings) ); default: diff --git a/ydb/core/kqp/executer_actor/kqp_executer_impl.h b/ydb/core/kqp/executer_actor/kqp_executer_impl.h index 11e34f906a57..c8dbcb3f163c 100644 --- a/ydb/core/kqp/executer_actor/kqp_executer_impl.h +++ b/ydb/core/kqp/executer_actor/kqp_executer_impl.h @@ -139,7 +139,8 @@ class TKqpExecuterBase : public TActor { const TIntrusivePtr& userRequestContext, ui32 statementResultIndex, ui64 spanVerbosity = 0, TString spanName = "KqpExecuterBase", - bool streamResult = false, const TActorId bufferActorId = {}, const IKqpTransactionManagerPtr& txManager = nullptr) + bool streamResult = false, const TActorId bufferActorId = {}, const IKqpTransactionManagerPtr& txManager = nullptr, + TMaybe batchOperationSettings = Nothing()) : NActors::TActor(&TDerived::ReadyState) , Request(std::move(request)) , AsyncIoFactory(std::move(asyncIoFactory)) @@ -159,6 +160,7 @@ class TKqpExecuterBase : public TActor { , StatementResultIndex(statementResultIndex) , BlockTrackingMode(tableServiceConfig.GetBlockTrackingMode()) , VerboseMemoryLimitException(tableServiceConfig.GetResourceManager().GetVerboseMemoryLimitException()) + , BatchOperationSettings(std::move(batchOperationSettings)) { if (tableServiceConfig.HasArrayBufferMinFillPercentage()) { ArrayBufferMinFillPercentage = tableServiceConfig.GetArrayBufferMinFillPercentage(); @@ -430,6 +432,14 @@ class TKqpExecuterBase : public TActor { ui64 cycleCount = GetCycleCountFast(); Stats->UpdateTaskStats(taskId, state.GetStats(), (NYql::NDqProto::EComputeState) state.GetState()); + + if (Stats->DeadlockedStageId) { + NYql::TIssues issues; + issues.AddIssue(TStringBuilder() << "Deadlock detected: stage " << *Stats->DeadlockedStageId << " waits for input while peer(s) wait for output"); + auto abortEv = MakeHolder(NYql::NDqProto::StatusIds::CANCELLED, issues); + this->Send(this->SelfId(), abortEv.Release()); + } + if (Request.ProgressStatsPeriod) { auto now = TInstant::Now(); if (LastProgressStats + Request.ProgressStatsPeriod <= now) { @@ -914,7 +924,7 @@ class TKqpExecuterBase : public TActor { task.Meta.Type = TTaskMeta::TTaskType::Compute; FillSecureParamsFromStage(task.Meta.SecureParams, stage); - BuildSinks(stage, task); + BuildSinks(stage, stageInfo, task); LOG_D("Stage " << stageInfo.Id << " create sysview scan task: " << task.Id); } @@ -938,7 +948,7 @@ class TKqpExecuterBase : public TActor { output.SinkSettings = extSink.GetSettings(); } - void BuildInternalSinks(const NKqpProto::TKqpSink& sink, TKqpTasksGraph::TTaskType& task) { + void BuildInternalSinks(const NKqpProto::TKqpSink& sink, const TStageInfo& stageInfo, TKqpTasksGraph::TTaskType& task) { const auto& intSink = sink.GetInternalSink(); auto& output = task.Outputs[sink.GetOutputIndex()]; output.Type = TTaskOutputType::Sink; @@ -946,7 +956,12 @@ class TKqpExecuterBase : public TActor { if (intSink.GetSettings().Is()) { NKikimrKqp::TKqpTableSinkSettings settings; - YQL_ENSURE(intSink.GetSettings().UnpackTo(&settings), "Failed to unpack settings"); + if (!stageInfo.Meta.ResolvedSinkSettings) { + YQL_ENSURE(intSink.GetSettings().UnpackTo(&settings), "Failed to unpack settings"); + } else { + settings = *stageInfo.Meta.ResolvedSinkSettings; + } + auto& lockTxId = TasksGraph.GetMeta().LockTxId; if (lockTxId) { settings.SetLockTxId(*lockTxId); @@ -974,14 +989,14 @@ class TKqpExecuterBase : public TActor { } } - void BuildSinks(const NKqpProto::TKqpPhyStage& stage, TKqpTasksGraph::TTaskType& task) { + void BuildSinks(const NKqpProto::TKqpPhyStage& stage, const TStageInfo& stageInfo, TKqpTasksGraph::TTaskType& task) { if (stage.SinksSize() > 0) { YQL_ENSURE(stage.SinksSize() == 1, "multiple sinks are not supported"); const auto& sink = stage.GetSinks(0); YQL_ENSURE(sink.GetOutputIndex() < task.Outputs.size()); if (sink.HasInternalSink()) { - BuildInternalSinks(sink, task); + BuildInternalSinks(sink, stageInfo, task); } else if (sink.HasExternalSink()) { BuildExternalSinks(sink, task); } else { @@ -1062,7 +1077,7 @@ class TKqpExecuterBase : public TActor { // finish building for (auto taskId : tasksIds) { - BuildSinks(stage, TasksGraph.GetTask(taskId)); + BuildSinks(stage, stageInfo, TasksGraph.GetTask(taskId)); } } @@ -1171,6 +1186,7 @@ class TKqpExecuterBase : public TActor { auto columnType = NScheme::ProtoColumnTypeFromTypeInfoMod(column.Type, column.TypeMod); protoColumn->SetType(columnType.TypeId); protoColumn->SetNotNull(column.NotNull); + protoColumn->SetIsPrimary(column.IsPrimary); if (columnType.TypeInfo) { *protoColumn->MutableTypeInfo() = *columnType.TypeInfo; } @@ -1218,9 +1234,14 @@ class TKqpExecuterBase : public TActor { settings->SetShardIdHint(*shardId); } - ui64 itemsLimit = ExtractItemsLimit(stageInfo, source.GetItemsLimit(), Request.TxAlloc->HolderFactory, + if (!BatchOperationSettings.Empty()) { + settings->SetItemsLimit(BatchOperationSettings->MaxBatchSize); + settings->SetIsBatch(true); + } else { + ui64 itemsLimit = ExtractItemsLimit(stageInfo, source.GetItemsLimit(), Request.TxAlloc->HolderFactory, Request.TxAlloc->TypeEnv); - settings->SetItemsLimit(itemsLimit); + settings->SetItemsLimit(itemsLimit); + } auto self = static_cast(this)->SelfId(); auto& lockTxId = TasksGraph.GetMeta().LockTxId; @@ -1313,7 +1334,7 @@ class TKqpExecuterBase : public TActor { auto buildSinks = [&]() { for (const ui64 taskId : createdTasksIds) { - BuildSinks(stage, TasksGraph.GetTask(taskId)); + BuildSinks(stage, stageInfo, TasksGraph.GetTask(taskId)); } }; @@ -1434,7 +1455,7 @@ class TKqpExecuterBase : public TActor { task.Meta.Type = TTaskMeta::TTaskType::Compute; task.Meta.ExecuterId = SelfId(); FillSecureParamsFromStage(task.Meta.SecureParams, stage); - BuildSinks(stage, task); + BuildSinks(stage, stageInfo, task); LOG_D("Stage " << stageInfo.Id << " create compute task: " << task.Id); } } @@ -1713,7 +1734,7 @@ class TKqpExecuterBase : public TActor { auto& task = TasksGraph.GetTask(taskIdx); task.Meta.SetEnableShardsSequentialScan(readSettings.IsSorted()); PrepareScanMetaForUsage(task.Meta, keyTypes); - BuildSinks(stage, task); + BuildSinks(stage, stageInfo, task); } } @@ -1767,7 +1788,7 @@ class TKqpExecuterBase : public TActor { task.Meta.Type = TTaskMeta::TTaskType::Scan; task.SetMetaId(t); FillSecureParamsFromStage(task.Meta.SecureParams, stage); - BuildSinks(stage, task); + BuildSinks(stage, stageInfo, task); for (const auto& readInfo: *task.Meta.Reads) { Y_ENSURE(hashByShardId.contains(readInfo.ShardId)); @@ -1809,7 +1830,7 @@ class TKqpExecuterBase : public TActor { task.Meta.Type = TTaskMeta::TTaskType::Scan; task.SetMetaId(metaGlueingId); FillSecureParamsFromStage(task.Meta.SecureParams, stage); - BuildSinks(stage, task); + BuildSinks(stage, stageInfo, task); } } } @@ -2079,6 +2100,15 @@ class TKqpExecuterBase : public TActor { } } + if (!BatchOperationSettings.Empty() && !Stats->TableStats.empty()) { + auto [_, tableStats] = *Stats->TableStats.begin(); + Counters->Counters->BatchOperationUpdateRows->Add(tableStats->GetWriteRows()); + Counters->Counters->BatchOperationUpdateBytes->Add(tableStats->GetWriteBytes()); + + Counters->Counters->BatchOperationDeleteRows->Add(tableStats->GetEraseRows()); + Counters->Counters->BatchOperationDeleteBytes->Add(tableStats->GetEraseBytes()); + } + auto finishSize = Stats->EstimateFinishMem(); Counters->Counters->QueryStatMemFinishBytes->Add(finishSize); response.MutableResult()->MutableStats()->SetStatFinishBytes(finishSize); @@ -2237,6 +2267,8 @@ class TKqpExecuterBase : public TActor { ui64 StatCollectInflightBytes = 0; ui64 StatFinishInflightBytes = 0; + + TMaybe BatchOperationSettings; private: static constexpr TDuration ResourceUsageUpdateInterval = TDuration::MilliSeconds(100); }; @@ -2249,7 +2281,8 @@ IActor* CreateKqpDataExecuter(IKqpGateway::TExecPhysicalRequest&& request, const NYql::NDq::IDqAsyncIoFactory::TPtr asyncIoFactory, const TActorId& creator, const TIntrusivePtr& userRequestContext, ui32 statementResultIndex, const std::optional& federatedQuerySetup, const TGUCSettings::TPtr& GUCSettings, - const TShardIdToTableInfoPtr& shardIdToTableInfo, const IKqpTransactionManagerPtr& txManager, const TActorId bufferActorId); + const TShardIdToTableInfoPtr& shardIdToTableInfo, const IKqpTransactionManagerPtr& txManager, const TActorId bufferActorId, + TMaybe batchOperationSettings = Nothing()); IActor* CreateKqpScanExecuter(IKqpGateway::TExecPhysicalRequest&& request, const TString& database, const TIntrusiveConstPtr& userToken, TKqpRequestCounters::TPtr counters, diff --git a/ydb/core/kqp/executer_actor/kqp_executer_stats.cpp b/ydb/core/kqp/executer_actor/kqp_executer_stats.cpp index 1f0c7c3d124a..c35ca6182cfe 100644 --- a/ydb/core/kqp/executer_actor/kqp_executer_stats.cpp +++ b/ydb/core/kqp/executer_actor/kqp_executer_stats.cpp @@ -12,6 +12,33 @@ ui64 NonZeroMin(ui64 a, ui64 b) { return (b == 0) ? a : ((a == 0 || a > b) ? b : a); } +ui64 ExportMinStats(std::vector& data); +ui64 ExportMaxStats(std::vector& data); + +void TMinStats::Resize(ui32 count) { + Values.resize(count); +} + +void TMinStats::Set(ui32 index, ui64 value) { + AFL_ENSURE(index < Values.size()); + auto maybeMin = Values[index] == MinValue; + Values[index] = value; + if (maybeMin) { + MinValue = ExportMinStats(Values); + } +} + +void TMaxStats::Resize(ui32 count) { + Values.resize(count); +} + +void TMaxStats::Set(ui32 index, ui64 value) { + AFL_ENSURE(index < Values.size()); + auto isMonotonic = value >= Values[index]; + Values[index] = value; + MaxValue = isMonotonic ? (value > MaxValue ? value : MaxValue) : ExportMaxStats(Values); +} + void TTimeSeriesStats::ExportAggStats(NYql::NDqProto::TDqStatsAggr& stats) { NKikimr::NKqp::ExportAggStats(Values, stats); } @@ -38,7 +65,7 @@ void TTimeSeriesStats::Resize(ui32 count) { void TTimeSeriesStats::SetNonZero(ui32 index, ui64 value) { if (value) { - Y_ASSERT(index < Values.size()); + AFL_ENSURE(index < Values.size()); Sum += value; Sum -= Values[index]; Values[index] = value; @@ -123,12 +150,12 @@ void TPartitionedStats::ResizeByParts(ui32 partCount, ui32 taskCount) { void TPartitionedStats::SetNonZero(ui32 taskIndex, ui32 partIndex, ui64 value, bool recordTimeSeries) { if (value) { - Y_ASSERT(partIndex < Parts.size()); + AFL_ENSURE(partIndex < Parts.size()); auto& part = Parts[partIndex]; auto delta = value - part[taskIndex]; - Y_ASSERT(taskIndex < part.size()); + AFL_ENSURE(taskIndex < part.size()); part[taskIndex] = value; - Y_ASSERT(partIndex < Values.size()); + AFL_ENSURE(partIndex < Values.size()); Values[partIndex] += delta; Sum += delta; if (recordTimeSeries) { @@ -249,7 +276,7 @@ void TOperatorStats::Resize(ui32 taskCount) { void TStageExecutionStats::Resize(ui32 taskCount) { - Y_DEBUG_ABORT_UNLESS((taskCount & 3) == 0); + AFL_ENSURE((taskCount & 3) == 0); CpuTimeUs.Resize(taskCount); SourceCpuTimeUs.resize(taskCount); @@ -272,6 +299,8 @@ void TStageExecutionStats::Resize(ui32 taskCount) { WaitInputTimeUs.Resize(taskCount); WaitOutputTimeUs.Resize(taskCount); + CurrentWaitInputTimeUs.Resize(taskCount); + CurrentWaitOutputTimeUs.Resize(taskCount); SpillingComputeBytes.Resize(taskCount); SpillingChannelBytes.Resize(taskCount); @@ -365,7 +394,7 @@ inline void SetNonZero(ui64& target, ui64 source) { } inline void SetNonZero(std::vector& vector, ui32 index, ui64 value) { - Y_ASSERT(index < vector.size()); + AFL_ENSURE(index < vector.size()); SetNonZero(vector[index], value); } @@ -397,7 +426,7 @@ ui64 TStageExecutionStats::UpdateAsyncStats(ui32 index, TAsyncStats& aggrAsyncSt aggrAsyncStats.WaitTimeUs.SetNonZero(index, asyncStats.GetWaitTimeUs()); SetNonZero(aggrAsyncStats.WaitPeriods, index, asyncStats.GetWaitPeriods()); if (firstMessageMs && lastMessageMs > firstMessageMs) { - Y_ASSERT(index < aggrAsyncStats.ActiveTimeUs.size()); + AFL_ENSURE(index < aggrAsyncStats.ActiveTimeUs.size()); aggrAsyncStats.ActiveTimeUs[index] = lastMessageMs - firstMessageMs; } @@ -409,7 +438,7 @@ ui64 TStageExecutionStats::UpdateStats(const NYql::NDqProto::TDqTaskStats& taskS auto it = Task2Index.find(taskId); ui64 baseTimeMs = 0; - Y_DEBUG_ABORT_UNLESS(TaskCount >= Task2Index.size()); + AFL_ENSURE(TaskCount >= Task2Index.size()); ui32 index; if (it == Task2Index.end()) { @@ -456,6 +485,12 @@ ui64 TStageExecutionStats::UpdateStats(const NYql::NDqProto::TDqTaskStats& taskS SetNonZero(DurationUs, index, durationUs); WaitInputTimeUs.SetNonZero(index, taskStats.GetWaitInputTimeUs()); WaitOutputTimeUs.SetNonZero(index, taskStats.GetWaitOutputTimeUs()); + CurrentWaitInputTimeUs.Set(index, taskStats.GetCurrentWaitInputTimeUs()); + CurrentWaitOutputTimeUs.Set(index, taskStats.GetCurrentWaitOutputTimeUs()); + + auto updateTimeMs = taskStats.GetUpdateTimeMs(); + UpdateTimeMs = std::max(UpdateTimeMs, updateTimeMs); + baseTimeMs = NonZeroMin(baseTimeMs, updateTimeMs); SpillingComputeBytes.SetNonZero(index, taskStats.GetSpillingComputeWriteBytes()); SpillingChannelBytes.SetNonZero(index, taskStats.GetSpillingChannelWriteBytes()); @@ -572,6 +607,23 @@ ui64 TStageExecutionStats::UpdateStats(const NYql::NDqProto::TDqTaskStats& taskS return baseTimeMs; } +bool TStageExecutionStats::IsDeadlocked(ui64 deadline) { + if (CurrentWaitInputTimeUs.MinValue < deadline || InputStages.empty()) { + return false; + } + + for (auto stat : InputStages) { + if (stat->CurrentWaitOutputTimeUs.MinValue < deadline || stat->IsFinished()) { + return false; + } + } + return true; +} + +bool TStageExecutionStats::IsFinished() { + return FinishedCount == Task2Index.size(); +} + namespace { TTableStat operator - (const TTableStat& l, const TTableStat& r) { @@ -739,6 +791,37 @@ bool CollectProfileStats(Ydb::Table::QueryStatsCollection::Mode statsMode) { return statsMode >= Ydb::Table::QueryStatsCollection::STATS_COLLECTION_PROFILE; } +void TQueryExecutionStats::Prepare() { + if (CollectFullStats(StatsMode)) { + // stages + for (auto& [stageId, info] : TasksGraph->GetStagesInfo()) { + auto [it, inserted] = StageStats.try_emplace(stageId); + Y_ENSURE(inserted); + it->second.StageId = stageId; + } + // connections + for (auto& [_, stageStats] : StageStats) { + auto& info = TasksGraph->GetStageInfo(stageStats.StageId); + auto& stage = info.Meta.GetStage(info.Id); + for (const auto& input : stage.GetInputs()) { + auto& peerStageStats = StageStats[NYql::NDq::TStageId(stageStats.StageId.TxId, input.GetStageIndex())]; + stageStats.InputStages.push_back(&peerStageStats); + peerStageStats.OutputStages.push_back(&stageStats); + } + } + // tasks + for (auto& task : TasksGraph->GetTasks()) { + auto& stageStats = StageStats[task.StageId]; + stageStats.Task2Index.emplace(task.Id, stageStats.Task2Index.size()); + } + for (auto& [_, stageStats] : StageStats) { + stageStats.TaskCount = (stageStats.Task2Index.size() + 3) & ~3; + stageStats.Resize(stageStats.TaskCount); + } + } +} + + void TQueryExecutionStats::FillStageDurationUs(NYql::NDqProto::TDqStageStats& stats) { if (stats.HasStartTimeMs() && stats.HasFinishTimeMs()) { auto startTimeMs = stats.GetStartTimeMs().GetMin(); @@ -799,6 +882,10 @@ void TQueryExecutionStats::AddComputeActorFullStatsByTask( UpdateAggr(stageStats->MutableWaitInputTimeUs(), task.GetWaitInputTimeUs()); UpdateAggr(stageStats->MutableWaitOutputTimeUs(), task.GetWaitOutputTimeUs()); + auto updateTimeMs = task.GetUpdateTimeMs(); + stageStats->SetUpdateTimeMs(std::max(stageStats->GetUpdateTimeMs(), updateTimeMs)); + BaseTimeMs = NonZeroMin(BaseTimeMs, updateTimeMs); + UpdateAggr(stageStats->MutableSpillingComputeBytes(), task.GetSpillingComputeWriteBytes()); UpdateAggr(stageStats->MutableSpillingChannelBytes(), task.GetSpillingChannelWriteBytes()); UpdateAggr(stageStats->MutableSpillingComputeTimeUs(), task.GetSpillingComputeReadTimeUs() + task.GetSpillingComputeWriteTimeUs()); @@ -1162,23 +1249,73 @@ void TQueryExecutionStats::AddBufferStats(NYql::NDqProto::TDqTaskStats&& taskSta } void TQueryExecutionStats::UpdateTaskStats(ui64 taskId, const NYql::NDqProto::TDqComputeActorStats& stats, NYql::NDqProto::EComputeState state) { - Y_ASSERT(stats.GetTasks().size() == 1); + AFL_ENSURE(stats.GetTasks().size() == 1); const NYql::NDqProto::TDqTaskStats& taskStats = stats.GetTasks(0); - Y_ASSERT(taskStats.GetTaskId() == taskId); - auto stageId = taskStats.GetStageId(); + AFL_ENSURE(taskStats.GetTaskId() == taskId); + auto stageId = TasksGraph->GetTask(taskId).StageId; auto [it, inserted] = StageStats.try_emplace(stageId); if (inserted) { - it->second.StageId = TasksGraph->GetTask(taskStats.GetTaskId()).StageId; + it->second.StageId = stageId; it->second.SetHistorySampleCount(HistorySampleCount); } BaseTimeMs = NonZeroMin(BaseTimeMs, it->second.UpdateStats(taskStats, state, stats.GetMaxMemoryUsage(), stats.GetDurationUs())); + + constexpr ui64 deadline = 600'000'000; // 10m + if (it->second.CurrentWaitOutputTimeUs.MinValue > deadline) { + for (auto stat : it->second.OutputStages) { + if (stat->IsDeadlocked(deadline)) { + DeadlockedStageId = stat->StageId.StageId; + break; + } + } + } else if (it->second.IsDeadlocked(deadline)) { + DeadlockedStageId = it->second.StageId.StageId; + } } // SIMD-friendly aggregations are below. Compiler is able to vectorize sum/count, but needs help with min/max +ui64 ExportMinStats(std::vector& data) { + + AFL_ENSURE((data.size() & 3) == 0); + + ui64 min4[4] = {0, 0, 0, 0}; + + for (auto it = data.begin(); it < data.end(); it += 4) { + min4[0] = min4[0] ? (it[0] ? (min4[0] < it[0] ? min4[0] : it[0]) : min4[0]) : it[0]; + min4[1] = min4[1] ? (it[1] ? (min4[1] < it[1] ? min4[1] : it[1]) : min4[1]) : it[1]; + min4[2] = min4[2] ? (it[2] ? (min4[2] < it[2] ? min4[2] : it[2]) : min4[2]) : it[2]; + min4[3] = min4[3] ? (it[3] ? (min4[3] < it[3] ? min4[3] : it[3]) : min4[3]) : it[3]; + } + + ui64 min01 = min4[0] ? (min4[1] ? (min4[0] < min4[1] ? min4[0] : min4[1]) : min4[0]) : min4[1]; + ui64 min23 = min4[2] ? (min4[3] ? (min4[2] < min4[3] ? min4[2] : min4[3]) : min4[2]) : min4[3]; + + return min01 ? (min23 ? (min01 < min23 ? min01 : min23) : min01) : min23; +} + +ui64 ExportMaxStats(std::vector& data) { + + AFL_ENSURE((data.size() & 3) == 0); + + ui64 max4[4] = {0, 0, 0, 0}; + + for (auto it = data.begin(); it < data.end(); it += 4) { + max4[0] = max4[0] > it[0] ? max4[0] : it[0]; + max4[1] = max4[1] > it[1] ? max4[1] : it[1]; + max4[2] = max4[2] > it[2] ? max4[2] : it[2]; + max4[3] = max4[3] > it[3] ? max4[3] : it[3]; + } + + ui64 max01 = max4[0] > max4[1] ? max4[0] : max4[1]; + ui64 max23 = max4[2] > max4[3] ? max4[2] : max4[3]; + + return max01 > max23 ? max01 : max23; +} + void ExportAggStats(std::vector& data, NYql::NDqProto::TDqStatsMinMax& stats) { - Y_DEBUG_ABORT_UNLESS((data.size() & 3) == 0); + AFL_ENSURE((data.size() & 3) == 0); ui64 count = 0; ui64 min4[4] = {0, 0, 0, 0}; @@ -1211,7 +1348,7 @@ void ExportAggStats(std::vector& data, NYql::NDqProto::TDqStatsMinMax& sta void ExportOffsetAggStats(std::vector& data, NYql::NDqProto::TDqStatsAggr& stats, ui64 offset) { - Y_DEBUG_ABORT_UNLESS((data.size() & 3) == 0); + AFL_ENSURE((data.size() & 3) == 0); ui64 count = 0; ui64 sum = 0; @@ -1256,7 +1393,7 @@ void ExportOffsetAggStats(std::vector& data, NYql::NDqProto::TDqStatsAggr& void ExportAggStats(std::vector& data, NYql::NDqProto::TDqStatsAggr& stats) { - Y_DEBUG_ABORT_UNLESS((data.size() & 3) == 0); + AFL_ENSURE((data.size() & 3) == 0); ui64 count = 0; ui64 sum = 0; @@ -1389,6 +1526,7 @@ void TQueryExecutionStats::ExportExecStats(NYql::NDqProto::TDqExecutionStats& st ExportAggStats(stageStat.DurationUs, *stageStats.MutableDurationUs()); stageStat.WaitInputTimeUs.ExportAggStats(BaseTimeMs, *stageStats.MutableWaitInputTimeUs()); stageStat.WaitOutputTimeUs.ExportAggStats(BaseTimeMs, *stageStats.MutableWaitOutputTimeUs()); + stageStats.SetUpdateTimeMs(stageStat.UpdateTimeMs > BaseTimeMs ? stageStat.UpdateTimeMs - BaseTimeMs : 0); stageStat.SpillingComputeBytes.ExportAggStats(BaseTimeMs, *stageStats.MutableSpillingComputeBytes()); stageStat.SpillingChannelBytes.ExportAggStats(BaseTimeMs, *stageStats.MutableSpillingChannelBytes()); @@ -1519,6 +1657,8 @@ void TQueryExecutionStats::AdjustBaseTime(NDqProto::TDqStageStats* stageStats) { for (auto& p : *stageStats->MutableEgress()) { AdjustAsyncBufferAggr(p.second); } + auto updateTimeMs = stageStats->GetUpdateTimeMs(); + stageStats->SetUpdateTimeMs(updateTimeMs > BaseTimeMs ? updateTimeMs - BaseTimeMs : 0); } void TQueryExecutionStats::Finish() { @@ -1562,7 +1702,7 @@ void TQueryExecutionStats::Finish() { } AdjustBaseTime(stageStats); - auto it = StageStats.find(stageId.StageId); + auto it = StageStats.find(stageId); if (it != StageStats.end()) { it->second.ExportHistory(BaseTimeMs, *stageStats); } diff --git a/ydb/core/kqp/executer_actor/kqp_executer_stats.h b/ydb/core/kqp/executer_actor/kqp_executer_stats.h index 9c8b7b7cf248..5dab7256d048 100644 --- a/ydb/core/kqp/executer_actor/kqp_executer_stats.h +++ b/ydb/core/kqp/executer_actor/kqp_executer_stats.h @@ -16,6 +16,22 @@ NYql::NDqProto::EDqStatsMode GetDqStatsModeShard(Ydb::Table::QueryStatsCollectio bool CollectFullStats(Ydb::Table::QueryStatsCollection::Mode statsMode); bool CollectProfileStats(Ydb::Table::QueryStatsCollection::Mode statsMode); +struct TMinStats { + std::vector Values; + ui64 MinValue = 0; + + void Resize(ui32 count); + void Set(ui32 index, ui64 value); +}; + +struct TMaxStats { + std::vector Values; + ui64 MaxValue = 0; + + void Resize(ui32 count); + void Set(ui32 index, ui64 value); +}; + struct TTimeSeriesStats { std::vector Values; ui32 HistorySampleCount = 0; @@ -200,6 +216,9 @@ struct TStageExecutionStats { std::vector DurationUs; TTimeSeriesStats WaitInputTimeUs; TTimeSeriesStats WaitOutputTimeUs; + TMinStats CurrentWaitInputTimeUs; + TMinStats CurrentWaitOutputTimeUs; + ui64 UpdateTimeMs = 0; TTimeSeriesStats SpillingComputeBytes; TTimeSeriesStats SpillingChannelBytes; @@ -219,9 +238,11 @@ struct TStageExecutionStats { TTimeSeriesStats MaxMemoryUsage; ui32 HistorySampleCount = 0; - ui32 TaskCount = 0; + ui32 TaskCount = 0; // rounded to 4 value of Task2Index.size(), which is actual std::vector Finished; ui32 FinishedCount = 0; + std::vector InputStages; + std::vector OutputStages; void Resize(ui32 taskCount); ui32 EstimateMem() { @@ -235,6 +256,8 @@ struct TStageExecutionStats { void ExportHistory(ui64 baseTimeMs, NYql::NDqProto::TDqStageStats& stageStats); ui64 UpdateAsyncStats(ui32 index, TAsyncStats& aggrAsyncStats, const NYql::NDqProto::TDqAsyncBufferStats& asyncStats); ui64 UpdateStats(const NYql::NDqProto::TDqTaskStats& taskStats, NYql::NDqProto::EComputeState state, ui64 maxMemoryUsage, ui64 durationUs); + bool IsDeadlocked(ui64 deadline); + bool IsFinished(); }; struct TExternalPartitionStat { @@ -257,12 +280,12 @@ struct TIngressExternalPartitionStat { struct TQueryExecutionStats { private: - std::map> ShardsCountByNode; - std::map UseLlvmByStageId; - std::map StageStats; - std::map ExternalPartitionStats; // FIXME: several ingresses + std::unordered_map> ShardsCountByNode; + std::unordered_map UseLlvmByStageId; + THashMap StageStats; + std::unordered_map ExternalPartitionStats; // FIXME: several ingresses ui64 BaseTimeMs = 0; - std::map LongestTaskDurations; + std::unordered_map LongestTaskDurations; void ExportAggAsyncStats(TAsyncStats& data, NYql::NDqProto::TDqAsyncStatsAggr& stats); void ExportAggAsyncBufferStats(TAsyncBufferStats& data, NYql::NDqProto::TDqAsyncBufferStatsAggr& stats); void AdjustExternalAggr(NYql::NDqProto::TDqExternalAggrStats& stats); @@ -274,6 +297,7 @@ struct TQueryExecutionStats { const Ydb::Table::QueryStatsCollection::Mode StatsMode; const TKqpTasksGraph* const TasksGraph = nullptr; NYql::NDqProto::TDqExecutionStats* const Result; + std::optional DeadlockedStageId; // basic stats std::unordered_set AffectedShards; @@ -307,6 +331,8 @@ struct TQueryExecutionStats { HistorySampleCount = 32; } + void Prepare(); + void AddComputeActorStats( ui32 nodeId, NYql::NDqProto::TDqComputeActorStats&& stats, diff --git a/ydb/core/kqp/executer_actor/kqp_partitioned_executer.cpp b/ydb/core/kqp/executer_actor/kqp_partitioned_executer.cpp index dc7ca246c230..6ad7df477403 100644 --- a/ydb/core/kqp/executer_actor/kqp_partitioned_executer.cpp +++ b/ydb/core/kqp/executer_actor/kqp_partitioned_executer.cpp @@ -1,227 +1,180 @@ #include "kqp_partitioned_executer.h" -#include "kqp_executer_impl.h" +#include "kqp_executer.h" -#include #include -#include +#include +#include +#include #include #include #include +#include #include +#include #include -#include +#include #include +#include namespace NKikimr { namespace NKqp { namespace { -template -bool FillParamValue(TQueryData::TPtr queryData, const TString& name, T value) { - auto type = queryData->GetParameterType(name); - return queryData->AddUVParam(name, type, NUdf::TUnboxedValuePod(value)); -} +#define PE_LOG_C(msg) LOG_CRIT_S(*TlsActivationContext, NKikimrServices::KQP_EXECUTER, LogPrefix() << msg) +#define PE_LOG_E(msg) LOG_ERROR_S(*TlsActivationContext, NKikimrServices::KQP_EXECUTER, LogPrefix() << msg) +#define PE_LOG_W(msg) LOG_WARN_S(*TlsActivationContext, NKikimrServices::KQP_EXECUTER, LogPrefix() << msg) +#define PE_LOG_N(msg) LOG_NOTICE_S(*TlsActivationContext, NKikimrServices::KQP_EXECUTER, LogPrefix() << msg) +#define PE_LOG_I(msg) LOG_INFO_S(*TlsActivationContext, NKikimrServices::KQP_EXECUTER, LogPrefix() << msg) +#define PE_LOG_D(msg) LOG_DEBUG_S(*TlsActivationContext, NKikimrServices::KQP_EXECUTER, LogPrefix() << msg) +#define PE_LOG_T(msg) LOG_TRACE_S(*TlsActivationContext, NKikimrServices::KQP_EXECUTER, LogPrefix() << msg) + +/* + TKqpPartitionedExecuter only executes BATCH UPDATE/DELETE queries + with idempotent set of updates (except primary key), without RETURNING + and without any joins or subqueries. + + Examples: ydb/core/kqp/ut/batch_operations +*/ class TKqpPartitionedExecuter : public TActorBootstrapped { - enum class EExecuterResponse { - NONE, - SUCCESS, - ERROR + using TPartitionIndex = size_t; + + struct TBatchPartitionInfo { + TMaybe BeginRange; + TMaybe EndRange; + TPartitionIndex PartitionIndex; + + TActorId ExecuterId; + TActorId BufferId; + + ui64 LimitSize; + ui64 RetryDelayMs; + + using TPtr = std::shared_ptr; }; public: + static constexpr char ActorName[] = "KQP_PARTITIONED_EXECUTER"; + static constexpr NKikimrServices::TActivity::EType ActorActivityType() { return NKikimrServices::TActivity::KQP_EXECUTER_ACTOR; } - TKqpPartitionedExecuter( - IKqpGateway::TExecPhysicalRequest&& request, - const TActorId sessionActorId, const TString& database, - const TIntrusiveConstPtr& userToken, - const TIntrusivePtr& counters, - TKqpRequestCounters::TPtr requestCounters, - const NKikimrConfig::TTableServiceConfig& tableServiceConfig, - NYql::NDq::IDqAsyncIoFactory::TPtr asyncIoFactory, - TPreparedQueryHolder::TConstPtr preparedQuery, - const TIntrusivePtr& userRequestContext, - ui32 statementResultIndex, const std::optional& federatedQuerySetup, - const TGUCSettings::TPtr& GUCSettings, - const TShardIdToTableInfoPtr& shardIdToTableInfo) - : Request(std::move(request)) - , SessionActorId(sessionActorId) - , Database(database) - , UserToken(userToken) - , Counters(counters) - , RequestCounters(requestCounters) - , TableServiceConfig(tableServiceConfig) - , UserRequestContext(userRequestContext) - , StatementResultIndex(statementResultIndex) - , AsyncIoFactory(std::move(asyncIoFactory)) - , PreparedQuery(preparedQuery) - , FederatedQuerySetup(federatedQuerySetup) - , GUCSettings(GUCSettings) - , ShardIdToTableInfo(shardIdToTableInfo) + explicit TKqpPartitionedExecuter(TKqpPartitionedExecuterSettings settings) + : LiteralRequest(std::move(settings.LiteralRequest)) + , PhysicalRequest(std::move(settings.PhysicalRequest)) + , SessionActorId(std::move(settings.SessionActorId)) + , FuncRegistry(std::move(settings.FuncRegistry)) + , TimeProvider(std::move(settings.TimeProvider)) + , RandomProvider(std::move(settings.RandomProvider)) + , Database(std::move(settings.Database)) + , UserToken(std::move(settings.UserToken)) + , RequestCounters(std::move(settings.RequestCounters)) + , TableServiceConfig(std::move(settings.TableServiceConfig)) + , UserRequestContext(std::move(settings.UserRequestContext)) + , StatementResultIndex(std::move(settings.StatementResultIndex)) + , AsyncIoFactory(std::move(std::move(settings.AsyncIoFactory))) + , PreparedQuery(std::move(settings.PreparedQuery)) + , FederatedQuerySetup(std::move(settings.FederatedQuerySetup)) + , GUCSettings(std::move(settings.GUCSettings)) + , ShardIdToTableInfo(std::move(settings.ShardIdToTableInfo)) + , WriteBufferInitialMemoryLimit(std::move(settings.WriteBufferInitialMemoryLimit)) + , WriteBufferMemoryLimit(std::move(settings.WriteBufferMemoryLimit)) { - YQL_ENSURE(Request.LocksOp != ELocksOp::Rollback); - YQL_ENSURE(Request.Transactions.size() == 1); - - ResponseEv = std::make_unique(Request.TxAlloc, + UseLiteral = PreparedQuery->GetTransactions().size() == 2; + ResponseEv = std::make_unique(PhysicalRequest.TxAlloc, TEvKqpExecuter::TEvTxResponse::EExecutionType::Data); - for (const auto& tx : Request.Transactions) { - YQL_ENSURE(tx.Body->StagesSize() > 0); - - for (const auto& stage : tx.Body->GetStages()) { - if (stage.SinksSize() != 1) { - continue; - } - - for (auto& sink : stage.GetSinks()) { + for (const auto& tx : PreparedQuery->GetTransactions()) { + for (const auto& stage : tx->GetStages()) { + for (const auto& sink : stage.GetSinks()) { FillTableMetaInfo(sink); + + if (!KeyColumnInfo.empty()) { + break; + } } } } - } - void Bootstrap() { - YQL_ENSURE(!KeyColumnTypes.empty()); - - const TVector minKey(KeyColumnTypes.size()); - const TTableRange range(minKey, true, {}, false, false); - YQL_ENSURE(range.IsFullRange(KeyColumnTypes.size())); - auto keyRange = MakeHolder( - TableId, - range, - TKeyDesc::ERowOperation::Update, - KeyColumnTypes, - TVector{}); + if (TableServiceConfig.HasBatchOperationSettings()) { + BatchOperationSettings = SetBatchOperationSettings(TableServiceConfig.GetBatchOperationSettings()); + } - TAutoPtr request(new NSchemeCache::TSchemeCacheRequest()); - request->ResultSet.emplace_back(std::move(keyRange)); + PE_LOG_I("Created " << ActorName << " with MaxBatchSize = " << BatchOperationSettings.MaxBatchSize + << ", PartitionExecutionLimit = " << BatchOperationSettings.PartitionExecutionLimit); + } - TAutoPtr resolveReq(new TEvTxProxySchemeCache::TEvResolveKeySet(request)); - Send(MakeSchemeCacheID(), resolveReq.Release()); + void Bootstrap() { + SendRequestGetPartitions(); Become(&TKqpPartitionedExecuter::PrepareState); } - static constexpr char ActorName[] = "KQP_PARTITIONED_EXECUTER"; - STFUNC(PrepareState) { try { switch (ev->GetTypeRewrite()) { - hFunc(TEvTxProxySchemeCache::TEvResolveKeySetResult, Handle); - hFunc(TEvKqp::TEvAbortExecution, HandleAbort); + hFunc(TEvTxProxySchemeCache::TEvResolveKeySetResult, HandlePrepare); + hFunc(TEvKqp::TEvAbortExecution, HandlePrepare); default: AFL_ENSURE(false)("unknown message", ev->GetTypeRewrite()); } } catch (...) { RuntimeError( Ydb::StatusIds::INTERNAL_ERROR, - NYql::TIssues({NYql::TIssue("RuntimeError: PrepareState.")})); + NYql::TIssues({NYql::TIssue(TStringBuilder() + << "from state handler = " << CurrentStateFuncName())})); } } - void Handle(TEvTxProxySchemeCache::TEvResolveKeySetResult::TPtr& ev) { + void HandlePrepare(TEvTxProxySchemeCache::TEvResolveKeySetResult::TPtr& ev) { auto* request = ev->Get()->Request.Get(); + PE_LOG_D("Got TEvTxProxySchemeCache::TEvResolveKeySetResult from ActorId = " << ev->Sender); + if (request->ErrorCount > 0) { - CA_LOG_E(TStringBuilder() << "Failed to get table: " - << TableId << "'"); - return; + return RuntimeError( + Ydb::StatusIds::INTERNAL_ERROR, + NYql::TIssues({NYql::TIssue(TStringBuilder() << CurrentStateFuncName() + << ", failed to get table")})); } YQL_ENSURE(request->ResultSet.size() == 1); - Partitioning = std::move(request->ResultSet[0].KeyDescription->Partitioning); - CreateExecuters(); + FillTablePartitioning(request->ResultSet[0].KeyDescription->Partitioning); + CreateExecutersWithBuffers(); } - void HandleAbort(TEvKqp::TEvAbortExecution::TPtr& ev) { + void HandlePrepare(TEvKqp::TEvAbortExecution::TPtr& ev) { auto& msg = ev->Get()->Record; auto issues = ev->Get()->GetIssues(); - LOG_D("Got EvAbortExecution from ActorId = " << ev->Sender - << " , abort child executers, status: " - << NYql::NDqProto::StatusIds_StatusCode_Name(msg.GetStatusCode()) - << ", message: " << issues.ToOneLineString()); - - if (auto idx = GetExecuterIdx(ev->Sender); idx != Executers.size()) { - ExecutersResponses[idx] = EExecuterResponse::ERROR; - } + auto it = ExecuterToPartition.find(ev->Sender); + if (it != ExecuterToPartition.end()) { + PE_LOG_D("Got TEvKqp::EvAbortExecution from ActorId = " << ev->Sender + << " , status: " << NYql::NDqProto::StatusIds_StatusCode_Name(msg.GetStatusCode()) + << ", message: " << issues.ToOneLineString() << ", abort child executers"); - Abort(); - } + ReturnIssues = issues; + ReturnIssues.AddIssue(YqlIssue(NYql::TPosition(), NYql::TIssuesIds::KIKIMR_INTERNAL_ERROR, + TStringBuilder() << "from PartitionedExecuterActor, state = " << CurrentStateFuncName())); - void CreateExecuters() { - Executers.resize(Partitioning->size()); - BufferActors.resize(Partitioning->size()); - ExecutersResponses.resize(Partitioning->size(), EExecuterResponse::NONE); - - for (size_t i = 0; i < Partitioning->size(); ++i) { - CreateExecuterWithBuffer(i, /*isRetry*/ false); + auto [_, partInfo] = *it; + AbortBuffer(partInfo->ExecuterId); + ForgetExecuterAndBuffer(partInfo); + ForgetPartition(partInfo); } - Become(&TKqpPartitionedExecuter::ExecuteState); - } - - void CreateExecuterWithBuffer(size_t partitionIdx, bool isRetry) { - IKqpGateway::TExecPhysicalRequest newRequest(Request.TxAlloc); - FillRequestWithParams(newRequest, partitionIdx); - - auto txManager = CreateKqpTransactionManager(); - - TKqpBufferWriterSettings settings { - .SessionActorId = SelfId(), - .TxManager = txManager, - .TraceId = Request.TraceId.GetTraceId(), - .Counters = Counters, - .TxProxyMon = RequestCounters->TxProxyMon, - }; - auto* bufferActor = CreateKqpBufferWriterActor(std::move(settings)); - auto bufferActorId = RegisterWithSameMailbox(bufferActor); - BufferActors[partitionIdx] = bufferActorId; - - auto executerActor = CreateKqpExecuter(std::move(newRequest), Database, UserToken, RequestCounters, - TableServiceConfig, AsyncIoFactory, PreparedQuery, SelfId(), UserRequestContext, StatementResultIndex, - FederatedQuerySetup, GUCSettings, ShardIdToTableInfo, txManager, bufferActorId); - - auto exId = RegisterWithSameMailbox(executerActor); - Executers[partitionIdx] = exId; - - LOG_D("Created new KQP executer from Partitioned: " << exId << ", isRetry = " - << isRetry << ", partitionIdx = " << partitionIdx); - - auto ev = std::make_unique(exId); - Send(MakeTxProxyID(), ev.release()); - } - - void Abort() { - SendAbortToActors(); - Become(&TKqpPartitionedExecuter::AbortState); - } - - void SendAbortToActors() { - for (size_t i = 0; i < Executers.size(); ++i) { - if (ExecutersResponses[i] == EExecuterResponse::SUCCESS) { - ExecutersResponses[i] = EExecuterResponse::NONE; - } - - if (ExecutersResponses[i] != EExecuterResponse::ERROR) { - auto abortEv = TEvKqp::TEvAbortExecution::Aborted("Aborted by Partitioned Executer"); - Send(Executers[i], abortEv.Release()); - } - - Send(BufferActors[i], new TEvKqpBuffer::TEvTerminate{}); - } + Abort(); } STFUNC(ExecuteState) { try { switch (ev->GetTypeRewrite()) { hFunc(TEvKqpExecuter::TEvTxResponse, HandleExecute); - hFunc(TEvKqp::TEvAbortExecution, HandleAbort); + hFunc(TEvKqpExecuter::TEvTxDelayedExecution, HandleExecute) + hFunc(TEvKqp::TEvAbortExecution, HandlePrepare); hFunc(TEvKqpBuffer::TEvError, HandleExecute); default: AFL_ENSURE(false)("unknown message", ev->GetTypeRewrite()); @@ -229,253 +182,712 @@ class TKqpPartitionedExecuter : public TActorBootstrappedGetIssues(), ReturnIssues); } - } - void OnSuccessResponse(size_t exId) { - if (exId == Executers.size()) { - return; - } + ForgetPartition(partInfo); - ExecutersResponses[exId] = EExecuterResponse::SUCCESS; - if (!CheckExecutersAreSuccess()) { - return; - } + ReturnIssues.AddIssue(YqlIssue(NYql::TPosition(), NYql::TIssuesIds::KIKIMR_INTERNAL_ERROR, + TStringBuilder() << "from PartitionedExecuterActor, state = " << CurrentStateFuncName())); - for (size_t i = 0; i < BufferActors.size(); ++i) { - Send(BufferActors[i], new TEvKqpBuffer::TEvTerminate{}); - } + RuntimeError(response->GetStatus(), ReturnIssues); + } - auto& response = *ResponseEv->Record.MutableResponse(); - response.SetStatus(Ydb::StatusIds::SUCCESS); + void HandleExecute(TEvKqpExecuter::TEvTxDelayedExecution::TPtr& ev) { + RequestCounters->Counters->BatchOperationRetries->Inc(); - Send(SessionActorId, ResponseEv.release()); - PassAway(); + auto& partInfo = StartedPartitions[ev->Get()->PartitionIdx]; + RetryPartExecution(partInfo); } void HandleExecute(TEvKqpBuffer::TEvError::TPtr& ev) { const auto& msg = *ev->Get(); - LOG_D("Got TEvError from ActorId = " << ev->Sender << ", status = " + + auto it = BufferToPartition.find(ev->Sender); + if (it == BufferToPartition.end()) { + PE_LOG_D("Got TEvKqpBuffer::TEvError from unknown actor with Id = " << ev->Sender << ", status = " + << NYql::NDqProto::StatusIds_StatusCode_Name(msg.StatusCode) << ", ignore"); + return; + } + + PE_LOG_D("Got TEvKqpBuffer::TEvError from ActorId = " << ev->Sender << ", status = " << NYql::NDqProto::StatusIds_StatusCode_Name(msg.StatusCode)); + auto [_, partInfo] = *it; + AbortExecuter(partInfo->ExecuterId, "got error from BufferWriteActor"); + ForgetExecuterAndBuffer(partInfo); + switch (msg.StatusCode) { case NYql::NDqProto::StatusIds::SUCCESS: + YQL_ENSURE(false); break; case NYql::NDqProto::StatusIds::UNSPECIFIED: case NYql::NDqProto::StatusIds::ABORTED: case NYql::NDqProto::StatusIds::UNAVAILABLE: case NYql::NDqProto::StatusIds::OVERLOADED: - RetryPartExecution(GetBufferIdx(ev->Sender), /* fromBuffer */ true); - break; + return ScheduleRetryWithNewLimit(partInfo); default: + ForgetPartition(partInfo); RuntimeError( Ydb::StatusIds::INTERNAL_ERROR, - NYql::TIssues({NYql::TIssue("RuntimeError: TEvError handle execute.")})); + NYql::TIssues({NYql::TIssue(TStringBuilder() << CurrentStateFuncName() + << ", from BufferWriteActor by PartitionedExecuterActor")})); } } - void RetryPartExecution(size_t partitionIdx, bool fromBuffer) { - if (partitionIdx == Executers.size()) { - return; - } - - if (fromBuffer) { - auto abortEv = TEvKqp::TEvAbortExecution::Aborted("Aborted by Partitioned Executer"); - Send(Executers[partitionIdx], abortEv.Release()); - } else { - Send(BufferActors[partitionIdx], new TEvKqpBuffer::TEvTerminate{}); - } - - ExecutersResponses[partitionIdx] = EExecuterResponse::NONE; - CreateExecuterWithBuffer(partitionIdx, /*isRetry*/ true); - } - STFUNC(AbortState) { try { switch (ev->GetTypeRewrite()) { hFunc(TEvKqpExecuter::TEvTxResponse, HandleAbort); + hFunc(TEvKqpExecuter::TEvTxDelayedExecution, HandleExecute) + hFunc(TEvKqp::TEvAbortExecution, HandleAbort); + hFunc(TEvKqpBuffer::TEvError, HandleAbort); default: - LOG_D("Got unknown message from ActorId = " << ev->Sender << ", typeRewrite = " << ev->GetTypeRewrite()); + PE_LOG_W("unknown message from ActorId = " << ev->Sender); } } catch (...) { RuntimeError( Ydb::StatusIds::INTERNAL_ERROR, - NYql::TIssues({NYql::TIssue("RuntimeError: AbortState.")})); + NYql::TIssues({NYql::TIssue(CurrentStateFuncName())})); } } void HandleAbort(TEvKqpExecuter::TEvTxResponse::TPtr& ev) { const auto& response = ev->Get()->Record.MutableResponse(); - auto idx = GetExecuterIdx(ev->Sender); + auto it = ExecuterToPartition.find(ev->Sender); + if (it == ExecuterToPartition.end()) { + PE_LOG_D("Got TEvKqpExecuter::TEvTxResponse from unknown actor with Id = " << ev->Sender + << ", status = " << response->GetStatus() << ", ignore"); + return; + } - LOG_D("Got EvTxResponse from ActorId = " << ev->Sender << ", status = " << response->GetStatus()); + PE_LOG_D("Got TEvKqpExecuter::TEvTxResponse from ActorId = " << ev->Sender + << ", status = " << response->GetStatus()); - if (idx == Executers.size()) { - return; + auto [_, partInfo] = *it; + AbortBuffer(partInfo->BufferId); + ForgetExecuterAndBuffer(partInfo); + ForgetPartition(partInfo); + + if (CheckExecutersAreFinished()) { + PE_LOG_I("All executers have been finished, abort PartitionedExecuterActor"); + RuntimeError(ReturnStatus, ReturnIssues); } + } - ExecutersResponses[idx] = EExecuterResponse::ERROR; + void HandleAbort(TEvKqp::TEvAbortExecution::TPtr& ev) { + auto& msg = ev->Get()->Record; + auto issues = ev->Get()->GetIssues(); - if (CheckExecutersAreFailed()) { - LOG_D("All executers are aborted. Abort partitioned executer."); - RuntimeError( - Ydb::StatusIds::ABORTED, - NYql::TIssues({NYql::TIssue("RuntimeError: Aborted.")})); + auto it = ExecuterToPartition.find(ev->Sender); + if (it == ExecuterToPartition.end()) { + PE_LOG_D("Got TEvKqp::EvAbortExecution from unknown actor with Id = " << ev->Sender + << " , status: " << NYql::NDqProto::StatusIds_StatusCode_Name(msg.GetStatusCode()) + << ", message: " << issues.ToOneLineString() << ", ignore"); + return; } + + PE_LOG_D("Got TEvKqp::EvAbortExecution from ActorId = " << ev->Sender + << " , status: " << NYql::NDqProto::StatusIds_StatusCode_Name(msg.GetStatusCode()) + << ", message: " << issues.ToOneLineString()); + + auto [_, partInfo] = *it; + AbortBuffer(partInfo->BufferId); + ForgetExecuterAndBuffer(partInfo); } - const TIntrusivePtr& GetUserRequestContext() const { - return UserRequestContext; + void HandleAbort(TEvKqpBuffer::TEvError::TPtr& ev) { + const auto& msg = *ev->Get(); + PE_LOG_D("Got TEvError from BufferWriteActor with Id = " << ev->Sender << ", status = " + << NYql::NDqProto::StatusIds_StatusCode_Name(msg.StatusCode) << ", ignore"); } -private: - size_t GetExecuterIdx(const TActorId exId) const { - auto end = std::find(Executers.begin(), Executers.end(), exId); - return std::distance(Executers.begin(), end); + TString LogPrefix() const { + TStringBuilder result = TStringBuilder() + << "[PARTITIONED] ActorId: " << SelfId() << ", " + << "ActorState: " << CurrentStateFuncName() << ", "; + return result; } - size_t GetBufferIdx(const TActorId buferId) const { - auto end = std::find(BufferActors.begin(), BufferActors.end(), buferId); - return std::distance(BufferActors.begin(), end); +private: + TString CurrentStateFuncName() const { + const auto& func = CurrentStateFunc(); + if (func == &TThis::PrepareState) { + return "PrepareState"; + } else if (func == &TThis::ExecuteState) { + return "ExecuteState"; + } else if (func == &TThis::AbortState) { + return "AbortState"; + } else { + return "unknown state"; + } } void FillTableMetaInfo(const NKqpProto::TKqpSink& sink) { NKikimrKqp::TKqpTableSinkSettings settings; YQL_ENSURE(sink.GetInternalSink().GetSettings().UnpackTo(&settings), "Failed to unpack settings"); - KeyColumnTypes.reserve(settings.GetKeyColumns().size()); - for (const auto& column : settings.GetKeyColumns()) { + switch (settings.GetType()) { + case NKikimrKqp::TKqpTableSinkSettings::MODE_UPDATE: + OperationType = TKeyDesc::ERowOperation::Update; + break; + case NKikimrKqp::TKqpTableSinkSettings::MODE_DELETE: + OperationType = TKeyDesc::ERowOperation::Erase; + break; + default: + break; + } + + KeyColumnInfo.reserve(settings.GetKeyColumns().size()); + for (int i = 0; i < settings.GetKeyColumns().size(); ++i) { + const auto& column = settings.GetKeyColumns()[i]; auto typeInfoMod = NScheme::TypeInfoModFromProtoColumnType(column.GetTypeId(), column.HasTypeInfo() ? &column.GetTypeInfo() : nullptr); - KeyColumnTypes.push_back(typeInfoMod.TypeInfo); + KeyColumnInfo.emplace_back(column.GetId(), typeInfoMod.TypeInfo, i); } TableId = MakeTableId(settings.GetTable()); - TablePath = settings.GetTable().GetPath(); } - void FillRequestWithParams(IKqpGateway::TExecPhysicalRequest& newRequest, size_t partitionIdx) { - YQL_ENSURE(Partitioning); - FillNewRequest(newRequest); + void SendRequestGetPartitions() { + YQL_ENSURE(!KeyColumnInfo.empty()); + + const TVector minKey(KeyColumnInfo.size()); + const TTableRange range(minKey, true, {}, false, false); + + YQL_ENSURE(range.IsFullRange(KeyColumnInfo.size())); + + TVector keyColumnTypes; + for (const auto& info : KeyColumnInfo) { + keyColumnTypes.push_back(info.Type); + } + + auto keyRange = MakeHolder(TableId, range, OperationType, keyColumnTypes, TVector{}); + + TAutoPtr request(new NSchemeCache::TSchemeCacheRequest()); + request->ResultSet.emplace_back(std::move(keyRange)); + + TAutoPtr resolveReq(new TEvTxProxySchemeCache::TEvResolveKeySet(request)); + + Send(MakeSchemeCacheID(), resolveReq.Release()); + } - auto& queryData = newRequest.Transactions.front().Params; + void FillTablePartitioning(std::shared_ptr> partitioning) { + TablePartitioning = std::move(partitioning); + } - YQL_ENSURE(FillParamValue(queryData, NBatchParams::IsFirstQuery, partitionIdx == 0)); + void CreateExecutersWithBuffers() { + Become(&TKqpPartitionedExecuter::ExecuteState); - auto partition = Partitioning->at(partitionIdx).Range; - if (!partition) { - YQL_ENSURE(false); + auto partCount = std::min(BatchOperationSettings.PartitionExecutionLimit, TablePartitioning->size()); + while (NextPartitionIndex < partCount) { + CreateExecuterWithBuffer(NextPartitionIndex++, /* isRetry */ false); } + } - auto cells = partition->EndKeyPrefix.GetCells(); + TBatchPartitionInfo::TPtr CreatePartition(TPartitionIndex idx) { + YQL_ENSURE(idx < TablePartitioning->size()); - YQL_ENSURE(FillParamValue(queryData, NBatchParams::IsLastQuery, cells.empty())); - YQL_ENSURE(FillParamValue(queryData, NBatchParams::IsInclusiveRight, partition->IsInclusive)); + auto partition = std::make_shared(); + StartedPartitions[idx] = partition; - for (size_t i = 0; i < cells.size(); ++i) { - auto endParam = NBatchParams::End + ToString(i + 1); - auto cellValue = NMiniKQL::GetCellValue(cells[i], KeyColumnTypes[i]); - YQL_ENSURE(FillParamValue(queryData, endParam, cellValue)); + partition->EndRange = TablePartitioning->at(idx).Range; + if (idx > 0 && !TablePartitioning->at(idx).Range.Empty()) { + partition->BeginRange = TablePartitioning->at(idx - 1).Range; + partition->BeginRange->IsInclusive = !partition->BeginRange->IsInclusive; } - if (partitionIdx > 0) { - auto prevPartition = Partitioning->at(partitionIdx - 1).Range; - if (!prevPartition) { - YQL_ENSURE(false); + partition->PartitionIndex = idx; + partition->LimitSize = BatchOperationSettings.MaxBatchSize; + partition->RetryDelayMs = BatchOperationSettings.StartRetryDelayMs; + + ReorderPartitionRanges(idx); + + return partition; + } + + void CreateExecuterWithBuffer(TPartitionIndex partitionIndex, bool isRetry) { + auto partInfo = (isRetry) ? StartedPartitions[partitionIndex] : CreatePartition(partitionIndex); + auto txAlloc = std::make_shared(FuncRegistry, TimeProvider, RandomProvider); + + IKqpGateway::TExecPhysicalRequest request(txAlloc); + FillPhysicalRequest(request, txAlloc, partitionIndex); + + auto txManager = CreateKqpTransactionManager(); + + auto alloc = std::make_shared( + __LOCATION__, NKikimr::TAlignedPagePoolCounters(), true, false); + + alloc->SetLimit(WriteBufferInitialMemoryLimit); + alloc->Ref().SetIncreaseMemoryLimitCallback([this, alloc=alloc.get()](ui64 currentLimit, ui64 required) { + if (required < WriteBufferMemoryLimit) { + PE_LOG_D("Increase memory limit from " << currentLimit << " to " << required); + alloc->SetLimit(required); } + }); + + TKqpBufferWriterSettings settings { + .SessionActorId = SelfId(), + .TxManager = txManager, + .TraceId = PhysicalRequest.TraceId.GetTraceId(), + .Counters = RequestCounters->Counters, + .TxProxyMon = RequestCounters->TxProxyMon, + .Alloc = std::move(alloc) + }; + + auto* bufferActor = CreateKqpBufferWriterActor(std::move(settings)); + auto bufferActorId = RegisterWithSameMailbox(bufferActor); + + auto batchSettings = TBatchOperationSettings(partInfo->LimitSize, BatchOperationSettings.MinBatchSize); + auto executerActor = CreateKqpExecuter(std::move(request), Database, UserToken, RequestCounters, + TableServiceConfig, AsyncIoFactory, PreparedQuery, SelfId(), UserRequestContext, StatementResultIndex, + FederatedQuerySetup, GUCSettings, ShardIdToTableInfo, txManager, bufferActorId, std::move(batchSettings)); + auto exId = RegisterWithSameMailbox(executerActor); + + partInfo->ExecuterId = exId; + partInfo->BufferId = bufferActorId; + ExecuterToPartition[exId] = BufferToPartition[bufferActorId] = partInfo; + + PE_LOG_I("Create new KQP executer by PartitionedExecuterActor: ExecuterId = " << partInfo->ExecuterId + << ", PartitionIndex = " << partitionIndex << ", LimitSize = " << partInfo->LimitSize + << ", RetryDelayMs = " << partInfo->RetryDelayMs); + + auto ev = std::make_unique(exId); + Send(MakeTxProxyID(), ev.release()); + } + + void Abort() { + Become(&TKqpPartitionedExecuter::AbortState); - YQL_ENSURE(FillParamValue(queryData, NBatchParams::IsInclusiveLeft, prevPartition->IsInclusive)); + if (CheckExecutersAreFinished()) { + PE_LOG_I("All executers have been finished, abort PartitionedExecuterActor"); + return RuntimeError(ReturnStatus, ReturnIssues); + } + + SendAbortToExecuters(); + } + + void SendAbortToExecuters() { + PE_LOG_I("Send abort to executers"); + + for (auto& [exId, partInfo] : ExecuterToPartition) { + AbortExecuter(exId, "runtime error"); + } + } + + void AbortExecuter(TActorId id, const TString& reason) { + auto abortEv = TEvKqp::TEvAbortExecution::Aborted("Aborted by PartitionedExecuterActor, reason: " + reason); + Send(id, abortEv.Release()); + } + + void AbortBuffer(TActorId id) { + Send(id, new TEvKqpBuffer::TEvTerminate{}); + } + + void ForgetExecuterAndBuffer(const TBatchPartitionInfo::TPtr& partInfo) { + YQL_ENSURE(ExecuterToPartition.erase(partInfo->ExecuterId) == 1); + YQL_ENSURE(BufferToPartition.erase(partInfo->BufferId) == 1); + } + + void ForgetPartition(const TBatchPartitionInfo::TPtr& partInfo) { + YQL_ENSURE(StartedPartitions.erase(partInfo->PartitionIndex) == 1); + } + + void OnSuccessResponse(TBatchPartitionInfo::TPtr& partInfo, TEvKqpExecuter::TEvTxResponse* ev) { + const auto& maxReadKeys = ev->BatchOperationMaxKeys; + const auto& keyIds = ev->BatchOperationKeyIds; + + TryReorderKeysByIds(keyIds); + + TSerializedCellVec maxKey = GetMaxCellVecKey(maxReadKeys); + if (!maxKey.GetCells().empty()) { + partInfo->BeginRange = TKeyDesc::TPartitionRangeInfo(maxKey, + /* IsInclusive */ false, + /* IsPoint */ false + ); + return RetryPartExecution(partInfo); + } + + ForgetPartition(partInfo); + + if (NextPartitionIndex < TablePartitioning->size()) { + return CreateExecuterWithBuffer(NextPartitionIndex++, /* isRetry */ false); + } + + if (CheckExecutersAreFinished()) { + auto& response = *ResponseEv->Record.MutableResponse(); + response.SetStatus(ReturnStatus); + + PE_LOG_I("All executers have been finished. Send SUCCESS to SessionActor"); + + Send(SessionActorId, ResponseEv.release()); + PassAway(); + } + } - auto prevCells = prevPartition->EndKeyPrefix.GetCells(); - YQL_ENSURE(!prevCells.empty()); + void RetryPartExecution(const TBatchPartitionInfo::TPtr& partInfo) { + PE_LOG_D("Retry query execution for PartitionIndex = " << partInfo->PartitionIndex + << ", RetryDelayMs = " << partInfo->RetryDelayMs); - for (size_t i = 0; i < prevCells.size(); ++i) { - auto beginParam = NBatchParams::Begin + ToString(i + 1); - auto prevCellValue = NMiniKQL::GetCellValue(prevCells[i], KeyColumnTypes[i]); - YQL_ENSURE(FillParamValue(queryData, beginParam, prevCellValue)); + if (this->CurrentStateFunc() != &TKqpPartitionedExecuter::AbortState) { + return CreateExecuterWithBuffer(partInfo->PartitionIndex, /* isRetry */ true); + } + + ForgetPartition(partInfo); + + if (CheckExecutersAreFinished()) { + PE_LOG_I("All executers have been finished, abort PartitionedExecuterActor"); + RuntimeError(ReturnStatus, ReturnIssues); + } + } + + void ScheduleRetryWithNewLimit(TBatchPartitionInfo::TPtr& partInfo) { + auto newLimit = std::max(partInfo->LimitSize / 2, BatchOperationSettings.MinBatchSize); + partInfo->LimitSize = newLimit; + + auto ev = std::make_unique(partInfo->PartitionIndex); + Schedule(TDuration::MilliSeconds(partInfo->RetryDelayMs), ev.release()); + + // We use the init delay value first and change it for the next attempt + auto decJitterDelay = RandomProvider->Uniform(BatchOperationSettings.StartRetryDelayMs, partInfo->RetryDelayMs * 3ul); + auto newDelay = std::min(BatchOperationSettings.MaxRetryDelayMs, decJitterDelay); + partInfo->RetryDelayMs = newDelay; + } + + void FillPhysicalRequest(IKqpGateway::TExecPhysicalRequest& physicalRequest, + TTxAllocatorState::TPtr txAlloc, TPartitionIndex partitionIndex) + { + FillRequestByInitWithParams(physicalRequest, partitionIndex, /* literal */ false); + + auto queryData = physicalRequest.Transactions.front().Params; + if (UseLiteral) { + IKqpGateway::TExecPhysicalRequest literalRequest(txAlloc); + FillRequestByInitWithParams(literalRequest, partitionIndex, /* literal */ true); + PrepareParameters(literalRequest); + + auto ev = ExecuteLiteral(std::move(literalRequest), RequestCounters, SelfId(), UserRequestContext); + auto* response = ev->Record.MutableResponse(); + + if (response->GetStatus() != Ydb::StatusIds::SUCCESS) { + return RuntimeError( + Ydb::StatusIds::BAD_REQUEST, + NYql::TIssues({NYql::TIssue(TStringBuilder() << CurrentStateFuncName() + << ", got error from KqpLiteralExecuter.")})); + } + + if (!ev->GetTxResults().empty()) { + queryData->AddTxResults(0, std::move(ev->GetTxResults())); } + + queryData->AddTxHolders(std::move(ev->GetTxHolders())); } + + PrepareParameters(physicalRequest); + LogDebugRequest(queryData, partitionIndex); + } + + void FillRequestByInitWithParams(IKqpGateway::TExecPhysicalRequest& request, TPartitionIndex partitionIndex, bool literal) + { + FillRequestByInit(request, literal); + + YQL_ENSURE(!request.Transactions.empty()); + + auto& queryData = request.Transactions.front().Params; + auto& partition = StartedPartitions[partitionIndex]; + + FillRequestRange(queryData, partition->BeginRange, /* isBegin */ true); + FillRequestRange(queryData, partition->EndRange, /* isBegin */ false); } - void FillNewRequest(IKqpGateway::TExecPhysicalRequest& newRequest) { - newRequest.AllowTrailingResults = Request.AllowTrailingResults; - newRequest.QueryType = Request.QueryType; - newRequest.PerRequestDataSizeLimit = Request.PerRequestDataSizeLimit; - newRequest.MaxShardCount = Request.MaxShardCount; - newRequest.DataShardLocks = Request.DataShardLocks; - newRequest.LocksOp = Request.LocksOp; - newRequest.AcquireLocksTxId = Request.AcquireLocksTxId; - newRequest.Timeout = Request.Timeout; - newRequest.CancelAfter = Request.CancelAfter; - newRequest.MaxComputeActors = Request.MaxComputeActors; - newRequest.MaxAffectedShards = Request.MaxAffectedShards; - newRequest.TotalReadSizeLimitBytes = Request.TotalReadSizeLimitBytes; - newRequest.MkqlMemoryLimit = Request.MkqlMemoryLimit; - newRequest.PerShardKeysSizeLimitBytes = Request.PerShardKeysSizeLimitBytes; - newRequest.StatsMode = Request.StatsMode; - newRequest.ProgressStatsPeriod = Request.ProgressStatsPeriod; - newRequest.Snapshot = Request.Snapshot; - newRequest.ResourceManager_ = Request.ResourceManager_; - newRequest.CaFactory_ = Request.CaFactory_; - newRequest.IsolationLevel = Request.IsolationLevel; - newRequest.RlPath = Request.RlPath; - newRequest.NeedTxId = Request.NeedTxId; - newRequest.UseImmediateEffects = Request.UseImmediateEffects; - // newRequest.Orbit = Request.Orbit; - // newRequest.TraceId = Request.TraceId; - newRequest.UserTraceId = Request.UserTraceId; - newRequest.OutputChunkMaxSize = Request.OutputChunkMaxSize; - - newRequest.Transactions.emplace_back(Request.Transactions.front().Body, std::make_shared(Request.TxAlloc)); - - auto newParams = newRequest.Transactions.front().Params; - auto oldParams = Request.Transactions.front().Params; - for (auto& [name, _] : oldParams->GetParams()) { + void FillRequestByInit(IKqpGateway::TExecPhysicalRequest& newRequest, bool literal) { + auto& from = (literal) ? LiteralRequest : PhysicalRequest; + IKqpGateway::TExecPhysicalRequest::FillRequestFrom(newRequest, from); + + auto tx = PreparedQuery->GetTransactions()[(UseLiteral) ? 1 - static_cast(literal) : 0]; + newRequest.Transactions.emplace_back(tx, std::make_shared(newRequest.TxAlloc)); + newRequest.TraceId = NWilson::TTraceId(); + + auto newData = newRequest.Transactions.front().Params; + auto oldData = (UseLiteral) ? LiteralRequest.Transactions.front().Params : PhysicalRequest.Transactions.front().Params; + for (auto& [name, _] : oldData->GetParams()) { if (!name.StartsWith(NBatchParams::Header)) { - TTypedUnboxedValue& typedValue = oldParams->GetParameterUnboxedValue(name); - newParams->AddUVParam(name, typedValue.first, typedValue.second); + TTypedUnboxedValue& typedValue = oldData->GetParameterUnboxedValue(name); + newData->AddUVParam(name, typedValue.first, typedValue.second); + } + } + } + + void FillRequestRange(TQueryData::TPtr queryData, const TMaybe& range, bool isBegin) { + /* + isBegin = true + + IsInclusiveLeft AND ((BeginPrefixSize = 0) OR ((BeginPrefixSize = 1) AND (Begin1 <= K1)) OR ((BeginPrefixSize = 2) AND ((Begin1, Begin2) <= (K1, K2)) OR ...) + OR + NOT IsInclusiveLeft AND ((BeginPrefixSize = 0) OR ((BeginPrefixSize = 1) AND (Begin1 < K1)) OR ((BeginPrefixSize = 2) AND ((Begin1, Begin2) < (K1, K2)) OR ...) + */ + + auto isInclusive = (isBegin) ? NBatchParams::IsInclusiveLeft : NBatchParams::IsInclusiveRight; + auto rangeName = ((isBegin) ? NBatchParams::Begin : NBatchParams::End); + auto prefixRangeName = ((isBegin) ? NBatchParams::BeginPrefixSize : NBatchParams::EndPrefixSize); + + FillRequestParameter(queryData, isInclusive, (!range.Empty()) ? range->IsInclusive : false); + + size_t firstEmpty = (range.Empty()) ? 0 : KeyColumnInfo.size(); + + for (size_t i = 0; i < KeyColumnInfo.size(); ++i) { + const auto& info = KeyColumnInfo[i]; + auto paramName = rangeName + ToString(info.ParamIndex + 1); + + if (range.Empty() || range->EndKeyPrefix.GetCells().size() <= i) { + firstEmpty = std::min(firstEmpty, info.ParamIndex); + FillRequestParameter(queryData, paramName, false, /* setDefault */ true); + continue; + } + + auto cellValue = NMiniKQL::GetCellValue(range->EndKeyPrefix.GetCells()[i], info.Type); + if (!cellValue.HasValue()) { + firstEmpty = std::min(firstEmpty, info.ParamIndex); + } + + FillRequestParameter(queryData, paramName, cellValue); + } + + FillRequestParameter(queryData, prefixRangeName, firstEmpty); + } + + template + void FillRequestParameter(TQueryData::TPtr queryData, const TString& name, T value, bool setDefault = false) { + for (const auto& paramDesc : PreparedQuery->GetParameters()) { + if (paramDesc.GetName() != name) { + continue; } + + NKikimrMiniKQL::TType protoType = paramDesc.GetType(); + NKikimr::NMiniKQL::TType* paramType = ImportTypeFromProto(protoType, queryData->GetAllocState()->TypeEnv); + + if (setDefault) { + auto defaultValue = MakeDefaultValueByType(paramType); + queryData->AddUVParam(name, paramType, defaultValue); + return; + } + + queryData->AddUVParam(name, paramType, NUdf::TUnboxedValuePod(value)); + return; } + + YQL_ENSURE(false); } - bool CheckExecutersAreSuccess() const { - return std::all_of(ExecutersResponses.cbegin(), ExecutersResponses.cend(), - [](const auto& resp) { return resp == EExecuterResponse::SUCCESS; }); + void PrepareParameters(IKqpGateway::TExecPhysicalRequest& request) { + auto& queryData = request.Transactions.front().Params; + TString paramName; + + try { + for (const auto& paramDesc : PreparedQuery->GetParameters()) { + paramName = paramDesc.GetName(); + queryData->ValidateParameter(paramDesc.GetName(), paramDesc.GetType(), request.TxAlloc->TypeEnv); + } + + for(const auto& paramBinding: request.Transactions.front().Body->GetParamBindings()) { + paramName = paramBinding.GetName(); + queryData->MaterializeParamValue(true, paramBinding); + } + } catch (const yexception& ex) { + RuntimeError( + Ydb::StatusIds::BAD_REQUEST, + NYql::TIssues({NYql::TIssue(TStringBuilder() << CurrentStateFuncName() + << ", cannot prepare parameters for request, parameter name = " << paramName)})); + } } - bool CheckExecutersAreFailed() const { - return std::all_of(ExecutersResponses.cbegin(), ExecutersResponses.cend(), - [](const auto& resp) { return resp == EExecuterResponse::ERROR; }); + bool CheckExecutersAreFinished() const { + return StartedPartitions.empty(); + } + + // SchemeCache and ReadActor may have the different order of key columns, + // so we need to reorder partition ranges for next compares. + void TryReorderKeysByIds(const TVector& keyIds) { + if (keyIds.empty()) { + return; + } + + YQL_ENSURE(KeyColumnInfo.size() == keyIds.size()); + + bool isEqual = true; + for (size_t i = 0; i < KeyColumnInfo.size(); ++i) { + if (KeyColumnInfo[i].Id != keyIds[i]) { + isEqual = false; + break; + } + } + + if (isEqual) { + return; + } + + ReorderKeyColumnInfo(keyIds); + for (const auto& [partIdx, _] : StartedPartitions) { + ReorderPartitionRanges(partIdx); + } + } + + void ReorderPartitionRanges(TPartitionIndex idx) { + PE_LOG_D("Reorder KeyColumnInfo and partitioning ranges by keyIds from RA"); + + auto& partInfo = StartedPartitions[idx]; + + auto& beginRow = partInfo->BeginRange; + if (!beginRow.Empty()) { + beginRow->EndKeyPrefix = ReorderRangeByKeyColumnInfo(beginRow->EndKeyPrefix); + } + + auto& endRow = partInfo->EndRange; + if (!endRow.Empty()) { + endRow->EndKeyPrefix = ReorderRangeByKeyColumnInfo(endRow->EndKeyPrefix); + } + } + + TSerializedCellVec ReorderRangeByKeyColumnInfo(const TSerializedCellVec& row) { + if (row.GetCells().empty()) { + return row; + } + + TVector newRow; + auto cells = row.GetCells(); + for (const auto& info : KeyColumnInfo) { + newRow.push_back(cells[info.ParamIndex]); + } + + TConstArrayRef rowRef(newRow); + return TSerializedCellVec(rowRef); + } + + void ReorderKeyColumnInfo(const TVector& keyIds) { + TVector newInfo; + + for (const auto& id : keyIds) { + auto it = std::find_if(KeyColumnInfo.cbegin(), KeyColumnInfo.cend(), [&id] (const TKeyColumnInfo& info) { + return info.Id == id; + }); + + YQL_ENSURE(it != KeyColumnInfo.cend()); + newInfo.push_back(*it); + } + + KeyColumnInfo = std::move(newInfo); + } + + TSerializedCellVec GetMaxCellVecKey(const TVector& maxReadKeys) const { + TSerializedCellVec maxKey; + for (size_t i = 0; i < maxReadKeys.size(); ++i) { + auto row = maxReadKeys[i]; + if (i == 0) { + maxKey = row; + continue; + } + + auto max_cells = maxKey.GetCells(); + auto row_cells = row.GetCells(); + + YQL_ENSURE(row_cells.size() == max_cells.size()); + + for (size_t j = 0; j < KeyColumnInfo.size(); ++j) { + NScheme::TTypeInfoOrder typeOrder(KeyColumnInfo[j].Type, NScheme::EOrder::Ascending); + if (CompareTypedCells(max_cells[j], row_cells[j], typeOrder) < 0) { + maxKey = row; + break; + } + } + } + return maxKey; + } + + void LogDebugRequest(TQueryData::TPtr queryData, TPartitionIndex partitionIndex) { + TStringBuilder builder; + builder << "Fill request with parameters, PartitionInddx = " << partitionIndex << ": "; + + auto [isInclusiveLeftType, isInclusiveLeftValue] = queryData->GetParameterUnboxedValue(NBatchParams::IsInclusiveLeft); + auto [isInclusiveRightType, isInclusiveRightValue] = queryData->GetParameterUnboxedValue(NBatchParams::IsInclusiveRight); + + auto [beginPrefixSizeType, beginPrefixSizeValue] = queryData->GetParameterUnboxedValue(NBatchParams::BeginPrefixSize); + auto [endPrefixSizeType, endPrefixSizeValue] = queryData->GetParameterUnboxedValue(NBatchParams::EndPrefixSize); + + builder << "("; + + for (size_t i = 0; i < KeyColumnInfo.size(); ++i) { + auto paramIndex = KeyColumnInfo[i].ParamIndex; + auto beginName = NBatchParams::Begin + ToString(paramIndex + 1); + auto [beginType, beginValue] = queryData->GetParameterUnboxedValue(beginName); + + auto endName = NBatchParams::End + ToString(paramIndex + 1); + auto [endType, endValue] = queryData->GetParameterUnboxedValue(endName); + + if (paramIndex >= beginPrefixSizeValue.Get()) { + builder << "-inf"; + } else { + builder << "[" << beginValue << "]"; + } + builder << ((isInclusiveLeftValue.Get()) ? " <= " : " < "); + + builder << ("Column" + ToString(paramIndex + 1)); + + builder << ((isInclusiveRightValue.Get()) ? " <= " : " < "); + if (paramIndex >= endPrefixSizeValue.Get()) { + builder << "+inf"; + } else { + builder << "[" << endValue << "]"; + } + + if (i + 1 < KeyColumnInfo.size()) { + builder << ", "; + } + } + + builder << ")"; + PE_LOG_D(builder); } void RuntimeError(Ydb::StatusIds::StatusCode code, const NYql::TIssues& issues) { + PE_LOG_E(Ydb::StatusIds_StatusCode_Name(code) << ": " << issues.ToOneLineString()); + if (this->CurrentStateFunc() != &TKqpPartitionedExecuter::AbortState) { - Abort(); - return; + ReturnStatus = code; + return Abort(); } - LOG_E(Ydb::StatusIds_StatusCode_Name(code) << ": " << issues.ToOneLineString()); ReplyErrorAndDie(code, issues); } @@ -505,22 +917,43 @@ class TKqpPartitionedExecuter : public TActorBootstrapped ResponseEv; - IKqpGateway::TExecPhysicalRequest Request; - const TActorId SessionActorId; - TVector Executers; - TVector BufferActors; - TVector ExecutersResponses; - TVector KeyColumnTypes; - std::shared_ptr> Partitioning; + TBatchOperationSettings BatchOperationSettings; + + // for errors only + Ydb::StatusIds::StatusCode ReturnStatus = Ydb::StatusIds::SUCCESS; + NYql::TIssues ReturnIssues; + + struct TKeyColumnInfo { + ui32 Id; + NScheme::TTypeInfo Type; + size_t ParamIndex; + }; + + // We have to save column ids and types for compare rows to start retry execution + TVector KeyColumnInfo; + + std::shared_ptr> TablePartitioning; + THashMap StartedPartitions; + TPartitionIndex NextPartitionIndex = 0; + + THashMap ExecuterToPartition; + THashMap BufferToPartition; + + TKeyDesc::ERowOperation OperationType; TTableId TableId; - TString TablePath; - TString LogPrefix; - ui64 TxId = 0; - // Args for child executers and buffer write actors + IKqpGateway::TExecPhysicalRequest LiteralRequest; + IKqpGateway::TExecPhysicalRequest PhysicalRequest; + bool UseLiteral; + + const TActorId SessionActorId; + const NMiniKQL::IFunctionRegistry* FuncRegistry; + TIntrusivePtr TimeProvider; + TIntrusivePtr RandomProvider; + + // The next variables are only for DEA and BWA TString Database; TIntrusiveConstPtr UserToken; - TIntrusivePtr Counters; TKqpRequestCounters::TPtr RequestCounters; NKikimrConfig::TTableServiceConfig TableServiceConfig; TIntrusivePtr UserRequestContext; @@ -530,21 +963,16 @@ class TKqpPartitionedExecuter : public TActorBootstrapped FederatedQuerySetup; const TGUCSettings::TPtr GUCSettings; TShardIdToTableInfoPtr ShardIdToTableInfo; + + const ui64 WriteBufferInitialMemoryLimit; + const ui64 WriteBufferMemoryLimit; }; } // namespace -NActors::IActor* CreateKqpPartitionedExecuter( - NKikimr::NKqp::IKqpGateway::TExecPhysicalRequest&& request, const TActorId sessionActorId, const TString& database, - const TIntrusiveConstPtr& userToken, const TIntrusivePtr& counters, - NKikimr::NKqp::TKqpRequestCounters::TPtr requestCounters, const NKikimrConfig::TTableServiceConfig& tableServiceConfig, - NYql::NDq::IDqAsyncIoFactory::TPtr asyncIoFactory, TPreparedQueryHolder::TConstPtr preparedQuery, - const TIntrusivePtr& userRequestContext, ui32 statementResultIndex, - const std::optional& federatedQuerySetup, const TGUCSettings::TPtr& GUCSettings, - const NKikimr::NKqp::TShardIdToTableInfoPtr& shardIdToTableInfo) +NActors::IActor* CreateKqpPartitionedExecuter(TKqpPartitionedExecuterSettings settings) { - return new TKqpPartitionedExecuter(std::move(request), sessionActorId, database, userToken, counters, requestCounters, tableServiceConfig, std::move(asyncIoFactory), std::move(preparedQuery), userRequestContext, statementResultIndex, federatedQuerySetup, - GUCSettings, shardIdToTableInfo); + return new TKqpPartitionedExecuter(std::move(settings)); } } // namespace NKqp diff --git a/ydb/core/kqp/executer_actor/kqp_partitioned_executer.h b/ydb/core/kqp/executer_actor/kqp_partitioned_executer.h index 6fd761c54d2d..80f02bbbb241 100644 --- a/ydb/core/kqp/executer_actor/kqp_partitioned_executer.h +++ b/ydb/core/kqp/executer_actor/kqp_partitioned_executer.h @@ -12,13 +12,28 @@ namespace NKikimr::NKqp { -NActors::IActor* CreateKqpPartitionedExecuter( - NKikimr::NKqp::IKqpGateway::TExecPhysicalRequest&& request, const TActorId sessionActorId, const TString& database, - const TIntrusiveConstPtr& userToken, const TIntrusivePtr& counters, - NKikimr::NKqp::TKqpRequestCounters::TPtr requestCounters, const NKikimrConfig::TTableServiceConfig& tableServiceConfig, - NYql::NDq::IDqAsyncIoFactory::TPtr asyncIoFactory, TPreparedQueryHolder::TConstPtr preparedQuery, - const TIntrusivePtr& userRequestContext, ui32 statementResultIndex, - const std::optional& federatedQuerySetup, const TGUCSettings::TPtr& GUCSettings, - const NKikimr::NKqp::TShardIdToTableInfoPtr& shardIdToTableInfo); +struct TKqpPartitionedExecuterSettings { + IKqpGateway::TExecPhysicalRequest&& LiteralRequest; + IKqpGateway::TExecPhysicalRequest&& PhysicalRequest; + TActorId SessionActorId; + const NMiniKQL::IFunctionRegistry* FuncRegistry; + TIntrusivePtr TimeProvider; + TIntrusivePtr RandomProvider; + TString Database; + const TIntrusiveConstPtr& UserToken; + TKqpRequestCounters::TPtr RequestCounters; + const NKikimrConfig::TTableServiceConfig& TableServiceConfig; + NYql::NDq::IDqAsyncIoFactory::TPtr AsyncIoFactory; + TPreparedQueryHolder::TConstPtr PreparedQuery; + const TIntrusivePtr& UserRequestContext; + ui32 StatementResultIndex; + std::optional& FederatedQuerySetup; + const TGUCSettings::TPtr& GUCSettings; + const TShardIdToTableInfoPtr& ShardIdToTableInfo; + ui64 WriteBufferInitialMemoryLimit; + ui64 WriteBufferMemoryLimit; +}; + +NActors::IActor* CreateKqpPartitionedExecuter(TKqpPartitionedExecuterSettings settings); } // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/executer_actor/kqp_table_resolver.cpp b/ydb/core/kqp/executer_actor/kqp_table_resolver.cpp index 605eceba9108..2062c303aeed 100644 --- a/ydb/core/kqp/executer_actor/kqp_table_resolver.cpp +++ b/ydb/core/kqp/executer_actor/kqp_table_resolver.cpp @@ -37,11 +37,21 @@ class TKqpTableResolver : public TActorBootstrapped { void Bootstrap() { ResolveKeys(); - Become(&TKqpTableResolver::ResolveKeysState); } private: + STATEFN(ResolveNamesState) { + switch (ev->GetTypeRewrite()) { + hFunc(TEvTxProxySchemeCache::TEvNavigateKeySetResult, HandleResolveNames); + hFunc(TEvents::TEvPoison, HandleResolveNames); + default: { + LOG_C("ResolveKeysState: unexpected event " << ev->GetTypeRewrite()); + GotUnexpectedEvent = ev->GetTypeRewrite(); + } + } + } + STATEFN(ResolveKeysState) { switch (ev->GetTypeRewrite()) { hFunc(TEvTxProxySchemeCache::TEvResolveKeySetResult, HandleResolveKeys); @@ -54,27 +64,167 @@ class TKqpTableResolver : public TActorBootstrapped { } } - void HandleResolveKeys(TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev) { + void HandleResolveNames(TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev) { if (ShouldTerminate) { PassAway(); return; } auto& results = ev->Get()->Request->ResultSet; - if (results.size() != TableRequestIds.size()) { + if (results.size() != TableRequestPathes.size()) { ReplyErrorAndDie(Ydb::StatusIds::INTERNAL_ERROR, TIssue(TStringBuilder() << "navigation problems for tables")); return; } LOG_D("Navigated key sets: " << results.size()); for (auto& entry : results) { - auto iter = TableRequestIds.find(entry.TableId); - if (iter == TableRequestIds.end()) { + if (entry.Status != NSchemeCache::TSchemeCacheNavigate::EStatus::Ok) { ReplyErrorAndDie(Ydb::StatusIds::SCHEME_ERROR, YqlIssue({}, NYql::TIssuesIds::KIKIMR_SCHEME_MISMATCH, TStringBuilder() - << "Incorrect tableId in reply " << entry.TableId << '.')); + << "Failed to resolve table with tableId: " << entry.TableId << " status: " << entry.Status << '.')); return; } - TVector stageIds(std::move(iter->second)); - TableRequestIds.erase(entry.TableId); + + auto iterTableRequestPathes = TableRequestPathes.find(CanonizePath(entry.Path)); + if (iterTableRequestPathes == TableRequestPathes.end()) { + ReplyErrorAndDie(Ydb::StatusIds::SCHEME_ERROR, + YqlIssue({}, NYql::TIssuesIds::KIKIMR_SCHEME_MISMATCH, TStringBuilder() + << "Incorrect table path in reply `" << CanonizePath(entry.Path) << "`.")); + return; + } + + AFL_ENSURE(entry.RequestType == NSchemeCache::TSchemeCacheNavigate::TEntry::ERequestType::ByPath); + if (iterTableRequestPathes != TableRequestPathes.end()) { + TVector stageIds(std::move(iterTableRequestPathes->second)); + const bool isOlap = (entry.Kind == NSchemeCache::TSchemeCacheNavigate::KindColumnTable); + + for (auto stageId : stageIds) { + auto& stageMeta = TasksGraph.GetStageInfo(stageId).Meta; + stageMeta.TableId = entry.TableId; + if (entry.Kind == NSchemeCache::TSchemeCacheNavigate::KindTable) { + stageMeta.TableKind = ETableKind::Datashard; + } else { + AFL_ENSURE(isOlap); + stageMeta.TableKind = ETableKind::Olap; + } + + auto& stage = stageMeta.GetStage(stageId); + AFL_ENSURE(stage.GetSinks().size() == 1); + const auto& sink = stage.GetSinks(0); + + AFL_ENSURE(sink.GetTypeCase() == NKqpProto::TKqpSink::kInternalSink && sink.GetInternalSink().GetSettings().Is()); + NKikimrKqp::TKqpTableSinkSettings settings; + AFL_ENSURE(sink.GetInternalSink().GetSettings().UnpackTo(&settings)); + AFL_ENSURE(settings.GetType() == NKikimrKqp::TKqpTableSinkSettings::MODE_FILL); + settings.MutableTable()->SetOwnerId(entry.TableId.PathId.OwnerId); + settings.MutableTable()->SetTableId(entry.TableId.PathId.LocalPathId); + settings.MutableTable()->SetSysView(entry.TableId.SysViewInfo); + settings.MutableTable()->SetVersion(entry.TableId.SchemaVersion); + + settings.SetIsOlap(isOlap); + + auto fillColumnProto = [] (const NKikimr::TSysTables::TTableColumnInfo& columnInfo, NKikimrKqp::TKqpColumnMetadataProto* columnProto ) { + columnProto->SetId(columnInfo.Id); + columnProto->SetName(columnInfo.Name); + columnProto->SetTypeId(columnInfo.PType.GetTypeId()); + + if (NScheme::NTypeIds::IsParametrizedType(columnInfo.PType.GetTypeId())) { + ProtoFromTypeInfo(columnInfo.PType, columnInfo.PTypeMod, *columnProto->MutableTypeInfo()); + } + }; + + THashMap columnNameToIndex; + TMap keyPositionToIndex; + TMap columnIdToIndex; + TVector keyTypes; + + // CTAS writes all columns + AFL_ENSURE(static_cast(settings.GetInputColumns().size()) == entry.Columns.size()); + + for (const auto& [index, columnInfo] : entry.Columns) { + columnNameToIndex[columnInfo.Name] = index; + columnIdToIndex[columnInfo.Id] = index; + if (columnInfo.KeyOrder != -1) { + AFL_ENSURE(columnInfo.KeyOrder >= 0); + keyPositionToIndex[columnInfo.KeyOrder] = index; + } + } + + keyTypes.reserve(keyPositionToIndex.size()); + for (const auto& [_, index] : keyPositionToIndex) { + const auto columnInfo = entry.Columns.FindPtr(index); + AFL_ENSURE(columnInfo); + + auto keyColumnProto = settings.AddKeyColumns(); + fillColumnProto(*columnInfo, keyColumnProto); + + keyTypes.push_back(columnInfo->PType); + } + AFL_ENSURE(!keyPositionToIndex.empty()); + + stageMeta.ShardKey = ExtractKey( + stageMeta.TableId, + keyTypes, + TKeyDesc::ERowOperation::Update); // CTAS is Update operation + + for (const auto& columnName : settings.GetInputColumns()) { + const auto index = columnNameToIndex.FindPtr(columnName); + AFL_ENSURE(index); + const auto columnInfo = entry.Columns.FindPtr(*index); + AFL_ENSURE(columnInfo); + + auto columnProto = settings.AddColumns(); + fillColumnProto(*columnInfo, columnProto); + } + + { + THashMap columnToOrder; + ui32 currentIndex = 0; + if (!isOlap) { + for (const auto& [_, index] : keyPositionToIndex) { + const auto columnInfo = entry.Columns.FindPtr(index); + AFL_ENSURE(columnInfo); + columnToOrder[columnInfo->Name] = currentIndex++; + } + } + for (const auto& [id, index] : columnIdToIndex) { + const auto columnInfo = entry.Columns.FindPtr(index); + AFL_ENSURE(columnInfo); + AFL_ENSURE(columnInfo->Id == id); + if (isOlap || columnInfo->KeyOrder == -1) { + columnToOrder[columnInfo->Name] = currentIndex++; + } else { + AFL_ENSURE(columnToOrder.contains(columnInfo->Name)); + } + } + + for (const auto& columnName : settings.GetInputColumns()) { + settings.AddWriteIndexes(columnToOrder.at(columnName)); + } + } + + AFL_ENSURE(settings.GetColumns().size() == settings.GetWriteIndexes().size()); + + stageMeta.ResolvedSinkSettings = settings; + } + } + } + + ResolvingNamesFinished = true; + ResolveKeys(); + } + + void HandleResolveKeys(TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev) { + AFL_ENSURE(ResolvingNamesFinished); + if (ShouldTerminate) { + PassAway(); + return; + } + auto& results = ev->Get()->Request->ResultSet; + if (results.size() != TableRequestIds.size()) { + ReplyErrorAndDie(Ydb::StatusIds::INTERNAL_ERROR, TIssue(TStringBuilder() << "navigation problems for tables")); + return; + } + LOG_D("Navigated key sets: " << results.size()); + for (auto& entry : results) { if (entry.Status != NSchemeCache::TSchemeCacheNavigate::EStatus::Ok) { ReplyErrorAndDie(Ydb::StatusIds::SCHEME_ERROR, YqlIssue({}, NYql::TIssuesIds::KIKIMR_SCHEME_MISMATCH, TStringBuilder() @@ -82,15 +232,28 @@ class TKqpTableResolver : public TActorBootstrapped { return; } + auto iterTableRequestIds = TableRequestIds.find(entry.TableId); + if (iterTableRequestIds == TableRequestIds.end()) { + ReplyErrorAndDie(Ydb::StatusIds::SCHEME_ERROR, + YqlIssue({}, NYql::TIssuesIds::KIKIMR_SCHEME_MISMATCH, TStringBuilder() + << "Incorrect tableId in reply " << entry.TableId << '.')); + return; + } + + TVector stageIds(std::move(iterTableRequestIds->second)); + TableRequestIds.erase(entry.TableId); + for (auto stageId : stageIds) { TasksGraph.GetStageInfo(stageId).Meta.ColumnTableInfoPtr = entry.ColumnTableInfo; } } + NavigationFinished = true; TryFinish(); } void HandleResolveKeys(TEvTxProxySchemeCache::TEvResolveKeySetResult::TPtr &ev) { + AFL_ENSURE(ResolvingNamesFinished); if (ShouldTerminate) { PassAway(); return; @@ -126,7 +289,7 @@ class TKqpTableResolver : public TActorBootstrapped { } for (auto& partition : entry.KeyDescription->GetPartitions()) { - YQL_ENSURE(partition.Range); + AFL_ENSURE(partition.Range); } LOG_D("Resolved key: " << entry.ToString(*AppData()->TypeRegistry)); @@ -145,9 +308,12 @@ class TKqpTableResolver : public TActorBootstrapped { ShouldTerminate = true; } + void HandleResolveNames(TEvents::TEvPoison::TPtr&) { + ShouldTerminate = true; + } + private: void ResolveKeys() { - auto requestNavigate = std::make_unique(); auto request = MakeHolder(); request->ResultSet.reserve(TasksGraph.GetStagesInfo().size()); @@ -155,68 +321,122 @@ class TKqpTableResolver : public TActorBootstrapped { request->UserToken = UserToken; } + bool needToResolveNames = false; + if (!ResolvingNamesFinished) { + for (const auto& [_, stageInfo] : TasksGraph.GetStagesInfo()) { + if (!stageInfo.Meta.ShardOperations.empty()) { + const auto& tableInfo = stageInfo.Meta.TableConstInfo; + if (!tableInfo) { + AFL_ENSURE(!stageInfo.Meta.TableId); + AFL_ENSURE(stageInfo.Meta.TablePath); + needToResolveNames = true; + } + } + } + ResolvingNamesFinished = !needToResolveNames; + } + for (auto& pair : TasksGraph.GetStagesInfo()) { auto& stageInfo = pair.second; if (!stageInfo.Meta.ShardOperations.empty()) { - YQL_ENSURE(stageInfo.Meta.TableId); - YQL_ENSURE(!stageInfo.Meta.ShardOperations.empty()); - for (const auto& operation : stageInfo.Meta.ShardOperations) { const auto& tableInfo = stageInfo.Meta.TableConstInfo; - Y_ENSURE(tableInfo); - TablePathsById.emplace(stageInfo.Meta.TableId, tableInfo->Path); - stageInfo.Meta.TableKind = tableInfo->TableKind; - - stageInfo.Meta.ShardKey = ExtractKey(stageInfo.Meta.TableId, stageInfo.Meta.TableConstInfo, operation); - - if (SystemViewRewrittenResolver->IsSystemView(stageInfo.Meta.TableId.SysViewInfo)) { - continue; - } - - if (stageInfo.Meta.TableKind == ETableKind::Olap) { - if (TableRequestIds.find(stageInfo.Meta.TableId) == TableRequestIds.end()) { + if (tableInfo) { + if (ResolvingNamesFinished) { + AFL_ENSURE(stageInfo.Meta.TableId); + TablePathsById.emplace(stageInfo.Meta.TableId, tableInfo->Path); + stageInfo.Meta.TableKind = tableInfo->TableKind; + + stageInfo.Meta.ShardKey = ExtractKey(stageInfo.Meta.TableId, stageInfo.Meta.TableConstInfo, operation); + + if (SystemViewRewrittenResolver->IsSystemView(stageInfo.Meta.TableId.SysViewInfo)) { + continue; + } + + if (stageInfo.Meta.TableKind == ETableKind::Olap) { + if (TableRequestIds.find(stageInfo.Meta.TableId) == TableRequestIds.end()) { + auto& entry = requestNavigate->ResultSet.emplace_back(); + entry.TableId = stageInfo.Meta.TableId; + entry.RequestType = NSchemeCache::TSchemeCacheNavigate::TEntry::ERequestType::ByTableId; + entry.Operation = NSchemeCache::TSchemeCacheNavigate::EOp::OpTable; + } + + TableRequestIds[stageInfo.Meta.TableId].emplace_back(pair.first); + } + + auto& entry = request->ResultSet.emplace_back(std::move(stageInfo.Meta.ShardKey)); + entry.UserData = EncodeStageInfo(stageInfo); + switch (operation) { + case TKeyDesc::ERowOperation::Read: + entry.Access = NACLib::EAccessRights::SelectRow; + break; + case TKeyDesc::ERowOperation::Update: + entry.Access = NACLib::EAccessRights::UpdateRow; + break; + case TKeyDesc::ERowOperation::Erase: + entry.Access = NACLib::EAccessRights::EraseRow; + break; + default: + YQL_ENSURE(false, "Unsupported row operation mode: " << (ui32)operation); + } + } + } else if (!ResolvingNamesFinished) { + // CTAS + AFL_ENSURE(!stageInfo.Meta.TableId); + AFL_ENSURE(stageInfo.Meta.TablePath); + const auto splittedPath = SplitPath(stageInfo.Meta.TablePath); + const auto canonizedPath = CanonizePath(splittedPath); + if (TableRequestPathes.find(canonizedPath) == TableRequestPathes.end()) { auto& entry = requestNavigate->ResultSet.emplace_back(); - entry.TableId = stageInfo.Meta.TableId; - entry.RequestType = NSchemeCache::TSchemeCacheNavigate::TEntry::ERequestType::ByTableId; + entry.Path = std::move(splittedPath); + entry.RequestType = NSchemeCache::TSchemeCacheNavigate::TEntry::ERequestType::ByPath; entry.Operation = NSchemeCache::TSchemeCacheNavigate::EOp::OpTable; } - TableRequestIds[stageInfo.Meta.TableId].emplace_back(pair.first); - } + TableRequestPathes[canonizedPath].emplace_back(pair.first); + if (requestNavigate->DatabaseName.empty()) { + requestNavigate->DatabaseName = TasksGraph.GetMeta().Database; + } + } else { + // CTAS + AFL_ENSURE(stageInfo.Meta.TableId); + AFL_ENSURE(stageInfo.Meta.TablePath); + + TablePathsById.emplace(stageInfo.Meta.TableId, stageInfo.Meta.TablePath); - auto& entry = request->ResultSet.emplace_back(std::move(stageInfo.Meta.ShardKey)); - entry.UserData = EncodeStageInfo(stageInfo); - switch (operation) { - case TKeyDesc::ERowOperation::Read: - entry.Access = NACLib::EAccessRights::SelectRow; - break; - case TKeyDesc::ERowOperation::Update: - entry.Access = NACLib::EAccessRights::UpdateRow; - break; - case TKeyDesc::ERowOperation::Erase: - entry.Access = NACLib::EAccessRights::EraseRow; - break; - default: - YQL_ENSURE(false, "Unsupported row operation mode: " << (ui32)operation); + auto& entry = request->ResultSet.emplace_back(std::move(stageInfo.Meta.ShardKey)); + entry.UserData = EncodeStageInfo(stageInfo); + AFL_ENSURE(operation == TKeyDesc::ERowOperation::Update); // CTAS is Update operation + entry.Access = NACLib::EAccessRights::UpdateRow; } } } } + + if (!ResolvingNamesFinished) { + Send(MakeSchemeCacheID(), new TEvTxProxySchemeCache::TEvNavigateKeySet(requestNavigate.release())); + Become(&TKqpTableResolver::ResolveNamesState); + return; + } + if (requestNavigate->ResultSet.size()) { Send(MakeSchemeCacheID(), new TEvTxProxySchemeCache::TEvNavigateKeySet(requestNavigate.release())); } else { NavigationFinished = true; } Send(MakeSchemeCacheID(), new TEvTxProxySchemeCache::TEvResolveKeySet(request)); + Become(&TKqpTableResolver::ResolveKeysState); } private: THolder ExtractKey(const TTableId& table, const TIntrusiveConstPtr& tableInfo, TKeyDesc::ERowOperation operation) { - auto range = GetFullRange(tableInfo->KeyColumnTypes.size()); + return ExtractKey(table, tableInfo->KeyColumnTypes, operation); + } - return MakeHolder(table, range.ToTableRange(), operation, tableInfo->KeyColumnTypes, - TVector{}); + THolder ExtractKey(const TTableId& table, const TVector& keyTypes, TKeyDesc::ERowOperation operation) { + auto range = GetFullRange(keyTypes.size()); + return MakeHolder(table, range.ToTableRange(), operation, keyTypes, TVector{}); } static TSerializedTableRange GetFullRange(ui32 columnsCount) { @@ -266,7 +486,9 @@ class TKqpTableResolver : public TActorBootstrapped { const ui64 TxId; TIntrusiveConstPtr UserToken; THashMap> TableRequestIds; + THashMap> TableRequestPathes; THashMap TablePathsById; + bool ResolvingNamesFinished = false; bool NavigationFinished = false; bool ResolvingFinished = false; diff --git a/ydb/core/kqp/executer_actor/kqp_tasks_graph.cpp b/ydb/core/kqp/executer_actor/kqp_tasks_graph.cpp index 21c23995f0e3..564964f1e885 100644 --- a/ydb/core/kqp/executer_actor/kqp_tasks_graph.cpp +++ b/ydb/core/kqp/executer_actor/kqp_tasks_graph.cpp @@ -148,14 +148,17 @@ void FillKqpTasksGraphStages(TKqpTasksGraph& tasksGraph, const TVectorGetTableConstInfoById()->Map.at(meta.TableId); + + if (settings.GetType() != NKikimrKqp::TKqpTableSinkSettings::MODE_FILL) { + meta.TableId = MakeTableId(settings.GetTable()); + meta.TableConstInfo = tx.Body->GetTableConstInfoById()->Map.at(meta.TableId); + } } } diff --git a/ydb/core/kqp/executer_actor/kqp_tasks_graph.h b/ydb/core/kqp/executer_actor/kqp_tasks_graph.h index 1c8c68f0ea69..043425824220 100644 --- a/ydb/core/kqp/executer_actor/kqp_tasks_graph.h +++ b/ydb/core/kqp/executer_actor/kqp_tasks_graph.h @@ -78,6 +78,7 @@ struct TStageInfoMeta { ETableKind TableKind; TIntrusiveConstPtr TableConstInfo; TIntrusiveConstPtr ColumnTableInfoPtr; + std::optional ResolvedSinkSettings; // CTAS only TVector SkipNullKeys; @@ -272,6 +273,7 @@ struct TTaskMeta { TString TypeMod; TString Name; bool NotNull; + bool IsPrimary = false; }; struct TColumnWrite { @@ -351,6 +353,11 @@ TVector BuildKqpColumns(const Proto& op, TIntrusiveConstPtr< TVector columns; columns.reserve(op.GetColumns().size()); + THashSet keyColumns; + for (auto column : tableInfo->KeyColumns) { + keyColumns.insert(std::move(column)); + } + for (const auto& column : op.GetColumns()) { TTaskMeta::TColumn c; @@ -360,6 +367,7 @@ TVector BuildKqpColumns(const Proto& op, TIntrusiveConstPtr< c.TypeMod = tableColumn.TypeMod; c.Name = column.GetName(); c.NotNull = tableColumn.NotNull; + c.IsPrimary = keyColumns.contains(c.Name); columns.emplace_back(std::move(c)); } diff --git a/ydb/core/kqp/expr_nodes/kqp_expr_nodes.json b/ydb/core/kqp/expr_nodes/kqp_expr_nodes.json index 9f2b033f353b..c286c758e611 100644 --- a/ydb/core/kqp/expr_nodes/kqp_expr_nodes.json +++ b/ydb/core/kqp/expr_nodes/kqp_expr_nodes.json @@ -239,6 +239,17 @@ {"Index": 0, "Name": "Table", "Type": "TKqpTable"} ] }, + { + "Name": "TKqlFillTable", + "Base": "TExprBase", + "Match": {"Type": "Callable", "Name": "KqlFillTable"}, + "Children": [ + {"Index": 0, "Name": "Input", "Type": "TExprBase"}, + {"Index": 1, "Name": "Table", "Type": "TCoAtom"}, + {"Index": 2, "Name": "Cluster", "Type": "TCoAtom"}, + {"Index": 3, "Name": "OriginalPath", "Type": "TCoAtom"} + ] + }, { "Name": "TKqlUpsertRowsBase", "Base": "TKqlTableEffect", @@ -553,10 +564,9 @@ {"Index": 1, "Name": "InconsistentWrite", "Type": "TCoAtom"}, {"Index": 2, "Name": "Mode", "Type": "TCoAtom"}, {"Index": 3, "Name": "Priority", "Type": "TCoAtom"}, - {"Index": 4, "Name": "TableType", "Type": "TCoAtom"}, - {"Index": 5, "Name": "StreamWrite", "Type": "TCoAtom"}, - {"Index": 6, "Name": "IsBatch", "Type": "TCoAtom"}, - {"Index": 7, "Name": "Settings", "Type": "TCoNameValueTupleList", "Optional": true} + {"Index": 4, "Name": "StreamWrite", "Type": "TCoAtom"}, + {"Index": 5, "Name": "IsBatch", "Type": "TCoAtom"}, + {"Index": 6, "Name": "Settings", "Type": "TCoNameValueTupleList", "Optional": true} ] }, { diff --git a/ydb/core/kqp/federated_query/kqp_federated_query_helpers.cpp b/ydb/core/kqp/federated_query/kqp_federated_query_helpers.cpp index c3f5c6759fbc..6bcb9487ad68 100644 --- a/ydb/core/kqp/federated_query/kqp_federated_query_helpers.cpp +++ b/ydb/core/kqp/federated_query/kqp_federated_query_helpers.cpp @@ -8,12 +8,14 @@ #include #include -#include -#include +#include #include +#include #include #include +#include + #include #include #include @@ -23,6 +25,35 @@ #include namespace NKikimr::NKqp { + + bool CheckNestingDepth(const google::protobuf::Message& message, ui32 maxDepth) { + if (!maxDepth) { + return false; + } + --maxDepth; + + const auto* descriptor = message.GetDescriptor(); + const auto* reflection = message.GetReflection(); + for (int i = 0; i < descriptor->field_count(); ++i) { + const auto* field = descriptor->field(i); + if (field->cpp_type() != google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { + continue; + } + + if (field->is_repeated()) { + for (int j = 0; j < reflection->FieldSize(message, field); ++j) { + if (!CheckNestingDepth(reflection->GetRepeatedMessage(message, field, j), maxDepth)) { + return false; + } + } + } else if (reflection->HasField(message, field) && !CheckNestingDepth(reflection->GetMessage(message, field), maxDepth)) { + return false; + } + } + + return true; + } + NYql::IYtGateway::TPtr MakeYtGateway(const NMiniKQL::IFunctionRegistry* functionRegistry, const NKikimrConfig::TQueryServiceConfig& queryServiceConfig) { NYql::TYtNativeServices ytServices; ytServices.FunctionRegistry = functionRegistry; @@ -215,4 +246,28 @@ namespace NKikimr::NKqp { return false; } + + NYql::TIssues TruncateIssues(const NYql::TIssues& issues, ui32 maxLevels, ui32 keepTailLevels) { + const auto options = NYql::TTruncateIssueOpts() + .SetMaxLevels(maxLevels) + .SetKeepTailLevels(keepTailLevels); + + NYql::TIssues result; + result.Reserve(issues.Size()); + for (const auto& issue : issues) { + result.AddIssue(NYql::TruncateIssueLevels(issue, options)); + } + return result; + } + + NYql::TIssues ValidateResultSetColumns(const google::protobuf::RepeatedPtrField& columns, ui32 maxNestingDepth) { + NYql::TIssues issues; + for (const auto& column : columns) { + if (!CheckNestingDepth(column.type(), maxNestingDepth)) { + issues.AddIssue(NYql::TIssue(TStringBuilder() << "Nesting depth of type for result column '" << column.name() << "' large than allowed limit " << maxNestingDepth)); + } + } + return issues; + } + } // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/federated_query/kqp_federated_query_helpers.h b/ydb/core/kqp/federated_query/kqp_federated_query_helpers.h index e15c5946fa75..e379e79f873b 100644 --- a/ydb/core/kqp/federated_query/kqp_federated_query_helpers.h +++ b/ydb/core/kqp/federated_query/kqp_federated_query_helpers.h @@ -12,6 +12,7 @@ #include #include +#include #include @@ -20,6 +21,9 @@ namespace NKikimrConfig { } namespace NKikimr::NKqp { + + bool CheckNestingDepth(const google::protobuf::Message& message, ui32 maxDepth); + NYql::IYtGateway::TPtr MakeYtGateway(const NMiniKQL::IFunctionRegistry* functionRegistry, const NKikimrConfig::TQueryServiceConfig& queryServiceConfig); NYql::IHTTPGateway::TPtr MakeHttpGateway(const NYql::THttpGatewayConfig& httpGatewayConfig, NMonitoring::TDynamicCounterPtr countersRoot); @@ -146,4 +150,16 @@ namespace NKikimr::NKqp { // Used only for unit tests bool WaitHttpGatewayFinalization(NMonitoring::TDynamicCounterPtr countersRoot, TDuration timeout = TDuration::Minutes(1), TDuration refreshPeriod = TDuration::MilliSeconds(100)); + + NYql::TIssues TruncateIssues(const NYql::TIssues& issues, ui32 maxLevels = 50, ui32 keepTailLevels = 3); + + template + void TruncateIssues(google::protobuf::RepeatedPtrField* issuesProto, ui32 maxLevels = 50, ui32 keepTailLevels = 3) { + NYql::TIssues issues; + NYql::IssuesFromMessage(*issuesProto, issues); + NYql::IssuesToMessage(TruncateIssues(issues, maxLevels, keepTailLevels), issuesProto); + } + + NYql::TIssues ValidateResultSetColumns(const google::protobuf::RepeatedPtrField& columns, ui32 maxNestingDepth = 90); + } // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/federated_query/kqp_federated_query_helpers_ut.cpp b/ydb/core/kqp/federated_query/kqp_federated_query_helpers_ut.cpp new file mode 100644 index 000000000000..f5996b0b3410 --- /dev/null +++ b/ydb/core/kqp/federated_query/kqp_federated_query_helpers_ut.cpp @@ -0,0 +1,68 @@ +#include "kqp_federated_query_helpers.h" + +#include + +#include + +#include + +namespace NKikimr::NKqp { + +Y_UNIT_TEST_SUITE(TestFederatedQueryHelpers) { + NYql::TIssue BuildNestedIssues(ui32 depth) { + NYql::TIssue issue("Testing nested issue"); + for (ui32 i = 0; i + 1 < depth; ++i) { + NYql::TIssue nestedIssue(TStringBuilder() << "Nested issue " << i); + nestedIssue.AddSubIssue(MakeIntrusive(issue)); + issue = nestedIssue; + } + return issue; + } + + Y_UNIT_TEST(TestCheckNestingDepth) { + constexpr ui32 depth = 30; + NYql::NIssue::NProto::IssueMessage nestedProto; + NYql::IssueToMessage(BuildNestedIssues(depth), &nestedProto); + + UNIT_ASSERT_C(!CheckNestingDepth(nestedProto, depth - 1), depth - 1); + UNIT_ASSERT_C(CheckNestingDepth(nestedProto, depth), depth); + UNIT_ASSERT_C(CheckNestingDepth(nestedProto, depth + 1), depth + 1); + } + + Y_UNIT_TEST(TestTruncateIssues) { + constexpr ui32 depth = 30; + NYql::TIssue issue = BuildNestedIssues(depth); + + constexpr ui32 maxLevels = 10; + constexpr ui32 keepTailLevels = 3; + const auto truncated = TruncateIssues({issue}, maxLevels, keepTailLevels); + UNIT_ASSERT_VALUES_EQUAL(truncated.Size(), 1); + + NYql::NIssue::NProto::IssueMessage nestedProto; + NYql::IssueToMessage(*truncated.begin(), &nestedProto); + UNIT_ASSERT(CheckNestingDepth(nestedProto, maxLevels + keepTailLevels)); + } + + Y_UNIT_TEST(TestValidateResultSetColumns) { + constexpr ui32 depth = 30; + + Ydb::Type type; + type.set_type_id(Ydb::Type::INT32); + for (ui32 i = 0; i < depth; ++i) { + Ydb::Type nestedType; + *nestedType.mutable_optional_type()->mutable_item() = type; + type = nestedType; + } + + Ydb::Query::ResultSetMeta meta; + *meta.add_columns()->mutable_type() = type; + + auto issues = ValidateResultSetColumns(meta.columns(), 2 * depth); + UNIT_ASSERT_C(!issues.Empty(), 2 * depth); + + issues = ValidateResultSetColumns(meta.columns(), 2 * depth + 1); + UNIT_ASSERT_C(issues.Empty(), issues.ToOneLineString()); + } +} + +} // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/federated_query/ut/ya.make b/ydb/core/kqp/federated_query/ut/ya.make new file mode 100644 index 000000000000..6570bfc7a3fe --- /dev/null +++ b/ydb/core/kqp/federated_query/ut/ya.make @@ -0,0 +1,20 @@ +UNITTEST_FOR(ydb/core/kqp/federated_query) + +PEERDIR( + ydb/core/kqp/federated_query + ydb/public/api/protos + yql/essentials/minikql/comp_nodes/llvm16 + yql/essentials/public/issue/protos + yql/essentials/public/udf/service/stub + yql/essentials/sql/pg_dummy + yt/yql/providers/yt/comp_nodes/dq/llvm16 + yt/yql/providers/yt/comp_nodes/llvm16 +) + +SRCS( + kqp_federated_query_helpers_ut.cpp +) + +YQL_LAST_ABI_VERSION() + +END() diff --git a/ydb/core/kqp/federated_query/ya.make b/ydb/core/kqp/federated_query/ya.make index 8eb6742cff99..519f4e92a737 100644 --- a/ydb/core/kqp/federated_query/ya.make +++ b/ydb/core/kqp/federated_query/ya.make @@ -12,8 +12,10 @@ PEERDIR( ydb/library/db_pool/protos ydb/library/yql/providers/common/http_gateway ydb/library/yql/providers/generic/connector/libcpp + ydb/library/yql/providers/s3/actors_factory ydb/library/yql/providers/solomon/gateway yql/essentials/core/dq_integration/transform + yql/essentials/public/issue yt/yql/providers/yt/gateway/native yt/yql/providers/yt/lib/yt_download yt/yql/providers/yt/mkql_dq @@ -22,3 +24,7 @@ PEERDIR( YQL_LAST_ABI_VERSION() END() + +RECURSE_FOR_TESTS( + ut +) diff --git a/ydb/core/kqp/gateway/behaviour/external_data_source/manager.cpp b/ydb/core/kqp/gateway/behaviour/external_data_source/manager.cpp index 7668434f045b..f6b151e11a04 100644 --- a/ydb/core/kqp/gateway/behaviour/external_data_source/manager.cpp +++ b/ydb/core/kqp/gateway/behaviour/external_data_source/manager.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace NKikimr::NKqp { @@ -87,11 +88,22 @@ TString GetOrEmpty(const NYql::TCreateObjectSettings& container, const TString& "service_name", // oracle "folder_id", // logging "use_ssl", // solomon - "grpc_port" // solomon + "grpc_port", // solomon + "reading_mode", // mongodb + "unexpected_type_display_mode", // mongodb + "unsupported_type_display_mode", // mongodb }; auto& featuresExtractor = settings.GetFeaturesExtractor(); - for (const auto& property: properties) { + + for (const auto& property : properties) { + if (const auto value = featuresExtractor.Extract(property)) { + externaDataSourceDesc.MutableProperties()->MutableProperties()->insert({property, *value}); + } + } + + // Iceberg properties for connector + for (const auto& property : NKikimr::NExternalSource::NIceberg::FieldsToConnector) { if (const auto value = featuresExtractor.Extract(property)) { externaDataSourceDesc.MutableProperties()->MutableProperties()->insert({property, *value}); } diff --git a/ydb/core/kqp/gateway/kqp_gateway.cpp b/ydb/core/kqp/gateway/kqp_gateway.cpp index a0e5f9ac0820..3ad7e7873041 100644 --- a/ydb/core/kqp/gateway/kqp_gateway.cpp +++ b/ydb/core/kqp/gateway/kqp_gateway.cpp @@ -1,4 +1,33 @@ #include "kqp_gateway.h" + namespace NKikimr::NKqp { +void IKqpGateway::TExecPhysicalRequest::FillRequestFrom(IKqpGateway::TExecPhysicalRequest& request, const IKqpGateway::TExecPhysicalRequest& from) { + request.AllowTrailingResults = from.AllowTrailingResults; + request.QueryType = from.QueryType; + request.PerRequestDataSizeLimit = from.PerRequestDataSizeLimit; + request.MaxShardCount = from.MaxShardCount; + request.DataShardLocks = from.DataShardLocks; + request.LocksOp = from.LocksOp; + request.AcquireLocksTxId = from.AcquireLocksTxId; + request.Timeout = from.Timeout; + request.CancelAfter = from.CancelAfter; + request.MaxComputeActors = from.MaxComputeActors; + request.MaxAffectedShards = from.MaxAffectedShards; + request.TotalReadSizeLimitBytes = from.TotalReadSizeLimitBytes; + request.MkqlMemoryLimit = from.MkqlMemoryLimit; + request.PerShardKeysSizeLimitBytes = from.PerShardKeysSizeLimitBytes; + request.StatsMode = from.StatsMode; + request.ProgressStatsPeriod = from.ProgressStatsPeriod; + request.Snapshot = from.Snapshot; + request.ResourceManager_ = from.ResourceManager_; + request.CaFactory_ = from.CaFactory_; + request.IsolationLevel = from.IsolationLevel; + request.RlPath = from.RlPath; + request.NeedTxId = from.NeedTxId; + request.UseImmediateEffects = from.UseImmediateEffects; + request.UserTraceId = from.UserTraceId; + request.OutputChunkMaxSize = from.OutputChunkMaxSize; +} + } diff --git a/ydb/core/kqp/gateway/kqp_gateway.h b/ydb/core/kqp/gateway/kqp_gateway.h index 8c482eea0005..91eaac14d2dc 100644 --- a/ydb/core/kqp/gateway/kqp_gateway.h +++ b/ydb/core/kqp/gateway/kqp_gateway.h @@ -135,6 +135,8 @@ class IKqpGateway : public NYql::IKikimrGateway { : TxAlloc(txAlloc) {} + static void FillRequestFrom(IKqpGateway::TExecPhysicalRequest& request, const IKqpGateway::TExecPhysicalRequest& from); + bool AllowTrailingResults = false; NKikimrKqp::EQueryType QueryType = NKikimrKqp::EQueryType::QUERY_TYPE_UNDEFINED; NKikimr::TControlWrapper PerRequestDataSizeLimit; diff --git a/ydb/core/kqp/host/kqp_explain_prepared.cpp b/ydb/core/kqp/host/kqp_explain_prepared.cpp index f76ce851140c..d116a2577804 100644 --- a/ydb/core/kqp/host/kqp_explain_prepared.cpp +++ b/ydb/core/kqp/host/kqp_explain_prepared.cpp @@ -65,7 +65,7 @@ class TKqpExplainPreparedTransformer : public NYql::TGraphTransformerBase { } PhyQuerySetTxPlans(query, TKqpPhysicalQuery(TransformCtx->ExplainTransformerInput), std::move(TxResults), - ctx, Cluster, TransformCtx->Tables, TransformCtx->Config, TypeCtx, OptimizeCtx); + ctx, Gateway->GetDatabase(), Cluster, TransformCtx->Tables, TransformCtx->Config, TypeCtx, OptimizeCtx); query.SetQueryAst(KqpExprToPrettyString(*input, ctx)); TransformCtx->ExplainTransformerInput = nullptr; diff --git a/ydb/core/kqp/host/kqp_gateway_proxy.cpp b/ydb/core/kqp/host/kqp_gateway_proxy.cpp index 11cf4998af41..3cfa732ec9b0 100644 --- a/ydb/core/kqp/host/kqp_gateway_proxy.cpp +++ b/ydb/core/kqp/host/kqp_gateway_proxy.cpp @@ -2658,7 +2658,7 @@ class TKqpGatewayProxy : public IKikimrGateway { target.SetDstPath(AdjustPath(dst, GetDatabase())); target.SetTransformLambda(lambda); if (settings.Settings.Batching && settings.Settings.Batching->BatchSizeBytes) { - config.MutableTransferSpecific()->MutableBatching()->SetBatchSizeBytes(settings.Settings.Batching->BatchSizeBytes); + config.MutableTransferSpecific()->MutableBatching()->SetBatchSizeBytes(settings.Settings.Batching->BatchSizeBytes.value()); } if (settings.Settings.Batching && settings.Settings.Batching->FlushInterval) { config.MutableTransferSpecific()->MutableBatching()->SetFlushIntervalMilliSeconds(settings.Settings.Batching->FlushInterval.MilliSeconds()); @@ -2716,7 +2716,7 @@ class TKqpGatewayProxy : public IKikimrGateway { op.MutableAlterTransfer()->SetFlushIntervalMilliSeconds(batching->FlushInterval.MilliSeconds()); } if (batching->BatchSizeBytes) { - op.MutableAlterTransfer()->SetBatchSizeBytes(batching->BatchSizeBytes); + op.MutableAlterTransfer()->SetBatchSizeBytes(batching->BatchSizeBytes.value()); } } diff --git a/ydb/core/kqp/host/kqp_runner.cpp b/ydb/core/kqp/host/kqp_runner.cpp index 2c11d6ad2a87..2064dde139a9 100644 --- a/ydb/core/kqp/host/kqp_runner.cpp +++ b/ydb/core/kqp/host/kqp_runner.cpp @@ -221,6 +221,10 @@ class TKqpRunner : public IKqpRunner { std::begin(operations), std::end(operations), [this](const auto& operation) { + if (operation.Operation() == "FillTable") { + // FillTable operation compiles without existing table. + return false; + } const auto& tableData = SessionCtx->Tables().ExistingTable(operation.Cluster(), operation.Table()); return tableData.Metadata->IsOlap(); }); diff --git a/ydb/core/kqp/host/kqp_statement_rewrite.cpp b/ydb/core/kqp/host/kqp_statement_rewrite.cpp index 750b103c5b9d..8d1a7ac85ba0 100644 --- a/ydb/core/kqp/host/kqp_statement_rewrite.cpp +++ b/ydb/core/kqp/host/kqp_statement_rewrite.cpp @@ -215,10 +215,14 @@ namespace { const auto name = item->GetName(); auto currentType = item->GetItemType(); + // All CTAS columns are created as nullable columns. Exception: primary keys for OLAP table. const bool notNull = primariKeyColumns.contains(name) && isOlap; if (notNull && currentType->GetKind() == NYql::ETypeAnnotationKind::Optional) { - currentType = currentType->Cast()->GetItemType(); + exprCtx.AddError(NYql::TIssue( + exprCtx.GetPosition(pos), + TStringBuilder() << "Can't create column table with nullable primary key column `" << name << "`.")); + return std::nullopt; } auto typeNode = NYql::ExpandType(pos, *currentType, exprCtx); @@ -286,7 +290,12 @@ namespace { insertSettings.push_back( exprCtx.NewList(pos, { exprCtx.NewAtom(pos, "mode"), - exprCtx.NewAtom(pos, "replace"), + exprCtx.NewAtom(pos, "fill_table"), + })); + insertSettings.push_back( + exprCtx.NewList(pos, { + exprCtx.NewAtom(pos, "OriginalPath"), + exprCtx.NewAtom(pos, tableName), })); insertSettings.push_back( exprCtx.NewList(pos, { diff --git a/ydb/core/kqp/host/kqp_type_ann.cpp b/ydb/core/kqp/host/kqp_type_ann.cpp index 2c4aed2bcc73..4be670f8a4e1 100644 --- a/ydb/core/kqp/host/kqp_type_ann.cpp +++ b/ydb/core/kqp/host/kqp_type_ann.cpp @@ -87,6 +87,11 @@ TStatus AnnotateTable(const TExprNode::TPtr& node, TExprContext& ctx, const TStr return TStatus::Error; } + if (pathId->Content() == "") { + node->SetTypeAnn(ctx.MakeType()); + return TStatus::Ok; + } + TString tablePath(path->Content()); auto tableDesc = tablesData.EnsureTableExists(cluster, tablePath, node->Pos(), ctx); if (!tableDesc) { @@ -606,6 +611,46 @@ TStatus AnnotateKeyTuple(const TExprNode::TPtr& node, TExprContext& ctx) { return TStatus::Ok; } +TStatus AnnotateFillTable(const TExprNode::TPtr& node, TExprContext& ctx) +{ + if (!EnsureMinMaxArgsCount(*node, 4, 4, ctx)) { + return TStatus::Error; + } + + const auto* input = node->Child(TKqlFillTable::idx_Input); + + AFL_ENSURE(input->GetTypeAnn()); + + const TTypeAnnotationNode* itemType = nullptr; + bool isStream = false; + if (input->GetTypeAnn()->GetKind() == ETypeAnnotationKind::Stream) { + if (!EnsureStreamType(*input, ctx)) { + return TStatus::Error; + } + itemType = input->GetTypeAnn()->Cast()->GetItemType(); + isStream = true; + } else { + if (!EnsureListType(*input, ctx)) { + return TStatus::Error; + } + itemType = input->GetTypeAnn()->Cast()->GetItemType(); + isStream = false; + } + + if (!EnsureStructType(input->Pos(), *itemType, ctx)) { + return TStatus::Error; + } + + auto effectType = MakeKqpEffectType(ctx); + if (isStream) { + node->SetTypeAnn(ctx.MakeType(effectType)); + } else { + node->SetTypeAnn(ctx.MakeType(effectType)); + } + + return TStatus::Ok; +} + TStatus AnnotateUpsertRows(const TExprNode::TPtr& node, TExprContext& ctx, const TString& cluster, const TKikimrTablesData& tablesData) { @@ -1913,6 +1958,10 @@ TAutoPtr CreateKqpTypeAnnotationTransformer(const TString& cl return AnnotateKeyTuple(input, ctx); } + if (TKqlFillTable::Match(input.Get())) { + return AnnotateFillTable(input, ctx); + } + if (TKqlUpsertRowsBase::Match(input.Get())) { return AnnotateUpsertRows(input, ctx, cluster, *tablesData); } diff --git a/ydb/core/kqp/node_service/kqp_node_service.cpp b/ydb/core/kqp/node_service/kqp_node_service.cpp index 22ecddfe7518..5d795c6f9df6 100644 --- a/ydb/core/kqp/node_service/kqp_node_service.cpp +++ b/ydb/core/kqp/node_service/kqp_node_service.cpp @@ -43,7 +43,7 @@ namespace { // Min interval between stats send from scan/compute actor to executor constexpr TDuration MinStatInterval = TDuration::MilliSeconds(20); // Max interval in case of no activety -constexpr TDuration MaxStatInterval = TDuration::MilliSeconds(100); +constexpr TDuration MaxStatInterval = TDuration::Seconds(1); template TString TasksIdsStr(const TTasksCollection& tasks) { diff --git a/ydb/core/kqp/opt/kqp_opt_build_txs.cpp b/ydb/core/kqp/opt/kqp_opt_build_txs.cpp index 2c1c856bc03f..a1b0acf3e4c6 100644 --- a/ydb/core/kqp/opt/kqp_opt_build_txs.cpp +++ b/ydb/core/kqp/opt/kqp_opt_build_txs.cpp @@ -607,8 +607,10 @@ class TKqpBuildTxsTransformer : public TSyncTransformerBase { } else { // Two table sinks can't be executed in one physical transaction if they write into same table and have same priority. - const auto& tableDescription = kqpCtx.Tables->ExistingTable(kqpCtx.Cluster, sinkSettings.Cast().Table().Path()); - if (tableDescription.Metadata->Kind == EKikimrTableKind::Olap) { + const bool needSingleEffect = sinkSettings.Cast().Mode() == "fill_table" + || (kqpCtx.Tables->ExistingTable(kqpCtx.Cluster, sinkSettings.Cast().Table().Path()).Metadata->Kind == EKikimrTableKind::Olap); + + if (needSingleEffect) { const TStringBuf tablePathId = sinkSettings.Cast().Table().PathId().Value(); auto it = std::find_if( diff --git a/ydb/core/kqp/opt/kqp_opt_effects.cpp b/ydb/core/kqp/opt/kqp_opt_effects.cpp index d8f84f5176ed..b308093193e8 100644 --- a/ydb/core/kqp/opt/kqp_opt_effects.cpp +++ b/ydb/core/kqp/opt/kqp_opt_effects.cpp @@ -232,10 +232,14 @@ TCoAtomList BuildKeyColumnsList(const TKikimrTableDescription& table, TPositionH } TDqStage RebuildPureStageWithSink(TExprBase expr, const TKqpTable& table, - const bool allowInconsistentWrites, const bool enableStreamWrite, const TCoAtom& isBatch, - const TStringBuf mode, const i64 order, const bool isOlap, TExprContext& ctx) { + const bool allowInconsistentWrites, const bool enableStreamWrite, bool isBatch, + const TStringBuf mode, const TVector& settings, const i64 order, TExprContext& ctx) { Y_DEBUG_ABORT_UNLESS(IsDqPureExpr(expr)); + auto settingsNode = Build(ctx, expr.Pos()) + .Add(settings) + .Done(); + return Build(ctx, expr.Pos()) .Inputs() .Build() @@ -262,10 +266,10 @@ TDqStage RebuildPureStageWithSink(TExprBase expr, const TKqpTable& table, : ctx.NewAtom(expr.Pos(), "false")) .Mode(ctx.NewAtom(expr.Pos(), mode)) .Priority(ctx.NewAtom(expr.Pos(), ToString(order))) - .TableType(ctx.NewAtom(expr.Pos(), isOlap ? "olap" : "oltp")) - .IsBatch(isBatch) - .Settings() - .Build() + .IsBatch(isBatch + ? ctx.NewAtom(expr.Pos(), "true") + : ctx.NewAtom(expr.Pos(), "false")) + .Settings(settingsNode) .Build() .Build() .Build() @@ -302,6 +306,101 @@ TDqPhyPrecompute BuildPrecomputeStage(TExprBase expr, TExprContext& ctx) { .Done(); } +bool BuildFillTableEffect(const TKqlFillTable& node, TExprContext& ctx, + TMaybeNode& stageInput, TMaybeNode& effect, bool& sinkEffect, const i64 order) +{ + sinkEffect = true; + const i64 priority = 0; + AFL_ENSURE(order == 0); + + const TKqpTable table = Build(ctx, node.Pos()) + .Path(node.Table()) + .PathId(ctx.NewAtom(node.Pos(), "")) + .SysView(ctx.NewAtom(node.Pos(), "")) + .Version(ctx.NewAtom(node.Pos(), "")) + .Done(); + + TVector settings; + settings.emplace_back( + Build(ctx, node.Pos()) + .Name().Build("OriginalPath") + .Value().Build(node.OriginalPath()) + .Done()); + + if (IsDqPureExpr(node.Input())) { + stageInput = RebuildPureStageWithSink( + node.Input(), table, + /* allowInconsistentWrites */ true, /* useStreamWrite */ true, + /* isBatch */ false, "fill_table", settings, + priority, ctx); + effect = Build(ctx, node.Pos()) + .Stage(stageInput.Cast().Ptr()) + .SinkIndex().Build("0") + .Done(); + return true; + } + + if (!EnsureDqUnion(node.Input(), ctx)) { + return false; + } + + auto settingsNode = Build(ctx, node.Pos()) + .Add(settings) + .Done(); + + auto dqUnion = node.Input().Cast(); + auto stage = dqUnion.Output().Stage(); + auto program = stage.Program(); + auto input = program.Body(); + + auto sink = Build(ctx, node.Pos()) + .DataSink() + .Category(ctx.NewAtom(node.Pos(), NYql::KqpTableSinkName)) + .Cluster(ctx.NewAtom(node.Pos(), "db")) + .Build() + .Index().Value("0").Build() + .Settings() + .Table(table) + .InconsistentWrite(ctx.NewAtom(node.Pos(), "true")) + .StreamWrite(ctx.NewAtom(node.Pos(), "true")) + .Mode(ctx.NewAtom(node.Pos(), "fill_table")) + .Priority(ctx.NewAtom(node.Pos(), ToString(priority))) + .IsBatch(ctx.NewAtom(node.Pos(), "false")) + .Settings(settingsNode) + .Build() + .Done(); + + const auto rowArgument = Build(ctx, node.Pos()) + .Name("row") + .Done(); + + auto mapCn = Build(ctx, node.Pos()) + .Output(dqUnion.Output()) + .Done(); + stageInput = Build(ctx, node.Pos()) + .Inputs() + .Add(mapCn) + .Build() + .Program() + .Args({rowArgument}) + .Body() + .Input(rowArgument) + .Build() + .Build() + .Outputs() + .Add(sink) + .Build() + .Settings().Build() + .Done(); + + effect = Build(ctx, node.Pos()) + .Stage(stageInput.Cast().Ptr()) + .SinkIndex().Build("0") + .Done(); + + return true; +} + bool BuildUpsertRowsEffect(const TKqlUpsertRows& node, TExprContext& ctx, const TKqpOptimizeContext& kqpCtx, const TCoArgument& inputArg, TMaybeNode& stageInput, TMaybeNode& effect, bool& sinkEffect, const i64 order) { @@ -326,7 +425,7 @@ bool BuildUpsertRowsEffect(const TKqlUpsertRows& node, TExprContext& ctx, const stageInput = RebuildPureStageWithSink( node.Input(), node.Table(), settings.AllowInconsistentWrites, useStreamWrite, - node.IsBatch(), settings.Mode, priority, isOlap, ctx); + node.IsBatch() == "true", settings.Mode, {}, priority, ctx); effect = Build(ctx, node.Pos()) .Stage(stageInput.Cast().Ptr()) .SinkIndex().Build("0") @@ -371,7 +470,6 @@ bool BuildUpsertRowsEffect(const TKqlUpsertRows& node, TExprContext& ctx, const : ctx.NewAtom(node.Pos(), "false")) .Mode(ctx.NewAtom(node.Pos(), settings.Mode)) .Priority(ctx.NewAtom(node.Pos(), ToString(priority))) - .TableType(ctx.NewAtom(node.Pos(), isOlap ? "olap" : "oltp")) .IsBatch(node.IsBatch()) .Settings() .Build() @@ -488,8 +586,8 @@ bool BuildDeleteRowsEffect(const TKqlDeleteRows& node, TExprContext& ctx, const const auto keyColumns = BuildKeyColumnsList(table, node.Pos(), ctx); stageInput = RebuildPureStageWithSink( node.Input(), node.Table(), - false, useStreamWrite, node.IsBatch(), - "delete", priority, isOlap, ctx); + false, useStreamWrite, node.IsBatch() == "true", + "delete", {}, priority, ctx); effect = Build(ctx, node.Pos()) .Stage(stageInput.Cast().Ptr()) .SinkIndex().Build("0") @@ -530,7 +628,6 @@ bool BuildDeleteRowsEffect(const TKqlDeleteRows& node, TExprContext& ctx, const : ctx.NewAtom(node.Pos(), "false")) .Mode(ctx.NewAtom(node.Pos(), "delete")) .Priority(ctx.NewAtom(node.Pos(), ToString(priority))) - .TableType(ctx.NewAtom(node.Pos(), isOlap ? "olap" : "oltp")) .IsBatch(node.IsBatch()) .Settings() .Build() @@ -627,8 +724,23 @@ bool BuildEffects(TPositionHandle pos, const TVector& effects, for (const auto& effect : effects) { TMaybeNode newEffect; bool sinkEffect = false; - YQL_ENSURE(effect.Maybe()); - if (effect.Maybe()) { + if (effect.Maybe()) { + TMaybeNode input; + TCoArgument inputArg = Build(ctx, pos) + .Name("inputArg") + .Done(); + const auto maybeFillTable = effect.Maybe(); + AFL_ENSURE(maybeFillTable); + if (!BuildFillTableEffect(maybeFillTable.Cast(), ctx, input, newEffect, sinkEffect, order)) { + return false; + } + ++order; + + if (input) { + inputArgs.push_back(inputArg); + inputs.push_back(input.Cast()); + } + } else if (effect.Maybe()) { TMaybeNode input; TCoArgument inputArg = Build(ctx, pos) .Name("inputArg") diff --git a/ydb/core/kqp/opt/kqp_opt_kql.cpp b/ydb/core/kqp/opt/kqp_opt_kql.cpp index e17184b0f9ca..c475fddf2e44 100644 --- a/ydb/core/kqp/opt/kqp_opt_kql.cpp +++ b/ydb/core/kqp/opt/kqp_opt_kql.cpp @@ -204,6 +204,10 @@ TExprNode::TPtr GetPgNotNullColumns( TExprNode::TPtr IsUpdateSetting(TExprContext& ctx, const TPositionHandle& pos) { return Build(ctx, pos) + .Add() + .Name().Build("Mode") + .Value().Build("update") + .Build() .Add() .Name().Build("IsUpdate") .Build() @@ -212,6 +216,10 @@ TExprNode::TPtr IsUpdateSetting(TExprContext& ctx, const TPositionHandle& pos) { TExprNode::TPtr IsConditionalUpdateSetting(TExprContext& ctx, const TPositionHandle& pos) { return Build(ctx, pos) + .Add() + .Name().Build("Mode") + .Value().Build("update") + .Build() .Add() .Name().Build("IsUpdate") .Build() @@ -300,6 +308,18 @@ TCoAtomList ExtendGenerateOnInsertColumnsList(const TKiWriteTable& write, TCoAto return Build(ctx, write.Pos()).Add(result).Done(); } +TExprBase BuildFillTable(const TKiWriteTable& write, TExprContext& ctx) +{ + auto originalPathNode = GetSetting(write.Settings().Ref(), "OriginalPath"); + AFL_ENSURE(originalPathNode); + return Build(ctx, write.Pos()) + .Input(write.Input()) + .Table(write.Table()) + .Cluster(write.DataSink().Cluster()) + .OriginalPath(TCoNameValueTuple(originalPathNode).Value().Cast()) + .Done(); +} + TExprBase BuildUpsertTable(const TKiWriteTable& write, const TCoAtomList& inputColumns, const TCoAtomList& autoincrement, const bool isSink, const TKikimrTableDescription& table, TExprContext& ctx) @@ -893,6 +913,9 @@ TExprBase WriteTableWithIndexUpdate(const TKiWriteTable& write, const TCoAtomLis TExprNode::TPtr HandleWriteTable(const TKiWriteTable& write, TExprContext& ctx, TKqpOptimizeContext& kqpCtx, const TKikimrTablesData& tablesData) { + if (GetTableOp(write) == TYdbOperation::FillTable) { + return BuildFillTable(write, ctx).Ptr(); + } auto& tableData = GetTableData(tablesData, write.DataSink().Cluster(), write.Table().Value()); const bool isSink = NeedSinks(tableData, kqpCtx); diff --git a/ydb/core/kqp/opt/kqp_query_plan.cpp b/ydb/core/kqp/opt/kqp_query_plan.cpp index 38a73f5b72ef..346bc14b7049 100644 --- a/ydb/core/kqp/opt/kqp_query_plan.cpp +++ b/ydb/core/kqp/opt/kqp_query_plan.cpp @@ -96,13 +96,15 @@ struct TExprScope { }; struct TSerializerCtx { - TSerializerCtx(TExprContext& exprCtx, const TString& cluster, + TSerializerCtx(TExprContext& exprCtx, const TString& database, + const TString& cluster, const TIntrusivePtr tablesData, const TKikimrConfiguration::TPtr config, ui32 txCount, TVector> pureTxResults, TTypeAnnotationContext& typeCtx, TIntrusivePtr optCtx) : ExprCtx(exprCtx) + , Database(database) , Cluster(cluster) , TablesData(tablesData) , Config(config) @@ -120,6 +122,7 @@ struct TSerializerCtx { ui32 PlanNodeId = 0; const TExprContext& ExprCtx; + const TString Database; const TString& Cluster; const TIntrusivePtr TablesData; const TKikimrConfiguration::TPtr Config; @@ -813,6 +816,7 @@ class TxPlanSerializer { if (dataSinkCategory == NYql::KqpTableSinkName) { auto settings = sink.Settings().Cast(); + TString tablePath; TTableWrite writeInfo; if (settings.Mode().StringValue() == "replace") { op.Properties["Name"] = "Replace"; @@ -829,14 +833,32 @@ class TxPlanSerializer { } else if (settings.Mode().StringValue() == "update") { op.Properties["Name"] = "Update"; writeInfo.Type = EPlanTableWriteType::MultiUpdate; + } else if (settings.Mode().StringValue() == "fill_table") { + op.Properties["Name"] = "FillTable"; + writeInfo.Type = EPlanTableWriteType::MultiReplace; } else { YQL_ENSURE(false, "Unsupported sink mode"); } - const auto tablePath = settings.Table().Path().StringValue(); - const auto& tableData = SerializerCtx.TablesData->GetTable(SerializerCtx.Cluster, tablePath); - op.Properties["Table"] = tableData.RelativePath ? *tableData.RelativePath : tablePath; - op.Properties["Path"] = tablePath; + if (settings.Mode().StringValue() != "fill_table") { + tablePath = settings.Table().Path().StringValue(); + const auto& tableData = SerializerCtx.TablesData->GetTable(SerializerCtx.Cluster, tablePath); + op.Properties["Table"] = tableData.RelativePath ? *tableData.RelativePath : tablePath; + op.Properties["Path"] = tablePath; + } else { + const auto originalPathNode = GetSetting(settings.Settings().Ref(), "OriginalPath"); + AFL_ENSURE(originalPathNode); + tablePath = TCoNameValueTuple(originalPathNode).Value().Cast().StringValue(); + op.Properties["Path"] = tablePath; + + TString error; + std::pair pathPair; + if (NKikimr::TrySplitPathByDb(tablePath, SerializerCtx.Database, pathPair, error)) { + op.Properties["Table"]= pathPair.second; + } else { + op.Properties["Table"] = tablePath; + } + } if (writeInfo.Type != EPlanTableWriteType::MultiErase) { const auto& tupleType = stage.Ref().GetTypeAnn()->Cast(); @@ -2632,11 +2654,11 @@ TString SerializeTxPlans(const TVector& txPlans, TIntrusivePtr> pureTxResults, TExprContext& ctx, const TString& cluster, - const TIntrusivePtr tablesData, TKikimrConfiguration::TPtr config, + TVector> pureTxResults, TExprContext& ctx, const TString& database, + const TString& cluster, const TIntrusivePtr tablesData, TKikimrConfiguration::TPtr config, TTypeAnnotationContext& typeCtx, TIntrusivePtr optCtx) { - TSerializerCtx serializerCtx(ctx, cluster, tablesData, config, query.Transactions().Size(), std::move(pureTxResults), typeCtx, optCtx); + TSerializerCtx serializerCtx(ctx, database, cluster, tablesData, config, query.Transactions().Size(), std::move(pureTxResults), typeCtx, optCtx); /* bindingName -> stage */ auto collectBindings = [&serializerCtx, &query] (auto id, const auto& phase) { @@ -2893,6 +2915,9 @@ TString AddExecStatsToTxPlan(const TString& txPlanJson, const NYql::NDqProto::TD stats["PhysicalStageId"] = (*stat)->GetStageId(); stats["Tasks"] = (*stat)->GetTotalTasksCount(); stats["FinishedTasks"] = (*stat)->GetFinishedTasksCount(); + if (auto updateTimeUs = (*stat)->GetUpdateTimeMs(); updateTimeUs) { + stats["UpdateTimeMs"] = updateTimeUs; + } stats["StageDurationUs"] = (*stat)->GetStageDurationUs(); diff --git a/ydb/core/kqp/opt/kqp_query_plan.h b/ydb/core/kqp/opt/kqp_query_plan.h index d1ac3f73020d..40486165462b 100644 --- a/ydb/core/kqp/opt/kqp_query_plan.h +++ b/ydb/core/kqp/opt/kqp_query_plan.h @@ -37,8 +37,8 @@ enum class EPlanTableWriteType { * table accesses is stored in top-level TKqpPhyQuery.QueryPlan. */ void PhyQuerySetTxPlans(NKqpProto::TKqpPhyQuery& queryProto, const NYql::NNodes::TKqpPhysicalQuery& query, - TVector> pureTxResults, NYql::TExprContext& ctx, const TString& cluster, - const TIntrusivePtr tablesData, NYql::TKikimrConfiguration::TPtr config, + TVector> pureTxResults, NYql::TExprContext& ctx, const TString& database, + const TString& cluster, const TIntrusivePtr tablesData, NYql::TKikimrConfiguration::TPtr config, NYql::TTypeAnnotationContext& typeCtx, TIntrusivePtr optCtx); /* diff --git a/ydb/core/kqp/opt/kqp_statistics_transformer.cpp b/ydb/core/kqp/opt/kqp_statistics_transformer.cpp index 152a11bf6893..b14b7ce27d20 100644 --- a/ydb/core/kqp/opt/kqp_statistics_transformer.cpp +++ b/ydb/core/kqp/opt/kqp_statistics_transformer.cpp @@ -116,6 +116,11 @@ void InferStatisticsForKqpTable(const TExprNode::TPtr& input, TTypeAnnotationCon auto readTable = inputNode.Cast(); auto path = readTable.Path(); + if (readTable.PathId() == "") { + // CTAS don't have created table during compilation. + return; + } + const auto& tableData = kqpCtx.Tables->ExistingTable(kqpCtx.Cluster, path.Value()); if (!tableData.Metadata->StatsLoaded && !kqpCtx.Config->OptOverrideStatistics.Get()) { YQL_CLOG(TRACE, CoreDq) << "Cannot infer statistics for table: " << path.Value(); @@ -490,7 +495,14 @@ class TKqpOlapPredicateSelectivityComputer: public TPredicateSelectivityComputer size_t listSize = listPtr->ChildrenSize(); if (listSize == 3) { TString compSign = TString(listPtr->Child(0)->Content()); - TString attr = TString(listPtr->Child(1)->Content()); + auto left = listPtr->ChildPtr(1); + auto right = listPtr->ChildPtr(2); + if (IsConstantExpr(left) && OlapOppositeCompSigns.contains(compSign)) { + compSign = OlapOppositeCompSigns[compSign]; + std::swap(left, right); + } + + TString attr = TString(left->Content()); TExprContext dummyCtx; TPositionHandle dummyPos; @@ -506,12 +518,12 @@ class TKqpOlapPredicateSelectivityComputer: public TPredicateSelectivityComputer .Name().Build(attr) .Done(); - auto value = TExprBase(listPtr->ChildPtr(2)); + auto value = TExprBase(right); if (listPtr->ChildPtr(2)->ChildrenSize() >= 2 && listPtr->ChildPtr(2)->ChildPtr(0)->Content() == "just") { value = TExprBase(listPtr->ChildPtr(2)->ChildPtr(1)); } if (OlapCompSigns.contains(compSign)) { - resSelectivity = this->ComputeComparisonSelectivity(member, value); + resSelectivity = this->ComputeInequalitySelectivity(member, value, OlapCompStrToEInequalityPredicate[compSign]); } else if (compSign == "eq") { resSelectivity = this->ComputeEqualitySelectivity(member, value); } else if (compSign == "neq") { @@ -544,6 +556,16 @@ class TKqpOlapPredicateSelectivityComputer: public TPredicateSelectivityComputer "starts_with", "ends_with" }; + + THashMap OlapCompStrToEInequalityPredicate = { + {"lt", EInequalityPredicateType::Less}, + {"lte", EInequalityPredicateType::LessOrEqual}, + {"gt", EInequalityPredicateType::GreaterOrEqual}, + {"gte", EInequalityPredicateType::GreaterOrEqual}, + }; + + THashMap OlapOppositeCompSigns = {{"lt", "gt"}, {"lte", "gte"}, {"gt", "lt"}, + {"gte", "lte"}, {"eq", "neq"}, {"neq", "eq"}}; }; void InferStatisticsForOlapFilter(const TExprNode::TPtr& input, TTypeAnnotationContext* typeCtx) { diff --git a/ydb/core/kqp/provider/yql_kikimr_datasink.cpp b/ydb/core/kqp/provider/yql_kikimr_datasink.cpp index 22c8feeab30b..6415aeced0ea 100644 --- a/ydb/core/kqp/provider/yql_kikimr_datasink.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_datasink.cpp @@ -9,6 +9,8 @@ #include +#include + namespace NYql { namespace { @@ -16,6 +18,7 @@ using namespace NKikimr; using namespace NNodes; namespace { + bool HasUpdateIntersection(const NCommon::TWriteTableSettings& settings) { THashSet columnNames; auto equalStmts = settings.Update.Cast().Ptr()->Child(1); @@ -41,112 +44,171 @@ bool HasUpdateIntersection(const NCommon::TWriteTableSettings& settings) { return hasIntersection; } -TExprNode::TPtr CreateNodeTypeParameter(const TString& name, const TTypeAnnotationNode* colType, TPositionHandle pos, +TCoParameter MakeTypeAnnotatedParameter(const TString& name, const TTypeAnnotationNode* colType, TPositionHandle pos, TExprContext& ctx) { - if (colType->GetKind() == ETypeAnnotationKind::Optional) { - colType = colType->Cast()->GetItemType(); - } + return Build(ctx, pos) + .Name().Build(name) + .Type(ExpandType(pos, *colType, ctx)) + .Done(); +} + +TCoParameter MakeCustomTypedParameter(const TString& name, const TString& typeName, TPositionHandle pos, TExprContext& ctx) { + return Build(ctx, pos) + .Name().Build(name) + .Type() + .Type().Value(typeName).Build() + .Build() + .Done(); +} - return ctx.NewCallable(pos, "Parameter", { - ctx.NewAtom(pos, name), - ctx.NewCallable(pos, "DataType", { - ctx.NewAtom(pos, FormatType(colType)) - }) - }); +TExprBase MakeBatchRange(const TVector& params, const TVector& members, const TString& sign, + TPositionHandle pos, TExprContext& ctx) +{ + auto paramsList = Build(ctx, pos).Add(params).Done(); + auto membersList = Build(ctx, pos).Add(members).Done(); + + if (sign == ">") { + return Build(ctx, pos) + .Left(paramsList) + .Right(membersList) + .Done(); + } else if (sign == ">=") { + return Build(ctx, pos) + .Left(paramsList) + .Right(membersList) + .Done(); + } else if (sign == "<") { + return Build(ctx, pos) + .Left(paramsList) + .Right(membersList) + .Done(); + } else if (sign == "<=") { + return Build(ctx, pos) + .Left(paramsList) + .Right(membersList) + .Done(); + } else { + YQL_ENSURE(false); + return TExprBase(nullptr); + } } -TExprNode::TPtr CreateNodeBoolParameter(const TString& name, TPositionHandle pos, TExprContext& ctx) { - return ctx.NewCallable(pos, "Parameter", { - ctx.NewAtom(pos, name), - ctx.NewCallable(pos, "DataType", { - ctx.NewAtom(pos, "Bool") - }) - }); +TCoOr MakeBatchRangesWithPrefixSize(const TVector& members, const TVector& types, const TString& sign, + bool isBegin, TPositionHandle pos, TExprContext& ctx) +{ + auto paramName = (isBegin) ? NKqp::NBatchParams::Begin : NKqp::NBatchParams::End; + auto prefixParamName = (isBegin) ? NKqp::NBatchParams::BeginPrefixSize : NKqp::NBatchParams::EndPrefixSize; + + TVector cur_params; + TVector cur_members; + TVector ranges; + + cur_params.reserve(types.size()); + cur_members.reserve(types.size()); + ranges.reserve(types.size() + 1); + + ranges.push_back(Build(ctx, pos) + .Left(MakeCustomTypedParameter(prefixParamName, "Uint32", pos, ctx)) + .Right() + .Literal().Build("0") + .Build() + .Done()); + + for (size_t i = 0; i < types.size(); ++i) { + cur_params.push_back(MakeTypeAnnotatedParameter(paramName + ToString(i + 1), types[i], pos, ctx)); + cur_members.push_back(members[i]); + + ranges.push_back(Build(ctx, pos) + .Add() + .Left(MakeCustomTypedParameter(prefixParamName, "Uint32", pos, ctx)) + .Right() + .Literal().Build(ToString(i + 1)) + .Build() + .Build() + .Add(MakeBatchRange(cur_params, cur_members, sign, pos, ctx)) + .Done()); + } + + return Build(ctx, pos) + .Add(ranges) + .Done(); } -TCoLambda RewriteBatchFilter(const TCoLambda& node, const TKikimrTableDescription& tableDesc, TExprContext& ctx) { - const TPositionHandle pos = node.Pos(); - const TExprNode::TPtr newLambda = ctx.DeepCopyLambda(node.Ref()); - const TExprNode::TPtr row = newLambda->ChildPtr(0)->ChildPtr(0); - const TExprNode::TPtr filter = newLambda->ChildPtr(1); +TCoLambda RewriteBatchFilter(const TCoLambda& lambda, const TKikimrTableDescription& tableDesc, TExprContext& ctx) { + const TPositionHandle pos = lambda.Pos(); + + YQL_ENSURE(lambda.Args().Size() == 1); + TCoArgument row = lambda.Args().Arg(0); TVector primaryColumns = tableDesc.Metadata->KeyColumnNames; + TVector members; + TVector types; - TExprNode::TListType beginParamsList; - TExprNode::TListType endParamsList; - TExprNode::TListType primaryMembersList; + members.reserve(primaryColumns.size()); + types.reserve(primaryColumns.size()); for (size_t i = 0; i < primaryColumns.size(); ++i) { - auto colType = tableDesc.GetColumnType(primaryColumns[i]); - beginParamsList.push_back(CreateNodeTypeParameter(NKqp::NBatchParams::Begin + ToString(i + 1), colType, pos, ctx)); - endParamsList.push_back(CreateNodeTypeParameter(NKqp::NBatchParams::End + ToString(i + 1), colType, pos, ctx)); - - primaryMembersList.push_back(ctx.NewCallable(pos, "Member", { - row, - ctx.NewAtom(pos, primaryColumns[i]) - })); - } - - TExprNode::TPtr beginNodeParams = beginParamsList.front(); - TExprNode::TPtr endNodeParams = endParamsList.front(); - TExprNode::TPtr primaryNodeMember = primaryMembersList.front(); - - if (primaryColumns.size() > 1) { - beginNodeParams = ctx.NewList(pos, std::move(beginParamsList)); - endNodeParams = ctx.NewList(pos, std::move(endParamsList)); - primaryNodeMember = ctx.NewList(pos, std::move(primaryMembersList)); - } - - TExprNode::TPtr newFilter = ctx.ChangeChild(*filter, 0, ctx.NewCallable(pos, "And", { - ctx.NewCallable(pos, "And", { - ctx.NewCallable(pos, "Or", { - CreateNodeBoolParameter(NKqp::NBatchParams::IsFirstQuery, pos, ctx), - ctx.NewCallable(pos, "Or", { - ctx.NewCallable(pos, "And", { - CreateNodeBoolParameter(NKqp::NBatchParams::IsInclusiveLeft, pos, ctx), - ctx.NewCallable(pos, ">=", { - primaryNodeMember, - beginNodeParams - }) - }), - ctx.NewCallable(pos, "And", { - ctx.NewCallable(pos, "Not", { - CreateNodeBoolParameter(NKqp::NBatchParams::IsInclusiveLeft, pos, ctx) - }), - ctx.NewCallable(pos, ">", { - primaryNodeMember, - beginNodeParams - }) - }) - }) - }), - ctx.NewCallable(pos, "Or", { - CreateNodeBoolParameter(NKqp::NBatchParams::IsLastQuery, pos, ctx), - ctx.NewCallable(pos, "Or", { - ctx.NewCallable(pos, "And", { - CreateNodeBoolParameter(NKqp::NBatchParams::IsInclusiveRight, pos, ctx), - ctx.NewCallable(pos, "<=", { - primaryNodeMember, - endNodeParams - }) - }), - ctx.NewCallable(pos, "And", { - ctx.NewCallable(pos, "Not", { - CreateNodeBoolParameter(NKqp::NBatchParams::IsInclusiveRight, pos, ctx) - }), - ctx.NewCallable(pos, "<", { - primaryNodeMember, - endNodeParams - }) - }) - }) - }), - }), - filter->ChildPtr(0) - })); - - return TCoLambda(ctx.ChangeChild(*newLambda, 1, std::move(newFilter))); + types.push_back(tableDesc.GetColumnType(primaryColumns[i])); + members.push_back(Build(ctx, pos) + .Struct(row) + .Name().Build(primaryColumns[i]) + .Done()); + } + + auto newFilter = Build(ctx, pos) + .Add() + .Add() + .Add(MakeCustomTypedParameter(NKqp::NBatchParams::IsInclusiveLeft, "Bool", pos, ctx)) + .Add(MakeBatchRangesWithPrefixSize(members, types, "<=", /* isBegin */ true, pos, ctx)) + .Build() + .Add() + .Add() + .Value(MakeCustomTypedParameter(NKqp::NBatchParams::IsInclusiveLeft, "Bool", pos, ctx)) + .Build() + .Add(MakeBatchRangesWithPrefixSize(members, types, "<", /* isBegin */ true, pos, ctx)) + .Build() + .Build() + .Add() + .Add() + .Add(MakeCustomTypedParameter(NKqp::NBatchParams::IsInclusiveRight, "Bool", pos, ctx)) + .Add(MakeBatchRangesWithPrefixSize(members, types, ">=", /* isBegin */ false, pos, ctx)) + .Build() + .Add() + .Add() + .Value(MakeCustomTypedParameter(NKqp::NBatchParams::IsInclusiveRight, "Bool", pos, ctx)) + .Build() + .Add(MakeBatchRangesWithPrefixSize(members, types, ">", /* isBegin */ false, pos, ctx)) + .Build() + .Build() + .Done(); + + if (lambda.Body().Maybe()) { + TCoCoalesce filter = lambda.Body().Cast(); + return Build(ctx, pos) + .Args({row}) + .Body() + .Predicate() + .Add(newFilter) + .Add(filter.Predicate()) + .Build() + .Value() + .Literal().Build("false") + .Build() + .Build() + .Done(); + } + + return Build(ctx, pos) + .Args({row}) + .Body() + .Predicate(newFilter) + .Value() + .Literal().Build("false") + .Build() + .Build() + .Done(); } + } // namespace class TKiSinkIntentDeterminationTransformer: public TKiSinkVisitorTransformer { @@ -453,10 +515,14 @@ class TKiSinkIntentDeterminationTransformer: public TKiSinkVisitorTransformer { mode == "insert_revert" || mode == "insert_abort" || mode == "delete_on" || - mode == "update_on") + mode == "update_on" || + mode == "fill_table") { SessionCtx->Tables().GetOrAddTable(TString(cluster), SessionCtx->GetDatabase(), key.GetTablePath()); return TStatus::Ok; + } else if (mode == "fill_table") { + SessionCtx->Tables().GetOrAddTable(TString(cluster), SessionCtx->GetDatabase(), key.GetTablePath()); + return TStatus::Ok; } else if (mode == "insert_ignore") { ctx.AddError(TIssue(ctx.GetPosition(node.Pos()), TStringBuilder() << "INSERT OR IGNORE is not yet supported for Kikimr.")); @@ -1144,7 +1210,18 @@ class TKikimrDataSink : public TDataProviderBase return false; } - if (tableDesc.Metadata->Kind == EKikimrTableKind::Olap && mode != "replace" && mode != "drop" && mode != "drop_if_exists" && mode != "insert_abort" && mode != "update" && mode != "upsert" && mode != "delete" && mode != "update_on" && mode != "delete_on" && mode != "analyze") { + if (tableDesc.Metadata->Kind == EKikimrTableKind::Olap + && mode != "replace" + && mode != "drop" + && mode != "drop_if_exists" + && mode != "insert_abort" + && mode != "update" + && mode != "upsert" + && mode != "delete" + && mode != "update_on" + && mode != "delete_on" + && mode != "analyze" + && mode != "fill_table") { ctx.AddError(TIssue(ctx.GetPosition(node->Pos()), TStringBuilder() << "Write mode '" << static_cast(mode) << "' is not supported for olap tables.")); return true; } diff --git a/ydb/core/kqp/provider/yql_kikimr_gateway.h b/ydb/core/kqp/provider/yql_kikimr_gateway.h index 5916726cd7a3..30718416ecb4 100644 --- a/ydb/core/kqp/provider/yql_kikimr_gateway.h +++ b/ydb/core/kqp/provider/yql_kikimr_gateway.h @@ -203,7 +203,7 @@ struct TIndexDescription { case EType::GlobalAsync: return false; case EType::GlobalSyncVectorKMeansTree: - return true; + return false; } } @@ -923,7 +923,7 @@ struct TTransferSettings : public TReplicationSettingsBase { struct TBatching { TDuration FlushInterval; - ui64 BatchSizeBytes; + std::optional BatchSizeBytes; }; TMaybe ConsumerName; diff --git a/ydb/core/kqp/provider/yql_kikimr_opt_build.cpp b/ydb/core/kqp/provider/yql_kikimr_opt_build.cpp index 4c21926196e1..38a3811939fd 100644 --- a/ydb/core/kqp/provider/yql_kikimr_opt_build.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_opt_build.cpp @@ -173,45 +173,41 @@ struct TKiExploreTxResults { } } - void AddWriteOpToQueryBlock(const TExprBase& effect, TKikimrTableMetadataPtr tableMeta, bool needMainTableRead) { - YQL_ENSURE(tableMeta, "Empty table metadata"); - + void AddWriteOpToQueryBlock(const TExprBase& effect, const TString& name, const TVector& indexes, bool needMainTableRead) { THashMap ops; if (needMainTableRead) { - ops[tableMeta->Name] |= TPrimitiveYdbOperation::Read; + ops[name] |= TPrimitiveYdbOperation::Read; } - ops[tableMeta->Name] |= TPrimitiveYdbOperation::Write; + ops[name] |= TPrimitiveYdbOperation::Write; - for (const auto& index : tableMeta->Indexes) { + for (const auto& index : indexes) { if (!index.ItUsedForWrite()) { continue; } - const auto indexTables = NKikimr::NKqp::NSchemeHelpers::CreateIndexTablePath(tableMeta->Name, index); + const auto indexTables = NKikimr::NKqp::NSchemeHelpers::CreateIndexTablePath(name, index); YQL_ENSURE(indexTables.size() == 1, "Only index with one impl table is supported"); const auto indexTable = indexTables[0]; - ops[tableMeta->Name] |= TPrimitiveYdbOperation::Read; + ops[name] |= TPrimitiveYdbOperation::Read; ops[indexTable] = TPrimitiveYdbOperation::Write; } AddEffect(effect, ops); } - void AddUpdateOpToQueryBlock(const TExprBase& effect, TKikimrTableMetadataPtr tableMeta, + void AddUpdateOpToQueryBlock(const TExprBase& effect, const TString& name, const TVector& indexes, const THashSet& updateColumns) { - YQL_ENSURE(tableMeta, "Empty table metadata"); - THashMap ops; // read and upsert rows into main table - ops[tableMeta->Name] = TPrimitiveYdbOperation::Read | TPrimitiveYdbOperation::Write; + ops[name] = TPrimitiveYdbOperation::Read | TPrimitiveYdbOperation::Write; - for (const auto& index : tableMeta->Indexes) { + for (const auto& index : indexes) { if (!index.ItUsedForWrite()) { continue; } - const auto indexTables = NKikimr::NKqp::NSchemeHelpers::CreateIndexTablePath(tableMeta->Name, index); + const auto indexTables = NKikimr::NKqp::NSchemeHelpers::CreateIndexTablePath(name, index); YQL_ENSURE(indexTables.size() == 1, "Only index with one impl table is supported"); const auto indexTable = indexTables[0]; @@ -436,8 +432,6 @@ bool ExploreNode(TExprBase node, TExprContext& ctx, const TKiDataSink& dataSink, auto tableOp = GetTableOp(write); YQL_ENSURE(tablesData); - const auto& tableData = tablesData->ExistingTable(cluster, table); - YQL_ENSURE(tableData.Metadata); if (!write.ReturningColumns().Empty()) { txRes.PrepareForResult(); @@ -451,9 +445,17 @@ bool ExploreNode(TExprBase node, TExprContext& ctx, const TKiDataSink& dataSink, for (const auto& column : inputColumns) { updateColumns.emplace(column); } - txRes.AddUpdateOpToQueryBlock(node, tableData.Metadata, updateColumns); + + const auto& tableData = tablesData->ExistingTable(cluster, table); + YQL_ENSURE(tableData.Metadata); + txRes.AddUpdateOpToQueryBlock(node, tableData.Metadata->Name, tableData.Metadata->Indexes, updateColumns); + } else if (tableOp == TYdbOperation::FillTable) { + // FillTable is used for CTAS. + txRes.AddWriteOpToQueryBlock(node, TString(table), {}, tableOp & KikimrReadOps()); } else { - txRes.AddWriteOpToQueryBlock(node, tableData.Metadata, tableOp & KikimrReadOps()); + const auto& tableData = tablesData->ExistingTable(cluster, table); + YQL_ENSURE(tableData.Metadata); + txRes.AddWriteOpToQueryBlock(node, tableData.Metadata->Name, tableData.Metadata->Indexes, tableOp & KikimrReadOps()); } if (!write.ReturningColumns().Empty()) { @@ -506,7 +508,7 @@ bool ExploreNode(TExprBase node, TExprContext& ctx, const TKiDataSink& dataSink, txRes.PrepareForResult(); } - txRes.AddUpdateOpToQueryBlock(node, tableData.Metadata, updateColumns); + txRes.AddUpdateOpToQueryBlock(node, tableData.Metadata->Name, tableData.Metadata->Indexes, updateColumns); if (!update.ReturningColumns().Empty()) { txRes.AddResult( Build(ctx, update.Pos()) @@ -544,7 +546,7 @@ bool ExploreNode(TExprBase node, TExprContext& ctx, const TKiDataSink& dataSink, txRes.PrepareForResult(); } - txRes.AddWriteOpToQueryBlock(node, tableData.Metadata, tableOp & KikimrReadOps()); + txRes.AddWriteOpToQueryBlock(node, tableData.Metadata->Name, tableData.Metadata->Indexes, tableOp & KikimrReadOps()); if (!del.ReturningColumns().Empty()) { txRes.AddResult( Build(ctx, del.Pos()) @@ -1360,6 +1362,8 @@ TYdbOperation GetTableOp(const TKiWriteTable& write) { return TYdbOperation::DeleteOn; } else if (mode == "update_on") { return TYdbOperation::UpdateOn; + } else if (mode == "fill_table") { + return TYdbOperation::FillTable; } YQL_ENSURE(false, "Unexpected TKiWriteTable mode: " << mode); diff --git a/ydb/core/kqp/provider/yql_kikimr_provider.h b/ydb/core/kqp/provider/yql_kikimr_provider.h index 45f21c161ce0..de2146416bb1 100644 --- a/ydb/core/kqp/provider/yql_kikimr_provider.h +++ b/ydb/core/kqp/provider/yql_kikimr_provider.h @@ -261,6 +261,7 @@ enum class TYdbOperation : ui64 { AlterTransfer = 1ull << 35, DropTransfer = 1ull << 36, AlterDatabase = 1ull << 37, + FillTable = 1ull << 38, }; Y_DECLARE_FLAGS(TYdbOperations, TYdbOperation); diff --git a/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp b/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp index 8ea634a0af61..375b39a45b0d 100644 --- a/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp @@ -459,6 +459,12 @@ class TKiSinkTypeAnnotationTransformer : public TKiSinkVisitorTransformer return TStatus::Error; } + auto op = GetTableOp(node); + if (op == TYdbOperation::FillTable) { + node.Ptr()->SetTypeAnn(node.World().Ref().GetTypeAnn()); + return TStatus::Ok; + } + auto table = SessionCtx->Tables().EnsureTableExists(TString(node.DataSink().Cluster()), TString(node.Table().Value()), node.Pos(), ctx); @@ -524,7 +530,6 @@ class TKiSinkTypeAnnotationTransformer : public TKiSinkVisitorTransformer } } - auto op = GetTableOp(node); if (NPgTypeAnn::IsPgInsert(node, op)) { TExprNode::TPtr newInput; auto ok = NCommon::RenamePgSelectColumns(node.Input().Cast(), newInput, TColumnOrder(table->Metadata->ColumnOrder), ctx, Types); diff --git a/ydb/core/kqp/proxy_service/kqp_proxy_service.cpp b/ydb/core/kqp/proxy_service/kqp_proxy_service.cpp index f4658345a59e..6fd47fa1a32b 100644 --- a/ydb/core/kqp/proxy_service/kqp_proxy_service.cpp +++ b/ydb/core/kqp/proxy_service/kqp_proxy_service.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -202,6 +203,7 @@ class TKqpProxyService : public TActorBootstrapped { , TableServiceConfig(tableServiceConfig) , QueryServiceConfig(queryServiceConfig) , FeatureFlags() + , WorkloadManagerConfig() , KqpSettings(std::make_shared(std::move(settings))) , FederatedQuerySetupFactory(federatedQuerySetupFactory) , QueryReplayFactory(std::move(queryReplayFactory)) @@ -216,6 +218,7 @@ class TKqpProxyService : public TActorBootstrapped { NLwTraceMonPage::ProbeRegistry().AddProbesList(LWTRACE_GET_PROBES(KQP_PROVIDER)); Counters = MakeIntrusive(AppData()->Counters, &TlsActivationContext->AsActorContext()); FeatureFlags = AppData()->FeatureFlags; + WorkloadManagerConfig = AppData()->WorkloadManagerConfig; // NOTE: some important actors are constructed within next call FederatedQuerySetup = FederatedQuerySetupFactory->Make(ctx.ActorSystem()); AsyncIoFactory = CreateKqpAsyncIoFactory(Counters, FederatedQuerySetup, S3ActorsFactory); @@ -240,13 +243,14 @@ class TKqpProxyService : public TActorBootstrapped { ui32 tableServiceConfigKind = (ui32)NKikimrConsole::TConfigItem::TableServiceConfigItem; ui32 logConfigKind = (ui32)NKikimrConsole::TConfigItem::LogConfigItem; ui32 featureFlagsKind = (ui32)NKikimrConsole::TConfigItem::FeatureFlagsItem; + ui32 workloadManagerKind = (ui32)NKikimrConsole::TConfigItem::WorkloadManagerConfigItem; Send(NConsole::MakeConfigsDispatcherID(SelfId().NodeId()), new NConsole::TEvConfigsDispatcher::TEvSetConfigSubscriptionRequest( - {tableServiceConfigKind, logConfigKind, featureFlagsKind}), + {tableServiceConfigKind, logConfigKind, featureFlagsKind, workloadManagerKind}), IEventHandle::FlagTrackDelivery); WhiteBoardService = NNodeWhiteboard::MakeNodeWhiteboardServiceId(SelfId().NodeId()); - ResourcePoolsCache.UpdateFeatureFlags(FeatureFlags, ActorContext()); + ResourcePoolsCache.UpdateConfig(FeatureFlags, WorkloadManagerConfig, ActorContext()); if (auto& cfg = TableServiceConfig.GetSpillingServiceConfig().GetLocalFileConfig(); cfg.GetEnable()) { TString spillingRoot = cfg.GetRoot(); @@ -517,7 +521,8 @@ class TKqpProxyService : public TActorBootstrapped { UpdateYqlLogLevels(); FeatureFlags.Swap(event.MutableConfig()->MutableFeatureFlags()); - ResourcePoolsCache.UpdateFeatureFlags(FeatureFlags, ActorContext()); + WorkloadManagerConfig.Swap(event.MutableConfig()->MutableWorkloadManagerConfig()); + ResourcePoolsCache.UpdateConfig(FeatureFlags, WorkloadManagerConfig, ActorContext()); auto responseEv = MakeHolder(event); Send(ev->Sender, responseEv.Release(), IEventHandle::FlagTrackDelivery, ev->Cookie); @@ -1598,10 +1603,10 @@ class TKqpProxyService : public TActorBootstrapped { } bool TryFillPoolInfoFromCache(TEvKqp::TEvQueryRequest::TPtr& ev, ui64 requestId) { - ResourcePoolsCache.UpdateFeatureFlags(FeatureFlags, ActorContext()); + ResourcePoolsCache.UpdateConfig(FeatureFlags, WorkloadManagerConfig, ActorContext()); const auto& databaseId = ev->Get()->GetDatabaseId(); - if (!ResourcePoolsCache.ResourcePoolsEnabled(databaseId)) { + if (!ResourcePoolsCache.ResourcePoolsEnabled(databaseId) || (ev->Get()->IsInternalCall() && WorkloadManagerConfig.GetEnabled())) { ev->Get()->SetPoolId(""); return true; } @@ -1894,6 +1899,7 @@ class TKqpProxyService : public TActorBootstrapped { NKikimrConfig::TTableServiceConfig TableServiceConfig; NKikimrConfig::TQueryServiceConfig QueryServiceConfig; NKikimrConfig::TFeatureFlags FeatureFlags; + NKikimrConfig::TWorkloadManagerConfig WorkloadManagerConfig; TKqpSettings::TConstPtr KqpSettings; IKqpFederatedQuerySetupFactory::TPtr FederatedQuerySetupFactory; std::optional FederatedQuerySetup; diff --git a/ydb/core/kqp/proxy_service/kqp_proxy_service_impl.h b/ydb/core/kqp/proxy_service/kqp_proxy_service_impl.h index 8758b67f2781..b2e2ee7e62ad 100644 --- a/ydb/core/kqp/proxy_service/kqp_proxy_service_impl.h +++ b/ydb/core/kqp/proxy_service/kqp_proxy_service_impl.h @@ -7,8 +7,9 @@ #include #include #include -#include #include +#include +#include #include @@ -491,9 +492,9 @@ class TResourcePoolsCache { return it->second; } - void UpdateFeatureFlags(const NKikimrConfig::TFeatureFlags& featureFlags, TActorContext actorContext) { - EnableResourcePools = featureFlags.GetEnableResourcePools(); - EnableResourcePoolsOnServerless = featureFlags.GetEnableResourcePoolsOnServerless(); + void UpdateConfig(const NKikimrConfig::TFeatureFlags& featureFlags, const NKikimrConfig::TWorkloadManagerConfig& workloadManagerConfig, TActorContext actorContext) { + EnableResourcePools = featureFlags.GetEnableResourcePools() || workloadManagerConfig.GetEnabled(); + EnableResourcePoolsOnServerless = featureFlags.GetEnableResourcePoolsOnServerless() || workloadManagerConfig.GetEnabled(); UpdateResourcePoolClassifiersSubscription(actorContext); } diff --git a/ydb/core/kqp/proxy_service/kqp_script_executions.cpp b/ydb/core/kqp/proxy_service/kqp_script_executions.cpp index 6a727ba48991..47e279e3b1b4 100644 --- a/ydb/core/kqp/proxy_service/kqp_script_executions.cpp +++ b/ydb/core/kqp/proxy_service/kqp_script_executions.cpp @@ -70,6 +70,30 @@ NYql::TIssues DeserializeIssues(const TString& issuesSerialized) { return issues; } +template +void SerializeBinaryProto(const TProto& proto, NJson::TJsonValue& value) { + value.SetType(NJson::EJsonValueType::JSON_MAP); + + const auto config = NProtobufJson::TProto2JsonConfig() + .AddStringTransform(MakeIntrusive()); + + NProtobufJson::Proto2Json(proto, value["encoded_proto"], config); +} + +template +void DeserializeBinaryProto(const NJson::TJsonValue& value, TProto& proto) { + const auto& valueMap = value.GetMap(); + const auto encodedProto = valueMap.find("encoded_proto"); + if (encodedProto == valueMap.end()) { + return NProtobufJson::Json2Proto(value, proto, NProtobufJson::TJson2ProtoConfig()); + } + + const auto config = NProtobufJson::TJson2ProtoConfig() + .AddStringTransform(MakeIntrusive()); + + NProtobufJson::Json2Proto(encodedProto->second, proto, config); +} + class TQueryBase : public NKikimr::TQueryBase { public: @@ -2272,7 +2296,7 @@ class TSaveScriptExternalEffectActor : public TQueryBase { NJson::TJsonValue::TArray& jsonArray = value.GetArraySafe(); jsonArray.resize(sinks.size()); for (size_t i = 0; i < sinks.size(); ++i) { - NProtobufJson::Proto2Json(sinks[i], jsonArray[i], NProtobufJson::TProto2JsonConfig()); + SerializeBinaryProto(sinks[i], jsonArray[i]); } NJsonWriter::TBuf serializedSinks; @@ -2416,7 +2440,7 @@ class TSaveScriptFinalStatusActor : public TQueryBase { value.GetValuePointer(i, &serializedSink); NKqpProto::TKqpExternalSink sink; - NProtobufJson::Json2Proto(*serializedSink, sink); + DeserializeBinaryProto(*serializedSink, sink); Response->Sinks.push_back(sink); } } diff --git a/ydb/core/kqp/query_compiler/kqp_query_compiler.cpp b/ydb/core/kqp/query_compiler/kqp_query_compiler.cpp index 9cbba6d02f7b..d26b5a630376 100644 --- a/ydb/core/kqp/query_compiler/kqp_query_compiler.cpp +++ b/ydb/core/kqp/query_compiler/kqp_query_compiler.cpp @@ -104,7 +104,6 @@ NKqpProto::EStreamLookupStrategy GetStreamLookupStrategy(EStreamLookupStrategyTy void FillTableId(const TKqpTable& table, NKqpProto::TKqpPhyTableId& tableProto) { auto pathId = TKikimrPathId::Parse(table.PathId()); - tableProto.SetPath(TString(table.Path())); tableProto.SetOwnerId(pathId.OwnerId()); tableProto.SetTableId(pathId.TableId()); @@ -1202,49 +1201,68 @@ class TKqpQueryCompiler : public IKqpQueryCompiler { columns.emplace_back(item->GetName()); } - FillTablesMap(settings.Table().Cast(), columns, tablesMap); - FillTableId(settings.Table().Cast(), *settingsProto.MutableTable()); + if (settings.Mode().Cast().StringValue() != "fill_table") { + AFL_ENSURE(settings.Table().Cast().PathId() != ""); + FillTableId(settings.Table().Cast(), *settingsProto.MutableTable()); + FillTablesMap(settings.Table().Cast(), columns, tablesMap); + + const auto tableMeta = TablesData->ExistingTable(Cluster, settings.Table().Cast().Path()).Metadata; - const auto tableMeta = TablesData->ExistingTable(Cluster, settings.Table().Cast().Path()).Metadata; + auto fillColumnProto = [] (TStringBuf columnName, const NYql::TKikimrColumnMetadata* column, NKikimrKqp::TKqpColumnMetadataProto* columnProto ) { + columnProto->SetId(column->Id); + columnProto->SetName(TString(columnName)); + columnProto->SetTypeId(column->TypeInfo.GetTypeId()); - auto fillColumnProto = [] (TStringBuf columnName, const NYql::TKikimrColumnMetadata* column, NKikimrKqp::TKqpColumnMetadataProto* columnProto ) { - columnProto->SetId(column->Id); - columnProto->SetName(TString(columnName)); - columnProto->SetTypeId(column->TypeInfo.GetTypeId()); + if(NScheme::NTypeIds::IsParametrizedType(column->TypeInfo.GetTypeId())) { + ProtoFromTypeInfo(column->TypeInfo, column->TypeMod, *columnProto->MutableTypeInfo()); + } + }; - if(NScheme::NTypeIds::IsParametrizedType(column->TypeInfo.GetTypeId())) { - ProtoFromTypeInfo(column->TypeInfo, column->TypeMod, *columnProto->MutableTypeInfo()); + for (const auto& columnName : tableMeta->KeyColumnNames) { + const auto columnMeta = tableMeta->Columns.FindPtr(columnName); + YQL_ENSURE(columnMeta != nullptr, "Unknown column in sink: \"" + TString(columnName) + "\""); + + auto keyColumnProto = settingsProto.AddKeyColumns(); + fillColumnProto(columnName, columnMeta, keyColumnProto); } - }; - for (const auto& columnName : tableMeta->KeyColumnNames) { - const auto columnMeta = tableMeta->Columns.FindPtr(columnName); - YQL_ENSURE(columnMeta != nullptr, "Unknown column in sink: \"" + TString(columnName) + "\""); + for (const auto& columnName : columns) { + const auto columnMeta = tableMeta->Columns.FindPtr(columnName); + YQL_ENSURE(columnMeta != nullptr, "Unknown column in sink: \"" + TString(columnName) + "\""); - auto keyColumnProto = settingsProto.AddKeyColumns(); - fillColumnProto(columnName, columnMeta, keyColumnProto); - } + auto columnProto = settingsProto.AddColumns(); + fillColumnProto(columnName, columnMeta, columnProto); + } - for (const auto& columnName : columns) { - const auto columnMeta = tableMeta->Columns.FindPtr(columnName); - YQL_ENSURE(columnMeta != nullptr, "Unknown column in sink: \"" + TString(columnName) + "\""); + AFL_ENSURE(tableMeta->Kind == EKikimrTableKind::Datashard || tableMeta->Kind == EKikimrTableKind::Olap); + const auto columnToOrder = CreateColumnToOrder( + columns, + tableMeta, + tableMeta->Kind == EKikimrTableKind::Datashard); + for (const auto& columnName : columns) { + settingsProto.AddWriteIndexes(columnToOrder.at(columnName)); + } - auto columnProto = settingsProto.AddColumns(); - fillColumnProto(columnName, columnMeta, columnProto); - } + settingsProto.SetIsOlap(tableMeta->Kind == EKikimrTableKind::Olap); - const auto columnToOrder = CreateColumnToOrder( - columns, - tableMeta, - settings.TableType().Cast().StringValue() == "oltp"); - for (const auto& columnName : columns) { - settingsProto.AddWriteIndexes(columnToOrder.at(columnName)); - } + AFL_ENSURE(settings.InconsistentWrite().Cast().StringValue() == "false"); + settingsProto.SetInconsistentTx(false); + } else { + // Table info will be filled during execution after resolving table by name. + settingsProto.MutableTable()->SetPath(TString(settings.Table().Cast().Path())); + for (const auto& column : columns) { + settingsProto.AddInputColumns(TString(column)); + } - if (const auto inconsistentWrite = settings.InconsistentWrite().Cast(); inconsistentWrite.StringValue() == "true") { + AFL_ENSURE(settings.InconsistentWrite().Cast().StringValue() == "true"); settingsProto.SetInconsistentTx(true); + + AFL_ENSURE(settings.Priority().Cast().StringValue() == "0"); + AFL_ENSURE(settings.StreamWrite().Cast().StringValue() == "true"); } + settingsProto.SetPriority(FromString(settings.Priority().Cast().StringValue())); + if (const auto streamWrite = settings.StreamWrite().Cast(); streamWrite.StringValue() == "true") { settingsProto.SetEnableStreamWrite(true); } @@ -1253,9 +1271,6 @@ class TKqpQueryCompiler : public IKqpQueryCompiler { settingsProto.SetIsBatch(true); } - settingsProto.SetIsOlap(settings.TableType().Cast().StringValue() == "olap"); - settingsProto.SetPriority(FromString(settings.Priority().Cast().StringValue())); - if (settings.Mode().Cast().StringValue() == "replace") { settingsProto.SetType(NKikimrKqp::TKqpTableSinkSettings::MODE_REPLACE); } else if (settings.Mode().Cast().StringValue() == "upsert" || settings.Mode().Cast().StringValue().empty() /* for compatibility, will be removed */) { @@ -1266,6 +1281,8 @@ class TKqpQueryCompiler : public IKqpQueryCompiler { settingsProto.SetType(NKikimrKqp::TKqpTableSinkSettings::MODE_DELETE); } else if (settings.Mode().Cast().StringValue() == "update") { settingsProto.SetType(NKikimrKqp::TKqpTableSinkSettings::MODE_UPDATE); + } else if (settings.Mode().Cast().StringValue() == "fill_table") { + settingsProto.SetType(NKikimrKqp::TKqpTableSinkSettings::MODE_FILL); } else { YQL_ENSURE(false, "Unsupported sink mode"); } diff --git a/ydb/core/kqp/query_data/kqp_prepared_query.cpp b/ydb/core/kqp/query_data/kqp_prepared_query.cpp index f591e514e224..8c203f28d8f1 100644 --- a/ydb/core/kqp/query_data/kqp_prepared_query.cpp +++ b/ydb/core/kqp/query_data/kqp_prepared_query.cpp @@ -272,9 +272,11 @@ void TPreparedQueryHolder::FillTables(const google::protobuf::RepeatedPtrField< NKikimrKqp::TKqpTableSinkSettings settings; YQL_ENSURE(sink.GetInternalSink().GetSettings().UnpackTo(&settings), "Failed to unpack settings"); - auto& info = GetInfo(MakeTableId(settings.GetTable())); - for (auto& column : settings.GetColumns()) { - info->AddColumn(column.GetName()); + if (settings.GetType() != NKikimrKqp::TKqpTableSinkSettings::MODE_FILL) { + auto& info = GetInfo(MakeTableId(settings.GetTable())); + for (auto& column : settings.GetColumns()) { + info->AddColumn(column.GetName()); + } } } } diff --git a/ydb/core/kqp/run_script_actor/kqp_run_script_actor.cpp b/ydb/core/kqp/run_script_actor/kqp_run_script_actor.cpp index 0b5543a63d7d..79976a574828 100644 --- a/ydb/core/kqp/run_script_actor/kqp_run_script_actor.cpp +++ b/ydb/core/kqp/run_script_actor/kqp_run_script_actor.cpp @@ -1,19 +1,20 @@ #include "kqp_run_script_actor.h" -#include #include #include #include #include +#include #include #include +#include #include -#include - #include #include #include #include +#include + #include #include @@ -384,6 +385,16 @@ class TRunScriptActor : public NActors::TActorBootstrapped { Ydb::Query::Internal::ResultSetMeta meta; if (newResultSet) { *meta.mutable_columns() = ev->Get()->Record.GetResultSet().columns(); + + if (const auto& issues = NKikimr::NKqp::ValidateResultSetColumns(meta.columns())) { + NYql::TIssue rootIssue(TStringBuilder() << "Invalid result set " << resultSetIndex << " columns, please contact internal support"); + for (const NYql::TIssue& issue : issues) { + rootIssue.AddSubIssue(MakeIntrusive(issue)); + } + Issues.AddIssue(rootIssue); + Finish(Ydb::StatusIds::INTERNAL_ERROR); + return; + } } if (resultSetInfo.Truncated) { meta.set_truncated(true); @@ -450,6 +461,7 @@ class TRunScriptActor : public NActors::TActorBootstrapped { const auto& issueMessage = record.GetResponse().GetQueryIssues(); NYql::IssuesFromMessage(issueMessage, Issues); + Issues = TruncateIssues(Issues); if (record.GetYdbStatus() == Ydb::StatusIds::TIMEOUT) { const TDuration timeout = GetQueryTimeout(NKikimrKqp::QUERY_TYPE_SQL_GENERIC_SCRIPT, Request.GetRequest().GetTimeoutMs(), {}, QueryServiceConfig); diff --git a/ydb/core/kqp/runtime/kqp_read_actor.cpp b/ydb/core/kqp/runtime/kqp_read_actor.cpp index 9a5b91ededae..deb0be512379 100644 --- a/ydb/core/kqp/runtime/kqp_read_actor.cpp +++ b/ydb/core/kqp/runtime/kqp_read_actor.cpp @@ -22,6 +22,7 @@ #include #include +#include namespace { @@ -804,12 +805,24 @@ class TKqpReadActor : public TActorBootstrapped, public NYql::NDq auto& record = ev->Record; state->FillEvRead(*ev, KeyColumnTypes, Settings->GetReverse()); - for (const auto& column : Settings->GetColumns()) { + + BatchOperationReadColumns.clear(); + + auto columnsSize = static_cast(Settings->GetColumns().size()); + for (size_t i = 0; i < columnsSize; ++i) { + const auto& column = Settings->GetColumns()[i]; if (!IsSystemColumn(column.GetId())) { record.AddColumns(column.GetId()); + + if (Settings->GetIsBatch()) { + NScheme::TTypeInfo typeInfo = NScheme::TypeInfoFromProto(column.GetType(), column.GetTypeInfo()); + BatchOperationReadColumns.emplace_back(column.GetId(), typeInfo, column.GetIsPrimary()); + } } } + YQL_ENSURE(!Settings->GetIsBatch() || BatchOperationReadColumns.size() >= KeyColumnTypes.size()); + if (CollectDuplicateStats) { for (const auto& column : DuplicateCheckExtraColumns) { record.AddColumns(column.Tag); @@ -1037,6 +1050,10 @@ class TKqpReadActor : public TActorBootstrapped, public NYql::NDq ui64 seqNo = ev->Get()->Record.GetSeqNo(); Reads[id].RegisterMessage(*ev->Get()); + if (Settings->GetIsBatch()) { + SetBatchOperationMaxRow(ev->Get()); + } + ReceivedRowCount += ev->Get()->GetRowsCount(); CA_LOG_D(TStringBuilder() << "new data for read #" << id @@ -1486,6 +1503,22 @@ class TKqpReadActor : public TActorBootstrapped, public NYql::NDq for (auto& lock : BrokenLocks) { resultInfo.AddLocks()->CopyFrom(lock); } + if (Settings->GetIsBatch() && !BatchOperationMaxRow.empty()) { + std::vector keyRow; + for (size_t i = 0; i < BatchOperationReadColumns.size(); ++i) { + if (const auto& column = BatchOperationReadColumns[i]; column.IsPrimary) { + keyRow.push_back(BatchOperationMaxRow[i]); + resultInfo.AddBatchOperationKeyIds(column.Id); + } + } + + if (!keyRow.empty()) { + YQL_ENSURE(keyRow.size() == KeyColumnTypes.size()); + + TConstArrayRef keyRef(keyRow); + resultInfo.SetBatchOperationMaxKey(TSerializedCellVec::Serialize(keyRef)); + } + } result.PackFrom(resultInfo); return result; } @@ -1535,6 +1568,13 @@ class TKqpReadActor : public TActorBootstrapped, public NYql::NDq } } + void SetBatchOperationMaxRow(TEvDataShard::TEvReadResult* ev) { + if (ev->GetRowsCount() > 0) { + auto cells = ev->GetCells(ev->GetRowsCount() - 1); + BatchOperationMaxRow = TOwnedCellVec::Make(cells); + } + } + private: struct TResultColumn { bool IsSystem = false; @@ -1605,6 +1645,15 @@ class TKqpReadActor : public TActorBootstrapped, public NYql::NDq THashMap DuplicateCheckStats; TVector DuplicateCheckExtraColumns; TVector DuplicateCheckColumnRemap; + + struct TReadColumnInfo { + ui32 Id; + NScheme::TTypeInfo TypeInfo; + bool IsPrimary = false; + }; + + TVector BatchOperationReadColumns; + TOwnedCellVec BatchOperationMaxRow; }; diff --git a/ydb/core/kqp/runtime/kqp_write_actor.cpp b/ydb/core/kqp/runtime/kqp_write_actor.cpp index 1118f45312ae..9c29d190d2a2 100644 --- a/ydb/core/kqp/runtime/kqp_write_actor.cpp +++ b/ydb/core/kqp/runtime/kqp_write_actor.cpp @@ -44,6 +44,7 @@ namespace { NKikimrDataEvents::TEvWrite::TOperation::EOperationType GetOperation(NKikimrKqp::TKqpTableSinkSettings::EType type) { switch (type) { + case NKikimrKqp::TKqpTableSinkSettings::MODE_FILL: case NKikimrKqp::TKqpTableSinkSettings::MODE_REPLACE: return NKikimrDataEvents::TEvWrite::TOperation::OPERATION_REPLACE; case NKikimrKqp::TKqpTableSinkSettings::MODE_UPSERT: @@ -1324,6 +1325,7 @@ class TKqpDirectWriteActor : public TActorBootstrapped, pu Settings.GetWriteIndexes().begin(), Settings.GetWriteIndexes().end()); + TGuard guard(*Alloc); if (Settings.GetIsOlap()) { Batcher = CreateColumnDataBatcher(columnsMetadata, std::move(writeIndex), Alloc); } else { @@ -1990,7 +1992,6 @@ class TKqpBufferWriteActor :public TActorBootstrapped, pub CA_LOG_D("Start rollback"); State = EState::ROLLINGBACK; SendToExternalShards(true); - SendToTopics(true); } void SendToExternalShards(bool isRollback) { @@ -2802,7 +2803,7 @@ class TKqpBufferWriteActor :public TActorBootstrapped, pub void UpdateTracingState(const char* name, NWilson::TTraceId traceId) { BufferWriteActorStateSpan = NWilson::TSpan(TWilsonKqp::BufferWriteActorState, std::move(traceId), name, NWilson::EFlags::AUTO_END); - if (traceId != BufferWriteActorSpan.GetTraceId()) { + if (BufferWriteActorStateSpan.GetTraceId() != BufferWriteActorSpan.GetTraceId()) { BufferWriteActorStateSpan.Link(BufferWriteActorSpan.GetTraceId()); } for (auto& [_, info] : WriteInfos) { @@ -2931,6 +2932,7 @@ class TKqpForwardWriteActor : public TActorBootstrapped, std::vector writeIndex( Settings.GetWriteIndexes().begin(), Settings.GetWriteIndexes().end()); + TGuard guard(*Alloc); if (Settings.GetIsOlap()) { Batcher = CreateColumnDataBatcher(columnsMetadata, std::move(writeIndex), Alloc); } else { diff --git a/ydb/core/kqp/runtime/kqp_write_table.cpp b/ydb/core/kqp/runtime/kqp_write_table.cpp index 36fb6a6eb300..a96793dd1ab6 100644 --- a/ydb/core/kqp/runtime/kqp_write_table.cpp +++ b/ydb/core/kqp/runtime/kqp_write_table.cpp @@ -245,7 +245,7 @@ class TRowBatch : public IDataBatch { for (const auto& row : Rows) { AFL_ENSURE(row.size() == Rows.front().size()); const auto size = EstimateSize(row); - SerializedMemory += GetCellHeaderSize() * rows.Size() + size; + SerializedMemory += GetCellHeaderSize() * row.size() + size; Memory += size; } } @@ -548,6 +548,7 @@ class TColumnShardPayloadSerializer : public IPayloadSerializer { } void AddBatch(IDataBatchPtr&& batch) override { + TGuard guard(*Alloc); auto columnshardBatch = dynamic_cast(batch.Get()); AFL_ENSURE(columnshardBatch); if (columnshardBatch->IsEmpty()) { @@ -555,11 +556,10 @@ class TColumnShardPayloadSerializer : public IPayloadSerializer { } auto data = columnshardBatch->Extract(); AFL_ENSURE(data); - ShardAndFlushBatch(data, false); + ShardAndFlushBatch(std::move(data), false); } - void ShardAndFlushBatch(const TRecordBatchPtr& unshardedBatch, bool force) { - TGuard guard(*Alloc); + void ShardAndFlushBatch(TRecordBatchPtr&& unshardedBatch, bool force) { for (auto [shardId, shardBatch] : Sharding->SplitByShardsToArrowBatches( unshardedBatch, NKikimr::NMiniKQL::GetArrowMemoryPool())) { const i64 shardBatchMemory = NArrow::GetBatchDataSize(shardBatch); @@ -647,6 +647,7 @@ class TColumnShardPayloadSerializer : public IPayloadSerializer { } void Close() override { + TGuard guard(*Alloc); AFL_ENSURE(!Closed); Closed = true; FlushUnpreparedForce(); @@ -665,6 +666,7 @@ class TColumnShardPayloadSerializer : public IPayloadSerializer { } TBatches FlushBatchesForce() override { + TGuard guard(*Alloc); FlushUnpreparedForce(); TBatches newBatches; @@ -678,6 +680,7 @@ class TColumnShardPayloadSerializer : public IPayloadSerializer { } IDataBatchPtr FlushBatch(ui64 shardId) override { + TGuard guard(*Alloc); if (!Batches.contains(shardId)) { return {}; } diff --git a/ydb/core/kqp/session_actor/kqp_query_state.cpp b/ydb/core/kqp/session_actor/kqp_query_state.cpp index 1979f926ac32..0ddc4fa5bf6e 100644 --- a/ydb/core/kqp/session_actor/kqp_query_state.cpp +++ b/ydb/core/kqp/session_actor/kqp_query_state.cpp @@ -373,6 +373,7 @@ std::unique_ptr TKqpQueryState::BuildCompileSplittedR switch (GetAction()) { case NKikimrKqp::QUERY_ACTION_EXECUTE: + case NKikimrKqp::QUERY_ACTION_EXPLAIN: query = TKqpQueryId(Cluster, Database, UserRequestContext->DatabaseId, GetQuery(), settings, GetQueryParameterTypes(), gUCSettings); break; default: @@ -392,6 +393,14 @@ std::unique_ptr TKqpQueryState::BuildCompileSplittedR statementAst = Statements[CurrentStatementId]; } + if (GetAction() == NKikimrKqp::QUERY_ACTION_EXPLAIN) { + // Splitted Expr can be used only for CTAS statement. + // CTAS consists of 3 exprs: CREATE TABLE, REPLACE, ALTER TABLE RENAME. + // For explain we need only REPLACE, because explain doesn't support for DDL statements. + AFL_ENSURE(SplittedExprs.size() == 3); + NextSplittedExpr = 1; + } + return std::make_unique(UserToken, ClientAddress, uid, std::move(query), false, false, perStatementResult, compileDeadline, DbCounters, gUCSettingsPtr, ApplicationName, std::move(cookie), UserRequestContext, std::move(Orbit), TempTablesState, GetCollectDiagnostics(), statementAst, @@ -429,7 +438,7 @@ bool TKqpQueryState::PrepareNextStatementPart() { void TKqpQueryState::AddOffsetsToTransaction() { YQL_ENSURE(HasTopicOperations()); - const auto& operations = GetTopicOperations(); + const auto& operations = GetTopicOperationsFromRequest(); TMaybe consumer; if (operations.HasConsumer()) { @@ -442,7 +451,6 @@ void TKqpQueryState::AddOffsetsToTransaction() { } TopicOperations = NTopic::TTopicOperations(); - for (auto& topic : operations.GetTopics()) { auto path = CanonizePath(NPersQueue::GetFullTopicPath(GetDatabase(), topic.path())); @@ -452,8 +460,7 @@ void TKqpQueryState::AddOffsetsToTransaction() { } else { for (auto& range : partition.partition_offsets()) { YQL_ENSURE(consumer.Defined()); - - TopicOperations.AddOperation(path, partition.partition_id(), *consumer, range); + TopicOperations.AddOperation(path, partition.partition_id(), *consumer, range, partition.force_commit(), partition.kill_read_session(), partition.only_check_commited_to_finish(), partition.read_session_id()); } } } @@ -474,7 +481,7 @@ std::unique_ptr TKqpQueryState::BuildSchemeC auto navigate = std::make_unique(); navigate->DatabaseName = CanonizePath(GetDatabase()); - const auto& operations = GetTopicOperations(); + const auto& operations = GetTopicOperationsFromRequest(); TMaybe consumer; if (operations.HasConsumer()) consumer = operations.GetConsumer(); diff --git a/ydb/core/kqp/session_actor/kqp_query_state.h b/ydb/core/kqp/session_actor/kqp_query_state.h index 57411dde5964..ee6ca15b7796 100644 --- a/ydb/core/kqp/session_actor/kqp_query_state.h +++ b/ydb/core/kqp/session_actor/kqp_query_state.h @@ -332,7 +332,7 @@ class TKqpQueryState : public TNonCopyable { return RequestEv->GetQuery(); } - const ::NKikimrKqp::TTopicOperationsRequest& GetTopicOperations() const { + const ::NKikimrKqp::TTopicOperationsRequest& GetTopicOperationsFromRequest() const { return RequestEv->GetTopicOperations(); } @@ -432,14 +432,14 @@ class TKqpQueryState : public TNonCopyable { return true; } - TKqpPhyTxHolder::TConstPtr GetCurrentPhyTx() { + TKqpPhyTxHolder::TConstPtr GetCurrentPhyTx(bool isBatchQuery, NMiniKQL::TTypeEnvironment& txTypeEnv) { const auto& phyQuery = PreparedQuery->GetPhysicalQuery(); auto tx = PreparedQuery->GetPhyTxOrEmpty(CurrentTx); - if (TxCtx->CanDeferEffects()) { + if (TxCtx->CanDeferEffects() && !isBatchQuery) { // Olap sinks require separate tnx with commit. while (tx && tx->GetHasEffects() && !TxCtx->HasOlapTable) { - QueryData->CreateKqpValueMap(tx); + QueryData->PrepareParameters(tx, PreparedQuery, txTypeEnv); bool success = TxCtx->AddDeferredEffect(tx, QueryData); YQL_ENSURE(success); if (CurrentTx + 1 < phyQuery.TransactionsSize()) { diff --git a/ydb/core/kqp/session_actor/kqp_session_actor.cpp b/ydb/core/kqp/session_actor/kqp_session_actor.cpp index 4fc64ec1a1c4..18348af42231 100644 --- a/ydb/core/kqp/session_actor/kqp_session_actor.cpp +++ b/ydb/core/kqp/session_actor/kqp_session_actor.cpp @@ -98,23 +98,29 @@ void FillColumnsMeta(const NKqpProto::TKqpPhyQuery& phyQuery, NKikimrKqp::TQuery } } -bool FillTableSinkSettings(NKikimrKqp::TKqpTableSinkSettings& settings, const TKqpPhyTxHolder::TConstPtr& tx) { - for (const auto& stage : tx->GetStages()) { - if (stage.SinksSize() != 1) { - continue; - } - for (auto& sink : stage.GetSinks()) { - return sink.GetInternalSink().GetSettings().UnpackTo(&settings); - } +bool FillTableSinkSettings(NKikimrKqp::TKqpTableSinkSettings& settings, const NKqpProto::TKqpSink& sink) { + if (sink.GetTypeCase() == NKqpProto::TKqpSink::kInternalSink + && sink.GetInternalSink().GetSettings().Is()) + { + return sink.GetInternalSink().GetSettings().UnpackTo(&settings); } return false; } -bool IsBatchQuery(const TKqpPhyTxHolder::TConstPtr& tx) { - NKikimrKqp::TKqpTableSinkSettings settings; - auto isFilledSettings = FillTableSinkSettings(settings, tx); - return isFilledSettings && settings.GetIsBatch(); +bool IsBatchQuery(const NKqpProto::TKqpPhyQuery& physicalQuery) { + NKikimrKqp::TKqpTableSinkSettings sinkSettings; + for (const auto& tx : physicalQuery.GetTransactions()) { + for (const auto& stage : tx.GetStages()) { + for (auto& sink : stage.GetSinks()) { + auto isFilledSettings = FillTableSinkSettings(sinkSettings, sink); + if (isFilledSettings && sinkSettings.HasIsBatch() && sinkSettings.GetIsBatch()) { + return true; + } + } + } + } + return false; } class TRequestFail : public yexception { @@ -624,7 +630,7 @@ class TKqpSessionActor : public TActorBootstrapped { if (QueryState->CompileResult->NeedToSplit) { if (!QueryState->HasTxControl()) { - YQL_ENSURE(QueryState->GetAction() == NKikimrKqp::QUERY_ACTION_EXECUTE); + YQL_ENSURE(QueryState->GetAction() == NKikimrKqp::QUERY_ACTION_EXECUTE || QueryState->GetAction() == NKikimrKqp::QUERY_ACTION_EXPLAIN); auto ev = QueryState->BuildSplitRequest(CompilationCookie, GUCSettings); Send(MakeKqpCompileServiceID(SelfId().NodeId()), ev.release(), 0, QueryState->QueryId, QueryState->KqpSessionSpan.GetTraceId()); @@ -1159,9 +1165,11 @@ class TKqpSessionActor : public TActorBootstrapped { return; } + bool isBatchQuery = IsBatchQuery(QueryState->PreparedQuery->GetPhysicalQuery()); + TKqpPhyTxHolder::TConstPtr tx; try { - tx = QueryState->GetCurrentPhyTx(); + tx = QueryState->GetCurrentPhyTx(isBatchQuery, QueryState->TxCtx->TxAlloc->TypeEnv); } catch (const yexception& ex) { ythrow TRequestFail(Ydb::StatusIds::BAD_REQUEST) << ex.what(); } @@ -1170,7 +1178,14 @@ class TKqpSessionActor : public TActorBootstrapped { return; } - if (QueryState->TxCtx->ShouldExecuteDeferredEffects(tx)) { + if (Settings.TableService.GetEnableOltpSink() && isBatchQuery) { + if (!Settings.TableService.GetEnableBatchUpdates()) { + ReplyQueryError(Ydb::StatusIds::PRECONDITION_FAILED, + "Batch updates and deletes are disabled at current time."); + } + + ExecutePartitioned(tx); + } else if (QueryState->TxCtx->ShouldExecuteDeferredEffects(tx)) { ExecuteDeferredEffectsImmediately(tx); } else if (auto commit = QueryState->ShouldCommitWithCurrentTx(tx); commit || tx) { ExecutePhyTx(tx, commit); @@ -1179,6 +1194,33 @@ class TKqpSessionActor : public TActorBootstrapped { } } + void ExecutePartitioned(const TKqpPhyTxHolder::TConstPtr& tx) { + if (QueryState->HasTxControl()) { + NYql::TIssues issues; + return ReplyQueryError( + ::Ydb::StatusIds::StatusCode::StatusIds_StatusCode_BAD_REQUEST, + "BATCH operation can be executed only in NoTx mode.", + MessageFromIssues(issues)); + } + + auto& txCtx = *QueryState->TxCtx; + + auto literalRequest = PrepareLiteralRequest(QueryState.get()); + auto physicalRequest = PreparePhysicalRequest(QueryState.get(), txCtx.TxAlloc); + + if (QueryState->PreparedQuery->GetTransactions().size() == 2) { + literalRequest.Transactions.emplace_back(tx, QueryState->QueryData); + } else { + physicalRequest.Transactions.emplace_back(tx, QueryState->QueryData); + } + + QueryState->TxCtx->OnNewExecutor(false); + QueryState->Commited = true; + + SendToPartitionedExecuter(QueryState->TxCtx.Get(), std::move(literalRequest), std::move(physicalRequest)); + QueryState->CurrentTx += QueryState->PreparedQuery->GetTransactions().size(); + } + void ExecuteDeferredEffectsImmediately(const TKqpPhyTxHolder::TConstPtr& tx) { YQL_ENSURE(QueryState->TxCtx->ShouldExecuteDeferredEffects(tx)); @@ -1270,22 +1312,6 @@ class TKqpSessionActor : public TActorBootstrapped { default: YQL_ENSURE(false, "Unexpected physical tx type in data query: " << (ui32)tx->GetType()); } - - for (const auto& paramDesc : QueryState->PreparedQuery->GetParameters()) { - if (!paramDesc.GetName().StartsWith(NBatchParams::Header)) { - continue; - } - - NKikimrMiniKQL::TType protoType = paramDesc.GetType(); - NKikimr::NMiniKQL::TType* paramType = ImportTypeFromProto(protoType, txCtx.TxAlloc->TypeEnv); - - NUdf::TUnboxedValue value = MakeDefaultValueByType(paramType); - if (paramDesc.GetName() == NBatchParams::IsFirstQuery || paramDesc.GetName() == NBatchParams::IsLastQuery) { - value = NUdf::TUnboxedValuePod(true); - } - - QueryState->QueryData->AddUVParam(paramDesc.GetName(), paramType, value); - } } try { @@ -1358,7 +1384,6 @@ class TKqpSessionActor : public TActorBootstrapped { } } } - request.TopicOperations = std::move(txCtx.TopicOperations); } else if (QueryState->ShouldAcquireLocks(tx) && (!txCtx.HasOlapTable || Settings.TableService.GetEnableOlapSink())) { request.AcquireLocksTxId = txCtx.Locks.GetLockTxId(); @@ -1423,22 +1448,6 @@ class TKqpSessionActor : public TActorBootstrapped { request.ResourceManager_ = ResourceManager_; LOG_D("Sending to Executer TraceId: " << request.TraceId.GetTraceId() << " " << request.TraceId.GetSpanIdSize()); - if (!request.Transactions.empty()) { - auto isBatch = IsBatchQuery(request.Transactions.front().Body); - - if (Settings.TableService.GetEnableOltpSink() && isBatch) { - if (!Settings.TableService.GetEnableBatchUpdates()) { - ReplyQueryError(Ydb::StatusIds::PRECONDITION_FAILED, - "Batch updates and deletes are disabled at current time."); - } - - SendToPartitionedExecuter(txCtx, std::move(request)); - return; - } - - YQL_ENSURE(!isBatch || Settings.TableService.GetEnableBatchUpdates()); - } - if (Settings.TableService.GetEnableOltpSink() && !txCtx->TxManager) { txCtx->TxManager = CreateKqpTransactionManager(); txCtx->TxManager->SetAllowVolatile(AppData()->FeatureFlags.GetEnableDataShardVolatileTransactions()); @@ -1504,12 +1513,63 @@ class TKqpSessionActor : public TActorBootstrapped { ExecuterId = exId; } - void SendToPartitionedExecuter(TKqpTransactionContext* txCtx, IKqpGateway::TExecPhysicalRequest&& request) { - auto executerActor = CreateKqpPartitionedExecuter(std::move(request), SelfId(), Settings.Database, - QueryState ? QueryState->UserToken : TIntrusiveConstPtr(), Counters, - RequestCounters, Settings.TableService, AsyncIoFactory, QueryState ? QueryState->PreparedQuery : nullptr, - QueryState ? QueryState->UserRequestContext : MakeIntrusive("", Settings.Database, SessionId), - QueryState ? QueryState->StatementResultIndex : 0, FederatedQuerySetup, GUCSettings, txCtx->ShardIdToTableInfo); + void SendToPartitionedExecuter(TKqpTransactionContext* txCtx, IKqpGateway::TExecPhysicalRequest&& literalRequest, + IKqpGateway::TExecPhysicalRequest&& physicalRequest) + { + physicalRequest.Orbit = std::move(QueryState->Orbit); + QueryState->StatementResultSize = GetResultsCount(physicalRequest); + + literalRequest.TraceId = QueryState->KqpSessionSpan.GetTraceId(); + + physicalRequest.LocksOp = ELocksOp::Commit; + physicalRequest.PerRequestDataSizeLimit = RequestControls.PerRequestDataSizeLimit; + physicalRequest.MaxShardCount = RequestControls.MaxShardCount; + physicalRequest.TraceId = QueryState + ? QueryState->KqpSessionSpan.GetTraceId() + : NWilson::TTraceId(); + physicalRequest.CaFactory_ = CaFactory_; + physicalRequest.ResourceManager_ = ResourceManager_; + + const auto& queryLimitsProto = Settings.TableService.GetQueryLimits(); + const auto& bufferLimitsProto = queryLimitsProto.GetBufferLimits(); + const ui64 writeBufferMemoryLimit = bufferLimitsProto.HasWriteBufferMemoryLimitBytes() + ? bufferLimitsProto.GetWriteBufferMemoryLimitBytes() + : ui64(Settings.MkqlMaxMemoryLimit); + const ui64 writeBufferInitialMemoryLimit = writeBufferMemoryLimit < ui64(Settings.MkqlInitialMemoryLimit) + ? writeBufferMemoryLimit + : ui64(Settings.MkqlInitialMemoryLimit); + + TKqpPartitionedExecuterSettings settings{ + .LiteralRequest = std::move(literalRequest), + .PhysicalRequest = std::move(physicalRequest), + .SessionActorId = SelfId(), + .FuncRegistry = AppData()->FunctionRegistry, + .TimeProvider = AppData()->TimeProvider, + .RandomProvider = AppData()->RandomProvider, + .Database = Settings.Database, + .UserToken = QueryState + ? QueryState->UserToken + : TIntrusiveConstPtr(), + .RequestCounters = RequestCounters, + .TableServiceConfig = Settings.TableService, + .AsyncIoFactory = AsyncIoFactory, + .PreparedQuery = QueryState + ? QueryState->PreparedQuery + : nullptr, + .UserRequestContext = QueryState + ? QueryState->UserRequestContext + : MakeIntrusive("", Settings.Database, SessionId), + .StatementResultIndex = QueryState + ? QueryState->StatementResultIndex + : 0, + .FederatedQuerySetup = FederatedQuerySetup, + .GUCSettings = GUCSettings, + .ShardIdToTableInfo = txCtx->ShardIdToTableInfo, + .WriteBufferInitialMemoryLimit = writeBufferInitialMemoryLimit, + .WriteBufferMemoryLimit = writeBufferMemoryLimit, + }; + + auto executerActor = CreateKqpPartitionedExecuter(std::move(settings)); ExecuterId = RegisterWithSameMailbox(executerActor); LOG_D("Created new KQP partitioned executer: " << ExecuterId); diff --git a/ydb/core/kqp/topics/kqp_topics.cpp b/ydb/core/kqp/topics/kqp_topics.cpp index fcd14d18934a..7dff2f08679c 100644 --- a/ydb/core/kqp/topics/kqp_topics.cpp +++ b/ydb/core/kqp/topics/kqp_topics.cpp @@ -1,6 +1,7 @@ #include "kqp_topics.h" #include +#include #include #include @@ -26,21 +27,50 @@ static void UpdateSupportivePartition(TMaybe& lhs, const TMaybe& rhs // bool TConsumerOperations::IsValid() const { - return Offsets_.GetNumIntervals() == 1; + return Offsets_.GetNumIntervals() <= 1; } -std::pair TConsumerOperations::GetRange() const +std::pair TConsumerOperations::GetOffsetsCommitRange() const { Y_ABORT_UNLESS(IsValid()); - return {Offsets_.Min(), Offsets_.Max()}; + if (Offsets_.Empty()) { + return {0,0}; + } else { + return {Offsets_.Min(), Offsets_.Max()}; + } +} + +bool TConsumerOperations::GetForceCommit() const +{ + return ForceCommit_; +} + +bool TConsumerOperations::GetKillReadSession() const +{ + return KillReadSession_; +} + +bool TConsumerOperations::GetOnlyCheckCommitedToFinish() const +{ + return OnlyCheckCommitedToFinish_; } -void TConsumerOperations::AddOperation(const TString& consumer, const Ydb::Topic::OffsetsRange& range) +TString TConsumerOperations::GetReadSessionId() const +{ + return ReadSessionId_; +} + +void TConsumerOperations::AddOperation(const TString& consumer, + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId) { Y_ABORT_UNLESS(Consumer_.Empty() || Consumer_ == consumer); - AddOperationImpl(consumer, range.start(), range.end()); + AddOperationImpl(consumer, range.start(), range.end(), forceCommit, killReadSession, onlyCheckCommitedToFinish, readSessionId); } void TConsumerOperations::Merge(const TConsumerOperations& rhs) @@ -48,13 +78,22 @@ void TConsumerOperations::Merge(const TConsumerOperations& rhs) Y_ABORT_UNLESS(rhs.Consumer_.Defined()); Y_ABORT_UNLESS(Consumer_.Empty() || Consumer_ == rhs.Consumer_); - for (auto& range : rhs.Offsets_) { - AddOperationImpl(*rhs.Consumer_, range.first, range.second); + if (!rhs.Offsets_.Empty()) { + for (auto& range : rhs.Offsets_) { + AddOperationImpl(*rhs.Consumer_, range.first, range.second, rhs.GetForceCommit(), rhs.GetKillReadSession(), rhs.GetOnlyCheckCommitedToFinish(), rhs.GetReadSessionId()); + } + } else { + AddOperationImpl(*rhs.Consumer_, 0, 0, rhs.GetForceCommit(), rhs.GetKillReadSession(), rhs.GetOnlyCheckCommitedToFinish(), rhs.GetReadSessionId()); } } void TConsumerOperations::AddOperationImpl(const TString& consumer, - ui64 begin, ui64 end) + ui64 begin, + ui64 end, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId) { if (Offsets_.Intersects(begin, end)) { ythrow TOffsetsRangeIntersectExpection() << "offset ranges intersect"; @@ -64,7 +103,14 @@ void TConsumerOperations::AddOperationImpl(const TString& consumer, Consumer_ = consumer; } - Offsets_.InsertInterval(begin, end); + if (end != 0) { + Offsets_.InsertInterval(begin, end); + } + + ForceCommit_ = forceCommit; + KillReadSession_ = killReadSession; + OnlyCheckCommitedToFinish_ = onlyCheckCommitedToFinish; + ReadSessionId_ = readSessionId; } // @@ -76,9 +122,14 @@ bool TTopicPartitionOperations::IsValid() const [](auto& x) { return x.second.IsValid(); }); } -void TTopicPartitionOperations::AddOperation(const TString& topic, ui32 partition, +void TTopicPartitionOperations::AddOperation(const TString& topic, + ui32 partition, const TString& consumer, - const Ydb::Topic::OffsetsRange& range) + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId) { Y_ABORT_UNLESS(Topic_.Empty() || Topic_ == topic); Y_ABORT_UNLESS(Partition_.Empty() || Partition_ == partition); @@ -88,7 +139,7 @@ void TTopicPartitionOperations::AddOperation(const TString& topic, ui32 partitio Partition_ = partition; } - Operations_[consumer].AddOperation(consumer, range); + Operations_[consumer].AddOperation(consumer, range, forceCommit, killReadSession, onlyCheckCommitedToFinish, readSessionId); } void TTopicPartitionOperations::AddOperation(const TString& topic, ui32 partition, @@ -117,11 +168,15 @@ void TTopicPartitionOperations::BuildTopicTxs(TTopicOperationTransactions& txs) for (auto& [consumer, operations] : Operations_) { NKikimrPQ::TPartitionOperation* o = t.tx.MutableOperations()->Add(); o->SetPartitionId(*Partition_); - auto [begin, end] = operations.GetRange(); - o->SetBegin(begin); - o->SetEnd(end); + auto [begin, end] = operations.GetOffsetsCommitRange(); + o->SetCommitOffsetsBegin(begin); + o->SetCommitOffsetsEnd(end); o->SetConsumer(consumer); o->SetPath(*Topic_); + o->SetKillReadSession(operations.GetKillReadSession()); + o->SetForceCommit(operations.GetForceCommit()); + o->SetOnlyCheckCommitedToFinish(operations.GetOnlyCheckCommitedToFinish()); + o->SetReadSessionId(operations.GetReadSessionId()); } if (HasWriteOperations_) { @@ -256,14 +311,25 @@ bool TTopicOperations::TabletHasReadOperations(ui64 tabletId) const return false; } -void TTopicOperations::AddOperation(const TString& topic, ui32 partition, +void TTopicOperations::AddOperation(const TString& topic, + ui32 partition, const TString& consumer, - const Ydb::Topic::OffsetsRange& range) + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId + ) { TTopicPartition key{topic, partition}; - Operations_[key].AddOperation(topic, partition, + Operations_[key].AddOperation(topic, + partition, consumer, - range); + range, + forceCommit, + killReadSession, + onlyCheckCommitedToFinish, + readSessionId); HasReadOperations_ = true; } diff --git a/ydb/core/kqp/topics/kqp_topics.h b/ydb/core/kqp/topics/kqp_topics.h index b04e7a186f5e..8eff402d1aa6 100644 --- a/ydb/core/kqp/topics/kqp_topics.h +++ b/ydb/core/kqp/topics/kqp_topics.h @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -26,20 +27,40 @@ class TConsumerOperations { public: bool IsValid() const; - std::pair GetRange() const; + std::pair GetOffsetsCommitRange() const; - ui64 GetBegin() const; - ui64 GetEnd() const; + ui64 GetOffsetCommitBegin() const; + ui64 GetOffsetCommitEnd() const; + + bool GetForceCommit() const; + bool GetKillReadSession() const; + bool GetOnlyCheckCommitedToFinish() const; + TString GetReadSessionId() const; + + void AddOperation(const TString& consumer, + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit = false, + bool killReadSession = false, + bool onlyCheckCommitedToFinish = false, + const TString& readSessionId = {}); - void AddOperation(const TString& consumer, const Ydb::Topic::OffsetsRange& range); void Merge(const TConsumerOperations& rhs); private: void AddOperationImpl(const TString& consumer, - ui64 begin, ui64 end); + ui64 begin, + ui64 end, + bool forceCommit = false, + bool killReadSession = false, + bool onlyCheckCommitedToFinish = false, + const TString& readSessionId = {}); TMaybe Consumer_; TDisjointIntervalTree Offsets_; + bool ForceCommit_ = false; + bool KillReadSession_ = false; + bool OnlyCheckCommitedToFinish_ = false; + TString ReadSessionId_; }; struct TTopicOperationTransaction { @@ -53,9 +74,14 @@ class TTopicPartitionOperations { public: bool IsValid() const; - void AddOperation(const TString& topic, ui32 partition, + void AddOperation(const TString& topic, + ui32 partition, const TString& consumer, - const Ydb::Topic::OffsetsRange& range); + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit = false, + bool killReadSession = false, + bool onlyCheckCommitedToFinish = false, + const TString& readSessionId = {}); void AddOperation(const TString& topic, ui32 partition, TMaybe supportivePartition); @@ -108,7 +134,11 @@ class TTopicOperations { void AddOperation(const TString& topic, ui32 partition, const TString& consumer, - const Ydb::Topic::OffsetsRange& range); + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId); void AddOperation(const TString& topic, ui32 partition, TMaybe supportivePartition); diff --git a/ydb/core/kqp/ut/batch_operations/kqp_batch_delete_ut.cpp b/ydb/core/kqp/ut/batch_operations/kqp_batch_delete_ut.cpp new file mode 100644 index 000000000000..19b5c64ad6ad --- /dev/null +++ b/ydb/core/kqp/ut/batch_operations/kqp_batch_delete_ut.cpp @@ -0,0 +1,362 @@ +#include + +#include +#include + +#include + +namespace NKikimr { +namespace NKqp { + +using namespace NYdb; +using namespace NYdb::NQuery; + +namespace { + +NKikimrConfig::TAppConfig GetAppConfig(size_t maxBatchSize = 10000, size_t partitionLimit = 10) { + auto app = NKikimrConfig::TAppConfig(); + app.MutableTableServiceConfig()->SetEnableOlapSink(true); + app.MutableTableServiceConfig()->SetEnableOltpSink(true); + app.MutableTableServiceConfig()->SetEnableBatchUpdates(true); + app.MutableTableServiceConfig()->MutableBatchOperationSettings()->SetMaxBatchSize(maxBatchSize); + app.MutableTableServiceConfig()->MutableBatchOperationSettings()->SetPartitionExecutionLimit(partitionLimit); + return app; +} + +void TestSimpleOnePartition(size_t maxBatchSize) { + TKikimrRunner kikimr(GetAppConfig(maxBatchSize)); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH DELETE FROM KeyValue; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM KeyValue; + )"); + } + { + auto query = Q_(R"( + BATCH DELETE FROM KeyValueLargePartition; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM KeyValueLargePartition; + )"); + } + { + auto query = Q_(R"( + BATCH DELETE FROM Test + WHERE Amount >= 5000ul; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM Test + WHERE Amount >= 5000ul; + )"); + } + { + auto query = Q_(R"( + BATCH DELETE FROM Test + WHERE Amount < 5000ul AND Group < 2; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM Test + WHERE Amount < 5000ul AND Group < 2; + )"); + } +} + +void TestSimplePartitions(size_t maxBatchSize, size_t partitionLimit) { + TKikimrRunner kikimr(GetAppConfig(maxBatchSize, partitionLimit)); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH DELETE FROM TwoShard + WHERE Key >= 2; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM TwoShard + WHERE Key >= 2; + )"); + } + { + auto query = Q_(R"( + BATCH DELETE FROM EightShard + WHERE Key > 300 AND Data = 2; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM EightShard + WHERE Key > 300 AND Data = 2; + )"); + } + { + auto query = Q_(R"( + BATCH DELETE FROM Logs + WHERE App = "kikimr-db"; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM Logs + WHERE App = "kikimr-db"; + )"); + } + { + auto query = Q_(R"( + DELETE FROM Join2 + WHERE Key1 = 102 AND Key2 = "One"; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM Join2 + WHERE Key1 = 102 AND Key2 = "One"; + )"); + } + { + auto query = Q_(R"( + BATCH DELETE FROM TuplePrimaryDescending + WHERE Col3 = 0; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM TuplePrimaryDescending + WHERE Col3 = 0; + )"); + } +} + +void TestManyPartitions(size_t maxBatchSize, size_t totalRows, size_t shards, size_t partitionLimit) { + TKikimrRunner kikimr(GetAppConfig(maxBatchSize, partitionLimit)); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + CreateManyShardsTable(kikimr, totalRows, shards, 1000); + + { + auto query = Q_(R"( + BATCH DELETE FROM ManyShardsTable + WHERE Data >= 200; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM ManyShardsTable + WHERE Data >= 200; + )"); + } +} + +void TestLarge(size_t maxBatchSize, size_t rowsPerShard) { + TKikimrRunner kikimr(GetAppConfig(maxBatchSize)); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + CreateLargeTable(kikimr, rowsPerShard, 4, 4, 10000); + + { + auto query = Q_(R"( + BATCH DELETE FROM LargeTable + WHERE Key >= 2000; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM LargeTable + WHERE Key >= 2000; + )"); + } +} + +} // namespace + +Y_UNIT_TEST_SUITE(KqpBatchDelete) { + Y_UNIT_TEST(SimpleOnePartition) { + for (size_t size = 1; size <= 1000; size *= 10) { + TestSimpleOnePartition(size); + } + } + + Y_UNIT_TEST(SimplePartitions) { + for (size_t size = 1; size <= 1000; size *= 10) { + for (size_t partitionLimit = 1; partitionLimit <= 10; partitionLimit *= 2) { + TestSimplePartitions(size, partitionLimit); + } + } + } + + Y_UNIT_TEST(ManyPartitions_1) { + for (size_t size = 1; size <= 1000; size *= 10) { + for (size_t partitionLimit = 1; partitionLimit <= 16; partitionLimit *= 2) { + TestManyPartitions(size, 100, 10, partitionLimit); + } + } + } + + Y_UNIT_TEST(ManyPartitions_2) { + for (size_t size = 1; size <= 1000; size *= 10) { + for (size_t partitionLimit = 1; partitionLimit <= 52; partitionLimit *= 4) { + TestManyPartitions(size, 500, 50, partitionLimit); + } + } + } + + Y_UNIT_TEST(ManyPartitions_3) { + for (size_t size = 1; size <= 1000; size *= 10) { + for (size_t partitionLimit = 1; partitionLimit <= 128; partitionLimit *= 8) { + TestManyPartitions(size, 1000, 100, partitionLimit); + } + } + } + + Y_UNIT_TEST(Large_1) { + ui32 sizeLimit = NSan::PlainOrUnderSanitizer(1000, 100); + for (size_t size = 1; size <= sizeLimit; size *= 10) { + TestLarge(size, 100); + } + } + + Y_UNIT_TEST(Large_2) { + ui32 sizeLimit = NSan::PlainOrUnderSanitizer(10000, 1000); + ui32 shardRows = NSan::PlainOrUnderSanitizer(10000, 5000); + for (size_t size = 100; size <= sizeLimit; size *= 10) { + TestLarge(size, shardRows); + } + } + + Y_UNIT_TEST(Large_3) { + ui32 sizeLimit = NSan::PlainOrUnderSanitizer(100000, 10000); + ui32 shardRows = NSan::PlainOrUnderSanitizer(50000, 25000); + for (size_t size = 1000; size <= sizeLimit; size *= 10) { + TestLarge(size, shardRows); + } + } + + Y_UNIT_TEST(MultiStatement) { + TKikimrRunner kikimr(GetAppConfig()); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH DELETE FROM Test + WHERE Amount IN ( + SELECT Amount FROM Test + ); + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH DELETE FROM Test + WHERE Amount > 100; + SELECT 42; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH DELETE FROM Test + WHERE Amount > 100; + SELECT * FROM Test; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH DELETE FROM KeyValue + WHERE Key >= 3; + UPSERT INTO KeyValue (Key, Value) + VALUES (10, "Value10"); + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH DELETE FROM KeyValue; + UPSERT INTO KeyValue2 (Key, Value) + VALUES ("Key10", "Value10"); + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + } + + Y_UNIT_TEST(Returning) { + TKikimrRunner kikimr(GetAppConfig()); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH DELETE FROM KeyValue + WHERE Key >= 3 + RETURNING *; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH DELETE is unsupported with RETURNING", result.GetIssues().ToString()); + } + } + + Y_UNIT_TEST(HasTxControl) { + TKikimrRunner kikimr(GetAppConfig()); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH DELETE FROM KeyValue + WHERE Key >= 3; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::BAD_REQUEST); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH operation can be executed only in NoTx mode.", result.GetIssues().ToString()); + } + } +} + +} // namespace NKqp +} // namespace NKikimr diff --git a/ydb/core/kqp/ut/batch_operations/kqp_batch_update_ut.cpp b/ydb/core/kqp/ut/batch_operations/kqp_batch_update_ut.cpp new file mode 100644 index 000000000000..f16cd5e73e02 --- /dev/null +++ b/ydb/core/kqp/ut/batch_operations/kqp_batch_update_ut.cpp @@ -0,0 +1,466 @@ +#include + +#include +#include + +#include + +namespace NKikimr { +namespace NKqp { + +using namespace NYdb; +using namespace NYdb::NQuery; + +namespace { + +NKikimrConfig::TAppConfig GetAppConfig(size_t maxBatchSize = 10000, size_t partitionLimit = 10) { + auto app = NKikimrConfig::TAppConfig(); + app.MutableTableServiceConfig()->SetEnableOlapSink(true); + app.MutableTableServiceConfig()->SetEnableOltpSink(true); + app.MutableTableServiceConfig()->SetEnableBatchUpdates(true); + app.MutableTableServiceConfig()->MutableBatchOperationSettings()->SetMaxBatchSize(maxBatchSize); + app.MutableTableServiceConfig()->MutableBatchOperationSettings()->SetPartitionExecutionLimit(partitionLimit); + return app; +} + +void TestSimpleOnePartition(size_t maxBatchSize) { + TKikimrRunner kikimr(GetAppConfig(maxBatchSize)); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH UPDATE KeyValue + SET Value = "None"; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM KeyValue + WHERE Value != "None"; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE KeyValue2 + SET Value = "None"; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM KeyValue2 + WHERE Value != "None"; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE KeyValueLargePartition + SET Value = "None"; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM KeyValueLargePartition + WHERE Value != "None"; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Amount = 0 + WHERE Comment = "None"; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM Test + WHERE Comment != "None" AND Amount != 0; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Amount = 100, Comment = "Yes" + WHERE Comment = "None" AND Group < 2; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM Test + WHERE Group < 2 AND Comment != "Yes" AND Amount != 100; + )"); + } +} + +void TestSimplePartitions(size_t maxBatchSize, size_t partitionLimit) { + TKikimrRunner kikimr(GetAppConfig(maxBatchSize, partitionLimit)); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH UPDATE TwoShard + SET Value2 = 3; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM TwoShard + WHERE Value2 != 3; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE TwoShard + SET Value2 = 5 + WHERE Key >= 2; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM TwoShard + WHERE Key >= 2 AND Value2 != 5; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE EightShard + SET Text = "None" + WHERE Key > 300 AND Data = 2; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM EightShard + WHERE Key > 300 AND Data = 2 AND Text != "None"; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE Logs + SET Message = "" + WHERE App = "kikimr-db"; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM Logs + WHERE App = "kikimr-db" AND Message != ""; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE Join2 + SET Name = "None", Value2 = "ValueN" + WHERE Key1 = 102 AND Key2 = "One"; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM Join2 + WHERE Key1 = 102 AND Key2 = "One" AND Name != "None" AND Value2 != "ValueN"; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE TuplePrimaryDescending + SET Col4 = 2 + WHERE Col3 = 0; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM TuplePrimaryDescending + WHERE Col3 = 0 AND Col4 != 2; + )"); + } +} + +void TestManyPartitions(size_t maxBatchSize, size_t totalRows, size_t shards, size_t partitionLimit) { + TKikimrRunner kikimr(GetAppConfig(maxBatchSize, partitionLimit)); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + CreateManyShardsTable(kikimr, totalRows, shards, 1000); + + { + auto query = Q_(R"( + BATCH UPDATE ManyShardsTable + SET Data = -10; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM ManyShardsTable + WHERE Data != -10; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE ManyShardsTable + SET Data = 2 + WHERE Key >= 2000; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM ManyShardsTable + WHERE Key >= 2000 AND Data != 2; + )"); + } +} + +void TestLarge(size_t maxBatchSize, size_t rowsPerShard) { + TKikimrRunner kikimr(GetAppConfig(maxBatchSize)); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + CreateLargeTable(kikimr, rowsPerShard, 4, 4, 10000); + + { + auto query = Q_(R"( + BATCH UPDATE LargeTable + SET Data = -1, DataText = "Updated"; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM LargeTable + WHERE Data != -1 AND DataText != "Updated"; + )"); + } + { + auto query = Q_(R"( + BATCH UPDATE LargeTable + SET Data = 2 + WHERE Key >= 2000; + )"); + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + + ExecQueryAndTestEmpty(session, R"( + SELECT count(*) FROM LargeTable + WHERE Key >= 2000 AND Data != 2; + )"); + } +} + +} // namespace + +Y_UNIT_TEST_SUITE(KqpBatchUpdate) { + Y_UNIT_TEST(SimpleOnePartition) { + for (size_t size = 1; size <= 1000; size *= 10) { + TestSimpleOnePartition(size); + } + } + + Y_UNIT_TEST(SimplePartitions) { + for (size_t size = 1; size <= 1000; size *= 10) { + for (size_t partitionLimit = 1; partitionLimit <= 10; partitionLimit *= 2) { + TestSimplePartitions(size, partitionLimit); + } + } + } + + Y_UNIT_TEST(ManyPartitions_1) { + for (size_t size = 1; size <= 1000; size *= 10) { + for (size_t partitionLimit = 1; partitionLimit <= 16; partitionLimit *= 2) { + TestManyPartitions(size, 100, 10, partitionLimit); + } + } + } + + Y_UNIT_TEST(ManyPartitions_2) { + for (size_t size = 1; size <= 1000; size *= 10) { + for (size_t partitionLimit = 1; partitionLimit <= 52; partitionLimit *= 4) { + TestManyPartitions(size, 500, 50, partitionLimit); + } + } + } + + Y_UNIT_TEST(ManyPartitions_3) { + for (size_t size = 1; size <= 1000; size *= 10) { + for (size_t partitionLimit = 1; partitionLimit <= 128; partitionLimit *= 8) { + TestManyPartitions(size, 1000, 100, partitionLimit); + } + } + } + + Y_UNIT_TEST(Large_1) { + ui32 sizeLimit = NSan::PlainOrUnderSanitizer(1000, 100); + for (size_t size = 1; size <= sizeLimit; size *= 10) { + TestLarge(size, 100); + } + } + + Y_UNIT_TEST(Large_2) { + ui32 sizeLimit = NSan::PlainOrUnderSanitizer(10000, 1000); + ui32 shardRows = NSan::PlainOrUnderSanitizer(10000, 5000); + for (size_t size = 100; size <= sizeLimit; size *= 10) { + TestLarge(size, shardRows); + } + } + + Y_UNIT_TEST(Large_3) { + ui32 sizeLimit = NSan::PlainOrUnderSanitizer(100000, 10000); + ui32 shardRows = NSan::PlainOrUnderSanitizer(50000, 25000); + for (size_t size = 1000; size <= sizeLimit; size *= 10) { + TestLarge(size, shardRows); + } + } + + Y_UNIT_TEST(NotIdempotent) { + TKikimrRunner kikimr(GetAppConfig()); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Amount = Amount * 10; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "Batch update is only supported for idempotent updates.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Amount = Amount * Group; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "Batch update is only supported for idempotent updates.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Name = Comment, Comment = Name; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "Batch update is only supported for idempotent updates.", result.GetIssues().ToString()); + } + } + + Y_UNIT_TEST(MultiStatement) { + TKikimrRunner kikimr(GetAppConfig()); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Amount = 1000 + WHERE Age in ( + SELECT Age FROM Test + ); + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Amount = 1000; + SELECT 42; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Amount = 1000; + SELECT * FROM Test; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH UPDATE KeyValue + SET Value = "None"; + UPSERT INTO KeyValue (Key, Value) + VALUES (10, "Value10"); + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + { + auto query = Q_(R"( + BATCH UPDATE KeyValue + SET Value = "None"; + UPSERT INTO KeyValue2 (Key, Value) + VALUES ("Key10", "Value10"); + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH can't be used with multiple writes or reads.", result.GetIssues().ToString()); + } + } + + Y_UNIT_TEST(Returning) { + TKikimrRunner kikimr(GetAppConfig()); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Amount = 1000 + RETURNING *; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH UPDATE is unsupported with RETURNING", result.GetIssues().ToString()); + } + } + + Y_UNIT_TEST(HasTxControl) { + TKikimrRunner kikimr(GetAppConfig()); + auto db = kikimr.GetQueryClient(); + auto session = db.GetSession().GetValueSync().GetSession(); + + { + auto query = Q_(R"( + BATCH UPDATE Test + SET Amount = 1000; + )"); + + auto result = session.ExecuteQuery(query, TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::BAD_REQUEST); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "BATCH operation can be executed only in NoTx mode.", result.GetIssues().ToString()); + } + } +} + +} // namespace NKqp +} // namespace NKikimr diff --git a/ydb/core/kqp/ut/batch_operations/ya.make b/ydb/core/kqp/ut/batch_operations/ya.make new file mode 100644 index 000000000000..e569dc0df7f6 --- /dev/null +++ b/ydb/core/kqp/ut/batch_operations/ya.make @@ -0,0 +1,26 @@ +UNITTEST_FOR(ydb/core/kqp) + +FORK_SUBTESTS() +SPLIT_FACTOR(50) + +IF (WITH_VALGRIND) + SIZE(LARGE) + TAG(ya:fat) +ELSE() + SIZE(MEDIUM) +ENDIF() + +SRCS( + kqp_batch_update_ut.cpp + kqp_batch_delete_ut.cpp +) + +PEERDIR( + ydb/core/kqp + ydb/core/kqp/ut/common + yql/essentials/sql/pg_dummy +) + +YQL_LAST_ABI_VERSION() + +END() diff --git a/ydb/core/kqp/ut/bulk_operations/kqp_batch_ut.cpp b/ydb/core/kqp/ut/bulk_operations/kqp_batch_ut.cpp deleted file mode 100644 index 7b1c6b6c4f6c..000000000000 --- a/ydb/core/kqp/ut/bulk_operations/kqp_batch_ut.cpp +++ /dev/null @@ -1,782 +0,0 @@ -#include - -#include -#include - -#include - -namespace NKikimr { -namespace NKqp { - -using namespace NYdb; -using namespace NYdb::NQuery; - -namespace { - -NKikimrConfig::TAppConfig GetAppConfig() { - auto app = NKikimrConfig::TAppConfig(); - app.MutableTableServiceConfig()->SetEnableOlapSink(true); - app.MutableTableServiceConfig()->SetEnableOltpSink(true); - app.MutableTableServiceConfig()->SetEnableBatchUpdates(true); - return app; -} - -NYdb::NQuery::TExecuteQuerySettings GetQuerySettings() { - NYdb::NQuery::TExecuteQuerySettings execSettings; - execSettings.StatsMode(NYdb::NQuery::EStatsMode::Basic); - return execSettings; -} - -void CreateSimpleTable(TSession& session, const TString& name = "TestTable") { - UNIT_ASSERT(session.ExecuteQuery(TStringBuilder() << R"( - CREATE TABLE `)" << name << R"(` ( - Group Uint32, - Name String, - Age Uint64, - Amount Uint64, - PRIMARY KEY (Group) - );)", NYdb::NQuery::TTxControl::NoTx()).GetValueSync().IsSuccess()); - - auto result = session.ExecuteQuery(TStringBuilder() << R"( - UPSERT INTO `/Root/)" << name << R"(` (Group, Name, Age, Amount) VALUES - (1u, "Anna", 23ul, 3500ul), - (2u, "Paul", 36ul, 300ul), - (3u, "Tony", 81ul, 7200ul), - (4u, "John", 11ul, 10ul), - (5u, "Lena", 3ul, 0ul); - )", NYdb::NQuery::TTxControl::BeginTx().CommitTx()).GetValueSync(); - UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); -} - -void CreateTwoPartitionsTable(TSession& session, const TString& name = "TestTable") { - UNIT_ASSERT(session.ExecuteQuery(TStringBuilder() << R"( - CREATE TABLE `)" << name << R"(` ( - Group Uint32, - Name String, - Age Uint64, - Amount Uint64, - PRIMARY KEY (Group) - ) WITH ( - AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 2, - PARTITION_AT_KEYS = (4u) - );)", NYdb::NQuery::TTxControl::NoTx()).GetValueSync().IsSuccess()); - - auto result = session.ExecuteQuery(TStringBuilder() << R"( - UPSERT INTO `/Root/)" << name << R"(` (Group, Name, Age, Amount) VALUES - (1u, "Anna", 23ul, 3500ul), - (2u, "Paul", 36ul, 300ul), - (3u, "Tony", 81ul, 7200ul), - (4u, "John", 11ul, 10ul), - (5u, "Lena", 3ul, 0ul), - (6u, "Mary", 48ul, 730ul); - )", NYdb::NQuery::TTxControl::BeginTx().CommitTx()).GetValueSync(); - UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); -} - -void CreateTuplePrimaryTable(TSession& session, const TString& name = "TestTable") { - UNIT_ASSERT(session.ExecuteQuery(TStringBuilder() << R"( - CREATE TABLE `)" << name << R"(` ( - Group Uint32, - Name String, - Age Uint64, - Amount Uint64, - PRIMARY KEY (Group, Name) - );)", NYdb::NQuery::TTxControl::NoTx()).GetValueSync().IsSuccess()); - - auto result = session.ExecuteQuery(TStringBuilder() << R"( - UPSERT INTO `/Root/)" << name << R"(` (Group, Name, Age, Amount) VALUES - (1u, "Anna", 23ul, 3500ul), - (2u, "Paul", 36ul, 300ul), - (3u, "Tony", 81ul, 7200ul), - (4u, "John", 11ul, 10ul), - (5u, "Lena", 3ul, 0ul); - )", NYdb::NQuery::TTxControl::BeginTx().CommitTx()).GetValueSync(); - UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); -} - -} // namespace - -Y_UNIT_TEST_SUITE(KqpBatch) { - Y_UNIT_TEST(UpdateSimple) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 1000 WHERE Age <= 30; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[1000u];[1u];["Anna"]]; - [[36u];[300u];[2u];["Paul"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[1000u];[4u];["John"]]; - [[3u];[1000u];[5u];["Lena"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - Y_UNIT_TEST(UpdateMultiFilter) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 1000 WHERE Age < 15 OR Group < 3 AND Name != "Anna"; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[3500u];[1u];["Anna"]]; - [[36u];[1000u];[2u];["Paul"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[1000u];[4u];["John"]]; - [[3u];[1000u];[5u];["Lena"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - Y_UNIT_TEST(UpdateMultiSet) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 0, Name = "None" WHERE Age <= 25; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[0u];[1u];["None"]]; - [[36u];[300u];[2u];["Paul"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[0u];[4u];["None"]]; - [[3u];[0u];[5u];["None"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - Y_UNIT_TEST(UpdateMultiBoth) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 0, Name = "None" WHERE Age > 15 AND Amount < 3500; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[3500u];[1u];["Anna"]]; - [[36u];[0u];[2u];["None"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[10u];[4u];["John"]]; - [[3u];[0u];[5u];["Lena"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - Y_UNIT_TEST(UpdateTwoPartitionsSimple) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateTwoPartitionsTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 100 WHERE Age <= 30; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[100u];[1u];["Anna"]]; - [[36u];[300u];[2u];["Paul"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[100u];[4u];["John"]]; - [[3u];[100u];[5u];["Lena"]]; - [[48u];[730u];[6u];["Mary"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - Y_UNIT_TEST(UpdateTwoPartitionsMulti) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateTwoPartitionsTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 0, Name = "None" WHERE Age > 15 AND Amount < 3500; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[3500u];[1u];["Anna"]]; - [[36u];[0u];[2u];["None"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[10u];[4u];["John"]]; - [[3u];[0u];[5u];["Lena"]]; - [[48u];[0u];[6u];["None"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - // todo partitioning==2 and abort by locks - Y_UNIT_TEST(UpdateTwoPartitionsByPrimaryRange) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateTwoPartitionsTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 25 WHERE Group <= 3; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[25u];[1u];["Anna"]]; - [[36u];[25u];[2u];["Paul"]]; - [[81u];[25u];[3u];["Tony"]]; - [[11u];[10u];[4u];["John"]]; - [[3u];[0u];[5u];["Lena"]]; - [[48u];[730u];[6u];["Mary"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - // todo partitioning==2, shards==1 and abort by locks - Y_UNIT_TEST(UpdateTwoPartitionsByPrimaryPoint) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateTwoPartitionsTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 0 WHERE Group = 1u; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[0u];[1u];["Anna"]]; - [[36u];[300u];[2u];["Paul"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[10u];[4u];["John"]]; - [[3u];[0u];[5u];["Lena"]]; - [[48u];[730u];[6u];["Mary"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - Y_UNIT_TEST(UpdateTuplePrimarySimple) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateTuplePrimaryTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 1000 WHERE Age <= 30; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[1000u];[1u];["Anna"]]; - [[36u];[300u];[2u];["Paul"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[1000u];[4u];["John"]]; - [[3u];[1000u];[5u];["Lena"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - Y_UNIT_TEST(UpdateTuplePrimaryMulti) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateTuplePrimaryTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 0, Age = 0 WHERE Age > 15 AND Amount < 3500; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[3500u];[1u];["Anna"]]; - [[0u];[0u];[2u];["Paul"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[10u];[4u];["John"]]; - [[3u];[0u];[5u];["Lena"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - // todo partitioning==2 and abort by locks - Y_UNIT_TEST(UpdateTuplePrimaryByPrimaryRange) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateTuplePrimaryTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 25 WHERE Group <= 3 AND Name <= "Tony"; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[25u];[1u];["Anna"]]; - [[36u];[25u];[2u];["Paul"]]; - [[81u];[25u];[3u];["Tony"]]; - [[11u];[10u];[4u];["John"]]; - [[3u];[0u];[5u];["Lena"]] - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - // todo partitioning==2, shards==1 and abort by locks - Y_UNIT_TEST(UpdateTuplePrimaryByPrimaryPoint) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateTuplePrimaryTable(session); - - { - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 0 WHERE Group = 1u AND Name = "Anna"; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - { - auto query = Q_(R"( - SELECT * FROM TestTable ORDER BY Group; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - - CompareYson(R"([ - [[23u];[0u];[1u];["Anna"]]; - [[36u];[300u];[2u];["Paul"]]; - [[81u];[7200u];[3u];["Tony"]]; - [[11u];[10u];[4u];["John"]]; - [[3u];[0u];[5u];["Lena"]]; - ])", FormatResultSetYson(result.GetResultSet(0))); - } - } - - Y_UNIT_TEST(UpdateNotIdempotent_1) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - auto query = Q_(R"( - BATCH UPDATE TestTable SET Age = Age * 10 WHERE Group = 1; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(UpdateNotIdempotent_2) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - auto query = Q_(R"( - BATCH UPDATE TestTable SET Age = Group * Age WHERE Group = 1; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(UpdateNotIdempotent_3) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - auto query = Q_(R"( - BATCH UPDATE TestTable SET Age = Amount, Amount = Age WHERE Group = 1; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(UpdateMultiTable_1) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 1000 WHERE Age IN (SELECT Age FROM TestTable WHERE Group = 1); - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(UpdateMultiTable_2) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session, "TestFirst"); - CreateSimpleTable(session, "TestSecond"); - - auto query = Q_(R"( - BATCH UPDATE TestFirst SET Amount = 1000 WHERE Age IN (SELECT Age FROM TestSecond WHERE Group = 1); - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(UpdateMultiTable_3) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session, "TestFirst"); - CreateSimpleTable(session, "TestSecond"); - - auto query = Q_(R"( - BATCH UPDATE TestFirst SET Amount = 1000 WHERE Age = 10; - BATCH UPDATE TestSecond SET Amount = 1000 WHERE Age = 10; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(UpdateMultiStatement_1) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 1000 WHERE Age = 10; - SELECT 42; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(UpdateMultiStatement_2) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session, "TestTable"); - - auto query = Q_(R"( - BATCH UPDATE TestTable SET Amount = 1000 WHERE Age = 10; - UPSERT INTO `/Root/TestTable` (Group, Name, Age, Amount, Comment) - VALUES (7u, "Mark", 74ul, 200ul, "None"); - SELECT * FROM TestTable; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(DeleteBatch) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - auto query = Q_(R"( - BATCH DELETE FROM TestTable WHERE Age >= 10ul; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); - } - - Y_UNIT_TEST(DeleteMultiTable_1) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - auto query = Q_(R"( - BATCH DELETE FROM TestTable WHERE Age IN (SELECT Age FROM TestTable WHERE Group = 2); - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(DeleteMultiTable_2) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session, "TestFirst"); - CreateSimpleTable(session, "TestSecond"); - - auto query = Q_(R"( - BATCH DELETE FROM TestFirst WHERE Age IN (SELECT Age FROM TestSecond WHERE Group = 2); - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(DeleteMultiTable_3) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session, "TestFirst"); - CreateSimpleTable(session, "TestSecond"); - - auto query = Q_(R"( - BATCH DELETE FROM TestFirst WHERE Age = 10; - BATCH DELETE FROM TestSecond WHERE Age = 10; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(DeleteMultiStatement_1) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - auto query = Q_(R"( - BATCH DELETE FROM TestTable WHERE Group = 2; - SELECT 42; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } - - Y_UNIT_TEST(DeleteMultiStatement_2) { - TKikimrRunner kikimr(GetAppConfig()); - auto db = kikimr.GetQueryClient(); - auto session = db.GetSession().GetValueSync().GetSession(); - - CreateSimpleTable(session); - - auto query = Q_(R"( - BATCH DELETE FROM TestTable WHERE Group = 2; - UPSERT INTO `/Root/TestTable` (Group, Name, Age, Amount, Comment) - VALUES (7u, "Mark", 74ul, 200ul, "None"); - SELECT * FROM TestTable; - )"); - - auto txControl = NYdb::NQuery::TTxControl::NoTx(); - - auto result = session.ExecuteQuery(query, txControl, GetQuerySettings()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); - } -} - -} // namespace NKqp -} // namespace NKikimr diff --git a/ydb/core/kqp/ut/bulk_operations/ya.make b/ydb/core/kqp/ut/bulk_operations/ya.make deleted file mode 100644 index fd2c5ff22a4c..000000000000 --- a/ydb/core/kqp/ut/bulk_operations/ya.make +++ /dev/null @@ -1,25 +0,0 @@ -UNITTEST_FOR(ydb/core/kqp) - -FORK_SUBTESTS() -SPLIT_FACTOR(50) - -IF (WITH_VALGRIND) - SIZE(LARGE) - TAG(ya:fat) -ELSE() - SIZE(MEDIUM) -ENDIF() - -SRCS( - kqp_batch_ut.cpp -) - -PEERDIR( - ydb/core/kqp - ydb/core/kqp/ut/common - yql/essentials/sql/pg_dummy -) - -YQL_LAST_ABI_VERSION() - -END() diff --git a/ydb/core/kqp/ut/common/kqp_ut_common.cpp b/ydb/core/kqp/ut/common/kqp_ut_common.cpp index a2b73a13bf29..f2b2db17e69b 100644 --- a/ydb/core/kqp/ut/common/kqp_ut_common.cpp +++ b/ydb/core/kqp/ut/common/kqp_ut_common.cpp @@ -343,6 +343,18 @@ void TKikimrRunner::CreateSampleTables() { WITH ( PARTITION_AT_KEYS = (105) ); + + CREATE TABLE `TuplePrimaryDescending` ( + Col1 Uint32, + Col2 Uint64, + Col3 Int64, + Col4 Int64, + PRIMARY KEY (Col2, Col1, Col3) + ) + WITH ( + AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 2, + PARTITION_AT_KEYS = (2, 3) + ); )").GetValueSync()); AssertSuccessResult(session.ExecuteDataQuery(R"( @@ -453,6 +465,24 @@ void TKikimrRunner::CreateSampleTables() { (105, "Two", "Name4", "Value28"), (106, "One", "Name3", "Value29"), (108, "One", NULL, "Value31"); + + REPLACE INTO `TuplePrimaryDescending` (Col1, Col2, Col3, Col4) VALUES + (0, 1, 0, 3), + (1, 1, 0, 1), + (1, 1, 1, 0), + (1, 1, 2, 1), + (2, 1, 0, 2), + (1, 2, 0, 1), + (1, 2, 1, 0), + (2, 2, 0, 1), + (3, 2, 1, 5), + (0, 3, 0, 1), + (1, 3, 3, 0), + (2, 3, 0, 1), + (0, 3, 2, 4), + (1, 3, 1, 1), + (2, 3, 1, 2), + (3, 3, 0, 1); )", TTxControl::BeginTx(TTxSettings::SerializableRW()).CommitTx()).GetValueSync()); } @@ -529,6 +559,8 @@ void TKikimrRunner::Initialize(const TKikimrSettings& settings) { SetupLogLevelFromTestParam(NKikimrServices::TX_COLUMNSHARD); SetupLogLevelFromTestParam(NKikimrServices::TX_COLUMNSHARD_SCAN); SetupLogLevelFromTestParam(NKikimrServices::LOCAL_PGWIRE); + SetupLogLevelFromTestParam(NKikimrServices::SSA_GRAPH_EXECUTION); + RunCall([this, domain = settings.DomainRoot]{ this->Client->InitRootScheme(domain); @@ -688,6 +720,14 @@ TDataQueryResult ExecQueryAndTestResult(TSession& session, const TString& query, return result; } +NYdb::NQuery::TExecuteQueryResult ExecQueryAndTestEmpty(NYdb::NQuery::TSession& session, const TString& query) { + auto result = session.ExecuteQuery(query, NYdb::NQuery::TTxControl::NoTx()) + .ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), NYdb::EStatus::SUCCESS); + CompareYson("[[0u]]", FormatResultSetYson(result.GetResultSet(0))); + return result; +} + void FillProfile(NYdb::NQuery::TExecuteQueryPart& streamPart, NYson::TYsonWriter& writer, TVector* profiles, ui32 profileIndex) { @@ -1518,7 +1558,7 @@ NJson::TJsonValue SimplifyPlan(NJson::TJsonValue& opt, const TGetPlanParams& par opName.find("Join") != TString::npos || opName.find("Union") != TString::npos || (opName.find("Filter") != TString::npos && params.IncludeFilters) || - (opName.find("HashShuffle") != TString::npos && params.IncludeShuffles) + (opName.find("HashShuffle") != TString::npos && params.IncludeShuffles) ) { NJson::TJsonValue newChildren; diff --git a/ydb/core/kqp/ut/common/kqp_ut_common.h b/ydb/core/kqp/ut/common/kqp_ut_common.h index 8ca4b064a493..d74d1877830d 100644 --- a/ydb/core/kqp/ut/common/kqp_ut_common.h +++ b/ydb/core/kqp/ut/common/kqp_ut_common.h @@ -124,6 +124,7 @@ struct TKikimrSettings: public TTestFeatureFlagsHolder { TKikimrSettings& SetEnableForceFollowers(bool value) { EnableForceFollowers = value; return *this; }; TKikimrSettings& SetS3ActorsFactory(std::shared_ptr value) { S3ActorsFactory = std::move(value); return *this; }; TKikimrSettings& SetControls(const NKikimrConfig::TImmediateControlsConfig& value) { Controls = value; return *this; } + TKikimrSettings& SetColumnShardReaderClassName(const TString& value) { AppConfig.MutableColumnShardConfig()->SetReaderClassName(value); return *this; } TKikimrSettings& SetColumnShardAlterObjectEnabled(bool enable) { AppConfig.MutableColumnShardConfig()->SetAlterObjectEnabled(enable); return *this; @@ -346,6 +347,8 @@ inline NYdb::NTable::TDataQueryResult ExecQueryAndTestResult(NYdb::NTable::TSess return ExecQueryAndTestResult(session, query, NYdb::TParamsBuilder().Build(), expectedYson); } +NYdb::NQuery::TExecuteQueryResult ExecQueryAndTestEmpty(NYdb::NQuery::TSession& session, const TString& query); + class TStreamReadError : public yexception { public: TStreamReadError(NYdb::EStatus status) diff --git a/ydb/core/kqp/ut/federated_query/common/common.cpp b/ydb/core/kqp/ut/federated_query/common/common.cpp index d6d04f455a81..40a838ec1c84 100644 --- a/ydb/core/kqp/ut/federated_query/common/common.cpp +++ b/ydb/core/kqp/ut/federated_query/common/common.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace NKikimr::NKqp::NFederatedQueryTest { TString GetSymbolsString(char start, char end, const TString& skip) { @@ -54,7 +55,7 @@ namespace NKikimr::NKqp::NFederatedQueryTest { NYql::IDatabaseAsyncResolver::TPtr databaseAsyncResolver, std::optional appConfig, std::shared_ptr s3ActorsFactory, - const TKikimrRunnerOptions& optionst) + const TKikimrRunnerOptions& options) { NKikimrConfig::TFeatureFlags featureFlags; featureFlags.SetEnableExternalDataSources(true); @@ -79,7 +80,7 @@ namespace NKikimr::NKqp::NFederatedQueryTest { auto federatedQuerySetupFactory = std::make_shared( httpGateway, connectorClient, - nullptr, + options.CredentialsFactory, databaseAsyncResolver, appConfig->GetQueryServiceConfig().GetS3(), appConfig->GetQueryServiceConfig().GetGeneric(), @@ -97,8 +98,8 @@ namespace NKikimr::NKqp::NFederatedQueryTest { .SetKqpSettings({}) .SetS3ActorsFactory(std::move(s3ActorsFactory)) .SetWithSampleTables(false) - .SetDomainRoot(optionst.DomainRoot) - .SetNodeCount(optionst.NodeCount); + .SetDomainRoot(options.DomainRoot) + .SetNodeCount(options.NodeCount); settings = settings.SetAppConfig(appConfig.value()); diff --git a/ydb/core/kqp/ut/federated_query/common/common.h b/ydb/core/kqp/ut/federated_query/common/common.h index 48c17ed7fa11..8c0fd4c4911e 100644 --- a/ydb/core/kqp/ut/federated_query/common/common.h +++ b/ydb/core/kqp/ut/federated_query/common/common.h @@ -20,6 +20,7 @@ namespace NKikimr::NKqp::NFederatedQueryTest { struct TKikimrRunnerOptions { TString DomainRoot = "Root"; ui32 NodeCount = 1; + NYql::ISecuredServiceAccountCredentialsFactory::TPtr CredentialsFactory; }; std::shared_ptr MakeKikimrRunner( @@ -29,4 +30,5 @@ namespace NKikimr::NKqp::NFederatedQueryTest { std::optional appConfig = std::nullopt, std::shared_ptr s3ActorsFactory = nullptr, const TKikimrRunnerOptions& options = {}); + } // namespace NKikimr::NKqp::NFederatedQueryTest diff --git a/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.cpp b/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.cpp new file mode 100644 index 000000000000..7c4f0e65b31a --- /dev/null +++ b/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.cpp @@ -0,0 +1,247 @@ +#include "iceberg_ut_data.h" + +#include +#include + +namespace NTestUtils { + +constexpr char VALUE_HIVE_URI[] = "hive_uri"; +constexpr char VALUE_S3_URI[] = "s3_uri"; +constexpr char VALUE_S3_ENDPOINT[] = "s3_endpoint"; +constexpr char VALUE_S3_REGION[] = "s3_region"; + +constexpr char VALUE_IAM[] = "IAM"; + +struct TTestData { + TTestData(TIcebergTestData* data) + : Credentials_(*Result_.mutable_credentials()) + , Options_(*Result_.mutable_iceberg_options()) + , Warehouse_(*Options_.mutable_warehouse()) + , Catalog_(*Options_.mutable_catalog()) + { + assert(data); + + switch (data->Auth_.Type) { + case TIcebergTestData::AuthBasic: { + auto& auth = *Credentials_.mutable_basic(); + auth.set_username(data->Auth_.Id); + auth.set_password(data->Auth_.Value); + break; + } + case TIcebergTestData::AuthSa: + case TIcebergTestData::AuthToken: { + auto& auth = *Credentials_.mutable_token(); + auth.set_type(data->Auth_.Id); + auth.set_value(data->Auth_.Value); + break; + } + } + + Result_.mutable_endpoint(); + Result_.set_kind(::NYql::EGenericDataSourceKind::ICEBERG); + Result_.set_database(data->Database_); + Result_.set_use_tls(data->UseTls_); + Result_.set_protocol(::NYql::EGenericProtocol::NATIVE); + + auto& s3 = *Warehouse_.mutable_s3(); + + s3.set_uri(VALUE_S3_URI); + s3.set_endpoint(VALUE_S3_ENDPOINT); + s3.set_region(VALUE_S3_REGION); + } + + NYql::TGenericDataSourceInstance Result_; + NYql::TGenericCredentials& Credentials_; + NYql::TIcebergDataSourceOptions& Options_; + NYql::TIcebergWarehouse& Warehouse_; + NYql::TIcebergCatalog& Catalog_; +}; + +TIcebergTestData::TIcebergTestData( + TAuth auth, + const TString& dataSourceName, + const TString& database, + bool useTls) + : Auth_(auth) + , DataSourceName_(dataSourceName) + , Database_(database) + , UseTls_(useTls) +{} + +NYql::TGenericDataSourceInstance TIcebergTestData::CreateDataSourceForHadoop() { + TTestData data(this); + data.Catalog_.mutable_hadoop(); + return data.Result_; +} + +NYql::TGenericDataSourceInstance TIcebergTestData::CreateDataSourceForHive() { + TTestData data(this); + auto& hive = *data.Catalog_.mutable_hive(); + hive.set_uri(VALUE_HIVE_URI); + return data.Result_; +} + +TString TIcebergTestData::CreateAuthSection() { + using namespace fmt::literals; + + switch (Auth_.Type) { + case TIcebergTestData::AuthBasic: + return fmt::format(R"( + AUTH_METHOD="BASIC", + LOGIN="{login}", + PASSWORD_SECRET_NAME="{data_source_name}_p" + )", + "data_source_name"_a = DataSourceName_, + "login"_a = Auth_.Id, + "password"_a = Auth_.Value + ); + case TIcebergTestData::AuthToken: + return fmt::format(R"( + AUTH_METHOD="TOKEN", + TOKEN_SECRET_NAME="{data_source_name}_p" + )", + "data_source_name"_a = DataSourceName_ + ); + case TIcebergTestData::AuthSa: + return fmt::format(R"( + AUTH_METHOD="SERVICE_ACCOUNT", + SERVICE_ACCOUNT_ID="my_sa", + SERVICE_ACCOUNT_SECRET_NAME="{data_source_name}_p" + )", + "data_source_name"_a = DataSourceName_ + ); + }; +} + +TString TIcebergTestData::CreateQuery(const TString& catalogSection) { + using namespace fmt::literals; + + return fmt::format( + R"( + CREATE OBJECT {data_source_name}_p (TYPE SECRET) WITH (value={secret}); + + CREATE EXTERNAL DATA SOURCE {data_source_name} WITH ( + SOURCE_TYPE="{source_type}", + DATABASE_NAME="{database}", + WAREHOUSE_TYPE="{s3}", + WAREHOUSE_S3_REGION="{s3_region}", + WAREHOUSE_S3_ENDPOINT="{s3_endpoint}", + WAREHOUSE_S3_URI="{s3_uri}", + {auth_section}, + {catalog_section}, + USE_TLS="{use_tls}" + ); + )", + "auth_section"_a = CreateAuthSection(), + "s3"_a = NKikimr::NExternalSource::NIceberg::VALUE_S3, + "s3_region"_a = VALUE_S3_REGION, + "s3_endpoint"_a = VALUE_S3_ENDPOINT, + "s3_uri"_a = VALUE_S3_URI, + "data_source_name"_a = DataSourceName_, + "catalog_section"_a = catalogSection, + "secret"_a = Auth_.Value, + "use_tls"_a = UseTls_ ? "TRUE" : "FALSE", + "source_type"_a = ToString(NYql::EDatabaseType::Iceberg), + "database"_a = Database_ + ); +} + +void TIcebergTestData::ExecuteQuery(const std::shared_ptr& kikimr, + const TString& query) +{ + auto c = kikimr->GetTableClient(); + auto session = c.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteSchemeQuery(query).GetValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); +} + + +void TIcebergTestData::ExecuteCreateHiveExternalDataSource(const std::shared_ptr& kikimr) { + using namespace fmt::literals; + + TString hiveCatalog = fmt::format(R"( + CATALOG_TYPE="{type}", + CATALOG_HIVE_URI="{uri}" + )", + "type"_a = NKikimr::NExternalSource::NIceberg::VALUE_HIVE, + "uri"_a = VALUE_HIVE_URI + ); + + ExecuteQuery(kikimr, CreateQuery(hiveCatalog)); +} + +void TIcebergTestData::ExecuteCreateHadoopExternalDataSource(const std::shared_ptr& kikimr) { + using namespace fmt::literals; + + TString hadoopCatalog = fmt::format(R"( + CATALOG_TYPE="{type}" + )", + "type"_a = NKikimr::NExternalSource::NIceberg::VALUE_HADOOP + ); + + ExecuteQuery(kikimr, CreateQuery(hadoopCatalog)); +} + +class TStaticCredentialsProvider : public NYdb::ICredentialsProvider { +public: + TStaticCredentialsProvider(const TString& yqlToken) + : YqlToken_(yqlToken) + {} + + std::string GetAuthInfo() const override { + return YqlToken_; + } + + bool IsValid() const override { + return true; + } + +private: + std::string YqlToken_; +}; + +class TStaticCredentialsProviderFactory : public NYdb::ICredentialsProviderFactory { +public: + TStaticCredentialsProviderFactory(const TString& yqlToken) + : YqlToken_(yqlToken) + {} + + std::shared_ptr CreateProvider() const override { + return std::make_shared(YqlToken_); + } + +private: + TString YqlToken_; +}; + +class TStaticSecuredCredentialsFactory : public NYql::ISecuredServiceAccountCredentialsFactory { +public: + TStaticSecuredCredentialsFactory(const TString& yqlToken) + : YqlToken_(yqlToken) + {} + + std::shared_ptr Create(const TString&, const TString&) override { + return std::make_shared(YqlToken_); + } + +private: + TString YqlToken_; +}; + +TIcebergTestData CreateIcebergBasic(const TString& dataSourceName, const TString& database, const TString& userName, const TString& password){ + return TIcebergTestData({TIcebergTestData::EAuthType::AuthBasic, userName, password}, dataSourceName, database, false); +} + +TIcebergTestData CreateIcebergToken(const TString& dataSourceName, const TString& database, const TString& token) { + return TIcebergTestData({TIcebergTestData::EAuthType::AuthToken, VALUE_IAM , token}, dataSourceName, database, false); +} + +TIcebergTestData CreateIcebergSa(const TString& dataSourceName, const TString& database, const TString& token) { + return TIcebergTestData({TIcebergTestData::EAuthType::AuthSa,VALUE_IAM, token}, dataSourceName, database, false); +} + +std::shared_ptr CreateCredentialProvider(const TString& token) { + return std::make_shared(token); +} + +} // NTestUtils diff --git a/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.h b/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.h new file mode 100644 index 000000000000..bc03d731f3e7 --- /dev/null +++ b/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include +#include + +namespace NTestUtils { + +struct TTestData; +class TIcebergTestData final { + friend struct TTestData; + +public: + enum EAuthType : int { + AuthBasic = 1, + AuthSa = 2, + AuthToken = 3 + }; + + struct TAuth { + EAuthType Type; + TString Id; + TString Value; + }; + +public: + TIcebergTestData(TAuth auth, const TString& dataSourceName, const TString& database, bool UseTls); + + NYql::TGenericDataSourceInstance CreateDataSourceForHadoop(); + + NYql::TGenericDataSourceInstance CreateDataSourceForHive(); + + void ExecuteCreateHiveExternalDataSource(const std::shared_ptr& kikimr); + + void ExecuteCreateHadoopExternalDataSource(const std::shared_ptr& kikimr); + +private: + TString CreateAuthSection(); + + TString CreateQuery(const TString& catalogSection); + + void ExecuteQuery(const std::shared_ptr& kikimr, const TString& query); + +private: + const TAuth Auth_; + const TString DataSourceName_; + const TString Database_; + const bool UseTls_; +}; + +TIcebergTestData CreateIcebergBasic(const TString& dataSourceName = NYql::NConnector::NTest::DEFAULT_DATA_SOURCE_NAME, + const TString& database = NYql::NConnector::NTest::DEFAULT_DATABASE, + const TString& userName = NYql::NConnector::NTest::DEFAULT_LOGIN, + const TString& password = NYql::NConnector::NTest::DEFAULT_PASSWORD); + +TIcebergTestData CreateIcebergToken(const TString& dataSourceName = NYql::NConnector::NTest::DEFAULT_DATA_SOURCE_NAME, + const TString& database = NYql::NConnector::NTest::DEFAULT_DATABASE, + const TString& token = NYql::NConnector::NTest::DEFAULT_PASSWORD); + +TIcebergTestData CreateIcebergSa(const TString& dataSourceName = NYql::NConnector::NTest::DEFAULT_DATA_SOURCE_NAME, + const TString& database = NYql::NConnector::NTest::DEFAULT_DATABASE, + const TString& token = NYql::NConnector::NTest::DEFAULT_PASSWORD); + +std::shared_ptr CreateCredentialProvider(const TString& token = NYql::NConnector::NTest::DEFAULT_PASSWORD); + +} // NTestUtils diff --git a/ydb/core/kqp/ut/federated_query/generic_ut/kqp_generic_provider_ut.cpp b/ydb/core/kqp/ut/federated_query/generic_ut/kqp_generic_provider_ut.cpp index 4724d18c1217..521f21db1d85 100644 --- a/ydb/core/kqp/ut/federated_query/generic_ut/kqp_generic_provider_ut.cpp +++ b/ydb/core/kqp/ut/federated_query/generic_ut/kqp_generic_provider_ut.cpp @@ -1,3 +1,5 @@ +#include "iceberg_ut_data.h" + #include #include #include @@ -36,6 +38,12 @@ namespace NKikimr::NKqp { PostgreSQL, ClickHouse, Ydb, + IcebergHiveBasic, + IcebergHiveSa, + IcebergHiveToken, + IcebergHadoopBasic, + IcebergHadoopSa, + IcebergHadoopToken, }; NYql::TGenericDataSourceInstance MakeDataSourceInstance(EProviderType providerType) { @@ -46,6 +54,18 @@ namespace NKikimr::NKqp { return TConnectorClientMock::TClickHouseDataSourceInstanceBuilder<>().GetResult(); case EProviderType::Ydb: return TConnectorClientMock::TYdbDataSourceInstanceBuilder<>().GetResult(); + case EProviderType::IcebergHiveBasic: + return NTestUtils::CreateIcebergBasic().CreateDataSourceForHive(); + case EProviderType::IcebergHiveSa: + return NTestUtils::CreateIcebergSa().CreateDataSourceForHive(); + case EProviderType::IcebergHiveToken: + return NTestUtils::CreateIcebergToken().CreateDataSourceForHive(); + case EProviderType::IcebergHadoopBasic: + return NTestUtils::CreateIcebergBasic().CreateDataSourceForHadoop(); + case EProviderType::IcebergHadoopSa: + return NTestUtils::CreateIcebergSa().CreateDataSourceForHadoop(); + case EProviderType::IcebergHadoopToken: + return NTestUtils::CreateIcebergToken().CreateDataSourceForHadoop(); } } @@ -57,6 +77,24 @@ namespace NKikimr::NKqp { return CreateClickHouseExternalDataSource(kikimr); case EProviderType::Ydb: return CreateYdbExternalDataSource(kikimr); + case EProviderType::IcebergHiveBasic: + return NTestUtils::CreateIcebergBasic() + .ExecuteCreateHiveExternalDataSource(kikimr); + case EProviderType::IcebergHiveSa: + return NTestUtils::CreateIcebergSa() + .ExecuteCreateHiveExternalDataSource(kikimr); + case EProviderType::IcebergHiveToken: + return NTestUtils::CreateIcebergToken() + .ExecuteCreateHiveExternalDataSource(kikimr); + case EProviderType::IcebergHadoopBasic: + return NTestUtils::CreateIcebergBasic() + .ExecuteCreateHadoopExternalDataSource(kikimr); + case EProviderType::IcebergHadoopSa: + return NTestUtils::CreateIcebergSa() + .ExecuteCreateHadoopExternalDataSource(kikimr); + case EProviderType::IcebergHadoopToken: + return NTestUtils::CreateIcebergToken() + .ExecuteCreateHadoopExternalDataSource(kikimr); } } @@ -65,15 +103,21 @@ namespace NKikimr::NKqp { NYql::TAttr dateTimeFormat; dateTimeFormat.SetName("DateTimeFormat"); dateTimeFormat.SetValue("string"); - appConfig.MutableQueryServiceConfig()->MutableGeneric()->MutableConnector()->SetUseSsl(false); - appConfig.MutableQueryServiceConfig()->MutableGeneric()->MutableConnector()->MutableEndpoint()->set_host("localhost"); - appConfig.MutableQueryServiceConfig()->MutableGeneric()->MutableConnector()->MutableEndpoint()->set_port(1234); - appConfig.MutableQueryServiceConfig()->MutableGeneric()->MutableDefaultSettings()->Add(std::move(dateTimeFormat)); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("ObjectStorage"); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("ClickHouse"); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("PostgreSQL"); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("MySQL"); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("Ydb"); + + auto& config = *appConfig.MutableQueryServiceConfig(); + auto& connector = *config.MutableGeneric()->MutableConnector(); + + connector.SetUseSsl(false); + connector.MutableEndpoint()->set_host("localhost"); + connector.MutableEndpoint()->set_port(1234); + + config.MutableGeneric()->MutableDefaultSettings()->Add(std::move(dateTimeFormat)); + config.AddAvailableExternalDataSources("ObjectStorage"); + config.AddAvailableExternalDataSources("ClickHouse"); + config.AddAvailableExternalDataSources("PostgreSQL"); + config.AddAvailableExternalDataSources("MySQL"); + config.AddAvailableExternalDataSources("Ydb"); + config.AddAvailableExternalDataSources("Iceberg"); return appConfig; } @@ -105,7 +149,6 @@ namespace NKikimr::NKqp { auto clientMock = std::make_shared(); const NYql::TGenericDataSourceInstance dataSourceInstance = MakeDataSourceInstance(providerType); - // step 1: DescribeTable // clang-format off clientMock->ExpectDescribeTable() @@ -152,7 +195,8 @@ namespace NKikimr::NKqp { // run test auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory, + {.CredentialsFactory = NTestUtils::CreateCredentialProvider()}); CreateExternalDataSource(providerType, kikimr); @@ -193,6 +237,30 @@ namespace NKikimr::NKqp { TestSelectAllFields(EProviderType::Ydb); } + Y_UNIT_TEST(IcebergHiveBasicSelectAll) { + TestSelectAllFields(EProviderType::IcebergHiveBasic); + } + + Y_UNIT_TEST(IcebergHiveSaSelectAll) { + TestSelectAllFields(EProviderType::IcebergHiveSa); + } + + Y_UNIT_TEST(IcebergHiveTokenSelectAll) { + TestSelectAllFields(EProviderType::IcebergHiveToken); + } + + Y_UNIT_TEST(IcebergHadoopBasicSelectAll) { + TestSelectAllFields(EProviderType::IcebergHadoopBasic); + } + + Y_UNIT_TEST(IcebergHadoopSaSelectAll) { + TestSelectAllFields(EProviderType::IcebergHadoopSa); + } + + Y_UNIT_TEST(IcebergHadoopTokenSelectAll) { + TestSelectAllFields(EProviderType::IcebergHadoopToken); + } + void TestSelectConstant(EProviderType providerType) { // prepare mock auto clientMock = std::make_shared(); @@ -243,7 +311,8 @@ namespace NKikimr::NKqp { // run test auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory, + {.CredentialsFactory = NTestUtils::CreateCredentialProvider()}); CreateExternalDataSource(providerType, kikimr); @@ -283,6 +352,30 @@ namespace NKikimr::NKqp { TestSelectConstant(EProviderType::Ydb); } + Y_UNIT_TEST(IcebergHiveBasicSelectConstant) { + TestSelectConstant(EProviderType::IcebergHiveBasic); + } + + Y_UNIT_TEST(IcebergHiveSaSelectConstant) { + TestSelectConstant(EProviderType::IcebergHiveSa); + } + + Y_UNIT_TEST(IcebergHiveTokenSelectConstant) { + TestSelectConstant(EProviderType::IcebergHiveToken); + } + + Y_UNIT_TEST(IcebergHadoopBasicSelectConstant) { + TestSelectConstant(EProviderType::IcebergHadoopBasic); + } + + Y_UNIT_TEST(IcebergHadoopSaSelectConstant) { + TestSelectConstant(EProviderType::IcebergHadoopSa); + } + + Y_UNIT_TEST(IcebergHadoopTokenSelectConstant) { + TestSelectConstant(EProviderType::IcebergHadoopToken); + } + void TestSelectCount(EProviderType providerType) { // prepare mock auto clientMock = std::make_shared(); @@ -333,7 +426,8 @@ namespace NKikimr::NKqp { // run test auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory, + {.CredentialsFactory = NTestUtils::CreateCredentialProvider()}); CreateExternalDataSource(providerType, kikimr); @@ -369,6 +463,30 @@ namespace NKikimr::NKqp { TestSelectCount(EProviderType::Ydb); } + Y_UNIT_TEST(IcebergHiveBasicSelectCount) { + TestSelectCount(EProviderType::IcebergHiveBasic); + } + + Y_UNIT_TEST(IcebergHiveSaSelectCount) { + TestSelectCount(EProviderType::IcebergHiveSa); + } + + Y_UNIT_TEST(IcebergHiveTokenSelectCount) { + TestSelectCount(EProviderType::IcebergHiveToken); + } + + Y_UNIT_TEST(IcebergHadoopBasicSelectCount) { + TestSelectCount(EProviderType::IcebergHadoopBasic); + } + + Y_UNIT_TEST(IcebergHadoopSaSelectCount) { + TestSelectCount(EProviderType::IcebergHadoopSa); + } + + Y_UNIT_TEST(IcebergHadoopTokenSelectCount) { + TestSelectCount(EProviderType::IcebergHadoopToken); + } + void TestFilterPushdown(EProviderType providerType) { // prepare mock auto clientMock = std::make_shared(); @@ -442,7 +560,8 @@ namespace NKikimr::NKqp { // run test auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory, + {.CredentialsFactory = NTestUtils::CreateCredentialProvider()}); CreateExternalDataSource(providerType, kikimr); @@ -480,12 +599,37 @@ namespace NKikimr::NKqp { TestFilterPushdown(EProviderType::Ydb); } + Y_UNIT_TEST(IcebergHiveBasicFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHiveBasic); + } + + Y_UNIT_TEST(IcebergHiveSaFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHiveSa); + } + + Y_UNIT_TEST(IcebergHiveTokenFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHiveToken); + } + + Y_UNIT_TEST(IcebergHadoopBasicFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHadoopBasic); + } + + Y_UNIT_TEST(IcebergHadoopSaFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHadoopSa); + } + + Y_UNIT_TEST(IcebergHadoopTokenFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHadoopToken); + } + void TestFailsOnIncorrectScriptExecutionOperation(const TString& operationId, const TString& fetchToken) { auto clientMock = std::make_shared(); auto databaseAsyncResolverMock = MakeDatabaseAsyncResolver(EProviderType::Ydb); auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory, + {.CredentialsFactory = NTestUtils::CreateCredentialProvider()}); // Create trash query NYdbGrpc::TGRpcClientLow clientLow; diff --git a/ydb/core/kqp/ut/federated_query/generic_ut/ya.make b/ydb/core/kqp/ut/federated_query/generic_ut/ya.make index 9711b911be05..ffe00f6023c8 100644 --- a/ydb/core/kqp/ut/federated_query/generic_ut/ya.make +++ b/ydb/core/kqp/ut/federated_query/generic_ut/ya.make @@ -4,6 +4,8 @@ FORK_SUBTESTS() SRCS( kqp_generic_provider_ut.cpp + iceberg_ut_data.cpp + iceberg_ut_data.h ) PEERDIR( diff --git a/ydb/core/kqp/ut/federated_query/s3/kqp_federated_query_ut.cpp b/ydb/core/kqp/ut/federated_query/s3/kqp_federated_query_ut.cpp index 85ae65f32fc3..026e9bda4cad 100644 --- a/ydb/core/kqp/ut/federated_query/s3/kqp_federated_query_ut.cpp +++ b/ydb/core/kqp/ut/federated_query/s3/kqp_federated_query_ut.cpp @@ -785,7 +785,10 @@ Y_UNIT_TEST_SUITE(KqpFederatedQuery) { Y_UNIT_TEST(InsertIntoBucketWithSelect) { const TString writeDataSourceName = "/Root/write_data_source"; const TString writeBucket = "test_bucket_write_with_select"; - const TString writeObject = "test_object_write/"; + + // Also tests large object path with size >= 128 + // for atomic upload commit case + const TString writeObject = TStringBuilder() << "test_object_write/" << TString(512, 'x') << "/"; { Aws::S3::S3Client s3Client = MakeS3Client(); @@ -811,6 +814,8 @@ Y_UNIT_TEST_SUITE(KqpFederatedQuery) { UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); const TString sql = fmt::format(R"( + PRAGMA s3.AtomicUploadCommit = "true"; + INSERT INTO `{write_source}`.`{write_object}` WITH (FORMAT = "csv_with_names") SELECT * FROM AS_TABLE([<|id: 0, payload: "#######"|>]); diff --git a/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp b/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp index 0cf0badfe434..a05490508b08 100644 --- a/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp +++ b/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp @@ -3238,6 +3238,77 @@ Y_UNIT_TEST_SUITE(KqpIndexes) { DoPositiveQueriesPrefixedVectorIndexOrderByCosine(session); } + Y_UNIT_TEST(VectorIndexIsNotUpdatable) { + NKikimrConfig::TFeatureFlags featureFlags; + featureFlags.SetEnableVectorIndex(true); + auto setting = NKikimrKqp::TKqpSetting(); + auto serverSettings = TKikimrSettings() + .SetFeatureFlags(featureFlags) + .SetKqpSettings({setting}); + + TKikimrRunner kikimr(serverSettings); + kikimr.GetTestServer().GetRuntime()->SetLogPriority(NKikimrServices::BUILD_INDEX, NActors::NLog::PRI_TRACE); + + auto db = kikimr.GetTableClient(); + auto session = DoCreateTableForVectorIndex(db, true); + + // Add first index + { + const TString createIndex(Q_(R"( + ALTER TABLE `/Root/TestTable` + ADD INDEX index1 + GLOBAL USING vector_kmeans_tree + ON (emb) + WITH (similarity=cosine, vector_type="uint8", vector_dimension=2, levels=2, clusters=2); + )")); + + auto result = session.ExecuteSchemeQuery(createIndex).ExtractValueSync(); + + UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); + } + + const TString originalPostingTable = ReadTablePartToYson(session, "/Root/TestTable/index1/indexImplPostingTable"); + + // Upsert to the table with index should succeed + { + const TString query1(Q_(R"( + UPSERT INTO `/Root/TestTable` (pk, emb, data) VALUES)" + "(10, \"\x76\x76\x03\", \"10\");" + )); + + auto result = session.ExecuteDataQuery( + query1, + TTxControl::BeginTx(TTxSettings::SerializableRW()).CommitTx()) + .ExtractValueSync(); + UNIT_ASSERT(result.IsSuccess()); + } + + const TString postingTable1 = ReadTablePartToYson(session, "/Root/TestTable/index1/indexImplPostingTable"); + + // First index is not updated + UNIT_ASSERT_STRINGS_EQUAL(originalPostingTable, postingTable1); + + // Add second index + { + const TString createIndex(Q_(R"( + ALTER TABLE `/Root/TestTable` + ADD INDEX index2 + GLOBAL USING vector_kmeans_tree + ON (emb) + WITH (similarity=cosine, vector_type="uint8", vector_dimension=2, levels=2, clusters=2); + )")); + + auto result = session.ExecuteSchemeQuery(createIndex).ExtractValueSync(); + + UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); + } + + const TString postingTable2 = ReadTablePartToYson(session, "/Root/TestTable/index2/indexImplPostingTable"); + + // Second index is different + UNIT_ASSERT_STRINGS_UNEQUAL(originalPostingTable, postingTable2); + } + Y_UNIT_TEST(ExplainCollectFullDiagnostics) { auto setting = NKikimrKqp::TKqpSetting(); auto serverSettings = TKikimrSettings() diff --git a/ydb/core/kqp/ut/join/kqp_join_ut.cpp b/ydb/core/kqp/ut/join/kqp_join_ut.cpp index 9fb6a785f297..c1f2963ec030 100644 --- a/ydb/core/kqp/ut/join/kqp_join_ut.cpp +++ b/ydb/core/kqp/ut/join/kqp_join_ut.cpp @@ -1878,6 +1878,48 @@ Y_UNIT_TEST_SUITE(KqpJoin) { )", FormatResultSetYson(result.GetResultSet(0))); } } + + Y_UNIT_TEST(HashJoinWithAsTable) { + TKikimrRunner kikimr; + + auto client = kikimr.GetQueryClient(); + + { + const TString query = R"( + CREATE TABLE test_table ( + test_column Int32, + PRIMARY key (test_column) + ))"; + + const auto result = client.ExecuteQuery(query, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + } + + const TString joinQuery = R"( + PRAGMA ydb.HashJoinMode = "grace"; + PRAGMA ydb.OptShuffleElimination = "true"; + + $as_table = SELECT * FROM AS_TABLE([<|test_column: 42|>]); + + SELECT + as_table.test_column + FROM $as_table AS as_table + LEFT JOIN test_table + ON test_table.test_column = as_table.test_column + )"; + + const auto result = client.ExecuteQuery(joinQuery, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1); + + const auto& resultSet = result.GetResultSet(0); + UNIT_ASSERT_VALUES_EQUAL(resultSet.ColumnsCount(), 1); + UNIT_ASSERT_VALUES_EQUAL(resultSet.RowsCount(), 1); + + TResultSetParser parser(resultSet); + UNIT_ASSERT(parser.TryNextRow()); + UNIT_ASSERT_VALUES_EQUAL(parser.ColumnParser(0).GetInt32(), 42); + } } } // namespace NKqp diff --git a/ydb/core/kqp/ut/olap/json_ut.cpp b/ydb/core/kqp/ut/olap/json_ut.cpp index b4349f04138a..d3fdb06e4e89 100644 --- a/ydb/core/kqp/ut/olap/json_ut.cpp +++ b/ydb/core/kqp/ut/olap/json_ut.cpp @@ -5,14 +5,19 @@ #include "helpers/writer.h" #include +#include #include -#include #include #include +#include #include #include #include +#include +#include + +#include #include #include @@ -243,6 +248,47 @@ Y_UNIT_TEST_SUITE(KqpOlapJson) { } }; + class TBulkUpsertCommand: public ICommand { + private: + TString TableName; + TString ArrowBatch; + Ydb::StatusIds_StatusCode ExpectedCode = Ydb::StatusIds::SUCCESS; + + public: + TBulkUpsertCommand() = default; + + virtual TConclusionStatus DoExecute(TKikimrRunner& kikimr) override { + TLocalHelper lHelper(kikimr); + lHelper.SendDataViaActorSystem(TableName, + NArrow::TStatusValidator::GetValid(NArrow::NSerialization::TNativeSerializer().Deserialize(ArrowBatch)), ExpectedCode); + return TConclusionStatus::Success(); + } + + bool DeserializeFromString(const TString& info) { + auto lines = StringSplitter(info).SplitBySet("\n").SkipEmpty().ToList(); + if (lines.size() < 2 || lines.size() > 3) { + return false; + } + TableName = Strip(lines[0]); + ArrowBatch = Base64Decode(Strip(lines[1])); + AFL_VERIFY(!!ArrowBatch); + if (lines.size() == 3) { + if (!Ydb::StatusIds_StatusCode_Parse(Strip(lines[2]), &ExpectedCode)) { + return false; + } + // if (lines[2] == "SUCCESS") { + // } else if (lines[2] = "INTERNAL_ERROR") { + // ExpectedCode = Ydb::StatusIds::INTERNAL_ERROR; + // } else if (lines[2] == "BAD_REQUEST") { + // ExpectedCode = Ydb::StatusIds::BAD_REQUEST; + // } else { + // return false; + // } + } + return true; + } + }; + class TScriptExecutor { private: std::vector> Commands; @@ -275,7 +321,12 @@ Y_UNIT_TEST_SUITE(KqpOlapJson) { private: std::vector Scripts; std::shared_ptr BuildCommand(TString command) { - if (command.StartsWith("SCHEMA:")) { + if (command.StartsWith("BULK_UPSERT:")) { + command = command.substr(12); + auto result = std::make_shared(); + AFL_VERIFY(result->DeserializeFromString(command)); + return result; + } else if (command.StartsWith("SCHEMA:")) { command = command.substr(7); return std::make_shared(command); } else if (command.StartsWith("DATA:")) { @@ -559,6 +610,39 @@ Y_UNIT_TEST_SUITE(KqpOlapJson) { TScriptVariator(script).Execute(); } + Y_UNIT_TEST(BrokenJsonWriting) { + NColumnShard::TTableUpdatesBuilder updates(NArrow::MakeArrowSchema( + { { "Col1", NScheme::TTypeInfo(NScheme::NTypeIds::Uint64) }, { "Col2", NScheme::TTypeInfo(NScheme::NTypeIds::Utf8) } })); + updates.AddRow().Add(1).Add("{\"a\" : \"c}"); + auto arrowString = Base64Encode(NArrow::NSerialization::TNativeSerializer().SerializeFull(updates.BuildArrow())); + + TString script = Sprintf(R"( + SCHEMA: + CREATE TABLE `/Root/ColumnTable` ( + Col1 Uint64 NOT NULL, + Col2 JsonDocument, + PRIMARY KEY (Col1) + ) + PARTITION BY HASH(Col1) + WITH (STORE = COLUMN, AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = $$1|2|10$$); + ------ + SCHEMA: + ALTER OBJECT `/Root/ColumnTable` (TYPE TABLE) SET (ACTION=UPSERT_OPTIONS, `SCAN_READER_POLICY_NAME`=`SIMPLE`) + ------ + SCHEMA: + ALTER OBJECT `/Root/ColumnTable` (TYPE TABLE) SET (ACTION=ALTER_COLUMN, NAME=Col2, `DATA_EXTRACTOR_CLASS_NAME`=`JSON_SCANNER`, `SCAN_FIRST_LEVEL_ONLY`=`false`, + `DATA_ACCESSOR_CONSTRUCTOR.CLASS_NAME`=`SUB_COLUMNS`, `FORCE_SIMD_PARSING`=`$$true|false$$`, `COLUMNS_LIMIT`=`$$1024|0|1$$`, + `SPARSED_DETECTOR_KFF`=`$$0|10|1000$$`, `MEM_LIMIT_CHUNK`=`$$0|100|1000000$$`, `OTHERS_ALLOWED_FRACTION`=`$$0|0.5$$`) + ------ + BULK_UPSERT: + /Root/ColumnTable + %s + BAD_REQUEST + )", + arrowString.data()); + TScriptVariator(script).Execute(); + } + Y_UNIT_TEST(RestoreJsonArrayVariants) { TString script = R"( SCHEMA: diff --git a/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp b/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp index 49618aec959a..981159a1c02a 100644 --- a/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp +++ b/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp @@ -3487,5 +3487,74 @@ Y_UNIT_TEST_SUITE(KqpOlap) { UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "Default values are not supported in column tables", result.GetIssues().ToString()); } } + + Y_UNIT_TEST(PredicateWithLimit) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOlapSink(true); + auto runnerSettings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true) + .SetColumnShardAlterObjectEnabled(true) + .SetColumnShardReaderClassName("SIMPLE"); + + TTestHelper testHelper(runnerSettings); + auto client = testHelper.GetKikimr().GetQueryClient(); + + TVector schema = { + TTestHelper::TColumnSchema().SetName("a").SetType(NScheme::NTypeIds::Uint64).SetNullable(false), + TTestHelper::TColumnSchema().SetName("b").SetType(NScheme::NTypeIds::Uint64).SetNullable(false), + }; + + TTestHelper::TColumnTable testTable; + testTable.SetName("/Root/ColumnTableTest").SetPrimaryKey({ "a", "b" }).SetSchema(schema); + testHelper.CreateTable(testTable); + + { + TTestHelper::TUpdatesBuilder tableInserter(testTable.GetArrowSchema(schema)); + tableInserter.AddRow().Add(1).Add(1); + tableInserter.AddRow().Add(2).Add(2); + testHelper.BulkUpsert(testTable, tableInserter); + } + + testHelper.ReadData("SELECT a, b FROM `/Root/ColumnTableTest` WHERE b = 2 LIMIT 2", "[[2u;2u]]"); + } + + Y_UNIT_TEST(SimpleRequestHasProjections) { + auto settings = TKikimrSettings() + .SetWithSampleTables(false); + TKikimrRunner kikimr(settings); + TLocalHelper(kikimr).CreateTestOlapTable(); + WriteTestData(kikimr, "/Root/olapStore/olapTable", 0, 1000000, 20); + auto client = kikimr.GetTableClient(); + Tests::NCommon::TLoggerInit(kikimr).Initialize(); + + { + auto it = client.StreamExecuteScanQuery(R"( + --!syntax_v1 + + SELECT 1 + FROM `/Root/olapStore/olapTable` + )").GetValueSync(); + + UNIT_ASSERT_C(it.IsSuccess(), it.GetIssues().ToString()); + TString result = StreamResultToYson(it); + + CompareYson(result, R"([[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1];[1]])"); + } + + { + auto it = client.StreamExecuteScanQuery(R"( + --!syntax_v1 + + SELECT count(*) + FROM `/Root/olapStore/olapTable` + )").GetValueSync(); + + UNIT_ASSERT_C(it.IsSuccess(), it.GetIssues().ToString()); + TString result = StreamResultToYson(it); + + CompareYson(result, R"([[20u]])"); + } + } } } diff --git a/ydb/core/kqp/ut/olap/sparsed_ut.cpp b/ydb/core/kqp/ut/olap/sparsed_ut.cpp index 147856f2d1e2..4c92f21fcc92 100644 --- a/ydb/core/kqp/ut/olap/sparsed_ut.cpp +++ b/ydb/core/kqp/ut/olap/sparsed_ut.cpp @@ -233,6 +233,9 @@ Y_UNIT_TEST_SUITE(KqpOlapSparsed) { } void ExecuteMultiColumn() { +#ifdef address_sanitizer_enabled + MultiColumnRepCount = 30; +#endif CSController->DisableBackground(NKikimr::NYDBTest::ICSController::EBackground::Indexation); CSController->DisableBackground(NKikimr::NYDBTest::ICSController::EBackground::Compaction); CSController->SetOverridePeriodicWakeupActivationPeriod(TDuration::MilliSeconds(100)); diff --git a/ydb/core/kqp/ut/opt/kqp_named_expressions_ut.cpp b/ydb/core/kqp/ut/opt/kqp_named_expressions_ut.cpp new file mode 100644 index 000000000000..3eac0573cfcd --- /dev/null +++ b/ydb/core/kqp/ut/opt/kqp_named_expressions_ut.cpp @@ -0,0 +1,466 @@ +#include + +#include +#include +#include +#include + +namespace NKikimr::NKqp { + +using namespace NYdb; + +Y_UNIT_TEST_SUITE(KqpNamedExpressions) { + Y_UNIT_TEST_TWIN(NamedExpressionSimple, UseSink) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseSink); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true); + TKikimrRunner kikimr(settings); + + const TString query = R"( + $t = SELECT * FROM KeyValue; + + SELECT * FROM $t; + + UPSERT INTO KeyValue (Key, Value) VALUES (3u, "test"); + + SELECT * FROM $t; + + UPSERT INTO KeyValue SELECT Key + 10u AS Key, Value FROM $t; + + SELECT * FROM $t; + )"; + + auto client = kikimr.GetQueryClient(); + auto result = client.ExecuteQuery(query, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + CompareYson(R"([[[1u];["One"]];[[2u];["Two"]]])", FormatResultSetYson(result.GetResultSet(0))); + Cerr << FormatResultSetYson(result.GetResultSet(1)) << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(2)) << Endl; + CompareYson(R"([[[1u];["One"]];[[2u];["Two"]]])", FormatResultSetYson(result.GetResultSet(1))); + CompareYson(R"([[[1u];["One"]];[[2u];["Two"]]])", FormatResultSetYson(result.GetResultSet(2))); + } + + Y_UNIT_TEST_TWIN(NamedExpressionChanged, UseSink) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseSink); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true); + TKikimrRunner kikimr(settings); + + const TString query = R"( + $t = ( + SELECT + Key As Key, + Value As OldValue, + "test" As NewValue + FROM KeyValue + WHERE Value != "test" + ); + + UPSERT INTO KeyValue2 ( + SELECT + CAST(Key AS String) AS Key, + NewValue AS Value + From $t + ); + + UPDATE KeyValue ON ( + SELECT + Key AS Key, + NewValue AS Value + From $t + ); + + SELECT + COUNT(*) + FROM $t; + + SELECT * FROM KeyValue2; + )"; + + auto client = kikimr.GetQueryClient(); + auto result = client.ExecuteQuery(query, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + CompareYson(R"([[2u]])", FormatResultSetYson(result.GetResultSet(0))); + CompareYson(R"([[["1"];["test"]];[["2"];["test"]]])", FormatResultSetYson(result.GetResultSet(1))); + } + + Y_UNIT_TEST_TWIN(NamedExpressionRandomChanged, UseSink) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseSink); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true); + TKikimrRunner kikimr(settings); + + { + const TString query = R"( + $t = ( + SELECT + Key As Key, + CAST(RandomUuid(Key) AS String) As NewValue + FROM KeyValue + WHERE LENGTH(Value) < 10 + LIMIT 10 + ); + + UPSERT INTO KeyValue2 ( + SELECT + CAST(Key AS String) AS Key, + NewValue AS Value + From $t + ); + + UPDATE KeyValue ON ( + SELECT + Key AS Key, + NewValue AS Value + From $t + ); + + SELECT + True + FROM $t + LIMIT 1; + )"; + + auto client = kikimr.GetTableClient(); + auto session = client.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteDataQuery(query, NYdb::NTable::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + Cerr << FormatResultSetYson(result.GetResultSet(0)) << Endl; + + CompareYson(R"([[%true]])", FormatResultSetYson(result.GetResultSet(0))); + } + + { + const TString query = R"( + SELECT Value FROM KeyValue ORDER BY Value; + SELECT Value FROM KeyValue2 ORDER BY Value; + )"; + + auto client = kikimr.GetTableClient(); + auto session = client.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteDataQuery(query, NYdb::NTable::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + Cerr << FormatResultSetYson(result.GetResultSet(0)) << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(1)) << Endl; + + UNIT_ASSERT_VALUES_EQUAL(FormatResultSetYson(result.GetResultSet(0)), FormatResultSetYson(result.GetResultSet(1))); + } + } + + Y_UNIT_TEST_TWIN(NamedExpressionRandomChanged2, UseSink) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseSink); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true); + TKikimrRunner kikimr(settings); + + const TString query = R"( + $t = ( + SELECT + Key As Key, + CAST(RandomUuid(Key) AS String) As Value + FROM KeyValue + WHERE LENGTH(Value) < 10 + ); + + UPDATE KeyValue ON ( + SELECT + Key AS Key, + Value AS Value + From $t + ); + + UPSERT INTO KeyValue2 ( + SELECT + CAST(Key AS String) AS Key, + Value AS Value + From $t + ); + + SELECT Value FROM KeyValue ORDER BY Value; + SELECT Value FROM KeyValue2 ORDER BY Value; + )"; + + auto client = kikimr.GetQueryClient(); + auto result = client.ExecuteQuery(query, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + Cerr << FormatResultSetYson(result.GetResultSet(0)) << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(1)) << Endl; + + UNIT_ASSERT_VALUES_EQUAL(FormatResultSetYson(result.GetResultSet(0)), FormatResultSetYson(result.GetResultSet(1))); + } + + Y_UNIT_TEST_TWIN(NamedExpressionRandom, UseSink) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseSink); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true); + + const std::vector> operations = { + {"UPSERT INTO", ""}, + {"REPLACE INTO", ""}, + {"UPDATE", "ON"}, + }; + + for (const auto& [operation, operationPart] : operations) { + TKikimrRunner kikimr(settings); + auto client = kikimr.GetQueryClient(); + + const TString query = std::format(R"( + $t = ( + SELECT + Key As Key, + CAST(RandomUuid(Key) AS String) As Value + FROM KeyValue + ); + + {0} KeyValue2 {1} ( + SELECT + CAST(Key AS String) AS Key, + Value AS Value + From $t + ); + + {0} KeyValue {1} ( + SELECT + Key AS Key, + Value AS Value + From $t + ); + + SELECT Value FROM KeyValue ORDER BY Value; + SELECT Value FROM KeyValue2 ORDER BY Value; + SELECT Value FROM $t ORDER BY Value; + )", operation, operationPart); + + auto result = client.ExecuteQuery(query, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + Cerr << FormatResultSetYson(result.GetResultSet(0)) << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(1)) << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(2)) << Endl; + + UNIT_ASSERT_VALUES_EQUAL(FormatResultSetYson(result.GetResultSet(0)), FormatResultSetYson(result.GetResultSet(1))); + UNIT_ASSERT(FormatResultSetYson(result.GetResultSet(0)) != FormatResultSetYson(result.GetResultSet(2))); + } + } + + Y_UNIT_TEST_TWIN(NamedExpressionRandomInsert, UseSink) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseSink); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true); + + const std::vector> operations = { + {"UPSERT INTO", ""}, + {"REPLACE INTO", ""}, + {"INSERT INTO", ""}, + }; + + for (const auto& [operation, operationPart] : operations) { + TKikimrRunner kikimr(settings); + auto client = kikimr.GetQueryClient(); + + const TString query = std::format(R"( + $t = ( + SELECT + Key As Key, + CAST(RandomUuid(Key) AS String) As Value + FROM KeyValue + ); + + DELETE FROM KeyValue2; + + {0} KeyValue2 {1} ( + SELECT + CAST(Key AS String) AS Key, + Value AS Value + From $t + ); + + {0} KeyValue2 {1} ( + SELECT + CAST(Key + 10u AS String) AS Key, + Value AS Value + From $t + ); + + SELECT Value FROM KeyValue2 WHERE CAST(Key AS Uint64) < 10u ORDER BY Value; + SELECT Value FROM KeyValue2 WHERE CAST(Key AS Uint64) > 10u ORDER BY Value; + SELECT Value FROM $t ORDER BY Value; + )", operation, operationPart); + + auto result = client.ExecuteQuery(query, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + Cerr << operation << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(0)) << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(1)) << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(2)) << Endl; + + if (!operation.contains("INSERT")) { + UNIT_ASSERT_VALUES_EQUAL(FormatResultSetYson(result.GetResultSet(0)), FormatResultSetYson(result.GetResultSet(1))); + } else { + UNIT_ASSERT(FormatResultSetYson(result.GetResultSet(0)) != FormatResultSetYson(result.GetResultSet(1))); + } + UNIT_ASSERT(FormatResultSetYson(result.GetResultSet(0)) != FormatResultSetYson(result.GetResultSet(2))); + } + } + + Y_UNIT_TEST_TWIN(NamedExpressionRandomDataQuery, UseSink) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseSink); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true); + + const std::vector> operations = { + {"UPSERT INTO", ""}, + {"REPLACE INTO", ""}, + {"UPDATE", "ON"}, + }; + + for (const auto& [operation, operationPart] : operations) { + TKikimrRunner kikimr(settings); + auto client = kikimr.GetTableClient(); + + { + const TString query = std::format(R"( + $t = ( + SELECT + Key As Key, + CAST(RandomUuid(Key) AS String) As Value + FROM KeyValue + WHERE LENGTH(Value) < 10u + ); + + {0} KeyValue2 {1} ( + SELECT + CAST(Key AS String) AS Key, + Value AS Value + From $t + ); + + {0} KeyValue {1} ( + SELECT + Key AS Key, + Value AS Value + From $t + ); + + SELECT Value FROM $t ORDER BY Value; + )", operation, operationPart); + + auto session = client.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteDataQuery(query, NYdb::NTable::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + Cerr << FormatResultSetYson(result.GetResultSet(0)) << Endl; + UNIT_ASSERT_VALUES_EQUAL(2, result.GetResultSet(0).RowsCount()); + } + { + const TString query = std::format(R"( + SELECT Value FROM KeyValue ORDER BY Value; + SELECT Value FROM KeyValue2 ORDER BY Value; + )", operation, operationPart); + + auto session = client.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteDataQuery(query, NYdb::NTable::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + Cerr << FormatResultSetYson(result.GetResultSet(0)) << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(1)) << Endl; + + UNIT_ASSERT_VALUES_EQUAL(FormatResultSetYson(result.GetResultSet(0)), FormatResultSetYson(result.GetResultSet(1))); + } + } + } + + Y_UNIT_TEST_TWIN(NamedExpressionRandomInsertDataQuery, UseSink) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseSink); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true); + + const std::vector> operations = { + {"UPSERT INTO", ""}, + {"REPLACE INTO", ""}, + {"INSERT INTO", ""}, + }; + + for (const auto& [operation, operationPart] : operations) { + TKikimrRunner kikimr(settings); + auto client = kikimr.GetTableClient(); + + { + const TString query = std::format(R"( + $t = ( + SELECT + Key As Key, + CAST(RandomUuid(Key) AS String) As Value + FROM KeyValue + ); + + DELETE FROM KeyValue2; + + {0} KeyValue2 {1} ( + SELECT + CAST(Key AS String) AS Key, + Value AS Value + From $t + ); + + {0} KeyValue2 {1} ( + SELECT + CAST(Key + 10u AS String) AS Key, + Value AS Value + From $t + ); + + SELECT Value FROM $t ORDER BY Value; + )", operation, operationPart); + + auto session = client.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteDataQuery(query, NYdb::NTable::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + Cerr << FormatResultSetYson(result.GetResultSet(0)) << Endl; + UNIT_ASSERT_VALUES_EQUAL(2, result.GetResultSet(0).RowsCount()); + } + { + const TString query = std::format(R"( + SELECT Value FROM KeyValue2 WHERE CAST(Key AS Uint64) < 10u ORDER BY Value; + SELECT Value FROM KeyValue2 WHERE CAST(Key AS Uint64) > 10u ORDER BY Value; + )", operation, operationPart); + + auto session = client.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteDataQuery(query, NYdb::NTable::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + Cerr << FormatResultSetYson(result.GetResultSet(0)) << Endl; + Cerr << FormatResultSetYson(result.GetResultSet(1)) << Endl; + + if (!operation.contains("INSERT")) { + UNIT_ASSERT_VALUES_EQUAL(FormatResultSetYson(result.GetResultSet(0)), FormatResultSetYson(result.GetResultSet(1))); + } else { + UNIT_ASSERT(FormatResultSetYson(result.GetResultSet(0)) != FormatResultSetYson(result.GetResultSet(1))); + } + } + } + } +} + +} // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/ut/opt/ya.make b/ydb/core/kqp/ut/opt/ya.make index 838ad3b00987..7a812834fcac 100644 --- a/ydb/core/kqp/ut/opt/ya.make +++ b/ydb/core/kqp/ut/opt/ya.make @@ -15,12 +15,13 @@ SRCS( kqp_extract_predicate_unpack_ut.cpp kqp_kv_ut.cpp kqp_merge_ut.cpp + kqp_named_expressions_ut.cpp kqp_ne_ut.cpp kqp_not_null_ut.cpp kqp_ranges_ut.cpp + kqp_returning_ut.cpp kqp_sort_ut.cpp kqp_sqlin_ut.cpp - kqp_returning_ut.cpp ) PEERDIR( diff --git a/ydb/core/kqp/ut/query/kqp_explain_ut.cpp b/ydb/core/kqp/ut/query/kqp_explain_ut.cpp index ae7016418efa..e9a07810a2e9 100644 --- a/ydb/core/kqp/ut/query/kqp_explain_ut.cpp +++ b/ydb/core/kqp/ut/query/kqp_explain_ut.cpp @@ -523,7 +523,7 @@ Y_UNIT_TEST_SUITE(KqpExplain) { auto deletesConstCount = CountPlanNodesByKv(plan, "Node Type", "Delete-ConstantExpr"); UNIT_ASSERT_VALUES_EQUAL(deletesConstCount, UseSink ? 0 : 1); - auto upsertsCount = CountPlanNodesByKv(plan, "Name", "Upsert"); + auto upsertsCount = CountPlanNodesByKv(plan, "Name", UseSink ? "Update" : "Upsert"); UNIT_ASSERT_VALUES_EQUAL(upsertsCount, UseSink ? 2 : 2); auto deletesCount = CountPlanNodesByKv(plan, "Name", "Delete"); @@ -549,7 +549,7 @@ Y_UNIT_TEST_SUITE(KqpExplain) { countOperationsByType("reads"); countOperationsByType("writes"); - UNIT_ASSERT_VALUES_EQUAL(counter["MultiUpsert"], UseSink ? upsertsCount : upsertsConstCount); + UNIT_ASSERT_VALUES_EQUAL(counter[UseSink ? "MultiUpdate" : "MultiUpsert"], UseSink ? upsertsCount : upsertsConstCount); UNIT_ASSERT_VALUES_EQUAL(counter["MultiErase"], UseSink ? deletesCount : deletesConstCount); UNIT_ASSERT_VALUES_EQUAL(counter["FullScan"], fullScansCount); UNIT_ASSERT_VALUES_EQUAL(counter["Scan"], rangeScansCount); @@ -931,6 +931,143 @@ Y_UNIT_TEST_SUITE(KqpExplain) { UNIT_ASSERT(cteLink1.IsDefined()); } + + Y_UNIT_TEST_TWIN(CreateTableAs, Stats) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableCreateTableAs(true); + auto kikimrSettings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(false) + .SetEnableTempTables(true); + TKikimrRunner kikimr(kikimrSettings); + auto client = kikimr.GetQueryClient(); + + { + auto result = client.ExecuteQuery( R"( + CREATE TABLE `/Root/Source` ( + Col1 Uint64 NOT NULL, + Col2 Int32, + PRIMARY KEY (Col1) + ) + WITH (AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 10); + )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + } + + { + auto result = client.ExecuteQuery( R"( + SELECT * FROM `/Root/Source`; + )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + } + + auto settings = NYdb::NQuery::TExecuteQuerySettings() + .ExecMode(NYdb::NQuery::EExecMode::Explain); + if (Stats) { + settings.StatsMode(NYdb::NQuery::EStatsMode::Full); + } + + { + auto result = client.ExecuteQuery(R"( + CREATE TABLE `/Root/Destination` ( + PRIMARY KEY (Col1) + ) + WITH (AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 4) + AS SELECT * FROM `/Root/Source`; + )", NYdb::NQuery::TTxControl::NoTx(), settings).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT(result.GetResultSets().empty()); + + UNIT_ASSERT(result.GetStats()); + UNIT_ASSERT(result.GetStats()->GetPlan()); + + Cerr << "PLAN::" << *result.GetStats()->GetPlan() << Endl; + + NJson::TJsonValue plan; + NJson::ReadJsonTree(*result.GetStats()->GetPlan(), &plan, true); + UNIT_ASSERT(ValidatePlanNodeIds(plan)); + + auto sink = FindPlanNodeByKv( + plan, + "Name", + "FillTable" + ); + + UNIT_ASSERT(sink.IsDefined()); + + UNIT_ASSERT_VALUES_EQUAL(sink["SinkType"], "KqpTableSink"); + UNIT_ASSERT_VALUES_EQUAL(sink["Path"], "/Root/Destination"); + UNIT_ASSERT_VALUES_EQUAL(sink["Table"], "Destination"); + } + + { + auto result = client.ExecuteQuery(R"( + CREATE TABLE `test/Destination2` ( + PRIMARY KEY (Col1) + ) + WITH (AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 4) + AS SELECT * FROM `/Root/Source`; + )", NYdb::NQuery::TTxControl::NoTx(), settings).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT(result.GetResultSets().empty()); + + UNIT_ASSERT(result.GetStats()); + UNIT_ASSERT(result.GetStats()->GetPlan()); + + Cerr << "PLAN::" << *result.GetStats()->GetPlan() << Endl; + + NJson::TJsonValue plan; + NJson::ReadJsonTree(*result.GetStats()->GetPlan(), &plan, true); + UNIT_ASSERT(ValidatePlanNodeIds(plan)); + + auto sink = FindPlanNodeByKv( + plan, + "Name", + "FillTable" + ); + + UNIT_ASSERT(sink.IsDefined()); + + UNIT_ASSERT_VALUES_EQUAL(sink["SinkType"], "KqpTableSink"); + UNIT_ASSERT_VALUES_EQUAL(sink["Path"], "/Root/test/Destination2"); + UNIT_ASSERT_VALUES_EQUAL(sink["Table"], "test/Destination2"); + } + + { + auto result = client.ExecuteQuery(R"( + PRAGMA TablePathPrefix("/Root/test"); + + CREATE TABLE `test2/Destination3` ( + PRIMARY KEY (Col1) + ) + WITH (AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 4) + AS SELECT * FROM `/Root/Source`; + )", NYdb::NQuery::TTxControl::NoTx(), settings).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT(result.GetResultSets().empty()); + + UNIT_ASSERT(result.GetStats()); + UNIT_ASSERT(result.GetStats()->GetPlan()); + + Cerr << "PLAN::" << *result.GetStats()->GetPlan() << Endl; + + NJson::TJsonValue plan; + NJson::ReadJsonTree(*result.GetStats()->GetPlan(), &plan, true); + UNIT_ASSERT(ValidatePlanNodeIds(plan)); + + auto sink = FindPlanNodeByKv( + plan, + "Name", + "FillTable" + ); + + UNIT_ASSERT(sink.IsDefined()); + + UNIT_ASSERT_VALUES_EQUAL(sink["SinkType"], "KqpTableSink"); + UNIT_ASSERT_VALUES_EQUAL(sink["Path"], "/Root/test/test2/Destination3"); + UNIT_ASSERT_VALUES_EQUAL(sink["Table"], "test/test2/Destination3"); + } + } } } // namespace NKqp diff --git a/ydb/core/kqp/ut/query/kqp_limits_ut.cpp b/ydb/core/kqp/ut/query/kqp_limits_ut.cpp index 85d59bbf920d..6ac59d016225 100644 --- a/ydb/core/kqp/ut/query/kqp_limits_ut.cpp +++ b/ydb/core/kqp/ut/query/kqp_limits_ut.cpp @@ -101,42 +101,45 @@ Y_UNIT_TEST_SUITE(KqpLimits) { auto app = NKikimrConfig::TAppConfig(); app.MutableTableServiceConfig()->SetEnableOltpSink(true); app.MutableTableServiceConfig()->SetEnableStreamWrite(Allowed); - app.MutableTableServiceConfig()->MutableWriteActorSettings()->SetInFlightMemoryLimitPerActorBytes(64); auto settings = TKikimrSettings() .SetAppConfig(app) .SetWithSampleTables(false); TKikimrRunner kikimr(settings); + CreateLargeTable(kikimr, 1000, 1_KB, 64_KB); auto db = kikimr.GetQueryClient(); { auto result = db.ExecuteQuery(R"( CREATE TABLE `/Root/DataShard` ( - Col1 Uint64 NOT NULL, - Col2 String NOT NULL, - Col3 Int32 NOT NULL, - PRIMARY KEY (Col1) + Key Uint64, + KeyText String, + Data Int64, + DataText String, + PRIMARY KEY (Key) ) - WITH (UNIFORM_PARTITIONS = 2, AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 2);)", + WITH ( + AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 8, + PARTITION_AT_KEYS = (1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000) + );)", NQuery::TTxControl::NoTx()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); } { auto result = db.ExecuteQuery(R"( - UPSERT INTO `/Root/DataShard` (Col1, Col2, Col3) VALUES - (10u, "test1", 10), (20u, "test2", 11), (30u, "test3", 12), (40u, "test", 13); + UPSERT INTO `/Root/DataShard` SELECT * FROM `/Root/LargeTable`; )", NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); result.GetIssues().PrintTo(Cerr); if (!Allowed) { - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::PRECONDITION_FAILED); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::PRECONDITION_FAILED, result.GetIssues().ToString()); UNIT_ASSERT_C( result.GetIssues().ToString().contains("Stream write queries aren't allowed."), result.GetIssues().ToString()); } else { - UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); } } } @@ -696,38 +699,38 @@ Y_UNIT_TEST_SUITE(KqpLimits) { Y_UNIT_TEST(AffectedShardsLimit) { NKikimrConfig::TAppConfig appConfig; auto& queryLimits = *appConfig.MutableTableServiceConfig()->MutableQueryLimits(); - queryLimits.MutablePhaseLimits()->SetAffectedShardsLimit(20); + queryLimits.MutablePhaseLimits()->SetAffectedShardsLimit(23); TKikimrRunner kikimr(appConfig); kikimr.GetTestClient().CreateTable("/Root", R"( - Name: "ManyShard20" + Name: "ManyShard23" Columns { Name: "Key", Type: "Uint32" } Columns { Name: "Value1", Type: "String" } Columns { Name: "Value2", Type: "Int32" } KeyColumnNames: ["Key"] - UniformPartitionsCount: 20 + UniformPartitionsCount: 23 )"); kikimr.GetTestClient().CreateTable("/Root", R"( - Name: "ManyShard21" + Name: "ManyShard24" Columns { Name: "Key", Type: "Uint32" } Columns { Name: "Value1", Type: "String" } Columns { Name: "Value2", Type: "Int32" } KeyColumnNames: ["Key"] - UniformPartitionsCount: 21 + UniformPartitionsCount: 24 )"); auto db = kikimr.GetTableClient(); auto session = db.CreateSession().GetValueSync().GetSession(); auto result = session.ExecuteDataQuery(Q_(R"( - SELECT COUNT(*) FROM `/Root/ManyShard20` + SELECT COUNT(*) FROM `/Root/ManyShard23` )"), TTxControl::BeginTx().CommitTx()).ExtractValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); result = session.ExecuteDataQuery(Q_(R"( - SELECT COUNT(*) FROM `/Root/ManyShard21` + SELECT COUNT(*) FROM `/Root/ManyShard24` )"), TTxControl::BeginTx().CommitTx()).ExtractValueSync(); result.GetIssues().PrintTo(Cerr); UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::PRECONDITION_FAILED); diff --git a/ydb/core/kqp/ut/query/kqp_params_ut.cpp b/ydb/core/kqp/ut/query/kqp_params_ut.cpp index 32e9b715d223..8542f017abad 100644 --- a/ydb/core/kqp/ut/query/kqp_params_ut.cpp +++ b/ydb/core/kqp/ut/query/kqp_params_ut.cpp @@ -78,6 +78,45 @@ Y_UNIT_TEST_SUITE(KqpParams) { UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::BAD_REQUEST, result.GetIssues().ToString()); } + Y_UNIT_TEST_TWIN(MissingOptionalParameter, UseSink) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseSink); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(true); + TKikimrRunner kikimr(settings); + auto db = kikimr.GetTableClient(); + auto session = db.CreateSession().GetValueSync().GetSession(); + + { + auto params = db.GetParamsBuilder() + .AddParam("$_amount") + .Uint64(42) + .Build() + .Build(); + auto result = session.ExecuteDataQuery(Q_(R"( + --!syntax_v1 + + DECLARE $_amount AS Uint64; + DECLARE $_comment AS String?; + + UPSERT INTO `/Root/Test` (Group, Name, Amount, Comment) VALUES + (1u, "test", $_amount, $_comment); + )"), TTxControl::BeginTx(TTxSettings::SerializableRW()).CommitTx(), params).ExtractValueSync(); + + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + } + + { + auto result = session.ExecuteDataQuery(Q_(R"( + SELECT * FROM `/Root/Test` WHERE Group = 1 AND Name = "test"; + )"), TTxControl::BeginTx(TTxSettings::SerializableRW()).CommitTx()).ExtractValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + CompareYson(R"([[[42u];#;[1u];["test"]]])", FormatResultSetYson(result.GetResultSet(0))); + } + } + Y_UNIT_TEST(BadParameterType) { TKikimrRunner kikimr; auto db = kikimr.GetTableClient(); diff --git a/ydb/core/kqp/ut/query/kqp_query_ut.cpp b/ydb/core/kqp/ut/query/kqp_query_ut.cpp index e55ed7a713da..1f2d3be087c1 100644 --- a/ydb/core/kqp/ut/query/kqp_query_ut.cpp +++ b/ydb/core/kqp/ut/query/kqp_query_ut.cpp @@ -2027,18 +2027,12 @@ Y_UNIT_TEST_SUITE(KqpQuery) { SELECT Col2 AS Col1, Col1 As Col2 FROM `/Root/ColSrc`; )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString()); - UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "Can't set NULL or optional value to not null column: Col1.", result.GetIssues().ToString()); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "Can't create column table with nullable primary key column `Col1`.", result.GetIssues().ToString()); result = client.ExecuteQuery(R"( SELECT * FROM `/Root/ColDst`; )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); - // TODO: Wait for RENAME from columnshards - UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); - - result = client.ExecuteQuery(R"( - DROP TABLE `/Root/ColDst`; - )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); - UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); + UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString()); } { @@ -2211,6 +2205,381 @@ Y_UNIT_TEST_SUITE(KqpQuery) { UNIT_ASSERT(result.GetStatus() == NYdb::EStatus::OVERLOADED); } } + + Y_UNIT_TEST(TableSinkWithSubquery) { + NKikimrConfig::TAppConfig appConfig; + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(false); + + TKikimrRunner kikimr(settings); + Tests::NCommon::TLoggerInit(kikimr).Initialize(); + + auto session = kikimr.GetTableClient().CreateSession().GetValueSync().GetSession(); + + const TString query = R"( + CREATE TABLE `/Root/table1` ( + p1 Utf8, + PRIMARY KEY (p1) + ) + WITH ( + STORE = ROW + ); + + CREATE TABLE `/Root/table2` ( + p1 Utf8, + PRIMARY KEY (p1) + ) + WITH ( + STORE = ROW + ); + )"; + + auto result = session.ExecuteSchemeQuery(query).GetValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + auto client = kikimr.GetQueryClient(); + + { + auto prepareResult = client.ExecuteQuery(R"( + UPSERT INTO `/Root/table1` (p1) VALUES ("a") , ("b"), ("c"); + )", NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(prepareResult.IsSuccess(), prepareResult.GetIssues().ToString()); + } + + { + auto result = client.ExecuteQuery(R"( + $data2 = Cast(AsList() As List>); + + /* query */ + SELECT d1.p1 AS p1, + FROM `/Root/table1` AS d1 + CROSS JOIN AS_TABLE($data2) AS d2; + )", NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); + } + + { + auto result = client.ExecuteQuery(R"( + $data2 = Cast(AsList() As List>); + + /* query */ + INSERT INTO `/Root/table1` + SELECT d1.p1 AS p1, + FROM `/Root/table2` AS d1 + CROSS JOIN AS_TABLE($data2) AS d2; + )", NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); + } + } + + Y_UNIT_TEST_QUAD(CreateAsSelectTypes, NotNull, IsOlap) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOlapSink(true); + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(true); + appConfig.MutableTableServiceConfig()->SetEnableCreateTableAs(true); + appConfig.MutableTableServiceConfig()->SetEnablePerStatementQueryExecution(true); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(false) + .SetEnableTempTables(true); + TKikimrRunner kikimr(settings); + auto client = kikimr.GetQueryClient(); + + { + const TString createSource = std::format(R"( + CREATE TABLE `/Root/Source` ( + Key Int8 NOT NULL, + CInt8 Int8 {0}, + CUint8 Uint8 {0}, + CInt16 Int16 {0}, + CUint16 Uint16 {0}, + CInt32 Int32 {0}, + CUint32 Uint32 {0}, + CInt64 Int64 {0}, + CUint64 Uint64 {0}, + CFloat Float {0}, + CDouble Double {0}, + CDate Date {0}, + CDatetime Datetime {0}, + CTimestamp Timestamp {0}, + CDate32 Date32 {0}, + CDatetime64 Datetime64 {0}, + CTimestamp64 Timestamp64 {0}, + CString String {0}, + CUtf8 Utf8 {0}, + CYson Yson {0}, + CJson Json {0}, + CJsonDocument JsonDocument {0}, + {1} + PRIMARY KEY (Key) + ); + )", + NotNull ? "NOT NULL" : "", + IsOlap ? "" : std::format(R"( + CBool Bool {0}, + CInterval Interval {0}, + CInterval64 Interval64 {0}, + CUuid Uuid {0}, + CDyNumber DyNumber {0},)", + NotNull ? "NOT NULL" : "")); + + auto result = client.ExecuteQuery(createSource, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + } + + { + auto prepareResult = client.ExecuteQuery(std::format(R"( + UPSERT INTO `/Root/Source` ( + Key + , CInt8 + , CUint8 + , CInt16 + , CUint16 + , CInt32 + , CUint32 + , CInt64 + , CUint64 + , CFloat + , CDouble + , CDate + , CDatetime + , CTimestamp + , CDate32 + , CDatetime64 + , CTimestamp64 + , CString + , CUtf8 + , CYson + , CJson + , CJsonDocument + {0} + ) + VALUES ( + 0 + , 42 + , 42 + , 42 + , 42 + , 42 + , 42 + , 42 + , 42 + , CAST(42.0 AS Float) + , 42.0 + , Date("2025-01-01") + , Datetime("2025-01-01T00:00:00Z") + , Timestamp("2025-01-01T00:00:00Z") + , Date("2025-01-01") + , Datetime("2025-01-01T00:00:00Z") + , Timestamp("2025-01-01T00:00:00Z") + , String("test") + , Utf8("test") + , Yson("[3;%false]") + , Json(@@{{"a":1,"b":null}}@@) + , JsonDocument('{{"a":1,"b":null}}') + {1} + ); + )", + IsOlap ? "" : ", CBool, CInterval, CInterval64, CUuid, CDyNumber", + IsOlap ? "" : ", False, Interval(\"P1DT2H3M4.567890S\"), Interval(\"P1DT2H3M4.567890S\"), Uuid(\"f9d5cc3f-f1dc-4d9c-b97e-766e57ca4ccb\"), DyNumber(\"42\")"), + NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(prepareResult.IsSuccess(), prepareResult.GetIssues().ToString()); + } + + { + auto prepareResult = client.ExecuteQuery(std::format(R"( + CREATE TABLE `/Root/Destination` ( + PRIMARY KEY (Key) + ) + WITH (STORE = {0}) + AS SELECT * + FROM `/Root/Source`; + )", IsOlap ? "COLUMN" : "ROW"), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(prepareResult.IsSuccess(), prepareResult.GetIssues().ToString()); + } + + { + auto db = kikimr.GetTableClient(); + auto session = db.CreateSession().GetValueSync().GetSession(); + auto desc = session.DescribeTable("/Root/Destination").ExtractValueSync(); + UNIT_ASSERT_C(desc.IsSuccess(), desc.GetIssues().ToString()); + + auto columns = desc.GetTableDescription().GetTableColumns(); + for (const auto& column : columns) { + if (column.Name == "Key") { + continue; + } + + UNIT_ASSERT(!column.NotNull); + + static THashMap nameToType = { + {"CBool", "Bool?"}, + {"CInt8", "Int8?"}, + {"CUint8", "Uint8?"}, + {"CInt16", "Int16?"}, + {"CUint16", "Uint16?"}, + {"CInt32", "Int32?"}, + {"CUint32", "Uint32?"}, + {"CInt64", "Int64?"}, + {"CUint64", "Uint64?"}, + {"CFloat", "Float?"}, + {"CDouble", "Double?"}, + {"CDate", "Date?"}, + {"CDatetime", "Datetime?"}, + {"CTimestamp", "Timestamp?"}, + {"CInterval", "Interval?"}, + {"CDate32", "Date32?"}, + {"CDatetime64", "Datetime64?"}, + {"CTimestamp64", "Timestamp64?"}, + {"CInterval64", "Interval64?"}, + {"CString", "String?"}, + {"CUtf8", "Utf8?"}, + {"CYson", "Yson?"}, + {"CJson", "Json?"}, + {"CUuid", "Uuid?"}, + {"CJsonDocument", "JsonDocument?"}, + {"CDyNumber", "DyNumber?"}, + }; + + UNIT_ASSERT_VALUES_EQUAL_C(nameToType.at(column.Name), column.Type.ToString(), column.Name); + } + } + } + + Y_UNIT_TEST_TWIN(CreateAsSelectBadTypes, IsOlap) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOlapSink(true); + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(true); + appConfig.MutableTableServiceConfig()->SetEnableCreateTableAs(true); + appConfig.MutableTableServiceConfig()->SetEnablePerStatementQueryExecution(true); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(false) + .SetEnableTempTables(true); + TKikimrRunner kikimr(settings); + auto client = kikimr.GetQueryClient(); + + { + auto result = client.ExecuteQuery(std::format(R"( + CREATE TABLE `/Root/Destination` ( + PRIMARY KEY (Key) + ) + WITH (STORE = {0}) + AS SELECT 1 AS Key, AsList(1, 2, 3, 4, 5) AS Value; + )", IsOlap ? "COLUMN" : "ROW"), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString()); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "Invalid type for column: Value.", result.GetIssues().ToString()); + } + + { + auto result = client.ExecuteQuery(std::format(R"( + CREATE TABLE `/Root/Destination` ( + PRIMARY KEY (Key) + ) + WITH (STORE = {0}) + AS SELECT 1 AS Key, NULL AS Value; + )", IsOlap ? "COLUMN" : "ROW"), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString()); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "Invalid type for column: Value.", result.GetIssues().ToString()); + } + + { + auto result = client.ExecuteQuery(std::format(R"( + CREATE TABLE `/Root/Destination` ( + PRIMARY KEY (Key) + ) + WITH (STORE = {0}) + AS SELECT 1 AS Key, [] AS Value; + )", IsOlap ? "COLUMN" : "ROW"), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString()); + UNIT_ASSERT_STRING_CONTAINS_C(result.GetIssues().ToString(), "Invalid type for column: Value.", result.GetIssues().ToString()); + } + } + + Y_UNIT_TEST_TWIN(CreateAsSelectPath, UseTablePathPrefix) { + const auto dirPath = UseTablePathPrefix ? "" : "/Root/test/"; + const auto pragma = UseTablePathPrefix ? "PRAGMA TablePathPrefix(\"/Root/test\");" : ""; + + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOlapSink(true); + appConfig.MutableTableServiceConfig()->SetEnableOltpSink(true); + appConfig.MutableTableServiceConfig()->SetEnableCreateTableAs(true); + appConfig.MutableTableServiceConfig()->SetEnablePerStatementQueryExecution(true); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(false) + .SetEnableTempTables(true) + .SetAuthToken("user0@builtin");; + TKikimrRunner kikimr(settings); + + { + auto driverConfig = TDriverConfig() + .SetEndpoint(kikimr.GetEndpoint()) + .SetAuthToken("root@builtin"); + auto driver = TDriver(driverConfig); + auto schemeClient = NYdb::NScheme::TSchemeClient(driver); + + { + auto result = schemeClient.MakeDirectory("/Root/test").ExtractValueSync(); + AssertSuccessResult(result); + } + { + NYdb::NScheme::TPermissions permissions("user0@builtin", + {"ydb.generic.read", "ydb.generic.write"} + ); + auto result = schemeClient.ModifyPermissions("/Root/test", + NYdb::NScheme::TModifyPermissionsSettings().AddGrantPermissions(permissions) + ).ExtractValueSync(); + AssertSuccessResult(result); + } + } + + const TString query = std::format(R"( + {1} + CREATE TABLE `{0}Source` ( + Col1 Uint64 NOT NULL, + Col2 Int32, + PRIMARY KEY (Col1) + ); + )", dirPath, pragma); + + auto client = kikimr.GetQueryClient(); + auto result = client.ExecuteQuery(query, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); + + { + auto prepareResult = client.ExecuteQuery(std::format(R"( + {1} + REPLACE INTO `{0}Source` (Col1, Col2) VALUES + (1u, 1), (100u, 100), (10u, 10); + )", dirPath, pragma), NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(prepareResult.IsSuccess(), prepareResult.GetIssues().ToString()); + } + + { + auto prepareResult = client.ExecuteQuery(std::format(R"( + {1} + CREATE TABLE `{0}Destination1` ( + PRIMARY KEY (Col1) + ) + AS SELECT Col2 As Col1, Col1 As Col2 + FROM `{0}Source`; + )", dirPath, pragma), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(prepareResult.IsSuccess(), prepareResult.GetIssues().ToString()); + } + + { + auto it = client.StreamExecuteQuery(std::format(R"( + {1} + SELECT Col1, Col2 FROM `{0}Destination1`; + )", dirPath, pragma), NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(it.GetStatus(), EStatus::SUCCESS, it.GetIssues().ToString()); + TString output = StreamResultToYson(it); + CompareYson(output, R"([[[1];[1u]];[[10];[10u]];[[100];[100u]]])"); + } + } + } } // namespace NKqp diff --git a/ydb/core/kqp/ut/runtime/kqp_scan_logging_ut.cpp b/ydb/core/kqp/ut/runtime/kqp_scan_logging_ut.cpp index cbe47a175a2e..24c4d7017a0f 100644 --- a/ydb/core/kqp/ut/runtime/kqp_scan_logging_ut.cpp +++ b/ydb/core/kqp/ut/runtime/kqp_scan_logging_ut.cpp @@ -66,11 +66,7 @@ void RunTestForQuery(const std::string& query, const std::string& expectedLog, b break; } } - - // TODO: remove this if after https://github.com/ydb-platform/ydb/issues/15597 - if (!enabledLogs) { - UNIT_ASSERT(hasExpectedLog == enabledLogs); - } + UNIT_ASSERT(hasExpectedLog == enabledLogs); } } // anonymous namespace diff --git a/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp b/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp index db77fa211c23..4a036cb13a0a 100644 --- a/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp +++ b/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp @@ -8352,6 +8352,21 @@ Y_UNIT_TEST_SUITE(KqpScheme) { const auto result = session.ExecuteSchemeQuery(query).GetValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); } + + { + auto query = Sprintf(R"( + --!syntax_v1 + CREATE TRANSFER `/Root/transfer_fi` + FROM `/Root/topic` TO `/Root/table` + WITH ( + CONNECTION_STRING = "%s", + FLUSH_INTERVAL = Interval('PT1S') + ); + )", kikimr.GetEndpoint().c_str()); + + const auto result = session.ExecuteSchemeQuery(query).GetValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + } } Y_UNIT_TEST(CreateTransfer_QueryService) { @@ -8595,6 +8610,21 @@ Y_UNIT_TEST_SUITE(KqpScheme) { const auto result = session.ExecuteQuery(query, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); } + + { + auto query = Sprintf(R"( + --!syntax_v1 + CREATE TRANSFER `/Root/transfer_fi` + FROM `/Root/topic` TO `/Root/table` + WITH ( + CONNECTION_STRING = "%s", + FLUSH_INTERVAL = Interval('PT1S') + ); + )", kikimr.GetEndpoint().c_str()); + + const auto result = session.ExecuteQuery(query, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + } } Y_UNIT_TEST(AlterTransfer) { diff --git a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp index d7fc0fa18634..7145fab83641 100644 --- a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp +++ b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp @@ -2944,7 +2944,7 @@ Y_UNIT_TEST_SUITE(KqpQueryService) { UNIT_ASSERT(!result.GetResultSets().empty()); CompareYson(R"([ - [["test_view"];["View"];["CREATE VIEW `test_view` WITH (security_invoker = TRUE) AS\nSELECT * FROM KeyValue;\n"]]; + [["test_view"];["View"];["CREATE VIEW `test_view` WITH (security_invoker = TRUE) AS\nSELECT\n *\nFROM\n KeyValue\n;\n"]]; ])", FormatResultSetYson(result.GetResultSet(0))); } } diff --git a/ydb/core/kqp/ut/sysview/kqp_sys_view_ut.cpp b/ydb/core/kqp/ut/sysview/kqp_sys_view_ut.cpp index 34ba3b2642d8..f40bf3c30dc4 100644 --- a/ydb/core/kqp/ut/sysview/kqp_sys_view_ut.cpp +++ b/ydb/core/kqp/ut/sysview/kqp_sys_view_ut.cpp @@ -276,7 +276,10 @@ order by SessionId;)", "%Y-%m-%d %H:%M:%S %Z", sessionsSet.front().GetId().data( [[72057594046644480u];[0u];["/Root/Join1"];[10u]]; [[72057594046644480u];[1u];["/Root/Join1"];[10u]]; [[72057594046644480u];[0u];["/Root/Join2"];[11u]]; - [[72057594046644480u];[1u];["/Root/Join2"];[11u]] + [[72057594046644480u];[1u];["/Root/Join2"];[11u]]; + [[72057594046644480u];[0u];["/Root/TuplePrimaryDescending"];[12u]]; + [[72057594046644480u];[1u];["/Root/TuplePrimaryDescending"];[12u]]; + [[72057594046644480u];[2u];["/Root/TuplePrimaryDescending"];[12u]] ])", StreamResultToYson(it)); } diff --git a/ydb/core/kqp/ut/tx/kqp_snapshot_isolation_ut.cpp b/ydb/core/kqp/ut/tx/kqp_snapshot_isolation_ut.cpp index 47fc6216bba6..1885e7f23c09 100644 --- a/ydb/core/kqp/ut/tx/kqp_snapshot_isolation_ut.cpp +++ b/ydb/core/kqp/ut/tx/kqp_snapshot_isolation_ut.cpp @@ -45,12 +45,14 @@ Y_UNIT_TEST_SUITE(KqpSnapshotIsolation) { }; Y_UNIT_TEST(TSimpleOltp) { + return; TSimple tester; tester.SetIsOlap(false); tester.Execute(); } Y_UNIT_TEST(TSimpleOltpNoSink) { + return; TSimple tester; tester.SetIsOlap(false); tester.SetDisableSinks(true); @@ -58,6 +60,7 @@ Y_UNIT_TEST_SUITE(KqpSnapshotIsolation) { } Y_UNIT_TEST(TSimpleOlap) { + return; TSimple tester; tester.SetIsOlap(true); tester.Execute(); @@ -100,12 +103,14 @@ Y_UNIT_TEST_SUITE(KqpSnapshotIsolation) { }; Y_UNIT_TEST(TConflictWriteOltp) { + return; TConflictWrite tester; tester.SetIsOlap(false); tester.Execute(); } Y_UNIT_TEST(TConflictWriteOltpNoSink) { + return; TConflictWrite tester; tester.SetIsOlap(false); tester.SetDisableSinks(true); @@ -113,6 +118,7 @@ Y_UNIT_TEST_SUITE(KqpSnapshotIsolation) { } Y_UNIT_TEST(TConflictWriteOlap) { + return; TConflictWrite tester; tester.SetIsOlap(true); tester.Execute(); @@ -154,12 +160,14 @@ Y_UNIT_TEST_SUITE(KqpSnapshotIsolation) { }; Y_UNIT_TEST(TConflictReadWriteOltp) { + return; TConflictReadWrite tester; tester.SetIsOlap(false); tester.Execute(); } Y_UNIT_TEST(TConflictReadWriteOltpNoSink) { + return; TConflictReadWrite tester; tester.SetIsOlap(false); tester.SetDisableSinks(true); @@ -167,6 +175,7 @@ Y_UNIT_TEST_SUITE(KqpSnapshotIsolation) { } Y_UNIT_TEST(TConflictReadWriteOlap) { + return; TConflictReadWrite tester; tester.SetIsOlap(true); tester.Execute(); @@ -209,12 +218,14 @@ Y_UNIT_TEST_SUITE(KqpSnapshotIsolation) { }; Y_UNIT_TEST(TReadOnlyOltp) { + return; TReadOnly tester; tester.SetIsOlap(false); tester.Execute(); } Y_UNIT_TEST(TReadOnlyOltpNoSink) { + return; TReadOnly tester; tester.SetIsOlap(false); tester.SetDisableSinks(true); @@ -222,6 +233,7 @@ Y_UNIT_TEST_SUITE(KqpSnapshotIsolation) { } Y_UNIT_TEST(TReadOnlyOlap) { + return; TReadOnly tester; tester.SetIsOlap(true); tester.Execute(); diff --git a/ydb/core/kqp/ut/ya.make b/ydb/core/kqp/ut/ya.make index 38757b3dca1f..94a7ea3d446a 100644 --- a/ydb/core/kqp/ut/ya.make +++ b/ydb/core/kqp/ut/ya.make @@ -1,5 +1,6 @@ RECURSE_FOR_TESTS( arrow + batch_operations cost data data_integrity diff --git a/ydb/core/kqp/workload_service/actors/actors.h b/ydb/core/kqp/workload_service/actors/actors.h index d21706f3df7b..1dfcaa85911c 100644 --- a/ydb/core/kqp/workload_service/actors/actors.h +++ b/ydb/core/kqp/workload_service/actors/actors.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace NKikimr::NKqp::NWorkload { @@ -9,10 +10,10 @@ namespace NKikimr::NKqp::NWorkload { NActors::IActor* CreatePoolHandlerActor(const TString& databaseId, const TString& poolId, const NResourcePool::TPoolSettings& poolConfig, NMonitoring::TDynamicCounterPtr counters); // Fetch pool and create default pool if needed -NActors::IActor* CreatePoolResolverActor(TEvPlaceRequestIntoPool::TPtr event, bool defaultPoolExists); +NActors::IActor* CreatePoolResolverActor(TEvPlaceRequestIntoPool::TPtr event, bool defaultPoolExists, const NKikimrConfig::TWorkloadManagerConfig& workloadManagerConfig); // Fetch and create pool in scheme shard -NActors::IActor* CreatePoolFetcherActor(const NActors::TActorId& replyActorId, const TString& databaseId, const TString& poolId, TIntrusiveConstPtr userToken); +NActors::IActor* CreatePoolFetcherActor(const NActors::TActorId& replyActorId, const TString& databaseId, const TString& poolId, TIntrusiveConstPtr userToken, const NKikimrConfig::TWorkloadManagerConfig& workloadManagerConfig); NActors::IActor* CreatePoolCreatorActor(const NActors::TActorId& replyActorId, const TString& databaseId, const TString& poolId, const NResourcePool::TPoolSettings& poolConfig, TIntrusiveConstPtr userToken, NACLibProto::TDiffACL diffAcl); // Checks that database is serverless and return database id diff --git a/ydb/core/kqp/workload_service/actors/pool_handlers_acors.cpp b/ydb/core/kqp/workload_service/actors/pool_handlers_actors.cpp similarity index 100% rename from ydb/core/kqp/workload_service/actors/pool_handlers_acors.cpp rename to ydb/core/kqp/workload_service/actors/pool_handlers_actors.cpp diff --git a/ydb/core/kqp/workload_service/actors/scheme_actors.cpp b/ydb/core/kqp/workload_service/actors/scheme_actors.cpp index ef1e7c3dce51..1b90c742fc94 100644 --- a/ydb/core/kqp/workload_service/actors/scheme_actors.cpp +++ b/ydb/core/kqp/workload_service/actors/scheme_actors.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -24,8 +25,9 @@ using namespace NActors; class TPoolResolverActor : public TActorBootstrapped { public: - TPoolResolverActor(TEvPlaceRequestIntoPool::TPtr event, bool defaultPoolExists) + TPoolResolverActor(TEvPlaceRequestIntoPool::TPtr event, bool defaultPoolExists, const NKikimrConfig::TWorkloadManagerConfig& workloadManagerConfig) : Event(std::move(event)) + , WorkloadManagerConfig(workloadManagerConfig) { if (!Event->Get()->PoolId) { Event->Get()->PoolId = NResourcePool::DEFAULT_POOL_ID; @@ -40,7 +42,7 @@ class TPoolResolverActor : public TActorBootstrapped { void StartPoolFetchRequest() const { LOG_D("Start pool fetching"); - Register(CreatePoolFetcherActor(SelfId(), Event->Get()->DatabaseId, Event->Get()->PoolId, Event->Get()->UserToken)); + Register(CreatePoolFetcherActor(SelfId(), Event->Get()->DatabaseId, Event->Get()->PoolId, Event->Get()->UserToken, WorkloadManagerConfig)); } void Handle(TEvPrivate::TEvFetchPoolResponse::TPtr& ev) { @@ -119,6 +121,7 @@ class TPoolResolverActor : public TActorBootstrapped { TEvPlaceRequestIntoPool::TPtr Event; bool CanCreatePool = false; bool DefaultPoolCreated = false; + NKikimrConfig::TWorkloadManagerConfig WorkloadManagerConfig; }; @@ -237,6 +240,63 @@ class TPoolFetcherActor : public TSchemeActorBase { NKikimrProto::TPathID PathId; }; +class TStaticPoolFetcherActor : public NActors::TActorBootstrapped { +public: + TStaticPoolFetcherActor(const TActorId& replyActorId, const TString& databaseId, const TString& poolId, const NKikimrConfig::TWorkloadManagerConfig& workloadManagerConfig) + : ReplyActorId(replyActorId) + , DatabaseId(databaseId) + , PoolId(poolId) + , WorkloadManagerConfig(workloadManagerConfig) + {} + + void Bootstrap() { + if (PoolId == NResourcePool::DEFAULT_POOL_ID) { + NResourcePool::TPoolSettings poolSettings; + poolSettings.ResourceWeight = WorkloadManagerConfig.GetResourceWeight(); + poolSettings.ConcurrentQueryLimit = WorkloadManagerConfig.GetConcurrentQueryLimit(); + poolSettings.QueueSize = WorkloadManagerConfig.GetQueueSize(); + poolSettings.QueryCpuLimitPercentPerNode = WorkloadManagerConfig.GetQueryCpuLimitPercentPerNode(); + poolSettings.QueryMemoryLimitPercentPerNode = WorkloadManagerConfig.GetQueryMemoryLimitPercentPerNode(); + poolSettings.TotalCpuLimitPercentPerNode = WorkloadManagerConfig.GetTotalCpuLimitPercentPerNode(); + poolSettings.DatabaseLoadCpuThreshold = WorkloadManagerConfig.GetDatabaseLoadCpuThreshold(); + Reply(poolSettings); + return; + } + ReplyError(Ydb::StatusIds::BAD_REQUEST, "Unknown static pool " + PoolId + ", please check the database configuration"); + } + + STRICT_STFUNC(StateFunc, + cFunc(TEvents::TEvBootstrap::EventType, Bootstrap); + ) + + TString LogPrefix() const { + return TStringBuilder() << "[TStaticPoolFetcherActor] ActorId: " << SelfId() << ", DatabaseId: " << DatabaseId << ", PoolId: " << PoolId << ", "; + } + +private: + void ReplyError(Ydb::StatusIds::StatusCode status, const TString& message) { + ReplyError(status, {NYql::TIssue(message)}); + } + + void ReplyError(Ydb::StatusIds::StatusCode status, NYql::TIssues issues) { + LOG_W("Failed to fetch static pool info, " << status << ", issues: " << issues.ToOneLineString()); + Send(ReplyActorId, new TEvPrivate::TEvFetchPoolResponse(status, DatabaseId, PoolId, {}, {}, std::move(issues))); + PassAway(); + } + + void Reply(const NResourcePool::TPoolSettings& poolConfig) { + LOG_D("Static Pool info successfully fetched"); + Send(ReplyActorId, new TEvPrivate::TEvFetchPoolResponse(Ydb::StatusIds::SUCCESS, DatabaseId, PoolId, poolConfig, {}, {})); + PassAway(); + } + +private: + const TActorId ReplyActorId; + const TString DatabaseId; + const TString PoolId; + const NKikimrConfig::TWorkloadManagerConfig WorkloadManagerConfig; +}; + class TPoolCreatorActor : public TSchemeActorBase { using TBase = TSchemeActorBase; @@ -571,11 +631,14 @@ class TDatabaseFetcherActor : public TSchemeActorBase { } // anonymous namespace -IActor* CreatePoolResolverActor(TEvPlaceRequestIntoPool::TPtr event, bool defaultPoolExists) { - return new TPoolResolverActor(std::move(event), defaultPoolExists); +IActor* CreatePoolResolverActor(TEvPlaceRequestIntoPool::TPtr event, bool defaultPoolExists, const NKikimrConfig::TWorkloadManagerConfig& workloadManagerConfig) { + return new TPoolResolverActor(std::move(event), defaultPoolExists, workloadManagerConfig); } -IActor* CreatePoolFetcherActor(const TActorId& replyActorId, const TString& databaseId, const TString& poolId, TIntrusiveConstPtr userToken) { +IActor* CreatePoolFetcherActor(const TActorId& replyActorId, const TString& databaseId, const TString& poolId, TIntrusiveConstPtr userToken, const NKikimrConfig::TWorkloadManagerConfig& workloadManagerConfig) { + if (workloadManagerConfig.GetEnabled()) { + return new TStaticPoolFetcherActor(replyActorId, databaseId, poolId, workloadManagerConfig); + } return new TPoolFetcherActor(replyActorId, databaseId, poolId, userToken); } diff --git a/ydb/core/kqp/workload_service/actors/ya.make b/ydb/core/kqp/workload_service/actors/ya.make index 774488a83d6a..1cb4c527b5ae 100644 --- a/ydb/core/kqp/workload_service/actors/ya.make +++ b/ydb/core/kqp/workload_service/actors/ya.make @@ -2,7 +2,7 @@ LIBRARY() SRCS( cpu_load_actors.cpp - pool_handlers_acors.cpp + pool_handlers_actors.cpp scheme_actors.cpp ) diff --git a/ydb/core/kqp/workload_service/kqp_workload_service.cpp b/ydb/core/kqp/workload_service/kqp_workload_service.cpp index d48435d3c9d5..b07999752299 100644 --- a/ydb/core/kqp/workload_service/kqp_workload_service.cpp +++ b/ydb/core/kqp/workload_service/kqp_workload_service.cpp @@ -14,6 +14,7 @@ #include #include +#include #include @@ -66,15 +67,16 @@ class TKqpWorkloadService : public TActorBootstrapped { void Bootstrap() { Become(&TKqpWorkloadService::MainState); - // Subscribe for FeatureFlags + // Subscribe for FeatureFlags and WorkloadManagerConfig Send(NConsole::MakeConfigsDispatcherID(SelfId().NodeId()), new NConsole::TEvConfigsDispatcher::TEvSetConfigSubscriptionRequest({ - (ui32)NKikimrConsole::TConfigItem::FeatureFlagsItem + (ui32)NKikimrConsole::TConfigItem::FeatureFlagsItem, (ui32)NKikimrConsole::TConfigItem::WorkloadManagerConfigItem }), IEventHandle::FlagTrackDelivery); CpuQuotaManager = std::make_unique(Counters.Counters->GetSubgroup("subcomponent", "CpuQuotaManager")); - EnabledResourcePools = AppData()->FeatureFlags.GetEnableResourcePools(); - EnabledResourcePoolsOnServerless = AppData()->FeatureFlags.GetEnableResourcePoolsOnServerless(); + WorkloadManagerConfig = AppData()->WorkloadManagerConfig; + EnabledResourcePools = AppData()->FeatureFlags.GetEnableResourcePools() || WorkloadManagerConfig.GetEnabled(); + EnabledResourcePoolsOnServerless = AppData()->FeatureFlags.GetEnableResourcePoolsOnServerless() || WorkloadManagerConfig.GetEnabled(); EnableResourcePoolsCounters = AppData()->FeatureFlags.GetEnableResourcePoolsCounters(); if (EnabledResourcePools) { InitializeWorkloadService(); @@ -101,8 +103,9 @@ class TKqpWorkloadService : public TActorBootstrapped { void Handle(NConsole::TEvConsole::TEvConfigNotificationRequest::TPtr& ev) { const auto& event = ev->Get()->Record; - EnabledResourcePools = event.GetConfig().GetFeatureFlags().GetEnableResourcePools(); - EnabledResourcePoolsOnServerless = event.GetConfig().GetFeatureFlags().GetEnableResourcePoolsOnServerless(); + WorkloadManagerConfig = event.GetConfig().GetWorkloadManagerConfig(); + EnabledResourcePools = event.GetConfig().GetFeatureFlags().GetEnableResourcePools() || WorkloadManagerConfig.GetEnabled(); + EnabledResourcePoolsOnServerless = event.GetConfig().GetFeatureFlags().GetEnableResourcePoolsOnServerless() || WorkloadManagerConfig.GetEnabled(); EnableResourcePoolsCounters = event.GetConfig().GetFeatureFlags().GetEnableResourcePoolsCounters(); if (EnabledResourcePools) { LOG_I("Resource pools was enanbled"); @@ -556,7 +559,7 @@ class TKqpWorkloadService : public TActorBootstrapped { return &databaseIt->second; } LOG_I("Creating new database state for id " << databaseId); - return &DatabaseToState.insert({databaseId, TDatabaseState{.SelfId = SelfId(), .EnabledResourcePoolsOnServerless = EnabledResourcePoolsOnServerless}}).first->second; + return &DatabaseToState.insert({databaseId, TDatabaseState{.SelfId = SelfId(), .EnabledResourcePoolsOnServerless = EnabledResourcePoolsOnServerless, .WorkloadManagerConfig = WorkloadManagerConfig}}).first->second; } TPoolState* GetOrCreatePoolState(const TString& databaseId, const TString& poolId, const NResourcePool::TPoolSettings& poolConfig) { @@ -604,6 +607,7 @@ class TKqpWorkloadService : public TActorBootstrapped { bool EnableResourcePoolsCounters = false; bool ServiceInitialized = false; bool IdleChecksStarted = false; + NKikimrConfig::TWorkloadManagerConfig WorkloadManagerConfig; ETablesCreationStatus TablesCreationStatus = ETablesCreationStatus::Cleanup; std::unordered_set PendingHandlers; // DatabaseID/PoolID diff --git a/ydb/core/kqp/workload_service/kqp_workload_service_impl.h b/ydb/core/kqp/workload_service/kqp_workload_service_impl.h index a2950bae88e6..71cc5b5ff0f6 100644 --- a/ydb/core/kqp/workload_service/kqp_workload_service_impl.h +++ b/ydb/core/kqp/workload_service/kqp_workload_service_impl.h @@ -18,6 +18,7 @@ constexpr TDuration IDLE_DURATION = TDuration::Seconds(60); struct TDatabaseState { TActorId SelfId; bool& EnabledResourcePoolsOnServerless; + NKikimrConfig::TWorkloadManagerConfig& WorkloadManagerConfig; std::vector PendingRequersts = {}; std::unordered_set PendingSessionIds = {}; @@ -33,7 +34,7 @@ struct TDatabaseState { const TString& poolId = ev->Get()->PoolId; auto& subscribers = PendingSubscriptions[poolId]; if (subscribers.empty()) { - TActivationContext::Register(CreatePoolFetcherActor(SelfId, ev->Get()->DatabaseId, poolId, nullptr)); + TActivationContext::Register(CreatePoolFetcherActor(SelfId, ev->Get()->DatabaseId, poolId, nullptr, WorkloadManagerConfig)); } subscribers.emplace(ev->Sender); @@ -103,7 +104,7 @@ struct TDatabaseState { } for (auto& ev : PendingRequersts) { - TActivationContext::Register(CreatePoolResolverActor(std::move(ev), HasDefaultPool)); + TActivationContext::Register(CreatePoolResolverActor(std::move(ev), HasDefaultPool, WorkloadManagerConfig)); } PendingRequersts.clear(); } diff --git a/ydb/core/kqp/workload_service/ut/common/kqp_workload_service_ut_common.cpp b/ydb/core/kqp/workload_service/ut/common/kqp_workload_service_ut_common.cpp index 739be4e8c006..d1df2af4687d 100644 --- a/ydb/core/kqp/workload_service/ut/common/kqp_workload_service_ut_common.cpp +++ b/ydb/core/kqp/workload_service/ut/common/kqp_workload_service_ut_common.cpp @@ -256,6 +256,7 @@ class TWorkloadServiceYdbSetup : public IYdbSetup { appConfig.MutableFeatureFlags()->SetEnableExternalDataSourcesOnServerless(Settings_.EnableExternalDataSourcesOnServerless_); appConfig.MutableFeatureFlags()->SetEnableExternalDataSources(true); appConfig.MutableFeatureFlags()->SetEnableResourcePoolsCounters(true); + *appConfig.MutableWorkloadManagerConfig() = Settings_.WorkloadManagerConfig_; appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("ObjectStorage"); return appConfig; diff --git a/ydb/core/kqp/workload_service/ut/common/kqp_workload_service_ut_common.h b/ydb/core/kqp/workload_service/ut/common/kqp_workload_service_ut_common.h index f679d5dc82f4..ad72d2f04de9 100644 --- a/ydb/core/kqp/workload_service/ut/common/kqp_workload_service_ut_common.h +++ b/ydb/core/kqp/workload_service/ut/common/kqp_workload_service_ut_common.h @@ -11,6 +11,8 @@ #include #include +#include + namespace NKikimr::NKqp::NWorkload { @@ -73,6 +75,8 @@ struct TYdbSetupSettings { FLUENT_SETTING_DEFAULT(bool, EnableResourcePoolsOnServerless, false); FLUENT_SETTING_DEFAULT(bool, EnableMetadataObjectsOnServerless, true); FLUENT_SETTING_DEFAULT(bool, EnableExternalDataSourcesOnServerless, true); + FLUENT_SETTING(NKikimrConfig::TWorkloadManagerConfig, WorkloadManagerConfig); + // Default pool settings FLUENT_SETTING_DEFAULT(TString, PoolId, "sample_pool_id"); diff --git a/ydb/core/kqp/workload_service/ut/kqp_workload_service_actors_ut.cpp b/ydb/core/kqp/workload_service/ut/kqp_workload_service_actors_ut.cpp index 7d9db86cccae..ebf553926f23 100644 --- a/ydb/core/kqp/workload_service/ut/kqp_workload_service_actors_ut.cpp +++ b/ydb/core/kqp/workload_service/ut/kqp_workload_service_actors_ut.cpp @@ -19,7 +19,7 @@ TEvPrivate::TEvFetchPoolResponse::TPtr FetchPool(TIntrusivePtr ydb, c auto userToken = MakeIntrusive(userSID, TVector{}); userToken->SaveSerializationInfo(); - runtime->Register(CreatePoolFetcherActor(edgeActor, settings.DomainName_, poolId ? poolId : settings.PoolId_, userToken)); + runtime->Register(CreatePoolFetcherActor(edgeActor, settings.DomainName_, poolId ? poolId : settings.PoolId_, userToken, NKikimrConfig::TWorkloadManagerConfig{})); return runtime->GrabEdgeEvent(edgeActor, FUTURE_WAIT_TIMEOUT); } diff --git a/ydb/core/kqp/workload_service/ut/kqp_workload_service_ut.cpp b/ydb/core/kqp/workload_service/ut/kqp_workload_service_ut.cpp index 374d54f55b4a..5470191eaa11 100644 --- a/ydb/core/kqp/workload_service/ut/kqp_workload_service_ut.cpp +++ b/ydb/core/kqp/workload_service/ut/kqp_workload_service_ut.cpp @@ -625,6 +625,69 @@ Y_UNIT_TEST_SUITE(ResourcePoolsDdl) { ydb->WaitPoolAccess(userSID, NACLib::EAccessRights::SelectRow, poolId); TSampleQueries::TSelect42::CheckResult(ydb->ExecuteQuery(TSampleQueries::TSelect42::Query, settings)); } + + Y_UNIT_TEST(TestWorkloadConfigOnServerless) { + NKikimrConfig::TWorkloadManagerConfig config; + config.SetEnabled(true); + config.SetConcurrentQueryLimit(1); + config.SetQueueSize(0); + config.SetDatabaseLoadCpuThreshold(-1); + config.SetQueryCpuLimitPercentPerNode(-1); + config.SetQueryMemoryLimitPercentPerNode(-1); + config.SetTotalCpuLimitPercentPerNode(-1); + auto ydb = TYdbSetupSettings() + .CreateSampleTenants(true) + .EnableResourcePoolsOnServerless(false) + .EnableResourcePools(false) + .WorkloadManagerConfig(config) + .Create(); + + const auto& sharedTenant = ydb->GetSettings().GetSharedTenantName(); + const auto& serverlessTenant = ydb->GetSettings().GetServerlessTenantName(); + auto settings = TQueryRunnerSettings() + .PoolId("") + .Database(serverlessTenant) + .NodeIndex(1); + + auto hangingRequest = ydb->ExecuteQueryAsync(TSampleQueries::TSelect42::Query, settings.HangUpDuringExecution(true)); + ydb->WaitQueryExecution(hangingRequest); + + settings.HangUpDuringExecution(false); + + { // Rejected result + auto result = ydb->ExecuteQuery(TSampleQueries::TSelect42::Query, settings); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::OVERLOADED, result.GetIssues().ToOneLineString()); + UNIT_ASSERT_STRING_CONTAINS(result.GetIssues().ToString(), TStringBuilder() << "Request was rejected, number of local pending requests is 1, number of global delayed/running requests is 1, sum of them is larger than allowed limit 0 (including concurrent query limit 1) for pool default"); + } + + { // Check tables + auto result = ydb->ExecuteQuery(R"( + SELECT * FROM `.metadata/workload_manager/running_requests` + )", settings.PoolId(NResourcePool::DEFAULT_POOL_ID).Database(ydb->GetSettings().GetSharedTenantName())); + TSampleQueries::CheckSuccess(result); + + NYdb::TResultSetParser resultSet(result.GetResultSet(0)); + { + UNIT_ASSERT_C(resultSet.TryNextRow(), "Unexpected row count"); + + const auto& databaseId = resultSet.ColumnParser("database").GetOptionalUtf8(); + UNIT_ASSERT_C(databaseId, "Unexpected database response"); + + UNIT_ASSERT_VALUES_EQUAL_C(*databaseId, ydb->FetchDatabase(sharedTenant)->Get()->DatabaseId, "Unexpected database id"); + } + { + UNIT_ASSERT_C(resultSet.TryNextRow(), "Unexpected row count"); + + const auto& databaseId = resultSet.ColumnParser("database").GetOptionalUtf8(); + UNIT_ASSERT_C(databaseId, "Unexpected database response"); + + UNIT_ASSERT_VALUES_EQUAL_C(*databaseId, ydb->FetchDatabase(serverlessTenant)->Get()->DatabaseId, "Unexpected database id"); + } + } + + ydb->ContinueQueryExecution(hangingRequest); + TSampleQueries::TSelect42::CheckResult(hangingRequest.GetResult()); + } } Y_UNIT_TEST_SUITE(ResourcePoolClassifiersDdl) { diff --git a/ydb/core/mind/bscontroller/bsc.cpp b/ydb/core/mind/bscontroller/bsc.cpp index 3ab5cdc7b117..02209c112e7d 100644 --- a/ydb/core/mind/bscontroller/bsc.cpp +++ b/ydb/core/mind/bscontroller/bsc.cpp @@ -463,7 +463,8 @@ void TBlobStorageController::Handle(TEvBlobStorage::TEvControllerDistconfRequest // commit it Execute(CreateTxCommitConfig(std::move(yamlConfig), std::make_optional(std::move(storageYaml)), std::nullopt, - expectedStorageYamlConfigVersion, std::exchange(h, {}), std::nullopt)); + expectedStorageYamlConfigVersion, std::exchange(h, {}), std::nullopt, + TAuditLogInfo{record.GetPeerName(), NACLib::TUserToken{record.GetUserToken()}})); break; } diff --git a/ydb/core/mind/bscontroller/bsc_audit.cpp b/ydb/core/mind/bscontroller/bsc_audit.cpp new file mode 100644 index 000000000000..c111f8a9cda2 --- /dev/null +++ b/ydb/core/mind/bscontroller/bsc_audit.cpp @@ -0,0 +1,35 @@ +#include "bsc_audit.h" + +#include +#include + +namespace NKikimr::NBsController { + +static const TString COMPONENT_NAME = "bsc"; +static const TString EMPTY_VALUE = "{none}"; + +void AuditLogCommitConfigTransaction( + const TString& peer, + const TString& userSID, + const TString& sanitizedToken, + const TString& oldConfig, + const TString& newConfig, + const TString& reason, + bool success) +{ + auto peerName = NKikimr::NAddressClassifier::ExtractAddress(peer); + + AUDIT_LOG( + AUDIT_PART("component", COMPONENT_NAME) + AUDIT_PART("remote_address", (!peerName.empty() ? peerName : EMPTY_VALUE)) + AUDIT_PART("subject", (!userSID.empty() ? userSID : EMPTY_VALUE)) + AUDIT_PART("sanitized_token", (!sanitizedToken.empty() ? sanitizedToken : EMPTY_VALUE)) + AUDIT_PART("status", TString(success ? "SUCCESS" : "ERROR")) + AUDIT_PART("reason", reason, !reason.empty()) + AUDIT_PART("operation", TString("REPLACE CONFIG")) + AUDIT_PART("old_config", oldConfig) + AUDIT_PART("new_config", newConfig) + ); +} + +} // namespace NKikimr::NBsController diff --git a/ydb/core/mind/bscontroller/bsc_audit.h b/ydb/core/mind/bscontroller/bsc_audit.h new file mode 100644 index 000000000000..50245148150d --- /dev/null +++ b/ydb/core/mind/bscontroller/bsc_audit.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace NKikimr::NBsController { + +void AuditLogCommitConfigTransaction( + const TString& peer, + const TString& userSID, + const TString& sanitizedToken, + const TString& oldConfig, + const TString& newConfig, + const TString& reason, + bool success); + +} // namespace NKikimr::NBsController diff --git a/ydb/core/mind/bscontroller/commit_config.cpp b/ydb/core/mind/bscontroller/commit_config.cpp index fca8960d51a5..ad2322d3c3bd 100644 --- a/ydb/core/mind/bscontroller/commit_config.cpp +++ b/ydb/core/mind/bscontroller/commit_config.cpp @@ -1,5 +1,6 @@ #include "impl.h" #include "console_interaction.h" +#include "bsc_audit.h" #include #include #include @@ -16,6 +17,7 @@ namespace NKikimr::NBsController { std::optional ExpectedStorageYamlConfigVersion; std::unique_ptr Handle; std::optional SwitchEnableConfigV2; + std::optional AuditLogInfo; ui64 GenerationOnStart = 0; TString FingerprintOnStart; @@ -25,7 +27,7 @@ namespace NKikimr::NBsController { std::optional>&& storageYamlConfig, std::optional&& storageConfig, std::optional expectedStorageYamlConfigVersion, std::unique_ptr handle, - std::optional switchEnableConfigV2) + std::optional switchEnableConfigV2, std::optional&& auditLogInfo) : TTransactionBase(controller) , YamlConfig(std::move(yamlConfig)) , StorageYamlConfig(std::move(storageYamlConfig)) @@ -33,6 +35,7 @@ namespace NKikimr::NBsController { , ExpectedStorageYamlConfigVersion(expectedStorageYamlConfigVersion) , Handle(std::move(handle)) , SwitchEnableConfigV2(switchEnableConfigV2) + , AuditLogInfo(std::move(auditLogInfo)) {} TTxType GetTxType() const override { return NBlobStorageController::TXTYPE_COMMIT_CONFIG; } @@ -68,6 +71,34 @@ namespace NKikimr::NBsController { LOG_ALERT_S(ctx, NKikimrServices::BS_CONTROLLER, "Storage config changed"); Y_DEBUG_ABORT("Storage config changed"); } + + if (AuditLogInfo) { + TStringBuilder oldConfig; + if (Self->YamlConfig) { + oldConfig << GetSingleConfigYaml(*Self->YamlConfig); + } + if (Self->StorageYamlConfig) { + oldConfig << *Self->StorageYamlConfig; + } + + TStringBuilder newConfig; + if (YamlConfig) { + newConfig << GetSingleConfigYaml(*YamlConfig); + } + if (StorageYamlConfig && *StorageYamlConfig) { + newConfig << **StorageYamlConfig; + } + + AuditLogCommitConfigTransaction( + /* peer = */ AuditLogInfo->PeerName, + /* userSID = */ AuditLogInfo->UserToken.GetUserSID(), + /* sanitizedToken = */ AuditLogInfo->UserToken.GetSanitizedToken(), + /* oldConfig = */ oldConfig, + /* newConfig = */ newConfig, + /* reason = */ {}, + /* success = */ true); + } + if (StorageConfig) { Self->StorageConfig = std::move(*StorageConfig); Self->ApplyStorageConfig(true); @@ -136,9 +167,9 @@ namespace NKikimr::NBsController { std::optional>&& storageYamlConfig, std::optional&& storageConfig, std::optional expectedStorageYamlConfigVersion, std::unique_ptr handle, - std::optional switchEnableConfigV2) { + std::optional switchEnableConfigV2, std::optional&& auditLogInfo) { return new TTxCommitConfig(this, std::move(yamlConfig), std::move(storageYamlConfig), std::move(storageConfig), - expectedStorageYamlConfigVersion, std::move(handle), switchEnableConfigV2); + expectedStorageYamlConfigVersion, std::move(handle), switchEnableConfigV2, std::move(auditLogInfo)); } } // namespace NKikimr::NBsController diff --git a/ydb/core/mind/bscontroller/console_interaction.cpp b/ydb/core/mind/bscontroller/console_interaction.cpp index a506e0cfac81..a28825b6fc52 100644 --- a/ydb/core/mind/bscontroller/console_interaction.cpp +++ b/ydb/core/mind/bscontroller/console_interaction.cpp @@ -105,7 +105,8 @@ namespace NKikimr::NBsController { TYamlConfig yamlConfig(std::move(yaml), version, std::move(yamlReturnedByFetch)); Self.Execute(Self.CreateTxCommitConfig(std::move(yamlConfig), std::nullopt, - std::move(storageConfig), std::nullopt, nullptr, std::nullopt)); + std::move(storageConfig), std::nullopt, nullptr, std::nullopt, + std::nullopt)); CommitInProgress = true; } } catch (const std::exception& ex) { @@ -240,6 +241,9 @@ namespace NKikimr::NBsController { ClientId = ev->Sender; ++ExpectedValidationTimeoutCookie; + // audit log settings + AuditLogInfo.emplace(record.GetPeerName(), NACLib::TUserToken{record.GetUserToken()}); + if (!Self.ConfigLock.empty() || Self.SelfManagementEnabled) { return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::OngoingCommit, "configuration is locked by distconf"); @@ -517,7 +521,8 @@ namespace NKikimr::NBsController { } Self.Execute(Self.CreateTxCommitConfig(std::move(yamlConfig), std::exchange(PendingStorageYamlConfig, {}), - std::move(storageConfig), expectedStorageYamlConfigVersion, nullptr, SwitchEnableConfigV2)); + std::move(storageConfig), expectedStorageYamlConfigVersion, nullptr, SwitchEnableConfigV2, + std::move(AuditLogInfo))); CommitInProgress = true; PendingYamlConfig.reset(); } catch (const TExError& error) { diff --git a/ydb/core/mind/bscontroller/console_interaction.h b/ydb/core/mind/bscontroller/console_interaction.h index 03a02425756b..100b83e782ab 100644 --- a/ydb/core/mind/bscontroller/console_interaction.h +++ b/ydb/core/mind/bscontroller/console_interaction.h @@ -49,6 +49,7 @@ namespace NKikimr::NBsController { bool CommitInProgress = false; std::optional SwitchEnableConfigV2; TEvBlobStorage::TEvControllerReplaceConfigRequest::TPtr PendingReplaceRequest; + std::optional AuditLogInfo; std::optional PendingYamlConfig; bool AllowUnknownFields = false; @@ -62,5 +63,4 @@ namespace NKikimr::NBsController { void IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::EStatus status, std::optional errorReason = std::nullopt, bool disabledConfigV2 = false); }; - } diff --git a/ydb/core/mind/bscontroller/defs.h b/ydb/core/mind/bscontroller/defs.h index f3755328ee50..a66843b52189 100644 --- a/ydb/core/mind/bscontroller/defs.h +++ b/ydb/core/mind/bscontroller/defs.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include diff --git a/ydb/core/mind/bscontroller/impl.h b/ydb/core/mind/bscontroller/impl.h index b102e601a431..8bfea0ec58fc 100644 --- a/ydb/core/mind/bscontroller/impl.h +++ b/ydb/core/mind/bscontroller/impl.h @@ -1986,12 +1986,18 @@ class TBlobStorageController : public TActor, public TTa ITransaction* CreateTxMigrate(); ITransaction* CreateTxLoadEverything(); ITransaction* CreateTxUpdateSeenOperational(TVector groups); + + struct TAuditLogInfo { + TString PeerName; + const NACLib::TUserToken UserToken; + }; + ITransaction* CreateTxCommitConfig(std::optional&& yamlConfig, std::optional>&& storageYamlConfig, std::optional&& storageConfig, std::optional expectedStorageYamlConfigVersion, std::unique_ptr handle, - std::optional switchEnableConfigV2); + std::optional switchEnableConfigV2, std::optional&& auditLogInfo); struct TVDiskAvailabilityTiming { TVSlotId VSlotId; diff --git a/ydb/core/mind/bscontroller/ya.make b/ydb/core/mind/bscontroller/ya.make index da444bc5fcdb..c0b8bc96857e 100644 --- a/ydb/core/mind/bscontroller/ya.make +++ b/ydb/core/mind/bscontroller/ya.make @@ -3,6 +3,8 @@ LIBRARY() SRCS( bsc.cpp bsc.h + bsc_audit.h + bsc_audit.cpp cmds_box.cpp cmds_drive_status.cpp cmds_host_config.cpp diff --git a/ydb/core/mind/bscontroller/yaml_config_helpers.h b/ydb/core/mind/bscontroller/yaml_config_helpers.h index 21610b3bd545..d65b0e6f2f98 100644 --- a/ydb/core/mind/bscontroller/yaml_config_helpers.h +++ b/ydb/core/mind/bscontroller/yaml_config_helpers.h @@ -57,6 +57,10 @@ inline ui64 GetSingleConfigHash(const TYamlConfig& config) { return NYaml::GetConfigHash(std::get<0>(config)); } +inline TString GetSingleConfigYaml(const TYamlConfig& config) { + return std::get<0>(config); +} + } // namespace NBsController } // namespace NKikimr diff --git a/ydb/core/mind/hive/boot_queue.cpp b/ydb/core/mind/hive/boot_queue.cpp index edf14b988535..29cc4a4f31e8 100644 --- a/ydb/core/mind/hive/boot_queue.cpp +++ b/ydb/core/mind/hive/boot_queue.cpp @@ -17,20 +17,54 @@ void TBootQueue::AddToBootQueue(TBootQueueRecord record) { } TBootQueue::TBootQueueRecord TBootQueue::PopFromBootQueue() { - TBootQueueRecord record = BootQueue.top(); - BootQueue.pop(); + TQueue& currentQueue = GetCurrentQueue(); + TBootQueueRecord record = currentQueue.top(); + currentQueue.pop(); + if (ProcessWaitQueue) { + NextFromWaitQueue = !NextFromWaitQueue; + } return record; } void TBootQueue::AddToWaitQueue(TBootQueueRecord record) { - WaitQueue.emplace_back(record); + WaitQueue.push(record); +} + +void TBootQueue::IncludeWaitQueue() { + ProcessWaitQueue = true; } -void TBootQueue::MoveFromWaitQueueToBootQueue() { - for (TBootQueueRecord record : WaitQueue) { - AddToBootQueue(record); +void TBootQueue::ExcludeWaitQueue() { + ProcessWaitQueue = false; +} + +bool TBootQueue::Empty() const { + if (ProcessWaitQueue) { + return BootQueue.empty() && WaitQueue.empty(); + } else { + return BootQueue.empty(); + } +} + +size_t TBootQueue::Size() const { + if (ProcessWaitQueue) { + return BootQueue.size() + WaitQueue.size(); + } else { + return BootQueue.size(); + } +} + +TBootQueue::TQueue& TBootQueue::GetCurrentQueue() { + if (BootQueue.empty()) { + return WaitQueue; + } + if (WaitQueue.empty()) { + return BootQueue; + } + if (ProcessWaitQueue && NextFromWaitQueue) { + return WaitQueue; } - WaitQueue.clear(); + return BootQueue; } } diff --git a/ydb/core/mind/hive/boot_queue.h b/ydb/core/mind/hive/boot_queue.h index 80c919f5a2e0..e0d345b121a6 100644 --- a/ydb/core/mind/hive/boot_queue.h +++ b/ydb/core/mind/hive/boot_queue.h @@ -52,18 +52,30 @@ struct TBootQueue { static_assert(sizeof(TBootQueueRecord) <= 24); - std::priority_queue> BootQueue; - std::deque WaitQueue; // tablets from BootQueue waiting for new nodes + using TQueue = TPriorityQueue; + TQueue BootQueue; + TQueue WaitQueue; // tablets from BootQueue waiting for new nodes +private: + bool ProcessWaitQueue = false; + bool NextFromWaitQueue = false; + +public: void AddToBootQueue(TBootQueueRecord record); TBootQueueRecord PopFromBootQueue(); void AddToWaitQueue(TBootQueueRecord record); - void MoveFromWaitQueueToBootQueue(); + void IncludeWaitQueue(); + void ExcludeWaitQueue(); + bool Empty() const; + size_t Size() const; template void EmplaceToBootQueue(Args&&... args) { BootQueue.emplace(args...); } + +private: + TQueue& GetCurrentQueue(); }; } diff --git a/ydb/core/mind/hive/hive_events.h b/ydb/core/mind/hive/hive_events.h index c768d1dedc14..6eac8909107e 100644 --- a/ydb/core/mind/hive/hive_events.h +++ b/ydb/core/mind/hive/hive_events.h @@ -51,7 +51,9 @@ struct TEvPrivate { {} }; - struct TEvProcessBootQueue : TEventLocal {}; + struct TEvProcessBootQueue : TEventLocal { + bool ProcessWaitQueue = false; // Only for use in tests + }; struct TEvPostponeProcessBootQueue : TEventLocal {}; diff --git a/ydb/core/mind/hive/hive_impl.cpp b/ydb/core/mind/hive/hive_impl.cpp index b6941692ff86..ad4ebe60464e 100644 --- a/ydb/core/mind/hive/hive_impl.cpp +++ b/ydb/core/mind/hive/hive_impl.cpp @@ -223,7 +223,7 @@ void THive::ExecuteProcessBootQueue(NIceDb::TNiceDb&, TSideEffects& sideEffects) THPTimer bootQueueProcessingTimer; if (ProcessWaitQueueScheduled) { BLOG_D("Handle ProcessWaitQueue (size: " << BootQueue.WaitQueue.size() << ")"); - BootQueue.MoveFromWaitQueueToBootQueue(); + BootQueue.IncludeWaitQueue(); ProcessWaitQueueScheduled = false; } ProcessBootQueueScheduled = false; @@ -231,7 +231,9 @@ void THive::ExecuteProcessBootQueue(NIceDb::TNiceDb&, TSideEffects& sideEffects) ui64 tabletsStarted = 0; TInstant postponedStart; TStackVec delayedTablets; - while (!BootQueue.BootQueue.empty() && processedItems < GetMaxBootBatchSize()) { + std::vector waitingTablets; + waitingTablets.reserve(std::min(BootQueue.Size(), GetMaxBootBatchSize())); + while (!BootQueue.Empty() && processedItems < GetMaxBootBatchSize()) { TBootQueue::TBootQueueRecord record = BootQueue.PopFromBootQueue(); BLOG_TRACE("Tablet " << record.TabletId << "." << record.FollowerId << " has priority " << record.Priority); ++processedItems; @@ -260,7 +262,7 @@ void THive::ExecuteProcessBootQueue(NIceDb::TNiceDb&, TSideEffects& sideEffects) sideEffects.Send(actorToNotify, new TEvPrivate::TEvRestartComplete(tablet->GetFullTabletId(), "boot delay")); } tablet->ActorsToNotifyOnRestart.clear(); - BootQueue.AddToWaitQueue(record); // waiting for new node + waitingTablets.push_back(record); // waiting for new node tablet->InWaitQueue = true; continue; } @@ -280,10 +282,16 @@ void THive::ExecuteProcessBootQueue(NIceDb::TNiceDb&, TSideEffects& sideEffects) delayedTablets.push_back(record); } } + if (waitingTablets.size() == processedItems || BootQueue.WaitQueue.empty()) { + BootQueue.ExcludeWaitQueue(); + } for (TBootQueue::TBootQueueRecord record : delayedTablets) { record.Priority -= 1; BootQueue.AddToBootQueue(record); } + for (auto& record : waitingTablets) { + BootQueue.AddToWaitQueue(record); + } if (TabletCounters != nullptr) { UpdateCounterBootQueueSize(BootQueue.BootQueue.size()); TabletCounters->Simple()[NHive::COUNTER_WAITQUEUE_SIZE].Set(BootQueue.WaitQueue.size()); @@ -301,7 +309,7 @@ void THive::ExecuteProcessBootQueue(NIceDb::TNiceDb&, TSideEffects& sideEffects) BLOG_D("ProcessBootQueue - BootQueue throttling (size: " << BootQueue.BootQueue.size() << ")"); return; } - if (processedItems == GetMaxBootBatchSize()) { + if (processedItems == GetMaxBootBatchSize() && !BootQueue.Empty()) { BLOG_D("ProcessBootQueue - rescheduling"); ProcessBootQueue(); } else if (postponedStart > now) { @@ -316,8 +324,11 @@ void THive::HandleInit(TEvPrivate::TEvProcessBootQueue::TPtr&) { Schedule(TDuration::Seconds(1), new TEvPrivate::TEvProcessBootQueue()); } -void THive::Handle(TEvPrivate::TEvProcessBootQueue::TPtr&) { +void THive::Handle(TEvPrivate::TEvProcessBootQueue::TPtr& ev) { BLOG_TRACE("ProcessBootQueue - executing"); + if (ev->Get()->ProcessWaitQueue) { + ProcessWaitQueue(); + } Execute(CreateProcessBootQueue()); } @@ -2065,9 +2076,18 @@ void THive::Handle(TEvHive::TEvRequestHiveNodeStats::TPtr& ev) { } } } else { + std::optional filterObjectDomain; + if (request.HasFilterTabletsByObjectDomain()) { + filterObjectDomain = TSubDomainKey(request.GetFilterTabletsByObjectDomain()); + } for (const auto& [state, set] : node.Tablets) { std::vector tabletTypeToCount; for (const TTabletInfo* tablet : set) { + if (filterObjectDomain) { + if (tablet->NodeFilter.ObjectDomain != *filterObjectDomain) { + continue; + } + } TTabletTypes::EType type = tablet->GetTabletType(); if (static_cast(type) >= tabletTypeToCount.size()) { tabletTypeToCount.resize(type + 1); @@ -2244,14 +2264,14 @@ TResourceRawValues THive::GetDefaultResourceInitialMaximumValues() { } void THive::ProcessTabletBalancer() { - if (!ProcessTabletBalancerScheduled && !ProcessTabletBalancerPostponed && BootQueue.BootQueue.empty()) { + if (!ProcessTabletBalancerScheduled && !ProcessTabletBalancerPostponed && BootQueue.Empty()) { Schedule(GetBalancerCooldown(LastBalancerTrigger), new TEvPrivate::TEvProcessTabletBalancer()); ProcessTabletBalancerScheduled = true; } } void THive::ProcessStorageBalancer() { - if (!ProcessStorageBalancerScheduled && BootQueue.BootQueue.empty()) { + if (!ProcessStorageBalancerScheduled && BootQueue.Empty()) { Schedule(GetBalancerCooldown(EBalancerType::Storage), new TEvPrivate::TEvProcessStorageBalancer()); ProcessStorageBalancerScheduled = true; } @@ -2503,10 +2523,7 @@ void THive::UpdateTotalResourceValues( TInstant now = TInstant::Now(); if (LastResourceChangeReaction + GetResourceChangeReactionPeriod() < now) { - // in case we had overloaded nodes - if (!BootQueue.WaitQueue.empty()) { - ProcessWaitQueue(); - } else if (!BootQueue.BootQueue.empty()) { + if (!BootQueue.Empty()) { ProcessBootQueue(); } ProcessTabletBalancer(); @@ -3538,7 +3555,7 @@ void THive::Handle(TEvPrivate::TEvUpdateFollowers::TPtr&) { void THive::MakeScaleRecommendation() { BLOG_D("[MSR] Started"); - + if (AreWeRootHive()) { return; } diff --git a/ydb/core/mind/hive/hive_impl.h b/ydb/core/mind/hive/hive_impl.h index 56cc212260ab..7020ac6ea3ce 100644 --- a/ydb/core/mind/hive/hive_impl.h +++ b/ydb/core/mind/hive/hive_impl.h @@ -1003,7 +1003,7 @@ TTabletInfo* FindTabletEvenInDeleting(TTabletId tabletId, TFollowerId followerId } ui64 GetNodeRestartsForPenalty() const { - return CurrentConfig.GetNodeRestartsForPenalty(); + return CurrentConfig.GetNodeRestartsForPenalty() ?: Max(); } static void ActualizeRestartStatistics(google::protobuf::RepeatedField& restartTimestamps, ui64 barrier); diff --git a/ydb/core/mind/hive/hive_impl_ut.cpp b/ydb/core/mind/hive/hive_impl_ut.cpp index fb5a5b718f08..70b764fbd7fc 100644 --- a/ydb/core/mind/hive/hive_impl_ut.cpp +++ b/ydb/core/mind/hive/hive_impl_ut.cpp @@ -58,14 +58,29 @@ Y_UNIT_TEST_SUITE(THiveImplTest) { timer.Reset(); double maxP = 100; + std::vector records; + records.reserve(NUM_TABLETS); + unsigned i = 0; - while (!bootQueue.BootQueue.empty()) { + while (!bootQueue.Empty()) { auto record = bootQueue.PopFromBootQueue(); UNIT_ASSERT(record.Priority <= maxP); maxP = record.Priority; - auto itTablet = tablets.find(record.TabletId); - if (itTablet != tablets.end()) { - bootQueue.AddToWaitQueue(itTablet->second); + UNIT_ASSERT(tablets.contains(record.TabletId)); + records.push_back(record); + if (++i == NUM_TABLETS / 2) { + // to test both modes + bootQueue.IncludeWaitQueue(); + } + } + bootQueue.ExcludeWaitQueue(); + + i = 0; + for (auto& record : records) { + if (++i % 3 == 0) { + bootQueue.AddToBootQueue(record); + } else { + bootQueue.AddToWaitQueue(record); } } @@ -81,7 +96,11 @@ Y_UNIT_TEST_SUITE(THiveImplTest) { timer.Reset(); - bootQueue.MoveFromWaitQueueToBootQueue(); + bootQueue.IncludeWaitQueue(); + while (!bootQueue.Empty()) { + bootQueue.PopFromBootQueue(); + } + bootQueue.ExcludeWaitQueue(); passed = timer.Get().SecondsFloat(); Ctest << "Move = " << passed << Endl; diff --git a/ydb/core/mind/hive/hive_ut.cpp b/ydb/core/mind/hive/hive_ut.cpp index 81646c75459d..cf151cac924f 100644 --- a/ydb/core/mind/hive/hive_ut.cpp +++ b/ydb/core/mind/hive/hive_ut.cpp @@ -645,6 +645,14 @@ Y_UNIT_TEST_SUITE(THiveTest) { runtime.SendToPipe(hiveTablet, senderB, new TEvHive::TEvReassignTabletSpace(tabletId, channels), 0, GetPipeConfigWithRetries()); } + TActorId GetHiveActor(TTestActorRuntime& runtime, ui64 hiveTablet) { + TActorId senderB = runtime.AllocateEdgeActor(0); + runtime.SendToPipe(hiveTablet, senderB, new TEvHive::TEvTabletMetrics, 0, GetPipeConfigWithRetries()); + TAutoPtr handle; + runtime.GrabEdgeEventRethrow(handle); + return handle->Sender; + } + void MakeSureTabletIsDown(TTestActorRuntime &runtime, ui64 tabletId, ui32 nodeIndex) { TActorId sender = runtime.AllocateEdgeActor(nodeIndex); runtime.ConnectToPipe(tabletId, sender, nodeIndex, NTabletPipe::TClientConfig()); @@ -3526,7 +3534,8 @@ Y_UNIT_TEST_SUITE(THiveTest) { TVector tabletIds; const ui64 hiveTablet = MakeDefaultHiveID(); const ui64 testerTablet = MakeTabletID(false, 1); - CreateTestBootstrapper(runtime, CreateTestTabletInfo(hiveTablet, TTabletTypes::Hive), &CreateDefaultHive); + const TActorId bootstrapper = CreateTestBootstrapper(runtime, CreateTestTabletInfo(hiveTablet, TTabletTypes::Hive), &CreateDefaultHive); + runtime.EnableScheduleForActor(bootstrapper); { TDispatchOptions options; options.FinalEvents.emplace_back(TEvLocal::EvSyncTablets, runtime.GetNodeCount()); @@ -7156,6 +7165,43 @@ Y_UNIT_TEST_SUITE(THiveTest) { } } + Y_UNIT_TEST(TestBootProgress) { + TTestBasicRuntime runtime(1, false); + Setup(runtime, true, 3, [](TAppPrepare& app) { + app.HiveConfig.SetMaxBootBatchSize(1); + app.HiveConfig.SetResourceChangeReactionPeriod(0); + }); + const ui64 hiveTablet = MakeDefaultHiveID(); + const ui64 testerTablet = MakeTabletID(false, 1); + const TActorId bootstrapper = CreateTestBootstrapper(runtime, CreateTestTabletInfo(hiveTablet, TTabletTypes::Hive), &CreateDefaultHive); + runtime.EnableScheduleForActor(bootstrapper); + { + TDispatchOptions options; + options.FinalEvents.emplace_back(TEvLocal::EvSyncTablets, runtime.GetNodeCount()); + runtime.DispatchEvents(options, TDuration::Zero()); + } + for (int i = 0; i < 5; ++i) { + THolder ev(new TEvHive::TEvCreateTablet(testerTablet, 100500 + i, TTabletTypes::Hive, BINDED_CHANNELS)); + ev->Record.AddAllowedDomains(); + ev->Record.MutableAllowedDomains(0)->SetSchemeShard(52); // garbage domain id - these tablets will never boot + ev->Record.MutableAllowedDomains(0)->SetPathId(42); + SendCreateTestTablet(runtime, hiveTablet, testerTablet, std::move(ev), 0, false); + } + TActorId hiveActor = GetHiveActor(runtime, hiveTablet); + // Simulate a situation when wait queue is constantly processed + // this could happen e. g. when nodes are often restarting + // (previously it would happen all the time because of metric updates) + auto handler = runtime.AddObserver([=](auto&& ev) { + if (ev->Recipient == hiveActor) { + ev->Get()->ProcessWaitQueue = true; + } + }); + THolder ev(new TEvHive::TEvCreateTablet(testerTablet, 100505, TTabletTypes::Dummy, BINDED_CHANNELS)); + auto tabletId = SendCreateTestTablet(runtime, hiveTablet, testerTablet, std::move(ev), 0, false); + MakeSureTabletIsUp(runtime, tabletId, 0); + + } + Y_UNIT_TEST(TestStopTenant) { TTestBasicRuntime runtime(2, false); Setup(runtime, true); diff --git a/ydb/core/mind/hive/monitoring.cpp b/ydb/core/mind/hive/monitoring.cpp index e259a9e7aef9..5c0e1a7af93c 100644 --- a/ydb/core/mind/hive/monitoring.cpp +++ b/ydb/core/mind/hive/monitoring.cpp @@ -245,7 +245,7 @@ class TTxMonEvent_MemStateTablets : public TTransactionBase { } if (WaitingOnly) { tabletIdIndex.reserve(Self->BootQueue.WaitQueue.size()); - for (const TBootQueue::TBootQueueRecord& rec : Self->BootQueue.WaitQueue) { + for (const TBootQueue::TBootQueueRecord& rec : Self->BootQueue.WaitQueue.Container()) { TTabletInfo* tablet = Self->FindTablet(rec.TabletId, rec.FollowerId); if (tablet != nullptr) { tabletIdIndex.push_back({tabletIndexFunction(*tablet), tablet}); diff --git a/ydb/core/persqueue/events/internal.h b/ydb/core/persqueue/events/internal.h index 176b12f48e66..77e2367f9bcc 100644 --- a/ydb/core/persqueue/events/internal.h +++ b/ydb/core/persqueue/events/internal.h @@ -492,15 +492,13 @@ struct TEvPQ { }; struct TEvBlobRequest : public TEventLocal { - TEvBlobRequest(const TString& user, const ui64 cookie, const NPQ::TPartitionId& partition, + TEvBlobRequest(const ui64 cookie, const NPQ::TPartitionId& partition, TVector&& blobs) - : User(user) - , Cookie(cookie) + : Cookie(cookie) , Partition(partition) , Blobs(std::move(blobs)) {} - TString User; ui64 Cookie; NPQ::TPartitionId Partition; TVector Blobs; @@ -811,11 +809,15 @@ struct TEvPQ { { } - void AddOperation(TString consumer, ui64 begin, ui64 end) { + void AddOperation(TString consumer, ui64 begin, ui64 end, bool forceCommit = false, bool killReadSession = false, bool onlyCheckCommitedToFinish = false, TString readSessionId = {}) { NKikimrPQ::TPartitionOperation operation; - operation.SetBegin(begin); - operation.SetEnd(end); + operation.SetCommitOffsetsBegin(begin); + operation.SetCommitOffsetsEnd(end); operation.SetConsumer(std::move(consumer)); + operation.SetForceCommit(forceCommit); + operation.SetKillReadSession(killReadSession); + operation.SetOnlyCheckCommitedToFinish(onlyCheckCommitedToFinish); + operation.SetReadSessionId(readSessionId); Operations.push_back(std::move(operation)); } diff --git a/ydb/core/persqueue/partition.cpp b/ydb/core/persqueue/partition.cpp index 6ca8e046216f..9a4ea983ba22 100644 --- a/ydb/core/persqueue/partition.cpp +++ b/ydb/core/persqueue/partition.cpp @@ -167,15 +167,14 @@ void TPartition::ReplyOk(const TActorContext& ctx, const ui64 dst, NWilson::TSpa } void TPartition::ReplyGetClientOffsetOk(const TActorContext& ctx, const ui64 dst, const i64 offset, - const TInstant writeTimestamp, const TInstant createTimestamp) { - ctx.Send(Tablet, MakeReplyGetClientOffsetOk(dst, offset, writeTimestamp, createTimestamp).Release()); + const TInstant writeTimestamp, const TInstant createTimestamp, bool consumerHasAnyCommits) { + ctx.Send(Tablet, MakeReplyGetClientOffsetOk(dst, offset, writeTimestamp, createTimestamp, consumerHasAnyCommits).Release()); } NKikimrClient::TKeyValueRequest::EStorageChannel GetChannel(ui32 i) { return NKikimrClient::TKeyValueRequest::EStorageChannel(NKikimrClient::TKeyValueRequest::MAIN + i); } - void AddCheckDiskRequest(TEvKeyValue::TEvRequest *request, ui32 numChannels) { for (ui32 i = 0; i < numChannels; ++i) { request->Record.AddCmdGetStatus()->SetStorageChannel(GetChannel(i)); @@ -498,24 +497,32 @@ void TPartition::DestroyActor(const TActorContext& ctx) { // Reply to all outstanding requests in order to destroy corresponding actors + NPersQueue::NErrorCode::EErrorCode errorCode; TStringBuilder ss; - ss << "Tablet is restarting, topic '" << TopicName() << "'"; + + if (IsSupportive()) { + errorCode = NPersQueue::NErrorCode::ERROR; + ss << "The transaction is completed"; + } else { + errorCode = NPersQueue::NErrorCode::INITIALIZING; + ss << "Tablet is restarting, topic '" << TopicName() << "'"; + } for (const auto& ev : WaitToChangeOwner) { - ReplyError(ctx, ev->Cookie, NPersQueue::NErrorCode::INITIALIZING, ss); + ReplyError(ctx, ev->Cookie, errorCode, ss); } for (auto& w : PendingRequests) { - ReplyError(ctx, w.GetCookie(), NPersQueue::NErrorCode::INITIALIZING, ss); + ReplyError(ctx, w.GetCookie(), errorCode, ss); w.Span.EndError(static_cast(ss)); } for (const auto& w : Responses) { - ReplyError(ctx, w.GetCookie(), NPersQueue::NErrorCode::INITIALIZING, TStringBuilder() << ss << " (WriteResponses)"); + ReplyError(ctx, w.GetCookie(), errorCode, TStringBuilder() << ss << " (WriteResponses)"); } for (const auto& ri : ReadInfo) { - ReplyError(ctx, ri.second.Destination, NPersQueue::NErrorCode::INITIALIZING, + ReplyError(ctx, ri.second.Destination, errorCode, TStringBuilder() << ss << " (ReadInfo) cookie " << ri.first); } @@ -651,6 +658,54 @@ void TPartition::Handle(TEvPQ::TEvPipeDisconnected::TPtr& ev, const TActorContex } +TConsumerSnapshot TPartition::CreateSnapshot(TUserInfo& userInfo) const { + auto now = TAppData::TimeProvider->Now(); + + userInfo.UpdateReadingTimeAndState(EndOffset, now); + + TConsumerSnapshot result; + result.Now = now; + + if (userInfo.Offset >= static_cast(EndOffset)) { + result.LastCommittedMessage.CreateTimestamp = now; + result.LastCommittedMessage.WriteTimestamp = now; + } else if (userInfo.ActualTimestamps) { + result.LastCommittedMessage.CreateTimestamp = userInfo.CreateTimestamp; + result.LastCommittedMessage.WriteTimestamp = userInfo.WriteTimestamp; + } else { + auto timestamp = GetWriteTimeEstimate(userInfo.Offset); + result.LastCommittedMessage.CreateTimestamp = timestamp; + result.LastCommittedMessage.WriteTimestamp = timestamp; + } + + auto readOffset = userInfo.GetReadOffset(); + + result.ReadOffset = readOffset; + result.LastReadTimestamp = userInfo.ReadTimestamp; + + if (readOffset >= static_cast(EndOffset)) { + result.LastReadMessage.CreateTimestamp = now; + result.LastReadMessage.WriteTimestamp = now; + } else if (userInfo.ReadOffset == -1) { + result.LastReadMessage = result.LastCommittedMessage; + } else if (userInfo.ReadWriteTimestamp) { + result.LastReadMessage.CreateTimestamp = userInfo.ReadCreateTimestamp; + result.LastReadMessage.WriteTimestamp = userInfo.ReadWriteTimestamp; + } else { + auto timestamp = GetWriteTimeEstimate(readOffset); + result.LastCommittedMessage.CreateTimestamp = timestamp; + result.LastCommittedMessage.WriteTimestamp = timestamp; + } + + if (readOffset < (i64)EndOffset) { + result.ReadLag = result.LastReadTimestamp - result.LastReadMessage.WriteTimestamp; + } + result.CommitedLag = result.LastCommittedMessage.WriteTimestamp - now; + result.TotalLag = TDuration::MilliSeconds(userInfo.GetWriteLagMs()) + result.ReadLag + (now - result.LastReadTimestamp); + + return result; +} + void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext& ctx) { const auto now = ctx.Now(); @@ -697,7 +752,7 @@ void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext bool filterConsumers = !ev->Get()->Consumers.empty(); TSet requiredConsumers(ev->Get()->Consumers.begin(), ev->Get()->Consumers.end()); for (auto& userInfoPair : UsersInfoStorage->GetAll()) { - const auto& userInfo = userInfoPair.second; + auto& userInfo = userInfoPair.second; auto& clientId = ev->Get()->ClientId; bool consumerShouldBeProcessed = filterConsumers ? requiredConsumers.contains(userInfo.User) @@ -720,46 +775,32 @@ void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext continue; } - auto estimateWriteTimestamp = [&]() { - auto timestamp = userInfo.GetWriteTimestamp(EndOffset); - if (!timestamp) { - timestamp = GetWriteTimeEstimate(userInfo.Offset); - } - return timestamp; - }; - - auto estimateReadWriteTimestamp = [&]() { - auto timestamp = userInfo.GetReadWriteTimestamp(EndOffset); - if (!timestamp) { - timestamp = GetWriteTimeEstimate(userInfo.GetReadOffset()); - }; - return timestamp; - }; - if (clientId == userInfo.User) { //fill lags NKikimrPQ::TClientInfo* clientInfo = result.MutableLagsInfo(); clientInfo->SetClientId(userInfo.User); + auto snapshot = CreateSnapshot(userInfo); + auto write = clientInfo->MutableWritePosition(); write->SetOffset(userInfo.Offset); - write->SetWriteTimestamp(estimateWriteTimestamp().MilliSeconds()); - write->SetCreateTimestamp(userInfo.GetCreateTimestamp(EndOffset).MilliSeconds()); + write->SetWriteTimestamp(snapshot.LastCommittedMessage.WriteTimestamp.MilliSeconds()); + write->SetCreateTimestamp(snapshot.LastCommittedMessage.CreateTimestamp.MilliSeconds()); write->SetSize(GetSizeLag(userInfo.Offset)); - auto read = clientInfo->MutableReadPosition(); - read->SetOffset(userInfo.GetReadOffset()); - read->SetWriteTimestamp(estimateReadWriteTimestamp().MilliSeconds()); - read->SetCreateTimestamp(userInfo.GetReadCreateTimestamp(EndOffset).MilliSeconds()); - read->SetSize(GetSizeLag(userInfo.GetReadOffset())); + auto readOffset = userInfo.GetReadOffset(); - clientInfo->SetLastReadTimestampMs(userInfo.GetReadTimestamp().MilliSeconds()); - if (IsActive() || userInfo.GetReadOffset() < (i64)EndOffset) { - clientInfo->SetReadLagMs(userInfo.GetReadOffset() < (i64)EndOffset - ? (userInfo.GetReadTimestamp() - TInstant::MilliSeconds(read->GetWriteTimestamp())).MilliSeconds() - : 0); + auto read = clientInfo->MutableReadPosition(); + read->SetOffset(readOffset); + read->SetWriteTimestamp(snapshot.LastReadMessage.WriteTimestamp.MilliSeconds()); + read->SetCreateTimestamp(snapshot.LastReadMessage.CreateTimestamp.MilliSeconds()); + read->SetSize(GetSizeLag(readOffset)); + + clientInfo->SetLastReadTimestampMs(snapshot.LastReadTimestamp.MilliSeconds()); + clientInfo->SetCommitedLagMs(snapshot.CommitedLag.MilliSeconds()); + if (IsActive() || readOffset < (i64)EndOffset) { + clientInfo->SetReadLagMs(snapshot.ReadLag.MilliSeconds()); clientInfo->SetWriteLagMs(userInfo.GetWriteLagMs()); - ui64 totalLag = clientInfo->GetReadLagMs() + userInfo.GetWriteLagMs() + (now - userInfo.GetReadTimestamp()).MilliSeconds(); - clientInfo->SetTotalLagMs(totalLag); + clientInfo->SetTotalLagMs(snapshot.TotalLag.MilliSeconds()); } else { clientInfo->SetReadLagMs(0); clientInfo->SetWriteLagMs(0); @@ -768,14 +809,16 @@ void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext } if (ev->Get()->GetStatForAllConsumers) { //fill lags + auto snapshot = CreateSnapshot(userInfo); + auto* clientInfo = result.AddConsumerResult(); clientInfo->SetConsumer(userInfo.User); clientInfo->SetLastReadTimestampMs(userInfo.GetReadTimestamp().MilliSeconds()); + clientInfo->SetCommitedLagMs(snapshot.CommitedLag.MilliSeconds()); - if (IsActive() || userInfo.GetReadOffset() < (i64)EndOffset) { - clientInfo->SetReadLagMs(userInfo.GetReadOffset() < (i64)EndOffset - ? (userInfo.GetReadTimestamp() - estimateReadWriteTimestamp()).MilliSeconds() - : 0); + auto readOffset = userInfo.GetReadOffset(); + if (IsActive() || readOffset < (i64)EndOffset) { + clientInfo->SetReadLagMs(snapshot.ReadLag.MilliSeconds()); clientInfo->SetWriteLagMs(userInfo.GetWriteLagMs()); } else { clientInfo->SetReadLagMs(0); @@ -841,7 +884,7 @@ void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext } } } - result.SetScaleStatus(SplitMergeEnabled(TabletConfig) ? ScaleStatus :NKikimrPQ::EScaleStatus::NORMAL); + result.SetScaleStatus(SplitMergeEnabled(TabletConfig) ? ScaleStatus : NKikimrPQ::EScaleStatus::NORMAL); ctx.Send(ev->Get()->Sender, new TEvPQ::TEvPartitionStatusResponse(result, Partition)); } @@ -863,20 +906,22 @@ void TPartition::Handle(TEvPQ::TEvGetPartitionClientInfo::TPtr& ev, const TActor result.SetEndOffset(EndOffset); result.SetResponseTimestamp(ctx.Now().MilliSeconds()); for (auto& pr : UsersInfoStorage->GetAll()) { + auto snapshot = CreateSnapshot(pr.second); + TUserInfo& userInfo(pr.second); NKikimrPQ::TClientInfo& clientInfo = *result.AddClientInfo(); clientInfo.SetClientId(pr.first); auto& write = *clientInfo.MutableWritePosition(); write.SetOffset(userInfo.Offset); - write.SetWriteTimestamp((userInfo.GetWriteTimestamp(EndOffset) ? userInfo.GetWriteTimestamp(EndOffset) : GetWriteTimeEstimate(userInfo.Offset)).MilliSeconds()); - write.SetCreateTimestamp(userInfo.GetCreateTimestamp(EndOffset).MilliSeconds()); + write.SetWriteTimestamp(snapshot.LastCommittedMessage.WriteTimestamp.MilliSeconds()); + write.SetCreateTimestamp(snapshot.LastCommittedMessage.CreateTimestamp.MilliSeconds()); write.SetSize(GetSizeLag(userInfo.Offset)); auto& read = *clientInfo.MutableReadPosition(); read.SetOffset(userInfo.GetReadOffset()); - read.SetWriteTimestamp((userInfo.GetReadWriteTimestamp(EndOffset) ? userInfo.GetReadWriteTimestamp(EndOffset) : GetWriteTimeEstimate(userInfo.GetReadOffset())).MilliSeconds()); - read.SetCreateTimestamp(userInfo.GetReadCreateTimestamp(EndOffset).MilliSeconds()); + read.SetWriteTimestamp(snapshot.LastReadMessage.WriteTimestamp.MilliSeconds()); + read.SetCreateTimestamp(snapshot.LastReadMessage.CreateTimestamp.MilliSeconds()); read.SetSize(GetSizeLag(userInfo.GetReadOffset())); } ctx.Send(ev->Get()->Sender, response.Release(), 0, ev->Cookie); @@ -1529,37 +1574,31 @@ bool TPartition::UpdateCounters(const TActorContext& ctx, bool force) { if (userInfoPair.first != CLIENTID_WITHOUT_CONSUMER && !userInfo.HasReadRule && !userInfo.Important) continue; bool haveChanges = false; - userInfo.UpdateReadingTimeAndState(EndOffset, now); - ui64 ts = userInfo.GetWriteTimestamp(EndOffset).MilliSeconds(); + auto snapshot = CreateSnapshot(userInfo); + auto ts = snapshot.LastCommittedMessage.WriteTimestamp.MilliSeconds(); if (ts < MIN_TIMESTAMP_MS) ts = Max(); if (userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_WRITE_TIME].Get() != ts) { haveChanges = true; userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_WRITE_TIME].Set(ts); } - ts = userInfo.GetCreateTimestamp(EndOffset).MilliSeconds(); + ts = snapshot.LastCommittedMessage.CreateTimestamp.MilliSeconds(); if (ts < MIN_TIMESTAMP_MS) ts = Max(); if (userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_CREATE_TIME].Get() != ts) { haveChanges = true; userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_CREATE_TIME].Set(ts); } - ts = userInfo.GetReadWriteTimestamp(EndOffset).MilliSeconds(); - if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_WRITE_TIME].Get() != ts) { + auto readWriteTimestamp = snapshot.LastReadMessage.WriteTimestamp; + if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_WRITE_TIME].Get() != readWriteTimestamp.MilliSeconds()) { haveChanges = true; - userInfo.LabeledCounters->GetCounters()[METRIC_READ_WRITE_TIME].Set(ts); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_WRITE_TIME].Set(readWriteTimestamp.MilliSeconds()); } - i64 off = userInfo.GetReadOffset(); //we want to track first not-readed offset - TInstant wts = userInfo.GetReadWriteTimestamp(EndOffset) ? userInfo.GetReadWriteTimestamp(EndOffset) : GetWriteTimeEstimate(userInfo.GetReadOffset()); - TInstant readTimestamp = userInfo.GetReadTimestamp(); - ui64 readTimeLag = off >= (i64)EndOffset ? 0 : (readTimestamp - wts).MilliSeconds(); - ui64 totalLag = userInfo.GetWriteLagMs() + readTimeLag + (now - readTimestamp).MilliSeconds(); - - if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_TIME].Get() != totalLag) { + if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_TIME].Get() != snapshot.TotalLag.MilliSeconds()) { haveChanges = true; - userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_TIME].Set(totalLag); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_TIME].Set(snapshot.TotalLag.MilliSeconds()); } - ts = readTimestamp.MilliSeconds(); + ts = snapshot.LastReadTimestamp.MilliSeconds(); if (userInfo.LabeledCounters->GetCounters()[METRIC_LAST_READ_TIME].Get() != ts) { haveChanges = true; userInfo.LabeledCounters->GetCounters()[METRIC_LAST_READ_TIME].Set(ts); @@ -1571,9 +1610,9 @@ bool TPartition::UpdateCounters(const TActorContext& ctx, bool force) { userInfo.LabeledCounters->GetCounters()[METRIC_WRITE_TIME_LAG].Set(timeLag); } - if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_TIME_LAG].Get() != readTimeLag) { + if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_TIME_LAG].Get() != snapshot.ReadLag.MilliSeconds()) { haveChanges = true; - userInfo.LabeledCounters->GetCounters()[METRIC_READ_TIME_LAG].Set(readTimeLag); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_TIME_LAG].Set(snapshot.ReadLag.MilliSeconds()); } if (userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_MESSAGE_LAG].Get() != EndOffset - userInfo.Offset) { @@ -1581,10 +1620,10 @@ bool TPartition::UpdateCounters(const TActorContext& ctx, bool force) { userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_MESSAGE_LAG].Set(EndOffset - userInfo.Offset); } - if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_MESSAGE_LAG].Get() != EndOffset - off) { + if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_MESSAGE_LAG].Get() != EndOffset - snapshot.ReadOffset) { haveChanges = true; - userInfo.LabeledCounters->GetCounters()[METRIC_READ_MESSAGE_LAG].Set(EndOffset - off); - userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_MESSAGE_LAG].Set(EndOffset - off); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_MESSAGE_LAG].Set(EndOffset - snapshot.ReadOffset); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_MESSAGE_LAG].Set(EndOffset - snapshot.ReadOffset); } ui64 sizeLag = GetSizeLag(userInfo.Offset); @@ -1977,23 +2016,23 @@ void TPartition::ContinueProcessTxsAndUserActs(const TActorContext&) msg->WaitPreviousWriteSpan.End(); } switch (std::visit(visitor, front.Event)) { - case EProcessResult::Continue: - MoveUserActOrTxToCommitState(); - FirstEvent = false; - break; - case EProcessResult::ContinueDrop: - UserActionAndTransactionEvents.pop_front(); - break; - case EProcessResult::Break: - MoveUserActOrTxToCommitState(); - BatchingState = ETxBatchingState::Finishing; - FirstEvent = false; - break; - case EProcessResult::Blocked: - BatchingState = ETxBatchingState::Executing; - return; - case EProcessResult::NotReady: - return; + case EProcessResult::Continue: + MoveUserActOrTxToCommitState(); + FirstEvent = false; + break; + case EProcessResult::ContinueDrop: + UserActionAndTransactionEvents.pop_front(); + break; + case EProcessResult::Break: + MoveUserActOrTxToCommitState(); + BatchingState = ETxBatchingState::Finishing; + FirstEvent = false; + break; + case EProcessResult::Blocked: + BatchingState = ETxBatchingState::Executing; + return; + case EProcessResult::NotReady: + return; } CurrentBatchSize += 1; } @@ -2304,15 +2343,15 @@ bool TPartition::ExecUserActionOrTransaction(TSimpleSharedPtr& t, return true; } -TPartition::EProcessResult TPartition::BeginTransaction(const TEvPQ::TEvTxCalcPredicate& tx, TMaybe& predicate) +TPartition::EProcessResult TPartition::BeginTransaction(const TEvPQ::TEvTxCalcPredicate& tx, TMaybe& predicateOut) { if (tx.ForcePredicateFalse) { - predicate = false; + predicateOut = false; return EProcessResult::Continue; } THashSet consumers; - bool ok = true; + bool result = true; for (auto& operation : tx.Operations) { const TString& consumer = operation.GetConsumer(); if (TxAffectedConsumers.contains(consumer)) { @@ -2325,55 +2364,69 @@ TPartition::EProcessResult TPartition::BeginTransaction(const TEvPQ::TEvTxCalcPr if (AffectedUsers.contains(consumer) && !GetPendingUserIfExists(consumer)) { PQ_LOG_D("Partition " << Partition << " Consumer '" << consumer << "' has been removed"); - ok = false; + result = false; break; } if (!UsersInfoStorage->GetIfExists(consumer)) { PQ_LOG_D("Partition " << Partition << " Unknown consumer '" << consumer << "'"); - ok = false; + result = false; break; } bool isAffectedConsumer = AffectedUsers.contains(consumer); TUserInfoBase& userInfo = GetOrCreatePendingUser(consumer); - if (operation.GetBegin() > operation.GetEnd()) { - PQ_LOG_D("Partition " << Partition << - " Consumer '" << consumer << "'" << - " Bad request (invalid range) " << - " Begin " << operation.GetBegin() << - " End " << operation.GetEnd()); - ok = false; - } else if (userInfo.Offset != (i64)operation.GetBegin()) { + if (!operation.GetReadSessionId().empty() && operation.GetReadSessionId() != userInfo.Session) { PQ_LOG_D("Partition " << Partition << - " Consumer '" << consumer << "'" << - " Bad request (gap) " << - " Offset " << userInfo.Offset << - " Begin " << operation.GetBegin()); - ok = false; - } else if (operation.GetEnd() > EndOffset) { - PQ_LOG_D("Partition " << Partition << - " Consumer '" << consumer << "'" << - " Bad request (behind the last offset) " << - " EndOffset " << EndOffset << - " End " << operation.GetEnd()); - ok = false; - } + " Consumer '" << consumer << "'" << + " Bad request (session already dead) " << + " RequestSessionId '" << operation.GetReadSessionId() << + " CurrentSessionId '" << userInfo.Session << + "'"); + result = false; + } else if (operation.GetOnlyCheckCommitedToFinish()) { + if (IsActive() || static_cast(userInfo.Offset) != EndOffset) { + result = false; + } + } else { + if (!operation.GetForceCommit() && operation.GetCommitOffsetsBegin() > operation.GetCommitOffsetsEnd()) { + PQ_LOG_D("Partition " << Partition << + " Consumer '" << consumer << "'" << + " Bad request (invalid range) " << + " Begin " << operation.GetCommitOffsetsBegin() << + " End " << operation.GetCommitOffsetsEnd()); + result = false; + } else if (!operation.GetForceCommit() && userInfo.Offset != (i64)operation.GetCommitOffsetsBegin()) { + PQ_LOG_D("Partition " << Partition << + " Consumer '" << consumer << "'" << + " Bad request (gap) " << + " Offset " << userInfo.Offset << + " Begin " << operation.GetCommitOffsetsBegin()); + result = false; + } else if (!operation.GetForceCommit() && operation.GetCommitOffsetsEnd() > EndOffset) { + PQ_LOG_D("Partition " << Partition << + " Consumer '" << consumer << "'" << + " Bad request (behind the last offset) " << + " EndOffset " << EndOffset << + " End " << operation.GetCommitOffsetsEnd()); + result = false; + } - if (!ok) { - if (!isAffectedConsumer) { - AffectedUsers.erase(consumer); + if (!result) { + if (!isAffectedConsumer) { + AffectedUsers.erase(consumer); + } + break; } - break; + consumers.insert(consumer); } - consumers.insert(consumer); } - if (ok) { + if (result) { TxAffectedConsumers.insert(consumers.begin(), consumers.end()); } - predicate = ok; + predicateOut = result; return EProcessResult::Continue; } @@ -2533,12 +2586,40 @@ void TPartition::CommitTransaction(TSimpleSharedPtr& t) Y_ABORT_UNLESS(t->Predicate.Defined() && *t->Predicate); for (auto& operation : t->Tx->Operations) { + if (operation.GetOnlyCheckCommitedToFinish()) { + continue; + } + TUserInfoBase& userInfo = GetOrCreatePendingUser(operation.GetConsumer()); - Y_ABORT_UNLESS(userInfo.Offset == (i64)operation.GetBegin()); + if (!operation.GetForceCommit()) { + Y_ABORT_UNLESS(userInfo.Offset == (i64)operation.GetCommitOffsetsBegin()); + } - userInfo.Offset = operation.GetEnd(); + if ((i64)operation.GetCommitOffsetsEnd() < userInfo.Offset && !operation.GetReadSessionId().empty()) { + continue; // this is stale request, answer ok for it + } + + if (operation.GetCommitOffsetsEnd() <= StartOffset) { + userInfo.AnyCommits = false; + userInfo.Offset = StartOffset; + } else if (operation.GetCommitOffsetsEnd() > EndOffset) { + userInfo.AnyCommits = true; + userInfo.Offset = EndOffset; + } else { + userInfo.AnyCommits = true; + userInfo.Offset = operation.GetCommitOffsetsEnd(); + } + + if (operation.GetKillReadSession()) { + userInfo.Session = ""; + userInfo.PartitionSessionId = 0; + userInfo.Generation = 0; + userInfo.Step = 0; + userInfo.PipeClient = {}; + } } + CommitWriteOperations(*t); ChangePlanStepAndTxId(t->Tx->Step, t->Tx->TxId); ScheduleReplyCommitDone(t->Tx->Step, t->Tx->TxId); @@ -2660,6 +2741,9 @@ void TPartition::OnProcessTxsAndUserActsWriteComplete(const TActorContext& ctx) userInfo.Generation = actual->Generation; userInfo.Step = actual->Step; userInfo.Offset = actual->Offset; + if (userInfo.Offset <= (i64)StartOffset) { + userInfo.AnyCommits = false; + } userInfo.ReadRuleGeneration = actual->ReadRuleGeneration; userInfo.ReadFromTimestamp = actual->ReadFromTimestamp; userInfo.HasReadRule = true; @@ -2804,12 +2888,12 @@ TPartition::EProcessResult TPartition::PreProcessImmediateTx(const NKikimrPQ::TE Y_ABORT_UNLESS(tx.HasData()); THashSet consumers; for (auto& operation : tx.GetData().GetOperations()) { - if (!operation.HasBegin() || !operation.HasEnd() || !operation.HasConsumer()) { + if (!operation.HasCommitOffsetsBegin() || !operation.HasCommitOffsetsEnd() || !operation.HasConsumer()) { continue; //Write operation - handled separately via WriteInfo } - Y_ABORT_UNLESS(operation.GetBegin() <= (ui64)Max(), "Unexpected begin offset: %" PRIu64, operation.GetBegin()); - Y_ABORT_UNLESS(operation.GetEnd() <= (ui64)Max(), "Unexpected end offset: %" PRIu64, operation.GetEnd()); + Y_ABORT_UNLESS(operation.GetCommitOffsetsBegin() <= (ui64)Max(), "Unexpected begin offset: %" PRIu64, operation.GetCommitOffsetsBegin()); + Y_ABORT_UNLESS(operation.GetCommitOffsetsEnd() <= (ui64)Max(), "Unexpected end offset: %" PRIu64, operation.GetCommitOffsetsEnd()); const TString& user = operation.GetConsumer(); if (TxAffectedConsumers.contains(user)) { @@ -2822,7 +2906,7 @@ TPartition::EProcessResult TPartition::PreProcessImmediateTx(const NKikimrPQ::TE "the consumer has been deleted"); return EProcessResult::ContinueDrop; } - if (operation.GetBegin() > operation.GetEnd()) { + if (operation.GetCommitOffsetsBegin() > operation.GetCommitOffsetsEnd()) { ScheduleReplyPropose(tx, NKikimrPQ::TEvProposeTransactionResult::BAD_REQUEST, NKikimrPQ::TError::BAD_REQUEST, @@ -2853,12 +2937,12 @@ void TPartition::ExecImmediateTx(TTransaction& t) return; } for (const auto& operation : record.GetData().GetOperations()) { - if (!operation.HasBegin() || !operation.HasEnd() || !operation.HasConsumer()) { + if (!operation.HasCommitOffsetsBegin() || !operation.HasCommitOffsetsEnd() || !operation.HasConsumer()) { continue; //Write operation - handled separately via WriteInfo } - Y_ABORT_UNLESS(operation.GetBegin() <= (ui64)Max(), "Unexpected begin offset: %" PRIu64, operation.GetBegin()); - Y_ABORT_UNLESS(operation.GetEnd() <= (ui64)Max(), "Unexpected end offset: %" PRIu64, operation.GetEnd()); + Y_ABORT_UNLESS(operation.GetCommitOffsetsBegin() <= (ui64)Max(), "Unexpected begin offset: %" PRIu64, operation.GetCommitOffsetsBegin()); + Y_ABORT_UNLESS(operation.GetCommitOffsetsEnd() <= (ui64)Max(), "Unexpected end offset: %" PRIu64, operation.GetCommitOffsetsEnd()); const TString& user = operation.GetConsumer(); if (!PendingUsersInfo.contains(user) && AffectedUsers.contains(user)) { @@ -2868,9 +2952,9 @@ void TPartition::ExecImmediateTx(TTransaction& t) "the consumer has been deleted"); return; } - TUserInfoBase& userInfo = GetOrCreatePendingUser(user); + TUserInfoBase& pendingUserInfo = GetOrCreatePendingUser(user); - if (operation.GetBegin() > operation.GetEnd()) { + if (!operation.GetForceCommit() && operation.GetCommitOffsetsBegin() > operation.GetCommitOffsetsEnd()) { ScheduleReplyPropose(record, NKikimrPQ::TEvProposeTransactionResult::BAD_REQUEST, NKikimrPQ::TError::BAD_REQUEST, @@ -2878,7 +2962,7 @@ void TPartition::ExecImmediateTx(TTransaction& t) return; } - if (userInfo.Offset != (i64)operation.GetBegin()) { + if (!operation.GetForceCommit() && pendingUserInfo.Offset != (i64)operation.GetCommitOffsetsBegin()) { ScheduleReplyPropose(record, NKikimrPQ::TEvProposeTransactionResult::ABORTED, NKikimrPQ::TError::BAD_REQUEST, @@ -2886,14 +2970,14 @@ void TPartition::ExecImmediateTx(TTransaction& t) return; } - if (operation.GetEnd() > EndOffset) { + if (!operation.GetForceCommit() && operation.GetCommitOffsetsEnd() > EndOffset) { ScheduleReplyPropose(record, NKikimrPQ::TEvProposeTransactionResult::BAD_REQUEST, NKikimrPQ::TError::BAD_REQUEST, "incorrect offset range (commit to the future)"); return; } - userInfo.Offset = operation.GetEnd(); + pendingUserInfo.Offset = operation.GetCommitOffsetsEnd(); } CommitWriteOperations(t); @@ -3029,7 +3113,7 @@ void TPartition::CommitUserAct(TEvPQ::TEvSetClientInfo& act) { userInfo.PipeClient = act.PipeClient; ScheduleReplyGetClientOffsetOk(act.Cookie, userInfo.Offset, - ts.first, ts.second); + ts.first, ts.second, ui->AnyCommits); return; } @@ -3125,15 +3209,16 @@ void TPartition::EmulatePostProcessUserAct(const TEvPQ::TEvSetClientInfo& act, ui32 step = act.Step; const ui64 readRuleGeneration = act.ReadRuleGeneration; - bool setSession = act.Type == TEvPQ::TEvSetClientInfo::ESCI_CREATE_SESSION; + bool createSession = act.Type == TEvPQ::TEvSetClientInfo::ESCI_CREATE_SESSION; bool dropSession = act.Type == TEvPQ::TEvSetClientInfo::ESCI_DROP_SESSION; - bool strictCommitOffset = (act.Type == TEvPQ::TEvSetClientInfo::ESCI_OFFSET && act.SessionId.empty()); + bool commitNotFromReadSession = (act.Type == TEvPQ::TEvSetClientInfo::ESCI_OFFSET && act.SessionId.empty()); if (act.Type == TEvPQ::TEvSetClientInfo::ESCI_DROP_READ_RULE) { userInfo.ReadRuleGeneration = 0; userInfo.Session = ""; userInfo.Generation = userInfo.Step = 0; userInfo.Offset = 0; + userInfo.AnyCommits = false; PQ_LOG_D("Topic '" << TopicName() << "' partition " << Partition << " user " << user << " drop done" @@ -3149,30 +3234,31 @@ void TPartition::EmulatePostProcessUserAct(const TEvPQ::TEvSetClientInfo& act, userInfo.PartitionSessionId = 0; userInfo.Generation = userInfo.Step = 0; userInfo.Offset = 0; + userInfo.AnyCommits = false; if (userInfo.Important) { userInfo.Offset = StartOffset; } } else { - if (setSession || dropSession) { + if (createSession || dropSession) { offset = userInfo.Offset; auto *ui = UsersInfoStorage->GetIfExists(userInfo.User); auto ts = ui ? GetTime(*ui, userInfo.Offset) : std::make_pair(TInstant::Zero(), TInstant::Zero()); ScheduleReplyGetClientOffsetOk(act.Cookie, offset, - ts.first, ts.second); + ts.first, ts.second, ui ? ui->AnyCommits : false); } else { ScheduleReplyOk(act.Cookie); } - if (setSession) { + if (createSession) { userInfo.Session = session; userInfo.Generation = generation; userInfo.Step = step; userInfo.PipeClient = act.PipeClient; userInfo.PartitionSessionId = act.PartitionSessionId; - } else if ((dropSession && act.PipeClient == userInfo.PipeClient) || strictCommitOffset) { + } else if ((dropSession && act.PipeClient == userInfo.PipeClient) || commitNotFromReadSession) { userInfo.Session = ""; userInfo.PartitionSessionId = 0; userInfo.Generation = 0; @@ -3182,17 +3268,20 @@ void TPartition::EmulatePostProcessUserAct(const TEvPQ::TEvSetClientInfo& act, Y_ABORT_UNLESS(offset <= (ui64)Max(), "Unexpected Offset: %" PRIu64, offset); PQ_LOG_D("Topic '" << TopicName() << "' partition " << Partition << " user " << user - << (setSession || dropSession ? " session" : " offset") + << (createSession || dropSession ? " session" : " offset") << " is set to " << offset << " (startOffset " << StartOffset << ") session " << session ); userInfo.Offset = offset; + if (userInfo.Offset <= (i64)StartOffset) { + userInfo.AnyCommits = false; + } if (LastOffsetHasBeenCommited(userInfo)) { SendReadingFinished(user); } - auto counter = setSession ? COUNTER_PQ_CREATE_SESSION_OK : (dropSession ? COUNTER_PQ_DELETE_SESSION_OK : COUNTER_PQ_SET_CLIENT_OFFSET_OK); + auto counter = createSession ? COUNTER_PQ_CREATE_SESSION_OK : (dropSession ? COUNTER_PQ_DELETE_SESSION_OK : COUNTER_PQ_SET_CLIENT_OFFSET_OK); TabletCounters.Cumulative()[counter].Increment(1); } } @@ -3205,12 +3294,16 @@ void TPartition::ScheduleReplyOk(const ui64 dst) void TPartition::ScheduleReplyGetClientOffsetOk(const ui64 dst, const i64 offset, - const TInstant writeTimestamp, const TInstant createTimestamp) + const TInstant writeTimestamp, + const TInstant createTimestamp, + bool consumerHasAnyCommits) { Replies.emplace_back(Tablet, MakeReplyGetClientOffsetOk(dst, offset, - writeTimestamp, createTimestamp).Release()); + writeTimestamp, + createTimestamp, + consumerHasAnyCommits).Release()); } @@ -3285,7 +3378,8 @@ void TPartition::AddCmdWrite(NKikimrClient::TKeyValueRequest& request, const TKeyPrefix& ikey, const TKeyPrefix& ikeyDeprecated, ui64 offset, ui32 gen, ui32 step, const TString& session, ui64 readOffsetRewindSum, - ui64 readRuleGeneration) + ui64 readRuleGeneration, + bool anyCommits) { TBuffer idata; { @@ -3296,6 +3390,7 @@ void TPartition::AddCmdWrite(NKikimrClient::TKeyValueRequest& request, userData.SetSession(session); userData.SetOffsetRewindSum(readOffsetRewindSum); userData.SetReadRuleGeneration(readRuleGeneration); + userData.SetAnyCommits(anyCommits); TString out; Y_PROTOBUF_SUPPRESS_NODISCARD userData.SerializeToString(&out); @@ -3356,7 +3451,8 @@ void TPartition::AddCmdWriteUserInfos(NKikimrClient::TKeyValueRequest& request) userInfo->Offset, userInfo->Generation, userInfo->Step, userInfo->Session, ui ? ui->ReadOffsetRewindSum : 0, - userInfo->ReadRuleGeneration); + userInfo->ReadRuleGeneration, + userInfo->AnyCommits); } else { AddCmdDeleteRange(request, ikey, ikeyDeprecated); @@ -3385,27 +3481,27 @@ TUserInfoBase& TPartition::GetOrCreatePendingUser(const TString& user, TMaybe readRuleGeneration) { TUserInfoBase* userInfo = nullptr; - auto i = PendingUsersInfo.find(user); - if (i == PendingUsersInfo.end()) { - auto ui = UsersInfoStorage->GetIfExists(user); - auto [p, _] = PendingUsersInfo.emplace(user, UsersInfoStorage->CreateUserInfo(user, readRuleGeneration)); + auto pendingUserIt = PendingUsersInfo.find(user); + if (pendingUserIt == PendingUsersInfo.end()) { + auto userIt = UsersInfoStorage->GetIfExists(user); + auto [newPendingUserIt, _] = PendingUsersInfo.emplace(user, UsersInfoStorage->CreateUserInfo(user, readRuleGeneration)); - if (ui) { - p->second.Session = ui->Session; - p->second.PartitionSessionId = ui->PartitionSessionId; - p->second.PipeClient = ui->PipeClient; + if (userIt) { + newPendingUserIt->second.Session = userIt->Session; + newPendingUserIt->second.PartitionSessionId = userIt->PartitionSessionId; + newPendingUserIt->second.PipeClient = userIt->PipeClient; - p->second.Generation = ui->Generation; - p->second.Step = ui->Step; - p->second.Offset = ui->Offset; - p->second.ReadRuleGeneration = ui->ReadRuleGeneration; - p->second.Important = ui->Important; - p->second.ReadFromTimestamp = ui->ReadFromTimestamp; + newPendingUserIt->second.Generation = userIt->Generation; + newPendingUserIt->second.Step = userIt->Step; + newPendingUserIt->second.Offset = userIt->Offset; + newPendingUserIt->second.ReadRuleGeneration = userIt->ReadRuleGeneration; + newPendingUserIt->second.Important = userIt->Important; + newPendingUserIt->second.ReadFromTimestamp = userIt->ReadFromTimestamp; } - userInfo = &p->second; + userInfo = &newPendingUserIt->second; } else { - userInfo = &i->second; + userInfo = &pendingUserIt->second; } AffectedUsers.insert(user); @@ -3435,7 +3531,8 @@ THolder TPartition::MakeReplyOk(const ui64 dst) THolder TPartition::MakeReplyGetClientOffsetOk(const ui64 dst, const i64 offset, const TInstant writeTimestamp, - const TInstant createTimestamp) + const TInstant createTimestamp, + bool consumerHasAnyCommits) { auto response = MakeHolder(dst); NKikimrClient::TResponse& resp = *response->Response; @@ -3459,10 +3556,9 @@ THolder TPartition::MakeReplyGetClientOffsetOk(const ui } else { user->SetSizeLag(0); } - + user->SetClientHasAnyCommits(consumerHasAnyCommits); return response; } - THolder TPartition::MakeReplyError(const ui64 dst, NPersQueue::NErrorCode::EErrorCode errorCode, const TString& error) @@ -3558,7 +3654,13 @@ void TPartition::Handle(TEvPQ::TEvApproveWriteQuota::TPtr& ev, const TActorConte TopicWriteQuotaWaitCounter->IncFor(TopicQuotaWaitTimeForCurrentBlob.MilliSeconds()); } - RequestBlobQuota(); + if (NeedDeletePartition) { + // deferred TEvPQ::TEvDeletePartition + DeletePartitionState = DELETION_INITED; + } else { + RequestBlobQuota(); + } + ProcessTxsAndUserActs(ctx); } @@ -3662,6 +3764,13 @@ void TPartition::ProcessPendingEvent(std::unique_ptr Y_ABORT_UNLESS(IsSupportive()); Y_ABORT_UNLESS(DeletePartitionState == DELETION_NOT_INITED); + NeedDeletePartition = true; + + if (TopicQuotaRequestCookie != 0) { + // wait for TEvPQ::TEvApproveWriteQuota + return; + } + DeletePartitionState = DELETION_INITED; ProcessTxsAndUserActs(ctx); diff --git a/ydb/core/persqueue/partition.h b/ydb/core/persqueue/partition.h index cdda09f3c6d6..358260cc2459 100644 --- a/ydb/core/persqueue/partition.h +++ b/ydb/core/persqueue/partition.h @@ -158,7 +158,7 @@ class TPartition : public TActorBootstrapped { NKikimrPQ::TError::EKind kind, const TString& reason); void ReplyErrorForStoredWrites(const TActorContext& ctx); - void ReplyGetClientOffsetOk(const TActorContext& ctx, const ui64 dst, const i64 offset, const TInstant writeTimestamp, const TInstant createTimestamp); + void ReplyGetClientOffsetOk(const TActorContext& ctx, const ui64 dst, const i64 offset, const TInstant writeTimestamp, const TInstant createTimestamp, bool consumerHasAnyCommits); void ReplyOk(const TActorContext& ctx, const ui64 dst); void ReplyOk(const TActorContext& ctx, const ui64 dst, NWilson::TSpan& span); void ReplyOwnerOk(const TActorContext& ctx, const ui64 dst, const TString& ownerCookie, ui64 seqNo, NWilson::TSpan& span); @@ -345,7 +345,9 @@ class TPartition : public TActorBootstrapped { void ScheduleReplyOk(const ui64 dst); void ScheduleReplyGetClientOffsetOk(const ui64 dst, const i64 offset, - const TInstant writeTimestamp, const TInstant createTimestamp); + const TInstant writeTimestamp, + const TInstant createTimestamp, + bool consumerHasAnyCommits); void ScheduleReplyError(const ui64 dst, NPersQueue::NErrorCode::EErrorCode errorCode, const TString& error); @@ -361,7 +363,8 @@ class TPartition : public TActorBootstrapped { const TKeyPrefix& ikey, const TKeyPrefix& ikeyDeprecated, ui64 offset, ui32 gen, ui32 step, const TString& session, ui64 readOffsetRewindSum, - ui64 readRuleGeneration); + ui64 readRuleGeneration, + bool anyCommits); void AddCmdWriteTxMeta(NKikimrClient::TKeyValueRequest& request); void AddCmdWriteUserInfos(NKikimrClient::TKeyValueRequest& request); void AddCmdWriteConfig(NKikimrClient::TKeyValueRequest& request); @@ -374,7 +377,9 @@ class TPartition : public TActorBootstrapped { THolder MakeReplyOk(const ui64 dst); THolder MakeReplyGetClientOffsetOk(const ui64 dst, const i64 offset, - const TInstant writeTimestamp, const TInstant createTimestamp); + const TInstant writeTimestamp, + const TInstant createTimestamp, + bool consumerHasAnyCommits); THolder MakeReplyError(const ui64 dst, NPersQueue::NErrorCode::EErrorCode errorCode, const TString& error); @@ -451,6 +456,8 @@ class TPartition : public TActorBootstrapped { ui64 GetReadOffset(ui64 offset, TMaybe readTimestamp) const; + TConsumerSnapshot CreateSnapshot(TUserInfo& userInfo) const; + public: static constexpr NKikimrServices::TActivity::EType ActorActivityType() { return NKikimrServices::TActivity::PERSQUEUE_PARTITION_ACTOR; @@ -927,6 +934,7 @@ class TPartition : public TActorBootstrapped { ui64 TopicQuotaRequestCookie = 0; ui64 NextTopicWriteQuotaRequestCookie = 1; ui64 BlobQuotaSize = 0; + bool NeedDeletePartition = false; // Wait topic quota metrics ui64 TotalPartitionWriteSpeed = 0; diff --git a/ydb/core/persqueue/partition_monitoring.cpp b/ydb/core/persqueue/partition_monitoring.cpp index 582afdb234b2..b4d8b61769e4 100644 --- a/ydb/core/persqueue/partition_monitoring.cpp +++ b/ydb/core/persqueue/partition_monitoring.cpp @@ -232,20 +232,21 @@ void TPartition::HandleMonitoring(TEvPQ::TEvMonRequest::TPtr& ev, const TActorCo } } TABLEBODY() { - for (auto& d: UsersInfoStorage->GetAll()) { + for (auto& [user, userInfo]: UsersInfoStorage->GetAll()) { + auto snapshot = CreateSnapshot(userInfo); TABLER() { - TABLED() {out << EncodeHtmlPcdata(d.first);} - TABLED() {out << d.second.Offset;} - TABLED() {out << (EndOffset - d.second.Offset);} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.ReadFromTimestamp);} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.WriteTimestamp);} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.CreateTimestamp);} - TABLED() {out << (d.second.GetReadOffset());} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.GetReadWriteTimestamp(EndOffset));} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.GetReadCreateTimestamp(EndOffset));} - TABLED() {out << (d.second.ReadOffsetRewindSum);} - TABLED() {out << d.second.ActiveReads;} - TABLED() {out << d.second.Subscriptions;} + TABLED() {out << EncodeHtmlPcdata(user);} + TABLED() {out << userInfo.Offset;} + TABLED() {out << (EndOffset - userInfo.Offset);} + TABLED() {out << ToStringLocalTimeUpToSeconds(userInfo.ReadFromTimestamp);} + TABLED() {out << ToStringLocalTimeUpToSeconds(snapshot.LastCommittedMessage.WriteTimestamp);} + TABLED() {out << ToStringLocalTimeUpToSeconds(snapshot.LastCommittedMessage.WriteTimestamp);} + TABLED() {out << (userInfo.GetReadOffset());} + TABLED() {out << ToStringLocalTimeUpToSeconds(snapshot.LastReadMessage.WriteTimestamp);} + TABLED() {out << ToStringLocalTimeUpToSeconds(snapshot.LastReadMessage.CreateTimestamp);} + TABLED() {out << (userInfo.ReadOffsetRewindSum);} + TABLED() {out << userInfo.ActiveReads;} + TABLED() {out << userInfo.Subscriptions;} } } } diff --git a/ydb/core/persqueue/partition_read.cpp b/ydb/core/persqueue/partition_read.cpp index faf618176a82..f7af353f3e8c 100644 --- a/ydb/core/persqueue/partition_read.cpp +++ b/ydb/core/persqueue/partition_read.cpp @@ -124,10 +124,10 @@ TAutoPtr TPartition::MakeHasDataInfoRespon ui32 partitionId = Partition.OriginalPartitionId; auto* node = PartitionGraph.GetPartition(partitionId); - for (auto* child : node->Children) { + for (auto* child : node->DirectChildren) { res->Record.AddChildPartitionIds(child->Id); - for (auto* p : child->Parents) { + for (auto* p : child->DirectParents) { if (p->Id != partitionId) { res->Record.AddAdjacentPartitionIds(p->Id); } @@ -252,7 +252,7 @@ void TPartition::InitUserInfoForImportantClients(const TActorContext& ctx) { } if (!userInfo) { userInfo = &UsersInfoStorage->Create( - ctx, consumer.GetName(), 0, true, "", 0, 0, 0, 0, 0, TInstant::Zero(), {} + ctx, consumer.GetName(), 0, true, "", 0, 0, 0, 0, 0, TInstant::Zero(), {}, false ); } if (userInfo->Offset < (i64)StartOffset) @@ -281,15 +281,13 @@ void TPartition::Handle(TEvPQ::TEvPartitionOffsets::TPtr& ev, const TActorContex if (!ev->Get()->ClientId.empty()) { TUserInfo* userInfo = UsersInfoStorage->GetIfExists(ev->Get()->ClientId); if (userInfo) { - i64 offset = Max(userInfo->Offset, 0); + auto snapshot = CreateSnapshot(*userInfo); result.SetClientOffset(userInfo->Offset); - TInstant tmp = userInfo->GetWriteTimestamp(EndOffset) ? userInfo->GetWriteTimestamp(EndOffset) : GetWriteTimeEstimate(offset); - result.SetWriteTimestampMS(tmp.MilliSeconds()); - result.SetCreateTimestampMS(userInfo->GetCreateTimestamp(EndOffset).MilliSeconds()); + result.SetWriteTimestampMS(snapshot.LastCommittedMessage.WriteTimestamp.MilliSeconds()); + result.SetCreateTimestampMS(snapshot.LastCommittedMessage.CreateTimestamp.MilliSeconds()); result.SetClientReadOffset(userInfo->GetReadOffset()); - tmp = userInfo->GetReadWriteTimestamp(EndOffset) ? userInfo->GetReadWriteTimestamp(EndOffset) : GetWriteTimeEstimate(userInfo->GetReadOffset()); - result.SetReadWriteTimestampMS(tmp.MilliSeconds()); - result.SetReadCreateTimestampMS(userInfo->GetReadCreateTimestamp(EndOffset).MilliSeconds()); + result.SetReadWriteTimestampMS(snapshot.LastReadMessage.WriteTimestamp.MilliSeconds()); + result.SetReadCreateTimestampMS(snapshot.LastReadMessage.CreateTimestamp.MilliSeconds()); } } ctx.Send(ev->Get()->Sender, new TEvPQ::TEvPartitionOffsetsResponse(result, Partition)); @@ -314,7 +312,7 @@ void TPartition::Handle(TEvPQ::TEvGetClientOffset::TPtr& ev, const TActorContext ui64 offset = Max(userInfo.Offset, 0); auto ts = GetTime(userInfo, offset); TabletCounters.Cumulative()[COUNTER_PQ_GET_CLIENT_OFFSET_OK].Increment(1); - ReplyGetClientOffsetOk(ctx, ev->Get()->Cookie, userInfo.Offset, ts.first, ts.second); + ReplyGetClientOffsetOk(ctx, ev->Get()->Cookie, userInfo.Offset, ts.first, ts.second, userInfo.AnyCommits); } void TPartition::Handle(TEvPQ::TEvSetClientInfo::TPtr& ev, const TActorContext& ctx) { @@ -776,7 +774,6 @@ void TPartition::Handle(TEvPQ::TEvRead::TPtr& ev, const TActorContext& ctx) { const TString& user = read->ClientId; auto& userInfo = UsersInfoStorage->GetOrCreate(user, ctx); - if (!read->SessionId.empty() && !userInfo.NoConsumer) { if (userInfo.Session != read->SessionId) { TabletCounters.Cumulative()[COUNTER_PQ_READ_ERROR_NO_SESSION].Increment(1); @@ -1065,13 +1062,12 @@ void TPartition::ProcessRead(const TActorContext& ctx, TReadInfo&& info, const u return; } - const TString user = info.User; bool res = ReadInfo.emplace(cookie, std::move(info)).second; PQ_LOG_D("Reading cookie " << cookie << ". Send blob request."); Y_ABORT_UNLESS(res); - THolder request(new TEvPQ::TEvBlobRequest(user, cookie, Partition, - std::move(blobs))); + auto request = MakeHolder(cookie, Partition, + std::move(blobs)); ctx.Send(BlobCache, request.Release()); } diff --git a/ydb/core/persqueue/partition_scale_manager.cpp b/ydb/core/persqueue/partition_scale_manager.cpp index 77f16ab019ea..3360752d7653 100644 --- a/ydb/core/persqueue/partition_scale_manager.cpp +++ b/ydb/core/persqueue/partition_scale_manager.cpp @@ -74,7 +74,7 @@ std::pair, std::vector> TPartition auto partitionId = PartitionsToSplit.begin(); while (allowedSplitsCount > 0 && partitionId != PartitionsToSplit.end()) { auto* node = PartitionGraph.GetPartition(*partitionId); - if (node->Children.empty()) { + if (node->DirectChildren.empty()) { auto from = node->From; auto to = node->To; auto mid = MiddleOf(from, to); diff --git a/ydb/core/persqueue/partition_sourcemanager.cpp b/ydb/core/persqueue/partition_sourcemanager.cpp index c9214300384a..c2b6d5a0edd4 100644 --- a/ydb/core/persqueue/partition_sourcemanager.cpp +++ b/ydb/core/persqueue/partition_sourcemanager.cpp @@ -50,7 +50,7 @@ TSourceIdStorage& TPartitionSourceManager::GetSourceIdStorage() const { bool TPartitionSourceManager::HasParents() const { auto node = GetPartitionNode(); - return node && !node->Parents.empty(); + return node && !node->DirectParents.empty(); } diff --git a/ydb/core/persqueue/partition_write.cpp b/ydb/core/persqueue/partition_write.cpp index 6bcfffd83192..38d75c485910 100644 --- a/ydb/core/persqueue/partition_write.cpp +++ b/ydb/core/persqueue/partition_write.cpp @@ -1638,7 +1638,7 @@ bool TPartition::RequestBlobQuota() void TPartition::HandlePendingRequests(const TActorContext& ctx) { - if (WaitingForPreviousBlobQuota() || WaitingForSubDomainQuota(ctx)) { + if (WaitingForPreviousBlobQuota() || WaitingForSubDomainQuota(ctx) || NeedDeletePartition) { return; } if (RequestBlobQuota()) { diff --git a/ydb/core/persqueue/pq_impl.cpp b/ydb/core/persqueue/pq_impl.cpp index 5447d7bc8515..cfd101855c3b 100644 --- a/ydb/core/persqueue/pq_impl.cpp +++ b/ydb/core/persqueue/pq_impl.cpp @@ -3203,7 +3203,7 @@ bool TPersQueue::CheckTxWriteOperations(const NKikimrPQ::TDataTransaction& txBod for (auto& operation : txBody.GetOperations()) { auto isWrite = [](const NKikimrPQ::TPartitionOperation& o) { - return !o.HasBegin(); + return !o.HasCommitOffsetsBegin(); }; if (isWrite(operation)) { @@ -3926,7 +3926,7 @@ TMaybe TPersQueue::FindPartitionId(const NKikimrPQ::TDataTransacti { auto hasWriteOperation = [](const auto& txBody) { for (const auto& o : txBody.GetOperations()) { - if (!o.HasBegin()) { + if (!o.HasCommitOffsetsBegin()) { return true; } } @@ -3978,10 +3978,14 @@ void TPersQueue::SendEvTxCalcPredicateToPartitions(const TActorContext& ctx, event = std::make_unique(tx.Step, tx.TxId); } - if (operation.HasBegin()) { + if (operation.HasCommitOffsetsBegin()) { event->AddOperation(operation.GetConsumer(), - operation.GetBegin(), - operation.GetEnd()); + operation.GetCommitOffsetsBegin(), + operation.GetCommitOffsetsEnd(), + operation.HasForceCommit() ? operation.GetForceCommit() : false, + operation.HasKillReadSession() ? operation.GetKillReadSession() : false, + operation.HasOnlyCheckCommitedToFinish() ? operation.GetOnlyCheckCommitedToFinish() : false, + operation.HasReadSessionId() ? operation.GetReadSessionId() : ""); } } diff --git a/ydb/core/persqueue/read_balancer__balancing.cpp b/ydb/core/persqueue/read_balancer__balancing.cpp index 79218cdff6b9..f8f97a4c4795 100644 --- a/ydb/core/persqueue/read_balancer__balancing.cpp +++ b/ydb/core/persqueue/read_balancer__balancing.cpp @@ -681,7 +681,7 @@ bool IsRoot(const TPartitionGraph::Node* node, const std::unordered_set& p if (node->IsRoot()) { return true; } - for (auto* p : node->Parents) { + for (auto* p : node->DirectParents) { if (partitions.contains(p->Id)) { return false; } @@ -966,10 +966,10 @@ bool TConsumer::IsReadable(ui32 partitionId) { } if (Partitions.empty()) { - return node->Parents.empty(); + return node->DirectParents.empty(); } - for(auto* parent : node->HierarhicalParents) { + for(auto* parent : node->AllParents) { if (!IsInactive(parent->Id)) { return false; } @@ -1035,9 +1035,9 @@ bool TConsumer::ProccessReadingFinished(ui32 partitionId, bool wasInactive, cons if (family->CanAttach(std::vector{id})) { auto* node = GetPartitionGraph().GetPartition(id); bool allParentsMerged = true; - if (node->Parents.size() > 1) { + if (node->DirectParents.size() > 1) { // The partition was obtained as a result of the merge. - for (auto* c : node->Parents) { + for (auto* c : node->DirectParents) { auto* other = FindFamily(c->Id); if (!other) { allParentsMerged = false; diff --git a/ydb/core/persqueue/read_balancer__balancing_app.cpp b/ydb/core/persqueue/read_balancer__balancing_app.cpp index fd565135d162..71c7b72150fb 100644 --- a/ydb/core/persqueue/read_balancer__balancing_app.cpp +++ b/ydb/core/persqueue/read_balancer__balancing_app.cpp @@ -76,7 +76,7 @@ void TBalancer::RenderApp(NApp::TNavigationBar& __navigationBar) const { for (auto& [partitionId, partition] : consumer->Partitions) { const auto* family = consumer->FindFamily(partitionId); const auto* node = consumer->GetPartitionGraph().GetPartition(partitionId); - TString style = node && node->Children.empty() ? "text-success" : "text-muted"; + TString style = node && node->DirectChildren.empty() ? "text-success" : "text-muted"; auto* partitionInfo = GetPartitionInfo(partitionId); TABLER() { @@ -110,7 +110,7 @@ void TBalancer::RenderApp(NApp::TNavigationBar& __navigationBar) const { } TABLED() { if (node) { - for (auto* parent : node->Parents) { + for (auto* parent : node->DirectParents) { HREF("#" + partitionAnchor(parent->Id)) { __stream << parent->Id; } __stream << ", "; } diff --git a/ydb/core/persqueue/read_balancer_app.cpp b/ydb/core/persqueue/read_balancer_app.cpp index d4f9f8abf137..9ca5c425258b 100644 --- a/ydb/core/persqueue/read_balancer_app.cpp +++ b/ydb/core/persqueue/read_balancer_app.cpp @@ -77,7 +77,7 @@ TString TPersQueueReadBalancer::GenerateStat() { for (auto& [partitionId, partitionInfo] : PartitionsInfo) { const auto& stats = AggregatedStats.Stats[partitionId]; const auto* node = PartitionGraph.GetPartition(partitionId); - TString style = node && node->Children.empty() ? "text-success" : "text-muted"; + TString style = node && node->DirectChildren.empty() ? "text-success" : "text-muted"; TABLER() { TABLED() { @@ -87,7 +87,7 @@ TString TPersQueueReadBalancer::GenerateStat() { } TABLED() { if (node) { - str << (node->Children.empty() ? "Active" : "Inactive"); + str << (node->DirectChildren.empty() ? "Active" : "Inactive"); if (node->IsRoot()) { str << " (root)"; } @@ -96,7 +96,7 @@ TString TPersQueueReadBalancer::GenerateStat() { TABLED() { HREF(TStringBuilder() << "?TabletID=" << partitionInfo.TabletId) { str << partitionInfo.TabletId; } } TABLED() { if (node) { - for (auto* parent : node->Parents) { + for (auto* parent : node->DirectParents) { HREF("#" + partitionAnchor(parent->Id)) { str << parent->Id; } str << ", "; } @@ -104,7 +104,7 @@ TString TPersQueueReadBalancer::GenerateStat() { } TABLED() { if (node) { - for (auto* child : node->Children) { + for (auto* child : node->DirectChildren) { HREF("#" + partitionAnchor(child->Id)) { str << child->Id; } str << ", "; } diff --git a/ydb/core/persqueue/transaction.cpp b/ydb/core/persqueue/transaction.cpp index 63fe2a184b20..25d5ee46f01f 100644 --- a/ydb/core/persqueue/transaction.cpp +++ b/ydb/core/persqueue/transaction.cpp @@ -77,7 +77,7 @@ void TDistributedTransaction::InitPartitions(const google::protobuf::RepeatedPtr Partitions.clear(); for (auto& o : operations) { - if (!o.HasBegin()) { + if (!o.HasCommitOffsetsBegin()) { HasWriteOperations = true; } @@ -185,16 +185,16 @@ void TDistributedTransaction::OnProposeTransaction(const NKikimrPQ::TConfigTrans continue; } - if (node->Children.empty()) { - for (const auto* r : node->Parents) { + if (node->DirectChildren.empty()) { + for (const auto* r : node->DirectParents) { if (extractTabletId != r->TabletId) { PredicatesReceived[r->TabletId].SetTabletId(r->TabletId); } } } - for (const auto* r : node->Children) { - if (r->Children.empty()) { + for (const auto* r : node->DirectChildren) { + if (r->DirectChildren.empty()) { if (extractTabletId != r->TabletId) { PredicateRecipients[r->TabletId] = false; } diff --git a/ydb/core/persqueue/user_info.cpp b/ydb/core/persqueue/user_info.cpp index 92bf080dbf5c..9b8560576756 100644 --- a/ydb/core/persqueue/user_info.cpp +++ b/ydb/core/persqueue/user_info.cpp @@ -95,7 +95,7 @@ void TUsersInfoStorage::ParseDeprecated(const TString& key, const TString& data, Y_ABORT_UNLESS(offset <= (ui64)Max(), "Offset is too big: %" PRIu64, offset); if (!userInfo) { - Create(ctx, user, 0, false, session, 0, gen, step, static_cast(offset), 0, TInstant::Zero(), {}); + Create(ctx, user, 0, false, session, 0, gen, step, static_cast(offset), 0, TInstant::Zero(), {}, false); } else { userInfo->Session = session; userInfo->Generation = gen; @@ -123,7 +123,7 @@ void TUsersInfoStorage::Parse(const TString& key, const TString& data, const TAc Create( ctx, user, userData.GetReadRuleGeneration(), false, userData.GetSession(), userData.GetPartitionSessionId(), userData.GetGeneration(), userData.GetStep(), offset, - userData.GetOffsetRewindSum(), TInstant::Zero(), {} + userData.GetOffsetRewindSum(), TInstant::Zero(), {}, userData.GetAnyCommits() ); } else { userInfo->Session = userData.GetSession(); @@ -150,7 +150,7 @@ TUserInfo& TUsersInfoStorage::GetOrCreate(const TString& user, const TActorConte if (it == UsersInfo.end()) { return Create( ctx, user, readRuleGeneration ? *readRuleGeneration : ++CurReadRuleGeneration, false, "", 0, - 0, 0, 0, 0, TInstant::Zero(), {} + 0, 0, 0, 0, TInstant::Zero(), {}, false ); } return it->second; @@ -177,7 +177,7 @@ TUserInfo TUsersInfoStorage::CreateUserInfo(const TActorContext& ctx, const TString& session, ui64 partitionSessionId, ui32 gen, ui32 step, i64 offset, ui64 readOffsetRewindSum, - TInstant readFromTimestamp, const TActorId& pipeClient) const + TInstant readFromTimestamp, const TActorId& pipeClient, bool anyCommits) const { TString defaultServiceType = AppData(ctx)->PQConfig.GetDefaultClientServiceType().GetName(); TString userServiceType = ""; @@ -195,7 +195,7 @@ TUserInfo TUsersInfoStorage::CreateUserInfo(const TActorContext& ctx, ctx, StreamCountersSubgroup, user, readRuleGeneration, important, TopicConverter, Partition, session, partitionSessionId, gen, step, offset, readOffsetRewindSum, DCId, readFromTimestamp, DbPath, - meterRead, pipeClient + meterRead, pipeClient, anyCommits }; } @@ -203,16 +203,16 @@ TUserInfoBase TUsersInfoStorage::CreateUserInfo(const TString& user, TMaybe readRuleGeneration) const { return TUserInfoBase{user, readRuleGeneration ? *readRuleGeneration : ++CurReadRuleGeneration, - "", 0, 0, 0, false, {}, 0, {}}; + "", 0, 0, 0, false, false, {}, 0, {}}; } TUserInfo& TUsersInfoStorage::Create( const TActorContext& ctx, const TString& user, const ui64 readRuleGeneration, bool important, const TString& session, ui64 partitionSessionId, ui32 gen, ui32 step, i64 offset, ui64 readOffsetRewindSum, - TInstant readFromTimestamp, const TActorId& pipeClient + TInstant readFromTimestamp, const TActorId& pipeClient, bool anyCommits ) { auto userInfo = CreateUserInfo(ctx, user, readRuleGeneration, important, session, partitionSessionId, - gen, step, offset, readOffsetRewindSum, readFromTimestamp, pipeClient); + gen, step, offset, readOffsetRewindSum, readFromTimestamp, pipeClient, anyCommits); auto result = UsersInfo.emplace(user, std::move(userInfo)); Y_ABORT_UNLESS(result.second); return result.first->second; diff --git a/ydb/core/persqueue/user_info.h b/ydb/core/persqueue/user_info.h index d93da603a10a..86559394bd00 100644 --- a/ydb/core/persqueue/user_info.h +++ b/ydb/core/persqueue/user_info.h @@ -37,6 +37,25 @@ static const TString CLIENTID_WITHOUT_CONSUMER = "$without_consumer"; typedef TProtobufTabletLabeledCounters TUserLabeledCounters; +struct TMessageInfo { + TInstant CreateTimestamp; + TInstant WriteTimestamp; +}; + +struct TConsumerSnapshot { + TInstant Now; + + TMessageInfo LastCommittedMessage; + + i64 ReadOffset; + TInstant LastReadTimestamp; + TMessageInfo LastReadMessage; + + TDuration ReadLag; + TDuration CommitedLag; + TDuration TotalLag; +}; + struct TUserInfoBase { TString User; ui64 ReadRuleGeneration = 0; @@ -45,6 +64,7 @@ struct TUserInfoBase { ui32 Generation = 0; ui32 Step = 0; i64 Offset = 0; + bool AnyCommits = false; bool Important = false; TInstant ReadFromTimestamp; @@ -54,13 +74,20 @@ struct TUserInfoBase { }; struct TUserInfo: public TUserInfoBase { + bool ActualTimestamps = false; + // WriteTimestamp of the last committed message TInstant WriteTimestamp; + // CreateTimestamp of the last committed message TInstant CreateTimestamp; + + // Timstamp of the last read TInstant ReadTimestamp; - bool ActualTimestamps = false; i64 ReadOffset = -1; + + // WriteTimestamp of the last read message TInstant ReadWriteTimestamp; + // CreateTimestamp of the last read message TInstant ReadCreateTimestamp; ui64 ReadOffsetRewindSum = 0; @@ -170,17 +197,17 @@ struct TUserInfo: public TUserInfoBase { const ui64 readRuleGeneration, const bool important, const NPersQueue::TTopicConverterPtr& topicConverter, const ui32 partition, const TString& session, ui64 partitionSession, ui32 gen, ui32 step, i64 offset, const ui64 readOffsetRewindSum, const TString& dcId, TInstant readFromTimestamp, - const TString& dbPath, bool meterRead, const TActorId& pipeClient + const TString& dbPath, bool meterRead, const TActorId& pipeClient, bool anyCommits ) - : TUserInfoBase{user, readRuleGeneration, session, gen, step, offset, important, + : TUserInfoBase{user, readRuleGeneration, session, gen, step, offset, anyCommits, important, readFromTimestamp, partitionSession, pipeClient} - , WriteTimestamp(TAppData::TimeProvider->Now()) - , CreateTimestamp(TAppData::TimeProvider->Now()) - , ReadTimestamp(TAppData::TimeProvider->Now()) , ActualTimestamps(false) + , WriteTimestamp(TInstant::Zero()) + , CreateTimestamp(TInstant::Zero()) + , ReadTimestamp(TAppData::TimeProvider->Now()) , ReadOffset(-1) - , ReadWriteTimestamp(TAppData::TimeProvider->Now()) - , ReadCreateTimestamp(TAppData::TimeProvider->Now()) + , ReadWriteTimestamp(TInstant::Zero()) + , ReadCreateTimestamp(TInstant::Zero()) , ReadOffsetRewindSum(readOffsetRewindSum) , ReadScheduled(false) , HasReadRule(false) @@ -333,30 +360,9 @@ struct TUserInfo: public TUserInfoBase { return ReadTimestamp; } - TInstant GetWriteTimestamp(i64 endOffset) const { - return Offset == endOffset ? TAppData::TimeProvider->Now() : WriteTimestamp; - } - - TInstant GetCreateTimestamp(i64 endOffset) const { - return Offset == endOffset ? TAppData::TimeProvider->Now() : CreateTimestamp; - } - - TInstant GetReadWriteTimestamp(i64 endOffset) const { - TInstant ts = ReadOffset == -1 ? WriteTimestamp : ReadWriteTimestamp; - ts = GetReadOffset() >= endOffset ? TAppData::TimeProvider->Now() : ts; - return ts; - } - ui64 GetWriteLagMs() const { return WriteLagMs.GetValue(); } - - TInstant GetReadCreateTimestamp(i64 endOffset) const { - TInstant ts = ReadOffset == -1 ? CreateTimestamp : ReadCreateTimestamp; - ts = GetReadOffset() >= endOffset ? TAppData::TimeProvider->Now() : ts; - return ts; - } - }; class TUsersInfoStorage { @@ -388,7 +394,7 @@ class TUsersInfoStorage { TUserInfo& Create( const TActorContext& ctx, const TString& user, const ui64 readRuleGeneration, bool important, const TString& session, ui64 partitionSessionId, ui32 gen, ui32 step, i64 offset, ui64 readOffsetRewindSum, - TInstant readFromTimestamp, const TActorId& pipeClient + TInstant readFromTimestamp, const TActorId& pipeClient, bool anyCommits ); void Clear(const TActorContext& ctx); @@ -404,7 +410,7 @@ class TUsersInfoStorage { const TString& session, ui64 partitionSessionId, ui32 gen, ui32 step, i64 offset, ui64 readOffsetRewindSum, - TInstant readFromTimestamp, const TActorId& pipeClient) const; + TInstant readFromTimestamp, const TActorId& pipeClient, bool anyCommits) const; private: THashMap UsersInfo; diff --git a/ydb/core/persqueue/ut/common/autoscaling_ut_common.cpp b/ydb/core/persqueue/ut/common/autoscaling_ut_common.cpp index dc877d041c9e..779bf4776c94 100644 --- a/ydb/core/persqueue/ut/common/autoscaling_ut_common.cpp +++ b/ydb/core/persqueue/ut/common/autoscaling_ut_common.cpp @@ -261,7 +261,6 @@ std::shared_ptr::TSdkReadSession> TTestReadS TString{message.GetData()}, impl->AutoCommit) .WithMsg(new MsgWrapper(message)); - impl->ReceivedMessages.push_back(msg); if (impl->AutoCommit) { @@ -450,7 +449,7 @@ void TTestReadSession::WaitAllMessages() { template void TTestReadSession::Commit() { - Cerr << ">>>>> " << Impl->Name << " Commit all received messages" << Endl << Flush; + Cerr << ">>>>> " << Impl->Name << "Commit all received messages" << Endl << Flush; for (auto& m : Impl->ReceivedMessages) { if (!m.Commited) { m.Msg->Commit(); diff --git a/ydb/core/persqueue/ut/partition_ut.cpp b/ydb/core/persqueue/ut/partition_ut.cpp index 3cee045ea4c7..3a98fd2c6870 100644 --- a/ydb/core/persqueue/ut/partition_ut.cpp +++ b/ydb/core/persqueue/ut/partition_ut.cpp @@ -286,7 +286,7 @@ class TPartitionFixture : public NUnitTest::TBaseFixture { void SendReserveBytes(const ui64 cookie, const ui32 size, const TString& ownerCookie, const ui64 messageNo, bool lastRequest = false); void SendChangeOwner(const ui64 cookie, const TString& owner, const TActorId& pipeClient, const bool force = true); void SendWrite(const ui64 cookie, const ui64 messageNo, const TString& ownerCookie, const TMaybe offset, const TString& data, - bool ignoreQuotaDeadline = false, ui64 seqNo = 0); + bool ignoreQuotaDeadline = false, ui64 seqNo = 0, bool isDirectWrite = false); void SendGetWriteInfo(); void ShadowPartitionCountersTest(bool isFirstClass); @@ -302,6 +302,14 @@ class TPartitionFixture : public NUnitTest::TBaseFixture { void SendEvent(IEventBase* event); void SendEvent(IEventBase* event, const TActorId& from, const TActorId& to); + THolder WaitForRequestQuotaAndHoldApproveWriteQuota(); + void SendDeletePartition(); + void WaitForDeletePartitionDoneTimeout(); + void SendApproveWriteQuota(THolder&& event); + void WaitForQuotaConsumed(); + void WaitForWriteError(ui64 cookie, NPersQueue::NErrorCode::EErrorCode errorCode); + void WaitForDeletePartitionDone(); + TMaybe Ctx; TMaybe Finalizer; @@ -639,7 +647,7 @@ void TPartitionFixture::SendReserveBytes(const ui64 cookie, const ui32 size, con void TPartitionFixture::SendWrite (const ui64 cookie, const ui64 messageNo, const TString& ownerCookie, const TMaybe offset, const TString& data, - bool ignoreQuotaDeadline, ui64 seqNo + bool ignoreQuotaDeadline, ui64 seqNo, bool isDirectWrite ) { TEvPQ::TEvWrite::TMsg msg; msg.SourceId = "SourceId"; @@ -661,7 +669,7 @@ void TPartitionFixture::SendWrite TVector msgs; msgs.push_back(msg); - auto event = MakeHolder(cookie, messageNo, ownerCookie, offset, std::move(msgs), false, std::nullopt); + auto event = MakeHolder(cookie, messageNo, ownerCookie, offset, std::move(msgs), isDirectWrite, std::nullopt); Ctx->Runtime->SingleSys()->Send(new IEventHandle(ActorId, Ctx->Edge, event.Release())); } @@ -977,8 +985,8 @@ void TPartitionFixture::SendProposeTransactionRequest(ui32 partition, auto* body = event->Record.MutableData(); auto* operation = body->MutableOperations()->Add(); operation->SetPartitionId(partition); - operation->SetBegin(begin); - operation->SetEnd(end); + operation->SetCommitOffsetsBegin(begin); + operation->SetCommitOffsetsEnd(end); operation->SetConsumer(client); operation->SetPath(topic); body->SetImmediate(immediate); @@ -1372,6 +1380,92 @@ void TPartitionFixture::TestWriteSubDomainOutOfSpace(TDuration quotaWaitDuration } } +THolder TPartitionFixture::WaitForRequestQuotaAndHoldApproveWriteQuota() +{ + THolder approveWriteQuota; + + auto observer = [&approveWriteQuota](TAutoPtr& ev) mutable { + if (auto* event = ev->CastAsLocal()) { + approveWriteQuota = MakeHolder(event->Cookie, + event->AccountQuotaWaitTime, + event->PartitionQuotaWaitTime); + return TTestActorRuntimeBase::EEventAction::DROP; + } + return TTestActorRuntimeBase::EEventAction::PROCESS; + }; + auto prevObserver = Ctx->Runtime->SetObserverFunc(observer); + + TDispatchOptions options; + options.CustomFinalCondition = [&]() { + return approveWriteQuota != nullptr; + }; + UNIT_ASSERT(Ctx->Runtime->DispatchEvents(options)); + + Ctx->Runtime->SetObserverFunc(prevObserver); + + UNIT_ASSERT(approveWriteQuota != nullptr); + + return approveWriteQuota; +} + +void TPartitionFixture::SendDeletePartition() +{ + auto event = MakeHolder(); + Ctx->Runtime->SingleSys()->Send(new IEventHandle(ActorId, Ctx->Edge, event.Release())); +} + +void TPartitionFixture::WaitForDeletePartitionDoneTimeout() +{ + auto event = Ctx->Runtime->GrabEdgeEvent(TDuration::Seconds(3)); + UNIT_ASSERT_VALUES_EQUAL(event, nullptr); +} + +void TPartitionFixture::SendApproveWriteQuota(THolder&& event) +{ + Ctx->Runtime->SingleSys()->Send(new IEventHandle(ActorId, Ctx->Edge, event.Release())); + event = nullptr; +} + +void TPartitionFixture::WaitForQuotaConsumed() +{ + bool hasQuotaConsumed = false; + + auto observer = [&hasQuotaConsumed](TAutoPtr& ev) mutable { + if (auto* event = ev->CastAsLocal()) { + hasQuotaConsumed = true; + } + return TTestActorRuntimeBase::EEventAction::PROCESS; + }; + auto prevObserver = Ctx->Runtime->SetObserverFunc(observer); + + TDispatchOptions options; + options.CustomFinalCondition = [&]() { + return hasQuotaConsumed; + }; + UNIT_ASSERT(Ctx->Runtime->DispatchEvents(options)); + + Ctx->Runtime->SetObserverFunc(prevObserver); + + UNIT_ASSERT(hasQuotaConsumed); +} + +void TPartitionFixture::WaitForWriteError(ui64 cookie, NPersQueue::NErrorCode::EErrorCode errorCode) +{ + auto event = Ctx->Runtime->GrabEdgeEvent(); + + UNIT_ASSERT(event != nullptr); + + UNIT_ASSERT_VALUES_EQUAL(cookie, event->Cookie); + UNIT_ASSERT_C(errorCode == event->ErrorCode, "extected: " << (int)errorCode << ", accepted: " << (int)event->ErrorCode); +} + +void TPartitionFixture::WaitForDeletePartitionDone() +{ + auto event = Ctx->Runtime->GrabEdgeEvent(); + + UNIT_ASSERT(event != nullptr); +} + struct TTestUserAct { TSrcIdMap SourceIds = {}; TString ClientId = {}; @@ -3485,6 +3579,36 @@ Y_UNIT_TEST_F(EndWriteTimestamp_HeadKeys, TPartitionFixture) { UNIT_ASSERT_C(now - TDuration::Seconds(2) < endWriteTimestamp && endWriteTimestamp < now, "" << (now - TDuration::Seconds(2)) << " < " << endWriteTimestamp << " < " << now ); } // EndWriteTimestamp_FromMeta +Y_UNIT_TEST_F(The_DeletePartition_Message_Arrives_Before_The_ApproveWriteQuota_Message, TPartitionFixture) +{ + // create a supportive partition + const TPartitionId partitionId{1, TWriteId{2, 3}, 4}; + CreatePartition({.Partition=partitionId}); + + // write 2 messages in it + SendWrite(1, 0, "owner", 0, "message #1", false, 1, true); + SendWrite(2, 1, "owner", 1, "message #2", false, 2, true); + + // delay the response from the quoter + auto approveWriteQuota = WaitForRequestQuotaAndHoldApproveWriteQuota(); + + // Send a `TEvDeletePartition`. The partition will wait for the response from the quoter to arrive. + SendDeletePartition(); + WaitForDeletePartitionDoneTimeout(); + + // The answer is from the quoter + SendApproveWriteQuota(std::move(approveWriteQuota)); + WaitForQuotaConsumed(); + + WaitCmdWrite(); + SendCmdWriteResponse(NMsgBusProxy::MSTATUS_OK); + + // Write operations fail with an error + WaitForWriteError(1, NPersQueue::NErrorCode::ERROR); + WaitForDeletePartitionDone(); + WaitForWriteError(2, NPersQueue::NErrorCode::ERROR); +} + } // End of suite } // namespace diff --git a/ydb/core/persqueue/ut/partitiongraph_ut.cpp b/ydb/core/persqueue/ut/partitiongraph_ut.cpp index eb8d1cff01cf..43603f312ef8 100644 --- a/ydb/core/persqueue/ut/partitiongraph_ut.cpp +++ b/ydb/core/persqueue/ut/partitiongraph_ut.cpp @@ -59,22 +59,22 @@ Y_UNIT_TEST_SUITE(TPartitionGraphTest) { UNIT_ASSERT(n4); UNIT_ASSERT(n5); - UNIT_ASSERT_VALUES_EQUAL(n0->Parents.size(), 0); - UNIT_ASSERT_VALUES_EQUAL(n0->Children.size(), 0); - UNIT_ASSERT_VALUES_EQUAL(n0->HierarhicalParents.size(), 0); - - UNIT_ASSERT_VALUES_EQUAL(n1->Parents.size(), 0); - UNIT_ASSERT_VALUES_EQUAL(n1->Children.size(), 1); - UNIT_ASSERT_VALUES_EQUAL(n1->HierarhicalParents.size(), 0); - - UNIT_ASSERT_VALUES_EQUAL(n5->Parents.size(), 2); - UNIT_ASSERT_VALUES_EQUAL(n5->Children.size(), 0u); - UNIT_ASSERT_VALUES_EQUAL(n5->HierarhicalParents.size(), 4); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n0) == n5->HierarhicalParents.end()); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n1) != n5->HierarhicalParents.end()); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n2) != n5->HierarhicalParents.end()); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n3) != n5->HierarhicalParents.end()); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n4) != n5->HierarhicalParents.end()); + UNIT_ASSERT_VALUES_EQUAL(n0->DirectParents.size(), 0); + UNIT_ASSERT_VALUES_EQUAL(n0->DirectChildren.size(), 0); + UNIT_ASSERT_VALUES_EQUAL(n0->AllParents.size(), 0); + + UNIT_ASSERT_VALUES_EQUAL(n1->DirectParents.size(), 0); + UNIT_ASSERT_VALUES_EQUAL(n1->DirectChildren.size(), 1); + UNIT_ASSERT_VALUES_EQUAL(n1->AllParents.size(), 0); + + UNIT_ASSERT_VALUES_EQUAL(n5->DirectParents.size(), 2); + UNIT_ASSERT_VALUES_EQUAL(n5->DirectChildren.size(), 0u); + UNIT_ASSERT_VALUES_EQUAL(n5->AllParents.size(), 4); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n0) == n5->AllParents.end()); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n1) != n5->AllParents.end()); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n2) != n5->AllParents.end()); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n3) != n5->AllParents.end()); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n4) != n5->AllParents.end()); { std::set traversedNodes; diff --git a/ydb/core/persqueue/ut/pqtablet_ut.cpp b/ydb/core/persqueue/ut/pqtablet_ut.cpp index 86e5fe7f2df0..ad86fb76432d 100644 --- a/ydb/core/persqueue/ut/pqtablet_ut.cpp +++ b/ydb/core/persqueue/ut/pqtablet_ut.cpp @@ -331,8 +331,8 @@ void TPQTabletFixture::SendProposeTransactionRequest(const TProposeTransactionPa auto* operation = body->MutableOperations()->Add(); operation->SetPartitionId(txOp.Partition); if (txOp.Begin.Defined()) { - operation->SetBegin(*txOp.Begin); - operation->SetEnd(*txOp.End); + operation->SetCommitOffsetsBegin(*txOp.Begin); + operation->SetCommitOffsetsEnd(*txOp.End); operation->SetConsumer(*txOp.Consumer); } operation->SetPath(txOp.Path); diff --git a/ydb/core/persqueue/ut/user_action_processor_ut.cpp b/ydb/core/persqueue/ut/user_action_processor_ut.cpp index 27ed3ed4ad61..809a15874da3 100644 --- a/ydb/core/persqueue/ut/user_action_processor_ut.cpp +++ b/ydb/core/persqueue/ut/user_action_processor_ut.cpp @@ -653,8 +653,8 @@ void TUserActionProcessorFixture::SendProposeTransactionRequest(ui32 partition, auto* body = event->Record.MutableTxBody(); auto* operation = body->MutableOperations()->Add(); operation->SetPartitionId(partition); - operation->SetBegin(begin); - operation->SetEnd(end); + operation->SetCommitOffsetsBegin(begin); + operation->SetCommitOffsetsEnd(end); operation->SetConsumer(client); operation->SetPath(topic); body->SetImmediate(immediate); @@ -679,8 +679,8 @@ void TUserActionProcessorFixture::SendProposeTransactionRequest(const TProposeTr for (auto& txOp : params.TxOps) { auto* operation = body->MutableOperations()->Add(); operation->SetPartitionId(txOp.Partition); - operation->SetBegin(txOp.Begin); - operation->SetEnd(txOp.End); + operation->SetCommitOffsetsBegin(txOp.Begin); + operation->SetCommitOffsetsEnd(txOp.End); operation->SetConsumer(txOp.Consumer); operation->SetPath(txOp.Path); } diff --git a/ydb/core/persqueue/ut/ut_with_sdk/autoscaling_ut.cpp b/ydb/core/persqueue/ut/ut_with_sdk/autoscaling_ut.cpp index f101a70b5154..d560b8181d03 100644 --- a/ydb/core/persqueue/ut/ut_with_sdk/autoscaling_ut.cpp +++ b/ydb/core/persqueue/ut/ut_with_sdk/autoscaling_ut.cpp @@ -622,15 +622,78 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { readSession2->Close(); } - Y_UNIT_TEST(CommitTopPast_BeforeAutoscaleAwareSDK) { + Y_UNIT_TEST(PartitionSplit_OffsetCommit) { TTopicSdkTestSetup setup = CreateSetup(); - setup.CreateTopicWithAutoscale(std::string{TEST_TOPIC}, std::string{TEST_CONSUMER}, 1, 100); + setup.CreateTopicWithAutoscale(); + TTopicClient client = setup.MakeClient(); + + setup.Write("message-1", 0); + setup.Write("message-2", 0); + setup.Write("message-3", 0); + setup.Write("message-4", 0); + setup.Write("message-5", 0); + setup.Write("message-6", 0); + + { + ui64 txId = 1006; + SplitPartition(setup, ++txId, 0, "a"); + + auto describe = setup.DescribeTopic(); + UNIT_ASSERT_EQUAL(describe.GetPartitions().size(), 3); + } + + setup.Write("message-7", 1); + setup.Write("message-8", 1); + setup.Write("message-9", 1); + setup.Write("message-10", 1); + + { + ui64 txId = 1007; + SplitPartition(setup, ++txId, 1, "0"); + + auto describe = setup.DescribeTopic(); + UNIT_ASSERT_EQUAL(describe.GetPartitions().size(), 5); + } + + setup.Write("message-11", 3); + setup.Write("message-12", 3); + + auto assertCommittedOffset = [&](size_t partition, size_t expectedOffset, const std::string& msg = "") { + auto description = setup.DescribeConsumer(); + auto stats = description.GetPartitions().at(partition).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + UNIT_ASSERT_VALUES_EQUAL_C(expectedOffset, stats->GetCommittedOffset(), "Partition " << partition << ": " << msg); + }; + + { + static constexpr size_t commited = 2; + auto status = setup.Commit(TEST_TOPIC, TEST_CONSUMER, 1, commited); + UNIT_ASSERT(status.IsSuccess()); + + assertCommittedOffset(0, 6, "Must be commited to the partition end because it is the parent"); + assertCommittedOffset(1, commited); + assertCommittedOffset(3, 0); + } + + { + static constexpr size_t commited = 3; + auto status = setup.Commit(TEST_TOPIC, TEST_CONSUMER, 0, commited); + UNIT_ASSERT(status.IsSuccess()); + + assertCommittedOffset(0, commited); + assertCommittedOffset(1, 0, "Must be commited to the partition begin because it is the child"); + assertCommittedOffset(3, 0); + } + } + + Y_UNIT_TEST(CommitTopPast) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopicWithAutoscale(); TTopicClient client = setup.MakeClient(); - auto writeSession = CreateWriteSession(client, "producer-1", 0); - UNIT_ASSERT(writeSession->Write(Msg("message_1", 2))); - UNIT_ASSERT(writeSession->Write(Msg("message_2", 3))); + setup.Write("message_1", 0); + setup.Write("message_2", 0); ui64 txId = 1023; SplitPartition(setup, ++txId, 0, "a"); @@ -648,7 +711,7 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { UNIT_ASSERT_VALUES_EQUAL_C(NYdb::EStatus::SUCCESS, status.GetStatus(), "The consumer can commit at the end of the inactive partition."); status = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 0).GetValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(NYdb::EStatus::BAD_REQUEST, status.GetStatus(), "The consumer cannot commit an offset for inactive, read-to-the-end partitions."); + UNIT_ASSERT_VALUES_EQUAL_C(NYdb::EStatus::SUCCESS, status.GetStatus(), "The consumer can commit an offset for inactive, read-to-the-end partitions."); } Y_UNIT_TEST(ControlPlane_CreateAlterDescribe) { @@ -869,6 +932,409 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), NYdb::EStatus::BAD_REQUEST); } + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopicWithAutoscale(); + TTopicClient client = setup.MakeClient(); + + setup.Write("message-1", 0, "producer-1", 1); + setup.Write("message-2", 0, "producer-1", 2); + setup.Write("message-3", 0, "producer-1", 3); + setup.Write("message-4", 0, "producer-1", 4); + setup.Write("message-5", 0, "producer-1", 5); + setup.Write("message-6", 0, "producer-2", 6); + + { + ui64 txId = 1006; + SplitPartition(setup, ++txId, 0, "a"); + + auto describe = setup.DescribeTopic(); + UNIT_ASSERT_EQUAL(describe.GetPartitions().size(), 3); + } + + setup.Write("message-7", 1, "producer-1", 7); + setup.Write("message-8", 1, "producer-1", 8); + setup.Write("message-9", 1, "producer-1", 9); + setup.Write("message-10", 1, "producer-2", 10); + + { + ui64 txId = 1007; + SplitPartition(setup, ++txId, 1, "0"); + + auto describe = setup.DescribeTopic(); + UNIT_ASSERT_EQUAL(describe.GetPartitions().size(), 5); + } + + auto count = 0; + const auto expected = 10; + + auto result = setup.Read(TEST_TOPIC, TEST_CONSUMER, [&](auto& x) { + auto& messages = x.GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + ++count; + auto& message = messages[i]; + Cerr << "SESSION EVENT read message: " << count << " from partition: " << message.GetPartitionSession()->GetPartitionId() << Endl << Flush; + message.Commit(); + } + + return true; + }); + + UNIT_ASSERT(result.Timeout); + UNIT_ASSERT_VALUES_EQUAL(count, expected); + + auto description = setup.DescribeConsumer(); + UNIT_ASSERT(description.GetPartitions().size() == 5); + + auto stats1 = description.GetPartitions().at(1).GetPartitionConsumerStats(); + UNIT_ASSERT(stats1); + UNIT_ASSERT(stats1->GetCommittedOffset() == 4); + } + + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit_ChildFirst) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopicWithAutoscale(); + + TTopicClient client = setup.MakeClient(); + + setup.Write("message-1", 0, "producer-1", 1); + setup.Write("message-2", 0, "producer-1", 2); + setup.Write("message-3", 0, "producer-1", 3); + setup.Write("message-4", 0, "producer-1", 4); + setup.Write("message-5", 0, "producer-1", 5); + setup.Write("message-6", 0, "producer-2", 6); + + { + ui64 txId = 1006; + SplitPartition(setup, ++txId, 0, "a"); + + auto describe = setup.DescribeTopic(); + UNIT_ASSERT_EQUAL(describe.GetPartitions().size(), 3); + } + + setup.Write("message-7", 1, "producer-1", 7); + setup.Write("message-8", 1, "producer-1", 8); + setup.Write("message-9", 1, "producer-1", 9); + setup.Write("message-10", 1, "producer-2", 10); + + { + ui64 txId = 1007; + SplitPartition(setup, ++txId, 1, "0"); + + auto describe = setup.DescribeTopic(); + UNIT_ASSERT_EQUAL(describe.GetPartitions().size(), 5); + } + + + auto count = 0; + const auto expected = 10; + + std::vector partition0Messages; + + auto result = setup.Read(TEST_TOPIC, TEST_CONSUMER, [&](auto& x) { + auto& messages = x.GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + auto& message = messages[i]; + count++; + int partitionId = message.GetPartitionSession()->GetPartitionId(); + Cerr << "SESSION EVENT read message: " << count << " from partition: " << partitionId << Endl << Flush; + if (partitionId == 1) { + // Commit messages from partition 1 immediately + message.Commit(); + } else if (partitionId == 0) { + // Store messages from partition 0 for later + partition0Messages.push_back(message); + } + } + + return true; + }); + + UNIT_ASSERT(result.Timeout); + UNIT_ASSERT_VALUES_EQUAL(count, expected); + + Sleep(TDuration::Seconds(5)); + + { + auto description = setup.DescribeConsumer(); + auto stats = description.GetPartitions().at(1).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + + // Messages in the parent partition hasn't been committed + UNIT_ASSERT_VALUES_EQUAL(stats->GetCommittedOffset(), 0); + } + + for (auto& message : partition0Messages) { + message.Commit(); + } + + Sleep(TDuration::Seconds(5)); + + { + auto description = setup.DescribeConsumer(); + auto stats = description.GetPartitions().at(1).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + + UNIT_ASSERT_VALUES_EQUAL(stats->GetCommittedOffset(), 4); + } + } + + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit_CheckSessionResetAfterCommit) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopicWithAutoscale(); + + TTopicClient client = setup.MakeClient(); + + auto seqNo = 1; + + setup.Write("message-1", 0, "producer-1", seqNo++); + setup.Write("message-2", 0, "producer-1", seqNo++); + setup.Write("message-3", 0, "producer-1", seqNo++); + setup.Write("message-4", 0, "producer-1", seqNo++); + setup.Write("message-5", 0, "producer-1", seqNo++); + setup.Write("message-6", 0, "producer-2", seqNo++); + + { + ui64 txId = 1006; + SplitPartition(setup, ++txId, 0, "a"); + + auto describe = setup.DescribeTopic(); + UNIT_ASSERT_EQUAL(describe.GetPartitions().size(), 3); + } + + setup.Write("message-7", 1, "producer-2", seqNo++); + setup.Write("message-8", 1, "producer-2", seqNo++); + + std::vector counters; + counters.resize(seqNo - 1); + + auto result = setup.Read(TEST_TOPIC, TEST_CONSUMER, [&](auto& x) { + auto& messages = x.GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + auto& message = messages[i]; + message.Commit(); + Cerr << "SESSION EVENT READ SeqNo: " << message.GetSeqNo() << Endl << Flush; + auto count = ++counters[message.GetSeqNo() - 1]; + + // check we get this SeqNo two times + if (message.GetSeqNo() == 6 && count == 1) { + Sleep(TDuration::MilliSeconds(300)); + auto status = setup.Commit(TEST_TOPIC, TEST_CONSUMER, 0, 3); + UNIT_ASSERT(status.IsSuccess()); + } + } + + return true; + }); + + UNIT_ASSERT_VALUES_EQUAL_C(1, counters[0], TStringBuilder() << "Message must be read 1 times because reset commit to offset 3, but 0 message has been read " << counters[0] << " times") ; + UNIT_ASSERT_VALUES_EQUAL_C(1, counters[1], TStringBuilder() << "Message must be read 1 times because reset commit to offset 3, but 1 message has been read " << counters[1] << " times") ; + UNIT_ASSERT_VALUES_EQUAL_C(1, counters[2], TStringBuilder() << "Message must be read 1 times because reset commit to offset 3, but 2 message has been read " << counters[2] << " times") ; + + UNIT_ASSERT_VALUES_EQUAL_C(2, counters[3], TStringBuilder() << "Message 1 must be read two times, but 3 message has been read " << counters[3] << " times") ; + UNIT_ASSERT_VALUES_EQUAL_C(2, counters[4], TStringBuilder() << "Message 1 must be read two times, but 4 message has been read " << counters[4] << " times") ; + UNIT_ASSERT_VALUES_EQUAL_C(2, counters[5], TStringBuilder() << "Message 1 must be read two times, but 5 message has been read " << counters[5] << " times") ; + + { + auto s = result.StartPartitionSessionEvents[0]; + UNIT_ASSERT_VALUES_EQUAL(0, s.GetPartitionSession()->GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(0, s.GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(6, s.GetEndOffset()); + } + { + auto s = result.StartPartitionSessionEvents[3]; + UNIT_ASSERT_VALUES_EQUAL(0, s.GetPartitionSession()->GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(3, s.GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(6, s.GetEndOffset()); + } + } + + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit_CheckOffsetCommitForDifferentCases_SplitedTopic) { + TTopicSdkTestSetup setup = CreateSetup(); + TTopicClient client = setup.MakeClient(); + + setup.CreateTopicWithAutoscale(); + + auto commit = [&](const std::string& sessionId, ui64 offset) { + return setup.Commit(TEST_TOPIC, TEST_CONSUMER, 0, offset, sessionId); + }; + + auto getConsumerState = [&](ui32 partition) { + auto description = setup.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER); + + auto stats = description.GetPartitions().at(partition).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + return stats; + }; + + setup.Write("message-1", 0, "producer-1", 1); + setup.Write("message-2", 0, "producer-1", 2); + setup.Write("message-3", 0, "producer-1", 3); + setup.Write("message-4", 0, "producer-1", 4); + setup.Write("message-5", 0, "producer-1", 5); + setup.Write("message-6", 0, "producer-1", 6); + setup.Write("message-7", 0, "producer-1", 7); + setup.Write("message-8", 0, "producer-2", 8); + + { + ui64 txId = 1006; + SplitPartition(setup, ++txId, 0, "a"); + + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 3); + } + + setup.Write("message-9", 1, "producer-2", 9); + setup.Write("message-10", 1, "producer-2", 10); + + auto commitSent = false; + TString readSessionId = ""; + + setup.Read(TEST_TOPIC, TEST_CONSUMER, [&](auto& x) { + auto& messages = x.GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + auto& message = messages[i]; + Cerr << "SESSION EVENT READ SeqNo: " << message.GetSeqNo() << Endl << Flush; + + if (commitSent) { + // read session not changed + UNIT_ASSERT_EQUAL(readSessionId, message.GetPartitionSession()->GetReadSessionId()); + } + + // check we NOT get this SeqNo two times + if (message.GetSeqNo() == 6) { + if (!commitSent) { + commitSent = true; + + readSessionId = message.GetPartitionSession()->GetReadSessionId(); + + { + auto status = commit(message.GetPartitionSession()->GetReadSessionId(), 8); + UNIT_ASSERT(status.IsSuccess()); + + auto stats = getConsumerState(0); + UNIT_ASSERT_VALUES_EQUAL(stats->GetCommittedOffset(), 8); + } + + { + // must be ignored, because commit to past + auto status = commit(message.GetPartitionSession()->GetReadSessionId(), 0); + UNIT_ASSERT(status.IsSuccess()); + + auto stats = getConsumerState(0); + UNIT_ASSERT_VALUES_EQUAL(stats->GetCommittedOffset(), 8); + } + + /* TODO uncomment this + { + // must be ignored, because wrong sessionid + auto status = commit("random session", 0); + UNIT_ASSERT(!status.IsSuccess()); + + Sleep(TDuration::MilliSeconds(500)); + + auto stats = getConsumerState(0); + UNIT_ASSERT_VALUES_EQUAL(stats->GetCommittedOffset(), 8); + } + */ + } else { + UNIT_ASSERT(false); + } + } else { + message.Commit(); + } + } + + return true; + }); + } + + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit_CheckOffsetCommitForDifferentCases_NotSplitedTopic) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopicWithAutoscale(); + TTopicClient client = setup.MakeClient(); + + auto commit = [&](const std::string& sessionId, ui64 offset) { + return setup.Commit(TEST_TOPIC, TEST_CONSUMER, 0, offset, sessionId); + }; + + auto getConsumerState = [&](ui32 partition) { + auto description = setup.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER); + + auto stats = description.GetPartitions().at(partition).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + return stats; + }; + + setup.Write("message-1", 0, "producer-1", 1); + setup.Write("message-2", 0, "producer-1", 2); + setup.Write("message-3", 0, "producer-1", 3); + setup.Write("message-4", 0, "producer-1", 4); + setup.Write("message-5", 0, "producer-1", 5); + setup.Write("message-6", 0, "producer-1", 6); + setup.Write("message-7", 0, "producer-1", 7); + setup.Write("message-8", 0, "producer-2", 8); + + auto commitSent = false; + TString readSessionId = ""; + + setup.Read(TEST_TOPIC, TEST_CONSUMER, [&](auto& x) { + auto& messages = x.GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + auto& message = messages[i]; + + if (commitSent) { + // read session not changed + UNIT_ASSERT_EQUAL(readSessionId, message.GetPartitionSession()->GetReadSessionId()); + } + + // check we NOT get this SeqNo two times + if (message.GetSeqNo() == 6) { + if (!commitSent) { + commitSent = true; + readSessionId = message.GetPartitionSession()->GetReadSessionId(); + + Sleep(TDuration::MilliSeconds(300)); + + { + auto status = commit(message.GetPartitionSession()->GetReadSessionId(), 8); + UNIT_ASSERT(status.IsSuccess()); + + auto stats = getConsumerState(0); + UNIT_ASSERT_VALUES_EQUAL(stats->GetCommittedOffset(), 8); + } + + { + // must be ignored, because commit to past + auto status = commit(message.GetPartitionSession()->GetReadSessionId(), 0); + UNIT_ASSERT(status.IsSuccess()); + + auto stats = getConsumerState(0); + UNIT_ASSERT_VALUES_EQUAL(stats->GetCommittedOffset(), 8); + } + + { + // must be ignored, because wrong sessionid + auto status = commit("random session", 0); + UNIT_ASSERT(!status.IsSuccess()); + + Sleep(TDuration::MilliSeconds(500)); + + auto stats = getConsumerState(0); + UNIT_ASSERT_VALUES_EQUAL(stats->GetCommittedOffset(), 8); + } + } else { + UNIT_ASSERT(false); + } + } else { + message.Commit(); + } + } + + return true; + }); + } + Y_UNIT_TEST(PartitionSplit_AutosplitByLoad) { TTopicSdkTestSetup setup = CreateSetup(); TTopicClient client = setup.MakeClient(); @@ -902,10 +1368,10 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { { UNIT_ASSERT(writeSession_1->Write(Msg(msg, 3))); - UNIT_ASSERT(writeSession_2->Write(Msg(msg, 4))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 4))); UNIT_ASSERT(writeSession_1->Write(Msg(msg, 5))); UNIT_ASSERT(writeSession_2->Write(Msg(msg, 6))); - Sleep(TDuration::Seconds(5)); + Sleep(TDuration::Seconds(15)); auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 3); } @@ -915,7 +1381,7 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { { UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 7))); - UNIT_ASSERT(writeSession2_2->Write(Msg(msg, 8))); + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 8))); UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 9))); UNIT_ASSERT(writeSession2_2->Write(Msg(msg, 10))); Sleep(TDuration::Seconds(5)); diff --git a/ydb/core/persqueue/ut/ut_with_sdk/topic_ut.cpp b/ydb/core/persqueue/ut/ut_with_sdk/topic_ut.cpp new file mode 100644 index 000000000000..5cc8256aaa09 --- /dev/null +++ b/ydb/core/persqueue/ut/ut_with_sdk/topic_ut.cpp @@ -0,0 +1,254 @@ +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace NKikimr { + +using namespace NYdb::NTopic; +using namespace NYdb::NTopic::NTests; +using namespace NSchemeShardUT_Private; +using namespace NKikimr::NPQ::NTest; + +#define UNIT_ASSERT_TIME_EQUAL(A, B, D) \ + do { \ + if (!(((A - B) >= TDuration::Zero()) && ((A - B) <= D)) \ + && !(((B - A) >= TDuration::Zero()) && ((B - A) <= D))) { \ + auto&& failMsg = Sprintf("%s and %s diferent more then %s", (::TStringBuilder() << A).data(), \ + (::TStringBuilder() << B).data(), (::TStringBuilder() << D).data()); \ + UNIT_FAIL_IMPL("assertion failure", failMsg); \ + } \ + } while (false) + + +Y_UNIT_TEST_SUITE(WithSDK) { + + Y_UNIT_TEST(DescribeConsumer) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopic(std::string{TEST_TOPIC}, std::string{TEST_CONSUMER}, 1); + + auto describe = [&]() { + return setup.DescribeConsumer(TString{TEST_TOPIC}, TString{TEST_CONSUMER}); + }; + + auto write = [&](size_t seqNo) { + TTopicClient client(setup.MakeDriver()); + + TWriteSessionSettings settings; + settings.Path(TEST_TOPIC); + settings.PartitionId(0); + settings.DeduplicationEnabled(false); + auto session = client.CreateSimpleBlockingWriteSession(settings); + + TString msgTxt = TStringBuilder() << "message_" << seqNo; + TWriteMessage msg(msgTxt); + msg.CreateTimestamp(TInstant::Now() - TDuration::Seconds(10 - seqNo)); + UNIT_ASSERT(session->Write(std::move(msg))); + + session->Close(TDuration::Seconds(5)); + }; + + // Check describe for empty topic + { + auto d = describe(); + UNIT_ASSERT_STRINGS_EQUAL(TEST_CONSUMER, d.GetConsumer().GetConsumerName()); + UNIT_ASSERT_VALUES_EQUAL(1, d.GetPartitions().size()); + auto& p = d.GetPartitions()[0]; + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(true, p.GetActive()); + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionStats()->GetEndOffset()); + auto& c = p.GetPartitionConsumerStats(); + UNIT_ASSERT_VALUES_EQUAL(true, c.has_value()); + UNIT_ASSERT_VALUES_EQUAL(0, c->GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxWriteTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxReadTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxCommittedTimeLag()); + UNIT_ASSERT_TIME_EQUAL(TInstant::Now(), c->GetLastReadTime(), TDuration::Seconds(3)); // why not zero? + UNIT_ASSERT_VALUES_EQUAL(0, c->GetLastReadOffset()); + } + + write(3); + write(7); + + // Check describe for topic which contains messages, but consumer hasn`t read + { + auto d = describe(); + UNIT_ASSERT_STRINGS_EQUAL(TEST_CONSUMER, d.GetConsumer().GetConsumerName()); + UNIT_ASSERT_VALUES_EQUAL(1, d.GetPartitions().size()); + auto& p = d.GetPartitions()[0]; + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(true, p.GetActive()); + UNIT_ASSERT_VALUES_EQUAL(2, p.GetPartitionStats()->GetEndOffset()); + auto& c = p.GetPartitionConsumerStats(); + UNIT_ASSERT_VALUES_EQUAL(true, c.has_value()); + UNIT_ASSERT_VALUES_EQUAL(0, c->GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(7), c->GetMaxWriteTimeLag()); // + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxReadTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxCommittedTimeLag()); + UNIT_ASSERT_TIME_EQUAL(TInstant::Now(), c->GetLastReadTime(), TDuration::Seconds(3)); // why not zero? + UNIT_ASSERT_VALUES_EQUAL(1, c->GetLastReadOffset()); + } + + UNIT_ASSERT(setup.Commit(TString{TEST_TOPIC}, TEST_CONSUMER, 0, 1).IsSuccess()); + + // Check describe for topic whis contains messages, has commited offset but hasn`t read (restart tablet for example) + { + auto d = describe(); + UNIT_ASSERT_STRINGS_EQUAL(TEST_CONSUMER, d.GetConsumer().GetConsumerName()); + UNIT_ASSERT_VALUES_EQUAL(1, d.GetPartitions().size()); + auto& p = d.GetPartitions()[0]; + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(true, p.GetActive()); + UNIT_ASSERT_VALUES_EQUAL(2, p.GetPartitionStats()->GetEndOffset()); + auto& c = p.GetPartitionConsumerStats(); + UNIT_ASSERT_VALUES_EQUAL(true, c.has_value()); + UNIT_ASSERT_VALUES_EQUAL(1, c->GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(7), c->GetMaxWriteTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxReadTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxCommittedTimeLag()); + UNIT_ASSERT_TIME_EQUAL(TInstant::Now(), c->GetLastReadTime(), TDuration::Seconds(3)); // why not zero? + UNIT_ASSERT_VALUES_EQUAL(1, c->GetLastReadOffset()); + } + + { + TTopicClient client(setup.MakeDriver()); + TReadSessionSettings settings; + settings.ConsumerName(TEST_CONSUMER); + settings.AppendTopics(TTopicReadSettings().Path(TEST_TOPIC)); + + auto session = client.CreateReadSession(settings); + + TInstant endTime = TInstant::Now() + TDuration::Seconds(5); + while (true) { + auto e = session->GetEvent(); + if (e) { + Cerr << ">>>>> Event = " << e->index() << Endl << Flush; + } + if (e && std::holds_alternative(e.value())) { + // we must recive only one date event with second message + break; + } else if (e && std::holds_alternative(e.value())) { + std::get(e.value()).Confirm(); + } + UNIT_ASSERT_C(endTime > TInstant::Now(), "Unable wait"); + } + + session->Close(TDuration::Seconds(1)); + } + + // Check describe for topic wich contains messages, has commited offset of first message and read second message + { + auto d = describe(); + UNIT_ASSERT_STRINGS_EQUAL(TEST_CONSUMER, d.GetConsumer().GetConsumerName()); + UNIT_ASSERT_VALUES_EQUAL(1, d.GetPartitions().size()); + auto& p = d.GetPartitions()[0]; + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(true, p.GetActive()); + UNIT_ASSERT_VALUES_EQUAL(2, p.GetPartitionStats()->GetEndOffset()); + auto& c = p.GetPartitionConsumerStats(); + UNIT_ASSERT_VALUES_EQUAL(true, c.has_value()); + UNIT_ASSERT_VALUES_EQUAL(1, c->GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(7), c->GetMaxWriteTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxReadTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxCommittedTimeLag()); + UNIT_ASSERT_TIME_EQUAL(TInstant::Now(), c->GetLastReadTime(), TDuration::Seconds(3)); + UNIT_ASSERT_VALUES_EQUAL(2, c->GetLastReadOffset()); + } + } + + Y_UNIT_TEST(CommitWithWrongSessionId) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopic(std::string{TEST_TOPIC}, std::string{TEST_CONSUMER}, 1); + + setup.Write("message-1"); + setup.Write("message-2"); + setup.Write("message-3"); + + { + auto result = setup.Commit(TString(TEST_TOPIC), TEST_CONSUMER, 0, 1, "wrong-read-session-id"); + UNIT_ASSERT_C(!result.IsSuccess(), "Commit doesn`t work with wrong session id"); + + auto desc = setup.DescribeConsumer(TString(TEST_TOPIC), TEST_CONSUMER); + UNIT_ASSERT_VALUES_EQUAL(0, desc.GetPartitions().at(0).GetPartitionConsumerStats()->GetCommittedOffset()); + } + } + + Y_UNIT_TEST(CommitToPastWithWrongSessionId) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopic(std::string{TEST_TOPIC}, std::string{TEST_CONSUMER}, 1); + + setup.Write("message-1"); + setup.Write("message-2"); + setup.Write("message-3"); + + { + auto result = setup.Commit(TString(TEST_TOPIC), TEST_CONSUMER, 0, 2); + UNIT_ASSERT_C(result.IsSuccess(), "Commited without session id. It is reset mode"); + + auto desc = setup.DescribeConsumer(TString(TEST_TOPIC), TEST_CONSUMER); + UNIT_ASSERT_VALUES_EQUAL(2, desc.GetPartitions().at(0).GetPartitionConsumerStats()->GetCommittedOffset()); + } + + { + auto result = setup.Commit(TString(TEST_TOPIC), TEST_CONSUMER, 0, 0, "wrong-read-session-id"); + UNIT_ASSERT_C(!result.IsSuccess(), "Commit doesn`t work with wrong session id"); + + auto desc = setup.DescribeConsumer(TString(TEST_TOPIC), TEST_CONSUMER); + UNIT_ASSERT_VALUES_EQUAL(2, desc.GetPartitions().at(0).GetPartitionConsumerStats()->GetCommittedOffset()); + } + } + + /* TODO Uncomment this test + Y_UNIT_TEST(CommitToParentPartitionWithWrongSessionId) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopicWithAutoscale(); + + setup.Write("message-1", 0); + + { + ui64 txId = 1006; + SplitPartition(setup, ++txId, 0, "a"); + } + + setup.Write("message-2", 1); + + Cerr << ">>>>> BEGIN 0" << Endl << Flush; + { + auto result = setup.Commit(TString(TEST_TOPIC), TEST_CONSUMER, 0, 1); + UNIT_ASSERT_C(result.IsSuccess(), "Commited without session id. It is reset mode"); + + auto desc = setup.DescribeConsumer(TString(TEST_TOPIC), TEST_CONSUMER); + UNIT_ASSERT_VALUES_EQUAL(1, desc.GetPartitions().at(0).GetPartitionConsumerStats()->GetCommittedOffset()); + } + + Cerr << ">>>>> BEGIN 1" << Endl << Flush; + { + auto result = setup.Commit(TString(TEST_TOPIC), TEST_CONSUMER, 1, 1); + UNIT_ASSERT_C(result.IsSuccess(), "Commited without session id. It is reset mode"); + + auto desc = setup.DescribeConsumer(TString(TEST_TOPIC), TEST_CONSUMER); + UNIT_ASSERT_VALUES_EQUAL(1, desc.GetPartitions().at(1).GetPartitionConsumerStats()->GetCommittedOffset()); + } + + Cerr << ">>>>> BEGIN 2" << Endl << Flush; + { + auto result = setup.Commit(TString(TEST_TOPIC), TEST_CONSUMER, 0, 0, "wrong-read-session-id"); + UNIT_ASSERT_C(!result.IsSuccess(), "Commit doesn`t work with wrong session id"); + + auto desc = setup.DescribeConsumer(TString(TEST_TOPIC), TEST_CONSUMER); + UNIT_ASSERT_VALUES_EQUAL_C(1, desc.GetPartitions().at(0).GetPartitionConsumerStats()->GetCommittedOffset(), "Offset doesn`t changed"); + } + Cerr << ">>>>> END" << Endl << Flush; + + } + */ +} + +} // namespace NKikimr diff --git a/ydb/core/persqueue/ut/ut_with_sdk/ya.make b/ydb/core/persqueue/ut/ut_with_sdk/ya.make index fdb6c2ff4054..eb370dff0244 100644 --- a/ydb/core/persqueue/ut/ut_with_sdk/ya.make +++ b/ydb/core/persqueue/ut/ut_with_sdk/ya.make @@ -32,6 +32,7 @@ SRCS( autoscaling_ut.cpp balancing_ut.cpp mirrorer_ut.cpp + topic_ut.cpp ) END() diff --git a/ydb/core/persqueue/utils.cpp b/ydb/core/persqueue/utils.cpp index 7f7ca3d81e10..ccdc3ffe95c2 100644 --- a/ydb/core/persqueue/utils.cpp +++ b/ydb/core/persqueue/utils.cpp @@ -170,10 +170,10 @@ std::set TPartitionGraph::GetActiveChildren(ui32 id) const { const auto* n = queue.front(); queue.pop_front(); - if (n->Children.empty()) { + if (n->DirectChildren.empty()) { result.emplace(n->Id); } else { - queue.insert(queue.end(), n->Children.begin(), n->Children.end()); + queue.insert(queue.end(), n->DirectChildren.begin(), n->DirectChildren.end()); } } @@ -186,7 +186,7 @@ void Travers0(std::deque& queue, const std::functi queue.pop_front(); if (func(node->Id)) { - queue.insert(queue.end(), node->Children.begin(), node->Children.end()); + queue.insert(queue.end(), node->DirectChildren.begin(), node->DirectChildren.end()); } } } @@ -203,7 +203,7 @@ void TPartitionGraph::Travers(const std::function& func) const { continue; } - queue.insert(queue.end(), n.Children.begin(), n.Children.end()); + queue.insert(queue.end(), n.DirectChildren.begin(), n.DirectChildren.end()); } Travers0(queue, func); @@ -220,7 +220,7 @@ void TPartitionGraph::Travers(ui32 id, const std::function& func } std::deque queue; - queue.insert(queue.end(), n->Children.begin(), n->Children.end()); + queue.insert(queue.end(), n->DirectChildren.begin(), n->DirectChildren.end()); Travers0(queue, func); } @@ -266,17 +266,18 @@ std::unordered_map BuildGraph(const TCollection& pa } std::deque queue; - for(const auto& p : partitions) { + + for (const auto& p : partitions) { auto& node = result[GetPartitionId(p)]; - node.Children.reserve(p.ChildPartitionIdsSize()); + node.DirectChildren.reserve(p.ChildPartitionIdsSize()); for (auto id : p.GetChildPartitionIds()) { - node.Children.push_back(&result[id]); + node.DirectChildren.push_back(&result[id]); } - node.Parents.reserve(p.ParentPartitionIdsSize()); + node.DirectParents.reserve(p.ParentPartitionIdsSize()); for (auto id : p.GetParentPartitionIds()) { - node.Parents.push_back(&result[id]); + node.DirectParents.push_back(&result[id]); } if (p.GetParentPartitionIds().empty()) { @@ -284,24 +285,39 @@ std::unordered_map BuildGraph(const TCollection& pa } } - while(!queue.empty()) { + while (!queue.empty()) { auto* n = queue.front(); queue.pop_front(); bool allCompleted = true; - for(auto* c : n->Parents) { - if (c->HierarhicalParents.empty() && !c->Parents.empty()) { + for (auto* c : n->DirectParents) { + if (c->AllParents.empty() && !c->DirectParents.empty()) { allCompleted = false; break; } } if (allCompleted) { - for(auto* c : n->Parents) { - n->HierarhicalParents.insert(c->HierarhicalParents.begin(), c->HierarhicalParents.end()); - n->HierarhicalParents.insert(c); + for (auto* c : n->DirectParents) { + n->AllParents.insert(c->AllParents.begin(), c->AllParents.end()); + n->AllParents.insert(c); + } + queue.insert(queue.end(), n->DirectChildren.begin(), n->DirectChildren.end()); + } + } + + for (auto& [_, node] : result) { + queue.push_back(&node); + + while (!queue.empty()) { + auto* current = queue.front(); + queue.pop_front(); + + for (auto* child : current->DirectChildren) { + if (node.AllChildren.insert(child).second) { + queue.push_back(child); + } } - queue.insert(queue.end(), n->Children.begin(), n->Children.end()); } } @@ -316,11 +332,11 @@ TPartitionGraph::Node::Node(ui32 id, ui64 tabletId, const TString& from, const T } bool TPartitionGraph::Node::IsRoot() const { - return Parents.empty(); + return DirectParents.empty(); } bool TPartitionGraph::Node::IsParent(ui32 partitionId) const { - return AnyOf(Parents, [=](const auto& p) { + return AnyOf(DirectParents, [=](const auto& p) { return p->Id == partitionId; }); } diff --git a/ydb/core/persqueue/utils.h b/ydb/core/persqueue/utils.h index 4b4b296bdbb0..43eb519f85ef 100644 --- a/ydb/core/persqueue/utils.h +++ b/ydb/core/persqueue/utils.h @@ -44,11 +44,13 @@ class TPartitionGraph { TString To; // Direct parents of this node - std::vector Parents; + std::vector DirectParents; // Direct children of this node - std::vector Children; + std::vector DirectChildren; // All parents include parents of parents and so on - std::set HierarhicalParents; + std::set AllParents; + // All children include children of children and so on + std::set AllChildren; bool IsRoot() const; bool IsParent(ui32 partitionId) const; diff --git a/ydb/core/protos/blob_depot_config.proto b/ydb/core/protos/blob_depot_config.proto index ab0ae9754488..ea6556c336e7 100644 --- a/ydb/core/protos/blob_depot_config.proto +++ b/ydb/core/protos/blob_depot_config.proto @@ -14,7 +14,7 @@ message TChannelKind { message TChannelProfile { optional string StoragePoolName = 1; // used when creating tablet through BSC -> Hive optional string StoragePoolKind = 2; // used when creating tablet through Schemeshard - optional uint32 Count = 3; + optional uint32 Count = 3 [default = 1]; optional TChannelKind.E ChannelKind = 4; } diff --git a/ydb/core/protos/blobstorage.proto b/ydb/core/protos/blobstorage.proto index dcecae12f0cb..e4d79151a28f 100644 --- a/ydb/core/protos/blobstorage.proto +++ b/ydb/core/protos/blobstorage.proto @@ -1449,6 +1449,8 @@ message TEvControllerReplaceConfigRequest { optional bool SwitchDedicatedStorageSection = 6; optional bool DedicatedConfigMode = 7; optional bool SwitchEnableConfigV2 = 10; // if set, overrides EnableConfigV2 field in BSC + optional string PeerName = 11; + optional bytes UserToken = 12; // console flags optional bool AllowUnknownFields = 8; optional bool BypassMetadataChecks = 9; @@ -1530,6 +1532,8 @@ message TEvControllerDistconfRequest { optional bytes CompressedStorageConfig = 3; // if used has provided storage config optional bool DedicatedConfigMode = 4; // as provided in used command optional uint64 ExpectedStorageConfigVersion = 5; + optional string PeerName = 6; + optional bytes UserToken = 7; } message TEvControllerDistconfResponse { diff --git a/ydb/core/protos/blobstorage_distributed_config.proto b/ydb/core/protos/blobstorage_distributed_config.proto index a186d1b710a1..0005d9439611 100644 --- a/ydb/core/protos/blobstorage_distributed_config.proto +++ b/ydb/core/protos/blobstorage_distributed_config.proto @@ -203,6 +203,8 @@ message TEvNodeConfigInvokeOnRoot { optional bool SwitchDedicatedStorageSection = 4; bool DedicatedStorageSectionConfigMode = 5; bool SkipConsoleValidation = 2; + optional bytes UserToken = 6; + optional string PeerName = 7; } message TBootstrapCluster { diff --git a/ydb/core/protos/config.proto b/ydb/core/protos/config.proto index ac4b45d8736b..b7616636a44c 100644 --- a/ydb/core/protos/config.proto +++ b/ydb/core/protos/config.proto @@ -10,13 +10,13 @@ import "ydb/core/protos/blobstorage_pdisk_config.proto"; import "ydb/core/protos/blobstorage_vdisk_config.proto"; import "ydb/core/protos/bootstrap.proto"; import "ydb/core/protos/cms.proto"; +import "ydb/core/protos/compaction.proto"; import "ydb/core/protos/config_units.proto"; import "ydb/core/protos/counters_schemeshard.proto"; import "ydb/core/protos/data_integrity_trails.proto"; import "ydb/core/protos/datashard_config.proto"; import "ydb/core/protos/drivemodel.proto"; import "ydb/core/protos/feature_flags.proto"; -import "ydb/core/protos/compaction.proto"; import "ydb/core/protos/flat_scheme_op.proto"; import "ydb/core/protos/hive.proto"; import "ydb/core/protos/http_config.proto"; @@ -35,6 +35,7 @@ import "ydb/core/protos/table_service_config.proto"; import "ydb/core/protos/tablet.proto"; import "ydb/core/protos/tenant_pool.proto"; import "ydb/core/protos/tenant_slot_broker.proto"; +import "ydb/core/protos/workload_manager_config.proto"; import "ydb/library/actors/protos/interconnect.proto"; import "yql/essentials/core/file_storage/proto/file_storage.proto"; import "yql/essentials/providers/common/proto/gateways_config.proto"; @@ -2331,6 +2332,7 @@ message TAppConfig { optional NKikimrProto.TDataIntegrityTrailsConfig DataIntegrityTrailsConfig = 87; optional TDataErasureConfig DataErasureConfig = 88; optional THealthCheckConfig HealthCheckConfig = 89; + optional TWorkloadManagerConfig WorkloadManagerConfig = 90; repeated TNamedConfig NamedConfigs = 100; optional string ClusterYamlConfig = 101; diff --git a/ydb/core/protos/console_config.proto b/ydb/core/protos/console_config.proto index a14c980aefe1..351f5e6944df 100644 --- a/ydb/core/protos/console_config.proto +++ b/ydb/core/protos/console_config.proto @@ -144,6 +144,7 @@ message TConfigItem { ReplicationConfigItem = 83; CompPrioritiesConfig = 85; HealthCheckConfigItem = 89; + WorkloadManagerConfigItem = 90; NamedConfigsItem = 100; ClusterYamlConfigItem = 101; @@ -267,6 +268,7 @@ message TSetYamlConfigRequest { optional string PeerName = 3; optional string IngressDatabase = 4; optional bool BypassAuth = 5; + optional bool SkipAuditLog = 6; } message TSetYamlConfigResponse { @@ -279,6 +281,7 @@ message TReplaceYamlConfigRequest { optional string PeerName = 3; optional string IngressDatabase = 4; optional bool BypassAuth = 5; + optional bool SkipAuditLog = 6; } message TReplaceYamlConfigResponse { diff --git a/ydb/core/protos/counters_blob_depot.proto b/ydb/core/protos/counters_blob_depot.proto index 669275fc1ab2..8877d99b3ec8 100644 --- a/ydb/core/protos/counters_blob_depot.proto +++ b/ydb/core/protos/counters_blob_depot.proto @@ -82,4 +82,5 @@ enum ETxTypes { TXTYPE_PROCESS_SCANNED_KEYS = 19 [(NKikimr.TxTypeOpts) = {Name: "TTxProcessScannedKeys"}]; TXTYPE_DECOMMIT_BLOBS = 20 [(NKikimr.TxTypeOpts) = {Name: "TTxDecommitBlobs"}]; TXTYPE_PREPARE = 21 [(NKikimr.TxTypeOpts) = {Name: "TTxPrepare"}]; + TXTYPE_HARD_COLLECT_ASSIMILATED_BLOBS = 22 [(NKikimr.TxTypeOpts) = {Name: "TTxHardCollectAssimilatedBlobs"}]; } diff --git a/ydb/core/protos/feature_flags.proto b/ydb/core/protos/feature_flags.proto index e07868b4638c..55666ce0a053 100644 --- a/ydb/core/protos/feature_flags.proto +++ b/ydb/core/protos/feature_flags.proto @@ -206,4 +206,5 @@ message TFeatureFlags { optional bool SwitchToConfigV1 = 180 [default = false]; optional bool EnableEncryptedExport = 181 [default = false]; optional bool EnableAlterDatabase = 182 [default = false]; + optional bool EnableSharedMetadataCache = 183 [default = true]; } diff --git a/ydb/core/protos/hive.proto b/ydb/core/protos/hive.proto index f168bb404742..7bb49b9ac13c 100644 --- a/ydb/core/protos/hive.proto +++ b/ydb/core/protos/hive.proto @@ -323,6 +323,7 @@ message TEvRequestHiveNodeStats { // The next 2 fields should always be used together optional uint64 FilterTabletsByPathId = 7; optional uint64 FilterTabletsBySchemeShardId = 8; + optional NKikimrSubDomains.TDomainKey FilterTabletsByObjectDomain = 9; } message THiveNodeStats { @@ -616,7 +617,7 @@ message TScaleRecommenderPolicies { message TScaleRecommenderPolicy { message TTargetTrackingPolicy { oneof Target { - uint32 AverageCpuUtilizationPercent = 1; + uint32 AverageCpuUtilizationPercent = 1; } } diff --git a/ydb/core/protos/kqp.proto b/ydb/core/protos/kqp.proto index 24b4df45df9f..11fa34060a3c 100644 --- a/ydb/core/protos/kqp.proto +++ b/ydb/core/protos/kqp.proto @@ -69,10 +69,38 @@ enum EIsolationLevel { message TTopicOperationsRequest { optional string Consumer = 1; - repeated Ydb.Topic.UpdateOffsetsInTransactionRequest.TopicOffsets Topics = 2; + repeated TopicOffsets Topics = 2; optional uint32 SupportivePartition = 3; + + message TopicOffsets { + // Topic path. + optional string path = 1; + + // Ranges of offsets by partitions. + repeated PartitionOffsets partitions = 2; + + message PartitionOffsets { + // Partition identifier. + optional int64 partition_id = 1; + + // List of offset ranges. + repeated OffsetsRange partition_offsets = 2; + + optional bool force_commit = 3; + optional bool kill_read_session = 4; + optional bool only_check_commited_to_finish = 5; + optional string read_session_id = 6; + + message OffsetsRange { + optional int64 start = 1; + optional int64 end = 2; + } + } + } } + + message TTopicOperationsResponse { message TWriteId { optional uint64 NodeId = 1; @@ -653,6 +681,8 @@ message TEvScanPing { } message TEvKqpScanCursor { + optional uint64 TabletId = 1; + message TColumnShardScanPlain { } message TColumnShardScanSimple { @@ -736,6 +766,7 @@ message TKqpTableSinkSettings { MODE_INSERT = 2; MODE_DELETE = 3; MODE_UPDATE = 4; + MODE_FILL = 5; } optional NKqpProto.TKqpPhyTableId Table = 3; @@ -753,6 +784,7 @@ message TKqpTableSinkSettings { optional NKikimrDataEvents.ELockMode LockMode = 15; optional bool EnableStreamWrite = 16; optional bool IsBatch = 17; + repeated string InputColumns = 18; // Only for MODE_FILL } message TKqpStreamLookupSettings { diff --git a/ydb/core/protos/msgbus_pq.proto b/ydb/core/protos/msgbus_pq.proto index 9e16ce29a372..ae4fe4ad0e91 100644 --- a/ydb/core/protos/msgbus_pq.proto +++ b/ydb/core/protos/msgbus_pq.proto @@ -472,7 +472,7 @@ message TPersQueuePartitionResponse { optional uint64 CreateTimestampMS = 6; //create Timestamp of record on Offset (next to be readed record); is not set if no such record exists (no lag) optional uint64 SizeLag = 7; optional uint64 WriteTimestampEstimateMS = 8; - + optional bool ClientHasAnyCommits = 9; } message TCmdGetOwnershipResult { diff --git a/ydb/core/protos/pqconfig.proto b/ydb/core/protos/pqconfig.proto index b2f9d7097285..b2c682c588fb 100644 --- a/ydb/core/protos/pqconfig.proto +++ b/ydb/core/protos/pqconfig.proto @@ -751,6 +751,7 @@ message TClientInfo { optional uint64 ReadLagMs = 5; optional uint64 LastReadTimestampMs = 8; optional uint64 TotalLagMs = 9; + optional uint64 CommitedLagMs = 10; } @@ -851,6 +852,7 @@ message TStatusResponse { optional uint64 CommitedOffset = 9; optional bool ReadingFinished = 10; + optional uint64 CommitedLagMs = 11; } @@ -904,7 +906,7 @@ message TUserInfo { optional uint64 OffsetRewindSum = 5; optional uint64 ReadRuleGeneration = 6; optional uint64 PartitionSessionId = 7; - + optional bool AnyCommits = 8; } message TPartitionClientInfo { @@ -952,11 +954,15 @@ message TYdsShardIterator { message TPartitionOperation { optional uint32 PartitionId = 1; - optional uint64 Begin = 2; - optional uint64 End = 3; + optional uint64 CommitOffsetsBegin = 2; + optional uint64 CommitOffsetsEnd = 3; optional string Consumer = 4; optional string Path = 5; // topic path optional uint32 SupportivePartition = 6; + optional bool ForceCommit = 7; + optional bool KillReadSession = 8; + optional bool OnlyCheckCommitedToFinish = 9; + optional string ReadSessionId = 10; }; message TWriteId { diff --git a/ydb/core/protos/sys_view.proto b/ydb/core/protos/sys_view.proto index 00700d0a2f30..d0d87296c926 100644 --- a/ydb/core/protos/sys_view.proto +++ b/ydb/core/protos/sys_view.proto @@ -277,7 +277,7 @@ message TGroupInfo { // desired disk categories ? // down/persisted down ? // metrics ? - optional bool LayoutCorrect = 16; // is the group layout correct? + optional bool LayoutCorrect = 16 [default = true]; // is the group layout correct? } message TGroupEntry { diff --git a/ydb/core/protos/table_service_config.proto b/ydb/core/protos/table_service_config.proto index c67f453c9f63..209437b1b36c 100644 --- a/ydb/core/protos/table_service_config.proto +++ b/ydb/core/protos/table_service_config.proto @@ -371,4 +371,14 @@ message TTableServiceConfig { optional bool AllowMultiBroadcasts = 79 [default = false]; optional bool DefaultEnableShuffleElimination = 80 [default = true]; + + message TBatchOperationSettings { + optional uint64 MaxBatchSize = 1 [ default = 10000 ]; + optional uint64 MinBatchSize = 2 [ default = 1 ]; + optional uint64 StartRetryDelayMs = 3 [ default = 50 ]; + optional uint64 MaxRetryDelayMs = 4 [ default = 30000 ]; + optional uint64 PartitionExecutionLimit = 5 [ default = 10 ]; + } + + optional TBatchOperationSettings BatchOperationSettings = 81; }; diff --git a/ydb/core/protos/tx_datashard.proto b/ydb/core/protos/tx_datashard.proto index 0c37e1f7c5bb..ec87c5d74e2c 100644 --- a/ydb/core/protos/tx_datashard.proto +++ b/ydb/core/protos/tx_datashard.proto @@ -33,7 +33,7 @@ enum EDatashardState { Readonly = 3; Offline = 4; PreOffline = 5; // Offline but waits for loaned snapshots to be returned and for SchemaChangedResult to be received - Frozen = 6; // Read only transactions are allowed. Scheme modification is forbiden + Frozen = 6; // Read only transactions are allowed. Scheme modification is forbidden // Split/Merge Src states SplitSrcWaitForNoTxInFlight = 101; // Temporary state: split src waits for all Tx to finish and then starts splitting @@ -131,6 +131,7 @@ message TKqpTransaction { optional uint32 Type = 3; optional NKikimrProto.TTypeInfo TypeInfo = 4; optional bool NotNull = 5; + optional bool IsPrimary = 6; } message TColumnWriteMeta { @@ -232,6 +233,8 @@ message TKqpTransaction { message TEvKqpInputActorResultInfo { repeated NKikimrDataEvents.TLock Locks = 1; + optional string BatchOperationMaxKey = 2; + repeated uint32 BatchOperationKeyIds = 3; } message TKqpReadRangesSourceSettings { @@ -265,6 +268,7 @@ message TKqpReadRangesSourceSettings { optional NKikimrDataEvents.ELockMode LockMode = 20; optional uint32 OptionalSorting = 21; + optional bool IsBatch = 22 [default = false]; } message TKqpTaskInfo { @@ -1424,14 +1428,14 @@ message TEvConditionalEraseRowsResponse { } message TEvBuildIndexCreateRequest { - optional uint64 BuildIndexId = 1; // unique id of build index proccess + optional uint64 BuildIndexId = 1; // unique id of build index process optional uint64 TabletId = 2; optional uint64 OwnerId = 3; optional uint64 PathId = 4; optional string TargetName = 5; - repeated string IndexColumns = 6; // key columns that is needed to transer in terms of target table + repeated string IndexColumns = 6; // key columns that is needed to transfer in terms of target table optional NKikimrTx.TKeyRange KeyRange = 7; // key range to transfer in term of source table @@ -1481,9 +1485,10 @@ message TEvSampleKRequest { optional NKikimrProto.TPathID PathId = 3; optional uint64 K = 4; - // For now we use tablet id as seed value, but it's not convinient for tests + optional uint64 Seed = 5; - // We want to sample small instead of large probabilites + + // We want to sample small instead of large probabilities // because size of message will be smaller (varint) optional uint64 MaxProbability = 6; @@ -1628,9 +1633,6 @@ message TEvReshuffleKMeansResponse { optional uint64 UploadBytes = 9; optional uint64 ReadRows = 10; optional uint64 ReadBytes = 11; - - // TODO(mbkkt) implement slow-path (reliable-path) - // optional last written primary key } message TEvPrefixKMeansRequest { diff --git a/ydb/core/protos/workload_manager_config.proto b/ydb/core/protos/workload_manager_config.proto new file mode 100644 index 000000000000..67ad00539c69 --- /dev/null +++ b/ydb/core/protos/workload_manager_config.proto @@ -0,0 +1,18 @@ +package NKikimrConfig; +option java_package = "ru.yandex.kikimr.proto"; + +message TWorkloadManagerConfig { + optional bool Enabled = 1 [default = false]; + // Inflight + optional int32 ConcurrentQueryLimit = 2 [default = 5]; + optional int32 QueueSize = 3 [default = 30]; + optional double DatabaseLoadCpuThreshold = 4 [default = 70]; + + // Cpu + optional double TotalCpuLimitPercentPerNode = 5 [default = 70]; + optional double QueryCpuLimitPercentPerNode = 6 [default = 100]; + optional double ResourceWeight = 7 [default = -1]; + + // Memory + optional double QueryMemoryLimitPercentPerNode = 8 [default = -1]; +}; diff --git a/ydb/core/protos/ya.make b/ydb/core/protos/ya.make index c519f7962af9..b005a19705ea 100644 --- a/ydb/core/protos/ya.make +++ b/ydb/core/protos/ya.make @@ -11,8 +11,8 @@ ENDIF() SRCS( alloc.proto auth.proto - base.proto backup.proto + base.proto bind_channel_storage_pool.proto blob_depot.proto blob_depot_config.proto @@ -65,9 +65,9 @@ SRCS( data_events.proto data_integrity_trails.proto database_basic_sausage_metainfo.proto + datashard_backup.proto datashard_config.proto datashard_load.proto - datashard_backup.proto db_metadata_cache.proto drivemodel.proto export.proto @@ -85,8 +85,8 @@ SRCS( http_config.proto import.proto index_builder.proto - kesus.proto kafka.proto + kesus.proto key.proto kqp.proto kqp_physical.proto @@ -151,6 +151,7 @@ SRCS( tx_sequenceshard.proto whiteboard_disk_states.proto whiteboard_flags.proto + workload_manager_config.proto ydb_result_set_old.proto ydb_table_impl.proto yql_translation_settings.proto diff --git a/ydb/core/quoter/kesus_quoter_proxy.cpp b/ydb/core/quoter/kesus_quoter_proxy.cpp index daa03a3f856e..3d8e6c40f579 100644 --- a/ydb/core/quoter/kesus_quoter_proxy.cpp +++ b/ydb/core/quoter/kesus_quoter_proxy.cpp @@ -1119,7 +1119,6 @@ class TKesusQuoterProxy : public TActorBootstrapped { NTabletPipe::TClientConfig GetPipeConnectionOptions(bool reconnection) { NTabletPipe::TClientConfig cfg; - cfg.CheckAliveness = true; cfg.RetryPolicy = { .RetryLimitCount = 3u, .DoFirstRetryInstantly = !reconnection diff --git a/ydb/core/sys_view/show_create/create_table_formatter.cpp b/ydb/core/sys_view/show_create/create_table_formatter.cpp index 9c53079ec883..0c31db94c600 100644 --- a/ydb/core/sys_view/show_create/create_table_formatter.cpp +++ b/ydb/core/sys_view/show_create/create_table_formatter.cpp @@ -245,8 +245,8 @@ class TStringStreamWrapper { TStringStream& Stream; }; -TFormatResult TCreateTableFormatter::Format(const TString& tablePath, - const TTableDescription& tableDesc, bool temporary) { +TFormatResult TCreateTableFormatter::Format(const TString& tablePath, const NKikimrSchemeOp::TTableDescription& tableDesc, + bool temporary, const THashMap>& persQueues) { Stream.Clear(); TStringStreamWrapper wrapper(Stream); @@ -402,7 +402,24 @@ TFormatResult TCreateTableFormatter::Format(const TString& tablePath, } if (printed) { - Stream << "\n);"; + Stream << "\n)"; + } + + Stream << ";"; + + if (!tableDesc.GetCdcStreams().empty()) { + Y_ENSURE((ui32)tableDesc.GetCdcStreams().size() == persQueues.size()); + auto firstColumnTypeId = columns[tableDesc.GetKeyColumnIds(0)]->GetTypeId(); + try { + Format(tablePath, tableDesc.GetCdcStreams(0), persQueues, firstColumnTypeId); + for (int i = 1; i < tableDesc.GetCdcStreams().size(); i++) { + Format(tablePath, tableDesc.GetCdcStreams(i), persQueues, firstColumnTypeId); + } + } catch (const TFormatFail& ex) { + return TFormatResult(ex.Status, ex.Error); + } catch (const yexception& e) { + return TFormatResult(Ydb::StatusIds::UNSUPPORTED, e.what()); + } } TString statement = Stream.Str(); @@ -872,6 +889,119 @@ bool TCreateTableFormatter::Format(const Ydb::Table::TtlSettings& ttlSettings, T return true; } +void TCreateTableFormatter::Format(const TString& tablePath, const NKikimrSchemeOp::TCdcStreamDescription& cdcStream, + const THashMap>& persQueues, ui32 firstColumnTypeId) { + Stream << "ALTER TABLE "; + EscapeName(tablePath, Stream); + Stream << "\n\t"; + auto persQueuePath = JoinPath({tablePath, cdcStream.GetName(), "streamImpl"}); + auto it = persQueues.find(persQueuePath); + if (it == persQueues.end() || !it->second) { + ythrow TFormatFail(Ydb::StatusIds::INTERNAL_ERROR, "Unexpected topic path"); + } + const auto& persQueue = *it->second; + + Stream << "ADD CHANGEFEED "; + EscapeName(cdcStream.GetName(), Stream); + Stream << " WITH ("; + + TString del = ""; + switch (cdcStream.GetMode()) { + case NKikimrSchemeOp::ECdcStreamMode::ECdcStreamModeKeysOnly: { + Stream << "MODE = \'KEYS_ONLY\'"; + del = ", "; + break; + } + case NKikimrSchemeOp::ECdcStreamMode::ECdcStreamModeUpdate: { + Stream << "MODE = \'UPDATES\'"; + del = ", "; + break; + } + case NKikimrSchemeOp::ECdcStreamMode::ECdcStreamModeNewImage: { + Stream << "MODE = \'NEW_IMAGE\'"; + del = ", "; + break; + } + case NKikimrSchemeOp::ECdcStreamMode::ECdcStreamModeOldImage: { + Stream << "MODE = \'OLD_IMAGE\'"; + del = ", "; + break; + } + case NKikimrSchemeOp::ECdcStreamMode::ECdcStreamModeNewAndOldImages: { + Stream << "MODE = \'NEW_AND_OLD_IMAGES\'"; + del = ", "; + break; + } + default: + ythrow TFormatFail(Ydb::StatusIds::INTERNAL_ERROR, "Unexpected cdc stream mode"); + } + + switch (cdcStream.GetFormat()) { + case NKikimrSchemeOp::ECdcStreamFormat::ECdcStreamFormatJson: { + Stream << del << "FORMAT = \'JSON\'"; + del = ", "; + break; + } + case NKikimrSchemeOp::ECdcStreamFormat::ECdcStreamFormatDebeziumJson: { + Stream << del << "FORMAT = \'DEBEZIUM_JSON\'"; + del = ", "; + break; + } + case NKikimrSchemeOp::ECdcStreamFormat::ECdcStreamFormatDynamoDBStreamsJson: { + Stream << del << "FORMAT = \'DYNAMODB_STREAMS_JSON\'"; + del = ", "; + break; + } + default: + ythrow TFormatFail(Ydb::StatusIds::INTERNAL_ERROR, "Unexpected cdc stream format"); + } + + if (cdcStream.GetVirtualTimestamps()) { + Stream << del << "VIRTUAL_TIMESTAMPS = TRUE"; + del = ", "; + } + + if (cdcStream.HasAwsRegion() && !cdcStream.GetAwsRegion().empty()) { + Stream << del << "AWS_REGION = \'" << cdcStream.GetAwsRegion() << "\'"; + del = ", "; + } + + const auto& pqConfig = persQueue.GetPQTabletConfig(); + const auto& partitionConfig = pqConfig.GetPartitionConfig(); + + if (partitionConfig.HasLifetimeSeconds()) { + Stream << del << "RETENTION_PERIOD = "; + TGuard guard(Alloc); + Stream << "INTERVAL("; + ui64 retentionPeriod = partitionConfig.GetLifetimeSeconds(); + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Interval, NUdf::TUnboxedValuePod(retentionPeriod * 1000000)); + Y_ENSURE(str.HasValue()); + EscapeString(TString(str.AsStringRef()), Stream); + Stream << ")"; + del = ", "; + } + + if (persQueue.HasTotalGroupCount()) { + switch (firstColumnTypeId) { + case NScheme::NTypeIds::Uint32: + case NScheme::NTypeIds::Uint64: + case NScheme::NTypeIds::Uuid: { + Stream << del << "TOPIC_MIN_ACTIVE_PARTITIONS = "; + Stream << persQueue.GetTotalGroupCount(); + del = ", "; + break; + } + } + } + + if (cdcStream.GetState() == NKikimrSchemeOp::ECdcStreamState::ECdcStreamStateScan) { + Stream << del << "INITIAL_SCAN = TRUE"; + } + + Stream << ");"; +} + + TFormatResult TCreateTableFormatter::Format(const TString& tablePath, const TColumnTableDescription& tableDesc, bool temporary) { Stream.Clear(); diff --git a/ydb/core/sys_view/show_create/create_table_formatter.h b/ydb/core/sys_view/show_create/create_table_formatter.h index bd82bc5a157d..a6923514d308 100644 --- a/ydb/core/sys_view/show_create/create_table_formatter.h +++ b/ydb/core/sys_view/show_create/create_table_formatter.h @@ -30,7 +30,8 @@ class TCreateTableFormatter { Alloc.Acquire(); } - TFormatResult Format(const TString& tablePath, const NKikimrSchemeOp::TTableDescription& tableDesc, bool temporary); + TFormatResult Format(const TString& tablePath, const NKikimrSchemeOp::TTableDescription& tableDesc, bool temporary, + const THashMap>& persQueues); TFormatResult Format(const TString& tablePath, const NKikimrSchemeOp::TColumnTableDescription& tableDesc, bool temporary); private: @@ -38,6 +39,9 @@ class TCreateTableFormatter { bool Format(const NKikimrSchemeOp::TFamilyDescription& familyDesc); bool Format(const NKikimrSchemeOp::TPartitioningPolicy& policy, ui32 shardsToCreate, TString& del, bool needWith); + void Format(const TString& tablePath, const NKikimrSchemeOp::TCdcStreamDescription& cdcStream, + const THashMap>& persQueues, ui32 firstColumnTypeId); + void Format(const Ydb::Table::TableIndex& index); bool Format(const Ydb::Table::ExplicitPartitions& explicitPartitions, TString& del, bool needWith); bool Format(const Ydb::Table::ReadReplicasSettings& readReplicasSettings, TString& del, bool needWith); diff --git a/ydb/core/sys_view/show_create/create_view_formatter.cpp b/ydb/core/sys_view/show_create/create_view_formatter.cpp index 746e96ae0161..8b8d49bd3391 100644 --- a/ydb/core/sys_view/show_create/create_view_formatter.cpp +++ b/ydb/core/sys_view/show_create/create_view_formatter.cpp @@ -1,22 +1,207 @@ #include "create_view_formatter.h" -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace NSQLTranslation; +using namespace NSQLTranslationV1; +using namespace NSQLv1Generated; +using namespace NYql; namespace NKikimr::NSysView { -TFormatResult TCreateViewFormatter::Format(const TString& viewPath, const NKikimrSchemeOp::TViewDescription& viewDesc) { - const auto [contextRecreation, select] = NYdb::NDump::SplitViewQuery(viewDesc.GetQueryText()); +namespace { + +bool BuildTranslationSettings(const TString& query, google::protobuf::Arena& arena, TTranslationSettings& settings, TIssues& issues) { + settings.Arena = &arena; + return ParseTranslationSettings(query, settings, issues); +} + +TLexers BuildLexers() { + TLexers lexers; + lexers.Antlr3 = MakeAntlr3LexerFactory(); + lexers.Antlr3Ansi = MakeAntlr3AnsiLexerFactory(); + lexers.Antlr4 = MakeAntlr4LexerFactory(); + lexers.Antlr4Ansi = MakeAntlr4AnsiLexerFactory(); + return lexers; +} + +TParsers BuildParsers() { + TParsers parsers; + parsers.Antlr3 = MakeAntlr3ParserFactory(); + parsers.Antlr3Ansi = MakeAntlr3AnsiParserFactory(); + parsers.Antlr4 = MakeAntlr4ParserFactory(); + parsers.Antlr4Ansi = MakeAntlr4AnsiParserFactory(); + return parsers; +} + +bool SplitViewQuery(const TString& query, const TLexers& lexers, const TParsers& parsers, const TTranslationSettings& translationSettings, TViewQuerySplit& split, TIssues& issues) { + TVector statements; + if (!SplitQueryToStatements(lexers, parsers, query, statements, issues, translationSettings)) { + return false; + } + if (statements.empty()) { + issues.AddIssue(TStringBuilder() << "No select statement in the view query: " << query.Quote()); + return false; + } + split = TViewQuerySplit(statements); + return true; +} + +struct TTokenCollector { + mutable TStringBuilder Tokens; + + void operator()(const NProtoBuf::Message& message) const { + if (const auto* token = dynamic_cast(&message)) { + const auto& value = token->GetValue(); + if (token->GetId() != NALPDefault::SQLv1LexerTokens::TOKEN_EOF) { + if (!Tokens.empty()) { + Tokens << ' '; + } + Tokens << value; + } + } + } +}; + +template +void VisitAllFields(const NProtoBuf::Message& msg, const TCallback& callback) { + const auto* md = msg.GetDescriptor(); + for (int i = 0; i < md->field_count(); ++i) { + const auto* fd = md->field(i); + NProtoBuf::TConstField field(msg, fd); + if (field.IsMessage()) { + for (size_t j = 0; j < field.Size(); ++j) { + const auto& message = *field.Get(j); + callback(message); + VisitAllFields(message, callback); + } + } + } +} + +TString GetTokens(const NProtoBuf::Message& message) { + TTokenCollector tokenCollector; + VisitAllFields(message, tokenCollector); + return tokenCollector.Tokens; +} + +TString TrimQuotes(TString&& s) { + if (s.size() > 1 && ((s.StartsWith('"') && s.EndsWith('"')) || (s.StartsWith('\'') && s.EndsWith('\'')))) { + return s.substr(1, s.size() - 2); + } + return s; +} + +bool GetTablePathPrefix(const TString& query, const TParsers& parsers, const TTranslationSettings& settings, TString& tablePathPrefix, TIssues& issues) { + const auto* message = SqlAST(parsers, query, settings.File, issues, SQL_MAX_PARSER_ERRORS, settings.AnsiLexer, settings.Antlr4Parser, settings.Arena); + if (!message || message->GetDescriptor()->name() != "TSQLv1ParserAST") { + issues.AddIssue(TStringBuilder() << "Cannot parse query: " << query.Quote()); + return false; + } + const auto& proto = static_cast(*message); + VisitAllFields(proto, [&tablePathPrefix](const NProtoBuf::Message& message) { + if (const auto* pragmaMessage = dynamic_cast(&message)) { + const auto pragma = to_lower(GetTokens(pragmaMessage->GetRule_an_id3())); + if (pragma == "tablepathprefix" && pragmaMessage->HasBlock4()) { + if (pragmaMessage->GetBlock4().HasAlt1()) { + const auto& pragmaValue = pragmaMessage->GetBlock4().GetAlt1().GetRule_pragma_value2(); + tablePathPrefix = TrimQuotes(GetTokens(pragmaValue)); + } else if (pragmaMessage->GetBlock4().GetAlt2().GetBlock3().size() == 1) { + // unfortunately, this syntax is also supported + const auto& pragmaValue = pragmaMessage->GetBlock4().GetAlt2().GetBlock3().Get(0).GetRule_pragma_value2(); + tablePathPrefix = TrimQuotes(GetTokens(pragmaValue)); + } + } + } + }); + return true; +} + +TString GetRelativePath(const TFsPath& prefix, const TFsPath& absolutePath) { + try { + return absolutePath.RelativePath(prefix); + } catch (...) { + return absolutePath; + } +} + +} + +TViewQuerySplit::TViewQuerySplit(const TVector& statements) { + TStringBuilder context; + for (int i = 0; i < std::ssize(statements) - 1; ++i) { + context << statements[i] << '\n'; + } + ContextRecreation = context; + Y_ENSURE(!statements.empty()); + Select = statements.back(); +} + +bool SplitViewQuery(const TString& query, TViewQuerySplit& split, TIssues& issues) { + google::protobuf::Arena arena; + TTranslationSettings translationSettings; + if (!BuildTranslationSettings(query, arena, translationSettings, issues)) { + return false; + } + auto lexers = BuildLexers(); + auto parsers = BuildParsers(); + return SplitViewQuery(query, lexers, parsers, translationSettings, split, issues); +} + +TFormatResult TCreateViewFormatter::Format(const TString& viewRelativePath, const TString& viewAbsolutePath, const NKikimrSchemeOp::TViewDescription& viewDesc) { + const auto& query = viewDesc.GetQueryText(); + + google::protobuf::Arena arena; + TTranslationSettings translationSettings; + TIssues issues; + if (!BuildTranslationSettings(query, arena, translationSettings, issues)) { + return TFormatResult(Ydb::StatusIds::SCHEME_ERROR, issues); + } + + auto lexers = BuildLexers(); + auto parsers = BuildParsers(); + TViewQuerySplit split; + if (!SplitViewQuery(query, lexers, parsers, translationSettings, split, issues)) { + return TFormatResult(Ydb::StatusIds::SCHEME_ERROR, issues); + } + + TString tablePathPrefix; + if (!GetTablePathPrefix(query, parsers, translationSettings, tablePathPrefix, issues)) { + return TFormatResult(Ydb::StatusIds::SCHEME_ERROR, issues); + } + const TString path = tablePathPrefix.empty() ? viewRelativePath : GetRelativePath(tablePathPrefix, viewAbsolutePath); const TString creationQuery = std::format( "{}" "CREATE VIEW `{}` WITH (security_invoker = TRUE) AS\n" - "{};\n", - contextRecreation.c_str(), - viewPath.c_str(), - select.c_str() + "{}\n", + split.ContextRecreation.c_str(), + path.c_str(), + split.Select.c_str() ); + TString formattedQuery; + if (!NYdb::NDump::Format(creationQuery, formattedQuery, issues)) { + return TFormatResult(Ydb::StatusIds::SCHEME_ERROR, issues); + } - return TFormatResult(creationQuery); + return TFormatResult(formattedQuery); } } diff --git a/ydb/core/sys_view/show_create/create_view_formatter.h b/ydb/core/sys_view/show_create/create_view_formatter.h index b71ba909fc48..d38e888a6c30 100644 --- a/ydb/core/sys_view/show_create/create_view_formatter.h +++ b/ydb/core/sys_view/show_create/create_view_formatter.h @@ -8,9 +8,19 @@ namespace NKikimr::NSysView { +struct TViewQuerySplit { + TString ContextRecreation; + TString Select; + + TViewQuerySplit() = default; + TViewQuerySplit(const TVector& statements); +}; + +bool SplitViewQuery(const TString& query, TViewQuerySplit& split, NYql::TIssues& issues); + class TCreateViewFormatter { public: - TFormatResult Format(const TString& viewPath, const NKikimrSchemeOp::TViewDescription& viewDesc); + TFormatResult Format(const TString& viewRelativePath, const TString& viewAbsolutePath, const NKikimrSchemeOp::TViewDescription& viewDesc); private: TStringStream Stream; diff --git a/ydb/core/sys_view/show_create/formatters_common.h b/ydb/core/sys_view/show_create/formatters_common.h index 64c133da8ec7..2d71ade4bf7e 100644 --- a/ydb/core/sys_view/show_create/formatters_common.h +++ b/ydb/core/sys_view/show_create/formatters_common.h @@ -4,6 +4,7 @@ #include #include +#include namespace NKikimr::NSysView { @@ -34,6 +35,10 @@ class TFormatResult { , Error(std::move(error)) {} + TFormatResult(Ydb::StatusIds::StatusCode status, NYql::TIssues& issues) + : TFormatResult(status, issues.ToString()) + {} + bool IsSuccess() const { return Status == Ydb::StatusIds::SUCCESS; } diff --git a/ydb/core/sys_view/show_create/show_create.cpp b/ydb/core/sys_view/show_create/show_create.cpp index dbe0ddbcd7ef..9496ceb2ee5a 100644 --- a/ydb/core/sys_view/show_create/show_create.cpp +++ b/ydb/core/sys_view/show_create/show_create.cpp @@ -76,6 +76,15 @@ class TShowCreate : public TScanActorBase { } } + STFUNC(StateCollectTableSettings) { + switch (ev->GetTypeRewrite()) { + hFunc(NSchemeShard::TEvSchemeShard::TEvDescribeSchemeResult, HandleCollectTableSettings); + default: + LOG_CRIT(*TlsActivationContext, NKikimrServices::SYSTEM_VIEWS, + "NSysView::TScanActorBase: unexpected event 0x%08" PRIx32, ev->GetTypeRewrite()); + } + } + private: void HandleLimiter(TEvSysView::TEvGetScanLimiterResult::TPtr& ev) override { @@ -160,6 +169,63 @@ class TShowCreate : public TScanActorBase { } } + void StartCollectTableSettings(const TString& tablePath, const NKikimrSchemeOp::TTableDescription& tableDesc, bool temporary) { + CollectTableSettingsState = MakeHolder(); + CollectTableSettingsState->TablePath = tablePath; + CollectTableSettingsState->TableDescription = tableDesc; + CollectTableSettingsState->Temporary = temporary; + + for (const auto& cdcStream: tableDesc.GetCdcStreams()) { + std::unique_ptr navigateRequest(new TEvTxUserProxy::TEvNavigate()); + navigateRequest->Record.SetDatabaseName(Database); + if (UserToken) { + navigateRequest->Record.SetUserToken(UserToken->GetSerializedToken()); + } + NKikimrSchemeOp::TDescribePath* record = navigateRequest->Record.MutableDescribePath(); + + auto persQueuePath = JoinPath({Path, cdcStream.GetName(), "streamImpl"}); + + CollectTableSettingsState->PersQueues[JoinPath({tablePath, cdcStream.GetName(), "streamImpl"})] = nullptr; + + record->SetPath(persQueuePath); + record->MutableOptions()->SetReturnBoundaries(true); + record->MutableOptions()->SetShowPrivateTable(true); + record->MutableOptions()->SetReturnIndexTableBoundaries(true); + record->MutableOptions()->SetReturnPartitionConfig(true); + record->MutableOptions()->SetReturnPartitioningInfo(false); + + Send(MakeTxProxyID(), navigateRequest.release()); + } + } + + void FillBatch(NKqp::TEvKqpCompute::TEvScanData& batch, const TString& path, const TString& statement) { + TVector cells; + for (auto column : Columns) { + switch (column.Tag) { + case Schema::ShowCreate::Path::ColumnId: { + cells.emplace_back(TCell(path.data(), path.size())); + break; + } + case Schema::ShowCreate::PathType::ColumnId: { + cells.emplace_back(TCell(PathType.data(), PathType.size())); + break; + } + case Schema::ShowCreate::Statement::ColumnId: { + cells.emplace_back(TCell(statement.data(), statement.size())); + break; + } + default: + ReplyErrorAndDie(Ydb::StatusIds::INTERNAL_ERROR, "Unexpected column tag"); + return; + } + } + + Y_ENSURE(cells.size() == 3); + TArrayRef resultRow(cells); + batch.Rows.emplace_back(TOwnedCellVec::Make(resultRow)); + batch.Finished = true; + } + void Handle(NSchemeShard::TEvSchemeShard::TEvDescribeSchemeResult::TPtr& ev) { const auto& record = ev->Get()->GetRecord(); const auto status = record.GetStatus(); @@ -197,8 +263,14 @@ class TShowCreate : public TScanActorBase { temporary = true; } + if (!tableDesc.GetCdcStreams().empty()) { + StartCollectTableSettings(tablePath, tableDesc, temporary); + Become(&TShowCreate::StateCollectTableSettings); + return; + } + TCreateTableFormatter formatter; - auto formatterResult = formatter.Format(tablePath, tableDesc, temporary); + auto formatterResult = formatter.Format(tablePath, tableDesc, temporary, {}); if (formatterResult.IsSuccess()) { path = tablePath; statement = formatterResult.ExtractOut(); @@ -237,7 +309,7 @@ class TShowCreate : public TScanActorBase { path = pathPair.second; TCreateViewFormatter formatter; - auto formatterResult = formatter.Format(*path, description); + auto formatterResult = formatter.Format(*path, Path, description); if (formatterResult.IsSuccess()) { statement = formatterResult.ExtractOut(); } else { @@ -277,31 +349,94 @@ class TShowCreate : public TScanActorBase { auto batch = MakeHolder(ScanId); - TVector cells; - for (auto column : Columns) { - switch (column.Tag) { - case Schema::ShowCreate::Path::ColumnId: { - cells.emplace_back(TCell(path.value().data(), path.value().size())); - break; - } - case Schema::ShowCreate::PathType::ColumnId: { - cells.emplace_back(TCell(PathType.data(), PathType.size())); - break; + FillBatch(*batch, path.value(), statement.value()); + + SendBatch(std::move(batch)); + } + + void HandleCollectTableSettings(NSchemeShard::TEvSchemeShard::TEvDescribeSchemeResult::TPtr& ev) { + Y_ENSURE(CollectTableSettingsState); + const auto& record = ev->Get()->GetRecord(); + const auto status = record.GetStatus(); + std::optional path; + std::optional statement; + switch (status) { + case NKikimrScheme::StatusSuccess: { + auto currentPath = record.GetPath(); + const auto& pathDescription = record.GetPathDescription(); + + std::pair pathPair; + { + TString error; + if (!TrySplitPathByDb(currentPath, Database, pathPair, error)) { + ReplyErrorAndDie(Ydb::StatusIds::SCHEME_ERROR, error); + return; + } } - case Schema::ShowCreate::Statement::ColumnId: { - cells.emplace_back(TCell(statement.value().data(), statement.value().size())); - break; + + switch (pathDescription.GetSelf().GetPathType()) { + case NKikimrSchemeOp::EPathTypePersQueueGroup: { + const auto& description = pathDescription.GetPersQueueGroup(); + + auto it = CollectTableSettingsState->PersQueues.find(pathPair.second); + if (it == CollectTableSettingsState->PersQueues.end() || it->second) { + return ReplyErrorAndDie(Ydb::StatusIds::INTERNAL_ERROR, TStringBuilder() << "Unexpected topic path"); + } + it->second = MakeHolder(description); + CollectTableSettingsState->CurrentPersQueuesNumber++; + + if (CollectTableSettingsState->CurrentPersQueuesNumber != CollectTableSettingsState->PersQueues.size()) { + return; + } + + TCreateTableFormatter formatter; + auto formatterResult = formatter.Format( + CollectTableSettingsState->TablePath, + CollectTableSettingsState->TableDescription, + CollectTableSettingsState->Temporary, + CollectTableSettingsState->PersQueues + ); + if (formatterResult.IsSuccess()) { + path = CollectTableSettingsState->TablePath; + statement = formatterResult.ExtractOut(); + } else { + ReplyErrorAndDie(formatterResult.GetStatus(), formatterResult.GetError()); + return; + } + break; + } + default: { + return ReplyErrorAndDie(Ydb::StatusIds::BAD_REQUEST, TStringBuilder() + << "Unsupported path type"); + } } - default: - ReplyErrorAndDie(Ydb::StatusIds::INTERNAL_ERROR, "Unexpected column tag"); - return; + break; + } + case NKikimrScheme::StatusPathDoesNotExist: + case NKikimrScheme::StatusSchemeError: { + ReplyErrorAndDie(Ydb::StatusIds::SCHEME_ERROR, record.GetReason()); + return; + } + case NKikimrScheme::StatusAccessDenied: { + ReplyErrorAndDie(Ydb::StatusIds::UNAUTHORIZED, record.GetReason()); + return; + } + case NKikimrScheme::StatusNotAvailable: { + ReplyErrorAndDie(Ydb::StatusIds::UNAVAILABLE, record.GetReason()); + return; + } + default: { + ReplyErrorAndDie(Ydb::StatusIds::INTERNAL_ERROR, record.GetReason()); + return; } } - Y_ENSURE(cells.size() == 3); - TArrayRef resultRow(cells); - batch->Rows.emplace_back(TOwnedCellVec::Make(resultRow)); - batch->Finished = true; + Y_ENSURE(path.has_value()); + Y_ENSURE(statement.has_value()); + + auto batch = MakeHolder(ScanId); + + FillBatch(*batch, path.value(), statement.value()); SendBatch(std::move(batch)); } @@ -311,6 +446,15 @@ class TShowCreate : public TScanActorBase { TIntrusiveConstPtr UserToken; TString Path; TString PathType; + + struct TCollectTableSettingsState { + TString TablePath; + NKikimrSchemeOp::TTableDescription TableDescription; + bool Temporary; + THashMap> PersQueues; + ui32 CurrentPersQueuesNumber = 0; + }; + THolder CollectTableSettingsState; }; } diff --git a/ydb/core/sys_view/show_create/ya.make b/ydb/core/sys_view/show_create/ya.make index 910379928be1..6cfe39634f25 100644 --- a/ydb/core/sys_view/show_create/ya.make +++ b/ydb/core/sys_view/show_create/ya.make @@ -22,6 +22,17 @@ PEERDIR( ydb/public/lib/ydb_cli/dump/util ydb/public/sdk/cpp/src/client/types yql/essentials/ast + yql/essentials/public/issue + yql/essentials/sql/settings + yql/essentials/sql/v1 + yql/essentials/sql/v1/lexer/antlr3 + yql/essentials/sql/v1/lexer/antlr3_ansi + yql/essentials/sql/v1/lexer/antlr4 + yql/essentials/sql/v1/lexer/antlr4_ansi + yql/essentials/sql/v1/proto_parser/antlr3 + yql/essentials/sql/v1/proto_parser/antlr3_ansi + yql/essentials/sql/v1/proto_parser/antlr4 + yql/essentials/sql/v1/proto_parser/antlr4_ansi ) YQL_LAST_ABI_VERSION() diff --git a/ydb/core/sys_view/ut_common.h b/ydb/core/sys_view/ut_common.h index abd34b37606a..53b6e421450a 100644 --- a/ydb/core/sys_view/ut_common.h +++ b/ydb/core/sys_view/ut_common.h @@ -23,7 +23,7 @@ struct TTestEnvSettings { bool EnableSVP = false; bool EnableForceFollowers = false; bool ShowCreateTable = false; - NKikimrProto::TAuthConfig AuthConfig; + NKikimrProto::TAuthConfig AuthConfig = {}; }; class TTestEnv { diff --git a/ydb/core/sys_view/ut_kqp.cpp b/ydb/core/sys_view/ut_kqp.cpp index c5bb53a373aa..39bd52c73593 100644 --- a/ydb/core/sys_view/ut_kqp.cpp +++ b/ydb/core/sys_view/ut_kqp.cpp @@ -1,5 +1,6 @@ #include "ut_common.h" +#include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -149,7 +151,7 @@ void BreakLock(TSession& session, const TString& tableName) { if (yson == "[]") { continue; } - + NKqp::CompareYson(R"([ [[55u];["Fifty five"]]; ])", yson); @@ -167,7 +169,7 @@ void BreakLock(TSession& session, const TString& tableName) { { // tx1: try to commit auto result = tx1->Commit().ExtractValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); - } + } } void SetupAuthEnvironment(TTestEnv& env) { @@ -256,22 +258,44 @@ void WaitForStats(TTableClient& client, const TString& tableName, const TString& break; Sleep(TDuration::Seconds(5)); } - UNIT_ASSERT_GE(rowCount, 0); + UNIT_ASSERT_GE(rowCount, 0); +} + +NQuery::TExecuteQueryResult ExecuteQuery(NQuery::TSession& session, const std::string& query) { + auto result = session.ExecuteQuery(query, NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + return result; +} + +NKikimrSchemeOp::TPathDescription DescribePath(TTestActorRuntime& runtime, TString&& path) { + if (!IsStartWithSlash(path)) { + path = CanonizePath(JoinPath({"/Root", path})); + } + auto sender = runtime.AllocateEdgeActor(); + TAutoPtr handle; + + auto request = MakeHolder(); + request->Record.MutableDescribePath()->SetPath(path); + request->Record.MutableDescribePath()->MutableOptions()->SetShowPrivateTable(true); + request->Record.MutableDescribePath()->MutableOptions()->SetReturnBoundaries(true); + runtime.Send(new IEventHandle(MakeTxProxyID(), sender, request.Release())); + return runtime.GrabEdgeEventRethrow(handle)->GetRecord().GetPathDescription(); } -class TShowCreateTableChecker { +class TShowCreateChecker { public: - explicit TShowCreateTableChecker(TTestEnv& env) + explicit TShowCreateChecker(TTestEnv& env) : Env(env) + , Runtime(*Env.GetServer().GetRuntime()) , QueryClient(NQuery::TQueryClient(Env.GetDriver())) - , TableClient(TTableClient(Env.GetDriver())) + , Session(QueryClient.GetSession().GetValueSync().GetSession()) { CreateTier("tier1"); CreateTier("tier2"); } - void CheckShowCreateTable(const std::string& query, const std::string& tableName, TString formatQuery = "", bool temporary = false) { + void CheckShowCreateTable(const std::string& query, const std::string& tableName, TString formatQuery = "", bool temporary = false, bool initialScan = false) { auto session = QueryClient.GetSession().GetValueSync().GetSession(); std::optional sessionId = std::nullopt; @@ -279,80 +303,86 @@ class TShowCreateTableChecker { sessionId = session.GetId(); } - CreateTable(session, query); + ExecuteQuery(session, query); auto showCreateTableQuery = ShowCreateTable(session, tableName); if (formatQuery) { UNIT_ASSERT_VALUES_EQUAL_C(UnescapeC(formatQuery), UnescapeC(showCreateTableQuery), UnescapeC(showCreateTableQuery)); } + if (initialScan) { + return; + } + auto describeResultOrig = DescribeTable(tableName, sessionId); DropTable(session, tableName); - CreateTable(session, showCreateTableQuery); + ExecuteQuery(session, showCreateTableQuery); auto describeResultNew = DescribeTable(tableName, sessionId); DropTable(session, tableName); - CompareDescriptions(std::move(describeResultOrig), std::move(describeResultNew), showCreateTableQuery); + CompareDescriptions(describeResultOrig, describeResultNew, showCreateTableQuery); } -private: + // Checks that the view created from the description provided by the `SHOW CREATE VIEW` statement + // can be used to create a view with a description equal to the original. + void CheckShowCreateView(const std::string& query, const std::string& viewName, const std::string& expectedResult = "") { + ExecuteQuery(Session, query); + auto showCreateViewResult = ShowCreateView(Session, viewName); - void CreateTable(NYdb::NQuery::TSession& session, const std::string& query) { - auto result = session.ExecuteQuery(query, NQuery::TTxControl::NoTx()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + if (!expectedResult.empty()) { + UNIT_ASSERT_STRINGS_EQUAL(UnescapeC(showCreateViewResult), UnescapeC(expectedResult)); + } + + const auto originalDescription = CanonizeViewDescription(DescribeView(viewName)); + + DropView(Session, viewName); + ExecuteQuery(Session, showCreateViewResult); + + const auto newDescription = CanonizeViewDescription(DescribeView(viewName)); + + CompareDescriptions(originalDescription, newDescription, showCreateViewResult); + DropView(Session, viewName); } - void CreateTier(const TString& tierName) { - auto session = TableClient.CreateSession().GetValueSync().GetSession(); - auto result = session.ExecuteSchemeQuery(R"( +private: + + void CreateTier(const std::string& tierName) { + ExecuteQuery(Session, std::format(R"( UPSERT OBJECT `accessKey` (TYPE SECRET) WITH (value = `secretAccessKey`); UPSERT OBJECT `secretKey` (TYPE SECRET) WITH (value = `fakeSecret`); - CREATE EXTERNAL DATA SOURCE `)" + tierName + R"(` WITH ( - SOURCE_TYPE="ObjectStorage", - LOCATION="http://fake.fake/olap-)" + tierName + R"(", - AUTH_METHOD="AWS", - AWS_ACCESS_KEY_ID_SECRET_NAME="accessKey", - AWS_SECRET_ACCESS_KEY_SECRET_NAME="secretKey", - AWS_REGION="ru-central1" - ); - )").GetValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + CREATE EXTERNAL DATA SOURCE `{}` WITH ( + SOURCE_TYPE = "ObjectStorage", + LOCATION = "http://fake.fake/olap-{}", + AUTH_METHOD = "AWS", + AWS_ACCESS_KEY_ID_SECRET_NAME = "accessKey", + AWS_SECRET_ACCESS_KEY_SECRET_NAME = "secretKey", + AWS_REGION = "ru-central1" + ); + )", tierName, tierName)); } - Ydb::Table::CreateTableRequest DescribeTable(const std::string& tableName, - std::optional sessionId = std::nullopt) { - - auto describeTable = [this](const TString& path) { - auto& runtime = *(this->Env.GetServer().GetRuntime()); - auto sender = runtime.AllocateEdgeActor(); - TAutoPtr handle; + Ydb::Table::DescribeTableResult DescribeTable(const std::string& tableName, std::optional sessionId = std::nullopt) { - auto request = MakeHolder(); - request->Record.MutableDescribePath()->SetPath(path); - request->Record.MutableDescribePath()->MutableOptions()->SetShowPrivateTable(true); - request->Record.MutableDescribePath()->MutableOptions()->SetReturnBoundaries(true); - runtime.Send(new IEventHandle(MakeTxProxyID(), sender, request.Release())); - auto reply = runtime.GrabEdgeEventRethrow(handle); + auto describeTable = [this](TString&& path) { + auto pathDescription = DescribePath(Runtime, std::move(path)); - if (reply->GetRecord().GetPathDescription().HasColumnTableDescription()) { - const auto& tableDescription = reply->GetRecord().GetPathDescription().GetColumnTableDescription(); - - return *GetCreateTableRequest(tableDescription); + if (pathDescription.HasColumnTableDescription()) { + const auto& tableDescription = pathDescription.GetColumnTableDescription(); + return *GetScheme(tableDescription); } - if (!reply->GetRecord().GetPathDescription().HasTable()) { - UNIT_ASSERT_C(false, "Invalid path type"); + if (!pathDescription.HasTable()) { + UNIT_FAIL("Invalid path type: " << pathDescription.GetSelf().GetPathType()); } - const auto& tableDescription = reply->GetRecord().GetPathDescription().GetTable(); - - return *GetCreateTableRequest(tableDescription); + const auto& tableDescription = pathDescription.GetTable(); + return *GetScheme(tableDescription); }; - TString tablePath = TString(tableName); + auto tablePath = TString(tableName); if (!IsStartWithSlash(tablePath)) { tablePath = CanonizePath(JoinPath({"/Root", tablePath})); } @@ -360,47 +390,56 @@ class TShowCreateTableChecker { auto pos = sessionId.value().find("&id="); tablePath = NKqp::GetTempTablePath("Root", sessionId.value().substr(pos + 4), tablePath); } - auto tableDesc = describeTable(tablePath); + auto tableDesc = describeTable(std::move(tablePath)); return tableDesc; } - std::string ShowCreateTable(NYdb::NQuery::TSession& session, const std::string& tableName) { - auto result = session.ExecuteQuery(TStringBuilder() << R"( - SHOW CREATE TABLE `)" << tableName << R"(`; - )", NQuery::TTxControl::NoTx()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + NKikimrSchemeOp::TViewDescription DescribeView(const std::string& viewName) { + auto pathDescription = DescribePath(Runtime, TString(viewName)); + UNIT_ASSERT_C(pathDescription.HasViewDescription(), pathDescription.DebugString()); + return pathDescription.GetViewDescription(); + } + + NKikimrSchemeOp::TViewDescription CanonizeViewDescription(NKikimrSchemeOp::TViewDescription&& description) { + description.ClearVersion(); + description.ClearPathId(); + + TString queryText; + NYql::TIssues issues; + UNIT_ASSERT_C(NDump::Format(description.GetQueryText(), queryText, issues), issues.ToString()); + *description.MutableQueryText() = queryText; + + return description; + } + + std::string ShowCreate(NQuery::TSession& session, std::string_view type, const std::string& path) { + const auto result = ExecuteQuery(session, std::format("SHOW CREATE {} `{}`;", type, path)); UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1); auto resultSet = result.GetResultSet(0); auto columnsMeta = resultSet.GetColumnsMeta(); - UNIT_ASSERT(columnsMeta.size() == 3); + UNIT_ASSERT_VALUES_EQUAL(columnsMeta.size(), 3); - NYdb::TResultSetParser parser(resultSet); + TResultSetParser parser(resultSet); UNIT_ASSERT(parser.TryNextRow()); - TString tablePath = TString(tableName); - TString statement = ""; - for (size_t i = 0; i < columnsMeta.size(); i++) { - const auto& column = columnsMeta[i]; + for (const auto& column : columnsMeta) { + TValueParser parserValue(parser.GetValue(column.Name)); + parserValue.OpenOptional(); + const auto& value = parserValue.GetUtf8(); + if (column.Name == "Path") { - TValueParser parserValue(parser.GetValue(i)); - parserValue.OpenOptional(); - UNIT_ASSERT_VALUES_EQUAL(parserValue.GetUtf8(), std::string(tablePath)); - continue; + UNIT_ASSERT_VALUES_EQUAL(value, path); } else if (column.Name == "PathType") { - TValueParser parserValue(parser.GetValue(i)); - parserValue.OpenOptional(); - UNIT_ASSERT_VALUES_EQUAL(parserValue.GetUtf8(), "Table"); - continue; + auto actualType = to_upper(TString(value)); + UNIT_ASSERT_VALUES_EQUAL(actualType, type); } else if (column.Name == "Statement") { - TValueParser parserValue(parser.GetValue(i)); - parserValue.OpenOptional(); - statement = parserValue.GetUtf8(); + statement = value; } else { - UNIT_ASSERT_C(false, "Invalid column name"); + UNIT_FAIL("Invalid column name: " << column.Name); } } UNIT_ASSERT(statement); @@ -408,14 +447,24 @@ class TShowCreateTableChecker { return statement; } - void DropTable(NYdb::NQuery::TSession& session, const std::string& tableName) { - auto result = session.ExecuteQuery(TStringBuilder() << R"( - DROP TABLE `)" << tableName << R"(`; - )", NQuery::TTxControl::NoTx()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + std::string ShowCreateTable(NQuery::TSession& session, const std::string& tableName) { + return ShowCreate(session, "TABLE", tableName); + } + + std::string ShowCreateView(NQuery::TSession& session, const std::string& viewName) { + return ShowCreate(session, "VIEW", viewName); + } + + void DropTable(NQuery::TSession& session, const std::string& tableName) { + ExecuteQuery(session, std::format("DROP TABLE `{}`;", tableName)); } - void CompareDescriptions(Ydb::Table::CreateTableRequest describeResultOrig, Ydb::Table::CreateTableRequest describeResultNew, const std::string& showCreateTableQuery) { + void DropView(NQuery::TSession& session, const std::string& viewName) { + ExecuteQuery(session, std::format("DROP VIEW `{}`;", viewName)); + } + + template + void CompareDescriptions(const TProtobufDescription& describeResultOrig, const TProtobufDescription& describeResultNew, const std::string& showCreateTableQuery) { TString first; ::google::protobuf::TextFormat::PrintToString(describeResultOrig, &first); TString second; @@ -424,8 +473,8 @@ class TShowCreateTableChecker { UNIT_ASSERT_VALUES_EQUAL_C(first, second, showCreateTableQuery); } - TMaybe GetCreateTableRequest(const NKikimrSchemeOp::TTableDescription& tableDesc) { - Ydb::Table::CreateTableRequest scheme; + TMaybe GetScheme(const NKikimrSchemeOp::TTableDescription& tableDesc) { + Ydb::Table::DescribeTableResult scheme; NKikimrMiniKQL::TType mkqlKeyType; @@ -444,6 +493,8 @@ class TShowCreateTableChecker { return Nothing(); } + FillChangefeedDescription(scheme, tableDesc); + FillStorageSettings(scheme, tableDesc); FillColumnFamilies(scheme, tableDesc); FillPartitioningSettings(scheme, tableDesc); @@ -459,8 +510,8 @@ class TShowCreateTableChecker { return scheme; } - TMaybe GetCreateTableRequest(const NKikimrSchemeOp::TColumnTableDescription& tableDesc) { - Ydb::Table::CreateTableRequest scheme; + TMaybe GetScheme(const NKikimrSchemeOp::TColumnTableDescription& tableDesc) { + Ydb::Table::DescribeTableResult scheme; FillColumnDescription(scheme, tableDesc); FillColumnFamilies(scheme, tableDesc); @@ -470,8 +521,9 @@ class TShowCreateTableChecker { private: TTestEnv& Env; + TTestActorRuntime& Runtime; NQuery::TQueryClient QueryClient; - TTableClient TableClient; + NQuery::TSession Session; }; class TYsonFieldChecker { @@ -705,7 +757,7 @@ Y_UNIT_TEST_SUITE(SystemView) { env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable( R"(CREATE TABLE test_show_create ( @@ -899,7 +951,7 @@ R"(CREATE TABLE `test_show_create` ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -992,7 +1044,7 @@ WITH (PARTITION_AT_KEYS = ((FALSE), (FALSE, 1, 2), (TRUE, 1, 1, 1, 1, 'str'), (T env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1029,7 +1081,7 @@ WITH ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1093,7 +1145,7 @@ WITH ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1117,7 +1169,7 @@ WITH ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1158,7 +1210,7 @@ WITH (READ_REPLICAS_SETTINGS = 'ANY_AZ:3'); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1199,7 +1251,7 @@ WITH (KEY_BLOOM_FILTER = DISABLED); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1315,7 +1367,7 @@ WITH ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TEMPORARY TABLE test_show_create ( @@ -1341,7 +1393,7 @@ R"(CREATE TEMPORARY TABLE `test_show_create` ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable( R"(CREATE TABLE `/Root/test_show_create` ( @@ -1489,6 +1541,121 @@ WITH ( ); } + Y_UNIT_TEST(ShowCreateTableChangefeeds) { + TTestEnv env(1, 4, {.StoragePools = 3, .ShowCreateTable = true}); + + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_EXECUTER, NActors::NLog::PRI_DEBUG); + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_COMPILE_SERVICE, NActors::NLog::PRI_DEBUG); + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); + + TShowCreateChecker checker(env); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key Uint64, + Value String, + PRIMARY KEY (Key) + ); + ALTER TABLE test_show_create ADD CHANGEFEED `feed` WITH ( + MODE = 'KEYS_ONLY', FORMAT = 'JSON', RETENTION_PERIOD = Interval("PT1H") + ); + )", "test_show_create", +R"(CREATE TABLE `test_show_create` ( + `Key` Uint64, + `Value` String, + PRIMARY KEY (`Key`) +); + +ALTER TABLE `test_show_create` + ADD CHANGEFEED `feed` WITH (MODE = 'KEYS_ONLY', FORMAT = 'JSON', RETENTION_PERIOD = INTERVAL('PT1H'), TOPIC_MIN_ACTIVE_PARTITIONS = 1) +; +)" + ); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key Uint64, + Value String, + PRIMARY KEY (Key) + ); + ALTER TABLE test_show_create + ADD CHANGEFEED `feed_1` WITH (MODE = 'OLD_IMAGE', FORMAT = 'DEBEZIUM_JSON', RETENTION_PERIOD = Interval("PT1H")); + ALTER TABLE test_show_create + ADD CHANGEFEED `feed_2` WITH (MODE = 'NEW_IMAGE', FORMAT = 'JSON', TOPIC_MIN_ACTIVE_PARTITIONS = 10, RETENTION_PERIOD = Interval("PT3H"), VIRTUAL_TIMESTAMPS = TRUE); + )", "test_show_create", +R"(CREATE TABLE `test_show_create` ( + `Key` Uint64, + `Value` String, + PRIMARY KEY (`Key`) +); + +ALTER TABLE `test_show_create` + ADD CHANGEFEED `feed_1` WITH (MODE = 'OLD_IMAGE', FORMAT = 'DEBEZIUM_JSON', RETENTION_PERIOD = INTERVAL('PT1H'), TOPIC_MIN_ACTIVE_PARTITIONS = 1) +; + +ALTER TABLE `test_show_create` + ADD CHANGEFEED `feed_2` WITH (MODE = 'NEW_IMAGE', FORMAT = 'JSON', VIRTUAL_TIMESTAMPS = TRUE, RETENTION_PERIOD = INTERVAL('PT3H'), TOPIC_MIN_ACTIVE_PARTITIONS = 10) +; +)" + ); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key String, + Value String, + PRIMARY KEY (Key) + ); + ALTER TABLE test_show_create + ADD CHANGEFEED `feed` WITH (MODE = 'KEYS_ONLY', FORMAT = 'JSON'); + )", "test_show_create", +R"(CREATE TABLE `test_show_create` ( + `Key` String, + `Value` String, + PRIMARY KEY (`Key`) +); + +ALTER TABLE `test_show_create` + ADD CHANGEFEED `feed` WITH (MODE = 'KEYS_ONLY', FORMAT = 'JSON', RETENTION_PERIOD = INTERVAL('P1D')) +; +)" + ); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key Uint64, + Value String, + PRIMARY KEY (Key) + ); + ALTER TABLE test_show_create + ADD CHANGEFEED `feed_1` WITH (MODE = 'OLD_IMAGE', FORMAT = 'DEBEZIUM_JSON', RETENTION_PERIOD = Interval("PT1H")); + ALTER TABLE test_show_create + ADD CHANGEFEED `feed_2` WITH (MODE = 'NEW_IMAGE', FORMAT = 'JSON', TOPIC_MIN_ACTIVE_PARTITIONS = 10, RETENTION_PERIOD = Interval("PT3H"), VIRTUAL_TIMESTAMPS = TRUE); + ALTER TABLE test_show_create + ADD CHANGEFEED `feed_3` WITH (MODE = 'KEYS_ONLY', TOPIC_MIN_ACTIVE_PARTITIONS = 3, FORMAT = 'JSON', RETENTION_PERIOD = Interval("PT30M"), INITIAL_SCAN = TRUE); + )", "test_show_create", +R"(CREATE TABLE `test_show_create` ( + `Key` Uint64, + `Value` String, + PRIMARY KEY (`Key`) +); + +ALTER TABLE `test_show_create` + ADD CHANGEFEED `feed_1` WITH (MODE = 'OLD_IMAGE', FORMAT = 'DEBEZIUM_JSON', RETENTION_PERIOD = INTERVAL('PT1H'), TOPIC_MIN_ACTIVE_PARTITIONS = 1) +; + +ALTER TABLE `test_show_create` + ADD CHANGEFEED `feed_2` WITH (MODE = 'NEW_IMAGE', FORMAT = 'JSON', VIRTUAL_TIMESTAMPS = TRUE, RETENTION_PERIOD = INTERVAL('PT3H'), TOPIC_MIN_ACTIVE_PARTITIONS = 10) +; + +ALTER TABLE `test_show_create` + ADD CHANGEFEED `feed_3` WITH (MODE = 'KEYS_ONLY', FORMAT = 'JSON', RETENTION_PERIOD = INTERVAL('PT30M'), TOPIC_MIN_ACTIVE_PARTITIONS = 3, INITIAL_SCAN = TRUE) +; +)" + , false, true + ); + } + Y_UNIT_TEST(Nodes) { TTestEnv env; CreateTenantsAndTables(env, false); @@ -1868,7 +2035,7 @@ WITH ( TTableClient client(env.GetDriver()); auto session = client.CreateSession().GetValueSync().GetSession(); - + BreakLock(session, "/Root/Table0"); WaitForStats(client, "/Root/.sys/partition_stats", "LocksBroken != 0"); @@ -1888,7 +2055,7 @@ WITH ( check.Uint64(1); // LocksAcquired check.Uint64(0); // LocksWholeShard check.Uint64(1); // LocksBroken - } + } Y_UNIT_TEST(PartitionStatsFields) { NDataShard::gDbStatsReportInterval = TDuration::Seconds(0); @@ -2717,7 +2884,7 @@ WITH ( TTableClient client(env.GetDriver()); auto session = client.CreateSession().GetValueSync().GetSession(); - + const TString tableName = "/Root/Tenant1/Table1"; const TString viewName = "/Root/Tenant1/.sys/top_partitions_by_tli_one_minute"; @@ -3470,7 +3637,7 @@ WITH ( // Check that user is locked out and cannot login { auto loginResult = env.GetClient().Login(*(env.GetServer().GetRuntime()), "user1", "password1"); - UNIT_ASSERT_EQUAL(loginResult.GetError(), "User user1 is not permitted to log in"); + UNIT_ASSERT_EQUAL(loginResult.GetError(), "User user1 login denied: too many failed password attempts"); } Sleep(TDuration::Seconds(5)); @@ -5694,5 +5861,256 @@ WITH ( } } +Y_UNIT_TEST_SUITE(ShowCreateView) { + +Y_UNIT_TEST(Basic) { + TTestEnv env(1, 4, {.StoragePools = 3, .ShowCreateTable = true}); + NQuery::TQueryClient queryClient(env.GetDriver()); + NQuery::TSession session(queryClient.GetSession().GetValueSync().GetSession()); + TShowCreateChecker checker(env); + + checker.CheckShowCreateView(R"( + CREATE VIEW `test_view` WITH security_invoker = TRUE AS SELECT 1; + )", + "test_view", +R"(CREATE VIEW `test_view` WITH (security_invoker = TRUE) AS +SELECT + 1 +; +)" + ); +} + +Y_UNIT_TEST(FromTable) { + TTestEnv env(1, 4, {.StoragePools = 3, .ShowCreateTable = true}); + NQuery::TQueryClient queryClient(env.GetDriver()); + NQuery::TSession session(queryClient.GetSession().GetValueSync().GetSession()); + TShowCreateChecker checker(env); + + ExecuteQuery(session, R"( + CREATE TABLE t ( + key int, + value utf8, + PRIMARY KEY(key) + ); + )"); + + checker.CheckShowCreateView(R"( + CREATE VIEW test_view WITH security_invoker = TRUE AS + SELECT * FROM t; + )", + "test_view", +R"(CREATE VIEW `test_view` WITH (security_invoker = TRUE) AS +SELECT + * +FROM + t +; +)" + ); +} + +Y_UNIT_TEST(WithTablePathPrefix) { + TTestEnv env(1, 4, {.StoragePools = 3, .ShowCreateTable = true}); + NQuery::TQueryClient queryClient(env.GetDriver()); + NQuery::TSession session(queryClient.GetSession().GetValueSync().GetSession()); + TShowCreateChecker checker(env); + + ExecuteQuery(session, R"( + CREATE TABLE `a/b/c/t` ( + key int, + value utf8, + PRIMARY KEY(key) + ); + )"); + + checker.CheckShowCreateView(R"( + PRAGMA TablePathPrefix = "/Root/a/b/c"; + CREATE VIEW test_view WITH security_invoker = TRUE AS + SELECT * FROM t; + )", + "a/b/c/test_view", +R"(PRAGMA TablePathPrefix = '/Root/a/b/c'; + +CREATE VIEW `test_view` WITH (security_invoker = TRUE) AS +SELECT + * +FROM + t +; +)" + ); +} + +Y_UNIT_TEST(WithSingleQuotedTablePathPrefix) { + TTestEnv env(1, 4, {.StoragePools = 3, .ShowCreateTable = true}); + NQuery::TQueryClient queryClient(env.GetDriver()); + NQuery::TSession session(queryClient.GetSession().GetValueSync().GetSession()); + TShowCreateChecker checker(env); + + ExecuteQuery(session, R"( + CREATE TABLE `a/b/c/t` ( + key int, + value utf8, + PRIMARY KEY(key) + ); + )"); + + checker.CheckShowCreateView(R"( + -- the case of the pragma identifier does not matter, but is preserved + pragma tabLEpathPRefix = '/Root/a/b'; + CREATE VIEW `../../test_view` WITH security_invoker = TRUE AS + SELECT * FROM `c/t`; + )", + "test_view", +R"(-- the case of the pragma identifier does not matter, but is preserved +PRAGMA tabLEpathPRefix = '/Root/a/b'; + +CREATE VIEW `../../test_view` WITH (security_invoker = TRUE) AS +SELECT + * +FROM + `c/t` +; +)" + ); +} + +Y_UNIT_TEST(WithPairedTablePathPrefix) { + TTestEnv env(1, 4, {.StoragePools = 3, .ShowCreateTable = true}); + NQuery::TQueryClient queryClient(env.GetDriver()); + NQuery::TSession session(queryClient.GetSession().GetValueSync().GetSession()); + TShowCreateChecker checker(env); + + ExecuteQuery(session, R"( + CREATE TABLE `a/b/c/t` ( + key int, + value utf8, + PRIMARY KEY(key) + ); + )"); + + checker.CheckShowCreateView(R"( + PRAGMA TablePathPrefix ("db", "/Root/a/b/c"); + CREATE VIEW `test_view` WITH security_invoker = TRUE AS + SELECT * FROM t; + )", + "a/b/c/test_view", +R"(PRAGMA TablePathPrefix('db', '/Root/a/b/c'); + +CREATE VIEW `test_view` WITH (security_invoker = TRUE) AS +SELECT + * +FROM + t +; +)" + ); +} + +Y_UNIT_TEST(WithTwoTablePathPrefixes) { + TTestEnv env(1, 4, {.StoragePools = 3, .ShowCreateTable = true}); + NQuery::TQueryClient queryClient(env.GetDriver()); + NQuery::TSession session(queryClient.GetSession().GetValueSync().GetSession()); + TShowCreateChecker checker(env); + + ExecuteQuery(session, R"( + CREATE TABLE `some/other/folder/t` ( + key int, + value utf8, + PRIMARY KEY(key) + ); + )"); + + checker.CheckShowCreateView(R"( + PRAGMA TablePathPrefix = "/Root/a/b/c"; + PRAGMA TablePathPrefix = "/Root/some/other/folder"; + CREATE VIEW `test_view` WITH security_invoker = TRUE AS + SELECT * FROM t; + )", + "some/other/folder/test_view", +R"(PRAGMA TablePathPrefix = '/Root/a/b/c'; +PRAGMA TablePathPrefix = '/Root/some/other/folder'; + +CREATE VIEW `test_view` WITH (security_invoker = TRUE) AS +SELECT + * +FROM + t +; +)" + ); +} + +} + +Y_UNIT_TEST_SUITE(ViewQuerySplit) { + +Y_UNIT_TEST(Basic) { + NYql::TIssues issues; + TViewQuerySplit split; + UNIT_ASSERT_C(SplitViewQuery("select 1", split, issues), issues.ToString()); + UNIT_ASSERT_STRINGS_EQUAL(split.ContextRecreation, ""); + UNIT_ASSERT_STRINGS_EQUAL(split.Select, "select 1"); +} + +Y_UNIT_TEST(WithPragmaTablePathPrefix) { + NYql::TIssues issues; + TViewQuerySplit split; + UNIT_ASSERT_C(SplitViewQuery( + "pragma tablepathprefix = \"/foo/bar\";\n" + "select 1", + split, issues + ), issues.ToString()); + UNIT_ASSERT_STRINGS_EQUAL(split.ContextRecreation, "pragma tablepathprefix = \"/foo/bar\";\n"); + UNIT_ASSERT_STRINGS_EQUAL(split.Select, "select 1"); +} + +Y_UNIT_TEST(WithPairedPragmaTablePathPrefix) { + NYql::TIssues issues; + TViewQuerySplit split; + UNIT_ASSERT_C(SplitViewQuery( + "pragma tablepathprefix (\"foo\", \"/bar/baz\");\n" + "select 1", + split, issues + ), issues.ToString()); + UNIT_ASSERT_STRINGS_EQUAL(split.ContextRecreation, "pragma tablepathprefix (\"foo\", \"/bar/baz\");\n"); + UNIT_ASSERT_STRINGS_EQUAL(split.Select, "select 1"); +} + +Y_UNIT_TEST(WithComments) { + NYql::TIssues issues; + TViewQuerySplit split; + UNIT_ASSERT_C(SplitViewQuery( + "-- what does the fox say?\n" + "pragma tablepathprefix = \"/foo/bar\";\n" + "select * from t", + split, issues + ), issues.ToString()); + UNIT_ASSERT_STRINGS_EQUAL(split.ContextRecreation, + "-- what does the fox say?\n" + "pragma tablepathprefix = \"/foo/bar\";\n" + ); + UNIT_ASSERT_STRINGS_EQUAL(split.Select, "select * from t"); +} + +Y_UNIT_TEST(Joins) { + NYql::TIssues issues; + TViewQuerySplit split; + UNIT_ASSERT_C(SplitViewQuery( + "$x = \"/t\";\n" + "$y = \"/tt\";\n" + "select * from $x as x join $y as y on x.key == y.key", + split, issues + ), issues.ToString()); + UNIT_ASSERT_STRINGS_EQUAL(split.ContextRecreation, + "$x = \"/t\";\n" + "$y = \"/tt\";\n" + ); + UNIT_ASSERT_STRINGS_EQUAL(split.Select, "select * from $x as x join $y as y on x.key == y.key"); +} + +} + } // NSysView } // NKikimr diff --git a/ydb/core/testlib/actors/test_runtime.cpp b/ydb/core/testlib/actors/test_runtime.cpp index 9f1682b95242..98658934f5d2 100644 --- a/ydb/core/testlib/actors/test_runtime.cpp +++ b/ydb/core/testlib/actors/test_runtime.cpp @@ -17,11 +17,12 @@ #include #include +#include #include #include #include #include -#include +#include /**** ACHTUNG: Do not make here any new dependecies on kikimr ****/ @@ -183,6 +184,7 @@ namespace NActors { nodeAppData->EnableMvccSnapshotWithLegacyDomainRoot = app0->EnableMvccSnapshotWithLegacyDomainRoot; nodeAppData->IoContextFactory = app0->IoContextFactory; nodeAppData->SchemeOperationFactory = app0->SchemeOperationFactory; + nodeAppData->WorkloadManagerConfig = app0->WorkloadManagerConfig; nodeAppData->TransferWriterFactory = std::make_shared(); if (nodeIndex < egg.Icb.size()) { nodeAppData->Icb = std::move(egg.Icb[nodeIndex]); diff --git a/ydb/core/testlib/basics/appdata.cpp b/ydb/core/testlib/basics/appdata.cpp index 1c7e6f040df9..6d4dcc6bc5a0 100644 --- a/ydb/core/testlib/basics/appdata.cpp +++ b/ydb/core/testlib/basics/appdata.cpp @@ -66,6 +66,7 @@ namespace NKikimr { app->S3ProxyResolverConfig = S3ProxyResolverConfig; app->GraphConfig = GraphConfig; app->InitFeatureFlags(FeatureFlags); + app->WorkloadManagerConfig = WorkloadManagerConfig; // This is a special setting active in test runtime only app->EnableMvccSnapshotWithLegacyDomainRoot = true; diff --git a/ydb/core/testlib/basics/appdata.h b/ydb/core/testlib/basics/appdata.h index 7e00f9d487e9..292dadc44d86 100644 --- a/ydb/core/testlib/basics/appdata.h +++ b/ydb/core/testlib/basics/appdata.h @@ -15,9 +15,10 @@ #include #include #include +#include #include #include -#include +#include namespace NKikimr { @@ -111,6 +112,7 @@ namespace NKikimr { NKikimrConfig::TGraphConfig GraphConfig; NKikimrConfig::TImmediateControlsConfig ImmediateControlsConfig; NKikimrResourceBroker::TResourceBrokerConfig ResourceBrokerConfig; + NKikimrConfig::TWorkloadManagerConfig WorkloadManagerConfig; std::vector> Icb; private: diff --git a/ydb/core/testlib/basics/feature_flags.h b/ydb/core/testlib/basics/feature_flags.h index 9992dde56355..22f1f11b4f24 100644 --- a/ydb/core/testlib/basics/feature_flags.h +++ b/ydb/core/testlib/basics/feature_flags.h @@ -77,6 +77,7 @@ class TTestFeatureFlagsHolder { FEATURE_FLAG_SETTER(EnableDatabaseAdmin) FEATURE_FLAG_SETTER(EnablePermissionsExport) FEATURE_FLAG_SETTER(EnableShowCreate) + FEATURE_FLAG_SETTER(EnableSharedMetadataCache) #undef FEATURE_FLAG_SETTER }; diff --git a/ydb/core/testlib/test_client.cpp b/ydb/core/testlib/test_client.cpp index 018965985313..b72ceeead0b7 100644 --- a/ydb/core/testlib/test_client.cpp +++ b/ydb/core/testlib/test_client.cpp @@ -41,10 +41,11 @@ #include #include #include -#include #include #include +#include #include +#include #include #include #include @@ -77,6 +78,7 @@ #include #include #include +#include #include #include #include @@ -539,6 +541,7 @@ namespace Tests { appData.SqsConfig.MergeFrom(Settings->AppConfig->GetSqsConfig()); appData.SharedCacheConfig.MergeFrom(Settings->AppConfig->GetSharedCacheConfig()); appData.TransferWriterFactory = Settings->TransferWriterFactory; + appData.WorkloadManagerConfig.MergeFrom(Settings->AppConfig->GetWorkloadManagerConfig()); appData.DynamicNameserviceConfig = new TDynamicNameserviceConfig; auto dnConfig = appData.DynamicNameserviceConfig; @@ -1178,6 +1181,16 @@ namespace Tests { const auto aid = Runtime->Register(actor, nodeIdx, appData.UserPoolId, TMailboxType::Revolving, 0); Runtime->RegisterService(NConveyor::TInsertServiceOperator::MakeServiceId(Runtime->GetNodeId(nodeIdx)), aid, nodeIdx); } + { + if (Settings->FeatureFlags.GetEnableSharedMetadataCache()) { + auto* actor = NKikimr::NOlap::NDataAccessorControl::TNodeActor::CreateActor(); + + const auto aid = Runtime->Register(actor, nodeIdx, appData.UserPoolId, TMailboxType::HTSwap, 0); + const auto serviceId = NKikimr::NOlap::NDataAccessorControl::TNodeActor::MakeActorId(Runtime->GetNodeId(nodeIdx)); + Runtime->RegisterService(serviceId, aid, nodeIdx); + } + } + Runtime->Register(CreateLabelsMaintainer({}), nodeIdx, appData.SystemPoolId, TMailboxType::Revolving, 0); auto sysViewService = NSysView::CreateSysViewServiceForTests(); diff --git a/ydb/core/tx/columnshard/background_controller.cpp b/ydb/core/tx/columnshard/background_controller.cpp index 1a26f8ed32f7..e1c149cee399 100644 --- a/ydb/core/tx/columnshard/background_controller.cpp +++ b/ydb/core/tx/columnshard/background_controller.cpp @@ -3,15 +3,21 @@ namespace NKikimr::NColumnShard { -bool TBackgroundController::StartCompaction(const NOlap::TPlanCompactionInfo& info) { - auto it = ActiveCompactionInfo.find(info.GetPathId()); - if (it == ActiveCompactionInfo.end()) { - it = ActiveCompactionInfo.emplace(info.GetPathId(), info.GetPathId()).first; - } +bool TBackgroundController::StartCompaction(const TInternalPathId pathId) { + auto [it, _] = ActiveCompactionInfo.emplace(pathId, NOlap::TPlanCompactionInfo{pathId}); it->second.Start(); return true; } +void TBackgroundController::FinishCompaction(const TInternalPathId pathId) { + auto it = ActiveCompactionInfo.find(pathId); + AFL_VERIFY(it != ActiveCompactionInfo.end()); + if (it->second.Finish()) { + ActiveCompactionInfo.erase(it); + } + Counters->OnCompactionFinish(pathId); +} + void TBackgroundController::CheckDeadlines() { for (auto&& i : ActiveCompactionInfo) { if (TMonotonic::Now() - i.second.GetStartTime() > NOlap::TCompactionLimits::CompactionTimeout) { diff --git a/ydb/core/tx/columnshard/background_controller.h b/ydb/core/tx/columnshard/background_controller.h index fad6527fb56f..bb5e0eb3ad8f 100644 --- a/ydb/core/tx/columnshard/background_controller.h +++ b/ydb/core/tx/columnshard/background_controller.h @@ -47,15 +47,9 @@ class TBackgroundController { void CheckDeadlines(); void CheckDeadlinesIndexation(); - bool StartCompaction(const NOlap::TPlanCompactionInfo& info); - void FinishCompaction(const NOlap::TPlanCompactionInfo& info) { - auto it = ActiveCompactionInfo.find(info.GetPathId()); - AFL_VERIFY(it != ActiveCompactionInfo.end()); - if (it->second.Finish()) { - ActiveCompactionInfo.erase(it); - } - Counters->OnCompactionFinish(info.GetPathId()); - } + bool StartCompaction(const TInternalPathId pathId); + void FinishCompaction(const TInternalPathId pathId); + ui32 GetCompactionsCount() const { return ActiveCompactionInfo.size(); } diff --git a/ydb/core/tx/columnshard/blobs_action/counters/read.h b/ydb/core/tx/columnshard/blobs_action/counters/read.h index d0e8f736f5b4..e081062c5ec0 100644 --- a/ydb/core/tx/columnshard/blobs_action/counters/read.h +++ b/ydb/core/tx/columnshard/blobs_action/counters/read.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace NKikimr::NOlap::NBlobOperations { diff --git a/ydb/core/tx/columnshard/blobs_action/counters/remove_declare.h b/ydb/core/tx/columnshard/blobs_action/counters/remove_declare.h index 4e11a6c68f40..e89f66a784ff 100644 --- a/ydb/core/tx/columnshard/blobs_action/counters/remove_declare.h +++ b/ydb/core/tx/columnshard/blobs_action/counters/remove_declare.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace NKikimr::NOlap::NBlobOperations { diff --git a/ydb/core/tx/columnshard/blobs_action/counters/remove_gc.h b/ydb/core/tx/columnshard/blobs_action/counters/remove_gc.h index f74f7f353f7b..210d730578ef 100644 --- a/ydb/core/tx/columnshard/blobs_action/counters/remove_gc.h +++ b/ydb/core/tx/columnshard/blobs_action/counters/remove_gc.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include diff --git a/ydb/core/tx/columnshard/blobs_action/counters/storage.h b/ydb/core/tx/columnshard/blobs_action/counters/storage.h index f2ded5d3556f..94b66e47e7c8 100644 --- a/ydb/core/tx/columnshard/blobs_action/counters/storage.h +++ b/ydb/core/tx/columnshard/blobs_action/counters/storage.h @@ -4,7 +4,7 @@ #include "remove_gc.h" #include "write.h" -#include +#include #include #include diff --git a/ydb/core/tx/columnshard/blobs_action/counters/write.h b/ydb/core/tx/columnshard/blobs_action/counters/write.h index a9b7f0282817..91576426ccd5 100644 --- a/ydb/core/tx/columnshard/blobs_action/counters/write.h +++ b/ydb/core/tx/columnshard/blobs_action/counters/write.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace NKikimr::NOlap::NBlobOperations { diff --git a/ydb/core/tx/columnshard/blobs_action/transaction/tx_blobs_written.cpp b/ydb/core/tx/columnshard/blobs_action/transaction/tx_blobs_written.cpp index cd7feae239d9..e0c5ab30a6b9 100644 --- a/ydb/core/tx/columnshard/blobs_action/transaction/tx_blobs_written.cpp +++ b/ydb/core/tx/columnshard/blobs_action/transaction/tx_blobs_written.cpp @@ -1,7 +1,7 @@ -#include #include "tx_blobs_written.h" #include +#include #include #include #include @@ -154,7 +154,9 @@ bool TTxBlobsWritingFailed::DoExecute(TTransactionContext& txc, const TActorCont Self->OperationsManager->AbortTransactionOnExecute(*Self, op->GetLockId(), txc); auto ev = NEvents::TDataEvents::TEvWriteResult::BuildError(Self->TabletID(), op->GetLockId(), - NKikimrDataEvents::TEvWriteResult::STATUS_INTERNAL_ERROR, "cannot write blob: " + ::ToString(PutBlobResult)); + wResult.IsInternalError() ? NKikimrDataEvents::TEvWriteResult::STATUS_INTERNAL_ERROR + : NKikimrDataEvents::TEvWriteResult::STATUS_BAD_REQUEST, + wResult.GetErrorMessage()); Results.emplace_back(std::move(ev), writeMeta.GetSource(), op->GetCookie()); } return true; diff --git a/ydb/core/tx/columnshard/blobs_action/transaction/tx_blobs_written.h b/ydb/core/tx/columnshard/blobs_action/transaction/tx_blobs_written.h index 6bb3549b20d4..738ca1e01675 100644 --- a/ydb/core/tx/columnshard/blobs_action/transaction/tx_blobs_written.h +++ b/ydb/core/tx/columnshard/blobs_action/transaction/tx_blobs_written.h @@ -55,7 +55,6 @@ class TTxBlobsWritingFinished: public TExtendedTransactionBase { class TTxBlobsWritingFailed: public TExtendedTransactionBase { private: using TBase = TExtendedTransactionBase; - const NKikimrProto::EReplyStatus PutBlobResult; TInsertedPortions Pack; class TReplyInfo { @@ -79,9 +78,8 @@ class TTxBlobsWritingFailed: public TExtendedTransactionBase { std::vector Results; public: - TTxBlobsWritingFailed(TColumnShard* self, const NKikimrProto::EReplyStatus writeStatus, TInsertedPortions&& pack) + TTxBlobsWritingFailed(TColumnShard* self, TInsertedPortions&& pack) : TBase(self) - , PutBlobResult(writeStatus) , Pack(std::move(pack)) { } diff --git a/ydb/core/tx/columnshard/blobs_reader/task.h b/ydb/core/tx/columnshard/blobs_reader/task.h index 00aaa396c742..a27fa02d069e 100644 --- a/ydb/core/tx/columnshard/blobs_reader/task.h +++ b/ydb/core/tx/columnshard/blobs_reader/task.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include diff --git a/ydb/core/tx/columnshard/columnshard.cpp b/ydb/core/tx/columnshard/columnshard.cpp index f3b3a37908a4..92308e4cfb74 100644 --- a/ydb/core/tx/columnshard/columnshard.cpp +++ b/ydb/core/tx/columnshard/columnshard.cpp @@ -4,6 +4,7 @@ #include "blobs_reader/actor.h" #include "counters/aggregation/table_stats.h" #include "data_accessor/actor.h" +#include "data_accessor/node_actor.h" #include "data_accessor/manager.h" #include "engines/column_engine_logs.h" #include "engines/writer/buffer/actor.h" @@ -124,7 +125,13 @@ void TColumnShard::OnActivateExecutor(const TActorContext& ctx) { ResourceSubscribeActor = ctx.Register(new NOlap::NResourceBroker::NSubscribe::TActor(TabletID(), SelfId())); BufferizationInsertionWriteActorId = ctx.Register(new NColumnShard::NWriting::TActor(TabletID(), SelfId())); BufferizationPortionsWriteActorId = ctx.Register(new NOlap::NWritingPortions::TActor(TabletID(), SelfId())); - DataAccessorsControlActorId = ctx.Register(new NOlap::NDataAccessorControl::TActor(TabletID(), SelfId())); + // Change actor here + if (AppData(ctx)->FeatureFlags.GetEnableSharedMetadataCache()){ + DataAccessorsControlActorId = NOlap::NDataAccessorControl::TNodeActor::MakeActorId(ctx.SelfID.NodeId()); + } else { + DataAccessorsControlActorId = ctx.Register(new NOlap::NDataAccessorControl::TActor(TabletID(), SelfId())); + } + DataAccessorsManager = std::make_shared(DataAccessorsControlActorId, SelfId()), PrioritizationClientId = NPrioritiesQueue::TCompServiceOperator::RegisterClient(); diff --git a/ydb/core/tx/columnshard/columnshard__propose_transaction.cpp b/ydb/core/tx/columnshard/columnshard__propose_transaction.cpp index 82cf16fec496..f864a1015186 100644 --- a/ydb/core/tx/columnshard/columnshard__propose_transaction.cpp +++ b/ydb/core/tx/columnshard/columnshard__propose_transaction.cpp @@ -12,6 +12,8 @@ using namespace NTabletFlatExecutor; class TTxProposeTransaction: public NTabletFlatExecutor::TTransactionBase { private: using TBase = NTabletFlatExecutor::TTransactionBase; + TEvColumnShard::TEvProposeTransaction::TPtr Ev; + std::shared_ptr TxOperator; std::optional TxInfo; public: @@ -69,7 +71,7 @@ class TTxProposeTransaction: public NTabletFlatExecutor::TTransactionBaseGet()->GetSource(), Ev->Cookie, msgSeqNo); + TxInfo.emplace(txKind, txId, Ev->Get()->GetSource(), Self->GetProgressTxController().GetAllowedStep(), Ev->Cookie, msgSeqNo); TxOperator = Self->GetProgressTxController().StartProposeOnExecute(*TxInfo, txBody, txc); return true; } @@ -114,8 +116,6 @@ class TTxProposeTransaction: public NTabletFlatExecutor::TTransactionBase TxOperator; }; diff --git a/ydb/core/tx/columnshard/columnshard__statistics.cpp b/ydb/core/tx/columnshard/columnshard__statistics.cpp index 61111ee13abf..c7ef61bfcf72 100644 --- a/ydb/core/tx/columnshard/columnshard__statistics.cpp +++ b/ydb/core/tx/columnshard/columnshard__statistics.cpp @@ -113,18 +113,22 @@ class TColumnPortionsAccumulator { std::shared_ptr DataAccessors; std::shared_ptr Result; const std::shared_ptr VersionedIndex; + const NOlap::TTabletId TabletId; public: TColumnPortionsAccumulator(const std::shared_ptr& storagesManager, const std::shared_ptr& result, const ui32 portionsCountLimit, const std::set& originalColumnTags, const std::shared_ptr& vIndex, - const std::shared_ptr& dataAccessorsManager) + const std::shared_ptr& dataAccessorsManager, + const NOlap::TTabletId tabletId) : StoragesManager(storagesManager) , ColumnTagsRequested(originalColumnTags) , PortionsCountLimit(portionsCountLimit) , DataAccessors(dataAccessorsManager) , Result(result) - , VersionedIndex(vIndex) { + , VersionedIndex(vIndex) + , TabletId(tabletId) + { } class TIndexReadTask: public NOlap::NBlobOperations::NRead::ITask { @@ -259,7 +263,7 @@ class TColumnPortionsAccumulator { } request->RegisterSubscriber(std::make_shared(StoragesManager, Result, VersionedIndex, ColumnTagsRequested)); Portions.clear(); - DataAccessors->AskData(request); + DataAccessors->AskData(TabletId, request); } void AddTask(const NOlap::TPortionInfo::TConstPtr& portion) { @@ -306,7 +310,7 @@ void TColumnShard::Handle(NStat::TEvStatistics::TEvStatisticsRequest::TPtr& ev, std::make_shared(columnTagsRequested, ev->Sender, ev->Cookie, std::move(response)); auto versionedIndex = std::make_shared(index.GetVersionedIndex()); TColumnPortionsAccumulator portionsPack( - StoragesManager, resultAccumulator, 1000, columnTagsRequested, versionedIndex, DataAccessorsManager.GetObjectPtrVerified()); + StoragesManager, resultAccumulator, 1000, columnTagsRequested, versionedIndex, DataAccessorsManager.GetObjectPtrVerified(), (NOlap::TTabletId)TabletID()); for (const auto& [_, portionInfo] : spg->GetPortions()) { if (!portionInfo->IsVisible(GetMaxReadVersion())) { diff --git a/ydb/core/tx/columnshard/columnshard__write.cpp b/ydb/core/tx/columnshard/columnshard__write.cpp index d82e11fd91dc..7e407387d861 100644 --- a/ydb/core/tx/columnshard/columnshard__write.cpp +++ b/ydb/core/tx/columnshard/columnshard__write.cpp @@ -121,12 +121,12 @@ void TColumnShard::Handle(NPrivateEvents::NWrite::TEvWritePortionResult::TPtr& e Counters.OnWritePutBlobsFailed(now - i.GetWriteMeta().GetWriteStartInstant(), i.GetRecordsCount()); Counters.GetCSCounters().OnWritePutBlobsFail(now - i.GetWriteMeta().GetWriteStartInstant()); AFL_WARN(NKikimrServices::TX_COLUMNSHARD_WRITE)("writing_size", i.GetDataSize())("event", "data_write_error")( - "writing_id", i.GetWriteMeta().GetId()); + "writing_id", i.GetWriteMeta().GetId())("reason", i.GetErrorMessage()); Counters.GetWritesMonitor()->OnFinishWrite(i.GetDataSize(), 1); i.MutableWriteMeta().OnStage(NEvWrite::EWriteStage::Finished); } - Execute(new TTxBlobsWritingFailed(this, ev->Get()->GetWriteStatus(), std::move(writtenData)), ctx); + Execute(new TTxBlobsWritingFailed(this, std::move(writtenData)), ctx); } } @@ -415,7 +415,8 @@ class TProposeWriteTransaction: public TExtendedTransactionBase { } proto.SetLockId(WriteCommit->GetLockId()); TxOperator = Self->GetProgressTxController().StartProposeOnExecute( - TTxController::TTxInfo(kind, WriteCommit->GetTxId(), Source, Cookie, {}), proto.SerializeAsString(), txc); + TTxController::TTxInfo(kind, WriteCommit->GetTxId(), Source, Self->GetProgressTxController().GetAllowedStep(), + Cookie, {}), proto.SerializeAsString(), txc); return true; } diff --git a/ydb/core/tx/columnshard/columnshard_impl.cpp b/ydb/core/tx/columnshard/columnshard_impl.cpp index ebaf53c86a37..c612bf617f08 100644 --- a/ydb/core/tx/columnshard/columnshard_impl.cpp +++ b/ydb/core/tx/columnshard/columnshard_impl.cpp @@ -85,7 +85,7 @@ TColumnShard::TColumnShard(TTabletStorageInfo* info, const TActorId& tablet) , PeriodicWakeupActivationPeriod(NYDBTest::TControllers::GetColumnShardController()->GetPeriodicWakeupActivationPeriod()) , StatsReportInterval(NYDBTest::TControllers::GetColumnShardController()->GetStatsReportInterval()) , InFlightReadsTracker(StoragesManager, Counters.GetRequestsTracingCounters()) - , TablesManager(StoragesManager, std::make_shared(nullptr), + , TablesManager(StoragesManager, std::make_shared((NOlap::TTabletId)info->TabletID, nullptr), std::make_shared(), Counters.GetPortionIndexCounters(), info->TabletID) , Subscribers(std::make_shared(*this)) , PipeClientCache(NTabletPipe::CreateBoundedClientCache(new NTabletPipe::TBoundedClientCacheConfig(), GetPipeClientConfig())) @@ -853,21 +853,24 @@ class TAccessorsMemorySubscriber: public NOlap::NResourceBroker::NSubscribe::ITa std::shared_ptr Request; std::shared_ptr Subscriber; std::shared_ptr DataAccessorsManager; + const NOlap::TTabletId TabletId; virtual void DoOnAllocationSuccess(const std::shared_ptr& guard) override { Subscriber->SetResourcesGuard(guard); Request->RegisterSubscriber(Subscriber); - DataAccessorsManager->AskData(Request); + DataAccessorsManager->AskData(TabletId, Request); } public: TAccessorsMemorySubscriber(const ui64 memory, const TString& externalTaskId, const NOlap::NResourceBroker::NSubscribe::TTaskContext& context, std::shared_ptr&& request, const std::shared_ptr& subscriber, - const std::shared_ptr& dataAccessorsManager) + const std::shared_ptr& dataAccessorsManager, + NOlap::TTabletId tabletId) : TBase(0, memory, externalTaskId, context) , Request(std::move(request)) , Subscriber(subscriber) - , DataAccessorsManager(dataAccessorsManager) { + , DataAccessorsManager(dataAccessorsManager) + , TabletId(tabletId){ } }; @@ -913,7 +916,7 @@ void TColumnShard::StartCompaction(const std::shared_ptr(accessorsMemory, indexChanges->GetTaskIdentifier(), - CompactTaskSubscription, std::move(request), subscriber, DataAccessorsManager.GetObjectPtrVerified())); + CompactTaskSubscription, std::move(request), subscriber, DataAccessorsManager.GetObjectPtrVerified(), (NOlap::TTabletId)TabletID())); } class TWriteEvictPortionsDataAccessorsSubscriber: public TDataAccessorsSubscriberWithRead { @@ -982,7 +985,7 @@ void TColumnShard::SetupMetadata() { NOlap::NResourceBroker::NSubscribe::ITask::StartResourceSubscription(ResourceSubscribeActor, std::make_shared(accessorsMemory, i.GetRequest()->GetTaskId(), TTLTaskSubscription, std::shared_ptr(i.GetRequest()), - std::make_shared(SelfId(), i.GetProcessor(), Generation()), DataAccessorsManager.GetObjectPtrVerified())); + std::make_shared(SelfId(), i.GetProcessor(), Generation()), DataAccessorsManager.GetObjectPtrVerified(), (NOlap::TTabletId)TabletID())); } } @@ -1021,7 +1024,7 @@ bool TColumnShard::SetupTtl() { request->PredictAccessorsMemory(TablesManager.GetPrimaryIndex()->GetVersionedIndex().GetLastSchema()) + memoryUsage; NOlap::NResourceBroker::NSubscribe::ITask::StartResourceSubscription( ResourceSubscribeActor, std::make_shared(accessorsMemory, i->GetTaskIdentifier(), TTLTaskSubscription, - std::move(request), subscriber, DataAccessorsManager.GetObjectPtrVerified())); + std::move(request), subscriber, DataAccessorsManager.GetObjectPtrVerified(), (NOlap::TTabletId)TabletID())); } return true; } @@ -1070,7 +1073,7 @@ void TColumnShard::SetupCleanupPortions() { NOlap::NResourceBroker::NSubscribe::ITask::StartResourceSubscription( ResourceSubscribeActor, std::make_shared(accessorsMemory, changes->GetTaskIdentifier(), TTLTaskSubscription, - std::move(request), subscriber, DataAccessorsManager.GetObjectPtrVerified())); + std::move(request), subscriber, DataAccessorsManager.GetObjectPtrVerified(), (NOlap::TTabletId)TabletID())); } void TColumnShard::SetupCleanupTables() { @@ -1393,6 +1396,7 @@ class TAccessorsParsingTask: public NConveyor::ITask { private: std::shared_ptr FetchCallback; std::vector Portions; + const NOlap::TTabletId TabletId; virtual TConclusionStatus DoExecute(const std::shared_ptr& /*taskPtr*/) override { std::vector accessors; @@ -1400,7 +1404,7 @@ class TAccessorsParsingTask: public NConveyor::ITask { for (auto&& i : Portions) { accessors.emplace_back(i.BuildAccessor()); } - FetchCallback->OnAccessorsFetched(std::move(accessors)); + FetchCallback->OnAccessorsFetched(TabletId, std::move(accessors)); return TConclusionStatus::Success(); } virtual void DoOnCannotExecute(const TString& reason) override { @@ -1413,9 +1417,10 @@ class TAccessorsParsingTask: public NConveyor::ITask { } TAccessorsParsingTask( - const std::shared_ptr& callback, std::vector&& portions) + const std::shared_ptr& callback, std::vector&& portions, const NOlap::TTabletId tabletId) : FetchCallback(callback) , Portions(std::move(portions)) + , TabletId(tabletId) { } @@ -1501,7 +1506,7 @@ class TTxAskPortionChunks: public TTransactionBase { } AFL_INFO(NKikimrServices::TX_COLUMNSHARD)("stage", "finished"); - NConveyor::TInsertServiceOperator::AsyncTaskToExecute(std::make_shared(FetchCallback, std::move(FetchedAccessors))); + NConveyor::TInsertServiceOperator::AsyncTaskToExecute(std::make_shared(FetchCallback, std::move(FetchedAccessors), (NOlap::TTabletId)txc.Tablet)); return true; } void Complete(const TActorContext& /*ctx*/) override { diff --git a/ydb/core/tx/columnshard/common/snapshot.cpp b/ydb/core/tx/columnshard/common/snapshot.cpp index e0e873488985..5fcd337b8c9f 100644 --- a/ydb/core/tx/columnshard/common/snapshot.cpp +++ b/ydb/core/tx/columnshard/common/snapshot.cpp @@ -39,6 +39,10 @@ NKikimr::NOlap::TSnapshot TSnapshot::MaxForPlanStep(const ui64 planStep) noexcep return TSnapshot(planStep, ::Max()); } +NKikimr::NOlap::TSnapshot TSnapshot::MaxForPlanStep(const TPositiveIncreasingControlInteger planStep) noexcept { + return MaxForPlanStep(planStep.Val()); +} + NKikimr::NOlap::TSnapshot TSnapshot::MaxForPlanInstant(const TInstant planInstant) noexcept { return TSnapshot(planInstant.MilliSeconds(), ::Max()); } diff --git a/ydb/core/tx/columnshard/common/snapshot.h b/ydb/core/tx/columnshard/common/snapshot.h index 7f04203eea8a..4f9e3841f791 100644 --- a/ydb/core/tx/columnshard/common/snapshot.h +++ b/ydb/core/tx/columnshard/common/snapshot.h @@ -1,6 +1,6 @@ #pragma once #include - +#include #include #include #include @@ -26,6 +26,11 @@ class TSnapshot { , TxId(txId) { } + constexpr TSnapshot(const TPositiveIncreasingControlInteger planStep, const ui64 txId) noexcept + : PlanStep(planStep.Val()) + , TxId(txId) { + } + NJson::TJsonValue SerializeToJson() const; constexpr TInstant GetPlanInstant() const noexcept { @@ -60,6 +65,8 @@ class TSnapshot { static TSnapshot MaxForPlanStep(const ui64 planStep) noexcept; + static TSnapshot MaxForPlanStep(const TPositiveIncreasingControlInteger planStep) noexcept; + constexpr bool operator==(const TSnapshot&) const noexcept = default; constexpr auto operator<=>(const TSnapshot&) const noexcept = default; diff --git a/ydb/core/tx/columnshard/counters/blobs_manager.h b/ydb/core/tx/columnshard/counters/blobs_manager.h index 8490ff38814e..cae14e75f869 100644 --- a/ydb/core/tx/columnshard/counters/blobs_manager.h +++ b/ydb/core/tx/columnshard/counters/blobs_manager.h @@ -1,5 +1,5 @@ #pragma once -#include "common/owner.h" +#include #include #include diff --git a/ydb/core/tx/columnshard/counters/columnshard.h b/ydb/core/tx/columnshard/counters/columnshard.h index 226bf070745d..974bc1433bf2 100644 --- a/ydb/core/tx/columnshard/counters/columnshard.h +++ b/ydb/core/tx/columnshard/counters/columnshard.h @@ -2,7 +2,7 @@ #include "initialization.h" #include "tx_progress.h" -#include "common/owner.h" +#include #include #include diff --git a/ydb/core/tx/columnshard/counters/common_data.h b/ydb/core/tx/columnshard/counters/common_data.h index 6c92a4fed41e..f087d2e32d1b 100644 --- a/ydb/core/tx/columnshard/counters/common_data.h +++ b/ydb/core/tx/columnshard/counters/common_data.h @@ -1,5 +1,5 @@ #pragma once -#include "common/owner.h" +#include #include diff --git a/ydb/core/tx/columnshard/counters/engine_logs.h b/ydb/core/tx/columnshard/counters/engine_logs.h index 7461981363b6..9c7a4aefb2a8 100644 --- a/ydb/core/tx/columnshard/counters/engine_logs.h +++ b/ydb/core/tx/columnshard/counters/engine_logs.h @@ -1,8 +1,8 @@ #pragma once #include "common_data.h" -#include "common/owner.h" -#include "common/histogram.h" +#include +#include #include #include #include diff --git a/ydb/core/tx/columnshard/counters/indexation.h b/ydb/core/tx/columnshard/counters/indexation.h index f527a219ff43..5fc395e92f48 100644 --- a/ydb/core/tx/columnshard/counters/indexation.h +++ b/ydb/core/tx/columnshard/counters/indexation.h @@ -2,7 +2,7 @@ #include "splitter.h" #include "sub_columns.h" -#include "common/owner.h" +#include #include diff --git a/ydb/core/tx/columnshard/counters/initialization.h b/ydb/core/tx/columnshard/counters/initialization.h index 2a6b432d6135..009c0a79637e 100644 --- a/ydb/core/tx/columnshard/counters/initialization.h +++ b/ydb/core/tx/columnshard/counters/initialization.h @@ -1,5 +1,5 @@ #pragma once -#include "common/owner.h" +#include #include diff --git a/ydb/core/tx/columnshard/counters/insert_table.h b/ydb/core/tx/columnshard/counters/insert_table.h index 0c20660d609e..32432acc164f 100644 --- a/ydb/core/tx/columnshard/counters/insert_table.h +++ b/ydb/core/tx/columnshard/counters/insert_table.h @@ -1,7 +1,7 @@ #pragma once #include "common_data.h" -#include "common/client.h" -#include "common/agent.h" +#include +#include namespace NKikimr::NColumnShard { diff --git a/ydb/core/tx/columnshard/counters/portions.h b/ydb/core/tx/columnshard/counters/portions.h index 72915d255b06..cfc06459a521 100644 --- a/ydb/core/tx/columnshard/counters/portions.h +++ b/ydb/core/tx/columnshard/counters/portions.h @@ -1,7 +1,7 @@ #pragma once -#include "common/agent.h" -#include "common/client.h" -#include "common/owner.h" +#include +#include +#include #include diff --git a/ydb/core/tx/columnshard/counters/req_tracer.h b/ydb/core/tx/columnshard/counters/req_tracer.h index f70cd02e4840..e8c6b109f0a0 100644 --- a/ydb/core/tx/columnshard/counters/req_tracer.h +++ b/ydb/core/tx/columnshard/counters/req_tracer.h @@ -1,5 +1,5 @@ #pragma once -#include "common/owner.h" +#include #include namespace NKikimr::NColumnShard { diff --git a/ydb/core/tx/columnshard/counters/scan.h b/ydb/core/tx/columnshard/counters/scan.h index 2dd3d7451ba9..9c5313f240fd 100644 --- a/ydb/core/tx/columnshard/counters/scan.h +++ b/ydb/core/tx/columnshard/counters/scan.h @@ -1,8 +1,8 @@ #pragma once #include "sub_columns.h" -#include "common/histogram.h" -#include "common/owner.h" +#include +#include #include #include diff --git a/ydb/core/tx/columnshard/counters/splitter.h b/ydb/core/tx/columnshard/counters/splitter.h index cbde8265a2f7..efe23b850f21 100644 --- a/ydb/core/tx/columnshard/counters/splitter.h +++ b/ydb/core/tx/columnshard/counters/splitter.h @@ -1,6 +1,6 @@ #pragma once #include -#include "common/owner.h" +#include namespace NKikimr::NColumnShard { diff --git a/ydb/core/tx/columnshard/counters/sub_columns.h b/ydb/core/tx/columnshard/counters/sub_columns.h index 36d4aeb2b0a3..66fcfea61a2a 100644 --- a/ydb/core/tx/columnshard/counters/sub_columns.h +++ b/ydb/core/tx/columnshard/counters/sub_columns.h @@ -1,5 +1,5 @@ #pragma once -#include "common/owner.h" +#include #include diff --git a/ydb/core/tx/columnshard/counters/tx_progress.h b/ydb/core/tx/columnshard/counters/tx_progress.h index 24319a3ab748..24cbd4ffed10 100644 --- a/ydb/core/tx/columnshard/counters/tx_progress.h +++ b/ydb/core/tx/columnshard/counters/tx_progress.h @@ -1,5 +1,5 @@ #pragma once -#include "common/owner.h" +#include #include #include diff --git a/ydb/core/tx/columnshard/counters/ya.make b/ydb/core/tx/columnshard/counters/ya.make index 12efb4545046..f27b507d885b 100644 --- a/ydb/core/tx/columnshard/counters/ya.make +++ b/ydb/core/tx/columnshard/counters/ya.make @@ -21,7 +21,7 @@ SRCS( PEERDIR( library/cpp/monlib/dynamic_counters ydb/core/tx/columnshard/counters/aggregation - ydb/core/tx/columnshard/counters/common + ydb/library/signals ydb/core/base ydb/library/actors/core ) diff --git a/ydb/core/tx/columnshard/data_accessor/abstract/collector.cpp b/ydb/core/tx/columnshard/data_accessor/abstract/collector.cpp index 18b138b607d7..6257aeac3d7e 100644 --- a/ydb/core/tx/columnshard/data_accessor/abstract/collector.cpp +++ b/ydb/core/tx/columnshard/data_accessor/abstract/collector.cpp @@ -16,8 +16,8 @@ TDataCategorized IGranuleDataAccessor::AnalyzeData( return DoAnalyzeData(portions, consumer); } -void TActorAccessorsCallback::OnAccessorsFetched(std::vector&& accessors) { - NActors::TActivationContext::Send(ActorId, std::make_unique(std::move(accessors))); +void TActorAccessorsCallback::OnAccessorsFetched(TTabletId tabletId, std::vector&& accessors) { + NActors::TActivationContext::Send(ActorId, std::make_unique(tabletId, std::move(accessors))); } } // namespace NKikimr::NOlap::NDataAccessorControl diff --git a/ydb/core/tx/columnshard/data_accessor/abstract/collector.h b/ydb/core/tx/columnshard/data_accessor/abstract/collector.h index 68cb91ef680b..86e2f721197b 100644 --- a/ydb/core/tx/columnshard/data_accessor/abstract/collector.h +++ b/ydb/core/tx/columnshard/data_accessor/abstract/collector.h @@ -5,7 +5,7 @@ namespace NKikimr::NOlap::NDataAccessorControl { class IAccessorCallback { public: - virtual void OnAccessorsFetched(std::vector&& accessors) = 0; + virtual void OnAccessorsFetched(TTabletId TabletId, std::vector&& accessors) = 0; virtual ~IAccessorCallback() = default; }; @@ -14,7 +14,7 @@ class TActorAccessorsCallback: public IAccessorCallback { const NActors::TActorId ActorId; public: - virtual void OnAccessorsFetched(std::vector&& accessors) override; + virtual void OnAccessorsFetched(TTabletId tabletId, std::vector&& accessors) override; TActorAccessorsCallback(const NActors::TActorId& actorId) : ActorId(actorId) { } @@ -37,6 +37,7 @@ class TDataCategorized { class IGranuleDataAccessor { private: const TInternalPathId PathId; + const TTabletId TabletId; virtual void DoAskData( const std::vector& portions, const std::shared_ptr& callback, const TString& consumer) = 0; @@ -49,9 +50,13 @@ class IGranuleDataAccessor { TInternalPathId GetPathId() const { return PathId; } + TTabletId GetTabletId() const { + return TabletId; + } - IGranuleDataAccessor(const TInternalPathId pathId) - : PathId(pathId) { + IGranuleDataAccessor(const TTabletId tabletId, const TInternalPathId pathId) + : PathId(pathId) + , TabletId(tabletId) { } void AskData( diff --git a/ydb/core/tx/columnshard/data_accessor/abstract/manager.h b/ydb/core/tx/columnshard/data_accessor/abstract/manager.h index ec1516c1cdbf..e6cf3d9147a7 100644 --- a/ydb/core/tx/columnshard/data_accessor/abstract/manager.h +++ b/ydb/core/tx/columnshard/data_accessor/abstract/manager.h @@ -12,7 +12,7 @@ class TGranuleMeta; namespace NKikimr::NOlap::NDataAccessorControl { class IMetadataMemoryManager { private: - virtual std::unique_ptr DoBuildCollector(const TInternalPathId pathId) = 0; + virtual std::unique_ptr DoBuildCollector(const TTabletId tabletId, const TInternalPathId pathId) = 0; virtual std::shared_ptr DoBuildLoader( const TVersionedIndex& versionedIndex, TGranuleMeta* granule, const std::shared_ptr& dsGroupSelector) = 0; @@ -22,8 +22,8 @@ class IMetadataMemoryManager { return false; } - std::unique_ptr BuildCollector(const TInternalPathId pathId) { - return DoBuildCollector(pathId); + std::unique_ptr BuildCollector(const TTabletId tabletId, const TInternalPathId pathId) { + return DoBuildCollector(tabletId, pathId); } std::shared_ptr BuildLoader( diff --git a/ydb/core/tx/columnshard/data_accessor/actor.cpp b/ydb/core/tx/columnshard/data_accessor/actor.cpp index 65680779d18e..8bb5663b3ba5 100644 --- a/ydb/core/tx/columnshard/data_accessor/actor.cpp +++ b/ydb/core/tx/columnshard/data_accessor/actor.cpp @@ -3,7 +3,7 @@ namespace NKikimr::NOlap::NDataAccessorControl { void TActor::Handle(TEvAskServiceDataAccessors::TPtr& ev) { - Manager->AskData(ev->Get()->GetRequest()); + Manager->AskData(ev->Get()->GetTabletId(), ev->Get()->GetRequest()); } void TActor::Bootstrap() { diff --git a/ydb/core/tx/columnshard/data_accessor/actor.h b/ydb/core/tx/columnshard/data_accessor/actor.h index e21b7af85205..0bc90c0d8390 100644 --- a/ydb/core/tx/columnshard/data_accessor/actor.h +++ b/ydb/core/tx/columnshard/data_accessor/actor.h @@ -22,18 +22,18 @@ class TActor: public TActorBootstrapped { } void Handle(TEvRegisterController::TPtr& ev) { - Manager->RegisterController(ev->Get()->ExtractController(), ev->Get()->IsUpdate()); + Manager->RegisterController(ev->Get()->ExtractController(), ev->Get()->GetTabletId(), ev->Get()->IsUpdate()); } void Handle(TEvUnregisterController::TPtr& ev) { - Manager->UnregisterController(ev->Get()->GetPathId()); + Manager->UnregisterController(ev->Get()->GetTabletId(), ev->Get()->GetPathId()); } void Handle(TEvAddPortion::TPtr& ev) { for (auto&& a : ev->Get()->ExtractAccessors()) { - Manager->AddPortion(std::move(a)); + Manager->AddPortion(ev->Get()->GetTabletId(), std::move(a)); } } void Handle(TEvRemovePortion::TPtr& ev) { - Manager->RemovePortion(ev->Get()->GetPortion()); + Manager->RemovePortion(ev->Get()->GetTabletId(), ev->Get()->GetPortion()); } void Handle(TEvAskServiceDataAccessors::TPtr& ev); diff --git a/ydb/core/tx/columnshard/data_accessor/events.h b/ydb/core/tx/columnshard/data_accessor/events.h index b9ffe399c789..bfc30f2a4a73 100644 --- a/ydb/core/tx/columnshard/data_accessor/events.h +++ b/ydb/core/tx/columnshard/data_accessor/events.h @@ -19,17 +19,20 @@ namespace NKikimr::NOlap::NDataAccessorControl { class TEvAddPortion: public NActors::TEventLocal { private: std::vector Accessors; + YDB_READONLY_DEF(TTabletId, TabletId); public: std::vector ExtractAccessors() { return std::move(Accessors); } - explicit TEvAddPortion(const TPortionDataAccessor& accessor) { + TEvAddPortion(const TTabletId tabletId, const TPortionDataAccessor& accessor) + : TabletId(tabletId) { Accessors.emplace_back(accessor); } - explicit TEvAddPortion(const std::vector& accessors) { + TEvAddPortion(const TTabletId tabletId, const std::vector& accessors) + : TabletId(tabletId) { Accessors = accessors; } }; @@ -37,10 +40,12 @@ class TEvAddPortion: public NActors::TEventLocal { private: YDB_READONLY_DEF(TPortionInfo::TConstPtr, Portion); + YDB_READONLY_DEF(TTabletId, TabletId); public: - explicit TEvRemovePortion(const TPortionInfo::TConstPtr& portion) - : Portion(portion) { + TEvRemovePortion(const TTabletId tabletId, const TPortionInfo::TConstPtr& portion) + : Portion(portion) + , TabletId(tabletId) { } }; @@ -48,6 +53,7 @@ class TEvRegisterController: public NActors::TEventLocal Controller; bool IsUpdateFlag = false; + TTabletId TabletId; public: bool IsUpdate() const { @@ -58,9 +64,12 @@ class TEvRegisterController: public NActors::TEventLocal&& accessor, const bool isUpdate) + TTabletId GetTabletId() const { return TabletId;} + + TEvRegisterController(std::unique_ptr&& accessor, const TTabletId tabletId, const bool isUpdate) : Controller(std::move(accessor)) , IsUpdateFlag(isUpdate) + , TabletId(tabletId) { } }; @@ -69,10 +78,12 @@ class TEvUnregisterController : public NActors::TEventLocal { private: YDB_READONLY_DEF(TInternalPathId, PathId); + YDB_READONLY_DEF(TTabletId, TabletId); public: - explicit TEvUnregisterController(const TInternalPathId pathId) - : PathId(pathId) { + TEvUnregisterController(const TTabletId tabletId, const TInternalPathId pathId) + : PathId(pathId) + , TabletId(tabletId){ } }; @@ -81,13 +92,15 @@ class TEvAskTabletDataAccessors: public NActors::TEventLocal, Portions); YDB_READONLY_DEF(std::shared_ptr, Callback); YDB_READONLY_DEF(TString, Consumer); + YDB_READONLY_DEF(TTabletId, TabletId); public: explicit TEvAskTabletDataAccessors(const std::vector& portions, - const std::shared_ptr& callback, const TString& consumer) + const std::shared_ptr& callback, const TString& consumer, const TTabletId tabletId) : Portions(portions) , Callback(callback) - , Consumer(consumer) { + , Consumer(consumer) + , TabletId(tabletId) { } }; @@ -95,10 +108,12 @@ class TEvAskServiceDataAccessors : public NActors::TEventLocal { private: YDB_READONLY_DEF(std::shared_ptr, Request); + YDB_READONLY_DEF(TTabletId, TabletId); public: - explicit TEvAskServiceDataAccessors(const std::shared_ptr& request) - : Request(request) { + explicit TEvAskServiceDataAccessors(const TTabletId tabletId, const std::shared_ptr& request) + : Request(request) + , TabletId(tabletId) { } }; diff --git a/ydb/core/tx/columnshard/data_accessor/in_mem/collector.h b/ydb/core/tx/columnshard/data_accessor/in_mem/collector.h index 407d4af2a95f..1c0d1d403ec4 100644 --- a/ydb/core/tx/columnshard/data_accessor/in_mem/collector.h +++ b/ydb/core/tx/columnshard/data_accessor/in_mem/collector.h @@ -14,8 +14,8 @@ class TCollector: public IGranuleDataAccessor { const std::vector& remove) override; public: - TCollector(const TInternalPathId pathId) - : TBase(pathId) { + TCollector(const TTabletId tabletId, const TInternalPathId pathId) + : TBase(tabletId, pathId) { } }; diff --git a/ydb/core/tx/columnshard/data_accessor/in_mem/manager.cpp b/ydb/core/tx/columnshard/data_accessor/in_mem/manager.cpp index c136734d172b..083be019d8f6 100644 --- a/ydb/core/tx/columnshard/data_accessor/in_mem/manager.cpp +++ b/ydb/core/tx/columnshard/data_accessor/in_mem/manager.cpp @@ -19,8 +19,8 @@ std::shared_ptr TManager::DoBuildLoader( return result; } -std::unique_ptr TManager::DoBuildCollector(const TInternalPathId pathId) { - return std::make_unique(pathId); +std::unique_ptr TManager::DoBuildCollector(const TTabletId tabletId, const TInternalPathId pathId) { + return std::make_unique(tabletId, pathId); } } // namespace NKikimr::NOlap::NDataAccessorControl::NInMem diff --git a/ydb/core/tx/columnshard/data_accessor/in_mem/manager.h b/ydb/core/tx/columnshard/data_accessor/in_mem/manager.h index 442c90f056a4..879d6310c63c 100644 --- a/ydb/core/tx/columnshard/data_accessor/in_mem/manager.h +++ b/ydb/core/tx/columnshard/data_accessor/in_mem/manager.h @@ -6,7 +6,7 @@ namespace NKikimr::NOlap::NDataAccessorControl::NInMem { class TManager: public IMetadataMemoryManager { private: - virtual std::unique_ptr DoBuildCollector(const TInternalPathId pathId) override; + virtual std::unique_ptr DoBuildCollector(const TTabletId tabletId, const TInternalPathId pathId) override; virtual std::shared_ptr DoBuildLoader( const TVersionedIndex& versionedIndex, TGranuleMeta* granule, const std::shared_ptr& dsGroupSelector) override; diff --git a/ydb/core/tx/columnshard/data_accessor/local_db/collector.cpp b/ydb/core/tx/columnshard/data_accessor/local_db/collector.cpp index 1a1d952b7f86..fec767f00ecc 100644 --- a/ydb/core/tx/columnshard/data_accessor/local_db/collector.cpp +++ b/ydb/core/tx/columnshard/data_accessor/local_db/collector.cpp @@ -7,7 +7,7 @@ void TCollector::DoAskData( const std::vector& portions, const std::shared_ptr& callback, const TString& consumer) { if (portions.size()) { NActors::TActivationContext::Send( - TabletActorId, std::make_unique(portions, callback, consumer)); + TabletActorId, std::make_unique(portions, callback, consumer, GetTabletId())); } } diff --git a/ydb/core/tx/columnshard/data_accessor/local_db/collector.h b/ydb/core/tx/columnshard/data_accessor/local_db/collector.h index 0cb754014b1d..448b9b61a536 100644 --- a/ydb/core/tx/columnshard/data_accessor/local_db/collector.h +++ b/ydb/core/tx/columnshard/data_accessor/local_db/collector.h @@ -24,8 +24,8 @@ class TCollector: public IGranuleDataAccessor { virtual void DoModifyPortions(const std::vector& add, const std::vector& remove) override; public: - TCollector(const TInternalPathId pathId, const ui64 maxSize, const NActors::TActorId& actorId) - : TBase(pathId) + TCollector(const TTabletId tabletId, const TInternalPathId pathId, const ui64 maxSize, const NActors::TActorId& actorId) + : TBase(tabletId, pathId) , TabletActorId(actorId) , AccessorsCache(maxSize) { } diff --git a/ydb/core/tx/columnshard/data_accessor/local_db/manager.cpp b/ydb/core/tx/columnshard/data_accessor/local_db/manager.cpp index 7c80ca0fcb1a..205f545d056b 100644 --- a/ydb/core/tx/columnshard/data_accessor/local_db/manager.cpp +++ b/ydb/core/tx/columnshard/data_accessor/local_db/manager.cpp @@ -10,8 +10,8 @@ std::shared_ptr TManager::DoBuildLoader( return nullptr; } -std::unique_ptr TManager::DoBuildCollector(const TInternalPathId pathId) { - return std::make_unique(pathId, MemoryCacheSize, TabletActorId); +std::unique_ptr TManager::DoBuildCollector(const TTabletId tabletId, const TInternalPathId pathId) { + return std::make_unique(tabletId, pathId, MemoryCacheSize, TabletActorId); } } // namespace NKikimr::NOlap::NDataAccessorControl::NLocalDB diff --git a/ydb/core/tx/columnshard/data_accessor/local_db/manager.h b/ydb/core/tx/columnshard/data_accessor/local_db/manager.h index ed8ad94f3a29..5aead386ebf6 100644 --- a/ydb/core/tx/columnshard/data_accessor/local_db/manager.h +++ b/ydb/core/tx/columnshard/data_accessor/local_db/manager.h @@ -8,7 +8,7 @@ class TManager: public IMetadataMemoryManager { const NActors::TActorId TabletActorId; const ui64 MemoryCacheSize; const bool FetchOnStart = true; - virtual std::unique_ptr DoBuildCollector(const TInternalPathId pathId) override; + virtual std::unique_ptr DoBuildCollector(const TTabletId tabletId, const TInternalPathId pathId) override; virtual std::shared_ptr DoBuildLoader( const TVersionedIndex& versionedIndex, TGranuleMeta* granule, const std::shared_ptr& dsGroupSelector) override; diff --git a/ydb/core/tx/columnshard/data_accessor/manager.cpp b/ydb/core/tx/columnshard/data_accessor/manager.cpp index 47a21a772ab9..30c45dbd5de8 100644 --- a/ydb/core/tx/columnshard/data_accessor/manager.cpp +++ b/ydb/core/tx/columnshard/data_accessor/manager.cpp @@ -6,7 +6,7 @@ namespace NKikimr::NOlap::NDataAccessorControl { -void TLocalManager::DrainQueue() { +void TLocalManager::DrainQueue(const TTabletId tabletId) { std::optional lastPathId; IGranuleDataAccessor* lastDataAccessor = nullptr; TPositiveControlInteger countToFlight; @@ -18,7 +18,7 @@ void TLocalManager::DrainQueue() { PortionsAsk.pop_front(); if (!lastPathId || *lastPathId != p->GetPathId()) { lastPathId = p->GetPathId(); - auto it = Managers.find(p->GetPathId()); + auto it = Managers.find(makeManagerKey(tabletId, p->GetPathId())); if (it == Managers.end()) { lastDataAccessor = nullptr; } else { @@ -52,7 +52,7 @@ void TLocalManager::DrainQueue() { } } for (auto&& i : portionsToAsk) { - auto it = Managers.find(i.first); + auto it = Managers.find(makeManagerKey(tabletId, i.first)); AFL_VERIFY(it != Managers.end()); auto dataAnalyzed = it->second->AnalyzeData(i.second, "ANALYZE"); for (auto&& accessor : dataAnalyzed.GetCachedAccessors()) { @@ -78,7 +78,7 @@ void TLocalManager::DrainQueue() { Counters.QueueSize->Set(PortionsAsk.size()); } -void TLocalManager::DoAskData(const std::shared_ptr& request) { +void TLocalManager::DoAskData(const TTabletId tabletId, const std::shared_ptr& request) { AFL_INFO(NKikimrServices::TX_COLUMNSHARD)("event", "ask_data")("request", request->DebugString()); for (auto&& pathId : request->GetPathIds()) { auto portions = request->StartFetching(pathId); @@ -94,23 +94,25 @@ void TLocalManager::DoAskData(const std::shared_ptr& requ } } } - DrainQueue(); + DrainQueue(tabletId); } -void TLocalManager::DoRegisterController(std::unique_ptr&& controller, const bool update) { +void TLocalManager::DoRegisterController(std::unique_ptr&& controller, const TTabletId tabletId, const bool update) { + const auto it = Managers.find(makeManagerKey(tabletId, controller->GetPathId())); if (update) { - auto it = Managers.find(controller->GetPathId()); if (it != Managers.end()) { it->second = std::move(controller); } } else { - AFL_VERIFY(Managers.emplace(controller->GetPathId(), std::move(controller)).second); + if (it == Managers.end()) { + AFL_VERIFY(Managers.emplace(makeManagerKey(tabletId, controller->GetPathId()), std::move(controller)).second); + } } } -void TLocalManager::DoAddPortion(const TPortionDataAccessor& accessor) { +void TLocalManager::DoAddPortion(const TTabletId tabletId, const TPortionDataAccessor& accessor) { { - auto it = Managers.find(accessor.GetPortionInfo().GetPathId()); + auto it = Managers.find(makeManagerKey(tabletId, accessor.GetPortionInfo().GetPathId())); AFL_VERIFY(it != Managers.end()); it->second->ModifyPortions({ accessor }, {}); } @@ -124,7 +126,7 @@ void TLocalManager::DoAddPortion(const TPortionDataAccessor& accessor) { } RequestsByPortion.erase(it); } - DrainQueue(); + DrainQueue(tabletId); } } // namespace NKikimr::NOlap::NDataAccessorControl diff --git a/ydb/core/tx/columnshard/data_accessor/manager.h b/ydb/core/tx/columnshard/data_accessor/manager.h index b50aba19e783..be11b0833323 100644 --- a/ydb/core/tx/columnshard/data_accessor/manager.h +++ b/ydb/core/tx/columnshard/data_accessor/manager.h @@ -34,11 +34,11 @@ class TAccessorSignals: public NColumnShard::TCommonCountersOwner { class IDataAccessorsManager { private: - virtual void DoAskData(const std::shared_ptr& request) = 0; - virtual void DoRegisterController(std::unique_ptr&& controller, const bool update) = 0; - virtual void DoUnregisterController(const TInternalPathId pathId) = 0; - virtual void DoAddPortion(const TPortionDataAccessor& accessor) = 0; - virtual void DoRemovePortion(const TPortionInfo::TConstPtr& portion) = 0; + virtual void DoAskData(const TTabletId tabletId, const std::shared_ptr& request) = 0; + virtual void DoRegisterController(std::unique_ptr&& controller, const TTabletId tabletId, const bool update) = 0; + virtual void DoUnregisterController(const TTabletId tabletId, const TInternalPathId pathId) = 0; + virtual void DoAddPortion(const TTabletId tabletId, const TPortionDataAccessor& accessor) = 0; + virtual void DoRemovePortion(const TTabletId tabletId, const TPortionInfo::TConstPtr& portion) = 0; const NActors::TActorId TabletActorId; public: @@ -52,23 +52,23 @@ class IDataAccessorsManager { virtual ~IDataAccessorsManager() = default; - void AddPortion(const TPortionDataAccessor& accessor) { - DoAddPortion(accessor); + void AddPortion(const TTabletId tabletId, const TPortionDataAccessor& accessor) { + DoAddPortion(tabletId, accessor); } - void RemovePortion(const TPortionInfo::TConstPtr& portion) { - DoRemovePortion(portion); + void RemovePortion(const TTabletId tabletId, const TPortionInfo::TConstPtr& portion) { + DoRemovePortion(tabletId, portion); } - void AskData(const std::shared_ptr& request) { + void AskData(const TTabletId tabletId, const std::shared_ptr& request) { AFL_VERIFY(request); AFL_VERIFY(request->HasSubscriber()); - return DoAskData(request); + return DoAskData(tabletId, request); } - void RegisterController(std::unique_ptr&& controller, const bool update) { + void RegisterController(std::unique_ptr&& controller, const TTabletId tabletId, const bool update) { AFL_VERIFY(controller); - return DoRegisterController(std::move(controller), update); + return DoRegisterController(std::move(controller), tabletId, update); } - void UnregisterController(const TInternalPathId pathId) { - return DoUnregisterController(pathId); + void UnregisterController(const TTabletId tabletId, const TInternalPathId pathId) { + return DoUnregisterController(tabletId, pathId); } }; @@ -85,20 +85,20 @@ class TActorAccessorsManager: public IDataAccessorsManager { using TBase = IDataAccessorsManager; const NActors::TActorId ActorId; std::shared_ptr AccessorsCallback; - virtual void DoAskData(const std::shared_ptr& request) override { - NActors::TActivationContext::Send(ActorId, std::make_unique(request)); + virtual void DoAskData(const TTabletId tabletId, const std::shared_ptr& request) override { + NActors::TActivationContext::Send(ActorId, std::make_unique(tabletId, request)); } - virtual void DoRegisterController(std::unique_ptr&& controller, const bool update) override { - NActors::TActivationContext::Send(ActorId, std::make_unique(std::move(controller), update)); + virtual void DoRegisterController(std::unique_ptr&& controller, const TTabletId tabletId, const bool update) override { + NActors::TActivationContext::Send(ActorId, std::make_unique(std::move(controller), tabletId, update)); } - virtual void DoUnregisterController(const TInternalPathId pathId) override { - NActors::TActivationContext::Send(ActorId, std::make_unique(pathId)); + virtual void DoUnregisterController(TTabletId tabletId, const TInternalPathId pathId) override { + NActors::TActivationContext::Send(ActorId, std::make_unique(tabletId, pathId)); } - virtual void DoAddPortion(const TPortionDataAccessor& accessor) override { - NActors::TActivationContext::Send(ActorId, std::make_unique(accessor)); + virtual void DoAddPortion(const TTabletId tabletId, const TPortionDataAccessor& accessor) override { + NActors::TActivationContext::Send(ActorId, std::make_unique(tabletId, accessor)); } - virtual void DoRemovePortion(const TPortionInfo::TConstPtr& portion) override { - NActors::TActivationContext::Send(ActorId, std::make_unique(portion)); + virtual void DoRemovePortion(const TTabletId tabletId, const TPortionInfo::TConstPtr& portion) override { + NActors::TActivationContext::Send(ActorId, std::make_unique(tabletId, portion)); } public: @@ -113,7 +113,12 @@ class TActorAccessorsManager: public IDataAccessorsManager { class TLocalManager: public IDataAccessorsManager { private: using TBase = IDataAccessorsManager; - THashMap> Managers; + using TManagerKey = std::pair; + + static TManagerKey makeManagerKey(TTabletId tabletId, const TInternalPathId pathId) { + return std::make_pair(tabletId, pathId); + } + THashMap> Managers; THashMap>> RequestsByPortion; TAccessorSignals Counters; const std::shared_ptr AccessorCallback; @@ -137,16 +142,16 @@ class TLocalManager: public IDataAccessorsManager { std::deque PortionsAsk; TPositiveControlInteger PortionsAskInFlight; - void DrainQueue(); + void DrainQueue(const TTabletId tabletId); - virtual void DoAskData(const std::shared_ptr& request) override; - virtual void DoRegisterController(std::unique_ptr&& controller, const bool update) override; - virtual void DoUnregisterController(const TInternalPathId pathId) override { - AFL_VERIFY(Managers.erase(pathId)); + virtual void DoAskData(TTabletId tabletId, const std::shared_ptr& request) override; + virtual void DoRegisterController(std::unique_ptr&& controller, TTabletId tabletId, const bool update) override; + virtual void DoUnregisterController(TTabletId tabletId, const TInternalPathId pathId) override { + AFL_VERIFY(Managers.erase(makeManagerKey(tabletId, pathId))); } - virtual void DoAddPortion(const TPortionDataAccessor& accessor) override; - virtual void DoRemovePortion(const TPortionInfo::TConstPtr& portionInfo) override { - auto it = Managers.find(portionInfo->GetPathId()); + virtual void DoAddPortion(const TTabletId tabletId, const TPortionDataAccessor& accessor) override; + virtual void DoRemovePortion(TTabletId tabletId, const TPortionInfo::TConstPtr& portionInfo) override { + auto it = Managers.find(makeManagerKey(tabletId, portionInfo->GetPathId())); AFL_VERIFY(it != Managers.end()); it->second->ModifyPortions({}, { portionInfo->GetPortionId() }); } @@ -155,17 +160,18 @@ class TLocalManager: public IDataAccessorsManager { class TTestingCallback: public IAccessorCallback { private: std::weak_ptr Manager; - virtual void OnAccessorsFetched(std::vector&& accessors) override { + virtual void OnAccessorsFetched(TTabletId tabletId, std::vector&& accessors) override { auto mImpl = Manager.lock(); if (!mImpl) { return; } for (auto&& i : accessors) { - mImpl->AddPortion(i); + mImpl->AddPortion(tabletId, i); } } public: + explicit TTestingCallback() {} void InitManager(const std::weak_ptr& manager) { Manager = manager; } @@ -178,7 +184,7 @@ class TLocalManager: public IDataAccessorsManager { return result; } - TLocalManager(const std::shared_ptr& callback) + explicit TLocalManager(const std::shared_ptr& callback) : TBase(NActors::TActorId()) , AccessorCallback(callback) { } diff --git a/ydb/core/tx/columnshard/data_accessor/node_actor.cpp b/ydb/core/tx/columnshard/data_accessor/node_actor.cpp new file mode 100644 index 000000000000..08c0947ed03c --- /dev/null +++ b/ydb/core/tx/columnshard/data_accessor/node_actor.cpp @@ -0,0 +1,19 @@ +#include "node_actor.h" + +namespace NKikimr::NOlap::NDataAccessorControl { + +NActors::IActor* TNodeActor::CreateActor() { + return new TNodeActor(); +} + +void TNodeActor::Handle(TEvAskServiceDataAccessors::TPtr& ev) { + Manager->AskData(ev->Get()->GetTabletId(), ev->Get()->GetRequest()); +} + +void TNodeActor::Bootstrap() { + AccessorsCallback = std::make_shared(SelfId()); + Manager = std::make_shared(AccessorsCallback); + Become(&TThis::StateWait); +} + +} diff --git a/ydb/core/tx/columnshard/data_accessor/node_actor.h b/ydb/core/tx/columnshard/data_accessor/node_actor.h new file mode 100644 index 000000000000..95acd47878b7 --- /dev/null +++ b/ydb/core/tx/columnshard/data_accessor/node_actor.h @@ -0,0 +1,68 @@ +#pragma once +#include "events.h" +#include "manager.h" + +#include "abstract/collector.h" + +#include +#include + +namespace NKikimr::NOlap::NDataAccessorControl { + +class TNodeActor: public TActorBootstrapped { +private: + std::shared_ptr Manager; + + std::shared_ptr AccessorsCallback; + + void StartStopping() { + PassAway(); + } + + void Handle(TEvRegisterController::TPtr& ev) { + Manager->RegisterController(ev->Get()->ExtractController(), ev->Get()->GetTabletId(), ev->Get()->IsUpdate()); + } + void Handle(TEvUnregisterController::TPtr& ev) { + Manager->UnregisterController(ev->Get()->GetTabletId(), ev->Get()->GetPathId()); + } + void Handle(TEvAddPortion::TPtr& ev) { + for (auto&& a : ev->Get()->ExtractAccessors()) { + Manager->AddPortion(ev->Get()->GetTabletId(), std::move(a)); + } + } + void Handle(TEvRemovePortion::TPtr& ev) { + Manager->RemovePortion(ev->Get()->GetTabletId(), ev->Get()->GetPortion()); + } + void Handle(TEvAskServiceDataAccessors::TPtr& ev); + +public: + + static inline TActorId MakeActorId(ui32 nodeId) { + char x[12] = {'s', 'h', 'a', 'r', 'e', + 'd', 'm', 'e', 't', 'a', 'd', 't'}; + return TActorId(nodeId, TStringBuf(x, 12)); + } + + static NActors::IActor* CreateActor(); + + TNodeActor() = default; + ~TNodeActor() = default; + + void Bootstrap(); + + STFUNC(StateWait) { + const NActors::TLogContextGuard lGuard = NActors::TLogContextBuilder::Build()("self_id", SelfId()); + switch (ev->GetTypeRewrite()) { + cFunc(NActors::TEvents::TEvPoison::EventType, StartStopping); + hFunc(TEvRegisterController, Handle); + hFunc(TEvUnregisterController, Handle); + hFunc(TEvAskServiceDataAccessors, Handle); + hFunc(TEvRemovePortion, Handle); + hFunc(TEvAddPortion, Handle); + default: + AFL_VERIFY(false); + } + } +}; + +} // namespace NKikimr::NOlap::NDataAccessorControl diff --git a/ydb/core/tx/columnshard/data_accessor/request.h b/ydb/core/tx/columnshard/data_accessor/request.h index 70d1a16eaba0..d0eaf8051c73 100644 --- a/ydb/core/tx/columnshard/data_accessor/request.h +++ b/ydb/core/tx/columnshard/data_accessor/request.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include @@ -127,7 +127,7 @@ class TPathFetchingState { return sb; } - TPathFetchingState(const TInternalPathId pathId) + explicit TPathFetchingState(const TInternalPathId pathId) : PathId(pathId) { } @@ -286,11 +286,12 @@ class TDataAccessorsRequest: public NColumnShard::TMonitoringObjectsCounterGetPortionId()).second); - PathIds.emplace(portion->GetPathId()); - auto it = PathIdStatus.find(portion->GetPathId()); + const auto& pathId = portion->GetPathId(); + PathIds.emplace(pathId); + auto it = PathIdStatus.find(pathId); if (it == PathIdStatus.end()) { PreparingCount.Inc(); - it = PathIdStatus.emplace(portion->GetPathId(), portion->GetPathId()).first; + it = PathIdStatus.emplace(pathId, TPathFetchingState{pathId}).first; } it->second.AddPortion(portion); } diff --git a/ydb/core/tx/columnshard/data_accessor/ya.make b/ydb/core/tx/columnshard/data_accessor/ya.make index f3212e91e74e..0355e0672a36 100644 --- a/ydb/core/tx/columnshard/data_accessor/ya.make +++ b/ydb/core/tx/columnshard/data_accessor/ya.make @@ -2,6 +2,7 @@ LIBRARY() SRCS( actor.cpp + node_actor.cpp events.cpp request.cpp manager.cpp diff --git a/ydb/core/tx/columnshard/engines/changes/abstract/compaction_info.h b/ydb/core/tx/columnshard/engines/changes/abstract/compaction_info.h index b1f51d9d74ad..fe99d6e8eb73 100644 --- a/ydb/core/tx/columnshard/engines/changes/abstract/compaction_info.h +++ b/ydb/core/tx/columnshard/engines/changes/abstract/compaction_info.h @@ -30,7 +30,7 @@ class TPlanCompactionInfo { return StartTime; } - TPlanCompactionInfo(const TInternalPathId pathId) + explicit TPlanCompactionInfo(const TInternalPathId pathId) : PathId(pathId) { } diff --git a/ydb/core/tx/columnshard/engines/changes/abstract/ya.make b/ydb/core/tx/columnshard/engines/changes/abstract/ya.make index 78095066a094..27b111dc5682 100644 --- a/ydb/core/tx/columnshard/engines/changes/abstract/ya.make +++ b/ydb/core/tx/columnshard/engines/changes/abstract/ya.make @@ -10,7 +10,7 @@ SRCS( ) PEERDIR( - ydb/core/tx/columnshard/counters/common + ydb/library/signals ydb/core/tx/columnshard/engines/changes/counters ydb/core/tablet_flat yql/essentials/core/expr_nodes diff --git a/ydb/core/tx/columnshard/engines/changes/compaction.cpp b/ydb/core/tx/columnshard/engines/changes/compaction.cpp index 40f08e502b8b..61b9e021dbae 100644 --- a/ydb/core/tx/columnshard/engines/changes/compaction.cpp +++ b/ydb/core/tx/columnshard/engines/changes/compaction.cpp @@ -32,7 +32,7 @@ void TCompactColumnEngineChanges::DoCompile(TFinalizationContext& context) { void TCompactColumnEngineChanges::DoStart(NColumnShard::TColumnShard& self) { TBase::DoStart(self); - self.BackgroundController.StartCompaction(NKikimr::NOlap::TPlanCompactionInfo(GranuleMeta->GetPathId())); + self.BackgroundController.StartCompaction(GranuleMeta->GetPathId()); NeedGranuleStatusProvide = true; GranuleMeta->OnCompactionStarted(); } @@ -45,7 +45,7 @@ void TCompactColumnEngineChanges::DoWriteIndexOnComplete(NColumnShard::TColumnSh } void TCompactColumnEngineChanges::DoOnFinish(NColumnShard::TColumnShard& self, TChangesFinishContext& context) { - self.BackgroundController.FinishCompaction(TPlanCompactionInfo(GranuleMeta->GetPathId())); + self.BackgroundController.FinishCompaction(GranuleMeta->GetPathId()); Y_ABORT_UNLESS(NeedGranuleStatusProvide); if (context.FinishedSuccessfully) { GranuleMeta->OnCompactionFinished(); diff --git a/ydb/core/tx/columnshard/engines/changes/counters/changes.h b/ydb/core/tx/columnshard/engines/changes/counters/changes.h index 2b2f301ae63b..377444fc5f88 100644 --- a/ydb/core/tx/columnshard/engines/changes/counters/changes.h +++ b/ydb/core/tx/columnshard/engines/changes/counters/changes.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include diff --git a/ydb/core/tx/columnshard/engines/changes/counters/general.h b/ydb/core/tx/columnshard/engines/changes/counters/general.h index 98deee42a6af..e4fff50744ab 100644 --- a/ydb/core/tx/columnshard/engines/changes/counters/general.h +++ b/ydb/core/tx/columnshard/engines/changes/counters/general.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include diff --git a/ydb/core/tx/columnshard/engines/changes/counters/ya.make b/ydb/core/tx/columnshard/engines/changes/counters/ya.make index b557eaee1e58..3b1dc197d21b 100644 --- a/ydb/core/tx/columnshard/engines/changes/counters/ya.make +++ b/ydb/core/tx/columnshard/engines/changes/counters/ya.make @@ -10,7 +10,7 @@ PEERDIR( ydb/library/actors/core ydb/core/tablet_flat ydb/core/tx/columnshard/blobs_action/counters - ydb/core/tx/columnshard/counters/common + ydb/library/signals ) GENERATE_ENUM_SERIALIZATION(changes.h) diff --git a/ydb/core/tx/columnshard/engines/column_engine.h b/ydb/core/tx/columnshard/engines/column_engine.h index b7ef4f5f4edb..e6a268f49196 100644 --- a/ydb/core/tx/columnshard/engines/column_engine.h +++ b/ydb/core/tx/columnshard/engines/column_engine.h @@ -150,7 +150,7 @@ class IColumnEngine { virtual std::shared_ptr StartInsert(std::vector&& dataToIndex) noexcept = 0; virtual std::shared_ptr StartCompaction(const std::shared_ptr& dataLocksManager) noexcept = 0; virtual ui64 GetCompactionPriority(const std::shared_ptr& dataLocksManager, const std::set& pathIds, - const std::optional waitingPriority) noexcept = 0; + const std::optional waitingPriority) const noexcept = 0; virtual std::shared_ptr StartCleanupPortions(const TSnapshot& snapshot, const THashSet& pathsToDrop, const std::shared_ptr& dataLocksManager) noexcept = 0; virtual std::shared_ptr StartCleanupTables(const THashSet& pathsToDrop) noexcept = 0; diff --git a/ydb/core/tx/columnshard/engines/column_engine_logs.cpp b/ydb/core/tx/columnshard/engines/column_engine_logs.cpp index 2a9dd4be6677..add8ee07f80c 100644 --- a/ydb/core/tx/columnshard/engines/column_engine_logs.cpp +++ b/ydb/core/tx/columnshard/engines/column_engine_logs.cpp @@ -30,7 +30,7 @@ namespace NKikimr::NOlap { TColumnEngineForLogs::TColumnEngineForLogs(const ui64 tabletId, const std::shared_ptr& schemaCache, const std::shared_ptr& dataAccessorsManager, const std::shared_ptr& storagesManager, const TSnapshot& snapshot, const ui64 presetId, const TSchemaInitializationData& schema, const std::shared_ptr& counters) - : GranulesStorage(std::make_shared(SignalCounters, dataAccessorsManager, storagesManager)) + : GranulesStorage(std::make_shared(SignalCounters, dataAccessorsManager, storagesManager, (TTabletId)tabletId)) , DataAccessorsManager(dataAccessorsManager) , StoragesManager(storagesManager) , SchemaObjectsCache(schemaCache) @@ -45,7 +45,7 @@ TColumnEngineForLogs::TColumnEngineForLogs(const ui64 tabletId, const std::share TColumnEngineForLogs::TColumnEngineForLogs(const ui64 tabletId, const std::shared_ptr& schemaCache, const std::shared_ptr& dataAccessorsManager, const std::shared_ptr& storagesManager, const TSnapshot& snapshot, const ui64 presetId, TIndexInfo&& schema, const std::shared_ptr& counters) - : GranulesStorage(std::make_shared(SignalCounters, dataAccessorsManager, storagesManager)) + : GranulesStorage(std::make_shared(SignalCounters, dataAccessorsManager, storagesManager, (TTabletId)tabletId)) , DataAccessorsManager(dataAccessorsManager) , StoragesManager(storagesManager) , SchemaObjectsCache(schemaCache) @@ -189,7 +189,7 @@ std::shared_ptr TColumnEngineForLogs::StartInsert(st } ui64 TColumnEngineForLogs::GetCompactionPriority(const std::shared_ptr& dataLocksManager, const std::set& pathIds, - const std::optional waitingPriority) noexcept { + const std::optional waitingPriority) const noexcept { auto priority = GranulesStorage->GetCompactionPriority(dataLocksManager, pathIds, waitingPriority); if (!priority) { return 0; diff --git a/ydb/core/tx/columnshard/engines/column_engine_logs.h b/ydb/core/tx/columnshard/engines/column_engine_logs.h index 89a1838a3015..63d2ec5d83e8 100644 --- a/ydb/core/tx/columnshard/engines/column_engine_logs.h +++ b/ydb/core/tx/columnshard/engines/column_engine_logs.h @@ -147,7 +147,7 @@ class TColumnEngineForLogs: public IColumnEngine { } std::shared_ptr StartInsert(std::vector&& dataToIndex) noexcept override; ui64 GetCompactionPriority(const std::shared_ptr& dataLocksManager, const std::set& pathIds, - const std::optional waitingPriority) noexcept override; + const std::optional waitingPriority) const noexcept override; std::shared_ptr StartCompaction(const std::shared_ptr& dataLocksManager) noexcept override; std::shared_ptr StartCleanupPortions(const TSnapshot& snapshot, const THashSet& pathsToDrop, const std::shared_ptr& dataLocksManager) noexcept override; diff --git a/ydb/core/tx/columnshard/engines/portions/meta.h b/ydb/core/tx/columnshard/engines/portions/meta.h index 579c80eb4bc7..a91b29dd08e4 100644 --- a/ydb/core/tx/columnshard/engines/portions/meta.h +++ b/ydb/core/tx/columnshard/engines/portions/meta.h @@ -65,7 +65,7 @@ class TPortionMetaBase { class TPortionMeta: public TPortionMetaBase { private: using TBase = TPortionMetaBase; - NArrow::TFirstLastSpecialKeys ReplaceKeyEdges; // first and last PK rows + NArrow::TFirstLastSpecialKeys ReplaceKeyEdges; YDB_READONLY_DEF(TString, TierName); YDB_READONLY(ui32, DeletionsCount, 0); YDB_READONLY(ui32, CompactionLevel, 0); diff --git a/ydb/core/tx/columnshard/engines/predicate/container.cpp b/ydb/core/tx/columnshard/engines/predicate/container.cpp index 780a3390befa..0c0cf5baf79c 100644 --- a/ydb/core/tx/columnshard/engines/predicate/container.cpp +++ b/ydb/core/tx/columnshard/engines/predicate/container.cpp @@ -179,4 +179,36 @@ TConclusion TPredicateContainer::BuildPredicateTo( } } +NArrow::TColumnFilter TPredicateContainer::BuildFilter(const std::shared_ptr& data) const { + if (!Object) { + auto result = NArrow::TColumnFilter::BuildAllowFilter(); + result.Add(true, data->GetRecordsCount()); + return result; + } + if (!data->GetRecordsCount()) { + return NArrow::TColumnFilter::BuildAllowFilter(); + } + auto sortingFields = Object->Batch->schema()->field_names(); + auto position = NArrow::NMerger::TRWSortableBatchPosition(data, 0, sortingFields, {}, false); + const auto border = NArrow::NMerger::TSortableBatchPosition(Object->Batch, 0, sortingFields, {}, false); + const bool needUppedBound = CompareType == NArrow::ECompareType::LESS_OR_EQUAL || CompareType == NArrow::ECompareType::GREATER; + const auto findBound = position.FindBound(position, 0, data->GetRecordsCount() - 1, border, needUppedBound); + const ui64 rowsBeforeBound = findBound ? findBound->GetPosition() : data->GetRecordsCount(); + + auto filter = NArrow::TColumnFilter::BuildAllowFilter(); + switch (CompareType) { + case NArrow::ECompareType::LESS: + case NArrow::ECompareType::LESS_OR_EQUAL: + filter.Add(true, rowsBeforeBound); + filter.Add(false, data->GetRecordsCount() - rowsBeforeBound); + break; + case NArrow::ECompareType::GREATER: + case NArrow::ECompareType::GREATER_OR_EQUAL: + filter.Add(false, rowsBeforeBound); + filter.Add(true, data->GetRecordsCount() - rowsBeforeBound); + break; + } + return filter; } + +} // namespace NKikimr::NOlap diff --git a/ydb/core/tx/columnshard/engines/predicate/container.h b/ydb/core/tx/columnshard/engines/predicate/container.h index bb30aebc59a0..78dcb041447a 100644 --- a/ydb/core/tx/columnshard/engines/predicate/container.h +++ b/ydb/core/tx/columnshard/engines/predicate/container.h @@ -1,7 +1,10 @@ #pragma once #include "predicate.h" +#include #include +#include +#include #include #include @@ -115,12 +118,7 @@ class TPredicateContainer { static TConclusion BuildPredicateTo( std::shared_ptr object, const std::shared_ptr& pkSchema); - NKikimr::NArrow::TColumnFilter BuildFilter(const arrow::Datum& data) const { - if (!Object) { - return NArrow::TColumnFilter::BuildAllowFilter(); - } - return NArrow::TColumnFilter::MakePredicateFilter(data, Object->Batch, CompareType); - } + NArrow::TColumnFilter BuildFilter(const std::shared_ptr& data) const; }; } // namespace NKikimr::NOlap diff --git a/ydb/core/tx/columnshard/engines/predicate/filter.cpp b/ydb/core/tx/columnshard/engines/predicate/filter.cpp index 28c47e6c89a4..002988f9aadd 100644 --- a/ydb/core/tx/columnshard/engines/predicate/filter.cpp +++ b/ydb/core/tx/columnshard/engines/predicate/filter.cpp @@ -7,13 +7,14 @@ namespace NKikimr::NOlap { -NKikimr::NArrow::TColumnFilter TPKRangesFilter::BuildFilter(const arrow::Datum& data) const { +NKikimr::NArrow::TColumnFilter TPKRangesFilter::BuildFilter(const std::shared_ptr& data) const { if (SortedRanges.empty()) { return NArrow::TColumnFilter::BuildAllowFilter(); } - NArrow::TColumnFilter result = SortedRanges.front().BuildFilter(data); - for (ui32 i = 1; i < SortedRanges.size(); ++i) { - result = result.Or(SortedRanges[i].BuildFilter(data)); + + auto result = NArrow::TColumnFilter::BuildDenyFilter(); + for (const auto& range : SortedRanges) { + result = result.Or(range.BuildFilter(data)); } return result; } diff --git a/ydb/core/tx/columnshard/engines/predicate/filter.h b/ydb/core/tx/columnshard/engines/predicate/filter.h index 93a52b46a5cd..0241cf20fe5b 100644 --- a/ydb/core/tx/columnshard/engines/predicate/filter.h +++ b/ydb/core/tx/columnshard/engines/predicate/filter.h @@ -64,7 +64,7 @@ class TPKRangesFilter { TPKRangeFilter::EUsageClass GetUsageClass(const NArrow::TReplaceKey& start, const NArrow::TReplaceKey& end) const; bool CheckPoint(const NArrow::TReplaceKey& point) const; - NArrow::TColumnFilter BuildFilter(const arrow::Datum& data) const; + NArrow::TColumnFilter BuildFilter(const std::shared_ptr& data) const; std::set GetColumnNames() const { std::set result; @@ -120,6 +120,8 @@ class ICursorEntity { class IScanCursor { private: + YDB_ACCESSOR_DEF(std::optional, TabletId); + virtual const std::shared_ptr& DoGetPKCursor() const = 0; virtual bool DoCheckEntityIsBorder(const ICursorEntity& entity, bool& usage) const = 0; virtual bool DoCheckSourceIntervalUsage(const ui64 sourceId, const ui32 indexStart, const ui32 recordsCount) const = 0; @@ -146,11 +148,17 @@ class IScanCursor { } TConclusionStatus DeserializeFromProto(const NKikimrKqp::TEvKqpScanCursor& proto) { + if (proto.HasTabletId()) { + TabletId = proto.GetTabletId(); + } return DoDeserializeFromProto(proto); } NKikimrKqp::TEvKqpScanCursor SerializeToProto() const { NKikimrKqp::TEvKqpScanCursor result; + if (TabletId) { + result.SetTabletId(*TabletId); + } DoSerializeToProto(result); return result; } @@ -168,7 +176,6 @@ class TSimpleScanCursor: public IScanCursor { } virtual const std::shared_ptr& DoGetPKCursor() const override { - AFL_VERIFY(!!PrimaryKey); return PrimaryKey; } @@ -242,7 +249,7 @@ class TNotSortedSimpleScanCursor: public TSimpleScanCursor { if (SourceId != entity.GetEntityId()) { return false; } - AFL_VERIFY(RecordIndex <= entity.GetEntityRecordsCount()); + AFL_VERIFY(RecordIndex <= entity.GetEntityRecordsCount())("index", RecordIndex)("count", entity.GetEntityRecordsCount()); usage = RecordIndex < entity.GetEntityRecordsCount(); return true; } diff --git a/ydb/core/tx/columnshard/engines/predicate/range.cpp b/ydb/core/tx/columnshard/engines/predicate/range.cpp index b00ed126d279..f7516e32d690 100644 --- a/ydb/core/tx/columnshard/engines/predicate/range.cpp +++ b/ydb/core/tx/columnshard/engines/predicate/range.cpp @@ -34,8 +34,8 @@ std::set TPKRangeFilter::GetColumnNames() const { return result; } -NKikimr::NArrow::TColumnFilter TPKRangeFilter::BuildFilter(const arrow::Datum& data) const { - NArrow::TColumnFilter result = PredicateTo.BuildFilter(data); +NArrow::TColumnFilter TPKRangeFilter::BuildFilter(const std::shared_ptr& data) const { + auto result = PredicateTo.BuildFilter(data); return result.And(PredicateFrom.BuildFilter(data)); } diff --git a/ydb/core/tx/columnshard/engines/predicate/range.h b/ydb/core/tx/columnshard/engines/predicate/range.h index fab63a7b9bca..91e7d58c4a77 100644 --- a/ydb/core/tx/columnshard/engines/predicate/range.h +++ b/ydb/core/tx/columnshard/engines/predicate/range.h @@ -36,7 +36,7 @@ class TPKRangeFilter { static TConclusion Build(TPredicateContainer&& from, TPredicateContainer&& to); - NArrow::TColumnFilter BuildFilter(const arrow::Datum& data) const; + NArrow::TColumnFilter BuildFilter(const std::shared_ptr& data) const; bool IsUsed(const TPortionInfo& info) const; bool CheckPoint(const NArrow::TReplaceKey& point) const; diff --git a/ydb/core/tx/columnshard/engines/reader/abstract/abstract.h b/ydb/core/tx/columnshard/engines/reader/abstract/abstract.h index 37ba57b89985..6968fd1be79f 100644 --- a/ydb/core/tx/columnshard/engines/reader/abstract/abstract.h +++ b/ydb/core/tx/columnshard/engines/reader/abstract/abstract.h @@ -7,7 +7,7 @@ namespace NKikimr::NOlap::NReader { class TScanIteratorBase { protected: - virtual void DoOnSentDataFromInterval(const ui32 /*intervalIdx*/) const { + virtual void DoOnSentDataFromInterval(const TPartialSourceAddress& /*intervalAddress*/) { } public: @@ -21,9 +21,9 @@ class TScanIteratorBase { virtual const TReadStats& GetStats() const; - void OnSentDataFromInterval(const std::optional intervalIdx) const { - if (intervalIdx) { - DoOnSentDataFromInterval(*intervalIdx); + void OnSentDataFromInterval(const std::optional& intervalAddress) { + if (intervalAddress) { + DoOnSentDataFromInterval(*intervalAddress); } } diff --git a/ydb/core/tx/columnshard/engines/reader/abstract/read_context.h b/ydb/core/tx/columnshard/engines/reader/abstract/read_context.h index 22bb1ce13920..c9a63b0bf53f 100644 --- a/ydb/core/tx/columnshard/engines/reader/abstract/read_context.h +++ b/ydb/core/tx/columnshard/engines/reader/abstract/read_context.h @@ -13,6 +13,7 @@ namespace NKikimr::NOlap::NReader { class TPartialReadResult; +class TPartialSourceAddress; class TComputeShardingPolicy { private: @@ -170,7 +171,7 @@ class IDataReader { Started = true; return DoStart(); } - virtual void OnSentDataFromInterval(const ui32 intervalIdx) const = 0; + virtual void OnSentDataFromInterval(const TPartialSourceAddress& address) = 0; const TReadContext& GetContext() const { return *Context; diff --git a/ydb/core/tx/columnshard/engines/reader/abstract/read_metadata.h b/ydb/core/tx/columnshard/engines/reader/abstract/read_metadata.h index c375ff2ccf89..aac729f0a4aa 100644 --- a/ydb/core/tx/columnshard/engines/reader/abstract/read_metadata.h +++ b/ydb/core/tx/columnshard/engines/reader/abstract/read_metadata.h @@ -1,9 +1,9 @@ #pragma once +#include #include #include #include #include -#include namespace NKikimr::NOlap { class TPortionInfo; @@ -46,6 +46,7 @@ class TReadMetadataBase { TSnapshot RequestSnapshot; std::optional RequestShardingInfo; std::shared_ptr ScanCursor; + const ui64 TabletId; virtual void DoOnReadFinished(NColumnShard::TColumnShard& /*owner*/) const { } virtual void DoOnBeforeStartReading(NColumnShard::TColumnShard& /*owner*/) const { @@ -61,7 +62,11 @@ class TReadMetadataBase { public: using TConstPtr = std::shared_ptr; - void SetRequestedLimit(const ui64 value) { + ui64 GetTabletId() const { + return TabletId; + } + + void SetRequestedLimit(const ui64 value) { AFL_VERIFY(!RequestedLimit); if (value == 0 || value >= Max()) { return; @@ -172,20 +177,23 @@ class TReadMetadataBase { } TReadMetadataBase(const std::shared_ptr index, const ESorting sorting, const TProgramContainer& ssaProgram, - const std::shared_ptr& schema, const TSnapshot& requestSnapshot, const std::shared_ptr& scanCursor) + const std::shared_ptr& schema, const TSnapshot& requestSnapshot, const std::shared_ptr& scanCursor, + const ui64 tabletId) : Sorting(sorting) , Program(ssaProgram) , IndexVersionsPointer(index) , RequestSnapshot(requestSnapshot) , ScanCursor(scanCursor) - , ResultIndexSchema(schema) - { + , TabletId(tabletId) + , ResultIndexSchema(schema) { + AFL_VERIFY(!ScanCursor || !ScanCursor->GetTabletId() || (*ScanCursor->GetTabletId() == TabletId))("cursor", ScanCursor->GetTabletId())( + "tablet_id", TabletId); } virtual ~TReadMetadataBase() = default; virtual TString DebugString() const { return TStringBuilder() << " predicate{" << (PKRangesFilter ? PKRangesFilter->DebugString() : "no_initialized") << "}" - << " " << Sorting << " sorted"; + << " " << Sorting << " sorted"; } std::set GetProcessingColumnIds() const { diff --git a/ydb/core/tx/columnshard/engines/reader/actor/actor.cpp b/ydb/core/tx/columnshard/engines/reader/actor/actor.cpp index c424c84b9ac8..f847b6d177e0 100644 --- a/ydb/core/tx/columnshard/engines/reader/actor/actor.cpp +++ b/ydb/core/tx/columnshard/engines/reader/actor/actor.cpp @@ -265,7 +265,7 @@ bool TColumnShardScan::ProduceResults() noexcept { } Result->LastCursorProto = CurrentLastReadKey->SerializeToProto(); SendResult(false, false); - ScanIterator->OnSentDataFromInterval(result.GetNotFinishedIntervalIdx()); + ScanIterator->OnSentDataFromInterval(result.GetNotFinishedInterval()); ACFL_DEBUG("stage", "finished")("iterator", ScanIterator->DebugString()); return true; } diff --git a/ydb/core/tx/columnshard/engines/reader/common/conveyor_task.cpp b/ydb/core/tx/columnshard/engines/reader/common/conveyor_task.cpp index ac778b00a6c7..1bcd853bec32 100644 --- a/ydb/core/tx/columnshard/engines/reader/common/conveyor_task.cpp +++ b/ydb/core/tx/columnshard/engines/reader/common/conveyor_task.cpp @@ -4,7 +4,7 @@ namespace NKikimr::NOlap::NReader { -NKikimr::TConclusionStatus IDataTasksProcessor::ITask::DoExecute(const std::shared_ptr& taskPtr) { +void IDataTasksProcessor::ITask::DoExecute(const std::shared_ptr& taskPtr) { auto result = DoExecuteImpl(); if (result.IsFail()) { NActors::TActivationContext::AsActorContext().Send(OwnerId, new NColumnShard::TEvPrivate::TEvTaskProcessedResult(result)); @@ -12,7 +12,6 @@ NKikimr::TConclusionStatus IDataTasksProcessor::ITask::DoExecute(const std::shar NActors::TActivationContext::AsActorContext().Send( OwnerId, new NColumnShard::TEvPrivate::TEvTaskProcessedResult(static_pointer_cast(taskPtr))); } - return result; } void IDataTasksProcessor::ITask::DoOnCannotExecute(const TString& reason) { diff --git a/ydb/core/tx/columnshard/engines/reader/common/conveyor_task.h b/ydb/core/tx/columnshard/engines/reader/common/conveyor_task.h index 0342577c2554..504bb41b6488 100644 --- a/ydb/core/tx/columnshard/engines/reader/common/conveyor_task.h +++ b/ydb/core/tx/columnshard/engines/reader/common/conveyor_task.h @@ -28,7 +28,7 @@ class IDataTasksProcessor { virtual TConclusionStatus DoExecuteImpl() = 0; protected: - virtual TConclusionStatus DoExecute(const std::shared_ptr& taskPtr) override final; + virtual void DoExecute(const std::shared_ptr& taskPtr) override final; virtual void DoOnCannotExecute(const TString& reason) override; public: diff --git a/ydb/core/tx/columnshard/engines/reader/common/description.h b/ydb/core/tx/columnshard/engines/reader/common/description.h index d3dba0d06e10..0572c4e8fc40 100644 --- a/ydb/core/tx/columnshard/engines/reader/common/description.h +++ b/ydb/core/tx/columnshard/engines/reader/common/description.h @@ -21,6 +21,7 @@ struct TReadDescription { std::shared_ptr ScanCursor; YDB_ACCESSOR_DEF(TString, ScanIdentifier); YDB_ACCESSOR(ERequestSorting, Sorting, ERequestSorting::NONE); + YDB_READONLY(ui64, TabletId, 0); public: // Table @@ -47,9 +48,10 @@ struct TReadDescription { ScanCursor = cursor; } - TReadDescription(const TSnapshot& snapshot, const ERequestSorting sorting) + TReadDescription(const ui64 tabletId, const TSnapshot& snapshot, const ERequestSorting sorting) : Snapshot(snapshot) , Sorting(sorting) + , TabletId(tabletId) , PKRangesFilter(std::make_shared()) { } diff --git a/ydb/core/tx/columnshard/engines/reader/common/result.cpp b/ydb/core/tx/columnshard/engines/reader/common/result.cpp index 92f55f3dfc77..38805a998232 100644 --- a/ydb/core/tx/columnshard/engines/reader/common/result.cpp +++ b/ydb/core/tx/columnshard/engines/reader/common/result.cpp @@ -55,12 +55,12 @@ std::vector> TPartialReadResult::SplitResult TPartialReadResult::TPartialReadResult(const std::vector>& resourceGuards, const std::shared_ptr& gGuard, const NArrow::TShardedRecordBatch& batch, const std::shared_ptr& scanCursor, const std::shared_ptr& context, - const std::optional notFinishedIntervalIdx) + const std::optional notFinishedInterval) : ResourceGuards(resourceGuards) , GroupGuard(gGuard) , ResultBatch(batch) , ScanCursor(scanCursor) - , NotFinishedIntervalIdx(notFinishedIntervalIdx) + , NotFinishedInterval(notFinishedInterval) , Guard(TValidator::CheckNotNull(context)->GetCounters().GetResultsForReplyGuard()) { Y_ABORT_UNLESS(ResultBatch.GetRecordsCount()); Y_ABORT_UNLESS(ScanCursor); diff --git a/ydb/core/tx/columnshard/engines/reader/common/result.h b/ydb/core/tx/columnshard/engines/reader/common/result.h index f4e7d7d4b1ee..6fff2c86083c 100644 --- a/ydb/core/tx/columnshard/engines/reader/common/result.h +++ b/ydb/core/tx/columnshard/engines/reader/common/result.h @@ -12,6 +12,22 @@ namespace NKikimr::NOlap::NReader { class TReadContext; +class TPartialSourceAddress { +private: + YDB_READONLY(ui32, SourceId, 0); + YDB_READONLY(ui32, SourceIdx, 0); + YDB_READONLY(ui32, SyncPointIndex, 0); + +public: + TPartialSourceAddress(const ui32 sourceId, const ui32 sourceIdx, const ui32 syncPointIndex) + : SourceId(sourceId) + , SourceIdx(sourceIdx) + , SyncPointIndex(syncPointIndex) + { + + } +}; + // Represents a batch of rows produced by ASC or DESC scan with applied filters and partial aggregation class TPartialReadResult: public TNonCopyable { private: @@ -22,7 +38,7 @@ class TPartialReadResult: public TNonCopyable { // This 1-row batch contains the last key that was read while producing the ResultBatch. // NOTE: it might be different from the Key of last row in ResulBatch in case of filtering/aggregation/limit std::shared_ptr ScanCursor; - YDB_READONLY_DEF(std::optional, NotFinishedIntervalIdx); + YDB_READONLY_DEF(std::optional, NotFinishedInterval); const NColumnShard::TCounterGuard Guard; public: @@ -61,11 +77,11 @@ class TPartialReadResult: public TNonCopyable { explicit TPartialReadResult(const std::vector>& resourceGuards, const std::shared_ptr& gGuard, const NArrow::TShardedRecordBatch& batch, const std::shared_ptr& scanCursor, const std::shared_ptr& context, - const std::optional notFinishedIntervalIdx); + const std::optional notFinishedInterval); explicit TPartialReadResult(const NArrow::TShardedRecordBatch& batch, const std::shared_ptr& scanCursor, - const std::shared_ptr& context, const std::optional notFinishedIntervalIdx) - : TPartialReadResult({}, nullptr, batch, scanCursor, context, notFinishedIntervalIdx) { + const std::shared_ptr& context, const std::optional notFinishedInterval) + : TPartialReadResult({}, nullptr, batch, scanCursor, context, notFinishedInterval) { } }; diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/constructor/read_metadata.cpp b/ydb/core/tx/columnshard/engines/reader/common_reader/constructor/read_metadata.cpp index 1ad7b8d3d3cb..a42de044970c 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/constructor/read_metadata.cpp +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/constructor/read_metadata.cpp @@ -44,7 +44,7 @@ TConclusionStatus TReadMetadata::Init( TReadMetadata::TReadMetadata(const std::shared_ptr& schemaIndex, const TReadDescription& read) : TBase(schemaIndex, read.GetSorting(), read.GetProgram(), schemaIndex->GetSchemaVerified(read.GetSnapshot()), read.GetSnapshot(), - read.GetScanCursorOptional()) + read.GetScanCursorOptional(), read.GetTabletId()) , PathId(read.PathId) , ReadStats(std::make_shared()) { } diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/columns_set.h b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/columns_set.h index a21652522430..4a14d95727f2 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/columns_set.h +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/columns_set.h @@ -14,13 +14,6 @@ enum class EMemType { RawSequential }; -enum class EStageFeaturesIndexes { - Accessors = 0, - Filter = 1, - Fetching = 2, - Merge = 3 -}; - class TIndexesSet { private: YDB_READONLY_DEF(std::vector, IndexIds); diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/constructor.cpp b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/constructor.cpp index 800ef6841e73..6d4027801631 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/constructor.cpp +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/constructor.cpp @@ -10,7 +10,7 @@ void TBlobsFetcherTask::DoOnDataReady(const std::shared_ptrAddEvent("fbf")); Source->MutableStageData().AddBlobs(Source->DecodeBlobAddresses(ExtractBlobsData())); AFL_VERIFY(Step.Next()); - auto task = std::make_shared(Source, std::move(Step), Context->GetCommonContext()->GetScanActorId()); + auto task = std::make_shared(Source, std::move(Step), Context->GetCommonContext()->GetScanActorId(), false); NConveyor::TScanServiceOperator::SendTaskToExecute(task, Context->GetCommonContext()->GetConveyorProcessId()); } @@ -54,7 +54,7 @@ void TColumnsFetcherTask::DoOnDataReady(const std::shared_ptrMutableStageData().AddFetcher(i.second); } - auto task = std::make_shared(Source, std::move(Cursor), Source->GetContext()->GetCommonContext()->GetScanActorId()); + auto task = std::make_shared(Source, std::move(Cursor), Source->GetContext()->GetCommonContext()->GetScanActorId(), false); NConveyor::TScanServiceOperator::SendTaskToExecute(task, Source->GetContext()->GetCommonContext()->GetConveyorProcessId()); } else { FOR_DEBUG_LOG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG, Source->AddEvent("cf_next")); diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetch_steps.cpp b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetch_steps.cpp index 51bfe780e313..3559e599b051 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetch_steps.cpp +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetch_steps.cpp @@ -48,25 +48,28 @@ bool TAllocateMemoryStep::TFetchingStepAllocation::DoOnAllocated(std::shared_ptr guard->Release(); return false; } - if (StageIndex == EStageFeaturesIndexes::Accessors) { + if (StageIndex == NArrow::NSSA::IMemoryCalculationPolicy::EStage::Accessors) { data->MutableStageData().SetAccessorsGuard(std::move(guard)); } else { data->RegisterAllocationGuard(std::move(guard)); } - Step.Next(); + if (NeedNextStep) { + Step.Next(); + } FOR_DEBUG_LOG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG, data->AddEvent("fmalloc")); - auto task = std::make_shared(data, std::move(Step), data->GetContext()->GetCommonContext()->GetScanActorId()); + auto task = std::make_shared(data, std::move(Step), data->GetContext()->GetCommonContext()->GetScanActorId(), false); NConveyor::TScanServiceOperator::SendTaskToExecute(task, data->GetContext()->GetCommonContext()->GetConveyorProcessId()); return true; } -TAllocateMemoryStep::TFetchingStepAllocation::TFetchingStepAllocation( - const std::shared_ptr& source, const ui64 mem, const TFetchingScriptCursor& step, const EStageFeaturesIndexes stageIndex) +TAllocateMemoryStep::TFetchingStepAllocation::TFetchingStepAllocation(const std::shared_ptr& source, const ui64 mem, + const TFetchingScriptCursor& step, const NArrow::NSSA::IMemoryCalculationPolicy::EStage stageIndex, const bool needNextStep) : TBase(mem) , Source(source) , Step(step) , TasksGuard(source->GetContext()->GetCommonContext()->GetCounters().GetResourcesAllocationTasksGuard()) - , StageIndex(stageIndex) { + , StageIndex(stageIndex) + , NeedNextStep(needNextStep) { } void TAllocateMemoryStep::TFetchingStepAllocation::DoOnAllocationImpossible(const TString& errorMessage) { @@ -75,6 +78,8 @@ void TAllocateMemoryStep::TFetchingStepAllocation::DoOnAllocationImpossible(cons FOR_DEBUG_LOG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG, sourcePtr->AddEvent("fail_malloc")); sourcePtr->GetContext()->GetCommonContext()->AbortWithError( "cannot allocate memory for step " + Step.GetName() + ": '" + errorMessage + "'"); + } else { + AFL_WARN(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "allocation_impossible")("error", errorMessage); } } diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetch_steps.h b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetch_steps.h index 0123678d75c9..3b8abd40ea48 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetch_steps.h +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetch_steps.h @@ -21,25 +21,10 @@ class TAllocateMemoryStep: public IFetchingStep { }; std::vector Packs; THashMap> Control; - const EStageFeaturesIndexes StageIndex; + const NArrow::NSSA::IMemoryCalculationPolicy::EStage StageIndex; const std::optional PredefinedSize; protected: - class TFetchingStepAllocation: public NGroupedMemoryManager::IAllocation { - private: - using TBase = NGroupedMemoryManager::IAllocation; - std::weak_ptr Source; - TFetchingScriptCursor Step; - NColumnShard::TCounterGuard TasksGuard; - const EStageFeaturesIndexes StageIndex; - virtual bool DoOnAllocated(std::shared_ptr&& guard, - const std::shared_ptr& allocation) override; - virtual void DoOnAllocationImpossible(const TString& errorMessage) override; - - public: - TFetchingStepAllocation(const std::shared_ptr& source, const ui64 mem, const TFetchingScriptCursor& step, - const EStageFeaturesIndexes stageIndex); - }; virtual TConclusion DoExecuteInplace(const std::shared_ptr& source, const TFetchingScriptCursor& step) const override; virtual ui64 GetProcessingDataSize(const std::shared_ptr& source) const override; virtual TString DoDebugString() const override { @@ -53,6 +38,22 @@ class TAllocateMemoryStep: public IFetchingStep { } public: + class TFetchingStepAllocation: public NGroupedMemoryManager::IAllocation { + private: + using TBase = NGroupedMemoryManager::IAllocation; + std::weak_ptr Source; + TFetchingScriptCursor Step; + NColumnShard::TCounterGuard TasksGuard; + const NArrow::NSSA::IMemoryCalculationPolicy::EStage StageIndex; + const bool NeedNextStep; + virtual bool DoOnAllocated(std::shared_ptr&& guard, + const std::shared_ptr& allocation) override; + virtual void DoOnAllocationImpossible(const TString& errorMessage) override; + + public: + TFetchingStepAllocation(const std::shared_ptr& source, const ui64 mem, const TFetchingScriptCursor& step, + const NArrow::NSSA::IMemoryCalculationPolicy::EStage stageIndex, const bool needNextStep = true); + }; void AddAllocation(const TColumnsSetIds& ids, const EMemType memType) { if (!ids.GetColumnsCount()) { return; @@ -62,17 +63,17 @@ class TAllocateMemoryStep: public IFetchingStep { } Packs.emplace_back(ids, memType); } - EStageFeaturesIndexes GetStage() const { + NArrow::NSSA::IMemoryCalculationPolicy::EStage GetStage() const { return StageIndex; } - TAllocateMemoryStep(const TColumnsSetIds& columns, const EMemType memType, const EStageFeaturesIndexes stageIndex) + TAllocateMemoryStep(const TColumnsSetIds& columns, const EMemType memType, const NArrow::NSSA::IMemoryCalculationPolicy::EStage stageIndex) : TBase("ALLOCATE_MEMORY::" + ::ToString(stageIndex)) , StageIndex(stageIndex) { AddAllocation(columns, memType); } - TAllocateMemoryStep(const ui64 memSize, const EStageFeaturesIndexes stageIndex) + TAllocateMemoryStep(const ui64 memSize, const NArrow::NSSA::IMemoryCalculationPolicy::EStage stageIndex) : TBase("ALLOCATE_MEMORY::" + ::ToString(stageIndex)) , StageIndex(stageIndex) , PredefinedSize(memSize) { diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetched_data.h b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetched_data.h index 6551b39c271d..e80f376d7913 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetched_data.h +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetched_data.h @@ -149,8 +149,8 @@ class TFetchedData { } } - bool IsEmptyFiltered() const { - return Table->IsEmptyFiltered(); + bool IsEmptyWithData() const { + return Table->HasDataAndResultIsEmpty(); } void Clear() { @@ -177,12 +177,35 @@ class TFetchedData { } }; +class TSourceChunkToReply { +private: + YDB_READONLY(ui32, StartIndex, 0); + YDB_READONLY(ui32, RecordsCount, 0); + std::shared_ptr Table; + +public: + const std::shared_ptr& GetTable() const { + AFL_VERIFY(Table); + return Table; + } + + bool HasData() const { + return !!Table && Table->num_rows(); + } + + TSourceChunkToReply(const ui32 startIndex, const ui32 recordsCount, const std::shared_ptr& table) + : StartIndex(startIndex) + , RecordsCount(recordsCount) + , Table(table) { + } +}; + class TFetchedResult { private: YDB_READONLY_DEF(std::shared_ptr, Batch); YDB_READONLY_DEF(std::shared_ptr, NotAppliedFilter); std::optional> PagesToResult; - std::optional> ChunkToReply; + std::optional ChunkToReply; TFetchedResult() = default; @@ -225,7 +248,7 @@ class TFetchedResult { AFL_VERIFY(page.GetIndexStart() == indexStart)("real", page.GetIndexStart())("expected", indexStart); AFL_VERIFY(page.GetRecordsCount() == recordsCount)("real", page.GetRecordsCount())("expected", recordsCount); AFL_VERIFY(!ChunkToReply); - ChunkToReply = std::move(table); + ChunkToReply = TSourceChunkToReply(indexStart, recordsCount, std::move(table)); } bool IsFinished() const { @@ -236,7 +259,7 @@ class TFetchedResult { return !!ChunkToReply; } - std::shared_ptr ExtractResultChunk() { + std::optional ExtractResultChunk() { AFL_VERIFY(!!ChunkToReply); auto result = std::move(*ChunkToReply); ChunkToReply.reset(); diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetching.cpp b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetching.cpp index f36ebb1a81cc..b9a686530b9b 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetching.cpp +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetching.cpp @@ -15,6 +15,7 @@ namespace NKikimr::NOlap::NReader::NCommon { bool TStepAction::DoApply(IDataReader& owner) const { if (FinishedFlag) { AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "apply"); + Source->StartSyncSection(); Source->OnSourceFetchingFinishedSafe(owner, Source); } return true; @@ -26,7 +27,7 @@ TConclusionStatus TStepAction::DoExecuteImpl() { return TConclusionStatus::Success(); } auto executeResult = Cursor.Execute(Source); - if (!executeResult) { + if (executeResult.IsFail()) { return executeResult; } if (*executeResult) { @@ -35,11 +36,17 @@ TConclusionStatus TStepAction::DoExecuteImpl() { return TConclusionStatus::Success(); } -TStepAction::TStepAction(const std::shared_ptr& source, TFetchingScriptCursor&& cursor, const NActors::TActorId& ownerActorId) +TStepAction::TStepAction(const std::shared_ptr& source, TFetchingScriptCursor&& cursor, const NActors::TActorId& ownerActorId, + const bool changeSyncSection) : TBase(ownerActorId) , Source(source) , Cursor(std::move(cursor)) , CountersGuard(Source->GetContext()->GetCommonContext()->GetCounters().GetAssembleTasksGuard()) { + if (changeSyncSection) { + Source->StartAsyncSection(); + } else { + Source->CheckAsyncSection(); + } } TConclusion TFetchingScriptCursor::Execute(const std::shared_ptr& source) { @@ -48,14 +55,16 @@ TConclusion TFetchingScriptCursor::Execute(const std::shared_ptrOnExecute(); AFL_VERIFY(!Script->IsFinished(CurrentStepIdx)); while (!Script->IsFinished(CurrentStepIdx)) { - if (source->HasStageData() && source->GetStageData().IsEmptyFiltered()) { + if (source->HasStageData() && source->GetStageData().IsEmptyWithData()) { source->OnEmptyStageData(source); break; + } else if (source->HasStageResult() && source->GetStageResult().IsEmpty()) { + break; } auto step = Script->GetStep(CurrentStepIdx); TMemoryProfileGuard mGuard("SCAN_PROFILE::FETCHING::" + step->GetName() + "::" + Script->GetBranchName(), IS_DEBUG_LOG_ENABLED(NKikimrServices::TX_COLUMNSHARD_SCAN_MEMORY)); - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("scan_step", step->DebugString())("scan_step_idx", CurrentStepIdx); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("scan_step", step->DebugString())("scan_step_idx", CurrentStepIdx)("source_id", source->GetSourceId()); const TMonotonic startInstant = TMonotonic::Now(); const TConclusion resultStep = step->ExecuteInplace(source, *this); @@ -105,7 +114,8 @@ TString TFetchingScript::ProfileDebugString() const { return sb; } -void TFetchingScriptBuilder::AddAllocation(const std::set& entityIds, const EStageFeaturesIndexes stage, const EMemType mType) { +void TFetchingScriptBuilder::AddAllocation( + const std::set& entityIds, const NArrow::NSSA::IMemoryCalculationPolicy::EStage stage, const EMemType mType) { if (Steps.size() == 0) { AddStep(std::make_shared(entityIds, mType, stage)); } else { @@ -148,7 +158,7 @@ TFetchingScriptBuilder::TFetchingScriptBuilder(const TSpecialReadContext& contex : TFetchingScriptBuilder(context.GetReadMetadata()->GetResultSchema(), context.GetMergeColumns()) { } -void TFetchingScriptBuilder::AddFetchingStep(const TColumnsSetIds& columns, const EStageFeaturesIndexes stage) { +void TFetchingScriptBuilder::AddFetchingStep(const TColumnsSetIds& columns, const NArrow::NSSA::IMemoryCalculationPolicy::EStage stage) { auto actualColumns = columns - AddedFetchingColumns; AddedFetchingColumns += columns; if (actualColumns.IsEmpty()) { @@ -166,7 +176,7 @@ void TFetchingScriptBuilder::AddFetchingStep(const TColumnsSetIds& columns, cons } void TFetchingScriptBuilder::AddAssembleStep( - const TColumnsSetIds& columns, const TString& purposeId, const EStageFeaturesIndexes stage, const bool sequential) { + const TColumnsSetIds& columns, const TString& purposeId, const NArrow::NSSA::IMemoryCalculationPolicy::EStage stage, const bool sequential) { auto actualColumns = columns - AddedAssembleColumns; AddedAssembleColumns += columns; if (actualColumns.IsEmpty()) { diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetching.h b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetching.h index 952c3cda3a3f..e8ca12f666d9 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetching.h +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/fetching.h @@ -1,7 +1,7 @@ #pragma once #include "columns_set.h" -#include +#include #include #include @@ -253,7 +253,7 @@ class TFetchingScriptBuilder { } private: - void AddAllocation(const std::set& entityIds, const EStageFeaturesIndexes stage, const EMemType mType); + void AddAllocation(const std::set& entityIds, const NArrow::NSSA::IMemoryCalculationPolicy::EStage stage, const EMemType mType); template std::shared_ptr InsertStep(const ui32 index, Args... args) { @@ -275,8 +275,9 @@ class TFetchingScriptBuilder { Steps.emplace_back(step); } - void AddFetchingStep(const TColumnsSetIds& columns, const EStageFeaturesIndexes stage); - void AddAssembleStep(const TColumnsSetIds& columns, const TString& purposeId, const EStageFeaturesIndexes stage, const bool sequential); + void AddFetchingStep(const TColumnsSetIds& columns, const NArrow::NSSA::IMemoryCalculationPolicy::EStage stage); + void AddAssembleStep(const TColumnsSetIds& columns, const TString& purposeId, const NArrow::NSSA::IMemoryCalculationPolicy::EStage stage, + const bool sequential); static TFetchingScriptBuilder MakeForTests(ISnapshotSchema::TPtr schema, std::shared_ptr guaranteeNotOptional = nullptr) { return TFetchingScriptBuilder(schema, guaranteeNotOptional ? guaranteeNotOptional : std::make_shared()); @@ -331,10 +332,11 @@ class TStepAction: public IDataTasksProcessor::ITask { } template - TStepAction(const std::shared_ptr& source, TFetchingScriptCursor&& cursor, const NActors::TActorId& ownerActorId) - : TStepAction(std::static_pointer_cast(source), std::move(cursor), ownerActorId) { + TStepAction(const std::shared_ptr& source, TFetchingScriptCursor&& cursor, const NActors::TActorId& ownerActorId, const bool changeSyncSection) + : TStepAction(std::static_pointer_cast(source), std::move(cursor), ownerActorId, changeSyncSection) { } - TStepAction(const std::shared_ptr& source, TFetchingScriptCursor&& cursor, const NActors::TActorId& ownerActorId); + TStepAction(const std::shared_ptr& source, TFetchingScriptCursor&& cursor, const NActors::TActorId& ownerActorId, + const bool changeSyncSection); }; class TProgramStep: public IFetchingStep { diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/iterator.cpp b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/iterator.cpp index 609773c897df..21a7e016baf1 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/iterator.cpp +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/iterator.cpp @@ -24,8 +24,8 @@ TConclusion TColumnShardScanIterator::ReadNextInterval() { return IndexedData->ReadNextInterval(); } -void TColumnShardScanIterator::DoOnSentDataFromInterval(const ui32 intervalIdx) const { - return IndexedData->OnSentDataFromInterval(intervalIdx); +void TColumnShardScanIterator::DoOnSentDataFromInterval(const TPartialSourceAddress& address) { + return IndexedData->OnSentDataFromInterval(address); } TColumnShardScanIterator::~TColumnShardScanIterator() { diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/iterator.h b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/iterator.h index cd570090aa7d..f525af31b9cd 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/iterator.h +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/iterator.h @@ -55,7 +55,7 @@ class TReadyResults { class TColumnShardScanIterator: public TScanIteratorBase { private: - virtual void DoOnSentDataFromInterval(const ui32 intervalIdx) const override; + virtual void DoOnSentDataFromInterval(const TPartialSourceAddress& address) override; protected: ui64 ItemsRead = 0; diff --git a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/source.h b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/source.h index c8c62b09af55..afdc0b4e36f1 100644 --- a/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/source.h +++ b/ydb/core/tx/columnshard/engines/reader/common_reader/iterator/source.h @@ -116,6 +116,7 @@ class TExecutionContext { class IDataSource: public ICursorEntity, public NArrow::NSSA::IDataSource { private: + TAtomic SyncSectionFlag = 1; YDB_READONLY(ui64, SourceId, 0); YDB_READONLY(ui32, SourceIdx, 0); YDB_READONLY(TSnapshot, RecordSnapshotMin, TSnapshot::Zero()); @@ -161,6 +162,22 @@ class IDataSource: public ICursorEntity, public NArrow::NSSA::IDataSource { std::unique_ptr StageResult; public: + void StartAsyncSection() { + AFL_VERIFY(AtomicCas(&SyncSectionFlag, 0, 1)); + } + + void CheckAsyncSection() { + AFL_VERIFY(AtomicGet(SyncSectionFlag) == 0); + } + + void StartSyncSection() { + AFL_VERIFY(AtomicCas(&SyncSectionFlag, 1, 0)); + } + + bool IsSyncSection() const { + return AtomicGet(SyncSectionFlag) == 1; + } + void AddEvent(const TString& evDescription) { AFL_VERIFY(!!Events); Events->AddEvent(evDescription); @@ -274,6 +291,10 @@ class IDataSource: public ICursorEntity, public NArrow::NSSA::IDataSource { return DoStartFetchingColumns(sourcePtr, step, columns); } + void ResetSourceFinishedFlag() { + AFL_VERIFY(AtomicCas(&SourceFinishedSafeFlag, 0, 1)); + } + void OnSourceFetchingFinishedSafe(IDataReader& owner, const std::shared_ptr& sourcePtr) { AFL_VERIFY(AtomicCas(&SourceFinishedSafeFlag, 1, 0)); AFL_VERIFY(sourcePtr); diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/context.cpp b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/context.cpp index ae2deb2810ea..2636db28693e 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/context.cpp +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/context.cpp @@ -30,7 +30,7 @@ std::shared_ptr TSpecialReadContext::DoGetColumnsFetchingPlan(c if (!AskAccumulatorsScript) { NCommon::TFetchingScriptBuilder acc(*this); if (ui64 size = source->PredictAccessorsMemory()) { - acc.AddStep(std::make_shared(size, EStageFeaturesIndexes::Accessors)); + acc.AddStep(std::make_shared(size, NArrow::NSSA::IMemoryCalculationPolicy::EStage::Accessors)); } acc.AddStep(std::make_shared()); acc.AddStep(std::make_shared(*GetFFColumns())); @@ -90,25 +90,25 @@ std::shared_ptr TSpecialReadContext::BuildColumnsFetchingPlan(c bool hasFilterSharding = false; if (needFilterSharding && !GetShardingColumns()->IsEmpty()) { hasFilterSharding = true; - acc.AddFetchingStep(*GetShardingColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetShardingColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); if (!exclusiveSource) { - acc.AddFetchingStep(*GetPKColumns(), EStageFeaturesIndexes::Filter); - acc.AddFetchingStep(*GetSpecColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetPKColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); + acc.AddFetchingStep(*GetSpecColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); } - acc.AddAssembleStep(acc.GetAddedFetchingColumns(), "SPEC_SHARDING", EStageFeaturesIndexes::Filter, false); + acc.AddAssembleStep(acc.GetAddedFetchingColumns(), "SPEC_SHARDING", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); } if (!GetEFColumns()->GetColumnsCount() && !partialUsageByPredicate) { acc.SetBranchName("simple"); - acc.AddFetchingStep(*GetFFColumns(), EStageFeaturesIndexes::Fetching); + acc.AddFetchingStep(*GetFFColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching); if (needFilterDeletion) { - acc.AddFetchingStep(*GetDeletionColumns(), EStageFeaturesIndexes::Fetching); + acc.AddFetchingStep(*GetDeletionColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching); } if (needSnapshots) { - acc.AddFetchingStep(*GetSpecColumns(), EStageFeaturesIndexes::Fetching); + acc.AddFetchingStep(*GetSpecColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching); } if (!exclusiveSource) { - acc.AddFetchingStep(*GetMergeColumns(), EStageFeaturesIndexes::Fetching); + acc.AddFetchingStep(*GetMergeColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching); } else { if (acc.GetAddedFetchingColumns().GetColumnsCount() == 1 && GetSpecColumns()->Contains(acc.GetAddedFetchingColumns()) && !hasFilterSharding) { return nullptr; @@ -116,76 +116,77 @@ std::shared_ptr TSpecialReadContext::BuildColumnsFetchingPlan(c } if (acc.GetAddedFetchingColumns().GetColumnsCount() || hasFilterSharding || needFilterDeletion) { if (needSnapshots) { - acc.AddAssembleStep(*GetSpecColumns(), "SPEC", EStageFeaturesIndexes::Fetching, false); + acc.AddAssembleStep(*GetSpecColumns(), "SPEC", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching, false); } if (!exclusiveSource) { - acc.AddAssembleStep(*GetMergeColumns(), "LAST_PK", EStageFeaturesIndexes::Fetching, false); + acc.AddAssembleStep(*GetMergeColumns(), "LAST_PK", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching, false); } if (needSnapshots) { acc.AddStep(std::make_shared()); } if (needFilterDeletion) { - acc.AddAssembleStep(*GetDeletionColumns(), "SPEC_DELETION", EStageFeaturesIndexes::Fetching, false); + acc.AddAssembleStep(*GetDeletionColumns(), "SPEC_DELETION", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching, false); acc.AddStep(std::make_shared()); } - acc.AddAssembleStep(acc.GetAddedFetchingColumns().GetColumnIds(), "LAST", EStageFeaturesIndexes::Fetching, !exclusiveSource); + acc.AddAssembleStep(acc.GetAddedFetchingColumns().GetColumnIds(), "LAST", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching, + !exclusiveSource); } else { return nullptr; } } else if (exclusiveSource) { acc.SetBranchName("exclusive"); - acc.AddFetchingStep(*GetEFColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetEFColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); if (needFilterDeletion) { - acc.AddFetchingStep(*GetDeletionColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetDeletionColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); } if (needSnapshots || GetFFColumns()->Cross(*GetSpecColumns())) { - acc.AddFetchingStep(*GetSpecColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetSpecColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); } if (partialUsageByPredicate) { - acc.AddFetchingStep(*GetPredicateColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetPredicateColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); } AFL_VERIFY(acc.GetAddedFetchingColumns().GetColumnsCount()); if (needFilterDeletion) { - acc.AddAssembleStep(*GetDeletionColumns(), "SPEC_DELETION", EStageFeaturesIndexes::Filter, false); + acc.AddAssembleStep(*GetDeletionColumns(), "SPEC_DELETION", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); } if (partialUsageByPredicate) { - acc.AddAssembleStep(*GetPredicateColumns(), "PREDICATE", EStageFeaturesIndexes::Filter, false); + acc.AddAssembleStep(*GetPredicateColumns(), "PREDICATE", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); } if (needSnapshots || GetFFColumns()->Cross(*GetSpecColumns())) { - acc.AddAssembleStep(*GetSpecColumns(), "SPEC", EStageFeaturesIndexes::Filter, false); + acc.AddAssembleStep(*GetSpecColumns(), "SPEC", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); } else if (GetProgramInputColumns()->Cross(*GetSpecColumns())) { acc.AddStep(std::make_shared()); } - acc.AddFetchingStep(*GetFFColumns(), EStageFeaturesIndexes::Fetching); - acc.AddAssembleStep(*GetFFColumns(), "LAST", EStageFeaturesIndexes::Fetching, !exclusiveSource); + acc.AddFetchingStep(*GetFFColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching); + acc.AddAssembleStep(*GetFFColumns(), "LAST", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching, !exclusiveSource); } else { acc.SetBranchName("merge"); - acc.AddFetchingStep(*GetMergeColumns(), EStageFeaturesIndexes::Filter); - acc.AddFetchingStep(*GetEFColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetMergeColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); + acc.AddFetchingStep(*GetEFColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); if (needFilterDeletion) { - acc.AddFetchingStep(*GetDeletionColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetDeletionColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); } AFL_VERIFY(acc.GetAddedFetchingColumns().GetColumnsCount()); - acc.AddAssembleStep(*GetSpecColumns(), "SPEC", EStageFeaturesIndexes::Filter, false); - acc.AddAssembleStep(*GetPKColumns(), "PK", EStageFeaturesIndexes::Filter, false); + acc.AddAssembleStep(*GetSpecColumns(), "SPEC", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); + acc.AddAssembleStep(*GetPKColumns(), "PK", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); if (needSnapshots) { acc.AddStep(std::make_shared()); } if (needFilterDeletion) { - acc.AddAssembleStep(*GetDeletionColumns(), "SPEC_DELETION", EStageFeaturesIndexes::Filter, false); + acc.AddAssembleStep(*GetDeletionColumns(), "SPEC_DELETION", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); } if (partialUsageByPredicate) { acc.AddStep(std::make_shared()); } - acc.AddFetchingStep(*GetFFColumns(), EStageFeaturesIndexes::Fetching); - acc.AddAssembleStep(*GetFFColumns(), "LAST", EStageFeaturesIndexes::Fetching, !exclusiveSource); + acc.AddFetchingStep(*GetFFColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching); + acc.AddAssembleStep(*GetFFColumns(), "LAST", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching, !exclusiveSource); } acc.AddStep(std::make_shared()); return std::move(acc).Build(); diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/context.h b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/context.h index 4d35be2eca8f..9500e54a3cf1 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/context.h +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/context.h @@ -13,7 +13,6 @@ namespace NKikimr::NOlap::NReader::NPlain { class IDataSource; using TColumnsSet = NCommon::TColumnsSet; -using EStageFeaturesIndexes = NCommon::EStageFeaturesIndexes; using TColumnsSetIds = NCommon::TColumnsSetIds; using EMemType = NCommon::EMemType; using TFetchingScript = NCommon::TFetchingScript; diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.cpp b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.cpp index 3c74c4fd25f3..97ddcb1968d0 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.cpp +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.cpp @@ -14,9 +14,10 @@ namespace NKikimr::NOlap::NReader::NPlain { TConclusion TPredicateFilter::DoExecuteInplace(const std::shared_ptr& source, const TFetchingScriptCursor& /*step*/) const { auto filter = source->GetContext()->GetReadMetadata()->GetPKRangesFilter().BuildFilter( - source->GetStageData().GetTable()->ToTable(source->GetContext()->GetReadMetadata()->GetPKRangesFilter().GetColumnIds( - source->GetContext()->GetReadMetadata()->GetResultSchema()->GetIndexInfo()), - source->GetContext()->GetCommonContext()->GetResolver(), true)); + source->GetStageData().GetTable()->ToGeneralContainer(source->GetContext()->GetCommonContext()->GetResolver(), + source->GetContext()->GetReadMetadata()->GetPKRangesFilter().GetColumnIds( + source->GetContext()->GetReadMetadata()->GetResultSchema()->GetIndexInfo()), + true)); source->MutableStageData().AddFilter(filter); return true; } @@ -34,7 +35,8 @@ TConclusion TSnapshotFilter::DoExecuteInplace(const std::shared_ptr TDeletionFilter::DoExecuteInplace(const std::shared_ptr& source, const TFetchingScriptCursor& /*step*/) const { - auto collection = source->GetStageData().GetTable()->SelectOptional(std::vector({ (ui32)IIndexInfo::ESpecialColumn::DELETE_FLAG }), false); + auto collection = + source->GetStageData().GetTable()->SelectOptional(std::vector({ (ui32)IIndexInfo::ESpecialColumn::DELETE_FLAG }), false); if (!collection) { return true; } @@ -86,7 +88,7 @@ TConclusion TDetectInMem::DoExecuteInplace(const std::shared_ptrGetContext()->GetColumnsFetchingPlan(source); source->InitFetchingPlan(plan); TFetchingScriptCursor cursor(plan, 0); - auto task = std::make_shared(source, std::move(cursor), source->GetContext()->GetCommonContext()->GetScanActorId()); + auto task = std::make_shared(source, std::move(cursor), source->GetContext()->GetCommonContext()->GetScanActorId(), false); NConveyor::TScanServiceOperator::SendTaskToExecute(task); return false; } @@ -94,9 +96,16 @@ TConclusion TDetectInMem::DoExecuteInplace(const std::shared_ptr TBuildFakeSpec::DoExecuteInplace(const std::shared_ptr& source, const TFetchingScriptCursor& /*step*/) const { std::vector> columns; for (auto&& f : IIndexInfo::ArrowSchemaSnapshot()->fields()) { - source->MutableStageData().GetTable()->AddVerified(IIndexInfo::GetColumnIdVerified(f->name()), - std::make_shared( - NArrow::TThreadSimpleArraysCache::GetConst(f->type(), NArrow::DefaultScalar(f->type()), source->GetRecordsCount())), true); + if (source->MutableStageData().GetTable()->HasColumn(IIndexInfo::GetColumnIdVerified(f->name()))) { + auto arr = source->MutableStageData().GetTable()->GetArrayVerified(IIndexInfo::GetColumnIdVerified(f->name())); + AFL_WARN(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "spec_column_exists")("column_name", f->name())( + "col", NArrow::DebugJson(arr, 2, 2).GetStringRobust()); + } else { + source->MutableStageData().GetTable()->AddVerified(IIndexInfo::GetColumnIdVerified(f->name()), + std::make_shared( + NArrow::TThreadSimpleArraysCache::GetConst(f->type(), NArrow::DefaultScalar(f->type()), source->GetRecordsCount())), + true); + } } return true; } diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.h b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.h index 1e3fa3a98b5a..b2fcbe88b7e9 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.h +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.h @@ -14,7 +14,6 @@ namespace NKikimr::NOlap::NReader::NPlain { using TColumnsSet = NCommon::TColumnsSet; using TIndexesSet = NCommon::TIndexesSet; -using EStageFeaturesIndexes = NCommon::EStageFeaturesIndexes; using TColumnsSetIds = NCommon::TColumnsSetIds; using EMemType = NCommon::EMemType; using TFetchingScriptCursor = NCommon::TFetchingScriptCursor; diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/interval.cpp b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/interval.cpp index 7f44376f3ad9..a431b81077f4 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/interval.cpp +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/interval.cpp @@ -20,7 +20,7 @@ void TFetchingInterval::ConstructResult() { auto task = std::make_shared(MergingContext, Context, std::move(Sources)); task->SetPriority(NConveyor::ITask::EPriority::High); NGroupedMemoryManager::TScanMemoryLimiterOperator::SendToAllocation(Context->GetProcessMemoryControlId(), - Context->GetCommonContext()->GetScanId(), GetIntervalId(), { task }, (ui32)EStageFeaturesIndexes::Merge); + Context->GetCommonContext()->GetScanId(), GetIntervalId(), { task }, (ui32)NArrow::NSSA::IMemoryCalculationPolicy::EStage::Merge); } } @@ -83,7 +83,7 @@ void TFetchingInterval::OnPartSendingComplete() { auto task = std::make_shared(MergingContext, Context, std::move(Merger)); task->SetPriority(NConveyor::ITask::EPriority::High); NGroupedMemoryManager::TScanMemoryLimiterOperator::SendToAllocation(Context->GetProcessMemoryControlId(), - Context->GetCommonContext()->GetScanId(), GetIntervalId(), { task }, (ui32)EStageFeaturesIndexes::Merge); + Context->GetCommonContext()->GetScanId(), GetIntervalId(), { task }, (ui32)NArrow::NSSA::IMemoryCalculationPolicy::EStage::Merge); } } // namespace NKikimr::NOlap::NReader::NPlain diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/plain_read_data.h b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/plain_read_data.h index 960f49541bc6..2b2f5e250fd7 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/plain_read_data.h +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/plain_read_data.h @@ -45,8 +45,8 @@ class TPlainReadData: public IDataReader, TNonCopyable, NColumnShard::TMonitorin } public: - virtual void OnSentDataFromInterval(const ui32 intervalIdx) const override { - Scanner->OnSentDataFromInterval(intervalIdx); + virtual void OnSentDataFromInterval(const TPartialSourceAddress& address) override { + Scanner->OnSentDataFromInterval(address); } template diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/scanner.cpp b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/scanner.cpp index b0e489fa74ea..076dd63d495d 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/scanner.cpp +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/scanner.cpp @@ -21,10 +21,10 @@ void TScanHead::OnIntervalResult(std::shared_ptrsecond->GetIntervalId()); if (newBatch && newBatch->GetRecordsCount()) { - std::optional callbackIdxSubscriver; + std::optional callbackIdxSubscriver; std::shared_ptr gGuard; if (itInterval->second->HasMerger()) { - callbackIdxSubscriver = intervalIdx; + callbackIdxSubscriver = TPartialSourceAddress(itInterval->second->GetIntervalId(), intervalIdx, 0); } else { gGuard = itInterval->second->GetGroupGuard(); } @@ -203,4 +203,13 @@ void TScanHead::Abort() { Y_ABORT_UNLESS(IsFinished()); } +void TScanHead::OnSentDataFromInterval(const TPartialSourceAddress& address) const { + if (Context->IsAborted()) { + return; + } + auto it = FetchingIntervals.find(address.GetSourceIdx()); + AFL_VERIFY(it != FetchingIntervals.end())("interval_idx", address.GetSourceIdx())("count", FetchingIntervals.size()); + it->second->OnPartSendingComplete(); +} + } // namespace NKikimr::NOlap::NReader::NPlain diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/scanner.h b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/scanner.h index 09649e788147..23888d410815 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/scanner.h +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/scanner.h @@ -84,14 +84,7 @@ class TScanHead { void DrainSources(); [[nodiscard]] TConclusionStatus DetectSourcesFeatureInContextIntervalScan(const THashMap>& intervalSources, const bool isExclusiveInterval) const; public: - void OnSentDataFromInterval(const ui32 intervalIdx) const { - if (Context->IsAborted()) { - return; - } - auto it = FetchingIntervals.find(intervalIdx); - AFL_VERIFY(it != FetchingIntervals.end())("interval_idx", intervalIdx)("count", FetchingIntervals.size()); - it->second->OnPartSendingComplete(); - } + void OnSentDataFromInterval(const TPartialSourceAddress& address) const; bool IsReverse() const; void Abort(); diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/source.cpp b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/source.cpp index c0300c23aeec..51e180925871 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/source.cpp +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/source.cpp @@ -36,7 +36,7 @@ void IDataSource::RegisterInterval(TFetchingInterval& interval, const std::share return; } TFetchingScriptCursor cursor(FetchingPlan, 0); - auto task = std::make_shared(sourcePtr, std::move(cursor), GetContext()->GetCommonContext()->GetScanActorId()); + auto task = std::make_shared(sourcePtr, std::move(cursor), GetContext()->GetCommonContext()->GetScanActorId(), true); NConveyor::TScanServiceOperator::SendTaskToExecute(task); } } @@ -170,7 +170,7 @@ class TPortionAccessorFetchingSubscriber: public IDataAccessorRequestsSubscriber AFL_VERIFY(result.GetPortions().size() == 1)("count", result.GetPortions().size()); Source->MutableStageData().SetPortionAccessor(std::move(result.ExtractPortionsVector().front())); AFL_VERIFY(Step.Next()); - auto task = std::make_shared(Source, std::move(Step), Source->GetContext()->GetCommonContext()->GetScanActorId()); + auto task = std::make_shared(Source, std::move(Step), Source->GetContext()->GetCommonContext()->GetScanActorId(), false); NConveyor::TScanServiceOperator::SendTaskToExecute(task); } @@ -190,7 +190,7 @@ bool TPortionDataSource::DoStartFetchingAccessor(const std::shared_ptr request = std::make_shared("PLAIN::" + step.GetName()); request->AddPortion(Portion); request->RegisterSubscriber(std::make_shared(step, sourcePtr)); - GetContext()->GetCommonContext()->GetDataAccessorsManager()->AskData(request); + GetContext()->GetCommonContext()->GetDataAccessorsManager()->AskData((NOlap::TTabletId)GetContext()->GetReadMetadata()->GetTabletId(), request); return true; } @@ -219,7 +219,8 @@ void TCommittedDataSource::DoAssembleColumns(const std::shared_ptr& const ISnapshotSchema::TPtr batchSchema = GetContext()->GetReadMetadata()->GetIndexVersions().GetSchemaVerified(GetCommitted().GetSchemaVersion()); const ISnapshotSchema::TPtr resultSchema = GetContext()->GetReadMetadata()->GetResultSchema(); - if (!GetStageData().GetTable()->HasAccessors()) { + if (!AssembledFlag) { + AssembledFlag = true; AFL_VERIFY(GetStageData().GetBlobs().size() == 1); auto bData = MutableStageData().ExtractBlob(GetStageData().GetBlobs().begin()->first); auto schema = GetContext()->GetReadMetadata()->GetBlobSchema(CommittedBlob.GetSchemaVersion()); diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/source.h b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/source.h index 3823b0a1cc0e..9ab171841c81 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/source.h +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/source.h @@ -191,6 +191,7 @@ class TPortionDataSource: public IDataSource { using TBase = IDataSource; const TPortionInfo::TConstPtr Portion; std::shared_ptr Schema; + TTabletId TabletId; void NeedFetchColumns(const std::set& columnIds, TBlobsAction& blobsAction, THashMap& nullBlocks, const std::shared_ptr& filter); @@ -299,7 +300,8 @@ class TPortionDataSource: public IDataSource { portion->RecordSnapshotMin(TSnapshot::Zero()), portion->RecordSnapshotMax(TSnapshot::Zero()), portion->GetRecordsCount(), portion->GetShardingVersionOptional(), portion->GetMeta().GetDeletionsCount()) , Portion(portion) - , Schema(GetContext()->GetReadMetadata()->GetLoadSchemaVerified(*portion)) { + , Schema(GetContext()->GetReadMetadata()->GetLoadSchemaVerified(*portion)) + , TabletId((NOlap::TTabletId)GetContext()->GetReadMetadata()->GetTabletId()){ } }; @@ -308,6 +310,7 @@ class TCommittedDataSource: public IDataSource { using TBase = IDataSource; TCommittedBlob CommittedBlob; bool ReadStarted = false; + bool AssembledFlag = false; virtual void DoAbort() override { } diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections.cpp deleted file mode 100644 index 1fb5b3dd31e1..000000000000 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "collections.h" - -#include - -namespace NKikimr::NOlap::NReader::NSimple { - -std::shared_ptr TScanWithLimitCollection::DoExtractNext() { - AFL_VERIFY(HeapSources.size()); - std::pop_heap(HeapSources.begin(), HeapSources.end()); - auto result = HeapSources.back().Construct(Context); - AFL_VERIFY(FetchingInFlightSources.emplace(TCompareKeyForScanSequence::FromFinish(result)).second); - auto predPosition = std::move(HeapSources.back()); - HeapSources.pop_back(); - FetchingInFlightCount.Inc(); - return result; -} - -void TScanWithLimitCollection::DoOnSourceFinished(const std::shared_ptr& source) { - if (!source->GetResultRecordsCount() && InFlightLimit < GetMaxInFlight()) { - InFlightLimit = 2 * InFlightLimit; - } - FetchingInFlightCount.Dec(); - AFL_VERIFY(FetchingInFlightSources.erase(TCompareKeyForScanSequence::FromFinish(source))); - while (FinishedSources.size() && (HeapSources.empty() || FinishedSources.begin()->first < HeapSources.front().GetStart())) { - auto finishedSource = FinishedSources.begin()->second; - FetchedCount += finishedSource.GetRecordsCount(); - FinishedSources.erase(FinishedSources.begin()); - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD)("event", "source_finished")("source_id", finishedSource.GetSourceId())( - "source_idx", finishedSource.GetSourceIdx())("limit", Limit)("fetched", finishedSource.GetRecordsCount()); - if (Limit <= FetchedCount && HeapSources.size()) { - AFL_NOTICE(NKikimrServices::TX_COLUMNSHARD)("event", "limit_exhausted")("limit", Limit)("fetched", FetchedCount); - HeapSources.clear(); - } - } -} - -ui32 TScanWithLimitCollection::GetInFlightIntervalsCount(const TCompareKeyForScanSequence& from, const TCompareKeyForScanSequence& to) const { - AFL_VERIFY(from < to); - ui32 inFlightCountLocal = 0; - { - auto itFinishedFrom = FinishedSources.lower_bound(from); - auto itFinishedTo = FinishedSources.lower_bound(to); - for (auto&& it = itFinishedFrom; it != itFinishedTo; ++it) { - ++inFlightCountLocal; - } - } - { - auto itFetchingFrom = FetchingInFlightSources.lower_bound(from); - auto itFetchingTo = FetchingInFlightSources.lower_bound(to); - for (auto&& it = itFetchingFrom; it != itFetchingTo; ++it) { - ++inFlightCountLocal; - } - } - return inFlightCountLocal; -} - -TScanWithLimitCollection::TScanWithLimitCollection( - const std::shared_ptr& context, std::deque&& sources, const std::shared_ptr& cursor) - : TBase(context) - , Limit((ui64)Context->GetCommonContext()->GetReadMetadata()->GetLimitRobust()) { - if (cursor && cursor->IsInitialized()) { - for (auto&& i : sources) { - bool usage = false; - if (!context->GetCommonContext()->GetScanCursor()->CheckEntityIsBorder(i, usage)) { - continue; - } - if (usage) { - i.SetIsStartedByCursor(); - } - break; - } - } - - HeapSources = std::move(sources); - std::make_heap(HeapSources.begin(), HeapSources.end()); -} - -void TScanWithLimitCollection::DoOnIntervalResult(const std::shared_ptr& table, const std::shared_ptr& source) { - std::vector> pkArrays; - for (auto&& f : Context->GetReadMetadata()->GetResultSchema()->GetIndexInfo().GetReplaceKey()->fields()) { - pkArrays.emplace_back(table->GetColumnByName(f->name())); - if (!pkArrays.back()) { - pkArrays.pop_back(); - break; - } - } - AFL_VERIFY(pkArrays.size()); - const ui32 partsCount = std::min(10, table->num_rows()); - std::optional lastPosition; - for (ui32 i = 0; i < partsCount; ++i) { - const i32 currentPosition = (i + 1) * (table->num_rows() - 1) / partsCount; - if (lastPosition) { - AFL_VERIFY(*lastPosition < currentPosition); - } - const i64 size = lastPosition ? (currentPosition - *lastPosition) : currentPosition; - lastPosition = currentPosition; - TReplaceKeyAdapter key(NArrow::TComparablePosition(pkArrays, currentPosition), Context->GetReadMetadata()->IsDescSorted()); - TCompareKeyForScanSequence finishPos(key, source->GetSourceId()); - AFL_VERIFY(FinishedSources.emplace(finishPos, TFinishedDataSource(source, size)).second); - } -} - -ISourcesCollection::ISourcesCollection(const std::shared_ptr& context) - : Context(context) { - if (HasAppData() && AppDataVerified().ColumnShardConfig.HasMaxInFlightIntervalsOnRequest()) { - MaxInFlight = AppDataVerified().ColumnShardConfig.GetMaxInFlightIntervalsOnRequest(); - } -} - -std::shared_ptr TNotSortedCollection::DoBuildCursor( - const std::shared_ptr& source, const ui32 readyRecords) const { - return std::make_shared(source->GetSourceId(), readyRecords); -} - -} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections.h deleted file mode 100644 index b497c2d761b4..000000000000 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections.h +++ /dev/null @@ -1,244 +0,0 @@ -#pragma once -#include "context.h" -#include "source.h" - -#include - -namespace NKikimr::NOlap::NReader::NSimple { - -class ISourcesCollection { -private: - virtual bool DoIsFinished() const = 0; - virtual std::shared_ptr DoExtractNext() = 0; - virtual bool DoCheckInFlightLimits() const = 0; - virtual void DoOnSourceFinished(const std::shared_ptr& source) = 0; - virtual void DoOnIntervalResult(const std::shared_ptr& table, const std::shared_ptr& source) = 0; - virtual void DoClear() = 0; - - TPositiveControlInteger SourcesInFlightCount; - YDB_READONLY(ui64, MaxInFlight, 1024); - - virtual TString DoDebugString() const { - return ""; - } - virtual std::shared_ptr DoBuildCursor(const std::shared_ptr& source, const ui32 readyRecords) const = 0; - -protected: - const std::shared_ptr Context; - -public: - std::shared_ptr BuildCursor(const std::shared_ptr& source, const ui32 readyRecords) const { - return DoBuildCursor(source, readyRecords); - } - - void OnIntervalResult(const std::shared_ptr& table, const std::shared_ptr& source) { - return DoOnIntervalResult(table, source); - } - - TString DebugString() const { - return DoDebugString(); - } - - virtual ~ISourcesCollection() = default; - - std::shared_ptr ExtractNext() { - SourcesInFlightCount.Inc(); - return DoExtractNext(); - } - - bool IsFinished() const { - return DoIsFinished(); - } - - void OnSourceFinished(const std::shared_ptr& source) { - AFL_VERIFY(source); - SourcesInFlightCount.Dec(); - DoOnSourceFinished(source); - } - - bool CheckInFlightLimits() const { - return DoCheckInFlightLimits(); - } - - void Clear() { - DoClear(); - } - - ISourcesCollection(const std::shared_ptr& context); -}; - -class TNotSortedCollection: public ISourcesCollection { -private: - using TBase = ISourcesCollection; - std::optional Limit; - ui32 InFlightLimit = 1; - std::deque Sources; - TPositiveControlInteger InFlightCount; - ui32 FetchedCount = 0; - virtual void DoClear() override { - Sources.clear(); - } - virtual std::shared_ptr DoBuildCursor(const std::shared_ptr& source, const ui32 readyRecords) const override; - virtual bool DoIsFinished() const override { - return Sources.empty(); - } - virtual std::shared_ptr DoExtractNext() override { - AFL_VERIFY(Sources.size()); - auto result = Sources.front().Construct(Context); - Sources.pop_front(); - InFlightCount.Inc(); - return result; - } - virtual bool DoCheckInFlightLimits() const override { - return InFlightCount < InFlightLimit; - } - virtual void DoOnIntervalResult(const std::shared_ptr& /*table*/, const std::shared_ptr& /*source*/) override { - } - virtual void DoOnSourceFinished(const std::shared_ptr& source) override { - if (!source->GetResultRecordsCount() && InFlightLimit * 2 < GetMaxInFlight()) { - InFlightLimit *= 2; - } - FetchedCount += source->GetResultRecordsCount(); - if (Limit && *Limit <= FetchedCount && Sources.size()) { - AFL_NOTICE(NKikimrServices::TX_COLUMNSHARD)("event", "limit_exhausted")("limit", Limit)("fetched", FetchedCount); - Sources.clear(); - } - InFlightCount.Dec(); - } - -public: - TNotSortedCollection(const std::shared_ptr& context, std::deque&& sources, - const std::shared_ptr& cursor, const std::optional limit) - : TBase(context) - , Limit(limit) { - if (Limit) { - InFlightLimit = 1; - } else { - InFlightLimit = GetMaxInFlight(); - } - if (cursor && cursor->IsInitialized()) { - while (sources.size()) { - bool usage = false; - if (!context->GetCommonContext()->GetScanCursor()->CheckEntityIsBorder(sources.front(), usage)) { - sources.pop_front(); - continue; - } - if (usage) { - sources.front().SetIsStartedByCursor(); - } - break; - } - } - Sources = std::move(sources); - } -}; - -class TSortedFullScanCollection: public ISourcesCollection { -private: - using TBase = ISourcesCollection; - std::deque HeapSources; - TPositiveControlInteger InFlightCount; - virtual void DoClear() override { - HeapSources.clear(); - } - virtual bool DoIsFinished() const override { - return HeapSources.empty(); - } - virtual std::shared_ptr DoBuildCursor(const std::shared_ptr& source, const ui32 readyRecords) const override { - return std::make_shared(source->GetStartPKRecordBatch(), source->GetSourceId(), readyRecords); - } - virtual void DoOnIntervalResult(const std::shared_ptr& /*table*/, const std::shared_ptr& /*source*/) override { - } - virtual std::shared_ptr DoExtractNext() override { - AFL_VERIFY(HeapSources.size()); - auto result = HeapSources.front().Construct(Context); - std::pop_heap(HeapSources.begin(), HeapSources.end()); - HeapSources.pop_back(); - InFlightCount.Inc(); - return result; - } - virtual bool DoCheckInFlightLimits() const override { - return InFlightCount < GetMaxInFlight(); - } - virtual void DoOnSourceFinished(const std::shared_ptr& /*source*/) override { - InFlightCount.Dec(); - } - -public: - TSortedFullScanCollection(const std::shared_ptr& context, std::deque&& sources, - const std::shared_ptr& cursor) - : TBase(context) { - if (cursor && cursor->IsInitialized()) { - for (auto&& i : sources) { - bool usage = false; - if (!context->GetCommonContext()->GetScanCursor()->CheckEntityIsBorder(i, usage)) { - continue; - } - if (usage) { - i.SetIsStartedByCursor(); - } - break; - } - } - HeapSources = std::move(sources); - std::make_heap(HeapSources.begin(), HeapSources.end()); - } -}; - -class TScanWithLimitCollection: public ISourcesCollection { -private: - using TBase = ISourcesCollection; - class TFinishedDataSource { - private: - YDB_READONLY(ui32, RecordsCount, 0); - YDB_READONLY(ui32, SourceId, 0); - YDB_READONLY(ui32, SourceIdx, 0); - - public: - TFinishedDataSource(const std::shared_ptr& source) - : RecordsCount(source->GetResultRecordsCount()) - , SourceId(source->GetSourceId()) - , SourceIdx(source->GetSourceIdx()) { - } - - TFinishedDataSource(const std::shared_ptr& source, const ui32 partSize) - : RecordsCount(partSize) - , SourceId(source->GetSourceId()) - , SourceIdx(source->GetSourceIdx()) { - AFL_VERIFY(partSize < source->GetResultRecordsCount()); - } - }; - - std::deque HeapSources; - TPositiveControlInteger FetchingInFlightCount; - TPositiveControlInteger FullIntervalsFetchingCount; - ui64 Limit = 0; - ui64 InFlightLimit = 1; - ui64 FetchedCount = 0; - std::map FinishedSources; - std::set FetchingInFlightSources; - - virtual void DoOnIntervalResult(const std::shared_ptr& table, const std::shared_ptr& source) override; - virtual std::shared_ptr DoBuildCursor(const std::shared_ptr& source, const ui32 readyRecords) const override { - return std::make_shared(source->GetStartPKRecordBatch(), source->GetSourceId(), readyRecords); - } - virtual void DoClear() override { - HeapSources.clear(); - } - virtual bool DoIsFinished() const override { - return HeapSources.empty(); - } - virtual std::shared_ptr DoExtractNext() override; - virtual bool DoCheckInFlightLimits() const override { - return (FetchingInFlightCount < InFlightLimit); - //&&(FullIntervalsFetchingCount < InFlightLimit); - } - virtual void DoOnSourceFinished(const std::shared_ptr& source) override; - ui32 GetInFlightIntervalsCount(const TCompareKeyForScanSequence& from, const TCompareKeyForScanSequence& to) const; - -public: - TScanWithLimitCollection(const std::shared_ptr& context, std::deque&& sources, - const std::shared_ptr& cursor); -}; - -} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/abstract.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/abstract.cpp new file mode 100644 index 000000000000..d40f3ee3b2a5 --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/abstract.cpp @@ -0,0 +1,14 @@ +#include "abstract.h" + +#include + +namespace NKikimr::NOlap::NReader::NSimple { + +ISourcesCollection::ISourcesCollection(const std::shared_ptr& context) + : Context(context) { + if (HasAppData() && AppDataVerified().ColumnShardConfig.HasMaxInFlightIntervalsOnRequest()) { + MaxInFlight = AppDataVerified().ColumnShardConfig.GetMaxInFlightIntervalsOnRequest(); + } +} + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/abstract.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/abstract.h new file mode 100644 index 000000000000..6f9eb00eff23 --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/abstract.h @@ -0,0 +1,81 @@ +#pragma once +#include +#include + +#include + +namespace NKikimr::NOlap::NReader::NSimple { + +class ISourcesCollection { +private: + virtual bool DoIsFinished() const = 0; + virtual std::shared_ptr DoExtractNext() = 0; + virtual bool DoCheckInFlightLimits() const = 0; + virtual void DoOnSourceFinished(const std::shared_ptr& source) = 0; + virtual void DoClear() = 0; + virtual void DoAbort() = 0; + + TPositiveControlInteger SourcesInFlightCount; + YDB_READONLY(ui64, MaxInFlight, 1024); + + virtual TString DoDebugString() const { + return ""; + } + virtual std::shared_ptr DoBuildCursor(const std::shared_ptr& source, const ui32 readyRecords) const = 0; + virtual bool DoHasData() const = 0; + +protected: + const std::shared_ptr Context; + +public: + bool HasData() const { + return DoHasData(); + } + + std::shared_ptr BuildCursor(const std::shared_ptr& source, const ui32 readyRecords, const ui64 tabletId) const { + AFL_VERIFY(source); + AFL_VERIFY(readyRecords <= source->GetRecordsCount())("count", source->GetRecordsCount())("ready", readyRecords); + auto result = DoBuildCursor(source, readyRecords); + AFL_VERIFY(result); + result->SetTabletId(tabletId); + AFL_VERIFY(tabletId); + return result; + } + + TString DebugString() const { + return DoDebugString(); + } + + virtual ~ISourcesCollection() = default; + + std::shared_ptr ExtractNext() { + SourcesInFlightCount.Inc(); + return DoExtractNext(); + } + + bool IsFinished() const { + return DoIsFinished(); + } + + void OnSourceFinished(const std::shared_ptr& source) { + AFL_VERIFY(source); + SourcesInFlightCount.Dec(); + DoOnSourceFinished(source); + } + + bool CheckInFlightLimits() const { + return DoCheckInFlightLimits(); + } + + void Clear() { + DoClear(); + } + + void Abort() { + DoAbort(); + } + + ISourcesCollection(const std::shared_ptr& context); +}; + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/full_scan_sorted.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/full_scan_sorted.cpp new file mode 100644 index 000000000000..a24f1158b65f --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/full_scan_sorted.cpp @@ -0,0 +1,5 @@ +#include "full_scan_sorted.h" + +namespace NKikimr::NOlap::NReader::NSimple { + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/full_scan_sorted.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/full_scan_sorted.h new file mode 100644 index 000000000000..9fe6771159ca --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/full_scan_sorted.h @@ -0,0 +1,65 @@ +#pragma once +#include "abstract.h" + +#include + +namespace NKikimr::NOlap::NReader::NSimple { + +class TSortedFullScanCollection: public ISourcesCollection { +private: + using TBase = ISourcesCollection; + std::deque HeapSources; + TPositiveControlInteger InFlightCount; + ui32 SourceIdx = 0; + virtual void DoClear() override { + HeapSources.clear(); + } + virtual bool DoHasData() const override { + return HeapSources.size(); + } + virtual void DoAbort() override { + HeapSources.clear(); + } + virtual bool DoIsFinished() const override { + return HeapSources.empty(); + } + virtual std::shared_ptr DoBuildCursor(const std::shared_ptr& source, const ui32 readyRecords) const override { + return std::make_shared(source->GetStartPKRecordBatch(), source->GetSourceId(), readyRecords); + } + virtual std::shared_ptr DoExtractNext() override { + AFL_VERIFY(HeapSources.size()); + auto result = HeapSources.front().Construct(SourceIdx++, Context); + std::pop_heap(HeapSources.begin(), HeapSources.end()); + HeapSources.pop_back(); + InFlightCount.Inc(); + return result; + } + virtual bool DoCheckInFlightLimits() const override { + return InFlightCount < GetMaxInFlight(); + } + virtual void DoOnSourceFinished(const std::shared_ptr& /*source*/) override { + InFlightCount.Dec(); + } + +public: + TSortedFullScanCollection(const std::shared_ptr& context, std::deque&& sources, + const std::shared_ptr& cursor) + : TBase(context) { + if (cursor && cursor->IsInitialized()) { + for (auto&& i : sources) { + bool usage = false; + if (!context->GetCommonContext()->GetScanCursor()->CheckEntityIsBorder(i, usage)) { + continue; + } + if (usage) { + i.SetIsStartedByCursor(); + } + break; + } + } + HeapSources = std::move(sources); + std::make_heap(HeapSources.begin(), HeapSources.end()); + } +}; + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/limit_sorted.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/limit_sorted.cpp new file mode 100644 index 000000000000..33b2c050e534 --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/limit_sorted.cpp @@ -0,0 +1,51 @@ +#include "limit_sorted.h" + +namespace NKikimr::NOlap::NReader::NSimple { + +std::shared_ptr TScanWithLimitCollection::DoExtractNext() { + AFL_VERIFY(HeapSources.size()); + std::pop_heap(HeapSources.begin(), HeapSources.end()); + auto result = NextSource ? NextSource : HeapSources.back().Construct(SourceIdxCurrent++, Context); + AFL_VERIFY(FetchingInFlightSources.emplace(result->GetSourceId()).second); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "DoExtractNext")("source_id", result->GetSourceId()); + HeapSources.pop_back(); + if (HeapSources.size()) { + NextSource = HeapSources.front().Construct(SourceIdxCurrent++, Context); + } else { + NextSource = nullptr; + } + return result; +} + +void TScanWithLimitCollection::DoOnSourceFinished(const std::shared_ptr& source) { + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "DoOnSourceFinished")("source_id", source->GetSourceId())("limit", Limit)( + "max", GetMaxInFlight())("in_flight_limit", InFlightLimit)("count", FetchingInFlightSources.size()); + if (!source->GetResultRecordsCount() && InFlightLimit < GetMaxInFlight()) { + InFlightLimit = 2 * InFlightLimit; + } + AFL_VERIFY(Cleared || Aborted || FetchingInFlightSources.erase(source->GetSourceId()))("source_id", source->GetSourceId()); +} + +TScanWithLimitCollection::TScanWithLimitCollection( + const std::shared_ptr& context, std::deque&& sources, const std::shared_ptr& cursor) + : TBase(context) + , Limit((ui64)Context->GetCommonContext()->GetReadMetadata()->GetLimitRobust()) { + HeapSources = std::move(sources); + std::make_heap(HeapSources.begin(), HeapSources.end()); + if (cursor && cursor->IsInitialized()) { + while (HeapSources.size()) { + bool usage = false; + if (!context->GetCommonContext()->GetScanCursor()->CheckEntityIsBorder(HeapSources.front(), usage)) { + std::pop_heap(HeapSources.begin(), HeapSources.end()); + HeapSources.pop_back(); + continue; + } + if (usage) { + HeapSources.front().SetIsStartedByCursor(); + } + break; + } + } +} + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/limit_sorted.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/limit_sorted.h new file mode 100644 index 000000000000..e04b1059645b --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/limit_sorted.h @@ -0,0 +1,79 @@ +#pragma once +#include "abstract.h" + +#include + +namespace NKikimr::NOlap::NReader::NSimple { + +class TScanWithLimitCollection: public ISourcesCollection { +private: + using TBase = ISourcesCollection; + class TFinishedDataSource { + private: + YDB_READONLY(ui32, RecordsCount, 0); + YDB_READONLY(ui32, SourceId, 0); + YDB_READONLY(ui32, SourceIdx, 0); + + public: + TFinishedDataSource(const std::shared_ptr& source) + : RecordsCount(source->GetResultRecordsCount()) + , SourceId(source->GetSourceId()) + , SourceIdx(source->GetSourceIdx()) { + } + + TFinishedDataSource(const std::shared_ptr& source, const ui32 partSize) + : RecordsCount(partSize) + , SourceId(source->GetSourceId()) + , SourceIdx(source->GetSourceIdx()) { + AFL_VERIFY(partSize < source->GetResultRecordsCount()); + } + }; + + virtual bool DoHasData() const override { + return HeapSources.size(); + } + ui32 SourceIdxCurrent = 0; + std::shared_ptr NextSource; + std::deque HeapSources; + ui64 Limit = 0; + ui64 InFlightLimit = 1; + std::set FetchingInFlightSources; + bool Aborted = false; + bool Cleared = false; + + void DrainToLimit(); + + virtual std::shared_ptr DoBuildCursor(const std::shared_ptr& source, const ui32 readyRecords) const override { + return std::make_shared(nullptr, source->GetSourceId(), readyRecords); + } + virtual void DoClear() override { + Cleared = true; + HeapSources.clear(); + FetchingInFlightSources.clear(); + } + virtual void DoAbort() override { + Aborted = true; + HeapSources.clear(); + FetchingInFlightSources.clear(); + } + virtual bool DoIsFinished() const override { + return HeapSources.empty() && FetchingInFlightSources.empty(); + } + virtual std::shared_ptr DoExtractNext() override; + virtual bool DoCheckInFlightLimits() const override { + return FetchingInFlightSources.size() < InFlightLimit; + } + + virtual void DoOnSourceFinished(const std::shared_ptr& source) override; + ui32 GetInFlightIntervalsCount(const TCompareKeyForScanSequence& from, const TCompareKeyForScanSequence& to) const; + +public: + const std::shared_ptr& GetNextSource() const { + return NextSource; + } + + TScanWithLimitCollection(const std::shared_ptr& context, std::deque&& sources, + const std::shared_ptr& cursor); +}; + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/not_sorted.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/not_sorted.cpp new file mode 100644 index 000000000000..8962f0263340 --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/not_sorted.cpp @@ -0,0 +1,10 @@ +#include "not_sorted.h" + +namespace NKikimr::NOlap::NReader::NSimple { + + std::shared_ptr TNotSortedCollection::DoBuildCursor( + const std::shared_ptr& source, const ui32 readyRecords) const { + return std::make_shared(source->GetSourceId(), readyRecords); +} + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/not_sorted.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/not_sorted.h new file mode 100644 index 000000000000..45b855d9db0e --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/not_sorted.h @@ -0,0 +1,78 @@ +#pragma once +#include "abstract.h" + +namespace NKikimr::NOlap::NReader::NSimple { + +class TNotSortedCollection: public ISourcesCollection { +private: + using TBase = ISourcesCollection; + std::optional Limit; + ui32 InFlightLimit = 1; + std::deque Sources; + TPositiveControlInteger InFlightCount; + ui32 FetchedCount = 0; + ui32 SourceIdx = 0; + virtual bool DoHasData() const override { + return Sources.size(); + } + virtual void DoClear() override { + Sources.clear(); + } + virtual void DoAbort() override { + Sources.clear(); + } + + virtual std::shared_ptr DoBuildCursor(const std::shared_ptr& source, const ui32 readyRecords) const override; + virtual bool DoIsFinished() const override { + return Sources.empty(); + } + virtual std::shared_ptr DoExtractNext() override { + AFL_VERIFY(Sources.size()); + auto result = Sources.front().Construct(SourceIdx++, Context); + Sources.pop_front(); + InFlightCount.Inc(); + return result; + } + virtual bool DoCheckInFlightLimits() const override { + return InFlightCount < InFlightLimit; + } + virtual void DoOnSourceFinished(const std::shared_ptr& source) override { + if (!source->GetResultRecordsCount() && InFlightLimit * 2 < GetMaxInFlight()) { + InFlightLimit *= 2; + } + FetchedCount += source->GetResultRecordsCount(); + if (Limit && *Limit <= FetchedCount && Sources.size()) { + AFL_NOTICE(NKikimrServices::TX_COLUMNSHARD)("event", "limit_exhausted")("limit", Limit)("fetched", FetchedCount); + Sources.clear(); + } + InFlightCount.Dec(); + } + +public: + TNotSortedCollection(const std::shared_ptr& context, std::deque&& sources, + const std::shared_ptr& cursor, const std::optional limit) + : TBase(context) + , Limit(limit) { + if (Limit) { + InFlightLimit = 1; + } else { + InFlightLimit = GetMaxInFlight(); + } + if (cursor && cursor->IsInitialized()) { + while (sources.size()) { + bool usage = false; + if (!context->GetCommonContext()->GetScanCursor()->CheckEntityIsBorder(sources.front(), usage)) { + sources.pop_front(); + continue; + } + if (usage) { + sources.front().SetIsStartedByCursor(); + } + break; + } + } + Sources = std::move(sources); + } +}; + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/ya.make b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/ya.make new file mode 100644 index 000000000000..640e7bbbe839 --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections/ya.make @@ -0,0 +1,14 @@ +LIBRARY() + +SRCS( + abstract.cpp + not_sorted.cpp + full_scan_sorted.cpp + limit_sorted.cpp +) + +PEERDIR( + ydb/core/formats/arrow +) + +END() diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/context.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/context.cpp index b00d2e8a3808..59f3601bf55e 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/context.cpp +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/context.cpp @@ -14,8 +14,8 @@ std::shared_ptr TSpecialReadContext::DoGetColumnsFetchingPlan(c if (!dontNeedColumns && !source->HasStageData()) { if (!AskAccumulatorsScript) { NCommon::TFetchingScriptBuilder acc(*this); - acc.AddStep(std::make_shared - (source->PredictAccessorsSize(GetFFColumns()->GetColumnIds()), EStageFeaturesIndexes::Accessors)); + acc.AddStep(std::make_shared( + source->PredictAccessorsSize(GetFFColumns()->GetColumnIds()), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Accessors)); acc.AddStep(std::make_shared()); acc.AddStep(std::make_shared(*GetFFColumns())); AskAccumulatorsScript = std::move(acc).Build(); @@ -64,31 +64,31 @@ std::shared_ptr TSpecialReadContext::BuildColumnsFetchingPlan(c NCommon::TFetchingScriptBuilder acc(*this); if (needFilterSharding && !GetShardingColumns()->IsEmpty()) { const TColumnsSetIds columnsFetch = *GetShardingColumns(); - acc.AddFetchingStep(columnsFetch, EStageFeaturesIndexes::Filter); - acc.AddAssembleStep(columnsFetch, "SPEC_SHARDING", EStageFeaturesIndexes::Filter, false); + acc.AddFetchingStep(columnsFetch, NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); + acc.AddAssembleStep(columnsFetch, "SPEC_SHARDING", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); } { acc.SetBranchName("exclusive"); if (needFilterDeletion) { - acc.AddFetchingStep(*GetDeletionColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetDeletionColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); } if (partialUsageByPredicate) { - acc.AddFetchingStep(*GetPredicateColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetPredicateColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); } if (needSnapshots || GetFFColumns()->Cross(*GetSpecColumns())) { - acc.AddFetchingStep(*GetSpecColumns(), EStageFeaturesIndexes::Filter); + acc.AddFetchingStep(*GetSpecColumns(), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); } if (needFilterDeletion) { - acc.AddAssembleStep(*GetDeletionColumns(), "SPEC_DELETION", EStageFeaturesIndexes::Filter, false); + acc.AddAssembleStep(*GetDeletionColumns(), "SPEC_DELETION", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); } if (partialUsageByPredicate) { - acc.AddAssembleStep(*GetPredicateColumns(), "PREDICATE", EStageFeaturesIndexes::Filter, false); + acc.AddAssembleStep(*GetPredicateColumns(), "PREDICATE", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); } if (needSnapshots || GetFFColumns()->Cross(*GetSpecColumns())) { - acc.AddAssembleStep(*GetSpecColumns(), "SPEC", EStageFeaturesIndexes::Filter, false); + acc.AddAssembleStep(*GetSpecColumns(), "SPEC", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); } const auto& chainProgram = GetReadMetadata()->GetProgram().GetChainVerified(); diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/context.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/context.h index f4e3d0ab36c3..c1859a3062d7 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/context.h +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/context.h @@ -12,7 +12,6 @@ namespace NKikimr::NOlap::NReader::NSimple { class IDataSource; using TColumnsSet = NCommon::TColumnsSet; -using EStageFeaturesIndexes = NCommon::EStageFeaturesIndexes; using TColumnsSetIds = NCommon::TColumnsSetIds; using EMemType = NCommon::EMemType; using TFetchingScript = NCommon::TFetchingScript; diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.cpp index fa7d86825f58..7d82fa672338 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.cpp +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.cpp @@ -22,9 +22,10 @@ ui64 IFetchingStep::GetProcessingDataSize(const std::shared_ptr TPredicateFilter::DoExecuteInplace(const std::shared_ptr& source, const TFetchingScriptCursor& /*step*/) const { auto filter = source->GetContext()->GetReadMetadata()->GetPKRangesFilter().BuildFilter( - source->GetStageData().GetTable()->ToTable(source->GetContext()->GetReadMetadata()->GetPKRangesFilter().GetColumnIds( - source->GetContext()->GetReadMetadata()->GetResultSchema()->GetIndexInfo()), - source->GetContext()->GetCommonContext()->GetResolver(), true)); + source->GetStageData().GetTable()->ToGeneralContainer(source->GetContext()->GetCommonContext()->GetResolver(), + source->GetContext()->GetReadMetadata()->GetPKRangesFilter().GetColumnIds( + source->GetContext()->GetReadMetadata()->GetResultSchema()->GetIndexInfo()), + true)); source->MutableStageData().AddFilter(filter); return true; } @@ -99,7 +100,7 @@ TConclusion TDetectInMem::DoExecuteInplace(const std::shared_ptrInitFetchingPlan(plan); TFetchingScriptCursor cursor(plan, 0); FOR_DEBUG_LOG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG, source->AddEvent("sdmem")); - auto task = std::make_shared(source, std::move(cursor), source->GetContext()->GetCommonContext()->GetScanActorId()); + auto task = std::make_shared(source, std::move(cursor), source->GetContext()->GetCommonContext()->GetScanActorId(), false); NConveyor::TScanServiceOperator::SendTaskToExecute(task); return false; } @@ -108,25 +109,19 @@ namespace { class TApplySourceResult: public IDataTasksProcessor::ITask { private: using TBase = IDataTasksProcessor::ITask; - YDB_READONLY_DEF(std::shared_ptr, Result); YDB_READONLY_DEF(std::shared_ptr, Source); - YDB_READONLY(ui32, StartIndex, 0); - YDB_READONLY(ui32, OriginalRecordsCount, 0); NColumnShard::TCounterGuard Guard; TFetchingScriptCursor Step; public: - TString GetTaskClassIdentifier() const override { + virtual TString GetTaskClassIdentifier() const override { return "TApplySourceResult"; } - TApplySourceResult(const std::shared_ptr& source, std::shared_ptr&& result, const ui32 startIndex, - const ui32 originalRecordsCount, const TFetchingScriptCursor& step) + TApplySourceResult( + const std::shared_ptr& source, const TFetchingScriptCursor& step) : TBase(NActors::TActorId()) - , Result(result) , Source(source) - , StartIndex(startIndex) - , OriginalRecordsCount(originalRecordsCount) , Guard(source->GetContext()->GetCommonContext()->GetCounters().GetResultsForSourceGuard()) , Step(step) { } @@ -137,9 +132,9 @@ class TApplySourceResult: public IDataTasksProcessor::ITask { } virtual bool DoApply(IDataReader& indexedDataRead) const override { auto* plainReader = static_cast(&indexedDataRead); - auto resultCopy = Result; Source->SetCursor(Step); - plainReader->MutableScanner().OnSourceReady(Source, std::move(resultCopy), StartIndex, OriginalRecordsCount, *plainReader); + Source->StartSyncSection(); + plainReader->MutableScanner().GetResultSyncPoint()->OnSourcePrepared(Source, *plainReader); return true; } }; @@ -163,33 +158,47 @@ TConclusion TBuildResultStep::DoExecuteInplace(const std::shared_ptrnum_rows() : 0; + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "TBuildResultStep")("source_id", source->GetSourceId())("count", recordsCount); + context->GetCommonContext()->GetCounters().OnSourceFinished(source->GetRecordsCount(), source->GetUsedRawBytes(), recordsCount); + source->MutableResultRecordsCount() += recordsCount; + if (!resultBatch || !resultBatch->num_rows()) { + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("empty_source", source->DebugJson().GetStringRobust()); + } + source->MutableStageResult().SetResultChunk(std::move(resultBatch), StartIndex, RecordsCount); NActors::TActivationContext::AsActorContext().Send(context->GetCommonContext()->GetScanActorId(), - new NColumnShard::TEvPrivate::TEvTaskProcessedResult( - std::make_shared(source, std::move(resultBatch), StartIndex, RecordsCount, step))); + new NColumnShard::TEvPrivate::TEvTaskProcessedResult(std::make_shared(source, step))); return false; } TConclusion TPrepareResultStep::DoExecuteInplace(const std::shared_ptr& source, const TFetchingScriptCursor& /*step*/) const { - NCommon::TFetchingScriptBuilder acc(*source->GetContext()); + const auto context = source->GetContext(); + NCommon::TFetchingScriptBuilder acc(*context); if (source->IsSourceInMemory()) { AFL_VERIFY(source->GetStageResult().GetPagesToResultVerified().size() == 1); } + AFL_VERIFY(!source->GetStageResult().IsEmpty()); for (auto&& i : source->GetStageResult().GetPagesToResultVerified()) { - if (source->GetIsStartedByCursor() && !source->GetContext()->GetCommonContext()->GetScanCursor()->CheckSourceIntervalUsage( + if (source->GetIsStartedByCursor() && !context->GetCommonContext()->GetScanCursor()->CheckSourceIntervalUsage( source->GetSourceId(), i.GetIndexStart(), i.GetRecordsCount())) { + AFL_WARN(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "TPrepareResultStep_ResultStep_SKIP_CURSOR")("source_id", source->GetSourceId()); continue; + } else { + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "TPrepareResultStep_ResultStep")("source_id", source->GetSourceId()); } acc.AddStep(std::make_shared(i.GetIndexStart(), i.GetRecordsCount())); } auto plan = std::move(acc).Build(); AFL_VERIFY(!plan->IsFinished(0)); source->InitFetchingPlan(plan); - - TFetchingScriptCursor cursor(plan, 0); - auto task = std::make_shared(source, std::move(cursor), source->GetContext()->GetCommonContext()->GetScanActorId()); - NConveyor::TScanServiceOperator::SendTaskToExecute(task); - return false; + if (source->NeedFullAnswer()) { + TFetchingScriptCursor cursor(plan, 0); + auto task = std::make_shared(source, std::move(cursor), context->GetCommonContext()->GetScanActorId(), false); + NConveyor::TScanServiceOperator::SendTaskToExecute(task); + return false; + } else { + return true; + } } } // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.h index 0a62e6c0a593..d1dcc822b035 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.h +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.h @@ -15,7 +15,6 @@ namespace NKikimr::NOlap::NReader::NSimple { class IDataSource; using TColumnsSet = NCommon::TColumnsSet; using TIndexesSet = NCommon::TIndexesSet; -using EStageFeaturesIndexes = NCommon::EStageFeaturesIndexes; using TColumnsSetIds = NCommon::TColumnsSetIds; using EMemType = NCommon::EMemType; using TFetchingScriptCursor = NCommon::TFetchingScriptCursor; diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/plain_read_data.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/plain_read_data.cpp index ab4cc51d6c6e..898c6f92c5db 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/plain_read_data.cpp +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/plain_read_data.cpp @@ -57,4 +57,11 @@ void TPlainReadData::OnIntervalResult(const std::shared_ptr& PartialResults.emplace_back(result); } +void TPlainReadData::OnSentDataFromInterval(const TPartialSourceAddress& sourceAddress) { + if (!SpecialReadContext->IsActive()) { + return; + } + Scanner->GetSyncPoint(sourceAddress.GetSyncPointIndex())->Continue(sourceAddress, *this); +} + } // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/plain_read_data.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/plain_read_data.h index adfe861d6319..19c8e14acedf 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/plain_read_data.h +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/plain_read_data.h @@ -60,12 +60,7 @@ class TPlainReadData: public IDataReader, TNonCopyable, NColumnShard::TMonitorin TScanHead& MutableScanner() { return *Scanner; } - virtual void OnSentDataFromInterval(const ui32 sourceIdx) const override { - if (!SpecialReadContext->IsActive()) { - return; - } - Scanner->ContinueSource(sourceIdx); - } + virtual void OnSentDataFromInterval(const TPartialSourceAddress& sourceAddress) override; void OnIntervalResult(const std::shared_ptr& result); diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/scanner.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/scanner.cpp index deecda048780..94602e987849 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/scanner.cpp +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/scanner.cpp @@ -1,6 +1,12 @@ #include "plain_read_data.h" #include "scanner.h" +#include "collections/full_scan_sorted.h" +#include "collections/limit_sorted.h" +#include "collections/not_sorted.h" +#include "sync_points/limit.h" +#include "sync_points/result.h" + #include #include @@ -8,59 +14,6 @@ namespace NKikimr::NOlap::NReader::NSimple { -void TScanHead::OnSourceReady(const std::shared_ptr& source, std::shared_ptr&& tableExt, const ui32 startIndex, - const ui32 recordsCount, TPlainReadData& reader) { - FOR_DEBUG_LOG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG, source->AddEvent("f")); - AFL_DEBUG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG)("event_log", source->GetEventsReport())("count", FetchingSources.size()); - source->MutableResultRecordsCount() += tableExt ? tableExt->num_rows() : 0; - if (!tableExt || !tableExt->num_rows()) { - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("empty_source", source->DebugJson().GetStringRobust()); - } - Context->GetCommonContext()->GetCounters().OnSourceFinished( - source->GetRecordsCount(), source->GetUsedRawBytes(), tableExt ? tableExt->num_rows() : 0); - - source->MutableStageResult().SetResultChunk(std::move(tableExt), startIndex, recordsCount); - while (FetchingSources.size()) { - auto frontSource = FetchingSources.front(); - if (!frontSource->HasStageResult()) { - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD)("event", "skip_no_result")("source_id", frontSource->GetSourceId())( - "source_idx", frontSource->GetSourceIdx()); - break; - } - if (!frontSource->GetStageResult().HasResultChunk()) { - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD)("event", "skip_no_result_chunk")("source_id", frontSource->GetSourceId())( - "source_idx", frontSource->GetSourceIdx()); - break; - } - auto table = frontSource->MutableStageResult().ExtractResultChunk(); - const bool isFinished = frontSource->GetStageResult().IsFinished(); - std::optional sourceIdxToContinue; - if (!isFinished) { - sourceIdxToContinue = frontSource->GetSourceIdx(); - } - if (table && table->num_rows()) { - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD)("event", "has_result")("source_id", frontSource->GetSourceId())( - "source_idx", frontSource->GetSourceIdx())("table", table->num_rows()); - auto cursor = SourcesCollection->BuildCursor(frontSource, startIndex + recordsCount); - reader.OnIntervalResult(std::make_shared(frontSource->GetResourceGuards(), frontSource->GetGroupGuard(), table, - cursor, Context->GetCommonContext(), sourceIdxToContinue)); - SourcesCollection->OnIntervalResult(table, frontSource); - } else if (sourceIdxToContinue) { - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD)("event", "continue_source")("source_id", frontSource->GetSourceId())( - "source_idx", frontSource->GetSourceIdx()); - ContinueSource(*sourceIdxToContinue); - break; - } - if (!isFinished) { - break; - } - AFL_VERIFY(FetchingSourcesByIdx.erase(frontSource->GetSourceIdx())); - FetchingSources.pop_front(); - frontSource->ClearResult(); - SourcesCollection->OnSourceFinished(frontSource); - } -} - TConclusionStatus TScanHead::Start() { return TConclusionStatus::Success(); } @@ -69,29 +22,30 @@ TScanHead::TScanHead(std::deque&& sources, const std::shared : Context(context) { if (Context->GetReadMetadata()->IsSorted()) { if (Context->GetReadMetadata()->HasLimit()) { - SourcesCollection = - std::make_unique(Context, std::move(sources), context->GetCommonContext()->GetScanCursor()); + auto collection = + std::make_shared(Context, std::move(sources), context->GetCommonContext()->GetScanCursor()); + SourcesCollection = collection; + SyncPoints.emplace_back(std::make_shared( + (ui64)Context->GetCommonContext()->GetReadMetadata()->GetLimitRobust(), SyncPoints.size(), context, collection)); } else { SourcesCollection = - std::make_unique(Context, std::move(sources), context->GetCommonContext()->GetScanCursor()); + std::make_shared(Context, std::move(sources), context->GetCommonContext()->GetScanCursor()); } } else { - SourcesCollection = std::make_unique( + SourcesCollection = std::make_shared( Context, std::move(sources), context->GetCommonContext()->GetScanCursor(), Context->GetReadMetadata()->GetLimitRobustOptional()); } + SyncPoints.emplace_back(std::make_shared(SyncPoints.size(), context, SourcesCollection)); + for (ui32 i = 0; i + 1 < SyncPoints.size(); ++i) { + SyncPoints[i]->SetNext(SyncPoints[i + 1]); + } } TConclusion TScanHead::BuildNextInterval() { - if (!Context->IsActive()) { - return false; - } bool changed = false; - while (!SourcesCollection->IsFinished() && SourcesCollection->CheckInFlightLimits() && Context->IsActive()) { + while (SourcesCollection->HasData() && SourcesCollection->CheckInFlightLimits()) { auto source = SourcesCollection->ExtractNext(); - source->InitFetchingPlan(Context->GetColumnsFetchingPlan(source)); - source->StartProcessing(source); - FetchingSources.emplace_back(source); - AFL_VERIFY(FetchingSourcesByIdx.emplace(source->GetSourceIdx(), source).second); + SyncPoints.front()->AddSource(source); changed = true; } return changed; @@ -107,16 +61,15 @@ bool TScanHead::IsReverse() const { void TScanHead::Abort() { AFL_VERIFY(!Context->IsActive()); - for (auto&& i : FetchingSources) { + for (auto&& i : SyncPoints) { i->Abort(); } - FetchingSources.clear(); - SourcesCollection->Clear(); + SourcesCollection->Abort(); Y_ABORT_UNLESS(IsFinished()); } TScanHead::~TScanHead() { - AFL_VERIFY(!IntervalsInFlightCount || !Context->IsActive()); + AFL_VERIFY(IsFinished() || !Context->IsActive()); } } // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/scanner.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/scanner.h index d38ebef6eb0f..c505433c14b7 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/scanner.h +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/scanner.h @@ -1,7 +1,9 @@ #pragma once -#include "collections.h" #include "source.h" +#include "collections/abstract.h" +#include "sync_points/abstract.h" + #include #include #include @@ -14,27 +16,39 @@ class TPlainReadData; class TScanHead { private: std::shared_ptr Context; - THashMap> FetchingSourcesByIdx; - std::deque> FetchingSources; - TPositiveControlInteger IntervalsInFlightCount; - std::unique_ptr SourcesCollection; - - void StartNextSource(const std::shared_ptr& source); + std::shared_ptr SourcesCollection; + std::vector> SyncPoints; public: - ~TScanHead(); + const std::shared_ptr& GetResultSyncPoint() const { + return SyncPoints.back(); + } + + const std::shared_ptr& GetSyncPoint(const ui32 index) const { + AFL_VERIFY(index < SyncPoints.size()); + return SyncPoints[index]; + } - void ContinueSource(const ui32 sourceIdx) const { - auto it = FetchingSourcesByIdx.find(sourceIdx); - AFL_VERIFY(it != FetchingSourcesByIdx.end())("source_idx", sourceIdx)("count", FetchingSourcesByIdx.size()); - it->second->ContinueCursor(it->second); + ISourcesCollection& MutableSourcesCollection() const { + return *SourcesCollection; } + const ISourcesCollection& GetSourcesCollection() const { + return *SourcesCollection; + } + + ~TScanHead(); + bool IsReverse() const; void Abort(); bool IsFinished() const { - return FetchingSources.empty() && SourcesCollection->IsFinished(); + for (auto&& i : SyncPoints) { + if (!i->IsFinished()) { + return false; + } + } + return SourcesCollection->IsFinished(); } const TReadContext& GetContext() const; @@ -42,16 +56,14 @@ class TScanHead { TString DebugString() const { TStringBuilder sb; sb << "S:{" << SourcesCollection->DebugString() << "};"; - sb << "F:"; - for (auto&& i : FetchingSources) { - sb << i->GetSourceId() << ";"; + sb << "SP:["; + for (auto&& i : SyncPoints) { + sb << "{" << i->DebugString() << "};"; } + sb << "]"; return sb; } - void OnSourceReady(const std::shared_ptr& source, std::shared_ptr&& table, const ui32 startIndex, - const ui32 recordsCount, TPlainReadData& reader); - TConclusionStatus Start(); TScanHead(std::deque&& sources, const std::shared_ptr& context); diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/source.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/source.cpp index 9f4b04cdddea..d51efb74058a 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/source.cpp +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/source.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -26,40 +27,46 @@ void IDataSource::InitFetchingPlan(const std::shared_ptr& fetch } void IDataSource::StartProcessing(const std::shared_ptr& sourcePtr) { - AFL_VERIFY(!ProcessingStarted); - InitStageData(std::make_unique( - GetContext()->GetReadMetadata()->GetProgram().GetChainVerified()->HasAggregations(), sourcePtr->GetRecordsCount())); AFL_VERIFY(FetchingPlan); - ProcessingStarted = true; - SourceGroupGuard = NGroupedMemoryManager::TScanMemoryLimiterOperator::BuildGroupGuard( - GetContext()->GetProcessMemoryControlId(), GetContext()->GetCommonContext()->GetScanId()); - SetMemoryGroupId(SourceGroupGuard->GetGroupId()); - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("InitFetchingPlan", FetchingPlan->DebugString())("source_idx", GetSourceIdx()); - // NActors::TLogContextGuard logGuard(NActors::TLogContextBuilder::Build()("source", SourceIdx)("method", "InitFetchingPlan")); + if (!ProcessingStarted) { + InitStageData(std::make_unique( + GetContext()->GetReadMetadata()->GetProgram().GetChainVerified()->HasAggregations(), sourcePtr->GetRecordsCount())); + ProcessingStarted = true; + SourceGroupGuard = NGroupedMemoryManager::TScanMemoryLimiterOperator::BuildGroupGuard( + GetContext()->GetProcessMemoryControlId(), GetContext()->GetCommonContext()->GetScanId()); + SetMemoryGroupId(SourceGroupGuard->GetGroupId()); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("InitFetchingPlan", FetchingPlan->DebugString())("source_idx", GetSourceIdx()); + // NActors::TLogContextGuard logGuard(NActors::TLogContextBuilder::Build()("source", SourceIdx)("method", "InitFetchingPlan")); + } TFetchingScriptCursor cursor(FetchingPlan, 0); - auto task = std::make_shared(sourcePtr, std::move(cursor), GetContext()->GetCommonContext()->GetScanActorId()); + auto task = std::make_shared(sourcePtr, std::move(cursor), GetContext()->GetCommonContext()->GetScanActorId(), true); NConveyor::TScanServiceOperator::SendTaskToExecute(task); } void IDataSource::ContinueCursor(const std::shared_ptr& sourcePtr) { - AFL_VERIFY(!!ScriptCursor); + AFL_VERIFY(!!ScriptCursor)("source_id", GetSourceId()); if (ScriptCursor->Next()) { - auto task = std::make_shared(sourcePtr, std::move(*ScriptCursor), GetContext()->GetCommonContext()->GetScanActorId()); - NConveyor::TScanServiceOperator::SendTaskToExecute(task); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("source_id", GetSourceId())("event", "ContinueCursor"); + auto cursor = std::move(*ScriptCursor); ScriptCursor.reset(); + auto task = std::make_shared(sourcePtr, std::move(cursor), GetContext()->GetCommonContext()->GetScanActorId(), true); + NConveyor::TScanServiceOperator::SendTaskToExecute(task); + } else { + AFL_WARN(NKikimrServices::TX_COLUMNSHARD_SCAN)("source_id", GetSourceId())("event", "CannotContinueCursor"); } } void IDataSource::DoOnSourceFetchingFinishedSafe(IDataReader& owner, const std::shared_ptr& sourcePtr) { auto* plainReader = static_cast(&owner); - plainReader->MutableScanner().OnSourceReady(std::static_pointer_cast(sourcePtr), nullptr, 0, GetRecordsCount(), *plainReader); + auto sourceSimple = std::static_pointer_cast(sourcePtr); + plainReader->MutableScanner().GetSyncPoint(sourceSimple->GetPurposeSyncPointIndex())->OnSourcePrepared(sourceSimple, *plainReader); } void IDataSource::DoOnEmptyStageData(const std::shared_ptr& /*sourcePtr*/) { TMemoryProfileGuard mpg("SCAN_PROFILE::STAGE_RESULT_EMPTY", IS_DEBUG_LOG_ENABLED(NKikimrServices::TX_COLUMNSHARD_SCAN_MEMORY)); ResourceGuards.clear(); StageResult = TFetchedResult::BuildEmpty(); - StageResult->SetPages({ TPortionDataAccessor::TReadPage(0, GetRecordsCount(), 0) }); + StageResult->SetPages({}); ClearStageData(); } @@ -69,6 +76,7 @@ void IDataSource::DoBuildStageResult(const std::shared_ptr void IDataSource::Finalize(const std::optional memoryLimit) { TMemoryProfileGuard mpg("SCAN_PROFILE::STAGE_RESULT", IS_DEBUG_LOG_ENABLED(NKikimrServices::TX_COLUMNSHARD_SCAN_MEMORY)); + AFL_VERIFY(!GetStageData().IsEmptyWithData()); if (memoryLimit && !IsSourceInMemory()) { const auto accessor = GetStageData().GetPortionAccessor(); StageResult = std::make_unique(ExtractStageData(), *GetContext()->GetCommonContext()->GetResolver()); @@ -77,6 +85,10 @@ void IDataSource::Finalize(const std::optional memoryLimit) { StageResult = std::make_unique(ExtractStageData(), *GetContext()->GetCommonContext()->GetResolver()); StageResult->SetPages({ TPortionDataAccessor::TReadPage(0, GetRecordsCount(), 0) }); } + if (StageResult->IsEmpty()) { + StageResult = TFetchedResult::BuildEmpty(); + StageResult->SetPages({}); + } ClearStageData(); } @@ -374,7 +386,7 @@ class TPortionAccessorFetchingSubscriber: public IDataAccessorRequestsSubscriber Source->MutableStageData().SetPortionAccessor(std::move(result.ExtractPortionsVector().front())); Source->InitUsedRawBytes(); AFL_VERIFY(Step.Next()); - auto task = std::make_shared(Source, std::move(Step), Source->GetContext()->GetCommonContext()->GetScanActorId()); + auto task = std::make_shared(Source, std::move(Step), Source->GetContext()->GetCommonContext()->GetScanActorId(), false); NConveyor::TScanServiceOperator::SendTaskToExecute(task); } @@ -404,7 +416,7 @@ bool TPortionDataSource::DoStartFetchingAccessor(const std::shared_ptrAddPortion(Portion); request->SetColumnIds(GetContext()->GetAllUsageColumns()->GetColumnIds()); request->RegisterSubscriber(std::make_shared(step, sourcePtr)); - GetContext()->GetCommonContext()->GetDataAccessorsManager()->AskData(request); + GetContext()->GetCommonContext()->GetDataAccessorsManager()->AskData((NOlap::TTabletId)GetContext()->GetReadMetadata()->GetTabletId(), request); return true; } @@ -417,4 +429,49 @@ TPortionDataSource::TPortionDataSource( , Schema(GetContext()->GetReadMetadata()->GetLoadSchemaVerified(*portion)) { } +TConclusion TPortionDataSource::DoStartReserveMemory(const NArrow::NSSA::TProcessorContext& context, + const THashMap& columns, const THashMap& /*indexes*/, + const THashMap& /*headers*/, const std::shared_ptr& policy) { + class TEntitySize { + private: + YDB_READONLY(ui64, BlobsSize, 0); + YDB_READONLY(ui64, RawSize, 0); + + public: + void Add(const TEntitySize& item) { + Add(item.BlobsSize, item.RawSize); + } + + void Add(const ui64 blob, const ui64 raw) { + BlobsSize += blob; + RawSize += raw; + } + }; + + THashMap sizeByColumn; + for (auto&& [_, info] : columns) { + auto chunks = GetStageData().GetPortionAccessor().GetColumnChunksPointers(info.GetColumnId()); + auto& sizes = sizeByColumn[info.GetColumnId()]; + for (auto&& i : chunks) { + sizes.Add(i->GetBlobRange().GetSize(), i->GetMeta().GetRawBytes()); + } + } + TEntitySize result; + for (auto&& i : sizeByColumn) { + result.Add(i.second); + } + + auto source = context.GetDataSourceVerifiedAs(); + + const ui64 sizeToReserve = policy->GetReserveMemorySize( + result.GetBlobsSize(), result.GetRawSize(), GetContext()->GetReadMetadata()->GetLimitRobustOptional(), GetRecordsCount()); + + auto allocation = std::make_shared( + source, sizeToReserve, GetExecutionContext().GetCursorStep(), policy->GetStage(), false); + FOR_DEBUG_LOG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG, AddEvent("mr")); + NGroupedMemoryManager::TScanMemoryLimiterOperator::SendToAllocation(GetContext()->GetProcessMemoryControlId(), + GetContext()->GetCommonContext()->GetScanId(), GetMemoryGroupId(), { allocation }, (ui32)policy->GetStage()); + return true; +} + } // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/source.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/source.h index 290a6f2205ca..de0d8faa3b54 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/source.h +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/source.h @@ -51,6 +51,10 @@ class TReplaceKeyAdapter { NArrow::TComparablePosition Value; public: + const NArrow::TComparablePosition& GetValue() const { + return Value; + } + TReplaceKeyAdapter(const NArrow::TReplaceKey& rk, const bool reverse) : Reverse(reverse) , Value(rk) { @@ -138,6 +142,8 @@ class IDataSource: public NCommon::IDataSource { virtual void DoOnEmptyStageData(const std::shared_ptr& /*sourcePtr*/) override; void Finalize(const std::optional memoryLimit); + bool NeedFullAnswerFlag = true; + std::optional PurposeSyncPointIndex; protected: std::optional UsedRawBytes; @@ -149,6 +155,33 @@ class IDataSource: public NCommon::IDataSource { virtual bool DoStartFetchingAccessor(const std::shared_ptr& sourcePtr, const TFetchingScriptCursor& step) = 0; public: + bool NeedFullAnswer() const { + return NeedFullAnswerFlag; + } + + void SetNeedFullAnswer(const bool value) { + NeedFullAnswerFlag = value; + } + + ui32 GetPurposeSyncPointIndex() const { + AFL_VERIFY(PurposeSyncPointIndex); + return *PurposeSyncPointIndex; + } + + void ResetPurposeSyncPointIndex() { + AFL_VERIFY(PurposeSyncPointIndex); + PurposeSyncPointIndex.reset(); + } + + void SetPurposeSyncPointIndex(const ui32 value) { + if (!PurposeSyncPointIndex) { + AFL_VERIFY(value == 0); + } else { + AFL_VERIFY(*PurposeSyncPointIndex < value); + } + PurposeSyncPointIndex = value; + } + virtual void InitUsedRawBytes() = 0; ui64 GetUsedRawBytes() const { @@ -226,6 +259,9 @@ class IDataSource: public NCommon::IDataSource { virtual bool HasIndexes(const std::set& indexIds) const = 0; void InitFetchingPlan(const std::shared_ptr& fetching); + bool HasFetchingPlan() const { + return !!FetchingPlan; + } virtual ui64 GetIndexRawBytes(const std::set& indexIds) const = 0; @@ -292,6 +328,9 @@ class TPortionDataSource: public IDataSource { virtual TConclusion DoStartFetchImpl( const NArrow::NSSA::TProcessorContext& context, const std::vector>& fetchersExt) override; + virtual TConclusion DoStartReserveMemory(const NArrow::NSSA::TProcessorContext& context, + const THashMap& columns, const THashMap& indexes, + const THashMap& headers, const std::shared_ptr& policy) override; virtual TConclusion>> DoStartFetchIndex( const NArrow::NSSA::TProcessorContext& context, const TFetchIndexContext& fetchContext) override; virtual TConclusion DoCheckIndex(const NArrow::NSSA::TProcessorContext& context, @@ -470,10 +509,10 @@ class TSourceConstructor: public ICursorEntity { return item.Start < Start; } - std::shared_ptr Construct(const std::shared_ptr& context) const { + std::shared_ptr Construct(const ui32 sourceIdx, const std::shared_ptr& context) const { const auto& portions = context->GetReadMetadata()->SelectInfo->Portions; - AFL_VERIFY(PortionIdx < portions.size()); - auto result = std::make_shared(PortionIdx, portions[PortionIdx], context); + AFL_VERIFY(sourceIdx < portions.size()); + auto result = std::make_shared(sourceIdx, portions[PortionIdx], context); if (IsStartedByCursorFlag) { result->SetIsStartedByCursor(); } diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/abstract.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/abstract.cpp new file mode 100644 index 000000000000..9d840e46432c --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/abstract.cpp @@ -0,0 +1,93 @@ +#include "abstract.h" + +#include + +#include + +namespace NKikimr::NOlap::NReader::NSimple { + +void ISyncPoint::OnSourcePrepared(const std::shared_ptr& sourceInput, TPlainReadData& reader) { + const NActors::TLogContextGuard gLogging = NActors::TLogContextBuilder::Build()("sync_point", GetPointName())("aborted", AbortFlag); + if (AbortFlag) { + FOR_DEBUG_LOG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG, sourceInput->AddEvent("a" + GetShortPointName())); + AFL_WARN(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "sync_point_aborted")("source_id", sourceInput->GetSourceId()); + return; + } else { + FOR_DEBUG_LOG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG, sourceInput->AddEvent("f" + GetShortPointName())); + } + AFL_DEBUG(NKikimrServices::COLUMNSHARD_SCAN_EVLOG)("event_log", sourceInput->GetEventsReport())("count", SourcesSequentially.size())( + "source_id", sourceInput->GetSourceId()); + AFL_VERIFY(sourceInput->IsSyncSection())("source_id", sourceInput->GetSourceId()); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "OnSourcePrepared")("source_id", sourceInput->GetSourceId()); + while (SourcesSequentially.size() && IsSourcePrepared(SourcesSequentially.front())) { + auto source = SourcesSequentially.front(); + switch (OnSourceReady(source, reader)) { + case ESourceAction::Finish: { + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "finish_source")("source_id", source->GetSourceId()); + reader.GetScanner().MutableSourcesCollection().OnSourceFinished(source); + SourcesSequentially.pop_front(); + break; + } + case ESourceAction::ProvideNext: { + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "provide_source")("source_id", source->GetSourceId()); + if (Next) { + source->ResetSourceFinishedFlag(); + Next->AddSource(source); + } else { + reader.GetScanner().MutableSourcesCollection().OnSourceFinished(source); + } + SourcesSequentially.pop_front(); + break; + } + case ESourceAction::Wait: { + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "wait_source")("source_id", source->GetSourceId()); + return; + } + } + } +} + +TString ISyncPoint::DebugString() const { + TStringBuilder sb; + sb << "{"; + for (auto&& i : SourcesSequentially) { + sb << i->GetSourceId() << ","; + } + sb << "}"; + return sb; +} + +void ISyncPoint::Continue(const TPartialSourceAddress& continueAddress, TPlainReadData& /*reader*/) { + AFL_VERIFY(PointIndex == continueAddress.GetSyncPointIndex()); + AFL_VERIFY(SourcesSequentially.size() && SourcesSequentially.front()->GetSourceId() == continueAddress.GetSourceId())("first_source_id", + SourcesSequentially.front()->GetSourceId())( + "continue_source_id", continueAddress.GetSourceId()); + const NActors::TLogContextGuard gLogging = NActors::TLogContextBuilder::Build()("sync_point", GetPointName())("event", "continue_source"); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("source_id", SourcesSequentially.front()->GetSourceId()); + SourcesSequentially.front()->ContinueCursor(SourcesSequentially.front()); +} + +void ISyncPoint::AddSource(const std::shared_ptr& source) { + const NActors::TLogContextGuard gLogging = NActors::TLogContextBuilder::Build()("sync_point", GetPointName())("event", "add_source"); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("source_id", source->GetSourceId()); + AFL_VERIFY(!AbortFlag); + source->SetPurposeSyncPointIndex(GetPointIndex()); + if (Next) { + source->SetNeedFullAnswer(false); + } + AFL_VERIFY(!!source); + if (!LastSourceIdx) { + LastSourceIdx = source->GetSourceIdx(); + } else { + AFL_VERIFY(*LastSourceIdx < source->GetSourceIdx()); + } + LastSourceIdx = source->GetSourceIdx(); + SourcesSequentially.emplace_back(source); + if (!source->HasFetchingPlan()) { + source->InitFetchingPlan(Context->GetColumnsFetchingPlan(source)); + } + OnAddSource(source); + source->StartProcessing(source); +} + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/abstract.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/abstract.h new file mode 100644 index 000000000000..5ef3e4ede21a --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/abstract.h @@ -0,0 +1,83 @@ +#pragma once +#include +#include +#include + +#include + +namespace NKikimr::NOlap::NReader::NSimple { + +class TPlainReadData; +class ISourcesCollection; + +class ISyncPoint { +public: + enum class ESourceAction { + Finish, + ProvideNext, + Wait + }; + +private: + YDB_READONLY(ui32, PointIndex, 0); + YDB_READONLY_DEF(TString, PointName); + std::optional LastSourceIdx; + virtual void OnAddSource(const std::shared_ptr& /*source*/) { + } + virtual bool IsSourcePrepared(const std::shared_ptr& source) const = 0; + virtual ESourceAction OnSourceReady(const std::shared_ptr& source, TPlainReadData& reader) = 0; + virtual void DoAbort() = 0; + bool AbortFlag = false; + +protected: + const std::shared_ptr Context; + const std::shared_ptr Collection; + std::shared_ptr Next; + std::deque> SourcesSequentially; + +public: + virtual ~ISyncPoint() = default; + + void Continue(const TPartialSourceAddress& continueAddress, TPlainReadData& reader); + + TString DebugString() const; + + void Abort() { + SourcesSequentially.clear(); + if (!AbortFlag) { + AbortFlag = true; + DoAbort(); + } + } + + bool IsFinished() const { + return SourcesSequentially.empty(); + } + + void SetNext(const std::shared_ptr& next) { + AFL_VERIFY(!Next); + Next = next; + } + + TString GetShortPointName() const { + if (PointName.size() < 2) { + return PointName; + } else { + return PointName.substr(0, 2); + } + } + + ISyncPoint(const ui32 pointIndex, const TString& pointName, const std::shared_ptr& context, + const std::shared_ptr& collection) + : PointIndex(pointIndex) + , PointName(pointName) + , Context(context) + , Collection(collection) { + } + + void AddSource(const std::shared_ptr& source); + + void OnSourcePrepared(const std::shared_ptr& sourceInput, TPlainReadData& reader); +}; + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/limit.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/limit.cpp new file mode 100644 index 000000000000..ef6b890ea39d --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/limit.cpp @@ -0,0 +1,96 @@ +#include "limit.h" + +#include + +namespace NKikimr::NOlap::NReader::NSimple { + +TSyncPointLimitControl::TSyncPointLimitControl(const ui32 limit, const ui32 pointIndex, const std::shared_ptr& context, + const std::shared_ptr& collection) + : TBase(pointIndex, "SYNC_LIMIT", context, collection) + , Limit(limit) + , Collection(collection) { + AFL_VERIFY(Collection); +} + +bool TSyncPointLimitControl::DrainToLimit() { + std::optional nextInHeap; + if (Collection->GetNextSource()) { + nextInHeap = TSourceIterator(Collection->GetNextSource()); + } + if (Iterators.empty() || (nextInHeap && Iterators.front() < *nextInHeap)) { + return false; + } + + while (Iterators.size()) { + if (!Iterators.front().IsFilled()) { + return false; + } + std::pop_heap(Iterators.begin(), Iterators.end()); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "LimitIteratorNext")("source_id", Iterators.back().GetSourceId())( + "fetched", FetchedCount)("limit", Limit)("iterators", Iterators.size()); + if (!Iterators.back().Next()) { + Iterators.pop_back(); + } else { + std::push_heap(Iterators.begin(), Iterators.end()); + if (++FetchedCount >= Limit) { + return true; + } + } + } + return false; +} + +ISyncPoint::ESourceAction TSyncPointLimitControl::OnSourceReady(const std::shared_ptr& source, TPlainReadData& /*reader*/) { + if (FetchedCount >= Limit) { + return ESourceAction::Finish; + } + const auto& rk = *source->GetSourceSchema()->GetIndexInfo().GetReplaceKey(); + const auto& g = source->GetStageResult().GetBatch(); + AFL_VERIFY(Iterators.size()); + AFL_VERIFY(Iterators.front().GetSourceId() == source->GetSourceId())("front", Iterators.front().DebugString())( + "source", source->GetStart().DebugString())("source_id", source->GetSourceId()); + std::pop_heap(Iterators.begin(), Iterators.end()); + if (!g || !g->GetRecordsCount()) { + Iterators.pop_back(); + } else { + std::vector> arrs; + for (auto&& i : rk.fields()) { + auto acc = g->GetAccessorByNameOptional(i->name()); + if (!acc) { + break; + } + arrs.emplace_back(acc); + } + AFL_VERIFY(arrs.size()); + if (!PKPrefixSize) { + PKPrefixSize = arrs.size(); + } else { + AFL_VERIFY(*PKPrefixSize == arrs.size())("prefix", PKPrefixSize)("arr", arrs.size()); + } + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "DoOnSourceCheckLimitFillIterator")("source_id", source->GetSourceId())( + "fetched", FetchedCount)("limit", Limit); + Iterators.back() = TSourceIterator(arrs, source->GetStageResult().GetNotAppliedFilter(), source); + AFL_VERIFY(Iterators.back().IsFilled()); + std::push_heap(Iterators.begin(), Iterators.end()); + } + if (DrainToLimit()) { + Collection->Clear(); + } + if (source->GetStageResult().IsEmpty()) { + return ESourceAction::Finish; + } else { + return ESourceAction::ProvideNext; + } +} + +TString TSyncPointLimitControl::TSourceIterator::DebugString() const { + TStringBuilder sb; + sb << "{"; + sb << "id=" << Source->GetSourceId() << ";"; + sb << "f=" << IsFilled() << ";"; + sb << "record=" << SortableRecord->DebugJson() << ";"; + sb << "start=" << Source->GetStart().DebugString() << ";"; + return sb; +} + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/limit.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/limit.h new file mode 100644 index 000000000000..47ef3894275b --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/limit.h @@ -0,0 +1,142 @@ +#pragma once +#include "abstract.h" + +namespace NKikimr::NOlap::NReader::NSimple { + +class TScanWithLimitCollection; + +class TSyncPointLimitControl: public ISyncPoint { +private: + using TBase = ISyncPoint; + + const ui32 Limit; + std::shared_ptr Collection; + ui32 FetchedCount = 0; + std::optional PKPrefixSize; + + virtual bool IsSourcePrepared(const std::shared_ptr& source) const override { + if (source->IsSyncSection() && source->HasStageResult()) { + AFL_VERIFY(!source->GetStageResult().HasResultChunk()); + return true; + } + return false; + } + class TSourceIterator { + private: + std::shared_ptr Source; + bool Reverse; + int Delta = 0; + i64 Start = 0; + i64 Finish = 0; + std::shared_ptr SortableRecord; + std::shared_ptr Filter; + std::shared_ptr FilterIterator; + bool IsValidFlag = true; + + bool ShiftWithFilter() const { + AFL_VERIFY(IsValidFlag); + while (!FilterIterator->GetCurrentAcceptance()) { + if (!FilterIterator->Next(1)) { + AFL_VERIFY(!SortableRecord->NextPosition(Delta)); + return false; + } else { + AFL_VERIFY(SortableRecord->NextPosition(Delta)); + } + } + return true; + } + + public: + TString DebugString() const; + + const std::shared_ptr& GetSource() const { + AFL_VERIFY(Source); + return Source; + } + + TSourceIterator(const std::shared_ptr& source) + : Source(source) + , Reverse(Source->GetContext()->GetReadMetadata()->IsDescSorted()) + , Delta(Reverse ? -1 : 1) { + AFL_VERIFY(Source); + auto arr = Source->GetStart().GetValue().GetArrays(); + auto batch = + arrow::RecordBatch::Make(Source->GetSourceSchema()->GetIndexInfo().GetReplaceKey(), arr.front()->length(), std::move(arr)); + SortableRecord = + std::make_shared(batch, Source->GetStart().GetValue().GetMonoPosition(), Reverse); + } + + TSourceIterator(const std::vector>& arrs, + const std::shared_ptr& filter, const std::shared_ptr& source) + : Source(source) + , Reverse(Source->GetContext()->GetReadMetadata()->IsDescSorted()) + , Delta(Reverse ? -1 : 1) + , Start(Reverse ? (arrs.front()->GetRecordsCount() - 1) : 0) + , Finish(Reverse ? 0 : (arrs.front()->GetRecordsCount() - 1)) + , Filter(filter ? filter : std::make_shared(NArrow::TColumnFilter::BuildAllowFilter())) { + AFL_VERIFY(arrs.size()); + AFL_VERIFY(arrs.front()->GetRecordsCount()); + FilterIterator = std::make_shared(Filter->GetIterator(Reverse, arrs.front()->GetRecordsCount())); + auto prefixSchema = Source->GetSourceSchema()->GetIndexInfo().GetReplaceKeyPrefix(arrs.size()); + auto copyArrs = arrs; + auto batch = std::make_shared(prefixSchema->fields(), std::move(copyArrs)); + SortableRecord = std::make_shared(batch, Start, Reverse); + IsValidFlag = ShiftWithFilter(); + } + + ui64 GetSourceId() const { + AFL_VERIFY(Source); + return Source->GetSourceId(); + } + + bool IsFilled() const { + return !!Filter; + } + + bool IsValid() const { + return IsValidFlag; + } + + bool Next() { + AFL_VERIFY(IsValidFlag); + AFL_VERIFY(!!SortableRecord); + AFL_VERIFY(!!Filter); + IsValidFlag = SortableRecord->NextPosition(Delta); + AFL_VERIFY(FilterIterator->Next(1) == IsValidFlag); + if (IsValidFlag) { + IsValidFlag = ShiftWithFilter(); + } + return IsValidFlag; + } + + bool operator<(const TSourceIterator& item) const { + const auto cmp = SortableRecord->ComparePartial(*item.SortableRecord); + if (cmp == std::partial_ordering::equivalent) { + return item.Source->GetSourceId() < Source->GetSourceId(); + } + return cmp == std::partial_ordering::greater; + } + }; + + std::vector Iterators; + + virtual void OnAddSource(const std::shared_ptr& source) override { + AFL_VERIFY(FetchedCount < Limit); + Iterators.emplace_back(TSourceIterator(source)); + std::push_heap(Iterators.begin(), Iterators.end()); + } + + virtual void DoAbort() override { + Iterators.clear(); + } + + virtual ESourceAction OnSourceReady(const std::shared_ptr& source, TPlainReadData& reader) override; + + bool DrainToLimit(); + +public: + TSyncPointLimitControl(const ui32 limit, const ui32 pointIndex, const std::shared_ptr& context, + const std::shared_ptr& collection); +}; + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/result.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/result.cpp new file mode 100644 index 000000000000..d848cd6f7a69 --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/result.cpp @@ -0,0 +1,36 @@ +#include "result.h" + +#include + +namespace NKikimr::NOlap::NReader::NSimple { + +ISyncPoint::ESourceAction TSyncPointResult::OnSourceReady(const std::shared_ptr& source, TPlainReadData& reader) { + if (source->GetStageResult().IsEmpty()) { + return ESourceAction::Finish; + } + auto resultChunk = source->MutableStageResult().ExtractResultChunk(); + const bool isFinished = source->GetStageResult().IsFinished(); + if (resultChunk && resultChunk->HasData()) { + std::optional partialSourceAddress; + if (!isFinished) { + partialSourceAddress = TPartialSourceAddress(source->GetSourceId(), source->GetSourceIdx(), GetPointIndex()); + } + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "has_result")("source_id", source->GetSourceId())( + "source_idx", source->GetSourceIdx())("table", resultChunk->GetTable()->num_rows())("is_finished", isFinished); + auto cursor = Collection->BuildCursor(source, resultChunk->GetStartIndex() + resultChunk->GetRecordsCount(), + Context->GetCommonContext()->GetReadMetadata()->GetTabletId()); + reader.OnIntervalResult(std::make_shared(source->GetResourceGuards(), source->GetGroupGuard(), + resultChunk->GetTable(), cursor, Context->GetCommonContext(), partialSourceAddress)); + } else if (!isFinished) { + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_SCAN)("event", "continue_source")("source_id", source->GetSourceId())( + "source_idx", source->GetSourceIdx()); + source->ContinueCursor(source); + } + if (!isFinished) { + return ESourceAction::Wait; + } + source->ClearResult(); + return ESourceAction::ProvideNext; +} + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/result.h b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/result.h new file mode 100644 index 000000000000..8df2879d938b --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/result.h @@ -0,0 +1,25 @@ +#pragma once +#include "abstract.h" + +namespace NKikimr::NOlap::NReader::NSimple { + +class TSyncPointResult: public ISyncPoint { +private: + using TBase = ISyncPoint; + virtual void DoAbort() override { + } + + virtual ESourceAction OnSourceReady(const std::shared_ptr& source, TPlainReadData& reader) override; + virtual bool IsSourcePrepared(const std::shared_ptr& source) const override { + return source->IsSyncSection() && source->HasStageResult() && + (source->GetStageResult().HasResultChunk() || source->GetStageResult().IsEmpty()); + } + +public: + TSyncPointResult( + const ui32 pointIndex, const std::shared_ptr& context, const std::shared_ptr& collection) + : TBase(pointIndex, "RESULT", context, collection) { + } +}; + +} // namespace NKikimr::NOlap::NReader::NSimple diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/ya.make b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/ya.make new file mode 100644 index 000000000000..58d66933ef7b --- /dev/null +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points/ya.make @@ -0,0 +1,13 @@ +LIBRARY() + +SRCS( + abstract.cpp + result.cpp + limit.cpp +) + +PEERDIR( + ydb/core/formats/arrow +) + +END() diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/ya.make b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/ya.make index 3917d8d91331..baff60941f27 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/ya.make +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/ya.make @@ -8,13 +8,14 @@ SRCS( context.cpp fetching.cpp iterator.cpp - collections.cpp ) PEERDIR( ydb/core/formats/arrow ydb/core/tx/columnshard/blobs_action ydb/core/tx/columnshard/engines/reader/common_reader/iterator + ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/collections + ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/sync_points ydb/core/tx/conveyor/usage ydb/core/tx/limiter/grouped_memory/usage ) diff --git a/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/iterator.cpp b/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/iterator.cpp index 09d1e7394467..26e1ebdb0950 100644 --- a/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/iterator.cpp +++ b/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/iterator.cpp @@ -44,7 +44,8 @@ TConclusion> TStatsIteratorBase::GetBatch() auto lastKey = keyBatch->Slice(keyBatch->num_rows() - 1, 1); { - NArrow::TColumnFilter filter = ReadMetadata->GetPKRangesFilter().BuildFilter(originalBatch); + NArrow::TColumnFilter filter = + ReadMetadata->GetPKRangesFilter().BuildFilter(std::make_shared(originalBatch)); filter.Apply(originalBatch); } diff --git a/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/metadata.h b/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/metadata.h index 7a9ee6bd36b5..63eff2dc866c 100644 --- a/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/metadata.h +++ b/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/metadata.h @@ -11,15 +11,13 @@ struct TReadStatsMetadata: public TReadMetadataBase { public: using TConstPtr = std::shared_ptr; - const ui64 TabletId; std::vector ReadColumnIds; std::vector ResultColumnIds; std::deque IndexGranules; explicit TReadStatsMetadata(const std::shared_ptr& info, ui64 tabletId, const ESorting sorting, const TProgramContainer& ssaProgram, const std::shared_ptr& schema, const TSnapshot& requestSnapshot) - : TBase(info, sorting, ssaProgram, schema, requestSnapshot, nullptr) - , TabletId(tabletId) { + : TBase(info, sorting, ssaProgram, schema, requestSnapshot, nullptr, tabletId) { } }; diff --git a/ydb/core/tx/columnshard/engines/reader/sys_view/chunks/chunks.cpp b/ydb/core/tx/columnshard/engines/reader/sys_view/chunks/chunks.cpp index 1d834877ba1c..664a4ac881cc 100644 --- a/ydb/core/tx/columnshard/engines/reader/sys_view/chunks/chunks.cpp +++ b/ydb/core/tx/columnshard/engines/reader/sys_view/chunks/chunks.cpp @@ -37,7 +37,7 @@ void TStatsIterator::AppendStats( for (auto&& r : records) { NArrow::Append(*builders[0], portion.GetPathId().GetRawValue()); NArrow::Append(*builders[1], prodView); - NArrow::Append(*builders[2], ReadMetadata->TabletId); + NArrow::Append(*builders[2], ReadMetadata->GetTabletId()); NArrow::Append(*builders[3], r->GetMeta().GetRecordsCount()); NArrow::Append(*builders[4], r->GetMeta().GetRawBytes()); NArrow::Append(*builders[5], portion.GetPortionId()); @@ -94,7 +94,7 @@ void TStatsIterator::AppendStats( for (auto&& r : indexes) { NArrow::Append(*builders[0], portion.GetPathId().GetRawValue()); NArrow::Append(*builders[1], prodView); - NArrow::Append(*builders[2], ReadMetadata->TabletId); + NArrow::Append(*builders[2], ReadMetadata->GetTabletId()); NArrow::Append(*builders[3], r->GetRecordsCount()); NArrow::Append(*builders[4], r->GetRawBytes()); NArrow::Append(*builders[5], portion.GetPortionId()); diff --git a/ydb/core/tx/columnshard/engines/reader/sys_view/chunks/chunks.h b/ydb/core/tx/columnshard/engines/reader/sys_view/chunks/chunks.h index c09a4f6d448b..802f14725150 100644 --- a/ydb/core/tx/columnshard/engines/reader/sys_view/chunks/chunks.h +++ b/ydb/core/tx/columnshard/engines/reader/sys_view/chunks/chunks.h @@ -5,6 +5,8 @@ #include #include +#include "ydb/core/tx/columnshard/engines/reader/abstract/read_context.h" + namespace NKikimr::NOlap::NReader::NSysView::NChunks { class TConstructor: public TStatScannerConstructor { @@ -111,7 +113,7 @@ class TStatsIterator: public NAbstract::TStatsIterator&& guard, const std::shared_ptr& /*selfPtr*/) override { Guard = std::move(guard); - AccessorsManager->AskData(std::move(Request)); + AccessorsManager->AskData((TTabletId)Context->GetReadMetadata()->GetTabletId(), std::move(Request)); return true; } virtual void DoOnAllocationImpossible(const TString& errorMessage) override; diff --git a/ydb/core/tx/columnshard/engines/reader/sys_view/granules/granules.cpp b/ydb/core/tx/columnshard/engines/reader/sys_view/granules/granules.cpp index 0144236ed3f8..b714821d7c9f 100644 --- a/ydb/core/tx/columnshard/engines/reader/sys_view/granules/granules.cpp +++ b/ydb/core/tx/columnshard/engines/reader/sys_view/granules/granules.cpp @@ -10,7 +10,7 @@ namespace NKikimr::NOlap::NReader::NSysView::NGranules { bool TStatsIterator::AppendStats(const std::vector>& builders, NAbstract::TGranuleMetaView& granule) const { NArrow::Append(*builders[0], granule.GetPathId().GetRawValue()); - NArrow::Append(*builders[1], ReadMetadata->TabletId); + NArrow::Append(*builders[1], ReadMetadata->GetTabletId()); NArrow::Append(*builders[2], granule.GetPortions().size()); NArrow::Append(*builders[3], HostNameField); NArrow::Append(*builders[4], NActors::TActivationContext::AsActorContext().SelfID.NodeId()); diff --git a/ydb/core/tx/columnshard/engines/reader/sys_view/optimizer/optimizer.cpp b/ydb/core/tx/columnshard/engines/reader/sys_view/optimizer/optimizer.cpp index 30ddcb83dc3d..c43e82b690fd 100644 --- a/ydb/core/tx/columnshard/engines/reader/sys_view/optimizer/optimizer.cpp +++ b/ydb/core/tx/columnshard/engines/reader/sys_view/optimizer/optimizer.cpp @@ -11,7 +11,7 @@ namespace NKikimr::NOlap::NReader::NSysView::NOptimizer { bool TStatsIterator::AppendStats(const std::vector>& builders, NAbstract::TGranuleMetaView& granule) const { for (auto&& i : granule.GetOptimizerTasks()) { NArrow::Append(*builders[0], granule.GetPathId().GetRawValue()); - NArrow::Append(*builders[1], ReadMetadata->TabletId); + NArrow::Append(*builders[1], ReadMetadata->GetTabletId()); NArrow::Append(*builders[2], i.GetTaskId()); NArrow::Append(*builders[3], HostNameField); NArrow::Append(*builders[4], NActors::TActivationContext::AsActorContext().SelfID.NodeId()); diff --git a/ydb/core/tx/columnshard/engines/reader/sys_view/portions/portions.cpp b/ydb/core/tx/columnshard/engines/reader/sys_view/portions/portions.cpp index 267b0cfbbd58..ae0e9bf3e29f 100644 --- a/ydb/core/tx/columnshard/engines/reader/sys_view/portions/portions.cpp +++ b/ydb/core/tx/columnshard/engines/reader/sys_view/portions/portions.cpp @@ -10,7 +10,7 @@ void TStatsIterator::AppendStats(const std::vector(*builders[0], portion.GetPathId().GetRawValue()); const std::string prod = ::ToString(portion.GetMeta().Produced); NArrow::Append(*builders[1], prod); - NArrow::Append(*builders[2], ReadMetadata->TabletId); + NArrow::Append(*builders[2], ReadMetadata->GetTabletId()); NArrow::Append(*builders[3], portion.GetRecordsCount()); NArrow::Append(*builders[4], portion.GetColumnRawBytes()); NArrow::Append(*builders[5], portion.GetIndexRawBytes()); diff --git a/ydb/core/tx/columnshard/engines/reader/transaction/tx_internal_scan.cpp b/ydb/core/tx/columnshard/engines/reader/transaction/tx_internal_scan.cpp index 4ff5ae1a3714..519cba47c90a 100644 --- a/ydb/core/tx/columnshard/engines/reader/transaction/tx_internal_scan.cpp +++ b/ydb/core/tx/columnshard/engines/reader/transaction/tx_internal_scan.cpp @@ -44,7 +44,7 @@ void TTxInternalScan::Complete(const TActorContext& ctx) { TScannerConstructorContext context(snapshot, 0, sorting); { - TReadDescription read(snapshot, sorting); + TReadDescription read(Self->TabletID(), snapshot, sorting); read.SetScanIdentifier(request.TaskIdentifier); read.PathId = request.GetPathId(); read.LockId = LockId; diff --git a/ydb/core/tx/columnshard/engines/reader/transaction/tx_scan.cpp b/ydb/core/tx/columnshard/engines/reader/transaction/tx_scan.cpp index 0982f11e1a92..bcca02549984 100644 --- a/ydb/core/tx/columnshard/engines/reader/transaction/tx_scan.cpp +++ b/ydb/core/tx/columnshard/engines/reader/transaction/tx_scan.cpp @@ -64,7 +64,7 @@ void TTxScan::Complete(const TActorContext& ctx) { { LOG_S_DEBUG("TTxScan prepare txId: " << txId << " scanId: " << scanId << " at tablet " << Self->TabletID()); - TReadDescription read(snapshot, sorting); + TReadDescription read(Self->TabletID(), snapshot, sorting); read.TxId = txId; if (request.HasLockTxId()) { read.LockId = request.GetLockTxId(); diff --git a/ydb/core/tx/columnshard/engines/scheme/index_info.h b/ydb/core/tx/columnshard/engines/scheme/index_info.h index 92574ef1a2b4..7fc0cce69a22 100644 --- a/ydb/core/tx/columnshard/engines/scheme/index_info.h +++ b/ydb/core/tx/columnshard/engines/scheme/index_info.h @@ -382,6 +382,16 @@ struct TIndexInfo: public IIndexInfo { return PKColumnIds[0]; } + std::shared_ptr GetReplaceKeyPrefix(const ui32 size) const { + AFL_VERIFY(size); + AFL_VERIFY(size <= (ui32)PrimaryKey->num_fields()); + if (size == (ui32)PrimaryKey->num_fields()) { + return PrimaryKey; + } else { + std::vector> fields(PrimaryKey->fields().begin(), PrimaryKey->fields().begin() + size); + return std::make_shared(std::move(fields)); + } + } const std::shared_ptr& GetReplaceKey() const { return PrimaryKey; } diff --git a/ydb/core/tx/columnshard/engines/scheme/versions/abstract_scheme.cpp b/ydb/core/tx/columnshard/engines/scheme/versions/abstract_scheme.cpp index b9a16ee06802..833ea12ff37d 100644 --- a/ydb/core/tx/columnshard/engines/scheme/versions/abstract_scheme.cpp +++ b/ydb/core/tx/columnshard/engines/scheme/versions/abstract_scheme.cpp @@ -340,6 +340,7 @@ TConclusion ISnapshotSchema::PrepareForWrite(c TConclusion> arrToWrite = loader->GetAccessorConstructor()->Construct(accessor, loader->BuildAccessorContext(accessor->GetRecordsCount())); if (arrToWrite.IsFail()) { + AFL_ERROR(NKikimrServices::TX_COLUMNSHARD)("event", "cannot build accessor")("reason", arrToWrite.GetErrorMessage()); return arrToWrite; } diff --git a/ydb/core/tx/columnshard/engines/storage/actualizer/counters/counters.h b/ydb/core/tx/columnshard/engines/storage/actualizer/counters/counters.h index e803df700f7b..1452f7bb342c 100644 --- a/ydb/core/tx/columnshard/engines/storage/actualizer/counters/counters.h +++ b/ydb/core/tx/columnshard/engines/storage/actualizer/counters/counters.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include namespace NKikimr::NOlap::NActualizer { diff --git a/ydb/core/tx/columnshard/engines/storage/actualizer/counters/ya.make b/ydb/core/tx/columnshard/engines/storage/actualizer/counters/ya.make index d73b370747be..81a1e3cdd937 100644 --- a/ydb/core/tx/columnshard/engines/storage/actualizer/counters/ya.make +++ b/ydb/core/tx/columnshard/engines/storage/actualizer/counters/ya.make @@ -7,7 +7,7 @@ SRCS( PEERDIR( ydb/library/actors/core ydb/core/tx/columnshard/engines/portions - ydb/core/tx/columnshard/counters/common + ydb/library/signals ) END() diff --git a/ydb/core/tx/columnshard/engines/storage/granule/granule.cpp b/ydb/core/tx/columnshard/engines/storage/granule/granule.cpp index 651b83e8c7ff..bbeb21b82c4d 100644 --- a/ydb/core/tx/columnshard/engines/storage/granule/granule.cpp +++ b/ydb/core/tx/columnshard/engines/storage/granule/granule.cpp @@ -31,7 +31,7 @@ void TGranuleMeta::AppendPortion(const std::shared_ptr& info) { void TGranuleMeta::AppendPortion(const TPortionDataAccessor& info) { AppendPortion(info.MutablePortionInfoPtr()); - DataAccessorsManager->AddPortion(info); + DataAccessorsManager->AddPortion(TabletId, info); } bool TGranuleMeta::ErasePortion(const ui64 portion) { @@ -42,7 +42,7 @@ bool TGranuleMeta::ErasePortion(const ui64 portion) { } else { AFL_TRACE(NKikimrServices::TX_COLUMNSHARD)("event", "portion_erased")("portion_info", it->second->DebugString())("pathId", PathId); } - DataAccessorsManager->RemovePortion(it->second); + DataAccessorsManager->RemovePortion(TabletId, it->second); OnBeforeChangePortion(it->second); Portions.erase(it); OnAfterChangePortion(nullptr, nullptr); @@ -136,6 +136,7 @@ const NKikimr::NOlap::TGranuleAdditiveSummary& TGranuleMeta::GetAdditiveSummary( TGranuleMeta::TGranuleMeta( const TInternalPathId pathId, const TGranulesStorage& owner, const NColumnShard::TGranuleDataCounters& counters, const TVersionedIndex& versionedIndex) : PathId(pathId) + , TabletId(owner.GetTabletId()) , DataAccessorsManager(owner.GetDataAccessorsManager()) , Counters(counters) , PortionInfoGuard(owner.GetCounters().BuildPortionBlobsGuard()) @@ -175,7 +176,7 @@ void TGranuleMeta::BuildActualizationTasks(NActualizer::TTieringProcessContext& void TGranuleMeta::ResetAccessorsManager(const std::shared_ptr& constructor, const NDataAccessorControl::TManagerConstructionContext& context) { MetadataMemoryManager = constructor->Build(context).DetachResult(); - DataAccessorsManager->RegisterController(MetadataMemoryManager->BuildCollector(PathId), context.IsUpdate()); + DataAccessorsManager->RegisterController(MetadataMemoryManager->BuildCollector(TabletId, PathId), TabletId, context.IsUpdate()); } void TGranuleMeta::ResetOptimizer(const std::shared_ptr& constructor, @@ -265,7 +266,7 @@ bool TGranuleMeta::TestingLoad(IDbWrapper& db, const TVersionedIndex& versionedI } for (auto&& [portionId, constructor] : constructors) { auto accessor = constructor.Build(false); - DataAccessorsManager->AddPortion(accessor); + DataAccessorsManager->AddPortion(TabletId, accessor); UpsertPortionOnLoad(accessor.MutablePortionInfoPtr()); } return true; @@ -274,7 +275,7 @@ bool TGranuleMeta::TestingLoad(IDbWrapper& db, const TVersionedIndex& versionedI void TGranuleMeta::InsertPortionOnComplete(const TPortionDataAccessor& portion, IColumnEngine& /*engine*/) { AFL_VERIFY(InsertedPortions.emplace(portion.GetPortionInfo().GetInsertWriteIdVerified(), portion.MutablePortionInfoPtr()).second); AFL_VERIFY(InsertedAccessors.emplace(portion.GetPortionInfo().GetInsertWriteIdVerified(), portion).second); - DataAccessorsManager->AddPortion(portion); + DataAccessorsManager->AddPortion(TabletId, portion); } void TGranuleMeta::InsertPortionOnExecute(NTabletFlatExecutor::TTransactionContext& txc, const TPortionDataAccessor& portion) const { diff --git a/ydb/core/tx/columnshard/engines/storage/granule/granule.h b/ydb/core/tx/columnshard/engines/storage/granule/granule.h index 0f2a02c135a3..6bc1ecba986a 100644 --- a/ydb/core/tx/columnshard/engines/storage/granule/granule.h +++ b/ydb/core/tx/columnshard/engines/storage/granule/granule.h @@ -127,6 +127,7 @@ class TGranuleMeta: TNonCopyable { mutable bool AllowInsertionFlag = false; const TInternalPathId PathId; + const TTabletId TabletId; std::shared_ptr DataAccessorsManager; const NColumnShard::TGranuleDataCounters Counters; NColumnShard::TEngineLogsCounters::TPortionsInfoGuard PortionInfoGuard; @@ -179,7 +180,7 @@ class TGranuleMeta: TNonCopyable { std::unique_ptr BuildDataAccessor() { AFL_VERIFY(!DataAccessorConstructed); DataAccessorConstructed = true; - return MetadataMemoryManager->BuildCollector(PathId); + return MetadataMemoryManager->BuildCollector(TabletId, PathId); } void RefreshTiering(const std::optional& tiering) { @@ -308,7 +309,7 @@ class TGranuleMeta: TNonCopyable { } request->RegisterSubscriber(std::make_shared()); - DataAccessorsManager->AskData(request); + DataAccessorsManager->AskData(TabletId, request); } if (ActualizationIndex->IsStarted()) { RefreshScheme(); diff --git a/ydb/core/tx/columnshard/engines/storage/granule/stages.cpp b/ydb/core/tx/columnshard/engines/storage/granule/stages.cpp index 18f321470e89..89dbc35499f9 100644 --- a/ydb/core/tx/columnshard/engines/storage/granule/stages.cpp +++ b/ydb/core/tx/columnshard/engines/storage/granule/stages.cpp @@ -54,14 +54,14 @@ bool TGranuleIndexesReader::DoPrecharge(NTabletFlatExecutor::TTransactionContext return db.Table().Prefix(Self->GetPathId().GetRawValue()).Select().IsReady(); } -bool TGranuleFinishAccessorsLoading::DoExecute(NTabletFlatExecutor::TTransactionContext& /*txc*/, const TActorContext& /*ctx*/) { +bool TGranuleFinishAccessorsLoading::DoExecute(NTabletFlatExecutor::TTransactionContext& txc, const TActorContext& /*ctx*/) { THashMap constructors = Context->ExtractConstructors(); AFL_VERIFY(Self->GetPortions().size() == constructors.size()); for (auto&& i : Self->GetPortions()) { auto it = constructors.find(i.first); AFL_VERIFY(it != constructors.end()); auto accessor = TPortionAccessorConstructor::BuildForLoading(i.second, std::move(it->second.MutableRecords()), std::move(it->second.MutableIndexes())); - Self->GetDataAccessorsManager()->AddPortion(accessor); + Self->GetDataAccessorsManager()->AddPortion((NOlap::TTabletId)txc.Tablet, accessor); } return true; } diff --git a/ydb/core/tx/columnshard/engines/storage/granule/storage.h b/ydb/core/tx/columnshard/engines/storage/granule/storage.h index b22f9f0c089e..49d0693a350e 100644 --- a/ydb/core/tx/columnshard/engines/storage/granule/storage.h +++ b/ydb/core/tx/columnshard/engines/storage/granule/storage.h @@ -97,6 +97,7 @@ class TGranulesStat { class TGranulesStorage { private: const NColumnShard::TEngineLogsCounters Counters; + const TTabletId TabletId; const std::shared_ptr DataAccessorsManager; std::shared_ptr StoragesManager; THashMap> Tables; // pathId into Granule that equal to Table @@ -121,17 +122,18 @@ class TGranulesStorage { TGranulesStorage(const NColumnShard::TEngineLogsCounters counters, const std::shared_ptr& dataAccessorsManager, - const std::shared_ptr& storagesManager) + const std::shared_ptr& storagesManager, + const TTabletId tabletId) : Counters(counters) + , TabletId(tabletId) , DataAccessorsManager(dataAccessorsManager) - , StoragesManager(storagesManager) - , Stats(std::make_shared(Counters)) { + , StoragesManager(storagesManager), Stats(std::make_shared(Counters)) { AFL_VERIFY(DataAccessorsManager); AFL_VERIFY(StoragesManager); } void FetchDataAccessors(const std::shared_ptr& request) const { - DataAccessorsManager->AskData(request); + DataAccessorsManager->AskData(TabletId, request); } const std::shared_ptr& GetStats() const { @@ -153,7 +155,7 @@ class TGranulesStorage { if (!it->second->IsErasable()) { return false; } - DataAccessorsManager->UnregisterController(pathId); + DataAccessorsManager->UnregisterController(TabletId, pathId); Tables.erase(it); return true; } @@ -214,6 +216,8 @@ class TGranulesStorage { return Counters; } + TTabletId GetTabletId() const { return TabletId;} + std::shared_ptr GetGranuleForCompaction(const std::shared_ptr& locksManager) const; std::optional GetCompactionPriority(const std::shared_ptr& locksManager, const std::set& pathIds = Default>(), const std::optional waitingPriority = std::nullopt, diff --git a/ydb/core/tx/columnshard/engines/storage/indexes/bloom_ngramm/meta.cpp b/ydb/core/tx/columnshard/engines/storage/indexes/bloom_ngramm/meta.cpp index f0d5443b89d7..e13c1086c548 100644 --- a/ydb/core/tx/columnshard/engines/storage/indexes/bloom_ngramm/meta.cpp +++ b/ydb/core/tx/columnshard/engines/storage/indexes/bloom_ngramm/meta.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace NKikimr::NOlap::NIndexes::NBloomNGramm { @@ -150,9 +151,9 @@ class TNGrammBuilder { (const ui8*)data, dataSize, HashesCount, nGrammSize, op, pred); } else { LowerStringBuffer.Clear(); - LowerStringBuffer.Reserve(dataSize); + LowerStringBuffer.Resize(dataSize); for (ui32 i = 0; i < dataSize; ++i) { - LowerStringBuffer.Append(std::tolower(data[i])); + LowerStringBuffer.Data()[i] = AsciiToLower(data[i]); } THashesSelector::BuildHashes( (const ui8*)LowerStringBuffer.Data(), dataSize, HashesCount, nGrammSize, op, pred); @@ -184,8 +185,7 @@ class TNGrammBuilder { } template - void FillNGrammHashes( - const ui32 nGrammSize, const NRequest::TLikePart::EOperation op, const TString& userReq, TFiller& fillData) { + void FillNGrammHashes(const ui32 nGrammSize, const NRequest::TLikePart::EOperation op, const TString& userReq, TFiller& fillData) { if (CaseSensitive) { BuildNGramms(userReq.data(), userReq.size(), op, nGrammSize, fillData); } else { diff --git a/ydb/core/tx/columnshard/engines/storage/optimizer/lbuckets/planner/optimizer.h b/ydb/core/tx/columnshard/engines/storage/optimizer/lbuckets/planner/optimizer.h index a5972524b302..0bb9984e8cf8 100644 --- a/ydb/core/tx/columnshard/engines/storage/optimizer/lbuckets/planner/optimizer.h +++ b/ydb/core/tx/columnshard/engines/storage/optimizer/lbuckets/planner/optimizer.h @@ -1246,8 +1246,8 @@ class TOptimizerPlanner: public IOptimizerPlanner { } virtual TOptimizationPriority DoGetUsefulMetric() const override { - if (Buckets.GetWeight()) { - return TOptimizationPriority::Critical(Buckets.GetWeight()); + if (const auto weight = Buckets.GetWeight()) { + return TOptimizationPriority::Critical(weight); } else { return TOptimizationPriority::Zero(); } diff --git a/ydb/core/tx/columnshard/engines/storage/optimizer/sbuckets/counters/counters.h b/ydb/core/tx/columnshard/engines/storage/optimizer/sbuckets/counters/counters.h index 0f04067f8ef4..8a309059eecf 100644 --- a/ydb/core/tx/columnshard/engines/storage/optimizer/sbuckets/counters/counters.h +++ b/ydb/core/tx/columnshard/engines/storage/optimizer/sbuckets/counters/counters.h @@ -1,6 +1,6 @@ #pragma once -#include -#include +#include +#include #include namespace NKikimr::NOlap::NStorageOptimizer::NSBuckets { diff --git a/ydb/core/tx/columnshard/engines/storage/optimizer/sbuckets/counters/ya.make b/ydb/core/tx/columnshard/engines/storage/optimizer/sbuckets/counters/ya.make index 7f45975900a7..762de70f968d 100644 --- a/ydb/core/tx/columnshard/engines/storage/optimizer/sbuckets/counters/ya.make +++ b/ydb/core/tx/columnshard/engines/storage/optimizer/sbuckets/counters/ya.make @@ -5,7 +5,7 @@ SRCS( ) PEERDIR( - ydb/core/tx/columnshard/counters/common + ydb/library/signals ydb/core/tx/columnshard/engines/portions ) diff --git a/ydb/core/tx/columnshard/engines/ut/ut_script.cpp b/ydb/core/tx/columnshard/engines/ut/ut_script.cpp index a50388e8bfb9..1ee5dd5091fa 100644 --- a/ydb/core/tx/columnshard/engines/ut/ut_script.cpp +++ b/ydb/core/tx/columnshard/engines/ut/ut_script.cpp @@ -26,26 +26,26 @@ Y_UNIT_TEST_SUITE(TestScript) { { 1, NTable::TColumn("c1", 0, NScheme::TTypeInfo(NScheme::NTypeIds::Int32), "") }, { 2, NTable::TColumn("c2", 0, NScheme::TTypeInfo(NScheme::NTypeIds::Int32), "") } })); - acc.AddFetchingStep(std::vector({ 0 }), NCommon::EStageFeaturesIndexes::Filter); - acc.AddFetchingStep(std::vector({ 0 }), NCommon::EStageFeaturesIndexes::Filter); - acc.AddAssembleStep(std::vector({ 0 }), "", NCommon::EStageFeaturesIndexes::Filter, false); + acc.AddFetchingStep(std::vector({ 0 }), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); + acc.AddFetchingStep(std::vector({ 0 }), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); + acc.AddAssembleStep(std::vector({ 0 }), "", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter, false); acc.AddStep(std::make_shared()); - acc.AddFetchingStep(std::vector({ 0, 1 }), NCommon::EStageFeaturesIndexes::Filter); - acc.AddFetchingStep(std::vector({ 1, 2 }), NCommon::EStageFeaturesIndexes::Fetching); - acc.AddFetchingStep(std::vector({ 0 }), NCommon::EStageFeaturesIndexes::Fetching); - acc.AddAssembleStep(std::vector({ 0, 1, 2 }), "", NCommon::EStageFeaturesIndexes::Fetching, false); + acc.AddFetchingStep(std::vector({ 0, 1 }), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Filter); + acc.AddFetchingStep(std::vector({ 1, 2 }), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching); + acc.AddFetchingStep(std::vector({ 0 }), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching); + acc.AddAssembleStep(std::vector({ 0, 1, 2 }), "", NArrow::NSSA::IMemoryCalculationPolicy::EStage::Fetching, false); acc.AddStep(std::make_shared()); - acc.AddFetchingStep(std::vector({ 0 }), NCommon::EStageFeaturesIndexes::Merge); + acc.AddFetchingStep(std::vector({ 0 }), NArrow::NSSA::IMemoryCalculationPolicy::EStage::Merge); auto script = std::move(acc).Build(); UNIT_ASSERT_STRINGS_EQUAL(script->DebugString(), "{branch:UNDEFINED;steps:[" - "{name=ALLOCATE_MEMORY::Filter;details={stage=Filter;column_ids=[Blob:0,Raw:0];};};" + "{name=ALLOCATE_MEMORY::FILTER;details={stage=FILTER;column_ids=[Blob:0,Raw:0];};};" "{name=FETCHING_COLUMNS;details={columns=0;};};" "{name=ASSEMBLER;details={columns=(column_ids=0;column_names=c0;);;};};" "{name=DELETION;details={};};" - "{name=ALLOCATE_MEMORY::Filter;details={stage=Filter;column_ids=[Blob:1];};};" - "{name=ALLOCATE_MEMORY::Fetching;details={stage=Fetching;column_ids=[Blob:2,Raw:1,Raw:2];};};" + "{name=ALLOCATE_MEMORY::FILTER;details={stage=FILTER;column_ids=[Blob:1];};};" + "{name=ALLOCATE_MEMORY::FETCHING;details={stage=FETCHING;column_ids=[Blob:2,Raw:1,Raw:2];};};" "{name=FETCHING_COLUMNS;details={columns=1,2;};};" "{name=ASSEMBLER;details={columns=(column_ids=1,2;column_names=c1,c2;);;};};" "{name=DELETION;details={};};]}"); diff --git a/ydb/core/tx/columnshard/engines/writer/indexed_blob_constructor.h b/ydb/core/tx/columnshard/engines/writer/indexed_blob_constructor.h index 8765968a0a00..1fcff6975285 100644 --- a/ydb/core/tx/columnshard/engines/writer/indexed_blob_constructor.h +++ b/ydb/core/tx/columnshard/engines/writer/indexed_blob_constructor.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/ydb/core/tx/columnshard/hooks/testing/ro_controller.h b/ydb/core/tx/columnshard/hooks/testing/ro_controller.h index cc7354f52b21..1487ad560507 100644 --- a/ydb/core/tx/columnshard/hooks/testing/ro_controller.h +++ b/ydb/core/tx/columnshard/hooks/testing/ro_controller.h @@ -4,6 +4,7 @@ #include #include #include +#include #include namespace NKikimr::NYDBTest::NColumnShard { @@ -108,7 +109,7 @@ class TReadOnlyController: public ICSController { } } - void WaitCleaning(const TDuration d) const { + void WaitCleaning(const TDuration d, NActors::TTestBasicRuntime* testRuntime = nullptr) const { TInstant start = TInstant::Now(); ui32 countStart = GetCleaningStartedCounter().Val(); while (Now() - start < d) { @@ -117,7 +118,11 @@ class TReadOnlyController: public ICSController { start = TInstant::Now(); } Cerr << "WAIT_CLEANING: " << GetCleaningStartedCounter().Val() << Endl; - Sleep(TDuration::Seconds(1)); + if (testRuntime) { + testRuntime->SimulateSleep(TDuration::Seconds(1)); + } else { + Sleep(TDuration::Seconds(1)); + } } } diff --git a/ydb/core/tx/columnshard/normalizer/portion/chunks.cpp b/ydb/core/tx/columnshard/normalizer/portion/chunks.cpp index 7cfdfcd21308..1d7e9656cd43 100644 --- a/ydb/core/tx/columnshard/normalizer/portion/chunks.cpp +++ b/ydb/core/tx/columnshard/normalizer/portion/chunks.cpp @@ -52,7 +52,7 @@ class TRowsAndBytesChangesTask: public NConveyor::ITask { TNormalizationContext NormContext; protected: - virtual TConclusionStatus DoExecute(const std::shared_ptr& /*taskPtr*/) override { + virtual void DoExecute(const std::shared_ptr& /*taskPtr*/) override { for (auto&& chunkInfo : Chunks) { const auto& blobRange = chunkInfo.GetBlobRange(); @@ -73,7 +73,6 @@ class TRowsAndBytesChangesTask: public NConveyor::ITask { auto changes = std::make_shared(std::move(Chunks)); TActorContext::AsActorContext().Send( NormContext.GetShardActor(), std::make_unique(changes)); - return TConclusionStatus::Success(); } public: diff --git a/ydb/core/tx/columnshard/operations/batch_builder/builder.cpp b/ydb/core/tx/columnshard/operations/batch_builder/builder.cpp index f5c44815990e..7f886c8be62e 100644 --- a/ydb/core/tx/columnshard/operations/batch_builder/builder.cpp +++ b/ydb/core/tx/columnshard/operations/batch_builder/builder.cpp @@ -21,19 +21,19 @@ void TBuildBatchesTask::ReplyError(const TString& message, const NColumnShard::T TActorContext::AsActorContext().Send(Context.GetTabletActorId(), result.release()); } -TConclusionStatus TBuildBatchesTask::DoExecute(const std::shared_ptr& /*taskPtr*/) { +void TBuildBatchesTask::DoExecute(const std::shared_ptr& /*taskPtr*/) { const NActors::TLogContextGuard lGuard = NActors::TLogContextBuilder::Build()("scope", "TBuildBatchesTask::DoExecute"); if (!Context.IsActive()) { AFL_WARN(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "abort_external"); ReplyError("writing aborted", NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass::Internal); - return TConclusionStatus::Fail("writing aborted"); + return; } TConclusion> batchConclusion = WriteData.GetData()->ExtractBatch(); if (batchConclusion.IsFail()) { AFL_WARN(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "abort_on_extract")("reason", batchConclusion.GetErrorMessage()); ReplyError("cannot extract incoming batch: " + batchConclusion.GetErrorMessage(), NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass::Internal); - return TConclusionStatus::Fail("cannot extract incoming batch: " + batchConclusion.GetErrorMessage()); + return; } Context.GetWritingCounters()->OnIncomingData(NArrow::GetBatchDataSize(*batchConclusion)); @@ -43,7 +43,7 @@ TConclusionStatus TBuildBatchesTask::DoExecute(const std::shared_ptr& /*t AFL_WARN(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "abort_on_prepare")("reason", preparedConclusion.GetErrorMessage()); ReplyError("cannot prepare incoming batch: " + preparedConclusion.GetErrorMessage(), NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass::Request); - return TConclusionStatus::Fail("cannot prepare incoming batch: " + preparedConclusion.GetErrorMessage()); + return; } auto batch = preparedConclusion.DetachResult(); std::shared_ptr merger; @@ -60,7 +60,7 @@ TConclusionStatus TBuildBatchesTask::DoExecute(const std::shared_ptr& /*t new NWritingPortions::TEvAddInsertedDataToBuffer( std::make_shared(WriteData), batch, std::make_shared(Context))); } - return TConclusionStatus::Success(); + return; } else { auto insertionConclusion = Context.GetActualSchema()->CheckColumnsDefault(defaultFields); auto conclusion = Context.GetActualSchema()->BuildDefaultBatch(Context.GetActualSchema()->GetIndexInfo().ArrowSchema(), 1, true); @@ -92,14 +92,12 @@ TConclusionStatus TBuildBatchesTask::DoExecute(const std::shared_ptr& /*t new NWritingPortions::TEvAddInsertedDataToBuffer( std::make_shared(WriteData), batch, std::make_shared(Context))); } - return TConclusionStatus::Success(); + return; } } std::shared_ptr task = std::make_shared(std::move(WriteData), merger, ActualSnapshot, batch, Context); NActors::TActivationContext::AsActorContext().Register(new NDataReader::TActor(task)); - - return TConclusionStatus::Success(); } } // namespace NKikimr::NOlap diff --git a/ydb/core/tx/columnshard/operations/batch_builder/builder.h b/ydb/core/tx/columnshard/operations/batch_builder/builder.h index 1ec9b1ae551f..50e156542972 100644 --- a/ydb/core/tx/columnshard/operations/batch_builder/builder.h +++ b/ydb/core/tx/columnshard/operations/batch_builder/builder.h @@ -17,7 +17,7 @@ class TBuildBatchesTask: public NConveyor::ITask, public NColumnShard::TMonitori void ReplyError(const TString& message, const NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass errorClass); protected: - virtual TConclusionStatus DoExecute(const std::shared_ptr& taskPtr) override; + virtual void DoExecute(const std::shared_ptr& taskPtr) override; public: virtual TString GetTaskClassIdentifier() const override { diff --git a/ydb/core/tx/columnshard/operations/events.h b/ydb/core/tx/columnshard/operations/events.h index 30328c0bfc49..bf0ac210c627 100644 --- a/ydb/core/tx/columnshard/operations/events.h +++ b/ydb/core/tx/columnshard/operations/events.h @@ -29,10 +29,36 @@ class TWriteResult { std::shared_ptr WriteMeta; YDB_READONLY(ui64, DataSize, 0); YDB_READONLY(bool, NoDataToWrite, false); + TString ErrorMessage; + std::optional IsInternalErrorFlag; std::shared_ptr PKBatch; ui32 RecordsCount; public: + TWriteResult& SetErrorMessage(const TString& value, const bool isInternal) { + AFL_VERIFY(!ErrorMessage); + IsInternalErrorFlag = isInternal; + ErrorMessage = value; + return *this; + } + + bool IsInternalError() const { + AFL_VERIFY_DEBUG(!!IsInternalErrorFlag); + if (!IsInternalErrorFlag) { + return true; + } + return *IsInternalErrorFlag; + } + + const TString& GetErrorMessage() const { + static TString undefinedMessage = "UNKNOWN_WRITE_RESULT_MESSAGE"; + AFL_VERIFY_DEBUG(!!ErrorMessage); + if (!ErrorMessage) { + return undefinedMessage; + } + return ErrorMessage; + } + const std::shared_ptr& GetPKBatchVerified() const { AFL_VERIFY(PKBatch); return PKBatch; @@ -91,11 +117,16 @@ namespace NKikimr::NColumnShard::NPrivateEvents::NWrite { class TEvWritePortionResult: public TEventLocal { private: YDB_READONLY_DEF(NKikimrProto::EReplyStatus, WriteStatus); - YDB_READONLY_DEF(std::shared_ptr, WriteAction); + std::optional> WriteAction; bool Detached = false; TInsertedPortions InsertedData; public: + const std::shared_ptr& GetWriteAction() const { + AFL_VERIFY(!!WriteAction); + return *WriteAction; + } + const TInsertedPortions& DetachInsertedData() { AFL_VERIFY(!Detached); Detached = true; diff --git a/ydb/core/tx/columnshard/operations/slice_builder/builder.cpp b/ydb/core/tx/columnshard/operations/slice_builder/builder.cpp index 866720bb1a65..fb79e54284b4 100644 --- a/ydb/core/tx/columnshard/operations/slice_builder/builder.cpp +++ b/ydb/core/tx/columnshard/operations/slice_builder/builder.cpp @@ -99,19 +99,19 @@ class TPortionWriteController: public NColumnShard::IWriteController, } }; -TConclusionStatus TBuildSlicesTask::DoExecute(const std::shared_ptr& /*taskPtr*/) { +void TBuildSlicesTask::DoExecute(const std::shared_ptr& /*taskPtr*/) { const NActors::TLogContextGuard g = NActors::TLogContextBuilder::Build(NKikimrServices::TX_COLUMNSHARD_WRITE)("tablet_id", TabletId)( "parent_id", Context.GetTabletActorId())("write_id", WriteData.GetWriteMeta().GetWriteId())( "table_id", WriteData.GetWriteMeta().GetTableId()); if (!Context.IsActive()) { AFL_WARN(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "abort_execution"); ReplyError("execution aborted", NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass::Internal); - return TConclusionStatus::Fail("execution aborted"); + return; } if (!OriginalBatch) { AFL_WARN(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "ev_write_bad_data"); ReplyError("no data in batch", NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass::Internal); - return TConclusionStatus::Fail("no data in batch"); + return; } if (WriteData.GetWritePortions()) { if (OriginalBatch->num_rows() == 0) { @@ -136,7 +136,7 @@ TConclusionStatus TBuildSlicesTask::DoExecute(const std::shared_ptr& /*ta WriteData.GetWriteMeta().GetModificationType(), Context.GetStoragesManager(), Context.GetSplitterCounters()); if (portionConclusion.IsFail()) { ReplyError(portionConclusion.GetErrorMessage(), NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass::Request); - return portionConclusion; + return; } portions.emplace_back(portionConclusion.DetachResult()); } @@ -157,7 +157,7 @@ TConclusionStatus TBuildSlicesTask::DoExecute(const std::shared_ptr& /*ta "problem", subsetConclusion.GetErrorMessage()); ReplyError("unadaptable schema: " + subsetConclusion.GetErrorMessage(), NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass::Internal); - return TConclusionStatus::Fail("cannot reorder schema: " + subsetConclusion.GetErrorMessage()); + return; } NArrow::TSchemaSubset subset = subsetConclusion.DetachResult(); @@ -186,9 +186,8 @@ TConclusionStatus TBuildSlicesTask::DoExecute(const std::shared_ptr& /*ta TActorContext::AsActorContext().Send(Context.GetBufferizationInsertionActorId(), result.release()); } else { ReplyError("Cannot slice input to batches", NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass::Internal); - return TConclusionStatus::Fail("Cannot slice input to batches"); + return; } } - return TConclusionStatus::Success(); } } // namespace NKikimr::NOlap diff --git a/ydb/core/tx/columnshard/operations/slice_builder/builder.h b/ydb/core/tx/columnshard/operations/slice_builder/builder.h index 0efd53378e3f..5d6bb4159777 100644 --- a/ydb/core/tx/columnshard/operations/slice_builder/builder.h +++ b/ydb/core/tx/columnshard/operations/slice_builder/builder.h @@ -18,7 +18,7 @@ class TBuildSlicesTask: public NConveyor::ITask, public NColumnShard::TMonitorin void ReplyError(const TString& message, const NColumnShard::TEvPrivate::TEvWriteBlobsResult::EErrorClass errorClass); protected: - virtual TConclusionStatus DoExecute(const std::shared_ptr& taskPtr) override; + virtual void DoExecute(const std::shared_ptr& taskPtr) override; public: virtual TString GetTaskClassIdentifier() const override { diff --git a/ydb/core/tx/columnshard/operations/slice_builder/pack_builder.cpp b/ydb/core/tx/columnshard/operations/slice_builder/pack_builder.cpp index d3bc168d9b7d..9b9b0e351b5b 100644 --- a/ydb/core/tx/columnshard/operations/slice_builder/pack_builder.cpp +++ b/ydb/core/tx/columnshard/operations/slice_builder/pack_builder.cpp @@ -44,6 +44,11 @@ class TPortionWriteController: public NColumnShard::IWriteController, for (auto&& i : Portions) { portions.emplace_back(i.ExtractPortion()); } + if (putResult->GetPutStatus() != NKikimrProto::OK) { + for (auto&& i : WriteResults) { + i.SetErrorMessage("cannot put blobs: " + ::ToString(putResult->GetPutStatus()), true); + } + } NColumnShard::TInsertedPortions pack(std::move(WriteResults), std::move(portions)); auto result = std::make_unique(putResult->GetPutStatus(), Action, std::move(pack)); @@ -97,6 +102,10 @@ class TSliceToMerge { if (Batches.size() == 1) { auto portionConclusion = context.GetActualSchema()->PrepareForWrite(context.GetActualSchema(), PathId, Batches.front().GetContainer(), ModificationType, context.GetStoragesManager(), context.GetSplitterCounters()); + if (portionConclusion.IsFail()) { + AFL_ERROR(NKikimrServices::TX_COLUMNSHARD)("event", "cannot prepare for write")("reason", portionConclusion.GetErrorMessage()); + return portionConclusion; + } result.emplace_back(portionConclusion.DetachResult()); } else { ui32 idx = 0; @@ -120,6 +129,8 @@ class TSliceToMerge { if (itBatchIndexes == i.GetColumnIndexes().end() || *itAllIndexes < *itBatchIndexes) { auto defaultColumn = indexInfo.BuildDefaultColumn(*itAllIndexes, i->num_rows(), false); if (defaultColumn.IsFail()) { + AFL_ERROR(NKikimrServices::TX_COLUMNSHARD)("event", "cannot build default column")( + "reason", defaultColumn.GetErrorMessage()); return defaultColumn; } gContainer->AddField(context.GetActualSchema()->GetFieldByIndexVerified(*itAllIndexes), defaultColumn.DetachResult()) @@ -155,19 +166,19 @@ class TSliceToMerge { stream.DrainAll(rbBuilder); auto portionConclusion = context.GetActualSchema()->PrepareForWrite(context.GetActualSchema(), PathId, rbBuilder.Finalize(), ModificationType, context.GetStoragesManager(), context.GetSplitterCounters()); + if (portionConclusion.IsFail()) { + AFL_ERROR(NKikimrServices::TX_COLUMNSHARD)("event", "cannot prepare for write")("reason", portionConclusion.GetErrorMessage()); + return portionConclusion; + } result.emplace_back(portionConclusion.DetachResult()); } return TConclusionStatus::Success(); } }; -TConclusionStatus TBuildPackSlicesTask::DoExecute(const std::shared_ptr& /*taskPtr*/) { +void TBuildPackSlicesTask::DoExecute(const std::shared_ptr& /*taskPtr*/) { const NActors::TLogContextGuard g = NActors::TLogContextBuilder::Build(NKikimrServices::TX_COLUMNSHARD_WRITE)("tablet_id", TabletId)( "parent_id", Context.GetTabletActorId())("path_id", PathId); - if (!Context.IsActive()) { - AFL_WARN(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "abort_execution"); - return TConclusionStatus::Fail("execution aborted"); - } NArrow::NMerger::TIntervalPositions splitPositions; for (auto&& unit : WriteUnits) { splitPositions.Merge(unit.GetData()->GetData()->GetSeparationPoints()); @@ -195,21 +206,39 @@ TConclusionStatus TBuildPackSlicesTask::DoExecute(const std::shared_ptr& } } std::vector portionsToWrite; - for (auto&& i : slicesToMerge) { - auto conclusion = i.Finalize(Context, portionsToWrite); - if (conclusion.IsFail()) { - return conclusion; + TString cancelWritingReason; + if (!Context.IsActive()) { + AFL_WARN(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "abort_execution"); + cancelWritingReason = "execution aborted"; + } else { + for (auto&& i : slicesToMerge) { + auto conclusion = i.Finalize(Context, portionsToWrite); + if (conclusion.IsFail()) { + AFL_ERROR(NKikimrServices::TX_COLUMNSHARD)("event", "cannot build slice")("reason", conclusion.GetErrorMessage()); + cancelWritingReason = conclusion.GetErrorMessage(); + break; + } } } - auto actions = WriteUnits.front().GetData()->GetBlobsAction(); - auto writeController = - std::make_shared(Context.GetTabletActorId(), actions, std::move(writeResults), std::move(portionsToWrite)); - if (actions->NeedDraftTransaction()) { - TActorContext::AsActorContext().Send( - Context.GetTabletActorId(), std::make_unique(writeController)); + if (!cancelWritingReason) { + auto actions = WriteUnits.front().GetData()->GetBlobsAction(); + auto writeController = + std::make_shared(Context.GetTabletActorId(), actions, std::move(writeResults), std::move(portionsToWrite)); + if (actions->NeedDraftTransaction()) { + TActorContext::AsActorContext().Send( + Context.GetTabletActorId(), std::make_unique(writeController)); + } else { + TActorContext::AsActorContext().Register(NColumnShard::CreateWriteActor(TabletId, writeController, TInstant::Max())); + } } else { - TActorContext::AsActorContext().Register(NColumnShard::CreateWriteActor(TabletId, writeController, TInstant::Max())); + for (auto&& i : writeResults) { + i.SetErrorMessage(cancelWritingReason, false); + } + NColumnShard::TInsertedPortions pack(std::move(writeResults), std::vector()); + auto result = + std::make_unique(NKikimrProto::EReplyStatus::ERROR, nullptr, std::move(pack)); + TActorContext::AsActorContext().Send(Context.GetTabletActorId(), result.release()); + } - return TConclusionStatus::Success(); } } // namespace NKikimr::NOlap::NWritingPortions diff --git a/ydb/core/tx/columnshard/operations/slice_builder/pack_builder.h b/ydb/core/tx/columnshard/operations/slice_builder/pack_builder.h index f8f46e35ba6d..cbcc954630db 100644 --- a/ydb/core/tx/columnshard/operations/slice_builder/pack_builder.h +++ b/ydb/core/tx/columnshard/operations/slice_builder/pack_builder.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include +#include #include #include #include @@ -35,7 +35,7 @@ class TBuildPackSlicesTask: public NConveyor::ITask, public NColumnShard::TMonit std::optional> BuildSlices(); protected: - virtual TConclusionStatus DoExecute(const std::shared_ptr& taskPtr) override; + virtual void DoExecute(const std::shared_ptr& taskPtr) override; public: virtual TString GetTaskClassIdentifier() const override { diff --git a/ydb/core/tx/columnshard/operations/write.h b/ydb/core/tx/columnshard/operations/write.h index 735a8aa93b0d..97800d78dc8a 100644 --- a/ydb/core/tx/columnshard/operations/write.h +++ b/ydb/core/tx/columnshard/operations/write.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/ydb/core/tx/columnshard/resource_subscriber/counters.h b/ydb/core/tx/columnshard/resource_subscriber/counters.h index 230222f8ffa3..5495f9cf2327 100644 --- a/ydb/core/tx/columnshard/resource_subscriber/counters.h +++ b/ydb/core/tx/columnshard/resource_subscriber/counters.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include namespace NKikimr::NOlap::NResourceBroker::NSubscribe { diff --git a/ydb/core/tx/columnshard/resource_subscriber/task.h b/ydb/core/tx/columnshard/resource_subscriber/task.h index 46a1ebebd32c..a065c8946691 100644 --- a/ydb/core/tx/columnshard/resource_subscriber/task.h +++ b/ydb/core/tx/columnshard/resource_subscriber/task.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include "counters.h" namespace NKikimr::NOlap::NResourceBroker::NSubscribe { diff --git a/ydb/core/tx/columnshard/resources/memory.h b/ydb/core/tx/columnshard/resources/memory.h index 3f0683d38dec..388caf15a6ae 100644 --- a/ydb/core/tx/columnshard/resources/memory.h +++ b/ydb/core/tx/columnshard/resources/memory.h @@ -1,6 +1,6 @@ #pragma once -#include -#include +#include +#include #include #include #include diff --git a/ydb/core/tx/columnshard/tables_manager.cpp b/ydb/core/tx/columnshard/tables_manager.cpp index 80caaec1aab4..752c9c8bf48c 100644 --- a/ydb/core/tx/columnshard/tables_manager.cpp +++ b/ydb/core/tx/columnshard/tables_manager.cpp @@ -54,11 +54,7 @@ bool TTablesManager::InitFromDB(NIceDb::TNiceDb& db) { } while (!rowset.EndOfSet()) { - TTableInfo table; - if (!table.InitFromDB(rowset)) { - timer.AddLoadingFail(); - return false; - } + TTableInfo table = table.InitFromDB(rowset); if (table.IsDropped()) { AFL_VERIFY(PathsToDrop[table.GetDropVersionVerified()].emplace(table.GetPathId()).second); } @@ -114,13 +110,13 @@ bool TTablesManager::InitFromDB(NIceDb::TNiceDb& db) { while (!rowset.EndOfSet()) { const auto pathId = TInternalPathId::FromRawValue(rowset.GetValue()); - Y_ABORT_UNLESS(Tables.contains(pathId)); + const auto table = Tables.FindPtr(pathId); + AFL_VERIFY(table); NOlap::TSnapshot version( rowset.GetValue(), rowset.GetValue()); - auto& table = Tables[pathId]; NKikimrTxColumnShard::TTableVersionInfo versionInfo; - Y_ABORT_UNLESS(versionInfo.ParseFromString(rowset.GetValue())); + AFL_VERIFY(versionInfo.ParseFromString(rowset.GetValue())); AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD)("event", "load_table_version")("path_id", pathId)("snapshot", version); AFL_VERIFY(preset); AFL_VERIFY(preset->Id == versionInfo.GetSchemaPresetId())("preset", preset->Id)("table", versionInfo.GetSchemaPresetId()); @@ -128,7 +124,7 @@ bool TTablesManager::InitFromDB(NIceDb::TNiceDb& db) { if (versionInfo.HasTtlSettings()) { Ttl.AddVersionFromProto(pathId, version, versionInfo.GetTtlSettings()); } - table.AddVersion(version); + table->AddVersion(version); if (!rowset.Next()) { timer.AddLoadingFail(); return false; @@ -223,9 +219,9 @@ ui64 TTablesManager::GetMemoryUsage() const { } void TTablesManager::DropTable(const TInternalPathId pathId, const NOlap::TSnapshot& version, NIceDb::TNiceDb& db) { - AFL_VERIFY(Tables.contains(pathId)); - auto& table = Tables[pathId]; - table.SetDropVersion(version); + auto* table = Tables.FindPtr(pathId); + AFL_VERIFY(table); + table->SetDropVersion(version); AFL_VERIFY(PathsToDrop[version].emplace(pathId).second); Schema::SaveTableDropVersion(db, pathId, version.GetPlanStep(), version.GetTxId()); } diff --git a/ydb/core/tx/columnshard/tables_manager.h b/ydb/core/tx/columnshard/tables_manager.h index c7b489c14183..bda8b9813356 100644 --- a/ydb/core/tx/columnshard/tables_manager.h +++ b/ydb/core/tx/columnshard/tables_manager.h @@ -93,8 +93,7 @@ class TSchemaPreset: public TVersionedSchema DropVersion; YDB_READONLY_DEF(TSet, Versions); @@ -131,20 +130,19 @@ class TTableInfo { return *DropVersion < *minReadSnapshot; } - TTableInfo() = default; - TTableInfo(const TInternalPathId pathId) : PathId(pathId) { } template - bool InitFromDB(const TRow& rowset) { - PathId = TInternalPathId::FromRawValue(rowset.template GetValue()); + static TTableInfo InitFromDB(const TRow& rowset) { + const auto pathId = TInternalPathId::FromRawValue(rowset.template GetValue()); + TTableInfo result(pathId); if (rowset.template HaveValue() && rowset.template HaveValue()) { - DropVersion.emplace( + result.DropVersion.emplace( rowset.template GetValue(), rowset.template GetValue()); } - return true; + return result; } }; diff --git a/ydb/core/tx/columnshard/tablet/write_queue.cpp b/ydb/core/tx/columnshard/tablet/write_queue.cpp index 41291f1d6f08..75726189c77e 100644 --- a/ydb/core/tx/columnshard/tablet/write_queue.cpp +++ b/ydb/core/tx/columnshard/tablet/write_queue.cpp @@ -7,12 +7,6 @@ namespace NKikimr::NColumnShard { bool TWriteTask::Execute(TColumnShard* owner, const TActorContext& /* ctx */) { - auto overloadStatus = owner->CheckOverloadedWait(PathId); - if (overloadStatus != TColumnShard::EOverloadStatus::None) { - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "wait_overload")("status", overloadStatus); - return false; - } - owner->Counters.GetCSCounters().WritingCounters->OnWritingTaskDequeue(TMonotonic::Now() - Created); owner->OperationsManager->RegisterLock(LockId, owner->Generation()); auto writeOperation = owner->OperationsManager->RegisterOperation( @@ -37,21 +31,39 @@ bool TWriteTasksQueue::Drain(const bool onWakeup, const TActorContext& ctx) { if (onWakeup) { WriteTasksOverloadCheckerScheduled = false; } - while (WriteTasks.size() && WriteTasks.front().Execute(Owner, ctx)) { - WriteTasks.pop_front(); + std::vector toRemove; + ui32 countTasks = 0; + for (auto&& i : WriteTasks) { + auto overloadStatus = Owner->CheckOverloadedWait(i.first); + if (overloadStatus != TColumnShard::EOverloadStatus::None) { + countTasks += i.second.size(); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "wait_overload")("status", overloadStatus)("path_id", i.first)( + "size", i.second.size()); + continue; + } + for (auto&& t : i.second) { + t.Execute(Owner, ctx); + } + toRemove.emplace_back(i.first); } - if (WriteTasks.size() && !WriteTasksOverloadCheckerScheduled) { + + for (auto&& i : toRemove) { + AFL_VERIFY(WriteTasks.erase(i)); + } + + if (countTasks && !WriteTasksOverloadCheckerScheduled) { Owner->Schedule(TDuration::MilliSeconds(300), new NActors::TEvents::TEvWakeup(1)); WriteTasksOverloadCheckerScheduled = true; - AFL_WARN(NKikimrServices::TX_COLUMNSHARD)("event", "queue_on_write")("size", WriteTasks.size()); + AFL_WARN(NKikimrServices::TX_COLUMNSHARD)("event", "queue_on_write")("size", countTasks); } - Owner->Counters.GetCSCounters().WritingCounters->QueueWaitSize->Add((i64)WriteTasks.size() - PredWriteTasksSize); - PredWriteTasksSize = (i64)WriteTasks.size(); - return !WriteTasks.size(); + Owner->Counters.GetCSCounters().WritingCounters->QueueWaitSize->Add((i64)countTasks - PredWriteTasksSize); + PredWriteTasksSize = (i64)countTasks; + return !countTasks; } void TWriteTasksQueue::Enqueue(TWriteTask&& task) { - WriteTasks.emplace_back(std::move(task)); + const TInternalPathId pathId = task.GetPathId(); + WriteTasks[pathId].emplace_back(std::move(task)); } TWriteTasksQueue::~TWriteTasksQueue() { diff --git a/ydb/core/tx/columnshard/tablet/write_queue.h b/ydb/core/tx/columnshard/tablet/write_queue.h index 4e0c63363b1d..aba35e5a6a20 100644 --- a/ydb/core/tx/columnshard/tablet/write_queue.h +++ b/ydb/core/tx/columnshard/tablet/write_queue.h @@ -35,6 +35,10 @@ class TWriteTask: TMoveOnly { , Behaviour(behaviour) { } + const TInternalPathId& GetPathId() const { + return PathId; + } + const TMonotonic& GetCreatedMonotonic() const { return Created; } @@ -45,7 +49,7 @@ class TWriteTask: TMoveOnly { class TWriteTasksQueue { private: bool WriteTasksOverloadCheckerScheduled = false; - std::deque WriteTasks; + THashMap> WriteTasks; i64 PredWriteTasksSize = 0; TColumnShard* Owner; diff --git a/ydb/core/tx/columnshard/test_helper/columnshard_ut_common.cpp b/ydb/core/tx/columnshard/test_helper/columnshard_ut_common.cpp index 833a430a4feb..9e2b466469a7 100644 --- a/ydb/core/tx/columnshard/test_helper/columnshard_ut_common.cpp +++ b/ydb/core/tx/columnshard/test_helper/columnshard_ut_common.cpp @@ -54,16 +54,34 @@ void RefreshTiering(TTestBasicRuntime& runtime, const TActorId& sender) { ForwardToTablet(runtime, TTestTxConfig::TxTablet0, sender, event.release()); } -bool ProposeSchemaTx(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, NOlap::TSnapshot snap) { +namespace { +std::optional ProposeSchemaTxOptional(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, const ui64 txId) { auto event = std::make_unique( - NKikimrTxColumnShard::TX_KIND_SCHEMA, 0, sender, snap.GetTxId(), txBody, 0, 0); - + NKikimrTxColumnShard::TX_KIND_SCHEMA, 0, sender, txId, txBody, 0, 0); + const auto now = runtime.GetTimeProvider()->Now(); ForwardToTablet(runtime, TTestTxConfig::TxTablet0, sender, event.release()); auto ev = runtime.GrabEdgeEvent(sender); const auto& res = ev->Get()->Record; - UNIT_ASSERT_EQUAL(res.GetTxId(), snap.GetTxId()); + UNIT_ASSERT_EQUAL(res.GetTxId(), txId); UNIT_ASSERT_EQUAL(res.GetTxKind(), NKikimrTxColumnShard::TX_KIND_SCHEMA); - return (res.GetStatus() == NKikimrTxColumnShard::PREPARED); + if (res.GetStatus() == NKikimrTxColumnShard::PREPARED) { + UNIT_ASSERT_LE(now.MilliSeconds(), res.GetMinStep()); + UNIT_ASSERT_EQUAL(res.GetMaxStep(), std::numeric_limits::max()); + return {TPlanStep(res.GetMinStep())}; + } + return std::nullopt; +} +} //namespace + +void ProposeSchemaTxFail(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, const ui64 txId) { + const auto result = ProposeSchemaTxOptional(runtime, sender, txBody, txId); + AFL_VERIFY(!result); +} + +TPlanStep ProposeSchemaTx(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, const ui64 txId) { + const auto result = ProposeSchemaTxOptional(runtime, sender, txBody, txId); + AFL_VERIFY(result); + return *result; } void PlanSchemaTx(TTestBasicRuntime& runtime, const TActorId& sender, NOlap::TSnapshot snap) { @@ -208,7 +226,7 @@ void ScanIndexStats(TTestBasicRuntime& runtime, TActorId& sender, const std::vec } template -void ProposeCommitCheck(TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, ui64 txId, const std::vector& /* writeIds */, const ui64 lockId, Checker&& checker) { +TPlanStep ProposeCommitCheck(TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, ui64 txId, const std::vector& /* writeIds */, const ui64 lockId, Checker&& checker) { auto write = std::make_unique(txId, NKikimrDataEvents::TEvWrite::MODE_PREPARE); auto* lock = write->Record.MutableLocks()->AddLocks(); lock->SetLockId(lockId); @@ -221,31 +239,37 @@ void ProposeCommitCheck(TTestBasicRuntime& runtime, TActorId& sender, ui64 shard auto& res = event->Record; checker(res); + return TPlanStep(res.GetMinStep()); } -void ProposeCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, ui64 txId, const std::vector& writeIds, const ui64 lockId) { - ProposeCommitCheck(runtime, sender, shardId, txId, writeIds, lockId, [&](auto& res) { +TPlanStep ProposeCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, ui64 txId, const std::vector& writeIds, const ui64 lockId) { + const auto now = runtime.GetTimeProvider()->Now(); + return ProposeCommitCheck(runtime, sender, shardId, txId, writeIds, lockId, [&](auto& res) { AFL_VERIFY(res.GetTxId() == txId)("tx_id", txId)("res", res.GetTxId()); UNIT_ASSERT_EQUAL(res.GetStatus(), NKikimrDataEvents::TEvWriteResult::STATUS_PREPARED); + UNIT_ASSERT_LE(now.MilliSeconds(), res.GetMinStep()); + UNIT_ASSERT_UNEQUAL(res.GetMaxStep(), std::numeric_limits::max()); + UNIT_ASSERT_LE(res.GetMinStep(), res.GetMaxStep()); }); } void ProposeCommitFail(TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, ui64 txId, const std::vector& writeIds, const ui64 lockId) { - ProposeCommitCheck(runtime, sender, shardId, txId, writeIds, lockId, [&](auto& res) { + const auto result = ProposeCommitCheck(runtime, sender, shardId, txId, writeIds, lockId, [&](auto& res) { UNIT_ASSERT_UNEQUAL(res.GetStatus(), NKikimrDataEvents::TEvWriteResult::STATUS_PREPARED); }); + Y_UNUSED(result); } -void ProposeCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 txId, const std::vector& writeIds, const ui64 lockId) { - ProposeCommit(runtime, sender, TTestTxConfig::TxTablet0, txId, writeIds, lockId); +TPlanStep ProposeCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 txId, const std::vector& writeIds, const ui64 lockId) { + return ProposeCommit(runtime, sender, TTestTxConfig::TxTablet0, txId, writeIds, lockId); } -void ProposeCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 txId, const std::vector& writeIds) { - ProposeCommit(runtime, sender, TTestTxConfig::TxTablet0, txId, writeIds); +TPlanStep ProposeCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 txId, const std::vector& writeIds) { + return ProposeCommit(runtime, sender, TTestTxConfig::TxTablet0, txId, writeIds); } -void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 planStep, const TSet& txIds) { +void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, TPlanStep planStep, const TSet& txIds) { PlanCommit(runtime, sender, TTestTxConfig::TxTablet0, planStep, txIds); } @@ -254,8 +278,8 @@ void Wakeup(TTestBasicRuntime& runtime, const TActorId& sender, const ui64 shard ForwardToTablet(runtime, shardId, sender, wakeup.release()); } -void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, ui64 planStep, const TSet& txIds) { - auto plan = std::make_unique(planStep, 0, shardId); +void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, TPlanStep planStep, const TSet& txIds) { + auto plan = std::make_unique(planStep.Val(), 0, shardId); for (ui64 txId : txIds) { auto tx = plan->Record.AddTransactions(); tx->SetTxId(txId); @@ -466,7 +490,7 @@ namespace NKikimr::NColumnShard { return NOlap::TIndexInfo::BuildDefault(NOlap::TTestStoragesManager::GetInstance(), columns, pkIds); } - void SetupSchema(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, const NOlap::TSnapshot& snapshot, bool succeed) { + NTxUT::TPlanStep SetupSchema(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, const ui64 txId) { auto controller = NYDBTest::TControllers::GetControllerAs(); while (controller && !controller->IsActiveTablet(TTestTxConfig::TxTablet0)) { @@ -474,17 +498,15 @@ namespace NKikimr::NColumnShard { } using namespace NTxUT; - bool ok = ProposeSchemaTx(runtime, sender, txBody, snapshot); - UNIT_ASSERT_VALUES_EQUAL(ok, succeed); - if (succeed) { - PlanSchemaTx(runtime, sender, snapshot); - } + const auto planStep = ProposeSchemaTx(runtime, sender, txBody, txId); + PlanSchemaTx(runtime, sender, NOlap::TSnapshot(planStep, txId)); + return planStep; } - void SetupSchema(TTestBasicRuntime& runtime, TActorId& sender, ui64 pathId, + NTxUT::TPlanStep SetupSchema(TTestBasicRuntime& runtime, TActorId& sender, ui64 pathId, const TestTableDescription& table, TString codec) { using namespace NTxUT; - NOlap::TSnapshot snapshot(10, 10); + const ui64 txId = 10; TString txBody; auto specials = TTestSchema::TTableSpecials().WithCodec(codec); if (table.InStore) { @@ -492,11 +514,11 @@ namespace NKikimr::NColumnShard { } else { txBody = TTestSchema::CreateStandaloneTableTxBody(pathId, table.Schema, table.Pk, specials); } - SetupSchema(runtime, sender, txBody, snapshot, true); + return SetupSchema(runtime, sender, txBody, txId); } - void PrepareTablet(TTestBasicRuntime& runtime, const ui64 tableId, const std::vector& schema, const ui32 keySize) { + NTxUT::TPlanStep PrepareTablet(TTestBasicRuntime& runtime, const ui64 tableId, const std::vector& schema, const ui32 keySize) { using namespace NTxUT; CreateTestBootstrapper(runtime, CreateTestTabletInfo(TTestTxConfig::TxTablet0, TTabletTypes::ColumnShard), &CreateColumnShard); @@ -512,10 +534,10 @@ namespace NKikimr::NColumnShard { tableDescription.Pk.push_back(schema[i]); } TActorId sender = runtime.AllocateEdgeActor(); - SetupSchema(runtime, sender, tableId, tableDescription); + return SetupSchema(runtime, sender, tableId, tableDescription); } - void PrepareTablet(TTestBasicRuntime& runtime, const TString& schemaTxBody, bool succeed) { + NTxUT::TPlanStep PrepareTablet(TTestBasicRuntime& runtime, const TString& schemaTxBody) { using namespace NTxUT; CreateTestBootstrapper(runtime, CreateTestTabletInfo(TTestTxConfig::TxTablet0, TTabletTypes::ColumnShard), &CreateColumnShard); @@ -524,7 +546,7 @@ namespace NKikimr::NColumnShard { runtime.DispatchEvents(options); TActorId sender = runtime.AllocateEdgeActor(); - SetupSchema(runtime, sender, schemaTxBody, NOlap::TSnapshot(1000, 100), succeed); + return SetupSchema(runtime, sender, schemaTxBody, 100); } std::shared_ptr ReadAllAsBatch(TTestBasicRuntime& runtime, const ui64 tableId, const NOlap::TSnapshot& snapshot, const std::vector& schema) { diff --git a/ydb/core/tx/columnshard/test_helper/columnshard_ut_common.h b/ydb/core/tx/columnshard/test_helper/columnshard_ut_common.h index a844f3f80114..0442307e6508 100644 --- a/ydb/core/tx/columnshard/test_helper/columnshard_ut_common.h +++ b/ydb/core/tx/columnshard/test_helper/columnshard_ut_common.h @@ -25,6 +25,8 @@ struct TIndexInfo; namespace NKikimr::NTxUT { +using TPlanStep = TPositiveIncreasingControlInteger; + // Private events of different actors reuse the same ES_PRIVATE range // So in order to capture the right private event we need to check its type via dynamic_cast template @@ -47,7 +49,7 @@ using TTypeId = NScheme::TTypeId; using TTypeInfo = NScheme::TTypeInfo; struct TTestSchema { - static inline const TString DefaultTtlColumn = "saved_at"; + static inline const TString DefaultTtlColumn = "timestamp"; struct TStorageTier { TString TtlColumn = DefaultTtlColumn; @@ -395,7 +397,8 @@ struct TTestSchema { void RefreshTiering(TTestBasicRuntime& runtime, const TActorId& sender); -bool ProposeSchemaTx(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, NOlap::TSnapshot snap); +void ProposeSchemaTxFail(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, const ui64 txId); +[[nodiscard]] TPlanStep ProposeSchemaTx(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, const ui64 txId); void PlanSchemaTx(TTestBasicRuntime& runtime, const TActorId& sender, NOlap::TSnapshot snap); void PlanWriteTx(TTestBasicRuntime& runtime, const TActorId& sender, NOlap::TSnapshot snap, bool waitResult = true); @@ -418,14 +421,14 @@ void ScanIndexStats(TTestBasicRuntime& runtime, TActorId& sender, const std::vec void ProposeCommitFail( TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, ui64 txId, const std::vector& writeIds, const ui64 lockId = 1); -void ProposeCommit( +[[nodiscard]] TPlanStep ProposeCommit( TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, ui64 txId, const std::vector& writeIds, const ui64 lockId = 1); -void ProposeCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 txId, const std::vector& writeIds, const ui64 lockId = 1); +[[nodiscard]] TPlanStep ProposeCommit(TTestBasicRuntime& runtime, TActorId& sender, const ui64 txId, const std::vector& writeIds, const ui64 lockId = 1); -void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, ui64 planStep, const TSet& txIds); -void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 planStep, const TSet& txIds); +void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 shardId, TPlanStep planStep, const TSet& txIds); +void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, TPlanStep planStep, const TSet& txIds); -inline void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, ui64 planStep, ui64 txId) { +inline void PlanCommit(TTestBasicRuntime& runtime, TActorId& sender, TPlanStep planStep, ui64 txId) { TSet ids; ids.insert(txId); PlanCommit(runtime, sender, planStep, ids); @@ -557,12 +560,11 @@ struct TestTableDescription { } }; -void SetupSchema(TTestBasicRuntime& runtime, TActorId& sender, ui64 pathId, const TestTableDescription& table = {}, TString codec = "none"); -void SetupSchema(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, const NOlap::TSnapshot& snapshot, bool succeed = true); +[[nodiscard]] NTxUT::TPlanStep SetupSchema(TTestBasicRuntime& runtime, TActorId& sender, ui64 pathId, const TestTableDescription& table = {}, TString codec = "none"); +[[nodiscard]] NTxUT::TPlanStep SetupSchema(TTestBasicRuntime& runtime, TActorId& sender, const TString& txBody, const ui64 txId); -void PrepareTablet( +[[nodiscard]] NTxUT::TPlanStep PrepareTablet( TTestBasicRuntime& runtime, const ui64 tableId, const std::vector& schema, const ui32 keySize = 1); -void PrepareTablet(TTestBasicRuntime& runtime, const TString& schemaTxBody, bool succeed); std::shared_ptr ReadAllAsBatch( TTestBasicRuntime& runtime, const ui64 tableId, const NOlap::TSnapshot& snapshot, const std::vector& schema); diff --git a/ydb/core/tx/columnshard/test_helper/shard_reader.h b/ydb/core/tx/columnshard/test_helper/shard_reader.h index ebef456bbee5..8f1d3afb1c8f 100644 --- a/ydb/core/tx/columnshard/test_helper/shard_reader.h +++ b/ydb/core/tx/columnshard/test_helper/shard_reader.h @@ -35,6 +35,8 @@ class TShardReader { std::vector> ResultBatches; YDB_READONLY(ui32, IterationsCount, 0); + std::vector Errors; + public: ui64 GetReadStat(const TString& paramName) const { AFL_VERIFY(IsCorrectlyFinished()); @@ -92,6 +94,10 @@ class TShardReader { return IsFinished() && *Finished == -1; } + const std::vector& GetErrors() const { + return Errors; + } + bool InitializeScanner() { AFL_VERIFY(!ScanActorId); const TActorId sender = Runtime.AllocateEdgeActor(); @@ -104,6 +110,9 @@ class TShardReader { ScanActorId = ActorIdFromProto(msg.GetScanActorId()); return true; } else if (auto* evError = std::get<1>(event)) { + for (auto issue : evError->Record.GetIssues()) { + Errors.emplace_back(issue); + } Finished = -1; } else { AFL_VERIFY(false); @@ -136,6 +145,9 @@ class TShardReader { Finished = 1; } } else if (auto* evError = std::get<1>(event)) { + for (auto issue : evError->Record.GetIssues()) { + Errors.emplace_back(issue); + } Finished = -1; } else { AFL_VERIFY(false); diff --git a/ydb/core/tx/columnshard/test_helper/shard_writer.cpp b/ydb/core/tx/columnshard/test_helper/shard_writer.cpp index f9c7583ef140..b1e61360b66f 100644 --- a/ydb/core/tx/columnshard/test_helper/shard_writer.cpp +++ b/ydb/core/tx/columnshard/test_helper/shard_writer.cpp @@ -8,7 +8,7 @@ namespace NKikimr::NTxUT { -NKikimrDataEvents::TEvWriteResult::EStatus TShardWriter::StartCommit(const ui64 txId) { +NKikimrDataEvents::TEvWriteResult TShardWriter::StartCommitImpl(const ui64 txId) { auto evCommit = std::make_unique(txId, NKikimrDataEvents::TEvWrite::MODE_IMMEDIATE); evCommit->Record.MutableLocks()->SetOp(NKikimrDataEvents::TKqpLocks::Commit); auto* lock = evCommit->Record.MutableLocks()->AddLocks(); @@ -19,7 +19,22 @@ NKikimrDataEvents::TEvWriteResult::EStatus TShardWriter::StartCommit(const ui64 auto event = Runtime.GrabEdgeEvent(handle); AFL_VERIFY(event); AFL_VERIFY(event->Record.GetTxId() == txId); - return event->Record.GetStatus(); + return event->Record; +} + +void TShardWriter::StartCommitFail(const ui64 txId) { + auto event = StartCommitImpl(txId); + AFL_VERIFY(event.GetStatus() == NKikimrDataEvents::TEvWriteResult::STATUS_BAD_REQUEST); +} + +TPlanStep TShardWriter::StartCommit(const ui64 txId) { + const auto now = Runtime.GetTimeProvider()->Now(); + auto event = StartCommitImpl(txId); + AFL_VERIFY(event.GetStatus() == NKikimrDataEvents::TEvWriteResult::STATUS_PREPARED); + AFL_VERIFY(now.MilliSeconds() <= event.GetMinStep()); + AFL_VERIFY(event.GetMinStep() <= event.GetMaxStep()); + AFL_VERIFY(event.GetMaxStep() < Max()); + return TPlanStep{event.GetMinStep()}; } NKikimrDataEvents::TEvWriteResult::EStatus TShardWriter::Abort(const ui64 txId) { diff --git a/ydb/core/tx/columnshard/test_helper/shard_writer.h b/ydb/core/tx/columnshard/test_helper/shard_writer.h index b43e9749a69b..584a443df480 100644 --- a/ydb/core/tx/columnshard/test_helper/shard_writer.h +++ b/ydb/core/tx/columnshard/test_helper/shard_writer.h @@ -1,6 +1,7 @@ #pragma once -#include +#include #include +#include #include @@ -19,6 +20,9 @@ class TShardWriter { YDB_ACCESSOR(ui64, LockNodeId, 1); const TActorId Sender; +private: + [[nodiscard]] NKikimrDataEvents::TEvWriteResult StartCommitImpl(const ui64 txId); + public: TShardWriter(TTestBasicRuntime& runtime, const ui64 tabletId, const ui64 pathId, const ui64 lockId) : Runtime(runtime) @@ -32,8 +36,8 @@ class TShardWriter { const TActorId& GetSender() const { return Sender; } - - [[nodiscard]] NKikimrDataEvents::TEvWriteResult::EStatus StartCommit(const ui64 txId); + void StartCommitFail(const ui64 txId); + [[nodiscard]] NTxUT::TPlanStep StartCommit(const ui64 txId); [[nodiscard]] NKikimrDataEvents::TEvWriteResult::EStatus Abort(const ui64 txId); [[nodiscard]] NKikimrDataEvents::TEvWriteResult::EStatus Write( diff --git a/ydb/core/tx/columnshard/test_helper/test_combinator.h b/ydb/core/tx/columnshard/test_helper/test_combinator.h new file mode 100644 index 000000000000..d98519465e44 --- /dev/null +++ b/ydb/core/tx/columnshard/test_helper/test_combinator.h @@ -0,0 +1,80 @@ +#pragma once + + +#define Y_UNIT_TEST_COMBINATOR_1(BaseName, Flag1) \ + template void BaseName(NUnitTest::TTestContext&); \ + struct TTestRegistration##BaseName { \ + TTestRegistration##BaseName() { \ + TCurrentTest::AddTest(#BaseName "-" #Flag1, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1, static_cast(&BaseName), false); \ + } \ + }; \ + static TTestRegistration##BaseName testRegistration##BaseName; \ + template \ + void BaseName(NUnitTest::TTestContext&) + +#define Y_UNIT_TEST_COMBINATOR_2(BaseName, Flag1, Flag2) \ + template void BaseName(NUnitTest::TTestContext&); \ + struct TTestRegistration##BaseName { \ + TTestRegistration##BaseName() { \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2, static_cast(&BaseName), false); \ + } \ + }; \ + static TTestRegistration##BaseName testRegistration##BaseName; \ + template \ + void BaseName(NUnitTest::TTestContext&) + + +#define Y_UNIT_TEST_COMBINATOR_3(BaseName, Flag1, Flag2, Flag3) \ + template void BaseName(NUnitTest::TTestContext&); \ + struct TTestRegistration##BaseName { \ + TTestRegistration##BaseName() { \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ + } \ + }; \ + static TTestRegistration##BaseName testRegistration##BaseName; \ + template \ + void BaseName(NUnitTest::TTestContext&) + +#define Y_UNIT_TEST_COMBINATOR_4(BaseName, Flag1, Flag2, Flag3, Flag4) \ + template void BaseName(NUnitTest::TTestContext&); \ + struct TTestRegistration##BaseName { \ + TTestRegistration##BaseName() { \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "-" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "-" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "-" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "-" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "+" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "+" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "+" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "+" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "-" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "-" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "-" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "-" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "+" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "+" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "+" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "+" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + } \ + }; \ + static TTestRegistration##BaseName testRegistration##BaseName; \ + template \ + void BaseName(NUnitTest::TTestContext&) + + +#define Y_UNIT_TEST_DUO Y_UNIT_TEST_COMBINATOR_1 +#define Y_UNIT_TEST_QUATRO Y_UNIT_TEST_COMBINATOR_2 +#define Y_UNIT_TEST_OCTO Y_UNIT_TEST_COMBINATOR_3 +#define Y_UNIT_TEST_SEDECIM Y_UNIT_TEST_COMBINATOR_4 + diff --git a/ydb/core/tx/columnshard/transactions/tx_controller.cpp b/ydb/core/tx/columnshard/transactions/tx_controller.cpp index bf9f76d9c631..c423e8915e3a 100644 --- a/ydb/core/tx/columnshard/transactions/tx_controller.cpp +++ b/ydb/core/tx/columnshard/transactions/tx_controller.cpp @@ -98,6 +98,8 @@ std::shared_ptr TTxController::UpdateTxSour op->ResetStatusOnUpdate(); auto& txInfo = op->MutableTxInfo(); txInfo.Source = tx.Source; + txInfo.MinStep = tx.MinStep; + txInfo.MaxStep = tx.MaxStep; txInfo.Cookie = tx.Cookie; txInfo.SeqNo = tx.SeqNo; diff --git a/ydb/core/tx/columnshard/transactions/tx_controller.h b/ydb/core/tx/columnshard/transactions/tx_controller.h index 664b32bde0b9..af7a497b47a9 100644 --- a/ydb/core/tx/columnshard/transactions/tx_controller.h +++ b/ydb/core/tx/columnshard/transactions/tx_controller.h @@ -50,7 +50,7 @@ struct TFullTxInfo: public TBasicTxInfo { public: static TFullTxInfo BuildFake(const NKikimrTxColumnShard::ETransactionKind kind) { - return TFullTxInfo(kind, 0, NActors::TActorId(), 0, {}); + return TFullTxInfo(kind, 0, NActors::TActorId(), 0, 0, {}); } bool operator==(const TFullTxInfo& item) const = default; @@ -86,9 +86,10 @@ struct TFullTxInfo: public TBasicTxInfo { : TBasicTxInfo(txKind, txId) { } - TFullTxInfo(const NKikimrTxColumnShard::ETransactionKind& txKind, const ui64 txId, const TActorId& source, const ui64 cookie, - const std::optional& seqNo) + TFullTxInfo(const NKikimrTxColumnShard::ETransactionKind& txKind, const ui64 txId, const TActorId& source, const ui64 minAllowedPlanStep, + const ui64 cookie, const std::optional& seqNo) : TBasicTxInfo(txKind, txId) + , MinStep(minAllowedPlanStep) , Source(source) , Cookie(cookie) , SeqNo(seqNo) { @@ -414,7 +415,6 @@ class TTxController { THashMap Operators; private: - ui64 GetAllowedStep() const; bool AbortTx(const TPlanQueueItem planQueueItem, NTabletFlatExecutor::TTransactionContext& txc); TTxInfo RegisterTx(const std::shared_ptr& txOperator, const TString& txBody, @@ -426,6 +426,8 @@ class TTxController { public: TTxController(TColumnShard& owner); + ui64 GetAllowedStep() const; + ITransactionOperator::TPtr GetTxOperatorOptional(const ui64 txId) const { auto it = Operators.find(txId); if (it == Operators.end()) { diff --git a/ydb/core/tx/columnshard/ut_rw/ut_backup.cpp b/ydb/core/tx/columnshard/ut_rw/ut_backup.cpp index 8ca1b5a87245..f0a8aeda7a64 100644 --- a/ydb/core/tx/columnshard/ut_rw/ut_backup.cpp +++ b/ydb/core/tx/columnshard/ut_rw/ut_backup.cpp @@ -17,7 +17,7 @@ using namespace NTxUT; Y_UNIT_TEST_SUITE(Backup) { - bool ProposeTx(TTestBasicRuntime& runtime, TActorId& sender, NKikimrTxColumnShard::ETransactionKind txKind, const TString& txBody, const ui64 txId) { + [[nodiscard]] TPlanStep ProposeTx(TTestBasicRuntime& runtime, TActorId& sender, NKikimrTxColumnShard::ETransactionKind txKind, const TString& txBody, const ui64 txId) { auto event = std::make_unique( txKind, sender, txId, txBody); @@ -26,7 +26,8 @@ Y_UNIT_TEST_SUITE(Backup) { const auto& res = ev->Get()->Record; UNIT_ASSERT_EQUAL(res.GetTxId(), txId); UNIT_ASSERT_EQUAL(res.GetTxKind(), txKind); - return (res.GetStatus() == NKikimrTxColumnShard::PREPARED); + UNIT_ASSERT_EQUAL(res.GetStatus(), NKikimrTxColumnShard::PREPARED); + return TPlanStep{res.GetMinStep()}; } void PlanTx(TTestBasicRuntime& runtime, TActorId& sender, NKikimrTxColumnShard::ETransactionKind txKind, NOlap::TSnapshot snap, bool waitResult = true) { @@ -67,10 +68,8 @@ Y_UNIT_TEST_SUITE(Backup) { NArrow::NTest::TTestColumn("field", TTypeInfo(NTypeIds::Utf8) ) }; auto csControllerGuard = NKikimr::NYDBTest::TControllers::RegisterCSControllerGuard(); - PrepareTablet(runtime, tableId, schema, 2); + auto planStep = PrepareTablet(runtime, tableId, schema, 2); ui64 txId = 111; - ui64 planStep = 1000000000; // greater then delays - ui64 writeId = 1; TActorId sender = runtime.AllocateEdgeActor(); @@ -78,8 +77,8 @@ Y_UNIT_TEST_SUITE(Backup) { { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, writeId++, tableId, MakeTestBlob({0, 100}, schema), schema, true, &writeIds)); - ProposeCommit(runtime, sender, ++txId, writeIds); - PlanCommit(runtime, sender, ++planStep, txId); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); + PlanCommit(runtime, sender, planStep, txId); } TestWaitCondition(runtime, "insert compacted", @@ -87,13 +86,13 @@ Y_UNIT_TEST_SUITE(Backup) { ++writeId; std::vector writeIds; WriteData(runtime, sender, writeId, tableId, MakeTestBlob({writeId * 100, (writeId + 1) * 100}, schema), schema, true, &writeIds); - ProposeCommit(runtime, sender, ++txId, writeIds); - PlanCommit(runtime, sender, ++planStep, txId); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); + PlanCommit(runtime, sender, planStep, txId); return true; }, TDuration::Seconds(1000)); NKikimrTxColumnShard::TBackupTxBody txBody; - NOlap::TSnapshot backupSnapshot(planStep, txId); + NOlap::TSnapshot backupSnapshot(planStep.Val(), txId); txBody.MutableBackupTask()->SetTableName("abcde"); txBody.MutableBackupTask()->SetTableId(tableId); txBody.MutableBackupTask()->SetSnapshotStep(backupSnapshot.GetPlanStep()); @@ -101,9 +100,9 @@ Y_UNIT_TEST_SUITE(Backup) { txBody.MutableBackupTask()->MutableS3Settings()->SetEndpoint("fake.fake"); txBody.MutableBackupTask()->MutableS3Settings()->SetSecretKey("fakeSecret"); AFL_VERIFY(csControllerGuard->GetFinishedExportsCount() == 0); - UNIT_ASSERT(ProposeTx(runtime, sender, NKikimrTxColumnShard::TX_KIND_BACKUP, txBody.SerializeAsString(), ++txId)); + planStep = ProposeTx(runtime, sender, NKikimrTxColumnShard::TX_KIND_BACKUP, txBody.SerializeAsString(), ++txId); AFL_VERIFY(csControllerGuard->GetFinishedExportsCount() == 1); - PlanTx(runtime, sender, NKikimrTxColumnShard::TX_KIND_BACKUP, NOlap::TSnapshot(++planStep, txId), false); + PlanTx(runtime, sender, NKikimrTxColumnShard::TX_KIND_BACKUP, NOlap::TSnapshot(planStep, txId), false); TestWaitCondition(runtime, "export", []() {return Singleton()->GetSize(); }); } diff --git a/ydb/core/tx/columnshard/ut_rw/ut_columnshard_read_write.cpp b/ydb/core/tx/columnshard/ut_rw/ut_columnshard_read_write.cpp index 394868ac5716..9d3ee177a7b0 100644 --- a/ydb/core/tx/columnshard/ut_rw/ut_columnshard_read_write.cpp +++ b/ydb/core/tx/columnshard/ut_rw/ut_columnshard_read_write.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -354,7 +355,7 @@ void TestWrite(const TestTableDescription& table) { ui64 writeId = 0; ui64 tableId = 1; - SetupSchema(runtime, sender, tableId, table); + Y_UNUSED(SetupSchema(runtime, sender, tableId, table)); const auto& ydbSchema = table.Schema; @@ -434,11 +435,12 @@ void TestWrite(const TestTableDescription& table) { UNIT_ASSERT(ok); } -void TestWriteOverload(const TestTableDescription& table) { +void TestWriteOverload(const TestTableDescription& table, bool WritePortionsOnInsert) { TTestBasicRuntime runtime; TTester::Setup(runtime); + runtime.GetAppData().FeatureFlags.SetEnableWritePortionsOnInsert(WritePortionsOnInsert); auto csDefaultControllerGuard = NKikimr::NYDBTest::TControllers::RegisterCSControllerGuard(); - + csDefaultControllerGuard->SetOverrideBlobSplitSettings(std::nullopt); TActorId sender = runtime.AllocateEdgeActor(); CreateTestBootstrapper(runtime, CreateTestTabletInfo(TTestTxConfig::TxTablet0, TTabletTypes::ColumnShard), &CreateColumnShard); @@ -450,7 +452,7 @@ void TestWriteOverload(const TestTableDescription& table) { ui64 writeId = 0; ui64 tableId = 1; - SetupSchema(runtime, sender, tableId, table); + Y_UNUSED(SetupSchema(runtime, sender, tableId, table)); TString testBlob = MakeTestBlob({ 0, 100 * 1000 }, table.Schema); UNIT_ASSERT(testBlob.size() > NOlap::TCompactionLimits::MAX_BLOB_SIZE / 2); @@ -462,26 +464,31 @@ void TestWriteOverload(const TestTableDescription& table) { TDeque> capturedWrites; auto captureEvents = [&](TTestActorRuntimeBase&, TAutoPtr& ev) { - if (auto* msg = TryGetPrivateEvent(ev)) { - Cerr << "CATCH TEvWrite, status " << msg->GetPutResult().GetPutStatus() << Endl; - if (toCatch && msg->GetPutResult().GetPutStatus() != NKikimrProto::UNKNOWN) { - capturedWrites.push_back(ev.Release()); + if (toCatch) { + TAutoPtr eventToCapture; + if (WritePortionsOnInsert) { + if (auto* msg = TryGetPrivateEvent(ev)) { + Cerr << "CATCH TEvWritePortionResult, status " << msg->GetWriteStatus() << Endl; + if (msg->GetWriteStatus() != NKikimrProto::EReplyStatus::UNKNOWN) { + eventToCapture = ev.Release(); + } + } + } else { + if (auto* msg = TryGetPrivateEvent(ev)) { + Cerr << "CATCH TEvWrite, status " << msg->GetPutResult().GetPutStatus() << Endl; + if (msg->GetPutResult().GetPutStatus() != NKikimrProto::UNKNOWN) { + eventToCapture = ev.Release(); + } + } + } + if (eventToCapture) { --toCatch; + capturedWrites.push_back(std::move(eventToCapture)); return true; - } else { - return false; } } return false; }; - - auto resendOneCaptured = [&]() { - UNIT_ASSERT(capturedWrites.size()); - Cerr << "RESEND TEvWrite" << Endl; - runtime.Send(capturedWrites.front().Release()); - capturedWrites.pop_front(); - }; - runtime.SetEventFilter(captureEvents); const ui32 toSend = toCatch + 1; @@ -492,7 +499,8 @@ void TestWriteOverload(const TestTableDescription& table) { UNIT_ASSERT_VALUES_EQUAL(WaitWriteResult(runtime, TTestTxConfig::TxTablet0), (ui32)NKikimrDataEvents::TEvWriteResult::STATUS_OVERLOADED); while (capturedWrites.size()) { - resendOneCaptured(); + runtime.Send(capturedWrites.front().Release()); + capturedWrites.pop_front(); UNIT_ASSERT_VALUES_EQUAL(WaitWriteResult(runtime, TTestTxConfig::TxTablet0), (ui32)NKikimrDataEvents::TEvWriteResult::STATUS_COMPLETED); } @@ -518,7 +526,7 @@ void TestWriteReadDup(const TestTableDescription& table = {}) { ui64 tableId = 1; auto ydbSchema = table.Schema; - SetupSchema(runtime, sender, tableId); + auto planStep = SetupSchema(runtime, sender, tableId); constexpr ui32 numRows = 10; std::pair portion = { 10, 10 + numRows }; @@ -526,21 +534,20 @@ void TestWriteReadDup(const TestTableDescription& table = {}) { TAutoPtr handle; ui64 txId = 0; - ui64 initPlanStep = 100; - for (ui64 planStep = initPlanStep; planStep < initPlanStep + 50; ++planStep) { + for (auto count = 0; count != 50; ++count) { TSet txIds; for (ui32 i = 0; i <= 5; ++i) { std::vector writeIds; ++txId; UNIT_ASSERT( WriteData(runtime, sender, ++writeId, tableId, testData, ydbSchema, true, &writeIds, NEvWrite::EModificationType::Upsert, txId)); - ProposeCommit(runtime, sender, txId, writeIds, txId); + planStep = ProposeCommit(runtime, sender, txId, writeIds, txId); txIds.insert(txId); } PlanCommit(runtime, sender, planStep, txIds); // read - if (planStep != initPlanStep) { + if (count != 0) { TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(planStep - 1, Max())); reader.SetReplyColumnIds(table.GetColumnIds({ "timestamp" })); auto rb = reader.ReadAll(); @@ -579,13 +586,14 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString }; auto proposeCommit = [&](TTestBasicRuntime& runtime, TActorId& sender, ui64 txId, const std::vector& writeIds) { - ProposeCommit(runtime, sender, txId, writeIds); + const auto result = ProposeCommit(runtime, sender, txId, writeIds); if (reboots) { RebootTablet(runtime, TTestTxConfig::TxTablet0, sender); } + return result; }; - auto planCommit = [&](TTestBasicRuntime& runtime, TActorId& sender, ui64 planStep, ui64 txId) { + auto planCommit = [&](TTestBasicRuntime& runtime, TActorId& sender, TPlanStep planStep, ui64 txId) { PlanCommit(runtime, sender, planStep, txId); if (reboots) { RebootTablet(runtime, TTestTxConfig::TxTablet0, sender); @@ -597,7 +605,7 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString ui64 writeId = 0; ui64 tableId = 1; - SetupSchema(runtime, sender, tableId, table, codec); + auto planStep = SetupSchema(runtime, sender, tableId, table, codec); const std::vector& ydbSchema = table.Schema; const std::vector& testYdbPk = table.Pk; @@ -627,10 +635,10 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString } // commit 1: ins:0, cmt:1, idx:0 - ui64 planStep = 21; ui64 txId = 100; - proposeCommit(runtime, sender, txId, intWriteIds); + planStep = proposeCommit(runtime, sender, txId, intWriteIds); planCommit(runtime, sender, planStep, txId); + const auto firstWritePlanStep = planStep; // read 2 (committed, old snapshot) { @@ -700,9 +708,8 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString // commit 2 (init indexation): ins:0, cmt:0, idx:1 - planStep = 22; ++txId; - proposeCommit(runtime, sender, txId, intWriteIds); + planStep = proposeCommit(runtime, sender, txId, intWriteIds); planCommit(runtime, sender, planStep, txId); // write 3: ins:1, cmt:0, idx:1 @@ -721,10 +728,10 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString UNIT_ASSERT(reader.IsCorrectlyFinished()); } - // read 7, planstep 21 (part of index) + // read 7, first write snapshot { NActors::TLogContextGuard guard = NActors::TLogContextBuilder::Build(NKikimrServices::TX_COLUMNSHARD)("TEST_STEP", 7); - TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(21, txId)); + TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(firstWritePlanStep, txId)); reader.SetReplyColumnIds(TTestSchema::ExtractIds(ydbSchema)); auto rb = reader.ReadAll(); UNIT_ASSERT(rb); @@ -738,10 +745,10 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString UNIT_ASSERT(DataNotHas({ rb }, portion[2])); } - // read 8, planstep 22 (full index) + // read 8 (full index) { NActors::TLogContextGuard guard = NActors::TLogContextBuilder::Build(NKikimrServices::TX_COLUMNSHARD)("TEST_STEP", 8); - TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(22, txId)); + TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(planStep, txId)); reader.SetReplyColumnIds(TTestSchema::ExtractIds(ydbSchema)); auto rb = reader.ReadAll(); UNIT_ASSERT(rb); @@ -757,9 +764,8 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString // commit 3: ins:0, cmt:1, idx:1 - planStep = 23; ++txId; - proposeCommit(runtime, sender, txId, intWriteIds); + planStep = proposeCommit(runtime, sender, txId, intWriteIds); planCommit(runtime, sender, planStep, txId); // write 4: ins:1, cmt:1, idx:1 @@ -771,7 +777,7 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString // read 9 (committed, indexed) { NActors::TLogContextGuard guard = NActors::TLogContextBuilder::Build(NKikimrServices::TX_COLUMNSHARD)("TEST_STEP", 9); - TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(23, txId)); + TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(planStep, txId)); reader.SetReplyColumnIds(TTestSchema::ExtractIds(ydbSchema)); auto rb = reader.ReadAll(); UNIT_ASSERT(rb); @@ -788,15 +794,14 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString // commit 4: ins:0, cmt:2, idx:1 (with duplicates in PK) - planStep = 24; ++txId; - proposeCommit(runtime, sender, txId, intWriteIds); + planStep = proposeCommit(runtime, sender, txId, intWriteIds); planCommit(runtime, sender, planStep, txId); // read 10 { NActors::TLogContextGuard guard = NActors::TLogContextBuilder::Build(NKikimrServices::TX_COLUMNSHARD)("TEST_STEP", 10); - TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(24, txId)); + TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(planStep, txId)); reader.SetReplyColumnIds(TTestSchema::ExtractIds(ydbSchema)); auto rb = reader.ReadAll(); UNIT_ASSERT(rb); @@ -841,7 +846,7 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString // read 11 (range predicate: closed interval) { NActors::TLogContextGuard guard = NActors::TLogContextBuilder::Build(NKikimrServices::TX_COLUMNSHARD)("TEST_STEP", 11); - TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(24, txId)); + TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(planStep, txId)); reader.SetReplyColumnIds(TTestSchema::ExtractIds(ydbSchema)); reader.AddRange(MakeTestRange({ 10, 42 }, true, true, testYdbPk)); auto rb = reader.ReadAll(); @@ -858,7 +863,7 @@ void TestWriteRead(bool reboots, const TestTableDescription& table = {}, TString // read 12 (range predicate: open interval) { NActors::TLogContextGuard guard = NActors::TLogContextBuilder::Build(NKikimrServices::TX_COLUMNSHARD)("TEST_STEP", 11); - TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(24, txId)); + TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(planStep, txId)); reader.SetReplyColumnIds(TTestSchema::ExtractIds(ydbSchema)); reader.AddRange(MakeTestRange({ 10, 42 }, false, false, testYdbPk)); auto rb = reader.ReadAll(); @@ -896,13 +901,14 @@ void TestCompactionInGranuleImpl(bool reboots, const TestTableDescription& table }; auto proposeCommit = [&](TTestBasicRuntime& runtime, TActorId& sender, ui64 txId, const std::vector& writeIds) { - ProposeCommit(runtime, sender, txId, writeIds); + auto result = ProposeCommit(runtime, sender, txId, writeIds); if (reboots) { RebootTablet(runtime, TTestTxConfig::TxTablet0, sender); } + return result; }; - auto planCommit = [&](TTestBasicRuntime& runtime, TActorId& sender, ui64 planStep, ui64 txId) { + auto planCommit = [&](TTestBasicRuntime& runtime, TActorId& sender, TPlanStep planStep, ui64 txId) { PlanCommit(runtime, sender, planStep, txId); if (reboots) { RebootTablet(runtime, TTestTxConfig::TxTablet0, sender); @@ -913,10 +919,9 @@ void TestCompactionInGranuleImpl(bool reboots, const TestTableDescription& table ui64 writeId = 0; ui64 tableId = 1; - ui64 planStep = 100; ui64 txId = 100; - SetupSchema(runtime, sender, tableId, table); + auto planStep = SetupSchema(runtime, sender, tableId, table); TAutoPtr handle; const auto& ydbSchema = table.Schema; const auto& ydbPk = table.Pk; @@ -935,7 +940,7 @@ void TestCompactionInGranuleImpl(bool reboots, const TestTableDescription& table // inserts triggered by count ui32 pos = triggerPortionSize; - for (ui32 i = 0; i < 1; ++i, ++planStep, ++txId) { + for (ui32 i = 0; i < 1; ++i, ++txId) { std::vector ids; ids.reserve(numWrites); for (ui32 w = 0; w < numWrites; ++w, ++writeId, pos += portionSize) { @@ -949,7 +954,7 @@ void TestCompactionInGranuleImpl(bool reboots, const TestTableDescription& table RebootTablet(runtime, TTestTxConfig::TxTablet0, sender); } - proposeCommit(runtime, sender, txId, ids); + planStep = proposeCommit(runtime, sender, txId, ids); planCommit(runtime, sender, planStep, txId); } std::pair smallWrites = { triggerPortionSize, pos }; @@ -958,16 +963,15 @@ void TestCompactionInGranuleImpl(bool reboots, const TestTableDescription& table NOlap::TCompactionLimits engineLimits; ui32 numTxs = engineLimits.GranuleSizeForOverloadPrevent / triggerData.size() + 1; - for (ui32 i = 0; i < numTxs; ++i, ++writeId, ++planStep, ++txId) { + for (ui32 i = 0; i < numTxs; ++i, ++writeId, ++txId) { std::vector writeIds; UNIT_ASSERT(write(runtime, sender, writeId, tableId, triggerData, ydbSchema, writeIds)); - proposeCommit(runtime, sender, txId, writeIds); + planStep = proposeCommit(runtime, sender, txId, writeIds); planCommit(runtime, sender, planStep, txId); } // TODO: Move tablet's time to the future with mediator timecast instead - --planStep; --txId; for (ui32 i = 0; i < 2; ++i) { @@ -1169,17 +1173,15 @@ void TestReadWithProgram(const TestTableDescription& table = {}) { ui64 writeId = 0; ui64 tableId = 1; - ui64 planStep = 100; ui64 txId = 100; - SetupSchema(runtime, sender, tableId, table); + auto planStep = SetupSchema(runtime, sender, tableId, table); { // write some data std::vector writeIds; bool ok = WriteData(runtime, sender, writeId, tableId, MakeTestBlob({ 0, 100 }, table.Schema), table.Schema, true, &writeIds); UNIT_ASSERT(ok); - - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } @@ -1253,17 +1255,16 @@ void TestReadWithProgramLike(const TestTableDescription& table = {}) { ui64 writeId = 0; ui64 tableId = 1; - ui64 planStep = 100; ui64 txId = 100; - SetupSchema(runtime, sender, tableId, table); + auto planStep = SetupSchema(runtime, sender, tableId, table); { // write some data std::vector writeIds; bool ok = WriteData(runtime, sender, writeId, tableId, MakeTestBlob({ 0, 100 }, table.Schema), table.Schema, true, &writeIds); UNIT_ASSERT(ok); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } @@ -1317,17 +1318,16 @@ void TestSomePrograms(const TestTableDescription& table) { ui64 writeId = 0; ui64 tableId = 1; - ui64 planStep = 100; ui64 txId = 100; - SetupSchema(runtime, sender, tableId, table); + auto planStep = SetupSchema(runtime, sender, tableId, table); { // write some data std::vector writeIds; bool ok = WriteData(runtime, sender, writeId, tableId, MakeTestBlob({ 0, 100 }, table.Schema), table.Schema, true, &writeIds); UNIT_ASSERT(ok); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } @@ -1354,6 +1354,83 @@ void TestSomePrograms(const TestTableDescription& table) { } } +void TestReadWithProgramNoProjection(const TestTableDescription& table = {}) { + TTestBasicRuntime runtime; + TTester::Setup(runtime); + auto csDefaultControllerGuard = NKikimr::NYDBTest::TControllers::RegisterCSControllerGuard(); + + TActorId sender = runtime.AllocateEdgeActor(); + CreateTestBootstrapper(runtime, CreateTestTabletInfo(TTestTxConfig::TxTablet0, TTabletTypes::ColumnShard), &CreateColumnShard); + + TDispatchOptions options; + options.FinalEvents.push_back(TDispatchOptions::TFinalEventCondition(TEvTablet::EvBoot)); + runtime.DispatchEvents(options); + + ui64 writeId = 0; + ui64 tableId = 1; + ui64 txId = 100; + + auto planStep = SetupSchema(runtime, sender, tableId, table); + + { // write some data + std::vector writeIds; + bool ok = WriteData(runtime, sender, writeId, tableId, MakeTestBlob({ 0, 100 }, table.Schema), table.Schema, true, &writeIds); + UNIT_ASSERT(ok); + planStep = ProposeCommit(runtime, sender, txId, writeIds); + PlanCommit(runtime, sender, planStep, txId); + } + + std::vector programs; + programs.push_back("XXXYYYZZZ"); + { + NKikimrSSA::TProgram ssa = MakeSelect(TAssignment::FUNC_CMP_EQUAL); + TString serialized; + UNIT_ASSERT(ssa.SerializeToString(&serialized)); + + NKikimrSSA::TOlapProgram program; + program.SetProgram(serialized); + + programs.push_back(""); + UNIT_ASSERT(program.SerializeToString(&programs.back())); + + //remove projections + auto* commands = ssa.MutableCommand(); + for(int i = commands->size() - 1; i >= 0; --i) { + if ((*commands)[i].HasProjection()) { + commands->DeleteSubrange(i, 1); + } + } + + UNIT_ASSERT(ssa.SerializeToString(&serialized)); + program.SetProgram(serialized); + programs.push_back(""); + UNIT_ASSERT(program.SerializeToString(&programs.back())); + } + + ui32 i = 0; + for (auto& programText : programs) { + TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(planStep, txId)); + reader.SetProgram(programText); + auto rb = reader.ReadAll(); + switch(i) { + case 0: + UNIT_ASSERT(reader.IsError()); + break; + + case 1: + UNIT_ASSERT(!reader.IsError()); + break; + + case 2: + UNIT_ASSERT(reader.IsError()); + UNIT_ASSERT(reader.GetErrors().back().Getmessage().Contains("program has no projections")); + break; + } + UNIT_ASSERT(reader.IsFinished()); + ++i; + } +} + struct TReadAggregateResult { ui32 NumRows = 1; @@ -1379,19 +1456,18 @@ void TestReadAggregate(const std::vector& ydbSchema, ui64 writeId = 0; ui64 tableId = 1; - ui64 planStep = 100; ui64 txId = 100; auto pk = NArrow::NTest::TTestColumn::CropSchema(ydbSchema, 4); TestTableDescription table{ .Schema = ydbSchema, .Pk = pk }; - SetupSchema(runtime, sender, tableId, table); + auto planStep = SetupSchema(runtime, sender, tableId, table); { // write some data std::vector writeIds; bool ok = WriteData(runtime, sender, writeId, tableId, testDataBlob, table.Schema, true, &writeIds); UNIT_ASSERT(ok); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } @@ -1496,7 +1572,8 @@ Y_UNIT_TEST_SUITE(EvWrite) { const std::vector schema = { NArrow::NTest::TTestColumn("key", TTypeInfo(NTypeIds::Uint64)), NArrow::NTest::TTestColumn("field", TTypeInfo(NTypeIds::Utf8)) }; const std::vector columnsIds = { 1, 2 }; - PrepareTablet(runtime, tableId, schema); + auto planStep = PrepareTablet(runtime, tableId, schema); + const auto schemaPlanStep = planStep; const ui64 txId = 111; NConstruction::IArrayBuilder::TPtr keyColumn = @@ -1508,21 +1585,19 @@ Y_UNIT_TEST_SUITE(EvWrite) { NTxUT::TShardWriter writer(runtime, TTestTxConfig::TxTablet0, tableId, 222); AFL_VERIFY(writer.Write(batch, {1, 2}, txId) == NKikimrDataEvents::TEvWriteResult::STATUS_COMPLETED); - AFL_VERIFY(writer.StartCommit(txId) == NKikimrDataEvents::TEvWriteResult::STATUS_PREPARED); + planStep = writer.StartCommit(txId); { NTxUT::TShardWriter writer(runtime, TTestTxConfig::TxTablet0, tableId, 444); - AFL_VERIFY(writer.StartCommit(444) == NKikimrDataEvents::TEvWriteResult::STATUS_BAD_REQUEST); + writer.StartCommitFail(444); } - { - auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(10, txId), schema); + auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(schemaPlanStep, txId), schema); UNIT_ASSERT_VALUES_EQUAL(readResult->num_rows(), 0); - - PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(11, txId)); + PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(planStep, txId)); } - auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot::MaxForPlanStep(11), schema); + auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot::MaxForPlanStep(planStep), schema); UNIT_ASSERT_VALUES_EQUAL(readResult->num_rows(), 2048); } @@ -1537,7 +1612,7 @@ Y_UNIT_TEST_SUITE(EvWrite) { const std::vector schema = { NArrow::NTest::TTestColumn("key", TTypeInfo(NTypeIds::Uint64)), NArrow::NTest::TTestColumn("field", TTypeInfo(NTypeIds::Utf8)) }; const std::vector columnsIds = { 1, 2 }; - PrepareTablet(runtime, tableId, schema); + auto planStep = PrepareTablet(runtime, tableId, schema); const ui64 txId = 111; NConstruction::IArrayBuilder::TPtr keyColumn = @@ -1550,9 +1625,9 @@ Y_UNIT_TEST_SUITE(EvWrite) { AFL_VERIFY(writer.Write(batch, {1, 2}, txId) == NKikimrDataEvents::TEvWriteResult::STATUS_COMPLETED); AFL_VERIFY(writer.Abort(txId) == NKikimrDataEvents::TEvWriteResult::STATUS_COMPLETED); - PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(10, txId + 1), false); + PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(planStep, txId + 1), false); - auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot::MaxForPlanStep(10), schema); + auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot::MaxForPlanStep(planStep), schema); UNIT_ASSERT_VALUES_EQUAL(readResult->num_rows(), 0); } @@ -1566,7 +1641,7 @@ Y_UNIT_TEST_SUITE(EvWrite) { const ui64 tableId = 1; const std::vector schema = { NArrow::NTest::TTestColumn("key", TTypeInfo(NTypeIds::Uint64)), NArrow::NTest::TTestColumn("field", TTypeInfo(NTypeIds::Utf8)) }; - PrepareTablet(runtime, tableId, schema); + auto planStep = PrepareTablet(runtime, tableId, schema); const ui64 txId = 111; NConstruction::IArrayBuilder::TPtr keyColumn = @@ -1580,11 +1655,11 @@ Y_UNIT_TEST_SUITE(EvWrite) { NTxUT::TShardWriter writer(runtime, TTestTxConfig::TxTablet0, tableId, 222); AFL_VERIFY(writer.Write(batch, {1, 2}, txId) == NKikimrDataEvents::TEvWriteResult::STATUS_COMPLETED); - AFL_VERIFY(writer.StartCommit(txId) == NKikimrDataEvents::TEvWriteResult::STATUS_PREPARED); + planStep = writer.StartCommit(txId); - PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(11, txId)); + PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(planStep, txId)); - auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot::MaxForPlanStep(11), schema); + auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot::MaxForPlanStep(planStep), schema); UNIT_ASSERT_VALUES_EQUAL(readResult->num_rows(), 2048); } @@ -1599,7 +1674,7 @@ Y_UNIT_TEST_SUITE(EvWrite) { const std::vector schema = { NArrow::NTest::TTestColumn("key", TTypeInfo(NTypeIds::Uint64)), NArrow::NTest::TTestColumn("field", TTypeInfo(NTypeIds::Utf8)) }; const std::vector columnIds = { 1, 2 }; - PrepareTablet(runtime, tableId, schema); + auto planStep = PrepareTablet(runtime, tableId, schema); const ui64 txId = 111; NTxUT::TShardWriter writer(runtime, TTestTxConfig::TxTablet0, tableId, 222); @@ -1612,7 +1687,7 @@ Y_UNIT_TEST_SUITE(EvWrite) { auto batch = NConstruction::TRecordBatchConstructor({ keyColumn, column }).BuildBatch(2048); AFL_VERIFY(writer.Write(batch, columnIds, txId) == NKikimrDataEvents::TEvWriteResult::STATUS_COMPLETED); { - auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(10, txId), schema); + auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(planStep, txId), schema); UNIT_ASSERT_VALUES_EQUAL(readResult->num_rows(), 0); } } @@ -1626,16 +1701,16 @@ Y_UNIT_TEST_SUITE(EvWrite) { AFL_VERIFY(writer.Write(batch, columnIds, txId) == NKikimrDataEvents::TEvWriteResult::STATUS_COMPLETED); { - auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(10, txId), schema); + auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(planStep, txId), schema); UNIT_ASSERT_VALUES_EQUAL(readResult->num_rows(), 0); } } { - AFL_VERIFY(writer.StartCommit(txId) == NKikimrDataEvents::TEvWriteResult::STATUS_PREPARED); - PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(11, txId)); + planStep = writer.StartCommit(txId); + PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(planStep, txId)); } - auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(11, txId), schema); + auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(planStep, txId), schema); UNIT_ASSERT_VALUES_EQUAL(readResult->num_rows(), 2 * 2048); } } @@ -1665,15 +1740,10 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { TestWrite(table); } - Y_UNIT_TEST(WriteOverload) { + Y_UNIT_TEST_QUATRO(WriteOverload, InStore, WithWritePortionsOnInsert) { TestTableDescription table; - TestWriteOverload(table); - } - - Y_UNIT_TEST(WriteStandaloneOverload) { - TestTableDescription table; - table.InStore = false; - TestWriteOverload(table); + table.InStore = InStore; + TestWriteOverload(table, WithWritePortionsOnInsert); } Y_UNIT_TEST(WriteReadDuplicate) { @@ -1699,7 +1769,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { ui64 tableId = 1; auto ydbSchema = table.Schema; - SetupSchema(runtime, sender, tableId); + auto planStep = SetupSchema(runtime, sender, tableId); constexpr ui32 numRows = 10; std::pair portion = { 10, 10 + numRows }; @@ -1707,13 +1777,12 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { TAutoPtr handle; ui64 txId = 0; - ui64 planStep = 100; { TSet txIds; std::vector writeIds; UNIT_ASSERT( WriteData(runtime, sender, ++writeId, tableId, testData, ydbSchema, true, &writeIds, NEvWrite::EModificationType::Update)); - ProposeCommit(runtime, sender, ++txId, writeIds); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); txIds.insert(txId); PlanCommit(runtime, sender, planStep, txIds); @@ -1722,14 +1791,13 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { auto rb = reader.ReadAll(); UNIT_ASSERT(reader.IsCorrectlyFinished()); UNIT_ASSERT(!rb || rb->num_rows() == 0); - ++planStep; } { TSet txIds; std::vector writeIds; UNIT_ASSERT( WriteData(runtime, sender, ++writeId, tableId, testData, ydbSchema, true, &writeIds, NEvWrite::EModificationType::Insert)); - ProposeCommit(runtime, sender, ++txId, writeIds); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); txIds.insert(txId); PlanCommit(runtime, sender, planStep, txIds); @@ -1739,14 +1807,13 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { UNIT_ASSERT(reader.IsCorrectlyFinished()); UNIT_ASSERT(CheckOrdered(rb)); UNIT_ASSERT(DataHas({ rb }, portion, true)); - ++planStep; } { TSet txIds; std::vector writeIds; UNIT_ASSERT( WriteData(runtime, sender, ++writeId, tableId, testData, ydbSchema, true, &writeIds, NEvWrite::EModificationType::Upsert)); - ProposeCommit(runtime, sender, ++txId, writeIds); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); txIds.insert(txId); PlanCommit(runtime, sender, planStep, txIds); @@ -1756,14 +1823,13 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { UNIT_ASSERT(reader.IsCorrectlyFinished()); UNIT_ASSERT(CheckOrdered(rb)); UNIT_ASSERT(DataHas({ rb }, portion, true)); - ++planStep; } { TSet txIds; std::vector writeIds; UNIT_ASSERT( WriteData(runtime, sender, ++writeId, tableId, testData, ydbSchema, true, &writeIds, NEvWrite::EModificationType::Update)); - ProposeCommit(runtime, sender, ++txId, writeIds); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); txIds.insert(txId); PlanCommit(runtime, sender, planStep, txIds); @@ -1773,7 +1839,6 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { UNIT_ASSERT(reader.IsCorrectlyFinished()); UNIT_ASSERT(CheckOrdered(rb)); UNIT_ASSERT(DataHas({ rb }, portion, true)); - ++planStep; } { TSet txIds; @@ -1786,7 +1851,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { std::vector writeIds; UNIT_ASSERT( WriteData(runtime, sender, ++writeId, tableId, testData, ydbSchema, true, &writeIds, NEvWrite::EModificationType::Delete)); - ProposeCommit(runtime, sender, ++txId, writeIds); + auto planStep = ProposeCommit(runtime, sender, ++txId, writeIds); txIds.insert(txId); PlanCommit(runtime, sender, planStep, txIds); @@ -1795,7 +1860,6 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { auto rb = reader.ReadAll(); UNIT_ASSERT(reader.IsCorrectlyFinished()); AFL_VERIFY(!rb || rb->num_rows() == 0)("count", rb->num_rows()); - ++planStep; } } @@ -1933,6 +1997,10 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { TestSomePrograms(table); } + Y_UNIT_TEST(ReadWithProgramNoProjection) { + TestReadWithProgramNoProjection(); + } + Y_UNIT_TEST(ReadAggregate) { auto schema = TTestSchema::YdbAllTypesSchema(); auto testBlob = MakeTestBlob({ 0, 100 }, schema); @@ -1990,13 +2058,13 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { class TTabletReadPredicateTest { private: TTestBasicRuntime& Runtime; - const ui64 PlanStep; + const TPlanStep PlanStep; const ui64 TxId; const std::vector YdbPk; public: TTabletReadPredicateTest( - TTestBasicRuntime& runtime, const ui64 planStep, const ui64 txId, const std::vector& ydbPk) + TTestBasicRuntime& runtime, const TPlanStep planStep, const ui64 txId, const std::vector& ydbPk) : Runtime(runtime) , PlanStep(planStep) , TxId(txId) @@ -2126,10 +2194,9 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { runtime.DispatchEvents(options); const ui64 tableId = 1; - ui64 planStep = 100; ui64 txId = 100; - SetupSchema(runtime, sender, tableId, table, "lz4"); + auto planStep = SetupSchema(runtime, sender, tableId, table, "lz4"); TAutoPtr handle; bool isStrPk0 = table.Pk[0].GetType() == TTypeInfo(NTypeIds::String) || table.Pk[0].GetType() == TTypeInfo(NTypeIds::Utf8); @@ -2142,7 +2209,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { const ui32 numWrites = 23; { ui64 writeId = 0; - for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++planStep, ++txId) { + for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++txId) { ui64 start = i * (triggerPortionSize - overlapSize); std::pair triggerPortion = { start, start + triggerPortionSize }; TString triggerData = MakeTestBlob(triggerPortion, table.Schema, testBlobOptions); @@ -2152,13 +2219,12 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, writeId, tableId, triggerData, table.Schema, true, &writeIds)); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } } // TODO: Move tablet's time to the future with mediator timecast instead - --planStep; --txId; const ui32 fullNumRows = numWrites * (triggerPortionSize - overlapSize) + overlapSize; @@ -2368,11 +2434,10 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { ui64 writeId = 0; ui64 tableId = 1; - ui64 planStep = 1000000; ui64 txId = 100; auto ydbSchema = TTestSchema::YdbSchema(); - SetupSchema(runtime, sender, tableId); + auto planStep = SetupSchema(runtime, sender, tableId); TAutoPtr handle; // Write some test data to advance the time @@ -2383,7 +2448,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, writeId, tableId, triggerData, ydbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } @@ -2397,7 +2462,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { request->Record.SetScanId(1); request->Record.SetLocalPathId(tableId); request->Record.SetTablePath("test_olap_table"); - request->Record.MutableSnapshot()->SetStep(planStep - staleness.MilliSeconds()); + request->Record.MutableSnapshot()->SetStep(planStep.Val() - staleness.MilliSeconds()); request->Record.MutableSnapshot()->SetTxId(Max()); ForwardToTablet(runtime, TTestTxConfig::TxTablet0, sender, request.release()); @@ -2410,7 +2475,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { // Cerr << response << Endl; UNIT_ASSERT_VALUES_EQUAL(response.GetStatus(), Ydb::StatusIds::BAD_REQUEST); UNIT_ASSERT_VALUES_EQUAL(response.IssuesSize(), 1); - UNIT_ASSERT_STRING_CONTAINS(response.GetIssues(0).message(), "Snapshot too old: {640000:max}"); + UNIT_ASSERT_STRING_CONTAINS(response.GetIssues(0).message(), TStringBuilder() << "Snapshot too old: {" << planStep - staleness.MilliSeconds() << ":max}"); } // Try to read snapshot that is too old @@ -2444,7 +2509,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { ui64 tableId = 1; auto ydbSchema = TTestSchema::YdbSchema(); - SetupSchema(runtime, sender, tableId); + auto planStep = SetupSchema(runtime, sender, tableId); TAutoPtr handle; bool blockReadFinished = true; @@ -2546,16 +2611,15 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { UNIT_ASSERT(triggerData.size() > NColumnShard::TLimits::MIN_BYTES_TO_INSERT); UNIT_ASSERT(triggerData.size() < NColumnShard::TLimits::GetMaxBlobSize()); - ui64 planStep = 5000000; ui64 txId = 1000; // Overwrite the same data multiple times to produce multiple portions at different timestamps ui32 numWrites = 14; - for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++planStep, ++txId) { + for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++txId) { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, writeId, tableId, triggerData, ydbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } @@ -2566,14 +2630,12 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, writeId, tableId, smallData, ydbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); ++writeId; - ++planStep; ++txId; } - --planStep; --txId; Cerr << compactionsHappened << Endl; // UNIT_ASSERT_GE(compactionsHappened, 3); // we catch it three times per action @@ -2596,14 +2658,12 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { // read request is in progress and keeps the portions // Advance the time in order to trigger GC - TDuration delay = TDuration::Minutes(6); - planStep += delay.MilliSeconds(); numWrites = 10; - for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++planStep, ++txId) { + for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++txId) { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, writeId, tableId, triggerData, ydbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } { @@ -2621,7 +2681,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { // Check that GC happened but it didn't collect some old portions UNIT_ASSERT_GT(compactionsHappened, previousCompactionsHappened); UNIT_ASSERT_EQUAL(cleanupsHappened, 0); - UNIT_ASSERT_GT_C(oldPortions.size(), deletedPortions.size(), "Some old portions must not be deleted because the are in use by read"); + UNIT_ASSERT_GT_C(oldPortions.size(), deletedPortions.size(), "Some old portions must not be deleted because they are in use by read"); UNIT_ASSERT_GT_C(delayedBlobs.size(), 0, "Read request is expected to have at least one committed blob, which deletion must be delayed"); previousCompactionsHappened = compactionsHappened; previousCleanupsHappened = cleanupsHappened; @@ -2635,17 +2695,17 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { } // Advance the time and trigger some more cleanups withno compactions + csDefaultControllerGuard->SetOverrideUsedSnapshotLivetime(csDefaultControllerGuard->GetMaxReadStalenessInMem() - TDuration::MilliSeconds(1)); csDefaultControllerGuard->DisableBackground(NKikimr::NYDBTest::ICSController::EBackground::Compaction); { auto read = std::make_unique(); ForwardToTablet(runtime, TTestTxConfig::TxTablet0, sender, read.release()); } - planStep += (2 * delay).MilliSeconds(); - for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++planStep, ++txId) { + for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++txId) { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, writeId, tableId, triggerData, ydbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } UNIT_ASSERT_EQUAL(cleanupsHappened, 0); @@ -2655,16 +2715,17 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { auto read = std::make_unique(); ForwardToTablet(runtime, TTestTxConfig::TxTablet0, sender, read.release()); } - for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++planStep, ++txId) { + for (ui32 i = 0; i < numWrites; ++i, ++writeId, ++txId) { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, writeId, tableId, triggerData, ydbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } AFL_VERIFY(csDefaultControllerGuard->GetRequestTracingSnapshotsSave().Val() == 1); AFL_VERIFY(csDefaultControllerGuard->GetRequestTracingSnapshotsRemove().Val() == 1); - + csDefaultControllerGuard->SetOverrideMaxReadStaleness(TDuration::Zero()); + csDefaultControllerGuard->WaitCleaning(TDuration::Seconds(20), &runtime); Cerr << "Compactions happened: " << csDefaultControllerGuard->GetCompactionStartedCounter().Val() << Endl; Cerr << "Indexations happened: " << csDefaultControllerGuard->GetInsertStartedCounter().Val() << Endl; Cerr << "Cleanups happened: " << csDefaultControllerGuard->GetCleaningStartedCounter().Val() << Endl; diff --git a/ydb/core/tx/columnshard/ut_rw/ut_normalizer.cpp b/ydb/core/tx/columnshard/ut_rw/ut_normalizer.cpp index 305778a5d0e3..731c578deea9 100644 --- a/ydb/core/tx/columnshard/ut_rw/ut_normalizer.cpp +++ b/ydb/core/tx/columnshard/ut_rw/ut_normalizer.cpp @@ -259,7 +259,7 @@ Y_UNIT_TEST_SUITE(Normalizers) { const std::vector schema = { NArrow::NTest::TTestColumn("key1", TTypeInfo(NTypeIds::Uint64)), NArrow::NTest::TTestColumn("key2", TTypeInfo(NTypeIds::Uint64)), NArrow::NTest::TTestColumn("field", TTypeInfo(NTypeIds::Utf8)) }; const std::vector columnsIds = { 1, 2, 3 }; - PrepareTablet(runtime, tableId, schema, 2); + auto planStep = PrepareTablet(runtime, tableId, schema, 2); const ui64 txId = 111; NConstruction::IArrayBuilder::TPtr key1Column = @@ -272,17 +272,17 @@ Y_UNIT_TEST_SUITE(Normalizers) { auto batch = NConstruction::TRecordBatchConstructor({ key1Column, key2Column, column }).BuildBatch(20048); NTxUT::TShardWriter writer(runtime, TTestTxConfig::TxTablet0, tableId, 222); AFL_VERIFY(writer.Write(batch, {1, 2, 3}, txId) == NKikimrDataEvents::TEvWriteResult::STATUS_COMPLETED); - AFL_VERIFY(writer.StartCommit(txId) == NKikimrDataEvents::TEvWriteResult::STATUS_PREPARED); - PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(11, txId)); + planStep = writer.StartCommit(txId); + PlanWriteTx(runtime, writer.GetSender(), NOlap::TSnapshot(planStep, txId)); { - auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(11, txId), schema); + auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(planStep, txId), schema); UNIT_ASSERT_VALUES_EQUAL(readResult->num_rows(), 20048); } RebootTablet(runtime, TTestTxConfig::TxTablet0, writer.GetSender()); { - auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(11, txId), schema); + auto readResult = ReadAllAsBatch(runtime, tableId, NOlap::TSnapshot(planStep, txId), schema); UNIT_ASSERT_VALUES_EQUAL(readResult->num_rows(), checker.RecordsCountAfterReboot(20048)); } } diff --git a/ydb/core/tx/columnshard/ut_schema/ut_columnshard_schema.cpp b/ydb/core/tx/columnshard/ut_schema/ut_columnshard_schema.cpp index 731fe98cc86a..439e58fe36d1 100644 --- a/ydb/core/tx/columnshard/ut_schema/ut_columnshard_schema.cpp +++ b/ydb/core/tx/columnshard/ut_schema/ut_columnshard_schema.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -20,24 +21,6 @@ #include #include -#define Y_UNIT_TEST_OCTO(BaseName, Flag1, Flag2, Flag3) \ - template void BaseName(NUnitTest::TTestContext&); \ - struct TTestRegistration##BaseName { \ - TTestRegistration##BaseName() { \ - TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ - } \ - }; \ - static TTestRegistration##BaseName testRegistration##BaseName; \ - template \ - void BaseName(NUnitTest::TTestContext&) - namespace NKikimr { @@ -219,7 +202,6 @@ void TestTtl(bool reboots, bool internal, bool useFirstPkColumnForTtl, NScheme:: ui64 writeId = 0; ui64 tableId = 1; - ui64 planStep = 1000000000; // greater then delays ui64 txId = 100; UNIT_ASSERT(ts.size() == 2); @@ -233,9 +215,8 @@ void TestTtl(bool reboots, bool internal, bool useFirstPkColumnForTtl, NScheme:: TTestSchema::TTableSpecials spec; spec.TtlColumn = ttlColumnName; spec.EvictAfter = TDuration::Seconds(ttlSec); - SetupSchema(runtime, sender, - TTestSchema::CreateInitShardTxBody(tableId, ydbSchema, testYdbPk, spec, "/Root/olapStore"), - NOlap::TSnapshot(++planStep, ++txId)); + auto planStep = SetupSchema(runtime, sender, + TTestSchema::CreateInitShardTxBody(tableId, ydbSchema, testYdbPk, spec, "/Root/olapStore"), ++txId); if (spec.HasTiers()) { csControllerGuard->OverrideTierConfigs(runtime, sender, TTestSchema::BuildSnapshot(spec)); } @@ -247,8 +228,8 @@ void TestTtl(bool reboots, bool internal, bool useFirstPkColumnForTtl, NScheme:: for (auto& data : blobs) { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, ++writeId, tableId, data, ydbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, ++txId, writeIds); - PlanCommit(runtime, sender, ++planStep, txId); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); + PlanCommit(runtime, sender, planStep, txId); } // TODO: write into path 2 (no ttl) @@ -283,9 +264,8 @@ void TestTtl(bool reboots, bool internal, bool useFirstPkColumnForTtl, NScheme:: } else { spec.EvictAfter = TDuration::Seconds(ttlSec); } - SetupSchema(runtime, sender, - TTestSchema::AlterTableTxBody(tableId, 2, spec), - NOlap::TSnapshot(++planStep, ++txId)); + planStep = SetupSchema(runtime, sender, + TTestSchema::AlterTableTxBody(tableId, 2, spec), ++txId); if (spec.HasTiers()) { csControllerGuard->OverrideTierConfigs(runtime, sender, TTestSchema::BuildSnapshot(spec)); } @@ -307,10 +287,8 @@ void TestTtl(bool reboots, bool internal, bool useFirstPkColumnForTtl, NScheme:: // Disable TTL lastTtlFinishedCount = csControllerGuard->GetTTLFinishedCounter().Val(); - auto ok = ProposeSchemaTx(runtime, sender, - TTestSchema::AlterTableTxBody(tableId, 3, TTestSchema::TTableSpecials()), - NOlap::TSnapshot(++planStep, ++txId)); - UNIT_ASSERT(ok); + planStep = SetupSchema(runtime, sender, + TTestSchema::AlterTableTxBody(tableId, 3, TTestSchema::TTableSpecials()), ++txId); if (spec.HasTiers()) { csControllerGuard->OverrideTierConfigs(runtime, sender, TTestSchema::BuildSnapshot(TTestSchema::TTableSpecials())); } @@ -319,8 +297,8 @@ void TestTtl(bool reboots, bool internal, bool useFirstPkColumnForTtl, NScheme:: std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, ++writeId, tableId, blobs[0], ydbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, ++txId, writeIds); - PlanCommit(runtime, sender, ++planStep, txId); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); + PlanCommit(runtime, sender, planStep, txId); ForwardToTablet(runtime, TTestTxConfig::TxTablet0, sender, new TEvPrivate::TEvPeriodicWakeup(true)); @@ -550,14 +528,12 @@ std::vector> TestTiers(bool reboots, const std::vector 0); - SetupSchema(runtime, sender, - TTestSchema::CreateInitShardTxBody(tableId, testYdbSchema, testYdbPk, specs[0], "/Root/olapStore"), - NOlap::TSnapshot(++planStep, ++txId)); + auto planStep = SetupSchema(runtime, sender, + TTestSchema::CreateInitShardTxBody(tableId, testYdbSchema, testYdbPk, specs[0], "/Root/olapStore"), ++txId); if (specs[0].Tiers.size()) { csControllerGuard->OverrideTierConfigs(runtime, sender, TTestSchema::BuildSnapshot(specs[0])); } @@ -565,8 +541,8 @@ std::vector> TestTiers(bool reboots, const std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, ++writeId, tableId, data, testYdbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, ++txId, writeIds); - PlanCommit(runtime, sender, ++planStep, txId); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); + PlanCommit(runtime, sender, planStep, txId); } if (reboots) { @@ -607,9 +583,7 @@ std::vector> TestTiers(bool reboots, const std::vectorOverrideTierConfigs(runtime, sender, TTestSchema::BuildSnapshot(specs[i])); @@ -944,13 +918,10 @@ void TestDrop(bool reboots) { ui64 writeId = 0; ui64 tableId = 1; - ui64 planStep = 1000000000; // greater then delays ui64 txId = 100; - SetupSchema(runtime, sender, TTestSchema::CreateTableTxBody(tableId, testYdbSchema, testYdbPk), - NOlap::TSnapshot(++planStep, ++txId)); - // - + auto planStep = SetupSchema(runtime, sender, + TTestSchema::CreateTableTxBody(tableId, testYdbSchema, testYdbPk), ++txId); TString data1 = MakeTestBlob({0, PORTION_ROWS}, testYdbSchema); UNIT_ASSERT(data1.size() > NColumnShard::TLimits::MIN_BYTES_TO_INSERT); UNIT_ASSERT(data1.size() < 7 * 1024 * 1024); @@ -961,21 +932,21 @@ void TestDrop(bool reboots) { // Write into index std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, ++writeId, tableId, data1, testYdbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, ++txId, writeIds); - PlanCommit(runtime, sender, ++planStep, txId); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); + PlanCommit(runtime, sender, planStep, txId); // Write into InsertTable writeIds.clear(); UNIT_ASSERT(WriteData(runtime, sender, ++writeId, tableId, data2, testYdbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, ++txId, writeIds); - PlanCommit(runtime, sender, ++planStep, txId); + planStep = ProposeCommit(runtime, sender, ++txId, writeIds); + PlanCommit(runtime, sender, planStep, txId); if (reboots) { RebootTablet(runtime, TTestTxConfig::TxTablet0, sender); } // Drop table - SetupSchema(runtime, sender, TTestSchema::DropTableTxBody(tableId, 2), NOlap::TSnapshot(++planStep, ++txId)); + planStep = SetupSchema(runtime, sender, TTestSchema::DropTableTxBody(tableId, 2), ++txId); if (reboots) { RebootTablet(runtime, TTestTxConfig::TxTablet0, sender); @@ -983,7 +954,6 @@ void TestDrop(bool reboots) { TAutoPtr handle; { - --planStep; TShardReader reader(runtime, TTestTxConfig::TxTablet0, tableId, NOlap::TSnapshot(planStep, Max())); reader.SetReplyColumnIds(TTestSchema::GetColumnIds(TTestSchema::YdbSchema(), { TTestSchema::DefaultTtlColumn })); auto rb = reader.ReadAll(); @@ -1009,32 +979,29 @@ void TestDropWriteRace() { // ui64 tableId = 1; - ui64 planStep = 1000000000; // greater then delays ui64 txId = 100; ui32 writeId = 0; NLongTxService::TLongTxId longTxId; UNIT_ASSERT(longTxId.ParseString("ydb://long-tx/01ezvvxjdk2hd4vdgjs68knvp8?node_id=1")); - SetupSchema(runtime, sender, TTestSchema::CreateTableTxBody(tableId, testYdbSchema, testYdbPk), - NOlap::TSnapshot(++planStep, ++txId)); + auto planStep = SetupSchema(runtime, sender, + TTestSchema::CreateTableTxBody(tableId, testYdbSchema, testYdbPk), ++txId); TString data = MakeTestBlob({0, 100}, testYdbSchema); UNIT_ASSERT(data.size() < NColumnShard::TLimits::MIN_BYTES_TO_INSERT); // Write into InsertTable ++txId; AFL_VERIFY(WriteData(runtime, sender, ++writeId, tableId, data, testYdbSchema)); - ProposeCommit(runtime, sender, txId, { writeId }); - auto commitTxId = txId; + planStep = ProposeCommit(runtime, sender, txId, { writeId }); + const auto commitTxId = txId; // Drop table - auto ok = ProposeSchemaTx(runtime, sender, TTestSchema::DropTableTxBody(tableId, 2), NOlap::TSnapshot(++planStep, ++txId)); - if (ok) { - PlanSchemaTx(runtime, sender, NOlap::TSnapshot(planStep, txId)); - } + planStep = ProposeSchemaTx(runtime, sender, TTestSchema::DropTableTxBody(tableId, 2), ++txId); + PlanSchemaTx(runtime, sender, NOlap::TSnapshot(planStep, txId)); // Plan commit - PlanCommit(runtime, sender, ++planStep, commitTxId); + PlanCommit(runtime, sender, planStep + 1, commitTxId); } void TestCompaction(std::optional numWrites = {}) { @@ -1054,11 +1021,10 @@ void TestCompaction(std::optional numWrites = {}) { // Create table ui64 writeId = 0; ui64 tableId = 1; - ui64 planStep = 100; ui64 txId = 100; - SetupSchema(runtime, sender, TTestSchema::CreateTableTxBody(tableId, testYdbSchema, testYdbPk), - NOlap::TSnapshot(++planStep, ++txId)); + auto planStep = SetupSchema(runtime, sender, + TTestSchema::CreateTableTxBody(tableId, testYdbSchema, testYdbPk), ++txId); // Set tiering ui64 ts = 1620000000; @@ -1074,8 +1040,8 @@ void TestCompaction(std::optional numWrites = {}) { spec.Tiers.back().EvictAfter = allow; spec.Tiers.back().S3 = TTestSchema::TStorageTier::FakeS3(); - SetupSchema(runtime, sender, TTestSchema::AlterTableTxBody(tableId, 1, spec), - NOlap::TSnapshot(++planStep, ++txId)); + planStep = SetupSchema(runtime, sender, TTestSchema::AlterTableTxBody(tableId, 1, spec), + ++txId); csControllerGuard->OverrideTierConfigs(runtime, sender, TTestSchema::BuildSnapshot(spec)); // Writes @@ -1089,13 +1055,12 @@ void TestCompaction(std::optional numWrites = {}) { numWrites = NOlap::TCompactionLimits().GranuleOverloadSize / triggerData.size(); } - ++planStep; ++txId; - for (ui32 i = 0; i < *numWrites; ++i, ++writeId, ++planStep, ++txId) { + for (ui32 i = 0; i < *numWrites; ++i, ++writeId, ++txId) { std::vector writeIds; UNIT_ASSERT(WriteData(runtime, sender, writeId, tableId, triggerData, testYdbSchema, true, &writeIds)); - ProposeCommit(runtime, sender, txId, writeIds); + planStep = ProposeCommit(runtime, sender, txId, writeIds); PlanCommit(runtime, sender, planStep, txId); } @@ -1146,7 +1111,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestSchema) { auto schema = TTestSchema::YdbSchema(NArrow::NTest::TTestColumn("k0", TTypeInfo(NTypeIds::Timestamp))); auto pk = NArrow::NTest::TTestColumn::CropSchema(schema, 4); - ui64 planStep = 1000; + TPlanStep planStep; ui64 txId = 100; ui64 generation = 0; @@ -1154,7 +1119,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestSchema) { schema[0].SetType(TTypeInfo(ydbType)); pk[0].SetType(TTypeInfo(ydbType)); auto txBody = TTestSchema::CreateTableTxBody(tableId++, schema, pk, {}, ++generation); - SetupSchema(runtime, sender, txBody, NOlap::TSnapshot(planStep++, txId++)); + planStep = SetupSchema(runtime, sender, txBody, txId++); } // TODO: support float types @@ -1167,7 +1132,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestSchema) { schema[0].SetType(TTypeInfo(ydbType)); pk[0].SetType(TTypeInfo(ydbType)); auto txBody = TTestSchema::CreateTableTxBody(tableId++, schema, pk, {}, ++generation); - SetupSchema(runtime, sender, txBody, NOlap::TSnapshot(planStep++, txId++), false); + ProposeSchemaTxFail(runtime, sender, txBody, txId++); } std::vector strTypes = { @@ -1179,7 +1144,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestSchema) { schema[0].SetType(TTypeInfo(ydbType)); pk[0].SetType(TTypeInfo(ydbType)); auto txBody = TTestSchema::CreateTableTxBody(tableId++, schema, pk, {}, ++generation); - SetupSchema(runtime, sender, txBody, NOlap::TSnapshot(planStep++, txId++)); + planStep = SetupSchema(runtime, sender, txBody, txId++); } std::vector xsonTypes = { @@ -1192,7 +1157,7 @@ Y_UNIT_TEST_SUITE(TColumnShardTestSchema) { schema[0].SetType(TTypeInfo(ydbType)); pk[0].SetType(TTypeInfo(ydbType)); auto txBody = TTestSchema::CreateTableTxBody(tableId++, schema, pk, {}, ++generation); - SetupSchema(runtime, sender, txBody, NOlap::TSnapshot(planStep++, txId++), false); + ProposeSchemaTxFail(runtime, sender, txBody, txId++); } } diff --git a/ydb/core/tx/conveyor/service/service.h b/ydb/core/tx/conveyor/service/service.h index d58167fe44ba..b3af6ea71d5a 100644 --- a/ydb/core/tx/conveyor/service/service.h +++ b/ydb/core/tx/conveyor/service/service.h @@ -2,7 +2,7 @@ #include "worker.h" #include #include -#include +#include #include #include #include diff --git a/ydb/core/tx/conveyor/service/worker.cpp b/ydb/core/tx/conveyor/service/worker.cpp index 6450725f15f3..a9e68d7b9359 100644 --- a/ydb/core/tx/conveyor/service/worker.cpp +++ b/ydb/core/tx/conveyor/service/worker.cpp @@ -8,7 +8,7 @@ void TWorker::ExecuteTask(std::vector&& workerTasks) { std::vector processes; instants.emplace_back(TMonotonic::Now()); for (auto&& t : workerTasks) { - Y_UNUSED(t.GetTask()->Execute(t.GetTaskSignals(), t.GetTask())); + t.GetTask()->Execute(t.GetTaskSignals(), t.GetTask()); instants.emplace_back(TMonotonic::Now()); processes.emplace_back(t.GetProcessId()); } diff --git a/ydb/core/tx/conveyor/usage/abstract.cpp b/ydb/core/tx/conveyor/usage/abstract.cpp index 55c19e7bba87..2c670d5a0227 100644 --- a/ydb/core/tx/conveyor/usage/abstract.cpp +++ b/ydb/core/tx/conveyor/usage/abstract.cpp @@ -8,30 +8,22 @@ #include namespace NKikimr::NConveyor { -TConclusionStatus ITask::Execute(std::shared_ptr signals, const std::shared_ptr& taskPtr) { +void ITask::Execute(std::shared_ptr signals, const std::shared_ptr& taskPtr) { AFL_VERIFY(!ExecutedFlag); ExecutedFlag = true; const TMonotonic start = TMonotonic::Now(); try { - TConclusionStatus result = DoExecute(taskPtr); - if (result.IsFail()) { - if (signals) { - signals->Fails->Add(1); - signals->FailsDuration->Add((TMonotonic::Now() - start).MicroSeconds()); - } - } else { - if (signals) { - signals->Success->Add(1); - signals->SuccessDuration->Add((TMonotonic::Now() - start).MicroSeconds()); - } + DoExecute(taskPtr); + if (signals) { + signals->Success->Add(1); + signals->SuccessDuration->Add((TMonotonic::Now() - start).MicroSeconds()); } - return result; } catch (...) { if (signals) { signals->Fails->Add(1); signals->FailsDuration->Add((TMonotonic::Now() - start).MicroSeconds()); } - return TConclusionStatus::Fail("exception: " + CurrentExceptionMessage()); + AFL_ERROR(NKikimrServices::TX_CONVEYOR)("event", "exception_on_execute")("message", CurrentExceptionMessage()); } } diff --git a/ydb/core/tx/conveyor/usage/abstract.h b/ydb/core/tx/conveyor/usage/abstract.h index d66e203274bb..909136d42639 100644 --- a/ydb/core/tx/conveyor/usage/abstract.h +++ b/ydb/core/tx/conveyor/usage/abstract.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include @@ -65,7 +65,7 @@ class ITask { YDB_ACCESSOR(EPriority, Priority, EPriority::Normal); bool ExecutedFlag = false; protected: - virtual TConclusionStatus DoExecute(const std::shared_ptr& taskPtr) = 0; + virtual void DoExecute(const std::shared_ptr& taskPtr) = 0; virtual void DoOnCannotExecute(const TString& reason); public: using TPtr = std::shared_ptr; @@ -76,7 +76,7 @@ class ITask { void OnCannotExecute(const TString& reason) { return DoOnCannotExecute(reason); } - TConclusionStatus Execute(std::shared_ptr signals, const std::shared_ptr& taskPtr); + void Execute(std::shared_ptr signals, const std::shared_ptr& taskPtr); }; } diff --git a/ydb/core/tx/data_events/common/signals_flow.h b/ydb/core/tx/data_events/common/signals_flow.h index e37e10a4ccc2..fcf6b9426819 100644 --- a/ydb/core/tx/data_events/common/signals_flow.h +++ b/ydb/core/tx/data_events/common/signals_flow.h @@ -1,5 +1,5 @@ #pragma once -#include +#include namespace NKikimr::NEvWrite { diff --git a/ydb/core/tx/data_events/shard_writer.h b/ydb/core/tx/data_events/shard_writer.h index c716f690cdbe..595d61e7c5e2 100644 --- a/ydb/core/tx/data_events/shard_writer.h +++ b/ydb/core/tx/data_events/shard_writer.h @@ -6,7 +6,7 @@ #include "common/modification_type.h" #include -#include +#include #include #include diff --git a/ydb/core/tx/data_events/write_data.h b/ydb/core/tx/data_events/write_data.h index 51e6b989c421..33af6e744eb1 100644 --- a/ydb/core/tx/data_events/write_data.h +++ b/ydb/core/tx/data_events/write_data.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/ydb/core/tx/datashard/build_index.cpp b/ydb/core/tx/datashard/build_index.cpp deleted file mode 100644 index 82fd0880bfb9..000000000000 --- a/ydb/core/tx/datashard/build_index.cpp +++ /dev/null @@ -1,629 +0,0 @@ -#include "datashard_impl.h" -#include "range_ops.h" -#include "scan_common.h" -#include "upload_stats.h" -#include "buffer_data.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -namespace NKikimr::NDataShard { - -#define LOG_N(stream) LOG_NOTICE_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) -#define LOG_T(stream) LOG_TRACE_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) -#define LOG_I(stream) LOG_INFO_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) -#define LOG_D(stream) LOG_DEBUG_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) -#define LOG_W(stream) LOG_WARN_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) -#define LOG_E(stream) LOG_ERROR_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) - -static std::shared_ptr BuildTypes(const TUserTable& tableInfo, const NKikimrIndexBuilder::TColumnBuildSettings& buildSettings) { - auto types = GetAllTypes(tableInfo); - - Y_ENSURE(buildSettings.columnSize() > 0); - auto result = std::make_shared(); - result->reserve(tableInfo.KeyColumnIds.size() + buildSettings.columnSize()); - - for (const auto& keyColId : tableInfo.KeyColumnIds) { - auto it = tableInfo.Columns.at(keyColId); - Ydb::Type type; - NScheme::ProtoFromTypeInfo(it.Type, type); - result->emplace_back(it.Name, type); - } - for (size_t i = 0; i < buildSettings.columnSize(); i++) { - const auto& column = buildSettings.column(i); - result->emplace_back(column.GetColumnName(), column.default_from_literal().type()); - } - return result; -} - -static std::shared_ptr BuildTypes(const TUserTable& tableInfo, TProtoColumnsCRef indexColumns, TProtoColumnsCRef dataColumns) { - auto types = GetAllTypes(tableInfo); - - auto result = std::make_shared(); - result->reserve(indexColumns.size() + dataColumns.size()); - - for (const auto& colName : indexColumns) { - Ydb::Type type; - NScheme::ProtoFromTypeInfo(types.at(colName), type); - result->emplace_back(colName, type); - } - for (const auto& colName : dataColumns) { - Ydb::Type type; - NScheme::ProtoFromTypeInfo(types.at(colName), type); - result->emplace_back(colName, type); - } - return result; -} - -bool BuildExtraColumns(TVector& cells, const NKikimrIndexBuilder::TColumnBuildSettings& buildSettings, TString& err, TMemoryPool& valueDataPool) { - cells.clear(); - cells.reserve(buildSettings.columnSize()); - for (size_t i = 0; i < buildSettings.columnSize(); i++) { - const auto& column = buildSettings.column(i); - - NScheme::TTypeInfo typeInfo; - i32 typeMod = -1; - Ydb::StatusIds::StatusCode status; - - if (column.default_from_literal().type().has_pg_type()) { - typeMod = column.default_from_literal().type().pg_type().typmod(); - } - - TString unusedtm; - if (!ExtractColumnTypeInfo(typeInfo, unusedtm, column.default_from_literal().type(), status, err)) { - return false; - } - - auto& back = cells.emplace_back(); - if (!CellFromProtoVal(typeInfo, typeMod, &column.default_from_literal().value(), false, back, err, valueDataPool)) { - return false; - } - } - - return true; -} - -template -class TBuildScanUpload: public TActor>, public NTable::IScan { - using TThis = TBuildScanUpload; - using TBase = TActor; - -protected: - const TIndexBuildScanSettings ScanSettings; - - const ui64 BuildIndexId; - const TString TargetTable; - const TScanRecord::TSeqNo SeqNo; - - const ui64 DataShardId; - const TActorId ProgressActorId; - - TTags ScanTags; // first: columns we scan, order as in IndexTable - std::shared_ptr UploadColumnsTypes; // columns types we upload to indexTable - NTxProxy::EUploadRowsMode UploadMode; - - const TTags KeyColumnIds; - const TVector KeyTypes; - - const TSerializedTableRange TableRange; - const TSerializedTableRange RequestedRange; - - IDriver* Driver = nullptr; - - TBufferData ReadBuf; - TBufferData WriteBuf; - TSerializedCellVec LastUploadedKey; - - TActorId Uploader; - ui32 RetryCount = 0; - - TUploadMonStats Stats = TUploadMonStats("tablets", "build_index_upload"); - TUploadStatus UploadStatus; - - TBuildScanUpload(ui64 buildIndexId, - const TString& target, - const TScanRecord::TSeqNo& seqNo, - ui64 dataShardId, - const TActorId& progressActorId, - const TSerializedTableRange& range, - const TUserTable& tableInfo, - const TIndexBuildScanSettings& scanSettings) - : TBase(&TThis::StateWork) - , ScanSettings(scanSettings) - , BuildIndexId(buildIndexId) - , TargetTable(target) - , SeqNo(seqNo) - , DataShardId(dataShardId) - , ProgressActorId(progressActorId) - , KeyColumnIds(tableInfo.KeyColumnIds) - , KeyTypes(tableInfo.KeyColumnTypes) - , TableRange(tableInfo.Range) - , RequestedRange(range) { - } - - template - EScan FeedImpl(TArrayRef key, const TRow& /*row*/, TAddRow&& addRow) { - LOG_T("Feed key " << DebugPrintPoint(KeyTypes, key, *AppData()->TypeRegistry) << " " << Debug()); - - addRow(); - - if (!HasReachedLimits(ReadBuf, ScanSettings)) { - return EScan::Feed; - } - - if (!WriteBuf.IsEmpty()) { - return EScan::Sleep; - } - - ReadBuf.FlushTo(WriteBuf); - - Upload(); - - return EScan::Feed; - } - -public: - static constexpr auto ActorActivityType() { - return Activity; - } - - ~TBuildScanUpload() override = default; - - TInitialState Prepare(IDriver* driver, TIntrusiveConstPtr) override { - TActivationContext::AsActorContext().RegisterWithSameMailbox(this); - - LOG_I("Prepare " << Debug()); - - Driver = driver; - - return {EScan::Feed, {}}; - } - - EScan Seek(TLead& lead, ui64 seq) override { - LOG_T("Seek no " << seq << " " << Debug()); - if (seq) { - if (!WriteBuf.IsEmpty()) { - return EScan::Sleep; - } - - if (!ReadBuf.IsEmpty()) { - ReadBuf.FlushTo(WriteBuf); - Upload(); - return EScan::Sleep; - } - - if (UploadStatus.IsNone()) { - UploadStatus.StatusCode = Ydb::StatusIds::SUCCESS; - UploadStatus.Issues.AddIssue(NYql::TIssue("Shard or requested range is empty")); - } - - return EScan::Final; - } - - auto scanRange = Intersect(KeyTypes, RequestedRange.ToTableRange(), TableRange.ToTableRange()); - - if (scanRange.From) { - auto seek = scanRange.InclusiveFrom ? NTable::ESeek::Lower : NTable::ESeek::Upper; - lead.To(ScanTags, scanRange.From, seek); - } else { - lead.To(ScanTags, {}, NTable::ESeek::Lower); - } - - if (scanRange.To) { - lead.Until(scanRange.To, scanRange.InclusiveTo); - } - - return EScan::Feed; - } - - TAutoPtr Finish(EAbort abort) override { - if (Uploader) { - this->Send(Uploader, new TEvents::TEvPoisonPill); - Uploader = {}; - } - - TAutoPtr progress = new TEvDataShard::TEvBuildIndexProgressResponse; - progress->Record.SetBuildIndexId(BuildIndexId); - progress->Record.SetTabletId(DataShardId); - progress->Record.SetRequestSeqNoGeneration(SeqNo.Generation); - progress->Record.SetRequestSeqNoRound(SeqNo.Round); - - if (abort != EAbort::None) { - progress->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::ABORTED); - UploadStatus.Issues.AddIssue(NYql::TIssue("Aborted by scan host env")); - - LOG_W(Debug()); - } else if (!UploadStatus.IsSuccess()) { - progress->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BUILD_ERROR); - } else { - progress->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::DONE); - } - - UploadStatusToMessage(progress->Record); - - LOG_N("Finish" << Debug() << " " << progress->Record.ShortDebugString()); - this->Send(ProgressActorId, progress.Release()); - - Driver = nullptr; - this->PassAway(); - return nullptr; - } - - void UploadStatusToMessage(NKikimrTxDataShard::TEvBuildIndexProgressResponse& msg) { - msg.SetUploadStatus(UploadStatus.StatusCode); - NYql::IssuesToMessage(UploadStatus.Issues, msg.MutableIssues()); - } - - void Describe(IOutputStream& out) const override { - out << Debug(); - } - - TString Debug() const { - return TStringBuilder() << "TBuildIndexScan: " - << "datashard: " << DataShardId - << ", requested range: " << DebugPrintRange(KeyTypes, RequestedRange.ToTableRange(), *AppData()->TypeRegistry) - << ", last acked point: " << DebugPrintPoint(KeyTypes, LastUploadedKey.GetCells(), *AppData()->TypeRegistry) - << Stats.ToString() - << UploadStatus.ToString(); - } - - EScan PageFault() override { - LOG_T("Page fault" - << " ReadBuf empty: " << ReadBuf.IsEmpty() - << " WriteBuf empty: " << WriteBuf.IsEmpty() - << " " << Debug()); - - if (!ReadBuf.IsEmpty() && WriteBuf.IsEmpty()) { - ReadBuf.FlushTo(WriteBuf); - Upload(); - } - - return EScan::Feed; - } - -private: - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - HFunc(TEvTxUserProxy::TEvUploadRowsResponse, Handle); - CFunc(TEvents::TSystem::Wakeup, HandleWakeup); - default: - LOG_E("TBuildIndexScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " << ev->ToString()); - } - } - - void HandleWakeup(const NActors::TActorContext& /*ctx*/) { - LOG_D("Retry upload " << Debug()); - - if (!WriteBuf.IsEmpty()) { - RetryUpload(); - } - } - - void Handle(TEvTxUserProxy::TEvUploadRowsResponse::TPtr& ev, const TActorContext& ctx) { - LOG_T("Handle TEvUploadRowsResponse " - << Debug() - << " Uploader: " << Uploader.ToString() - << " ev->Sender: " << ev->Sender.ToString()); - - if (Uploader) { - Y_ENSURE(Uploader == ev->Sender, - "Mismatch" - << " Uploader: " << Uploader.ToString() - << " ev->Sender: " << ev->Sender.ToString()); - } else { - Y_ENSURE(Driver == nullptr); - return; - } - - UploadStatus.StatusCode = ev->Get()->Status; - UploadStatus.Issues.AddIssues(ev->Get()->Issues); - - if (UploadStatus.IsSuccess()) { - Stats.Aggr(&WriteBuf); - LastUploadedKey = WriteBuf.ExtractLastKey(); - - //send progress - TAutoPtr progress = new TEvDataShard::TEvBuildIndexProgressResponse; - progress->Record.SetBuildIndexId(BuildIndexId); - progress->Record.SetTabletId(DataShardId); - progress->Record.SetRequestSeqNoGeneration(SeqNo.Generation); - progress->Record.SetRequestSeqNoRound(SeqNo.Round); - - // TODO(mbkkt) ReleaseBuffer isn't possible, we use LastUploadedKey for logging - progress->Record.SetLastKeyAck(LastUploadedKey.GetBuffer()); - progress->Record.SetRowsDelta(WriteBuf.GetRows()); - progress->Record.SetBytesDelta(WriteBuf.GetBytes()); - WriteBuf.Clear(); - - progress->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::IN_PROGRESS); - UploadStatusToMessage(progress->Record); - - this->Send(ProgressActorId, progress.Release()); - - if (HasReachedLimits(ReadBuf, ScanSettings)) { - ReadBuf.FlushTo(WriteBuf); - Upload(); - } - - Driver->Touch(EScan::Feed); - return; - } - - if (RetryCount < ScanSettings.GetMaxBatchRetries() && UploadStatus.IsRetriable()) { - LOG_N("Got retriable error, " << Debug()); - - ctx.Schedule(GetRetryWakeupTimeoutBackoff(RetryCount), new TEvents::TEvWakeup()); - return; - } - - LOG_N("Got error, abort scan, " << Debug()); - - Driver->Touch(EScan::Final); - } - - void RetryUpload() { - Upload(true); - } - - void Upload(bool isRetry = false) { - if (isRetry) { - ++RetryCount; - } else { - RetryCount = 0; - } - - LOG_D("Upload, last key " << DebugPrintPoint(KeyTypes, WriteBuf.GetLastKey().GetCells(), *AppData()->TypeRegistry) << " " << Debug()); - - auto actor = NTxProxy::CreateUploadRowsInternal( - this->SelfId(), TargetTable, - UploadColumnsTypes, - WriteBuf.GetRowsData(), - UploadMode, - true /*writeToPrivateTable*/); - - Uploader = this->Register(actor); - } -}; - -class TBuildIndexScan final: public TBuildScanUpload { - const ui32 TargetDataColumnPos; // positon of first data column in target table - -public: - TBuildIndexScan(ui64 buildIndexId, - const TString& target, - const TScanRecord::TSeqNo& seqNo, - ui64 dataShardId, - const TActorId& progressActorId, - const TSerializedTableRange& range, - TProtoColumnsCRef targetIndexColumns, - TProtoColumnsCRef targetDataColumns, - const TUserTable& tableInfo, - const TIndexBuildScanSettings& scanSettings) - : TBuildScanUpload(buildIndexId, target, seqNo, dataShardId, progressActorId, range, tableInfo, scanSettings) - , TargetDataColumnPos(targetIndexColumns.size()) { - ScanTags = BuildTags(tableInfo, targetIndexColumns, targetDataColumns); - UploadColumnsTypes = BuildTypes(tableInfo, targetIndexColumns, targetDataColumns); - UploadMode = NTxProxy::EUploadRowsMode::WriteToTableShadow; - } - - EScan Feed(TArrayRef key, const TRow& row) final { - return FeedImpl(key, row, [&] { - const auto rowCells = *row; - - ReadBuf.AddRow( - TSerializedCellVec(rowCells.Slice(0, TargetDataColumnPos)), - TSerializedCellVec::Serialize(rowCells.Slice(TargetDataColumnPos)), - TSerializedCellVec(key)); - }); - } -}; - -class TBuildColumnsScan final: public TBuildScanUpload { - TString ValueSerialized; - -public: - TBuildColumnsScan(ui64 buildIndexId, - const TString& target, - const TScanRecord::TSeqNo& seqNo, - ui64 dataShardId, - const TActorId& progressActorId, - const TSerializedTableRange& range, - const NKikimrIndexBuilder::TColumnBuildSettings& columnBuildSettings, - const TUserTable& tableInfo, - const TIndexBuildScanSettings& scanSettings) - : TBuildScanUpload(buildIndexId, target, seqNo, dataShardId, progressActorId, range, tableInfo, scanSettings) { - Y_ENSURE(columnBuildSettings.columnSize() > 0); - UploadColumnsTypes = BuildTypes(tableInfo, columnBuildSettings); - UploadMode = NTxProxy::EUploadRowsMode::UpsertIfExists; - - TMemoryPool valueDataPool(256); - TVector cells; - TString err; - Y_ENSURE(BuildExtraColumns(cells, columnBuildSettings, err, valueDataPool)); - ValueSerialized = TSerializedCellVec::Serialize(cells); - } - - EScan Feed(TArrayRef key, const TRow& row) final { - return FeedImpl(key, row, [&] { - TSerializedCellVec pk(key); - auto pkTarget = pk; - auto valueTarget = ValueSerialized; - ReadBuf.AddRow( - std::move(pkTarget), - std::move(valueTarget), - std::move(pk)); - }); - } -}; - -TAutoPtr CreateBuildIndexScan( - ui64 buildIndexId, - TString target, - const TScanRecord::TSeqNo& seqNo, - ui64 dataShardId, - const TActorId& progressActorId, - const TSerializedTableRange& range, - TProtoColumnsCRef targetIndexColumns, - TProtoColumnsCRef targetDataColumns, - const NKikimrIndexBuilder::TColumnBuildSettings& columnsToBuild, - const TUserTable& tableInfo, - const TIndexBuildScanSettings& scanSettings) { - if (columnsToBuild.columnSize() > 0) { - return new TBuildColumnsScan( - buildIndexId, target, seqNo, dataShardId, progressActorId, range, columnsToBuild, tableInfo, scanSettings); - } - return new TBuildIndexScan( - buildIndexId, target, seqNo, dataShardId, progressActorId, range, targetIndexColumns, targetDataColumns, tableInfo, scanSettings); -} - -class TDataShard::TTxHandleSafeBuildIndexScan: public NTabletFlatExecutor::TTransactionBase { -public: - TTxHandleSafeBuildIndexScan(TDataShard* self, TEvDataShard::TEvBuildIndexCreateRequest::TPtr&& ev) - : TTransactionBase(self) - , Ev(std::move(ev)) { - } - - bool Execute(TTransactionContext&, const TActorContext& ctx) { - Self->HandleSafe(Ev, ctx); - return true; - } - - void Complete(const TActorContext&) { - // nothing - } - -private: - TEvDataShard::TEvBuildIndexCreateRequest::TPtr Ev; -}; - -void TDataShard::Handle(TEvDataShard::TEvBuildIndexCreateRequest::TPtr& ev, const TActorContext&) { - Execute(new TTxHandleSafeBuildIndexScan(this, std::move(ev))); -} - -void TDataShard::HandleSafe(TEvDataShard::TEvBuildIndexCreateRequest::TPtr& ev, const TActorContext& ctx) { - const auto& record = ev->Get()->Record; - TRowVersion rowVersion(record.GetSnapshotStep(), record.GetSnapshotTxId()); - - LOG_N("Starting TBuildIndexScan " << record.ShortDebugString() - << " row version " << rowVersion); - - // Note: it's very unlikely that we have volatile txs before this snapshot - if (VolatileTxManager.HasVolatileTxsAtSnapshot(rowVersion)) { - VolatileTxManager.AttachWaitingSnapshotEvent(rowVersion, - std::unique_ptr(ev.Release())); - return; - } - - TScanRecord::TSeqNo seqNo = {record.GetSeqNoGeneration(), record.GetSeqNoRound()}; - auto badRequest = [&](const TString& error) { - auto response = MakeHolder(); - response->Record.SetBuildIndexId(record.GetBuildIndexId()); - response->Record.SetTabletId(TabletID()); - response->Record.SetRequestSeqNoGeneration(seqNo.Generation); - response->Record.SetRequestSeqNoRound(seqNo.Round); - response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); - auto issue = response->Record.AddIssues(); - issue->set_severity(NYql::TSeverityIds::S_ERROR); - issue->set_message(error); - ctx.Send(ev->Sender, std::move(response)); - }; - - const ui64 buildIndexId = record.GetBuildIndexId(); - const ui64 shardId = record.GetTabletId(); - const auto tableId = TTableId(record.GetOwnerId(), record.GetPathId()); - - if (shardId != TabletID()) { - badRequest(TStringBuilder() << "Wrong shard " << shardId << " this is " << TabletID()); - return; - } - - if (!GetUserTables().contains(tableId.PathId.LocalPathId)) { - badRequest(TStringBuilder() << "Unknown table id: " << tableId.PathId.LocalPathId); - return; - } - - const auto& userTable = *GetUserTables().at(tableId.PathId.LocalPathId); - - if (const auto* recCard = ScanManager.Get(buildIndexId)) { - if (recCard->SeqNo == seqNo) { - // do no start one more scan - return; - } - - for (auto scanId : recCard->ScanIds) { - CancelScan(userTable.LocalTid, scanId); - } - ScanManager.Drop(buildIndexId); - } - - TSerializedTableRange requestedRange; - requestedRange.Load(record.GetKeyRange()); - - auto scanRange = Intersect(userTable.KeyColumnTypes, requestedRange.ToTableRange(), userTable.Range.ToTableRange()); - - if (scanRange.IsEmptyRange(userTable.KeyColumnTypes)) { - badRequest(TStringBuilder() << " requested range doesn't intersect with table range" - << " requestedRange: " << DebugPrintRange(userTable.KeyColumnTypes, requestedRange.ToTableRange(), *AppData()->TypeRegistry) - << " tableRange: " << DebugPrintRange(userTable.KeyColumnTypes, userTable.Range.ToTableRange(), *AppData()->TypeRegistry) - << " scanRange: " << DebugPrintRange(userTable.KeyColumnTypes, scanRange, *AppData()->TypeRegistry)); - return; - } - - if (!record.HasSnapshotStep() || !record.HasSnapshotTxId()) { - badRequest(TStringBuilder() << " request doesn't have Shapshot Step or TxId"); - return; - } - - const TSnapshotKey snapshotKey(tableId.PathId, rowVersion.Step, rowVersion.TxId); - const TSnapshot* snapshot = SnapshotManager.FindAvailable(snapshotKey); - if (!snapshot) { - badRequest(TStringBuilder() - << "no snapshot has been found" - << " , path id is " << tableId.PathId.OwnerId << ":" << tableId.PathId.LocalPathId - << " , snapshot step is " << snapshotKey.Step - << " , snapshot tx is " << snapshotKey.TxId); - return; - } - - if (!IsStateActive()) { - badRequest(TStringBuilder() << "Shard " << TabletID() << " is not ready for requests"); - return; - } - - TScanOptions scanOpts; - scanOpts.SetSnapshotRowVersion(rowVersion); - scanOpts.SetResourceBroker("build_index", 10); - - const auto scanId = QueueScan(userTable.LocalTid, - CreateBuildIndexScan(buildIndexId, - record.GetTargetName(), - seqNo, - shardId, - ev->Sender, - requestedRange, - record.GetIndexColumns(), - record.GetDataColumns(), - record.GetColumnBuildSettings(), - userTable, - record.GetScanSettings()), - 0, - scanOpts); - - ScanManager.Set(buildIndexId, seqNo).push_back(scanId); -} - -} diff --git a/ydb/core/tx/datashard/kmeans_helper.cpp b/ydb/core/tx/datashard/build_index/kmeans_helper.cpp similarity index 98% rename from ydb/core/tx/datashard/kmeans_helper.cpp rename to ydb/core/tx/datashard/build_index/kmeans_helper.cpp index 19c84d1f5f45..2e2e6c8b40e5 100644 --- a/ydb/core/tx/datashard/kmeans_helper.cpp +++ b/ydb/core/tx/datashard/build_index/kmeans_helper.cpp @@ -125,9 +125,11 @@ MakeUploadTypes(const TUserTable& table, NKikimrTxDataShard::EKMeansState upload for (const auto& column : data) { addType(column); } - } break; + break; + } default: - Y_UNREACHABLE(); + Y_ASSERT(false); + } return uploadTypes; } diff --git a/ydb/core/tx/datashard/kmeans_helper.h b/ydb/core/tx/datashard/build_index/kmeans_helper.h similarity index 98% rename from ydb/core/tx/datashard/kmeans_helper.h rename to ydb/core/tx/datashard/build_index/kmeans_helper.h index a074f87fd8a6..b9466499632a 100644 --- a/ydb/core/tx/datashard/kmeans_helper.h +++ b/ydb/core/tx/datashard/build_index/kmeans_helper.h @@ -224,11 +224,6 @@ MakeUploadTypes(const TUserTable& table, NKikimrTxDataShard::EKMeansState upload void MakeScan(auto& record, const auto& createScan, const auto& badRequest) { - if (!record.HasEmbeddingColumn()) { - badRequest("Should be specified embedding column"); - return; - } - const auto& settings = record.GetSettings(); if (settings.vector_dimension() < 1) { badRequest("Dimension of vector should be at least one"); diff --git a/ydb/core/tx/datashard/build_index/local_kmeans.cpp b/ydb/core/tx/datashard/build_index/local_kmeans.cpp new file mode 100644 index 000000000000..cca8ddc6bc60 --- /dev/null +++ b/ydb/core/tx/datashard/build_index/local_kmeans.cpp @@ -0,0 +1,913 @@ +#include "kmeans_helper.h" +#include "../datashard_impl.h" +#include "../scan_common.h" +#include "../upload_stats.h" +#include "../buffer_data.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +namespace NKikimr::NDataShard { +using namespace NKMeans; + +// This scan needed to run local (not distributed) kmeans. +// We have this local stage because we construct kmeans tree from top to bottom. +// And bottom kmeans can be constructed completely locally in datashards to avoid extra communication. +// Also it can be used for small tables. +// +// This class is kind of state machine, it has 3 phases. +// Each of them corresponds to 1-N rounds of NTable::IScan (which is kind of state machine itself). +// 1. First iteration collect sample of clusters +// 2. Then N iterations recompute clusters (main cycle of batched kmeans) +// 3. Finally last iteration upload clusters to level table and postings to corresponding posting table +// +// These phases maps to State: +// 1. -- EState::SAMPLE +// 2. -- EState::KMEANS +// 3. -- EState::UPLOAD* +// +// Which UPLOAD* will be used depends on that will client of this scan request (see UploadState) +// +// NTable::IScan::Seek used to switch from current state to the next one. + +// If less than 1% of vectors are reassigned to new clusters we want to stop +// TODO(mbkkt) 1% is choosen by common sense and should be adjusted in future +static constexpr double MinVectorsNeedsReassigned = 0.01; + +class TLocalKMeansScanBase: public TActor, public NTable::IScan { +protected: + using EState = NKikimrTxDataShard::EKMeansState; + + NTableIndex::TClusterId Parent = 0; + NTableIndex::TClusterId Child = 0; + + ui32 Round = 0; + const ui32 MaxRounds = 0; + + const ui32 InitK = 0; + ui32 K = 0; + + EState State; + const EState UploadState; + + IDriver* Driver = nullptr; + + TLead Lead; + + ui64 TabletId = 0; + ui64 BuildId = 0; + + ui64 ReadRows = 0; + ui64 ReadBytes = 0; + + // Sample + ui64 MaxProbability = std::numeric_limits::max(); + TReallyFastRng32 Rng; + + struct TProbability { + ui64 P = 0; + ui64 I = 0; + + auto operator<=>(const TProbability&) const noexcept = default; + }; + + std::vector MaxRows; + std::vector Clusters; + std::vector ClusterSizes; + + // Upload + std::shared_ptr LevelTypes; + std::shared_ptr PostingTypes; + std::shared_ptr UploadTypes; + + const TString LevelTable; + const TString PostingTable; + TString UploadTable; + + TBufferData LevelBuf; + TBufferData PostingBuf; + TBufferData UploadBuf; + + NTable::TPos EmbeddingPos = 0; + NTable::TPos DataPos = 1; + + ui32 RetryCount = 0; + + TActorId Uploader; + const TIndexBuildScanSettings ScanSettings; + + NTable::TTag EmbeddingTag; + TTags ScanTags; + + TUploadStatus UploadStatus; + + ui64 UploadRows = 0; + ui64 UploadBytes = 0; + + TActorId ResponseActorId; + TAutoPtr Response; + + // FIXME: save PrefixRows as std::vector> to avoid parsing + const ui32 PrefixColumns; + TSerializedCellVec Prefix; + TBufferData PrefixRows; + bool IsFirstPrefixFeed = true; + bool IsPrefixRowsValid = true; + + bool IsExhausted = false; + +public: + static constexpr NKikimrServices::TActivity::EType ActorActivityType() + { + return NKikimrServices::TActivity::LOCAL_KMEANS_SCAN_ACTOR; + } + + TLocalKMeansScanBase(ui64 tabletId, const TUserTable& table, + const NKikimrTxDataShard::TEvLocalKMeansRequest& request, + const TActorId& responseActorId, + TAutoPtr&& response, + TLead&& lead) + : TActor{&TThis::StateWork} + , Parent{request.GetParentFrom()} + , Child{request.GetChild()} + , MaxRounds{request.GetNeedsRounds()} + , InitK{request.GetK()} + , K{request.GetK()} + , State{EState::SAMPLE} + , UploadState{request.GetUpload()} + , Lead{std::move(lead)} + , TabletId(tabletId) + , BuildId{request.GetId()} + , Rng{request.GetSeed()} + , LevelTable{request.GetLevelName()} + , PostingTable{request.GetPostingName()} + , ScanSettings(request.GetScanSettings()) + , ResponseActorId{responseActorId} + , Response{std::move(response)} + , PrefixColumns{request.GetParentFrom() == 0 && request.GetParentTo() == 0 ? 0u : 1u} + { + const auto& embedding = request.GetEmbeddingColumn(); + const auto& data = request.GetDataColumns(); + // scan tags + ScanTags = MakeUploadTags(table, embedding, data, EmbeddingPos, DataPos, EmbeddingTag); + Lead.SetTags(ScanTags); + // upload types + { + Ydb::Type type; + LevelTypes = std::make_shared(3); + type.set_type_id(NTableIndex::ClusterIdType); + (*LevelTypes)[0] = {NTableIndex::NTableVectorKmeansTreeIndex::ParentColumn, type}; + (*LevelTypes)[1] = {NTableIndex::NTableVectorKmeansTreeIndex::IdColumn, type}; + type.set_type_id(Ydb::Type::STRING); + (*LevelTypes)[2] = {NTableIndex::NTableVectorKmeansTreeIndex::CentroidColumn, type}; + } + PostingTypes = MakeUploadTypes(table, UploadState, embedding, data); + } + + TInitialState Prepare(IDriver* driver, TIntrusiveConstPtr) final + { + TActivationContext::AsActorContext().RegisterWithSameMailbox(this); + LOG_I("Prepare " << Debug()); + + Driver = driver; + return {EScan::Feed, {}}; + } + + TAutoPtr Finish(EAbort abort) final + { + if (Uploader) { + Send(Uploader, new TEvents::TEvPoison); + Uploader = {}; + } + + auto& record = Response->Record; + record.SetReadRows(ReadRows); + record.SetReadBytes(ReadBytes); + record.SetUploadRows(UploadRows); + record.SetUploadBytes(UploadBytes); + if (abort != EAbort::None) { + record.SetStatus(NKikimrIndexBuilder::EBuildStatus::ABORTED); + } else if (UploadStatus.IsNone() || UploadStatus.IsSuccess()) { + record.SetStatus(NKikimrIndexBuilder::EBuildStatus::DONE); + } else { + record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BUILD_ERROR); + } + NYql::IssuesToMessage(UploadStatus.Issues, record.MutableIssues()); + + if (Response->Record.GetStatus() == NKikimrIndexBuilder::DONE) { + LOG_N("Done " << Debug() << " " << Response->Record.ShortDebugString()); + } else { + LOG_E("Failed " << Debug() << " " << Response->Record.ShortDebugString()); + } + Send(ResponseActorId, Response.Release()); + + Driver = nullptr; + this->PassAway(); + return nullptr; + } + + void Describe(IOutputStream& out) const final + { + out << Debug(); + } + + TString Debug() const + { + return TStringBuilder() << "TLocalKMeansScan TabletId: " << TabletId << " Id: " << BuildId + << " Parent: " << Parent << " Child: " << Child + << " K: " << K << " Clusters: " << Clusters.size() + << " State: " << State << " Round: " << Round << " / " << MaxRounds + << " LevelBuf size: " << LevelBuf.Size() << " PostingBuf size: " << PostingBuf.Size() + << " UploadTable: " << UploadTable << " UploadBuf size: " << UploadBuf.Size() << " RetryCount: " << RetryCount; + } + + EScan PageFault() final + { + LOG_T("PageFault " << Debug()); + return EScan::Feed; + } + +protected: + STFUNC(StateWork) + { + switch (ev->GetTypeRewrite()) { + HFunc(TEvTxUserProxy::TEvUploadRowsResponse, Handle); + CFunc(TEvents::TSystem::Wakeup, HandleWakeup); + default: + LOG_E("StateWork unexpected event type: " << ev->GetTypeRewrite() + << " event: " << ev->ToString() << " " << Debug()); + } + } + + void HandleWakeup(const NActors::TActorContext& /*ctx*/) + { + LOG_D("Retry upload " << Debug()); + + if (UploadInProgress()) { + RetryUpload(); + } + } + + void Handle(TEvTxUserProxy::TEvUploadRowsResponse::TPtr& ev, const TActorContext& ctx) + { + LOG_D("Handle TEvUploadRowsResponse " << Debug() + << " Uploader: " << (Uploader ? Uploader.ToString() : "") + << " ev->Sender: " << ev->Sender.ToString()); + + if (Uploader) { + Y_ENSURE(Uploader == ev->Sender, "Mismatch" + << " Uploader: " << Uploader.ToString() + << " Sender: " << ev->Sender.ToString()); + Uploader = {}; + } else { + Y_ENSURE(Driver == nullptr); + return; + } + + UploadStatus.StatusCode = ev->Get()->Status; + UploadStatus.Issues = ev->Get()->Issues; + if (UploadStatus.IsSuccess()) { + UploadRows += UploadBuf.GetRows(); + UploadBytes += UploadBuf.GetBytes(); + UploadBuf.Clear(); + + TryUpload(LevelBuf, LevelTable, LevelTypes, true) + || TryUpload(PostingBuf, PostingTable, PostingTypes, true); + + Driver->Touch(EScan::Feed); + return; + } + + if (RetryCount < ScanSettings.GetMaxBatchRetries() && UploadStatus.IsRetriable()) { + LOG_N("Got retriable error, " << Debug() << " " << UploadStatus.ToString()); + + ctx.Schedule(GetRetryWakeupTimeoutBackoff(RetryCount), new TEvents::TEvWakeup()); + return; + } + + LOG_N("Got error, abort scan, " << Debug() << " " << UploadStatus.ToString()); + + Driver->Touch(EScan::Final); + } + + bool ShouldWaitUpload() + { + if (!HasReachedLimits(LevelBuf, ScanSettings) && !HasReachedLimits(PostingBuf, ScanSettings)) { + return false; + } + + if (UploadInProgress()) { + return true; + } + + TryUpload(LevelBuf, LevelTable, LevelTypes, true) + || TryUpload(PostingBuf, PostingTable, PostingTypes, true); + + return !HasReachedLimits(LevelBuf, ScanSettings) && !HasReachedLimits(PostingBuf, ScanSettings); + } + + void UploadImpl() + { + LOG_D("Uploading " << Debug()); + + Y_ASSERT(!UploadBuf.IsEmpty()); + Y_ASSERT(!Uploader); + auto actor = NTxProxy::CreateUploadRowsInternal( + this->SelfId(), UploadTable, UploadTypes, UploadBuf.GetRowsData(), + NTxProxy::EUploadRowsMode::WriteToTableShadow, true /*writeToPrivateTable*/); + + Uploader = this->Register(actor); + } + + void InitUpload(std::string_view table, std::shared_ptr types) + { + RetryCount = 0; + UploadTable = table; + UploadTypes = std::move(types); + UploadImpl(); + } + + void RetryUpload() + { + ++RetryCount; + UploadImpl(); + } + + bool UploadInProgress() + { + return !UploadBuf.IsEmpty(); + } + + bool TryUpload(TBufferData& buffer, const TString& table, const std::shared_ptr& types, bool byLimit) + { + if (Y_UNLIKELY(UploadInProgress())) { + // already uploading something + return true; + } + + if (!buffer.IsEmpty() && (!byLimit || HasReachedLimits(buffer, ScanSettings))) { + buffer.FlushTo(UploadBuf); + InitUpload(table, types); + return true; + } + + return false; + } + + void FormLevelRows() + { + std::array pk; + std::array data; + for (NTable::TPos pos = 0; const auto& row : Clusters) { + pk[0] = TCell::Make(Parent); + pk[1] = TCell::Make(Child + pos); + data[0] = TCell{row}; + LevelBuf.AddRow(TSerializedCellVec{pk}, TSerializedCellVec::Serialize(data)); + ++pos; + } + } + + ui64 GetProbability() + { + return Rng.GenRand64(); + } +}; + +template +class TLocalKMeansScan final: public TLocalKMeansScanBase, private TCalculation { + // KMeans + using TEmbedding = std::vector; + + struct TAggregatedCluster { + TEmbedding Cluster; + ui64 Size = 0; + }; + std::vector AggregatedClusters; + + void StartNewPrefix() { + Round = 0; + K = InitK; + State = EState::SAMPLE; + Lead.Valid = true; + Lead.Key = TSerializedCellVec(Prefix.GetCells()); // seek to (prefix, inf) + Lead.Relation = NTable::ESeek::Upper; + Prefix = {}; + IsFirstPrefixFeed = true; + IsPrefixRowsValid = true; + PrefixRows.Clear(); + MaxProbability = std::numeric_limits::max(); + MaxRows.clear(); + Clusters.clear(); + ClusterSizes.clear(); + AggregatedClusters.clear(); + } + +public: + TLocalKMeansScan(ui64 tabletId, const TUserTable& table, NKikimrTxDataShard::TEvLocalKMeansRequest& request, + const TActorId& responseActorId, TAutoPtr&& response, + TLead&& lead) + : TLocalKMeansScanBase{tabletId, table, request, responseActorId, std::move(response), std::move(lead)} + { + this->Dimensions = request.GetSettings().vector_dimension(); + LOG_I("Create " << Debug()); + } + + EScan Seek(TLead& lead, ui64 seq) final + { + LOG_D("Seek " << seq << " " << Debug()); + + if (IsExhausted) { + if (UploadInProgress() + || TryUpload(LevelBuf, LevelTable, LevelTypes, false) + || TryUpload(PostingBuf, PostingTable, PostingTypes, false)) + { + return EScan::Sleep; + } + return EScan::Final; + } + + lead = Lead; + + return EScan::Feed; + } + + EScan Feed(TArrayRef key, const TRow& row) final + { + LOG_T("Feed " << Debug()); + + ++ReadRows; + ReadBytes += CountBytes(key, row); + + if (PrefixColumns && Prefix && !TCellVectorsEquals{}(Prefix.GetCells(), key.subspan(0, PrefixColumns))) { + if (!FinishPrefix()) { + // scan current prefix rows with a new state again + return EScan::Reset; + } + } + + if (PrefixColumns && !Prefix) { + Prefix = TSerializedCellVec{key.subspan(0, PrefixColumns)}; + auto newParent = key.at(0).template AsValue(); + Child += (newParent - Parent) * InitK; + Parent = newParent; + } + + if (IsFirstPrefixFeed && IsPrefixRowsValid) { + PrefixRows.AddRow(TSerializedCellVec{key}, TSerializedCellVec::Serialize(*row)); + if (HasReachedLimits(PrefixRows, ScanSettings)) { + PrefixRows.Clear(); + IsPrefixRowsValid = false; + } + } + + Feed(key, *row); + + return ShouldWaitUpload() ? EScan::Sleep : EScan::Feed; + } + + EScan Exhausted() final + { + LOG_D("Exhausted " << Debug()); + + if (!FinishPrefix()) { + return EScan::Reset; + } + + IsExhausted = true; + + // call Seek to wait uploads + return EScan::Reset; + } + +private: + bool FinishPrefix() + { + if (FinishPrefixImpl()) { + StartNewPrefix(); + LOG_D("FinishPrefix finished " << Debug()); + return true; + } else { + IsFirstPrefixFeed = false; + + if (IsPrefixRowsValid) { + LOG_D("FinishPrefix not finished, manually feeding " << PrefixRows.Size() << " saved rows " << Debug()); + for (ui64 iteration = 0; ; iteration++) { + for (const auto& [key, row_] : *PrefixRows.GetRowsData()) { + TSerializedCellVec row(row_); + Feed(key.GetCells(), row.GetCells()); + } + if (FinishPrefixImpl()) { + StartNewPrefix(); + LOG_D("FinishPrefix finished in " << iteration << " iterations " << Debug()); + return true; + } else { + LOG_D("FinishPrefix not finished in " << iteration << " iterations " << Debug()); + } + } + } else { + LOG_D("FinishPrefix not finished, rescanning rows " << Debug()); + } + + return false; + } + } + + bool FinishPrefixImpl() + { + if (State == EState::SAMPLE) { + State = EState::KMEANS; + if (!InitAggregatedClusters()) { + // We don't need to do anything, + // because this datashard doesn't have valid embeddings for this prefix + return true; + } + Round = 1; + return false; // do KMEANS + } + + if (State == EState::KMEANS) { + if (RecomputeClusters()) { + FormLevelRows(); + State = UploadState; + return false; // do UPLOAD_* + } else { + ++Round; + return false; // recompute KMEANS + } + } + + if (State == UploadState) { + return true; + } + + Y_ASSERT(false); + return true; + } + + bool InitAggregatedClusters() + { + if (Clusters.size() == 0) { + return false; + } + if (Clusters.size() < K) { + // if this datashard have less than K valid embeddings for this parent + // lets make single centroid for it + K = 1; + Clusters.resize(K); + } + Y_ASSERT(Clusters.size() == K); + ClusterSizes.resize(K, 0); + AggregatedClusters.resize(K); + for (auto& aggregate : AggregatedClusters) { + aggregate.Cluster.resize(this->Dimensions, 0); + } + return true; + } + + void AggregateToCluster(ui32 pos, const char* embedding) + { + if (pos >= K) { + return; + } + auto& aggregate = AggregatedClusters[pos]; + auto* coords = aggregate.Cluster.data(); + for (auto coord : this->GetCoords(embedding)) { + *coords++ += coord; + } + ++aggregate.Size; + } + + bool RecomputeClusters() + { + Y_ASSERT(K >= 1); + ui64 vectorCount = 0; + ui64 reassignedCount = 0; + for (size_t i = 0; auto& aggregate : AggregatedClusters) { + vectorCount += aggregate.Size; + + auto& clusterSize = ClusterSizes[i]; + reassignedCount += clusterSize < aggregate.Size ? aggregate.Size - clusterSize : 0; + clusterSize = aggregate.Size; + + if (aggregate.Size != 0) { + this->Fill(Clusters[i], aggregate.Cluster.data(), aggregate.Size); + Y_ASSERT(aggregate.Size == 0); + } + ++i; + } + Y_ASSERT(vectorCount >= K); + Y_ASSERT(reassignedCount <= vectorCount); + if (K == 1) { + return true; + } + + bool last = Round >= MaxRounds; + if (!last && Round > 1) { + const auto changes = static_cast(reassignedCount) / static_cast(vectorCount); + last = changes < MinVectorsNeedsReassigned; + } + if (!last) { + return false; + } + + size_t w = 0; + for (size_t r = 0; r < ClusterSizes.size(); ++r) { + if (ClusterSizes[r] != 0) { + ClusterSizes[w] = ClusterSizes[r]; + Clusters[w] = std::move(Clusters[r]); + ++w; + } + } + ClusterSizes.erase(ClusterSizes.begin() + w, ClusterSizes.end()); + Clusters.erase(Clusters.begin() + w, Clusters.end()); + return true; + } + + void Feed(TArrayRef key, TArrayRef row) + { + switch (State) { + case EState::SAMPLE: + FeedSample(row); + break; + case EState::KMEANS: + FeedKMeans(row); + break; + case EState::UPLOAD_MAIN_TO_BUILD: + FeedUploadMain2Build(key, row); + break; + case EState::UPLOAD_MAIN_TO_POSTING: + FeedUploadMain2Posting(key, row); + break; + case EState::UPLOAD_BUILD_TO_BUILD: + FeedUploadBuild2Build(key, row); + break; + case EState::UPLOAD_BUILD_TO_POSTING: + FeedUploadBuild2Posting(key, row); + break; + default: + Y_ASSERT(false); + } + } + + void FeedSample(TArrayRef row) + { + const auto embedding = row.at(EmbeddingPos).AsRef(); + if (!this->IsExpectedSize(embedding)) { + return; + } + + const auto probability = GetProbability(); + if (Clusters.size() < K) { + MaxRows.push_back({probability, Clusters.size()}); + Clusters.emplace_back(embedding.data(), embedding.size()); + if (Clusters.size() == K) { + std::make_heap(MaxRows.begin(), MaxRows.end()); + MaxProbability = MaxRows.front().P; + } + } else if (probability < MaxProbability) { + // TODO(mbkkt) use tournament tree to make less compare and swaps + std::pop_heap(MaxRows.begin(), MaxRows.end()); + Clusters[MaxRows.back().I].assign(embedding.data(), embedding.size()); + MaxRows.back().P = probability; + std::push_heap(MaxRows.begin(), MaxRows.end()); + MaxProbability = MaxRows.front().P; + } + } + + void FeedKMeans(TArrayRef row) + { + const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); + AggregateToCluster(pos, row.at(EmbeddingPos).Data()); + } + + void FeedUploadMain2Build(TArrayRef key, TArrayRef row) + { + const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); + if (pos < K) { + AddRowMain2Build(PostingBuf, Child + pos, key, row); + } + } + + void FeedUploadMain2Posting(TArrayRef key, TArrayRef row) + { + const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); + if (pos < K) { + AddRowMain2Posting(PostingBuf, Child + pos, key, row, DataPos); + } + } + + void FeedUploadBuild2Build(TArrayRef key, TArrayRef row) + { + const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); + if (pos < K) { + AddRowBuild2Build(PostingBuf, Child + pos, key, row); + } + } + + void FeedUploadBuild2Posting(TArrayRef key, TArrayRef row) + { + const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); + if (pos < K) { + AddRowBuild2Posting(PostingBuf, Child + pos, key, row, DataPos); + } + } +}; + +class TDataShard::TTxHandleSafeLocalKMeansScan final: public NTabletFlatExecutor::TTransactionBase { +public: + TTxHandleSafeLocalKMeansScan(TDataShard* self, TEvDataShard::TEvLocalKMeansRequest::TPtr&& ev) + : TTransactionBase(self) + , Ev(std::move(ev)) + { + } + + bool Execute(TTransactionContext&, const TActorContext& ctx) final + { + Self->HandleSafe(Ev, ctx); + return true; + } + + void Complete(const TActorContext&) final + { + } + +private: + TEvDataShard::TEvLocalKMeansRequest::TPtr Ev; +}; + +void TDataShard::Handle(TEvDataShard::TEvLocalKMeansRequest::TPtr& ev, const TActorContext&) +{ + Execute(new TTxHandleSafeLocalKMeansScan(this, std::move(ev))); +} + +void TDataShard::HandleSafe(TEvDataShard::TEvLocalKMeansRequest::TPtr& ev, const TActorContext& ctx) +{ + auto& request = ev->Get()->Record; + const ui64 id = request.GetId(); + auto rowVersion = request.HasSnapshotStep() || request.HasSnapshotTxId() + ? TRowVersion(request.GetSnapshotStep(), request.GetSnapshotTxId()) + : GetMvccTxVersion(EMvccTxMode::ReadOnly); + TScanRecord::TSeqNo seqNo = {request.GetSeqNoGeneration(), request.GetSeqNoRound()}; + + auto response = MakeHolder(); + response->Record.SetId(id); + response->Record.SetTabletId(TabletID()); + response->Record.SetRequestSeqNoGeneration(seqNo.Generation); + response->Record.SetRequestSeqNoRound(seqNo.Round); + + LOG_N("Starting TLocalKMeansScan TabletId: " << TabletID() + << " " << request.ShortDebugString() + << " row version " << rowVersion); + + // Note: it's very unlikely that we have volatile txs before this snapshot + if (VolatileTxManager.HasVolatileTxsAtSnapshot(rowVersion)) { + VolatileTxManager.AttachWaitingSnapshotEvent(rowVersion, std::unique_ptr(ev.Release())); + return; + } + + auto badRequest = [&](const TString& error) { + response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); + auto issue = response->Record.AddIssues(); + issue->set_severity(NYql::TSeverityIds::S_ERROR); + issue->set_message(error); + }; + auto trySendBadRequest = [&] { + if (response->Record.GetStatus() == NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST) { + LOG_E("Rejecting TLocalKMeansScan bad request TabletId: " << TabletID() + << " " << request.ShortDebugString() + << " with response " << response->Record.ShortDebugString()); + ctx.Send(ev->Sender, std::move(response)); + return true; + } else { + return false; + } + }; + + // 1. Validating table and path existence + if (request.GetTabletId() != TabletID()) { + badRequest(TStringBuilder() << "Wrong shard " << request.GetTabletId() << " this is " << TabletID()); + } + if (!IsStateActive()) { + badRequest(TStringBuilder() << "Shard " << TabletID() << " is " << State << " and not ready for requests"); + } + const auto pathId = TPathId::FromProto(request.GetPathId()); + const auto* userTableIt = GetUserTables().FindPtr(pathId.LocalPathId); + if (!userTableIt) { + badRequest(TStringBuilder() << "Unknown table id: " << pathId.LocalPathId); + } + if (trySendBadRequest()) { + return; + } + const auto& userTable = **userTableIt; + + // 2. Validating request fields + if (request.HasSnapshotStep() || request.HasSnapshotTxId()) { + const TSnapshotKey snapshotKey(pathId, rowVersion.Step, rowVersion.TxId); + if (!SnapshotManager.FindAvailable(snapshotKey)) { + badRequest(TStringBuilder() << "Unknown snapshot for path id " << pathId.OwnerId << ":" << pathId.LocalPathId + << ", snapshot step is " << snapshotKey.Step << ", snapshot tx is " << snapshotKey.TxId); + } + } + + if (request.GetUpload() != NKikimrTxDataShard::UPLOAD_MAIN_TO_BUILD + && request.GetUpload() != NKikimrTxDataShard::UPLOAD_MAIN_TO_POSTING + && request.GetUpload() != NKikimrTxDataShard::UPLOAD_BUILD_TO_BUILD + && request.GetUpload() != NKikimrTxDataShard::UPLOAD_BUILD_TO_POSTING) + { + badRequest("Wrong upload"); + } + + if (request.GetK() < 2) { + badRequest("Should be requested partition on at least two rows"); + } + + const auto parentFrom = request.GetParentFrom(); + const auto parentTo = request.GetParentTo(); + NTable::TLead lead; + if (parentFrom == 0 && parentTo == 0) { + lead.To({}, NTable::ESeek::Lower); + } else if (parentFrom > parentTo) { + badRequest(TStringBuilder() << "Parent from " << parentFrom << " should be less or equal to parent to " << parentTo); + } else { + TCell from = TCell::Make(parentFrom - 1); + TCell to = TCell::Make(parentTo); + TTableRange range{{&from, 1}, false, {&to, 1}, true}; + auto scanRange = Intersect(userTable.KeyColumnTypes, range, userTable.Range.ToTableRange()); + if (scanRange.IsEmptyRange(userTable.KeyColumnTypes)) { + badRequest(TStringBuilder() << "Requested range doesn't intersect with table range:" + << " requestedRange: " << DebugPrintRange(userTable.KeyColumnTypes, range, *AppData()->TypeRegistry) + << " tableRange: " << DebugPrintRange(userTable.KeyColumnTypes, userTable.Range.ToTableRange(), *AppData()->TypeRegistry) + << " scanRange: " << DebugPrintRange(userTable.KeyColumnTypes, scanRange, *AppData()->TypeRegistry)); + } + lead.To(range.From, NTable::ESeek::Upper); + lead.Until(range.To, true); + } + + if (!request.HasLevelName()) { + badRequest(TStringBuilder() << "Empty level table name"); + } + if (!request.HasPostingName()) { + badRequest(TStringBuilder() << "Empty posting table name"); + } + + auto tags = GetAllTags(userTable); + if (!tags.contains(request.GetEmbeddingColumn())) { + badRequest(TStringBuilder() << "Unknown embedding column: " << request.GetEmbeddingColumn()); + } + for (auto dataColumn : request.GetDataColumns()) { + if (!tags.contains(dataColumn)) { + badRequest(TStringBuilder() << "Unknown data column: " << dataColumn); + } + } + + if (trySendBadRequest()) { + return; + } + + // 3. Validating vector index settings + TAutoPtr scan; + auto createScan = [&] { + scan = new TLocalKMeansScan{ + TabletID(), userTable, request, ev->Sender, std::move(response), + std::move(lead) + }; + }; + MakeScan(request, createScan, badRequest); + if (!scan) { + auto sent = trySendBadRequest(); + Y_ENSURE(sent); + return; + } + + if (const auto* recCard = ScanManager.Get(id)) { + if (recCard->SeqNo == seqNo) { + // do no start one more scan + return; + } + + for (auto scanId : recCard->ScanIds) { + CancelScan(userTable.LocalTid, scanId); + } + ScanManager.Drop(id); + } + + TScanOptions scanOpts; + scanOpts.SetSnapshotRowVersion(rowVersion); + scanOpts.SetResourceBroker("build_index", 10); // TODO(mbkkt) Should be different group? + const auto scanId = QueueScan(userTable.LocalTid, std::move(scan), 0, scanOpts); + ScanManager.Set(id, seqNo).push_back(scanId); +} + +} diff --git a/ydb/core/tx/datashard/prefix_kmeans.cpp b/ydb/core/tx/datashard/build_index/prefix_kmeans.cpp similarity index 87% rename from ydb/core/tx/datashard/prefix_kmeans.cpp rename to ydb/core/tx/datashard/build_index/prefix_kmeans.cpp index 5a36035d782d..4bdacc46d2c1 100644 --- a/ydb/core/tx/datashard/prefix_kmeans.cpp +++ b/ydb/core/tx/datashard/build_index/prefix_kmeans.cpp @@ -1,8 +1,8 @@ -#include "datashard_impl.h" #include "kmeans_helper.h" -#include "scan_common.h" -#include "upload_stats.h" -#include "buffer_data.h" +#include "../datashard_impl.h" +#include "../scan_common.h" +#include "../upload_stats.h" +#include "../buffer_data.h" #include #include @@ -45,6 +45,7 @@ class TPrefixKMeansScanBase: public TActor, public NTable TLead Lead; + ui64 TabletId = 0; ui64 BuildId = 0; ui64 ReadRows = 0; @@ -101,12 +102,12 @@ class TPrefixKMeansScanBase: public TActor, public NTable TAutoPtr Response; // FIXME: save PrefixRows as std::vector> to avoid parsing - ui32 PrefixColumns; + const ui32 PrefixColumns; TSerializedCellVec Prefix; TBufferData PrefixRows; bool IsFirstPrefixFeed = true; bool IsPrefixRowsValid = true; - + bool IsExhausted = false; public: @@ -115,7 +116,7 @@ class TPrefixKMeansScanBase: public TActor, public NTable return NKikimrServices::TActivity::LOCAL_KMEANS_SCAN_ACTOR; } - TPrefixKMeansScanBase(const TUserTable& table, + TPrefixKMeansScanBase(ui64 tabletId, const TUserTable& table, const NKikimrTxDataShard::TEvPrefixKMeansRequest& request, const TActorId& responseActorId, TAutoPtr&& response) @@ -127,6 +128,7 @@ class TPrefixKMeansScanBase: public TActor, public NTable , K{request.GetK()} , State{EState::SAMPLE} , UploadState{request.GetUpload()} + , TabletId(tabletId) , BuildId{request.GetId()} , Rng{request.GetSeed()} , LevelTable{request.GetLevelName()} @@ -153,6 +155,7 @@ class TPrefixKMeansScanBase: public TActor, public NTable (*LevelTypes)[2] = {NTableIndex::NTableVectorKmeansTreeIndex::CentroidColumn, type}; } PostingTypes = MakeUploadTypes(table, UploadState, embedding, data, PrefixColumns); + // prefix types { auto types = GetAllTypes(table); @@ -207,7 +210,11 @@ class TPrefixKMeansScanBase: public TActor, public NTable } NYql::IssuesToMessage(UploadStatus.Issues, record.MutableIssues()); - LOG_N("Finish " << Debug() << " " << Response->Record.ShortDebugString()); + if (Response->Record.GetStatus() == NKikimrIndexBuilder::DONE) { + LOG_N("Done " << Debug() << " " << Response->Record.ShortDebugString()); + } else { + LOG_E("Failed " << Debug() << " " << Response->Record.ShortDebugString()); + } Send(ResponseActorId, Response.Release()); Driver = nullptr; @@ -222,7 +229,8 @@ class TPrefixKMeansScanBase: public TActor, public NTable TString Debug() const { - return TStringBuilder() << "TPrefixKMeansScan Id: " << BuildId << " Parent: " << Parent << " Child: " << Child + return TStringBuilder() << "TPrefixKMeansScan TabletId: " << TabletId << " Id: " << BuildId + << " Parent: " << Parent << " Child: " << Child << " K: " << K << " Clusters: " << Clusters.size() << " State: " << State << " Round: " << Round << " / " << MaxRounds << " LevelBuf size: " << LevelBuf.Size() << " PostingBuf size: " << PostingBuf.Size() << " PrefixBuf size: " << PrefixBuf.Size() @@ -242,8 +250,8 @@ class TPrefixKMeansScanBase: public TActor, public NTable HFunc(TEvTxUserProxy::TEvUploadRowsResponse, Handle); CFunc(TEvents::TSystem::Wakeup, HandleWakeup); default: - LOG_E("TPrefixKMeansScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " - << ev->ToString() << " " << Debug()); + LOG_E("StateWork unexpected event type: " << ev->GetTypeRewrite() + << " event: " << ev->ToString() << " " << Debug()); } } @@ -299,11 +307,6 @@ class TPrefixKMeansScanBase: public TActor, public NTable Driver->Touch(EScan::Final); } - ui64 GetProbability() - { - return Rng.GenRand64(); - } - bool ShouldWaitUpload() { if (!HasReachedLimits(LevelBuf, ScanSettings) && !HasReachedLimits(PostingBuf, ScanSettings) && !HasReachedLimits(PrefixBuf, ScanSettings)) { @@ -381,6 +384,11 @@ class TPrefixKMeansScanBase: public TActor, public NTable ++pos; } } + + ui64 GetProbability() + { + return Rng.GenRand64(); + } }; template @@ -394,17 +402,13 @@ class TPrefixKMeansScan final: public TPrefixKMeansScanBase, private TCalculatio }; std::vector AggregatedClusters; - void StartNewPrefix() { Parent = Child + K; Child = Parent + 1; Round = 0; K = InitK; State = EState::SAMPLE; - // TODO(mbkkt) Upper or Lower doesn't matter here, because we seek to (prefix, inf) - // so we can choose Lower if it's faster. - // Exact seek with Lower also possible but needs to rewrite some code in Feed - Lead.To(Prefix.GetCells(), NTable::ESeek::Upper); + Lead.To(Prefix.GetCells(), NTable::ESeek::Upper); // seek to (prefix, inf) Prefix = {}; IsFirstPrefixFeed = true; IsPrefixRowsValid = true; @@ -417,9 +421,9 @@ class TPrefixKMeansScan final: public TPrefixKMeansScanBase, private TCalculatio } public: - TPrefixKMeansScan(const TUserTable& table, NKikimrTxDataShard::TEvPrefixKMeansRequest& request, + TPrefixKMeansScan(ui64 tabletId, const TUserTable& table, NKikimrTxDataShard::TEvPrefixKMeansRequest& request, const TActorId& responseActorId, TAutoPtr&& response) - : TPrefixKMeansScanBase{table, request, responseActorId, std::move(response)} + : TPrefixKMeansScanBase{tabletId, table, request, responseActorId, std::move(response)} { this->Dimensions = request.GetSettings().vector_dimension(); LOG_I("Create " << Debug()); @@ -739,9 +743,18 @@ void TDataShard::Handle(TEvDataShard::TEvPrefixKMeansRequest::TPtr& ev, const TA void TDataShard::HandleSafe(TEvDataShard::TEvPrefixKMeansRequest::TPtr& ev, const TActorContext& ctx) { auto& request = ev->Get()->Record; + const ui64 id = request.GetId(); TRowVersion rowVersion = GetMvccTxVersion(EMvccTxMode::ReadOnly); + TScanRecord::TSeqNo seqNo = {request.GetSeqNoGeneration(), request.GetSeqNoRound()}; - LOG_N("Starting TPrefixKMeansScan " << request.ShortDebugString() + auto response = MakeHolder(); + response->Record.SetId(id); + response->Record.SetTabletId(TabletID()); + response->Record.SetRequestSeqNoGeneration(seqNo.Generation); + response->Record.SetRequestSeqNoRound(seqNo.Round); + + LOG_N("Starting TPrefixKMeansScan TabletId: " << TabletID() + << " " << request.ShortDebugString() << " row version " << rowVersion); // Note: it's very unlikely that we have volatile txs before this snapshot @@ -749,73 +762,109 @@ void TDataShard::HandleSafe(TEvDataShard::TEvPrefixKMeansRequest::TPtr& ev, cons VolatileTxManager.AttachWaitingSnapshotEvent(rowVersion, std::unique_ptr(ev.Release())); return; } - const ui64 id = request.GetId(); - - auto response = MakeHolder(); - response->Record.SetId(id); - response->Record.SetTabletId(TabletID()); - - TScanRecord::TSeqNo seqNo = {request.GetSeqNoGeneration(), request.GetSeqNoRound()}; - response->Record.SetRequestSeqNoGeneration(seqNo.Generation); - response->Record.SetRequestSeqNoRound(seqNo.Round); auto badRequest = [&](const TString& error) { response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); auto issue = response->Record.AddIssues(); issue->set_severity(NYql::TSeverityIds::S_ERROR); issue->set_message(error); - ctx.Send(ev->Sender, std::move(response)); - response.Reset(); + }; + auto trySendBadRequest = [&] { + if (response->Record.GetStatus() == NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST) { + LOG_E("Rejecting TPrefixKMeansScan bad request TabletId: " << TabletID() + << " " << request.ShortDebugString() + << " with response " << response->Record.ShortDebugString()); + ctx.Send(ev->Sender, std::move(response)); + return true; + } else { + return false; + } }; - if (const ui64 shardId = request.GetTabletId(); shardId != TabletID()) { - badRequest(TStringBuilder() << "Wrong shard " << shardId << " this is " << TabletID()); - return; + // 1. Validating table and path existence + if (request.GetTabletId() != TabletID()) { + badRequest(TStringBuilder() << "Wrong shard " << request.GetTabletId() << " this is " << TabletID()); + } + if (!IsStateActive()) { + badRequest(TStringBuilder() << "Shard " << TabletID() << " is " << State << " and not ready for requests"); } - const auto pathId = TPathId::FromProto(request.GetPathId()); const auto* userTableIt = GetUserTables().FindPtr(pathId.LocalPathId); if (!userTableIt) { badRequest(TStringBuilder() << "Unknown table id: " << pathId.LocalPathId); + } + if (trySendBadRequest()) { return; } - Y_ENSURE(*userTableIt); const auto& userTable = **userTableIt; - if (const auto* recCard = ScanManager.Get(id)) { - if (recCard->SeqNo == seqNo) { - // do no start one more scan - return; - } + // 2. Validating request fields + if (request.GetUpload() != NKikimrTxDataShard::UPLOAD_BUILD_TO_BUILD + && request.GetUpload() != NKikimrTxDataShard::UPLOAD_BUILD_TO_POSTING) + { + badRequest("Wrong upload"); + } - for (auto scanId : recCard->ScanIds) { - CancelScan(userTable.LocalTid, scanId); - } - ScanManager.Drop(id); + if (request.GetK() < 2) { + badRequest("Should be requested partition on at least two rows"); } - if (!IsStateActive()) { - badRequest(TStringBuilder() << "Shard " << TabletID() << " is not ready for requests"); - return; + if (!request.HasLevelName()) { + badRequest(TStringBuilder() << "Empty level table name"); + } + if (!request.HasPostingName()) { + badRequest(TStringBuilder() << "Empty posting table name"); + } + if (!request.HasPrefixName()) { + badRequest(TStringBuilder() << "Empty prefix table name"); } - if (request.GetK() < 2) { - badRequest("Should be requested partition on at least two rows"); + auto tags = GetAllTags(userTable); + if (!tags.contains(request.GetEmbeddingColumn())) { + badRequest(TStringBuilder() << "Unknown embedding column: " << request.GetEmbeddingColumn()); + } + for (auto dataColumn : request.GetDataColumns()) { + if (!tags.contains(dataColumn)) { + badRequest(TStringBuilder() << "Unknown data column: " << dataColumn); + } + } + if (request.GetPrefixColumns() <= 0) { + badRequest("Should be requested on at least one prefix column"); + } + if (request.GetPrefixColumns() > userTable.KeyColumnIds.size()) { + badRequest(TStringBuilder() << "Should not be requested on more than " << userTable.KeyColumnIds.size() << " prefix columns"); + } + + if (trySendBadRequest()) { return; } + // 3. Validating vector index settings TAutoPtr scan; auto createScan = [&] { scan = new TPrefixKMeansScan{ - userTable, request, ev->Sender, std::move(response), + TabletID(), userTable, request, ev->Sender, std::move(response), }; }; MakeScan(request, createScan, badRequest); if (!scan) { - Y_ASSERT(!response); + auto sent = trySendBadRequest(); + Y_ENSURE(sent); return; } + if (const auto* recCard = ScanManager.Get(id)) { + if (recCard->SeqNo == seqNo) { + // do no start one more scan + return; + } + + for (auto scanId : recCard->ScanIds) { + CancelScan(userTable.LocalTid, scanId); + } + ScanManager.Drop(id); + } + TScanOptions scanOpts; scanOpts.SetSnapshotRowVersion(rowVersion); scanOpts.SetResourceBroker("build_index", 10); // TODO(mbkkt) Should be different group? diff --git a/ydb/core/tx/datashard/reshuffle_kmeans.cpp b/ydb/core/tx/datashard/build_index/reshuffle_kmeans.cpp similarity index 76% rename from ydb/core/tx/datashard/reshuffle_kmeans.cpp rename to ydb/core/tx/datashard/build_index/reshuffle_kmeans.cpp index f7db951e60b6..1c1deaedf3ab 100644 --- a/ydb/core/tx/datashard/reshuffle_kmeans.cpp +++ b/ydb/core/tx/datashard/build_index/reshuffle_kmeans.cpp @@ -1,8 +1,8 @@ -#include "datashard_impl.h" #include "kmeans_helper.h" -#include "scan_common.h" -#include "upload_stats.h" -#include "buffer_data.h" +#include "../datashard_impl.h" +#include "../scan_common.h" +#include "../upload_stats.h" +#include "../buffer_data.h" #include #include @@ -38,6 +38,7 @@ class TReshuffleKMeansScanBase: public TActor, public TLead Lead; + ui64 TabletId = 0; ui64 BuildId = 0; ui64 ReadRows = 0; @@ -78,7 +79,7 @@ class TReshuffleKMeansScanBase: public TActor, public return NKikimrServices::TActivity::RESHUFFLE_KMEANS_SCAN_ACTOR; } - TReshuffleKMeansScanBase(const TUserTable& table, TLead&& lead, + TReshuffleKMeansScanBase(ui64 tabletId, const TUserTable& table, TLead&& lead, const NKikimrTxDataShard::TEvReshuffleKMeansRequest& request, const TActorId& responseActorId, TAutoPtr&& response) @@ -88,6 +89,7 @@ class TReshuffleKMeansScanBase: public TActor, public , K{static_cast(request.ClustersSize())} , UploadState{request.GetUpload()} , Lead{std::move(lead)} + , TabletId(tabletId) , BuildId{request.GetId()} , Clusters{request.GetClusters().begin(), request.GetClusters().end()} , TargetTable{request.GetPostingName()} @@ -156,7 +158,11 @@ class TReshuffleKMeansScanBase: public TActor, public } NYql::IssuesToMessage(UploadStatus.Issues, record.MutableIssues()); - LOG_N("Finish " << Debug() << " " << Response->Record.ShortDebugString()); + if (Response->Record.GetStatus() == NKikimrIndexBuilder::DONE) { + LOG_N("Done " << Debug() << " " << Response->Record.ShortDebugString()); + } else { + LOG_E("Failed " << Debug() << " " << Response->Record.ShortDebugString()); + } Send(ResponseActorId, Response.Release()); Driver = nullptr; @@ -171,7 +177,8 @@ class TReshuffleKMeansScanBase: public TActor, public TString Debug() const { - return TStringBuilder() << "TReshuffleKMeansScan Id: " << BuildId << " Parent: " << Parent << " Child: " << Child + return TStringBuilder() << "TReshuffleKMeansScan TabletId: " << TabletId << " Id: " << BuildId + << " Parent: " << Parent << " Child: " << Child << " Target: " << TargetTable << " K: " << K << " Clusters: " << Clusters.size() << " ReadBuf size: " << ReadBuf.Size() << " WriteBuf size: " << WriteBuf.Size(); } @@ -189,8 +196,8 @@ class TReshuffleKMeansScanBase: public TActor, public hFunc(TEvTxUserProxy::TEvUploadRowsResponse, Handle); cFunc(TEvents::TSystem::Wakeup, HandleWakeup); default: - LOG_E("TReshuffleKMeansScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " - << ev->ToString() << " " << Debug()); + LOG_E("StateWork unexpected event type: " << ev->GetTypeRewrite() + << " event: " << ev->ToString() << " " << Debug()); } } @@ -276,9 +283,9 @@ class TReshuffleKMeansScanBase: public TActor, public template class TReshuffleKMeansScan final: public TReshuffleKMeansScanBase, private TCalculation { public: - TReshuffleKMeansScan(const TUserTable& table, TLead&& lead, NKikimrTxDataShard::TEvReshuffleKMeansRequest& request, + TReshuffleKMeansScan(ui64 tabletId, const TUserTable& table, TLead&& lead, NKikimrTxDataShard::TEvReshuffleKMeansRequest& request, const TActorId& responseActorId, TAutoPtr&& response) - : TReshuffleKMeansScanBase{table, std::move(lead), request, responseActorId, std::move(response)} + : TReshuffleKMeansScanBase{tabletId, table, std::move(lead), request, responseActorId, std::move(response)} { this->Dimensions = request.GetSettings().vector_dimension(); LOG_I("Create " << Debug()); @@ -377,14 +384,21 @@ void TDataShard::Handle(TEvDataShard::TEvReshuffleKMeansRequest::TPtr& ev, const void TDataShard::HandleSafe(TEvDataShard::TEvReshuffleKMeansRequest::TPtr& ev, const TActorContext& ctx) { - auto& record = ev->Get()->Record; - const bool needsSnapshot = record.HasSnapshotStep() || record.HasSnapshotTxId(); - TRowVersion rowVersion(record.GetSnapshotStep(), record.GetSnapshotTxId()); - if (!needsSnapshot) { - rowVersion = GetMvccTxVersion(EMvccTxMode::ReadOnly); - } + auto& request = ev->Get()->Record; + const ui64 id = request.GetId(); + auto rowVersion = request.HasSnapshotStep() || request.HasSnapshotTxId() + ? TRowVersion(request.GetSnapshotStep(), request.GetSnapshotTxId()) + : GetMvccTxVersion(EMvccTxMode::ReadOnly); + TScanRecord::TSeqNo seqNo = {request.GetSeqNoGeneration(), request.GetSeqNoRound()}; + + auto response = MakeHolder(); + response->Record.SetId(id); + response->Record.SetTabletId(TabletID()); + response->Record.SetRequestSeqNoGeneration(seqNo.Generation); + response->Record.SetRequestSeqNoRound(seqNo.Round); - LOG_N("Starting TReshuffleKMeansScan " << record.ShortDebugString() + LOG_N("Starting TReshuffleKMeansScan TabletId: " << TabletID() + << " " << request.ShortDebugString() << " row version " << rowVersion); // Note: it's very unlikely that we have volatile txs before this snapshot @@ -392,88 +406,113 @@ void TDataShard::HandleSafe(TEvDataShard::TEvReshuffleKMeansRequest::TPtr& ev, c VolatileTxManager.AttachWaitingSnapshotEvent(rowVersion, std::unique_ptr(ev.Release())); return; } - const ui64 id = record.GetId(); - - auto response = MakeHolder(); - response->Record.SetId(id); - response->Record.SetTabletId(TabletID()); - - TScanRecord::TSeqNo seqNo = {record.GetSeqNoGeneration(), record.GetSeqNoRound()}; - response->Record.SetRequestSeqNoGeneration(seqNo.Generation); - response->Record.SetRequestSeqNoRound(seqNo.Round); auto badRequest = [&](const TString& error) { response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); auto issue = response->Record.AddIssues(); issue->set_severity(NYql::TSeverityIds::S_ERROR); issue->set_message(error); - ctx.Send(ev->Sender, std::move(response)); - response.Reset(); + }; + auto trySendBadRequest = [&] { + if (response->Record.GetStatus() == NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST) { + LOG_E("Rejecting TReshuffleKMeansScan bad request TabletId: " << TabletID() + << " " << request.ShortDebugString() + << " with response " << response->Record.ShortDebugString()); + ctx.Send(ev->Sender, std::move(response)); + return true; + } else { + return false; + } }; - if (const ui64 shardId = record.GetTabletId(); shardId != TabletID()) { - badRequest(TStringBuilder() << "Wrong shard " << shardId << " this is " << TabletID()); - return; + // 1. Validating table and path existence + if (request.GetTabletId() != TabletID()) { + badRequest(TStringBuilder() << "Wrong shard " << request.GetTabletId() << " this is " << TabletID()); } - - const auto pathId = TPathId::FromProto(record.GetPathId()); + if (!IsStateActive()) { + badRequest(TStringBuilder() << "Shard " << TabletID() << " is " << State << " and not ready for requests"); + } + const auto pathId = TPathId::FromProto(request.GetPathId()); const auto* userTableIt = GetUserTables().FindPtr(pathId.LocalPathId); if (!userTableIt) { badRequest(TStringBuilder() << "Unknown table id: " << pathId.LocalPathId); + } + if (trySendBadRequest()) { return; } - Y_ENSURE(*userTableIt); const auto& userTable = **userTableIt; - if (const auto* recCard = ScanManager.Get(id)) { - if (recCard->SeqNo == seqNo) { - // do no start one more scan - return; + // 2. Validating request fields + if (request.HasSnapshotStep() || request.HasSnapshotTxId()) { + const TSnapshotKey snapshotKey(pathId, rowVersion.Step, rowVersion.TxId); + if (!SnapshotManager.FindAvailable(snapshotKey)) { + badRequest(TStringBuilder() << "Unknown snapshot for path id " << pathId.OwnerId << ":" << pathId.LocalPathId + << ", snapshot step is " << snapshotKey.Step << ", snapshot tx is " << snapshotKey.TxId); } + } - for (auto scanId : recCard->ScanIds) { - CancelScan(userTable.LocalTid, scanId); - } - ScanManager.Drop(id); + if (request.GetUpload() != NKikimrTxDataShard::UPLOAD_MAIN_TO_BUILD + && request.GetUpload() != NKikimrTxDataShard::UPLOAD_MAIN_TO_POSTING + && request.GetUpload() != NKikimrTxDataShard::UPLOAD_BUILD_TO_BUILD + && request.GetUpload() != NKikimrTxDataShard::UPLOAD_BUILD_TO_POSTING) + { + badRequest("Wrong upload"); + } + + if (request.ClustersSize() < 1) { + badRequest("Should be requested at least single cluster"); } TCell from, to; - const auto range = CreateRangeFrom(userTable, record.GetParent(), from, to); + const auto range = CreateRangeFrom(userTable, request.GetParent(), from, to); if (range.IsEmptyRange(userTable.KeyColumnTypes)) { badRequest(TStringBuilder() << " requested range doesn't intersect with table range"); - return; } - const TSnapshotKey snapshotKey(pathId, rowVersion.Step, rowVersion.TxId); - if (needsSnapshot && !SnapshotManager.FindAvailable(snapshotKey)) { - badRequest(TStringBuilder() << "no snapshot has been found" << " , path id is " << pathId.OwnerId << ":" - << pathId.LocalPathId << " , snapshot step is " << snapshotKey.Step - << " , snapshot tx is " << snapshotKey.TxId); - return; + if (!request.HasPostingName()) { + badRequest(TStringBuilder() << "Empty posting table name"); } - if (!IsStateActive()) { - badRequest(TStringBuilder() << "Shard " << TabletID() << " is not ready for requests"); - return; + auto tags = GetAllTags(userTable); + if (!tags.contains(request.GetEmbeddingColumn())) { + badRequest(TStringBuilder() << "Unknown embedding column: " << request.GetEmbeddingColumn()); + } + for (auto dataColumn : request.GetDataColumns()) { + if (!tags.contains(dataColumn)) { + badRequest(TStringBuilder() << "Unknown data column: " << dataColumn); + } } - if (record.ClustersSize() < 1) { - badRequest("Should be requested at least single cluster"); + if (trySendBadRequest()) { return; } + // 3. Validating vector index settings TAutoPtr scan; auto createScan = [&] { scan = new TReshuffleKMeansScan{ - userTable, CreateLeadFrom(range), record, ev->Sender, std::move(response), + TabletID(), userTable, CreateLeadFrom(range), request, ev->Sender, std::move(response), }; }; - MakeScan(record, createScan, badRequest); + MakeScan(request, createScan, badRequest); if (!scan) { - Y_ASSERT(!response); + auto sent = trySendBadRequest(); + Y_ENSURE(sent); return; } + if (const auto* recCard = ScanManager.Get(id)) { + if (recCard->SeqNo == seqNo) { + // do no start one more scan + return; + } + + for (auto scanId : recCard->ScanIds) { + CancelScan(userTable.LocalTid, scanId); + } + ScanManager.Drop(id); + } + TScanOptions scanOpts; scanOpts.SetSnapshotRowVersion(rowVersion); scanOpts.SetResourceBroker("build_index", 10); // TODO(mbkkt) Should be different group? diff --git a/ydb/core/tx/datashard/build_index/sample_k.cpp b/ydb/core/tx/datashard/build_index/sample_k.cpp new file mode 100644 index 000000000000..4c99628975fc --- /dev/null +++ b/ydb/core/tx/datashard/build_index/sample_k.cpp @@ -0,0 +1,359 @@ +#include "kmeans_helper.h" +#include "../datashard_impl.h" +#include "../range_ops.h" +#include "../scan_common.h" +#include "../upload_stats.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +namespace NKikimr::NDataShard { + +class TSampleKScan final: public TActor, public NTable::IScan { +protected: + const TAutoPtr Response; + const TActorId ResponseActorId; + + const TTags ScanTags; + const TVector KeyTypes; + + const TSerializedTableRange TableRange; + const TSerializedTableRange RequestedRange; + const ui64 K; + + struct TProbability { + ui64 P = 0; + ui64 I = 0; + + auto operator<=>(const TProbability&) const noexcept = default; + }; + + ui64 TabletId = 0; + ui64 BuildId = 0; + + ui64 ReadRows = 0; + ui64 ReadBytes = 0; + + // We are using binary heap, because we don't want to do batch processing here, + // serialization is more expensive than compare + ui64 MaxProbability = 0; + TReallyFastRng32 Rng; + std::vector MaxRows; + std::vector DataRows; + + IDriver* Driver = nullptr; + +public: + static constexpr NKikimrServices::TActivity::EType ActorActivityType() { + return NKikimrServices::TActivity::SAMPLE_K_SCAN_ACTOR; + } + + TSampleKScan(ui64 tabletId, const TUserTable& table, NKikimrTxDataShard::TEvSampleKRequest& request, + const TActorId& responseActorId, TAutoPtr&& response, + const TSerializedTableRange& range) + : TActor(&TThis::StateWork) + , Response(std::move(response)) + , ResponseActorId(responseActorId) + , ScanTags(BuildTags(table, request.GetColumns())) + , KeyTypes(table.KeyColumnTypes) + , TableRange(table.Range) + , RequestedRange(range) + , K(request.GetK()) + , TabletId(tabletId) + , BuildId(request.GetId()) + , MaxProbability(request.GetMaxProbability()) + , Rng(request.GetSeed()) + { + LOG_I("Create " << Debug()); + } + + ~TSampleKScan() final = default; + + TInitialState Prepare(IDriver* driver, TIntrusiveConstPtr) final { + TActivationContext::AsActorContext().RegisterWithSameMailbox(this); + + LOG_I("Prepare " << Debug()); + + Driver = driver; + + return {EScan::Feed, {}}; + } + + EScan Seek(TLead& lead, ui64 seq) final { + Y_ENSURE(seq == 0); + LOG_D("Seek " << Debug()); + + auto scanRange = Intersect(KeyTypes, RequestedRange.ToTableRange(), TableRange.ToTableRange()); + + if (scanRange.From) { + auto seek = scanRange.InclusiveFrom ? NTable::ESeek::Lower : NTable::ESeek::Upper; + lead.To(ScanTags, scanRange.From, seek); + } else { + lead.To(ScanTags, {}, NTable::ESeek::Lower); + } + + if (scanRange.To) { + lead.Until(scanRange.To, scanRange.InclusiveTo); + } + + return EScan::Feed; + } + + EScan Feed(TArrayRef key, const TRow& row) final { + LOG_T("Feed key " << DebugPrintPoint(KeyTypes, key, *AppData()->TypeRegistry) << " " << Debug()); + ++ReadRows; + ReadBytes += CountBytes(key, row); + + const auto probability = GetProbability(); + if (probability > MaxProbability) { + return EScan::Feed; + } + + if (DataRows.size() < K) { + MaxRows.push_back({probability, DataRows.size()}); + DataRows.emplace_back(TSerializedCellVec::Serialize(*row)); + if (DataRows.size() == K) { + std::make_heap(MaxRows.begin(), MaxRows.end()); + MaxProbability = MaxRows.front().P; + } + } else { + // TODO(mbkkt) use tournament tree to make less compare and swaps + std::pop_heap(MaxRows.begin(), MaxRows.end()); + TSerializedCellVec::Serialize(DataRows[MaxRows.back().I], *row); + MaxRows.back().P = probability; + std::push_heap(MaxRows.begin(), MaxRows.end()); + MaxProbability = MaxRows.front().P; + } + + if (MaxProbability == 0) { + return EScan::Final; + } + return EScan::Feed; + } + + TAutoPtr Finish(EAbort abort) final { + Y_ENSURE(Response); + Response->Record.SetReadRows(ReadRows); + Response->Record.SetReadBytes(ReadBytes); + if (abort == EAbort::None) { + FillResponse(); + } else { + Response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::ABORTED); + } + + if (Response->Record.GetStatus() == NKikimrIndexBuilder::DONE) { + LOG_N("Done " << Debug() << " " << Response->Record.ShortDebugString()); + } else { + LOG_E("Failed " << Debug() << " " << Response->Record.ShortDebugString()); + } + Send(ResponseActorId, Response.Release()); + Driver = nullptr; + PassAway(); + return nullptr; + } + + void Describe(IOutputStream& out) const final { + out << Debug(); + } + + EScan Exhausted() final { + return EScan::Final; + } + + TString Debug() const { + return TStringBuilder() << "TSampleKScan TabletId: " << TabletId << " Id: " << BuildId + << " K: " << K << " Clusters: " << MaxRows.size(); + } + +private: + STFUNC(StateWork) { + switch (ev->GetTypeRewrite()) { + default: + LOG_E("StateWork unexpected event type: " << ev->GetTypeRewrite() + << " event: " << ev->ToString() << " " << Debug()); + } + } + + void FillResponse() { + std::sort(MaxRows.begin(), MaxRows.end()); + auto& record = Response->Record; + for (auto& [p, i] : MaxRows) { + record.AddProbabilities(p); + record.AddRows(std::move(DataRows[i])); + } + record.SetStatus(NKikimrIndexBuilder::EBuildStatus::DONE); + } + + ui64 GetProbability() { + while (true) { + auto p = Rng.GenRand64(); + // We exclude max ui64 from generated probabilities, so we can use this value as initial max + if (Y_LIKELY(p != std::numeric_limits::max())) { + return p; + } + } + } +}; + +class TDataShard::TTxHandleSafeSampleKScan: public NTabletFlatExecutor::TTransactionBase { +public: + TTxHandleSafeSampleKScan(TDataShard* self, TEvDataShard::TEvSampleKRequest::TPtr&& ev) + : TTransactionBase(self) + , Ev(std::move(ev)) { + } + + bool Execute(TTransactionContext&, const TActorContext& ctx) { + Self->HandleSafe(Ev, ctx); + return true; + } + + void Complete(const TActorContext&) { + // nothing + } + +private: + TEvDataShard::TEvSampleKRequest::TPtr Ev; +}; + +void TDataShard::Handle(TEvDataShard::TEvSampleKRequest::TPtr& ev, const TActorContext&) { + Execute(new TTxHandleSafeSampleKScan(this, std::move(ev))); +} + +void TDataShard::HandleSafe(TEvDataShard::TEvSampleKRequest::TPtr& ev, const TActorContext& ctx) { + auto& request = ev->Get()->Record; + const ui64 id = request.GetId(); + auto rowVersion = request.HasSnapshotStep() || request.HasSnapshotTxId() + ? TRowVersion(request.GetSnapshotStep(), request.GetSnapshotTxId()) + : GetMvccTxVersion(EMvccTxMode::ReadOnly); + TScanRecord::TSeqNo seqNo = {request.GetSeqNoGeneration(), request.GetSeqNoRound()}; + + auto response = MakeHolder(); + response->Record.SetId(id); + response->Record.SetTabletId(TabletID()); + response->Record.SetRequestSeqNoGeneration(seqNo.Generation); + response->Record.SetRequestSeqNoRound(seqNo.Round); + + LOG_N("Starting TSampleKScan TabletId: " << TabletID() + << " " << request.ShortDebugString() + << " row version " << rowVersion); + + // Note: it's very unlikely that we have volatile txs before this snapshot + if (VolatileTxManager.HasVolatileTxsAtSnapshot(rowVersion)) { + VolatileTxManager.AttachWaitingSnapshotEvent(rowVersion, std::unique_ptr(ev.Release())); + return; + } + + auto badRequest = [&](const TString& error) { + response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); + auto issue = response->Record.AddIssues(); + issue->set_severity(NYql::TSeverityIds::S_ERROR); + issue->set_message(error); + }; + auto trySendBadRequest = [&] { + if (response->Record.GetStatus() == NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST) { + LOG_E("Rejecting TSampleKScan bad request TabletId: " << TabletID() + << " " << request.ShortDebugString() + << " with response " << response->Record.ShortDebugString()); + ctx.Send(ev->Sender, std::move(response)); + return true; + } else { + return false; + } + }; + + // 1. Validating table and path existence + if (request.GetTabletId() != TabletID()) { + badRequest(TStringBuilder() << "Wrong shard " << request.GetTabletId() << " this is " << TabletID()); + } + if (!IsStateActive()) { + badRequest(TStringBuilder() << "Shard " << TabletID() << " is " << State << " and not ready for requests"); + } + const auto pathId = TPathId::FromProto(request.GetPathId()); + const auto* userTableIt = GetUserTables().FindPtr(pathId.LocalPathId); + if (!userTableIt) { + badRequest(TStringBuilder() << "Unknown table id: " << pathId.LocalPathId); + } + if (trySendBadRequest()) { + return; + } + const auto& userTable = **userTableIt; + + // 2. Validating request fields + if (request.HasSnapshotStep() || request.HasSnapshotTxId()) { + const TSnapshotKey snapshotKey(pathId, rowVersion.Step, rowVersion.TxId); + if (!SnapshotManager.FindAvailable(snapshotKey)) { + badRequest(TStringBuilder() << "Unknown snapshot for path id " << pathId.OwnerId << ":" << pathId.LocalPathId + << ", snapshot step is " << snapshotKey.Step << ", snapshot tx is " << snapshotKey.TxId); + } + } + + if (request.GetK() < 1) { + badRequest("Should be requested on at least one row"); + } + + if (request.GetMaxProbability() <= 0) { + badRequest("Max probability should be positive"); + } + + TSerializedTableRange requestedRange; + requestedRange.Load(request.GetKeyRange()); + auto scanRange = Intersect(userTable.KeyColumnTypes, requestedRange.ToTableRange(), userTable.Range.ToTableRange()); + if (scanRange.IsEmptyRange(userTable.KeyColumnTypes)) { + badRequest(TStringBuilder() << " requested range doesn't intersect with table range" + << " requestedRange: " << DebugPrintRange(userTable.KeyColumnTypes, requestedRange.ToTableRange(), *AppData()->TypeRegistry) + << " tableRange: " << DebugPrintRange(userTable.KeyColumnTypes, userTable.Range.ToTableRange(), *AppData()->TypeRegistry) + << " scanRange: " << DebugPrintRange(userTable.KeyColumnTypes, scanRange, *AppData()->TypeRegistry)); + } + + if (request.ColumnsSize() < 1) { + badRequest("Should be requested at least one column"); + } + auto tags = GetAllTags(userTable); + for (auto column : request.GetColumns()) { + if (!tags.contains(column)) { + badRequest(TStringBuilder() << "Unknown column: " << column); + } + } + + if (trySendBadRequest()) { + return; + } + + // 3. Creating scan + TAutoPtr scan = new TSampleKScan(TabletID(), userTable, + request, ev->Sender, std::move(response), + requestedRange); + + if (const auto* recCard = ScanManager.Get(id)) { + if (recCard->SeqNo == seqNo) { + // do no start one more scan + return; + } + + for (auto scanId : recCard->ScanIds) { + CancelScan(userTable.LocalTid, scanId); + } + ScanManager.Drop(id); + } + + TScanOptions scanOpts; + scanOpts.SetSnapshotRowVersion(rowVersion); + scanOpts.SetResourceBroker("build_index", 10); // TODO(mbkkt) Should be different group? + const auto scanId = QueueScan(userTable.LocalTid, std::move(scan), 0, scanOpts); + ScanManager.Set(id, seqNo).push_back(scanId); +} + +} diff --git a/ydb/core/tx/datashard/build_index/secondary_index.cpp b/ydb/core/tx/datashard/build_index/secondary_index.cpp new file mode 100644 index 000000000000..0b769c47d5d9 --- /dev/null +++ b/ydb/core/tx/datashard/build_index/secondary_index.cpp @@ -0,0 +1,648 @@ +#include "../datashard_impl.h" +#include "../range_ops.h" +#include "../scan_common.h" +#include "../upload_stats.h" +#include "../buffer_data.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +namespace NKikimr::NDataShard { + +#define LOG_N(stream) LOG_NOTICE_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) +#define LOG_T(stream) LOG_TRACE_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) +#define LOG_I(stream) LOG_INFO_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) +#define LOG_D(stream) LOG_DEBUG_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) +#define LOG_W(stream) LOG_WARN_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) +#define LOG_E(stream) LOG_ERROR_S(*TlsActivationContext, NKikimrServices::TX_DATASHARD, stream) + +static std::shared_ptr BuildTypes(const TUserTable& tableInfo, const NKikimrIndexBuilder::TColumnBuildSettings& buildSettings) { + auto types = GetAllTypes(tableInfo); + + Y_ENSURE(buildSettings.columnSize() > 0); + auto result = std::make_shared(); + result->reserve(tableInfo.KeyColumnIds.size() + buildSettings.columnSize()); + + for (const auto& keyColId : tableInfo.KeyColumnIds) { + auto it = tableInfo.Columns.at(keyColId); + Ydb::Type type; + NScheme::ProtoFromTypeInfo(it.Type, type); + result->emplace_back(it.Name, type); + } + for (size_t i = 0; i < buildSettings.columnSize(); i++) { + const auto& column = buildSettings.column(i); + result->emplace_back(column.GetColumnName(), column.default_from_literal().type()); + } + return result; +} + +static std::shared_ptr BuildTypes(const TUserTable& tableInfo, TProtoColumnsCRef indexColumns, TProtoColumnsCRef dataColumns) { + auto types = GetAllTypes(tableInfo); + + auto result = std::make_shared(); + result->reserve(indexColumns.size() + dataColumns.size()); + + for (const auto& colName : indexColumns) { + Ydb::Type type; + NScheme::ProtoFromTypeInfo(types.at(colName), type); + result->emplace_back(colName, type); + } + for (const auto& colName : dataColumns) { + Ydb::Type type; + NScheme::ProtoFromTypeInfo(types.at(colName), type); + result->emplace_back(colName, type); + } + return result; +} + +bool BuildExtraColumns(TVector& cells, const NKikimrIndexBuilder::TColumnBuildSettings& buildSettings, TString& err, TMemoryPool& valueDataPool) { + cells.clear(); + cells.reserve(buildSettings.columnSize()); + for (size_t i = 0; i < buildSettings.columnSize(); i++) { + const auto& column = buildSettings.column(i); + + NScheme::TTypeInfo typeInfo; + i32 typeMod = -1; + Ydb::StatusIds::StatusCode status; + + if (column.default_from_literal().type().has_pg_type()) { + typeMod = column.default_from_literal().type().pg_type().typmod(); + } + + TString unusedtm; + if (!ExtractColumnTypeInfo(typeInfo, unusedtm, column.default_from_literal().type(), status, err)) { + return false; + } + + auto& back = cells.emplace_back(); + if (!CellFromProtoVal(typeInfo, typeMod, &column.default_from_literal().value(), false, back, err, valueDataPool)) { + return false; + } + } + + return true; +} + +template +class TBuildScanUpload: public TActor>, public NTable::IScan { + using TThis = TBuildScanUpload; + using TBase = TActor; + +protected: + const TIndexBuildScanSettings ScanSettings; + + const ui64 BuildIndexId; + const TString TargetTable; + const TScanRecord::TSeqNo SeqNo; + + const ui64 DataShardId; + const TActorId ProgressActorId; + + TTags ScanTags; // first: columns we scan, order as in IndexTable + std::shared_ptr UploadColumnsTypes; // columns types we upload to indexTable + NTxProxy::EUploadRowsMode UploadMode; + + const TTags KeyColumnIds; + const TVector KeyTypes; + + const TSerializedTableRange TableRange; + const TSerializedTableRange RequestedRange; + + IDriver* Driver = nullptr; + + TBufferData ReadBuf; + TBufferData WriteBuf; + TSerializedCellVec LastUploadedKey; + + TActorId Uploader; + ui32 RetryCount = 0; + + TUploadMonStats Stats = TUploadMonStats("tablets", "build_index_upload"); + TUploadStatus UploadStatus; + + TBuildScanUpload(ui64 buildIndexId, + const TString& target, + const TScanRecord::TSeqNo& seqNo, + ui64 dataShardId, + const TActorId& progressActorId, + const TSerializedTableRange& range, + const TUserTable& tableInfo, + const TIndexBuildScanSettings& scanSettings) + : TBase(&TThis::StateWork) + , ScanSettings(scanSettings) + , BuildIndexId(buildIndexId) + , TargetTable(target) + , SeqNo(seqNo) + , DataShardId(dataShardId) + , ProgressActorId(progressActorId) + , KeyColumnIds(tableInfo.KeyColumnIds) + , KeyTypes(tableInfo.KeyColumnTypes) + , TableRange(tableInfo.Range) + , RequestedRange(range) { + } + + template + EScan FeedImpl(TArrayRef key, const TRow& /*row*/, TAddRow&& addRow) { + LOG_T("Feed key " << DebugPrintPoint(KeyTypes, key, *AppData()->TypeRegistry) << " " << Debug()); + + addRow(); + + if (!HasReachedLimits(ReadBuf, ScanSettings)) { + return EScan::Feed; + } + + if (!WriteBuf.IsEmpty()) { + return EScan::Sleep; + } + + ReadBuf.FlushTo(WriteBuf); + + Upload(); + + return EScan::Feed; + } + +public: + static constexpr auto ActorActivityType() { + return Activity; + } + + ~TBuildScanUpload() override = default; + + TInitialState Prepare(IDriver* driver, TIntrusiveConstPtr) override { + TActivationContext::AsActorContext().RegisterWithSameMailbox(this); + + LOG_I("Prepare " << Debug()); + + Driver = driver; + + return {EScan::Feed, {}}; + } + + EScan Seek(TLead& lead, ui64 seq) override { + LOG_T("Seek no " << seq << " " << Debug()); + if (seq) { + if (!WriteBuf.IsEmpty()) { + return EScan::Sleep; + } + + if (!ReadBuf.IsEmpty()) { + ReadBuf.FlushTo(WriteBuf); + Upload(); + return EScan::Sleep; + } + + if (UploadStatus.IsNone()) { + UploadStatus.StatusCode = Ydb::StatusIds::SUCCESS; + UploadStatus.Issues.AddIssue(NYql::TIssue("Shard or requested range is empty")); + } + + return EScan::Final; + } + + auto scanRange = Intersect(KeyTypes, RequestedRange.ToTableRange(), TableRange.ToTableRange()); + + if (scanRange.From) { + auto seek = scanRange.InclusiveFrom ? NTable::ESeek::Lower : NTable::ESeek::Upper; + lead.To(ScanTags, scanRange.From, seek); + } else { + lead.To(ScanTags, {}, NTable::ESeek::Lower); + } + + if (scanRange.To) { + lead.Until(scanRange.To, scanRange.InclusiveTo); + } + + return EScan::Feed; + } + + TAutoPtr Finish(EAbort abort) override { + if (Uploader) { + this->Send(Uploader, new TEvents::TEvPoisonPill); + Uploader = {}; + } + + TAutoPtr progress = new TEvDataShard::TEvBuildIndexProgressResponse; + progress->Record.SetBuildIndexId(BuildIndexId); + progress->Record.SetTabletId(DataShardId); + progress->Record.SetRequestSeqNoGeneration(SeqNo.Generation); + progress->Record.SetRequestSeqNoRound(SeqNo.Round); + + if (abort != EAbort::None) { + progress->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::ABORTED); + UploadStatus.Issues.AddIssue(NYql::TIssue("Aborted by scan host env")); + + LOG_W(Debug()); + } else if (!UploadStatus.IsSuccess()) { + progress->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BUILD_ERROR); + } else { + progress->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::DONE); + } + + UploadStatusToMessage(progress->Record); + + if (progress->Record.GetStatus() == NKikimrIndexBuilder::DONE) { + LOG_N("Done " << Debug() << " " << progress->Record.ShortDebugString()); + } else { + LOG_E("Failed " << Debug() << " " << progress->Record.ShortDebugString()); + } + this->Send(ProgressActorId, progress.Release()); + + Driver = nullptr; + this->PassAway(); + return nullptr; + } + + void UploadStatusToMessage(NKikimrTxDataShard::TEvBuildIndexProgressResponse& msg) { + msg.SetUploadStatus(UploadStatus.StatusCode); + NYql::IssuesToMessage(UploadStatus.Issues, msg.MutableIssues()); + } + + void Describe(IOutputStream& out) const override { + out << Debug(); + } + + TString Debug() const { + return TStringBuilder() << "TBuildIndexScan TabletId: " << DataShardId << " Id: " << BuildIndexId + << ", requested range: " << DebugPrintRange(KeyTypes, RequestedRange.ToTableRange(), *AppData()->TypeRegistry) + << ", last acked point: " << DebugPrintPoint(KeyTypes, LastUploadedKey.GetCells(), *AppData()->TypeRegistry) + << Stats.ToString() + << UploadStatus.ToString(); + } + + EScan PageFault() override { + LOG_T("Page fault" + << " ReadBuf empty: " << ReadBuf.IsEmpty() + << " WriteBuf empty: " << WriteBuf.IsEmpty() + << " " << Debug()); + + if (!ReadBuf.IsEmpty() && WriteBuf.IsEmpty()) { + ReadBuf.FlushTo(WriteBuf); + Upload(); + } + + return EScan::Feed; + } + +private: + STFUNC(StateWork) { + switch (ev->GetTypeRewrite()) { + HFunc(TEvTxUserProxy::TEvUploadRowsResponse, Handle); + CFunc(TEvents::TSystem::Wakeup, HandleWakeup); + default: + LOG_E("TBuildIndexScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " << ev->ToString()); + } + } + + void HandleWakeup(const NActors::TActorContext& /*ctx*/) { + LOG_D("Retry upload " << Debug()); + + if (!WriteBuf.IsEmpty()) { + RetryUpload(); + } + } + + void Handle(TEvTxUserProxy::TEvUploadRowsResponse::TPtr& ev, const TActorContext& ctx) { + LOG_T("Handle TEvUploadRowsResponse " + << Debug() + << " Uploader: " << Uploader.ToString() + << " ev->Sender: " << ev->Sender.ToString()); + + if (Uploader) { + Y_ENSURE(Uploader == ev->Sender, + "Mismatch" + << " Uploader: " << Uploader.ToString() + << " ev->Sender: " << ev->Sender.ToString()); + } else { + Y_ENSURE(Driver == nullptr); + return; + } + + UploadStatus.StatusCode = ev->Get()->Status; + UploadStatus.Issues.AddIssues(ev->Get()->Issues); + + if (UploadStatus.IsSuccess()) { + Stats.Aggr(&WriteBuf); + LastUploadedKey = WriteBuf.ExtractLastKey(); + + //send progress + TAutoPtr progress = new TEvDataShard::TEvBuildIndexProgressResponse; + progress->Record.SetBuildIndexId(BuildIndexId); + progress->Record.SetTabletId(DataShardId); + progress->Record.SetRequestSeqNoGeneration(SeqNo.Generation); + progress->Record.SetRequestSeqNoRound(SeqNo.Round); + + // TODO(mbkkt) ReleaseBuffer isn't possible, we use LastUploadedKey for logging + progress->Record.SetLastKeyAck(LastUploadedKey.GetBuffer()); + progress->Record.SetRowsDelta(WriteBuf.GetRows()); + progress->Record.SetBytesDelta(WriteBuf.GetBytes()); + WriteBuf.Clear(); + + progress->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::IN_PROGRESS); + UploadStatusToMessage(progress->Record); + + this->Send(ProgressActorId, progress.Release()); + + if (HasReachedLimits(ReadBuf, ScanSettings)) { + ReadBuf.FlushTo(WriteBuf); + Upload(); + } + + Driver->Touch(EScan::Feed); + return; + } + + if (RetryCount < ScanSettings.GetMaxBatchRetries() && UploadStatus.IsRetriable()) { + LOG_N("Got retriable error, " << Debug()); + + ctx.Schedule(GetRetryWakeupTimeoutBackoff(RetryCount), new TEvents::TEvWakeup()); + return; + } + + LOG_N("Got error, abort scan, " << Debug()); + + Driver->Touch(EScan::Final); + } + + void RetryUpload() { + Upload(true); + } + + void Upload(bool isRetry = false) { + if (isRetry) { + ++RetryCount; + } else { + RetryCount = 0; + } + + LOG_D("Upload, last key " << DebugPrintPoint(KeyTypes, WriteBuf.GetLastKey().GetCells(), *AppData()->TypeRegistry) << " " << Debug()); + + auto actor = NTxProxy::CreateUploadRowsInternal( + this->SelfId(), TargetTable, + UploadColumnsTypes, + WriteBuf.GetRowsData(), + UploadMode, + true /*writeToPrivateTable*/); + + Uploader = this->Register(actor); + } +}; + +class TBuildIndexScan final: public TBuildScanUpload { + const ui32 TargetDataColumnPos; // positon of first data column in target table + +public: + TBuildIndexScan(ui64 buildIndexId, + const TString& target, + const TScanRecord::TSeqNo& seqNo, + ui64 dataShardId, + const TActorId& progressActorId, + const TSerializedTableRange& range, + TProtoColumnsCRef targetIndexColumns, + TProtoColumnsCRef targetDataColumns, + const TUserTable& tableInfo, + const TIndexBuildScanSettings& scanSettings) + : TBuildScanUpload(buildIndexId, target, seqNo, dataShardId, progressActorId, range, tableInfo, scanSettings) + , TargetDataColumnPos(targetIndexColumns.size()) { + ScanTags = BuildTags(tableInfo, targetIndexColumns, targetDataColumns); + UploadColumnsTypes = BuildTypes(tableInfo, targetIndexColumns, targetDataColumns); + UploadMode = NTxProxy::EUploadRowsMode::WriteToTableShadow; + } + + EScan Feed(TArrayRef key, const TRow& row) final { + return FeedImpl(key, row, [&] { + const auto rowCells = *row; + + ReadBuf.AddRow( + TSerializedCellVec(rowCells.Slice(0, TargetDataColumnPos)), + TSerializedCellVec::Serialize(rowCells.Slice(TargetDataColumnPos)), + TSerializedCellVec(key)); + }); + } +}; + +class TBuildColumnsScan final: public TBuildScanUpload { + TString ValueSerialized; + +public: + TBuildColumnsScan(ui64 buildIndexId, + const TString& target, + const TScanRecord::TSeqNo& seqNo, + ui64 dataShardId, + const TActorId& progressActorId, + const TSerializedTableRange& range, + const NKikimrIndexBuilder::TColumnBuildSettings& columnBuildSettings, + const TUserTable& tableInfo, + const TIndexBuildScanSettings& scanSettings) + : TBuildScanUpload(buildIndexId, target, seqNo, dataShardId, progressActorId, range, tableInfo, scanSettings) { + Y_ENSURE(columnBuildSettings.columnSize() > 0); + UploadColumnsTypes = BuildTypes(tableInfo, columnBuildSettings); + UploadMode = NTxProxy::EUploadRowsMode::UpsertIfExists; + + TMemoryPool valueDataPool(256); + TVector cells; + TString err; + Y_ENSURE(BuildExtraColumns(cells, columnBuildSettings, err, valueDataPool)); + ValueSerialized = TSerializedCellVec::Serialize(cells); + } + + EScan Feed(TArrayRef key, const TRow& row) final { + return FeedImpl(key, row, [&] { + TSerializedCellVec pk(key); + auto pkTarget = pk; + auto valueTarget = ValueSerialized; + ReadBuf.AddRow( + std::move(pkTarget), + std::move(valueTarget), + std::move(pk)); + }); + } +}; + +TAutoPtr CreateBuildIndexScan( + ui64 buildIndexId, + TString target, + const TScanRecord::TSeqNo& seqNo, + ui64 dataShardId, + const TActorId& progressActorId, + const TSerializedTableRange& range, + TProtoColumnsCRef targetIndexColumns, + TProtoColumnsCRef targetDataColumns, + const NKikimrIndexBuilder::TColumnBuildSettings& columnsToBuild, + const TUserTable& tableInfo, + const TIndexBuildScanSettings& scanSettings) { + if (columnsToBuild.columnSize() > 0) { + return new TBuildColumnsScan( + buildIndexId, target, seqNo, dataShardId, progressActorId, range, columnsToBuild, tableInfo, scanSettings); + } + return new TBuildIndexScan( + buildIndexId, target, seqNo, dataShardId, progressActorId, range, targetIndexColumns, targetDataColumns, tableInfo, scanSettings); +} + +class TDataShard::TTxHandleSafeBuildIndexScan: public NTabletFlatExecutor::TTransactionBase { +public: + TTxHandleSafeBuildIndexScan(TDataShard* self, TEvDataShard::TEvBuildIndexCreateRequest::TPtr&& ev) + : TTransactionBase(self) + , Ev(std::move(ev)) { + } + + bool Execute(TTransactionContext&, const TActorContext& ctx) { + Self->HandleSafe(Ev, ctx); + return true; + } + + void Complete(const TActorContext&) { + // nothing + } + +private: + TEvDataShard::TEvBuildIndexCreateRequest::TPtr Ev; +}; + +void TDataShard::Handle(TEvDataShard::TEvBuildIndexCreateRequest::TPtr& ev, const TActorContext&) { + Execute(new TTxHandleSafeBuildIndexScan(this, std::move(ev))); +} + +void TDataShard::HandleSafe(TEvDataShard::TEvBuildIndexCreateRequest::TPtr& ev, const TActorContext& ctx) { + auto& request = ev->Get()->Record; + const ui64 id = request.GetBuildIndexId(); + TRowVersion rowVersion(request.GetSnapshotStep(), request.GetSnapshotTxId()); + TScanRecord::TSeqNo seqNo = {request.GetSeqNoGeneration(), request.GetSeqNoRound()}; + + auto response = MakeHolder(); + response->Record.SetBuildIndexId(request.GetBuildIndexId()); + response->Record.SetTabletId(TabletID()); + response->Record.SetRequestSeqNoGeneration(seqNo.Generation); + response->Record.SetRequestSeqNoRound(seqNo.Round); + + LOG_N("Starting TBuildIndexScan TabletId: " << TabletID() + << " " << request.ShortDebugString() + << " row version " << rowVersion); + + // Note: it's very unlikely that we have volatile txs before this snapshot + if (VolatileTxManager.HasVolatileTxsAtSnapshot(rowVersion)) { + VolatileTxManager.AttachWaitingSnapshotEvent(rowVersion, std::unique_ptr(ev.Release())); + return; + } + + auto badRequest = [&](const TString& error) { + response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); + auto issue = response->Record.AddIssues(); + issue->set_severity(NYql::TSeverityIds::S_ERROR); + issue->set_message(error); + }; + auto trySendBadRequest = [&] { + if (response->Record.GetStatus() == NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST) { + LOG_E("Rejecting TBuildIndexScan bad request TabletId: " << TabletID() + << " " << request.ShortDebugString() + << " with response " << response->Record.ShortDebugString()); + ctx.Send(ev->Sender, std::move(response)); + return true; + } else { + return false; + } + }; + + // 1. Validating table and path existence + const auto tableId = TTableId(request.GetOwnerId(), request.GetPathId()); + if (request.GetTabletId() != TabletID()) { + badRequest(TStringBuilder() << "Wrong shard " << request.GetTabletId() << " this is " << TabletID()); + } + if (!IsStateActive()) { + badRequest(TStringBuilder() << "Shard " << TabletID() << " is " << State << " and not ready for requests"); + } + if (!GetUserTables().contains(tableId.PathId.LocalPathId)) { + badRequest(TStringBuilder() << "Unknown table id: " << tableId.PathId.LocalPathId); + } + if (trySendBadRequest()) { + return; + } + const auto& userTable = *GetUserTables().at(tableId.PathId.LocalPathId); + + // 2. Validating request fields + if (!request.HasSnapshotStep() || !request.HasSnapshotTxId()) { + badRequest(TStringBuilder() << "Empty snapshot"); + } + const TSnapshotKey snapshotKey(tableId.PathId, rowVersion.Step, rowVersion.TxId); + if (!SnapshotManager.FindAvailable(snapshotKey)) { + badRequest(TStringBuilder() << "Unknown snapshot for path id " << tableId.PathId.OwnerId << ":" << tableId.PathId.LocalPathId + << ", snapshot step is " << snapshotKey.Step << ", snapshot tx is " << snapshotKey.TxId); + } + + TSerializedTableRange requestedRange; + requestedRange.Load(request.GetKeyRange()); + auto scanRange = Intersect(userTable.KeyColumnTypes, requestedRange.ToTableRange(), userTable.Range.ToTableRange()); + if (scanRange.IsEmptyRange(userTable.KeyColumnTypes)) { + badRequest(TStringBuilder() << " requested range doesn't intersect with table range" + << " requestedRange: " << DebugPrintRange(userTable.KeyColumnTypes, requestedRange.ToTableRange(), *AppData()->TypeRegistry) + << " tableRange: " << DebugPrintRange(userTable.KeyColumnTypes, userTable.Range.ToTableRange(), *AppData()->TypeRegistry) + << " scanRange: " << DebugPrintRange(userTable.KeyColumnTypes, scanRange, *AppData()->TypeRegistry)); + } + + if (!request.HasTargetName()) { + badRequest(TStringBuilder() << "Empty target table name"); + } + + auto tags = GetAllTags(userTable); + for (auto column : request.GetIndexColumns()) { + if (!tags.contains(column)) { + badRequest(TStringBuilder() << "Unknown index column: " << column); + } + } + for (auto column : request.GetDataColumns()) { + if (!tags.contains(column)) { + badRequest(TStringBuilder() << "Unknown data column: " << column); + } + } + + if (trySendBadRequest()) { + return; + } + + // 3. Creating scan + TAutoPtr scan = CreateBuildIndexScan(id, + request.GetTargetName(), + seqNo, + request.GetTabletId(), + ev->Sender, + requestedRange, + request.GetIndexColumns(), + request.GetDataColumns(), + request.GetColumnBuildSettings(), + userTable, + request.GetScanSettings()); + + if (const auto* recCard = ScanManager.Get(id)) { + if (recCard->SeqNo == seqNo) { + // do no start one more scan + return; + } + + for (auto scanId : recCard->ScanIds) { + CancelScan(userTable.LocalTid, scanId); + } + ScanManager.Drop(id); + } + + TScanOptions scanOpts; + scanOpts.SetSnapshotRowVersion(rowVersion); + scanOpts.SetResourceBroker("build_index", 10); + const auto scanId = QueueScan(userTable.LocalTid, std::move(scan), 0, scanOpts); + ScanManager.Set(id, seqNo).push_back(scanId); +} + +} diff --git a/ydb/core/tx/datashard/build_index/ut/ut_local_kmeans.cpp b/ydb/core/tx/datashard/build_index/ut/ut_local_kmeans.cpp new file mode 100644 index 000000000000..b8743ac4dd14 --- /dev/null +++ b/ydb/core/tx/datashard/build_index/ut/ut_local_kmeans.cpp @@ -0,0 +1,894 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace NKikimr { +using namespace Tests; +using Ydb::Table::VectorIndexSettings; +using namespace NTableIndex::NTableVectorKmeansTreeIndex; + +static std::atomic sId = 1; +static const TString kMainTable = "/Root/table-main"; +static const TString kLevelTable = "/Root/table-level"; +static const TString kPostingTable = "/Root/table-posting"; + +Y_UNIT_TEST_SUITE(TTxDataShardLocalKMeansScan) { + + static void DoBadRequest(Tests::TServer::TPtr server, TActorId sender, + std::function setupRequest, + TString expectedError, bool expectedErrorSubstring = false) + { + auto id = sId.fetch_add(1, std::memory_order_relaxed); + auto& runtime = *server->GetRuntime(); + auto snapshot = CreateVolatileSnapshot(server, {kMainTable}); + auto datashards = GetTableShards(server, sender, kMainTable); + TTableId tableId = ResolveTableId(server, sender, kMainTable); + + TStringBuilder data; + TString err; + UNIT_ASSERT(datashards.size() == 1); + + auto ev = std::make_unique(); + auto& rec = ev->Record; + rec.SetId(1); + + rec.SetSeqNoGeneration(id); + rec.SetSeqNoRound(1); + + rec.SetTabletId(datashards[0]); + tableId.PathId.ToProto(rec.MutablePathId()); + + rec.SetSnapshotTxId(snapshot.TxId); + rec.SetSnapshotStep(snapshot.Step); + + VectorIndexSettings settings; + settings.set_vector_dimension(2); + settings.set_vector_type(VectorIndexSettings::VECTOR_TYPE_FLOAT); + settings.set_metric(VectorIndexSettings::DISTANCE_COSINE); + *rec.MutableSettings() = settings; + + rec.SetK(2); + rec.SetSeed(1337); + + rec.SetUpload(NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING); + + rec.SetNeedsRounds(3); + + rec.SetParentFrom(0); + rec.SetParentTo(0); + rec.SetChild(1); + + rec.SetEmbeddingColumn("embedding"); + + rec.SetLevelName(kLevelTable); + rec.SetPostingName(kPostingTable); + + setupRequest(rec); + + runtime.SendToPipe(datashards[0], sender, ev.release(), 0, GetPipeConfigWithRetries()); + + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); + + NYql::TIssues issues; + NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); + if (expectedErrorSubstring) { + UNIT_ASSERT_STRING_CONTAINS(issues.ToOneLineString(), expectedError); + } else { + UNIT_ASSERT_VALUES_EQUAL(issues.ToOneLineString(), expectedError); + } + } + + static std::tuple DoLocalKMeans( + Tests::TServer::TPtr server, TActorId sender, NTableIndex::TClusterId parentFrom, NTableIndex::TClusterId parentTo, ui64 seed, ui64 k, + NKikimrTxDataShard::EKMeansState upload, VectorIndexSettings::VectorType type, + VectorIndexSettings::Metric metric, ui32 maxBatchRows = 50000) + { + auto id = sId.fetch_add(1, std::memory_order_relaxed); + auto& runtime = *server->GetRuntime(); + auto snapshot = CreateVolatileSnapshot(server, {kMainTable}); + auto datashards = GetTableShards(server, sender, kMainTable); + TTableId tableId = ResolveTableId(server, sender, kMainTable); + + TString err; + + for (auto tid : datashards) { + auto ev1 = std::make_unique(); + auto ev2 = std::make_unique(); + auto fill = [&](std::unique_ptr& ev) { + auto& rec = ev->Record; + rec.SetId(1); + + rec.SetSeqNoGeneration(id); + rec.SetSeqNoRound(1); + + rec.SetTabletId(tid); + tableId.PathId.ToProto(rec.MutablePathId()); + + rec.SetSnapshotTxId(snapshot.TxId); + rec.SetSnapshotStep(snapshot.Step); + + VectorIndexSettings settings; + settings.set_vector_dimension(2); + settings.set_vector_type(type); + settings.set_metric(metric); + *rec.MutableSettings() = settings; + + rec.SetK(k); + rec.SetSeed(seed); + + rec.SetUpload(upload); + + rec.SetNeedsRounds(300); + + rec.SetParentFrom(parentFrom); + rec.SetParentTo(parentTo); + rec.SetChild(parentTo + 1); + + rec.SetEmbeddingColumn("embedding"); + rec.AddDataColumns("data"); + + rec.SetLevelName(kLevelTable); + rec.SetPostingName(kPostingTable); + + rec.MutableScanSettings()->SetMaxBatchRows(maxBatchRows); + }; + fill(ev1); + fill(ev2); + + runtime.SendToPipe(tid, sender, ev1.release(), 0, GetPipeConfigWithRetries()); + runtime.SendToPipe(tid, sender, ev2.release(), 0, GetPipeConfigWithRetries()); + + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + + NYql::TIssues issues; + NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); + UNIT_ASSERT_EQUAL_C(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::DONE, + issues.ToOneLineString()); + } + + auto level = ReadShardedTable(server, kLevelTable); + auto posting = ReadShardedTable(server, kPostingTable); + Cerr << "Level:" << Endl; + Cerr << level << Endl; + Cerr << "Posting:" << Endl; + Cerr << posting << Endl; + return {std::move(level), std::move(posting)}; + } + + static void DropTable(Tests::TServer::TPtr server, TActorId sender, const TString& name) + { + ui64 txId = AsyncDropTable(server, sender, "/Root", name); + WaitTxNotification(server, sender, txId); + } + + static void CreateMainTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) + { + options.AllowSystemColumnNames(false); + options.Columns({ + {"key", "Uint32", true, true}, + {"embedding", "String", false, false}, + {"data", "String", false, false}, + }); + CreateShardedTable(server, sender, "/Root", "table-main", options); + } + + static void CreateLevelTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) + { + options.AllowSystemColumnNames(true); + options.Columns({ + {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, + {IdColumn, NTableIndex::ClusterIdTypeName, true, true}, + {CentroidColumn, "String", false, true}, + }); + CreateShardedTable(server, sender, "/Root", "table-level", options); + } + + static void CreatePostingTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) + { + options.AllowSystemColumnNames(true); + options.Columns({ + {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, + {"key", "Uint32", true, true}, + {"data", "String", false, false}, + }); + CreateShardedTable(server, sender, "/Root", "table-posting", options); + } + + static void CreateBuildTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options, const TString& name) + { + options.AllowSystemColumnNames(true); + options.Columns({ + {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, + {"key", "Uint32", true, true}, + {"embedding", "String", false, false}, + {"data", "String", false, false}, + }); + CreateShardedTable(server, sender, "/Root", name, options); + } + + Y_UNIT_TEST (BadRequest) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + CreateMainTable(server, sender, options); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetTabletId(0); + }, TStringBuilder() << "{
: Error: Wrong shard 0 this is " << GetTableShards(server, sender, kMainTable)[0] << " }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + TPathId(0, 0).ToProto(request.MutablePathId()); + }, "{
: Error: Unknown table id: 0 }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetSnapshotStep(request.GetSnapshotStep() + 1); + }, "Error: Unknown snapshot", true); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetSnapshotTxId(request.GetSnapshotTxId() + 1); + }, "Error: Unknown snapshot", true); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.MutableSettings()->set_vector_type(VectorIndexSettings::VECTOR_TYPE_UNSPECIFIED); + }, "{
: Error: Wrong vector type }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.MutableSettings()->set_vector_type(VectorIndexSettings::VECTOR_TYPE_BIT); + }, "{
: Error: TODO(mbkkt) bit vector type is not supported }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.MutableSettings()->set_metric(VectorIndexSettings::METRIC_UNSPECIFIED); + }, "{
: Error: Wrong similarity }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetUpload(NKikimrTxDataShard::UNSPECIFIED); + }, "{
: Error: Wrong upload }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetUpload(NKikimrTxDataShard::SAMPLE); + }, "{
: Error: Wrong upload }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetK(0); + }, "{
: Error: Should be requested partition on at least two rows }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetK(1); + }, "{
: Error: Should be requested partition on at least two rows }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetParentFrom(100); + request.SetParentTo(99); + }, "{
: Error: Parent from 100 should be less or equal to parent to 99 }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.ClearLevelName(); + }, "{
: Error: Empty level table name }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.ClearPostingName(); + }, "{
: Error: Empty posting table name }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetEmbeddingColumn("some"); + }, "{
: Error: Unknown embedding column: some }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.AddDataColumns("some"); + }, "{
: Error: Unknown data column: some }"); + + // test multiple issues: + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvLocalKMeansRequest& request) { + request.SetK(1); + request.SetEmbeddingColumn("some"); + }, "[ {
: Error: Should be requested partition on at least two rows } {
: Error: Unknown embedding column: some } ]"); + } + + Y_UNIT_TEST (MainToPosting) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateMainTable(server, sender, options); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (key, embedding, data) + VALUES )" + "(1, \"\x30\x30\3\", \"one\")," + "(2, \"\x31\x31\3\", \"two\")," + "(3, \"\x32\x32\3\", \"three\")," + "(4, \"\x65\x65\3\", \"four\")," + "(5, \"\x75\x75\3\", \"five\");"); + + auto create = [&] { + CreateLevelTable(server, sender, options); + CreatePostingTable(server, sender, options); + }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-level"); + DropTable(server, sender, "table-posting"); + create(); + }; + + ui64 seed, k; + k = 2; + + seed = 0; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = mm\3\n" + "__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = 11\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, data = four\n" + "__ydb_parent = 1, key = 5, data = five\n" + "__ydb_parent = 2, key = 1, data = one\n" + "__ydb_parent = 2, key = 2, data = two\n" + "__ydb_parent = 2, key = 3, data = three\n"); + recreate(); + } + + seed = 111; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = 11\3\n" + "__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = mm\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n" + "__ydb_parent = 1, key = 2, data = two\n" + "__ydb_parent = 1, key = 3, data = three\n" + "__ydb_parent = 2, key = 4, data = four\n" + "__ydb_parent = 2, key = 5, data = five\n"); + recreate(); + } + seed = 32; + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, + VectorIndexSettings::DISTANCE_COSINE}) + { + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = II\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n" + "__ydb_parent = 1, key = 2, data = two\n" + "__ydb_parent = 1, key = 3, data = three\n" + "__ydb_parent = 1, key = 4, data = four\n" + "__ydb_parent = 1, key = 5, data = five\n"); + recreate(); + } + } + + Y_UNIT_TEST (MainToBuild) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateMainTable(server, sender, options); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (key, embedding, data) + VALUES )" + "(1, \"\x30\x30\3\", \"one\")," + "(2, \"\x31\x31\3\", \"two\")," + "(3, \"\x32\x32\3\", \"three\")," + "(4, \"\x65\x65\3\", \"four\")," + "(5, \"\x75\x75\3\", \"five\");"); + + auto create = [&] { + CreateLevelTable(server, sender, options); + CreateBuildTable(server, sender, options, "table-posting"); + }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-level"); + DropTable(server, sender, "table-posting"); + create(); + }; + + ui64 seed, k; + k = 2; + + seed = 0; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = mm\3\n" + "__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = 11\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 1, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 2, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 2, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 2, key = 3, embedding = \x32\x32\3, data = three\n"); + recreate(); + } + + seed = 111; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = 11\3\n" + "__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = mm\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 2, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 2, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + seed = 32; + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, + VectorIndexSettings::DISTANCE_COSINE}) + { + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = II\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 1, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 1, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + } + + Y_UNIT_TEST (BuildToPosting) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateBuildTable(server, sender, options, "table-main"); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (__ydb_parent, key, embedding, data) + VALUES )" + "(39, 1, \"\x30\x30\3\", \"one\")," + "(40, 1, \"\x30\x30\3\", \"one\")," + "(40, 2, \"\x31\x31\3\", \"two\")," + "(40, 3, \"\x32\x32\3\", \"three\")," + "(40, 4, \"\x65\x65\3\", \"four\")," + "(40, 5, \"\x75\x75\3\", \"five\")," + "(41, 5, \"\x75\x75\3\", \"five\");"); + + auto create = [&] { + CreateLevelTable(server, sender, options); + CreatePostingTable(server, sender, options); + }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-level"); + DropTable(server, sender, "table-posting"); + create(); + }; + + ui64 seed, k; + k = 2; + + seed = 0; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, data = four\n" + "__ydb_parent = 41, key = 5, data = five\n" + "__ydb_parent = 42, key = 1, data = one\n" + "__ydb_parent = 42, key = 2, data = two\n" + "__ydb_parent = 42, key = 3, data = three\n"); + recreate(); + } + + seed = 111; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n" + "__ydb_parent = 41, key = 2, data = two\n" + "__ydb_parent = 41, key = 3, data = three\n" + "__ydb_parent = 42, key = 4, data = four\n" + "__ydb_parent = 42, key = 5, data = five\n"); + recreate(); + } + seed = 32; + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, + VectorIndexSettings::DISTANCE_COSINE}) + { + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n" + "__ydb_parent = 41, key = 2, data = two\n" + "__ydb_parent = 41, key = 3, data = three\n" + "__ydb_parent = 41, key = 4, data = four\n" + "__ydb_parent = 41, key = 5, data = five\n"); + recreate(); + } + } + + Y_UNIT_TEST (BuildToBuild) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateBuildTable(server, sender, options, "table-main"); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (__ydb_parent, key, embedding, data) + VALUES )" + "(39, 1, \"\x30\x30\3\", \"one\")," + "(40, 1, \"\x30\x30\3\", \"one\")," + "(40, 2, \"\x31\x31\3\", \"two\")," + "(40, 3, \"\x32\x32\3\", \"three\")," + "(40, 4, \"\x65\x65\3\", \"four\")," + "(40, 5, \"\x75\x75\3\", \"five\")," + "(41, 5, \"\x75\x75\3\", \"five\");"); + + auto create = [&] { + CreateLevelTable(server, sender, options); + CreateBuildTable(server, sender, options, "table-posting"); + }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-level"); + DropTable(server, sender, "table-posting"); + create(); + }; + + ui64 seed, k; + k = 2; + + seed = 0; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 41, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 42, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 42, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 42, key = 3, embedding = \x32\x32\3, data = three\n"); + recreate(); + } + + seed = 111; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 42, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 42, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + seed = 32; + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, + VectorIndexSettings::DISTANCE_COSINE}) + { + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); + UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 41, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 41, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + } + + Y_UNIT_TEST (BuildToBuild_Ranges) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateBuildTable(server, sender, options, "table-main"); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (__ydb_parent, key, embedding, data) + VALUES )" + "(39, 1, \"\x30\x30\3\", \"one\")," + "(39, 2, \"\x32\x32\3\", \"two\")," + "(40, 1, \"\x30\x30\3\", \"one\")," + "(40, 2, \"\x31\x31\3\", \"two\")," + "(40, 3, \"\x32\x32\3\", \"three\")," + "(40, 4, \"\x65\x65\3\", \"four\")," + "(40, 5, \"\x75\x75\3\", \"five\")," + "(41, 5, \"\x75\x75\3\", \"five2\")," + "(41, 6, \"\x76\x76\3\", \"six\");"); + + auto create = [&] { + CreateLevelTable(server, sender, options); + CreateBuildTable(server, sender, options, "table-posting"); + }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-level"); + DropTable(server, sender, "table-posting"); + create(); + }; + + { // ParentFrom = 39 ParentTo = 39 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 39, 39, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 39, __ydb_id = 40, __ydb_centroid = 00\3\n" + "__ydb_parent = 39, __ydb_id = 41, __ydb_centroid = 22\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 40, key = 1, embedding = 00\3, data = one\n" + "__ydb_parent = 41, key = 2, embedding = 22\3, data = two\n"); + recreate(); + } + } + + { // ParentFrom = 40 ParentTo = 40 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 40, 40, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 42, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 42, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + } + + { // ParentFrom = 41 ParentTo = 41 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 41, 41, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 41, __ydb_id = 42, __ydb_centroid = uu\3\n" + "__ydb_parent = 41, __ydb_id = 43, __ydb_centroid = vv\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 42, key = 5, embedding = uu\3, data = five2\n" + "__ydb_parent = 43, key = 6, embedding = vv\3, data = six\n"); + recreate(); + } + } + + { // ParentFrom = 39 ParentTo = 40 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 39, 40, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 39, __ydb_id = 41, __ydb_centroid = 00\3\n" + "__ydb_parent = 39, __ydb_id = 42, __ydb_centroid = 22\3\n" + "__ydb_parent = 40, __ydb_id = 43, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 44, __ydb_centroid = mm\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 1, embedding = 00\3, data = one\n" + "__ydb_parent = 42, key = 2, embedding = 22\3, data = two\n" + "__ydb_parent = 43, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 43, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 43, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 44, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 44, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + } + + { // ParentFrom = 40 ParentTo = 41 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 40, 41, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 43, __ydb_centroid = mm\3\n" + "__ydb_parent = 41, __ydb_id = 44, __ydb_centroid = uu\3\n" + "__ydb_parent = 41, __ydb_id = 45, __ydb_centroid = vv\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 42, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 42, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 42, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 43, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 43, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 44, key = 5, embedding = uu\3, data = five2\n" + "__ydb_parent = 45, key = 6, embedding = vv\3, data = six\n"); + recreate(); + } + } + + { // ParentFrom = 39 ParentTo = 41 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 39, 41, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 39, __ydb_id = 42, __ydb_centroid = 00\3\n" + "__ydb_parent = 39, __ydb_id = 43, __ydb_centroid = 22\3\n" + "__ydb_parent = 40, __ydb_id = 44, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 45, __ydb_centroid = mm\3\n" + "__ydb_parent = 41, __ydb_id = 46, __ydb_centroid = uu\3\n" + "__ydb_parent = 41, __ydb_id = 47, __ydb_centroid = vv\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 42, key = 1, embedding = 00\3, data = one\n" + "__ydb_parent = 43, key = 2, embedding = 22\3, data = two\n" + "__ydb_parent = 44, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 44, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 44, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 45, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 45, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 46, key = 5, embedding = uu\3, data = five2\n" + "__ydb_parent = 47, key = 6, embedding = vv\3, data = six\n"); + recreate(); + } + } + + { // ParentFrom = 30 ParentTo = 50 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 30, 50, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 39, __ydb_id = 69, __ydb_centroid = 00\3\n" + "__ydb_parent = 39, __ydb_id = 70, __ydb_centroid = 22\3\n" + "__ydb_parent = 40, __ydb_id = 71, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 72, __ydb_centroid = mm\3\n" + "__ydb_parent = 41, __ydb_id = 73, __ydb_centroid = uu\3\n" + "__ydb_parent = 41, __ydb_id = 74, __ydb_centroid = vv\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 69, key = 1, embedding = 00\3, data = one\n" + "__ydb_parent = 70, key = 2, embedding = 22\3, data = two\n" + "__ydb_parent = 71, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 71, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 71, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 72, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 72, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 73, key = 5, embedding = uu\3, data = five2\n" + "__ydb_parent = 74, key = 6, embedding = vv\3, data = six\n"); + recreate(); + } + } + + { // ParentFrom = 30 ParentTo = 31 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 30, 31, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, ""); + UNIT_ASSERT_VALUES_EQUAL(posting, ""); + recreate(); + } + } + + { // ParentFrom = 100 ParentTo = 101 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 100, 101, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, ""); + UNIT_ASSERT_VALUES_EQUAL(posting, ""); + recreate(); + } + } + } +} + +} diff --git a/ydb/core/tx/datashard/build_index/ut/ut_prefix_kmeans.cpp b/ydb/core/tx/datashard/build_index/ut/ut_prefix_kmeans.cpp new file mode 100644 index 000000000000..883c4c705665 --- /dev/null +++ b/ydb/core/tx/datashard/build_index/ut/ut_prefix_kmeans.cpp @@ -0,0 +1,612 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace NKikimr { +using namespace Tests; +using Ydb::Table::VectorIndexSettings; +using namespace NTableIndex::NTableVectorKmeansTreeIndex; + +static std::atomic sId = 1; +static const TString kMainTable = "/Root/table-main"; +static const TString kPrefixTable = "/Root/table-prefix"; +static const TString kLevelTable = "/Root/table-level"; +static const TString kPostingTable = "/Root/table-posting"; + +Y_UNIT_TEST_SUITE (TTxDataShardPrefixKMeansScan) { + + static void DoBadRequest(Tests::TServer::TPtr server, TActorId sender, + std::function setupRequest, + TString expectedError, bool expectedErrorSubstring = false) + { + auto id = sId.fetch_add(1, std::memory_order_relaxed); + auto& runtime = *server->GetRuntime(); + auto datashards = GetTableShards(server, sender, kMainTable); + TTableId tableId = ResolveTableId(server, sender, kMainTable); + + TStringBuilder data; + TString err; + UNIT_ASSERT(datashards.size() == 1); + + auto ev = std::make_unique(); + auto& rec = ev->Record; + rec.SetId(1); + + rec.SetSeqNoGeneration(id); + rec.SetSeqNoRound(1); + + rec.SetTabletId(datashards[0]); + if (!rec.HasPathId()) { + tableId.PathId.ToProto(rec.MutablePathId()); + } + + VectorIndexSettings settings; + settings.set_vector_dimension(2); + settings.set_vector_type(VectorIndexSettings::VECTOR_TYPE_FLOAT); + settings.set_metric(VectorIndexSettings::DISTANCE_COSINE); + *rec.MutableSettings() = settings; + + rec.SetK(2); + rec.SetSeed(1337); + + rec.SetUpload(NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING); + + rec.SetNeedsRounds(3); + + rec.SetChild(1); + + rec.SetEmbeddingColumn("embedding"); + rec.SetPrefixColumns(1); + + rec.SetLevelName(kLevelTable); + rec.SetPostingName(kPostingTable); + rec.SetPrefixName(kPrefixTable); + + setupRequest(rec); + + runtime.SendToPipe(datashards[0], sender, ev.release(), 0, GetPipeConfigWithRetries()); + + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); + + NYql::TIssues issues; + NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); + if (expectedErrorSubstring) { + UNIT_ASSERT_STRING_CONTAINS(issues.ToOneLineString(), expectedError); + } else { + UNIT_ASSERT_VALUES_EQUAL(issues.ToOneLineString(), expectedError); + } + } + + static std::tuple DoPrefixKMeans( + Tests::TServer::TPtr server, TActorId sender, NTableIndex::TClusterId parent, ui64 seed, ui64 k, + NKikimrTxDataShard::EKMeansState upload, VectorIndexSettings::VectorType type, + VectorIndexSettings::Metric metric, ui32 maxBatchRows) + { + auto id = sId.fetch_add(1, std::memory_order_relaxed); + auto& runtime = *server->GetRuntime(); + auto datashards = GetTableShards(server, sender, kMainTable); + TTableId tableId = ResolveTableId(server, sender, kMainTable); + + TString err; + + for (auto tid : datashards) { + auto ev1 = std::make_unique(); + auto ev2 = std::make_unique(); + auto fill = [&](std::unique_ptr& ev) { + auto& rec = ev->Record; + rec.SetId(1); + + rec.SetSeqNoGeneration(id); + rec.SetSeqNoRound(1); + + rec.SetTabletId(tid); + tableId.PathId.ToProto(rec.MutablePathId()); + + VectorIndexSettings settings; + settings.set_vector_dimension(2); + settings.set_vector_type(type); + settings.set_metric(metric); + *rec.MutableSettings() = settings; + + rec.SetK(k); + rec.SetSeed(seed); + + rec.SetUpload(upload); + + rec.SetNeedsRounds(300); + + rec.SetChild(parent); + + rec.SetEmbeddingColumn("embedding"); + rec.AddDataColumns("data"); + rec.SetPrefixColumns(1); + + rec.SetPrefixName(kPrefixTable); + rec.SetLevelName(kLevelTable); + rec.SetPostingName(kPostingTable); + + rec.MutableScanSettings()->SetMaxBatchRows(maxBatchRows); + }; + fill(ev1); + fill(ev2); + + runtime.SendToPipe(tid, sender, ev1.release(), 0, GetPipeConfigWithRetries()); + runtime.SendToPipe(tid, sender, ev2.release(), 0, GetPipeConfigWithRetries()); + + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + + NYql::TIssues issues; + NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); + UNIT_ASSERT_EQUAL_C(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::DONE, + issues.ToOneLineString()); + } + + auto prefix = ReadShardedTable(server, kPrefixTable); + auto level = ReadShardedTable(server, kLevelTable); + auto posting = ReadShardedTable(server, kPostingTable); + return {std::move(prefix), std::move(level), std::move(posting)}; + } + + static void DropTable(Tests::TServer::TPtr server, TActorId sender, const TString& name) + { + ui64 txId = AsyncDropTable(server, sender, "/Root", name); + WaitTxNotification(server, sender, txId); + } + + static void CreatePrefixTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) + { + options.AllowSystemColumnNames(true); + options.Columns({ + {"user", "String", true, true}, + {IdColumn, NTableIndex::ClusterIdTypeName, true, true}, + }); + CreateShardedTable(server, sender, "/Root", "table-prefix", options); + } + + static void CreateLevelTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) + { + options.AllowSystemColumnNames(true); + options.Columns({ + {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, + {IdColumn, NTableIndex::ClusterIdTypeName, true, true}, + {CentroidColumn, "String", false, true}, + }); + CreateShardedTable(server, sender, "/Root", "table-level", options); + } + + static void CreatePostingTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) + { + options.AllowSystemColumnNames(true); + options.Columns({ + {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, + {"key", "Uint32", true, true}, + {"data", "String", false, false}, + }); + CreateShardedTable(server, sender, "/Root", "table-posting", options); + } + + static void CreateBuildTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options, const TString& name) + { + options.AllowSystemColumnNames(true); + options.Columns({ + {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, + {"key", "Uint32", true, true}, + {"embedding", "String", false, false}, + {"data", "String", false, false}, + }); + CreateShardedTable(server, sender, "/Root", name, options); + } + + static void CreateBuildPrefixTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options, const TString& name) + { + options.Columns({ + {"user", "String", true, true}, + {"key", "Uint32", true, true}, + {"embedding", "String", false, false}, + {"data", "String", false, false}, + }); + CreateShardedTable(server, sender, "/Root", name, options); + } + + Y_UNIT_TEST (BadRequest) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + CreateBuildPrefixTable(server, sender, options, "table-main"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetTabletId(0); + }, TStringBuilder() << "{
: Error: Wrong shard 0 this is " << GetTableShards(server, sender, kMainTable)[0] << " }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + TPathId(0, 0).ToProto(request.MutablePathId()); + }, "{
: Error: Unknown table id: 0 }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.MutableSettings()->set_vector_type(VectorIndexSettings::VECTOR_TYPE_UNSPECIFIED); + }, "{
: Error: Wrong vector type }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.MutableSettings()->set_vector_type(VectorIndexSettings::VECTOR_TYPE_BIT); + }, "{
: Error: TODO(mbkkt) bit vector type is not supported }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.MutableSettings()->set_metric(VectorIndexSettings::METRIC_UNSPECIFIED); + }, "{
: Error: Wrong similarity }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetUpload(NKikimrTxDataShard::UNSPECIFIED); + }, "{
: Error: Wrong upload }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetUpload(NKikimrTxDataShard::SAMPLE); + }, "{
: Error: Wrong upload }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetUpload(NKikimrTxDataShard::UPLOAD_MAIN_TO_BUILD); + }, "{
: Error: Wrong upload }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetK(0); + }, "{
: Error: Should be requested partition on at least two rows }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetK(1); + }, "{
: Error: Should be requested partition on at least two rows }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.ClearLevelName(); + }, "{
: Error: Empty level table name }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.ClearPostingName(); + }, "{
: Error: Empty posting table name }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.ClearPrefixName(); + }, "{
: Error: Empty prefix table name }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetEmbeddingColumn("some"); + }, "{
: Error: Unknown embedding column: some }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.AddDataColumns("some"); + }, "{
: Error: Unknown data column: some }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetPrefixColumns(0); + }, "{
: Error: Should be requested on at least one prefix column }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetPrefixColumns(99); + }, "{
: Error: Should not be requested on more than 2 prefix columns }"); + + // test multiple issues: + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvPrefixKMeansRequest& request) { + request.SetK(1); + request.SetEmbeddingColumn("some"); + }, "[ {
: Error: Should be requested partition on at least two rows } {
: Error: Unknown embedding column: some } ]"); + } + + Y_UNIT_TEST (BuildToPosting) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateBuildPrefixTable(server, sender, options, "table-main"); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (user, key, embedding, data) + VALUES )" + "(\"user-1\", 11, \"\x30\x30\3\", \"1-one\")," + "(\"user-1\", 12, \"\x31\x31\3\", \"1-two\")," + "(\"user-1\", 13, \"\x32\x32\3\", \"1-three\")," + "(\"user-1\", 14, \"\x65\x65\3\", \"1-four\")," + "(\"user-1\", 15, \"\x75\x75\3\", \"1-five\")," + + "(\"user-2\", 21, \"\x30\x30\3\", \"2-one\")," + "(\"user-2\", 22, \"\x31\x31\3\", \"2-two\")," + "(\"user-2\", 23, \"\x32\x32\3\", \"2-three\")," + "(\"user-2\", 24, \"\x65\x65\3\", \"2-four\")," + "(\"user-2\", 25, \"\x75\x75\3\", \"2-five\");"); + + auto create = [&] { + CreatePrefixTable(server, sender, options); + CreateLevelTable(server, sender, options); + CreatePostingTable(server, sender, options); + }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-prefix"); + DropTable(server, sender, "table-level"); + DropTable(server, sender, "table-posting"); + create(); + }; + + ui64 seed, k; + k = 2; + + seed = 0; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance, maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(prefix, + "user = user-1, __ydb_id = 40\n" + + "user = user-2, __ydb_id = 43\n" + ); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n" + + "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = 11\3\n" + "__ydb_parent = 43, __ydb_id = 45, __ydb_centroid = mm\3\n" + ); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 14, data = 1-four\n" + "__ydb_parent = 41, key = 15, data = 1-five\n" + "__ydb_parent = 42, key = 11, data = 1-one\n" + "__ydb_parent = 42, key = 12, data = 1-two\n" + "__ydb_parent = 42, key = 13, data = 1-three\n" + + "__ydb_parent = 44, key = 21, data = 2-one\n" + "__ydb_parent = 44, key = 22, data = 2-two\n" + "__ydb_parent = 44, key = 23, data = 2-three\n" + "__ydb_parent = 45, key = 24, data = 2-four\n" + "__ydb_parent = 45, key = 25, data = 2-five\n" + ); + recreate(); + }} + + seed = 111; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance, maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(prefix, + "user = user-1, __ydb_id = 40\n" + + "user = user-2, __ydb_id = 43\n" + ); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n" + + "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = 11\3\n" + "__ydb_parent = 43, __ydb_id = 45, __ydb_centroid = mm\3\n" + ); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 11, data = 1-one\n" + "__ydb_parent = 41, key = 12, data = 1-two\n" + "__ydb_parent = 41, key = 13, data = 1-three\n" + "__ydb_parent = 42, key = 14, data = 1-four\n" + "__ydb_parent = 42, key = 15, data = 1-five\n" + + "__ydb_parent = 44, key = 21, data = 2-one\n" + "__ydb_parent = 44, key = 22, data = 2-two\n" + "__ydb_parent = 44, key = 23, data = 2-three\n" + "__ydb_parent = 45, key = 24, data = 2-four\n" + "__ydb_parent = 45, key = 25, data = 2-five\n" + ); + recreate(); + }} + seed = 32; + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, VectorIndexSettings::DISTANCE_COSINE}) { + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity, maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(prefix, + "user = user-1, __ydb_id = 40\n" + + "user = user-2, __ydb_id = 43\n" + ); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n" + + "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = II\3\n" + ); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 11, data = 1-one\n" + "__ydb_parent = 41, key = 12, data = 1-two\n" + "__ydb_parent = 41, key = 13, data = 1-three\n" + "__ydb_parent = 41, key = 14, data = 1-four\n" + "__ydb_parent = 41, key = 15, data = 1-five\n" + + "__ydb_parent = 44, key = 21, data = 2-one\n" + "__ydb_parent = 44, key = 22, data = 2-two\n" + "__ydb_parent = 44, key = 23, data = 2-three\n" + "__ydb_parent = 44, key = 24, data = 2-four\n" + "__ydb_parent = 44, key = 25, data = 2-five\n" + ); + recreate(); + }} + } + + Y_UNIT_TEST (BuildToBuild) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateBuildPrefixTable(server, sender, options, "table-main"); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (user, key, embedding, data) + VALUES )" + "(\"user-1\", 11, \"\x30\x30\3\", \"1-one\")," + "(\"user-1\", 12, \"\x31\x31\3\", \"1-two\")," + "(\"user-1\", 13, \"\x32\x32\3\", \"1-three\")," + "(\"user-1\", 14, \"\x65\x65\3\", \"1-four\")," + "(\"user-1\", 15, \"\x75\x75\3\", \"1-five\")," + + "(\"user-2\", 21, \"\x30\x30\3\", \"2-one\")," + "(\"user-2\", 22, \"\x31\x31\3\", \"2-two\")," + "(\"user-2\", 23, \"\x32\x32\3\", \"2-three\")," + "(\"user-2\", 24, \"\x65\x65\3\", \"2-four\")," + "(\"user-2\", 25, \"\x75\x75\3\", \"2-five\");"); + + auto create = [&] { + CreatePrefixTable(server, sender, options); + CreateLevelTable(server, sender, options); + CreateBuildTable(server, sender, options, "table-posting"); + }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-prefix"); + DropTable(server, sender, "table-level"); + DropTable(server, sender, "table-posting"); + create(); + }; + + ui64 seed, k; + k = 2; + + seed = 0; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance, maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(prefix, + "user = user-1, __ydb_id = 40\n" + + "user = user-2, __ydb_id = 43\n" + ); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n" + + "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = 11\3\n" + "__ydb_parent = 43, __ydb_id = 45, __ydb_centroid = mm\3\n" + ); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 14, embedding = \x65\x65\3, data = 1-four\n" + "__ydb_parent = 41, key = 15, embedding = \x75\x75\3, data = 1-five\n" + "__ydb_parent = 42, key = 11, embedding = \x30\x30\3, data = 1-one\n" + "__ydb_parent = 42, key = 12, embedding = \x31\x31\3, data = 1-two\n" + "__ydb_parent = 42, key = 13, embedding = \x32\x32\3, data = 1-three\n" + + "__ydb_parent = 44, key = 21, embedding = \x30\x30\3, data = 2-one\n" + "__ydb_parent = 44, key = 22, embedding = \x31\x31\3, data = 2-two\n" + "__ydb_parent = 44, key = 23, embedding = \x32\x32\3, data = 2-three\n" + "__ydb_parent = 45, key = 24, embedding = \x65\x65\3, data = 2-four\n" + "__ydb_parent = 45, key = 25, embedding = \x75\x75\3, data = 2-five\n" + ); + recreate(); + }} + + seed = 111; + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance, maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(prefix, + "user = user-1, __ydb_id = 40\n" + + "user = user-2, __ydb_id = 43\n" + ); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n" + + "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = 11\3\n" + "__ydb_parent = 43, __ydb_id = 45, __ydb_centroid = mm\3\n" + ); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 11, embedding = \x30\x30\3, data = 1-one\n" + "__ydb_parent = 41, key = 12, embedding = \x31\x31\3, data = 1-two\n" + "__ydb_parent = 41, key = 13, embedding = \x32\x32\3, data = 1-three\n" + "__ydb_parent = 42, key = 14, embedding = \x65\x65\3, data = 1-four\n" + "__ydb_parent = 42, key = 15, embedding = \x75\x75\3, data = 1-five\n" + + "__ydb_parent = 44, key = 21, embedding = \x30\x30\3, data = 2-one\n" + "__ydb_parent = 44, key = 22, embedding = \x31\x31\3, data = 2-two\n" + "__ydb_parent = 44, key = 23, embedding = \x32\x32\3, data = 2-three\n" + "__ydb_parent = 45, key = 24, embedding = \x65\x65\3, data = 2-four\n" + "__ydb_parent = 45, key = 25, embedding = \x75\x75\3, data = 2-five\n" + ); + recreate(); + }} + seed = 32; + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, VectorIndexSettings::DISTANCE_COSINE}) { + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity, maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(prefix, + "user = user-1, __ydb_id = 40\n" + + "user = user-2, __ydb_id = 43\n" + ); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n" + + "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = II\3\n" + ); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 11, embedding = \x30\x30\3, data = 1-one\n" + "__ydb_parent = 41, key = 12, embedding = \x31\x31\3, data = 1-two\n" + "__ydb_parent = 41, key = 13, embedding = \x32\x32\3, data = 1-three\n" + "__ydb_parent = 41, key = 14, embedding = \x65\x65\3, data = 1-four\n" + "__ydb_parent = 41, key = 15, embedding = \x75\x75\3, data = 1-five\n" + + "__ydb_parent = 44, key = 21, embedding = \x30\x30\3, data = 2-one\n" + "__ydb_parent = 44, key = 22, embedding = \x31\x31\3, data = 2-two\n" + "__ydb_parent = 44, key = 23, embedding = \x32\x32\3, data = 2-three\n" + "__ydb_parent = 44, key = 24, embedding = \x65\x65\3, data = 2-four\n" + "__ydb_parent = 44, key = 25, embedding = \x75\x75\3, data = 2-five\n" + ); + recreate(); + }} + } +} + +} diff --git a/ydb/core/tx/datashard/build_index/ut/ut_reshuffle_kmeans.cpp b/ydb/core/tx/datashard/build_index/ut/ut_reshuffle_kmeans.cpp new file mode 100644 index 000000000000..9c8212987d02 --- /dev/null +++ b/ydb/core/tx/datashard/build_index/ut/ut_reshuffle_kmeans.cpp @@ -0,0 +1,613 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace NKikimr { +using namespace Tests; +using Ydb::Table::VectorIndexSettings; +using namespace NTableIndex::NTableVectorKmeansTreeIndex; + +static std::atomic sId = 1; +static constexpr const char* kMainTable = "/Root/table-main"; +static constexpr const char* kPostingTable = "/Root/table-posting"; + +Y_UNIT_TEST_SUITE (TTxDataShardReshuffleKMeansScan) { + + static void DoBadRequest(Tests::TServer::TPtr server, TActorId sender, + std::function setupRequest, + TString expectedError, bool expectedErrorSubstring = false) + { + auto id = sId.fetch_add(1, std::memory_order_relaxed); + auto& runtime = *server->GetRuntime(); + auto snapshot = CreateVolatileSnapshot(server, {kMainTable}); + auto datashards = GetTableShards(server, sender, kMainTable); + TTableId tableId = ResolveTableId(server, sender, kMainTable); + + TStringBuilder data; + TString err; + UNIT_ASSERT(datashards.size() == 1); + + auto ev = std::make_unique(); + auto& rec = ev->Record; + rec.SetId(1); + + rec.SetSeqNoGeneration(id); + rec.SetSeqNoRound(1); + + rec.SetTabletId(datashards[0]); + tableId.PathId.ToProto(rec.MutablePathId()); + + rec.SetSnapshotTxId(snapshot.TxId); + rec.SetSnapshotStep(snapshot.Step); + + VectorIndexSettings settings; + settings.set_vector_dimension(2); + settings.set_vector_type(VectorIndexSettings::VECTOR_TYPE_FLOAT); + settings.set_metric(VectorIndexSettings::DISTANCE_COSINE); + *rec.MutableSettings() = settings; + + rec.SetUpload(NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING); + + rec.SetParent(0); + rec.SetChild(1); + + rec.AddClusters("something"); + + rec.SetEmbeddingColumn("embedding"); + + rec.SetPostingName(kPostingTable); + + setupRequest(rec); + + runtime.SendToPipe(datashards[0], sender, ev.release(), 0, GetPipeConfigWithRetries()); + + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); + + NYql::TIssues issues; + NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); + if (expectedErrorSubstring) { + UNIT_ASSERT_STRING_CONTAINS(issues.ToOneLineString(), expectedError); + } else { + UNIT_ASSERT_VALUES_EQUAL(issues.ToOneLineString(), expectedError); + } + } + + static TString DoReshuffleKMeans(Tests::TServer::TPtr server, TActorId sender, NTableIndex::TClusterId parent, + const std::vector& level, + NKikimrTxDataShard::EKMeansState upload, + VectorIndexSettings::VectorType type, VectorIndexSettings::Metric metric) + { + auto id = sId.fetch_add(1, std::memory_order_relaxed); + auto& runtime = *server->GetRuntime(); + auto snapshot = CreateVolatileSnapshot(server, {kMainTable}); + auto datashards = GetTableShards(server, sender, kMainTable); + TTableId tableId = ResolveTableId(server, sender, kMainTable); + + TString err; + + for (auto tid : datashards) { + auto ev1 = std::make_unique(); + auto ev2 = std::make_unique(); + auto fill = [&](std::unique_ptr& ev) { + auto& rec = ev->Record; + rec.SetId(1); + + rec.SetSeqNoGeneration(id); + rec.SetSeqNoRound(1); + + rec.SetTabletId(tid); + tableId.PathId.ToProto(rec.MutablePathId()); + + rec.SetSnapshotTxId(snapshot.TxId); + rec.SetSnapshotStep(snapshot.Step); + + VectorIndexSettings settings; + settings.set_vector_dimension(2); + settings.set_vector_type(type); + settings.set_metric(metric); + *rec.MutableSettings() = settings; + + rec.SetUpload(upload); + + *rec.MutableClusters() = {level.begin(), level.end()}; + + rec.SetParent(parent); + rec.SetChild(parent + 1); + + rec.SetEmbeddingColumn("embedding"); + rec.AddDataColumns("data"); + + rec.SetPostingName(kPostingTable); + }; + fill(ev1); + fill(ev2); + + runtime.SendToPipe(tid, sender, ev1.release(), 0, GetPipeConfigWithRetries()); + runtime.SendToPipe(tid, sender, ev2.release(), 0, GetPipeConfigWithRetries()); + + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + + NYql::TIssues issues; + NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); + UNIT_ASSERT_EQUAL_C(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::DONE, + issues.ToOneLineString()); + } + + auto posting = ReadShardedTable(server, kPostingTable); + return std::move(posting); + } + + static void DropTable(Tests::TServer::TPtr server, TActorId sender, const char* name) + { + ui64 txId = AsyncDropTable(server, sender, "/Root", name); + WaitTxNotification(server, sender, txId); + } + + static void CreateMainTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) + { + options.AllowSystemColumnNames(false); + options.Columns({ + {"key", "Uint32", true, true}, + {"embedding", "String", false, false}, + {"data", "String", false, false}, + }); + CreateShardedTable(server, sender, "/Root", "table-main", options); + } + + static void CreatePostingTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) + { + options.AllowSystemColumnNames(true); + options.Columns({ + {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, + {"key", "Uint32", true, true}, + {"data", "String", false, false}, + }); + CreateShardedTable(server, sender, "/Root", "table-posting", options); + } + + static void CreateBuildTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options, + const char* name) + { + options.AllowSystemColumnNames(true); + options.Columns({ + {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, + {"key", "Uint32", true, true}, + {"embedding", "String", false, false}, + {"data", "String", false, false}, + }); + CreateShardedTable(server, sender, "/Root", name, options); + } + + Y_UNIT_TEST(BadRequest) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + CreateMainTable(server, sender, options); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.SetTabletId(0); + }, TStringBuilder() << "{
: Error: Wrong shard 0 this is " << GetTableShards(server, sender, kMainTable)[0] << " }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + TPathId(0, 0).ToProto(request.MutablePathId()); + }, "{
: Error: Unknown table id: 0 }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.SetSnapshotStep(request.GetSnapshotStep() + 1); + }, "Error: Unknown snapshot", true); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.SetSnapshotTxId(request.GetSnapshotTxId() + 1); + }, "Error: Unknown snapshot", true); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.MutableSettings()->set_vector_type(VectorIndexSettings::VECTOR_TYPE_UNSPECIFIED); + }, "{
: Error: Wrong vector type }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.MutableSettings()->set_vector_type(VectorIndexSettings::VECTOR_TYPE_BIT); + }, "{
: Error: TODO(mbkkt) bit vector type is not supported }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.MutableSettings()->set_metric(VectorIndexSettings::METRIC_UNSPECIFIED); + }, "{
: Error: Wrong similarity }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.SetUpload(NKikimrTxDataShard::UNSPECIFIED); + }, "{
: Error: Wrong upload }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.SetUpload(NKikimrTxDataShard::SAMPLE); + }, "{
: Error: Wrong upload }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.ClearClusters(); + }, "{
: Error: Should be requested at least single cluster }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.ClearPostingName(); + }, "{
: Error: Empty posting table name }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.SetEmbeddingColumn("some"); + }, "{
: Error: Unknown embedding column: some }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.AddDataColumns("some"); + }, "{
: Error: Unknown data column: some }"); + + // test multiple issues: + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvReshuffleKMeansRequest& request) { + request.ClearClusters(); + request.SetEmbeddingColumn("some"); + }, "[ {
: Error: Should be requested at least single cluster } {
: Error: Unknown embedding column: some } ]"); + } + + Y_UNIT_TEST(MainToPosting) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + CreateMainTable(server, sender, options); + + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (key, embedding, data) + VALUES )" + "(1, \"\x30\x30\3\", \"one\")," + "(2, \"\x31\x31\3\", \"two\")," + "(3, \"\x32\x32\3\", \"three\")," + "(4, \"\x65\x65\3\", \"four\")," + "(5, \"\x75\x75\3\", \"five\");"); + + auto create = [&] { CreatePostingTable(server, sender, options); }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-posting"); + create(); + }; + + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + std::vector level = { + "mm\3", + "11\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 0, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, data = four\n" + "__ydb_parent = 1, key = 5, data = five\n" + "__ydb_parent = 2, key = 1, data = one\n" + "__ydb_parent = 2, key = 2, data = two\n" + "__ydb_parent = 2, key = 3, data = three\n"); + recreate(); + } + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + std::vector level = { + "11\3", + "mm\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 0, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n" + "__ydb_parent = 1, key = 2, data = two\n" + "__ydb_parent = 1, key = 3, data = three\n" + "__ydb_parent = 2, key = 4, data = four\n" + "__ydb_parent = 2, key = 5, data = five\n"); + recreate(); + } + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, + VectorIndexSettings::DISTANCE_COSINE}) + { + std::vector level = { + "II\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 0, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n" + "__ydb_parent = 1, key = 2, data = two\n" + "__ydb_parent = 1, key = 3, data = three\n" + "__ydb_parent = 1, key = 4, data = four\n" + "__ydb_parent = 1, key = 5, data = five\n"); + recreate(); + } + } + + Y_UNIT_TEST(MainToBuild) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + CreateMainTable(server, sender, options); + + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (key, embedding, data) + VALUES )" + "(1, \"\x30\x30\3\", \"one\")," + "(2, \"\x31\x31\3\", \"two\")," + "(3, \"\x32\x32\3\", \"three\")," + "(4, \"\x65\x65\3\", \"four\")," + "(5, \"\x75\x75\3\", \"five\");"); + + auto create = [&] { CreateBuildTable(server, sender, options, "table-posting"); }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-posting"); + create(); + }; + + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + std::vector level = { + "mm\3", + "11\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 0, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 1, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 2, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 2, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 2, key = 3, embedding = \x32\x32\3, data = three\n"); + recreate(); + } + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + std::vector level = { + "11\3", + "mm\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 0, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 2, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 2, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, + VectorIndexSettings::DISTANCE_COSINE}) + { + std::vector level = { + "II\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 0, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 1, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 1, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + } + + Y_UNIT_TEST(BuildToPosting) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateBuildTable(server, sender, options, "table-main"); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (__ydb_parent, key, embedding, data) + VALUES )" + "(39, 1, \"\x30\x30\3\", \"one\")," + "(40, 1, \"\x30\x30\3\", \"one\")," + "(40, 2, \"\x31\x31\3\", \"two\")," + "(40, 3, \"\x32\x32\3\", \"three\")," + "(40, 4, \"\x65\x65\3\", \"four\")," + "(40, 5, \"\x75\x75\3\", \"five\")," + "(41, 5, \"\x75\x75\3\", \"five\");"); + + auto create = [&] { CreatePostingTable(server, sender, options); }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-posting"); + create(); + }; + + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + std::vector level = { + "mm\3", + "11\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 40, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, data = four\n" + "__ydb_parent = 41, key = 5, data = five\n" + "__ydb_parent = 42, key = 1, data = one\n" + "__ydb_parent = 42, key = 2, data = two\n" + "__ydb_parent = 42, key = 3, data = three\n"); + recreate(); + } + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + std::vector level = { + "11\3", + "mm\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 40, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n" + "__ydb_parent = 41, key = 2, data = two\n" + "__ydb_parent = 41, key = 3, data = three\n" + "__ydb_parent = 42, key = 4, data = four\n" + "__ydb_parent = 42, key = 5, data = five\n"); + recreate(); + } + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, + VectorIndexSettings::DISTANCE_COSINE}) + { + std::vector level = { + "II\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 40, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n" + "__ydb_parent = 41, key = 2, data = two\n" + "__ydb_parent = 41, key = 3, data = three\n" + "__ydb_parent = 41, key = 4, data = four\n" + "__ydb_parent = 41, key = 5, data = five\n"); + recreate(); + } + } + + Y_UNIT_TEST(BuildToBuild) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateBuildTable(server, sender, options, "table-main"); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (__ydb_parent, key, embedding, data) + VALUES )" + "(39, 1, \"\x30\x30\3\", \"one\")," + "(40, 1, \"\x30\x30\3\", \"one\")," + "(40, 2, \"\x31\x31\3\", \"two\")," + "(40, 3, \"\x32\x32\3\", \"three\")," + "(40, 4, \"\x65\x65\3\", \"four\")," + "(40, 5, \"\x75\x75\3\", \"five\")," + "(41, 5, \"\x75\x75\3\", \"five\");"); + + auto create = [&] { CreateBuildTable(server, sender, options, "table-posting"); }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-posting"); + create(); + }; + + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + std::vector level = { + "mm\3", + "11\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 40, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 41, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 42, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 42, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 42, key = 3, embedding = \x32\x32\3, data = three\n"); + recreate(); + } + for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { + std::vector level = { + "11\3", + "mm\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 40, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, distance); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 42, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 42, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, + VectorIndexSettings::DISTANCE_COSINE}) + { + std::vector level = { + "II\3", + }; + auto posting = DoReshuffleKMeans(server, sender, 40, level, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, + VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); + UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 41, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 41, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + } +} + +} diff --git a/ydb/core/tx/datashard/build_index/ut/ut_sample_k.cpp b/ydb/core/tx/datashard/build_index/ut/ut_sample_k.cpp new file mode 100644 index 000000000000..ccae467a1be6 --- /dev/null +++ b/ydb/core/tx/datashard/build_index/ut/ut_sample_k.cpp @@ -0,0 +1,269 @@ +#include "defs.h" +#include "datashard_ut_common_kqp.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace NKikimr { + +static std::atomic sId = 1; + +using namespace NKikimr::NDataShard::NKqpHelpers; +using namespace NSchemeShard; +using namespace Tests; + +static const TString kTable = "/Root/table-1"; + +Y_UNIT_TEST_SUITE (TTxDataShardSampleKScan) { + + static void DoBadRequest(Tests::TServer::TPtr server, TActorId sender, + std::function setupRequest, + TString expectedError, bool expectedErrorSubstring = false) + { + auto id = sId.fetch_add(1, std::memory_order_relaxed); + auto& runtime = *server->GetRuntime(); + auto snapshot = CreateVolatileSnapshot(server, {kTable}); + auto datashards = GetTableShards(server, sender, kTable); + TTableId tableId = ResolveTableId(server, sender, kTable); + + TStringBuilder data; + TString err; + UNIT_ASSERT(datashards.size() == 1); + + auto ev = std::make_unique(); + auto& rec = ev->Record; + rec.SetId(1); + + rec.SetSeqNoGeneration(id); + rec.SetSeqNoRound(1); + + rec.SetTabletId(datashards[0]); + + tableId.PathId.ToProto(rec.MutablePathId()); + + rec.AddColumns("value"); + rec.AddColumns("key"); + + rec.SetSnapshotTxId(snapshot.TxId); + rec.SetSnapshotStep(snapshot.Step); + + rec.SetMaxProbability(std::numeric_limits::max()); + rec.SetSeed(1337); + rec.SetK(1); + + setupRequest(rec); + + runtime.SendToPipe(datashards[0], sender, ev.release(), 0, GetPipeConfigWithRetries()); + + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); + + NYql::TIssues issues; + NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); + if (expectedErrorSubstring) { + UNIT_ASSERT_STRING_CONTAINS(issues.ToOneLineString(), expectedError); + } else { + UNIT_ASSERT_VALUES_EQUAL(issues.ToOneLineString(), expectedError); + } + } + + static TString DoSampleK(Tests::TServer::TPtr server, TActorId sender, const TString& tableFrom, const TRowVersion& snapshot, ui64 seed, ui64 k) { + auto id = sId.fetch_add(1, std::memory_order_relaxed); + auto& runtime = *server->GetRuntime(); + auto datashards = GetTableShards(server, sender, tableFrom); + TTableId tableId = ResolveTableId(server, sender, tableFrom); + + TStringBuilder data; + TString err; + + for (auto tid : datashards) { + auto ev1 = std::make_unique(); + auto ev2 = std::make_unique(); + auto fill = [&](auto& ev) { + auto& rec = ev->Record; + rec.SetId(1); + + rec.SetSeqNoGeneration(id); + rec.SetSeqNoRound(1); + + rec.SetTabletId(tid); + tableId.PathId.ToProto(rec.MutablePathId()); + + rec.AddColumns("value"); + rec.AddColumns("key"); + + if (snapshot.TxId) { + rec.SetSnapshotTxId(snapshot.TxId); + rec.SetSnapshotStep(snapshot.Step); + } + + rec.SetMaxProbability(std::numeric_limits::max()); + rec.SetSeed(seed); + rec.SetK(k); + }; + fill(ev1); + fill(ev2); + + runtime.SendToPipe(tid, sender, ev1.release(), 0, GetPipeConfigWithRetries()); + runtime.SendToPipe(tid, sender, ev2.release(), 0, GetPipeConfigWithRetries()); + + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::DONE); + + const auto& rows = reply->Record.GetRows(); + UNIT_ASSERT(!rows.empty()); + for (auto& row : rows) { + TSerializedCellVec vec; + UNIT_ASSERT(TSerializedCellVec::TryParse(row, vec)); + const auto& cells = vec.GetCells(); + UNIT_ASSERT_EQUAL(cells.size(), 2); + data.Out << "value = "; + UNIT_ASSERT(cells[0].ToStream(data.Out, err)); + data.Out << ", key = "; + UNIT_ASSERT(cells[1].ToStream(data.Out, err)); + data.Out << "\n"; + } + auto& probabilities = reply->Record.GetProbabilities(); + UNIT_ASSERT(rows.size() == probabilities.size()); + UNIT_ASSERT(std::is_sorted(probabilities.begin(), probabilities.end())); + } + return data; + } + + Y_UNIT_TEST(BadRequest) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + CreateShardedTable(server, sender, "/Root", "table-1", 1, false); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvSampleKRequest& request) { + request.SetTabletId(0); + }, TStringBuilder() << "{
: Error: Wrong shard 0 this is " << GetTableShards(server, sender, kTable)[0] << " }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvSampleKRequest& request) { + TPathId(0, 0).ToProto(request.MutablePathId()); + }, "{
: Error: Unknown table id: 0 }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvSampleKRequest& request) { + request.SetSnapshotStep(request.GetSnapshotStep() + 1); + }, "Error: Unknown snapshot", true); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvSampleKRequest& request) { + request.SetSnapshotTxId(request.GetSnapshotTxId() + 1); + }, "Error: Unknown snapshot", true); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvSampleKRequest& request) { + request.SetK(0); + }, "{
: Error: Should be requested on at least one row }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvSampleKRequest& request) { + request.SetMaxProbability(0); + }, "{
: Error: Max probability should be positive }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvSampleKRequest& request) { + request.ClearColumns(); + }, "{
: Error: Should be requested at least one column }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvSampleKRequest& request) { + request.AddColumns("some"); + }, "{
: Error: Unknown column: some }"); + + // test multiple issues: + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvSampleKRequest& request) { + request.SetK(0); + request.AddColumns("some"); + }, "[ {
: Error: Should be requested on at least one row } {
: Error: Unknown column: some } ]"); + } + + Y_UNIT_TEST(RunScan) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + CreateShardedTable(server, sender, "/Root", "table-1", 1, false); + + // Upsert some initial values + ExecSQL(server, sender, "UPSERT INTO `/Root/table-1` (key, value) VALUES (1, 10), (2, 20), (3, 30), (4, 40), (5, 50);"); + + auto snapshot = CreateVolatileSnapshot(server, {kTable}); + + ui64 seed, k; + TString data; + + seed = 0; + { + k = 1; + data = DoSampleK(server, sender, kTable, snapshot, seed, k); + UNIT_ASSERT_VALUES_EQUAL(data, + "value = 30, key = 3\n"); + + k = 3; + data = DoSampleK(server, sender, kTable, snapshot, seed, k); + UNIT_ASSERT_VALUES_EQUAL(data, + "value = 30, key = 3\n" + "value = 20, key = 2\n" + "value = 50, key = 5\n"); + + k = 9; + data = DoSampleK(server, sender, kTable, snapshot, seed, k); + UNIT_ASSERT_VALUES_EQUAL(data, + "value = 30, key = 3\n" + "value = 20, key = 2\n" + "value = 50, key = 5\n" + "value = 40, key = 4\n" + "value = 10, key = 1\n"); + } + snapshot = {}; + seed = 111; + { + k = 1; + data = DoSampleK(server, sender, kTable, snapshot, seed, k); + UNIT_ASSERT_VALUES_EQUAL(data, + "value = 10, key = 1\n"); + + k = 3; + data = DoSampleK(server, sender, kTable, snapshot, seed, k); + UNIT_ASSERT_VALUES_EQUAL(data, + "value = 10, key = 1\n" + "value = 20, key = 2\n" + "value = 30, key = 3\n"); + + k = 9; + data = DoSampleK(server, sender, kTable, snapshot, seed, k); + UNIT_ASSERT_VALUES_EQUAL(data, + "value = 10, key = 1\n" + "value = 20, key = 2\n" + "value = 30, key = 3\n" + "value = 50, key = 5\n" + "value = 40, key = 4\n"); + } + } +} + +} // namespace NKikimr diff --git a/ydb/core/tx/datashard/build_index/ut/ut_secondary_index.cpp b/ydb/core/tx/datashard/build_index/ut/ut_secondary_index.cpp new file mode 100644 index 000000000000..37ccc25634f6 --- /dev/null +++ b/ydb/core/tx/datashard/build_index/ut/ut_secondary_index.cpp @@ -0,0 +1,333 @@ +#include "defs.h" +#include +#include "datashard_ut_common_kqp.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace NKikimr { + +using namespace NKikimr::NDataShard::NKqpHelpers; +using namespace NSchemeShard; +using namespace Tests; + +static const TString kMainTable = "/Root/table-1"; +static const TString kIndexTable = "/Root/table-2"; + +Y_UNIT_TEST_SUITE(TTxDataShardBuildIndexScan) { + + static void DoBadRequest(Tests::TServer::TPtr server, TActorId sender, + std::function setupRequest, + TString expectedError, bool expectedErrorSubstring = false) + { + auto &runtime = *server->GetRuntime(); + auto snapshot = CreateVolatileSnapshot(server, {kMainTable}); + TVector datashards = GetTableShards(server, sender, kMainTable); + TTableId tableId = ResolveTableId(server, sender, kMainTable); + + TStringBuilder data; + TString err; + UNIT_ASSERT(datashards.size() == 1); + + auto ev = new TEvDataShard::TEvBuildIndexCreateRequest; + NKikimrTxDataShard::TEvBuildIndexCreateRequest& rec = ev->Record; + rec.SetBuildIndexId(1); + + rec.SetTabletId(datashards[0]); + rec.SetOwnerId(tableId.PathId.OwnerId); + rec.SetPathId(tableId.PathId.LocalPathId); + + rec.SetTargetName(kIndexTable); + rec.AddIndexColumns("value"); + rec.AddIndexColumns("key"); + + rec.SetSnapshotTxId(snapshot.TxId); + rec.SetSnapshotStep(snapshot.Step); + + setupRequest(rec); + + runtime.SendToPipe(datashards[0], sender, ev, 0, GetPipeConfigWithRetries()); + + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); + + NYql::TIssues issues; + NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); + if (expectedErrorSubstring) { + UNIT_ASSERT_STRING_CONTAINS(issues.ToOneLineString(), expectedError); + } else { + UNIT_ASSERT_VALUES_EQUAL(issues.ToOneLineString(), expectedError); + } + } + + static void DoBuildIndex(Tests::TServer::TPtr server, TActorId sender, + const TString& tableFrom, const TString& tableTo, + const TRowVersion& snapshot, + const NKikimrIndexBuilder::EBuildStatus& expected) { + auto &runtime = *server->GetRuntime(); + TVector datashards = GetTableShards(server, sender, tableFrom); + TTableId tableId = ResolveTableId(server, sender, tableFrom); + + for (auto tid: datashards) { + auto ev = new TEvDataShard::TEvBuildIndexCreateRequest; + NKikimrTxDataShard::TEvBuildIndexCreateRequest& rec = ev->Record; + rec.SetBuildIndexId(1); + + rec.SetTabletId(tid); + rec.SetOwnerId(tableId.PathId.OwnerId); + rec.SetPathId(tableId.PathId.LocalPathId); + + rec.SetTargetName(tableTo); + rec.AddIndexColumns("value"); + rec.AddIndexColumns("key"); + + rec.SetSnapshotTxId(snapshot.TxId); + rec.SetSnapshotStep(snapshot.Step); + + runtime.SendToPipe(tid, sender, ev, 0, GetPipeConfigWithRetries()); + + while (true) { + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle); + + if (expected == NKikimrIndexBuilder::EBuildStatus::DONE + && reply->Record.GetStatus() == NKikimrIndexBuilder::EBuildStatus::ACCEPTED) { + Cerr << "skip ACCEPTED" << Endl; + continue; + } + + if (expected != NKikimrIndexBuilder::EBuildStatus::IN_PROGRESS + && reply->Record.GetStatus() == NKikimrIndexBuilder::EBuildStatus::IN_PROGRESS) { + Cerr << "skip INPROGRESS" << Endl; + continue; + } + + NYql::TIssues issues; + NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); + UNIT_ASSERT_VALUES_EQUAL_C(reply->Record.GetStatus(), expected, issues.ToString()); + break; + } + } + } + + static void CreateShardedTableForIndex( + Tests::TServer::TPtr server, TActorId sender, + const TString &root, const TString &name, + ui64 shards, bool enableOutOfOrder) + { + NLocalDb::TCompactionPolicyPtr policy = NLocalDb::CreateDefaultUserTablePolicy(); + policy->KeepEraseMarkers = true; + + auto opts = TShardedTableOptions() + .Shards(shards) + .EnableOutOfOrder(enableOutOfOrder) + .Policy(policy.Get()) + .ShadowData(EShadowDataMode::Enabled) + .Columns({{"value", "Uint32", true, false}, {"key", "Uint32", true, false}}); + + CreateShardedTable(server, sender, root, name, opts); + } + + Y_UNIT_TEST(BadRequest) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root") + .SetUseRealThreads(false); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto &runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + // Allow manipulating shadow data using normal schemeshard operations + runtime.GetAppData().AllowShadowDataInSchemeShardForTests = true; + + InitRoot(server, sender); + + CreateShardedTable(server, sender, "/Root", "table-1", 1, false); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvBuildIndexCreateRequest& request) { + request.SetTabletId(0); + }, TStringBuilder() << "{
: Error: Wrong shard 0 this is " << GetTableShards(server, sender, kMainTable)[0] << " }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvBuildIndexCreateRequest& request) { + request.SetPathId(0); + }, "{
: Error: Unknown table id: 0 }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvBuildIndexCreateRequest& request) { + request.SetSnapshotStep(request.GetSnapshotStep() + 1); + }, "Error: Unknown snapshot", true); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvBuildIndexCreateRequest& request) { + request.SetSnapshotTxId(request.GetSnapshotTxId() + 1); + }, "Error: Unknown snapshot", true); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvBuildIndexCreateRequest& request) { + request.ClearTargetName(); + }, "{
: Error: Empty target table name }"); + + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvBuildIndexCreateRequest& request) { + request.AddIndexColumns("some"); + }, "{
: Error: Unknown index column: some }"); + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvBuildIndexCreateRequest& request) { + request.AddDataColumns("some"); + }, "{
: Error: Unknown data column: some }"); + + // test multiple issues: + DoBadRequest(server, sender, [](NKikimrTxDataShard::TEvBuildIndexCreateRequest& request) { + request.AddIndexColumns("some1"); + request.AddDataColumns("some2"); + }, "[ {
: Error: Unknown index column: some1 } {
: Error: Unknown data column: some2 } ]"); + } + + Y_UNIT_TEST(RunScan) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root") + .SetUseRealThreads(false); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto &runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + // Allow manipulating shadow data using normal schemeshard operations + runtime.GetAppData().AllowShadowDataInSchemeShardForTests = true; + + InitRoot(server, sender); + + CreateShardedTable(server, sender, "/Root", "table-1", 1, false); + + // Upsert some initial values + ExecSQL(server, sender, "UPSERT INTO `/Root/table-1` (key, value) VALUES (1, 100), (3, 300), (5, 500);"); + + CreateShardedTableForIndex(server, sender, "/Root", "table-2", 1, false); + + auto snapshot = CreateVolatileSnapshot(server, { kMainTable }); + + DoBuildIndex(server, sender, kMainTable, kIndexTable, snapshot, NKikimrIndexBuilder::EBuildStatus::DONE); + + // Writes to shadow data should not be visible yet + auto data = ReadShardedTable(server, kIndexTable); + UNIT_ASSERT_VALUES_EQUAL(data, ""); + + // Alter table: disable shadow data and change compaction policy + auto policy = NLocalDb::CreateDefaultUserTablePolicy(); + policy->KeepEraseMarkers = false; + WaitTxNotification(server, AsyncAlterAndDisableShadow(server, "/Root", "table-2", policy.Get())); + + // Shadow data must be visible now + auto data2 = ReadShardedTable(server, kIndexTable); + UNIT_ASSERT_VALUES_EQUAL(data2, + "value = 100, key = 1\n" + "value = 300, key = 3\n" + "value = 500, key = 5\n"); + } + + Y_UNIT_TEST(ShadowBorrowCompaction) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings + .SetDomainName("Root") + .SetUseRealThreads(false); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto &runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + runtime.SetLogPriority(NKikimrServices::FLAT_TX_SCHEMESHARD, NLog::PRI_TRACE); + runtime.SetLogPriority(NKikimrServices::TABLET_EXECUTOR, NLog::PRI_DEBUG); + + // Allow manipulating shadow data using normal schemeshard operations + runtime.GetAppData().AllowShadowDataInSchemeShardForTests = true; + + InitRoot(server, sender); + + CreateShardedTable(server, sender, "/Root", "table-1", 1, false); + + // Upsert some initial values + ExecSQL(server, sender, "UPSERT INTO `/Root/table-1` (key, value) VALUES (1, 100), (2, 200), (3, 300), (4, 400), (5, 500);"); + + CreateShardedTableForIndex(server, sender, "/Root", "table-2", 1, false); + + TBlockEvents block(runtime, [&](const TEvDataShard::TEvCompactBorrowed::TPtr& event) { + return runtime.FindActorName(event->Sender) == "FLAT_SCHEMESHARD_ACTOR"; + }); + + auto snapshot = CreateVolatileSnapshot(server, { kMainTable }); + + DoBuildIndex(server, sender, kMainTable, kIndexTable, snapshot, NKikimrIndexBuilder::EBuildStatus::DONE); + + // Writes to shadow data should not be visible yet + auto data = ReadShardedTable(server, kIndexTable); + UNIT_ASSERT_VALUES_EQUAL(data, ""); + + // Split index + auto shards1 = GetTableShards(server, sender, kIndexTable); + UNIT_ASSERT_VALUES_EQUAL(shards1.size(), 1u); + + // Split would fail otherwise :( + SetSplitMergePartCountLimit(server->GetRuntime(), -1); + + auto senderSplit = runtime.AllocateEdgeActor(); + ui64 txId = AsyncSplitTable(server, senderSplit, kIndexTable, shards1.at(0), 300); + WaitTxNotification(server, senderSplit, txId); + + auto shards2 = GetTableShards(server, sender, kIndexTable); + UNIT_ASSERT_VALUES_EQUAL(shards2.size(), 2u); + + for (auto shardIndex : xrange(2u)) { + auto stats = WaitTableStats(runtime, shards2.at(shardIndex)); + // Cerr << "Received shard stats:" << Endl << stats.DebugString() << Endl; + + UNIT_ASSERT_VALUES_EQUAL(stats.GetTableStats().GetRowCount(), shardIndex == 0 ? 2 : 3); + + THashSet owners(stats.GetUserTablePartOwners().begin(), stats.GetUserTablePartOwners().end()); + // Note: datashard always adds current shard to part owners, even if there are no parts + UNIT_ASSERT_VALUES_EQUAL(owners, (THashSet{shards1.at(0), shards2.at(shardIndex)})); + + auto tableId = ResolveTableId(server, sender, kIndexTable); + auto result = CompactBorrowed(runtime, shards2.at(shardIndex), tableId); + // Cerr << "Compact result " << result.DebugString() << Endl; + UNIT_ASSERT_VALUES_EQUAL(result.GetTabletId(), shards2.at(shardIndex)); + UNIT_ASSERT_VALUES_EQUAL(result.GetPathId().GetOwnerId(), tableId.PathId.OwnerId); + UNIT_ASSERT_VALUES_EQUAL(result.GetPathId().GetLocalId(), tableId.PathId.LocalPathId); + + for (int i = 0; i < 5 && (owners.size() > 1 || owners.contains(shards1.at(0))); ++i) { + auto stats = WaitTableStats(runtime, shards2.at(shardIndex)); + owners = THashSet(stats.GetUserTablePartOwners().begin(), stats.GetUserTablePartOwners().end()); + } + + UNIT_ASSERT_VALUES_EQUAL(owners, (THashSet{shards2.at(shardIndex)})); + } + + // Alter table: disable shadow data and change compaction policy + auto policy = NLocalDb::CreateDefaultUserTablePolicy(); + policy->KeepEraseMarkers = false; + WaitTxNotification(server, AsyncAlterAndDisableShadow(server, "/Root", "table-2", policy.Get())); + + // Shadow data must be visible now + auto data2 = ReadShardedTable(server, kIndexTable); + UNIT_ASSERT_VALUES_EQUAL(data2, + "value = 100, key = 1\n" + "value = 200, key = 2\n" + "value = 300, key = 3\n" + "value = 400, key = 4\n" + "value = 500, key = 5\n"); + } +} + +} // namespace NKikimr diff --git a/ydb/core/tx/datashard/build_index/ut/ya.make b/ydb/core/tx/datashard/build_index/ut/ya.make new file mode 100644 index 000000000000..6a624f37f96c --- /dev/null +++ b/ydb/core/tx/datashard/build_index/ut/ya.make @@ -0,0 +1,37 @@ +UNITTEST_FOR(ydb/core/tx/datashard) + +FORK_SUBTESTS() + +SPLIT_FACTOR(1) + +IF (SANITIZER_TYPE == "thread" OR WITH_VALGRIND) + SIZE(LARGE) + TAG(ya:fat) +ELSE() + SIZE(MEDIUM) +ENDIF() + +PEERDIR( + ydb/core/tx/datashard/ut_common + library/cpp/getopt + library/cpp/regex/pcre + library/cpp/svnversion + ydb/core/kqp/ut/common + ydb/core/testlib/default + ydb/core/tx + yql/essentials/public/udf/service/exception_policy + ydb/public/lib/yson_value + ydb/public/sdk/cpp/src/client/result +) + +YQL_LAST_ABI_VERSION() + +SRCS( + ut_local_kmeans.cpp + ut_prefix_kmeans.cpp + ut_reshuffle_kmeans.cpp + ut_sample_k.cpp + ut_secondary_index.cpp +) + +END() diff --git a/ydb/core/tx/datashard/datashard.cpp b/ydb/core/tx/datashard/datashard.cpp index 8e49843eb95c..3e4d4c0eb7b7 100644 --- a/ydb/core/tx/datashard/datashard.cpp +++ b/ydb/core/tx/datashard/datashard.cpp @@ -2522,10 +2522,11 @@ ui64 TDataShard::GetMaxObservedStep() const { } void TDataShard::SendImmediateWriteResult( - const TRowVersion& version, const TActorId& target, IEventBase* event, ui64 cookie, + const TRowVersion& version, const TActorId& target, IEventBase* eventRawPtr, ui64 cookie, const TActorId& sessionId, NWilson::TTraceId traceId) { + THolder event(eventRawPtr); NWilson::TSpan span(TWilsonTablet::TabletDetailed, std::move(traceId), "Datashard.SendImmediateWriteResult", NWilson::EFlags::AUTO_END); const ui64 step = version.Step; @@ -2537,9 +2538,9 @@ void TDataShard::SendImmediateWriteResult( if (Y_LIKELY(!InMemoryVarsFrozen) || version <= SnapshotManager.GetImmediateWriteEdgeReplied()) { SnapshotManager.PromoteImmediateWriteEdgeReplied(version); if (!sessionId) { - Send(target, event, 0, cookie, span.GetTraceId()); + Send(target, event.Release(), 0, cookie, span.GetTraceId()); } else { - SendViaSession(sessionId, target, SelfId(), event, 0, cookie, span.GetTraceId()); + SendViaSession(sessionId, target, SelfId(), event.Release(), 0, cookie, span.GetTraceId()); } } else { span.EndError("Dropped"); @@ -2550,7 +2551,7 @@ void TDataShard::SendImmediateWriteResult( MediatorDelayedReplies.emplace( std::piecewise_construct, std::forward_as_tuple(version), - std::forward_as_tuple(target, THolder(event), cookie, sessionId, std::move(span))); + std::forward_as_tuple(target, std::move(event), cookie, sessionId, std::move(span))); // Try to subscribe to the next step, when needed if (MediatorTimeCastEntry && (MediatorTimeCastWaitingSteps.empty() || step < *MediatorTimeCastWaitingSteps.begin())) { diff --git a/ydb/core/tx/datashard/datashard_ut_build_index.cpp b/ydb/core/tx/datashard/datashard_ut_build_index.cpp deleted file mode 100644 index 1b034e4109a3..000000000000 --- a/ydb/core/tx/datashard/datashard_ut_build_index.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#include "defs.h" -#include -#include "datashard_ut_common_kqp.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include - -namespace NKikimr { - -using namespace NKikimr::NDataShard::NKqpHelpers; -using namespace NSchemeShard; -using namespace Tests; - - -Y_UNIT_TEST_SUITE(TTxDataShardBuildIndexScan) { - - static void DoBuildIndex(Tests::TServer::TPtr server, TActorId sender, - const TString& tableFrom, const TString& tableTo, - const TRowVersion& snapshot, - const NKikimrIndexBuilder::EBuildStatus& expected) { - auto &runtime = *server->GetRuntime(); - TVector datashards = GetTableShards(server, sender, tableFrom); - TTableId tableId = ResolveTableId(server, sender, tableFrom); - - for (auto tid: datashards) { - auto ev = new TEvDataShard::TEvBuildIndexCreateRequest; - NKikimrTxDataShard::TEvBuildIndexCreateRequest& rec = ev->Record; - rec.SetBuildIndexId(1); - - rec.SetTabletId(tid); - rec.SetOwnerId(tableId.PathId.OwnerId); - rec.SetPathId(tableId.PathId.LocalPathId); - - rec.SetTargetName(tableTo); - rec.AddIndexColumns("value"); - rec.AddIndexColumns("key"); - - rec.SetSnapshotTxId(snapshot.TxId); - rec.SetSnapshotStep(snapshot.Step); - - runtime.SendToPipe(tid, sender, ev, 0, GetPipeConfigWithRetries()); - - while (true) { - TAutoPtr handle; - auto reply = runtime.GrabEdgeEventRethrow(handle); - - if (expected == NKikimrIndexBuilder::EBuildStatus::DONE - && reply->Record.GetStatus() == NKikimrIndexBuilder::EBuildStatus::ACCEPTED) { - Cerr << "skip ACCEPTED" << Endl; - continue; - } - - if (expected != NKikimrIndexBuilder::EBuildStatus::IN_PROGRESS - && reply->Record.GetStatus() == NKikimrIndexBuilder::EBuildStatus::IN_PROGRESS) { - Cerr << "skip INPROGRESS" << Endl; - continue; - } - - NYql::TIssues issues; - NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); - UNIT_ASSERT_VALUES_EQUAL_C(reply->Record.GetStatus(), expected, issues.ToString()); - break; - } - } - } - - static void CreateShardedTableForIndex( - Tests::TServer::TPtr server, TActorId sender, - const TString &root, const TString &name, - ui64 shards, bool enableOutOfOrder) - { - NLocalDb::TCompactionPolicyPtr policy = NLocalDb::CreateDefaultUserTablePolicy(); - policy->KeepEraseMarkers = true; - - auto opts = TShardedTableOptions() - .Shards(shards) - .EnableOutOfOrder(enableOutOfOrder) - .Policy(policy.Get()) - .ShadowData(EShadowDataMode::Enabled) - .Columns({{"value", "Uint32", true, false}, {"key", "Uint32", true, false}}); - - CreateShardedTable(server, sender, root, name, opts); - } - - Y_UNIT_TEST(RunScan) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root") - .SetUseRealThreads(false); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto &runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - // Allow manipulating shadow data using normal schemeshard operations - runtime.GetAppData().AllowShadowDataInSchemeShardForTests = true; - - InitRoot(server, sender); - - CreateShardedTable(server, sender, "/Root", "table-1", 1, false); - - // Upsert some initial values - ExecSQL(server, sender, "UPSERT INTO `/Root/table-1` (key, value) VALUES (1, 100), (3, 300), (5, 500);"); - - CreateShardedTableForIndex(server, sender, "/Root", "table-2", 1, false); - - auto snapshot = CreateVolatileSnapshot(server, { "/Root/table-1" }); - - DoBuildIndex(server, sender, "/Root/table-1", "/Root/table-2", snapshot, NKikimrIndexBuilder::EBuildStatus::DONE); - - // Writes to shadow data should not be visible yet - auto data = ReadShardedTable(server, "/Root/table-2"); - UNIT_ASSERT_VALUES_EQUAL(data, ""); - - // Alter table: disable shadow data and change compaction policy - auto policy = NLocalDb::CreateDefaultUserTablePolicy(); - policy->KeepEraseMarkers = false; - WaitTxNotification(server, AsyncAlterAndDisableShadow(server, "/Root", "table-2", policy.Get())); - - // Shadow data must be visible now - auto data2 = ReadShardedTable(server, "/Root/table-2"); - UNIT_ASSERT_VALUES_EQUAL(data2, - "value = 100, key = 1\n" - "value = 300, key = 3\n" - "value = 500, key = 5\n"); - } - - Y_UNIT_TEST(ShadowBorrowCompaction) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings - .SetDomainName("Root") - .SetUseRealThreads(false); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto &runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - runtime.SetLogPriority(NKikimrServices::FLAT_TX_SCHEMESHARD, NLog::PRI_TRACE); - runtime.SetLogPriority(NKikimrServices::TABLET_EXECUTOR, NLog::PRI_DEBUG); - - // Allow manipulating shadow data using normal schemeshard operations - runtime.GetAppData().AllowShadowDataInSchemeShardForTests = true; - - InitRoot(server, sender); - - CreateShardedTable(server, sender, "/Root", "table-1", 1, false); - - // Upsert some initial values - ExecSQL(server, sender, "UPSERT INTO `/Root/table-1` (key, value) VALUES (1, 100), (2, 200), (3, 300), (4, 400), (5, 500);"); - - CreateShardedTableForIndex(server, sender, "/Root", "table-2", 1, false); - - TBlockEvents block(runtime, [&](const TEvDataShard::TEvCompactBorrowed::TPtr& event) { - return runtime.FindActorName(event->Sender) == "FLAT_SCHEMESHARD_ACTOR"; - }); - - auto snapshot = CreateVolatileSnapshot(server, { "/Root/table-1" }); - - DoBuildIndex(server, sender, "/Root/table-1", "/Root/table-2", snapshot, NKikimrIndexBuilder::EBuildStatus::DONE); - - // Writes to shadow data should not be visible yet - auto data = ReadShardedTable(server, "/Root/table-2"); - UNIT_ASSERT_VALUES_EQUAL(data, ""); - - // Split index - auto shards1 = GetTableShards(server, sender, "/Root/table-2"); - UNIT_ASSERT_VALUES_EQUAL(shards1.size(), 1u); - - // Split would fail otherwise :( - SetSplitMergePartCountLimit(server->GetRuntime(), -1); - - auto senderSplit = runtime.AllocateEdgeActor(); - ui64 txId = AsyncSplitTable(server, senderSplit, "/Root/table-2", shards1.at(0), 300); - WaitTxNotification(server, senderSplit, txId); - - auto shards2 = GetTableShards(server, sender, "/Root/table-2"); - UNIT_ASSERT_VALUES_EQUAL(shards2.size(), 2u); - - for (auto shardIndex : xrange(2u)) { - auto stats = WaitTableStats(runtime, shards2.at(shardIndex)); - // Cerr << "Received shard stats:" << Endl << stats.DebugString() << Endl; - - UNIT_ASSERT_VALUES_EQUAL(stats.GetTableStats().GetRowCount(), shardIndex == 0 ? 2 : 3); - - THashSet owners(stats.GetUserTablePartOwners().begin(), stats.GetUserTablePartOwners().end()); - // Note: datashard always adds current shard to part owners, even if there are no parts - UNIT_ASSERT_VALUES_EQUAL(owners, (THashSet{shards1.at(0), shards2.at(shardIndex)})); - - auto tableId = ResolveTableId(server, sender, "/Root/table-2"); - auto result = CompactBorrowed(runtime, shards2.at(shardIndex), tableId); - // Cerr << "Compact result " << result.DebugString() << Endl; - UNIT_ASSERT_VALUES_EQUAL(result.GetTabletId(), shards2.at(shardIndex)); - UNIT_ASSERT_VALUES_EQUAL(result.GetPathId().GetOwnerId(), tableId.PathId.OwnerId); - UNIT_ASSERT_VALUES_EQUAL(result.GetPathId().GetLocalId(), tableId.PathId.LocalPathId); - - for (int i = 0; i < 5 && (owners.size() > 1 || owners.contains(shards1.at(0))); ++i) { - auto stats = WaitTableStats(runtime, shards2.at(shardIndex)); - owners = THashSet(stats.GetUserTablePartOwners().begin(), stats.GetUserTablePartOwners().end()); - } - - UNIT_ASSERT_VALUES_EQUAL(owners, (THashSet{shards2.at(shardIndex)})); - } - - // Alter table: disable shadow data and change compaction policy - auto policy = NLocalDb::CreateDefaultUserTablePolicy(); - policy->KeepEraseMarkers = false; - WaitTxNotification(server, AsyncAlterAndDisableShadow(server, "/Root", "table-2", policy.Get())); - - // Shadow data must be visible now - auto data2 = ReadShardedTable(server, "/Root/table-2"); - UNIT_ASSERT_VALUES_EQUAL(data2, - "value = 100, key = 1\n" - "value = 200, key = 2\n" - "value = 300, key = 3\n" - "value = 400, key = 4\n" - "value = 500, key = 5\n"); - } -} - -} // namespace NKikimr diff --git a/ydb/core/tx/datashard/datashard_ut_local_kmeans.cpp b/ydb/core/tx/datashard/datashard_ut_local_kmeans.cpp deleted file mode 100644 index 3d081ef34add..000000000000 --- a/ydb/core/tx/datashard/datashard_ut_local_kmeans.cpp +++ /dev/null @@ -1,668 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -namespace NKikimr { -using namespace Tests; -using Ydb::Table::VectorIndexSettings; -using namespace NTableIndex::NTableVectorKmeansTreeIndex; - -static std::atomic sId = 1; -static constexpr const char* kMainTable = "/Root/table-main"; -static constexpr const char* kLevelTable = "/Root/table-level"; -static constexpr const char* kPostingTable = "/Root/table-posting"; - -Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { - static void DoBadRequest(Tests::TServer::TPtr server, TActorId sender, - std::unique_ptr & ev, size_t dims = 2, - VectorIndexSettings::VectorType type = VectorIndexSettings::VECTOR_TYPE_FLOAT, - VectorIndexSettings::Metric metric = VectorIndexSettings::DISTANCE_COSINE) - { - auto id = sId.fetch_add(1, std::memory_order_relaxed); - auto& runtime = *server->GetRuntime(); - auto snapshot = CreateVolatileSnapshot(server, {kMainTable}); - auto datashards = GetTableShards(server, sender, kMainTable); - TTableId tableId = ResolveTableId(server, sender, kMainTable); - - TStringBuilder data; - TString err; - UNIT_ASSERT(datashards.size() == 1); - - for (auto tid : datashards) { - auto& rec = ev->Record; - rec.SetId(1); - - rec.SetSeqNoGeneration(id); - rec.SetSeqNoRound(1); - - if (!rec.HasTabletId()) { - rec.SetTabletId(tid); - } - if (!rec.HasPathId()) { - tableId.PathId.ToProto(rec.MutablePathId()); - } - - rec.SetSnapshotTxId(snapshot.TxId); - rec.SetSnapshotStep(snapshot.Step); - - VectorIndexSettings settings; - settings.set_vector_dimension(dims); - settings.set_vector_type(type); - settings.set_metric(metric); - *rec.MutableSettings() = settings; - - if (!rec.HasK()) { - rec.SetK(2); - } - rec.SetSeed(1337); - - rec.SetUpload(NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING); - - rec.SetNeedsRounds(3); - - rec.SetParentFrom(0); - rec.SetParentTo(0); - rec.SetChild(1); - - if (rec.HasEmbeddingColumn()) { - rec.ClearEmbeddingColumn(); - } else { - rec.SetEmbeddingColumn("embedding"); - } - - rec.SetLevelName(kLevelTable); - rec.SetPostingName(kPostingTable); - - runtime.SendToPipe(tid, sender, ev.release(), 0, GetPipeConfigWithRetries()); - - TAutoPtr handle; - auto reply = runtime.GrabEdgeEventRethrow(handle); - UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); - } - } - - static std::tuple DoLocalKMeans( - Tests::TServer::TPtr server, TActorId sender, NTableIndex::TClusterId parent, ui64 seed, ui64 k, - NKikimrTxDataShard::EKMeansState upload, VectorIndexSettings::VectorType type, - VectorIndexSettings::Metric metric) - { - auto id = sId.fetch_add(1, std::memory_order_relaxed); - auto& runtime = *server->GetRuntime(); - auto snapshot = CreateVolatileSnapshot(server, {kMainTable}); - auto datashards = GetTableShards(server, sender, kMainTable); - TTableId tableId = ResolveTableId(server, sender, kMainTable); - - TString err; - - for (auto tid : datashards) { - auto ev1 = std::make_unique(); - auto ev2 = std::make_unique(); - auto fill = [&](std::unique_ptr& ev) { - auto& rec = ev->Record; - rec.SetId(1); - - rec.SetSeqNoGeneration(id); - rec.SetSeqNoRound(1); - - rec.SetTabletId(tid); - tableId.PathId.ToProto(rec.MutablePathId()); - - rec.SetSnapshotTxId(snapshot.TxId); - rec.SetSnapshotStep(snapshot.Step); - - VectorIndexSettings settings; - settings.set_vector_dimension(2); - settings.set_vector_type(type); - settings.set_metric(metric); - *rec.MutableSettings() = settings; - - rec.SetK(k); - rec.SetSeed(seed); - - rec.SetUpload(upload); - - rec.SetNeedsRounds(300); - - rec.SetParentFrom(parent); - rec.SetParentTo(parent); - rec.SetChild(parent + 1); - - rec.SetEmbeddingColumn("embedding"); - rec.AddDataColumns("data"); - - rec.SetLevelName(kLevelTable); - rec.SetPostingName(kPostingTable); - }; - fill(ev1); - fill(ev2); - - runtime.SendToPipe(tid, sender, ev1.release(), 0, GetPipeConfigWithRetries()); - runtime.SendToPipe(tid, sender, ev2.release(), 0, GetPipeConfigWithRetries()); - - TAutoPtr handle; - auto reply = runtime.GrabEdgeEventRethrow(handle); - - NYql::TIssues issues; - NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); - UNIT_ASSERT_EQUAL_C(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::DONE, - issues.ToOneLineString()); - } - - auto level = ReadShardedTable(server, kLevelTable); - auto posting = ReadShardedTable(server, kPostingTable); - return {std::move(level), std::move(posting)}; - } - - static void DropTable(Tests::TServer::TPtr server, TActorId sender, const char* name) - { - ui64 txId = AsyncDropTable(server, sender, "/Root", name); - WaitTxNotification(server, sender, txId); - } - - static void CreateMainTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) - { - options.AllowSystemColumnNames(false); - options.Columns({ - {"key", "Uint32", true, true}, - {"embedding", "String", false, false}, - {"data", "String", false, false}, - }); - CreateShardedTable(server, sender, "/Root", "table-main", options); - } - - static void CreateLevelTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) - { - options.AllowSystemColumnNames(true); - options.Columns({ - {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, - {IdColumn, NTableIndex::ClusterIdTypeName, true, true}, - {CentroidColumn, "String", false, true}, - }); - CreateShardedTable(server, sender, "/Root", "table-level", options); - } - - static void CreatePostingTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) - { - options.AllowSystemColumnNames(true); - options.Columns({ - {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, - {"key", "Uint32", true, true}, - {"data", "String", false, false}, - }); - CreateShardedTable(server, sender, "/Root", "table-posting", options); - } - - static void CreateBuildTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options, - const char* name) - { - options.AllowSystemColumnNames(true); - options.Columns({ - {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, - {"key", "Uint32", true, true}, - {"embedding", "String", false, false}, - {"data", "String", false, false}, - }); - CreateShardedTable(server, sender, "/Root", name, options); - } - - Y_UNIT_TEST (BadRequest) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - CreateShardedTable(server, sender, "/Root", "table-main", 1); - - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetK(0); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetK(1); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetEmbeddingColumn("some"); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetTabletId(0); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - TPathId(0, 0).ToProto(rec.MutablePathId()); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - - DoBadRequest(server, sender, ev, 0); - } - { - auto ev = std::make_unique(); - - // TODO(mbkkt) bit vector not supported for now - DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_BIT); - } - { - auto ev = std::make_unique(); - - DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_UNSPECIFIED); - } - { - auto ev = std::make_unique(); - - DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_FLOAT, - VectorIndexSettings::METRIC_UNSPECIFIED); - } - // TODO(mbkkt) For now all build_index, sample_k, build_columns, local_kmeans doesn't really check this - // { - // auto ev = std::make_unique(); - // auto snapshotCopy = snapshot; - // snapshotCopy.Step++; - // DoBadRequest(server, sender, ev); - // } - // { - // auto ev = std::make_unique(); - // auto snapshotCopy = snapshot; - // snapshotCopy.TxId++; - // DoBadRequest(server, sender, ev); - // } - } - - Y_UNIT_TEST (MainToPosting) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateMainTable(server, sender, options); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (key, embedding, data) - VALUES )" - "(1, \"\x30\x30\3\", \"one\")," - "(2, \"\x31\x31\3\", \"two\")," - "(3, \"\x32\x32\3\", \"three\")," - "(4, \"\x65\x65\3\", \"four\")," - "(5, \"\x75\x75\3\", \"five\");"); - - auto create = [&] { - CreateLevelTable(server, sender, options); - CreatePostingTable(server, sender, options); - }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-level"); - DropTable(server, sender, "table-posting"); - create(); - }; - - ui64 seed, k; - k = 2; - - seed = 0; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = mm\3\n" - "__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = 11\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, data = four\n" - "__ydb_parent = 1, key = 5, data = five\n" - "__ydb_parent = 2, key = 1, data = one\n" - "__ydb_parent = 2, key = 2, data = two\n" - "__ydb_parent = 2, key = 3, data = three\n"); - recreate(); - } - - seed = 111; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = 11\3\n" - "__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = mm\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n" - "__ydb_parent = 1, key = 2, data = two\n" - "__ydb_parent = 1, key = 3, data = three\n" - "__ydb_parent = 2, key = 4, data = four\n" - "__ydb_parent = 2, key = 5, data = five\n"); - recreate(); - } - seed = 32; - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, - VectorIndexSettings::DISTANCE_COSINE}) - { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = II\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n" - "__ydb_parent = 1, key = 2, data = two\n" - "__ydb_parent = 1, key = 3, data = three\n" - "__ydb_parent = 1, key = 4, data = four\n" - "__ydb_parent = 1, key = 5, data = five\n"); - recreate(); - } - } - - Y_UNIT_TEST (MainToBuild) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateMainTable(server, sender, options); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (key, embedding, data) - VALUES )" - "(1, \"\x30\x30\3\", \"one\")," - "(2, \"\x31\x31\3\", \"two\")," - "(3, \"\x32\x32\3\", \"three\")," - "(4, \"\x65\x65\3\", \"four\")," - "(5, \"\x75\x75\3\", \"five\");"); - - auto create = [&] { - CreateLevelTable(server, sender, options); - CreateBuildTable(server, sender, options, "table-posting"); - }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-level"); - DropTable(server, sender, "table-posting"); - create(); - }; - - ui64 seed, k; - k = 2; - - seed = 0; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = mm\3\n" - "__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = 11\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 1, key = 5, embedding = \x75\x75\3, data = five\n" - "__ydb_parent = 2, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 2, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 2, key = 3, embedding = \x32\x32\3, data = three\n"); - recreate(); - } - - seed = 111; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = 11\3\n" - "__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = mm\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n" - "__ydb_parent = 2, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 2, key = 5, embedding = \x75\x75\3, data = five\n"); - recreate(); - } - seed = 32; - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, - VectorIndexSettings::DISTANCE_COSINE}) - { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = II\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n" - "__ydb_parent = 1, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 1, key = 5, embedding = \x75\x75\3, data = five\n"); - recreate(); - } - } - - Y_UNIT_TEST (BuildToPosting) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateBuildTable(server, sender, options, "table-main"); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (__ydb_parent, key, embedding, data) - VALUES )" - "(39, 1, \"\x30\x30\3\", \"one\")," - "(40, 1, \"\x30\x30\3\", \"one\")," - "(40, 2, \"\x31\x31\3\", \"two\")," - "(40, 3, \"\x32\x32\3\", \"three\")," - "(40, 4, \"\x65\x65\3\", \"four\")," - "(40, 5, \"\x75\x75\3\", \"five\")," - "(41, 5, \"\x75\x75\3\", \"five\");"); - - auto create = [&] { - CreateLevelTable(server, sender, options); - CreatePostingTable(server, sender, options); - }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-level"); - DropTable(server, sender, "table-posting"); - create(); - }; - - ui64 seed, k; - k = 2; - - seed = 0; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" - "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, data = four\n" - "__ydb_parent = 41, key = 5, data = five\n" - "__ydb_parent = 42, key = 1, data = one\n" - "__ydb_parent = 42, key = 2, data = two\n" - "__ydb_parent = 42, key = 3, data = three\n"); - recreate(); - } - - seed = 111; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" - "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n" - "__ydb_parent = 41, key = 2, data = two\n" - "__ydb_parent = 41, key = 3, data = three\n" - "__ydb_parent = 42, key = 4, data = four\n" - "__ydb_parent = 42, key = 5, data = five\n"); - recreate(); - } - seed = 32; - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, - VectorIndexSettings::DISTANCE_COSINE}) - { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n" - "__ydb_parent = 41, key = 2, data = two\n" - "__ydb_parent = 41, key = 3, data = three\n" - "__ydb_parent = 41, key = 4, data = four\n" - "__ydb_parent = 41, key = 5, data = five\n"); - recreate(); - } - } - - Y_UNIT_TEST (BuildToBuild) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateBuildTable(server, sender, options, "table-main"); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (__ydb_parent, key, embedding, data) - VALUES )" - "(39, 1, \"\x30\x30\3\", \"one\")," - "(40, 1, \"\x30\x30\3\", \"one\")," - "(40, 2, \"\x31\x31\3\", \"two\")," - "(40, 3, \"\x32\x32\3\", \"three\")," - "(40, 4, \"\x65\x65\3\", \"four\")," - "(40, 5, \"\x75\x75\3\", \"five\")," - "(41, 5, \"\x75\x75\3\", \"five\");"); - - auto create = [&] { - CreateLevelTable(server, sender, options); - CreateBuildTable(server, sender, options, "table-posting"); - }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-level"); - DropTable(server, sender, "table-posting"); - create(); - }; - - ui64 seed, k; - k = 2; - - seed = 0; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" - "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 41, key = 5, embedding = \x75\x75\3, data = five\n" - "__ydb_parent = 42, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 42, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 42, key = 3, embedding = \x32\x32\3, data = three\n"); - recreate(); - } - - seed = 111; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" - "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" - "__ydb_parent = 42, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 42, key = 5, embedding = \x75\x75\3, data = five\n"); - recreate(); - } - seed = 32; - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, - VectorIndexSettings::DISTANCE_COSINE}) - { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); - UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n"); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" - "__ydb_parent = 41, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 41, key = 5, embedding = \x75\x75\3, data = five\n"); - recreate(); - } - } -} - -} diff --git a/ydb/core/tx/datashard/datashard_ut_prefix_kmeans.cpp b/ydb/core/tx/datashard/datashard_ut_prefix_kmeans.cpp deleted file mode 100644 index 4bab0e10981e..000000000000 --- a/ydb/core/tx/datashard/datashard_ut_prefix_kmeans.cpp +++ /dev/null @@ -1,616 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -namespace NKikimr { -using namespace Tests; -using Ydb::Table::VectorIndexSettings; -using namespace NTableIndex::NTableVectorKmeansTreeIndex; - -static std::atomic sId = 1; -static constexpr const char* kMainTable = "/Root/table-main"; -static constexpr const char* kPrefixTable = "/Root/table-prefix"; -static constexpr const char* kLevelTable = "/Root/table-level"; -static constexpr const char* kPostingTable = "/Root/table-posting"; - -Y_UNIT_TEST_SUITE (TTxDataShardPrefixKMeansScan) { - static void DoBadRequest(Tests::TServer::TPtr server, TActorId sender, - std::unique_ptr & ev, size_t dims = 2, - VectorIndexSettings::VectorType type = VectorIndexSettings::VECTOR_TYPE_FLOAT, - VectorIndexSettings::Metric metric = VectorIndexSettings::DISTANCE_COSINE) - { - auto id = sId.fetch_add(1, std::memory_order_relaxed); - auto& runtime = *server->GetRuntime(); - auto datashards = GetTableShards(server, sender, kMainTable); - TTableId tableId = ResolveTableId(server, sender, kMainTable); - - TStringBuilder data; - TString err; - UNIT_ASSERT(datashards.size() == 1); - - for (auto tid : datashards) { - auto& rec = ev->Record; - rec.SetId(1); - - rec.SetSeqNoGeneration(id); - rec.SetSeqNoRound(1); - - if (!rec.HasTabletId()) { - rec.SetTabletId(tid); - } - if (!rec.HasPathId()) { - tableId.PathId.ToProto(rec.MutablePathId()); - } - - VectorIndexSettings settings; - settings.set_vector_dimension(dims); - settings.set_vector_type(type); - settings.set_metric(metric); - *rec.MutableSettings() = settings; - - if (!rec.HasK()) { - rec.SetK(2); - } - rec.SetSeed(1337); - - rec.SetUpload(NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING); - - rec.SetNeedsRounds(3); - - rec.SetChild(1); - - if (rec.HasEmbeddingColumn()) { - rec.ClearEmbeddingColumn(); - } else { - rec.SetEmbeddingColumn("embedding"); - } - - rec.SetLevelName(kLevelTable); - rec.SetPostingName(kPostingTable); - - runtime.SendToPipe(tid, sender, ev.release(), 0, GetPipeConfigWithRetries()); - - TAutoPtr handle; - auto reply = runtime.GrabEdgeEventRethrow(handle); - UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); - } - } - - static std::tuple DoPrefixKMeans( - Tests::TServer::TPtr server, TActorId sender, NTableIndex::TClusterId parent, ui64 seed, ui64 k, - NKikimrTxDataShard::EKMeansState upload, VectorIndexSettings::VectorType type, - VectorIndexSettings::Metric metric, ui32 maxBatchRows) - { - auto id = sId.fetch_add(1, std::memory_order_relaxed); - auto& runtime = *server->GetRuntime(); - auto datashards = GetTableShards(server, sender, kMainTable); - TTableId tableId = ResolveTableId(server, sender, kMainTable); - - TString err; - - for (auto tid : datashards) { - auto ev1 = std::make_unique(); - auto ev2 = std::make_unique(); - auto fill = [&](std::unique_ptr& ev) { - auto& rec = ev->Record; - rec.SetId(1); - - rec.SetSeqNoGeneration(id); - rec.SetSeqNoRound(1); - - rec.SetTabletId(tid); - tableId.PathId.ToProto(rec.MutablePathId()); - - VectorIndexSettings settings; - settings.set_vector_dimension(2); - settings.set_vector_type(type); - settings.set_metric(metric); - *rec.MutableSettings() = settings; - - rec.SetK(k); - rec.SetSeed(seed); - - rec.SetUpload(upload); - - rec.SetNeedsRounds(300); - - rec.SetChild(parent); - - rec.SetEmbeddingColumn("embedding"); - rec.AddDataColumns("data"); - rec.SetPrefixColumns(1); - - rec.SetPrefixName(kPrefixTable); - rec.SetLevelName(kLevelTable); - rec.SetPostingName(kPostingTable); - - rec.MutableScanSettings()->SetMaxBatchRows(maxBatchRows); - }; - fill(ev1); - fill(ev2); - - runtime.SendToPipe(tid, sender, ev1.release(), 0, GetPipeConfigWithRetries()); - runtime.SendToPipe(tid, sender, ev2.release(), 0, GetPipeConfigWithRetries()); - - TAutoPtr handle; - auto reply = runtime.GrabEdgeEventRethrow(handle); - - NYql::TIssues issues; - NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); - UNIT_ASSERT_EQUAL_C(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::DONE, - issues.ToOneLineString()); - } - - auto prefix = ReadShardedTable(server, kPrefixTable); - auto level = ReadShardedTable(server, kLevelTable); - auto posting = ReadShardedTable(server, kPostingTable); - return {std::move(prefix), std::move(level), std::move(posting)}; - } - - static void DropTable(Tests::TServer::TPtr server, TActorId sender, const char* name) - { - ui64 txId = AsyncDropTable(server, sender, "/Root", name); - WaitTxNotification(server, sender, txId); - } - - static void CreatePrefixTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) - { - options.AllowSystemColumnNames(true); - options.Columns({ - {"user", "String", true, true}, - {IdColumn, NTableIndex::ClusterIdTypeName, true, true}, - }); - CreateShardedTable(server, sender, "/Root", "table-prefix", options); - } - - static void CreateLevelTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) - { - options.AllowSystemColumnNames(true); - options.Columns({ - {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, - {IdColumn, NTableIndex::ClusterIdTypeName, true, true}, - {CentroidColumn, "String", false, true}, - }); - CreateShardedTable(server, sender, "/Root", "table-level", options); - } - - static void CreatePostingTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) - { - options.AllowSystemColumnNames(true); - options.Columns({ - {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, - {"key", "Uint32", true, true}, - {"data", "String", false, false}, - }); - CreateShardedTable(server, sender, "/Root", "table-posting", options); - } - - static void CreateBuildTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options, - const char* name) - { - options.AllowSystemColumnNames(true); - options.Columns({ - {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, - {"key", "Uint32", true, true}, - {"embedding", "String", false, false}, - {"data", "String", false, false}, - }); - CreateShardedTable(server, sender, "/Root", name, options); - } - - static void CreateBuildPrefixTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options, - const char* name) - { - options.Columns({ - {"user", "String", true, true}, - {"key", "Uint32", true, true}, - {"embedding", "String", false, false}, - {"data", "String", false, false}, - }); - CreateShardedTable(server, sender, "/Root", name, options); - } - - Y_UNIT_TEST (BadRequest) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); - - InitRoot(server, sender); - - CreateShardedTable(server, sender, "/Root", "table-main", 1); - - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetK(0); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetK(1); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetEmbeddingColumn("some"); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetTabletId(0); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - TPathId(0, 0).ToProto(rec.MutablePathId()); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - - DoBadRequest(server, sender, ev, 0); - } - { - auto ev = std::make_unique(); - - // TODO(mbkkt) bit vector not supported for now - DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_BIT); - } - { - auto ev = std::make_unique(); - - DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_UNSPECIFIED); - } - { - auto ev = std::make_unique(); - - DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_FLOAT, - VectorIndexSettings::METRIC_UNSPECIFIED); - } - // TODO(mbkkt) For now all build_index, sample_k, build_columns, local_kmeans, prefix_kmeans doesn't really check this - // { - // auto ev = std::make_unique(); - // auto snapshotCopy = snapshot; - // snapshotCopy.Step++; - // DoBadRequest(server, sender, ev); - // } - // { - // auto ev = std::make_unique(); - // auto snapshotCopy = snapshot; - // snapshotCopy.TxId++; - // DoBadRequest(server, sender, ev); - // } - } - - Y_UNIT_TEST (BuildToPosting) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateBuildPrefixTable(server, sender, options, "table-main"); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (user, key, embedding, data) - VALUES )" - "(\"user-1\", 11, \"\x30\x30\3\", \"1-one\")," - "(\"user-1\", 12, \"\x31\x31\3\", \"1-two\")," - "(\"user-1\", 13, \"\x32\x32\3\", \"1-three\")," - "(\"user-1\", 14, \"\x65\x65\3\", \"1-four\")," - "(\"user-1\", 15, \"\x75\x75\3\", \"1-five\")," - - "(\"user-2\", 21, \"\x30\x30\3\", \"2-one\")," - "(\"user-2\", 22, \"\x31\x31\3\", \"2-two\")," - "(\"user-2\", 23, \"\x32\x32\3\", \"2-three\")," - "(\"user-2\", 24, \"\x65\x65\3\", \"2-four\")," - "(\"user-2\", 25, \"\x75\x75\3\", \"2-five\");"); - - auto create = [&] { - CreatePrefixTable(server, sender, options); - CreateLevelTable(server, sender, options); - CreatePostingTable(server, sender, options); - }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-prefix"); - DropTable(server, sender, "table-level"); - DropTable(server, sender, "table-posting"); - create(); - }; - - ui64 seed, k; - k = 2; - - seed = 0; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { - auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance, maxBatchRows); - UNIT_ASSERT_VALUES_EQUAL(prefix, - "user = user-1, __ydb_id = 40\n" - - "user = user-2, __ydb_id = 43\n" - ); - UNIT_ASSERT_VALUES_EQUAL(level, - "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" - "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n" - - "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = 11\3\n" - "__ydb_parent = 43, __ydb_id = 45, __ydb_centroid = mm\3\n" - ); - UNIT_ASSERT_VALUES_EQUAL(posting, - "__ydb_parent = 41, key = 14, data = 1-four\n" - "__ydb_parent = 41, key = 15, data = 1-five\n" - "__ydb_parent = 42, key = 11, data = 1-one\n" - "__ydb_parent = 42, key = 12, data = 1-two\n" - "__ydb_parent = 42, key = 13, data = 1-three\n" - - "__ydb_parent = 44, key = 21, data = 2-one\n" - "__ydb_parent = 44, key = 22, data = 2-two\n" - "__ydb_parent = 44, key = 23, data = 2-three\n" - "__ydb_parent = 45, key = 24, data = 2-four\n" - "__ydb_parent = 45, key = 25, data = 2-five\n" - ); - recreate(); - }} - - seed = 111; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { - auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance, maxBatchRows); - UNIT_ASSERT_VALUES_EQUAL(prefix, - "user = user-1, __ydb_id = 40\n" - - "user = user-2, __ydb_id = 43\n" - ); - UNIT_ASSERT_VALUES_EQUAL(level, - "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" - "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n" - - "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = 11\3\n" - "__ydb_parent = 43, __ydb_id = 45, __ydb_centroid = mm\3\n" - ); - UNIT_ASSERT_VALUES_EQUAL(posting, - "__ydb_parent = 41, key = 11, data = 1-one\n" - "__ydb_parent = 41, key = 12, data = 1-two\n" - "__ydb_parent = 41, key = 13, data = 1-three\n" - "__ydb_parent = 42, key = 14, data = 1-four\n" - "__ydb_parent = 42, key = 15, data = 1-five\n" - - "__ydb_parent = 44, key = 21, data = 2-one\n" - "__ydb_parent = 44, key = 22, data = 2-two\n" - "__ydb_parent = 44, key = 23, data = 2-three\n" - "__ydb_parent = 45, key = 24, data = 2-four\n" - "__ydb_parent = 45, key = 25, data = 2-five\n" - ); - recreate(); - }} - seed = 32; - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, VectorIndexSettings::DISTANCE_COSINE}) { - for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { - auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity, maxBatchRows); - UNIT_ASSERT_VALUES_EQUAL(prefix, - "user = user-1, __ydb_id = 40\n" - - "user = user-2, __ydb_id = 43\n" - ); - UNIT_ASSERT_VALUES_EQUAL(level, - "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n" - - "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = II\3\n" - ); - UNIT_ASSERT_VALUES_EQUAL(posting, - "__ydb_parent = 41, key = 11, data = 1-one\n" - "__ydb_parent = 41, key = 12, data = 1-two\n" - "__ydb_parent = 41, key = 13, data = 1-three\n" - "__ydb_parent = 41, key = 14, data = 1-four\n" - "__ydb_parent = 41, key = 15, data = 1-five\n" - - "__ydb_parent = 44, key = 21, data = 2-one\n" - "__ydb_parent = 44, key = 22, data = 2-two\n" - "__ydb_parent = 44, key = 23, data = 2-three\n" - "__ydb_parent = 44, key = 24, data = 2-four\n" - "__ydb_parent = 44, key = 25, data = 2-five\n" - ); - recreate(); - }} - } - - Y_UNIT_TEST (BuildToBuild) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateBuildPrefixTable(server, sender, options, "table-main"); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (user, key, embedding, data) - VALUES )" - "(\"user-1\", 11, \"\x30\x30\3\", \"1-one\")," - "(\"user-1\", 12, \"\x31\x31\3\", \"1-two\")," - "(\"user-1\", 13, \"\x32\x32\3\", \"1-three\")," - "(\"user-1\", 14, \"\x65\x65\3\", \"1-four\")," - "(\"user-1\", 15, \"\x75\x75\3\", \"1-five\")," - - "(\"user-2\", 21, \"\x30\x30\3\", \"2-one\")," - "(\"user-2\", 22, \"\x31\x31\3\", \"2-two\")," - "(\"user-2\", 23, \"\x32\x32\3\", \"2-three\")," - "(\"user-2\", 24, \"\x65\x65\3\", \"2-four\")," - "(\"user-2\", 25, \"\x75\x75\3\", \"2-five\");"); - - auto create = [&] { - CreatePrefixTable(server, sender, options); - CreateLevelTable(server, sender, options); - CreateBuildTable(server, sender, options, "table-posting"); - }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-prefix"); - DropTable(server, sender, "table-level"); - DropTable(server, sender, "table-posting"); - create(); - }; - - ui64 seed, k; - k = 2; - - seed = 0; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { - auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance, maxBatchRows); - UNIT_ASSERT_VALUES_EQUAL(prefix, - "user = user-1, __ydb_id = 40\n" - - "user = user-2, __ydb_id = 43\n" - ); - UNIT_ASSERT_VALUES_EQUAL(level, - "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" - "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n" - - "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = 11\3\n" - "__ydb_parent = 43, __ydb_id = 45, __ydb_centroid = mm\3\n" - ); - UNIT_ASSERT_VALUES_EQUAL(posting, - "__ydb_parent = 41, key = 14, embedding = \x65\x65\3, data = 1-four\n" - "__ydb_parent = 41, key = 15, embedding = \x75\x75\3, data = 1-five\n" - "__ydb_parent = 42, key = 11, embedding = \x30\x30\3, data = 1-one\n" - "__ydb_parent = 42, key = 12, embedding = \x31\x31\3, data = 1-two\n" - "__ydb_parent = 42, key = 13, embedding = \x32\x32\3, data = 1-three\n" - - "__ydb_parent = 44, key = 21, embedding = \x30\x30\3, data = 2-one\n" - "__ydb_parent = 44, key = 22, embedding = \x31\x31\3, data = 2-two\n" - "__ydb_parent = 44, key = 23, embedding = \x32\x32\3, data = 2-three\n" - "__ydb_parent = 45, key = 24, embedding = \x65\x65\3, data = 2-four\n" - "__ydb_parent = 45, key = 25, embedding = \x75\x75\3, data = 2-five\n" - ); - recreate(); - }} - - seed = 111; - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { - auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance, maxBatchRows); - UNIT_ASSERT_VALUES_EQUAL(prefix, - "user = user-1, __ydb_id = 40\n" - - "user = user-2, __ydb_id = 43\n" - ); - UNIT_ASSERT_VALUES_EQUAL(level, - "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" - "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n" - - "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = 11\3\n" - "__ydb_parent = 43, __ydb_id = 45, __ydb_centroid = mm\3\n" - ); - UNIT_ASSERT_VALUES_EQUAL(posting, - "__ydb_parent = 41, key = 11, embedding = \x30\x30\3, data = 1-one\n" - "__ydb_parent = 41, key = 12, embedding = \x31\x31\3, data = 1-two\n" - "__ydb_parent = 41, key = 13, embedding = \x32\x32\3, data = 1-three\n" - "__ydb_parent = 42, key = 14, embedding = \x65\x65\3, data = 1-four\n" - "__ydb_parent = 42, key = 15, embedding = \x75\x75\3, data = 1-five\n" - - "__ydb_parent = 44, key = 21, embedding = \x30\x30\3, data = 2-one\n" - "__ydb_parent = 44, key = 22, embedding = \x31\x31\3, data = 2-two\n" - "__ydb_parent = 44, key = 23, embedding = \x32\x32\3, data = 2-three\n" - "__ydb_parent = 45, key = 24, embedding = \x65\x65\3, data = 2-four\n" - "__ydb_parent = 45, key = 25, embedding = \x75\x75\3, data = 2-five\n" - ); - recreate(); - }} - seed = 32; - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, VectorIndexSettings::DISTANCE_COSINE}) { - for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { - auto [prefix, level, posting] = DoPrefixKMeans(server, sender, 40, seed, k, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity, maxBatchRows); - UNIT_ASSERT_VALUES_EQUAL(prefix, - "user = user-1, __ydb_id = 40\n" - - "user = user-2, __ydb_id = 43\n" - ); - UNIT_ASSERT_VALUES_EQUAL(level, - "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n" - - "__ydb_parent = 43, __ydb_id = 44, __ydb_centroid = II\3\n" - ); - UNIT_ASSERT_VALUES_EQUAL(posting, - "__ydb_parent = 41, key = 11, embedding = \x30\x30\3, data = 1-one\n" - "__ydb_parent = 41, key = 12, embedding = \x31\x31\3, data = 1-two\n" - "__ydb_parent = 41, key = 13, embedding = \x32\x32\3, data = 1-three\n" - "__ydb_parent = 41, key = 14, embedding = \x65\x65\3, data = 1-four\n" - "__ydb_parent = 41, key = 15, embedding = \x75\x75\3, data = 1-five\n" - - "__ydb_parent = 44, key = 21, embedding = \x30\x30\3, data = 2-one\n" - "__ydb_parent = 44, key = 22, embedding = \x31\x31\3, data = 2-two\n" - "__ydb_parent = 44, key = 23, embedding = \x32\x32\3, data = 2-three\n" - "__ydb_parent = 44, key = 24, embedding = \x65\x65\3, data = 2-four\n" - "__ydb_parent = 44, key = 25, embedding = \x75\x75\3, data = 2-five\n" - ); - recreate(); - }} - } -} - -} diff --git a/ydb/core/tx/datashard/datashard_ut_reshuffle_kmeans.cpp b/ydb/core/tx/datashard/datashard_ut_reshuffle_kmeans.cpp deleted file mode 100644 index 75e5663ef3d1..000000000000 --- a/ydb/core/tx/datashard/datashard_ut_reshuffle_kmeans.cpp +++ /dev/null @@ -1,620 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -namespace NKikimr { -using namespace Tests; -using Ydb::Table::VectorIndexSettings; -using namespace NTableIndex::NTableVectorKmeansTreeIndex; - -static std::atomic sId = 1; -static constexpr const char* kMainTable = "/Root/table-main"; -static constexpr const char* kPostingTable = "/Root/table-posting"; - -Y_UNIT_TEST_SUITE (TTxDataShardReshuffleKMeansScan) { - static void DoBadRequest(Tests::TServer::TPtr server, TActorId sender, - std::unique_ptr & ev, size_t dims = 2, - VectorIndexSettings::VectorType type = VectorIndexSettings::VECTOR_TYPE_FLOAT, - VectorIndexSettings::Metric metric = VectorIndexSettings::DISTANCE_COSINE) - { - auto id = sId.fetch_add(1, std::memory_order_relaxed); - auto& runtime = *server->GetRuntime(); - auto snapshot = CreateVolatileSnapshot(server, {kMainTable}); - auto datashards = GetTableShards(server, sender, kMainTable); - TTableId tableId = ResolveTableId(server, sender, kMainTable); - - TStringBuilder data; - TString err; - UNIT_ASSERT(datashards.size() == 1); - - for (auto tid : datashards) { - auto& rec = ev->Record; - rec.SetId(1); - - rec.SetSeqNoGeneration(id); - rec.SetSeqNoRound(1); - - if (!rec.HasTabletId()) { - rec.SetTabletId(tid); - } - if (!rec.HasPathId()) { - tableId.PathId.ToProto(rec.MutablePathId()); - } - - rec.SetSnapshotTxId(snapshot.TxId); - rec.SetSnapshotStep(snapshot.Step); - - VectorIndexSettings settings; - settings.set_vector_dimension(dims); - settings.set_vector_type(type); - settings.set_metric(metric); - *rec.MutableSettings() = settings; - - rec.SetUpload(NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING); - - rec.SetParent(0); - rec.SetChild(1); - - if (rec.ClustersSize() == 0) { - rec.AddClusters("something"); - } else { - rec.ClearClusters(); - } - - if (rec.HasEmbeddingColumn()) { - rec.ClearEmbeddingColumn(); - } else { - rec.SetEmbeddingColumn("embedding"); - } - - rec.SetPostingName(kPostingTable); - - runtime.SendToPipe(tid, sender, ev.release(), 0, GetPipeConfigWithRetries()); - - TAutoPtr handle; - auto reply = runtime.GrabEdgeEventRethrow(handle); - UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); - } - } - - static TString DoReshuffleKMeans(Tests::TServer::TPtr server, TActorId sender, NTableIndex::TClusterId parent, - const std::vector& level, - NKikimrTxDataShard::EKMeansState upload, - VectorIndexSettings::VectorType type, VectorIndexSettings::Metric metric) - { - auto id = sId.fetch_add(1, std::memory_order_relaxed); - auto& runtime = *server->GetRuntime(); - auto snapshot = CreateVolatileSnapshot(server, {kMainTable}); - auto datashards = GetTableShards(server, sender, kMainTable); - TTableId tableId = ResolveTableId(server, sender, kMainTable); - - TString err; - - for (auto tid : datashards) { - auto ev1 = std::make_unique(); - auto ev2 = std::make_unique(); - auto fill = [&](std::unique_ptr& ev) { - auto& rec = ev->Record; - rec.SetId(1); - - rec.SetSeqNoGeneration(id); - rec.SetSeqNoRound(1); - - rec.SetTabletId(tid); - tableId.PathId.ToProto(rec.MutablePathId()); - - rec.SetSnapshotTxId(snapshot.TxId); - rec.SetSnapshotStep(snapshot.Step); - - VectorIndexSettings settings; - settings.set_vector_dimension(2); - settings.set_vector_type(type); - settings.set_metric(metric); - *rec.MutableSettings() = settings; - - rec.SetUpload(upload); - - *rec.MutableClusters() = {level.begin(), level.end()}; - - rec.SetParent(parent); - rec.SetChild(parent + 1); - - rec.SetEmbeddingColumn("embedding"); - rec.AddDataColumns("data"); - - rec.SetPostingName(kPostingTable); - }; - fill(ev1); - fill(ev2); - - runtime.SendToPipe(tid, sender, ev1.release(), 0, GetPipeConfigWithRetries()); - runtime.SendToPipe(tid, sender, ev2.release(), 0, GetPipeConfigWithRetries()); - - TAutoPtr handle; - auto reply = runtime.GrabEdgeEventRethrow(handle); - - NYql::TIssues issues; - NYql::IssuesFromMessage(reply->Record.GetIssues(), issues); - UNIT_ASSERT_EQUAL_C(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::DONE, - issues.ToOneLineString()); - } - - auto posting = ReadShardedTable(server, kPostingTable); - return std::move(posting); - } - - static void DropTable(Tests::TServer::TPtr server, TActorId sender, const char* name) - { - ui64 txId = AsyncDropTable(server, sender, "/Root", name); - WaitTxNotification(server, sender, txId); - } - - static void CreateMainTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) - { - options.AllowSystemColumnNames(false); - options.Columns({ - {"key", "Uint32", true, true}, - {"embedding", "String", false, false}, - {"data", "String", false, false}, - }); - CreateShardedTable(server, sender, "/Root", "table-main", options); - } - - static void CreatePostingTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options) - { - options.AllowSystemColumnNames(true); - options.Columns({ - {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, - {"key", "Uint32", true, true}, - {"data", "String", false, false}, - }); - CreateShardedTable(server, sender, "/Root", "table-posting", options); - } - - static void CreateBuildTable(Tests::TServer::TPtr server, TActorId sender, TShardedTableOptions options, - const char* name) - { - options.AllowSystemColumnNames(true); - options.Columns({ - {ParentColumn, NTableIndex::ClusterIdTypeName, true, true}, - {"key", "Uint32", true, true}, - {"embedding", "String", false, false}, - {"data", "String", false, false}, - }); - CreateShardedTable(server, sender, "/Root", name, options); - } - - Y_UNIT_TEST (BadRequest) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - CreateShardedTable(server, sender, "/Root", "table-main", 1); - - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.AddClusters("to make it empty"); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetEmbeddingColumn("to make it empty"); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetTabletId(0); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - TPathId(0, 0).ToProto(rec.MutablePathId()); - DoBadRequest(server, sender, ev); - } - { - auto ev = std::make_unique(); - - DoBadRequest(server, sender, ev, 0); - } - { - auto ev = std::make_unique(); - - // TODO(mbkkt) bit vector not supported for now - DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_BIT); - } - { - auto ev = std::make_unique(); - - DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_UNSPECIFIED); - } - { - auto ev = std::make_unique(); - - DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_FLOAT, - VectorIndexSettings::METRIC_UNSPECIFIED); - } - // TODO(mbkkt) For now all build_index, sample_k, build_columns, local_kmeans doesn't really check this - // { - // auto ev = std::make_unique(); - // auto snapshotCopy = snapshot; - // snapshotCopy.Step++; - // DoBadRequest(server, sender, ev); - // } - // { - // auto ev = std::make_unique(); - // auto snapshotCopy = snapshot; - // snapshotCopy.TxId++; - // DoBadRequest(server, sender, ev); - // } - } - - Y_UNIT_TEST (MainToPosting) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateMainTable(server, sender, options); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (key, embedding, data) - VALUES )" - "(1, \"\x30\x30\3\", \"one\")," - "(2, \"\x31\x31\3\", \"two\")," - "(3, \"\x32\x32\3\", \"three\")," - "(4, \"\x65\x65\3\", \"four\")," - "(5, \"\x75\x75\3\", \"five\");"); - - auto create = [&] { CreatePostingTable(server, sender, options); }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-posting"); - create(); - }; - - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - std::vector level = { - "mm\3", - "11\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 0, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, data = four\n" - "__ydb_parent = 1, key = 5, data = five\n" - "__ydb_parent = 2, key = 1, data = one\n" - "__ydb_parent = 2, key = 2, data = two\n" - "__ydb_parent = 2, key = 3, data = three\n"); - recreate(); - } - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - std::vector level = { - "11\3", - "mm\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 0, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n" - "__ydb_parent = 1, key = 2, data = two\n" - "__ydb_parent = 1, key = 3, data = three\n" - "__ydb_parent = 2, key = 4, data = four\n" - "__ydb_parent = 2, key = 5, data = five\n"); - recreate(); - } - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, - VectorIndexSettings::DISTANCE_COSINE}) - { - std::vector level = { - "II\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 0, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n" - "__ydb_parent = 1, key = 2, data = two\n" - "__ydb_parent = 1, key = 3, data = three\n" - "__ydb_parent = 1, key = 4, data = four\n" - "__ydb_parent = 1, key = 5, data = five\n"); - recreate(); - } - } - - Y_UNIT_TEST (MainToBuild) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateMainTable(server, sender, options); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (key, embedding, data) - VALUES )" - "(1, \"\x30\x30\3\", \"one\")," - "(2, \"\x31\x31\3\", \"two\")," - "(3, \"\x32\x32\3\", \"three\")," - "(4, \"\x65\x65\3\", \"four\")," - "(5, \"\x75\x75\3\", \"five\");"); - - auto create = [&] { CreateBuildTable(server, sender, options, "table-posting"); }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-posting"); - create(); - }; - - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - std::vector level = { - "mm\3", - "11\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 0, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 1, key = 5, embedding = \x75\x75\3, data = five\n" - "__ydb_parent = 2, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 2, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 2, key = 3, embedding = \x32\x32\3, data = three\n"); - recreate(); - } - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - std::vector level = { - "11\3", - "mm\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 0, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n" - "__ydb_parent = 2, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 2, key = 5, embedding = \x75\x75\3, data = five\n"); - recreate(); - } - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, - VectorIndexSettings::DISTANCE_COSINE}) - { - std::vector level = { - "II\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 0, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n" - "__ydb_parent = 1, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 1, key = 5, embedding = \x75\x75\3, data = five\n"); - recreate(); - } - } - - Y_UNIT_TEST (BuildToPosting) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateBuildTable(server, sender, options, "table-main"); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (__ydb_parent, key, embedding, data) - VALUES )" - "(39, 1, \"\x30\x30\3\", \"one\")," - "(40, 1, \"\x30\x30\3\", \"one\")," - "(40, 2, \"\x31\x31\3\", \"two\")," - "(40, 3, \"\x32\x32\3\", \"three\")," - "(40, 4, \"\x65\x65\3\", \"four\")," - "(40, 5, \"\x75\x75\3\", \"five\")," - "(41, 5, \"\x75\x75\3\", \"five\");"); - - auto create = [&] { CreatePostingTable(server, sender, options); }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-posting"); - create(); - }; - - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - std::vector level = { - "mm\3", - "11\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 40, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, data = four\n" - "__ydb_parent = 41, key = 5, data = five\n" - "__ydb_parent = 42, key = 1, data = one\n" - "__ydb_parent = 42, key = 2, data = two\n" - "__ydb_parent = 42, key = 3, data = three\n"); - recreate(); - } - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - std::vector level = { - "11\3", - "mm\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 40, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n" - "__ydb_parent = 41, key = 2, data = two\n" - "__ydb_parent = 41, key = 3, data = three\n" - "__ydb_parent = 42, key = 4, data = four\n" - "__ydb_parent = 42, key = 5, data = five\n"); - recreate(); - } - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, - VectorIndexSettings::DISTANCE_COSINE}) - { - std::vector level = { - "II\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 40, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n" - "__ydb_parent = 41, key = 2, data = two\n" - "__ydb_parent = 41, key = 3, data = three\n" - "__ydb_parent = 41, key = 4, data = four\n" - "__ydb_parent = 41, key = 5, data = five\n"); - recreate(); - } - } - - Y_UNIT_TEST (BuildToBuild) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - TShardedTableOptions options; - options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? - options.Shards(1); - - CreateBuildTable(server, sender, options, "table-main"); - // Upsert some initial values - ExecSQL(server, sender, - R"( - UPSERT INTO `/Root/table-main` - (__ydb_parent, key, embedding, data) - VALUES )" - "(39, 1, \"\x30\x30\3\", \"one\")," - "(40, 1, \"\x30\x30\3\", \"one\")," - "(40, 2, \"\x31\x31\3\", \"two\")," - "(40, 3, \"\x32\x32\3\", \"three\")," - "(40, 4, \"\x65\x65\3\", \"four\")," - "(40, 5, \"\x75\x75\3\", \"five\")," - "(41, 5, \"\x75\x75\3\", \"five\");"); - - auto create = [&] { CreateBuildTable(server, sender, options, "table-posting"); }; - create(); - auto recreate = [&] { - DropTable(server, sender, "table-posting"); - create(); - }; - - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - std::vector level = { - "mm\3", - "11\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 40, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 41, key = 5, embedding = \x75\x75\3, data = five\n" - "__ydb_parent = 42, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 42, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 42, key = 3, embedding = \x32\x32\3, data = three\n"); - recreate(); - } - for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - std::vector level = { - "11\3", - "mm\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 40, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, distance); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" - "__ydb_parent = 42, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 42, key = 5, embedding = \x75\x75\3, data = five\n"); - recreate(); - } - for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, - VectorIndexSettings::DISTANCE_COSINE}) - { - std::vector level = { - "II\3", - }; - auto posting = DoReshuffleKMeans(server, sender, 40, level, - NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, - VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); - UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" - "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" - "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" - "__ydb_parent = 41, key = 4, embedding = \x65\x65\3, data = four\n" - "__ydb_parent = 41, key = 5, embedding = \x75\x75\3, data = five\n"); - recreate(); - } - } -} - -} diff --git a/ydb/core/tx/datashard/datashard_ut_sample_k.cpp b/ydb/core/tx/datashard/datashard_ut_sample_k.cpp deleted file mode 100644 index 6b36a2bc146b..000000000000 --- a/ydb/core/tx/datashard/datashard_ut_sample_k.cpp +++ /dev/null @@ -1,273 +0,0 @@ -#include "defs.h" -#include "datashard_ut_common_kqp.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include - -namespace NKikimr { - -static std::atomic sId = 1; - -using namespace NKikimr::NDataShard::NKqpHelpers; -using namespace NSchemeShard; -using namespace Tests; - -Y_UNIT_TEST_SUITE (TTxDataShardSampleKScan) { - static void DoSampleKBad(Tests::TServer::TPtr server, TActorId sender, - const TString& tableFrom, const TRowVersion& snapshot, std::unique_ptr& ev) { - auto id = sId.fetch_add(1, std::memory_order_relaxed); - auto& runtime = *server->GetRuntime(); - auto datashards = GetTableShards(server, sender, tableFrom); - TTableId tableId = ResolveTableId(server, sender, tableFrom); - - TStringBuilder data; - TString err; - UNIT_ASSERT(datashards.size() == 1); - - for (auto tid : datashards) { - auto& rec = ev->Record; - rec.SetId(1); - - rec.SetSeqNoGeneration(id); - rec.SetSeqNoRound(1); - - if (!rec.HasTabletId()) { - rec.SetTabletId(tid); - } - - if (!rec.HasPathId()) { - tableId.PathId.ToProto(rec.MutablePathId()); - } - - if (rec.ColumnsSize() == 0) { - rec.AddColumns("value"); - rec.AddColumns("key"); - } else { - rec.ClearColumns(); - } - - rec.SetSnapshotTxId(snapshot.TxId); - rec.SetSnapshotStep(snapshot.Step); - - rec.SetMaxProbability(std::numeric_limits::max()); - rec.SetSeed(1337); - if (!rec.HasK()) { - rec.SetK(1); - } - - runtime.SendToPipe(tid, sender, ev.release(), 0, GetPipeConfigWithRetries()); - - TAutoPtr handle; - auto reply = runtime.GrabEdgeEventRethrow(handle); - UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); - } - } - - static TString DoSampleK(Tests::TServer::TPtr server, TActorId sender, - const TString& tableFrom, const TRowVersion& snapshot, ui64 seed, ui64 k) { - auto id = sId.fetch_add(1, std::memory_order_relaxed); - auto& runtime = *server->GetRuntime(); - auto datashards = GetTableShards(server, sender, tableFrom); - TTableId tableId = ResolveTableId(server, sender, tableFrom); - - TStringBuilder data; - TString err; - - for (auto tid : datashards) { - auto ev1 = std::make_unique(); - auto ev2 = std::make_unique(); - auto fill = [&](auto& ev) { - auto& rec = ev->Record; - rec.SetId(1); - - rec.SetSeqNoGeneration(id); - rec.SetSeqNoRound(1); - - rec.SetTabletId(tid); - tableId.PathId.ToProto(rec.MutablePathId()); - - rec.AddColumns("value"); - rec.AddColumns("key"); - - if (snapshot.TxId) { - rec.SetSnapshotTxId(snapshot.TxId); - rec.SetSnapshotStep(snapshot.Step); - } - - rec.SetMaxProbability(std::numeric_limits::max()); - rec.SetSeed(seed); - rec.SetK(k); - }; - fill(ev1); - fill(ev2); - - runtime.SendToPipe(tid, sender, ev1.release(), 0, GetPipeConfigWithRetries()); - runtime.SendToPipe(tid, sender, ev2.release(), 0, GetPipeConfigWithRetries()); - - TAutoPtr handle; - auto reply = runtime.GrabEdgeEventRethrow(handle); - UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrIndexBuilder::EBuildStatus::DONE); - - const auto& rows = reply->Record.GetRows(); - UNIT_ASSERT(!rows.empty()); - for (auto& row : rows) { - TSerializedCellVec vec; - UNIT_ASSERT(TSerializedCellVec::TryParse(row, vec)); - const auto& cells = vec.GetCells(); - UNIT_ASSERT_EQUAL(cells.size(), 2); - data.Out << "value = "; - UNIT_ASSERT(cells[0].ToStream(data.Out, err)); - data.Out << ", key = "; - UNIT_ASSERT(cells[1].ToStream(data.Out, err)); - data.Out << "\n"; - } - auto& probabilities = reply->Record.GetProbabilities(); - UNIT_ASSERT(rows.size() == probabilities.size()); - UNIT_ASSERT(std::is_sorted(probabilities.begin(), probabilities.end())); - } - return data; - } - - Y_UNIT_TEST (RunScan) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - CreateShardedTable(server, sender, "/Root", "table-1", 1, false); - - // Upsert some initial values - ExecSQL(server, sender, "UPSERT INTO `/Root/table-1` (key, value) VALUES (1, 10), (2, 20), (3, 30), (4, 40), (5, 50);"); - - auto snapshot = CreateVolatileSnapshot(server, {"/Root/table-1"}); - - ui64 seed, k; - TString data; - - seed = 0; - { - k = 1; - data = DoSampleK(server, sender, "/Root/table-1", snapshot, seed, k); - UNIT_ASSERT_VALUES_EQUAL(data, - "value = 30, key = 3\n"); - - k = 3; - data = DoSampleK(server, sender, "/Root/table-1", snapshot, seed, k); - UNIT_ASSERT_VALUES_EQUAL(data, - "value = 30, key = 3\n" - "value = 20, key = 2\n" - "value = 50, key = 5\n"); - - k = 9; - data = DoSampleK(server, sender, "/Root/table-1", snapshot, seed, k); - UNIT_ASSERT_VALUES_EQUAL(data, - "value = 30, key = 3\n" - "value = 20, key = 2\n" - "value = 50, key = 5\n" - "value = 40, key = 4\n" - "value = 10, key = 1\n"); - } - snapshot = {}; - seed = 111; - { - k = 1; - data = DoSampleK(server, sender, "/Root/table-1", snapshot, seed, k); - UNIT_ASSERT_VALUES_EQUAL(data, - "value = 10, key = 1\n"); - - k = 3; - data = DoSampleK(server, sender, "/Root/table-1", snapshot, seed, k); - UNIT_ASSERT_VALUES_EQUAL(data, - "value = 10, key = 1\n" - "value = 20, key = 2\n" - "value = 30, key = 3\n"); - - k = 9; - data = DoSampleK(server, sender, "/Root/table-1", snapshot, seed, k); - UNIT_ASSERT_VALUES_EQUAL(data, - "value = 10, key = 1\n" - "value = 20, key = 2\n" - "value = 30, key = 3\n" - "value = 50, key = 5\n" - "value = 40, key = 4\n"); - } - } - - Y_UNIT_TEST (ScanBadParameters) { - TPortManager pm; - TServerSettings serverSettings(pm.GetPort(2134)); - serverSettings.SetDomainName("Root"); - - Tests::TServer::TPtr server = new TServer(serverSettings); - auto& runtime = *server->GetRuntime(); - auto sender = runtime.AllocateEdgeActor(); - - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); - - InitRoot(server, sender); - - CreateShardedTable(server, sender, "/Root", "table-1", 1, false); - - auto snapshot = CreateVolatileSnapshot(server, {"/Root/table-1"}); - - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetK(0); - DoSampleKBad(server, sender, "/Root/table-1", snapshot, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.AddColumns(); - DoSampleKBad(server, sender, "/Root/table-1", snapshot, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - rec.SetTabletId(0); - DoSampleKBad(server, sender, "/Root/table-1", snapshot, ev); - } - { - auto ev = std::make_unique(); - auto& rec = ev->Record; - - TPathId(0, 0).ToProto(rec.MutablePathId()); - DoSampleKBad(server, sender, "/Root/table-1", snapshot, ev); - } - { - auto ev = std::make_unique(); - - auto snapshotCopy = snapshot; - snapshotCopy.Step++; - DoSampleKBad(server, sender, "/Root/table-1", snapshotCopy, ev); - } - { - auto ev = std::make_unique(); - - auto snapshotCopy = snapshot; - snapshotCopy.TxId++; - DoSampleKBad(server, sender, "/Root/table-1", snapshotCopy, ev); - } - } -} - -} // namespace NKikimr diff --git a/ydb/core/tx/datashard/local_kmeans.cpp b/ydb/core/tx/datashard/local_kmeans.cpp deleted file mode 100644 index b39a09c3f600..000000000000 --- a/ydb/core/tx/datashard/local_kmeans.cpp +++ /dev/null @@ -1,787 +0,0 @@ -#include "datashard_impl.h" -#include "kmeans_helper.h" -#include "scan_common.h" -#include "upload_stats.h" -#include "buffer_data.h" - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -namespace NKikimr::NDataShard { -using namespace NKMeans; - -class TResult { -public: - explicit TResult(const TActorId& responseActorId, TAutoPtr response) - : ResponseActorId{responseActorId} - , Response{std::move(response)} { - Y_ASSERT(Response); - } - - void SizeAdd(i64 size) { - if (size != 0) { - std::lock_guard lock{Mutex}; - Size += size; - } - } - - template - void Send(const TActorContext& ctx, Func&& func) { - std::unique_lock lock{Mutex}; - if (Size <= 0) { - return; - } - if (func(Response->Record) && --Size > 0) { - return; - } - Size = 0; - lock.unlock(); - - LOG_N("Finish TLocalKMeansScan " << Response->Record.ShortDebugString()); - ctx.Send(ResponseActorId, std::move(Response)); - } - -private: - std::mutex Mutex; - i64 Size = 1; - TActorId ResponseActorId; - TAutoPtr Response; -}; - -// This scan needed to run local (not distributed) kmeans. -// We have this local stage because we construct kmeans tree from top to bottom. -// And bottom kmeans can be constructed completely locally in datashards to avoid extra communication. -// Also it can be used for small tables. -// -// This class is kind of state machine, it has 3 phases. -// Each of them corresponds to 1-N rounds of NTable::IScan (which is kind of state machine itself). -// 1. First iteration collect sample of clusters -// 2. Then N iterations recompute clusters (main cycle of batched kmeans) -// 3. Finally last iteration upload clusters to level table and postings to corresponding posting table -// -// These phases maps to State: -// 1. -- EState::SAMPLE -// 2. -- EState::KMEANS -// 3. -- EState::UPLOAD* -// -// Which UPLOAD* will be used depends on that will client of this scan request (see UploadState) -// -// NTable::IScan::Seek used to switch from current state to the next one. - -// If less than 1% of vectors are reassigned to new clusters we want to stop -// TODO(mbkkt) 1% is choosed by common sense and should be adjusted in future -static constexpr double MinVectorsNeedsReassigned = 0.01; - -class TLocalKMeansScanBase: public TActor, public NTable::IScan { -protected: - using EState = NKikimrTxDataShard::EKMeansState; - - NTableIndex::TClusterId Parent = 0; - NTableIndex::TClusterId Child = 0; - - ui32 Round = 0; - ui32 MaxRounds = 0; - - ui32 K = 0; - - EState State; - EState UploadState; - - IDriver* Driver = nullptr; - - TLead Lead; - - ui64 BuildId = 0; - - ui64 ReadRows = 0; - ui64 ReadBytes = 0; - - // Sample - ui64 MaxProbability = std::numeric_limits::max(); - TReallyFastRng32 Rng; - - struct TProbability { - ui64 P = 0; - ui64 I = 0; - - auto operator<=>(const TProbability&) const noexcept = default; - }; - - std::vector MaxRows; - std::vector Clusters; - std::vector ClusterSizes; - - // Upload - std::shared_ptr TargetTypes; - std::shared_ptr NextTypes; - - TString TargetTable; - TString NextTable; - - TBufferData ReadBuf; - TBufferData WriteBuf; - - NTable::TPos EmbeddingPos = 0; - NTable::TPos DataPos = 1; - - ui32 RetryCount = 0; - - TActorId Uploader; - const TIndexBuildScanSettings ScanSettings; - - NTable::TTag KMeansScan; - TTags UploadScan; - - TUploadStatus UploadStatus; - - ui64 UploadRows = 0; - ui64 UploadBytes = 0; - - std::shared_ptr Result; - -public: - static constexpr NKikimrServices::TActivity::EType ActorActivityType() - { - return NKikimrServices::TActivity::LOCAL_KMEANS_SCAN_ACTOR; - } - - TLocalKMeansScanBase(ui64 buildId, const TUserTable& table, TLead&& lead, NTableIndex::TClusterId parent, NTableIndex::TClusterId child, - const NKikimrTxDataShard::TEvLocalKMeansRequest& request, - std::shared_ptr result) - : TActor{&TThis::StateWork} - , Parent{parent} - , Child{child} - , MaxRounds{request.GetNeedsRounds()} - , K{request.GetK()} - , State{EState::SAMPLE} - , UploadState{request.GetUpload()} - , Lead{std::move(lead)} - , BuildId{buildId} - , Rng{request.GetSeed()} - , TargetTable{request.GetLevelName()} - , NextTable{request.GetPostingName()} - , ScanSettings(request.GetScanSettings()) - , Result{std::move(result)} - { - const auto& embedding = request.GetEmbeddingColumn(); - const auto& data = request.GetDataColumns(); - // scan tags - UploadScan = MakeUploadTags(table, embedding, data, EmbeddingPos, DataPos, KMeansScan); - // upload types - if (Ydb::Type type; State <= EState::KMEANS) { - TargetTypes = std::make_shared(3); - type.set_type_id(NTableIndex::ClusterIdType); - (*TargetTypes)[0] = {NTableIndex::NTableVectorKmeansTreeIndex::ParentColumn, type}; - (*TargetTypes)[1] = {NTableIndex::NTableVectorKmeansTreeIndex::IdColumn, type}; - type.set_type_id(Ydb::Type::STRING); - (*TargetTypes)[2] = {NTableIndex::NTableVectorKmeansTreeIndex::CentroidColumn, type}; - } - NextTypes = MakeUploadTypes(table, UploadState, embedding, data); - } - - TInitialState Prepare(IDriver* driver, TIntrusiveConstPtr) final - { - TActivationContext::AsActorContext().RegisterWithSameMailbox(this); - LOG_I("Prepare " << Debug()); - - Driver = driver; - return {EScan::Feed, {}}; - } - - TAutoPtr Finish(EAbort abort) final - { - LOG_D("Finish " << Debug()); - - if (Uploader) { - Send(Uploader, new TEvents::TEvPoisonPill); - Uploader = {}; - } - - Result->Send(TActivationContext::AsActorContext(), [&] (NKikimrTxDataShard::TEvLocalKMeansResponse& response) { - response.SetReadRows(ReadRows); - response.SetReadBytes(ReadBytes); - response.SetUploadRows(UploadRows); - response.SetUploadBytes(UploadBytes); - NYql::IssuesToMessage(UploadStatus.Issues, response.MutableIssues()); - if (abort != EAbort::None) { - response.SetStatus(NKikimrIndexBuilder::EBuildStatus::ABORTED); - return false; - } else if (UploadStatus.IsSuccess()) { - response.SetStatus(NKikimrIndexBuilder::EBuildStatus::DONE); - return true; - } else { - response.SetStatus(NKikimrIndexBuilder::EBuildStatus::BUILD_ERROR); - return false; - } - }); - - Driver = nullptr; - this->PassAway(); - return nullptr; - } - - void Describe(IOutputStream& out) const final - { - out << Debug(); - } - - TString Debug() const - { - return TStringBuilder() << "TLocalKMeansScan Id: " << BuildId << " Parent: " << Parent << " Child: " << Child - << " Target: " << TargetTable << " K: " << K << " Clusters: " << Clusters.size() - << " State: " << State << " Round: " << Round << " / " << MaxRounds - << " ReadBuf size: " << ReadBuf.Size() << " WriteBuf size: " << WriteBuf.Size(); - } - - EScan PageFault() final - { - LOG_T("PageFault " << Debug()); - return EScan::Feed; - } - -protected: - STFUNC(StateWork) - { - switch (ev->GetTypeRewrite()) { - HFunc(TEvTxUserProxy::TEvUploadRowsResponse, Handle); - CFunc(TEvents::TSystem::Wakeup, HandleWakeup); - default: - LOG_E("TLocalKMeansScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " - << ev->ToString() << " " << Debug()); - } - } - - void HandleWakeup(const NActors::TActorContext& /*ctx*/) - { - LOG_I("Retry upload " << Debug()); - - if (!WriteBuf.IsEmpty()) { - Upload(true); - } - } - - void Handle(TEvTxUserProxy::TEvUploadRowsResponse::TPtr& ev, const TActorContext& ctx) - { - LOG_D("Handle TEvUploadRowsResponse " << Debug() - << " Uploader: " << Uploader.ToString() << " ev->Sender: " << ev->Sender.ToString()); - - if (Uploader) { - Y_ENSURE(Uploader == ev->Sender, "Mismatch Uploader: " << Uploader.ToString() << " ev->Sender: " - << ev->Sender.ToString() << Debug()); - } else { - Y_ENSURE(Driver == nullptr); - return; - } - - UploadStatus.StatusCode = ev->Get()->Status; - UploadStatus.Issues = ev->Get()->Issues; - if (UploadStatus.IsSuccess()) { - UploadRows += WriteBuf.GetRows(); - UploadBytes += WriteBuf.GetBytes(); - WriteBuf.Clear(); - if (HasReachedLimits(ReadBuf, ScanSettings)) { - ReadBuf.FlushTo(WriteBuf); - Upload(false); - } - - Driver->Touch(EScan::Feed); - return; - } - - if (RetryCount < ScanSettings.GetMaxBatchRetries() && UploadStatus.IsRetriable()) { - LOG_N("Got retriable error, " << Debug() << UploadStatus.ToString()); - - ctx.Schedule(GetRetryWakeupTimeoutBackoff(RetryCount), new TEvents::TEvWakeup()); - return; - } - - LOG_N("Got error, abort scan, " << Debug() << UploadStatus.ToString()); - - Driver->Touch(EScan::Final); - } - - EScan FeedUpload() - { - if (!HasReachedLimits(ReadBuf, ScanSettings)) { - return EScan::Feed; - } - if (!WriteBuf.IsEmpty()) { - return EScan::Sleep; - } - ReadBuf.FlushTo(WriteBuf); - Upload(false); - return EScan::Feed; - } - - ui64 GetProbability() - { - return Rng.GenRand64(); - } - - void Upload(bool isRetry) - { - if (isRetry) { - ++RetryCount; - } else { - RetryCount = 0; - if (State != EState::KMEANS && NextTypes) { - TargetTypes = std::exchange(NextTypes, {}); - TargetTable = std::move(NextTable); - } - } - - auto actor = NTxProxy::CreateUploadRowsInternal( - this->SelfId(), TargetTable, TargetTypes, WriteBuf.GetRowsData(), - NTxProxy::EUploadRowsMode::WriteToTableShadow, true /*writeToPrivateTable*/); - - Uploader = this->Register(actor); - } - - void UploadSample() - { - Y_ASSERT(ReadBuf.IsEmpty()); - Y_ASSERT(WriteBuf.IsEmpty()); - std::array pk; - std::array data; - for (NTable::TPos pos = 0; const auto& row : Clusters) { - pk[0] = TCell::Make(Parent); - pk[1] = TCell::Make(Child + pos); - data[0] = TCell{row}; - WriteBuf.AddRow(TSerializedCellVec{pk}, TSerializedCellVec::Serialize(data)); - ++pos; - } - Upload(false); - } -}; - -template -class TLocalKMeansScan final: public TLocalKMeansScanBase, private TCalculation { - // KMeans - using TEmbedding = std::vector; - - struct TAggregatedCluster { - TEmbedding Cluster; - ui64 Size = 0; - }; - std::vector AggregatedClusters; - -public: - TLocalKMeansScan(ui64 buildId, const TUserTable& table, TLead&& lead, NTableIndex::TClusterId parent, NTableIndex::TClusterId child, NKikimrTxDataShard::TEvLocalKMeansRequest& request, - std::shared_ptr result) - : TLocalKMeansScanBase{buildId, table, std::move(lead), parent, child, request, std::move(result)} - { - this->Dimensions = request.GetSettings().vector_dimension(); - LOG_I("Create " << Debug()); - } - - EScan Seek(TLead& lead, ui64 seq) final - { - LOG_D("Seek " << Debug()); - if (State == UploadState) { - if (!WriteBuf.IsEmpty()) { - return EScan::Sleep; - } - if (!ReadBuf.IsEmpty()) { - ReadBuf.FlushTo(WriteBuf); - Upload(false); - return EScan::Sleep; - } - if (UploadStatus.IsNone()) { - UploadStatus.StatusCode = Ydb::StatusIds::SUCCESS; - } - return EScan::Final; - } - - if (State == EState::SAMPLE) { - lead = Lead; - lead.SetTags({&KMeansScan, 1}); - if (seq == 0) { - return EScan::Feed; - } - State = EState::KMEANS; - if (!InitAggregatedClusters()) { - // We don't need to do anything, - // because this datashard doesn't have valid embeddings for this parent - if (UploadStatus.IsNone()) { - UploadStatus.StatusCode = Ydb::StatusIds::SUCCESS; - } - return EScan::Final; - } - ++Round; - return EScan::Feed; - } - - Y_ASSERT(State == EState::KMEANS); - if (RecomputeClusters()) { - lead = std::move(Lead); - lead.SetTags(UploadScan); - - UploadSample(); - State = UploadState; - } else { - lead = Lead; - lead.SetTags({&KMeansScan, 1}); - ++Round; - } - return EScan::Feed; - } - - EScan Feed(TArrayRef key, const TRow& row_) final - { - LOG_T("Feed " << Debug()); - - ++ReadRows; - ReadBytes += CountBytes(key, row_); - auto row = *row_; - - switch (State) { - case EState::SAMPLE: - return FeedSample(row); - case EState::KMEANS: - return FeedKMeans(row); - case EState::UPLOAD_MAIN_TO_BUILD: - return FeedUploadMain2Build(key, row); - case EState::UPLOAD_MAIN_TO_POSTING: - return FeedUploadMain2Posting(key, row); - case EState::UPLOAD_BUILD_TO_BUILD: - return FeedUploadBuild2Build(key, row); - case EState::UPLOAD_BUILD_TO_POSTING: - return FeedUploadBuild2Posting(key, row); - default: - return EScan::Final; - } - } - -private: - bool InitAggregatedClusters() - { - if (Clusters.size() == 0) { - return false; - } - if (Clusters.size() < K) { - // if this datashard have smaller than K count of valid embeddings for this parent - // lets make single centroid for it - K = 1; - Clusters.resize(K); - } - Y_ASSERT(Clusters.size() == K); - ClusterSizes.resize(K, 0); - AggregatedClusters.resize(K); - for (auto& aggregate : AggregatedClusters) { - aggregate.Cluster.resize(this->Dimensions, 0); - } - return true; - } - - void AggregateToCluster(ui32 pos, const char* embedding) - { - if (pos >= K) { - return; - } - auto& aggregate = AggregatedClusters[pos]; - auto* coords = aggregate.Cluster.data(); - for (auto coord : this->GetCoords(embedding)) { - *coords++ += coord; - } - ++aggregate.Size; - } - - bool RecomputeClusters() - { - Y_ASSERT(K >= 1); - ui64 vectorCount = 0; - ui64 reassignedCount = 0; - for (size_t i = 0; auto& aggregate : AggregatedClusters) { - vectorCount += aggregate.Size; - - auto& clusterSize = ClusterSizes[i]; - reassignedCount += clusterSize < aggregate.Size ? aggregate.Size - clusterSize : 0; - clusterSize = aggregate.Size; - - if (aggregate.Size != 0) { - this->Fill(Clusters[i], aggregate.Cluster.data(), aggregate.Size); - Y_ASSERT(aggregate.Size == 0); - } - ++i; - } - Y_ASSERT(vectorCount >= K); - Y_ASSERT(reassignedCount <= vectorCount); - if (K == 1) { - return true; - } - - bool last = Round >= MaxRounds; - if (!last && Round > 1) { - const auto changes = static_cast(reassignedCount) / static_cast(vectorCount); - last = changes < MinVectorsNeedsReassigned; - } - if (!last) { - return false; - } - - size_t w = 0; - for (size_t r = 0; r < ClusterSizes.size(); ++r) { - if (ClusterSizes[r] != 0) { - ClusterSizes[w] = ClusterSizes[r]; - Clusters[w] = std::move(Clusters[r]); - ++w; - } - } - ClusterSizes.erase(ClusterSizes.begin() + w, ClusterSizes.end()); - Clusters.erase(Clusters.begin() + w, Clusters.end()); - return true; - } - - EScan FeedSample(TArrayRef row) - { - Y_ASSERT(row.size() == 1); - const auto embedding = row.at(0).AsRef(); - if (!this->IsExpectedSize(embedding)) { - return EScan::Feed; - } - - const auto probability = GetProbability(); - if (Clusters.size() < K) { - MaxRows.push_back({probability, Clusters.size()}); - Clusters.emplace_back(embedding.data(), embedding.size()); - if (Clusters.size() == K) { - std::make_heap(MaxRows.begin(), MaxRows.end()); - MaxProbability = MaxRows.front().P; - } - } else if (probability < MaxProbability) { - // TODO(mbkkt) use tournament tree to make less compare and swaps - std::pop_heap(MaxRows.begin(), MaxRows.end()); - Clusters[MaxRows.back().I].assign(embedding.data(), embedding.size()); - MaxRows.back().P = probability; - std::push_heap(MaxRows.begin(), MaxRows.end()); - MaxProbability = MaxRows.front().P; - } - return MaxProbability != 0 ? EScan::Feed : EScan::Reset; - } - - EScan FeedKMeans(TArrayRef row) - { - Y_ASSERT(row.size() == 1); - const ui32 pos = FeedEmbedding(*this, Clusters, row, 0); - AggregateToCluster(pos, row.at(0).Data()); - return EScan::Feed; - } - - EScan FeedUploadMain2Build(TArrayRef key, TArrayRef row) - { - const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); - if (pos >= K) { - return EScan::Feed; - } - AddRowMain2Build(ReadBuf, Child + pos, key, row); - return FeedUpload(); - } - - EScan FeedUploadMain2Posting(TArrayRef key, TArrayRef row) - { - const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); - if (pos >= K) { - return EScan::Feed; - } - AddRowMain2Posting(ReadBuf, Child + pos, key, row, DataPos); - return FeedUpload(); - } - - EScan FeedUploadBuild2Build(TArrayRef key, TArrayRef row) - { - const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); - if (pos >= K) { - return EScan::Feed; - } - AddRowBuild2Build(ReadBuf, Child + pos, key, row); - return FeedUpload(); - } - - EScan FeedUploadBuild2Posting(TArrayRef key, TArrayRef row) - { - const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); - if (pos >= K) { - return EScan::Feed; - } - AddRowBuild2Posting(ReadBuf, Child + pos, key, row, DataPos); - return FeedUpload(); - } -}; - -class TDataShard::TTxHandleSafeLocalKMeansScan final: public NTabletFlatExecutor::TTransactionBase { -public: - TTxHandleSafeLocalKMeansScan(TDataShard* self, TEvDataShard::TEvLocalKMeansRequest::TPtr&& ev) - : TTransactionBase(self) - , Ev(std::move(ev)) - { - } - - bool Execute(TTransactionContext&, const TActorContext& ctx) final - { - Self->HandleSafe(Ev, ctx); - return true; - } - - void Complete(const TActorContext&) final - { - } - -private: - TEvDataShard::TEvLocalKMeansRequest::TPtr Ev; -}; - -void TDataShard::Handle(TEvDataShard::TEvLocalKMeansRequest::TPtr& ev, const TActorContext&) -{ - Execute(new TTxHandleSafeLocalKMeansScan(this, std::move(ev))); -} - -void TDataShard::HandleSafe(TEvDataShard::TEvLocalKMeansRequest::TPtr& ev, const TActorContext& ctx) -{ - auto& request = ev->Get()->Record; - auto rowVersion = request.HasSnapshotStep() || request.HasSnapshotTxId() - ? TRowVersion(request.GetSnapshotStep(), request.GetSnapshotTxId()) - : GetMvccTxVersion(EMvccTxMode::ReadOnly); - - LOG_N("Starting TLocalKMeansScan " << request.ShortDebugString() - << " row version " << rowVersion); - - // Note: it's very unlikely that we have volatile txs before this snapshot - if (VolatileTxManager.HasVolatileTxsAtSnapshot(rowVersion)) { - VolatileTxManager.AttachWaitingSnapshotEvent(rowVersion, std::unique_ptr(ev.Release())); - return; - } - const ui64 id = request.GetId(); - - auto response = MakeHolder(); - response->Record.SetId(id); - response->Record.SetTabletId(TabletID()); - - TScanRecord::TSeqNo seqNo = {request.GetSeqNoGeneration(), request.GetSeqNoRound()}; - response->Record.SetRequestSeqNoGeneration(seqNo.Generation); - response->Record.SetRequestSeqNoRound(seqNo.Round); - auto result = std::make_shared(ev->Sender, std::move(response)); - ui32 localTid = 0; - TScanRecord::TScanIds scanIds; - - auto badRequest = [&](const TString& error) { - for (auto scanId : scanIds) { - CancelScan(localTid, scanId); - } - result->Send(ctx, [&] (NKikimrTxDataShard::TEvLocalKMeansResponse& response) { - response.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); - auto issue = response.AddIssues(); - issue->set_severity(NYql::TSeverityIds::S_ERROR); - issue->set_message(error); - return false; - }); - result.reset(); - }; - - if (const ui64 shardId = request.GetTabletId(); shardId != TabletID()) { - badRequest(TStringBuilder() << "Wrong shard " << shardId << " this is " << TabletID()); - return; - } - - const auto pathId = TPathId::FromProto(request.GetPathId()); - const auto* userTableIt = GetUserTables().FindPtr(pathId.LocalPathId); - if (!userTableIt) { - badRequest(TStringBuilder() << "Unknown table id: " << pathId.LocalPathId); - return; - } - Y_ENSURE(*userTableIt); - const auto& userTable = **userTableIt; - - if (const auto* recCard = ScanManager.Get(id)) { - if (recCard->SeqNo == seqNo) { - // do no start one more scan - return; - } - - for (auto scanId : recCard->ScanIds) { - CancelScan(userTable.LocalTid, scanId); - } - ScanManager.Drop(id); - } - - localTid = userTable.LocalTid; - - if (request.HasSnapshotStep() || request.HasSnapshotTxId()) { - const TSnapshotKey snapshotKey(pathId, rowVersion.Step, rowVersion.TxId); - if (!SnapshotManager.FindAvailable(snapshotKey)) { - badRequest(TStringBuilder() << "no snapshot has been found" << " , path id is " << pathId.OwnerId << ":" - << pathId.LocalPathId << " , snapshot step is " << snapshotKey.Step - << " , snapshot tx is " << snapshotKey.TxId); - return; - } - } - - if (!IsStateActive()) { - badRequest(TStringBuilder() << "Shard " << TabletID() << " is not ready for requests"); - return; - } - - if (request.GetK() < 2) { - badRequest("Should be requested partition on at least two rows"); - return; - } - - const auto parentFrom = request.GetParentFrom(); - const auto parentTo = request.GetParentTo(); - if (parentFrom > parentTo) { - badRequest(TStringBuilder() << "Parent from " << parentFrom << " should be less or equal to parent to " << parentTo); - return; - } - const i64 expectedSize = parentTo - parentFrom + 1; - result->SizeAdd(expectedSize); - - for (auto parent = parentFrom; parent <= parentTo; ++parent) { - TCell from, to; - const auto range = CreateRangeFrom(userTable, parent, from, to); - if (range.IsEmptyRange(userTable.KeyColumnTypes)) { - LOG_D("TEvLocalKMeansRequst " << request.GetId() << " parent " << parent << " is empty"); - continue; - } - - TAutoPtr scan; - auto createScan = [&] { - scan = new TLocalKMeansScan{ - request.GetId(), userTable, - CreateLeadFrom(range), parent, request.GetChild() + request.GetK() * (parent - parentFrom), - request, result, - }; - }; - MakeScan(request, createScan, badRequest); - if (!scan) { - Y_ASSERT(!result); - return; - } - - TScanOptions scanOpts; - scanOpts.SetSnapshotRowVersion(rowVersion); - scanOpts.SetResourceBroker("build_index", 10); // TODO(mbkkt) Should be different group? - const auto scanId = QueueScan(userTable.LocalTid, std::move(scan), 0, scanOpts); - scanIds.push_back(scanId); - } - - if (scanIds.empty()) { - badRequest("Requested range doesn't intersect with table range"); - return; - } - result->SizeAdd(static_cast(scanIds.size()) - expectedSize); - result->Send(ctx, [] (auto&) { return true; }); // decrement extra one - ScanManager.Set(id, seqNo) = std::move(scanIds); -} - -} diff --git a/ydb/core/tx/datashard/sample_k.cpp b/ydb/core/tx/datashard/sample_k.cpp deleted file mode 100644 index e8472a4d7ec1..000000000000 --- a/ydb/core/tx/datashard/sample_k.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include "datashard_impl.h" -#include "kmeans_helper.h" -#include "range_ops.h" -#include "scan_common.h" -#include "upload_stats.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -namespace NKikimr::NDataShard { - -class TSampleKScan final: public TActor, public NTable::IScan { -protected: - const TAutoPtr Response; - const TActorId ResponseActorId; - - const TTags ScanTags; - const TVector KeyTypes; - - const TSerializedTableRange TableRange; - const TSerializedTableRange RequestedRange; - const ui64 K; - - struct TProbability { - ui64 P = 0; - ui64 I = 0; - - auto operator<=>(const TProbability&) const noexcept = default; - }; - - ui64 BuildId = 0; - - ui64 ReadRows = 0; - ui64 ReadBytes = 0; - - // We are using binary heap, because we don't want to do batch processing here, - // serialization is more expensive than compare - ui64 MaxProbability = 0; - TReallyFastRng32 Rng; - std::vector MaxRows; - std::vector DataRows; - - IDriver* Driver = nullptr; - -public: - static constexpr NKikimrServices::TActivity::EType ActorActivityType() { - return NKikimrServices::TActivity::SAMPLE_K_SCAN_ACTOR; - } - - TSampleKScan(TAutoPtr&& response, - const TActorId& responseActorId, - const TSerializedTableRange& range, - ui64 k, - ui64 seed, - ui64 maxProbability, - TProtoColumnsCRef columns, - const TUserTable& tableInfo) - : TActor(&TThis::StateWork) - , Response(std::move(response)) - , ResponseActorId(responseActorId) - , ScanTags(BuildTags(tableInfo, columns)) - , KeyTypes(tableInfo.KeyColumnTypes) - , TableRange(tableInfo.Range) - , RequestedRange(range) - , K(k) - , BuildId(Response->Record.GetId()) - , MaxProbability(maxProbability) - , Rng(seed) { - Y_ASSERT(MaxProbability != 0); - LOG_I("Create " << Debug()); - } - - ~TSampleKScan() final = default; - - TInitialState Prepare(IDriver* driver, TIntrusiveConstPtr) final { - TActivationContext::AsActorContext().RegisterWithSameMailbox(this); - - LOG_I("Prepare " << Debug()); - - Driver = driver; - - return {EScan::Feed, {}}; - } - - EScan Seek(TLead& lead, ui64 seq) final { - Y_ENSURE(seq == 0); - LOG_D("Seek " << Debug()); - - auto scanRange = Intersect(KeyTypes, RequestedRange.ToTableRange(), TableRange.ToTableRange()); - - if (scanRange.From) { - auto seek = scanRange.InclusiveFrom ? NTable::ESeek::Lower : NTable::ESeek::Upper; - lead.To(ScanTags, scanRange.From, seek); - } else { - lead.To(ScanTags, {}, NTable::ESeek::Lower); - } - - if (scanRange.To) { - lead.Until(scanRange.To, scanRange.InclusiveTo); - } - - return EScan::Feed; - } - - EScan Feed(TArrayRef key, const TRow& row) final { - LOG_T("Feed key " << DebugPrintPoint(KeyTypes, key, *AppData()->TypeRegistry) << " " << Debug()); - ++ReadRows; - ReadBytes += CountBytes(key, row); - - const auto probability = GetProbability(); - if (probability > MaxProbability) { - return EScan::Feed; - } - - if (DataRows.size() < K) { - MaxRows.push_back({probability, DataRows.size()}); - DataRows.emplace_back(TSerializedCellVec::Serialize(*row)); - if (DataRows.size() == K) { - std::make_heap(MaxRows.begin(), MaxRows.end()); - MaxProbability = MaxRows.front().P; - } - } else { - // TODO(mbkkt) use tournament tree to make less compare and swaps - std::pop_heap(MaxRows.begin(), MaxRows.end()); - TSerializedCellVec::Serialize(DataRows[MaxRows.back().I], *row); - MaxRows.back().P = probability; - std::push_heap(MaxRows.begin(), MaxRows.end()); - MaxProbability = MaxRows.front().P; - } - - if (MaxProbability == 0) { - return EScan::Final; - } - return EScan::Feed; - } - - TAutoPtr Finish(EAbort abort) final { - Y_ENSURE(Response); - Response->Record.SetReadRows(ReadRows); - Response->Record.SetReadBytes(ReadBytes); - if (abort == EAbort::None) { - FillResponse(); - } else { - Response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::ABORTED); - } - LOG_N("Finish " << Debug() << " " << Response->Record.ShortDebugString()); - Send(ResponseActorId, Response.Release()); - Driver = nullptr; - PassAway(); - return nullptr; - } - - void Describe(IOutputStream& out) const final { - out << Debug(); - } - - EScan Exhausted() final { - return EScan::Final; - } - - TString Debug() const { - return TStringBuilder() << "TSampleKScan Id: " << BuildId - << " K: " << K << " Clusters: " << MaxRows.size(); - } - -private: - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - default: - LOG_E("TSampleKScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " << ev->ToString() << " " << Debug()); - } - } - - void FillResponse() { - std::sort(MaxRows.begin(), MaxRows.end()); - auto& record = Response->Record; - for (auto& [p, i] : MaxRows) { - record.AddProbabilities(p); - record.AddRows(std::move(DataRows[i])); - } - record.SetStatus(NKikimrIndexBuilder::EBuildStatus::DONE); - } - - ui64 GetProbability() { - while (true) { - auto p = Rng.GenRand64(); - // We exclude max ui64 from generated probabilities, so we can use this value as initial max - if (Y_LIKELY(p != std::numeric_limits::max())) { - return p; - } - } - } -}; - -class TDataShard::TTxHandleSafeSampleKScan: public NTabletFlatExecutor::TTransactionBase { -public: - TTxHandleSafeSampleKScan(TDataShard* self, TEvDataShard::TEvSampleKRequest::TPtr&& ev) - : TTransactionBase(self) - , Ev(std::move(ev)) { - } - - bool Execute(TTransactionContext&, const TActorContext& ctx) { - Self->HandleSafe(Ev, ctx); - return true; - } - - void Complete(const TActorContext&) { - // nothing - } - -private: - TEvDataShard::TEvSampleKRequest::TPtr Ev; -}; - -void TDataShard::Handle(TEvDataShard::TEvSampleKRequest::TPtr& ev, const TActorContext&) { - Execute(new TTxHandleSafeSampleKScan(this, std::move(ev))); -} - -void TDataShard::HandleSafe(TEvDataShard::TEvSampleKRequest::TPtr& ev, const TActorContext& ctx) { - const auto& record = ev->Get()->Record; - const bool needsSnapshot = record.HasSnapshotStep() || record.HasSnapshotTxId(); - TRowVersion rowVersion(record.GetSnapshotStep(), record.GetSnapshotTxId()); - if (!needsSnapshot) { - rowVersion = GetMvccTxVersion(EMvccTxMode::ReadOnly); - } - - // Note: it's very unlikely that we have volatile txs before this snapshot - if (VolatileTxManager.HasVolatileTxsAtSnapshot(rowVersion)) { - VolatileTxManager.AttachWaitingSnapshotEvent(rowVersion, - std::unique_ptr(ev.Release())); - return; - } - const ui64 id = record.GetId(); - - auto response = MakeHolder(); - response->Record.SetId(id); - response->Record.SetTabletId(TabletID()); - - TScanRecord::TSeqNo seqNo = {record.GetSeqNoGeneration(), record.GetSeqNoRound()}; - response->Record.SetRequestSeqNoGeneration(seqNo.Generation); - response->Record.SetRequestSeqNoRound(seqNo.Round); - - auto badRequest = [&](const TString& error) { - response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); - auto issue = response->Record.AddIssues(); - issue->set_severity(NYql::TSeverityIds::S_ERROR); - issue->set_message(error); - ctx.Send(ev->Sender, std::move(response)); - }; - - if (const ui64 shardId = record.GetTabletId(); shardId != TabletID()) { - badRequest(TStringBuilder() << "Wrong shard " << shardId << " this is " << TabletID()); - return; - } - - const auto pathId = TPathId::FromProto(record.GetPathId()); - const auto* userTableIt = GetUserTables().FindPtr(pathId.LocalPathId); - if (!userTableIt) { - badRequest(TStringBuilder() << "Unknown table id: " << pathId.LocalPathId); - return; - } - Y_ENSURE(*userTableIt); - const auto& userTable = **userTableIt; - - if (const auto* recCard = ScanManager.Get(id)) { - if (recCard->SeqNo == seqNo) { - // do no start one more scan - return; - } - - for (auto scanId : recCard->ScanIds) { - CancelScan(userTable.LocalTid, scanId); - } - ScanManager.Drop(id); - } - - TSerializedTableRange requestedRange; - requestedRange.Load(record.GetKeyRange()); - - auto scanRange = Intersect(userTable.KeyColumnTypes, requestedRange.ToTableRange(), userTable.Range.ToTableRange()); - - if (scanRange.IsEmptyRange(userTable.KeyColumnTypes)) { - badRequest(TStringBuilder() << " requested range doesn't intersect with table range" - << " requestedRange: " << DebugPrintRange(userTable.KeyColumnTypes, requestedRange.ToTableRange(), *AppData()->TypeRegistry) - << " tableRange: " << DebugPrintRange(userTable.KeyColumnTypes, userTable.Range.ToTableRange(), *AppData()->TypeRegistry) - << " scanRange: " << DebugPrintRange(userTable.KeyColumnTypes, scanRange, *AppData()->TypeRegistry)); - return; - } - - const TSnapshotKey snapshotKey(pathId, rowVersion.Step, rowVersion.TxId); - if (needsSnapshot && !SnapshotManager.FindAvailable(snapshotKey)) { - badRequest(TStringBuilder() - << "no snapshot has been found" - << " , path id is " << pathId.OwnerId << ":" << pathId.LocalPathId - << " , snapshot step is " << snapshotKey.Step - << " , snapshot tx is " << snapshotKey.TxId); - return; - } - - if (!IsStateActive()) { - badRequest(TStringBuilder() << "Shard " << TabletID() << " is not ready for requests"); - return; - } - - if (record.GetK() < 1) { - badRequest("Should be requested at least single row"); - return; - } - - if (record.ColumnsSize() < 1) { - badRequest("Should be requested at least single column"); - return; - } - - TScanOptions scanOpts; - scanOpts.SetSnapshotRowVersion(rowVersion); - scanOpts.SetResourceBroker("build_index", 10); // TODO(mbkkt) Should be different group? - - const auto scanId = QueueScan(userTable.LocalTid, - new TSampleKScan( - std::move(response), - ev->Sender, - requestedRange, - record.GetK(), - record.GetSeed(), - record.GetMaxProbability(), - record.GetColumns(), - userTable), - 0, - scanOpts); - - ScanManager.Set(id, seqNo).push_back(scanId); -} - -} diff --git a/ydb/core/tx/datashard/ut_build_index/ya.make b/ydb/core/tx/datashard/ut_build_index/ya.make deleted file mode 100644 index 103577bd90c8..000000000000 --- a/ydb/core/tx/datashard/ut_build_index/ya.make +++ /dev/null @@ -1,33 +0,0 @@ -UNITTEST_FOR(ydb/core/tx/datashard) - -FORK_SUBTESTS() - -SPLIT_FACTOR(1) - -IF (SANITIZER_TYPE == "thread" OR WITH_VALGRIND) - SIZE(LARGE) - TAG(ya:fat) -ELSE() - SIZE(MEDIUM) -ENDIF() - -PEERDIR( - ydb/core/tx/datashard/ut_common - library/cpp/getopt - library/cpp/regex/pcre - library/cpp/svnversion - ydb/core/kqp/ut/common - ydb/core/testlib/default - ydb/core/tx - yql/essentials/public/udf/service/exception_policy - ydb/public/lib/yson_value - ydb/public/sdk/cpp/src/client/result -) - -YQL_LAST_ABI_VERSION() - -SRCS( - datashard_ut_build_index.cpp -) - -END() diff --git a/ydb/core/tx/datashard/ut_local_kmeans/ya.make b/ydb/core/tx/datashard/ut_local_kmeans/ya.make deleted file mode 100644 index 313a310175c9..000000000000 --- a/ydb/core/tx/datashard/ut_local_kmeans/ya.make +++ /dev/null @@ -1,33 +0,0 @@ -UNITTEST_FOR(ydb/core/tx/datashard) - -FORK_SUBTESTS() - -SPLIT_FACTOR(1) - -IF (SANITIZER_TYPE == "thread" OR WITH_VALGRIND) - SIZE(LARGE) - TAG(ya:fat) -ELSE() - SIZE(MEDIUM) -ENDIF() - -PEERDIR( - ydb/core/tx/datashard/ut_common - library/cpp/getopt - library/cpp/regex/pcre - library/cpp/svnversion - ydb/core/kqp/ut/common - ydb/core/testlib/default - ydb/core/tx - yql/essentials/public/udf/service/exception_policy - ydb/public/lib/yson_value - ydb/public/sdk/cpp/src/client/result -) - -YQL_LAST_ABI_VERSION() - -SRCS( - datashard_ut_local_kmeans.cpp -) - -END() diff --git a/ydb/core/tx/datashard/ut_prefix_kmeans/ya.make b/ydb/core/tx/datashard/ut_prefix_kmeans/ya.make deleted file mode 100644 index 8c1a7869e441..000000000000 --- a/ydb/core/tx/datashard/ut_prefix_kmeans/ya.make +++ /dev/null @@ -1,33 +0,0 @@ -UNITTEST_FOR(ydb/core/tx/datashard) - -FORK_SUBTESTS() - -SPLIT_FACTOR(1) - -IF (SANITIZER_TYPE == "thread" OR WITH_VALGRIND) - SIZE(LARGE) - TAG(ya:fat) -ELSE() - SIZE(MEDIUM) -ENDIF() - -PEERDIR( - ydb/core/tx/datashard/ut_common - library/cpp/getopt - library/cpp/regex/pcre - library/cpp/svnversion - ydb/core/kqp/ut/common - ydb/core/testlib/default - ydb/core/tx - yql/essentials/public/udf/service/exception_policy - ydb/public/lib/yson_value - ydb/public/sdk/cpp/src/client/result -) - -YQL_LAST_ABI_VERSION() - -SRCS( - datashard_ut_prefix_kmeans.cpp -) - -END() diff --git a/ydb/core/tx/datashard/ut_reshuffle_kmeans/ya.make b/ydb/core/tx/datashard/ut_reshuffle_kmeans/ya.make deleted file mode 100644 index 24a35f2de72e..000000000000 --- a/ydb/core/tx/datashard/ut_reshuffle_kmeans/ya.make +++ /dev/null @@ -1,33 +0,0 @@ -UNITTEST_FOR(ydb/core/tx/datashard) - -FORK_SUBTESTS() - -SPLIT_FACTOR(1) - -IF (SANITIZER_TYPE == "thread" OR WITH_VALGRIND) - SIZE(LARGE) - TAG(ya:fat) -ELSE() - SIZE(MEDIUM) -ENDIF() - -PEERDIR( - ydb/core/tx/datashard/ut_common - library/cpp/getopt - library/cpp/regex/pcre - library/cpp/svnversion - ydb/core/kqp/ut/common - ydb/core/testlib/default - ydb/core/tx - yql/essentials/public/udf/service/exception_policy - ydb/public/lib/yson_value - ydb/public/sdk/cpp/src/client/result -) - -YQL_LAST_ABI_VERSION() - -SRCS( - datashard_ut_reshuffle_kmeans.cpp -) - -END() diff --git a/ydb/core/tx/datashard/ut_sample_k/ya.make b/ydb/core/tx/datashard/ut_sample_k/ya.make deleted file mode 100644 index 18713b07ee68..000000000000 --- a/ydb/core/tx/datashard/ut_sample_k/ya.make +++ /dev/null @@ -1,33 +0,0 @@ -UNITTEST_FOR(ydb/core/tx/datashard) - -FORK_SUBTESTS() - -SPLIT_FACTOR(1) - -IF (SANITIZER_TYPE == "thread" OR WITH_VALGRIND) - SIZE(LARGE) - TAG(ya:fat) -ELSE() - SIZE(MEDIUM) -ENDIF() - -PEERDIR( - ydb/core/tx/datashard/ut_common - library/cpp/getopt - library/cpp/regex/pcre - library/cpp/svnversion - ydb/core/kqp/ut/common - ydb/core/testlib/default - ydb/core/tx - yql/essentials/public/udf/service/exception_policy - ydb/public/lib/yson_value - ydb/public/sdk/cpp/src/client/result -) - -YQL_LAST_ABI_VERSION() - -SRCS( - datashard_ut_sample_k.cpp -) - -END() diff --git a/ydb/core/tx/datashard/ya.make b/ydb/core/tx/datashard/ya.make index 4c7087836059..9f3577b20938 100644 --- a/ydb/core/tx/datashard/ya.make +++ b/ydb/core/tx/datashard/ya.make @@ -8,7 +8,6 @@ SRCS( build_and_wait_dependencies_unit.cpp build_data_tx_out_rs_unit.cpp build_distributed_erase_tx_out_rs_unit.cpp - build_index.cpp build_kqp_data_tx_out_rs_unit.cpp build_scheme_tx_out_rs_unit.cpp build_write_out_rs_unit.cpp @@ -168,11 +167,9 @@ SRCS( key_conflicts.cpp key_conflicts.h key_validator.cpp - kmeans_helper.cpp load_and_wait_in_rs_unit.cpp load_tx_details_unit.cpp load_write_details_unit.cpp - local_kmeans.cpp make_scan_snapshot_unit.cpp make_snapshot_unit.cpp memory_state_migration.cpp @@ -181,7 +178,6 @@ SRCS( operation.cpp operation.h plan_queue_unit.cpp - prefix_kmeans.cpp prepare_data_tx_in_rs_unit.cpp prepare_distributed_erase_tx_in_rs_unit.cpp prepare_kqp_data_tx_in_rs_unit.cpp @@ -201,9 +197,7 @@ SRCS( remove_lock_change_records.cpp remove_locks.cpp remove_schema_snapshots.cpp - reshuffle_kmeans.cpp restore_unit.cpp - sample_k.cpp scan_common.cpp setup_sys_locks.h store_and_send_out_rs_unit.cpp @@ -221,6 +215,13 @@ SRCS( volatile_tx_mon.cpp wait_for_plan_unit.cpp wait_for_stream_clearance_unit.cpp + + build_index/prefix_kmeans.cpp + build_index/kmeans_helper.cpp + build_index/local_kmeans.cpp + build_index/sample_k.cpp + build_index/secondary_index.cpp + build_index/reshuffle_kmeans.cpp ) GENERATE_ENUM_SERIALIZATION(backup_restore_traits.h) @@ -304,8 +305,8 @@ ENDIF() END() RECURSE_FOR_TESTS( + build_index/ut ut_background_compaction - ut_build_index ut_change_collector ut_change_exchange ut_column_stats @@ -321,21 +322,17 @@ RECURSE_FOR_TESTS( ut_kqp ut_kqp_errors ut_kqp_scan - ut_local_kmeans ut_locks ut_minikql ut_minstep ut_object_storage_listing ut_order - ut_prefix_kmeans ut_range_ops ut_read_iterator ut_read_table ut_reassign ut_replication - ut_reshuffle_kmeans ut_rs - ut_sample_k ut_sequence ut_snapshot ut_stats diff --git a/ydb/core/tx/limiter/grouped_memory/service/allocation.h b/ydb/core/tx/limiter/grouped_memory/service/allocation.h index 678a4f97f859..a96377258984 100644 --- a/ydb/core/tx/limiter/grouped_memory/service/allocation.h +++ b/ydb/core/tx/limiter/grouped_memory/service/allocation.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include namespace NKikimr::NOlap::NGroupedMemoryManager { diff --git a/ydb/core/tx/limiter/grouped_memory/service/counters.h b/ydb/core/tx/limiter/grouped_memory/service/counters.h index 1d55b7b17f4a..2e75604b5792 100644 --- a/ydb/core/tx/limiter/grouped_memory/service/counters.h +++ b/ydb/core/tx/limiter/grouped_memory/service/counters.h @@ -1,5 +1,5 @@ #pragma once -#include +#include namespace NKikimr::NOlap::NGroupedMemoryManager { diff --git a/ydb/core/tx/limiter/grouped_memory/service/group.h b/ydb/core/tx/limiter/grouped_memory/service/group.h index 1c988081b02e..d97bf79012e8 100644 --- a/ydb/core/tx/limiter/grouped_memory/service/group.h +++ b/ydb/core/tx/limiter/grouped_memory/service/group.h @@ -1,7 +1,7 @@ #pragma once #include "allocation.h" -#include +#include namespace NKikimr::NOlap::NGroupedMemoryManager { diff --git a/ydb/core/tx/limiter/grouped_memory/service/process.h b/ydb/core/tx/limiter/grouped_memory/service/process.h index 3a53ff542750..a7631dd390ef 100644 --- a/ydb/core/tx/limiter/grouped_memory/service/process.h +++ b/ydb/core/tx/limiter/grouped_memory/service/process.h @@ -2,7 +2,7 @@ #include "group.h" #include "ids.h" -#include +#include #include diff --git a/ydb/core/tx/limiter/grouped_memory/service/ya.make b/ydb/core/tx/limiter/grouped_memory/service/ya.make index d67332688426..7611cc6b7cb9 100644 --- a/ydb/core/tx/limiter/grouped_memory/service/ya.make +++ b/ydb/core/tx/limiter/grouped_memory/service/ya.make @@ -12,7 +12,7 @@ SRCS( PEERDIR( ydb/core/protos - ydb/core/tx/columnshard/counters/common + ydb/library/signals ) GENERATE_ENUM_SERIALIZATION(allocation.h) diff --git a/ydb/core/tx/limiter/service/service.h b/ydb/core/tx/limiter/service/service.h index 32e9c45faca5..dd7fd10f3d49 100644 --- a/ydb/core/tx/limiter/service/service.h +++ b/ydb/core/tx/limiter/service/service.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/ydb/core/tx/limiter/usage/abstract.h b/ydb/core/tx/limiter/usage/abstract.h index ff3e460a771c..3a4b45983b5b 100644 --- a/ydb/core/tx/limiter/usage/abstract.h +++ b/ydb/core/tx/limiter/usage/abstract.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace NKikimr::NLimiter { class IResourceRequest { diff --git a/ydb/core/tx/priorities/service/counters.h b/ydb/core/tx/priorities/service/counters.h index 7eb2202d9556..660b84a40429 100644 --- a/ydb/core/tx/priorities/service/counters.h +++ b/ydb/core/tx/priorities/service/counters.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include diff --git a/ydb/core/tx/program/program.cpp b/ydb/core/tx/program/program.cpp index acc920cfe755..febf3fc84173 100644 --- a/ydb/core/tx/program/program.cpp +++ b/ydb/core/tx/program/program.cpp @@ -100,8 +100,8 @@ TConclusionStatus TProgramContainer::ParseProgram(const NArrow::NSSA::IColumnRes using TId = NKikimrSSA::TProgram::TCommand; AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD)("parse_proto_program", program.DebugString()); -// Cerr << program.DebugString() << Endl; NArrow::NSSA::TProgramBuilder programBuilder(columnResolver, KernelsRegistry); + bool hasProjection = false; for (auto& cmd : program.GetCommand()) { switch (cmd.GetLineCase()) { case TId::kAssign: { @@ -123,6 +123,7 @@ TConclusionStatus TProgramContainer::ParseProgram(const NArrow::NSSA::IColumnRes if (status.IsFail()) { return status; } + hasProjection = true; break; } case TId::kGroupBy: { @@ -136,6 +137,9 @@ TConclusionStatus TProgramContainer::ParseProgram(const NArrow::NSSA::IColumnRes return TConclusionStatus::Fail("incorrect SSA line case"); } } + if (!hasProjection) { + return TConclusionStatus::Fail("program has no projections"); + } auto programStatus = programBuilder.Finish(); if (programStatus.IsFail()) { return programStatus; diff --git a/ydb/core/tx/schemeshard/schemeshard__delete_tablet_reply.cpp b/ydb/core/tx/schemeshard/schemeshard__delete_tablet_reply.cpp index 3534906ac50f..c19f0332fe46 100644 --- a/ydb/core/tx/schemeshard/schemeshard__delete_tablet_reply.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__delete_tablet_reply.cpp @@ -180,7 +180,7 @@ struct TSchemeShard::TTxDeleteTabletReply : public TSchemeShard::TRwTxBase { "Close pipe to deleted shardIdx " << ShardIdx << " tabletId " << TabletId); Self->PipeClientCache->ForceClose(ctx, ui64(TabletId)); } - if (Self->DataErasureManager->GetStatus() == EDataErasureStatus::IN_PROGRESS) { + if (Self->EnableDataErasure && Self->DataErasureManager->GetStatus() == EDataErasureStatus::IN_PROGRESS) { Self->Execute(Self->CreateTxCancelDataErasureShards({ShardIdx})); } } diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_alter_sequence.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_alter_sequence.cpp index d2da3b45f850..cd43d916b24d 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_alter_sequence.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_alter_sequence.cpp @@ -488,7 +488,7 @@ class TAlterSequence: public TSubOperation { const NScheme::TTypeRegistry* typeRegistry = AppData()->TypeRegistry; auto description = GetAlterSequenceDescription( - sequenceInfo->Description, sequenceAlter, *typeRegistry, context.SS->EnableTablePgTypes, errStr); + sequenceInfo->Description, sequenceAlter, *typeRegistry, AppData()->FeatureFlags.GetEnableTablePgTypes(), errStr); if (!description) { status = NKikimrScheme::StatusInvalidParameter; result->SetError(status, errStr); diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_alter_table.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_alter_table.cpp index 155b5e1339ed..792d461e8a1c 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_alter_table.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_alter_table.cpp @@ -145,9 +145,9 @@ TTableInfo::TAlterDataPtr ParseParams(const TPath& path, TTableInfo::TPtr table, const TSubDomainInfo& subDomain = *path.DomainInfo(); const TSchemeLimits& limits = subDomain.GetSchemeLimits(); const TTableInfo::TCreateAlterDataFeatureFlags featureFlags = { - .EnableTablePgTypes = context.SS->EnableTablePgTypes, - .EnableTableDatetime64 = context.SS->EnableTableDatetime64, - .EnableParameterizedDecimal = context.SS->EnableParameterizedDecimal, + .EnableTablePgTypes = AppData()->FeatureFlags.GetEnableTablePgTypes(), + .EnableTableDatetime64 = AppData()->FeatureFlags.GetEnableTableDatetime64(), + .EnableParameterizedDecimal = AppData()->FeatureFlags.GetEnableParameterizedDecimal(), }; diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp index 5c3bfb8047ca..6843d7ce016e 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp @@ -578,11 +578,13 @@ class TCopyTable: public TSubOperation { const NScheme::TTypeRegistry* typeRegistry = AppData()->TypeRegistry; const TSchemeLimits& limits = domainInfo->GetSchemeLimits(); + // Copy table should not check feature flags for columns types. + // If the types in original table are created then they should be allowed in destination table. const TTableInfo::TCreateAlterDataFeatureFlags featureFlags = { - .EnableTablePgTypes = context.SS->EnableTablePgTypes, - .EnableTableDatetime64 = context.SS->EnableTableDatetime64, - .EnableParameterizedDecimal = context.SS->EnableParameterizedDecimal, - }; + .EnableTablePgTypes = true, + .EnableTableDatetime64 = true, + .EnableParameterizedDecimal = true, + }; TTableInfo::TAlterDataPtr alterData = TTableInfo::CreateAlterData(nullptr, schema, *typeRegistry, limits, *domainInfo, featureFlags, errStr, LocalSequences); if (!alterData.Get()) { diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_create_sequence.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_create_sequence.cpp index 0e23348c0880..9fdb1e8d66b7 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_create_sequence.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_create_sequence.cpp @@ -508,7 +508,7 @@ class TCreateSequence : public TSubOperation { TSequenceInfo::TPtr alterData = sequenceInfo->CreateNextVersion(); const NScheme::TTypeRegistry* typeRegistry = AppData()->TypeRegistry; auto description = FillSequenceDescription( - descr, *typeRegistry, context.SS->EnableTablePgTypes, errStr); + descr, *typeRegistry, AppData()->FeatureFlags.GetEnableTablePgTypes(), errStr); if (!description) { status = NKikimrScheme::StatusInvalidParameter; result->SetError(status, errStr); diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_create_table.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_create_table.cpp index d43c27aee881..ec28d65e1887 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_create_table.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_create_table.cpp @@ -578,9 +578,9 @@ class TCreateTable: public TSubOperation { const NScheme::TTypeRegistry* typeRegistry = AppData()->TypeRegistry; const TSchemeLimits& limits = domainInfo->GetSchemeLimits(); const TTableInfo::TCreateAlterDataFeatureFlags featureFlags = { - .EnableTablePgTypes = context.SS->EnableTablePgTypes, - .EnableTableDatetime64 = context.SS->EnableTableDatetime64, - .EnableParameterizedDecimal = context.SS->EnableParameterizedDecimal, + .EnableTablePgTypes = AppData()->FeatureFlags.GetEnableTablePgTypes(), + .EnableTableDatetime64 = AppData()->FeatureFlags.GetEnableTableDatetime64(), + .EnableParameterizedDecimal = AppData()->FeatureFlags.GetEnableParameterizedDecimal(), }; TTableInfo::TAlterDataPtr alterData = TTableInfo::CreateAlterData( nullptr, diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_side_effects.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_side_effects.cpp index c0dbe726583b..e03cf0debbd0 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_side_effects.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_side_effects.cpp @@ -555,7 +555,7 @@ void TSideEffects::DoUpdateTenant(TSchemeShard* ss, NTabletFlatExecutor::TTransa } if (!hasChanges) { - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "DoUpdateTenant no hasChanges" << ", pathId: " << pathId << ", tenantLink: " << tenantLink diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_split_merge.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_split_merge.cpp index 25e08ad235f3..83e876b011b6 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_split_merge.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_split_merge.cpp @@ -721,18 +721,31 @@ class TSplitMerge: public TSubOperation { } LOG_NOTICE_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "TSplitMerge Propose" - << ", tableStr: " << info.GetTablePath() - << ", tableId: " << pathId - << ", opId: " << OperationId - << ", at schemeshard: " << ssId); - + "TSplitMerge Propose" + << ", tableStr: " << info.GetTablePath() + << ", tableId: " << pathId + << ", opId: " << OperationId + << ", at schemeshard: " << ssId + << ", request: " << info.ShortDebugString()); + auto result = MakeHolder(NKikimrScheme::StatusAccepted, ui64(OperationId.GetTxId()), ui64(ssId)); + + auto setResultError = [&](NKikimrScheme::EStatus status, const TString& error) { + result->SetError(status, error); + LOG_WARN_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TSplitMerge Propose failed " << status << " " << error + << ", tableStr: " << info.GetTablePath() + << ", tableId: " << pathId + << ", opId: " << OperationId + << ", at schemeshard: " << ssId + << ", request: " << info.ShortDebugString()); + }; + TString errStr; if (!info.HasTablePath() && !info.HasTableLocalId()) { errStr = "Neither table name nor pathId in SplitMergeInfo"; - result->SetError(NKikimrScheme::StatusInvalidParameter, errStr); + setResultError(NKikimrScheme::StatusInvalidParameter, errStr); return result; } @@ -759,18 +772,18 @@ class TSplitMerge: public TSubOperation { } if (!checks) { - result->SetError(checks.GetStatus(), checks.GetError()); + setResultError(checks.GetStatus(), checks.GetError()); return result; } } if (!context.SS->CheckApplyIf(Transaction, errStr)) { - result->SetError(NKikimrScheme::StatusPreconditionFailed, errStr); + setResultError(NKikimrScheme::StatusPreconditionFailed, errStr); return result; } if (!context.SS->CheckLocks(path.Base()->PathId, Transaction, errStr)) { - result->SetError(NKikimrScheme::StatusMultipleModifications, errStr); + setResultError(NKikimrScheme::StatusMultipleModifications, errStr); return result; } @@ -781,14 +794,14 @@ class TSplitMerge: public TSubOperation { if (tableInfo->IsBackup) { TString errMsg = TStringBuilder() << "cannot split/merge backup table " << info.GetTablePath(); - result->SetError(NKikimrScheme::StatusInvalidParameter, errMsg); + setResultError(NKikimrScheme::StatusInvalidParameter, errMsg); return result; } if (tableInfo->IsRestore) { TString errMsg = TStringBuilder() << "cannot split/merge restore table " << info.GetTablePath(); - result->SetError(NKikimrScheme::StatusInvalidParameter, errMsg); + setResultError(NKikimrScheme::StatusInvalidParameter, errMsg); return result; } @@ -801,7 +814,7 @@ class TSplitMerge: public TSubOperation { auto srcShardIdx = context.SS->GetShardIdx(srcTabletId); if (!srcShardIdx) { TString errMsg = TStringBuilder() << "Unknown SourceTabletId: " << srcTabletId; - result->SetError(NKikimrScheme::StatusInvalidParameter, errMsg); + setResultError(NKikimrScheme::StatusInvalidParameter, errMsg); return result; } @@ -811,7 +824,7 @@ class TSplitMerge: public TSubOperation { << ", tablet: " << srcTabletId << ", srcShardIdx: " << srcShardIdx << ", pathId: " << path.Base()->PathId; - result->SetError(NKikimrScheme::StatusInvalidParameter, errMsg); + setResultError(NKikimrScheme::StatusInvalidParameter, errMsg); return result; } @@ -821,20 +834,20 @@ class TSplitMerge: public TSubOperation { << ", tablet: " << srcTabletId << ", srcShardIdx: " << srcShardIdx << ", pathId: " << path.Base()->PathId; - result->SetError(NKikimrScheme::StatusInvalidParameter, errMsg); + setResultError(NKikimrScheme::StatusInvalidParameter, errMsg); return result; } if (context.SS->ShardInfos.FindPtr(srcShardIdx)->PathId != path.Base()->PathId || !shardIdx2partition.contains(srcShardIdx)) { TString errMsg = TStringBuilder() << "TabletId " << srcTabletId << " is not a partition of table " << info.GetTablePath(); - result->SetError(NKikimrScheme::StatusInvalidParameter, errMsg); + setResultError(NKikimrScheme::StatusInvalidParameter, errMsg); return result; } if (context.SS->ShardIsUnderSplitMergeOp(srcShardIdx)) { TString errMsg = TStringBuilder() << "TabletId " << srcTabletId << " is already in process of split"; - result->SetError(NKikimrScheme::StatusMultipleModifications, errMsg); + setResultError(NKikimrScheme::StatusMultipleModifications, errMsg); return result; } @@ -842,7 +855,7 @@ class TSplitMerge: public TSubOperation { const auto* stats = tableInfo->GetStats().PartitionStats.FindPtr(srcShardIdx); if (!stats || stats->ShardState != NKikimrTxDataShard::Ready) { TString errMsg = TStringBuilder() << "Src TabletId " << srcTabletId << " is not in Ready state"; - result->SetError(NKikimrScheme::StatusNotAvailable, errMsg); + setResultError(NKikimrScheme::StatusNotAvailable, errMsg); return result; } @@ -857,7 +870,7 @@ class TSplitMerge: public TSubOperation { if (context.SS->SplitSettings.SplitMergePartCountLimit != -1 && totalSrcPartCount >= context.SS->SplitSettings.SplitMergePartCountLimit) { - result->SetError(NKikimrScheme::StatusNotAvailable, + setResultError(NKikimrScheme::StatusNotAvailable, Sprintf("Split/Merge operation involves too many parts: %" PRIu64, totalSrcPartCount)); LOG_CRIT_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, @@ -869,7 +882,7 @@ class TSplitMerge: public TSubOperation { } if (srcPartitionIdxs.empty()) { - result->SetError(NKikimrScheme::StatusInvalidParameter, TStringBuilder() << "No source partitions specified for split/merge TxId " << OperationId.GetTxId()); + setResultError(NKikimrScheme::StatusInvalidParameter, TStringBuilder() << "No source partitions specified for split/merge TxId " << OperationId.GetTxId()); return result; } @@ -885,7 +898,7 @@ class TSplitMerge: public TSubOperation { if (!context.SS->GetBindingsRooms(path.GetPathIdForDomain(), tableInfo->PartitionConfig(), storageRooms, familyRooms, channelsBinding, errStr)) { errStr = TString("database doesn't have required storage pools to create tablet with storage config, details: ") + errStr; - result->SetError(NKikimrScheme::StatusInvalidParameter, errStr); + setResultError(NKikimrScheme::StatusInvalidParameter, errStr); return result; } @@ -900,7 +913,7 @@ class TSplitMerge: public TSubOperation { } } else if (context.SS->IsCompatibleChannelProfileLogic(path.GetPathIdForDomain(), tableInfo)) { if (!context.SS->GetChannelsBindings(path.GetPathIdForDomain(), tableInfo, channelsBinding, errStr)) { - result->SetError(NKikimrScheme::StatusInvalidParameter, errStr); + setResultError(NKikimrScheme::StatusInvalidParameter, errStr); return result; } } @@ -920,17 +933,17 @@ class TSplitMerge: public TSubOperation { if (srcPartitionIdxs.size() == 1 && dstCount > 1) { // This is Split operation, allocate new shards for split Dsts if (!AllocateDstForSplit(info, OperationId.GetTxId(), path.Base()->PathId, srcPartitionIdxs[0], tableInfo, op, channelsBinding, errStr, context)) { - result->SetError(NKikimrScheme::StatusInvalidParameter, errStr); + setResultError(NKikimrScheme::StatusInvalidParameter, errStr); return result; } } else if (dstCount == 1 && srcPartitionIdxs.size() > 1) { // This is merge, allocate 1 Dst shard if (!AllocateDstForMerge(info, OperationId.GetTxId(), path.Base()->PathId, srcPartitionIdxs, tableInfo, op, channelsBinding, errStr, context)) { - result->SetError(NKikimrScheme::StatusInvalidParameter, errStr); + setResultError(NKikimrScheme::StatusInvalidParameter, errStr); return result; } } else { - result->SetError(NKikimrScheme::StatusInvalidParameter, "Invalid request: only 1->N or N->1 are supported"); + setResultError(NKikimrScheme::StatusInvalidParameter, "Invalid request: only 1->N or N->1 are supported"); return result; } @@ -978,6 +991,16 @@ class TSplitMerge: public TSubOperation { path->IncShardsInside(dstCount); SetState(NextState()); + + LOG_NOTICE_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TSplitMerge Propose accepted" + << ", tableStr: " << info.GetTablePath() + << ", tableId: " << pathId + << ", opId: " << OperationId + << ", at schemeshard: " << ssId + << ", op: " << op.SplitDescription->ShortDebugString() + << ", request: " << info.ShortDebugString()); + return result; } diff --git a/ydb/core/tx/schemeshard/schemeshard__pq_stats.cpp b/ydb/core/tx/schemeshard/schemeshard__pq_stats.cpp index 29bb1a15aff7..caecef552515 100644 --- a/ydb/core/tx/schemeshard/schemeshard__pq_stats.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__pq_stats.cpp @@ -115,7 +115,7 @@ void TSchemeShard::Handle(TEvPersQueue::TEvPeriodicTopicStats::TPtr& ev, const T } void TSchemeShard::Handle(TEvPrivate::TEvPersistTopicStats::TPtr&, const TActorContext& ctx) { - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "Started TEvPersistStats at tablet " << TabletID() << ", queue size# " << TopicStatsQueue.Size()); TopicStatsBatchScheduled = false; diff --git a/ydb/core/tx/schemeshard/schemeshard__root_data_erasure_manager.cpp b/ydb/core/tx/schemeshard/schemeshard__root_data_erasure_manager.cpp index 27164725d78b..455856204d17 100644 --- a/ydb/core/tx/schemeshard/schemeshard__root_data_erasure_manager.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__root_data_erasure_manager.cpp @@ -313,22 +313,14 @@ void TRootDataErasureManager::OnDone(const TPathId& pathId, NIceDb::TNiceDb& db) ActivePipes.erase(pathId); auto it = WaitingDataErasureTenants.find(pathId); if (it != WaitingDataErasureTenants.end()) { - it->second = EDataErasureStatus::COMPLETED; - db.Table().Key(pathId.OwnerId, pathId.LocalPathId).Update(it->second); + db.Table().Key(pathId.OwnerId, pathId.LocalPathId).Delete(); + WaitingDataErasureTenants.erase(it); } SchemeShard->TabletCounters->Cumulative()[COUNTER_DATA_ERASURE_OK].Increment(1); UpdateMetrics(); - bool isDataErasureCompleted = true; - for (const auto& [pathId, status] : WaitingDataErasureTenants) { - if (status == EDataErasureStatus::IN_PROGRESS) { - isDataErasureCompleted = false; - break; - } - } - - if (isDataErasureCompleted) { + if (WaitingDataErasureTenants.empty()) { LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "[RootDataErasureManager] Data erasure in tenants is completed. Send request to BS controller"); Status = EDataErasureStatus::IN_PROGRESS_BSC; @@ -465,16 +457,10 @@ bool TRootDataErasureManager::Remove(const TPathId& pathId) { if (it != WaitingDataErasureTenants.end()) { Queue->Remove(pathId); ActivePipes.erase(pathId); - WaitingDataErasureTenants[pathId] = EDataErasureStatus::COMPLETED; - bool isDataErasureCompleted = true; - for (const auto& [pathId, status] : WaitingDataErasureTenants) { - if (status == EDataErasureStatus::IN_PROGRESS) { - isDataErasureCompleted = false; - break; - } - } + WaitingDataErasureTenants.erase(it); - if (isDataErasureCompleted) { + if (WaitingDataErasureTenants.empty()) { + Status = EDataErasureStatus::IN_PROGRESS_BSC; SendRequestToBSC(); } return true; diff --git a/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp b/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp index 71d616f75bfa..9dfaac175603 100644 --- a/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp @@ -279,19 +279,15 @@ bool TTxStoreTableStats::PersistSingleStats(const TPathId& pathId, shardInfo->BindedChannels); const auto pathElement = Self->PathsById[pathId]; + const TPartitionStats newStats = PrepareStats(ctx, rec, channelsMapping); + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "TTxStoreTableStats.PersistSingleStats: main stats from" << " datashardId(TabletID)=" << datashardId << " maps to shardIdx: " << shardIdx << " followerId=" << followerId << ", pathId: " << pathId << ", pathId map=" << pathElement->Name - << ", is column=" << isColumnTable << ", is olap=" << isOlapStore); - - const TPartitionStats newStats = PrepareStats(ctx, rec, channelsMapping); - - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "Add stats from shard with datashardId(TabletID)=" << datashardId << " followerId=" << followerId - << ", pathId " << pathId.LocalPathId - << ": RowCount " << newStats.RowCount + << ", is column=" << isColumnTable << ", is olap=" << isOlapStore + << ", RowCount " << newStats.RowCount << ", DataSize " << newStats.DataSize << (newStats.HasBorrowedData ? ", with borrowed parts" : "")); @@ -470,12 +466,21 @@ bool TTxStoreTableStats::PersistSingleStats(const TPathId& pathId, TString reason; if (table->ShouldSplitBySize(dataSize, forceShardSplitSettings, reason)) { // We would like to split by size and do this no matter how many partitions there are + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "Want to split tablet " << datashardId << " by size " << reason); } else if (table->GetPartitions().size() >= table->GetMaxPartitionsCount()) { // We cannot split as there are max partitions already + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "Do not want to split tablet " << datashardId << " by size," + << " its table already has "<< table->GetPartitions().size() << " out of " << table->GetMaxPartitionsCount() << " partitions"); return true; } else if (table->CheckSplitByLoad(Self->SplitSettings, shardIdx, dataSize, rowCount, mainTableForIndex, reason)) { + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "Want to split tablet " << datashardId << " by load " << reason); collectKeySample = true; } else { + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "Do not want to split tablet " << datashardId); return true; } @@ -498,15 +503,15 @@ bool TTxStoreTableStats::PersistSingleStats(const TPathId& pathId, } if (newStats.HasBorrowedData) { - // We don't want to split shards that have borrow parts - // We must ask them to compact first + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "Postpone split tablet " << datashardId << " because it has borrow parts, enqueue compact them first"); Self->EnqueueBorrowedCompaction(shardIdx); return true; } // Request histograms from the datashard - LOG_DEBUG(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "Requesting full stats from datashard %" PRIu64, rec.GetDatashardId()); + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "Requesting full tablet stats " << datashardId << " to split it"); auto request = new TEvDataShard::TEvGetTableStats(pathId.LocalPathId); request->Record.SetCollectKeySample(collectKeySample); PendingMessages.emplace_back(item.Ev->Sender, request); @@ -543,7 +548,7 @@ void TSchemeShard::Handle(TEvDataShard::TEvPeriodicTableStats::TPtr& ev, const T ? TPathId(TOwnerId(rec.GetTableOwnerId()), TLocalPathId(rec.GetTableLocalId())) : MakeLocalId(TLocalPathId(rec.GetTableLocalId())); - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "Got periodic table stats at tablet " << TabletID() << " from shard " << datashardId << " followerId " << followerId @@ -577,7 +582,7 @@ void TSchemeShard::Handle(TEvDataShard::TEvPeriodicTableStats::TPtr& ev, const T } void TSchemeShard::Handle(TEvPrivate::TEvPersistTableStats::TPtr&, const TActorContext& ctx) { - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "Started TEvPersistStats at tablet " << TabletID() << ", queue size# " << TableStatsQueue.Size()); TableStatsBatchScheduled = false; diff --git a/ydb/core/tx/schemeshard/schemeshard__table_stats_histogram.cpp b/ydb/core/tx/schemeshard/schemeshard__table_stats_histogram.cpp index 11ff0e429792..f78ff9771654 100644 --- a/ydb/core/tx/schemeshard/schemeshard__table_stats_histogram.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__table_stats_histogram.cpp @@ -222,7 +222,6 @@ TSerializedCellVec ChooseSplitKeyByKeySample(const NKikimrTableStats::THistogram enum struct ESplitReason { NO_SPLIT = 0, - FAST_SPLIT_INDEX, SPLIT_BY_SIZE, SPLIT_BY_LOAD }; @@ -231,8 +230,6 @@ const char* ToString(ESplitReason splitReason) { switch (splitReason) { case ESplitReason::NO_SPLIT: return "No split"; - case ESplitReason::FAST_SPLIT_INDEX: - return "Fast split index table"; case ESplitReason::SPLIT_BY_SIZE: return "Split by size"; case ESplitReason::SPLIT_BY_LOAD: @@ -277,9 +274,9 @@ void TSchemeShard::Handle(TEvDataShard::TEvGetTableStatsResult::TPtr& ev, const LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "Got partition histogram at tablet " << TabletID() <<" from datashard " << datashardId - << " state: '" << DatashardStateName(rec.GetShardState()) << "'" - << " data size: " << dataSize - << " row count: " << rowCount + << " state " << DatashardStateName(rec.GetShardState()) + << " data size " << dataSize + << " row count " << rowCount ); Execute(new TTxPartitionHistogram(this, ev), ctx); @@ -313,14 +310,14 @@ THolder SplitRequest( bool TTxPartitionHistogram::Execute(TTransactionContext& txc, const TActorContext& ctx) { const auto& rec = Ev->Get()->Record; - if (!rec.GetFullStatsReady()) + if (!rec.GetFullStatsReady()) { return true; + } auto datashardId = TTabletId(rec.GetDatashardId()); TPathId tableId = InvalidPathId; if (rec.HasTableOwnerId()) { - tableId = TPathId(TOwnerId(rec.GetTableOwnerId()), - TLocalPathId(rec.GetTableLocalId())); + tableId = TPathId(TOwnerId(rec.GetTableOwnerId()), TLocalPathId(rec.GetTableLocalId())); } else { tableId = Self->MakeLocalId(TLocalPathId(rec.GetTableLocalId())); } @@ -328,26 +325,35 @@ bool TTxPartitionHistogram::Execute(TTransactionContext& txc, const TActorContex ui64 rowCount = rec.GetTableStats().GetRowCount(); LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "TTxPartitionHistogram::Execute partition histogram" - << " at tablet " << Self->SelfTabletId() - << " from datashard " << datashardId - << " for pathId " << tableId - << " state '" << DatashardStateName(rec.GetShardState()).data() << "'" - << " dataSize " << dataSize - << " rowCount " << rowCount - << " dataSizeHistogram buckets " << rec.GetTableStats().GetDataSizeHistogram().BucketsSize()); - - if (!Self->Tables.contains(tableId)) + "TTxPartitionHistogram Execute partition histogram" + << " at tablet " << Self->SelfTabletId() + << " from datashard " << datashardId + << " for pathId " << tableId + << " state '" << DatashardStateName(rec.GetShardState()).data() << "'" + << " dataSize " << dataSize + << " rowCount " << rowCount + << " dataSizeHistogram buckets " << rec.GetTableStats().GetDataSizeHistogram().BucketsSize()); + + if (!Self->Tables.contains(tableId)) { + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TTxPartitionHistogram Unknown table " << tableId << " tablet " << datashardId); return true; + } TTableInfo::TPtr table = Self->Tables[tableId]; - if (!Self->TabletIdToShardIdx.contains(datashardId)) + if (!Self->TabletIdToShardIdx.contains(datashardId)) { + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TTxPartitionHistogram Unknown tablet " << datashardId); return true; + } // Don't split/merge backup tables - if (table->IsBackup) + if (table->IsBackup) { + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TTxPartitionHistogram Skip backup table tablet " << datashardId); return true; + } auto shardIdx = Self->TabletIdToShardIdx[datashardId]; const auto forceShardSplitSettings = Self->SplitSettings.GetForceShardSplitSettings(); @@ -365,13 +371,23 @@ bool TTxPartitionHistogram::Execute(TTransactionContext& txc, const TActorContex } if (splitReason == ESplitReason::NO_SPLIT) { + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TTxPartitionHistogram Do not want to split tablet " << datashardId); return true; } if (splitReason != ESplitReason::SPLIT_BY_SIZE && table->GetPartitions().size() >= table->GetMaxPartitionsCount()) { + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TTxPartitionHistogram Do not want to split tablet " << datashardId << " by size," + << " its table already has "<< table->GetPartitions().size() << " out of " << table->GetMaxPartitionsCount() << " partitions"); return true; } + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TTxPartitionHistogram Want to" + << " " << ToString(splitReason) << " " << splitReasonMsg + << " tablet " << datashardId); + TSmallVec keyColumnTypes(table->KeyColumnIds.size()); for (size_t ki = 0; ki < table->KeyColumnIds.size(); ++ki) { keyColumnTypes[ki] = table->Columns.FindPtr(table->KeyColumnIds[ki])->PType; @@ -390,9 +406,10 @@ bool TTxPartitionHistogram::Execute(TTransactionContext& txc, const TActorContex splitKey = ChooseSplitKeyByHistogram(histogram, dataSize, keyColumnTypes); if (splitKey.GetBuffer().empty()) { - LOG_WARN(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "Failed to find proper split key (initially) for '%s' of datashard %" PRIu64, - ToString(splitReason), datashardId); + LOG_WARN_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TTxPartitionHistogram Failed to find proper split key (initially) for" + << " " << ToString(splitReason) << " " << splitReasonMsg + << " tablet " << datashardId); return true; } @@ -402,17 +419,19 @@ bool TTxPartitionHistogram::Execute(TTransactionContext& txc, const TActorContex keyColumnTypes.data(), lowestKey.GetCells().size(), splitKey.GetCells().size())) { - LOG_WARN(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "Failed to find proper split key (less than first) for '%s' of datashard %" PRIu64, - ToString(splitReason), datashardId); + LOG_WARN_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TTxPartitionHistogram Failed to find proper split key (less than first) for" + << " " << ToString(splitReason) << " " << splitReasonMsg + << " tablet " << datashardId); return true; } } if (splitKey.GetBuffer().empty()) { - LOG_WARN(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "Failed to find proper split key for '%s' of datashard %" PRIu64, - ToString(splitReason), datashardId); + LOG_WARN_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "TTxPartitionHistogram Failed to find proper split key for" + << " " << ToString(splitReason) << " " << splitReasonMsg + << " tablet " << datashardId); return true; } @@ -420,17 +439,20 @@ bool TTxPartitionHistogram::Execute(TTransactionContext& txc, const TActorContex if (!txId) { LOG_WARN_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "Do not request split op" - << ", reason: no cached tx ids for internal operation" - << ", shardIdx: " << shardIdx); + "TTxPartitionHistogram Do not request split: no cached tx ids for internal operation" + << " " << ToString(splitReason) << " " << splitReasonMsg + << " tablet " << datashardId + << " shardIdx " << shardIdx); return true; } auto request = SplitRequest(Self, txId, tableId, datashardId, splitKey.GetBuffer()); LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "Propose split request : " << request->Record.ShortDebugString() - << ", reason: " << splitReasonMsg); + "TTxPartitionHistogram Propose" + << " " << ToString(splitReason) << " " << splitReasonMsg + << " tablet " << datashardId + << " request " << request->Record.ShortDebugString()); TMemoryChanges memChanges; TStorageChanges dbChanges; diff --git a/ydb/core/tx/schemeshard/schemeshard__tenant_data_erasure_manager.cpp b/ydb/core/tx/schemeshard/schemeshard__tenant_data_erasure_manager.cpp index 893ed3874ce2..1baf873455b3 100644 --- a/ydb/core/tx/schemeshard/schemeshard__tenant_data_erasure_manager.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__tenant_data_erasure_manager.cpp @@ -114,7 +114,7 @@ void TTenantDataErasureManager::Run(NIceDb::TNiceDb& db) { Status = EDataErasureStatus::IN_PROGRESS; for (const auto& [shardIdx, shardInfo] : SchemeShard->ShardInfos) { if (shardInfo.TabletType == ETabletType::DataShard) { - Enqueue(shardIdx); // forward generation + Enqueue(shardIdx); WaitingDataErasureShards[shardIdx] = EDataErasureStatus::IN_PROGRESS; db.Table().Key(shardIdx.GetOwnerId(), shardIdx.GetLocalId()).Update(WaitingDataErasureShards[shardIdx]); } @@ -291,21 +291,15 @@ void TTenantDataErasureManager::OnDone(const TTabletId& tabletId, NIceDb::TNiceD { auto it = WaitingDataErasureShards.find(shardIdx); if (it != WaitingDataErasureShards.end()) { - it->second = EDataErasureStatus::COMPLETED; + db.Table().Key(shardIdx.GetOwnerId(), shardIdx.GetLocalId()).Delete(); + WaitingDataErasureShards.erase(it); } - db.Table().Key(shardIdx.GetOwnerId(), shardIdx.GetLocalId()).Update(it->second); } SchemeShard->TabletCounters->Cumulative()[COUNTER_TENANT_DATA_ERASURE_OK].Increment(1); UpdateMetrics(); - bool isTenantDataErasureCompleted = true; - for (const auto& [shardIdx, status] : WaitingDataErasureShards) { - if (status == EDataErasureStatus::IN_PROGRESS) { - isTenantDataErasureCompleted = false; - } - } - if (isTenantDataErasureCompleted) { + if (WaitingDataErasureShards.empty()) { LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "[TenantDataErasureManager] Data erasure in shards is completed. Send response to root schemeshard"); Complete(); @@ -399,14 +393,8 @@ bool TTenantDataErasureManager::Remove(const TShardIdx& shardIdx) { if (it != WaitingDataErasureShards.end()) { Queue->Remove(shardIdx); ActivePipes.erase(shardIdx); - it->second = EDataErasureStatus::COMPLETED; - bool isTenantDataErasureCompleted = true; - for (const auto& [shardIdx, status] : WaitingDataErasureShards) { - if (status == EDataErasureStatus::IN_PROGRESS) { - isTenantDataErasureCompleted = false; - } - } - if (isTenantDataErasureCompleted) { + WaitingDataErasureShards.erase(it); + if (WaitingDataErasureShards.empty()) { auto ctx = SchemeShard->ActorContext(); LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "[TenantDataErasureManager] [Remove] Data erasure in shards is completed. Send response to root schemeshard"); @@ -620,7 +608,7 @@ struct TSchemeShard::TTxCancelDataErasureShards : public TSchemeShard::TRwTxBase NIceDb::TNiceDb db(txc.DB); for (const auto& shard : DataErasureShards) { if (Self->DataErasureManager->Remove(shard)) { - db.Table().Key(shard.GetOwnerId(), shard.GetLocalId()).Update(EDataErasureStatus::COMPLETED); + db.Table().Key(shard.GetOwnerId(), shard.GetLocalId()).Delete(); } } if (Self->DataErasureManager->GetStatus() == EDataErasureStatus::COMPLETED) { diff --git a/ydb/core/tx/schemeshard/schemeshard_audit_log.cpp b/ydb/core/tx/schemeshard/schemeshard_audit_log.cpp index aa66cfb98da4..a3608413dc19 100644 --- a/ydb/core/tx/schemeshard/schemeshard_audit_log.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_audit_log.cpp @@ -128,9 +128,9 @@ void AuditLogModifySchemeOperation(const NKikimrSchemeOp::TModifyScheme& operati AUDIT_PART(name, (!value.empty() ? value : EmptyValue)) } - AUDIT_PART("cloud_id", cloud_id, !cloud_id.empty()); - AUDIT_PART("folder_id", folder_id, !folder_id.empty()); - AUDIT_PART("resource_id", database_id, !database_id.empty()); + AUDIT_PART("cloud_id", cloud_id, !cloud_id.empty()) + AUDIT_PART("folder_id", folder_id, !folder_id.empty()) + AUDIT_PART("resource_id", database_id, !database_id.empty()) // Additionally: @@ -140,21 +140,23 @@ void AuditLogModifySchemeOperation(const NKikimrSchemeOp::TModifyScheme& operati // 1. explicit operation ESchemeOpModifyACL -- to modify ACL on a path // 2. ESchemeOpMkDir or ESchemeOpCreate* operations -- to set rights to newly created paths/entities // 3. ESchemeOpCopyTable -- to be checked against acl size limit, not to be applied in any way - AUDIT_PART("new_owner", logEntry.NewOwner, !logEntry.NewOwner.empty()); - AUDIT_PART("acl_add", RenderList(logEntry.ACLAdd), !logEntry.ACLAdd.empty()); - AUDIT_PART("acl_remove", RenderList(logEntry.ACLRemove), !logEntry.ACLRemove.empty()); + AUDIT_PART("new_owner", logEntry.NewOwner, !logEntry.NewOwner.empty()) + AUDIT_PART("acl_add", RenderList(logEntry.ACLAdd), !logEntry.ACLAdd.empty()) + AUDIT_PART("acl_remove", RenderList(logEntry.ACLRemove), !logEntry.ACLRemove.empty()) // AlterUserAttributes. // 1. explicit operation ESchemeOpAlterUserAttributes -- to modify user attributes on a path // 2. ESchemeOpMkDir or some ESchemeOpCreate* operations -- to set user attributes for newly created paths/entities - AUDIT_PART("user_attrs_add", RenderList(logEntry.UserAttrsAdd), !logEntry.UserAttrsAdd.empty()); - AUDIT_PART("user_attrs_remove", RenderList(logEntry.UserAttrsRemove), !logEntry.UserAttrsRemove.empty()); + AUDIT_PART("user_attrs_add", RenderList(logEntry.UserAttrsAdd), !logEntry.UserAttrsAdd.empty()) + AUDIT_PART("user_attrs_remove", RenderList(logEntry.UserAttrsRemove), !logEntry.UserAttrsRemove.empty()) // AlterLogin. // explicit operation ESchemeOpAlterLogin -- to modify user and groups - AUDIT_PART("login_user", logEntry.LoginUser); - AUDIT_PART("login_group", logEntry.LoginGroup); - AUDIT_PART("login_member", logEntry.LoginMember); + AUDIT_PART("login_user", logEntry.LoginUser) + AUDIT_PART("login_group", logEntry.LoginGroup) + AUDIT_PART("login_member", logEntry.LoginMember) + + AUDIT_PART("login_user_change", RenderList(logEntry.LoginUserChange), logEntry.LoginUserChange) ); } diff --git a/ydb/core/tx/schemeshard/schemeshard_audit_log_fragment.cpp b/ydb/core/tx/schemeshard/schemeshard_audit_log_fragment.cpp index 97506b73eb95..7920ee2de4e2 100644 --- a/ydb/core/tx/schemeshard/schemeshard_audit_log_fragment.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_audit_log_fragment.cpp @@ -678,40 +678,74 @@ struct TChangeLogin { TString LoginUser; TString LoginGroup; TString LoginMember; + TVector LoginUserChange; }; TChangeLogin ExtractLoginChange(const NKikimrSchemeOp::TModifyScheme& tx) { if (tx.HasAlterLogin()) { + const auto& alter = tx.GetAlterLogin(); + TChangeLogin result; switch (tx.GetAlterLogin().GetAlterCase()) { - case NKikimrSchemeOp::TAlterLogin::kCreateUser: - result.LoginUser = tx.GetAlterLogin().GetCreateUser().GetUser(); + case NKikimrSchemeOp::TAlterLogin::kCreateUser: { + result.LoginUser = alter.GetCreateUser().GetUser(); break; - case NKikimrSchemeOp::TAlterLogin::kModifyUser: - result.LoginUser = tx.GetAlterLogin().GetModifyUser().GetUser(); + } + + case NKikimrSchemeOp::TAlterLogin::kModifyUser: { + const auto& modify = alter.GetModifyUser(); + result.LoginUser = modify.GetUser(); + + if (modify.HasPassword()) { // there is no difference beetwen password and password's hash + result.LoginUserChange.push_back("password"); + } + + if (modify.HasCanLogin() && modify.GetCanLogin()) { + result.LoginUserChange.push_back("unblocking"); + } + + if (modify.HasCanLogin() && !modify.GetCanLogin()) { + result.LoginUserChange.push_back("blocking"); + } + break; - case NKikimrSchemeOp::TAlterLogin::kRemoveUser: - result.LoginUser = tx.GetAlterLogin().GetRemoveUser().GetUser(); + } + + case NKikimrSchemeOp::TAlterLogin::kRemoveUser: { + result.LoginUser = alter.GetRemoveUser().GetUser(); break; - case NKikimrSchemeOp::TAlterLogin::kCreateGroup: - result.LoginGroup = tx.GetAlterLogin().GetCreateGroup().GetGroup(); + } + + case NKikimrSchemeOp::TAlterLogin::kCreateGroup: { + result.LoginGroup = alter.GetCreateGroup().GetGroup(); break; - case NKikimrSchemeOp::TAlterLogin::kAddGroupMembership: - result.LoginGroup = tx.GetAlterLogin().GetAddGroupMembership().GetGroup(); - result.LoginMember = tx.GetAlterLogin().GetAddGroupMembership().GetMember(); + } + + case NKikimrSchemeOp::TAlterLogin::kAddGroupMembership: { + result.LoginGroup = alter.GetAddGroupMembership().GetGroup(); + result.LoginMember = alter.GetAddGroupMembership().GetMember(); break; - case NKikimrSchemeOp::TAlterLogin::kRemoveGroupMembership: - result.LoginGroup = tx.GetAlterLogin().GetRemoveGroupMembership().GetGroup(); - result.LoginMember = tx.GetAlterLogin().GetRemoveGroupMembership().GetMember(); + } + + case NKikimrSchemeOp::TAlterLogin::kRemoveGroupMembership: { + result.LoginGroup = alter.GetRemoveGroupMembership().GetGroup(); + result.LoginMember = alter.GetRemoveGroupMembership().GetMember(); break; - case NKikimrSchemeOp::TAlterLogin::kRenameGroup: - result.LoginGroup = tx.GetAlterLogin().GetRenameGroup().GetGroup(); + } + + case NKikimrSchemeOp::TAlterLogin::kRenameGroup: { + result.LoginGroup = alter.GetRenameGroup().GetGroup(); break; - case NKikimrSchemeOp::TAlterLogin::kRemoveGroup: - result.LoginGroup = tx.GetAlterLogin().GetRemoveGroup().GetGroup(); + } + + case NKikimrSchemeOp::TAlterLogin::kRemoveGroup: { + result.LoginGroup = alter.GetRemoveGroup().GetGroup(); break; - default: + } + + default: { Y_ABORT("switch should cover all operation types"); + } } return result; } @@ -725,7 +759,7 @@ namespace NKikimr::NSchemeShard { TAuditLogFragment MakeAuditLogFragment(const NKikimrSchemeOp::TModifyScheme& tx) { auto [aclAdd, aclRemove] = ExtractACLChange(tx); auto [userAttrsAdd, userAttrsRemove] = ExtractUserAttrChange(tx); - auto [loginUser, loginGroup, loginMember] = ExtractLoginChange(tx); + auto [loginUser, loginGroup, loginMember, loginUserChange] = ExtractLoginChange(tx); return { .Operation = DefineUserOperationName(tx), @@ -738,6 +772,7 @@ TAuditLogFragment MakeAuditLogFragment(const NKikimrSchemeOp::TModifyScheme& tx) .LoginUser = loginUser, .LoginGroup = loginGroup, .LoginMember = loginMember, + .LoginUserChange = loginUserChange }; } diff --git a/ydb/core/tx/schemeshard/schemeshard_audit_log_fragment.h b/ydb/core/tx/schemeshard/schemeshard_audit_log_fragment.h index e6347fb73255..52258901427d 100644 --- a/ydb/core/tx/schemeshard/schemeshard_audit_log_fragment.h +++ b/ydb/core/tx/schemeshard/schemeshard_audit_log_fragment.h @@ -21,6 +21,7 @@ struct TAuditLogFragment { TString LoginUser; TString LoginGroup; TString LoginMember; + TVector LoginUserChange; }; TAuditLogFragment MakeAuditLogFragment(const NKikimrSchemeOp::TModifyScheme& tx); diff --git a/ydb/core/tx/schemeshard/schemeshard_export.cpp b/ydb/core/tx/schemeshard/schemeshard_export.cpp index ce828f8960d8..36eef38b793d 100644 --- a/ydb/core/tx/schemeshard/schemeshard_export.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_export.cpp @@ -110,7 +110,8 @@ void TSchemeShard::FromXxportInfo(NKikimrExport::TExport& exprt, const TExportIn ? Ydb::Export::ExportProgress::PROGRESS_DONE : Ydb::Export::ExportProgress::PROGRESS_TRANSFER_DATA); break; - + + case TExportInfo::EState::AutoDropping: case TExportInfo::EState::Dropping: exprt.SetProgress(Ydb::Export::ExportProgress::PROGRESS_DONE); break; diff --git a/ydb/core/tx/schemeshard/schemeshard_export__create.cpp b/ydb/core/tx/schemeshard/schemeshard_export__create.cpp index ea97b3310ec2..06a11c1a9d2f 100644 --- a/ydb/core/tx/schemeshard/schemeshard_export__create.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_export__create.cpp @@ -796,6 +796,7 @@ struct TSchemeShard::TExport::TTxProgress: public TSchemeShard::TXxport::TTxBase SendNotificationsIfFinished(exportInfo); break; + case EState::AutoDropping: case EState::Dropping: if (!exportInfo->AllItemsAreDropped()) { for (ui32 itemIdx : xrange(exportInfo->Items.size())) { @@ -880,6 +881,7 @@ struct TSchemeShard::TExport::TTxProgress: public TSchemeShard::TXxport::TTxBase } break; + case EState::AutoDropping: case EState::Dropping: if (exportInfo->PendingDropItems) { itemIdx = PopFront(exportInfo->PendingDropItems); @@ -952,6 +954,7 @@ struct TSchemeShard::TExport::TTxProgress: public TSchemeShard::TXxport::TTxBase } break; + case EState::AutoDropping: case EState::Dropping: if (isMultipleMods || isNotExist) { if (record.GetPathDropTxId()) { @@ -1056,6 +1059,7 @@ struct TSchemeShard::TExport::TTxProgress: public TSchemeShard::TXxport::TTxBase Self->PersistExportItemState(db, exportInfo, itemIdx); break; + case EState::AutoDropping: case EState::Dropping: if (!exportInfo->AllItemsAreDropped()) { Y_ABORT_UNLESS(itemIdx < exportInfo->Items.size()); @@ -1142,7 +1146,8 @@ struct TSchemeShard::TExport::TTxProgress: public TSchemeShard::TXxport::TTxBase Self->PersistExportItemState(db, exportInfo, itemIdx); if (AllOf(exportInfo->Items, &TExportInfo::TItem::IsDone)) { - EndExport(exportInfo, EState::Done, db); + PrepareDropping(Self, exportInfo, db, true); + AllocateTxId(exportInfo); } } else if (exportInfo->State == EState::Cancellation) { item.State = EState::Cancelled; @@ -1342,14 +1347,15 @@ struct TSchemeShard::TExport::TTxProgress: public TSchemeShard::TXxport::TTxBase } } if (!itemHasIssues && AllOf(exportInfo->Items, &TExportInfo::TItem::IsDone)) { - exportInfo->State = EState::Done; - exportInfo->EndTime = TAppData::TimeProvider->Now(); + PrepareDropping(Self, exportInfo, db, true); + AllocateTxId(exportInfo); } Self->PersistExportItemState(db, exportInfo, itemIdx); break; } + case EState::AutoDropping: case EState::Dropping: if (!exportInfo->AllItemsAreDropped()) { Y_ABORT_UNLESS(itemIdx < exportInfo->Items.size()); @@ -1359,12 +1365,16 @@ struct TSchemeShard::TExport::TTxProgress: public TSchemeShard::TXxport::TTxBase item.WaitTxId = InvalidTxId; Self->PersistExportItemState(db, exportInfo, itemIdx); - if (exportInfo->AllItemsAreDropped()) { + if (exportInfo->AllItemsAreDropped() || exportInfo->State == EState::AutoDropping) { AllocateTxId(exportInfo); } } else { SendNotificationsIfFinished(exportInfo, true); // for tests + if (exportInfo->State == EState::AutoDropping) { + return EndExport(exportInfo, EState::Done, db); + } + if (exportInfo->Uid) { Self->ExportsByUid.erase(exportInfo->Uid); } diff --git a/ydb/core/tx/schemeshard/schemeshard_export__forget.cpp b/ydb/core/tx/schemeshard/schemeshard_export__forget.cpp index 2a4fd3c5f186..d4455cc40837 100644 --- a/ydb/core/tx/schemeshard/schemeshard_export__forget.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_export__forget.cpp @@ -77,23 +77,8 @@ struct TSchemeShard::TExport::TTxForget: public TSchemeShard::TXxport::TTxBase { LOG_D("TExport::TTxForget, dropping export tables" << ", info: " << exportInfo->ToString() ); - exportInfo->WaitTxId = InvalidTxId; - exportInfo->State = TExportInfo::EState::Dropping; - Self->PersistExportState(db, exportInfo); - - for (ui32 itemIdx : xrange(exportInfo->Items.size())) { - auto& item = exportInfo->Items.at(itemIdx); - - item.WaitTxId = InvalidTxId; - item.State = TExportInfo::EState::Dropped; - - const TPath itemPath = TPath::Resolve(ExportItemPathName(Self, exportInfo, itemIdx), Self); - if (itemPath.IsResolved() && !itemPath.IsDeleted()) { - item.State = TExportInfo::EState::Dropping; - } - - Self->PersistExportItemState(db, exportInfo, itemIdx); - } + + PrepareDropping(Self, exportInfo, db); Progress = true; } diff --git a/ydb/core/tx/schemeshard/schemeshard_export_flow_proposals.cpp b/ydb/core/tx/schemeshard/schemeshard_export_flow_proposals.cpp index 238003bbea82..22ca33b0d24d 100644 --- a/ydb/core/tx/schemeshard/schemeshard_export_flow_proposals.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_export_flow_proposals.cpp @@ -328,5 +328,27 @@ TString ExportItemPathName(const TString& exportPathName, ui32 itemIdx) { return TStringBuilder() << exportPathName << "/" << itemIdx; } +void PrepareDropping(TSchemeShard* ss, TExportInfo::TPtr exportInfo, NIceDb::TNiceDb& db, bool isAutoDropping) { + exportInfo->WaitTxId = InvalidTxId; + exportInfo->State = isAutoDropping ? TExportInfo::EState::AutoDropping : TExportInfo::EState::Dropping; + ss->PersistExportState(db, exportInfo); + + for (ui32 itemIdx : xrange(exportInfo->Items.size())) { + auto& item = exportInfo->Items.at(itemIdx); + + item.WaitTxId = InvalidTxId; + item.State = TExportInfo::EState::Dropped; + const TPath itemPath = TPath::Resolve(ExportItemPathName(ss, exportInfo, itemIdx), ss); + if (itemPath.IsResolved() && !itemPath.IsDeleted()) { + item.State = TExportInfo::EState::Dropping; + if (isAutoDropping) { + exportInfo->PendingDropItems.push_back(itemIdx); + } + } + + ss->PersistExportItemState(db, exportInfo, itemIdx); + } +} + } // NSchemeShard } // NKikimr diff --git a/ydb/core/tx/schemeshard/schemeshard_export_flow_proposals.h b/ydb/core/tx/schemeshard/schemeshard_export_flow_proposals.h index a84cb925ea08..c6f7b5aaa342 100644 --- a/ydb/core/tx/schemeshard/schemeshard_export_flow_proposals.h +++ b/ydb/core/tx/schemeshard/schemeshard_export_flow_proposals.h @@ -47,5 +47,7 @@ THolder CancelPropose( TString ExportItemPathName(TSchemeShard* ss, const TExportInfo::TPtr exportInfo, ui32 itemIdx); TString ExportItemPathName(const TString& exportPathName, ui32 itemIdx); +void PrepareDropping(TSchemeShard* ss, TExportInfo::TPtr exportInfo, NIceDb::TNiceDb& db, bool isAutoDropping = false); + } // NSchemeShard } // NKikimr diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.cpp b/ydb/core/tx/schemeshard/schemeshard_impl.cpp index 4a2756a256ef..87e03e53afba 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_impl.cpp @@ -1362,7 +1362,7 @@ bool TSchemeShard::CheckApplyIf(const NKikimrSchemeOp::TModifyScheme& scheme, TS if (item.HasLockedTxId()) { const auto lockOwnerTxId = TTxId(item.GetLockedTxId()); - + TString lockErr = "fail user constraint in ApplyIf section:"; if (!CheckLocks(pathId, lockOwnerTxId, lockErr)) { errStr = lockErr; @@ -2295,7 +2295,7 @@ void TSchemeShard::PersistRemoveSubDomain(NIceDb::TNiceDb& db, const TPathId& pa } if (DataErasureManager->Remove(pathId)) { - db.Table().Key(pathId.OwnerId, pathId.LocalPathId).Update(EDataErasureStatus::COMPLETED); + db.Table().Key(pathId.OwnerId, pathId.LocalPathId).Delete(); } db.Table().Key(pathId.LocalPathId).Delete(); @@ -4701,14 +4701,11 @@ void TSchemeShard::OnActivateExecutor(const TActorContext &ctx) { EnableAlterDatabaseCreateHiveFirst = appData->FeatureFlags.GetEnableAlterDatabaseCreateHiveFirst(); EnablePQConfigTransactionsAtSchemeShard = appData->FeatureFlags.GetEnablePQConfigTransactionsAtSchemeShard(); EnableStatistics = appData->FeatureFlags.GetEnableStatistics(); - EnableTablePgTypes = appData->FeatureFlags.GetEnableTablePgTypes(); EnableServerlessExclusiveDynamicNodes = appData->FeatureFlags.GetEnableServerlessExclusiveDynamicNodes(); EnableAddColumsWithDefaults = appData->FeatureFlags.GetEnableAddColumsWithDefaults(); EnableReplaceIfExistsForExternalEntities = appData->FeatureFlags.GetEnableReplaceIfExistsForExternalEntities(); EnableTempTables = appData->FeatureFlags.GetEnableTempTables(); - EnableTableDatetime64 = appData->FeatureFlags.GetEnableTableDatetime64(); EnableVectorIndex = appData->FeatureFlags.GetEnableVectorIndex(); - EnableParameterizedDecimal = appData->FeatureFlags.GetEnableParameterizedDecimal(); EnableDataErasure = appData->FeatureFlags.GetEnableDataErasure(); ConfigureCompactionQueues(appData->CompactionConfig, ctx); @@ -5755,7 +5752,7 @@ void TSchemeShard::Handle(TEvTabletPipe::TEvServerDisconnected::TPtr &, const TA void TSchemeShard::Handle(TEvSchemeShard::TEvSyncTenantSchemeShard::TPtr& ev, const TActorContext& ctx) { const auto& record = ev->Get()->Record; - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "Handle TEvSyncTenantSchemeShard" << ", at schemeshard: " << TabletID() << ", msg: " << record.DebugString()); @@ -7150,7 +7147,7 @@ void TSchemeShard::SetPartitioning(TPathId pathId, TTableInfo::TPtr tableInfo, T newPartitioningSet.reserve(newPartitioning.size()); const auto& oldPartitioning = tableInfo->GetPartitions(); - std::vector dataErasureShards; + std::vector newDataErasureShards; for (const auto& p: newPartitioning) { if (!oldPartitioning.empty()) newPartitioningSet.insert(p.ShardIdx); @@ -7160,11 +7157,11 @@ void TSchemeShard::SetPartitioning(TPathId pathId, TTableInfo::TPtr tableInfo, T if (it != partitionStats.end()) { EnqueueBackgroundCompaction(p.ShardIdx, it->second); UpdateShardMetrics(p.ShardIdx, it->second); - dataErasureShards.push_back(p.ShardIdx); + newDataErasureShards.push_back(p.ShardIdx); } } - if (DataErasureManager->GetStatus() == EDataErasureStatus::IN_PROGRESS) { - Execute(CreateTxAddEntryToDataErasure(dataErasureShards), this->ActorContext()); + if (EnableDataErasure && DataErasureManager->GetStatus() == EDataErasureStatus::IN_PROGRESS) { + Execute(CreateTxAddEntryToDataErasure(newDataErasureShards), this->ActorContext()); } for (const auto& p: oldPartitioning) { @@ -7342,16 +7339,13 @@ void TSchemeShard::ApplyConsoleConfigs(const NKikimrConfig::TFeatureFlags& featu EnableAlterDatabaseCreateHiveFirst = featureFlags.GetEnableAlterDatabaseCreateHiveFirst(); EnablePQConfigTransactionsAtSchemeShard = featureFlags.GetEnablePQConfigTransactionsAtSchemeShard(); EnableStatistics = featureFlags.GetEnableStatistics(); - EnableTablePgTypes = featureFlags.GetEnableTablePgTypes(); EnableServerlessExclusiveDynamicNodes = featureFlags.GetEnableServerlessExclusiveDynamicNodes(); EnableAddColumsWithDefaults = featureFlags.GetEnableAddColumsWithDefaults(); EnableTempTables = featureFlags.GetEnableTempTables(); EnableReplaceIfExistsForExternalEntities = featureFlags.GetEnableReplaceIfExistsForExternalEntities(); - EnableTableDatetime64 = featureFlags.GetEnableTableDatetime64(); EnableResourcePoolsOnServerless = featureFlags.GetEnableResourcePoolsOnServerless(); EnableVectorIndex = featureFlags.GetEnableVectorIndex(); EnableExternalDataSourcesOnServerless = featureFlags.GetEnableExternalDataSourcesOnServerless(); - EnableParameterizedDecimal = featureFlags.GetEnableParameterizedDecimal(); EnableDataErasure = featureFlags.GetEnableDataErasure(); } diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.h b/ydb/core/tx/schemeshard/schemeshard_impl.h index 9b4a405f96d6..b1bf42759fb0 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.h +++ b/ydb/core/tx/schemeshard/schemeshard_impl.h @@ -334,16 +334,13 @@ class TSchemeShard bool EnableAlterDatabaseCreateHiveFirst = false; bool EnablePQConfigTransactionsAtSchemeShard = false; bool EnableStatistics = false; - bool EnableTablePgTypes = false; bool EnableServerlessExclusiveDynamicNodes = false; bool EnableAddColumsWithDefaults = false; bool EnableReplaceIfExistsForExternalEntities = false; bool EnableTempTables = false; - bool EnableTableDatetime64 = false; bool EnableResourcePoolsOnServerless = false; bool EnableVectorIndex = false; bool EnableExternalDataSourcesOnServerless = false; - bool EnableParameterizedDecimal = false; bool EnableDataErasure = false; TShardDeleter ShardDeleter; diff --git a/ydb/core/tx/schemeshard/schemeshard_info_types.h b/ydb/core/tx/schemeshard/schemeshard_info_types.h index 08a66fd56f85..c6b78adcdbd2 100644 --- a/ydb/core/tx/schemeshard/schemeshard_info_types.h +++ b/ydb/core/tx/schemeshard/schemeshard_info_types.h @@ -2688,6 +2688,7 @@ struct TExportInfo: public TSimpleRefCount { Done = 240, Dropping = 241, Dropped = 242, + AutoDropping = 243, Cancellation = 250, Cancelled = 251, }; @@ -2805,12 +2806,16 @@ struct TExportInfo: public TSimpleRefCount { return State == EState::Dropping; } + bool IsAutoDropping() const { + return State == EState::AutoDropping; + } + bool IsCancelling() const { return State == EState::Cancellation; } bool IsInProgress() const { - return IsPreparing() || IsWorking() || IsDropping() || IsCancelling(); + return IsPreparing() || IsWorking() || IsDropping() || IsAutoDropping() || IsCancelling(); } bool IsDone() const { diff --git a/ydb/core/tx/schemeshard/ut_base/ut_table_decimal_types.cpp b/ydb/core/tx/schemeshard/ut_base/ut_table_decimal_types.cpp index a05ce0d9d593..6f9ce1c7e497 100644 --- a/ydb/core/tx/schemeshard/ut_base/ut_table_decimal_types.cpp +++ b/ydb/core/tx/schemeshard/ut_base/ut_table_decimal_types.cpp @@ -107,6 +107,39 @@ Y_UNIT_TEST_SUITE(TSchemeShardDecimalTypesInTables) { }); } + Y_UNIT_TEST(CopyTableShouldNotFailOnDisabledFeatureFlag) { + TTestBasicRuntime runtime; + TTestEnv env(runtime, TTestEnvOptions().EnableParameterizedDecimal(true)); + ui64 txId = 100; + + AsyncCreateTable(runtime, ++txId, "/MyRoot", R"_( + Name: "Table1" + Columns { Name: "key" Type: "Decimal(35,6)" } + Columns { Name: "value" Type: "Decimal(35,6)" } + KeyColumnNames: ["key"] + )_"); + TestModificationResults(runtime, txId, {TExpectedResult(NKikimrScheme::StatusAccepted)}); + env.TestWaitNotification(runtime, txId); + + TestDescribeResult(DescribePath(runtime, "/MyRoot/Table1"), { + NLs::PathExist, + NLs::Finished, + NLs::CheckColumnType(0, "Decimal(35,6)") + }); + + runtime.GetAppData().FeatureFlags.SetEnableParameterizedDecimal(false); + + AsyncCopyTable(runtime, ++txId, "/MyRoot", "Copy1", "/MyRoot/Table1"); + TestModificationResults(runtime, txId, {TExpectedResult(NKikimrScheme::StatusAccepted)}); + env.TestWaitNotification(runtime, txId); + + TestDescribeResult(DescribePath(runtime, "/MyRoot/Copy1"), { + NLs::PathExist, + NLs::Finished, + NLs::CheckColumnType(0, "Decimal(35,6)") + }); + } + Y_UNIT_TEST(CreateWithWrongParameters) { TTestBasicRuntime runtime; TTestEnv env(runtime, TTestEnvOptions().EnableParameterizedDecimal(true)); diff --git a/ydb/core/tx/schemeshard/ut_export/ut_export.cpp b/ydb/core/tx/schemeshard/ut_export/ut_export.cpp index fb5674b9455b..4534fc6d2546 100644 --- a/ydb/core/tx/schemeshard/ut_export/ut_export.cpp +++ b/ydb/core/tx/schemeshard/ut_export/ut_export.cpp @@ -1231,10 +1231,24 @@ partitioning_settings { } )", port)); const ui64 exportId = txId; + ::NKikimrSubDomains::TDiskSpaceUsage afterExport; + + TTestActorRuntime::TEventObserver prevObserverFunc; + prevObserverFunc = runtime.SetObserverFunc([&](TAutoPtr& event) { + if (auto* p = event->CastAsLocal()) { + auto& record = p->Record; + if (record.TransactionSize() >= 1 && + record.GetTransaction(0).GetOperationType() == NKikimrSchemeOp::ESchemeOpDropTable) { + afterExport = waitForStats(2); + } + } + return prevObserverFunc(event); + }); + env.TestWaitNotification(runtime, exportId); TestGetExport(runtime, exportId, "/MyRoot", Ydb::StatusIds::SUCCESS); - const auto afterExport = waitForStats(2); + UNIT_ASSERT_STRINGS_EQUAL(expected.DebugString(), afterExport.DebugString()); TestForgetExport(runtime, ++txId, "/MyRoot", exportId); @@ -1250,13 +1264,23 @@ partitioning_settings { TTestEnv env(runtime); ui64 txId = 100; + TBlockEvents blockPartition0(runtime, [](auto&& ev) { + return ev->Get()->Request.GetKey() == "/data_01.csv"; + }); + TestCreateTable(runtime, ++txId, "/MyRoot", R"( Name: "Table" - Columns { Name: "key" Type: "Utf8" } + Columns { Name: "key" Type: "Uint32" } Columns { Name: "value" Type: "Utf8" } KeyColumnNames: ["key"] + SplitBoundary { KeyPrefix { Tuple { Optional { Uint32: 10 } }}} )"); env.TestWaitNotification(runtime, txId); + + WriteRow(runtime, ++txId, "/MyRoot/Table", 0, 1, "v1"); + env.TestWaitNotification(runtime, txId); + WriteRow(runtime, ++txId, "/MyRoot/Table", 1, 100, "v100"); + env.TestWaitNotification(runtime, txId); TPortManager portManager; const ui16 port = portManager.GetPort(); @@ -1274,17 +1298,35 @@ partitioning_settings { } } )", port)); + + + runtime.WaitFor("put object request from 01 partition", [&]{ return blockPartition0.size() >= 1; }); + bool isCompleted = false; + + while (!isCompleted) { + const auto desc = TestGetExport(runtime, txId, "/MyRoot"); + const auto entry = desc.GetResponse().GetEntry(); + const auto& item = entry.GetItemsProgress(0); + + if (item.parts_completed() > 0) { + isCompleted = true; + UNIT_ASSERT_VALUES_EQUAL(item.parts_total(), 2); + UNIT_ASSERT_VALUES_EQUAL(item.parts_completed(), 1); + UNIT_ASSERT(item.has_start_time()); + } else { + runtime.SimulateSleep(TDuration::Seconds(1)); + } + } + + blockPartition0.Stop(); + blockPartition0.Unblock(); + env.TestWaitNotification(runtime, txId); const auto desc = TestGetExport(runtime, txId, "/MyRoot"); - const auto& entry = desc.GetResponse().GetEntry(); - UNIT_ASSERT_VALUES_EQUAL(entry.ItemsProgressSize(), 1); + const auto entry = desc.GetResponse().GetEntry(); - const auto& item = entry.GetItemsProgress(0); - UNIT_ASSERT_VALUES_EQUAL(item.parts_total(), 1); - UNIT_ASSERT_VALUES_EQUAL(item.parts_completed(), 1); - UNIT_ASSERT(item.has_start_time()); - UNIT_ASSERT(item.has_end_time()); + UNIT_ASSERT_VALUES_EQUAL(entry.ItemsProgressSize(), 1); } Y_UNIT_TEST(ShouldRestartOnScanErrors) { @@ -2888,4 +2930,41 @@ attributes { UNIT_ASSERT_C(ivs.insert(iv.GetBinaryString()).second, key); } } + + Y_UNIT_TEST(AutoDropping) { + TTestBasicRuntime runtime; + + TPortManager portManager; + const ui16 port = portManager.GetPort(); + + TS3Mock s3Mock({}, TS3Mock::TSettings(port)); + UNIT_ASSERT(s3Mock.Start()); + + + auto request = Sprintf(R"( + ExportToS3Settings { + endpoint: "localhost:%d" + scheme: HTTP + items { + source_path: "/MyRoot/Table" + destination_prefix: "" + } + } + )", port); + + TTestEnv env(runtime); + + Run(runtime, env, TVector{ + R"( + Name: "Table" + Columns { Name: "key" Type: "Utf8" } + Columns { Name: "value" Type: "Utf8" } + KeyColumnNames: ["key"] + )", + }, request, Ydb::StatusIds::SUCCESS, "/MyRoot"); + + auto desc = DescribePath(runtime, "/MyRoot"); + UNIT_ASSERT_EQUAL(desc.GetPathDescription().ChildrenSize(), 1); + UNIT_ASSERT_EQUAL(desc.GetPathDescription().GetChildren(0).GetName(), "Table"); + } } diff --git a/ydb/core/tx/schemeshard/ut_export_reboots_s3/ut_export_reboots_s3.cpp b/ydb/core/tx/schemeshard/ut_export_reboots_s3/ut_export_reboots_s3.cpp index 73823901479f..a3c1b56825da 100644 --- a/ydb/core/tx/schemeshard/ut_export_reboots_s3/ut_export_reboots_s3.cpp +++ b/ydb/core/tx/schemeshard/ut_export_reboots_s3/ut_export_reboots_s3.cpp @@ -510,7 +510,7 @@ Y_UNIT_TEST_SUITE(TExportToS3WithRebootsTests) { )"); } - class TestData { + class TTestData { public: static const TTypedScheme& Table() { return TableScheme; @@ -531,9 +531,9 @@ Y_UNIT_TEST_SUITE(TExportToS3WithRebootsTests) { static const TString RequestString; }; - const char* TestData::TableName = "Table"; + const char* TTestData::TableName = "Table"; - const TTypedScheme TestData::TableScheme = TTypedScheme { + const TTypedScheme TTestData::TableScheme = TTypedScheme { EPathTypeTable, Sprintf(R"( Name: "%s" @@ -543,7 +543,7 @@ Y_UNIT_TEST_SUITE(TExportToS3WithRebootsTests) { )", TableName) }; - const TTypedScheme TestData::ChangefeedScheme = TTypedScheme { + const TTypedScheme TTestData::ChangefeedScheme = TTypedScheme { EPathTypeCdcStream, Sprintf(R"( TableName: "%s" @@ -556,7 +556,7 @@ Y_UNIT_TEST_SUITE(TExportToS3WithRebootsTests) { )", TableName) }; - const TString TestData::RequestString = R"( + const TString TTestData::RequestString = R"( ExportToS3Settings { endpoint: "localhost:%d" scheme: HTTP @@ -569,22 +569,55 @@ Y_UNIT_TEST_SUITE(TExportToS3WithRebootsTests) { Y_UNIT_TEST(ShouldSucceedOnSingleShardTableWithChangefeed) { RunS3({ - TestData::Table(), - TestData::Changefeed() - }, TestData::Request()); + TTestData::Table(), + TTestData::Changefeed() + }, TTestData::Request()); } Y_UNIT_TEST(CancelOnSingleShardTableWithChangefeed) { CancelS3({ - TestData::Table(), - TestData::Changefeed() - }, TestData::Request()); + TTestData::Table(), + TTestData::Changefeed() + }, TTestData::Request()); } Y_UNIT_TEST(ForgetShouldSucceedOnSingleShardTableWithChangefeed) { ForgetS3({ - TestData::Table(), - TestData::Changefeed() - }, TestData::Request()); + TTestData::Table(), + TTestData::Changefeed() + }, TTestData::Request()); + } + + Y_UNIT_TEST(ShouldSucceedAutoDropping) { + TPortManager portManager; + const ui16 port = portManager.GetPort(); + + TTestWithReboots t; + TS3Mock s3Mock({}, TS3Mock::TSettings(port)); + UNIT_ASSERT(s3Mock.Start()); + + t.Run([&](TTestActorRuntime& runtime, bool& activeZone) { + runtime.SetLogPriority(NKikimrServices::EXPORT, NActors::NLog::PRI_TRACE); + { + TInactiveZone inactive(activeZone); + CreateSchemeObjects(t, runtime, { + TTestData::Table() + }); + + TestExport(runtime, ++t.TxId, "/MyRoot", Sprintf(TTestData::Request().data(), port)); + } + + const ui64 exportId = t.TxId; + t.TestEnv->TestWaitNotification(runtime, exportId); + + { + TInactiveZone inactive(activeZone); + TestGetExport(runtime, exportId, "/MyRoot"); + TestRmDir(runtime, ++t.TxId, "/MyRoot", "DirA"); + auto desc = DescribePath(runtime, "/MyRoot"); + UNIT_ASSERT_EQUAL(desc.GetPathDescription().ChildrenSize(), 1); + UNIT_ASSERT_EQUAL(desc.GetPathDescription().GetChildren(0).GetName(), "Table"); + } + }); } } diff --git a/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp b/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp index e1a7ce6deea7..8393600803d5 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp +++ b/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp @@ -2114,7 +2114,7 @@ namespace NSchemeShardUT_Private { return event->Record; } - void ChangeIsEnabledUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, const TString& user, bool isEnabled) { + void ModifyUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, std::function&& initiator) { auto modifyTx = std::make_unique(txId, TTestTxConfig::SchemeShard); auto transaction = modifyTx->Record.AddTransaction(); transaction->SetWorkingDir(database); @@ -2122,12 +2122,33 @@ namespace NSchemeShardUT_Private { auto alterUser = transaction->MutableAlterLogin()->MutableModifyUser(); - alterUser->SetUser(user); - alterUser->SetCanLogin(isEnabled); + initiator(alterUser); AsyncSend(runtime, TTestTxConfig::SchemeShard, modifyTx.release()); TAutoPtr handle; - [[maybe_unused]]auto event = runtime.GrabEdgeEvent(handle); // wait() + [[maybe_unused]]auto event = runtime.GrabEdgeEvent(handle); // wait() + } + + void ChangeIsEnabledUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, const TString& user, bool isEnabled) { + ModifyUser(runtime, txId, database, [user, isEnabled](auto* alterUser) { + alterUser->SetUser(std::move(user)); + alterUser->SetCanLogin(isEnabled); + }); + } + + void ChangePasswordUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, const TString& user, const TString& password) { + ModifyUser(runtime, txId, database, [user, password](auto* alterUser) { + alterUser->SetUser(std::move(user)); + alterUser->SetPassword(std::move(password)); + }); + } + + void ChangePasswordHashUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, const TString& user, const TString& hash) { + ModifyUser(runtime, txId, database, [user, hash](auto* alterUser) { + alterUser->SetUser(std::move(user)); + alterUser->SetPassword(std::move(hash)); + alterUser->SetIsHashedPassword(true); + }); } // class TFakeDataReq { diff --git a/ydb/core/tx/schemeshard/ut_helpers/helpers.h b/ydb/core/tx/schemeshard/ut_helpers/helpers.h index baf3bcbe2a40..7e1e28e0ef0f 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/helpers.h +++ b/ydb/core/tx/schemeshard/ut_helpers/helpers.h @@ -551,9 +551,17 @@ namespace NSchemeShardUT_Private { NKikimrScheme::TEvLoginResult Login(TTestActorRuntime& runtime, const TString& user, const TString& password); + void ModifyUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, std::function&& initiator); + void ChangeIsEnabledUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, const TString& user, bool isEnabled); + void ChangePasswordUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, + const TString& user, const TString& password); + + void ChangePasswordHashUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, + const TString& user, const TString& hash); + // Mimics data query to a single table with multiple partitions class TFakeDataReq { public: diff --git a/ydb/core/tx/schemeshard/ut_login/ut_login.cpp b/ydb/core/tx/schemeshard/ut_login/ut_login.cpp index e904bcb126ef..348a572e2f6d 100644 --- a/ydb/core/tx/schemeshard/ut_login/ut_login.cpp +++ b/ydb/core/tx/schemeshard/ut_login/ut_login.cpp @@ -574,7 +574,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { UNIT_ASSERT_VALUES_EQUAL(resultLogin1.error(), ""); ChangeIsEnabledUser(runtime, ++txId, "/MyRoot", "user1", false); auto resultLogin2 = Login(runtime, "user1", "123"); - UNIT_ASSERT_VALUES_EQUAL(resultLogin2.error(), "User user1 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin2.error(), "User user1 login denied: account is blocked"); ChangeIsEnabledUser(runtime, ++txId, "/MyRoot", "user1", true); auto resultLogin3 = Login(runtime, "user1", "123"); UNIT_ASSERT_VALUES_EQUAL(resultLogin3.error(), ""); @@ -610,7 +610,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { Sleep(TDuration::Seconds(4)); auto resultLogin = Login(runtime, "user1", "123"); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), "User user1 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), "User user1 login denied: account is blocked"); } Y_UNIT_TEST(ChangeAcceptablePasswordParameters) { @@ -854,11 +854,11 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), "Invalid password"); } resultLogin = Login(runtime, "user1", TStringBuilder() << "wrongpassword" << accountLockoutConfig.GetAttemptThreshold()); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 login denied: too many failed password attempts"); // Also do not accept correct password resultLogin = Login(runtime, "user1", "password1"); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 login denied: too many failed password attempts"); { auto describe = DescribePath(runtime, TTestTxConfig::SchemeShard, "/MyRoot"); @@ -951,7 +951,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), "Invalid password"); } resultLogin = Login(runtime, "user1", TStringBuilder() << "wrongpassword" << accountLockoutConfig.GetAttemptThreshold()); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 login denied: too many failed password attempts"); { auto describe = DescribePath(runtime, TTestTxConfig::SchemeShard, "/MyRoot"); @@ -982,7 +982,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { } resultLogin = Login(runtime, "user2", TStringBuilder() << "wrongpassword2" << newAttemptThreshold); // User is not permitted to log in after 6 attempts - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user2 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user2 login denied: too many failed password attempts"); { auto describe = DescribePath(runtime, TTestTxConfig::SchemeShard, "/MyRoot"); @@ -993,7 +993,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { // After 4 seconds user2 must be locked out Sleep(TDuration::Seconds(4)); resultLogin = Login(runtime, "user2", "wrongpassword28"); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user2 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user2 login denied: too many failed password attempts"); // After 7 seconds user2 must be unlocked Sleep(TDuration::Seconds(8)); @@ -1026,11 +1026,11 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), "Invalid password"); } resultLogin = Login(runtime, "user1", TStringBuilder() << "wrongpassword" << accountLockoutConfig.GetAttemptThreshold()); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 login denied: too many failed password attempts"); // Also do not accept correct password resultLogin = Login(runtime, "user1", "password1"); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 login denied: too many failed password attempts"); } Y_UNIT_TEST(CheckThatLockedOutParametersIsRestoredFromLocalDb) { @@ -1067,7 +1067,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), "Invalid password"); } resultLogin = Login(runtime, "user1", TStringBuilder() << "wrongpassword" << accountLockoutConfig.GetAttemptThreshold()); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 login denied: too many failed password attempts"); { auto describe = DescribePath(runtime, TTestTxConfig::SchemeShard, "/MyRoot"); @@ -1079,7 +1079,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { // After reboot schemeshard user1 must be locked out resultLogin = Login(runtime, "user1", TStringBuilder() << "wrongpassword" << accountLockoutConfig.GetAttemptThreshold()); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 is not permitted to log in"); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), TStringBuilder() << "User user1 login denied: too many failed password attempts"); // User1 must be unlocked in 1 second after reboot schemeshard Sleep(TDuration::Seconds(2)); @@ -1133,9 +1133,9 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { CreateAlterLoginCreateUser(runtime, ++txId, "/MyRoot", userName, userPassword); blockUser(); - loginUser(TStringBuilder() << "User " << userName << " is not permitted to log in"); + loginUser(TStringBuilder() << "User " << userName << " login denied: too many failed password attempts"); reboot(); - loginUser(TStringBuilder() << "User " << userName << " is not permitted to log in"); + loginUser(TStringBuilder() << "User " << userName << " login denied: too many failed password attempts"); ChangeIsEnabledUser(runtime, ++txId, "/MyRoot", userName, true); loginUser(""); @@ -1197,7 +1197,7 @@ NHttp::THttpIncomingRequestPtr MakeLogoutRequest(const TString& cookieName, cons Y_UNIT_TEST_SUITE(TWebLoginService) { void AuditLogLoginTest(TTestBasicRuntime& runtime, bool isUserAdmin) { std::vector lines; - runtime.AuditLogBackends = std::move(CreateTestAuditLogBackends(lines)); + runtime.AuditLogBackends = CreateTestAuditLogBackends(lines); TTestEnv env(runtime); UNIT_ASSERT_VALUES_EQUAL(lines.size(), 1); // alter root subdomain @@ -1267,7 +1267,7 @@ Y_UNIT_TEST_SUITE(TWebLoginService) { Y_UNIT_TEST(AuditLogLoginBadPassword) { TTestBasicRuntime runtime; std::vector lines; - runtime.AuditLogBackends = std::move(CreateTestAuditLogBackends(lines)); + runtime.AuditLogBackends = CreateTestAuditLogBackends(lines); TTestEnv env(runtime); UNIT_ASSERT_VALUES_EQUAL(lines.size(), 1); // alter root subdomain @@ -1309,7 +1309,7 @@ Y_UNIT_TEST_SUITE(TWebLoginService) { Y_UNIT_TEST(AuditLogLdapLoginSuccess) { TTestBasicRuntime runtime; std::vector lines; - runtime.AuditLogBackends = std::move(CreateTestAuditLogBackends(lines)); + runtime.AuditLogBackends = CreateTestAuditLogBackends(lines); // Enable and configure ldap auth runtime.SetLogPriority(NKikimrServices::LDAP_AUTH_PROVIDER, NActors::NLog::PRI_DEBUG); TTestEnv env(runtime); @@ -1405,7 +1405,7 @@ Y_UNIT_TEST_SUITE(TWebLoginService) { Y_UNIT_TEST(AuditLogLdapLoginBadPassword) { TTestBasicRuntime runtime; std::vector lines; - runtime.AuditLogBackends = std::move(CreateTestAuditLogBackends(lines)); + runtime.AuditLogBackends =CreateTestAuditLogBackends(lines); // Enable and configure ldap auth runtime.SetLogPriority(NKikimrServices::LDAP_AUTH_PROVIDER, NActors::NLog::PRI_DEBUG); TTestEnv env(runtime); @@ -1500,7 +1500,7 @@ Y_UNIT_TEST_SUITE(TWebLoginService) { Y_UNIT_TEST(AuditLogLdapLoginBadUser) { TTestBasicRuntime runtime; std::vector lines; - runtime.AuditLogBackends = std::move(CreateTestAuditLogBackends(lines)); + runtime.AuditLogBackends =CreateTestAuditLogBackends(lines); // Enable and configure ldap auth runtime.SetLogPriority(NKikimrServices::LDAP_AUTH_PROVIDER, NActors::NLog::PRI_DEBUG); TTestEnv env(runtime); @@ -1596,7 +1596,7 @@ Y_UNIT_TEST_SUITE(TWebLoginService) { Y_UNIT_TEST(AuditLogLdapLoginBadBind) { TTestBasicRuntime runtime; std::vector lines; - runtime.AuditLogBackends = std::move(CreateTestAuditLogBackends(lines)); + runtime.AuditLogBackends =CreateTestAuditLogBackends(lines); // Enable and configure ldap auth runtime.SetLogPriority(NKikimrServices::LDAP_AUTH_PROVIDER, NActors::NLog::PRI_DEBUG); TTestEnv env(runtime); @@ -1691,7 +1691,7 @@ Y_UNIT_TEST_SUITE(TWebLoginService) { Y_UNIT_TEST(AuditLogLogout) { TTestBasicRuntime runtime; std::vector lines; - runtime.AuditLogBackends = std::move(CreateTestAuditLogBackends(lines)); + runtime.AuditLogBackends =CreateTestAuditLogBackends(lines); TTestEnv env(runtime); // Add ticket parser to the mix @@ -1792,4 +1792,88 @@ Y_UNIT_TEST_SUITE(TWebLoginService) { UNIT_ASSERT(last.find("sanitized_token={none}") == std::string::npos); } } + + Y_UNIT_TEST(AuditLogCreateModifyUser) { + TTestBasicRuntime runtime; + std::vector lines; + runtime.AuditLogBackends = CreateTestAuditLogBackends(lines); + TTestEnv env(runtime); + UNIT_ASSERT_VALUES_EQUAL(lines.size(), 1); + ui64 txId = 100; + + TString database = "/MyRoot"; + TString user = "user1"; + TString password = "password1"; + TString newPassword = "password2"; + TString hash = R"( + { + "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=", + "salt": "U+tzBtgo06EBQCjlARA6Jg==", + "type": "argon2id" + } + )"; + + auto check = [&](const TString& operation, const TVector& details = {}) { + auto render = [](const TVector& list) { + auto result = TStringBuilder(); + result << "[" << JoinStrings(list.begin(), list.end(), ", ") << "]"; + return result; + }; + + auto last = FindAuditLine(lines, Sprintf("tx_id=%u", txId)); + + UNIT_ASSERT_STRING_CONTAINS(last, Sprintf("operation=%s", operation.c_str())); + + if (!details.empty()) { + UNIT_ASSERT_STRING_CONTAINS(last, Sprintf("login_user_change=%s", render(details).c_str())); + } + + UNIT_ASSERT_STRING_CONTAINS(last, "component=schemeshard"); + UNIT_ASSERT_STRING_CONTAINS(last, Sprintf("database=%s", database.c_str())); + UNIT_ASSERT_STRING_CONTAINS(last, "status=SUCCESS"); + UNIT_ASSERT_STRING_CONTAINS(last, "detailed_status=StatusSuccess"); + UNIT_ASSERT_STRING_CONTAINS(last, "login_user_level=admin"); + UNIT_ASSERT_STRING_CONTAINS(last, Sprintf("login_user=%s", user.c_str())); + }; + + CreateAlterLoginCreateUser(runtime, ++txId, database, user, password); + { + UNIT_ASSERT_VALUES_EQUAL(lines.size(), 2); + check("CREATE USER"); + } + + ChangePasswordUser(runtime, ++txId, database, user, newPassword); + { + UNIT_ASSERT_VALUES_EQUAL(lines.size(), 3); + check("MODIFY USER", {"password"}); + } + + ChangeIsEnabledUser(runtime, ++txId, database, user, false); + { + UNIT_ASSERT_VALUES_EQUAL(lines.size(), 4); + check("MODIFY USER", {"blocking"}); + } + + ChangeIsEnabledUser(runtime, ++txId, database, user, true); + { + UNIT_ASSERT_VALUES_EQUAL(lines.size(), 5); + check("MODIFY USER", {"unblocking"}); + } + + ChangePasswordHashUser(runtime, ++txId, database, user, hash); + { + UNIT_ASSERT_VALUES_EQUAL(lines.size(), 6); + check("MODIFY USER", {"password"}); + } + + ModifyUser(runtime, ++txId, database, [user, password, isEnabled = false](auto* alterUser) { + alterUser->SetUser(std::move(user)); + alterUser->SetCanLogin(isEnabled); + alterUser->SetPassword(std::move(password)); + }); + { + UNIT_ASSERT_VALUES_EQUAL(lines.size(), 7); + check("MODIFY USER", {"password", "blocking"}); + } + } } diff --git a/ydb/core/tx/schemeshard/ut_olap/ut_olap.cpp b/ydb/core/tx/schemeshard/ut_olap/ut_olap.cpp index 45b18aac2f7b..8420e3f96589 100644 --- a/ydb/core/tx/schemeshard/ut_olap/ut_olap.cpp +++ b/ydb/core/tx/schemeshard/ut_olap/ut_olap.cpp @@ -889,12 +889,12 @@ Y_UNIT_TEST_SUITE(TOlap) { ui64 pathId = 0; ui64 shardId = 0; - ui64 planStep = 0; + NTxUT::TPlanStep planStep; auto checkFn = [&](const NKikimrScheme::TEvDescribeSchemeResult& record) { auto& self = record.GetPathDescription().GetSelf(); pathId = self.GetPathId(); txId = self.GetCreateTxId() + 1; - planStep = self.GetCreateStep(); + planStep = NTxUT::TPlanStep{self.GetCreateStep()}; auto& sharding = record.GetPathDescription().GetColumnTableDescription().GetSharding(); UNIT_ASSERT_VALUES_EQUAL(sharding.ColumnShardsSize(), 1); shardId = sharding.GetColumnShards()[0]; @@ -904,7 +904,7 @@ Y_UNIT_TEST_SUITE(TOlap) { TestLsPathId(runtime, 3, checkFn); UNIT_ASSERT(shardId); UNIT_ASSERT(pathId); - UNIT_ASSERT(planStep); + UNIT_ASSERT(planStep.Val()); { auto description = DescribePrivatePath(runtime, TTestTxConfig::SchemeShard, "/MyRoot/OlapStore/ColumnTable", true, true); Cerr << description.DebugString() << Endl; @@ -929,11 +929,11 @@ Y_UNIT_TEST_SUITE(TOlap) { std::vector writeIds; ++txId; NTxUT::WriteData(runtime, sender, shardId, ++writeId, pathId, data, defaultYdbSchema, &writeIds, NEvWrite::EModificationType::Upsert, txId); - NTxUT::ProposeCommit(runtime, sender, shardId, txId, writeIds, txId); + planStep = NTxUT::ProposeCommit(runtime, sender, shardId, txId, writeIds, txId); txIds.insert(txId); } - NTxUT::PlanCommit(runtime, sender, shardId, ++planStep, txIds); + NTxUT::PlanCommit(runtime, sender, shardId, planStep, txIds); // emulate timeout runtime.UpdateCurrentTime(TInstant::Now()); @@ -942,8 +942,8 @@ Y_UNIT_TEST_SUITE(TOlap) { std::vector writeIds; ++txId; NTxUT::WriteData(runtime, sender, shardId, ++writeId, pathId, data, defaultYdbSchema, &writeIds, NEvWrite::EModificationType::Upsert, txId); - NTxUT::ProposeCommit(runtime, sender, shardId, txId, writeIds, txId); - NTxUT::PlanCommit(runtime, sender, shardId, ++planStep, { txId }); + planStep = NTxUT::ProposeCommit(runtime, sender, shardId, txId, writeIds, txId); + NTxUT::PlanCommit(runtime, sender, shardId, planStep, { txId }); } csController->WaitIndexation(TDuration::Seconds(5)); { @@ -1068,12 +1068,12 @@ Y_UNIT_TEST_SUITE(TOlap) { ui64 pathId = 0; ui64 shardId = 0; - ui64 planStep = 0; + NTxUT::TPlanStep planStep; auto checkFn = [&](const NKikimrScheme::TEvDescribeSchemeResult& record) { auto& self = record.GetPathDescription().GetSelf(); pathId = self.GetPathId(); txId = self.GetCreateTxId() + 1; - planStep = self.GetCreateStep(); + planStep = NTxUT::TPlanStep{self.GetCreateStep()}; auto& sharding = record.GetPathDescription().GetColumnTableDescription().GetSharding(); UNIT_ASSERT_VALUES_EQUAL(sharding.ColumnShardsSize(), 1); shardId = sharding.GetColumnShards()[0]; @@ -1083,7 +1083,7 @@ Y_UNIT_TEST_SUITE(TOlap) { TestLsPathId(runtime, 4, checkFn); UNIT_ASSERT(shardId); UNIT_ASSERT(pathId); - UNIT_ASSERT(planStep); + UNIT_ASSERT(planStep.Val()); { auto description = DescribePrivatePath(runtime, TTestTxConfig::SchemeShard, "/MyRoot/SomeDatabase/OlapStore/ColumnTable", true, true); Cerr << description.DebugString() << Endl; @@ -1108,11 +1108,11 @@ Y_UNIT_TEST_SUITE(TOlap) { std::vector writeIds; ++txId; NTxUT::WriteData(runtime, sender, shardId, ++writeId, pathId, data, defaultYdbSchema, &writeIds, NEvWrite::EModificationType::Upsert, txId); - NTxUT::ProposeCommit(runtime, sender, shardId, txId, writeIds, txId); + planStep = NTxUT::ProposeCommit(runtime, sender, shardId, txId, writeIds, txId); txIds.insert(txId); } - NTxUT::PlanCommit(runtime, sender, shardId, ++planStep, txIds); + NTxUT::PlanCommit(runtime, sender, shardId, planStep, txIds); WaitTableStats(runtime, shardId); CheckQuotaExceedance(runtime, TTestTxConfig::SchemeShard, "/MyRoot/SomeDatabase", true, DEBUG_HINT); @@ -1157,9 +1157,9 @@ Y_UNIT_TEST_SUITE(TOlap) { ++txId; bool delResult = NTxUT::WriteData(runtime, sender, shardId, ++writeId, pathId, data, defaultYdbSchema, &writeIds, NEvWrite::EModificationType::Delete, txId); Y_UNUSED(delResult); - NTxUT::ProposeCommit(runtime, sender, shardId, txId, writeIds, txId); + planStep = NTxUT::ProposeCommit(runtime, sender, shardId, txId, writeIds, txId); txIds.insert(txId); - NTxUT::PlanCommit(runtime, sender, shardId, ++planStep, txIds); + NTxUT::PlanCommit(runtime, sender, shardId, planStep, txIds); csController->EnableBackground(NKikimr::NYDBTest::ICSController::EBackground::Compaction); csController->WaitCompactions(TDuration::Seconds(60)); diff --git a/ydb/core/tx/sequenceproxy/public/events.h b/ydb/core/tx/sequenceproxy/public/events.h index a046f1b019c4..aa63f48c8c0a 100644 --- a/ydb/core/tx/sequenceproxy/public/events.h +++ b/ydb/core/tx/sequenceproxy/public/events.h @@ -21,6 +21,8 @@ namespace NSequenceProxy { EvNextValResult, EvSetVal, EvSetValResult, + EvGetSequence, + EvGetSequenceResult, EvEnd, }; @@ -70,6 +72,60 @@ namespace NSequenceProxy { , Value(value) { } }; + + struct TEvGetSequence : public TEventLocal { + TString Database; + TPathId PathId; + TIntrusivePtr UserToken; + + explicit TEvGetSequence(const TPathId& pathId) + : PathId(pathId) + { } + + TEvGetSequence(const TString& database, const TPathId& pathId) + : Database(database) + , PathId(pathId) + { } + }; + + struct TEvGetSequenceResult : public TEventLocal { + Ydb::StatusIds::StatusCode Status; + NYql::TIssues Issues; + TPathId PathId; + + i64 MinValue; + i64 MaxValue; + i64 StartValue; + i64 NextValue; + bool NextUsed; + ui64 Cache; + i64 Increment; + bool Cycle; + + TEvGetSequenceResult(const TPathId& pathId) + : Status(Ydb::StatusIds::SUCCESS) + , PathId(pathId) + { } + + TEvGetSequenceResult(Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues) + : Status(status) + , Issues(issues) + { } + + explicit TEvGetSequenceResult(const TEvGetSequenceResult& ev) + : Status(ev.Status) + , Issues(ev.Issues) + , PathId(ev.PathId) + , MinValue(ev.MinValue) + , MaxValue(ev.MaxValue) + , StartValue(ev.StartValue) + , NextValue(ev.NextValue) + , NextUsed(ev.NextUsed) + , Cache(ev.Cache) + , Increment(ev.Increment) + , Cycle(ev.Cycle) + { } + }; }; } // namespace NSequenceProxy diff --git a/ydb/core/tx/sequenceproxy/sequenceproxy_get_sequence.cpp b/ydb/core/tx/sequenceproxy/sequenceproxy_get_sequence.cpp new file mode 100644 index 000000000000..0c268651ac8c --- /dev/null +++ b/ydb/core/tx/sequenceproxy/sequenceproxy_get_sequence.cpp @@ -0,0 +1,133 @@ +#include "sequenceproxy_impl.h" + +#include +#include +#include +#include + +#include +#include + +#define TXLOG_LOG(priority, stream) \ + LOG_LOG_S(*TlsActivationContext, priority, NKikimrServices::SEQUENCEPROXY, LogPrefix << stream) +#define TXLOG_DEBUG(stream) TXLOG_LOG(NActors::NLog::PRI_DEBUG, stream) +#define TXLOG_NOTICE(stream) TXLOG_LOG(NActors::NLog::PRI_NOTICE, stream) +#define TXLOG_ERROR(stream) TXLOG_LOG(NActors::NLog::PRI_ERROR, stream) + +namespace NKikimr { +namespace NSequenceProxy { + + using namespace NKikimr::NSequenceShard; + + class TSequenceProxy::TGetSequenceActor : public TActorBootstrapped { + public: + TGetSequenceActor(const TActorId& owner, ui64 cookie, ui64 tabletId, const TPathId& pathId) + : Owner(owner) + , Cookie(cookie) + , PipeCache(MakePipePerNodeCacheID(true)) + , TabletId(tabletId) + , PathId(pathId) + { } + + void Bootstrap() { + Send(PipeCache, + new TEvPipeCache::TEvForward( + new TEvSequenceShard::TEvGetSequence(PathId), + TabletId, + true), + IEventHandle::FlagTrackDelivery); + Become(&TThis::StateGetSequence); + } + + void PassAway() override { + Send(PipeCache, new TEvPipeCache::TEvUnlink(0)); + TActorBootstrapped::PassAway(); + } + + void ReplyAndDie(Ydb::StatusIds::StatusCode status, NKikimrIssues::TIssuesIds::EIssueCode code, const TString& message) { + NYql::TIssueManager issueManager; + issueManager.RaiseIssue(MakeIssue(code, message)); + auto res = MakeHolder(status, issueManager.GetIssues()); + Send(Owner, res.Release(), 0, Cookie); + PassAway(); + } + + private: + STFUNC(StateGetSequence) { + switch (ev->GetTypeRewrite()) { + hFunc(TEvSequenceShard::TEvGetSequenceResult, Handle); + hFunc(TEvPipeCache::TEvDeliveryProblem, Handle); + hFunc(TEvents::TEvUndelivered, Handle); + } + } + + void Handle(TEvSequenceShard::TEvGetSequenceResult::TPtr& ev) { + auto* msg = ev->Get(); + switch (msg->Record.GetStatus()) { + case NKikimrTxSequenceShard::TEvGetSequenceResult::SUCCESS: + break; + + case NKikimrTxSequenceShard::TEvGetSequenceResult::SEQUENCE_NOT_FOUND: + return ReplyAndDie(Ydb::StatusIds::SCHEME_ERROR, + NKikimrIssues::TIssuesIds::PATH_NOT_EXIST, + "The specified sequence no longer exists"); + + case NKikimrTxSequenceShard::TEvGetSequenceResult::SEQUENCE_MOVED: + // Switch to a different tablet and retry transparently + TabletId = msg->Record.GetMovedTo(); + return Bootstrap(); + + default: + return ReplyAndDie(Ydb::StatusIds::INTERNAL_ERROR, + NKikimrIssues::TIssuesIds::GENERIC_TXPROXY_ERROR, + TStringBuilder() + << "Unexpected error from sequence shard " << TabletId); + } + + auto res = MakeHolder(PathId); + res->MinValue = msg->Record.GetMinValue(); + res->MaxValue = msg->Record.GetMaxValue(); + res->StartValue = msg->Record.GetStartValue(); + res->NextValue = msg->Record.GetNextValue(); + res->NextUsed = msg->Record.GetNextUsed(); + res->Cache = msg->Record.GetCache(); + res->Increment = msg->Record.GetIncrement(); + res->Cycle = msg->Record.GetCycle(); + Send(Owner, res.Release(), 0, Cookie); + PassAway(); + } + + void Handle(TEvPipeCache::TEvDeliveryProblem::TPtr& ev) { + ui64 tabletId = ev->Get()->TabletId; + if (tabletId == TabletId) { + const TString error = TStringBuilder() + << "sequence shard " << tabletId << " is unavailable"; + return ReplyAndDie(Ydb::StatusIds::UNAVAILABLE, NKikimrIssues::TIssuesIds::SHARD_NOT_AVAILABLE, error); + } + } + + void Handle(TEvents::TEvUndelivered::TPtr&) { + const TString error = "Pipe cache may not be configured correctly"; + return ReplyAndDie(Ydb::StatusIds::UNAVAILABLE, NKikimrIssues::TIssuesIds::GENERIC_TXPROXY_ERROR, error); + } + + private: + const TActorId Owner; + const ui64 Cookie; + const TActorId PipeCache; + ui64 TabletId; + TPathId PathId; + NYql::TIssueManager IssueManager; + }; + + ui64 TSequenceProxy::StartGetSequence(ui64 tabletId, const TString& database, const TPathId& pathId) { + ui64 cookie = ++LastCookie; + auto& info = GetSequenceInFlight[cookie]; + info.Database = database; + info.PathId = pathId; + Register(new TGetSequenceActor(SelfId(), cookie, tabletId, pathId)); + return cookie; + } + +} // namespace NSequenceProxy +} // namespace NKikimr diff --git a/ydb/core/tx/sequenceproxy/sequenceproxy_impl.cpp b/ydb/core/tx/sequenceproxy/sequenceproxy_impl.cpp index 6bc5a0997e23..233046dd2472 100644 --- a/ydb/core/tx/sequenceproxy/sequenceproxy_impl.cpp +++ b/ydb/core/tx/sequenceproxy/sequenceproxy_impl.cpp @@ -53,6 +53,16 @@ namespace NSequenceProxy { msg->Path); } + void TSequenceProxy::Handle(TEvSequenceProxy::TEvGetSequence::TPtr& ev) { + auto* msg = ev->Get(); + TGetSequenceRequestInfo request; + request.Sender = ev->Sender; + request.Cookie = ev->Cookie; + request.UserToken = std::move(msg->UserToken); + request.StartAt = AppData()->MonotonicTimeProvider->Now(); + DoGetSequence(std::move(request), msg->Database, msg->PathId); + } + void TSequenceProxy::Reply(const TNextValRequestInfo& request, Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues) { Counters->ResponseCount->Inc(); auto milliseconds = (AppData()->MonotonicTimeProvider->Now() - request.StartAt).MilliSeconds(); @@ -68,6 +78,17 @@ namespace NSequenceProxy { Send(request.Sender, new TEvSequenceProxy::TEvNextValResult(pathId, value), 0, request.Cookie); } + void TSequenceProxy::Reply(const TGetSequenceRequestInfo& request, Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues) { + Counters->ResponseCount->Inc(); + Counters->ErrorsCount->Inc(); + Send(request.Sender, new TEvSequenceProxy::TEvGetSequenceResult(status, issues), 0, request.Cookie); + } + + void TSequenceProxy::Reply(const TGetSequenceRequestInfo& request, const TEvSequenceProxy::TEvGetSequenceResult& ev) { + Counters->ResponseCount->Inc(); + Send(request.Sender, new TEvSequenceProxy::TEvGetSequenceResult(ev), 0, request.Cookie); + } + void TSequenceProxy::MaybeStartResolve(const TString& database, const TString& path, TSequenceByName& info) { if (!info.ResolveInProgress && !info.NewNextValResolve.empty()) { info.PendingNextValResolve = std::move(info.NewNextValResolve); @@ -111,6 +132,28 @@ namespace NSequenceProxy { OnChanged(database, pathId, info); } + void TSequenceProxy::DoGetSequence(TGetSequenceRequestInfo&& request, const TString& database, const TPathId& pathId) { + Counters->RequestCount->Inc(); + + auto& info = Databases[database].SequenceByPathId[pathId]; + if (!info.ResolveInProgress) { + StartResolve(database, pathId, !info.SequenceInfo); + info.ResolveInProgress = true; + } + if (!info.SequenceInfo) { + info.PendingGetSequenceResolve.emplace_back(std::move(request)); + return; + } + + if (DoMaybeReplyUnauthorized(request, pathId, info)) { + return; + } + + info.PendingGetSequence.emplace_back(std::move(request)); + + OnChanged(database, pathId, info); + } + void TSequenceProxy::OnResolveError(const TString& database, const TString& path, Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues) { auto& info = Databases[database].SequenceByName[path]; Y_ABORT_UNLESS(info.ResolveInProgress); @@ -139,7 +182,9 @@ namespace NSequenceProxy { auto& infoById = Databases[database].SequenceByPathId[pathId]; infoById.SequenceInfo = result.SequenceInfo; infoById.SecurityObject = result.SecurityObject; - OnResolved(database, pathId, infoById, info.PendingNextValResolve); + + TList resolvedGetSequence; + OnResolved(database, pathId, infoById, info.PendingNextValResolve, resolvedGetSequence); MaybeStartResolve(database, path, info); } @@ -153,6 +198,11 @@ namespace NSequenceProxy { Reply(info.PendingNextValResolve.front(), status, issues); info.PendingNextValResolve.pop_front(); } + + while (!info.PendingGetSequenceResolve.empty()) { + Reply(info.PendingGetSequenceResolve.front(), status, issues); + info.PendingGetSequenceResolve.pop_front(); + } } void TSequenceProxy::OnResolveResult(const TString& database, const TPathId& pathId, TResolveResult&& result) { @@ -163,20 +213,29 @@ namespace NSequenceProxy { Y_ABORT_UNLESS(result.SequenceInfo); info.SequenceInfo = result.SequenceInfo; info.SecurityObject = result.SecurityObject; - OnResolved(database, pathId, info, info.PendingNextValResolve); + OnResolved(database, pathId, info, info.PendingNextValResolve, info.PendingGetSequenceResolve); } - void TSequenceProxy::OnResolved(const TString& database, const TPathId& pathId, TSequenceByPathId& info, TList& resolved) { + void TSequenceProxy::OnResolved(const TString& database, const TPathId& pathId, TSequenceByPathId& info, + TList& resolvedNextVal, TList& resolvedGetSequence) { info.LastKnownTabletId = info.SequenceInfo->Description.GetSequenceShard(); info.DefaultCacheSize = Max(info.SequenceInfo->Description.GetCache(), ui64(1)); - while (!resolved.empty()) { - auto& request = resolved.front(); + while (!resolvedNextVal.empty()) { + auto& request = resolvedNextVal.front(); if (!DoMaybeReplyUnauthorized(request, pathId, info)) { info.PendingNextVal.emplace_back(std::move(request)); ++info.TotalRequested; } - resolved.pop_front(); + resolvedNextVal.pop_front(); + } + + while (!resolvedGetSequence.empty()) { + auto& request = resolvedGetSequence.front(); + if (!DoMaybeReplyUnauthorized(request, pathId, info)) { + info.PendingGetSequence.emplace_back(std::move(request)); + } + resolvedGetSequence.pop_front(); } OnChanged(database, pathId, info); @@ -215,6 +274,34 @@ namespace NSequenceProxy { OnChanged(database, pathId, info); } + void TSequenceProxy::Handle(TEvSequenceProxy::TEvGetSequenceResult::TPtr& ev) { + auto it = GetSequenceInFlight.find(ev->Cookie); + Y_ABORT_UNLESS(it != GetSequenceInFlight.end()); + auto database = it->second.Database; + auto pathId = it->second.PathId; + GetSequenceInFlight.erase(it); + + auto& info = Databases[database].SequenceByPathId[pathId]; + Y_ABORT_UNLESS(info.GetSequenceInProgress); + info.GetSequenceInProgress = false; + + auto* msg = ev->Get(); + + if (msg->Status == Ydb::StatusIds::SUCCESS) { + while (!info.PendingGetSequence.empty()) { + Reply(info.PendingGetSequence.front(), *msg); + info.PendingGetSequence.pop_front(); + } + } else { + while (!info.PendingGetSequence.empty()) { + Reply(info.PendingGetSequence.front(), msg->Status, msg->Issues); + info.PendingGetSequence.pop_front(); + } + } + + OnChanged(database, pathId, info); + } + void TSequenceProxy::OnChanged(const TString& database, const TPathId& pathId, TSequenceByPathId& info) { while (info.TotalCached > 0 && !info.PendingNextVal.empty()) { const auto& request = info.PendingNextVal.front(); @@ -230,9 +317,15 @@ namespace NSequenceProxy { info.AllocateInProgress = true; info.TotalAllocating += cache; } + + if (!info.PendingGetSequence.empty() && !info.GetSequenceInProgress) { + StartGetSequence(info.LastKnownTabletId, database, pathId); + info.GetSequenceInProgress = true; + } } - bool TSequenceProxy::DoMaybeReplyUnauthorized(const TNextValRequestInfo& request, const TPathId& pathId, TSequenceByPathId& info) { + template + bool TSequenceProxy::DoMaybeReplyUnauthorized(const TRequestInfo& request, const TPathId& pathId, TSequenceByPathId& info) { if (request.UserToken && info.SecurityObject) { ui32 access = NACLib::EAccessRights::SelectRow; if (!info.SecurityObject->CheckAccess(access, *request.UserToken)) { diff --git a/ydb/core/tx/sequenceproxy/sequenceproxy_impl.h b/ydb/core/tx/sequenceproxy/sequenceproxy_impl.h index 6868a82d2b28..f9f7d3074c05 100644 --- a/ydb/core/tx/sequenceproxy/sequenceproxy_impl.h +++ b/ydb/core/tx/sequenceproxy/sequenceproxy_impl.h @@ -42,13 +42,14 @@ namespace NSequenceProxy { private: class TAllocateActor; + class TGetSequenceActor; using TSequenceInfo = NSchemeCache::TSchemeCacheNavigate::TSequenceInfo; struct TEvPrivate { enum EEv { EvBegin = EventSpaceBegin(TKikimrEvents::ES_PRIVATE), - EvAllocateResult, + EvAllocateResult }; struct TEvAllocateResult : public TEventLocal { @@ -76,6 +77,13 @@ namespace NSequenceProxy { TMonotonic StartAt; }; + struct TGetSequenceRequestInfo { + TActorId Sender; + ui64 Cookie; + TIntrusivePtr UserToken; + TMonotonic StartAt; + }; + struct TCachedAllocation { i64 Start, Increment; ui64 Count; @@ -95,10 +103,13 @@ namespace NSequenceProxy { TList CachedAllocations; TList PendingNextValResolve; TList PendingNextVal; + TList PendingGetSequenceResolve; + TList PendingGetSequence; ui64 LastKnownTabletId = 0; ui64 DefaultCacheSize = 0; bool ResolveInProgress = false; bool AllocateInProgress = false; + bool GetSequenceInProgress = false; ui64 TotalCached = 0; ui64 TotalRequested = 0; ui64 TotalAllocating = 0; @@ -128,11 +139,18 @@ namespace NSequenceProxy { TPathId PathId; }; + struct TGetSequenceInFlight { + TString Database; + TPathId PathId; + }; + private: STFUNC(StateWork) { switch (ev->GetTypeRewrite()) { sFunc(TEvents::TEvPoison, HandlePoison); hFunc(TEvSequenceProxy::TEvNextVal, Handle); + hFunc(TEvSequenceProxy::TEvGetSequence, Handle); + hFunc(TEvSequenceProxy::TEvGetSequenceResult, Handle); hFunc(TEvPrivate::TEvAllocateResult, Handle); hFunc(TEvTxProxySchemeCache::TEvNavigateKeySetResult, Handle); } @@ -140,23 +158,32 @@ namespace NSequenceProxy { void HandlePoison(); void Handle(TEvSequenceProxy::TEvNextVal::TPtr& ev); + void Handle(TEvSequenceProxy::TEvGetSequence::TPtr& ev); void Handle(TEvPrivate::TEvAllocateResult::TPtr& ev); + void Handle(TEvSequenceProxy::TEvGetSequenceResult::TPtr& ev); void Handle(TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev); void Reply(const TNextValRequestInfo& request, Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues); void Reply(const TNextValRequestInfo& request, const TPathId& pathId, i64 value); + void Reply(const TGetSequenceRequestInfo& request, Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues); + void Reply(const TGetSequenceRequestInfo& request, const TEvSequenceProxy::TEvGetSequenceResult& ev); ui64 StartResolve(const TString& database, const std::variant& path, bool syncVersion); ui64 StartAllocate(ui64 tabletId, const TString& database, const TPathId& pathId, ui64 cache); + ui64 StartGetSequence(ui64 tabletId, const TString& database, const TPathId& pathId); void MaybeStartResolve(const TString& database, const TString& path, TSequenceByName& info); void DoNextVal(TNextValRequestInfo&& request, const TString& database, const TString& path); void DoNextVal(TNextValRequestInfo&& request, const TString& database, const TPathId& pathId, bool needRefresh = true); + void DoGetSequence(TGetSequenceRequestInfo&& request, const TString& database, const TPathId& pathId); void OnResolveError(const TString& database, const TString& path, Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues); void OnResolveError(const TString& database, const TPathId& pathId, Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues); void OnResolveResult(const TString& database, const TString& path, TResolveResult&& result); void OnResolveResult(const TString& database, const TPathId& pathId, TResolveResult&& result); - void OnResolved(const TString& database, const TPathId& pathId, TSequenceByPathId& info, TList& resolved); + void OnResolved(const TString& database, const TPathId& pathId, TSequenceByPathId& info, TList& resolvedNextVal, TList& resolvedGetSequence); void OnChanged(const TString& database, const TPathId& pathId, TSequenceByPathId& info); - bool DoMaybeReplyUnauthorized(const TNextValRequestInfo& request, const TPathId& pathId, TSequenceByPathId& info); + + template + bool DoMaybeReplyUnauthorized(const TRequestInfo& request, const TPathId& pathId, TSequenceByPathId& info); + bool DoReplyFromCache(const TNextValRequestInfo& request, const TPathId& pathId, TSequenceByPathId& info); private: @@ -165,6 +192,7 @@ namespace NSequenceProxy { THashMap Databases; THashMap ResolveInFlight; THashMap AllocateInFlight; + THashMap GetSequenceInFlight; ui64 LastCookie = 0; TIntrusivePtr Counters; }; diff --git a/ydb/core/tx/sequenceproxy/sequenceproxy_ut.cpp b/ydb/core/tx/sequenceproxy/sequenceproxy_ut.cpp index 50931d8935cf..0400d38032dd 100644 --- a/ydb/core/tx/sequenceproxy/sequenceproxy_ut.cpp +++ b/ydb/core/tx/sequenceproxy/sequenceproxy_ut.cpp @@ -126,11 +126,31 @@ Y_UNIT_TEST_SUITE(SequenceProxy) { runtime.GrabEdgeEventRethrow(edge); } + TPathId DescribeSequence(TTestActorRuntime& runtime, const TActorId& sender, const TString& path) { + TAutoPtr handle; + + auto request = MakeHolder(); + request->Record.MutableDescribePath()->SetPath(path); + runtime.Send(new IEventHandle(MakeTxProxyID(), sender, request.Release())); + auto reply = runtime.GrabEdgeEventRethrow(handle); + + UNIT_ASSERT(reply->GetRecord().GetPathDescription().HasSequenceDescription()); + + const auto& sequenceDescription = reply->GetRecord().GetPathDescription().GetSequenceDescription(); + + return TPathId::FromProto(sequenceDescription.GetPathId()); + } + void SendNextValRequest(TTestActorRuntime& runtime, const TActorId& sender, const TString& path) { auto request = MakeHolder(path); runtime.Send(new IEventHandle(MakeSequenceProxyServiceID(), sender, request.Release())); } + void SendGetSequenceRequest(TTestActorRuntime& runtime, const TActorId& sender, const TPathId& pathId) { + auto request = MakeHolder(pathId); + runtime.Send(new IEventHandle(MakeSequenceProxyServiceID(), sender, request.Release())); + } + i64 WaitNextValResult(TTestActorRuntime& runtime, const TActorId& sender, Ydb::StatusIds::StatusCode expectedStatus = Ydb::StatusIds::SUCCESS) { auto ev = runtime.GrabEdgeEventRethrow(sender); auto* msg = ev->Get(); @@ -138,33 +158,75 @@ Y_UNIT_TEST_SUITE(SequenceProxy) { return msg->Status == Ydb::StatusIds::SUCCESS ? msg->Value : 0; } + i64 WaitGetSequenceResult(TTestActorRuntime& runtime, const TActorId& sender, Ydb::StatusIds::StatusCode expectedStatus = Ydb::StatusIds::SUCCESS) { + auto ev = runtime.GrabEdgeEventRethrow(sender); + auto* msg = ev->Get(); + if (msg->Status != Ydb::StatusIds::SUCCESS) { + return 0; + } + UNIT_ASSERT_VALUES_EQUAL(msg->Status, expectedStatus); + UNIT_ASSERT_VALUES_EQUAL(msg->MinValue, 1); + UNIT_ASSERT_VALUES_EQUAL(msg->MaxValue, 9223372036854775807LL); + UNIT_ASSERT_VALUES_EQUAL(msg->StartValue, 1); + UNIT_ASSERT_VALUES_EQUAL(msg->Cache, 1); + UNIT_ASSERT_VALUES_EQUAL(msg->Increment, 1); + UNIT_ASSERT_VALUES_EQUAL(msg->Cycle, false); + UNIT_ASSERT_VALUES_EQUAL(msg->NextUsed, false); + return msg->NextValue; + } + i64 DoNextVal(TTestActorRuntime& runtime, const TString& path, Ydb::StatusIds::StatusCode expectedStatus = Ydb::StatusIds::SUCCESS) { auto sender = runtime.AllocateEdgeActor(0); SendNextValRequest(runtime, sender, path); return WaitNextValResult(runtime, sender, expectedStatus); } + i64 DoGetSequence(TTestActorRuntime& runtime, const TString& path, Ydb::StatusIds::StatusCode expectedStatus = Ydb::StatusIds::SUCCESS) { + auto sender = runtime.AllocateEdgeActor(0); + auto pathId = DescribeSequence(runtime, sender, path); + SendGetSequenceRequest(runtime, sender, pathId); + return WaitGetSequenceResult(runtime, sender, expectedStatus); + } + } // namespace Y_UNIT_TEST(Basics) { TTenantTestRuntime runtime(MakeTenantTestConfig(false)); StartSchemeCache(runtime); + auto sender = runtime.AllocateEdgeActor(0); CreateSequence(runtime, "/dc-1", R"( Name: "seq" )"); - i64 value = DoNextVal(runtime, "/dc-1/seq"); + i64 value = DoGetSequence(runtime, "/dc-1/seq"); + UNIT_ASSERT_VALUES_EQUAL(value, 1); + + value = DoNextVal(runtime, "/dc-1/seq"); UNIT_ASSERT_VALUES_EQUAL(value, 1); + value = DoGetSequence(runtime, "/dc-1/seq"); + UNIT_ASSERT_VALUES_EQUAL(value, 2); + + value = DoGetSequence(runtime, "/dc-1/seq"); + UNIT_ASSERT_VALUES_EQUAL(value, 2); + + DoNextVal(runtime, "/dc-1/noseq", Ydb::StatusIds::SCHEME_ERROR); + SendGetSequenceRequest(runtime, sender, TPathId()); + WaitGetSequenceResult(runtime, sender, Ydb::StatusIds::SCHEME_ERROR); + ui64 allocateEvents = 0; + ui64 getSequenceEvents = 0; auto observerFunc = [&](auto& ev) { switch (ev->GetTypeRewrite()) { case TEvSequenceShard::TEvAllocateSequence::EventType: ++allocateEvents; break; + case TEvSequenceShard::TEvGetSequence::EventType: + ++getSequenceEvents; + break; default: break; @@ -174,16 +236,36 @@ Y_UNIT_TEST_SUITE(SequenceProxy) { }; auto prevObserver = runtime.SetObserverFunc(observerFunc); - auto sender = runtime.AllocateEdgeActor(0); + auto pathId = DescribeSequence(runtime, sender, "/dc-1/seq"); + for (int i = 0; i < 7; ++i) { SendNextValRequest(runtime, sender, "/dc-1/seq"); } for (int i = 0; i < 7; ++i) { - i64 value = WaitNextValResult(runtime, sender); + value = WaitNextValResult(runtime, sender); UNIT_ASSERT_VALUES_EQUAL(value, 2 + i); } + UNIT_ASSERT_C(allocateEvents < 7, "Too many TEvSequenceShard::TEvAllocateSequence events: " << allocateEvents); + + for (int i = 0; i < 7; ++i) { + SendGetSequenceRequest(runtime, sender, pathId); + } + for (int i = 0; i < 7; ++i) { + value = WaitGetSequenceResult(runtime, sender); + UNIT_ASSERT_VALUES_EQUAL(value, 9); + } + UNIT_ASSERT_C(getSequenceEvents < 7, "Too many TEvSequenceShard::TEvGetSequence events: " << getSequenceEvents); + ui64 prevGetSequenceEvents = getSequenceEvents; + + for (int i = 0; i < 7; ++i) { + SendNextValRequest(runtime, sender, "/dc-1/seq"); + SendGetSequenceRequest(runtime, sender, pathId); + } + for (int i = 0; i < 7; ++i) { + WaitGetSequenceResult(runtime, sender); + } - UNIT_ASSERT_C(allocateEvents < 7, "Too many TEvAllocateSequence events: " << allocateEvents); + UNIT_ASSERT_C(getSequenceEvents < 7 + prevGetSequenceEvents, "Too many TEvSequenceShard::TEvGetSequence events: " << getSequenceEvents - prevGetSequenceEvents); } Y_UNIT_TEST(DropRecreate) { diff --git a/ydb/core/tx/sequenceproxy/ya.make b/ydb/core/tx/sequenceproxy/ya.make index 4b904b7427be..02988d04bc17 100644 --- a/ydb/core/tx/sequenceproxy/ya.make +++ b/ydb/core/tx/sequenceproxy/ya.make @@ -10,6 +10,7 @@ PEERDIR( SRCS( sequenceproxy.cpp sequenceproxy_allocate.cpp + sequenceproxy_get_sequence.cpp sequenceproxy_impl.cpp sequenceproxy_resolve.cpp ) diff --git a/ydb/core/tx/tx_proxy/rpc_long_tx.cpp b/ydb/core/tx/tx_proxy/rpc_long_tx.cpp index 435dd536bec6..24f0d1a8bae6 100644 --- a/ydb/core/tx/tx_proxy/rpc_long_tx.cpp +++ b/ydb/core/tx/tx_proxy/rpc_long_tx.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include diff --git a/ydb/core/tx/tx_proxy/upload_rows_common_impl.h b/ydb/core/tx/tx_proxy/upload_rows_common_impl.h index 6c845f0a7183..f4fd56b2f5bb 100644 --- a/ydb/core/tx/tx_proxy/upload_rows_common_impl.h +++ b/ydb/core/tx/tx_proxy/upload_rows_common_impl.h @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include diff --git a/ydb/core/tx/tx_proxy/upload_rows_counters.h b/ydb/core/tx/tx_proxy/upload_rows_counters.h index 4839e76da172..f48292b896c1 100644 --- a/ydb/core/tx/tx_proxy/upload_rows_counters.h +++ b/ydb/core/tx/tx_proxy/upload_rows_counters.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/ydb/core/viewer/json_pipe_req.cpp b/ydb/core/viewer/json_pipe_req.cpp index cbea3eea89b9..4c4d0a27835a 100644 --- a/ydb/core/viewer/json_pipe_req.cpp +++ b/ydb/core/viewer/json_pipe_req.cpp @@ -451,8 +451,16 @@ TViewerPipeClient::TRequestResponse TViewerPi TActorId pipeClient = ConnectTabletPipe(hiveId); auto response = MakeRequestToPipe(pipeClient, request, hiveId); if (response.Span) { - auto hive_id = "#" + ::ToString(hiveId); - response.Span.Attribute("hive_id", hive_id); + response.Span.Attribute("hive_id", TStringBuilder() << '#' << hiveId); + if (request->Record.GetFilterTabletsBySchemeShardId()) { + response.Span.Attribute("schemeshard_id", TStringBuilder() << '#' << request->Record.GetFilterTabletsBySchemeShardId()); + } + if (request->Record.GetFilterTabletsByPathId()) { + response.Span.Attribute("path_id", TStringBuilder() << '#' << request->Record.GetFilterTabletsByPathId()); + } + if (request->Record.HasFilterTabletsByObjectDomain()) { + response.Span.Attribute("object_domain", TStringBuilder() << TSubDomainKey(request->Record.GetFilterTabletsByObjectDomain())); + } } return response; } @@ -737,6 +745,7 @@ THolder TViewerPipeClient::SchemeCacheNaviga ) { THolder request = MakeHolder(); entry.RedirectRequired = false; + entry.ShowPrivatePath = true; entry.Operation = NSchemeCache::TSchemeCacheNavigate::EOp::OpPath; request->ResultSet.emplace_back(std::move(entry)); return request; @@ -763,6 +772,7 @@ TViewerPipeClient::TRequestResponseResultSet.emplace_back(entry); auto response = MakeRequest(MakeSchemeCacheID(), new TEvTxProxySchemeCache::TEvNavigateKeySet(request.Release()), 0 /*flags*/, cookie); @@ -778,6 +788,7 @@ TViewerPipeClient::TRequestResponseResultSet.emplace_back(entry); auto response = MakeRequest(MakeSchemeCacheID(), new TEvTxProxySchemeCache::TEvNavigateKeySet(request.Release()), 0 /*flags*/, cookie); @@ -822,9 +833,10 @@ TViewerPipeClient::TRequestResponse request(new TEvTxUserProxy::TEvNavigate()); request->Record.MutableDescribePath()->SetPath(path); + request->Record.MutableDescribePath()->MutableOptions()->CopyFrom(options); if (Event && !Event->Get()->UserToken.empty()) { request->Record.SetUserToken(Event->Get()->UserToken); } diff --git a/ydb/core/viewer/json_pipe_req.h b/ydb/core/viewer/json_pipe_req.h index 5e185a27f226..bf475ae549fa 100644 --- a/ydb/core/viewer/json_pipe_req.h +++ b/ydb/core/viewer/json_pipe_req.h @@ -318,7 +318,7 @@ class TViewerPipeClient : public TActorBootstrapped { const TString& path, bool showPrivate, ui32 access, ui64 cookie = 0); TRequestResponse MakeRequestViewer(TNodeId nodeId, TEvViewer::TEvViewerRequest* request, ui32 flags = 0); - void RequestTxProxyDescribe(const TString& path); + void RequestTxProxyDescribe(const TString& path, const NKikimrSchemeOp::TDescribeOptions& options = {}); void RequestStateStorageEndpointsLookup(const TString& path); void RequestStateStorageMetadataCacheEndpointsLookup(const TString& path); TRequestResponse MakeRequestStateStorageEndpointsLookup(const TString& path, ui64 cookie = 0); diff --git a/ydb/core/viewer/monitoring/CHANGELOG.md b/ydb/core/viewer/monitoring/CHANGELOG.md new file mode 100644 index 000000000000..f06cf3eac9fa --- /dev/null +++ b/ydb/core/viewer/monitoring/CHANGELOG.md @@ -0,0 +1,3012 @@ +# Changelog + +## [8.22.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.22.0...v8.22.1) (2025-04-15) + + +### Bug Fixes + +* update autorefresh if more that autorefresh in inactive tab passed ([#2140](https://github.com/ydb-platform/ydb-embedded-ui/issues/2140)) ([c5bd2ac](https://github.com/ydb-platform/ydb-embedded-ui/commit/c5bd2ac759ae4729497106b258b20f529a471b7c)) +* useHotkeysPanel hook ([#2151](https://github.com/ydb-platform/ydb-embedded-ui/issues/2151)) ([08b39d1](https://github.com/ydb-platform/ydb-embedded-ui/commit/08b39d11d1d7b5a66993001867c7e4fb6df93fcb)) + +## [8.22.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.21.0...v8.22.0) (2025-04-11) + + +### Features + +* **Tenants:** correct links with relative path in balancer ([#2125](https://github.com/ydb-platform/ydb-embedded-ui/issues/2125)) ([f427375](https://github.com/ydb-platform/ydb-embedded-ui/commit/f42737575b20f3cdf80af98e80f43666443bedd3)) + +## [8.21.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.20.1...v8.21.0) (2025-04-09) + + +### Features + +* **Clusters:** correct links with relative path in balancer ([#2121](https://github.com/ydb-platform/ydb-embedded-ui/issues/2121)) ([4776c0c](https://github.com/ydb-platform/ydb-embedded-ui/commit/4776c0c118df42ef11d6790c8f8348d5dabe937c)) +* design query tab ([#2077](https://github.com/ydb-platform/ydb-embedded-ui/issues/2077)) ([06d243d](https://github.com/ydb-platform/ydb-embedded-ui/commit/06d243dfa5aefdb46001f2d9a78be2218a929869)) +* do not automatically refresh content when browser tab is inactive ([#2122](https://github.com/ydb-platform/ydb-embedded-ui/issues/2122)) ([341c0d8](https://github.com/ydb-platform/ydb-embedded-ui/commit/341c0d8c337a944d582649d8aee1b9f6e34fd757)) +* make keyboard shortcuts help page ([#2116](https://github.com/ydb-platform/ydb-embedded-ui/issues/2116)) ([b401559](https://github.com/ydb-platform/ydb-embedded-ui/commit/b401559355a51f18d14203e146c59af90aad25d6)) + + +### Bug Fixes + +* reuse table schema for select template for current table ([#2127](https://github.com/ydb-platform/ydb-embedded-ui/issues/2127)) ([b577ee5](https://github.com/ydb-platform/ydb-embedded-ui/commit/b577ee5fe60f220d322948a43d17568a19e36596)) +* try no unsaved for templates ([#2117](https://github.com/ydb-platform/ydb-embedded-ui/issues/2117)) ([e7d4a50](https://github.com/ydb-platform/ydb-embedded-ui/commit/e7d4a50f4ebf9f46567d48a9ef56683b9395e8b7)) +* use blue color only for not replicated vdisks ([#2110](https://github.com/ydb-platform/ydb-embedded-ui/issues/2110)) ([2e6051b](https://github.com/ydb-platform/ydb-embedded-ui/commit/2e6051bc4448951945594f0982d6899d338c004a)) + +## [8.20.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.20.0...v8.20.1) (2025-04-04) + + +### Bug Fixes + +* add RealNumberOfCpus to aggregates ([#2095](https://github.com/ydb-platform/ydb-embedded-ui/issues/2095)) ([b0453d5](https://github.com/ydb-platform/ydb-embedded-ui/commit/b0453d56ff19e61a4a0c003249aa89a46586071c)) + +## [8.20.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.19.1...v8.20.0) (2025-04-03) + + +### Features + +* allow pass create and delete DB funcs to UI ([#2087](https://github.com/ydb-platform/ydb-embedded-ui/issues/2087)) ([810f60b](https://github.com/ydb-platform/ydb-embedded-ui/commit/810f60b46ad75ad184c43d61ce4fa65504f29ee2)) + +## [8.19.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.19.0...v8.19.1) (2025-04-03) + + +### Bug Fixes + +* fake commit for release to build ([#2088](https://github.com/ydb-platform/ydb-embedded-ui/issues/2088)) ([3b97fa7](https://github.com/ydb-platform/ydb-embedded-ui/commit/3b97fa77c06a7bfb2a71ed18ebbb8b7e397ffe52)) + +## [8.19.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.18.0...v8.19.0) (2025-04-02) + + +### Features + +* add new popup menu icon ([#2045](https://github.com/ydb-platform/ydb-embedded-ui/issues/2045)) ([21de77f](https://github.com/ydb-platform/ydb-embedded-ui/commit/21de77faad169cb1a2890e480a3b860d8d2ef8aa)) +* add support for RealNumberOfCpus for load average ([#2082](https://github.com/ydb-platform/ydb-embedded-ui/issues/2082)) ([0bad262](https://github.com/ydb-platform/ydb-embedded-ui/commit/0bad262ff3befee4039956f2588bc0a61a22b03c)) + + +### Bug Fixes + +* **PDiskPage:** fix error boundary on failed restart ([#2069](https://github.com/ydb-platform/ydb-embedded-ui/issues/2069)) ([4624845](https://github.com/ydb-platform/ydb-embedded-ui/commit/4624845577d32d8617221892bb9d5e79871315de)) +* **PDiskSpaceDistribution:** use only space severity for slots ([#2070](https://github.com/ydb-platform/ydb-embedded-ui/issues/2070)) ([4ea21a1](https://github.com/ydb-platform/ydb-embedded-ui/commit/4ea21a156f07fb206629a82bfc143394a3ebe8aa)) +* shards table dissapeared ([#2072](https://github.com/ydb-platform/ydb-embedded-ui/issues/2072)) ([6ea6cd5](https://github.com/ydb-platform/ydb-embedded-ui/commit/6ea6cd55f71e6cd7837409c41ffec64d68622773)) +* stream test in safari ([#2059](https://github.com/ydb-platform/ydb-embedded-ui/issues/2059)) ([74355a4](https://github.com/ydb-platform/ydb-embedded-ui/commit/74355a430712c7970b56dd18852673075e692d7d)) + +## [8.18.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.17.0...v8.18.0) (2025-03-27) + + +### Features + +* show transfer errors in UI ([#2043](https://github.com/ydb-platform/ydb-embedded-ui/issues/2043)) ([cb5a755](https://github.com/ydb-platform/ydb-embedded-ui/commit/cb5a755a553b1eaa946f69d5f7a9e1b24700863d)) +* turn streaming on by default ([#2028](https://github.com/ydb-platform/ydb-embedded-ui/issues/2028)) ([bc5d59d](https://github.com/ydb-platform/ydb-embedded-ui/commit/bc5d59d09d577b2bfc6661a1a667ffbb1f2ffa95)) + + +### Bug Fixes + +* **Versions:** loading state ([#2050](https://github.com/ydb-platform/ydb-embedded-ui/issues/2050)) ([66cbd6f](https://github.com/ydb-platform/ydb-embedded-ui/commit/66cbd6f3a05a519df0afe0dd591cd310999d1280)) +* whole tablet family for tabletPage ([#2054](https://github.com/ydb-platform/ydb-embedded-ui/issues/2054)) ([98bfb54](https://github.com/ydb-platform/ydb-embedded-ui/commit/98bfb540ff20f473d9a565c91811d07b2ef398d5)) + +## [8.17.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.16.0...v8.17.0) (2025-03-26) + + +### Features + +* followerId for tablets ([#2025](https://github.com/ydb-platform/ydb-embedded-ui/issues/2025)) ([63d5afd](https://github.com/ydb-platform/ydb-embedded-ui/commit/63d5afd64754df291e0e5eec90142a37114ebf85)) +* parse logging link as default value ([#2036](https://github.com/ydb-platform/ydb-embedded-ui/issues/2036)) ([74f7a58](https://github.com/ydb-platform/ydb-embedded-ui/commit/74f7a5892a08a6a61cd6eff1bfe3acde9aac7f6e)) + + +### Bug Fixes + +* add required field SubDomainKey to getNodes ([#2047](https://github.com/ydb-platform/ydb-embedded-ui/issues/2047)) ([cf1ddc3](https://github.com/ydb-platform/ydb-embedded-ui/commit/cf1ddc39225ada474d858f3ae8eb1f1f595da068)) +* supported changes of the transfer configuration structure ([#2032](https://github.com/ydb-platform/ydb-embedded-ui/issues/2032)) ([78965ed](https://github.com/ydb-platform/ydb-embedded-ui/commit/78965edd4caf013ec4a2aca91614cef7550a9f16)) + +## [8.16.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.15.0...v8.16.0) (2025-03-20) + + +### Features + +* add database hyperlink to logging service ([#2021](https://github.com/ydb-platform/ydb-embedded-ui/issues/2021)) ([dbab46b](https://github.com/ydb-platform/ydb-embedded-ui/commit/dbab46b2d688b25669f07b2aa7294598eb5443d2)) +* query streaming only for queryService ([#2015](https://github.com/ydb-platform/ydb-embedded-ui/issues/2015)) ([105fd2c](https://github.com/ydb-platform/ydb-embedded-ui/commit/105fd2c5a706bf886c6457a78a805e374df6a67c)) +* request clusters handler only on Versions tab ([#2008](https://github.com/ydb-platform/ydb-embedded-ui/issues/2008)) ([7aacdfe](https://github.com/ydb-platform/ydb-embedded-ui/commit/7aacdfe8e939e730d2a1dbc10a7c7fa785f54bbb)) + + +### Bug Fixes + +* kind export operations type ([#2030](https://github.com/ydb-platform/ydb-embedded-ui/issues/2030)) ([3b47eb5](https://github.com/ydb-platform/ydb-embedded-ui/commit/3b47eb59b5444f3f3bff5425f08f3d132c251446)) +* **ObjectSummary:** do not display CreateTime if CreateStep is 0 ([#2018](https://github.com/ydb-platform/ydb-embedded-ui/issues/2018)) ([7af1ed3](https://github.com/ydb-platform/ydb-embedded-ui/commit/7af1ed377fe47fb38498dd7540f8c273a8a9b0be)) +* **ShemaViewer:** show loader correctly ([#2019](https://github.com/ydb-platform/ydb-embedded-ui/issues/2019)) ([29ae340](https://github.com/ydb-platform/ydb-embedded-ui/commit/29ae340156be237a7e01ff429bc62fa38408c63a)) +* unsaved changes in query editor ([#2026](https://github.com/ydb-platform/ydb-embedded-ui/issues/2026)) ([d1d64f7](https://github.com/ydb-platform/ydb-embedded-ui/commit/d1d64f7792842abf42de9c72de3b50c8c3bde1ec)) +* **VDiskInfo:** lowercase vdisk page ([#2014](https://github.com/ydb-platform/ydb-embedded-ui/issues/2014)) ([577c9aa](https://github.com/ydb-platform/ydb-embedded-ui/commit/577c9aa2f545e4792fac6fd299dea9f8653a9082)) + +## [8.15.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.14.0...v8.15.0) (2025-03-10) + + +### Features + +* add QUERY_TECHNICAL_MARK to all UI queries ([#1992](https://github.com/ydb-platform/ydb-embedded-ui/issues/1992)) ([6d53518](https://github.com/ydb-platform/ydb-embedded-ui/commit/6d535186247307f40b01386a850bf30ffb9ffb93)) +* add ShardsTable to componentsRegistry ([#1993](https://github.com/ydb-platform/ydb-embedded-ui/issues/1993)) ([a390679](https://github.com/ydb-platform/ydb-embedded-ui/commit/a390679234d1085b5e19e1933691a60414a450d8)) +* **YDBSyntaxHighlighter:** separate component, load languages on demand ([#2004](https://github.com/ydb-platform/ydb-embedded-ui/issues/2004)) ([a544def](https://github.com/ydb-platform/ydb-embedded-ui/commit/a544deff6db5539f5622111519f770a2c474377b)) + +## [8.14.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.13.0...v8.14.0) (2025-03-07) + + +### Features + +* create Api directly with YdbEmbeddedAPI class ([#1998](https://github.com/ydb-platform/ydb-embedded-ui/issues/1998)) ([b139eb5](https://github.com/ydb-platform/ydb-embedded-ui/commit/b139eb5fe5ac62175227b63dceac8e9889bdb588)) +* support transfer ([#1995](https://github.com/ydb-platform/ydb-embedded-ui/issues/1995)) ([966ff4b](https://github.com/ydb-platform/ydb-embedded-ui/commit/966ff4b6fc5e32ae7fafc4e865949bb02c3a5f01)) +* **TopShards:** colorize usage ([#2003](https://github.com/ydb-platform/ydb-embedded-ui/issues/2003)) ([dde82b0](https://github.com/ydb-platform/ydb-embedded-ui/commit/dde82b0769fa728b4b22f09ce6b40df4a9f86a15)) + + +### Bug Fixes + +* fix undefined process in package ([#1997](https://github.com/ydb-platform/ydb-embedded-ui/issues/1997)) ([0b6b99d](https://github.com/ydb-platform/ydb-embedded-ui/commit/0b6b99d2bcd0d3d00af40c01beff095ba8ae4d7e)) +* **LinkWithIcon:** make inline ([#2002](https://github.com/ydb-platform/ydb-embedded-ui/issues/2002)) ([290bb18](https://github.com/ydb-platform/ydb-embedded-ui/commit/290bb183a98a21e74b49ae419cd64ed10074728e)) +* **PDiskInfo:** display SharedWithOs only when true ([#1991](https://github.com/ydb-platform/ydb-embedded-ui/issues/1991)) ([7c21d71](https://github.com/ydb-platform/ydb-embedded-ui/commit/7c21d71c6fcf272da2329977be1af9671913372e)) +* **TopShards:** display table for column entities ([#1999](https://github.com/ydb-platform/ydb-embedded-ui/issues/1999)) ([6b28803](https://github.com/ydb-platform/ydb-embedded-ui/commit/6b2880321f437a40be52f0b78207390c9019ad93)) + +## [8.13.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.12.0...v8.13.0) (2025-02-28) + + +### Features + +* **ErrorBoundary:** rework error page ([#1983](https://github.com/ydb-platform/ydb-embedded-ui/issues/1983)) ([4a97195](https://github.com/ydb-platform/ydb-embedded-ui/commit/4a97195befe991b6204752d175519ae2d5afaebd)) +* make links from disk pop-up better ([#1986](https://github.com/ydb-platform/ydb-embedded-ui/issues/1986)) ([336d74b](https://github.com/ydb-platform/ydb-embedded-ui/commit/336d74b95502e5d6f2e508bce979a8d02521a64b)) +* redesign query ([#1974](https://github.com/ydb-platform/ydb-embedded-ui/issues/1974)) ([9ac8cfc](https://github.com/ydb-platform/ydb-embedded-ui/commit/9ac8cfc46c71b38aceae2f1ed8b84113b7fbf90b)) +* resource pool – add proper icon ([#1982](https://github.com/ydb-platform/ydb-embedded-ui/issues/1982)) ([9c0c6f8](https://github.com/ydb-platform/ydb-embedded-ui/commit/9c0c6f8ce93e44920c860eb19d961b209d469f7b)) + + +### Bug Fixes + +* rename tabs in query result ([#1987](https://github.com/ydb-platform/ydb-embedded-ui/issues/1987)) ([b9d9f0b](https://github.com/ydb-platform/ydb-embedded-ui/commit/b9d9f0be128537b30117922274b16f477d491205)) +* tests ([#1988](https://github.com/ydb-platform/ydb-embedded-ui/issues/1988)) ([519f587](https://github.com/ydb-platform/ydb-embedded-ui/commit/519f5873ffa5eecb031e71b34206140ae1e02859)) + +## [8.12.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.11.1...v8.12.0) (2025-02-25) + + +### Features + +* add database to authentication process ([#1976](https://github.com/ydb-platform/ydb-embedded-ui/issues/1976)) ([d9067b3](https://github.com/ydb-platform/ydb-embedded-ui/commit/d9067b373f832083c537eb35ca51ab6e56853552)) +* hide some columns and storage nodes for users-viewers ([#1967](https://github.com/ydb-platform/ydb-embedded-ui/issues/1967)) ([249011d](https://github.com/ydb-platform/ydb-embedded-ui/commit/249011d93bff8a20e71ea48504f8c4a4367ff33b)) +* support multipart responses in query ([#1865](https://github.com/ydb-platform/ydb-embedded-ui/issues/1865)) ([99ee997](https://github.com/ydb-platform/ydb-embedded-ui/commit/99ee99713be9165ffd2140e3cab29ec26758b70f)) +* **TabletsTable:** add search by id ([#1981](https://github.com/ydb-platform/ydb-embedded-ui/issues/1981)) ([d68adba](https://github.com/ydb-platform/ydb-embedded-ui/commit/d68adba4d239bbfaf35f006b25e337d1976e1ab5)) + + +### Bug Fixes + +* **Node:** fix developer ui link in dev mode ([#1979](https://github.com/ydb-platform/ydb-embedded-ui/issues/1979)) ([ad64c8c](https://github.com/ydb-platform/ydb-embedded-ui/commit/ad64c8c8e3aa951ec5f97ce6cbb68e9cb3b3254b)) + +## [8.11.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.11.0...v8.11.1) (2025-02-18) + + +### Bug Fixes + +* **JsonViewer:** handle case sensitive search ([#1966](https://github.com/ydb-platform/ydb-embedded-ui/issues/1966)) ([f2aabb7](https://github.com/ydb-platform/ydb-embedded-ui/commit/f2aabb7041cd6cb445df78490b54df7d1dd0945b)) +* unipika styles in one file ([#1963](https://github.com/ydb-platform/ydb-embedded-ui/issues/1963)) ([ff018a1](https://github.com/ydb-platform/ydb-embedded-ui/commit/ff018a1e90404c2d7600d832723b2c75824aa786)) + +## [8.11.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.10.0...v8.11.0) (2025-02-18) + + +### Features + +* add new JsonViewer ([#1951](https://github.com/ydb-platform/ydb-embedded-ui/issues/1951)) ([61a8d48](https://github.com/ydb-platform/ydb-embedded-ui/commit/61a8d4882e2fff38e11bb33c09b3464da8a639fd)) + + +### Bug Fixes + +* make SLO uppercase ([#1959](https://github.com/ydb-platform/ydb-embedded-ui/issues/1959)) ([53e013c](https://github.com/ydb-platform/ydb-embedded-ui/commit/53e013c027d990100574463d5f9983206405ceef)) +* **ObjectSummary:** refresh tabs with tree refresh, disable autorefresh ([#1946](https://github.com/ydb-platform/ydb-embedded-ui/issues/1946)) ([c28ade6](https://github.com/ydb-platform/ydb-embedded-ui/commit/c28ade6a94d63ff9fdd071d56b9970deff19e91b)) +* **schemaQueryTemplates:** insert $ sign ([#1945](https://github.com/ydb-platform/ydb-embedded-ui/issues/1945)) ([267c445](https://github.com/ydb-platform/ydb-embedded-ui/commit/267c4451a0e1df3221e5db26905836360a9f39fc)) +* **SchemaViewer:** fix sort order and add key icon ([#1957](https://github.com/ydb-platform/ydb-embedded-ui/issues/1957)) ([8b5221a](https://github.com/ydb-platform/ydb-embedded-ui/commit/8b5221a6bd284fb8d10930a1975c16c4d57a5eae)) +* **Storage:** fix disks view for degraded group ([#1930](https://github.com/ydb-platform/ydb-embedded-ui/issues/1930)) ([a2b7d1c](https://github.com/ydb-platform/ydb-embedded-ui/commit/a2b7d1c74cf9933d179181e97885347c3a60d06c)) + +## [8.10.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.9.0...v8.10.0) (2025-02-12) + + +### Features + +* **HealthcheckPreview:** manual fetch for ydb_ru ([#1937](https://github.com/ydb-platform/ydb-embedded-ui/issues/1937)) ([6b1cac8](https://github.com/ydb-platform/ydb-embedded-ui/commit/6b1cac892e8afa5f06c9cf6437c76fe7ba13ac18)) + + +### Bug Fixes + +* add monaco-yql-languages to peer deps ([#1932](https://github.com/ydb-platform/ydb-embedded-ui/issues/1932)) ([40b803c](https://github.com/ydb-platform/ydb-embedded-ui/commit/40b803cce83414078a22518ac6183ed0b544099b)) + +## [8.9.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.8.0...v8.9.0) (2025-02-11) + + +### Features + +* move autocomplete logic to library ([#1909](https://github.com/ydb-platform/ydb-embedded-ui/issues/1909)) ([58a0f08](https://github.com/ydb-platform/ydb-embedded-ui/commit/58a0f08478f2b6c1a0bcecbbd3612e78c3bf0d80)) +* **Node:** rework page ([#1917](https://github.com/ydb-platform/ydb-embedded-ui/issues/1917)) ([187032b](https://github.com/ydb-platform/ydb-embedded-ui/commit/187032b6cc77ffc60d925663766dd8e830f4d5d4)) + + +### Bug Fixes + +* code assistant option ([#1922](https://github.com/ydb-platform/ydb-embedded-ui/issues/1922)) ([38ea87f](https://github.com/ydb-platform/ydb-embedded-ui/commit/38ea87fe65e3eb33ee8287b213e65b32d0d20e48)) +* **VDisk:** do not show vdisk as not replicated if no data ([#1921](https://github.com/ydb-platform/ydb-embedded-ui/issues/1921)) ([f648f08](https://github.com/ydb-platform/ydb-embedded-ui/commit/f648f0890b3e308a5875566a141be168302d3924)) + +## [8.8.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.7.0...v8.8.0) (2025-02-07) + + +### Features + +* code assistant integration ([#1902](https://github.com/ydb-platform/ydb-embedded-ui/issues/1902)) ([a10a5cd](https://github.com/ydb-platform/ydb-embedded-ui/commit/a10a5cddaba18100bbc23a1b0267fd15417497b9)) +* extend alter table query templates with enable auto split ([#1913](https://github.com/ydb-platform/ydb-embedded-ui/issues/1913)) ([cc81623](https://github.com/ydb-platform/ydb-embedded-ui/commit/cc81623ab9bc73b19ab24ae3d9367ff8d59a0344)) + + +### Bug Fixes + +* **Configs,Operations:** fix blicks on autorefresh ([#1908](https://github.com/ydb-platform/ydb-embedded-ui/issues/1908)) ([4d9c2b6](https://github.com/ydb-platform/ydb-embedded-ui/commit/4d9c2b6e5dbac9065e46794d96acbdddba66cfbf)) +* create topic template ([#1910](https://github.com/ydb-platform/ydb-embedded-ui/issues/1910)) ([9ab321b](https://github.com/ydb-platform/ydb-embedded-ui/commit/9ab321bca3a3388059eeb7b7da014196bd00227a)) +* **FormattedBytes:** show 1_000 with another unit ([#1901](https://github.com/ydb-platform/ydb-embedded-ui/issues/1901)) ([0e8bdd8](https://github.com/ydb-platform/ydb-embedded-ui/commit/0e8bdd8ea577f82be6d6b775b1f8ab22b771b4d9)) +* **PDiskSpaceDistribution:** update slots severity calculation ([#1907](https://github.com/ydb-platform/ydb-embedded-ui/issues/1907)) ([0a49720](https://github.com/ydb-platform/ydb-embedded-ui/commit/0a497206b578f01af946fb53ebb969e83ebde5c1)) +* remove trace polling ([#1915](https://github.com/ydb-platform/ydb-embedded-ui/issues/1915)) ([5541ca7](https://github.com/ydb-platform/ydb-embedded-ui/commit/5541ca7319a36c67fb9ca93bc5c36d4c2dc6f969)) +* **SchemaViewer:** use partitioning keys order from HashColumns ([#1916](https://github.com/ydb-platform/ydb-embedded-ui/issues/1916)) ([fe3845c](https://github.com/ydb-platform/ydb-embedded-ui/commit/fe3845c2f8203f4d2ca570232f15f23b4622a215)) + +## [8.7.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.6.0...v8.7.0) (2025-01-31) + + +### Features + +* **MetricChart:** add legend to some charts ([#1893](https://github.com/ydb-platform/ydb-embedded-ui/issues/1893)) ([b190e24](https://github.com/ydb-platform/ydb-embedded-ui/commit/b190e2461b6b3edecc272a804597415fbe0742f5)) +* **SchemaViewer:** calculate column width based on data ([#1885](https://github.com/ydb-platform/ydb-embedded-ui/issues/1885)) ([85f19c3](https://github.com/ydb-platform/ydb-embedded-ui/commit/85f19c3d579a2d365056a69be43856a82bd5a9e4)) + + +### Bug Fixes + +* add additional timeout for flaky tests ([#1884](https://github.com/ydb-platform/ydb-embedded-ui/issues/1884)) ([9a502d2](https://github.com/ydb-platform/ydb-embedded-ui/commit/9a502d27e592522ee93f296be6b9047e7e87032e)) +* avoid confusion with information interpretation ([#1871](https://github.com/ydb-platform/ydb-embedded-ui/issues/1871)) ([54c7091](https://github.com/ydb-platform/ydb-embedded-ui/commit/54c7091184d4cc1993bb735a4df9673fc2c32873)) +* disable autorefresh for ydb_ru ([#1890](https://github.com/ydb-platform/ydb-embedded-ui/issues/1890)) ([a0ba20f](https://github.com/ydb-platform/ydb-embedded-ui/commit/a0ba20f68b288bb8be9fa4a12effeea1d00cd9b6)) +* **Storage:** tune popups for vdisk and pdisk ([#1883](https://github.com/ydb-platform/ydb-embedded-ui/issues/1883)) ([ae115d9](https://github.com/ydb-platform/ydb-embedded-ui/commit/ae115d97dedf4dcb353cf3c53d0418131550bb19)) +* **Tenant:** fix tabs reset on schema object change ([#1881](https://github.com/ydb-platform/ydb-embedded-ui/issues/1881)) ([4dd053d](https://github.com/ydb-platform/ydb-embedded-ui/commit/4dd053deb240823780a0c87aa88d3628631f26da)) + +## [8.6.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.5.0...v8.6.0) (2025-01-27) + + +### Features + +* add connect to DB dialog ([#1838](https://github.com/ydb-platform/ydb-embedded-ui/issues/1838)) ([ba22a39](https://github.com/ydb-platform/ydb-embedded-ui/commit/ba22a39e20f6417a9f24a2c0f5084cb63c4cf759)) +* pass database to whoami ([#1860](https://github.com/ydb-platform/ydb-embedded-ui/issues/1860)) ([1990103](https://github.com/ydb-platform/ydb-embedded-ui/commit/19901033fef639450c729e398fb73c75e4cacc66)) +* **SchemaTree:** do not expand childless nodes ([#1868](https://github.com/ydb-platform/ydb-embedded-ui/issues/1868)) ([ae8aa6d](https://github.com/ydb-platform/ydb-embedded-ui/commit/ae8aa6d0e75b42609e51612a12594d0ab7b2bdcf)) +* **Storage:** add State column ([#1859](https://github.com/ydb-platform/ydb-embedded-ui/issues/1859)) ([cda185b](https://github.com/ydb-platform/ydb-embedded-ui/commit/cda185bb35ec4c860b737bd407dd50af96bb31fe)) + + +### Bug Fixes + +* **QueryEditor:** dont render Results every time editor input changes ([#1879](https://github.com/ydb-platform/ydb-embedded-ui/issues/1879)) ([4db34be](https://github.com/ydb-platform/ydb-embedded-ui/commit/4db34be1f6a30054feb9674d69ef9f80e57c112f)) +* **SchemaTree:** expand nodes if ChildrenExist is undefined ([#1872](https://github.com/ydb-platform/ydb-embedded-ui/issues/1872)) ([2af9d9e](https://github.com/ydb-platform/ydb-embedded-ui/commit/2af9d9e3ed075d8b457748d8c80e48947c07ca0b)) +* **UptimeViewer:** do not show StartTime if DisconnectTime present ([#1864](https://github.com/ydb-platform/ydb-embedded-ui/issues/1864)) ([36038bc](https://github.com/ydb-platform/ydb-embedded-ui/commit/36038bcfb7a463a32d49c3c20d5ca29ae615a552)) +* use eye icon for preview ([#1873](https://github.com/ydb-platform/ydb-embedded-ui/issues/1873)) ([c11e616](https://github.com/ydb-platform/ydb-embedded-ui/commit/c11e6165791b8c7258aca5ab9f972b2360cbfd21)) +* **VDisks:** use fixed VDisk width ([#1857](https://github.com/ydb-platform/ydb-embedded-ui/issues/1857)) ([613bbf6](https://github.com/ydb-platform/ydb-embedded-ui/commit/613bbf60600bb802aba2338db78b86044e1a0e1c)) + +## [8.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.4.0...v8.5.0) (2025-01-22) + + +### Features + +* **ClusterInfo:** add slo logs link ([#1850](https://github.com/ydb-platform/ydb-embedded-ui/issues/1850)) ([7e0429b](https://github.com/ydb-platform/ydb-embedded-ui/commit/7e0429b632a73a79051a366c94224e7333d84f05)) +* download dump with all info ([#1862](https://github.com/ydb-platform/ydb-embedded-ui/issues/1862)) ([f09cbe9](https://github.com/ydb-platform/ydb-embedded-ui/commit/f09cbe9dce9634cfa1f001d428d48837ba58df1c)) +* move to node 20, update deps ([#1792](https://github.com/ydb-platform/ydb-embedded-ui/issues/1792)) ([33ab5de](https://github.com/ydb-platform/ydb-embedded-ui/commit/33ab5de4c6e0207490a0077ffdd220163714c32b)) +* **QueryEditor:** add error highlighting ([#1833](https://github.com/ydb-platform/ydb-embedded-ui/issues/1833)) ([b89d084](https://github.com/ydb-platform/ydb-embedded-ui/commit/b89d084c5999d82baf080bf1228c4a7ad30b6afc)) +* **Storage:** group disks by DC ([#1823](https://github.com/ydb-platform/ydb-embedded-ui/issues/1823)) ([dec5b95](https://github.com/ydb-platform/ydb-embedded-ui/commit/dec5b9592ed3b491e5073a5b8903eef65be4dc1d)) +* use the same thresholds for all progress bars ([#1820](https://github.com/ydb-platform/ydb-embedded-ui/issues/1820)) ([1b74502](https://github.com/ydb-platform/ydb-embedded-ui/commit/1b74502de4cf91f8babb9349c6740cf11e63a238)) + + +### Bug Fixes + +* **EntityStatus:** background color for button under hover ([#1842](https://github.com/ydb-platform/ydb-embedded-ui/issues/1842)) ([5c722dd](https://github.com/ydb-platform/ydb-embedded-ui/commit/5c722dd461049a4f4719eadd915f29d063cf2f1d)) +* hide dev ui links for users with viewer rights ([#1824](https://github.com/ydb-platform/ydb-embedded-ui/issues/1824)) ([093e79a](https://github.com/ydb-platform/ydb-embedded-ui/commit/093e79a466104b4dc8c049f705d7f0324a6b79df)) +* **OperationCell:** increase font weight for operation name ([#1825](https://github.com/ydb-platform/ydb-embedded-ui/issues/1825)) ([2e618f4](https://github.com/ydb-platform/ydb-embedded-ui/commit/2e618f42b97f074a1a7b2dcba0d10da186d5b6da)) +* remove retries ([#1829](https://github.com/ydb-platform/ydb-embedded-ui/issues/1829)) ([3cd7364](https://github.com/ydb-platform/ydb-embedded-ui/commit/3cd73641351ad32fb0b8e650386a989a04ff9769)) +* **Storage:** fix encryption label shrink ([#1851](https://github.com/ydb-platform/ydb-embedded-ui/issues/1851)) ([bb6d7be](https://github.com/ydb-platform/ydb-embedded-ui/commit/bb6d7bed75f4cdb7a401022100099d65e855c5e6)) +* update actions ([#1834](https://github.com/ydb-platform/ydb-embedded-ui/issues/1834)) ([e3c2243](https://github.com/ydb-platform/ydb-embedded-ui/commit/e3c224302b0e7492069b00271dcc53f10f9fc68d)) +* **UserSettings:** show description under setting control ([#1827](https://github.com/ydb-platform/ydb-embedded-ui/issues/1827)) ([45ddc7e](https://github.com/ydb-platform/ydb-embedded-ui/commit/45ddc7ea912be8abe38d40cfa0f0578175177fe7)) + +## [8.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.3.0...v8.4.0) (2025-01-13) + + +### Features + +* **autocomplete:** suggest columns from subqueries ([#1788](https://github.com/ydb-platform/ydb-embedded-ui/issues/1788)) ([1095d96](https://github.com/ydb-platform/ydb-embedded-ui/commit/1095d96fba7b803f013761ad250808e5f547566d)) +* **Issues:** click on issue sets cursor to error in editor ([#1797](https://github.com/ydb-platform/ydb-embedded-ui/issues/1797)) ([6434633](https://github.com/ydb-platform/ydb-embedded-ui/commit/643463385501010fba0c901cc6fef6ab3b479b59)) +* set pdisks column width ([#1793](https://github.com/ydb-platform/ydb-embedded-ui/issues/1793)) ([db11791](https://github.com/ydb-platform/ydb-embedded-ui/commit/db11791071f0b8721d3329516515ca92f5185f71)) + + +### Bug Fixes + +* **Auth:** do not show access error when redirecting to auth ([#1803](https://github.com/ydb-platform/ydb-embedded-ui/issues/1803)) ([b2dbe17](https://github.com/ydb-platform/ydb-embedded-ui/commit/b2dbe176f554dfda378b4ab4fd3acec7ac60a78d)) +* **Cluster:** show loader if capabilities not loaded ([#1785](https://github.com/ydb-platform/ydb-embedded-ui/issues/1785)) ([01b8424](https://github.com/ydb-platform/ydb-embedded-ui/commit/01b8424a8040c1d422f7fc1ec87e92d3a833ad4e)) +* handlers list that should be refetched in autorefresh mode ([#1791](https://github.com/ydb-platform/ydb-embedded-ui/issues/1791)) ([9d2280e](https://github.com/ydb-platform/ydb-embedded-ui/commit/9d2280e41fe5153fb5d5c62d30fc8ed25834c875)) +* **VDiskPage:** fix evict action ([#1817](https://github.com/ydb-platform/ydb-embedded-ui/issues/1817)) ([3312ae2](https://github.com/ydb-platform/ydb-embedded-ui/commit/3312ae20bc0f912a4a2b28572e1833efdb770a73)) + +## [8.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.2.2...v8.3.0) (2024-12-23) + + +### Features + +* display view query text ([#1780](https://github.com/ydb-platform/ydb-embedded-ui/issues/1780)) ([d590f05](https://github.com/ydb-platform/ydb-embedded-ui/commit/d590f0557c161dbed49a12fa419f307f6fa9f416)) + +## [8.2.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.2.1...v8.2.2) (2024-12-23) + + +### Bug Fixes + +* **Table:** selectors specifity ([#1778](https://github.com/ydb-platform/ydb-embedded-ui/issues/1778)) ([005c672](https://github.com/ydb-platform/ydb-embedded-ui/commit/005c672a1319140dfa1dadab2bf3dd25ab99fc3b)) + +## [8.2.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.2.0...v8.2.1) (2024-12-23) + + +### Bug Fixes + +* **Table:** increase styles specifity ([#1776](https://github.com/ydb-platform/ydb-embedded-ui/issues/1776)) ([96b8d2f](https://github.com/ydb-platform/ydb-embedded-ui/commit/96b8d2fc20bb9382cbb48a3aed87417ca1be5f39)) + +## [8.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.1.0...v8.2.0) (2024-12-20) + + +### Features + +* add absolute timestamp to uptime ([#1768](https://github.com/ydb-platform/ydb-embedded-ui/issues/1768)) ([a77e6db](https://github.com/ydb-platform/ydb-embedded-ui/commit/a77e6db725c09e765529deb7b7b06f3f0d688e0a)) +* vdisks in 2 rows ([#1758](https://github.com/ydb-platform/ydb-embedded-ui/issues/1758)) ([1f8d6fc](https://github.com/ydb-platform/ydb-embedded-ui/commit/1f8d6fc42612f39fb14b7de24f043e1554f00593)) + + +### Bug Fixes + +* create view template text ([#1772](https://github.com/ydb-platform/ydb-embedded-ui/issues/1772)) ([4773ce8](https://github.com/ydb-platform/ydb-embedded-ui/commit/4773ce82c48ae3a4940911475f38a355d83cd25b)) +* **Schema:** increase default columns width ([#1765](https://github.com/ydb-platform/ydb-embedded-ui/issues/1765)) ([6be903d](https://github.com/ydb-platform/ydb-embedded-ui/commit/6be903d7dedbd9965994cb13ffbeed778d88dddf)) +* **SchemaTree:** snippet not insert if user is not on Query tab ([#1766](https://github.com/ydb-platform/ydb-embedded-ui/issues/1766)) ([1e29666](https://github.com/ydb-platform/ydb-embedded-ui/commit/1e296666c6d3f38819f89784bb5e489124f90afe)) +* **Stack:** reduce offset y on hover ([#1771](https://github.com/ydb-platform/ydb-embedded-ui/issues/1771)) ([640dd97](https://github.com/ydb-platform/ydb-embedded-ui/commit/640dd971f98803726eb51fad59866475c59abb37)) +* **Table:** cell aligning should be maximum specific ([#1764](https://github.com/ydb-platform/ydb-embedded-ui/issues/1764)) ([5db78c9](https://github.com/ydb-platform/ydb-embedded-ui/commit/5db78c98be3c5c26b8ce8346aacc1f6ac78b0000)) + +## [8.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v8.0.0...v8.1.0) (2024-12-17) + + +### Features + +* **autocomplete:** suggest variables ([#1752](https://github.com/ydb-platform/ydb-embedded-ui/issues/1752)) ([44e079a](https://github.com/ydb-platform/ydb-embedded-ui/commit/44e079a2001b40a20583311dcba621ea142e027c)) +* remove /meta/cluster ([#1757](https://github.com/ydb-platform/ydb-embedded-ui/issues/1757)) ([6abc16e](https://github.com/ydb-platform/ydb-embedded-ui/commit/6abc16e5d31024884628c56d32704cb8daa354d7)) + + +### Bug Fixes + +* fix 1 week uptime formatting ([#1759](https://github.com/ydb-platform/ydb-embedded-ui/issues/1759)) ([e3de008](https://github.com/ydb-platform/ydb-embedded-ui/commit/e3de0084cbb6f1338dd892c74f0aaaaed1736104)) + +## [8.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v7.2.0...v8.0.0) (2024-12-12) + + +### ⚠ BREAKING CHANGES + +* only pagination tables in storage ([#1745](https://github.com/ydb-platform/ydb-embedded-ui/issues/1745)) + +### Features + +* change uptime format ([#1748](https://github.com/ydb-platform/ydb-embedded-ui/issues/1748)) ([d40aea0](https://github.com/ydb-platform/ydb-embedded-ui/commit/d40aea027dd87defdf2fbceb60eb44a5d480034d)) +* remove unused exports, functions and files ([#1750](https://github.com/ydb-platform/ydb-embedded-ui/issues/1750)) ([cdf9ebc](https://github.com/ydb-platform/ydb-embedded-ui/commit/cdf9ebc46850cf5a0d150436bd4b07183b2080a8)) + + +### Bug Fixes + +* **ClusterInfo:** update links view ([#1746](https://github.com/ydb-platform/ydb-embedded-ui/issues/1746)) ([b3d5897](https://github.com/ydb-platform/ydb-embedded-ui/commit/b3d5897a05f503226458f4a47fcee113ced428db)) +* execution plan svg not saving in chrome ([#1744](https://github.com/ydb-platform/ydb-embedded-ui/issues/1744)) ([189174a](https://github.com/ydb-platform/ydb-embedded-ui/commit/189174a20c8d8a1270e0f5fdaa86a5c43bfe0751)) + + +### Miscellaneous Chores + +* only pagination tables in storage ([#1745](https://github.com/ydb-platform/ydb-embedded-ui/issues/1745)) ([b12599e](https://github.com/ydb-platform/ydb-embedded-ui/commit/b12599e365d9ae9e0cbe3e87091568c575a0074e)) + +## [7.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v7.1.0...v7.2.0) (2024-12-10) + + +### Features + +* add wrapper for gravity-ui/table ([#1736](https://github.com/ydb-platform/ydb-embedded-ui/issues/1736)) ([26d00e9](https://github.com/ydb-platform/ydb-embedded-ui/commit/26d00e910a078ad7042a3a41599978c0fb1995ad)) +* **JSONTree:** allow case insensitive search ([#1735](https://github.com/ydb-platform/ydb-embedded-ui/issues/1735)) ([d4845d3](https://github.com/ydb-platform/ydb-embedded-ui/commit/d4845d3cd598ebbaece4934e7b0a4a886f657170)) +* redirect to embedded ([#1732](https://github.com/ydb-platform/ydb-embedded-ui/issues/1732)) ([dacc546](https://github.com/ydb-platform/ydb-embedded-ui/commit/dacc546dc86f1e442c81dcd3120b40707d5a0504)) +* show negative uptime for nodes when disconnected ([#1740](https://github.com/ydb-platform/ydb-embedded-ui/issues/1740)) ([3991c56](https://github.com/ydb-platform/ydb-embedded-ui/commit/3991c5666c222688fbcc24c578d58833ba258904)) +* **TopQueries:** add limit, sort on backend ([#1737](https://github.com/ydb-platform/ydb-embedded-ui/issues/1737)) ([bc8acee](https://github.com/ydb-platform/ydb-embedded-ui/commit/bc8aceee8ac50c85110139324ddbed279b863925)) + + +### Bug Fixes + +* make grey more grey ([#1738](https://github.com/ydb-platform/ydb-embedded-ui/issues/1738)) ([6d39f9d](https://github.com/ydb-platform/ydb-embedded-ui/commit/6d39f9d498d86e2ec9f6763758a2c379aec71518)) + +## [7.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v7.0.0...v7.1.0) (2024-12-04) + + +### Features + +* **ClusterInfo:** add cores and logging links ([#1731](https://github.com/ydb-platform/ydb-embedded-ui/issues/1731)) ([f8acb2b](https://github.com/ydb-platform/ydb-embedded-ui/commit/f8acb2baad8d92c06f620e5a7f03aba499c852f1)) + + +### Bug Fixes + +* **autocomplete:** should work properly if handler returns no entites ([#1726](https://github.com/ydb-platform/ydb-embedded-ui/issues/1726)) ([9cdab88](https://github.com/ydb-platform/ydb-embedded-ui/commit/9cdab88c00619e1c9d37faff27376d9156257fe1)) + +## [7.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.37.2...v7.0.0) (2024-12-02) + + +### ⚠ BREAKING CHANGES + +* `window.api` was previously a flat `YdbEmbeddedAPI` object. It has been refactored into multiple distributed `AxiosWrapper` instances. Each endpoint is now handled by a dedicated wrapper instance, improving modularity and maintainability. Developers should update their integrations to use the new structure. For example: Replace `window.api.getTenants` with `window.api.viewer.getTenants`. + +### Features + +* **Network:** add peer role filter ([#1724](https://github.com/ydb-platform/ydb-embedded-ui/issues/1724)) ([1285049](https://github.com/ydb-platform/ydb-embedded-ui/commit/1285049d7101dcac432b9f9c934d58e7b074faa7)) +* **Preview:** add rows count and truncated flag ([#1715](https://github.com/ydb-platform/ydb-embedded-ui/issues/1715)) ([6e1e701](https://github.com/ydb-platform/ydb-embedded-ui/commit/6e1e701b975b6fd3582bf7a6e30b2c97fb7d8235)) +* **QueryResultTable:** display row number ([#1714](https://github.com/ydb-platform/ydb-embedded-ui/issues/1714)) ([eba72a0](https://github.com/ydb-platform/ydb-embedded-ui/commit/eba72a0a18605377f06e485f54d8072255900915)) +* refactor API structure ([#1718](https://github.com/ydb-platform/ydb-embedded-ui/issues/1718)) ([e050bd7](https://github.com/ydb-platform/ydb-embedded-ui/commit/e050bd7e93355de1adf50b78c1c50dfcf78794e1)) +* **Versions:** use columns from Nodes table ([#1713](https://github.com/ydb-platform/ydb-embedded-ui/issues/1713)) ([9b3f779](https://github.com/ydb-platform/ydb-embedded-ui/commit/9b3f779ce41579af1dc1420c32ab8d10d6ab7b7f)) + + +### Bug Fixes + +* dependabot found vulnerabilities ([#1720](https://github.com/ydb-platform/ydb-embedded-ui/issues/1720)) ([0faaf87](https://github.com/ydb-platform/ydb-embedded-ui/commit/0faaf87126728cc01a2961f901020ec07f2402ad)) +* deploy test report error ([#1703](https://github.com/ydb-platform/ydb-embedded-ui/issues/1703)) ([efb0b9c](https://github.com/ydb-platform/ydb-embedded-ui/commit/efb0b9c65bb2b188f4aef8104c9c5ebf7e25143f)) +* **FullScreen:** ensure the content is scrollable ([#1723](https://github.com/ydb-platform/ydb-embedded-ui/issues/1723)) ([f6e79f2](https://github.com/ydb-platform/ydb-embedded-ui/commit/f6e79f29fadf1b689dfc1e089cd122bde74e653a)) +* **QueryResultTable:** optimise rendering ([#1697](https://github.com/ydb-platform/ydb-embedded-ui/issues/1697)) ([d93e866](https://github.com/ydb-platform/ydb-embedded-ui/commit/d93e866d8333cdf2fa0f3b3e2a16065f1cc4358a)) +* **styles:** tune hover for tables ([#1710](https://github.com/ydb-platform/ydb-embedded-ui/issues/1710)) ([e86c845](https://github.com/ydb-platform/ydb-embedded-ui/commit/e86c8454ffc035786bdf7247ead77d80e4f3241f)) +* **TopQueries:** add queryHashColumns ([#1701](https://github.com/ydb-platform/ydb-embedded-ui/issues/1701)) ([278f622](https://github.com/ydb-platform/ydb-embedded-ui/commit/278f622ad2886632bc6c0f42c366979ec7f4252f)) +* **Versions:** tune default color ([#1719](https://github.com/ydb-platform/ydb-embedded-ui/issues/1719)) ([97c66b8](https://github.com/ydb-platform/ydb-embedded-ui/commit/97c66b87799695add99514f7173aedd1ef873077)) + +## [6.37.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.37.1...v6.37.2) (2024-11-26) + + +### Bug Fixes + +* **AsideNavigation:** fix documentation link ([#1687](https://github.com/ydb-platform/ydb-embedded-ui/issues/1687)) ([017b983](https://github.com/ydb-platform/ydb-embedded-ui/commit/017b983ceed8c0899e6837f91f6c1178abd6fa6f)) +* change default tables columns, reorder columns ([#1694](https://github.com/ydb-platform/ydb-embedded-ui/issues/1694)) ([f164489](https://github.com/ydb-platform/ydb-embedded-ui/commit/f1644891c4c59f47f15fc28c2071ec020885aca0)) +* fallback for detailed memory ([#1696](https://github.com/ydb-platform/ydb-embedded-ui/issues/1696)) ([05094d7](https://github.com/ydb-platform/ydb-embedded-ui/commit/05094d7d7b657b9e9ee30ca5a8532aaa1cd82389)) +* make limit rows less or equal to 100_000 ([#1695](https://github.com/ydb-platform/ydb-embedded-ui/issues/1695)) ([db8ec37](https://github.com/ydb-platform/ydb-embedded-ui/commit/db8ec37b43313617a00c762f44afedfd1a76f4e8)) +* memory tests ([#1699](https://github.com/ydb-platform/ydb-embedded-ui/issues/1699)) ([4b1889f](https://github.com/ydb-platform/ydb-embedded-ui/commit/4b1889fa63aea2583850a6f6494eed360e7e56a0)) + +## [6.37.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.37.0...v6.37.1) (2024-11-25) + + +### Bug Fixes + +* investigate 1 minute query timeout ([#1690](https://github.com/ydb-platform/ydb-embedded-ui/issues/1690)) ([70ac486](https://github.com/ydb-platform/ydb-embedded-ui/commit/70ac4869db5cf2930a201f0e639689381182e780)) + +## [6.37.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.36.1...v6.37.0) (2024-11-25) + + +### Features + +* **autocomplete:** show column attributes ([#1665](https://github.com/ydb-platform/ydb-embedded-ui/issues/1665)) ([de0b9b6](https://github.com/ydb-platform/ydb-embedded-ui/commit/de0b9b6f1305e71b4f4a37e2b289f41971d131ea)) +* indicate schema description loading ([#1672](https://github.com/ydb-platform/ydb-embedded-ui/issues/1672)) ([c0781f1](https://github.com/ydb-platform/ydb-embedded-ui/commit/c0781f102250e1aa6c7f4886919b08d97ce54e09)) + + +### Bug Fixes + +* add couple of template tests ([#1662](https://github.com/ydb-platform/ydb-embedded-ui/issues/1662)) ([80b3b88](https://github.com/ydb-platform/ydb-embedded-ui/commit/80b3b8889bdff30938bc62b5911433c40e5e785a)) +* deploy report condition ([#1671](https://github.com/ydb-platform/ydb-embedded-ui/issues/1671)) ([09b6784](https://github.com/ydb-platform/ydb-embedded-ui/commit/09b678420c89d1bd76ef1c5b9bdeebf8579375aa)) +* remove push trigger ([#1669](https://github.com/ydb-platform/ydb-embedded-ui/issues/1669)) ([108db81](https://github.com/ydb-platform/ydb-embedded-ui/commit/108db81c2e8115495ef946b181610ee5b5a2f637)) +* show zero default for column ([#1681](https://github.com/ydb-platform/ydb-embedded-ui/issues/1681)) ([e33b702](https://github.com/ydb-platform/ydb-embedded-ui/commit/e33b7025ab967ef1c43bd21befeea170e18dacc2)) +* split deploy and update pr ([#1670](https://github.com/ydb-platform/ydb-embedded-ui/issues/1670)) ([aa216b1](https://github.com/ydb-platform/ydb-embedded-ui/commit/aa216b11616a283786300a17805c33c9d0b3a2a2)) + +## [6.36.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.36.0...v6.36.1) (2024-11-21) + + +### Bug Fixes + +* should not set filters for SELECT with known context ([#1666](https://github.com/ydb-platform/ydb-embedded-ui/issues/1666)) ([3e4ceef](https://github.com/ydb-platform/ydb-embedded-ui/commit/3e4ceef952a0821c94ec100f116fb97d033cc1f2)) + +## [6.36.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.35.0...v6.36.0) (2024-11-20) + + +### Features + +* render tenant memory details ([#1623](https://github.com/ydb-platform/ydb-embedded-ui/issues/1623)) ([09b1238](https://github.com/ydb-platform/ydb-embedded-ui/commit/09b1238dfd6024778d187dcca2a5132d5c601fec)) + + +### Bug Fixes + +* make plan to svg more comprehensive ([#1658](https://github.com/ydb-platform/ydb-embedded-ui/issues/1658)) ([e973bae](https://github.com/ydb-platform/ydb-embedded-ui/commit/e973bae006fb67452a219f4f20f1772d8d73674f)) +* **PaginatedTable:** fix autorefresh when no data ([#1650](https://github.com/ydb-platform/ydb-embedded-ui/issues/1650)) ([ed9a03b](https://github.com/ydb-platform/ydb-embedded-ui/commit/ed9a03b599d4fd8aaafab0c5e2005b2f111af009)) +* **Versions:** should not show nodes withot version ([#1653](https://github.com/ydb-platform/ydb-embedded-ui/issues/1653)) ([fd60b9d](https://github.com/ydb-platform/ydb-embedded-ui/commit/fd60b9d0d71ecd98dfff2d254425d254525d6853)) + +## [6.35.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.34.0...v6.35.0) (2024-11-18) + + +### Features + +* **Network:** add table view ([#1622](https://github.com/ydb-platform/ydb-embedded-ui/issues/1622)) ([507aa71](https://github.com/ydb-platform/ydb-embedded-ui/commit/507aa712afd529a6ea7e180e91c827d611844cfd)) +* use monaco snippets for query templates ([#1626](https://github.com/ydb-platform/ydb-embedded-ui/issues/1626)) ([bcdefd5](https://github.com/ydb-platform/ydb-embedded-ui/commit/bcdefd5994161318c9da4b7a75beeac03c1bd14c)) + + +### Bug Fixes + +* move @ebay/nice-modal-react to dependencies ([#1647](https://github.com/ydb-platform/ydb-embedded-ui/issues/1647)) ([8887b75](https://github.com/ydb-platform/ydb-embedded-ui/commit/8887b7554dd65a5caf064ad84ebbc13af9a13f9a)) +* remove empty selectedConsumer from url ([#1644](https://github.com/ydb-platform/ydb-embedded-ui/issues/1644)) ([14f3fa4](https://github.com/ydb-platform/ydb-embedded-ui/commit/14f3fa46747e9222bf93b82af19ec8b2dae853e4)) +* **SaveQueryDialog:** should not duplicate component in DOM ([#1649](https://github.com/ydb-platform/ydb-embedded-ui/issues/1649)) ([3b37565](https://github.com/ydb-platform/ydb-embedded-ui/commit/3b37565241126763269aa8cc1e328e6ea2a14bc7)) +* tests for templates ([#1648](https://github.com/ydb-platform/ydb-embedded-ui/issues/1648)) ([da2a02d](https://github.com/ydb-platform/ydb-embedded-ui/commit/da2a02d017b5af972fa68d5f5b02a4956e0763ab)) + +## [6.34.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.33.0...v6.34.0) (2024-11-18) + + +### Features + +* add to embedded ui link to plan2svg converter ([#1619](https://github.com/ydb-platform/ydb-embedded-ui/issues/1619)) ([fb007a7](https://github.com/ydb-platform/ydb-embedded-ui/commit/fb007a764c8cf40d97242d598e4fa90310c97460)) +* **ConfirmationDialog:** add saving query before replace ([#1629](https://github.com/ydb-platform/ydb-embedded-ui/issues/1629)) ([c71925d](https://github.com/ydb-platform/ydb-embedded-ui/commit/c71925dee41c588d5ca18f6170a62a15e32d9e8d)) +* **Navigation:** allow to change user icon ([#1628](https://github.com/ydb-platform/ydb-embedded-ui/issues/1628)) ([71956ec](https://github.com/ydb-platform/ydb-embedded-ui/commit/71956ec3a1be3318f70b82c75656940a81478b3a)) +* render per component memory consumption ([#1574](https://github.com/ydb-platform/ydb-embedded-ui/issues/1574)) ([3e4a04b](https://github.com/ydb-platform/ydb-embedded-ui/commit/3e4a04b2eaf68c98403b87f98ab1d31da930206a)) +* warn about unsaved changes in editor ([#1620](https://github.com/ydb-platform/ydb-embedded-ui/issues/1620)) ([2632b90](https://github.com/ydb-platform/ydb-embedded-ui/commit/2632b90ed38cd89a1691b77b8cf4bccb2cf19507)) + + +### Bug Fixes + +* change trace and svg mutations to lazy query ([#1640](https://github.com/ydb-platform/ydb-embedded-ui/issues/1640)) ([19d7f56](https://github.com/ydb-platform/ydb-embedded-ui/commit/19d7f5629786531781dec738310b3cee8d3fd83e)) +* delete directory from gh-pages on pr close ([#1638](https://github.com/ydb-platform/ydb-embedded-ui/issues/1638)) ([d99e295](https://github.com/ydb-platform/ydb-embedded-ui/commit/d99e295ba5574f04eb42def2770cc59113669b46)) +* dont remove previous tests reports ([#1630](https://github.com/ydb-platform/ydb-embedded-ui/issues/1630)) ([5302a94](https://github.com/ydb-platform/ydb-embedded-ui/commit/5302a94e871eb55050bc2d462d9629b61cb9f685)) +* **EntityStatus:** show title for text part only ([#1608](https://github.com/ydb-platform/ydb-embedded-ui/issues/1608)) ([7e234a5](https://github.com/ydb-platform/ydb-embedded-ui/commit/7e234a5e7d62e1bb845632f5bef9ab30103fc49e)) +* **schemaActions:** preserve query settings when insert snippet ([#1615](https://github.com/ydb-platform/ydb-embedded-ui/issues/1615)) ([2ec5ccd](https://github.com/ydb-platform/ydb-embedded-ui/commit/2ec5ccde77a26228b148e46b7857b8767e134e1f)) +* **schemaActions:** use different sets for row and column tables ([#1627](https://github.com/ydb-platform/ydb-embedded-ui/issues/1627)) ([9972ac2](https://github.com/ydb-platform/ydb-embedded-ui/commit/9972ac2fafc027564b7bc1df163ccd97de346801)) +* **schemaQueryTemplates:** doc link for topic creation ([#1616](https://github.com/ydb-platform/ydb-embedded-ui/issues/1616)) ([3e07ca5](https://github.com/ydb-platform/ydb-embedded-ui/commit/3e07ca5488577aa7f2bad2731ae7ef09f8c66e6b)) + +## [6.33.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.32.0...v6.33.0) (2024-11-11) + + +### Features + +* **autocomplete:** suggest all columns in a row ([#1599](https://github.com/ydb-platform/ydb-embedded-ui/issues/1599)) ([b4d2b7f](https://github.com/ydb-platform/ydb-embedded-ui/commit/b4d2b7f45c35b7eaadf93faf602cca16776093eb)) + + +### Bug Fixes + +* **Clusters:** controls and aggregations layout ([#1588](https://github.com/ydb-platform/ydb-embedded-ui/issues/1588)) ([ee61273](https://github.com/ydb-platform/ydb-embedded-ui/commit/ee61273c3b67a383a9c0ad8f7b783716cf53f750)) +* **Nodes:** remove redundant group by params ([#1598](https://github.com/ydb-platform/ydb-embedded-ui/issues/1598)) ([d3c5714](https://github.com/ydb-platform/ydb-embedded-ui/commit/d3c571446d5b37dc83e359254d7872c01eca3c31)) + +## [6.32.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.31.0...v6.32.0) (2024-11-08) + + +### Features + +* **Nodes:** add grouping ([#1584](https://github.com/ydb-platform/ydb-embedded-ui/issues/1584)) ([88ec214](https://github.com/ydb-platform/ydb-embedded-ui/commit/88ec214d3f89067a9c55243068c73a5d029a7068)) + + +### Bug Fixes + +* **Header:** fix developer ui link for embedded UI with proxy ([#1580](https://github.com/ydb-platform/ydb-embedded-ui/issues/1580)) ([b229301](https://github.com/ydb-platform/ydb-embedded-ui/commit/b229301e167c8651550606ee5450f6d7f2409048)) +* if popover has actions increase delayClosing ([#1573](https://github.com/ydb-platform/ydb-embedded-ui/issues/1573)) ([7680e96](https://github.com/ydb-platform/ydb-embedded-ui/commit/7680e96681a9edf6b29589b73189ac72ef48f3d4)) +* **NodeEndpointsTooltipContent:** change fields order ([#1585](https://github.com/ydb-platform/ydb-embedded-ui/issues/1585)) ([949a518](https://github.com/ydb-platform/ydb-embedded-ui/commit/949a518a272e920e36f4c2a94c3b502d37d6e3a4)) +* query templates modification ([#1579](https://github.com/ydb-platform/ydb-embedded-ui/issues/1579)) ([697921a](https://github.com/ydb-platform/ydb-embedded-ui/commit/697921abe30e0b3415c0cd08519b8fecdfaaa03b)) +* refresh schema and autoresresh icons should be similar ([#1572](https://github.com/ydb-platform/ydb-embedded-ui/issues/1572)) ([03bc63d](https://github.com/ydb-platform/ydb-embedded-ui/commit/03bc63dc5d386591a4ef2e73c7051349b37c83ed)) +* use both BSC and Whiteboard for disks ([#1564](https://github.com/ydb-platform/ydb-embedded-ui/issues/1564)) ([da6dfcd](https://github.com/ydb-platform/ydb-embedded-ui/commit/da6dfcd856468ff89b031a2d6bbf710c7033ef5a)) + +## [6.31.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.30.0...v6.31.0) (2024-11-02) + + +### Features + +* add control to execute forget command for an export ([#1552](https://github.com/ydb-platform/ydb-embedded-ui/issues/1552)) ([b31d2cf](https://github.com/ydb-platform/ydb-embedded-ui/commit/b31d2cfd44f34e0fc5a94d019389c4ca8ae77486)) +* implement simple and narrow vertical progress bar ([#1560](https://github.com/ydb-platform/ydb-embedded-ui/issues/1560)) ([e5d0823](https://github.com/ydb-platform/ydb-embedded-ui/commit/e5d0823d7869d547f9c92d3681e8abc5c70000b9)) +* **NodeEndpointsTooltipContent:** add fields ([#1566](https://github.com/ydb-platform/ydb-embedded-ui/issues/1566)) ([3287f99](https://github.com/ydb-platform/ydb-embedded-ui/commit/3287f9921ef1a92942c6fee4205e6a26465877d6)) + + +### Bug Fixes + +* **Nodes,Storage:** reorder controls - prevent moving on count change ([#1562](https://github.com/ydb-platform/ydb-embedded-ui/issues/1562)) ([74b27f7](https://github.com/ydb-platform/ydb-embedded-ui/commit/74b27f7758287dfc6861b9de032b24a4288aea63)) +* **VDiskInfo:** fix title layout ([#1561](https://github.com/ydb-platform/ydb-embedded-ui/issues/1561)) ([7bd2262](https://github.com/ydb-platform/ydb-embedded-ui/commit/7bd2262ba583f7d007929d2d2d5c3ed9a1829a85)) + +## [6.30.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.29.3...v6.30.0) (2024-10-31) + + +### Features + +* **ObjectSummary:** add button to refresh tree ([#1559](https://github.com/ydb-platform/ydb-embedded-ui/issues/1559)) ([e7dbf9d](https://github.com/ydb-platform/ydb-embedded-ui/commit/e7dbf9dcabfa6b0f8fed0e16886e59e1c9b46d09)) + + +### Bug Fixes + +* **Cluster:** use /capabilities to show dashboard ([#1556](https://github.com/ydb-platform/ydb-embedded-ui/issues/1556)) ([7811347](https://github.com/ydb-platform/ydb-embedded-ui/commit/78113477d3a9b0bee26de20b4a4a9e38e8eefd5f)) +* pass database to capabilities query ([#1551](https://github.com/ydb-platform/ydb-embedded-ui/issues/1551)) ([7e7b3e3](https://github.com/ydb-platform/ydb-embedded-ui/commit/7e7b3e38c82aa7df8a454f6ce2bc4f37c2fd1a99)) +* tracing issues ([#1555](https://github.com/ydb-platform/ydb-embedded-ui/issues/1555)) ([4cb2d7f](https://github.com/ydb-platform/ydb-embedded-ui/commit/4cb2d7fdd59126a44ef3b003a73e3375ba1f853b)) + +## [6.29.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.29.2...v6.29.3) (2024-10-28) + + +### Bug Fixes + +* very bad performance when scrolling paginated tables ([#1513](https://github.com/ydb-platform/ydb-embedded-ui/issues/1513)) ([e2f7a25](https://github.com/ydb-platform/ydb-embedded-ui/commit/e2f7a2557e4699f2737b7f660579fec47580f48a)) + +## [6.29.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.29.1...v6.29.2) (2024-10-28) + + +### Bug Fixes + +* **ClusterMetricsCores:** format value and capacity same way ([#1532](https://github.com/ydb-platform/ydb-embedded-ui/issues/1532)) ([4eb5c04](https://github.com/ydb-platform/ydb-embedded-ui/commit/4eb5c041f8b5615a2806bf5d5bd015afa963ac09)) +* **TabletsTable:** action icons coincide in tablet's page and in table ([#1549](https://github.com/ydb-platform/ydb-embedded-ui/issues/1549)) ([26f77a8](https://github.com/ydb-platform/ydb-embedded-ui/commit/26f77a8563e3c3a100001b198e3e7ee5f97ad7f9)) + +## [6.29.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.29.0...v6.29.1) (2024-10-25) + + +### Bug Fixes + +* **EntityStatus:** wrapper layout without clipboard ([#1538](https://github.com/ydb-platform/ydb-embedded-ui/issues/1538)) ([9858369](https://github.com/ydb-platform/ydb-embedded-ui/commit/9858369022c5921f1c66b17341355d2d97dd2e66)) +* primary keys for column tables ([#1541](https://github.com/ydb-platform/ydb-embedded-ui/issues/1541)) ([4359ca6](https://github.com/ydb-platform/ydb-embedded-ui/commit/4359ca6124da4e59e9541c6534bf524f3038c3ec)) + +## [6.29.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.28.0...v6.29.0) (2024-10-25) + + +### Features + +* add Bytes and Text types suggestion in autocomplete ([#1531](https://github.com/ydb-platform/ydb-embedded-ui/issues/1531)) ([6a99452](https://github.com/ydb-platform/ydb-embedded-ui/commit/6a994523986f68d775c1efb13f49c624f0125107)) + + +### Bug Fixes + +* **ClusterDashboard:** hide dashboard if /cluster handler version less 5 ([#1535](https://github.com/ydb-platform/ydb-embedded-ui/issues/1535)) ([f24e5e4](https://github.com/ydb-platform/ydb-embedded-ui/commit/f24e5e4cb2498fd1fa828d8dc40a7f36253016a1)) +* remove excessive slash for requests via tenant node ([#1537](https://github.com/ydb-platform/ydb-embedded-ui/issues/1537)) ([6fb97a9](https://github.com/ydb-platform/ydb-embedded-ui/commit/6fb97a96710bccc39918bb5b127df421df1cbfc4)) +* **TenantOverview:** fix used tablet storage calculation ([#1528](https://github.com/ydb-platform/ydb-embedded-ui/issues/1528)) ([96411ee](https://github.com/ydb-platform/ydb-embedded-ui/commit/96411ee7b3f7f1830c2bd445c584438964cc7347)) + +## [6.28.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.27.1...v6.28.0) (2024-10-23) + + +### Features + +* add developer ui links to disks popups ([#1512](https://github.com/ydb-platform/ydb-embedded-ui/issues/1512)) ([57d2092](https://github.com/ydb-platform/ydb-embedded-ui/commit/57d20927839b4a11b7f24b57f7d3cf9b7549fb0f)) + + +### Bug Fixes + +* **Cluster:** handle cluster error in meta requests ([#1525](https://github.com/ydb-platform/ydb-embedded-ui/issues/1525)) ([71b254e](https://github.com/ydb-platform/ydb-embedded-ui/commit/71b254ec73ae492d722f8a720cda4e1de714e286)) +* correct width for columns with ProgressViewer ([#1522](https://github.com/ydb-platform/ydb-embedded-ui/issues/1522)) ([e27749a](https://github.com/ydb-platform/ydb-embedded-ui/commit/e27749af04d9230edd8cd24f5e3a59d968d87dcf)) +* **EntityStatus:** remove additionalControls, fix ClipboardButton layout ([#1524](https://github.com/ydb-platform/ydb-embedded-ui/issues/1524)) ([ea4d3a9](https://github.com/ydb-platform/ydb-embedded-ui/commit/ea4d3a95ffe99c8380f0a8971ff41f9b9b534aa7)) +* fields required in all groups and nodes requests ([#1515](https://github.com/ydb-platform/ydb-embedded-ui/issues/1515)) ([a9f79a3](https://github.com/ydb-platform/ydb-embedded-ui/commit/a9f79a31ced8a642dabd6231df4e810e1f14eaa3)) +* operations kind button width ([#1521](https://github.com/ydb-platform/ydb-embedded-ui/issues/1521)) ([980d4fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/980d4facf842eb2f64275afaf925e6dde309c0fe)) +* replace EntityStatus with StatusIcon where possible ([#1518](https://github.com/ydb-platform/ydb-embedded-ui/issues/1518)) ([017c82a](https://github.com/ydb-platform/ydb-embedded-ui/commit/017c82a54fac97c2e62422ac971f615f39434d84)) +* **Storage:** display unavailable vdisks with average size ([#1511](https://github.com/ydb-platform/ydb-embedded-ui/issues/1511)) ([1868e18](https://github.com/ydb-platform/ydb-embedded-ui/commit/1868e182bd88fec178b400f32219f80f1cee1c02)) +* update license ([#1516](https://github.com/ydb-platform/ydb-embedded-ui/issues/1516)) ([cabcb5c](https://github.com/ydb-platform/ydb-embedded-ui/commit/cabcb5c89b0fa50ea4fdb2018eff39091d1b440f)) + +## [6.27.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.27.0...v6.27.1) (2024-10-22) + + +### Bug Fixes + +* increase storage/groups timeout ([#1510](https://github.com/ydb-platform/ydb-embedded-ui/issues/1510)) ([b3dad05](https://github.com/ydb-platform/ydb-embedded-ui/commit/b3dad0545744ba091349c468ec5b62408dcfaff5)) +* remove unneeded titles ([#1508](https://github.com/ydb-platform/ydb-embedded-ui/issues/1508)) ([b4c44e9](https://github.com/ydb-platform/ydb-embedded-ui/commit/b4c44e9f668bbf3528bc156117e821d126225865)) + +## [6.27.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.26.1...v6.27.0) (2024-10-21) + + +### Features + +* **Cluster:** rework cluster page ([#1473](https://github.com/ydb-platform/ydb-embedded-ui/issues/1473)) ([ee06b4e](https://github.com/ydb-platform/ydb-embedded-ui/commit/ee06b4e47e0450d7c1e8e2ba79d00d6786155425)) +* display a list of operations ([#1445](https://github.com/ydb-platform/ydb-embedded-ui/issues/1445)) ([3dda3fe](https://github.com/ydb-platform/ydb-embedded-ui/commit/3dda3feab9ba43c0ff6b73ce6a6d7c87ed32de0e)) +* **Storage,Nodes:** request only needed fields from backend ([#1491](https://github.com/ydb-platform/ydb-embedded-ui/issues/1491)) ([0af72a4](https://github.com/ydb-platform/ydb-embedded-ui/commit/0af72a42c7035aef519340334a7c954e86ab272d)) + + +### Bug Fixes + +* cluster layout ([#1507](https://github.com/ydb-platform/ydb-embedded-ui/issues/1507)) ([d38d01b](https://github.com/ydb-platform/ydb-embedded-ui/commit/d38d01b9a1dfd1c8b5ccb6cf814a5d02689e3f42)) +* fix cdc stream query template ([#1498](https://github.com/ydb-platform/ydb-embedded-ui/issues/1498)) ([8405466](https://github.com/ydb-platform/ydb-embedded-ui/commit/84054666dae4df611a9657027b7be2bde84f153d)) +* **overview:** broken loading state calculation ([#1499](https://github.com/ydb-platform/ydb-embedded-ui/issues/1499)) ([05d89be](https://github.com/ydb-platform/ydb-embedded-ui/commit/05d89be1bcc8718781ec003b4444a922c32b0e43)) +* **Preview:** do not auto refresh table preview ([#1503](https://github.com/ydb-platform/ydb-embedded-ui/issues/1503)) ([dbe83b2](https://github.com/ydb-platform/ydb-embedded-ui/commit/dbe83b2ee05cf5b2b01c876b59f8d7a127ac0f67)) +* **topic:** broken memoization ([#1500](https://github.com/ydb-platform/ydb-embedded-ui/issues/1500)) ([e85f70e](https://github.com/ydb-platform/ydb-embedded-ui/commit/e85f70ea2f6053d3b9dae7e0f6630b3fe672a488)) + +## [6.26.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.26.0...v6.26.1) (2024-10-18) + + +### Bug Fixes + +* **EntityStatus:** set minimum container width ([#1494](https://github.com/ydb-platform/ydb-embedded-ui/issues/1494)) ([d6c6a4c](https://github.com/ydb-platform/ydb-embedded-ui/commit/d6c6a4c709e5b8ce6bdff85fe756b1299805b776)) + +## [6.26.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.25.0...v6.26.0) (2024-10-18) + + +### Features + +* add/drop table index template ([#1456](https://github.com/ydb-platform/ydb-embedded-ui/issues/1456)) ([d7a8e0b](https://github.com/ydb-platform/ydb-embedded-ui/commit/d7a8e0ba5d59ac0d9f483b8f70083393531b8a5c)) +* improve appearing controls styles ([#1436](https://github.com/ydb-platform/ydb-embedded-ui/issues/1436)) ([830c0a5](https://github.com/ydb-platform/ydb-embedded-ui/commit/830c0a503db6a49b2daf316585e0f31d998149d1)) +* **ObjectSummary:** improve object overview ([#1447](https://github.com/ydb-platform/ydb-embedded-ui/issues/1447)) ([4afa2b6](https://github.com/ydb-platform/ydb-embedded-ui/commit/4afa2b65370772a78980114f856579e8c73b5952)) +* paginated tables - enable setting by default ([#1464](https://github.com/ydb-platform/ydb-embedded-ui/issues/1464)) ([9006a52](https://github.com/ydb-platform/ydb-embedded-ui/commit/9006a527be9c75227cd970eda848bf0316977616)) +* **RunningQueries:** add userSID search ([#1462](https://github.com/ydb-platform/ydb-embedded-ui/issues/1462)) ([1194b34](https://github.com/ydb-platform/ydb-embedded-ui/commit/1194b34cacacc25c7547da60e6f6ec305bfae173)) +* snippets for table (under tree dots in navigation tree) ([#1476](https://github.com/ydb-platform/ydb-embedded-ui/issues/1476)) ([39d86c9](https://github.com/ydb-platform/ydb-embedded-ui/commit/39d86c9a9492acf6d7f8b82e8713c2b412a952b8)) +* **Versions:** show overall version info in Versions tab ([#1442](https://github.com/ydb-platform/ydb-embedded-ui/issues/1442)) ([6cc07d5](https://github.com/ydb-platform/ydb-embedded-ui/commit/6cc07d5e55d1ac9d601ea9e463085fc241465988)) + + +### Bug Fixes + +* **Cluster, TabletsTable:** add node fqdn and loading state ([#1468](https://github.com/ydb-platform/ydb-embedded-ui/issues/1468)) ([4090696](https://github.com/ydb-platform/ydb-embedded-ui/commit/40906964c978189c84dfff86c9c581756d5ebfa5)) +* correct key columns order ([#1478](https://github.com/ydb-platform/ydb-embedded-ui/issues/1478)) ([da4cf1f](https://github.com/ydb-platform/ydb-embedded-ui/commit/da4cf1ffd25b7fbba374d933099be01785c6b49f)) +* exclude top and running queries itself ([#1487](https://github.com/ydb-platform/ydb-embedded-ui/issues/1487)) ([4c91b29](https://github.com/ydb-platform/ydb-embedded-ui/commit/4c91b2928c5a3504a47bbd82f65120aaafcf18c1)) +* get info about topic children from overview ([#1489](https://github.com/ydb-platform/ydb-embedded-ui/issues/1489)) ([82531a5](https://github.com/ydb-platform/ydb-embedded-ui/commit/82531a584e59ff8a6c17343e3ec18772b9e39c05)) +* popup closes on context menu copy ([#1453](https://github.com/ydb-platform/ydb-embedded-ui/issues/1453)) ([9daa5a3](https://github.com/ydb-platform/ydb-embedded-ui/commit/9daa5a384a433dac57bc5822a72df108067ef973)) +* **Tablet:** remove nodeId from header and api requests for tablet ([#1461](https://github.com/ydb-platform/ydb-embedded-ui/issues/1461)) ([e452f15](https://github.com/ydb-platform/ydb-embedded-ui/commit/e452f15b797dc85ff5af3fffe43f7fa42ad7f5bf)) +* turn off default paginated tables ([#1475](https://github.com/ydb-platform/ydb-embedded-ui/issues/1475)) ([d4f528c](https://github.com/ydb-platform/ydb-embedded-ui/commit/d4f528cafb660ddc603b1ba9f740f7d119526985)) +* **Versions:** request only SystemState ([#1481](https://github.com/ydb-platform/ydb-embedded-ui/issues/1481)) ([df74377](https://github.com/ydb-platform/ydb-embedded-ui/commit/df743773c2f259264fef82a7fd13d354c640b478)) + +## [6.25.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.24.0...v6.25.0) (2024-10-11) + + +### Features + +* **Cluster:** add Tablets tab ([#1438](https://github.com/ydb-platform/ydb-embedded-ui/issues/1438)) ([f349bcd](https://github.com/ydb-platform/ydb-embedded-ui/commit/f349bcdf758483e42aa571ba293cf3558a9d2e34)) + + +### Bug Fixes + +* do not hide pdisk and vdisk popups if mouse on popup content ([#1435](https://github.com/ydb-platform/ydb-embedded-ui/issues/1435)) ([ac70e8d](https://github.com/ydb-platform/ydb-embedded-ui/commit/ac70e8d62ec81913e0d4256900cdc4422fa44cf5)) +* **ExecuteResult:** do not show title if no result ([#1444](https://github.com/ydb-platform/ydb-embedded-ui/issues/1444)) ([78cd713](https://github.com/ydb-platform/ydb-embedded-ui/commit/78cd7137f5f77990daaca28a460766baaa5f96b1)) +* **Storage:** do not display group control if not available ([#1449](https://github.com/ydb-platform/ydb-embedded-ui/issues/1449)) ([a647026](https://github.com/ydb-platform/ydb-embedded-ui/commit/a6470263d3f9a2948be0baefcf13fbfb80b282ca)) + +## [6.24.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.23.1...v6.24.0) (2024-10-10) + + +### Features + +* add dimming to vdisk page (nodes) and pdisk page (vdisks) ([#1397](https://github.com/ydb-platform/ydb-embedded-ui/issues/1397)) ([deb2a88](https://github.com/ydb-platform/ydb-embedded-ui/commit/deb2a88d86ac0ad84f13acf1b7a3bf89289f5722)) +* **Databases:** use balancer + /node/:id as backend endpoint ([#1418](https://github.com/ydb-platform/ydb-embedded-ui/issues/1418)) ([f8a0db1](https://github.com/ydb-platform/ydb-embedded-ui/commit/f8a0db18fa01b9e9198e7c1ad4a656ba17de5922)) +* **Storage:** add disk space usage column ([#1425](https://github.com/ydb-platform/ydb-embedded-ui/issues/1425)) ([d254ee2](https://github.com/ydb-platform/ydb-embedded-ui/commit/d254ee2bd71b5028eb48b4d34c30bc5ea48fa484)) +* **StorageNodes:** add columns, use the same nodes columns ([#1396](https://github.com/ydb-platform/ydb-embedded-ui/issues/1396)) ([90a3403](https://github.com/ydb-platform/ydb-embedded-ui/commit/90a34037c8ea8e7fe8e680a47d6e1323b9fd9ff2)) +* **VDisk:** show VDisk donors inside popup ([#1422](https://github.com/ydb-platform/ydb-embedded-ui/issues/1422)) ([fc12a38](https://github.com/ydb-platform/ydb-embedded-ui/commit/fc12a38156e117e43e89b301b58df59408a98928)) + + +### Bug Fixes + +* **Authentication:** handle login error properly ([#1426](https://github.com/ydb-platform/ydb-embedded-ui/issues/1426)) ([10f817e](https://github.com/ydb-platform/ydb-embedded-ui/commit/10f817ef9879ce8fc3beddda1377a03ca285bc5f)) +* autocomplete not working in standalone version ([#1405](https://github.com/ydb-platform/ydb-embedded-ui/issues/1405)) ([8f516be](https://github.com/ydb-platform/ydb-embedded-ui/commit/8f516becf0fc0cfdd25d10abf00a41dc6953a326)) +* **cluster:** infoV2 check ([#1401](https://github.com/ydb-platform/ydb-embedded-ui/issues/1401)) ([6dbe56d](https://github.com/ydb-platform/ydb-embedded-ui/commit/6dbe56db0e3a85c44852b85477e2027f8e1754b4)) +* nodes list stops working on sort by uptime scroll down ([#1424](https://github.com/ydb-platform/ydb-embedded-ui/issues/1424)) ([5ecaecb](https://github.com/ydb-platform/ydb-embedded-ui/commit/5ecaecbfdedd47d39539e871cca8a7cf5a45e1f0)) +* **StorageGroups:** display full pool name with left cut ([#1421](https://github.com/ydb-platform/ydb-embedded-ui/issues/1421)) ([09599c1](https://github.com/ydb-platform/ydb-embedded-ui/commit/09599c1d920fc691e2e8f97ced5ccf057651ca53)) +* **StorageGroups:** fix latency column ([#1403](https://github.com/ydb-platform/ydb-embedded-ui/issues/1403)) ([5e1961c](https://github.com/ydb-platform/ydb-embedded-ui/commit/5e1961c72d2904be7a7700259c1b517c5fa997db)) +* **Storage:** prevent duplicating vdisks when no whiteboard ([#1420](https://github.com/ydb-platform/ydb-embedded-ui/issues/1420)) ([73e9e6b](https://github.com/ydb-platform/ydb-embedded-ui/commit/73e9e6bf939873c497b900286f8557ba12621917)) +* tracelevel none by default ([#1432](https://github.com/ydb-platform/ydb-embedded-ui/issues/1432)) ([1c786cb](https://github.com/ydb-platform/ydb-embedded-ui/commit/1c786cb2b62e2470b79193b6b2d10b46ed384ff6)) +* use babel loader from create-react-app ([#1409](https://github.com/ydb-platform/ydb-embedded-ui/issues/1409)) ([0a4734e](https://github.com/ydb-platform/ydb-embedded-ui/commit/0a4734ebc54c036c422fd269e8e6b691af5a6b5d)) + +## [6.23.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.23.0...v6.23.1) (2024-10-03) + + +### Bug Fixes + +* **Cluster:** contatiner should take its parent width ([#1393](https://github.com/ydb-platform/ydb-embedded-ui/issues/1393)) ([a34bb3e](https://github.com/ydb-platform/ydb-embedded-ui/commit/a34bb3e1248a4656887b25118e4d4b153aa485b7)) + +## [6.23.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.22.0...v6.23.0) (2024-10-02) + + +### Features + +* dim vdisks on the node page that are not on the selected node ([#1369](https://github.com/ydb-platform/ydb-embedded-ui/issues/1369)) ([446019f](https://github.com/ydb-platform/ydb-embedded-ui/commit/446019f06ecd26c775dbf59fc9d5bed0b786f0ca)) +* **ExecuteResult:** add row count for all results ([#1368](https://github.com/ydb-platform/ydb-embedded-ui/issues/1368)) ([570507e](https://github.com/ydb-platform/ydb-embedded-ui/commit/570507e911d339fc994df4d0d9ebf7c4e9f0ed94)) +* move query templates to a hierarchical menu at query editor ([#1327](https://github.com/ydb-platform/ydb-embedded-ui/issues/1327)) ([960e97f](https://github.com/ydb-platform/ydb-embedded-ui/commit/960e97fcdf1e2d358006abd7811e92c1243f2109)) +* **Nodes:** add node name column ([#1385](https://github.com/ydb-platform/ydb-embedded-ui/issues/1385)) ([a4c24e1](https://github.com/ydb-platform/ydb-embedded-ui/commit/a4c24e147b9e09c1675ee6a597b3c8e56f1602d7)) +* **PaginatedStorage:** add grouping ([#1364](https://github.com/ydb-platform/ydb-embedded-ui/issues/1364)) ([93dd920](https://github.com/ydb-platform/ydb-embedded-ui/commit/93dd9200a0a299195f7887fa2b04c3b0e5c4d476)) +* show running queries ([#1313](https://github.com/ydb-platform/ydb-embedded-ui/issues/1313)) ([acd4a1e](https://github.com/ydb-platform/ydb-embedded-ui/commit/acd4a1ec7e83806aef106168e843f196879d71e7)) +* **StorageGroups:** add latency and allocation units columns ([#1390](https://github.com/ydb-platform/ydb-embedded-ui/issues/1390)) ([4cb6fed](https://github.com/ydb-platform/ydb-embedded-ui/commit/4cb6fedc30b969c0e5a38e18415145389e9dc86a)) +* use relative entity path in schema actions ([#1366](https://github.com/ydb-platform/ydb-embedded-ui/issues/1366)) ([418d3d8](https://github.com/ydb-platform/ydb-embedded-ui/commit/418d3d8a74256b4eee2e74084a11acc61e819f11)) + + +### Bug Fixes + +* always show required columns ([#1374](https://github.com/ydb-platform/ydb-embedded-ui/issues/1374)) ([6cab2df](https://github.com/ydb-platform/ydb-embedded-ui/commit/6cab2df320535cb0c4fdcd163608f677e2c603a6)) +* **Diagnostics:** hide graph for column tables ([#1356](https://github.com/ydb-platform/ydb-embedded-ui/issues/1356)) ([4fe1a24](https://github.com/ydb-platform/ydb-embedded-ui/commit/4fe1a24a90e2bf2d86ef9c665ce6cb71d24519ea)) +* different measurements look confusing ([#1381](https://github.com/ydb-platform/ydb-embedded-ui/issues/1381)) ([5f26767](https://github.com/ydb-platform/ydb-embedded-ui/commit/5f2676737a6f2733c30562f69b3f80fb06229a7e)) +* fix columns width on long rowset ([#1384](https://github.com/ydb-platform/ydb-embedded-ui/issues/1384)) ([f30a38f](https://github.com/ydb-platform/ydb-embedded-ui/commit/f30a38f5801b3a3eef2ca8c44fa980718682e76e)) +* **Header:** show cluster name in breadcrumb for PDisk/VDisk pages ([#1357](https://github.com/ydb-platform/ydb-embedded-ui/issues/1357)) ([56839bc](https://github.com/ydb-platform/ydb-embedded-ui/commit/56839bc12bccd3874f7270e2951711f8d3811068)) +* **PaginatedStorage:** properly pass ids, display 1 node on Node page ([#1382](https://github.com/ydb-platform/ydb-embedded-ui/issues/1382)) ([e63d22b](https://github.com/ydb-platform/ydb-embedded-ui/commit/e63d22b41d85059f66d311b299b28a330097669a)) +* **PDisk:** show node host name in popup ([#1352](https://github.com/ydb-platform/ydb-embedded-ui/issues/1352)) ([12010dd](https://github.com/ydb-platform/ydb-embedded-ui/commit/12010ddd75d90b1e3f30e55916e39481298858b4)) +* **Storage:** completely remove usage filter ([#1375](https://github.com/ydb-platform/ydb-embedded-ui/issues/1375)) ([d200b4c](https://github.com/ydb-platform/ydb-embedded-ui/commit/d200b4c0d07060b946fb03d9332895f8b2583d41)) +* **StorageNodes:** uniform render type ([#1376](https://github.com/ydb-platform/ydb-embedded-ui/issues/1376)) ([9e25733](https://github.com/ydb-platform/ydb-embedded-ui/commit/9e2573363f3e1c9aa54a5ed47d37821fffcdbc41)) + +## [6.22.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.21.0...v6.22.0) (2024-09-24) + + +### Features + +* add rows limit to query settings ([#1291](https://github.com/ydb-platform/ydb-embedded-ui/issues/1291)) ([1728e61](https://github.com/ydb-platform/ydb-embedded-ui/commit/1728e6162e5be9c5fdc0954595b562873ad6fb9b)) +* big query results freeze interface ([#1354](https://github.com/ydb-platform/ydb-embedded-ui/issues/1354)) ([660f89c](https://github.com/ydb-platform/ydb-embedded-ui/commit/660f89cd696f85b2ea61ce31a64e7ef2d70f9283)) +* in query results show when it was truncated ([#1309](https://github.com/ydb-platform/ydb-embedded-ui/issues/1309)) ([0434410](https://github.com/ydb-platform/ydb-embedded-ui/commit/043441045d5e9cc463271da505bec6bf04489f5d)) +* **Nodes:** add columns setup ([#1320](https://github.com/ydb-platform/ydb-embedded-ui/issues/1320)) ([c9ec3b7](https://github.com/ydb-platform/ydb-embedded-ui/commit/c9ec3b790d461ea150d315bb0f364e979218f788)) +* **ObjectSummary:** add link to Schema in Diagnostics ([#1323](https://github.com/ydb-platform/ydb-embedded-ui/issues/1323)) ([deaf519](https://github.com/ydb-platform/ydb-embedded-ui/commit/deaf519c35b7df50919bf12de6fd87fe2a764aa9)) +* **ObjectSummary:** add paths and shards limits ([#1326](https://github.com/ydb-platform/ydb-embedded-ui/issues/1326)) ([61c3562](https://github.com/ydb-platform/ydb-embedded-ui/commit/61c3562ea569b217d2fffb5622b38d2054240aeb)) +* show vdisks of selected group in a special color ([#1336](https://github.com/ydb-platform/ydb-embedded-ui/issues/1336)) ([5402c86](https://github.com/ydb-platform/ydb-embedded-ui/commit/5402c86a9a07f8999bb084ac2d50ebda54c9adc6)) +* **Storage:** add columns setup ([#1321](https://github.com/ydb-platform/ydb-embedded-ui/issues/1321)) ([b53487e](https://github.com/ydb-platform/ydb-embedded-ui/commit/b53487e7a6ad5779dbc02b08eaf4b1a9929021b6)) + + +### Bug Fixes + +* **Clusters:** fix columns setup do not save values ([#1316](https://github.com/ydb-platform/ydb-embedded-ui/issues/1316)) ([964122f](https://github.com/ydb-platform/ydb-embedded-ui/commit/964122f5560cff67fcb3562cfa7ee05f33646b5b)) +* do not send empty strings in filters ([#1330](https://github.com/ydb-platform/ydb-embedded-ui/issues/1330)) ([5af61ac](https://github.com/ydb-platform/ydb-embedded-ui/commit/5af61acd52202c58815883bcfa179bfcbaabc8c3)) +* show structure tab and PDisk/VDisk if disk's new API is absent ([#1338](https://github.com/ydb-platform/ydb-embedded-ui/issues/1338)) ([6213ed7](https://github.com/ydb-platform/ydb-embedded-ui/commit/6213ed7856a80cb2158bc0ff1af79ed160b3b3f1)) +* **Storage:** fix additional props not passed ([#1350](https://github.com/ydb-platform/ydb-embedded-ui/issues/1350)) ([e8beb49](https://github.com/ydb-platform/ydb-embedded-ui/commit/e8beb4900685be5c7d7c339364d3941bd25fadda)) +* **StorageGroups:** make group id first column ([#1351](https://github.com/ydb-platform/ydb-embedded-ui/issues/1351)) ([73642db](https://github.com/ydb-platform/ydb-embedded-ui/commit/73642db54728fb15be91de64e9ca0eb60ac2a857)) + +## [6.21.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.20.0...v6.21.0) (2024-09-18) + + +### Features + +* add storage group page ([#1289](https://github.com/ydb-platform/ydb-embedded-ui/issues/1289)) ([8e05166](https://github.com/ydb-platform/ydb-embedded-ui/commit/8e05166388964c9fbe01984723c8d3e4cedd48a8)) + + +### Bug Fixes + +* **api:** correctly get cluster info from data (/meta/db_clusters) ([#1314](https://github.com/ydb-platform/ydb-embedded-ui/issues/1314)) ([762f8ed](https://github.com/ydb-platform/ydb-embedded-ui/commit/762f8ede6cda7b3f3e20eb7d69286d5ff76ea627)) +* check feature flag api is available ([#1308](https://github.com/ydb-platform/ydb-embedded-ui/issues/1308)) ([8531b95](https://github.com/ydb-platform/ydb-embedded-ui/commit/8531b954cd8870c5ecf7495064a5bac65aea55d6)) + +## [6.20.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.19.0...v6.20.0) (2024-09-17) + + +### Features + +* use new /viewer/cluster handler format ([#1272](https://github.com/ydb-platform/ydb-embedded-ui/issues/1272)) ([f0742ab](https://github.com/ydb-platform/ydb-embedded-ui/commit/f0742ab480bf595f7b5a250dcbd23d33f15ea523)) + + +### Bug Fixes + +* **DecommissionButton:** add checkbox to dialog ([#1294](https://github.com/ydb-platform/ydb-embedded-ui/issues/1294)) ([6d65839](https://github.com/ydb-platform/ydb-embedded-ui/commit/6d6583951e31d2ad407077dbd9c9b29472a4983a)) +* **queries:** do not fail on response with 200 code and null body ([#1304](https://github.com/ydb-platform/ydb-embedded-ui/issues/1304)) ([d115989](https://github.com/ydb-platform/ydb-embedded-ui/commit/d115989a8ad0479a8269507df14c4b533f7d2084)) +* remove break nodes setting, remove compute ([#1306](https://github.com/ydb-platform/ydb-embedded-ui/issues/1306)) ([de315ae](https://github.com/ydb-platform/ydb-embedded-ui/commit/de315ae980b3e7d4bbea48f1497934d11180002a)) + +## [6.19.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.18.0...v6.19.0) (2024-09-13) + + +### Features + +* add storage/groups endpoint ([#1273](https://github.com/ydb-platform/ydb-embedded-ui/issues/1273)) ([42ee9a4](https://github.com/ydb-platform/ydb-embedded-ui/commit/42ee9a470632807650cfc0dd934f5b0a3d30c909)) +* **Diagnostics:** display db feature flags ([#1229](https://github.com/ydb-platform/ydb-embedded-ui/issues/1229)) ([182d803](https://github.com/ydb-platform/ydb-embedded-ui/commit/182d803205667794f16811de1be5ea685b1478e8)) +* **Header:** use cluster domain if cluster name is undefined ([#1271](https://github.com/ydb-platform/ydb-embedded-ui/issues/1271)) ([125d556](https://github.com/ydb-platform/ydb-embedded-ui/commit/125d556810a4013aee9a97bfde3db27f3e4e0b5b)) +* **Node:** enable nodes switch in storage tab on node page ([#1277](https://github.com/ydb-platform/ydb-embedded-ui/issues/1277)) ([07560ed](https://github.com/ydb-platform/ydb-embedded-ui/commit/07560ed8fca8cedbd473f629267522596d1ecb35)) +* **package:** export AsideNavigation ([#1262](https://github.com/ydb-platform/ydb-embedded-ui/issues/1262)) ([bb647f5](https://github.com/ydb-platform/ydb-embedded-ui/commit/bb647f5588a7ddcf11b3efa45067b79462159e97)) +* paginated table fixes ([#1265](https://github.com/ydb-platform/ydb-embedded-ui/issues/1265)) ([d0ef412](https://github.com/ydb-platform/ydb-embedded-ui/commit/d0ef412197f84542faff019e524855bf81989315)) +* use /db_clusters to get base cluster info ([#1251](https://github.com/ydb-platform/ydb-embedded-ui/issues/1251)) ([cd8c7dc](https://github.com/ydb-platform/ydb-embedded-ui/commit/cd8c7dc69364eedfcb490060ca1cdd2d0b4e1e77)) +* use groups handler for storage ([#1225](https://github.com/ydb-platform/ydb-embedded-ui/issues/1225)) ([45c0a1e](https://github.com/ydb-platform/ydb-embedded-ui/commit/45c0a1e8dc15eb4a404177a6f02e3e947d9a27e2)) + + +### Bug Fixes + +* **autocomplete:** do not lose folder if its name is equals to database ([#1290](https://github.com/ydb-platform/ydb-embedded-ui/issues/1290)) ([f22bdba](https://github.com/ydb-platform/ydb-embedded-ui/commit/f22bdbab6493a07c6150d7a6a52b4064f62f58ac)) +* better retry timeout for traces ([#1263](https://github.com/ydb-platform/ydb-embedded-ui/issues/1263)) ([400a526](https://github.com/ydb-platform/ydb-embedded-ui/commit/400a526d9b587563eb977c33e70d0134f41d861d)) +* gh-pages commit history ([#1275](https://github.com/ydb-platform/ydb-embedded-ui/issues/1275)) ([f09ccd3](https://github.com/ydb-platform/ydb-embedded-ui/commit/f09ccd3d8fe7fa87b1b162ef386c6dd01f69eb4f)) +* **PaginatedStorageNodes:** increase row height ([#1282](https://github.com/ydb-platform/ydb-embedded-ui/issues/1282)) ([08e4308](https://github.com/ydb-platform/ydb-embedded-ui/commit/08e43089fd99ad762d1d6c0300c9c07e5c07dc00)) +* unnecessary background refresh on query page ([#1256](https://github.com/ydb-platform/ydb-embedded-ui/issues/1256)) ([04b4313](https://github.com/ydb-platform/ydb-embedded-ui/commit/04b431377e143c002426c39ceca713dbe14cd23e)) +* update alter table query template ([#1284](https://github.com/ydb-platform/ydb-embedded-ui/issues/1284)) ([4bf43af](https://github.com/ydb-platform/ydb-embedded-ui/commit/4bf43aff05acd1ab20f670e77b3bdd42c9213d42)) + +## [6.18.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.17.2...v6.18.0) (2024-09-04) + + +### Features + +* **PDiskPage:** add decommission button ([#1168](https://github.com/ydb-platform/ydb-embedded-ui/issues/1168)) ([d3e5f70](https://github.com/ydb-platform/ydb-embedded-ui/commit/d3e5f70a4b71e95f6f42478b979a1157c80e6a36)) +* show query trace results ([#1248](https://github.com/ydb-platform/ydb-embedded-ui/issues/1248)) ([2be0f0b](https://github.com/ydb-platform/ydb-embedded-ui/commit/2be0f0b6aa931bf68597370923e7815935db4ba8)) +* **Storage:** add advanced disks view ([#1235](https://github.com/ydb-platform/ydb-embedded-ui/issues/1235)) ([3d780aa](https://github.com/ydb-platform/ydb-embedded-ui/commit/3d780aa4c6724f75a811c5d75061c2febd81a4a3)) + + +### Bug Fixes + +* **PaginatedTable:** fix table overflow, make column width optional ([#1234](https://github.com/ydb-platform/ydb-embedded-ui/issues/1234)) ([2d06930](https://github.com/ydb-platform/ydb-embedded-ui/commit/2d069305167ffb0b47c2d0e59ed2057dc73e649c)) +* **Tablet:** preserve query params when switch tabs ([#1254](https://github.com/ydb-platform/ydb-embedded-ui/issues/1254)) ([c79ccbc](https://github.com/ydb-platform/ydb-embedded-ui/commit/c79ccbc5c9a07b664620c3e3155d24f2754844b5)) +* **TopShards:** fix data update on schema object change ([#1245](https://github.com/ydb-platform/ydb-embedded-ui/issues/1245)) ([024fec4](https://github.com/ydb-platform/ydb-embedded-ui/commit/024fec40a4395a31e4780f7ab2206b25d0762e82)) + +## [6.17.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.17.1...v6.17.2) (2024-09-02) + + +### Bug Fixes + +* add implicit transaction_mode to query settings ([#1240](https://github.com/ydb-platform/ydb-embedded-ui/issues/1240)) ([75a0d89](https://github.com/ydb-platform/ydb-embedded-ui/commit/75a0d892bd30b31da49e1b0e56de87eb13ec00b8)) + +## [6.17.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.17.0...v6.17.1) (2024-08-30) + + +### Bug Fixes + +* **PaginatedTable:** fix layout ([#1237](https://github.com/ydb-platform/ydb-embedded-ui/issues/1237)) ([fc22275](https://github.com/ydb-platform/ydb-embedded-ui/commit/fc2227553b92ce2b0850a949f1636397b3307784)) + +## [6.17.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.16.0...v6.17.0) (2024-08-29) + + +### Features + +* add setting to add tracing to all requests ([#1218](https://github.com/ydb-platform/ydb-embedded-ui/issues/1218)) ([d7df777](https://github.com/ydb-platform/ydb-embedded-ui/commit/d7df77750d123be881264993c2333c1767a8b66c)) +* display all types of keys as plain text ([#1219](https://github.com/ydb-platform/ydb-embedded-ui/issues/1219)) ([13d21cb](https://github.com/ydb-platform/ydb-embedded-ui/commit/13d21cb3bfcca00138e08f83b00cc4068d12dc51)) +* **Tablets:** pass database and nodeId params to api handler ([#1199](https://github.com/ydb-platform/ydb-embedded-ui/issues/1199)) ([c049f75](https://github.com/ydb-platform/ydb-embedded-ui/commit/c049f75f0bbd140e40c3caa196a95e0c702ce091)) +* **VDiskPage:** use storage table instead of storage info ([#1209](https://github.com/ydb-platform/ydb-embedded-ui/issues/1209)) ([027c668](https://github.com/ydb-platform/ydb-embedded-ui/commit/027c668d917b216646ec15f659707dc146b23d87)) + + +### Bug Fixes + +* **AsyncReplicationInfo:** do not show empty fields ([#1189](https://github.com/ydb-platform/ydb-embedded-ui/issues/1189)) ([7b1eff6](https://github.com/ydb-platform/ydb-embedded-ui/commit/7b1eff693c4e4440b96f7a9d2628b916d9d58131)) +* incorrect database count with hidden root ([#1206](https://github.com/ydb-platform/ydb-embedded-ui/issues/1206)) ([c0f716f](https://github.com/ydb-platform/ydb-embedded-ui/commit/c0f716f3e30df1ae00aaad231748a8807e395359)) +* **Overview:** use nodes?group=Version to get node versions ([#1230](https://github.com/ydb-platform/ydb-embedded-ui/issues/1230)) ([d95ea95](https://github.com/ydb-platform/ydb-embedded-ui/commit/d95ea95c3cd392b9e7052268703b469212c0f508)) +* paginated tables not working in safari ([#1231](https://github.com/ydb-platform/ydb-embedded-ui/issues/1231)) ([7162aeb](https://github.com/ydb-platform/ydb-embedded-ui/commit/7162aeb81e1bd453eb8f401a359f922716dd6148)) +* remove binary data setting description ([#1180](https://github.com/ydb-platform/ydb-embedded-ui/issues/1180)) ([ec46259](https://github.com/ydb-platform/ydb-embedded-ui/commit/ec46259195e213c0d5c65aca6857ce3b65b32f75)) +* set ErrorBoundary max width ([#1221](https://github.com/ydb-platform/ydb-embedded-ui/issues/1221)) ([3191b31](https://github.com/ydb-platform/ydb-embedded-ui/commit/3191b31e0a42970ed4cdd25b21f313381cb57eb5)) +* **store:** remove unused params from url mapping ([#1227](https://github.com/ydb-platform/ydb-embedded-ui/issues/1227)) ([be442a0](https://github.com/ydb-platform/ydb-embedded-ui/commit/be442a055a50003ad189a12e372cdf7a2a4d0de8)) +* **Versions:** use /nodes instead of /sysinfo to collect versions ([#1220](https://github.com/ydb-platform/ydb-embedded-ui/issues/1220)) ([217d77b](https://github.com/ydb-platform/ydb-embedded-ui/commit/217d77bab69a8e2277de3e4077c3f407b36cd70c)) + +## [6.16.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.15.1...v6.16.0) (2024-08-21) + + +### Features + +* [query settings] display trace level selector ([#1170](https://github.com/ydb-platform/ydb-embedded-ui/issues/1170)) ([f1ab08c](https://github.com/ydb-platform/ydb-embedded-ui/commit/f1ab08c3146135b6fef039ce541311bf2ca73fba)) +* **Describe:** add button to copy content to clipboard ([#1192](https://github.com/ydb-platform/ydb-embedded-ui/issues/1192)) ([dc64506](https://github.com/ydb-platform/ydb-embedded-ui/commit/dc64506f3f4fc6a8bf9a1b9a7cad5fc40a12cd38)) +* **diagnostics:** render bloom filter better ([#1165](https://github.com/ydb-platform/ydb-embedded-ui/issues/1165)) ([0562b0c](https://github.com/ydb-platform/ydb-embedded-ui/commit/0562b0cf8c2b949ad80a765a2b7bce407b100c4a)) +* duration & endtime in queries history ([#1169](https://github.com/ydb-platform/ydb-embedded-ui/issues/1169)) ([f28402c](https://github.com/ydb-platform/ydb-embedded-ui/commit/f28402caed4002f86f265d1b003c2b0b8845eda2)) +* enable autorefresh for paginated tables ([#1146](https://github.com/ydb-platform/ydb-embedded-ui/issues/1146)) ([2519c80](https://github.com/ydb-platform/ydb-embedded-ui/commit/2519c80a2807572fe64efbe4360fdcb0f02b533a)) +* **Tablet:** redesign tablet page, add data from hive ([#1183](https://github.com/ydb-platform/ydb-embedded-ui/issues/1183)) ([ab3528b](https://github.com/ydb-platform/ydb-embedded-ui/commit/ab3528bd4b1d3a806bd677ac37accb29dc8e5a04)) + + +### Bug Fixes + +* default value fixes ([#1166](https://github.com/ydb-platform/ydb-embedded-ui/issues/1166)) ([a210ba1](https://github.com/ydb-platform/ydb-embedded-ui/commit/a210ba17f9f022062e30fc86ca047a245de41313)) +* do not reset query results when switch query tabs ([#1198](https://github.com/ydb-platform/ydb-embedded-ui/issues/1198)) ([8be55f1](https://github.com/ydb-platform/ydb-embedded-ui/commit/8be55f1ea710a72b40a30f48a6b20095c89420f0)) +* **Nodes:** pass database param to nodes api handler ([#1197](https://github.com/ydb-platform/ydb-embedded-ui/issues/1197)) ([345600f](https://github.com/ydb-platform/ydb-embedded-ui/commit/345600ff227e2f3383dbd9f838ee2221fe31a744)) +* preview hides when opening query settings ([#1187](https://github.com/ydb-platform/ydb-embedded-ui/issues/1187)) ([5b80904](https://github.com/ydb-platform/ydb-embedded-ui/commit/5b80904e22ca80383d2e7e0e52d6775da384e2b1)) +* use-QueryService-by-default-for-running-queries-1171 ([#1188](https://github.com/ydb-platform/ydb-embedded-ui/issues/1188)) ([62de3e6](https://github.com/ydb-platform/ydb-embedded-ui/commit/62de3e64e1ec139586ce06ae2111137ca2416caf)) + +## [6.15.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.15.0...v6.15.1) (2024-08-16) + + +### Bug Fixes + +* **api:** do not duplicate request params on retry ([#1105](https://github.com/ydb-platform/ydb-embedded-ui/issues/1105)) ([0580adc](https://github.com/ydb-platform/ydb-embedded-ui/commit/0580adc64a37c6ef6b776a9499a6b10fffa926d9)) +* autorefresh control doesnt update info tab in diagnostics ([#1163](https://github.com/ydb-platform/ydb-embedded-ui/issues/1163)) ([ac380ba](https://github.com/ydb-platform/ydb-embedded-ui/commit/ac380ba2394351610d1ca3873825d08b0749f5ab)) +* base64 flag both in sendQuery params and body ([#1172](https://github.com/ydb-platform/ydb-embedded-ui/issues/1172)) ([57f393b](https://github.com/ydb-platform/ydb-embedded-ui/commit/57f393b140a9bd4bfad13a48f6184591ba43a997)) +* **Preview:** remove wrong and stale styles ([#1162](https://github.com/ydb-platform/ydb-embedded-ui/issues/1162)) ([8134a64](https://github.com/ydb-platform/ydb-embedded-ui/commit/8134a64857bff8d6d76a8a23889dad42ed3c3a66)) +* **Tenant:** fix infinite load if describe returns empty data ([#1167](https://github.com/ydb-platform/ydb-embedded-ui/issues/1167)) ([8535629](https://github.com/ydb-platform/ydb-embedded-ui/commit/853562925727e5334750f6e5a2e1e398c2a17623)) + +## [6.15.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.14.1...v6.15.0) (2024-08-14) + + +### Features + +* **Acl:** support InterruptInheritance, fix styles ([#1154](https://github.com/ydb-platform/ydb-embedded-ui/issues/1154)) ([89804af](https://github.com/ydb-platform/ydb-embedded-ui/commit/89804aff8397e2f9ae4fee02396bdaf6acae6de3)) +* search in queries history & saved ([#1127](https://github.com/ydb-platform/ydb-embedded-ui/issues/1127)) ([efd5813](https://github.com/ydb-platform/ydb-embedded-ui/commit/efd5813bcea7777eb3f4bde10de3b1f28f724502)) +* table preview doesnt update on click ([#1152](https://github.com/ydb-platform/ydb-embedded-ui/issues/1152)) ([512786c](https://github.com/ydb-platform/ydb-embedded-ui/commit/512786ccabcd866a21d69c2e12564c9b198c8132)) + + +### Bug Fixes + +* completed query status on page load ([#1132](https://github.com/ydb-platform/ydb-embedded-ui/issues/1132)) ([2fa6922](https://github.com/ydb-platform/ydb-embedded-ui/commit/2fa69229e40103750b7ded1ef828665e7a6aa082)) +* **CriticalActionDialog:** increase padding-top ([#1149](https://github.com/ydb-platform/ydb-embedded-ui/issues/1149)) ([aa1f0a2](https://github.com/ydb-platform/ydb-embedded-ui/commit/aa1f0a228a3c95c65e3deada0ea0b11be958022f)) +* detect object that looks like axios error ([#1145](https://github.com/ydb-platform/ydb-embedded-ui/issues/1145)) ([085e116](https://github.com/ydb-platform/ydb-embedded-ui/commit/085e116ff62f0ce022c3df047e2273e190fe5999)) +* do not show Authentication page before redirect ([#1139](https://github.com/ydb-platform/ydb-embedded-ui/issues/1139)) ([e266c8f](https://github.com/ydb-platform/ydb-embedded-ui/commit/e266c8fc95fef4f9e34d56f82cd57c0b20b89ff6)) +* don't show data for un auth user ([#1150](https://github.com/ydb-platform/ydb-embedded-ui/issues/1150)) ([bc17fa4](https://github.com/ydb-platform/ydb-embedded-ui/commit/bc17fa459375611c8a8863a028bc57459410e8df)) +* remove tablets from some api handlers ([#1148](https://github.com/ydb-platform/ydb-embedded-ui/issues/1148)) ([b05bff3](https://github.com/ydb-platform/ydb-embedded-ui/commit/b05bff3b20c364b218c3d6f71061570cc6779f39)) +* **VDiskInfo:** hide developer ui link for users with viewer rights ([#1137](https://github.com/ydb-platform/ydb-embedded-ui/issues/1137)) ([86104e3](https://github.com/ydb-platform/ydb-embedded-ui/commit/86104e31a6ba335c33a481b322d429205732641b)) + +## [6.14.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.14.0...v6.14.1) (2024-08-07) + + +### Bug Fixes + +* package build ([#1129](https://github.com/ydb-platform/ydb-embedded-ui/issues/1129)) ([ea8aa29](https://github.com/ydb-platform/ydb-embedded-ui/commit/ea8aa29e8446679bf34f5c5bbc6033cb2482b6b4)) + +## [6.14.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.13.0...v6.14.0) (2024-08-07) + + +### Features + +* copy json query stats ([#1113](https://github.com/ydb-platform/ydb-embedded-ui/issues/1113)) ([e9cfa8a](https://github.com/ydb-platform/ydb-embedded-ui/commit/e9cfa8a7cc8dad7a1dc3fca354419a3af9a852bf)) +* display relative schema object path on left overview tab ([#1118](https://github.com/ydb-platform/ydb-embedded-ui/issues/1118)) ([c55164c](https://github.com/ydb-platform/ydb-embedded-ui/commit/c55164c4f6688ee61e520a9eebaa4b2382600a06)) +* **e2e:** add warmup for e2e ([#1122](https://github.com/ydb-platform/ydb-embedded-ui/issues/1122)) ([c15dc1a](https://github.com/ydb-platform/ydb-embedded-ui/commit/c15dc1a1a3954cab96abbf76edfb232321485d99)) +* remove tablets column from databases table ([#1121](https://github.com/ydb-platform/ydb-embedded-ui/issues/1121)) ([68c3972](https://github.com/ydb-platform/ydb-embedded-ui/commit/68c39726fccb24725bb47aaaad1beadc7d2b26bf)) +* stop running query ([#1117](https://github.com/ydb-platform/ydb-embedded-ui/issues/1117)) ([a30258f](https://github.com/ydb-platform/ydb-embedded-ui/commit/a30258f1f362d6a1aa2e098e197fb03d90abee2b)) + + +### Bug Fixes + +* **e2e:** use baseurl from config ([#1123](https://github.com/ydb-platform/ydb-embedded-ui/issues/1123)) ([d0efbb1](https://github.com/ydb-platform/ydb-embedded-ui/commit/d0efbb13cbf61accce10e453f408681560d59f3d)) +* pass database to topic api handlers ([#1128](https://github.com/ydb-platform/ydb-embedded-ui/issues/1128)) ([b23fc79](https://github.com/ydb-platform/ydb-embedded-ui/commit/b23fc79548b8bdea31d86505bd56ee2baf6d8c1a)) +* schema in sendQuery is only query parameter ([#1119](https://github.com/ydb-platform/ydb-embedded-ui/issues/1119)) ([5bb0461](https://github.com/ydb-platform/ydb-embedded-ui/commit/5bb0461b98eb7d5d5deba99199b447abda013fe4)) +* **SimplifiedPlan:** should hide dividers if item is collapsed ([#1124](https://github.com/ydb-platform/ydb-embedded-ui/issues/1124)) ([5759e1b](https://github.com/ydb-platform/ydb-embedded-ui/commit/5759e1b5aaa6865eb45f6dda4cbdd0cee91ed533)) + +## [6.13.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.12.0...v6.13.0) (2024-08-02) + + +### Features + +* add flaky tests and bundle size ([#1109](https://github.com/ydb-platform/ydb-embedded-ui/issues/1109)) ([e343a13](https://github.com/ydb-platform/ydb-embedded-ui/commit/e343a13c4cffd7bb6682183208736b3179451056)) +* check whoami before other requests ([#1103](https://github.com/ydb-platform/ydb-embedded-ui/issues/1103)) ([70b6dc3](https://github.com/ydb-platform/ydb-embedded-ui/commit/70b6dc3f116aac1a2d86144f5c2a6091c7294190)) +* **Diagnostics:** display column's default value in diagnostics schema ([#1102](https://github.com/ydb-platform/ydb-embedded-ui/issues/1102)) ([97013c3](https://github.com/ydb-platform/ydb-embedded-ui/commit/97013c3cc7580feb58e03be4b61cb344319d61a2)) +* **ExecuteResult:** show query schema with stats ([#1083](https://github.com/ydb-platform/ydb-embedded-ui/issues/1083)) ([eb6c746](https://github.com/ydb-platform/ydb-embedded-ui/commit/eb6c7462248c5c308bc9c33a183b3a88531495ab)) +* **ExecuteResult:** show simplified plan ([#1098](https://github.com/ydb-platform/ydb-embedded-ui/issues/1098)) ([0a18fab](https://github.com/ydb-platform/ydb-embedded-ui/commit/0a18fabdbb9302cdb09b3aac3e14451308f70c38)) +* **ExplainResult:** add visualization for simplified query plan ([#1061](https://github.com/ydb-platform/ydb-embedded-ui/issues/1061)) ([73c53dd](https://github.com/ydb-platform/ydb-embedded-ui/commit/73c53dd77a54627df95b2f9148f993b156719fcb)) +* move test reports ([#1106](https://github.com/ydb-platform/ydb-embedded-ui/issues/1106)) ([5f8a852](https://github.com/ydb-platform/ydb-embedded-ui/commit/5f8a8522e8cd011e750abf11bb58e966ed37a753)) +* option to hide domain ([#1094](https://github.com/ydb-platform/ydb-embedded-ui/issues/1094)) ([8b2fb41](https://github.com/ydb-platform/ydb-embedded-ui/commit/8b2fb412d2744cd470f321d3d944702984cfce60)) +* **PDiskPage:** add force restart ([#1073](https://github.com/ydb-platform/ydb-embedded-ui/issues/1073)) ([27f7350](https://github.com/ydb-platform/ydb-embedded-ui/commit/27f7350d60507890ef07d1a640fdea2d795d696f)) +* release query settings dialog (and ci test reports) ([#1101](https://github.com/ydb-platform/ydb-embedded-ui/issues/1101)) ([d0ef39c](https://github.com/ydb-platform/ydb-embedded-ui/commit/d0ef39c2456dd2b51897f79efbdddb2fa0e0b8f6)) +* settings usage in requests and modification ([#1068](https://github.com/ydb-platform/ydb-embedded-ui/issues/1068)) ([c767175](https://github.com/ydb-platform/ydb-embedded-ui/commit/c767175d483214a4b05c60f26e0be2e2b994eb04)) +* show cached data on errors ([#1095](https://github.com/ydb-platform/ydb-embedded-ui/issues/1095)) ([d38f0f0](https://github.com/ydb-platform/ydb-embedded-ui/commit/d38f0f08a677afd8f30c86ced5d032569081eab4)) +* use features versions from backend ([#1097](https://github.com/ydb-platform/ydb-embedded-ui/issues/1097)) ([3f041de](https://github.com/ydb-platform/ydb-embedded-ui/commit/3f041de928f48c8f9e31264647ef68066c0f73bd)) +* **VDiskPage:** add force evict ([#1093](https://github.com/ydb-platform/ydb-embedded-ui/issues/1093)) ([97dfcfb](https://github.com/ydb-platform/ydb-embedded-ui/commit/97dfcfb318952b33a146d77f2960b7a2d3524752)) + + +### Bug Fixes + +* infinite describe requests ([#1086](https://github.com/ydb-platform/ydb-embedded-ui/issues/1086)) ([a8ee1a7](https://github.com/ydb-platform/ydb-embedded-ui/commit/a8ee1a7e62c7bf4b5f5dd828afd39cfcefd84535)) +* **Nodes:** better memory bars ([#1091](https://github.com/ydb-platform/ydb-embedded-ui/issues/1091)) ([87f2b92](https://github.com/ydb-platform/ydb-embedded-ui/commit/87f2b92aef40d40ff7af21b19d57b2c2f66528e5)) +* **QueryHistory:** query history not saving ([#1111](https://github.com/ydb-platform/ydb-embedded-ui/issues/1111)) ([b5df0d6](https://github.com/ydb-platform/ydb-embedded-ui/commit/b5df0d64c9617d28a912a3e7a8a23e368e3786ba)) +* **QuerySettingsForm:** remove excessive updates ([#1099](https://github.com/ydb-platform/ydb-embedded-ui/issues/1099)) ([a41bbff](https://github.com/ydb-platform/ydb-embedded-ui/commit/a41bbffebd0fb6d35ae1b50d5354aa5861800ba3)) +* tests not running ([#1108](https://github.com/ydb-platform/ydb-embedded-ui/issues/1108)) ([eb5a627](https://github.com/ydb-platform/ydb-embedded-ui/commit/eb5a627974c6b93c7fa89bc8d3ba7512a262ee4c)) + +## [6.12.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.11.0...v6.12.0) (2024-07-29) + + +### Features + +* add effective ACL ([#1036](https://github.com/ydb-platform/ydb-embedded-ui/issues/1036)) ([bce4e92](https://github.com/ydb-platform/ydb-embedded-ui/commit/bce4e926d6395dcfc53d14e6ea373073ef724145)) +* cpu info toggle – display top queries for last hour ([#1049](https://github.com/ydb-platform/ydb-embedded-ui/issues/1049)) ([1fb9078](https://github.com/ydb-platform/ydb-embedded-ui/commit/1fb9078c8ea76c237a5397f74397663eb0b0f7d3)) +* **PDiskPage:** add disk space distribution ([#1029](https://github.com/ydb-platform/ydb-embedded-ui/issues/1029)) ([82375c3](https://github.com/ydb-platform/ydb-embedded-ui/commit/82375c39b67a23046e673e4172aa29bbde659ab5)) +* **PDiskPage:** add pdisk attributes, display in 2 columns ([#1069](https://github.com/ydb-platform/ydb-embedded-ui/issues/1069)) ([d3b3d9b](https://github.com/ydb-platform/ydb-embedded-ui/commit/d3b3d9bf77dbbe7966bbc072d64cb4c4b5c3d0c4)) +* use date pickers from date-components ([#1031](https://github.com/ydb-platform/ydb-embedded-ui/issues/1031)) ([dbb5ba7](https://github.com/ydb-platform/ydb-embedded-ui/commit/dbb5ba797870d738423ebf2f7bfd688d9a9b6d75)) +* use monaco-yql-languages for syntax highlight ([#1063](https://github.com/ydb-platform/ydb-embedded-ui/issues/1063)) ([96976aa](https://github.com/ydb-platform/ydb-embedded-ui/commit/96976aaa4f13a3287e3ee8283db77c96703e268e)) + + +### Bug Fixes + +* add margin for developer ui button ([#1041](https://github.com/ydb-platform/ydb-embedded-ui/issues/1041)) ([6fa1e0b](https://github.com/ydb-platform/ydb-embedded-ui/commit/6fa1e0bddaa40a972d2160959fba80773d567830)) +* do not retry requests by user ([#1059](https://github.com/ydb-platform/ydb-embedded-ui/issues/1059)) ([f4af922](https://github.com/ydb-platform/ydb-embedded-ui/commit/f4af922491faf34e08022dd1e3c9af007a6765d1)) +* mark follower is Leader is false ([#1055](https://github.com/ydb-platform/ydb-embedded-ui/issues/1055)) ([c668f52](https://github.com/ydb-platform/ydb-embedded-ui/commit/c668f52171bfc34db4c724341edc9c63a0498aa7)) +* **ObjectSummary:** treat EPathTypeSubDomain as EPathTypeExtSubDomain ([#1064](https://github.com/ydb-platform/ydb-embedded-ui/issues/1064)) ([ce0c03e](https://github.com/ydb-platform/ydb-embedded-ui/commit/ce0c03ecfefdc752101b67ae2052e9c1f984ef96)) +* pass database param to all handlers inside DB ([#1066](https://github.com/ydb-platform/ydb-embedded-ui/issues/1066)) ([4b34e05](https://github.com/ydb-platform/ydb-embedded-ui/commit/4b34e05ae53ce5c5cab811d37f3a7062ff2f7718)) +* **PDiskPage:** move autorefresh to meta level ([#1058](https://github.com/ydb-platform/ydb-embedded-ui/issues/1058)) ([248e57d](https://github.com/ydb-platform/ydb-embedded-ui/commit/248e57de68684e86bb8aa688ac6cceeae45edc7d)) +* **PDiskSpaceDistribution:** increase slot height, display 0 id ([#1071](https://github.com/ydb-platform/ydb-embedded-ui/issues/1071)) ([7b9adda](https://github.com/ydb-platform/ydb-embedded-ui/commit/7b9adda65395855625bbcd6a1bd08c0ece81f79b)) +* ru.json for datepicker ([#1044](https://github.com/ydb-platform/ydb-embedded-ui/issues/1044)) ([f2dfacb](https://github.com/ydb-platform/ydb-embedded-ui/commit/f2dfacbf5f183dd3ffdb410d9d13acbc59009e74)) +* **TableInfo:** update column table info ([#1056](https://github.com/ydb-platform/ydb-embedded-ui/issues/1056)) ([3305cdb](https://github.com/ydb-platform/ydb-embedded-ui/commit/3305cdbcef990ab846a953ae6cf06a88526c0cd3)) + +## [6.11.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.10.3...v6.11.0) (2024-07-19) + + +### Features + +* add data sorting to TopQueries table ([#1028](https://github.com/ydb-platform/ydb-embedded-ui/issues/1028)) ([03608f1](https://github.com/ydb-platform/ydb-embedded-ui/commit/03608f11142a5ef50e140f18bc56cd265553bd4a)) +* show developer ui links for hosts and tablets ([#1017](https://github.com/ydb-platform/ydb-embedded-ui/issues/1017)) ([9d198c5](https://github.com/ydb-platform/ydb-embedded-ui/commit/9d198c5477117a8f428acd8a214bf5767166320b)) + + +### Bug Fixes + +* **Overview:** use stats from describe for all column tables ([#1026](https://github.com/ydb-platform/ydb-embedded-ui/issues/1026)) ([e1c8f83](https://github.com/ydb-platform/ydb-embedded-ui/commit/e1c8f836be0f577c043121c5c5cb7cbb1f6798e8)) +* reduce autocomplete triggers ([#1030](https://github.com/ydb-platform/ydb-embedded-ui/issues/1030)) ([89b4782](https://github.com/ydb-platform/ydb-embedded-ui/commit/89b47823f038a51f63b5c41eae61088e8976df7f)) +* **TenantOverview:** add correct tablet storage value ([#1040](https://github.com/ydb-platform/ydb-embedded-ui/issues/1040)) ([c8f3182](https://github.com/ydb-platform/ydb-embedded-ui/commit/c8f3182fc776fac7200d23ce8f34f0b506a95ab3)) + +## [6.10.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.10.2...v6.10.3) (2024-07-16) + + +### Bug Fixes + +* **Overview:** disable column tables stats request ([#1024](https://github.com/ydb-platform/ydb-embedded-ui/issues/1024)) ([a453d0a](https://github.com/ydb-platform/ydb-embedded-ui/commit/a453d0ab11c055846022c6731480812a0356fd2a)) +* **schema:** use one cache entree for tenant path schemas ([#1016](https://github.com/ydb-platform/ydb-embedded-ui/issues/1016)) ([7f283a0](https://github.com/ydb-platform/ydb-embedded-ui/commit/7f283a0f595d587eac3921428d14fe659cf6ee9c)) + +## [6.10.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.10.1...v6.10.2) (2024-07-10) + + +### Bug Fixes + +* json inspector styles ([#1008](https://github.com/ydb-platform/ydb-embedded-ui/issues/1008)) ([bba245f](https://github.com/ydb-platform/ydb-embedded-ui/commit/bba245fcc4e98252347743fc3807cb15d3aaf836)) + +## [6.10.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.10.0...v6.10.1) (2024-07-10) + + +### Bug Fixes + +* store types should be stored separately ([#1005](https://github.com/ydb-platform/ydb-embedded-ui/issues/1005)) ([8c2949e](https://github.com/ydb-platform/ydb-embedded-ui/commit/8c2949e81662602d62cf3336546f3093056f46aa)) + +## [6.10.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.9.2...v6.10.0) (2024-07-10) + + +### Features + +* add setting to enable actions with directories from UI ([#997](https://github.com/ydb-platform/ydb-embedded-ui/issues/997)) ([d1fd058](https://github.com/ydb-platform/ydb-embedded-ui/commit/d1fd05855de40fefc1079c1b4bb2d3f7131a89c3)) +* **QueryEditor:** save query on Cmd/Ctrl + S ([#944](https://github.com/ydb-platform/ydb-embedded-ui/issues/944)) ([1077e2e](https://github.com/ydb-platform/ydb-embedded-ui/commit/1077e2e2b9e4c83e31633391b0e6f294b80b9f66)) +* **UserSettings:** add setting for separate disks pages ([#993](https://github.com/ydb-platform/ydb-embedded-ui/issues/993)) ([18253bd](https://github.com/ydb-platform/ydb-embedded-ui/commit/18253bda3c16b114aa8a7fc5c0575be292d27710)) + + +### Bug Fixes + +* **Graph:** fix broken tab for column tables ([#1004](https://github.com/ydb-platform/ydb-embedded-ui/issues/1004)) ([0ac18ea](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ac18ea3915c5d9d36c1fbcbdf59b6f9769d3f51)) +* **Query:** fix query layout ([#999](https://github.com/ydb-platform/ydb-embedded-ui/issues/999)) ([2ee3e79](https://github.com/ydb-platform/ydb-embedded-ui/commit/2ee3e79c281bf133ee10dec7f8a463e074098461)) +* rename VirtualTable to PaginatedTable, remove old hooks ([#995](https://github.com/ydb-platform/ydb-embedded-ui/issues/995)) ([a9c37d9](https://github.com/ydb-platform/ydb-embedded-ui/commit/a9c37d922b0f2edbb987ff4db4dd6db37631d43b)) +* **Settings:** do not display balancer setting in embedded version ([#990](https://github.com/ydb-platform/ydb-embedded-ui/issues/990)) ([9b91080](https://github.com/ydb-platform/ydb-embedded-ui/commit/9b910808e4dbc3a49f3e9a83b179015ba8afb4c4)) +* **Storage:** do not request tablets for nodes ([#992](https://github.com/ydb-platform/ydb-embedded-ui/issues/992)) ([b33c1ea](https://github.com/ydb-platform/ydb-embedded-ui/commit/b33c1eae22be46910e5ae08a0e2c16a0d92ea79b)) +* **Versions:** return lost copy button ([#1003](https://github.com/ydb-platform/ydb-embedded-ui/issues/1003)) ([a06f1df](https://github.com/ydb-platform/ydb-embedded-ui/commit/a06f1df4416ab71f4fd80797de5734567a3c453b)) + +## [6.9.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.9.1...v6.9.2) (2024-07-05) + + +### Bug Fixes + +* **Header:** fix state mutation ([#987](https://github.com/ydb-platform/ydb-embedded-ui/issues/987)) ([12ba9c0](https://github.com/ydb-platform/ydb-embedded-ui/commit/12ba9c078ce820267e74f4dc3c290bb989d19e2c)) + +## [6.9.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.9.0...v6.9.1) (2024-07-05) + + +### Bug Fixes + +* fix package ([#985](https://github.com/ydb-platform/ydb-embedded-ui/issues/985)) ([8eaa897](https://github.com/ydb-platform/ydb-embedded-ui/commit/8eaa897ac9e601d32311490820f3617200c4baf7)) + +## [6.9.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.8.0...v6.9.0) (2024-07-05) + + +### Features + +* add creating directory through context menu in navigation tree ([#958](https://github.com/ydb-platform/ydb-embedded-ui/issues/958)) ([d1902d4](https://github.com/ydb-platform/ydb-embedded-ui/commit/d1902d49f2703ec91b56a6d48d2510533ebbf1a9)) +* **AutoRefresh:** use auto refresh control on other pages ([#976](https://github.com/ydb-platform/ydb-embedded-ui/issues/976)) ([6ec3d33](https://github.com/ydb-platform/ydb-embedded-ui/commit/6ec3d333e59a358e6db6045dd6942c91de910f8f)) +* prepare for react-router 6, lazy load routes ([#980](https://github.com/ydb-platform/ydb-embedded-ui/issues/980)) ([459a3dd](https://github.com/ydb-platform/ydb-embedded-ui/commit/459a3dde10208a15c7eb6e9fa32f3ed57674aee9)) + + +### Bug Fixes + +* **CreateDirectoryDialog:** check path is not empty ([#981](https://github.com/ydb-platform/ydb-embedded-ui/issues/981)) ([5794dcd](https://github.com/ydb-platform/ydb-embedded-ui/commit/5794dcddb8d1908bd3de6c1a67c98011f5568333)) +* fix node LoadAverage calculation ([#978](https://github.com/ydb-platform/ydb-embedded-ui/issues/978)) ([191ac71](https://github.com/ydb-platform/ydb-embedded-ui/commit/191ac71f247c9a77765b709365874deefb804af1)) +* package update ([#977](https://github.com/ydb-platform/ydb-embedded-ui/issues/977)) ([761b29e](https://github.com/ydb-platform/ydb-embedded-ui/commit/761b29e858be6d60adb438b1e4333be9b0b4ec82)) +* **UserSettings:** change default settings values ([#983](https://github.com/ydb-platform/ydb-embedded-ui/issues/983)) ([4dcbb2e](https://github.com/ydb-platform/ydb-embedded-ui/commit/4dcbb2e34316e0714189a085d547b192fb2dc83c)) + +## [6.8.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.7.0...v6.8.0) (2024-07-03) + + +### Features + +* **Acl:** improve view ([#955](https://github.com/ydb-platform/ydb-embedded-ui/issues/955)) ([46aff45](https://github.com/ydb-platform/ydb-embedded-ui/commit/46aff451d7768a44d50d4fe56ff4cedb0be505b0)) +* add action "Create async replication" ([#959](https://github.com/ydb-platform/ydb-embedded-ui/issues/959)) ([75b0fa8](https://github.com/ydb-platform/ydb-embedded-ui/commit/75b0fa8532a2a051f3e7042f97d98ca0125a93ae)) +* add ReadOnly label to replicated tables ([#970](https://github.com/ydb-platform/ydb-embedded-ui/issues/970)) ([669f7f0](https://github.com/ydb-platform/ydb-embedded-ui/commit/669f7f00e0dc8d0dcbac6f54cf854915a2ca1ac0)) + + +### Bug Fixes + +* expand the column 'degraded' width ([#962](https://github.com/ydb-platform/ydb-embedded-ui/issues/962)) ([0d13d53](https://github.com/ydb-platform/ydb-embedded-ui/commit/0d13d53810f4ccbc5aa2545911021126274fbaf8)) +* fix replication template ([#973](https://github.com/ydb-platform/ydb-embedded-ui/issues/973)) ([071b0a7](https://github.com/ydb-platform/ydb-embedded-ui/commit/071b0a76b46c860015018c59c961c0dbb7ea3459)) +* **TenantNavigation:** fix radio button value ([#969](https://github.com/ydb-platform/ydb-embedded-ui/issues/969)) ([7d85393](https://github.com/ydb-platform/ydb-embedded-ui/commit/7d85393f42e96e567fc670e122d8e94a0f4b6c7b)) +* update deps ([#975](https://github.com/ydb-platform/ydb-embedded-ui/issues/975)) ([89703da](https://github.com/ydb-platform/ydb-embedded-ui/commit/89703da7276aaf50b5bd1058ee786210a5867d7d)) +* **UserSettings:** fix highlight on search ([#972](https://github.com/ydb-platform/ydb-embedded-ui/issues/972)) ([6fbd52c](https://github.com/ydb-platform/ydb-embedded-ui/commit/6fbd52c2725c1c5313f04b92217356e749ab7fe6)) + +## [6.7.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.6.1...v6.7.0) (2024-06-28) + + +### Features + +* add "Create column table" action ([#957](https://github.com/ydb-platform/ydb-embedded-ui/issues/957)) ([6cb3e2b](https://github.com/ydb-platform/ydb-embedded-ui/commit/6cb3e2b65bd8ed3d9de723fa03ce33848c3f7f05)) +* add auto-increment for raw table type ([#929](https://github.com/ydb-platform/ydb-embedded-ui/issues/929)) ([87e22cd](https://github.com/ydb-platform/ydb-embedded-ui/commit/87e22cd2f490f14cdb03a24dd45e6712018ec234)) +* **api:** add retries on errors ([#934](https://github.com/ydb-platform/ydb-embedded-ui/issues/934)) ([86faa42](https://github.com/ydb-platform/ydb-embedded-ui/commit/86faa42c49c9c757c5aa75eb65567eae0a34e260)) +* **autoRefresh:** move auto refresh to separate reducer ([#943](https://github.com/ydb-platform/ydb-embedded-ui/issues/943)) ([a391e94](https://github.com/ydb-platform/ydb-embedded-ui/commit/a391e9408595d7c6ac3903a13244644475d10ece)) +* **autoRefresh:** use user settings to store auto refresh interval ([#956](https://github.com/ydb-platform/ydb-embedded-ui/issues/956)) ([99a24ce](https://github.com/ydb-platform/ydb-embedded-ui/commit/99a24ceadda3623e59743a9c510810994b0c0a42)) +* **Header:** use InternalLink for breadcrumb items ([#913](https://github.com/ydb-platform/ydb-embedded-ui/issues/913)) ([cdf36da](https://github.com/ydb-platform/ydb-embedded-ui/commit/cdf36daab24e9a558e5c80f6a8672afd1e84e668)) +* **HealthCheck:** show aggregated status in preview ([#839](https://github.com/ydb-platform/ydb-embedded-ui/issues/839)) ([71d316c](https://github.com/ydb-platform/ydb-embedded-ui/commit/71d316c111cdbec2f417fcb54c54144377d326e6)) +* **Navigation:** relocate tenant nav to main space ([#936](https://github.com/ydb-platform/ydb-embedded-ui/issues/936)) ([6161d97](https://github.com/ydb-platform/ydb-embedded-ui/commit/6161d97c3c6a7aa0108cb1af8945ada9f039ec00)) +* **schema:** use rtk-query ([#948](https://github.com/ydb-platform/ydb-embedded-ui/issues/948)) ([524e815](https://github.com/ydb-platform/ydb-embedded-ui/commit/524e815bc593c60381aa78135bf02b3c2f2b8103)) +* **store:** rewrite some reducers to rtk-query ([#942](https://github.com/ydb-platform/ydb-embedded-ui/issues/942)) ([59d41f2](https://github.com/ydb-platform/ydb-embedded-ui/commit/59d41f2868633ae5934d68de44aa538013f9a4ae)) +* **user-settings:** sync user settings with LS ([#951](https://github.com/ydb-platform/ydb-embedded-ui/issues/951)) ([9919358](https://github.com/ydb-platform/ydb-embedded-ui/commit/99193580050336b80a6e65544c0d8fcc9294796e)) + + +### Bug Fixes + +* handle with undefined value of row and column in issue position ([#932](https://github.com/ydb-platform/ydb-embedded-ui/issues/932)) ([2cb27c5](https://github.com/ydb-platform/ydb-embedded-ui/commit/2cb27c575b9f307e6fe164f7e18a3328b4d5a487)) +* rework overview pane in schema browser ([#954](https://github.com/ydb-platform/ydb-embedded-ui/issues/954)) ([ed46a5f](https://github.com/ydb-platform/ydb-embedded-ui/commit/ed46a5f74480813d1eeb3567fae699f4193bd8c7)) +* **TableInfo:** scroll ([#946](https://github.com/ydb-platform/ydb-embedded-ui/issues/946)) ([190992e](https://github.com/ydb-platform/ydb-embedded-ui/commit/190992e25fc422e79f8feb68b6a653b24043aa66)) +* **Tablets:** enable sort by fqdn ([#947](https://github.com/ydb-platform/ydb-embedded-ui/issues/947)) ([e33dc72](https://github.com/ydb-platform/ydb-embedded-ui/commit/e33dc724045340b2492a6b75325147887582fb7d)) +* typo in prettier ([#931](https://github.com/ydb-platform/ydb-embedded-ui/issues/931)) ([e08a36a](https://github.com/ydb-platform/ydb-embedded-ui/commit/e08a36ac67d42691311b9c7ae709f54016ff945d)) + +## [6.6.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.6.0...v6.6.1) (2024-06-14) + + +### Bug Fixes + +* fix npm package ([#925](https://github.com/ydb-platform/ydb-embedded-ui/issues/925)) ([6a3a594](https://github.com/ydb-platform/ydb-embedded-ui/commit/6a3a5949ccccbe053e063276648ad4322ff9c063)) + +## [6.6.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.5.0...v6.6.0) (2024-06-14) + +### Features + +* @gravity-ui/websql-autocomplete -> 9.1.0, enable autocomplete by default ([#904](https://github.com/ydb-platform/ydb-embedded-ui/issues/904)) ([e71fad9](https://github.com/ydb-platform/ydb-embedded-ui/commit/e71fad97fe16ec56dd3ee14e2e1f9ac76eb1bed9)) +* **Diagnostics:** add tablets tab to all entities with tablets ([#892](https://github.com/ydb-platform/ydb-embedded-ui/issues/892)) ([e94d53a](https://github.com/ydb-platform/ydb-embedded-ui/commit/e94d53a1fb293119dc3383add220da5f0cf601c3)) +* **Overview:** add view info ([#912](https://github.com/ydb-platform/ydb-embedded-ui/issues/912)) ([02e0cd6](https://github.com/ydb-platform/ydb-embedded-ui/commit/02e0cd66739b442eed649c9edd257ac1de87dcae)) +* **SchemaViewer:** refactor, add view schema ([#910](https://github.com/ydb-platform/ydb-embedded-ui/issues/910)) ([3a10460](https://github.com/ydb-platform/ydb-embedded-ui/commit/3a1046031b0ced98494c821b8dc5bf13b87081c4)) +* **UserSettings:** display app version ([#889](https://github.com/ydb-platform/ydb-embedded-ui/issues/889)) ([e52639e](https://github.com/ydb-platform/ydb-embedded-ui/commit/e52639e84dc5e1ca2707bb38ed917cd613a9c395)) + + +### Bug Fixes + +* **AsyncReplication:** fix table styles ([#891](https://github.com/ydb-platform/ydb-embedded-ui/issues/891)) ([f879369](https://github.com/ydb-platform/ydb-embedded-ui/commit/f87936951e28e18823c8743b3634f6f7d0d18b55)) +* **TenantOverview:** increase section margin ([#916](https://github.com/ydb-platform/ydb-embedded-ui/issues/916)) ([d8f97f0](https://github.com/ydb-platform/ydb-embedded-ui/commit/d8f97f0de7d452a5f741cca023e233968be97bfa)) +* revert release, fix package ([#920](https://github.com/ydb-platform/ydb-embedded-ui/issues/920)) ([5d3a7c6](https://github.com/ydb-platform/ydb-embedded-ui/commit/5d3a7c6cb347c6943a84e2938d836fca4da47328)) + +## [6.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.4.0...v6.5.0) (2024-06-06) + + +### Features + +* disable controls for users with viewer rights ([#848](https://github.com/ydb-platform/ydb-embedded-ui/issues/848)) ([a15e87c](https://github.com/ydb-platform/ydb-embedded-ui/commit/a15e87c6ceaf5220f23c63dfb6b3b24a02519c96)) +* **HotKeys:** add help card ([#861](https://github.com/ydb-platform/ydb-embedded-ui/issues/861)) ([3124bdb](https://github.com/ydb-platform/ydb-embedded-ui/commit/3124bdba5c0186d03f86ceb88d55a2f2c902caec)) +* suggest views and table settings ([#864](https://github.com/ydb-platform/ydb-embedded-ui/issues/864)) ([496514b](https://github.com/ydb-platform/ydb-embedded-ui/commit/496514b2e80f2513575a2c5d53bda6b01525f385)) +* support async replications ([#856](https://github.com/ydb-platform/ydb-embedded-ui/issues/856)) ([2cecddd](https://github.com/ydb-platform/ydb-embedded-ui/commit/2cecddd837f3864bee300cfd8200291dbd6044bd)) +* use existing clusters statuses in filter ([#884](https://github.com/ydb-platform/ydb-embedded-ui/issues/884)) ([bb8cdce](https://github.com/ydb-platform/ydb-embedded-ui/commit/bb8cdcefcaa614ce2b79d324ec08473811ad0417)) + + +### Bug Fixes + +* **Query:** parse 200 error response ([#883](https://github.com/ydb-platform/ydb-embedded-ui/issues/883)) ([c4cd541](https://github.com/ydb-platform/ydb-embedded-ui/commit/c4cd541d405da2311ef8292347826bdbeeb808e1)) +* **Tenant:** should not duplicate api requests ([#879](https://github.com/ydb-platform/ydb-embedded-ui/issues/879)) ([3bd1e5d](https://github.com/ydb-platform/ydb-embedded-ui/commit/3bd1e5dc26d1535ae7d75eb88548427f6f9aaa45)) + +## [6.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.3.0...v6.4.0) (2024-05-31) + + +### Features + +* add Nodes and Storage filters to url ([#849](https://github.com/ydb-platform/ydb-embedded-ui/issues/849)) ([5a789d5](https://github.com/ydb-platform/ydb-embedded-ui/commit/5a789d50d86df2e4fd1918d3bb2e3eb87a1d26dc)) +* delete icons sprite, use gravity icons ([#853](https://github.com/ydb-platform/ydb-embedded-ui/issues/853)) ([be1d6c3](https://github.com/ydb-platform/ydb-embedded-ui/commit/be1d6c39ba6818844163aba5267f138150a12a75)) +* **Diagnostics:** display tablets as table ([#852](https://github.com/ydb-platform/ydb-embedded-ui/issues/852)) ([7915463](https://github.com/ydb-platform/ydb-embedded-ui/commit/7915463ac0fdeac4266667e5b64f9ed4afa2c174)) +* **Node:** add developer ui link for embedded version ([#863](https://github.com/ydb-platform/ydb-embedded-ui/issues/863)) ([163b104](https://github.com/ydb-platform/ydb-embedded-ui/commit/163b10410f54fade05b925cabd932ea597741423)) +* **Node:** display tablets as a table ([#855](https://github.com/ydb-platform/ydb-embedded-ui/issues/855)) ([10018ae](https://github.com/ydb-platform/ydb-embedded-ui/commit/10018ae9e2a389f910b4a12f3974af69f05f36d8)) + + +### Bug Fixes + +* fix ast always light theme ([#827](https://github.com/ydb-platform/ydb-embedded-ui/issues/827)) ([45084a6](https://github.com/ydb-platform/ydb-embedded-ui/commit/45084a6ea373b8489d1520600303eb1583186fff)) +* set 0 for tenant metrics if consumption undefined ([#850](https://github.com/ydb-platform/ydb-embedded-ui/issues/850)) ([313d130](https://github.com/ydb-platform/ydb-embedded-ui/commit/313d1305d1a279f803a77e911ead5006164501db)) +* **Tenant:** always set tenantPage in the url ([#859](https://github.com/ydb-platform/ydb-embedded-ui/issues/859)) ([0ee9127](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ee9127596f002e667b5acd1aa7f2ff12149be3d)) +* use soft quota for tenant storage ([#837](https://github.com/ydb-platform/ydb-embedded-ui/issues/837)) ([5aa5b68](https://github.com/ydb-platform/ydb-embedded-ui/commit/5aa5b68a619ade6e7b7683d82891d26a36a84ee9)) + +## [6.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.2.2...v6.3.0) (2024-05-24) + + +### Features + +* add view to schema ([#834](https://github.com/ydb-platform/ydb-embedded-ui/issues/834)) ([fbeea1a](https://github.com/ydb-platform/ydb-embedded-ui/commit/fbeea1afab22803b6df87fe996b67e3c4e6ba94d)) + + +### Bug Fixes + +* @gravity-ui/components -> 3.4.1 ([#845](https://github.com/ydb-platform/ydb-embedded-ui/issues/845)) ([96299d4](https://github.com/ydb-platform/ydb-embedded-ui/commit/96299d4e70281b3535f9d8d8a6ef82c89a257230)) + +## [6.2.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.2.1...v6.2.2) (2024-05-23) + + +### Bug Fixes + +* fix copy button not hidden after copy ([#838](https://github.com/ydb-platform/ydb-embedded-ui/issues/838)) ([a8d0524](https://github.com/ydb-platform/ydb-embedded-ui/commit/a8d052489d21f5a16ad79d119a7025df3e49c111)) + +## [6.2.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.2.0...v6.2.1) (2024-05-21) + + +### Bug Fixes + +* fix buttons incorrect align in Nodes and Tenants tables ([#830](https://github.com/ydb-platform/ydb-embedded-ui/issues/830)) ([f97c082](https://github.com/ydb-platform/ydb-embedded-ui/commit/f97c08214c9afce731bc76f6513abbd33101b912)) +* **Preview:** send request only for tables ([#832](https://github.com/ydb-platform/ydb-embedded-ui/issues/832)) ([62d8ec9](https://github.com/ydb-platform/ydb-embedded-ui/commit/62d8ec962c281727bd04db5be9b0a12d279f726c)) + +## [6.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.1.0...v6.2.0) (2024-05-17) + + +### Features + +* make tables resizeable ([#823](https://github.com/ydb-platform/ydb-embedded-ui/issues/823)) ([ff27390](https://github.com/ydb-platform/ydb-embedded-ui/commit/ff2739033437a069892d4ddf203e98a53ee3a934)) +* update deps ([#826](https://github.com/ydb-platform/ydb-embedded-ui/issues/826)) ([e3f08cf](https://github.com/ydb-platform/ydb-embedded-ui/commit/e3f08cf9365587b4fbcd6c151d340b6967622756)) + +## [6.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.0.1...v6.0.2) (2024-05-14) + + +### Features + +* improve autocomplete ([#814](https://github.com/ydb-platform/ydb-embedded-ui/issues/814)) ([2615f7e](https://github.com/ydb-platform/ydb-embedded-ui/commit/2615f7e1709ab8280fd1fcd1135f1641d669eaf3)) + +### Bug Fixes + +* **PDiskPage:** explicit error on failed restart ([#821](https://github.com/ydb-platform/ydb-embedded-ui/issues/821)) ([fb81b29](https://github.com/ydb-platform/ydb-embedded-ui/commit/fb81b295073034ac400f08fe7bd26023b1b8a8d8)) + +## [6.0.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v6.0.0...v6.0.1) (2024-05-13) + + +### Bug Fixes + +* fix monaco bug in safari ([#812](https://github.com/ydb-platform/ydb-embedded-ui/issues/812)) ([075c5db](https://github.com/ydb-platform/ydb-embedded-ui/commit/075c5db1eea7c73ebea8db3a78ed3253485d564a)) + +## [6.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v5.5.0...v6.0.0) (2024-05-03) + + +### ⚠ BREAKING CHANGES + +* update to uikit 6 ([#789](https://github.com/ydb-platform/ydb-embedded-ui/issues/789)) + +### Features + +* auto refresh with advanced control ([#804](https://github.com/ydb-platform/ydb-embedded-ui/issues/804)) ([bfbd3d0](https://github.com/ydb-platform/ydb-embedded-ui/commit/bfbd3d01083270a362b8db3f858f7b7c2df4fbcd)) +* **Cluster:** persist nodes filter in URL ([#797](https://github.com/ydb-platform/ydb-embedded-ui/issues/797)) ([32ef8d6](https://github.com/ydb-platform/ydb-embedded-ui/commit/32ef8d65f53a887a871cff7ef13760bbde6935d6)) +* **Diagnostics:** add Schema tab with column family info ([#767](https://github.com/ydb-platform/ydb-embedded-ui/issues/767)) ([504468b](https://github.com/ydb-platform/ydb-embedded-ui/commit/504468bfac2f95ea61d0941058d685ea343f8a9c)) +* **healthcheck:** use rtk query ([#800](https://github.com/ydb-platform/ydb-embedded-ui/issues/800)) ([65e25f8](https://github.com/ydb-platform/ydb-embedded-ui/commit/65e25f8c1008cf6e714ada6baa601cd6a876c9ac)) +* move some pages to rtk query ([#799](https://github.com/ydb-platform/ydb-embedded-ui/issues/799)) ([876510c](https://github.com/ydb-platform/ydb-embedded-ui/commit/876510ccfd68d99bfae056476a526561101f825a)) +* **TenantOverview:** bars instead of circles ([#792](https://github.com/ydb-platform/ydb-embedded-ui/issues/792)) ([05fbeff](https://github.com/ydb-platform/ydb-embedded-ui/commit/05fbeffa9407694bc885b34e36899be32b936382)) +* **Tenant:** use rtk query ([#802](https://github.com/ydb-platform/ydb-embedded-ui/issues/802)) ([19487b1](https://github.com/ydb-platform/ydb-embedded-ui/commit/19487b16990dd571c9c21ec9e66609183c7c4de1)) +* update to uikit 6 ([#789](https://github.com/ydb-platform/ydb-embedded-ui/issues/789)) ([1a3154d](https://github.com/ydb-platform/ydb-embedded-ui/commit/1a3154de595e6254fe25049373200d40cc41d751)) +* use rtk query ([#795](https://github.com/ydb-platform/ydb-embedded-ui/issues/795)) ([9f82408](https://github.com/ydb-platform/ydb-embedded-ui/commit/9f82408e9185a988128ff9f2d6d600cfd6e6325c)) + + +### Bug Fixes + +* add cluster dashboard to monitoring link object ([#793](https://github.com/ydb-platform/ydb-embedded-ui/issues/793)) ([b021fe0](https://github.com/ydb-platform/ydb-embedded-ui/commit/b021fe013460328a00f152484947af32ab46e4ee)) +* **MetricChart:** spanGaps ([#796](https://github.com/ydb-platform/ydb-embedded-ui/issues/796)) ([33687fb](https://github.com/ydb-platform/ydb-embedded-ui/commit/33687fb5b237347ae1be86192b152b1140dadbb4)) +* **QueryEditor:** use `full` stats mode instead of `profile` ([#791](https://github.com/ydb-platform/ydb-embedded-ui/issues/791)) ([6488896](https://github.com/ydb-platform/ydb-embedded-ui/commit/64888960c171934d8ee0a080fb731a7abae79e2c)) + +## [5.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v5.4.0...v5.5.0) (2024-04-02) + + +### Features + +* add databases label ([#774](https://github.com/ydb-platform/ydb-embedded-ui/issues/774)) ([7b8e473](https://github.com/ydb-platform/ydb-embedded-ui/commit/7b8e473845e0769575e3e35a3cd525fdfcdf02b9)) +* add VDisk page ([#773](https://github.com/ydb-platform/ydb-embedded-ui/issues/773)) ([ea7ea88](https://github.com/ydb-platform/ydb-embedded-ui/commit/ea7ea884bce3f6660a6c96adced730b6fb6a9e1e)) +* **formatNumber:** render numbers with spaces instead of comas ([#778](https://github.com/ydb-platform/ydb-embedded-ui/issues/778)) ([5b42808](https://github.com/ydb-platform/ydb-embedded-ui/commit/5b4280858fb8bc44975bc7a705c15c7152b69c45)) + + +### Bug Fixes + +* initial bundle size ([#776](https://github.com/ydb-platform/ydb-embedded-ui/issues/776)) ([b13344d](https://github.com/ydb-platform/ydb-embedded-ui/commit/b13344d3da2a91a6c76733100d34fb3bc3c0f8fa)) +* **MetricChart:** zero min value ([#787](https://github.com/ydb-platform/ydb-embedded-ui/issues/787)) ([f767d00](https://github.com/ydb-platform/ydb-embedded-ui/commit/f767d00000666e2a0109a334291406b1bb2a5686)) +* **Storage:** use media type for groups ([#788](https://github.com/ydb-platform/ydb-embedded-ui/issues/788)) ([4b46f38](https://github.com/ydb-platform/ydb-embedded-ui/commit/4b46f38bc535971a5e1f9a3ec37f9b1e134084cc)) +* **Tablet:** disable restart for stopped tablets ([#780](https://github.com/ydb-platform/ydb-embedded-ui/issues/780)) ([9bcffd6](https://github.com/ydb-platform/ydb-embedded-ui/commit/9bcffd6540e70cdfa93ea22fcd2ca69e97187389)) +* **VirtualTable:** make table resizeable by default ([#772](https://github.com/ydb-platform/ydb-embedded-ui/issues/772)) ([fe6ad27](https://github.com/ydb-platform/ydb-embedded-ui/commit/fe6ad27e5b598191d8a3b5c3aeba94ff3377a164)) + +## [5.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v5.3.0...v5.4.0) (2024-03-23) + + +### Features + +* **MetricChart:** display per pool cpu usage ([#769](https://github.com/ydb-platform/ydb-embedded-ui/issues/769)) ([6902afa](https://github.com/ydb-platform/ydb-embedded-ui/commit/6902afab43a635fa70f25aa9149e5c6802ec489b)) +* **PDisk:** add restart button ([#766](https://github.com/ydb-platform/ydb-embedded-ui/issues/766)) ([7239727](https://github.com/ydb-platform/ydb-embedded-ui/commit/723972712a3aabfb519ec29a4c191096887d5a1b)) + + +### Bug Fixes + +* **MetricChart:** draw area charts ([#764](https://github.com/ydb-platform/ydb-embedded-ui/issues/764)) ([51eb1bf](https://github.com/ydb-platform/ydb-embedded-ui/commit/51eb1bf2a37805012630907774bee8f9b00affff)) + +## [5.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v5.2.1...v5.3.0) (2024-03-15) + + +### Features + +* add PDisk page ([#759](https://github.com/ydb-platform/ydb-embedded-ui/issues/759)) ([c1d3f99](https://github.com/ydb-platform/ydb-embedded-ui/commit/c1d3f996f5b0f1c23cd7ba5e717fad3680ba63af)) +* add setting to enable autocomplete, fix constants for completion ([#765](https://github.com/ydb-platform/ydb-embedded-ui/issues/765)) ([88cfc52](https://github.com/ydb-platform/ydb-embedded-ui/commit/88cfc5258eaf64a1b2e5ff6c1403f827e71ed54a)) +* add YQL autocomplete ([#755](https://github.com/ydb-platform/ydb-embedded-ui/issues/755)) ([799a05f](https://github.com/ydb-platform/ydb-embedded-ui/commit/799a05fe3301d4be05c33bce8a44eb3018a199c7)) +* **MetricChart:** make charts database specific ([#750](https://github.com/ydb-platform/ydb-embedded-ui/issues/750)) ([fa98a22](https://github.com/ydb-platform/ydb-embedded-ui/commit/fa98a2222e5be1d0fe83b90f99d73207eb93fc71)) +* use rtk to init store and add typed dispatch ([#749](https://github.com/ydb-platform/ydb-embedded-ui/issues/749)) ([323cb6b](https://github.com/ydb-platform/ydb-embedded-ui/commit/323cb6b5de9204e40af2c2b80ca436edcddb686d)) + + +### Bug Fixes + +* add absent deps, update axios ([#756](https://github.com/ydb-platform/ydb-embedded-ui/issues/756)) ([ee723cd](https://github.com/ydb-platform/ydb-embedded-ui/commit/ee723cd8f7122949f388a8380ee05fe96c624ff3)) +* add Blue status to EFlag ([#754](https://github.com/ydb-platform/ydb-embedded-ui/issues/754)) ([9a0b867](https://github.com/ydb-platform/ydb-embedded-ui/commit/9a0b867b45262919baaa7032f73cf44d415d3f27)) +* fix status colors ([#757](https://github.com/ydb-platform/ydb-embedded-ui/issues/757)) ([9928ee2](https://github.com/ydb-platform/ydb-embedded-ui/commit/9928ee23ee55959eb2162de5c948c321ed849fe7)) +* **MetricChart:** explicitly process error with html ([#752](https://github.com/ydb-platform/ydb-embedded-ui/issues/752)) ([6d8a0ba](https://github.com/ydb-platform/ydb-embedded-ui/commit/6d8a0ba454061db4edff948af86731bc6873a356)) +* **Tablet:** correctly process error in dialog action ([#758](https://github.com/ydb-platform/ydb-embedded-ui/issues/758)) ([b6bcd68](https://github.com/ydb-platform/ydb-embedded-ui/commit/b6bcd686df4e092019da0d39e9da384930cf4a0a)) +* **TEvDescribeSchemeResult:** support null value ([#762](https://github.com/ydb-platform/ydb-embedded-ui/issues/762)) ([72ce541](https://github.com/ydb-platform/ydb-embedded-ui/commit/72ce54159b237f607f971159d0bba4879dfea73c)) + +## [5.2.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v5.2.0...v5.2.1) (2024-03-05) + + +### Bug Fixes + +* **Cluster:** make cluster title sticky ([#743](https://github.com/ydb-platform/ydb-embedded-ui/issues/743)) ([823709d](https://github.com/ydb-platform/ydb-embedded-ui/commit/823709d3d12992db86254ccdb4941ead1dc30295)) +* display rack for din nodes ([#742](https://github.com/ydb-platform/ydb-embedded-ui/issues/742)) ([54384dd](https://github.com/ydb-platform/ydb-embedded-ui/commit/54384dd2447465109008f4053ba748241a1fa133)) +* **QueryEditor:** rename actions ([#741](https://github.com/ydb-platform/ydb-embedded-ui/issues/741)) ([784c5b3](https://github.com/ydb-platform/ydb-embedded-ui/commit/784c5b3ca45aa9be77a25f253b5aae2bb4ecc88b)) + +## [5.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v5.1.0...v5.2.0) (2024-03-04) + + +### Features + +* add binary data in plain text display ([#739](https://github.com/ydb-platform/ydb-embedded-ui/issues/739)) ([dd126b0](https://github.com/ydb-platform/ydb-embedded-ui/commit/dd126b0c03bef61110362596a15b5d069644c232)) +* allow replace ErrorBoundary compponent ([#744](https://github.com/ydb-platform/ydb-embedded-ui/issues/744)) ([588c1f1](https://github.com/ydb-platform/ydb-embedded-ui/commit/588c1f165ced6087afc85f535abf3cd08733648d)) + +## [5.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v5.0.0...v5.1.0) (2024-02-29) + + +### Features + +* **Cluster:** move cluster info to overview tab ([#710](https://github.com/ydb-platform/ydb-embedded-ui/issues/710)) ([7abcbc1](https://github.com/ydb-platform/ydb-embedded-ui/commit/7abcbc1148a981bd26240caec0809c45b06c3b98)) +* do not use external settings ([#725](https://github.com/ydb-platform/ydb-embedded-ui/issues/725)) ([8af45b0](https://github.com/ydb-platform/ydb-embedded-ui/commit/8af45b073d986b3e6bbd25a0823df7fe78622f09)) +* **HotKeys:** revive ([#722](https://github.com/ydb-platform/ydb-embedded-ui/issues/722)) ([8047fe4](https://github.com/ydb-platform/ydb-embedded-ui/commit/8047fe431733f3838021fc0e4074179a8a8a75c4)) +* **QueryEditor:** execute query with selected text ([#737](https://github.com/ydb-platform/ydb-embedded-ui/issues/737)) ([122a006](https://github.com/ydb-platform/ydb-embedded-ui/commit/122a0069ba96857cd0377a76cbf744735d287c45)) +* show different page titles on different pages ([#733](https://github.com/ydb-platform/ydb-embedded-ui/issues/733)) ([4881f09](https://github.com/ydb-platform/ydb-embedded-ui/commit/4881f090f1c808b3bd0baf2cbf2e71373bb5d641)) +* **TopQueries:** add Duration column ([#711](https://github.com/ydb-platform/ydb-embedded-ui/issues/711)) ([3f6a892](https://github.com/ydb-platform/ydb-embedded-ui/commit/3f6a892e42a12a5575253e6e93078195a7212a57)) + + +### Bug Fixes + +* configure i18n for libs ([#724](https://github.com/ydb-platform/ydb-embedded-ui/issues/724)) ([c0b7c7d](https://github.com/ydb-platform/ydb-embedded-ui/commit/c0b7c7d21048a35462cf1c4f27a5348e2a9692b1)) +* **ExecuteResults:** escape values in table cells when copy as tsv ([#720](https://github.com/ydb-platform/ydb-embedded-ui/issues/720)) ([de40fe6](https://github.com/ydb-platform/ydb-embedded-ui/commit/de40fe611da78fd7f38f429c1f175aed110874b7)) +* pass route component props to slot ([#716](https://github.com/ydb-platform/ydb-embedded-ui/issues/716)) ([51e7872](https://github.com/ydb-platform/ydb-embedded-ui/commit/51e7872908f691ef6e84995425b1d169045ebddd)) +* **ProgressViewer:** make text more contrast ([#714](https://github.com/ydb-platform/ydb-embedded-ui/issues/714)) ([e09ec79](https://github.com/ydb-platform/ydb-embedded-ui/commit/e09ec792a99df38e7f742defe03bcc8850967abe)) +* remove console log on monitoring data parsing error ([#723](https://github.com/ydb-platform/ydb-embedded-ui/issues/723)) ([f73dbc8](https://github.com/ydb-platform/ydb-embedded-ui/commit/f73dbc8a735179e8466d6fbd08325cdf76790e1d)) +* **TopQueries:** use EndTime ([#727](https://github.com/ydb-platform/ydb-embedded-ui/issues/727)) ([5e708ca](https://github.com/ydb-platform/ydb-embedded-ui/commit/5e708cad9c98530e64dbebd195edb43fea360830)) +* update tenant cpu ([#736](https://github.com/ydb-platform/ydb-embedded-ui/issues/736)) ([775bacf](https://github.com/ydb-platform/ydb-embedded-ui/commit/775bacfda549e5cea09ea03069908a59c12c0c3e)) +* update tenant storage ([#726](https://github.com/ydb-platform/ydb-embedded-ui/issues/726)) ([dc0df8a](https://github.com/ydb-platform/ydb-embedded-ui/commit/dc0df8ab09d6a3953279d6be52d245a64c78680c)) +* use DC and Rack from Location for nodes ([#713](https://github.com/ydb-platform/ydb-embedded-ui/issues/713)) ([e64c3b0](https://github.com/ydb-platform/ydb-embedded-ui/commit/e64c3b065dd07f8c2b1b7f131e52ed01e2f579fb)) + +## [5.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.33.0...v5.0.0) (2024-02-13) + + +### Features + +* add multi clusters support ([#701](https://github.com/ydb-platform/ydb-embedded-ui/issues/701)) ([429aa0e](https://github.com/ydb-platform/ydb-embedded-ui/commit/429aa0e2138c4635f5c0ab26ba07901ec0d0162d)) + +## [4.33.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.32.0...v4.33.0) (2024-02-07) + + +### Features + +* **VirtualTable:** enable columns resize ([#697](https://github.com/ydb-platform/ydb-embedded-ui/issues/697)) ([907b275](https://github.com/ydb-platform/ydb-embedded-ui/commit/907b2751541575cde3effcf5359a19cd9b6adffa)) + + +### Bug Fixes + +* **TableInfo:** format partitions count ([#704](https://github.com/ydb-platform/ydb-embedded-ui/issues/704)) ([2271535](https://github.com/ydb-platform/ydb-embedded-ui/commit/2271535964e4dcf72a3205f61769abfbb22543d4)) +* **TenantDashboard:** hide if charts not enabled ([#675](https://github.com/ydb-platform/ydb-embedded-ui/issues/675)) ([fe0cad4](https://github.com/ydb-platform/ydb-embedded-ui/commit/fe0cad4e37e6b9dc8b8e9b5aeca882e798ec0cce)) + +## [4.32.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.31.2...v4.32.0) (2024-02-07) + + +### Features + +* use VirtualTable in Nodes and Diagnostics ([#678](https://github.com/ydb-platform/ydb-embedded-ui/issues/678)) ([9158050](https://github.com/ydb-platform/ydb-embedded-ui/commit/91580507abf8dd4ac7d2ce070f83e9838ddd4bda)) + +## [4.31.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.31.1...v4.31.2) (2024-02-01) + + +### Bug Fixes + +* **VirtualTable:** optimise requests ([#676](https://github.com/ydb-platform/ydb-embedded-ui/issues/676)) ([9a50a34](https://github.com/ydb-platform/ydb-embedded-ui/commit/9a50a34110eeeeddc0bf83cc5626bca30804ac1a)) + +## [4.31.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.31.0...v4.31.1) (2024-02-01) + + +### Bug Fixes + +* **MetricChart:** do not convert nulls ([#677](https://github.com/ydb-platform/ydb-embedded-ui/issues/677)) ([c51c7aa](https://github.com/ydb-platform/ydb-embedded-ui/commit/c51c7aa1b6fb84342ab38466726175077cd7ef2e)) + +## [4.31.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.31.0...v4.31.0) (2024-01-31) + + +### Features + +* **TenantOverview:** add charts ([#657](https://github.com/ydb-platform/ydb-embedded-ui/issues/657)) ([78daa0b](https://github.com/ydb-platform/ydb-embedded-ui/commit/78daa0bc5a1eb66d0bb0b88ccb559335294e44a7)) + +## [4.30.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.29.0...v4.30.0) (2024-01-16) + + +### Features + +* add clipboard button to nodes tree titles ([#648](https://github.com/ydb-platform/ydb-embedded-ui/issues/648)) ([1411651](https://github.com/ydb-platform/ydb-embedded-ui/commit/141165173189be064e9e9314b42aa3eb7fce9c69)) + +## [4.29.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.28.0...v4.29.0) (2024-01-12) + + +### Features + +* add ErrorBoundary ([#549](https://github.com/ydb-platform/ydb-embedded-ui/issues/549)) ([f5ad224](https://github.com/ydb-platform/ydb-embedded-ui/commit/f5ad224b342e0fa25b1bafa3f5e2202ce165ef80)) + +## [4.28.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.27.1...v4.28.0) (2024-01-10) + + +### Features + +* **Storage:** use VirtualTable ([#628](https://github.com/ydb-platform/ydb-embedded-ui/issues/628)) ([67fd9b0](https://github.com/ydb-platform/ydb-embedded-ui/commit/67fd9b03653dd28be650094c987451b09fcce858)) + +## [4.27.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.27.0...v4.27.1) (2024-01-10) + + +### Bug Fixes + +* enable extract and set user settings manually ([#629](https://github.com/ydb-platform/ydb-embedded-ui/issues/629)) ([5eecd58](https://github.com/ydb-platform/ydb-embedded-ui/commit/5eecd58249688b4a8b3ecad766564f7b404e839c)) + +## [4.27.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.26.0...v4.27.0) (2023-12-28) + + +### Features + +* migrate from external settings api ([#621](https://github.com/ydb-platform/ydb-embedded-ui/issues/621)) ([ae2fbbe](https://github.com/ydb-platform/ydb-embedded-ui/commit/ae2fbbef66d9aba150012027baf8b89bf79cd741)) + +## [4.26.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.25.0...v4.26.0) (2023-12-14) + + +### Features + +* update to uikit5 ([#607](https://github.com/ydb-platform/ydb-embedded-ui/issues/607)) ([ddd263b](https://github.com/ydb-platform/ydb-embedded-ui/commit/ddd263bd39d4de262e6c891dce6c6ff6ba2a3379)) + +## [4.25.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.24.0...v4.25.0) (2023-12-07) + + +### Features + +* **Diagnostics:** remove tenant diagnostics cards setting ([#602](https://github.com/ydb-platform/ydb-embedded-ui/issues/602)) ([fe61df8](https://github.com/ydb-platform/ydb-embedded-ui/commit/fe61df86048013432c4e4788d1e621298ecb1fb2)) +* **Query:** remove query modes setting ([#600](https://github.com/ydb-platform/ydb-embedded-ui/issues/600)) ([78c63e4](https://github.com/ydb-platform/ydb-embedded-ui/commit/78c63e4a2e60950970914eaba49304b68aad0f80)) + +## [4.24.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.23.0...v4.24.0) (2023-12-07) + + +### Features + +* always use localStorage if no settingsApi ([#603](https://github.com/ydb-platform/ydb-embedded-ui/issues/603)) ([ff692df](https://github.com/ydb-platform/ydb-embedded-ui/commit/ff692dffa99d278f6b261bbf1aac0ee24c661a6d)) + +## [4.23.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.22.0...v4.23.0) (2023-12-06) + + +### Features + +* **ClusterInfo:** display groups stats ([#598](https://github.com/ydb-platform/ydb-embedded-ui/issues/598)) ([c31d048](https://github.com/ydb-platform/ydb-embedded-ui/commit/c31d0480a1b91cf01a660fd1d9726c6708f7c252)) +* **TenantOverview:** add links to sections titles ([#599](https://github.com/ydb-platform/ydb-embedded-ui/issues/599)) ([30401fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/30401fa354d90943bc4af4ddbf65466ce10381f9)) + + +### Bug Fixes + +* **Schema:** display keys in right order ([#596](https://github.com/ydb-platform/ydb-embedded-ui/issues/596)) ([c99b7e2](https://github.com/ydb-platform/ydb-embedded-ui/commit/c99b7e2e97acffc1cab450dfbf758c38b8b6e4d5)) + +## [4.22.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.21.1...v4.22.0) (2023-11-27) + + +### Features + +* **Query:** enable queries with multiple resultsets ([#595](https://github.com/ydb-platform/ydb-embedded-ui/issues/595)) ([2eedfb6](https://github.com/ydb-platform/ydb-embedded-ui/commit/2eedfb6ec3be932c7399bb67de901798c0b31b50)) +* **TenantOverview:** add columns to memory table ([#593](https://github.com/ydb-platform/ydb-embedded-ui/issues/593)) ([6379577](https://github.com/ydb-platform/ydb-embedded-ui/commit/6379577782cfa69de9fb39640d2a143f1670be39)) + + +### Bug Fixes + +* fix disks developer UI links for paths with nodeId ([#594](https://github.com/ydb-platform/ydb-embedded-ui/issues/594)) ([7f5a783](https://github.com/ydb-platform/ydb-embedded-ui/commit/7f5a78393d0c23e584ad73040fd0e73d404e5d01)) +* **TopShards:** sort by InFlightTxCount ([#591](https://github.com/ydb-platform/ydb-embedded-ui/issues/591)) ([eb3592d](https://github.com/ydb-platform/ydb-embedded-ui/commit/eb3592d69a465814de27e8b1e368b34cc60fed2f)) + +## [4.21.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.21.0...v4.21.1) (2023-11-17) + + +### Bug Fixes + +* move inverted disk space setting to general page ([#589](https://github.com/ydb-platform/ydb-embedded-ui/issues/589)) ([b09345e](https://github.com/ydb-platform/ydb-embedded-ui/commit/b09345e1ebe9e7a47beea5ab2dac4257790232cc)) +* **Nodes:** always use nodes when flag is enabled ([#584](https://github.com/ydb-platform/ydb-embedded-ui/issues/584)) ([6ac6ee2](https://github.com/ydb-platform/ydb-embedded-ui/commit/6ac6ee2516bb2612cc7832e67ffa0bf92615a36c)) +* **QueryResultTable:** fix table error on null cell sort ([#590](https://github.com/ydb-platform/ydb-embedded-ui/issues/590)) ([805a339](https://github.com/ydb-platform/ydb-embedded-ui/commit/805a339b0bba34412bf8e854cf6d24ae7c080539)) +* **Tablets:** reduce rerenders ([#585](https://github.com/ydb-platform/ydb-embedded-ui/issues/585)) ([f1767a1](https://github.com/ydb-platform/ydb-embedded-ui/commit/f1767a143b139de4cd7c0df5c8c243c0224ebd3c)) +* turn on query modes and metrics cards by default ([#588](https://github.com/ydb-platform/ydb-embedded-ui/issues/588)) ([c2f0d74](https://github.com/ydb-platform/ydb-embedded-ui/commit/c2f0d7424cb3182926f125a1e8c16cd4a2d422b9)) +* update links to VDisk and PDisk Developer UI ([#582](https://github.com/ydb-platform/ydb-embedded-ui/issues/582)) ([97dda88](https://github.com/ydb-platform/ydb-embedded-ui/commit/97dda88bd595295eefaed4c0cbcd333e84b047f0)) +* **VirtualNodes:** display developerUI link on hover ([#587](https://github.com/ydb-platform/ydb-embedded-ui/issues/587)) ([ba6c249](https://github.com/ydb-platform/ydb-embedded-ui/commit/ba6c249a9793b0bac45607b0b36f284dea4e0a7a)) + +## [4.21.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.20.4...v4.21.0) (2023-10-27) + + +### Features + +* add VirtualTable, use for Nodes ([#578](https://github.com/ydb-platform/ydb-embedded-ui/issues/578)) ([d6197d4](https://github.com/ydb-platform/ydb-embedded-ui/commit/d6197d4bebf509596dfff4e1b4a7fe51a847424e)) + +## [4.20.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.20.3...v4.20.4) (2023-10-27) + + +### Bug Fixes + +* **Storage:** set storage true for nodes ([#579](https://github.com/ydb-platform/ydb-embedded-ui/issues/579)) ([146d235](https://github.com/ydb-platform/ydb-embedded-ui/commit/146d23563ef50461260f13eedf66ad7da9f76c8a)) + +## [4.20.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.20.2...v4.20.3) (2023-10-25) + + +### Bug Fixes + +* fix port doesnt match ([#576](https://github.com/ydb-platform/ydb-embedded-ui/issues/576)) ([147a2a9](https://github.com/ydb-platform/ydb-embedded-ui/commit/147a2a919c5fe8ec99f19620da70387ab6c0e519)) + +## [4.20.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.20.1...v4.20.2) (2023-10-25) + + +### Bug Fixes + +* fix diagnostics top queries width ([#574](https://github.com/ydb-platform/ydb-embedded-ui/issues/574)) ([afa17f2](https://github.com/ydb-platform/ydb-embedded-ui/commit/afa17f236331692167a0a37936b090a8baa772df)) +* fix sticky storage info ([#573](https://github.com/ydb-platform/ydb-embedded-ui/issues/573)) ([4b923d1](https://github.com/ydb-platform/ydb-embedded-ui/commit/4b923d1db73c53c63e95f43487127b4c2c1e4cac)) +* use UsageLabel in top groups by usage table ([#572](https://github.com/ydb-platform/ydb-embedded-ui/issues/572)) ([752888d](https://github.com/ydb-platform/ydb-embedded-ui/commit/752888d26ac2cab75307011fb1354830b1cb6db6)) + +## [4.20.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.20.0...v4.20.1) (2023-10-24) + + +### Bug Fixes + +* fix createExternalUILink ([#571](https://github.com/ydb-platform/ydb-embedded-ui/issues/571)) ([52546f1](https://github.com/ydb-platform/ydb-embedded-ui/commit/52546f17dbfdb255b2429836e880d6812b19d66a)) +* fix incorrect truncate strings with popover ([#567](https://github.com/ydb-platform/ydb-embedded-ui/issues/567)) ([d82e65b](https://github.com/ydb-platform/ydb-embedded-ui/commit/d82e65b925b76dc539a76520eccf601951654e94)) +* fix top queries table row height ([#565](https://github.com/ydb-platform/ydb-embedded-ui/issues/565)) ([b12dceb](https://github.com/ydb-platform/ydb-embedded-ui/commit/b12dcebdb0167fd5852c247bca48844ef6ab35af)) +* refactor metrics storage section ([#568](https://github.com/ydb-platform/ydb-embedded-ui/issues/568)) ([db5d922](https://github.com/ydb-platform/ydb-embedded-ui/commit/db5d922d06b88c9d8a792220d2a178c81806c09e)) +* update @types/react ([#570](https://github.com/ydb-platform/ydb-embedded-ui/issues/570)) ([1e38c5b](https://github.com/ydb-platform/ydb-embedded-ui/commit/1e38c5bb3b4b2139b2141636d6434c2a2ec65772)) + +## [4.20.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.19.3...v4.20.0) (2023-10-19) + + +### Features + +* add top nodes by memory table ([#562](https://github.com/ydb-platform/ydb-embedded-ui/issues/562)) ([0d4ccf2](https://github.com/ydb-platform/ydb-embedded-ui/commit/0d4ccf2a85251fadad66182ab7d6ccd54a58e6cf)) +* add top tables links ([#564](https://github.com/ydb-platform/ydb-embedded-ui/issues/564)) ([e9b918f](https://github.com/ydb-platform/ydb-embedded-ui/commit/e9b918f0abace890cfafd9d7b219be5b69cac820)) +* **Storage:** hide nodes table for node page ([#557](https://github.com/ydb-platform/ydb-embedded-ui/issues/557)) ([9a25a00](https://github.com/ydb-platform/ydb-embedded-ui/commit/9a25a002b28824f7e616ac8143dbde12de0b0fb7)) +* **TenantOverview:** add cpu tab to tenant diagnostics ([#550](https://github.com/ydb-platform/ydb-embedded-ui/issues/550)) ([3048f84](https://github.com/ydb-platform/ydb-embedded-ui/commit/3048f8478d97249da4f7b66c26ed55f6f21e0f81)) + + +### Bug Fixes + +* add loader for healthcheck ([#563](https://github.com/ydb-platform/ydb-embedded-ui/issues/563)) ([6caea3d](https://github.com/ydb-platform/ydb-embedded-ui/commit/6caea3dec8f901090b0f8f7c1796880d7dc90a99)) +* **LinkToSchemaObject:** fix schema link ([#566](https://github.com/ydb-platform/ydb-embedded-ui/issues/566)) ([6ca8a70](https://github.com/ydb-platform/ydb-embedded-ui/commit/6ca8a705b6ddacb1f845aabb7761fd22c0c3b4e0)) + +## [4.19.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.19.2...v4.19.3) (2023-10-13) + + +### Bug Fixes + +* fix ProgressViewer background ([#556](https://github.com/ydb-platform/ydb-embedded-ui/issues/556)) ([6234462](https://github.com/ydb-platform/ydb-embedded-ui/commit/62344629713059fdfb191d3b8a57742f864dad66)) +* **Storage:** display all groups by default ([#554](https://github.com/ydb-platform/ydb-embedded-ui/issues/554)) ([1da83f1](https://github.com/ydb-platform/ydb-embedded-ui/commit/1da83f19661ed8e49dd7c8a0930ce89a7c8c0185)) + +## [4.19.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.19.1...v4.19.2) (2023-10-12) + + +### Bug Fixes + +* add default data formatter to ProgressViewer ([#552](https://github.com/ydb-platform/ydb-embedded-ui/issues/552)) ([ac372a4](https://github.com/ydb-platform/ydb-embedded-ui/commit/ac372a415e67e7126518d9c5a8d04594b82cf485)) +* **Tenant:** fix tree not fully collapsed bug ([#551](https://github.com/ydb-platform/ydb-embedded-ui/issues/551)) ([8469307](https://github.com/ydb-platform/ydb-embedded-ui/commit/8469307b67d463ed2aafd17b2c0319ea40c1f8d5)) + +## [4.19.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.19.0...v4.19.1) (2023-10-11) + + +### Bug Fixes + +* add storage value to tb formatter ([#547](https://github.com/ydb-platform/ydb-embedded-ui/issues/547)) ([f1e4377](https://github.com/ydb-platform/ydb-embedded-ui/commit/f1e4377443be493a7072aca33a62b51e381f6841)) + +## [4.19.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.18.0...v4.19.0) (2023-10-11) + + +### Features + +* **TenantOverview:** add storage tab to tenant diagnostics ([#541](https://github.com/ydb-platform/ydb-embedded-ui/issues/541)) ([c4cdd35](https://github.com/ydb-platform/ydb-embedded-ui/commit/c4cdd354cd9780dfd7dfee80ec225f59d4230625)) + + +### Bug Fixes + +* add NodeId to NodeAddress type ([#545](https://github.com/ydb-platform/ydb-embedded-ui/issues/545)) ([3df82d3](https://github.com/ydb-platform/ydb-embedded-ui/commit/3df82d39466696ec61e34b915b355dacd0482ebc)) +* display database name in node info ([#543](https://github.com/ydb-platform/ydb-embedded-ui/issues/543)) ([788ad9a](https://github.com/ydb-platform/ydb-embedded-ui/commit/788ad9a7a1a56ffe93ec7e4861ded6cceef72d9c)) +* fix cpu usage calculation ([#542](https://github.com/ydb-platform/ydb-embedded-ui/issues/542)) ([f46b03d](https://github.com/ydb-platform/ydb-embedded-ui/commit/f46b03d6157f19017560d71a9ab6591f045bad96)) +* fix incorrect data display in ProgressViewer ([#546](https://github.com/ydb-platform/ydb-embedded-ui/issues/546)) ([be077b8](https://github.com/ydb-platform/ydb-embedded-ui/commit/be077b83a4b4cf083d506e77abf0f2b6570c87d3)) + +## [4.18.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.17.0...v4.18.0) (2023-09-25) + + +### Features + +* **ProgressViewer:** add custom threasholds to ProgressViewer ([#540](https://github.com/ydb-platform/ydb-embedded-ui/issues/540)) ([3553065](https://github.com/ydb-platform/ydb-embedded-ui/commit/35530655581357f4a79c277a5bf9846b3befb784)) + + +### Bug Fixes + +* **Authentication:** enable page redirect ([#539](https://github.com/ydb-platform/ydb-embedded-ui/issues/539)) ([721883c](https://github.com/ydb-platform/ydb-embedded-ui/commit/721883cc7f4ca60e64d4a5f77b939dbb8e960855)) +* **Healthcheck:** add merge_records request param ([#538](https://github.com/ydb-platform/ydb-embedded-ui/issues/538)) ([6a47481](https://github.com/ydb-platform/ydb-embedded-ui/commit/6a474814f71c3318715a8ce638fd522a770d8038)) +* **Nodes:** use nodes endpoint by default ([#535](https://github.com/ydb-platform/ydb-embedded-ui/issues/535)) ([12d4fef](https://github.com/ydb-platform/ydb-embedded-ui/commit/12d4fefde7a6663bb1a11f46b4e94fb24b23e966)) +* rename flag for display metrics cards for database diagnostics ([#536](https://github.com/ydb-platform/ydb-embedded-ui/issues/536)) ([957e1fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/957e1fafbbc43928498ae9e8d0bc119bcda5288d)) + +## [4.17.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.16.2...v4.17.0) (2023-09-18) + + +### Features + +* add sorting of issues in issues tree ([#532](https://github.com/ydb-platform/ydb-embedded-ui/issues/532)) ([9f7837c](https://github.com/ydb-platform/ydb-embedded-ui/commit/9f7837c95bd1132dd287011e1aadc96c0819b40d)) +* move healthcheck to tabs ([#531](https://github.com/ydb-platform/ydb-embedded-ui/issues/531)) ([1879d3d](https://github.com/ydb-platform/ydb-embedded-ui/commit/1879d3d8f717a0baaec0d506ad354d81a226fa62)) +* update TenantOverview design ([#527](https://github.com/ydb-platform/ydb-embedded-ui/issues/527)) ([8a752e0](https://github.com/ydb-platform/ydb-embedded-ui/commit/8a752e0def3dc4317fd18519aed210bdc23fefa2)) + + +### Bug Fixes + +* fix Healthcheck blinking ([#528](https://github.com/ydb-platform/ydb-embedded-ui/issues/528)) ([0fc6c46](https://github.com/ydb-platform/ydb-embedded-ui/commit/0fc6c46eb15aeb73a984ba2c2cbe18ef7116382e)) +* **Tenants:** use blob storage ([#530](https://github.com/ydb-platform/ydb-embedded-ui/issues/530)) ([8a546a1](https://github.com/ydb-platform/ydb-embedded-ui/commit/8a546a1ab2f812acc1523c1c35738f4c605c32a5)) + +## [4.16.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.16.1...v4.16.2) (2023-08-28) + + +### Bug Fixes + +* fix topic templates ([#524](https://github.com/ydb-platform/ydb-embedded-ui/issues/524)) ([f593b57](https://github.com/ydb-platform/ydb-embedded-ui/commit/f593b575fb64d0c69b56e743fd4cd6faba1e9d0e)) +* rename additionalInfo params to additionalProps ([#525](https://github.com/ydb-platform/ydb-embedded-ui/issues/525)) ([dd2b040](https://github.com/ydb-platform/ydb-embedded-ui/commit/dd2b04039cd80072fe11744f3490c176fe21b16b)) + +## [4.16.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.16.0...v4.16.1) (2023-08-25) + + +### Bug Fixes + +* fix types for external props ([#522](https://github.com/ydb-platform/ydb-embedded-ui/issues/522)) ([173081f](https://github.com/ydb-platform/ydb-embedded-ui/commit/173081f2f0d2814b2311757988d91fbffc2a509f)) + +## [4.16.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.15.1...v4.16.0) (2023-08-25) + + +### Features + +* add language setting ([#520](https://github.com/ydb-platform/ydb-embedded-ui/issues/520)) ([425c9ae](https://github.com/ydb-platform/ydb-embedded-ui/commit/425c9ae1fed83d7695d2a9288c2ef24c2807d8da)) +* **Diagnostics:** update Healthcheck design ([#509](https://github.com/ydb-platform/ydb-embedded-ui/issues/509)) ([e315ca4](https://github.com/ydb-platform/ydb-embedded-ui/commit/e315ca42ac6c9d1736aaa25e2dd90afc2bcb9a8e)) +* **Query:** support PostgreSQL syntax ([#515](https://github.com/ydb-platform/ydb-embedded-ui/issues/515)) ([0c8346e](https://github.com/ydb-platform/ydb-embedded-ui/commit/0c8346efc3643a8d201137901880f985dc100458)) + + +### Bug Fixes + +* **UserSettings:** update query mode setting description ([#521](https://github.com/ydb-platform/ydb-embedded-ui/issues/521)) ([c526471](https://github.com/ydb-platform/ydb-embedded-ui/commit/c52647192ff95d8fb9961479a85cc4d5a639d4e6)) + +## [4.15.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.15.0...v4.15.1) (2023-08-21) + + +### Bug Fixes + +* **SchemaTree:** update create table template ([#512](https://github.com/ydb-platform/ydb-embedded-ui/issues/512)) ([712b3f3](https://github.com/ydb-platform/ydb-embedded-ui/commit/712b3f3612b09fdc5c850ffc3a984cd86827e5b9)) + +## [4.15.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.14.0...v4.15.0) (2023-08-17) + + +### Features + +* **SchemaTree:** add actions for topic ([#507](https://github.com/ydb-platform/ydb-embedded-ui/issues/507)) ([6700136](https://github.com/ydb-platform/ydb-embedded-ui/commit/670013629cb68425e670969323a2ef466ef7c018)) +* **Storage:** sort on backend ([#510](https://github.com/ydb-platform/ydb-embedded-ui/issues/510)) ([034a89a](https://github.com/ydb-platform/ydb-embedded-ui/commit/034a89a9844021c5ea3a73c8f6456e35128078c0)) +* **Storage:** v2 api and backend filters ([#506](https://github.com/ydb-platform/ydb-embedded-ui/issues/506)) ([ce4bf6d](https://github.com/ydb-platform/ydb-embedded-ui/commit/ce4bf6d0ef154b87a7b3a44d56281230b2b5b554)) + +## [4.14.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.13.0...v4.14.0) (2023-08-11) + + +### Features + +* **Nodes:** filter and sort on backend ([#503](https://github.com/ydb-platform/ydb-embedded-ui/issues/503)) ([2e8ab8e](https://github.com/ydb-platform/ydb-embedded-ui/commit/2e8ab8e9965db61ec281f7340b89dd3967b639df)) +* **Query:** add explanation to query duration ([#501](https://github.com/ydb-platform/ydb-embedded-ui/issues/501)) ([a5f5140](https://github.com/ydb-platform/ydb-embedded-ui/commit/a5f5140a23864147d8495e3c6b94709e5e710a9b)) + + +### Bug Fixes + +* **Header:** add icons for nodes and tablets ([#500](https://github.com/ydb-platform/ydb-embedded-ui/issues/500)) ([862660c](https://github.com/ydb-platform/ydb-embedded-ui/commit/862660c1928c2c2b626e4417cd043f0bd5a65df9)) +* **Query:** fix query method selector help text ([#504](https://github.com/ydb-platform/ydb-embedded-ui/issues/504)) ([65cdf9e](https://github.com/ydb-platform/ydb-embedded-ui/commit/65cdf9ee93277c193cc1ad036b2cb38d2ae15b71)) +* **Query:** transfer API calls to a new line ([#499](https://github.com/ydb-platform/ydb-embedded-ui/issues/499)) ([de3d540](https://github.com/ydb-platform/ydb-embedded-ui/commit/de3d5404310f32ba05598bb99a1afb1b65ab45a1)) +* **SchemaTree:** transfer Show Preview to SchemaTree ([#505](https://github.com/ydb-platform/ydb-embedded-ui/issues/505)) ([46220c4](https://github.com/ydb-platform/ydb-embedded-ui/commit/46220c4b2cd111acf12712b4693744c52aaf7231)) + +## [4.13.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.12.0...v4.13.0) (2023-08-04) + + +### Features + +* info and summary tabs for external objects ([#493](https://github.com/ydb-platform/ydb-embedded-ui/issues/493)) ([88d9041](https://github.com/ydb-platform/ydb-embedded-ui/commit/88d9041f080f13046aeaf55765609dbc13b87285)) + + +### Bug Fixes + +* **SchemaTree:** add actions to external objects ([#497](https://github.com/ydb-platform/ydb-embedded-ui/issues/497)) ([5029579](https://github.com/ydb-platform/ydb-embedded-ui/commit/5029579796dd5fb985005f39e9ef8daf142366d0)) +* **SchemaTree:** set required query mode for tree actions ([#491](https://github.com/ydb-platform/ydb-embedded-ui/issues/491)) ([ccd1eda](https://github.com/ydb-platform/ydb-embedded-ui/commit/ccd1edac0d84357cd605c9d131c99890449d8bd8)) + +## [4.12.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.11.1...v4.12.0) (2023-08-02) + + +### Features + +* **Query:** add explanation to the query method selector ([#492](https://github.com/ydb-platform/ydb-embedded-ui/issues/492)) ([ce6407c](https://github.com/ydb-platform/ydb-embedded-ui/commit/ce6407c254e9498d5b3bce60298905ea72621766)) + + +### Bug Fixes + +* fix tablet size ([#490](https://github.com/ydb-platform/ydb-embedded-ui/issues/490)) ([5a9b9d9](https://github.com/ydb-platform/ydb-embedded-ui/commit/5a9b9d955a882b1191502f5bac8eff5cf8638a52)) +* **Search:** add minimum width to Search ([#494](https://github.com/ydb-platform/ydb-embedded-ui/issues/494)) ([2add1dc](https://github.com/ydb-platform/ydb-embedded-ui/commit/2add1dcb3c8a76297ab35600e6d8a8772a411b1d)) + +## [4.11.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.11.0...v4.11.1) (2023-07-27) + + +### Bug Fixes + +* **Issues:** fix types ([#488](https://github.com/ydb-platform/ydb-embedded-ui/issues/488)) ([e2fe731](https://github.com/ydb-platform/ydb-embedded-ui/commit/e2fe731ae23db6703f21179668582d5657de9550)) + +## [4.11.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.10.1...v4.11.0) (2023-07-27) + + +### Features + +* support external objects in schema tree ([#485](https://github.com/ydb-platform/ydb-embedded-ui/issues/485)) ([cf96f9a](https://github.com/ydb-platform/ydb-embedded-ui/commit/cf96f9af02db1352f3990f21f8a84c1282229517)) + + +### Bug Fixes + +* **ClusterInfo:** change cluster default name ([#478](https://github.com/ydb-platform/ydb-embedded-ui/issues/478)) ([398df6e](https://github.com/ydb-platform/ydb-embedded-ui/commit/398df6e3a5778c245653f61b41ba2e1bd0ea3a51)) +* fix copy schema action ([#483](https://github.com/ydb-platform/ydb-embedded-ui/issues/483)) ([f6b01c3](https://github.com/ydb-platform/ydb-embedded-ui/commit/f6b01c3cc2808337d5597f990f65ff3e7c010b05)) +* **Nodes:** support v2 compute ([#476](https://github.com/ydb-platform/ydb-embedded-ui/issues/476)) ([696d43a](https://github.com/ydb-platform/ydb-embedded-ui/commit/696d43a04109c7fc68986e036e66767593af8d00)) +* **ObjectSummary:** fix issue on object change with active schema tab ([#482](https://github.com/ydb-platform/ydb-embedded-ui/issues/482)) ([b50db5f](https://github.com/ydb-platform/ydb-embedded-ui/commit/b50db5ff742c5c7fc27e292309831b937e5d40bd)) +* **ObjectSummary:** fix wrong tree alignment bug ([#486](https://github.com/ydb-platform/ydb-embedded-ui/issues/486)) ([e8bfe99](https://github.com/ydb-platform/ydb-embedded-ui/commit/e8bfe99657870c735a41d24febaa907ac1383479)) +* **Query:** process null issues error ([#480](https://github.com/ydb-platform/ydb-embedded-ui/issues/480)) ([4c4e684](https://github.com/ydb-platform/ydb-embedded-ui/commit/4c4e6845e539296ecbdefa930bc63d3321f277dc)) + +## [4.10.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.10.0...v4.10.1) (2023-07-14) + + +### Bug Fixes + +* apply design fixes ([#475](https://github.com/ydb-platform/ydb-embedded-ui/issues/475)) ([5e7c9ca](https://github.com/ydb-platform/ydb-embedded-ui/commit/5e7c9caa9f54094a3eb6448d92d43242d3e738dd)) +* **AsideNavigation:** replace query icon ([#466](https://github.com/ydb-platform/ydb-embedded-ui/issues/466)) ([4495eb2](https://github.com/ydb-platform/ydb-embedded-ui/commit/4495eb2634e48feda677c03591b92393ad28981e)) +* **ClusterInfo:** add Databases field ([#474](https://github.com/ydb-platform/ydb-embedded-ui/issues/474)) ([28a9936](https://github.com/ydb-platform/ydb-embedded-ui/commit/28a99364bf5e916381a54a59d4d3f979b35f6eff)) +* **Cluster:** make global scroll ([#470](https://github.com/ydb-platform/ydb-embedded-ui/issues/470)) ([30f8bc5](https://github.com/ydb-platform/ydb-embedded-ui/commit/30f8bc5ce52fceda076d278b1464d413e899ae21)) +* **Cluster:** remove tabs icons and numbers ([#473](https://github.com/ydb-platform/ydb-embedded-ui/issues/473)) ([d2e43d4](https://github.com/ydb-platform/ydb-embedded-ui/commit/d2e43d41759b085f34b7f29f52f3aba60cd0588f)) +* **Query:** rename New Query tab to Query ([#467](https://github.com/ydb-platform/ydb-embedded-ui/issues/467)) ([c3f5585](https://github.com/ydb-platform/ydb-embedded-ui/commit/c3f5585562a204ef0831d0c45766b17c3dc72f82)) +* **TableIndexInfo:** format DataSize ([#468](https://github.com/ydb-platform/ydb-embedded-ui/issues/468)) ([a189b8c](https://github.com/ydb-platform/ydb-embedded-ui/commit/a189b8cf9610f6b1b7b5f4c01896eda5f8347ebf)) + +## [4.10.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.9.0...v4.10.0) (2023-07-07) + + +### Bug Fixes + +* **AsideNavigation:** swap icons ([#465](https://github.com/ydb-platform/ydb-embedded-ui/issues/465)) ([13bc92a](https://github.com/ydb-platform/ydb-embedded-ui/commit/13bc92a0150ee8d809b3811b528f5d31f4999815)) +* move sendQuery timeout to request query ([#464](https://github.com/ydb-platform/ydb-embedded-ui/issues/464)) ([6323038](https://github.com/ydb-platform/ydb-embedded-ui/commit/6323038b9e327a9e348812b43514008e9d07640c)) +* **QueryEditor:** do not reset input on empty savedPath ([#451](https://github.com/ydb-platform/ydb-embedded-ui/issues/451)) ([7f98e44](https://github.com/ydb-platform/ydb-embedded-ui/commit/7f98e44834b54bfc1398bb418909fae21e22a3dc)) +* show 5 digits size in table info ([#461](https://github.com/ydb-platform/ydb-embedded-ui/issues/461)) ([8c4ecc4](https://github.com/ydb-platform/ydb-embedded-ui/commit/8c4ecc41ed41cad34debaa6ff7f39f1f10f8d974)) +* **TenantOverview:** add copy button to tenant name ([#459](https://github.com/ydb-platform/ydb-embedded-ui/issues/459)) ([2d8b380](https://github.com/ydb-platform/ydb-embedded-ui/commit/2d8b38049a038fb889e82d0135c026462107a124)) +* **UsageFilter:** fix bar flashes ([#457](https://github.com/ydb-platform/ydb-embedded-ui/issues/457)) ([ae1965e](https://github.com/ydb-platform/ydb-embedded-ui/commit/ae1965ec894c7d012f0ebfc5949b73d4499b390e)) + +## [4.9.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.8.2...v4.9.0) (2023-06-30) + + +### Features + +* **QueryEditor:** remove old controls, update setting ([#445](https://github.com/ydb-platform/ydb-embedded-ui/issues/445)) ([75efd44](https://github.com/ydb-platform/ydb-embedded-ui/commit/75efd444c8b8ba5213117ec9c33f6b9664855a2c)) + + +### Bug Fixes + +* **QueryEditor:** color last used query action, run on command ([#436](https://github.com/ydb-platform/ydb-embedded-ui/issues/436)) ([c4d3bb8](https://github.com/ydb-platform/ydb-embedded-ui/commit/c4d3bb81bc1cea8ec3fe2e5e7e18c997d94f5714)) +* **QueryEditor:** rename query modes ([#449](https://github.com/ydb-platform/ydb-embedded-ui/issues/449)) ([c93c9c1](https://github.com/ydb-platform/ydb-embedded-ui/commit/c93c9c17ba26e01c596009657cac02ecc9cc9ab0)) +* **StorageNodes:** sort by uptime ([#447](https://github.com/ydb-platform/ydb-embedded-ui/issues/447)) ([283cb81](https://github.com/ydb-platform/ydb-embedded-ui/commit/283cb81b3f4711ddc2bb991615729a9bda7e893c)) +* **Storage:** remove visible entities filter ([#448](https://github.com/ydb-platform/ydb-embedded-ui/issues/448)) ([b4d9489](https://github.com/ydb-platform/ydb-embedded-ui/commit/b4d948965cd349a54fe833a6b81ea3b087782735)) + +## [4.8.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.8.1...v4.8.2) (2023-06-27) + + +### Bug Fixes + +* **breadcrumbs:** update tenant and tablet params ([#443](https://github.com/ydb-platform/ydb-embedded-ui/issues/443)) ([b0d31ac](https://github.com/ydb-platform/ydb-embedded-ui/commit/b0d31acce6d6e97d759180c885e6aea3b762a91c)) + +## [4.8.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.8.0...v4.8.1) (2023-06-26) + + +### Bug Fixes + +* **Tenants:** fix tenant link ([#439](https://github.com/ydb-platform/ydb-embedded-ui/issues/439)) ([432c621](https://github.com/ydb-platform/ydb-embedded-ui/commit/432c621eb2fb2ffd5a747299af930236d5cc06f7)) + +## [4.8.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.7.0...v4.8.0) (2023-06-26) + + +### Features + +* **Tenant:** transform general tabs into left navigation items ([#431](https://github.com/ydb-platform/ydb-embedded-ui/issues/431)) ([7117b96](https://github.com/ydb-platform/ydb-embedded-ui/commit/7117b9622d5f6469dcc2bcc1c0d5cb71d4f94c0b)) + +## [4.7.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.6.0...v4.7.0) (2023-06-23) + + +### Features + +* **QueryEditor:** transform history and saved to tabs ([#427](https://github.com/ydb-platform/ydb-embedded-ui/issues/427)) ([6378ca7](https://github.com/ydb-platform/ydb-embedded-ui/commit/6378ca7013239b33e55c1f88fdde7cab3a102df6)) +* update breadcrumbs ([#432](https://github.com/ydb-platform/ydb-embedded-ui/issues/432)) ([e583a03](https://github.com/ydb-platform/ydb-embedded-ui/commit/e583a03fe0d77698f29c924e611133f015c3f7ad)) + + +### Bug Fixes + +* **Cluster:** add icons to tabs ([#430](https://github.com/ydb-platform/ydb-embedded-ui/issues/430)) ([e9e649f](https://github.com/ydb-platform/ydb-embedded-ui/commit/e9e649f614691e44172c9b93dd3119066c145413)) +* **ClusterInfo:** hide by default ([#435](https://github.com/ydb-platform/ydb-embedded-ui/issues/435)) ([ef2b353](https://github.com/ydb-platform/ydb-embedded-ui/commit/ef2b3535f2c6324a34c4386680f5050655a04eb4)) +* **Cluster:** use counter from uikit for tabs ([#428](https://github.com/ydb-platform/ydb-embedded-ui/issues/428)) ([19ca3bd](https://github.com/ydb-platform/ydb-embedded-ui/commit/19ca3bd14b15bdab1a9621939ddceee6d23b08ac)) +* **DetailedOverview:** prevent tenant info scroll on overflow ([#434](https://github.com/ydb-platform/ydb-embedded-ui/issues/434)) ([8ed6076](https://github.com/ydb-platform/ydb-embedded-ui/commit/8ed60760d54913d05f39d35d00a34c8b1d7d9738)) +* rename Internal Viewer to Developer UI ([#423](https://github.com/ydb-platform/ydb-embedded-ui/issues/423)) ([3eb21f3](https://github.com/ydb-platform/ydb-embedded-ui/commit/3eb21f35a230cc591f02ef9b195f99031f832e8a)) +* **Storage:** update columns ([#437](https://github.com/ydb-platform/ydb-embedded-ui/issues/437)) ([264fbc9](https://github.com/ydb-platform/ydb-embedded-ui/commit/264fbc984cd9ef1467110d3e2f5ed9b29a526c2b)) +* **Tablet:** clear tablet data on unmount ([#425](https://github.com/ydb-platform/ydb-embedded-ui/issues/425)) ([5d308cd](https://github.com/ydb-platform/ydb-embedded-ui/commit/5d308cdded342d7a40cbc6a91431d3f286c39b8a)) +* **TabletsStatistic:** use tenant backend ([#429](https://github.com/ydb-platform/ydb-embedded-ui/issues/429)) ([d290684](https://github.com/ydb-platform/ydb-embedded-ui/commit/d290684ba08aec8b66c0492ba571a5337b5b896c)) + +## [4.6.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.5.2...v4.6.0) (2023-06-13) + + +### Features + +* **QueryEditor:** add data and query modes ([#422](https://github.com/ydb-platform/ydb-embedded-ui/issues/422)) ([c142f03](https://github.com/ydb-platform/ydb-embedded-ui/commit/c142f03e9caeab4dcf1d34b3988e949a94213932)) +* rework navigation, update breadcrumbs ([#418](https://github.com/ydb-platform/ydb-embedded-ui/issues/418)) ([2d807d6](https://github.com/ydb-platform/ydb-embedded-ui/commit/2d807d6a52e13edcf2a7e1591672224339d91949)) + + +### Bug Fixes + +* **Diagnostics:** remove unneded tenantInfo fetch ([#420](https://github.com/ydb-platform/ydb-embedded-ui/issues/420)) ([ccaafe4](https://github.com/ydb-platform/ydb-embedded-ui/commit/ccaafe4ec9346ee1ec2ebd2a62600274f2175bfb)) + +## [4.5.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.5.1...v4.5.2) (2023-06-06) + + +### Bug Fixes + +* **Versions:** enable table dynamic render ([#416](https://github.com/ydb-platform/ydb-embedded-ui/issues/416)) ([3c877ea](https://github.com/ydb-platform/ydb-embedded-ui/commit/3c877ea88a0c4036213b38099676f473cf3ac2d6)) + +## [4.5.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.5.0...v4.5.1) (2023-06-02) + + +### Bug Fixes + +* **Tablet:** fetch data on action finish ([#405](https://github.com/ydb-platform/ydb-embedded-ui/issues/405)) ([f1d71c5](https://github.com/ydb-platform/ydb-embedded-ui/commit/f1d71c5af330a0a13246f8d87433e6bba1d3509a)) + +## [4.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.4.2...v4.5.0) (2023-06-01) + + +### Features + +* **ClusterInfo:** update versions bar, rework DC and Tablets fields ([#407](https://github.com/ydb-platform/ydb-embedded-ui/issues/407)) ([4824f0d](https://github.com/ydb-platform/ydb-embedded-ui/commit/4824f0d2be9d7bec3641302c88b39a3a87f37c18)) + +## [4.4.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.4.1...v4.4.2) (2023-05-29) + + +### Bug Fixes + +* **Partitions:** fix offsets calculation ([#402](https://github.com/ydb-platform/ydb-embedded-ui/issues/402)) ([fd4741f](https://github.com/ydb-platform/ydb-embedded-ui/commit/fd4741f8761aa6aa9ec31681522c4d261a83273f)) + +## [4.4.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.4.0...v4.4.1) (2023-05-25) + + +### Bug Fixes + +* **Nodes:** fix endpoint setting ([#397](https://github.com/ydb-platform/ydb-embedded-ui/issues/397)) ([4aea8a2](https://github.com/ydb-platform/ydb-embedded-ui/commit/4aea8a2597909338e31ac51577989a4d82ec93cf)) + +## [4.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.3.0...v4.4.0) (2023-05-25) + + +### Features + +* add Versions ([#394](https://github.com/ydb-platform/ydb-embedded-ui/issues/394)) ([d5abb58](https://github.com/ydb-platform/ydb-embedded-ui/commit/d5abb586a127135c5756a3aa5076060c0dce3fba)) +* remove unsupported pages ([b2bc3b2](https://github.com/ydb-platform/ydb-embedded-ui/commit/b2bc3b22029679769bb0de73f2c33827028de8a8)) + + +### Bug Fixes + +* **ClusterInfo:** do not show response error on cancelled requests ([83501b5](https://github.com/ydb-platform/ydb-embedded-ui/commit/83501b50f0c266ba654858767ca89a2a3fa891ed)) +* **Cluster:** remove padding from cluster page ([8138823](https://github.com/ydb-platform/ydb-embedded-ui/commit/8138823a9d5d3dbd1f086fb0bb23265d7faa8025)) +* **Partitions:** fix columns titles ([4fe21a0](https://github.com/ydb-platform/ydb-embedded-ui/commit/4fe21a0dc149c7bca0611c74990756fbdc5fb273)) +* **Partitions:** update Select empty value ([a7df6d1](https://github.com/ydb-platform/ydb-embedded-ui/commit/a7df6d1c86224a4534fac048cebc61b6f5a78fde)) +* **UserSettings:** separate Setting, enable additional settings ([#396](https://github.com/ydb-platform/ydb-embedded-ui/issues/396)) ([e8a17a1](https://github.com/ydb-platform/ydb-embedded-ui/commit/e8a17a160c82212a181b1ef4e3b9f223db29907e)) + +## [4.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.2.1...v4.3.0) (2023-05-18) + + +### Features + +* **Partitions:** display partitions for topic without consumers ([0843a49](https://github.com/ydb-platform/ydb-embedded-ui/commit/0843a49c46cb6765b376832a847c3ac0ce8b6b85)) + + +### Bug Fixes + +* **Tablet:** update state to color mapping ([7ccc8c7](https://github.com/ydb-platform/ydb-embedded-ui/commit/7ccc8c79225cd311a7a3674150335b58a94f293e)) + +## [4.2.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.2.0...v4.2.1) (2023-05-18) + + +### Bug Fixes + +* export toaster ([b5d12c0](https://github.com/ydb-platform/ydb-embedded-ui/commit/b5d12c0aa39ea3877a9b74071e3124f89a309ca3)) + +## [4.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.1.0...v4.2.0) (2023-05-16) + + +### Features + +* **Tablet:** display node fqdn in table ([4d8099a](https://github.com/ydb-platform/ydb-embedded-ui/commit/4d8099a454f34fc76886b26ca948895171c57ab8)) + + +### Bug Fixes + +* **api:** change nulls to empty objects ([0ab14e8](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ab14e883a47aeac2f2bab437f2214a32ccb1c9b)) +* display storage pool in VDisks popups ([5b5dd8a](https://github.com/ydb-platform/ydb-embedded-ui/commit/5b5dd8a4e6cb4bcc1ead78a7c06d2e80a81424cc)) +* fix Select label and values align ([f796730](https://github.com/ydb-platform/ydb-embedded-ui/commit/f7967309fe4a042e7637de212f33b1ebfc6877fc)) +* **Overview:** partitioning by size disabled for 0 SizeToSpit ([1028e7d](https://github.com/ydb-platform/ydb-embedded-ui/commit/1028e7d8d3566f5f5e6b2ebe04112ef135d7b55e)) +* **Schema:** display NotNull columns ([d61eaa4](https://github.com/ydb-platform/ydb-embedded-ui/commit/d61eaa4ccff357c1e9ca6efde855ec46be24a314)) + +## [4.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.0.0...v4.1.0) (2023-05-10) + + +### Features + +* **Navigation:** remove legacy navigation setting support ([8544f11](https://github.com/ydb-platform/ydb-embedded-ui/commit/8544f114255ba44834d38cd9e709450c49e4a96a)) + + +### Bug Fixes + +* disable link and popover for unavailable nodes ([990a9fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/990a9fa42a7133a6c40d07e11c3518240e18b4a9)) + +## [4.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.5.0...v4.0.0) (2023-04-28) + + +### ⚠ BREAKING CHANGES + +* app no longer parses query responses from older ydb versions +* v0.1 explain plans are no longer rendered + +### Features + +* enable explain-script parsing, remove deprecated code ([5c6e9a2](https://github.com/ydb-platform/ydb-embedded-ui/commit/5c6e9a21026ea9eb3e32650e6fdda89c7900e7e6)) +* **QueryEditor:** add explain query modes ([39ad943](https://github.com/ydb-platform/ydb-embedded-ui/commit/39ad9434c1622e22901e6cc1af1568e0edf6b434)) +* **QueryEditor:** display query duration ([967f102](https://github.com/ydb-platform/ydb-embedded-ui/commit/967f10296d2362709654172ed7318509286efc78)) +* remove support for explain v0.1 ([c8741a6](https://github.com/ydb-platform/ydb-embedded-ui/commit/c8741a69b82053185a07c7ba563455d4f28ecdce)) + + +### Bug Fixes + +* **query:** correctly process NetworkError on actions failure ([cf5bd6c](https://github.com/ydb-platform/ydb-embedded-ui/commit/cf5bd6c5c4c2972fec93b2dc9135c92c639fa5f9)) +* **QueryExplain:** do not request ast when missing ([54cf151](https://github.com/ydb-platform/ydb-embedded-ui/commit/54cf151452e17256173736450f5727085ea591ff)) +* **QueryExplain:** request AST if it is empty ([d028b4e](https://github.com/ydb-platform/ydb-embedded-ui/commit/d028b4ed08a98281baff81683204f1cbc1c20c37)) + +## [3.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.5...v3.5.0) (2023-04-18) + + +### Features + +* **TableInfo:** extend Table and ColumnTable info ([89e54aa](https://github.com/ydb-platform/ydb-embedded-ui/commit/89e54aa97d7bcbabfd5100daeb1dc0c03608e86e)) +* **TopQueries:** add columns ([b49b98d](https://github.com/ydb-platform/ydb-embedded-ui/commit/b49b98db2da08c355b23f4a33bf05247530543db)) + + +### Bug Fixes + +* **settings:** use system theme by default ([726c9cb](https://github.com/ydb-platform/ydb-embedded-ui/commit/726c9cb14d7f87cc9248340d1ebebfc8bf0d0384)) +* **Storage:** fix incorrect usage on zero available space ([2704cd7](https://github.com/ydb-platform/ydb-embedded-ui/commit/2704cd7c696d337cc8e3af68941cf444f8dfae81)) +* **TableInfo:** add default format for FollowerGroup fields ([961334a](https://github.com/ydb-platform/ydb-embedded-ui/commit/961334aabe89672994f0f3440e20602e180b3394)) +* **Tablet:** fix dialog type enum ([c477042](https://github.com/ydb-platform/ydb-embedded-ui/commit/c477042cacc2e777cae4bd6981381a8042c603ed)) +* **TopQueries:** enable go back to TopQueries from Query tab ([bbdfe72](https://github.com/ydb-platform/ydb-embedded-ui/commit/bbdfe726c9081f01422dca787b83399ea44b3956)) +* **TopShards:** fix table crash on undefined values ([604e99a](https://github.com/ydb-platform/ydb-embedded-ui/commit/604e99a9427021c61ceb8ea366e316e629032b84)) +* **TruncatedQuery:** wrap message ([f41b7ff](https://github.com/ydb-platform/ydb-embedded-ui/commit/f41b7ff33ac0145446ca89aab031036247f3ddf8)) + +## [3.4.5](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.4...v3.4.5) (2023-03-30) + + +### Bug Fixes + +* **Consumers:** fix typo ([aaa9dbd](https://github.com/ydb-platform/ydb-embedded-ui/commit/aaa9dbda1f28702917793a61bae2813f6ef018bb)) +* **PDisk:** add display block to content ([130dab2](https://github.com/ydb-platform/ydb-embedded-ui/commit/130dab20ffdc9da77225c94a6e6064f0308a1c2a)) +* **Storage:** get nodes hosts from /nodelist ([cc82dd9](https://github.com/ydb-platform/ydb-embedded-ui/commit/cc82dd93808133b0d1dcd21b31ee3744df4f7383)) +* **StorageNodes:** make fqdn similar to nodes page ([344298a](https://github.com/ydb-platform/ydb-embedded-ui/commit/344298a9a29380f1068b002fa304cdcc221ce0d4)) +* **TopicInfo:** do not display /s when speed is undefined ([2d41832](https://github.com/ydb-platform/ydb-embedded-ui/commit/2d4183247ec33acdfa45be72a93f0dbd93b716e0)) +* **TopicStats:** use prepared stats, update fields ([a614a8c](https://github.com/ydb-platform/ydb-embedded-ui/commit/a614a8caa2744b844d97f23f25e5385387367d6b)) + +## [3.4.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.3...v3.4.4) (2023-03-22) + + +### Bug Fixes + +* **Diagnostics:** display nodes tab for not db entities ([a542dbc](https://github.com/ydb-platform/ydb-embedded-ui/commit/a542dbc23d01138a5c1a4126cfc1836a1543b68c)) + +## [3.4.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.2...v3.4.3) (2023-03-17) + + +### Bug Fixes + +* add opacity to unavailable nodes ([8b82c78](https://github.com/ydb-platform/ydb-embedded-ui/commit/8b82c78f0b6bed536ca23c63b78b141b29afc4a8)) +* **Tablet:** add error check ([49f13cf](https://github.com/ydb-platform/ydb-embedded-ui/commit/49f13cf0cff2d6dad59b8f6a4c2885966bf3450a)) +* **VDisk:** fix typo ([1528d03](https://github.com/ydb-platform/ydb-embedded-ui/commit/1528d03531f482e438e0bdb6c761be236822fc27)) + +## [3.4.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.1...v3.4.2) (2023-03-03) + + +### Bug Fixes + +* **Partitions:** add search to consumers filter ([95e4462](https://github.com/ydb-platform/ydb-embedded-ui/commit/95e446295cb2b2729daf0d0ef719e37c7c8e0d3c)) +* **Partitions:** fix error on wrong consumer in query string ([44269fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/44269fa9240fe31c9ef69e061c20d58b2b55fae3)) +* **PDisk:** display vdisks donors ([8b39b01](https://github.com/ydb-platform/ydb-embedded-ui/commit/8b39b01e8bf62624e9e12ac0a329fda5d03cc8df)) + +## [3.4.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.0...v3.4.1) (2023-03-01) + + +### Bug Fixes + +* **Consumers:** enable navigation to Partitions tab ([fa79081](https://github.com/ydb-platform/ydb-embedded-ui/commit/fa7908124bc4392e272aa829fd4e5c1639fcf209)) +* **Consumers:** update topic stats values align ([f2af851](https://github.com/ydb-platform/ydb-embedded-ui/commit/f2af851208a640ef9aa392fd7176eb579a2401db)) +* **TopShards:** keep state on request cancel ([1bd4f65](https://github.com/ydb-platform/ydb-embedded-ui/commit/1bd4f65dd047b42f8edf9e4bb41c722f30220d77)) + +## [3.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.4...v3.4.0) (2023-02-17) + + +### Features + +* **Diagnostics:** add Partitions tab ([914702b](https://github.com/ydb-platform/ydb-embedded-ui/commit/914702be7e8aea28fcdc9f2ddf1cb7356995146a)) +* **Diagnostics:** rework Consumers tab ([0dae9d8](https://github.com/ydb-platform/ydb-embedded-ui/commit/0dae9d84c254d556db2a0d18345fdc10c152172a)) + + +### Bug Fixes + +* add read and lag images ([a3f0648](https://github.com/ydb-platform/ydb-embedded-ui/commit/a3f0648fc4f23c2ac2c9e73c4078bf5f06d1a57e)) +* add reducer for consumer ([4ab65e3](https://github.com/ydb-platform/ydb-embedded-ui/commit/4ab65e3fb3dd4f29b4757473275ba84bec0f5411)) +* add SpeedMultiMeter component ([39acbf1](https://github.com/ydb-platform/ydb-embedded-ui/commit/39acbf1a1e234f36a090b29935872e694e1525c0)) +* **ResponseError:** make error prop optional ([f706e94](https://github.com/ydb-platform/ydb-embedded-ui/commit/f706e940e51e62841e18338775b01183831761e1)) +* **Storage:** display not full donors ([13f4b9f](https://github.com/ydb-platform/ydb-embedded-ui/commit/13f4b9fe9f796e8ef6fee094f7b5bc6056e2833b)) +* **Topic:** use SpeedMultiMeter and utils functions ([3e0293c](https://github.com/ydb-platform/ydb-embedded-ui/commit/3e0293cc5cf69c2dee5b6c4cdcf053829960dac5)) +* **utils:** add formatBytesCustom function ([2f18c22](https://github.com/ydb-platform/ydb-embedded-ui/commit/2f18c2233b37b666e16327af0ca8e20bccf01de6)) + +## [3.3.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.3...v3.3.4) (2023-02-16) + + +### Bug Fixes + +* **OverloadedShards:** rename to top shards ([ffa4f27](https://github.com/ydb-platform/ydb-embedded-ui/commit/ffa4f27f2cf0a5e12b2800c81bf61b1d3c25912c)) +* **StorageGroups:** display Erasure ([4a7ebc0](https://github.com/ydb-platform/ydb-embedded-ui/commit/4a7ebc08b87fe75af83df70a38ebd486d64d6d4e)) +* **TopShards:** switch between history and immediate data ([eeb9bb0](https://github.com/ydb-platform/ydb-embedded-ui/commit/eeb9bb0911b9e889b633558c9d3c13f986f72bfe)) + +## [3.3.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.2...v3.3.3) (2023-02-08) + + +### Bug Fixes + +* **Auth:** add a step in history for auth form ([c72d06e](https://github.com/ydb-platform/ydb-embedded-ui/commit/c72d06ecacdba47cac59bd705c1185e1ddf0b20d)) +* format dates with date-utils ([948598b](https://github.com/ydb-platform/ydb-embedded-ui/commit/948598b83c9bdd09268d128e15a42d5a6e0c15cc)) +* **InfoViewer:** add prop renderEmptyState ([44fe28f](https://github.com/ydb-platform/ydb-embedded-ui/commit/44fe28f72ea299b3b5d9b5a33a0a0130d471f7dd)) +* minor fixes in Nodes and Tenants tables ([8dca43a](https://github.com/ydb-platform/ydb-embedded-ui/commit/8dca43a482b0da31dbc618875b416dcfcedac036)) +* **OverloadedShards:** display IntervalEnd ([c7cbd72](https://github.com/ydb-platform/ydb-embedded-ui/commit/c7cbd7215eaf60601941410acb13ffb25d151eb9)) +* **Overview:** display error statusText on schema error ([99b030f](https://github.com/ydb-platform/ydb-embedded-ui/commit/99b030f90e6044e98a151e5128603835c84e1b4e)) +* **PDisk:** calculate severity based on usage ([64c6890](https://github.com/ydb-platform/ydb-embedded-ui/commit/64c6890ac6d5a77aef73da7dfc7f1eaff8a72441)) +* **QueryEditor:** make client request timeout 9 min ([44528a8](https://github.com/ydb-platform/ydb-embedded-ui/commit/44528a865b039003cda4c7b1b1367840da015d09)) +* **QueryEditor:** result status for aborted connection ([4b0d84b](https://github.com/ydb-platform/ydb-embedded-ui/commit/4b0d84b550deb41a140d4a3d215e52084507a558)) +* **QueryResult:** output client error messages ([deef610](https://github.com/ydb-platform/ydb-embedded-ui/commit/deef6103f4d08825837520cab9e8ae5b8c7fd496)) +* **Storage:** replace hasOwn to hasOwnProperty ([2452310](https://github.com/ydb-platform/ydb-embedded-ui/commit/2452310ce8e953d7a9ee4bbaa2bd466396aa0131)) +* **TopQueries:** display IntervalEnd ([e5b2b07](https://github.com/ydb-platform/ydb-embedded-ui/commit/e5b2b07cf1e686c20817dcdc1ae32e0c8912a21a)) + +## [3.3.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.1...v3.3.2) (2023-01-31) + + +### Bug Fixes + +* **QueryEditor:** collapse bottom panel if empty ([566db3b](https://github.com/ydb-platform/ydb-embedded-ui/commit/566db3b15c4393555071f058c88ad36b4073cc2d)) +* **VDisk:** use pdiskid field for link ([5ee0705](https://github.com/ydb-platform/ydb-embedded-ui/commit/5ee0705416aa31be9bee4be0776ecb8a61d3e82c)) + +## [3.3.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.0...v3.3.1) (2023-01-31) + + +### Bug Fixes + +* **UserSettings:** reword nodes setting and add popup ([2fda2b8](https://github.com/ydb-platform/ydb-embedded-ui/commit/2fda2b815b921a8163f80527c45f788172df4ba8)) + +## [3.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.2.3...v3.3.0) (2023-01-30) + + +### Features + +* **Nodes:** use /viewer/json/nodes endpoint ([226cc70](https://github.com/ydb-platform/ydb-embedded-ui/commit/226cc70dcb89262890856b4d0cb03eac0675256d)) +* **Overview:** display topic stats for topics and streams ([08e9fe0](https://github.com/ydb-platform/ydb-embedded-ui/commit/08e9fe0ee379715229474322a03ec668e26bdb9b)) +* **Storage:** display vdisks over pdisks ([bb5d1fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/bb5d1fa5ae2953ca30b13df45340b7a1a63056cb)) + + +### Bug Fixes + +* add duration formatter ([e325d98](https://github.com/ydb-platform/ydb-embedded-ui/commit/e325d98845d29dea208debdfcb88d330c1d6daee)) +* add protobuf time formatters ([c74cd9d](https://github.com/ydb-platform/ydb-embedded-ui/commit/c74cd9d0949674414ba2c9754e3dcc5c2be622a5)) +* add verticalBars component ([053ffa8](https://github.com/ydb-platform/ydb-embedded-ui/commit/053ffa8fd460f89f4296a96fcf46a9267ac4cae3)) +* **PDisk:** grey color for unknown state ([54f7e15](https://github.com/ydb-platform/ydb-embedded-ui/commit/54f7e159aaddd932ccecddfb10265ee596fed1e2)) +* **Storage:** request only static nodes ([e91e136](https://github.com/ydb-platform/ydb-embedded-ui/commit/e91e136d7c72bea694c7a282c83d577cc60e5386)) +* **Topic:** add reducer for describe_topic ([7c61dc9](https://github.com/ydb-platform/ydb-embedded-ui/commit/7c61dc906452df2e1a77a2ff602916f6ea785df5)) +* update PDisks and VDisks tests ([3bf660e](https://github.com/ydb-platform/ydb-embedded-ui/commit/3bf660e41d92e1a32444872c5fb9d47209bef8b5)) + +## [3.2.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.2.2...v3.2.3) (2023-01-16) + + +### Bug Fixes + +* fix crash on invalid search query ([4d6f551](https://github.com/ydb-platform/ydb-embedded-ui/commit/4d6f551fa4348a05ca3d8d2d6bd8b52ccb6310ee)) + +## [3.2.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.2.1...v3.2.2) (2023-01-13) + + +### Bug Fixes + +* **Tablets:** fix infinite rerender ([79b3c58](https://github.com/ydb-platform/ydb-embedded-ui/commit/79b3c58fb7c3ff7f123e111189b10f42c5272401)) + +## [3.2.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.2.0...v3.2.1) (2023-01-12) + + +### Bug Fixes + +* align standard errors to the left ([cce100c](https://github.com/ydb-platform/ydb-embedded-ui/commit/cce100c5df83243df1fb0bc59d84d0d9b33719e6)) +* **TabletsFilters:** properly display long data in select options ([ea37d9f](https://github.com/ydb-platform/ydb-embedded-ui/commit/ea37d9fc08245ccdd38a6120dd620f59a528879c)) +* **TabletsFilters:** replace constants ([ea948ca](https://github.com/ydb-platform/ydb-embedded-ui/commit/ea948ca86276b5521979105b2ab99546da389e80)) +* **TabletsStatistic:** process different tablets state types ([78798de](https://github.com/ydb-platform/ydb-embedded-ui/commit/78798de984bf4f6133515bb1c440e4fe0d15b07e)) +* **Tenant:** always display Pools heading ([94baeff](https://github.com/ydb-platform/ydb-embedded-ui/commit/94baeff82f9c2c1aecda7c11c3b090125ba9e4b6)) + +## [3.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.1.0...v3.2.0) (2023-01-09) + + +### Features + +* **Nodes:** display rack in table ([3b8cdd5](https://github.com/ydb-platform/ydb-embedded-ui/commit/3b8cdd5b472f98132b2faaa9b71b8911750545a6)) +* **StorageNodes:** display datacenter in table ([4507bfd](https://github.com/ydb-platform/ydb-embedded-ui/commit/4507bfde839b0aafa3722828b7528885c6ac8f84)) +* **TopQueries:** date range filter ([b9a8e95](https://github.com/ydb-platform/ydb-embedded-ui/commit/b9a8e9504fa68556a724b214ee91b73ec900d37e)) +* **TopQueries:** filter by query text ([2c8ea97](https://github.com/ydb-platform/ydb-embedded-ui/commit/2c8ea97dd215ea59165cf05315bc5809cf7fafd7)) + + +### Bug Fixes + +* **InfoViewer:** min width for values ([64a4fd4](https://github.com/ydb-platform/ydb-embedded-ui/commit/64a4fd4de16738a9e2fac9cb4fba94eafc938762)) +* **Nodes:** open external link in new tab ([b7c3ddd](https://github.com/ydb-platform/ydb-embedded-ui/commit/b7c3ddd1e611f2b61466e3eda51f3341f8407588)) +* **TopQueries:** proper table dynamic render type ([9add6ca](https://github.com/ydb-platform/ydb-embedded-ui/commit/9add6ca9fbfe0475caf1586070a800210320cee6)) +* **TopShards:** rename to overloaded shards ([d9978bd](https://github.com/ydb-platform/ydb-embedded-ui/commit/d9978bdd84b9a883e4eefcac7f85f856da55d770)) +* **UserSettings:** treat invertedDisks settings as string ([ad7742a](https://github.com/ydb-platform/ydb-embedded-ui/commit/ad7742a6bf0be59c2b9cbbf947aaa66f79d748be)) + +## [3.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.0.1...v3.1.0) (2022-12-13) + + +### Features + +* **TopShards:** date range filter ([aab4396](https://github.com/ydb-platform/ydb-embedded-ui/commit/aab439600ec28d30799c4a7ef7a9c68fcacc148c)) + +## [3.0.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.0.0...v3.0.1) (2022-12-12) + + +### Bug Fixes + +* **Overview:** display titles for topic, stream and tableIndex ([2ee7889](https://github.com/ydb-platform/ydb-embedded-ui/commit/2ee788932d4f0a6fbe3e9e0526b8ba50e3103d76)) +* **SchemaOverview:** display entity name ([2d28a2a](https://github.com/ydb-platform/ydb-embedded-ui/commit/2d28a2ad30263e31bc3c8b783d4f42af92537624)) +* **TenantOverview:** display database type in title ([5f73eed](https://github.com/ydb-platform/ydb-embedded-ui/commit/5f73eed6f9043586885f8e68137d8f31923e8e3b)) +* **TopShards:** render a message for empty data ([8cda003](https://github.com/ydb-platform/ydb-embedded-ui/commit/8cda0038396b356b10033b44824933f711e1175e)) + +## [3.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.6.0...v3.0.0) (2022-12-05) + + +### ⚠ BREAKING CHANGES + +Updated build config ([11e02c6](https://github.com/ydb-platform/ydb-embedded-ui/commit/11e02c668ef186f058b2ece9d5f1082d0e96e23d)) + +**Before the change** +- the target dir for the production build was `build/resources` +- `favicon.png` was placed directly in `build` + +**After the change** +- the target dir is `build/static` +- `favicon.png` is in `build/static` + +This change is intended to simplify build config and make it closer to the default one. Previously there were some custom tweaks after the build, they caused bugs and were hard to maintain. Now the application builds using the default `create-react-app` config. + + +## [2.6.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.5.0...v2.6.0) (2022-12-05) + + +### Features + +* **Describe:** add topic data for CDCStream ([3a289d4](https://github.com/ydb-platform/ydb-embedded-ui/commit/3a289d4f6452e3f2d719c0d508f48b389fd044d7)) +* **Diagnostics:** add consumers tab for CdcStream ([22c6efd](https://github.com/ydb-platform/ydb-embedded-ui/commit/22c6efdd39d85ab1585943bc13d88cf03f9bc2ae)) +* **Overview:** add topic data for CDCStream ([be80545](https://github.com/ydb-platform/ydb-embedded-ui/commit/be80545df65a03820265875fedd98c6f181af491)) + + +### Bug Fixes + +* **Compute:** update data on path change ([1783240](https://github.com/ydb-platform/ydb-embedded-ui/commit/17832403623ae3e718f47aec508c834cd2e3458c)) +* **Diagnostics:** render db tabs for not root dbs ([7d46ce2](https://github.com/ydb-platform/ydb-embedded-ui/commit/7d46ce2783a58b1ae6e41cae6592e78f95d61bcc)) +* **Healthcheck:** render loader on path change ([ec40f19](https://github.com/ydb-platform/ydb-embedded-ui/commit/ec40f19c0b369de0b8d0658b4a1dd68c5c419c1c)) +* **InfoViewer:** allow multiline values ([17755dc](https://github.com/ydb-platform/ydb-embedded-ui/commit/17755dc2eae7b6fc0a56ff70da95679fc590dccb)) +* **Network:** update data on path change ([588c53f](https://github.com/ydb-platform/ydb-embedded-ui/commit/588c53f80a81376301216a77d9ead95cdff9812f)) +* **SchemaTree:** do not expand childless components ([90468de](https://github.com/ydb-platform/ydb-embedded-ui/commit/90468de74b74e00a66255ba042378c9d7e1cbc27)) +* **Storage:** update data on path change ([f5486bc](https://github.com/ydb-platform/ydb-embedded-ui/commit/f5486bcb2838b9e290c566089980533b4d22d035)) +* **Tablets:** fix postponed data update on path change ([d474c6c](https://github.com/ydb-platform/ydb-embedded-ui/commit/d474c6cb36597f0c720ef3bb8d0360ec73973e26)) +* **TopQueries:** update data on path change ([32d7720](https://github.com/ydb-platform/ydb-embedded-ui/commit/32d77208b8ef09682c41160c60a1a7742b0c6c4c)) + +## [2.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.4...v2.5.0) (2022-11-25) + + +### Features + +* **Nodes:** add uptime filter ([9bb4f66](https://github.com/ydb-platform/ydb-embedded-ui/commit/9bb4f664df8fadec5b5e612b2adb866c28415efa)) +* **NodesViewer:** add uptime filter ([a802442](https://github.com/ydb-platform/ydb-embedded-ui/commit/a8024422a09ff95e55c399d26046f5103cab3f89)) +* **Storage:** add nodes uptime filter ([d8cfea1](https://github.com/ydb-platform/ydb-embedded-ui/commit/d8cfea14369e8235d1f7ef86a9a3f34c05efdf5c)) + + +### Bug Fixes + +* **Consumers:** add autorefresh to useAutofetcher ([e0da2a1](https://github.com/ydb-platform/ydb-embedded-ui/commit/e0da2a11fcd18cb8ba808a07873a78cbf7191cdc)) +* **Consumers:** add loader ([a59f472](https://github.com/ydb-platform/ydb-embedded-ui/commit/a59f472fd7c9347bcde8cc21d4001f999fc88110)) +* **QueryExplain:** fix schema rerender on path change ([eb52978](https://github.com/ydb-platform/ydb-embedded-ui/commit/eb529787bf747bb2bf49bae65676011426341a23)) +* **Storage:** add message on empty nodes with small uptime ([70959ab](https://github.com/ydb-platform/ydb-embedded-ui/commit/70959ab90bd0f81ebab7712b7d34c0ca80f4dd0b)) +* **Storage:** fix uneven PDisks ([0269dba](https://github.com/ydb-platform/ydb-embedded-ui/commit/0269dbab0336ae5b8cbf43e1b52458e932527a66)) +* **StorageNodes:** fix message display on not empty data ([bb5fffa](https://github.com/ydb-platform/ydb-embedded-ui/commit/bb5fffa786cde3f680375f8e11e3893c52c4f6da)) +* **UsageFilter:** add min-width ([56b2701](https://github.com/ydb-platform/ydb-embedded-ui/commit/56b2701a17420e0322fac0223bce26e18a2f0e47)) + +## [2.4.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.3...v2.4.4) (2022-11-22) + + +### Bug Fixes + +* **api:** update getDescribe and getSchema requests params ([d70ba54](https://github.com/ydb-platform/ydb-embedded-ui/commit/d70ba54b90b9c86a393bd3f7845183114e5afbf1)) +* **describe:** cancel concurrent requests ([2f39ad0](https://github.com/ydb-platform/ydb-embedded-ui/commit/2f39ad0f736d44c3749d9523f5024151c51fcf6f)) +* **Describe:** render loader on path change ([baf552a](https://github.com/ydb-platform/ydb-embedded-ui/commit/baf552af8bb67046baa36e9115064b4b192cb015)) +* **QueryExplain:** fix colors on theme change ([cc0a2d6](https://github.com/ydb-platform/ydb-embedded-ui/commit/cc0a2d67139457748089c6bf1fb1045b0a6b0b93)) +* **SchemaTree:** remove unneeded fetches ([c7c0489](https://github.com/ydb-platform/ydb-embedded-ui/commit/c7c048937c5ae9e5e243d6e538aab8c2e2921df5)) +* **SchemaTree:** remove unneeded getDescribe ([1146f13](https://github.com/ydb-platform/ydb-embedded-ui/commit/1146f13a7a5a277a292b3789d45a0872dda0c487)) +* **Tenant:** make tenant fetch schema only on tenant change ([ccefbff](https://github.com/ydb-platform/ydb-embedded-ui/commit/ccefbffea08fc8f248a3dd1135e82de6db9f0645)) + +## [2.4.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.2...v2.4.3) (2022-11-14) + + +### Bug Fixes + +* fix app crash on ColumnTable path type ([a1aefa8](https://github.com/ydb-platform/ydb-embedded-ui/commit/a1aefa876600b1b459bf3024f0704883431df5a2)) +* **schema:** add types for ColumnTable and ColumnStore ([dc13307](https://github.com/ydb-platform/ydb-embedded-ui/commit/dc13307dcea801c05863b7dd5ee19f01aa074c85)) + +## [2.4.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.1...v2.4.2) (2022-11-09) + + +### Bug Fixes + +* **QueryExplain:** apply all node types ([06d26de](https://github.com/ydb-platform/ydb-embedded-ui/commit/06d26def15496f8e2de00d941b39bf6a68382f14)) + +## [2.4.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.0...v2.4.1) (2022-11-01) + + +### Performance Improvements + +* **SchemaTree:** batch preloaded data dispatch ([c9ac514](https://github.com/ydb-platform/ydb-embedded-ui/commit/c9ac514aabf5e9674aae95956604f47ba8a2d257)) + +## [2.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.3.0...v2.4.0) (2022-10-27) + + +### Features + +* **Diagnostics:** add consumers tab for topics ([4bb801c](https://github.com/ydb-platform/ydb-embedded-ui/commit/4bb801c0ef19dcda227c59e464b08f5e8f284c38)) + + +### Bug Fixes + +* add checks for fetch failure with no errors ([2c55107](https://github.com/ydb-platform/ydb-embedded-ui/commit/2c55107a7b47b3540ed0af66630ff85591f269a1)) +* **Nodes:** display access denied on 403 ([7832afe](https://github.com/ydb-platform/ydb-embedded-ui/commit/7832afee601a40fc8b75f83bf0ed18b01c798d71)) +* **QueryResult:** fix table display in fullscreen ([98674db](https://github.com/ydb-platform/ydb-embedded-ui/commit/98674db26b5fb09ac0d039a7779ae0c58951adde)) +* **QueryResultTable:** make preview display all rows ([0ac83d0](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ac83d0258b0d0d3d2e14c06be096fe5ddce02da)) +* **Storage:** display access denied on 403 ([6d20333](https://github.com/ydb-platform/ydb-embedded-ui/commit/6d2033378956a54f05190905b0d537c6bd6c9851)) +* **TabletsFilters:** display access denied on 403 ([018be19](https://github.com/ydb-platform/ydb-embedded-ui/commit/018be199602123f1d90e58c0b95545f6accc41fb)) + +## [2.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.2.1...v2.3.0) (2022-10-24) + + +### Features + +* **PDisk:** display type on disk progressbar ([00bcbf5](https://github.com/ydb-platform/ydb-embedded-ui/commit/00bcbf5d439ca3bb4834fd5f191c65f0ac62585f)) +* **Storage:** display media type for groups ([cdff5e9](https://github.com/ydb-platform/ydb-embedded-ui/commit/cdff5e9882f3f1f8769a3aeaf3e53c05f3ce1c07)) +* **Storage:** display shield icon for encrypted groups ([d0a4442](https://github.com/ydb-platform/ydb-embedded-ui/commit/d0a4442dc100c312dcc54afcf685057cc587211d)) + + +### Bug Fixes + +* **Diagnostics:** fix tabs reset on page reload ([68d2971](https://github.com/ydb-platform/ydb-embedded-ui/commit/68d297165aea1360d1081349d8133804004f8fe0)) +* **Storage:** prevent loading reset on cancelled fetch ([625159a](https://github.com/ydb-platform/ydb-embedded-ui/commit/625159a396e1ab84fe9da94d047da67fdd03b30f)) +* **Storage:** shrink tooltip active area on FQDN ([7c33d5a](https://github.com/ydb-platform/ydb-embedded-ui/commit/7c33d5afb561efa64f90ce5b93edd30f7d27c247)) +* **Tenant:** prevent selected tab reset on tree navigation ([a4e633a](https://github.com/ydb-platform/ydb-embedded-ui/commit/a4e633aa45c803503fe69e52f0f2cfac4c6aae0d)) +* **Tenant:** show loader when fetching overview data ([ae77495](https://github.com/ydb-platform/ydb-embedded-ui/commit/ae77495faa687652040a1f2965700184220778b4)) +* use correct prop for textinputs value ([de97ba1](https://github.com/ydb-platform/ydb-embedded-ui/commit/de97ba17ba8da54a626509cf08f147f9fcc67004)) +* **useAutofetcher:** pass argument to indicate background fetch ([4063cb1](https://github.com/ydb-platform/ydb-embedded-ui/commit/4063cb1411338d351b612fc46c06bcc708fe32f1)) + +## [2.2.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.2.0...v2.2.1) (2022-10-19) + + +### Bug Fixes + +* revert prettier config, fix build ([c47dddf](https://github.com/ydb-platform/ydb-embedded-ui/commit/c47dddf834eadfd5642af62e0cc94f7567ec68fd)) + +## [2.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.1.0...v2.2.0) (2022-10-14) + + +### Features + +* **Healthcheck:** rework issues list in modal ([e7cb0df](https://github.com/ydb-platform/ydb-embedded-ui/commit/e7cb0df58e22c8c9cd25aae83b78be4808e9ba81)) + + +### Bug Fixes + +* **EntityStatus:** enable component to left trim links ([fbc6c51](https://github.com/ydb-platform/ydb-embedded-ui/commit/fbc6c51f9fbea3c1a7f5f70cb542971a41f4d8b3)) +* fix pre-commit prettier linting and add json linting ([#189](https://github.com/ydb-platform/ydb-embedded-ui/issues/189)) ([047415d](https://github.com/ydb-platform/ydb-embedded-ui/commit/047415d2d69ecf4a2d99f0092b9e6735bd8efbc0)) +* **Healthcheck:** delete unneeded i18n translations ([0c6de90](https://github.com/ydb-platform/ydb-embedded-ui/commit/0c6de9031607e4cde1387387393a9cfc9e1e2b8f)) +* **Healthcheck:** enable update button in modal to fetch data ([de0b06e](https://github.com/ydb-platform/ydb-embedded-ui/commit/de0b06e7f2d3536df1b3896cbf86a947b2e7a291)) +* **Healthcheck:** fix layout shift on scrollbar appearance ([ccdde6e](https://github.com/ydb-platform/ydb-embedded-ui/commit/ccdde6e065abbdb1c22a2c3bdd17e63f706d0f77)) +* **Healthcheck:** fix styles for long issues trees ([32f1a8d](https://github.com/ydb-platform/ydb-embedded-ui/commit/32f1a8db58d9f84073327b92dcd80a5b4626a526)) +* **Healthcheck:** fix variable typo ([0f0e056](https://github.com/ydb-platform/ydb-embedded-ui/commit/0f0e056576b9ec18fc3ce574d3742d55e5da6e35)) +* **Healthcheck:** full check status in a preview ([bc0b51e](https://github.com/ydb-platform/ydb-embedded-ui/commit/bc0b51eedd4ff3b4ae1650946832f463a6703c12)) +* **Healthcheck:** make modal show only one first level issue ([cdc95a7](https://github.com/ydb-platform/ydb-embedded-ui/commit/cdc95a7412c1266d990df7e2807630a8f4c88780)) +* **Healthcheck:** redesign healthcheck header ([867f57a](https://github.com/ydb-platform/ydb-embedded-ui/commit/867f57aed84b7b72c22a816c6ac02387490ff495)) +* **Healthcheck:** replace update button with icon ([709a994](https://github.com/ydb-platform/ydb-embedded-ui/commit/709a994544f068db1b0fe09009ecb4d8db46fc38)) +* **Healthcheck:** update styles to be closer to the design ([aa1083d](https://github.com/ydb-platform/ydb-embedded-ui/commit/aa1083d299e24590336eeb3d913a9c53fd77bad6)) +* **Nodes:** case insensitive search ([11d2c98](https://github.com/ydb-platform/ydb-embedded-ui/commit/11d2c985e0c30bb74ed07e22273d8b3459b54c89)) +* **QueryEditor:** smarter error message trim ([8632948](https://github.com/ydb-platform/ydb-embedded-ui/commit/863294828090dc8eb2595884283d0996156c3785)) +* **Tenants:** case insensitive search ([0ad93f5](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ad93f57dcbba7d9746be54a4ba7b76ab4d45108)) +* **Tenants:** fix filtering by ControlPlane name ([4941c82](https://github.com/ydb-platform/ydb-embedded-ui/commit/4941c821cdbb7c5d0da26a3b0d5c00d8979401c0)) +* **Tenants:** left trim db names in db list ([81bf0fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/81bf0fafe901d3601dc04fdf71939e914493ff1c)) + +## [2.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.0.0...v2.1.0) (2022-10-04) + + +### Features + +* autofocus all text search fields ([a38ee84](https://github.com/ydb-platform/ydb-embedded-ui/commit/a38ee84abad4202f5e9b8af897eb68d2c006233a)) +* **Healthcheck:** display first level issues in overview ([10b4bf5](https://github.com/ydb-platform/ydb-embedded-ui/commit/10b4bf5d15d32f028702ff8cfecca0e06bc5616f)) + + +### Bug Fixes + +* fix production assets paths ([8eaad0f](https://github.com/ydb-platform/ydb-embedded-ui/commit/8eaad0f1db109c4cf3cbf7d11ad32ea335a6b0c1)) +* **Healthcheck:** add translations ([75f9851](https://github.com/ydb-platform/ydb-embedded-ui/commit/75f9851a35766ef692805a6f154d40340b003487)) +* move eslint hooks rule extension to src config ([179b81d](https://github.com/ydb-platform/ydb-embedded-ui/commit/179b81d60adf422addc8d72f947800c72bd3e4c5)) +* **QueryEditor:** disable fullscreen button for empty result ([4825b5b](https://github.com/ydb-platform/ydb-embedded-ui/commit/4825b5b8dcb89fcafd828dabbace521ddc429922)) +* **QueryEditor:** fix query stats spacings ([b836d72](https://github.com/ydb-platform/ydb-embedded-ui/commit/b836d72824a791b3fde2b9e4585c6c9b42385265)) +* **useAutofetcher:** private autofetcher instance for each usage ([3f34b7a](https://github.com/ydb-platform/ydb-embedded-ui/commit/3f34b7aee2042562a42e6d1a7daf03ffddd888c0)) + +## [2.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.14.2...v2.0.0) (2022-09-26) + + +### ⚠ BREAKING CHANGES + +* peer deps update: migrated from `@yandex-cloud/uikit` to `@gravity-ui/uikit` + + +### Bug Fixes + +* **QueryEditor:** adjust execute issues scrollbar position ([8b03400](https://github.com/ydb-platform/ydb-embedded-ui/commit/8b03400aa084a660f44dced437a97e4b956704d6)) +* **QueryEditor:** adjust explain components position ([193d326](https://github.com/ydb-platform/ydb-embedded-ui/commit/193d3263c2c9b57381f8d5ba160b95e76b5d32af)) +* **QueryEditor:** properly handle empty query explanations ([5943d1b](https://github.com/ydb-platform/ydb-embedded-ui/commit/5943d1b38534e26729310e34aa24dc30a658a0fa)) +* **QueryEditor:** render v2 explain with default topology ([44947e1](https://github.com/ydb-platform/ydb-embedded-ui/commit/44947e10248f5d14d0d685a030e2dbca0c87399d)) +* **QueryEditor:** use modern explain query schema ([78acc45](https://github.com/ydb-platform/ydb-embedded-ui/commit/78acc45765d9f9ff45a37934be61559373b5c07c)) +* **Storage:** encouraging message for empty filtered lists ([028aa8d](https://github.com/ydb-platform/ydb-embedded-ui/commit/028aa8db2ddff9f64d1b6ac6543d7d640a3187a9)) +* **Tenant:** adjust info tab spacings ([89e5809](https://github.com/ydb-platform/ydb-embedded-ui/commit/89e580939766c2ed4018b4e46c3b34d8744a9957)) +* **Tenant:** display 0 values in columns tables info ([ba2cbde](https://github.com/ydb-platform/ydb-embedded-ui/commit/ba2cbde662471dfbe34892154aa2211088100f31)) +* **Tenant:** modern query response for column tables ([ab2e45f](https://github.com/ydb-platform/ydb-embedded-ui/commit/ab2e45f4df33a2366f3a673b1beab97f3d76a3a4)) +* **Tenant:** properly fetch column tables data for info tab ([8762746](https://github.com/ydb-platform/ydb-embedded-ui/commit/8762746d9c89faeea25f9f47107b6d93fffee918)) +* **TopQueries:** modern query response ([fe2b45a](https://github.com/ydb-platform/ydb-embedded-ui/commit/fe2b45a15b25c4d1ca8324e9727bee9194bdb9bc)) +* **TopShards:** modern query response ([3f847eb](https://github.com/ydb-platform/ydb-embedded-ui/commit/3f847eb23fe1fca216e2026764a897cbafd56a38)) +* **UserSettings:** save invertedDisks as string ([d41dcc6](https://github.com/ydb-platform/ydb-embedded-ui/commit/d41dcc68d4eff47ddb54781e1bbd8192ba669500)) + +## [1.14.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.14.1...v1.14.2) (2022-09-19) + + +### Bug Fixes + +* process new explain format ([2ede9ab](https://github.com/ydb-platform/ydb-embedded-ui/commit/2ede9ab11a29667204cca110858b0cca74588255)) +* process new query format ([eb880be](https://github.com/ydb-platform/ydb-embedded-ui/commit/eb880be36b99efe7f0c0ff96b58401293ff080e1)) + +## [1.14.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.14.0...v1.14.1) (2022-09-16) + + +### Bug Fixes + +* **Tenants:** display nodes count 0 for undefined NodeIds ([4be42ec](https://github.com/ydb-platform/ydb-embedded-ui/commit/4be42eca84557929837e799d7d8dcebd858470d4)) + +## [1.14.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.13.2...v1.14.0) (2022-09-16) + + +### Features + +* **Preview:** use modern query schema ([60bed3f](https://github.com/ydb-platform/ydb-embedded-ui/commit/60bed3fcb0fd76b869883742a2f2911201c0c226)) +* **QueryEditor:** use modern query schema ([ecf38aa](https://github.com/ydb-platform/ydb-embedded-ui/commit/ecf38aa6b164ef7705e004aa77c8dab0e3164b51)) +* **QueryResultTable:** component for displaying query result ([1b8be10](https://github.com/ydb-platform/ydb-embedded-ui/commit/1b8be10546ad9ae13b1043b2871b2aa110a5b6d4)) +* **Storage:** experimental settings for disk colors ([b4291f4](https://github.com/ydb-platform/ydb-embedded-ui/commit/b4291f4ca19c588bc17eca50da51e898e6ccf581)) +* **Tenant:** cdc streams info ([4cc773f](https://github.com/ydb-platform/ydb-embedded-ui/commit/4cc773f0351e3f1f6e279d1bebbb78329695e9ae)) +* **Tenant:** cdc streams overview ([d1aed44](https://github.com/ydb-platform/ydb-embedded-ui/commit/d1aed4467135adaf01a06f8c4c4a4b3eb0b53106)) +* **Tenant:** pq groups info & overview ([e1878a6](https://github.com/ydb-platform/ydb-embedded-ui/commit/e1878a6353933f74e62b204bf210f56a18a16c49)) +* **Tenants:** display tenant nodes count ([72aef25](https://github.com/ydb-platform/ydb-embedded-ui/commit/72aef250006aae53d7704ff539b9eb537e6bfbd4)) +* use schema param in sendQuery api ([01f9c71](https://github.com/ydb-platform/ydb-embedded-ui/commit/01f9c71190622279f03cd1c01d6b6e8e6739362a)) + + +### UI Updates + +* **Storage:** new disks design ([26033d2](https://github.com/ydb-platform/ydb-embedded-ui/commit/26033d21e994c6ece7b3b8999d0fabbf82b43021)) +* **Tenant:** consistent paddings for query results ([7f0a7c2](https://github.com/ydb-platform/ydb-embedded-ui/commit/7f0a7c28d18e48013223239b5780dbaca18f68a8)) + + +### Bug Fixes + +* always parse query error to string ([0fcabf7](https://github.com/ydb-platform/ydb-embedded-ui/commit/0fcabf7042adfc728f1ec651ebae50e8c40e9199)) +* correct types & parsing for query api response ([d6a177c](https://github.com/ydb-platform/ydb-embedded-ui/commit/d6a177cd0e726f1d19e27c642e0a9c1d2832bbe0)) +* **Preview:** display "table is empty" only for tables ([21a93c1](https://github.com/ydb-platform/ydb-embedded-ui/commit/21a93c1a070dbd04f7338537200cd2cb9849ff88)) +* **Preview:** fix action type id ([7793fad](https://github.com/ydb-platform/ydb-embedded-ui/commit/7793fad6b618bfc4c35b85481b2a0b794698eaa1)) +* **QueryResultTable:** don't display absent result as empty ([e2e5bfa](https://github.com/ydb-platform/ydb-embedded-ui/commit/e2e5bfaf0dbb89ec64766bf4ed5a4fab10ae8844)) +* **QueryResultTable:** don't require theme prop ([c9686d4](https://github.com/ydb-platform/ydb-embedded-ui/commit/c9686d46eb2efdeb4bc093ecd44619e6c1a9c2fd)) +* **Tenant:** input working query for 'select query' action in schema ([de152bd](https://github.com/ydb-platform/ydb-embedded-ui/commit/de152bdcc38fd6f4b1e5a5e6102c621f0155be36)) +* **Tenant:** rename tab overview -> info ([2d13ffe](https://github.com/ydb-platform/ydb-embedded-ui/commit/2d13ffeb149765680c2887ea7ffb86d68ac92d5c)) + +## [1.13.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.13.1...v1.13.2) (2022-09-05) + + +### Bug Fixes + +* **Tenant:** fix acl scroll ([161bc8d](https://github.com/ydb-platform/ydb-embedded-ui/commit/161bc8d507de126c1383a10713e2ffaaaf13301d)) +* **Tenant:** fix layout after moving tabs ([6abfded](https://github.com/ydb-platform/ydb-embedded-ui/commit/6abfdedb97345b555be306d49ea2454f35de9bb4)) +* **Tenant:** load root if cahced path is not in tree ([2d86044](https://github.com/ydb-platform/ydb-embedded-ui/commit/2d8604464711a638dbd20cf8a14142b0de3e3a95)) + +## [1.13.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.13.0...v1.13.1) (2022-09-02) + + +### Bug Fixes + +* **Storage:** fix groups/nodes counter ([9b59ae0](https://github.com/ydb-platform/ydb-embedded-ui/commit/9b59ae0d045beff7aa45560e028618a88bd8483f)) + +## [1.13.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.12.2...v1.13.0) (2022-09-01) + + +### Features + +* **Storage:** add usage filter component ([a35067f](https://github.com/ydb-platform/ydb-embedded-ui/commit/a35067f8c34ad5d3faf4fb9381c0d6023df9afbd)) +* **Storage:** usage filter ([276f027](https://github.com/ydb-platform/ydb-embedded-ui/commit/276f0270a458601929624a4872ec81e001931853)) + + +### Bug Fixes + +* **Storage:** properly debounce text input filter ([bc5e8fd](https://github.com/ydb-platform/ydb-embedded-ui/commit/bc5e8fd7b067b850f0376b55d995213292b8a31e)) +* **Storage:** use current list size for counter ([e6fea58](https://github.com/ydb-platform/ydb-embedded-ui/commit/e6fea58b075de4c35ad8a60d339417c1e7204d83)) +* **Tenant:** move general tabs outside navigation ([5bf21ea](https://github.com/ydb-platform/ydb-embedded-ui/commit/5bf21eac6f38c0392c8dc6e04be1b6fd0e147064)) + +## [1.12.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.12.1...v1.12.2) (2022-08-29) + + +### Bug Fixes + +* **Storage:** bright red usage starting from 90% ([69b7ed2](https://github.com/ydb-platform/ydb-embedded-ui/commit/69b7ed248151f518ffc5fabbdccf5ea9bbcd9405)) +* **Storage:** display usage without gte sign ([39630a2](https://github.com/ydb-platform/ydb-embedded-ui/commit/39630a2a06b574d53d0ef74c1b3e0dc96b9666a8)) + +## [1.12.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.12.0...v1.12.1) (2022-08-26) + + +### Bug Fixes + +* **Storage:** properly display usage for 0 storage ([aee67f9](https://github.com/ydb-platform/ydb-embedded-ui/commit/aee67f9314341c995e2c9468f5eedc48fa0a3d35)) + +## [1.12.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.11.1...v1.12.0) (2022-08-26) + + +### Features + +* **Storage:** show usage column ([73aed5f](https://github.com/ydb-platform/ydb-embedded-ui/commit/73aed5f9ed60b6d2bd77fd315ae514ee7443c489)) +* **Storage:** vividly show degraded disks count ([7315a9c](https://github.com/ydb-platform/ydb-embedded-ui/commit/7315a9cfd98002a7fab85d721712aa82c6dbb552)) + +## [1.11.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.11.0...v1.11.1) (2022-08-26) + + +### Bug Fixes + +* number type instead of string for uint32 ([e60799e](https://github.com/ydb-platform/ydb-embedded-ui/commit/e60799edec4ef831e8c0d51f4384cde83520541d)) +* **Storage:** expect arbitrary donors data ([09f8e08](https://github.com/ydb-platform/ydb-embedded-ui/commit/09f8e085c94faacd9da502643355e932346502ac)) +* vdisk data contains pdisk data, not id ([bd1ea7f](https://github.com/ydb-platform/ydb-embedded-ui/commit/bd1ea7f59e0461256bb12f146b50470d21ac1ace)) + +## [1.11.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.10.3...v1.11.0) (2022-08-23) + + +### Features + +* **Stack:** new component for stacked elements ([c42ba37](https://github.com/ydb-platform/ydb-embedded-ui/commit/c42ba37fafdd9dedc4be9d625d7e756a83c01fe3)) +* **Storage:** display donor disks ([b808fe9](https://github.com/ydb-platform/ydb-embedded-ui/commit/b808fe951987c615f797af56017f8045a1ed852f)) +* **VDisk:** display label for donors ([bba5ae8](https://github.com/ydb-platform/ydb-embedded-ui/commit/bba5ae8e44347a5b1d9cb72424f5a963a6848e59)) + + +### Bug Fixes + +* **InfoViewer:** add size_s ([fc06451](https://github.com/ydb-platform/ydb-embedded-ui/commit/fc0645118f64a79f660d734c2ff43c42c738fd40)) +* **PDisk:** new popup design ([9c0355d](https://github.com/ydb-platform/ydb-embedded-ui/commit/9c0355d4d9ccf69d43a5287b0e78d7c7993c4a18)) +* **PDisk:** restrict component interface ([328efa9](https://github.com/ydb-platform/ydb-embedded-ui/commit/328efa90d214eca1bceeeb5bd9099aab36a3ddb0)) +* **Storage:** shrink tooltip active area on Pool Name ([30a2b92](https://github.com/ydb-platform/ydb-embedded-ui/commit/30a2b92ff598d9caeabe17a4b8de214943945a91)) +* **VDisk:** add a missing prop type ([39b6cf3](https://github.com/ydb-platform/ydb-embedded-ui/commit/39b6cf38811cab6c4374c77d3eb63c11fa7b83d5)) +* **VDisk:** don't paint donors blue ([6b148b9](https://github.com/ydb-platform/ydb-embedded-ui/commit/6b148b914663a74e528a01a35f575f87ed6e9f09)) +* **VDisk:** new popup design ([107b139](https://github.com/ydb-platform/ydb-embedded-ui/commit/107b13900b08631ea42034a6a2f7961c49c86556)) + +## [1.10.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.10.2...v1.10.3) (2022-08-23) + + +### Bug Fixes + +* **Overview:** format undefined values to empty string, not 0 ([1a37c27](https://github.com/ydb-platform/ydb-embedded-ui/commit/1a37c278328ad8eb4397d9507566829f01a9c872)) + +## [1.10.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.10.1...v1.10.2) (2022-08-17) + + +### Bug Fixes + +* convert bytes on decimal scale ([db9b0a7](https://github.com/ydb-platform/ydb-embedded-ui/commit/db9b0a71fc5334f5a40992cc6abc0688782ad5d2)) +* display HDD instead of ROT as pdisk type ([bd9e5ba](https://github.com/ydb-platform/ydb-embedded-ui/commit/bd9e5ba4e594cb3a1f6a964f619f9824e083ae7c)) +* **InfoViewer:** accept default value formatter ([e03d8cc](https://github.com/ydb-platform/ydb-embedded-ui/commit/e03d8cc5de76e4ac00b05586ae6f6522a9708fb0)) +* **InfoViewer:** allow longer labels ([89060a3](https://github.com/ydb-platform/ydb-embedded-ui/commit/89060a381858b5beaa3c3cf3402c13c917705676)) +* **Overview:** display table r/o replicas ([6dbe0b4](https://github.com/ydb-platform/ydb-embedded-ui/commit/6dbe0b45fc5e3867f9d6141d270c15508a693e35)) +* **Overview:** format & group table info in overview ([1a35cfc](https://github.com/ydb-platform/ydb-embedded-ui/commit/1a35cfcd2075454c4a1f1fc4961a4b3106b6d225)) +* **QueryEditor:** save chosen run action ([b0fb436](https://github.com/ydb-platform/ydb-embedded-ui/commit/b0fb43651e0c6d1dc5d6a25f92716703402b556d)) +* use current i18n lang for numeral formatting ([5d58fcf](https://github.com/ydb-platform/ydb-embedded-ui/commit/5d58fcffde21924f3cbe6c28946c7a9f755a8490)) + +## [1.10.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.10.0...v1.10.1) (2022-08-10) + + +### Bug Fixes + +* **Tenant:** fix actions set for topics ([0c75bf4](https://github.com/ydb-platform/ydb-embedded-ui/commit/0c75bf4561966dd663ab1cd7c7b81ef6b4632e50)) + +## [1.10.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.9.0...v1.10.0) (2022-08-10) + + +### Features + +* **TopShards:** add DataSize column ([cbcd047](https://github.com/ydb-platform/ydb-embedded-ui/commit/cbcd047d277f699a67bc002a5542f3b9f6a0c942)) +* **TopShards:** sort table data on backend ([dc28c5c](https://github.com/ydb-platform/ydb-embedded-ui/commit/dc28c5c75b0036480bf804d49f82fc54eac98c8e)) + + +### Bug Fixes + +* add concurrentId for sendQuery request ([dc6b32a](https://github.com/ydb-platform/ydb-embedded-ui/commit/dc6b32a8fd51064ddeca2fc60a0f08a725216334)) +* **Storage:** display pdisk type in tooltip ([2b03a35](https://github.com/ydb-platform/ydb-embedded-ui/commit/2b03a35fc11ddeae3bdd30a0690b324ae917f5c3)) +* **Tablet:** change Kill to Restart ([dd585b1](https://github.com/ydb-platform/ydb-embedded-ui/commit/dd585b1d1a6a5ddb484a702523773b169900f582)) +* **Tenant:** add missing schema node types ([62a0ecb](https://github.com/ydb-platform/ydb-embedded-ui/commit/62a0ecb848dbcee53e18535cbf7c03a731d0cfeb)) +* **Tenant:** ensure correct behavior for new schema node types ([f80c381](https://github.com/ydb-platform/ydb-embedded-ui/commit/f80c38152656e8bbbe51ec38b29fc0d954c361cc)) +* **Tenant:** use new schema icons ([389a921](https://github.com/ydb-platform/ydb-embedded-ui/commit/389a9214c64b1adb183fa0c6caa6f2ec536dbef3)) +* **TopShards:** disable virtualization for table ([006d3d9](https://github.com/ydb-platform/ydb-embedded-ui/commit/006d3d9fb9a4744b8bb4ad03e53693199213f80e)) +* **TopShards:** format DataSize value ([c51ce66](https://github.com/ydb-platform/ydb-embedded-ui/commit/c51ce66286f6454f7252d1194628ee5a50aafba2)) +* **TopShards:** only allow DESC sort ([6aa326f](https://github.com/ydb-platform/ydb-embedded-ui/commit/6aa326fc4b8165f00f8b3ecf5becdb0943ed57af)) +* **TopShards:** substring tenant name out of shards path ([9e57672](https://github.com/ydb-platform/ydb-embedded-ui/commit/9e5767222c7dac7734c68abd08067cea507b1e15)) + +## [1.9.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.8...v1.9.0) (2022-07-29) + + +### Features + +* **Node:** display endpoints in overview ([89e9e47](https://github.com/ydb-platform/ydb-embedded-ui/commit/89e9e470499b6f458e8949211d97293c0b7d9b97)) +* **Node:** display node basic info above tabs ([aafb15b](https://github.com/ydb-platform/ydb-embedded-ui/commit/aafb15b399bf116026eff36f3c4ac817e2c40e18)) +* **Node:** more informative pdisks panels ([342712b](https://github.com/ydb-platform/ydb-embedded-ui/commit/342712bcaa793971e1ca354da57fb962639ef90c)) +* **Nodes:** show node endpoints in tooltip ([34be559](https://github.com/ydb-platform/ydb-embedded-ui/commit/34be55957e02f947ede30b43f22fde82d21df308)) +* **Tenant:** table index overview ([2aed714](https://github.com/ydb-platform/ydb-embedded-ui/commit/2aed71488cde1175e6569c236ab609bb126f9cf3)) +* **Tenant:** virtualized tree in schema ([815f558](https://github.com/ydb-platform/ydb-embedded-ui/commit/815f5588e5fed6fb86f69653c4937e975465372f)) +* utils for parsing bitfields in pdisk data ([da22b4a](https://github.com/ydb-platform/ydb-embedded-ui/commit/da22b4afde9efe4d9605cefb69ddd51aed989722)) + + +### Bug Fixes + +* **Node:** fix pdisk title items width ([ca5fec6](https://github.com/ydb-platform/ydb-embedded-ui/commit/ca5fec6388364b7d1d6362f1bda36431d9c29749)) +* **Nodes:** hide tooltip on unmount ([54e4fdc](https://github.com/ydb-platform/ydb-embedded-ui/commit/54e4fdc8045c555338e79d89a93faf58e888fa0e)) +* **ProgressViewer:** apply provided custom class name ([aa60e9d](https://github.com/ydb-platform/ydb-embedded-ui/commit/aa60e9d1b9c0752853f4323d3bcfd220bedd272d)) +* **Tenant:** display all table props in overview ([d70e311](https://github.com/ydb-platform/ydb-embedded-ui/commit/d70e311296f6a4d1781f6e72929c70e0db7c3226)) +* **Tenant:** display PartCount first in table overview ([8c09746](https://github.com/ydb-platform/ydb-embedded-ui/commit/8c09746b026a23a36fe31be94057cc92535aceaa)) + +## [1.8.8](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.7...v1.8.8) (2022-07-21) + + +### Bug Fixes + +* **TabletsFilters:** display tablets grid full-height ([0dde809](https://github.com/ydb-platform/ydb-embedded-ui/commit/0dde8097fe026248aade97f034fa35c56b28e903)) +* **TabletsOverall:** properly hide tooltip on mouseleave ([df36eba](https://github.com/ydb-platform/ydb-embedded-ui/commit/df36ebaf44d8966bc419f3720d51390dfd767a87)) +* **Tablets:** properly display tablets in grid ([f3b64fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/f3b64fae3a1e1a46ababd2d2f04ddff488698676)) +* **Tenant:** align info in overview ([acb39fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/acb39fab70b7b4e0e78124fd887b2f1b76815221)) +* **Tenant:** display tenant name in single line ([301e391](https://github.com/ydb-platform/ydb-embedded-ui/commit/301e3911330024f80ebfda6d1a16823b64d94b36)) +* **Tenant:** move tablets under tenant name ([b7e4b8f](https://github.com/ydb-platform/ydb-embedded-ui/commit/b7e4b8f7027f1481a7c1baff77bf8ad5e2ed467c)) + +## [1.8.7](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.6...v1.8.7) (2022-07-18) + + +### Bug Fixes + +* **Preview:** sort numbers as numbers, not string ([6c42a62](https://github.com/ydb-platform/ydb-embedded-ui/commit/6c42a62d077fcb9419ceb680906d4cef78a0134f)) + +## [1.8.6](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.5...v1.8.6) (2022-07-14) + + +### Bug Fixes + +* **Tenant:** fix switching between groups and nodes on storage tab ([6923885](https://github.com/ydb-platform/ydb-embedded-ui/commit/6923885336fa21ac985879e41685137adbf8159a)) + +## [1.8.5](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.4...v1.8.5) (2022-07-11) + + +### Bug Fixes + +* **AsideNavigation:** aside header is compact by default ([aa3ad03](https://github.com/ydb-platform/ydb-embedded-ui/commit/aa3ad033fc6b62e6f2ee595e266343e67e764ec6)) + +## [1.8.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.3...v1.8.4) (2022-07-11) + + +### Bug Fixes + +* **Nodes:** add /internal for nodes external link ([a649dd2](https://github.com/ydb-platform/ydb-embedded-ui/commit/a649dd209bae4abd6916f23d0894df893602aaf7)) + +## [1.8.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.2...v1.8.3) (2022-07-08) + + +### Bug Fixes + +* timeout 600 sec for requests /viewer/json/query ([cf65122](https://github.com/ydb-platform/ydb-embedded-ui/commit/cf651221f866e5f56ecf6c900b3778dedc31eb95)) + +## [1.8.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.1...v1.8.2) (2022-07-07) + + +### Bug Fixes + +* **Tenant:** 3 tabs for indexes ([9280384](https://github.com/ydb-platform/ydb-embedded-ui/commit/9280384733938c4bd269bf6f9adf23efb552c6e8)) +* **Tenant:** hide preview button for index tables ([a25e0ea](https://github.com/ydb-platform/ydb-embedded-ui/commit/a25e0ea0413277e27c54d123e2be7a15b8a2aaa4)) + +## [1.8.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.0...v1.8.1) (2022-07-06) + + +### Bug Fixes + +* **Tenant:** diagnostics view for table indexes ([63d3133](https://github.com/ydb-platform/ydb-embedded-ui/commit/63d3133c0d61f6d39186f0c5df2eb6983a9c8bf7)) +* **Tenant:** own context actions for table indexes ([3cd946a](https://github.com/ydb-platform/ydb-embedded-ui/commit/3cd946a333be402cec70569affef5865b0dd8934)) + +## [1.8.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.7.1...v1.8.0) (2022-07-05) + + +### Features + +* add Illustration component ([7d10880](https://github.com/ydb-platform/ydb-embedded-ui/commit/7d10880cd4d9f945e7c8a7232327d8db68f0865c)) +* **Tenant:** proper 403 error page ([d822a2b](https://github.com/ydb-platform/ydb-embedded-ui/commit/d822a2b6e3e18c24882ecf30db399087053b83b3)) + + +### Bug Fixes + +* fix empty state illustration layout ([7cfd97e](https://github.com/ydb-platform/ydb-embedded-ui/commit/7cfd97e13ebcaa703478bd7b4e29774150bd569e)) + +## [1.7.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.7.0...v1.7.1) (2022-07-05) + + +### Performance Improvements + +* **Tenant:** use api call viewer/json/acl instead of metainfo ([c3603c4](https://github.com/ydb-platform/ydb-embedded-ui/commit/c3603c4b364cef79cb4790c7e9e4378d5b66e0ed)) + +## [1.7.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.6.4...v1.7.0) (2022-06-29) + + +### Features + +* **Storage:** show total groups count ([5e31cfe](https://github.com/ydb-platform/ydb-embedded-ui/commit/5e31cfee9edc50fa4bc0770c443b136291a3536e)) +* **Storage:** show total nodes count ([b438f70](https://github.com/ydb-platform/ydb-embedded-ui/commit/b438f7075961e878a1412ca185743c4374dd9178)) +* **Tenant:** display tables indexes ([693a100](https://github.com/ydb-platform/ydb-embedded-ui/commit/693a1001db6487b2d43aeca7d8168afcd06f5cbd)) + +## [1.6.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.6.3...v1.6.4) (2022-06-24) + + +### Bug Fixes + +* **Tenant:** properly display ColumnTables ([14d1e07](https://github.com/ydb-platform/ydb-embedded-ui/commit/14d1e074bf615be50f4f466d25e605b418f22b47)) + +## [1.6.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.6.2...v1.6.3) (2022-06-22) + + +### Bug Fixes + +* **ClipboardButton:** clickable area now matches visual area ([8c0b5ef](https://github.com/ydb-platform/ydb-embedded-ui/commit/8c0b5ef27d5d31b28a29455b3019de23bdbf8f68)) + +## [1.6.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.6.1...v1.6.2) (2022-06-07) + + +### Bug Fixes + +* shouls always select result tab ([98d4bcb](https://github.com/ydb-platform/ydb-embedded-ui/commit/98d4bcbc94bc2b9db9fb9b9cd5aced9f079ecdae)) + +## [1.6.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.6.0...v1.6.1) (2022-06-07) + + +### Bug Fixes + +* should show Pending instead of Pendin ([0b93f80](https://github.com/ydb-platform/ydb-embedded-ui/commit/0b93f8000dffca27cd26321eb86f41e4f458faa6)) +* should show query error even if no issues ([708bac5](https://github.com/ydb-platform/ydb-embedded-ui/commit/708bac56c2e671ec23e23c5055d0c0a9d419cd86)) + +## [1.6.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.5.3...v1.6.0) (2022-06-06) + + +### Features + +* query issues displaying ([3ba4c25](https://github.com/ydb-platform/ydb-embedded-ui/commit/3ba4c2591542ef902eba4f7c44550f3c59618575)) + + +### Bug Fixes + +* code-review ([742c58a](https://github.com/ydb-platform/ydb-embedded-ui/commit/742c58a9bc4fa0dd0b24aa0119b7352e2be6fc8e)) +* **package.json:** typecheck script ([111b525](https://github.com/ydb-platform/ydb-embedded-ui/commit/111b525f51a050010bbc03a3d0990be00c18ccd8)) + +### [1.5.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.5.2...v1.5.3) (2022-05-26) + + +### Bug Fixes + +* explicitly set lang for ydb-ui-components i18n ([5684524](https://github.com/ydb-platform/ydb-embedded-ui/commit/5684524267e2cbf19a44de75b0e0b2bf98b617fd)) +* proper icon size in uikit/Select ([a665d6d](https://github.com/ydb-platform/ydb-embedded-ui/commit/a665d6d829dae61ccf25566dd7b8cd1e46a743bb)) +* update code for @yandex-cloud/uikit@^2.0.0 ([49d67a1](https://github.com/ydb-platform/ydb-embedded-ui/commit/49d67a1bddcba6fa138b5ebaeb280f16366b3329)) + + +### chore + +* update @yandex-cloud/uikit to 2.4.0 ([d2eb2e5](https://github.com/ydb-platform/ydb-embedded-ui/commit/d2eb2e5db147604ae346aea295ae22759712eaa4)) +* add @yandex-cloud/uikit to peer deps ([9c9f599](https://github.com/ydb-platform/ydb-embedded-ui/commit/9c9f5997dcca1be5868d013da311a28e495e7faa)) +* update ydb-ui-components to v2.0.1 ([3d6a8d3](https://github.com/ydb-platform/ydb-embedded-ui/commit/3d6a8d30ab2ab47203eb956904e891ae106c0bc7)) + +### [1.5.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.5.1...v1.5.2) (2022-05-26) + + +### Bug Fixes + +* **Tenant:** always update diagnostics tabs for root ([db03266](https://github.com/ydb-platform/ydb-embedded-ui/commit/db03266fd7dd6e4588c1db0d109bdfaa8f693e2d)) +* **Tenant:** don't use HistoryAPI and redux-location-state together ([c1bc562](https://github.com/ydb-platform/ydb-embedded-ui/commit/c1bc5621e3ead44b1b84e592f8d7106bbc918e37)) + +### [1.5.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.5.0...v1.5.1) (2022-05-25) + + +### Bug Fixes + +* **Authentication:** submit form with enter in the login field ([7b6132a](https://github.com/ydb-platform/ydb-embedded-ui/commit/7b6132a6b2556939648167f30b08c5688b56ab98)) + +## [1.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.4.2...v1.5.0) (2022-05-24) + + +### Features + +* **Healthcheck:** use TreeView in issues viewer ([bcd81e5](https://github.com/ydb-platform/ydb-embedded-ui/commit/bcd81e56dc613cf3e9f31d77d930b79e070372e4)) +* **Tenant:** use NavigationTree for schemas ([f2867e1](https://github.com/ydb-platform/ydb-embedded-ui/commit/f2867e18898028ca265df46fcc8bfa4f929173f0)) + + +### Bug Fixes + +* **Healthcheck:** don't display reasonsItems in issues viewer ([f0a545f](https://github.com/ydb-platform/ydb-embedded-ui/commit/f0a545f7c70d449c121d64f8d1820e53b880a0fc)) +* **Tenant:** add ellipsis to menu items inserting queries ([09135a2](https://github.com/ydb-platform/ydb-embedded-ui/commit/09135a2777ec9183ddf71bd2a4de66c5ef422ac8)) +* **Tenant:** change messages for path copy toasts ([09adfa5](https://github.com/ydb-platform/ydb-embedded-ui/commit/09adfa52735bf706deb1ee9bf37f4bfa459b3758)) +* **Tenant:** switch to query tab for inserted query ([991f156](https://github.com/ydb-platform/ydb-embedded-ui/commit/991f156ff819c58ff79146a44b57fb400729f325)) + +### [1.4.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.4.1...v1.4.2) (2022-05-23) + + +### UI Updates + +* **QueryEditor:** replace warning for query losing with note about how query are saved ([89820ca](https://github.com/ydb-platform/ydb-embedded-ui/commit/89820ca7e2d02f880eb81d484b8947d599798d5f)) + + +### Bug Fixes + +* **QueryEditor:** confirm query deletion with enter ([d3dadbd](https://github.com/ydb-platform/ydb-embedded-ui/commit/d3dadbd0244fead5f41bd98445669c4f5ce23c43)) +* **QueryEditor:** field autofocus in query save dialog ([9225238](https://github.com/ydb-platform/ydb-embedded-ui/commit/92252384dc68c40191f7898fff9a2c1106b0b2f1)) +* **QueryEditor:** save query with enter ([5f9c450](https://github.com/ydb-platform/ydb-embedded-ui/commit/5f9c450aedc90f0e162515294a74000c006f9be7)) + +### [1.4.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.4.0...v1.4.1) (2022-05-17) + + +### UI Updates + +* **Tenant:** add tenant name wrapper ([8176d28](https://github.com/ydb-platform/ydb-embedded-ui/commit/8176d28a5769b2b95d667ed960ad34d7a0d9bb4c)) + + +### Bug Fixes + +* **NodesTable:** align external link icon ([a379796](https://github.com/ydb-platform/ydb-embedded-ui/commit/a379796c6b8087f25f95ce3db4be33f18da71e04)) + +## [1.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.3.0...v1.4.0) (2022-05-16) + + +### Features + +* **Tenant:** save initial tab preference ([7195d0f](https://github.com/ydb-platform/ydb-embedded-ui/commit/7195d0f7f5754c461555211515f80ea96464ca15)) + + +### UI Updtaes + +* **NodesTable:** don't reserve space for icons next to node fqdn ([8fcf1b3](https://github.com/ydb-platform/ydb-embedded-ui/commit/8fcf1b3269dee7ada83d7c5abcf44ad004191851)) + + +### Bug Fixes + +* **Tenant:** mapDispatchToProps types ([7dcaf56](https://github.com/ydb-platform/ydb-embedded-ui/commit/7dcaf561ec0c361d52d789b2ea3b1aba75339d83)) + +## [1.3.0](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.2.6...v1.3.0) (2022-05-12) + + +### Features + +* **Storage:** red progress bars for unavailable disks ([17cf94d](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/17cf94defb23681bc62c768d3282eed00c7e974d)) + +### [1.2.6](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.2.5...v1.2.6) (2022-05-05) + + +### Bug Fixes + +* code-review ([1068339](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/1068339d128fb44b661837b7d777b5e5f725a611)) +* **Diagnostics:** layout ([2b11c35](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/2b11c35c14cd1fa17d36bbeb2a371fb2fef3fb70)) + +### [1.2.5](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.2.4...v1.2.5) (2022-05-05) + + +### Bug Fixes + +* **Node:** right padding on the storage page ([3a09d80](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/3a09d8030c2b9d8f34675f3a790e19bba5b864e4)) +* **Tenant:** fix horizontal scrollbar on diagnostics storage page ([017f5f3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/017f5f3470875824b11575c506837ab461a4e840)) +* **Tenant:** keep acl heading at top ([7859fc6](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/7859fc6a2e47071daf18b48a23974f2393e31417)) +* **Storage:** move filters out of scrollable container ([66baaec](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/66baaec170449c89da2d9f8e2170875c13334e68)) +* **NodesViewer:** match default control styles ([c007674](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/c0076742e78fdb87aadae9b22e073b923e7ca57e)) + +### [1.2.4](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.2.3...v1.2.4) (2022-05-05) + + +### Bug Fixes + +* **Storage:** make 2 argument in getStorageInfo optional ([e349f8b](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/e349f8b958756258b2d3790fbc9018c63b86498e)) + +### [1.2.3](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.2.2...v1.2.3) (2022-05-05) + + +### Bug Fixes + +* **node reducer:** should specify concurrentId in getNodeStructure ([103c843](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/103c843524e21af421954444774d68bda540ceae)) + +### [1.2.2](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.2.1...v1.2.2) (2022-05-04) + + +### Bug Fixes + +* code-review ([288fda3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/288fda3cd207908e9b5c0486c4d486c6f2e17dd4)) +* reducer clusterInfo should not be used ([1cafcbf](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/1cafcbfb15f668b100cf6628b540b7cd234f6024)) + +### [1.2.1](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.2.0...v1.2.1) (2022-04-27) + + +### Bug Fixes + +* **Vdisk:** should not fail if no node id passed ([d66686d](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/d66686d0cbd9f61c4e106f6775db2fca226c922f)) + +## [1.2.0](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.1.3...v1.2.0) (2022-04-26) + + +### Features + +* **Storage:** smoother loading state for storage table ([f7f38c4](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/f7f38c455dd9abc3f898048081e90af9b460f922)) + + +### Bug Fixes + +* prevent ghost autofetch ([153d829](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/153d8291d315f1dab001a69981a12e30d3d2aea9)) + +### [1.1.3](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.1.2...v1.1.3) (2022-04-20) + + +### Bug Fixes + +* should prepare internal link correctly ([3da36e2](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/3da36e22f6adbce6a1b14ac1afb0fb4aa46bb75f)) + +### [1.1.2](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.1.1...v1.1.2) (2022-04-19) + + +### Bug Fixes + +* **ObjectSummary:** should correctly parse table creation time ([c9887dd](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/c9887dd162720667dcbe3b4834b3b0ba5a9f3f6e)) + +### [1.1.1](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.1.0...v1.1.1) (2022-04-19) + + +### Bug Fixes + +* add typecheck + fix type errors ([e6d9086](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/e6d9086c46702a611f848c992377d18826ca2e23)) +* **Node:** scroll to selected vdisk should not apply to undefined container ([7236a43](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/7236a43655b935777abb5b8df228ae011ceb6bed)) + +## [1.1.0](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.4...v1.1.0) (2022-04-15) + + +### Features + +* local precommit check ([d5da9b3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/d5da9b3fb89eeeb5461e7e14fe33964a8ed9078d)) +* new Node Structure view ([5cf5dd3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/5cf5dd39fa59625be4bb89f16796f16ecb9d9d78)) + + +### Bug Fixes + +* **Authentication:** should be able to send authentication data with empty password [YDB-1610] ([5d4d881](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/5d4d8810bb2ddabb9db1316a99194f5a1bd986b6)) +* **Cluster:** should show additional info ([cb21ce3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/cb21ce317c55d05c7a7c166bc09dc1fe14e41692)) +* code-review ([a706903](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/a706903e6a30ee62aff5829c37ba8c197335e106)) +* different interface fixes ([0bd3a32](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/0bd3a32bf1502cc6d0f7419aa9d00653afe5d7bf)) +* improve usability ([20f1acc](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/20f1acc255876968ea366a860d33a12eecc5e74f)) +* **Nodes:** default path to node should be Overview ([ac4add6](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/ac4add6c1403ac2b9614f252fabf23b9e97ef2c2)) +* query run type select should be styled as action button [YDB-1567] ([d06cd6a](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/d06cd6ac72ccb8c7eef205fddb1153e6383baeea)) +* **QueryEditor:** should resolve row key by index [YDB-1604] ([4acd2a3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/4acd2a30d03f2e45368587839549f4e5981f93dd)) +* refactoring ([0c5aca5](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/0c5aca5b96bc5d5e9c3f121aa1ffe394f3fbd28f)) +* **Storage:** wording fixed [YDB-1552] ([431f77f](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/431f77f090073037404639c686246d2f115d98f4)) +* styles ([2725055](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/2725055b0f25e711c73e2888da41cfaf2657b110)) + +### [1.0.4](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.3...v1.0.4) (2022-03-24) + + +### Bug Fixes + +* freeze deps ([349dee8](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/349dee8cbc7376e316e3cb87f5eb46142975de6c)) +* styles ([502bc0b](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/502bc0bd319a141e2d3e90787eae41abcd24e76d)) + +### [1.0.3](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.2...v1.0.3) (2022-03-21) + + +### Bug Fixes + +* query status should not be shown when query is loading ([d214eee](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/d214eee575b63341082f0be33163e3fce520df88)) +* should set correct initial current index in queries history ([c3228d7](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/c3228d7a6a0c810982db1bdbec7762889ac44ffa)) +* **Storage:** wording fixed [YDB-1552] ([3f487ff](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/3f487ff01117963760b676d14281e93e5f3002c0)) + +### [1.0.2](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.1...v1.0.2) (2022-03-11) + + +### Bug Fixes + +* **Header:** add link to internal viewer ([64af24f](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/64af24f8d78cf0d34466ac129be10c0764cce3d4)) + +### [1.0.1](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.0...v1.0.1) (2022-03-05) + + +### Bug Fixes + +* **QueriesHistory:** should save history to local storage ([#8](https://www.github.com/ydb-platform/ydb-embedded-ui/issues/8)) ([57031ab](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/57031ab16900e9d1112bbf506d5c777f94f883bb)) + +## [1.0.0](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v0.2.0...v1.0.0) (2022-03-01) + + +### Bug Fixes + +* **ObjectSummary:** start time should be taken from current schema object ([e7511be](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/e7511be61e5c8d2052ad3a2247a713f55049d3e6)) +* **QueryEditor:** key bindings should work properly ([ebe59b3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/ebe59b3c838889ee81e308232e4c8d2ba23a1a3a)) +* **QueryExplain:** should render graph in fullscreen view properly ([da511da](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/da511da2fc1a36282ad99f20d5d6fd0b5b4ea05b)) +* **README:** ui path should be correct ([e2668ef](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/e2668ef329de4cf31fd31061dfe3b4ac091e0121)) + +## [0.2.0](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v0.1.0...v0.2.0) (2022-02-24) + + +### Features + +* new design, refactoring ([#3](https://www.github.com/ydb-platform/ydb-embedded-ui/issues/3)) ([76d7cb0](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/76d7cb0ebad5658a6654254a0376b1ecf203e696)) + +## 0.1.0 (2022-02-17) + + +### Features + +* initial import ([9bf5e83](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/9bf5e833e3d2d10897215f7d439b284a4c3c10df)) diff --git a/ydb/core/viewer/monitoring/asset-manifest.json b/ydb/core/viewer/monitoring/asset-manifest.json index 770cb4080639..9fe22a2a9d95 100644 --- a/ydb/core/viewer/monitoring/asset-manifest.json +++ b/ydb/core/viewer/monitoring/asset-manifest.json @@ -1,7 +1,7 @@ { "files": { - "main.css": "./static/css/main.84f98361.css", - "main.js": "./static/js/main.56991933.js", + "main.css": "./static/css/main.9b3791f5.css", + "main.js": "./static/js/main.c85cd3ad.js", "static/js/89222.d941dfbd.chunk.js": "./static/js/89222.d941dfbd.chunk.js", "static/js/59243.5de594f4.chunk.js": "./static/js/59243.5de594f4.chunk.js", "static/js/6881.7e6434c9.chunk.js": "./static/js/6881.7e6434c9.chunk.js", @@ -146,29 +146,29 @@ "static/js/60221.8d560e16.chunk.js": "./static/js/60221.8d560e16.chunk.js", "static/js/76879.ff0dd32c.chunk.js": "./static/js/76879.ff0dd32c.chunk.js", "static/css/47512.67d2c551.chunk.css": "./static/css/47512.67d2c551.chunk.css", - "static/js/47512.39fd7220.chunk.js": "./static/js/47512.39fd7220.chunk.js", - "static/css/64464.f737743e.chunk.css": "./static/css/64464.f737743e.chunk.css", - "static/js/64464.e1dcaef9.chunk.js": "./static/js/64464.e1dcaef9.chunk.js", + "static/js/47512.78ddf2e4.chunk.js": "./static/js/47512.78ddf2e4.chunk.js", + "static/css/79004.401dcbac.chunk.css": "./static/css/79004.401dcbac.chunk.css", + "static/js/79004.3bac7414.chunk.js": "./static/js/79004.3bac7414.chunk.js", "static/css/96079.c2e5026a.chunk.css": "./static/css/96079.c2e5026a.chunk.css", "static/js/96079.c09d99cc.chunk.js": "./static/js/96079.c09d99cc.chunk.js", "static/css/38527.13440c26.chunk.css": "./static/css/38527.13440c26.chunk.css", "static/js/38527.b39cc908.chunk.js": "./static/js/38527.b39cc908.chunk.js", "static/css/85917.9f2a4a06.chunk.css": "./static/css/85917.9f2a4a06.chunk.css", "static/js/85917.743a4384.chunk.js": "./static/js/85917.743a4384.chunk.js", - "static/css/75510.b1faff6b.chunk.css": "./static/css/75510.b1faff6b.chunk.css", - "static/js/75510.026d82a2.chunk.js": "./static/js/75510.026d82a2.chunk.js", - "static/css/49393.82d9be05.chunk.css": "./static/css/49393.82d9be05.chunk.css", - "static/js/49393.48f114fd.chunk.js": "./static/js/49393.48f114fd.chunk.js", + "static/css/35614.b1faff6b.chunk.css": "./static/css/35614.b1faff6b.chunk.css", + "static/js/35614.8c037c0d.chunk.js": "./static/js/35614.8c037c0d.chunk.js", + "static/css/49393.519eef72.chunk.css": "./static/css/49393.519eef72.chunk.css", + "static/js/49393.b6b17049.chunk.js": "./static/js/49393.b6b17049.chunk.js", "static/css/23779.b38c45c0.chunk.css": "./static/css/23779.b38c45c0.chunk.css", - "static/js/23779.2a240d6f.chunk.js": "./static/js/23779.2a240d6f.chunk.js", + "static/js/23779.5bbf5687.chunk.js": "./static/js/23779.5bbf5687.chunk.js", "static/js/67329.08db90c1.chunk.js": "./static/js/67329.08db90c1.chunk.js", "static/js/73238.abca2b52.chunk.js": "./static/js/73238.abca2b52.chunk.js", "static/js/3872.a25d87b5.chunk.js": "./static/js/3872.a25d87b5.chunk.js", "static/js/81299.b1fcb7d9.chunk.js": "./static/js/81299.b1fcb7d9.chunk.js", "static/js/98256.8a661541.chunk.js": "./static/js/98256.8a661541.chunk.js", "static/js/56990.be6d200f.chunk.js": "./static/js/56990.be6d200f.chunk.js", - "static/css/94695.6eb9306c.chunk.css": "./static/css/94695.6eb9306c.chunk.css", - "static/js/94695.41c32507.chunk.js": "./static/js/94695.41c32507.chunk.js", + "static/css/94695.b2628977.chunk.css": "./static/css/94695.b2628977.chunk.css", + "static/js/94695.6a06e965.chunk.js": "./static/js/94695.6a06e965.chunk.js", "static/css/90099.7cffb936.chunk.css": "./static/css/90099.7cffb936.chunk.css", "static/js/90099.38466d3d.chunk.js": "./static/js/90099.38466d3d.chunk.js", "static/js/62308.fe05af2f.chunk.js": "./static/js/62308.fe05af2f.chunk.js", @@ -289,12 +289,12 @@ "static/js/61387.f19330bb.chunk.js": "./static/js/61387.f19330bb.chunk.js", "static/js/28125.0776827a.chunk.js": "./static/js/28125.0776827a.chunk.js", "static/js/9511.aceb118a.chunk.js": "./static/js/9511.aceb118a.chunk.js", - "static/js/56421.a250ca1b.chunk.js": "./static/js/56421.a250ca1b.chunk.js", + "static/js/78802.412f4dbd.chunk.js": "./static/js/78802.412f4dbd.chunk.js", "static/js/85595.262d8065.chunk.js": "./static/js/85595.262d8065.chunk.js", "static/js/52036.0bcd45d5.chunk.js": "./static/js/52036.0bcd45d5.chunk.js", "static/js/29866.16645b0d.chunk.js": "./static/js/29866.16645b0d.chunk.js", "static/js/83012.103c3f36.chunk.js": "./static/js/83012.103c3f36.chunk.js", - "static/js/95264.612bf2f8.chunk.js": "./static/js/95264.612bf2f8.chunk.js", + "static/js/95264.54993ac0.chunk.js": "./static/js/95264.54993ac0.chunk.js", "static/js/56026.85d58e2b.chunk.js": "./static/js/56026.85d58e2b.chunk.js", "static/js/62888.e3af7359.chunk.js": "./static/js/62888.e3af7359.chunk.js", "static/js/84960.05121e37.chunk.js": "./static/js/84960.05121e37.chunk.js", @@ -547,16 +547,15 @@ "static/css/71867.d30d0ff3.chunk.css": "./static/css/71867.d30d0ff3.chunk.css", "static/js/71867.4808e834.chunk.js": "./static/js/71867.4808e834.chunk.js", "static/js/24130.160bfd14.chunk.js": "./static/js/24130.160bfd14.chunk.js", - "static/js/56013.d9e34466.chunk.js": "./static/js/56013.d9e34466.chunk.js", "static/js/59172.d3dd36c7.chunk.js": "./static/js/59172.d3dd36c7.chunk.js", "static/js/66820.ec86ae7a.chunk.js": "./static/js/66820.ec86ae7a.chunk.js", - "static/css/58884.1e565ac5.chunk.css": "./static/css/58884.1e565ac5.chunk.css", - "static/js/58884.1009923e.chunk.js": "./static/js/58884.1009923e.chunk.js", + "static/css/56421.545f7f9d.chunk.css": "./static/css/56421.545f7f9d.chunk.css", + "static/js/56421.5464a012.chunk.js": "./static/js/56421.5464a012.chunk.js", "static/js/81836.55b6c25b.chunk.js": "./static/js/81836.55b6c25b.chunk.js", - "static/js/88669.310e189c.chunk.js": "./static/js/88669.310e189c.chunk.js", - "static/js/99796.a8f76855.chunk.js": "./static/js/99796.a8f76855.chunk.js", - "static/css/58705.b781fc86.chunk.css": "./static/css/58705.b781fc86.chunk.css", - "static/js/65824.1f5e112a.chunk.js": "./static/js/65824.1f5e112a.chunk.js", + "static/js/17893.97279c58.chunk.js": "./static/js/17893.97279c58.chunk.js", + "static/js/99796.af99aa08.chunk.js": "./static/js/99796.af99aa08.chunk.js", + "static/css/52852.f32aa6d8.chunk.css": "./static/css/52852.f32aa6d8.chunk.css", + "static/js/92412.2aef0234.chunk.js": "./static/js/92412.2aef0234.chunk.js", "static/js/47293.68cfbf41.chunk.js": "./static/js/47293.68cfbf41.chunk.js", "ts.worker.js": "./ts.worker.js", "css.worker.js": "./css.worker.js", @@ -570,7 +569,7 @@ "index.html": "./index.html" }, "entrypoints": [ - "static/css/main.84f98361.css", - "static/js/main.56991933.js" + "static/css/main.9b3791f5.css", + "static/js/main.c85cd3ad.js" ] } \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/index.html b/ydb/core/viewer/monitoring/index.html index 648b549e15fb..4ac0cd286d44 100644 --- a/ydb/core/viewer/monitoring/index.html +++ b/ydb/core/viewer/monitoring/index.html @@ -1 +1 @@ -YDB Monitoring
\ No newline at end of file +YDB Monitoring
\ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/75510.b1faff6b.chunk.css b/ydb/core/viewer/monitoring/static/css/35614.b1faff6b.chunk.css similarity index 100% rename from ydb/core/viewer/monitoring/static/css/75510.b1faff6b.chunk.css rename to ydb/core/viewer/monitoring/static/css/35614.b1faff6b.chunk.css diff --git a/ydb/core/viewer/monitoring/static/css/49393.519eef72.chunk.css b/ydb/core/viewer/monitoring/static/css/49393.519eef72.chunk.css new file mode 100644 index 000000000000..6e9ff43883e6 --- /dev/null +++ b/ydb/core/viewer/monitoring/static/css/49393.519eef72.chunk.css @@ -0,0 +1 @@ +@charset "UTF-8";.ydb-entity-page-title{text-wrap:nowrap;align-items:baseline;display:flex;flex-flow:row nowrap;font-size:var(--g-text-header-2-font-size);line-height:var(--g-text-header-2-line-height)}.ydb-entity-page-title__prefix{color:var(--g-color-text-secondary);margin-right:6px}.ydb-entity-page-title__icon{margin-right:8px}.auto-refresh-control{align-items:center;display:flex;gap:var(--g-spacing-1)}.ydb-page-meta__info{text-wrap:nowrap;color:var(--g-color-text-primary);display:flex;flex-flow:row nowrap;flex-grow:1;font-size:var(--g-text-body-2-font-size);height:var(--g-text-body-2-line-height);line-height:var(--g-text-body-2-line-height)}.ydb-page-meta__skeleton{height:80%;width:80%}.kv-shorty-string__toggle{font-size:.85em;margin-left:2em}.kv-result-issues{padding:0 10px}.kv-result-issues__error-message{align-items:center;background-color:var(--g-color-base-background);display:flex;left:0;padding:10px 0;position:sticky;top:0;z-index:2}.kv-result-issues__error-message-text{margin:0 10px}.kv-issues{position:relative}.kv-issue_leaf{margin-left:31px}.kv-issue__issues{padding-left:24px}.kv-issue__line{align-items:flex-start;display:flex;margin:0 0 10px;padding:0 10px 0 0}.kv-issue__place-text{color:var(--g-color-text-secondary);display:inline-block;padding-right:10px;text-align:left}.kv-issue__message{display:flex;font-family:var(--g-font-family-monospace);font-size:var(--g-text-code-2-font-size);line-height:var(--g-text-header-2-line-height);margin-left:10px;margin-right:auto}.kv-issue__message-text{flex:1 1 auto;min-width:240px;white-space:pre-wrap;word-break:break-word}.kv-issue__code{color:var(--g-color-text-complementary);flex:0 0 auto;font-size:12px;margin-left:1.5em;padding:3px 0}.kv-issue__arrow-toggle{margin-right:5px}.yql-issue-severity{align-items:center;display:flex;line-height:28px;white-space:nowrap}.yql-issue-severity_severity_error .yql-issue-severity__icon,.yql-issue-severity_severity_fatal .yql-issue-severity__icon{color:var(--g-color-text-danger)}.yql-issue-severity_severity_warning .yql-issue-severity__icon{color:var(--g-color-text-warning)}.yql-issue-severity_severity_info .yql-issue-severity__icon{color:var(--g-color-text-info)}.yql-issue-severity__title{color:var(--g-color-text-complementary);margin-left:4px;text-transform:capitalize}.ydb-critical-dialog{padding-top:var(--g-spacing-3)}.ydb-critical-dialog__warning-icon{color:var(--ydb-color-status-yellow);margin-right:16px}.ydb-critical-dialog__error-icon{color:var(--ydb-color-status-red);height:24px;margin-right:16px}.ydb-critical-dialog__body{display:flex;flex-direction:column;gap:var(--g-spacing-6)}.ydb-critical-dialog__body-message{align-items:center;display:flex}.ydb-critical-dialog__body-message_error,.ydb-critical-dialog__body-message_warning{border:1px solid;border-radius:var(--g-modal-border-radius,5px);padding:var(--g-spacing-4) var(--g-spacing-5)}.ydb-critical-dialog__body-message_warning{border-color:var(--ydb-color-status-yellow)}.ydb-critical-dialog__body-message_error{border-color:var(--ydb-color-status-red)}.g-checkbox__indicator{cursor:inherit;display:inline-block;position:relative}.g-checkbox__indicator:before{background-color:initial;border:1px solid var(--g-color-line-generic-accent);border-radius:4px;content:"";inset:0;position:absolute;transition:background .1s linear}.g-checkbox__indicator:after{content:" ";visibility:hidden}.g-checkbox__icon{align-items:center;color:#0000;display:flex;inset:0;justify-content:center;pointer-events:none;position:absolute;transform:translateY(-5px);transition:color .1s,transform .2s;visibility:hidden}.g-checkbox__control{border:none;cursor:inherit;margin:0;opacity:0;outline:none;padding:0}.g-checkbox__control,.g-checkbox__outline{background:none;height:100%;inset-block-start:0;inset-inline-start:0;position:absolute;width:100%}.g-checkbox__outline{border-radius:4px;pointer-events:none}.g-checkbox__control:focus-visible+.g-checkbox__outline{outline:2px solid var(--g-color-line-focus)}.g-checkbox_size_m .g-checkbox__icon-svg_type_tick{height:10px;width:8px}.g-checkbox_size_m .g-checkbox__icon-svg_type_dash{height:12px;width:12px}.g-checkbox_size_m .g-checkbox__indicator{height:14px;width:14px}.g-checkbox_size_l .g-checkbox__icon-svg_type_tick{height:9px;width:11px}.g-checkbox_size_l .g-checkbox__icon-svg_type_dash{height:15px;width:15px}.g-checkbox_size_l .g-checkbox__indicator{height:17px;width:17px}.g-checkbox:hover .g-checkbox__indicator:before{border-color:var(--g-color-line-generic-accent-hover)}.g-checkbox_checked .g-checkbox__indicator:before,.g-checkbox_indeterminate .g-checkbox__indicator:before{background-color:var(--g-color-base-brand);border:#0000}.g-checkbox_checked .g-checkbox__icon,.g-checkbox_indeterminate .g-checkbox__icon{color:var(--g-color-text-brand-contrast);transform:translateX(0);visibility:visible}.g-checkbox_disabled .g-checkbox__indicator:before{background-color:var(--g-color-base-generic-accent-disabled);border:#0000}.g-checkbox_disabled.g-checkbox_checked .g-checkbox__indicator:before,.g-checkbox_disabled.g-checkbox_indeterminate .g-checkbox__indicator:before{background-color:var(--g-color-base-brand);opacity:.5}.link,.ydb-tablet-info__link{color:var(--g-color-text-link);text-decoration:none}.link:hover,.ydb-tablet-info__link:hover{color:var(--g-color-text-link-hover)}.ydb-tablet-info__section-title{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-2-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-2-line-height);margin:var(--g-spacing-1) 0 var(--g-spacing-3)}.ydb-table{--ydb-table-cell-height:40px}.ydb-table__table-header-content{align-items:center;border-bottom:1px solid var(--g-color-line-generic);display:inline-flex;height:100%;padding:var(--g-spacing-1) var(--g-spacing-2);width:100%}.ydb-table__table{border-collapse:collapse;border-spacing:0;table-layout:fixed}.ydb-table__table tr:hover{background-color:var(--g-color-base-simple-hover)!important}.ydb-table__table tr:nth-of-type(odd){background-color:var(--g-color-base-generic-ultralight)}.ydb-table__table_width_max{width:100%}.ydb-table__table-header-cell{background-color:var(--g-color-base-background);font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-2-font-size);font-weight:var(--g-text-subheader-font-weight);height:var(--ydb-table-cell-height)!important;line-height:var(--g-text-subheader-2-line-height);padding:0;text-align:left;vertical-align:middle}:is(.ydb-table__table-header-cell_align_right) .ydb-table__table-header-content{justify-content:flex-end;text-align:right}.ydb-table__table-cell{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);height:var(--ydb-table-cell-height)!important;line-height:var(--g-text-body-2-line-height);padding:0}.ydb-table__table-cell_align_right{text-align:right!important}.ydb-table__table-cell_vertical-align_top{vertical-align:top!important}.gt-table{border:none;border-collapse:initial;border-spacing:0}.gt-table__row_interactive{cursor:pointer}.gt-table__header_sticky{inset-block-start:0;position:sticky;z-index:1}.gt-table__footer_sticky{inset-block-end:0;position:sticky;z-index:1}.gt-table__cell{font-weight:400}.gt-table__footer-cell,.gt-table__header-cell{font-weight:500;position:relative}.gt-table__cell,.gt-table__footer-cell,.gt-table__header-cell{box-sizing:border-box;height:inherit;padding:0;text-align:start}.gt-table__cell_pinned,.gt-table__footer-cell_pinned,.gt-table__header-cell_pinned{position:sticky;z-index:1}.gt-table__sort{cursor:pointer;-webkit-user-select:none;user-select:none}.gt-table_with-row-virtualization{display:grid;height:auto}.gt-table_with-row-virtualization .gt-table__body{display:grid;position:relative}.gt-table_with-row-virtualization .gt-table__footer,.gt-table_with-row-virtualization .gt-table__header{display:grid}.gt-table_with-row-virtualization .gt-table__footer-row,.gt-table_with-row-virtualization .gt-table__header-row{display:flex;height:auto}.gt-table_with-row-virtualization .gt-table__row{display:flex;height:auto;position:absolute}.gt-table_with-row-virtualization .gt-table__row_empty{position:relative}.gt-group-header{inset-inline-start:0;margin:0;position:sticky}.gt-group-header__button{appearance:none;background:inherit;border:none;cursor:pointer;display:flex;gap:8px;outline:none;padding:0;width:100%}.gt-group-header__icon{display:inline-block;transform:rotate(-90deg);transition:transform .1s ease-out;vertical-align:middle}.gt-group-header__icon_expanded{transform:rotate(0)}.gt-group-header__content{display:inline-flex;font-weight:500;gap:4px}.gt-sort-indicator{color:var(--g-color-text-hint);display:inline-flex;margin-inline-start:4px;transform:rotate(0);vertical-align:middle}.gt-sort-indicator_invisible{opacity:0}.gt-table__header-cell:hover .gt-sort-indicator_invisible{opacity:1}.gt-sort-indicator_order_asc{transform:rotate(180deg)}.gt-resize-handle{background:#d3d3d3;cursor:col-resize;height:100%;inset-block-start:0;opacity:0;position:absolute;touch-action:none;-webkit-user-select:none;user-select:none;width:6px}.gt-resize-handle_direction_ltr{inset-inline-end:0}.gt-resize-handle_direction_rtl{inset-inline-start:0}.gt-resize-handle_resizing,.gt-table__header-cell:hover .gt-resize-handle{opacity:1}.ydb-tablet-storage-info__metrics-cell{white-space:nowrap}.ydb-tablet-storage-info__metrics-cell,.ydb-tablet-storage-info__name-wrapper{padding:var(--g-spacing-1) var(--g-spacing-2)}.ydb-tablet-storage-info__with-padding{padding-left:calc(var(--g-spacing-2) + var(--g-spacing-6))}.ydb-tablet-storage-info__name-content_no-control{padding-left:var(--g-spacing-6)}.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.ydb-tablet-page{font-size:var(--g-text-body-2-font-size);height:100%;line-height:var(--g-text-body-2-line-height);padding:20px}.ydb-tablet-page__placeholder{align-items:center;display:flex;flex:1 1 auto;justify-content:center}.ydb-tablet-page__loader{margin-left:var(--g-spacing-2)} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/49393.82d9be05.chunk.css b/ydb/core/viewer/monitoring/static/css/49393.82d9be05.chunk.css deleted file mode 100644 index bfb7dea4346e..000000000000 --- a/ydb/core/viewer/monitoring/static/css/49393.82d9be05.chunk.css +++ /dev/null @@ -1 +0,0 @@ -@charset "UTF-8";.ydb-entity-page-title{text-wrap:nowrap;align-items:baseline;display:flex;flex-flow:row nowrap;font-size:var(--g-text-header-2-font-size);line-height:var(--g-text-header-2-line-height)}.ydb-entity-page-title__prefix{color:var(--g-color-text-secondary);margin-right:6px}.ydb-entity-page-title__icon{margin-right:8px}.auto-refresh-control{align-items:center;display:flex;gap:var(--g-spacing-1)}.g-skeleton{--_--animation-from:calc(-100%*var(--g-flow-direction));--_--animation-to:calc(100%*var(--g-flow-direction));--_--gradient-deg:calc(90deg*var(--g-flow-direction));background-color:var(--g-color-base-generic);border-radius:5px;display:inline-block;overflow:hidden;position:relative;width:100%;z-index:0}.g-skeleton:after{animation:g-skeleton 1.2s ease-out infinite;background-image:linear-gradient(var(--_--gradient-deg),#0000,var(--g-color-base-generic));content:"";inset:0;position:absolute}@keyframes g-skeleton{0%{transform:translateX(var(--_--animation-from))}to{transform:translateX(var(--_--animation-to))}}.ydb-page-meta__info{text-wrap:nowrap;color:var(--g-color-text-primary);display:flex;flex-flow:row nowrap;flex-grow:1;font-size:var(--g-text-body-2-font-size);height:var(--g-text-body-2-line-height);line-height:var(--g-text-body-2-line-height)}.ydb-page-meta__skeleton{height:80%;width:80%}.kv-shorty-string__toggle{font-size:.85em;margin-left:2em}.kv-result-issues{padding:0 10px}.kv-result-issues__error-message{align-items:center;background-color:var(--g-color-base-background);display:flex;left:0;padding:10px 0;position:sticky;top:0;z-index:2}.kv-result-issues__error-message-text{margin:0 10px}.kv-issues{position:relative}.kv-issue_leaf{margin-left:31px}.kv-issue__issues{padding-left:24px}.kv-issue__line{align-items:flex-start;display:flex;margin:0 0 10px;padding:0 10px 0 0}.kv-issue__place-text{color:var(--g-color-text-secondary);display:inline-block;padding-right:10px;text-align:left}.kv-issue__message{display:flex;font-family:var(--g-font-family-monospace);font-size:var(--g-text-code-2-font-size);line-height:var(--g-text-header-2-line-height);margin-left:10px;margin-right:auto}.kv-issue__message-text{flex:1 1 auto;min-width:240px;white-space:pre-wrap;word-break:break-word}.kv-issue__code{color:var(--g-color-text-complementary);flex:0 0 auto;font-size:12px;margin-left:1.5em;padding:3px 0}.kv-issue__arrow-toggle{margin-right:5px}.yql-issue-severity{align-items:center;display:flex;line-height:28px;white-space:nowrap}.yql-issue-severity_severity_error .yql-issue-severity__icon,.yql-issue-severity_severity_fatal .yql-issue-severity__icon{color:var(--g-color-text-danger)}.yql-issue-severity_severity_warning .yql-issue-severity__icon{color:var(--g-color-text-warning)}.yql-issue-severity_severity_info .yql-issue-severity__icon{color:var(--g-color-text-info)}.yql-issue-severity__title{color:var(--g-color-text-complementary);margin-left:4px;text-transform:capitalize}.ydb-critical-dialog{padding-top:var(--g-spacing-3)}.ydb-critical-dialog__warning-icon{color:var(--ydb-color-status-yellow);margin-right:16px}.ydb-critical-dialog__error-icon{color:var(--ydb-color-status-red);height:24px;margin-right:16px}.ydb-critical-dialog__body{display:flex;flex-direction:column;gap:var(--g-spacing-6)}.ydb-critical-dialog__body-message{align-items:center;display:flex}.ydb-critical-dialog__body-message_error,.ydb-critical-dialog__body-message_warning{border:1px solid;border-radius:var(--g-modal-border-radius,5px);padding:var(--g-spacing-4) var(--g-spacing-5)}.ydb-critical-dialog__body-message_warning{border-color:var(--ydb-color-status-yellow)}.ydb-critical-dialog__body-message_error{border-color:var(--ydb-color-status-red)}.g-checkbox__indicator{cursor:inherit;display:inline-block;position:relative}.g-checkbox__indicator:before{background-color:initial;border:1px solid var(--g-color-line-generic-accent);border-radius:4px;content:"";inset:0;position:absolute;transition:background .1s linear}.g-checkbox__indicator:after{content:" ";visibility:hidden}.g-checkbox__icon{align-items:center;color:#0000;display:flex;inset:0;justify-content:center;pointer-events:none;position:absolute;transform:translateY(-5px);transition:color .1s,transform .2s;visibility:hidden}.g-checkbox__control{border:none;cursor:inherit;margin:0;opacity:0;outline:none;padding:0}.g-checkbox__control,.g-checkbox__outline{background:none;height:100%;inset-block-start:0;inset-inline-start:0;position:absolute;width:100%}.g-checkbox__outline{border-radius:4px;pointer-events:none}.g-checkbox__control:focus-visible+.g-checkbox__outline{outline:2px solid var(--g-color-line-focus)}.g-checkbox_size_m .g-checkbox__icon-svg_type_tick{height:10px;width:8px}.g-checkbox_size_m .g-checkbox__icon-svg_type_dash{height:12px;width:12px}.g-checkbox_size_m .g-checkbox__indicator{height:14px;width:14px}.g-checkbox_size_l .g-checkbox__icon-svg_type_tick{height:9px;width:11px}.g-checkbox_size_l .g-checkbox__icon-svg_type_dash{height:15px;width:15px}.g-checkbox_size_l .g-checkbox__indicator{height:17px;width:17px}.g-checkbox:hover .g-checkbox__indicator:before{border-color:var(--g-color-line-generic-accent-hover)}.g-checkbox_checked .g-checkbox__indicator:before,.g-checkbox_indeterminate .g-checkbox__indicator:before{background-color:var(--g-color-base-brand);border:#0000}.g-checkbox_checked .g-checkbox__icon,.g-checkbox_indeterminate .g-checkbox__icon{color:var(--g-color-text-brand-contrast);transform:translateX(0);visibility:visible}.g-checkbox_disabled .g-checkbox__indicator:before{background-color:var(--g-color-base-generic-accent-disabled);border:#0000}.g-checkbox_disabled.g-checkbox_checked .g-checkbox__indicator:before,.g-checkbox_disabled.g-checkbox_indeterminate .g-checkbox__indicator:before{background-color:var(--g-color-base-brand);opacity:.5}.link,.ydb-tablet-info__link{color:var(--g-color-text-link);text-decoration:none}.link:hover,.ydb-tablet-info__link:hover{color:var(--g-color-text-link-hover)}.ydb-tablet-info__section-title{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-2-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-2-line-height);margin:var(--g-spacing-1) 0 var(--g-spacing-3)}.ydb-table{--ydb-table-cell-height:40px}.ydb-table__table-header-content{align-items:center;border-bottom:1px solid var(--g-color-line-generic);display:inline-flex;height:100%;padding:var(--g-spacing-1) var(--g-spacing-2);width:100%}.ydb-table__table{border-collapse:collapse;border-spacing:0;table-layout:fixed}.ydb-table__table tr:hover{background-color:var(--g-color-base-simple-hover)!important}.ydb-table__table tr:nth-of-type(odd){background-color:var(--g-color-base-generic-ultralight)}.ydb-table__table_width_max{width:100%}.ydb-table__table-header-cell{background-color:var(--g-color-base-background);font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-2-font-size);font-weight:var(--g-text-subheader-font-weight);height:var(--ydb-table-cell-height)!important;line-height:var(--g-text-subheader-2-line-height);padding:0;text-align:left;vertical-align:middle}:is(.ydb-table__table-header-cell_align_right) .ydb-table__table-header-content{justify-content:flex-end;text-align:right}.ydb-table__table-cell{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);height:var(--ydb-table-cell-height)!important;line-height:var(--g-text-body-2-line-height);padding:0}.ydb-table__table-cell_align_right{text-align:right!important}.ydb-table__table-cell_vertical-align_top{vertical-align:top!important}.gt-table{border:none;border-collapse:initial;border-spacing:0}.gt-table__row_interactive{cursor:pointer}.gt-table__header_sticky{inset-block-start:0;position:sticky;z-index:1}.gt-table__footer_sticky{inset-block-end:0;position:sticky;z-index:1}.gt-table__cell{font-weight:400}.gt-table__footer-cell,.gt-table__header-cell{font-weight:500;position:relative}.gt-table__cell,.gt-table__footer-cell,.gt-table__header-cell{box-sizing:border-box;height:inherit;padding:0;text-align:start}.gt-table__cell_pinned,.gt-table__footer-cell_pinned,.gt-table__header-cell_pinned{position:sticky;z-index:1}.gt-table__sort{cursor:pointer;-webkit-user-select:none;user-select:none}.gt-table_with-row-virtualization{display:grid;height:auto}.gt-table_with-row-virtualization .gt-table__body{display:grid;position:relative}.gt-table_with-row-virtualization .gt-table__footer,.gt-table_with-row-virtualization .gt-table__header{display:grid}.gt-table_with-row-virtualization .gt-table__footer-row,.gt-table_with-row-virtualization .gt-table__header-row{display:flex;height:auto}.gt-table_with-row-virtualization .gt-table__row{display:flex;height:auto;position:absolute}.gt-table_with-row-virtualization .gt-table__row_empty{position:relative}.gt-group-header{inset-inline-start:0;margin:0;position:sticky}.gt-group-header__button{appearance:none;background:inherit;border:none;cursor:pointer;display:flex;gap:8px;outline:none;padding:0;width:100%}.gt-group-header__icon{display:inline-block;transform:rotate(-90deg);transition:transform .1s ease-out;vertical-align:middle}.gt-group-header__icon_expanded{transform:rotate(0)}.gt-group-header__content{display:inline-flex;font-weight:500;gap:4px}.gt-sort-indicator{color:var(--g-color-text-hint);display:inline-flex;margin-inline-start:4px;transform:rotate(0);vertical-align:middle}.gt-sort-indicator_invisible{opacity:0}.gt-table__header-cell:hover .gt-sort-indicator_invisible{opacity:1}.gt-sort-indicator_order_asc{transform:rotate(180deg)}.gt-resize-handle{background:#d3d3d3;cursor:col-resize;height:100%;inset-block-start:0;opacity:0;position:absolute;touch-action:none;-webkit-user-select:none;user-select:none;width:6px}.gt-resize-handle_direction_ltr{inset-inline-end:0}.gt-resize-handle_direction_rtl{inset-inline-start:0}.gt-resize-handle_resizing,.gt-table__header-cell:hover .gt-resize-handle{opacity:1}.ydb-tablet-storage-info__metrics-cell{white-space:nowrap}.ydb-tablet-storage-info__metrics-cell,.ydb-tablet-storage-info__name-wrapper{padding:var(--g-spacing-1) var(--g-spacing-2)}.ydb-tablet-storage-info__with-padding{padding-left:calc(var(--g-spacing-2) + var(--g-spacing-6))}.ydb-tablet-storage-info__name-content_no-control{padding-left:var(--g-spacing-6)}.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.ydb-tablet-page{font-size:var(--g-text-body-2-font-size);height:100%;line-height:var(--g-text-body-2-line-height);padding:20px}.ydb-tablet-page__placeholder{align-items:center;display:flex;flex:1 1 auto;justify-content:center}.ydb-tablet-page__loader{margin-left:var(--g-spacing-2)} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/52852.f32aa6d8.chunk.css b/ydb/core/viewer/monitoring/static/css/52852.f32aa6d8.chunk.css new file mode 100644 index 000000000000..d66cad0581dd --- /dev/null +++ b/ydb/core/viewer/monitoring/static/css/52852.f32aa6d8.chunk.css @@ -0,0 +1 @@ +.auto-refresh-control{align-items:center;display:flex;gap:var(--g-spacing-1)}.table-skeleton__wrapper{width:100%}.table-skeleton__wrapper_hidden{visibility:hidden}.table-skeleton__row{align-items:center;display:flex;height:var(--data-table-row-height)}.table-skeleton__row .g-skeleton{height:var(--g-text-body-2-line-height)}.table-skeleton__col-1{margin-right:5%;width:10%}.table-skeleton__col-2{margin-right:5%;width:7%}.table-skeleton__col-3,.table-skeleton__col-4{margin-right:5%;width:5%}.table-skeleton__col-5{width:20%}.table-skeleton__col-full{width:100%}.ydb-table-with-controls-layout{--data-table-sticky-top-offset:62px;box-sizing:border-box;display:inline-block;min-width:100%}.ydb-table-with-controls-layout__controls-wrapper{background-color:var(--g-color-base-background);box-sizing:border-box;left:0;position:sticky;top:0;width:100%;z-index:3}.ydb-table-with-controls-layout__controls{align-items:center;background-color:var(--g-color-base-background);display:flex;gap:12px;height:62px;left:0;padding:16px 0 18px;position:sticky;top:0;width:max-content;z-index:3}.ydb-table-with-controls-layout__table{position:relative;z-index:2}.ydb-table-with-controls-layout .ydb-paginated-table__head{top:var(--data-table-sticky-top-offset,62px)}.ydb-table-with-controls-layout .data-table__sticky_moving{top:var(--data-table-sticky-top-offset,62px)!important}.progress-viewer{align-items:center;background:var(--g-color-base-generic);border-radius:2px;color:var(--g-color-text-complementary);display:flex;font-size:var(--g-text-body-2-font-size);height:23px;justify-content:center;min-width:150px;overflow:hidden;padding:0 4px;position:relative;white-space:nowrap;z-index:0}.progress-viewer_theme_dark{color:var(--g-color-text-light-primary)}.progress-viewer_theme_dark .progress-viewer__line{opacity:.75}.progress-viewer_status_good{background-color:var(--g-color-base-positive-light)}.progress-viewer_status_good .progress-viewer__line{background-color:var(--ydb-color-status-green)}.progress-viewer_status_warning{background-color:var(--g-color-base-yellow-light)}.progress-viewer_status_warning .progress-viewer__line{background-color:var(--ydb-color-status-yellow)}.progress-viewer_status_danger{background-color:var(--g-color-base-danger-light)}.progress-viewer_status_danger .progress-viewer__line{background-color:var(--ydb-color-status-red)}.progress-viewer__line{height:100%;left:0;position:absolute;top:0}.progress-viewer__text{position:relative;z-index:1}.progress-viewer_size_xs{font-size:var(--g-text-body-2-font-size);height:20px;line-height:var(--g-text-body-2-line-height)}.progress-viewer_size_s{font-size:var(--g-text-body-1-font-size);height:28px;line-height:28px}.progress-viewer_size_m{font-size:var(--g-text-body-2-font-size);height:32px;line-height:32px}.progress-viewer_size_ns{font-size:13px;height:24px;line-height:var(--g-text-subheader-3-line-height)}.progress-viewer_size_n{font-size:var(--g-text-body-1-font-size);height:36px;line-height:36px}.progress-viewer_size_l{font-size:var(--g-text-subheader-3-font-size);height:38px;line-height:38px}.progress-viewer_size_head{font-size:var(--g-text-body-1-font-size);line-height:36px}.ydb-table-group{border:1px solid var(--g-color-line-generic);border-radius:var(--g-spacing-2);display:flex;flex-direction:column;margin-bottom:20px;width:100%}.ydb-table-group__button{background:unset;border:unset;cursor:pointer;padding:8px 0}.ydb-table-group__title-wrapper{align-items:center;display:flex;flex-direction:row;gap:var(--g-spacing-2);justify-content:flex-start;left:0;padding-left:20px;position:sticky;width:max-content}.ydb-table-group__title{display:flex;flex-direction:row;gap:var(--g-spacing-4)}.ydb-table-group__count{display:flex;flex-direction:row;gap:var(--g-spacing-3)}.ydb-table-group__content{padding:12px 0 20px 20px}.ydb-search{min-width:100px}.g-tree-select{display:inline-block;max-width:100%}.g-tree-select_width_max{width:100%}.g-tree-select__popup{overflow:hidden;padding:4px 0}.g-tree-select__popup_size_s{border-radius:var(--g-list-container-border-radius,5px)}.g-tree-select__popup_size_m{border-radius:var(--g-list-container-border-radius,6px)}.g-tree-select__popup_size_l{border-radius:var(--g-list-container-border-radius,8px)}.g-tree-select__popup_size_xl{border-radius:var(--g-list-container-border-radius,10px)}.g-tree-select__list{padding:0 4px}.g-list-item-expand-icon{flex-shrink:0}.g-list-item-view{align-items:center;display:flex;flex-grow:1;flex-shrink:0}.g-list-item-view__content{height:100%;width:100%}.g-list-item-view__main-content{display:grid;gap:var(--g-spacing-half,2px);width:100%}.g-list-item-view:hover.g-list-item-view_activeOnHover,.g-list-item-view_active{background:var(--g-color-base-simple-hover)}.g-list-item-view_clickable{cursor:pointer}.g-list-item-view_selected,.g-list-item-view_selected.g-list-item-view_active,.g-list-item-view_selected:hover.g-list-item-view_activeOnHover{background:var(--g-color-base-selection)}.g-list-item-view_dragging,.g-list-item-view_dragging.g-list-item-view_active,.g-list-item-view_dragging.g-list-item-view_selected{background:var(--g-color-base-simple-hover-solid);z-index:100001!important}.g-list-item-view_radius_s{border-radius:var(--g-list-item-border-radius,3px)}.g-list-item-view_radius_m{border-radius:var(--g-list-item-border-radius,5px)}.g-list-item-view_radius_l{border-radius:var(--g-list-item-border-radius,6px)}.g-list-item-view_radius_xl{border-radius:var(--g-list-item-border-radius,8px)}.g-list-item-view__slot{flex-shrink:0}.g-list-recursive-renderer{margin:0;padding:0}.g-list-container-view{box-sizing:border-box;outline:none;width:100%}.g-list-container-view_fixed-height{height:var(--g-list-container-height,300px)}.g-list-container-view:not(.g-list-container-view_fixed-height){overflow:auto}.g-inner-table-column-setup{display:inline-block}.g-inner-table-column-setup__controls{margin:var(--g-spacing-1) var(--g-spacing-1) 0}.g-inner-table-column-setup__filter-input{border-block-end:1px solid var(--g-color-line-generic);box-sizing:border-box;padding:0 var(--g-spacing-2) var(--g-spacing-1)}.g-inner-table-column-setup__empty-placeholder{padding:var(--g-spacing-2)}.g-table-column-setup__status{color:var(--g-color-text-secondary);margin-inline-start:5px}.ydb-paginated-table{--paginated-table-cell-vertical-padding:5px;--paginated-table-cell-horizontal-padding:10px;--paginated-table-border-color:var(--g-color-base-generic-hover);--paginated-table-hover-color:var(--g-color-base-simple-hover-solid);font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);width:100%}.ydb-paginated-table__table{border-collapse:initial;border-spacing:0;max-width:100%;table-layout:fixed;width:max-content}.ydb-paginated-table__table th{padding:0}.ydb-paginated-table__row{position:relative;transform:translateZ(0);z-index:1}.ydb-paginated-table__row:hover{background:var(--paginated-table-hover-color)}.ydb-paginated-table__row_empty:hover{background-color:initial}.ydb-paginated-table__head{background-color:var(--g-color-base-background);left:0;position:sticky;top:0;z-index:2}.ydb-paginated-table__sort-icon-container{color:inherit;display:flex;justify-content:center}.ydb-paginated-table__sort-icon-container_shadow{opacity:.15}.ydb-paginated-table__sort-icon_desc{transform:rotate(180deg)}.ydb-paginated-table__head-cell-wrapper{border-bottom:1px solid var(--paginated-table-border-color);display:table-cell;overflow-x:hidden;position:relative}.ydb-paginated-table__head-cell{align-items:center;display:flex;flex-direction:row;max-width:100%;padding:var(--paginated-table-cell-vertical-padding) var(--paginated-table-cell-horizontal-padding);width:100%}.ydb-paginated-table__head-cell_align_left{justify-content:left}.ydb-paginated-table__head-cell_align_center{justify-content:center}.ydb-paginated-table__head-cell_align_right{justify-content:right}.ydb-paginated-table__head-cell{cursor:default;font-weight:700;gap:8px}.ydb-paginated-table__head-cell_sortable{cursor:pointer}.ydb-paginated-table__head-cell_sortable.ydb-paginated-table__head-cell_align_right{flex-direction:row-reverse}.ydb-paginated-table__head-cell-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:min-content}.ydb-paginated-table__row-cell{border-bottom:1px solid var(--paginated-table-border-color);display:table-cell;max-width:100%;overflow-x:hidden;padding:var(--paginated-table-cell-vertical-padding) var(--paginated-table-cell-horizontal-padding);text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:100%}.ydb-paginated-table__row-cell_align_left{text-align:left}.ydb-paginated-table__row-cell_align_center{text-align:center}.ydb-paginated-table__row-cell_align_right{text-align:right}.ydb-paginated-table__resize-handler{background-color:var(--g-color-base-generic);cursor:col-resize;height:100%;position:absolute;right:0;top:0;visibility:hidden;width:6px}.ydb-paginated-table__head-cell-wrapper:hover>.ydb-paginated-table__resize-handler,.ydb-paginated-table__resize-handler_resizing{visibility:visible}.ydb-paginated-table__resizeable-table-container{padding-right:20px;width:max-content}.ydb-paginated-table__row-skeleton:after{animation:none!important}.hover-popup{padding:var(--g-spacing-3)}.memory-viewer{min-width:150px;padding:0 var(--g-spacing-1);position:relative;z-index:0}.memory-viewer__progress-container{background:var(--g-color-base-generic);border-radius:2px;height:20px;overflow:hidden;position:relative}.memory-viewer__container{display:flex;padding:2px 0}.memory-viewer__legend{border-radius:2px;bottom:2px;height:20px;position:absolute;width:20px}.memory-viewer__legend_type_AllocatorCachesMemory{background-color:var(--g-color-base-utility-medium-hover)}.memory-viewer__legend_type_SharedCacheConsumption{background-color:var(--g-color-base-info-medium-hover)}.memory-viewer__legend_type_MemTableConsumption{background-color:var(--g-color-base-warning-medium-hover)}.memory-viewer__legend_type_QueryExecutionConsumption{background-color:var(--g-color-base-positive-medium-hover)}.memory-viewer__legend_type_Other{background-color:var(--g-color-base-generic-medium-hover)}.memory-viewer__segment{height:100%;position:absolute}.memory-viewer__segment_type_AllocatorCachesMemory{background-color:var(--g-color-base-utility-medium-hover)}.memory-viewer__segment_type_SharedCacheConsumption{background-color:var(--g-color-base-info-medium-hover)}.memory-viewer__segment_type_MemTableConsumption{background-color:var(--g-color-base-warning-medium-hover)}.memory-viewer__segment_type_QueryExecutionConsumption{background-color:var(--g-color-base-positive-medium-hover)}.memory-viewer__segment_type_Other{background-color:var(--g-color-base-generic-medium-hover)}.memory-viewer__name{padding-left:28px}.memory-viewer_theme_dark{color:var(--g-color-text-light-primary)}.memory-viewer_theme_dark .memory-viewer__segment{opacity:.75}.memory-viewer_status_good .memory-viewer__progress-container{background-color:var(--g-color-base-positive-light)}.memory-viewer_status_warning .memory-viewer__progress-container{background-color:var(--g-color-base-yellow-light)}.memory-viewer_status_danger .memory-viewer__progress-container{background-color:var(--g-color-base-danger-light)}.memory-viewer__text{align-items:center;display:flex;justify-content:center}.ydb-pool-bar{border:1px solid;border-radius:1px;cursor:pointer;height:20px;margin-right:2px;position:relative;width:6px}.ydb-pool-bar__popup-content{padding:10px;width:170px}.ydb-pool-bar:last-child{margin-right:0}.ydb-pool-bar_type_normal{border-color:var(--ydb-color-status-green)}.ydb-pool-bar_type_warning{border-color:var(--ydb-color-status-yellow)}.ydb-pool-bar_type_danger{border-color:var(--ydb-color-status-red)}.ydb-pool-bar__value{bottom:0;min-height:1px;position:absolute;width:100%}.ydb-pool-bar__value_type_normal{background-color:var(--ydb-color-status-green)}.ydb-pool-bar__value_type_warning{background-color:var(--ydb-color-status-yellow)}.ydb-pool-bar__value_type_danger{background-color:var(--ydb-color-status-red)}.ydb-pools-graph{display:flex}.tablets-statistic{align-items:center;display:flex;gap:2px}.tablets-statistic__tablet{border:1px solid;border-radius:2px;color:var(--g-color-text-secondary);display:inline-block;font-size:11px;height:20px;line-height:20px;padding:0 4px;text-align:center;text-decoration:none;text-transform:uppercase}.tablets-statistic__tablet_state_green{background-color:var(--g-color-base-positive-light);color:var(--g-color-text-positive)}.tablets-statistic__tablet_state_yellow{background-color:var(--g-color-base-warning-light);color:var(--g-color-text-warning)}.tablets-statistic__tablet_state_blue{background-color:var(--g-color-base-info-light);color:var(--g-color-text-info)}.tablets-statistic__tablet_state_orange{background-color:var(--g-color-base-warning-light);color:var(--g-color-text-warning-heavy)}.tablets-statistic__tablet_state_red{background:var(--g-color-base-danger-light);color:var(--g-color-text-danger)}.tablets-statistic__tablet_state_grey{border:1px solid var(--g-color-line-generic-hover);color:var(--g-color-text-secondary)}.ydb-nodes-columns__column-cpu,.ydb-nodes-columns__column-ram{min-width:40px}.storage-disk-progress-bar{--progress-bar-full-height:var(--g-text-body-3-line-height);--progress-bar-compact-height:12px;--entity-state-border-color:var(--g-color-base-misc-heavy);--entity-state-background-color:var(--g-color-base-misc-light);--entity-state-fill-color:var(--g-color-base-misc-medium);--entity-state-font-color:var(--g-color-text-primary);background-color:var(--entity-state-background-color);border:1px solid var(--entity-state-border-color);border-radius:4px;color:var(--g-color-text-primary);height:var(--progress-bar-full-height);min-width:50px;position:relative;text-align:center;z-index:0}.storage-disk-progress-bar_green{--entity-state-font-color:var(--g-color-text-positive);--entity-state-border-color:var(--g-color-base-positive-heavy);--entity-state-background-color:var(--g-color-base-positive-light);--entity-state-fill-color:var(--g-color-base-positive-medium)}.storage-disk-progress-bar_blue{--entity-state-font-color:var(--g-color-text-info);--entity-state-border-color:var(--g-color-base-info-heavy);--entity-state-background-color:var(--g-color-base-info-light);--entity-state-fill-color:var(--g-color-base-info-medium)}.storage-disk-progress-bar_yellow{--entity-state-font-color:var(--g-color-text-warning);--entity-state-border-color:var(--g-color-base-warning-heavy);--entity-state-background-color:var(--g-color-base-yellow-light);--entity-state-fill-color:var(--g-color-base-yellow-medium)}.storage-disk-progress-bar_orange{--entity-state-font-color:var(--g-color-private-orange-500);--entity-state-border-color:var(--ydb-color-status-orange);--entity-state-background-color:var(--g-color-private-orange-100);--entity-state-fill-color:var(--g-color-private-orange-300)}.storage-disk-progress-bar_red{--entity-state-font-color:var(--g-color-text-danger);--entity-state-border-color:var(--g-color-base-danger-heavy);--entity-state-background-color:var(--g-color-base-danger-light);--entity-state-fill-color:var(--g-color-base-danger-medium)}.storage-disk-progress-bar__grey{--entity-state-font-color:var(--g-color-text-secondary);--entity-state-border-color:var(--g-color-line-generic-hover)}.storage-disk-progress-bar_compact{border-radius:2px;height:var(--progress-bar-compact-height);min-width:0}.storage-disk-progress-bar_faded{background-color:unset}.storage-disk-progress-bar_inactive{opacity:.5}.storage-disk-progress-bar_empty{background-color:unset;border-style:dashed;color:var(--g-color-text-hint)}.storage-disk-progress-bar__fill-bar{background-color:var(--entity-state-fill-color);border-radius:3px 0 0 3px;height:100%;left:0;position:absolute;top:0}.storage-disk-progress-bar__fill-bar_faded{background-color:var(--entity-state-background-color)}.storage-disk-progress-bar__fill-bar_compact{border-radius:1px}.storage-disk-progress-bar__fill-bar_inverted{border-radius:0 3px 3px 0;left:auto;right:0}.storage-disk-progress-bar__title{color:inherit;font-size:var(--g-text-body-1-font-size);line-height:calc(var(--progress-bar-full-height) - 2px);position:relative;z-index:2}.vdisk-storage-popup .info-viewer+.info-viewer{border-top:1px solid var(--g-color-line-generic);margin-top:8px;padding-top:8px}.vdisk-storage-popup__donor-label{margin-bottom:8px}.ydb-vdisk-component{border-radius:4px}.ydb-vdisk-component__content{border-radius:4px;display:block}.pdisk-storage{display:flex;flex-direction:column;justify-content:flex-end;min-width:var(--pdisk-min-width);position:relative;width:var(--pdisk-width)}.pdisk-storage__content{border-radius:4px;display:block;flex:1 1;position:relative}.pdisk-storage__vdisks{display:flex;flex:0 0 auto;gap:var(--pdisk-gap-width);margin-bottom:4px;white-space:nowrap}.pdisk-storage__vdisks-item{flex:0 0 var(--pdisk-vdisk-width);min-width:var(--pdisk-vdisk-width)}.data-table__row:hover .pdisk-storage__vdisks-item .stack__layer{background:var(--ydb-data-table-color-hover)}.pdisk-storage__donors-stack{--ydb-stack-offset-x:0px;--ydb-stack-offset-y:-2px;--ydb-stack-offset-x-hover:0px;--ydb-stack-offset-y-hover:-7px}.pdisk-storage__media-type{color:var(--g-color-text-secondary);font-size:var(--g-text-body-1-font-size);line-height:var(--g-text-body-1-line-height);position:absolute;right:4px;top:50%;transform:translateY(-50%)}.ydb-storage-disks{align-items:center;display:flex;flex-direction:row;gap:20px;width:max-content}.ydb-storage-disks__pdisks-wrapper{display:flex;flex-direction:row;justify-content:left;width:max-content}.ydb-storage-disks__vdisk-item{flex-basis:8px;flex-shrink:0}.ydb-storage-disks__vdisk-progress-bar{--progress-bar-compact-height:18px;border-radius:4px}.ydb-storage-disks__pdisk-item{margin-right:4px;min-width:80px}.ydb-storage-disks__pdisk-item_with-dc-margin{margin-right:12px}.ydb-storage-disks__pdisk-item:last-child{margin-right:0}.ydb-storage-disks__pdisk-progress-bar{--progress-bar-full-height:20px;padding-left:var(--g-spacing-2);text-align:left}.stack{--ydb-stack-base-z-index:100;--ydb-stack-offset-x:4px;--ydb-stack-offset-y:4px;--ydb-stack-offset-x-hover:4px;--ydb-stack-offset-y-hover:6px;position:relative}.stack__layer{background:var(--g-color-base-background);transition:transform .1s ease-out}.stack__layer:first-child{position:relative;z-index:var(--ydb-stack-base-z-index)}.stack__layer+.stack__layer{height:100%;left:0;position:absolute;top:0;transform:translate(calc(var(--ydb-stack-level)*var(--ydb-stack-offset-x)),calc(var(--ydb-stack-level)*var(--ydb-stack-offset-y)));width:100%;z-index:calc(var(--ydb-stack-base-z-index) - var(--ydb-stack-level))}.stack:hover .stack__layer:first-child{transform:translate(calc(var(--ydb-stack-offset-x-hover)*-1),calc(var(--ydb-stack-offset-y-hover)*-1))}.stack:hover .stack__layer+.stack__layer{transform:translate(calc(var(--ydb-stack-level)*var(--ydb-stack-offset-x-hover)*2 - var(--ydb-stack-offset-x-hover)),calc(var(--ydb-stack-level)*var(--ydb-stack-offset-y-hover)*2 - var(--ydb-stack-offset-y-hover)))}.ydb-storage-vdisks__wrapper{display:flex}.ydb-storage-vdisks__item{margin-right:6px;width:90px}.ydb-storage-vdisks__item_with-dc-margin{margin-right:12px}.ydb-storage-vdisks__item:last-child{margin-right:0}.data-table__row:hover .ydb-storage-vdisks__item .stack__layer{background:var(--ydb-data-table-color-hover)}.ydb-storage-groups-columns__disks-column,.ydb-storage-groups-columns__vdisks-column{overflow:visible}.ydb-storage-groups-columns__pool-name-wrapper{direction:rtl;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ydb-storage-groups-columns__pool-name{unicode-bidi:plaintext}.ydb-storage-groups-columns__group-id{font-weight:500;margin-right:var(--g-spacing-1)}.global-storage__search{width:238px}.global-storage__table .g-tooltip{height:var(--g-text-body-2-line-height)!important}.global-storage .entity-status{justify-content:center}.global-storage__groups-wrapper{padding-right:20px}.ydb-storage-nodes__node_unavailable{opacity:.6}.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.ydb-storage-nodes-columns__pdisks-column{overflow:visible}.ydb-storage-nodes-columns__pdisks-wrapper{--pdisk-vdisk-width:3px;--pdisk-gap-width:2px;--pdisk-min-width:120px;--pdisk-margin:10px;--pdisk-width:max(calc(var(--maximum-slots, 1)*var(--pdisk-vdisk-width) + (var(--maximum-slots, 1) - 1)*var(--pdisk-gap-width)),var(--pdisk-min-width));--pdisks-container-width:calc(var(--maximum-disks, 1)*var(--pdisk-width) + (var(--maximum-disks, 1) - 1)*var(--pdisk-margin));display:flex;gap:var(--pdisk-margin);height:40px;width:var(--pdisks-container-width)}.ydb-storage-nodes-columns__pdisks-item{display:flex;flex-shrink:0}.ydb-info-viewer-skeleton{display:flex;flex-direction:column;gap:16px}.ydb-info-viewer-skeleton__row{align-items:flex-start;display:flex}.ydb-info-viewer-skeleton__row,.ydb-info-viewer-skeleton__row .g-skeleton{min-height:var(--g-text-body-2-font-size)}.ydb-info-viewer-skeleton__label{align-items:baseline;display:flex;flex:0 1 auto;width:200px}.ydb-info-viewer-skeleton__label__text{width:100px}.ydb-info-viewer-skeleton__label__dots{border-bottom:1px dotted var(--g-color-text-secondary);margin:0 2px;width:100px}.ydb-info-viewer-skeleton__value{max-width:20%;min-width:200px} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/56421.545f7f9d.chunk.css b/ydb/core/viewer/monitoring/static/css/56421.545f7f9d.chunk.css new file mode 100644 index 000000000000..876cff458bbf --- /dev/null +++ b/ydb/core/viewer/monitoring/static/css/56421.545f7f9d.chunk.css @@ -0,0 +1,9 @@ +@charset "UTF-8";.g-checkbox__indicator{cursor:inherit;display:inline-block;position:relative}.g-checkbox__indicator:before{background-color:initial;border:1px solid var(--g-color-line-generic-accent);border-radius:4px;content:"";inset:0;position:absolute;transition:background .1s linear}.g-checkbox__indicator:after{content:" ";visibility:hidden}.g-checkbox__icon{align-items:center;color:#0000;display:flex;inset:0;justify-content:center;pointer-events:none;position:absolute;transform:translateY(-5px);transition:color .1s,transform .2s;visibility:hidden}.g-checkbox__control{border:none;cursor:inherit;margin:0;opacity:0;outline:none;padding:0}.g-checkbox__control,.g-checkbox__outline{background:none;height:100%;inset-block-start:0;inset-inline-start:0;position:absolute;width:100%}.g-checkbox__outline{border-radius:4px;pointer-events:none}.g-checkbox__control:focus-visible+.g-checkbox__outline{outline:2px solid var(--g-color-line-focus)}.g-checkbox_size_m .g-checkbox__icon-svg_type_tick{height:10px;width:8px}.g-checkbox_size_m .g-checkbox__icon-svg_type_dash{height:12px;width:12px}.g-checkbox_size_m .g-checkbox__indicator{height:14px;width:14px}.g-checkbox_size_l .g-checkbox__icon-svg_type_tick{height:9px;width:11px}.g-checkbox_size_l .g-checkbox__icon-svg_type_dash{height:15px;width:15px}.g-checkbox_size_l .g-checkbox__indicator{height:17px;width:17px}.g-checkbox:hover .g-checkbox__indicator:before{border-color:var(--g-color-line-generic-accent-hover)}.g-checkbox_checked .g-checkbox__indicator:before,.g-checkbox_indeterminate .g-checkbox__indicator:before{background-color:var(--g-color-base-brand);border:#0000}.g-checkbox_checked .g-checkbox__icon,.g-checkbox_indeterminate .g-checkbox__icon{color:var(--g-color-text-brand-contrast);transform:translateX(0);visibility:visible}.g-checkbox_disabled .g-checkbox__indicator:before{background-color:var(--g-color-base-generic-accent-disabled);border:#0000}.g-checkbox_disabled.g-checkbox_checked .g-checkbox__indicator:before,.g-checkbox_disabled.g-checkbox_indeterminate .g-checkbox__indicator:before{background-color:var(--g-color-base-brand);opacity:.5}.g-tree-select{display:inline-block;max-width:100%}.g-tree-select_width_max{width:100%}.g-tree-select__popup{overflow:hidden;padding:4px 0}.g-tree-select__popup_size_s{border-radius:var(--g-list-container-border-radius,5px)}.g-tree-select__popup_size_m{border-radius:var(--g-list-container-border-radius,6px)}.g-tree-select__popup_size_l{border-radius:var(--g-list-container-border-radius,8px)}.g-tree-select__popup_size_xl{border-radius:var(--g-list-container-border-radius,10px)}.g-tree-select__list{padding:0 4px}.g-list-item-expand-icon{flex-shrink:0}.g-list-item-view{align-items:center;display:flex;flex-grow:1;flex-shrink:0}.g-list-item-view__content{height:100%;width:100%}.g-list-item-view__main-content{display:grid;gap:var(--g-spacing-half,2px);width:100%}.g-list-item-view:hover.g-list-item-view_activeOnHover,.g-list-item-view_active{background:var(--g-color-base-simple-hover)}.g-list-item-view_clickable{cursor:pointer}.g-list-item-view_selected,.g-list-item-view_selected.g-list-item-view_active,.g-list-item-view_selected:hover.g-list-item-view_activeOnHover{background:var(--g-color-base-selection)}.g-list-item-view_dragging,.g-list-item-view_dragging.g-list-item-view_active,.g-list-item-view_dragging.g-list-item-view_selected{background:var(--g-color-base-simple-hover-solid);z-index:100001!important}.g-list-item-view_radius_s{border-radius:var(--g-list-item-border-radius,3px)}.g-list-item-view_radius_m{border-radius:var(--g-list-item-border-radius,5px)}.g-list-item-view_radius_l{border-radius:var(--g-list-item-border-radius,6px)}.g-list-item-view_radius_xl{border-radius:var(--g-list-item-border-radius,8px)}.g-list-item-view__slot{flex-shrink:0}.g-list-recursive-renderer{margin:0;padding:0}.g-list-container-view{box-sizing:border-box;outline:none;width:100%}.g-list-container-view_fixed-height{height:var(--g-list-container-height,300px)}.g-list-container-view:not(.g-list-container-view_fixed-height){overflow:auto}.g-inner-table-column-setup{display:inline-block}.g-inner-table-column-setup__controls{margin:var(--g-spacing-1) var(--g-spacing-1) 0}.g-inner-table-column-setup__filter-input{border-block-end:1px solid var(--g-color-line-generic);box-sizing:border-box;padding:0 var(--g-spacing-2) var(--g-spacing-1)}.g-inner-table-column-setup__empty-placeholder{padding:var(--g-spacing-2)}.g-table-column-setup__status{color:var(--g-color-text-secondary);margin-inline-start:5px}.gc-help-popover__button{background:none;border:none;color:inherit;color:var(--g-color-text-hint);cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0}.gc-help-popover__button:focus-visible{border-radius:50%;outline:2px solid var(--g-color-line-focus)}.gc-definition-list__list{margin:0}.gc-definition-list__group-title{margin-block-end:var(--g-spacing-3)}.gc-definition-list__group-title:not(:first-of-type){margin-block-start:var(--g-spacing-5)}.gc-definition-list__item{align-items:baseline;display:flex;gap:var(--g-spacing-1)}.gc-definition-list__item+.gc-definition-list__item{margin-block-start:var(--g-spacing-4)}.gc-definition-list__item_grouped+.gc-definition-list__item_grouped{margin-block-start:var(--g-spacing-3)}.gc-definition-list_margin:not(:first-of-type){margin-block-start:var(--g-spacing-5)}.gc-definition-list__term-container{align-items:baseline;display:flex;flex:0 0 auto;max-width:300px;overflow:hidden;position:relative;width:300px}.gc-definition-list__term-wrapper{color:var(--g-color-text-secondary);flex:0 1 auto;overflow:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap}.gc-definition-list__term-container_multiline .gc-definition-list__term-wrapper{white-space:unset}.gc-definition-list__term-container_multiline .gc-definition-list__item-note-tooltip{position:absolute}.gc-definition-list__dots{border-block-end:1px dotted var(--g-color-line-generic-active);box-sizing:border-box;flex:1 0 auto;margin:0 2px;min-width:40px}.gc-definition-list__dots_with-note{margin-inline-start:15px;min-width:25px}.gc-definition-list__definition{flex:0 1 auto;margin:0}.gc-definition-list_responsive .gc-definition-list__term-container{flex:1 0 auto}.gc-definition-list__copy-container{align-items:center;display:inline-flex;margin-inline-end:calc(var(--g-spacing-7)*-1);padding-inline-end:var(--g-spacing-7);position:relative}.gc-definition-list__copy-container:hover .gc-definition-list__copy-button{opacity:1}.gc-definition-list__copy-container_icon-inside{margin-inline-end:unset;padding-inline-end:unset}.gc-definition-list__copy-container_icon-inside .gc-definition-list__copy-button{inset-block-start:0}.gc-definition-list__copy-button{display:inline-block;inset-inline-end:0;margin-inline-start:10px;opacity:0;position:absolute}.gc-definition-list__copy-button:focus-visible{opacity:1}.gc-definition-list_vertical .gc-definition-list__term-container{flex:1 0 auto}.gc-definition-list_vertical .gc-definition-list__item{flex-direction:column;gap:var(--g-spacing-half)}.gc-definition-list_vertical .gc-definition-list__item+.gc-definition-list__item{margin-block-start:var(--g-spacing-3)}.gc-definition-list_vertical .gc-definition-list__group-title:not(:first-of-type),.gc-definition-list_vertical .gc-definition-list_margin:not(:first-of-type){margin-block-start:var(--g-spacing-8)}.chartkit-loader{align-items:center;display:flex;justify-content:center}.chartkit,.chartkit-loader{height:100%;width:100%}.chartkit_mobile .chartkit-scrollable-node{max-height:3000px}.chartkit-theme_common{--highcarts-navigator-border:var(--g-color-line-generic);--highcarts-navigator-track:var(--g-color-base-generic);--highcarts-navigator-body:var(--g-color-scroll-handle);--highcharts-series-border:var(--g-color-base-background);--highcharts-grid-line:var(--g-color-line-generic);--highcharts-axis-line:var(--g-color-line-generic);--highcharts-tick:var(--g-color-line-generic);--highcharts-title:var(--g-color-text-primary);--highcharts-axis-labels:var(--g-color-text-secondary);--highcharts-data-labels:var(--g-color-text-secondary);--highcharts-plot-line-label:var(--g-color-text-secondary);--highcharts-legend-item:var(--g-color-text-secondary);--highcharts-legend-item-hover:var(--g-color-text-primary);--highcharts-legend-item-hidden:var(--g-color-text-hint);--highcharts-floating-bg:var(--g-color-infographics-tooltip-bg);--highcharts-tooltip-text:var(--g-color-text-primary);--highcharts-tooltip-bg:var(--highcharts-floating-bg);--highcharts-tooltip-alternate-bg:var(--g-color-base-generic);--highcharts-tooltip-text-complementary:var(--g-color-text-secondary);--highcharts-holiday-band:var(--g-color-base-generic)}.ydb-tree-view{--ydb-tree-view-level:0;font-size:13px;line-height:18px}.ydb-tree-view,.ydb-tree-view *{box-sizing:border-box}.ydb-tree-view__item{align-items:center;border-bottom:1px solid var(--g-color-line-generic-solid);cursor:pointer;display:flex;height:24px;padding-left:calc(24px*var(--ydb-tree-view-level));padding-right:3px}.ydb-tree-view__item:hover{background-color:var(--g-color-base-simple-hover)}.ydb-tree-view__item:hover .ydb-tree-view__actions{display:flex}.ydb-tree-view__item_active{background-color:var(--g-color-base-selection);font-weight:700}.ydb-tree-view__item_active:hover{background-color:var(--g-color-base-selection-hover)}.ydb-tree-view__content{align-items:center;display:flex;flex-grow:1;overflow:hidden}.ydb-tree-view__icon{align-items:center;color:var(--g-color-text-hint);display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.ydb-tree-view__icon svg{display:block}.ydb-tree-view__text{flex-grow:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ydb-tree-view__actions{align-items:center;display:none;margin-left:6px}.ydb-tree-view__arrow{background:url('data:image/svg+xml;utf8,') no-repeat 50%;border:none;cursor:pointer;flex-shrink:0;height:24px;padding:0;width:24px}.g-root_theme_dark .ydb-tree-view__arrow{background:url('data:image/svg+xml;utf8,') no-repeat 50%}.ydb-tree-view__arrow:focus-visible{outline:2px solid var(--g-color-line-focus)}.ydb-tree-view__arrow:not(.ydb-tree-view__arrow_collapsed){transform:rotate(90deg)}.ydb-tree-view__arrow_hidden{visibility:hidden}.ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:24px}.ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:48px}.ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:72px}.ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:96px}.ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:120px}.g-card{--_--background-color:#0000;--_--border-color:#0000;--_--border-width:0;--_--box-shadow:none;background-color:var(--g-card-background-color,var(--_--background-color));border:var(--g-card-border-width,var(--_--border-width)) solid var(--g-card-border-color,var(--_--border-color));border-radius:var(--g-card-border-radius,var(--_--border-radius));box-shadow:var(--g-card-box-shadow,var(--_--box-shadow));box-sizing:border-box;outline:none}.g-card_theme_normal{--_--border-color:var(--g-color-line-generic);--_--background-color:var(--g-color-base-generic)}.g-card_theme_info{--_--border-color:var(--g-color-line-info);--_--background-color:var(--g-color-base-info-light)}.g-card_theme_success{--_--border-color:var(--g-color-line-positive);--_--background-color:var(--g-color-base-positive-light)}.g-card_theme_warning{--_--border-color:var(--g-color-line-warning);--_--background-color:var(--g-color-base-warning-light)}.g-card_theme_danger{--_--border-color:var(--g-color-line-danger);--_--background-color:var(--g-color-base-danger-light)}.g-card_theme_utility{--_--border-color:var(--g-color-line-utility);--_--background-color:var(--g-color-base-utility-light)}.g-card_view_clear,.g-card_view_outlined{--_--background-color:#0000}.g-card_view_outlined{--_--border-width:1px}.g-card_type_action{--_--background-color:var(--g-color-base-float);--_--box-shadow:0px 1px 5px var(--g-color-sfx-shadow)}.g-card_type_action:after{border-radius:var(--g-card-border-radius,var(--_--border-radius));inset:0;pointer-events:none;position:absolute}.g-card_type_action.g-card_clickable{cursor:pointer;position:relative}.g-card_type_action.g-card_clickable:hover{--_--box-shadow:0px 3px 10px var(--g-color-sfx-shadow)}.g-card_type_action.g-card_clickable:focus-visible:after{content:"";outline:2px solid var(--g-color-line-focus)}.g-card_type_selection{--_--border-width:1px;--_--border-color:var(--g-color-line-generic);position:relative}.g-card_type_selection:before{inset:-1px}.g-card_type_selection:after,.g-card_type_selection:before{border-radius:var(--g-card-border-radius,var(--_--border-radius));pointer-events:none;position:absolute}.g-card_type_selection:after{inset:0}.g-card_type_selection.g-card_clickable{cursor:pointer}.g-card_type_selection.g-card_clickable:hover{--_--border-color:#0000}.g-card_type_selection.g-card_clickable:hover:not(.g-card_selected):before{border:2px solid var(--g-color-line-brand);content:"";opacity:.5}.g-card_type_selection.g-card_clickable:hover:focus-visible:before{border-color:#0000}.g-card_type_selection.g-card_clickable:focus-visible:after{content:"";outline:2px solid var(--g-color-line-focus)}.g-card_type_selection.g-card_selected:not(.g-card_disabled){--_--border-color:#0000}.g-card_type_selection.g-card_selected:not(.g-card_disabled):before{border:2px solid var(--g-color-line-brand);content:""}.g-card_type_selection.g-card_view_clear{--_--border-color:#0000}.g-card_type_container.g-card_view_raised{--_--background-color:var(--g-color-base-float)}.g-card_type_container.g-card_view_raised.g-card_size_m{--_--box-shadow:0px 1px 5px var(--g-color-sfx-shadow)}.g-card_type_container.g-card_view_raised.g-card_size_l{--_--box-shadow:0px 1px 6px var(--g-color-sfx-shadow-light),1px 3px 13px var(--g-color-sfx-shadow-light)}.g-card_size_m{--_--border-radius:8px}.g-card_size_l{--_--border-radius:16px}.g-date-relative-range-date-picker-control__input{caret-color:#0000}.g-date-relative-range-date-picker-control__input_mobile{pointer-events:none}.g-date-relative-range-date-picker-control__mobile-trigger{--_--g-date-mobile-trigger-clear-width:0px;--_--g-date-mobile-trigger-errors-width:0px;--_--g-date-mobile-trigger-button-width:24px;inset:0;inset-inline-end:calc(var(--g-spacing-2) + var(--_--g-date-mobile-trigger-button-width) + var(--_--g-date-mobile-trigger-clear-width) + var(--_--g-date-mobile-trigger-errors-width));opacity:0;position:absolute}.g-date-relative-range-date-picker-control__mobile-trigger_size_s{--_--g-date-mobile-trigger-button-width:20px}.g-date-relative-range-date-picker-control__mobile-trigger_size_l{--_--g-date-mobile-trigger-button-width:28px}.g-date-relative-range-date-picker-control__mobile-trigger_size_xl{--_--g-date-mobile-trigger-button-width:36px}.g-date-relative-range-date-picker-control__mobile-trigger_has-clear{--_--g-date-mobile-trigger-clear-width:calc(var(--_--g-date-mobile-trigger-button-width) + 2px)}.g-date-relative-range-date-picker-control__mobile-trigger_has-errors{--_--g-date-mobile-trigger-errors-width:calc(var(--_--g-date-mobile-trigger-button-width) + 2px)}.g-date-relative-range-date-picker-presets-doc__button{--g-button-background-color-hover:#0000}.g-date-relative-range-date-picker-presets-doc__content{--g-popover-max-width:"none"}.g-date-relative-range-date-picker-presets-doc__table_size_xl{font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-date-relative-range-date-picker-presets-doc__table>table{width:100%}.g-table,.g-table__scroll-container{overflow:auto;position:relative}.g-table__scroll-container{-ms-overflow-style:none;scrollbar-width:none}.g-table__scroll-container::-webkit-scrollbar{display:none}.g-table__horizontal-scroll-bar{margin-block-start:-1px;overflow-x:auto}.g-table__horizontal-scroll-bar-inner{height:1px;position:relative}.g-table__horizontal-scroll-bar-inner:before{background-color:#ffffff03;content:"";height:1px;inset-block-start:0;inset-inline-start:0;position:absolute;width:1px}.g-table__horizontal-scroll-bar_sticky-horizontal-scroll{position:sticky;z-index:3}.g-table__table{border-collapse:initial;border-spacing:0}.g-table__table_width_max{width:100%}.g-table__cell{border-block-end:1px solid var(--g-color-line-generic);box-sizing:initial;line-height:18px;overflow-wrap:break-word;padding:11px var(--g-spacing-2) 10px;text-align:start}.g-table__cell:first-child{padding-inline-start:0}.g-table__cell:last-child{padding-inline-end:0}.g-table__cell:not(.g-table__cell_word-wrap){overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.g-table__cell_align_center{text-align:center}.g-table__cell_align_end{text-align:end}.g-table .g-table__cell_sticky_end,.g-table .g-table__cell_sticky_start{background:var(--g-color-base-background);position:sticky;z-index:2}.g-table__cell_border_right{border-inline-end:1px solid var(--g-color-line-generic)}.g-table__cell_edge-padding:first-child{padding-inline-start:var(--g-spacing-3)}.g-table__cell_edge-padding:last-child{padding-inline-end:var(--g-spacing-3)}.g-table__row_vertical-align_top{vertical-align:top}.g-table__row_vertical-align_middle{vertical-align:middle}.g-table__row_empty .g-table__cell{text-align:center}.g-table__body .g-table__row:last-child .g-table__cell{border-block-end-color:#0000}.g-table__head .g-table__cell{font-weight:var(--g-text-accent-font-weight)}.g-table__body .g-table__row_interactive:hover{background-color:var(--g-color-base-simple-hover-solid);cursor:pointer}.g-table__body .g-table__row_interactive:hover .g-table__cell_sticky_end,.g-table__body .g-table__row_interactive:hover .g-table__cell_sticky_start{background:var(--g-color-base-simple-hover-solid)}.g-table__body .g-table__row_disabled{opacity:.3}.g-table_with-primary .g-table__body .g-table__cell{color:var(--g-color-text-secondary)}.g-table_with-primary .g-table__body .g-table__cell_primary{color:var(--g-color-text-primary)}.g-table_with-sticky-scroll{overflow:visible}.g-date-relative-range-date-picker-presets{--g-list-item-padding:0 var(--_--g-date-picker-presets-padding,0)}.g-date-relative-range-date-picker-presets__tabs{--g-tabs-border-width:0;align-items:center;box-shadow:inset 0 -1px var(--g-color-line-generic);display:flex;gap:var(--g-spacing-2);padding-inline:var(--_--g-date-picker-presets-padding,0)}.g-date-relative-range-date-picker-presets__list-container{outline:none}.g-date-relative-range-date-picker-presets__doc{margin-inline-start:auto}.g-date-relative-range-date-picker-presets__content{height:128px;overflow:auto}.g-date-relative-range-date-picker-presets_size_l .g-date-relative-range-date-picker-presets__content{height:144px}.g-date-relative-range-date-picker-presets_size_xl .g-date-relative-range-date-picker-presets__content{font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);height:162px;line-height:var(--g-text-body-2-line-height)}.g-date-relative-range-date-picker-zones__control{--g-button-background-color-hover:#0000}.g-date-relative-range-date-picker-dialog__content{--_--popup-content-padding:var(--g-spacing-2);--_--g-date-picker-presets-padding:var(--_--popup-content-padding);padding:var(--_--popup-content-padding)}.g-date-relative-range-date-picker-dialog__content_mobile{--_--popup-content-padding:var(--g-spacing-5)}.g-date-relative-range-date-picker-dialog__content:not(.g-date-relative-range-date-picker-dialog__content_mobile){width:310px}.g-date-relative-range-date-picker-dialog__content_size_xl:not(.g-date-relative-range-date-picker-dialog__content_mobile){width:380px}.g-date-relative-range-date-picker-dialog__pickers{display:flex;flex-direction:column;gap:var(--g-spacing-2)}.g-date-relative-range-date-picker-dialog__pickers .g-text-input__label{width:40px}.g-date-relative-range-date-picker-dialog__content_size_xl .g-date-relative-range-date-picker-dialog__pickers .g-text-input__label{width:50px}.g-date-relative-range-date-picker-dialog__apply{margin-block-start:var(--g-spacing-2)}.g-date-relative-range-date-picker-dialog__zone{border-block-start:1px solid var(--g-color-line-generic);margin-block:var(--g-spacing-2) calc(var(--_--popup-content-padding)*-1)}.g-date-relative-range-date-picker-dialog__presets,.g-date-relative-range-date-picker-dialog__zone{margin-inline:calc(var(--_--popup-content-padding)*-1)}.g-date-mobile-calendar{border:none;box-sizing:border-box;cursor:pointer;height:100%;inset-block-start:0;inset-inline-start:0;margin:0;min-width:100%;opacity:0;padding:0;position:absolute;z-index:1}.g-date-mobile-calendar::-webkit-calendar-picker-indicator{cursor:pointer;height:100%;inset-block-start:0;inset-inline-start:0;margin:0;min-width:100%;padding:0;position:absolute}.g-date-stub-button{display:inline-block;height:24px;position:relative;width:24px}.g-date-stub-button_size_xs{height:20px;width:20px}.g-date-stub-button_size_m{height:28px;width:28px}.g-date-stub-button_size_l{height:36px;width:36px}.g-date-stub-button__icon{align-items:center;color:var(--g-color-text-secondary);display:flex;inset:0;justify-content:center;position:absolute}.g-date-relative-date-picker{display:inline-flex;outline:none;position:relative}.g-date-relative-date-picker__input_mobile{pointer-events:none}.g-date-relative-date-picker__field{width:100%}.g-date-relative-date-picker__popup-content{outline:none}.g-date-relative-date-picker__time-field{width:100%}.g-date-relative-date-picker__time-field-wrapper{padding:10px}.g-date-calendar{--_--calendar-padding:var(--g-date-calendar-padding,8px);--_--calendar-day-size:var(--g-date-calendar-day-size,28px);--_--calendar-days-gap:var(--g-date-calendar-days-gap,2px);--_--calendar-width:calc(var(--_--calendar-day-size)*7 + var(--_--calendar-days-gap)*6 + var(--_--calendar-padding)*2);--_--calendar-grid-height:calc(var(--_--calendar-day-size)*7 + var(--_--calendar-days-gap)*5 + var(--_--calendar-padding));display:inline-block;width:var(--_--calendar-width)}.g-date-calendar_size_l{--g-date-calendar-day-size:36px}.g-date-calendar_size_xl{--g-date-calendar-day-size:42px;font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-date-calendar__header{display:flex;padding:var(--_--calendar-padding) var(--_--calendar-padding) 0}.g-date-calendar__years-label{color:var(--g-color-text-secondary)}.g-date-calendar__controls{margin-inline-start:auto}.g-date-calendar__control-icon{transform:scaleX(var(--g-flow-direction))}.g-date-calendar__grid{height:var(--_--calendar-grid-height);overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;width:100%}.g-date-calendar__content{box-sizing:border-box;display:grid;grid-template-rows:var(--_--calendar-day-size) 1fr;height:100%;inset-block-start:0;inset-inline-start:0;padding:0 var(--_--calendar-padding) var(--_--calendar-padding);position:absolute;width:100%}@keyframes calendar-forward{0%{transform:translateX(0)}to{transform:translateX(100%)}}@keyframes calendar-backward{0%{transform:translateX(0)}to{transform:translateX(-100%)}}@keyframes calendar-zoom-in-showing{0%{opacity:0;transform:scale(2)}to{opacity:1;transform:scale(1)}}@keyframes calendar-zoom-in-hiding{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(0)}}@keyframes calendar-zoom-out-showing{0%{opacity:0;transform:scale(0)}to{opacity:1;transform:scale(1)}}@keyframes calendar-zoom-out-hiding{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(2)}}.g-date-calendar__content_animation_forward{animation:calendar-forward .25s ease forwards;transform:translateX(-100%)}.g-date-calendar__content_animation_forward.g-date-calendar__current-state{inset-inline-start:calc(var(--g-flow-direction)*-100%)}.g-date-calendar__content_animation_backward{animation:calendar-backward .25s ease forwards;transform:translateX(0)}.g-date-calendar__content_animation_backward.g-date-calendar__current-state{inset-inline-start:calc(var(--g-flow-direction)*100%)}.g-date-calendar__content_animation_zoom-in{transform:scale()}.g-date-calendar__content_animation_zoom-in.g-date-calendar__previous-state{animation:calendar-zoom-in-hiding .25s ease forwards}.g-date-calendar__content_animation_zoom-in.g-date-calendar__current-state{animation:calendar-zoom-in-showing .25s ease forwards}.g-date-calendar__content_animation_zoom-out{transform:scale()}.g-date-calendar__content_animation_zoom-out.g-date-calendar__current-state{animation:calendar-zoom-out-showing .25s ease forwards}.g-date-calendar__content_animation_zoom-out.g-date-calendar__previous-state{animation:calendar-zoom-out-hiding .25s ease forwards}@media (update:slow),screen and (prefers-reduced-motion:reduce){.g-date-calendar__content[class]{animation-duration:.001ms}}.g-date-calendar__grid-rowgroup{display:grid;gap:var(--_--calendar-days-gap)}.g-date-calendar__grid-rowgroup_mode_months,.g-date-calendar__grid-rowgroup_mode_quarters,.g-date-calendar__grid-rowgroup_mode_years{grid-row:1/-1;padding:12px 0 0}.g-date-calendar__grid-rowgroup-header{align-self:center}.g-date-calendar__grid-row{display:grid;gap:var(--_--calendar-days-gap);grid-auto-columns:1fr;grid-auto-flow:column}.g-date-calendar__weekday{align-items:center;display:flex;height:100%;justify-content:center;width:100%}.g-date-calendar__weekday_weekend{color:var(--g-color-text-danger)}.g-date-calendar__button{align-items:center;border-radius:4px;cursor:pointer;display:flex;font-weight:var(--g-text-subheader-font-weight);height:100%;justify-content:center;outline:none;position:relative;width:100%}.g-date-calendar__button:focus{box-shadow:0 0 0 2px var(--g-color-line-misc)}.g-date-calendar__button:focus:not(:focus-visible){box-shadow:none}.g-date-calendar__button:hover{background-color:var(--g-color-base-generic)}.g-date-calendar__button_selected[class]{background-color:var(--g-color-base-selection)}.g-date-calendar__button_selected.g-date-calendar__button_selection-end,.g-date-calendar__button_selected.g-date-calendar__button_selection-start{background-color:var(--g-color-base-brand)}.g-date-calendar__button_weekend{color:var(--g-color-text-danger)}.g-date-calendar__button_out-of-boundary{font-weight:var(--g-text-body-font-weight);opacity:.6}.g-date-calendar__button_current:before{background-color:currentColor;border-radius:50%;content:"";display:block;height:4px;inset-block-start:50%;position:absolute;transform:translateY(8px);width:4px}.g-date-calendar__button_disabled{font-weight:var(--g-text-body-font-weight);opacity:.6;pointer-events:none}.g-date-calendar__button_unavailable:not(.g-date-calendar__button_disabled){background-color:var(--g-color-base-generic);cursor:default;font-weight:var(--g-text-body-font-weight);opacity:.5}.g-date-date-field{display:inline-block;width:auto}.g-date-relative-range-date-picker{display:inline-flex;position:relative}.g-date-relative-range-date-picker__value-label{display:flex;width:100%}.g-date-relative-range-date-picker__value-label>div{flex:1 0}.g-date-relative-range-date-picker__value-label-content{display:flex;flex-direction:column}.g-date-relative-range-date-picker__value-label-tooltip{--g-popover-max-width:"none"}.g-date-relative-range-date-picker__value-label-item,.g-date-relative-range-date-picker__value-label-to,.g-date-relative-range-date-picker__value-label-tz{text-align:center}.g-date-relative-range-date-picker__value-label-tz{color:var(--g-color-text-hint);margin-block-start:5px}.g-tooltip[class]{--g-popup-border-width:0}.g-tooltip[class]>div{animation-duration:1ms;box-shadow:0 1px 5px 0 #00000026;box-sizing:border-box;max-width:360px;padding:4px 8px}.g-tooltip__content{-webkit-box-orient:vertical;-ms-box-orient:vertical;-webkit-line-clamp:20;-moz-line-clamp:20;-ms-line-clamp:20;display:-webkit-box;overflow:hidden;text-overflow:ellipsis}.g-spin{animation:g-spin 1s linear infinite;backface-visibility:hidden;display:inline-block}.g-spin__inner{border:2px solid var(--g-color-line-brand);border-end-end-radius:25px;border-inline-start:none;border-start-end-radius:25px;box-sizing:border-box;height:100%;margin-inline-start:50%;width:50%}.g-spin_size_xs{height:16px;width:16px}.g-spin_size_s{height:24px;width:24px}.g-spin_size_m{height:28px;width:28px}.g-spin_size_l{height:32px;width:32px}.g-spin_size_xl{height:36px;width:36px}@keyframes g-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.g-alert_corners_square{--g-card-border-radius:0}.g-alert__text-content{width:100%}.g-alert__actions_minContent{width:min-content}.g-alert__close-btn{flex-shrink:0}.monaco-editor .rendered-markdown kbd{border-bottom-color:var(--vscode-keybindingLabel-bottomBorder);border-width:1px}@font-face{font-display:block;font-family:codicon;src:url(../../static/media/codicon.f6283f7ccaed1249d9eb.ttf) format("truetype")}.context-view-block,.context-view-pointerBlock{cursor:auto;height:100%;left:0;position:fixed;top:0;width:100%}.action-widget .monaco-list-row.action .monaco-keybinding>.monaco-keybinding-key{border-bottom-color:var(--vscode-keybindingLabel-bottomBorder);border-width:1px}.monaco-editor,.monaco-editor-background{background-color:var(--vscode-editor-background)}.monaco-editor .margin-view-overlays .current-line,.monaco-editor .view-overlays .current-line{box-sizing:border-box;display:block;height:100%;left:0;position:absolute;top:0}.monaco-editor .mtkw,.monaco-editor .mtkz{color:var(--vscode-editorWhitespace-foreground)!important}.monaco-editor .minimap.slider-mouseover .minimap-slider.active,.monaco-editor .minimap.slider-mouseover:hover .minimap-slider{opacity:1}.monaco-editor .codelens-decoration>a:hover,.monaco-editor .codelens-decoration>a:hover .codicon{color:var(--vscode-editorLink-activeForeground)!important}.colorpicker-body .hue-strip{background:linear-gradient(180deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.monaco-editor .inlineSuggestionsHints a,.monaco-editor .inlineSuggestionsHints a:hover{color:var(--vscode-foreground)}.monaco-hover ol,.monaco-hover ul{padding-left:20px}.monaco-editor .peekview-widget .head .peekview-title .dirname,.monaco-editor .peekview-widget .head .peekview-title .filename,.monaco-editor .peekview-widget .head .peekview-title .meta{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hc-black .monaco-custom-toggle,.hc-black .monaco-custom-toggle:hover,.hc-light .monaco-custom-toggle,.hc-light .monaco-custom-toggle:hover{background:none}.monaco-editor .movedModified,.monaco-editor .movedOriginal{border:2px solid var(--vscode-diffEditor-move-border)}.monaco-scrollable-element.modified-in-monaco-diff-editor.vs .scrollbar,.monaco-scrollable-element.modified-in-monaco-diff-editor.vs-dark .scrollbar{background:#0000}.modified-in-monaco-diff-editor.hc-black .slider.active,.modified-in-monaco-diff-editor.hc-light .slider.active,.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-black .scrollbar,.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-light .scrollbar{background:none}.monaco-editor .inline-added-margin-view-zone,.monaco-editor .inline-deleted-margin-view-zone{text-align:right}.monaco-diff-editor .gutter{&>div{position:absolute}.gutterItem{opacity:0;transition:opacity .7s;&.showAlways{opacity:1}&.noTransition,&.showAlways{transition:none}}&:hover .gutterItem{opacity:1;transition:opacity .1s ease-in-out}.gutterItem{.background{border-left:2px solid var(--vscode-menu-border);height:100%;left:50%;position:absolute;width:1px}.buttons{align-items:center;display:flex;justify-content:center;position:absolute;width:100%;.monaco-toolbar{height:fit-content;.monaco-action-bar{line-height:1;.actions-container{background:var(--vscode-editorGutter-commentRangeForeground);border-radius:4px;width:fit-content;.action-item{&:hover{background:var(--vscode-toolbar-hoverBackground)}.action-label{padding:1px 2px}}}}}}}}.monaco-diff-editor .diff-hidden-lines-compact{.line-left,.line-right{border-top:1px solid;border-color:var(--vscode-editorCodeLens-foreground);height:1px;margin:auto;opacity:.5;width:100%}.line-left{width:20px}.text{text-wrap:nowrap;color:var(--vscode-editorCodeLens-foreground);font-size:11px;line-height:11px;margin:0 4px}}.monaco-editor .find-widget,.monaco-editor .findOptionsWidget{background-color:var(--vscode-editorWidget-background);box-shadow:0 0 8px 2px var(--vscode-widget-shadow);color:var(--vscode-editorWidget-foreground)}.monaco-editor .find-widget>.find-part .find-actions,.monaco-editor .find-widget>.replace-part .replace-actions{align-items:center;display:flex;height:25px}.monaco-editor .iPadShowKeyboard{background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTMiIGhlaWdodD0iMzYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTQ4LjAzNiA0LjAxSDQuMDA4VjMyLjAzaDQ0LjAyOFY0LjAxWk00LjAwOC4wMDhBNC4wMDMgNC4wMDMgMCAwIDAgLjAwNSA0LjAxVjMyLjAzYTQuMDAzIDQuMDAzIDAgMCAwIDQuMDAzIDQuMDAyaDQ0LjAyOGE0LjAwMyA0LjAwMyAwIDAgMCA0LjAwMy00LjAwMlY0LjAxQTQuMDAzIDQuMDAzIDAgMCAwIDQ4LjAzNi4wMDhINC4wMDhaTTguMDEgOC4wMTNoNC4wMDN2NC4wMDNIOC4wMVY4LjAxM1ptMTIuMDA4IDBoLTQuMDAydjQuMDAzaDQuMDAyVjguMDEzWm00LjAwMyAwaDQuMDAydjQuMDAzaC00LjAwMlY4LjAxM1ptMTIuMDA4IDBoLTQuMDAzdjQuMDAzaDQuMDAzVjguMDEzWm00LjAwMiAwaDQuMDAzdjQuMDAzSDQwLjAzVjguMDEzWm0tMjQuMDE1IDguMDA1SDguMDF2NC4wMDNoOC4wMDZ2LTQuMDAzWm00LjAwMiAwaDQuMDAzdjQuMDAzaC00LjAwM3YtNC4wMDNabTEyLjAwOCAwaC00LjAwM3Y0LjAwM2g0LjAwM3YtNC4wMDNabTEyLjAwOCAwdjQuMDAzaC04LjAwNXYtNC4wMDNoOC4wMDVabS0zMi4wMjEgOC4wMDVIOC4wMXY0LjAwM2g0LjAwM3YtNC4wMDNabTQuMDAzIDBoMjAuMDEzdjQuMDAzSDE2LjAxNnYtNC4wMDNabTI4LjAxOCAwSDQwLjAzdjQuMDAzaDQuMDAzdi00LjAwM1oiIGZpbGw9IiM0MjQyNDIiLz48L2c+PGRlZnM+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMCAwaDUzdjM2SDB6Ii8+PC9jbGlwUGF0aD48L2RlZnM+PC9zdmc+) 50% no-repeat}.monaco-editor.vs-dark .iPadShowKeyboard{background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTMiIGhlaWdodD0iMzYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTQ4LjAzNiA0LjAxSDQuMDA4VjMyLjAzaDQ0LjAyOFY0LjAxWk00LjAwOC4wMDhBNC4wMDMgNC4wMDMgMCAwIDAgLjAwNSA0LjAxVjMyLjAzYTQuMDAzIDQuMDAzIDAgMCAwIDQuMDAzIDQuMDAyaDQ0LjAyOGE0LjAwMyA0LjAwMyAwIDAgMCA0LjAwMy00LjAwMlY0LjAxQTQuMDAzIDQuMDAzIDAgMCAwIDQ4LjAzNi4wMDhINC4wMDhaTTguMDEgOC4wMTNoNC4wMDN2NC4wMDNIOC4wMVY4LjAxM1ptMTIuMDA4IDBoLTQuMDAydjQuMDAzaDQuMDAyVjguMDEzWm00LjAwMyAwaDQuMDAydjQuMDAzaC00LjAwMlY4LjAxM1ptMTIuMDA4IDBoLTQuMDAzdjQuMDAzaDQuMDAzVjguMDEzWm00LjAwMiAwaDQuMDAzdjQuMDAzSDQwLjAzVjguMDEzWm0tMjQuMDE1IDguMDA1SDguMDF2NC4wMDNoOC4wMDZ2LTQuMDAzWm00LjAwMiAwaDQuMDAzdjQuMDAzaC00LjAwM3YtNC4wMDNabTEyLjAwOCAwaC00LjAwM3Y0LjAwM2g0LjAwM3YtNC4wMDNabTEyLjAwOCAwdjQuMDAzaC04LjAwNXYtNC4wMDNoOC4wMDVabS0zMi4wMjEgOC4wMDVIOC4wMXY0LjAwM2g0LjAwM3YtNC4wMDNabTQuMDAzIDBoMjAuMDEzdjQuMDAzSDE2LjAxNnYtNC4wMDNabTI4LjAxOCAwSDQwLjAzdjQuMDAzaDQuMDAzdi00LjAwM1oiIGZpbGw9IiNDNUM1QzUiLz48L2c+PGRlZnM+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMCAwaDUzdjM2SDB6Ii8+PC9jbGlwUGF0aD48L2RlZnM+PC9zdmc+) 50% no-repeat}.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.right>.details-label,.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label)>.contents>.main>.right>.details-label,.monaco-editor .suggest-widget:not(.shows-details) .monaco-list .monaco-list-row.focused>.contents>.main>.right>.details-label{display:inline}.monaco-editor .suggest-details ol,.monaco-editor .suggest-details ul{padding-left:20px}.monaco-editor .inlineEditHints a,.monaco-editor .inlineEditHints a:hover{color:var(--vscode-foreground)}.monaco-editor div.inline-edits-widget{.promptEditor .monaco-editor{--vscode-editor-placeholder-foreground:var(--vscode-editorGhostText-foreground)}.promptEditor,.toolbar{opacity:0;transition:opacity .2s ease-in-out}&.focused,&:hover{.promptEditor,.toolbar{opacity:1}}.preview .monaco-editor{--vscode-editor-background:var(--widget-color);.mtk1{color:var(--vscode-editorGhostText-foreground)}.current-line-margin,.view-overlays .current-line-exact{border:none}}svg{.gradient-start{stop-color:var(--vscode-editor-background)}.gradient-stop{stop-color:var(--widget-color)}}}.monaco-editor{.editorPlaceholder{text-wrap:nowrap;color:var(--vscode-editor-placeholder-foreground);overflow:hidden;pointer-events:none;position:absolute;text-overflow:ellipsis;top:0}}.monaco-editor.hc-black .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-editor.hc-light .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-editor.vs-dark .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-menu .monaco-action-bar.vertical .action-item .action-menu-item:focus .action-label{stroke-width:1.2px}.monaco-diff-editor .synthetic-focus,.monaco-diff-editor [tabindex="-1"]:focus,.monaco-diff-editor [tabindex="0"]:focus,.monaco-diff-editor button:focus,.monaco-diff-editor input[type=button]:focus,.monaco-diff-editor input[type=checkbox]:focus,.monaco-diff-editor input[type=search]:focus,.monaco-diff-editor input[type=text]:focus,.monaco-diff-editor select:focus,.monaco-diff-editor textarea:focus,.monaco-editor{opacity:1;outline-color:var(--vscode-focusBorder);outline-offset:-1px;outline-style:solid;outline-width:1px}.quick-input-widget .monaco-highlighted-label .highlight{color:#0066bf}.vs .quick-input-widget .monaco-list-row.focused .monaco-highlighted-label .highlight{color:#9dddff}.vs-dark .quick-input-widget .monaco-highlighted-label .highlight{color:#0097fb}.hc-black .quick-input-widget .monaco-highlighted-label .highlight{color:#f38518}.hc-light .quick-input-widget .monaco-highlighted-label .highlight{color:#0f4a85}.monaco-keybinding>.monaco-keybinding-key{background-color:#ddd6;border-color:#ccc6 #ccc6 #bbb6;box-shadow:inset 0 -1px 0 #bbb6}.monaco-component.multiDiffEditor{>div{height:100%;left:0;position:absolute;top:0;width:100%;&.placeholder{display:grid;place-content:center;place-items:center;visibility:hidden;&.visible{visibility:visible}}}.active{--vscode-multiDiffEditor-border:var(--vscode-focusBorder)}.multiDiffEntry{display:flex;flex:1 1;flex-direction:column;overflow:hidden;.collapse-button{cursor:pointer;margin:0 5px;a{display:block}}.header{background:var(--vscode-editor-background);z-index:1000;&:not(.collapsed) .header-content{border-bottom:1px solid var(--vscode-sideBarSectionHeader-border)}.header-content{align-items:center;background:var(--vscode-multiDiffEditor-headerBackground);border-top:1px solid var(--vscode-multiDiffEditor-border);color:var(--vscode-foreground);display:flex;margin:8px 0 0;padding:4px 5px;&.shadow{box-shadow:var(--vscode-scrollbar-shadow) 0 6px 6px -6px}.file-path{display:flex;flex:1 1;min-width:0;.title{font-size:14px;line-height:22px;&.original{flex:1 1;min-width:0;text-overflow:ellipsis}}.status{font-weight:600;line-height:22px;margin:0 10px;opacity:.75}}.actions{padding:0 8px}}}.editorParent{border-bottom:1px solid var(--vscode-multiDiffEditor-border);display:flex;flex:1 1;flex-direction:column;overflow:hidden}.editorContainer{flex:1 1}}}.gt-table{border:none;border-collapse:initial;border-spacing:0}.gt-table__row_interactive{cursor:pointer}.gt-table__header_sticky{inset-block-start:0;position:sticky;z-index:1}.gt-table__footer_sticky{inset-block-end:0;position:sticky;z-index:1}.gt-table__cell{font-weight:400}.gt-table__footer-cell,.gt-table__header-cell{font-weight:500;position:relative}.gt-table__cell,.gt-table__footer-cell,.gt-table__header-cell{box-sizing:border-box;height:inherit;padding:0;text-align:start}.gt-table__cell_pinned,.gt-table__footer-cell_pinned,.gt-table__header-cell_pinned{position:sticky;z-index:1}.gt-table__sort{cursor:pointer;-webkit-user-select:none;user-select:none}.gt-table_with-row-virtualization{display:grid;height:auto}.gt-table_with-row-virtualization .gt-table__body{display:grid;position:relative}.gt-table_with-row-virtualization .gt-table__footer,.gt-table_with-row-virtualization .gt-table__header{display:grid}.gt-table_with-row-virtualization .gt-table__footer-row,.gt-table_with-row-virtualization .gt-table__header-row{display:flex;height:auto}.gt-table_with-row-virtualization .gt-table__row{display:flex;height:auto;position:absolute}.gt-table_with-row-virtualization .gt-table__row_empty{position:relative}.gt-group-header{inset-inline-start:0;margin:0;position:sticky}.gt-group-header__button{appearance:none;background:inherit;border:none;cursor:pointer;display:flex;gap:8px;outline:none;padding:0;width:100%}.gt-group-header__icon{display:inline-block;transform:rotate(-90deg);transition:transform .1s ease-out;vertical-align:middle}.gt-group-header__icon_expanded{transform:rotate(0)}.gt-group-header__content{display:inline-flex;font-weight:500;gap:4px}.gt-sort-indicator{color:var(--g-color-text-hint);display:inline-flex;margin-inline-start:4px;transform:rotate(0);vertical-align:middle}.gt-sort-indicator_invisible{opacity:0}.gt-table__header-cell:hover .gt-sort-indicator_invisible{opacity:1}.gt-sort-indicator_order_asc{transform:rotate(180deg)}.gt-resize-handle{background:#d3d3d3;cursor:col-resize;height:100%;inset-block-start:0;opacity:0;position:absolute;touch-action:none;-webkit-user-select:none;user-select:none;width:6px}.gt-resize-handle_direction_ltr{inset-inline-end:0}.gt-resize-handle_direction_rtl{inset-inline-start:0}.gt-resize-handle_resizing,.gt-table__header-cell:hover .gt-resize-handle{opacity:1} +/*!----------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1) + * Released under the MIT license + * https://github.com/microsoft/vscode/blob/main/LICENSE.txt + *-----------------------------------------------------------*/.monaco-action-bar{height:100%;white-space:nowrap}.monaco-action-bar .actions-container{align-items:center;display:flex;height:100%;margin:0 auto;padding:0;width:100%}.monaco-action-bar.vertical .actions-container{display:inline-block}.monaco-action-bar .action-item{align-items:center;cursor:pointer;display:block;justify-content:center;position:relative}.monaco-action-bar .action-item.disabled{cursor:default}.monaco-action-bar .action-item .codicon,.monaco-action-bar .action-item .icon{display:block}.monaco-action-bar .action-item .codicon{align-items:center;display:flex;height:16px;width:16px}.monaco-action-bar .action-label{border-radius:5px;display:flex;font-size:11px;padding:3px}.monaco-action-bar .action-item.disabled .action-label,.monaco-action-bar .action-item.disabled .action-label:before,.monaco-action-bar .action-item.disabled .action-label:hover{color:var(--vscode-disabledForeground)}.monaco-action-bar.vertical{text-align:left}.monaco-action-bar.vertical .action-item{display:block}.monaco-action-bar.vertical .action-label.separator{border-bottom:1px solid #bbb;display:block;margin-left:.8em;margin-right:.8em;padding-top:1px}.monaco-action-bar .action-item .action-label.separator{background-color:#bbb;cursor:default;height:16px;margin:5px 4px!important;min-width:1px;padding:0;width:1px}.secondary-actions .monaco-action-bar .action-label{margin-left:6px}.monaco-action-bar .action-item.select-container{align-items:center;display:flex;flex:1 1;justify-content:center;margin-right:10px;max-width:170px;min-width:60px;overflow:hidden}.monaco-action-bar .action-item.action-dropdown-item{display:flex}.monaco-action-bar .action-item.action-dropdown-item>.action-dropdown-item-separator{align-items:center;cursor:default;display:flex}.monaco-action-bar .action-item.action-dropdown-item>.action-dropdown-item-separator>div{width:1px}.monaco-aria-container{left:-999em;position:absolute}.monaco-text-button{align-items:center;border:1px solid var(--vscode-button-border,#0000);border-radius:2px;box-sizing:border-box;cursor:pointer;display:flex;justify-content:center;line-height:18px;padding:4px;text-align:center;width:100%}.monaco-text-button:focus{outline-offset:2px!important}.monaco-text-button:hover{text-decoration:none!important}.monaco-button.disabled,.monaco-button.disabled:focus{cursor:default;opacity:.4!important}.monaco-text-button .codicon{color:inherit!important;margin:0 .2em}.monaco-text-button.monaco-text-button-with-short-label{flex-direction:row;flex-wrap:wrap;height:28px;overflow:hidden;padding:0 4px}.monaco-text-button.monaco-text-button-with-short-label>.monaco-button-label{flex-basis:100%}.monaco-text-button.monaco-text-button-with-short-label>.monaco-button-label-short{flex-grow:1;overflow:hidden;width:0}.monaco-text-button.monaco-text-button-with-short-label>.monaco-button-label,.monaco-text-button.monaco-text-button-with-short-label>.monaco-button-label-short{align-items:center;display:flex;font-style:inherit;font-weight:400;justify-content:center;padding:4px 0}.monaco-button-dropdown{cursor:pointer;display:flex}.monaco-button-dropdown.disabled{cursor:default}.monaco-button-dropdown>.monaco-button:focus{outline-offset:-1px!important}.monaco-button-dropdown.disabled>.monaco-button-dropdown-separator,.monaco-button-dropdown.disabled>.monaco-button.disabled,.monaco-button-dropdown.disabled>.monaco-button.disabled:focus{opacity:.4!important}.monaco-button-dropdown>.monaco-button.monaco-text-button{border-right-width:0!important}.monaco-button-dropdown .monaco-button-dropdown-separator{cursor:default;padding:4px 0}.monaco-button-dropdown .monaco-button-dropdown-separator>div{height:100%;width:1px}.monaco-button-dropdown>.monaco-button.monaco-dropdown-button{align-items:center;border:1px solid var(--vscode-button-border,#0000);border-left-width:0!important;border-radius:0 2px 2px 0;display:flex}.monaco-button-dropdown>.monaco-button.monaco-text-button{border-radius:2px 0 0 2px}.monaco-description-button{align-items:center;display:flex;flex-direction:column;margin:4px 5px}.monaco-description-button .monaco-button-description{font-size:11px;font-style:italic;padding:4px 20px}.monaco-description-button .monaco-button-description,.monaco-description-button .monaco-button-label{align-items:center;display:flex;justify-content:center}.monaco-description-button .monaco-button-description>.codicon,.monaco-description-button .monaco-button-label>.codicon{color:inherit!important;margin:0 .2em}.monaco-button-dropdown.default-colors>.monaco-button,.monaco-button.default-colors{background-color:var(--vscode-button-background);color:var(--vscode-button-foreground)}.monaco-button-dropdown.default-colors>.monaco-button:hover,.monaco-button.default-colors:hover{background-color:var(--vscode-button-hoverBackground)}.monaco-button-dropdown.default-colors>.monaco-button.secondary,.monaco-button.default-colors.secondary{background-color:var(--vscode-button-secondaryBackground);color:var(--vscode-button-secondaryForeground)}.monaco-button-dropdown.default-colors>.monaco-button.secondary:hover,.monaco-button.default-colors.secondary:hover{background-color:var(--vscode-button-secondaryHoverBackground)}.monaco-button-dropdown.default-colors .monaco-button-dropdown-separator{background-color:var(--vscode-button-background);border-bottom:1px solid var(--vscode-button-border);border-top:1px solid var(--vscode-button-border)}.monaco-button-dropdown.default-colors .monaco-button.secondary+.monaco-button-dropdown-separator{background-color:var(--vscode-button-secondaryBackground)}.monaco-button-dropdown.default-colors .monaco-button-dropdown-separator>div{background-color:var(--vscode-button-separator)}@font-face{font-display:block;font-family:codicon;src:url(../../static/media/codicon.f6283f7ccaed1249d9eb.ttf) format("truetype")}.codicon[class*=codicon-]{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;font:normal normal normal 16px/1 codicon;text-align:center;text-decoration:none;text-rendering:auto;text-transform:none;user-select:none;-webkit-user-select:none}.codicon-wrench-subaction{opacity:.5}@keyframes codicon-spin{to{transform:rotate(1turn)}}.codicon-gear.codicon-modifier-spin,.codicon-loading.codicon-modifier-spin,.codicon-notebook-state-executing.codicon-modifier-spin,.codicon-sync.codicon-modifier-spin{animation:codicon-spin 1.5s steps(30) infinite}.codicon-modifier-disabled{opacity:.4}.codicon-loading,.codicon-tree-item-loading:before{animation-duration:1s!important;animation-timing-function:cubic-bezier(.53,.21,.29,.67)!important}.context-view{position:absolute}.context-view.fixed{all:initial;color:inherit;font-family:inherit;font-size:13px;position:fixed}.monaco-count-badge{border-radius:11px;box-sizing:border-box;display:inline-block;font-size:11px;font-weight:400;line-height:11px;min-height:18px;min-width:18px;padding:3px 6px;text-align:center}.monaco-count-badge.long{border-radius:2px;line-height:normal;min-height:auto;padding:2px 3px}.monaco-dropdown{height:100%;padding:0}.monaco-dropdown>.dropdown-label{align-items:center;cursor:pointer;display:flex;height:100%;justify-content:center}.monaco-dropdown>.dropdown-label>.action-label.disabled{cursor:default}.monaco-dropdown-with-primary{border-radius:5px;display:flex!important;flex-direction:row}.monaco-dropdown-with-primary>.action-container>.action-label{margin-right:0}.monaco-dropdown-with-primary>.dropdown-action-container>.monaco-dropdown>.dropdown-label .codicon[class*=codicon-]{font-size:12px;line-height:16px;margin-left:-3px;padding-left:0;padding-right:0}.monaco-dropdown-with-primary>.dropdown-action-container>.monaco-dropdown>.dropdown-label>.action-label{background-position:50%;background-repeat:no-repeat;background-size:16px;display:block}.monaco-findInput{position:relative}.monaco-findInput .monaco-inputbox{font-size:13px;width:100%}.monaco-findInput>.controls{position:absolute;right:2px;top:3px}.vs .monaco-findInput.disabled{background-color:#e1e1e1}.vs-dark .monaco-findInput.disabled{background-color:#333}.hc-light .monaco-findInput.highlight-0 .controls,.monaco-findInput.highlight-0 .controls{animation:monaco-findInput-highlight-0 .1s linear 0s}.hc-light .monaco-findInput.highlight-1 .controls,.monaco-findInput.highlight-1 .controls{animation:monaco-findInput-highlight-1 .1s linear 0s}.hc-black .monaco-findInput.highlight-0 .controls,.vs-dark .monaco-findInput.highlight-0 .controls{animation:monaco-findInput-highlight-dark-0 .1s linear 0s}.hc-black .monaco-findInput.highlight-1 .controls,.vs-dark .monaco-findInput.highlight-1 .controls{animation:monaco-findInput-highlight-dark-1 .1s linear 0s}@keyframes monaco-findInput-highlight-0{0%{background:#fdff00cc}to{background:#0000}}@keyframes monaco-findInput-highlight-1{0%{background:#fdff00cc}99%{background:#0000}}@keyframes monaco-findInput-highlight-dark-0{0%{background:#ffffff70}to{background:#0000}}@keyframes monaco-findInput-highlight-dark-1{0%{background:#ffffff70}99%{background:#0000}}.monaco-hover{animation:fadein .1s linear;box-sizing:border-box;cursor:default;line-height:1.5em;overflow:hidden;position:absolute;user-select:text;-webkit-user-select:text;white-space:var(--vscode-hover-whiteSpace,normal)}.monaco-hover.hidden{display:none}.monaco-hover a:hover:not(.disabled){cursor:pointer}.monaco-hover .hover-contents:not(.html-hover-contents){padding:4px 8px}.monaco-hover .markdown-hover>.hover-contents:not(.code-hover-contents){word-wrap:break-word;max-width:var(--vscode-hover-maxWidth,500px)}.monaco-hover .markdown-hover>.hover-contents:not(.code-hover-contents) hr{min-width:100%}.monaco-hover .code,.monaco-hover h1,.monaco-hover h2,.monaco-hover h3,.monaco-hover h4,.monaco-hover h5,.monaco-hover h6,.monaco-hover p,.monaco-hover ul{margin:8px 0}.monaco-hover h1,.monaco-hover h2,.monaco-hover h3,.monaco-hover h4,.monaco-hover h5,.monaco-hover h6{line-height:1.1}.monaco-hover code{font-family:var(--monaco-monospace-font)}.monaco-hover hr{border-left:0;border-right:0;box-sizing:border-box;height:1px;margin:4px -8px -4px}.monaco-hover .code:first-child,.monaco-hover p:first-child,.monaco-hover ul:first-child{margin-top:0}.monaco-hover .code:last-child,.monaco-hover p:last-child,.monaco-hover ul:last-child{margin-bottom:0}.monaco-hover ol,.monaco-hover ul{padding-left:20px}.monaco-hover li>p{margin-bottom:0}.monaco-hover li>ul{margin-top:0}.monaco-hover code{border-radius:3px;padding:0 .4em}.monaco-hover .monaco-tokenized-source{white-space:var(--vscode-hover-sourceWhiteSpace,pre-wrap)}.monaco-hover .hover-row.status-bar{font-size:12px;line-height:22px}.monaco-hover .hover-row.status-bar .info{font-style:italic;padding:0 8px}.monaco-hover .hover-row.status-bar .actions{display:flex;padding:0 8px;width:100%}.monaco-hover .hover-row.status-bar .actions .action-container{cursor:pointer;margin-right:16px}.monaco-hover .hover-row.status-bar .actions .action-container .action .icon{padding-right:4px}.monaco-hover .hover-row.status-bar .actions .action-container a{color:var(--vscode-textLink-foreground);-webkit-text-decoration:var(--text-link-decoration);text-decoration:var(--text-link-decoration)}.monaco-hover .markdown-hover .hover-contents .codicon{color:inherit;font-size:inherit;vertical-align:middle}.monaco-hover .hover-contents a.code-link,.monaco-hover .hover-contents a.code-link:hover{color:inherit}.monaco-hover .hover-contents a.code-link:before{content:"("}.monaco-hover .hover-contents a.code-link:after{content:")"}.monaco-hover .hover-contents a.code-link>span{border-bottom:1px solid #0000;color:var(--vscode-textLink-foreground);text-decoration:underline;text-underline-position:under}.monaco-hover .hover-contents a.code-link>span:hover{color:var(--vscode-textLink-activeForeground)}.monaco-hover .markdown-hover .hover-contents:not(.code-hover-contents):not(.html-hover-contents) span{display:inline-block;margin-bottom:4px}.monaco-hover .markdown-hover .hover-contents:not(.code-hover-contents):not(.html-hover-contents) span.codicon{margin-bottom:2px}.monaco-hover-content .action-container a{-webkit-user-select:none;user-select:none}.monaco-hover-content .action-container.disabled{cursor:default;opacity:.4;pointer-events:none}.monaco-icon-label{display:flex;overflow:hidden;text-overflow:ellipsis}.monaco-icon-label:before{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-position:0;background-repeat:no-repeat;background-size:16px;display:inline-block;flex-shrink:0;height:22px;line-height:inherit!important;padding-right:6px;vertical-align:top;width:16px}.monaco-icon-label-iconpath{display:flex;height:16px;margin-top:2px;padding-left:2px;width:16px}.monaco-icon-label-container.disabled{color:var(--vscode-disabledForeground)}.monaco-icon-label>.monaco-icon-label-container{flex:1 1;min-width:0;overflow:hidden;text-overflow:ellipsis}.monaco-icon-label>.monaco-icon-label-container>.monaco-icon-name-container>.label-name{color:inherit;white-space:pre}.monaco-icon-label>.monaco-icon-label-container>.monaco-icon-name-container>.label-name>.label-separator{margin:0 2px;opacity:.5}.monaco-icon-label>.monaco-icon-label-container>.monaco-icon-suffix-container>.label-suffix{opacity:.7;white-space:pre}.monaco-icon-label>.monaco-icon-label-container>.monaco-icon-description-container>.label-description{font-size:.9em;margin-left:.5em;opacity:.7;white-space:pre}.monaco-icon-label.nowrap>.monaco-icon-label-container>.monaco-icon-description-container>.label-description{white-space:nowrap}.vs .monaco-icon-label>.monaco-icon-label-container>.monaco-icon-description-container>.label-description{opacity:.95}.monaco-icon-label.italic>.monaco-icon-label-container>.monaco-icon-description-container>.label-description,.monaco-icon-label.italic>.monaco-icon-label-container>.monaco-icon-name-container>.label-name{font-style:italic}.monaco-icon-label.deprecated{opacity:.66;text-decoration:line-through}.monaco-icon-label.italic:after{font-style:italic}.monaco-icon-label.strikethrough>.monaco-icon-label-container>.monaco-icon-description-container>.label-description,.monaco-icon-label.strikethrough>.monaco-icon-label-container>.monaco-icon-name-container>.label-name{text-decoration:line-through}.monaco-icon-label:after{font-size:90%;font-weight:600;margin:auto 16px 0 5px;opacity:.75;text-align:center}.monaco-list:focus .selected .monaco-icon-label,.monaco-list:focus .selected .monaco-icon-label:after{color:inherit!important}.monaco-list-row.focused.selected .label-description,.monaco-list-row.selected .label-description{opacity:.8}.monaco-inputbox{border-radius:2px;box-sizing:border-box;display:block;font-size:inherit;padding:0;position:relative}.monaco-inputbox>.ibwrapper>.input,.monaco-inputbox>.ibwrapper>.mirror{padding:4px 6px}.monaco-inputbox>.ibwrapper{height:100%;position:relative;width:100%}.monaco-inputbox>.ibwrapper>.input{border:none;box-sizing:border-box;color:inherit;display:inline-block;font-family:inherit;font-size:inherit;height:100%;line-height:inherit;resize:none;width:100%}.monaco-inputbox>.ibwrapper>input{text-overflow:ellipsis}.monaco-inputbox>.ibwrapper>textarea.input{display:block;outline:none;scrollbar-width:none}.monaco-inputbox>.ibwrapper>textarea.input::-webkit-scrollbar{display:none}.monaco-inputbox>.ibwrapper>textarea.input.empty{white-space:nowrap}.monaco-inputbox>.ibwrapper>.mirror{word-wrap:break-word;box-sizing:border-box;display:inline-block;left:0;position:absolute;top:0;visibility:hidden;white-space:pre-wrap;width:100%}.monaco-inputbox-container{text-align:right}.monaco-inputbox-container .monaco-inputbox-message{word-wrap:break-word;box-sizing:border-box;display:inline-block;font-size:12px;line-height:17px;margin-top:-1px;overflow:hidden;padding:.4em;text-align:left;width:100%}.monaco-inputbox .monaco-action-bar{position:absolute;right:2px;top:4px}.monaco-inputbox .monaco-action-bar .action-item{margin-left:2px}.monaco-inputbox .monaco-action-bar .action-item .codicon{background-repeat:no-repeat;height:16px;width:16px}.monaco-keybinding{align-items:center;display:flex;line-height:10px}.monaco-keybinding>.monaco-keybinding-key{border-radius:3px;border-style:solid;border-width:1px;display:inline-block;font-size:11px;margin:0 2px;padding:3px 5px;vertical-align:middle}.monaco-keybinding>.monaco-keybinding-key:first-child{margin-left:0}.monaco-keybinding>.monaco-keybinding-key:last-child{margin-right:0}.monaco-keybinding>.monaco-keybinding-key-separator{display:inline-block}.monaco-keybinding>.monaco-keybinding-key-chord-separator{width:6px}.monaco-list{height:100%;position:relative;white-space:nowrap;width:100%}.monaco-list.mouse-support{user-select:none;-webkit-user-select:none}.monaco-list>.monaco-scrollable-element{height:100%}.monaco-list-rows{height:100%;position:relative;width:100%}.monaco-list.horizontal-scrolling .monaco-list-rows{min-width:100%;width:auto}.monaco-list-row{box-sizing:border-box;overflow:hidden;position:absolute;width:100%}.monaco-list.mouse-support .monaco-list-row{cursor:pointer;touch-action:none}.monaco-list .monaco-scrollable-element>.scrollbar.vertical,.monaco-pane-view>.monaco-split-view2.vertical>.monaco-scrollable-element>.scrollbar.vertical{z-index:14}.monaco-list-row.scrolling{display:none!important}.monaco-list.element-focused,.monaco-list.selection-multiple,.monaco-list.selection-single{outline:0!important}.monaco-drag-image{border-radius:10px;display:inline-block;font-size:12px;padding:1px 7px;position:absolute;z-index:1000}.monaco-list-type-filter-message{box-sizing:border-box;height:100%;left:0;opacity:.7;padding:40px 1em 1em;pointer-events:none;position:absolute;text-align:center;top:0;white-space:normal;width:100%}.monaco-list-type-filter-message:empty{display:none}.monaco-mouse-cursor-text{cursor:text}.monaco-progress-container{height:2px;overflow:hidden;width:100%}.monaco-progress-container .progress-bit{display:none;height:2px;left:0;position:absolute;width:2%}.monaco-progress-container.active .progress-bit{display:inherit}.monaco-progress-container.discrete .progress-bit{left:0;transition:width .1s linear}.monaco-progress-container.discrete.done .progress-bit{width:100%}.monaco-progress-container.infinite .progress-bit{animation-duration:4s;animation-iteration-count:infinite;animation-name:progress;animation-timing-function:linear;transform:translateZ(0)}.monaco-progress-container.infinite.infinite-long-running .progress-bit{animation-timing-function:steps(100)}@keyframes progress{0%{transform:translateX(0) scaleX(1)}50%{transform:translateX(2500%) scaleX(3)}to{transform:translateX(4900%) scaleX(1)}}:root{--vscode-sash-size:4px;--vscode-sash-hover-size:4px}.monaco-sash{position:absolute;touch-action:none;z-index:35}.monaco-sash.disabled{pointer-events:none}.monaco-sash.mac.vertical{cursor:col-resize}.monaco-sash.vertical.minimum{cursor:e-resize}.monaco-sash.vertical.maximum{cursor:w-resize}.monaco-sash.mac.horizontal{cursor:row-resize}.monaco-sash.horizontal.minimum{cursor:s-resize}.monaco-sash.horizontal.maximum{cursor:n-resize}.monaco-sash.disabled{cursor:default!important;pointer-events:none!important}.monaco-sash.vertical{cursor:ew-resize;height:100%;top:0;width:var(--vscode-sash-size)}.monaco-sash.horizontal{cursor:ns-resize;height:var(--vscode-sash-size);left:0;width:100%}.monaco-sash:not(.disabled)>.orthogonal-drag-handle{content:" ";cursor:all-scroll;display:block;height:calc(var(--vscode-sash-size)*2);position:absolute;width:calc(var(--vscode-sash-size)*2);z-index:100}.monaco-sash.horizontal.orthogonal-edge-north:not(.disabled)>.orthogonal-drag-handle.start,.monaco-sash.horizontal.orthogonal-edge-south:not(.disabled)>.orthogonal-drag-handle.end{cursor:nwse-resize}.monaco-sash.horizontal.orthogonal-edge-north:not(.disabled)>.orthogonal-drag-handle.end,.monaco-sash.horizontal.orthogonal-edge-south:not(.disabled)>.orthogonal-drag-handle.start{cursor:nesw-resize}.monaco-sash.vertical>.orthogonal-drag-handle.start{left:calc(var(--vscode-sash-size)*-.5);top:calc(var(--vscode-sash-size)*-1)}.monaco-sash.vertical>.orthogonal-drag-handle.end{bottom:calc(var(--vscode-sash-size)*-1);left:calc(var(--vscode-sash-size)*-.5)}.monaco-sash.horizontal>.orthogonal-drag-handle.start{left:calc(var(--vscode-sash-size)*-1);top:calc(var(--vscode-sash-size)*-.5)}.monaco-sash.horizontal>.orthogonal-drag-handle.end{right:calc(var(--vscode-sash-size)*-1);top:calc(var(--vscode-sash-size)*-.5)}.monaco-sash:before{background:#0000;content:"";height:100%;pointer-events:none;position:absolute;width:100%}.monaco-workbench:not(.reduce-motion) .monaco-sash:before{transition:background-color .1s ease-out}.monaco-sash.active:before,.monaco-sash.hover:before{background:var(--vscode-sash-hoverBorder)}.monaco-sash.vertical:before{left:calc(50% - var(--vscode-sash-hover-size)/2);width:var(--vscode-sash-hover-size)}.monaco-sash.horizontal:before{height:var(--vscode-sash-hover-size);top:calc(50% - var(--vscode-sash-hover-size)/2)}.pointer-events-disabled{pointer-events:none!important}.monaco-sash.debug{background:cyan}.monaco-sash.debug.disabled{background:#0ff3}.monaco-sash.debug:not(.disabled)>.orthogonal-drag-handle{background:red}.monaco-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.monaco-scrollable-element>.visible{background:#0000;opacity:1;transition:opacity .1s linear;z-index:11}.monaco-scrollable-element>.invisible{opacity:0;pointer-events:none}.monaco-scrollable-element>.invisible.fade{transition:opacity .8s linear}.monaco-scrollable-element>.shadow{display:none;position:absolute}.monaco-scrollable-element>.shadow.top{box-shadow:var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset;display:block;height:3px;left:3px;top:0;width:100%}.monaco-scrollable-element>.shadow.left{box-shadow:var(--vscode-scrollbar-shadow) 6px 0 6px -6px inset;display:block;height:100%;left:0;top:3px;width:3px}.monaco-scrollable-element>.shadow.top-left-corner{display:block;height:3px;left:0;top:0;width:3px}.monaco-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow) 6px 0 6px -6px inset}.monaco-scrollable-element>.scrollbar>.slider{background:var(--vscode-scrollbarSlider-background)}.monaco-scrollable-element>.scrollbar>.slider:hover{background:var(--vscode-scrollbarSlider-hoverBackground)}.monaco-scrollable-element>.scrollbar>.slider.active{background:var(--vscode-scrollbarSlider-activeBackground)}.monaco-select-box{border-radius:2px;cursor:pointer;width:100%}.monaco-select-box-dropdown-container{font-size:13px;font-weight:400;text-transform:none}.monaco-action-bar .action-item.select-container{cursor:default}.monaco-action-bar .action-item .monaco-select-box{cursor:pointer;min-height:18px;min-width:100px;padding:2px 23px 2px 8px}.mac .monaco-action-bar .action-item .monaco-select-box{border-radius:5px;font-size:11px}.monaco-select-box-dropdown-padding{--dropdown-padding-top:1px;--dropdown-padding-bottom:1px}.hc-black .monaco-select-box-dropdown-padding,.hc-light .monaco-select-box-dropdown-padding{--dropdown-padding-top:3px;--dropdown-padding-bottom:4px}.monaco-select-box-dropdown-container{box-sizing:border-box;display:none}.monaco-select-box-dropdown-container>.select-box-details-pane>.select-box-description-markdown *{margin:0}.monaco-select-box-dropdown-container>.select-box-details-pane>.select-box-description-markdown a:focus{outline:1px solid -webkit-focus-ring-color;outline-offset:-1px}.monaco-select-box-dropdown-container>.select-box-details-pane>.select-box-description-markdown code{font-family:var(--monaco-monospace-font);line-height:15px}.monaco-select-box-dropdown-container.visible{border-bottom-left-radius:3px;border-bottom-right-radius:3px;display:flex;flex-direction:column;overflow:hidden;text-align:left;width:1px}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container{align-self:flex-start;box-sizing:border-box;flex:0 0 auto;overflow:hidden;padding-bottom:var(--dropdown-padding-bottom);padding-left:1px;padding-right:1px;padding-top:var(--dropdown-padding-top);width:100%}.monaco-select-box-dropdown-container>.select-box-details-pane{padding:5px}.hc-black .monaco-select-box-dropdown-container>.select-box-dropdown-list-container{padding-bottom:var(--dropdown-padding-bottom);padding-top:var(--dropdown-padding-top)}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row{cursor:pointer}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row>.option-text{float:left;overflow:hidden;padding-left:3.5px;text-overflow:ellipsis;white-space:nowrap}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row>.option-detail{float:left;opacity:.7;overflow:hidden;padding-left:3.5px;text-overflow:ellipsis;white-space:nowrap}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row>.option-decorator-right{float:right;overflow:hidden;padding-right:10px;text-overflow:ellipsis;white-space:nowrap}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row>.visually-hidden{height:1px;left:-10000px;overflow:hidden;position:absolute;top:auto;width:1px}.monaco-select-box-dropdown-container>.select-box-dropdown-container-width-control{align-self:flex-start;flex:1 1 auto;opacity:0}.monaco-select-box-dropdown-container>.select-box-dropdown-container-width-control>.width-control-div{max-height:0;overflow:hidden}.monaco-select-box-dropdown-container>.select-box-dropdown-container-width-control>.width-control-div>.option-text-width-control{padding-left:4px;padding-right:8px;white-space:nowrap}.monaco-split-view2{height:100%;position:relative;width:100%}.monaco-split-view2>.sash-container{height:100%;pointer-events:none;position:absolute;width:100%}.monaco-split-view2>.sash-container>.monaco-sash{pointer-events:auto}.monaco-split-view2>.monaco-scrollable-element{height:100%;width:100%}.monaco-split-view2>.monaco-scrollable-element>.split-view-container{height:100%;position:relative;white-space:nowrap;width:100%}.monaco-split-view2>.monaco-scrollable-element>.split-view-container>.split-view-view{position:absolute;white-space:normal}.monaco-split-view2>.monaco-scrollable-element>.split-view-container>.split-view-view:not(.visible){display:none}.monaco-split-view2.vertical>.monaco-scrollable-element>.split-view-container>.split-view-view{width:100%}.monaco-split-view2.horizontal>.monaco-scrollable-element>.split-view-container>.split-view-view{height:100%}.monaco-split-view2.separator-border>.monaco-scrollable-element>.split-view-container>.split-view-view:not(:first-child):before{background-color:var(--separator-border);content:" ";left:0;pointer-events:none;position:absolute;top:0;z-index:5}.monaco-split-view2.separator-border.horizontal>.monaco-scrollable-element>.split-view-container>.split-view-view:not(:first-child):before{height:100%;width:1px}.monaco-split-view2.separator-border.vertical>.monaco-scrollable-element>.split-view-container>.split-view-view:not(:first-child):before{height:1px;width:100%}.monaco-table{display:flex;flex-direction:column;height:100%;overflow:hidden;position:relative;white-space:nowrap;width:100%}.monaco-table>.monaco-split-view2{border-bottom:1px solid #0000}.monaco-table>.monaco-list{flex:1 1}.monaco-table-tr{display:flex;height:100%}.monaco-table-th{font-weight:700;height:100%;overflow:hidden;text-overflow:ellipsis;width:100%}.monaco-table-td,.monaco-table-th{box-sizing:border-box;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.monaco-table>.monaco-split-view2 .monaco-sash.vertical:before{border-left:1px solid #0000;content:"";left:calc(var(--vscode-sash-size)/2);position:absolute;width:0}.monaco-workbench:not(.reduce-motion) .monaco-table>.monaco-split-view2,.monaco-workbench:not(.reduce-motion) .monaco-table>.monaco-split-view2 .monaco-sash.vertical:before{transition:border-color .2s ease-out}.monaco-custom-toggle{border:1px solid #0000;border-radius:3px;box-sizing:border-box;cursor:pointer;float:left;height:20px;margin-left:2px;overflow:hidden;padding:1px;user-select:none;-webkit-user-select:none;width:20px}.monaco-custom-toggle:hover{background-color:var(--vscode-inputOption-hoverBackground)}.hc-black .monaco-custom-toggle:hover,.hc-light .monaco-custom-toggle:hover{border:1px dashed var(--vscode-focusBorder)}.hc-black .monaco-custom-toggle,.hc-black .monaco-custom-toggle:hover,.hc-light .monaco-custom-toggle,.hc-light .monaco-custom-toggle:hover{background:none}.monaco-custom-toggle.monaco-checkbox{background-size:16px!important;border:1px solid #0000;border-radius:3px;height:18px;margin-left:0;margin-right:9px;opacity:1;padding:0;width:18px}.monaco-action-bar .checkbox-action-item{align-items:center;border-radius:2px;display:flex;padding-right:2px}.monaco-action-bar .checkbox-action-item:hover{background-color:var(--vscode-toolbar-hoverBackground)}.monaco-action-bar .checkbox-action-item>.monaco-custom-toggle.monaco-checkbox{margin-right:4px}.monaco-action-bar .checkbox-action-item>.checkbox-label{font-size:12px}.monaco-custom-toggle.monaco-checkbox:not(.checked):before{visibility:hidden}.monaco-toolbar{height:100%}.monaco-toolbar .toolbar-toggle-more{display:inline-block;padding:0}.monaco-tl-row{align-items:center;display:flex;height:100%;position:relative}.monaco-tl-row.disabled{cursor:default}.monaco-tl-indent{height:100%;left:16px;pointer-events:none;position:absolute;top:0}.hide-arrows .monaco-tl-indent{left:12px}.monaco-tl-indent>.indent-guide{border-left:1px solid #0000;box-sizing:border-box;display:inline-block;height:100%}.monaco-workbench:not(.reduce-motion) .monaco-tl-indent>.indent-guide{transition:border-color .1s linear}.monaco-tl-contents,.monaco-tl-twistie{height:100%}.monaco-tl-twistie{align-items:center;display:flex!important;flex-shrink:0;font-size:10px;justify-content:center;padding-right:6px;text-align:right;transform:translateX(3px);width:16px}.monaco-tl-contents{flex:1 1;overflow:hidden}.monaco-tl-twistie:before{border-radius:20px}.monaco-tl-twistie.collapsed:before{transform:rotate(-90deg)}.monaco-tl-twistie.codicon-tree-item-loading:before{animation:codicon-spin 1.25s steps(30) infinite}.monaco-tree-type-filter{border:1px solid var(--vscode-widget-border);border-bottom-left-radius:4px;border-bottom-right-radius:4px;display:flex;margin:0 6px;max-width:200px;padding:3px;position:absolute;top:0;z-index:100}.monaco-workbench:not(.reduce-motion) .monaco-tree-type-filter{transition:top .3s}.monaco-tree-type-filter.disabled{top:-40px!important}.monaco-tree-type-filter-grab{align-items:center;cursor:grab;display:flex!important;justify-content:center;margin-right:2px}.monaco-tree-type-filter-grab.grabbing{cursor:grabbing}.monaco-tree-type-filter-input{flex:1 1}.monaco-tree-type-filter-input .monaco-inputbox{height:23px}.monaco-tree-type-filter-input .monaco-inputbox>.ibwrapper>.input,.monaco-tree-type-filter-input .monaco-inputbox>.ibwrapper>.mirror{padding:2px 4px}.monaco-tree-type-filter-input .monaco-findInput>.controls{top:2px}.monaco-tree-type-filter-actionbar{margin-left:4px}.monaco-tree-type-filter-actionbar .monaco-action-bar .action-label{padding:2px}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container{background-color:var(--vscode-sideBar-background);height:0;left:0;position:absolute;top:0;width:100%;z-index:13}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-row.monaco-list-row{background-color:var(--vscode-sideBar-background);opacity:1!important;overflow:hidden;position:absolute;width:100%}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-row:hover{background-color:var(--vscode-list-hoverBackground)!important;cursor:pointer}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container.empty,.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container.empty .monaco-tree-sticky-container-shadow{display:none}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-container-shadow{bottom:-3px;height:0;left:0;position:absolute;width:100%}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container[tabindex="0"]:focus{outline:none}.monaco-editor .inputarea{background-color:initial;border:none;color:#0000;margin:0;min-height:0;min-width:0;outline:none!important;overflow:hidden;padding:0;position:absolute;resize:none;z-index:-10}.monaco-editor .inputarea.ime-input{caret-color:var(--vscode-editorCursor-foreground);color:var(--vscode-editor-foreground);z-index:10}.monaco-workbench .workbench-hover{background:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);border-radius:3px;box-shadow:0 2px 8px var(--vscode-widget-shadow);color:var(--vscode-editorHoverWidget-foreground);font-size:13px;line-height:19px;max-width:700px;overflow:hidden;position:relative;z-index:40}.monaco-workbench .workbench-hover hr{border-bottom:none}.monaco-workbench .workbench-hover:not(.skip-fade-in){animation:fadein .1s linear}.monaco-workbench .workbench-hover.compact{font-size:12px}.monaco-workbench .workbench-hover.compact .hover-contents{padding:2px 8px}.monaco-workbench .workbench-hover-container.locked .workbench-hover{outline:1px solid var(--vscode-editorHoverWidget-border)}.monaco-workbench .workbench-hover-container.locked .workbench-hover:focus,.monaco-workbench .workbench-hover-lock:focus{outline:1px solid var(--vscode-focusBorder)}.monaco-workbench .workbench-hover-container.locked .workbench-hover-lock:hover{background:var(--vscode-toolbar-hoverBackground)}.monaco-workbench .workbench-hover-pointer{pointer-events:none;position:absolute;z-index:41}.monaco-workbench .workbench-hover-pointer:after{background-color:var(--vscode-editorHoverWidget-background);border-bottom:1px solid var(--vscode-editorHoverWidget-border);border-right:1px solid var(--vscode-editorHoverWidget-border);content:"";height:5px;position:absolute;width:5px}.monaco-workbench .locked .workbench-hover-pointer:after{border-bottom-width:2px;border-right-width:2px;height:4px;width:4px}.monaco-workbench .workbench-hover-pointer.left{left:-3px}.monaco-workbench .workbench-hover-pointer.right{right:3px}.monaco-workbench .workbench-hover-pointer.top{top:-3px}.monaco-workbench .workbench-hover-pointer.bottom{bottom:3px}.monaco-workbench .workbench-hover-pointer.left:after{transform:rotate(135deg)}.monaco-workbench .workbench-hover-pointer.right:after{transform:rotate(315deg)}.monaco-workbench .workbench-hover-pointer.top:after{transform:rotate(225deg)}.monaco-workbench .workbench-hover-pointer.bottom:after{transform:rotate(45deg)}.monaco-workbench .workbench-hover a{color:var(--vscode-textLink-foreground)}.monaco-workbench .workbench-hover a:focus{outline:1px solid;outline-color:var(--vscode-focusBorder);outline-offset:-1px;text-decoration:underline}.monaco-workbench .workbench-hover a:active,.monaco-workbench .workbench-hover a:hover{color:var(--vscode-textLink-activeForeground)}.monaco-workbench .workbench-hover code{background:var(--vscode-textCodeBlock-background)}.monaco-workbench .workbench-hover .hover-row .actions{background:var(--vscode-editorHoverWidget-statusBarBackground)}.monaco-workbench .workbench-hover.right-aligned{left:1px}.monaco-workbench .workbench-hover.right-aligned .hover-row.status-bar .actions{flex-direction:row-reverse}.monaco-workbench .workbench-hover.right-aligned .hover-row.status-bar .actions .action-container{margin-left:16px;margin-right:0}.monaco-editor .blockDecorations-container{pointer-events:none;position:absolute;top:0}.monaco-editor .blockDecorations-block{box-sizing:border-box;position:absolute}.monaco-editor .margin-view-overlays .current-line,.monaco-editor .view-overlays .current-line{box-sizing:border-box;display:block;height:100%;left:0;position:absolute;top:0}.monaco-editor + .margin-view-overlays + .current-line.current-line-margin.current-line-margin-both{border-right:0}.monaco-editor .lines-content .cdr{height:100%;position:absolute}.monaco-editor .glyph-margin{position:absolute;top:0}.monaco-editor .glyph-margin-widgets .cgmr{align-items:center;display:flex;justify-content:center;position:absolute}.monaco-editor .glyph-margin-widgets .cgmr.codicon-modifier-spin:before{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.monaco-editor .lines-content .core-guide{box-sizing:border-box;height:100%;position:absolute}.monaco-editor .margin-view-overlays .line-numbers{font-feature-settings:"tnum";bottom:0;box-sizing:border-box;cursor:default;display:inline-block;font-variant-numeric:tabular-nums;position:absolute;text-align:right;vertical-align:middle}.monaco-editor .relative-current-line-number{display:inline-block;text-align:left;width:100%}.monaco-editor .margin-view-overlays .line-numbers.lh-odd{margin-top:1px}.monaco-editor .line-numbers{color:var(--vscode-editorLineNumber-foreground)}.monaco-editor .line-numbers.active-line-number{color:var(--vscode-editorLineNumber-activeForeground)}.mtkcontrol{background:#960000!important;color:#fff!important}.mtkoverflow{background-color:var(--vscode-button-background,var(--vscode-editor-background));border-color:var(--vscode-contrastBorder);border-radius:2px;border-style:solid;border-width:1px;color:var(--vscode-button-foreground,var(--vscode-editor-foreground));cursor:pointer;padding:4px}.mtkoverflow:hover{background-color:var(--vscode-button-hoverBackground)}.monaco-editor.no-user-select .lines-content,.monaco-editor.no-user-select .view-line,.monaco-editor.no-user-select .view-lines{user-select:none;-webkit-user-select:none}.monaco-editor.mac .lines-content:hover,.monaco-editor.mac .view-line:hover,.monaco-editor.mac .view-lines:hover{user-select:text;-webkit-user-select:text;-ms-user-select:text}.monaco-editor.enable-user-select{user-select:auto;-webkit-user-select:initial}.monaco-editor .view-lines{white-space:nowrap}.monaco-editor .view-line{position:absolute;width:100%}.monaco-editor .lines-content>.view-lines>.view-line>span{bottom:0;position:absolute;top:0}.monaco-editor .mtkw,.monaco-editor .mtkz{color:var(--vscode-editorWhitespace-foreground)!important}.monaco-editor .mtkz{display:inline-block}.monaco-editor .lines-decorations{background:#fff;position:absolute;top:0}.monaco-editor .margin-view-overlays .cldr{height:100%;position:absolute}.monaco-editor .margin{background-color:var(--vscode-editorGutter-background)}.monaco-editor .margin-view-overlays .cmdr{height:100%;left:0;position:absolute;width:100%}.monaco-editor .minimap.slider-mouseover .minimap-slider{opacity:0;transition:opacity .1s linear}.monaco-editor .minimap.slider-mouseover .minimap-slider.active,.monaco-editor .minimap.slider-mouseover:hover .minimap-slider{opacity:1}.monaco-editor .minimap-slider .minimap-slider-horizontal{background:var(--vscode-minimapSlider-background)}.monaco-editor .minimap-slider:hover .minimap-slider-horizontal{background:var(--vscode-minimapSlider-hoverBackground)}.monaco-editor .minimap-slider.active .minimap-slider-horizontal{background:var(--vscode-minimapSlider-activeBackground)}.monaco-editor .minimap-shadow-visible{box-shadow:var(--vscode-scrollbar-shadow) -6px 0 6px -6px inset}.monaco-editor .minimap-shadow-hidden{position:absolute;width:0}.monaco-editor .minimap-shadow-visible{left:-6px;position:absolute;width:6px}.monaco-editor.no-minimap-shadow .minimap-shadow-visible{left:-1px;position:absolute;width:1px}.minimap.autohide{opacity:0;transition:opacity .5s}.minimap.autohide:hover{opacity:1}.monaco-editor .minimap{z-index:5}.monaco-editor .overlayWidgets{left:0;position:absolute;top:0}.monaco-editor .view-ruler{box-shadow:1px 0 0 0 var(--vscode-editorRuler-foreground) inset;position:absolute;top:0}.monaco-editor .scroll-decoration{box-shadow:var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset;height:6px;left:0;position:absolute;top:0}.monaco-editor .lines-content .cslr{position:absolute}.monaco-editor .focused .selected-text{background-color:var(--vscode-editor-selectionBackground)}.monaco-editor .selected-text{background-color:var(--vscode-editor-inactiveSelectionBackground)}.monaco-editor .top-left-radius{border-top-left-radius:3px}.monaco-editor .bottom-left-radius{border-bottom-left-radius:3px}.monaco-editor .top-right-radius{border-top-right-radius:3px}.monaco-editor .bottom-right-radius{border-bottom-right-radius:3px}.monaco-editor.hc-black .top-left-radius{border-top-left-radius:0}.monaco-editor.hc-black .bottom-left-radius{border-bottom-left-radius:0}.monaco-editor.hc-black .top-right-radius{border-top-right-radius:0}.monaco-editor.hc-black .bottom-right-radius{border-bottom-right-radius:0}.monaco-editor.hc-light .top-left-radius{border-top-left-radius:0}.monaco-editor.hc-light .bottom-left-radius{border-bottom-left-radius:0}.monaco-editor.hc-light .top-right-radius{border-top-right-radius:0}.monaco-editor.hc-light .bottom-right-radius{border-bottom-right-radius:0}.monaco-editor .cursors-layer{position:absolute;top:0}.monaco-editor .cursors-layer>.cursor{box-sizing:border-box;overflow:hidden;position:absolute}.monaco-editor .cursors-layer.cursor-smooth-caret-animation>.cursor{transition:all 80ms}.monaco-editor .cursors-layer.cursor-block-outline-style>.cursor{background:#0000!important;border-style:solid;border-width:1px}.monaco-editor .cursors-layer.cursor-underline-style>.cursor{background:#0000!important;border-bottom-style:solid;border-bottom-width:2px}.monaco-editor .cursors-layer.cursor-underline-thin-style>.cursor{background:#0000!important;border-bottom-style:solid;border-bottom-width:1px}@keyframes monaco-cursor-smooth{0%,20%{opacity:1}60%,to{opacity:0}}@keyframes monaco-cursor-phase{0%,20%{opacity:1}90%,to{opacity:0}}@keyframes monaco-cursor-expand{0%,20%{transform:scaleY(1)}80%,to{transform:scaleY(0)}}.cursor-smooth{animation:monaco-cursor-smooth .5s ease-in-out 0s 20 alternate}.cursor-phase{animation:monaco-cursor-phase .5s ease-in-out 0s 20 alternate}.cursor-expand>.cursor{animation:monaco-cursor-expand .5s ease-in-out 0s 20 alternate}.monaco-editor .mwh{color:var(--vscode-editorWhitespace-foreground)!important;position:absolute}::-ms-clear{display:none}.monaco-editor .editor-widget input{color:inherit}.monaco-editor{-webkit-text-size-adjust:100%;color:var(--vscode-editor-foreground);overflow:visible;overflow-wrap:normal;position:relative}.monaco-editor,.monaco-editor-background{background-color:var(--vscode-editor-background)}.monaco-editor .rangeHighlight{background-color:var(--vscode-editor-rangeHighlightBackground);border:1px solid var(--vscode-editor-rangeHighlightBorder);box-sizing:border-box}.monaco-editor.hc-black .rangeHighlight,.monaco-editor.hc-light .rangeHighlight{border-style:dotted}.monaco-editor .symbolHighlight{background-color:var(--vscode-editor-symbolHighlightBackground);border:1px solid var(--vscode-editor-symbolHighlightBorder);box-sizing:border-box}.monaco-editor.hc-black .symbolHighlight,.monaco-editor.hc-light .symbolHighlight{border-style:dotted}.monaco-editor .overflow-guard{overflow:hidden;position:relative}.monaco-editor .view-overlays{position:absolute;top:0}.monaco-editor .margin-view-overlays>div,.monaco-editor .view-overlays>div{position:absolute;width:100%}.monaco-editor .squiggly-error{border-bottom:4px double var(--vscode-editorError-border)}.monaco-editor .squiggly-error:before{background:var(--vscode-editorError-background);content:"";display:block;height:100%;width:100%}.monaco-editor .squiggly-warning{border-bottom:4px double var(--vscode-editorWarning-border)}.monaco-editor .squiggly-warning:before{background:var(--vscode-editorWarning-background);content:"";display:block;height:100%;width:100%}.monaco-editor .squiggly-info{border-bottom:4px double var(--vscode-editorInfo-border)}.monaco-editor .squiggly-info:before{background:var(--vscode-editorInfo-background);content:"";display:block;height:100%;width:100%}.monaco-editor .squiggly-hint{border-bottom:2px dotted var(--vscode-editorHint-border)}.monaco-editor.showUnused .squiggly-unnecessary{border-bottom:2px dashed var(--vscode-editorUnnecessaryCode-border)}.monaco-editor.showDeprecated .squiggly-inline-deprecated{text-decoration:line-through;text-decoration-color:var(--vscode-editor-foreground,inherit)}.monaco-component.diff-review{user-select:none;-webkit-user-select:none;z-index:99}.monaco-diff-editor .diff-review{position:absolute}.monaco-component.diff-review .diff-review-line-number{color:var(--vscode-editorLineNumber-foreground);display:inline-block;text-align:right}.monaco-component.diff-review .diff-review-summary{padding-left:10px}.monaco-component.diff-review .diff-review-shadow{box-shadow:var(--vscode-scrollbar-shadow) 0 -6px 6px -6px inset;position:absolute}.monaco-component.diff-review .diff-review-row{white-space:pre}.monaco-component.diff-review .diff-review-table{display:table;min-width:100%}.monaco-component.diff-review .diff-review-row{display:table-row;width:100%}.monaco-component.diff-review .diff-review-spacer{display:inline-block;vertical-align:middle;width:10px}.monaco-component.diff-review .diff-review-spacer>.codicon{font-size:9px!important}.monaco-component.diff-review .diff-review-actions{display:inline-block;position:absolute;right:10px;top:2px;z-index:100}.monaco-component.diff-review .diff-review-actions .action-label{height:16px;margin:2px 0;width:16px}.monaco-component.diff-review .revertButton{cursor:pointer}.monaco-editor .diff-hidden-lines-widget{width:100%}.monaco-editor .diff-hidden-lines{font-size:13px;height:0;line-height:14px;transform:translateY(-10px)}.monaco-editor .diff-hidden-lines .bottom.dragging,.monaco-editor .diff-hidden-lines .top.dragging,.monaco-editor .diff-hidden-lines:not(.dragging) .bottom:hover,.monaco-editor .diff-hidden-lines:not(.dragging) .top:hover{background-color:var(--vscode-focusBorder)}.monaco-editor .diff-hidden-lines .bottom,.monaco-editor .diff-hidden-lines .top{background-clip:padding-box;background-color:initial;border-bottom:2px solid #0000;border-top:4px solid #0000;height:4px;transition:background-color .1s ease-out}.monaco-editor .diff-hidden-lines .bottom.canMoveTop:not(.canMoveBottom),.monaco-editor .diff-hidden-lines .top.canMoveTop:not(.canMoveBottom),.monaco-editor.draggingUnchangedRegion.canMoveTop:not(.canMoveBottom) *{cursor:n-resize!important}.monaco-editor .diff-hidden-lines .bottom:not(.canMoveTop).canMoveBottom,.monaco-editor .diff-hidden-lines .top:not(.canMoveTop).canMoveBottom,.monaco-editor.draggingUnchangedRegion:not(.canMoveTop).canMoveBottom *{cursor:s-resize!important}.monaco-editor .diff-hidden-lines .bottom.canMoveTop.canMoveBottom,.monaco-editor .diff-hidden-lines .top.canMoveTop.canMoveBottom,.monaco-editor.draggingUnchangedRegion.canMoveTop.canMoveBottom *{cursor:ns-resize!important}.monaco-editor .diff-hidden-lines .top{transform:translateY(4px)}.monaco-editor .diff-hidden-lines .bottom{transform:translateY(-6px)}.monaco-editor .diff-unchanged-lines{background:var(--vscode-diffEditor-unchangedCodeBackground)}.monaco-editor .noModificationsOverlay{align-items:center;background:var(--vscode-editor-background);display:flex;justify-content:center;z-index:1}.monaco-editor .diff-hidden-lines .center{background:var(--vscode-diffEditor-unchangedRegionBackground);box-shadow:inset 0 -5px 5px -7px var(--vscode-diffEditor-unchangedRegionShadow),inset 0 5px 5px -7px var(--vscode-diffEditor-unchangedRegionShadow);color:var(--vscode-diffEditor-unchangedRegionForeground);display:block;height:24px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.monaco-editor .diff-hidden-lines .center span.codicon{vertical-align:middle}.monaco-editor .diff-hidden-lines .center a:hover .codicon{color:var(--vscode-editorLink-activeForeground)!important;cursor:pointer}.monaco-editor .diff-hidden-lines div.breadcrumb-item{cursor:pointer}.monaco-editor .diff-hidden-lines div.breadcrumb-item:hover{color:var(--vscode-editorLink-activeForeground)}.monaco-editor .movedModified,.monaco-editor .movedOriginal{border:2px solid var(--vscode-diffEditor-move-border)}.monaco-editor .movedModified.currentMove,.monaco-editor .movedOriginal.currentMove{border:2px solid var(--vscode-diffEditor-moveActive-border)}.monaco-diff-editor .moved-blocks-lines path.currentMove{stroke:var(--vscode-diffEditor-moveActive-border)}.monaco-diff-editor .moved-blocks-lines path{pointer-events:visiblestroke}.monaco-diff-editor .moved-blocks-lines .arrow{fill:var(--vscode-diffEditor-move-border)}.monaco-diff-editor .moved-blocks-lines .arrow.currentMove{fill:var(--vscode-diffEditor-moveActive-border)}.monaco-diff-editor .moved-blocks-lines .arrow-rectangle{fill:var(--vscode-editor-background)}.monaco-diff-editor .moved-blocks-lines{pointer-events:none;position:absolute}.monaco-diff-editor .moved-blocks-lines path{fill:none;stroke:var(--vscode-diffEditor-move-border);stroke-width:2}.monaco-editor .char-delete.diff-range-empty{border-left:3px solid var(--vscode-diffEditor-removedTextBackground);margin-left:-1px}.monaco-editor .char-insert.diff-range-empty{border-left:3px solid var(--vscode-diffEditor-insertedTextBackground)}.monaco-editor .fold-unchanged{cursor:pointer}.monaco-diff-editor .diff-moved-code-block{display:flex;justify-content:flex-end;margin-top:-4px}.monaco-diff-editor .diff-moved-code-block .action-bar .action-label.codicon{font-size:12px;height:12px;width:12px}.monaco-diff-editor .diffOverview{z-index:9}.monaco-diff-editor .diffOverview .diffViewport{z-index:10}.monaco-diff-editor.vs .diffOverview{background:#00000008}.monaco-diff-editor.vs-dark .diffOverview{background:#ffffff03}.monaco-scrollable-element.modified-in-monaco-diff-editor.vs .scrollbar,.monaco-scrollable-element.modified-in-monaco-diff-editor.vs-dark .scrollbar{background:#0000}.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-black .scrollbar,.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-light .scrollbar{background:none}.monaco-scrollable-element.modified-in-monaco-diff-editor .slider{z-index:10}.modified-in-monaco-diff-editor .slider.active{background:#ababab66}.modified-in-monaco-diff-editor.hc-black .slider.active,.modified-in-monaco-diff-editor.hc-light .slider.active{background:none}.monaco-diff-editor .delete-sign,.monaco-diff-editor .insert-sign,.monaco-editor .delete-sign,.monaco-editor .insert-sign{align-items:center;display:flex!important;font-size:11px!important;opacity:.7!important}.monaco-diff-editor.hc-black .delete-sign,.monaco-diff-editor.hc-black .insert-sign,.monaco-diff-editor.hc-light .delete-sign,.monaco-diff-editor.hc-light .insert-sign,.monaco-editor.hc-black .delete-sign,.monaco-editor.hc-black .insert-sign,.monaco-editor.hc-light .delete-sign,.monaco-editor.hc-light .insert-sign{opacity:1}.monaco-editor .inline-added-margin-view-zone,.monaco-editor .inline-deleted-margin-view-zone{text-align:right}.monaco-editor .arrow-revert-change{position:absolute;z-index:10}.monaco-editor .arrow-revert-change:hover{cursor:pointer}.monaco-editor .view-zones .view-lines .view-line span{display:inline-block}.monaco-editor .margin-view-zones .lightbulb-glyph:hover{cursor:pointer}.monaco-diff-editor .char-insert,.monaco-editor .char-insert{background-color:var(--vscode-diffEditor-insertedTextBackground)}.monaco-diff-editor .line-insert,.monaco-editor .line-insert{background-color:var(--vscode-diffEditor-insertedLineBackground,var(--vscode-diffEditor-insertedTextBackground))}.monaco-editor .char-insert,.monaco-editor .line-insert{border:1px solid var(--vscode-diffEditor-insertedTextBorder);box-sizing:border-box}.monaco-editor.hc-black .char-insert,.monaco-editor.hc-black .line-insert,.monaco-editor.hc-light .char-insert,.monaco-editor.hc-light .line-insert{border-style:dashed}.monaco-editor .char-delete,.monaco-editor .line-delete{border:1px solid var(--vscode-diffEditor-removedTextBorder);box-sizing:border-box}.monaco-editor.hc-black .char-delete,.monaco-editor.hc-black .line-delete,.monaco-editor.hc-light .char-delete,.monaco-editor.hc-light .line-delete{border-style:dashed}.monaco-diff-editor .gutter-insert,.monaco-editor .gutter-insert,.monaco-editor .inline-added-margin-view-zone{background-color:var(--vscode-diffEditorGutter-insertedLineBackground,var(--vscode-diffEditor-insertedLineBackground),var(--vscode-diffEditor-insertedTextBackground))}.monaco-diff-editor .char-delete,.monaco-editor .char-delete,.monaco-editor .inline-deleted-text{background-color:var(--vscode-diffEditor-removedTextBackground)}.monaco-editor .inline-deleted-text{text-decoration:line-through}.monaco-diff-editor .line-delete,.monaco-editor .line-delete{background-color:var(--vscode-diffEditor-removedLineBackground,var(--vscode-diffEditor-removedTextBackground))}.monaco-diff-editor .gutter-delete,.monaco-editor .gutter-delete,.monaco-editor .inline-deleted-margin-view-zone{background-color:var(--vscode-diffEditorGutter-removedLineBackground,var(--vscode-diffEditor-removedLineBackground),var(--vscode-diffEditor-removedTextBackground))}.monaco-diff-editor.side-by-side .editor.modified{border-left:1px solid var(--vscode-diffEditor-border);box-shadow:-6px 0 5px -5px var(--vscode-scrollbar-shadow)}.monaco-diff-editor.side-by-side .editor.original{border-right:1px solid var(--vscode-diffEditor-border);box-shadow:6px 0 5px -5px var(--vscode-scrollbar-shadow)}.monaco-diff-editor .diffViewport{background:var(--vscode-scrollbarSlider-background)}.monaco-diff-editor .diffViewport:hover{background:var(--vscode-scrollbarSlider-hoverBackground)}.monaco-diff-editor .diffViewport:active{background:var(--vscode-scrollbarSlider-activeBackground)}.monaco-editor .diagonal-fill{background-image:linear-gradient(-45deg,var(--vscode-diffEditor-diagonalFill) 12.5%,#0000 12.5%,#0000 50%,var(--vscode-diffEditor-diagonalFill) 50%,var(--vscode-diffEditor-diagonalFill) 62.5%,#0000 62.5%,#0000 100%);background-size:8px 8px}.monaco-diff-editor .gutter{flex-grow:0;flex-shrink:0;overflow:hidden;position:relative}.monaco-diff-editor .gutter>div{position:absolute}.monaco-diff-editor .gutter .gutterItem{opacity:0;transition:opacity .7s}.monaco-diff-editor .gutter .gutterItem.showAlways{opacity:1;transition:none}.monaco-diff-editor .gutter .gutterItem.noTransition{transition:none}.monaco-diff-editor .gutter:hover .gutterItem{opacity:1;transition:opacity .1s ease-in-out}.monaco-diff-editor .gutter .gutterItem .background{border-left:2px solid var(--vscode-menu-border);height:100%;left:50%;position:absolute;width:1px}.monaco-diff-editor .gutter .gutterItem .buttons{align-items:center;display:flex;justify-content:center;position:absolute;width:100%}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar{height:fit-content}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar .monaco-action-bar{line-height:1}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar .monaco-action-bar .actions-container{background:var(--vscode-editorGutter-commentRangeForeground);border-radius:4px;width:fit-content}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar .monaco-action-bar .actions-container .action-item:hover{background:var(--vscode-toolbar-hoverBackground)}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar .monaco-action-bar .actions-container .action-item .action-label{padding:1px 2px}.monaco-diff-editor .diff-hidden-lines-compact{display:flex;height:11px}.monaco-diff-editor .diff-hidden-lines-compact .line-left,.monaco-diff-editor .diff-hidden-lines-compact .line-right{border-top:1px solid;border-color:var(--vscode-editorCodeLens-foreground);height:1px;margin:auto;opacity:.5;width:100%}.monaco-diff-editor .diff-hidden-lines-compact .line-left{width:20px}.monaco-diff-editor .diff-hidden-lines-compact .text{text-wrap:nowrap;color:var(--vscode-editorCodeLens-foreground);font-size:11px;line-height:11px;margin:0 4px}.monaco-editor .rendered-markdown kbd{background-color:var(--vscode-keybindingLabel-background);border-color:var(--vscode-keybindingLabel-border);border-bottom:1px var(--vscode-keybindingLabel-bottomBorder);border-left-width:1px;border-radius:3px;border-right-width:1px;border-style:solid;border-top-width:1px;box-shadow:inset 0 -1px 0 var(--vscode-widget-shadow);color:var(--vscode-keybindingLabel-foreground);padding:1px 3px;vertical-align:middle}.rendered-markdown li:has(input[type=checkbox]){list-style-type:none}.monaco-component.multiDiffEditor{background:var(--vscode-multiDiffEditor-background);height:100%;overflow-y:hidden;position:relative;width:100%}.monaco-component.multiDiffEditor>div{height:100%;left:0;position:absolute;top:0;width:100%}.monaco-component.multiDiffEditor>div.placeholder{display:grid;place-content:center;place-items:center;visibility:hidden}.monaco-component.multiDiffEditor>div.placeholder.visible{visibility:visible}.monaco-component.multiDiffEditor .active{--vscode-multiDiffEditor-border:var(--vscode-focusBorder)}.monaco-component.multiDiffEditor .multiDiffEntry{display:flex;flex:1 1;flex-direction:column;overflow:hidden}.monaco-component.multiDiffEditor .multiDiffEntry .collapse-button{cursor:pointer;margin:0 5px}.monaco-component.multiDiffEditor .multiDiffEntry .collapse-button a{display:block}.monaco-component.multiDiffEditor .multiDiffEntry .header{background:var(--vscode-editor-background);z-index:1000}.monaco-component.multiDiffEditor .multiDiffEntry .header:not(.collapsed) .header-content{border-bottom:1px solid var(--vscode-sideBarSectionHeader-border)}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content{align-items:center;background:var(--vscode-multiDiffEditor-headerBackground);border-top:1px solid var(--vscode-multiDiffEditor-border);color:var(--vscode-foreground);display:flex;margin:8px 0 0;padding:4px 5px}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content.shadow{box-shadow:var(--vscode-scrollbar-shadow) 0 6px 6px -6px}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .file-path{display:flex;flex:1 1;min-width:0}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .file-path .title{font-size:14px;line-height:22px}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .file-path .title.original{flex:1 1;min-width:0;text-overflow:ellipsis}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .file-path .status{font-weight:600;line-height:22px;margin:0 10px;opacity:.75}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .actions{padding:0 8px}.monaco-component.multiDiffEditor .multiDiffEntry .editorParent{border-bottom:1px solid var(--vscode-multiDiffEditor-border);display:flex;flex:1 1;flex-direction:column;overflow:hidden}.monaco-component.multiDiffEditor .multiDiffEntry .editorContainer{flex:1 1}.monaco-editor .selection-anchor{background-color:#007acc;width:2px!important}.monaco-editor .bracket-match{background-color:var(--vscode-editorBracketMatch-background);border:1px solid var(--vscode-editorBracketMatch-border);box-sizing:border-box}.monaco-editor .lightBulbWidget{align-items:center;display:flex;justify-content:center}.monaco-editor .lightBulbWidget:hover{cursor:pointer}.monaco-editor .lightBulbWidget.codicon-light-bulb,.monaco-editor .lightBulbWidget.codicon-lightbulb-sparkle{color:var(--vscode-editorLightBulb-foreground)}.monaco-editor .lightBulbWidget.codicon-lightbulb-autofix,.monaco-editor .lightBulbWidget.codicon-lightbulb-sparkle-autofix{color:var(--vscode-editorLightBulbAutoFix-foreground,var(--vscode-editorLightBulb-foreground))}.monaco-editor .lightBulbWidget.codicon-sparkle-filled{color:var(--vscode-editorLightBulbAi-foreground,var(--vscode-icon-foreground))}.monaco-editor .lightBulbWidget:before{position:relative;z-index:2}.monaco-editor .lightBulbWidget:after{content:"";display:block;height:100%;left:0;opacity:.3;position:absolute;top:0;width:100%;z-index:1}.monaco-editor .glyph-margin-widgets .cgmr[class*=codicon-gutter-lightbulb]{cursor:pointer;display:block}.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb,.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb-sparkle{color:var(--vscode-editorLightBulb-foreground)}.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb-aifix-auto-fix,.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb-auto-fix{color:var(--vscode-editorLightBulbAutoFix-foreground,var(--vscode-editorLightBulb-foreground))}.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb-sparkle-filled{color:var(--vscode-editorLightBulbAi-foreground,var(--vscode-icon-foreground))}.monaco-editor .codelens-decoration{font-feature-settings:var(--vscode-editorCodeLens-fontFeatureSettings);color:var(--vscode-editorCodeLens-foreground);display:inline-block;font-family:var(--vscode-editorCodeLens-fontFamily),var(--vscode-editorCodeLens-fontFamilyDefault);font-size:var(--vscode-editorCodeLens-fontSize);line-height:var(--vscode-editorCodeLens-lineHeight);overflow:hidden;padding-right:calc(var(--vscode-editorCodeLens-fontSize)*.5);text-overflow:ellipsis;white-space:nowrap}.monaco-editor .codelens-decoration>a,.monaco-editor .codelens-decoration>span{user-select:none;-webkit-user-select:none;vertical-align:sub;white-space:nowrap}.monaco-editor .codelens-decoration>a{text-decoration:none}.monaco-editor .codelens-decoration>a:hover{cursor:pointer}.monaco-editor .codelens-decoration>a:hover,.monaco-editor .codelens-decoration>a:hover .codicon{color:var(--vscode-editorLink-activeForeground)!important}.monaco-editor .codelens-decoration .codicon{color:currentColor!important;color:var(--vscode-editorCodeLens-foreground);font-size:var(--vscode-editorCodeLens-fontSize);line-height:var(--vscode-editorCodeLens-lineHeight);vertical-align:middle}.monaco-editor .codelens-decoration>a:hover .codicon:before{cursor:pointer}@keyframes fadein{0%{opacity:0;visibility:visible}to{opacity:1}}.monaco-editor .codelens-decoration.fadein{animation:fadein .1s linear}.colorpicker-widget{height:190px;user-select:none;-webkit-user-select:none}.colorpicker-color-decoration,.hc-light .colorpicker-color-decoration{border:.1em solid #000;box-sizing:border-box;cursor:pointer;display:inline-block;height:.8em;line-height:.8em;margin:.1em .2em 0;width:.8em}.hc-black .colorpicker-color-decoration,.vs-dark .colorpicker-color-decoration{border:.1em solid #eee}.colorpicker-header{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTZEaa/1AAAAHUlEQVQYV2PYvXu3JAi7uLiAMaYAjAGTQBPYLQkAa/0Zef3qRswAAAAASUVORK5CYII=);background-size:9px 9px;display:flex;height:24px;image-rendering:pixelated;position:relative}.colorpicker-header .picked-color{align-items:center;color:#fff;cursor:pointer;display:flex;flex:1 1;justify-content:center;line-height:24px;overflow:hidden;white-space:nowrap;width:240px}.colorpicker-header .picked-color .picked-color-presentation{margin-left:5px;margin-right:5px;white-space:nowrap}.colorpicker-header .picked-color .codicon{color:inherit;font-size:14px}.colorpicker-header .picked-color.light{color:#000}.colorpicker-header .original-color{cursor:pointer;width:74px;z-index:inherit}.standalone-colorpicker{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground)}.colorpicker-header.standalone-colorpicker{border-bottom:none}.colorpicker-header .close-button{background-color:var(--vscode-editorHoverWidget-background);border-left:1px solid var(--vscode-editorHoverWidget-border);cursor:pointer}.colorpicker-header .close-button-inner-div{height:100%;text-align:center;width:100%}.colorpicker-header .close-button-inner-div:hover{background-color:var(--vscode-toolbar-hoverBackground)}.colorpicker-header .close-icon{padding:3px}.colorpicker-body{display:flex;padding:8px;position:relative}.colorpicker-body .saturation-wrap{flex:1 1;height:150px;min-width:220px;overflow:hidden;position:relative}.colorpicker-body .saturation-box{height:150px;position:absolute}.colorpicker-body .saturation-selection{border:1px solid #fff;border-radius:100%;box-shadow:0 0 2px #000c;height:9px;margin:-5px 0 0 -5px;position:absolute;width:9px}.colorpicker-body .strip{height:150px;width:25px}.colorpicker-body .standalone-strip{height:122px;width:25px}.colorpicker-body .hue-strip{background:linear-gradient(180deg,red,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red);cursor:grab;margin-left:8px;position:relative}.colorpicker-body .opacity-strip{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTZEaa/1AAAAHUlEQVQYV2PYvXu3JAi7uLiAMaYAjAGTQBPYLQkAa/0Zef3qRswAAAAASUVORK5CYII=);background-size:9px 9px;cursor:grab;image-rendering:pixelated;margin-left:8px;position:relative}.colorpicker-body .strip.grabbing{cursor:grabbing}.colorpicker-body .slider{border:1px solid #ffffffb5;box-shadow:0 0 1px #000000d9;box-sizing:border-box;height:4px;left:-2px;position:absolute;top:0;width:calc(100% + 4px)}.colorpicker-body .strip .overlay{height:150px;pointer-events:none}.colorpicker-body .standalone-strip .standalone-overlay{height:122px;pointer-events:none}.standalone-colorpicker-body{border:1px solid #0000;border-bottom:1px solid var(--vscode-editorHoverWidget-border);display:block;overflow:hidden}.colorpicker-body .insert-button{background:var(--vscode-button-background);border:none;border-radius:2px;bottom:8px;color:var(--vscode-button-foreground);cursor:pointer;height:20px;padding:0;position:absolute;right:8px;width:58px}.colorpicker-body .insert-button:hover{background:var(--vscode-button-hoverBackground)}.monaco-editor.hc-light .dnd-target,.monaco-editor.vs .dnd-target{border-right:2px dotted #000;color:#fff}.monaco-editor.vs-dark .dnd-target{border-right:2px dotted #aeafad;color:#51504f}.monaco-editor.hc-black .dnd-target{border-right:2px dotted #fff;color:#000}.monaco-editor.hc-black.mac.mouse-default .view-lines,.monaco-editor.hc-light.mac.mouse-default .view-lines,.monaco-editor.mouse-default .view-lines,.monaco-editor.vs-dark.mac.mouse-default .view-lines{cursor:default}.monaco-editor.hc-black.mac.mouse-copy .view-lines,.monaco-editor.hc-light.mac.mouse-copy .view-lines,.monaco-editor.mouse-copy .view-lines,.monaco-editor.vs-dark.mac.mouse-copy .view-lines{cursor:copy}.post-edit-widget{background-color:var(--vscode-editorWidget-background);border:1px solid var(--vscode-widget-border,#0000);border-radius:4px;box-shadow:0 0 8px 2px var(--vscode-widget-shadow);overflow:hidden}.post-edit-widget .monaco-button{border:none;border-radius:0;padding:2px}.post-edit-widget .monaco-button:hover{background-color:var(--vscode-button-secondaryHoverBackground)!important}.post-edit-widget .monaco-button .codicon{margin:0}.monaco-editor .findOptionsWidget{border:2px solid var(--vscode-contrastBorder)}.monaco-editor .find-widget,.monaco-editor .findOptionsWidget{background-color:var(--vscode-editorWidget-background);box-shadow:0 0 8px 2px var(--vscode-widget-shadow);color:var(--vscode-editorWidget-foreground)}.monaco-editor .find-widget{border-bottom:1px solid var(--vscode-widget-border);border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-left:1px solid var(--vscode-widget-border);border-right:1px solid var(--vscode-widget-border);box-sizing:border-box;height:33px;line-height:19px;overflow:hidden;padding:0 4px;position:absolute;transform:translateY(calc(-100% - 10px));transition:transform .2s linear;z-index:35}.monaco-workbench.reduce-motion .monaco-editor .find-widget{transition:transform 0ms linear}.monaco-editor .find-widget textarea{margin:0}.monaco-editor .find-widget.hiddenEditor{display:none}.monaco-editor .find-widget.replaceToggled>.replace-part{display:flex}.monaco-editor .find-widget.visible{transform:translateY(0)}.monaco-editor .find-widget .monaco-inputbox.synthetic-focus{outline:1px solid -webkit-focus-ring-color;outline-color:var(--vscode-focusBorder);outline-offset:-1px}.monaco-editor .find-widget .monaco-inputbox .input{background-color:initial;min-height:0}.monaco-editor .find-widget .monaco-findInput .input{font-size:13px}.monaco-editor .find-widget>.find-part,.monaco-editor .find-widget>.replace-part{display:flex;font-size:12px;margin:3px 25px 0 17px}.monaco-editor .find-widget>.find-part .monaco-inputbox,.monaco-editor .find-widget>.replace-part .monaco-inputbox{min-height:25px}.monaco-editor .find-widget>.replace-part .monaco-inputbox>.ibwrapper>.mirror{padding-right:22px}.monaco-editor .find-widget>.find-part .monaco-inputbox>.ibwrapper>.input,.monaco-editor .find-widget>.find-part .monaco-inputbox>.ibwrapper>.mirror,.monaco-editor .find-widget>.replace-part .monaco-inputbox>.ibwrapper>.input,.monaco-editor .find-widget>.replace-part .monaco-inputbox>.ibwrapper>.mirror{padding-bottom:2px;padding-top:2px}.monaco-editor .find-widget>.find-part .find-actions,.monaco-editor .find-widget>.replace-part .replace-actions{align-items:center;display:flex;height:25px}.monaco-editor .find-widget .monaco-findInput{display:flex;flex:1 1;vertical-align:middle}.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element{width:100%}.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element .scrollbar.vertical{opacity:0}.monaco-editor .find-widget .matchesCount{box-sizing:border-box;display:flex;flex:initial;height:25px;line-height:23px;margin:0 0 0 3px;padding:2px 0 0 2px;text-align:center;vertical-align:middle}.monaco-editor .find-widget .button{align-items:center;background-position:50%;background-repeat:no-repeat;border-radius:5px;cursor:pointer;display:flex;flex:initial;height:16px;justify-content:center;margin-left:3px;padding:3px;width:16px}.monaco-editor .find-widget .codicon-find-selection{border-radius:5px;height:22px;padding:3px;width:22px}.monaco-editor .find-widget .button.left{margin-left:0;margin-right:3px}.monaco-editor .find-widget .button.wide{padding:1px 6px;top:-1px;width:auto}.monaco-editor .find-widget .button.toggle{border-radius:0;box-sizing:border-box;height:100%;left:3px;position:absolute;top:0;width:18px}.monaco-editor .find-widget .button.toggle.disabled{display:none}.monaco-editor .find-widget .disabled{color:var(--vscode-disabledForeground);cursor:default}.monaco-editor .find-widget>.replace-part{display:none}.monaco-editor .find-widget>.replace-part>.monaco-findInput{display:flex;flex:auto;flex-grow:0;flex-shrink:0;position:relative;vertical-align:middle}.monaco-editor .find-widget>.replace-part>.monaco-findInput>.controls{position:absolute;right:2px;top:3px}.monaco-editor .find-widget.reduced-find-widget .matchesCount{display:none}.monaco-editor .find-widget.narrow-find-widget{max-width:257px!important}.monaco-editor .find-widget.collapsed-find-widget{max-width:170px!important}.monaco-editor .find-widget.collapsed-find-widget .button.next,.monaco-editor .find-widget.collapsed-find-widget .button.previous,.monaco-editor .find-widget.collapsed-find-widget .button.replace,.monaco-editor .find-widget.collapsed-find-widget .button.replace-all,.monaco-editor .find-widget.collapsed-find-widget>.find-part .monaco-findInput .controls{display:none}.monaco-editor .find-widget.no-results .matchesCount{color:var(--vscode-errorForeground)}.monaco-editor .findMatch{animation-duration:0;animation-name:inherit!important;background-color:var(--vscode-editor-findMatchHighlightBackground)}.monaco-editor .currentFindMatch{background-color:var(--vscode-editor-findMatchBackground);border:2px solid var(--vscode-editor-findMatchBorder);box-sizing:border-box;padding:1px}.monaco-editor .findScope{background-color:var(--vscode-editor-findRangeHighlightBackground)}.monaco-editor .find-widget .monaco-sash{background-color:var(--vscode-editorWidget-resizeBorder,var(--vscode-editorWidget-border));left:0!important}.monaco-editor.hc-black .find-widget .button:before{left:2px;position:relative;top:1px}.monaco-editor .find-widget .button:not(.disabled):hover,.monaco-editor .find-widget .codicon-find-selection:hover{background-color:var(--vscode-toolbar-hoverBackground)!important}.monaco-editor.findMatch{background-color:var(--vscode-editor-findMatchHighlightBackground)}.monaco-editor.currentFindMatch{background-color:var(--vscode-editor-findMatchBackground)}.monaco-editor.findScope{background-color:var(--vscode-editor-findRangeHighlightBackground)}.monaco-editor.findMatch{background-color:var(--vscode-editorWidget-background)}.monaco-editor .find-widget>.button.codicon-widget-close{position:absolute;right:4px;top:5px}.monaco-editor .margin-view-overlays .codicon-folding-collapsed,.monaco-editor .margin-view-overlays .codicon-folding-expanded,.monaco-editor .margin-view-overlays .codicon-folding-manual-collapsed,.monaco-editor .margin-view-overlays .codicon-folding-manual-expanded{align-items:center;cursor:pointer;display:flex;font-size:140%;justify-content:center;margin-left:2px;opacity:0;transition:opacity .5s}.monaco-workbench.reduce-motion .monaco-editor .margin-view-overlays .codicon-folding-collapsed,.monaco-workbench.reduce-motion .monaco-editor .margin-view-overlays .codicon-folding-expanded,.monaco-workbench.reduce-motion .monaco-editor .margin-view-overlays .codicon-folding-manual-collapsed,.monaco-workbench.reduce-motion .monaco-editor .margin-view-overlays .codicon-folding-manual-expanded{transition:initial}.monaco-editor .margin-view-overlays .codicon.alwaysShowFoldIcons,.monaco-editor .margin-view-overlays .codicon.codicon-folding-collapsed,.monaco-editor .margin-view-overlays .codicon.codicon-folding-manual-collapsed,.monaco-editor .margin-view-overlays:hover .codicon{opacity:1}.monaco-editor .inline-folded:after{color:var(--vscode-editor-foldPlaceholderForeground);content:"\22EF";cursor:pointer;display:inline;line-height:1em;margin:.1em .2em 0}.monaco-editor .folded-background{background-color:var(--vscode-editor-foldBackground)}.monaco-editor .cldr.codicon.codicon-folding-collapsed,.monaco-editor .cldr.codicon.codicon-folding-expanded,.monaco-editor .cldr.codicon.codicon-folding-manual-collapsed,.monaco-editor .cldr.codicon.codicon-folding-manual-expanded{color:var(--vscode-editorGutter-foldingControlForeground)!important}.monaco-editor .peekview-widget .head .peekview-title .severity-icon{display:inline-block;margin-right:4px;vertical-align:text-top}.monaco-editor .marker-widget{text-overflow:ellipsis;white-space:nowrap}.monaco-editor .marker-widget>.stale{font-style:italic;opacity:.6}.monaco-editor .marker-widget .title{display:inline-block;padding-right:5px}.monaco-editor .marker-widget .descriptioncontainer{padding:8px 12px 0 20px;position:absolute;user-select:text;-webkit-user-select:text;white-space:pre}.monaco-editor .marker-widget .descriptioncontainer .message{display:flex;flex-direction:column}.monaco-editor .marker-widget .descriptioncontainer .message .details{padding-left:6px}.monaco-editor .marker-widget .descriptioncontainer .message .source,.monaco-editor .marker-widget .descriptioncontainer .message span.code{opacity:.6}.monaco-editor .marker-widget .descriptioncontainer .message a.code-link{color:inherit;opacity:.6}.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:before{content:"("}.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:after{content:")"}.monaco-editor .marker-widget .descriptioncontainer .message a.code-link>span{border-bottom:1px solid #0000;color:var(--vscode-textLink-activeForeground);text-decoration:underline;text-underline-position:under}.monaco-editor .marker-widget .descriptioncontainer .filename{color:var(--vscode-textLink-activeForeground);cursor:pointer}.monaco-editor .goto-definition-link{color:var(--vscode-editorLink-activeForeground)!important;cursor:pointer;text-decoration:underline}.monaco-editor .zone-widget .zone-widget-container.reference-zone-widget{border-bottom-width:1px;border-top-width:1px}.monaco-editor .reference-zone-widget .inline{display:inline-block;vertical-align:top}.monaco-editor .reference-zone-widget .messages{height:100%;padding:3em 0;text-align:center;width:100%}.monaco-editor .reference-zone-widget .ref-tree{background-color:var(--vscode-peekViewResult-background);color:var(--vscode-peekViewResult-lineForeground);line-height:23px}.monaco-editor .reference-zone-widget .ref-tree .reference{overflow:hidden;text-overflow:ellipsis}.monaco-editor .reference-zone-widget .ref-tree .reference-file{color:var(--vscode-peekViewResult-fileForeground);display:inline-flex;height:100%;width:100%}.monaco-editor .reference-zone-widget .ref-tree .monaco-list:focus .selected .reference-file{color:inherit!important}.monaco-editor .reference-zone-widget .ref-tree .monaco-list:focus .monaco-list-rows>.monaco-list-row.selected:not(.highlighted){background-color:var(--vscode-peekViewResult-selectionBackground);color:var(--vscode-peekViewResult-selectionForeground)!important}.monaco-editor .reference-zone-widget .ref-tree .reference-file .count{margin-left:auto;margin-right:12px}.monaco-editor .reference-zone-widget .ref-tree .referenceMatch .highlight{background-color:var(--vscode-peekViewResult-matchHighlightBackground)}.monaco-editor .reference-zone-widget .preview .reference-decoration{background-color:var(--vscode-peekViewEditor-matchHighlightBackground);border:2px solid var(--vscode-peekViewEditor-matchHighlightBorder);box-sizing:border-box}.monaco-editor .reference-zone-widget .preview .monaco-editor .inputarea.ime-input,.monaco-editor .reference-zone-widget .preview .monaco-editor .monaco-editor-background{background-color:var(--vscode-peekViewEditor-background)}.monaco-editor .reference-zone-widget .preview .monaco-editor .margin{background-color:var(--vscode-peekViewEditorGutter-background)}.monaco-editor.hc-black .reference-zone-widget .ref-tree .reference-file,.monaco-editor.hc-light .reference-zone-widget .ref-tree .reference-file{font-weight:700}.monaco-editor.hc-black .reference-zone-widget .ref-tree .referenceMatch .highlight,.monaco-editor.hc-light .reference-zone-widget .ref-tree .referenceMatch .highlight{border:1px dotted var(--vscode-contrastActiveBorder,#0000);box-sizing:border-box}.monaco-editor .hoverHighlight{background-color:var(--vscode-editor-hoverHighlightBackground)}.monaco-editor .monaco-hover-content{box-sizing:border-box;padding-bottom:2px;padding-right:2px}.monaco-editor .monaco-hover{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);border-radius:3px;color:var(--vscode-editorHoverWidget-foreground)}.monaco-editor .monaco-hover a{color:var(--vscode-textLink-foreground)}.monaco-editor .monaco-hover a:hover{color:var(--vscode-textLink-activeForeground)}.monaco-editor .monaco-hover .hover-row{display:flex}.monaco-editor .monaco-hover .hover-row .hover-row-contents{display:flex;flex-direction:column;min-width:0}.monaco-editor .monaco-hover .hover-row .verbosity-actions{border-right:1px solid var(--vscode-editorHoverWidget-border);display:flex;flex-direction:column;justify-content:end;padding-left:5px;padding-right:5px}.monaco-editor .monaco-hover .hover-row .verbosity-actions .codicon{cursor:pointer;font-size:11px}.monaco-editor .monaco-hover .hover-row .verbosity-actions .codicon.enabled{color:var(--vscode-textLink-foreground)}.monaco-editor .monaco-hover .hover-row .verbosity-actions .codicon.disabled{opacity:.6}.monaco-editor .monaco-hover .hover-row .actions{background-color:var(--vscode-editorHoverWidget-statusBarBackground)}.monaco-editor .monaco-hover code{background-color:var(--vscode-textCodeBlock-background)}.monaco-editor.vs .valueSetReplacement{outline:solid 2px var(--vscode-editorBracketMatch-border)}.monaco-editor .inlineSuggestionsHints.withBorder{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);z-index:39}.monaco-editor .inlineSuggestionsHints a,.monaco-editor .inlineSuggestionsHints a:hover{color:var(--vscode-foreground)}.monaco-editor .inlineSuggestionsHints .keybinding{display:flex;margin-left:4px;opacity:.6}.monaco-editor .inlineSuggestionsHints .keybinding .monaco-keybinding-key{font-size:8px;padding:2px 3px}.monaco-editor .inlineSuggestionsHints .availableSuggestionCount a{display:flex;justify-content:center;min-width:19px}.monaco-editor .inlineSuggestionStatusBarItemLabel{margin-right:2px}.monaco-editor .suggest-preview-additional-widget{white-space:nowrap}.monaco-editor .suggest-preview-additional-widget .content-spacer{color:#0000;white-space:pre}.monaco-editor .suggest-preview-additional-widget .button{cursor:pointer;display:inline-block;text-decoration:underline;text-underline-position:under}.monaco-editor .ghost-text-hidden{font-size:0;opacity:0}.monaco-editor .ghost-text-decoration,.monaco-editor .suggest-preview-text .ghost-text{font-style:italic}.monaco-editor .ghost-text-decoration,.monaco-editor .ghost-text-decoration-preview,.monaco-editor .suggest-preview-text .ghost-text{background-color:var(--vscode-editorGhostText-background);border:1px solid var(--vscode-editorGhostText-border);color:var(--vscode-editorGhostText-foreground)!important}.monaco-editor .inline-edit-remove{background-color:var(--vscode-editorGhostText-background);font-style:italic}.monaco-editor .inline-edit-hidden{font-size:0;opacity:0}.monaco-editor .inline-edit-decoration,.monaco-editor .suggest-preview-text .inline-edit{font-style:italic}.monaco-editor .inline-completion-text-to-replace{text-decoration:underline;text-underline-position:under}.monaco-editor .inline-edit-decoration,.monaco-editor .inline-edit-decoration-preview,.monaco-editor .suggest-preview-text .inline-edit{background-color:var(--vscode-editorGhostText-background);border:1px solid var(--vscode-editorGhostText-border);color:var(--vscode-editorGhostText-foreground)!important}.monaco-editor .inlineEditHints.withBorder{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);z-index:39}.monaco-editor .inlineEditHints a,.monaco-editor .inlineEditHints a:hover{color:var(--vscode-foreground)}.monaco-editor .inlineEditHints .keybinding{display:flex;margin-left:4px;opacity:.6}.monaco-editor .inlineEditHints .keybinding .monaco-keybinding-key{font-size:8px;padding:2px 3px}.monaco-editor .inlineEditStatusBarItemLabel{margin-right:2px}.monaco-editor .inlineEditSideBySide{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);white-space:pre;z-index:39}.monaco-editor div.inline-edits-widget{--widget-color:var(--vscode-notifications-background)}.monaco-editor div.inline-edits-widget .promptEditor .monaco-editor{--vscode-editor-placeholder-foreground:var(--vscode-editorGhostText-foreground)}.monaco-editor div.inline-edits-widget .promptEditor,.monaco-editor div.inline-edits-widget .toolbar{opacity:0;transition:opacity .2s ease-in-out}.monaco-editor div.inline-edits-widget.focused .promptEditor,.monaco-editor div.inline-edits-widget.focused .toolbar,.monaco-editor div.inline-edits-widget:hover .promptEditor,.monaco-editor div.inline-edits-widget:hover .toolbar{opacity:1}.monaco-editor div.inline-edits-widget .preview .monaco-editor{--vscode-editor-background:var(--widget-color)}.monaco-editor div.inline-edits-widget .preview .monaco-editor .mtk1{color:var(--vscode-editorGhostText-foreground)}.monaco-editor div.inline-edits-widget .preview .monaco-editor .current-line-margin,.monaco-editor div.inline-edits-widget .preview .monaco-editor .view-overlays .current-line-exact{border:none}.monaco-editor div.inline-edits-widget svg .gradient-start{stop-color:var(--vscode-editor-background)}.monaco-editor div.inline-edits-widget svg .gradient-stop{stop-color:var(--widget-color)}.inline-editor-progress-decoration{display:inline-block;height:1em;width:1em}.inline-progress-widget{align-items:center;display:flex!important;justify-content:center}.inline-progress-widget .icon{font-size:80%!important}.inline-progress-widget:hover .icon{animation:none;font-size:90%!important}.inline-progress-widget:hover .icon:before{content:var(--vscode-icon-x-content);font-family:var(--vscode-icon-x-font-family)}.monaco-editor .linked-editing-decoration{background-color:var(--vscode-editor-linkedEditingBackground);min-width:1px}.monaco-editor .detected-link,.monaco-editor .detected-link-active{text-decoration:underline;text-underline-position:under}.monaco-editor .detected-link-active{color:var(--vscode-editorLink-activeForeground)!important;cursor:pointer}.monaco-editor .monaco-editor-overlaymessage{padding-bottom:8px;z-index:10000}.monaco-editor .monaco-editor-overlaymessage.below{padding-bottom:0;padding-top:8px;z-index:10000}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.monaco-editor .monaco-editor-overlaymessage.fadeIn{animation:fadeIn .15s ease-out}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.monaco-editor .monaco-editor-overlaymessage.fadeOut{animation:fadeOut .1s ease-out}.monaco-editor .monaco-editor-overlaymessage .message{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-inputValidation-infoBorder);border-radius:3px;color:var(--vscode-editorHoverWidget-foreground);padding:2px 4px}.monaco-editor .monaco-editor-overlaymessage .message p{margin-block:0}.monaco-editor .monaco-editor-overlaymessage .message a{color:var(--vscode-textLink-foreground)}.monaco-editor .monaco-editor-overlaymessage .message a:hover{color:var(--vscode-textLink-activeForeground)}.monaco-editor.hc-black .monaco-editor-overlaymessage .message,.monaco-editor.hc-light .monaco-editor-overlaymessage .message{border-width:2px}.monaco-editor .monaco-editor-overlaymessage .anchor{border:8px solid #0000;height:0!important;left:2px;position:absolute;width:0!important;z-index:1000}.monaco-editor .monaco-editor-overlaymessage .anchor.top{border-bottom-color:var(--vscode-inputValidation-infoBorder)}.monaco-editor .monaco-editor-overlaymessage .anchor.below{border-top-color:var(--vscode-inputValidation-infoBorder)}.monaco-editor .monaco-editor-overlaymessage.below .anchor.below,.monaco-editor .monaco-editor-overlaymessage:not(.below) .anchor.top{display:none}.monaco-editor .monaco-editor-overlaymessage.below .anchor.top{display:inherit;top:-8px}.monaco-editor .parameter-hints-widget{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);cursor:default;display:flex;flex-direction:column;line-height:1.5em;z-index:39}.hc-black .monaco-editor .parameter-hints-widget,.hc-light .monaco-editor .parameter-hints-widget{border-width:2px}.monaco-editor .parameter-hints-widget>.phwrapper{display:flex;flex-direction:row;max-width:440px}.monaco-editor .parameter-hints-widget.multiple{min-height:3.3em;padding:0}.monaco-editor .parameter-hints-widget.multiple .body:before{border-left:1px solid var(--vscode-editorHoverWidget-border);content:"";display:block;height:100%;opacity:.5;position:absolute}.monaco-editor .parameter-hints-widget p,.monaco-editor .parameter-hints-widget ul{margin:8px 0}.monaco-editor .parameter-hints-widget .body,.monaco-editor .parameter-hints-widget .monaco-scrollable-element{display:flex;flex:1 1;flex-direction:column;min-height:100%}.monaco-editor .parameter-hints-widget .signature{padding:4px 5px;position:relative}.monaco-editor .parameter-hints-widget .signature.has-docs:after{border-bottom:1px solid var(--vscode-editorHoverWidget-border);content:"";display:block;left:0;opacity:.5;padding-top:4px;position:absolute;width:100%}.monaco-editor .parameter-hints-widget .code{font-family:var(--vscode-parameterHintsWidget-editorFontFamily),var(--vscode-parameterHintsWidget-editorFontFamilyDefault)}.monaco-editor .parameter-hints-widget .docs{padding:0 10px 0 5px;white-space:pre-wrap}.monaco-editor .parameter-hints-widget .docs.empty{display:none}.monaco-editor .parameter-hints-widget .docs a{color:var(--vscode-textLink-foreground)}.monaco-editor .parameter-hints-widget .docs a:hover{color:var(--vscode-textLink-activeForeground);cursor:pointer}.monaco-editor .parameter-hints-widget .docs .markdown-docs{white-space:normal}.monaco-editor .parameter-hints-widget .docs code{background-color:var(--vscode-textCodeBlock-background);border-radius:3px;font-family:var(--monaco-monospace-font);padding:0 .4em}.monaco-editor .parameter-hints-widget .docs .code,.monaco-editor .parameter-hints-widget .docs .monaco-tokenized-source{white-space:pre-wrap}.monaco-editor .parameter-hints-widget .controls{align-items:center;display:none;flex-direction:column;justify-content:flex-end;min-width:22px}.monaco-editor .parameter-hints-widget.multiple .controls{display:flex;padding:0 2px}.monaco-editor .parameter-hints-widget.multiple .button{background-repeat:no-repeat;cursor:pointer;height:16px;width:16px}.monaco-editor .parameter-hints-widget .button.previous{bottom:24px}.monaco-editor .parameter-hints-widget .overloads{font-family:var(--monaco-monospace-font);height:12px;line-height:12px;text-align:center}.monaco-editor .parameter-hints-widget .signature .parameter.active{color:var(--vscode-editorHoverWidget-highlightForeground);font-weight:700}.monaco-editor .parameter-hints-widget .documentation-parameter>.parameter{font-weight:700;margin-right:.5em}.monaco-editor .peekview-widget .head{box-sizing:border-box;display:flex;flex-wrap:nowrap;justify-content:space-between}.monaco-editor .peekview-widget .head .peekview-title{align-items:baseline;display:flex;font-size:13px;margin-left:20px;min-width:0;overflow:hidden;text-overflow:ellipsis}.monaco-editor .peekview-widget .head .peekview-title.clickable{cursor:pointer}.monaco-editor .peekview-widget .head .peekview-title .dirname:not(:empty){font-size:.9em;margin-left:.5em}.monaco-editor .peekview-widget .head .peekview-title .dirname,.monaco-editor .peekview-widget .head .peekview-title .filename,.monaco-editor .peekview-widget .head .peekview-title .meta{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.monaco-editor .peekview-widget .head .peekview-title .meta:not(:empty):before{content:"-";padding:0 .3em}.monaco-editor .peekview-widget .head .peekview-actions{flex:1 1;padding-right:2px;text-align:right}.monaco-editor .peekview-widget .head .peekview-actions>.monaco-action-bar{display:inline-block}.monaco-editor .peekview-widget .head .peekview-actions>.monaco-action-bar,.monaco-editor .peekview-widget .head .peekview-actions>.monaco-action-bar>.actions-container{height:100%}.monaco-editor .peekview-widget>.body{border-top:1px solid;position:relative}.monaco-editor .peekview-widget .head .peekview-title .codicon{align-self:center;margin-right:4px}.monaco-editor .peekview-widget .monaco-list .monaco-list-row.focused .codicon{color:inherit!important}.monaco-editor{--vscode-editor-placeholder-foreground:var(--vscode-editorGhostText-foreground)}.monaco-editor .editorPlaceholder{text-wrap:nowrap;color:var(--vscode-editor-placeholder-foreground);overflow:hidden;pointer-events:none;position:absolute;text-overflow:ellipsis;top:0}.monaco-editor .rename-box{border-radius:4px;color:inherit;z-index:100}.monaco-editor .rename-box.preview{padding:4px 4px 0}.monaco-editor .rename-box .rename-input-with-button{border-radius:2px;padding:3px;width:calc(100% - 8px)}.monaco-editor .rename-box .rename-input{padding:0;width:calc(100% - 8px)}.monaco-editor .rename-box .rename-input:focus{outline:none}.monaco-editor .rename-box .rename-suggestions-button{align-items:center;background-color:initial;border:none;border-radius:5px;cursor:pointer;display:flex;padding:3px}.monaco-editor .rename-box .rename-suggestions-button:hover{background-color:var(--vscode-toolbar-hoverBackground)}.monaco-editor .rename-box .rename-candidate-list-container .monaco-list-row{border-radius:2px}.monaco-editor .rename-box .rename-label{display:none;opacity:.8}.monaco-editor .rename-box.preview .rename-label{display:inherit}.monaco-editor .snippet-placeholder{background-color:var(--vscode-editor-snippetTabstopHighlightBackground,#0000);min-width:2px;outline-color:var(--vscode-editor-snippetTabstopHighlightBorder,#0000);outline-style:solid;outline-width:1px}.monaco-editor .finish-snippet-placeholder{background-color:var(--vscode-editor-snippetFinalTabstopHighlightBackground,#0000);outline-color:var(--vscode-editor-snippetFinalTabstopHighlightBorder,#0000);outline-style:solid;outline-width:1px}.monaco-editor .sticky-widget{overflow:hidden}.monaco-editor .sticky-widget-line-numbers{background-color:inherit;float:left}.monaco-editor .sticky-widget-lines-scrollable{background-color:inherit;display:inline-block;overflow:hidden;position:absolute;width:var(--vscode-editorStickyScroll-scrollableWidth)}.monaco-editor .sticky-widget-lines{background-color:inherit;position:absolute}.monaco-editor .sticky-line-content,.monaco-editor .sticky-line-number{background-color:inherit;color:var(--vscode-editorLineNumber-foreground);display:inline-block;position:absolute;white-space:nowrap}.monaco-editor .sticky-line-number .codicon-folding-collapsed,.monaco-editor .sticky-line-number .codicon-folding-expanded{float:right;transition:var(--vscode-editorStickyScroll-foldingOpacityTransition)}.monaco-editor .sticky-line-content{background-color:inherit;white-space:nowrap;width:var(--vscode-editorStickyScroll-scrollableWidth)}.monaco-editor .sticky-line-number-inner{display:inline-block;text-align:right}.monaco-editor .sticky-widget{border-bottom:1px solid var(--vscode-editorStickyScroll-border)}.monaco-editor .sticky-line-content:hover{background-color:var(--vscode-editorStickyScrollHover-background);cursor:pointer}.monaco-editor .sticky-widget{background-color:var(--vscode-editorStickyScroll-background);box-shadow:var(--vscode-editorStickyScroll-shadow) 0 4px 2px -2px;right:auto!important;width:100%;z-index:4}.monaco-editor .sticky-widget.peek{background-color:var(--vscode-peekViewEditorStickyScroll-background)}.monaco-editor .suggest-widget{border-radius:3px;display:flex;flex-direction:column;width:430px;z-index:40}.monaco-editor .suggest-widget.message{align-items:center;flex-direction:row}.monaco-editor .suggest-details,.monaco-editor .suggest-widget{background-color:var(--vscode-editorSuggestWidget-background);border-color:var(--vscode-editorSuggestWidget-border);border-style:solid;border-width:1px;flex:0 1 auto;width:100%}.monaco-editor.hc-black .suggest-details,.monaco-editor.hc-black .suggest-widget,.monaco-editor.hc-light .suggest-details,.monaco-editor.hc-light .suggest-widget{border-width:2px}.monaco-editor .suggest-widget .suggest-status-bar{border-top:1px solid var(--vscode-editorSuggestWidget-border);box-sizing:border-box;display:none;flex-flow:row nowrap;font-size:80%;justify-content:space-between;overflow:hidden;padding:0 4px;width:100%}.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar{display:flex}.monaco-editor .suggest-widget .suggest-status-bar .left{padding-right:8px}.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar .action-label{color:var(--vscode-editorSuggestWidgetStatus-foreground)}.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar .action-item:not(:last-of-type) .action-label{margin-right:0}.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar .action-item:not(:last-of-type) .action-label:after{content:", ";margin-right:.3em}.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused.string-label>.contents>.main>.right>.readMore,.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row>.contents>.main>.right>.readMore{display:none}.monaco-editor .suggest-widget.with-status-bar:not(.docs-side) .monaco-list .monaco-list-row:hover>.contents>.main>.right.can-expand-details>.details-label{width:100%}.monaco-editor .suggest-widget>.message{padding-left:22px}.monaco-editor .suggest-widget>.tree{height:100%;width:100%}.monaco-editor .suggest-widget .monaco-list{user-select:none;-webkit-user-select:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row{background-position:2px 2px;background-repeat:no-repeat;-mox-box-sizing:border-box;box-sizing:border-box;cursor:pointer;display:flex;padding-right:10px;touch-action:none;white-space:nowrap}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused{color:var(--vscode-editorSuggestWidget-selectedForeground)}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused .codicon{color:var(--vscode-editorSuggestWidget-selectedIconForeground)}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents{flex:1 1;height:100%;overflow:hidden;padding-left:2px}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main{display:flex;justify-content:space-between;overflow:hidden;text-overflow:ellipsis;white-space:pre}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left,.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right{display:flex}.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.focused)>.contents>.main .monaco-icon-label{color:var(--vscode-editorSuggestWidget-foreground)}.monaco-editor .suggest-widget:not(.frozen) .monaco-highlighted-label .highlight{font-weight:700}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main .monaco-highlighted-label .highlight{color:var(--vscode-editorSuggestWidget-highlightForeground)}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused>.contents>.main .monaco-highlighted-label .highlight{color:var(--vscode-editorSuggestWidget-focusHighlightForeground)}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close,.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore:before{color:inherit;cursor:pointer;font-size:14px;opacity:1}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close{position:absolute;right:2px;top:6px}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close:hover,.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore:hover{opacity:1}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label{opacity:.7}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.signature-label{opacity:.6;overflow:hidden;text-overflow:ellipsis}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.qualifier-label{align-self:center;font-size:85%;line-height:normal;margin-left:12px;opacity:.4;overflow:hidden;text-overflow:ellipsis}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label{font-size:85%;margin-left:1.1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label>.monaco-tokenized-source{display:inline}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label{display:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.right>.details-label,.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label)>.contents>.main>.right>.details-label,.monaco-editor .suggest-widget:not(.shows-details) .monaco-list .monaco-list-row.focused>.contents>.main>.right>.details-label{display:inline}.monaco-editor .suggest-widget:not(.docs-side) .monaco-list .monaco-list-row.focused:hover>.contents>.main>.right.can-expand-details>.details-label{width:calc(100% - 26px)}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left{flex-grow:1;flex-shrink:1;overflow:hidden}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.monaco-icon-label{flex-shrink:0}.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.left>.monaco-icon-label{max-width:100%}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label>.contents>.main>.left>.monaco-icon-label{flex-shrink:1}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right{flex-shrink:4;max-width:70%;overflow:hidden}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore{display:inline-block;height:18px;position:absolute;right:10px;visibility:hidden;width:18px}.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row>.contents>.main>.right>.readMore{display:none!important}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label>.contents>.main>.right>.readMore{display:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused.string-label>.contents>.main>.right>.readMore{display:inline-block}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused:hover>.contents>.main>.right>.readMore{visibility:visible}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated{opacity:.66;text-decoration:unset}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated>.monaco-icon-label-container>.monaco-icon-name-container{text-decoration:line-through}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label:before{height:100%}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon{background-position:50%;background-repeat:no-repeat;background-size:80%;display:block;height:16px;margin-left:2px;width:16px}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.hide{display:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon{align-items:center;display:flex;margin-right:4px}.monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .icon,.monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .suggest-icon:before{display:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.customcolor .colorspan{border:.1em solid #000;display:inline-block;height:.7em;margin:0 0 0 .3em;width:.7em}.monaco-editor .suggest-details-container{z-index:41}.monaco-editor .suggest-details{color:var(--vscode-editorSuggestWidget-foreground);cursor:default;display:flex;flex-direction:column}.monaco-editor .suggest-details.focused{border-color:var(--vscode-focusBorder)}.monaco-editor .suggest-details a{color:var(--vscode-textLink-foreground)}.monaco-editor .suggest-details a:hover{color:var(--vscode-textLink-activeForeground)}.monaco-editor .suggest-details code{background-color:var(--vscode-textCodeBlock-background)}.monaco-editor .suggest-details.no-docs{display:none}.monaco-editor .suggest-details>.monaco-scrollable-element{flex:1 1}.monaco-editor .suggest-details>.monaco-scrollable-element>.body{box-sizing:border-box;height:100%;width:100%}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.type{flex:2 1;margin:0 24px 0 0;opacity:.7;overflow:hidden;padding:4px 0 12px 5px;text-overflow:ellipsis;white-space:pre}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.type.auto-wrap{white-space:normal;word-break:break-all}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs{margin:0;padding:4px 5px;white-space:pre-wrap}.monaco-editor .suggest-details.no-type>.monaco-scrollable-element>.body>.docs{margin-right:24px;overflow:hidden}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs{min-height:calc(1rem + 8px);padding:0;white-space:normal}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div,.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>span:not(:empty){padding:4px 5px}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div>p:first-child{margin-top:0}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div>p:last-child{margin-bottom:0}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs .monaco-tokenized-source{white-space:pre}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs .code{word-wrap:break-word;white-space:pre-wrap}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs .codicon{vertical-align:sub}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>p:empty{display:none}.monaco-editor .suggest-details code{border-radius:3px;padding:0 .4em}.monaco-editor .suggest-details ol,.monaco-editor .suggest-details ul{padding-left:20px}.monaco-editor .suggest-details p code{font-family:var(--monaco-monospace-font)}.monaco-editor .codicon.codicon-symbol-array,.monaco-workbench .codicon.codicon-symbol-array{color:var(--vscode-symbolIcon-arrayForeground)}.monaco-editor .codicon.codicon-symbol-boolean,.monaco-workbench .codicon.codicon-symbol-boolean{color:var(--vscode-symbolIcon-booleanForeground)}.monaco-editor .codicon.codicon-symbol-class,.monaco-workbench .codicon.codicon-symbol-class{color:var(--vscode-symbolIcon-classForeground)}.monaco-editor .codicon.codicon-symbol-method,.monaco-workbench .codicon.codicon-symbol-method{color:var(--vscode-symbolIcon-methodForeground)}.monaco-editor .codicon.codicon-symbol-color,.monaco-workbench .codicon.codicon-symbol-color{color:var(--vscode-symbolIcon-colorForeground)}.monaco-editor .codicon.codicon-symbol-constant,.monaco-workbench .codicon.codicon-symbol-constant{color:var(--vscode-symbolIcon-constantForeground)}.monaco-editor .codicon.codicon-symbol-constructor,.monaco-workbench .codicon.codicon-symbol-constructor{color:var(--vscode-symbolIcon-constructorForeground)}.monaco-editor .codicon.codicon-symbol-enum,.monaco-editor .codicon.codicon-symbol-value,.monaco-workbench .codicon.codicon-symbol-enum,.monaco-workbench .codicon.codicon-symbol-value{color:var(--vscode-symbolIcon-enumeratorForeground)}.monaco-editor .codicon.codicon-symbol-enum-member,.monaco-workbench .codicon.codicon-symbol-enum-member{color:var(--vscode-symbolIcon-enumeratorMemberForeground)}.monaco-editor .codicon.codicon-symbol-event,.monaco-workbench .codicon.codicon-symbol-event{color:var(--vscode-symbolIcon-eventForeground)}.monaco-editor .codicon.codicon-symbol-field,.monaco-workbench .codicon.codicon-symbol-field{color:var(--vscode-symbolIcon-fieldForeground)}.monaco-editor .codicon.codicon-symbol-file,.monaco-workbench .codicon.codicon-symbol-file{color:var(--vscode-symbolIcon-fileForeground)}.monaco-editor .codicon.codicon-symbol-folder,.monaco-workbench .codicon.codicon-symbol-folder{color:var(--vscode-symbolIcon-folderForeground)}.monaco-editor .codicon.codicon-symbol-function,.monaco-workbench .codicon.codicon-symbol-function{color:var(--vscode-symbolIcon-functionForeground)}.monaco-editor .codicon.codicon-symbol-interface,.monaco-workbench .codicon.codicon-symbol-interface{color:var(--vscode-symbolIcon-interfaceForeground)}.monaco-editor .codicon.codicon-symbol-key,.monaco-workbench .codicon.codicon-symbol-key{color:var(--vscode-symbolIcon-keyForeground)}.monaco-editor .codicon.codicon-symbol-keyword,.monaco-workbench .codicon.codicon-symbol-keyword{color:var(--vscode-symbolIcon-keywordForeground)}.monaco-editor .codicon.codicon-symbol-module,.monaco-workbench .codicon.codicon-symbol-module{color:var(--vscode-symbolIcon-moduleForeground)}.monaco-editor .codicon.codicon-symbol-namespace,.monaco-workbench .codicon.codicon-symbol-namespace{color:var(--vscode-symbolIcon-namespaceForeground)}.monaco-editor .codicon.codicon-symbol-null,.monaco-workbench .codicon.codicon-symbol-null{color:var(--vscode-symbolIcon-nullForeground)}.monaco-editor .codicon.codicon-symbol-number,.monaco-workbench .codicon.codicon-symbol-number{color:var(--vscode-symbolIcon-numberForeground)}.monaco-editor .codicon.codicon-symbol-object,.monaco-workbench .codicon.codicon-symbol-object{color:var(--vscode-symbolIcon-objectForeground)}.monaco-editor .codicon.codicon-symbol-operator,.monaco-workbench .codicon.codicon-symbol-operator{color:var(--vscode-symbolIcon-operatorForeground)}.monaco-editor .codicon.codicon-symbol-package,.monaco-workbench .codicon.codicon-symbol-package{color:var(--vscode-symbolIcon-packageForeground)}.monaco-editor .codicon.codicon-symbol-property,.monaco-workbench .codicon.codicon-symbol-property{color:var(--vscode-symbolIcon-propertyForeground)}.monaco-editor .codicon.codicon-symbol-reference,.monaco-workbench .codicon.codicon-symbol-reference{color:var(--vscode-symbolIcon-referenceForeground)}.monaco-editor .codicon.codicon-symbol-snippet,.monaco-workbench .codicon.codicon-symbol-snippet{color:var(--vscode-symbolIcon-snippetForeground)}.monaco-editor .codicon.codicon-symbol-string,.monaco-workbench .codicon.codicon-symbol-string{color:var(--vscode-symbolIcon-stringForeground)}.monaco-editor .codicon.codicon-symbol-struct,.monaco-workbench .codicon.codicon-symbol-struct{color:var(--vscode-symbolIcon-structForeground)}.monaco-editor .codicon.codicon-symbol-text,.monaco-workbench .codicon.codicon-symbol-text{color:var(--vscode-symbolIcon-textForeground)}.monaco-editor .codicon.codicon-symbol-type-parameter,.monaco-workbench .codicon.codicon-symbol-type-parameter{color:var(--vscode-symbolIcon-typeParameterForeground)}.monaco-editor .codicon.codicon-symbol-unit,.monaco-workbench .codicon.codicon-symbol-unit{color:var(--vscode-symbolIcon-unitForeground)}.monaco-editor .codicon.codicon-symbol-variable,.monaco-workbench .codicon.codicon-symbol-variable{color:var(--vscode-symbolIcon-variableForeground)}.editor-banner{background:var(--vscode-banner-background);box-sizing:border-box;cursor:default;display:flex;font-size:12px;height:26px;overflow:visible;width:100%}.editor-banner .icon-container{align-items:center;display:flex;flex-shrink:0;padding:0 6px 0 10px}.editor-banner .icon-container.custom-icon{background-position:50%;background-repeat:no-repeat;background-size:16px;margin:0 6px 0 10px;padding:0;width:16px}.editor-banner .message-container{align-items:center;display:flex;line-height:26px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.editor-banner .message-container p{margin-block-end:0;margin-block-start:0}.editor-banner .message-actions-container{flex-grow:1;flex-shrink:0;line-height:26px;margin:0 4px}.editor-banner .message-actions-container a.monaco-button{margin:2px 8px;padding:0 12px;width:inherit}.editor-banner .message-actions-container a{margin-left:12px;padding:3px;text-decoration:underline}.editor-banner .action-container{padding:0 10px 0 6px}.editor-banner{background-color:var(--vscode-banner-background)}.editor-banner,.editor-banner .action-container .codicon,.editor-banner .message-actions-container .monaco-link{color:var(--vscode-banner-foreground)}.editor-banner .icon-container .codicon{color:var(--vscode-banner-iconForeground)}.monaco-editor .unicode-highlight{background-color:var(--vscode-editorUnicodeHighlight-background);border:1px solid var(--vscode-editorUnicodeHighlight-border);box-sizing:border-box}.monaco-editor .focused .selectionHighlight{background-color:var(--vscode-editor-selectionHighlightBackground);border:1px solid var(--vscode-editor-selectionHighlightBorder);box-sizing:border-box}.monaco-editor.hc-black .focused .selectionHighlight,.monaco-editor.hc-light .focused .selectionHighlight{border-style:dotted}.monaco-editor .wordHighlight{background-color:var(--vscode-editor-wordHighlightBackground);border:1px solid var(--vscode-editor-wordHighlightBorder);box-sizing:border-box}.monaco-editor.hc-black .wordHighlight,.monaco-editor.hc-light .wordHighlight{border-style:dotted}.monaco-editor .wordHighlightStrong{background-color:var(--vscode-editor-wordHighlightStrongBackground);border:1px solid var(--vscode-editor-wordHighlightStrongBorder);box-sizing:border-box}.monaco-editor.hc-black .wordHighlightStrong,.monaco-editor.hc-light .wordHighlightStrong{border-style:dotted}.monaco-editor .wordHighlightText{background-color:var(--vscode-editor-wordHighlightTextBackground);border:1px solid var(--vscode-editor-wordHighlightTextBorder);box-sizing:border-box}.monaco-editor.hc-black .wordHighlightText,.monaco-editor.hc-light .wordHighlightText{border-style:dotted}.monaco-editor .zone-widget{position:absolute;z-index:10}.monaco-editor .zone-widget .zone-widget-container{border-bottom-style:solid;border-bottom-width:0;border-top-style:solid;border-top-width:0;position:relative}.monaco-editor .iPadShowKeyboard{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MyIgaGVpZ2h0PSIzNiIgZmlsbD0ibm9uZSI+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBmaWxsPSIjNDI0MjQyIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00OC4wMzYgNC4wMUg0LjAwOHYyOC4wMmg0NC4wMjh6TTQuMDA4LjAwOEE0LjAwMyA0LjAwMyAwIDAgMCAuMDA1IDQuMDF2MjguMDJhNC4wMDMgNC4wMDMgMCAwIDAgNC4wMDMgNC4wMDJoNDQuMDI4YTQuMDAzIDQuMDAzIDAgMCAwIDQuMDAzLTQuMDAyVjQuMDFBNC4wMDMgNC4wMDMgMCAwIDAgNDguMDM2LjAwOHpNOC4wMSA4LjAxM2g0LjAwM3Y0LjAwM0g4LjAxem0xMi4wMDggMGgtNC4wMDJ2NC4wMDNoNC4wMDJ6bTQuMDAzIDBoNC4wMDJ2NC4wMDNoLTQuMDAyem0xMi4wMDggMGgtNC4wMDN2NC4wMDNoNC4wMDN6bTQuMDAyIDBoNC4wMDN2NC4wMDNINDAuMDN6bS0yNC4wMTUgOC4wMDVIOC4wMXY0LjAwM2g4LjAwNnptNC4wMDIgMGg0LjAwM3Y0LjAwM2gtNC4wMDN6bTEyLjAwOCAwaC00LjAwM3Y0LjAwM2g0LjAwM3ptMTIuMDA4IDB2NC4wMDNoLTguMDA1di00LjAwM3ptLTMyLjAyMSA4LjAwNUg4LjAxdjQuMDAzaDQuMDAzem00LjAwMyAwaDIwLjAxM3Y0LjAwM0gxNi4wMTZ6bTI4LjAxOCAwSDQwLjAzdjQuMDAzaDQuMDAzeiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9nPjxkZWZzPjxjbGlwUGF0aCBpZD0iYSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTAgMGg1M3YzNkgweiIvPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg==) 50% no-repeat;border:4px solid #f6f6f6;border-radius:4px;height:36px;margin:0;min-height:0;min-width:0;overflow:hidden;padding:0;position:absolute;resize:none;width:58px}.monaco-editor.vs-dark .iPadShowKeyboard{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MyIgaGVpZ2h0PSIzNiIgZmlsbD0ibm9uZSI+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBmaWxsPSIjQzVDNUM1IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00OC4wMzYgNC4wMUg0LjAwOHYyOC4wMmg0NC4wMjh6TTQuMDA4LjAwOEE0LjAwMyA0LjAwMyAwIDAgMCAuMDA1IDQuMDF2MjguMDJhNC4wMDMgNC4wMDMgMCAwIDAgNC4wMDMgNC4wMDJoNDQuMDI4YTQuMDAzIDQuMDAzIDAgMCAwIDQuMDAzLTQuMDAyVjQuMDFBNC4wMDMgNC4wMDMgMCAwIDAgNDguMDM2LjAwOHpNOC4wMSA4LjAxM2g0LjAwM3Y0LjAwM0g4LjAxem0xMi4wMDggMGgtNC4wMDJ2NC4wMDNoNC4wMDJ6bTQuMDAzIDBoNC4wMDJ2NC4wMDNoLTQuMDAyem0xMi4wMDggMGgtNC4wMDN2NC4wMDNoNC4wMDN6bTQuMDAyIDBoNC4wMDN2NC4wMDNINDAuMDN6bS0yNC4wMTUgOC4wMDVIOC4wMXY0LjAwM2g4LjAwNnptNC4wMDIgMGg0LjAwM3Y0LjAwM2gtNC4wMDN6bTEyLjAwOCAwaC00LjAwM3Y0LjAwM2g0LjAwM3ptMTIuMDA4IDB2NC4wMDNoLTguMDA1di00LjAwM3ptLTMyLjAyMSA4LjAwNUg4LjAxdjQuMDAzaDQuMDAzem00LjAwMyAwaDIwLjAxM3Y0LjAwM0gxNi4wMTZ6bTI4LjAxOCAwSDQwLjAzdjQuMDAzaDQuMDAzeiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9nPjxkZWZzPjxjbGlwUGF0aCBpZD0iYSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTAgMGg1M3YzNkgweiIvPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg==) 50% no-repeat;border:4px solid #252526}.monaco-editor .tokens-inspect-widget{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);padding:10px;user-select:text;-webkit-user-select:text;z-index:50}.monaco-editor.hc-black .tokens-inspect-widget,.monaco-editor.hc-light .tokens-inspect-widget{border-width:2px}.monaco-editor .tokens-inspect-widget .tokens-inspect-separator{background-color:var(--vscode-editorHoverWidget-border);border:0;height:1px}.monaco-editor .tokens-inspect-widget .tm-token{font-family:var(--monaco-monospace-font)}.monaco-editor .tokens-inspect-widget .tm-token-length{float:right;font-size:60%;font-weight:400}.monaco-editor .tokens-inspect-widget .tm-metadata-table{width:100%}.monaco-editor .tokens-inspect-widget .tm-metadata-value{font-family:var(--monaco-monospace-font);text-align:right}.monaco-editor .tokens-inspect-widget .tm-token-type{font-family:var(--monaco-monospace-font)}.quick-input-widget{font-size:13px}.quick-input-widget .monaco-highlighted-label .highlight{color:#0066bf}.vs .quick-input-widget .monaco-list-row.focused .monaco-highlighted-label .highlight{color:#9dddff}.vs-dark .quick-input-widget .monaco-highlighted-label .highlight{color:#0097fb}.hc-black .quick-input-widget .monaco-highlighted-label .highlight{color:#f38518}.hc-light .quick-input-widget .monaco-highlighted-label .highlight{color:#0f4a85}.monaco-keybinding>.monaco-keybinding-key{background-color:#dedede66;border:1px solid;border-color:#ccc6 #ccc6 #bababa66;box-shadow:inset 0 -1px 0 #bababa66;color:#555}.hc-black .monaco-keybinding>.monaco-keybinding-key{background-color:initial;border:1px solid #6fc3df;box-shadow:none;color:#fff}.hc-light .monaco-keybinding>.monaco-keybinding-key{background-color:initial;border:1px solid #0f4a85;box-shadow:none;color:#292929}.vs-dark .monaco-keybinding>.monaco-keybinding-key{background-color:#8080802b;border:1px solid;border-color:#3339 #3339 #4449;box-shadow:inset 0 -1px 0 #4449;color:#ccc}.monaco-editor{--monaco-monospace-font:"SF Mono",Monaco,Menlo,Consolas,"Ubuntu Mono","Liberation Mono","DejaVu Sans Mono","Courier New",monospace;font-family:-apple-system,BlinkMacSystemFont,Segoe WPC,Segoe UI,HelveticaNeue-Light,system-ui,Ubuntu,Droid Sans,sans-serif}.monaco-editor.hc-black .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-editor.hc-light .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-editor.vs-dark .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-menu .monaco-action-bar.vertical .action-item .action-menu-item:focus .action-label{stroke-width:1.2px}.monaco-hover p{margin:0}.monaco-aria-container{clip:rect(1px,1px,1px,1px);clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute!important;top:0;width:1px}.monaco-diff-editor .synthetic-focus,.monaco-diff-editor [tabindex="-1"]:focus,.monaco-diff-editor [tabindex="0"]:focus,.monaco-diff-editor button:focus,.monaco-diff-editor input[type=button]:focus,.monaco-diff-editor input[type=checkbox]:focus,.monaco-diff-editor input[type=search]:focus,.monaco-diff-editor input[type=text]:focus,.monaco-diff-editor select:focus,.monaco-diff-editor textarea:focus,.monaco-editor{opacity:1;outline-color:var(--vscode-focusBorder);outline-offset:-1px;outline-style:solid;outline-width:1px}.action-widget{background-color:var(--vscode-editorActionList-background);border:1px solid var(--vscode-editorWidget-border)!important;border-radius:0;border-radius:5px;box-shadow:0 2px 8px var(--vscode-widget-shadow);color:var(--vscode-editorActionList-foreground);display:block;font-size:13px;max-width:80vw;min-width:160px;padding:4px;width:100%;z-index:40}.context-view-block{z-index:-1}.context-view-block,.context-view-pointerBlock{cursor:auto;height:100%;left:0;position:fixed;top:0;width:100%}.context-view-pointerBlock{z-index:2}.action-widget .monaco-list{border:0!important;user-select:none;-webkit-user-select:none}.action-widget .monaco-list:focus:before{outline:0!important}.action-widget .monaco-list .monaco-scrollable-element{overflow:visible}.action-widget .monaco-list .monaco-list-row{border-radius:4px;cursor:pointer;padding:0 10px;touch-action:none;white-space:nowrap;width:100%}.action-widget .monaco-list .monaco-list-row.action.focused:not(.option-disabled){background-color:var(--vscode-editorActionList-focusBackground)!important;color:var(--vscode-editorActionList-focusForeground);outline:1px solid var(--vscode-menu-selectionBorder,#0000);outline-offset:-1px}.action-widget .monaco-list-row.group-header{color:var(--vscode-descriptionForeground)!important;font-size:12px;font-weight:600}.action-widget .monaco-list-row.group-header:not(:first-of-type){margin-top:2px}.action-widget .monaco-list .group-header,.action-widget .monaco-list .option-disabled,.action-widget .monaco-list .option-disabled .focused,.action-widget .monaco-list .option-disabled .focused:before,.action-widget .monaco-list .option-disabled:before{-webkit-touch-callout:none;background-color:initial!important;cursor:default!important;outline:0 solid!important;-webkit-user-select:none;user-select:none}.action-widget .monaco-list-row.action{align-items:center;display:flex;gap:8px}.action-widget .monaco-list-row.action.option-disabled,.action-widget .monaco-list-row.action.option-disabled .codicon,.action-widget .monaco-list:focus .monaco-list-row.focused.action.option-disabled,.action-widget .monaco-list:not(.drop-target):not(.dragging) .monaco-list-row:hover:not(.selected):not(.focused).option-disabled{color:var(--vscode-disabledForeground)}.action-widget .monaco-list-row.action:not(.option-disabled) .codicon{color:inherit}.action-widget .monaco-list-row.action .title{flex:1 1;overflow:hidden;text-overflow:ellipsis}.action-widget .monaco-list-row.action .monaco-keybinding>.monaco-keybinding-key{background-color:var(--vscode-keybindingLabel-background);border-color:var(--vscode-keybindingLabel-border);border-bottom:1px var(--vscode-keybindingLabel-bottomBorder);border-left-width:1px;border-radius:3px;border-right-width:1px;border-style:solid;border-top-width:1px;box-shadow:inset 0 -1px 0 var(--vscode-widget-shadow);color:var(--vscode-keybindingLabel-foreground)}.action-widget .action-widget-action-bar{background-color:var(--vscode-editorActionList-background);border-top:1px solid var(--vscode-editorHoverWidget-border);margin-top:2px}.action-widget .action-widget-action-bar:before{content:"";display:block;width:100%}.action-widget .action-widget-action-bar .actions-container{padding:3px 8px 0}.action-widget-action-bar .action-label{color:var(--vscode-textLink-activeForeground);font-size:12px;line-height:22px;padding:0;pointer-events:all}.action-widget-action-bar .action-item{margin-right:16px;pointer-events:none}.action-widget-action-bar .action-label:hover{background-color:initial!important}.monaco-action-bar .actions-container.highlight-toggled .action-label.checked{background:var(--vscode-actionBar-toggledBackground)!important}.monaco-action-bar .action-item.menu-entry .action-label.icon{background-position:50%;background-repeat:no-repeat;background-size:16px;height:16px;width:16px}.monaco-action-bar .action-item.menu-entry.text-only .action-label{border-radius:2px;color:var(--vscode-descriptionForeground);overflow:hidden}.monaco-action-bar .action-item.menu-entry.text-only.use-comma:not(:last-of-type) .action-label:after{content:", "}.monaco-action-bar .action-item.menu-entry.text-only+.action-item:not(.text-only)>.monaco-dropdown .action-label{color:var(--vscode-descriptionForeground)}.monaco-dropdown-with-default{border-radius:5px;display:flex!important;flex-direction:row}.monaco-dropdown-with-default>.action-container>.action-label{margin-right:0}.monaco-dropdown-with-default>.action-container.menu-entry>.action-label.icon{background-position:50%;background-repeat:no-repeat;background-size:16px;height:16px;width:16px}.monaco-dropdown-with-default:hover{background-color:var(--vscode-toolbar-hoverBackground)}.monaco-dropdown-with-default>.dropdown-action-container>.monaco-dropdown>.dropdown-label .codicon[class*=codicon-]{font-size:12px;line-height:16px;margin-left:-3px;padding-left:0;padding-right:0}.monaco-dropdown-with-default>.dropdown-action-container>.monaco-dropdown>.dropdown-label>.action-label{background-position:50%;background-repeat:no-repeat;background-size:16px;display:block}.monaco-link{color:var(--vscode-textLink-foreground)}.monaco-link:hover{color:var(--vscode-textLink-activeForeground)}.quick-input-widget{-webkit-app-region:no-drag;border-radius:6px;left:50%;margin-left:-300px;position:absolute;width:600px;z-index:2550}.quick-input-titlebar{align-items:center;border-top-left-radius:5px;border-top-right-radius:5px;display:flex}.quick-input-left-action-bar{display:flex;flex:1 1;margin-left:4px}.quick-input-inline-action-bar{margin:2px 0 0 5px}.quick-input-title{overflow:hidden;padding:3px 0;text-align:center;text-overflow:ellipsis}.quick-input-right-action-bar{display:flex;flex:1 1;margin-right:4px}.quick-input-right-action-bar>.actions-container{justify-content:flex-end}.quick-input-titlebar .monaco-action-bar .action-label.codicon{background-position:50%;background-repeat:no-repeat;padding:2px}.quick-input-description{margin:6px 6px 6px 11px}.quick-input-header .quick-input-description{flex:1 1;margin:4px 2px}.quick-input-header{display:flex;padding:8px 6px 2px}.quick-input-widget.hidden-input .quick-input-header{margin-bottom:0;padding:0}.quick-input-and-message{display:flex;flex-direction:column;flex-grow:1;min-width:0;position:relative}.quick-input-check-all{align-self:center;margin:0}.quick-input-filter{display:flex;flex-grow:1;position:relative}.quick-input-box{flex-grow:1}.quick-input-widget.show-checkboxes .quick-input-box,.quick-input-widget.show-checkboxes .quick-input-message{margin-left:5px}.quick-input-visible-count{left:-10000px;position:absolute}.quick-input-count{align-items:center;align-self:center;display:flex;position:absolute;right:4px}.quick-input-count .monaco-count-badge{border-radius:2px;line-height:normal;min-height:auto;padding:2px 4px;vertical-align:middle}.quick-input-action{margin-left:6px}.quick-input-action .monaco-text-button{align-items:center;display:flex;font-size:11px;height:25px;padding:0 6px}.quick-input-message{margin-top:-1px;overflow-wrap:break-word;padding:5px}.quick-input-message>.codicon{margin:0 .2em;vertical-align:text-bottom}.quick-input-message a{color:inherit}.quick-input-progress.monaco-progress-container{position:relative}.quick-input-list{line-height:22px}.quick-input-widget.hidden-input .quick-input-list{margin-top:4px;padding-bottom:4px}.quick-input-list .monaco-list{max-height:440px;overflow:hidden;padding-bottom:5px}.quick-input-list .monaco-scrollable-element{padding:0 5px}.quick-input-list .quick-input-list-entry{box-sizing:border-box;display:flex;overflow:hidden;padding:0 6px}.quick-input-list .quick-input-list-entry.quick-input-list-separator-border{border-top-style:solid;border-top-width:1px}.quick-input-list .monaco-list-row{border-radius:3px}.quick-input-list .monaco-list-row[data-index="0"] .quick-input-list-entry.quick-input-list-separator-border{border-top-style:none}.quick-input-list .quick-input-list-label{display:flex;flex:1 1;height:100%;overflow:hidden}.quick-input-list .quick-input-list-checkbox{align-self:center;margin:0}.quick-input-list .quick-input-list-icon{align-items:center;background-position:0;background-repeat:no-repeat;background-size:16px;display:flex;height:22px;justify-content:center;padding-right:6px;width:16px}.quick-input-list .quick-input-list-rows{display:flex;flex:1 1;flex-direction:column;height:100%;margin-left:5px;overflow:hidden;text-overflow:ellipsis}.quick-input-widget.show-checkboxes .quick-input-list .quick-input-list-rows{margin-left:10px}.quick-input-widget .quick-input-list .quick-input-list-checkbox{display:none}.quick-input-widget.show-checkboxes .quick-input-list .quick-input-list-checkbox{display:inline}.quick-input-list .quick-input-list-rows>.quick-input-list-row{align-items:center;display:flex}.quick-input-list .quick-input-list-rows>.quick-input-list-row .monaco-icon-label,.quick-input-list .quick-input-list-rows>.quick-input-list-row .monaco-icon-label .monaco-icon-label-container>.monaco-icon-name-container{flex:1 1}.quick-input-list .quick-input-list-rows>.quick-input-list-row .codicon[class*=codicon-]{vertical-align:text-bottom}.quick-input-list .quick-input-list-rows .monaco-highlighted-label>span{opacity:1}.quick-input-list .quick-input-list-entry .quick-input-list-entry-keybinding{margin-right:8px}.quick-input-list .quick-input-list-label-meta{line-height:normal;opacity:.7;overflow:hidden;text-overflow:ellipsis}.quick-input-list .monaco-list .monaco-list-row .monaco-highlighted-label .highlight{background-color:unset;color:var(--vscode-list-highlightForeground)!important;font-weight:700}.quick-input-list .monaco-list .monaco-list-row.focused .monaco-highlighted-label .highlight{color:var(--vscode-list-focusHighlightForeground)!important}.quick-input-list .quick-input-list-entry .quick-input-list-separator{margin-right:4px}.quick-input-list .quick-input-list-entry-action-bar{display:flex;flex:0 1;overflow:visible}.quick-input-list .quick-input-list-entry-action-bar .action-label{display:none}.quick-input-list .quick-input-list-entry-action-bar .action-label.codicon{margin-right:4px;padding:2px}.quick-input-list .quick-input-list-entry-action-bar{margin-right:4px;margin-top:1px}.quick-input-list .monaco-list-row.focused .quick-input-list-entry-action-bar .action-label,.quick-input-list .monaco-list-row.passive-focused .quick-input-list-entry-action-bar .action-label,.quick-input-list .quick-input-list-entry .quick-input-list-entry-action-bar .action-label.always-visible,.quick-input-list .quick-input-list-entry.focus-inside .quick-input-list-entry-action-bar .action-label,.quick-input-list .quick-input-list-entry:hover .quick-input-list-entry-action-bar .action-label{display:flex}.quick-input-list .monaco-list-row.focused .monaco-keybinding-key,.quick-input-list .monaco-list-row.focused .quick-input-list-entry .quick-input-list-separator{color:inherit}.quick-input-list .monaco-list-row.focused .monaco-keybinding-key{background:none}.quick-input-list .quick-input-list-separator-as-item{font-size:12px;padding:4px 6px}.quick-input-list .quick-input-list-separator-as-item .label-name{font-weight:600}.quick-input-list .quick-input-list-separator-as-item .label-description{opacity:1!important}.quick-input-list .monaco-tree-sticky-row .quick-input-list-entry.quick-input-list-separator-as-item.quick-input-list-separator-border{border-top-style:none}.quick-input-list .monaco-tree-sticky-row{padding:0 5px}.quick-input-list .monaco-tl-twistie{display:none!important}.extension-editor .codicon.codicon-error,.extensions-viewlet>.extensions .codicon.codicon-error,.markers-panel .marker-icon .codicon.codicon-error,.markers-panel .marker-icon.error,.monaco-editor .zone-widget .codicon.codicon-error,.preferences-editor .codicon.codicon-error,.text-search-provider-messages .providerMessage .codicon.codicon-error{color:var(--vscode-problemsErrorIcon-foreground)}.extension-editor .codicon.codicon-warning,.extensions-viewlet>.extensions .codicon.codicon-warning,.markers-panel .marker-icon .codicon.codicon-warning,.markers-panel .marker-icon.warning,.monaco-editor .zone-widget .codicon.codicon-warning,.preferences-editor .codicon.codicon-warning,.text-search-provider-messages .providerMessage .codicon.codicon-warning{color:var(--vscode-problemsWarningIcon-foreground)}.extension-editor .codicon.codicon-info,.extensions-viewlet>.extensions .codicon.codicon-info,.markers-panel .marker-icon .codicon.codicon-info,.markers-panel .marker-icon.info,.monaco-editor .zone-widget .codicon.codicon-info,.preferences-editor .codicon.codicon-info,.text-search-provider-messages .providerMessage .codicon.codicon-info{color:var(--vscode-problemsInfoIcon-foreground)}.ydb-navigation-tree-view-empty{color:var(--g-color-text-secondary);font-style:italic}.ydb-navigation-tree-view-error{color:var(--g-color-text-danger)}.ydb-navigation-tree-view-loader{align-items:center;display:flex;height:24px;justify-content:center;width:20px} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/58705.b781fc86.chunk.css b/ydb/core/viewer/monitoring/static/css/58705.b781fc86.chunk.css deleted file mode 100644 index 174754d67136..000000000000 --- a/ydb/core/viewer/monitoring/static/css/58705.b781fc86.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.auto-refresh-control{align-items:center;display:flex;gap:var(--g-spacing-1)}.table-skeleton__wrapper{width:100%}.table-skeleton__wrapper_hidden{visibility:hidden}.table-skeleton__row{align-items:center;display:flex;height:var(--data-table-row-height)}.table-skeleton__row .g-skeleton{height:var(--g-text-body-2-line-height)}.table-skeleton__col-1{margin-right:5%;width:10%}.table-skeleton__col-2{margin-right:5%;width:7%}.table-skeleton__col-3,.table-skeleton__col-4{margin-right:5%;width:5%}.table-skeleton__col-5{width:20%}.table-skeleton__col-full{width:100%}.g-skeleton{--_--animation-from:calc(-100%*var(--g-flow-direction));--_--animation-to:calc(100%*var(--g-flow-direction));--_--gradient-deg:calc(90deg*var(--g-flow-direction));background-color:var(--g-color-base-generic);border-radius:5px;display:inline-block;overflow:hidden;position:relative;width:100%;z-index:0}.g-skeleton:after{animation:g-skeleton 1.2s ease-out infinite;background-image:linear-gradient(var(--_--gradient-deg),#0000,var(--g-color-base-generic));content:"";inset:0;position:absolute}@keyframes g-skeleton{0%{transform:translateX(var(--_--animation-from))}to{transform:translateX(var(--_--animation-to))}}.ydb-table-with-controls-layout{--data-table-sticky-top-offset:62px;box-sizing:border-box;display:inline-block;min-width:100%}.ydb-table-with-controls-layout__controls-wrapper{background-color:var(--g-color-base-background);box-sizing:border-box;left:0;position:sticky;top:0;width:100%;z-index:3}.ydb-table-with-controls-layout__controls{align-items:center;background-color:var(--g-color-base-background);display:flex;gap:12px;height:62px;left:0;padding:16px 0 18px;position:sticky;top:0;width:max-content;z-index:3}.ydb-table-with-controls-layout__table{position:relative;z-index:2}.ydb-table-with-controls-layout .ydb-paginated-table__head{top:var(--data-table-sticky-top-offset,62px)}.ydb-table-with-controls-layout .data-table__sticky_moving{top:var(--data-table-sticky-top-offset,62px)!important}.progress-viewer{align-items:center;background:var(--g-color-base-generic);border-radius:2px;color:var(--g-color-text-complementary);display:flex;font-size:var(--g-text-body-2-font-size);height:23px;justify-content:center;min-width:150px;overflow:hidden;padding:0 4px;position:relative;white-space:nowrap;z-index:0}.progress-viewer_theme_dark{color:var(--g-color-text-light-primary)}.progress-viewer_theme_dark .progress-viewer__line{opacity:.75}.progress-viewer_status_good{background-color:var(--g-color-base-positive-light)}.progress-viewer_status_good .progress-viewer__line{background-color:var(--ydb-color-status-green)}.progress-viewer_status_warning{background-color:var(--g-color-base-yellow-light)}.progress-viewer_status_warning .progress-viewer__line{background-color:var(--ydb-color-status-yellow)}.progress-viewer_status_danger{background-color:var(--g-color-base-danger-light)}.progress-viewer_status_danger .progress-viewer__line{background-color:var(--ydb-color-status-red)}.progress-viewer__line{height:100%;left:0;position:absolute;top:0}.progress-viewer__text{position:relative;z-index:1}.progress-viewer_size_xs{font-size:var(--g-text-body-2-font-size);height:20px;line-height:var(--g-text-body-2-line-height)}.progress-viewer_size_s{font-size:var(--g-text-body-1-font-size);height:28px;line-height:28px}.progress-viewer_size_m{font-size:var(--g-text-body-2-font-size);height:32px;line-height:32px}.progress-viewer_size_ns{font-size:13px;height:24px;line-height:var(--g-text-subheader-3-line-height)}.progress-viewer_size_n{font-size:var(--g-text-body-1-font-size);height:36px;line-height:36px}.progress-viewer_size_l{font-size:var(--g-text-subheader-3-font-size);height:38px;line-height:38px}.progress-viewer_size_head{font-size:var(--g-text-body-1-font-size);line-height:36px}.ydb-table-group{border:1px solid var(--g-color-line-generic);border-radius:var(--g-spacing-2);display:flex;flex-direction:column;margin-bottom:20px;width:100%}.ydb-table-group__button{background:unset;border:unset;cursor:pointer;padding:8px 0}.ydb-table-group__title-wrapper{align-items:center;display:flex;flex-direction:row;gap:var(--g-spacing-2);justify-content:flex-start;left:0;padding-left:20px;position:sticky;width:max-content}.ydb-table-group__title{display:flex;flex-direction:row;gap:var(--g-spacing-4)}.ydb-table-group__count{display:flex;flex-direction:row;gap:var(--g-spacing-3)}.ydb-table-group__content{padding:12px 0 20px 20px}.ydb-search{min-width:100px}.g-tree-select{display:inline-block;max-width:100%}.g-tree-select_width_max{width:100%}.g-tree-select__popup{overflow:hidden;padding:4px 0}.g-tree-select__popup_size_s{border-radius:var(--g-list-container-border-radius,5px)}.g-tree-select__popup_size_m{border-radius:var(--g-list-container-border-radius,6px)}.g-tree-select__popup_size_l{border-radius:var(--g-list-container-border-radius,8px)}.g-tree-select__popup_size_xl{border-radius:var(--g-list-container-border-radius,10px)}.g-tree-select__list{padding:0 4px}.g-list-item-expand-icon{flex-shrink:0}.g-list-item-view{align-items:center;display:flex;flex-grow:1;flex-shrink:0}.g-list-item-view__content{height:100%;width:100%}.g-list-item-view__main-content{display:grid;gap:var(--g-spacing-half,2px);width:100%}.g-list-item-view:hover.g-list-item-view_activeOnHover,.g-list-item-view_active{background:var(--g-color-base-simple-hover)}.g-list-item-view_clickable{cursor:pointer}.g-list-item-view_selected,.g-list-item-view_selected.g-list-item-view_active,.g-list-item-view_selected:hover.g-list-item-view_activeOnHover{background:var(--g-color-base-selection)}.g-list-item-view_dragging,.g-list-item-view_dragging.g-list-item-view_active,.g-list-item-view_dragging.g-list-item-view_selected{background:var(--g-color-base-simple-hover-solid);z-index:100001!important}.g-list-item-view_radius_s{border-radius:var(--g-list-item-border-radius,3px)}.g-list-item-view_radius_m{border-radius:var(--g-list-item-border-radius,5px)}.g-list-item-view_radius_l{border-radius:var(--g-list-item-border-radius,6px)}.g-list-item-view_radius_xl{border-radius:var(--g-list-item-border-radius,8px)}.g-list-item-view__slot{flex-shrink:0}.g-list-recursive-renderer{margin:0;padding:0}.g-list-container-view{box-sizing:border-box;outline:none;width:100%}.g-list-container-view_fixed-height{height:var(--g-list-container-height,300px)}.g-list-container-view:not(.g-list-container-view_fixed-height){overflow:auto}.g-inner-table-column-setup{display:inline-block}.g-inner-table-column-setup__controls{margin:var(--g-spacing-1) var(--g-spacing-1) 0}.g-inner-table-column-setup__filter-input{border-block-end:1px solid var(--g-color-line-generic);box-sizing:border-box;padding:0 var(--g-spacing-2) var(--g-spacing-1)}.g-inner-table-column-setup__empty-placeholder{padding:var(--g-spacing-2)}.g-table-column-setup__status{color:var(--g-color-text-secondary);margin-inline-start:5px}.ydb-paginated-table{--paginated-table-cell-vertical-padding:5px;--paginated-table-cell-horizontal-padding:10px;--paginated-table-border-color:var(--g-color-base-generic-hover);--paginated-table-hover-color:var(--g-color-base-simple-hover-solid);font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);width:100%}.ydb-paginated-table__table{border-collapse:initial;border-spacing:0;max-width:100%;table-layout:fixed;width:max-content}.ydb-paginated-table__table th{padding:0}.ydb-paginated-table__row{position:relative;transform:translateZ(0);z-index:1}.ydb-paginated-table__row:hover{background:var(--paginated-table-hover-color)}.ydb-paginated-table__row_empty:hover{background-color:initial}.ydb-paginated-table__head{background-color:var(--g-color-base-background);left:0;position:sticky;top:0;z-index:2}.ydb-paginated-table__sort-icon-container{color:inherit;display:flex;justify-content:center}.ydb-paginated-table__sort-icon-container_shadow{opacity:.15}.ydb-paginated-table__sort-icon_desc{transform:rotate(180deg)}.ydb-paginated-table__head-cell-wrapper{border-bottom:1px solid var(--paginated-table-border-color);display:table-cell;overflow-x:hidden;position:relative}.ydb-paginated-table__head-cell{align-items:center;display:flex;flex-direction:row;max-width:100%;padding:var(--paginated-table-cell-vertical-padding) var(--paginated-table-cell-horizontal-padding);width:100%}.ydb-paginated-table__head-cell_align_left{justify-content:left}.ydb-paginated-table__head-cell_align_center{justify-content:center}.ydb-paginated-table__head-cell_align_right{justify-content:right}.ydb-paginated-table__head-cell{cursor:default;font-weight:700;gap:8px}.ydb-paginated-table__head-cell_sortable{cursor:pointer}.ydb-paginated-table__head-cell_sortable.ydb-paginated-table__head-cell_align_right{flex-direction:row-reverse}.ydb-paginated-table__head-cell-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:min-content}.ydb-paginated-table__row-cell{border-bottom:1px solid var(--paginated-table-border-color);display:table-cell;max-width:100%;overflow-x:hidden;padding:var(--paginated-table-cell-vertical-padding) var(--paginated-table-cell-horizontal-padding);text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:100%}.ydb-paginated-table__row-cell_align_left{text-align:left}.ydb-paginated-table__row-cell_align_center{text-align:center}.ydb-paginated-table__row-cell_align_right{text-align:right}.ydb-paginated-table__resize-handler{background-color:var(--g-color-base-generic);cursor:col-resize;height:100%;position:absolute;right:0;top:0;visibility:hidden;width:6px}.ydb-paginated-table__head-cell-wrapper:hover>.ydb-paginated-table__resize-handler,.ydb-paginated-table__resize-handler_resizing{visibility:visible}.ydb-paginated-table__resizeable-table-container{padding-right:20px;width:max-content}.ydb-paginated-table__row-skeleton:after{animation:none!important}.hover-popup{padding:var(--g-spacing-3)}.memory-viewer{min-width:150px;padding:0 var(--g-spacing-1);position:relative;z-index:0}.memory-viewer__progress-container{background:var(--g-color-base-generic);border-radius:2px;height:20px;overflow:hidden;position:relative}.memory-viewer__container{display:flex;padding:2px 0}.memory-viewer__legend{border-radius:2px;bottom:2px;height:20px;position:absolute;width:20px}.memory-viewer__legend_type_AllocatorCachesMemory{background-color:var(--g-color-base-utility-medium-hover)}.memory-viewer__legend_type_SharedCacheConsumption{background-color:var(--g-color-base-info-medium-hover)}.memory-viewer__legend_type_MemTableConsumption{background-color:var(--g-color-base-warning-medium-hover)}.memory-viewer__legend_type_QueryExecutionConsumption{background-color:var(--g-color-base-positive-medium-hover)}.memory-viewer__legend_type_Other{background-color:var(--g-color-base-generic-medium-hover)}.memory-viewer__segment{height:100%;position:absolute}.memory-viewer__segment_type_AllocatorCachesMemory{background-color:var(--g-color-base-utility-medium-hover)}.memory-viewer__segment_type_SharedCacheConsumption{background-color:var(--g-color-base-info-medium-hover)}.memory-viewer__segment_type_MemTableConsumption{background-color:var(--g-color-base-warning-medium-hover)}.memory-viewer__segment_type_QueryExecutionConsumption{background-color:var(--g-color-base-positive-medium-hover)}.memory-viewer__segment_type_Other{background-color:var(--g-color-base-generic-medium-hover)}.memory-viewer__name{padding-left:28px}.memory-viewer_theme_dark{color:var(--g-color-text-light-primary)}.memory-viewer_theme_dark .memory-viewer__segment{opacity:.75}.memory-viewer_status_good .memory-viewer__progress-container{background-color:var(--g-color-base-positive-light)}.memory-viewer_status_warning .memory-viewer__progress-container{background-color:var(--g-color-base-yellow-light)}.memory-viewer_status_danger .memory-viewer__progress-container{background-color:var(--g-color-base-danger-light)}.memory-viewer__text{align-items:center;display:flex;justify-content:center}.ydb-pool-bar{border:1px solid;border-radius:1px;cursor:pointer;height:20px;margin-right:2px;position:relative;width:6px}.ydb-pool-bar__popup-content{padding:10px;width:170px}.ydb-pool-bar:last-child{margin-right:0}.ydb-pool-bar_type_normal{border-color:var(--ydb-color-status-green)}.ydb-pool-bar_type_warning{border-color:var(--ydb-color-status-yellow)}.ydb-pool-bar_type_danger{border-color:var(--ydb-color-status-red)}.ydb-pool-bar__value{bottom:0;min-height:1px;position:absolute;width:100%}.ydb-pool-bar__value_type_normal{background-color:var(--ydb-color-status-green)}.ydb-pool-bar__value_type_warning{background-color:var(--ydb-color-status-yellow)}.ydb-pool-bar__value_type_danger{background-color:var(--ydb-color-status-red)}.ydb-pools-graph{display:flex}.tablets-statistic{align-items:center;display:flex;gap:2px}.tablets-statistic__tablet{border:1px solid;border-radius:2px;color:var(--g-color-text-secondary);display:inline-block;font-size:11px;height:20px;line-height:20px;padding:0 4px;text-align:center;text-decoration:none;text-transform:uppercase}.tablets-statistic__tablet_state_green{background-color:var(--g-color-base-positive-light);color:var(--g-color-text-positive)}.tablets-statistic__tablet_state_yellow{background-color:var(--g-color-base-warning-light);color:var(--g-color-text-warning)}.tablets-statistic__tablet_state_blue{background-color:var(--g-color-base-info-light);color:var(--g-color-text-info)}.tablets-statistic__tablet_state_orange{background-color:var(--g-color-base-warning-light);color:var(--g-color-text-warning-heavy)}.tablets-statistic__tablet_state_red{background:var(--g-color-base-danger-light);color:var(--g-color-text-danger)}.tablets-statistic__tablet_state_grey{border:1px solid var(--g-color-line-generic-hover);color:var(--g-color-text-secondary)}.ydb-nodes-columns__column-cpu,.ydb-nodes-columns__column-ram{min-width:40px}.storage-disk-progress-bar{--progress-bar-full-height:var(--g-text-body-3-line-height);--progress-bar-compact-height:12px;--entity-state-border-color:var(--g-color-base-misc-heavy);--entity-state-background-color:var(--g-color-base-misc-light);--entity-state-fill-color:var(--g-color-base-misc-medium);--entity-state-font-color:var(--g-color-text-primary);background-color:var(--entity-state-background-color);border:1px solid var(--entity-state-border-color);border-radius:4px;color:var(--g-color-text-primary);height:var(--progress-bar-full-height);min-width:50px;position:relative;text-align:center;z-index:0}.storage-disk-progress-bar_green{--entity-state-font-color:var(--g-color-text-positive);--entity-state-border-color:var(--g-color-base-positive-heavy);--entity-state-background-color:var(--g-color-base-positive-light);--entity-state-fill-color:var(--g-color-base-positive-medium)}.storage-disk-progress-bar_blue{--entity-state-font-color:var(--g-color-text-info);--entity-state-border-color:var(--g-color-base-info-heavy);--entity-state-background-color:var(--g-color-base-info-light);--entity-state-fill-color:var(--g-color-base-info-medium)}.storage-disk-progress-bar_yellow{--entity-state-font-color:var(--g-color-text-warning);--entity-state-border-color:var(--g-color-base-warning-heavy);--entity-state-background-color:var(--g-color-base-yellow-light);--entity-state-fill-color:var(--g-color-base-yellow-medium)}.storage-disk-progress-bar_orange{--entity-state-font-color:var(--g-color-private-orange-500);--entity-state-border-color:var(--ydb-color-status-orange);--entity-state-background-color:var(--g-color-private-orange-100);--entity-state-fill-color:var(--g-color-private-orange-300)}.storage-disk-progress-bar_red{--entity-state-font-color:var(--g-color-text-danger);--entity-state-border-color:var(--g-color-base-danger-heavy);--entity-state-background-color:var(--g-color-base-danger-light);--entity-state-fill-color:var(--g-color-base-danger-medium)}.storage-disk-progress-bar__grey{--entity-state-font-color:var(--g-color-text-secondary);--entity-state-border-color:var(--g-color-line-generic-hover)}.storage-disk-progress-bar_compact{border-radius:2px;height:var(--progress-bar-compact-height);min-width:0}.storage-disk-progress-bar_faded{background-color:unset}.storage-disk-progress-bar_inactive{opacity:.5}.storage-disk-progress-bar_empty{background-color:unset;border-style:dashed;color:var(--g-color-text-hint)}.storage-disk-progress-bar__fill-bar{background-color:var(--entity-state-fill-color);border-radius:3px 0 0 3px;height:100%;left:0;position:absolute;top:0}.storage-disk-progress-bar__fill-bar_faded{background-color:var(--entity-state-background-color)}.storage-disk-progress-bar__fill-bar_compact{border-radius:1px}.storage-disk-progress-bar__fill-bar_inverted{border-radius:0 3px 3px 0;left:auto;right:0}.storage-disk-progress-bar__title{color:inherit;font-size:var(--g-text-body-1-font-size);line-height:calc(var(--progress-bar-full-height) - 2px);position:relative;z-index:2}.vdisk-storage-popup .info-viewer+.info-viewer{border-top:1px solid var(--g-color-line-generic);margin-top:8px;padding-top:8px}.vdisk-storage-popup__donor-label{margin-bottom:8px}.ydb-vdisk-component{border-radius:4px}.ydb-vdisk-component__content{border-radius:4px;display:block}.pdisk-storage{display:flex;flex-direction:column;justify-content:flex-end;min-width:var(--pdisk-min-width);position:relative;width:var(--pdisk-width)}.pdisk-storage__content{border-radius:4px;display:block;flex:1 1;position:relative}.pdisk-storage__vdisks{display:flex;flex:0 0 auto;gap:var(--pdisk-gap-width);margin-bottom:4px;white-space:nowrap}.pdisk-storage__vdisks-item{flex:0 0 var(--pdisk-vdisk-width);min-width:var(--pdisk-vdisk-width)}.data-table__row:hover .pdisk-storage__vdisks-item .stack__layer{background:var(--ydb-data-table-color-hover)}.pdisk-storage__donors-stack{--ydb-stack-offset-x:0px;--ydb-stack-offset-y:-2px;--ydb-stack-offset-x-hover:0px;--ydb-stack-offset-y-hover:-7px}.pdisk-storage__media-type{color:var(--g-color-text-secondary);font-size:var(--g-text-body-1-font-size);line-height:var(--g-text-body-1-line-height);position:absolute;right:4px;top:50%;transform:translateY(-50%)}.ydb-storage-disks{align-items:center;display:flex;flex-direction:row;gap:20px;width:max-content}.ydb-storage-disks__pdisks-wrapper{display:flex;flex-direction:row;justify-content:left;width:max-content}.ydb-storage-disks__vdisk-item{flex-basis:8px;flex-shrink:0}.ydb-storage-disks__vdisk-progress-bar{--progress-bar-compact-height:18px;border-radius:4px}.ydb-storage-disks__pdisk-item{margin-right:4px;min-width:80px}.ydb-storage-disks__pdisk-item_with-dc-margin{margin-right:12px}.ydb-storage-disks__pdisk-item:last-child{margin-right:0}.ydb-storage-disks__pdisk-progress-bar{--progress-bar-full-height:20px;padding-left:var(--g-spacing-2);text-align:left}.stack{--ydb-stack-base-z-index:100;--ydb-stack-offset-x:4px;--ydb-stack-offset-y:4px;--ydb-stack-offset-x-hover:4px;--ydb-stack-offset-y-hover:6px;position:relative}.stack__layer{background:var(--g-color-base-background);transition:transform .1s ease-out}.stack__layer:first-child{position:relative;z-index:var(--ydb-stack-base-z-index)}.stack__layer+.stack__layer{height:100%;left:0;position:absolute;top:0;transform:translate(calc(var(--ydb-stack-level)*var(--ydb-stack-offset-x)),calc(var(--ydb-stack-level)*var(--ydb-stack-offset-y)));width:100%;z-index:calc(var(--ydb-stack-base-z-index) - var(--ydb-stack-level))}.stack:hover .stack__layer:first-child{transform:translate(calc(var(--ydb-stack-offset-x-hover)*-1),calc(var(--ydb-stack-offset-y-hover)*-1))}.stack:hover .stack__layer+.stack__layer{transform:translate(calc(var(--ydb-stack-level)*var(--ydb-stack-offset-x-hover)*2 - var(--ydb-stack-offset-x-hover)),calc(var(--ydb-stack-level)*var(--ydb-stack-offset-y-hover)*2 - var(--ydb-stack-offset-y-hover)))}.ydb-storage-vdisks__wrapper{display:flex}.ydb-storage-vdisks__item{margin-right:6px;width:90px}.ydb-storage-vdisks__item_with-dc-margin{margin-right:12px}.ydb-storage-vdisks__item:last-child{margin-right:0}.data-table__row:hover .ydb-storage-vdisks__item .stack__layer{background:var(--ydb-data-table-color-hover)}.ydb-storage-groups-columns__disks-column,.ydb-storage-groups-columns__vdisks-column{overflow:visible}.ydb-storage-groups-columns__pool-name-wrapper{direction:rtl;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ydb-storage-groups-columns__pool-name{unicode-bidi:plaintext}.ydb-storage-groups-columns__group-id{font-weight:500;margin-right:var(--g-spacing-1)}.global-storage__search{width:238px}.global-storage__table .g-tooltip{height:var(--g-text-body-2-line-height)!important}.global-storage .entity-status{justify-content:center}.global-storage__groups-wrapper{padding-right:20px}.ydb-storage-nodes__node_unavailable{opacity:.6}.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.ydb-storage-nodes-columns__pdisks-column{overflow:visible}.ydb-storage-nodes-columns__pdisks-wrapper{--pdisk-vdisk-width:3px;--pdisk-gap-width:2px;--pdisk-min-width:120px;--pdisk-margin:10px;--pdisk-width:max(calc(var(--maximum-slots, 1)*var(--pdisk-vdisk-width) + (var(--maximum-slots, 1) - 1)*var(--pdisk-gap-width)),var(--pdisk-min-width));--pdisks-container-width:calc(var(--maximum-disks, 1)*var(--pdisk-width) + (var(--maximum-disks, 1) - 1)*var(--pdisk-margin));display:flex;gap:var(--pdisk-margin);height:40px;width:var(--pdisks-container-width)}.ydb-storage-nodes-columns__pdisks-item{display:flex;flex-shrink:0}.ydb-info-viewer-skeleton{display:flex;flex-direction:column;gap:16px}.ydb-info-viewer-skeleton__row{align-items:flex-start;display:flex}.ydb-info-viewer-skeleton__row,.ydb-info-viewer-skeleton__row .g-skeleton{min-height:var(--g-text-body-2-font-size)}.ydb-info-viewer-skeleton__label{align-items:baseline;display:flex;flex:0 1 auto;width:200px}.ydb-info-viewer-skeleton__label__text{width:100px}.ydb-info-viewer-skeleton__label__dots{border-bottom:1px dotted var(--g-color-text-secondary);margin:0 2px;width:100px}.ydb-info-viewer-skeleton__value{max-width:20%;min-width:200px} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/58884.1e565ac5.chunk.css b/ydb/core/viewer/monitoring/static/css/58884.1e565ac5.chunk.css deleted file mode 100644 index fc2cf1d3d89d..000000000000 --- a/ydb/core/viewer/monitoring/static/css/58884.1e565ac5.chunk.css +++ /dev/null @@ -1,9 +0,0 @@ -@charset "UTF-8";.g-checkbox__indicator{cursor:inherit;display:inline-block;position:relative}.g-checkbox__indicator:before{background-color:initial;border:1px solid var(--g-color-line-generic-accent);border-radius:4px;content:"";inset:0;position:absolute;transition:background .1s linear}.g-checkbox__indicator:after{content:" ";visibility:hidden}.g-checkbox__icon{align-items:center;color:#0000;display:flex;inset:0;justify-content:center;pointer-events:none;position:absolute;transform:translateY(-5px);transition:color .1s,transform .2s;visibility:hidden}.g-checkbox__control{border:none;cursor:inherit;margin:0;opacity:0;outline:none;padding:0}.g-checkbox__control,.g-checkbox__outline{background:none;height:100%;inset-block-start:0;inset-inline-start:0;position:absolute;width:100%}.g-checkbox__outline{border-radius:4px;pointer-events:none}.g-checkbox__control:focus-visible+.g-checkbox__outline{outline:2px solid var(--g-color-line-focus)}.g-checkbox_size_m .g-checkbox__icon-svg_type_tick{height:10px;width:8px}.g-checkbox_size_m .g-checkbox__icon-svg_type_dash{height:12px;width:12px}.g-checkbox_size_m .g-checkbox__indicator{height:14px;width:14px}.g-checkbox_size_l .g-checkbox__icon-svg_type_tick{height:9px;width:11px}.g-checkbox_size_l .g-checkbox__icon-svg_type_dash{height:15px;width:15px}.g-checkbox_size_l .g-checkbox__indicator{height:17px;width:17px}.g-checkbox:hover .g-checkbox__indicator:before{border-color:var(--g-color-line-generic-accent-hover)}.g-checkbox_checked .g-checkbox__indicator:before,.g-checkbox_indeterminate .g-checkbox__indicator:before{background-color:var(--g-color-base-brand);border:#0000}.g-checkbox_checked .g-checkbox__icon,.g-checkbox_indeterminate .g-checkbox__icon{color:var(--g-color-text-brand-contrast);transform:translateX(0);visibility:visible}.g-checkbox_disabled .g-checkbox__indicator:before{background-color:var(--g-color-base-generic-accent-disabled);border:#0000}.g-checkbox_disabled.g-checkbox_checked .g-checkbox__indicator:before,.g-checkbox_disabled.g-checkbox_indeterminate .g-checkbox__indicator:before{background-color:var(--g-color-base-brand);opacity:.5}.g-skeleton{--_--animation-from:calc(-100%*var(--g-flow-direction));--_--animation-to:calc(100%*var(--g-flow-direction));--_--gradient-deg:calc(90deg*var(--g-flow-direction));background-color:var(--g-color-base-generic);border-radius:5px;display:inline-block;overflow:hidden;position:relative;width:100%;z-index:0}.g-skeleton:after{animation:g-skeleton 1.2s ease-out infinite;background-image:linear-gradient(var(--_--gradient-deg),#0000,var(--g-color-base-generic));content:"";inset:0;position:absolute}@keyframes g-skeleton{0%{transform:translateX(var(--_--animation-from))}to{transform:translateX(var(--_--animation-to))}}.g-tree-select{display:inline-block;max-width:100%}.g-tree-select_width_max{width:100%}.g-tree-select__popup{overflow:hidden;padding:4px 0}.g-tree-select__popup_size_s{border-radius:var(--g-list-container-border-radius,5px)}.g-tree-select__popup_size_m{border-radius:var(--g-list-container-border-radius,6px)}.g-tree-select__popup_size_l{border-radius:var(--g-list-container-border-radius,8px)}.g-tree-select__popup_size_xl{border-radius:var(--g-list-container-border-radius,10px)}.g-tree-select__list{padding:0 4px}.g-list-item-expand-icon{flex-shrink:0}.g-list-item-view{align-items:center;display:flex;flex-grow:1;flex-shrink:0}.g-list-item-view__content{height:100%;width:100%}.g-list-item-view__main-content{display:grid;gap:var(--g-spacing-half,2px);width:100%}.g-list-item-view:hover.g-list-item-view_activeOnHover,.g-list-item-view_active{background:var(--g-color-base-simple-hover)}.g-list-item-view_clickable{cursor:pointer}.g-list-item-view_selected,.g-list-item-view_selected.g-list-item-view_active,.g-list-item-view_selected:hover.g-list-item-view_activeOnHover{background:var(--g-color-base-selection)}.g-list-item-view_dragging,.g-list-item-view_dragging.g-list-item-view_active,.g-list-item-view_dragging.g-list-item-view_selected{background:var(--g-color-base-simple-hover-solid);z-index:100001!important}.g-list-item-view_radius_s{border-radius:var(--g-list-item-border-radius,3px)}.g-list-item-view_radius_m{border-radius:var(--g-list-item-border-radius,5px)}.g-list-item-view_radius_l{border-radius:var(--g-list-item-border-radius,6px)}.g-list-item-view_radius_xl{border-radius:var(--g-list-item-border-radius,8px)}.g-list-item-view__slot{flex-shrink:0}.g-list-recursive-renderer{margin:0;padding:0}.g-list-container-view{box-sizing:border-box;outline:none;width:100%}.g-list-container-view_fixed-height{height:var(--g-list-container-height,300px)}.g-list-container-view:not(.g-list-container-view_fixed-height){overflow:auto}.g-inner-table-column-setup{display:inline-block}.g-inner-table-column-setup__controls{margin:var(--g-spacing-1) var(--g-spacing-1) 0}.g-inner-table-column-setup__filter-input{border-block-end:1px solid var(--g-color-line-generic);box-sizing:border-box;padding:0 var(--g-spacing-2) var(--g-spacing-1)}.g-inner-table-column-setup__empty-placeholder{padding:var(--g-spacing-2)}.g-table-column-setup__status{color:var(--g-color-text-secondary);margin-inline-start:5px}.gc-help-popover__button{background:none;border:none;color:inherit;color:var(--g-color-text-hint);cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0}.gc-help-popover__button:focus-visible{border-radius:50%;outline:2px solid var(--g-color-line-focus)}.gc-definition-list__list{margin:0}.gc-definition-list__group-title{margin-block-end:var(--g-spacing-3)}.gc-definition-list__group-title:not(:first-of-type){margin-block-start:var(--g-spacing-5)}.gc-definition-list__item{align-items:baseline;display:flex;gap:var(--g-spacing-1)}.gc-definition-list__item+.gc-definition-list__item{margin-block-start:var(--g-spacing-4)}.gc-definition-list__item_grouped+.gc-definition-list__item_grouped{margin-block-start:var(--g-spacing-3)}.gc-definition-list_margin:not(:first-of-type){margin-block-start:var(--g-spacing-5)}.gc-definition-list__term-container{align-items:baseline;display:flex;flex:0 0 auto;max-width:300px;overflow:hidden;position:relative;width:300px}.gc-definition-list__term-wrapper{color:var(--g-color-text-secondary);flex:0 1 auto;overflow:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap}.gc-definition-list__term-container_multiline .gc-definition-list__term-wrapper{white-space:unset}.gc-definition-list__term-container_multiline .gc-definition-list__item-note-tooltip{position:absolute}.gc-definition-list__dots{border-block-end:1px dotted var(--g-color-line-generic-active);box-sizing:border-box;flex:1 0 auto;margin:0 2px;min-width:40px}.gc-definition-list__dots_with-note{margin-inline-start:15px;min-width:25px}.gc-definition-list__definition{flex:0 1 auto;margin:0}.gc-definition-list_responsive .gc-definition-list__term-container{flex:1 0 auto}.gc-definition-list__copy-container{align-items:center;display:inline-flex;margin-inline-end:calc(var(--g-spacing-7)*-1);padding-inline-end:var(--g-spacing-7);position:relative}.gc-definition-list__copy-container:hover .gc-definition-list__copy-button{opacity:1}.gc-definition-list__copy-container_icon-inside{margin-inline-end:unset;padding-inline-end:unset}.gc-definition-list__copy-container_icon-inside .gc-definition-list__copy-button{inset-block-start:0}.gc-definition-list__copy-button{display:inline-block;inset-inline-end:0;margin-inline-start:10px;opacity:0;position:absolute}.gc-definition-list__copy-button:focus-visible{opacity:1}.gc-definition-list_vertical .gc-definition-list__term-container{flex:1 0 auto}.gc-definition-list_vertical .gc-definition-list__item{flex-direction:column;gap:var(--g-spacing-half)}.gc-definition-list_vertical .gc-definition-list__item+.gc-definition-list__item{margin-block-start:var(--g-spacing-3)}.gc-definition-list_vertical .gc-definition-list__group-title:not(:first-of-type),.gc-definition-list_vertical .gc-definition-list_margin:not(:first-of-type){margin-block-start:var(--g-spacing-8)}.chartkit-loader{align-items:center;display:flex;justify-content:center}.chartkit,.chartkit-loader{height:100%;width:100%}.chartkit_mobile .chartkit-scrollable-node{max-height:3000px}.chartkit-theme_common{--highcarts-navigator-border:var(--g-color-line-generic);--highcarts-navigator-track:var(--g-color-base-generic);--highcarts-navigator-body:var(--g-color-scroll-handle);--highcharts-series-border:var(--g-color-base-background);--highcharts-grid-line:var(--g-color-line-generic);--highcharts-axis-line:var(--g-color-line-generic);--highcharts-tick:var(--g-color-line-generic);--highcharts-title:var(--g-color-text-primary);--highcharts-axis-labels:var(--g-color-text-secondary);--highcharts-data-labels:var(--g-color-text-secondary);--highcharts-plot-line-label:var(--g-color-text-secondary);--highcharts-legend-item:var(--g-color-text-secondary);--highcharts-legend-item-hover:var(--g-color-text-primary);--highcharts-legend-item-hidden:var(--g-color-text-hint);--highcharts-floating-bg:var(--g-color-infographics-tooltip-bg);--highcharts-tooltip-text:var(--g-color-text-primary);--highcharts-tooltip-bg:var(--highcharts-floating-bg);--highcharts-tooltip-alternate-bg:var(--g-color-base-generic);--highcharts-tooltip-text-complementary:var(--g-color-text-secondary);--highcharts-holiday-band:var(--g-color-base-generic)}.ydb-tree-view{--ydb-tree-view-level:0;font-size:13px;line-height:18px}.ydb-tree-view,.ydb-tree-view *{box-sizing:border-box}.ydb-tree-view__item{align-items:center;border-bottom:1px solid var(--g-color-line-generic-solid);cursor:pointer;display:flex;height:24px;padding-left:calc(24px*var(--ydb-tree-view-level));padding-right:3px}.ydb-tree-view__item:hover{background-color:var(--g-color-base-simple-hover)}.ydb-tree-view__item:hover .ydb-tree-view__actions{display:flex}.ydb-tree-view__item_active{background-color:var(--g-color-base-selection);font-weight:700}.ydb-tree-view__item_active:hover{background-color:var(--g-color-base-selection-hover)}.ydb-tree-view__content{align-items:center;display:flex;flex-grow:1;overflow:hidden}.ydb-tree-view__icon{align-items:center;color:var(--g-color-text-hint);display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.ydb-tree-view__icon svg{display:block}.ydb-tree-view__text{flex-grow:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ydb-tree-view__actions{align-items:center;display:none;margin-left:6px}.ydb-tree-view__arrow{background:url('data:image/svg+xml;utf8,') no-repeat 50%;border:none;cursor:pointer;flex-shrink:0;height:24px;padding:0;width:24px}.g-root_theme_dark .ydb-tree-view__arrow{background:url('data:image/svg+xml;utf8,') no-repeat 50%}.ydb-tree-view__arrow:focus-visible{outline:2px solid var(--g-color-line-focus)}.ydb-tree-view__arrow:not(.ydb-tree-view__arrow_collapsed){transform:rotate(90deg)}.ydb-tree-view__arrow_hidden{visibility:hidden}.ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:24px}.ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:48px}.ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:72px}.ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:96px}.ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view .ydb-tree-view__item{padding-left:120px}.g-card{--_--background-color:#0000;--_--border-color:#0000;--_--border-width:0;--_--box-shadow:none;background-color:var(--g-card-background-color,var(--_--background-color));border:var(--g-card-border-width,var(--_--border-width)) solid var(--g-card-border-color,var(--_--border-color));border-radius:var(--g-card-border-radius,var(--_--border-radius));box-shadow:var(--g-card-box-shadow,var(--_--box-shadow));box-sizing:border-box;outline:none}.g-card_theme_normal{--_--border-color:var(--g-color-line-generic);--_--background-color:var(--g-color-base-generic)}.g-card_theme_info{--_--border-color:var(--g-color-line-info);--_--background-color:var(--g-color-base-info-light)}.g-card_theme_success{--_--border-color:var(--g-color-line-positive);--_--background-color:var(--g-color-base-positive-light)}.g-card_theme_warning{--_--border-color:var(--g-color-line-warning);--_--background-color:var(--g-color-base-warning-light)}.g-card_theme_danger{--_--border-color:var(--g-color-line-danger);--_--background-color:var(--g-color-base-danger-light)}.g-card_theme_utility{--_--border-color:var(--g-color-line-utility);--_--background-color:var(--g-color-base-utility-light)}.g-card_view_clear,.g-card_view_outlined{--_--background-color:#0000}.g-card_view_outlined{--_--border-width:1px}.g-card_type_action{--_--background-color:var(--g-color-base-float);--_--box-shadow:0px 1px 5px var(--g-color-sfx-shadow)}.g-card_type_action:after{border-radius:var(--g-card-border-radius,var(--_--border-radius));inset:0;pointer-events:none;position:absolute}.g-card_type_action.g-card_clickable{cursor:pointer;position:relative}.g-card_type_action.g-card_clickable:hover{--_--box-shadow:0px 3px 10px var(--g-color-sfx-shadow)}.g-card_type_action.g-card_clickable:focus-visible:after{content:"";outline:2px solid var(--g-color-line-focus)}.g-card_type_selection{--_--border-width:1px;--_--border-color:var(--g-color-line-generic);position:relative}.g-card_type_selection:before{inset:-1px}.g-card_type_selection:after,.g-card_type_selection:before{border-radius:var(--g-card-border-radius,var(--_--border-radius));pointer-events:none;position:absolute}.g-card_type_selection:after{inset:0}.g-card_type_selection.g-card_clickable{cursor:pointer}.g-card_type_selection.g-card_clickable:hover{--_--border-color:#0000}.g-card_type_selection.g-card_clickable:hover:not(.g-card_selected):before{border:2px solid var(--g-color-line-brand);content:"";opacity:.5}.g-card_type_selection.g-card_clickable:hover:focus-visible:before{border-color:#0000}.g-card_type_selection.g-card_clickable:focus-visible:after{content:"";outline:2px solid var(--g-color-line-focus)}.g-card_type_selection.g-card_selected:not(.g-card_disabled){--_--border-color:#0000}.g-card_type_selection.g-card_selected:not(.g-card_disabled):before{border:2px solid var(--g-color-line-brand);content:""}.g-card_type_selection.g-card_view_clear{--_--border-color:#0000}.g-card_type_container.g-card_view_raised{--_--background-color:var(--g-color-base-float)}.g-card_type_container.g-card_view_raised.g-card_size_m{--_--box-shadow:0px 1px 5px var(--g-color-sfx-shadow)}.g-card_type_container.g-card_view_raised.g-card_size_l{--_--box-shadow:0px 1px 6px var(--g-color-sfx-shadow-light),1px 3px 13px var(--g-color-sfx-shadow-light)}.g-card_size_m{--_--border-radius:8px}.g-card_size_l{--_--border-radius:16px}.g-date-relative-range-date-picker-control__input{caret-color:#0000}.g-date-relative-range-date-picker-control__input_mobile{pointer-events:none}.g-date-relative-range-date-picker-control__mobile-trigger{--_--g-date-mobile-trigger-clear-width:0px;--_--g-date-mobile-trigger-errors-width:0px;--_--g-date-mobile-trigger-button-width:24px;inset:0;inset-inline-end:calc(var(--g-spacing-2) + var(--_--g-date-mobile-trigger-button-width) + var(--_--g-date-mobile-trigger-clear-width) + var(--_--g-date-mobile-trigger-errors-width));opacity:0;position:absolute}.g-date-relative-range-date-picker-control__mobile-trigger_size_s{--_--g-date-mobile-trigger-button-width:20px}.g-date-relative-range-date-picker-control__mobile-trigger_size_l{--_--g-date-mobile-trigger-button-width:28px}.g-date-relative-range-date-picker-control__mobile-trigger_size_xl{--_--g-date-mobile-trigger-button-width:36px}.g-date-relative-range-date-picker-control__mobile-trigger_has-clear{--_--g-date-mobile-trigger-clear-width:calc(var(--_--g-date-mobile-trigger-button-width) + 2px)}.g-date-relative-range-date-picker-control__mobile-trigger_has-errors{--_--g-date-mobile-trigger-errors-width:calc(var(--_--g-date-mobile-trigger-button-width) + 2px)}.g-date-relative-range-date-picker-presets-doc__button{--g-button-background-color-hover:#0000}.g-date-relative-range-date-picker-presets-doc__content{--g-popover-max-width:"none"}.g-date-relative-range-date-picker-presets-doc__table_size_xl{font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-date-relative-range-date-picker-presets-doc__table>table{width:100%}.g-table,.g-table__scroll-container{overflow:auto;position:relative}.g-table__scroll-container{-ms-overflow-style:none;scrollbar-width:none}.g-table__scroll-container::-webkit-scrollbar{display:none}.g-table__horizontal-scroll-bar{margin-block-start:-1px;overflow-x:auto}.g-table__horizontal-scroll-bar-inner{height:1px;position:relative}.g-table__horizontal-scroll-bar-inner:before{background-color:#ffffff03;content:"";height:1px;inset-block-start:0;inset-inline-start:0;position:absolute;width:1px}.g-table__horizontal-scroll-bar_sticky-horizontal-scroll{position:sticky;z-index:3}.g-table__table{border-collapse:initial;border-spacing:0}.g-table__table_width_max{width:100%}.g-table__cell{border-block-end:1px solid var(--g-color-line-generic);box-sizing:initial;line-height:18px;overflow-wrap:break-word;padding:11px var(--g-spacing-2) 10px;text-align:start}.g-table__cell:first-child{padding-inline-start:0}.g-table__cell:last-child{padding-inline-end:0}.g-table__cell:not(.g-table__cell_word-wrap){overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.g-table__cell_align_center{text-align:center}.g-table__cell_align_end{text-align:end}.g-table .g-table__cell_sticky_end,.g-table .g-table__cell_sticky_start{background:var(--g-color-base-background);position:sticky;z-index:2}.g-table__cell_border_right{border-inline-end:1px solid var(--g-color-line-generic)}.g-table__cell_edge-padding:first-child{padding-inline-start:var(--g-spacing-3)}.g-table__cell_edge-padding:last-child{padding-inline-end:var(--g-spacing-3)}.g-table__row_vertical-align_top{vertical-align:top}.g-table__row_vertical-align_middle{vertical-align:middle}.g-table__row_empty .g-table__cell{text-align:center}.g-table__body .g-table__row:last-child .g-table__cell{border-block-end-color:#0000}.g-table__head .g-table__cell{font-weight:var(--g-text-accent-font-weight)}.g-table__body .g-table__row_interactive:hover{background-color:var(--g-color-base-simple-hover-solid);cursor:pointer}.g-table__body .g-table__row_interactive:hover .g-table__cell_sticky_end,.g-table__body .g-table__row_interactive:hover .g-table__cell_sticky_start{background:var(--g-color-base-simple-hover-solid)}.g-table__body .g-table__row_disabled{opacity:.3}.g-table_with-primary .g-table__body .g-table__cell{color:var(--g-color-text-secondary)}.g-table_with-primary .g-table__body .g-table__cell_primary{color:var(--g-color-text-primary)}.g-table_with-sticky-scroll{overflow:visible}.g-date-relative-range-date-picker-presets{--g-list-item-padding:0 var(--_--g-date-picker-presets-padding,0)}.g-date-relative-range-date-picker-presets__tabs{--g-tabs-border-width:0;align-items:center;box-shadow:inset 0 -1px var(--g-color-line-generic);display:flex;gap:var(--g-spacing-2);padding-inline:var(--_--g-date-picker-presets-padding,0)}.g-date-relative-range-date-picker-presets__list-container{outline:none}.g-date-relative-range-date-picker-presets__doc{margin-inline-start:auto}.g-date-relative-range-date-picker-presets__content{height:128px;overflow:auto}.g-date-relative-range-date-picker-presets_size_l .g-date-relative-range-date-picker-presets__content{height:144px}.g-date-relative-range-date-picker-presets_size_xl .g-date-relative-range-date-picker-presets__content{font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);height:162px;line-height:var(--g-text-body-2-line-height)}.g-date-relative-range-date-picker-zones__control{--g-button-background-color-hover:#0000}.g-date-relative-range-date-picker-dialog__content{--_--popup-content-padding:var(--g-spacing-2);--_--g-date-picker-presets-padding:var(--_--popup-content-padding);padding:var(--_--popup-content-padding)}.g-date-relative-range-date-picker-dialog__content_mobile{--_--popup-content-padding:var(--g-spacing-5)}.g-date-relative-range-date-picker-dialog__content:not(.g-date-relative-range-date-picker-dialog__content_mobile){width:310px}.g-date-relative-range-date-picker-dialog__content_size_xl:not(.g-date-relative-range-date-picker-dialog__content_mobile){width:380px}.g-date-relative-range-date-picker-dialog__pickers{display:flex;flex-direction:column;gap:var(--g-spacing-2)}.g-date-relative-range-date-picker-dialog__pickers .g-text-input__label{width:40px}.g-date-relative-range-date-picker-dialog__content_size_xl .g-date-relative-range-date-picker-dialog__pickers .g-text-input__label{width:50px}.g-date-relative-range-date-picker-dialog__apply{margin-block-start:var(--g-spacing-2)}.g-date-relative-range-date-picker-dialog__zone{border-block-start:1px solid var(--g-color-line-generic);margin-block:var(--g-spacing-2) calc(var(--_--popup-content-padding)*-1)}.g-date-relative-range-date-picker-dialog__presets,.g-date-relative-range-date-picker-dialog__zone{margin-inline:calc(var(--_--popup-content-padding)*-1)}.g-date-mobile-calendar{border:none;box-sizing:border-box;cursor:pointer;height:100%;inset-block-start:0;inset-inline-start:0;margin:0;min-width:100%;opacity:0;padding:0;position:absolute;z-index:1}.g-date-mobile-calendar::-webkit-calendar-picker-indicator{cursor:pointer;height:100%;inset-block-start:0;inset-inline-start:0;margin:0;min-width:100%;padding:0;position:absolute}.g-date-stub-button{display:inline-block;height:24px;position:relative;width:24px}.g-date-stub-button_size_xs{height:20px;width:20px}.g-date-stub-button_size_m{height:28px;width:28px}.g-date-stub-button_size_l{height:36px;width:36px}.g-date-stub-button__icon{align-items:center;color:var(--g-color-text-secondary);display:flex;inset:0;justify-content:center;position:absolute}.g-date-relative-date-picker{display:inline-flex;outline:none;position:relative}.g-date-relative-date-picker__input_mobile{pointer-events:none}.g-date-relative-date-picker__field{width:100%}.g-date-relative-date-picker__popup-content{outline:none}.g-date-relative-date-picker__time-field{width:100%}.g-date-relative-date-picker__time-field-wrapper{padding:10px}.g-date-calendar{--_--calendar-padding:var(--g-date-calendar-padding,8px);--_--calendar-day-size:var(--g-date-calendar-day-size,28px);--_--calendar-days-gap:var(--g-date-calendar-days-gap,2px);--_--calendar-width:calc(var(--_--calendar-day-size)*7 + var(--_--calendar-days-gap)*6 + var(--_--calendar-padding)*2);--_--calendar-grid-height:calc(var(--_--calendar-day-size)*7 + var(--_--calendar-days-gap)*5 + var(--_--calendar-padding));display:inline-block;width:var(--_--calendar-width)}.g-date-calendar_size_l{--g-date-calendar-day-size:36px}.g-date-calendar_size_xl{--g-date-calendar-day-size:42px;font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-date-calendar__header{display:flex;padding:var(--_--calendar-padding) var(--_--calendar-padding) 0}.g-date-calendar__years-label{color:var(--g-color-text-secondary)}.g-date-calendar__controls{margin-inline-start:auto}.g-date-calendar__control-icon{transform:scaleX(var(--g-flow-direction))}.g-date-calendar__grid{height:var(--_--calendar-grid-height);overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;width:100%}.g-date-calendar__content{box-sizing:border-box;display:grid;grid-template-rows:var(--_--calendar-day-size) 1fr;height:100%;inset-block-start:0;inset-inline-start:0;padding:0 var(--_--calendar-padding) var(--_--calendar-padding);position:absolute;width:100%}@keyframes calendar-forward{0%{transform:translateX(0)}to{transform:translateX(100%)}}@keyframes calendar-backward{0%{transform:translateX(0)}to{transform:translateX(-100%)}}@keyframes calendar-zoom-in-showing{0%{opacity:0;transform:scale(2)}to{opacity:1;transform:scale(1)}}@keyframes calendar-zoom-in-hiding{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(0)}}@keyframes calendar-zoom-out-showing{0%{opacity:0;transform:scale(0)}to{opacity:1;transform:scale(1)}}@keyframes calendar-zoom-out-hiding{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(2)}}.g-date-calendar__content_animation_forward{animation:calendar-forward .25s ease forwards;transform:translateX(-100%)}.g-date-calendar__content_animation_forward.g-date-calendar__current-state{inset-inline-start:calc(var(--g-flow-direction)*-100%)}.g-date-calendar__content_animation_backward{animation:calendar-backward .25s ease forwards;transform:translateX(0)}.g-date-calendar__content_animation_backward.g-date-calendar__current-state{inset-inline-start:calc(var(--g-flow-direction)*100%)}.g-date-calendar__content_animation_zoom-in{transform:scale()}.g-date-calendar__content_animation_zoom-in.g-date-calendar__previous-state{animation:calendar-zoom-in-hiding .25s ease forwards}.g-date-calendar__content_animation_zoom-in.g-date-calendar__current-state{animation:calendar-zoom-in-showing .25s ease forwards}.g-date-calendar__content_animation_zoom-out{transform:scale()}.g-date-calendar__content_animation_zoom-out.g-date-calendar__current-state{animation:calendar-zoom-out-showing .25s ease forwards}.g-date-calendar__content_animation_zoom-out.g-date-calendar__previous-state{animation:calendar-zoom-out-hiding .25s ease forwards}@media (update:slow),screen and (prefers-reduced-motion:reduce){.g-date-calendar__content[class]{animation-duration:.001ms}}.g-date-calendar__grid-rowgroup{display:grid;gap:var(--_--calendar-days-gap)}.g-date-calendar__grid-rowgroup_mode_months,.g-date-calendar__grid-rowgroup_mode_quarters,.g-date-calendar__grid-rowgroup_mode_years{grid-row:1/-1;padding:12px 0 0}.g-date-calendar__grid-rowgroup-header{align-self:center}.g-date-calendar__grid-row{display:grid;gap:var(--_--calendar-days-gap);grid-auto-columns:1fr;grid-auto-flow:column}.g-date-calendar__weekday{align-items:center;display:flex;height:100%;justify-content:center;width:100%}.g-date-calendar__weekday_weekend{color:var(--g-color-text-danger)}.g-date-calendar__button{align-items:center;border-radius:4px;cursor:pointer;display:flex;font-weight:var(--g-text-subheader-font-weight);height:100%;justify-content:center;outline:none;position:relative;width:100%}.g-date-calendar__button:focus{box-shadow:0 0 0 2px var(--g-color-line-misc)}.g-date-calendar__button:focus:not(:focus-visible){box-shadow:none}.g-date-calendar__button:hover{background-color:var(--g-color-base-generic)}.g-date-calendar__button_selected[class]{background-color:var(--g-color-base-selection)}.g-date-calendar__button_selected.g-date-calendar__button_selection-end,.g-date-calendar__button_selected.g-date-calendar__button_selection-start{background-color:var(--g-color-base-brand)}.g-date-calendar__button_weekend{color:var(--g-color-text-danger)}.g-date-calendar__button_out-of-boundary{font-weight:var(--g-text-body-font-weight);opacity:.6}.g-date-calendar__button_current:before{background-color:currentColor;border-radius:50%;content:"";display:block;height:4px;inset-block-start:50%;position:absolute;transform:translateY(8px);width:4px}.g-date-calendar__button_disabled{font-weight:var(--g-text-body-font-weight);opacity:.6;pointer-events:none}.g-date-calendar__button_unavailable:not(.g-date-calendar__button_disabled){background-color:var(--g-color-base-generic);cursor:default;font-weight:var(--g-text-body-font-weight);opacity:.5}.g-date-date-field{display:inline-block;width:auto}.g-date-relative-range-date-picker{display:inline-flex;position:relative}.g-date-relative-range-date-picker__value-label{display:flex;width:100%}.g-date-relative-range-date-picker__value-label>div{flex:1 0}.g-date-relative-range-date-picker__value-label-content{display:flex;flex-direction:column}.g-date-relative-range-date-picker__value-label-tooltip{--g-popover-max-width:"none"}.g-date-relative-range-date-picker__value-label-item,.g-date-relative-range-date-picker__value-label-to,.g-date-relative-range-date-picker__value-label-tz{text-align:center}.g-date-relative-range-date-picker__value-label-tz{color:var(--g-color-text-hint);margin-block-start:5px}.g-tooltip[class]{--g-popup-border-width:0}.g-tooltip[class]>div{animation-duration:1ms;box-shadow:0 1px 5px 0 #00000026;box-sizing:border-box;max-width:360px;padding:4px 8px}.g-tooltip__content{-webkit-box-orient:vertical;-ms-box-orient:vertical;-webkit-line-clamp:20;-moz-line-clamp:20;-ms-line-clamp:20;display:-webkit-box;overflow:hidden;text-overflow:ellipsis}.g-spin{animation:g-spin 1s linear infinite;backface-visibility:hidden;display:inline-block}.g-spin__inner{border:2px solid var(--g-color-line-brand);border-end-end-radius:25px;border-inline-start:none;border-start-end-radius:25px;box-sizing:border-box;height:100%;margin-inline-start:50%;width:50%}.g-spin_size_xs{height:16px;width:16px}.g-spin_size_s{height:24px;width:24px}.g-spin_size_m{height:28px;width:28px}.g-spin_size_l{height:32px;width:32px}.g-spin_size_xl{height:36px;width:36px}@keyframes g-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.g-alert_corners_square{--g-card-border-radius:0}.g-alert__text-content{width:100%}.g-alert__actions_minContent{width:min-content}.g-alert__close-btn{flex-shrink:0}.monaco-editor .rendered-markdown kbd{border-bottom-color:var(--vscode-keybindingLabel-bottomBorder);border-width:1px}@font-face{font-display:block;font-family:codicon;src:url(../../static/media/codicon.f6283f7ccaed1249d9eb.ttf) format("truetype")}.context-view-block,.context-view-pointerBlock{cursor:auto;height:100%;left:0;position:fixed;top:0;width:100%}.action-widget .monaco-list-row.action .monaco-keybinding>.monaco-keybinding-key{border-bottom-color:var(--vscode-keybindingLabel-bottomBorder);border-width:1px}.monaco-editor,.monaco-editor-background{background-color:var(--vscode-editor-background)}.monaco-editor .margin-view-overlays .current-line,.monaco-editor .view-overlays .current-line{box-sizing:border-box;display:block;height:100%;left:0;position:absolute;top:0}.monaco-editor .mtkw,.monaco-editor .mtkz{color:var(--vscode-editorWhitespace-foreground)!important}.monaco-editor .minimap.slider-mouseover .minimap-slider.active,.monaco-editor .minimap.slider-mouseover:hover .minimap-slider{opacity:1}.monaco-editor .codelens-decoration>a:hover,.monaco-editor .codelens-decoration>a:hover .codicon{color:var(--vscode-editorLink-activeForeground)!important}.colorpicker-body .hue-strip{background:linear-gradient(180deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.monaco-editor .inlineSuggestionsHints a,.monaco-editor .inlineSuggestionsHints a:hover{color:var(--vscode-foreground)}.monaco-hover ol,.monaco-hover ul{padding-left:20px}.monaco-editor .peekview-widget .head .peekview-title .dirname,.monaco-editor .peekview-widget .head .peekview-title .filename,.monaco-editor .peekview-widget .head .peekview-title .meta{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hc-black .monaco-custom-toggle,.hc-black .monaco-custom-toggle:hover,.hc-light .monaco-custom-toggle,.hc-light .monaco-custom-toggle:hover{background:none}.monaco-editor .movedModified,.monaco-editor .movedOriginal{border:2px solid var(--vscode-diffEditor-move-border)}.monaco-scrollable-element.modified-in-monaco-diff-editor.vs .scrollbar,.monaco-scrollable-element.modified-in-monaco-diff-editor.vs-dark .scrollbar{background:#0000}.modified-in-monaco-diff-editor.hc-black .slider.active,.modified-in-monaco-diff-editor.hc-light .slider.active,.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-black .scrollbar,.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-light .scrollbar{background:none}.monaco-editor .inline-added-margin-view-zone,.monaco-editor .inline-deleted-margin-view-zone{text-align:right}.monaco-diff-editor .gutter{&>div{position:absolute}.gutterItem{opacity:0;transition:opacity .7s;&.showAlways{opacity:1}&.noTransition,&.showAlways{transition:none}}&:hover .gutterItem{opacity:1;transition:opacity .1s ease-in-out}.gutterItem{.background{border-left:2px solid var(--vscode-menu-border);height:100%;left:50%;position:absolute;width:1px}.buttons{align-items:center;display:flex;justify-content:center;position:absolute;width:100%;.monaco-toolbar{height:fit-content;.monaco-action-bar{line-height:1;.actions-container{background:var(--vscode-editorGutter-commentRangeForeground);border-radius:4px;width:fit-content;.action-item{&:hover{background:var(--vscode-toolbar-hoverBackground)}.action-label{padding:1px 2px}}}}}}}}.monaco-diff-editor .diff-hidden-lines-compact{.line-left,.line-right{border-top:1px solid;border-color:var(--vscode-editorCodeLens-foreground);height:1px;margin:auto;opacity:.5;width:100%}.line-left{width:20px}.text{text-wrap:nowrap;color:var(--vscode-editorCodeLens-foreground);font-size:11px;line-height:11px;margin:0 4px}}.monaco-editor .find-widget,.monaco-editor .findOptionsWidget{background-color:var(--vscode-editorWidget-background);box-shadow:0 0 8px 2px var(--vscode-widget-shadow);color:var(--vscode-editorWidget-foreground)}.monaco-editor .find-widget>.find-part .find-actions,.monaco-editor .find-widget>.replace-part .replace-actions{align-items:center;display:flex;height:25px}.monaco-editor .iPadShowKeyboard{background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTMiIGhlaWdodD0iMzYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTQ4LjAzNiA0LjAxSDQuMDA4VjMyLjAzaDQ0LjAyOFY0LjAxWk00LjAwOC4wMDhBNC4wMDMgNC4wMDMgMCAwIDAgLjAwNSA0LjAxVjMyLjAzYTQuMDAzIDQuMDAzIDAgMCAwIDQuMDAzIDQuMDAyaDQ0LjAyOGE0LjAwMyA0LjAwMyAwIDAgMCA0LjAwMy00LjAwMlY0LjAxQTQuMDAzIDQuMDAzIDAgMCAwIDQ4LjAzNi4wMDhINC4wMDhaTTguMDEgOC4wMTNoNC4wMDN2NC4wMDNIOC4wMVY4LjAxM1ptMTIuMDA4IDBoLTQuMDAydjQuMDAzaDQuMDAyVjguMDEzWm00LjAwMyAwaDQuMDAydjQuMDAzaC00LjAwMlY4LjAxM1ptMTIuMDA4IDBoLTQuMDAzdjQuMDAzaDQuMDAzVjguMDEzWm00LjAwMiAwaDQuMDAzdjQuMDAzSDQwLjAzVjguMDEzWm0tMjQuMDE1IDguMDA1SDguMDF2NC4wMDNoOC4wMDZ2LTQuMDAzWm00LjAwMiAwaDQuMDAzdjQuMDAzaC00LjAwM3YtNC4wMDNabTEyLjAwOCAwaC00LjAwM3Y0LjAwM2g0LjAwM3YtNC4wMDNabTEyLjAwOCAwdjQuMDAzaC04LjAwNXYtNC4wMDNoOC4wMDVabS0zMi4wMjEgOC4wMDVIOC4wMXY0LjAwM2g0LjAwM3YtNC4wMDNabTQuMDAzIDBoMjAuMDEzdjQuMDAzSDE2LjAxNnYtNC4wMDNabTI4LjAxOCAwSDQwLjAzdjQuMDAzaDQuMDAzdi00LjAwM1oiIGZpbGw9IiM0MjQyNDIiLz48L2c+PGRlZnM+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMCAwaDUzdjM2SDB6Ii8+PC9jbGlwUGF0aD48L2RlZnM+PC9zdmc+) 50% no-repeat}.monaco-editor.vs-dark .iPadShowKeyboard{background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTMiIGhlaWdodD0iMzYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTQ4LjAzNiA0LjAxSDQuMDA4VjMyLjAzaDQ0LjAyOFY0LjAxWk00LjAwOC4wMDhBNC4wMDMgNC4wMDMgMCAwIDAgLjAwNSA0LjAxVjMyLjAzYTQuMDAzIDQuMDAzIDAgMCAwIDQuMDAzIDQuMDAyaDQ0LjAyOGE0LjAwMyA0LjAwMyAwIDAgMCA0LjAwMy00LjAwMlY0LjAxQTQuMDAzIDQuMDAzIDAgMCAwIDQ4LjAzNi4wMDhINC4wMDhaTTguMDEgOC4wMTNoNC4wMDN2NC4wMDNIOC4wMVY4LjAxM1ptMTIuMDA4IDBoLTQuMDAydjQuMDAzaDQuMDAyVjguMDEzWm00LjAwMyAwaDQuMDAydjQuMDAzaC00LjAwMlY4LjAxM1ptMTIuMDA4IDBoLTQuMDAzdjQuMDAzaDQuMDAzVjguMDEzWm00LjAwMiAwaDQuMDAzdjQuMDAzSDQwLjAzVjguMDEzWm0tMjQuMDE1IDguMDA1SDguMDF2NC4wMDNoOC4wMDZ2LTQuMDAzWm00LjAwMiAwaDQuMDAzdjQuMDAzaC00LjAwM3YtNC4wMDNabTEyLjAwOCAwaC00LjAwM3Y0LjAwM2g0LjAwM3YtNC4wMDNabTEyLjAwOCAwdjQuMDAzaC04LjAwNXYtNC4wMDNoOC4wMDVabS0zMi4wMjEgOC4wMDVIOC4wMXY0LjAwM2g0LjAwM3YtNC4wMDNabTQuMDAzIDBoMjAuMDEzdjQuMDAzSDE2LjAxNnYtNC4wMDNabTI4LjAxOCAwSDQwLjAzdjQuMDAzaDQuMDAzdi00LjAwM1oiIGZpbGw9IiNDNUM1QzUiLz48L2c+PGRlZnM+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMCAwaDUzdjM2SDB6Ii8+PC9jbGlwUGF0aD48L2RlZnM+PC9zdmc+) 50% no-repeat}.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.right>.details-label,.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label)>.contents>.main>.right>.details-label,.monaco-editor .suggest-widget:not(.shows-details) .monaco-list .monaco-list-row.focused>.contents>.main>.right>.details-label{display:inline}.monaco-editor .suggest-details ol,.monaco-editor .suggest-details ul{padding-left:20px}.monaco-editor .inlineEditHints a,.monaco-editor .inlineEditHints a:hover{color:var(--vscode-foreground)}.monaco-editor div.inline-edits-widget{.promptEditor .monaco-editor{--vscode-editor-placeholder-foreground:var(--vscode-editorGhostText-foreground)}.promptEditor,.toolbar{opacity:0;transition:opacity .2s ease-in-out}&.focused,&:hover{.promptEditor,.toolbar{opacity:1}}.preview .monaco-editor{--vscode-editor-background:var(--widget-color);.mtk1{color:var(--vscode-editorGhostText-foreground)}.current-line-margin,.view-overlays .current-line-exact{border:none}}svg{.gradient-start{stop-color:var(--vscode-editor-background)}.gradient-stop{stop-color:var(--widget-color)}}}.monaco-editor{.editorPlaceholder{text-wrap:nowrap;color:var(--vscode-editor-placeholder-foreground);overflow:hidden;pointer-events:none;position:absolute;text-overflow:ellipsis;top:0}}.monaco-editor.hc-black .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-editor.hc-light .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-editor.vs-dark .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-menu .monaco-action-bar.vertical .action-item .action-menu-item:focus .action-label{stroke-width:1.2px}.monaco-diff-editor .synthetic-focus,.monaco-diff-editor [tabindex="-1"]:focus,.monaco-diff-editor [tabindex="0"]:focus,.monaco-diff-editor button:focus,.monaco-diff-editor input[type=button]:focus,.monaco-diff-editor input[type=checkbox]:focus,.monaco-diff-editor input[type=search]:focus,.monaco-diff-editor input[type=text]:focus,.monaco-diff-editor select:focus,.monaco-diff-editor textarea:focus,.monaco-editor{opacity:1;outline-color:var(--vscode-focusBorder);outline-offset:-1px;outline-style:solid;outline-width:1px}.quick-input-widget .monaco-highlighted-label .highlight{color:#0066bf}.vs .quick-input-widget .monaco-list-row.focused .monaco-highlighted-label .highlight{color:#9dddff}.vs-dark .quick-input-widget .monaco-highlighted-label .highlight{color:#0097fb}.hc-black .quick-input-widget .monaco-highlighted-label .highlight{color:#f38518}.hc-light .quick-input-widget .monaco-highlighted-label .highlight{color:#0f4a85}.monaco-keybinding>.monaco-keybinding-key{background-color:#ddd6;border-color:#ccc6 #ccc6 #bbb6;box-shadow:inset 0 -1px 0 #bbb6}.monaco-component.multiDiffEditor{>div{height:100%;left:0;position:absolute;top:0;width:100%;&.placeholder{display:grid;place-content:center;place-items:center;visibility:hidden;&.visible{visibility:visible}}}.active{--vscode-multiDiffEditor-border:var(--vscode-focusBorder)}.multiDiffEntry{display:flex;flex:1 1;flex-direction:column;overflow:hidden;.collapse-button{cursor:pointer;margin:0 5px;a{display:block}}.header{background:var(--vscode-editor-background);z-index:1000;&:not(.collapsed) .header-content{border-bottom:1px solid var(--vscode-sideBarSectionHeader-border)}.header-content{align-items:center;background:var(--vscode-multiDiffEditor-headerBackground);border-top:1px solid var(--vscode-multiDiffEditor-border);color:var(--vscode-foreground);display:flex;margin:8px 0 0;padding:4px 5px;&.shadow{box-shadow:var(--vscode-scrollbar-shadow) 0 6px 6px -6px}.file-path{display:flex;flex:1 1;min-width:0;.title{font-size:14px;line-height:22px;&.original{flex:1 1;min-width:0;text-overflow:ellipsis}}.status{font-weight:600;line-height:22px;margin:0 10px;opacity:.75}}.actions{padding:0 8px}}}.editorParent{border-bottom:1px solid var(--vscode-multiDiffEditor-border);display:flex;flex:1 1;flex-direction:column;overflow:hidden}.editorContainer{flex:1 1}}}.gt-table{border:none;border-collapse:initial;border-spacing:0}.gt-table__row_interactive{cursor:pointer}.gt-table__header_sticky{inset-block-start:0;position:sticky;z-index:1}.gt-table__footer_sticky{inset-block-end:0;position:sticky;z-index:1}.gt-table__cell{font-weight:400}.gt-table__footer-cell,.gt-table__header-cell{font-weight:500;position:relative}.gt-table__cell,.gt-table__footer-cell,.gt-table__header-cell{box-sizing:border-box;height:inherit;padding:0;text-align:start}.gt-table__cell_pinned,.gt-table__footer-cell_pinned,.gt-table__header-cell_pinned{position:sticky;z-index:1}.gt-table__sort{cursor:pointer;-webkit-user-select:none;user-select:none}.gt-table_with-row-virtualization{display:grid;height:auto}.gt-table_with-row-virtualization .gt-table__body{display:grid;position:relative}.gt-table_with-row-virtualization .gt-table__footer,.gt-table_with-row-virtualization .gt-table__header{display:grid}.gt-table_with-row-virtualization .gt-table__footer-row,.gt-table_with-row-virtualization .gt-table__header-row{display:flex;height:auto}.gt-table_with-row-virtualization .gt-table__row{display:flex;height:auto;position:absolute}.gt-table_with-row-virtualization .gt-table__row_empty{position:relative}.gt-group-header{inset-inline-start:0;margin:0;position:sticky}.gt-group-header__button{appearance:none;background:inherit;border:none;cursor:pointer;display:flex;gap:8px;outline:none;padding:0;width:100%}.gt-group-header__icon{display:inline-block;transform:rotate(-90deg);transition:transform .1s ease-out;vertical-align:middle}.gt-group-header__icon_expanded{transform:rotate(0)}.gt-group-header__content{display:inline-flex;font-weight:500;gap:4px}.gt-sort-indicator{color:var(--g-color-text-hint);display:inline-flex;margin-inline-start:4px;transform:rotate(0);vertical-align:middle}.gt-sort-indicator_invisible{opacity:0}.gt-table__header-cell:hover .gt-sort-indicator_invisible{opacity:1}.gt-sort-indicator_order_asc{transform:rotate(180deg)}.gt-resize-handle{background:#d3d3d3;cursor:col-resize;height:100%;inset-block-start:0;opacity:0;position:absolute;touch-action:none;-webkit-user-select:none;user-select:none;width:6px}.gt-resize-handle_direction_ltr{inset-inline-end:0}.gt-resize-handle_direction_rtl{inset-inline-start:0}.gt-resize-handle_resizing,.gt-table__header-cell:hover .gt-resize-handle{opacity:1} -/*!----------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1) - * Released under the MIT license - * https://github.com/microsoft/vscode/blob/main/LICENSE.txt - *-----------------------------------------------------------*/.monaco-action-bar{height:100%;white-space:nowrap}.monaco-action-bar .actions-container{align-items:center;display:flex;height:100%;margin:0 auto;padding:0;width:100%}.monaco-action-bar.vertical .actions-container{display:inline-block}.monaco-action-bar .action-item{align-items:center;cursor:pointer;display:block;justify-content:center;position:relative}.monaco-action-bar .action-item.disabled{cursor:default}.monaco-action-bar .action-item .codicon,.monaco-action-bar .action-item .icon{display:block}.monaco-action-bar .action-item .codicon{align-items:center;display:flex;height:16px;width:16px}.monaco-action-bar .action-label{border-radius:5px;display:flex;font-size:11px;padding:3px}.monaco-action-bar .action-item.disabled .action-label,.monaco-action-bar .action-item.disabled .action-label:before,.monaco-action-bar .action-item.disabled .action-label:hover{color:var(--vscode-disabledForeground)}.monaco-action-bar.vertical{text-align:left}.monaco-action-bar.vertical .action-item{display:block}.monaco-action-bar.vertical .action-label.separator{border-bottom:1px solid #bbb;display:block;margin-left:.8em;margin-right:.8em;padding-top:1px}.monaco-action-bar .action-item .action-label.separator{background-color:#bbb;cursor:default;height:16px;margin:5px 4px!important;min-width:1px;padding:0;width:1px}.secondary-actions .monaco-action-bar .action-label{margin-left:6px}.monaco-action-bar .action-item.select-container{align-items:center;display:flex;flex:1 1;justify-content:center;margin-right:10px;max-width:170px;min-width:60px;overflow:hidden}.monaco-action-bar .action-item.action-dropdown-item{display:flex}.monaco-action-bar .action-item.action-dropdown-item>.action-dropdown-item-separator{align-items:center;cursor:default;display:flex}.monaco-action-bar .action-item.action-dropdown-item>.action-dropdown-item-separator>div{width:1px}.monaco-aria-container{left:-999em;position:absolute}.monaco-text-button{align-items:center;border:1px solid var(--vscode-button-border,#0000);border-radius:2px;box-sizing:border-box;cursor:pointer;display:flex;justify-content:center;line-height:18px;padding:4px;text-align:center;width:100%}.monaco-text-button:focus{outline-offset:2px!important}.monaco-text-button:hover{text-decoration:none!important}.monaco-button.disabled,.monaco-button.disabled:focus{cursor:default;opacity:.4!important}.monaco-text-button .codicon{color:inherit!important;margin:0 .2em}.monaco-text-button.monaco-text-button-with-short-label{flex-direction:row;flex-wrap:wrap;height:28px;overflow:hidden;padding:0 4px}.monaco-text-button.monaco-text-button-with-short-label>.monaco-button-label{flex-basis:100%}.monaco-text-button.monaco-text-button-with-short-label>.monaco-button-label-short{flex-grow:1;overflow:hidden;width:0}.monaco-text-button.monaco-text-button-with-short-label>.monaco-button-label,.monaco-text-button.monaco-text-button-with-short-label>.monaco-button-label-short{align-items:center;display:flex;font-style:inherit;font-weight:400;justify-content:center;padding:4px 0}.monaco-button-dropdown{cursor:pointer;display:flex}.monaco-button-dropdown.disabled{cursor:default}.monaco-button-dropdown>.monaco-button:focus{outline-offset:-1px!important}.monaco-button-dropdown.disabled>.monaco-button-dropdown-separator,.monaco-button-dropdown.disabled>.monaco-button.disabled,.monaco-button-dropdown.disabled>.monaco-button.disabled:focus{opacity:.4!important}.monaco-button-dropdown>.monaco-button.monaco-text-button{border-right-width:0!important}.monaco-button-dropdown .monaco-button-dropdown-separator{cursor:default;padding:4px 0}.monaco-button-dropdown .monaco-button-dropdown-separator>div{height:100%;width:1px}.monaco-button-dropdown>.monaco-button.monaco-dropdown-button{align-items:center;border:1px solid var(--vscode-button-border,#0000);border-left-width:0!important;border-radius:0 2px 2px 0;display:flex}.monaco-button-dropdown>.monaco-button.monaco-text-button{border-radius:2px 0 0 2px}.monaco-description-button{align-items:center;display:flex;flex-direction:column;margin:4px 5px}.monaco-description-button .monaco-button-description{font-size:11px;font-style:italic;padding:4px 20px}.monaco-description-button .monaco-button-description,.monaco-description-button .monaco-button-label{align-items:center;display:flex;justify-content:center}.monaco-description-button .monaco-button-description>.codicon,.monaco-description-button .monaco-button-label>.codicon{color:inherit!important;margin:0 .2em}.monaco-button-dropdown.default-colors>.monaco-button,.monaco-button.default-colors{background-color:var(--vscode-button-background);color:var(--vscode-button-foreground)}.monaco-button-dropdown.default-colors>.monaco-button:hover,.monaco-button.default-colors:hover{background-color:var(--vscode-button-hoverBackground)}.monaco-button-dropdown.default-colors>.monaco-button.secondary,.monaco-button.default-colors.secondary{background-color:var(--vscode-button-secondaryBackground);color:var(--vscode-button-secondaryForeground)}.monaco-button-dropdown.default-colors>.monaco-button.secondary:hover,.monaco-button.default-colors.secondary:hover{background-color:var(--vscode-button-secondaryHoverBackground)}.monaco-button-dropdown.default-colors .monaco-button-dropdown-separator{background-color:var(--vscode-button-background);border-bottom:1px solid var(--vscode-button-border);border-top:1px solid var(--vscode-button-border)}.monaco-button-dropdown.default-colors .monaco-button.secondary+.monaco-button-dropdown-separator{background-color:var(--vscode-button-secondaryBackground)}.monaco-button-dropdown.default-colors .monaco-button-dropdown-separator>div{background-color:var(--vscode-button-separator)}@font-face{font-display:block;font-family:codicon;src:url(../../static/media/codicon.f6283f7ccaed1249d9eb.ttf) format("truetype")}.codicon[class*=codicon-]{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;font:normal normal normal 16px/1 codicon;text-align:center;text-decoration:none;text-rendering:auto;text-transform:none;user-select:none;-webkit-user-select:none}.codicon-wrench-subaction{opacity:.5}@keyframes codicon-spin{to{transform:rotate(1turn)}}.codicon-gear.codicon-modifier-spin,.codicon-loading.codicon-modifier-spin,.codicon-notebook-state-executing.codicon-modifier-spin,.codicon-sync.codicon-modifier-spin{animation:codicon-spin 1.5s steps(30) infinite}.codicon-modifier-disabled{opacity:.4}.codicon-loading,.codicon-tree-item-loading:before{animation-duration:1s!important;animation-timing-function:cubic-bezier(.53,.21,.29,.67)!important}.context-view{position:absolute}.context-view.fixed{all:initial;color:inherit;font-family:inherit;font-size:13px;position:fixed}.monaco-count-badge{border-radius:11px;box-sizing:border-box;display:inline-block;font-size:11px;font-weight:400;line-height:11px;min-height:18px;min-width:18px;padding:3px 6px;text-align:center}.monaco-count-badge.long{border-radius:2px;line-height:normal;min-height:auto;padding:2px 3px}.monaco-dropdown{height:100%;padding:0}.monaco-dropdown>.dropdown-label{align-items:center;cursor:pointer;display:flex;height:100%;justify-content:center}.monaco-dropdown>.dropdown-label>.action-label.disabled{cursor:default}.monaco-dropdown-with-primary{border-radius:5px;display:flex!important;flex-direction:row}.monaco-dropdown-with-primary>.action-container>.action-label{margin-right:0}.monaco-dropdown-with-primary>.dropdown-action-container>.monaco-dropdown>.dropdown-label .codicon[class*=codicon-]{font-size:12px;line-height:16px;margin-left:-3px;padding-left:0;padding-right:0}.monaco-dropdown-with-primary>.dropdown-action-container>.monaco-dropdown>.dropdown-label>.action-label{background-position:50%;background-repeat:no-repeat;background-size:16px;display:block}.monaco-findInput{position:relative}.monaco-findInput .monaco-inputbox{font-size:13px;width:100%}.monaco-findInput>.controls{position:absolute;right:2px;top:3px}.vs .monaco-findInput.disabled{background-color:#e1e1e1}.vs-dark .monaco-findInput.disabled{background-color:#333}.hc-light .monaco-findInput.highlight-0 .controls,.monaco-findInput.highlight-0 .controls{animation:monaco-findInput-highlight-0 .1s linear 0s}.hc-light .monaco-findInput.highlight-1 .controls,.monaco-findInput.highlight-1 .controls{animation:monaco-findInput-highlight-1 .1s linear 0s}.hc-black .monaco-findInput.highlight-0 .controls,.vs-dark .monaco-findInput.highlight-0 .controls{animation:monaco-findInput-highlight-dark-0 .1s linear 0s}.hc-black .monaco-findInput.highlight-1 .controls,.vs-dark .monaco-findInput.highlight-1 .controls{animation:monaco-findInput-highlight-dark-1 .1s linear 0s}@keyframes monaco-findInput-highlight-0{0%{background:#fdff00cc}to{background:#0000}}@keyframes monaco-findInput-highlight-1{0%{background:#fdff00cc}99%{background:#0000}}@keyframes monaco-findInput-highlight-dark-0{0%{background:#ffffff70}to{background:#0000}}@keyframes monaco-findInput-highlight-dark-1{0%{background:#ffffff70}99%{background:#0000}}.monaco-hover{animation:fadein .1s linear;box-sizing:border-box;cursor:default;line-height:1.5em;overflow:hidden;position:absolute;user-select:text;-webkit-user-select:text;white-space:var(--vscode-hover-whiteSpace,normal)}.monaco-hover.hidden{display:none}.monaco-hover a:hover:not(.disabled){cursor:pointer}.monaco-hover .hover-contents:not(.html-hover-contents){padding:4px 8px}.monaco-hover .markdown-hover>.hover-contents:not(.code-hover-contents){word-wrap:break-word;max-width:var(--vscode-hover-maxWidth,500px)}.monaco-hover .markdown-hover>.hover-contents:not(.code-hover-contents) hr{min-width:100%}.monaco-hover .code,.monaco-hover h1,.monaco-hover h2,.monaco-hover h3,.monaco-hover h4,.monaco-hover h5,.monaco-hover h6,.monaco-hover p,.monaco-hover ul{margin:8px 0}.monaco-hover h1,.monaco-hover h2,.monaco-hover h3,.monaco-hover h4,.monaco-hover h5,.monaco-hover h6{line-height:1.1}.monaco-hover code{font-family:var(--monaco-monospace-font)}.monaco-hover hr{border-left:0;border-right:0;box-sizing:border-box;height:1px;margin:4px -8px -4px}.monaco-hover .code:first-child,.monaco-hover p:first-child,.monaco-hover ul:first-child{margin-top:0}.monaco-hover .code:last-child,.monaco-hover p:last-child,.monaco-hover ul:last-child{margin-bottom:0}.monaco-hover ol,.monaco-hover ul{padding-left:20px}.monaco-hover li>p{margin-bottom:0}.monaco-hover li>ul{margin-top:0}.monaco-hover code{border-radius:3px;padding:0 .4em}.monaco-hover .monaco-tokenized-source{white-space:var(--vscode-hover-sourceWhiteSpace,pre-wrap)}.monaco-hover .hover-row.status-bar{font-size:12px;line-height:22px}.monaco-hover .hover-row.status-bar .info{font-style:italic;padding:0 8px}.monaco-hover .hover-row.status-bar .actions{display:flex;padding:0 8px;width:100%}.monaco-hover .hover-row.status-bar .actions .action-container{cursor:pointer;margin-right:16px}.monaco-hover .hover-row.status-bar .actions .action-container .action .icon{padding-right:4px}.monaco-hover .hover-row.status-bar .actions .action-container a{color:var(--vscode-textLink-foreground);-webkit-text-decoration:var(--text-link-decoration);text-decoration:var(--text-link-decoration)}.monaco-hover .markdown-hover .hover-contents .codicon{color:inherit;font-size:inherit;vertical-align:middle}.monaco-hover .hover-contents a.code-link,.monaco-hover .hover-contents a.code-link:hover{color:inherit}.monaco-hover .hover-contents a.code-link:before{content:"("}.monaco-hover .hover-contents a.code-link:after{content:")"}.monaco-hover .hover-contents a.code-link>span{border-bottom:1px solid #0000;color:var(--vscode-textLink-foreground);text-decoration:underline;text-underline-position:under}.monaco-hover .hover-contents a.code-link>span:hover{color:var(--vscode-textLink-activeForeground)}.monaco-hover .markdown-hover .hover-contents:not(.code-hover-contents):not(.html-hover-contents) span{display:inline-block;margin-bottom:4px}.monaco-hover .markdown-hover .hover-contents:not(.code-hover-contents):not(.html-hover-contents) span.codicon{margin-bottom:2px}.monaco-hover-content .action-container a{-webkit-user-select:none;user-select:none}.monaco-hover-content .action-container.disabled{cursor:default;opacity:.4;pointer-events:none}.monaco-icon-label{display:flex;overflow:hidden;text-overflow:ellipsis}.monaco-icon-label:before{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-position:0;background-repeat:no-repeat;background-size:16px;display:inline-block;flex-shrink:0;height:22px;line-height:inherit!important;padding-right:6px;vertical-align:top;width:16px}.monaco-icon-label-iconpath{display:flex;height:16px;margin-top:2px;padding-left:2px;width:16px}.monaco-icon-label-container.disabled{color:var(--vscode-disabledForeground)}.monaco-icon-label>.monaco-icon-label-container{flex:1 1;min-width:0;overflow:hidden;text-overflow:ellipsis}.monaco-icon-label>.monaco-icon-label-container>.monaco-icon-name-container>.label-name{color:inherit;white-space:pre}.monaco-icon-label>.monaco-icon-label-container>.monaco-icon-name-container>.label-name>.label-separator{margin:0 2px;opacity:.5}.monaco-icon-label>.monaco-icon-label-container>.monaco-icon-suffix-container>.label-suffix{opacity:.7;white-space:pre}.monaco-icon-label>.monaco-icon-label-container>.monaco-icon-description-container>.label-description{font-size:.9em;margin-left:.5em;opacity:.7;white-space:pre}.monaco-icon-label.nowrap>.monaco-icon-label-container>.monaco-icon-description-container>.label-description{white-space:nowrap}.vs .monaco-icon-label>.monaco-icon-label-container>.monaco-icon-description-container>.label-description{opacity:.95}.monaco-icon-label.italic>.monaco-icon-label-container>.monaco-icon-description-container>.label-description,.monaco-icon-label.italic>.monaco-icon-label-container>.monaco-icon-name-container>.label-name{font-style:italic}.monaco-icon-label.deprecated{opacity:.66;text-decoration:line-through}.monaco-icon-label.italic:after{font-style:italic}.monaco-icon-label.strikethrough>.monaco-icon-label-container>.monaco-icon-description-container>.label-description,.monaco-icon-label.strikethrough>.monaco-icon-label-container>.monaco-icon-name-container>.label-name{text-decoration:line-through}.monaco-icon-label:after{font-size:90%;font-weight:600;margin:auto 16px 0 5px;opacity:.75;text-align:center}.monaco-list:focus .selected .monaco-icon-label,.monaco-list:focus .selected .monaco-icon-label:after{color:inherit!important}.monaco-list-row.focused.selected .label-description,.monaco-list-row.selected .label-description{opacity:.8}.monaco-inputbox{border-radius:2px;box-sizing:border-box;display:block;font-size:inherit;padding:0;position:relative}.monaco-inputbox>.ibwrapper>.input,.monaco-inputbox>.ibwrapper>.mirror{padding:4px 6px}.monaco-inputbox>.ibwrapper{height:100%;position:relative;width:100%}.monaco-inputbox>.ibwrapper>.input{border:none;box-sizing:border-box;color:inherit;display:inline-block;font-family:inherit;font-size:inherit;height:100%;line-height:inherit;resize:none;width:100%}.monaco-inputbox>.ibwrapper>input{text-overflow:ellipsis}.monaco-inputbox>.ibwrapper>textarea.input{display:block;outline:none;scrollbar-width:none}.monaco-inputbox>.ibwrapper>textarea.input::-webkit-scrollbar{display:none}.monaco-inputbox>.ibwrapper>textarea.input.empty{white-space:nowrap}.monaco-inputbox>.ibwrapper>.mirror{word-wrap:break-word;box-sizing:border-box;display:inline-block;left:0;position:absolute;top:0;visibility:hidden;white-space:pre-wrap;width:100%}.monaco-inputbox-container{text-align:right}.monaco-inputbox-container .monaco-inputbox-message{word-wrap:break-word;box-sizing:border-box;display:inline-block;font-size:12px;line-height:17px;margin-top:-1px;overflow:hidden;padding:.4em;text-align:left;width:100%}.monaco-inputbox .monaco-action-bar{position:absolute;right:2px;top:4px}.monaco-inputbox .monaco-action-bar .action-item{margin-left:2px}.monaco-inputbox .monaco-action-bar .action-item .codicon{background-repeat:no-repeat;height:16px;width:16px}.monaco-keybinding{align-items:center;display:flex;line-height:10px}.monaco-keybinding>.monaco-keybinding-key{border-radius:3px;border-style:solid;border-width:1px;display:inline-block;font-size:11px;margin:0 2px;padding:3px 5px;vertical-align:middle}.monaco-keybinding>.monaco-keybinding-key:first-child{margin-left:0}.monaco-keybinding>.monaco-keybinding-key:last-child{margin-right:0}.monaco-keybinding>.monaco-keybinding-key-separator{display:inline-block}.monaco-keybinding>.monaco-keybinding-key-chord-separator{width:6px}.monaco-list{height:100%;position:relative;white-space:nowrap;width:100%}.monaco-list.mouse-support{user-select:none;-webkit-user-select:none}.monaco-list>.monaco-scrollable-element{height:100%}.monaco-list-rows{height:100%;position:relative;width:100%}.monaco-list.horizontal-scrolling .monaco-list-rows{min-width:100%;width:auto}.monaco-list-row{box-sizing:border-box;overflow:hidden;position:absolute;width:100%}.monaco-list.mouse-support .monaco-list-row{cursor:pointer;touch-action:none}.monaco-list .monaco-scrollable-element>.scrollbar.vertical,.monaco-pane-view>.monaco-split-view2.vertical>.monaco-scrollable-element>.scrollbar.vertical{z-index:14}.monaco-list-row.scrolling{display:none!important}.monaco-list.element-focused,.monaco-list.selection-multiple,.monaco-list.selection-single{outline:0!important}.monaco-drag-image{border-radius:10px;display:inline-block;font-size:12px;padding:1px 7px;position:absolute;z-index:1000}.monaco-list-type-filter-message{box-sizing:border-box;height:100%;left:0;opacity:.7;padding:40px 1em 1em;pointer-events:none;position:absolute;text-align:center;top:0;white-space:normal;width:100%}.monaco-list-type-filter-message:empty{display:none}.monaco-mouse-cursor-text{cursor:text}.monaco-progress-container{height:2px;overflow:hidden;width:100%}.monaco-progress-container .progress-bit{display:none;height:2px;left:0;position:absolute;width:2%}.monaco-progress-container.active .progress-bit{display:inherit}.monaco-progress-container.discrete .progress-bit{left:0;transition:width .1s linear}.monaco-progress-container.discrete.done .progress-bit{width:100%}.monaco-progress-container.infinite .progress-bit{animation-duration:4s;animation-iteration-count:infinite;animation-name:progress;animation-timing-function:linear;transform:translateZ(0)}.monaco-progress-container.infinite.infinite-long-running .progress-bit{animation-timing-function:steps(100)}@keyframes progress{0%{transform:translateX(0) scaleX(1)}50%{transform:translateX(2500%) scaleX(3)}to{transform:translateX(4900%) scaleX(1)}}:root{--vscode-sash-size:4px;--vscode-sash-hover-size:4px}.monaco-sash{position:absolute;touch-action:none;z-index:35}.monaco-sash.disabled{pointer-events:none}.monaco-sash.mac.vertical{cursor:col-resize}.monaco-sash.vertical.minimum{cursor:e-resize}.monaco-sash.vertical.maximum{cursor:w-resize}.monaco-sash.mac.horizontal{cursor:row-resize}.monaco-sash.horizontal.minimum{cursor:s-resize}.monaco-sash.horizontal.maximum{cursor:n-resize}.monaco-sash.disabled{cursor:default!important;pointer-events:none!important}.monaco-sash.vertical{cursor:ew-resize;height:100%;top:0;width:var(--vscode-sash-size)}.monaco-sash.horizontal{cursor:ns-resize;height:var(--vscode-sash-size);left:0;width:100%}.monaco-sash:not(.disabled)>.orthogonal-drag-handle{content:" ";cursor:all-scroll;display:block;height:calc(var(--vscode-sash-size)*2);position:absolute;width:calc(var(--vscode-sash-size)*2);z-index:100}.monaco-sash.horizontal.orthogonal-edge-north:not(.disabled)>.orthogonal-drag-handle.start,.monaco-sash.horizontal.orthogonal-edge-south:not(.disabled)>.orthogonal-drag-handle.end{cursor:nwse-resize}.monaco-sash.horizontal.orthogonal-edge-north:not(.disabled)>.orthogonal-drag-handle.end,.monaco-sash.horizontal.orthogonal-edge-south:not(.disabled)>.orthogonal-drag-handle.start{cursor:nesw-resize}.monaco-sash.vertical>.orthogonal-drag-handle.start{left:calc(var(--vscode-sash-size)*-.5);top:calc(var(--vscode-sash-size)*-1)}.monaco-sash.vertical>.orthogonal-drag-handle.end{bottom:calc(var(--vscode-sash-size)*-1);left:calc(var(--vscode-sash-size)*-.5)}.monaco-sash.horizontal>.orthogonal-drag-handle.start{left:calc(var(--vscode-sash-size)*-1);top:calc(var(--vscode-sash-size)*-.5)}.monaco-sash.horizontal>.orthogonal-drag-handle.end{right:calc(var(--vscode-sash-size)*-1);top:calc(var(--vscode-sash-size)*-.5)}.monaco-sash:before{background:#0000;content:"";height:100%;pointer-events:none;position:absolute;width:100%}.monaco-workbench:not(.reduce-motion) .monaco-sash:before{transition:background-color .1s ease-out}.monaco-sash.active:before,.monaco-sash.hover:before{background:var(--vscode-sash-hoverBorder)}.monaco-sash.vertical:before{left:calc(50% - var(--vscode-sash-hover-size)/2);width:var(--vscode-sash-hover-size)}.monaco-sash.horizontal:before{height:var(--vscode-sash-hover-size);top:calc(50% - var(--vscode-sash-hover-size)/2)}.pointer-events-disabled{pointer-events:none!important}.monaco-sash.debug{background:cyan}.monaco-sash.debug.disabled{background:#0ff3}.monaco-sash.debug:not(.disabled)>.orthogonal-drag-handle{background:red}.monaco-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.monaco-scrollable-element>.visible{background:#0000;opacity:1;transition:opacity .1s linear;z-index:11}.monaco-scrollable-element>.invisible{opacity:0;pointer-events:none}.monaco-scrollable-element>.invisible.fade{transition:opacity .8s linear}.monaco-scrollable-element>.shadow{display:none;position:absolute}.monaco-scrollable-element>.shadow.top{box-shadow:var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset;display:block;height:3px;left:3px;top:0;width:100%}.monaco-scrollable-element>.shadow.left{box-shadow:var(--vscode-scrollbar-shadow) 6px 0 6px -6px inset;display:block;height:100%;left:0;top:3px;width:3px}.monaco-scrollable-element>.shadow.top-left-corner{display:block;height:3px;left:0;top:0;width:3px}.monaco-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow) 6px 0 6px -6px inset}.monaco-scrollable-element>.scrollbar>.slider{background:var(--vscode-scrollbarSlider-background)}.monaco-scrollable-element>.scrollbar>.slider:hover{background:var(--vscode-scrollbarSlider-hoverBackground)}.monaco-scrollable-element>.scrollbar>.slider.active{background:var(--vscode-scrollbarSlider-activeBackground)}.monaco-select-box{border-radius:2px;cursor:pointer;width:100%}.monaco-select-box-dropdown-container{font-size:13px;font-weight:400;text-transform:none}.monaco-action-bar .action-item.select-container{cursor:default}.monaco-action-bar .action-item .monaco-select-box{cursor:pointer;min-height:18px;min-width:100px;padding:2px 23px 2px 8px}.mac .monaco-action-bar .action-item .monaco-select-box{border-radius:5px;font-size:11px}.monaco-select-box-dropdown-padding{--dropdown-padding-top:1px;--dropdown-padding-bottom:1px}.hc-black .monaco-select-box-dropdown-padding,.hc-light .monaco-select-box-dropdown-padding{--dropdown-padding-top:3px;--dropdown-padding-bottom:4px}.monaco-select-box-dropdown-container{box-sizing:border-box;display:none}.monaco-select-box-dropdown-container>.select-box-details-pane>.select-box-description-markdown *{margin:0}.monaco-select-box-dropdown-container>.select-box-details-pane>.select-box-description-markdown a:focus{outline:1px solid -webkit-focus-ring-color;outline-offset:-1px}.monaco-select-box-dropdown-container>.select-box-details-pane>.select-box-description-markdown code{font-family:var(--monaco-monospace-font);line-height:15px}.monaco-select-box-dropdown-container.visible{border-bottom-left-radius:3px;border-bottom-right-radius:3px;display:flex;flex-direction:column;overflow:hidden;text-align:left;width:1px}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container{align-self:flex-start;box-sizing:border-box;flex:0 0 auto;overflow:hidden;padding-bottom:var(--dropdown-padding-bottom);padding-left:1px;padding-right:1px;padding-top:var(--dropdown-padding-top);width:100%}.monaco-select-box-dropdown-container>.select-box-details-pane{padding:5px}.hc-black .monaco-select-box-dropdown-container>.select-box-dropdown-list-container{padding-bottom:var(--dropdown-padding-bottom);padding-top:var(--dropdown-padding-top)}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row{cursor:pointer}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row>.option-text{float:left;overflow:hidden;padding-left:3.5px;text-overflow:ellipsis;white-space:nowrap}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row>.option-detail{float:left;opacity:.7;overflow:hidden;padding-left:3.5px;text-overflow:ellipsis;white-space:nowrap}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row>.option-decorator-right{float:right;overflow:hidden;padding-right:10px;text-overflow:ellipsis;white-space:nowrap}.monaco-select-box-dropdown-container>.select-box-dropdown-list-container .monaco-list .monaco-list-row>.visually-hidden{height:1px;left:-10000px;overflow:hidden;position:absolute;top:auto;width:1px}.monaco-select-box-dropdown-container>.select-box-dropdown-container-width-control{align-self:flex-start;flex:1 1 auto;opacity:0}.monaco-select-box-dropdown-container>.select-box-dropdown-container-width-control>.width-control-div{max-height:0;overflow:hidden}.monaco-select-box-dropdown-container>.select-box-dropdown-container-width-control>.width-control-div>.option-text-width-control{padding-left:4px;padding-right:8px;white-space:nowrap}.monaco-split-view2{height:100%;position:relative;width:100%}.monaco-split-view2>.sash-container{height:100%;pointer-events:none;position:absolute;width:100%}.monaco-split-view2>.sash-container>.monaco-sash{pointer-events:auto}.monaco-split-view2>.monaco-scrollable-element{height:100%;width:100%}.monaco-split-view2>.monaco-scrollable-element>.split-view-container{height:100%;position:relative;white-space:nowrap;width:100%}.monaco-split-view2>.monaco-scrollable-element>.split-view-container>.split-view-view{position:absolute;white-space:normal}.monaco-split-view2>.monaco-scrollable-element>.split-view-container>.split-view-view:not(.visible){display:none}.monaco-split-view2.vertical>.monaco-scrollable-element>.split-view-container>.split-view-view{width:100%}.monaco-split-view2.horizontal>.monaco-scrollable-element>.split-view-container>.split-view-view{height:100%}.monaco-split-view2.separator-border>.monaco-scrollable-element>.split-view-container>.split-view-view:not(:first-child):before{background-color:var(--separator-border);content:" ";left:0;pointer-events:none;position:absolute;top:0;z-index:5}.monaco-split-view2.separator-border.horizontal>.monaco-scrollable-element>.split-view-container>.split-view-view:not(:first-child):before{height:100%;width:1px}.monaco-split-view2.separator-border.vertical>.monaco-scrollable-element>.split-view-container>.split-view-view:not(:first-child):before{height:1px;width:100%}.monaco-table{display:flex;flex-direction:column;height:100%;overflow:hidden;position:relative;white-space:nowrap;width:100%}.monaco-table>.monaco-split-view2{border-bottom:1px solid #0000}.monaco-table>.monaco-list{flex:1 1}.monaco-table-tr{display:flex;height:100%}.monaco-table-th{font-weight:700;height:100%;overflow:hidden;text-overflow:ellipsis;width:100%}.monaco-table-td,.monaco-table-th{box-sizing:border-box;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.monaco-table>.monaco-split-view2 .monaco-sash.vertical:before{border-left:1px solid #0000;content:"";left:calc(var(--vscode-sash-size)/2);position:absolute;width:0}.monaco-workbench:not(.reduce-motion) .monaco-table>.monaco-split-view2,.monaco-workbench:not(.reduce-motion) .monaco-table>.monaco-split-view2 .monaco-sash.vertical:before{transition:border-color .2s ease-out}.monaco-custom-toggle{border:1px solid #0000;border-radius:3px;box-sizing:border-box;cursor:pointer;float:left;height:20px;margin-left:2px;overflow:hidden;padding:1px;user-select:none;-webkit-user-select:none;width:20px}.monaco-custom-toggle:hover{background-color:var(--vscode-inputOption-hoverBackground)}.hc-black .monaco-custom-toggle:hover,.hc-light .monaco-custom-toggle:hover{border:1px dashed var(--vscode-focusBorder)}.hc-black .monaco-custom-toggle,.hc-black .monaco-custom-toggle:hover,.hc-light .monaco-custom-toggle,.hc-light .monaco-custom-toggle:hover{background:none}.monaco-custom-toggle.monaco-checkbox{background-size:16px!important;border:1px solid #0000;border-radius:3px;height:18px;margin-left:0;margin-right:9px;opacity:1;padding:0;width:18px}.monaco-action-bar .checkbox-action-item{align-items:center;border-radius:2px;display:flex;padding-right:2px}.monaco-action-bar .checkbox-action-item:hover{background-color:var(--vscode-toolbar-hoverBackground)}.monaco-action-bar .checkbox-action-item>.monaco-custom-toggle.monaco-checkbox{margin-right:4px}.monaco-action-bar .checkbox-action-item>.checkbox-label{font-size:12px}.monaco-custom-toggle.monaco-checkbox:not(.checked):before{visibility:hidden}.monaco-toolbar{height:100%}.monaco-toolbar .toolbar-toggle-more{display:inline-block;padding:0}.monaco-tl-row{align-items:center;display:flex;height:100%;position:relative}.monaco-tl-row.disabled{cursor:default}.monaco-tl-indent{height:100%;left:16px;pointer-events:none;position:absolute;top:0}.hide-arrows .monaco-tl-indent{left:12px}.monaco-tl-indent>.indent-guide{border-left:1px solid #0000;box-sizing:border-box;display:inline-block;height:100%}.monaco-workbench:not(.reduce-motion) .monaco-tl-indent>.indent-guide{transition:border-color .1s linear}.monaco-tl-contents,.monaco-tl-twistie{height:100%}.monaco-tl-twistie{align-items:center;display:flex!important;flex-shrink:0;font-size:10px;justify-content:center;padding-right:6px;text-align:right;transform:translateX(3px);width:16px}.monaco-tl-contents{flex:1 1;overflow:hidden}.monaco-tl-twistie:before{border-radius:20px}.monaco-tl-twistie.collapsed:before{transform:rotate(-90deg)}.monaco-tl-twistie.codicon-tree-item-loading:before{animation:codicon-spin 1.25s steps(30) infinite}.monaco-tree-type-filter{border:1px solid var(--vscode-widget-border);border-bottom-left-radius:4px;border-bottom-right-radius:4px;display:flex;margin:0 6px;max-width:200px;padding:3px;position:absolute;top:0;z-index:100}.monaco-workbench:not(.reduce-motion) .monaco-tree-type-filter{transition:top .3s}.monaco-tree-type-filter.disabled{top:-40px!important}.monaco-tree-type-filter-grab{align-items:center;cursor:grab;display:flex!important;justify-content:center;margin-right:2px}.monaco-tree-type-filter-grab.grabbing{cursor:grabbing}.monaco-tree-type-filter-input{flex:1 1}.monaco-tree-type-filter-input .monaco-inputbox{height:23px}.monaco-tree-type-filter-input .monaco-inputbox>.ibwrapper>.input,.monaco-tree-type-filter-input .monaco-inputbox>.ibwrapper>.mirror{padding:2px 4px}.monaco-tree-type-filter-input .monaco-findInput>.controls{top:2px}.monaco-tree-type-filter-actionbar{margin-left:4px}.monaco-tree-type-filter-actionbar .monaco-action-bar .action-label{padding:2px}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container{background-color:var(--vscode-sideBar-background);height:0;left:0;position:absolute;top:0;width:100%;z-index:13}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-row.monaco-list-row{background-color:var(--vscode-sideBar-background);opacity:1!important;overflow:hidden;position:absolute;width:100%}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-row:hover{background-color:var(--vscode-list-hoverBackground)!important;cursor:pointer}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container.empty,.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container.empty .monaco-tree-sticky-container-shadow{display:none}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-container-shadow{bottom:-3px;height:0;left:0;position:absolute;width:100%}.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container[tabindex="0"]:focus{outline:none}.monaco-editor .inputarea{background-color:initial;border:none;color:#0000;margin:0;min-height:0;min-width:0;outline:none!important;overflow:hidden;padding:0;position:absolute;resize:none;z-index:-10}.monaco-editor .inputarea.ime-input{caret-color:var(--vscode-editorCursor-foreground);color:var(--vscode-editor-foreground);z-index:10}.monaco-workbench .workbench-hover{background:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);border-radius:3px;box-shadow:0 2px 8px var(--vscode-widget-shadow);color:var(--vscode-editorHoverWidget-foreground);font-size:13px;line-height:19px;max-width:700px;overflow:hidden;position:relative;z-index:40}.monaco-workbench .workbench-hover hr{border-bottom:none}.monaco-workbench .workbench-hover:not(.skip-fade-in){animation:fadein .1s linear}.monaco-workbench .workbench-hover.compact{font-size:12px}.monaco-workbench .workbench-hover.compact .hover-contents{padding:2px 8px}.monaco-workbench .workbench-hover-container.locked .workbench-hover{outline:1px solid var(--vscode-editorHoverWidget-border)}.monaco-workbench .workbench-hover-container.locked .workbench-hover:focus,.monaco-workbench .workbench-hover-lock:focus{outline:1px solid var(--vscode-focusBorder)}.monaco-workbench .workbench-hover-container.locked .workbench-hover-lock:hover{background:var(--vscode-toolbar-hoverBackground)}.monaco-workbench .workbench-hover-pointer{pointer-events:none;position:absolute;z-index:41}.monaco-workbench .workbench-hover-pointer:after{background-color:var(--vscode-editorHoverWidget-background);border-bottom:1px solid var(--vscode-editorHoverWidget-border);border-right:1px solid var(--vscode-editorHoverWidget-border);content:"";height:5px;position:absolute;width:5px}.monaco-workbench .locked .workbench-hover-pointer:after{border-bottom-width:2px;border-right-width:2px;height:4px;width:4px}.monaco-workbench .workbench-hover-pointer.left{left:-3px}.monaco-workbench .workbench-hover-pointer.right{right:3px}.monaco-workbench .workbench-hover-pointer.top{top:-3px}.monaco-workbench .workbench-hover-pointer.bottom{bottom:3px}.monaco-workbench .workbench-hover-pointer.left:after{transform:rotate(135deg)}.monaco-workbench .workbench-hover-pointer.right:after{transform:rotate(315deg)}.monaco-workbench .workbench-hover-pointer.top:after{transform:rotate(225deg)}.monaco-workbench .workbench-hover-pointer.bottom:after{transform:rotate(45deg)}.monaco-workbench .workbench-hover a{color:var(--vscode-textLink-foreground)}.monaco-workbench .workbench-hover a:focus{outline:1px solid;outline-color:var(--vscode-focusBorder);outline-offset:-1px;text-decoration:underline}.monaco-workbench .workbench-hover a:active,.monaco-workbench .workbench-hover a:hover{color:var(--vscode-textLink-activeForeground)}.monaco-workbench .workbench-hover code{background:var(--vscode-textCodeBlock-background)}.monaco-workbench .workbench-hover .hover-row .actions{background:var(--vscode-editorHoverWidget-statusBarBackground)}.monaco-workbench .workbench-hover.right-aligned{left:1px}.monaco-workbench .workbench-hover.right-aligned .hover-row.status-bar .actions{flex-direction:row-reverse}.monaco-workbench .workbench-hover.right-aligned .hover-row.status-bar .actions .action-container{margin-left:16px;margin-right:0}.monaco-editor .blockDecorations-container{pointer-events:none;position:absolute;top:0}.monaco-editor .blockDecorations-block{box-sizing:border-box;position:absolute}.monaco-editor .margin-view-overlays .current-line,.monaco-editor .view-overlays .current-line{box-sizing:border-box;display:block;height:100%;left:0;position:absolute;top:0}.monaco-editor - .margin-view-overlays - .current-line.current-line-margin.current-line-margin-both{border-right:0}.monaco-editor .lines-content .cdr{height:100%;position:absolute}.monaco-editor .glyph-margin{position:absolute;top:0}.monaco-editor .glyph-margin-widgets .cgmr{align-items:center;display:flex;justify-content:center;position:absolute}.monaco-editor .glyph-margin-widgets .cgmr.codicon-modifier-spin:before{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.monaco-editor .lines-content .core-guide{box-sizing:border-box;height:100%;position:absolute}.monaco-editor .margin-view-overlays .line-numbers{font-feature-settings:"tnum";bottom:0;box-sizing:border-box;cursor:default;display:inline-block;font-variant-numeric:tabular-nums;position:absolute;text-align:right;vertical-align:middle}.monaco-editor .relative-current-line-number{display:inline-block;text-align:left;width:100%}.monaco-editor .margin-view-overlays .line-numbers.lh-odd{margin-top:1px}.monaco-editor .line-numbers{color:var(--vscode-editorLineNumber-foreground)}.monaco-editor .line-numbers.active-line-number{color:var(--vscode-editorLineNumber-activeForeground)}.mtkcontrol{background:#960000!important;color:#fff!important}.mtkoverflow{background-color:var(--vscode-button-background,var(--vscode-editor-background));border-color:var(--vscode-contrastBorder);border-radius:2px;border-style:solid;border-width:1px;color:var(--vscode-button-foreground,var(--vscode-editor-foreground));cursor:pointer;padding:4px}.mtkoverflow:hover{background-color:var(--vscode-button-hoverBackground)}.monaco-editor.no-user-select .lines-content,.monaco-editor.no-user-select .view-line,.monaco-editor.no-user-select .view-lines{user-select:none;-webkit-user-select:none}.monaco-editor.mac .lines-content:hover,.monaco-editor.mac .view-line:hover,.monaco-editor.mac .view-lines:hover{user-select:text;-webkit-user-select:text;-ms-user-select:text}.monaco-editor.enable-user-select{user-select:auto;-webkit-user-select:initial}.monaco-editor .view-lines{white-space:nowrap}.monaco-editor .view-line{position:absolute;width:100%}.monaco-editor .lines-content>.view-lines>.view-line>span{bottom:0;position:absolute;top:0}.monaco-editor .mtkw,.monaco-editor .mtkz{color:var(--vscode-editorWhitespace-foreground)!important}.monaco-editor .mtkz{display:inline-block}.monaco-editor .lines-decorations{background:#fff;position:absolute;top:0}.monaco-editor .margin-view-overlays .cldr{height:100%;position:absolute}.monaco-editor .margin{background-color:var(--vscode-editorGutter-background)}.monaco-editor .margin-view-overlays .cmdr{height:100%;left:0;position:absolute;width:100%}.monaco-editor .minimap.slider-mouseover .minimap-slider{opacity:0;transition:opacity .1s linear}.monaco-editor .minimap.slider-mouseover .minimap-slider.active,.monaco-editor .minimap.slider-mouseover:hover .minimap-slider{opacity:1}.monaco-editor .minimap-slider .minimap-slider-horizontal{background:var(--vscode-minimapSlider-background)}.monaco-editor .minimap-slider:hover .minimap-slider-horizontal{background:var(--vscode-minimapSlider-hoverBackground)}.monaco-editor .minimap-slider.active .minimap-slider-horizontal{background:var(--vscode-minimapSlider-activeBackground)}.monaco-editor .minimap-shadow-visible{box-shadow:var(--vscode-scrollbar-shadow) -6px 0 6px -6px inset}.monaco-editor .minimap-shadow-hidden{position:absolute;width:0}.monaco-editor .minimap-shadow-visible{left:-6px;position:absolute;width:6px}.monaco-editor.no-minimap-shadow .minimap-shadow-visible{left:-1px;position:absolute;width:1px}.minimap.autohide{opacity:0;transition:opacity .5s}.minimap.autohide:hover{opacity:1}.monaco-editor .minimap{z-index:5}.monaco-editor .overlayWidgets{left:0;position:absolute;top:0}.monaco-editor .view-ruler{box-shadow:1px 0 0 0 var(--vscode-editorRuler-foreground) inset;position:absolute;top:0}.monaco-editor .scroll-decoration{box-shadow:var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset;height:6px;left:0;position:absolute;top:0}.monaco-editor .lines-content .cslr{position:absolute}.monaco-editor .focused .selected-text{background-color:var(--vscode-editor-selectionBackground)}.monaco-editor .selected-text{background-color:var(--vscode-editor-inactiveSelectionBackground)}.monaco-editor .top-left-radius{border-top-left-radius:3px}.monaco-editor .bottom-left-radius{border-bottom-left-radius:3px}.monaco-editor .top-right-radius{border-top-right-radius:3px}.monaco-editor .bottom-right-radius{border-bottom-right-radius:3px}.monaco-editor.hc-black .top-left-radius{border-top-left-radius:0}.monaco-editor.hc-black .bottom-left-radius{border-bottom-left-radius:0}.monaco-editor.hc-black .top-right-radius{border-top-right-radius:0}.monaco-editor.hc-black .bottom-right-radius{border-bottom-right-radius:0}.monaco-editor.hc-light .top-left-radius{border-top-left-radius:0}.monaco-editor.hc-light .bottom-left-radius{border-bottom-left-radius:0}.monaco-editor.hc-light .top-right-radius{border-top-right-radius:0}.monaco-editor.hc-light .bottom-right-radius{border-bottom-right-radius:0}.monaco-editor .cursors-layer{position:absolute;top:0}.monaco-editor .cursors-layer>.cursor{box-sizing:border-box;overflow:hidden;position:absolute}.monaco-editor .cursors-layer.cursor-smooth-caret-animation>.cursor{transition:all 80ms}.monaco-editor .cursors-layer.cursor-block-outline-style>.cursor{background:#0000!important;border-style:solid;border-width:1px}.monaco-editor .cursors-layer.cursor-underline-style>.cursor{background:#0000!important;border-bottom-style:solid;border-bottom-width:2px}.monaco-editor .cursors-layer.cursor-underline-thin-style>.cursor{background:#0000!important;border-bottom-style:solid;border-bottom-width:1px}@keyframes monaco-cursor-smooth{0%,20%{opacity:1}60%,to{opacity:0}}@keyframes monaco-cursor-phase{0%,20%{opacity:1}90%,to{opacity:0}}@keyframes monaco-cursor-expand{0%,20%{transform:scaleY(1)}80%,to{transform:scaleY(0)}}.cursor-smooth{animation:monaco-cursor-smooth .5s ease-in-out 0s 20 alternate}.cursor-phase{animation:monaco-cursor-phase .5s ease-in-out 0s 20 alternate}.cursor-expand>.cursor{animation:monaco-cursor-expand .5s ease-in-out 0s 20 alternate}.monaco-editor .mwh{color:var(--vscode-editorWhitespace-foreground)!important;position:absolute}::-ms-clear{display:none}.monaco-editor .editor-widget input{color:inherit}.monaco-editor{-webkit-text-size-adjust:100%;color:var(--vscode-editor-foreground);overflow:visible;overflow-wrap:normal;position:relative}.monaco-editor,.monaco-editor-background{background-color:var(--vscode-editor-background)}.monaco-editor .rangeHighlight{background-color:var(--vscode-editor-rangeHighlightBackground);border:1px solid var(--vscode-editor-rangeHighlightBorder);box-sizing:border-box}.monaco-editor.hc-black .rangeHighlight,.monaco-editor.hc-light .rangeHighlight{border-style:dotted}.monaco-editor .symbolHighlight{background-color:var(--vscode-editor-symbolHighlightBackground);border:1px solid var(--vscode-editor-symbolHighlightBorder);box-sizing:border-box}.monaco-editor.hc-black .symbolHighlight,.monaco-editor.hc-light .symbolHighlight{border-style:dotted}.monaco-editor .overflow-guard{overflow:hidden;position:relative}.monaco-editor .view-overlays{position:absolute;top:0}.monaco-editor .margin-view-overlays>div,.monaco-editor .view-overlays>div{position:absolute;width:100%}.monaco-editor .squiggly-error{border-bottom:4px double var(--vscode-editorError-border)}.monaco-editor .squiggly-error:before{background:var(--vscode-editorError-background);content:"";display:block;height:100%;width:100%}.monaco-editor .squiggly-warning{border-bottom:4px double var(--vscode-editorWarning-border)}.monaco-editor .squiggly-warning:before{background:var(--vscode-editorWarning-background);content:"";display:block;height:100%;width:100%}.monaco-editor .squiggly-info{border-bottom:4px double var(--vscode-editorInfo-border)}.monaco-editor .squiggly-info:before{background:var(--vscode-editorInfo-background);content:"";display:block;height:100%;width:100%}.monaco-editor .squiggly-hint{border-bottom:2px dotted var(--vscode-editorHint-border)}.monaco-editor.showUnused .squiggly-unnecessary{border-bottom:2px dashed var(--vscode-editorUnnecessaryCode-border)}.monaco-editor.showDeprecated .squiggly-inline-deprecated{text-decoration:line-through;text-decoration-color:var(--vscode-editor-foreground,inherit)}.monaco-component.diff-review{user-select:none;-webkit-user-select:none;z-index:99}.monaco-diff-editor .diff-review{position:absolute}.monaco-component.diff-review .diff-review-line-number{color:var(--vscode-editorLineNumber-foreground);display:inline-block;text-align:right}.monaco-component.diff-review .diff-review-summary{padding-left:10px}.monaco-component.diff-review .diff-review-shadow{box-shadow:var(--vscode-scrollbar-shadow) 0 -6px 6px -6px inset;position:absolute}.monaco-component.diff-review .diff-review-row{white-space:pre}.monaco-component.diff-review .diff-review-table{display:table;min-width:100%}.monaco-component.diff-review .diff-review-row{display:table-row;width:100%}.monaco-component.diff-review .diff-review-spacer{display:inline-block;vertical-align:middle;width:10px}.monaco-component.diff-review .diff-review-spacer>.codicon{font-size:9px!important}.monaco-component.diff-review .diff-review-actions{display:inline-block;position:absolute;right:10px;top:2px;z-index:100}.monaco-component.diff-review .diff-review-actions .action-label{height:16px;margin:2px 0;width:16px}.monaco-component.diff-review .revertButton{cursor:pointer}.monaco-editor .diff-hidden-lines-widget{width:100%}.monaco-editor .diff-hidden-lines{font-size:13px;height:0;line-height:14px;transform:translateY(-10px)}.monaco-editor .diff-hidden-lines .bottom.dragging,.monaco-editor .diff-hidden-lines .top.dragging,.monaco-editor .diff-hidden-lines:not(.dragging) .bottom:hover,.monaco-editor .diff-hidden-lines:not(.dragging) .top:hover{background-color:var(--vscode-focusBorder)}.monaco-editor .diff-hidden-lines .bottom,.monaco-editor .diff-hidden-lines .top{background-clip:padding-box;background-color:initial;border-bottom:2px solid #0000;border-top:4px solid #0000;height:4px;transition:background-color .1s ease-out}.monaco-editor .diff-hidden-lines .bottom.canMoveTop:not(.canMoveBottom),.monaco-editor .diff-hidden-lines .top.canMoveTop:not(.canMoveBottom),.monaco-editor.draggingUnchangedRegion.canMoveTop:not(.canMoveBottom) *{cursor:n-resize!important}.monaco-editor .diff-hidden-lines .bottom:not(.canMoveTop).canMoveBottom,.monaco-editor .diff-hidden-lines .top:not(.canMoveTop).canMoveBottom,.monaco-editor.draggingUnchangedRegion:not(.canMoveTop).canMoveBottom *{cursor:s-resize!important}.monaco-editor .diff-hidden-lines .bottom.canMoveTop.canMoveBottom,.monaco-editor .diff-hidden-lines .top.canMoveTop.canMoveBottom,.monaco-editor.draggingUnchangedRegion.canMoveTop.canMoveBottom *{cursor:ns-resize!important}.monaco-editor .diff-hidden-lines .top{transform:translateY(4px)}.monaco-editor .diff-hidden-lines .bottom{transform:translateY(-6px)}.monaco-editor .diff-unchanged-lines{background:var(--vscode-diffEditor-unchangedCodeBackground)}.monaco-editor .noModificationsOverlay{align-items:center;background:var(--vscode-editor-background);display:flex;justify-content:center;z-index:1}.monaco-editor .diff-hidden-lines .center{background:var(--vscode-diffEditor-unchangedRegionBackground);box-shadow:inset 0 -5px 5px -7px var(--vscode-diffEditor-unchangedRegionShadow),inset 0 5px 5px -7px var(--vscode-diffEditor-unchangedRegionShadow);color:var(--vscode-diffEditor-unchangedRegionForeground);display:block;height:24px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.monaco-editor .diff-hidden-lines .center span.codicon{vertical-align:middle}.monaco-editor .diff-hidden-lines .center a:hover .codicon{color:var(--vscode-editorLink-activeForeground)!important;cursor:pointer}.monaco-editor .diff-hidden-lines div.breadcrumb-item{cursor:pointer}.monaco-editor .diff-hidden-lines div.breadcrumb-item:hover{color:var(--vscode-editorLink-activeForeground)}.monaco-editor .movedModified,.monaco-editor .movedOriginal{border:2px solid var(--vscode-diffEditor-move-border)}.monaco-editor .movedModified.currentMove,.monaco-editor .movedOriginal.currentMove{border:2px solid var(--vscode-diffEditor-moveActive-border)}.monaco-diff-editor .moved-blocks-lines path.currentMove{stroke:var(--vscode-diffEditor-moveActive-border)}.monaco-diff-editor .moved-blocks-lines path{pointer-events:visiblestroke}.monaco-diff-editor .moved-blocks-lines .arrow{fill:var(--vscode-diffEditor-move-border)}.monaco-diff-editor .moved-blocks-lines .arrow.currentMove{fill:var(--vscode-diffEditor-moveActive-border)}.monaco-diff-editor .moved-blocks-lines .arrow-rectangle{fill:var(--vscode-editor-background)}.monaco-diff-editor .moved-blocks-lines{pointer-events:none;position:absolute}.monaco-diff-editor .moved-blocks-lines path{fill:none;stroke:var(--vscode-diffEditor-move-border);stroke-width:2}.monaco-editor .char-delete.diff-range-empty{border-left:3px solid var(--vscode-diffEditor-removedTextBackground);margin-left:-1px}.monaco-editor .char-insert.diff-range-empty{border-left:3px solid var(--vscode-diffEditor-insertedTextBackground)}.monaco-editor .fold-unchanged{cursor:pointer}.monaco-diff-editor .diff-moved-code-block{display:flex;justify-content:flex-end;margin-top:-4px}.monaco-diff-editor .diff-moved-code-block .action-bar .action-label.codicon{font-size:12px;height:12px;width:12px}.monaco-diff-editor .diffOverview{z-index:9}.monaco-diff-editor .diffOverview .diffViewport{z-index:10}.monaco-diff-editor.vs .diffOverview{background:#00000008}.monaco-diff-editor.vs-dark .diffOverview{background:#ffffff03}.monaco-scrollable-element.modified-in-monaco-diff-editor.vs .scrollbar,.monaco-scrollable-element.modified-in-monaco-diff-editor.vs-dark .scrollbar{background:#0000}.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-black .scrollbar,.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-light .scrollbar{background:none}.monaco-scrollable-element.modified-in-monaco-diff-editor .slider{z-index:10}.modified-in-monaco-diff-editor .slider.active{background:#ababab66}.modified-in-monaco-diff-editor.hc-black .slider.active,.modified-in-monaco-diff-editor.hc-light .slider.active{background:none}.monaco-diff-editor .delete-sign,.monaco-diff-editor .insert-sign,.monaco-editor .delete-sign,.monaco-editor .insert-sign{align-items:center;display:flex!important;font-size:11px!important;opacity:.7!important}.monaco-diff-editor.hc-black .delete-sign,.monaco-diff-editor.hc-black .insert-sign,.monaco-diff-editor.hc-light .delete-sign,.monaco-diff-editor.hc-light .insert-sign,.monaco-editor.hc-black .delete-sign,.monaco-editor.hc-black .insert-sign,.monaco-editor.hc-light .delete-sign,.monaco-editor.hc-light .insert-sign{opacity:1}.monaco-editor .inline-added-margin-view-zone,.monaco-editor .inline-deleted-margin-view-zone{text-align:right}.monaco-editor .arrow-revert-change{position:absolute;z-index:10}.monaco-editor .arrow-revert-change:hover{cursor:pointer}.monaco-editor .view-zones .view-lines .view-line span{display:inline-block}.monaco-editor .margin-view-zones .lightbulb-glyph:hover{cursor:pointer}.monaco-diff-editor .char-insert,.monaco-editor .char-insert{background-color:var(--vscode-diffEditor-insertedTextBackground)}.monaco-diff-editor .line-insert,.monaco-editor .line-insert{background-color:var(--vscode-diffEditor-insertedLineBackground,var(--vscode-diffEditor-insertedTextBackground))}.monaco-editor .char-insert,.monaco-editor .line-insert{border:1px solid var(--vscode-diffEditor-insertedTextBorder);box-sizing:border-box}.monaco-editor.hc-black .char-insert,.monaco-editor.hc-black .line-insert,.monaco-editor.hc-light .char-insert,.monaco-editor.hc-light .line-insert{border-style:dashed}.monaco-editor .char-delete,.monaco-editor .line-delete{border:1px solid var(--vscode-diffEditor-removedTextBorder);box-sizing:border-box}.monaco-editor.hc-black .char-delete,.monaco-editor.hc-black .line-delete,.monaco-editor.hc-light .char-delete,.monaco-editor.hc-light .line-delete{border-style:dashed}.monaco-diff-editor .gutter-insert,.monaco-editor .gutter-insert,.monaco-editor .inline-added-margin-view-zone{background-color:var(--vscode-diffEditorGutter-insertedLineBackground,var(--vscode-diffEditor-insertedLineBackground),var(--vscode-diffEditor-insertedTextBackground))}.monaco-diff-editor .char-delete,.monaco-editor .char-delete,.monaco-editor .inline-deleted-text{background-color:var(--vscode-diffEditor-removedTextBackground)}.monaco-editor .inline-deleted-text{text-decoration:line-through}.monaco-diff-editor .line-delete,.monaco-editor .line-delete{background-color:var(--vscode-diffEditor-removedLineBackground,var(--vscode-diffEditor-removedTextBackground))}.monaco-diff-editor .gutter-delete,.monaco-editor .gutter-delete,.monaco-editor .inline-deleted-margin-view-zone{background-color:var(--vscode-diffEditorGutter-removedLineBackground,var(--vscode-diffEditor-removedLineBackground),var(--vscode-diffEditor-removedTextBackground))}.monaco-diff-editor.side-by-side .editor.modified{border-left:1px solid var(--vscode-diffEditor-border);box-shadow:-6px 0 5px -5px var(--vscode-scrollbar-shadow)}.monaco-diff-editor.side-by-side .editor.original{border-right:1px solid var(--vscode-diffEditor-border);box-shadow:6px 0 5px -5px var(--vscode-scrollbar-shadow)}.monaco-diff-editor .diffViewport{background:var(--vscode-scrollbarSlider-background)}.monaco-diff-editor .diffViewport:hover{background:var(--vscode-scrollbarSlider-hoverBackground)}.monaco-diff-editor .diffViewport:active{background:var(--vscode-scrollbarSlider-activeBackground)}.monaco-editor .diagonal-fill{background-image:linear-gradient(-45deg,var(--vscode-diffEditor-diagonalFill) 12.5%,#0000 12.5%,#0000 50%,var(--vscode-diffEditor-diagonalFill) 50%,var(--vscode-diffEditor-diagonalFill) 62.5%,#0000 62.5%,#0000 100%);background-size:8px 8px}.monaco-diff-editor .gutter{flex-grow:0;flex-shrink:0;overflow:hidden;position:relative}.monaco-diff-editor .gutter>div{position:absolute}.monaco-diff-editor .gutter .gutterItem{opacity:0;transition:opacity .7s}.monaco-diff-editor .gutter .gutterItem.showAlways{opacity:1;transition:none}.monaco-diff-editor .gutter .gutterItem.noTransition{transition:none}.monaco-diff-editor .gutter:hover .gutterItem{opacity:1;transition:opacity .1s ease-in-out}.monaco-diff-editor .gutter .gutterItem .background{border-left:2px solid var(--vscode-menu-border);height:100%;left:50%;position:absolute;width:1px}.monaco-diff-editor .gutter .gutterItem .buttons{align-items:center;display:flex;justify-content:center;position:absolute;width:100%}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar{height:fit-content}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar .monaco-action-bar{line-height:1}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar .monaco-action-bar .actions-container{background:var(--vscode-editorGutter-commentRangeForeground);border-radius:4px;width:fit-content}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar .monaco-action-bar .actions-container .action-item:hover{background:var(--vscode-toolbar-hoverBackground)}.monaco-diff-editor .gutter .gutterItem .buttons .monaco-toolbar .monaco-action-bar .actions-container .action-item .action-label{padding:1px 2px}.monaco-diff-editor .diff-hidden-lines-compact{display:flex;height:11px}.monaco-diff-editor .diff-hidden-lines-compact .line-left,.monaco-diff-editor .diff-hidden-lines-compact .line-right{border-top:1px solid;border-color:var(--vscode-editorCodeLens-foreground);height:1px;margin:auto;opacity:.5;width:100%}.monaco-diff-editor .diff-hidden-lines-compact .line-left{width:20px}.monaco-diff-editor .diff-hidden-lines-compact .text{text-wrap:nowrap;color:var(--vscode-editorCodeLens-foreground);font-size:11px;line-height:11px;margin:0 4px}.monaco-editor .rendered-markdown kbd{background-color:var(--vscode-keybindingLabel-background);border-color:var(--vscode-keybindingLabel-border);border-bottom:1px var(--vscode-keybindingLabel-bottomBorder);border-left-width:1px;border-radius:3px;border-right-width:1px;border-style:solid;border-top-width:1px;box-shadow:inset 0 -1px 0 var(--vscode-widget-shadow);color:var(--vscode-keybindingLabel-foreground);padding:1px 3px;vertical-align:middle}.rendered-markdown li:has(input[type=checkbox]){list-style-type:none}.monaco-component.multiDiffEditor{background:var(--vscode-multiDiffEditor-background);height:100%;overflow-y:hidden;position:relative;width:100%}.monaco-component.multiDiffEditor>div{height:100%;left:0;position:absolute;top:0;width:100%}.monaco-component.multiDiffEditor>div.placeholder{display:grid;place-content:center;place-items:center;visibility:hidden}.monaco-component.multiDiffEditor>div.placeholder.visible{visibility:visible}.monaco-component.multiDiffEditor .active{--vscode-multiDiffEditor-border:var(--vscode-focusBorder)}.monaco-component.multiDiffEditor .multiDiffEntry{display:flex;flex:1 1;flex-direction:column;overflow:hidden}.monaco-component.multiDiffEditor .multiDiffEntry .collapse-button{cursor:pointer;margin:0 5px}.monaco-component.multiDiffEditor .multiDiffEntry .collapse-button a{display:block}.monaco-component.multiDiffEditor .multiDiffEntry .header{background:var(--vscode-editor-background);z-index:1000}.monaco-component.multiDiffEditor .multiDiffEntry .header:not(.collapsed) .header-content{border-bottom:1px solid var(--vscode-sideBarSectionHeader-border)}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content{align-items:center;background:var(--vscode-multiDiffEditor-headerBackground);border-top:1px solid var(--vscode-multiDiffEditor-border);color:var(--vscode-foreground);display:flex;margin:8px 0 0;padding:4px 5px}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content.shadow{box-shadow:var(--vscode-scrollbar-shadow) 0 6px 6px -6px}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .file-path{display:flex;flex:1 1;min-width:0}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .file-path .title{font-size:14px;line-height:22px}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .file-path .title.original{flex:1 1;min-width:0;text-overflow:ellipsis}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .file-path .status{font-weight:600;line-height:22px;margin:0 10px;opacity:.75}.monaco-component.multiDiffEditor .multiDiffEntry .header .header-content .actions{padding:0 8px}.monaco-component.multiDiffEditor .multiDiffEntry .editorParent{border-bottom:1px solid var(--vscode-multiDiffEditor-border);display:flex;flex:1 1;flex-direction:column;overflow:hidden}.monaco-component.multiDiffEditor .multiDiffEntry .editorContainer{flex:1 1}.monaco-editor .selection-anchor{background-color:#007acc;width:2px!important}.monaco-editor .bracket-match{background-color:var(--vscode-editorBracketMatch-background);border:1px solid var(--vscode-editorBracketMatch-border);box-sizing:border-box}.monaco-editor .lightBulbWidget{align-items:center;display:flex;justify-content:center}.monaco-editor .lightBulbWidget:hover{cursor:pointer}.monaco-editor .lightBulbWidget.codicon-light-bulb,.monaco-editor .lightBulbWidget.codicon-lightbulb-sparkle{color:var(--vscode-editorLightBulb-foreground)}.monaco-editor .lightBulbWidget.codicon-lightbulb-autofix,.monaco-editor .lightBulbWidget.codicon-lightbulb-sparkle-autofix{color:var(--vscode-editorLightBulbAutoFix-foreground,var(--vscode-editorLightBulb-foreground))}.monaco-editor .lightBulbWidget.codicon-sparkle-filled{color:var(--vscode-editorLightBulbAi-foreground,var(--vscode-icon-foreground))}.monaco-editor .lightBulbWidget:before{position:relative;z-index:2}.monaco-editor .lightBulbWidget:after{content:"";display:block;height:100%;left:0;opacity:.3;position:absolute;top:0;width:100%;z-index:1}.monaco-editor .glyph-margin-widgets .cgmr[class*=codicon-gutter-lightbulb]{cursor:pointer;display:block}.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb,.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb-sparkle{color:var(--vscode-editorLightBulb-foreground)}.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb-aifix-auto-fix,.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb-auto-fix{color:var(--vscode-editorLightBulbAutoFix-foreground,var(--vscode-editorLightBulb-foreground))}.monaco-editor .glyph-margin-widgets .cgmr.codicon-gutter-lightbulb-sparkle-filled{color:var(--vscode-editorLightBulbAi-foreground,var(--vscode-icon-foreground))}.monaco-editor .codelens-decoration{font-feature-settings:var(--vscode-editorCodeLens-fontFeatureSettings);color:var(--vscode-editorCodeLens-foreground);display:inline-block;font-family:var(--vscode-editorCodeLens-fontFamily),var(--vscode-editorCodeLens-fontFamilyDefault);font-size:var(--vscode-editorCodeLens-fontSize);line-height:var(--vscode-editorCodeLens-lineHeight);overflow:hidden;padding-right:calc(var(--vscode-editorCodeLens-fontSize)*.5);text-overflow:ellipsis;white-space:nowrap}.monaco-editor .codelens-decoration>a,.monaco-editor .codelens-decoration>span{user-select:none;-webkit-user-select:none;vertical-align:sub;white-space:nowrap}.monaco-editor .codelens-decoration>a{text-decoration:none}.monaco-editor .codelens-decoration>a:hover{cursor:pointer}.monaco-editor .codelens-decoration>a:hover,.monaco-editor .codelens-decoration>a:hover .codicon{color:var(--vscode-editorLink-activeForeground)!important}.monaco-editor .codelens-decoration .codicon{color:currentColor!important;color:var(--vscode-editorCodeLens-foreground);font-size:var(--vscode-editorCodeLens-fontSize);line-height:var(--vscode-editorCodeLens-lineHeight);vertical-align:middle}.monaco-editor .codelens-decoration>a:hover .codicon:before{cursor:pointer}@keyframes fadein{0%{opacity:0;visibility:visible}to{opacity:1}}.monaco-editor .codelens-decoration.fadein{animation:fadein .1s linear}.colorpicker-widget{height:190px;user-select:none;-webkit-user-select:none}.colorpicker-color-decoration,.hc-light .colorpicker-color-decoration{border:.1em solid #000;box-sizing:border-box;cursor:pointer;display:inline-block;height:.8em;line-height:.8em;margin:.1em .2em 0;width:.8em}.hc-black .colorpicker-color-decoration,.vs-dark .colorpicker-color-decoration{border:.1em solid #eee}.colorpicker-header{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTZEaa/1AAAAHUlEQVQYV2PYvXu3JAi7uLiAMaYAjAGTQBPYLQkAa/0Zef3qRswAAAAASUVORK5CYII=);background-size:9px 9px;display:flex;height:24px;image-rendering:pixelated;position:relative}.colorpicker-header .picked-color{align-items:center;color:#fff;cursor:pointer;display:flex;flex:1 1;justify-content:center;line-height:24px;overflow:hidden;white-space:nowrap;width:240px}.colorpicker-header .picked-color .picked-color-presentation{margin-left:5px;margin-right:5px;white-space:nowrap}.colorpicker-header .picked-color .codicon{color:inherit;font-size:14px}.colorpicker-header .picked-color.light{color:#000}.colorpicker-header .original-color{cursor:pointer;width:74px;z-index:inherit}.standalone-colorpicker{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground)}.colorpicker-header.standalone-colorpicker{border-bottom:none}.colorpicker-header .close-button{background-color:var(--vscode-editorHoverWidget-background);border-left:1px solid var(--vscode-editorHoverWidget-border);cursor:pointer}.colorpicker-header .close-button-inner-div{height:100%;text-align:center;width:100%}.colorpicker-header .close-button-inner-div:hover{background-color:var(--vscode-toolbar-hoverBackground)}.colorpicker-header .close-icon{padding:3px}.colorpicker-body{display:flex;padding:8px;position:relative}.colorpicker-body .saturation-wrap{flex:1 1;height:150px;min-width:220px;overflow:hidden;position:relative}.colorpicker-body .saturation-box{height:150px;position:absolute}.colorpicker-body .saturation-selection{border:1px solid #fff;border-radius:100%;box-shadow:0 0 2px #000c;height:9px;margin:-5px 0 0 -5px;position:absolute;width:9px}.colorpicker-body .strip{height:150px;width:25px}.colorpicker-body .standalone-strip{height:122px;width:25px}.colorpicker-body .hue-strip{background:linear-gradient(180deg,red,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red);cursor:grab;margin-left:8px;position:relative}.colorpicker-body .opacity-strip{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTZEaa/1AAAAHUlEQVQYV2PYvXu3JAi7uLiAMaYAjAGTQBPYLQkAa/0Zef3qRswAAAAASUVORK5CYII=);background-size:9px 9px;cursor:grab;image-rendering:pixelated;margin-left:8px;position:relative}.colorpicker-body .strip.grabbing{cursor:grabbing}.colorpicker-body .slider{border:1px solid #ffffffb5;box-shadow:0 0 1px #000000d9;box-sizing:border-box;height:4px;left:-2px;position:absolute;top:0;width:calc(100% + 4px)}.colorpicker-body .strip .overlay{height:150px;pointer-events:none}.colorpicker-body .standalone-strip .standalone-overlay{height:122px;pointer-events:none}.standalone-colorpicker-body{border:1px solid #0000;border-bottom:1px solid var(--vscode-editorHoverWidget-border);display:block;overflow:hidden}.colorpicker-body .insert-button{background:var(--vscode-button-background);border:none;border-radius:2px;bottom:8px;color:var(--vscode-button-foreground);cursor:pointer;height:20px;padding:0;position:absolute;right:8px;width:58px}.colorpicker-body .insert-button:hover{background:var(--vscode-button-hoverBackground)}.monaco-editor.hc-light .dnd-target,.monaco-editor.vs .dnd-target{border-right:2px dotted #000;color:#fff}.monaco-editor.vs-dark .dnd-target{border-right:2px dotted #aeafad;color:#51504f}.monaco-editor.hc-black .dnd-target{border-right:2px dotted #fff;color:#000}.monaco-editor.hc-black.mac.mouse-default .view-lines,.monaco-editor.hc-light.mac.mouse-default .view-lines,.monaco-editor.mouse-default .view-lines,.monaco-editor.vs-dark.mac.mouse-default .view-lines{cursor:default}.monaco-editor.hc-black.mac.mouse-copy .view-lines,.monaco-editor.hc-light.mac.mouse-copy .view-lines,.monaco-editor.mouse-copy .view-lines,.monaco-editor.vs-dark.mac.mouse-copy .view-lines{cursor:copy}.post-edit-widget{background-color:var(--vscode-editorWidget-background);border:1px solid var(--vscode-widget-border,#0000);border-radius:4px;box-shadow:0 0 8px 2px var(--vscode-widget-shadow);overflow:hidden}.post-edit-widget .monaco-button{border:none;border-radius:0;padding:2px}.post-edit-widget .monaco-button:hover{background-color:var(--vscode-button-secondaryHoverBackground)!important}.post-edit-widget .monaco-button .codicon{margin:0}.monaco-editor .findOptionsWidget{border:2px solid var(--vscode-contrastBorder)}.monaco-editor .find-widget,.monaco-editor .findOptionsWidget{background-color:var(--vscode-editorWidget-background);box-shadow:0 0 8px 2px var(--vscode-widget-shadow);color:var(--vscode-editorWidget-foreground)}.monaco-editor .find-widget{border-bottom:1px solid var(--vscode-widget-border);border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-left:1px solid var(--vscode-widget-border);border-right:1px solid var(--vscode-widget-border);box-sizing:border-box;height:33px;line-height:19px;overflow:hidden;padding:0 4px;position:absolute;transform:translateY(calc(-100% - 10px));transition:transform .2s linear;z-index:35}.monaco-workbench.reduce-motion .monaco-editor .find-widget{transition:transform 0ms linear}.monaco-editor .find-widget textarea{margin:0}.monaco-editor .find-widget.hiddenEditor{display:none}.monaco-editor .find-widget.replaceToggled>.replace-part{display:flex}.monaco-editor .find-widget.visible{transform:translateY(0)}.monaco-editor .find-widget .monaco-inputbox.synthetic-focus{outline:1px solid -webkit-focus-ring-color;outline-color:var(--vscode-focusBorder);outline-offset:-1px}.monaco-editor .find-widget .monaco-inputbox .input{background-color:initial;min-height:0}.monaco-editor .find-widget .monaco-findInput .input{font-size:13px}.monaco-editor .find-widget>.find-part,.monaco-editor .find-widget>.replace-part{display:flex;font-size:12px;margin:3px 25px 0 17px}.monaco-editor .find-widget>.find-part .monaco-inputbox,.monaco-editor .find-widget>.replace-part .monaco-inputbox{min-height:25px}.monaco-editor .find-widget>.replace-part .monaco-inputbox>.ibwrapper>.mirror{padding-right:22px}.monaco-editor .find-widget>.find-part .monaco-inputbox>.ibwrapper>.input,.monaco-editor .find-widget>.find-part .monaco-inputbox>.ibwrapper>.mirror,.monaco-editor .find-widget>.replace-part .monaco-inputbox>.ibwrapper>.input,.monaco-editor .find-widget>.replace-part .monaco-inputbox>.ibwrapper>.mirror{padding-bottom:2px;padding-top:2px}.monaco-editor .find-widget>.find-part .find-actions,.monaco-editor .find-widget>.replace-part .replace-actions{align-items:center;display:flex;height:25px}.monaco-editor .find-widget .monaco-findInput{display:flex;flex:1 1;vertical-align:middle}.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element{width:100%}.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element .scrollbar.vertical{opacity:0}.monaco-editor .find-widget .matchesCount{box-sizing:border-box;display:flex;flex:initial;height:25px;line-height:23px;margin:0 0 0 3px;padding:2px 0 0 2px;text-align:center;vertical-align:middle}.monaco-editor .find-widget .button{align-items:center;background-position:50%;background-repeat:no-repeat;border-radius:5px;cursor:pointer;display:flex;flex:initial;height:16px;justify-content:center;margin-left:3px;padding:3px;width:16px}.monaco-editor .find-widget .codicon-find-selection{border-radius:5px;height:22px;padding:3px;width:22px}.monaco-editor .find-widget .button.left{margin-left:0;margin-right:3px}.monaco-editor .find-widget .button.wide{padding:1px 6px;top:-1px;width:auto}.monaco-editor .find-widget .button.toggle{border-radius:0;box-sizing:border-box;height:100%;left:3px;position:absolute;top:0;width:18px}.monaco-editor .find-widget .button.toggle.disabled{display:none}.monaco-editor .find-widget .disabled{color:var(--vscode-disabledForeground);cursor:default}.monaco-editor .find-widget>.replace-part{display:none}.monaco-editor .find-widget>.replace-part>.monaco-findInput{display:flex;flex:auto;flex-grow:0;flex-shrink:0;position:relative;vertical-align:middle}.monaco-editor .find-widget>.replace-part>.monaco-findInput>.controls{position:absolute;right:2px;top:3px}.monaco-editor .find-widget.reduced-find-widget .matchesCount{display:none}.monaco-editor .find-widget.narrow-find-widget{max-width:257px!important}.monaco-editor .find-widget.collapsed-find-widget{max-width:170px!important}.monaco-editor .find-widget.collapsed-find-widget .button.next,.monaco-editor .find-widget.collapsed-find-widget .button.previous,.monaco-editor .find-widget.collapsed-find-widget .button.replace,.monaco-editor .find-widget.collapsed-find-widget .button.replace-all,.monaco-editor .find-widget.collapsed-find-widget>.find-part .monaco-findInput .controls{display:none}.monaco-editor .find-widget.no-results .matchesCount{color:var(--vscode-errorForeground)}.monaco-editor .findMatch{animation-duration:0;animation-name:inherit!important;background-color:var(--vscode-editor-findMatchHighlightBackground)}.monaco-editor .currentFindMatch{background-color:var(--vscode-editor-findMatchBackground);border:2px solid var(--vscode-editor-findMatchBorder);box-sizing:border-box;padding:1px}.monaco-editor .findScope{background-color:var(--vscode-editor-findRangeHighlightBackground)}.monaco-editor .find-widget .monaco-sash{background-color:var(--vscode-editorWidget-resizeBorder,var(--vscode-editorWidget-border));left:0!important}.monaco-editor.hc-black .find-widget .button:before{left:2px;position:relative;top:1px}.monaco-editor .find-widget .button:not(.disabled):hover,.monaco-editor .find-widget .codicon-find-selection:hover{background-color:var(--vscode-toolbar-hoverBackground)!important}.monaco-editor.findMatch{background-color:var(--vscode-editor-findMatchHighlightBackground)}.monaco-editor.currentFindMatch{background-color:var(--vscode-editor-findMatchBackground)}.monaco-editor.findScope{background-color:var(--vscode-editor-findRangeHighlightBackground)}.monaco-editor.findMatch{background-color:var(--vscode-editorWidget-background)}.monaco-editor .find-widget>.button.codicon-widget-close{position:absolute;right:4px;top:5px}.monaco-editor .margin-view-overlays .codicon-folding-collapsed,.monaco-editor .margin-view-overlays .codicon-folding-expanded,.monaco-editor .margin-view-overlays .codicon-folding-manual-collapsed,.monaco-editor .margin-view-overlays .codicon-folding-manual-expanded{align-items:center;cursor:pointer;display:flex;font-size:140%;justify-content:center;margin-left:2px;opacity:0;transition:opacity .5s}.monaco-workbench.reduce-motion .monaco-editor .margin-view-overlays .codicon-folding-collapsed,.monaco-workbench.reduce-motion .monaco-editor .margin-view-overlays .codicon-folding-expanded,.monaco-workbench.reduce-motion .monaco-editor .margin-view-overlays .codicon-folding-manual-collapsed,.monaco-workbench.reduce-motion .monaco-editor .margin-view-overlays .codicon-folding-manual-expanded{transition:initial}.monaco-editor .margin-view-overlays .codicon.alwaysShowFoldIcons,.monaco-editor .margin-view-overlays .codicon.codicon-folding-collapsed,.monaco-editor .margin-view-overlays .codicon.codicon-folding-manual-collapsed,.monaco-editor .margin-view-overlays:hover .codicon{opacity:1}.monaco-editor .inline-folded:after{color:var(--vscode-editor-foldPlaceholderForeground);content:"\22EF";cursor:pointer;display:inline;line-height:1em;margin:.1em .2em 0}.monaco-editor .folded-background{background-color:var(--vscode-editor-foldBackground)}.monaco-editor .cldr.codicon.codicon-folding-collapsed,.monaco-editor .cldr.codicon.codicon-folding-expanded,.monaco-editor .cldr.codicon.codicon-folding-manual-collapsed,.monaco-editor .cldr.codicon.codicon-folding-manual-expanded{color:var(--vscode-editorGutter-foldingControlForeground)!important}.monaco-editor .peekview-widget .head .peekview-title .severity-icon{display:inline-block;margin-right:4px;vertical-align:text-top}.monaco-editor .marker-widget{text-overflow:ellipsis;white-space:nowrap}.monaco-editor .marker-widget>.stale{font-style:italic;opacity:.6}.monaco-editor .marker-widget .title{display:inline-block;padding-right:5px}.monaco-editor .marker-widget .descriptioncontainer{padding:8px 12px 0 20px;position:absolute;user-select:text;-webkit-user-select:text;white-space:pre}.monaco-editor .marker-widget .descriptioncontainer .message{display:flex;flex-direction:column}.monaco-editor .marker-widget .descriptioncontainer .message .details{padding-left:6px}.monaco-editor .marker-widget .descriptioncontainer .message .source,.monaco-editor .marker-widget .descriptioncontainer .message span.code{opacity:.6}.monaco-editor .marker-widget .descriptioncontainer .message a.code-link{color:inherit;opacity:.6}.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:before{content:"("}.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:after{content:")"}.monaco-editor .marker-widget .descriptioncontainer .message a.code-link>span{border-bottom:1px solid #0000;color:var(--vscode-textLink-activeForeground);text-decoration:underline;text-underline-position:under}.monaco-editor .marker-widget .descriptioncontainer .filename{color:var(--vscode-textLink-activeForeground);cursor:pointer}.monaco-editor .goto-definition-link{color:var(--vscode-editorLink-activeForeground)!important;cursor:pointer;text-decoration:underline}.monaco-editor .zone-widget .zone-widget-container.reference-zone-widget{border-bottom-width:1px;border-top-width:1px}.monaco-editor .reference-zone-widget .inline{display:inline-block;vertical-align:top}.monaco-editor .reference-zone-widget .messages{height:100%;padding:3em 0;text-align:center;width:100%}.monaco-editor .reference-zone-widget .ref-tree{background-color:var(--vscode-peekViewResult-background);color:var(--vscode-peekViewResult-lineForeground);line-height:23px}.monaco-editor .reference-zone-widget .ref-tree .reference{overflow:hidden;text-overflow:ellipsis}.monaco-editor .reference-zone-widget .ref-tree .reference-file{color:var(--vscode-peekViewResult-fileForeground);display:inline-flex;height:100%;width:100%}.monaco-editor .reference-zone-widget .ref-tree .monaco-list:focus .selected .reference-file{color:inherit!important}.monaco-editor .reference-zone-widget .ref-tree .monaco-list:focus .monaco-list-rows>.monaco-list-row.selected:not(.highlighted){background-color:var(--vscode-peekViewResult-selectionBackground);color:var(--vscode-peekViewResult-selectionForeground)!important}.monaco-editor .reference-zone-widget .ref-tree .reference-file .count{margin-left:auto;margin-right:12px}.monaco-editor .reference-zone-widget .ref-tree .referenceMatch .highlight{background-color:var(--vscode-peekViewResult-matchHighlightBackground)}.monaco-editor .reference-zone-widget .preview .reference-decoration{background-color:var(--vscode-peekViewEditor-matchHighlightBackground);border:2px solid var(--vscode-peekViewEditor-matchHighlightBorder);box-sizing:border-box}.monaco-editor .reference-zone-widget .preview .monaco-editor .inputarea.ime-input,.monaco-editor .reference-zone-widget .preview .monaco-editor .monaco-editor-background{background-color:var(--vscode-peekViewEditor-background)}.monaco-editor .reference-zone-widget .preview .monaco-editor .margin{background-color:var(--vscode-peekViewEditorGutter-background)}.monaco-editor.hc-black .reference-zone-widget .ref-tree .reference-file,.monaco-editor.hc-light .reference-zone-widget .ref-tree .reference-file{font-weight:700}.monaco-editor.hc-black .reference-zone-widget .ref-tree .referenceMatch .highlight,.monaco-editor.hc-light .reference-zone-widget .ref-tree .referenceMatch .highlight{border:1px dotted var(--vscode-contrastActiveBorder,#0000);box-sizing:border-box}.monaco-editor .hoverHighlight{background-color:var(--vscode-editor-hoverHighlightBackground)}.monaco-editor .monaco-hover-content{box-sizing:border-box;padding-bottom:2px;padding-right:2px}.monaco-editor .monaco-hover{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);border-radius:3px;color:var(--vscode-editorHoverWidget-foreground)}.monaco-editor .monaco-hover a{color:var(--vscode-textLink-foreground)}.monaco-editor .monaco-hover a:hover{color:var(--vscode-textLink-activeForeground)}.monaco-editor .monaco-hover .hover-row{display:flex}.monaco-editor .monaco-hover .hover-row .hover-row-contents{display:flex;flex-direction:column;min-width:0}.monaco-editor .monaco-hover .hover-row .verbosity-actions{border-right:1px solid var(--vscode-editorHoverWidget-border);display:flex;flex-direction:column;justify-content:end;padding-left:5px;padding-right:5px}.monaco-editor .monaco-hover .hover-row .verbosity-actions .codicon{cursor:pointer;font-size:11px}.monaco-editor .monaco-hover .hover-row .verbosity-actions .codicon.enabled{color:var(--vscode-textLink-foreground)}.monaco-editor .monaco-hover .hover-row .verbosity-actions .codicon.disabled{opacity:.6}.monaco-editor .monaco-hover .hover-row .actions{background-color:var(--vscode-editorHoverWidget-statusBarBackground)}.monaco-editor .monaco-hover code{background-color:var(--vscode-textCodeBlock-background)}.monaco-editor.vs .valueSetReplacement{outline:solid 2px var(--vscode-editorBracketMatch-border)}.monaco-editor .inlineSuggestionsHints.withBorder{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);z-index:39}.monaco-editor .inlineSuggestionsHints a,.monaco-editor .inlineSuggestionsHints a:hover{color:var(--vscode-foreground)}.monaco-editor .inlineSuggestionsHints .keybinding{display:flex;margin-left:4px;opacity:.6}.monaco-editor .inlineSuggestionsHints .keybinding .monaco-keybinding-key{font-size:8px;padding:2px 3px}.monaco-editor .inlineSuggestionsHints .availableSuggestionCount a{display:flex;justify-content:center;min-width:19px}.monaco-editor .inlineSuggestionStatusBarItemLabel{margin-right:2px}.monaco-editor .suggest-preview-additional-widget{white-space:nowrap}.monaco-editor .suggest-preview-additional-widget .content-spacer{color:#0000;white-space:pre}.monaco-editor .suggest-preview-additional-widget .button{cursor:pointer;display:inline-block;text-decoration:underline;text-underline-position:under}.monaco-editor .ghost-text-hidden{font-size:0;opacity:0}.monaco-editor .ghost-text-decoration,.monaco-editor .suggest-preview-text .ghost-text{font-style:italic}.monaco-editor .ghost-text-decoration,.monaco-editor .ghost-text-decoration-preview,.monaco-editor .suggest-preview-text .ghost-text{background-color:var(--vscode-editorGhostText-background);border:1px solid var(--vscode-editorGhostText-border);color:var(--vscode-editorGhostText-foreground)!important}.monaco-editor .inline-edit-remove{background-color:var(--vscode-editorGhostText-background);font-style:italic}.monaco-editor .inline-edit-hidden{font-size:0;opacity:0}.monaco-editor .inline-edit-decoration,.monaco-editor .suggest-preview-text .inline-edit{font-style:italic}.monaco-editor .inline-completion-text-to-replace{text-decoration:underline;text-underline-position:under}.monaco-editor .inline-edit-decoration,.monaco-editor .inline-edit-decoration-preview,.monaco-editor .suggest-preview-text .inline-edit{background-color:var(--vscode-editorGhostText-background);border:1px solid var(--vscode-editorGhostText-border);color:var(--vscode-editorGhostText-foreground)!important}.monaco-editor .inlineEditHints.withBorder{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);z-index:39}.monaco-editor .inlineEditHints a,.monaco-editor .inlineEditHints a:hover{color:var(--vscode-foreground)}.monaco-editor .inlineEditHints .keybinding{display:flex;margin-left:4px;opacity:.6}.monaco-editor .inlineEditHints .keybinding .monaco-keybinding-key{font-size:8px;padding:2px 3px}.monaco-editor .inlineEditStatusBarItemLabel{margin-right:2px}.monaco-editor .inlineEditSideBySide{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);white-space:pre;z-index:39}.monaco-editor div.inline-edits-widget{--widget-color:var(--vscode-notifications-background)}.monaco-editor div.inline-edits-widget .promptEditor .monaco-editor{--vscode-editor-placeholder-foreground:var(--vscode-editorGhostText-foreground)}.monaco-editor div.inline-edits-widget .promptEditor,.monaco-editor div.inline-edits-widget .toolbar{opacity:0;transition:opacity .2s ease-in-out}.monaco-editor div.inline-edits-widget.focused .promptEditor,.monaco-editor div.inline-edits-widget.focused .toolbar,.monaco-editor div.inline-edits-widget:hover .promptEditor,.monaco-editor div.inline-edits-widget:hover .toolbar{opacity:1}.monaco-editor div.inline-edits-widget .preview .monaco-editor{--vscode-editor-background:var(--widget-color)}.monaco-editor div.inline-edits-widget .preview .monaco-editor .mtk1{color:var(--vscode-editorGhostText-foreground)}.monaco-editor div.inline-edits-widget .preview .monaco-editor .current-line-margin,.monaco-editor div.inline-edits-widget .preview .monaco-editor .view-overlays .current-line-exact{border:none}.monaco-editor div.inline-edits-widget svg .gradient-start{stop-color:var(--vscode-editor-background)}.monaco-editor div.inline-edits-widget svg .gradient-stop{stop-color:var(--widget-color)}.inline-editor-progress-decoration{display:inline-block;height:1em;width:1em}.inline-progress-widget{align-items:center;display:flex!important;justify-content:center}.inline-progress-widget .icon{font-size:80%!important}.inline-progress-widget:hover .icon{animation:none;font-size:90%!important}.inline-progress-widget:hover .icon:before{content:var(--vscode-icon-x-content);font-family:var(--vscode-icon-x-font-family)}.monaco-editor .linked-editing-decoration{background-color:var(--vscode-editor-linkedEditingBackground);min-width:1px}.monaco-editor .detected-link,.monaco-editor .detected-link-active{text-decoration:underline;text-underline-position:under}.monaco-editor .detected-link-active{color:var(--vscode-editorLink-activeForeground)!important;cursor:pointer}.monaco-editor .monaco-editor-overlaymessage{padding-bottom:8px;z-index:10000}.monaco-editor .monaco-editor-overlaymessage.below{padding-bottom:0;padding-top:8px;z-index:10000}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.monaco-editor .monaco-editor-overlaymessage.fadeIn{animation:fadeIn .15s ease-out}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.monaco-editor .monaco-editor-overlaymessage.fadeOut{animation:fadeOut .1s ease-out}.monaco-editor .monaco-editor-overlaymessage .message{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-inputValidation-infoBorder);border-radius:3px;color:var(--vscode-editorHoverWidget-foreground);padding:2px 4px}.monaco-editor .monaco-editor-overlaymessage .message p{margin-block:0}.monaco-editor .monaco-editor-overlaymessage .message a{color:var(--vscode-textLink-foreground)}.monaco-editor .monaco-editor-overlaymessage .message a:hover{color:var(--vscode-textLink-activeForeground)}.monaco-editor.hc-black .monaco-editor-overlaymessage .message,.monaco-editor.hc-light .monaco-editor-overlaymessage .message{border-width:2px}.monaco-editor .monaco-editor-overlaymessage .anchor{border:8px solid #0000;height:0!important;left:2px;position:absolute;width:0!important;z-index:1000}.monaco-editor .monaco-editor-overlaymessage .anchor.top{border-bottom-color:var(--vscode-inputValidation-infoBorder)}.monaco-editor .monaco-editor-overlaymessage .anchor.below{border-top-color:var(--vscode-inputValidation-infoBorder)}.monaco-editor .monaco-editor-overlaymessage.below .anchor.below,.monaco-editor .monaco-editor-overlaymessage:not(.below) .anchor.top{display:none}.monaco-editor .monaco-editor-overlaymessage.below .anchor.top{display:inherit;top:-8px}.monaco-editor .parameter-hints-widget{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);cursor:default;display:flex;flex-direction:column;line-height:1.5em;z-index:39}.hc-black .monaco-editor .parameter-hints-widget,.hc-light .monaco-editor .parameter-hints-widget{border-width:2px}.monaco-editor .parameter-hints-widget>.phwrapper{display:flex;flex-direction:row;max-width:440px}.monaco-editor .parameter-hints-widget.multiple{min-height:3.3em;padding:0}.monaco-editor .parameter-hints-widget.multiple .body:before{border-left:1px solid var(--vscode-editorHoverWidget-border);content:"";display:block;height:100%;opacity:.5;position:absolute}.monaco-editor .parameter-hints-widget p,.monaco-editor .parameter-hints-widget ul{margin:8px 0}.monaco-editor .parameter-hints-widget .body,.monaco-editor .parameter-hints-widget .monaco-scrollable-element{display:flex;flex:1 1;flex-direction:column;min-height:100%}.monaco-editor .parameter-hints-widget .signature{padding:4px 5px;position:relative}.monaco-editor .parameter-hints-widget .signature.has-docs:after{border-bottom:1px solid var(--vscode-editorHoverWidget-border);content:"";display:block;left:0;opacity:.5;padding-top:4px;position:absolute;width:100%}.monaco-editor .parameter-hints-widget .code{font-family:var(--vscode-parameterHintsWidget-editorFontFamily),var(--vscode-parameterHintsWidget-editorFontFamilyDefault)}.monaco-editor .parameter-hints-widget .docs{padding:0 10px 0 5px;white-space:pre-wrap}.monaco-editor .parameter-hints-widget .docs.empty{display:none}.monaco-editor .parameter-hints-widget .docs a{color:var(--vscode-textLink-foreground)}.monaco-editor .parameter-hints-widget .docs a:hover{color:var(--vscode-textLink-activeForeground);cursor:pointer}.monaco-editor .parameter-hints-widget .docs .markdown-docs{white-space:normal}.monaco-editor .parameter-hints-widget .docs code{background-color:var(--vscode-textCodeBlock-background);border-radius:3px;font-family:var(--monaco-monospace-font);padding:0 .4em}.monaco-editor .parameter-hints-widget .docs .code,.monaco-editor .parameter-hints-widget .docs .monaco-tokenized-source{white-space:pre-wrap}.monaco-editor .parameter-hints-widget .controls{align-items:center;display:none;flex-direction:column;justify-content:flex-end;min-width:22px}.monaco-editor .parameter-hints-widget.multiple .controls{display:flex;padding:0 2px}.monaco-editor .parameter-hints-widget.multiple .button{background-repeat:no-repeat;cursor:pointer;height:16px;width:16px}.monaco-editor .parameter-hints-widget .button.previous{bottom:24px}.monaco-editor .parameter-hints-widget .overloads{font-family:var(--monaco-monospace-font);height:12px;line-height:12px;text-align:center}.monaco-editor .parameter-hints-widget .signature .parameter.active{color:var(--vscode-editorHoverWidget-highlightForeground);font-weight:700}.monaco-editor .parameter-hints-widget .documentation-parameter>.parameter{font-weight:700;margin-right:.5em}.monaco-editor .peekview-widget .head{box-sizing:border-box;display:flex;flex-wrap:nowrap;justify-content:space-between}.monaco-editor .peekview-widget .head .peekview-title{align-items:baseline;display:flex;font-size:13px;margin-left:20px;min-width:0;overflow:hidden;text-overflow:ellipsis}.monaco-editor .peekview-widget .head .peekview-title.clickable{cursor:pointer}.monaco-editor .peekview-widget .head .peekview-title .dirname:not(:empty){font-size:.9em;margin-left:.5em}.monaco-editor .peekview-widget .head .peekview-title .dirname,.monaco-editor .peekview-widget .head .peekview-title .filename,.monaco-editor .peekview-widget .head .peekview-title .meta{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.monaco-editor .peekview-widget .head .peekview-title .meta:not(:empty):before{content:"-";padding:0 .3em}.monaco-editor .peekview-widget .head .peekview-actions{flex:1 1;padding-right:2px;text-align:right}.monaco-editor .peekview-widget .head .peekview-actions>.monaco-action-bar{display:inline-block}.monaco-editor .peekview-widget .head .peekview-actions>.monaco-action-bar,.monaco-editor .peekview-widget .head .peekview-actions>.monaco-action-bar>.actions-container{height:100%}.monaco-editor .peekview-widget>.body{border-top:1px solid;position:relative}.monaco-editor .peekview-widget .head .peekview-title .codicon{align-self:center;margin-right:4px}.monaco-editor .peekview-widget .monaco-list .monaco-list-row.focused .codicon{color:inherit!important}.monaco-editor{--vscode-editor-placeholder-foreground:var(--vscode-editorGhostText-foreground)}.monaco-editor .editorPlaceholder{text-wrap:nowrap;color:var(--vscode-editor-placeholder-foreground);overflow:hidden;pointer-events:none;position:absolute;text-overflow:ellipsis;top:0}.monaco-editor .rename-box{border-radius:4px;color:inherit;z-index:100}.monaco-editor .rename-box.preview{padding:4px 4px 0}.monaco-editor .rename-box .rename-input-with-button{border-radius:2px;padding:3px;width:calc(100% - 8px)}.monaco-editor .rename-box .rename-input{padding:0;width:calc(100% - 8px)}.monaco-editor .rename-box .rename-input:focus{outline:none}.monaco-editor .rename-box .rename-suggestions-button{align-items:center;background-color:initial;border:none;border-radius:5px;cursor:pointer;display:flex;padding:3px}.monaco-editor .rename-box .rename-suggestions-button:hover{background-color:var(--vscode-toolbar-hoverBackground)}.monaco-editor .rename-box .rename-candidate-list-container .monaco-list-row{border-radius:2px}.monaco-editor .rename-box .rename-label{display:none;opacity:.8}.monaco-editor .rename-box.preview .rename-label{display:inherit}.monaco-editor .snippet-placeholder{background-color:var(--vscode-editor-snippetTabstopHighlightBackground,#0000);min-width:2px;outline-color:var(--vscode-editor-snippetTabstopHighlightBorder,#0000);outline-style:solid;outline-width:1px}.monaco-editor .finish-snippet-placeholder{background-color:var(--vscode-editor-snippetFinalTabstopHighlightBackground,#0000);outline-color:var(--vscode-editor-snippetFinalTabstopHighlightBorder,#0000);outline-style:solid;outline-width:1px}.monaco-editor .sticky-widget{overflow:hidden}.monaco-editor .sticky-widget-line-numbers{background-color:inherit;float:left}.monaco-editor .sticky-widget-lines-scrollable{background-color:inherit;display:inline-block;overflow:hidden;position:absolute;width:var(--vscode-editorStickyScroll-scrollableWidth)}.monaco-editor .sticky-widget-lines{background-color:inherit;position:absolute}.monaco-editor .sticky-line-content,.monaco-editor .sticky-line-number{background-color:inherit;color:var(--vscode-editorLineNumber-foreground);display:inline-block;position:absolute;white-space:nowrap}.monaco-editor .sticky-line-number .codicon-folding-collapsed,.monaco-editor .sticky-line-number .codicon-folding-expanded{float:right;transition:var(--vscode-editorStickyScroll-foldingOpacityTransition)}.monaco-editor .sticky-line-content{background-color:inherit;white-space:nowrap;width:var(--vscode-editorStickyScroll-scrollableWidth)}.monaco-editor .sticky-line-number-inner{display:inline-block;text-align:right}.monaco-editor .sticky-widget{border-bottom:1px solid var(--vscode-editorStickyScroll-border)}.monaco-editor .sticky-line-content:hover{background-color:var(--vscode-editorStickyScrollHover-background);cursor:pointer}.monaco-editor .sticky-widget{background-color:var(--vscode-editorStickyScroll-background);box-shadow:var(--vscode-editorStickyScroll-shadow) 0 4px 2px -2px;right:auto!important;width:100%;z-index:4}.monaco-editor .sticky-widget.peek{background-color:var(--vscode-peekViewEditorStickyScroll-background)}.monaco-editor .suggest-widget{border-radius:3px;display:flex;flex-direction:column;width:430px;z-index:40}.monaco-editor .suggest-widget.message{align-items:center;flex-direction:row}.monaco-editor .suggest-details,.monaco-editor .suggest-widget{background-color:var(--vscode-editorSuggestWidget-background);border-color:var(--vscode-editorSuggestWidget-border);border-style:solid;border-width:1px;flex:0 1 auto;width:100%}.monaco-editor.hc-black .suggest-details,.monaco-editor.hc-black .suggest-widget,.monaco-editor.hc-light .suggest-details,.monaco-editor.hc-light .suggest-widget{border-width:2px}.monaco-editor .suggest-widget .suggest-status-bar{border-top:1px solid var(--vscode-editorSuggestWidget-border);box-sizing:border-box;display:none;flex-flow:row nowrap;font-size:80%;justify-content:space-between;overflow:hidden;padding:0 4px;width:100%}.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar{display:flex}.monaco-editor .suggest-widget .suggest-status-bar .left{padding-right:8px}.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar .action-label{color:var(--vscode-editorSuggestWidgetStatus-foreground)}.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar .action-item:not(:last-of-type) .action-label{margin-right:0}.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar .action-item:not(:last-of-type) .action-label:after{content:", ";margin-right:.3em}.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused.string-label>.contents>.main>.right>.readMore,.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row>.contents>.main>.right>.readMore{display:none}.monaco-editor .suggest-widget.with-status-bar:not(.docs-side) .monaco-list .monaco-list-row:hover>.contents>.main>.right.can-expand-details>.details-label{width:100%}.monaco-editor .suggest-widget>.message{padding-left:22px}.monaco-editor .suggest-widget>.tree{height:100%;width:100%}.monaco-editor .suggest-widget .monaco-list{user-select:none;-webkit-user-select:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row{background-position:2px 2px;background-repeat:no-repeat;-mox-box-sizing:border-box;box-sizing:border-box;cursor:pointer;display:flex;padding-right:10px;touch-action:none;white-space:nowrap}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused{color:var(--vscode-editorSuggestWidget-selectedForeground)}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused .codicon{color:var(--vscode-editorSuggestWidget-selectedIconForeground)}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents{flex:1 1;height:100%;overflow:hidden;padding-left:2px}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main{display:flex;justify-content:space-between;overflow:hidden;text-overflow:ellipsis;white-space:pre}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left,.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right{display:flex}.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.focused)>.contents>.main .monaco-icon-label{color:var(--vscode-editorSuggestWidget-foreground)}.monaco-editor .suggest-widget:not(.frozen) .monaco-highlighted-label .highlight{font-weight:700}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main .monaco-highlighted-label .highlight{color:var(--vscode-editorSuggestWidget-highlightForeground)}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused>.contents>.main .monaco-highlighted-label .highlight{color:var(--vscode-editorSuggestWidget-focusHighlightForeground)}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close,.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore:before{color:inherit;cursor:pointer;font-size:14px;opacity:1}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close{position:absolute;right:2px;top:6px}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close:hover,.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore:hover{opacity:1}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label{opacity:.7}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.signature-label{opacity:.6;overflow:hidden;text-overflow:ellipsis}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.qualifier-label{align-self:center;font-size:85%;line-height:normal;margin-left:12px;opacity:.4;overflow:hidden;text-overflow:ellipsis}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label{font-size:85%;margin-left:1.1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label>.monaco-tokenized-source{display:inline}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label{display:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.right>.details-label,.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label)>.contents>.main>.right>.details-label,.monaco-editor .suggest-widget:not(.shows-details) .monaco-list .monaco-list-row.focused>.contents>.main>.right>.details-label{display:inline}.monaco-editor .suggest-widget:not(.docs-side) .monaco-list .monaco-list-row.focused:hover>.contents>.main>.right.can-expand-details>.details-label{width:calc(100% - 26px)}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left{flex-grow:1;flex-shrink:1;overflow:hidden}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.monaco-icon-label{flex-shrink:0}.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.left>.monaco-icon-label{max-width:100%}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label>.contents>.main>.left>.monaco-icon-label{flex-shrink:1}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right{flex-shrink:4;max-width:70%;overflow:hidden}.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore{display:inline-block;height:18px;position:absolute;right:10px;visibility:hidden;width:18px}.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row>.contents>.main>.right>.readMore{display:none!important}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label>.contents>.main>.right>.readMore{display:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused.string-label>.contents>.main>.right>.readMore{display:inline-block}.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused:hover>.contents>.main>.right>.readMore{visibility:visible}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated{opacity:.66;text-decoration:unset}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated>.monaco-icon-label-container>.monaco-icon-name-container{text-decoration:line-through}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label:before{height:100%}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon{background-position:50%;background-repeat:no-repeat;background-size:80%;display:block;height:16px;margin-left:2px;width:16px}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.hide{display:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon{align-items:center;display:flex;margin-right:4px}.monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .icon,.monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .suggest-icon:before{display:none}.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.customcolor .colorspan{border:.1em solid #000;display:inline-block;height:.7em;margin:0 0 0 .3em;width:.7em}.monaco-editor .suggest-details-container{z-index:41}.monaco-editor .suggest-details{color:var(--vscode-editorSuggestWidget-foreground);cursor:default;display:flex;flex-direction:column}.monaco-editor .suggest-details.focused{border-color:var(--vscode-focusBorder)}.monaco-editor .suggest-details a{color:var(--vscode-textLink-foreground)}.monaco-editor .suggest-details a:hover{color:var(--vscode-textLink-activeForeground)}.monaco-editor .suggest-details code{background-color:var(--vscode-textCodeBlock-background)}.monaco-editor .suggest-details.no-docs{display:none}.monaco-editor .suggest-details>.monaco-scrollable-element{flex:1 1}.monaco-editor .suggest-details>.monaco-scrollable-element>.body{box-sizing:border-box;height:100%;width:100%}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.type{flex:2 1;margin:0 24px 0 0;opacity:.7;overflow:hidden;padding:4px 0 12px 5px;text-overflow:ellipsis;white-space:pre}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.type.auto-wrap{white-space:normal;word-break:break-all}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs{margin:0;padding:4px 5px;white-space:pre-wrap}.monaco-editor .suggest-details.no-type>.monaco-scrollable-element>.body>.docs{margin-right:24px;overflow:hidden}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs{min-height:calc(1rem + 8px);padding:0;white-space:normal}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div,.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>span:not(:empty){padding:4px 5px}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div>p:first-child{margin-top:0}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div>p:last-child{margin-bottom:0}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs .monaco-tokenized-source{white-space:pre}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs .code{word-wrap:break-word;white-space:pre-wrap}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs .codicon{vertical-align:sub}.monaco-editor .suggest-details>.monaco-scrollable-element>.body>p:empty{display:none}.monaco-editor .suggest-details code{border-radius:3px;padding:0 .4em}.monaco-editor .suggest-details ol,.monaco-editor .suggest-details ul{padding-left:20px}.monaco-editor .suggest-details p code{font-family:var(--monaco-monospace-font)}.monaco-editor .codicon.codicon-symbol-array,.monaco-workbench .codicon.codicon-symbol-array{color:var(--vscode-symbolIcon-arrayForeground)}.monaco-editor .codicon.codicon-symbol-boolean,.monaco-workbench .codicon.codicon-symbol-boolean{color:var(--vscode-symbolIcon-booleanForeground)}.monaco-editor .codicon.codicon-symbol-class,.monaco-workbench .codicon.codicon-symbol-class{color:var(--vscode-symbolIcon-classForeground)}.monaco-editor .codicon.codicon-symbol-method,.monaco-workbench .codicon.codicon-symbol-method{color:var(--vscode-symbolIcon-methodForeground)}.monaco-editor .codicon.codicon-symbol-color,.monaco-workbench .codicon.codicon-symbol-color{color:var(--vscode-symbolIcon-colorForeground)}.monaco-editor .codicon.codicon-symbol-constant,.monaco-workbench .codicon.codicon-symbol-constant{color:var(--vscode-symbolIcon-constantForeground)}.monaco-editor .codicon.codicon-symbol-constructor,.monaco-workbench .codicon.codicon-symbol-constructor{color:var(--vscode-symbolIcon-constructorForeground)}.monaco-editor .codicon.codicon-symbol-enum,.monaco-editor .codicon.codicon-symbol-value,.monaco-workbench .codicon.codicon-symbol-enum,.monaco-workbench .codicon.codicon-symbol-value{color:var(--vscode-symbolIcon-enumeratorForeground)}.monaco-editor .codicon.codicon-symbol-enum-member,.monaco-workbench .codicon.codicon-symbol-enum-member{color:var(--vscode-symbolIcon-enumeratorMemberForeground)}.monaco-editor .codicon.codicon-symbol-event,.monaco-workbench .codicon.codicon-symbol-event{color:var(--vscode-symbolIcon-eventForeground)}.monaco-editor .codicon.codicon-symbol-field,.monaco-workbench .codicon.codicon-symbol-field{color:var(--vscode-symbolIcon-fieldForeground)}.monaco-editor .codicon.codicon-symbol-file,.monaco-workbench .codicon.codicon-symbol-file{color:var(--vscode-symbolIcon-fileForeground)}.monaco-editor .codicon.codicon-symbol-folder,.monaco-workbench .codicon.codicon-symbol-folder{color:var(--vscode-symbolIcon-folderForeground)}.monaco-editor .codicon.codicon-symbol-function,.monaco-workbench .codicon.codicon-symbol-function{color:var(--vscode-symbolIcon-functionForeground)}.monaco-editor .codicon.codicon-symbol-interface,.monaco-workbench .codicon.codicon-symbol-interface{color:var(--vscode-symbolIcon-interfaceForeground)}.monaco-editor .codicon.codicon-symbol-key,.monaco-workbench .codicon.codicon-symbol-key{color:var(--vscode-symbolIcon-keyForeground)}.monaco-editor .codicon.codicon-symbol-keyword,.monaco-workbench .codicon.codicon-symbol-keyword{color:var(--vscode-symbolIcon-keywordForeground)}.monaco-editor .codicon.codicon-symbol-module,.monaco-workbench .codicon.codicon-symbol-module{color:var(--vscode-symbolIcon-moduleForeground)}.monaco-editor .codicon.codicon-symbol-namespace,.monaco-workbench .codicon.codicon-symbol-namespace{color:var(--vscode-symbolIcon-namespaceForeground)}.monaco-editor .codicon.codicon-symbol-null,.monaco-workbench .codicon.codicon-symbol-null{color:var(--vscode-symbolIcon-nullForeground)}.monaco-editor .codicon.codicon-symbol-number,.monaco-workbench .codicon.codicon-symbol-number{color:var(--vscode-symbolIcon-numberForeground)}.monaco-editor .codicon.codicon-symbol-object,.monaco-workbench .codicon.codicon-symbol-object{color:var(--vscode-symbolIcon-objectForeground)}.monaco-editor .codicon.codicon-symbol-operator,.monaco-workbench .codicon.codicon-symbol-operator{color:var(--vscode-symbolIcon-operatorForeground)}.monaco-editor .codicon.codicon-symbol-package,.monaco-workbench .codicon.codicon-symbol-package{color:var(--vscode-symbolIcon-packageForeground)}.monaco-editor .codicon.codicon-symbol-property,.monaco-workbench .codicon.codicon-symbol-property{color:var(--vscode-symbolIcon-propertyForeground)}.monaco-editor .codicon.codicon-symbol-reference,.monaco-workbench .codicon.codicon-symbol-reference{color:var(--vscode-symbolIcon-referenceForeground)}.monaco-editor .codicon.codicon-symbol-snippet,.monaco-workbench .codicon.codicon-symbol-snippet{color:var(--vscode-symbolIcon-snippetForeground)}.monaco-editor .codicon.codicon-symbol-string,.monaco-workbench .codicon.codicon-symbol-string{color:var(--vscode-symbolIcon-stringForeground)}.monaco-editor .codicon.codicon-symbol-struct,.monaco-workbench .codicon.codicon-symbol-struct{color:var(--vscode-symbolIcon-structForeground)}.monaco-editor .codicon.codicon-symbol-text,.monaco-workbench .codicon.codicon-symbol-text{color:var(--vscode-symbolIcon-textForeground)}.monaco-editor .codicon.codicon-symbol-type-parameter,.monaco-workbench .codicon.codicon-symbol-type-parameter{color:var(--vscode-symbolIcon-typeParameterForeground)}.monaco-editor .codicon.codicon-symbol-unit,.monaco-workbench .codicon.codicon-symbol-unit{color:var(--vscode-symbolIcon-unitForeground)}.monaco-editor .codicon.codicon-symbol-variable,.monaco-workbench .codicon.codicon-symbol-variable{color:var(--vscode-symbolIcon-variableForeground)}.editor-banner{background:var(--vscode-banner-background);box-sizing:border-box;cursor:default;display:flex;font-size:12px;height:26px;overflow:visible;width:100%}.editor-banner .icon-container{align-items:center;display:flex;flex-shrink:0;padding:0 6px 0 10px}.editor-banner .icon-container.custom-icon{background-position:50%;background-repeat:no-repeat;background-size:16px;margin:0 6px 0 10px;padding:0;width:16px}.editor-banner .message-container{align-items:center;display:flex;line-height:26px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.editor-banner .message-container p{margin-block-end:0;margin-block-start:0}.editor-banner .message-actions-container{flex-grow:1;flex-shrink:0;line-height:26px;margin:0 4px}.editor-banner .message-actions-container a.monaco-button{margin:2px 8px;padding:0 12px;width:inherit}.editor-banner .message-actions-container a{margin-left:12px;padding:3px;text-decoration:underline}.editor-banner .action-container{padding:0 10px 0 6px}.editor-banner{background-color:var(--vscode-banner-background)}.editor-banner,.editor-banner .action-container .codicon,.editor-banner .message-actions-container .monaco-link{color:var(--vscode-banner-foreground)}.editor-banner .icon-container .codicon{color:var(--vscode-banner-iconForeground)}.monaco-editor .unicode-highlight{background-color:var(--vscode-editorUnicodeHighlight-background);border:1px solid var(--vscode-editorUnicodeHighlight-border);box-sizing:border-box}.monaco-editor .focused .selectionHighlight{background-color:var(--vscode-editor-selectionHighlightBackground);border:1px solid var(--vscode-editor-selectionHighlightBorder);box-sizing:border-box}.monaco-editor.hc-black .focused .selectionHighlight,.monaco-editor.hc-light .focused .selectionHighlight{border-style:dotted}.monaco-editor .wordHighlight{background-color:var(--vscode-editor-wordHighlightBackground);border:1px solid var(--vscode-editor-wordHighlightBorder);box-sizing:border-box}.monaco-editor.hc-black .wordHighlight,.monaco-editor.hc-light .wordHighlight{border-style:dotted}.monaco-editor .wordHighlightStrong{background-color:var(--vscode-editor-wordHighlightStrongBackground);border:1px solid var(--vscode-editor-wordHighlightStrongBorder);box-sizing:border-box}.monaco-editor.hc-black .wordHighlightStrong,.monaco-editor.hc-light .wordHighlightStrong{border-style:dotted}.monaco-editor .wordHighlightText{background-color:var(--vscode-editor-wordHighlightTextBackground);border:1px solid var(--vscode-editor-wordHighlightTextBorder);box-sizing:border-box}.monaco-editor.hc-black .wordHighlightText,.monaco-editor.hc-light .wordHighlightText{border-style:dotted}.monaco-editor .zone-widget{position:absolute;z-index:10}.monaco-editor .zone-widget .zone-widget-container{border-bottom-style:solid;border-bottom-width:0;border-top-style:solid;border-top-width:0;position:relative}.monaco-editor .iPadShowKeyboard{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MyIgaGVpZ2h0PSIzNiIgZmlsbD0ibm9uZSI+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBmaWxsPSIjNDI0MjQyIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00OC4wMzYgNC4wMUg0LjAwOHYyOC4wMmg0NC4wMjh6TTQuMDA4LjAwOEE0LjAwMyA0LjAwMyAwIDAgMCAuMDA1IDQuMDF2MjguMDJhNC4wMDMgNC4wMDMgMCAwIDAgNC4wMDMgNC4wMDJoNDQuMDI4YTQuMDAzIDQuMDAzIDAgMCAwIDQuMDAzLTQuMDAyVjQuMDFBNC4wMDMgNC4wMDMgMCAwIDAgNDguMDM2LjAwOHpNOC4wMSA4LjAxM2g0LjAwM3Y0LjAwM0g4LjAxem0xMi4wMDggMGgtNC4wMDJ2NC4wMDNoNC4wMDJ6bTQuMDAzIDBoNC4wMDJ2NC4wMDNoLTQuMDAyem0xMi4wMDggMGgtNC4wMDN2NC4wMDNoNC4wMDN6bTQuMDAyIDBoNC4wMDN2NC4wMDNINDAuMDN6bS0yNC4wMTUgOC4wMDVIOC4wMXY0LjAwM2g4LjAwNnptNC4wMDIgMGg0LjAwM3Y0LjAwM2gtNC4wMDN6bTEyLjAwOCAwaC00LjAwM3Y0LjAwM2g0LjAwM3ptMTIuMDA4IDB2NC4wMDNoLTguMDA1di00LjAwM3ptLTMyLjAyMSA4LjAwNUg4LjAxdjQuMDAzaDQuMDAzem00LjAwMyAwaDIwLjAxM3Y0LjAwM0gxNi4wMTZ6bTI4LjAxOCAwSDQwLjAzdjQuMDAzaDQuMDAzeiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9nPjxkZWZzPjxjbGlwUGF0aCBpZD0iYSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTAgMGg1M3YzNkgweiIvPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg==) 50% no-repeat;border:4px solid #f6f6f6;border-radius:4px;height:36px;margin:0;min-height:0;min-width:0;overflow:hidden;padding:0;position:absolute;resize:none;width:58px}.monaco-editor.vs-dark .iPadShowKeyboard{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MyIgaGVpZ2h0PSIzNiIgZmlsbD0ibm9uZSI+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBmaWxsPSIjQzVDNUM1IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00OC4wMzYgNC4wMUg0LjAwOHYyOC4wMmg0NC4wMjh6TTQuMDA4LjAwOEE0LjAwMyA0LjAwMyAwIDAgMCAuMDA1IDQuMDF2MjguMDJhNC4wMDMgNC4wMDMgMCAwIDAgNC4wMDMgNC4wMDJoNDQuMDI4YTQuMDAzIDQuMDAzIDAgMCAwIDQuMDAzLTQuMDAyVjQuMDFBNC4wMDMgNC4wMDMgMCAwIDAgNDguMDM2LjAwOHpNOC4wMSA4LjAxM2g0LjAwM3Y0LjAwM0g4LjAxem0xMi4wMDggMGgtNC4wMDJ2NC4wMDNoNC4wMDJ6bTQuMDAzIDBoNC4wMDJ2NC4wMDNoLTQuMDAyem0xMi4wMDggMGgtNC4wMDN2NC4wMDNoNC4wMDN6bTQuMDAyIDBoNC4wMDN2NC4wMDNINDAuMDN6bS0yNC4wMTUgOC4wMDVIOC4wMXY0LjAwM2g4LjAwNnptNC4wMDIgMGg0LjAwM3Y0LjAwM2gtNC4wMDN6bTEyLjAwOCAwaC00LjAwM3Y0LjAwM2g0LjAwM3ptMTIuMDA4IDB2NC4wMDNoLTguMDA1di00LjAwM3ptLTMyLjAyMSA4LjAwNUg4LjAxdjQuMDAzaDQuMDAzem00LjAwMyAwaDIwLjAxM3Y0LjAwM0gxNi4wMTZ6bTI4LjAxOCAwSDQwLjAzdjQuMDAzaDQuMDAzeiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9nPjxkZWZzPjxjbGlwUGF0aCBpZD0iYSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTAgMGg1M3YzNkgweiIvPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg==) 50% no-repeat;border:4px solid #252526}.monaco-editor .tokens-inspect-widget{background-color:var(--vscode-editorHoverWidget-background);border:1px solid var(--vscode-editorHoverWidget-border);color:var(--vscode-editorHoverWidget-foreground);padding:10px;user-select:text;-webkit-user-select:text;z-index:50}.monaco-editor.hc-black .tokens-inspect-widget,.monaco-editor.hc-light .tokens-inspect-widget{border-width:2px}.monaco-editor .tokens-inspect-widget .tokens-inspect-separator{background-color:var(--vscode-editorHoverWidget-border);border:0;height:1px}.monaco-editor .tokens-inspect-widget .tm-token{font-family:var(--monaco-monospace-font)}.monaco-editor .tokens-inspect-widget .tm-token-length{float:right;font-size:60%;font-weight:400}.monaco-editor .tokens-inspect-widget .tm-metadata-table{width:100%}.monaco-editor .tokens-inspect-widget .tm-metadata-value{font-family:var(--monaco-monospace-font);text-align:right}.monaco-editor .tokens-inspect-widget .tm-token-type{font-family:var(--monaco-monospace-font)}.quick-input-widget{font-size:13px}.quick-input-widget .monaco-highlighted-label .highlight{color:#0066bf}.vs .quick-input-widget .monaco-list-row.focused .monaco-highlighted-label .highlight{color:#9dddff}.vs-dark .quick-input-widget .monaco-highlighted-label .highlight{color:#0097fb}.hc-black .quick-input-widget .monaco-highlighted-label .highlight{color:#f38518}.hc-light .quick-input-widget .monaco-highlighted-label .highlight{color:#0f4a85}.monaco-keybinding>.monaco-keybinding-key{background-color:#dedede66;border:1px solid;border-color:#ccc6 #ccc6 #bababa66;box-shadow:inset 0 -1px 0 #bababa66;color:#555}.hc-black .monaco-keybinding>.monaco-keybinding-key{background-color:initial;border:1px solid #6fc3df;box-shadow:none;color:#fff}.hc-light .monaco-keybinding>.monaco-keybinding-key{background-color:initial;border:1px solid #0f4a85;box-shadow:none;color:#292929}.vs-dark .monaco-keybinding>.monaco-keybinding-key{background-color:#8080802b;border:1px solid;border-color:#3339 #3339 #4449;box-shadow:inset 0 -1px 0 #4449;color:#ccc}.monaco-editor{--monaco-monospace-font:"SF Mono",Monaco,Menlo,Consolas,"Ubuntu Mono","Liberation Mono","DejaVu Sans Mono","Courier New",monospace;font-family:-apple-system,BlinkMacSystemFont,Segoe WPC,Segoe UI,HelveticaNeue-Light,system-ui,Ubuntu,Droid Sans,sans-serif}.monaco-editor.hc-black .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-editor.hc-light .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-editor.vs-dark .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,.monaco-menu .monaco-action-bar.vertical .action-item .action-menu-item:focus .action-label{stroke-width:1.2px}.monaco-hover p{margin:0}.monaco-aria-container{clip:rect(1px,1px,1px,1px);clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute!important;top:0;width:1px}.monaco-diff-editor .synthetic-focus,.monaco-diff-editor [tabindex="-1"]:focus,.monaco-diff-editor [tabindex="0"]:focus,.monaco-diff-editor button:focus,.monaco-diff-editor input[type=button]:focus,.monaco-diff-editor input[type=checkbox]:focus,.monaco-diff-editor input[type=search]:focus,.monaco-diff-editor input[type=text]:focus,.monaco-diff-editor select:focus,.monaco-diff-editor textarea:focus,.monaco-editor{opacity:1;outline-color:var(--vscode-focusBorder);outline-offset:-1px;outline-style:solid;outline-width:1px}.action-widget{background-color:var(--vscode-editorActionList-background);border:1px solid var(--vscode-editorWidget-border)!important;border-radius:0;border-radius:5px;box-shadow:0 2px 8px var(--vscode-widget-shadow);color:var(--vscode-editorActionList-foreground);display:block;font-size:13px;max-width:80vw;min-width:160px;padding:4px;width:100%;z-index:40}.context-view-block{z-index:-1}.context-view-block,.context-view-pointerBlock{cursor:auto;height:100%;left:0;position:fixed;top:0;width:100%}.context-view-pointerBlock{z-index:2}.action-widget .monaco-list{border:0!important;user-select:none;-webkit-user-select:none}.action-widget .monaco-list:focus:before{outline:0!important}.action-widget .monaco-list .monaco-scrollable-element{overflow:visible}.action-widget .monaco-list .monaco-list-row{border-radius:4px;cursor:pointer;padding:0 10px;touch-action:none;white-space:nowrap;width:100%}.action-widget .monaco-list .monaco-list-row.action.focused:not(.option-disabled){background-color:var(--vscode-editorActionList-focusBackground)!important;color:var(--vscode-editorActionList-focusForeground);outline:1px solid var(--vscode-menu-selectionBorder,#0000);outline-offset:-1px}.action-widget .monaco-list-row.group-header{color:var(--vscode-descriptionForeground)!important;font-size:12px;font-weight:600}.action-widget .monaco-list-row.group-header:not(:first-of-type){margin-top:2px}.action-widget .monaco-list .group-header,.action-widget .monaco-list .option-disabled,.action-widget .monaco-list .option-disabled .focused,.action-widget .monaco-list .option-disabled .focused:before,.action-widget .monaco-list .option-disabled:before{-webkit-touch-callout:none;background-color:initial!important;cursor:default!important;outline:0 solid!important;-webkit-user-select:none;user-select:none}.action-widget .monaco-list-row.action{align-items:center;display:flex;gap:8px}.action-widget .monaco-list-row.action.option-disabled,.action-widget .monaco-list-row.action.option-disabled .codicon,.action-widget .monaco-list:focus .monaco-list-row.focused.action.option-disabled,.action-widget .monaco-list:not(.drop-target):not(.dragging) .monaco-list-row:hover:not(.selected):not(.focused).option-disabled{color:var(--vscode-disabledForeground)}.action-widget .monaco-list-row.action:not(.option-disabled) .codicon{color:inherit}.action-widget .monaco-list-row.action .title{flex:1 1;overflow:hidden;text-overflow:ellipsis}.action-widget .monaco-list-row.action .monaco-keybinding>.monaco-keybinding-key{background-color:var(--vscode-keybindingLabel-background);border-color:var(--vscode-keybindingLabel-border);border-bottom:1px var(--vscode-keybindingLabel-bottomBorder);border-left-width:1px;border-radius:3px;border-right-width:1px;border-style:solid;border-top-width:1px;box-shadow:inset 0 -1px 0 var(--vscode-widget-shadow);color:var(--vscode-keybindingLabel-foreground)}.action-widget .action-widget-action-bar{background-color:var(--vscode-editorActionList-background);border-top:1px solid var(--vscode-editorHoverWidget-border);margin-top:2px}.action-widget .action-widget-action-bar:before{content:"";display:block;width:100%}.action-widget .action-widget-action-bar .actions-container{padding:3px 8px 0}.action-widget-action-bar .action-label{color:var(--vscode-textLink-activeForeground);font-size:12px;line-height:22px;padding:0;pointer-events:all}.action-widget-action-bar .action-item{margin-right:16px;pointer-events:none}.action-widget-action-bar .action-label:hover{background-color:initial!important}.monaco-action-bar .actions-container.highlight-toggled .action-label.checked{background:var(--vscode-actionBar-toggledBackground)!important}.monaco-action-bar .action-item.menu-entry .action-label.icon{background-position:50%;background-repeat:no-repeat;background-size:16px;height:16px;width:16px}.monaco-action-bar .action-item.menu-entry.text-only .action-label{border-radius:2px;color:var(--vscode-descriptionForeground);overflow:hidden}.monaco-action-bar .action-item.menu-entry.text-only.use-comma:not(:last-of-type) .action-label:after{content:", "}.monaco-action-bar .action-item.menu-entry.text-only+.action-item:not(.text-only)>.monaco-dropdown .action-label{color:var(--vscode-descriptionForeground)}.monaco-dropdown-with-default{border-radius:5px;display:flex!important;flex-direction:row}.monaco-dropdown-with-default>.action-container>.action-label{margin-right:0}.monaco-dropdown-with-default>.action-container.menu-entry>.action-label.icon{background-position:50%;background-repeat:no-repeat;background-size:16px;height:16px;width:16px}.monaco-dropdown-with-default:hover{background-color:var(--vscode-toolbar-hoverBackground)}.monaco-dropdown-with-default>.dropdown-action-container>.monaco-dropdown>.dropdown-label .codicon[class*=codicon-]{font-size:12px;line-height:16px;margin-left:-3px;padding-left:0;padding-right:0}.monaco-dropdown-with-default>.dropdown-action-container>.monaco-dropdown>.dropdown-label>.action-label{background-position:50%;background-repeat:no-repeat;background-size:16px;display:block}.monaco-link{color:var(--vscode-textLink-foreground)}.monaco-link:hover{color:var(--vscode-textLink-activeForeground)}.quick-input-widget{-webkit-app-region:no-drag;border-radius:6px;left:50%;margin-left:-300px;position:absolute;width:600px;z-index:2550}.quick-input-titlebar{align-items:center;border-top-left-radius:5px;border-top-right-radius:5px;display:flex}.quick-input-left-action-bar{display:flex;flex:1 1;margin-left:4px}.quick-input-inline-action-bar{margin:2px 0 0 5px}.quick-input-title{overflow:hidden;padding:3px 0;text-align:center;text-overflow:ellipsis}.quick-input-right-action-bar{display:flex;flex:1 1;margin-right:4px}.quick-input-right-action-bar>.actions-container{justify-content:flex-end}.quick-input-titlebar .monaco-action-bar .action-label.codicon{background-position:50%;background-repeat:no-repeat;padding:2px}.quick-input-description{margin:6px 6px 6px 11px}.quick-input-header .quick-input-description{flex:1 1;margin:4px 2px}.quick-input-header{display:flex;padding:8px 6px 2px}.quick-input-widget.hidden-input .quick-input-header{margin-bottom:0;padding:0}.quick-input-and-message{display:flex;flex-direction:column;flex-grow:1;min-width:0;position:relative}.quick-input-check-all{align-self:center;margin:0}.quick-input-filter{display:flex;flex-grow:1;position:relative}.quick-input-box{flex-grow:1}.quick-input-widget.show-checkboxes .quick-input-box,.quick-input-widget.show-checkboxes .quick-input-message{margin-left:5px}.quick-input-visible-count{left:-10000px;position:absolute}.quick-input-count{align-items:center;align-self:center;display:flex;position:absolute;right:4px}.quick-input-count .monaco-count-badge{border-radius:2px;line-height:normal;min-height:auto;padding:2px 4px;vertical-align:middle}.quick-input-action{margin-left:6px}.quick-input-action .monaco-text-button{align-items:center;display:flex;font-size:11px;height:25px;padding:0 6px}.quick-input-message{margin-top:-1px;overflow-wrap:break-word;padding:5px}.quick-input-message>.codicon{margin:0 .2em;vertical-align:text-bottom}.quick-input-message a{color:inherit}.quick-input-progress.monaco-progress-container{position:relative}.quick-input-list{line-height:22px}.quick-input-widget.hidden-input .quick-input-list{margin-top:4px;padding-bottom:4px}.quick-input-list .monaco-list{max-height:440px;overflow:hidden;padding-bottom:5px}.quick-input-list .monaco-scrollable-element{padding:0 5px}.quick-input-list .quick-input-list-entry{box-sizing:border-box;display:flex;overflow:hidden;padding:0 6px}.quick-input-list .quick-input-list-entry.quick-input-list-separator-border{border-top-style:solid;border-top-width:1px}.quick-input-list .monaco-list-row{border-radius:3px}.quick-input-list .monaco-list-row[data-index="0"] .quick-input-list-entry.quick-input-list-separator-border{border-top-style:none}.quick-input-list .quick-input-list-label{display:flex;flex:1 1;height:100%;overflow:hidden}.quick-input-list .quick-input-list-checkbox{align-self:center;margin:0}.quick-input-list .quick-input-list-icon{align-items:center;background-position:0;background-repeat:no-repeat;background-size:16px;display:flex;height:22px;justify-content:center;padding-right:6px;width:16px}.quick-input-list .quick-input-list-rows{display:flex;flex:1 1;flex-direction:column;height:100%;margin-left:5px;overflow:hidden;text-overflow:ellipsis}.quick-input-widget.show-checkboxes .quick-input-list .quick-input-list-rows{margin-left:10px}.quick-input-widget .quick-input-list .quick-input-list-checkbox{display:none}.quick-input-widget.show-checkboxes .quick-input-list .quick-input-list-checkbox{display:inline}.quick-input-list .quick-input-list-rows>.quick-input-list-row{align-items:center;display:flex}.quick-input-list .quick-input-list-rows>.quick-input-list-row .monaco-icon-label,.quick-input-list .quick-input-list-rows>.quick-input-list-row .monaco-icon-label .monaco-icon-label-container>.monaco-icon-name-container{flex:1 1}.quick-input-list .quick-input-list-rows>.quick-input-list-row .codicon[class*=codicon-]{vertical-align:text-bottom}.quick-input-list .quick-input-list-rows .monaco-highlighted-label>span{opacity:1}.quick-input-list .quick-input-list-entry .quick-input-list-entry-keybinding{margin-right:8px}.quick-input-list .quick-input-list-label-meta{line-height:normal;opacity:.7;overflow:hidden;text-overflow:ellipsis}.quick-input-list .monaco-list .monaco-list-row .monaco-highlighted-label .highlight{background-color:unset;color:var(--vscode-list-highlightForeground)!important;font-weight:700}.quick-input-list .monaco-list .monaco-list-row.focused .monaco-highlighted-label .highlight{color:var(--vscode-list-focusHighlightForeground)!important}.quick-input-list .quick-input-list-entry .quick-input-list-separator{margin-right:4px}.quick-input-list .quick-input-list-entry-action-bar{display:flex;flex:0 1;overflow:visible}.quick-input-list .quick-input-list-entry-action-bar .action-label{display:none}.quick-input-list .quick-input-list-entry-action-bar .action-label.codicon{margin-right:4px;padding:2px}.quick-input-list .quick-input-list-entry-action-bar{margin-right:4px;margin-top:1px}.quick-input-list .monaco-list-row.focused .quick-input-list-entry-action-bar .action-label,.quick-input-list .monaco-list-row.passive-focused .quick-input-list-entry-action-bar .action-label,.quick-input-list .quick-input-list-entry .quick-input-list-entry-action-bar .action-label.always-visible,.quick-input-list .quick-input-list-entry.focus-inside .quick-input-list-entry-action-bar .action-label,.quick-input-list .quick-input-list-entry:hover .quick-input-list-entry-action-bar .action-label{display:flex}.quick-input-list .monaco-list-row.focused .monaco-keybinding-key,.quick-input-list .monaco-list-row.focused .quick-input-list-entry .quick-input-list-separator{color:inherit}.quick-input-list .monaco-list-row.focused .monaco-keybinding-key{background:none}.quick-input-list .quick-input-list-separator-as-item{font-size:12px;padding:4px 6px}.quick-input-list .quick-input-list-separator-as-item .label-name{font-weight:600}.quick-input-list .quick-input-list-separator-as-item .label-description{opacity:1!important}.quick-input-list .monaco-tree-sticky-row .quick-input-list-entry.quick-input-list-separator-as-item.quick-input-list-separator-border{border-top-style:none}.quick-input-list .monaco-tree-sticky-row{padding:0 5px}.quick-input-list .monaco-tl-twistie{display:none!important}.extension-editor .codicon.codicon-error,.extensions-viewlet>.extensions .codicon.codicon-error,.markers-panel .marker-icon .codicon.codicon-error,.markers-panel .marker-icon.error,.monaco-editor .zone-widget .codicon.codicon-error,.preferences-editor .codicon.codicon-error,.text-search-provider-messages .providerMessage .codicon.codicon-error{color:var(--vscode-problemsErrorIcon-foreground)}.extension-editor .codicon.codicon-warning,.extensions-viewlet>.extensions .codicon.codicon-warning,.markers-panel .marker-icon .codicon.codicon-warning,.markers-panel .marker-icon.warning,.monaco-editor .zone-widget .codicon.codicon-warning,.preferences-editor .codicon.codicon-warning,.text-search-provider-messages .providerMessage .codicon.codicon-warning{color:var(--vscode-problemsWarningIcon-foreground)}.extension-editor .codicon.codicon-info,.extensions-viewlet>.extensions .codicon.codicon-info,.markers-panel .marker-icon .codicon.codicon-info,.markers-panel .marker-icon.info,.monaco-editor .zone-widget .codicon.codicon-info,.preferences-editor .codicon.codicon-info,.text-search-provider-messages .providerMessage .codicon.codicon-info{color:var(--vscode-problemsInfoIcon-foreground)}.ydb-navigation-tree-view-empty{color:var(--g-color-text-secondary);font-style:italic}.ydb-navigation-tree-view-error{color:var(--g-color-text-danger)}.ydb-navigation-tree-view-loader{align-items:center;display:flex;height:24px;justify-content:center;width:20px} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/64464.f737743e.chunk.css b/ydb/core/viewer/monitoring/static/css/64464.f737743e.chunk.css deleted file mode 100644 index 47a0affaecc1..000000000000 --- a/ydb/core/viewer/monitoring/static/css/64464.f737743e.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.kv-split{display:flex;height:100%;outline:none;-webkit-user-select:text;user-select:text;z-index:0}.kv-split.horizontal{flex-direction:row}.kv-split.vertical{flex-direction:column;min-height:100%;width:100%}.kv-split .gutter{background:var(--g-color-base-background);position:relative;z-index:10}.kv-split .gutter:after{background-color:var(--g-color-base-generic-ultralight);content:"";inset:0;position:absolute}.kv-split .gutter.active:after,.kv-split .gutter:hover:after{background-color:var(--g-color-line-generic-hover);transition:background-color 1s ease}.kv-split .gutter.disabled{display:none}.kv-split .gutter.gutter-vertical{cursor:row-resize;height:8px;width:100%}.kv-split .gutter.gutter-vertical:before{border-color:var(--g-color-base-generic-hover);border-style:solid;border-width:1px 0;content:"";height:4px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:16px}.kv-split .gutter.gutter-horizontal{cursor:col-resize;height:100%;width:8px}.kv-split .gutter.gutter-horizontal:before{border-color:var(--g-color-base-generic-hover);border-style:solid;border-width:0 1px;content:"";height:16px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:4px}.auto-refresh-control{align-items:center;display:flex;gap:var(--g-spacing-1)}.histogram{display:flex;flex:1 1 auto}.histogram__chart{align-items:baseline;border-bottom:1px solid var(--g-color-base-generic);border-left:1px solid var(--g-color-base-generic);display:flex;height:300px;margin-left:50px;margin-top:30px;position:relative;width:800px}.histogram__x-min{left:-3px}.histogram__x-max,.histogram__x-min{bottom:-25px;color:var(--g-color-text-secondary);position:absolute}.histogram__x-max{right:0}.histogram__y-min{bottom:-7px;left:-30px;width:20px}.histogram__y-max,.histogram__y-min{color:var(--g-color-text-secondary);position:absolute;text-align:right}.histogram__y-max{left:-60px;top:-5px;width:50px}.histogram__item{cursor:pointer;margin-right:.5%;width:1.5%}.heatmap{display:flex;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto}.heatmap__limits{align-items:center;display:flex;margin-left:20px}.heatmap__limits-block{display:flex;margin-right:10px}.heatmap__limits-title{color:var(--g-color-text-secondary);margin-right:5px}.heatmap__row{align-items:center}.heatmap__row_overall{margin:15px 20px}.heatmap__row_overall .g-progress{margin:0;width:300px}.heatmap__label{font-size:var(--g-text-body-2-font-size);font-weight:500;line-height:var(--g-text-body-2-line-height);margin-right:16px;text-transform:uppercase}.heatmap__label_overall{margin-right:15px}.heatmap__items{overflow:auto}.heatmap__canvas-container{cursor:pointer;overflow:auto}.heatmap__filters{align-items:center;display:flex;margin:0 0 10px}.heatmap__filter-control{margin-right:10px;max-width:200px;min-width:100px}.heatmap__filter-control:last-child{margin-right:0}.heatmap__histogram-checkbox,.heatmap__sort-checkbox{margin-left:10px}.heatmap__row{display:flex}.heatmap .tablet,.heatmap__row{margin-bottom:2px}.table-skeleton__wrapper{width:100%}.table-skeleton__wrapper_hidden{visibility:hidden}.table-skeleton__row{align-items:center;display:flex;height:var(--data-table-row-height)}.table-skeleton__row .g-skeleton{height:var(--g-text-body-2-line-height)}.table-skeleton__col-1{margin-right:5%;width:10%}.table-skeleton__col-2{margin-right:5%;width:7%}.table-skeleton__col-3,.table-skeleton__col-4{margin-right:5%;width:5%}.table-skeleton__col-5{width:20%}.table-skeleton__col-full{width:100%}.ydb-table-with-controls-layout{--data-table-sticky-top-offset:62px;box-sizing:border-box;display:inline-block;min-width:100%}.ydb-table-with-controls-layout__controls-wrapper{background-color:var(--g-color-base-background);box-sizing:border-box;left:0;position:sticky;top:0;width:100%;z-index:3}.ydb-table-with-controls-layout__controls{align-items:center;background-color:var(--g-color-base-background);display:flex;gap:12px;height:62px;left:0;padding:16px 0 18px;position:sticky;top:0;width:max-content;z-index:3}.ydb-table-with-controls-layout__table{position:relative;z-index:2}.ydb-table-with-controls-layout .ydb-paginated-table__head{top:var(--data-table-sticky-top-offset,62px)}.ydb-table-with-controls-layout .data-table__sticky_moving{top:var(--data-table-sticky-top-offset,62px)!important}.ydb-table-group{border:1px solid var(--g-color-line-generic);border-radius:var(--g-spacing-2);display:flex;flex-direction:column;margin-bottom:20px;width:100%}.ydb-table-group__button{background:unset;border:unset;cursor:pointer;padding:8px 0}.ydb-table-group__title-wrapper{align-items:center;display:flex;flex-direction:row;gap:var(--g-spacing-2);justify-content:flex-start;left:0;padding-left:20px;position:sticky;width:max-content}.ydb-table-group__title{display:flex;flex-direction:row;gap:var(--g-spacing-4)}.ydb-table-group__count{display:flex;flex-direction:row;gap:var(--g-spacing-3)}.ydb-table-group__content{padding:12px 0 20px 20px}.ydb-search{min-width:100px}.ydb-paginated-table{--paginated-table-cell-vertical-padding:5px;--paginated-table-cell-horizontal-padding:10px;--paginated-table-border-color:var(--g-color-base-generic-hover);--paginated-table-hover-color:var(--g-color-base-simple-hover-solid);font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);width:100%}.ydb-paginated-table__table{border-collapse:initial;border-spacing:0;max-width:100%;table-layout:fixed;width:max-content}.ydb-paginated-table__table th{padding:0}.ydb-paginated-table__row{position:relative;transform:translateZ(0);z-index:1}.ydb-paginated-table__row:hover{background:var(--paginated-table-hover-color)}.ydb-paginated-table__row_empty:hover{background-color:initial}.ydb-paginated-table__head{background-color:var(--g-color-base-background);left:0;position:sticky;top:0;z-index:2}.ydb-paginated-table__sort-icon-container{color:inherit;display:flex;justify-content:center}.ydb-paginated-table__sort-icon-container_shadow{opacity:.15}.ydb-paginated-table__sort-icon_desc{transform:rotate(180deg)}.ydb-paginated-table__head-cell-wrapper{border-bottom:1px solid var(--paginated-table-border-color);display:table-cell;overflow-x:hidden;position:relative}.ydb-paginated-table__head-cell{align-items:center;display:flex;flex-direction:row;max-width:100%;padding:var(--paginated-table-cell-vertical-padding) var(--paginated-table-cell-horizontal-padding);width:100%}.ydb-paginated-table__head-cell_align_left{justify-content:left}.ydb-paginated-table__head-cell_align_center{justify-content:center}.ydb-paginated-table__head-cell_align_right{justify-content:right}.ydb-paginated-table__head-cell{cursor:default;font-weight:700;gap:8px}.ydb-paginated-table__head-cell_sortable{cursor:pointer}.ydb-paginated-table__head-cell_sortable.ydb-paginated-table__head-cell_align_right{flex-direction:row-reverse}.ydb-paginated-table__head-cell-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:min-content}.ydb-paginated-table__row-cell{border-bottom:1px solid var(--paginated-table-border-color);display:table-cell;max-width:100%;overflow-x:hidden;padding:var(--paginated-table-cell-vertical-padding) var(--paginated-table-cell-horizontal-padding);text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:100%}.ydb-paginated-table__row-cell_align_left{text-align:left}.ydb-paginated-table__row-cell_align_center{text-align:center}.ydb-paginated-table__row-cell_align_right{text-align:right}.ydb-paginated-table__resize-handler{background-color:var(--g-color-base-generic);cursor:col-resize;height:100%;position:absolute;right:0;top:0;visibility:hidden;width:6px}.ydb-paginated-table__head-cell-wrapper:hover>.ydb-paginated-table__resize-handler,.ydb-paginated-table__resize-handler_resizing{visibility:visible}.ydb-paginated-table__resizeable-table-container{padding-right:20px;width:max-content}.ydb-paginated-table__row-skeleton:after{animation:none!important}.hover-popup{padding:var(--g-spacing-3)}.progress-viewer{align-items:center;background:var(--g-color-base-generic);border-radius:2px;color:var(--g-color-text-complementary);display:flex;font-size:var(--g-text-body-2-font-size);height:23px;justify-content:center;min-width:150px;overflow:hidden;padding:0 4px;position:relative;white-space:nowrap;z-index:0}.progress-viewer_theme_dark{color:var(--g-color-text-light-primary)}.progress-viewer_theme_dark .progress-viewer__line{opacity:.75}.progress-viewer_status_good{background-color:var(--g-color-base-positive-light)}.progress-viewer_status_good .progress-viewer__line{background-color:var(--ydb-color-status-green)}.progress-viewer_status_warning{background-color:var(--g-color-base-yellow-light)}.progress-viewer_status_warning .progress-viewer__line{background-color:var(--ydb-color-status-yellow)}.progress-viewer_status_danger{background-color:var(--g-color-base-danger-light)}.progress-viewer_status_danger .progress-viewer__line{background-color:var(--ydb-color-status-red)}.progress-viewer__line{height:100%;left:0;position:absolute;top:0}.progress-viewer__text{position:relative;z-index:1}.progress-viewer_size_xs{font-size:var(--g-text-body-2-font-size);height:20px;line-height:var(--g-text-body-2-line-height)}.progress-viewer_size_s{font-size:var(--g-text-body-1-font-size);height:28px;line-height:28px}.progress-viewer_size_m{font-size:var(--g-text-body-2-font-size);height:32px;line-height:32px}.progress-viewer_size_ns{font-size:13px;height:24px;line-height:var(--g-text-subheader-3-line-height)}.progress-viewer_size_n{font-size:var(--g-text-body-1-font-size);height:36px;line-height:36px}.progress-viewer_size_l{font-size:var(--g-text-subheader-3-font-size);height:38px;line-height:38px}.progress-viewer_size_head{font-size:var(--g-text-body-1-font-size);line-height:36px}.memory-viewer{min-width:150px;padding:0 var(--g-spacing-1);position:relative;z-index:0}.memory-viewer__progress-container{background:var(--g-color-base-generic);border-radius:2px;height:20px;overflow:hidden;position:relative}.memory-viewer__container{display:flex;padding:2px 0}.memory-viewer__legend{border-radius:2px;bottom:2px;height:20px;position:absolute;width:20px}.memory-viewer__legend_type_AllocatorCachesMemory{background-color:var(--g-color-base-utility-medium-hover)}.memory-viewer__legend_type_SharedCacheConsumption{background-color:var(--g-color-base-info-medium-hover)}.memory-viewer__legend_type_MemTableConsumption{background-color:var(--g-color-base-warning-medium-hover)}.memory-viewer__legend_type_QueryExecutionConsumption{background-color:var(--g-color-base-positive-medium-hover)}.memory-viewer__legend_type_Other{background-color:var(--g-color-base-generic-medium-hover)}.memory-viewer__segment{height:100%;position:absolute}.memory-viewer__segment_type_AllocatorCachesMemory{background-color:var(--g-color-base-utility-medium-hover)}.memory-viewer__segment_type_SharedCacheConsumption{background-color:var(--g-color-base-info-medium-hover)}.memory-viewer__segment_type_MemTableConsumption{background-color:var(--g-color-base-warning-medium-hover)}.memory-viewer__segment_type_QueryExecutionConsumption{background-color:var(--g-color-base-positive-medium-hover)}.memory-viewer__segment_type_Other{background-color:var(--g-color-base-generic-medium-hover)}.memory-viewer__name{padding-left:28px}.memory-viewer_theme_dark{color:var(--g-color-text-light-primary)}.memory-viewer_theme_dark .memory-viewer__segment{opacity:.75}.memory-viewer_status_good .memory-viewer__progress-container{background-color:var(--g-color-base-positive-light)}.memory-viewer_status_warning .memory-viewer__progress-container{background-color:var(--g-color-base-yellow-light)}.memory-viewer_status_danger .memory-viewer__progress-container{background-color:var(--g-color-base-danger-light)}.memory-viewer__text{align-items:center;display:flex;justify-content:center}.ydb-pool-bar{border:1px solid;border-radius:1px;cursor:pointer;height:20px;margin-right:2px;position:relative;width:6px}.ydb-pool-bar__popup-content{padding:10px;width:170px}.ydb-pool-bar:last-child{margin-right:0}.ydb-pool-bar_type_normal{border-color:var(--ydb-color-status-green)}.ydb-pool-bar_type_warning{border-color:var(--ydb-color-status-yellow)}.ydb-pool-bar_type_danger{border-color:var(--ydb-color-status-red)}.ydb-pool-bar__value{bottom:0;min-height:1px;position:absolute;width:100%}.ydb-pool-bar__value_type_normal{background-color:var(--ydb-color-status-green)}.ydb-pool-bar__value_type_warning{background-color:var(--ydb-color-status-yellow)}.ydb-pool-bar__value_type_danger{background-color:var(--ydb-color-status-red)}.ydb-pools-graph{display:flex}.tablets-statistic{align-items:center;display:flex;gap:2px}.tablets-statistic__tablet{border:1px solid;border-radius:2px;color:var(--g-color-text-secondary);display:inline-block;font-size:11px;height:20px;line-height:20px;padding:0 4px;text-align:center;text-decoration:none;text-transform:uppercase}.tablets-statistic__tablet_state_green{background-color:var(--g-color-base-positive-light);color:var(--g-color-text-positive)}.tablets-statistic__tablet_state_yellow{background-color:var(--g-color-base-warning-light);color:var(--g-color-text-warning)}.tablets-statistic__tablet_state_blue{background-color:var(--g-color-base-info-light);color:var(--g-color-text-info)}.tablets-statistic__tablet_state_orange{background-color:var(--g-color-base-warning-light);color:var(--g-color-text-warning-heavy)}.tablets-statistic__tablet_state_red{background:var(--g-color-base-danger-light);color:var(--g-color-text-danger)}.tablets-statistic__tablet_state_grey{border:1px solid var(--g-color-line-generic-hover);color:var(--g-color-text-secondary)}.ydb-nodes-columns__column-cpu,.ydb-nodes-columns__column-ram{min-width:40px}.ydb-nodes__search{width:238px}.ydb-nodes__show-all-wrapper{left:0;margin-bottom:15px;position:sticky}.ydb-nodes__node_unavailable{opacity:.6}.ydb-nodes__groups-wrapper{padding-right:20px}.operations__search{width:220px}.kv-shorty-string__toggle{font-size:.85em;margin-left:2em}.kv-result-issues{padding:0 10px}.kv-result-issues__error-message{align-items:center;background-color:var(--g-color-base-background);display:flex;left:0;padding:10px 0;position:sticky;top:0;z-index:2}.kv-result-issues__error-message-text{margin:0 10px}.kv-issues{position:relative}.kv-issue_leaf{margin-left:31px}.kv-issue__issues{padding-left:24px}.kv-issue__line{align-items:flex-start;display:flex;margin:0 0 10px;padding:0 10px 0 0}.kv-issue__place-text{color:var(--g-color-text-secondary);display:inline-block;padding-right:10px;text-align:left}.kv-issue__message{display:flex;font-family:var(--g-font-family-monospace);font-size:var(--g-text-code-2-font-size);line-height:var(--g-text-header-2-line-height);margin-left:10px;margin-right:auto}.kv-issue__message-text{flex:1 1 auto;min-width:240px;white-space:pre-wrap;word-break:break-word}.kv-issue__code{color:var(--g-color-text-complementary);flex:0 0 auto;font-size:12px;margin-left:1.5em;padding:3px 0}.kv-issue__arrow-toggle{margin-right:5px}.yql-issue-severity{align-items:center;display:flex;line-height:28px;white-space:nowrap}.yql-issue-severity_severity_error .yql-issue-severity__icon,.yql-issue-severity_severity_fatal .yql-issue-severity__icon{color:var(--g-color-text-danger)}.yql-issue-severity_severity_warning .yql-issue-severity__icon{color:var(--g-color-text-warning)}.yql-issue-severity_severity_info .yql-issue-severity__icon{color:var(--g-color-text-info)}.yql-issue-severity__title{color:var(--g-color-text-complementary);margin-left:4px;text-transform:capitalize}.ydb-critical-dialog{padding-top:var(--g-spacing-3)}.ydb-critical-dialog__warning-icon{color:var(--ydb-color-status-yellow);margin-right:16px}.ydb-critical-dialog__error-icon{color:var(--ydb-color-status-red);height:24px;margin-right:16px}.ydb-critical-dialog__body{display:flex;flex-direction:column;gap:var(--g-spacing-6)}.ydb-critical-dialog__body-message{align-items:center;display:flex}.ydb-critical-dialog__body-message_error,.ydb-critical-dialog__body-message_warning{border:1px solid;border-radius:var(--g-modal-border-radius,5px);padding:var(--g-spacing-4) var(--g-spacing-5)}.ydb-critical-dialog__body-message_warning{border-color:var(--ydb-color-status-yellow)}.ydb-critical-dialog__body-message_error{border-color:var(--ydb-color-status-red)}.storage-disk-progress-bar{--progress-bar-full-height:var(--g-text-body-3-line-height);--progress-bar-compact-height:12px;--entity-state-border-color:var(--g-color-base-misc-heavy);--entity-state-background-color:var(--g-color-base-misc-light);--entity-state-fill-color:var(--g-color-base-misc-medium);--entity-state-font-color:var(--g-color-text-primary);background-color:var(--entity-state-background-color);border:1px solid var(--entity-state-border-color);border-radius:4px;color:var(--g-color-text-primary);height:var(--progress-bar-full-height);min-width:50px;position:relative;text-align:center;z-index:0}.storage-disk-progress-bar_green{--entity-state-font-color:var(--g-color-text-positive);--entity-state-border-color:var(--g-color-base-positive-heavy);--entity-state-background-color:var(--g-color-base-positive-light);--entity-state-fill-color:var(--g-color-base-positive-medium)}.storage-disk-progress-bar_blue{--entity-state-font-color:var(--g-color-text-info);--entity-state-border-color:var(--g-color-base-info-heavy);--entity-state-background-color:var(--g-color-base-info-light);--entity-state-fill-color:var(--g-color-base-info-medium)}.storage-disk-progress-bar_yellow{--entity-state-font-color:var(--g-color-text-warning);--entity-state-border-color:var(--g-color-base-warning-heavy);--entity-state-background-color:var(--g-color-base-yellow-light);--entity-state-fill-color:var(--g-color-base-yellow-medium)}.storage-disk-progress-bar_orange{--entity-state-font-color:var(--g-color-private-orange-500);--entity-state-border-color:var(--ydb-color-status-orange);--entity-state-background-color:var(--g-color-private-orange-100);--entity-state-fill-color:var(--g-color-private-orange-300)}.storage-disk-progress-bar_red{--entity-state-font-color:var(--g-color-text-danger);--entity-state-border-color:var(--g-color-base-danger-heavy);--entity-state-background-color:var(--g-color-base-danger-light);--entity-state-fill-color:var(--g-color-base-danger-medium)}.storage-disk-progress-bar__grey{--entity-state-font-color:var(--g-color-text-secondary);--entity-state-border-color:var(--g-color-line-generic-hover)}.storage-disk-progress-bar_compact{border-radius:2px;height:var(--progress-bar-compact-height);min-width:0}.storage-disk-progress-bar_faded{background-color:unset}.storage-disk-progress-bar_inactive{opacity:.5}.storage-disk-progress-bar_empty{background-color:unset;border-style:dashed;color:var(--g-color-text-hint)}.storage-disk-progress-bar__fill-bar{background-color:var(--entity-state-fill-color);border-radius:3px 0 0 3px;height:100%;left:0;position:absolute;top:0}.storage-disk-progress-bar__fill-bar_faded{background-color:var(--entity-state-background-color)}.storage-disk-progress-bar__fill-bar_compact{border-radius:1px}.storage-disk-progress-bar__fill-bar_inverted{border-radius:0 3px 3px 0;left:auto;right:0}.storage-disk-progress-bar__title{color:inherit;font-size:var(--g-text-body-1-font-size);line-height:calc(var(--progress-bar-full-height) - 2px);position:relative;z-index:2}.vdisk-storage-popup .info-viewer+.info-viewer{border-top:1px solid var(--g-color-line-generic);margin-top:8px;padding-top:8px}.vdisk-storage-popup__donor-label{margin-bottom:8px}.ydb-vdisk-component{border-radius:4px}.ydb-vdisk-component__content{border-radius:4px;display:block}.pdisk-storage{display:flex;flex-direction:column;justify-content:flex-end;min-width:var(--pdisk-min-width);position:relative;width:var(--pdisk-width)}.pdisk-storage__content{border-radius:4px;display:block;flex:1 1;position:relative}.pdisk-storage__vdisks{display:flex;flex:0 0 auto;gap:var(--pdisk-gap-width);margin-bottom:4px;white-space:nowrap}.pdisk-storage__vdisks-item{flex:0 0 var(--pdisk-vdisk-width);min-width:var(--pdisk-vdisk-width)}.data-table__row:hover .pdisk-storage__vdisks-item .stack__layer{background:var(--ydb-data-table-color-hover)}.pdisk-storage__donors-stack{--ydb-stack-offset-x:0px;--ydb-stack-offset-y:-2px;--ydb-stack-offset-x-hover:0px;--ydb-stack-offset-y-hover:-7px}.pdisk-storage__media-type{color:var(--g-color-text-secondary);font-size:var(--g-text-body-1-font-size);line-height:var(--g-text-body-1-line-height);position:absolute;right:4px;top:50%;transform:translateY(-50%)}.ydb-storage-disks{align-items:center;display:flex;flex-direction:row;gap:20px;width:max-content}.ydb-storage-disks__pdisks-wrapper{display:flex;flex-direction:row;justify-content:left;width:max-content}.ydb-storage-disks__vdisk-item{flex-basis:8px;flex-shrink:0}.ydb-storage-disks__vdisk-progress-bar{--progress-bar-compact-height:18px;border-radius:4px}.ydb-storage-disks__pdisk-item{margin-right:4px;min-width:80px}.ydb-storage-disks__pdisk-item_with-dc-margin{margin-right:12px}.ydb-storage-disks__pdisk-item:last-child{margin-right:0}.ydb-storage-disks__pdisk-progress-bar{--progress-bar-full-height:20px;padding-left:var(--g-spacing-2);text-align:left}.stack{--ydb-stack-base-z-index:100;--ydb-stack-offset-x:4px;--ydb-stack-offset-y:4px;--ydb-stack-offset-x-hover:4px;--ydb-stack-offset-y-hover:6px;position:relative}.stack__layer{background:var(--g-color-base-background);transition:transform .1s ease-out}.stack__layer:first-child{position:relative;z-index:var(--ydb-stack-base-z-index)}.stack__layer+.stack__layer{height:100%;left:0;position:absolute;top:0;transform:translate(calc(var(--ydb-stack-level)*var(--ydb-stack-offset-x)),calc(var(--ydb-stack-level)*var(--ydb-stack-offset-y)));width:100%;z-index:calc(var(--ydb-stack-base-z-index) - var(--ydb-stack-level))}.stack:hover .stack__layer:first-child{transform:translate(calc(var(--ydb-stack-offset-x-hover)*-1),calc(var(--ydb-stack-offset-y-hover)*-1))}.stack:hover .stack__layer+.stack__layer{transform:translate(calc(var(--ydb-stack-level)*var(--ydb-stack-offset-x-hover)*2 - var(--ydb-stack-offset-x-hover)),calc(var(--ydb-stack-level)*var(--ydb-stack-offset-y-hover)*2 - var(--ydb-stack-offset-y-hover)))}.ydb-storage-vdisks__wrapper{display:flex}.ydb-storage-vdisks__item{margin-right:6px;width:90px}.ydb-storage-vdisks__item_with-dc-margin{margin-right:12px}.ydb-storage-vdisks__item:last-child{margin-right:0}.data-table__row:hover .ydb-storage-vdisks__item .stack__layer{background:var(--ydb-data-table-color-hover)}.ydb-storage-groups-columns__disks-column,.ydb-storage-groups-columns__vdisks-column{overflow:visible}.ydb-storage-groups-columns__pool-name-wrapper{direction:rtl;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ydb-storage-groups-columns__pool-name{unicode-bidi:plaintext}.ydb-storage-groups-columns__group-id{font-weight:500;margin-right:var(--g-spacing-1)}.global-storage__search{width:238px}.global-storage__table .g-tooltip{height:var(--g-text-body-2-line-height)!important}.global-storage .entity-status{justify-content:center}.global-storage__groups-wrapper{padding-right:20px}.ydb-storage-nodes__node_unavailable{opacity:.6}.ydb-storage-nodes-columns__pdisks-column{overflow:visible}.ydb-storage-nodes-columns__pdisks-wrapper{--pdisk-vdisk-width:3px;--pdisk-gap-width:2px;--pdisk-min-width:120px;--pdisk-margin:10px;--pdisk-width:max(calc(var(--maximum-slots, 1)*var(--pdisk-vdisk-width) + (var(--maximum-slots, 1) - 1)*var(--pdisk-gap-width)),var(--pdisk-min-width));--pdisks-container-width:calc(var(--maximum-disks, 1)*var(--pdisk-width) + (var(--maximum-disks, 1) - 1)*var(--pdisk-margin));display:flex;gap:var(--pdisk-margin);height:40px;width:var(--pdisks-container-width)}.ydb-storage-nodes-columns__pdisks-item{display:flex;flex-shrink:0}.schema-viewer__keys{display:inline-block;padding-bottom:var(--g-spacing-4);padding-left:10px}.schema-viewer__keys-values{color:var(--g-color-text-complementary);display:inline;font-size:var(--g-text-body-1-font-size);line-height:var(--g-text-body-1-line-height)}.schema-viewer__keys-header{color:var(--g-color-text-primary);display:inline;font-size:var(--g-text-subheader-1-font-size);font-weight:700;line-height:var(--g-text-subheader-1-line-height);white-space:nowrap}.schema-viewer__keys-label{cursor:pointer}.schema-viewer__keys-wrapper{left:0;position:sticky;width:100%;z-index:1}.schema-viewer__keys+.schema-viewer__keys{margin-left:var(--g-spacing-8)}.schema-viewer__keys_summary+.schema-viewer__keys_summary{margin-left:0}.schema-viewer__popup-content{padding:var(--g-spacing-2) var(--g-spacing-4)}.schema-viewer__popup-item{padding-bottom:var(--g-spacing-2)}.schema-viewer__popup-item:last-child{padding-bottom:0}.schema-viewer__more-badge{margin-left:var(--g-spacing-1)}.schema-viewer__key-icon{margin-left:var(--g-spacing-half);position:absolute;top:3.5px;vertical-align:initial}.schema-viewer__id-wrapper{display:inline-block;padding-right:var(--g-spacing-1);position:relative}.ydb-diagnostics-configs__icon-touched{color:var(--g-color-text-secondary);cursor:default!important;line-height:1}.speed-multimeter{display:flex;width:100%}.speed-multimeter__content{display:flex;flex-direction:row;flex-grow:1;justify-content:flex-end;line-height:22px}.speed-multimeter__displayed-value{display:flex;flex-direction:row;justify-content:flex-end;margin-right:10px}.speed-multimeter__bars{align-items:flex-start;display:flex;flex-direction:column;margin-right:5px;overflow:hidden;width:32px}.speed-multimeter__bar-container{height:6px;width:100%}.speed-multimeter__bar-container_highlighted{background:var(--g-color-line-generic)}.speed-multimeter__bar{height:100%;min-width:2px}.speed-multimeter__bar_color_light{background:var(--g-color-base-info-medium)}.speed-multimeter__bar_color_dark{background:var(--g-color-base-info-heavy)}.speed-multimeter__bar-container+.speed-multimeter__bar-container{margin-top:2px}.speed-multimeter__popover-container{align-items:center;display:flex;justify-content:center}.speed-multimeter__popover-content{padding:10px}.speed-multimeter__popover-header{display:block;font-size:18px;line-height:24px;margin-bottom:7px}.speed-multimeter__popover-row{display:block;font-size:13px;line-height:18px}.speed-multimeter__popover-row_color_primary{color:var(--g-color-text-primary)}.speed-multimeter__popover-row_color_secondary{color:var(--g-color-text-secondary)}.ydb-diagnostics-consumers-topic-stats{font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height)}.ydb-diagnostics-consumers-topic-stats__wrapper{border-left:1px solid var(--g-color-line-generic);display:flex;flex-direction:row;padding-left:16px}.ydb-diagnostics-consumers-topic-stats__item{display:flex;flex-direction:column;margin-right:20px}.ydb-diagnostics-consumers-topic-stats__label{color:var(--g-color-text-secondary);margin-bottom:4px}.ydb-diagnostics-consumers-topic-stats__value{align-items:center;display:flex;height:30px;justify-content:flex-start}.ydb-lag-popover-content__text{margin-bottom:10px}.ydb-lag-popover-content_type_read{max-width:280px}.ydb-lag-popover-content_type_write{max-width:220px}.ydb-diagnostics-consumers-columns-header__lags{white-space:nowrap}.ydb-diagnostics-consumers-columns__lags-header{text-align:center}.ydb-diagnostics-consumers{display:flex;flex-grow:1;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto}.ydb-diagnostics-consumers__controls{align-items:center;display:flex;gap:12px;padding:16px 0 18px}.ydb-diagnostics-consumers__search{width:238px}.ydb-diagnostics-consumers__table-wrapper{display:flex;flex:1 1 auto;flex-direction:column;overflow:auto}.ydb-diagnostics-consumers__table-content{height:100%;overflow:auto}.ydb-diagnostics-consumers__table .data-table__head-row:first-child .data-table__th:first-child,.ydb-diagnostics-consumers__table .data-table__td:first-child{background-color:var(--g-color-base-background);border-right:1px solid var(--g-color-line-generic);left:0;position:sticky;z-index:2000}.ydb-diagnostics-consumers__table .data-table__row:hover .data-table__td:first-child{background-color:var(--ydb-data-table-color-hover)!important}.ydb-diagnostics-consumers__table .data-table__head-row:first-child .data-table__th:nth-child(0),.ydb-diagnostics-consumers__table .data-table__td:nth-child(0){border-right:unset;box-shadow:unset}.ydb-diagnostics-consumers__table .data-table__head-row:first-child .data-table__th:first-child,.ydb-diagnostics-consumers__table .data-table__td:first-child{box-shadow:unset}.ydb-json-viewer{--data-table-row-height:20px;--toolbar-background-color:var(--g-color-base-background)}.ydb-json-viewer__toolbar{background-color:var(--toolbar-background-color);left:0;padding-bottom:var(--g-spacing-2);position:sticky;top:0;z-index:2}.ydb-json-viewer__content{font-family:var(--g-font-family-monospace)}.ydb-json-viewer__row{height:1em}.ydb-json-viewer__cell{position:relative}.ydb-json-viewer__cell,.ydb-json-viewer__cell *{white-space:nowrap!important}.ydb-json-viewer__collapsed{margin-left:-3ex;margin-top:-2px;position:absolute}.ydb-json-viewer__match-counter{text-wrap:nowrap;align-content:center;color:var(--g-color-text-secondary)}.ydb-json-viewer__key{color:var(--g-color-text-misc)}.ydb-json-viewer__value_type_string{color:var(--color-unipika-string)}.ydb-json-viewer__value_type_boolean{color:var(--color-unipika-bool)}.ydb-json-viewer__value_type_null{color:var(--color-unipika-null)}.ydb-json-viewer__value_type_int64{color:var(--color-unipika-int)}.ydb-json-viewer__value_type_double{color:var(--color-unipika-float)}.ydb-json-viewer__filter{width:300px}.ydb-json-viewer__filtered_highlighted{background-color:var(--g-color-base-generic-medium)}.ydb-json-viewer__filtered_clickable{color:var(--g-color-text-info);cursor:pointer}.ydb-json-viewer__match-btn{margin-left:-1px}.ydb-json-viewer__full-value{font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);margin:var(--g-spacing-3) 0;max-height:90vh;max-width:90vw;overflow:hidden auto;word-break:break-all}.ydb-json-viewer__extra-tools{margin-left:1ex}.ydb-json-viewer .data-table__head{display:none}.ydb-json-viewer .data-table__td{overflow:visible;padding:0}.ydb-describe__message-container{padding:15px 0}.ydb-describe__result{display:flex;flex:0 0 auto;padding:0 20px 20px 0;position:relative}.ydb-external-data-source-info__location,.ydb-external-table-info__location{max-width:var(--tenant-object-info-max-value-width)}.ydb-syntax-highlighter{height:100%;position:relative;z-index:0}.ydb-syntax-highlighter__sticky-container{background-color:var(--g-color-base-background);left:0;position:sticky;top:52px;top:0;z-index:1}.ydb-syntax-highlighter__copy{position:absolute;right:14px;top:13px}.ydb-definition-list{display:flex;flex:1 1 auto;flex-direction:column}.ydb-definition-list__title{font-size:var(--g-text-body-2-font-size);font-weight:600;line-height:var(--g-text-body-2-line-height);margin:15px 0 10px}.ydb-definition-list__properties-list{max-width:calc(100% - 40px)}.ydb-async-replication-paths__title,.ydb-overview-topic-stats__title{font-size:var(--g-text-body-2-font-size);font-weight:600;line-height:var(--g-text-body-2-line-height);margin:15px 0 10px}.ydb-overview-topic-stats .ydb-loader{margin-top:50px}.ydb-overview-topic-stats .info-viewer__row{align-items:flex-start}.ydb-overview-topic-stats .speed-multimeter{margin-top:-5px}.ydb-overview-topic-stats .speed-multimeter__content{justify-content:flex-start}.ydb-overview-topic-stats__info .info-viewer__label-text_multiline{max-width:150px}.ydb-overview-topic-stats__bytes-written{margin-top:7px;padding-left:20px}.ydb-overview-topic-stats__bytes-written .info-viewer__label{min-width:180px}.ydb-diagnostics-table-info__title{font-size:var(--g-text-body-2-font-size);font-weight:600;line-height:var(--g-text-body-2-line-height);margin:15px 0 10px}.ydb-diagnostics-table-info__row{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.ydb-diagnostics-table-info__col{align-items:flex-start;display:flex;flex-direction:column;justify-content:flex-start}.ydb-diagnostics-table-info__col:not(:last-child){margin-right:50px}.ydb-diagnostics-table-info__info-block{margin-bottom:20px}.ydb-diagnostics-table-info__info-block .info-viewer__items{grid-template-columns:minmax(max-content,280px)}.ydb-metric-chart{border:1px solid var(--g-color-line-generic);border-radius:8px;display:flex;flex-direction:column;padding:16px 16px 8px}.ydb-metric-chart__title{margin-bottom:10px}.ydb-metric-chart__chart{display:flex;height:100%;overflow:hidden;position:relative;width:100%}.ydb-metric-chart__error{left:50%;position:absolute;text-align:center;top:10%;transform:translateX(-50%);z-index:1}.ydb-timeframe-selector{display:flex;gap:2px}.ydb-tenant-dashboard{margin-bottom:var(--diagnostics-section-margin);width:var(--diagnostics-section-table-width)}.ydb-tenant-dashboard__controls{margin-bottom:10px}.ydb-tenant-dashboard__charts{display:flex;flex-flow:row wrap;gap:16px}.issue-tree-item{align-items:center;cursor:pointer;display:flex;height:40px;justify-content:space-between}.issue-tree-item__field{display:flex;overflow:hidden}.issue-tree-item__field_status{display:flex;white-space:nowrap}.issue-tree-item__field_additional{color:var(--g-color-text-link);cursor:pointer;width:max-content}.issue-tree-item__field_additional:hover{color:var(--g-color-text-link-hover)}.issue-tree-item__field_message{flex-shrink:0;overflow:hidden;white-space:normal;width:300px}.issue-tree-item__field-tooltip.issue-tree-item__field-tooltip{max-width:500px;min-width:500px}.issue-tree-item__field-label{color:var(--g-color-text-secondary)}.issue-tree{display:flex}.issue-tree__block{width:100%}.issue-tree__checkbox{margin:5px 0 10px}.issue-tree__info-panel{background:var(--g-color-base-generic);border-radius:4px;height:100%;margin:11px 0;padding:8px 20px;position:sticky}.issue-tree__info-panel .ydb-json-viewer{--toolbar-background-color:var(--g-color-base-simple-hover-solid)}.issue-tree .ydb-tree-view__item{height:40px}.issue-tree .ydb-tree-view .tree-view_arrow{height:40px;width:40px}.issue-tree .ydb-tree-view .ydb-tree-view__item{margin-left:calc(24px*var(--ydb-tree-view-level))!important;padding-left:0!important}.issue-tree .ydb-tree-view .issue-tree__info-panel{margin-left:calc(24px*var(--ydb-tree-view-level))}.healthcheck__details{width:872px}.healthcheck__details-content-wrapper{overflow-x:hidden}.healthcheck__preview{display:flex;flex-direction:column;height:100%}.healthcheck__preview-title{color:var(--g-color-text-link);font-size:var(--g-text-subheader-3-font-size);font-weight:600;line-height:var(--g-text-subheader-3-line-height)}.healthcheck__preview-content{line-height:24px;margin:auto}.healthcheck__preview-status-icon{height:64px;width:64px}.healthcheck__preview-title-wrapper{align-items:center;display:flex;gap:8px;margin-bottom:4px}.healthcheck__preview-issue{align-items:center;display:flex;flex-direction:column;gap:4px;position:relative;top:-8px}.healthcheck__preview-issue_good{color:var(--g-color-text-positive)}.healthcheck__preview-issue_good .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-positive-light)}.healthcheck__preview-issue_degraded{color:var(--g-color-text-info)}.healthcheck__preview-issue_degraded .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-info-light)}.healthcheck__preview-issue_emergency{color:var(--g-color-text-danger)}.healthcheck__preview-issue_emergency .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-danger-light)}.healthcheck__preview-issue_unspecified{color:var(--g-color-text-misc)}.healthcheck__preview-issue_unspecified .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-misc-light)}.healthcheck__preview-issue_maintenance_required{color:var(--g-color-text-warning-heavy)}.healthcheck__preview-issue_maintenance_required .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-warning-light)}.healthcheck__self-check-status-indicator{text-wrap:nowrap;border-radius:4px;display:inline-block;font-size:13px;line-height:24px;padding:0 8px}.healthcheck__icon-warn{color:var(--g-color-text-warning)}.healthcheck__icon-wrapper{display:flex}.ydb-diagnostic-card{background-color:#0000;border:1px solid var(--g-color-line-generic);border-radius:8px;flex-shrink:0;padding:16px 16px 28px}.ydb-diagnostic-card_active{background-color:var(--g-color-base-selection);border-color:var(--g-color-base-info-medium)}.ydb-diagnostic-card_interactive:hover{box-shadow:0 1px 5px var(--g-color-sfx-shadow);cursor:pointer}.ydb-diagnostic-card_size_m{min-width:206px;width:206px}.ydb-diagnostic-card_size_l{min-width:289px;width:289px}.ydb-diagnostic-card_size_s{min-width:134px;width:134px}.ydb-metrics-card{min-height:252px}.ydb-metrics-card__header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:10px}.ydb-metrics-card__label{color:var(--g-color-text-link);font-size:var(--g-text-subheader-3-font-size);font-weight:600;line-height:var(--g-text-subheader-3-line-height)}.ydb-metrics-card__content{color:var(--g-color-text-secondary);display:flex;flex-direction:column;gap:10px}.ydb-metrics-card__metric-title{height:var(--g-text-body-2-line-height)}.ydb-metrics-card_active .ydb-metrics-card__content{color:var(--g-color-text-complementary)}.metrics-cards{display:flex;gap:16px;margin-bottom:32px}.metrics-cards__tab{color:inherit;text-decoration:none}.confirmation-dialog__caption,.confirmation-dialog__message{white-space:pre-wrap}.ydb-save-query__dialog-row{align-items:flex-start;display:flex}.ydb-save-query__dialog-row+.ydb-save-query__dialog-row{margin-top:var(--g-text-body-1-line-height)}.ydb-save-query__field-title{font-weight:500;line-height:28px;margin-right:12px;white-space:nowrap}.ydb-save-query__field-title.required:after{color:var(--g-color-text-danger);content:"*"}.ydb-save-query__control-wrapper{display:flex;flex-grow:1;min-height:48px}.kv-truncated-query{max-width:100%;vertical-align:top;white-space:pre;word-break:break-word}.kv-truncated-query__message{white-space:pre-wrap}.kv-truncated-query__message_color_secondary{color:var(--g-color-text-secondary)}.kv-top-queries{display:flex;flex-direction:column;height:100%}.kv-top-queries .data-table__box .data-table__table-wrapper{padding-bottom:20px}.kv-top-queries .data-table__th{box-shadow:inset 0 -1px 0 0 var(--g-tabs-color-divider)}.kv-top-queries__search{width:238px}.kv-top-queries__row{cursor:pointer}.kv-top-queries__query{overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:pre-wrap;word-break:break-word}.kv-top-queries__user-sid{max-width:200px;overflow:hidden;text-overflow:ellipsis}.tenant-overview{height:100%;overflow:auto;padding-bottom:20px}.tenant-overview__loader{display:flex;justify-content:center}.tenant-overview__tenant-name-wrapper{align-items:center;display:flex;overflow:hidden}.tenant-overview__top{line-height:24px;margin-bottom:10px}.tenant-overview__top-label{font-weight:600;gap:10px;line-height:24px;margin-bottom:var(--diagnostics-section-title-margin)}.tenant-overview__info{left:0;position:sticky;width:max-content}.tenant-overview__title{font-size:var(--g-text-body-2-font-size);font-weight:700;line-height:var(--g-text-body-2-line-height);margin-bottom:10px}.tenant-overview__table:not(:last-child){margin-bottom:var(--diagnostics-section-margin)}.tenant-overview__top-queries-row{cursor:pointer}.tenant-overview__storage-info{margin-bottom:36px}.tenant-overview__memory-info{margin-bottom:36px;width:300px}.kv-detailed-overview{display:flex;flex-direction:column;gap:20px;height:100%;width:100%}.kv-detailed-overview__section{display:flex;flex-basis:calc(50% - 10px);flex-direction:column;flex-grow:1;flex-shrink:0;min-width:300px}.kv-detailed-overview__modal .g-modal__content{position:relative}.kv-detailed-overview__close-modal-button{position:absolute;right:13px;top:23px}.ydb-hot-keys__primary-key-column{align-items:center;display:flex;gap:5px}.ydb-hot-keys__help-card{left:0;margin-bottom:20px;padding:20px 40px 20px 20px;position:sticky}.ydb-hot-keys__help-card__close-button{position:absolute;right:5px;top:5px}.node-network{border:1px solid #0000;border-radius:4px;box-sizing:border-box;color:var(--g-color-text-complementary);cursor:pointer;display:inline-block;font-size:12px;height:14px;line-height:14px;margin-bottom:5px;margin-right:5px;padding:0 5px;text-align:center;text-transform:uppercase;width:14px}.node-network_id{height:14px;width:42px}.node-network_blur{opacity:.25}.node-network_grey{background:var(--ydb-color-status-grey)}.node-network_black{background-color:var(--ydb-color-status-black);color:var(--g-color-text-light-primary)}.node-network_green{background-color:var(--ydb-color-status-green)}.node-network_yellow{background-color:var(--ydb-color-status-yellow)}.node-network_red{background-color:var(--ydb-color-status-red)}.node-network:hover{border:1px solid var(--g-color-text-primary)}.network{flex-direction:column;font-size:var(--g-text-body-2-font-size);justify-content:space-between;line-height:var(--g-text-body-2-line-height);max-width:1305px}.network,.network__nodes-row{display:flex;flex-grow:1;height:100%;overflow:auto}.network__nodes-row{align-items:flex-start;flex-direction:row}.network__inner{display:flex;flex:1 1 auto;flex-direction:column;overflow:auto}.network__right{height:100%;padding-left:20px;width:100%}.network__left{border-right:1px solid var(--g-color-base-generic-accent);height:100%}.network__placeholder{align-items:center;display:flex;flex-direction:column;flex-grow:1;height:100%;justify-content:center;width:100%}.network__placeholder-text{margin-top:15px}.network__placeholder-img{color:#0000}.network__nodes{display:flex;flex-wrap:wrap}.network__nodes-container{min-width:325px}.network__nodes-container_right{margin-right:60px}.network__nodes-title{border-bottom:1px solid var(--g-color-base-generic-accent);color:var(--g-color-text-secondary);font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);margin:0 0 15px}.network__link{color:var(--g-color-base-brand);text-decoration:none}.network__title{font-size:var(--g-text-body-1-font-size);font-weight:500;line-height:var(--g-text-body-1-line-height);margin:20px 0}.network__checkbox-wrapper{align-items:center;display:flex}.network__checkbox-wrapper label{white-space:nowrap}.network__label{margin-bottom:16px}.network__controls{display:flex;gap:12px;margin:0 16px 16px 0}.network__controls-wrapper{display:flex;flex:1 1 auto;flex-direction:row;flex-direction:column}.network__select{margin:0 15px;max-width:115px}.network__rack-column{align-items:center;background-color:#00000012;border-radius:4px;display:flex;flex-direction:column;margin-bottom:5px;margin-right:5px;padding:2px}.network__rack-column .node-network{margin-right:0}.ydb-diagnostics-partitions-columns-header__multiline{white-space:normal}.ydb-diagnostics-partitions-columns-header__read-session{white-space:normal;width:80px}.ydb-diagnostics-partitions-columns-header__lags{white-space:nowrap}.ydb-diagnostics-partitions-columns-header__messages{white-space:normal;width:90px}.ydb-diagnostics-partitions-columns-header__messages-popover-content{max-width:200px}.ydb-diagnostics-partitions-columns__lags-header{text-align:center}.ydb-diagnostics-partitions{display:flex;flex-grow:1;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto}.ydb-diagnostics-partitions__controls{align-items:center;display:flex;gap:12px;padding:16px 0 18px}.ydb-diagnostics-partitions__consumer-select{width:220px}.ydb-diagnostics-partitions__select-option_empty{color:var(--g-color-text-hint)}.ydb-diagnostics-partitions__search{width:238px}.ydb-diagnostics-partitions__search_partition{width:100px}.ydb-diagnostics-partitions__search_general{width:280px}.ydb-diagnostics-partitions__table-wrapper{display:flex;flex:1 1 auto;flex-direction:column;overflow:auto}.ydb-diagnostics-partitions__table-content{height:100%;overflow:auto}.ydb-diagnostics-partitions__table .data-table__head-row:first-child .data-table__th:first-child,.ydb-diagnostics-partitions__table .data-table__td:first-child{background-color:var(--g-color-base-background);border-right:1px solid var(--g-color-line-generic);left:0;position:sticky;z-index:2000}.ydb-diagnostics-partitions__table .data-table__row:hover .data-table__td:first-child{background-color:var(--ydb-data-table-color-hover)!important}.ydb-diagnostics-partitions__table .data-table__head-row:first-child .data-table__th:nth-child(0),.ydb-diagnostics-partitions__table .data-table__td:nth-child(0){border-right:unset;box-shadow:unset}.ydb-diagnostics-partitions__table .data-table__head-row:first-child .data-table__th:first-child,.ydb-diagnostics-partitions__table .data-table__td:first-child{box-shadow:unset}.date-range__range-input_s{width:200px}.date-range__range-input_m{width:300px}.date-range__range-input_l{width:350px}.date-range__range-input input{cursor:pointer}.top-shards__hint{left:0;position:sticky;width:max-content}.kv-tenant-diagnostics{display:flex;flex-direction:column;height:100%;overflow:hidden}.kv-tenant-diagnostics__header-wrapper{background-color:var(--g-color-base-background);padding:0 20px 16px}.kv-tenant-diagnostics__tabs{--g-tabs-border-width:0;align-items:center;box-shadow:inset 0 -1px 0 0 var(--g-color-line-generic);display:flex;justify-content:space-between}.kv-tenant-diagnostics__tabs .g-tabs_direction_horizontal{box-shadow:unset}.kv-tenant-diagnostics__tab{margin-right:40px;text-decoration:none}.kv-tenant-diagnostics__tab:first-letter{text-transform:uppercase}.kv-tenant-diagnostics__page-wrapper{flex-grow:1;overflow:auto;padding:0 20px;width:100%}.kv-tenant-diagnostics__page-wrapper .ydb-table-with-controls-layout__controls{height:46px;padding-top:0}.kv-tenant-diagnostics__page-wrapper .ydb-table-with-controls-layout .data-table__sticky_moving,.kv-tenant-diagnostics__page-wrapper .ydb-table-with-controls-layout .ydb-paginated-table__head{top:46px!important}.ydb-queries-history{display:flex;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto;padding:0 20px}.ydb-queries-history .ydb-table-with-controls-layout__controls{height:46px;padding-top:0}.ydb-queries-history.ydb-table-with-controls-layout .data-table__sticky_moving{top:46px!important}.ydb-queries-history__search{width:238px}.ydb-queries-history__table-row{cursor:pointer}.ydb-queries-history__query{flex-grow:1;overflow:hidden;text-overflow:ellipsis;white-space:pre}.kv-pane-visibility-button_hidden{display:none}.kv-pane-visibility-button_bottom{transform:rotate(180deg)}.kv-pane-visibility-button_bottom.rotate{transform:rotate(0)}.kv-pane-visibility-button_left{transform:rotate(-90deg)}.kv-pane-visibility-button_left.rotate{transform:rotate(90deg)}.kv-pane-visibility-button_top.rotate{transform:rotate(180deg)}.ydb-fullscreen{flex-grow:1;overflow:hidden}.ydb-fullscreen_fullscreen{background-color:var(--g-color-base-background);inset:0;position:absolute;z-index:10}.ydb-fullscreen__close-button{display:none;position:fixed;right:20px;top:8px;z-index:11}.ydb-fullscreen_fullscreen .ydb-fullscreen__close-button{display:block}.ydb-fullscreen__content{display:flex;height:100%;overflow:auto;width:100%}.ydb-query-result-table__cell{cursor:pointer;display:inline-block;max-width:600px;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:100%}.ydb-query-result-table__message{padding:15px 10px}.ydb-query-result-table__table-wrapper{height:0}.kv-preview{display:flex;flex:1 1 auto;flex-direction:column;height:100%}.kv-preview .data-table__box .data-table__table-wrapper{padding-bottom:20px}.kv-preview .data-table__th{box-shadow:inset 0 -1px 0 0 var(--g-tabs-color-divider)}.kv-preview__header{align-items:center;background-color:var(--g-color-base-background);border-bottom:1px solid var(--g-color-line-generic);display:flex;flex-shrink:0;height:53px;justify-content:space-between;padding:0 20px;position:sticky;top:0}.kv-preview__title{display:flex;gap:var(--g-spacing-1)}.kv-preview__table-name{color:var(--g-color-text-complementary);margin-left:var(--g-spacing-1)}.kv-preview__controls-left{display:flex;gap:var(--g-spacing-1)}.kv-preview__message-container{padding:15px 20px}.kv-preview__loader-container{align-items:center;display:flex;height:100%;justify-content:center}.kv-preview__result{overflow:auto;padding-left:10px;width:100%}.ydb-query-settings-description__message{display:flex;flex-wrap:wrap;white-space:pre}.ydb-query-editor-button__explain-button,.ydb-query-editor-button__run-button,.ydb-query-editor-button__stop-button{width:92px}.ydb-query-editor-button__stop-button_error{animation:errorAnimation .5s linear}@keyframes errorAnimation{41%,8%{transform:translateX(-2px)}25%,58%{transform:translateX(2px)}75%{transform:translateX(-1px)}92%{transform:translateX(1px)}0%,to{transform:translateX(0)}}.ydb-query-editor-controls{align-items:center;display:flex;flex:0 0 60px;gap:24px;justify-content:space-between;min-height:60px}.ydb-query-editor-controls__left,.ydb-query-editor-controls__right{display:flex;gap:12px}.ydb-query-editor-controls__mode-selector__button{margin-left:2px;width:241px}.ydb-query-editor-controls__mode-selector__button-content{align-items:center;display:flex;justify-content:space-between;width:215px}.ydb-query-editor-controls__mode-selector__popup{width:241px}.ydb-query-editor-controls__item-with-popover{align-items:center;display:flex;height:24px;line-height:normal}.ydb-query-editor-controls__popover{max-width:420px;white-space:pre-wrap}.kv-query-execution-status{align-items:center;display:flex;gap:4px}.ydb-query-settings-banner,.ydb-query-stopped-banner{margin-left:var(--g-spacing-4);margin-right:var(--g-spacing-4);margin-top:var(--g-spacing-4)}.ydb-query-ast{height:100%;overflow:hidden;white-space:pre-wrap;width:100%}.ydb-query-result-stub-message{padding:15px 20px}.ydb-query-explain-graph__canvas-container{height:100%;overflow-y:auto;width:100%}.query-info-dropdown__menu-item{align-items:start}.query-info-dropdown__menu-item-content{display:flex;flex-direction:column;padding:var(--g-spacing-1) 0}.query-info-dropdown__icon{margin-right:var(--g-spacing-2);margin-top:var(--g-spacing-2)}.ydb-query-json-viewer{height:100%;padding:15px 0;width:100%}.ydb-query-json-viewer__tree{height:100%;overflow-y:auto;padding:0 10px;width:100%}.ydb-query-result-error__message{padding-left:var(--g-spacing-4);padding-top:var(--g-spacing-4)}.ydb-query-result-sets-viewer__tabs{margin-bottom:var(--g-spacing-1);padding-left:var(--g-spacing-4);padding-top:var(--g-spacing-1)}.ydb-query-result-sets-viewer__title{padding-bottom:var(--g-spacing-4);padding-left:var(--g-spacing-4);padding-top:var(--g-spacing-4)}.ydb-query-result-sets-viewer__result-wrapper{display:flex;flex-direction:column;width:100%}.ydb-query-result-sets-viewer__result{display:flex;flex-direction:column;flex-grow:1;overflow:auto;padding-left:10px}.ydb-query-result-sets-viewer__result .data-table__box .data-table__table-wrapper{padding-bottom:20px}.ydb-query-result-sets-viewer__result .data-table__th{box-shadow:inset 0 -1px 0 0 var(--g-tabs-color-divider)}.ydb-query-result-sets-viewer__result .data-table__table-wrapper{padding-bottom:0}.ydb-table{--ydb-table-cell-height:40px}.ydb-table__table-header-content{align-items:center;border-bottom:1px solid var(--g-color-line-generic);display:inline-flex;height:100%;padding:var(--g-spacing-1) var(--g-spacing-2);width:100%}.ydb-table__table{border-collapse:collapse;border-spacing:0;table-layout:fixed}.ydb-table__table tr:hover{background-color:var(--g-color-base-simple-hover)!important}.ydb-table__table tr:nth-of-type(odd){background-color:var(--g-color-base-generic-ultralight)}.ydb-table__table_width_max{width:100%}.ydb-table__table-header-cell{background-color:var(--g-color-base-background);font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-2-font-size);font-weight:var(--g-text-subheader-font-weight);height:var(--ydb-table-cell-height)!important;line-height:var(--g-text-subheader-2-line-height);padding:0;text-align:left;vertical-align:middle}:is(.ydb-table__table-header-cell_align_right) .ydb-table__table-header-content{justify-content:flex-end;text-align:right}.ydb-table__table-cell{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);height:var(--ydb-table-cell-height)!important;line-height:var(--g-text-body-2-line-height);padding:0}.ydb-table__table-cell_align_right{text-align:right!important}.ydb-table__table-cell_vertical-align_top{vertical-align:top!important}.ydb-query-simplified-plan{height:100%;overflow:auto;padding:0 15px 15px;width:100%}.ydb-query-simplified-plan__name{align-items:center;display:flex;gap:var(--g-spacing-1);max-width:100%}.ydb-query-simplified-plan__metrics-cell{padding:var(--g-spacing-1) var(--g-spacing-2)}.ydb-query-simplified-plan__operation-params{color:var(--g-color-text-secondary)}.ydb-query-simplified-plan__operation-name{font-weight:500;height:100%;max-width:100%;position:relative}.ydb-query-simplified-plan__divider{bottom:0;box-shadow:1px 0 0 0 var(--g-color-line-generic) inset;height:100%;position:absolute;width:12px}.ydb-query-simplified-plan__divider_last{border-radius:0 0 0 1px;bottom:unset;box-shadow:1px -1px 0 0 var(--g-color-line-generic) inset;height:14px;top:0;width:12px}.ydb-query-simplified-plan__divider_horizontal{bottom:unset;box-shadow:0 -1px 0 0 var(--g-color-line-generic) inset;height:14px;top:0;width:12px}.ydb-query-simplified-plan__divider_first{height:calc(100% - 30px)}.ydb-query-simplified-plan__operation-content{height:100%;max-width:100%;padding:var(--g-spacing-1) 0;word-break:break-word}.ydb-query-simplified-plan__operation-name-content{display:flex;flex-grow:1}.ydb-query-result__controls{align-items:center;background-color:var(--g-color-base-background);border-bottom:1px solid var(--g-color-line-generic);display:flex;height:53px;justify-content:space-between;padding:var(--g-spacing-3) var(--g-spacing-4);position:sticky;top:0;z-index:2}.ydb-query-result__controls-left{align-items:center;display:flex;gap:12px;height:100%}.ydb-query-result__controls-right{display:flex;gap:4px}.ydb-query-result__elapsed-label{margin-left:var(--g-spacing-3)}.ydb-query-settings-select__selector{width:100%}.ydb-query-settings-select__popup{max-width:320px}.ydb-query-settings-select__item-description{color:var(--g-color-text-secondary);white-space:pre-wrap}.ydb-query-settings-select__item{padding:var(--g-spacing-1) 0}.ydb-timeout-label__switch{align-items:center;height:var(--g-text-header-2-line-height);margin-right:var(--g-spacing-1)}.ydb-timeout-label__label-title,.ydb-timeout-label__switch-title{align-items:center;flex:4 1;font-weight:500;margin-right:var(--g-spacing-3);white-space:nowrap}.ydb-timeout-label__label-title{line-height:var(--g-text-header-2-line-height)}.ydb-query-settings-timeout__control-wrapper{align-items:center;display:flex;flex:6 1}.ydb-query-settings-timeout__input{width:50%}.ydb-query-settings-timeout__postfix{color:var(--g-color-text-secondary);margin-right:var(--g-spacing-2)}.ydb-query-settings-dialog__dialog-row+.ydb-query-settings-dialog__dialog-row{margin-top:var(--g-text-body-1-line-height)}.ydb-query-settings-dialog__field-title{flex:4 1;font-weight:500;line-height:var(--g-text-header-2-line-height);margin-right:var(--g-spacing-3);white-space:nowrap}.ydb-query-settings-dialog .g-dialog-footer__bts-wrapper{width:100%}.ydb-query-settings-dialog__dialog-body{padding-top:var(--g-spacing-6)}.ydb-query-settings-dialog__control-wrapper{display:flex;flex:6 1}.ydb-query-settings-dialog__limit-rows{margin-right:var(--g-spacing-2);width:50%}.ydb-query-settings-dialog__postfix{color:var(--g-color-text-secondary);margin-right:var(--g-spacing-2)}.ydb-query-settings-dialog__buttons-container{display:flex;justify-content:space-between;width:100%}.ydb-query-settings-dialog__main-buttons{display:flex;gap:10px}.query-editor{display:flex;flex:1 1 auto;flex-direction:column;height:100%;position:relative}.query-editor .data-table__box .data-table__table-wrapper{padding-bottom:20px}.query-editor .data-table__th{box-shadow:inset 0 -1px 0 0 var(--g-tabs-color-divider)}.query-editor .data-table__box .data-table__table-wrapper{padding-bottom:0}.query-editor__monaco{border:1px solid var(--g-color-line-generic);display:flex;height:100%;position:relative;width:100%}.query-editor__monaco-wrapper{height:calc(100% - 49px);min-height:0;width:100%}.query-editor__pane-wrapper{background-color:var(--g-color-base-background);display:flex;flex-direction:column;z-index:2}.query-editor__pane-wrapper_top{border-bottom:1px solid var(--g-color-line-generic);padding:0 16px}.ydb-saved-queries{display:flex;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto;padding:0 20px}.ydb-saved-queries .ydb-table-with-controls-layout__controls{height:46px;padding-top:0}.ydb-saved-queries.ydb-table-with-controls-layout .data-table__sticky_moving{top:46px!important}.ydb-saved-queries__search{width:238px}.ydb-saved-queries__row{cursor:pointer}.ydb-saved-queries__row :hover .ydb-saved-queries__controls{display:flex}.ydb-saved-queries__query-name{overflow:hidden;text-overflow:ellipsis;white-space:pre-wrap}.ydb-saved-queries__query{align-items:center;display:flex;flex-direction:row;justify-content:space-between}.ydb-saved-queries__query-body{flex-grow:1;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:pre}.ydb-saved-queries__controls{display:none}.ydb-saved-queries__dialog-query-name{font-weight:500}.ydb-query{display:flex;flex:1 1 auto;flex-direction:column;max-height:calc(100% - 56px)}.ydb-query__tabs{padding:0 20px 16px}.ydb-query__content{height:100%;overflow:hidden}.ydb-tenant-navigation{padding:12px 16px 8px}.ydb-tenant-navigation__item{align-items:center;display:flex;gap:5px}.ydb-tenant-navigation__icon{flex-shrink:0}.ydb-tenant-navigation__text{overflow:hidden;text-overflow:ellipsis}.object-general{display:flex;flex-direction:column;flex-grow:1;height:100%;max-height:100%;width:100%}.object-general__loader{display:flex}.ydb-acl{width:100%}.ydb-acl__result{padding-bottom:var(--g-spacing-4);padding-left:var(--g-spacing-2)}.ydb-acl__result_no-title{margin-top:var(--g-spacing-3)}.ydb-acl__definition-content{align-items:flex-end;display:flex;flex-direction:column}.ydb-acl__list-title{font-weight:600;margin:var(--g-spacing-3) 0 var(--g-spacing-5)}.ydb-acl__group-label,.ydb-acl__list-title{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-2-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-2-line-height)}.ydb-schema-create-directory-dialog__label{display:flex;flex-direction:column;margin-bottom:8px}.ydb-schema-create-directory-dialog__description{color:var(--g-color-text-secondary)}.ydb-schema-create-directory-dialog__input-wrapper{min-height:48px}.ydb-object-summary{height:100%;max-height:100%;overflow:hidden;width:100%}.ydb-object-summary,.ydb-object-summary__overview-wrapper{display:flex;flex-direction:column;flex-grow:1;position:relative}.ydb-object-summary__overview-wrapper{overflow:auto;padding:0 12px 16px}.ydb-object-summary_hidden{visibility:hidden}.ydb-object-summary__actions{background-color:var(--g-color-base-background);position:absolute;right:5px;top:19px}.ydb-object-summary__button_hidden{display:none}.ydb-object-summary__tree-wrapper{display:flex;flex-direction:column}.ydb-object-summary__tree{flex:1 1 auto;height:100%;overflow-y:scroll;padding:0 12px 12px 16px}.ydb-object-summary__tree-header{padding:23px 12px 17px 20px}.ydb-object-summary__sticky-top{background-color:var(--g-color-base-background);left:0;position:sticky;top:0;z-index:5}.ydb-object-summary__tabs{padding:8px 12px 16px}.ydb-object-summary__tabs-inner{--g-tabs-border-width:0;box-shadow:inset 0 -1px 0 0 var(--g-color-line-generic)}.ydb-object-summary__tab{text-decoration:none}.ydb-object-summary__info{display:flex;flex-direction:column;overflow:hidden}.ydb-object-summary__info-controls{display:flex;gap:4px}.ydb-object-summary__info-action-button{background-color:var(--g-color-base-background)}.ydb-object-summary__info-action-button_hidden{display:none}.ydb-object-summary__rotated90{transform:rotate(-90deg)}.ydb-object-summary__rotated180{transform:rotate(180deg)}.ydb-object-summary__rotated270{transform:rotate(90deg)}.ydb-object-summary__info-header{align-items:center;border-bottom:1px solid var(--g-color-line-generic);display:flex;justify-content:space-between;padding:12px 12px 10px}.ydb-object-summary__info-title{align-items:center;display:flex;font-weight:600;overflow:hidden}.ydb-object-summary__path-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ydb-object-summary__entity-type{background-color:var(--g-color-base-generic);border-radius:3px;display:inline-block;font-weight:400;margin-right:5px;padding:3px 8px;text-transform:lowercase}.ydb-object-summary__entity-type_error{background-color:#0000;padding:3px 0}.ydb-object-summary__overview-title{font-size:var(--g-text-body-2-font-size);font-weight:600;line-height:var(--g-text-body-2-line-height);margin:15px 0 10px}.ydb-object-summary__overview-item-content{text-align:end;white-space:nowrap}.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.tenant-page{display:flex;flex:1 1 auto;flex-direction:column;font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);overflow:hidden}.tenant-page__main{flex-grow:1} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/79004.401dcbac.chunk.css b/ydb/core/viewer/monitoring/static/css/79004.401dcbac.chunk.css new file mode 100644 index 000000000000..dc9b5a253ab8 --- /dev/null +++ b/ydb/core/viewer/monitoring/static/css/79004.401dcbac.chunk.css @@ -0,0 +1 @@ +.kv-split{display:flex;height:100%;outline:none;-webkit-user-select:text;user-select:text;z-index:0}.kv-split.horizontal{flex-direction:row}.kv-split.vertical{flex-direction:column;min-height:100%;width:100%}.kv-split .gutter{background:var(--g-color-base-background);position:relative;z-index:10}.kv-split .gutter:after{background-color:var(--g-color-base-generic-ultralight);content:"";inset:0;position:absolute}.kv-split .gutter.active:after,.kv-split .gutter:hover:after{background-color:var(--g-color-line-generic-hover);transition:background-color 1s ease}.kv-split .gutter.disabled{display:none}.kv-split .gutter.gutter-vertical{cursor:row-resize;height:8px;width:100%}.kv-split .gutter.gutter-vertical:before{border-color:var(--g-color-base-generic-hover);border-style:solid;border-width:1px 0;content:"";height:4px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:16px}.kv-split .gutter.gutter-horizontal{cursor:col-resize;height:100%;width:8px}.kv-split .gutter.gutter-horizontal:before{border-color:var(--g-color-base-generic-hover);border-style:solid;border-width:0 1px;content:"";height:16px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:4px}.auto-refresh-control{align-items:center;display:flex;gap:var(--g-spacing-1)}.histogram{display:flex;flex:1 1 auto}.histogram__chart{align-items:baseline;border-bottom:1px solid var(--g-color-base-generic);border-left:1px solid var(--g-color-base-generic);display:flex;height:300px;margin-left:50px;margin-top:30px;position:relative;width:800px}.histogram__x-min{left:-3px}.histogram__x-max,.histogram__x-min{bottom:-25px;color:var(--g-color-text-secondary);position:absolute}.histogram__x-max{right:0}.histogram__y-min{bottom:-7px;left:-30px;width:20px}.histogram__y-max,.histogram__y-min{color:var(--g-color-text-secondary);position:absolute;text-align:right}.histogram__y-max{left:-60px;top:-5px;width:50px}.histogram__item{cursor:pointer;margin-right:.5%;width:1.5%}.heatmap{display:flex;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto}.heatmap__limits{align-items:center;display:flex;margin-left:20px}.heatmap__limits-block{display:flex;margin-right:10px}.heatmap__limits-title{color:var(--g-color-text-secondary);margin-right:5px}.heatmap__row{align-items:center}.heatmap__row_overall{margin:15px 20px}.heatmap__row_overall .g-progress{margin:0;width:300px}.heatmap__label{font-size:var(--g-text-body-2-font-size);font-weight:500;line-height:var(--g-text-body-2-line-height);margin-right:16px;text-transform:uppercase}.heatmap__label_overall{margin-right:15px}.heatmap__items{overflow:auto}.heatmap__canvas-container{cursor:pointer;overflow:auto}.heatmap__filters{align-items:center;display:flex;margin:0 0 10px}.heatmap__filter-control{margin-right:10px;max-width:200px;min-width:100px}.heatmap__filter-control:last-child{margin-right:0}.heatmap__histogram-checkbox,.heatmap__sort-checkbox{margin-left:10px}.heatmap__row{display:flex}.heatmap .tablet,.heatmap__row{margin-bottom:2px}.table-skeleton__wrapper{width:100%}.table-skeleton__wrapper_hidden{visibility:hidden}.table-skeleton__row{align-items:center;display:flex;height:var(--data-table-row-height)}.table-skeleton__row .g-skeleton{height:var(--g-text-body-2-line-height)}.table-skeleton__col-1{margin-right:5%;width:10%}.table-skeleton__col-2{margin-right:5%;width:7%}.table-skeleton__col-3,.table-skeleton__col-4{margin-right:5%;width:5%}.table-skeleton__col-5{width:20%}.table-skeleton__col-full{width:100%}.ydb-table-with-controls-layout{--data-table-sticky-top-offset:62px;box-sizing:border-box;display:inline-block;min-width:100%}.ydb-table-with-controls-layout__controls-wrapper{background-color:var(--g-color-base-background);box-sizing:border-box;left:0;position:sticky;top:0;width:100%;z-index:3}.ydb-table-with-controls-layout__controls{align-items:center;background-color:var(--g-color-base-background);display:flex;gap:12px;height:62px;left:0;padding:16px 0 18px;position:sticky;top:0;width:max-content;z-index:3}.ydb-table-with-controls-layout__table{position:relative;z-index:2}.ydb-table-with-controls-layout .ydb-paginated-table__head{top:var(--data-table-sticky-top-offset,62px)}.ydb-table-with-controls-layout .data-table__sticky_moving{top:var(--data-table-sticky-top-offset,62px)!important}.ydb-table-group{border:1px solid var(--g-color-line-generic);border-radius:var(--g-spacing-2);display:flex;flex-direction:column;margin-bottom:20px;width:100%}.ydb-table-group__button{background:unset;border:unset;cursor:pointer;padding:8px 0}.ydb-table-group__title-wrapper{align-items:center;display:flex;flex-direction:row;gap:var(--g-spacing-2);justify-content:flex-start;left:0;padding-left:20px;position:sticky;width:max-content}.ydb-table-group__title{display:flex;flex-direction:row;gap:var(--g-spacing-4)}.ydb-table-group__count{display:flex;flex-direction:row;gap:var(--g-spacing-3)}.ydb-table-group__content{padding:12px 0 20px 20px}.ydb-search{min-width:100px}.ydb-paginated-table{--paginated-table-cell-vertical-padding:5px;--paginated-table-cell-horizontal-padding:10px;--paginated-table-border-color:var(--g-color-base-generic-hover);--paginated-table-hover-color:var(--g-color-base-simple-hover-solid);font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);width:100%}.ydb-paginated-table__table{border-collapse:initial;border-spacing:0;max-width:100%;table-layout:fixed;width:max-content}.ydb-paginated-table__table th{padding:0}.ydb-paginated-table__row{position:relative;transform:translateZ(0);z-index:1}.ydb-paginated-table__row:hover{background:var(--paginated-table-hover-color)}.ydb-paginated-table__row_empty:hover{background-color:initial}.ydb-paginated-table__head{background-color:var(--g-color-base-background);left:0;position:sticky;top:0;z-index:2}.ydb-paginated-table__sort-icon-container{color:inherit;display:flex;justify-content:center}.ydb-paginated-table__sort-icon-container_shadow{opacity:.15}.ydb-paginated-table__sort-icon_desc{transform:rotate(180deg)}.ydb-paginated-table__head-cell-wrapper{border-bottom:1px solid var(--paginated-table-border-color);display:table-cell;overflow-x:hidden;position:relative}.ydb-paginated-table__head-cell{align-items:center;display:flex;flex-direction:row;max-width:100%;padding:var(--paginated-table-cell-vertical-padding) var(--paginated-table-cell-horizontal-padding);width:100%}.ydb-paginated-table__head-cell_align_left{justify-content:left}.ydb-paginated-table__head-cell_align_center{justify-content:center}.ydb-paginated-table__head-cell_align_right{justify-content:right}.ydb-paginated-table__head-cell{cursor:default;font-weight:700;gap:8px}.ydb-paginated-table__head-cell_sortable{cursor:pointer}.ydb-paginated-table__head-cell_sortable.ydb-paginated-table__head-cell_align_right{flex-direction:row-reverse}.ydb-paginated-table__head-cell-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:min-content}.ydb-paginated-table__row-cell{border-bottom:1px solid var(--paginated-table-border-color);display:table-cell;max-width:100%;overflow-x:hidden;padding:var(--paginated-table-cell-vertical-padding) var(--paginated-table-cell-horizontal-padding);text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:100%}.ydb-paginated-table__row-cell_align_left{text-align:left}.ydb-paginated-table__row-cell_align_center{text-align:center}.ydb-paginated-table__row-cell_align_right{text-align:right}.ydb-paginated-table__resize-handler{background-color:var(--g-color-base-generic);cursor:col-resize;height:100%;position:absolute;right:0;top:0;visibility:hidden;width:6px}.ydb-paginated-table__head-cell-wrapper:hover>.ydb-paginated-table__resize-handler,.ydb-paginated-table__resize-handler_resizing{visibility:visible}.ydb-paginated-table__resizeable-table-container{padding-right:20px;width:max-content}.ydb-paginated-table__row-skeleton:after{animation:none!important}.hover-popup{padding:var(--g-spacing-3)}.progress-viewer{align-items:center;background:var(--g-color-base-generic);border-radius:2px;color:var(--g-color-text-complementary);display:flex;font-size:var(--g-text-body-2-font-size);height:23px;justify-content:center;min-width:150px;overflow:hidden;padding:0 4px;position:relative;white-space:nowrap;z-index:0}.progress-viewer_theme_dark{color:var(--g-color-text-light-primary)}.progress-viewer_theme_dark .progress-viewer__line{opacity:.75}.progress-viewer_status_good{background-color:var(--g-color-base-positive-light)}.progress-viewer_status_good .progress-viewer__line{background-color:var(--ydb-color-status-green)}.progress-viewer_status_warning{background-color:var(--g-color-base-yellow-light)}.progress-viewer_status_warning .progress-viewer__line{background-color:var(--ydb-color-status-yellow)}.progress-viewer_status_danger{background-color:var(--g-color-base-danger-light)}.progress-viewer_status_danger .progress-viewer__line{background-color:var(--ydb-color-status-red)}.progress-viewer__line{height:100%;left:0;position:absolute;top:0}.progress-viewer__text{position:relative;z-index:1}.progress-viewer_size_xs{font-size:var(--g-text-body-2-font-size);height:20px;line-height:var(--g-text-body-2-line-height)}.progress-viewer_size_s{font-size:var(--g-text-body-1-font-size);height:28px;line-height:28px}.progress-viewer_size_m{font-size:var(--g-text-body-2-font-size);height:32px;line-height:32px}.progress-viewer_size_ns{font-size:13px;height:24px;line-height:var(--g-text-subheader-3-line-height)}.progress-viewer_size_n{font-size:var(--g-text-body-1-font-size);height:36px;line-height:36px}.progress-viewer_size_l{font-size:var(--g-text-subheader-3-font-size);height:38px;line-height:38px}.progress-viewer_size_head{font-size:var(--g-text-body-1-font-size);line-height:36px}.memory-viewer{min-width:150px;padding:0 var(--g-spacing-1);position:relative;z-index:0}.memory-viewer__progress-container{background:var(--g-color-base-generic);border-radius:2px;height:20px;overflow:hidden;position:relative}.memory-viewer__container{display:flex;padding:2px 0}.memory-viewer__legend{border-radius:2px;bottom:2px;height:20px;position:absolute;width:20px}.memory-viewer__legend_type_AllocatorCachesMemory{background-color:var(--g-color-base-utility-medium-hover)}.memory-viewer__legend_type_SharedCacheConsumption{background-color:var(--g-color-base-info-medium-hover)}.memory-viewer__legend_type_MemTableConsumption{background-color:var(--g-color-base-warning-medium-hover)}.memory-viewer__legend_type_QueryExecutionConsumption{background-color:var(--g-color-base-positive-medium-hover)}.memory-viewer__legend_type_Other{background-color:var(--g-color-base-generic-medium-hover)}.memory-viewer__segment{height:100%;position:absolute}.memory-viewer__segment_type_AllocatorCachesMemory{background-color:var(--g-color-base-utility-medium-hover)}.memory-viewer__segment_type_SharedCacheConsumption{background-color:var(--g-color-base-info-medium-hover)}.memory-viewer__segment_type_MemTableConsumption{background-color:var(--g-color-base-warning-medium-hover)}.memory-viewer__segment_type_QueryExecutionConsumption{background-color:var(--g-color-base-positive-medium-hover)}.memory-viewer__segment_type_Other{background-color:var(--g-color-base-generic-medium-hover)}.memory-viewer__name{padding-left:28px}.memory-viewer_theme_dark{color:var(--g-color-text-light-primary)}.memory-viewer_theme_dark .memory-viewer__segment{opacity:.75}.memory-viewer_status_good .memory-viewer__progress-container{background-color:var(--g-color-base-positive-light)}.memory-viewer_status_warning .memory-viewer__progress-container{background-color:var(--g-color-base-yellow-light)}.memory-viewer_status_danger .memory-viewer__progress-container{background-color:var(--g-color-base-danger-light)}.memory-viewer__text{align-items:center;display:flex;justify-content:center}.ydb-pool-bar{border:1px solid;border-radius:1px;cursor:pointer;height:20px;margin-right:2px;position:relative;width:6px}.ydb-pool-bar__popup-content{padding:10px;width:170px}.ydb-pool-bar:last-child{margin-right:0}.ydb-pool-bar_type_normal{border-color:var(--ydb-color-status-green)}.ydb-pool-bar_type_warning{border-color:var(--ydb-color-status-yellow)}.ydb-pool-bar_type_danger{border-color:var(--ydb-color-status-red)}.ydb-pool-bar__value{bottom:0;min-height:1px;position:absolute;width:100%}.ydb-pool-bar__value_type_normal{background-color:var(--ydb-color-status-green)}.ydb-pool-bar__value_type_warning{background-color:var(--ydb-color-status-yellow)}.ydb-pool-bar__value_type_danger{background-color:var(--ydb-color-status-red)}.ydb-pools-graph{display:flex}.tablets-statistic{align-items:center;display:flex;gap:2px}.tablets-statistic__tablet{border:1px solid;border-radius:2px;color:var(--g-color-text-secondary);display:inline-block;font-size:11px;height:20px;line-height:20px;padding:0 4px;text-align:center;text-decoration:none;text-transform:uppercase}.tablets-statistic__tablet_state_green{background-color:var(--g-color-base-positive-light);color:var(--g-color-text-positive)}.tablets-statistic__tablet_state_yellow{background-color:var(--g-color-base-warning-light);color:var(--g-color-text-warning)}.tablets-statistic__tablet_state_blue{background-color:var(--g-color-base-info-light);color:var(--g-color-text-info)}.tablets-statistic__tablet_state_orange{background-color:var(--g-color-base-warning-light);color:var(--g-color-text-warning-heavy)}.tablets-statistic__tablet_state_red{background:var(--g-color-base-danger-light);color:var(--g-color-text-danger)}.tablets-statistic__tablet_state_grey{border:1px solid var(--g-color-line-generic-hover);color:var(--g-color-text-secondary)}.ydb-nodes-columns__column-cpu,.ydb-nodes-columns__column-ram{min-width:40px}.ydb-nodes__search{width:238px}.ydb-nodes__show-all-wrapper{left:0;margin-bottom:15px;position:sticky}.ydb-nodes__node_unavailable{opacity:.6}.ydb-nodes__groups-wrapper{padding-right:20px}.operations__search{width:220px}.kv-shorty-string__toggle{font-size:.85em;margin-left:2em}.kv-result-issues{padding:0 10px}.kv-result-issues__error-message{align-items:center;background-color:var(--g-color-base-background);display:flex;left:0;padding:10px 0;position:sticky;top:0;z-index:2}.kv-result-issues__error-message-text{margin:0 10px}.kv-issues{position:relative}.kv-issue_leaf{margin-left:31px}.kv-issue__issues{padding-left:24px}.kv-issue__line{align-items:flex-start;display:flex;margin:0 0 10px;padding:0 10px 0 0}.kv-issue__place-text{color:var(--g-color-text-secondary);display:inline-block;padding-right:10px;text-align:left}.kv-issue__message{display:flex;font-family:var(--g-font-family-monospace);font-size:var(--g-text-code-2-font-size);line-height:var(--g-text-header-2-line-height);margin-left:10px;margin-right:auto}.kv-issue__message-text{flex:1 1 auto;min-width:240px;white-space:pre-wrap;word-break:break-word}.kv-issue__code{color:var(--g-color-text-complementary);flex:0 0 auto;font-size:12px;margin-left:1.5em;padding:3px 0}.kv-issue__arrow-toggle{margin-right:5px}.yql-issue-severity{align-items:center;display:flex;line-height:28px;white-space:nowrap}.yql-issue-severity_severity_error .yql-issue-severity__icon,.yql-issue-severity_severity_fatal .yql-issue-severity__icon{color:var(--g-color-text-danger)}.yql-issue-severity_severity_warning .yql-issue-severity__icon{color:var(--g-color-text-warning)}.yql-issue-severity_severity_info .yql-issue-severity__icon{color:var(--g-color-text-info)}.yql-issue-severity__title{color:var(--g-color-text-complementary);margin-left:4px;text-transform:capitalize}.ydb-critical-dialog{padding-top:var(--g-spacing-3)}.ydb-critical-dialog__warning-icon{color:var(--ydb-color-status-yellow);margin-right:16px}.ydb-critical-dialog__error-icon{color:var(--ydb-color-status-red);height:24px;margin-right:16px}.ydb-critical-dialog__body{display:flex;flex-direction:column;gap:var(--g-spacing-6)}.ydb-critical-dialog__body-message{align-items:center;display:flex}.ydb-critical-dialog__body-message_error,.ydb-critical-dialog__body-message_warning{border:1px solid;border-radius:var(--g-modal-border-radius,5px);padding:var(--g-spacing-4) var(--g-spacing-5)}.ydb-critical-dialog__body-message_warning{border-color:var(--ydb-color-status-yellow)}.ydb-critical-dialog__body-message_error{border-color:var(--ydb-color-status-red)}.storage-disk-progress-bar{--progress-bar-full-height:var(--g-text-body-3-line-height);--progress-bar-compact-height:12px;--entity-state-border-color:var(--g-color-base-misc-heavy);--entity-state-background-color:var(--g-color-base-misc-light);--entity-state-fill-color:var(--g-color-base-misc-medium);--entity-state-font-color:var(--g-color-text-primary);background-color:var(--entity-state-background-color);border:1px solid var(--entity-state-border-color);border-radius:4px;color:var(--g-color-text-primary);height:var(--progress-bar-full-height);min-width:50px;position:relative;text-align:center;z-index:0}.storage-disk-progress-bar_green{--entity-state-font-color:var(--g-color-text-positive);--entity-state-border-color:var(--g-color-base-positive-heavy);--entity-state-background-color:var(--g-color-base-positive-light);--entity-state-fill-color:var(--g-color-base-positive-medium)}.storage-disk-progress-bar_blue{--entity-state-font-color:var(--g-color-text-info);--entity-state-border-color:var(--g-color-base-info-heavy);--entity-state-background-color:var(--g-color-base-info-light);--entity-state-fill-color:var(--g-color-base-info-medium)}.storage-disk-progress-bar_yellow{--entity-state-font-color:var(--g-color-text-warning);--entity-state-border-color:var(--g-color-base-warning-heavy);--entity-state-background-color:var(--g-color-base-yellow-light);--entity-state-fill-color:var(--g-color-base-yellow-medium)}.storage-disk-progress-bar_orange{--entity-state-font-color:var(--g-color-private-orange-500);--entity-state-border-color:var(--ydb-color-status-orange);--entity-state-background-color:var(--g-color-private-orange-100);--entity-state-fill-color:var(--g-color-private-orange-300)}.storage-disk-progress-bar_red{--entity-state-font-color:var(--g-color-text-danger);--entity-state-border-color:var(--g-color-base-danger-heavy);--entity-state-background-color:var(--g-color-base-danger-light);--entity-state-fill-color:var(--g-color-base-danger-medium)}.storage-disk-progress-bar__grey{--entity-state-font-color:var(--g-color-text-secondary);--entity-state-border-color:var(--g-color-line-generic-hover)}.storage-disk-progress-bar_compact{border-radius:2px;height:var(--progress-bar-compact-height);min-width:0}.storage-disk-progress-bar_faded{background-color:unset}.storage-disk-progress-bar_inactive{opacity:.5}.storage-disk-progress-bar_empty{background-color:unset;border-style:dashed;color:var(--g-color-text-hint)}.storage-disk-progress-bar__fill-bar{background-color:var(--entity-state-fill-color);border-radius:3px 0 0 3px;height:100%;left:0;position:absolute;top:0}.storage-disk-progress-bar__fill-bar_faded{background-color:var(--entity-state-background-color)}.storage-disk-progress-bar__fill-bar_compact{border-radius:1px}.storage-disk-progress-bar__fill-bar_inverted{border-radius:0 3px 3px 0;left:auto;right:0}.storage-disk-progress-bar__title{color:inherit;font-size:var(--g-text-body-1-font-size);line-height:calc(var(--progress-bar-full-height) - 2px);position:relative;z-index:2}.vdisk-storage-popup .info-viewer+.info-viewer{border-top:1px solid var(--g-color-line-generic);margin-top:8px;padding-top:8px}.vdisk-storage-popup__donor-label{margin-bottom:8px}.ydb-vdisk-component{border-radius:4px}.ydb-vdisk-component__content{border-radius:4px;display:block}.pdisk-storage{display:flex;flex-direction:column;justify-content:flex-end;min-width:var(--pdisk-min-width);position:relative;width:var(--pdisk-width)}.pdisk-storage__content{border-radius:4px;display:block;flex:1 1;position:relative}.pdisk-storage__vdisks{display:flex;flex:0 0 auto;gap:var(--pdisk-gap-width);margin-bottom:4px;white-space:nowrap}.pdisk-storage__vdisks-item{flex:0 0 var(--pdisk-vdisk-width);min-width:var(--pdisk-vdisk-width)}.data-table__row:hover .pdisk-storage__vdisks-item .stack__layer{background:var(--ydb-data-table-color-hover)}.pdisk-storage__donors-stack{--ydb-stack-offset-x:0px;--ydb-stack-offset-y:-2px;--ydb-stack-offset-x-hover:0px;--ydb-stack-offset-y-hover:-7px}.pdisk-storage__media-type{color:var(--g-color-text-secondary);font-size:var(--g-text-body-1-font-size);line-height:var(--g-text-body-1-line-height);position:absolute;right:4px;top:50%;transform:translateY(-50%)}.ydb-storage-disks{align-items:center;display:flex;flex-direction:row;gap:20px;width:max-content}.ydb-storage-disks__pdisks-wrapper{display:flex;flex-direction:row;justify-content:left;width:max-content}.ydb-storage-disks__vdisk-item{flex-basis:8px;flex-shrink:0}.ydb-storage-disks__vdisk-progress-bar{--progress-bar-compact-height:18px;border-radius:4px}.ydb-storage-disks__pdisk-item{margin-right:4px;min-width:80px}.ydb-storage-disks__pdisk-item_with-dc-margin{margin-right:12px}.ydb-storage-disks__pdisk-item:last-child{margin-right:0}.ydb-storage-disks__pdisk-progress-bar{--progress-bar-full-height:20px;padding-left:var(--g-spacing-2);text-align:left}.stack{--ydb-stack-base-z-index:100;--ydb-stack-offset-x:4px;--ydb-stack-offset-y:4px;--ydb-stack-offset-x-hover:4px;--ydb-stack-offset-y-hover:6px;position:relative}.stack__layer{background:var(--g-color-base-background);transition:transform .1s ease-out}.stack__layer:first-child{position:relative;z-index:var(--ydb-stack-base-z-index)}.stack__layer+.stack__layer{height:100%;left:0;position:absolute;top:0;transform:translate(calc(var(--ydb-stack-level)*var(--ydb-stack-offset-x)),calc(var(--ydb-stack-level)*var(--ydb-stack-offset-y)));width:100%;z-index:calc(var(--ydb-stack-base-z-index) - var(--ydb-stack-level))}.stack:hover .stack__layer:first-child{transform:translate(calc(var(--ydb-stack-offset-x-hover)*-1),calc(var(--ydb-stack-offset-y-hover)*-1))}.stack:hover .stack__layer+.stack__layer{transform:translate(calc(var(--ydb-stack-level)*var(--ydb-stack-offset-x-hover)*2 - var(--ydb-stack-offset-x-hover)),calc(var(--ydb-stack-level)*var(--ydb-stack-offset-y-hover)*2 - var(--ydb-stack-offset-y-hover)))}.ydb-storage-vdisks__wrapper{display:flex}.ydb-storage-vdisks__item{margin-right:6px;width:90px}.ydb-storage-vdisks__item_with-dc-margin{margin-right:12px}.ydb-storage-vdisks__item:last-child{margin-right:0}.data-table__row:hover .ydb-storage-vdisks__item .stack__layer{background:var(--ydb-data-table-color-hover)}.ydb-storage-groups-columns__disks-column,.ydb-storage-groups-columns__vdisks-column{overflow:visible}.ydb-storage-groups-columns__pool-name-wrapper{direction:rtl;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ydb-storage-groups-columns__pool-name{unicode-bidi:plaintext}.ydb-storage-groups-columns__group-id{font-weight:500;margin-right:var(--g-spacing-1)}.global-storage__search{width:238px}.global-storage__table .g-tooltip{height:var(--g-text-body-2-line-height)!important}.global-storage .entity-status{justify-content:center}.global-storage__groups-wrapper{padding-right:20px}.ydb-storage-nodes__node_unavailable{opacity:.6}.ydb-storage-nodes-columns__pdisks-column{overflow:visible}.ydb-storage-nodes-columns__pdisks-wrapper{--pdisk-vdisk-width:3px;--pdisk-gap-width:2px;--pdisk-min-width:120px;--pdisk-margin:10px;--pdisk-width:max(calc(var(--maximum-slots, 1)*var(--pdisk-vdisk-width) + (var(--maximum-slots, 1) - 1)*var(--pdisk-gap-width)),var(--pdisk-min-width));--pdisks-container-width:calc(var(--maximum-disks, 1)*var(--pdisk-width) + (var(--maximum-disks, 1) - 1)*var(--pdisk-margin));display:flex;gap:var(--pdisk-margin);height:40px;width:var(--pdisks-container-width)}.ydb-storage-nodes-columns__pdisks-item{display:flex;flex-shrink:0}.schema-viewer__keys{display:inline-block;padding-bottom:var(--g-spacing-4);padding-left:10px}.schema-viewer__keys-values{color:var(--g-color-text-complementary);display:inline;font-size:var(--g-text-body-1-font-size);line-height:var(--g-text-body-1-line-height)}.schema-viewer__keys-header{color:var(--g-color-text-primary);display:inline;font-size:var(--g-text-subheader-1-font-size);font-weight:700;line-height:var(--g-text-subheader-1-line-height);white-space:nowrap}.schema-viewer__keys-label{cursor:pointer}.schema-viewer__keys-wrapper{left:0;position:sticky;width:100%;z-index:1}.schema-viewer__keys+.schema-viewer__keys{margin-left:var(--g-spacing-8)}.schema-viewer__keys_summary+.schema-viewer__keys_summary{margin-left:0}.schema-viewer__popup-content{padding:var(--g-spacing-2) var(--g-spacing-4)}.schema-viewer__popup-item{padding-bottom:var(--g-spacing-2)}.schema-viewer__popup-item:last-child{padding-bottom:0}.schema-viewer__more-badge{margin-left:var(--g-spacing-1)}.schema-viewer__key-icon{margin-left:var(--g-spacing-half);position:absolute;top:3.5px;vertical-align:initial}.schema-viewer__id-wrapper{display:inline-block;padding-right:var(--g-spacing-1);position:relative}.ydb-diagnostics-configs__icon-touched{color:var(--g-color-text-secondary);cursor:default!important;line-height:1}.speed-multimeter{display:flex;width:100%}.speed-multimeter__content{display:flex;flex-direction:row;flex-grow:1;justify-content:flex-end;line-height:22px}.speed-multimeter__displayed-value{display:flex;flex-direction:row;justify-content:flex-end;margin-right:10px}.speed-multimeter__bars{align-items:flex-start;display:flex;flex-direction:column;margin-right:5px;overflow:hidden;width:32px}.speed-multimeter__bar-container{height:6px;width:100%}.speed-multimeter__bar-container_highlighted{background:var(--g-color-line-generic)}.speed-multimeter__bar{height:100%;min-width:2px}.speed-multimeter__bar_color_light{background:var(--g-color-base-info-medium)}.speed-multimeter__bar_color_dark{background:var(--g-color-base-info-heavy)}.speed-multimeter__bar-container+.speed-multimeter__bar-container{margin-top:2px}.speed-multimeter__popover-container{align-items:center;display:flex;justify-content:center}.speed-multimeter__popover-content{padding:10px}.speed-multimeter__popover-header{display:block;font-size:18px;line-height:24px;margin-bottom:7px}.speed-multimeter__popover-row{display:block;font-size:13px;line-height:18px}.speed-multimeter__popover-row_color_primary{color:var(--g-color-text-primary)}.speed-multimeter__popover-row_color_secondary{color:var(--g-color-text-secondary)}.ydb-diagnostics-consumers-topic-stats{font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height)}.ydb-diagnostics-consumers-topic-stats__wrapper{border-left:1px solid var(--g-color-line-generic);display:flex;flex-direction:row;padding-left:16px}.ydb-diagnostics-consumers-topic-stats__item{display:flex;flex-direction:column;margin-right:20px}.ydb-diagnostics-consumers-topic-stats__label{color:var(--g-color-text-secondary);margin-bottom:4px}.ydb-diagnostics-consumers-topic-stats__value{align-items:center;display:flex;height:30px;justify-content:flex-start}.ydb-lag-popover-content__text{margin-bottom:10px}.ydb-lag-popover-content_type_read{max-width:280px}.ydb-lag-popover-content_type_write{max-width:220px}.ydb-diagnostics-consumers-columns-header__lags{white-space:nowrap}.ydb-diagnostics-consumers-columns__lags-header{text-align:center}.ydb-diagnostics-consumers{display:flex;flex-grow:1;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto}.ydb-diagnostics-consumers__controls{align-items:center;display:flex;gap:12px;padding:16px 0 18px}.ydb-diagnostics-consumers__search{width:238px}.ydb-diagnostics-consumers__table-wrapper{display:flex;flex:1 1 auto;flex-direction:column;overflow:auto}.ydb-diagnostics-consumers__table-content{height:100%;overflow:auto}.ydb-diagnostics-consumers__table .data-table__head-row:first-child .data-table__th:first-child,.ydb-diagnostics-consumers__table .data-table__td:first-child{background-color:var(--g-color-base-background);border-right:1px solid var(--g-color-line-generic);left:0;position:sticky;z-index:2000}.ydb-diagnostics-consumers__table .data-table__row:hover .data-table__td:first-child{background-color:var(--ydb-data-table-color-hover)!important}.ydb-diagnostics-consumers__table .data-table__head-row:first-child .data-table__th:nth-child(0),.ydb-diagnostics-consumers__table .data-table__td:nth-child(0){border-right:unset;box-shadow:unset}.ydb-diagnostics-consumers__table .data-table__head-row:first-child .data-table__th:first-child,.ydb-diagnostics-consumers__table .data-table__td:first-child{box-shadow:unset}.ydb-json-viewer{--data-table-row-height:20px;--toolbar-background-color:var(--g-color-base-background)}.ydb-json-viewer__toolbar{background-color:var(--toolbar-background-color);left:0;padding-bottom:var(--g-spacing-2);position:sticky;top:0;z-index:2}.ydb-json-viewer__content{font-family:var(--g-font-family-monospace)}.ydb-json-viewer__row{height:1em}.ydb-json-viewer__cell{position:relative}.ydb-json-viewer__cell,.ydb-json-viewer__cell *{white-space:nowrap!important}.ydb-json-viewer__collapsed{margin-left:-3ex;margin-top:-2px;position:absolute}.ydb-json-viewer__match-counter{text-wrap:nowrap;align-content:center;color:var(--g-color-text-secondary)}.ydb-json-viewer__key{color:var(--g-color-text-misc)}.ydb-json-viewer__value_type_string{color:var(--color-unipika-string)}.ydb-json-viewer__value_type_boolean{color:var(--color-unipika-bool)}.ydb-json-viewer__value_type_null{color:var(--color-unipika-null)}.ydb-json-viewer__value_type_int64{color:var(--color-unipika-int)}.ydb-json-viewer__value_type_double{color:var(--color-unipika-float)}.ydb-json-viewer__filter{width:300px}.ydb-json-viewer__filtered_highlighted{background-color:var(--g-color-base-generic-medium)}.ydb-json-viewer__filtered_clickable{color:var(--g-color-text-info);cursor:pointer}.ydb-json-viewer__match-btn{margin-left:-1px}.ydb-json-viewer__full-value{font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);margin:var(--g-spacing-3) 0;max-height:90vh;max-width:90vw;overflow:hidden auto;word-break:break-all}.ydb-json-viewer__extra-tools{margin-left:1ex}.ydb-json-viewer .data-table__head{display:none}.ydb-json-viewer .data-table__td{overflow:visible;padding:0}.ydb-describe__message-container{padding:15px 0}.ydb-describe__result{display:flex;flex:0 0 auto;padding:0 20px 20px 0;position:relative}.ydb-external-data-source-info__location,.ydb-external-table-info__location{max-width:var(--tenant-object-info-max-value-width)}.ydb-syntax-highlighter{height:100%;position:relative;z-index:0}.ydb-syntax-highlighter__sticky-container{background-color:var(--g-color-base-background);left:0;position:sticky;top:52px;top:0;z-index:1}.ydb-syntax-highlighter__copy{opacity:0;pointer-events:all;position:absolute;right:14px;top:13px}.data-table__row:hover .ydb-syntax-highlighter__copy,.ydb-paginated-table__row:hover .ydb-syntax-highlighter__copy,.ydb-syntax-highlighter__copy_visible{opacity:1}.ydb-definition-list{display:flex;flex:1 1 auto;flex-direction:column}.ydb-definition-list__title{font-size:var(--g-text-body-2-font-size);font-weight:600;line-height:var(--g-text-body-2-line-height);margin:15px 0 10px}.ydb-definition-list__properties-list{max-width:calc(100% - 40px)}.ydb-async-replication-paths__title,.ydb-overview-topic-stats__title{font-size:var(--g-text-body-2-font-size);font-weight:600;line-height:var(--g-text-body-2-line-height);margin:15px 0 10px}.ydb-overview-topic-stats .ydb-loader{margin-top:50px}.ydb-overview-topic-stats .info-viewer__row{align-items:flex-start}.ydb-overview-topic-stats .speed-multimeter{margin-top:-5px}.ydb-overview-topic-stats .speed-multimeter__content{justify-content:flex-start}.ydb-overview-topic-stats__info .info-viewer__label-text_multiline{max-width:150px}.ydb-overview-topic-stats__bytes-written{margin-top:7px;padding-left:20px}.ydb-overview-topic-stats__bytes-written .info-viewer__label{min-width:180px}.ydb-diagnostics-table-info__title{font-size:var(--g-text-body-2-font-size);font-weight:600;line-height:var(--g-text-body-2-line-height);margin:15px 0 10px}.ydb-diagnostics-table-info__row{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.ydb-diagnostics-table-info__col{align-items:flex-start;display:flex;flex-direction:column;justify-content:flex-start}.ydb-diagnostics-table-info__col:not(:last-child){margin-right:50px}.ydb-diagnostics-table-info__info-block{margin-bottom:20px}.ydb-diagnostics-table-info__info-block .info-viewer__items{grid-template-columns:minmax(max-content,280px)}.ydb-metric-chart{border:1px solid var(--g-color-line-generic);border-radius:8px;display:flex;flex-direction:column;padding:16px 16px 8px}.ydb-metric-chart__title{margin-bottom:10px}.ydb-metric-chart__chart{display:flex;height:100%;overflow:hidden;position:relative;width:100%}.ydb-metric-chart__error{left:50%;position:absolute;text-align:center;top:10%;transform:translateX(-50%);z-index:1}.ydb-timeframe-selector{display:flex;gap:2px}.ydb-tenant-dashboard{margin-bottom:var(--diagnostics-section-margin);width:var(--diagnostics-section-table-width)}.ydb-tenant-dashboard__controls{margin-bottom:10px}.ydb-tenant-dashboard__charts{display:flex;flex-flow:row wrap;gap:16px}.issue-tree-item{align-items:center;cursor:pointer;display:flex;height:40px;justify-content:space-between}.issue-tree-item__field{display:flex;overflow:hidden}.issue-tree-item__field_status{display:flex;white-space:nowrap}.issue-tree-item__field_additional{color:var(--g-color-text-link);cursor:pointer;width:max-content}.issue-tree-item__field_additional:hover{color:var(--g-color-text-link-hover)}.issue-tree-item__field_message{flex-shrink:0;overflow:hidden;white-space:normal;width:300px}.issue-tree-item__field-tooltip.issue-tree-item__field-tooltip{max-width:500px;min-width:500px}.issue-tree-item__field-label{color:var(--g-color-text-secondary)}.issue-tree{display:flex}.issue-tree__block{width:100%}.issue-tree__checkbox{margin:5px 0 10px}.issue-tree__info-panel{background:var(--g-color-base-generic);border-radius:4px;height:100%;margin:11px 0;padding:8px 20px;position:sticky}.issue-tree__info-panel .ydb-json-viewer{--toolbar-background-color:var(--g-color-base-simple-hover-solid)}.issue-tree .ydb-tree-view__item{height:40px}.issue-tree .ydb-tree-view .tree-view_arrow{height:40px;width:40px}.issue-tree .ydb-tree-view .ydb-tree-view__item{margin-left:calc(24px*var(--ydb-tree-view-level))!important;padding-left:0!important}.issue-tree .ydb-tree-view .issue-tree__info-panel{margin-left:calc(24px*var(--ydb-tree-view-level))}.healthcheck__details{width:872px}.healthcheck__details-content-wrapper{overflow-x:hidden}.healthcheck__preview{display:flex;flex-direction:column;height:100%}.healthcheck__preview-title{color:var(--g-color-text-link);font-size:var(--g-text-subheader-3-font-size);font-weight:600;line-height:var(--g-text-subheader-3-line-height)}.healthcheck__preview-content{line-height:24px;margin:auto}.healthcheck__preview-status-icon{height:64px;width:64px}.healthcheck__preview-title-wrapper{align-items:center;display:flex;gap:8px;margin-bottom:4px}.healthcheck__preview-issue{align-items:center;display:flex;flex-direction:column;gap:4px;position:relative;top:-8px}.healthcheck__preview-issue_good{color:var(--g-color-text-positive)}.healthcheck__preview-issue_good .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-positive-light)}.healthcheck__preview-issue_degraded{color:var(--g-color-text-info)}.healthcheck__preview-issue_degraded .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-info-light)}.healthcheck__preview-issue_emergency{color:var(--g-color-text-danger)}.healthcheck__preview-issue_emergency .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-danger-light)}.healthcheck__preview-issue_unspecified{color:var(--g-color-text-misc)}.healthcheck__preview-issue_unspecified .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-misc-light)}.healthcheck__preview-issue_maintenance_required{color:var(--g-color-text-warning-heavy)}.healthcheck__preview-issue_maintenance_required .healthcheck__self-check-status-indicator{background-color:var(--g-color-base-warning-light)}.healthcheck__self-check-status-indicator{text-wrap:nowrap;border-radius:4px;display:inline-block;font-size:13px;line-height:24px;padding:0 8px}.healthcheck__icon-warn{color:var(--g-color-text-warning)}.healthcheck__icon-wrapper{display:flex}.ydb-diagnostic-card{background-color:#0000;border:1px solid var(--g-color-line-generic);border-radius:8px;flex-shrink:0;padding:16px 16px 28px}.ydb-diagnostic-card_active{background-color:var(--g-color-base-selection);border-color:var(--g-color-base-info-medium)}.ydb-diagnostic-card_interactive:hover{box-shadow:0 1px 5px var(--g-color-sfx-shadow);cursor:pointer}.ydb-diagnostic-card_size_m{min-width:206px;width:206px}.ydb-diagnostic-card_size_l{min-width:289px;width:289px}.ydb-diagnostic-card_size_s{min-width:134px;width:134px}.ydb-metrics-card{min-height:252px}.ydb-metrics-card__header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:10px}.ydb-metrics-card__label{color:var(--g-color-text-link);font-size:var(--g-text-subheader-3-font-size);font-weight:600;line-height:var(--g-text-subheader-3-line-height)}.ydb-metrics-card__content{color:var(--g-color-text-secondary);display:flex;flex-direction:column;gap:10px}.ydb-metrics-card__metric-title{height:var(--g-text-body-2-line-height)}.ydb-metrics-card_active .ydb-metrics-card__content{color:var(--g-color-text-complementary)}.metrics-cards{display:flex;gap:16px;margin-bottom:32px}.metrics-cards__tab{color:inherit;text-decoration:none}.confirmation-dialog__caption,.confirmation-dialog__message{white-space:pre-wrap}.ydb-save-query__dialog-row{align-items:flex-start;display:flex}.ydb-save-query__dialog-row+.ydb-save-query__dialog-row{margin-top:var(--g-text-body-1-line-height)}.ydb-save-query__field-title{font-weight:500;line-height:28px;margin-right:12px;white-space:nowrap}.ydb-save-query__field-title.required:after{color:var(--g-color-text-danger);content:"*"}.ydb-save-query__control-wrapper{display:flex;flex-grow:1;min-height:48px}.kv-truncated-query{max-width:100%;vertical-align:top;white-space:pre;word-break:break-word}.kv-truncated-query__message{white-space:pre-wrap}.kv-truncated-query__message_color_secondary{color:var(--g-color-text-secondary)}.kv-top-queries{display:flex;flex-direction:column;height:100%}.kv-top-queries .data-table__box .data-table__table-wrapper{padding-bottom:20px}.kv-top-queries .data-table__th{box-shadow:inset 0 -1px 0 0 var(--g-tabs-color-divider)}.kv-top-queries__search{width:238px}.kv-top-queries__row{cursor:pointer}.kv-top-queries__query{overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:pre-wrap;word-break:break-word}.kv-top-queries__user-sid{max-width:200px;overflow:hidden;text-overflow:ellipsis}.tenant-overview{height:100%;overflow:auto;padding-bottom:20px}.tenant-overview__loader{display:flex;justify-content:center}.tenant-overview__tenant-name-wrapper{align-items:center;display:flex;overflow:hidden}.tenant-overview__top{line-height:24px;margin-bottom:10px}.tenant-overview__top-label{font-weight:600;gap:10px;line-height:24px;margin-bottom:var(--diagnostics-section-title-margin)}.tenant-overview__info{left:0;position:sticky;width:max-content}.tenant-overview__title{font-size:var(--g-text-body-2-font-size);font-weight:700;line-height:var(--g-text-body-2-line-height);margin-bottom:10px}.tenant-overview__table:not(:last-child){margin-bottom:var(--diagnostics-section-margin)}.tenant-overview__top-queries-row{cursor:pointer}.tenant-overview__storage-info{margin-bottom:36px}.tenant-overview__memory-info{margin-bottom:36px;width:300px}.kv-detailed-overview{display:flex;flex-direction:column;gap:20px;height:100%;width:100%}.kv-detailed-overview__section{display:flex;flex-basis:calc(50% - 10px);flex-direction:column;flex-grow:1;flex-shrink:0;min-width:300px}.kv-detailed-overview__modal .g-modal__content{position:relative}.kv-detailed-overview__close-modal-button{position:absolute;right:13px;top:23px}.ydb-hot-keys__primary-key-column{align-items:center;display:flex;gap:5px}.ydb-hot-keys__help-card{left:0;margin-bottom:20px;padding:20px 40px 20px 20px;position:sticky}.ydb-hot-keys__help-card__close-button{position:absolute;right:5px;top:5px}.node-network{border:1px solid #0000;border-radius:4px;box-sizing:border-box;color:var(--g-color-text-complementary);cursor:pointer;display:inline-block;font-size:12px;height:14px;line-height:14px;margin-bottom:5px;margin-right:5px;padding:0 5px;text-align:center;text-transform:uppercase;width:14px}.node-network_id{height:14px;width:42px}.node-network_blur{opacity:.25}.node-network_grey{background:var(--ydb-color-status-grey)}.node-network_black{background-color:var(--ydb-color-status-black);color:var(--g-color-text-light-primary)}.node-network_green{background-color:var(--ydb-color-status-green)}.node-network_yellow{background-color:var(--ydb-color-status-yellow)}.node-network_red{background-color:var(--ydb-color-status-red)}.node-network:hover{border:1px solid var(--g-color-text-primary)}.network{flex-direction:column;font-size:var(--g-text-body-2-font-size);justify-content:space-between;line-height:var(--g-text-body-2-line-height);max-width:1305px}.network,.network__nodes-row{display:flex;flex-grow:1;height:100%;overflow:auto}.network__nodes-row{align-items:flex-start;flex-direction:row}.network__inner{display:flex;flex:1 1 auto;flex-direction:column;overflow:auto}.network__right{height:100%;padding-left:20px;width:100%}.network__left{border-right:1px solid var(--g-color-base-generic-accent);height:100%}.network__placeholder{align-items:center;display:flex;flex-direction:column;flex-grow:1;height:100%;justify-content:center;width:100%}.network__placeholder-text{margin-top:15px}.network__placeholder-img{color:#0000}.network__nodes{display:flex;flex-wrap:wrap}.network__nodes-container{min-width:325px}.network__nodes-container_right{margin-right:60px}.network__nodes-title{border-bottom:1px solid var(--g-color-base-generic-accent);color:var(--g-color-text-secondary);font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);margin:0 0 15px}.network__link{color:var(--g-color-base-brand);text-decoration:none}.network__title{font-size:var(--g-text-body-1-font-size);font-weight:500;line-height:var(--g-text-body-1-line-height);margin:20px 0}.network__checkbox-wrapper{align-items:center;display:flex}.network__checkbox-wrapper label{white-space:nowrap}.network__label{margin-bottom:16px}.network__controls{display:flex;gap:12px;margin:0 16px 16px 0}.network__controls-wrapper{display:flex;flex:1 1 auto;flex-direction:row;flex-direction:column}.network__select{margin:0 15px;max-width:115px}.network__rack-column{align-items:center;background-color:#00000012;border-radius:4px;display:flex;flex-direction:column;margin-bottom:5px;margin-right:5px;padding:2px}.network__rack-column .node-network{margin-right:0}.ydb-diagnostics-partitions-columns-header__multiline{white-space:normal}.ydb-diagnostics-partitions-columns-header__read-session{white-space:normal;width:80px}.ydb-diagnostics-partitions-columns-header__lags{white-space:nowrap}.ydb-diagnostics-partitions-columns-header__messages{white-space:normal;width:90px}.ydb-diagnostics-partitions-columns-header__messages-popover-content{max-width:200px}.ydb-diagnostics-partitions-columns__lags-header{text-align:center}.ydb-diagnostics-partitions{display:flex;flex-grow:1;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto}.ydb-diagnostics-partitions__controls{align-items:center;display:flex;gap:12px;padding:16px 0 18px}.ydb-diagnostics-partitions__consumer-select{width:220px}.ydb-diagnostics-partitions__select-option_empty{color:var(--g-color-text-hint)}.ydb-diagnostics-partitions__search{width:238px}.ydb-diagnostics-partitions__search_partition{width:100px}.ydb-diagnostics-partitions__search_general{width:280px}.ydb-diagnostics-partitions__table-wrapper{display:flex;flex:1 1 auto;flex-direction:column;overflow:auto}.ydb-diagnostics-partitions__table-content{height:100%;overflow:auto}.ydb-diagnostics-partitions__table .data-table__head-row:first-child .data-table__th:first-child,.ydb-diagnostics-partitions__table .data-table__td:first-child{background-color:var(--g-color-base-background);border-right:1px solid var(--g-color-line-generic);left:0;position:sticky;z-index:2000}.ydb-diagnostics-partitions__table .data-table__row:hover .data-table__td:first-child{background-color:var(--ydb-data-table-color-hover)!important}.ydb-diagnostics-partitions__table .data-table__head-row:first-child .data-table__th:nth-child(0),.ydb-diagnostics-partitions__table .data-table__td:nth-child(0){border-right:unset;box-shadow:unset}.ydb-diagnostics-partitions__table .data-table__head-row:first-child .data-table__th:first-child,.ydb-diagnostics-partitions__table .data-table__td:first-child{box-shadow:unset}.date-range__range-input_s{width:130px}.date-range__range-input_m{width:300px}.date-range__range-input_l{width:350px}.date-range__range-input input{cursor:pointer}.top-shards__hint{left:0;position:sticky;width:max-content}.kv-tenant-diagnostics{display:flex;flex-direction:column;height:100%;overflow:hidden}.kv-tenant-diagnostics__header-wrapper{background-color:var(--g-color-base-background);padding:0 20px 16px}.kv-tenant-diagnostics__tabs{--g-tabs-border-width:0;align-items:center;box-shadow:inset 0 -1px 0 0 var(--g-color-line-generic);display:flex;justify-content:space-between}.kv-tenant-diagnostics__tabs .g-tabs_direction_horizontal{box-shadow:unset}.kv-tenant-diagnostics__tab{margin-right:40px;text-decoration:none}.kv-tenant-diagnostics__tab:first-letter{text-transform:uppercase}.kv-tenant-diagnostics__page-wrapper{flex-grow:1;overflow:auto;padding:0 20px;width:100%}.kv-tenant-diagnostics__page-wrapper .ydb-table-with-controls-layout__controls{height:46px;padding-top:0}.kv-tenant-diagnostics__page-wrapper .ydb-table-with-controls-layout .data-table__sticky_moving,.kv-tenant-diagnostics__page-wrapper .ydb-table-with-controls-layout .ydb-paginated-table__head{top:46px!important}.ydb-queries-history{display:flex;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto;padding:0 20px}.ydb-queries-history .ydb-table-with-controls-layout__controls{height:46px;padding-top:0}.ydb-queries-history.ydb-table-with-controls-layout .data-table__sticky_moving{top:46px!important}.ydb-queries-history__search{width:238px}.ydb-queries-history__table-row{cursor:pointer}.ydb-queries-history__query{flex-grow:1;overflow:hidden;text-overflow:ellipsis;white-space:pre}.kv-pane-visibility-button_hidden{display:none}.kv-pane-visibility-button_bottom{transform:rotate(180deg)}.kv-pane-visibility-button_bottom.rotate{transform:rotate(0)}.kv-pane-visibility-button_left{transform:rotate(-90deg)}.kv-pane-visibility-button_left.rotate{transform:rotate(90deg)}.kv-pane-visibility-button_top.rotate{transform:rotate(180deg)}.ydb-fullscreen{flex-grow:1;overflow:hidden}.ydb-fullscreen_fullscreen{background-color:var(--g-color-base-background);inset:0;position:absolute;z-index:10}.ydb-fullscreen__close-button{display:none;position:fixed;right:20px;top:8px;z-index:11}.ydb-fullscreen_fullscreen .ydb-fullscreen__close-button{display:block}.ydb-fullscreen__content{display:flex;height:100%;overflow:auto;width:100%}.ydb-query-result-table__cell{cursor:pointer;display:inline-block;max-width:600px;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:100%}.ydb-query-result-table__message{padding:15px 10px}.ydb-query-result-table__table-wrapper{height:0}.kv-preview{display:flex;flex:1 1 auto;flex-direction:column;height:100%}.kv-preview .data-table__box .data-table__table-wrapper{padding-bottom:20px}.kv-preview .data-table__th{box-shadow:inset 0 -1px 0 0 var(--g-tabs-color-divider)}.kv-preview__header{align-items:center;background-color:var(--g-color-base-background);border-bottom:1px solid var(--g-color-line-generic);display:flex;flex-shrink:0;height:53px;justify-content:space-between;padding:0 20px;position:sticky;top:0}.kv-preview__title{display:flex;gap:var(--g-spacing-1)}.kv-preview__table-name{color:var(--g-color-text-complementary);margin-left:var(--g-spacing-1)}.kv-preview__controls-left{display:flex;gap:var(--g-spacing-1)}.kv-preview__message-container{padding:15px 20px}.kv-preview__loader-container{align-items:center;display:flex;height:100%;justify-content:center}.kv-preview__result{overflow:auto;padding-left:10px;width:100%}.ydb-query-settings-description__message{display:flex;flex-wrap:wrap;white-space:pre}.ydb-query-editor-button__explain-button,.ydb-query-editor-button__run-button,.ydb-query-editor-button__stop-button{width:92px}.ydb-query-editor-button__stop-button_error{animation:errorAnimation .5s linear}@keyframes errorAnimation{41%,8%{transform:translateX(-2px)}25%,58%{transform:translateX(2px)}75%{transform:translateX(-1px)}92%{transform:translateX(1px)}0%,to{transform:translateX(0)}}.ydb-query-editor-controls{align-items:center;display:flex;flex:0 0 60px;gap:24px;justify-content:space-between;min-height:60px}.ydb-query-editor-controls__left,.ydb-query-editor-controls__right{display:flex;gap:12px}.ydb-query-editor-controls__mode-selector__button{margin-left:2px;width:241px}.ydb-query-editor-controls__mode-selector__button-content{align-items:center;display:flex;justify-content:space-between;width:215px}.ydb-query-editor-controls__mode-selector__popup{width:241px}.ydb-query-editor-controls__item-with-popover{align-items:center;display:flex;height:24px;line-height:normal}.ydb-query-editor-controls__popover{max-width:420px;white-space:pre-wrap}.kv-query-execution-status{align-items:center;display:flex;gap:4px}.ydb-query-settings-banner,.ydb-query-stopped-banner{margin-left:var(--g-spacing-4);margin-right:var(--g-spacing-4);margin-top:var(--g-spacing-4)}.ydb-query-ast{height:100%;overflow:hidden;white-space:pre-wrap;width:100%}.ydb-query-result-stub-message{padding:15px 20px}.ydb-query-explain-graph__canvas-container{height:100%;overflow-y:auto;width:100%}.query-info-dropdown__menu-item{align-items:start}.query-info-dropdown__menu-item-content{display:flex;flex-direction:column;padding:var(--g-spacing-1) 0}.query-info-dropdown__icon{margin-right:var(--g-spacing-2);margin-top:var(--g-spacing-2)}.ydb-query-json-viewer{height:100%;padding:15px 0;width:100%}.ydb-query-json-viewer__tree{height:100%;overflow-y:auto;padding:0 10px;width:100%}.ydb-query-result-error__message{padding-left:var(--g-spacing-4);padding-top:var(--g-spacing-4)}.ydb-query-result-sets-viewer__tabs{margin-bottom:var(--g-spacing-1);padding-left:var(--g-spacing-4);padding-top:var(--g-spacing-1)}.ydb-query-result-sets-viewer__title{padding-bottom:var(--g-spacing-4);padding-left:var(--g-spacing-4);padding-top:var(--g-spacing-4)}.ydb-query-result-sets-viewer__result-wrapper{display:flex;flex-direction:column;width:100%}.ydb-query-result-sets-viewer__result{display:flex;flex-direction:column;flex-grow:1;overflow:auto;padding-left:10px}.ydb-query-result-sets-viewer__result .data-table__box .data-table__table-wrapper{padding-bottom:20px}.ydb-query-result-sets-viewer__result .data-table__th{box-shadow:inset 0 -1px 0 0 var(--g-tabs-color-divider)}.ydb-query-result-sets-viewer__result .data-table__table-wrapper{padding-bottom:0}.ydb-table{--ydb-table-cell-height:40px}.ydb-table__table-header-content{align-items:center;border-bottom:1px solid var(--g-color-line-generic);display:inline-flex;height:100%;padding:var(--g-spacing-1) var(--g-spacing-2);width:100%}.ydb-table__table{border-collapse:collapse;border-spacing:0;table-layout:fixed}.ydb-table__table tr:hover{background-color:var(--g-color-base-simple-hover)!important}.ydb-table__table tr:nth-of-type(odd){background-color:var(--g-color-base-generic-ultralight)}.ydb-table__table_width_max{width:100%}.ydb-table__table-header-cell{background-color:var(--g-color-base-background);font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-2-font-size);font-weight:var(--g-text-subheader-font-weight);height:var(--ydb-table-cell-height)!important;line-height:var(--g-text-subheader-2-line-height);padding:0;text-align:left;vertical-align:middle}:is(.ydb-table__table-header-cell_align_right) .ydb-table__table-header-content{justify-content:flex-end;text-align:right}.ydb-table__table-cell{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);height:var(--ydb-table-cell-height)!important;line-height:var(--g-text-body-2-line-height);padding:0}.ydb-table__table-cell_align_right{text-align:right!important}.ydb-table__table-cell_vertical-align_top{vertical-align:top!important}.ydb-query-simplified-plan{height:100%;overflow:auto;padding:0 15px 15px;width:100%}.ydb-query-simplified-plan__name{align-items:center;display:flex;gap:var(--g-spacing-1);max-width:100%}.ydb-query-simplified-plan__metrics-cell{padding:var(--g-spacing-1) var(--g-spacing-2)}.ydb-query-simplified-plan__operation-params{color:var(--g-color-text-secondary)}.ydb-query-simplified-plan__operation-name{font-weight:500;height:100%;max-width:100%;position:relative}.ydb-query-simplified-plan__divider{bottom:0;box-shadow:1px 0 0 0 var(--g-color-line-generic) inset;height:100%;position:absolute;width:12px}.ydb-query-simplified-plan__divider_last{border-radius:0 0 0 1px;bottom:unset;box-shadow:1px -1px 0 0 var(--g-color-line-generic) inset;height:14px;top:0;width:12px}.ydb-query-simplified-plan__divider_horizontal{bottom:unset;box-shadow:0 -1px 0 0 var(--g-color-line-generic) inset;height:14px;top:0;width:12px}.ydb-query-simplified-plan__divider_first{height:calc(100% - 30px)}.ydb-query-simplified-plan__operation-content{height:100%;max-width:100%;padding:var(--g-spacing-1) 0;word-break:break-word}.ydb-query-simplified-plan__operation-name-content{display:flex;flex-grow:1}.ydb-query-result__controls{align-items:center;background-color:var(--g-color-base-background);border-bottom:1px solid var(--g-color-line-generic);display:flex;height:53px;justify-content:space-between;padding:var(--g-spacing-3) var(--g-spacing-4);position:sticky;top:0;z-index:2}.ydb-query-result__controls-left{align-items:center;display:flex;gap:12px;height:100%}.ydb-query-result__controls-right{display:flex;gap:4px}.ydb-query-result__elapsed-label{margin-left:var(--g-spacing-3)}.ydb-query-settings-select__selector{width:100%}.ydb-query-settings-select__popup{max-width:320px}.ydb-query-settings-select__item-description{color:var(--g-color-text-secondary);white-space:pre-wrap}.ydb-query-settings-select__item{padding:var(--g-spacing-1) 0}.ydb-timeout-label__switch{align-items:center;height:var(--g-text-header-2-line-height);margin-right:var(--g-spacing-1)}.ydb-timeout-label__label-title,.ydb-timeout-label__switch-title{align-items:center;flex:4 1;font-weight:500;margin-right:var(--g-spacing-3);white-space:nowrap}.ydb-timeout-label__label-title{line-height:var(--g-text-header-2-line-height)}.ydb-query-settings-timeout__control-wrapper{align-items:center;display:flex;flex:6 1}.ydb-query-settings-timeout__input{width:50%}.ydb-query-settings-timeout__postfix{color:var(--g-color-text-secondary);margin-right:var(--g-spacing-2)}.ydb-query-settings-dialog__dialog-row+.ydb-query-settings-dialog__dialog-row{margin-top:var(--g-text-body-1-line-height)}.ydb-query-settings-dialog__field-title{flex:4 1;font-weight:500;line-height:var(--g-text-header-2-line-height);margin-right:var(--g-spacing-3);white-space:nowrap}.ydb-query-settings-dialog .g-dialog-footer__bts-wrapper{width:100%}.ydb-query-settings-dialog__dialog-body{padding-top:var(--g-spacing-6)}.ydb-query-settings-dialog__control-wrapper{display:flex;flex:6 1}.ydb-query-settings-dialog__limit-rows{margin-right:var(--g-spacing-2);width:50%}.ydb-query-settings-dialog__postfix{color:var(--g-color-text-secondary);margin-right:var(--g-spacing-2)}.ydb-query-settings-dialog__buttons-container{display:flex;justify-content:space-between;width:100%}.ydb-query-settings-dialog__main-buttons{display:flex;gap:10px}.query-editor{display:flex;flex:1 1 auto;flex-direction:column;height:100%;position:relative}.query-editor .data-table__box .data-table__table-wrapper{padding-bottom:20px}.query-editor .data-table__th{box-shadow:inset 0 -1px 0 0 var(--g-tabs-color-divider)}.query-editor .data-table__box .data-table__table-wrapper{padding-bottom:0}.query-editor__monaco{border:1px solid var(--g-color-line-generic);display:flex;height:100%;position:relative;width:100%}.query-editor__monaco-wrapper{height:calc(100% - 49px);min-height:0;width:100%}.query-editor__pane-wrapper{background-color:var(--g-color-base-background);display:flex;flex-direction:column;z-index:2}.query-editor__pane-wrapper_top{border-bottom:1px solid var(--g-color-line-generic);padding:0 16px}.ydb-saved-queries{display:flex;flex:1 1 auto;flex-direction:column;height:100%;overflow:auto;padding:0 20px}.ydb-saved-queries .ydb-table-with-controls-layout__controls{height:46px;padding-top:0}.ydb-saved-queries.ydb-table-with-controls-layout .data-table__sticky_moving{top:46px!important}.ydb-saved-queries__search{width:238px}.ydb-saved-queries__row{cursor:pointer}.ydb-saved-queries__row :hover .ydb-saved-queries__controls{display:flex}.ydb-saved-queries__query-name{overflow:hidden;text-overflow:ellipsis;white-space:pre-wrap}.ydb-saved-queries__query{align-items:center;display:flex;flex-direction:row;justify-content:space-between}.ydb-saved-queries__query-body{flex-grow:1;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:pre}.ydb-saved-queries__controls{display:none}.ydb-saved-queries__dialog-query-name{font-weight:500}.ydb-query{display:flex;flex:1 1 auto;flex-direction:column;max-height:calc(100% - 56px)}.ydb-query__tabs{padding:0 20px 16px}.ydb-query__content{height:100%;overflow:hidden}.ydb-tenant-navigation{padding:12px 16px 8px}.ydb-tenant-navigation__item{align-items:center;display:flex;gap:5px}.ydb-tenant-navigation__icon{flex-shrink:0}.ydb-tenant-navigation__text{overflow:hidden;text-overflow:ellipsis}.object-general{display:flex;flex-direction:column;flex-grow:1;height:100%;max-height:100%;width:100%}.object-general__loader{display:flex}.ydb-acl{width:100%}.ydb-acl__result{padding-bottom:var(--g-spacing-4);padding-left:var(--g-spacing-2)}.ydb-acl__result_no-title{margin-top:var(--g-spacing-3)}.ydb-acl__definition-content{align-items:flex-end;display:flex;flex-direction:column}.ydb-acl__list-title{font-weight:600;margin:var(--g-spacing-3) 0 var(--g-spacing-5)}.ydb-acl__group-label,.ydb-acl__list-title{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-2-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-2-line-height)}.ydb-schema-create-directory-dialog__label{display:flex;flex-direction:column;margin-bottom:8px}.ydb-schema-create-directory-dialog__description{color:var(--g-color-text-secondary)}.ydb-schema-create-directory-dialog__input-wrapper{min-height:48px}.ydb-object-summary{height:100%;max-height:100%;overflow:hidden;width:100%}.ydb-object-summary,.ydb-object-summary__overview-wrapper{display:flex;flex-direction:column;flex-grow:1;position:relative}.ydb-object-summary__overview-wrapper{overflow:auto;padding:0 12px 16px}.ydb-object-summary_hidden{visibility:hidden}.ydb-object-summary__actions{background-color:var(--g-color-base-background);position:absolute;right:5px;top:19px}.ydb-object-summary__button_hidden{display:none}.ydb-object-summary__tree-wrapper{display:flex;flex-direction:column}.ydb-object-summary__tree{flex:1 1 auto;height:100%;overflow-y:scroll;padding:0 12px 12px 16px}.ydb-object-summary__tree-header{padding:23px 12px 17px 20px}.ydb-object-summary__sticky-top{background-color:var(--g-color-base-background);left:0;position:sticky;top:0;z-index:5}.ydb-object-summary__tabs{padding:8px 12px 16px}.ydb-object-summary__tabs-inner{--g-tabs-border-width:0;box-shadow:inset 0 -1px 0 0 var(--g-color-line-generic)}.ydb-object-summary__tab{text-decoration:none}.ydb-object-summary__info{display:flex;flex-direction:column;overflow:hidden}.ydb-object-summary__info-controls{display:flex;gap:4px}.ydb-object-summary__info-action-button{background-color:var(--g-color-base-background)}.ydb-object-summary__info-action-button_hidden{display:none}.ydb-object-summary__rotated90{transform:rotate(-90deg)}.ydb-object-summary__rotated180{transform:rotate(180deg)}.ydb-object-summary__rotated270{transform:rotate(90deg)}.ydb-object-summary__info-header{align-items:center;border-bottom:1px solid var(--g-color-line-generic);display:flex;justify-content:space-between;padding:12px 12px 10px}.ydb-object-summary__info-title{align-items:center;display:flex;font-weight:600;overflow:hidden}.ydb-object-summary__path-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ydb-object-summary__entity-type{background-color:var(--g-color-base-generic);border-radius:3px;display:inline-block;font-weight:400;margin-right:5px;padding:3px 8px;text-transform:lowercase}.ydb-object-summary__entity-type_error{background-color:#0000;padding:3px 0}.ydb-object-summary__overview-title{font-size:var(--g-text-body-2-font-size);font-weight:600;line-height:var(--g-text-body-2-line-height);margin:15px 0 10px}.ydb-object-summary__overview-item-content{text-align:end;white-space:nowrap}.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.tenant-page{display:flex;flex:1 1 auto;flex-direction:column;font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);overflow:hidden}.tenant-page__main{flex-grow:1} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/94695.6eb9306c.chunk.css b/ydb/core/viewer/monitoring/static/css/94695.6eb9306c.chunk.css deleted file mode 100644 index 63281432ebae..000000000000 --- a/ydb/core/viewer/monitoring/static/css/94695.6eb9306c.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.ydb-syntax-highlighter{height:100%;position:relative;z-index:0}.ydb-syntax-highlighter__sticky-container{background-color:var(--g-color-base-background);left:0;position:sticky;top:52px;top:0;z-index:1}.ydb-syntax-highlighter__copy{position:absolute;right:14px;top:13px} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/94695.b2628977.chunk.css b/ydb/core/viewer/monitoring/static/css/94695.b2628977.chunk.css new file mode 100644 index 000000000000..613ed3465e60 --- /dev/null +++ b/ydb/core/viewer/monitoring/static/css/94695.b2628977.chunk.css @@ -0,0 +1 @@ +.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.ydb-syntax-highlighter{height:100%;position:relative;z-index:0}.ydb-syntax-highlighter__sticky-container{background-color:var(--g-color-base-background);left:0;position:sticky;top:52px;top:0;z-index:1}.ydb-syntax-highlighter__copy{opacity:0;pointer-events:all;position:absolute;right:14px;top:13px}.data-table__row:hover .ydb-syntax-highlighter__copy,.ydb-paginated-table__row:hover .ydb-syntax-highlighter__copy,.ydb-syntax-highlighter__copy_visible{opacity:1} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/main.84f98361.css b/ydb/core/viewer/monitoring/static/css/main.84f98361.css deleted file mode 100644 index 3e81d95d3196..000000000000 --- a/ydb/core/viewer/monitoring/static/css/main.84f98361.css +++ /dev/null @@ -1,9 +0,0 @@ -@charset "UTF-8";@import url(https://fonts.googleapis.com/css2?family=Rubik&display=swap);:root{--data-table-header-vertical-padding:5px;--data-table-cell-vertical-padding:5px;--data-table-cell-horizontal-padding:10px;--data-table-cell-border-padding:var(--data-table-cell-horizontal-padding);--data-table-cell-align:top;--data-table-head-align:top;--data-table-row-height:30px;--data-table-sort-icon-space:18px;--data-table-sort-icon-opacity-inactive:0.15;--data-table-sort-icon-color:inherit}.data-table{box-sizing:border-box;position:relative}.data-table__box{box-sizing:border-box;height:100%;width:100%}.data-table__box_sticky-head_moving{overflow:visible;position:relative;z-index:0}.data-table__box_sticky-head_moving .data-table__th{border-bottom:0;border-top:0;padding-bottom:0;padding-top:0}.data-table__box_sticky-head_moving .data-table__head-cell{display:block;height:0;overflow:hidden}.data-table__box_sticky-head_moving .data-table__row_header-data{visibility:hidden}.data-table__box_sticky-footer_fixed,.data-table__box_sticky-head_fixed{overflow:auto}.data-table__table{border-collapse:collapse;table-layout:fixed}.data-table__table_sticky{background:var(--data-table-color-base);width:100%}.data-table__row{height:var(--data-table-row-height)}.data-table__th{border:1px solid var(--data-table-border-color);box-sizing:border-box;cursor:default;font-weight:500;padding:var(--data-table-header-vertical-padding) var(--data-table-cell-horizontal-padding);position:relative;text-align:left;vertical-align:var(--data-table-head-align)}.data-table__th_sortable{cursor:pointer}.data-table__th_sortable .data-table__head-cell{padding-right:var(--data-table-sort-icon-space)}.data-table__th_sortable.data-table__th_align_right .data-table__head-cell{padding-left:var(--data-table-sort-icon-space);padding-right:0}.data-table__th_sortable.data-table__th_align_right .data-table__sort-icon{left:0;right:auto;transform:translateY(-50%) scaleX(-1)}.data-table__td{border:1px solid var(--data-table-border-color);box-sizing:border-box;overflow:hidden;padding:var(--data-table-cell-vertical-padding) var(--data-table-cell-horizontal-padding);text-overflow:ellipsis;vertical-align:var(--data-table-cell-align);white-space:nowrap}.data-table__td_index,.data-table__th_index{text-align:right}.data-table__td_align_left,.data-table__th_align_left{text-align:left}.data-table__td_align_center,.data-table__th_align_center{text-align:center}.data-table__td_align_right,.data-table__th_align_right{text-align:right}.data-table__td:first-child,.data-table__th:first-child{padding-left:var(--data-table-cell-border-padding)}.data-table__td:last-child,.data-table__th:last-child{padding-right:var(--data-table-cell-border-padding)}.data-table__index{text-align:right}.data-table__head-cell{box-sizing:border-box;display:inline-block;max-width:100%;overflow:hidden;position:relative;text-overflow:ellipsis;vertical-align:top;white-space:nowrap}.data-table__error{padding:20px;white-space:pre-wrap}.data-table__sort-icon{color:var(--data-table-sort-icon-color);display:inline-flex;position:absolute;right:0;top:50%;transform:translateY(-50%)}.data-table__sort-icon:after{content:attr(data-index);font-size:8px;left:100%;position:absolute;top:-5px}.data-table__sort-icon_shadow{opacity:var(--data-table-sort-icon-opacity-inactive)}.data-table__sort-icon_shadow:after{content:none}.data-table__icon{vertical-align:top}.data-table__no-data{background:var(--data-table-color-stripe)}.data-table__sticky_fixed{left:0;overflow:hidden;position:absolute;right:0;z-index:1}.data-table__sticky_fixed.data-table__sticky_head{top:0}.data-table__sticky_fixed.data-table__sticky_footer{bottom:0}.data-table__sticky_moving{margin-bottom:-1px;position:sticky;z-index:1}.data-table_striped-rows .data-table__row_odd{background:var(--data-table-color-stripe)}.data-table_highlight-rows .data-table__row:hover{background:var(--data-table-color-hover-area)}.data-table_header_multiline .data-table__head-cell{white-space:normal}.data-table_header_pre .data-table__head-cell{white-space:pre}.data-table__foot{background:var(--data-table-color-footer-area)}.data-table__foot_has-sticky-footer_moving{visibility:hidden}.data-table_theme_yandex-cloud{--data-table-color-base:var(--g-color-base-background,var(--yc-color-base-background));--data-table-color-stripe:var( --g-color-base-generic-ultralight,var(--yc-color-base-generic-ultralight) );--data-table-border-color:var( --g-color-base-generic-hover,var(--yc-color-base-generic-hover) );--data-table-color-hover-area:var( --g-color-base-simple-hover,var(--yc-color-base-simple-hover) );--data-table-color-footer-area:var(--data-table-color-base)}.data-table_theme_legacy{--data-table-color-base:#fff;--data-table-color-stripe:#00000008;--data-table-border-color:#ddd;--data-table-color-hover-area:#ffeba0;--data-table-color-footer-area:var(--data-table-color-base)}.data-table__resize-handler{background-color:var(--g-color-base-generic);cursor:col-resize;height:100%;position:absolute;right:0;top:0;visibility:hidden;width:6px}.data-table__resize-handler_resizing,.data-table__th:hover>.data-table__resize-handler{visibility:visible}.ydb-error-boundary{--g-definition-list-item-gap:var(--g-spacing-1);padding:var(--g-spacing-8)}.ydb-error-boundary__error-stack-wrapper{background-color:var(--code-background-color);border-radius:var(--g-border-radius-xs);height:430px;overflow:auto;scrollbar-color:var(--g-color-scroll-handle) #0000;width:800px}.ydb-error-boundary__error-stack-title{border-bottom:1px solid var(--g-color-line-generic);left:0;padding:var(--g-spacing-2) var(--g-spacing-3);position:sticky}.ydb-error-boundary__error-stack-code{padding:var(--g-spacing-3) var(--g-spacing-3) var(--g-spacing-2);white-space:pre-wrap}.ydb-error-boundary__qr-help-text{text-align:right}.g-s__m_0{margin:var(--g-spacing-0)}.g-s__mr_0{margin-inline-end:var(--g-spacing-0)}.g-s__ml_0{margin-inline-start:var(--g-spacing-0)}.g-s__mt_0{margin-block-start:var(--g-spacing-0)}.g-s__mb_0{margin-block-end:var(--g-spacing-0)}.g-s__mx_0{margin-inline:var(--g-spacing-0)}.g-s__my_0{margin-block:var(--g-spacing-0)}.g-s__p_0{padding:var(--g-spacing-0)}.g-s__pl_0{padding-inline-start:var(--g-spacing-0)}.g-s__pr_0{padding-inline-end:var(--g-spacing-0)}.g-s__pb_0{padding-block-end:var(--g-spacing-0)}.g-s__pt_0{padding-block-start:var(--g-spacing-0)}.g-s__py_0{padding-block:var(--g-spacing-0)}.g-s__px_0{padding-inline:var(--g-spacing-0)}.g-s__m_half{margin:var(--g-spacing-half)}.g-s__mr_half{margin-inline-end:var(--g-spacing-half)}.g-s__ml_half{margin-inline-start:var(--g-spacing-half)}.g-s__mt_half{margin-block-start:var(--g-spacing-half)}.g-s__mb_half{margin-block-end:var(--g-spacing-half)}.g-s__mx_half{margin-inline:var(--g-spacing-half)}.g-s__my_half{margin-block:var(--g-spacing-half)}.g-s__p_half{padding:var(--g-spacing-half)}.g-s__pl_half{padding-inline-start:var(--g-spacing-half)}.g-s__pr_half{padding-inline-end:var(--g-spacing-half)}.g-s__pb_half{padding-block-end:var(--g-spacing-half)}.g-s__pt_half{padding-block-start:var(--g-spacing-half)}.g-s__py_half{padding-block:var(--g-spacing-half)}.g-s__px_half{padding-inline:var(--g-spacing-half)}.g-s__m_1{margin:var(--g-spacing-1)}.g-s__mr_1{margin-inline-end:var(--g-spacing-1)}.g-s__ml_1{margin-inline-start:var(--g-spacing-1)}.g-s__mt_1{margin-block-start:var(--g-spacing-1)}.g-s__mb_1{margin-block-end:var(--g-spacing-1)}.g-s__mx_1{margin-inline:var(--g-spacing-1)}.g-s__my_1{margin-block:var(--g-spacing-1)}.g-s__p_1{padding:var(--g-spacing-1)}.g-s__pl_1{padding-inline-start:var(--g-spacing-1)}.g-s__pr_1{padding-inline-end:var(--g-spacing-1)}.g-s__pb_1{padding-block-end:var(--g-spacing-1)}.g-s__pt_1{padding-block-start:var(--g-spacing-1)}.g-s__py_1{padding-block:var(--g-spacing-1)}.g-s__px_1{padding-inline:var(--g-spacing-1)}.g-s__m_2{margin:var(--g-spacing-2)}.g-s__mr_2{margin-inline-end:var(--g-spacing-2)}.g-s__ml_2{margin-inline-start:var(--g-spacing-2)}.g-s__mt_2{margin-block-start:var(--g-spacing-2)}.g-s__mb_2{margin-block-end:var(--g-spacing-2)}.g-s__mx_2{margin-inline:var(--g-spacing-2)}.g-s__my_2{margin-block:var(--g-spacing-2)}.g-s__p_2{padding:var(--g-spacing-2)}.g-s__pl_2{padding-inline-start:var(--g-spacing-2)}.g-s__pr_2{padding-inline-end:var(--g-spacing-2)}.g-s__pb_2{padding-block-end:var(--g-spacing-2)}.g-s__pt_2{padding-block-start:var(--g-spacing-2)}.g-s__py_2{padding-block:var(--g-spacing-2)}.g-s__px_2{padding-inline:var(--g-spacing-2)}.g-s__m_3{margin:var(--g-spacing-3)}.g-s__mr_3{margin-inline-end:var(--g-spacing-3)}.g-s__ml_3{margin-inline-start:var(--g-spacing-3)}.g-s__mt_3{margin-block-start:var(--g-spacing-3)}.g-s__mb_3{margin-block-end:var(--g-spacing-3)}.g-s__mx_3{margin-inline:var(--g-spacing-3)}.g-s__my_3{margin-block:var(--g-spacing-3)}.g-s__p_3{padding:var(--g-spacing-3)}.g-s__pl_3{padding-inline-start:var(--g-spacing-3)}.g-s__pr_3{padding-inline-end:var(--g-spacing-3)}.g-s__pb_3{padding-block-end:var(--g-spacing-3)}.g-s__pt_3{padding-block-start:var(--g-spacing-3)}.g-s__py_3{padding-block:var(--g-spacing-3)}.g-s__px_3{padding-inline:var(--g-spacing-3)}.g-s__m_4{margin:var(--g-spacing-4)}.g-s__mr_4{margin-inline-end:var(--g-spacing-4)}.g-s__ml_4{margin-inline-start:var(--g-spacing-4)}.g-s__mt_4{margin-block-start:var(--g-spacing-4)}.g-s__mb_4{margin-block-end:var(--g-spacing-4)}.g-s__mx_4{margin-inline:var(--g-spacing-4)}.g-s__my_4{margin-block:var(--g-spacing-4)}.g-s__p_4{padding:var(--g-spacing-4)}.g-s__pl_4{padding-inline-start:var(--g-spacing-4)}.g-s__pr_4{padding-inline-end:var(--g-spacing-4)}.g-s__pb_4{padding-block-end:var(--g-spacing-4)}.g-s__pt_4{padding-block-start:var(--g-spacing-4)}.g-s__py_4{padding-block:var(--g-spacing-4)}.g-s__px_4{padding-inline:var(--g-spacing-4)}.g-s__m_5{margin:var(--g-spacing-5)}.g-s__mr_5{margin-inline-end:var(--g-spacing-5)}.g-s__ml_5{margin-inline-start:var(--g-spacing-5)}.g-s__mt_5{margin-block-start:var(--g-spacing-5)}.g-s__mb_5{margin-block-end:var(--g-spacing-5)}.g-s__mx_5{margin-inline:var(--g-spacing-5)}.g-s__my_5{margin-block:var(--g-spacing-5)}.g-s__p_5{padding:var(--g-spacing-5)}.g-s__pl_5{padding-inline-start:var(--g-spacing-5)}.g-s__pr_5{padding-inline-end:var(--g-spacing-5)}.g-s__pb_5{padding-block-end:var(--g-spacing-5)}.g-s__pt_5{padding-block-start:var(--g-spacing-5)}.g-s__py_5{padding-block:var(--g-spacing-5)}.g-s__px_5{padding-inline:var(--g-spacing-5)}.g-s__m_6{margin:var(--g-spacing-6)}.g-s__mr_6{margin-inline-end:var(--g-spacing-6)}.g-s__ml_6{margin-inline-start:var(--g-spacing-6)}.g-s__mt_6{margin-block-start:var(--g-spacing-6)}.g-s__mb_6{margin-block-end:var(--g-spacing-6)}.g-s__mx_6{margin-inline:var(--g-spacing-6)}.g-s__my_6{margin-block:var(--g-spacing-6)}.g-s__p_6{padding:var(--g-spacing-6)}.g-s__pl_6{padding-inline-start:var(--g-spacing-6)}.g-s__pr_6{padding-inline-end:var(--g-spacing-6)}.g-s__pb_6{padding-block-end:var(--g-spacing-6)}.g-s__pt_6{padding-block-start:var(--g-spacing-6)}.g-s__py_6{padding-block:var(--g-spacing-6)}.g-s__px_6{padding-inline:var(--g-spacing-6)}.g-s__m_7{margin:var(--g-spacing-7)}.g-s__mr_7{margin-inline-end:var(--g-spacing-7)}.g-s__ml_7{margin-inline-start:var(--g-spacing-7)}.g-s__mt_7{margin-block-start:var(--g-spacing-7)}.g-s__mb_7{margin-block-end:var(--g-spacing-7)}.g-s__mx_7{margin-inline:var(--g-spacing-7)}.g-s__my_7{margin-block:var(--g-spacing-7)}.g-s__p_7{padding:var(--g-spacing-7)}.g-s__pl_7{padding-inline-start:var(--g-spacing-7)}.g-s__pr_7{padding-inline-end:var(--g-spacing-7)}.g-s__pb_7{padding-block-end:var(--g-spacing-7)}.g-s__pt_7{padding-block-start:var(--g-spacing-7)}.g-s__py_7{padding-block:var(--g-spacing-7)}.g-s__px_7{padding-inline:var(--g-spacing-7)}.g-s__m_8{margin:var(--g-spacing-8)}.g-s__mr_8{margin-inline-end:var(--g-spacing-8)}.g-s__ml_8{margin-inline-start:var(--g-spacing-8)}.g-s__mt_8{margin-block-start:var(--g-spacing-8)}.g-s__mb_8{margin-block-end:var(--g-spacing-8)}.g-s__mx_8{margin-inline:var(--g-spacing-8)}.g-s__my_8{margin-block:var(--g-spacing-8)}.g-s__p_8{padding:var(--g-spacing-8)}.g-s__pl_8{padding-inline-start:var(--g-spacing-8)}.g-s__pr_8{padding-inline-end:var(--g-spacing-8)}.g-s__pb_8{padding-block-end:var(--g-spacing-8)}.g-s__pt_8{padding-block-start:var(--g-spacing-8)}.g-s__py_8{padding-block:var(--g-spacing-8)}.g-s__px_8{padding-inline:var(--g-spacing-8)}.g-s__m_9{margin:var(--g-spacing-9)}.g-s__mr_9{margin-inline-end:var(--g-spacing-9)}.g-s__ml_9{margin-inline-start:var(--g-spacing-9)}.g-s__mt_9{margin-block-start:var(--g-spacing-9)}.g-s__mb_9{margin-block-end:var(--g-spacing-9)}.g-s__mx_9{margin-inline:var(--g-spacing-9)}.g-s__my_9{margin-block:var(--g-spacing-9)}.g-s__p_9{padding:var(--g-spacing-9)}.g-s__pl_9{padding-inline-start:var(--g-spacing-9)}.g-s__pr_9{padding-inline-end:var(--g-spacing-9)}.g-s__pb_9{padding-block-end:var(--g-spacing-9)}.g-s__pt_9{padding-block-start:var(--g-spacing-9)}.g-s__py_9{padding-block:var(--g-spacing-9)}.g-s__px_9{padding-inline:var(--g-spacing-9)}.g-s__m_10{margin:var(--g-spacing-10)}.g-s__mr_10{margin-inline-end:var(--g-spacing-10)}.g-s__ml_10{margin-inline-start:var(--g-spacing-10)}.g-s__mt_10{margin-block-start:var(--g-spacing-10)}.g-s__mb_10{margin-block-end:var(--g-spacing-10)}.g-s__mx_10{margin-inline:var(--g-spacing-10)}.g-s__my_10{margin-block:var(--g-spacing-10)}.g-s__p_10{padding:var(--g-spacing-10)}.g-s__pl_10{padding-inline-start:var(--g-spacing-10)}.g-s__pr_10{padding-inline-end:var(--g-spacing-10)}.g-s__pb_10{padding-block-end:var(--g-spacing-10)}.g-s__pt_10{padding-block-start:var(--g-spacing-10)}.g-s__py_10{padding-block:var(--g-spacing-10)}.g-s__px_10{padding-inline:var(--g-spacing-10)}.g-box{box-sizing:border-box}.g-box_overflow_hidden{overflow:hidden}.g-box_overflow_auto{overflow:auto}.g-box_overflow_x{overflow:hidden auto}.g-box_overflow_y{overflow:auto hidden}.g-flex{display:flex}.g-flex_inline{display:inline-flex}.g-flex_center-content{align-items:center;justify-content:center}.g-flex_s_0{margin-block-start:calc(var(--g-spacing-0)*-1)!important;margin-inline-start:calc(var(--g-spacing-0)*-1)!important}.g-flex_s_0>*{padding-block-start:var(--g-spacing-0)!important;padding-inline-start:var(--g-spacing-0)!important}.g-flex_s_half{margin-block-start:calc(var(--g-spacing-half)*-1)!important;margin-inline-start:calc(var(--g-spacing-half)*-1)!important}.g-flex_s_half>*{padding-block-start:var(--g-spacing-half)!important;padding-inline-start:var(--g-spacing-half)!important}.g-flex_s_1{margin-block-start:calc(var(--g-spacing-1)*-1)!important;margin-inline-start:calc(var(--g-spacing-1)*-1)!important}.g-flex_s_1>*{padding-block-start:var(--g-spacing-1)!important;padding-inline-start:var(--g-spacing-1)!important}.g-flex_s_2{margin-block-start:calc(var(--g-spacing-2)*-1)!important;margin-inline-start:calc(var(--g-spacing-2)*-1)!important}.g-flex_s_2>*{padding-block-start:var(--g-spacing-2)!important;padding-inline-start:var(--g-spacing-2)!important}.g-flex_s_3{margin-block-start:calc(var(--g-spacing-3)*-1)!important;margin-inline-start:calc(var(--g-spacing-3)*-1)!important}.g-flex_s_3>*{padding-block-start:var(--g-spacing-3)!important;padding-inline-start:var(--g-spacing-3)!important}.g-flex_s_4{margin-block-start:calc(var(--g-spacing-4)*-1)!important;margin-inline-start:calc(var(--g-spacing-4)*-1)!important}.g-flex_s_4>*{padding-block-start:var(--g-spacing-4)!important;padding-inline-start:var(--g-spacing-4)!important}.g-flex_s_5{margin-block-start:calc(var(--g-spacing-5)*-1)!important;margin-inline-start:calc(var(--g-spacing-5)*-1)!important}.g-flex_s_5>*{padding-block-start:var(--g-spacing-5)!important;padding-inline-start:var(--g-spacing-5)!important}.g-flex_s_6{margin-block-start:calc(var(--g-spacing-6)*-1)!important;margin-inline-start:calc(var(--g-spacing-6)*-1)!important}.g-flex_s_6>*{padding-block-start:var(--g-spacing-6)!important;padding-inline-start:var(--g-spacing-6)!important}.g-flex_s_7{margin-block-start:calc(var(--g-spacing-7)*-1)!important;margin-inline-start:calc(var(--g-spacing-7)*-1)!important}.g-flex_s_7>*{padding-block-start:var(--g-spacing-7)!important;padding-inline-start:var(--g-spacing-7)!important}.g-flex_s_8{margin-block-start:calc(var(--g-spacing-8)*-1)!important;margin-inline-start:calc(var(--g-spacing-8)*-1)!important}.g-flex_s_8>*{padding-block-start:var(--g-spacing-8)!important;padding-inline-start:var(--g-spacing-8)!important}.g-flex_s_9{margin-block-start:calc(var(--g-spacing-9)*-1)!important;margin-inline-start:calc(var(--g-spacing-9)*-1)!important}.g-flex_s_9>*{padding-block-start:var(--g-spacing-9)!important;padding-inline-start:var(--g-spacing-9)!important}.g-flex_s_10{margin-block-start:calc(var(--g-spacing-10)*-1)!important;margin-inline-start:calc(var(--g-spacing-10)*-1)!important}.g-flex_s_10>*{padding-block-start:var(--g-spacing-10)!important;padding-inline-start:var(--g-spacing-10)!important}.g-color-text_color_primary{color:var(--g-color-text-primary)}.g-color-text_color_complementary{color:var(--g-color-text-complementary)}.g-color-text_color_secondary{color:var(--g-color-text-secondary)}.g-color-text_color_hint{color:var(--g-color-text-hint)}.g-color-text_color_info{color:var(--g-color-text-info)}.g-color-text_color_info-heavy{color:var(--g-color-text-info-heavy)}.g-color-text_color_positive{color:var(--g-color-text-positive)}.g-color-text_color_positive-heavy{color:var(--g-color-text-positive-heavy)}.g-color-text_color_warning{color:var(--g-color-text-warning)}.g-color-text_color_warning-heavy{color:var(--g-color-text-warning-heavy)}.g-color-text_color_danger{color:var(--g-color-text-danger)}.g-color-text_color_danger-heavy{color:var(--g-color-text-danger-heavy)}.g-color-text_color_utility{color:var(--g-color-text-utility)}.g-color-text_color_utility-heavy{color:var(--g-color-text-utility-heavy)}.g-color-text_color_misc{color:var(--g-color-text-misc)}.g-color-text_color_misc-heavy{color:var(--g-color-text-misc-heavy)}.g-color-text_color_brand{color:var(--g-color-text-brand)}.g-color-text_color_link{color:var(--g-color-text-link)}.g-color-text_color_link-hover{color:var(--g-color-text-link-hover)}.g-color-text_color_link-visited{color:var(--g-color-text-link-visited)}.g-color-text_color_link-visited-hover{color:var(--g-color-text-link-visited-hover)}.g-color-text_color_dark-primary{color:var(--g-color-text-dark-primary)}.g-color-text_color_dark-complementary{color:var(--g-color-text-dark-complementary)}.g-color-text_color_dark-secondary{color:var(--g-color-text-dark-secondary)}.g-color-text_color_light-primary{color:var(--g-color-text-light-primary)}.g-color-text_color_light-complementary{color:var(--g-color-text-light-complementary)}.g-color-text_color_light-secondary{color:var(--g-color-text-light-secondary)}.g-color-text_color_light-hint{color:var(--g-color-text-light-hint)}.g-color-text_color_inverted-primary{color:var(--g-color-text-inverted-primary)}.g-color-text_color_inverted-complementary{color:var(--g-color-text-inverted-complementary)}.g-color-text_color_inverted-secondary{color:var(--g-color-text-inverted-secondary)}.g-color-text_color_inverted-hint{color:var(--g-color-text-inverted-hint)}.g-text_variant_display-1{font-size:var(--g-text-display-1-font-size);line-height:var(--g-text-display-1-line-height)}.g-text_variant_display-1,.g-text_variant_display-2{font-family:var(--g-text-display-font-family);font-weight:var(--g-text-display-font-weight)}.g-text_variant_display-2{font-size:var(--g-text-display-2-font-size);line-height:var(--g-text-display-2-line-height)}.g-text_variant_display-3{font-size:var(--g-text-display-3-font-size);line-height:var(--g-text-display-3-line-height)}.g-text_variant_display-3,.g-text_variant_display-4{font-family:var(--g-text-display-font-family);font-weight:var(--g-text-display-font-weight)}.g-text_variant_display-4{font-size:var(--g-text-display-4-font-size);line-height:var(--g-text-display-4-line-height)}.g-text_variant_code-1{font-size:var(--g-text-code-1-font-size);line-height:var(--g-text-code-1-line-height)}.g-text_variant_code-1,.g-text_variant_code-2{font-family:var(--g-text-code-font-family);font-weight:var(--g-text-code-font-weight)}.g-text_variant_code-2{font-size:var(--g-text-code-2-font-size);line-height:var(--g-text-code-2-line-height)}.g-text_variant_code-3{font-size:var(--g-text-code-3-font-size);line-height:var(--g-text-code-3-line-height)}.g-text_variant_code-3,.g-text_variant_code-inline-1{font-family:var(--g-text-code-font-family);font-weight:var(--g-text-code-font-weight)}.g-text_variant_code-inline-1{font-size:var(--g-text-code-inline-1-font-size);line-height:var(--g-text-code-inline-1-line-height)}.g-text_variant_code-inline-2{font-size:var(--g-text-code-inline-2-font-size);line-height:var(--g-text-code-inline-2-line-height)}.g-text_variant_code-inline-2,.g-text_variant_code-inline-3{font-family:var(--g-text-code-font-family);font-weight:var(--g-text-code-font-weight)}.g-text_variant_code-inline-3{font-size:var(--g-text-code-inline-3-font-size);line-height:var(--g-text-code-inline-3-line-height)}.g-text_variant_body-1{font-size:var(--g-text-body-1-font-size);line-height:var(--g-text-body-1-line-height)}.g-text_variant_body-1,.g-text_variant_body-2{font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight)}.g-text_variant_body-2{font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height)}.g-text_variant_body-3{font-size:var(--g-text-body-3-font-size);line-height:var(--g-text-body-3-line-height)}.g-text_variant_body-3,.g-text_variant_body-short{font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight)}.g-text_variant_body-short{font-size:var(--g-text-body-short-font-size);line-height:var(--g-text-body-short-line-height)}.g-text_variant_caption-1{font-size:var(--g-text-caption-1-font-size);line-height:var(--g-text-caption-1-line-height)}.g-text_variant_caption-1,.g-text_variant_caption-2{font-family:var(--g-text-caption-font-family);font-weight:var(--g-text-caption-font-weight)}.g-text_variant_caption-2{font-size:var(--g-text-caption-2-font-size);line-height:var(--g-text-caption-2-line-height)}.g-text_variant_header-1{font-size:var(--g-text-header-1-font-size);line-height:var(--g-text-header-1-line-height)}.g-text_variant_header-1,.g-text_variant_header-2{font-family:var(--g-text-header-font-family);font-weight:var(--g-text-header-font-weight)}.g-text_variant_header-2{font-size:var(--g-text-header-2-font-size);line-height:var(--g-text-header-2-line-height)}.g-text_variant_subheader-1{font-size:var(--g-text-subheader-1-font-size);line-height:var(--g-text-subheader-1-line-height)}.g-text_variant_subheader-1,.g-text_variant_subheader-2{font-family:var(--g-text-subheader-font-family);font-weight:var(--g-text-subheader-font-weight)}.g-text_variant_subheader-2{font-size:var(--g-text-subheader-2-font-size);line-height:var(--g-text-subheader-2-line-height)}.g-text_variant_subheader-3{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height)}.g-text_ellipsis{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.g-text_ellipsis-lines{-webkit-box-orient:vertical;-webkit-line-clamp:2;align-self:center;display:-webkit-box;overflow:hidden;white-space:normal}.g-text_ws_nowrap{white-space:nowrap}.g-text_ws_break-spaces{white-space:break-spaces}.g-text_wb_break-all{word-break:break-all}.g-text_wb_break-word{word-break:break-word}.g-clipboard-button__icon{pointer-events:none}.g-icon{line-height:0;vertical-align:top}.g-button{--_--text-color:var(--g-color-text-primary);--_--text-color-hover:var(--_--text-color);--_--background-color:#0000;--_--background-color-hover:var(--g-color-base-simple-hover);--_--border-width:0;--_--border-color:currentColor;--_--focus-outline-color:var(--g-color-line-focus);--_--focus-outline-offset:0;--_--font-size:var(--g-text-body-1-font-size);-webkit-tap-highlight-color:rgba(0,0,0,0);background:none;background:#0000;border:none;box-sizing:border-box;color:inherit;color:var(--g-button-text-color,var(--_--text-color));cursor:pointer;display:inline-flex;font-family:var(--g-text-body-font-family);font-size:inherit;font-size:var(--g-button-font-size,var(--_--font-size));font-weight:var(--g-text-body-font-weight);gap:var(--g-button-icon-offset,var(--_--icon-offset));height:var(--g-button-height,var(--_--height));justify-content:center;line-height:var(--g-button-height,var(--_--height));outline:none;overflow:visible;padding:0;padding:0 var(--g-button-padding,var(--_--padding));position:relative;text-align:center;text-decoration:none;touch-action:manipulation;transform:scale(1);transition:transform .1s ease-out,color .15s linear;-webkit-user-select:none;user-select:none;white-space:nowrap}.g-button:before{background-color:var(--g-button-background-color,var(--_--background-color));border:var(--g-button-border-width,var(--_--border-width)) var(--g-button-border-style,solid) var(--g-button-border-color,var(--_--border-color));content:"";inset:0;position:absolute;transition:background-color .15s linear;z-index:-1}.g-button:hover{color:var(--g-button-text-color-hover,var(--_--text-color-hover))}.g-button:hover:before{background-color:var(--g-button-background-color-hover,var(--_--background-color-hover))}.g-button:focus-visible:before{outline:var(--g-button-focus-outline-color,var(--_--focus-outline-color)) var(--g-button-focus-outline-style,solid) var(--g-button-focus-outline-width,2px);outline-offset:var(--g-button-focus-outline-offset,var(--_--focus-outline-offset))}.g-button:after{content:"";inset:0;position:absolute;transform:scale(1);transition:none;z-index:-1}.g-button:active{transform:scale(.96);transition:none}.g-button:active:after{transform:scale(1.042)}.g-button_size_xs{--_--height:20px;--_--border-radius:var(--g-border-radius-xs);--_--padding:6px;--_--icon-size:12px;--_--icon-offset:4px}.g-button_size_s{--_--height:24px;--_--border-radius:var(--g-border-radius-s);--_--padding:8px;--_--icon-size:16px;--_--icon-offset:4px}.g-button_size_m{--_--height:28px;--_--border-radius:var(--g-border-radius-m);--_--padding:12px;--_--icon-size:16px;--_--icon-offset:8px}.g-button_size_l{--_--height:36px;--_--border-radius:var(--g-border-radius-l);--_--padding:16px;--_--icon-size:16px;--_--icon-offset:8px}.g-button_size_xl{--_--height:44px;--_--border-radius:var(--g-border-radius-xl);--_--padding:24px;--_--icon-size:20px;--_--icon-offset:12px;--_--font-size:var(--g-text-body-2-font-size)}.g-button_view_normal{--_--background-color:var(--g-color-base-generic);--_--background-color-hover:var(--g-color-base-generic-hover)}.g-button_view_action{--_--text-color:var(--g-color-text-brand-contrast);--_--background-color:var(--g-color-base-brand);--_--background-color-hover:var(--g-color-base-brand-hover);--_--focus-outline-color:var(--g-color-base-brand);--_--focus-outline-offset:1px}.g-button_view_outlined{--_--border-width:1px;--_--border-color:var(--g-color-line-generic)}.g-button_view_outlined-info{--_--text-color:var(--g-color-text-info);--_--border-width:1px;--_--border-color:var(--g-color-line-info)}.g-button_view_outlined-success{--_--text-color:var(--g-color-text-positive);--_--border-width:1px;--_--border-color:var(--g-color-line-positive)}.g-button_view_outlined-warning{--_--text-color:var(--g-color-text-warning);--_--border-width:1px;--_--border-color:var(--g-color-line-warning)}.g-button_view_outlined-danger{--_--text-color:var(--g-color-text-danger);--_--border-width:1px;--_--border-color:var(--g-color-line-danger)}.g-button_view_outlined-utility{--_--text-color:var(--g-color-text-utility);--_--border-width:1px;--_--border-color:var(--g-color-line-utility)}.g-button_view_outlined-action{--_--text-color:var(--g-color-text-brand);--_--border-width:1px;--_--border-color:var(--g-color-line-brand)}.g-button_view_raised{--_--background-color-hover:var(--g-color-base-float-hover);background:var(--g-color-base-float)}.g-button_view_raised:before{box-shadow:0 3px 5px var(--g-color-sfx-shadow)}.g-button_view_raised:active:before{box-shadow:0 1px 2px var(--g-color-sfx-shadow)}.g-button_view_flat-secondary{--_--text-color:var(--g-color-text-secondary);--_--text-color-hover:var(--g-color-text-primary)}.g-button_view_flat-info{--_--text-color:var(--g-color-text-info)}.g-button_view_flat-success{--_--text-color:var(--g-color-text-positive)}.g-button_view_flat-warning{--_--text-color:var(--g-color-text-warning)}.g-button_view_flat-danger{--_--text-color:var(--g-color-text-danger)}.g-button_view_flat-utility{--_--text-color:var(--g-color-text-utility)}.g-button_view_flat-action{--_--text-color:var(--g-color-text-brand)}.g-button_view_normal-contrast{--_--text-color:var(--g-color-text-dark-primary);--_--background-color:var(--g-color-base-light);--_--background-color-hover:var(--g-color-base-light-hover);--_--focus-outline-color:var(--g-color-line-light)}.g-button_view_normal-contrast.g-button_loading{--_--background-color-hover:var(--g-color-base-simple-hover)}.g-button_view_outlined-contrast{--_--text-color:var(--g-color-text-light-primary);--_--background-color-hover:var(--g-color-base-light-simple-hover);--_--border-width:1px;--_--border-color:var(--g-color-line-light);--_--focus-outline-color:var(--g-color-line-light)}.g-button_view_flat-contrast{--_--text-color:var(--g-color-text-light-primary);--_--background-color-hover:var(--g-color-base-light-simple-hover);--_--focus-outline-color:var(--g-color-line-light)}.g-button.g-button_pin_round-round.g-button{border-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-brick.g-button{border-radius:0}.g-button.g-button_pin_clear-clear.g-button{border-inline:0;border-radius:0}.g-button.g-button_pin_circle-circle.g-button{border-radius:100px}.g-button.g-button_pin_round-brick.g-button{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-round.g-button{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_round-clear.g-button{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-inline-end:0;border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_clear-round.g-button{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-inline-start:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_brick-clear.g-button{border-inline-end:0;border-radius:0}.g-button.g-button_pin_clear-brick.g-button{border-inline-start:0;border-radius:0}.g-button.g-button_pin_circle-brick.g-button{border-end-end-radius:0;border-end-start-radius:100px;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_brick-circle.g-button{border-end-end-radius:100px;border-end-start-radius:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_circle-clear.g-button{border-end-end-radius:0;border-end-start-radius:100px;border-inline-end:0;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_clear-circle.g-button{border-end-end-radius:100px;border-end-start-radius:0;border-inline-start:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_round-round:before{border-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-brick:before{border-radius:0}.g-button.g-button_pin_clear-clear:before{border-inline:0;border-radius:0}.g-button.g-button_pin_circle-circle:before{border-radius:100px}.g-button.g-button_pin_round-brick:before{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-round:before{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_round-clear:before{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-inline-end:0;border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_clear-round:before{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-inline-start:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_brick-clear:before{border-inline-end:0;border-radius:0}.g-button.g-button_pin_clear-brick:before{border-inline-start:0;border-radius:0}.g-button.g-button_pin_circle-brick:before{border-end-end-radius:0;border-end-start-radius:100px;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_brick-circle:before{border-end-end-radius:100px;border-end-start-radius:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_circle-clear:before{border-end-end-radius:0;border-end-start-radius:100px;border-inline-end:0;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_clear-circle:before{border-end-end-radius:100px;border-end-start-radius:0;border-inline-start:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_round-round:after{border-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-brick:after{border-radius:0}.g-button.g-button_pin_clear-clear:after{border-inline:0;border-radius:0}.g-button.g-button_pin_circle-circle:after{border-radius:100px}.g-button.g-button_pin_round-brick:after{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-round:after{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_round-clear:after{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-inline-end:0;border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_clear-round:after{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-inline-start:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_brick-clear:after{border-inline-end:0;border-radius:0}.g-button.g-button_pin_clear-brick:after{border-inline-start:0;border-radius:0}.g-button.g-button_pin_circle-brick:after{border-end-end-radius:0;border-end-start-radius:100px;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_brick-circle:after{border-end-end-radius:100px;border-end-start-radius:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_circle-clear:after{border-end-end-radius:0;border-end-start-radius:100px;border-inline-end:0;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_clear-circle:after{border-end-end-radius:100px;border-end-start-radius:0;border-inline-start:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button__text{display:inline-block;white-space:nowrap}.g-button__icon{display:inline-block;height:var(--g-button-height,var(--_--height));margin:0 calc((var(--g-button-height, var(--_--height)) - var(--g-button-icon-size, var(--_--icon-size)))/2*-1);position:relative;width:var(--g-button-height,var(--_--height))}.g-button__icon:after{content:" ";visibility:hidden}.g-button__icon-inner{align-items:center;display:flex;inset:0;justify-content:center;position:absolute}.g-button__icon_side_start{order:-1}.g-button__icon_side_end{order:1}.g-button__icon:only-child{margin:0}.g-button:has(.g-button__icon:only-child){--_--padding:0}.g-button:has(.g-button__icon:only-child):not(.g-button_width_max){width:var(--g-button-height,var(--_--height))}.g-button_selected:not(.g-button_view_outlined-contrast){--_--border-width:0}.g-button_selected:not(.g-button_view_normal-contrast,.g-button_view_flat-contrast,.g-button_view_outlined-contrast){--_--text-color:var(--g-color-text-brand-heavy);--_--background-color:var(--g-color-base-selection);--_--background-color-hover:var(--g-color-base-selection-hover)}.g-button_selected.g-button_view_flat-info,.g-button_selected.g-button_view_outlined-info{--_--text-color:var(--g-color-text-info-heavy);--_--background-color:var(--g-color-base-info-light);--_--background-color-hover:var(--g-color-base-info-light-hover)}.g-button_selected.g-button_view_flat-success,.g-button_selected.g-button_view_outlined-success{--_--text-color:var(--g-color-text-positive-heavy);--_--background-color:var(--g-color-base-positive-light);--_--background-color-hover:var(--g-color-base-positive-light-hover)}.g-button_selected.g-button_view_flat-warning,.g-button_selected.g-button_view_outlined-warning{--_--text-color:var(--g-color-text-warning-heavy);--_--background-color:var(--g-color-base-warning-light);--_--background-color-hover:var(--g-color-base-warning-light-hover)}.g-button_selected.g-button_view_flat-danger,.g-button_selected.g-button_view_outlined-danger{--_--text-color:var(--g-color-text-danger-heavy);--_--background-color:var(--g-color-base-danger-light);--_--background-color-hover:var(--g-color-base-danger-light-hover)}.g-button_selected.g-button_view_flat-utility,.g-button_selected.g-button_view_outlined-utility{--_--text-color:var(--g-color-text-utility-heavy);--_--background-color:var(--g-color-base-utility-light);--_--background-color-hover:var(--g-color-base-utility-light-hover)}.g-button_disabled{cursor:default;pointer-events:none}.g-button_disabled:not(.g-button_loading){--_--text-color:var(--g-color-text-hint);--_--background-color:var(--g-color-base-generic-accent-disabled);--_--background-color-hover:var(--g-color-base-generic-accent-disabled);--_--border-width:0}.g-button_disabled:not(.g-button_loading):is(.g-button_view_normal-contrast,.g-button_view_outlined-contrast){--_--text-color:var(--g-color-text-light-secondary);--_--background-color:var(--g-color-base-light-disabled);--_--background-color-hover:var(--g-color-base-light-disabled)}.g-button_disabled:not(.g-button_loading):is(.g-button_view_flat,.g-button_view_flat-secondary,.g-button_view_flat-info,.g-button_view_flat-success,.g-button_view_flat-warning,.g-button_view_flat-danger,.g-button_view_flat-utility,.g-button_view_flat-action,.g-button_view_flat-contrast){--_--text-color:var(--g-color-text-hint);--_--background-color:#0000;--_--background-color-hover:#0000}.g-button_disabled:not(.g-button_loading).g-button_view_flat-contrast{--_--text-color:var(--g-color-text-light-hint)}.g-button_disabled:active{transform:scale(1)}.g-button_loading:before{animation:g-loading-animation .5s linear infinite;background-clip:padding-box;background-image:repeating-linear-gradient(-45deg,var(--g-button-background-color,var(--_--background-color)),var(--g-button-background-color,var(--_--background-color)) 4px,var(--g-button-background-color-hover,var(--_--background-color-hover)) 4px,var(--g-button-background-color-hover,var(--_--background-color-hover)) 8px);background-size:150%}.g-button_width_auto{max-width:100%}.g-button_width_max{width:100%}.g-button_width_auto .g-button__text,.g-button_width_max .g-button__text{display:block;overflow:hidden;text-overflow:ellipsis}.g-action-tooltip{--g-popup-border-width:0;--g-popup-background-color:var(--g-color-base-float-heavy)}.g-action-tooltip__content{box-sizing:border-box;color:var(--g-color-text-light-primary);max-width:300px;padding:6px 12px}.g-action-tooltip__heading{align-items:baseline;display:flex;justify-content:space-between}.g-action-tooltip__title{color:var(--g-color-text-light-primary)}.g-action-tooltip__hotkey{margin-inline-start:8px}.g-action-tooltip__description{color:var(--g-color-text-light-secondary);margin-block-start:4px}.g-popup{--_--background-color:var(--g-popup-background-color,var(--g-color-base-float));--_--border-color:var(--g-popup-border-color,var(--g-color-line-generic-solid));--_--border-width:var(--g-popup-border-width,1px);visibility:hidden;z-index:1000}.g-popup_exit_active,.g-popup_open{visibility:visible}.g-popup_exit_active[data-popper-placement*=bottom] .g-popup__content{animation-name:g-popup-bottom}.g-popup_exit_active[data-popper-placement*=top] .g-popup__content{animation-name:g-popup-top}.g-popup_exit_active[data-popper-placement*=left] .g-popup__content{animation-name:g-popup-left}.g-popup_exit_active[data-popper-placement*=right] .g-popup__content{animation-name:g-popup-right}.g-popup_appear_active[data-popper-placement*=bottom] .g-popup__content,.g-popup_enter_active[data-popper-placement*=bottom] .g-popup__content{animation-name:g-popup-bottom-open}.g-popup_appear_active[data-popper-placement*=top] .g-popup__content,.g-popup_enter_active[data-popper-placement*=top] .g-popup__content{animation-name:g-popup-top-open}.g-popup_appear_active[data-popper-placement*=left] .g-popup__content,.g-popup_enter_active[data-popper-placement*=left] .g-popup__content{animation-name:g-popup-left-open}.g-popup_appear_active[data-popper-placement*=right] .g-popup__content,.g-popup_enter_active[data-popper-placement*=right] .g-popup__content{animation-name:g-popup-right-open}.g-popup[data-popper-placement*=bottom] .g-popup__arrow{inset-block-start:-9px}.g-popup[data-popper-placement*=top] .g-popup__arrow{inset-block-end:-9px}.g-popup[data-popper-placement*=top] .g-popup__arrow-content{transform:rotate(180deg)}.g-popup[data-popper-placement*=left] .g-popup__arrow{right:-9px}.g-popup[data-popper-placement*=left] .g-popup__arrow-content{transform:rotate(90deg)}.g-popup[data-popper-placement*=right] .g-popup__arrow{left:-9px}.g-popup[data-popper-placement*=right] .g-popup__arrow-content{transform:rotate(-90deg)}.g-popup__content{animation-duration:.1s;animation-fill-mode:forwards;animation-timing-function:ease-out;background-color:var(--_--background-color);border-radius:4px;box-shadow:0 0 0 var(--_--border-width) var(--_--border-color),0 8px 20px var(--_--border-width) var(--g-color-sfx-shadow);outline:none;position:relative}.g-popup__content>.g-popup__arrow+*,.g-popup__content>:first-child:not(.g-popup__arrow){border-start-end-radius:inherit;border-start-start-radius:inherit}.g-popup__content>:last-child{border-end-end-radius:inherit;border-end-start-radius:inherit}.g-popup__arrow-content{display:flex;height:18px;overflow:hidden;position:relative;width:18px}.g-popup__arrow-circle-wrapper{background-color:initial;height:9px;overflow:hidden;position:relative;width:9px}.g-popup__arrow-circle{border-radius:50%;box-shadow:inset 0 0 0 calc(5px - var(--_--border-width)) var(--_--background-color),inset 0 0 0 5px var(--_--border-color);box-sizing:border-box;height:30px;position:absolute;width:28px}.g-popup__arrow-circle_left{inset-block-end:-4px;inset-inline-end:-5px}.g-popup__arrow-circle_right{inset-block-end:-4px;inset-inline-start:-5px}@keyframes g-popup-bottom{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(10px)}}@keyframes g-popup-bottom-open{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes g-popup-top{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-10px)}}@keyframes g-popup-top-open{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes g-popup-left{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(-10px)}}@keyframes g-popup-left-open{0%{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:translateX(0)}}@keyframes g-popup-right{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(10px)}}@keyframes g-popup-right-open{0%{opacity:0;transform:translateX(10px)}to{opacity:1;transform:translateX(0)}}.g-portal__theme-wrapper{display:contents}.g-hotkey{border-radius:4px;padding:1px 5px}.g-hotkey,.g-hotkey kbd{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height)}.g-hotkey_view_light{background-color:var(--g-color-base-generic)}.g-hotkey_view_light .g-hotkey__plus{color:var(--g-color-text-hint)}.g-hotkey_view_dark{background-color:var(--g-color-base-light-simple-hover);color:var(--g-color-text-light-complementary)}.g-hotkey_view_dark .g-hotkey__plus{color:var(--g-color-text-light-hint)}.g-help-mark__button{background:none;border:none;color:inherit;color:var(--g-color-text-hint);cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0}.g-help-mark__button:focus-visible{border-radius:50%;outline:2px solid var(--g-color-line-focus)}.g-link{-webkit-tap-highlight-color:rgba(0,0,0,0);border-radius:var(--g-focus-border-radius);cursor:pointer;text-decoration:none;touch-action:manipulation}.g-link:focus-visible{outline:2px solid var(--g-color-line-focus)}.g-link_view_normal{color:var(--g-color-text-link)}.g-link_view_primary{color:var(--g-color-text-primary)}.g-link_view_secondary{color:var(--g-color-text-secondary)}.g-link_view_normal:hover,.g-link_view_primary:hover,.g-link_view_secondary:hover{color:var(--g-color-text-link-hover)}.g-link_visitable:visited{color:var(--g-color-text-link-visited)}.g-link_visitable:visited:hover{color:var(--g-color-text-link-visited-hover)}.g-link_underline{text-decoration:underline}.g-popover{display:inline-block;position:relative}.g-popover:not(.g-popover_disabled){cursor:pointer}.g-popover__handler{display:inline-block}.g-popover__tooltip{--_--padding:16px;--_--close-offset:8px;--_--close-size:24px}.g-popover__tooltip-popup-content{box-sizing:border-box;cursor:default;max-width:var(--g-popover-max-width,300px);min-height:40px;padding:var(--g-popover-padding,var(--_--padding))}.g-popover__tooltip-title{display:inline-flex;font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height);margin:0 0 12px}.g-popover__tooltip-buttons{display:flex;flex-wrap:wrap;gap:5px;margin-block-start:20px}.g-popover__tooltip-button{flex:1 1}.g-popover__tooltip-close{inset-block-start:var(--_--close-offset);inset-inline-end:var(--_--close-offset);position:absolute}.g-popover__tooltip-content{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height);overflow-wrap:break-word}.g-popover__tooltip-content_secondary{opacity:.7}.g-popover__tooltip-links>*{margin-block-start:8px}.g-popover__tooltip-links>:first-child{margin-block-start:0}.g-popover__tooltip-content+.g-popover__tooltip-links>:first-child{margin-block-start:12px}.g-popover__tooltip-link{display:inline-block;font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height)}.g-popover__tooltip_theme_announcement .g-popover__tooltip_theme_announcement,.g-popover__tooltip_theme_announcement.g-popover__tooltip_theme_info,.g-popover__tooltip_theme_info .g-popover__tooltip_theme_announcement,.g-popover__tooltip_theme_info.g-popover__tooltip_theme_info{color:var(--g-color-text-primary)}.g-popover__tooltip_force-links-appearance.g-popover__tooltip_theme_info .g-popover__tooltip-content a:not(.g-button),.g-popover__tooltip_theme_announcement .g-popover__tooltip-content a:not(.g-button){color:var(--g-color-text-link);text-decoration:none}.g-popover__tooltip_force-links-appearance.g-popover__tooltip_theme_info .g-popover__tooltip-content a:not(.g-button):hover,.g-popover__tooltip_theme_announcement .g-popover__tooltip-content a:not(.g-button):hover{color:var(--g-color-text-link-hover)}.g-popover__tooltip_theme_announcement{--g-popup-background-color:var(--g-color-base-simple-hover-solid);--g-popup-border-color:var(--g-color-base-simple-hover-solid)}.g-popover__tooltip_theme_special{--g-popup-background-color:var(--g-color-base-brand);--g-popup-border-color:var(--g-color-base-brand);color:var(--g-color-text-light-primary)}.g-popover__tooltip_theme_special .g-popover__tooltip-content a:not(.g-button){color:var(--g-color-text-light-primary);font-weight:var(--g-text-accent-font-weight)}.g-popover__tooltip_theme_special .g-popover__tooltip-content a:not(.g-button):hover{color:var(--g-color-text-light-secondary)}.g-popover__tooltip_theme_special .g-link{color:var(--g-color-text-light-primary)}.g-popover__tooltip_theme_special .g-link:hover{color:var(--g-color-text-light-secondary)}.g-popover__tooltip_size_l{--_--padding:24px}.g-popover__tooltip_size_l .g-popover__tooltip-title{font-family:var(--g-text-header-font-family);font-size:var(--g-text-header-1-font-size);font-weight:var(--g-text-header-font-weight);line-height:var(--g-text-header-1-line-height)}.g-popover__tooltip_size_l .g-popover__tooltip-content{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-popover__tooltip_with-close .g-popover__tooltip-content,.g-popover__tooltip_with-close .g-popover__tooltip-title{padding-inline-end:calc(var(--_--close-offset) + var(--_--close-size) - var(--_--padding))}.g-definition-list{--_--item-block-start:var(--g-spacing-4);--_--term-width:300px;margin:0}.g-definition-list__item{align-items:baseline;display:flex;gap:var(--g-spacing-1)}.g-definition-list__item+.g-definition-list__item{margin-block-start:var(--g-definition-list-item-gap,var(--_--item-block-start))}.g-definition-list__term-container{align-items:baseline;display:flex;flex:0 0 auto;max-width:var(--_--term-width);overflow:hidden;position:relative;width:var(--_--term-width)}.g-definition-list__term-wrapper{color:var(--g-color-text-secondary)}.g-definition-list__dots{border-block-end:1px dotted var(--g-color-line-generic-active);box-sizing:border-box;flex:1 0 auto;margin:0 2px;min-width:25px}.g-definition-list__definition{flex:0 1 auto;margin:0}.g-definition-list_responsive .g-definition-list__term-container{--_--term-width:auto;flex:1 0 min-content}.g-definition-list_vertical{--_--item-block-start:var(--g-spacing-3);--_--term-width:auto}.g-definition-list_vertical .g-definition-list__term-container{flex:1 0 auto}.g-definition-list_vertical .g-definition-list__item{flex-direction:column;gap:var(--g-spacing-half)}.g-definition-list__copy-container{align-items:center;display:inline-flex;margin-inline-end:calc(var(--g-spacing-7)*-1);padding-inline-end:var(--g-spacing-7);position:relative}.g-definition-list__copy-container:hover .g-definition-list__copy-button{opacity:1}.g-definition-list__copy-button{display:inline-block;inset-inline-end:0;margin-inline-start:10px;opacity:0;position:absolute}.g-definition-list__copy-button:focus-visible{opacity:1}.g-switch{position:relative}.g-switch__control{cursor:pointer;opacity:0}.g-switch__indicator{display:inline-block;position:relative}.g-switch__indicator:before{background-color:var(--g-color-base-generic-medium);content:"";inset:0;position:absolute;transition:background .1s linear}.g-switch__indicator:after{content:" ";visibility:hidden}.g-switch__slider{background-color:var(--g-color-base-background);border-radius:50%;content:"";position:absolute;transition:transform .15s ease-out}.g-switch__outline{background:none;height:100%;inset-block-start:0;inset-inline-start:0;pointer-events:none;position:absolute;width:100%}.g-switch__control:focus-visible+.g-switch__outline{outline:2px solid var(--g-color-line-focus)}.g-switch_size_m .g-switch__indicator,.g-switch_size_m .g-switch__indicator:before,.g-switch_size_m .g-switch__outline{border-radius:10px;height:20px;width:36px}.g-switch_size_m .g-switch__slider{height:16px;inset-block-start:2px;inset-inline-start:2px;width:16px}.g-switch_size_m .g-switch__text{margin-block-start:3px}.g-switch_size_l .g-switch__indicator,.g-switch_size_l .g-switch__indicator:before,.g-switch_size_l .g-switch__outline{border-radius:12px;height:24px;width:42px}.g-switch_size_l .g-switch__slider{height:18px;inset-block-start:3px;inset-inline-start:3px;width:18px}.g-switch_size_l .g-switch__text{margin-block-start:4px}.g-switch:hover .g-switch__indicator:before{background-color:var(--g-color-base-generic-medium-hover)}.g-switch_checked .g-switch__slider{--_--translate-x:calc(100%*var(--g-flow-direction));transform:translateX(var(--_--translate-x))}.g-switch_checked .g-switch__indicator:before,.g-switch_checked:hover .g-switch__indicator:before{background-color:var(--g-color-base-brand)}.g-switch_disabled .g-switch__indicator:before{background-color:var(--g-color-base-generic-accent-disabled)}.g-switch_disabled.g-switch_checked .g-switch__indicator:before{background-color:var(--g-color-base-brand);opacity:.5}.g-control-label{-webkit-tap-highlight-color:rgba(0,0,0,0);color:var(--g-color-text-primary);cursor:pointer;display:inline-flex;font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight);touch-action:manipulation;-webkit-user-select:none;user-select:none}.g-control-label_disabled{cursor:default;pointer-events:none}.g-control-label_size_m{font-size:var(--g-text-body-1-font-size);line-height:15px}.g-control-label_size_l{font-size:var(--g-text-body-2-font-size);line-height:18px}.g-control-label__indicator{flex-shrink:0}.g-control-label__text{flex-grow:1;white-space:normal}.g-control-label_disabled .g-control-label__text{opacity:.6}.g-control-label_size_m .g-control-label__text{margin-inline-start:5px}.g-control-label_size_l .g-control-label__text{margin-inline-start:7px}.g-radio-button{--_--border-radius-inner:calc(var(--_--border-radius) - 3px);background-color:var(--g-color-base-generic);border-radius:var(--_--border-radius);box-sizing:border-box;display:inline-flex;flex-direction:row;font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight);position:relative}.g-radio-button__plate{inset-block:0;position:absolute;transition:left .2s,width .2s}.g-radio-button__plate[hidden]{display:none}.g-radio-button__option{border-radius:var(--_--border-radius-inner);cursor:pointer;flex:1 1 auto;font-size:var(--g-text-body-1-font-size);text-align:center;transform:scale(1);transition:color .15s linear;-webkit-user-select:none;user-select:none}.g-radio-button__option-outline{border-radius:var(--_--border-radius-inner);content:"";inset:3px;position:absolute;z-index:-1}.g-radio-button__option-control{border:none;cursor:inherit;height:100%;inset-block-start:0;inset-inline-start:0;margin:0;opacity:0;outline:none;padding:0;position:absolute;width:100%}.g-radio-button__option-control:focus-visible+.g-radio-button__option-outline{outline:2px solid var(--g-color-line-focus)}.g-radio-button__option-text{color:var(--g-color-text-complementary);display:inline-block;white-space:nowrap}.g-radio-button__option-text_icon{align-items:center;display:flex;height:100%}.g-radio-button__option:hover .g-radio-button__option-text,.g-radio-button__option_checked .g-radio-button__option-text{color:var(--g-color-text-primary)}.g-radio-button__option_checked{cursor:default}.g-radio-button__option_disabled{cursor:default;pointer-events:none}.g-radio-button__option_disabled .g-radio-button__option-text{color:var(--g-color-text-hint)}.g-radio-button__option:before,.g-radio-button__plate:before{border-radius:var(--_--border-radius-inner);inset:3px;position:absolute}.g-radio-button__option:before{z-index:-1}.g-radio-button__plate:before,.g-radio-button__plate[hidden]~.g-radio-button__option_checked:before{background-color:var(--g-color-base-background);content:""}.g-radio-button_size_s{--_--border-radius:var(--g-border-radius-s)}.g-radio-button_size_s .g-radio-button__option{height:24px;line-height:24px}.g-radio-button_size_s .g-radio-button__option-text{margin:0 10px}.g-radio-button_size_m{--_--border-radius:var(--g-border-radius-m)}.g-radio-button_size_m .g-radio-button__option{height:28px;line-height:28px}.g-radio-button_size_m .g-radio-button__option-text{margin:0 13px}.g-radio-button_size_l{--_--border-radius:var(--g-border-radius-l)}.g-radio-button_size_l .g-radio-button__option{height:36px;line-height:36px}.g-radio-button_size_l .g-radio-button__option-text{margin:0 18px}.g-radio-button_size_xl{--_--border-radius:var(--g-border-radius-xl)}.g-radio-button_size_xl .g-radio-button__option{font-size:var(--g-text-body-2-font-size);height:44px;line-height:44px}.g-radio-button_size_xl .g-radio-button__option-text{margin:0 25px}.g-radio-button_width_auto{max-width:100%}.g-radio-button_width_max{width:100%}.g-radio-button_width_auto .g-radio-button__option,.g-radio-button_width_max .g-radio-button__option{overflow:hidden}.g-radio-button_width_auto .g-radio-button__option-text,.g-radio-button_width_max .g-radio-button__option-text{display:block;overflow:hidden;text-overflow:ellipsis}.g-label{--_--bg-color:none;--_--bg-color-hover:none;--_--text-color:none;align-items:center;background-color:var(--_--bg-color);border-radius:var(--_--border-radius);box-sizing:border-box;color:var(--_--text-color);display:inline-flex;height:var(--_--height);isolation:isolate;position:relative;transition-duration:.15s;transition-property:opacity,color,background-color;transition-timing-function:ease-in-out}.g-label__text{align-items:baseline;display:flex;font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height);line-height:var(--_--height);margin:0 var(--_--margin-inline);overflow:hidden;text-align:center;white-space:nowrap;width:100%}.g-label__content,.g-label__key{overflow:hidden;text-overflow:ellipsis}.g-label__value{display:flex;opacity:.7;overflow:hidden}.g-label__separator{margin:0 4px}.g-label__main-button{background:none;border:none;border-radius:inherit;color:inherit;cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0;z-index:1}.g-label__main-button:empty{inset:0;position:absolute}.g-label__addon{align-items:center;border-radius:var(--_--border-radius);display:flex;height:var(--_--height);justify-content:center;width:var(--_--height)}.g-label__addon_side_end,.g-label__addon_side_start{inset-block-start:0;position:absolute}.g-label__addon_side_start{border-end-end-radius:0;border-start-end-radius:0;inset-inline-start:2px}.g-label__addon_side_end{border-end-start-radius:0;border-start-start-radius:0;inset-inline-end:0}.g-label__addon_type_button{background:none;background-color:initial;border:none;color:inherit;color:var(--_--text-color);cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,transform .1s ease-out;z-index:2}.g-label__addon_type_button:active{transform:scale(.96)}.g-label_size_xs{--_--height:20px;--_--border-radius:var(--g-border-radius-xs);--_--margin-inline:8px;--_--margin-addon-start:24px;--_--margin-addon-end:22px}.g-label_size_s{--_--height:24px;--_--border-radius:var(--g-border-radius-s);--_--margin-inline:10px;--_--margin-addon-start:28px;--_--margin-addon-end:26px}.g-label_size_m{--_--height:28px;--_--border-radius:var(--g-border-radius-m);--_--margin-inline:12px;--_--margin-addon-start:32px;--_--margin-addon-end:32px}.g-label_disabled{opacity:.7;pointer-events:none}.g-label_interactive{cursor:pointer}.g-label_theme_normal{--_--bg-color:var(--g-color-base-misc-light);--_--bg-color-hover:var(--g-color-base-misc-light-hover);--_--text-color:var(--g-color-text-misc-heavy)}.g-label_theme_success{--_--bg-color:var(--g-color-base-positive-light);--_--bg-color-hover:var(--g-color-base-positive-light-hover);--_--text-color:var(--g-color-text-positive-heavy)}.g-label_theme_info{--_--bg-color:var(--g-color-base-info-light);--_--bg-color-hover:var(--g-color-base-info-light-hover);--_--text-color:var(--g-color-text-info-heavy)}.g-label_theme_warning{--_--bg-color:var(--g-color-base-warning-light);--_--bg-color-hover:var(--g-color-base-warning-light-hover);--_--text-color:var(--g-color-text-warning-heavy)}.g-label_theme_danger{--_--bg-color:var(--g-color-base-danger-light);--_--bg-color-hover:var(--g-color-base-danger-light-hover);--_--text-color:var(--g-color-text-danger-heavy)}.g-label_theme_utility{--_--bg-color:var(--g-color-base-utility-light);--_--bg-color-hover:var(--g-color-base-utility-light-hover);--_--text-color:var(--g-color-text-utility-heavy)}.g-label_theme_unknown{--_--bg-color:var(--g-color-base-neutral-light);--_--bg-color-hover:var(--g-color-base-neutral-light-hover);--_--text-color:var(--g-color-text-complementary)}.g-label_theme_clear{--_--bg-color:#0000;--_--bg-color-hover:var(--g-color-base-simple-hover);--_--text-color:var(--g-color-text-complementary);box-shadow:inset 0 0 0 1px var(--g-color-line-generic)}.g-label:has(.g-label__addon_side_start) .g-label__text{margin-inline-start:var(--_--margin-addon-start)}.g-label:has(.g-label__addon_side_end) .g-label__text{margin-inline-end:var(--_--margin-addon-end)}.g-label__addon_type_button:hover,.g-label_interactive:hover:not(:has(.g-label__addon_type_button:hover)){background-color:var(--_--bg-color-hover)}.g-label__addon_type_button:focus-visible,.g-label__main-button:focus-visible{outline:2px solid var(--g-color-line-focus)}.g-tabs{--_--vertical-item-padding:var(--g-tabs-vertical-item-padding,6px 20px);--_--vertical-item-height:var(--g-tabs-vertical-item-height,18px)}.g-tabs_size_m{--_--item-height:36px;--_--item-gap:24px;--_--item-border-width:2px}.g-tabs_size_m .g-tabs__item-counter,.g-tabs_size_m .g-tabs__item-title{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height)}.g-tabs_size_l{--_--item-height:40px;--_--item-gap:28px;--_--item-border-width:2px}.g-tabs_size_l .g-tabs__item-counter,.g-tabs_size_l .g-tabs__item-title{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-tabs_size_xl{--_--item-height:44px;--_--item-gap:32px;--_--item-border-width:3px}.g-tabs_size_xl .g-tabs__item-counter,.g-tabs_size_xl .g-tabs__item-title{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height)}.g-tabs__item{cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.g-tabs__item-content{align-items:center;border-radius:var(--g-focus-border-radius);display:flex}.g-tabs__item_overflow .g-tabs__item-content{min-width:0}.g-tabs__item-icon{margin-inline-end:8px}.g-tabs__item-title{white-space:nowrap}.g-tabs__item_overflow .g-tabs__item-title{overflow:hidden;text-overflow:ellipsis}.g-tabs__item-counter,.g-tabs__item-label{margin-inline-start:8px}.g-tabs__item-icon>svg{display:block}.g-tabs_direction_horizontal{align-items:flex-end;box-shadow:inset 0 calc(var(--g-tabs-border-width, 1px)*-1) 0 0 var(--g-color-line-generic);display:flex;flex-wrap:wrap;overflow:hidden}.g-tabs_direction_horizontal .g-tabs__item{align-items:center;border-block-end:var(--g-tabs-item-border-width,var(--_--item-border-width)) solid #0000;box-sizing:border-box;display:flex;height:var(--g-tabs-item-height,var(--_--item-height));padding-block-start:var(--_--item-border-width)}.g-tabs_direction_horizontal .g-tabs__item:focus-visible .g-tabs__item-content{outline:2px solid var(--g-color-line-focus);outline-offset:-2px}.g-tabs_direction_horizontal .g-tabs__item-meta{display:none}.g-tabs_direction_horizontal .g-tabs__item-title{color:var(--g-color-text-secondary)}.g-tabs_direction_horizontal .g-tabs__item-counter,.g-tabs_direction_horizontal .g-tabs__item-icon{color:var(--g-color-text-hint)}.g-tabs_direction_horizontal .g-tabs__item:focus-visible .g-tabs__item-title,.g-tabs_direction_horizontal .g-tabs__item:hover .g-tabs__item-title,.g-tabs_direction_horizontal .g-tabs__item_active .g-tabs__item-title{color:var(--g-color-text-primary)}.g-tabs_direction_horizontal .g-tabs__item:focus-visible .g-tabs__item-counter,.g-tabs_direction_horizontal .g-tabs__item:focus-visible .g-tabs__item-icon,.g-tabs_direction_horizontal .g-tabs__item:hover .g-tabs__item-counter,.g-tabs_direction_horizontal .g-tabs__item:hover .g-tabs__item-icon,.g-tabs_direction_horizontal .g-tabs__item_active .g-tabs__item-counter,.g-tabs_direction_horizontal .g-tabs__item_active .g-tabs__item-icon{color:var(--g-color-text-secondary)}.g-tabs_direction_horizontal .g-tabs__item_active,.g-tabs_direction_horizontal .g-tabs__item_active:focus-visible,.g-tabs_direction_horizontal .g-tabs__item_active:hover{border-color:var(--g-color-line-brand)}.g-tabs_direction_horizontal .g-tabs__item_disabled{pointer-events:none}.g-tabs_direction_horizontal .g-tabs__item_disabled .g-tabs__item-title{color:var(--g-color-text-hint)}.g-tabs_direction_horizontal>:not(:last-child){margin-inline-end:var(--g-tabs-item-gap,var(--_--item-gap))}.g-tabs_direction_vertical{display:flex;flex-direction:column}.g-tabs_direction_vertical .g-tabs__item{padding:var(--_--vertical-item-padding)}.g-tabs_direction_vertical .g-tabs__item-title{color:var(--g-color-text-primary);line-height:var(--_--vertical-item-height)}.g-tabs_direction_vertical .g-tabs__item-meta{color:var(--g-color-text-secondary);line-height:var(--_--vertical-item-height)}.g-tabs_direction_vertical .g-tabs__item-counter,.g-tabs_direction_vertical .g-tabs__item-icon{color:var(--g-color-text-secondary)}.g-tabs_direction_vertical .g-tabs__item:focus-visible,.g-tabs_direction_vertical .g-tabs__item:hover{background-color:var(--g-color-base-generic-hover)}.g-tabs_direction_vertical .g-tabs__item_active{background-color:var(--g-color-base-selection)}.g-tabs_direction_vertical .g-tabs__item_active:focus-visible,.g-tabs_direction_vertical .g-tabs__item_active:hover{background-color:var(--g-color-base-selection-hover)}.g-tabs_direction_vertical .g-tabs__item_disabled{pointer-events:none}.g-tabs_direction_vertical .g-tabs__item_disabled .g-tabs__item-title{color:var(--g-color-text-secondary)}.g-outer-additional-content{display:flex;justify-content:space-between;vertical-align:top}.g-outer-additional-content__error,.g-outer-additional-content__note{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height);margin-block-start:2px}.g-outer-additional-content__error{color:var(--g-color-text-danger)}.g-outer-additional-content__error:not(:last-child){margin-inline-end:var(--g-spacing-2)}.g-outer-additional-content__note{margin-inline-start:auto}.g-text-input{--_--text-color:var(--g-color-text-primary);--_--label-color:inherit;--_--placeholder-color:var(--g-color-text-hint);--_--background-color:#0000;--_--border-width:1px;--_--focus-outline-color:var(--g-text-input-focus-outline-color);display:inline-block;position:relative;width:100%}.g-text-input__content{background-color:var(--g-text-input-background-color,var(--_--background-color));border-color:var(--g-text-input-border-color,var(--_--border-color));border-style:solid;border-width:var(--g-text-input-border-width,var(--_--border-width));box-sizing:border-box;color:var(--g-text-input-text-color,var(--_--text-color));display:flex;overflow:hidden;width:100%}.g-text-input__content:hover{border-color:var(--g-text-input-border-color-hover,var(--_--border-color-hover))}.g-text-input__content:focus-within{border-color:var(--g-text-input-border-color-active,var(--_--border-color-active));outline:2px solid var(--g-text-input-focus-outline-color,var(--_--focus-outline-color));outline-offset:-1px}.g-text-input__control{background-color:initial;border:none;box-sizing:border-box;color:inherit;display:inline-block;flex-grow:1;font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight);height:var(--g-text-input-height);margin:0;padding:0;position:relative;vertical-align:top;width:100%}.g-text-input__control::placeholder{color:var(--g-text-input-placeholder-color,var(--_--placeholder-color));overflow:hidden;white-space:nowrap}.g-text-input__control:focus{outline:none}.g-text-input__control[type=number]{appearance:textfield}.g-text-input__label{box-sizing:border-box;color:var(--g-text-input-label-color,var(--_--label-color));overflow:hidden;position:absolute;text-overflow:ellipsis;white-space:nowrap;z-index:1}.g-text-input__clear{flex-shrink:0;margin:auto 0}.g-text-input__clear_size_m,.g-text-input__clear_size_s{margin-inline-end:1px}.g-text-input__clear_size_l,.g-text-input__clear_size_xl{margin-inline-end:2px}.g-text-input__error-icon{box-sizing:initial;color:var(--g-color-text-danger);padding-block:var(--_--error-icon-padding-block);padding-inline:var(--_--error-icon-padding-inline)}.g-text-input__additional-content{align-items:center;display:flex}.g-text-input_size_s{--_--error-icon-padding-block:5px;--_--error-icon-padding-inline:0 5px;--_--border-radius:var(--g-border-radius-s)}.g-text-input_size_s .g-text-input__control{--_--input-control-border-width:var( - --g-text-input-border-width,var(--g-text-area-border-width,1px) - );height:calc(24px - var(--_--input-control-border-width)*2);padding:3px 8px}.g-text-input_size_s .g-text-input__control,.g-text-input_size_s .g-text-input__label{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-short-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-short-line-height)}.g-text-input_size_s .g-text-input__label{font-weight:var(--g-text-accent-font-weight);padding-block:3px;padding-inline:8px 4px}.g-text-input_size_s.g-text-input_has-start-content .g-text-input__label{padding-inline-start:2px}.g-text-input_size_s .g-text-input__additional-content{height:22px}.g-text-input_size_s .g-text-input__additional-content_placement_start{padding-inline-start:1px}.g-text-input_size_s .g-text-input__additional-content_placement_end{padding-inline-end:1px}.g-text-input_size_m{--_--error-icon-padding-block:5px;--_--error-icon-padding-inline:0 5px;--_--border-radius:var(--g-border-radius-m)}.g-text-input_size_m .g-text-input__control{--_--input-control-border-width:var( - --g-text-input-border-width,var(--g-text-area-border-width,1px) - );height:calc(28px - var(--_--input-control-border-width)*2);padding:5px 8px}.g-text-input_size_m .g-text-input__control,.g-text-input_size_m .g-text-input__label{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-short-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-short-line-height)}.g-text-input_size_m .g-text-input__label{font-weight:var(--g-text-accent-font-weight);padding-block:5px;padding-inline:8px 4px}.g-text-input_size_m.g-text-input_has-start-content .g-text-input__label{padding-inline-start:2px}.g-text-input_size_m .g-text-input__additional-content{height:26px}.g-text-input_size_m .g-text-input__additional-content_placement_start{padding-inline-start:1px}.g-text-input_size_m .g-text-input__additional-content_placement_end{padding-inline-end:1px}.g-text-input_size_l{--_--error-icon-padding-block:9px;--_--error-icon-padding-inline:0 9px;--_--border-radius:var(--g-border-radius-l)}.g-text-input_size_l .g-text-input__control{--_--input-control-border-width:var( - --g-text-input-border-width,var(--g-text-area-border-width,1px) - );height:calc(36px - var(--_--input-control-border-width)*2);padding:9px 12px}.g-text-input_size_l .g-text-input__control,.g-text-input_size_l .g-text-input__label{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-short-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-short-line-height)}.g-text-input_size_l .g-text-input__label{font-weight:var(--g-text-accent-font-weight);padding-block:9px;padding-inline:12px 4px}.g-text-input_size_l.g-text-input_has-start-content .g-text-input__label{padding-inline-start:3px}.g-text-input_size_l .g-text-input__additional-content{height:34px}.g-text-input_size_l .g-text-input__additional-content_placement_start{padding-inline-start:3px}.g-text-input_size_l .g-text-input__additional-content_placement_end{padding-inline-end:3px}.g-text-input_size_xl{--_--error-icon-padding-block:13px;--_--error-icon-padding-inline:0 13px;--_--border-radius:var(--g-border-radius-xl)}.g-text-input_size_xl .g-text-input__control{--_--input-control-border-width:var( - --g-text-input-border-width,var(--g-text-area-border-width,1px) - );height:calc(44px - var(--_--input-control-border-width)*2);padding:11px 12px}.g-text-input_size_xl .g-text-input__control,.g-text-input_size_xl .g-text-input__label{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-text-input_size_xl .g-text-input__label{font-weight:var(--g-text-accent-font-weight);padding-block:11px;padding-inline:12px 4px}.g-text-input_size_xl.g-text-input_has-start-content .g-text-input__label{padding-inline-start:3px}.g-text-input_size_xl .g-text-input__additional-content{height:42px}.g-text-input_size_xl .g-text-input__additional-content_placement_start{padding-inline-start:3px}.g-text-input_size_xl .g-text-input__additional-content_placement_end{padding-inline-end:3px}.g-text-input_view_normal{--_--border-color:var(--g-color-line-generic);--_--border-color-hover:var(--g-color-line-generic-hover);--_--border-color-active:var(--g-color-line-generic-active)}.g-text-input_view_clear{--_--border-color:#0000;--_--border-color-hover:#0000;--_--border-color-active:#0000;--_--border-radius:0}.g-text-input_view_clear .g-text-input__content{border-inline:0}.g-text-input_view_clear .g-text-input__control{padding-inline:0}.g-text-input.g-text-input_pin_round-round .g-text-input__content{border-radius:var(--g-text-input-border-radius,var(--_--border-radius))}.g-text-input.g-text-input_pin_brick-brick .g-text-input__content{border-radius:0}.g-text-input.g-text-input_pin_clear-clear .g-text-input__content{border-inline:0;border-radius:0}.g-text-input.g-text-input_pin_circle-circle .g-text-input__content{border-radius:100px}.g-text-input.g-text-input_pin_round-brick .g-text-input__content{border-end-end-radius:0;border-end-start-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-start-end-radius:0;border-start-start-radius:var(--g-text-input-border-radius,var(--_--border-radius))}.g-text-input.g-text-input_pin_brick-round .g-text-input__content{border-end-end-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-end-start-radius:0;border-start-end-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-text-input.g-text-input_pin_round-clear .g-text-input__content{border-end-end-radius:0;border-end-start-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-inline-end:0;border-start-end-radius:0;border-start-start-radius:var(--g-text-input-border-radius,var(--_--border-radius))}.g-text-input.g-text-input_pin_clear-round .g-text-input__content{border-end-end-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-end-start-radius:0;border-inline-start:0;border-start-end-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-text-input.g-text-input_pin_brick-clear .g-text-input__content{border-inline-end:0;border-radius:0}.g-text-input.g-text-input_pin_clear-brick .g-text-input__content{border-inline-start:0;border-radius:0}.g-text-input.g-text-input_pin_circle-brick .g-text-input__content{border-end-end-radius:0;border-end-start-radius:100px;border-start-end-radius:0;border-start-start-radius:100px}.g-text-input.g-text-input_pin_brick-circle .g-text-input__content{border-end-end-radius:100px;border-end-start-radius:0;border-start-end-radius:100px;border-start-start-radius:0}.g-text-input.g-text-input_pin_circle-clear .g-text-input__content{border-end-end-radius:0;border-end-start-radius:100px;border-inline-end:0;border-start-end-radius:0;border-start-start-radius:100px}.g-text-input.g-text-input_pin_clear-circle .g-text-input__content{border-end-end-radius:100px;border-end-start-radius:0;border-inline-start:0;border-start-end-radius:100px;border-start-start-radius:0}.g-text-input_disabled{--_--text-color:var(--g-color-text-hint);--_--background-color:var(--g-color-base-generic-accent-disabled);--_--border-color:#0000;--_--border-color-hover:#0000;--_--border-color-active:#0000}.g-text-input_has-scrollbar .g-text-input__clear{inset-inline-end:var(--g-scrollbar-width)}.g-text-input_has-start-content .g-text-input__control{padding-inline-start:2px}.g-text-input_has-end-content .g-text-input__control{padding-inline-end:2px}.g-text-input_has-unstable-end-content{--_--error-icon-padding-inline:0}.g-text-input_state_error.g-text-input_view_normal .g-text-input__content,.g-text-input_state_error.g-text-input_view_normal .g-text-input__content:focus-within,.g-text-input_state_error.g-text-input_view_normal .g-text-input__content:hover{border-color:var(--g-color-line-danger)}.g-text-input_state_error.g-text-input_view_normal .g-text-input__content:focus-within{--_--focus-outline-color:var(--g-color-line-danger)}.g-text-input_state_error.g-text-input_view_clear .g-text-input__content,.g-text-input_state_error.g-text-input_view_clear .g-text-input__content:focus-within,.g-text-input_state_error.g-text-input_view_clear .g-text-input__content:hover{border-block-end:1px solid var(--g-color-line-danger)}.g-text-input_state_error.g-text-input_view_clear .g-text-input__content:focus-within{--_--focus-outline-color:var(--g-color-line-danger)}.g-clear-button{--g-button-text-color:var(--g-color-text-hint);--g-button-text-color-hover:var(--g-color-text-primary);--g-button-background-color:#0000;--g-button-background-color-hover:#0000}@keyframes g-pulse{50%{opacity:15%}}.g-loader{align-items:center;display:inline-flex}.g-loader__center,.g-loader__left,.g-loader__right{animation:g-pulse .8s ease infinite;background:var(--g-color-base-brand)}.g-loader__left{animation-delay:.2s}.g-loader__center{animation-delay:.4s}.g-loader__right{animation-delay:.6s}.g-loader_size_s .g-loader__left{height:13.33333px;width:5px}.g-loader_size_s .g-loader__center{height:20px;margin-inline-start:5px;width:5px}.g-loader_size_s .g-loader__right{height:13.33333px;margin-inline-start:5px;width:5px}.g-loader_size_m .g-loader__left{height:18.66667px;width:7px}.g-loader_size_m .g-loader__center{height:28px;margin-inline-start:7px;width:7px}.g-loader_size_m .g-loader__right{height:18.66667px;margin-inline-start:7px;width:7px}.g-loader_size_l .g-loader__left{height:24px;width:9px}.g-loader_size_l .g-loader__center{height:36px;margin-inline-start:9px;width:9px}.g-loader_size_l .g-loader__right{height:24px;margin-inline-start:9px;width:9px}.kv-ydb-internal-user{align-items:center;display:flex;flex-grow:1;justify-content:space-between;line-height:var(--g-text-body-2-line-height);margin-left:16px}.kv-ydb-internal-user__user-info-wrapper{display:flex;flex-direction:column}.kv-ydb-internal-user__ydb-internal-user-title{font-weight:500}.kv-ydb-internal-user__ydb-user-wrapper{padding:10px;width:300px}.ydb-link-with-icon{align-items:center;display:inline-flex;flex-wrap:nowrap;white-space:nowrap}.ydb-node-endpoints-tooltip-content .info-viewer__value{min-width:70px}.ydb-node-endpoints-tooltip-content__list-container{padding-right:20px}.ydb-node-endpoints-tooltip-content__definition{text-align:right;word-break:break-word}.info-viewer{--ydb-info-viewer-font-size:var(--g-text-body-2-font-size);--ydb-info-viewer-line-height:var(--g-text-body-2-line-height);--ydb-info-viewer-title-font-weight:600;--ydb-info-viewer-title-margin:15px 0 10px;--ydb-info-viewer-items-gap:7px;font-size:var(--ydb-info-viewer-font-size);line-height:var(--ydb-info-viewer-line-height)}.info-viewer__title{font-weight:var(--ydb-info-viewer-title-font-weight);margin:var(--ydb-info-viewer-title-margin)}.info-viewer__items{display:flex;flex-direction:column;gap:var(--ydb-info-viewer-items-gap);max-width:100%}.info-viewer__row{align-items:baseline;display:flex;max-width:100%;padding-top:4px}.info-viewer__label{align-items:baseline;color:var(--g-color-text-secondary);display:flex;flex:0 1 auto;min-width:200px;white-space:nowrap}.info-viewer__label-text_multiline{max-width:180px;overflow:visible;white-space:normal}.info-viewer__dots{border-bottom:1px dotted var(--g-color-text-secondary);display:flex;flex:1 1 auto;margin:0 2px}.info-viewer__value{display:flex;min-width:130px;word-break:break-all}.info-viewer_size_s{--ydb-info-viewer-font-size:var(--g-text-body-1-font-size);--ydb-info-viewer-line-height:var(--g-text-body-1-line-height);--ydb-info-viewer-title-font-weight:500;--ydb-info-viewer-title-margin:0 0 4px;--ydb-info-viewer-items-gap:4px}.info-viewer_size_s .info-viewer__row{height:auto}.info-viewer_size_s .info-viewer__label{min-width:85px}.ydb-cell-with-popover{display:inline-flex;max-width:100%}.ydb-cell-with-popover_full-width{display:flex}.ydb-cell-with-popover__popover{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap}.ydb-cell-with-popover__popover .g-popover__handler{display:inline}.ydb-cell-with-popover__popover_full-width{width:100%}.popup2{animation:none!important;max-width:300px}.histogram-tooltip,.node-tootltip{padding:10px}.histogram-tooltip__label,.node-tootltip__label{color:var(--g-color-text-secondary);padding-right:15px}.cell-tooltip{padding:10px;word-break:break-word}.empty-state{padding:20px}.empty-state_size_m{height:400px}.empty-state__wrapper{display:grid;grid-template-areas:"image title" "image description" "image actions"}.empty-state__wrapper_size_s{height:120px;width:460px}.empty-state__wrapper_size_m{height:240px;width:800px}.empty-state__wrapper_position_center{margin:0 auto;position:relative}.empty-state__image{color:var(--g-color-base-info-light-hover);grid-area:image;justify-self:end;margin-right:60px}.g-root_theme_dark .empty-state__image{color:var(--g-color-base-generic)}.empty-state__title{align-self:center;font-weight:500;grid-area:title}.empty-state__title_size_s{font-size:var(--g-text-subheader-3-font-size);line-height:var(--g-text-subheader-3-line-height)}.empty-state__title_size_m{font-size:var(--g-text-header-2-font-size);line-height:var(--g-text-header-2-line-height)}.empty-state__description{font-size:var(--g-text-body-2-font-size);grid-area:description;line-height:var(--g-text-body-2-line-height)}.empty-state__actions{grid-area:actions}.empty-state__actions>*{margin-right:8px}.ydb-loader{flex:1 1 auto}.authentication,.ydb-loader{align-items:center;display:flex;height:100%;justify-content:center}.authentication{background-blend-mode:normal;background-color:#b8d4fd1a;background-image:radial-gradient(at 0 100%,#0066ff26 20%,#f7f7f700 40%),radial-gradient(at 55% 0,#0066ff26 20%,#f7f7f700 40%),radial-gradient(at 110% 100%,#0066ff26 20%,#f7f7f700 40%)}.authentication .g-text-input{display:flex}.authentication__header{align-items:center;display:flex;font-size:var(--g-text-body-1-font-size);justify-content:space-between;line-height:var(--g-text-header-1-line-height);width:100%}.authentication__logo{align-items:center;display:flex;font-size:16px;font-weight:600;gap:8px}.authentication__title{font-size:var(--g-text-header-2-font-size);font-weight:600;line-height:var(--g-text-header-2-line-height);margin:34px 0 16px}.authentication__form-wrapper{align-items:center;background-color:var(--g-color-base-background);border-radius:16px;display:flex;flex-direction:column;flex-shrink:0;justify-content:center;min-width:320px;padding:40px;width:400px}.authentication__field-wrapper{align-items:flex-start;display:flex;justify-content:space-between;margin-bottom:16px;width:320px}.authentication__field-wrapper .g-text-input_state_error{flex-direction:column}.authentication__button-sign-in{display:inline-flex;justify-content:center}.authentication__show-password-button{margin-left:4px}.authentication__close{position:absolute;right:40px;top:40px}.ydb-connect-to-db__dialog-tabs,.ydb-connect-to-db__docs{margin-top:var(--g-spacing-4)}.ydb-connect-to-db__snippet-container{height:270px}.g-dialog-btn-close{inset-block-start:14px;inset-inline-end:14px;position:absolute;z-index:1}.g-dialog-body{flex:1 1 auto;overflow-y:auto;padding:10px var(--_--side-padding)}.g-dialog-body_has-borders{border-block-end:1px solid var(--g-color-line-generic)}.g-dialog-body_has-borders,.g-dialog-divider{border-block-start:1px solid var(--g-color-line-generic)}.g-dialog-divider{margin:0 calc(var(--_--side-padding)*-1)}.g-dialog-footer{align-items:center;display:flex;padding:28px var(--_--side-padding)}.g-dialog-footer__bts-wrapper{display:flex;gap:10px}.g-dialog-footer__children{align-items:center;display:flex;flex-grow:1;height:100%}.g-dialog-footer__button{min-width:128px;position:relative}.g-dialog-footer__error{color:var(--g-color-text-danger);padding:10px}.g-dialog-header{align-items:center;color:var(--g-color-text-primary);display:flex;justify-content:flex-start;line-height:24px;padding-block:20px 10px;padding-inline:var(--_--side-padding) calc(var(--_--side-padding) + var(--_--close-button-space)*var(--g-flow-is-ltr) + var(--_--close-button-space)*var(--g-flow-is-rtl))}.g-dialog-header__caption{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height)}.g-dialog{--_--side-padding:32px;--_--close-button-space:0px;display:flex;flex-direction:column;position:relative;width:var(--g-dialog-width,var(--_--width))}.g-dialog_has-scroll{max-height:calc(100vh - var(--g-modal-margin, 20px)*2);overflow-y:auto}.g-dialog_size_s{--_--width:480px}.g-dialog_size_m{--_--width:720px}.g-dialog_size_l{--_--width:900px}.g-dialog_has-close{--_--close-button-space:24px}.g-modal{-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);background-color:var(--g-color-sfx-veil);display:none;inset:0;margin:-9999px 0 0 -9999px;overflow:auto;position:fixed;visibility:hidden;z-index:1000}.g-modal__content-aligner{align-items:center;display:inline-flex;justify-content:center;min-height:100%;min-width:100%}.g-modal__content-wrapper{margin:var(--g-modal-margin,20px);overflow-x:hidden}.g-modal__content,.g-modal__content-wrapper{border-radius:var(--g-modal-border-radius,5px)}.g-modal__content{background-color:var(--g-color-base-modal)}.g-modal__content_has-scroll{max-height:calc(100vh - var(--g-modal-margin, 20px)*2);overflow-y:auto}.g-modal,.g-modal__content{animation-fill-mode:forwards;animation-timing-function:ease-out;outline:none}.g-modal_exit_active,.g-modal_open{display:block;margin:0;visibility:visible}.g-modal_appear_active,.g-modal_enter_active{animation-duration:.15s;animation-name:g-modal-open}.g-modal_appear_active .g-modal__content,.g-modal_enter_active .g-modal__content{animation-duration:.15s;animation-name:g-modal-content-open}.g-modal_exit_active{animation-duration:.2s;animation-name:g-modal}@keyframes g-modal{0%{opacity:1}to{opacity:0}}@keyframes g-modal-open{0%{opacity:0}to{opacity:1}}@keyframes g-modal-content-open{0%{transform:scale(.75)}to{transform:scale(1)}}.tablet-icon{border:1px solid;border-radius:4px;display:flex;font-size:10px;height:16px;justify-content:center;text-transform:uppercase;width:23px}.tablet-icon__type{line-height:14px}.header{align-items:center;border-bottom:1px solid var(--g-color-line-generic);display:flex;flex:0 0 40px;justify-content:space-between;padding:0 20px 0 12px}.header__breadcrumbs-item{color:var(--g-color-text-secondary);display:flex;gap:3px}.header__breadcrumbs-item_link:hover{color:var(--g-color-text-complementary)}.header__breadcrumbs-item_active{color:var(--g-color-text-primary)}.header__breadcrumbs-icon{align-items:center;display:flex}.g-divider{--_--content-gap:8px;--_--size:1px}.g-divider:not(:empty){align-items:center;border:none;display:flex}.g-divider:not(:empty):after,.g-divider:not(:empty):before{content:""}.g-divider:after,.g-divider:before{background:var(--g-divider-color,var(--g-color-line-generic));flex-grow:1}.g-divider_orientation_vertical{border-inline-start:1px solid var(--g-divider-color,var(--g-color-line-generic));flex-direction:column}.g-divider_orientation_vertical:after,.g-divider_orientation_vertical:before{width:var(--_--size)}.g-divider_orientation_vertical:before{margin-block-end:var(--_--content-gap)}.g-divider_orientation_vertical:after{margin-block-start:var(--_--content-gap)}.g-divider_orientation_horizontal{border-block-start:1px solid var(--g-divider-color,var(--g-color-line-generic))}.g-divider_orientation_horizontal:after,.g-divider_orientation_horizontal:before{height:var(--_--size)}.g-divider_orientation_horizontal:before{margin-inline-end:var(--_--content-gap)}.g-divider_orientation_horizontal:after{margin-inline-start:var(--_--content-gap)}.g-divider_align_end:after,.g-divider_align_start:before{display:none}.g-menu{background-color:var(--g-color-base-float);box-sizing:border-box;color:var(--g-color-text-primary);display:block;font-size:var(--g-text-body-1-font-size);list-style:none;margin:0;outline:none;overflow:hidden auto;padding:0;-webkit-user-select:none;user-select:none}.g-menu__list-group-item+.g-menu__list-group-item,.g-menu__list-group-item+.g-menu__list-item,.g-menu__list-item+.g-menu__list-group-item{border-block-start:1px solid var(--g-color-line-generic)}.g-menu__item{-webkit-tap-highlight-color:rgba(0,0,0,0);align-items:center;color:var(--g-color-text-primary);display:flex;outline:none;text-decoration:none;touch-action:manipulation}.g-menu__item-icon{display:flex}.g-menu__item-icon-end{display:flex;margin-inline-end:0}.g-menu__item-content{flex-grow:1;min-width:0}.g-menu__item_interactive{cursor:pointer}.g-menu__item_interactive:focus-visible,.g-menu__item_interactive:hover,.g-menu__item_selected{background-color:var(--g-color-base-simple-hover)}.g-menu__item_disabled{color:var(--g-color-text-secondary);cursor:default;pointer-events:none}.g-menu__item_disabled:hover{background-color:initial}.g-menu__item_active{background-color:var(--g-color-base-selection);cursor:default}.g-menu__item_active:focus-visible,.g-menu__item_active:hover{background-color:var(--g-color-base-selection-hover)}.g-menu__item_theme_danger:not(.g-menu__item_disabled){color:var(--g-color-text-danger)}.g-menu__group-label{color:var(--g-color-text-hint);font-weight:var(--g-text-accent-font-weight)}.g-menu__group-list{list-style:none;margin:0;padding:0}.g-menu_size_s{line-height:24px;padding:3px 0}.g-menu_size_s .g-menu__group-label,.g-menu_size_s .g-menu__item{padding:0 10px}.g-menu_size_s .g-menu__item-icon{margin-inline-end:3px}.g-menu_size_s .g-menu__item-icon-end{margin-inline-start:3px}.g-menu_size_s .g-menu__list-group-item+.g-menu__list-group-item,.g-menu_size_s .g-menu__list-group-item+.g-menu__list-item,.g-menu_size_s .g-menu__list-item+.g-menu__list-group-item{margin-block-start:3px;padding-block-start:3px}.g-menu_size_m{line-height:24px;padding:4px 0}.g-menu_size_m .g-menu__group-label,.g-menu_size_m .g-menu__item{padding:0 13px}.g-menu_size_m .g-menu__item-icon{margin-inline-end:4px}.g-menu_size_m .g-menu__item-icon-end{margin-inline-start:4px}.g-menu_size_m .g-menu__list-group-item+.g-menu__list-group-item,.g-menu_size_m .g-menu__list-group-item+.g-menu__list-item,.g-menu_size_m .g-menu__list-item+.g-menu__list-group-item{margin-block-start:4px;padding-block-start:4px}.g-menu_size_l{line-height:28px;padding:5px 0}.g-menu_size_l .g-menu__group-label,.g-menu_size_l .g-menu__item{padding:0 15px}.g-menu_size_l .g-menu__item-icon{margin-inline-end:5px}.g-menu_size_l .g-menu__item-icon-end{margin-inline-start:5px}.g-menu_size_l .g-menu__list-group-item+.g-menu__list-group-item,.g-menu_size_l .g-menu__list-group-item+.g-menu__list-item,.g-menu_size_l .g-menu__list-item+.g-menu__list-group-item{margin-block-start:5px;padding-block-start:5px}.g-menu_size_xl{font-size:var(--g-text-body-2-font-size);line-height:36px;padding:6px 0}.g-menu_size_xl .g-menu__group-label,.g-menu_size_xl .g-menu__item{padding:0 15px}.g-menu_size_xl .g-menu__item-icon{margin-inline-end:6px}.g-menu_size_xl .g-menu__item-icon-end{margin-inline-start:6px}.g-menu_size_xl .g-menu__list-group-item:not(:first-child){margin-block-start:6px;padding-block-start:6px}.g-menu_size_xl .g-menu__list-group-item:not(:last-child){margin-block-end:6px;padding-block-end:6px}.g-dropdown-menu__switcher-wrapper{display:inline-block}.g-dropdown-menu__switcher-button{display:flex}.g-dropdown-menu__menu-item_separator{border-block-start:1px solid var(--g-color-line-generic-solid);margin:.5em 0;pointer-events:none}.g-dropdown-menu__sub-menu-arrow{inset-inline-end:-4px;position:relative}.g-dropdown-menu__sub-menu{position:relative}.g-dropdown-menu__sub-menu .g-dropdown-menu__menu:after,.g-dropdown-menu__sub-menu .g-dropdown-menu__menu:before{content:"";height:100%;inset-block-start:0;position:absolute;width:10px}.g-dropdown-menu__sub-menu .g-dropdown-menu__menu:before{inset-inline-start:-10px}.g-dropdown-menu__sub-menu .g-dropdown-menu__menu:after{inset-inline-end:-10px}.g-breadcrumbs__inner{align-items:center;display:inline-flex;gap:4px;min-height:24px;overflow:hidden;width:100%}.g-breadcrumbs__switcher{background:none;border:none;color:inherit;color:var(--g-color-text-secondary);cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0}.g-breadcrumbs__switcher:focus-visible{outline:2px solid var(--g-color-line-focus)}.g-breadcrumbs__item,.g-breadcrumbs__switcher{display:inline-block;flex-shrink:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.g-breadcrumbs__item:focus-visible,.g-breadcrumbs__switcher:focus-visible{border-radius:var(--g-focus-border-radius);outline:2px solid var(--g-color-line-focus)}.g-breadcrumbs_calculated_no .g-breadcrumbs__item{overflow:visible}.g-breadcrumbs__divider{align-items:center;color:var(--g-color-text-secondary);display:flex}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item .g-menu__item{padding-inline-start:80px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(0) .g-menu__item{padding-inline-start:0!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:first-child .g-menu__item{padding-inline-start:8px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(2) .g-menu__item{padding-inline-start:16px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(3) .g-menu__item{padding-inline-start:24px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(4) .g-menu__item{padding-inline-start:32px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(5) .g-menu__item{padding-inline-start:40px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(6) .g-menu__item{padding-inline-start:48px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(7) .g-menu__item{padding-inline-start:56px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(8) .g-menu__item{padding-inline-start:64px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(9) .g-menu__item{padding-inline-start:72px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(10) .g-menu__item{padding-inline-start:80px!important}*{font-feature-settings:"tnum";box-sizing:border-box;font-variant-numeric:tabular-nums}.g-select-popup__tick-icon{box-sizing:initial}#root,body,html{box-sizing:border-box;height:100%;margin:0;overflow:auto;padding:0}:root{--g-color-base-yellow-light:#ffc70026;--g-color-base-yellow-medium:#ffdb4d66;--tenant-object-info-max-value-width:300px;--diagnostics-section-title-margin:20px;--diagnostics-section-margin:30px;--diagnostics-section-table-width:872px}.g-root{--ydb-data-table-color-hover:var(--g-color-base-simple-hover-solid);--ydb-color-status-grey:var(--g-color-base-neutral-heavy);--ydb-color-status-green:var(--g-color-base-positive-heavy);--ydb-color-status-yellow:var(--g-color-base-warning-heavy);--ydb-color-status-orange:var(--g-color-private-orange-500-solid);--ydb-color-status-red:var(--g-color-base-danger-heavy);--ydb-color-status-blue:var(--g-color-base-info-heavy);--ydb-color-status-black:var(--g-color-base-misc-heavy);--g-popover-max-width:500px}.g-root_theme_light,.g-root_theme_light-hc{--code-background-color:var(--g-color-base-simple-hover)}.g-root_theme_dark,.g-root_theme_dark-hc{--code-background-color:#1e1e1e}:is(#tab,.g-tabs-item_active .g-tabs-item__title){color:var(--g-color-text-primary)!important}:is(#tab,.g-tabs-item__title){color:var(--g-color-text-secondary)}.gn-aside-header__pane-container{height:100%}.gn-aside-header__content{display:flex;flex-direction:column;height:100%;overflow:auto;position:relative}.loader{align-items:center;display:flex;justify-content:center;left:50%;position:fixed;top:50%;z-index:99999999}.app{--data-table-row-height:40px;--data-table-cell-align:middle;--data-table-head-align:middle;display:flex;flex:1 1 auto;flex-direction:column;height:100%}.app .data-table{font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height)}.app .data-table__td,.app .data-table__th{border-left:unset;border-right:unset;border-top:unset;height:var(--data-table-row-height)}.app .data-table__th{font-weight:700}.app .data-table__table{border-collapse:initial;border-spacing:0}.app .data-table__box_sticky-head_moving .data-table__th{height:unset}.app__main{display:flex;flex:1 1 auto;flex-direction:column;overflow:auto}.error{color:var(--g-color-text-danger)}.g-root .data-table_highlight-rows .data-table__row:hover{background:var(--ydb-data-table-color-hover)}.g-table-column-setup__item{cursor:pointer!important;padding:0 8px 0 32px!important}.app_embedded{font-family:Rubik,sans-serif}.kv-navigation__internal-user{align-items:center;display:flex;justify-content:space-between;line-height:var(--g-text-body-2-line-height);margin-left:16px}.kv-navigation__user-info-wrapper{display:flex;flex-direction:column}.kv-navigation__ydb-internal-user-title{font-weight:500}.kv-navigation__ydb-user-wrapper{padding:10px;width:300px}.g-list{--_--item-padding:var(--g-list-item-padding,0);display:flex;flex:1 1 auto;flex-direction:column;outline:none;width:100%}.g-list__filter{flex:0 0 auto;margin-block-end:8px;padding:var(--_--item-padding)}.g-list__items{flex:1 1 auto}.g-list__empty-placeholder,.g-list__item{align-items:center;box-sizing:border-box;display:flex;overflow:hidden;padding:var(--_--item-padding);-webkit-user-select:none;user-select:none}.g-list__item_active{background:var(--g-color-base-simple-hover)}.g-list__item_selected{background:var(--g-color-base-selection)}.g-list__item_selected:hover{background:var(--g-color-base-selection-hover)}.g-list__item_sort-handle-align_right{flex-direction:row-reverse}.g-list__item_sort-handle-align_right .g-list__item-sort-icon{margin-inline:10px 0}.g-list__item_sortable[data-rbd-drag-handle-context-id]:active{cursor:grabbing}.g-list__item_dragging{background:var(--g-color-base-simple-hover-solid);z-index:100001}.g-list__empty-placeholder{box-sizing:border-box;color:var(--g-color-text-hint);min-height:36px;padding-block:8px}.g-list__item-content{align-items:center;display:flex;flex:1 1 auto;height:100%;overflow:hidden;text-overflow:ellipsis}.g-list__item-sort-icon{align-items:center;color:var(--g-color-text-hint);display:flex;flex:0 0 auto;margin-inline-end:4px;width:12px}.g-list__loading-indicator{align-items:center;display:flex;justify-content:center;width:100%}.ydb-resizeable-data-table{display:flex;padding-right:20px;width:max-content}.ydb-status-icon__status-color_state_green{background-color:var(--ydb-color-status-green)}.ydb-status-icon__status-color_state_yellow{background-color:var(--ydb-color-status-yellow)}.ydb-status-icon__status-color_state_blue{background-color:var(--ydb-color-status-blue)}.ydb-status-icon__status-color_state_red{background-color:var(--ydb-color-status-red)}.ydb-status-icon__status-color_state_grey{background-color:var(--ydb-color-status-grey)}.ydb-status-icon__status-color_state_orange{background-color:var(--ydb-color-status-orange)}.ydb-status-icon__status-icon_state_blue{color:var(--ydb-color-status-blue)}.ydb-status-icon__status-icon_state_yellow{color:var(--ydb-color-status-yellow)}.ydb-status-icon__status-icon_state_orange{color:var(--ydb-color-status-orange)}.ydb-status-icon__status-icon_state_red{color:var(--ydb-color-status-red)}.ydb-status-icon__status-color,.ydb-status-icon__status-icon{border-radius:3px;display:inline-flex;flex-shrink:0}.ydb-status-icon__status-color_size_xs,.ydb-status-icon__status-icon_size_xs{aspect-ratio:1;height:12px;width:12px}.ydb-status-icon__status-color_size_s,.ydb-status-icon__status-icon_size_s{aspect-ratio:1;height:16px;width:16px}.ydb-status-icon__status-color_size_m,.ydb-status-icon__status-icon_size_m{aspect-ratio:1;height:18px;width:18px}.ydb-status-icon__status-color_size_l,.ydb-status-icon__status-icon_size_l{height:24px;width:24px}.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.entity-status{--button-width:28px;align-items:center;display:inline-flex;font-size:var(--g-text-body-2-font-size);height:100%;line-height:var(--g-text-body-2-line-height);max-width:100%;position:relative}.entity-status__icon{margin-right:var(--g-spacing-2)}.entity-status__clipboard-button,.entity-status__info-icon{color:var(--g-color-text-secondary);opacity:0}.entity-status__clipboard-button:focus-visible,.entity-status__clipboard-button_visible,.entity-status__info-icon:focus-visible,.entity-status__info-icon_visible{opacity:1}.entity-status__clipboard-button:focus-visible,.entity-status__info-icon:focus-visible{background-color:var(--g-color-base-float);position:absolute;right:2px;top:2px}.data-table__row:hover .entity-status__clipboard-button,.data-table__row:hover .entity-status__info-icon,.ydb-paginated-table__row:hover .entity-status__clipboard-button,.ydb-paginated-table__row:hover .entity-status__info-icon{opacity:1}.data-table__row:hover .entity-status__clipboard-button:focus-visible,.data-table__row:hover .entity-status__info-icon:focus-visible,.ydb-paginated-table__row:hover .entity-status__clipboard-button:focus-visible,.ydb-paginated-table__row:hover .entity-status__info-icon:focus-visible{background-color:unset;position:static}.entity-status__clipboard-button_visible,.entity-status__info-icon_visible{opacity:1}.entity-status__info-icon:hover{color:var(--g-color-text-primary)}.entity-status__wrapper{overflow:hidden;position:relative}.entity-status__wrapper_with-clipboard-button,.entity-status__wrapper_with-info-button{padding-right:var(--button-width)}.entity-status__wrapper_with-clipboard-button.entity-status__wrapper_with-info-button{padding-right:calc(var(--button-width)*2)}.entity-status__controls-wrapper{align-items:center;display:flex;gap:var(--g-spacing-1);height:100%;position:absolute;right:0;top:0;width:0}.entity-status__controls-wrapper_visible{background-color:var(--g-color-base-background);padding:var(--g-spacing-1);width:min-content}.data-table__row:hover .entity-status__controls-wrapper,.ydb-paginated-table__row:hover .entity-status__controls-wrapper,.ydb-tree-view__item .entity-status__controls-wrapper{background-color:var(--ydb-data-table-color-hover);padding:var(--g-spacing-1);width:min-content}.entity-status__label{color:var(--g-color-text-complementary);font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);margin-right:2px}.entity-status__label_size_l{font-size:var(--g-text-header-2-font-size)}.entity-status__link{display:inline-block;margin-top:5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.entity-status__wrapper_with-clipboard-button .entity-status__link,.entity-status__wrapper_with-info-button .entity-status__link{width:calc(100% + var(--button-width))}.entity-status__wrapper_with-clipboard-button.entity-status__wrapper_with-info-button .entity-status__link{width:calc(100% + var(--button-width)*2)}.entity-status__link_with-left-trim{direction:rtl;text-align:end}.entity-status__link_with-left-trim .entity-status__name{unicode-bidi:plaintext}.entity-status__label_state_blue{color:var(--ydb-color-status-blue)}.entity-status__label_state_yellow{color:var(--ydb-color-status-yellow)}.entity-status__label_state_orange{color:var(--ydb-color-status-orange)}.entity-status__label_state_red{color:var(--ydb-color-status-red)}.ydb-usage-label_overload{background-color:var(--ydb-color-status-red);color:var(--g-color-text-light-primary)}.extended-cluster{display:flex;height:100%}.extended-cluster__balancer{align-items:center;display:flex;flex-direction:row}.extended-cluster__clipboard-button{margin-left:5px}.g-toast{--_--item-gap:10px;--_--item-padding:16px;--_--background-color:var(--g-color-base-background);background-color:var(--_--background-color);border-radius:8px;box-shadow:0 0 15px var(--g-color-sfx-shadow);box-sizing:border-box;display:flex;font-size:var(--g-text-body-2-font-size);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));overflow:hidden;padding:var(--g-toaster-item-padding,var(--_--item-padding));position:relative;width:inherit;z-index:0}.g-toast_mobile{width:100%}.g-toast_theme_normal{--_--background-color:var(--g-color-base-float)}.g-toast_theme_info{--_--container-background-color:var(--g-color-base-info-light);--_--icon-color:var(--g-color-text-info-heavy)}.g-toast_theme_success{--_--container-background-color:var(--g-color-base-positive-light);--_--icon-color:var(--g-color-text-positive-heavy)}.g-toast_theme_warning{--_--container-background-color:var(--g-color-base-warning-light);--_--icon-color:var(--g-color-text-warning-heavy)}.g-toast_theme_danger{--_--container-background-color:var(--g-color-base-danger-light);--_--icon-color:var(--g-color-text-danger-heavy)}.g-toast_theme_utility{--_--container-background-color:var(--g-color-base-utility-light);--_--icon-color:var(--g-color-text-utility-heavy)}.g-toast__container{display:flex;flex:1 1 auto;flex-flow:column nowrap;min-height:var(--g-text-body-2-line-height);min-width:0}.g-toast__container:before{background-color:var(--_--container-background-color);content:"";height:100%;inset-block-start:0;inset-inline-start:0;pointer-events:none;position:absolute;width:100%;z-index:-1}.g-toast__icon-container{color:var(--_--icon-color);flex:0 0 auto;min-width:0;padding-block-start:2px;padding-inline-end:8px}.g-toast__title{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height);margin:0;padding-inline-end:32px}.g-toast__content{margin-block-start:var(--g-spacing-2)}.g-toast__content_without-title{margin-block-start:0;padding-inline-end:32px}.g-toast__actions{margin-block-start:var(--g-spacing-3)}.g-toast__action{margin-inline-end:8px}.g-toast .g-toast__btn-close{inset-block-start:16px;inset-inline-end:16px;position:absolute}.g-toast-animation-mobile_enter{opacity:0;position:absolute}.g-toast-animation-mobile_enter_active{animation:g-toast-enter-mobile .6s ease-out forwards;position:relative}.g-toast-animation-mobile_exit_active{animation:g-toast-exit-mobile .6s ease-in forwards}@keyframes g-toast-enter-mobile{0%{height:0;margin-block-end:0;opacity:0;padding:0;transform:translateY(10px)}50%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:0;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateY(10px)}to{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:1;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(0)}}@keyframes g-toast-exit-mobile{0%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:1;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(0)}50%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:0;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateY(10px)}to{height:0;margin-block-end:0;opacity:0;padding:0;transform:translateY(10px)}}.g-toast-animation-desktop_enter{opacity:0;position:absolute}.g-toast-animation-desktop_enter_active{animation:g-toast-enter-desktop .6s ease-out forwards;position:relative}.g-toast-animation-desktop_exit_active{animation:g-toast-exit-desktop .6s ease-in forwards}@keyframes g-toast-enter-desktop{0%{height:0;margin-block-end:0;opacity:0;padding:0;transform:translateX(calc(var(--g-flow-direction)*10px))}50%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:0;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(calc(var(--g-flow-direction)*10px))}to{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:1;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(0)}}@keyframes g-toast-exit-desktop{0%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:1;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(0)}50%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:0;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(calc(var(--g-flow-direction)*10px))}to{height:0;margin-block-end:0;opacity:0;padding:0;transform:translateX(calc(var(--g-flow-direction)*10px))}}.g-toaster{--_--width:312px;align-items:flex-end;display:flex;flex-direction:column;inset-block-end:0;inset-inline-end:10px;position:fixed;width:var(--g-toaster-width,var(--_--width));z-index:100000}.g-toaster_mobile{--_--width:calc(100% - 20px);inset-inline-start:50%;transform:translate(-50%)}.g-root{--g-font-family-sans:"Inter","Helvetica Neue","Helvetica","Arial",sans-serif;--g-font-family-monospace:"Menlo","Monaco","Consolas","Ubuntu Mono","Liberation Mono","DejaVu Sans Mono","Courier New","Courier",monospace;--g-text-body-font-family:var(--g-font-family-sans);--g-text-caption-font-family:var(--g-font-family-sans);--g-text-header-font-family:var(--g-font-family-sans);--g-text-subheader-font-family:var(--g-font-family-sans);--g-text-display-font-family:var(--g-font-family-sans);--g-text-code-font-family:var(--g-font-family-monospace);--g-text-body-font-weight:400;--g-text-caption-font-weight:400;--g-text-header-font-weight:600;--g-text-display-font-weight:600;--g-text-code-font-weight:400;--g-text-accent-font-weight:600;--g-text-body-1-font-size:13px;--g-text-body-1-line-height:18px;--g-text-body-2-font-size:15px;--g-text-body-2-line-height:20px;--g-text-body-3-font-size:17px;--g-text-body-3-line-height:24px;--g-text-body-short-font-size:13px;--g-text-body-short-line-height:16px;--g-text-caption-1-font-size:9px;--g-text-caption-1-line-height:12px;--g-text-caption-2-font-size:11px;--g-text-caption-2-line-height:16px;--g-text-header-1-font-size:20px;--g-text-header-1-line-height:24px;--g-text-header-2-font-size:24px;--g-text-header-2-line-height:28px;--g-text-subheader-1-font-size:13px;--g-text-subheader-1-line-height:18px;--g-text-subheader-2-font-size:15px;--g-text-subheader-2-line-height:20px;--g-text-subheader-3-font-size:17px;--g-text-subheader-3-line-height:24px;--g-text-display-1-font-size:28px;--g-text-display-1-line-height:36px;--g-text-display-2-font-size:32px;--g-text-display-2-line-height:40px;--g-text-display-3-font-size:40px;--g-text-display-3-line-height:48px;--g-text-display-4-font-size:48px;--g-text-display-4-line-height:52px;--g-text-code-1-font-size:12px;--g-text-code-1-line-height:18px;--g-text-code-2-font-size:14px;--g-text-code-2-line-height:20px;--g-text-code-3-font-size:16px;--g-text-code-3-line-height:24px;--g-text-code-inline-1-font-size:12px;--g-text-code-inline-1-line-height:14px;--g-text-code-inline-2-font-size:14px;--g-text-code-inline-2-line-height:16px;--g-text-code-inline-3-font-size:16px;--g-text-code-inline-3-line-height:20px;--g-spacing-base:4px;--g-spacing-0:calc(var(--g-spacing-base)*0);--g-spacing-half:calc(var(--g-spacing-base)*0.5);--g-spacing-1:var(--g-spacing-base);--g-spacing-2:calc(var(--g-spacing-base)*2);--g-spacing-3:calc(var(--g-spacing-base)*3);--g-spacing-4:calc(var(--g-spacing-base)*4);--g-spacing-5:calc(var(--g-spacing-base)*5);--g-spacing-6:calc(var(--g-spacing-base)*6);--g-spacing-7:calc(var(--g-spacing-base)*7);--g-spacing-8:calc(var(--g-spacing-base)*8);--g-spacing-9:calc(var(--g-spacing-base)*9);--g-spacing-10:calc(var(--g-spacing-base)*10);--g-scrollbar-width:12px;--g-border-radius-xs:3px;--g-border-radius-s:5px;--g-border-radius-m:6px;--g-border-radius-l:8px;--g-border-radius-xl:10px;--g-focus-border-radius:2px;background:var(--g-color-base-background);color:var(--g-color-text-primary);font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height)}.g-root[dir=ltr],body.g-root{--g-flow-direction:1;--g-flow-is-ltr:1;--g-flow-is-rtl:0}.g-root[dir=rtl]{--g-flow-direction:-1;--g-flow-is-ltr:0;--g-flow-is-rtl:1}.g-root_theme_light{--g-color-private-blue-50:#3697f11a;--g-color-private-blue-100:#3697f126;--g-color-private-blue-150:#3697f133;--g-color-private-blue-200:#3697f14d;--g-color-private-blue-250:#3697f166;--g-color-private-blue-300:#3697f180;--g-color-private-blue-350:#3697f199;--g-color-private-blue-400:#3697f1b3;--g-color-private-blue-450:#3697f1cc;--g-color-private-blue-500:#3697f1e6;--g-color-private-blue-50-solid:#ebf5fe;--g-color-private-blue-100-solid:#e1effd;--g-color-private-blue-150-solid:#d7eafc;--g-color-private-blue-200-solid:#c3e0fb;--g-color-private-blue-250-solid:#afd5f9;--g-color-private-blue-300-solid:#9bcbf8;--g-color-private-blue-350-solid:#86c1f7;--g-color-private-blue-400-solid:#72b6f5;--g-color-private-blue-450-solid:#5eacf4;--g-color-private-blue-500-solid:#4aa1f2;--g-color-private-blue-550-solid:#3697f1;--g-color-private-blue-600-solid:#348bdc;--g-color-private-blue-650-solid:#327fc8;--g-color-private-blue-700-solid:#3072b3;--g-color-private-blue-750-solid:#2e669e;--g-color-private-blue-800-solid:#2c5a8a;--g-color-private-blue-850-solid:#2a4e75;--g-color-private-blue-900-solid:#284260;--g-color-private-blue-950-solid:#26354b;--g-color-private-blue-1000-solid:#252f41;--g-color-private-green-50:#32ba761a;--g-color-private-green-100:#32ba7626;--g-color-private-green-150:#32ba7633;--g-color-private-green-200:#32ba764d;--g-color-private-green-250:#32ba7666;--g-color-private-green-300:#32ba7680;--g-color-private-green-350:#32ba7699;--g-color-private-green-400:#32ba76b3;--g-color-private-green-450:#32ba76cc;--g-color-private-green-500:#32ba76e6;--g-color-private-green-50-solid:#ebf8f1;--g-color-private-green-100-solid:#e0f5ea;--g-color-private-green-150-solid:#d6f1e4;--g-color-private-green-200-solid:#c2ead6;--g-color-private-green-250-solid:#ade3c8;--g-color-private-green-300-solid:#9db;--g-color-private-green-350-solid:#84d6ad;--g-color-private-green-400-solid:#70cf9f;--g-color-private-green-450-solid:#5bc891;--g-color-private-green-500-solid:#47c184;--g-color-private-green-550-solid:#32ba76;--g-color-private-green-600-solid:#30aa6e;--g-color-private-green-650-solid:#2f9b65;--g-color-private-green-700-solid:#2d8b5d;--g-color-private-green-750-solid:#2c7b54;--g-color-private-green-800-solid:#2a6c4c;--g-color-private-green-850-solid:#285c44;--g-color-private-green-900-solid:#274c3b;--g-color-private-green-950-solid:#253c33;--g-color-private-green-1000-solid:#24352f;--g-color-private-yellow-50:#ffbe5c1a;--g-color-private-yellow-100:#ffbe5c26;--g-color-private-yellow-150:#ffbe5c33;--g-color-private-yellow-200:#ffbe5c4d;--g-color-private-yellow-250:#ffbe5c66;--g-color-private-yellow-300:#ffbe5c80;--g-color-private-yellow-350:#ffbe5c99;--g-color-private-yellow-400:#ffbe5cb3;--g-color-private-yellow-450:#ffbe5ccc;--g-color-private-yellow-500:#ffbe5ce6;--g-color-private-yellow-50-solid:#fff9ef;--g-color-private-yellow-100-solid:#fff5e7;--g-color-private-yellow-150-solid:#fff2de;--g-color-private-yellow-200-solid:#ffecce;--g-color-private-yellow-250-solid:#ffe5be;--g-color-private-yellow-300-solid:#ffdfae;--g-color-private-yellow-350-solid:#ffd89d;--g-color-private-yellow-400-solid:#ffd28d;--g-color-private-yellow-450-solid:#ffcb7d;--g-color-private-yellow-500-solid:#ffc56c;--g-color-private-yellow-550-solid:#ffbe5c;--g-color-private-yellow-600-solid:#e9ae56;--g-color-private-yellow-650-solid:#d39e50;--g-color-private-yellow-700-solid:#bd8e4b;--g-color-private-yellow-750-solid:#a77e45;--g-color-private-yellow-800-solid:#916e3f;--g-color-private-yellow-850-solid:#7a5d39;--g-color-private-yellow-900-solid:#644d33;--g-color-private-yellow-950-solid:#4e3d2e;--g-color-private-yellow-1000-solid:#43352b;--g-color-private-orange-400-solid:#ffa04d;--g-color-private-orange-500-solid:#ff8519;--g-color-private-orange-600-solid:#e96e03;--g-color-private-orange-650-solid:#d36507;--g-color-private-orange-700-solid:#bd5c0a;--g-color-private-orange-750-solid:#a7530e;--g-color-private-orange-800-solid:#914a11;--g-color-private-orange-850-solid:#7a4114;--g-color-private-orange-900-solid:#643818;--g-color-private-orange-950-solid:#4e2f1b;--g-color-private-orange-1000-solid:#432b1d;--g-color-private-red-50:#ff003d1a;--g-color-private-red-100:#ff003d26;--g-color-private-red-150:#ff003d33;--g-color-private-red-200:#ff003d4d;--g-color-private-red-250:#ff003d66;--g-color-private-red-300:#ff003d80;--g-color-private-red-350:#ff003d99;--g-color-private-red-400:#ff003db3;--g-color-private-red-450:#ff003dcc;--g-color-private-red-500:#ff003de6;--g-color-private-red-50-solid:#ffe6ec;--g-color-private-red-100-solid:#ffd9e2;--g-color-private-red-150-solid:#ffccd8;--g-color-private-red-200-solid:#ffb3c5;--g-color-private-red-250-solid:#ff99b1;--g-color-private-red-300-solid:#ff809e;--g-color-private-red-350-solid:#ff668b;--g-color-private-red-400-solid:#ff4d77;--g-color-private-red-450-solid:#ff3364;--g-color-private-red-500-solid:#ff1950;--g-color-private-red-550-solid:#ff003d;--g-color-private-red-600-solid:#e9033a;--g-color-private-red-650-solid:#d30638;--g-color-private-red-700-solid:#bd0935;--g-color-private-red-750-solid:#a70c32;--g-color-private-red-800-solid:#910f30;--g-color-private-red-850-solid:#7a112d;--g-color-private-red-900-solid:#64142a;--g-color-private-red-950-solid:#4e1727;--g-color-private-red-1000-solid:#431926;--g-color-private-purple-600-solid:#844dbb;--g-color-private-purple-650-solid:#7947aa;--g-color-private-purple-700-solid:#6e4299;--g-color-private-purple-750-solid:#633d88;--g-color-private-purple-800-solid:#593877;--g-color-private-purple-850-solid:#4e3266;--g-color-private-purple-900-solid:#432d55;--g-color-private-purple-950-solid:#382844;--g-color-private-purple-1000-solid:#32253c;--g-color-private-cool-grey-300-solid:#b5c2cc;--g-color-private-cool-grey-600-solid:#647a8d;--g-color-private-cool-grey-650-solid:#5c6f81;--g-color-private-cool-grey-700-solid:#556575;--g-color-private-cool-grey-750-solid:#4e5b69;--g-color-private-cool-grey-800-solid:#47515e;--g-color-private-cool-grey-850-solid:#3f4652;--g-color-private-cool-grey-900-solid:#383c46;--g-color-private-cool-grey-950-solid:#31323a;--g-color-private-cool-grey-1000-solid:#2d2c34;--g-color-text-primary:var(--g-color-text-dark-primary);--g-color-text-complementary:var(--g-color-text-dark-complementary);--g-color-text-secondary:var(--g-color-text-dark-secondary);--g-color-text-hint:var(--g-color-text-dark-hint);--g-color-text-info:var(--g-color-private-blue-600-solid);--g-color-text-positive:var(--g-color-private-green-600-solid);--g-color-text-warning:var(--g-color-private-yellow-700-solid);--g-color-text-danger:var(--g-color-private-red-600-solid);--g-color-text-utility:var(--g-color-private-purple-600-solid);--g-color-text-misc:var(--g-color-private-cool-grey-600-solid);--g-color-text-info-heavy:var(--g-color-private-blue-700-solid);--g-color-text-positive-heavy:var(--g-color-private-green-700-solid);--g-color-text-warning-heavy:var(--g-color-private-orange-700-solid);--g-color-text-danger-heavy:var(--g-color-private-red-700-solid);--g-color-text-utility-heavy:var(--g-color-private-purple-700-solid);--g-color-text-misc-heavy:var(--g-color-private-cool-grey-700-solid);--g-color-text-brand:var(--g-color-private-yellow-700-solid);--g-color-text-brand-heavy:var(--g-color-private-orange-700-solid);--g-color-text-brand-contrast:var(--g-color-text-dark-primary);--g-color-text-link:var(--g-color-private-yellow-650-solid);--g-color-text-link-hover:var(--g-color-private-orange-650-solid);--g-color-text-link-visited:var(--g-color-private-purple-550-solid);--g-color-text-link-visited-hover:var(--g-color-private-purple-800-solid);--g-color-text-dark-primary:var(--g-color-private-black-850);--g-color-text-dark-complementary:var(--g-color-private-black-700);--g-color-text-dark-secondary:var(--g-color-private-black-500);--g-color-text-dark-hint:var(--g-color-private-black-300);--g-color-text-light-primary:var(--g-color-private-white-1000-solid);--g-color-text-light-complementary:var(--g-color-private-white-850);--g-color-text-light-secondary:var(--g-color-private-white-700);--g-color-text-light-hint:var(--g-color-private-white-500);--g-color-text-inverted-primary:var(--g-color-text-light-primary);--g-color-text-inverted-complementary:var(--g-color-text-light-complementary);--g-color-text-inverted-secondary:var(--g-color-text-light-secondary);--g-color-text-inverted-hint:var(--g-color-text-light-hint);--g-color-base-background:var(--g-color-private-white-1000-solid);--g-color-base-generic:var(--g-color-private-black-50);--g-color-base-generic-hover:var(--g-color-private-black-150);--g-color-base-generic-medium:var(--g-color-private-black-150);--g-color-base-generic-medium-hover:var(--g-color-private-black-250);--g-color-base-generic-accent:var(--g-color-private-black-150);--g-color-base-generic-accent-disabled:var(--g-color-private-black-70);--g-color-base-generic-ultralight:var(--g-color-private-black-20-solid);--g-color-base-simple-hover:var(--g-color-private-black-50);--g-color-base-simple-hover-solid:var(--g-color-private-black-50-solid);--g-color-base-brand:var(--g-color-private-yellow-550-solid);--g-color-base-brand-hover:var(--g-color-private-yellow-600-solid);--g-color-base-selection:var(--g-color-private-yellow-200);--g-color-base-selection-hover:var(--g-color-private-yellow-300);--g-color-base-info-light:var(--g-color-private-blue-100);--g-color-base-info-light-hover:var(--g-color-private-blue-200);--g-color-base-info-medium:var(--g-color-private-blue-200);--g-color-base-info-medium-hover:var(--g-color-private-blue-300);--g-color-base-info-heavy:var(--g-color-private-blue-600-solid);--g-color-base-info-heavy-hover:var(--g-color-private-blue-700-solid);--g-color-base-positive-light:var(--g-color-private-green-100);--g-color-base-positive-light-hover:var(--g-color-private-green-200);--g-color-base-positive-medium:var(--g-color-private-green-200);--g-color-base-positive-medium-hover:var(--g-color-private-green-300);--g-color-base-positive-heavy:var(--g-color-private-green-600-solid);--g-color-base-positive-heavy-hover:var(--g-color-private-green-700-solid);--g-color-base-warning-light:var(--g-color-private-yellow-200);--g-color-base-warning-light-hover:var(--g-color-private-yellow-300);--g-color-base-warning-medium:var(--g-color-private-yellow-400);--g-color-base-warning-medium-hover:var(--g-color-private-yellow-500);--g-color-base-warning-heavy:var(--g-color-private-yellow-550-solid);--g-color-base-warning-heavy-hover:var(--g-color-private-yellow-650-solid);--g-color-base-danger-light:var(--g-color-private-red-100);--g-color-base-danger-light-hover:var(--g-color-private-red-200);--g-color-base-danger-medium:var(--g-color-private-red-200);--g-color-base-danger-medium-hover:var(--g-color-private-red-300);--g-color-base-danger-heavy:var(--g-color-private-red-600-solid);--g-color-base-danger-heavy-hover:var(--g-color-private-red-700-solid);--g-color-base-utility-light:var(--g-color-private-purple-100);--g-color-base-utility-light-hover:var(--g-color-private-purple-200);--g-color-base-utility-medium:var(--g-color-private-purple-200);--g-color-base-utility-medium-hover:var(--g-color-private-purple-300);--g-color-base-utility-heavy:var(--g-color-private-purple-600-solid);--g-color-base-utility-heavy-hover:var(--g-color-private-purple-700-solid);--g-color-base-neutral-light:var(--g-color-private-black-50);--g-color-base-neutral-light-hover:var(--g-color-private-black-100);--g-color-base-neutral-medium:var(--g-color-private-black-200);--g-color-base-neutral-medium-hover:var(--g-color-private-black-250);--g-color-base-neutral-heavy:var(--g-color-private-black-450);--g-color-base-neutral-heavy-hover:var(--g-color-private-black-550);--g-color-base-misc-light:var(--g-color-private-cool-grey-100);--g-color-base-misc-light-hover:var(--g-color-private-cool-grey-200);--g-color-base-misc-medium:var(--g-color-private-cool-grey-200);--g-color-base-misc-medium-hover:var(--g-color-private-cool-grey-300);--g-color-base-misc-heavy:var(--g-color-private-cool-grey-600-solid);--g-color-base-misc-heavy-hover:var(--g-color-private-cool-grey-700-solid);--g-color-base-light:var(--g-color-private-white-1000-solid);--g-color-base-light-hover:var(--g-color-private-white-850);--g-color-base-light-simple-hover:var(--g-color-private-white-150);--g-color-base-light-disabled:var(--g-color-private-white-150);--g-color-base-light-accent-disabled:var(--g-color-private-white-300);--g-color-base-float:var(--g-color-private-white-1000-solid);--g-color-base-float-hover:var(--g-color-private-black-50-solid);--g-color-base-float-medium:var(--g-color-private-black-550-solid);--g-color-base-float-heavy:var(--g-color-private-black-700-solid);--g-color-base-float-accent:var(--g-color-private-white-1000-solid);--g-color-base-float-accent-hover:var(--g-color-private-white-850);--g-color-base-float-announcement:var(--g-color-private-cool-grey-50-solid);--g-color-base-modal:var(--g-color-base-background);--g-color-line-generic:var(--g-color-private-black-100);--g-color-line-generic-hover:var(--g-color-private-black-150);--g-color-line-generic-active:var(--g-color-private-black-300);--g-color-line-generic-accent:var(--g-color-private-black-150);--g-color-line-generic-accent-hover:var(--g-color-private-black-300);--g-color-line-generic-solid:var(--g-color-private-black-100-solid);--g-color-line-brand:var(--g-color-private-yellow-600-solid);--g-color-line-focus:var(--g-color-private-cool-grey-450);--g-color-line-light:var(--g-color-private-white-500);--g-color-line-info:var(--g-color-private-blue-450);--g-color-line-positive:var(--g-color-private-green-450);--g-color-line-warning:var(--g-color-private-yellow-600-solid);--g-color-line-danger:var(--g-color-private-red-450);--g-color-line-utility:var(--g-color-private-purple-450);--g-color-line-misc:var(--g-color-private-cool-grey-450);--g-color-sfx-veil:var(--g-color-private-black-250);--g-color-sfx-shadow:var(--g-color-private-black-150);--g-color-sfx-shadow-heavy:var(--g-color-private-black-500);--g-color-sfx-shadow-light:var(--g-color-private-black-50);--g-color-sfx-fade:var(--g-color-private-white-300);--g-color-scroll-track:var(--g-color-base-background);--g-color-scroll-handle:var(--g-color-private-black-100);--g-color-scroll-handle-hover:var(--g-color-private-black-150);--g-color-scroll-corner:var(--g-color-private-black-100);--g-color-infographics-axis:var(--g-color-private-black-150-solid);--g-color-infographics-tooltip-bg:var(--g-color-private-white-950)}.g-root_theme_dark{--g-color-private-white-20-solid:#262226;--g-color-private-white-50-solid:#2d282d;--g-color-private-white-70-solid:#312d31;--g-color-private-white-100-solid:#383438;--g-color-private-white-150-solid:#433f43;--g-color-private-white-200-solid:#4e4a4e;--g-color-private-white-250-solid:#595559;--g-color-private-white-300-solid:#646164;--g-color-private-white-350-solid:#6f6c6f;--g-color-private-white-400-solid:#7a777a;--g-color-private-white-450-solid:#858385;--g-color-private-white-500-solid:#908e90;--g-color-private-white-550-solid:#9c999c;--g-color-private-white-600-solid:#a7a5a7;--g-color-private-white-650-solid:#b2b0b2;--g-color-private-white-700-solid:#bdbbbd;--g-color-private-white-750-solid:#c8c6c8;--g-color-private-white-800-solid:#d3d2d3;--g-color-private-white-850-solid:#deddde;--g-color-private-white-900-solid:#e9e8e9;--g-color-private-white-950-solid:#f4f4f4;--g-color-private-blue-50:#3697f11a;--g-color-private-blue-100:#3697f126;--g-color-private-blue-150:#3697f133;--g-color-private-blue-200:#3697f14d;--g-color-private-blue-250:#3697f166;--g-color-private-blue-300:#3697f180;--g-color-private-blue-350:#3697f199;--g-color-private-blue-400:#3697f1b3;--g-color-private-blue-450:#3697f1cc;--g-color-private-blue-500:#3697f1e6;--g-color-private-blue-50-solid:#242937;--g-color-private-blue-100-solid:#252f41;--g-color-private-blue-150-solid:#26354b;--g-color-private-blue-200-solid:#284260;--g-color-private-blue-250-solid:#2a4e75;--g-color-private-blue-300-solid:#2c5a8a;--g-color-private-blue-350-solid:#2e669e;--g-color-private-blue-400-solid:#3072b3;--g-color-private-blue-450-solid:#327fc8;--g-color-private-blue-500-solid:#348bdc;--g-color-private-blue-550-solid:#3697f1;--g-color-private-blue-600-solid:#4aa1f2;--g-color-private-blue-650-solid:#5eacf4;--g-color-private-blue-700-solid:#72b6f5;--g-color-private-blue-750-solid:#86c1f7;--g-color-private-blue-800-solid:#9bcbf8;--g-color-private-blue-850-solid:#afd5f9;--g-color-private-blue-900-solid:#c3e0fb;--g-color-private-blue-950-solid:#d7eafc;--g-color-private-blue-1000-solid:#e1effd;--g-color-private-green-50:#4db09b1a;--g-color-private-green-100:#4db09b26;--g-color-private-green-150:#4db09b33;--g-color-private-green-200:#4db09b4d;--g-color-private-green-250:#4db09b66;--g-color-private-green-300:#4db09b80;--g-color-private-green-350:#4db09b99;--g-color-private-green-400:#4db09bb3;--g-color-private-green-450:#4db09bcc;--g-color-private-green-500:#4db09be6;--g-color-private-green-50-solid:#262c2e;--g-color-private-green-100-solid:#283334;--g-color-private-green-150-solid:#2b3a3a;--g-color-private-green-200-solid:#2f4946;--g-color-private-green-250-solid:#335852;--g-color-private-green-300-solid:#38675f;--g-color-private-green-350-solid:#3c756b;--g-color-private-green-400-solid:#408477;--g-color-private-green-450-solid:#449383;--g-color-private-green-500-solid:#49a18f;--g-color-private-green-550-solid:#4db09b;--g-color-private-green-600-solid:#5fb8a5;--g-color-private-green-650-solid:#71c0af;--g-color-private-green-700-solid:#82c8b9;--g-color-private-green-750-solid:#94d0c3;--g-color-private-green-800-solid:#a6d8cd;--g-color-private-green-850-solid:#b8dfd7;--g-color-private-green-900-solid:#cae7e1;--g-color-private-green-950-solid:#dbefeb;--g-color-private-green-1000-solid:#e4f3f0;--g-color-private-yellow-50:#ffbe5c1a;--g-color-private-yellow-100:#ffbe5c26;--g-color-private-yellow-150:#ffbe5c33;--g-color-private-yellow-200:#ffbe5c4d;--g-color-private-yellow-250:#ffbe5c66;--g-color-private-yellow-300:#ffbe5c80;--g-color-private-yellow-350:#ffbe5c99;--g-color-private-yellow-400:#ffbe5cb3;--g-color-private-yellow-450:#ffbe5ccc;--g-color-private-yellow-500:#ffbe5ce6;--g-color-private-yellow-50-solid:#382d28;--g-color-private-yellow-100-solid:#43352b;--g-color-private-yellow-150-solid:#4e3d2e;--g-color-private-yellow-200-solid:#644d33;--g-color-private-yellow-250-solid:#7a5d39;--g-color-private-yellow-300-solid:#916e3f;--g-color-private-yellow-350-solid:#a77e45;--g-color-private-yellow-400-solid:#bd8e4b;--g-color-private-yellow-450-solid:#d39e50;--g-color-private-yellow-500-solid:#e9ae56;--g-color-private-yellow-550-solid:#ffbe5c;--g-color-private-yellow-600-solid:#ffc56c;--g-color-private-yellow-650-solid:#ffcb7d;--g-color-private-yellow-700-solid:#ffd28d;--g-color-private-yellow-750-solid:#ffd89d;--g-color-private-yellow-800-solid:#ffdfae;--g-color-private-yellow-850-solid:#ffe5be;--g-color-private-yellow-900-solid:#ffecce;--g-color-private-yellow-950-solid:#fff2de;--g-color-private-yellow-1000-solid:#fff5e7;--g-color-private-orange-50-solid:#332420;--g-color-private-orange-100-solid:#3b281f;--g-color-private-orange-150-solid:#432b1e;--g-color-private-orange-200-solid:#54321b;--g-color-private-orange-250-solid:#643919;--g-color-private-orange-300-solid:#754017;--g-color-private-orange-350-solid:#864715;--g-color-private-orange-400-solid:#964e13;--g-color-private-orange-450-solid:#a75510;--g-color-private-orange-500-solid:#b75c0e;--g-color-private-orange-700-solid:#d99255;--g-color-private-orange-800-solid:#e4b186;--g-color-private-red-50:#e5325d1a;--g-color-private-red-100:#e5325d26;--g-color-private-red-150:#e5325d33;--g-color-private-red-200:#e5325d4d;--g-color-private-red-250:#e5325d66;--g-color-private-red-300:#e5325d80;--g-color-private-red-350:#e5325d99;--g-color-private-red-400:#e5325db3;--g-color-private-red-450:#e5325dcc;--g-color-private-red-500:#e5325de6;--g-color-private-red-50-solid:#361f28;--g-color-private-red-100-solid:#3f202b;--g-color-private-red-150-solid:#49212e;--g-color-private-red-200-solid:#5d2334;--g-color-private-red-250-solid:#70253a;--g-color-private-red-300-solid:#842840;--g-color-private-red-350-solid:#972a45;--g-color-private-red-400-solid:#ab2c4b;--g-color-private-red-450-solid:#be2e51;--g-color-private-red-500-solid:#d23057;--g-color-private-red-550-solid:#e5325d;--g-color-private-red-600-solid:#e8476d;--g-color-private-red-650-solid:#ea5b7d;--g-color-private-red-700-solid:#ed708e;--g-color-private-red-750-solid:#ef849e;--g-color-private-red-800-solid:#f299ae;--g-color-private-red-850-solid:#f5adbe;--g-color-private-red-900-solid:#f7c2ce;--g-color-private-red-950-solid:#fad6df;--g-color-private-red-1000-solid:#fbe0e7;--g-color-private-purple-50-solid:#2d2233;--g-color-private-purple-100-solid:#32253c;--g-color-private-purple-150-solid:#382844;--g-color-private-purple-200-solid:#432d55;--g-color-private-purple-250-solid:#4e3266;--g-color-private-purple-300-solid:#593877;--g-color-private-purple-350-solid:#633d88;--g-color-private-purple-400-solid:#6e4299;--g-color-private-purple-450-solid:#7947aa;--g-color-private-purple-500-solid:#844dbb;--g-color-private-cool-grey-50-solid:#28272e;--g-color-private-cool-grey-100-solid:#2b2c34;--g-color-private-cool-grey-150-solid:#2e313a;--g-color-private-cool-grey-200-solid:#353b47;--g-color-private-cool-grey-250-solid:#3b4553;--g-color-private-cool-grey-300-solid:#414f5f;--g-color-private-cool-grey-350-solid:#47586b;--g-color-private-cool-grey-400-solid:#4d6277;--g-color-private-cool-grey-450-solid:#546c84;--g-color-private-cool-grey-500-solid:#5a7690;--g-color-private-cool-grey-750-solid:#a0b3c4;--g-color-private-cool-grey-800-solid:#b0c0ce;--g-color-text-primary:var(--g-color-text-light-primary);--g-color-text-complementary:var(--g-color-text-light-complementary);--g-color-text-secondary:var(--g-color-text-light-secondary);--g-color-text-hint:var(--g-color-text-light-hint);--g-color-text-info:var(--g-color-private-blue-550-solid);--g-color-text-positive:var(--g-color-private-green-550-solid);--g-color-text-warning:var(--g-color-private-yellow-550-solid);--g-color-text-danger:var(--g-color-private-red-550-solid);--g-color-text-utility:var(--g-color-private-purple-600-solid);--g-color-text-misc:var(--g-color-private-cool-grey-600-solid);--g-color-text-info-heavy:var(--g-color-private-blue-600-solid);--g-color-text-positive-heavy:var(--g-color-private-green-600-solid);--g-color-text-warning-heavy:var(--g-color-private-yellow-600-solid);--g-color-text-danger-heavy:var(--g-color-private-red-600-solid);--g-color-text-utility-heavy:var(--g-color-private-purple-650-solid);--g-color-text-misc-heavy:var(--g-color-private-cool-grey-650-solid);--g-color-text-brand:var(--g-color-private-yellow-600-solid);--g-color-text-brand-heavy:var(--g-color-private-yellow-700-solid);--g-color-text-brand-contrast:var(--g-color-text-dark-primary);--g-color-text-link:var(--g-color-private-yellow-550-solid);--g-color-text-link-hover:var(--g-color-private-orange-550-solid);--g-color-text-link-visited:var(--g-color-private-purple-600-solid);--g-color-text-link-visited-hover:var(--g-color-private-purple-750-solid);--g-color-text-dark-primary:var(--g-color-private-black-900);--g-color-text-dark-complementary:var(--g-color-private-black-700);--g-color-text-dark-secondary:var(--g-color-private-black-500);--g-color-text-dark-hint:var(--g-color-private-black-300);--g-color-text-light-primary:var(--g-color-private-white-850);--g-color-text-light-complementary:var(--g-color-private-white-700);--g-color-text-light-secondary:var(--g-color-private-white-500);--g-color-text-light-hint:var(--g-color-private-white-300);--g-color-text-inverted-primary:var(--g-color-text-dark-primary);--g-color-text-inverted-complementary:var(--g-color-text-dark-complementary);--g-color-text-inverted-secondary:var(--g-color-text-dark-secondary);--g-color-text-inverted-hint:var(--g-color-text-dark-hint);--g-color-base-background:#221d22;--g-color-base-generic:var(--g-color-private-white-100);--g-color-base-generic-hover:var(--g-color-private-white-150);--g-color-base-generic-medium:var(--g-color-private-white-250);--g-color-base-generic-medium-hover:var(--g-color-private-white-300);--g-color-base-generic-accent:var(--g-color-private-white-150);--g-color-base-generic-accent-disabled:var(--g-color-private-white-70);--g-color-base-generic-ultralight:var(--g-color-private-white-20-solid);--g-color-base-simple-hover:var(--g-color-private-white-100);--g-color-base-simple-hover-solid:var(--g-color-private-white-100-solid);--g-color-base-brand:var(--g-color-private-yellow-550-solid);--g-color-base-brand-hover:var(--g-color-private-yellow-650-solid);--g-color-base-selection:var(--g-color-private-yellow-150);--g-color-base-selection-hover:var(--g-color-private-yellow-200);--g-color-base-info-light:var(--g-color-private-blue-150);--g-color-base-info-light-hover:var(--g-color-private-blue-200);--g-color-base-info-medium:var(--g-color-private-blue-300);--g-color-base-info-medium-hover:var(--g-color-private-blue-400);--g-color-base-info-heavy:var(--g-color-private-blue-600-solid);--g-color-base-info-heavy-hover:var(--g-color-private-blue-700-solid);--g-color-base-positive-light:var(--g-color-private-green-150);--g-color-base-positive-light-hover:var(--g-color-private-green-200);--g-color-base-positive-medium:var(--g-color-private-green-300);--g-color-base-positive-medium-hover:var(--g-color-private-green-400);--g-color-base-positive-heavy:var(--g-color-private-green-600-solid);--g-color-base-positive-heavy-hover:var(--g-color-private-green-700-solid);--g-color-base-warning-light:var(--g-color-private-yellow-150);--g-color-base-warning-light-hover:var(--g-color-private-yellow-200);--g-color-base-warning-medium:var(--g-color-private-yellow-300);--g-color-base-warning-medium-hover:var(--g-color-private-yellow-400);--g-color-base-warning-heavy:var(--g-color-private-yellow-600-solid);--g-color-base-warning-heavy-hover:var(--g-color-private-yellow-700-solid);--g-color-base-danger-light:var(--g-color-private-red-150);--g-color-base-danger-light-hover:var(--g-color-private-red-200);--g-color-base-danger-medium:var(--g-color-private-red-300);--g-color-base-danger-medium-hover:var(--g-color-private-red-400);--g-color-base-danger-heavy:var(--g-color-private-red-600-solid);--g-color-base-danger-heavy-hover:var(--g-color-private-red-700-solid);--g-color-base-utility-light:var(--g-color-private-purple-150);--g-color-base-utility-light-hover:var(--g-color-private-purple-250);--g-color-base-utility-medium:var(--g-color-private-purple-300);--g-color-base-utility-medium-hover:var(--g-color-private-purple-400);--g-color-base-utility-heavy:var(--g-color-private-purple-600-solid);--g-color-base-utility-heavy-hover:var(--g-color-private-purple-700-solid);--g-color-base-neutral-light:var(--g-color-private-white-100);--g-color-base-neutral-light-hover:var(--g-color-private-white-150);--g-color-base-neutral-medium:var(--g-color-private-white-250);--g-color-base-neutral-medium-hover:var(--g-color-private-white-350);--g-color-base-neutral-heavy:var(--g-color-private-white-550);--g-color-base-neutral-heavy-hover:var(--g-color-private-white-650);--g-color-base-misc-light:var(--g-color-private-cool-grey-150);--g-color-base-misc-light-hover:var(--g-color-private-cool-grey-200);--g-color-base-misc-medium:var(--g-color-private-cool-grey-300);--g-color-base-misc-medium-hover:var(--g-color-private-cool-grey-400);--g-color-base-misc-heavy:var(--g-color-private-cool-grey-600-solid);--g-color-base-misc-heavy-hover:var(--g-color-private-cool-grey-700-solid);--g-color-base-light:var(--g-color-private-white-850);--g-color-base-light-hover:var(--g-color-private-white-700);--g-color-base-light-simple-hover:var(--g-color-private-white-150);--g-color-base-light-disabled:var(--g-color-private-white-150);--g-color-base-light-accent-disabled:var(--g-color-private-white-300);--g-color-base-float:var(--g-color-private-white-100-solid);--g-color-base-float-hover:var(--g-color-private-white-150-solid);--g-color-base-float-medium:var(--g-color-private-white-150-solid);--g-color-base-float-heavy:var(--g-color-private-white-250-solid);--g-color-base-float-accent:var(--g-color-private-white-150-solid);--g-color-base-float-accent-hover:var(--g-color-private-white-200-solid);--g-color-base-float-announcement:var(--g-color-private-white-150-solid);--g-color-base-modal:var(--g-color-base-background);--g-color-line-generic:var(--g-color-private-white-150);--g-color-line-generic-hover:var(--g-color-private-white-250);--g-color-line-generic-active:var(--g-color-private-white-300);--g-color-line-generic-accent:var(--g-color-private-white-150);--g-color-line-generic-accent-hover:var(--g-color-private-white-300);--g-color-line-generic-solid:var(--g-color-private-white-150-solid);--g-color-line-brand:var(--g-color-private-yellow-600-solid);--g-color-line-focus:var(--g-color-private-cool-grey-450);--g-color-line-light:var(--g-color-private-white-500);--g-color-line-info:var(--g-color-private-blue-450);--g-color-line-positive:var(--g-color-private-green-450);--g-color-line-warning:var(--g-color-private-yellow-450);--g-color-line-danger:var(--g-color-private-red-450);--g-color-line-utility:var(--g-color-private-purple-450);--g-color-line-misc:var(--g-color-private-cool-grey-450);--g-color-sfx-veil:var(--g-color-private-black-600);--g-color-sfx-shadow:var(--g-color-private-black-200);--g-color-sfx-shadow-heavy:var(--g-color-private-black-500);--g-color-sfx-shadow-light:var(--g-color-private-black-200);--g-color-sfx-fade:var(--g-color-private-white-250);--g-color-scroll-track:var(--g-color-base-background);--g-color-scroll-handle:var(--g-color-private-white-150);--g-color-scroll-handle-hover:var(--g-color-private-white-250);--g-color-scroll-corner:var(--g-color-private-white-150);--g-color-infographics-axis:var(--g-color-private-white-150-solid);--g-color-infographics-tooltip-bg:var(--g-color-private-white-opaque-150)}.g-root_theme_light-hc{--g-color-private-blue-50:#3697f11a;--g-color-private-blue-100:#3697f126;--g-color-private-blue-150:#3697f133;--g-color-private-blue-200:#3697f14d;--g-color-private-blue-250:#3697f166;--g-color-private-blue-300:#3697f180;--g-color-private-blue-350:#3697f199;--g-color-private-blue-400:#3697f1b3;--g-color-private-blue-450:#3697f1cc;--g-color-private-blue-500:#3697f1e6;--g-color-private-blue-50-solid:#ebf5fe;--g-color-private-blue-100-solid:#e1effd;--g-color-private-blue-150-solid:#d7eafc;--g-color-private-blue-200-solid:#c3e0fb;--g-color-private-blue-250-solid:#afd5f9;--g-color-private-blue-300-solid:#9bcbf8;--g-color-private-blue-350-solid:#86c1f7;--g-color-private-blue-400-solid:#72b6f5;--g-color-private-blue-450-solid:#5eacf4;--g-color-private-blue-500-solid:#4aa1f2;--g-color-private-blue-550-solid:#3697f1;--g-color-private-blue-600-solid:#328adb;--g-color-private-blue-650-solid:#2f7cc4;--g-color-private-blue-700-solid:#2b6fae;--g-color-private-blue-750-solid:#286198;--g-color-private-blue-800-solid:#245482;--g-color-private-blue-850-solid:#20476b;--g-color-private-blue-900-solid:#1d3955;--g-color-private-blue-950-solid:#192c3f;--g-color-private-blue-1000-solid:#172533;--g-color-private-green-50:#32ba761a;--g-color-private-green-100:#32ba7626;--g-color-private-green-150:#32ba7633;--g-color-private-green-200:#32ba764d;--g-color-private-green-250:#32ba7666;--g-color-private-green-300:#32ba7680;--g-color-private-green-350:#32ba7699;--g-color-private-green-400:#32ba76b3;--g-color-private-green-450:#32ba76cc;--g-color-private-green-500:#32ba76e6;--g-color-private-green-50-solid:#ebf8f1;--g-color-private-green-100-solid:#e0f5ea;--g-color-private-green-150-solid:#d6f1e4;--g-color-private-green-200-solid:#c2ead6;--g-color-private-green-250-solid:#ade3c8;--g-color-private-green-300-solid:#9db;--g-color-private-green-350-solid:#84d6ad;--g-color-private-green-400-solid:#70cf9f;--g-color-private-green-450-solid:#5bc891;--g-color-private-green-500-solid:#47c184;--g-color-private-green-550-solid:#32ba76;--g-color-private-green-600-solid:#2fa96c;--g-color-private-green-650-solid:#2c9862;--g-color-private-green-700-solid:#288758;--g-color-private-green-750-solid:#25764e;--g-color-private-green-800-solid:#264;--g-color-private-green-850-solid:#1f553a;--g-color-private-green-900-solid:#1c4430;--g-color-private-green-950-solid:#183326;--g-color-private-green-1000-solid:#172a21;--g-color-private-yellow-50:#ffbe5c1a;--g-color-private-yellow-100:#ffbe5c26;--g-color-private-yellow-150:#ffbe5c33;--g-color-private-yellow-200:#ffbe5c4d;--g-color-private-yellow-250:#ffbe5c66;--g-color-private-yellow-300:#ffbe5c80;--g-color-private-yellow-350:#ffbe5c99;--g-color-private-yellow-400:#ffbe5cb3;--g-color-private-yellow-450:#ffbe5ccc;--g-color-private-yellow-500:#ffbe5ce6;--g-color-private-yellow-50-solid:#fff9ef;--g-color-private-yellow-100-solid:#fff5e7;--g-color-private-yellow-150-solid:#fff2de;--g-color-private-yellow-200-solid:#ffecce;--g-color-private-yellow-250-solid:#ffe5be;--g-color-private-yellow-300-solid:#ffdfae;--g-color-private-yellow-350-solid:#ffd89d;--g-color-private-yellow-400-solid:#ffd28d;--g-color-private-yellow-450-solid:#ffcb7d;--g-color-private-yellow-500-solid:#ffc56c;--g-color-private-yellow-550-solid:#ffbe5c;--g-color-private-yellow-600-solid:#e7ad55;--g-color-private-yellow-650-solid:#d09b4d;--g-color-private-yellow-700-solid:#b88a46;--g-color-private-yellow-750-solid:#a0793e;--g-color-private-yellow-800-solid:#896837;--g-color-private-yellow-850-solid:#715630;--g-color-private-yellow-900-solid:#594528;--g-color-private-yellow-950-solid:#413421;--g-color-private-yellow-1000-solid:#362b1d;--g-color-private-orange-400-solid:#ffa04d;--g-color-private-orange-500-solid:#ff8519;--g-color-private-orange-600-solid:#e76d02;--g-color-private-orange-650-solid:#d06304;--g-color-private-orange-700-solid:#b85805;--g-color-private-orange-750-solid:#a04e07;--g-color-private-orange-800-solid:#894409;--g-color-private-orange-850-solid:#713a0b;--g-color-private-orange-900-solid:#59300d;--g-color-private-orange-950-solid:#41250e;--g-color-private-orange-1000-solid:#36200f;--g-color-private-red-50:#ff003d1a;--g-color-private-red-100:#ff003d26;--g-color-private-red-150:#ff003d33;--g-color-private-red-200:#ff003d4d;--g-color-private-red-250:#ff003d66;--g-color-private-red-300:#ff003d80;--g-color-private-red-350:#ff003d99;--g-color-private-red-400:#ff003db3;--g-color-private-red-450:#ff003dcc;--g-color-private-red-500:#ff003de6;--g-color-private-red-50-solid:#ffe6ec;--g-color-private-red-100-solid:#ffd9e2;--g-color-private-red-150-solid:#ffccd8;--g-color-private-red-200-solid:#ffb3c5;--g-color-private-red-250-solid:#ff99b1;--g-color-private-red-300-solid:#ff809e;--g-color-private-red-350-solid:#ff668b;--g-color-private-red-400-solid:#ff4d77;--g-color-private-red-450-solid:#ff3364;--g-color-private-red-500-solid:#ff1950;--g-color-private-red-550-solid:#ff003d;--g-color-private-red-600-solid:#e70239;--g-color-private-red-650-solid:#d00334;--g-color-private-red-700-solid:#b80530;--g-color-private-red-750-solid:#a0072c;--g-color-private-red-800-solid:#890928;--g-color-private-red-850-solid:#710a23;--g-color-private-red-900-solid:#590c1f;--g-color-private-red-950-solid:#410e1b;--g-color-private-red-1000-solid:#360e18;--g-color-private-purple-600-solid:#834cb9;--g-color-private-purple-650-solid:#7645a7;--g-color-private-purple-700-solid:#6a3f94;--g-color-private-purple-750-solid:#5d3882;--g-color-private-purple-800-solid:#51326f;--g-color-private-purple-850-solid:#442b5c;--g-color-private-purple-900-solid:#38254a;--g-color-private-purple-950-solid:#2b1e37;--g-color-private-purple-1000-solid:#251b2e;--g-color-private-cool-grey-300-solid:#b5c2cc;--g-color-private-cool-grey-600-solid:#62798c;--g-color-private-cool-grey-650-solid:#596d7e;--g-color-private-cool-grey-700-solid:#506271;--g-color-private-cool-grey-750-solid:#475663;--g-color-private-cool-grey-800-solid:#3f4b56;--g-color-private-cool-grey-850-solid:#363f48;--g-color-private-cool-grey-900-solid:#2d343b;--g-color-private-cool-grey-950-solid:#24282d;--g-color-private-cool-grey-1000-solid:#1f2226;--g-color-text-primary:var(--g-color-text-dark-primary);--g-color-text-complementary:var(--g-color-text-dark-complementary);--g-color-text-secondary:var(--g-color-text-dark-secondary);--g-color-text-hint:var(--g-color-text-dark-hint);--g-color-text-info:var(--g-color-private-blue-650-solid);--g-color-text-positive:var(--g-color-private-green-650-solid);--g-color-text-warning:var(--g-color-private-yellow-700-solid);--g-color-text-danger:var(--g-color-private-red-650-solid);--g-color-text-utility:var(--g-color-private-purple-650-solid);--g-color-text-misc:var(--g-color-private-cool-grey-650-solid);--g-color-text-info-heavy:var(--g-color-private-blue-900-solid);--g-color-text-positive-heavy:var(--g-color-private-green-900-solid);--g-color-text-warning-heavy:var(--g-color-private-orange-900-solid);--g-color-text-danger-heavy:var(--g-color-private-red-900-solid);--g-color-text-utility-heavy:var(--g-color-private-purple-900-solid);--g-color-text-misc-heavy:var(--g-color-private-cool-grey-900-solid);--g-color-text-brand:var(--g-color-private-yellow-700-solid);--g-color-text-brand-heavy:var(--g-color-private-orange-900-solid);--g-color-text-brand-contrast:var(--g-color-text-dark-primary);--g-color-text-link:var(--g-color-private-yellow-700-solid);--g-color-text-link-hover:var(--g-color-private-orange-700-solid);--g-color-text-link-visited:var(--g-color-private-purple-600-solid);--g-color-text-link-visited-hover:var(--g-color-private-purple-850-solid);--g-color-text-dark-primary:var(--g-color-private-black-1000-solid);--g-color-text-dark-complementary:var(--g-color-private-black-850);--g-color-text-dark-secondary:var(--g-color-private-black-700);--g-color-text-dark-hint:var(--g-color-private-black-500);--g-color-text-light-primary:var(--g-color-private-white-1000-solid);--g-color-text-light-complementary:var(--g-color-private-white-850);--g-color-text-light-secondary:var(--g-color-private-white-700);--g-color-text-light-hint:var(--g-color-private-white-500);--g-color-text-inverted-primary:var(--g-color-text-light-primary);--g-color-text-inverted-complementary:var(--g-color-text-light-complementary);--g-color-text-inverted-secondary:var(--g-color-text-light-secondary);--g-color-text-inverted-hint:var(--g-color-text-light-hint);--g-color-base-background:var(--g-color-private-white-1000-solid);--g-color-base-generic:var(--g-color-private-black-150);--g-color-base-generic-hover:var(--g-color-private-black-300);--g-color-base-generic-medium:var(--g-color-private-black-250);--g-color-base-generic-medium-hover:var(--g-color-private-black-350);--g-color-base-generic-accent:var(--g-color-private-black-250);--g-color-base-generic-accent-disabled:var(--g-color-private-black-150);--g-color-base-generic-ultralight:var(--g-color-private-black-50-solid);--g-color-base-simple-hover:var(--g-color-private-black-150);--g-color-base-simple-hover-solid:var(--g-color-private-black-150-solid);--g-color-base-brand:var(--g-color-private-yellow-550-solid);--g-color-base-brand-hover:var(--g-color-private-yellow-650-solid);--g-color-base-selection:var(--g-color-private-yellow-300);--g-color-base-selection-hover:var(--g-color-private-yellow-400);--g-color-base-info-light:var(--g-color-private-blue-250);--g-color-base-info-light-hover:var(--g-color-private-blue-350);--g-color-base-info-medium:var(--g-color-private-blue-400);--g-color-base-info-medium-hover:var(--g-color-private-blue-500);--g-color-base-info-heavy:var(--g-color-private-blue-700-solid);--g-color-base-info-heavy-hover:var(--g-color-private-blue-850-solid);--g-color-base-positive-light:var(--g-color-private-green-250);--g-color-base-positive-light-hover:var(--g-color-private-green-350);--g-color-base-positive-medium:var(--g-color-private-green-400);--g-color-base-positive-medium-hover:var(--g-color-private-green-500);--g-color-base-positive-heavy:var(--g-color-private-green-700-solid);--g-color-base-positive-heavy-hover:var(--g-color-private-green-800-solid);--g-color-base-warning-light:var(--g-color-private-yellow-300);--g-color-base-warning-light-hover:var(--g-color-private-yellow-400);--g-color-base-warning-medium:var(--g-color-private-yellow-400);--g-color-base-warning-medium-hover:var(--g-color-private-yellow-550-solid);--g-color-base-warning-heavy:var(--g-color-private-yellow-600-solid);--g-color-base-warning-heavy-hover:var(--g-color-private-yellow-700-solid);--g-color-base-danger-light:var(--g-color-private-red-250);--g-color-base-danger-light-hover:var(--g-color-private-red-350);--g-color-base-danger-medium:var(--g-color-private-red-400);--g-color-base-danger-medium-hover:var(--g-color-private-red-500);--g-color-base-danger-heavy:var(--g-color-private-red-700-solid);--g-color-base-danger-heavy-hover:var(--g-color-private-red-800-solid);--g-color-base-utility-light:var(--g-color-private-purple-250);--g-color-base-utility-light-hover:var(--g-color-private-purple-350);--g-color-base-utility-medium:var(--g-color-private-purple-400);--g-color-base-utility-medium-hover:var(--g-color-private-purple-500);--g-color-base-utility-heavy:var(--g-color-private-purple-700-solid);--g-color-base-utility-heavy-hover:var(--g-color-private-purple-800-solid);--g-color-base-neutral-light:var(--g-color-private-black-150);--g-color-base-neutral-light-hover:var(--g-color-private-black-250);--g-color-base-neutral-medium:var(--g-color-private-black-300);--g-color-base-neutral-medium-hover:var(--g-color-private-black-400);--g-color-base-neutral-heavy:var(--g-color-private-black-550);--g-color-base-neutral-heavy-hover:var(--g-color-private-black-650);--g-color-base-misc-light:var(--g-color-private-cool-grey-250);--g-color-base-misc-light-hover:var(--g-color-private-cool-grey-350);--g-color-base-misc-medium:var(--g-color-private-cool-grey-400);--g-color-base-misc-medium-hover:var(--g-color-private-cool-grey-500);--g-color-base-misc-heavy:var(--g-color-private-cool-grey-700-solid);--g-color-base-misc-heavy-hover:var(--g-color-private-cool-grey-800-solid);--g-color-base-light:var(--g-color-private-white-1000-solid);--g-color-base-light-hover:var(--g-color-private-white-850);--g-color-base-light-simple-hover:var(--g-color-private-white-300);--g-color-base-light-disabled:var(--g-color-private-white-150);--g-color-base-light-accent-disabled:var(--g-color-private-white-300);--g-color-base-float:var(--g-color-private-white-1000-solid);--g-color-base-float-hover:var(--g-color-private-black-150-solid);--g-color-base-float-medium:var(--g-color-private-black-550-solid);--g-color-base-float-heavy:var(--g-color-private-black-700-solid);--g-color-base-float-accent:var(--g-color-private-white-1000-solid);--g-color-base-float-accent-hover:var(--g-color-private-white-850);--g-color-base-float-announcement:var(--g-color-private-cool-grey-150-solid);--g-color-base-modal:var(--g-color-base-background);--g-color-line-generic:var(--g-color-private-black-200);--g-color-line-generic-hover:var(--g-color-private-black-400);--g-color-line-generic-active:var(--g-color-private-black-700);--g-color-line-generic-accent:var(--g-color-private-black-300);--g-color-line-generic-accent-hover:var(--g-color-private-black-700);--g-color-line-generic-solid:var(--g-color-private-black-200-solid);--g-color-line-brand:var(--g-color-private-yellow-600-solid);--g-color-line-focus:var(--g-color-private-cool-grey-450);--g-color-line-light:var(--g-color-private-white-500);--g-color-line-info:var(--g-color-private-blue-450);--g-color-line-positive:var(--g-color-private-green-450);--g-color-line-warning:var(--g-color-private-yellow-600-solid);--g-color-line-danger:var(--g-color-private-red-450);--g-color-line-utility:var(--g-color-private-purple-450);--g-color-line-misc:var(--g-color-private-cool-grey-450);--g-color-sfx-veil:var(--g-color-private-black-450);--g-color-sfx-shadow:var(--g-color-private-black-300);--g-color-sfx-shadow-heavy:var(--g-color-private-black-600);--g-color-sfx-shadow-light:var(--g-color-private-black-100);--g-color-sfx-fade:var(--g-color-private-white-300);--g-color-scroll-track:var(--g-color-base-background);--g-color-scroll-handle:var(--g-color-private-black-100);--g-color-scroll-handle-hover:var(--g-color-private-black-150);--g-color-scroll-corner:var(--g-color-private-black-100);--g-color-infographics-axis:var(--g-color-private-black-150-solid);--g-color-infographics-tooltip-bg:var(--g-color-private-white-950)}.g-root_theme_dark-hc{--g-color-private-white-50-solid:#1e1d1e;--g-color-private-white-70-solid:#232223;--g-color-private-white-100-solid:#2a292a;--g-color-private-white-150-solid:#363536;--g-color-private-white-200-solid:#414141;--g-color-private-white-250-solid:#4d4d4d;--g-color-private-white-300-solid:#595859;--g-color-private-white-350-solid:#656465;--g-color-private-white-400-solid:#717071;--g-color-private-white-450-solid:#7d7c7d;--g-color-private-white-500-solid:#888;--g-color-private-white-550-solid:#949494;--g-color-private-white-600-solid:#a0a0a0;--g-color-private-white-650-solid:#acacac;--g-color-private-white-700-solid:#b8b8b8;--g-color-private-white-750-solid:#c4c3c4;--g-color-private-white-800-solid:#d0cfd0;--g-color-private-white-850-solid:#d0cfd0;--g-color-private-white-900-solid:#e7e7e7;--g-color-private-white-950-solid:#f3f3f3;--g-color-private-blue-50:#3697f11a;--g-color-private-blue-100:#3697f126;--g-color-private-blue-150:#3697f133;--g-color-private-blue-200:#3697f14d;--g-color-private-blue-250:#3697f166;--g-color-private-blue-300:#3697f180;--g-color-private-blue-350:#3697f199;--g-color-private-blue-400:#3697f1b3;--g-color-private-blue-450:#3697f1cc;--g-color-private-blue-500:#3697f1e6;--g-color-private-blue-50-solid:#161e28;--g-color-private-blue-100-solid:#172533;--g-color-private-blue-150-solid:#192c3f;--g-color-private-blue-200-solid:#1d3955;--g-color-private-blue-250-solid:#20476b;--g-color-private-blue-300-solid:#245482;--g-color-private-blue-350-solid:#286198;--g-color-private-blue-400-solid:#2b6fae;--g-color-private-blue-450-solid:#2f7cc4;--g-color-private-blue-500-solid:#328adb;--g-color-private-blue-550-solid:#3697f1;--g-color-private-blue-600-solid:#4aa1f2;--g-color-private-blue-650-solid:#5eacf4;--g-color-private-blue-700-solid:#72b6f5;--g-color-private-blue-750-solid:#86c1f7;--g-color-private-blue-800-solid:#9bcbf8;--g-color-private-blue-850-solid:#afd5f9;--g-color-private-blue-900-solid:#c3e0fb;--g-color-private-blue-950-solid:#d7eafc;--g-color-private-blue-1000-solid:#e1effd;--g-color-private-green-50:#4db09b1a;--g-color-private-green-100:#4db09b26;--g-color-private-green-150:#4db09b33;--g-color-private-green-200:#4db09b4d;--g-color-private-green-250:#4db09b66;--g-color-private-green-300:#4db09b80;--g-color-private-green-350:#4db09b99;--g-color-private-green-400:#4db09bb3;--g-color-private-green-450:#4db09bcc;--g-color-private-green-500:#4db09be6;--g-color-private-green-50-solid:#182120;--g-color-private-green-100-solid:#1b2927;--g-color-private-green-150-solid:#1e312d;--g-color-private-green-200-solid:#24413b;--g-color-private-green-250-solid:#2a5149;--g-color-private-green-300-solid:#306157;--g-color-private-green-350-solid:#357064;--g-color-private-green-400-solid:#3b8072;--g-color-private-green-450-solid:#419080;--g-color-private-green-500-solid:#47a08d;--g-color-private-green-550-solid:#4db09b;--g-color-private-green-600-solid:#5fb8a5;--g-color-private-green-650-solid:#71c0af;--g-color-private-green-700-solid:#82c8b9;--g-color-private-green-750-solid:#94d0c3;--g-color-private-green-800-solid:#a6d8cd;--g-color-private-green-850-solid:#b8dfd7;--g-color-private-green-900-solid:#cae7e1;--g-color-private-green-950-solid:#dbefeb;--g-color-private-green-1000-solid:#e4f3f0;--g-color-private-yellow-50:#ffbe5c1a;--g-color-private-yellow-100:#ffbe5c26;--g-color-private-yellow-150:#ffbe5c33;--g-color-private-yellow-200:#ffbe5c4d;--g-color-private-yellow-250:#ffbe5c66;--g-color-private-yellow-300:#ffbe5c80;--g-color-private-yellow-350:#ffbe5c99;--g-color-private-yellow-400:#ffbe5cb3;--g-color-private-yellow-450:#ffbe5ccc;--g-color-private-yellow-500:#ffbe5ce6;--g-color-private-yellow-50-solid:#2a2219;--g-color-private-yellow-100-solid:#362b1d;--g-color-private-yellow-150-solid:#413421;--g-color-private-yellow-200-solid:#594528;--g-color-private-yellow-250-solid:#715630;--g-color-private-yellow-300-solid:#896837;--g-color-private-yellow-350-solid:#a0793e;--g-color-private-yellow-400-solid:#b88a46;--g-color-private-yellow-450-solid:#d09b4d;--g-color-private-yellow-500-solid:#e7ad55;--g-color-private-yellow-550-solid:#ffbe5c;--g-color-private-yellow-600-solid:#ffc56c;--g-color-private-yellow-650-solid:#ffcb7d;--g-color-private-yellow-700-solid:#ffd28d;--g-color-private-yellow-750-solid:#ffd89d;--g-color-private-yellow-800-solid:#ffdfae;--g-color-private-yellow-850-solid:#ffe5be;--g-color-private-yellow-900-solid:#ffecce;--g-color-private-yellow-950-solid:#fff2de;--g-color-private-yellow-1000-solid:#fff5e7;--g-color-private-orange-50-solid:#241911;--g-color-private-orange-100-solid:#2d1d11;--g-color-private-orange-150-solid:#362111;--g-color-private-orange-200-solid:#492a10;--g-color-private-orange-250-solid:#5b3210;--g-color-private-orange-300-solid:#6d3a0f;--g-color-private-orange-350-solid:#7f420e;--g-color-private-orange-400-solid:#914a0e;--g-color-private-orange-450-solid:#a4530d;--g-color-private-orange-500-solid:#b65b0d;--g-color-private-orange-700-solid:#d99255;--g-color-private-orange-800-solid:#e4b186;--g-color-private-red-50:#e5325d1a;--g-color-private-red-100:#e5325d26;--g-color-private-red-150:#e5325d33;--g-color-private-red-200:#e5325d4d;--g-color-private-red-250:#e5325d66;--g-color-private-red-300:#e5325d80;--g-color-private-red-350:#e5325d99;--g-color-private-red-400:#e5325db3;--g-color-private-red-450:#e5325dcc;--g-color-private-red-500:#e5325de6;--g-color-private-red-50-solid:#27141a;--g-color-private-red-100-solid:#32161d;--g-color-private-red-150-solid:#3c1821;--g-color-private-red-200-solid:#511b29;--g-color-private-red-250-solid:#661e30;--g-color-private-red-300-solid:#7c2238;--g-color-private-red-350-solid:#91253f;--g-color-private-red-400-solid:#a62847;--g-color-private-red-450-solid:#bb2b4e;--g-color-private-red-500-solid:#d02f56;--g-color-private-red-550-solid:#e5325d;--g-color-private-red-600-solid:#e8476d;--g-color-private-red-650-solid:#ea5b7d;--g-color-private-red-700-solid:#ed708e;--g-color-private-red-750-solid:#ef849e;--g-color-private-red-800-solid:#f299ae;--g-color-private-red-850-solid:#f5adbe;--g-color-private-red-900-solid:#f7c2ce;--g-color-private-red-950-solid:#fad6df;--g-color-private-red-1000-solid:#fbe0e7;--g-color-private-purple-50-solid:#1f1825;--g-color-private-purple-100-solid:#251b2e;--g-color-private-purple-150-solid:#2b1e37;--g-color-private-purple-200-solid:#38254a;--g-color-private-purple-250-solid:#442b5c;--g-color-private-purple-300-solid:#51326f;--g-color-private-purple-350-solid:#5d3882;--g-color-private-purple-400-solid:#6a3f94;--g-color-private-purple-450-solid:#7645a7;--g-color-private-purple-500-solid:#834cb9;--g-color-private-cool-grey-50-solid:#1a1c20;--g-color-private-cool-grey-100-solid:#1e2227;--g-color-private-cool-grey-150-solid:#22272e;--g-color-private-cool-grey-200-solid:#29323b;--g-color-private-cool-grey-250-solid:#313d49;--g-color-private-cool-grey-300-solid:#394957;--g-color-private-cool-grey-350-solid:#415465;--g-color-private-cool-grey-400-solid:#495f73;--g-color-private-cool-grey-450-solid:#506a80;--g-color-private-cool-grey-500-solid:#58758e;--g-color-private-cool-grey-750-solid:#a0b3c4;--g-color-private-cool-grey-800-solid:#b0c0ce;--g-color-text-primary:var(--g-color-text-light-primary);--g-color-text-complementary:var(--g-color-text-light-complementary);--g-color-text-secondary:var(--g-color-text-light-secondary);--g-color-text-hint:var(--g-color-text-light-hint);--g-color-text-info:var(--g-color-private-blue-650-solid);--g-color-text-positive:var(--g-color-private-green-650-solid);--g-color-text-warning:var(--g-color-private-yellow-650-solid);--g-color-text-danger:var(--g-color-private-red-650-solid);--g-color-text-utility:var(--g-color-private-purple-650-solid);--g-color-text-misc:var(--g-color-private-cool-grey-650-solid);--g-color-text-info-heavy:var(--g-color-private-blue-850-solid);--g-color-text-positive-heavy:var(--g-color-private-green-850-solid);--g-color-text-warning-heavy:var(--g-color-private-yellow-850-solid);--g-color-text-danger-heavy:var(--g-color-private-red-850-solid);--g-color-text-utility-heavy:var(--g-color-private-purple-850-solid);--g-color-text-misc-heavy:var(--g-color-private-cool-grey-850-solid);--g-color-text-brand:var(--g-color-private-yellow-600-solid);--g-color-text-brand-heavy:var(--g-color-private-yellow-700-solid);--g-color-text-brand-contrast:var(--g-color-text-dark-primary);--g-color-text-link:var(--g-color-private-yellow-550-solid);--g-color-text-link-hover:var(--g-color-private-orange-550-solid);--g-color-text-link-visited:var(--g-color-private-purple-650-solid);--g-color-text-link-visited-hover:var(--g-color-private-purple-800-solid);--g-color-text-dark-primary:var(--g-color-private-black-1000-solid);--g-color-text-dark-complementary:var(--g-color-private-black-800);--g-color-text-dark-secondary:var(--g-color-private-black-600);--g-color-text-dark-hint:var(--g-color-private-black-400);--g-color-text-light-primary:var(--g-color-private-white-1000-solid);--g-color-text-light-complementary:var(--g-color-private-white-800);--g-color-text-light-secondary:var(--g-color-private-white-600);--g-color-text-light-hint:var(--g-color-private-white-400);--g-color-text-inverted-primary:var(--g-color-text-dark-primary);--g-color-text-inverted-complementary:var(--g-color-text-dark-complementary);--g-color-text-inverted-secondary:var(--g-color-text-dark-secondary);--g-color-text-inverted-hint:var(--g-color-text-dark-hint);--g-color-base-background:#121112;--g-color-base-generic:var(--g-color-private-white-100);--g-color-base-generic-hover:var(--g-color-private-white-250);--g-color-base-generic-medium:var(--g-color-private-white-250);--g-color-base-generic-medium-hover:var(--g-color-private-white-400);--g-color-base-generic-accent:var(--g-color-private-white-200);--g-color-base-generic-accent-disabled:var(--g-color-private-white-150);--g-color-base-generic-ultralight:var(--g-color-private-white-50);--g-color-base-simple-hover:var(--g-color-private-white-250);--g-color-base-simple-hover-solid:var(--g-color-private-white-250-solid);--g-color-base-brand:var(--g-color-private-yellow-550-solid);--g-color-base-brand-hover:var(--g-color-private-yellow-700-solid);--g-color-base-selection:var(--g-color-private-yellow-250);--g-color-base-selection-hover:var(--g-color-private-yellow-400);--g-color-base-info-light:var(--g-color-private-blue-250);--g-color-base-info-light-hover:var(--g-color-private-blue-400);--g-color-base-info-medium:var(--g-color-private-blue-450);--g-color-base-info-medium-hover:var(--g-color-private-blue-600-solid);--g-color-base-info-heavy:var(--g-color-private-blue-700-solid);--g-color-base-info-heavy-hover:var(--g-color-private-blue-850-solid);--g-color-base-positive-light:var(--g-color-private-green-250);--g-color-base-positive-light-hover:var(--g-color-private-green-400);--g-color-base-positive-medium:var(--g-color-private-green-450);--g-color-base-positive-medium-hover:var(--g-color-private-green-600-solid);--g-color-base-positive-heavy:var(--g-color-private-green-700-solid);--g-color-base-positive-heavy-hover:var(--g-color-private-green-850-solid);--g-color-base-warning-light:var(--g-color-private-yellow-250);--g-color-base-warning-light-hover:var(--g-color-private-yellow-400);--g-color-base-warning-medium:var(--g-color-private-yellow-450);--g-color-base-warning-medium-hover:var(--g-color-private-yellow-600-solid);--g-color-base-warning-heavy:var(--g-color-private-yellow-700-solid);--g-color-base-warning-heavy-hover:var(--g-color-private-yellow-850-solid);--g-color-base-danger-light:var(--g-color-private-red-250);--g-color-base-danger-light-hover:var(--g-color-private-red-400);--g-color-base-danger-medium:var(--g-color-private-red-450);--g-color-base-danger-medium-hover:var(--g-color-private-red-600-solid);--g-color-base-danger-heavy:var(--g-color-private-red-700-solid);--g-color-base-danger-heavy-hover:var(--g-color-private-red-850-solid);--g-color-base-utility-light:var(--g-color-private-purple-250);--g-color-base-utility-light-hover:var(--g-color-private-purple-400);--g-color-base-utility-medium:var(--g-color-private-purple-450);--g-color-base-utility-medium-hover:var(--g-color-private-purple-600-solid);--g-color-base-utility-heavy:var(--g-color-private-purple-700-solid);--g-color-base-utility-heavy-hover:var(--g-color-private-purple-850-solid);--g-color-base-neutral-light:var(--g-color-private-white-200);--g-color-base-neutral-light-hover:var(--g-color-private-white-350);--g-color-base-neutral-medium:var(--g-color-private-white-400);--g-color-base-neutral-medium-hover:var(--g-color-private-white-550);--g-color-base-neutral-heavy:var(--g-color-private-white-650);--g-color-base-neutral-heavy-hover:var(--g-color-private-white-750);--g-color-base-misc-light:var(--g-color-private-cool-grey-250);--g-color-base-misc-light-hover:var(--g-color-private-cool-grey-400);--g-color-base-misc-medium:var(--g-color-private-cool-grey-450);--g-color-base-misc-medium-hover:var(--g-color-private-cool-grey-600-solid);--g-color-base-misc-heavy:var(--g-color-private-cool-grey-700-solid);--g-color-base-misc-heavy-hover:var(--g-color-private-cool-grey-850-solid);--g-color-base-light:var(--g-color-private-white-850);--g-color-base-light-hover:var(--g-color-private-white-700);--g-color-base-light-simple-hover:var(--g-color-private-white-150);--g-color-base-light-disabled:var(--g-color-private-white-150);--g-color-base-light-accent-disabled:var(--g-color-private-white-300);--g-color-base-float:var(--g-color-private-white-100-solid);--g-color-base-float-hover:var(--g-color-private-white-200-solid);--g-color-base-float-medium:var(--g-color-private-white-200-solid);--g-color-base-float-heavy:var(--g-color-private-white-300-solid);--g-color-base-float-accent:var(--g-color-private-white-300-solid);--g-color-base-float-accent-hover:var(--g-color-private-white-400-solid);--g-color-base-float-announcement:var(--g-color-private-white-200-solid);--g-color-base-modal:var(--g-color-base-background);--g-color-line-generic:var(--g-color-private-white-150);--g-color-line-generic-hover:var(--g-color-private-white-250);--g-color-line-generic-active:var(--g-color-private-white-600);--g-color-line-generic-accent:var(--g-color-private-white-350);--g-color-line-generic-accent-hover:var(--g-color-private-white-800);--g-color-line-generic-solid:var(--g-color-private-white-150-solid);--g-color-line-brand:var(--g-color-private-yellow-600-solid);--g-color-line-focus:var(--g-color-private-cool-grey-550-solid);--g-color-line-light:var(--g-color-private-white-500);--g-color-line-info:var(--g-color-private-blue-550-solid);--g-color-line-positive:var(--g-color-private-green-550-solid);--g-color-line-warning:var(--g-color-private-yellow-550-solid);--g-color-line-danger:var(--g-color-private-red-550-solid);--g-color-line-utility:var(--g-color-private-purple-550-solid);--g-color-line-misc:var(--g-color-private-cool-grey-550-solid);--g-color-sfx-veil:var(--g-color-private-black-700);--g-color-sfx-shadow:var(--g-color-private-black-200);--g-color-sfx-shadow-heavy:var(--g-color-private-black-400);--g-color-sfx-shadow-light:var(--g-color-private-black-200);--g-color-sfx-fade:var(--g-color-private-white-250);--g-color-scroll-track:var(--g-color-base-background);--g-color-scroll-handle:var(--g-color-private-white-150);--g-color-scroll-handle-hover:var(--g-color-private-white-250);--g-color-scroll-corner:var(--g-color-private-white-150);--g-color-infographics-axis:var(--g-color-private-white-150-solid);--g-color-infographics-tooltip-bg:var(--g-color-private-white-opaque-150)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar){scrollbar-color:var(--g-color-scroll-handle) var(--g-color-scroll-track);scrollbar-width:var(--g-scrollbar-width)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar{background:var(--g-color-scroll-track);height:var(--g-scrollbar-width);width:var(--g-scrollbar-width)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar-track,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar-track{background:var(--g-color-scroll-track)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar-corner,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar-corner{background:var(--g-color-scroll-corner)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar-thumb,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar-thumb{background:var(--g-color-scroll-handle)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar-thumb:hover,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar-thumb:hover{background:var(--g-color-scroll-handle-hover)}@keyframes g-loading-animation{0%{background-position:-12px 0}to{background-position:0 0}}:root:has(body.g-root_theme_light),:root:has(body.g-root_theme_light-hc){color-scheme:light}:root:has(body.g-root_theme_dark),:root:has(body.g-root_theme_dark-hc){color-scheme:dark}@media(prefers-reduced-motion:reduce){*,:after,:before{animation-duration:.001ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.001ms!important}}.g-root{--g-text-header-font-weight:500;--g-text-subheader-font-weight:600;--g-text-display-font-weight:500;--g-text-accent-font-weight:500}.g-root_theme_light{--g-color-base-background:#fff;--g-color-base-brand:var(--g-color-private-blue-550-solid);--g-color-base-brand-hover:var(--g-color-private-blue-600-solid);--g-color-base-selection:var(--g-color-private-blue-100);--g-color-base-selection-hover:var(--g-color-private-blue-200);--g-color-line-brand:var(--g-color-private-blue-550-solid);--g-color-text-brand:var(--g-color-private-blue-600-solid);--g-color-text-brand-heavy:var(--g-color-private-blue-700-solid);--g-color-text-brand-contrast:var(--g-color-text-light-primary);--g-color-text-link:var(--g-color-private-blue-600-solid);--g-color-text-link-hover:var(--g-color-private-blue-800-solid);--g-color-private-white-50:#ffffff0d;--g-color-private-white-70:#ffffff12;--g-color-private-white-100:#ffffff1a;--g-color-private-white-150:#ffffff26;--g-color-private-white-200:#fff3;--g-color-private-white-250:#ffffff40;--g-color-private-white-300:#ffffff4d;--g-color-private-white-350:#ffffff59;--g-color-private-white-400:#fff6;--g-color-private-white-450:#ffffff73;--g-color-private-white-500:#ffffff80;--g-color-private-white-550:#ffffff8c;--g-color-private-white-600:#fff9;--g-color-private-white-650:#ffffffa6;--g-color-private-white-700:#ffffffb3;--g-color-private-white-750:#ffffffbf;--g-color-private-white-800:#fffc;--g-color-private-white-850:#ffffffd9;--g-color-private-white-900:#ffffffe6;--g-color-private-white-950:#fffffff2;--g-color-private-white-1000-solid:#fff;--g-color-private-black-50:#0000000d;--g-color-private-black-70:#00000012;--g-color-private-black-100:#0000001a;--g-color-private-black-150:#00000026;--g-color-private-black-200:#0003;--g-color-private-black-250:#00000040;--g-color-private-black-300:#0000004d;--g-color-private-black-350:#00000059;--g-color-private-black-400:#0006;--g-color-private-black-450:#00000073;--g-color-private-black-500:#00000080;--g-color-private-black-550:#0000008c;--g-color-private-black-600:#0009;--g-color-private-black-650:#000000a6;--g-color-private-black-700:#000000b3;--g-color-private-black-750:#000000bf;--g-color-private-black-800:#000c;--g-color-private-black-850:#000000d9;--g-color-private-black-900:#000000e6;--g-color-private-black-950:#000000f2;--g-color-private-black-20-solid:#fafafa;--g-color-private-black-50-solid:#f2f2f2;--g-color-private-black-100-solid:#e5e5e5;--g-color-private-black-150-solid:#d9d9d9;--g-color-private-black-200-solid:#ccc;--g-color-private-black-250-solid:#bfbfbf;--g-color-private-black-300-solid:#b3b3b3;--g-color-private-black-350-solid:#a6a6a6;--g-color-private-black-400-solid:#999;--g-color-private-black-450-solid:#8c8c8c;--g-color-private-black-500-solid:grey;--g-color-private-black-550-solid:#737373;--g-color-private-black-600-solid:#666;--g-color-private-black-650-solid:#595959;--g-color-private-black-700-solid:#4c4c4c;--g-color-private-black-750-solid:#404040;--g-color-private-black-800-solid:#333;--g-color-private-black-850-solid:#262626;--g-color-private-black-900-solid:#1a1a1a;--g-color-private-black-950-solid:#0d0d0d;--g-color-private-black-1000-solid:#000;--g-color-private-blue-50:#5282ff1a;--g-color-private-blue-100:#5282ff26;--g-color-private-blue-150:#5282ff33;--g-color-private-blue-200:#5282ff4d;--g-color-private-blue-250:#5282ff66;--g-color-private-blue-300:#5282ff80;--g-color-private-blue-350:#5282ff99;--g-color-private-blue-400:#5282ffb3;--g-color-private-blue-450:#5282ffcc;--g-color-private-blue-500:#5282ffe6;--g-color-private-blue-50-solid:#eef3ff;--g-color-private-blue-100-solid:#e5ecff;--g-color-private-blue-150-solid:#dce6ff;--g-color-private-blue-200-solid:#cbdaff;--g-color-private-blue-250-solid:#bacdff;--g-color-private-blue-300-solid:#a8c1ff;--g-color-private-blue-350-solid:#97b4ff;--g-color-private-blue-400-solid:#86a8ff;--g-color-private-blue-450-solid:#749bff;--g-color-private-blue-500-solid:#638fff;--g-color-private-blue-550-solid:#5282ff;--g-color-private-blue-600-solid:#4e79eb;--g-color-private-blue-650-solid:#4a71d6;--g-color-private-blue-700-solid:#4768c2;--g-color-private-blue-750-solid:#4360ad;--g-color-private-blue-800-solid:#3f5799;--g-color-private-blue-850-solid:#3c4f85;--g-color-private-blue-900-solid:#384670;--g-color-private-blue-950-solid:#343d5c;--g-color-private-blue-1000-solid:#333952;--g-color-private-green-50:#3bc9351a;--g-color-private-green-100:#3bc93526;--g-color-private-green-150:#3bc93533;--g-color-private-green-200:#3bc9354d;--g-color-private-green-250:#3bc93566;--g-color-private-green-300:#3bc93580;--g-color-private-green-350:#3bc93599;--g-color-private-green-400:#3bc935b3;--g-color-private-green-450:#3bc935cc;--g-color-private-green-500:#3bc935e6;--g-color-private-green-50-solid:#ebfaeb;--g-color-private-green-100-solid:#e2f7e1;--g-color-private-green-150-solid:#d8f4d7;--g-color-private-green-200-solid:#c4efc2;--g-color-private-green-250-solid:#b1e9ae;--g-color-private-green-300-solid:#9de49a;--g-color-private-green-350-solid:#89df86;--g-color-private-green-400-solid:#76d972;--g-color-private-green-450-solid:#62d45d;--g-color-private-green-500-solid:#4fce49;--g-color-private-green-550-solid:#3bc935;--g-color-private-green-600-solid:#3ab935;--g-color-private-green-650-solid:#38aa35;--g-color-private-green-700-solid:#379a34;--g-color-private-green-750-solid:#358a34;--g-color-private-green-800-solid:#347b34;--g-color-private-green-850-solid:#336b34;--g-color-private-green-900-solid:#315b34;--g-color-private-green-950-solid:#304b33;--g-color-private-green-1000-solid:#2f4433;--g-color-private-yellow-50:#ffdb4d1a;--g-color-private-yellow-100:#ffdb4d26;--g-color-private-yellow-150:#ffdb4d33;--g-color-private-yellow-200:#ffdb4d4d;--g-color-private-yellow-250:#ffdb4d66;--g-color-private-yellow-300:#ffdb4d80;--g-color-private-yellow-350:#ffdb4d99;--g-color-private-yellow-400:#ffdb4db3;--g-color-private-yellow-450:#ffdb4dcc;--g-color-private-yellow-500:#ffdb4de6;--g-color-private-yellow-50-solid:#fffbed;--g-color-private-yellow-100-solid:#fffae4;--g-color-private-yellow-150-solid:#fff8db;--g-color-private-yellow-200-solid:#fff4ca;--g-color-private-yellow-250-solid:#fff1b8;--g-color-private-yellow-300-solid:#ffeda6;--g-color-private-yellow-350-solid:#ffe994;--g-color-private-yellow-400-solid:#ffe682;--g-color-private-yellow-450-solid:#ffe271;--g-color-private-yellow-500-solid:#ffdf5f;--g-color-private-yellow-550-solid:#ffdb4d;--g-color-private-yellow-600-solid:#eac94a;--g-color-private-yellow-650-solid:#d5b848;--g-color-private-yellow-700-solid:#c0a645;--g-color-private-yellow-750-solid:#ab9543;--g-color-private-yellow-800-solid:#968340;--g-color-private-yellow-850-solid:#81723d;--g-color-private-yellow-900-solid:#6c603b;--g-color-private-yellow-950-solid:#574f38;--g-color-private-yellow-1000-solid:#4d4637;--g-color-private-orange-50:#ff77001a;--g-color-private-orange-100:#ff770026;--g-color-private-orange-150:#f703;--g-color-private-orange-200:#ff77004d;--g-color-private-orange-250:#f706;--g-color-private-orange-300:#ff770080;--g-color-private-orange-350:#f709;--g-color-private-orange-400:#ff7700b3;--g-color-private-orange-450:#f70c;--g-color-private-orange-500:#ff7700e6;--g-color-private-orange-50-solid:#fff1e6;--g-color-private-orange-100-solid:#ffebd9;--g-color-private-orange-150-solid:#ffe4cc;--g-color-private-orange-200-solid:#ffd6b3;--g-color-private-orange-250-solid:#ffc999;--g-color-private-orange-300-solid:#ffbb80;--g-color-private-orange-350-solid:#ffad66;--g-color-private-orange-400-solid:#ffa04c;--g-color-private-orange-450-solid:#ff9233;--g-color-private-orange-500-solid:#ff851a;--g-color-private-orange-550-solid:#f70;--g-color-private-orange-600-solid:#ea7005;--g-color-private-orange-650-solid:#d5680a;--g-color-private-orange-700-solid:#c0600f;--g-color-private-orange-750-solid:#ab5914;--g-color-private-orange-800-solid:#965119;--g-color-private-orange-850-solid:#814a1f;--g-color-private-orange-900-solid:#6c4324;--g-color-private-orange-950-solid:#573b29;--g-color-private-orange-1000-solid:#4d372b;--g-color-private-red-50:#ff04001a;--g-color-private-red-100:#ff040026;--g-color-private-red-150:#ff040033;--g-color-private-red-200:#ff04004d;--g-color-private-red-250:#ff040066;--g-color-private-red-300:#ff040080;--g-color-private-red-350:#ff040099;--g-color-private-red-400:#ff0400b3;--g-color-private-red-450:#ff0400cc;--g-color-private-red-500:#ff0400e6;--g-color-private-red-50-solid:#ffe6e6;--g-color-private-red-100-solid:#ffd9d9;--g-color-private-red-150-solid:#ffcdcc;--g-color-private-red-200-solid:#ffb4b3;--g-color-private-red-250-solid:#ff9b99;--g-color-private-red-300-solid:#ff8280;--g-color-private-red-350-solid:#ff6966;--g-color-private-red-400-solid:#ff504c;--g-color-private-red-450-solid:#ff3733;--g-color-private-red-500-solid:#ff1e1a;--g-color-private-red-550-solid:#ff0400;--g-color-private-red-600-solid:#ea0805;--g-color-private-red-650-solid:#d50c0a;--g-color-private-red-700-solid:#c0100f;--g-color-private-red-750-solid:#ab1414;--g-color-private-red-800-solid:#961819;--g-color-private-red-850-solid:#811c1f;--g-color-private-red-900-solid:#6c2024;--g-color-private-red-950-solid:#572429;--g-color-private-red-1000-solid:#4d262b;--g-color-private-purple-50:#8f52cc1a;--g-color-private-purple-100:#8f52cc26;--g-color-private-purple-150:#8f52cc33;--g-color-private-purple-200:#8f52cc4d;--g-color-private-purple-250:#8f52cc66;--g-color-private-purple-300:#8f52cc80;--g-color-private-purple-350:#8f52cc99;--g-color-private-purple-400:#8f52ccb3;--g-color-private-purple-450:#8f52cccc;--g-color-private-purple-500:#8f52cce6;--g-color-private-purple-50-solid:#f4eefa;--g-color-private-purple-100-solid:#eee5f7;--g-color-private-purple-150-solid:#e9dcf5;--g-color-private-purple-200-solid:#ddcbf0;--g-color-private-purple-250-solid:#d2baeb;--g-color-private-purple-300-solid:#c7a9e6;--g-color-private-purple-350-solid:#bc97e0;--g-color-private-purple-400-solid:#b186db;--g-color-private-purple-450-solid:#a575d6;--g-color-private-purple-500-solid:#9a63d1;--g-color-private-purple-550-solid:#8f52cc;--g-color-private-purple-600-solid:#854ebd;--g-color-private-purple-650-solid:#7b4aad;--g-color-private-purple-700-solid:#72479e;--g-color-private-purple-750-solid:#68438f;--g-color-private-purple-800-solid:#5e3f80;--g-color-private-purple-850-solid:#543b70;--g-color-private-purple-900-solid:#4a3761;--g-color-private-purple-950-solid:#413452;--g-color-private-purple-1000-solid:#3c324a;--g-color-private-cool-grey-50:#6b84991a;--g-color-private-cool-grey-100:#6b849926;--g-color-private-cool-grey-150:#6b849933;--g-color-private-cool-grey-200:#6b84994d;--g-color-private-cool-grey-250:#6b849966;--g-color-private-cool-grey-300:#6b849980;--g-color-private-cool-grey-350:#6b849999;--g-color-private-cool-grey-400:#6b8499b3;--g-color-private-cool-grey-450:#6b8499cc;--g-color-private-cool-grey-500:#6b8499e6;--g-color-private-cool-grey-50-solid:#f0f3f5;--g-color-private-cool-grey-100-solid:#e9edf0;--g-color-private-cool-grey-150-solid:#e1e6eb;--g-color-private-cool-grey-200-solid:#d3dae0;--g-color-private-cool-grey-250-solid:#c4ced6;--g-color-private-cool-grey-300-solid:#b5c1cc;--g-color-private-cool-grey-350-solid:#a6b5c2;--g-color-private-cool-grey-400-solid:#97a9b8;--g-color-private-cool-grey-450-solid:#899dad;--g-color-private-cool-grey-500-solid:#7a90a3;--g-color-private-cool-grey-550-solid:#6b8499;--g-color-private-cool-grey-600-solid:#657b8f;--g-color-private-cool-grey-650-solid:#5f7285;--g-color-private-cool-grey-700-solid:#586a7a;--g-color-private-cool-grey-750-solid:#526170;--g-color-private-cool-grey-800-solid:#4c5866;--g-color-private-cool-grey-850-solid:#464f5c;--g-color-private-cool-grey-900-solid:#404652;--g-color-private-cool-grey-950-solid:#393e47;--g-color-private-cool-grey-1000-solid:#363942}.g-root_theme_light-hc{--g-color-base-background:#fff;--g-color-base-brand:var(--g-color-private-blue-600-solid);--g-color-base-brand-hover:var(--g-color-private-blue-800-solid);--g-color-base-selection:var(--g-color-private-blue-250);--g-color-base-selection-hover:var(--g-color-private-blue-350);--g-color-line-brand:var(--g-color-private-blue-600-solid);--g-color-text-brand:var(--g-color-private-blue-650-solid);--g-color-text-brand-heavy:var(--g-color-private-blue-900-solid);--g-color-text-brand-contrast:var(--g-color-text-light-primary);--g-color-text-link:var(--g-color-private-blue-650-solid);--g-color-text-link-hover:var(--g-color-private-blue-850-solid);--g-color-private-white-50:#ffffff0d;--g-color-private-white-70:#ffffff12;--g-color-private-white-100:#ffffff1a;--g-color-private-white-150:#ffffff26;--g-color-private-white-200:#fff3;--g-color-private-white-250:#ffffff40;--g-color-private-white-300:#ffffff4d;--g-color-private-white-350:#ffffff59;--g-color-private-white-400:#fff6;--g-color-private-white-450:#ffffff73;--g-color-private-white-500:#ffffff80;--g-color-private-white-550:#ffffff8c;--g-color-private-white-600:#fff9;--g-color-private-white-650:#ffffffa6;--g-color-private-white-700:#ffffffb3;--g-color-private-white-750:#ffffffbf;--g-color-private-white-800:#fffc;--g-color-private-white-850:#ffffffd9;--g-color-private-white-900:#ffffffe6;--g-color-private-white-950:#fffffff2;--g-color-private-white-1000-solid:#fff;--g-color-private-black-50:#0000000d;--g-color-private-black-100:#0000001a;--g-color-private-black-150:#00000026;--g-color-private-black-200:#0003;--g-color-private-black-250:#00000040;--g-color-private-black-300:#0000004d;--g-color-private-black-350:#00000059;--g-color-private-black-400:#0006;--g-color-private-black-450:#00000073;--g-color-private-black-500:#00000080;--g-color-private-black-550:#0000008c;--g-color-private-black-600:#0009;--g-color-private-black-650:#000000a6;--g-color-private-black-700:#000000b3;--g-color-private-black-750:#000000bf;--g-color-private-black-800:#000c;--g-color-private-black-850:#000000d9;--g-color-private-black-900:#000000e6;--g-color-private-black-950:#000000f2;--g-color-private-black-50-solid:#f2f2f2;--g-color-private-black-100-solid:#e5e5e5;--g-color-private-black-150-solid:#d9d9d9;--g-color-private-black-200-solid:#ccc;--g-color-private-black-250-solid:#bfbfbf;--g-color-private-black-300-solid:#b3b3b3;--g-color-private-black-350-solid:#a6a6a6;--g-color-private-black-400-solid:#999;--g-color-private-black-450-solid:#8c8c8c;--g-color-private-black-500-solid:grey;--g-color-private-black-550-solid:#737373;--g-color-private-black-600-solid:#666;--g-color-private-black-650-solid:#595959;--g-color-private-black-700-solid:#4c4c4c;--g-color-private-black-750-solid:#404040;--g-color-private-black-800-solid:#333;--g-color-private-black-850-solid:#262626;--g-color-private-black-900-solid:#1a1a1a;--g-color-private-black-950-solid:#0d0d0d;--g-color-private-black-1000-solid:#000;--g-color-private-blue-50:#5282ff1a;--g-color-private-blue-100:#5282ff26;--g-color-private-blue-150:#5282ff33;--g-color-private-blue-200:#5282ff4d;--g-color-private-blue-250:#5282ff66;--g-color-private-blue-300:#5282ff80;--g-color-private-blue-350:#5282ff99;--g-color-private-blue-400:#5282ffb3;--g-color-private-blue-450:#5282ffcc;--g-color-private-blue-500:#5282ffe6;--g-color-private-blue-50-solid:#eef3ff;--g-color-private-blue-100-solid:#e5ecff;--g-color-private-blue-150-solid:#dce6ff;--g-color-private-blue-200-solid:#cbdaff;--g-color-private-blue-250-solid:#bacdff;--g-color-private-blue-300-solid:#a8c1ff;--g-color-private-blue-350-solid:#97b4ff;--g-color-private-blue-400-solid:#86a8ff;--g-color-private-blue-450-solid:#749bff;--g-color-private-blue-500-solid:#638fff;--g-color-private-blue-550-solid:#5282ff;--g-color-private-blue-600-solid:#4d79e9;--g-color-private-blue-650-solid:#486fd4;--g-color-private-blue-700-solid:#4366be;--g-color-private-blue-750-solid:#3f5ca8;--g-color-private-blue-800-solid:#3a5393;--g-color-private-blue-850-solid:#35497d;--g-color-private-blue-900-solid:#304067;--g-color-private-blue-950-solid:#2c3651;--g-color-private-blue-1000-solid:#293147;--g-color-private-green-50:#3bc9351a;--g-color-private-green-100:#3bc93526;--g-color-private-green-150:#3bc93533;--g-color-private-green-200:#3bc9354d;--g-color-private-green-250:#3bc93566;--g-color-private-green-300:#3bc93580;--g-color-private-green-350:#3bc93599;--g-color-private-green-400:#3bc935b3;--g-color-private-green-450:#3bc935cc;--g-color-private-green-500:#3bc935e6;--g-color-private-green-50-solid:#ebfaeb;--g-color-private-green-100-solid:#e2f7e1;--g-color-private-green-150-solid:#d8f4d7;--g-color-private-green-200-solid:#c4efc2;--g-color-private-green-250-solid:#b1e9ae;--g-color-private-green-300-solid:#9de49a;--g-color-private-green-350-solid:#89df86;--g-color-private-green-400-solid:#76d972;--g-color-private-green-450-solid:#62d45d;--g-color-private-green-500-solid:#4fce49;--g-color-private-green-550-solid:#3bc935;--g-color-private-green-600-solid:#38b833;--g-color-private-green-650-solid:#36a832;--g-color-private-green-700-solid:#339730;--g-color-private-green-750-solid:#31872f;--g-color-private-green-800-solid:#2f762e;--g-color-private-green-850-solid:#2c652c;--g-color-private-green-900-solid:#29552b;--g-color-private-green-950-solid:#274429;--g-color-private-green-1000-solid:#263c28;--g-color-private-yellow-50:#ffdb4d1a;--g-color-private-yellow-100:#ffdb4d26;--g-color-private-yellow-150:#ffdb4d33;--g-color-private-yellow-200:#ffdb4d4d;--g-color-private-yellow-250:#ffdb4d66;--g-color-private-yellow-300:#ffdb4d80;--g-color-private-yellow-350:#ffdb4d99;--g-color-private-yellow-400:#ffdb4db3;--g-color-private-yellow-450:#ffdb4dcc;--g-color-private-yellow-500:#ffdb4de6;--g-color-private-yellow-50-solid:#fffbed;--g-color-private-yellow-100-solid:#fffae4;--g-color-private-yellow-150-solid:#fff8db;--g-color-private-yellow-200-solid:#fff4ca;--g-color-private-yellow-250-solid:#fff1b8;--g-color-private-yellow-300-solid:#ffeda6;--g-color-private-yellow-350-solid:#ffe994;--g-color-private-yellow-400-solid:#ffe682;--g-color-private-yellow-450-solid:#ffe271;--g-color-private-yellow-500-solid:#ffdf5f;--g-color-private-yellow-550-solid:#ffdb4d;--g-color-private-yellow-600-solid:#e9c949;--g-color-private-yellow-650-solid:#d3b645;--g-color-private-yellow-700-solid:#bda441;--g-color-private-yellow-750-solid:#a7913d;--g-color-private-yellow-800-solid:#907f3a;--g-color-private-yellow-850-solid:#7a6d36;--g-color-private-yellow-900-solid:#645a32;--g-color-private-yellow-950-solid:#4e482e;--g-color-private-yellow-1000-solid:#433f2c;--g-color-private-orange-50:#ff77001a;--g-color-private-orange-100:#ff770026;--g-color-private-orange-150:#f703;--g-color-private-orange-200:#ff77004d;--g-color-private-orange-250:#f706;--g-color-private-orange-300:#ff770080;--g-color-private-orange-350:#f709;--g-color-private-orange-400:#ff7700b3;--g-color-private-orange-450:#f70c;--g-color-private-orange-500:#ff7700e6;--g-color-private-orange-50-solid:#fff1e6;--g-color-private-orange-100-solid:#ffebd9;--g-color-private-orange-150-solid:#ffe4cc;--g-color-private-orange-200-solid:#ffd6b3;--g-color-private-orange-250-solid:#ffc999;--g-color-private-orange-300-solid:#ffbb80;--g-color-private-orange-350-solid:#ffad66;--g-color-private-orange-400-solid:#ffa04c;--g-color-private-orange-450-solid:#ff9233;--g-color-private-orange-500-solid:#ff851a;--g-color-private-orange-550-solid:#f70;--g-color-private-orange-600-solid:#e96f04;--g-color-private-orange-650-solid:#d36608;--g-color-private-orange-700-solid:#bd5e0b;--g-color-private-orange-750-solid:#a7550f;--g-color-private-orange-800-solid:#904d13;--g-color-private-orange-850-solid:#7a4517;--g-color-private-orange-900-solid:#643c1b;--g-color-private-orange-950-solid:#4e341e;--g-color-private-orange-1000-solid:#433020;--g-color-private-red-50:#ff04001a;--g-color-private-red-100:#ff040026;--g-color-private-red-150:#ff040033;--g-color-private-red-200:#ff04004d;--g-color-private-red-250:#ff040066;--g-color-private-red-300:#ff040080;--g-color-private-red-350:#ff040099;--g-color-private-red-400:#ff0400b3;--g-color-private-red-450:#ff0400cc;--g-color-private-red-500:#ff0400e6;--g-color-private-red-50-solid:#ffe6e6;--g-color-private-red-100-solid:#ffd9d9;--g-color-private-red-150-solid:#ffcdcc;--g-color-private-red-200-solid:#ffb4b3;--g-color-private-red-250-solid:#ff9b99;--g-color-private-red-300-solid:#ff8280;--g-color-private-red-350-solid:#ff6966;--g-color-private-red-400-solid:#ff504c;--g-color-private-red-450-solid:#ff3733;--g-color-private-red-500-solid:#ff1e1a;--g-color-private-red-550-solid:#ff0400;--g-color-private-red-600-solid:#e90804;--g-color-private-red-650-solid:#d30b08;--g-color-private-red-700-solid:#bd0e0b;--g-color-private-red-750-solid:#a6110f;--g-color-private-red-800-solid:#901413;--g-color-private-red-850-solid:#7a1717;--g-color-private-red-900-solid:#641a1b;--g-color-private-red-950-solid:#4e1d1e;--g-color-private-red-1000-solid:#431e20;--g-color-private-purple-50:#8f52cc1a;--g-color-private-purple-100:#8f52cc26;--g-color-private-purple-150:#8f52cc33;--g-color-private-purple-200:#8f52cc4d;--g-color-private-purple-250:#8f52cc66;--g-color-private-purple-300:#8f52cc80;--g-color-private-purple-350:#8f52cc99;--g-color-private-purple-400:#8f52ccb3;--g-color-private-purple-450:#8f52cccc;--g-color-private-purple-500:#8f52cce6;--g-color-private-purple-50-solid:#f4eefa;--g-color-private-purple-100-solid:#eee5f7;--g-color-private-purple-150-solid:#e9dcf5;--g-color-private-purple-200-solid:#ddcbf0;--g-color-private-purple-250-solid:#d2baeb;--g-color-private-purple-300-solid:#c7a9e6;--g-color-private-purple-350-solid:#bc97e0;--g-color-private-purple-400-solid:#b186db;--g-color-private-purple-450-solid:#a575d6;--g-color-private-purple-500-solid:#9a63d1;--g-color-private-purple-550-solid:#8f52cc;--g-color-private-purple-600-solid:#844dbb;--g-color-private-purple-650-solid:#7949ab;--g-color-private-purple-700-solid:#6e449a;--g-color-private-purple-750-solid:#633f8a;--g-color-private-purple-800-solid:#593b79;--g-color-private-purple-850-solid:#4e3668;--g-color-private-purple-900-solid:#433158;--g-color-private-purple-950-solid:#382c47;--g-color-private-purple-1000-solid:#322a3f;--g-color-private-cool-grey-50:#6b84991a;--g-color-private-cool-grey-100:#6b849926;--g-color-private-cool-grey-150:#6b849933;--g-color-private-cool-grey-200:#6b84994d;--g-color-private-cool-grey-250:#6b849966;--g-color-private-cool-grey-300:#6b849980;--g-color-private-cool-grey-350:#6b849999;--g-color-private-cool-grey-400:#6b8499b3;--g-color-private-cool-grey-450:#6b8499cc;--g-color-private-cool-grey-500:#6b8499e6;--g-color-private-cool-grey-50-solid:#f0f3f5;--g-color-private-cool-grey-100-solid:#e9edf0;--g-color-private-cool-grey-150-solid:#e1e6eb;--g-color-private-cool-grey-200-solid:#d3dae0;--g-color-private-cool-grey-250-solid:#c4ced6;--g-color-private-cool-grey-300-solid:#b5c1cc;--g-color-private-cool-grey-350-solid:#a6b5c2;--g-color-private-cool-grey-400-solid:#97a9b8;--g-color-private-cool-grey-450-solid:#899dad;--g-color-private-cool-grey-500-solid:#7a90a3;--g-color-private-cool-grey-550-solid:#6b8499;--g-color-private-cool-grey-600-solid:#647a8e;--g-color-private-cool-grey-650-solid:#5c7182;--g-color-private-cool-grey-700-solid:#556776;--g-color-private-cool-grey-750-solid:#4e5d6b;--g-color-private-cool-grey-800-solid:#465360;--g-color-private-cool-grey-850-solid:#3f4a54;--g-color-private-cool-grey-900-solid:#384049;--g-color-private-cool-grey-950-solid:#31363d;--g-color-private-cool-grey-1000-solid:#2d3237}.g-root_theme_dark{--g-color-base-background:#2d2c33;--g-color-base-brand:var(--g-color-private-blue-450-solid);--g-color-base-brand-hover:var(--g-color-private-blue-600-solid);--g-color-base-selection:var(--g-color-private-blue-150);--g-color-base-selection-hover:var(--g-color-private-blue-200);--g-color-line-brand:var(--g-color-private-blue-550-solid);--g-color-text-brand:var(--g-color-private-blue-550-solid);--g-color-text-brand-heavy:var(--g-color-private-blue-600-solid);--g-color-text-brand-contrast:var(--g-color-text-light-primary);--g-color-text-link:var(--g-color-private-blue-550-solid);--g-color-text-link-hover:var(--g-color-private-blue-700-solid);--g-color-private-white-20:#ffffff05;--g-color-private-white-50:#ffffff0d;--g-color-private-white-70:#ffffff12;--g-color-private-white-100:#ffffff1a;--g-color-private-white-150:#ffffff26;--g-color-private-white-200:#fff3;--g-color-private-white-250:#ffffff40;--g-color-private-white-300:#ffffff4d;--g-color-private-white-350:#ffffff59;--g-color-private-white-400:#fff6;--g-color-private-white-450:#ffffff73;--g-color-private-white-500:#ffffff80;--g-color-private-white-550:#ffffff8c;--g-color-private-white-600:#fff9;--g-color-private-white-650:#ffffffa6;--g-color-private-white-700:#ffffffb3;--g-color-private-white-750:#ffffffbf;--g-color-private-white-800:#fffc;--g-color-private-white-850:#ffffffd9;--g-color-private-white-900:#ffffffe6;--g-color-private-white-950:#fffffff2;--g-color-private-white-20-solid:#313037;--g-color-private-white-50-solid:#38373d;--g-color-private-white-70-solid:#3c3b41;--g-color-private-white-100-solid:#424147;--g-color-private-white-150-solid:#4d4c52;--g-color-private-white-200-solid:#57565c;--g-color-private-white-250-solid:#616166;--g-color-private-white-300-solid:#6c6b70;--g-color-private-white-350-solid:#77767a;--g-color-private-white-400-solid:#818085;--g-color-private-white-450-solid:#8b8b8f;--g-color-private-white-500-solid:#969699;--g-color-private-white-550-solid:#a0a0a3;--g-color-private-white-600-solid:#ababad;--g-color-private-white-650-solid:#b6b5b8;--g-color-private-white-700-solid:#c0c0c2;--g-color-private-white-750-solid:#cacacc;--g-color-private-white-800-solid:#d5d5d6;--g-color-private-white-850-solid:#dfdfe0;--g-color-private-white-900-solid:#eaeaeb;--g-color-private-white-950-solid:#f5f5f5;--g-color-private-white-1000-solid:#fff;--g-color-private-white-opaque-150:#4c4b51f2;--g-color-private-black-20:#00000005;--g-color-private-black-50:#0000000d;--g-color-private-black-100:#0000001a;--g-color-private-black-150:#00000026;--g-color-private-black-200:#0003;--g-color-private-black-250:#00000040;--g-color-private-black-300:#0000004d;--g-color-private-black-350:#00000059;--g-color-private-black-400:#0006;--g-color-private-black-450:#00000073;--g-color-private-black-500:#00000080;--g-color-private-black-550:#0000008c;--g-color-private-black-600:#0009;--g-color-private-black-650:#000000a6;--g-color-private-black-700:#000000b3;--g-color-private-black-750:#000000bf;--g-color-private-black-800:#000c;--g-color-private-black-850:#000000d9;--g-color-private-black-900:#000000e6;--g-color-private-black-950:#000000f2;--g-color-private-black-1000-solid:#000;--g-color-private-black-rock-850:#2d2c33;--g-color-private-blue-50:#5282ff1a;--g-color-private-blue-100:#5282ff26;--g-color-private-blue-150:#5282ff33;--g-color-private-blue-200:#5282ff4d;--g-color-private-blue-250:#5282ff66;--g-color-private-blue-300:#5282ff80;--g-color-private-blue-350:#5282ff99;--g-color-private-blue-400:#5282ffb3;--g-color-private-blue-450:#5282ffcc;--g-color-private-blue-500:#5282ffe6;--g-color-private-blue-50-solid:#313547;--g-color-private-blue-100-solid:#333952;--g-color-private-blue-150-solid:#343d5c;--g-color-private-blue-200-solid:#384670;--g-color-private-blue-250-solid:#3c4e85;--g-color-private-blue-300-solid:#405799;--g-color-private-blue-350-solid:#4360ad;--g-color-private-blue-400-solid:#4768c2;--g-color-private-blue-450-solid:#4b71d6;--g-color-private-blue-500-solid:#4e79eb;--g-color-private-blue-550-solid:#5282ff;--g-color-private-blue-600-solid:#638fff;--g-color-private-blue-650-solid:#759bff;--g-color-private-blue-700-solid:#86a8ff;--g-color-private-blue-750-solid:#97b4ff;--g-color-private-blue-800-solid:#a9c1ff;--g-color-private-blue-850-solid:#bacdff;--g-color-private-blue-900-solid:#cbdaff;--g-color-private-blue-950-solid:#dce6ff;--g-color-private-blue-1000-solid:#e5ecff;--g-color-private-green-50:#5bb5571a;--g-color-private-green-100:#5bb55726;--g-color-private-green-150:#5bb55733;--g-color-private-green-200:#5bb5574d;--g-color-private-green-250:#5bb55766;--g-color-private-green-300:#5bb55780;--g-color-private-green-350:#5bb55799;--g-color-private-green-400:#5bb557b3;--g-color-private-green-450:#5bb557cc;--g-color-private-green-500:#5bb557e6;--g-color-private-green-50-solid:#323a37;--g-color-private-green-100-solid:#344138;--g-color-private-green-150-solid:#36473a;--g-color-private-green-200-solid:#3b553e;--g-color-private-green-250-solid:#3f6341;--g-color-private-green-300-solid:#447145;--g-color-private-green-350-solid:#497e49;--g-color-private-green-400-solid:#4d8c4c;--g-color-private-green-450-solid:#529a50;--g-color-private-green-500-solid:#56a753;--g-color-private-green-550-solid:#5bb557;--g-color-private-green-600-solid:#6bbc68;--g-color-private-green-650-solid:#7cc479;--g-color-private-green-700-solid:#8ccb89;--g-color-private-green-750-solid:#9dd39a;--g-color-private-green-800-solid:#addaab;--g-color-private-green-850-solid:#bde1bc;--g-color-private-green-900-solid:#cee9cd;--g-color-private-green-950-solid:#def0dd;--g-color-private-green-1000-solid:#e6f4e6;--g-color-private-yellow-50:#ffcb001a;--g-color-private-yellow-100:#ffcb0026;--g-color-private-yellow-150:#ffcb0033;--g-color-private-yellow-200:#ffcb004d;--g-color-private-yellow-250:#ffcb0066;--g-color-private-yellow-300:#ffcb0080;--g-color-private-yellow-350:#ffcb0099;--g-color-private-yellow-400:#ffcb00b3;--g-color-private-yellow-450:#ffcb00cc;--g-color-private-yellow-500:#ffcb00e6;--g-color-private-yellow-50-solid:#423c2e;--g-color-private-yellow-100-solid:#4d442b;--g-color-private-yellow-150-solid:#574c29;--g-color-private-yellow-200-solid:#6c5c24;--g-color-private-yellow-250-solid:#816c1f;--g-color-private-yellow-300-solid:#967c19;--g-color-private-yellow-350-solid:#ab8c14;--g-color-private-yellow-400-solid:#c09b0f;--g-color-private-yellow-450-solid:#d5ab0a;--g-color-private-yellow-500-solid:#e9ba04;--g-color-private-yellow-550-solid:#ffcb00;--g-color-private-yellow-600-solid:#ffd01a;--g-color-private-yellow-650-solid:#ffd533;--g-color-private-yellow-700-solid:#ffdb4c;--g-color-private-yellow-750-solid:#ffe066;--g-color-private-yellow-800-solid:#ffe580;--g-color-private-yellow-850-solid:#ffea99;--g-color-private-yellow-900-solid:#ffefb3;--g-color-private-yellow-950-solid:#fff5cc;--g-color-private-yellow-1000-solid:#fff7d9;--g-color-private-orange-50:#c8630c1a;--g-color-private-orange-100:#c8630c26;--g-color-private-orange-150:#c8630c33;--g-color-private-orange-200:#c8630c4d;--g-color-private-orange-250:#c8630c66;--g-color-private-orange-300:#c8630c80;--g-color-private-orange-350:#c8630c99;--g-color-private-orange-400:#c8630cb3;--g-color-private-orange-450:#c8630ccc;--g-color-private-orange-500:#c8630ce6;--g-color-private-orange-50-solid:#3d322f;--g-color-private-orange-100-solid:#44342d;--g-color-private-orange-150-solid:#4c372b;--g-color-private-orange-200-solid:#5c3d27;--g-color-private-orange-250-solid:#6b4223;--g-color-private-orange-300-solid:#7b4720;--g-color-private-orange-350-solid:#8a4d1c;--g-color-private-orange-400-solid:#995218;--g-color-private-orange-450-solid:#a95814;--g-color-private-orange-500-solid:#b95e10;--g-color-private-orange-550-solid:#c8630c;--g-color-private-orange-600-solid:#ce7324;--g-color-private-orange-650-solid:#d3823d;--g-color-private-orange-700-solid:#d89255;--g-color-private-orange-750-solid:#dea16d;--g-color-private-orange-800-solid:#e3b185;--g-color-private-orange-850-solid:#e9c19e;--g-color-private-orange-900-solid:#efd0b6;--g-color-private-orange-950-solid:#f4e0ce;--g-color-private-orange-1000-solid:#f7e8db;--g-color-private-red-50:#e849451a;--g-color-private-red-100:#e8494526;--g-color-private-red-150:#e8494533;--g-color-private-red-200:#e849454d;--g-color-private-red-250:#e8494566;--g-color-private-red-300:#e8494580;--g-color-private-red-350:#e8494599;--g-color-private-red-400:#e84945b3;--g-color-private-red-450:#e84945cc;--g-color-private-red-500:#e84945e6;--g-color-private-red-50-solid:#402f35;--g-color-private-red-100-solid:#493036;--g-color-private-red-150-solid:#523237;--g-color-private-red-200-solid:#653539;--g-color-private-red-250-solid:#78383a;--g-color-private-red-300-solid:#8a3a3c;--g-color-private-red-350-solid:#9d3d3e;--g-color-private-red-400-solid:#b04040;--g-color-private-red-450-solid:#c34341;--g-color-private-red-500-solid:#d54644;--g-color-private-red-550-solid:#e84945;--g-color-private-red-600-solid:#ea5b58;--g-color-private-red-650-solid:#ec6d6b;--g-color-private-red-700-solid:#ef7f7d;--g-color-private-red-750-solid:#f19290;--g-color-private-red-800-solid:#f3a4a2;--g-color-private-red-850-solid:#f6b6b5;--g-color-private-red-900-solid:#f8c8c7;--g-color-private-red-950-solid:#fadbda;--g-color-private-red-1000-solid:#fce4e3;--g-color-private-purple-50:#8f52cc1a;--g-color-private-purple-100:#8f52cc26;--g-color-private-purple-150:#8f52cc33;--g-color-private-purple-200:#8f52cc4d;--g-color-private-purple-250:#8f52cc66;--g-color-private-purple-300:#8f52cc80;--g-color-private-purple-350:#8f52cc99;--g-color-private-purple-400:#8f52ccb3;--g-color-private-purple-450:#8f52cccc;--g-color-private-purple-500:#8f52cce6;--g-color-private-purple-50-solid:#373042;--g-color-private-purple-100-solid:#3c324a;--g-color-private-purple-150-solid:#413452;--g-color-private-purple-200-solid:#4a3761;--g-color-private-purple-250-solid:#543b70;--g-color-private-purple-300-solid:#5e3f80;--g-color-private-purple-350-solid:#68438f;--g-color-private-purple-400-solid:#72479e;--g-color-private-purple-450-solid:#7b4aad;--g-color-private-purple-500-solid:#854ebd;--g-color-private-purple-550-solid:#8f52cc;--g-color-private-purple-600-solid:#9a63d1;--g-color-private-purple-650-solid:#a575d6;--g-color-private-purple-700-solid:#b186db;--g-color-private-purple-750-solid:#bc97e0;--g-color-private-purple-800-solid:#c7a9e6;--g-color-private-purple-850-solid:#d2baeb;--g-color-private-purple-900-solid:#ddcbf0;--g-color-private-purple-950-solid:#e9dcf5;--g-color-private-purple-1000-solid:#eee5f7;--g-color-private-cool-grey-50:#60809c1a;--g-color-private-cool-grey-100:#60809c26;--g-color-private-cool-grey-150:#60809c33;--g-color-private-cool-grey-200:#60809c4d;--g-color-private-cool-grey-250:#60809c66;--g-color-private-cool-grey-300:#60809c80;--g-color-private-cool-grey-350:#60809c99;--g-color-private-cool-grey-400:#60809cb3;--g-color-private-cool-grey-450:#60809ccc;--g-color-private-cool-grey-500:#60809ce6;--g-color-private-cool-grey-50-solid:#32343e;--g-color-private-cool-grey-100-solid:#353943;--g-color-private-cool-grey-150-solid:#373d48;--g-color-private-cool-grey-200-solid:#3c4552;--g-color-private-cool-grey-250-solid:#414e5d;--g-color-private-cool-grey-300-solid:#465667;--g-color-private-cool-grey-350-solid:#4c5e72;--g-color-private-cool-grey-400-solid:#51677d;--g-color-private-cool-grey-450-solid:#566f87;--g-color-private-cool-grey-500-solid:#5b7892;--g-color-private-cool-grey-550-solid:#60809c;--g-color-private-cool-grey-600-solid:#708da6;--g-color-private-cool-grey-650-solid:#8099b0;--g-color-private-cool-grey-700-solid:#90a6ba;--g-color-private-cool-grey-750-solid:#a0b3c3;--g-color-private-cool-grey-800-solid:#b0bfcd;--g-color-private-cool-grey-850-solid:#bfccd7;--g-color-private-cool-grey-900-solid:#cfd9e1;--g-color-private-cool-grey-950-solid:#dfe6eb;--g-color-private-cool-grey-1000-solid:#e7ecf0}.g-root_theme_dark-hc{--g-color-base-background:#222326;--g-color-base-brand:var(--g-color-private-blue-450-solid);--g-color-base-brand-hover:var(--g-color-private-blue-650-solid);--g-color-base-selection:var(--g-color-private-blue-250);--g-color-base-selection-hover:var(--g-color-private-blue-400);--g-color-line-brand:var(--g-color-private-blue-550-solid);--g-color-text-brand:var(--g-color-private-blue-650-solid);--g-color-text-brand-heavy:var(--g-color-private-blue-850-solid);--g-color-text-brand-contrast:var(--g-color-text-light-primary);--g-color-text-link:var(--g-color-private-blue-650-solid);--g-color-text-link-hover:var(--g-color-private-blue-800-solid);--g-color-private-white-50:#ffffff0d;--g-color-private-white-70:#ffffff12;--g-color-private-white-100:#ffffff1a;--g-color-private-white-150:#ffffff26;--g-color-private-white-200:#fff3;--g-color-private-white-250:#ffffff40;--g-color-private-white-300:#ffffff4d;--g-color-private-white-350:#ffffff59;--g-color-private-white-400:#fff6;--g-color-private-white-450:#ffffff73;--g-color-private-white-500:#ffffff80;--g-color-private-white-550:#ffffff8c;--g-color-private-white-600:#fff9;--g-color-private-white-650:#ffffffa6;--g-color-private-white-700:#ffffffb3;--g-color-private-white-750:#ffffffbf;--g-color-private-white-800:#fffc;--g-color-private-white-850:#ffffffd9;--g-color-private-white-900:#ffffffe6;--g-color-private-white-950:#fffffff2;--g-color-private-white-50-solid:#2d2e31;--g-color-private-white-100-solid:#38393c;--g-color-private-white-150-solid:#434447;--g-color-private-white-200-solid:#4e4f51;--g-color-private-white-250-solid:#595a5c;--g-color-private-white-300-solid:#646567;--g-color-private-white-350-solid:#6f7072;--g-color-private-white-400-solid:#7a7b7d;--g-color-private-white-450-solid:#858688;--g-color-private-white-500-solid:#909193;--g-color-private-white-550-solid:#9c9c9d;--g-color-private-white-600-solid:#a7a7a8;--g-color-private-white-650-solid:#b2b2b3;--g-color-private-white-700-solid:#bdbdbe;--g-color-private-white-750-solid:#c8c8c9;--g-color-private-white-800-solid:#d3d3d4;--g-color-private-white-850-solid:#dededf;--g-color-private-white-900-solid:#e9e9e9;--g-color-private-white-950-solid:#f4f4f4;--g-color-private-white-1000-solid:#fff;--g-color-private-white-opaque-150:#38393cf7;--g-color-private-black-20:#00000005;--g-color-private-black-50:#0000000d;--g-color-private-black-100:#0000001a;--g-color-private-black-150:#00000026;--g-color-private-black-200:#0003;--g-color-private-black-250:#00000040;--g-color-private-black-300:#0000004d;--g-color-private-black-350:#00000059;--g-color-private-black-400:#0006;--g-color-private-black-450:#00000073;--g-color-private-black-500:#00000080;--g-color-private-black-550:#0000008c;--g-color-private-black-600:#0009;--g-color-private-black-650:#000000a6;--g-color-private-black-700:#000000b3;--g-color-private-black-750:#000000bf;--g-color-private-black-800:#000c;--g-color-private-black-850:#000000d9;--g-color-private-black-900:#000000e6;--g-color-private-black-950:#000000f2;--g-color-private-black-1000-solid:#000;--g-color-private-black-rock-850:#2d2c33;--g-color-private-black-rock-950:#222326;--g-color-private-blue-50:#5282ff1a;--g-color-private-blue-100:#5282ff26;--g-color-private-blue-150:#5282ff33;--g-color-private-blue-200:#5282ff4d;--g-color-private-blue-250:#5282ff66;--g-color-private-blue-300:#5282ff80;--g-color-private-blue-350:#5282ff99;--g-color-private-blue-400:#5282ffb3;--g-color-private-blue-450:#5282ffcc;--g-color-private-blue-500:#5282ffe6;--g-color-private-blue-50-solid:#272d3c;--g-color-private-blue-100-solid:#293147;--g-color-private-blue-150-solid:#2c3651;--g-color-private-blue-200-solid:#304067;--g-color-private-blue-250-solid:#35497d;--g-color-private-blue-300-solid:#3a5393;--g-color-private-blue-350-solid:#3f5ca8;--g-color-private-blue-400-solid:#4466be;--g-color-private-blue-450-solid:#486fd4;--g-color-private-blue-500-solid:#4d79e9;--g-color-private-blue-550-solid:#5282ff;--g-color-private-blue-600-solid:#638fff;--g-color-private-blue-650-solid:#759bff;--g-color-private-blue-700-solid:#86a8ff;--g-color-private-blue-750-solid:#97b4ff;--g-color-private-blue-800-solid:#a9c1ff;--g-color-private-blue-850-solid:#bacdff;--g-color-private-blue-900-solid:#cbdaff;--g-color-private-blue-950-solid:#dce6ff;--g-color-private-blue-1000-solid:#e5ecff;--g-color-private-green-50:#5bb5571a;--g-color-private-green-100:#5bb55726;--g-color-private-green-150:#000;--g-color-private-green-200:#5bb5574d;--g-color-private-green-250:#5bb55766;--g-color-private-green-300:#5bb55780;--g-color-private-green-350:#5bb55799;--g-color-private-green-400:#5bb557b3;--g-color-private-green-450:#5bb557cc;--g-color-private-green-500:#5bb557e6;--g-color-private-green-50-solid:#28322b;--g-color-private-green-100-solid:#2b392d;--g-color-private-green-150-solid:#2d4030;--g-color-private-green-200-solid:#334f35;--g-color-private-green-250-solid:#395d3a;--g-color-private-green-300-solid:#3f6c3f;--g-color-private-green-350-solid:#447b43;--g-color-private-green-400-solid:#4a8948;--g-color-private-green-450-solid:#50984d;--g-color-private-green-500-solid:#55a652;--g-color-private-green-550-solid:#5bb557;--g-color-private-green-600-solid:#6bbc68;--g-color-private-green-650-solid:#7cc479;--g-color-private-green-700-solid:#8ccb89;--g-color-private-green-750-solid:#9dd39a;--g-color-private-green-800-solid:#addaab;--g-color-private-green-850-solid:#bde1bc;--g-color-private-green-900-solid:#cee9cd;--g-color-private-green-950-solid:#def0dd;--g-color-private-green-1000-solid:#e6f4e6;--g-color-private-yellow-50:#ffcb001a;--g-color-private-yellow-100:#ffcb0026;--g-color-private-yellow-150:#ffcb0033;--g-color-private-yellow-200:#ffcb004d;--g-color-private-yellow-250:#ffcb0066;--g-color-private-yellow-300:#ffcb0080;--g-color-private-yellow-350:#ffcb0099;--g-color-private-yellow-400:#ffcb00b3;--g-color-private-yellow-450:#ffcb00cc;--g-color-private-yellow-500:#ffcb00e6;--g-color-private-yellow-50-solid:#383422;--g-color-private-yellow-100-solid:#433c20;--g-color-private-yellow-150-solid:#4e451e;--g-color-private-yellow-200-solid:#64551b;--g-color-private-yellow-250-solid:#7a6617;--g-color-private-yellow-300-solid:#907713;--g-color-private-yellow-350-solid:#a7880f;--g-color-private-yellow-400-solid:#bd990b;--g-color-private-yellow-450-solid:#d3a908;--g-color-private-yellow-500-solid:#e9ba04;--g-color-private-yellow-550-solid:#ffcb00;--g-color-private-yellow-600-solid:#ffd01a;--g-color-private-yellow-650-solid:#ffd533;--g-color-private-yellow-700-solid:#ffdb4c;--g-color-private-yellow-750-solid:#ffe066;--g-color-private-yellow-800-solid:#ffe580;--g-color-private-yellow-850-solid:#ffea99;--g-color-private-yellow-900-solid:#ffefb3;--g-color-private-yellow-950-solid:#fff5cc;--g-color-private-yellow-1000-solid:#fff7d9;--g-color-private-orange-50:#c8630c1a;--g-color-private-orange-100:#c8630c26;--g-color-private-orange-150:#c8630c33;--g-color-private-orange-200:#c8630c4d;--g-color-private-orange-250:#c8630c66;--g-color-private-orange-300:#c8630c80;--g-color-private-orange-350:#c8630c99;--g-color-private-orange-400:#c8630cb3;--g-color-private-orange-450:#c8630ccc;--g-color-private-orange-500:#c8630ce6;--g-color-private-orange-50-solid:#332923;--g-color-private-orange-100-solid:#3b2d22;--g-color-private-orange-150-solid:#433021;--g-color-private-orange-200-solid:#54361e;--g-color-private-orange-250-solid:#643d1c;--g-color-private-orange-300-solid:#754319;--g-color-private-orange-350-solid:#864916;--g-color-private-orange-400-solid:#965014;--g-color-private-orange-450-solid:#a75611;--g-color-private-orange-500-solid:#b75d0f;--g-color-private-orange-550-solid:#c8630c;--g-color-private-orange-600-solid:#ce7324;--g-color-private-orange-650-solid:#d3823d;--g-color-private-orange-700-solid:#d89255;--g-color-private-orange-750-solid:#dea16d;--g-color-private-orange-800-solid:#e3b185;--g-color-private-orange-850-solid:#e9c19e;--g-color-private-orange-900-solid:#efd0b6;--g-color-private-orange-950-solid:#f4e0ce;--g-color-private-orange-1000-solid:#f7e8db;--g-color-private-red-50:#e849451a;--g-color-private-red-100:#e8494526;--g-color-private-red-150:#e8494533;--g-color-private-red-200:#e849454d;--g-color-private-red-250:#e8494566;--g-color-private-red-300:#e8494580;--g-color-private-red-350:#e8494599;--g-color-private-red-400:#e84945b3;--g-color-private-red-450:#e84945cc;--g-color-private-red-500:#e84945e6;--g-color-private-red-50-solid:#362729;--g-color-private-red-100-solid:#40292b;--g-color-private-red-150-solid:#4a2b2c;--g-color-private-red-200-solid:#5d2e2f;--g-color-private-red-250-solid:#713233;--g-color-private-red-300-solid:#853636;--g-color-private-red-350-solid:#993a39;--g-color-private-red-400-solid:#ac3d3c;--g-color-private-red-450-solid:#c0413f;--g-color-private-red-500-solid:#d44542;--g-color-private-red-550-solid:#e84945;--g-color-private-red-600-solid:#ea5b58;--g-color-private-red-650-solid:#ec6d6b;--g-color-private-red-700-solid:#ef7f7d;--g-color-private-red-750-solid:#f19290;--g-color-private-red-800-solid:#f3a4a2;--g-color-private-red-850-solid:#f6b6b5;--g-color-private-red-900-solid:#f8c8c7;--g-color-private-red-950-solid:#fadbda;--g-color-private-red-1000-solid:#fce4e3;--g-color-private-purple-50:#8f52cc1a;--g-color-private-purple-100:#8f52cc26;--g-color-private-purple-150:#8f52cc33;--g-color-private-purple-200:#8f52cc4d;--g-color-private-purple-250:#8f52cc66;--g-color-private-purple-300:#8f52cc80;--g-color-private-purple-350:#8f52cc99;--g-color-private-purple-400:#8f52ccb3;--g-color-private-purple-450:#8f52cccc;--g-color-private-purple-500:#8f52cce6;--g-color-private-purple-50-solid:#2d2837;--g-color-private-purple-100-solid:#322a3f;--g-color-private-purple-150-solid:#382c47;--g-color-private-purple-200-solid:#433158;--g-color-private-purple-250-solid:#4e3668;--g-color-private-purple-300-solid:#593b79;--g-color-private-purple-350-solid:#633f8a;--g-color-private-purple-400-solid:#6e449a;--g-color-private-purple-450-solid:#7949ab;--g-color-private-purple-500-solid:#844dbb;--g-color-private-purple-550-solid:#8f52cc;--g-color-private-purple-600-solid:#9a63d1;--g-color-private-purple-650-solid:#a575d6;--g-color-private-purple-700-solid:#b186db;--g-color-private-purple-750-solid:#bc97e0;--g-color-private-purple-800-solid:#c7a9e6;--g-color-private-purple-850-solid:#d2baeb;--g-color-private-purple-900-solid:#ddcbf0;--g-color-private-purple-950-solid:#e9dcf5;--g-color-private-purple-1000-solid:#eee5f7;--g-color-private-cool-grey-50:#60809c1a;--g-color-private-cool-grey-100:#60809c26;--g-color-private-cool-grey-150:#60809c33;--g-color-private-cool-grey-200:#60809c4d;--g-color-private-cool-grey-250:#60809c66;--g-color-private-cool-grey-300:#60809c80;--g-color-private-cool-grey-350:#60809c99;--g-color-private-cool-grey-400:#60809cb3;--g-color-private-cool-grey-450:#60809ccc;--g-color-private-cool-grey-500:#60809ce6;--g-color-private-cool-grey-50-solid:#282c32;--g-color-private-cool-grey-100-solid:#2b3138;--g-color-private-cool-grey-150-solid:#2e363e;--g-color-private-cool-grey-200-solid:#353f49;--g-color-private-cool-grey-250-solid:#3b4855;--g-color-private-cool-grey-300-solid:#415161;--g-color-private-cool-grey-350-solid:#475b6d;--g-color-private-cool-grey-400-solid:#4d6479;--g-color-private-cool-grey-450-solid:#546d84;--g-color-private-cool-grey-500-solid:#5a7790;--g-color-private-cool-grey-550-solid:#60809c;--g-color-private-cool-grey-600-solid:#708da6;--g-color-private-cool-grey-650-solid:#8099b0;--g-color-private-cool-grey-700-solid:#90a6ba;--g-color-private-cool-grey-750-solid:#a0b3c3;--g-color-private-cool-grey-800-solid:#b0bfcd;--g-color-private-cool-grey-850-solid:#bfccd7;--g-color-private-cool-grey-900-solid:#cfd9e1;--g-color-private-cool-grey-950-solid:#dfe6eb;--g-color-private-cool-grey-1000-solid:#e7ecf0}.unipika{--color-unipika-default:#a9a9a9;--color-unipika-string:#594c4c;--color-unipika-key:#d36b6b;--color-unipika-null:#594c4c;--color-unipika-int:#0095ff;--color-unipika-uint:#c200ff;--color-unipika-float:#ff00b9;--color-unipika-bool:#00ba0a;--color-unipika-date:#693;--color-unipika-interval:#399;--color-unipika-escape-text:#c7254e;--color-unipika-escape-back:#ffeff3;--color-unipika-binary-back:#fcf8e3;--color-unipika-binary-after:#888;--color-unipika-uuid:#c63;--color-unipika-tag-url:#04b;--color-unipika-tag-url-hover:#c00;color:var(--color-unipika-default);overflow-wrap:break-word;white-space:pre-wrap;word-break:normal}.unipika .pg_category_e,.unipika .pg_category_i,.unipika .pg_category_s,.unipika .string,.unipika .yql_string,.unipika .yql_utf8{color:var(--color-unipika-string)}.unipika .key,.unipika .special-key{color:var(--color-unipika-key)}.unipika .special-key{font-style:italic}.unipika .null,.unipika .yql_null{color:var(--color-unipika-null)}.unipika .null{font-style:italic}.unipika .yql_null{text-transform:uppercase}.unipika .int64,.unipika .number,.unipika .pg_category_n,.unipika .yql_int16,.unipika .yql_int32,.unipika .yql_int64,.unipika .yql_int8{color:var(--color-unipika-int)}.unipika .pg_category_a,.unipika .uint64,.unipika .yql_uint16,.unipika .yql_uint32,.unipika .yql_uint64,.unipika .yql_uint8{color:var(--color-unipika-uint)}.unipika .double,.unipika .pg_category_c,.unipika .yql_decimal,.unipika .yql_double,.unipika .yql_float{color:var(--color-unipika-float)}.unipika .boolean,.unipika .pg_category_b,.unipika .yql_bool,.unipika .yql_enum{color:var(--color-unipika-bool)}.unipika .pg_category_d,.unipika .yql_date,.unipika .yql_date32,.unipika .yql_datetime,.unipika .yql_datetime64,.unipika .yql_timestamp,.unipika .yql_timestamp64,.unipika .yql_tzdate,.unipika .yql_tzdate32,.unipika .yql_tzdatetime,.unipika .yql_tzdatetime64,.unipika .yql_tztimestamp,.unipika .yql_tztimestamp64{color:var(--color-unipika-date)}.unipika .pg_category_t,.unipika .yql_interval,.unipika .yql_interval64{color:var(--color-unipika-interval)}.unipika .yql_tagged.tag_image{vertical-align:top}.unipika .escape{background-color:var(--color-unipika-escape-back);color:var(--color-unipika-escape-text)}.unipika .quote{color:var(--color-unipika-default)}.unipika .binary,.unipika .incomplete,.unipika .pg_category_v{background-color:var(--color-unipika-binary-back)}.unipika .binary:after,.unipika .incomplete:after{color:var(--color-unipika-binary-after);padding-inline-start:.8em}.unipika .incomplete:after{content:"[truncated]";white-space:nowrap}.unipika .binary:after{content:"[binary]";white-space:nowrap}.unipika .incomplete.binary:after{content:"[truncated][binary]";white-space:nowrap}.unipika .pg_category_g,.unipika .yql_uuid{color:var(--color-unipika-uuid)}.unipika .pg_category_g.binary,.unipika .pg_category_g.incomplete,.unipika .yql_uuid.binary,.unipika .yql_uuid.incomplete{background:none}.unipika .pg_category_g.binary:after,.unipika .pg_category_g.incomplete:after,.unipika .yql_uuid.binary:after,.unipika .yql_uuid.incomplete:after{content:"";display:none}.unipika .tag_url{color:var(--color-unipika-tag-url);text-decoration:none}.unipika .tag_url:hover{color:var(--color-unipika-tag-url-hover)}.unipika-wrapper_inline_yes .unipika{display:inline-block}.g-root .unipika{font-family:var(--g-font-family-monospace)}.g-root .unipika-wrapper .g-root .unipika{border:0;margin:0;padding:0}.g-root_theme_dark .unipika,.g-root_theme_dark-hc .unipika{--color-unipika-default:#707070;--color-unipika-string:#9a8e8e;--color-unipika-key:#d36b6b;--color-unipika-null:#9a8e8e;--color-unipika-int:#0095ff;--color-unipika-uint:#c200ff;--color-unipika-float:#ff00b9;--color-unipika-bool:#00ba0a;--color-unipika-date:#693;--color-unipika-interval:#399;--color-unipika-escape-text:#c7254e;--color-unipika-escape-back:#292e1f;--color-unipika-binary-back:#292e1f;--color-unipika-binary-after:#666;--color-unipika-uuid:#c63;--color-unipika-tag-url:#47b;--color-unipika-tag-url-hover:#6af}.g-root_theme_light,.g-root_theme_light-hc{--gil-color-object-base:var(--g-color-private-yellow-550-solid);--gil-color-object-accent-heavy:var(--g-color-private-orange-650-solid);--gil-color-object-hightlight:var(--g-color-private-yellow-350-solid);--gil-color-shadow-over-object:var(--g-color-private-yellow-650-solid);--gil-color-background-lines:var(--g-color-private-black-450-solid);--gil-color-background-shapes:var(--g-color-private-black-50-solid);--gil-color-object-accent-light:var(--g-color-private-white-1000-solid);--gil-color-object-danger:var(--g-color-private-red-550-solid)}.g-root_theme_dark,.g-root_theme_dark-hc{--gil-color-object-base:var(--g-color-private-yellow-550-solid);--gil-color-object-accent-heavy:var(--g-color-private-orange-650-solid);--gil-color-object-hightlight:var(--g-color-private-yellow-700-solid);--gil-color-shadow-over-object:var(--g-color-private-yellow-500-solid);--gil-color-background-lines:var(--g-color-private-white-550-solid);--gil-color-background-shapes:var(--g-color-private-white-200-solid);--gil-color-object-accent-light:var(--g-color-private-white-1000-solid);--gil-color-object-danger:var(--g-color-private-red-550-solid)}.g-root_theme_dark,.g-root_theme_dark-hc,.g-root_theme_light,.g-root_theme_light-hc{--gil-color-object-base:var(--g-color-private-blue-450-solid);--gil-color-object-accent-heavy:var(--g-color-private-blue-850-solid);--gil-color-object-hightlight:var(--g-color-private-blue-350-solid);--gil-color-shadow-over-object:var(--g-color-private-blue-650-solid)}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/css/main.9b3791f5.css b/ydb/core/viewer/monitoring/static/css/main.9b3791f5.css new file mode 100644 index 000000000000..8781765c1b2b --- /dev/null +++ b/ydb/core/viewer/monitoring/static/css/main.9b3791f5.css @@ -0,0 +1,9 @@ +@charset "UTF-8";@import url(https://fonts.googleapis.com/css2?family=Rubik&display=swap);:root{--data-table-header-vertical-padding:5px;--data-table-cell-vertical-padding:5px;--data-table-cell-horizontal-padding:10px;--data-table-cell-border-padding:var(--data-table-cell-horizontal-padding);--data-table-cell-align:top;--data-table-head-align:top;--data-table-row-height:30px;--data-table-sort-icon-space:18px;--data-table-sort-icon-opacity-inactive:0.15;--data-table-sort-icon-color:inherit}.data-table{box-sizing:border-box;position:relative}.data-table__box{box-sizing:border-box;height:100%;width:100%}.data-table__box_sticky-head_moving{overflow:visible;position:relative;z-index:0}.data-table__box_sticky-head_moving .data-table__th{border-bottom:0;border-top:0;padding-bottom:0;padding-top:0}.data-table__box_sticky-head_moving .data-table__head-cell{display:block;height:0;overflow:hidden}.data-table__box_sticky-head_moving .data-table__row_header-data{visibility:hidden}.data-table__box_sticky-footer_fixed,.data-table__box_sticky-head_fixed{overflow:auto}.data-table__table{border-collapse:collapse;table-layout:fixed}.data-table__table_sticky{background:var(--data-table-color-base);width:100%}.data-table__row{height:var(--data-table-row-height)}.data-table__th{border:1px solid var(--data-table-border-color);box-sizing:border-box;cursor:default;font-weight:500;padding:var(--data-table-header-vertical-padding) var(--data-table-cell-horizontal-padding);position:relative;text-align:left;vertical-align:var(--data-table-head-align)}.data-table__th_sortable{cursor:pointer}.data-table__th_sortable .data-table__head-cell{padding-right:var(--data-table-sort-icon-space)}.data-table__th_sortable.data-table__th_align_right .data-table__head-cell{padding-left:var(--data-table-sort-icon-space);padding-right:0}.data-table__th_sortable.data-table__th_align_right .data-table__sort-icon{left:0;right:auto;transform:translateY(-50%) scaleX(-1)}.data-table__td{border:1px solid var(--data-table-border-color);box-sizing:border-box;overflow:hidden;padding:var(--data-table-cell-vertical-padding) var(--data-table-cell-horizontal-padding);text-overflow:ellipsis;vertical-align:var(--data-table-cell-align);white-space:nowrap}.data-table__td_index,.data-table__th_index{text-align:right}.data-table__td_align_left,.data-table__th_align_left{text-align:left}.data-table__td_align_center,.data-table__th_align_center{text-align:center}.data-table__td_align_right,.data-table__th_align_right{text-align:right}.data-table__td:first-child,.data-table__th:first-child{padding-left:var(--data-table-cell-border-padding)}.data-table__td:last-child,.data-table__th:last-child{padding-right:var(--data-table-cell-border-padding)}.data-table__index{text-align:right}.data-table__head-cell{box-sizing:border-box;display:inline-block;max-width:100%;overflow:hidden;position:relative;text-overflow:ellipsis;vertical-align:top;white-space:nowrap}.data-table__error{padding:20px;white-space:pre-wrap}.data-table__sort-icon{color:var(--data-table-sort-icon-color);display:inline-flex;position:absolute;right:0;top:50%;transform:translateY(-50%)}.data-table__sort-icon:after{content:attr(data-index);font-size:8px;left:100%;position:absolute;top:-5px}.data-table__sort-icon_shadow{opacity:var(--data-table-sort-icon-opacity-inactive)}.data-table__sort-icon_shadow:after{content:none}.data-table__icon{vertical-align:top}.data-table__no-data{background:var(--data-table-color-stripe)}.data-table__sticky_fixed{left:0;overflow:hidden;position:absolute;right:0;z-index:1}.data-table__sticky_fixed.data-table__sticky_head{top:0}.data-table__sticky_fixed.data-table__sticky_footer{bottom:0}.data-table__sticky_moving{margin-bottom:-1px;position:sticky;z-index:1}.data-table_striped-rows .data-table__row_odd{background:var(--data-table-color-stripe)}.data-table_highlight-rows .data-table__row:hover{background:var(--data-table-color-hover-area)}.data-table_header_multiline .data-table__head-cell{white-space:normal}.data-table_header_pre .data-table__head-cell{white-space:pre}.data-table__foot{background:var(--data-table-color-footer-area)}.data-table__foot_has-sticky-footer_moving{visibility:hidden}.data-table_theme_yandex-cloud{--data-table-color-base:var(--g-color-base-background,var(--yc-color-base-background));--data-table-color-stripe:var( --g-color-base-generic-ultralight,var(--yc-color-base-generic-ultralight) );--data-table-border-color:var( --g-color-base-generic-hover,var(--yc-color-base-generic-hover) );--data-table-color-hover-area:var( --g-color-base-simple-hover,var(--yc-color-base-simple-hover) );--data-table-color-footer-area:var(--data-table-color-base)}.data-table_theme_legacy{--data-table-color-base:#fff;--data-table-color-stripe:#00000008;--data-table-border-color:#ddd;--data-table-color-hover-area:#ffeba0;--data-table-color-footer-area:var(--data-table-color-base)}.data-table__resize-handler{background-color:var(--g-color-base-generic);cursor:col-resize;height:100%;position:absolute;right:0;top:0;visibility:hidden;width:6px}.data-table__resize-handler_resizing,.data-table__th:hover>.data-table__resize-handler{visibility:visible}.ydb-error-boundary{--g-definition-list-item-gap:var(--g-spacing-1);padding:var(--g-spacing-8)}.ydb-error-boundary__error-stack-wrapper{background-color:var(--code-background-color);border-radius:var(--g-border-radius-xs);height:430px;overflow:auto;scrollbar-color:var(--g-color-scroll-handle) #0000;width:800px}.ydb-error-boundary__error-stack-title{border-bottom:1px solid var(--g-color-line-generic);left:0;padding:var(--g-spacing-2) var(--g-spacing-3);position:sticky}.ydb-error-boundary__error-stack-code{padding:var(--g-spacing-3) var(--g-spacing-3) var(--g-spacing-2);white-space:pre-wrap}.ydb-error-boundary__qr-help-text{text-align:right}.g-s__m_0{margin:var(--g-spacing-0)}.g-s__mr_0{margin-inline-end:var(--g-spacing-0)}.g-s__ml_0{margin-inline-start:var(--g-spacing-0)}.g-s__mt_0{margin-block-start:var(--g-spacing-0)}.g-s__mb_0{margin-block-end:var(--g-spacing-0)}.g-s__mx_0{margin-inline:var(--g-spacing-0)}.g-s__my_0{margin-block:var(--g-spacing-0)}.g-s__p_0{padding:var(--g-spacing-0)}.g-s__pl_0{padding-inline-start:var(--g-spacing-0)}.g-s__pr_0{padding-inline-end:var(--g-spacing-0)}.g-s__pb_0{padding-block-end:var(--g-spacing-0)}.g-s__pt_0{padding-block-start:var(--g-spacing-0)}.g-s__py_0{padding-block:var(--g-spacing-0)}.g-s__px_0{padding-inline:var(--g-spacing-0)}.g-s__m_half{margin:var(--g-spacing-half)}.g-s__mr_half{margin-inline-end:var(--g-spacing-half)}.g-s__ml_half{margin-inline-start:var(--g-spacing-half)}.g-s__mt_half{margin-block-start:var(--g-spacing-half)}.g-s__mb_half{margin-block-end:var(--g-spacing-half)}.g-s__mx_half{margin-inline:var(--g-spacing-half)}.g-s__my_half{margin-block:var(--g-spacing-half)}.g-s__p_half{padding:var(--g-spacing-half)}.g-s__pl_half{padding-inline-start:var(--g-spacing-half)}.g-s__pr_half{padding-inline-end:var(--g-spacing-half)}.g-s__pb_half{padding-block-end:var(--g-spacing-half)}.g-s__pt_half{padding-block-start:var(--g-spacing-half)}.g-s__py_half{padding-block:var(--g-spacing-half)}.g-s__px_half{padding-inline:var(--g-spacing-half)}.g-s__m_1{margin:var(--g-spacing-1)}.g-s__mr_1{margin-inline-end:var(--g-spacing-1)}.g-s__ml_1{margin-inline-start:var(--g-spacing-1)}.g-s__mt_1{margin-block-start:var(--g-spacing-1)}.g-s__mb_1{margin-block-end:var(--g-spacing-1)}.g-s__mx_1{margin-inline:var(--g-spacing-1)}.g-s__my_1{margin-block:var(--g-spacing-1)}.g-s__p_1{padding:var(--g-spacing-1)}.g-s__pl_1{padding-inline-start:var(--g-spacing-1)}.g-s__pr_1{padding-inline-end:var(--g-spacing-1)}.g-s__pb_1{padding-block-end:var(--g-spacing-1)}.g-s__pt_1{padding-block-start:var(--g-spacing-1)}.g-s__py_1{padding-block:var(--g-spacing-1)}.g-s__px_1{padding-inline:var(--g-spacing-1)}.g-s__m_2{margin:var(--g-spacing-2)}.g-s__mr_2{margin-inline-end:var(--g-spacing-2)}.g-s__ml_2{margin-inline-start:var(--g-spacing-2)}.g-s__mt_2{margin-block-start:var(--g-spacing-2)}.g-s__mb_2{margin-block-end:var(--g-spacing-2)}.g-s__mx_2{margin-inline:var(--g-spacing-2)}.g-s__my_2{margin-block:var(--g-spacing-2)}.g-s__p_2{padding:var(--g-spacing-2)}.g-s__pl_2{padding-inline-start:var(--g-spacing-2)}.g-s__pr_2{padding-inline-end:var(--g-spacing-2)}.g-s__pb_2{padding-block-end:var(--g-spacing-2)}.g-s__pt_2{padding-block-start:var(--g-spacing-2)}.g-s__py_2{padding-block:var(--g-spacing-2)}.g-s__px_2{padding-inline:var(--g-spacing-2)}.g-s__m_3{margin:var(--g-spacing-3)}.g-s__mr_3{margin-inline-end:var(--g-spacing-3)}.g-s__ml_3{margin-inline-start:var(--g-spacing-3)}.g-s__mt_3{margin-block-start:var(--g-spacing-3)}.g-s__mb_3{margin-block-end:var(--g-spacing-3)}.g-s__mx_3{margin-inline:var(--g-spacing-3)}.g-s__my_3{margin-block:var(--g-spacing-3)}.g-s__p_3{padding:var(--g-spacing-3)}.g-s__pl_3{padding-inline-start:var(--g-spacing-3)}.g-s__pr_3{padding-inline-end:var(--g-spacing-3)}.g-s__pb_3{padding-block-end:var(--g-spacing-3)}.g-s__pt_3{padding-block-start:var(--g-spacing-3)}.g-s__py_3{padding-block:var(--g-spacing-3)}.g-s__px_3{padding-inline:var(--g-spacing-3)}.g-s__m_4{margin:var(--g-spacing-4)}.g-s__mr_4{margin-inline-end:var(--g-spacing-4)}.g-s__ml_4{margin-inline-start:var(--g-spacing-4)}.g-s__mt_4{margin-block-start:var(--g-spacing-4)}.g-s__mb_4{margin-block-end:var(--g-spacing-4)}.g-s__mx_4{margin-inline:var(--g-spacing-4)}.g-s__my_4{margin-block:var(--g-spacing-4)}.g-s__p_4{padding:var(--g-spacing-4)}.g-s__pl_4{padding-inline-start:var(--g-spacing-4)}.g-s__pr_4{padding-inline-end:var(--g-spacing-4)}.g-s__pb_4{padding-block-end:var(--g-spacing-4)}.g-s__pt_4{padding-block-start:var(--g-spacing-4)}.g-s__py_4{padding-block:var(--g-spacing-4)}.g-s__px_4{padding-inline:var(--g-spacing-4)}.g-s__m_5{margin:var(--g-spacing-5)}.g-s__mr_5{margin-inline-end:var(--g-spacing-5)}.g-s__ml_5{margin-inline-start:var(--g-spacing-5)}.g-s__mt_5{margin-block-start:var(--g-spacing-5)}.g-s__mb_5{margin-block-end:var(--g-spacing-5)}.g-s__mx_5{margin-inline:var(--g-spacing-5)}.g-s__my_5{margin-block:var(--g-spacing-5)}.g-s__p_5{padding:var(--g-spacing-5)}.g-s__pl_5{padding-inline-start:var(--g-spacing-5)}.g-s__pr_5{padding-inline-end:var(--g-spacing-5)}.g-s__pb_5{padding-block-end:var(--g-spacing-5)}.g-s__pt_5{padding-block-start:var(--g-spacing-5)}.g-s__py_5{padding-block:var(--g-spacing-5)}.g-s__px_5{padding-inline:var(--g-spacing-5)}.g-s__m_6{margin:var(--g-spacing-6)}.g-s__mr_6{margin-inline-end:var(--g-spacing-6)}.g-s__ml_6{margin-inline-start:var(--g-spacing-6)}.g-s__mt_6{margin-block-start:var(--g-spacing-6)}.g-s__mb_6{margin-block-end:var(--g-spacing-6)}.g-s__mx_6{margin-inline:var(--g-spacing-6)}.g-s__my_6{margin-block:var(--g-spacing-6)}.g-s__p_6{padding:var(--g-spacing-6)}.g-s__pl_6{padding-inline-start:var(--g-spacing-6)}.g-s__pr_6{padding-inline-end:var(--g-spacing-6)}.g-s__pb_6{padding-block-end:var(--g-spacing-6)}.g-s__pt_6{padding-block-start:var(--g-spacing-6)}.g-s__py_6{padding-block:var(--g-spacing-6)}.g-s__px_6{padding-inline:var(--g-spacing-6)}.g-s__m_7{margin:var(--g-spacing-7)}.g-s__mr_7{margin-inline-end:var(--g-spacing-7)}.g-s__ml_7{margin-inline-start:var(--g-spacing-7)}.g-s__mt_7{margin-block-start:var(--g-spacing-7)}.g-s__mb_7{margin-block-end:var(--g-spacing-7)}.g-s__mx_7{margin-inline:var(--g-spacing-7)}.g-s__my_7{margin-block:var(--g-spacing-7)}.g-s__p_7{padding:var(--g-spacing-7)}.g-s__pl_7{padding-inline-start:var(--g-spacing-7)}.g-s__pr_7{padding-inline-end:var(--g-spacing-7)}.g-s__pb_7{padding-block-end:var(--g-spacing-7)}.g-s__pt_7{padding-block-start:var(--g-spacing-7)}.g-s__py_7{padding-block:var(--g-spacing-7)}.g-s__px_7{padding-inline:var(--g-spacing-7)}.g-s__m_8{margin:var(--g-spacing-8)}.g-s__mr_8{margin-inline-end:var(--g-spacing-8)}.g-s__ml_8{margin-inline-start:var(--g-spacing-8)}.g-s__mt_8{margin-block-start:var(--g-spacing-8)}.g-s__mb_8{margin-block-end:var(--g-spacing-8)}.g-s__mx_8{margin-inline:var(--g-spacing-8)}.g-s__my_8{margin-block:var(--g-spacing-8)}.g-s__p_8{padding:var(--g-spacing-8)}.g-s__pl_8{padding-inline-start:var(--g-spacing-8)}.g-s__pr_8{padding-inline-end:var(--g-spacing-8)}.g-s__pb_8{padding-block-end:var(--g-spacing-8)}.g-s__pt_8{padding-block-start:var(--g-spacing-8)}.g-s__py_8{padding-block:var(--g-spacing-8)}.g-s__px_8{padding-inline:var(--g-spacing-8)}.g-s__m_9{margin:var(--g-spacing-9)}.g-s__mr_9{margin-inline-end:var(--g-spacing-9)}.g-s__ml_9{margin-inline-start:var(--g-spacing-9)}.g-s__mt_9{margin-block-start:var(--g-spacing-9)}.g-s__mb_9{margin-block-end:var(--g-spacing-9)}.g-s__mx_9{margin-inline:var(--g-spacing-9)}.g-s__my_9{margin-block:var(--g-spacing-9)}.g-s__p_9{padding:var(--g-spacing-9)}.g-s__pl_9{padding-inline-start:var(--g-spacing-9)}.g-s__pr_9{padding-inline-end:var(--g-spacing-9)}.g-s__pb_9{padding-block-end:var(--g-spacing-9)}.g-s__pt_9{padding-block-start:var(--g-spacing-9)}.g-s__py_9{padding-block:var(--g-spacing-9)}.g-s__px_9{padding-inline:var(--g-spacing-9)}.g-s__m_10{margin:var(--g-spacing-10)}.g-s__mr_10{margin-inline-end:var(--g-spacing-10)}.g-s__ml_10{margin-inline-start:var(--g-spacing-10)}.g-s__mt_10{margin-block-start:var(--g-spacing-10)}.g-s__mb_10{margin-block-end:var(--g-spacing-10)}.g-s__mx_10{margin-inline:var(--g-spacing-10)}.g-s__my_10{margin-block:var(--g-spacing-10)}.g-s__p_10{padding:var(--g-spacing-10)}.g-s__pl_10{padding-inline-start:var(--g-spacing-10)}.g-s__pr_10{padding-inline-end:var(--g-spacing-10)}.g-s__pb_10{padding-block-end:var(--g-spacing-10)}.g-s__pt_10{padding-block-start:var(--g-spacing-10)}.g-s__py_10{padding-block:var(--g-spacing-10)}.g-s__px_10{padding-inline:var(--g-spacing-10)}.g-box{box-sizing:border-box}.g-box_overflow_hidden{overflow:hidden}.g-box_overflow_auto{overflow:auto}.g-box_overflow_x{overflow:hidden auto}.g-box_overflow_y{overflow:auto hidden}.g-flex{display:flex}.g-flex_inline{display:inline-flex}.g-flex_center-content{align-items:center;justify-content:center}.g-flex_s_0{margin-block-start:calc(var(--g-spacing-0)*-1)!important;margin-inline-start:calc(var(--g-spacing-0)*-1)!important}.g-flex_s_0>*{padding-block-start:var(--g-spacing-0)!important;padding-inline-start:var(--g-spacing-0)!important}.g-flex_s_half{margin-block-start:calc(var(--g-spacing-half)*-1)!important;margin-inline-start:calc(var(--g-spacing-half)*-1)!important}.g-flex_s_half>*{padding-block-start:var(--g-spacing-half)!important;padding-inline-start:var(--g-spacing-half)!important}.g-flex_s_1{margin-block-start:calc(var(--g-spacing-1)*-1)!important;margin-inline-start:calc(var(--g-spacing-1)*-1)!important}.g-flex_s_1>*{padding-block-start:var(--g-spacing-1)!important;padding-inline-start:var(--g-spacing-1)!important}.g-flex_s_2{margin-block-start:calc(var(--g-spacing-2)*-1)!important;margin-inline-start:calc(var(--g-spacing-2)*-1)!important}.g-flex_s_2>*{padding-block-start:var(--g-spacing-2)!important;padding-inline-start:var(--g-spacing-2)!important}.g-flex_s_3{margin-block-start:calc(var(--g-spacing-3)*-1)!important;margin-inline-start:calc(var(--g-spacing-3)*-1)!important}.g-flex_s_3>*{padding-block-start:var(--g-spacing-3)!important;padding-inline-start:var(--g-spacing-3)!important}.g-flex_s_4{margin-block-start:calc(var(--g-spacing-4)*-1)!important;margin-inline-start:calc(var(--g-spacing-4)*-1)!important}.g-flex_s_4>*{padding-block-start:var(--g-spacing-4)!important;padding-inline-start:var(--g-spacing-4)!important}.g-flex_s_5{margin-block-start:calc(var(--g-spacing-5)*-1)!important;margin-inline-start:calc(var(--g-spacing-5)*-1)!important}.g-flex_s_5>*{padding-block-start:var(--g-spacing-5)!important;padding-inline-start:var(--g-spacing-5)!important}.g-flex_s_6{margin-block-start:calc(var(--g-spacing-6)*-1)!important;margin-inline-start:calc(var(--g-spacing-6)*-1)!important}.g-flex_s_6>*{padding-block-start:var(--g-spacing-6)!important;padding-inline-start:var(--g-spacing-6)!important}.g-flex_s_7{margin-block-start:calc(var(--g-spacing-7)*-1)!important;margin-inline-start:calc(var(--g-spacing-7)*-1)!important}.g-flex_s_7>*{padding-block-start:var(--g-spacing-7)!important;padding-inline-start:var(--g-spacing-7)!important}.g-flex_s_8{margin-block-start:calc(var(--g-spacing-8)*-1)!important;margin-inline-start:calc(var(--g-spacing-8)*-1)!important}.g-flex_s_8>*{padding-block-start:var(--g-spacing-8)!important;padding-inline-start:var(--g-spacing-8)!important}.g-flex_s_9{margin-block-start:calc(var(--g-spacing-9)*-1)!important;margin-inline-start:calc(var(--g-spacing-9)*-1)!important}.g-flex_s_9>*{padding-block-start:var(--g-spacing-9)!important;padding-inline-start:var(--g-spacing-9)!important}.g-flex_s_10{margin-block-start:calc(var(--g-spacing-10)*-1)!important;margin-inline-start:calc(var(--g-spacing-10)*-1)!important}.g-flex_s_10>*{padding-block-start:var(--g-spacing-10)!important;padding-inline-start:var(--g-spacing-10)!important}.g-color-text_color_primary{color:var(--g-color-text-primary)}.g-color-text_color_complementary{color:var(--g-color-text-complementary)}.g-color-text_color_secondary{color:var(--g-color-text-secondary)}.g-color-text_color_hint{color:var(--g-color-text-hint)}.g-color-text_color_info{color:var(--g-color-text-info)}.g-color-text_color_info-heavy{color:var(--g-color-text-info-heavy)}.g-color-text_color_positive{color:var(--g-color-text-positive)}.g-color-text_color_positive-heavy{color:var(--g-color-text-positive-heavy)}.g-color-text_color_warning{color:var(--g-color-text-warning)}.g-color-text_color_warning-heavy{color:var(--g-color-text-warning-heavy)}.g-color-text_color_danger{color:var(--g-color-text-danger)}.g-color-text_color_danger-heavy{color:var(--g-color-text-danger-heavy)}.g-color-text_color_utility{color:var(--g-color-text-utility)}.g-color-text_color_utility-heavy{color:var(--g-color-text-utility-heavy)}.g-color-text_color_misc{color:var(--g-color-text-misc)}.g-color-text_color_misc-heavy{color:var(--g-color-text-misc-heavy)}.g-color-text_color_brand{color:var(--g-color-text-brand)}.g-color-text_color_link{color:var(--g-color-text-link)}.g-color-text_color_link-hover{color:var(--g-color-text-link-hover)}.g-color-text_color_link-visited{color:var(--g-color-text-link-visited)}.g-color-text_color_link-visited-hover{color:var(--g-color-text-link-visited-hover)}.g-color-text_color_dark-primary{color:var(--g-color-text-dark-primary)}.g-color-text_color_dark-complementary{color:var(--g-color-text-dark-complementary)}.g-color-text_color_dark-secondary{color:var(--g-color-text-dark-secondary)}.g-color-text_color_light-primary{color:var(--g-color-text-light-primary)}.g-color-text_color_light-complementary{color:var(--g-color-text-light-complementary)}.g-color-text_color_light-secondary{color:var(--g-color-text-light-secondary)}.g-color-text_color_light-hint{color:var(--g-color-text-light-hint)}.g-color-text_color_inverted-primary{color:var(--g-color-text-inverted-primary)}.g-color-text_color_inverted-complementary{color:var(--g-color-text-inverted-complementary)}.g-color-text_color_inverted-secondary{color:var(--g-color-text-inverted-secondary)}.g-color-text_color_inverted-hint{color:var(--g-color-text-inverted-hint)}.g-text_variant_display-1{font-size:var(--g-text-display-1-font-size);line-height:var(--g-text-display-1-line-height)}.g-text_variant_display-1,.g-text_variant_display-2{font-family:var(--g-text-display-font-family);font-weight:var(--g-text-display-font-weight)}.g-text_variant_display-2{font-size:var(--g-text-display-2-font-size);line-height:var(--g-text-display-2-line-height)}.g-text_variant_display-3{font-size:var(--g-text-display-3-font-size);line-height:var(--g-text-display-3-line-height)}.g-text_variant_display-3,.g-text_variant_display-4{font-family:var(--g-text-display-font-family);font-weight:var(--g-text-display-font-weight)}.g-text_variant_display-4{font-size:var(--g-text-display-4-font-size);line-height:var(--g-text-display-4-line-height)}.g-text_variant_code-1{font-size:var(--g-text-code-1-font-size);line-height:var(--g-text-code-1-line-height)}.g-text_variant_code-1,.g-text_variant_code-2{font-family:var(--g-text-code-font-family);font-weight:var(--g-text-code-font-weight)}.g-text_variant_code-2{font-size:var(--g-text-code-2-font-size);line-height:var(--g-text-code-2-line-height)}.g-text_variant_code-3{font-size:var(--g-text-code-3-font-size);line-height:var(--g-text-code-3-line-height)}.g-text_variant_code-3,.g-text_variant_code-inline-1{font-family:var(--g-text-code-font-family);font-weight:var(--g-text-code-font-weight)}.g-text_variant_code-inline-1{font-size:var(--g-text-code-inline-1-font-size);line-height:var(--g-text-code-inline-1-line-height)}.g-text_variant_code-inline-2{font-size:var(--g-text-code-inline-2-font-size);line-height:var(--g-text-code-inline-2-line-height)}.g-text_variant_code-inline-2,.g-text_variant_code-inline-3{font-family:var(--g-text-code-font-family);font-weight:var(--g-text-code-font-weight)}.g-text_variant_code-inline-3{font-size:var(--g-text-code-inline-3-font-size);line-height:var(--g-text-code-inline-3-line-height)}.g-text_variant_body-1{font-size:var(--g-text-body-1-font-size);line-height:var(--g-text-body-1-line-height)}.g-text_variant_body-1,.g-text_variant_body-2{font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight)}.g-text_variant_body-2{font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height)}.g-text_variant_body-3{font-size:var(--g-text-body-3-font-size);line-height:var(--g-text-body-3-line-height)}.g-text_variant_body-3,.g-text_variant_body-short{font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight)}.g-text_variant_body-short{font-size:var(--g-text-body-short-font-size);line-height:var(--g-text-body-short-line-height)}.g-text_variant_caption-1{font-size:var(--g-text-caption-1-font-size);line-height:var(--g-text-caption-1-line-height)}.g-text_variant_caption-1,.g-text_variant_caption-2{font-family:var(--g-text-caption-font-family);font-weight:var(--g-text-caption-font-weight)}.g-text_variant_caption-2{font-size:var(--g-text-caption-2-font-size);line-height:var(--g-text-caption-2-line-height)}.g-text_variant_header-1{font-size:var(--g-text-header-1-font-size);line-height:var(--g-text-header-1-line-height)}.g-text_variant_header-1,.g-text_variant_header-2{font-family:var(--g-text-header-font-family);font-weight:var(--g-text-header-font-weight)}.g-text_variant_header-2{font-size:var(--g-text-header-2-font-size);line-height:var(--g-text-header-2-line-height)}.g-text_variant_subheader-1{font-size:var(--g-text-subheader-1-font-size);line-height:var(--g-text-subheader-1-line-height)}.g-text_variant_subheader-1,.g-text_variant_subheader-2{font-family:var(--g-text-subheader-font-family);font-weight:var(--g-text-subheader-font-weight)}.g-text_variant_subheader-2{font-size:var(--g-text-subheader-2-font-size);line-height:var(--g-text-subheader-2-line-height)}.g-text_variant_subheader-3{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height)}.g-text_ellipsis{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.g-text_ellipsis-lines{-webkit-box-orient:vertical;-webkit-line-clamp:2;align-self:center;display:-webkit-box;overflow:hidden;white-space:normal}.g-text_ws_nowrap{white-space:nowrap}.g-text_ws_break-spaces{white-space:break-spaces}.g-text_wb_break-all{word-break:break-all}.g-text_wb_break-word{word-break:break-word}.g-clipboard-button__icon{pointer-events:none}.g-icon{line-height:0;vertical-align:top}.g-button{--_--text-color:var(--g-color-text-primary);--_--text-color-hover:var(--_--text-color);--_--background-color:#0000;--_--background-color-hover:var(--g-color-base-simple-hover);--_--border-width:0;--_--border-color:currentColor;--_--focus-outline-color:var(--g-color-line-focus);--_--focus-outline-offset:0;--_--font-size:var(--g-text-body-1-font-size);-webkit-tap-highlight-color:rgba(0,0,0,0);background:none;background:#0000;border:none;box-sizing:border-box;color:inherit;color:var(--g-button-text-color,var(--_--text-color));cursor:pointer;display:inline-flex;font-family:var(--g-text-body-font-family);font-size:inherit;font-size:var(--g-button-font-size,var(--_--font-size));font-weight:var(--g-text-body-font-weight);gap:var(--g-button-icon-offset,var(--_--icon-offset));height:var(--g-button-height,var(--_--height));justify-content:center;line-height:var(--g-button-height,var(--_--height));outline:none;overflow:visible;padding:0;padding:0 var(--g-button-padding,var(--_--padding));position:relative;text-align:center;text-decoration:none;touch-action:manipulation;transform:scale(1);transition:transform .1s ease-out,color .15s linear;-webkit-user-select:none;user-select:none;white-space:nowrap}.g-button:before{background-color:var(--g-button-background-color,var(--_--background-color));border:var(--g-button-border-width,var(--_--border-width)) var(--g-button-border-style,solid) var(--g-button-border-color,var(--_--border-color));content:"";inset:0;position:absolute;transition:background-color .15s linear;z-index:-1}.g-button:hover{color:var(--g-button-text-color-hover,var(--_--text-color-hover))}.g-button:hover:before{background-color:var(--g-button-background-color-hover,var(--_--background-color-hover))}.g-button:focus-visible:before{outline:var(--g-button-focus-outline-color,var(--_--focus-outline-color)) var(--g-button-focus-outline-style,solid) var(--g-button-focus-outline-width,2px);outline-offset:var(--g-button-focus-outline-offset,var(--_--focus-outline-offset))}.g-button:after{content:"";inset:0;position:absolute;transform:scale(1);transition:none;z-index:-1}.g-button:active{transform:scale(.96);transition:none}.g-button:active:after{transform:scale(1.042)}.g-button_size_xs{--_--height:20px;--_--border-radius:var(--g-border-radius-xs);--_--padding:6px;--_--icon-size:12px;--_--icon-offset:4px}.g-button_size_s{--_--height:24px;--_--border-radius:var(--g-border-radius-s);--_--padding:8px;--_--icon-size:16px;--_--icon-offset:4px}.g-button_size_m{--_--height:28px;--_--border-radius:var(--g-border-radius-m);--_--padding:12px;--_--icon-size:16px;--_--icon-offset:8px}.g-button_size_l{--_--height:36px;--_--border-radius:var(--g-border-radius-l);--_--padding:16px;--_--icon-size:16px;--_--icon-offset:8px}.g-button_size_xl{--_--height:44px;--_--border-radius:var(--g-border-radius-xl);--_--padding:24px;--_--icon-size:20px;--_--icon-offset:12px;--_--font-size:var(--g-text-body-2-font-size)}.g-button_view_normal{--_--background-color:var(--g-color-base-generic);--_--background-color-hover:var(--g-color-base-generic-hover)}.g-button_view_action{--_--text-color:var(--g-color-text-brand-contrast);--_--background-color:var(--g-color-base-brand);--_--background-color-hover:var(--g-color-base-brand-hover);--_--focus-outline-color:var(--g-color-base-brand);--_--focus-outline-offset:1px}.g-button_view_outlined{--_--border-width:1px;--_--border-color:var(--g-color-line-generic)}.g-button_view_outlined-info{--_--text-color:var(--g-color-text-info);--_--border-width:1px;--_--border-color:var(--g-color-line-info)}.g-button_view_outlined-success{--_--text-color:var(--g-color-text-positive);--_--border-width:1px;--_--border-color:var(--g-color-line-positive)}.g-button_view_outlined-warning{--_--text-color:var(--g-color-text-warning);--_--border-width:1px;--_--border-color:var(--g-color-line-warning)}.g-button_view_outlined-danger{--_--text-color:var(--g-color-text-danger);--_--border-width:1px;--_--border-color:var(--g-color-line-danger)}.g-button_view_outlined-utility{--_--text-color:var(--g-color-text-utility);--_--border-width:1px;--_--border-color:var(--g-color-line-utility)}.g-button_view_outlined-action{--_--text-color:var(--g-color-text-brand);--_--border-width:1px;--_--border-color:var(--g-color-line-brand)}.g-button_view_raised{--_--background-color-hover:var(--g-color-base-float-hover);background:var(--g-color-base-float)}.g-button_view_raised:before{box-shadow:0 3px 5px var(--g-color-sfx-shadow)}.g-button_view_raised:active:before{box-shadow:0 1px 2px var(--g-color-sfx-shadow)}.g-button_view_flat-secondary{--_--text-color:var(--g-color-text-secondary);--_--text-color-hover:var(--g-color-text-primary)}.g-button_view_flat-info{--_--text-color:var(--g-color-text-info)}.g-button_view_flat-success{--_--text-color:var(--g-color-text-positive)}.g-button_view_flat-warning{--_--text-color:var(--g-color-text-warning)}.g-button_view_flat-danger{--_--text-color:var(--g-color-text-danger)}.g-button_view_flat-utility{--_--text-color:var(--g-color-text-utility)}.g-button_view_flat-action{--_--text-color:var(--g-color-text-brand)}.g-button_view_normal-contrast{--_--text-color:var(--g-color-text-dark-primary);--_--background-color:var(--g-color-base-light);--_--background-color-hover:var(--g-color-base-light-hover);--_--focus-outline-color:var(--g-color-line-light)}.g-button_view_normal-contrast.g-button_loading{--_--background-color-hover:var(--g-color-base-simple-hover)}.g-button_view_outlined-contrast{--_--text-color:var(--g-color-text-light-primary);--_--background-color-hover:var(--g-color-base-light-simple-hover);--_--border-width:1px;--_--border-color:var(--g-color-line-light);--_--focus-outline-color:var(--g-color-line-light)}.g-button_view_flat-contrast{--_--text-color:var(--g-color-text-light-primary);--_--background-color-hover:var(--g-color-base-light-simple-hover);--_--focus-outline-color:var(--g-color-line-light)}.g-button.g-button_pin_round-round.g-button{border-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-brick.g-button{border-radius:0}.g-button.g-button_pin_clear-clear.g-button{border-inline:0;border-radius:0}.g-button.g-button_pin_circle-circle.g-button{border-radius:100px}.g-button.g-button_pin_round-brick.g-button{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-round.g-button{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_round-clear.g-button{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-inline-end:0;border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_clear-round.g-button{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-inline-start:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_brick-clear.g-button{border-inline-end:0;border-radius:0}.g-button.g-button_pin_clear-brick.g-button{border-inline-start:0;border-radius:0}.g-button.g-button_pin_circle-brick.g-button{border-end-end-radius:0;border-end-start-radius:100px;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_brick-circle.g-button{border-end-end-radius:100px;border-end-start-radius:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_circle-clear.g-button{border-end-end-radius:0;border-end-start-radius:100px;border-inline-end:0;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_clear-circle.g-button{border-end-end-radius:100px;border-end-start-radius:0;border-inline-start:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_round-round:before{border-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-brick:before{border-radius:0}.g-button.g-button_pin_clear-clear:before{border-inline:0;border-radius:0}.g-button.g-button_pin_circle-circle:before{border-radius:100px}.g-button.g-button_pin_round-brick:before{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-round:before{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_round-clear:before{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-inline-end:0;border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_clear-round:before{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-inline-start:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_brick-clear:before{border-inline-end:0;border-radius:0}.g-button.g-button_pin_clear-brick:before{border-inline-start:0;border-radius:0}.g-button.g-button_pin_circle-brick:before{border-end-end-radius:0;border-end-start-radius:100px;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_brick-circle:before{border-end-end-radius:100px;border-end-start-radius:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_circle-clear:before{border-end-end-radius:0;border-end-start-radius:100px;border-inline-end:0;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_clear-circle:before{border-end-end-radius:100px;border-end-start-radius:0;border-inline-start:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_round-round:after{border-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-brick:after{border-radius:0}.g-button.g-button_pin_clear-clear:after{border-inline:0;border-radius:0}.g-button.g-button_pin_circle-circle:after{border-radius:100px}.g-button.g-button_pin_round-brick:after{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_brick-round:after{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_round-clear:after{border-end-end-radius:0;border-end-start-radius:var(--g-button-border-radius,var(--_--border-radius));border-inline-end:0;border-start-end-radius:0;border-start-start-radius:var(--g-button-border-radius,var(--_--border-radius))}.g-button.g-button_pin_clear-round:after{border-end-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-end-start-radius:0;border-inline-start:0;border-start-end-radius:var(--g-button-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-button.g-button_pin_brick-clear:after{border-inline-end:0;border-radius:0}.g-button.g-button_pin_clear-brick:after{border-inline-start:0;border-radius:0}.g-button.g-button_pin_circle-brick:after{border-end-end-radius:0;border-end-start-radius:100px;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_brick-circle:after{border-end-end-radius:100px;border-end-start-radius:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button.g-button_pin_circle-clear:after{border-end-end-radius:0;border-end-start-radius:100px;border-inline-end:0;border-start-end-radius:0;border-start-start-radius:100px}.g-button.g-button_pin_clear-circle:after{border-end-end-radius:100px;border-end-start-radius:0;border-inline-start:0;border-start-end-radius:100px;border-start-start-radius:0}.g-button__text{display:inline-block;white-space:nowrap}.g-button__icon{display:inline-block;height:var(--g-button-height,var(--_--height));margin:0 calc((var(--g-button-height, var(--_--height)) - var(--g-button-icon-size, var(--_--icon-size)))/2*-1);position:relative;width:var(--g-button-height,var(--_--height))}.g-button__icon:after{content:" ";visibility:hidden}.g-button__icon-inner{align-items:center;display:flex;inset:0;justify-content:center;position:absolute}.g-button__icon_side_start{order:-1}.g-button__icon_side_end{order:1}.g-button__icon:only-child{margin:0}.g-button:has(.g-button__icon:only-child){--_--padding:0}.g-button:has(.g-button__icon:only-child):not(.g-button_width_max){width:var(--g-button-height,var(--_--height))}.g-button_selected:not(.g-button_view_outlined-contrast){--_--border-width:0}.g-button_selected:not(.g-button_view_normal-contrast,.g-button_view_flat-contrast,.g-button_view_outlined-contrast){--_--text-color:var(--g-color-text-brand-heavy);--_--background-color:var(--g-color-base-selection);--_--background-color-hover:var(--g-color-base-selection-hover)}.g-button_selected.g-button_view_flat-info,.g-button_selected.g-button_view_outlined-info{--_--text-color:var(--g-color-text-info-heavy);--_--background-color:var(--g-color-base-info-light);--_--background-color-hover:var(--g-color-base-info-light-hover)}.g-button_selected.g-button_view_flat-success,.g-button_selected.g-button_view_outlined-success{--_--text-color:var(--g-color-text-positive-heavy);--_--background-color:var(--g-color-base-positive-light);--_--background-color-hover:var(--g-color-base-positive-light-hover)}.g-button_selected.g-button_view_flat-warning,.g-button_selected.g-button_view_outlined-warning{--_--text-color:var(--g-color-text-warning-heavy);--_--background-color:var(--g-color-base-warning-light);--_--background-color-hover:var(--g-color-base-warning-light-hover)}.g-button_selected.g-button_view_flat-danger,.g-button_selected.g-button_view_outlined-danger{--_--text-color:var(--g-color-text-danger-heavy);--_--background-color:var(--g-color-base-danger-light);--_--background-color-hover:var(--g-color-base-danger-light-hover)}.g-button_selected.g-button_view_flat-utility,.g-button_selected.g-button_view_outlined-utility{--_--text-color:var(--g-color-text-utility-heavy);--_--background-color:var(--g-color-base-utility-light);--_--background-color-hover:var(--g-color-base-utility-light-hover)}.g-button_disabled{cursor:default;pointer-events:none}.g-button_disabled:not(.g-button_loading){--_--text-color:var(--g-color-text-hint);--_--background-color:var(--g-color-base-generic-accent-disabled);--_--background-color-hover:var(--g-color-base-generic-accent-disabled);--_--border-width:0}.g-button_disabled:not(.g-button_loading):is(.g-button_view_normal-contrast,.g-button_view_outlined-contrast){--_--text-color:var(--g-color-text-light-secondary);--_--background-color:var(--g-color-base-light-disabled);--_--background-color-hover:var(--g-color-base-light-disabled)}.g-button_disabled:not(.g-button_loading):is(.g-button_view_flat,.g-button_view_flat-secondary,.g-button_view_flat-info,.g-button_view_flat-success,.g-button_view_flat-warning,.g-button_view_flat-danger,.g-button_view_flat-utility,.g-button_view_flat-action,.g-button_view_flat-contrast){--_--text-color:var(--g-color-text-hint);--_--background-color:#0000;--_--background-color-hover:#0000}.g-button_disabled:not(.g-button_loading).g-button_view_flat-contrast{--_--text-color:var(--g-color-text-light-hint)}.g-button_disabled:active{transform:scale(1)}.g-button_loading:before{animation:g-loading-animation .5s linear infinite;background-clip:padding-box;background-image:repeating-linear-gradient(-45deg,var(--g-button-background-color,var(--_--background-color)),var(--g-button-background-color,var(--_--background-color)) 4px,var(--g-button-background-color-hover,var(--_--background-color-hover)) 4px,var(--g-button-background-color-hover,var(--_--background-color-hover)) 8px);background-size:150%}.g-button_width_auto{max-width:100%}.g-button_width_max{width:100%}.g-button_width_auto .g-button__text,.g-button_width_max .g-button__text{display:block;overflow:hidden;text-overflow:ellipsis}.g-action-tooltip{--g-popup-border-width:0;--g-popup-background-color:var(--g-color-base-float-heavy)}.g-action-tooltip__content{box-sizing:border-box;color:var(--g-color-text-light-primary);max-width:300px;padding:6px 12px}.g-action-tooltip__heading{align-items:baseline;display:flex;justify-content:space-between}.g-action-tooltip__title{color:var(--g-color-text-light-primary)}.g-action-tooltip__hotkey{margin-inline-start:8px}.g-action-tooltip__description{color:var(--g-color-text-light-secondary);margin-block-start:4px}.g-popup{--_--background-color:var(--g-popup-background-color,var(--g-color-base-float));--_--border-color:var(--g-popup-border-color,var(--g-color-line-generic-solid));--_--border-width:var(--g-popup-border-width,1px);visibility:hidden;z-index:1000}.g-popup_exit_active,.g-popup_open{visibility:visible}.g-popup_exit_active[data-popper-placement*=bottom] .g-popup__content{animation-name:g-popup-bottom}.g-popup_exit_active[data-popper-placement*=top] .g-popup__content{animation-name:g-popup-top}.g-popup_exit_active[data-popper-placement*=left] .g-popup__content{animation-name:g-popup-left}.g-popup_exit_active[data-popper-placement*=right] .g-popup__content{animation-name:g-popup-right}.g-popup_appear_active[data-popper-placement*=bottom] .g-popup__content,.g-popup_enter_active[data-popper-placement*=bottom] .g-popup__content{animation-name:g-popup-bottom-open}.g-popup_appear_active[data-popper-placement*=top] .g-popup__content,.g-popup_enter_active[data-popper-placement*=top] .g-popup__content{animation-name:g-popup-top-open}.g-popup_appear_active[data-popper-placement*=left] .g-popup__content,.g-popup_enter_active[data-popper-placement*=left] .g-popup__content{animation-name:g-popup-left-open}.g-popup_appear_active[data-popper-placement*=right] .g-popup__content,.g-popup_enter_active[data-popper-placement*=right] .g-popup__content{animation-name:g-popup-right-open}.g-popup[data-popper-placement*=bottom] .g-popup__arrow{inset-block-start:-9px}.g-popup[data-popper-placement*=top] .g-popup__arrow{inset-block-end:-9px}.g-popup[data-popper-placement*=top] .g-popup__arrow-content{transform:rotate(180deg)}.g-popup[data-popper-placement*=left] .g-popup__arrow{right:-9px}.g-popup[data-popper-placement*=left] .g-popup__arrow-content{transform:rotate(90deg)}.g-popup[data-popper-placement*=right] .g-popup__arrow{left:-9px}.g-popup[data-popper-placement*=right] .g-popup__arrow-content{transform:rotate(-90deg)}.g-popup__content{animation-duration:.1s;animation-fill-mode:forwards;animation-timing-function:ease-out;background-color:var(--_--background-color);border-radius:4px;box-shadow:0 0 0 var(--_--border-width) var(--_--border-color),0 8px 20px var(--_--border-width) var(--g-color-sfx-shadow);outline:none;position:relative}.g-popup__content>.g-popup__arrow+*,.g-popup__content>:first-child:not(.g-popup__arrow){border-start-end-radius:inherit;border-start-start-radius:inherit}.g-popup__content>:last-child{border-end-end-radius:inherit;border-end-start-radius:inherit}.g-popup__arrow-content{display:flex;height:18px;overflow:hidden;position:relative;width:18px}.g-popup__arrow-circle-wrapper{background-color:initial;height:9px;overflow:hidden;position:relative;width:9px}.g-popup__arrow-circle{border-radius:50%;box-shadow:inset 0 0 0 calc(5px - var(--_--border-width)) var(--_--background-color),inset 0 0 0 5px var(--_--border-color);box-sizing:border-box;height:30px;position:absolute;width:28px}.g-popup__arrow-circle_left{inset-block-end:-4px;inset-inline-end:-5px}.g-popup__arrow-circle_right{inset-block-end:-4px;inset-inline-start:-5px}@keyframes g-popup-bottom{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(10px)}}@keyframes g-popup-bottom-open{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes g-popup-top{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-10px)}}@keyframes g-popup-top-open{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes g-popup-left{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(-10px)}}@keyframes g-popup-left-open{0%{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:translateX(0)}}@keyframes g-popup-right{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(10px)}}@keyframes g-popup-right-open{0%{opacity:0;transform:translateX(10px)}to{opacity:1;transform:translateX(0)}}.g-portal__theme-wrapper{display:contents}.g-hotkey{border-radius:4px;padding:1px 5px}.g-hotkey,.g-hotkey kbd{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height)}.g-hotkey_view_light{background-color:var(--g-color-base-generic)}.g-hotkey_view_light .g-hotkey__plus{color:var(--g-color-text-hint)}.g-hotkey_view_dark{background-color:var(--g-color-base-light-simple-hover);color:var(--g-color-text-light-complementary)}.g-hotkey_view_dark .g-hotkey__plus{color:var(--g-color-text-light-hint)}.g-help-mark__button{background:none;border:none;color:inherit;color:var(--g-color-text-hint);cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0}.g-help-mark__button:focus-visible{border-radius:50%;outline:2px solid var(--g-color-line-focus)}.g-link{-webkit-tap-highlight-color:rgba(0,0,0,0);border-radius:var(--g-focus-border-radius);cursor:pointer;text-decoration:none;touch-action:manipulation}.g-link:focus-visible{outline:2px solid var(--g-color-line-focus)}.g-link_view_normal{color:var(--g-color-text-link)}.g-link_view_primary{color:var(--g-color-text-primary)}.g-link_view_secondary{color:var(--g-color-text-secondary)}.g-link_view_normal:hover,.g-link_view_primary:hover,.g-link_view_secondary:hover{color:var(--g-color-text-link-hover)}.g-link_visitable:visited{color:var(--g-color-text-link-visited)}.g-link_visitable:visited:hover{color:var(--g-color-text-link-visited-hover)}.g-link_underline{text-decoration:underline}.g-popover{display:inline-block;position:relative}.g-popover:not(.g-popover_disabled){cursor:pointer}.g-popover__handler{display:inline-block}.g-popover__tooltip{--_--padding:16px;--_--close-offset:8px;--_--close-size:24px}.g-popover__tooltip-popup-content{box-sizing:border-box;cursor:default;max-width:var(--g-popover-max-width,300px);min-height:40px;padding:var(--g-popover-padding,var(--_--padding))}.g-popover__tooltip-title{display:inline-flex;font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height);margin:0 0 12px}.g-popover__tooltip-buttons{display:flex;flex-wrap:wrap;gap:5px;margin-block-start:20px}.g-popover__tooltip-button{flex:1 1}.g-popover__tooltip-close{inset-block-start:var(--_--close-offset);inset-inline-end:var(--_--close-offset);position:absolute}.g-popover__tooltip-content{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height);overflow-wrap:break-word}.g-popover__tooltip-content_secondary{opacity:.7}.g-popover__tooltip-links>*{margin-block-start:8px}.g-popover__tooltip-links>:first-child{margin-block-start:0}.g-popover__tooltip-content+.g-popover__tooltip-links>:first-child{margin-block-start:12px}.g-popover__tooltip-link{display:inline-block;font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height)}.g-popover__tooltip_theme_announcement .g-popover__tooltip_theme_announcement,.g-popover__tooltip_theme_announcement.g-popover__tooltip_theme_info,.g-popover__tooltip_theme_info .g-popover__tooltip_theme_announcement,.g-popover__tooltip_theme_info.g-popover__tooltip_theme_info{color:var(--g-color-text-primary)}.g-popover__tooltip_force-links-appearance.g-popover__tooltip_theme_info .g-popover__tooltip-content a:not(.g-button),.g-popover__tooltip_theme_announcement .g-popover__tooltip-content a:not(.g-button){color:var(--g-color-text-link);text-decoration:none}.g-popover__tooltip_force-links-appearance.g-popover__tooltip_theme_info .g-popover__tooltip-content a:not(.g-button):hover,.g-popover__tooltip_theme_announcement .g-popover__tooltip-content a:not(.g-button):hover{color:var(--g-color-text-link-hover)}.g-popover__tooltip_theme_announcement{--g-popup-background-color:var(--g-color-base-simple-hover-solid);--g-popup-border-color:var(--g-color-base-simple-hover-solid)}.g-popover__tooltip_theme_special{--g-popup-background-color:var(--g-color-base-brand);--g-popup-border-color:var(--g-color-base-brand);color:var(--g-color-text-light-primary)}.g-popover__tooltip_theme_special .g-popover__tooltip-content a:not(.g-button){color:var(--g-color-text-light-primary);font-weight:var(--g-text-accent-font-weight)}.g-popover__tooltip_theme_special .g-popover__tooltip-content a:not(.g-button):hover{color:var(--g-color-text-light-secondary)}.g-popover__tooltip_theme_special .g-link{color:var(--g-color-text-light-primary)}.g-popover__tooltip_theme_special .g-link:hover{color:var(--g-color-text-light-secondary)}.g-popover__tooltip_size_l{--_--padding:24px}.g-popover__tooltip_size_l .g-popover__tooltip-title{font-family:var(--g-text-header-font-family);font-size:var(--g-text-header-1-font-size);font-weight:var(--g-text-header-font-weight);line-height:var(--g-text-header-1-line-height)}.g-popover__tooltip_size_l .g-popover__tooltip-content{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-popover__tooltip_with-close .g-popover__tooltip-content,.g-popover__tooltip_with-close .g-popover__tooltip-title{padding-inline-end:calc(var(--_--close-offset) + var(--_--close-size) - var(--_--padding))}.g-definition-list{--_--item-block-start:var(--g-spacing-4);--_--term-width:300px;margin:0}.g-definition-list__item{align-items:baseline;display:flex;gap:var(--g-spacing-1)}.g-definition-list__item+.g-definition-list__item{margin-block-start:var(--g-definition-list-item-gap,var(--_--item-block-start))}.g-definition-list__term-container{align-items:baseline;display:flex;flex:0 0 auto;max-width:var(--_--term-width);overflow:hidden;position:relative;width:var(--_--term-width)}.g-definition-list__term-wrapper{color:var(--g-color-text-secondary)}.g-definition-list__dots{border-block-end:1px dotted var(--g-color-line-generic-active);box-sizing:border-box;flex:1 0 auto;margin:0 2px;min-width:25px}.g-definition-list__definition{flex:0 1 auto;margin:0}.g-definition-list_responsive .g-definition-list__term-container{--_--term-width:auto;flex:1 0 min-content}.g-definition-list_vertical{--_--item-block-start:var(--g-spacing-3);--_--term-width:auto}.g-definition-list_vertical .g-definition-list__term-container{flex:1 0 auto}.g-definition-list_vertical .g-definition-list__item{flex-direction:column;gap:var(--g-spacing-half)}.g-definition-list__copy-container{align-items:center;display:inline-flex;margin-inline-end:calc(var(--g-spacing-7)*-1);padding-inline-end:var(--g-spacing-7);position:relative}.g-definition-list__copy-container:hover .g-definition-list__copy-button{opacity:1}.g-definition-list__copy-button{display:inline-block;inset-inline-end:0;margin-inline-start:10px;opacity:0;position:absolute}.g-definition-list__copy-button:focus-visible{opacity:1}.g-switch{position:relative}.g-switch__control{cursor:pointer;opacity:0}.g-switch__indicator{display:inline-block;position:relative}.g-switch__indicator:before{background-color:var(--g-color-base-generic-medium);content:"";inset:0;position:absolute;transition:background .1s linear}.g-switch__indicator:after{content:" ";visibility:hidden}.g-switch__slider{background-color:var(--g-color-base-background);border-radius:50%;content:"";position:absolute;transition:transform .15s ease-out}.g-switch__outline{background:none;height:100%;inset-block-start:0;inset-inline-start:0;pointer-events:none;position:absolute;width:100%}.g-switch__control:focus-visible+.g-switch__outline{outline:2px solid var(--g-color-line-focus)}.g-switch_size_m .g-switch__indicator,.g-switch_size_m .g-switch__indicator:before,.g-switch_size_m .g-switch__outline{border-radius:10px;height:20px;width:36px}.g-switch_size_m .g-switch__slider{height:16px;inset-block-start:2px;inset-inline-start:2px;width:16px}.g-switch_size_m .g-switch__text{margin-block-start:3px}.g-switch_size_l .g-switch__indicator,.g-switch_size_l .g-switch__indicator:before,.g-switch_size_l .g-switch__outline{border-radius:12px;height:24px;width:42px}.g-switch_size_l .g-switch__slider{height:18px;inset-block-start:3px;inset-inline-start:3px;width:18px}.g-switch_size_l .g-switch__text{margin-block-start:4px}.g-switch:hover .g-switch__indicator:before{background-color:var(--g-color-base-generic-medium-hover)}.g-switch_checked .g-switch__slider{--_--translate-x:calc(100%*var(--g-flow-direction));transform:translateX(var(--_--translate-x))}.g-switch_checked .g-switch__indicator:before,.g-switch_checked:hover .g-switch__indicator:before{background-color:var(--g-color-base-brand)}.g-switch_disabled .g-switch__indicator:before{background-color:var(--g-color-base-generic-accent-disabled)}.g-switch_disabled.g-switch_checked .g-switch__indicator:before{background-color:var(--g-color-base-brand);opacity:.5}.g-control-label{-webkit-tap-highlight-color:rgba(0,0,0,0);color:var(--g-color-text-primary);cursor:pointer;display:inline-flex;font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight);touch-action:manipulation;-webkit-user-select:none;user-select:none}.g-control-label_disabled{cursor:default;pointer-events:none}.g-control-label_size_m{font-size:var(--g-text-body-1-font-size);line-height:15px}.g-control-label_size_l{font-size:var(--g-text-body-2-font-size);line-height:18px}.g-control-label__indicator{flex-shrink:0}.g-control-label__text{flex-grow:1;white-space:normal}.g-control-label_disabled .g-control-label__text{opacity:.6}.g-control-label_size_m .g-control-label__text{margin-inline-start:5px}.g-control-label_size_l .g-control-label__text{margin-inline-start:7px}.g-radio-button{--_--border-radius-inner:calc(var(--_--border-radius) - 3px);background-color:var(--g-color-base-generic);border-radius:var(--_--border-radius);box-sizing:border-box;display:inline-flex;flex-direction:row;font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight);position:relative}.g-radio-button__plate{inset-block:0;position:absolute;transition:left .2s,width .2s}.g-radio-button__plate[hidden]{display:none}.g-radio-button__option{border-radius:var(--_--border-radius-inner);cursor:pointer;flex:1 1 auto;font-size:var(--g-text-body-1-font-size);text-align:center;transform:scale(1);transition:color .15s linear;-webkit-user-select:none;user-select:none}.g-radio-button__option-outline{border-radius:var(--_--border-radius-inner);content:"";inset:3px;position:absolute;z-index:-1}.g-radio-button__option-control{border:none;cursor:inherit;height:100%;inset-block-start:0;inset-inline-start:0;margin:0;opacity:0;outline:none;padding:0;position:absolute;width:100%}.g-radio-button__option-control:focus-visible+.g-radio-button__option-outline{outline:2px solid var(--g-color-line-focus)}.g-radio-button__option-text{color:var(--g-color-text-complementary);display:inline-block;white-space:nowrap}.g-radio-button__option-text_icon{align-items:center;display:flex;height:100%}.g-radio-button__option:hover .g-radio-button__option-text,.g-radio-button__option_checked .g-radio-button__option-text{color:var(--g-color-text-primary)}.g-radio-button__option_checked{cursor:default}.g-radio-button__option_disabled{cursor:default;pointer-events:none}.g-radio-button__option_disabled .g-radio-button__option-text{color:var(--g-color-text-hint)}.g-radio-button__option:before,.g-radio-button__plate:before{border-radius:var(--_--border-radius-inner);inset:3px;position:absolute}.g-radio-button__option:before{z-index:-1}.g-radio-button__plate:before,.g-radio-button__plate[hidden]~.g-radio-button__option_checked:before{background-color:var(--g-color-base-background);content:""}.g-radio-button_size_s{--_--border-radius:var(--g-border-radius-s)}.g-radio-button_size_s .g-radio-button__option{height:24px;line-height:24px}.g-radio-button_size_s .g-radio-button__option-text{margin:0 10px}.g-radio-button_size_m{--_--border-radius:var(--g-border-radius-m)}.g-radio-button_size_m .g-radio-button__option{height:28px;line-height:28px}.g-radio-button_size_m .g-radio-button__option-text{margin:0 13px}.g-radio-button_size_l{--_--border-radius:var(--g-border-radius-l)}.g-radio-button_size_l .g-radio-button__option{height:36px;line-height:36px}.g-radio-button_size_l .g-radio-button__option-text{margin:0 18px}.g-radio-button_size_xl{--_--border-radius:var(--g-border-radius-xl)}.g-radio-button_size_xl .g-radio-button__option{font-size:var(--g-text-body-2-font-size);height:44px;line-height:44px}.g-radio-button_size_xl .g-radio-button__option-text{margin:0 25px}.g-radio-button_width_auto{max-width:100%}.g-radio-button_width_max{width:100%}.g-radio-button_width_auto .g-radio-button__option,.g-radio-button_width_max .g-radio-button__option{overflow:hidden}.g-radio-button_width_auto .g-radio-button__option-text,.g-radio-button_width_max .g-radio-button__option-text{display:block;overflow:hidden;text-overflow:ellipsis}.g-label{--_--bg-color:none;--_--bg-color-hover:none;--_--text-color:none;align-items:center;background-color:var(--_--bg-color);border-radius:var(--_--border-radius);box-sizing:border-box;color:var(--_--text-color);display:inline-flex;height:var(--_--height);isolation:isolate;position:relative;transition-duration:.15s;transition-property:opacity,color,background-color;transition-timing-function:ease-in-out}.g-label__text{align-items:baseline;display:flex;font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height);line-height:var(--_--height);margin:0 var(--_--margin-inline);overflow:hidden;text-align:center;white-space:nowrap;width:100%}.g-label__content,.g-label__key{overflow:hidden;text-overflow:ellipsis}.g-label__value{display:flex;opacity:.7;overflow:hidden}.g-label__separator{margin:0 4px}.g-label__main-button{background:none;border:none;border-radius:inherit;color:inherit;cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0;z-index:1}.g-label__main-button:empty{inset:0;position:absolute}.g-label__addon{align-items:center;border-radius:var(--_--border-radius);display:flex;height:var(--_--height);justify-content:center;width:var(--_--height)}.g-label__addon_side_end,.g-label__addon_side_start{inset-block-start:0;position:absolute}.g-label__addon_side_start{border-end-end-radius:0;border-start-end-radius:0;inset-inline-start:2px}.g-label__addon_side_end{border-end-start-radius:0;border-start-start-radius:0;inset-inline-end:0}.g-label__addon_type_button{background:none;background-color:initial;border:none;color:inherit;color:var(--_--text-color);cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,transform .1s ease-out;z-index:2}.g-label__addon_type_button:active{transform:scale(.96)}.g-label_size_xs{--_--height:20px;--_--border-radius:var(--g-border-radius-xs);--_--margin-inline:8px;--_--margin-addon-start:24px;--_--margin-addon-end:22px}.g-label_size_s{--_--height:24px;--_--border-radius:var(--g-border-radius-s);--_--margin-inline:10px;--_--margin-addon-start:28px;--_--margin-addon-end:26px}.g-label_size_m{--_--height:28px;--_--border-radius:var(--g-border-radius-m);--_--margin-inline:12px;--_--margin-addon-start:32px;--_--margin-addon-end:32px}.g-label_disabled{opacity:.7;pointer-events:none}.g-label_interactive{cursor:pointer}.g-label_theme_normal{--_--bg-color:var(--g-color-base-misc-light);--_--bg-color-hover:var(--g-color-base-misc-light-hover);--_--text-color:var(--g-color-text-misc-heavy)}.g-label_theme_success{--_--bg-color:var(--g-color-base-positive-light);--_--bg-color-hover:var(--g-color-base-positive-light-hover);--_--text-color:var(--g-color-text-positive-heavy)}.g-label_theme_info{--_--bg-color:var(--g-color-base-info-light);--_--bg-color-hover:var(--g-color-base-info-light-hover);--_--text-color:var(--g-color-text-info-heavy)}.g-label_theme_warning{--_--bg-color:var(--g-color-base-warning-light);--_--bg-color-hover:var(--g-color-base-warning-light-hover);--_--text-color:var(--g-color-text-warning-heavy)}.g-label_theme_danger{--_--bg-color:var(--g-color-base-danger-light);--_--bg-color-hover:var(--g-color-base-danger-light-hover);--_--text-color:var(--g-color-text-danger-heavy)}.g-label_theme_utility{--_--bg-color:var(--g-color-base-utility-light);--_--bg-color-hover:var(--g-color-base-utility-light-hover);--_--text-color:var(--g-color-text-utility-heavy)}.g-label_theme_unknown{--_--bg-color:var(--g-color-base-neutral-light);--_--bg-color-hover:var(--g-color-base-neutral-light-hover);--_--text-color:var(--g-color-text-complementary)}.g-label_theme_clear{--_--bg-color:#0000;--_--bg-color-hover:var(--g-color-base-simple-hover);--_--text-color:var(--g-color-text-complementary);box-shadow:inset 0 0 0 1px var(--g-color-line-generic)}.g-label:has(.g-label__addon_side_start) .g-label__text{margin-inline-start:var(--_--margin-addon-start)}.g-label:has(.g-label__addon_side_end) .g-label__text{margin-inline-end:var(--_--margin-addon-end)}.g-label__addon_type_button:hover,.g-label_interactive:hover:not(:has(.g-label__addon_type_button:hover)){background-color:var(--_--bg-color-hover)}.g-label__addon_type_button:focus-visible,.g-label__main-button:focus-visible{outline:2px solid var(--g-color-line-focus)}.g-tabs{--_--vertical-item-padding:var(--g-tabs-vertical-item-padding,6px 20px);--_--vertical-item-height:var(--g-tabs-vertical-item-height,18px)}.g-tabs_size_m{--_--item-height:36px;--_--item-gap:24px;--_--item-border-width:2px}.g-tabs_size_m .g-tabs__item-counter,.g-tabs_size_m .g-tabs__item-title{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height)}.g-tabs_size_l{--_--item-height:40px;--_--item-gap:28px;--_--item-border-width:2px}.g-tabs_size_l .g-tabs__item-counter,.g-tabs_size_l .g-tabs__item-title{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-tabs_size_xl{--_--item-height:44px;--_--item-gap:32px;--_--item-border-width:3px}.g-tabs_size_xl .g-tabs__item-counter,.g-tabs_size_xl .g-tabs__item-title{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height)}.g-tabs__item{cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.g-tabs__item-content{align-items:center;border-radius:var(--g-focus-border-radius);display:flex}.g-tabs__item_overflow .g-tabs__item-content{min-width:0}.g-tabs__item-icon{margin-inline-end:8px}.g-tabs__item-title{white-space:nowrap}.g-tabs__item_overflow .g-tabs__item-title{overflow:hidden;text-overflow:ellipsis}.g-tabs__item-counter,.g-tabs__item-label{margin-inline-start:8px}.g-tabs__item-icon>svg{display:block}.g-tabs_direction_horizontal{align-items:flex-end;box-shadow:inset 0 calc(var(--g-tabs-border-width, 1px)*-1) 0 0 var(--g-color-line-generic);display:flex;flex-wrap:wrap;overflow:hidden}.g-tabs_direction_horizontal .g-tabs__item{align-items:center;border-block-end:var(--g-tabs-item-border-width,var(--_--item-border-width)) solid #0000;box-sizing:border-box;display:flex;height:var(--g-tabs-item-height,var(--_--item-height));padding-block-start:var(--_--item-border-width)}.g-tabs_direction_horizontal .g-tabs__item:focus-visible .g-tabs__item-content{outline:2px solid var(--g-color-line-focus);outline-offset:-2px}.g-tabs_direction_horizontal .g-tabs__item-meta{display:none}.g-tabs_direction_horizontal .g-tabs__item-title{color:var(--g-color-text-secondary)}.g-tabs_direction_horizontal .g-tabs__item-counter,.g-tabs_direction_horizontal .g-tabs__item-icon{color:var(--g-color-text-hint)}.g-tabs_direction_horizontal .g-tabs__item:focus-visible .g-tabs__item-title,.g-tabs_direction_horizontal .g-tabs__item:hover .g-tabs__item-title,.g-tabs_direction_horizontal .g-tabs__item_active .g-tabs__item-title{color:var(--g-color-text-primary)}.g-tabs_direction_horizontal .g-tabs__item:focus-visible .g-tabs__item-counter,.g-tabs_direction_horizontal .g-tabs__item:focus-visible .g-tabs__item-icon,.g-tabs_direction_horizontal .g-tabs__item:hover .g-tabs__item-counter,.g-tabs_direction_horizontal .g-tabs__item:hover .g-tabs__item-icon,.g-tabs_direction_horizontal .g-tabs__item_active .g-tabs__item-counter,.g-tabs_direction_horizontal .g-tabs__item_active .g-tabs__item-icon{color:var(--g-color-text-secondary)}.g-tabs_direction_horizontal .g-tabs__item_active,.g-tabs_direction_horizontal .g-tabs__item_active:focus-visible,.g-tabs_direction_horizontal .g-tabs__item_active:hover{border-color:var(--g-color-line-brand)}.g-tabs_direction_horizontal .g-tabs__item_disabled{pointer-events:none}.g-tabs_direction_horizontal .g-tabs__item_disabled .g-tabs__item-title{color:var(--g-color-text-hint)}.g-tabs_direction_horizontal>:not(:last-child){margin-inline-end:var(--g-tabs-item-gap,var(--_--item-gap))}.g-tabs_direction_vertical{display:flex;flex-direction:column}.g-tabs_direction_vertical .g-tabs__item{padding:var(--_--vertical-item-padding)}.g-tabs_direction_vertical .g-tabs__item-title{color:var(--g-color-text-primary);line-height:var(--_--vertical-item-height)}.g-tabs_direction_vertical .g-tabs__item-meta{color:var(--g-color-text-secondary);line-height:var(--_--vertical-item-height)}.g-tabs_direction_vertical .g-tabs__item-counter,.g-tabs_direction_vertical .g-tabs__item-icon{color:var(--g-color-text-secondary)}.g-tabs_direction_vertical .g-tabs__item:focus-visible,.g-tabs_direction_vertical .g-tabs__item:hover{background-color:var(--g-color-base-generic-hover)}.g-tabs_direction_vertical .g-tabs__item_active{background-color:var(--g-color-base-selection)}.g-tabs_direction_vertical .g-tabs__item_active:focus-visible,.g-tabs_direction_vertical .g-tabs__item_active:hover{background-color:var(--g-color-base-selection-hover)}.g-tabs_direction_vertical .g-tabs__item_disabled{pointer-events:none}.g-tabs_direction_vertical .g-tabs__item_disabled .g-tabs__item-title{color:var(--g-color-text-secondary)}.g-outer-additional-content{display:flex;justify-content:space-between;vertical-align:top}.g-outer-additional-content__error,.g-outer-additional-content__note{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height);margin-block-start:2px}.g-outer-additional-content__error{color:var(--g-color-text-danger)}.g-outer-additional-content__error:not(:last-child){margin-inline-end:var(--g-spacing-2)}.g-outer-additional-content__note{margin-inline-start:auto}.g-text-input{--_--text-color:var(--g-color-text-primary);--_--label-color:inherit;--_--placeholder-color:var(--g-color-text-hint);--_--background-color:#0000;--_--border-width:1px;--_--focus-outline-color:var(--g-text-input-focus-outline-color);display:inline-block;position:relative;width:100%}.g-text-input__content{background-color:var(--g-text-input-background-color,var(--_--background-color));border-color:var(--g-text-input-border-color,var(--_--border-color));border-style:solid;border-width:var(--g-text-input-border-width,var(--_--border-width));box-sizing:border-box;color:var(--g-text-input-text-color,var(--_--text-color));display:flex;overflow:hidden;width:100%}.g-text-input__content:hover{border-color:var(--g-text-input-border-color-hover,var(--_--border-color-hover))}.g-text-input__content:focus-within{border-color:var(--g-text-input-border-color-active,var(--_--border-color-active));outline:2px solid var(--g-text-input-focus-outline-color,var(--_--focus-outline-color));outline-offset:-1px}.g-text-input__control{background-color:initial;border:none;box-sizing:border-box;color:inherit;display:inline-block;flex-grow:1;font-family:var(--g-text-body-font-family);font-weight:var(--g-text-body-font-weight);height:var(--g-text-input-height);margin:0;padding:0;position:relative;vertical-align:top;width:100%}.g-text-input__control::placeholder{color:var(--g-text-input-placeholder-color,var(--_--placeholder-color));overflow:hidden;white-space:nowrap}.g-text-input__control:focus{outline:none}.g-text-input__control[type=number]{appearance:textfield}.g-text-input__label{box-sizing:border-box;color:var(--g-text-input-label-color,var(--_--label-color));overflow:hidden;position:absolute;text-overflow:ellipsis;white-space:nowrap;z-index:1}.g-text-input__clear{flex-shrink:0;margin:auto 0}.g-text-input__clear_size_m,.g-text-input__clear_size_s{margin-inline-end:1px}.g-text-input__clear_size_l,.g-text-input__clear_size_xl{margin-inline-end:2px}.g-text-input__error-icon{box-sizing:initial;color:var(--g-color-text-danger);padding-block:var(--_--error-icon-padding-block);padding-inline:var(--_--error-icon-padding-inline)}.g-text-input__additional-content{align-items:center;display:flex}.g-text-input_size_s{--_--error-icon-padding-block:5px;--_--error-icon-padding-inline:0 5px;--_--border-radius:var(--g-border-radius-s)}.g-text-input_size_s .g-text-input__control{--_--input-control-border-width:var( + --g-text-input-border-width,var(--g-text-area-border-width,1px) + );height:calc(24px - var(--_--input-control-border-width)*2);padding:3px 8px}.g-text-input_size_s .g-text-input__control,.g-text-input_size_s .g-text-input__label{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-short-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-short-line-height)}.g-text-input_size_s .g-text-input__label{font-weight:var(--g-text-accent-font-weight);padding-block:3px;padding-inline:8px 4px}.g-text-input_size_s.g-text-input_has-start-content .g-text-input__label{padding-inline-start:2px}.g-text-input_size_s .g-text-input__additional-content{height:22px}.g-text-input_size_s .g-text-input__additional-content_placement_start{padding-inline-start:1px}.g-text-input_size_s .g-text-input__additional-content_placement_end{padding-inline-end:1px}.g-text-input_size_m{--_--error-icon-padding-block:5px;--_--error-icon-padding-inline:0 5px;--_--border-radius:var(--g-border-radius-m)}.g-text-input_size_m .g-text-input__control{--_--input-control-border-width:var( + --g-text-input-border-width,var(--g-text-area-border-width,1px) + );height:calc(28px - var(--_--input-control-border-width)*2);padding:5px 8px}.g-text-input_size_m .g-text-input__control,.g-text-input_size_m .g-text-input__label{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-short-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-short-line-height)}.g-text-input_size_m .g-text-input__label{font-weight:var(--g-text-accent-font-weight);padding-block:5px;padding-inline:8px 4px}.g-text-input_size_m.g-text-input_has-start-content .g-text-input__label{padding-inline-start:2px}.g-text-input_size_m .g-text-input__additional-content{height:26px}.g-text-input_size_m .g-text-input__additional-content_placement_start{padding-inline-start:1px}.g-text-input_size_m .g-text-input__additional-content_placement_end{padding-inline-end:1px}.g-text-input_size_l{--_--error-icon-padding-block:9px;--_--error-icon-padding-inline:0 9px;--_--border-radius:var(--g-border-radius-l)}.g-text-input_size_l .g-text-input__control{--_--input-control-border-width:var( + --g-text-input-border-width,var(--g-text-area-border-width,1px) + );height:calc(36px - var(--_--input-control-border-width)*2);padding:9px 12px}.g-text-input_size_l .g-text-input__control,.g-text-input_size_l .g-text-input__label{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-short-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-short-line-height)}.g-text-input_size_l .g-text-input__label{font-weight:var(--g-text-accent-font-weight);padding-block:9px;padding-inline:12px 4px}.g-text-input_size_l.g-text-input_has-start-content .g-text-input__label{padding-inline-start:3px}.g-text-input_size_l .g-text-input__additional-content{height:34px}.g-text-input_size_l .g-text-input__additional-content_placement_start{padding-inline-start:3px}.g-text-input_size_l .g-text-input__additional-content_placement_end{padding-inline-end:3px}.g-text-input_size_xl{--_--error-icon-padding-block:13px;--_--error-icon-padding-inline:0 13px;--_--border-radius:var(--g-border-radius-xl)}.g-text-input_size_xl .g-text-input__control{--_--input-control-border-width:var( + --g-text-input-border-width,var(--g-text-area-border-width,1px) + );height:calc(44px - var(--_--input-control-border-width)*2);padding:11px 12px}.g-text-input_size_xl .g-text-input__control,.g-text-input_size_xl .g-text-input__label{font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-2-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-2-line-height)}.g-text-input_size_xl .g-text-input__label{font-weight:var(--g-text-accent-font-weight);padding-block:11px;padding-inline:12px 4px}.g-text-input_size_xl.g-text-input_has-start-content .g-text-input__label{padding-inline-start:3px}.g-text-input_size_xl .g-text-input__additional-content{height:42px}.g-text-input_size_xl .g-text-input__additional-content_placement_start{padding-inline-start:3px}.g-text-input_size_xl .g-text-input__additional-content_placement_end{padding-inline-end:3px}.g-text-input_view_normal{--_--border-color:var(--g-color-line-generic);--_--border-color-hover:var(--g-color-line-generic-hover);--_--border-color-active:var(--g-color-line-generic-active)}.g-text-input_view_clear{--_--border-color:#0000;--_--border-color-hover:#0000;--_--border-color-active:#0000;--_--border-radius:0}.g-text-input_view_clear .g-text-input__content{border-inline:0}.g-text-input_view_clear .g-text-input__control{padding-inline:0}.g-text-input.g-text-input_pin_round-round .g-text-input__content{border-radius:var(--g-text-input-border-radius,var(--_--border-radius))}.g-text-input.g-text-input_pin_brick-brick .g-text-input__content{border-radius:0}.g-text-input.g-text-input_pin_clear-clear .g-text-input__content{border-inline:0;border-radius:0}.g-text-input.g-text-input_pin_circle-circle .g-text-input__content{border-radius:100px}.g-text-input.g-text-input_pin_round-brick .g-text-input__content{border-end-end-radius:0;border-end-start-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-start-end-radius:0;border-start-start-radius:var(--g-text-input-border-radius,var(--_--border-radius))}.g-text-input.g-text-input_pin_brick-round .g-text-input__content{border-end-end-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-end-start-radius:0;border-start-end-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-text-input.g-text-input_pin_round-clear .g-text-input__content{border-end-end-radius:0;border-end-start-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-inline-end:0;border-start-end-radius:0;border-start-start-radius:var(--g-text-input-border-radius,var(--_--border-radius))}.g-text-input.g-text-input_pin_clear-round .g-text-input__content{border-end-end-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-end-start-radius:0;border-inline-start:0;border-start-end-radius:var(--g-text-input-border-radius,var(--_--border-radius));border-start-start-radius:0}.g-text-input.g-text-input_pin_brick-clear .g-text-input__content{border-inline-end:0;border-radius:0}.g-text-input.g-text-input_pin_clear-brick .g-text-input__content{border-inline-start:0;border-radius:0}.g-text-input.g-text-input_pin_circle-brick .g-text-input__content{border-end-end-radius:0;border-end-start-radius:100px;border-start-end-radius:0;border-start-start-radius:100px}.g-text-input.g-text-input_pin_brick-circle .g-text-input__content{border-end-end-radius:100px;border-end-start-radius:0;border-start-end-radius:100px;border-start-start-radius:0}.g-text-input.g-text-input_pin_circle-clear .g-text-input__content{border-end-end-radius:0;border-end-start-radius:100px;border-inline-end:0;border-start-end-radius:0;border-start-start-radius:100px}.g-text-input.g-text-input_pin_clear-circle .g-text-input__content{border-end-end-radius:100px;border-end-start-radius:0;border-inline-start:0;border-start-end-radius:100px;border-start-start-radius:0}.g-text-input_disabled{--_--text-color:var(--g-color-text-hint);--_--background-color:var(--g-color-base-generic-accent-disabled);--_--border-color:#0000;--_--border-color-hover:#0000;--_--border-color-active:#0000}.g-text-input_has-scrollbar .g-text-input__clear{inset-inline-end:var(--g-scrollbar-width)}.g-text-input_has-start-content .g-text-input__control{padding-inline-start:2px}.g-text-input_has-end-content .g-text-input__control{padding-inline-end:2px}.g-text-input_has-unstable-end-content{--_--error-icon-padding-inline:0}.g-text-input_state_error.g-text-input_view_normal .g-text-input__content,.g-text-input_state_error.g-text-input_view_normal .g-text-input__content:focus-within,.g-text-input_state_error.g-text-input_view_normal .g-text-input__content:hover{border-color:var(--g-color-line-danger)}.g-text-input_state_error.g-text-input_view_normal .g-text-input__content:focus-within{--_--focus-outline-color:var(--g-color-line-danger)}.g-text-input_state_error.g-text-input_view_clear .g-text-input__content,.g-text-input_state_error.g-text-input_view_clear .g-text-input__content:focus-within,.g-text-input_state_error.g-text-input_view_clear .g-text-input__content:hover{border-block-end:1px solid var(--g-color-line-danger)}.g-text-input_state_error.g-text-input_view_clear .g-text-input__content:focus-within{--_--focus-outline-color:var(--g-color-line-danger)}.g-clear-button{--g-button-text-color:var(--g-color-text-hint);--g-button-text-color-hover:var(--g-color-text-primary);--g-button-background-color:#0000;--g-button-background-color-hover:#0000}@keyframes g-pulse{50%{opacity:15%}}.g-loader{align-items:center;display:inline-flex}.g-loader__center,.g-loader__left,.g-loader__right{animation:g-pulse .8s ease infinite;background:var(--g-color-base-brand)}.g-loader__left{animation-delay:.2s}.g-loader__center{animation-delay:.4s}.g-loader__right{animation-delay:.6s}.g-loader_size_s .g-loader__left{height:13.33333px;width:5px}.g-loader_size_s .g-loader__center{height:20px;margin-inline-start:5px;width:5px}.g-loader_size_s .g-loader__right{height:13.33333px;margin-inline-start:5px;width:5px}.g-loader_size_m .g-loader__left{height:18.66667px;width:7px}.g-loader_size_m .g-loader__center{height:28px;margin-inline-start:7px;width:7px}.g-loader_size_m .g-loader__right{height:18.66667px;margin-inline-start:7px;width:7px}.g-loader_size_l .g-loader__left{height:24px;width:9px}.g-loader_size_l .g-loader__center{height:36px;margin-inline-start:9px;width:9px}.g-loader_size_l .g-loader__right{height:24px;margin-inline-start:9px;width:9px}.kv-ydb-internal-user{align-items:center;display:flex;flex-grow:1;justify-content:space-between;line-height:var(--g-text-body-2-line-height);margin-left:16px}.kv-ydb-internal-user__user-info-wrapper{display:flex;flex-direction:column}.kv-ydb-internal-user__ydb-internal-user-title{font-weight:500}.kv-ydb-internal-user__ydb-user-wrapper{padding:10px;width:300px}.ydb-link-with-icon{align-items:center;display:inline-flex;flex-wrap:nowrap;white-space:nowrap}.ydb-node-endpoints-tooltip-content .info-viewer__value{min-width:70px}.ydb-node-endpoints-tooltip-content__list-container{padding-right:20px}.ydb-node-endpoints-tooltip-content__definition{text-align:right;word-break:break-word}.info-viewer{--ydb-info-viewer-font-size:var(--g-text-body-2-font-size);--ydb-info-viewer-line-height:var(--g-text-body-2-line-height);--ydb-info-viewer-title-font-weight:600;--ydb-info-viewer-title-margin:15px 0 10px;--ydb-info-viewer-items-gap:7px;font-size:var(--ydb-info-viewer-font-size);line-height:var(--ydb-info-viewer-line-height)}.info-viewer__title{font-weight:var(--ydb-info-viewer-title-font-weight);margin:var(--ydb-info-viewer-title-margin)}.info-viewer__items{display:flex;flex-direction:column;gap:var(--ydb-info-viewer-items-gap);max-width:100%}.info-viewer__row{align-items:baseline;display:flex;max-width:100%;padding-top:4px}.info-viewer__label{align-items:baseline;color:var(--g-color-text-secondary);display:flex;flex:0 1 auto;min-width:200px;white-space:nowrap}.info-viewer__label-text_multiline{max-width:180px;overflow:visible;white-space:normal}.info-viewer__dots{border-bottom:1px dotted var(--g-color-text-secondary);display:flex;flex:1 1 auto;margin:0 2px}.info-viewer__value{display:flex;min-width:130px;word-break:break-all}.info-viewer_size_s{--ydb-info-viewer-font-size:var(--g-text-body-1-font-size);--ydb-info-viewer-line-height:var(--g-text-body-1-line-height);--ydb-info-viewer-title-font-weight:500;--ydb-info-viewer-title-margin:0 0 4px;--ydb-info-viewer-items-gap:4px}.info-viewer_size_s .info-viewer__row{height:auto}.info-viewer_size_s .info-viewer__label{min-width:85px}.ydb-cell-with-popover{display:inline-flex;max-width:100%}.ydb-cell-with-popover_full-width{display:flex}.ydb-cell-with-popover__popover{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap}.ydb-cell-with-popover__popover .g-popover__handler{display:inline}.ydb-cell-with-popover__popover_full-width{width:100%}.popup2{animation:none!important;max-width:300px}.histogram-tooltip,.node-tootltip{padding:10px}.histogram-tooltip__label,.node-tootltip__label{color:var(--g-color-text-secondary);padding-right:15px}.cell-tooltip{padding:10px;word-break:break-word}.empty-state{padding:20px}.empty-state_size_m{height:400px}.empty-state__wrapper{display:grid;grid-template-areas:"image title" "image description" "image actions"}.empty-state__wrapper_size_s{height:120px;width:460px}.empty-state__wrapper_size_m{height:240px;width:800px}.empty-state__wrapper_position_center{margin:0 auto;position:relative}.empty-state__image{color:var(--g-color-base-info-light-hover);grid-area:image;justify-self:end;margin-right:60px}.g-root_theme_dark .empty-state__image{color:var(--g-color-base-generic)}.empty-state__title{align-self:center;font-weight:500;grid-area:title}.empty-state__title_size_s{font-size:var(--g-text-subheader-3-font-size);line-height:var(--g-text-subheader-3-line-height)}.empty-state__title_size_m{font-size:var(--g-text-header-2-font-size);line-height:var(--g-text-header-2-line-height)}.empty-state__description{font-size:var(--g-text-body-2-font-size);grid-area:description;line-height:var(--g-text-body-2-line-height)}.empty-state__actions{grid-area:actions}.empty-state__actions>*{margin-right:8px}.ydb-loader{flex:1 1 auto}.authentication,.ydb-loader{align-items:center;display:flex;height:100%;justify-content:center}.authentication{background-blend-mode:normal;background-color:#b8d4fd1a;background-image:radial-gradient(at 0 100%,#0066ff26 20%,#f7f7f700 40%),radial-gradient(at 55% 0,#0066ff26 20%,#f7f7f700 40%),radial-gradient(at 110% 100%,#0066ff26 20%,#f7f7f700 40%)}.authentication .g-text-input{display:flex}.authentication__header{align-items:center;display:flex;font-size:var(--g-text-body-1-font-size);justify-content:space-between;line-height:var(--g-text-header-1-line-height);width:100%}.authentication__logo{align-items:center;display:flex;font-size:16px;font-weight:600;gap:8px}.authentication__title{font-size:var(--g-text-header-2-font-size);font-weight:600;line-height:var(--g-text-header-2-line-height);margin:34px 0 16px}.authentication__form-wrapper{align-items:center;background-color:var(--g-color-base-background);border-radius:16px;display:flex;flex-direction:column;flex-shrink:0;justify-content:center;min-width:320px;padding:40px;width:400px}.authentication__field-wrapper{align-items:flex-start;display:flex;justify-content:space-between;margin-bottom:16px;width:320px}.authentication__field-wrapper .g-text-input_state_error{flex-direction:column}.authentication__button-sign-in{display:inline-flex;justify-content:center}.authentication__show-password-button{margin-left:4px}.authentication__close{position:absolute;right:40px;top:40px}.ydb-connect-to-db__dialog-tabs,.ydb-connect-to-db__docs{margin-top:var(--g-spacing-4)}.ydb-connect-to-db__snippet-container{height:270px}.g-dialog-btn-close{inset-block-start:14px;inset-inline-end:14px;position:absolute;z-index:1}.g-dialog-body{flex:1 1 auto;overflow-y:auto;padding:10px var(--_--side-padding)}.g-dialog-body_has-borders{border-block-end:1px solid var(--g-color-line-generic)}.g-dialog-body_has-borders,.g-dialog-divider{border-block-start:1px solid var(--g-color-line-generic)}.g-dialog-divider{margin:0 calc(var(--_--side-padding)*-1)}.g-dialog-footer{align-items:center;display:flex;padding:28px var(--_--side-padding)}.g-dialog-footer__bts-wrapper{display:flex;gap:10px}.g-dialog-footer__children{align-items:center;display:flex;flex-grow:1;height:100%}.g-dialog-footer__button{min-width:128px;position:relative}.g-dialog-footer__error{color:var(--g-color-text-danger);padding:10px}.g-dialog-header{align-items:center;color:var(--g-color-text-primary);display:flex;justify-content:flex-start;line-height:24px;padding-block:20px 10px;padding-inline:var(--_--side-padding) calc(var(--_--side-padding) + var(--_--close-button-space)*var(--g-flow-is-ltr) + var(--_--close-button-space)*var(--g-flow-is-rtl))}.g-dialog-header__caption{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height)}.g-dialog{--_--side-padding:32px;--_--close-button-space:0px;display:flex;flex-direction:column;position:relative;width:var(--g-dialog-width,var(--_--width))}.g-dialog_has-scroll{max-height:calc(100vh - var(--g-modal-margin, 20px)*2);overflow-y:auto}.g-dialog_size_s{--_--width:480px}.g-dialog_size_m{--_--width:720px}.g-dialog_size_l{--_--width:900px}.g-dialog_has-close{--_--close-button-space:24px}.g-modal{-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);background-color:var(--g-color-sfx-veil);display:none;inset:0;margin:-9999px 0 0 -9999px;overflow:auto;position:fixed;visibility:hidden;z-index:1000}.g-modal__content-aligner{align-items:center;display:inline-flex;justify-content:center;min-height:100%;min-width:100%}.g-modal__content-wrapper{margin:var(--g-modal-margin,20px);overflow-x:hidden}.g-modal__content,.g-modal__content-wrapper{border-radius:var(--g-modal-border-radius,5px)}.g-modal__content{background-color:var(--g-color-base-modal)}.g-modal__content_has-scroll{max-height:calc(100vh - var(--g-modal-margin, 20px)*2);overflow-y:auto}.g-modal,.g-modal__content{animation-fill-mode:forwards;animation-timing-function:ease-out;outline:none}.g-modal_exit_active,.g-modal_open{display:block;margin:0;visibility:visible}.g-modal_appear_active,.g-modal_enter_active{animation-duration:.15s;animation-name:g-modal-open}.g-modal_appear_active .g-modal__content,.g-modal_enter_active .g-modal__content{animation-duration:.15s;animation-name:g-modal-content-open}.g-modal_exit_active{animation-duration:.2s;animation-name:g-modal}@keyframes g-modal{0%{opacity:1}to{opacity:0}}@keyframes g-modal-open{0%{opacity:0}to{opacity:1}}@keyframes g-modal-content-open{0%{transform:scale(.75)}to{transform:scale(1)}}.tablet-icon{border:1px solid;border-radius:4px;display:flex;font-size:10px;height:16px;justify-content:center;text-transform:uppercase;width:23px}.tablet-icon__type{line-height:14px}.header{align-items:center;border-bottom:1px solid var(--g-color-line-generic);display:flex;flex:0 0 40px;justify-content:space-between;padding:0 20px 0 12px}.header__breadcrumbs-item{color:var(--g-color-text-secondary);display:flex;gap:3px}.header__breadcrumbs-item_link:hover{color:var(--g-color-text-complementary)}.header__breadcrumbs-item_active{color:var(--g-color-text-primary)}.header__breadcrumbs-icon{align-items:center;display:flex}.g-divider{--_--content-gap:8px;--_--size:1px}.g-divider:not(:empty){align-items:center;border:none;display:flex}.g-divider:not(:empty):after,.g-divider:not(:empty):before{content:""}.g-divider:after,.g-divider:before{background:var(--g-divider-color,var(--g-color-line-generic));flex-grow:1}.g-divider_orientation_vertical{border-inline-start:1px solid var(--g-divider-color,var(--g-color-line-generic));flex-direction:column}.g-divider_orientation_vertical:after,.g-divider_orientation_vertical:before{width:var(--_--size)}.g-divider_orientation_vertical:before{margin-block-end:var(--_--content-gap)}.g-divider_orientation_vertical:after{margin-block-start:var(--_--content-gap)}.g-divider_orientation_horizontal{border-block-start:1px solid var(--g-divider-color,var(--g-color-line-generic))}.g-divider_orientation_horizontal:after,.g-divider_orientation_horizontal:before{height:var(--_--size)}.g-divider_orientation_horizontal:before{margin-inline-end:var(--_--content-gap)}.g-divider_orientation_horizontal:after{margin-inline-start:var(--_--content-gap)}.g-divider_align_end:after,.g-divider_align_start:before{display:none}.g-menu{background-color:var(--g-color-base-float);box-sizing:border-box;color:var(--g-color-text-primary);display:block;font-size:var(--g-text-body-1-font-size);list-style:none;margin:0;outline:none;overflow:hidden auto;padding:0;-webkit-user-select:none;user-select:none}.g-menu__list-group-item+.g-menu__list-group-item,.g-menu__list-group-item+.g-menu__list-item,.g-menu__list-item+.g-menu__list-group-item{border-block-start:1px solid var(--g-color-line-generic)}.g-menu__item{-webkit-tap-highlight-color:rgba(0,0,0,0);align-items:center;color:var(--g-color-text-primary);display:flex;outline:none;text-decoration:none;touch-action:manipulation}.g-menu__item-icon{display:flex}.g-menu__item-icon-end{display:flex;margin-inline-end:0}.g-menu__item-content{flex-grow:1;min-width:0}.g-menu__item_interactive{cursor:pointer}.g-menu__item_interactive:focus-visible,.g-menu__item_interactive:hover,.g-menu__item_selected{background-color:var(--g-color-base-simple-hover)}.g-menu__item_disabled{color:var(--g-color-text-secondary);cursor:default;pointer-events:none}.g-menu__item_disabled:hover{background-color:initial}.g-menu__item_active{background-color:var(--g-color-base-selection);cursor:default}.g-menu__item_active:focus-visible,.g-menu__item_active:hover{background-color:var(--g-color-base-selection-hover)}.g-menu__item_theme_danger:not(.g-menu__item_disabled){color:var(--g-color-text-danger)}.g-menu__group-label{color:var(--g-color-text-hint);font-weight:var(--g-text-accent-font-weight)}.g-menu__group-list{list-style:none;margin:0;padding:0}.g-menu_size_s{line-height:24px;padding:3px 0}.g-menu_size_s .g-menu__group-label,.g-menu_size_s .g-menu__item{padding:0 10px}.g-menu_size_s .g-menu__item-icon{margin-inline-end:3px}.g-menu_size_s .g-menu__item-icon-end{margin-inline-start:3px}.g-menu_size_s .g-menu__list-group-item+.g-menu__list-group-item,.g-menu_size_s .g-menu__list-group-item+.g-menu__list-item,.g-menu_size_s .g-menu__list-item+.g-menu__list-group-item{margin-block-start:3px;padding-block-start:3px}.g-menu_size_m{line-height:24px;padding:4px 0}.g-menu_size_m .g-menu__group-label,.g-menu_size_m .g-menu__item{padding:0 13px}.g-menu_size_m .g-menu__item-icon{margin-inline-end:4px}.g-menu_size_m .g-menu__item-icon-end{margin-inline-start:4px}.g-menu_size_m .g-menu__list-group-item+.g-menu__list-group-item,.g-menu_size_m .g-menu__list-group-item+.g-menu__list-item,.g-menu_size_m .g-menu__list-item+.g-menu__list-group-item{margin-block-start:4px;padding-block-start:4px}.g-menu_size_l{line-height:28px;padding:5px 0}.g-menu_size_l .g-menu__group-label,.g-menu_size_l .g-menu__item{padding:0 15px}.g-menu_size_l .g-menu__item-icon{margin-inline-end:5px}.g-menu_size_l .g-menu__item-icon-end{margin-inline-start:5px}.g-menu_size_l .g-menu__list-group-item+.g-menu__list-group-item,.g-menu_size_l .g-menu__list-group-item+.g-menu__list-item,.g-menu_size_l .g-menu__list-item+.g-menu__list-group-item{margin-block-start:5px;padding-block-start:5px}.g-menu_size_xl{font-size:var(--g-text-body-2-font-size);line-height:36px;padding:6px 0}.g-menu_size_xl .g-menu__group-label,.g-menu_size_xl .g-menu__item{padding:0 15px}.g-menu_size_xl .g-menu__item-icon{margin-inline-end:6px}.g-menu_size_xl .g-menu__item-icon-end{margin-inline-start:6px}.g-menu_size_xl .g-menu__list-group-item:not(:first-child){margin-block-start:6px;padding-block-start:6px}.g-menu_size_xl .g-menu__list-group-item:not(:last-child){margin-block-end:6px;padding-block-end:6px}.g-dropdown-menu__switcher-wrapper{display:inline-block}.g-dropdown-menu__switcher-button{display:flex}.g-dropdown-menu__menu-item_separator{border-block-start:1px solid var(--g-color-line-generic-solid);margin:.5em 0;pointer-events:none}.g-dropdown-menu__sub-menu-arrow{inset-inline-end:-4px;position:relative}.g-dropdown-menu__sub-menu{position:relative}.g-dropdown-menu__sub-menu .g-dropdown-menu__menu:after,.g-dropdown-menu__sub-menu .g-dropdown-menu__menu:before{content:"";height:100%;inset-block-start:0;position:absolute;width:10px}.g-dropdown-menu__sub-menu .g-dropdown-menu__menu:before{inset-inline-start:-10px}.g-dropdown-menu__sub-menu .g-dropdown-menu__menu:after{inset-inline-end:-10px}.g-breadcrumbs__inner{align-items:center;display:inline-flex;gap:4px;min-height:24px;overflow:hidden;width:100%}.g-breadcrumbs__switcher{background:none;border:none;color:inherit;color:var(--g-color-text-secondary);cursor:pointer;font-family:var(--g-text-body-font-family);font-size:inherit;font-weight:var(--g-text-body-font-weight);outline:none;padding:0}.g-breadcrumbs__switcher:focus-visible{outline:2px solid var(--g-color-line-focus)}.g-breadcrumbs__item,.g-breadcrumbs__switcher{display:inline-block;flex-shrink:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.g-breadcrumbs__item:focus-visible,.g-breadcrumbs__switcher:focus-visible{border-radius:var(--g-focus-border-radius);outline:2px solid var(--g-color-line-focus)}.g-breadcrumbs_calculated_no .g-breadcrumbs__item{overflow:visible}.g-breadcrumbs__divider{align-items:center;color:var(--g-color-text-secondary);display:flex}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item .g-menu__item{padding-inline-start:80px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(0) .g-menu__item{padding-inline-start:0!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:first-child .g-menu__item{padding-inline-start:8px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(2) .g-menu__item{padding-inline-start:16px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(3) .g-menu__item{padding-inline-start:24px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(4) .g-menu__item{padding-inline-start:32px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(5) .g-menu__item{padding-inline-start:40px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(6) .g-menu__item{padding-inline-start:48px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(7) .g-menu__item{padding-inline-start:56px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(8) .g-menu__item{padding-inline-start:64px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(9) .g-menu__item{padding-inline-start:72px!important}.g-breadcrumbs__popup_staircase .g-menu .g-menu__list-item:nth-child(10) .g-menu__item{padding-inline-start:80px!important}*{font-feature-settings:"tnum";box-sizing:border-box;font-variant-numeric:tabular-nums}.g-select-popup__tick-icon{box-sizing:initial}#root,body,html{box-sizing:border-box;height:100%;margin:0;overflow:auto;padding:0}:root{--g-color-base-yellow-light:#ffc70026;--g-color-base-yellow-medium:#ffdb4d66;--tenant-object-info-max-value-width:300px;--diagnostics-section-title-margin:20px;--diagnostics-section-margin:30px;--diagnostics-section-table-width:872px}.g-root{--ydb-data-table-color-hover:var(--g-color-base-simple-hover-solid);--ydb-color-status-grey:var(--g-color-base-neutral-heavy);--ydb-color-status-green:var(--g-color-base-positive-heavy);--ydb-color-status-yellow:var(--g-color-base-warning-heavy);--ydb-color-status-orange:var(--g-color-private-orange-500-solid);--ydb-color-status-red:var(--g-color-base-danger-heavy);--ydb-color-status-blue:var(--g-color-base-info-heavy);--ydb-color-status-black:var(--g-color-base-misc-heavy);--g-popover-max-width:500px}.g-root_theme_light,.g-root_theme_light-hc{--code-background-color:var(--g-color-base-simple-hover)}.g-root_theme_dark,.g-root_theme_dark-hc{--code-background-color:#1e1e1e}:is(#tab,.g-tabs-item_active .g-tabs-item__title){color:var(--g-color-text-primary)!important}:is(#tab,.g-tabs-item__title){color:var(--g-color-text-secondary)}.gn-aside-header__pane-container{height:100%}.gn-aside-header__content{display:flex;flex-direction:column;height:100%;overflow:auto;position:relative}.loader{align-items:center;display:flex;justify-content:center;left:50%;position:fixed;top:50%;z-index:99999999}.app{--data-table-row-height:40px;--data-table-cell-align:middle;--data-table-head-align:middle;display:flex;flex:1 1 auto;flex-direction:column;height:100%}.app .data-table{font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height)}.app .data-table__td,.app .data-table__th{border-left:unset;border-right:unset;border-top:unset;height:var(--data-table-row-height)}.app .data-table__th{font-weight:700}.app .data-table__table{border-collapse:initial;border-spacing:0}.app .data-table__box_sticky-head_moving .data-table__th{height:unset}.app__main{display:flex;flex:1 1 auto;flex-direction:column;overflow:auto}.error{color:var(--g-color-text-danger)}.g-root .data-table_highlight-rows .data-table__row:hover{background:var(--ydb-data-table-color-hover)}.g-table-column-setup__item{cursor:pointer!important;padding:0 8px 0 32px!important}.app_embedded{font-family:Rubik,sans-serif}.g-list{--_--item-padding:var(--g-list-item-padding,0);display:flex;flex:1 1 auto;flex-direction:column;outline:none;width:100%}.g-list__filter{flex:0 0 auto;margin-block-end:8px;padding:var(--_--item-padding)}.g-list__items{flex:1 1 auto}.g-list__empty-placeholder,.g-list__item{align-items:center;box-sizing:border-box;display:flex;overflow:hidden;padding:var(--_--item-padding);-webkit-user-select:none;user-select:none}.g-list__item_active{background:var(--g-color-base-simple-hover)}.g-list__item_selected{background:var(--g-color-base-selection)}.g-list__item_selected:hover{background:var(--g-color-base-selection-hover)}.g-list__item_sort-handle-align_right{flex-direction:row-reverse}.g-list__item_sort-handle-align_right .g-list__item-sort-icon{margin-inline:10px 0}.g-list__item_sortable[data-rbd-drag-handle-context-id]:active{cursor:grabbing}.g-list__item_dragging{background:var(--g-color-base-simple-hover-solid);z-index:100001}.g-list__empty-placeholder{box-sizing:border-box;color:var(--g-color-text-hint);min-height:36px;padding-block:8px}.g-list__item-content{align-items:center;display:flex;flex:1 1 auto;height:100%;overflow:hidden;text-overflow:ellipsis}.g-list__item-sort-icon{align-items:center;color:var(--g-color-text-hint);display:flex;flex:0 0 auto;margin-inline-end:4px;width:12px}.g-list__loading-indicator{align-items:center;display:flex;justify-content:center;width:100%}:root{--information-popup-padding:16px;--information-popup-header-padding:16px}.information-popup__content{box-sizing:border-box;display:flex;flex-direction:column;padding:var(--information-popup-header-padding) 0 0 0;position:relative;width:280px}.information-popup__docs,.information-popup__footer{display:flex;flex-direction:column;flex-shrink:0}.information-popup__docs{padding-bottom:8px}.information-popup__footer{background-color:var(--g-color-base-generic);border-top:1px solid var(--g-color-line-generic);padding:12px 0 8px;position:relative}.information-popup__title{flex-shrink:0;margin-bottom:4px;padding:4px var(--information-popup-padding)}.information-popup__docs-list-wrap{display:flex;flex-direction:column;flex-shrink:0;margin-bottom:12px}.information-popup__docs-list-wrap:last-child{margin-bottom:0}.information-popup__docs-link,.information-popup__shortcuts-item{align-items:center;box-sizing:border-box;cursor:pointer;display:flex;flex-grow:1;height:100%;line-height:var(--g-text-body-1-line-height);padding:8px var(--information-popup-padding);width:100%}.information-popup__docs-link:hover,.information-popup__shortcuts-item:hover{background-color:var(--g-color-base-simple-hover)}.information-popup__shortcuts-item{justify-content:space-between}.information-popup__docs-link,.information-popup__docs-link:active,.information-popup__docs-link:focus,.information-popup__docs-link:hover,.information-popup__docs-link:visited{color:inherit;outline:none;text-decoration:none}.information-popup__item-icon-wrap{height:16px;margin-right:10px;width:16px}.information-popup__shortcuts-content,.kv-navigation__internal-user{align-items:center;display:flex}.kv-navigation__internal-user{justify-content:space-between;line-height:var(--g-text-body-2-line-height);margin-left:16px}.kv-navigation__user-info-wrapper{display:flex;flex-direction:column}.kv-navigation__ydb-internal-user-title{font-weight:500}.kv-navigation__ydb-user-wrapper{padding:10px;width:300px}.kv-navigation__hotkeys-panel-title{display:flex;gap:var(--g-spacing-2)}.ydb-resizeable-data-table{display:flex;padding-right:20px;width:max-content}.ydb-resizeable-data-table__row-skeleton{height:50%;width:100%}.ydb-resizeable-data-table__row-skeleton:after{animation:none!important}.g-skeleton{--_--animation-from:calc(-100%*var(--g-flow-direction));--_--animation-to:calc(100%*var(--g-flow-direction));--_--gradient-deg:calc(90deg*var(--g-flow-direction));background-color:var(--g-color-base-generic);border-radius:5px;display:inline-block;overflow:hidden;position:relative;width:100%;z-index:0}.g-skeleton:after{animation:g-skeleton 1.2s ease-out infinite;background-image:linear-gradient(var(--_--gradient-deg),#0000,var(--g-color-base-generic));content:"";inset:0;position:absolute}@keyframes g-skeleton{0%{transform:translateX(var(--_--animation-from))}to{transform:translateX(var(--_--animation-to))}}.ydb-status-icon__status-color_state_green{background-color:var(--ydb-color-status-green)}.ydb-status-icon__status-color_state_yellow{background-color:var(--ydb-color-status-yellow)}.ydb-status-icon__status-color_state_blue{background-color:var(--ydb-color-status-blue)}.ydb-status-icon__status-color_state_red{background-color:var(--ydb-color-status-red)}.ydb-status-icon__status-color_state_grey{background-color:var(--ydb-color-status-grey)}.ydb-status-icon__status-color_state_orange{background-color:var(--ydb-color-status-orange)}.ydb-status-icon__status-icon_state_blue{color:var(--ydb-color-status-blue)}.ydb-status-icon__status-icon_state_yellow{color:var(--ydb-color-status-yellow)}.ydb-status-icon__status-icon_state_orange{color:var(--ydb-color-status-orange)}.ydb-status-icon__status-icon_state_red{color:var(--ydb-color-status-red)}.ydb-status-icon__status-color,.ydb-status-icon__status-icon{border-radius:3px;display:inline-flex;flex-shrink:0}.ydb-status-icon__status-color_size_xs,.ydb-status-icon__status-icon_size_xs{aspect-ratio:1;height:12px;width:12px}.ydb-status-icon__status-color_size_s,.ydb-status-icon__status-icon_size_s{aspect-ratio:1;height:16px;width:16px}.ydb-status-icon__status-color_size_m,.ydb-status-icon__status-icon_size_m{aspect-ratio:1;height:18px;width:18px}.ydb-status-icon__status-color_size_l,.ydb-status-icon__status-icon_size_l{height:24px;width:24px}.link{color:var(--g-color-text-link);text-decoration:none}.link_external{margin-right:10px}.link:hover{color:var(--g-color-text-link-hover)}.entity-status{--button-width:28px;align-items:center;display:inline-flex;font-size:var(--g-text-body-2-font-size);height:100%;line-height:var(--g-text-body-2-line-height);max-width:100%;position:relative}.entity-status__icon{margin-right:var(--g-spacing-2)}.entity-status__clipboard-button,.entity-status__info-icon{color:var(--g-color-text-secondary);opacity:0}.entity-status__clipboard-button:focus-visible,.entity-status__clipboard-button_visible,.entity-status__info-icon:focus-visible,.entity-status__info-icon_visible{opacity:1}.entity-status__clipboard-button:focus-visible,.entity-status__info-icon:focus-visible{background-color:var(--g-color-base-float);position:absolute;right:2px;top:2px}.data-table__row:hover .entity-status__clipboard-button,.data-table__row:hover .entity-status__info-icon,.ydb-paginated-table__row:hover .entity-status__clipboard-button,.ydb-paginated-table__row:hover .entity-status__info-icon{opacity:1}.data-table__row:hover .entity-status__clipboard-button:focus-visible,.data-table__row:hover .entity-status__info-icon:focus-visible,.ydb-paginated-table__row:hover .entity-status__clipboard-button:focus-visible,.ydb-paginated-table__row:hover .entity-status__info-icon:focus-visible{background-color:unset;position:static}.entity-status__clipboard-button_visible,.entity-status__info-icon_visible{opacity:1}.entity-status__info-icon:hover{color:var(--g-color-text-primary)}.entity-status__wrapper{overflow:hidden;position:relative}.entity-status__wrapper_with-clipboard-button,.entity-status__wrapper_with-info-button{padding-right:var(--button-width)}.entity-status__wrapper_with-clipboard-button.entity-status__wrapper_with-info-button{padding-right:calc(var(--button-width)*2)}.entity-status__controls-wrapper{align-items:center;display:flex;gap:var(--g-spacing-1);height:100%;position:absolute;right:0;top:0;width:0}.entity-status__controls-wrapper_visible{background-color:var(--g-color-base-background);padding:var(--g-spacing-1);width:min-content}.data-table__row:hover .entity-status__controls-wrapper,.ydb-paginated-table__row:hover .entity-status__controls-wrapper,.ydb-tree-view__item .entity-status__controls-wrapper{background-color:var(--ydb-data-table-color-hover);padding:var(--g-spacing-1);width:min-content}.entity-status__label{color:var(--g-color-text-complementary);font-size:var(--g-text-body-2-font-size);line-height:var(--g-text-body-2-line-height);margin-right:2px}.entity-status__label_size_l{font-size:var(--g-text-header-2-font-size)}.entity-status__link{display:inline-block;margin-top:5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.entity-status__wrapper_with-clipboard-button .entity-status__link,.entity-status__wrapper_with-info-button .entity-status__link{width:calc(100% + var(--button-width))}.entity-status__wrapper_with-clipboard-button.entity-status__wrapper_with-info-button .entity-status__link{width:calc(100% + var(--button-width)*2)}.entity-status__link_with-left-trim{direction:rtl;text-align:end}.entity-status__link_with-left-trim .entity-status__name{unicode-bidi:plaintext}.entity-status__label_state_blue{color:var(--ydb-color-status-blue)}.entity-status__label_state_yellow{color:var(--ydb-color-status-yellow)}.entity-status__label_state_orange{color:var(--ydb-color-status-orange)}.entity-status__label_state_red{color:var(--ydb-color-status-red)}.ydb-usage-label_overload{background-color:var(--ydb-color-status-red);color:var(--g-color-text-light-primary)}.extended-cluster{display:flex;height:100%}.extended-cluster__balancer{align-items:center;display:flex;flex-direction:row}.extended-cluster__clipboard-button{margin-left:5px}.g-toast{--_--item-gap:10px;--_--item-padding:16px;--_--background-color:var(--g-color-base-background);background-color:var(--_--background-color);border-radius:8px;box-shadow:0 0 15px var(--g-color-sfx-shadow);box-sizing:border-box;display:flex;font-size:var(--g-text-body-2-font-size);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));overflow:hidden;padding:var(--g-toaster-item-padding,var(--_--item-padding));position:relative;width:inherit;z-index:0}.g-toast_mobile{width:100%}.g-toast_theme_normal{--_--background-color:var(--g-color-base-float)}.g-toast_theme_info{--_--container-background-color:var(--g-color-base-info-light);--_--icon-color:var(--g-color-text-info-heavy)}.g-toast_theme_success{--_--container-background-color:var(--g-color-base-positive-light);--_--icon-color:var(--g-color-text-positive-heavy)}.g-toast_theme_warning{--_--container-background-color:var(--g-color-base-warning-light);--_--icon-color:var(--g-color-text-warning-heavy)}.g-toast_theme_danger{--_--container-background-color:var(--g-color-base-danger-light);--_--icon-color:var(--g-color-text-danger-heavy)}.g-toast_theme_utility{--_--container-background-color:var(--g-color-base-utility-light);--_--icon-color:var(--g-color-text-utility-heavy)}.g-toast__container{display:flex;flex:1 1 auto;flex-flow:column nowrap;min-height:var(--g-text-body-2-line-height);min-width:0}.g-toast__container:before{background-color:var(--_--container-background-color);content:"";height:100%;inset-block-start:0;inset-inline-start:0;pointer-events:none;position:absolute;width:100%;z-index:-1}.g-toast__icon-container{color:var(--_--icon-color);flex:0 0 auto;min-width:0;padding-block-start:2px;padding-inline-end:8px}.g-toast__title{font-family:var(--g-text-subheader-font-family);font-size:var(--g-text-subheader-3-font-size);font-weight:var(--g-text-subheader-font-weight);line-height:var(--g-text-subheader-3-line-height);margin:0;padding-inline-end:32px}.g-toast__content{margin-block-start:var(--g-spacing-2)}.g-toast__content_without-title{margin-block-start:0;padding-inline-end:32px}.g-toast__actions{margin-block-start:var(--g-spacing-3)}.g-toast__action{margin-inline-end:8px}.g-toast .g-toast__btn-close{inset-block-start:16px;inset-inline-end:16px;position:absolute}.g-toast-animation-mobile_enter{opacity:0;position:absolute}.g-toast-animation-mobile_enter_active{animation:g-toast-enter-mobile .6s ease-out forwards;position:relative}.g-toast-animation-mobile_exit_active{animation:g-toast-exit-mobile .6s ease-in forwards}@keyframes g-toast-enter-mobile{0%{height:0;margin-block-end:0;opacity:0;padding:0;transform:translateY(10px)}50%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:0;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateY(10px)}to{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:1;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(0)}}@keyframes g-toast-exit-mobile{0%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:1;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(0)}50%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:0;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateY(10px)}to{height:0;margin-block-end:0;opacity:0;padding:0;transform:translateY(10px)}}.g-toast-animation-desktop_enter{opacity:0;position:absolute}.g-toast-animation-desktop_enter_active{animation:g-toast-enter-desktop .6s ease-out forwards;position:relative}.g-toast-animation-desktop_exit_active{animation:g-toast-exit-desktop .6s ease-in forwards}@keyframes g-toast-enter-desktop{0%{height:0;margin-block-end:0;opacity:0;padding:0;transform:translateX(calc(var(--g-flow-direction)*10px))}50%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:0;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(calc(var(--g-flow-direction)*10px))}to{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:1;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(0)}}@keyframes g-toast-exit-desktop{0%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:1;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(0)}50%{height:var(--_--item-height);margin-block-end:var(--g-toaster-item-gap,var(--_--item-gap));opacity:0;padding:var(--g-toaster-item-padding,var(--_--item-padding));transform:translateX(calc(var(--g-flow-direction)*10px))}to{height:0;margin-block-end:0;opacity:0;padding:0;transform:translateX(calc(var(--g-flow-direction)*10px))}}.g-toaster{--_--width:312px;align-items:flex-end;display:flex;flex-direction:column;inset-block-end:0;inset-inline-end:10px;position:fixed;width:var(--g-toaster-width,var(--_--width));z-index:100000}.g-toaster_mobile{--_--width:calc(100% - 20px);inset-inline-start:50%;transform:translate(-50%)}.g-root{--g-font-family-sans:"Inter","Helvetica Neue","Helvetica","Arial",sans-serif;--g-font-family-monospace:"Menlo","Monaco","Consolas","Ubuntu Mono","Liberation Mono","DejaVu Sans Mono","Courier New","Courier",monospace;--g-text-body-font-family:var(--g-font-family-sans);--g-text-caption-font-family:var(--g-font-family-sans);--g-text-header-font-family:var(--g-font-family-sans);--g-text-subheader-font-family:var(--g-font-family-sans);--g-text-display-font-family:var(--g-font-family-sans);--g-text-code-font-family:var(--g-font-family-monospace);--g-text-body-font-weight:400;--g-text-caption-font-weight:400;--g-text-header-font-weight:600;--g-text-display-font-weight:600;--g-text-code-font-weight:400;--g-text-accent-font-weight:600;--g-text-body-1-font-size:13px;--g-text-body-1-line-height:18px;--g-text-body-2-font-size:15px;--g-text-body-2-line-height:20px;--g-text-body-3-font-size:17px;--g-text-body-3-line-height:24px;--g-text-body-short-font-size:13px;--g-text-body-short-line-height:16px;--g-text-caption-1-font-size:9px;--g-text-caption-1-line-height:12px;--g-text-caption-2-font-size:11px;--g-text-caption-2-line-height:16px;--g-text-header-1-font-size:20px;--g-text-header-1-line-height:24px;--g-text-header-2-font-size:24px;--g-text-header-2-line-height:28px;--g-text-subheader-1-font-size:13px;--g-text-subheader-1-line-height:18px;--g-text-subheader-2-font-size:15px;--g-text-subheader-2-line-height:20px;--g-text-subheader-3-font-size:17px;--g-text-subheader-3-line-height:24px;--g-text-display-1-font-size:28px;--g-text-display-1-line-height:36px;--g-text-display-2-font-size:32px;--g-text-display-2-line-height:40px;--g-text-display-3-font-size:40px;--g-text-display-3-line-height:48px;--g-text-display-4-font-size:48px;--g-text-display-4-line-height:52px;--g-text-code-1-font-size:12px;--g-text-code-1-line-height:18px;--g-text-code-2-font-size:14px;--g-text-code-2-line-height:20px;--g-text-code-3-font-size:16px;--g-text-code-3-line-height:24px;--g-text-code-inline-1-font-size:12px;--g-text-code-inline-1-line-height:14px;--g-text-code-inline-2-font-size:14px;--g-text-code-inline-2-line-height:16px;--g-text-code-inline-3-font-size:16px;--g-text-code-inline-3-line-height:20px;--g-spacing-base:4px;--g-spacing-0:calc(var(--g-spacing-base)*0);--g-spacing-half:calc(var(--g-spacing-base)*0.5);--g-spacing-1:var(--g-spacing-base);--g-spacing-2:calc(var(--g-spacing-base)*2);--g-spacing-3:calc(var(--g-spacing-base)*3);--g-spacing-4:calc(var(--g-spacing-base)*4);--g-spacing-5:calc(var(--g-spacing-base)*5);--g-spacing-6:calc(var(--g-spacing-base)*6);--g-spacing-7:calc(var(--g-spacing-base)*7);--g-spacing-8:calc(var(--g-spacing-base)*8);--g-spacing-9:calc(var(--g-spacing-base)*9);--g-spacing-10:calc(var(--g-spacing-base)*10);--g-scrollbar-width:12px;--g-border-radius-xs:3px;--g-border-radius-s:5px;--g-border-radius-m:6px;--g-border-radius-l:8px;--g-border-radius-xl:10px;--g-focus-border-radius:2px;background:var(--g-color-base-background);color:var(--g-color-text-primary);font-family:var(--g-text-body-font-family);font-size:var(--g-text-body-1-font-size);font-weight:var(--g-text-body-font-weight);line-height:var(--g-text-body-1-line-height)}.g-root[dir=ltr],body.g-root{--g-flow-direction:1;--g-flow-is-ltr:1;--g-flow-is-rtl:0}.g-root[dir=rtl]{--g-flow-direction:-1;--g-flow-is-ltr:0;--g-flow-is-rtl:1}.g-root_theme_light{--g-color-private-blue-50:#3697f11a;--g-color-private-blue-100:#3697f126;--g-color-private-blue-150:#3697f133;--g-color-private-blue-200:#3697f14d;--g-color-private-blue-250:#3697f166;--g-color-private-blue-300:#3697f180;--g-color-private-blue-350:#3697f199;--g-color-private-blue-400:#3697f1b3;--g-color-private-blue-450:#3697f1cc;--g-color-private-blue-500:#3697f1e6;--g-color-private-blue-50-solid:#ebf5fe;--g-color-private-blue-100-solid:#e1effd;--g-color-private-blue-150-solid:#d7eafc;--g-color-private-blue-200-solid:#c3e0fb;--g-color-private-blue-250-solid:#afd5f9;--g-color-private-blue-300-solid:#9bcbf8;--g-color-private-blue-350-solid:#86c1f7;--g-color-private-blue-400-solid:#72b6f5;--g-color-private-blue-450-solid:#5eacf4;--g-color-private-blue-500-solid:#4aa1f2;--g-color-private-blue-550-solid:#3697f1;--g-color-private-blue-600-solid:#348bdc;--g-color-private-blue-650-solid:#327fc8;--g-color-private-blue-700-solid:#3072b3;--g-color-private-blue-750-solid:#2e669e;--g-color-private-blue-800-solid:#2c5a8a;--g-color-private-blue-850-solid:#2a4e75;--g-color-private-blue-900-solid:#284260;--g-color-private-blue-950-solid:#26354b;--g-color-private-blue-1000-solid:#252f41;--g-color-private-green-50:#32ba761a;--g-color-private-green-100:#32ba7626;--g-color-private-green-150:#32ba7633;--g-color-private-green-200:#32ba764d;--g-color-private-green-250:#32ba7666;--g-color-private-green-300:#32ba7680;--g-color-private-green-350:#32ba7699;--g-color-private-green-400:#32ba76b3;--g-color-private-green-450:#32ba76cc;--g-color-private-green-500:#32ba76e6;--g-color-private-green-50-solid:#ebf8f1;--g-color-private-green-100-solid:#e0f5ea;--g-color-private-green-150-solid:#d6f1e4;--g-color-private-green-200-solid:#c2ead6;--g-color-private-green-250-solid:#ade3c8;--g-color-private-green-300-solid:#9db;--g-color-private-green-350-solid:#84d6ad;--g-color-private-green-400-solid:#70cf9f;--g-color-private-green-450-solid:#5bc891;--g-color-private-green-500-solid:#47c184;--g-color-private-green-550-solid:#32ba76;--g-color-private-green-600-solid:#30aa6e;--g-color-private-green-650-solid:#2f9b65;--g-color-private-green-700-solid:#2d8b5d;--g-color-private-green-750-solid:#2c7b54;--g-color-private-green-800-solid:#2a6c4c;--g-color-private-green-850-solid:#285c44;--g-color-private-green-900-solid:#274c3b;--g-color-private-green-950-solid:#253c33;--g-color-private-green-1000-solid:#24352f;--g-color-private-yellow-50:#ffbe5c1a;--g-color-private-yellow-100:#ffbe5c26;--g-color-private-yellow-150:#ffbe5c33;--g-color-private-yellow-200:#ffbe5c4d;--g-color-private-yellow-250:#ffbe5c66;--g-color-private-yellow-300:#ffbe5c80;--g-color-private-yellow-350:#ffbe5c99;--g-color-private-yellow-400:#ffbe5cb3;--g-color-private-yellow-450:#ffbe5ccc;--g-color-private-yellow-500:#ffbe5ce6;--g-color-private-yellow-50-solid:#fff9ef;--g-color-private-yellow-100-solid:#fff5e7;--g-color-private-yellow-150-solid:#fff2de;--g-color-private-yellow-200-solid:#ffecce;--g-color-private-yellow-250-solid:#ffe5be;--g-color-private-yellow-300-solid:#ffdfae;--g-color-private-yellow-350-solid:#ffd89d;--g-color-private-yellow-400-solid:#ffd28d;--g-color-private-yellow-450-solid:#ffcb7d;--g-color-private-yellow-500-solid:#ffc56c;--g-color-private-yellow-550-solid:#ffbe5c;--g-color-private-yellow-600-solid:#e9ae56;--g-color-private-yellow-650-solid:#d39e50;--g-color-private-yellow-700-solid:#bd8e4b;--g-color-private-yellow-750-solid:#a77e45;--g-color-private-yellow-800-solid:#916e3f;--g-color-private-yellow-850-solid:#7a5d39;--g-color-private-yellow-900-solid:#644d33;--g-color-private-yellow-950-solid:#4e3d2e;--g-color-private-yellow-1000-solid:#43352b;--g-color-private-orange-400-solid:#ffa04d;--g-color-private-orange-500-solid:#ff8519;--g-color-private-orange-600-solid:#e96e03;--g-color-private-orange-650-solid:#d36507;--g-color-private-orange-700-solid:#bd5c0a;--g-color-private-orange-750-solid:#a7530e;--g-color-private-orange-800-solid:#914a11;--g-color-private-orange-850-solid:#7a4114;--g-color-private-orange-900-solid:#643818;--g-color-private-orange-950-solid:#4e2f1b;--g-color-private-orange-1000-solid:#432b1d;--g-color-private-red-50:#ff003d1a;--g-color-private-red-100:#ff003d26;--g-color-private-red-150:#ff003d33;--g-color-private-red-200:#ff003d4d;--g-color-private-red-250:#ff003d66;--g-color-private-red-300:#ff003d80;--g-color-private-red-350:#ff003d99;--g-color-private-red-400:#ff003db3;--g-color-private-red-450:#ff003dcc;--g-color-private-red-500:#ff003de6;--g-color-private-red-50-solid:#ffe6ec;--g-color-private-red-100-solid:#ffd9e2;--g-color-private-red-150-solid:#ffccd8;--g-color-private-red-200-solid:#ffb3c5;--g-color-private-red-250-solid:#ff99b1;--g-color-private-red-300-solid:#ff809e;--g-color-private-red-350-solid:#ff668b;--g-color-private-red-400-solid:#ff4d77;--g-color-private-red-450-solid:#ff3364;--g-color-private-red-500-solid:#ff1950;--g-color-private-red-550-solid:#ff003d;--g-color-private-red-600-solid:#e9033a;--g-color-private-red-650-solid:#d30638;--g-color-private-red-700-solid:#bd0935;--g-color-private-red-750-solid:#a70c32;--g-color-private-red-800-solid:#910f30;--g-color-private-red-850-solid:#7a112d;--g-color-private-red-900-solid:#64142a;--g-color-private-red-950-solid:#4e1727;--g-color-private-red-1000-solid:#431926;--g-color-private-purple-600-solid:#844dbb;--g-color-private-purple-650-solid:#7947aa;--g-color-private-purple-700-solid:#6e4299;--g-color-private-purple-750-solid:#633d88;--g-color-private-purple-800-solid:#593877;--g-color-private-purple-850-solid:#4e3266;--g-color-private-purple-900-solid:#432d55;--g-color-private-purple-950-solid:#382844;--g-color-private-purple-1000-solid:#32253c;--g-color-private-cool-grey-300-solid:#b5c2cc;--g-color-private-cool-grey-600-solid:#647a8d;--g-color-private-cool-grey-650-solid:#5c6f81;--g-color-private-cool-grey-700-solid:#556575;--g-color-private-cool-grey-750-solid:#4e5b69;--g-color-private-cool-grey-800-solid:#47515e;--g-color-private-cool-grey-850-solid:#3f4652;--g-color-private-cool-grey-900-solid:#383c46;--g-color-private-cool-grey-950-solid:#31323a;--g-color-private-cool-grey-1000-solid:#2d2c34;--g-color-text-primary:var(--g-color-text-dark-primary);--g-color-text-complementary:var(--g-color-text-dark-complementary);--g-color-text-secondary:var(--g-color-text-dark-secondary);--g-color-text-hint:var(--g-color-text-dark-hint);--g-color-text-info:var(--g-color-private-blue-600-solid);--g-color-text-positive:var(--g-color-private-green-600-solid);--g-color-text-warning:var(--g-color-private-yellow-700-solid);--g-color-text-danger:var(--g-color-private-red-600-solid);--g-color-text-utility:var(--g-color-private-purple-600-solid);--g-color-text-misc:var(--g-color-private-cool-grey-600-solid);--g-color-text-info-heavy:var(--g-color-private-blue-700-solid);--g-color-text-positive-heavy:var(--g-color-private-green-700-solid);--g-color-text-warning-heavy:var(--g-color-private-orange-700-solid);--g-color-text-danger-heavy:var(--g-color-private-red-700-solid);--g-color-text-utility-heavy:var(--g-color-private-purple-700-solid);--g-color-text-misc-heavy:var(--g-color-private-cool-grey-700-solid);--g-color-text-brand:var(--g-color-private-yellow-700-solid);--g-color-text-brand-heavy:var(--g-color-private-orange-700-solid);--g-color-text-brand-contrast:var(--g-color-text-dark-primary);--g-color-text-link:var(--g-color-private-yellow-650-solid);--g-color-text-link-hover:var(--g-color-private-orange-650-solid);--g-color-text-link-visited:var(--g-color-private-purple-550-solid);--g-color-text-link-visited-hover:var(--g-color-private-purple-800-solid);--g-color-text-dark-primary:var(--g-color-private-black-850);--g-color-text-dark-complementary:var(--g-color-private-black-700);--g-color-text-dark-secondary:var(--g-color-private-black-500);--g-color-text-dark-hint:var(--g-color-private-black-300);--g-color-text-light-primary:var(--g-color-private-white-1000-solid);--g-color-text-light-complementary:var(--g-color-private-white-850);--g-color-text-light-secondary:var(--g-color-private-white-700);--g-color-text-light-hint:var(--g-color-private-white-500);--g-color-text-inverted-primary:var(--g-color-text-light-primary);--g-color-text-inverted-complementary:var(--g-color-text-light-complementary);--g-color-text-inverted-secondary:var(--g-color-text-light-secondary);--g-color-text-inverted-hint:var(--g-color-text-light-hint);--g-color-base-background:var(--g-color-private-white-1000-solid);--g-color-base-generic:var(--g-color-private-black-50);--g-color-base-generic-hover:var(--g-color-private-black-150);--g-color-base-generic-medium:var(--g-color-private-black-150);--g-color-base-generic-medium-hover:var(--g-color-private-black-250);--g-color-base-generic-accent:var(--g-color-private-black-150);--g-color-base-generic-accent-disabled:var(--g-color-private-black-70);--g-color-base-generic-ultralight:var(--g-color-private-black-20-solid);--g-color-base-simple-hover:var(--g-color-private-black-50);--g-color-base-simple-hover-solid:var(--g-color-private-black-50-solid);--g-color-base-brand:var(--g-color-private-yellow-550-solid);--g-color-base-brand-hover:var(--g-color-private-yellow-600-solid);--g-color-base-selection:var(--g-color-private-yellow-200);--g-color-base-selection-hover:var(--g-color-private-yellow-300);--g-color-base-info-light:var(--g-color-private-blue-100);--g-color-base-info-light-hover:var(--g-color-private-blue-200);--g-color-base-info-medium:var(--g-color-private-blue-200);--g-color-base-info-medium-hover:var(--g-color-private-blue-300);--g-color-base-info-heavy:var(--g-color-private-blue-600-solid);--g-color-base-info-heavy-hover:var(--g-color-private-blue-700-solid);--g-color-base-positive-light:var(--g-color-private-green-100);--g-color-base-positive-light-hover:var(--g-color-private-green-200);--g-color-base-positive-medium:var(--g-color-private-green-200);--g-color-base-positive-medium-hover:var(--g-color-private-green-300);--g-color-base-positive-heavy:var(--g-color-private-green-600-solid);--g-color-base-positive-heavy-hover:var(--g-color-private-green-700-solid);--g-color-base-warning-light:var(--g-color-private-yellow-200);--g-color-base-warning-light-hover:var(--g-color-private-yellow-300);--g-color-base-warning-medium:var(--g-color-private-yellow-400);--g-color-base-warning-medium-hover:var(--g-color-private-yellow-500);--g-color-base-warning-heavy:var(--g-color-private-yellow-550-solid);--g-color-base-warning-heavy-hover:var(--g-color-private-yellow-650-solid);--g-color-base-danger-light:var(--g-color-private-red-100);--g-color-base-danger-light-hover:var(--g-color-private-red-200);--g-color-base-danger-medium:var(--g-color-private-red-200);--g-color-base-danger-medium-hover:var(--g-color-private-red-300);--g-color-base-danger-heavy:var(--g-color-private-red-600-solid);--g-color-base-danger-heavy-hover:var(--g-color-private-red-700-solid);--g-color-base-utility-light:var(--g-color-private-purple-100);--g-color-base-utility-light-hover:var(--g-color-private-purple-200);--g-color-base-utility-medium:var(--g-color-private-purple-200);--g-color-base-utility-medium-hover:var(--g-color-private-purple-300);--g-color-base-utility-heavy:var(--g-color-private-purple-600-solid);--g-color-base-utility-heavy-hover:var(--g-color-private-purple-700-solid);--g-color-base-neutral-light:var(--g-color-private-black-50);--g-color-base-neutral-light-hover:var(--g-color-private-black-100);--g-color-base-neutral-medium:var(--g-color-private-black-200);--g-color-base-neutral-medium-hover:var(--g-color-private-black-250);--g-color-base-neutral-heavy:var(--g-color-private-black-450);--g-color-base-neutral-heavy-hover:var(--g-color-private-black-550);--g-color-base-misc-light:var(--g-color-private-cool-grey-100);--g-color-base-misc-light-hover:var(--g-color-private-cool-grey-200);--g-color-base-misc-medium:var(--g-color-private-cool-grey-200);--g-color-base-misc-medium-hover:var(--g-color-private-cool-grey-300);--g-color-base-misc-heavy:var(--g-color-private-cool-grey-600-solid);--g-color-base-misc-heavy-hover:var(--g-color-private-cool-grey-700-solid);--g-color-base-light:var(--g-color-private-white-1000-solid);--g-color-base-light-hover:var(--g-color-private-white-850);--g-color-base-light-simple-hover:var(--g-color-private-white-150);--g-color-base-light-disabled:var(--g-color-private-white-150);--g-color-base-light-accent-disabled:var(--g-color-private-white-300);--g-color-base-float:var(--g-color-private-white-1000-solid);--g-color-base-float-hover:var(--g-color-private-black-50-solid);--g-color-base-float-medium:var(--g-color-private-black-550-solid);--g-color-base-float-heavy:var(--g-color-private-black-700-solid);--g-color-base-float-accent:var(--g-color-private-white-1000-solid);--g-color-base-float-accent-hover:var(--g-color-private-white-850);--g-color-base-float-announcement:var(--g-color-private-cool-grey-50-solid);--g-color-base-modal:var(--g-color-base-background);--g-color-line-generic:var(--g-color-private-black-100);--g-color-line-generic-hover:var(--g-color-private-black-150);--g-color-line-generic-active:var(--g-color-private-black-300);--g-color-line-generic-accent:var(--g-color-private-black-150);--g-color-line-generic-accent-hover:var(--g-color-private-black-300);--g-color-line-generic-solid:var(--g-color-private-black-100-solid);--g-color-line-brand:var(--g-color-private-yellow-600-solid);--g-color-line-focus:var(--g-color-private-cool-grey-450);--g-color-line-light:var(--g-color-private-white-500);--g-color-line-info:var(--g-color-private-blue-450);--g-color-line-positive:var(--g-color-private-green-450);--g-color-line-warning:var(--g-color-private-yellow-600-solid);--g-color-line-danger:var(--g-color-private-red-450);--g-color-line-utility:var(--g-color-private-purple-450);--g-color-line-misc:var(--g-color-private-cool-grey-450);--g-color-sfx-veil:var(--g-color-private-black-250);--g-color-sfx-shadow:var(--g-color-private-black-150);--g-color-sfx-shadow-heavy:var(--g-color-private-black-500);--g-color-sfx-shadow-light:var(--g-color-private-black-50);--g-color-sfx-fade:var(--g-color-private-white-300);--g-color-scroll-track:var(--g-color-base-background);--g-color-scroll-handle:var(--g-color-private-black-100);--g-color-scroll-handle-hover:var(--g-color-private-black-150);--g-color-scroll-corner:var(--g-color-private-black-100);--g-color-infographics-axis:var(--g-color-private-black-150-solid);--g-color-infographics-tooltip-bg:var(--g-color-private-white-950)}.g-root_theme_dark{--g-color-private-white-20-solid:#262226;--g-color-private-white-50-solid:#2d282d;--g-color-private-white-70-solid:#312d31;--g-color-private-white-100-solid:#383438;--g-color-private-white-150-solid:#433f43;--g-color-private-white-200-solid:#4e4a4e;--g-color-private-white-250-solid:#595559;--g-color-private-white-300-solid:#646164;--g-color-private-white-350-solid:#6f6c6f;--g-color-private-white-400-solid:#7a777a;--g-color-private-white-450-solid:#858385;--g-color-private-white-500-solid:#908e90;--g-color-private-white-550-solid:#9c999c;--g-color-private-white-600-solid:#a7a5a7;--g-color-private-white-650-solid:#b2b0b2;--g-color-private-white-700-solid:#bdbbbd;--g-color-private-white-750-solid:#c8c6c8;--g-color-private-white-800-solid:#d3d2d3;--g-color-private-white-850-solid:#deddde;--g-color-private-white-900-solid:#e9e8e9;--g-color-private-white-950-solid:#f4f4f4;--g-color-private-blue-50:#3697f11a;--g-color-private-blue-100:#3697f126;--g-color-private-blue-150:#3697f133;--g-color-private-blue-200:#3697f14d;--g-color-private-blue-250:#3697f166;--g-color-private-blue-300:#3697f180;--g-color-private-blue-350:#3697f199;--g-color-private-blue-400:#3697f1b3;--g-color-private-blue-450:#3697f1cc;--g-color-private-blue-500:#3697f1e6;--g-color-private-blue-50-solid:#242937;--g-color-private-blue-100-solid:#252f41;--g-color-private-blue-150-solid:#26354b;--g-color-private-blue-200-solid:#284260;--g-color-private-blue-250-solid:#2a4e75;--g-color-private-blue-300-solid:#2c5a8a;--g-color-private-blue-350-solid:#2e669e;--g-color-private-blue-400-solid:#3072b3;--g-color-private-blue-450-solid:#327fc8;--g-color-private-blue-500-solid:#348bdc;--g-color-private-blue-550-solid:#3697f1;--g-color-private-blue-600-solid:#4aa1f2;--g-color-private-blue-650-solid:#5eacf4;--g-color-private-blue-700-solid:#72b6f5;--g-color-private-blue-750-solid:#86c1f7;--g-color-private-blue-800-solid:#9bcbf8;--g-color-private-blue-850-solid:#afd5f9;--g-color-private-blue-900-solid:#c3e0fb;--g-color-private-blue-950-solid:#d7eafc;--g-color-private-blue-1000-solid:#e1effd;--g-color-private-green-50:#4db09b1a;--g-color-private-green-100:#4db09b26;--g-color-private-green-150:#4db09b33;--g-color-private-green-200:#4db09b4d;--g-color-private-green-250:#4db09b66;--g-color-private-green-300:#4db09b80;--g-color-private-green-350:#4db09b99;--g-color-private-green-400:#4db09bb3;--g-color-private-green-450:#4db09bcc;--g-color-private-green-500:#4db09be6;--g-color-private-green-50-solid:#262c2e;--g-color-private-green-100-solid:#283334;--g-color-private-green-150-solid:#2b3a3a;--g-color-private-green-200-solid:#2f4946;--g-color-private-green-250-solid:#335852;--g-color-private-green-300-solid:#38675f;--g-color-private-green-350-solid:#3c756b;--g-color-private-green-400-solid:#408477;--g-color-private-green-450-solid:#449383;--g-color-private-green-500-solid:#49a18f;--g-color-private-green-550-solid:#4db09b;--g-color-private-green-600-solid:#5fb8a5;--g-color-private-green-650-solid:#71c0af;--g-color-private-green-700-solid:#82c8b9;--g-color-private-green-750-solid:#94d0c3;--g-color-private-green-800-solid:#a6d8cd;--g-color-private-green-850-solid:#b8dfd7;--g-color-private-green-900-solid:#cae7e1;--g-color-private-green-950-solid:#dbefeb;--g-color-private-green-1000-solid:#e4f3f0;--g-color-private-yellow-50:#ffbe5c1a;--g-color-private-yellow-100:#ffbe5c26;--g-color-private-yellow-150:#ffbe5c33;--g-color-private-yellow-200:#ffbe5c4d;--g-color-private-yellow-250:#ffbe5c66;--g-color-private-yellow-300:#ffbe5c80;--g-color-private-yellow-350:#ffbe5c99;--g-color-private-yellow-400:#ffbe5cb3;--g-color-private-yellow-450:#ffbe5ccc;--g-color-private-yellow-500:#ffbe5ce6;--g-color-private-yellow-50-solid:#382d28;--g-color-private-yellow-100-solid:#43352b;--g-color-private-yellow-150-solid:#4e3d2e;--g-color-private-yellow-200-solid:#644d33;--g-color-private-yellow-250-solid:#7a5d39;--g-color-private-yellow-300-solid:#916e3f;--g-color-private-yellow-350-solid:#a77e45;--g-color-private-yellow-400-solid:#bd8e4b;--g-color-private-yellow-450-solid:#d39e50;--g-color-private-yellow-500-solid:#e9ae56;--g-color-private-yellow-550-solid:#ffbe5c;--g-color-private-yellow-600-solid:#ffc56c;--g-color-private-yellow-650-solid:#ffcb7d;--g-color-private-yellow-700-solid:#ffd28d;--g-color-private-yellow-750-solid:#ffd89d;--g-color-private-yellow-800-solid:#ffdfae;--g-color-private-yellow-850-solid:#ffe5be;--g-color-private-yellow-900-solid:#ffecce;--g-color-private-yellow-950-solid:#fff2de;--g-color-private-yellow-1000-solid:#fff5e7;--g-color-private-orange-50-solid:#332420;--g-color-private-orange-100-solid:#3b281f;--g-color-private-orange-150-solid:#432b1e;--g-color-private-orange-200-solid:#54321b;--g-color-private-orange-250-solid:#643919;--g-color-private-orange-300-solid:#754017;--g-color-private-orange-350-solid:#864715;--g-color-private-orange-400-solid:#964e13;--g-color-private-orange-450-solid:#a75510;--g-color-private-orange-500-solid:#b75c0e;--g-color-private-orange-700-solid:#d99255;--g-color-private-orange-800-solid:#e4b186;--g-color-private-red-50:#e5325d1a;--g-color-private-red-100:#e5325d26;--g-color-private-red-150:#e5325d33;--g-color-private-red-200:#e5325d4d;--g-color-private-red-250:#e5325d66;--g-color-private-red-300:#e5325d80;--g-color-private-red-350:#e5325d99;--g-color-private-red-400:#e5325db3;--g-color-private-red-450:#e5325dcc;--g-color-private-red-500:#e5325de6;--g-color-private-red-50-solid:#361f28;--g-color-private-red-100-solid:#3f202b;--g-color-private-red-150-solid:#49212e;--g-color-private-red-200-solid:#5d2334;--g-color-private-red-250-solid:#70253a;--g-color-private-red-300-solid:#842840;--g-color-private-red-350-solid:#972a45;--g-color-private-red-400-solid:#ab2c4b;--g-color-private-red-450-solid:#be2e51;--g-color-private-red-500-solid:#d23057;--g-color-private-red-550-solid:#e5325d;--g-color-private-red-600-solid:#e8476d;--g-color-private-red-650-solid:#ea5b7d;--g-color-private-red-700-solid:#ed708e;--g-color-private-red-750-solid:#ef849e;--g-color-private-red-800-solid:#f299ae;--g-color-private-red-850-solid:#f5adbe;--g-color-private-red-900-solid:#f7c2ce;--g-color-private-red-950-solid:#fad6df;--g-color-private-red-1000-solid:#fbe0e7;--g-color-private-purple-50-solid:#2d2233;--g-color-private-purple-100-solid:#32253c;--g-color-private-purple-150-solid:#382844;--g-color-private-purple-200-solid:#432d55;--g-color-private-purple-250-solid:#4e3266;--g-color-private-purple-300-solid:#593877;--g-color-private-purple-350-solid:#633d88;--g-color-private-purple-400-solid:#6e4299;--g-color-private-purple-450-solid:#7947aa;--g-color-private-purple-500-solid:#844dbb;--g-color-private-cool-grey-50-solid:#28272e;--g-color-private-cool-grey-100-solid:#2b2c34;--g-color-private-cool-grey-150-solid:#2e313a;--g-color-private-cool-grey-200-solid:#353b47;--g-color-private-cool-grey-250-solid:#3b4553;--g-color-private-cool-grey-300-solid:#414f5f;--g-color-private-cool-grey-350-solid:#47586b;--g-color-private-cool-grey-400-solid:#4d6277;--g-color-private-cool-grey-450-solid:#546c84;--g-color-private-cool-grey-500-solid:#5a7690;--g-color-private-cool-grey-750-solid:#a0b3c4;--g-color-private-cool-grey-800-solid:#b0c0ce;--g-color-text-primary:var(--g-color-text-light-primary);--g-color-text-complementary:var(--g-color-text-light-complementary);--g-color-text-secondary:var(--g-color-text-light-secondary);--g-color-text-hint:var(--g-color-text-light-hint);--g-color-text-info:var(--g-color-private-blue-550-solid);--g-color-text-positive:var(--g-color-private-green-550-solid);--g-color-text-warning:var(--g-color-private-yellow-550-solid);--g-color-text-danger:var(--g-color-private-red-550-solid);--g-color-text-utility:var(--g-color-private-purple-600-solid);--g-color-text-misc:var(--g-color-private-cool-grey-600-solid);--g-color-text-info-heavy:var(--g-color-private-blue-600-solid);--g-color-text-positive-heavy:var(--g-color-private-green-600-solid);--g-color-text-warning-heavy:var(--g-color-private-yellow-600-solid);--g-color-text-danger-heavy:var(--g-color-private-red-600-solid);--g-color-text-utility-heavy:var(--g-color-private-purple-650-solid);--g-color-text-misc-heavy:var(--g-color-private-cool-grey-650-solid);--g-color-text-brand:var(--g-color-private-yellow-600-solid);--g-color-text-brand-heavy:var(--g-color-private-yellow-700-solid);--g-color-text-brand-contrast:var(--g-color-text-dark-primary);--g-color-text-link:var(--g-color-private-yellow-550-solid);--g-color-text-link-hover:var(--g-color-private-orange-550-solid);--g-color-text-link-visited:var(--g-color-private-purple-600-solid);--g-color-text-link-visited-hover:var(--g-color-private-purple-750-solid);--g-color-text-dark-primary:var(--g-color-private-black-900);--g-color-text-dark-complementary:var(--g-color-private-black-700);--g-color-text-dark-secondary:var(--g-color-private-black-500);--g-color-text-dark-hint:var(--g-color-private-black-300);--g-color-text-light-primary:var(--g-color-private-white-850);--g-color-text-light-complementary:var(--g-color-private-white-700);--g-color-text-light-secondary:var(--g-color-private-white-500);--g-color-text-light-hint:var(--g-color-private-white-300);--g-color-text-inverted-primary:var(--g-color-text-dark-primary);--g-color-text-inverted-complementary:var(--g-color-text-dark-complementary);--g-color-text-inverted-secondary:var(--g-color-text-dark-secondary);--g-color-text-inverted-hint:var(--g-color-text-dark-hint);--g-color-base-background:#221d22;--g-color-base-generic:var(--g-color-private-white-100);--g-color-base-generic-hover:var(--g-color-private-white-150);--g-color-base-generic-medium:var(--g-color-private-white-250);--g-color-base-generic-medium-hover:var(--g-color-private-white-300);--g-color-base-generic-accent:var(--g-color-private-white-150);--g-color-base-generic-accent-disabled:var(--g-color-private-white-70);--g-color-base-generic-ultralight:var(--g-color-private-white-20-solid);--g-color-base-simple-hover:var(--g-color-private-white-100);--g-color-base-simple-hover-solid:var(--g-color-private-white-100-solid);--g-color-base-brand:var(--g-color-private-yellow-550-solid);--g-color-base-brand-hover:var(--g-color-private-yellow-650-solid);--g-color-base-selection:var(--g-color-private-yellow-150);--g-color-base-selection-hover:var(--g-color-private-yellow-200);--g-color-base-info-light:var(--g-color-private-blue-150);--g-color-base-info-light-hover:var(--g-color-private-blue-200);--g-color-base-info-medium:var(--g-color-private-blue-300);--g-color-base-info-medium-hover:var(--g-color-private-blue-400);--g-color-base-info-heavy:var(--g-color-private-blue-600-solid);--g-color-base-info-heavy-hover:var(--g-color-private-blue-700-solid);--g-color-base-positive-light:var(--g-color-private-green-150);--g-color-base-positive-light-hover:var(--g-color-private-green-200);--g-color-base-positive-medium:var(--g-color-private-green-300);--g-color-base-positive-medium-hover:var(--g-color-private-green-400);--g-color-base-positive-heavy:var(--g-color-private-green-600-solid);--g-color-base-positive-heavy-hover:var(--g-color-private-green-700-solid);--g-color-base-warning-light:var(--g-color-private-yellow-150);--g-color-base-warning-light-hover:var(--g-color-private-yellow-200);--g-color-base-warning-medium:var(--g-color-private-yellow-300);--g-color-base-warning-medium-hover:var(--g-color-private-yellow-400);--g-color-base-warning-heavy:var(--g-color-private-yellow-600-solid);--g-color-base-warning-heavy-hover:var(--g-color-private-yellow-700-solid);--g-color-base-danger-light:var(--g-color-private-red-150);--g-color-base-danger-light-hover:var(--g-color-private-red-200);--g-color-base-danger-medium:var(--g-color-private-red-300);--g-color-base-danger-medium-hover:var(--g-color-private-red-400);--g-color-base-danger-heavy:var(--g-color-private-red-600-solid);--g-color-base-danger-heavy-hover:var(--g-color-private-red-700-solid);--g-color-base-utility-light:var(--g-color-private-purple-150);--g-color-base-utility-light-hover:var(--g-color-private-purple-250);--g-color-base-utility-medium:var(--g-color-private-purple-300);--g-color-base-utility-medium-hover:var(--g-color-private-purple-400);--g-color-base-utility-heavy:var(--g-color-private-purple-600-solid);--g-color-base-utility-heavy-hover:var(--g-color-private-purple-700-solid);--g-color-base-neutral-light:var(--g-color-private-white-100);--g-color-base-neutral-light-hover:var(--g-color-private-white-150);--g-color-base-neutral-medium:var(--g-color-private-white-250);--g-color-base-neutral-medium-hover:var(--g-color-private-white-350);--g-color-base-neutral-heavy:var(--g-color-private-white-550);--g-color-base-neutral-heavy-hover:var(--g-color-private-white-650);--g-color-base-misc-light:var(--g-color-private-cool-grey-150);--g-color-base-misc-light-hover:var(--g-color-private-cool-grey-200);--g-color-base-misc-medium:var(--g-color-private-cool-grey-300);--g-color-base-misc-medium-hover:var(--g-color-private-cool-grey-400);--g-color-base-misc-heavy:var(--g-color-private-cool-grey-600-solid);--g-color-base-misc-heavy-hover:var(--g-color-private-cool-grey-700-solid);--g-color-base-light:var(--g-color-private-white-850);--g-color-base-light-hover:var(--g-color-private-white-700);--g-color-base-light-simple-hover:var(--g-color-private-white-150);--g-color-base-light-disabled:var(--g-color-private-white-150);--g-color-base-light-accent-disabled:var(--g-color-private-white-300);--g-color-base-float:var(--g-color-private-white-100-solid);--g-color-base-float-hover:var(--g-color-private-white-150-solid);--g-color-base-float-medium:var(--g-color-private-white-150-solid);--g-color-base-float-heavy:var(--g-color-private-white-250-solid);--g-color-base-float-accent:var(--g-color-private-white-150-solid);--g-color-base-float-accent-hover:var(--g-color-private-white-200-solid);--g-color-base-float-announcement:var(--g-color-private-white-150-solid);--g-color-base-modal:var(--g-color-base-background);--g-color-line-generic:var(--g-color-private-white-150);--g-color-line-generic-hover:var(--g-color-private-white-250);--g-color-line-generic-active:var(--g-color-private-white-300);--g-color-line-generic-accent:var(--g-color-private-white-150);--g-color-line-generic-accent-hover:var(--g-color-private-white-300);--g-color-line-generic-solid:var(--g-color-private-white-150-solid);--g-color-line-brand:var(--g-color-private-yellow-600-solid);--g-color-line-focus:var(--g-color-private-cool-grey-450);--g-color-line-light:var(--g-color-private-white-500);--g-color-line-info:var(--g-color-private-blue-450);--g-color-line-positive:var(--g-color-private-green-450);--g-color-line-warning:var(--g-color-private-yellow-450);--g-color-line-danger:var(--g-color-private-red-450);--g-color-line-utility:var(--g-color-private-purple-450);--g-color-line-misc:var(--g-color-private-cool-grey-450);--g-color-sfx-veil:var(--g-color-private-black-600);--g-color-sfx-shadow:var(--g-color-private-black-200);--g-color-sfx-shadow-heavy:var(--g-color-private-black-500);--g-color-sfx-shadow-light:var(--g-color-private-black-200);--g-color-sfx-fade:var(--g-color-private-white-250);--g-color-scroll-track:var(--g-color-base-background);--g-color-scroll-handle:var(--g-color-private-white-150);--g-color-scroll-handle-hover:var(--g-color-private-white-250);--g-color-scroll-corner:var(--g-color-private-white-150);--g-color-infographics-axis:var(--g-color-private-white-150-solid);--g-color-infographics-tooltip-bg:var(--g-color-private-white-opaque-150)}.g-root_theme_light-hc{--g-color-private-blue-50:#3697f11a;--g-color-private-blue-100:#3697f126;--g-color-private-blue-150:#3697f133;--g-color-private-blue-200:#3697f14d;--g-color-private-blue-250:#3697f166;--g-color-private-blue-300:#3697f180;--g-color-private-blue-350:#3697f199;--g-color-private-blue-400:#3697f1b3;--g-color-private-blue-450:#3697f1cc;--g-color-private-blue-500:#3697f1e6;--g-color-private-blue-50-solid:#ebf5fe;--g-color-private-blue-100-solid:#e1effd;--g-color-private-blue-150-solid:#d7eafc;--g-color-private-blue-200-solid:#c3e0fb;--g-color-private-blue-250-solid:#afd5f9;--g-color-private-blue-300-solid:#9bcbf8;--g-color-private-blue-350-solid:#86c1f7;--g-color-private-blue-400-solid:#72b6f5;--g-color-private-blue-450-solid:#5eacf4;--g-color-private-blue-500-solid:#4aa1f2;--g-color-private-blue-550-solid:#3697f1;--g-color-private-blue-600-solid:#328adb;--g-color-private-blue-650-solid:#2f7cc4;--g-color-private-blue-700-solid:#2b6fae;--g-color-private-blue-750-solid:#286198;--g-color-private-blue-800-solid:#245482;--g-color-private-blue-850-solid:#20476b;--g-color-private-blue-900-solid:#1d3955;--g-color-private-blue-950-solid:#192c3f;--g-color-private-blue-1000-solid:#172533;--g-color-private-green-50:#32ba761a;--g-color-private-green-100:#32ba7626;--g-color-private-green-150:#32ba7633;--g-color-private-green-200:#32ba764d;--g-color-private-green-250:#32ba7666;--g-color-private-green-300:#32ba7680;--g-color-private-green-350:#32ba7699;--g-color-private-green-400:#32ba76b3;--g-color-private-green-450:#32ba76cc;--g-color-private-green-500:#32ba76e6;--g-color-private-green-50-solid:#ebf8f1;--g-color-private-green-100-solid:#e0f5ea;--g-color-private-green-150-solid:#d6f1e4;--g-color-private-green-200-solid:#c2ead6;--g-color-private-green-250-solid:#ade3c8;--g-color-private-green-300-solid:#9db;--g-color-private-green-350-solid:#84d6ad;--g-color-private-green-400-solid:#70cf9f;--g-color-private-green-450-solid:#5bc891;--g-color-private-green-500-solid:#47c184;--g-color-private-green-550-solid:#32ba76;--g-color-private-green-600-solid:#2fa96c;--g-color-private-green-650-solid:#2c9862;--g-color-private-green-700-solid:#288758;--g-color-private-green-750-solid:#25764e;--g-color-private-green-800-solid:#264;--g-color-private-green-850-solid:#1f553a;--g-color-private-green-900-solid:#1c4430;--g-color-private-green-950-solid:#183326;--g-color-private-green-1000-solid:#172a21;--g-color-private-yellow-50:#ffbe5c1a;--g-color-private-yellow-100:#ffbe5c26;--g-color-private-yellow-150:#ffbe5c33;--g-color-private-yellow-200:#ffbe5c4d;--g-color-private-yellow-250:#ffbe5c66;--g-color-private-yellow-300:#ffbe5c80;--g-color-private-yellow-350:#ffbe5c99;--g-color-private-yellow-400:#ffbe5cb3;--g-color-private-yellow-450:#ffbe5ccc;--g-color-private-yellow-500:#ffbe5ce6;--g-color-private-yellow-50-solid:#fff9ef;--g-color-private-yellow-100-solid:#fff5e7;--g-color-private-yellow-150-solid:#fff2de;--g-color-private-yellow-200-solid:#ffecce;--g-color-private-yellow-250-solid:#ffe5be;--g-color-private-yellow-300-solid:#ffdfae;--g-color-private-yellow-350-solid:#ffd89d;--g-color-private-yellow-400-solid:#ffd28d;--g-color-private-yellow-450-solid:#ffcb7d;--g-color-private-yellow-500-solid:#ffc56c;--g-color-private-yellow-550-solid:#ffbe5c;--g-color-private-yellow-600-solid:#e7ad55;--g-color-private-yellow-650-solid:#d09b4d;--g-color-private-yellow-700-solid:#b88a46;--g-color-private-yellow-750-solid:#a0793e;--g-color-private-yellow-800-solid:#896837;--g-color-private-yellow-850-solid:#715630;--g-color-private-yellow-900-solid:#594528;--g-color-private-yellow-950-solid:#413421;--g-color-private-yellow-1000-solid:#362b1d;--g-color-private-orange-400-solid:#ffa04d;--g-color-private-orange-500-solid:#ff8519;--g-color-private-orange-600-solid:#e76d02;--g-color-private-orange-650-solid:#d06304;--g-color-private-orange-700-solid:#b85805;--g-color-private-orange-750-solid:#a04e07;--g-color-private-orange-800-solid:#894409;--g-color-private-orange-850-solid:#713a0b;--g-color-private-orange-900-solid:#59300d;--g-color-private-orange-950-solid:#41250e;--g-color-private-orange-1000-solid:#36200f;--g-color-private-red-50:#ff003d1a;--g-color-private-red-100:#ff003d26;--g-color-private-red-150:#ff003d33;--g-color-private-red-200:#ff003d4d;--g-color-private-red-250:#ff003d66;--g-color-private-red-300:#ff003d80;--g-color-private-red-350:#ff003d99;--g-color-private-red-400:#ff003db3;--g-color-private-red-450:#ff003dcc;--g-color-private-red-500:#ff003de6;--g-color-private-red-50-solid:#ffe6ec;--g-color-private-red-100-solid:#ffd9e2;--g-color-private-red-150-solid:#ffccd8;--g-color-private-red-200-solid:#ffb3c5;--g-color-private-red-250-solid:#ff99b1;--g-color-private-red-300-solid:#ff809e;--g-color-private-red-350-solid:#ff668b;--g-color-private-red-400-solid:#ff4d77;--g-color-private-red-450-solid:#ff3364;--g-color-private-red-500-solid:#ff1950;--g-color-private-red-550-solid:#ff003d;--g-color-private-red-600-solid:#e70239;--g-color-private-red-650-solid:#d00334;--g-color-private-red-700-solid:#b80530;--g-color-private-red-750-solid:#a0072c;--g-color-private-red-800-solid:#890928;--g-color-private-red-850-solid:#710a23;--g-color-private-red-900-solid:#590c1f;--g-color-private-red-950-solid:#410e1b;--g-color-private-red-1000-solid:#360e18;--g-color-private-purple-600-solid:#834cb9;--g-color-private-purple-650-solid:#7645a7;--g-color-private-purple-700-solid:#6a3f94;--g-color-private-purple-750-solid:#5d3882;--g-color-private-purple-800-solid:#51326f;--g-color-private-purple-850-solid:#442b5c;--g-color-private-purple-900-solid:#38254a;--g-color-private-purple-950-solid:#2b1e37;--g-color-private-purple-1000-solid:#251b2e;--g-color-private-cool-grey-300-solid:#b5c2cc;--g-color-private-cool-grey-600-solid:#62798c;--g-color-private-cool-grey-650-solid:#596d7e;--g-color-private-cool-grey-700-solid:#506271;--g-color-private-cool-grey-750-solid:#475663;--g-color-private-cool-grey-800-solid:#3f4b56;--g-color-private-cool-grey-850-solid:#363f48;--g-color-private-cool-grey-900-solid:#2d343b;--g-color-private-cool-grey-950-solid:#24282d;--g-color-private-cool-grey-1000-solid:#1f2226;--g-color-text-primary:var(--g-color-text-dark-primary);--g-color-text-complementary:var(--g-color-text-dark-complementary);--g-color-text-secondary:var(--g-color-text-dark-secondary);--g-color-text-hint:var(--g-color-text-dark-hint);--g-color-text-info:var(--g-color-private-blue-650-solid);--g-color-text-positive:var(--g-color-private-green-650-solid);--g-color-text-warning:var(--g-color-private-yellow-700-solid);--g-color-text-danger:var(--g-color-private-red-650-solid);--g-color-text-utility:var(--g-color-private-purple-650-solid);--g-color-text-misc:var(--g-color-private-cool-grey-650-solid);--g-color-text-info-heavy:var(--g-color-private-blue-900-solid);--g-color-text-positive-heavy:var(--g-color-private-green-900-solid);--g-color-text-warning-heavy:var(--g-color-private-orange-900-solid);--g-color-text-danger-heavy:var(--g-color-private-red-900-solid);--g-color-text-utility-heavy:var(--g-color-private-purple-900-solid);--g-color-text-misc-heavy:var(--g-color-private-cool-grey-900-solid);--g-color-text-brand:var(--g-color-private-yellow-700-solid);--g-color-text-brand-heavy:var(--g-color-private-orange-900-solid);--g-color-text-brand-contrast:var(--g-color-text-dark-primary);--g-color-text-link:var(--g-color-private-yellow-700-solid);--g-color-text-link-hover:var(--g-color-private-orange-700-solid);--g-color-text-link-visited:var(--g-color-private-purple-600-solid);--g-color-text-link-visited-hover:var(--g-color-private-purple-850-solid);--g-color-text-dark-primary:var(--g-color-private-black-1000-solid);--g-color-text-dark-complementary:var(--g-color-private-black-850);--g-color-text-dark-secondary:var(--g-color-private-black-700);--g-color-text-dark-hint:var(--g-color-private-black-500);--g-color-text-light-primary:var(--g-color-private-white-1000-solid);--g-color-text-light-complementary:var(--g-color-private-white-850);--g-color-text-light-secondary:var(--g-color-private-white-700);--g-color-text-light-hint:var(--g-color-private-white-500);--g-color-text-inverted-primary:var(--g-color-text-light-primary);--g-color-text-inverted-complementary:var(--g-color-text-light-complementary);--g-color-text-inverted-secondary:var(--g-color-text-light-secondary);--g-color-text-inverted-hint:var(--g-color-text-light-hint);--g-color-base-background:var(--g-color-private-white-1000-solid);--g-color-base-generic:var(--g-color-private-black-150);--g-color-base-generic-hover:var(--g-color-private-black-300);--g-color-base-generic-medium:var(--g-color-private-black-250);--g-color-base-generic-medium-hover:var(--g-color-private-black-350);--g-color-base-generic-accent:var(--g-color-private-black-250);--g-color-base-generic-accent-disabled:var(--g-color-private-black-150);--g-color-base-generic-ultralight:var(--g-color-private-black-50-solid);--g-color-base-simple-hover:var(--g-color-private-black-150);--g-color-base-simple-hover-solid:var(--g-color-private-black-150-solid);--g-color-base-brand:var(--g-color-private-yellow-550-solid);--g-color-base-brand-hover:var(--g-color-private-yellow-650-solid);--g-color-base-selection:var(--g-color-private-yellow-300);--g-color-base-selection-hover:var(--g-color-private-yellow-400);--g-color-base-info-light:var(--g-color-private-blue-250);--g-color-base-info-light-hover:var(--g-color-private-blue-350);--g-color-base-info-medium:var(--g-color-private-blue-400);--g-color-base-info-medium-hover:var(--g-color-private-blue-500);--g-color-base-info-heavy:var(--g-color-private-blue-700-solid);--g-color-base-info-heavy-hover:var(--g-color-private-blue-850-solid);--g-color-base-positive-light:var(--g-color-private-green-250);--g-color-base-positive-light-hover:var(--g-color-private-green-350);--g-color-base-positive-medium:var(--g-color-private-green-400);--g-color-base-positive-medium-hover:var(--g-color-private-green-500);--g-color-base-positive-heavy:var(--g-color-private-green-700-solid);--g-color-base-positive-heavy-hover:var(--g-color-private-green-800-solid);--g-color-base-warning-light:var(--g-color-private-yellow-300);--g-color-base-warning-light-hover:var(--g-color-private-yellow-400);--g-color-base-warning-medium:var(--g-color-private-yellow-400);--g-color-base-warning-medium-hover:var(--g-color-private-yellow-550-solid);--g-color-base-warning-heavy:var(--g-color-private-yellow-600-solid);--g-color-base-warning-heavy-hover:var(--g-color-private-yellow-700-solid);--g-color-base-danger-light:var(--g-color-private-red-250);--g-color-base-danger-light-hover:var(--g-color-private-red-350);--g-color-base-danger-medium:var(--g-color-private-red-400);--g-color-base-danger-medium-hover:var(--g-color-private-red-500);--g-color-base-danger-heavy:var(--g-color-private-red-700-solid);--g-color-base-danger-heavy-hover:var(--g-color-private-red-800-solid);--g-color-base-utility-light:var(--g-color-private-purple-250);--g-color-base-utility-light-hover:var(--g-color-private-purple-350);--g-color-base-utility-medium:var(--g-color-private-purple-400);--g-color-base-utility-medium-hover:var(--g-color-private-purple-500);--g-color-base-utility-heavy:var(--g-color-private-purple-700-solid);--g-color-base-utility-heavy-hover:var(--g-color-private-purple-800-solid);--g-color-base-neutral-light:var(--g-color-private-black-150);--g-color-base-neutral-light-hover:var(--g-color-private-black-250);--g-color-base-neutral-medium:var(--g-color-private-black-300);--g-color-base-neutral-medium-hover:var(--g-color-private-black-400);--g-color-base-neutral-heavy:var(--g-color-private-black-550);--g-color-base-neutral-heavy-hover:var(--g-color-private-black-650);--g-color-base-misc-light:var(--g-color-private-cool-grey-250);--g-color-base-misc-light-hover:var(--g-color-private-cool-grey-350);--g-color-base-misc-medium:var(--g-color-private-cool-grey-400);--g-color-base-misc-medium-hover:var(--g-color-private-cool-grey-500);--g-color-base-misc-heavy:var(--g-color-private-cool-grey-700-solid);--g-color-base-misc-heavy-hover:var(--g-color-private-cool-grey-800-solid);--g-color-base-light:var(--g-color-private-white-1000-solid);--g-color-base-light-hover:var(--g-color-private-white-850);--g-color-base-light-simple-hover:var(--g-color-private-white-300);--g-color-base-light-disabled:var(--g-color-private-white-150);--g-color-base-light-accent-disabled:var(--g-color-private-white-300);--g-color-base-float:var(--g-color-private-white-1000-solid);--g-color-base-float-hover:var(--g-color-private-black-150-solid);--g-color-base-float-medium:var(--g-color-private-black-550-solid);--g-color-base-float-heavy:var(--g-color-private-black-700-solid);--g-color-base-float-accent:var(--g-color-private-white-1000-solid);--g-color-base-float-accent-hover:var(--g-color-private-white-850);--g-color-base-float-announcement:var(--g-color-private-cool-grey-150-solid);--g-color-base-modal:var(--g-color-base-background);--g-color-line-generic:var(--g-color-private-black-200);--g-color-line-generic-hover:var(--g-color-private-black-400);--g-color-line-generic-active:var(--g-color-private-black-700);--g-color-line-generic-accent:var(--g-color-private-black-300);--g-color-line-generic-accent-hover:var(--g-color-private-black-700);--g-color-line-generic-solid:var(--g-color-private-black-200-solid);--g-color-line-brand:var(--g-color-private-yellow-600-solid);--g-color-line-focus:var(--g-color-private-cool-grey-450);--g-color-line-light:var(--g-color-private-white-500);--g-color-line-info:var(--g-color-private-blue-450);--g-color-line-positive:var(--g-color-private-green-450);--g-color-line-warning:var(--g-color-private-yellow-600-solid);--g-color-line-danger:var(--g-color-private-red-450);--g-color-line-utility:var(--g-color-private-purple-450);--g-color-line-misc:var(--g-color-private-cool-grey-450);--g-color-sfx-veil:var(--g-color-private-black-450);--g-color-sfx-shadow:var(--g-color-private-black-300);--g-color-sfx-shadow-heavy:var(--g-color-private-black-600);--g-color-sfx-shadow-light:var(--g-color-private-black-100);--g-color-sfx-fade:var(--g-color-private-white-300);--g-color-scroll-track:var(--g-color-base-background);--g-color-scroll-handle:var(--g-color-private-black-100);--g-color-scroll-handle-hover:var(--g-color-private-black-150);--g-color-scroll-corner:var(--g-color-private-black-100);--g-color-infographics-axis:var(--g-color-private-black-150-solid);--g-color-infographics-tooltip-bg:var(--g-color-private-white-950)}.g-root_theme_dark-hc{--g-color-private-white-50-solid:#1e1d1e;--g-color-private-white-70-solid:#232223;--g-color-private-white-100-solid:#2a292a;--g-color-private-white-150-solid:#363536;--g-color-private-white-200-solid:#414141;--g-color-private-white-250-solid:#4d4d4d;--g-color-private-white-300-solid:#595859;--g-color-private-white-350-solid:#656465;--g-color-private-white-400-solid:#717071;--g-color-private-white-450-solid:#7d7c7d;--g-color-private-white-500-solid:#888;--g-color-private-white-550-solid:#949494;--g-color-private-white-600-solid:#a0a0a0;--g-color-private-white-650-solid:#acacac;--g-color-private-white-700-solid:#b8b8b8;--g-color-private-white-750-solid:#c4c3c4;--g-color-private-white-800-solid:#d0cfd0;--g-color-private-white-850-solid:#d0cfd0;--g-color-private-white-900-solid:#e7e7e7;--g-color-private-white-950-solid:#f3f3f3;--g-color-private-blue-50:#3697f11a;--g-color-private-blue-100:#3697f126;--g-color-private-blue-150:#3697f133;--g-color-private-blue-200:#3697f14d;--g-color-private-blue-250:#3697f166;--g-color-private-blue-300:#3697f180;--g-color-private-blue-350:#3697f199;--g-color-private-blue-400:#3697f1b3;--g-color-private-blue-450:#3697f1cc;--g-color-private-blue-500:#3697f1e6;--g-color-private-blue-50-solid:#161e28;--g-color-private-blue-100-solid:#172533;--g-color-private-blue-150-solid:#192c3f;--g-color-private-blue-200-solid:#1d3955;--g-color-private-blue-250-solid:#20476b;--g-color-private-blue-300-solid:#245482;--g-color-private-blue-350-solid:#286198;--g-color-private-blue-400-solid:#2b6fae;--g-color-private-blue-450-solid:#2f7cc4;--g-color-private-blue-500-solid:#328adb;--g-color-private-blue-550-solid:#3697f1;--g-color-private-blue-600-solid:#4aa1f2;--g-color-private-blue-650-solid:#5eacf4;--g-color-private-blue-700-solid:#72b6f5;--g-color-private-blue-750-solid:#86c1f7;--g-color-private-blue-800-solid:#9bcbf8;--g-color-private-blue-850-solid:#afd5f9;--g-color-private-blue-900-solid:#c3e0fb;--g-color-private-blue-950-solid:#d7eafc;--g-color-private-blue-1000-solid:#e1effd;--g-color-private-green-50:#4db09b1a;--g-color-private-green-100:#4db09b26;--g-color-private-green-150:#4db09b33;--g-color-private-green-200:#4db09b4d;--g-color-private-green-250:#4db09b66;--g-color-private-green-300:#4db09b80;--g-color-private-green-350:#4db09b99;--g-color-private-green-400:#4db09bb3;--g-color-private-green-450:#4db09bcc;--g-color-private-green-500:#4db09be6;--g-color-private-green-50-solid:#182120;--g-color-private-green-100-solid:#1b2927;--g-color-private-green-150-solid:#1e312d;--g-color-private-green-200-solid:#24413b;--g-color-private-green-250-solid:#2a5149;--g-color-private-green-300-solid:#306157;--g-color-private-green-350-solid:#357064;--g-color-private-green-400-solid:#3b8072;--g-color-private-green-450-solid:#419080;--g-color-private-green-500-solid:#47a08d;--g-color-private-green-550-solid:#4db09b;--g-color-private-green-600-solid:#5fb8a5;--g-color-private-green-650-solid:#71c0af;--g-color-private-green-700-solid:#82c8b9;--g-color-private-green-750-solid:#94d0c3;--g-color-private-green-800-solid:#a6d8cd;--g-color-private-green-850-solid:#b8dfd7;--g-color-private-green-900-solid:#cae7e1;--g-color-private-green-950-solid:#dbefeb;--g-color-private-green-1000-solid:#e4f3f0;--g-color-private-yellow-50:#ffbe5c1a;--g-color-private-yellow-100:#ffbe5c26;--g-color-private-yellow-150:#ffbe5c33;--g-color-private-yellow-200:#ffbe5c4d;--g-color-private-yellow-250:#ffbe5c66;--g-color-private-yellow-300:#ffbe5c80;--g-color-private-yellow-350:#ffbe5c99;--g-color-private-yellow-400:#ffbe5cb3;--g-color-private-yellow-450:#ffbe5ccc;--g-color-private-yellow-500:#ffbe5ce6;--g-color-private-yellow-50-solid:#2a2219;--g-color-private-yellow-100-solid:#362b1d;--g-color-private-yellow-150-solid:#413421;--g-color-private-yellow-200-solid:#594528;--g-color-private-yellow-250-solid:#715630;--g-color-private-yellow-300-solid:#896837;--g-color-private-yellow-350-solid:#a0793e;--g-color-private-yellow-400-solid:#b88a46;--g-color-private-yellow-450-solid:#d09b4d;--g-color-private-yellow-500-solid:#e7ad55;--g-color-private-yellow-550-solid:#ffbe5c;--g-color-private-yellow-600-solid:#ffc56c;--g-color-private-yellow-650-solid:#ffcb7d;--g-color-private-yellow-700-solid:#ffd28d;--g-color-private-yellow-750-solid:#ffd89d;--g-color-private-yellow-800-solid:#ffdfae;--g-color-private-yellow-850-solid:#ffe5be;--g-color-private-yellow-900-solid:#ffecce;--g-color-private-yellow-950-solid:#fff2de;--g-color-private-yellow-1000-solid:#fff5e7;--g-color-private-orange-50-solid:#241911;--g-color-private-orange-100-solid:#2d1d11;--g-color-private-orange-150-solid:#362111;--g-color-private-orange-200-solid:#492a10;--g-color-private-orange-250-solid:#5b3210;--g-color-private-orange-300-solid:#6d3a0f;--g-color-private-orange-350-solid:#7f420e;--g-color-private-orange-400-solid:#914a0e;--g-color-private-orange-450-solid:#a4530d;--g-color-private-orange-500-solid:#b65b0d;--g-color-private-orange-700-solid:#d99255;--g-color-private-orange-800-solid:#e4b186;--g-color-private-red-50:#e5325d1a;--g-color-private-red-100:#e5325d26;--g-color-private-red-150:#e5325d33;--g-color-private-red-200:#e5325d4d;--g-color-private-red-250:#e5325d66;--g-color-private-red-300:#e5325d80;--g-color-private-red-350:#e5325d99;--g-color-private-red-400:#e5325db3;--g-color-private-red-450:#e5325dcc;--g-color-private-red-500:#e5325de6;--g-color-private-red-50-solid:#27141a;--g-color-private-red-100-solid:#32161d;--g-color-private-red-150-solid:#3c1821;--g-color-private-red-200-solid:#511b29;--g-color-private-red-250-solid:#661e30;--g-color-private-red-300-solid:#7c2238;--g-color-private-red-350-solid:#91253f;--g-color-private-red-400-solid:#a62847;--g-color-private-red-450-solid:#bb2b4e;--g-color-private-red-500-solid:#d02f56;--g-color-private-red-550-solid:#e5325d;--g-color-private-red-600-solid:#e8476d;--g-color-private-red-650-solid:#ea5b7d;--g-color-private-red-700-solid:#ed708e;--g-color-private-red-750-solid:#ef849e;--g-color-private-red-800-solid:#f299ae;--g-color-private-red-850-solid:#f5adbe;--g-color-private-red-900-solid:#f7c2ce;--g-color-private-red-950-solid:#fad6df;--g-color-private-red-1000-solid:#fbe0e7;--g-color-private-purple-50-solid:#1f1825;--g-color-private-purple-100-solid:#251b2e;--g-color-private-purple-150-solid:#2b1e37;--g-color-private-purple-200-solid:#38254a;--g-color-private-purple-250-solid:#442b5c;--g-color-private-purple-300-solid:#51326f;--g-color-private-purple-350-solid:#5d3882;--g-color-private-purple-400-solid:#6a3f94;--g-color-private-purple-450-solid:#7645a7;--g-color-private-purple-500-solid:#834cb9;--g-color-private-cool-grey-50-solid:#1a1c20;--g-color-private-cool-grey-100-solid:#1e2227;--g-color-private-cool-grey-150-solid:#22272e;--g-color-private-cool-grey-200-solid:#29323b;--g-color-private-cool-grey-250-solid:#313d49;--g-color-private-cool-grey-300-solid:#394957;--g-color-private-cool-grey-350-solid:#415465;--g-color-private-cool-grey-400-solid:#495f73;--g-color-private-cool-grey-450-solid:#506a80;--g-color-private-cool-grey-500-solid:#58758e;--g-color-private-cool-grey-750-solid:#a0b3c4;--g-color-private-cool-grey-800-solid:#b0c0ce;--g-color-text-primary:var(--g-color-text-light-primary);--g-color-text-complementary:var(--g-color-text-light-complementary);--g-color-text-secondary:var(--g-color-text-light-secondary);--g-color-text-hint:var(--g-color-text-light-hint);--g-color-text-info:var(--g-color-private-blue-650-solid);--g-color-text-positive:var(--g-color-private-green-650-solid);--g-color-text-warning:var(--g-color-private-yellow-650-solid);--g-color-text-danger:var(--g-color-private-red-650-solid);--g-color-text-utility:var(--g-color-private-purple-650-solid);--g-color-text-misc:var(--g-color-private-cool-grey-650-solid);--g-color-text-info-heavy:var(--g-color-private-blue-850-solid);--g-color-text-positive-heavy:var(--g-color-private-green-850-solid);--g-color-text-warning-heavy:var(--g-color-private-yellow-850-solid);--g-color-text-danger-heavy:var(--g-color-private-red-850-solid);--g-color-text-utility-heavy:var(--g-color-private-purple-850-solid);--g-color-text-misc-heavy:var(--g-color-private-cool-grey-850-solid);--g-color-text-brand:var(--g-color-private-yellow-600-solid);--g-color-text-brand-heavy:var(--g-color-private-yellow-700-solid);--g-color-text-brand-contrast:var(--g-color-text-dark-primary);--g-color-text-link:var(--g-color-private-yellow-550-solid);--g-color-text-link-hover:var(--g-color-private-orange-550-solid);--g-color-text-link-visited:var(--g-color-private-purple-650-solid);--g-color-text-link-visited-hover:var(--g-color-private-purple-800-solid);--g-color-text-dark-primary:var(--g-color-private-black-1000-solid);--g-color-text-dark-complementary:var(--g-color-private-black-800);--g-color-text-dark-secondary:var(--g-color-private-black-600);--g-color-text-dark-hint:var(--g-color-private-black-400);--g-color-text-light-primary:var(--g-color-private-white-1000-solid);--g-color-text-light-complementary:var(--g-color-private-white-800);--g-color-text-light-secondary:var(--g-color-private-white-600);--g-color-text-light-hint:var(--g-color-private-white-400);--g-color-text-inverted-primary:var(--g-color-text-dark-primary);--g-color-text-inverted-complementary:var(--g-color-text-dark-complementary);--g-color-text-inverted-secondary:var(--g-color-text-dark-secondary);--g-color-text-inverted-hint:var(--g-color-text-dark-hint);--g-color-base-background:#121112;--g-color-base-generic:var(--g-color-private-white-100);--g-color-base-generic-hover:var(--g-color-private-white-250);--g-color-base-generic-medium:var(--g-color-private-white-250);--g-color-base-generic-medium-hover:var(--g-color-private-white-400);--g-color-base-generic-accent:var(--g-color-private-white-200);--g-color-base-generic-accent-disabled:var(--g-color-private-white-150);--g-color-base-generic-ultralight:var(--g-color-private-white-50);--g-color-base-simple-hover:var(--g-color-private-white-250);--g-color-base-simple-hover-solid:var(--g-color-private-white-250-solid);--g-color-base-brand:var(--g-color-private-yellow-550-solid);--g-color-base-brand-hover:var(--g-color-private-yellow-700-solid);--g-color-base-selection:var(--g-color-private-yellow-250);--g-color-base-selection-hover:var(--g-color-private-yellow-400);--g-color-base-info-light:var(--g-color-private-blue-250);--g-color-base-info-light-hover:var(--g-color-private-blue-400);--g-color-base-info-medium:var(--g-color-private-blue-450);--g-color-base-info-medium-hover:var(--g-color-private-blue-600-solid);--g-color-base-info-heavy:var(--g-color-private-blue-700-solid);--g-color-base-info-heavy-hover:var(--g-color-private-blue-850-solid);--g-color-base-positive-light:var(--g-color-private-green-250);--g-color-base-positive-light-hover:var(--g-color-private-green-400);--g-color-base-positive-medium:var(--g-color-private-green-450);--g-color-base-positive-medium-hover:var(--g-color-private-green-600-solid);--g-color-base-positive-heavy:var(--g-color-private-green-700-solid);--g-color-base-positive-heavy-hover:var(--g-color-private-green-850-solid);--g-color-base-warning-light:var(--g-color-private-yellow-250);--g-color-base-warning-light-hover:var(--g-color-private-yellow-400);--g-color-base-warning-medium:var(--g-color-private-yellow-450);--g-color-base-warning-medium-hover:var(--g-color-private-yellow-600-solid);--g-color-base-warning-heavy:var(--g-color-private-yellow-700-solid);--g-color-base-warning-heavy-hover:var(--g-color-private-yellow-850-solid);--g-color-base-danger-light:var(--g-color-private-red-250);--g-color-base-danger-light-hover:var(--g-color-private-red-400);--g-color-base-danger-medium:var(--g-color-private-red-450);--g-color-base-danger-medium-hover:var(--g-color-private-red-600-solid);--g-color-base-danger-heavy:var(--g-color-private-red-700-solid);--g-color-base-danger-heavy-hover:var(--g-color-private-red-850-solid);--g-color-base-utility-light:var(--g-color-private-purple-250);--g-color-base-utility-light-hover:var(--g-color-private-purple-400);--g-color-base-utility-medium:var(--g-color-private-purple-450);--g-color-base-utility-medium-hover:var(--g-color-private-purple-600-solid);--g-color-base-utility-heavy:var(--g-color-private-purple-700-solid);--g-color-base-utility-heavy-hover:var(--g-color-private-purple-850-solid);--g-color-base-neutral-light:var(--g-color-private-white-200);--g-color-base-neutral-light-hover:var(--g-color-private-white-350);--g-color-base-neutral-medium:var(--g-color-private-white-400);--g-color-base-neutral-medium-hover:var(--g-color-private-white-550);--g-color-base-neutral-heavy:var(--g-color-private-white-650);--g-color-base-neutral-heavy-hover:var(--g-color-private-white-750);--g-color-base-misc-light:var(--g-color-private-cool-grey-250);--g-color-base-misc-light-hover:var(--g-color-private-cool-grey-400);--g-color-base-misc-medium:var(--g-color-private-cool-grey-450);--g-color-base-misc-medium-hover:var(--g-color-private-cool-grey-600-solid);--g-color-base-misc-heavy:var(--g-color-private-cool-grey-700-solid);--g-color-base-misc-heavy-hover:var(--g-color-private-cool-grey-850-solid);--g-color-base-light:var(--g-color-private-white-850);--g-color-base-light-hover:var(--g-color-private-white-700);--g-color-base-light-simple-hover:var(--g-color-private-white-150);--g-color-base-light-disabled:var(--g-color-private-white-150);--g-color-base-light-accent-disabled:var(--g-color-private-white-300);--g-color-base-float:var(--g-color-private-white-100-solid);--g-color-base-float-hover:var(--g-color-private-white-200-solid);--g-color-base-float-medium:var(--g-color-private-white-200-solid);--g-color-base-float-heavy:var(--g-color-private-white-300-solid);--g-color-base-float-accent:var(--g-color-private-white-300-solid);--g-color-base-float-accent-hover:var(--g-color-private-white-400-solid);--g-color-base-float-announcement:var(--g-color-private-white-200-solid);--g-color-base-modal:var(--g-color-base-background);--g-color-line-generic:var(--g-color-private-white-150);--g-color-line-generic-hover:var(--g-color-private-white-250);--g-color-line-generic-active:var(--g-color-private-white-600);--g-color-line-generic-accent:var(--g-color-private-white-350);--g-color-line-generic-accent-hover:var(--g-color-private-white-800);--g-color-line-generic-solid:var(--g-color-private-white-150-solid);--g-color-line-brand:var(--g-color-private-yellow-600-solid);--g-color-line-focus:var(--g-color-private-cool-grey-550-solid);--g-color-line-light:var(--g-color-private-white-500);--g-color-line-info:var(--g-color-private-blue-550-solid);--g-color-line-positive:var(--g-color-private-green-550-solid);--g-color-line-warning:var(--g-color-private-yellow-550-solid);--g-color-line-danger:var(--g-color-private-red-550-solid);--g-color-line-utility:var(--g-color-private-purple-550-solid);--g-color-line-misc:var(--g-color-private-cool-grey-550-solid);--g-color-sfx-veil:var(--g-color-private-black-700);--g-color-sfx-shadow:var(--g-color-private-black-200);--g-color-sfx-shadow-heavy:var(--g-color-private-black-400);--g-color-sfx-shadow-light:var(--g-color-private-black-200);--g-color-sfx-fade:var(--g-color-private-white-250);--g-color-scroll-track:var(--g-color-base-background);--g-color-scroll-handle:var(--g-color-private-white-150);--g-color-scroll-handle-hover:var(--g-color-private-white-250);--g-color-scroll-corner:var(--g-color-private-white-150);--g-color-infographics-axis:var(--g-color-private-white-150-solid);--g-color-infographics-tooltip-bg:var(--g-color-private-white-opaque-150)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar){scrollbar-color:var(--g-color-scroll-handle) var(--g-color-scroll-track);scrollbar-width:var(--g-scrollbar-width)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar{background:var(--g-color-scroll-track);height:var(--g-scrollbar-width);width:var(--g-scrollbar-width)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar-track,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar-track{background:var(--g-color-scroll-track)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar-corner,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar-corner{background:var(--g-color-scroll-corner)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar-thumb,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar-thumb{background:var(--g-color-scroll-handle)}.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar) ::-webkit-scrollbar-thumb:hover,.g-root:not(.g-root_mobile):not(.g-root_native-scrollbar)::-webkit-scrollbar-thumb:hover{background:var(--g-color-scroll-handle-hover)}@keyframes g-loading-animation{0%{background-position:-12px 0}to{background-position:0 0}}:root:has(body.g-root_theme_light),:root:has(body.g-root_theme_light-hc){color-scheme:light}:root:has(body.g-root_theme_dark),:root:has(body.g-root_theme_dark-hc){color-scheme:dark}@media(prefers-reduced-motion:reduce){*,:after,:before{animation-duration:.001ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.001ms!important}}.g-root{--g-text-header-font-weight:500;--g-text-subheader-font-weight:600;--g-text-display-font-weight:500;--g-text-accent-font-weight:500}.g-root_theme_light{--g-color-base-background:#fff;--g-color-base-brand:var(--g-color-private-blue-550-solid);--g-color-base-brand-hover:var(--g-color-private-blue-600-solid);--g-color-base-selection:var(--g-color-private-blue-100);--g-color-base-selection-hover:var(--g-color-private-blue-200);--g-color-line-brand:var(--g-color-private-blue-550-solid);--g-color-text-brand:var(--g-color-private-blue-600-solid);--g-color-text-brand-heavy:var(--g-color-private-blue-700-solid);--g-color-text-brand-contrast:var(--g-color-text-light-primary);--g-color-text-link:var(--g-color-private-blue-600-solid);--g-color-text-link-hover:var(--g-color-private-blue-800-solid);--g-color-private-white-50:#ffffff0d;--g-color-private-white-70:#ffffff12;--g-color-private-white-100:#ffffff1a;--g-color-private-white-150:#ffffff26;--g-color-private-white-200:#fff3;--g-color-private-white-250:#ffffff40;--g-color-private-white-300:#ffffff4d;--g-color-private-white-350:#ffffff59;--g-color-private-white-400:#fff6;--g-color-private-white-450:#ffffff73;--g-color-private-white-500:#ffffff80;--g-color-private-white-550:#ffffff8c;--g-color-private-white-600:#fff9;--g-color-private-white-650:#ffffffa6;--g-color-private-white-700:#ffffffb3;--g-color-private-white-750:#ffffffbf;--g-color-private-white-800:#fffc;--g-color-private-white-850:#ffffffd9;--g-color-private-white-900:#ffffffe6;--g-color-private-white-950:#fffffff2;--g-color-private-white-1000-solid:#fff;--g-color-private-black-50:#0000000d;--g-color-private-black-70:#00000012;--g-color-private-black-100:#0000001a;--g-color-private-black-150:#00000026;--g-color-private-black-200:#0003;--g-color-private-black-250:#00000040;--g-color-private-black-300:#0000004d;--g-color-private-black-350:#00000059;--g-color-private-black-400:#0006;--g-color-private-black-450:#00000073;--g-color-private-black-500:#00000080;--g-color-private-black-550:#0000008c;--g-color-private-black-600:#0009;--g-color-private-black-650:#000000a6;--g-color-private-black-700:#000000b3;--g-color-private-black-750:#000000bf;--g-color-private-black-800:#000c;--g-color-private-black-850:#000000d9;--g-color-private-black-900:#000000e6;--g-color-private-black-950:#000000f2;--g-color-private-black-20-solid:#fafafa;--g-color-private-black-50-solid:#f2f2f2;--g-color-private-black-100-solid:#e5e5e5;--g-color-private-black-150-solid:#d9d9d9;--g-color-private-black-200-solid:#ccc;--g-color-private-black-250-solid:#bfbfbf;--g-color-private-black-300-solid:#b3b3b3;--g-color-private-black-350-solid:#a6a6a6;--g-color-private-black-400-solid:#999;--g-color-private-black-450-solid:#8c8c8c;--g-color-private-black-500-solid:grey;--g-color-private-black-550-solid:#737373;--g-color-private-black-600-solid:#666;--g-color-private-black-650-solid:#595959;--g-color-private-black-700-solid:#4c4c4c;--g-color-private-black-750-solid:#404040;--g-color-private-black-800-solid:#333;--g-color-private-black-850-solid:#262626;--g-color-private-black-900-solid:#1a1a1a;--g-color-private-black-950-solid:#0d0d0d;--g-color-private-black-1000-solid:#000;--g-color-private-blue-50:#5282ff1a;--g-color-private-blue-100:#5282ff26;--g-color-private-blue-150:#5282ff33;--g-color-private-blue-200:#5282ff4d;--g-color-private-blue-250:#5282ff66;--g-color-private-blue-300:#5282ff80;--g-color-private-blue-350:#5282ff99;--g-color-private-blue-400:#5282ffb3;--g-color-private-blue-450:#5282ffcc;--g-color-private-blue-500:#5282ffe6;--g-color-private-blue-50-solid:#eef3ff;--g-color-private-blue-100-solid:#e5ecff;--g-color-private-blue-150-solid:#dce6ff;--g-color-private-blue-200-solid:#cbdaff;--g-color-private-blue-250-solid:#bacdff;--g-color-private-blue-300-solid:#a8c1ff;--g-color-private-blue-350-solid:#97b4ff;--g-color-private-blue-400-solid:#86a8ff;--g-color-private-blue-450-solid:#749bff;--g-color-private-blue-500-solid:#638fff;--g-color-private-blue-550-solid:#5282ff;--g-color-private-blue-600-solid:#4e79eb;--g-color-private-blue-650-solid:#4a71d6;--g-color-private-blue-700-solid:#4768c2;--g-color-private-blue-750-solid:#4360ad;--g-color-private-blue-800-solid:#3f5799;--g-color-private-blue-850-solid:#3c4f85;--g-color-private-blue-900-solid:#384670;--g-color-private-blue-950-solid:#343d5c;--g-color-private-blue-1000-solid:#333952;--g-color-private-green-50:#3bc9351a;--g-color-private-green-100:#3bc93526;--g-color-private-green-150:#3bc93533;--g-color-private-green-200:#3bc9354d;--g-color-private-green-250:#3bc93566;--g-color-private-green-300:#3bc93580;--g-color-private-green-350:#3bc93599;--g-color-private-green-400:#3bc935b3;--g-color-private-green-450:#3bc935cc;--g-color-private-green-500:#3bc935e6;--g-color-private-green-50-solid:#ebfaeb;--g-color-private-green-100-solid:#e2f7e1;--g-color-private-green-150-solid:#d8f4d7;--g-color-private-green-200-solid:#c4efc2;--g-color-private-green-250-solid:#b1e9ae;--g-color-private-green-300-solid:#9de49a;--g-color-private-green-350-solid:#89df86;--g-color-private-green-400-solid:#76d972;--g-color-private-green-450-solid:#62d45d;--g-color-private-green-500-solid:#4fce49;--g-color-private-green-550-solid:#3bc935;--g-color-private-green-600-solid:#3ab935;--g-color-private-green-650-solid:#38aa35;--g-color-private-green-700-solid:#379a34;--g-color-private-green-750-solid:#358a34;--g-color-private-green-800-solid:#347b34;--g-color-private-green-850-solid:#336b34;--g-color-private-green-900-solid:#315b34;--g-color-private-green-950-solid:#304b33;--g-color-private-green-1000-solid:#2f4433;--g-color-private-yellow-50:#ffdb4d1a;--g-color-private-yellow-100:#ffdb4d26;--g-color-private-yellow-150:#ffdb4d33;--g-color-private-yellow-200:#ffdb4d4d;--g-color-private-yellow-250:#ffdb4d66;--g-color-private-yellow-300:#ffdb4d80;--g-color-private-yellow-350:#ffdb4d99;--g-color-private-yellow-400:#ffdb4db3;--g-color-private-yellow-450:#ffdb4dcc;--g-color-private-yellow-500:#ffdb4de6;--g-color-private-yellow-50-solid:#fffbed;--g-color-private-yellow-100-solid:#fffae4;--g-color-private-yellow-150-solid:#fff8db;--g-color-private-yellow-200-solid:#fff4ca;--g-color-private-yellow-250-solid:#fff1b8;--g-color-private-yellow-300-solid:#ffeda6;--g-color-private-yellow-350-solid:#ffe994;--g-color-private-yellow-400-solid:#ffe682;--g-color-private-yellow-450-solid:#ffe271;--g-color-private-yellow-500-solid:#ffdf5f;--g-color-private-yellow-550-solid:#ffdb4d;--g-color-private-yellow-600-solid:#eac94a;--g-color-private-yellow-650-solid:#d5b848;--g-color-private-yellow-700-solid:#c0a645;--g-color-private-yellow-750-solid:#ab9543;--g-color-private-yellow-800-solid:#968340;--g-color-private-yellow-850-solid:#81723d;--g-color-private-yellow-900-solid:#6c603b;--g-color-private-yellow-950-solid:#574f38;--g-color-private-yellow-1000-solid:#4d4637;--g-color-private-orange-50:#ff77001a;--g-color-private-orange-100:#ff770026;--g-color-private-orange-150:#f703;--g-color-private-orange-200:#ff77004d;--g-color-private-orange-250:#f706;--g-color-private-orange-300:#ff770080;--g-color-private-orange-350:#f709;--g-color-private-orange-400:#ff7700b3;--g-color-private-orange-450:#f70c;--g-color-private-orange-500:#ff7700e6;--g-color-private-orange-50-solid:#fff1e6;--g-color-private-orange-100-solid:#ffebd9;--g-color-private-orange-150-solid:#ffe4cc;--g-color-private-orange-200-solid:#ffd6b3;--g-color-private-orange-250-solid:#ffc999;--g-color-private-orange-300-solid:#ffbb80;--g-color-private-orange-350-solid:#ffad66;--g-color-private-orange-400-solid:#ffa04c;--g-color-private-orange-450-solid:#ff9233;--g-color-private-orange-500-solid:#ff851a;--g-color-private-orange-550-solid:#f70;--g-color-private-orange-600-solid:#ea7005;--g-color-private-orange-650-solid:#d5680a;--g-color-private-orange-700-solid:#c0600f;--g-color-private-orange-750-solid:#ab5914;--g-color-private-orange-800-solid:#965119;--g-color-private-orange-850-solid:#814a1f;--g-color-private-orange-900-solid:#6c4324;--g-color-private-orange-950-solid:#573b29;--g-color-private-orange-1000-solid:#4d372b;--g-color-private-red-50:#ff04001a;--g-color-private-red-100:#ff040026;--g-color-private-red-150:#ff040033;--g-color-private-red-200:#ff04004d;--g-color-private-red-250:#ff040066;--g-color-private-red-300:#ff040080;--g-color-private-red-350:#ff040099;--g-color-private-red-400:#ff0400b3;--g-color-private-red-450:#ff0400cc;--g-color-private-red-500:#ff0400e6;--g-color-private-red-50-solid:#ffe6e6;--g-color-private-red-100-solid:#ffd9d9;--g-color-private-red-150-solid:#ffcdcc;--g-color-private-red-200-solid:#ffb4b3;--g-color-private-red-250-solid:#ff9b99;--g-color-private-red-300-solid:#ff8280;--g-color-private-red-350-solid:#ff6966;--g-color-private-red-400-solid:#ff504c;--g-color-private-red-450-solid:#ff3733;--g-color-private-red-500-solid:#ff1e1a;--g-color-private-red-550-solid:#ff0400;--g-color-private-red-600-solid:#ea0805;--g-color-private-red-650-solid:#d50c0a;--g-color-private-red-700-solid:#c0100f;--g-color-private-red-750-solid:#ab1414;--g-color-private-red-800-solid:#961819;--g-color-private-red-850-solid:#811c1f;--g-color-private-red-900-solid:#6c2024;--g-color-private-red-950-solid:#572429;--g-color-private-red-1000-solid:#4d262b;--g-color-private-purple-50:#8f52cc1a;--g-color-private-purple-100:#8f52cc26;--g-color-private-purple-150:#8f52cc33;--g-color-private-purple-200:#8f52cc4d;--g-color-private-purple-250:#8f52cc66;--g-color-private-purple-300:#8f52cc80;--g-color-private-purple-350:#8f52cc99;--g-color-private-purple-400:#8f52ccb3;--g-color-private-purple-450:#8f52cccc;--g-color-private-purple-500:#8f52cce6;--g-color-private-purple-50-solid:#f4eefa;--g-color-private-purple-100-solid:#eee5f7;--g-color-private-purple-150-solid:#e9dcf5;--g-color-private-purple-200-solid:#ddcbf0;--g-color-private-purple-250-solid:#d2baeb;--g-color-private-purple-300-solid:#c7a9e6;--g-color-private-purple-350-solid:#bc97e0;--g-color-private-purple-400-solid:#b186db;--g-color-private-purple-450-solid:#a575d6;--g-color-private-purple-500-solid:#9a63d1;--g-color-private-purple-550-solid:#8f52cc;--g-color-private-purple-600-solid:#854ebd;--g-color-private-purple-650-solid:#7b4aad;--g-color-private-purple-700-solid:#72479e;--g-color-private-purple-750-solid:#68438f;--g-color-private-purple-800-solid:#5e3f80;--g-color-private-purple-850-solid:#543b70;--g-color-private-purple-900-solid:#4a3761;--g-color-private-purple-950-solid:#413452;--g-color-private-purple-1000-solid:#3c324a;--g-color-private-cool-grey-50:#6b84991a;--g-color-private-cool-grey-100:#6b849926;--g-color-private-cool-grey-150:#6b849933;--g-color-private-cool-grey-200:#6b84994d;--g-color-private-cool-grey-250:#6b849966;--g-color-private-cool-grey-300:#6b849980;--g-color-private-cool-grey-350:#6b849999;--g-color-private-cool-grey-400:#6b8499b3;--g-color-private-cool-grey-450:#6b8499cc;--g-color-private-cool-grey-500:#6b8499e6;--g-color-private-cool-grey-50-solid:#f0f3f5;--g-color-private-cool-grey-100-solid:#e9edf0;--g-color-private-cool-grey-150-solid:#e1e6eb;--g-color-private-cool-grey-200-solid:#d3dae0;--g-color-private-cool-grey-250-solid:#c4ced6;--g-color-private-cool-grey-300-solid:#b5c1cc;--g-color-private-cool-grey-350-solid:#a6b5c2;--g-color-private-cool-grey-400-solid:#97a9b8;--g-color-private-cool-grey-450-solid:#899dad;--g-color-private-cool-grey-500-solid:#7a90a3;--g-color-private-cool-grey-550-solid:#6b8499;--g-color-private-cool-grey-600-solid:#657b8f;--g-color-private-cool-grey-650-solid:#5f7285;--g-color-private-cool-grey-700-solid:#586a7a;--g-color-private-cool-grey-750-solid:#526170;--g-color-private-cool-grey-800-solid:#4c5866;--g-color-private-cool-grey-850-solid:#464f5c;--g-color-private-cool-grey-900-solid:#404652;--g-color-private-cool-grey-950-solid:#393e47;--g-color-private-cool-grey-1000-solid:#363942}.g-root_theme_light-hc{--g-color-base-background:#fff;--g-color-base-brand:var(--g-color-private-blue-600-solid);--g-color-base-brand-hover:var(--g-color-private-blue-800-solid);--g-color-base-selection:var(--g-color-private-blue-250);--g-color-base-selection-hover:var(--g-color-private-blue-350);--g-color-line-brand:var(--g-color-private-blue-600-solid);--g-color-text-brand:var(--g-color-private-blue-650-solid);--g-color-text-brand-heavy:var(--g-color-private-blue-900-solid);--g-color-text-brand-contrast:var(--g-color-text-light-primary);--g-color-text-link:var(--g-color-private-blue-650-solid);--g-color-text-link-hover:var(--g-color-private-blue-850-solid);--g-color-private-white-50:#ffffff0d;--g-color-private-white-70:#ffffff12;--g-color-private-white-100:#ffffff1a;--g-color-private-white-150:#ffffff26;--g-color-private-white-200:#fff3;--g-color-private-white-250:#ffffff40;--g-color-private-white-300:#ffffff4d;--g-color-private-white-350:#ffffff59;--g-color-private-white-400:#fff6;--g-color-private-white-450:#ffffff73;--g-color-private-white-500:#ffffff80;--g-color-private-white-550:#ffffff8c;--g-color-private-white-600:#fff9;--g-color-private-white-650:#ffffffa6;--g-color-private-white-700:#ffffffb3;--g-color-private-white-750:#ffffffbf;--g-color-private-white-800:#fffc;--g-color-private-white-850:#ffffffd9;--g-color-private-white-900:#ffffffe6;--g-color-private-white-950:#fffffff2;--g-color-private-white-1000-solid:#fff;--g-color-private-black-50:#0000000d;--g-color-private-black-100:#0000001a;--g-color-private-black-150:#00000026;--g-color-private-black-200:#0003;--g-color-private-black-250:#00000040;--g-color-private-black-300:#0000004d;--g-color-private-black-350:#00000059;--g-color-private-black-400:#0006;--g-color-private-black-450:#00000073;--g-color-private-black-500:#00000080;--g-color-private-black-550:#0000008c;--g-color-private-black-600:#0009;--g-color-private-black-650:#000000a6;--g-color-private-black-700:#000000b3;--g-color-private-black-750:#000000bf;--g-color-private-black-800:#000c;--g-color-private-black-850:#000000d9;--g-color-private-black-900:#000000e6;--g-color-private-black-950:#000000f2;--g-color-private-black-50-solid:#f2f2f2;--g-color-private-black-100-solid:#e5e5e5;--g-color-private-black-150-solid:#d9d9d9;--g-color-private-black-200-solid:#ccc;--g-color-private-black-250-solid:#bfbfbf;--g-color-private-black-300-solid:#b3b3b3;--g-color-private-black-350-solid:#a6a6a6;--g-color-private-black-400-solid:#999;--g-color-private-black-450-solid:#8c8c8c;--g-color-private-black-500-solid:grey;--g-color-private-black-550-solid:#737373;--g-color-private-black-600-solid:#666;--g-color-private-black-650-solid:#595959;--g-color-private-black-700-solid:#4c4c4c;--g-color-private-black-750-solid:#404040;--g-color-private-black-800-solid:#333;--g-color-private-black-850-solid:#262626;--g-color-private-black-900-solid:#1a1a1a;--g-color-private-black-950-solid:#0d0d0d;--g-color-private-black-1000-solid:#000;--g-color-private-blue-50:#5282ff1a;--g-color-private-blue-100:#5282ff26;--g-color-private-blue-150:#5282ff33;--g-color-private-blue-200:#5282ff4d;--g-color-private-blue-250:#5282ff66;--g-color-private-blue-300:#5282ff80;--g-color-private-blue-350:#5282ff99;--g-color-private-blue-400:#5282ffb3;--g-color-private-blue-450:#5282ffcc;--g-color-private-blue-500:#5282ffe6;--g-color-private-blue-50-solid:#eef3ff;--g-color-private-blue-100-solid:#e5ecff;--g-color-private-blue-150-solid:#dce6ff;--g-color-private-blue-200-solid:#cbdaff;--g-color-private-blue-250-solid:#bacdff;--g-color-private-blue-300-solid:#a8c1ff;--g-color-private-blue-350-solid:#97b4ff;--g-color-private-blue-400-solid:#86a8ff;--g-color-private-blue-450-solid:#749bff;--g-color-private-blue-500-solid:#638fff;--g-color-private-blue-550-solid:#5282ff;--g-color-private-blue-600-solid:#4d79e9;--g-color-private-blue-650-solid:#486fd4;--g-color-private-blue-700-solid:#4366be;--g-color-private-blue-750-solid:#3f5ca8;--g-color-private-blue-800-solid:#3a5393;--g-color-private-blue-850-solid:#35497d;--g-color-private-blue-900-solid:#304067;--g-color-private-blue-950-solid:#2c3651;--g-color-private-blue-1000-solid:#293147;--g-color-private-green-50:#3bc9351a;--g-color-private-green-100:#3bc93526;--g-color-private-green-150:#3bc93533;--g-color-private-green-200:#3bc9354d;--g-color-private-green-250:#3bc93566;--g-color-private-green-300:#3bc93580;--g-color-private-green-350:#3bc93599;--g-color-private-green-400:#3bc935b3;--g-color-private-green-450:#3bc935cc;--g-color-private-green-500:#3bc935e6;--g-color-private-green-50-solid:#ebfaeb;--g-color-private-green-100-solid:#e2f7e1;--g-color-private-green-150-solid:#d8f4d7;--g-color-private-green-200-solid:#c4efc2;--g-color-private-green-250-solid:#b1e9ae;--g-color-private-green-300-solid:#9de49a;--g-color-private-green-350-solid:#89df86;--g-color-private-green-400-solid:#76d972;--g-color-private-green-450-solid:#62d45d;--g-color-private-green-500-solid:#4fce49;--g-color-private-green-550-solid:#3bc935;--g-color-private-green-600-solid:#38b833;--g-color-private-green-650-solid:#36a832;--g-color-private-green-700-solid:#339730;--g-color-private-green-750-solid:#31872f;--g-color-private-green-800-solid:#2f762e;--g-color-private-green-850-solid:#2c652c;--g-color-private-green-900-solid:#29552b;--g-color-private-green-950-solid:#274429;--g-color-private-green-1000-solid:#263c28;--g-color-private-yellow-50:#ffdb4d1a;--g-color-private-yellow-100:#ffdb4d26;--g-color-private-yellow-150:#ffdb4d33;--g-color-private-yellow-200:#ffdb4d4d;--g-color-private-yellow-250:#ffdb4d66;--g-color-private-yellow-300:#ffdb4d80;--g-color-private-yellow-350:#ffdb4d99;--g-color-private-yellow-400:#ffdb4db3;--g-color-private-yellow-450:#ffdb4dcc;--g-color-private-yellow-500:#ffdb4de6;--g-color-private-yellow-50-solid:#fffbed;--g-color-private-yellow-100-solid:#fffae4;--g-color-private-yellow-150-solid:#fff8db;--g-color-private-yellow-200-solid:#fff4ca;--g-color-private-yellow-250-solid:#fff1b8;--g-color-private-yellow-300-solid:#ffeda6;--g-color-private-yellow-350-solid:#ffe994;--g-color-private-yellow-400-solid:#ffe682;--g-color-private-yellow-450-solid:#ffe271;--g-color-private-yellow-500-solid:#ffdf5f;--g-color-private-yellow-550-solid:#ffdb4d;--g-color-private-yellow-600-solid:#e9c949;--g-color-private-yellow-650-solid:#d3b645;--g-color-private-yellow-700-solid:#bda441;--g-color-private-yellow-750-solid:#a7913d;--g-color-private-yellow-800-solid:#907f3a;--g-color-private-yellow-850-solid:#7a6d36;--g-color-private-yellow-900-solid:#645a32;--g-color-private-yellow-950-solid:#4e482e;--g-color-private-yellow-1000-solid:#433f2c;--g-color-private-orange-50:#ff77001a;--g-color-private-orange-100:#ff770026;--g-color-private-orange-150:#f703;--g-color-private-orange-200:#ff77004d;--g-color-private-orange-250:#f706;--g-color-private-orange-300:#ff770080;--g-color-private-orange-350:#f709;--g-color-private-orange-400:#ff7700b3;--g-color-private-orange-450:#f70c;--g-color-private-orange-500:#ff7700e6;--g-color-private-orange-50-solid:#fff1e6;--g-color-private-orange-100-solid:#ffebd9;--g-color-private-orange-150-solid:#ffe4cc;--g-color-private-orange-200-solid:#ffd6b3;--g-color-private-orange-250-solid:#ffc999;--g-color-private-orange-300-solid:#ffbb80;--g-color-private-orange-350-solid:#ffad66;--g-color-private-orange-400-solid:#ffa04c;--g-color-private-orange-450-solid:#ff9233;--g-color-private-orange-500-solid:#ff851a;--g-color-private-orange-550-solid:#f70;--g-color-private-orange-600-solid:#e96f04;--g-color-private-orange-650-solid:#d36608;--g-color-private-orange-700-solid:#bd5e0b;--g-color-private-orange-750-solid:#a7550f;--g-color-private-orange-800-solid:#904d13;--g-color-private-orange-850-solid:#7a4517;--g-color-private-orange-900-solid:#643c1b;--g-color-private-orange-950-solid:#4e341e;--g-color-private-orange-1000-solid:#433020;--g-color-private-red-50:#ff04001a;--g-color-private-red-100:#ff040026;--g-color-private-red-150:#ff040033;--g-color-private-red-200:#ff04004d;--g-color-private-red-250:#ff040066;--g-color-private-red-300:#ff040080;--g-color-private-red-350:#ff040099;--g-color-private-red-400:#ff0400b3;--g-color-private-red-450:#ff0400cc;--g-color-private-red-500:#ff0400e6;--g-color-private-red-50-solid:#ffe6e6;--g-color-private-red-100-solid:#ffd9d9;--g-color-private-red-150-solid:#ffcdcc;--g-color-private-red-200-solid:#ffb4b3;--g-color-private-red-250-solid:#ff9b99;--g-color-private-red-300-solid:#ff8280;--g-color-private-red-350-solid:#ff6966;--g-color-private-red-400-solid:#ff504c;--g-color-private-red-450-solid:#ff3733;--g-color-private-red-500-solid:#ff1e1a;--g-color-private-red-550-solid:#ff0400;--g-color-private-red-600-solid:#e90804;--g-color-private-red-650-solid:#d30b08;--g-color-private-red-700-solid:#bd0e0b;--g-color-private-red-750-solid:#a6110f;--g-color-private-red-800-solid:#901413;--g-color-private-red-850-solid:#7a1717;--g-color-private-red-900-solid:#641a1b;--g-color-private-red-950-solid:#4e1d1e;--g-color-private-red-1000-solid:#431e20;--g-color-private-purple-50:#8f52cc1a;--g-color-private-purple-100:#8f52cc26;--g-color-private-purple-150:#8f52cc33;--g-color-private-purple-200:#8f52cc4d;--g-color-private-purple-250:#8f52cc66;--g-color-private-purple-300:#8f52cc80;--g-color-private-purple-350:#8f52cc99;--g-color-private-purple-400:#8f52ccb3;--g-color-private-purple-450:#8f52cccc;--g-color-private-purple-500:#8f52cce6;--g-color-private-purple-50-solid:#f4eefa;--g-color-private-purple-100-solid:#eee5f7;--g-color-private-purple-150-solid:#e9dcf5;--g-color-private-purple-200-solid:#ddcbf0;--g-color-private-purple-250-solid:#d2baeb;--g-color-private-purple-300-solid:#c7a9e6;--g-color-private-purple-350-solid:#bc97e0;--g-color-private-purple-400-solid:#b186db;--g-color-private-purple-450-solid:#a575d6;--g-color-private-purple-500-solid:#9a63d1;--g-color-private-purple-550-solid:#8f52cc;--g-color-private-purple-600-solid:#844dbb;--g-color-private-purple-650-solid:#7949ab;--g-color-private-purple-700-solid:#6e449a;--g-color-private-purple-750-solid:#633f8a;--g-color-private-purple-800-solid:#593b79;--g-color-private-purple-850-solid:#4e3668;--g-color-private-purple-900-solid:#433158;--g-color-private-purple-950-solid:#382c47;--g-color-private-purple-1000-solid:#322a3f;--g-color-private-cool-grey-50:#6b84991a;--g-color-private-cool-grey-100:#6b849926;--g-color-private-cool-grey-150:#6b849933;--g-color-private-cool-grey-200:#6b84994d;--g-color-private-cool-grey-250:#6b849966;--g-color-private-cool-grey-300:#6b849980;--g-color-private-cool-grey-350:#6b849999;--g-color-private-cool-grey-400:#6b8499b3;--g-color-private-cool-grey-450:#6b8499cc;--g-color-private-cool-grey-500:#6b8499e6;--g-color-private-cool-grey-50-solid:#f0f3f5;--g-color-private-cool-grey-100-solid:#e9edf0;--g-color-private-cool-grey-150-solid:#e1e6eb;--g-color-private-cool-grey-200-solid:#d3dae0;--g-color-private-cool-grey-250-solid:#c4ced6;--g-color-private-cool-grey-300-solid:#b5c1cc;--g-color-private-cool-grey-350-solid:#a6b5c2;--g-color-private-cool-grey-400-solid:#97a9b8;--g-color-private-cool-grey-450-solid:#899dad;--g-color-private-cool-grey-500-solid:#7a90a3;--g-color-private-cool-grey-550-solid:#6b8499;--g-color-private-cool-grey-600-solid:#647a8e;--g-color-private-cool-grey-650-solid:#5c7182;--g-color-private-cool-grey-700-solid:#556776;--g-color-private-cool-grey-750-solid:#4e5d6b;--g-color-private-cool-grey-800-solid:#465360;--g-color-private-cool-grey-850-solid:#3f4a54;--g-color-private-cool-grey-900-solid:#384049;--g-color-private-cool-grey-950-solid:#31363d;--g-color-private-cool-grey-1000-solid:#2d3237}.g-root_theme_dark{--g-color-base-background:#2d2c33;--g-color-base-brand:var(--g-color-private-blue-450-solid);--g-color-base-brand-hover:var(--g-color-private-blue-600-solid);--g-color-base-selection:var(--g-color-private-blue-150);--g-color-base-selection-hover:var(--g-color-private-blue-200);--g-color-line-brand:var(--g-color-private-blue-550-solid);--g-color-text-brand:var(--g-color-private-blue-550-solid);--g-color-text-brand-heavy:var(--g-color-private-blue-600-solid);--g-color-text-brand-contrast:var(--g-color-text-light-primary);--g-color-text-link:var(--g-color-private-blue-550-solid);--g-color-text-link-hover:var(--g-color-private-blue-700-solid);--g-color-private-white-20:#ffffff05;--g-color-private-white-50:#ffffff0d;--g-color-private-white-70:#ffffff12;--g-color-private-white-100:#ffffff1a;--g-color-private-white-150:#ffffff26;--g-color-private-white-200:#fff3;--g-color-private-white-250:#ffffff40;--g-color-private-white-300:#ffffff4d;--g-color-private-white-350:#ffffff59;--g-color-private-white-400:#fff6;--g-color-private-white-450:#ffffff73;--g-color-private-white-500:#ffffff80;--g-color-private-white-550:#ffffff8c;--g-color-private-white-600:#fff9;--g-color-private-white-650:#ffffffa6;--g-color-private-white-700:#ffffffb3;--g-color-private-white-750:#ffffffbf;--g-color-private-white-800:#fffc;--g-color-private-white-850:#ffffffd9;--g-color-private-white-900:#ffffffe6;--g-color-private-white-950:#fffffff2;--g-color-private-white-20-solid:#313037;--g-color-private-white-50-solid:#38373d;--g-color-private-white-70-solid:#3c3b41;--g-color-private-white-100-solid:#424147;--g-color-private-white-150-solid:#4d4c52;--g-color-private-white-200-solid:#57565c;--g-color-private-white-250-solid:#616166;--g-color-private-white-300-solid:#6c6b70;--g-color-private-white-350-solid:#77767a;--g-color-private-white-400-solid:#818085;--g-color-private-white-450-solid:#8b8b8f;--g-color-private-white-500-solid:#969699;--g-color-private-white-550-solid:#a0a0a3;--g-color-private-white-600-solid:#ababad;--g-color-private-white-650-solid:#b6b5b8;--g-color-private-white-700-solid:#c0c0c2;--g-color-private-white-750-solid:#cacacc;--g-color-private-white-800-solid:#d5d5d6;--g-color-private-white-850-solid:#dfdfe0;--g-color-private-white-900-solid:#eaeaeb;--g-color-private-white-950-solid:#f5f5f5;--g-color-private-white-1000-solid:#fff;--g-color-private-white-opaque-150:#4c4b51f2;--g-color-private-black-20:#00000005;--g-color-private-black-50:#0000000d;--g-color-private-black-100:#0000001a;--g-color-private-black-150:#00000026;--g-color-private-black-200:#0003;--g-color-private-black-250:#00000040;--g-color-private-black-300:#0000004d;--g-color-private-black-350:#00000059;--g-color-private-black-400:#0006;--g-color-private-black-450:#00000073;--g-color-private-black-500:#00000080;--g-color-private-black-550:#0000008c;--g-color-private-black-600:#0009;--g-color-private-black-650:#000000a6;--g-color-private-black-700:#000000b3;--g-color-private-black-750:#000000bf;--g-color-private-black-800:#000c;--g-color-private-black-850:#000000d9;--g-color-private-black-900:#000000e6;--g-color-private-black-950:#000000f2;--g-color-private-black-1000-solid:#000;--g-color-private-black-rock-850:#2d2c33;--g-color-private-blue-50:#5282ff1a;--g-color-private-blue-100:#5282ff26;--g-color-private-blue-150:#5282ff33;--g-color-private-blue-200:#5282ff4d;--g-color-private-blue-250:#5282ff66;--g-color-private-blue-300:#5282ff80;--g-color-private-blue-350:#5282ff99;--g-color-private-blue-400:#5282ffb3;--g-color-private-blue-450:#5282ffcc;--g-color-private-blue-500:#5282ffe6;--g-color-private-blue-50-solid:#313547;--g-color-private-blue-100-solid:#333952;--g-color-private-blue-150-solid:#343d5c;--g-color-private-blue-200-solid:#384670;--g-color-private-blue-250-solid:#3c4e85;--g-color-private-blue-300-solid:#405799;--g-color-private-blue-350-solid:#4360ad;--g-color-private-blue-400-solid:#4768c2;--g-color-private-blue-450-solid:#4b71d6;--g-color-private-blue-500-solid:#4e79eb;--g-color-private-blue-550-solid:#5282ff;--g-color-private-blue-600-solid:#638fff;--g-color-private-blue-650-solid:#759bff;--g-color-private-blue-700-solid:#86a8ff;--g-color-private-blue-750-solid:#97b4ff;--g-color-private-blue-800-solid:#a9c1ff;--g-color-private-blue-850-solid:#bacdff;--g-color-private-blue-900-solid:#cbdaff;--g-color-private-blue-950-solid:#dce6ff;--g-color-private-blue-1000-solid:#e5ecff;--g-color-private-green-50:#5bb5571a;--g-color-private-green-100:#5bb55726;--g-color-private-green-150:#5bb55733;--g-color-private-green-200:#5bb5574d;--g-color-private-green-250:#5bb55766;--g-color-private-green-300:#5bb55780;--g-color-private-green-350:#5bb55799;--g-color-private-green-400:#5bb557b3;--g-color-private-green-450:#5bb557cc;--g-color-private-green-500:#5bb557e6;--g-color-private-green-50-solid:#323a37;--g-color-private-green-100-solid:#344138;--g-color-private-green-150-solid:#36473a;--g-color-private-green-200-solid:#3b553e;--g-color-private-green-250-solid:#3f6341;--g-color-private-green-300-solid:#447145;--g-color-private-green-350-solid:#497e49;--g-color-private-green-400-solid:#4d8c4c;--g-color-private-green-450-solid:#529a50;--g-color-private-green-500-solid:#56a753;--g-color-private-green-550-solid:#5bb557;--g-color-private-green-600-solid:#6bbc68;--g-color-private-green-650-solid:#7cc479;--g-color-private-green-700-solid:#8ccb89;--g-color-private-green-750-solid:#9dd39a;--g-color-private-green-800-solid:#addaab;--g-color-private-green-850-solid:#bde1bc;--g-color-private-green-900-solid:#cee9cd;--g-color-private-green-950-solid:#def0dd;--g-color-private-green-1000-solid:#e6f4e6;--g-color-private-yellow-50:#ffcb001a;--g-color-private-yellow-100:#ffcb0026;--g-color-private-yellow-150:#ffcb0033;--g-color-private-yellow-200:#ffcb004d;--g-color-private-yellow-250:#ffcb0066;--g-color-private-yellow-300:#ffcb0080;--g-color-private-yellow-350:#ffcb0099;--g-color-private-yellow-400:#ffcb00b3;--g-color-private-yellow-450:#ffcb00cc;--g-color-private-yellow-500:#ffcb00e6;--g-color-private-yellow-50-solid:#423c2e;--g-color-private-yellow-100-solid:#4d442b;--g-color-private-yellow-150-solid:#574c29;--g-color-private-yellow-200-solid:#6c5c24;--g-color-private-yellow-250-solid:#816c1f;--g-color-private-yellow-300-solid:#967c19;--g-color-private-yellow-350-solid:#ab8c14;--g-color-private-yellow-400-solid:#c09b0f;--g-color-private-yellow-450-solid:#d5ab0a;--g-color-private-yellow-500-solid:#e9ba04;--g-color-private-yellow-550-solid:#ffcb00;--g-color-private-yellow-600-solid:#ffd01a;--g-color-private-yellow-650-solid:#ffd533;--g-color-private-yellow-700-solid:#ffdb4c;--g-color-private-yellow-750-solid:#ffe066;--g-color-private-yellow-800-solid:#ffe580;--g-color-private-yellow-850-solid:#ffea99;--g-color-private-yellow-900-solid:#ffefb3;--g-color-private-yellow-950-solid:#fff5cc;--g-color-private-yellow-1000-solid:#fff7d9;--g-color-private-orange-50:#c8630c1a;--g-color-private-orange-100:#c8630c26;--g-color-private-orange-150:#c8630c33;--g-color-private-orange-200:#c8630c4d;--g-color-private-orange-250:#c8630c66;--g-color-private-orange-300:#c8630c80;--g-color-private-orange-350:#c8630c99;--g-color-private-orange-400:#c8630cb3;--g-color-private-orange-450:#c8630ccc;--g-color-private-orange-500:#c8630ce6;--g-color-private-orange-50-solid:#3d322f;--g-color-private-orange-100-solid:#44342d;--g-color-private-orange-150-solid:#4c372b;--g-color-private-orange-200-solid:#5c3d27;--g-color-private-orange-250-solid:#6b4223;--g-color-private-orange-300-solid:#7b4720;--g-color-private-orange-350-solid:#8a4d1c;--g-color-private-orange-400-solid:#995218;--g-color-private-orange-450-solid:#a95814;--g-color-private-orange-500-solid:#b95e10;--g-color-private-orange-550-solid:#c8630c;--g-color-private-orange-600-solid:#ce7324;--g-color-private-orange-650-solid:#d3823d;--g-color-private-orange-700-solid:#d89255;--g-color-private-orange-750-solid:#dea16d;--g-color-private-orange-800-solid:#e3b185;--g-color-private-orange-850-solid:#e9c19e;--g-color-private-orange-900-solid:#efd0b6;--g-color-private-orange-950-solid:#f4e0ce;--g-color-private-orange-1000-solid:#f7e8db;--g-color-private-red-50:#e849451a;--g-color-private-red-100:#e8494526;--g-color-private-red-150:#e8494533;--g-color-private-red-200:#e849454d;--g-color-private-red-250:#e8494566;--g-color-private-red-300:#e8494580;--g-color-private-red-350:#e8494599;--g-color-private-red-400:#e84945b3;--g-color-private-red-450:#e84945cc;--g-color-private-red-500:#e84945e6;--g-color-private-red-50-solid:#402f35;--g-color-private-red-100-solid:#493036;--g-color-private-red-150-solid:#523237;--g-color-private-red-200-solid:#653539;--g-color-private-red-250-solid:#78383a;--g-color-private-red-300-solid:#8a3a3c;--g-color-private-red-350-solid:#9d3d3e;--g-color-private-red-400-solid:#b04040;--g-color-private-red-450-solid:#c34341;--g-color-private-red-500-solid:#d54644;--g-color-private-red-550-solid:#e84945;--g-color-private-red-600-solid:#ea5b58;--g-color-private-red-650-solid:#ec6d6b;--g-color-private-red-700-solid:#ef7f7d;--g-color-private-red-750-solid:#f19290;--g-color-private-red-800-solid:#f3a4a2;--g-color-private-red-850-solid:#f6b6b5;--g-color-private-red-900-solid:#f8c8c7;--g-color-private-red-950-solid:#fadbda;--g-color-private-red-1000-solid:#fce4e3;--g-color-private-purple-50:#8f52cc1a;--g-color-private-purple-100:#8f52cc26;--g-color-private-purple-150:#8f52cc33;--g-color-private-purple-200:#8f52cc4d;--g-color-private-purple-250:#8f52cc66;--g-color-private-purple-300:#8f52cc80;--g-color-private-purple-350:#8f52cc99;--g-color-private-purple-400:#8f52ccb3;--g-color-private-purple-450:#8f52cccc;--g-color-private-purple-500:#8f52cce6;--g-color-private-purple-50-solid:#373042;--g-color-private-purple-100-solid:#3c324a;--g-color-private-purple-150-solid:#413452;--g-color-private-purple-200-solid:#4a3761;--g-color-private-purple-250-solid:#543b70;--g-color-private-purple-300-solid:#5e3f80;--g-color-private-purple-350-solid:#68438f;--g-color-private-purple-400-solid:#72479e;--g-color-private-purple-450-solid:#7b4aad;--g-color-private-purple-500-solid:#854ebd;--g-color-private-purple-550-solid:#8f52cc;--g-color-private-purple-600-solid:#9a63d1;--g-color-private-purple-650-solid:#a575d6;--g-color-private-purple-700-solid:#b186db;--g-color-private-purple-750-solid:#bc97e0;--g-color-private-purple-800-solid:#c7a9e6;--g-color-private-purple-850-solid:#d2baeb;--g-color-private-purple-900-solid:#ddcbf0;--g-color-private-purple-950-solid:#e9dcf5;--g-color-private-purple-1000-solid:#eee5f7;--g-color-private-cool-grey-50:#60809c1a;--g-color-private-cool-grey-100:#60809c26;--g-color-private-cool-grey-150:#60809c33;--g-color-private-cool-grey-200:#60809c4d;--g-color-private-cool-grey-250:#60809c66;--g-color-private-cool-grey-300:#60809c80;--g-color-private-cool-grey-350:#60809c99;--g-color-private-cool-grey-400:#60809cb3;--g-color-private-cool-grey-450:#60809ccc;--g-color-private-cool-grey-500:#60809ce6;--g-color-private-cool-grey-50-solid:#32343e;--g-color-private-cool-grey-100-solid:#353943;--g-color-private-cool-grey-150-solid:#373d48;--g-color-private-cool-grey-200-solid:#3c4552;--g-color-private-cool-grey-250-solid:#414e5d;--g-color-private-cool-grey-300-solid:#465667;--g-color-private-cool-grey-350-solid:#4c5e72;--g-color-private-cool-grey-400-solid:#51677d;--g-color-private-cool-grey-450-solid:#566f87;--g-color-private-cool-grey-500-solid:#5b7892;--g-color-private-cool-grey-550-solid:#60809c;--g-color-private-cool-grey-600-solid:#708da6;--g-color-private-cool-grey-650-solid:#8099b0;--g-color-private-cool-grey-700-solid:#90a6ba;--g-color-private-cool-grey-750-solid:#a0b3c3;--g-color-private-cool-grey-800-solid:#b0bfcd;--g-color-private-cool-grey-850-solid:#bfccd7;--g-color-private-cool-grey-900-solid:#cfd9e1;--g-color-private-cool-grey-950-solid:#dfe6eb;--g-color-private-cool-grey-1000-solid:#e7ecf0}.g-root_theme_dark-hc{--g-color-base-background:#222326;--g-color-base-brand:var(--g-color-private-blue-450-solid);--g-color-base-brand-hover:var(--g-color-private-blue-650-solid);--g-color-base-selection:var(--g-color-private-blue-250);--g-color-base-selection-hover:var(--g-color-private-blue-400);--g-color-line-brand:var(--g-color-private-blue-550-solid);--g-color-text-brand:var(--g-color-private-blue-650-solid);--g-color-text-brand-heavy:var(--g-color-private-blue-850-solid);--g-color-text-brand-contrast:var(--g-color-text-light-primary);--g-color-text-link:var(--g-color-private-blue-650-solid);--g-color-text-link-hover:var(--g-color-private-blue-800-solid);--g-color-private-white-50:#ffffff0d;--g-color-private-white-70:#ffffff12;--g-color-private-white-100:#ffffff1a;--g-color-private-white-150:#ffffff26;--g-color-private-white-200:#fff3;--g-color-private-white-250:#ffffff40;--g-color-private-white-300:#ffffff4d;--g-color-private-white-350:#ffffff59;--g-color-private-white-400:#fff6;--g-color-private-white-450:#ffffff73;--g-color-private-white-500:#ffffff80;--g-color-private-white-550:#ffffff8c;--g-color-private-white-600:#fff9;--g-color-private-white-650:#ffffffa6;--g-color-private-white-700:#ffffffb3;--g-color-private-white-750:#ffffffbf;--g-color-private-white-800:#fffc;--g-color-private-white-850:#ffffffd9;--g-color-private-white-900:#ffffffe6;--g-color-private-white-950:#fffffff2;--g-color-private-white-50-solid:#2d2e31;--g-color-private-white-100-solid:#38393c;--g-color-private-white-150-solid:#434447;--g-color-private-white-200-solid:#4e4f51;--g-color-private-white-250-solid:#595a5c;--g-color-private-white-300-solid:#646567;--g-color-private-white-350-solid:#6f7072;--g-color-private-white-400-solid:#7a7b7d;--g-color-private-white-450-solid:#858688;--g-color-private-white-500-solid:#909193;--g-color-private-white-550-solid:#9c9c9d;--g-color-private-white-600-solid:#a7a7a8;--g-color-private-white-650-solid:#b2b2b3;--g-color-private-white-700-solid:#bdbdbe;--g-color-private-white-750-solid:#c8c8c9;--g-color-private-white-800-solid:#d3d3d4;--g-color-private-white-850-solid:#dededf;--g-color-private-white-900-solid:#e9e9e9;--g-color-private-white-950-solid:#f4f4f4;--g-color-private-white-1000-solid:#fff;--g-color-private-white-opaque-150:#38393cf7;--g-color-private-black-20:#00000005;--g-color-private-black-50:#0000000d;--g-color-private-black-100:#0000001a;--g-color-private-black-150:#00000026;--g-color-private-black-200:#0003;--g-color-private-black-250:#00000040;--g-color-private-black-300:#0000004d;--g-color-private-black-350:#00000059;--g-color-private-black-400:#0006;--g-color-private-black-450:#00000073;--g-color-private-black-500:#00000080;--g-color-private-black-550:#0000008c;--g-color-private-black-600:#0009;--g-color-private-black-650:#000000a6;--g-color-private-black-700:#000000b3;--g-color-private-black-750:#000000bf;--g-color-private-black-800:#000c;--g-color-private-black-850:#000000d9;--g-color-private-black-900:#000000e6;--g-color-private-black-950:#000000f2;--g-color-private-black-1000-solid:#000;--g-color-private-black-rock-850:#2d2c33;--g-color-private-black-rock-950:#222326;--g-color-private-blue-50:#5282ff1a;--g-color-private-blue-100:#5282ff26;--g-color-private-blue-150:#5282ff33;--g-color-private-blue-200:#5282ff4d;--g-color-private-blue-250:#5282ff66;--g-color-private-blue-300:#5282ff80;--g-color-private-blue-350:#5282ff99;--g-color-private-blue-400:#5282ffb3;--g-color-private-blue-450:#5282ffcc;--g-color-private-blue-500:#5282ffe6;--g-color-private-blue-50-solid:#272d3c;--g-color-private-blue-100-solid:#293147;--g-color-private-blue-150-solid:#2c3651;--g-color-private-blue-200-solid:#304067;--g-color-private-blue-250-solid:#35497d;--g-color-private-blue-300-solid:#3a5393;--g-color-private-blue-350-solid:#3f5ca8;--g-color-private-blue-400-solid:#4466be;--g-color-private-blue-450-solid:#486fd4;--g-color-private-blue-500-solid:#4d79e9;--g-color-private-blue-550-solid:#5282ff;--g-color-private-blue-600-solid:#638fff;--g-color-private-blue-650-solid:#759bff;--g-color-private-blue-700-solid:#86a8ff;--g-color-private-blue-750-solid:#97b4ff;--g-color-private-blue-800-solid:#a9c1ff;--g-color-private-blue-850-solid:#bacdff;--g-color-private-blue-900-solid:#cbdaff;--g-color-private-blue-950-solid:#dce6ff;--g-color-private-blue-1000-solid:#e5ecff;--g-color-private-green-50:#5bb5571a;--g-color-private-green-100:#5bb55726;--g-color-private-green-150:#000;--g-color-private-green-200:#5bb5574d;--g-color-private-green-250:#5bb55766;--g-color-private-green-300:#5bb55780;--g-color-private-green-350:#5bb55799;--g-color-private-green-400:#5bb557b3;--g-color-private-green-450:#5bb557cc;--g-color-private-green-500:#5bb557e6;--g-color-private-green-50-solid:#28322b;--g-color-private-green-100-solid:#2b392d;--g-color-private-green-150-solid:#2d4030;--g-color-private-green-200-solid:#334f35;--g-color-private-green-250-solid:#395d3a;--g-color-private-green-300-solid:#3f6c3f;--g-color-private-green-350-solid:#447b43;--g-color-private-green-400-solid:#4a8948;--g-color-private-green-450-solid:#50984d;--g-color-private-green-500-solid:#55a652;--g-color-private-green-550-solid:#5bb557;--g-color-private-green-600-solid:#6bbc68;--g-color-private-green-650-solid:#7cc479;--g-color-private-green-700-solid:#8ccb89;--g-color-private-green-750-solid:#9dd39a;--g-color-private-green-800-solid:#addaab;--g-color-private-green-850-solid:#bde1bc;--g-color-private-green-900-solid:#cee9cd;--g-color-private-green-950-solid:#def0dd;--g-color-private-green-1000-solid:#e6f4e6;--g-color-private-yellow-50:#ffcb001a;--g-color-private-yellow-100:#ffcb0026;--g-color-private-yellow-150:#ffcb0033;--g-color-private-yellow-200:#ffcb004d;--g-color-private-yellow-250:#ffcb0066;--g-color-private-yellow-300:#ffcb0080;--g-color-private-yellow-350:#ffcb0099;--g-color-private-yellow-400:#ffcb00b3;--g-color-private-yellow-450:#ffcb00cc;--g-color-private-yellow-500:#ffcb00e6;--g-color-private-yellow-50-solid:#383422;--g-color-private-yellow-100-solid:#433c20;--g-color-private-yellow-150-solid:#4e451e;--g-color-private-yellow-200-solid:#64551b;--g-color-private-yellow-250-solid:#7a6617;--g-color-private-yellow-300-solid:#907713;--g-color-private-yellow-350-solid:#a7880f;--g-color-private-yellow-400-solid:#bd990b;--g-color-private-yellow-450-solid:#d3a908;--g-color-private-yellow-500-solid:#e9ba04;--g-color-private-yellow-550-solid:#ffcb00;--g-color-private-yellow-600-solid:#ffd01a;--g-color-private-yellow-650-solid:#ffd533;--g-color-private-yellow-700-solid:#ffdb4c;--g-color-private-yellow-750-solid:#ffe066;--g-color-private-yellow-800-solid:#ffe580;--g-color-private-yellow-850-solid:#ffea99;--g-color-private-yellow-900-solid:#ffefb3;--g-color-private-yellow-950-solid:#fff5cc;--g-color-private-yellow-1000-solid:#fff7d9;--g-color-private-orange-50:#c8630c1a;--g-color-private-orange-100:#c8630c26;--g-color-private-orange-150:#c8630c33;--g-color-private-orange-200:#c8630c4d;--g-color-private-orange-250:#c8630c66;--g-color-private-orange-300:#c8630c80;--g-color-private-orange-350:#c8630c99;--g-color-private-orange-400:#c8630cb3;--g-color-private-orange-450:#c8630ccc;--g-color-private-orange-500:#c8630ce6;--g-color-private-orange-50-solid:#332923;--g-color-private-orange-100-solid:#3b2d22;--g-color-private-orange-150-solid:#433021;--g-color-private-orange-200-solid:#54361e;--g-color-private-orange-250-solid:#643d1c;--g-color-private-orange-300-solid:#754319;--g-color-private-orange-350-solid:#864916;--g-color-private-orange-400-solid:#965014;--g-color-private-orange-450-solid:#a75611;--g-color-private-orange-500-solid:#b75d0f;--g-color-private-orange-550-solid:#c8630c;--g-color-private-orange-600-solid:#ce7324;--g-color-private-orange-650-solid:#d3823d;--g-color-private-orange-700-solid:#d89255;--g-color-private-orange-750-solid:#dea16d;--g-color-private-orange-800-solid:#e3b185;--g-color-private-orange-850-solid:#e9c19e;--g-color-private-orange-900-solid:#efd0b6;--g-color-private-orange-950-solid:#f4e0ce;--g-color-private-orange-1000-solid:#f7e8db;--g-color-private-red-50:#e849451a;--g-color-private-red-100:#e8494526;--g-color-private-red-150:#e8494533;--g-color-private-red-200:#e849454d;--g-color-private-red-250:#e8494566;--g-color-private-red-300:#e8494580;--g-color-private-red-350:#e8494599;--g-color-private-red-400:#e84945b3;--g-color-private-red-450:#e84945cc;--g-color-private-red-500:#e84945e6;--g-color-private-red-50-solid:#362729;--g-color-private-red-100-solid:#40292b;--g-color-private-red-150-solid:#4a2b2c;--g-color-private-red-200-solid:#5d2e2f;--g-color-private-red-250-solid:#713233;--g-color-private-red-300-solid:#853636;--g-color-private-red-350-solid:#993a39;--g-color-private-red-400-solid:#ac3d3c;--g-color-private-red-450-solid:#c0413f;--g-color-private-red-500-solid:#d44542;--g-color-private-red-550-solid:#e84945;--g-color-private-red-600-solid:#ea5b58;--g-color-private-red-650-solid:#ec6d6b;--g-color-private-red-700-solid:#ef7f7d;--g-color-private-red-750-solid:#f19290;--g-color-private-red-800-solid:#f3a4a2;--g-color-private-red-850-solid:#f6b6b5;--g-color-private-red-900-solid:#f8c8c7;--g-color-private-red-950-solid:#fadbda;--g-color-private-red-1000-solid:#fce4e3;--g-color-private-purple-50:#8f52cc1a;--g-color-private-purple-100:#8f52cc26;--g-color-private-purple-150:#8f52cc33;--g-color-private-purple-200:#8f52cc4d;--g-color-private-purple-250:#8f52cc66;--g-color-private-purple-300:#8f52cc80;--g-color-private-purple-350:#8f52cc99;--g-color-private-purple-400:#8f52ccb3;--g-color-private-purple-450:#8f52cccc;--g-color-private-purple-500:#8f52cce6;--g-color-private-purple-50-solid:#2d2837;--g-color-private-purple-100-solid:#322a3f;--g-color-private-purple-150-solid:#382c47;--g-color-private-purple-200-solid:#433158;--g-color-private-purple-250-solid:#4e3668;--g-color-private-purple-300-solid:#593b79;--g-color-private-purple-350-solid:#633f8a;--g-color-private-purple-400-solid:#6e449a;--g-color-private-purple-450-solid:#7949ab;--g-color-private-purple-500-solid:#844dbb;--g-color-private-purple-550-solid:#8f52cc;--g-color-private-purple-600-solid:#9a63d1;--g-color-private-purple-650-solid:#a575d6;--g-color-private-purple-700-solid:#b186db;--g-color-private-purple-750-solid:#bc97e0;--g-color-private-purple-800-solid:#c7a9e6;--g-color-private-purple-850-solid:#d2baeb;--g-color-private-purple-900-solid:#ddcbf0;--g-color-private-purple-950-solid:#e9dcf5;--g-color-private-purple-1000-solid:#eee5f7;--g-color-private-cool-grey-50:#60809c1a;--g-color-private-cool-grey-100:#60809c26;--g-color-private-cool-grey-150:#60809c33;--g-color-private-cool-grey-200:#60809c4d;--g-color-private-cool-grey-250:#60809c66;--g-color-private-cool-grey-300:#60809c80;--g-color-private-cool-grey-350:#60809c99;--g-color-private-cool-grey-400:#60809cb3;--g-color-private-cool-grey-450:#60809ccc;--g-color-private-cool-grey-500:#60809ce6;--g-color-private-cool-grey-50-solid:#282c32;--g-color-private-cool-grey-100-solid:#2b3138;--g-color-private-cool-grey-150-solid:#2e363e;--g-color-private-cool-grey-200-solid:#353f49;--g-color-private-cool-grey-250-solid:#3b4855;--g-color-private-cool-grey-300-solid:#415161;--g-color-private-cool-grey-350-solid:#475b6d;--g-color-private-cool-grey-400-solid:#4d6479;--g-color-private-cool-grey-450-solid:#546d84;--g-color-private-cool-grey-500-solid:#5a7790;--g-color-private-cool-grey-550-solid:#60809c;--g-color-private-cool-grey-600-solid:#708da6;--g-color-private-cool-grey-650-solid:#8099b0;--g-color-private-cool-grey-700-solid:#90a6ba;--g-color-private-cool-grey-750-solid:#a0b3c3;--g-color-private-cool-grey-800-solid:#b0bfcd;--g-color-private-cool-grey-850-solid:#bfccd7;--g-color-private-cool-grey-900-solid:#cfd9e1;--g-color-private-cool-grey-950-solid:#dfe6eb;--g-color-private-cool-grey-1000-solid:#e7ecf0}.unipika{--color-unipika-default:#a9a9a9;--color-unipika-string:#594c4c;--color-unipika-key:#d36b6b;--color-unipika-null:#594c4c;--color-unipika-int:#0095ff;--color-unipika-uint:#c200ff;--color-unipika-float:#ff00b9;--color-unipika-bool:#00ba0a;--color-unipika-date:#693;--color-unipika-interval:#399;--color-unipika-escape-text:#c7254e;--color-unipika-escape-back:#ffeff3;--color-unipika-binary-back:#fcf8e3;--color-unipika-binary-after:#888;--color-unipika-uuid:#c63;--color-unipika-tag-url:#04b;--color-unipika-tag-url-hover:#c00;color:var(--color-unipika-default);overflow-wrap:break-word;white-space:pre-wrap;word-break:normal}.unipika .pg_category_e,.unipika .pg_category_i,.unipika .pg_category_s,.unipika .string,.unipika .yql_string,.unipika .yql_utf8{color:var(--color-unipika-string)}.unipika .key,.unipika .special-key{color:var(--color-unipika-key)}.unipika .special-key{font-style:italic}.unipika .null,.unipika .yql_null{color:var(--color-unipika-null)}.unipika .null{font-style:italic}.unipika .yql_null{text-transform:uppercase}.unipika .int64,.unipika .number,.unipika .pg_category_n,.unipika .yql_int16,.unipika .yql_int32,.unipika .yql_int64,.unipika .yql_int8{color:var(--color-unipika-int)}.unipika .pg_category_a,.unipika .uint64,.unipika .yql_uint16,.unipika .yql_uint32,.unipika .yql_uint64,.unipika .yql_uint8{color:var(--color-unipika-uint)}.unipika .double,.unipika .pg_category_c,.unipika .yql_decimal,.unipika .yql_double,.unipika .yql_float{color:var(--color-unipika-float)}.unipika .boolean,.unipika .pg_category_b,.unipika .yql_bool,.unipika .yql_enum{color:var(--color-unipika-bool)}.unipika .pg_category_d,.unipika .yql_date,.unipika .yql_date32,.unipika .yql_datetime,.unipika .yql_datetime64,.unipika .yql_timestamp,.unipika .yql_timestamp64,.unipika .yql_tzdate,.unipika .yql_tzdate32,.unipika .yql_tzdatetime,.unipika .yql_tzdatetime64,.unipika .yql_tztimestamp,.unipika .yql_tztimestamp64{color:var(--color-unipika-date)}.unipika .pg_category_t,.unipika .yql_interval,.unipika .yql_interval64{color:var(--color-unipika-interval)}.unipika .yql_tagged.tag_image{vertical-align:top}.unipika .escape{background-color:var(--color-unipika-escape-back);color:var(--color-unipika-escape-text)}.unipika .quote{color:var(--color-unipika-default)}.unipika .binary,.unipika .incomplete,.unipika .pg_category_v{background-color:var(--color-unipika-binary-back)}.unipika .binary:after,.unipika .incomplete:after{color:var(--color-unipika-binary-after);padding-inline-start:.8em}.unipika .incomplete:after{content:"[truncated]";white-space:nowrap}.unipika .binary:after{content:"[binary]";white-space:nowrap}.unipika .incomplete.binary:after{content:"[truncated][binary]";white-space:nowrap}.unipika .pg_category_g,.unipika .yql_uuid{color:var(--color-unipika-uuid)}.unipika .pg_category_g.binary,.unipika .pg_category_g.incomplete,.unipika .yql_uuid.binary,.unipika .yql_uuid.incomplete{background:none}.unipika .pg_category_g.binary:after,.unipika .pg_category_g.incomplete:after,.unipika .yql_uuid.binary:after,.unipika .yql_uuid.incomplete:after{content:"";display:none}.unipika .tag_url{color:var(--color-unipika-tag-url);text-decoration:none}.unipika .tag_url:hover{color:var(--color-unipika-tag-url-hover)}.unipika-wrapper_inline_yes .unipika{display:inline-block}.g-root .unipika{font-family:var(--g-font-family-monospace)}.g-root .unipika-wrapper .g-root .unipika{border:0;margin:0;padding:0}.g-root_theme_dark .unipika,.g-root_theme_dark-hc .unipika{--color-unipika-default:#707070;--color-unipika-string:#9a8e8e;--color-unipika-key:#d36b6b;--color-unipika-null:#9a8e8e;--color-unipika-int:#0095ff;--color-unipika-uint:#c200ff;--color-unipika-float:#ff00b9;--color-unipika-bool:#00ba0a;--color-unipika-date:#693;--color-unipika-interval:#399;--color-unipika-escape-text:#c7254e;--color-unipika-escape-back:#292e1f;--color-unipika-binary-back:#292e1f;--color-unipika-binary-after:#666;--color-unipika-uuid:#c63;--color-unipika-tag-url:#47b;--color-unipika-tag-url-hover:#6af}.g-root_theme_light,.g-root_theme_light-hc{--gil-color-object-base:var(--g-color-private-yellow-550-solid);--gil-color-object-accent-heavy:var(--g-color-private-orange-650-solid);--gil-color-object-hightlight:var(--g-color-private-yellow-350-solid);--gil-color-shadow-over-object:var(--g-color-private-yellow-650-solid);--gil-color-background-lines:var(--g-color-private-black-450-solid);--gil-color-background-shapes:var(--g-color-private-black-50-solid);--gil-color-object-accent-light:var(--g-color-private-white-1000-solid);--gil-color-object-danger:var(--g-color-private-red-550-solid)}.g-root_theme_dark,.g-root_theme_dark-hc{--gil-color-object-base:var(--g-color-private-yellow-550-solid);--gil-color-object-accent-heavy:var(--g-color-private-orange-650-solid);--gil-color-object-hightlight:var(--g-color-private-yellow-700-solid);--gil-color-shadow-over-object:var(--g-color-private-yellow-500-solid);--gil-color-background-lines:var(--g-color-private-white-550-solid);--gil-color-background-shapes:var(--g-color-private-white-200-solid);--gil-color-object-accent-light:var(--g-color-private-white-1000-solid);--gil-color-object-danger:var(--g-color-private-red-550-solid)}.g-root_theme_dark,.g-root_theme_dark-hc,.g-root_theme_light,.g-root_theme_light-hc{--gil-color-object-base:var(--g-color-private-blue-450-solid);--gil-color-object-accent-heavy:var(--g-color-private-blue-850-solid);--gil-color-object-hightlight:var(--g-color-private-blue-350-solid);--gil-color-shadow-over-object:var(--g-color-private-blue-650-solid)}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace} \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/17893.97279c58.chunk.js b/ydb/core/viewer/monitoring/static/js/17893.97279c58.chunk.js new file mode 100644 index 000000000000..ac0755469ce6 --- /dev/null +++ b/ydb/core/viewer/monitoring/static/js/17893.97279c58.chunk.js @@ -0,0 +1 @@ +(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[17893],{2680:(e,t,n)=>{var a=n(43665),l=n(81061),s=n(28293),r=n(19305);e.exports=function(e,t){return function(n,i){var c=r(n)?a:l,o=t?t():{};return c(n,e,s(i,2),o)}}},6170:(e,t,n)=>{"use strict";n.d(t,{B:()=>o});var a=n(59284),l=n(73633),s=n(84375),r=n(99991);const i=(0,n(98192).om)("help-popover"),c=16;function o(e){var t;return a.createElement(s.A,Object.assign({},e,{className:i(null,e.className)}),a.createElement("button",Object.assign({ref:e.buttonRef,type:"button"},e.buttonProps,{className:i("button",null===(t=e.buttonProps)||void 0===t?void 0:t.className)}),a.createElement(r.I,{data:l.A,size:c})))}},18143:(e,t,n)=>{"use strict";n.d(t,{k:()=>d});var a=n(59284);const l=(0,n(69220).om)("progress");function s(e){const{text:t,offset:n=0}=e;return t?a.createElement("div",{className:l("text-inner"),style:{transform:`translateX(calc(var(--g-flow-direction) * ${-n}%))`}},t):null}function r({item:e}){const{value:t,color:n,className:s,theme:r,title:i,content:c,loading:o}=e,m={loading:o};return"undefined"===typeof n&&(m.theme=r||"default"),Number.isFinite(t)?a.createElement("div",{className:l("item",m,s),style:{width:`${t}%`,backgroundColor:n},title:i},c):null}function i(e){return e<100?e-100:0}function c(e){const{theme:t,colorStops:n,colorStopsValue:a,value:l}=e;if(n){const e=n.find(((e,t)=>{const s="number"===typeof a?a:l,r=t>1?n[t-1].stop:0,i=t=r&&s<=i}));return e?e.theme:t}return t}function o(e){const{stack:t,stackClassName:n,value:c,text:o}=e,m=i(c||function(e){return e.reduce(((e,{value:t})=>e+t),0)}(t));return a.createElement("div",{className:l("stack",n),style:{transform:`translateX(calc(var(--g-flow-direction) * ${m}%))`}},a.createElement("div",{className:l("item"),style:{width:-m+"%"}}),t.map(((e,t)=>a.createElement(r,{key:t,item:e}))),a.createElement(s,{offset:m,text:o}))}function m(e){const{value:t,loading:n,text:r}=e,o=i(t);return Number.isFinite(t)?a.createElement("div",{className:l("item",{theme:c(e),loading:n}),style:{transform:`translateX(calc(var(--g-flow-direction) * ${o}%))`}},a.createElement(s,{offset:o,text:r})):null}const d=a.forwardRef((function(e,t){const{text:n="",theme:s="default",size:r="m",loading:i=!1,className:c,qa:d}=e,u=Object.assign(Object.assign({},e),{text:n,theme:s,size:r,loading:i});return a.createElement("div",{ref:t,className:l({size:r},c),"data-qa":d},a.createElement("div",{className:l("text")},n),function(e){return void 0!==e.stack}(u)?a.createElement(o,Object.assign({},u)):a.createElement(m,Object.assign({},u)))}))},18677:(e,t,n)=>{"use strict";n.d(t,{A:()=>l});var a=n(59284);const l=e=>a.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),a.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14M6.53 5.47a.75.75 0 0 0-1.06 1.06L6.94 8 5.47 9.47a.75.75 0 1 0 1.06 1.06L8 9.06l1.47 1.47a.75.75 0 1 0 1.06-1.06L9.06 8l1.47-1.47a.75.75 0 1 0-1.06-1.06L8 6.94z",clipRule:"evenodd"}))},43665:e=>{e.exports=function(e,t,n,a){for(var l=-1,s=null==e?0:e.length;++l{"use strict";n.d(t,{o:()=>a});const a=(0,n(82435).withNaming)({e:"__",m:"_"})},57439:(e,t,n)=>{"use strict";n.d(t,{u:()=>O});var a=n(59284),l=n(96873),s=n(98192);const r=(0,s.om)("definition-list");const i=e=>"label"in e&&!("name"in e),c=e=>!e.some((e=>i(e)));function o(e,t){return e||("string"===typeof t||"number"===typeof t?String(t):void 0)}function m({copyText:e,content:t,copyPosition:n}){const s="inside"===n,i=null!==t&&void 0!==t?t:"\u2014";return e?a.createElement("div",{className:r("copy-container",{"icon-inside":s})},a.createElement("span",null,i),a.createElement(l.b,{size:"s",text:e,className:r("copy-button"),view:s?"raised":"flat-secondary"})):i}var d=n(98089);function u({label:e}){return a.createElement("div",{className:r("group-title")},a.createElement(d.E,{variant:"subheader-1",color:"complementary"},e))}var v=n(6170),p=n(72837);const h=JSON.parse('{"label_note":"Note"}'),f=JSON.parse('{"label_note":"\u0421\u043f\u0440\u0430\u0432\u043a\u0430"}'),b=(0,p.N)({en:h,ru:f},`${s.CU}definition-list`);var g=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"===typeof Object.getOwnPropertySymbols){var l=0;for(a=Object.getOwnPropertySymbols(e);le.map(((e,t)=>Object.assign(Object.assign({},e),{key:t})))),[e]);return a.createElement("div",{className:r({responsive:t,vertical:"vertical"===n},i),"data-qa":u},a.createElement("dl",{className:r("list")},h.map((e=>{const{name:t,key:l,content:s,contentTitle:i,nameTitle:u,copyText:h,note:f,multilineName:b}=e;return a.createElement("div",{key:l,className:r("item",c)},a.createElement("dt",{className:r("term-container",{multiline:b}),style:v},a.createElement(E,{direction:n,name:t,nameTitle:u,note:f,multilineName:b})),a.createElement("dd",{className:r("definition"),title:o(i,s),style:Object.assign(Object.assign({},p),{lineBreak:"string"===typeof s&&(g=20,function(e){return e.split(/\s+/).some((e=>e.length>g))})(s)?"anywhere":void 0})},a.createElement(m,{copyPosition:d,copyText:h,content:s})));var g}))))}function x(e){var{items:t,className:n,itemClassName:l}=e,s=N(e,["items","className","itemClassName"]);const i=a.useMemo((()=>t.map(((e,t)=>Object.assign(Object.assign({},e),{key:t})))),[t]);return a.createElement("div",{className:r({vertical:"vertical"===s.direction},n)},i.map((e=>{const{key:t,label:n}=e;return a.createElement(a.Fragment,{key:t},n&&a.createElement(u,{label:n}),e.items&&a.createElement(y,Object.assign({},s,{className:r({margin:!n}),items:e.items,itemClassName:r("item",{grouped:Boolean(n)},l)})))})))}function O(e){var{items:t}=e,n=N(e,["items"]);if(c(t))return a.createElement(y,Object.assign({},n,{items:t}));const l=function(e){const t=[];let n=[];for(const a of e)i(a)?(n.length&&(t.push({items:n,label:null}),n=[]),t.push(a)):n.push(a);return n.length&&(t.push({items:n,label:null}),n=[]),t}(t);return a.createElement(x,Object.assign({},n,{items:l}))}},63126:(e,t,n)=>{"use strict";n.d(t,{G:()=>o});var a=n(60712),l=n(59284),s=n(40569),r=n(53302);const i="--ydb-tree-view-level",c=(0,r.o)("ydb-tree-view");function o({children:e,name:t,title:n,icon:r,collapsed:o=!0,active:m=!1,onClick:d,onArrowClick:u,onActionsOpenToggle:v,hasArrow:p=!1,actions:h,additionalNodeElements:f,level:b}){const g=l.useCallback((e=>{if(!d)return;e.nativeEvent.composedPath().some((e=>e instanceof HTMLElement&&("BUTTON"===e.nodeName&&!e.hasAttribute("disabled")||e.hasAttribute("tabindex")&&e.tabIndex>-1)))||d()}),[d]),w=u||d;let E="tree-view_arrow",N="tree-view_children";return o&&(E+=" tree-view_arrow-collapsed",N+=" tree-view_children-collapsed"),(0,a.jsx)("div",{className:c(),style:{[i]:b},children:(0,a.jsxs)("div",{className:"tree-view",children:[(0,a.jsxs)("div",{className:`tree-view_item ${c("item",{active:m})}`,onClick:g,children:[(0,a.jsx)("button",{type:"button",className:`${E} ${c("arrow",{collapsed:o,hidden:!p})}`,disabled:!w,onClick:w}),(0,a.jsxs)("div",{className:c("content"),children:[r&&(0,a.jsx)("div",{className:c("icon"),children:r}),(0,a.jsx)("div",{className:c("text"),title:n,children:t}),h&&h.length>0&&(0,a.jsxs)("div",{className:c("actions"),children:[f,(0,a.jsx)(s.r,{onOpenToggle:v,defaultSwitcherProps:{view:"flat-secondary",size:"s",pin:"brick-brick"},items:h})]})]})]}),(0,a.jsx)("div",{className:`${N} ${c("container",{collapsed:o})}`,children:o?null:e})]})})}},64470:(e,t,n)=>{"use strict";n.d(t,{A:()=>l});var a=n(59284);const l=e=>a.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),a.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M9 2H7a.5.5 0 0 0-.5.5V3h3v-.5A.5.5 0 0 0 9 2m2 1v-.5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2V3H2.251a.75.75 0 0 0 0 1.5h.312l.317 7.625A3 3 0 0 0 5.878 15h4.245a3 3 0 0 0 2.997-2.875l.318-7.625h.312a.75.75 0 0 0 0-1.5zm.936 1.5H4.064l.315 7.562A1.5 1.5 0 0 0 5.878 13.5h4.245a1.5 1.5 0 0 0 1.498-1.438zm-6.186 2v5a.75.75 0 0 0 1.5 0v-5a.75.75 0 0 0-1.5 0m3.75-.75a.75.75 0 0 1 .75.75v5a.75.75 0 0 1-1.5 0v-5a.75.75 0 0 1 .75-.75",clipRule:"evenodd"}))},74321:(e,t,n)=>{"use strict";n.d(t,{S:()=>o});var a=n(59284),l=n(64222),s=n(46898);function r(e){return a.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 17 17",width:"16",height:"16",fill:"currentColor"},e),a.createElement("path",{d:"M4 7h9v3H4z"}))}function i(e){return a.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 12 10",width:"16",height:"16",fill:"currentColor"},e),a.createElement("path",{d:"M.49 5.385l1.644-1.644 4.385 4.385L4.874 9.77.49 5.385zm4.384 1.096L10.356 1 12 2.644 6.519 8.126 4.874 6.48v.001z"}))}const c=(0,n(69220).om)("checkbox"),o=a.forwardRef((function(e,t){const{size:n="m",indeterminate:o,disabled:m=!1,content:d,children:u,title:v,style:p,className:h,qa:f}=e,{checked:b,inputProps:g}=(0,l.v)(e),w=d||u,E=a.createElement("span",{className:c("indicator")},a.createElement("span",{className:c("icon"),"aria-hidden":!0},o?a.createElement(r,{className:c("icon-svg",{type:"dash"})}):a.createElement(i,{className:c("icon-svg",{type:"tick"})})),a.createElement("input",Object.assign({},g,{className:c("control")})),a.createElement("span",{className:c("outline")}));return a.createElement(s.m,{ref:t,title:v,style:p,size:n,disabled:m,className:c({size:n,disabled:m,indeterminate:o,checked:b},h),qa:f,control:E},w)}))},76938:(e,t,n)=>{"use strict";n.d(t,{A:()=>l});var a=n(59284);const l=e=>a.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),a.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M8 1.5a6.5 6.5 0 1 1-6.445 7.348.75.75 0 1 1 1.487-.194A5.001 5.001 0 1 0 4.43 4.5h1.32a.75.75 0 0 1 0 1.5h-3A.75.75 0 0 1 2 5.25v-3a.75.75 0 0 1 1.5 0v1.06A6.48 6.48 0 0 1 8 1.5",clipRule:"evenodd"}))},78018:(e,t,n)=>{var a=n(80472),l=n(2680),s=Object.prototype.hasOwnProperty,r=l((function(e,t,n){s.call(e,n)?e[n].push(t):a(e,n,[t])}));e.exports=r},79879:(e,t,n)=>{"use strict";n.d(t,{A:()=>l});var a=n(59284);const l=e=>a.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),a.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"m3.003 4.702 4.22-2.025a1.8 1.8 0 0 1 1.554 0l4.22 2.025a.89.89 0 0 1 .503.8V6a8.55 8.55 0 0 1-3.941 7.201l-.986.631a1.06 1.06 0 0 1-1.146 0l-.986-.63A8.55 8.55 0 0 1 2.5 6v-.498c0-.341.196-.652.503-.8m3.57-3.377L2.354 3.35A2.39 2.39 0 0 0 1 5.502V6a10.05 10.05 0 0 0 4.632 8.465l.986.63a2.56 2.56 0 0 0 2.764 0l.986-.63A10.05 10.05 0 0 0 15 6v-.498c0-.918-.526-1.755-1.354-2.152l-4.22-2.025a3.3 3.3 0 0 0-2.852 0M9.5 7a1.5 1.5 0 0 1-.75 1.3v1.95a.75.75 0 0 1-1.5 0V8.3A1.5 1.5 0 1 1 9.5 7",clipRule:"evenodd"}))},81061:(e,t,n)=>{var a=n(75125);e.exports=function(e,t,n,l){return a(e,(function(e,a,s){t(l,e,n(e),s)})),l}},93381:(e,t,n)=>{"use strict";n.d(t,{A:()=>l});var a=n(59284);const l=e=>a.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),a.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M13.5 8a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0M15 8A7 7 0 1 1 1 8a7 7 0 0 1 14 0M8.75 5.5a.75.75 0 0 0-1.5 0v1.75H5.5a.75.75 0 1 0 0 1.5h1.75v1.75a.75.75 0 0 0 1.5 0V8.75h1.75a.75.75 0 0 0 0-1.5H8.75z",clipRule:"evenodd"}))},98192:(e,t,n)=>{"use strict";n.d(t,{CU:()=>l,om:()=>s});var a=n(82435);const l="gc-",s=((0,a.withNaming)({e:"__",m:"_",v:"_"}),(0,a.withNaming)({n:l,e:"__",m:"_",v:"_"}))}}]); \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/23779.2a240d6f.chunk.js b/ydb/core/viewer/monitoring/static/js/23779.2a240d6f.chunk.js deleted file mode 100644 index 0dfcfdce7bb2..000000000000 --- a/ydb/core/viewer/monitoring/static/js/23779.2a240d6f.chunk.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[23779],{6170:(e,s,t)=>{t.d(s,{B:()=>c});var r=t(59284),a=t(73633),l=t(84375),n=t(99991);const o=(0,t(98192).om)("help-popover"),i=16;function c(e){var s;return r.createElement(l.A,Object.assign({},e,{className:o(null,e.className)}),r.createElement("button",Object.assign({ref:e.buttonRef,type:"button"},e.buttonProps,{className:o("button",null===(s=e.buttonProps)||void 0===s?void 0:s.className)}),r.createElement(n.I,{data:a.A,size:i})))}},15132:(e,s,t)=>{t.d(s,{O:()=>v});var r=t(38501),a=t(77506),l=t(56839),n=t(35736),o=t(41650),i=t(60712);const c=(0,a.cn)("progress-viewer"),d=e=>(0,l.ZV)((0,l.CR)(Number(e),2)),u=(e,s)=>[d(e),d(s)];function v({value:e,capacity:s,formatValues:t=u,percents:a,className:l,size:d="xs",colorizeProgress:v,inverseColorize:m,warningThreshold:h,dangerThreshold:N,hideCapacity:g}){const p=(0,r.D)();let f=Math.round(parseFloat(String(e))/parseFloat(String(s))*100)||0;f=f>100?100:f;let S=e,b=s,x="/";a?(S=f+"%",b="",x=""):t&&([S,b]=t(Number(e),Number(s)));const E=(0,n.w)({fillWidth:f,warningThreshold:h,dangerThreshold:N,colorizeProgress:v,inverseColorize:m});v&&!(0,o.kf)(s)&&(f=100);const j={width:f+"%"};return(0,o.kf)(e)?(0,i.jsxs)("div",{className:c({size:d,theme:p,status:E},l),children:[(0,i.jsx)("div",{className:c("line"),style:j}),(0,i.jsx)("span",{className:c("text"),children:(0,o.kf)(s)&&!g?`${S} ${x} ${b}`:S})]}):(0,i.jsx)("div",{className:`${c({size:d})} ${l} error`,children:"no data"})}},18143:(e,s,t)=>{t.d(s,{k:()=>u});var r=t(59284);const a=(0,t(69220).om)("progress");function l(e){const{text:s,offset:t=0}=e;return s?r.createElement("div",{className:a("text-inner"),style:{transform:`translateX(calc(var(--g-flow-direction) * ${-t}%))`}},s):null}function n({item:e}){const{value:s,color:t,className:l,theme:n,title:o,content:i,loading:c}=e,d={loading:c};return"undefined"===typeof t&&(d.theme=n||"default"),Number.isFinite(s)?r.createElement("div",{className:a("item",d,l),style:{width:`${s}%`,backgroundColor:t},title:o},i):null}function o(e){return e<100?e-100:0}function i(e){const{theme:s,colorStops:t,colorStopsValue:r,value:a}=e;if(t){const e=t.find(((e,s)=>{const l="number"===typeof r?r:a,n=s>1?t[s-1].stop:0,o=s=n&&l<=o}));return e?e.theme:s}return s}function c(e){const{stack:s,stackClassName:t,value:i,text:c}=e,d=o(i||function(e){return e.reduce(((e,{value:s})=>e+s),0)}(s));return r.createElement("div",{className:a("stack",t),style:{transform:`translateX(calc(var(--g-flow-direction) * ${d}%))`}},r.createElement("div",{className:a("item"),style:{width:-d+"%"}}),s.map(((e,s)=>r.createElement(n,{key:s,item:e}))),r.createElement(l,{offset:d,text:c}))}function d(e){const{value:s,loading:t,text:n}=e,c=o(s);return Number.isFinite(s)?r.createElement("div",{className:a("item",{theme:i(e),loading:t}),style:{transform:`translateX(calc(var(--g-flow-direction) * ${c}%))`}},r.createElement(l,{offset:c,text:n})):null}const u=r.forwardRef((function(e,s){const{text:t="",theme:l="default",size:n="m",loading:o=!1,className:i,qa:u}=e,v=Object.assign(Object.assign({},e),{text:t,theme:l,size:n,loading:o});return r.createElement("div",{ref:s,className:a({size:n},i),"data-qa":u},r.createElement("div",{className:a("text")},t),function(e){return void 0!==e.stack}(v)?r.createElement(c,Object.assign({},v)):r.createElement(d,Object.assign({},v)))}))},35736:(e,s,t)=>{t.d(s,{w:()=>a});var r=t(76086);function a({inverseColorize:e,warningThreshold:s=r.Hh,dangerThreshold:t=r.Ed,colorizeProgress:a,fillWidth:l}){let n=e?"danger":"good";return a&&(l>s&&l<=t?n="warning":l>t&&(n=e?"good":"danger")),n}},41775:(e,s,t)=>{t.d(s,{v:()=>i});var r=t(59284),a=t(28664),l=t(77506),n=t(60712);const o=(0,l.cn)("ydb-search"),i=({onChange:e,value:s="",width:t,className:l,debounce:i=200,placeholder:c})=>{const[d,u]=r.useState(s),v=r.useRef();r.useEffect((()=>{u((e=>e!==s?s:e))}),[s]);return(0,n.jsx)(a.k,{hasClear:!0,autoFocus:!0,style:{width:t},className:o(null,l),placeholder:c,value:d,onUpdate:s=>{u(s),window.clearTimeout(v.current),v.current=window.setTimeout((()=>{null===e||void 0===e||e(s)}),i)}})}},43951:(e,s,t)=>{t.d(s,{K:()=>l});var r=t(59284),a=t(59001);const l=(e,s,t,l,n)=>{const[o,i]=r.useState((()=>a.f.readUserSettingsValue(s,l)));return{columnsToShow:r.useMemo((()=>e.filter((e=>{const s=e.name,t=o.includes(s),r=null===n||void 0===n?void 0:n.includes(s);return t||r}))),[e,n,o]),columnsToSelect:r.useMemo((()=>e.map((e=>e.name)).map((e=>{const s=null===n||void 0===n?void 0:n.includes(e),r=o.includes(e);return{id:e,title:t[e],selected:s||r,required:s,sticky:s?"start":void 0}}))),[e,t,n,o]),setColumns:r.useCallback((e=>{const t=e.filter((e=>e.selected)).map((e=>e.id));a.f.setUserSettingsValue(s,t),i(t)}),[s])}}},48288:(e,s,t)=>{t.r(s),t.d(s,{Clusters:()=>te});var r=t(59284),a=t(4557),l=t(24555),n=t(69775),o=t(61750),i=t(90053),c=t(44508),d=t(52248),u=t(17594),v=t(95963),m=t(39567),h=t(23536),N=t.n(h),g=t(41650);const p=e=>e.clusters.clusterName,f=e=>e.clusters.status,S=e=>e.clusters.service,b=e=>e.clusters.version,x=(e,s)=>0===s.length||e.status&&s.includes(e.status),E=(e,s)=>0===s.length||e.service&&s.includes(e.service),j=(e,s)=>0===s.length||s.some((s=>{var t,r;return null===(t=e.cluster)||void 0===t||null===(r=t.Versions)||void 0===r?void 0:r.some((e=>e.startsWith(s)))})),T=(e,s="")=>{var t;if(!s)return!0;const r=s.toLowerCase(),a=r.split(" "),l=(null===(t=e.title)||void 0===t?void 0:t.toLowerCase().match(/[^\d\s]+|\d+|[^-\s]+|[^_\s]+/g))||[],n=a.every((s=>{const t=N()(s),r=new RegExp(`^${t}|[\\s\\-_]${t}`,"i");return e.title&&r.test(e.title)||l.some((e=>e.startsWith(s)))})),o=e.preparedVersions.some((e=>e.version.includes(r))),i=Boolean(e.hosts&&e.hosts[r]);return n||o||i};var O=t(76086),C=t(90182),w=t(43951),A=t(38596),_=t(15132),y=t(56839),R=t(48372);const I=JSON.parse('{"controls_status-select-label":"Status:","controls_service-select-label":"Service:","controls_version-select-label":"Version:","controls_search-placeholder":"Cluster name, version, host","controls_select-placeholder":"All","statistics_clusters":"Clusters","statistics_hosts":"Hosts","statistics_tenants":"Tenants","statistics_nodes":"Nodes","statistics_load":"Load","statistics_storage":"Storage","tooltip_no-cluster-data":"No cluster data","page_title":"Clusters"}'),D=JSON.parse('{"controls_status-select-label":"\u0421\u0442\u0430\u0442\u0443\u0441:","controls_service-select-label":"\u0421\u0435\u0440\u0432\u0438\u0441:","controls_version-select-label":"\u0412\u0435\u0440\u0441\u0438\u044f:","controls_search-placeholder":"\u0418\u043c\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430, \u0432\u0435\u0440\u0441\u0438\u044f \u0438\u043b\u0438 \u0445\u043e\u0441\u0442","controls_select-placeholder":"\u0412\u0441\u0435","statistics_clusters":"\u041a\u043b\u0430\u0441\u0442\u0435\u0440\u044b","statistics_hosts":"\u0425\u043e\u0441\u0442\u044b","statistics_tenants":"\u0411\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445","statistics_nodes":"\u0423\u0437\u043b\u044b","statistics_load":"\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430","statistics_storage":"\u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435","tooltip_no-cluster-data":"\u041d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430","page_title":"\u041a\u043b\u0430\u0441\u0442\u0435\u0440\u044b"}'),L=(0,R.g4)("ydb-clusters-page",{ru:D,en:I});var z=t(77506);const k=(0,z.cn)("clusters");var V=t(60712);const U=({count:e,stats:s})=>{const{NodesTotal:t,NodesAlive:r,Hosts:a,Tenants:l,LoadAverage:n,NumberOfCpus:o,StorageUsed:i,StorageTotal:c}=s;return(0,V.jsxs)("div",{className:k("aggregation"),children:[(0,V.jsxs)("div",{className:k("aggregation-value-container"),children:[(0,V.jsx)("span",{className:k("aggregation-label"),children:L("statistics_clusters")}),e]}),(0,V.jsxs)("div",{className:k("aggregation-value-container"),children:[(0,V.jsx)("span",{className:k("aggregation-label"),children:L("statistics_hosts")}),a]}),(0,V.jsxs)("div",{className:k("aggregation-value-container"),children:[(0,V.jsx)("span",{className:k("aggregation-label"),children:L("statistics_tenants")}),l]}),(0,V.jsxs)("div",{className:k("aggregation-value-container"),children:[(0,V.jsx)("span",{className:k("aggregation-label"),children:L("statistics_nodes")}),(0,V.jsx)(_.O,{size:"ns",value:r,capacity:t,colorizeProgress:!0,inverseColorize:!0})]}),(0,V.jsxs)("div",{className:k("aggregation-value-container"),children:[(0,V.jsx)("span",{className:k("aggregation-label"),children:L("statistics_load")}),(0,V.jsx)(_.O,{size:"ns",value:n,capacity:o,colorizeProgress:!0})]}),(0,V.jsxs)("div",{className:k("aggregation-value-container"),children:[(0,V.jsx)("span",{className:k("aggregation-label"),children:L("statistics_storage")}),(0,V.jsx)(_.O,{size:"ns",value:i,capacity:c,formatValues:y.j9,colorizeProgress:!0})]})]})};var G=t(6170),P=t(67884),W=t(18143),M=t(96873),$=t(34271);const H=(0,z.cn)("kv-user");function B({login:e,className:s}){const t=(0,$.x)("StaffCard");return(0,V.jsx)("div",{className:H(null,s),children:(0,V.jsx)(t,{login:e,children:(0,V.jsx)("div",{className:H("name"),children:e})})})}var F=t(31684),q=t(69446),J=t(87842);const K="selectedColumns",Q={TITLE:"title",VERSIONS:"versions",DC:"dc",SERVICE:"service",STATUS:"status",NODES:"nodes",LOAD:"load",STORAGE:"storage",HOSTS:"hosts",TENANTS:"tenants",OWNER:"owner",DESCRIPTION:"description",BALANCER:"balancer"},X=[Q.TITLE,Q.VERSIONS,Q.SERVICE,Q.STATUS,Q.NODES,Q.LOAD,Q.STORAGE,Q.HOSTS,Q.TENANTS,Q.OWNER,Q.BALANCER],Y={[Q.TITLE]:"Cluster",[Q.VERSIONS]:"Versions",[Q.DC]:"DC",[Q.SERVICE]:"Service",[Q.STATUS]:"Status",[Q.NODES]:"Nodes",[Q.LOAD]:"Load",[Q.STORAGE]:"Storage",[Q.HOSTS]:"Hosts",[Q.TENANTS]:"Tenants",[Q.OWNER]:"Owner",[Q.DESCRIPTION]:"Description",[Q.BALANCER]:"Balancer"},Z="clustersTableColumnsWidth",ee=(0,V.jsx)("span",{className:k("empty-cell"),children:"\u2014"}),se=[{name:Q.TITLE,header:Y[Q.TITLE],width:230,render:({row:e})=>{var s,t;const{balancer:r,name:a,use_embedded_ui:l}=e,n=r&&(0,q.PG)(r),o=l&&n?(0,F.t1)(n):(0,J.a)(void 0,{backend:n,clusterName:a}),i=null===(s=e.cluster)||void 0===s?void 0:s.Overall;return(0,V.jsxs)("div",{className:k("cluster"),children:[i?(0,V.jsx)(P.N,{href:o,children:(0,V.jsx)("div",{className:k("cluster-status",{type:i&&i.toLowerCase()})})}):(0,V.jsx)("div",{className:k("cluster-status"),children:(0,V.jsx)(G.B,{content:(0,V.jsx)("span",{className:k("tooltip-content"),children:(null===(t=e.cluster)||void 0===t?void 0:t.error)||L("tooltip_no-cluster-data")}),offset:{left:0}})}),(0,V.jsx)("div",{className:k("cluster-name"),children:(0,V.jsx)(P.N,{href:o,children:e.title})})]})},defaultOrder:a.Ay.ASCENDING},{name:Q.VERSIONS,header:Y[Q.VERSIONS],width:300,defaultOrder:a.Ay.DESCENDING,sortAccessor:({preparedVersions:e})=>e.map((e=>e.version.replace(/^[0-9]\+\./g,""))).sort(((e,s)=>e.localeCompare(s)))[0]||void 0,render:({row:e})=>{const{preparedVersions:s,versions:t=[],balancer:a,name:l}=e;if(!t.length||t.some((e=>!e.version)))return ee;const n=t.reduce(((e,s)=>e+s.count),0),o=t.map((e=>{var t;return{value:e.count/n*100,color:null===(t=s.find((s=>s.version===e.version)))||void 0===t?void 0:t.color}})),i=a&&(0,q.PG)(a);return s.length>0&&(0,V.jsx)(P.N,{className:k("cluster-versions"),href:(0,J.a)(J.Bi.versions,{backend:i,clusterName:l}),children:(0,V.jsxs)(r.Fragment,{children:[s.map(((e,s)=>(0,V.jsx)("div",{className:k("cluster-version"),style:{color:e.color},title:e.version,children:e.version},s))),(0,V.jsx)(W.k,{size:"s",value:100,stack:o})]})})}},{name:Q.DC,header:Y[Q.DC],width:120,sortable:!1,render:({row:e})=>{const s=e.cluster&&e.cluster.DataCenters||[];return(0,V.jsx)("div",{className:k("cluster-dc"),children:s.join(", ")||ee})}},{name:Q.SERVICE,header:Y[Q.SERVICE],width:100,sortable:!0},{name:Q.STATUS,header:Y[Q.STATUS],width:150,sortable:!0},{name:Q.NODES,header:Y[Q.NODES],resizeMinWidth:170,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e={}})=>{const{NodesTotal:s=0}=e;return s},render:({row:e})=>{const{NodesAlive:s=0,NodesTotal:t=0,Overall:r}=e.cluster||{};return r?(0,V.jsx)(_.O,{value:s,capacity:t}):ee}},{name:Q.LOAD,header:Y[Q.LOAD],resizeMinWidth:170,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e})=>null===e||void 0===e?void 0:e.NumberOfCpus,render:({row:e})=>{const{LoadAverage:s=0,NumberOfCpus:t=0,RealNumberOfCpus:r,Overall:a}=e.cluster||{};return a?(0,V.jsx)(_.O,{value:s,capacity:null!==r&&void 0!==r?r:t}):ee}},{name:Q.STORAGE,header:Y[Q.STORAGE],resizeMinWidth:170,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e})=>Number(null===e||void 0===e?void 0:e.StorageTotal),render:({row:e})=>{const{StorageUsed:s=0,StorageTotal:t=0,Overall:r}=e.cluster||{};return r?(0,V.jsx)(_.O,{value:s,capacity:t,formatValues:y.ki}):ee}},{name:Q.HOSTS,header:Y[Q.HOSTS],width:80,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e})=>Number(null===e||void 0===e?void 0:e.Hosts)||0,render:({row:e})=>{var s;return Number(null===(s=e.cluster)||void 0===s?void 0:s.Hosts)||ee}},{name:Q.TENANTS,header:Y[Q.TENANTS],width:80,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e})=>Number(null===e||void 0===e?void 0:e.Tenants)||0,render:({row:e})=>{var s;return Number(null===(s=e.cluster)||void 0===s?void 0:s.Tenants)||ee}},{name:Q.OWNER,header:Y[Q.OWNER],sortable:!1,width:120,render:({row:e})=>{var s;const t=null===(s=e.owner)||void 0===s?void 0:s.split(", ");return null!==t&&void 0!==t&&t.length?t.map((e=>(0,V.jsx)(B,{login:e},e))):ee}},{name:Q.DESCRIPTION,header:Y[Q.DESCRIPTION],sortable:!1,width:150,render:({row:e})=>e.description?(0,V.jsx)("div",{className:k("description"),children:e.description}):ee},{name:Q.BALANCER,header:Y[Q.BALANCER],sortable:!1,width:290,render:({row:e})=>{if(!e.balancer)return ee;const s=(0,q.Zd)(e.balancer);return(0,V.jsxs)("div",{className:k("balancer-cell"),children:[(0,V.jsx)("div",{className:k("balancer-text"),children:s}),(0,V.jsx)(M.b,{size:"s",text:s,className:k("balancer-icon")})]})}}];function te(){const[e]=(0,C.Nt)(),s=m.ub.useGetClustersListQuery(void 0,{pollingInterval:e}),t=(0,C.YQ)(),h=(0,C.N4)(p),N=(0,C.N4)(f),_=(0,C.N4)(S),y=(0,C.N4)(b),{columnsToShow:R,columnsToSelect:I,setColumns:D}=(0,w.K)(se,K,Y,X,[Q.TITLE]),z=s.data,{servicesToSelect:G,versions:P}=r.useMemo((()=>{const e=new Set,s=new Set;return(null!==z&&void 0!==z?z:[]).forEach((t=>{var r,a;t.service&&e.add(t.service),null===(r=t.cluster)||void 0===r||null===(a=r.Versions)||void 0===a||a.forEach((e=>{s.add((0,A.U)(e))}))})),{servicesToSelect:Array.from(e).map((e=>({value:e,content:e}))),versions:Array.from(s).map((e=>({value:e,content:e})))}}),[z]),W=r.useMemo((()=>function(e,s){return e.filter((e=>x(e,s.status)&&E(e,s.service)&&j(e,s.version)&&T(e,s.clusterName)))}(null!==z&&void 0!==z?z:[],{clusterName:h,status:N,service:_,version:y})),[h,z,_,N,y]),M=r.useMemo((()=>function(e){let s=0,t=0,r=0,a=0,l=0,n=0,o=0;const i=new Set;return e.filter((({cluster:e})=>!(null!==e&&void 0!==e&&e.error))).forEach((({cluster:e,hosts:c={}})=>{s+=(null===e||void 0===e?void 0:e.NodesTotal)||0,t+=(null===e||void 0===e?void 0:e.NodesAlive)||0,Object.keys(c).forEach((e=>i.add(e))),o+=Number(null===e||void 0===e?void 0:e.Tenants)||0,r+=Number(null===e||void 0===e?void 0:e.LoadAverage)||0,a+=(0,g.kf)(null===e||void 0===e?void 0:e.RealNumberOfCpus)?null===e||void 0===e?void 0:e.RealNumberOfCpus:(null===e||void 0===e?void 0:e.NumberOfCpus)||0,l+=null!==e&&void 0!==e&&e.StorageUsed?Math.floor(parseInt(e.StorageUsed,10)):0,n+=null!==e&&void 0!==e&&e.StorageTotal?Math.floor(parseInt(e.StorageTotal,10)):0})),{NodesTotal:s,NodesAlive:t,Hosts:i.size,Tenants:o,LoadAverage:r,NumberOfCpus:a,StorageUsed:l,StorageTotal:n}}(W)),[W]),$=r.useMemo((()=>Array.from(new Set((null!==z&&void 0!==z?z:[]).map((e=>e.status)).filter(Boolean))).sort().map((e=>({value:e,content:e})))),[z]);return(0,V.jsxs)("div",{className:k(),children:[(0,V.jsx)(o.mg,{children:(0,V.jsx)("title",{children:L("page_title")})}),(0,V.jsx)(U,{stats:M,count:W.length}),(0,V.jsxs)("div",{className:k("controls"),children:[(0,V.jsx)("div",{className:k("control",{wide:!0}),children:(0,V.jsx)(v.v,{placeholder:L("controls_search-placeholder"),onChange:e=>{t((0,m.Fe)({clusterName:e}))},value:h})}),(0,V.jsx)("div",{className:k("control"),children:(0,V.jsx)(l.l,{multiple:!0,filterable:!0,hasClear:!0,placeholder:L("controls_select-placeholder"),label:L("controls_status-select-label"),value:N,options:$,onUpdate:e=>{t((0,m.Fe)({status:e}))},width:"max"})}),(0,V.jsx)("div",{className:k("control"),children:(0,V.jsx)(l.l,{multiple:!0,filterable:!0,hasClear:!0,placeholder:L("controls_select-placeholder"),label:L("controls_service-select-label"),value:_,options:G,onUpdate:e=>{t((0,m.Fe)({service:e}))},width:"max"})}),(0,V.jsx)("div",{className:k("control"),children:(0,V.jsx)(l.l,{multiple:!0,filterable:!0,hasClear:!0,placeholder:L("controls_select-placeholder"),label:L("controls_version-select-label"),value:y,options:P,onUpdate:e=>{t((0,m.Fe)({version:e}))},width:"max"})}),(0,V.jsx)("div",{className:k("control"),children:(0,V.jsx)(n.O,{popupWidth:242,items:I,showStatus:!0,onUpdate:D,sortable:!1},"TableColumnSetup")}),(0,V.jsx)(i.E,{className:k("autorefresh")})]}),s.isError?(0,V.jsx)(c.o,{error:s.error,className:k("error")}):null,s.isLoading?(0,V.jsx)(d.a,{size:"l"}):null,s.fulfilledTimeStamp?(0,V.jsx)("div",{className:k("table-wrapper"),children:(0,V.jsx)("div",{className:k("table-content"),children:(0,V.jsx)(u.l,{columnsWidthLSKey:Z,wrapperClassName:k("table"),data:W,columns:R,settings:{...O.N3,dynamicRender:!1},initialSortOrder:{columnId:Q.TITLE,order:a.Ay.ASCENDING}})})}):null]})}},52248:(e,s,t)=>{t.d(s,{a:()=>r.a});var r=t(47334)},90053:(e,s,t)=>{t.d(s,{E:()=>h});var r=t(8873),a=t(84476),l=t(24555),n=t(21334),o=t(77506),i=t(90182),c=t(48372);const d=JSON.parse('{"None":"None","15 sec":"15 sec","1 min":"1 min","2 min":"2 min","5 min":"5 min","Refresh":"Refresh"}'),u=(0,c.g4)("ydb-diagnostics-autorefresh-control",{en:d});var v=t(60712);const m=(0,o.cn)("auto-refresh-control");function h({className:e,onManualRefresh:s}){const t=(0,i.YQ)(),[o,c]=(0,i.Nt)();return(0,v.jsxs)("div",{className:m(null,e),children:[(0,v.jsx)(a.$,{view:"flat-secondary",onClick:()=>{t(n.F.util.invalidateTags(["All"])),null===s||void 0===s||s()},extraProps:{"aria-label":u("Refresh")},children:(0,v.jsx)(a.$.Icon,{children:(0,v.jsx)(r.A,{})})}),(0,v.jsxs)(l.l,{value:[String(o)],onUpdate:e=>{c(Number(e))},width:85,qa:"ydb-autorefresh-select",children:[(0,v.jsx)(l.l.Option,{value:"0",children:u("None")}),(0,v.jsx)(l.l.Option,{value:"15000",children:u("15 sec")}),(0,v.jsx)(l.l.Option,{value:"60000",children:u("1 min")}),(0,v.jsx)(l.l.Option,{value:"120000",children:u("2 min")}),(0,v.jsx)(l.l.Option,{value:"300000",children:u("5 min")})]})]})}},95963:(e,s,t)=>{t.d(s,{v:()=>r.v});var r=t(41775)},98192:(e,s,t)=>{t.d(s,{CU:()=>a,om:()=>l});var r=t(82435);const a="gc-",l=((0,r.withNaming)({e:"__",m:"_",v:"_"}),(0,r.withNaming)({n:a,e:"__",m:"_",v:"_"}))}}]); \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/23779.5bbf5687.chunk.js b/ydb/core/viewer/monitoring/static/js/23779.5bbf5687.chunk.js new file mode 100644 index 000000000000..894597c15691 --- /dev/null +++ b/ydb/core/viewer/monitoring/static/js/23779.5bbf5687.chunk.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[23779],{6170:(e,s,t)=>{t.d(s,{B:()=>c});var r=t(59284),a=t(73633),l=t(84375),n=t(99991);const o=(0,t(98192).om)("help-popover"),i=16;function c(e){var s;return r.createElement(l.A,Object.assign({},e,{className:o(null,e.className)}),r.createElement("button",Object.assign({ref:e.buttonRef,type:"button"},e.buttonProps,{className:o("button",null===(s=e.buttonProps)||void 0===s?void 0:s.className)}),r.createElement(n.I,{data:a.A,size:i})))}},15132:(e,s,t)=>{t.d(s,{O:()=>v});var r=t(38501),a=t(77506),l=t(56839),n=t(35736),o=t(41650),i=t(60712);const c=(0,a.cn)("progress-viewer"),d=e=>(0,l.ZV)((0,l.CR)(Number(e),2)),u=(e,s)=>[d(e),d(s)];function v({value:e,capacity:s,formatValues:t=u,percents:a,className:l,size:d="xs",colorizeProgress:v,inverseColorize:m,warningThreshold:h,dangerThreshold:N,hideCapacity:g}){const p=(0,r.D)();let f=Math.round(parseFloat(String(e))/parseFloat(String(s))*100)||0;f=f>100?100:f;let S=e,x=s,b="/";a?(S=f+"%",x="",b=""):t&&([S,x]=t(Number(e),Number(s)));const E=(0,n.w)({fillWidth:f,warningThreshold:h,dangerThreshold:N,colorizeProgress:v,inverseColorize:m});v&&!(0,o.kf)(s)&&(f=100);const j={width:f+"%"};return(0,o.kf)(e)?(0,i.jsxs)("div",{className:c({size:d,theme:p,status:E},l),children:[(0,i.jsx)("div",{className:c("line"),style:j}),(0,i.jsx)("span",{className:c("text"),children:(0,o.kf)(s)&&!g?`${S} ${b} ${x}`:S})]}):(0,i.jsx)("div",{className:`${c({size:d})} ${l} error`,children:"no data"})}},18143:(e,s,t)=>{t.d(s,{k:()=>u});var r=t(59284);const a=(0,t(69220).om)("progress");function l(e){const{text:s,offset:t=0}=e;return s?r.createElement("div",{className:a("text-inner"),style:{transform:`translateX(calc(var(--g-flow-direction) * ${-t}%))`}},s):null}function n({item:e}){const{value:s,color:t,className:l,theme:n,title:o,content:i,loading:c}=e,d={loading:c};return"undefined"===typeof t&&(d.theme=n||"default"),Number.isFinite(s)?r.createElement("div",{className:a("item",d,l),style:{width:`${s}%`,backgroundColor:t},title:o},i):null}function o(e){return e<100?e-100:0}function i(e){const{theme:s,colorStops:t,colorStopsValue:r,value:a}=e;if(t){const e=t.find(((e,s)=>{const l="number"===typeof r?r:a,n=s>1?t[s-1].stop:0,o=s=n&&l<=o}));return e?e.theme:s}return s}function c(e){const{stack:s,stackClassName:t,value:i,text:c}=e,d=o(i||function(e){return e.reduce(((e,{value:s})=>e+s),0)}(s));return r.createElement("div",{className:a("stack",t),style:{transform:`translateX(calc(var(--g-flow-direction) * ${d}%))`}},r.createElement("div",{className:a("item"),style:{width:-d+"%"}}),s.map(((e,s)=>r.createElement(n,{key:s,item:e}))),r.createElement(l,{offset:d,text:c}))}function d(e){const{value:s,loading:t,text:n}=e,c=o(s);return Number.isFinite(s)?r.createElement("div",{className:a("item",{theme:i(e),loading:t}),style:{transform:`translateX(calc(var(--g-flow-direction) * ${c}%))`}},r.createElement(l,{offset:c,text:n})):null}const u=r.forwardRef((function(e,s){const{text:t="",theme:l="default",size:n="m",loading:o=!1,className:i,qa:u}=e,v=Object.assign(Object.assign({},e),{text:t,theme:l,size:n,loading:o});return r.createElement("div",{ref:s,className:a({size:n},i),"data-qa":u},r.createElement("div",{className:a("text")},t),function(e){return void 0!==e.stack}(v)?r.createElement(c,Object.assign({},v)):r.createElement(d,Object.assign({},v)))}))},35736:(e,s,t)=>{t.d(s,{w:()=>a});var r=t(76086);function a({inverseColorize:e,warningThreshold:s=r.Hh,dangerThreshold:t=r.Ed,colorizeProgress:a,fillWidth:l}){let n=e?"danger":"good";return a&&(l>s&&l<=t?n="warning":l>t&&(n=e?"good":"danger")),n}},41775:(e,s,t)=>{t.d(s,{v:()=>i});var r=t(59284),a=t(28664),l=t(77506),n=t(60712);const o=(0,l.cn)("ydb-search"),i=({onChange:e,value:s="",width:t,className:l,debounce:i=200,placeholder:c})=>{const[d,u]=r.useState(s),v=r.useRef();r.useEffect((()=>{u((e=>e!==s?s:e))}),[s]);return(0,n.jsx)(a.k,{hasClear:!0,autoFocus:!0,style:{width:t},className:o(null,l),placeholder:c,value:d,onUpdate:s=>{u(s),window.clearTimeout(v.current),v.current=window.setTimeout((()=>{null===e||void 0===e||e(s)}),i)}})}},43951:(e,s,t)=>{t.d(s,{K:()=>l});var r=t(59284),a=t(59001);const l=(e,s,t,l,n)=>{const[o,i]=r.useState((()=>a.f.readUserSettingsValue(s,l)));return{columnsToShow:r.useMemo((()=>e.filter((e=>{const s=e.name,t=o.includes(s),r=null===n||void 0===n?void 0:n.includes(s);return t||r}))),[e,n,o]),columnsToSelect:r.useMemo((()=>e.map((e=>e.name)).map((e=>{const s=null===n||void 0===n?void 0:n.includes(e),r=o.includes(e);return{id:e,title:t[e],selected:s||r,required:s,sticky:s?"start":void 0}}))),[e,t,n,o]),setColumns:r.useCallback((e=>{const t=e.filter((e=>e.selected)).map((e=>e.id));a.f.setUserSettingsValue(s,t),i(t)}),[s])}}},48288:(e,s,t)=>{t.r(s),t.d(s,{Clusters:()=>te});var r=t(59284),a=t(4557),l=t(24555),n=t(69775),o=t(61750),i=t(90053),c=t(44508),d=t(52248),u=t(17594),v=t(95963),m=t(39567),h=t(23536),N=t.n(h),g=t(41650);const p=e=>e.clusters.clusterName,f=e=>e.clusters.status,S=e=>e.clusters.service,x=e=>e.clusters.version,b=(e,s)=>0===s.length||e.status&&s.includes(e.status),E=(e,s)=>0===s.length||e.service&&s.includes(e.service),j=(e,s)=>0===s.length||s.some((s=>{var t,r;return null===(t=e.cluster)||void 0===t||null===(r=t.Versions)||void 0===r?void 0:r.some((e=>e.startsWith(s)))})),T=(e,s="")=>{var t;if(!s)return!0;const r=s.toLowerCase(),a=r.split(" "),l=(null===(t=e.title)||void 0===t?void 0:t.toLowerCase().match(/[^\d\s]+|\d+|[^-\s]+|[^_\s]+/g))||[],n=a.every((s=>{const t=N()(s),r=new RegExp(`^${t}|[\\s\\-_]${t}`,"i");return e.title&&r.test(e.title)||l.some((e=>e.startsWith(s)))})),o=e.preparedVersions.some((e=>e.version.includes(r))),i=Boolean(e.hosts&&e.hosts[r]);return n||o||i};var O=t(76086),C=t(90182),w=t(43951),A=t(38596),_=t(15132),y=t(56839),R=t(48372);const I=JSON.parse('{"controls_status-select-label":"Status:","controls_service-select-label":"Service:","controls_version-select-label":"Version:","controls_search-placeholder":"Cluster name, version, host","controls_select-placeholder":"All","statistics_clusters":"Clusters","statistics_hosts":"Hosts","statistics_tenants":"Tenants","statistics_nodes":"Nodes","statistics_load":"Load","statistics_storage":"Storage","tooltip_no-cluster-data":"No cluster data","page_title":"Clusters"}'),D=JSON.parse('{"controls_status-select-label":"\u0421\u0442\u0430\u0442\u0443\u0441:","controls_service-select-label":"\u0421\u0435\u0440\u0432\u0438\u0441:","controls_version-select-label":"\u0412\u0435\u0440\u0441\u0438\u044f:","controls_search-placeholder":"\u0418\u043c\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430, \u0432\u0435\u0440\u0441\u0438\u044f \u0438\u043b\u0438 \u0445\u043e\u0441\u0442","controls_select-placeholder":"\u0412\u0441\u0435","statistics_clusters":"\u041a\u043b\u0430\u0441\u0442\u0435\u0440\u044b","statistics_hosts":"\u0425\u043e\u0441\u0442\u044b","statistics_tenants":"\u0411\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445","statistics_nodes":"\u0423\u0437\u043b\u044b","statistics_load":"\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430","statistics_storage":"\u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435","tooltip_no-cluster-data":"\u041d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430","page_title":"\u041a\u043b\u0430\u0441\u0442\u0435\u0440\u044b"}'),L=(0,R.g4)("ydb-clusters-page",{ru:D,en:I});var k=t(77506);const z=(0,k.cn)("clusters");var V=t(60712);const U=({count:e,stats:s})=>{const{NodesTotal:t,NodesAlive:r,Hosts:a,Tenants:l,LoadAverage:n,NumberOfCpus:o,StorageUsed:i,StorageTotal:c}=s;return(0,V.jsxs)("div",{className:z("aggregation"),children:[(0,V.jsxs)("div",{className:z("aggregation-value-container"),children:[(0,V.jsx)("span",{className:z("aggregation-label"),children:L("statistics_clusters")}),e]}),(0,V.jsxs)("div",{className:z("aggregation-value-container"),children:[(0,V.jsx)("span",{className:z("aggregation-label"),children:L("statistics_hosts")}),a]}),(0,V.jsxs)("div",{className:z("aggregation-value-container"),children:[(0,V.jsx)("span",{className:z("aggregation-label"),children:L("statistics_tenants")}),l]}),(0,V.jsxs)("div",{className:z("aggregation-value-container"),children:[(0,V.jsx)("span",{className:z("aggregation-label"),children:L("statistics_nodes")}),(0,V.jsx)(_.O,{size:"ns",value:r,capacity:t,colorizeProgress:!0,inverseColorize:!0})]}),(0,V.jsxs)("div",{className:z("aggregation-value-container"),children:[(0,V.jsx)("span",{className:z("aggregation-label"),children:L("statistics_load")}),(0,V.jsx)(_.O,{size:"ns",value:n,capacity:o,colorizeProgress:!0})]}),(0,V.jsxs)("div",{className:z("aggregation-value-container"),children:[(0,V.jsx)("span",{className:z("aggregation-label"),children:L("statistics_storage")}),(0,V.jsx)(_.O,{size:"ns",value:i,capacity:c,formatValues:y.j9,colorizeProgress:!0})]})]})};var W=t(6170),G=t(67884),B=t(18143),M=t(96873),P=t(34271);const $=(0,k.cn)("kv-user");function H({login:e,className:s}){const t=(0,P.x)("StaffCard");return(0,V.jsx)("div",{className:$(null,s),children:(0,V.jsx)(t,{login:e,children:(0,V.jsx)("div",{className:$("name"),children:e})})})}var F=t(31684),q=t(69446),J=t(87842);const K="selectedColumns",Q={TITLE:"title",VERSIONS:"versions",DC:"dc",SERVICE:"service",STATUS:"status",NODES:"nodes",LOAD:"load",STORAGE:"storage",HOSTS:"hosts",TENANTS:"tenants",OWNER:"owner",DESCRIPTION:"description",BALANCER:"balancer"},X=[Q.TITLE,Q.VERSIONS,Q.SERVICE,Q.STATUS,Q.NODES,Q.LOAD,Q.STORAGE,Q.HOSTS,Q.TENANTS,Q.OWNER,Q.BALANCER],Y={[Q.TITLE]:"Cluster",[Q.VERSIONS]:"Versions",[Q.DC]:"DC",[Q.SERVICE]:"Service",[Q.STATUS]:"Status",[Q.NODES]:"Nodes",[Q.LOAD]:"Load",[Q.STORAGE]:"Storage",[Q.HOSTS]:"Hosts",[Q.TENANTS]:"Tenants",[Q.OWNER]:"Owner",[Q.DESCRIPTION]:"Description",[Q.BALANCER]:"Balancer"},Z="clustersTableColumnsWidth",ee=(0,V.jsx)("span",{className:z("empty-cell"),children:"\u2014"}),se=[{name:Q.TITLE,header:Y[Q.TITLE],width:230,render:({row:e})=>{var s,t;const{name:r,use_embedded_ui:a,preparedBackend:l}=e,n=a&&l?(0,F.t1)(l):(0,J.a)(void 0,{backend:l,clusterName:r}),o=null===(s=e.cluster)||void 0===s?void 0:s.Overall;return(0,V.jsxs)("div",{className:z("cluster"),children:[o?(0,V.jsx)(G.N,{href:n,children:(0,V.jsx)("div",{className:z("cluster-status",{type:o&&o.toLowerCase()})})}):(0,V.jsx)("div",{className:z("cluster-status"),children:(0,V.jsx)(W.B,{content:(0,V.jsx)("span",{className:z("tooltip-content"),children:(null===(t=e.cluster)||void 0===t?void 0:t.error)||L("tooltip_no-cluster-data")}),offset:{left:0}})}),(0,V.jsx)("div",{className:z("cluster-name"),children:(0,V.jsx)(G.N,{href:n,children:e.title})})]})},defaultOrder:a.Ay.ASCENDING},{name:Q.VERSIONS,header:Y[Q.VERSIONS],width:300,defaultOrder:a.Ay.DESCENDING,sortAccessor:({preparedVersions:e})=>e.map((e=>e.version.replace(/^[0-9]\+\./g,""))).sort(((e,s)=>e.localeCompare(s)))[0]||void 0,render:({row:e})=>{const{preparedVersions:s,versions:t=[],name:a,preparedBackend:l}=e;if(!t.length||t.some((e=>!e.version)))return ee;const n=t.reduce(((e,s)=>e+s.count),0),o=t.map((e=>{var t;return{value:e.count/n*100,color:null===(t=s.find((s=>s.version===e.version)))||void 0===t?void 0:t.color}}));return s.length>0&&(0,V.jsx)(G.N,{className:z("cluster-versions"),href:(0,J.a)(J.Bi.versions,{backend:l,clusterName:a}),children:(0,V.jsxs)(r.Fragment,{children:[s.map(((e,s)=>(0,V.jsx)("div",{className:z("cluster-version"),style:{color:e.color},title:e.version,children:e.version},s))),(0,V.jsx)(B.k,{size:"s",value:100,stack:o})]})})}},{name:Q.DC,header:Y[Q.DC],width:120,sortable:!1,render:({row:e})=>{const s=e.cluster&&e.cluster.DataCenters||[];return(0,V.jsx)("div",{className:z("cluster-dc"),children:s.join(", ")||ee})}},{name:Q.SERVICE,header:Y[Q.SERVICE],width:100,sortable:!0},{name:Q.STATUS,header:Y[Q.STATUS],width:150,sortable:!0},{name:Q.NODES,header:Y[Q.NODES],resizeMinWidth:170,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e={}})=>{const{NodesTotal:s=0}=e;return s},render:({row:e})=>{const{NodesAlive:s=0,NodesTotal:t=0,Overall:r}=e.cluster||{};return r?(0,V.jsx)(_.O,{value:s,capacity:t}):ee}},{name:Q.LOAD,header:Y[Q.LOAD],resizeMinWidth:170,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e})=>null===e||void 0===e?void 0:e.NumberOfCpus,render:({row:e})=>{const{LoadAverage:s=0,NumberOfCpus:t=0,RealNumberOfCpus:r,Overall:a}=e.cluster||{};return a?(0,V.jsx)(_.O,{value:s,capacity:null!==r&&void 0!==r?r:t}):ee}},{name:Q.STORAGE,header:Y[Q.STORAGE],resizeMinWidth:170,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e})=>Number(null===e||void 0===e?void 0:e.StorageTotal),render:({row:e})=>{const{StorageUsed:s=0,StorageTotal:t=0,Overall:r}=e.cluster||{};return r?(0,V.jsx)(_.O,{value:s,capacity:t,formatValues:y.ki}):ee}},{name:Q.HOSTS,header:Y[Q.HOSTS],width:80,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e})=>Number(null===e||void 0===e?void 0:e.Hosts)||0,render:({row:e})=>{var s;return Number(null===(s=e.cluster)||void 0===s?void 0:s.Hosts)||ee}},{name:Q.TENANTS,header:Y[Q.TENANTS],width:80,defaultOrder:a.Ay.DESCENDING,sortAccessor:({cluster:e})=>Number(null===e||void 0===e?void 0:e.Tenants)||0,render:({row:e})=>{var s;return Number(null===(s=e.cluster)||void 0===s?void 0:s.Tenants)||ee}},{name:Q.OWNER,header:Y[Q.OWNER],sortable:!1,width:120,render:({row:e})=>{var s;const t=null===(s=e.owner)||void 0===s?void 0:s.split(", ");return null!==t&&void 0!==t&&t.length?t.map((e=>(0,V.jsx)(H,{login:e},e))):ee}},{name:Q.DESCRIPTION,header:Y[Q.DESCRIPTION],sortable:!1,width:150,render:({row:e})=>e.description?(0,V.jsx)("div",{className:z("description"),children:e.description}):ee},{name:Q.BALANCER,header:Y[Q.BALANCER],sortable:!1,width:290,render:({row:e})=>{if(!e.balancer)return ee;const s=(0,q.Zd)(e.balancer);return(0,V.jsxs)("div",{className:z("balancer-cell"),children:[(0,V.jsx)("div",{className:z("balancer-text"),children:s}),(0,V.jsx)(M.b,{size:"s",text:s,className:z("balancer-icon")})]})}}];function te(){const[e]=(0,C.Nt)(),s=m.ub.useGetClustersListQuery(void 0,{pollingInterval:e}),t=(0,C.YQ)(),h=(0,C.N4)(p),N=(0,C.N4)(f),_=(0,C.N4)(S),y=(0,C.N4)(x),{columnsToShow:R,columnsToSelect:I,setColumns:D}=(0,w.K)(se,K,Y,X,[Q.TITLE]),k=s.data,{servicesToSelect:W,versions:G}=r.useMemo((()=>{const e=new Set,s=new Set;return(null!==k&&void 0!==k?k:[]).forEach((t=>{var r,a;t.service&&e.add(t.service),null===(r=t.cluster)||void 0===r||null===(a=r.Versions)||void 0===a||a.forEach((e=>{s.add((0,A.U)(e))}))})),{servicesToSelect:Array.from(e).map((e=>({value:e,content:e}))),versions:Array.from(s).map((e=>({value:e,content:e})))}}),[k]),B=r.useMemo((()=>function(e,s){return e.filter((e=>b(e,s.status)&&E(e,s.service)&&j(e,s.version)&&T(e,s.clusterName)))}(null!==k&&void 0!==k?k:[],{clusterName:h,status:N,service:_,version:y})),[h,k,_,N,y]),M=r.useMemo((()=>function(e){let s=0,t=0,r=0,a=0,l=0,n=0,o=0;const i=new Set;return e.filter((({cluster:e})=>!(null!==e&&void 0!==e&&e.error))).forEach((({cluster:e,hosts:c={}})=>{s+=(null===e||void 0===e?void 0:e.NodesTotal)||0,t+=(null===e||void 0===e?void 0:e.NodesAlive)||0,Object.keys(c).forEach((e=>i.add(e))),o+=Number(null===e||void 0===e?void 0:e.Tenants)||0,r+=Number(null===e||void 0===e?void 0:e.LoadAverage)||0,a+=(0,g.kf)(null===e||void 0===e?void 0:e.RealNumberOfCpus)?null===e||void 0===e?void 0:e.RealNumberOfCpus:(null===e||void 0===e?void 0:e.NumberOfCpus)||0,l+=null!==e&&void 0!==e&&e.StorageUsed?Math.floor(parseInt(e.StorageUsed,10)):0,n+=null!==e&&void 0!==e&&e.StorageTotal?Math.floor(parseInt(e.StorageTotal,10)):0})),{NodesTotal:s,NodesAlive:t,Hosts:i.size,Tenants:o,LoadAverage:r,NumberOfCpus:a,StorageUsed:l,StorageTotal:n}}(B)),[B]),P=r.useMemo((()=>Array.from(new Set((null!==k&&void 0!==k?k:[]).map((e=>e.status)).filter(Boolean))).sort().map((e=>({value:e,content:e})))),[k]);return(0,V.jsxs)("div",{className:z(),children:[(0,V.jsx)(o.mg,{children:(0,V.jsx)("title",{children:L("page_title")})}),(0,V.jsx)(U,{stats:M,count:B.length}),(0,V.jsxs)("div",{className:z("controls"),children:[(0,V.jsx)("div",{className:z("control",{wide:!0}),children:(0,V.jsx)(v.v,{placeholder:L("controls_search-placeholder"),onChange:e=>{t((0,m.Fe)({clusterName:e}))},value:h})}),(0,V.jsx)("div",{className:z("control"),children:(0,V.jsx)(l.l,{multiple:!0,filterable:!0,hasClear:!0,placeholder:L("controls_select-placeholder"),label:L("controls_status-select-label"),value:N,options:P,onUpdate:e=>{t((0,m.Fe)({status:e}))},width:"max"})}),(0,V.jsx)("div",{className:z("control"),children:(0,V.jsx)(l.l,{multiple:!0,filterable:!0,hasClear:!0,placeholder:L("controls_select-placeholder"),label:L("controls_service-select-label"),value:_,options:W,onUpdate:e=>{t((0,m.Fe)({service:e}))},width:"max"})}),(0,V.jsx)("div",{className:z("control"),children:(0,V.jsx)(l.l,{multiple:!0,filterable:!0,hasClear:!0,placeholder:L("controls_select-placeholder"),label:L("controls_version-select-label"),value:y,options:G,onUpdate:e=>{t((0,m.Fe)({version:e}))},width:"max"})}),(0,V.jsx)("div",{className:z("control"),children:(0,V.jsx)(n.O,{popupWidth:242,items:I,showStatus:!0,onUpdate:D,sortable:!1},"TableColumnSetup")}),(0,V.jsx)(i.E,{className:z("autorefresh")})]}),s.isError?(0,V.jsx)(c.o,{error:s.error,className:z("error")}):null,s.isLoading?(0,V.jsx)(d.a,{size:"l"}):null,s.fulfilledTimeStamp?(0,V.jsx)("div",{className:z("table-wrapper"),children:(0,V.jsx)("div",{className:z("table-content"),children:(0,V.jsx)(u.l,{columnsWidthLSKey:Z,wrapperClassName:z("table"),data:B,columns:R,settings:{...O.N3,dynamicRender:!1},initialSortOrder:{columnId:Q.TITLE,order:a.Ay.ASCENDING}})})}):null]})}},52248:(e,s,t)=>{t.d(s,{a:()=>r.a});var r=t(47334)},90053:(e,s,t)=>{t.d(s,{E:()=>h});var r=t(8873),a=t(84476),l=t(24555),n=t(21334),o=t(77506),i=t(90182),c=t(48372);const d=JSON.parse('{"None":"None","15 sec":"15 sec","1 min":"1 min","2 min":"2 min","5 min":"5 min","Refresh":"Refresh"}'),u=(0,c.g4)("ydb-diagnostics-autorefresh-control",{en:d});var v=t(60712);const m=(0,o.cn)("auto-refresh-control");function h({className:e,onManualRefresh:s}){const t=(0,i.YQ)(),[o,c]=(0,i.Nt)();return(0,v.jsxs)("div",{className:m(null,e),children:[(0,v.jsx)(a.$,{view:"flat-secondary",onClick:()=>{t(n.F.util.invalidateTags(["All"])),null===s||void 0===s||s()},extraProps:{"aria-label":u("Refresh")},children:(0,v.jsx)(a.$.Icon,{children:(0,v.jsx)(r.A,{})})}),(0,v.jsxs)(l.l,{value:[String(o)],onUpdate:e=>{c(Number(e))},width:85,qa:"ydb-autorefresh-select",children:[(0,v.jsx)(l.l.Option,{value:"0",children:u("None")}),(0,v.jsx)(l.l.Option,{value:"15000",children:u("15 sec")}),(0,v.jsx)(l.l.Option,{value:"60000",children:u("1 min")}),(0,v.jsx)(l.l.Option,{value:"120000",children:u("2 min")}),(0,v.jsx)(l.l.Option,{value:"300000",children:u("5 min")})]})]})}},95963:(e,s,t)=>{t.d(s,{v:()=>r.v});var r=t(41775)},98192:(e,s,t)=>{t.d(s,{CU:()=>a,om:()=>l});var r=t(82435);const a="gc-",l=((0,r.withNaming)({e:"__",m:"_",v:"_"}),(0,r.withNaming)({n:a,e:"__",m:"_",v:"_"}))}}]); \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/35614.8c037c0d.chunk.js b/ydb/core/viewer/monitoring/static/js/35614.8c037c0d.chunk.js new file mode 100644 index 000000000000..6a4276ae3311 --- /dev/null +++ b/ydb/core/viewer/monitoring/static/js/35614.8c037c0d.chunk.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[35614],{3685:(e,a,s)=>{s.d(a,{$:()=>u});var l=s(54090),t=s(77506),r=s(33775),n=s(60712);const o=(0,t.cn)("ydb-entity-page-title");function u({entityName:e,status:a=l.m.Grey,id:s,className:t}){return(0,n.jsxs)("div",{className:o(null,t),children:[(0,n.jsx)("span",{className:o("prefix"),children:e}),(0,n.jsx)(r.k,{className:o("icon"),status:a,size:"s"}),s]})}},42655:(e,a,s)=>{s.d(a,{y:()=>c});var l=s(59284),t=s(89169),r=s(77506),n=s(66781),o=s(60712);const u=(0,r.cn)("ydb-info-viewer-skeleton"),i=()=>(0,o.jsxs)("div",{className:u("label"),children:[(0,o.jsx)(t.E,{className:u("label__text")}),(0,o.jsx)("div",{className:u("label__dots")})]}),c=({rows:e=8,className:a,delay:s=600})=>{const[r]=(0,n.y)(s);let c=(0,o.jsxs)(l.Fragment,{children:[(0,o.jsx)(i,{}),(0,o.jsx)(t.E,{className:u("value")})]});return r||(c=null),(0,o.jsx)("div",{className:u(null,a),children:[...new Array(e)].map(((e,a)=>(0,o.jsx)("div",{className:u("row"),children:c},`skeleton-row-${a}`)))})}},58389:(e,a,s)=>{s.d(a,{B:()=>p});var l=s(87184),t=s(77506),r=s(90053),n=s(70043),o=s(60712);const u=(0,t.cn)("ydb-page-meta"),i="\xa0\xa0\xb7\xa0\xa0";function c({items:e,loading:a}){return(0,o.jsx)("div",{className:u("info"),children:a?(0,o.jsx)(n.E,{className:u("skeleton")}):e.filter((e=>Boolean(e))).join(i)})}function p({className:e,...a}){return(0,o.jsxs)(l.s,{gap:1,alignItems:"center",justifyContent:"space-between",className:u(null,e),children:[(0,o.jsx)(c,{...a}),(0,o.jsx)(r.E,{})]})}},70043:(e,a,s)=>{s.d(a,{E:()=>n});var l=s(89169),t=s(66781),r=s(60712);const n=({delay:e=600,className:a})=>{const[s]=(0,t.y)(e);return s?(0,r.jsx)(l.E,{className:a}):null}},75510:(e,a,s)=>{s.r(a),s.d(a,{StorageGroupPage:()=>_});var l=s(59284),t=s(44992),r=s(61750),n=s(67087),o=s(3685),u=s(44508),i=s(42655),c=s(58389),p=s(87184),d=s(7435),g=s(56839),v=s(73891),m=s(41650),h=s(60073),f=s(15132),b=s(33775),y=s(48372);const x=JSON.parse('{"encryption":"Encryption","overall":"Overall","disk-space":"Disk Space","media-type":"Media Type","erasure-species":"Erasure Species","used-space":"Used Space","usage":"Usage","read-throughput":"Read Throughput","write-throughput":"Write Throughput","yes":"Yes","no":"No","group-generation":"Group Generation","latency":"Latency","allocation-units":"Units","state":"State","missing-disks":"Missing Disks","available":"Available Space","latency-put-tablet-log":"Latency (Put Tablet Log)","latency-put-user-data":"Latency (Put User Data)","latency-get-fast":"Latency (Get Fast)"}'),N=(0,y.g4)("storage-group-info",{en:x});var j=s(60712);function w({data:e,className:a,...s}){const{Encryption:l,Overall:t,DiskSpace:r,MediaType:n,ErasureSpecies:o,Used:u,Limit:i,Usage:c,Read:y,Write:x,GroupGeneration:w,Latency:k,AllocationUnits:S,State:G,MissingDisks:E,Available:L,LatencyPutTabletLogMs:P,LatencyPutUserDataMs:T,LatencyGetFastMs:A}=e||{},M=[];(0,d.f8)(w)&&M.push({label:N("group-generation"),value:w}),(0,d.f8)(o)&&M.push({label:N("erasure-species"),value:o}),(0,d.f8)(n)&&M.push({label:N("media-type"),value:n}),(0,d.f8)(l)&&M.push({label:N("encryption"),value:N(l?"yes":"no")}),(0,d.f8)(t)&&M.push({label:N("overall"),value:(0,j.jsx)(b.k,{status:t})}),(0,d.f8)(G)&&M.push({label:N("state"),value:G}),(0,d.f8)(E)&&M.push({label:N("missing-disks"),value:E});const $=[];return(0,d.f8)(u)&&(0,d.f8)(i)&&$.push({label:N("used-space"),value:(0,j.jsx)(f.O,{value:Number(u),capacity:Number(i),formatValues:g.vX,colorizeProgress:!0})}),(0,d.f8)(L)&&$.push({label:N("available"),value:(0,g.vX)(Number(L))}),(0,d.f8)(c)&&$.push({label:N("usage"),value:`${c.toFixed(2)}%`}),(0,d.f8)(r)&&$.push({label:N("disk-space"),value:(0,j.jsx)(b.k,{status:r})}),(0,d.f8)(k)&&$.push({label:N("latency"),value:(0,j.jsx)(b.k,{status:k})}),(0,d.f8)(P)&&$.push({label:N("latency-put-tablet-log"),value:(0,v.Xo)(P)}),(0,d.f8)(T)&&$.push({label:N("latency-put-user-data"),value:(0,v.Xo)(T)}),(0,d.f8)(A)&&$.push({label:N("latency-get-fast"),value:(0,v.Xo)(A)}),(0,d.f8)(S)&&$.push({label:N("allocation-units"),value:S}),(0,d.f8)(y)&&$.push({label:N("read-throughput"),value:(0,m.O4)(Number(y))}),(0,d.f8)(x)&&$.push({label:N("write-throughput"),value:(0,m.O4)(Number(x))}),(0,j.jsxs)(p.s,{className:a,gap:2,direction:"row",wrap:!0,children:[(0,j.jsx)(h.z_,{info:M,...s}),(0,j.jsx)(h.z_,{info:$,...s})]})}var k=s(67028),S=s(40174),G=s(10174),E=s(54090),L=s(77506),P=s(90182),T=s(99936);const A=JSON.parse('{"storage-group":"Storage Group","storage":"Storage","pool-name":"Pool Name"}'),M=(0,y.g4)("ydb-storage-group-page",{en:A}),$=(0,L.cn)("ydb-storage-group-page");function _(){var e,a;const s=(0,P.YQ)(),p=l.useRef(null),[{groupId:g}]=(0,n.useQueryParams)({groupId:n.StringParam});l.useEffect((()=>{s((0,S.g)("storageGroup",{groupId:g}))}),[s,g]);const[v]=(0,P.Nt)(),m=(0,k.YA)(),h=(0,k.Pm)(),f=G.S.useGetStorageGroupsInfoQuery((0,d.f8)(g)?{groupId:g,shouldUseGroupsHandler:m,with:"all",fieldsRequired:"all"}:t.hT,{pollingInterval:v,skip:!h}),b=null===(e=f.data)||void 0===e||null===(a=e.groups)||void 0===a?void 0:a[0],y=f.isFetching&&void 0===b;return(0,j.jsxs)("div",{className:$(null),ref:p,children:[(()=>{const e=g?`${M("storage-group")} ${g}`:M("storage-group");return(0,j.jsx)(r.mg,{titleTemplate:`%s - ${e} \u2014 YDB Monitoring`,defaultTitle:`${e} \u2014 YDB Monitoring`})})(),(()=>{if(!g)return null;const e=[`${M("pool-name")}: ${null===b||void 0===b?void 0:b.PoolName}`];return(0,j.jsx)(c.B,{className:$("meta"),loading:y,items:e})})(),(0,j.jsx)(o.$,{className:$("title"),entityName:M("storage-group"),status:(null===b||void 0===b?void 0:b.Overall)||E.m.Grey,id:g}),f.error?(0,j.jsx)(u.o,{error:f.error}):null,y?(0,j.jsx)(i.y,{className:$("info"),rows:10}):(0,j.jsx)(w,{data:b,className:$("info")}),g?(0,j.jsxs)(l.Fragment,{children:[(0,j.jsx)("div",{className:$("storage-title"),children:M("storage")}),(0,j.jsx)(T.z,{groupId:g,parentRef:p,viewContext:{groupId:null===g||void 0===g?void 0:g.toString()}})]}):null]})}},79879:(e,a,s)=>{s.d(a,{A:()=>t});var l=s(59284);const t=e=>l.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),l.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"m3.003 4.702 4.22-2.025a1.8 1.8 0 0 1 1.554 0l4.22 2.025a.89.89 0 0 1 .503.8V6a8.55 8.55 0 0 1-3.941 7.201l-.986.631a1.06 1.06 0 0 1-1.146 0l-.986-.63A8.55 8.55 0 0 1 2.5 6v-.498c0-.341.196-.652.503-.8m3.57-3.377L2.354 3.35A2.39 2.39 0 0 0 1 5.502V6a10.05 10.05 0 0 0 4.632 8.465l.986.63a2.56 2.56 0 0 0 2.764 0l.986-.63A10.05 10.05 0 0 0 15 6v-.498c0-.918-.526-1.755-1.354-2.152l-4.22-2.025a3.3 3.3 0 0 0-2.852 0M9.5 7a1.5 1.5 0 0 1-.75 1.3v1.95a.75.75 0 0 1-1.5 0V8.3A1.5 1.5 0 1 1 9.5 7",clipRule:"evenodd"}))}}]); \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/47512.39fd7220.chunk.js b/ydb/core/viewer/monitoring/static/js/47512.39fd7220.chunk.js deleted file mode 100644 index 11d98fdc2b13..000000000000 --- a/ydb/core/viewer/monitoring/static/js/47512.39fd7220.chunk.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[47512],{14188:(e,s,n)=>{n.r(s),n.d(s,{Cluster:()=>Ws});var t=n(59284),l=n(89169),r=n(23871),a=n(61750),o=n(10755),i=n(67087),d=n(90053),c=n(10508),u=n(44294),v=n(92459),h=n(67028),m=n(67157),p=n(40174),g=n(77506),j=n(90182),x=n(7117),N=n(99936),f=n(88616),b=n(93381),y=n(64470),C=n(4557),k=n(84476),w=n(99991),T=n(40569),_=n(28539),S=n(44508),E=n(78524),V=n(48295),O=n(9252),D=n(17594),L=n(95963),A=n(89073),M=n(23900),z=n(87184),I=n(54309),G=n(12888),P=n(25196),R=n(48372);const $=JSON.parse('{"field_links":"Links","field_monitoring-link":"Monitoring","field_logs-link":"Logs","context_unknown":"unknown database"}'),B=(0,R.g4)("ydb-tenant-name-wrapper",{en:$});var U=n(60712);function F({tenant:e,additionalTenantsProps:s}){var n,t;const l=(0,G.X)(),r=((e,s)=>{var n,t;if("function"!==typeof(null===s||void 0===s?void 0:s.prepareTenantBackend))return;let l=null!==(n=e.MonitoringEndpoint)&&void 0!==n?n:e.backend;const r=null!==(t=e.NodeIds)&&void 0!==t?t:e.sharedNodeIds;!l&&r&&r.length>0&&(l={NodeId:r[Math.floor(Math.random()*r.length)]});return s.prepareTenantBackend(l)})(e,s),a=Boolean(r),o=null===s||void 0===s||null===(n=s.getMonitoringLink)||void 0===n?void 0:n.call(s,e.Name,e.Type),i=null===s||void 0===s||null===(t=s.getLogsLink)||void 0===t?void 0:t.call(s,e.Name),d=(o||i)&&l?(0,U.jsx)(M.u,{responsive:!0,children:(0,U.jsx)(M.u.Item,{name:B("field_links"),children:(0,U.jsxs)(z.s,{gap:2,wrap:"wrap",children:[o&&(0,U.jsx)(P.K,{title:B("field_monitoring-link"),url:o}),i&&(0,U.jsx)(P.K,{title:B("field_logs-link"),url:i})]})})}):null;return(0,U.jsx)(c.c,{externalLink:a,name:e.Name||B("context_unknown"),withLeftTrim:!0,status:e.Overall,infoPopoverContent:d,hasClipboardButton:!0,path:(0,I.YL)({database:e.Name,backend:r})})}var W=n(88610),Z=n(53850),q=n(23536),H=n.n(q),Q=n(54090),Y=n(76086),K=n(56674);const J=(0,Z.Mz)((e=>e),(e=>K.GJ.endpoints.getTenantsInfo.select({clusterName:e}))),X=(0,Z.Mz)((e=>e),((e,s)=>J(s)),(e=>(0,W.CN)(e,Y.Xm)),((e,s,n)=>{var t;const l=null!==(t=s(e).data)&&void 0!==t?t:[];return!n&&l.length>1?l.filter((e=>"Domain"!==e.Type)):l})),ee=e=>e.tenants.searchValue,se=(0,Z.Mz)([X,W.yV,ee],((e,s,n)=>{let t=((e,s)=>s===W.s$.ALL?e:e.filter((e=>e.Overall&&e.Overall!==Q.m.Green)))(e,s);return t=((e,s)=>e.filter((e=>{const n=new RegExp(H()(s),"i");return n.test(e.Name||"")||n.test(e.controlPlaneName)})))(t,n),t})),ne={};const te=new Proxy(ne,{set:()=>{throw new Error("Use configureUIFactory(...) method instead of direct modifications")}});var le=n(56839),re=n(28232);const ae=JSON.parse('{"create-database":"Create database","remove":"Remove"}'),oe=(0,R.g4)("ydb-tenants-table",{en:ae}),ie=(0,g.cn)("tenants"),de=({additionalTenantsProps:e})=>{const s=(0,j.YQ)(),n=(0,re.H)(),[l]=(0,j.Nt)(),{currentData:r,isFetching:a,error:o}=K.GJ.useGetTenantsInfoQuery({clusterName:n},{pollingInterval:l}),i=a&&void 0===r,d=(0,h.sH)()&&void 0!==te.onCreateDB,c=(0,h.TW)()&&void 0!==te.onDeleteDB,u=(0,j.N4)((e=>X(e,n))),v=(0,j.N4)(ee),m=(0,j.N4)((e=>se(e,n))),p=(0,j.N4)(W.yV),g=e=>{s((0,W.$u)(e))},x=e=>{s((0,K.gB)(e))};return(0,U.jsx)("div",{className:ie("table-wrapper"),children:(0,U.jsxs)(A.L,{children:[(0,U.jsx)(A.L.Controls,{className:ie("controls"),children:(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)(L.v,{value:v,onChange:x,placeholder:"Database name",className:ie("search")}),(0,U.jsx)(O.k,{value:p,onChange:g}),(0,U.jsx)(_.T,{total:u.length,current:(null===m||void 0===m?void 0:m.length)||0,label:"Databases",loading:i}),d&&n?(0,U.jsxs)(k.$,{view:"action",onClick:()=>{var e;return null===(e=te.onCreateDB)||void 0===e?void 0:e.call(te,{clusterName:n})},className:ie("create-database"),children:[(0,U.jsx)(w.I,{data:b.A}),oe("create-database")]}):null]})}),o?(0,U.jsx)(S.o,{error:o}):null,(0,U.jsx)(A.L.Table,{loading:i,children:r?(()=>{const s=[{name:"Name",header:"Database",render:({row:s})=>(0,U.jsx)(F,{tenant:s,additionalTenantsProps:e}),width:440,sortable:!0,defaultOrder:C.Ay.DESCENDING},{name:"controlPlaneName",header:"Name",render:({row:e})=>e.controlPlaneName,width:200,sortable:!0,defaultOrder:C.Ay.DESCENDING},{name:"Type",width:200,resizeMinWidth:150,render:({row:e})=>"Serverless"!==e.Type?e.Type:(0,U.jsxs)("div",{className:ie("type"),children:[(0,U.jsx)("span",{className:ie("type-value"),children:e.Type}),(0,U.jsx)(k.$,{className:ie("type-button"),onClick:()=>x(e.sharedTenantName||""),children:"Show shared"})]})},{name:"State",width:90,render:({row:e})=>e.State?e.State.toLowerCase():"\u2014",customStyle:()=>({textTransform:"capitalize"})},{name:"cpu",header:"CPU",width:80,render:({row:e})=>e.cpu&&e.cpu>1e4?(0,le.iM)(e.cpu):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"memory",header:"Memory",width:120,render:({row:e})=>e.memory?(0,le.vX)(e.memory):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"storage",header:"Storage",width:120,render:({row:e})=>e.storage?(0,le.vX)(e.storage):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"nodesCount",header:"Nodes",width:100,render:({row:e})=>e.nodesCount?(0,le.ZV)(e.nodesCount):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"groupsCount",header:"Groups",width:100,render:({row:e})=>e.groupsCount?(0,le.ZV)(e.groupsCount):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"PoolStats",header:"Pools",width:100,resizeMinWidth:60,sortAccessor:({PoolStats:e=[]})=>e.reduce(((e,s)=>e+(s.Usage||0)),0),defaultOrder:C.Ay.DESCENDING,align:C.Ay.LEFT,render:({row:e})=>(0,U.jsx)(V._,{pools:e.PoolStats})}];return c&&s.push({name:"actions",header:"",width:40,resizeable:!1,align:C.Ay.CENTER,render:({row:e})=>{var s;const t=null===(s=e.UserAttributes)||void 0===s?void 0:s.database_id,l=e.Name;let r=[];return n&&l&&t&&(r=[{text:oe("remove"),iconStart:(0,U.jsx)(y.A,{}),action:()=>{var e;null===(e=te.onDeleteDB)||void 0===e||e.call(te,{clusterName:n,databaseId:t,databaseName:l})},className:ie("remove-db")}]),r.length?(0,U.jsx)(T.r,{defaultSwitcherProps:{view:"flat",size:"s",pin:"brick-brick"},items:r}):null}}),0===m.length&&p!==W.s$.ALL?(0,U.jsx)(E.v,{name:"thumbsUp",width:"200"}):(0,U.jsx)(D.l,{columnsWidthLSKey:"databasesTableColumnsWidth",data:m,columns:s,settings:Y.N3,emptyDataMessage:"No such tenants"})})():null})]})})};var ce=n(44433),ue=n(74321),ve=n(98167),he=n(15298),me=n(18143);const pe=(0,g.cn)("ydb-cluster-versions-bar"),ge=({versionsValues:e=[],size:s="s",progressClassName:n})=>(0,U.jsxs)("div",{className:pe(),children:[(0,U.jsx)(me.k,{value:100,stack:e,size:s,className:n}),(0,U.jsx)("div",{className:pe("versions"),children:e.map(((s,n)=>(0,U.jsx)("div",{className:pe("version-title"),style:{color:s.color},title:s.version,children:`${s.version}${n===e.length-1?"":","}`},s.version)))})]});var je=n(63126),xe=n(78762),Ne=n(88655);function fe(e){return[(0,xe._E)(),(0,xe.Nh)(e),(0,xe.jl)(),(0,xe.pH)(),(0,xe.fr)(),(0,xe.ID)()]}const be=({nodes:e})=>{const s=(0,Ne.E)(),n=fe({getNodeRef:null===s||void 0===s?void 0:s.getNodeRef});return(0,U.jsx)(D.l,{columnsWidthLSKey:"versionsTableColumnsWidth",data:e,columns:n,settings:Y.N3})};var ye=n(96873);const Ce=(0,g.cn)("ydb-versions-nodes-tree-title"),ke=({title:e,nodes:s,items:n,versionColor:t,versionsValues:l})=>{let r;return r=n?n.reduce(((e,s)=>s.nodes?e+s.nodes.length:e),0):s?s.length:0,(0,U.jsxs)("div",{className:Ce("overview"),children:[(0,U.jsxs)("div",{className:Ce("overview-container"),children:[t?(0,U.jsx)("div",{className:Ce("version-color"),style:{background:t}}):null,e?(0,U.jsxs)("span",{className:Ce("overview-title"),children:[e,(0,U.jsx)(ye.b,{text:e,size:"s",className:Ce("clipboard-button"),view:"normal"})]}):null]}),(0,U.jsxs)("div",{className:Ce("overview-info"),children:[(0,U.jsxs)("div",{children:[(0,U.jsx)("span",{className:Ce("info-value"),children:r}),(0,U.jsx)("span",{className:Ce("info-label",{margin:"left"}),children:"Nodes"})]}),l?(0,U.jsxs)("div",{className:Ce("version-progress"),children:[(0,U.jsx)("span",{className:Ce("info-label",{margin:"right"}),children:"Versions"}),(0,U.jsx)(me.k,{size:"s",value:100,stack:l})]}):null]})]})},we=(0,g.cn)("ydb-versions-grouped-node-tree"),Te=({title:e,nodes:s,items:n,expanded:l=!1,versionColor:r,versionsValues:a,level:o=0})=>{const[i,d]=t.useState(!1);t.useEffect((()=>{d(l)}),[l]);const c=(0,U.jsx)(ke,{title:e,nodes:s,items:n,versionColor:r,versionsValues:a}),u=()=>{d((e=>!e))};return n?(0,U.jsx)("div",{className:we({"first-level":0===o}),children:(0,U.jsx)(je.G,{name:c,collapsed:!i,hasArrow:!0,onClick:u,onArrowClick:u,children:n.map(((e,s)=>(0,U.jsx)(Te,{title:e.title,nodes:e.nodes,expanded:l,versionColor:e.versionColor,level:o+1},s)))},e)}):(0,U.jsx)("div",{className:we({"first-level":0===o}),children:(0,U.jsx)(je.G,{name:c,collapsed:!i,hasArrow:!0,onClick:u,onArrowClick:u,children:(0,U.jsx)("div",{className:we("dt-wrapper"),children:(0,U.jsx)(be,{nodes:s||[]})})},e)})};var _e=n(78018),Se=n.n(_e),Ee=n(38596);const Ve=.5,Oe=(e=[],s)=>{const n=e.reduce(((e,s)=>(s.Version&&(e[s.Version]?e[s.Version]=e[s.Version]+1:e[s.Version]=1),e)),{});return Le(Object.keys(n).map((t=>{const l=n[t]/e.length*100;return{title:t,version:t,color:null===s||void 0===s?void 0:s.get((0,Ee.U)(t)),value:le+s.count),0);return Le(e.map((e=>{const n=e.count/t*100;return{title:e.name,version:e.name,color:null===s||void 0===s?void 0:s.get(e.name),value:n{t+=e.value,e.value>s&&(s=e.value,n=l)}));const l=[...e];return l[n]={...e[n],value:s+100-t},l}let Ae=function(e){return e.VERSION="Version",e.TENANT="Database",e.STORAGE="Storage",e}({});const Me=(e,s)=>{var n;return(null===(n=e.title)||void 0===n?void 0:n.localeCompare(s.title||""))||-1},ze=(e,s,n)=>{if(e&&e.length){if(n===Ae.VERSION){const n=Se()(e,"Version");return Object.keys(n).map((e=>{const t=n[e].filter((({Tenants:e})=>Boolean(e))),l=Se()(t,"Tenants"),r=Object.keys(l).map((e=>({title:e,nodes:l[e]}))).sort(Me);return r.length?{title:e,items:r,versionColor:null===s||void 0===s?void 0:s.get((0,Ee.U)(e))}:null})).filter((e=>Boolean(e)))}{const n=e.filter((({Tenants:e})=>Boolean(e))),t=Se()(n,"Tenants");return Object.keys(t).map((e=>{const n=Oe(t[e],s),l=Se()(t[e],"Version"),r=Object.keys(l).map((e=>({title:e,nodes:l[e],versionColor:null===s||void 0===s?void 0:s.get((0,Ee.U)(e))})));return r.length?{title:e,items:r,versionsValues:n}:null})).filter((e=>Boolean(e))).sort(Me)}}},Ie=(e,s)=>{if(!e||!e.length)return;const n=e.filter((({Roles:e})=>null===e||void 0===e?void 0:e.includes("Storage"))),t=Se()(n,"Version");return Object.keys(t).map((e=>({title:e,nodes:t[e],versionColor:null===s||void 0===s?void 0:s.get((0,Ee.U)(e))})))},Ge=(e,s)=>{if(!e||!e.length)return;const n=e.filter((({Roles:e,Version:s})=>!e&&s)),t=Se()(n,"Version");return Object.keys(t).map((e=>({title:e,nodes:t[e],versionColor:null===s||void 0===s?void 0:s.get((0,Ee.U)(e))})))},Pe=JSON.parse('{"title_overall":"Overall","title_storage":"Storage nodes","title_database":"Database nodes","title_other":"Other nodes"}'),Re=(0,R.g4)("ydb-versions",{en:Pe});var $e=n(44992),Be=n(39567),Ue=n(98730),Fe=n(40537),We=n(66592);const Ze=({cluster:e,versionToColor:s,clusterLoading:n})=>{const{currentData:l}=he.s.useGetNodesQuery((0,Ue.L)(e)||n?$e.hT:{tablets:!1,fieldsRequired:["SystemState","SubDomainKey"],group:"Version"});return t.useMemo((()=>{if((0,Ue.L)(e)&&e.MapVersions){return De(Object.entries(e.MapVersions).map((([e,s])=>({name:e,count:s}))),s,e.NodesTotal)}return l?Array.isArray(l.NodeGroups)?De(l.NodeGroups,s,null===e||void 0===e?void 0:e.NodesTotal):Oe(l.Nodes,s):[]}),[l,s,e])};function qe(e){const s=function(){const[e]=(0,i.useQueryParam)("clusterName",i.StringParam),s=(0,j.N4)((e=>e.singleClusterMode)),{data:n}=Be.ub.useGetClustersListQuery(void 0,{skip:s});return t.useMemo((()=>{if(s)return;const t=(n||[]).find((s=>s.name===e)),l=(null===t||void 0===t?void 0:t.versions)||[];return()=>(0,Fe.Vm)((0,Fe.HD)(l))}),[s,n,e])}();return t.useMemo((()=>s?s():(0,We._n)(null===e||void 0===e?void 0:e.Versions)),[null===e||void 0===e?void 0:e.Versions,s])}const He=(0,g.cn)("ydb-versions");function Qe({cluster:e,loading:s}){const[n]=(0,j.Nt)(),{currentData:t,isLoading:l}=he.s.useGetNodesQuery({tablets:!1,fieldsRequired:["SystemState","SubDomainKey"]},{pollingInterval:n}),r=qe(),a=Ze({cluster:e,versionToColor:r,clusterLoading:s});return(0,U.jsx)(ve.r,{loading:s||l,children:(0,U.jsx)(Ye,{versionsValues:a,nodes:null===t||void 0===t?void 0:t.Nodes,versionToColor:r})})}function Ye({versionsValues:e,nodes:s,versionToColor:n}){const[l,r]=t.useState(Ae.VERSION),[a,o]=t.useState(!1),i=e=>{r(e)},d=ze(s,n,l),c=Ie(s,n),u=Ge(s,n),v=null!==c&&void 0!==c&&c.length?(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)("h4",{children:Re("title_storage")}),c.map((({title:e,nodes:s,items:n,versionColor:t})=>(0,U.jsx)(Te,{title:e,nodes:s,items:n,versionColor:t},`storage-nodes-${e}`)))]}):null,h=null!==d&&void 0!==d&&d.length?(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)("h4",{children:Re("title_database")}),(0,U.jsxs)("div",{className:He("controls"),children:[(0,U.jsxs)("div",{className:He("group"),children:[(0,U.jsx)("span",{className:He("label"),children:"Group by:"}),(0,U.jsxs)(ce.a,{value:l,onUpdate:i,children:[(0,U.jsx)(ce.a.Option,{value:Ae.TENANT,children:Ae.TENANT}),(0,U.jsx)(ce.a.Option,{value:Ae.VERSION,children:Ae.VERSION})]})]}),(0,U.jsx)(ue.S,{className:He("checkbox"),onChange:()=>o((e=>!e)),checked:a,children:"All expanded"})]}),d.map((({title:e,nodes:s,items:n,versionColor:t,versionsValues:l})=>(0,U.jsx)(Te,{title:e,nodes:s,items:n,expanded:a,versionColor:t,versionsValues:l},`tenant-nodes-${e}`)))]}):null,m=null!==u&&void 0!==u&&u.length?(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)("h4",{children:Re("title_other")}),u.map((({title:e,nodes:s,items:n,versionColor:t,versionsValues:l})=>(0,U.jsx)(Te,{title:e,nodes:s,items:n,versionColor:t,versionsValues:l},`other-nodes-${e}`)))]}):null,p=(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)("h4",{children:Re("title_overall")}),(0,U.jsx)("div",{className:He("overall-wrapper"),children:(0,U.jsx)(ge,{progressClassName:He("overall-progress"),versionsValues:e.filter((e=>"unknown"!==e.title)),size:"m"})})]});return(0,U.jsxs)("div",{className:He(),children:[p,v,h,m]})}var Ke=n(98089);const Je=(0,g.cn)("tag"),Xe=({text:e,type:s})=>(0,U.jsx)("div",{className:Je({type:s}),children:e}),es=({tags:e,tagsType:s,className:n="",gap:t=1})=>(0,U.jsx)(z.s,{className:n,gap:t,wrap:"wrap",alignItems:"center",children:e&&e.map(((e,n)=>(0,U.jsx)(Xe,{text:e,type:s},n)))});var ss=n(7435);const ns=JSON.parse('{"disk-type":"Disk Type","erasure":"Erasure","allocated":"Allocated","available":"Available","usage":"Usage","label_nodes-state":"Nodes state","label_dc":"Nodes data centers","storage-size":"Storage size","storage-groups":"Storage groups, {{diskType}}","links":"Links","link_cores":"Coredumps","link_logging":"Logging","link_slo-logs":"SLO Logs","context_cores":"cores","title_cpu":"CPU","title_storage":"Storage","title_memory":"Memory","title_info":"Info","title_links":"Links","label_nodes":"Nodes","label_hosts":"Hosts","label_storage-groups":"Storage groups","label_databases":"Databases","label_load":"Load"}'),ts=(0,R.g4)("ydb-cluster",{en:ns});var ls=n(2102);const rs=(0,g.cn)("ydb-doughnut-metrics");function as({status:e,fillWidth:s,children:n,className:t}){let l="var(--g-color-line-generic-solid)",r=3.6*s-90;s>50&&(l="var(--doughnut-color)",r=3.6*s+90);const a=r;return(0,U.jsx)("div",{className:rs(null,t),children:(0,U.jsx)("div",{style:{backgroundImage:`linear-gradient(${a}deg, transparent 50%, ${l} 50%), linear-gradient(-90deg, var(--g-color-line-generic-solid) 50%, transparent 50%)`},className:rs("doughnut",{status:e}),children:(0,U.jsx)("div",{className:rs("text-wrapper"),children:n})})})}as.Legend=function({children:e,variant:s="subheader-3"}){return(0,U.jsx)(Ke.E,{variant:s,color:"secondary",className:rs("legend"),children:e})},as.Value=function({children:e,variant:s="subheader-2"}){return(0,U.jsx)(Ke.E,{variant:s,color:"secondary",className:rs("value"),children:e})};var os=n(70043);const is=(0,g.cn)("ydb-cluster-dashboard");function ds({children:e,title:s,size:n,className:t}){return(0,U.jsxs)(ls.A,{className:is("card",{size:n},t),size:n,interactive:!1,children:[s?(0,U.jsx)(Ke.E,{variant:"subheader-3",className:is("card-title"),children:s}):null,e]})}function cs({title:e,children:s,size:n,...t}){return(0,U.jsx)(ds,{title:e,size:n,children:(0,U.jsx)(as,{...t,className:is("doughnut"),children:s})})}function us(){return(0,U.jsx)(ds,{className:is("skeleton-wrapper"),children:(0,U.jsx)(os.E,{className:is("skeleton")})})}function vs(){return(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)(us,{}),(0,U.jsx)(us,{}),(0,U.jsx)(us,{})]})}var hs=n(35736),ms=n(57439),ps=n(24543),gs=n(46549);const js=(0,g.cn)("ydb-disk-groups-stats"),xs=({stats:e,children:s})=>(0,U.jsx)("div",{className:js(),children:(0,U.jsx)(ps.u,{placement:["right"],pinOnClick:!0,content:(0,U.jsx)(Ns,{stats:e}),children:s})});function Ns({stats:e}){const{diskType:s,erasure:n,allocatedSize:t,availableSize:l}=e,r=(0,gs.fn)(Math.max(t,l)),a=(0,gs.z3)({value:t,size:r}),o=(0,gs.z3)({value:l,size:r}),i=Math.round(t/(t+l)*100),d=[{name:ts("disk-type"),content:s},{name:ts("erasure"),content:n},{name:ts("allocated"),content:a},{name:ts("available"),content:o},{name:ts("usage"),content:i+"%"}];return(0,U.jsx)(ms.u,{items:d,className:js("popup-content"),responsive:!0})}function fs({value:e,capacity:s,colorizeProgress:n=!0,warningThreshold:t,dangerThreshold:l,inverseColorize:r=!1,legendFormatter:a}){const o=parseFloat(String(e)),i=parseFloat(String(s));let d=o/i*100||0;d=d>100?100:d;const c=d<1?.5:d;return{status:(0,hs.w)({fillWidth:d,warningThreshold:t,dangerThreshold:l,colorizeProgress:n,inverseColorize:r}),percents:(0,le.l9)(d/100),legend:a({value:o,capacity:i}),fill:c}}const bs=["storage","tenant"];const ys=e=>Object.values(e).reduce(((e,s)=>(Object.values(s).forEach((s=>{e+=s.createdGroups})),e)),0);function Cs({value:e,capacity:s}){let n=[];return n=s<1e4?[(0,le.ZV)(Math.round(e)),(0,le.ZV)(Math.round(s))]:(0,le.Nd)(e,s,void 0,"",!0),`${n[0]} / ${n[1]}\n${ts("context_cores")}`}function ks({value:e,capacity:s,...n}){const{status:t,percents:l,legend:r,fill:a}=fs({value:e,capacity:s,legendFormatter:Cs,...n});return(0,U.jsxs)(cs,{status:t,fillWidth:a,title:ts("title_cpu"),children:[(0,U.jsx)(as.Legend,{children:r}),(0,U.jsx)(as.Value,{children:l})]})}function ws({value:e,capacity:s}){const n=(0,le.j9)(e,s,void 0,"\n");return`${n[0]} / ${n[1]}`}function Ts({value:e,capacity:s,...n}){const{status:t,percents:l,legend:r,fill:a}=fs({value:e,capacity:s,legendFormatter:ws,...n});return(0,U.jsxs)(cs,{status:t,fillWidth:a,title:ts("title_memory"),children:[(0,U.jsx)(as.Legend,{children:r}),(0,U.jsx)(as.Value,{children:l})]})}function _s({value:e,capacity:s}){const n=(0,le.j9)(e,s,void 0,"\n");return`${n[0]} / ${n[1]}`}function Ss({value:e,capacity:s,...n}){const{status:t,percents:l,legend:r,fill:a}=fs({value:e,capacity:s,legendFormatter:_s,...n});return(0,U.jsxs)(cs,{status:t,fillWidth:a,title:ts("title_storage"),children:[(0,U.jsx)(as.Legend,{children:r}),(0,U.jsx)(as.Value,{children:l})]})}function Es({value:e}){return(0,ss.f8)(e)?(0,U.jsx)(Ke.E,{variant:"subheader-3",color:"secondary",children:(0,le.ZV)(e)}):null}function Vs({cluster:e,...s}){return s.error?(0,U.jsx)(S.o,{error:s.error,className:is("error")}):(0,U.jsx)("div",{className:is(),children:(0,U.jsxs)(z.s,{gap:4,wrap:!0,children:[(0,U.jsx)(z.s,{gap:4,wrap:"nowrap",children:(0,U.jsx)(Os,{...s,cluster:e})}),(0,U.jsx)("div",{className:is("cards-container"),children:(0,U.jsx)(Ds,{...s,cluster:e})})]})})}function Os({cluster:e,loading:s}){if(s)return(0,U.jsx)(vs,{});const n=[];if((0,Ue.L)(e)){const{CoresUsed:s,NumberOfCpus:t,CoresTotal:l}=e,r=null!==l&&void 0!==l?l:t;(0,ss.f8)(s)&&(0,ss.f8)(r)&&n.push((0,U.jsx)(ks,{value:s,capacity:r},"cores"))}const{StorageTotal:t,StorageUsed:l}=e;(0,ss.f8)(t)&&(0,ss.f8)(l)&&n.push((0,U.jsx)(Ss,{value:l,capacity:t},"storage"));const{MemoryTotal:r,MemoryUsed:a}=e;return(0,ss.f8)(r)&&(0,ss.f8)(a)&&n.push((0,U.jsx)(Ts,{value:a,capacity:r},"memory")),n}function Ds({cluster:e,groupStats:s={},loading:n}){if(n)return null;const l=[],r=function(e){const s=[];if((0,Ue.L)(e)&&e.MapNodeRoles)for(const[n,l]of Object.entries(e.MapNodeRoles))bs.includes(n.toLowerCase())&&s.push((0,U.jsxs)(t.Fragment,{children:[n,": ",(0,le.ZV)(l)]},n));return s}(e);if(l.push((0,U.jsx)(ds,{size:"l",title:ts("label_nodes"),children:(0,U.jsxs)(z.s,{gap:2,direction:"column",children:[(0,U.jsx)(Es,{value:null===e||void 0===e?void 0:e.NodesAlive}),null!==r&&void 0!==r&&r.length?(0,U.jsx)(es,{tags:r,gap:3}):null]})},"roles")),Object.keys(s).length){const e=function(e){const s=[];return Object.entries(e).forEach((([e,n])=>{Object.values(n).forEach((n=>{s.push((0,U.jsxs)(xs,{stats:n,children:[e,": ",(0,le.ZV)(n.createdGroups)," /"," ",(0,le.ZV)(n.totalGroups)]},`${e}|${n.erasure}`))}))})),s}(s),n=ys(s);l.push((0,U.jsx)(ds,{size:"l",title:ts("label_storage-groups"),children:(0,U.jsxs)(z.s,{gap:2,direction:"column",children:[(0,U.jsx)(Es,{value:n}),(0,U.jsx)(es,{tags:e,gap:3})]})},"groups"))}const a=function(e){var s;return(0,Ue.L)(e)&&e.MapDataCenters?Object.keys(e.MapDataCenters):null===(s=e.DataCenters)||void 0===s?void 0:s.filter(Boolean)}(e);return null!==a&&void 0!==a&&a.length&&l.push((0,U.jsx)(ds,{size:"l",title:ts("label_hosts"),children:(0,U.jsxs)(z.s,{gap:2,direction:"column",children:[(0,U.jsx)(Es,{value:null===e||void 0===e?void 0:e.Hosts}),(0,U.jsx)(es,{tags:a,gap:3})]})},"hosts")),e.Tenants&&l.push((0,U.jsx)(ds,{size:"l",title:ts("label_databases"),children:(0,U.jsx)(Es,{value:null===e||void 0===e?void 0:e.Tenants})},"tenants")),l}var Ls=n(42655);const As=(0,g.cn)("cluster-info");var Ms=n(41650);function zs(){const{cores:e,logging:s}=(0,m.Zd)();return t.useMemo((()=>{const n=[],t=function(e){try{const s=(0,Ms.qF)(e);if(s&&"object"===typeof s&&"url"in s&&"string"===typeof s.url)return s.url}catch{}}(e),{logsUrl:l,sloLogsUrl:r}=function(e){try{const s=(0,Ms.qF)(e);if(s&&"object"===typeof s){return{logsUrl:"url"in s&&"string"===typeof s.url?s.url:void 0,sloLogsUrl:"slo_logs_url"in s&&"string"===typeof s.slo_logs_url?s.slo_logs_url:void 0}}}catch{}return{}}(s);return t&&n.push({title:ts("link_cores"),url:t}),l&&n.push({title:ts("link_logging"),url:l}),r&&n.push({title:ts("link_slo-logs"),url:r}),n}),[e,s])}var Is=n(15132);const Gs=(0,g.cn)("ydb-nodes-state");function Ps({state:e,children:s}){return(0,U.jsx)("div",{className:Gs({[e.toLowerCase()]:!0}),children:s})}const Rs={Green:5,Blue:4,Yellow:3,Orange:2,Red:1,Grey:0},$s=(e,s)=>{var n;const l=[];if((0,Ue.L)(e)&&e.MapNodeStates){const s=Object.entries(e.MapNodeStates);s.sort(((e,s)=>Rs[s[0]]-Rs[e[0]]));const n=s.map((([e,s])=>(0,U.jsx)(Ps,{state:e,children:(0,le.ZV)(s)},e)));l.push({label:ts("label_nodes-state"),value:(0,U.jsx)(z.s,{gap:2,children:n})})}const r=(e=>{if((0,Ue.L)(e)&&e.MapDataCenters)return Object.entries(e.MapDataCenters).map((([e,s])=>(0,U.jsxs)(t.Fragment,{children:[e,": ",(0,le.ZV)(s)]},e)))})(e);return null!==r&&void 0!==r&&r.length&&l.push({label:ts("label_dc"),value:(0,U.jsx)(es,{tags:r,gap:2,className:As("dc")})}),l.push({label:ts("label_load"),value:(0,U.jsx)(Is.O,{value:null===e||void 0===e?void 0:e.LoadAverage,capacity:null!==(n=null===e||void 0===e?void 0:e.RealNumberOfCpus)&&void 0!==n?n:null===e||void 0===e?void 0:e.NumberOfCpus})}),l.push(...s),l},Bs=({cluster:e,loading:s,error:n,additionalClusterProps:t={}})=>{const{info:l=[],links:r=[]}=t,a=zs(),o=r.concat(a),i=$s(null!==e&&void 0!==e?e:{},l);return(0,U.jsxs)("div",{className:As(),children:[n?(0,U.jsx)(S.o,{error:n,className:As("error")}):null,s?(0,U.jsx)(Ls.y,{className:As("skeleton"),rows:4}):(0,U.jsxs)(z.s,{gap:10,wrap:"nowrap",children:[n&&!e?null:(0,U.jsxs)("div",{children:[(0,U.jsx)("div",{className:As("section-title"),children:ts("title_info")}),(0,U.jsx)(M.u,{nameMaxWidth:200,children:i.map((({label:e,value:s})=>(0,U.jsx)(M.u.Item,{name:e,children:s},e)))})]}),o.length?(0,U.jsxs)("div",{children:[(0,U.jsx)("div",{className:As("section-title"),children:ts("title_links")}),(0,U.jsx)(z.s,{direction:"column",gap:4,children:o.map((({title:e,url:s})=>(0,U.jsx)(P.K,{title:e,url:s},e)))})]}):null]})]})};var Us=n(87842);const Fs=(0,g.cn)("ydb-cluster");function Ws({additionalClusterProps:e,additionalTenantsProps:s,additionalNodesProps:n}){const g=t.useRef(null),b=(0,h.fp)(),y=(0,j.YQ)(),C=function(){const e=(0,j.YQ)(),s=(0,j.N4)((e=>e.cluster.defaultClusterTab)),n=(0,o.W5)(v.Ay.cluster),{activeTab:l}=(null===n||void 0===n?void 0:n.params)||{};let r;r=(0,Us.eC)(l)?l:s;return t.useEffect((()=>{r!==s&&e((0,m.Yv)(r))}),[r,s,e]),r}(),[{clusterName:k,backend:w}]=(0,i.useQueryParams)({clusterName:i.StringParam,backend:i.StringParam}),T=(0,j.N4)((e=>(0,m.zR)(e,null!==k&&void 0!==k?k:void 0))),{title:_}=(0,m.Zd)(),S=null!==_&&void 0!==_?_:T,{data:{clusterData:E,groupsStats:V}={},isLoading:O,error:D}=m.Zh.useGetClusterInfoQuery(null!==k&&void 0!==k?k:void 0),L=D&&"object"===typeof D?D:void 0,A=(0,j.N4)((e=>(0,m.ds)(e,null!==k&&void 0!==k?k:void 0)));t.useEffect((()=>{y((0,p.g)("cluster",{}))}),[y]);const M=t.useMemo((()=>Us.bn.find((({id:e})=>e===C))),[C]);return(0,U.jsxs)("div",{className:Fs(),ref:g,children:[(0,U.jsx)(a.mg,{defaultTitle:`${S} \u2014 YDB Monitoring`,titleTemplate:`%s \u2014 ${S} \u2014 YDB Monitoring`,children:M?(0,U.jsx)("title",{children:M.title}):null}),(0,U.jsx)("div",{className:Fs("header"),children:O?(0,U.jsx)(l.E,{className:Fs("title-skeleton")}):(0,U.jsx)(c.c,{size:"m",status:null===E||void 0===E?void 0:E.Overall,name:S,className:Fs("title")})}),(0,U.jsx)("div",{className:Fs("sticky-wrapper"),children:(0,U.jsx)(d.E,{className:Fs("auto-refresh-control")})}),b&&(0,U.jsx)(Vs,{cluster:null!==E&&void 0!==E?E:{},groupStats:V,loading:O,error:L||(null===E||void 0===E?void 0:E.error)}),(0,U.jsx)("div",{className:Fs("tabs-sticky-wrapper"),children:(0,U.jsx)(r.t,{size:"l",allowNotSelected:!0,activeTab:C,items:Us.bn,wrapTo:({id:e},s)=>{const n=(0,Us.a)(e,{clusterName:k,backend:w});return(0,U.jsx)(u.E,{to:n,onClick:()=>{y((0,m.Yv)(e))},children:s},e)}})}),(0,U.jsxs)(o.dO,{children:[(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.overview)).pathname,children:(0,U.jsx)(Bs,{cluster:E,loading:O,error:L,additionalClusterProps:e})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.tablets)).pathname,children:(0,U.jsx)(f.Q,{loading:O,tablets:A})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.tenants)).pathname,children:(0,U.jsx)(de,{additionalTenantsProps:s})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.nodes)).pathname,children:(0,U.jsx)(x.G,{parentRef:g,additionalNodesProps:n})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.storage)).pathname,children:(0,U.jsx)(N.z,{parentRef:g})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.versions)).pathname,children:(0,U.jsx)(Qe,{cluster:E,loading:O})}),(0,U.jsx)(o.qh,{render:()=>(0,U.jsx)(o.rd,{to:(0,v.a3)((0,Us.a)(C))})})]})]})}},42655:(e,s,n)=>{n.d(s,{y:()=>c});var t=n(59284),l=n(89169),r=n(77506),a=n(66781),o=n(60712);const i=(0,r.cn)("ydb-info-viewer-skeleton"),d=()=>(0,o.jsxs)("div",{className:i("label"),children:[(0,o.jsx)(l.E,{className:i("label__text")}),(0,o.jsx)("div",{className:i("label__dots")})]}),c=({rows:e=8,className:s,delay:n=600})=>{const[r]=(0,a.y)(n);let c=(0,o.jsxs)(t.Fragment,{children:[(0,o.jsx)(d,{}),(0,o.jsx)(l.E,{className:i("value")})]});return r||(c=null),(0,o.jsx)("div",{className:i(null,s),children:[...new Array(e)].map(((e,s)=>(0,o.jsx)("div",{className:i("row"),children:c},`skeleton-row-${s}`)))})}},70043:(e,s,n)=>{n.d(s,{E:()=>a});var t=n(89169),l=n(66781),r=n(60712);const a=({delay:e=600,className:s})=>{const[n]=(0,l.y)(e);return n?(0,r.jsx)(t.E,{className:s}):null}}}]); \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/47512.78ddf2e4.chunk.js b/ydb/core/viewer/monitoring/static/js/47512.78ddf2e4.chunk.js new file mode 100644 index 000000000000..5b12d30e6eab --- /dev/null +++ b/ydb/core/viewer/monitoring/static/js/47512.78ddf2e4.chunk.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[47512],{14188:(e,s,n)=>{n.r(s),n.d(s,{Cluster:()=>Ws});var t=n(59284),r=n(89169),l=n(23871),a=n(61750),o=n(10755),i=n(67087),d=n(90053),c=n(10508),u=n(44294),v=n(92459),h=n(67028),m=n(67157),p=n(40174),g=n(77506),j=n(90182),x=n(7117),N=n(99936),f=n(88616),b=n(93381),y=n(64470),C=n(4557),w=n(84476),k=n(99991),T=n(40569),S=n(28539),_=n(44508),E=n(78524),V=n(48295),O=n(9252),D=n(17594),L=n(95963),A=n(89073),z=n(23900),M=n(87184),G=n(54309),I=n(12888),P=n(25196),R=n(48372);const $=JSON.parse('{"field_links":"Links","field_monitoring-link":"Monitoring","field_logs-link":"Logs","context_unknown":"unknown database"}'),B=(0,R.g4)("ydb-tenant-name-wrapper",{en:$});var U=n(60712);function F({tenant:e,additionalTenantsProps:s}){var n,t;const r=(0,I.X)(),l=((e,s)=>{var n;if("function"!==typeof(null===s||void 0===s?void 0:s.prepareTenantBackend))return;let t;const r=null!==(n=e.NodeIds)&&void 0!==n?n:e.sharedNodeIds;r&&r.length>0&&(t=r[Math.floor(Math.random()*r.length)].toString());return s.prepareTenantBackend(t)})(e,s),a=Boolean(l),o=null===s||void 0===s||null===(n=s.getMonitoringLink)||void 0===n?void 0:n.call(s,e.Name,e.Type),i=null===s||void 0===s||null===(t=s.getLogsLink)||void 0===t?void 0:t.call(s,e.Name),d=(o||i)&&r?(0,U.jsx)(z.u,{responsive:!0,children:(0,U.jsx)(z.u.Item,{name:B("field_links"),children:(0,U.jsxs)(M.s,{gap:2,wrap:"wrap",children:[o&&(0,U.jsx)(P.K,{title:B("field_monitoring-link"),url:o}),i&&(0,U.jsx)(P.K,{title:B("field_logs-link"),url:i})]})})}):null;return(0,U.jsx)(c.c,{externalLink:a,name:e.Name||B("context_unknown"),withLeftTrim:!0,status:e.Overall,infoPopoverContent:d,hasClipboardButton:!0,path:(0,G.YL)({database:e.Name,backend:l})})}var W=n(88610),Z=n(53850),q=n(23536),H=n.n(q),Q=n(54090),Y=n(76086),K=n(56674);const J=(0,Z.Mz)((e=>e),(e=>K.GJ.endpoints.getTenantsInfo.select({clusterName:e}))),X=(0,Z.Mz)((e=>e),((e,s)=>J(s)),(e=>(0,W.CN)(e,Y.Xm)),((e,s,n)=>{var t;const r=null!==(t=s(e).data)&&void 0!==t?t:[];return!n&&r.length>1?r.filter((e=>"Domain"!==e.Type)):r})),ee=e=>e.tenants.searchValue,se=(0,Z.Mz)([X,W.yV,ee],((e,s,n)=>{let t=((e,s)=>s===W.s$.ALL?e:e.filter((e=>e.Overall&&e.Overall!==Q.m.Green)))(e,s);return t=((e,s)=>e.filter((e=>{const n=new RegExp(H()(s),"i");return n.test(e.Name||"")||n.test(e.controlPlaneName)})))(t,n),t})),ne={};const te=new Proxy(ne,{set:()=>{throw new Error("Use configureUIFactory(...) method instead of direct modifications")}});var re=n(56839),le=n(28232);const ae=JSON.parse('{"create-database":"Create database","remove":"Remove"}'),oe=(0,R.g4)("ydb-tenants-table",{en:ae}),ie=(0,g.cn)("tenants"),de=({additionalTenantsProps:e})=>{const s=(0,j.YQ)(),n=(0,le.H)(),[r]=(0,j.Nt)(),{currentData:l,isFetching:a,error:o}=K.GJ.useGetTenantsInfoQuery({clusterName:n},{pollingInterval:r}),i=a&&void 0===l,d=(0,h.sH)()&&void 0!==te.onCreateDB,c=(0,h.TW)()&&void 0!==te.onDeleteDB,u=(0,j.N4)((e=>X(e,n))),v=(0,j.N4)(ee),m=(0,j.N4)((e=>se(e,n))),p=(0,j.N4)(W.yV),g=e=>{s((0,W.$u)(e))},x=e=>{s((0,K.gB)(e))};return(0,U.jsx)("div",{className:ie("table-wrapper"),children:(0,U.jsxs)(A.L,{children:[(0,U.jsx)(A.L.Controls,{className:ie("controls"),children:(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)(L.v,{value:v,onChange:x,placeholder:"Database name",className:ie("search")}),(0,U.jsx)(O.k,{value:p,onChange:g}),(0,U.jsx)(S.T,{total:u.length,current:(null===m||void 0===m?void 0:m.length)||0,label:"Databases",loading:i}),d&&n?(0,U.jsxs)(w.$,{view:"action",onClick:()=>{var e;return null===(e=te.onCreateDB)||void 0===e?void 0:e.call(te,{clusterName:n})},className:ie("create-database"),children:[(0,U.jsx)(k.I,{data:b.A}),oe("create-database")]}):null]})}),o?(0,U.jsx)(_.o,{error:o}):null,(0,U.jsx)(A.L.Table,{loading:i,children:l?(()=>{const s=[{name:"Name",header:"Database",render:({row:s})=>(0,U.jsx)(F,{tenant:s,additionalTenantsProps:e}),width:440,sortable:!0,defaultOrder:C.Ay.DESCENDING},{name:"controlPlaneName",header:"Name",render:({row:e})=>e.controlPlaneName,width:200,sortable:!0,defaultOrder:C.Ay.DESCENDING},{name:"Type",width:200,resizeMinWidth:150,render:({row:e})=>"Serverless"!==e.Type?e.Type:(0,U.jsxs)("div",{className:ie("type"),children:[(0,U.jsx)("span",{className:ie("type-value"),children:e.Type}),(0,U.jsx)(w.$,{className:ie("type-button"),onClick:()=>x(e.sharedTenantName||""),children:"Show shared"})]})},{name:"State",width:90,render:({row:e})=>e.State?e.State.toLowerCase():"\u2014",customStyle:()=>({textTransform:"capitalize"})},{name:"cpu",header:"CPU",width:80,render:({row:e})=>e.cpu&&e.cpu>1e4?(0,re.iM)(e.cpu):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"memory",header:"Memory",width:120,render:({row:e})=>e.memory?(0,re.vX)(e.memory):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"storage",header:"Storage",width:120,render:({row:e})=>e.storage?(0,re.vX)(e.storage):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"nodesCount",header:"Nodes",width:100,render:({row:e})=>e.nodesCount?(0,re.ZV)(e.nodesCount):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"groupsCount",header:"Groups",width:100,render:({row:e})=>e.groupsCount?(0,re.ZV)(e.groupsCount):"\u2014",align:C.Ay.RIGHT,defaultOrder:C.Ay.DESCENDING},{name:"PoolStats",header:"Pools",width:100,resizeMinWidth:60,sortAccessor:({PoolStats:e=[]})=>e.reduce(((e,s)=>e+(s.Usage||0)),0),defaultOrder:C.Ay.DESCENDING,align:C.Ay.LEFT,render:({row:e})=>(0,U.jsx)(V._,{pools:e.PoolStats})}];return c&&s.push({name:"actions",header:"",width:40,resizeable:!1,align:C.Ay.CENTER,render:({row:e})=>{var s;const t=null===(s=e.UserAttributes)||void 0===s?void 0:s.database_id,r=e.Name;let l=[];return n&&r&&t&&(l=[{text:oe("remove"),iconStart:(0,U.jsx)(y.A,{}),action:()=>{var e;null===(e=te.onDeleteDB)||void 0===e||e.call(te,{clusterName:n,databaseId:t,databaseName:r})},className:ie("remove-db")}]),l.length?(0,U.jsx)(T.r,{defaultSwitcherProps:{view:"flat",size:"s",pin:"brick-brick"},items:l}):null}}),0===m.length&&p!==W.s$.ALL?(0,U.jsx)(E.v,{name:"thumbsUp",width:"200"}):(0,U.jsx)(D.l,{columnsWidthLSKey:"databasesTableColumnsWidth",data:m,columns:s,settings:Y.N3,emptyDataMessage:"No such tenants"})})():null})]})})};var ce=n(44433),ue=n(74321),ve=n(98167),he=n(15298),me=n(18143);const pe=(0,g.cn)("ydb-cluster-versions-bar"),ge=({versionsValues:e=[],size:s="s",progressClassName:n})=>(0,U.jsxs)("div",{className:pe(),children:[(0,U.jsx)(me.k,{value:100,stack:e,size:s,className:n}),(0,U.jsx)("div",{className:pe("versions"),children:e.map(((s,n)=>(0,U.jsx)("div",{className:pe("version-title"),style:{color:s.color},title:s.version,children:`${s.version}${n===e.length-1?"":","}`},s.version)))})]});var je=n(63126),xe=n(78762),Ne=n(88655);function fe(e){return[(0,xe._E)(),(0,xe.Nh)(e),(0,xe.jl)(),(0,xe.pH)(),(0,xe.fr)(),(0,xe.ID)()]}const be=({nodes:e})=>{const s=(0,Ne.E)(),n=fe({getNodeRef:null===s||void 0===s?void 0:s.getNodeRef});return(0,U.jsx)(D.l,{columnsWidthLSKey:"versionsTableColumnsWidth",data:e,columns:n,settings:Y.N3})};var ye=n(96873);const Ce=(0,g.cn)("ydb-versions-nodes-tree-title"),we=({title:e,nodes:s,items:n,versionColor:t,versionsValues:r})=>{let l;return l=n?n.reduce(((e,s)=>s.nodes?e+s.nodes.length:e),0):s?s.length:0,(0,U.jsxs)("div",{className:Ce("overview"),children:[(0,U.jsxs)("div",{className:Ce("overview-container"),children:[t?(0,U.jsx)("div",{className:Ce("version-color"),style:{background:t}}):null,e?(0,U.jsxs)("span",{className:Ce("overview-title"),children:[e,(0,U.jsx)(ye.b,{text:e,size:"s",className:Ce("clipboard-button"),view:"normal"})]}):null]}),(0,U.jsxs)("div",{className:Ce("overview-info"),children:[(0,U.jsxs)("div",{children:[(0,U.jsx)("span",{className:Ce("info-value"),children:l}),(0,U.jsx)("span",{className:Ce("info-label",{margin:"left"}),children:"Nodes"})]}),r?(0,U.jsxs)("div",{className:Ce("version-progress"),children:[(0,U.jsx)("span",{className:Ce("info-label",{margin:"right"}),children:"Versions"}),(0,U.jsx)(me.k,{size:"s",value:100,stack:r})]}):null]})]})},ke=(0,g.cn)("ydb-versions-grouped-node-tree"),Te=({title:e,nodes:s,items:n,expanded:r=!1,versionColor:l,versionsValues:a,level:o=0})=>{const[i,d]=t.useState(!1);t.useEffect((()=>{d(r)}),[r]);const c=(0,U.jsx)(we,{title:e,nodes:s,items:n,versionColor:l,versionsValues:a}),u=()=>{d((e=>!e))};return n?(0,U.jsx)("div",{className:ke({"first-level":0===o}),children:(0,U.jsx)(je.G,{name:c,collapsed:!i,hasArrow:!0,onClick:u,onArrowClick:u,children:n.map(((e,s)=>(0,U.jsx)(Te,{title:e.title,nodes:e.nodes,expanded:r,versionColor:e.versionColor,level:o+1},s)))},e)}):(0,U.jsx)("div",{className:ke({"first-level":0===o}),children:(0,U.jsx)(je.G,{name:c,collapsed:!i,hasArrow:!0,onClick:u,onArrowClick:u,children:(0,U.jsx)("div",{className:ke("dt-wrapper"),children:(0,U.jsx)(be,{nodes:s||[]})})},e)})};var Se=n(78018),_e=n.n(Se),Ee=n(38596);const Ve=.5,Oe=(e=[],s)=>{const n=e.reduce(((e,s)=>(s.Version&&(e[s.Version]?e[s.Version]=e[s.Version]+1:e[s.Version]=1),e)),{});return Le(Object.keys(n).map((t=>{const r=n[t]/e.length*100;return{title:t,version:t,color:null===s||void 0===s?void 0:s.get((0,Ee.U)(t)),value:re+s.count),0);return Le(e.map((e=>{const n=e.count/t*100;return{title:e.name,version:e.name,color:null===s||void 0===s?void 0:s.get(e.name),value:n{t+=e.value,e.value>s&&(s=e.value,n=r)}));const r=[...e];return r[n]={...e[n],value:s+100-t},r}let Ae=function(e){return e.VERSION="Version",e.TENANT="Database",e.STORAGE="Storage",e}({});const ze=(e,s)=>{var n;return(null===(n=e.title)||void 0===n?void 0:n.localeCompare(s.title||""))||-1},Me=(e,s,n)=>{if(e&&e.length){if(n===Ae.VERSION){const n=_e()(e,"Version");return Object.keys(n).map((e=>{const t=n[e].filter((({Tenants:e})=>Boolean(e))),r=_e()(t,"Tenants"),l=Object.keys(r).map((e=>({title:e,nodes:r[e]}))).sort(ze);return l.length?{title:e,items:l,versionColor:null===s||void 0===s?void 0:s.get((0,Ee.U)(e))}:null})).filter((e=>Boolean(e)))}{const n=e.filter((({Tenants:e})=>Boolean(e))),t=_e()(n,"Tenants");return Object.keys(t).map((e=>{const n=Oe(t[e],s),r=_e()(t[e],"Version"),l=Object.keys(r).map((e=>({title:e,nodes:r[e],versionColor:null===s||void 0===s?void 0:s.get((0,Ee.U)(e))})));return l.length?{title:e,items:l,versionsValues:n}:null})).filter((e=>Boolean(e))).sort(ze)}}},Ge=(e,s)=>{if(!e||!e.length)return;const n=e.filter((({Roles:e})=>null===e||void 0===e?void 0:e.includes("Storage"))),t=_e()(n,"Version");return Object.keys(t).map((e=>({title:e,nodes:t[e],versionColor:null===s||void 0===s?void 0:s.get((0,Ee.U)(e))})))},Ie=(e,s)=>{if(!e||!e.length)return;const n=e.filter((({Roles:e,Version:s})=>!e&&s)),t=_e()(n,"Version");return Object.keys(t).map((e=>({title:e,nodes:t[e],versionColor:null===s||void 0===s?void 0:s.get((0,Ee.U)(e))})))},Pe=JSON.parse('{"title_overall":"Overall","title_storage":"Storage nodes","title_database":"Database nodes","title_other":"Other nodes"}'),Re=(0,R.g4)("ydb-versions",{en:Pe});var $e=n(44992),Be=n(39567),Ue=n(98730),Fe=n(40537),We=n(66592);const Ze=({cluster:e,versionToColor:s,clusterLoading:n})=>{const{currentData:r}=he.s.useGetNodesQuery((0,Ue.L)(e)||n?$e.hT:{tablets:!1,fieldsRequired:["SystemState","SubDomainKey"],group:"Version"});return t.useMemo((()=>{if((0,Ue.L)(e)&&e.MapVersions){return De(Object.entries(e.MapVersions).map((([e,s])=>({name:e,count:s}))),s,e.NodesTotal)}return r?Array.isArray(r.NodeGroups)?De(r.NodeGroups,s,null===e||void 0===e?void 0:e.NodesTotal):Oe(r.Nodes,s):[]}),[r,s,e])};function qe(e){const s=function(){const[e]=(0,i.useQueryParam)("clusterName",i.StringParam),s=(0,j.N4)((e=>e.singleClusterMode)),{data:n}=Be.ub.useGetClustersListQuery(void 0,{skip:s});return t.useMemo((()=>{if(s)return;const t=(n||[]).find((s=>s.name===e)),r=(null===t||void 0===t?void 0:t.versions)||[];return()=>(0,Fe.Vm)((0,Fe.HD)(r))}),[s,n,e])}();return t.useMemo((()=>s?s():(0,We._n)(null===e||void 0===e?void 0:e.Versions)),[null===e||void 0===e?void 0:e.Versions,s])}const He=(0,g.cn)("ydb-versions");function Qe({cluster:e,loading:s}){const[n]=(0,j.Nt)(),{currentData:t,isLoading:r}=he.s.useGetNodesQuery({tablets:!1,fieldsRequired:["SystemState","SubDomainKey"]},{pollingInterval:n}),l=qe(),a=Ze({cluster:e,versionToColor:l,clusterLoading:s});return(0,U.jsx)(ve.r,{loading:s||r,children:(0,U.jsx)(Ye,{versionsValues:a,nodes:null===t||void 0===t?void 0:t.Nodes,versionToColor:l})})}function Ye({versionsValues:e,nodes:s,versionToColor:n}){const[r,l]=t.useState(Ae.VERSION),[a,o]=t.useState(!1),i=e=>{l(e)},d=Me(s,n,r),c=Ge(s,n),u=Ie(s,n),v=null!==c&&void 0!==c&&c.length?(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)("h4",{children:Re("title_storage")}),c.map((({title:e,nodes:s,items:n,versionColor:t})=>(0,U.jsx)(Te,{title:e,nodes:s,items:n,versionColor:t},`storage-nodes-${e}`)))]}):null,h=null!==d&&void 0!==d&&d.length?(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)("h4",{children:Re("title_database")}),(0,U.jsxs)("div",{className:He("controls"),children:[(0,U.jsxs)("div",{className:He("group"),children:[(0,U.jsx)("span",{className:He("label"),children:"Group by:"}),(0,U.jsxs)(ce.a,{value:r,onUpdate:i,children:[(0,U.jsx)(ce.a.Option,{value:Ae.TENANT,children:Ae.TENANT}),(0,U.jsx)(ce.a.Option,{value:Ae.VERSION,children:Ae.VERSION})]})]}),(0,U.jsx)(ue.S,{className:He("checkbox"),onChange:()=>o((e=>!e)),checked:a,children:"All expanded"})]}),d.map((({title:e,nodes:s,items:n,versionColor:t,versionsValues:r})=>(0,U.jsx)(Te,{title:e,nodes:s,items:n,expanded:a,versionColor:t,versionsValues:r},`tenant-nodes-${e}`)))]}):null,m=null!==u&&void 0!==u&&u.length?(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)("h4",{children:Re("title_other")}),u.map((({title:e,nodes:s,items:n,versionColor:t,versionsValues:r})=>(0,U.jsx)(Te,{title:e,nodes:s,items:n,versionColor:t,versionsValues:r},`other-nodes-${e}`)))]}):null,p=(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)("h4",{children:Re("title_overall")}),(0,U.jsx)("div",{className:He("overall-wrapper"),children:(0,U.jsx)(ge,{progressClassName:He("overall-progress"),versionsValues:e.filter((e=>"unknown"!==e.title)),size:"m"})})]});return(0,U.jsxs)("div",{className:He(),children:[p,v,h,m]})}var Ke=n(98089);const Je=(0,g.cn)("tag"),Xe=({text:e,type:s})=>(0,U.jsx)("div",{className:Je({type:s}),children:e}),es=({tags:e,tagsType:s,className:n="",gap:t=1})=>(0,U.jsx)(M.s,{className:n,gap:t,wrap:"wrap",alignItems:"center",children:e&&e.map(((e,n)=>(0,U.jsx)(Xe,{text:e,type:s},n)))});var ss=n(7435);const ns=JSON.parse('{"disk-type":"Disk Type","erasure":"Erasure","allocated":"Allocated","available":"Available","usage":"Usage","label_nodes-state":"Nodes state","label_dc":"Nodes data centers","storage-size":"Storage size","storage-groups":"Storage groups, {{diskType}}","links":"Links","link_cores":"Coredumps","link_logging":"Logging","link_slo-logs":"SLO Logs","context_cores":"cores","title_cpu":"CPU","title_storage":"Storage","title_memory":"Memory","title_info":"Info","title_links":"Links","label_nodes":"Nodes","label_hosts":"Hosts","label_storage-groups":"Storage groups","label_databases":"Databases","label_load":"Load"}'),ts=(0,R.g4)("ydb-cluster",{en:ns});var rs=n(2102);const ls=(0,g.cn)("ydb-doughnut-metrics");function as({status:e,fillWidth:s,children:n,className:t}){let r="var(--g-color-line-generic-solid)",l=3.6*s-90;s>50&&(r="var(--doughnut-color)",l=3.6*s+90);const a=l;return(0,U.jsx)("div",{className:ls(null,t),children:(0,U.jsx)("div",{style:{backgroundImage:`linear-gradient(${a}deg, transparent 50%, ${r} 50%), linear-gradient(-90deg, var(--g-color-line-generic-solid) 50%, transparent 50%)`},className:ls("doughnut",{status:e}),children:(0,U.jsx)("div",{className:ls("text-wrapper"),children:n})})})}as.Legend=function({children:e,variant:s="subheader-3"}){return(0,U.jsx)(Ke.E,{variant:s,color:"secondary",className:ls("legend"),children:e})},as.Value=function({children:e,variant:s="subheader-2"}){return(0,U.jsx)(Ke.E,{variant:s,color:"secondary",className:ls("value"),children:e})};var os=n(70043);const is=(0,g.cn)("ydb-cluster-dashboard");function ds({children:e,title:s,size:n,className:t}){return(0,U.jsxs)(rs.A,{className:is("card",{size:n},t),size:n,interactive:!1,children:[s?(0,U.jsx)(Ke.E,{variant:"subheader-3",className:is("card-title"),children:s}):null,e]})}function cs({title:e,children:s,size:n,...t}){return(0,U.jsx)(ds,{title:e,size:n,children:(0,U.jsx)(as,{...t,className:is("doughnut"),children:s})})}function us(){return(0,U.jsx)(ds,{className:is("skeleton-wrapper"),children:(0,U.jsx)(os.E,{className:is("skeleton")})})}function vs(){return(0,U.jsxs)(t.Fragment,{children:[(0,U.jsx)(us,{}),(0,U.jsx)(us,{}),(0,U.jsx)(us,{})]})}var hs=n(35736),ms=n(57439),ps=n(24543),gs=n(46549);const js=(0,g.cn)("ydb-disk-groups-stats"),xs=({stats:e,children:s})=>(0,U.jsx)("div",{className:js(),children:(0,U.jsx)(ps.u,{placement:["right"],pinOnClick:!0,content:(0,U.jsx)(Ns,{stats:e}),children:s})});function Ns({stats:e}){const{diskType:s,erasure:n,allocatedSize:t,availableSize:r}=e,l=(0,gs.fn)(Math.max(t,r)),a=(0,gs.z3)({value:t,size:l}),o=(0,gs.z3)({value:r,size:l}),i=Math.round(t/(t+r)*100),d=[{name:ts("disk-type"),content:s},{name:ts("erasure"),content:n},{name:ts("allocated"),content:a},{name:ts("available"),content:o},{name:ts("usage"),content:i+"%"}];return(0,U.jsx)(ms.u,{items:d,className:js("popup-content"),responsive:!0})}function fs({value:e,capacity:s,colorizeProgress:n=!0,warningThreshold:t,dangerThreshold:r,inverseColorize:l=!1,legendFormatter:a}){const o=parseFloat(String(e)),i=parseFloat(String(s));let d=o/i*100||0;d=d>100?100:d;const c=d<1?.5:d;return{status:(0,hs.w)({fillWidth:d,warningThreshold:t,dangerThreshold:r,colorizeProgress:n,inverseColorize:l}),percents:(0,re.l9)(d/100),legend:a({value:o,capacity:i}),fill:c}}const bs=["storage","tenant"];const ys=e=>Object.values(e).reduce(((e,s)=>(Object.values(s).forEach((s=>{e+=s.createdGroups})),e)),0);function Cs({value:e,capacity:s}){let n=[];return n=s<1e4?[(0,re.ZV)(Math.round(e)),(0,re.ZV)(Math.round(s))]:(0,re.Nd)(e,s,void 0,"",!0),`${n[0]} / ${n[1]}\n${ts("context_cores")}`}function ws({value:e,capacity:s,...n}){const{status:t,percents:r,legend:l,fill:a}=fs({value:e,capacity:s,legendFormatter:Cs,...n});return(0,U.jsxs)(cs,{status:t,fillWidth:a,title:ts("title_cpu"),children:[(0,U.jsx)(as.Legend,{children:l}),(0,U.jsx)(as.Value,{children:r})]})}function ks({value:e,capacity:s}){const n=(0,re.j9)(e,s,void 0,"\n");return`${n[0]} / ${n[1]}`}function Ts({value:e,capacity:s,...n}){const{status:t,percents:r,legend:l,fill:a}=fs({value:e,capacity:s,legendFormatter:ks,...n});return(0,U.jsxs)(cs,{status:t,fillWidth:a,title:ts("title_memory"),children:[(0,U.jsx)(as.Legend,{children:l}),(0,U.jsx)(as.Value,{children:r})]})}function Ss({value:e,capacity:s}){const n=(0,re.j9)(e,s,void 0,"\n");return`${n[0]} / ${n[1]}`}function _s({value:e,capacity:s,...n}){const{status:t,percents:r,legend:l,fill:a}=fs({value:e,capacity:s,legendFormatter:Ss,...n});return(0,U.jsxs)(cs,{status:t,fillWidth:a,title:ts("title_storage"),children:[(0,U.jsx)(as.Legend,{children:l}),(0,U.jsx)(as.Value,{children:r})]})}function Es({value:e}){return(0,ss.f8)(e)?(0,U.jsx)(Ke.E,{variant:"subheader-3",color:"secondary",children:(0,re.ZV)(e)}):null}function Vs({cluster:e,...s}){return s.error?(0,U.jsx)(_.o,{error:s.error,className:is("error")}):(0,U.jsx)("div",{className:is(),children:(0,U.jsxs)(M.s,{gap:4,wrap:!0,children:[(0,U.jsx)(M.s,{gap:4,wrap:"nowrap",children:(0,U.jsx)(Os,{...s,cluster:e})}),(0,U.jsx)("div",{className:is("cards-container"),children:(0,U.jsx)(Ds,{...s,cluster:e})})]})})}function Os({cluster:e,loading:s}){if(s)return(0,U.jsx)(vs,{});const n=[];if((0,Ue.L)(e)){const{CoresUsed:s,NumberOfCpus:t,CoresTotal:r}=e,l=null!==r&&void 0!==r?r:t;(0,ss.f8)(s)&&(0,ss.f8)(l)&&n.push((0,U.jsx)(ws,{value:s,capacity:l},"cores"))}const{StorageTotal:t,StorageUsed:r}=e;(0,ss.f8)(t)&&(0,ss.f8)(r)&&n.push((0,U.jsx)(_s,{value:r,capacity:t},"storage"));const{MemoryTotal:l,MemoryUsed:a}=e;return(0,ss.f8)(l)&&(0,ss.f8)(a)&&n.push((0,U.jsx)(Ts,{value:a,capacity:l},"memory")),n}function Ds({cluster:e,groupStats:s={},loading:n}){if(n)return null;const r=[],l=function(e){const s=[];if((0,Ue.L)(e)&&e.MapNodeRoles)for(const[n,r]of Object.entries(e.MapNodeRoles))bs.includes(n.toLowerCase())&&s.push((0,U.jsxs)(t.Fragment,{children:[n,": ",(0,re.ZV)(r)]},n));return s}(e);if(r.push((0,U.jsx)(ds,{size:"l",title:ts("label_nodes"),children:(0,U.jsxs)(M.s,{gap:2,direction:"column",children:[(0,U.jsx)(Es,{value:null===e||void 0===e?void 0:e.NodesAlive}),null!==l&&void 0!==l&&l.length?(0,U.jsx)(es,{tags:l,gap:3}):null]})},"roles")),Object.keys(s).length){const e=function(e){const s=[];return Object.entries(e).forEach((([e,n])=>{Object.values(n).forEach((n=>{s.push((0,U.jsxs)(xs,{stats:n,children:[e,": ",(0,re.ZV)(n.createdGroups)," /"," ",(0,re.ZV)(n.totalGroups)]},`${e}|${n.erasure}`))}))})),s}(s),n=ys(s);r.push((0,U.jsx)(ds,{size:"l",title:ts("label_storage-groups"),children:(0,U.jsxs)(M.s,{gap:2,direction:"column",children:[(0,U.jsx)(Es,{value:n}),(0,U.jsx)(es,{tags:e,gap:3})]})},"groups"))}const a=function(e){var s;return(0,Ue.L)(e)&&e.MapDataCenters?Object.keys(e.MapDataCenters):null===(s=e.DataCenters)||void 0===s?void 0:s.filter(Boolean)}(e);return null!==a&&void 0!==a&&a.length&&r.push((0,U.jsx)(ds,{size:"l",title:ts("label_hosts"),children:(0,U.jsxs)(M.s,{gap:2,direction:"column",children:[(0,U.jsx)(Es,{value:null===e||void 0===e?void 0:e.Hosts}),(0,U.jsx)(es,{tags:a,gap:3})]})},"hosts")),e.Tenants&&r.push((0,U.jsx)(ds,{size:"l",title:ts("label_databases"),children:(0,U.jsx)(Es,{value:null===e||void 0===e?void 0:e.Tenants})},"tenants")),r}var Ls=n(42655);const As=(0,g.cn)("cluster-info");var zs=n(41650);function Ms(){const{cores:e,logging:s}=(0,m.Zd)();return t.useMemo((()=>{const n=[],t=function(e){try{const s=(0,zs.qF)(e);if(s&&"object"===typeof s&&"url"in s&&"string"===typeof s.url)return s.url}catch{}}(e),{logsUrl:r,sloLogsUrl:l}=function(e){try{const s=(0,zs.qF)(e);if(s&&"object"===typeof s){return{logsUrl:"url"in s&&"string"===typeof s.url?s.url:void 0,sloLogsUrl:"slo_logs_url"in s&&"string"===typeof s.slo_logs_url?s.slo_logs_url:void 0}}}catch{}return{}}(s);return t&&n.push({title:ts("link_cores"),url:t}),r&&n.push({title:ts("link_logging"),url:r}),l&&n.push({title:ts("link_slo-logs"),url:l}),n}),[e,s])}var Gs=n(15132);const Is=(0,g.cn)("ydb-nodes-state");function Ps({state:e,children:s}){return(0,U.jsx)("div",{className:Is({[e.toLowerCase()]:!0}),children:s})}const Rs={Green:5,Blue:4,Yellow:3,Orange:2,Red:1,Grey:0},$s=(e,s)=>{var n;const r=[];if((0,Ue.L)(e)&&e.MapNodeStates){const s=Object.entries(e.MapNodeStates);s.sort(((e,s)=>Rs[s[0]]-Rs[e[0]]));const n=s.map((([e,s])=>(0,U.jsx)(Ps,{state:e,children:(0,re.ZV)(s)},e)));r.push({label:ts("label_nodes-state"),value:(0,U.jsx)(M.s,{gap:2,children:n})})}const l=(e=>{if((0,Ue.L)(e)&&e.MapDataCenters)return Object.entries(e.MapDataCenters).map((([e,s])=>(0,U.jsxs)(t.Fragment,{children:[e,": ",(0,re.ZV)(s)]},e)))})(e);return null!==l&&void 0!==l&&l.length&&r.push({label:ts("label_dc"),value:(0,U.jsx)(es,{tags:l,gap:2,className:As("dc")})}),r.push({label:ts("label_load"),value:(0,U.jsx)(Gs.O,{value:null===e||void 0===e?void 0:e.LoadAverage,capacity:null!==(n=null===e||void 0===e?void 0:e.RealNumberOfCpus)&&void 0!==n?n:null===e||void 0===e?void 0:e.NumberOfCpus})}),r.push(...s),r},Bs=({cluster:e,loading:s,error:n,additionalClusterProps:t={}})=>{const{info:r=[],links:l=[]}=t,a=Ms(),o=l.concat(a),i=$s(null!==e&&void 0!==e?e:{},r);return(0,U.jsxs)("div",{className:As(),children:[n?(0,U.jsx)(_.o,{error:n,className:As("error")}):null,s?(0,U.jsx)(Ls.y,{className:As("skeleton"),rows:4}):(0,U.jsxs)(M.s,{gap:10,wrap:"nowrap",children:[n&&!e?null:(0,U.jsxs)("div",{children:[(0,U.jsx)("div",{className:As("section-title"),children:ts("title_info")}),(0,U.jsx)(z.u,{nameMaxWidth:200,children:i.map((({label:e,value:s})=>(0,U.jsx)(z.u.Item,{name:e,children:s},e)))})]}),o.length?(0,U.jsxs)("div",{children:[(0,U.jsx)("div",{className:As("section-title"),children:ts("title_links")}),(0,U.jsx)(M.s,{direction:"column",gap:4,children:o.map((({title:e,url:s})=>(0,U.jsx)(P.K,{title:e,url:s},e)))})]}):null]})]})};var Us=n(87842);const Fs=(0,g.cn)("ydb-cluster");function Ws({additionalClusterProps:e,additionalTenantsProps:s,additionalNodesProps:n}){const g=t.useRef(null),b=(0,h.fp)(),y=(0,j.YQ)(),C=function(){const e=(0,j.YQ)(),s=(0,j.N4)((e=>e.cluster.defaultClusterTab)),n=(0,o.W5)(v.Ay.cluster),{activeTab:r}=(null===n||void 0===n?void 0:n.params)||{};let l;l=(0,Us.eC)(r)?r:s;return t.useEffect((()=>{l!==s&&e((0,m.Yv)(l))}),[l,s,e]),l}(),[{clusterName:w,backend:k}]=(0,i.useQueryParams)({clusterName:i.StringParam,backend:i.StringParam}),T=(0,j.N4)((e=>(0,m.zR)(e,null!==w&&void 0!==w?w:void 0))),{title:S}=(0,m.Zd)(),_=null!==S&&void 0!==S?S:T,{data:{clusterData:E,groupsStats:V}={},isLoading:O,error:D}=m.Zh.useGetClusterInfoQuery(null!==w&&void 0!==w?w:void 0),L=D&&"object"===typeof D?D:void 0,A=(0,j.N4)((e=>(0,m.ds)(e,null!==w&&void 0!==w?w:void 0)));t.useEffect((()=>{y((0,p.g)("cluster",{}))}),[y]);const z=t.useMemo((()=>Us.bn.find((({id:e})=>e===C))),[C]);return(0,U.jsxs)("div",{className:Fs(),ref:g,children:[(0,U.jsx)(a.mg,{defaultTitle:`${_} \u2014 YDB Monitoring`,titleTemplate:`%s \u2014 ${_} \u2014 YDB Monitoring`,children:z?(0,U.jsx)("title",{children:z.title}):null}),(0,U.jsx)("div",{className:Fs("header"),children:O?(0,U.jsx)(r.E,{className:Fs("title-skeleton")}):(0,U.jsx)(c.c,{size:"m",status:null===E||void 0===E?void 0:E.Overall,name:_,className:Fs("title")})}),(0,U.jsx)("div",{className:Fs("sticky-wrapper"),children:(0,U.jsx)(d.E,{className:Fs("auto-refresh-control")})}),b&&(0,U.jsx)(Vs,{cluster:null!==E&&void 0!==E?E:{},groupStats:V,loading:O,error:L||(null===E||void 0===E?void 0:E.error)}),(0,U.jsx)("div",{className:Fs("tabs-sticky-wrapper"),children:(0,U.jsx)(l.t,{size:"l",allowNotSelected:!0,activeTab:C,items:Us.bn,wrapTo:({id:e},s)=>{const n=(0,Us.a)(e,{clusterName:w,backend:k});return(0,U.jsx)(u.E,{to:n,onClick:()=>{y((0,m.Yv)(e))},children:s},e)}})}),(0,U.jsxs)(o.dO,{children:[(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.overview)).pathname,children:(0,U.jsx)(Bs,{cluster:E,loading:O,error:L,additionalClusterProps:e})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.tablets)).pathname,children:(0,U.jsx)(f.Q,{loading:O,tablets:A})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.tenants)).pathname,children:(0,U.jsx)(de,{additionalTenantsProps:s})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.nodes)).pathname,children:(0,U.jsx)(x.G,{parentRef:g,additionalNodesProps:n})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.storage)).pathname,children:(0,U.jsx)(N.z,{parentRef:g})}),(0,U.jsx)(o.qh,{path:(0,v.a3)((0,Us.a)(Us.Bi.versions)).pathname,children:(0,U.jsx)(Qe,{cluster:E,loading:O})}),(0,U.jsx)(o.qh,{render:()=>(0,U.jsx)(o.rd,{to:(0,v.a3)((0,Us.a)(C))})})]})]})}},42655:(e,s,n)=>{n.d(s,{y:()=>c});var t=n(59284),r=n(89169),l=n(77506),a=n(66781),o=n(60712);const i=(0,l.cn)("ydb-info-viewer-skeleton"),d=()=>(0,o.jsxs)("div",{className:i("label"),children:[(0,o.jsx)(r.E,{className:i("label__text")}),(0,o.jsx)("div",{className:i("label__dots")})]}),c=({rows:e=8,className:s,delay:n=600})=>{const[l]=(0,a.y)(n);let c=(0,o.jsxs)(t.Fragment,{children:[(0,o.jsx)(d,{}),(0,o.jsx)(r.E,{className:i("value")})]});return l||(c=null),(0,o.jsx)("div",{className:i(null,s),children:[...new Array(e)].map(((e,s)=>(0,o.jsx)("div",{className:i("row"),children:c},`skeleton-row-${s}`)))})}},70043:(e,s,n)=>{n.d(s,{E:()=>a});var t=n(89169),r=n(66781),l=n(60712);const a=({delay:e=600,className:s})=>{const[n]=(0,r.y)(e);return n?(0,l.jsx)(t.E,{className:s}):null}}}]); \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/49393.48f114fd.chunk.js b/ydb/core/viewer/monitoring/static/js/49393.48f114fd.chunk.js deleted file mode 100644 index cb61c25a4402..000000000000 --- a/ydb/core/viewer/monitoring/static/js/49393.48f114fd.chunk.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[49393],{3685:(e,t,a)=>{a.d(t,{$:()=>i});var n=a(54090),l=a(77506),s=a(33775),o=a(60712);const r=(0,l.cn)("ydb-entity-page-title");function i({entityName:e,status:t=n.m.Grey,id:a,className:l}){return(0,o.jsxs)("div",{className:r(null,l),children:[(0,o.jsx)("span",{className:r("prefix"),children:e}),(0,o.jsx)(s.k,{className:r("icon"),status:t,size:"s"}),a]})}},21545:(e,t,a)=>{a.d(t,{X:()=>l});var n=a(78034);const l=a(21334).F.injectEndpoints({endpoints:e=>({getTablet:e.query({queryFn:async({id:e,database:t,followerId:a},{signal:l})=>{try{const[s,o,r]=await Promise.all([window.api.viewer.getTablet({id:e,database:t,followerId:a},{signal:l}),window.api.viewer.getTabletHistory({id:e,database:t},{signal:l}),window.api.viewer.getNodesList({signal:l})]),i=(0,n.nN)(r),d=Object.keys(o).reduce(((e,t)=>{var a;const n=null===(a=o[t])||void 0===a?void 0:a.TabletStateInfo;return null===n||void 0===n||n.forEach((a=>{var n;const{ChangeTime:l,Generation:s,State:o,Leader:r,FollowerId:d}=a,c=i&&t?null===(n=i.get(Number(t)))||void 0===n?void 0:n.Host:void 0;e.push({nodeId:t,generation:s,changeTime:l,state:o,leader:r,followerId:d,fqdn:c})})),e}),[]),{TabletStateInfo:c=[]}=s,u=void 0===a?c.find((e=>e.Leader)):c.find((e=>{var t;return(null===(t=e.FollowerId)||void 0===t?void 0:t.toString())===a})),{TabletId:h}=u||{};return{data:{id:h,data:u,history:d}}}catch(s){return{error:s}}},providesTags:(e,t,a)=>["All",{type:"Tablet",id:a.id}]}),getTabletDescribe:e.query({queryFn:async({tenantId:e},{signal:t})=>{try{const a=await window.api.viewer.getTabletDescribe(e,{signal:t}),{SchemeShard:n,PathId:l}=e;return{data:(null===a||void 0===a?void 0:a.Path)||`${n}:${l}`}}catch(a){return{error:a}}},providesTags:["All"]}),getAdvancedTableInfo:e.query({queryFn:async({id:e,hiveId:t},{signal:a})=>{try{return{data:await window.api.tablets.getTabletFromHive({id:e,hiveId:t},{signal:a})}}catch(n){return{error:n}}},providesTags:(e,t,a)=>["All",{type:"Tablet",id:a.id}]}),killTablet:e.mutation({queryFn:async({id:e})=>{try{return{data:await window.api.tablets.killTablet(e)}}catch(t){return{error:t}}},invalidatesTags:(e,t,a)=>[{type:"Tablet",id:a.id},{type:"Tablet",id:"LIST"}]}),stopTablet:e.mutation({queryFn:async({id:e,hiveId:t})=>{try{return{data:await window.api.tablets.stopTablet(e,t)}}catch(a){return{error:a}}},invalidatesTags:(e,t,a)=>[{type:"Tablet",id:a.id},{type:"Tablet",id:"LIST"}]}),resumeTablet:e.mutation({queryFn:async({id:e,hiveId:t})=>{try{return{data:await window.api.tablets.resumeTablet(e,t)}}catch(a){return{error:a}}},invalidatesTags:(e,t,a)=>[{type:"Tablet",id:a.id},{type:"Tablet",id:"LIST"}]})}),overrideExisting:"throw"})},22983:(e,t,a)=>{a.d(t,{B:()=>d});var n=a(59284),l=a(84476),s=a(84375),o=a(55974),r=a(42829),i=a(60712);function d({children:e,onConfirmAction:t,onConfirmActionSuccess:a,dialogHeader:d,dialogText:c,retryButtonText:u,buttonDisabled:h=!1,buttonView:m="action",buttonTitle:v,buttonClassName:p,withPopover:b=!1,popoverContent:g,popoverPlacement:x="right",popoverDisabled:f=!0}){const[y,w]=n.useState(!1),[j,N]=n.useState(!1),[I,T]=n.useState(!1),S=()=>(0,i.jsx)(l.$,{onClick:()=>w(!0),view:m,disabled:h,loading:!h&&j,className:p,title:v,children:e});return(0,i.jsxs)(n.Fragment,{children:[(0,i.jsx)(o.g,{visible:y,header:d,text:c,withRetry:I,retryButtonText:u,onConfirm:async e=>{N(!0),await t(e)},onConfirmActionSuccess:async()=>{T(!1);try{await(null===a||void 0===a?void 0:a())}finally{N(!1)}},onConfirmActionError:e=>{T((0,r.D)(e)),N(!1)},onClose:()=>{w(!1)}}),b?(0,i.jsx)(s.A,{content:g,placement:x,disabled:f,children:S()}):S()]})}},27775:(e,t,a)=>{a.d(t,{i:()=>o});var n=a(47665),l=a(58267),s=a(60712);function o({state:e}){return(0,s.jsx)(n.J,{theme:(0,l._)(e),children:e})}},42829:(e,t,a)=>{a.d(t,{D:()=>n});const n=e=>Boolean(e&&"object"===typeof e&&"retryPossible"in e&&e.retryPossible)},55974:(e,t,a)=>{a.d(t,{g:()=>x});var n=a(59284),l=a(18677),s=a(71153),o=a(74321),r=a(2198),i=a(99991),d=a(89954),c=a(77506),u=a(81288),h=a(48372);const m=JSON.parse('{"default-error":"Something went wrong, action cannot be completed","no-rights-error":"You don\'t have enough rights to complete the operation","button-confirm":"Confirm","button-retry":"Retry","button-cancel":"Cancel","button-close":"Close","checkbox-text":"I understand what I\'m doing"}'),v=(0,h.g4)("ydb-critical-action-dialog",{en:m});var p=a(60712);const b=(0,c.cn)("ydb-critical-dialog"),g=e=>{if((0,u.cH)(e)){if(403===e.status)return v("no-rights-error");if("string"===typeof e.data)return e.data;if((0,u._E)(e)&&e.data)return(0,p.jsx)(d.O,{hideSeverity:!0,data:e.data});if(e.statusText)return e.statusText}return v("default-error")};function x({visible:e,header:t,text:a,withRetry:d,retryButtonText:c,withCheckBox:u,onClose:h,onConfirm:m,onConfirmActionSuccess:x,onConfirmActionError:f}){const[y,w]=n.useState(!1),[j,N]=n.useState(),[I,T]=n.useState(!1),S=async e=>(w(!0),m(e).then((()=>{x(),h()})).catch((e=>{f(e),N(e)})).finally((()=>{w(!1)})));return(0,p.jsx)(r.l,{open:e,hasCloseButton:!1,className:b(),size:"s",onClose:h,onTransitionExited:()=>{N(void 0),T(!1)},children:j?(0,p.jsxs)(n.Fragment,{children:[(0,p.jsx)(r.l.Header,{caption:t}),(0,p.jsx)(r.l.Body,{className:b("body"),children:(0,p.jsxs)("div",{className:b("body-message",{error:!0}),children:[(0,p.jsx)("span",{className:b("error-icon"),children:(0,p.jsx)(l.A,{width:"24",height:"22"})}),g(j)]})}),(0,p.jsx)(r.l.Footer,{loading:!1,preset:"default",textButtonApply:d?c||v("button-retry"):void 0,textButtonCancel:v("button-close"),onClickButtonApply:()=>S(!0),onClickButtonCancel:h})]}):(0,p.jsxs)(n.Fragment,{children:[(0,p.jsx)(r.l.Header,{caption:t}),(0,p.jsxs)(r.l.Body,{className:b("body"),children:[(0,p.jsxs)("div",{className:b("body-message",{warning:!0}),children:[(0,p.jsx)("span",{className:b("warning-icon"),children:(0,p.jsx)(i.I,{data:s.A,size:24})}),a]}),u?(0,p.jsx)(o.S,{checked:I,onUpdate:T,children:v("checkbox-text")}):null]}),(0,p.jsx)(r.l.Footer,{loading:y,preset:"default",textButtonApply:v("button-confirm"),textButtonCancel:v("button-cancel"),propsButtonApply:{type:"submit",disabled:u&&!I},onClickButtonCancel:h,onClickButtonApply:()=>S()})]})})}},58267:(e,t,a)=>{a.d(t,{P:()=>o,_:()=>r});var n=a(54090),l=a(6354);const s={[l.r.Dead]:n.m.Red,[l.r.Created]:n.m.Yellow,[l.r.ResolveStateStorage]:n.m.Yellow,[l.r.Candidate]:n.m.Yellow,[l.r.BlockBlobStorage]:n.m.Yellow,[l.r.WriteZeroEntry]:n.m.Yellow,[l.r.Restored]:n.m.Yellow,[l.r.Discover]:n.m.Yellow,[l.r.Lock]:n.m.Yellow,[l.r.Stopped]:n.m.Yellow,[l.r.ResolveLeader]:n.m.Yellow,[l.r.RebuildGraph]:n.m.Yellow,[l.r.Deleted]:n.m.Green,[l.r.Active]:n.m.Green},o=e=>{if(!e)return n.m.Grey;return t=e,Object.values(n.m).includes(t)?e:s[e];var t};function r(e){if(!e)return"unknown";switch(e){case l.r.Dead:return"danger";case l.r.Active:case l.r.Deleted:return"success";default:return"warning"}}},58389:(e,t,a)=>{a.d(t,{B:()=>u});var n=a(87184),l=a(77506),s=a(90053),o=a(70043),r=a(60712);const i=(0,l.cn)("ydb-page-meta"),d="\xa0\xa0\xb7\xa0\xa0";function c({items:e,loading:t}){return(0,r.jsx)("div",{className:i("info"),children:t?(0,r.jsx)(o.E,{className:i("skeleton")}):e.filter((e=>Boolean(e))).join(d)})}function u({className:e,...t}){return(0,r.jsxs)(n.s,{gap:1,alignItems:"center",justifyContent:"space-between",className:i(null,e),children:[(0,r.jsx)(c,{...t}),(0,r.jsx)(s.E,{})]})}},70043:(e,t,a)=>{a.d(t,{E:()=>o});var n=a(89169),l=a(66781),s=a(60712);const o=({delay:e=600,className:t})=>{const[a]=(0,l.y)(e);return a?(0,s.jsx)(n.E,{className:t}):null}},79737:(e,t,a)=>{a.d(t,{A:()=>r,X:()=>i});var n=a(5874),l=a(77506),s=a(60712);const o=(0,l.cn)("ydb-table");function r({children:e,className:t}){return(0,s.jsx)("div",{className:o("table-header-content",t),children:e})}function i({className:e,width:t,wrapperClassName:a,...l}){return(0,s.jsx)("div",{className:o(null,a),children:(0,s.jsx)(n.W,{headerCellClassName:({column:e})=>{var t;const a=null===(t=e.columnDef.meta)||void 0===t?void 0:t.align;return o("table-header-cell",{align:a})},cellClassName:e=>{var t,a;const n=null===e||void 0===e||null===(t=e.column.columnDef.meta)||void 0===t?void 0:t.align,l=null===e||void 0===e||null===(a=e.column.columnDef.meta)||void 0===a?void 0:a.verticalAlign;return o("table-cell",{align:n,"vertical-align":l})},className:o("table",{width:t},e),...l})})}},81342:(e,t,a)=>{a.r(t),a.d(t,{Tablet:()=>pe});var n=a(59284),l=a(87184),s=a(23871),o=a(44992),r=a(61750),i=a(10755),d=a(67087),c=a(370),u=a(7889),h=a(3685),m=a(44508),v=a(44294),p=a(98167),b=a(58389),g=a(92459),x=a(40174),f=a(21545),y=a(54090),w=a(77506),j=a(76086),N=a(90182),I=a(12888),T=a(76938);const S=e=>n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),n.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M4.5 1.5a3 3 0 0 0-3 3v7a3 3 0 0 0 3 3h7a3 3 0 0 0 3-3v-7a3 3 0 0 0-3-3z",clipRule:"evenodd"})),_=e=>n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),n.createElement("path",{fill:"currentColor",d:"M13.756 10.164c1.665-.962 1.665-3.366 0-4.328L5.251.919C3.584-.045 1.5 1.158 1.5 3.083v9.834c0 1.925 2.084 3.128 3.751 2.164z"}));var C=a(99991),A=a(22983),k=a(6354),D=a(48372);const E=JSON.parse('{"tablet.header":"Tablet","tablet.meta-database":"Database","tablet.meta-follower":"Follower","controls.kill":"Restart","controls.stop":"Stop","controls.resume":"Resume","controls.kill-not-allowed":"You don\'t have enough rights to restart tablet","controls.stop-not-allowed":"You don\'t have enough rights to stop tablet","controls.resume-not-allowed":"You don\'t have enough rights to resume tablet","dialog.kill-header":"Restart tablet","dialog.stop-header":"Stop tablet","dialog.resume-header":"Resume tablet","dialog.kill-text":"The tablet will be restarted. Do you want to proceed?","dialog.stop-text":"The tablet will be stopped. Do you want to proceed?","dialog.resume-text":"The tablet will be resumed. Do you want to proceed?","emptyState":"The tablet was not found","label_tablet-history":"Tablets","label_tablet-channels":"Storage"}'),F=(0,D.g4)("ydb-tablet-page",{en:E});function B(e){return Boolean(e&&"0"!==e)}var R=a(60712);const O=({tablet:e})=>{const{TabletId:t,HiveId:a}=e,s=(0,I.X)(),[o]=f.X.useKillTabletMutation(),[r]=f.X.useStopTabletMutation(),[i]=f.X.useResumeTabletMutation();if(!t)return null;const d=B(a),c=e.State===k.r.Stopped,u=e.State!==k.r.Stopped&&e.State!==k.r.Dead,h=e.State===k.r.Stopped||e.State===k.r.Deleted;return(0,R.jsxs)(l.s,{gap:2,wrap:"nowrap",children:[(0,R.jsxs)(A.B,{dialogHeader:F("dialog.kill-header"),dialogText:F("dialog.kill-text"),onConfirmAction:()=>o({id:t}).unwrap(),buttonDisabled:c||!s,withPopover:!0,buttonView:"normal",popoverContent:F("controls.kill-not-allowed"),popoverPlacement:"bottom",popoverDisabled:s,children:[(0,R.jsx)(C.I,{data:T.A}),F("controls.kill")]}),d&&(0,R.jsxs)(n.Fragment,{children:[(0,R.jsxs)(A.B,{dialogHeader:F("dialog.stop-header"),dialogText:F("dialog.stop-text"),onConfirmAction:()=>r({id:t,hiveId:a}).unwrap(),buttonDisabled:h||!s,withPopover:!0,buttonView:"normal",popoverContent:F("controls.stop-not-allowed"),popoverPlacement:"bottom",popoverDisabled:s,children:[(0,R.jsx)(C.I,{data:S}),F("controls.stop")]}),(0,R.jsxs)(A.B,{dialogHeader:F("dialog.resume-header"),dialogText:F("dialog.resume-text"),onConfirmAction:()=>i({id:t,hiveId:a}).unwrap(),buttonDisabled:u||!s,withPopover:!0,buttonView:"normal",popoverContent:F("controls.resume-not-allowed"),popoverPlacement:"bottom",popoverDisabled:s,children:[(0,R.jsx)(C.I,{data:_}),F("controls.resume")]})]})]})};var P=a(52905),$=a(60073),G=a(25196),H=a(27775),L=a(41826),q=a(31684),z=a(29819);const Y=JSON.parse('{"field_scheme-shard":"SchemeShard","field_follower":"Follower","field_generation":"Generation","field_hive":"HiveId","field_state":"State","field_uptime":"Uptime","field_node":"Node","field_links":"Links","field_developer-ui-app":"App","field_developer-ui-counters":"Counters","field_developer-ui-executor":"Executor DB internals","field_developer-ui-state":"State Storage","title_info":"Info","title_links":"Links"}'),M=(0,D.g4)("ydb-tablet-info",{en:Y}),K=(0,w.cn)("ydb-tablet-info"),X=({tablet:e})=>{const t=(0,I.X)(),{ChangeTime:a,Generation:n,FollowerId:s,NodeId:o,HiveId:r,State:i,TenantId:{SchemeShard:d}={},TabletId:c}=e,u=B(r),h=i===k.r.Active,m=[];u&&m.push({label:M("field_hive"),value:(0,R.jsx)(P.N_,{to:(0,g.DM)(r),className:K("link"),children:r})}),d&&m.push({label:M("field_scheme-shard"),value:(0,R.jsx)(P.N_,{to:(0,g.DM)(d),className:K("link"),children:d})}),m.push({label:M("field_state"),value:(0,R.jsx)(H.i,{state:i})}),h&&m.push({label:M("field_uptime"),value:(0,R.jsx)(L.H,{ChangeTime:a})}),m.push({label:M("field_generation"),value:n},{label:M("field_node"),value:(0,R.jsx)(P.N_,{className:K("link"),to:(0,z.vI)(String(o)),children:o})}),s&&m.push({label:M("field_follower"),value:s});return(0,R.jsxs)(l.s,{gap:10,wrap:"nowrap",children:[(0,R.jsxs)("div",{children:[(0,R.jsx)("div",{className:K("section-title"),children:M("title_info")}),(0,R.jsx)($.z_,{info:m})]}),t&&c?(0,R.jsxs)("div",{children:[(0,R.jsx)("div",{className:K("section-title"),children:M("title_links")}),(0,R.jsxs)(l.s,{direction:"column",gap:3,children:[(0,R.jsx)(G.K,{title:M("field_developer-ui-app"),url:(0,q._t)(c,"app")}),(0,R.jsx)(G.K,{title:M("field_developer-ui-counters"),url:(0,q._t)(c,"counters")}),(0,R.jsx)(G.K,{title:M("field_developer-ui-executor"),url:(0,q._t)(c,"executorInternals")}),(0,R.jsx)(G.K,{title:M("field_developer-ui-state"),url:(0,q._t)(c,void 0,"SsId")})]})]}):null]})};var Q=a(36590),J=a(79737),V=a(84476),W=a(33705),U=a(56839);const Z=JSON.parse('{"label_channel-index":"Channel","label_storage-pool":"Storage Pool Name","label_group-id":"Group ID","label_generation":"From generation","label_timestamp":"Timestamp"}'),ee=(0,D.g4)("ydb-tablet-storage-info",{en:Z}),te=(0,w.cn)("ydb-tablet-storage-info");function ae(e,t){const a=e.getValue(),n="function"===typeof t?t(a):a;return(0,R.jsx)("div",{className:te("metrics-cell"),children:n})}function ne({row:e,name:t,hasExpand:a}){const n=e.getCanExpand();return(0,R.jsxs)(l.s,{gap:1,alignItems:"flex-start",className:te("name-wrapper"),children:[n&&(0,R.jsx)(V.$,{view:"flat",size:"xs",onClick:e.getToggleExpandedHandler(),children:(0,R.jsx)(V.$.Icon,{children:(0,R.jsx)(W.I,{direction:e.getIsExpanded()?"bottom":"right",size:14})})}),(0,R.jsx)("div",{className:te("name-content",{"no-control":a&&!n}),children:t})]})}function le({data:e}){const[t,a]=n.useState({}),l=n.useMemo((()=>function(e){var t;if(!e)return[];const{BoundChannels:a,TabletStorageInfo:n={}}=e,l=null!==(t=n.Channels)&&void 0!==t?t:[],s=[];for(const r of l){var o;const e=r.Channel,t=r.History;if(!e||!t||!t.length)continue;const n=[...t];n.reverse();const[l,...i]=n,d={...l,storagePoolName:null===a||void 0===a||null===(o=a[e])||void 0===o?void 0:o.StoragePoolName,channelIndex:e,children:i};s.push(d)}return s}(e)),[e]),s=n.useMemo((()=>l.some((e=>{var t;return null===(t=e.children)||void 0===t?void 0:t.length}))),[l]),o=n.useMemo((()=>{return e=s,[{accessorKey:"channelIndex",header:()=>(0,R.jsx)(J.A,{children:ee("label_channel-index")}),size:50,cell:ae,meta:{align:"right"}},{accessorKey:"storagePoolName",header:()=>(0,R.jsx)(J.A,{children:ee("label_storage-pool")}),size:200,cell:ae},{accessorKey:"GroupID",header:()=>(0,R.jsx)(J.A,{className:e?te("with-padding"):void 0,children:ee("label_group-id")}),size:100,cell:t=>(0,R.jsx)(ne,{row:t.row,name:t.getValue(),hasExpand:e})},{accessorKey:"FromGeneration",header:()=>(0,R.jsx)(J.A,{children:ee("label_generation")}),size:100,cell:ae,meta:{align:"right"}},{accessorKey:"Timestamp",header:()=>(0,R.jsx)(J.A,{children:ee("label_timestamp")}),size:200,cell:e=>ae(e,U.Ey),meta:{align:"right"}}];var e}),[s]),r=(0,Q.K)({columns:o,data:l,getSubRows:e=>e.children,enableExpanding:!0,onExpandedChange:a,state:{expanded:t}});return(0,R.jsx)(J.X,{table:r})}var se=a(4557),oe=a(10508),re=a(82015),ie=a(17594);const de={displayIndices:!1,highlightRows:!0},ce=({history:e,database:t,tabletId:a})=>{const l=n.useMemo((()=>(({database:e,tabletId:t})=>[{name:"Generation",align:se.Ay.RIGHT,render:({row:e})=>e.generation},{name:"Change time",align:se.Ay.RIGHT,sortable:!1,render:({row:e})=>(0,R.jsx)(L.H,{ChangeTime:e.changeTime}),width:120},{name:"State",sortable:!1,render:({row:e})=>(0,R.jsx)(H.i,{state:e.state})},{name:"Tablet",sortable:!1,render:({row:a})=>{var n;const l=(0,g.DM)(t,{database:e,followerId:a.leader||null===(n=a.followerId)||void 0===n?void 0:n.toString()}),s=`${t}${a.followerId?`.${a.followerId}`:""}`;return(0,R.jsx)(re.E,{to:l,children:s})}},{name:"Node ID",align:se.Ay.RIGHT,sortable:!1,render:({row:e})=>(0,R.jsx)(re.E,{to:(0,z.vI)(e.nodeId),children:e.nodeId})},{name:"Node FQDN",sortable:!1,width:300,render:({row:e})=>e.fqdn?(0,R.jsx)(oe.c,{name:e.fqdn,showStatus:!1,hasClipboardButton:!0}):(0,R.jsx)("span",{children:"\u2014"})}])({database:t,tabletId:a})),[t,a]);return(0,R.jsx)(ie.l,{columnsWidthLSKey:"tabletTableColumnsWidth",data:e,columns:l,settings:de,initialSortOrder:{columnId:"Generation",order:se.Ay.DESCENDING}})},ue=(0,w.cn)("ydb-tablet-page"),he={history:"history",channels:"channels"},me=[{id:he.history,get title(){return F("label_tablet-history")}},{id:he.channels,get title(){return F("label_tablet-channels")},isAdvanced:!0}],ve=c.z.nativeEnum(he).catch(he.history);function pe(){var e;const t=(0,N.YQ)(),{id:a}=(0,i.g)(),[{database:s,clusterName:c,followerId:u}]=(0,d.useQueryParams)(g.qc),[h]=(0,N.Nt)(),{currentData:v,isFetching:y,error:w}=f.X.useGetTabletQuery({id:a,database:null!==s&&void 0!==s?s:void 0,followerId:null!==u&&void 0!==u?u:void 0},{pollingInterval:h}),I=y&&void 0===v,{data:T={},history:S=[]}=v||{},{currentData:_}=f.X.useGetTabletDescribeQuery(T.TenantId?{tenantId:T.TenantId}:o.hT),C=null!==(e=_||s)&&void 0!==e?e:void 0,A=T.Type;n.useEffect((()=>{t((0,x.g)("tablet",{tenantName:null!==s&&void 0!==s?s:void 0,tabletId:a,tabletType:A}))}),[t,s,a,A]);const{Leader:k,Type:D}=T,E=[];return C&&E.push(`${F("tablet.meta-database")}: ${C}`),D&&E.push(D),!1===k&&E.push(F("tablet.meta-follower").toUpperCase()),(0,R.jsxs)(l.s,{gap:5,direction:"column",className:ue(),children:[(0,R.jsx)(r.mg,{children:(0,R.jsx)("title",{children:`${a} \u2014 ${F("tablet.header")} \u2014 ${C||c||j.QM}`})}),(0,R.jsx)(b.B,{items:E}),(0,R.jsxs)(p.r,{loading:I,size:"l",children:[w?(0,R.jsx)(m.o,{error:w}):null,v?(0,R.jsx)(be,{id:a,tablet:T,history:S,database:C}):null]})]})}function be({id:e,tablet:t,history:a,database:n}){const s=!Object.keys(t).length,{Overall:o,HiveId:r,FollowerId:i}=t,d=`${e}${i?`.${i}`:""}`;return(0,R.jsxs)(u.q,{title:F("emptyState"),className:ue("placeholder"),isEmpty:s,children:[(0,R.jsxs)(l.s,{gap:5,direction:"column",children:[(0,R.jsx)(h.$,{entityName:F("tablet.header"),status:null!==o&&void 0!==o?o:y.m.Grey,id:d}),(0,R.jsx)(O,{tablet:t}),(0,R.jsx)(X,{tablet:t})]}),(0,R.jsx)(ge,{id:e,hiveId:r,history:a,database:n})]})}function ge({id:e,hiveId:t,history:a,database:o}){var r;const[{activeTab:i,...c},u]=(0,d.useQueryParams)(g.qc),h=!(0,I.X)()||!B(t);let m=ve.parse(i);return h&&null!==(r=me.find((e=>e.id===m)))&&void 0!==r&&r.isAdvanced&&(m=he.history),n.useEffect((()=>{i!==m&&u({activeTab:m},"replaceIn")}),[i,m,u]),(0,R.jsxs)(l.s,{gap:5,direction:"column",children:[(0,R.jsx)("div",{children:(0,R.jsx)(s.t,{size:"l",items:me.filter((({isAdvanced:e})=>!e||!h)),activeTab:m,wrapTo:(t,a)=>{const n=(0,g.DM)(e,{...c,activeTab:t.id});return(0,R.jsx)(v.E,{to:n,children:a},t.id)}})}),"history"===m?(0,R.jsx)(ce,{history:a,tabletId:e,database:o}):null,"channels"!==m||h?null:(0,R.jsx)(xe,{id:e,hiveId:t})]})}function xe({id:e,hiveId:t}){const[a]=(0,N.Nt)(),{currentData:n,error:l,isFetching:s}=f.X.useGetAdvancedTableInfoQuery({id:e,hiveId:t},{pollingInterval:a}),o=s&&void 0===n;return(0,R.jsxs)(p.r,{loading:o,size:"l",children:[l?(0,R.jsx)(m.o,{error:l}):null,n?(0,R.jsx)(le,{data:n}):null]})}},89169:(e,t,a)=>{a.d(t,{E:()=>s});var n=a(59284);const l=(0,a(69220).om)("skeleton");function s({className:e,style:t,qa:a}){return n.createElement("div",{className:l(null,e),style:t,"data-qa":a})}},89954:(e,t,a)=>{a.d(t,{O:()=>S});var n=a(59284),l=a(45720),s=a(16929),o=a(71153),r=a(18677),i=a(84476),d=a(33705),c=a(67884),u=a(99991),h=a(77506),m=a(48372);const v=JSON.parse('{"default_collapse_label":"Show less","default_expand_label":"Show more","chars_count":[" ({{count}} symbol)"," ({{count}} symbols)"," ({{count}} symbols)"," ({{count}} symbols)"]}'),p=JSON.parse('{"default_collapse_label":"\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435","default_expand_label":"\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0435\u0449\u0451","chars_count":[" ({{count}} \u0441\u0438\u043c\u0432\u043e\u043b)"," ({{count}} \u0441\u0438\u043c\u0432\u043e\u043b\u0430)"," ({{count}} \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432)"," ({{count}} \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432)"]}'),b=(0,m.g4)("ydb-shorty-string",{ru:p,en:v});var g=a(60712);const x=(0,h.cn)("kv-shorty-string");function f({value:e="",limit:t=200,strict:a=!1,displayLength:l=!0,render:s=e=>e,onToggle:o,expandLabel:r=b("default_expand_label"),collapseLabel:i=b("default_collapse_label")}){const[d,u]=n.useState(!1),h=(d?i:r)+(l&&!d?b("chars_count",{count:e.length}):""),m=e.length>t+(a?0:h.length),v=d||!m?e:e.slice(0,t-4)+"\xa0...";return(0,g.jsxs)("div",{className:x(),children:[s(v),m?(0,g.jsx)(c.N,{className:x("toggle"),href:"#",onClick:e=>{e.stopPropagation(),e.preventDefault(),u((e=>!e)),null===o||void 0===o||o()},children:h}):null]})}var y=a(41650);const w=["S_FATAL","S_ERROR","S_WARNING","S_INFO"];function j(e){return function(e){return!!e&&void 0!==w[e]}(e)?w[e]:"S_INFO"}const N=(0,h.cn)("kv-result-issues"),I=(0,h.cn)("kv-issues"),T=(0,h.cn)("kv-issue");function S({data:e,hideSeverity:t}){const[a,l]=n.useState(!1),s="string"===typeof e||null===e||void 0===e?void 0:e.issues,o=Array.isArray(s)&&s.length>0;return(0,g.jsxs)("div",{className:N(),children:[(0,g.jsxs)("div",{className:N("error-message"),children:[(()=>{let a;if("string"===typeof e)a=e;else{var l,s;const o=j(null===e||void 0===e||null===(l=e.error)||void 0===l?void 0:l.severity);a=(0,g.jsxs)(n.Fragment,{children:[t?null:(0,g.jsxs)(n.Fragment,{children:[(0,g.jsx)(F,{severity:o})," "]}),(0,g.jsx)("span",{className:N("error-message-text"),children:null===e||void 0===e||null===(s=e.error)||void 0===s?void 0:s.message})]})}return a})(),o&&(0,g.jsx)(i.$,{view:"normal",onClick:()=>l(!a),children:a?"Hide details":"Show details"})]}),o&&a&&(0,g.jsx)(_,{hideSeverity:t,issues:s})]})}function _({issues:e,hideSeverity:t}){const a=null===e||void 0===e?void 0:e.reduce(((e,t)=>{var a;const n=null!==(a=t.severity)&&void 0!==a?a:10;return Math.min(e,n)}),10);return(0,g.jsx)("div",{className:I(null),children:null===e||void 0===e?void 0:e.map(((e,n)=>(0,g.jsx)(C,{hideSeverity:t,issue:e,expanded:e===a},n)))})}function C({issue:e,hideSeverity:t,level:a=0}){const[l,s]=n.useState(!0),o=j(e.severity),r=e.issues,c=Array.isArray(r)&&r.length>0,u=l?"bottom":"right";return(0,g.jsxs)("div",{className:T({leaf:!c,"has-issues":c}),children:[(0,g.jsxs)("div",{className:T("line"),children:[c&&(0,g.jsx)(i.$,{view:"flat-secondary",onClick:()=>s(!l),className:T("arrow-toggle"),children:(0,g.jsx)(d.I,{direction:u,size:16})}),t?null:(0,g.jsx)(F,{severity:o}),(0,g.jsx)(A,{issue:e}),e.issue_code?(0,g.jsxs)("span",{className:T("code"),children:["Code: ",e.issue_code]}):null]}),c&&l&&(0,g.jsx)("div",{className:T("issues"),children:(0,g.jsx)(k,{issues:r,level:a+1,expanded:l})})]})}function A({issue:e}){var t;const a=function(e){const{position:t}=e;if("object"!==typeof t||null===t||!(0,y.kf)(t.row))return"";const{row:a,column:n}=t;return(0,y.kf)(n)?`${a}:${n}`:`line ${a}`}(e),n=window.ydbEditor,l=()=>(0,g.jsxs)("span",{className:T("message"),children:[a&&(0,g.jsx)("span",{className:T("place-text"),title:"Position",children:a}),(0,g.jsx)("div",{className:T("message-text"),children:(0,g.jsx)(f,{value:e.message,expandLabel:"Show full message"})})]}),{row:s,column:o}=null!==(t=e.position)&&void 0!==t?t:{};if(!((0,y.kf)(s)&&n))return l();return(0,g.jsx)(c.N,{href:"#",extraProps:{draggable:!1},onClick:()=>{const e={lineNumber:s,column:null!==o&&void 0!==o?o:0};n.setPosition(e),n.revealPositionInCenterIfOutsideViewport(e),n.focus()},view:"primary",children:l()})}function k(e){const{issues:t,level:a,expanded:n}=e;return(0,g.jsx)("div",{className:T("list"),children:t.map(((e,t)=>(0,g.jsx)(C,{issue:e,level:a,expanded:n},t)))})}const D={S_INFO:l.A,S_WARNING:s.A,S_ERROR:o.A,S_FATAL:r.A},E=(0,h.cn)("yql-issue-severity");function F({severity:e}){const t=e.slice(2).toLowerCase();return(0,g.jsxs)("span",{className:E({severity:t}),children:[(0,g.jsx)(u.I,{className:E("icon"),data:D[e]}),(0,g.jsx)("span",{className:E("title"),children:t})]})}},90053:(e,t,a)=>{a.d(t,{E:()=>v});var n=a(8873),l=a(84476),s=a(24555),o=a(21334),r=a(77506),i=a(90182),d=a(48372);const c=JSON.parse('{"None":"None","15 sec":"15 sec","1 min":"1 min","2 min":"2 min","5 min":"5 min","Refresh":"Refresh"}'),u=(0,d.g4)("ydb-diagnostics-autorefresh-control",{en:c});var h=a(60712);const m=(0,r.cn)("auto-refresh-control");function v({className:e,onManualRefresh:t}){const a=(0,i.YQ)(),[r,d]=(0,i.Nt)();return(0,h.jsxs)("div",{className:m(null,e),children:[(0,h.jsx)(l.$,{view:"flat-secondary",onClick:()=>{a(o.F.util.invalidateTags(["All"])),null===t||void 0===t||t()},extraProps:{"aria-label":u("Refresh")},children:(0,h.jsx)(l.$.Icon,{children:(0,h.jsx)(n.A,{})})}),(0,h.jsxs)(s.l,{value:[String(r)],onUpdate:e=>{d(Number(e))},width:85,qa:"ydb-autorefresh-select",children:[(0,h.jsx)(s.l.Option,{value:"0",children:u("None")}),(0,h.jsx)(s.l.Option,{value:"15000",children:u("15 sec")}),(0,h.jsx)(s.l.Option,{value:"60000",children:u("1 min")}),(0,h.jsx)(s.l.Option,{value:"120000",children:u("2 min")}),(0,h.jsx)(s.l.Option,{value:"300000",children:u("5 min")})]})]})}}}]); \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/49393.b6b17049.chunk.js b/ydb/core/viewer/monitoring/static/js/49393.b6b17049.chunk.js new file mode 100644 index 000000000000..268702ae9402 --- /dev/null +++ b/ydb/core/viewer/monitoring/static/js/49393.b6b17049.chunk.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[49393],{3685:(e,t,a)=>{a.d(t,{$:()=>i});var n=a(54090),l=a(77506),s=a(33775),o=a(60712);const r=(0,l.cn)("ydb-entity-page-title");function i({entityName:e,status:t=n.m.Grey,id:a,className:l}){return(0,o.jsxs)("div",{className:r(null,l),children:[(0,o.jsx)("span",{className:r("prefix"),children:e}),(0,o.jsx)(s.k,{className:r("icon"),status:t,size:"s"}),a]})}},21545:(e,t,a)=>{a.d(t,{X:()=>l});var n=a(78034);const l=a(21334).F.injectEndpoints({endpoints:e=>({getTablet:e.query({queryFn:async({id:e,database:t,followerId:a},{signal:l})=>{try{const[s,o,r]=await Promise.all([window.api.viewer.getTablet({id:e,database:t,followerId:a},{signal:l}),window.api.viewer.getTabletHistory({id:e,database:t},{signal:l}),window.api.viewer.getNodesList({signal:l})]),i=(0,n.nN)(r),d=Object.keys(o).reduce(((e,t)=>{var a;const n=null===(a=o[t])||void 0===a?void 0:a.TabletStateInfo;return null===n||void 0===n||n.forEach((a=>{var n;const{ChangeTime:l,Generation:s,State:o,Leader:r,FollowerId:d}=a,c=i&&t?null===(n=i.get(Number(t)))||void 0===n?void 0:n.Host:void 0;e.push({nodeId:t,generation:s,changeTime:l,state:o,leader:r,followerId:d,fqdn:c})})),e}),[]),{TabletStateInfo:c=[]}=s,u=void 0===a?c.find((e=>e.Leader)):c.find((e=>{var t;return(null===(t=e.FollowerId)||void 0===t?void 0:t.toString())===a})),{TabletId:h}=u||{};return{data:{id:h,data:u,history:d}}}catch(s){return{error:s}}},providesTags:(e,t,a)=>["All",{type:"Tablet",id:a.id}]}),getTabletDescribe:e.query({queryFn:async({tenantId:e},{signal:t})=>{try{const a=await window.api.viewer.getTabletDescribe(e,{signal:t}),{SchemeShard:n,PathId:l}=e;return{data:(null===a||void 0===a?void 0:a.Path)||`${n}:${l}`}}catch(a){return{error:a}}},providesTags:["All"]}),getAdvancedTableInfo:e.query({queryFn:async({id:e,hiveId:t},{signal:a})=>{try{return{data:await window.api.tablets.getTabletFromHive({id:e,hiveId:t},{signal:a})}}catch(n){return{error:n}}},providesTags:(e,t,a)=>["All",{type:"Tablet",id:a.id}]}),killTablet:e.mutation({queryFn:async({id:e})=>{try{return{data:await window.api.tablets.killTablet(e)}}catch(t){return{error:t}}},invalidatesTags:(e,t,a)=>[{type:"Tablet",id:a.id},{type:"Tablet",id:"LIST"}]}),stopTablet:e.mutation({queryFn:async({id:e,hiveId:t})=>{try{return{data:await window.api.tablets.stopTablet(e,t)}}catch(a){return{error:a}}},invalidatesTags:(e,t,a)=>[{type:"Tablet",id:a.id},{type:"Tablet",id:"LIST"}]}),resumeTablet:e.mutation({queryFn:async({id:e,hiveId:t})=>{try{return{data:await window.api.tablets.resumeTablet(e,t)}}catch(a){return{error:a}}},invalidatesTags:(e,t,a)=>[{type:"Tablet",id:a.id},{type:"Tablet",id:"LIST"}]})}),overrideExisting:"throw"})},22983:(e,t,a)=>{a.d(t,{B:()=>d});var n=a(59284),l=a(84476),s=a(84375),o=a(55974),r=a(42829),i=a(60712);function d({children:e,onConfirmAction:t,onConfirmActionSuccess:a,dialogHeader:d,dialogText:c,retryButtonText:u,buttonDisabled:h=!1,buttonView:m="action",buttonTitle:v,buttonClassName:p,withPopover:b=!1,popoverContent:g,popoverPlacement:x="right",popoverDisabled:f=!0}){const[y,w]=n.useState(!1),[j,N]=n.useState(!1),[I,T]=n.useState(!1),S=()=>(0,i.jsx)(l.$,{onClick:()=>w(!0),view:m,disabled:h,loading:!h&&j,className:p,title:v,children:e});return(0,i.jsxs)(n.Fragment,{children:[(0,i.jsx)(o.g,{visible:y,header:d,text:c,withRetry:I,retryButtonText:u,onConfirm:async e=>{N(!0),await t(e)},onConfirmActionSuccess:async()=>{T(!1);try{await(null===a||void 0===a?void 0:a())}finally{N(!1)}},onConfirmActionError:e=>{T((0,r.D)(e)),N(!1)},onClose:()=>{w(!1)}}),b?(0,i.jsx)(s.A,{content:g,placement:x,disabled:f,children:S()}):S()]})}},27775:(e,t,a)=>{a.d(t,{i:()=>o});var n=a(47665),l=a(58267),s=a(60712);function o({state:e}){return(0,s.jsx)(n.J,{theme:(0,l._)(e),children:e})}},42829:(e,t,a)=>{a.d(t,{D:()=>n});const n=e=>Boolean(e&&"object"===typeof e&&"retryPossible"in e&&e.retryPossible)},55974:(e,t,a)=>{a.d(t,{g:()=>x});var n=a(59284),l=a(18677),s=a(71153),o=a(74321),r=a(2198),i=a(99991),d=a(89954),c=a(77506),u=a(81288),h=a(48372);const m=JSON.parse('{"default-error":"Something went wrong, action cannot be completed","no-rights-error":"You don\'t have enough rights to complete the operation","button-confirm":"Confirm","button-retry":"Retry","button-cancel":"Cancel","button-close":"Close","checkbox-text":"I understand what I\'m doing"}'),v=(0,h.g4)("ydb-critical-action-dialog",{en:m});var p=a(60712);const b=(0,c.cn)("ydb-critical-dialog"),g=e=>{if((0,u.cH)(e)){if(403===e.status)return v("no-rights-error");if("string"===typeof e.data)return e.data;if((0,u._E)(e)&&e.data)return(0,p.jsx)(d.O,{hideSeverity:!0,data:e.data});if(e.statusText)return e.statusText}return v("default-error")};function x({visible:e,header:t,text:a,withRetry:d,retryButtonText:c,withCheckBox:u,onClose:h,onConfirm:m,onConfirmActionSuccess:x,onConfirmActionError:f}){const[y,w]=n.useState(!1),[j,N]=n.useState(),[I,T]=n.useState(!1),S=async e=>(w(!0),m(e).then((()=>{x(),h()})).catch((e=>{f(e),N(e)})).finally((()=>{w(!1)})));return(0,p.jsx)(r.l,{open:e,hasCloseButton:!1,className:b(),size:"s",onClose:h,onTransitionExited:()=>{N(void 0),T(!1)},children:j?(0,p.jsxs)(n.Fragment,{children:[(0,p.jsx)(r.l.Header,{caption:t}),(0,p.jsx)(r.l.Body,{className:b("body"),children:(0,p.jsxs)("div",{className:b("body-message",{error:!0}),children:[(0,p.jsx)("span",{className:b("error-icon"),children:(0,p.jsx)(l.A,{width:"24",height:"22"})}),g(j)]})}),(0,p.jsx)(r.l.Footer,{loading:!1,preset:"default",textButtonApply:d?c||v("button-retry"):void 0,textButtonCancel:v("button-close"),onClickButtonApply:()=>S(!0),onClickButtonCancel:h})]}):(0,p.jsxs)(n.Fragment,{children:[(0,p.jsx)(r.l.Header,{caption:t}),(0,p.jsxs)(r.l.Body,{className:b("body"),children:[(0,p.jsxs)("div",{className:b("body-message",{warning:!0}),children:[(0,p.jsx)("span",{className:b("warning-icon"),children:(0,p.jsx)(i.I,{data:s.A,size:24})}),a]}),u?(0,p.jsx)(o.S,{checked:I,onUpdate:T,children:v("checkbox-text")}):null]}),(0,p.jsx)(r.l.Footer,{loading:y,preset:"default",textButtonApply:v("button-confirm"),textButtonCancel:v("button-cancel"),propsButtonApply:{type:"submit",disabled:u&&!I},onClickButtonCancel:h,onClickButtonApply:()=>S()})]})})}},58267:(e,t,a)=>{a.d(t,{P:()=>o,_:()=>r});var n=a(54090),l=a(6354);const s={[l.r.Dead]:n.m.Red,[l.r.Created]:n.m.Yellow,[l.r.ResolveStateStorage]:n.m.Yellow,[l.r.Candidate]:n.m.Yellow,[l.r.BlockBlobStorage]:n.m.Yellow,[l.r.WriteZeroEntry]:n.m.Yellow,[l.r.Restored]:n.m.Yellow,[l.r.Discover]:n.m.Yellow,[l.r.Lock]:n.m.Yellow,[l.r.Stopped]:n.m.Yellow,[l.r.ResolveLeader]:n.m.Yellow,[l.r.RebuildGraph]:n.m.Yellow,[l.r.Deleted]:n.m.Green,[l.r.Active]:n.m.Green},o=e=>{if(!e)return n.m.Grey;return t=e,Object.values(n.m).includes(t)?e:s[e];var t};function r(e){if(!e)return"unknown";switch(e){case l.r.Dead:return"danger";case l.r.Active:case l.r.Deleted:return"success";default:return"warning"}}},58389:(e,t,a)=>{a.d(t,{B:()=>u});var n=a(87184),l=a(77506),s=a(90053),o=a(70043),r=a(60712);const i=(0,l.cn)("ydb-page-meta"),d="\xa0\xa0\xb7\xa0\xa0";function c({items:e,loading:t}){return(0,r.jsx)("div",{className:i("info"),children:t?(0,r.jsx)(o.E,{className:i("skeleton")}):e.filter((e=>Boolean(e))).join(d)})}function u({className:e,...t}){return(0,r.jsxs)(n.s,{gap:1,alignItems:"center",justifyContent:"space-between",className:i(null,e),children:[(0,r.jsx)(c,{...t}),(0,r.jsx)(s.E,{})]})}},70043:(e,t,a)=>{a.d(t,{E:()=>o});var n=a(89169),l=a(66781),s=a(60712);const o=({delay:e=600,className:t})=>{const[a]=(0,l.y)(e);return a?(0,s.jsx)(n.E,{className:t}):null}},79737:(e,t,a)=>{a.d(t,{A:()=>r,X:()=>i});var n=a(5874),l=a(77506),s=a(60712);const o=(0,l.cn)("ydb-table");function r({children:e,className:t}){return(0,s.jsx)("div",{className:o("table-header-content",t),children:e})}function i({className:e,width:t,wrapperClassName:a,...l}){return(0,s.jsx)("div",{className:o(null,a),children:(0,s.jsx)(n.W,{headerCellClassName:({column:e})=>{var t;const a=null===(t=e.columnDef.meta)||void 0===t?void 0:t.align;return o("table-header-cell",{align:a})},cellClassName:e=>{var t,a;const n=null===e||void 0===e||null===(t=e.column.columnDef.meta)||void 0===t?void 0:t.align,l=null===e||void 0===e||null===(a=e.column.columnDef.meta)||void 0===a?void 0:a.verticalAlign;return o("table-cell",{align:n,"vertical-align":l})},className:o("table",{width:t},e),...l})})}},81342:(e,t,a)=>{a.r(t),a.d(t,{Tablet:()=>pe});var n=a(59284),l=a(87184),s=a(23871),o=a(44992),r=a(61750),i=a(10755),d=a(67087),c=a(370),u=a(7889),h=a(3685),m=a(44508),v=a(44294),p=a(98167),b=a(58389),g=a(92459),x=a(40174),f=a(21545),y=a(54090),w=a(77506),j=a(76086),N=a(90182),I=a(12888),T=a(76938);const S=e=>n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),n.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M4.5 1.5a3 3 0 0 0-3 3v7a3 3 0 0 0 3 3h7a3 3 0 0 0 3-3v-7a3 3 0 0 0-3-3z",clipRule:"evenodd"})),_=e=>n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),n.createElement("path",{fill:"currentColor",d:"M13.756 10.164c1.665-.962 1.665-3.366 0-4.328L5.251.919C3.584-.045 1.5 1.158 1.5 3.083v9.834c0 1.925 2.084 3.128 3.751 2.164z"}));var C=a(99991),A=a(22983),k=a(6354),D=a(48372);const E=JSON.parse('{"tablet.header":"Tablet","tablet.meta-database":"Database","tablet.meta-follower":"Follower","controls.kill":"Restart","controls.stop":"Stop","controls.resume":"Resume","controls.kill-not-allowed":"You don\'t have enough rights to restart tablet","controls.stop-not-allowed":"You don\'t have enough rights to stop tablet","controls.resume-not-allowed":"You don\'t have enough rights to resume tablet","dialog.kill-header":"Restart tablet","dialog.stop-header":"Stop tablet","dialog.resume-header":"Resume tablet","dialog.kill-text":"The tablet will be restarted. Do you want to proceed?","dialog.stop-text":"The tablet will be stopped. Do you want to proceed?","dialog.resume-text":"The tablet will be resumed. Do you want to proceed?","emptyState":"The tablet was not found","label_tablet-history":"Tablets","label_tablet-channels":"Storage"}'),F=(0,D.g4)("ydb-tablet-page",{en:E});function B(e){return Boolean(e&&"0"!==e)}var R=a(60712);const O=({tablet:e})=>{const{TabletId:t,HiveId:a}=e,s=(0,I.X)(),[o]=f.X.useKillTabletMutation(),[r]=f.X.useStopTabletMutation(),[i]=f.X.useResumeTabletMutation();if(!t)return null;const d=B(a),c=e.State===k.r.Stopped,u=e.State!==k.r.Stopped&&e.State!==k.r.Dead,h=e.State===k.r.Stopped||e.State===k.r.Deleted;return(0,R.jsxs)(l.s,{gap:2,wrap:"nowrap",children:[(0,R.jsxs)(A.B,{dialogHeader:F("dialog.kill-header"),dialogText:F("dialog.kill-text"),onConfirmAction:()=>o({id:t}).unwrap(),buttonDisabled:c||!s,withPopover:!0,buttonView:"normal",popoverContent:F("controls.kill-not-allowed"),popoverPlacement:"bottom",popoverDisabled:s,children:[(0,R.jsx)(C.I,{data:T.A}),F("controls.kill")]}),d&&(0,R.jsxs)(n.Fragment,{children:[(0,R.jsxs)(A.B,{dialogHeader:F("dialog.stop-header"),dialogText:F("dialog.stop-text"),onConfirmAction:()=>r({id:t,hiveId:a}).unwrap(),buttonDisabled:h||!s,withPopover:!0,buttonView:"normal",popoverContent:F("controls.stop-not-allowed"),popoverPlacement:"bottom",popoverDisabled:s,children:[(0,R.jsx)(C.I,{data:S}),F("controls.stop")]}),(0,R.jsxs)(A.B,{dialogHeader:F("dialog.resume-header"),dialogText:F("dialog.resume-text"),onConfirmAction:()=>i({id:t,hiveId:a}).unwrap(),buttonDisabled:u||!s,withPopover:!0,buttonView:"normal",popoverContent:F("controls.resume-not-allowed"),popoverPlacement:"bottom",popoverDisabled:s,children:[(0,R.jsx)(C.I,{data:_}),F("controls.resume")]})]})]})};var P=a(52905),$=a(60073),G=a(25196),H=a(27775),L=a(41826),z=a(31684),q=a(29819);const Y=JSON.parse('{"field_scheme-shard":"SchemeShard","field_follower":"Follower","field_generation":"Generation","field_hive":"HiveId","field_state":"State","field_uptime":"Uptime","field_node":"Node","field_links":"Links","field_developer-ui-app":"App","field_developer-ui-counters":"Counters","field_developer-ui-executor":"Executor DB internals","field_developer-ui-state":"State Storage","title_info":"Info","title_links":"Links"}'),M=(0,D.g4)("ydb-tablet-info",{en:Y}),K=(0,w.cn)("ydb-tablet-info"),X=({tablet:e})=>{const t=(0,I.X)(),{ChangeTime:a,Generation:n,FollowerId:s,NodeId:o,HiveId:r,State:i,TenantId:{SchemeShard:d}={},TabletId:c}=e,u=B(r),h=i===k.r.Active,m=[];u&&m.push({label:M("field_hive"),value:(0,R.jsx)(P.N_,{to:(0,g.DM)(r),className:K("link"),children:r})}),d&&m.push({label:M("field_scheme-shard"),value:(0,R.jsx)(P.N_,{to:(0,g.DM)(d),className:K("link"),children:d})}),m.push({label:M("field_state"),value:(0,R.jsx)(H.i,{state:i})}),h&&m.push({label:M("field_uptime"),value:(0,R.jsx)(L.H,{ChangeTime:a})}),m.push({label:M("field_generation"),value:n},{label:M("field_node"),value:(0,R.jsx)(P.N_,{className:K("link"),to:(0,q.vI)(String(o)),children:o})}),s&&m.push({label:M("field_follower"),value:s});return(0,R.jsxs)(l.s,{gap:10,wrap:"nowrap",children:[(0,R.jsxs)("div",{children:[(0,R.jsx)("div",{className:K("section-title"),children:M("title_info")}),(0,R.jsx)($.z_,{info:m})]}),t&&c?(0,R.jsxs)("div",{children:[(0,R.jsx)("div",{className:K("section-title"),children:M("title_links")}),(0,R.jsxs)(l.s,{direction:"column",gap:3,children:[(0,R.jsx)(G.K,{title:M("field_developer-ui-app"),url:(0,z._t)(c,"app")}),(0,R.jsx)(G.K,{title:M("field_developer-ui-counters"),url:(0,z._t)(c,"counters")}),(0,R.jsx)(G.K,{title:M("field_developer-ui-executor"),url:(0,z._t)(c,"executorInternals")}),(0,R.jsx)(G.K,{title:M("field_developer-ui-state"),url:(0,z._t)(c,void 0,"SsId")})]})]}):null]})};var Q=a(36590),J=a(79737),V=a(84476),W=a(33705),U=a(56839);const Z=JSON.parse('{"label_channel-index":"Channel","label_storage-pool":"Storage Pool Name","label_group-id":"Group ID","label_generation":"From generation","label_timestamp":"Timestamp"}'),ee=(0,D.g4)("ydb-tablet-storage-info",{en:Z}),te=(0,w.cn)("ydb-tablet-storage-info");function ae(e,t){const a=e.getValue(),n="function"===typeof t?t(a):a;return(0,R.jsx)("div",{className:te("metrics-cell"),children:n})}function ne({row:e,name:t,hasExpand:a}){const n=e.getCanExpand();return(0,R.jsxs)(l.s,{gap:1,alignItems:"flex-start",className:te("name-wrapper"),children:[n&&(0,R.jsx)(V.$,{view:"flat",size:"xs",onClick:e.getToggleExpandedHandler(),children:(0,R.jsx)(V.$.Icon,{children:(0,R.jsx)(W.I,{direction:e.getIsExpanded()?"bottom":"right",size:14})})}),(0,R.jsx)("div",{className:te("name-content",{"no-control":a&&!n}),children:t})]})}function le({data:e}){const[t,a]=n.useState({}),l=n.useMemo((()=>function(e){var t;if(!e)return[];const{BoundChannels:a,TabletStorageInfo:n={}}=e,l=null!==(t=n.Channels)&&void 0!==t?t:[],s=[];for(const r of l){var o;const e=r.Channel,t=r.History;if(!e||!t||!t.length)continue;const n=[...t];n.reverse();const[l,...i]=n,d={...l,storagePoolName:null===a||void 0===a||null===(o=a[e])||void 0===o?void 0:o.StoragePoolName,channelIndex:e,children:i};s.push(d)}return s}(e)),[e]),s=n.useMemo((()=>l.some((e=>{var t;return null===(t=e.children)||void 0===t?void 0:t.length}))),[l]),o=n.useMemo((()=>{return e=s,[{accessorKey:"channelIndex",header:()=>(0,R.jsx)(J.A,{children:ee("label_channel-index")}),size:50,cell:ae,meta:{align:"right"}},{accessorKey:"storagePoolName",header:()=>(0,R.jsx)(J.A,{children:ee("label_storage-pool")}),size:200,cell:ae},{accessorKey:"GroupID",header:()=>(0,R.jsx)(J.A,{className:e?te("with-padding"):void 0,children:ee("label_group-id")}),size:100,cell:t=>(0,R.jsx)(ne,{row:t.row,name:t.getValue(),hasExpand:e})},{accessorKey:"FromGeneration",header:()=>(0,R.jsx)(J.A,{children:ee("label_generation")}),size:100,cell:ae,meta:{align:"right"}},{accessorKey:"Timestamp",header:()=>(0,R.jsx)(J.A,{children:ee("label_timestamp")}),size:200,cell:e=>ae(e,U.Ey),meta:{align:"right"}}];var e}),[s]),r=(0,Q.K)({columns:o,data:l,getSubRows:e=>e.children,enableExpanding:!0,onExpandedChange:a,state:{expanded:t}});return(0,R.jsx)(J.X,{table:r})}var se=a(4557),oe=a(10508),re=a(82015),ie=a(17594);const de={displayIndices:!1,highlightRows:!0},ce=({history:e,database:t,tabletId:a})=>{const l=n.useMemo((()=>(({database:e,tabletId:t})=>[{name:"Generation",align:se.Ay.RIGHT,render:({row:e})=>e.generation},{name:"Change time",align:se.Ay.RIGHT,sortable:!1,render:({row:e})=>(0,R.jsx)(L.H,{ChangeTime:e.changeTime}),width:120},{name:"State",sortable:!1,render:({row:e})=>(0,R.jsx)(H.i,{state:e.state})},{name:"Tablet",sortable:!1,render:({row:a})=>{var n;const l=(0,g.DM)(t,{database:e,followerId:a.leader||null===(n=a.followerId)||void 0===n?void 0:n.toString()}),s=`${t}${a.followerId?`.${a.followerId}`:""}`;return(0,R.jsx)(re.E,{to:l,children:s})}},{name:"Node ID",align:se.Ay.RIGHT,sortable:!1,render:({row:e})=>(0,R.jsx)(re.E,{to:(0,q.vI)(e.nodeId),children:e.nodeId})},{name:"Node FQDN",sortable:!1,width:300,render:({row:e})=>e.fqdn?(0,R.jsx)(oe.c,{name:e.fqdn,showStatus:!1,hasClipboardButton:!0}):(0,R.jsx)("span",{children:"\u2014"})}])({database:t,tabletId:a})),[t,a]);return(0,R.jsx)(ie.l,{columnsWidthLSKey:"tabletTableColumnsWidth",data:e,columns:l,settings:de,initialSortOrder:{columnId:"Generation",order:se.Ay.DESCENDING}})},ue=(0,w.cn)("ydb-tablet-page"),he={history:"history",channels:"channels"},me=[{id:he.history,get title(){return F("label_tablet-history")}},{id:he.channels,get title(){return F("label_tablet-channels")},isAdvanced:!0}],ve=c.z.nativeEnum(he).catch(he.history);function pe(){var e;const t=(0,N.YQ)(),{id:a}=(0,i.g)(),[{database:s,clusterName:c,followerId:u}]=(0,d.useQueryParams)(g.qc),[h]=(0,N.Nt)(),{currentData:v,isFetching:y,error:w}=f.X.useGetTabletQuery({id:a,database:null!==s&&void 0!==s?s:void 0,followerId:null!==u&&void 0!==u?u:void 0},{pollingInterval:h}),I=y&&void 0===v,{data:T={},history:S=[]}=v||{},{currentData:_}=f.X.useGetTabletDescribeQuery(T.TenantId?{tenantId:T.TenantId}:o.hT),C=null!==(e=_||s)&&void 0!==e?e:void 0,A=T.Type;n.useEffect((()=>{t((0,x.g)("tablet",{tenantName:null!==s&&void 0!==s?s:void 0,tabletId:a,tabletType:A}))}),[t,s,a,A]);const{Leader:k,Type:D}=T,E=[];return C&&E.push(`${F("tablet.meta-database")}: ${C}`),D&&E.push(D),!1===k&&E.push(F("tablet.meta-follower").toUpperCase()),(0,R.jsxs)(l.s,{gap:5,direction:"column",className:ue(),children:[(0,R.jsx)(r.mg,{children:(0,R.jsx)("title",{children:`${a} \u2014 ${F("tablet.header")} \u2014 ${C||c||j.QM}`})}),(0,R.jsx)(b.B,{items:E}),(0,R.jsxs)(p.r,{loading:I,size:"l",children:[w?(0,R.jsx)(m.o,{error:w}):null,v?(0,R.jsx)(be,{id:a,tablet:T,history:S,database:C}):null]})]})}function be({id:e,tablet:t,history:a,database:n}){const s=!Object.keys(t).length,{Overall:o,HiveId:r,FollowerId:i}=t,d=`${e}${i?`.${i}`:""}`;return(0,R.jsxs)(u.q,{title:F("emptyState"),className:ue("placeholder"),isEmpty:s,children:[(0,R.jsxs)(l.s,{gap:5,direction:"column",children:[(0,R.jsx)(h.$,{entityName:F("tablet.header"),status:null!==o&&void 0!==o?o:y.m.Grey,id:d}),(0,R.jsx)(O,{tablet:t}),(0,R.jsx)(X,{tablet:t})]}),(0,R.jsx)(ge,{id:e,hiveId:r,history:a,database:n})]})}function ge({id:e,hiveId:t,history:a,database:o}){var r;const[{activeTab:i,...c},u]=(0,d.useQueryParams)(g.qc),h=!(0,I.X)()||!B(t);let m=ve.parse(i);return h&&null!==(r=me.find((e=>e.id===m)))&&void 0!==r&&r.isAdvanced&&(m=he.history),n.useEffect((()=>{i!==m&&u({activeTab:m},"replaceIn")}),[i,m,u]),(0,R.jsxs)(l.s,{gap:5,direction:"column",children:[(0,R.jsx)("div",{children:(0,R.jsx)(s.t,{size:"l",items:me.filter((({isAdvanced:e})=>!e||!h)),activeTab:m,wrapTo:(t,a)=>{const n=(0,g.DM)(e,{...c,activeTab:t.id});return(0,R.jsx)(v.E,{to:n,children:a},t.id)}})}),"history"===m?(0,R.jsx)(ce,{history:a,tabletId:e,database:o}):null,"channels"!==m||h?null:(0,R.jsx)(xe,{id:e,hiveId:t})]})}function xe({id:e,hiveId:t}){const[a]=(0,N.Nt)(),{currentData:n,error:l,isFetching:s}=f.X.useGetAdvancedTableInfoQuery({id:e,hiveId:t},{pollingInterval:a}),o=s&&void 0===n;return(0,R.jsxs)(p.r,{loading:o,size:"l",children:[l?(0,R.jsx)(m.o,{error:l}):null,n?(0,R.jsx)(le,{data:n}):null]})}},89954:(e,t,a)=>{a.d(t,{O:()=>S});var n=a(59284),l=a(45720),s=a(16929),o=a(71153),r=a(18677),i=a(84476),d=a(33705),c=a(67884),u=a(99991),h=a(77506),m=a(48372);const v=JSON.parse('{"default_collapse_label":"Show less","default_expand_label":"Show more","chars_count":[" ({{count}} symbol)"," ({{count}} symbols)"," ({{count}} symbols)"," ({{count}} symbols)"]}'),p=JSON.parse('{"default_collapse_label":"\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435","default_expand_label":"\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0435\u0449\u0451","chars_count":[" ({{count}} \u0441\u0438\u043c\u0432\u043e\u043b)"," ({{count}} \u0441\u0438\u043c\u0432\u043e\u043b\u0430)"," ({{count}} \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432)"," ({{count}} \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432)"]}'),b=(0,m.g4)("ydb-shorty-string",{ru:p,en:v});var g=a(60712);const x=(0,h.cn)("kv-shorty-string");function f({value:e="",limit:t=200,strict:a=!1,displayLength:l=!0,render:s=e=>e,onToggle:o,expandLabel:r=b("default_expand_label"),collapseLabel:i=b("default_collapse_label")}){const[d,u]=n.useState(!1),h=(d?i:r)+(l&&!d?b("chars_count",{count:e.length}):""),m=e.length>t+(a?0:h.length),v=d||!m?e:e.slice(0,t-4)+"\xa0...";return(0,g.jsxs)("div",{className:x(),children:[s(v),m?(0,g.jsx)(c.N,{className:x("toggle"),href:"#",onClick:e=>{e.stopPropagation(),e.preventDefault(),u((e=>!e)),null===o||void 0===o||o()},children:h}):null]})}var y=a(41650);const w=["S_FATAL","S_ERROR","S_WARNING","S_INFO"];function j(e){return function(e){return!!e&&void 0!==w[e]}(e)?w[e]:"S_INFO"}const N=(0,h.cn)("kv-result-issues"),I=(0,h.cn)("kv-issues"),T=(0,h.cn)("kv-issue");function S({data:e,hideSeverity:t}){const[a,l]=n.useState(!1),s="string"===typeof e||null===e||void 0===e?void 0:e.issues,o=Array.isArray(s)&&s.length>0;return(0,g.jsxs)("div",{className:N(),children:[(0,g.jsxs)("div",{className:N("error-message"),children:[(()=>{let a;if("string"===typeof e)a=e;else{var l,s;const o=j(null===e||void 0===e||null===(l=e.error)||void 0===l?void 0:l.severity);a=(0,g.jsxs)(n.Fragment,{children:[t?null:(0,g.jsxs)(n.Fragment,{children:[(0,g.jsx)(F,{severity:o})," "]}),(0,g.jsx)("span",{className:N("error-message-text"),children:null===e||void 0===e||null===(s=e.error)||void 0===s?void 0:s.message})]})}return a})(),o&&(0,g.jsx)(i.$,{view:"normal",onClick:()=>l(!a),children:a?"Hide details":"Show details"})]}),o&&a&&(0,g.jsx)(_,{hideSeverity:t,issues:s})]})}function _({issues:e,hideSeverity:t}){const a=null===e||void 0===e?void 0:e.reduce(((e,t)=>{var a;const n=null!==(a=t.severity)&&void 0!==a?a:10;return Math.min(e,n)}),10);return(0,g.jsx)("div",{className:I(null),children:null===e||void 0===e?void 0:e.map(((e,n)=>(0,g.jsx)(C,{hideSeverity:t,issue:e,expanded:e===a},n)))})}function C({issue:e,hideSeverity:t,level:a=0}){const[l,s]=n.useState(!0),o=j(e.severity),r=e.issues,c=Array.isArray(r)&&r.length>0,u=l?"bottom":"right";return(0,g.jsxs)("div",{className:T({leaf:!c,"has-issues":c}),children:[(0,g.jsxs)("div",{className:T("line"),children:[c&&(0,g.jsx)(i.$,{view:"flat-secondary",onClick:()=>s(!l),className:T("arrow-toggle"),children:(0,g.jsx)(d.I,{direction:u,size:16})}),t?null:(0,g.jsx)(F,{severity:o}),(0,g.jsx)(A,{issue:e}),e.issue_code?(0,g.jsxs)("span",{className:T("code"),children:["Code: ",e.issue_code]}):null]}),c&&l&&(0,g.jsx)("div",{className:T("issues"),children:(0,g.jsx)(k,{issues:r,level:a+1,expanded:l})})]})}function A({issue:e}){var t;const a=function(e){const{position:t}=e;if("object"!==typeof t||null===t||!(0,y.kf)(t.row))return"";const{row:a,column:n}=t;return(0,y.kf)(n)?`${a}:${n}`:`line ${a}`}(e),n=window.ydbEditor,l=()=>(0,g.jsxs)("span",{className:T("message"),children:[a&&(0,g.jsx)("span",{className:T("place-text"),title:"Position",children:a}),(0,g.jsx)("div",{className:T("message-text"),children:(0,g.jsx)(f,{value:e.message,expandLabel:"Show full message"})})]}),{row:s,column:o}=null!==(t=e.position)&&void 0!==t?t:{};if(!((0,y.kf)(s)&&n))return l();return(0,g.jsx)(c.N,{href:"#",extraProps:{draggable:!1},onClick:()=>{const e={lineNumber:s,column:null!==o&&void 0!==o?o:0};n.setPosition(e),n.revealPositionInCenterIfOutsideViewport(e),n.focus()},view:"primary",children:l()})}function k(e){const{issues:t,level:a,expanded:n}=e;return(0,g.jsx)("div",{className:T("list"),children:t.map(((e,t)=>(0,g.jsx)(C,{issue:e,level:a,expanded:n},t)))})}const D={S_INFO:l.A,S_WARNING:s.A,S_ERROR:o.A,S_FATAL:r.A},E=(0,h.cn)("yql-issue-severity");function F({severity:e}){const t=e.slice(2).toLowerCase();return(0,g.jsxs)("span",{className:E({severity:t}),children:[(0,g.jsx)(u.I,{className:E("icon"),data:D[e]}),(0,g.jsx)("span",{className:E("title"),children:t})]})}},90053:(e,t,a)=>{a.d(t,{E:()=>v});var n=a(8873),l=a(84476),s=a(24555),o=a(21334),r=a(77506),i=a(90182),d=a(48372);const c=JSON.parse('{"None":"None","15 sec":"15 sec","1 min":"1 min","2 min":"2 min","5 min":"5 min","Refresh":"Refresh"}'),u=(0,d.g4)("ydb-diagnostics-autorefresh-control",{en:c});var h=a(60712);const m=(0,r.cn)("auto-refresh-control");function v({className:e,onManualRefresh:t}){const a=(0,i.YQ)(),[r,d]=(0,i.Nt)();return(0,h.jsxs)("div",{className:m(null,e),children:[(0,h.jsx)(l.$,{view:"flat-secondary",onClick:()=>{a(o.F.util.invalidateTags(["All"])),null===t||void 0===t||t()},extraProps:{"aria-label":u("Refresh")},children:(0,h.jsx)(l.$.Icon,{children:(0,h.jsx)(n.A,{})})}),(0,h.jsxs)(s.l,{value:[String(r)],onUpdate:e=>{d(Number(e))},width:85,qa:"ydb-autorefresh-select",children:[(0,h.jsx)(s.l.Option,{value:"0",children:u("None")}),(0,h.jsx)(s.l.Option,{value:"15000",children:u("15 sec")}),(0,h.jsx)(s.l.Option,{value:"60000",children:u("1 min")}),(0,h.jsx)(s.l.Option,{value:"120000",children:u("2 min")}),(0,h.jsx)(s.l.Option,{value:"300000",children:u("5 min")})]})]})}}}]); \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/56013.d9e34466.chunk.js b/ydb/core/viewer/monitoring/static/js/56013.d9e34466.chunk.js deleted file mode 100644 index 14a9875e0f22..000000000000 --- a/ydb/core/viewer/monitoring/static/js/56013.d9e34466.chunk.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 56013.d9e34466.chunk.js.LICENSE.txt */ -(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[56013],{13847:function(n,t,r){var e;n=r.nmd(n),function(){var u,i="Expected a function",o="__lodash_hash_undefined__",f="__lodash_placeholder__",a=16,c=32,l=64,s=128,h=256,p=1/0,v=9007199254740991,_=NaN,g=4294967295,y=[["ary",s],["bind",1],["bindKey",2],["curry",8],["curryRight",a],["flip",512],["partial",c],["partialRight",l],["rearg",h]],d="[object Arguments]",b="[object Array]",w="[object Boolean]",m="[object Date]",x="[object Error]",j="[object Function]",A="[object GeneratorFunction]",k="[object Map]",O="[object Number]",E="[object Object]",I="[object Promise]",R="[object RegExp]",z="[object Set]",S="[object String]",C="[object Symbol]",L="[object WeakMap]",W="[object ArrayBuffer]",B="[object DataView]",T="[object Float32Array]",U="[object Float64Array]",$="[object Int8Array]",D="[object Int16Array]",M="[object Int32Array]",N="[object Uint8Array]",F="[object Uint8ClampedArray]",q="[object Uint16Array]",P="[object Uint32Array]",Z=/\b__p \+= '';/g,V=/\b(__p \+=) '' \+/g,K=/(__e\(.*?\)|\b__t\)) \+\n'';/g,G=/&(?:amp|lt|gt|quot|#39);/g,H=/[&<>"']/g,J=RegExp(G.source),Y=RegExp(H.source),Q=/<%-([\s\S]+?)%>/g,X=/<%([\s\S]+?)%>/g,nn=/<%=([\s\S]+?)%>/g,tn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,rn=/^\w*$/,en=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,un=/[\\^$.*+?()[\]{}|]/g,on=RegExp(un.source),fn=/^\s+/,an=/\s/,cn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,ln=/\{\n\/\* \[wrapped with (.+)\] \*/,sn=/,? & /,hn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,pn=/[()=,{}\[\]\/\s]/,vn=/\\(\\)?/g,_n=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,gn=/\w*$/,yn=/^[-+]0x[0-9a-f]+$/i,dn=/^0b[01]+$/i,bn=/^\[object .+?Constructor\]$/,wn=/^0o[0-7]+$/i,mn=/^(?:0|[1-9]\d*)$/,xn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,jn=/($^)/,An=/['\n\r\u2028\u2029\\]/g,kn="\\ud800-\\udfff",On="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",En="\\u2700-\\u27bf",In="a-z\\xdf-\\xf6\\xf8-\\xff",Rn="A-Z\\xc0-\\xd6\\xd8-\\xde",zn="\\ufe0e\\ufe0f",Sn="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Cn="['\u2019]",Ln="["+kn+"]",Wn="["+Sn+"]",Bn="["+On+"]",Tn="\\d+",Un="["+En+"]",$n="["+In+"]",Dn="[^"+kn+Sn+Tn+En+In+Rn+"]",Mn="\\ud83c[\\udffb-\\udfff]",Nn="[^"+kn+"]",Fn="(?:\\ud83c[\\udde6-\\uddff]){2}",qn="[\\ud800-\\udbff][\\udc00-\\udfff]",Pn="["+Rn+"]",Zn="\\u200d",Vn="(?:"+$n+"|"+Dn+")",Kn="(?:"+Pn+"|"+Dn+")",Gn="(?:['\u2019](?:d|ll|m|re|s|t|ve))?",Hn="(?:['\u2019](?:D|LL|M|RE|S|T|VE))?",Jn="(?:"+Bn+"|"+Mn+")"+"?",Yn="["+zn+"]?",Qn=Yn+Jn+("(?:"+Zn+"(?:"+[Nn,Fn,qn].join("|")+")"+Yn+Jn+")*"),Xn="(?:"+[Un,Fn,qn].join("|")+")"+Qn,nt="(?:"+[Nn+Bn+"?",Bn,Fn,qn,Ln].join("|")+")",tt=RegExp(Cn,"g"),rt=RegExp(Bn,"g"),et=RegExp(Mn+"(?="+Mn+")|"+nt+Qn,"g"),ut=RegExp([Pn+"?"+$n+"+"+Gn+"(?="+[Wn,Pn,"$"].join("|")+")",Kn+"+"+Hn+"(?="+[Wn,Pn+Vn,"$"].join("|")+")",Pn+"?"+Vn+"+"+Gn,Pn+"+"+Hn,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Tn,Xn].join("|"),"g"),it=RegExp("["+Zn+kn+On+zn+"]"),ot=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,ft=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],at=-1,ct={};ct[T]=ct[U]=ct[$]=ct[D]=ct[M]=ct[N]=ct[F]=ct[q]=ct[P]=!0,ct[d]=ct[b]=ct[W]=ct[w]=ct[B]=ct[m]=ct[x]=ct[j]=ct[k]=ct[O]=ct[E]=ct[R]=ct[z]=ct[S]=ct[L]=!1;var lt={};lt[d]=lt[b]=lt[W]=lt[B]=lt[w]=lt[m]=lt[T]=lt[U]=lt[$]=lt[D]=lt[M]=lt[k]=lt[O]=lt[E]=lt[R]=lt[z]=lt[S]=lt[C]=lt[N]=lt[F]=lt[q]=lt[P]=!0,lt[x]=lt[j]=lt[L]=!1;var st={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},ht=parseFloat,pt=parseInt,vt="object"==typeof r.g&&r.g&&r.g.Object===Object&&r.g,_t="object"==typeof self&&self&&self.Object===Object&&self,gt=vt||_t||Function("return this")(),yt=t&&!t.nodeType&&t,dt=yt&&n&&!n.nodeType&&n,bt=dt&&dt.exports===yt,wt=bt&&vt.process,mt=function(){try{var n=dt&&dt.require&&dt.require("util").types;return n||wt&&wt.binding&&wt.binding("util")}catch(t){}}(),xt=mt&&mt.isArrayBuffer,jt=mt&&mt.isDate,At=mt&&mt.isMap,kt=mt&&mt.isRegExp,Ot=mt&&mt.isSet,Et=mt&&mt.isTypedArray;function It(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function Rt(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u-1}function Bt(n,t,r){for(var e=-1,u=null==n?0:n.length;++e-1;);return r}function ur(n,t){for(var r=n.length;r--&&Pt(t,n[r],0)>-1;);return r}var ir=Ht({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),or=Ht({"&":"&","<":"<",">":">",'"':""","'":"'"});function fr(n){return"\\"+st[n]}function ar(n){return it.test(n)}function cr(n){var t=-1,r=Array(n.size);return n.forEach((function(n,e){r[++t]=[e,n]})),r}function lr(n,t){return function(r){return n(t(r))}}function sr(n,t){for(var r=-1,e=n.length,u=0,i=[];++r",""":'"',"'":"'"});var dr=function n(t){var r=(t=null==t?gt:dr.defaults(gt.Object(),t,dr.pick(gt,ft))).Array,e=t.Date,an=t.Error,kn=t.Function,On=t.Math,En=t.Object,In=t.RegExp,Rn=t.String,zn=t.TypeError,Sn=r.prototype,Cn=kn.prototype,Ln=En.prototype,Wn=t["__core-js_shared__"],Bn=Cn.toString,Tn=Ln.hasOwnProperty,Un=0,$n=function(){var n=/[^.]+$/.exec(Wn&&Wn.keys&&Wn.keys.IE_PROTO||"");return n?"Symbol(src)_1."+n:""}(),Dn=Ln.toString,Mn=Bn.call(En),Nn=gt._,Fn=In("^"+Bn.call(Tn).replace(un,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),qn=bt?t.Buffer:u,Pn=t.Symbol,Zn=t.Uint8Array,Vn=qn?qn.allocUnsafe:u,Kn=lr(En.getPrototypeOf,En),Gn=En.create,Hn=Ln.propertyIsEnumerable,Jn=Sn.splice,Yn=Pn?Pn.isConcatSpreadable:u,Qn=Pn?Pn.iterator:u,Xn=Pn?Pn.toStringTag:u,nt=function(){try{var n=si(En,"defineProperty");return n({},"",{}),n}catch(t){}}(),et=t.clearTimeout!==gt.clearTimeout&&t.clearTimeout,it=e&&e.now!==gt.Date.now&&e.now,st=t.setTimeout!==gt.setTimeout&&t.setTimeout,vt=On.ceil,_t=On.floor,yt=En.getOwnPropertySymbols,dt=qn?qn.isBuffer:u,wt=t.isFinite,mt=Sn.join,Nt=lr(En.keys,En),Ht=On.max,br=On.min,wr=e.now,mr=t.parseInt,xr=On.random,jr=Sn.reverse,Ar=si(t,"DataView"),kr=si(t,"Map"),Or=si(t,"Promise"),Er=si(t,"Set"),Ir=si(t,"WeakMap"),Rr=si(En,"create"),zr=Ir&&new Ir,Sr={},Cr=Ui(Ar),Lr=Ui(kr),Wr=Ui(Or),Br=Ui(Er),Tr=Ui(Ir),Ur=Pn?Pn.prototype:u,$r=Ur?Ur.valueOf:u,Dr=Ur?Ur.toString:u;function Mr(n){if(tf(n)&&!Po(n)&&!(n instanceof Pr)){if(n instanceof qr)return n;if(Tn.call(n,"__wrapped__"))return $i(n)}return new qr(n)}var Nr=function(){function n(){}return function(t){if(!nf(t))return{};if(Gn)return Gn(t);n.prototype=t;var r=new n;return n.prototype=u,r}}();function Fr(){}function qr(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=u}function Pr(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=g,this.__views__=[]}function Zr(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function ae(n,t,r,e,i,o){var f,a=1&t,c=2&t,l=4&t;if(r&&(f=i?r(n,e,i,o):r(n)),f!==u)return f;if(!nf(n))return n;var s=Po(n);if(s){if(f=function(n){var t=n.length,r=new n.constructor(t);t&&"string"==typeof n[0]&&Tn.call(n,"index")&&(r.index=n.index,r.input=n.input);return r}(n),!a)return Ru(n,f)}else{var h=vi(n),p=h==j||h==A;if(Go(n))return ju(n,a);if(h==E||h==d||p&&!i){if(f=c||p?{}:gi(n),!a)return c?function(n,t){return zu(n,pi(n),t)}(n,function(n,t){return n&&zu(t,Lf(t),n)}(f,n)):function(n,t){return zu(n,hi(n),t)}(n,ue(f,n))}else{if(!lt[h])return i?n:{};f=function(n,t,r){var e=n.constructor;switch(t){case W:return Au(n);case w:case m:return new e(+n);case B:return function(n,t){var r=t?Au(n.buffer):n.buffer;return new n.constructor(r,n.byteOffset,n.byteLength)}(n,r);case T:case U:case $:case D:case M:case N:case F:case q:case P:return ku(n,r);case k:return new e;case O:case S:return new e(n);case R:return function(n){var t=new n.constructor(n.source,gn.exec(n));return t.lastIndex=n.lastIndex,t}(n);case z:return new e;case C:return u=n,$r?En($r.call(u)):{}}var u}(n,h,a)}}o||(o=new Hr);var v=o.get(n);if(v)return v;o.set(n,f),ff(n)?n.forEach((function(e){f.add(ae(e,t,r,e,n,o))})):rf(n)&&n.forEach((function(e,u){f.set(u,ae(e,t,r,u,n,o))}));var _=s?u:(l?c?ui:ei:c?Lf:Cf)(n);return zt(_||n,(function(e,u){_&&(e=n[u=e]),te(f,u,ae(e,t,r,u,n,o))})),f}function ce(n,t,r){var e=r.length;if(null==n)return!e;for(n=En(n);e--;){var i=r[e],o=t[i],f=n[i];if(f===u&&!(i in n)||!o(f))return!1}return!0}function le(n,t,r){if("function"!=typeof n)throw new zn(i);return zi((function(){n.apply(u,r)}),t)}function se(n,t,r,e){var u=-1,i=Wt,o=!0,f=n.length,a=[],c=t.length;if(!f)return a;r&&(t=Tt(t,nr(r))),e?(i=Bt,o=!1):t.length>=200&&(i=rr,o=!1,t=new Gr(t));n:for(;++u-1},Vr.prototype.set=function(n,t){var r=this.__data__,e=re(r,n);return e<0?(++this.size,r.push([n,t])):r[e][1]=t,this},Kr.prototype.clear=function(){this.size=0,this.__data__={hash:new Zr,map:new(kr||Vr),string:new Zr}},Kr.prototype.delete=function(n){var t=ci(this,n).delete(n);return this.size-=t?1:0,t},Kr.prototype.get=function(n){return ci(this,n).get(n)},Kr.prototype.has=function(n){return ci(this,n).has(n)},Kr.prototype.set=function(n,t){var r=ci(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},Gr.prototype.add=Gr.prototype.push=function(n){return this.__data__.set(n,o),this},Gr.prototype.has=function(n){return this.__data__.has(n)},Hr.prototype.clear=function(){this.__data__=new Vr,this.size=0},Hr.prototype.delete=function(n){var t=this.__data__,r=t.delete(n);return this.size=t.size,r},Hr.prototype.get=function(n){return this.__data__.get(n)},Hr.prototype.has=function(n){return this.__data__.has(n)},Hr.prototype.set=function(n,t){var r=this.__data__;if(r instanceof Vr){var e=r.__data__;if(!kr||e.length<199)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new Kr(e)}return r.set(n,t),this.size=r.size,this};var he=Lu(we),pe=Lu(me,!0);function ve(n,t){var r=!0;return he(n,(function(n,e,u){return r=!!t(n,e,u)})),r}function _e(n,t,r){for(var e=-1,i=n.length;++e0&&r(f)?t>1?ye(f,t-1,r,e,u):Ut(u,f):e||(u[u.length]=f)}return u}var de=Wu(),be=Wu(!0);function we(n,t){return n&&de(n,t,Cf)}function me(n,t){return n&&be(n,t,Cf)}function xe(n,t){return Lt(t,(function(t){return Yo(n[t])}))}function je(n,t){for(var r=0,e=(t=bu(t,n)).length;null!=n&&rt}function Ee(n,t){return null!=n&&Tn.call(n,t)}function Ie(n,t){return null!=n&&t in En(n)}function Re(n,t,e){for(var i=e?Bt:Wt,o=n[0].length,f=n.length,a=f,c=r(f),l=1/0,s=[];a--;){var h=n[a];a&&t&&(h=Tt(h,nr(t))),l=br(h.length,l),c[a]=!e&&(t||o>=120&&h.length>=120)?new Gr(a&&h):u}h=n[0];var p=-1,v=c[0];n:for(;++p=f?a:a*("desc"==r[e]?-1:1)}return n.index-t.index}(n,t,r)}))}function Ze(n,t,r){for(var e=-1,u=t.length,i={};++e-1;)f!==n&&Jn.call(f,a,1),Jn.call(n,a,1);return n}function Ke(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];if(r==e||u!==i){var i=u;di(u)?Jn.call(n,u,1):su(n,u)}}return n}function Ge(n,t){return n+_t(xr()*(t-n+1))}function He(n,t){var r="";if(!n||t<1||t>v)return r;do{t%2&&(r+=n),(t=_t(t/2))&&(n+=n)}while(t);return r}function Je(n,t){return Si(Oi(n,t,ua),n+"")}function Ye(n){return Yr(Nf(n))}function Qe(n,t){var r=Nf(n);return Wi(r,fe(t,0,r.length))}function Xe(n,t,r,e){if(!nf(n))return n;for(var i=-1,o=(t=bu(t,n)).length,f=o-1,a=n;null!=a&&++ii?0:i+t),(e=e>i?i:e)<0&&(e+=i),i=t>e?0:e-t>>>0,t>>>=0;for(var o=r(i);++u>>1,o=n[i];null!==o&&!cf(o)&&(r?o<=t:o=200){var c=t?null:Hu(n);if(c)return hr(c);o=!1,u=rr,a=new Gr}else a=t?[]:f;n:for(;++e=e?n:eu(n,t,r)}var xu=et||function(n){return gt.clearTimeout(n)};function ju(n,t){if(t)return n.slice();var r=n.length,e=Vn?Vn(r):new n.constructor(r);return n.copy(e),e}function Au(n){var t=new n.constructor(n.byteLength);return new Zn(t).set(new Zn(n)),t}function ku(n,t){var r=t?Au(n.buffer):n.buffer;return new n.constructor(r,n.byteOffset,n.length)}function Ou(n,t){if(n!==t){var r=n!==u,e=null===n,i=n===n,o=cf(n),f=t!==u,a=null===t,c=t===t,l=cf(t);if(!a&&!l&&!o&&n>t||o&&f&&c&&!a&&!l||e&&f&&c||!r&&c||!i)return 1;if(!e&&!o&&!l&&n1?r[i-1]:u,f=i>2?r[2]:u;for(o=n.length>3&&"function"==typeof o?(i--,o):u,f&&bi(r[0],r[1],f)&&(o=i<3?u:o,i=1),t=En(t);++e-1?i[o?t[f]:f]:u}}function Du(n){return ri((function(t){var r=t.length,e=r,o=qr.prototype.thru;for(n&&t.reverse();e--;){var f=t[e];if("function"!=typeof f)throw new zn(i);if(o&&!a&&"wrapper"==oi(f))var a=new qr([],!0)}for(e=a?e:r;++e1&&w.reverse(),p&&la))return!1;var l=o.get(n),s=o.get(t);if(l&&s)return l==t&&s==n;var h=-1,p=!0,v=2&r?new Gr:u;for(o.set(n,t),o.set(t,n);++h-1&&n%1==0&&n1?"& ":"")+t[e],t=t.join(r>2?", ":" "),n.replace(cn,"{\n/* [wrapped with "+t+"] */\n")}(e,function(n,t){return zt(y,(function(r){var e="_."+r[0];t&r[1]&&!Wt(n,e)&&n.push(e)})),n.sort()}(function(n){var t=n.match(ln);return t?t[1].split(sn):[]}(e),r)))}function Li(n){var t=0,r=0;return function(){var e=wr(),i=16-(e-r);if(r=e,i>0){if(++t>=800)return arguments[0]}else t=0;return n.apply(u,arguments)}}function Wi(n,t){var r=-1,e=n.length,i=e-1;for(t=t===u?e:t;++r1?n[t-1]:u;return r="function"==typeof r?(n.pop(),r):u,uo(n,r)}));function so(n){var t=Mr(n);return t.__chain__=!0,t}function ho(n,t){return t(n)}var po=ri((function(n){var t=n.length,r=t?n[0]:0,e=this.__wrapped__,i=function(t){return oe(t,n)};return!(t>1||this.__actions__.length)&&e instanceof Pr&&di(r)?((e=e.slice(r,+r+(t?1:0))).__actions__.push({func:ho,args:[i],thisArg:u}),new qr(e,this.__chain__).thru((function(n){return t&&!n.length&&n.push(u),n}))):this.thru(i)}));var vo=Su((function(n,t,r){Tn.call(n,r)?++n[r]:ie(n,r,1)}));var _o=$u(Fi),go=$u(qi);function yo(n,t){return(Po(n)?zt:he)(n,ai(t,3))}function bo(n,t){return(Po(n)?St:pe)(n,ai(t,3))}var wo=Su((function(n,t,r){Tn.call(n,r)?n[r].push(t):ie(n,r,[t])}));var mo=Je((function(n,t,e){var u=-1,i="function"==typeof t,o=Vo(n)?r(n.length):[];return he(n,(function(n){o[++u]=i?It(t,n,e):ze(n,t,e)})),o})),xo=Su((function(n,t,r){ie(n,r,t)}));function jo(n,t){return(Po(n)?Tt:De)(n,ai(t,3))}var Ao=Su((function(n,t,r){n[r?0:1].push(t)}),(function(){return[[],[]]}));var ko=Je((function(n,t){if(null==n)return[];var r=t.length;return r>1&&bi(n,t[0],t[1])?t=[]:r>2&&bi(t[0],t[1],t[2])&&(t=[t[0]]),Pe(n,ye(t,1),[])})),Oo=it||function(){return gt.Date.now()};function Eo(n,t,r){return t=r?u:t,t=n&&null==t?n.length:t,Yu(n,s,u,u,u,u,t)}function Io(n,t){var r;if("function"!=typeof t)throw new zn(i);return n=_f(n),function(){return--n>0&&(r=t.apply(this,arguments)),n<=1&&(t=u),r}}var Ro=Je((function(n,t,r){var e=1;if(r.length){var u=sr(r,fi(Ro));e|=c}return Yu(n,e,t,r,u)})),zo=Je((function(n,t,r){var e=3;if(r.length){var u=sr(r,fi(zo));e|=c}return Yu(t,e,n,r,u)}));function So(n,t,r){var e,o,f,a,c,l,s=0,h=!1,p=!1,v=!0;if("function"!=typeof n)throw new zn(i);function _(t){var r=e,i=o;return e=o=u,s=t,a=n.apply(i,r)}function g(n){var r=n-l;return l===u||r>=t||r<0||p&&n-s>=f}function y(){var n=Oo();if(g(n))return d(n);c=zi(y,function(n){var r=t-(n-l);return p?br(r,f-(n-s)):r}(n))}function d(n){return c=u,v&&e?_(n):(e=o=u,a)}function b(){var n=Oo(),r=g(n);if(e=arguments,o=this,l=n,r){if(c===u)return function(n){return s=n,c=zi(y,t),h?_(n):a}(l);if(p)return xu(c),c=zi(y,t),_(l)}return c===u&&(c=zi(y,t)),a}return t=yf(t)||0,nf(r)&&(h=!!r.leading,f=(p="maxWait"in r)?Ht(yf(r.maxWait)||0,t):f,v="trailing"in r?!!r.trailing:v),b.cancel=function(){c!==u&&xu(c),s=0,e=l=o=c=u},b.flush=function(){return c===u?a:d(Oo())},b}var Co=Je((function(n,t){return le(n,1,t)})),Lo=Je((function(n,t,r){return le(n,yf(t)||0,r)}));function Wo(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new zn(i);var r=function(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;if(i.has(u))return i.get(u);var o=n.apply(this,e);return r.cache=i.set(u,o)||i,o};return r.cache=new(Wo.Cache||Kr),r}function Bo(n){if("function"!=typeof n)throw new zn(i);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}Wo.Cache=Kr;var To=wu((function(n,t){var r=(t=1==t.length&&Po(t[0])?Tt(t[0],nr(ai())):Tt(ye(t,1),nr(ai()))).length;return Je((function(e){for(var u=-1,i=br(e.length,r);++u=t})),qo=Se(function(){return arguments}())?Se:function(n){return tf(n)&&Tn.call(n,"callee")&&!Hn.call(n,"callee")},Po=r.isArray,Zo=xt?nr(xt):function(n){return tf(n)&&ke(n)==W};function Vo(n){return null!=n&&Xo(n.length)&&!Yo(n)}function Ko(n){return tf(n)&&Vo(n)}var Go=dt||ya,Ho=jt?nr(jt):function(n){return tf(n)&&ke(n)==m};function Jo(n){if(!tf(n))return!1;var t=ke(n);return t==x||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!uf(n)}function Yo(n){if(!nf(n))return!1;var t=ke(n);return t==j||t==A||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Qo(n){return"number"==typeof n&&n==_f(n)}function Xo(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=v}function nf(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function tf(n){return null!=n&&"object"==typeof n}var rf=At?nr(At):function(n){return tf(n)&&vi(n)==k};function ef(n){return"number"==typeof n||tf(n)&&ke(n)==O}function uf(n){if(!tf(n)||ke(n)!=E)return!1;var t=Kn(n);if(null===t)return!0;var r=Tn.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&Bn.call(r)==Mn}var of=kt?nr(kt):function(n){return tf(n)&&ke(n)==R};var ff=Ot?nr(Ot):function(n){return tf(n)&&vi(n)==z};function af(n){return"string"==typeof n||!Po(n)&&tf(n)&&ke(n)==S}function cf(n){return"symbol"==typeof n||tf(n)&&ke(n)==C}var lf=Et?nr(Et):function(n){return tf(n)&&Xo(n.length)&&!!ct[ke(n)]};var sf=Vu($e),hf=Vu((function(n,t){return n<=t}));function pf(n){if(!n)return[];if(Vo(n))return af(n)?_r(n):Ru(n);if(Qn&&n[Qn])return function(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}(n[Qn]());var t=vi(n);return(t==k?cr:t==z?hr:Nf)(n)}function vf(n){return n?(n=yf(n))===p||n===-1/0?17976931348623157e292*(n<0?-1:1):n===n?n:0:0===n?n:0}function _f(n){var t=vf(n),r=t%1;return t===t?r?t-r:t:0}function gf(n){return n?fe(_f(n),0,g):0}function yf(n){if("number"==typeof n)return n;if(cf(n))return _;if(nf(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=nf(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=Xt(n);var r=dn.test(n);return r||wn.test(n)?pt(n.slice(2),r?2:8):yn.test(n)?_:+n}function df(n){return zu(n,Lf(n))}function bf(n){return null==n?"":cu(n)}var wf=Cu((function(n,t){if(ji(t)||Vo(t))zu(t,Cf(t),n);else for(var r in t)Tn.call(t,r)&&te(n,r,t[r])})),mf=Cu((function(n,t){zu(t,Lf(t),n)})),xf=Cu((function(n,t,r,e){zu(t,Lf(t),n,e)})),jf=Cu((function(n,t,r,e){zu(t,Cf(t),n,e)})),Af=ri(oe);var kf=Je((function(n,t){n=En(n);var r=-1,e=t.length,i=e>2?t[2]:u;for(i&&bi(t[0],t[1],i)&&(e=1);++r1),t})),zu(n,ui(n),r),e&&(r=ae(r,7,ni));for(var u=t.length;u--;)su(r,t[u]);return r}));var Uf=ri((function(n,t){return null==n?{}:function(n,t){return Ze(n,t,(function(t,r){return If(n,r)}))}(n,t)}));function $f(n,t){if(null==n)return{};var r=Tt(ui(n),(function(n){return[n]}));return t=ai(t),Ze(n,r,(function(n,r){return t(n,r[0])}))}var Df=Ju(Cf),Mf=Ju(Lf);function Nf(n){return null==n?[]:tr(n,Cf(n))}var Ff=Tu((function(n,t,r){return t=t.toLowerCase(),n+(r?qf(t):t)}));function qf(n){return Yf(bf(n).toLowerCase())}function Pf(n){return(n=bf(n))&&n.replace(xn,ir).replace(rt,"")}var Zf=Tu((function(n,t,r){return n+(r?"-":"")+t.toLowerCase()})),Vf=Tu((function(n,t,r){return n+(r?" ":"")+t.toLowerCase()})),Kf=Bu("toLowerCase");var Gf=Tu((function(n,t,r){return n+(r?"_":"")+t.toLowerCase()}));var Hf=Tu((function(n,t,r){return n+(r?" ":"")+Yf(t)}));var Jf=Tu((function(n,t,r){return n+(r?" ":"")+t.toUpperCase()})),Yf=Bu("toUpperCase");function Qf(n,t,r){return n=bf(n),(t=r?u:t)===u?function(n){return ot.test(n)}(n)?function(n){return n.match(ut)||[]}(n):function(n){return n.match(hn)||[]}(n):n.match(t)||[]}var Xf=Je((function(n,t){try{return It(n,u,t)}catch(r){return Jo(r)?r:new an(r)}})),na=ri((function(n,t){return zt(t,(function(t){t=Ti(t),ie(n,t,Ro(n[t],n))})),n}));function ta(n){return function(){return n}}var ra=Du(),ea=Du(!0);function ua(n){return n}function ia(n){return Be("function"==typeof n?n:ae(n,1))}var oa=Je((function(n,t){return function(r){return ze(r,n,t)}})),fa=Je((function(n,t){return function(r){return ze(n,r,t)}}));function aa(n,t,r){var e=Cf(t),u=xe(t,e);null!=r||nf(t)&&(u.length||!e.length)||(r=t,t=n,n=this,u=xe(t,Cf(t)));var i=!(nf(r)&&"chain"in r)||!!r.chain,o=Yo(n);return zt(u,(function(r){var e=t[r];n[r]=e,o&&(n.prototype[r]=function(){var t=this.__chain__;if(i||t){var r=n(this.__wrapped__);return(r.__actions__=Ru(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,Ut([this.value()],arguments))})})),n}function ca(){}var la=qu(Tt),sa=qu(Ct),ha=qu(Mt);function pa(n){return wi(n)?Gt(Ti(n)):function(n){return function(t){return je(t,n)}}(n)}var va=Zu(),_a=Zu(!0);function ga(){return[]}function ya(){return!1}var da=Fu((function(n,t){return n+t}),0),ba=Gu("ceil"),wa=Fu((function(n,t){return n/t}),1),ma=Gu("floor");var xa=Fu((function(n,t){return n*t}),1),ja=Gu("round"),Aa=Fu((function(n,t){return n-t}),0);return Mr.after=function(n,t){if("function"!=typeof t)throw new zn(i);return n=_f(n),function(){if(--n<1)return t.apply(this,arguments)}},Mr.ary=Eo,Mr.assign=wf,Mr.assignIn=mf,Mr.assignInWith=xf,Mr.assignWith=jf,Mr.at=Af,Mr.before=Io,Mr.bind=Ro,Mr.bindAll=na,Mr.bindKey=zo,Mr.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return Po(n)?n:[n]},Mr.chain=so,Mr.chunk=function(n,t,e){t=(e?bi(n,t,e):t===u)?1:Ht(_f(t),0);var i=null==n?0:n.length;if(!i||t<1)return[];for(var o=0,f=0,a=r(vt(i/t));oi?0:i+r),(e=e===u||e>i?i:_f(e))<0&&(e+=i),e=r>e?0:gf(e);r>>0)?(n=bf(n))&&("string"==typeof t||null!=t&&!of(t))&&!(t=cu(t))&&ar(n)?mu(_r(n),0,r):n.split(t,r):[]},Mr.spread=function(n,t){if("function"!=typeof n)throw new zn(i);return t=null==t?0:Ht(_f(t),0),Je((function(r){var e=r[t],u=mu(r,0,t);return e&&Ut(u,e),It(n,this,u)}))},Mr.tail=function(n){var t=null==n?0:n.length;return t?eu(n,1,t):[]},Mr.take=function(n,t,r){return n&&n.length?eu(n,0,(t=r||t===u?1:_f(t))<0?0:t):[]},Mr.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?eu(n,(t=e-(t=r||t===u?1:_f(t)))<0?0:t,e):[]},Mr.takeRightWhile=function(n,t){return n&&n.length?pu(n,ai(t,3),!1,!0):[]},Mr.takeWhile=function(n,t){return n&&n.length?pu(n,ai(t,3)):[]},Mr.tap=function(n,t){return t(n),n},Mr.throttle=function(n,t,r){var e=!0,u=!0;if("function"!=typeof n)throw new zn(i);return nf(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),So(n,t,{leading:e,maxWait:t,trailing:u})},Mr.thru=ho,Mr.toArray=pf,Mr.toPairs=Df,Mr.toPairsIn=Mf,Mr.toPath=function(n){return Po(n)?Tt(n,Ti):cf(n)?[n]:Ru(Bi(bf(n)))},Mr.toPlainObject=df,Mr.transform=function(n,t,r){var e=Po(n),u=e||Go(n)||lf(n);if(t=ai(t,4),null==r){var i=n&&n.constructor;r=u?e?new i:[]:nf(n)&&Yo(i)?Nr(Kn(n)):{}}return(u?zt:we)(n,(function(n,e,u){return t(r,n,e,u)})),r},Mr.unary=function(n){return Eo(n,1)},Mr.union=no,Mr.unionBy=to,Mr.unionWith=ro,Mr.uniq=function(n){return n&&n.length?lu(n):[]},Mr.uniqBy=function(n,t){return n&&n.length?lu(n,ai(t,2)):[]},Mr.uniqWith=function(n,t){return t="function"==typeof t?t:u,n&&n.length?lu(n,u,t):[]},Mr.unset=function(n,t){return null==n||su(n,t)},Mr.unzip=eo,Mr.unzipWith=uo,Mr.update=function(n,t,r){return null==n?n:hu(n,t,du(r))},Mr.updateWith=function(n,t,r,e){return e="function"==typeof e?e:u,null==n?n:hu(n,t,du(r),e)},Mr.values=Nf,Mr.valuesIn=function(n){return null==n?[]:tr(n,Lf(n))},Mr.without=io,Mr.words=Qf,Mr.wrap=function(n,t){return Uo(du(t),n)},Mr.xor=oo,Mr.xorBy=fo,Mr.xorWith=ao,Mr.zip=co,Mr.zipObject=function(n,t){return gu(n||[],t||[],te)},Mr.zipObjectDeep=function(n,t){return gu(n||[],t||[],Xe)},Mr.zipWith=lo,Mr.entries=Df,Mr.entriesIn=Mf,Mr.extend=mf,Mr.extendWith=xf,aa(Mr,Mr),Mr.add=da,Mr.attempt=Xf,Mr.camelCase=Ff,Mr.capitalize=qf,Mr.ceil=ba,Mr.clamp=function(n,t,r){return r===u&&(r=t,t=u),r!==u&&(r=(r=yf(r))===r?r:0),t!==u&&(t=(t=yf(t))===t?t:0),fe(yf(n),t,r)},Mr.clone=function(n){return ae(n,4)},Mr.cloneDeep=function(n){return ae(n,5)},Mr.cloneDeepWith=function(n,t){return ae(n,5,t="function"==typeof t?t:u)},Mr.cloneWith=function(n,t){return ae(n,4,t="function"==typeof t?t:u)},Mr.conformsTo=function(n,t){return null==t||ce(n,t,Cf(t))},Mr.deburr=Pf,Mr.defaultTo=function(n,t){return null==n||n!==n?t:n},Mr.divide=wa,Mr.endsWith=function(n,t,r){n=bf(n),t=cu(t);var e=n.length,i=r=r===u?e:fe(_f(r),0,e);return(r-=t.length)>=0&&n.slice(r,i)==t},Mr.eq=Mo,Mr.escape=function(n){return(n=bf(n))&&Y.test(n)?n.replace(H,or):n},Mr.escapeRegExp=function(n){return(n=bf(n))&&on.test(n)?n.replace(un,"\\$&"):n},Mr.every=function(n,t,r){var e=Po(n)?Ct:ve;return r&&bi(n,t,r)&&(t=u),e(n,ai(t,3))},Mr.find=_o,Mr.findIndex=Fi,Mr.findKey=function(n,t){return Ft(n,ai(t,3),we)},Mr.findLast=go,Mr.findLastIndex=qi,Mr.findLastKey=function(n,t){return Ft(n,ai(t,3),me)},Mr.floor=ma,Mr.forEach=yo,Mr.forEachRight=bo,Mr.forIn=function(n,t){return null==n?n:de(n,ai(t,3),Lf)},Mr.forInRight=function(n,t){return null==n?n:be(n,ai(t,3),Lf)},Mr.forOwn=function(n,t){return n&&we(n,ai(t,3))},Mr.forOwnRight=function(n,t){return n&&me(n,ai(t,3))},Mr.get=Ef,Mr.gt=No,Mr.gte=Fo,Mr.has=function(n,t){return null!=n&&_i(n,t,Ee)},Mr.hasIn=If,Mr.head=Zi,Mr.identity=ua,Mr.includes=function(n,t,r,e){n=Vo(n)?n:Nf(n),r=r&&!e?_f(r):0;var u=n.length;return r<0&&(r=Ht(u+r,0)),af(n)?r<=u&&n.indexOf(t,r)>-1:!!u&&Pt(n,t,r)>-1},Mr.indexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=null==r?0:_f(r);return u<0&&(u=Ht(e+u,0)),Pt(n,t,u)},Mr.inRange=function(n,t,r){return t=vf(t),r===u?(r=t,t=0):r=vf(r),function(n,t,r){return n>=br(t,r)&&n=-9007199254740991&&n<=v},Mr.isSet=ff,Mr.isString=af,Mr.isSymbol=cf,Mr.isTypedArray=lf,Mr.isUndefined=function(n){return n===u},Mr.isWeakMap=function(n){return tf(n)&&vi(n)==L},Mr.isWeakSet=function(n){return tf(n)&&"[object WeakSet]"==ke(n)},Mr.join=function(n,t){return null==n?"":mt.call(n,t)},Mr.kebabCase=Zf,Mr.last=Hi,Mr.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var i=e;return r!==u&&(i=(i=_f(r))<0?Ht(e+i,0):br(i,e-1)),t===t?function(n,t,r){for(var e=r+1;e--;)if(n[e]===t)return e;return e}(n,t,i):qt(n,Vt,i,!0)},Mr.lowerCase=Vf,Mr.lowerFirst=Kf,Mr.lt=sf,Mr.lte=hf,Mr.max=function(n){return n&&n.length?_e(n,ua,Oe):u},Mr.maxBy=function(n,t){return n&&n.length?_e(n,ai(t,2),Oe):u},Mr.mean=function(n){return Kt(n,ua)},Mr.meanBy=function(n,t){return Kt(n,ai(t,2))},Mr.min=function(n){return n&&n.length?_e(n,ua,$e):u},Mr.minBy=function(n,t){return n&&n.length?_e(n,ai(t,2),$e):u},Mr.stubArray=ga,Mr.stubFalse=ya,Mr.stubObject=function(){return{}},Mr.stubString=function(){return""},Mr.stubTrue=function(){return!0},Mr.multiply=xa,Mr.nth=function(n,t){return n&&n.length?qe(n,_f(t)):u},Mr.noConflict=function(){return gt._===this&&(gt._=Nn),this},Mr.noop=ca,Mr.now=Oo,Mr.pad=function(n,t,r){n=bf(n);var e=(t=_f(t))?vr(n):0;if(!t||e>=t)return n;var u=(t-e)/2;return Pu(_t(u),r)+n+Pu(vt(u),r)},Mr.padEnd=function(n,t,r){n=bf(n);var e=(t=_f(t))?vr(n):0;return t&&et){var e=n;n=t,t=e}if(r||n%1||t%1){var i=xr();return br(n+i*(t-n+ht("1e-"+((i+"").length-1))),t)}return Ge(n,t)},Mr.reduce=function(n,t,r){var e=Po(n)?$t:Jt,u=arguments.length<3;return e(n,ai(t,4),r,u,he)},Mr.reduceRight=function(n,t,r){var e=Po(n)?Dt:Jt,u=arguments.length<3;return e(n,ai(t,4),r,u,pe)},Mr.repeat=function(n,t,r){return t=(r?bi(n,t,r):t===u)?1:_f(t),He(bf(n),t)},Mr.replace=function(){var n=arguments,t=bf(n[0]);return n.length<3?t:t.replace(n[1],n[2])},Mr.result=function(n,t,r){var e=-1,i=(t=bu(t,n)).length;for(i||(i=1,n=u);++ev)return[];var r=g,e=br(n,g);t=ai(t),n-=g;for(var u=Qt(e,t);++r=o)return n;var a=r-vr(e);if(a<1)return e;var c=f?mu(f,0,a).join(""):n.slice(0,a);if(i===u)return c+e;if(f&&(a+=c.length-a),of(i)){if(n.slice(a).search(i)){var l,s=c;for(i.global||(i=In(i.source,bf(gn.exec(i))+"g")),i.lastIndex=0;l=i.exec(s);)var h=l.index;c=c.slice(0,h===u?a:h)}}else if(n.indexOf(cu(i),a)!=a){var p=c.lastIndexOf(i);p>-1&&(c=c.slice(0,p))}return c+e},Mr.unescape=function(n){return(n=bf(n))&&J.test(n)?n.replace(G,yr):n},Mr.uniqueId=function(n){var t=++Un;return bf(n)+t},Mr.upperCase=Jf,Mr.upperFirst=Yf,Mr.each=yo,Mr.eachRight=bo,Mr.first=Zi,aa(Mr,function(){var n={};return we(Mr,(function(t,r){Tn.call(Mr.prototype,r)||(n[r]=t)})),n}(),{chain:!1}),Mr.VERSION="4.17.21",zt(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(n){Mr[n].placeholder=Mr})),zt(["drop","take"],(function(n,t){Pr.prototype[n]=function(r){r=r===u?1:Ht(_f(r),0);var e=this.__filtered__&&!t?new Pr(this):this.clone();return e.__filtered__?e.__takeCount__=br(r,e.__takeCount__):e.__views__.push({size:br(r,g),type:n+(e.__dir__<0?"Right":"")}),e},Pr.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}})),zt(["filter","map","takeWhile"],(function(n,t){var r=t+1,e=1==r||3==r;Pr.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:ai(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}})),zt(["head","last"],(function(n,t){var r="take"+(t?"Right":"");Pr.prototype[n]=function(){return this[r](1).value()[0]}})),zt(["initial","tail"],(function(n,t){var r="drop"+(t?"":"Right");Pr.prototype[n]=function(){return this.__filtered__?new Pr(this):this[r](1)}})),Pr.prototype.compact=function(){return this.filter(ua)},Pr.prototype.find=function(n){return this.filter(n).head()},Pr.prototype.findLast=function(n){return this.reverse().find(n)},Pr.prototype.invokeMap=Je((function(n,t){return"function"==typeof n?new Pr(this):this.map((function(r){return ze(r,n,t)}))})),Pr.prototype.reject=function(n){return this.filter(Bo(ai(n)))},Pr.prototype.slice=function(n,t){n=_f(n);var r=this;return r.__filtered__&&(n>0||t<0)?new Pr(r):(n<0?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==u&&(r=(t=_f(t))<0?r.dropRight(-t):r.take(t-n)),r)},Pr.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Pr.prototype.toArray=function(){return this.take(g)},we(Pr.prototype,(function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),i=Mr[e?"take"+("last"==t?"Right":""):t],o=e||/^find/.test(t);i&&(Mr.prototype[t]=function(){var t=this.__wrapped__,f=e?[1]:arguments,a=t instanceof Pr,c=f[0],l=a||Po(t),s=function(n){var t=i.apply(Mr,Ut([n],f));return e&&h?t[0]:t};l&&r&&"function"==typeof c&&1!=c.length&&(a=l=!1);var h=this.__chain__,p=!!this.__actions__.length,v=o&&!h,_=a&&!p;if(!o&&l){t=_?t:new Pr(this);var g=n.apply(t,f);return g.__actions__.push({func:ho,args:[s],thisArg:u}),new qr(g,h)}return v&&_?n.apply(this,f):(g=this.thru(s),v?e?g.value()[0]:g.value():g)})})),zt(["pop","push","shift","sort","splice","unshift"],(function(n){var t=Sn[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);Mr.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(Po(u)?u:[],n)}return this[r]((function(r){return t.apply(Po(r)?r:[],n)}))}})),we(Pr.prototype,(function(n,t){var r=Mr[t];if(r){var e=r.name+"";Tn.call(Sr,e)||(Sr[e]=[]),Sr[e].push({name:t,func:r})}})),Sr[Mu(u,2).name]=[{name:"wrapper",func:u}],Pr.prototype.clone=function(){var n=new Pr(this.__wrapped__);return n.__actions__=Ru(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Ru(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Ru(this.__views__),n},Pr.prototype.reverse=function(){if(this.__filtered__){var n=new Pr(this);n.__dir__=-1,n.__filtered__=!0}else(n=this.clone()).__dir__*=-1;return n},Pr.prototype.value=function(){var n=this.__wrapped__.value(),t=this.__dir__,r=Po(n),e=t<0,u=r?n.length:0,i=function(n,t,r){var e=-1,u=r.length;for(;++e=this.__values__.length;return{done:n,value:n?u:this.__values__[this.__index__++]}},Mr.prototype.plant=function(n){for(var t,r=this;r instanceof Fr;){var e=$i(r);e.__index__=0,e.__values__=u,t?i.__wrapped__=e:t=e;var i=e;r=r.__wrapped__}return i.__wrapped__=n,t},Mr.prototype.reverse=function(){var n=this.__wrapped__;if(n instanceof Pr){var t=n;return this.__actions__.length&&(t=new Pr(this)),(t=t.reverse()).__actions__.push({func:ho,args:[Xi],thisArg:u}),new qr(t,this.__chain__)}return this.thru(Xi)},Mr.prototype.toJSON=Mr.prototype.valueOf=Mr.prototype.value=function(){return vu(this.__wrapped__,this.__actions__)},Mr.prototype.first=Mr.prototype.head,Qn&&(Mr.prototype[Qn]=function(){return this}),Mr}();gt._=dr,(e=function(){return dr}.call(t,r,t,n))===u||(n.exports=e)}.call(this)},79879:(n,t,r)=>{"use strict";r.d(t,{A:()=>u});var e=r(59284);const u=n=>e.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},n),e.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"m3.003 4.702 4.22-2.025a1.8 1.8 0 0 1 1.554 0l4.22 2.025a.89.89 0 0 1 .503.8V6a8.55 8.55 0 0 1-3.941 7.201l-.986.631a1.06 1.06 0 0 1-1.146 0l-.986-.63A8.55 8.55 0 0 1 2.5 6v-.498c0-.341.196-.652.503-.8m3.57-3.377L2.354 3.35A2.39 2.39 0 0 0 1 5.502V6a10.05 10.05 0 0 0 4.632 8.465l.986.63a2.56 2.56 0 0 0 2.764 0l.986-.63A10.05 10.05 0 0 0 15 6v-.498c0-.918-.526-1.755-1.354-2.152l-4.22-2.025a3.3 3.3 0 0 0-2.852 0M9.5 7a1.5 1.5 0 0 1-.75 1.3v1.95a.75.75 0 0 1-1.5 0V8.3A1.5 1.5 0 1 1 9.5 7",clipRule:"evenodd"}))},89169:(n,t,r)=>{"use strict";r.d(t,{E:()=>i});var e=r(59284);const u=(0,r(69220).om)("skeleton");function i({className:n,style:t,qa:r}){return e.createElement("div",{className:u(null,n),style:t,"data-qa":r})}}}]); \ No newline at end of file diff --git a/ydb/core/viewer/monitoring/static/js/56013.d9e34466.chunk.js.LICENSE.txt b/ydb/core/viewer/monitoring/static/js/56013.d9e34466.chunk.js.LICENSE.txt deleted file mode 100644 index b1121f519abf..000000000000 --- a/ydb/core/viewer/monitoring/static/js/56013.d9e34466.chunk.js.LICENSE.txt +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @license - * Lodash - * Copyright OpenJS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ diff --git a/ydb/core/viewer/monitoring/static/js/56421.5464a012.chunk.js b/ydb/core/viewer/monitoring/static/js/56421.5464a012.chunk.js new file mode 100644 index 000000000000..bc43d7868c64 --- /dev/null +++ b/ydb/core/viewer/monitoring/static/js/56421.5464a012.chunk.js @@ -0,0 +1,2 @@ +/*! For license information please see 56421.5464a012.chunk.js.LICENSE.txt */ +(globalThis.webpackChunkydb_embedded_ui=globalThis.webpackChunkydb_embedded_ui||[]).push([[56421],{253:(e,t,i)=>{"use strict";i.d(t,{f:()=>r,j:()=>n});var s=i(32848);const n=(0,i(63591).u1)("accessibilityService"),r=new s.N1("accessibilityModeEnabled",!1)},538:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"pascal",extensions:[".pas",".p",".pp"],aliases:["Pascal","pas"],mimetypes:["text/x-pascal-source","text/x-pascal"],loader:()=>i.e(40132).then(i.bind(i,40132))})},631:(e,t,i)=>{"use strict";function s(e){return"string"===typeof e}function n(e){return"object"===typeof e&&null!==e&&!Array.isArray(e)&&!(e instanceof RegExp)&&!(e instanceof Date)}function r(e){const t=Object.getPrototypeOf(Uint8Array);return"object"===typeof e&&e instanceof t}function o(e){return"number"===typeof e&&!isNaN(e)}function a(e){return!!e&&"function"===typeof e[Symbol.iterator]}function c(e){return!0===e||!1===e}function l(e){return"undefined"===typeof e}function h(e){return!d(e)}function d(e){return l(e)||null===e}function u(e,t){if(!e)throw new Error(t?`Unexpected type, expected '${t}'`:"Unexpected type")}function g(e){if(d(e))throw new Error("Assertion Failed: argument is undefined or null");return e}function p(e){return"function"===typeof e}function m(e,t){const i=Math.min(e.length,t.length);for(let s=0;so,Gv:()=>n,Kg:()=>s,Lm:()=>c,O9:()=>h,Tn:()=>p,b0:()=>l,eU:()=>g,iu:()=>r,j:()=>u,jx:()=>m,xZ:()=>a,z:()=>d})},796:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"julia",extensions:[".jl"],aliases:["julia","Julia"],loader:()=>i.e(77642).then(i.bind(i,77642))})},908:(e,t,i)=>{"use strict";i.d(t,{As:()=>r,qg:()=>o});var s=i(81674),n=i(79400);function r(e){return JSON.stringify(e,a)}function o(e){let t=JSON.parse(e);return t=c(t),t}function a(e,t){return t instanceof RegExp?{$mid:2,source:t.source,flags:t.flags}:t}function c(e,t=0){if(!e||t>200)return e;if("object"===typeof e){switch(e.$mid){case 1:return n.r.revive(e);case 2:return new RegExp(e.source,e.flags);case 17:return new Date(e.source)}if(e instanceof s.MB||e instanceof Uint8Array)return e;if(Array.isArray(e))for(let i=0;i{!function(){"use strict";const t=i(94297),s=i(85858),n=i(76531),r=i(1449).decode,o="$value",a="$type",c="$attributes",l="$incomplete",h={string:null,number:null,boolean:null,null:null,object:null,array:null};const d="_type_tag";function u(e){if(Object.prototype.hasOwnProperty.call(e,"$attributes")&&!Object.prototype.hasOwnProperty.call(e,"$incomplete")){const t=e.$attributes[d];if("undefined"!==typeof t){const i=n.value(t),s=function(e,t){if("url"===e)return function(e){const t=e.$value,i=e.$type;if("string"===i)return{$type:"tag_value",$value:{href:t}};if("map"===i&&Object.prototype.hasOwnProperty.call(t,"href"))return{$type:"tag_value",$value:{href:n.value(t.href),text:n.value(t.text),title:n.value(t.title)}}}(t);return function(e){return{$type:e.$type,$value:e.$value}}(t)}(i,e);s&&(e.$type="tagged",e.$tag=i,e.$value=s,delete e.$attributes[d])}}}function g(e){const t={};return function(e,t){e[o]=n.hasSpecialProperty(t,o)?t[o]:t;const i=s(e[o]);if(!Object.prototype.hasOwnProperty.call(h,i))throw new Error('unipika: invalid input - $value type "'+i+'" is not supported.');if(n.hasSpecialProperty(t,a)){const i=s(t[a]);if("undefined"!==i&&"string"!==i)throw new Error('unipika: invalid input - $type must be a string instead got "'+i+'".');e[a]=t[a]}else e[a]=function(e){switch(e){case"array":return"list";case"object":return"map";default:return e}}(i)}(t,e),function(e,t){if(n.hasSpecialProperty(t,c)){const i=s(t[c]);if("object"!==i)throw new Error('unipika: invalid input - $attributes must be an object instead got "'+i+'".');e[c]=Object.assign({},t[c])}}(t,e),function(e,t){if(n.hasSpecialProperty(t,l)){const i=s(t[l]);if("boolean"!==i)throw new Error('unipika: invalid input - $attributes must be an object instead got "'+i+'".');e[l]=t[l]}}(t,e),u(t),t}function p(e,t){return Object.keys(e).map((function(i){const s=m(g(i),t);return s.$key=!0,[s,m(e[i],t)]}))}const m=function(e,i){let s;return(i=i||{}).decodeUTF8=t.parseSetting(i,"decodeUTF8",!0),(e=g(e))&&(n.hasSpecialProperty(e,c)&&(e=function(e,t){return e[c]=p(e[c],t),e}(e)),s=e[a],"map"===s?e=function(e,t){return e[o]=p(e[o],t),e}(e,i):"list"===s?e=function(e,t){return e[o]=e[o].map((function(e){return m(e,t)})),e}(e,i):"string"===s&&(e=function(e,t){try{e.$decoded_value=t.decodeUTF8?r(e[o],{allowTruncatedEnd:e[l]}):e[o]}catch(i){e.$binary=!0}return e}(e,i))),e};e.exports=m}()},1098:(e,t,i)=>{"use strict";i.d(t,{X:()=>l});var s=i(8597),n=i(51241),r=i(5662),o=i(31308),a=i(87958),c=i(38844);class l extends r.jG{static{this.ID="editor.contrib.placeholderText"}constructor(e){var t,i;super(),this._editor=e,this._editorObs=(0,c.Ud)(this._editor),this._placeholderText=this._editorObs.getOption(88),this._state=(0,o.C)({owner:this,equalsFn:n.dB},(e=>{const t=this._placeholderText.read(e);if(t&&this._editorObs.valueIsEmpty.read(e))return{placeholder:t}})),this._shouldViewBeAlive=(t=this,i=e=>void 0!==this._state.read(e)?.placeholder,(0,o.ZX)(t,((e,t)=>!0===t||i(e)))),this._view=(0,a.rm)(((e,t)=>{if(!this._shouldViewBeAlive.read(e))return;const i=(0,s.h)("div.editorPlaceholder");t.add((0,o.fm)((e=>{const t=this._state.read(e),s=void 0!==t?.placeholder;i.root.style.display=s?"block":"none",i.root.innerText=t?.placeholder??""}))),t.add((0,o.fm)((e=>{const t=this._editorObs.layoutInfo.read(e);i.root.style.left=`${t.contentLeft}px`,i.root.style.width=t.contentWidth-t.verticalScrollbarWidth+"px",i.root.style.top=`${this._editor.getTopForLineNumber(0)}px`}))),t.add((0,o.fm)((e=>{i.root.style.fontFamily=this._editorObs.getOption(49).read(e),i.root.style.fontSize=this._editorObs.getOption(52).read(e)+"px",i.root.style.lineHeight=this._editorObs.getOption(67).read(e)+"px"}))),t.add(this._editorObs.createOverlayWidget({allowEditorOverflow:!1,minContentWidthInPx:(0,o.lk)(0),position:(0,o.lk)(null),domNode:i.root}))})),this._view.recomputeInitiallyAndOnChange(this._store)}}},1155:(e,t,i)=>{"use strict";i.d(t,{m:()=>u});var s=i(59284),n=i(32084),r=i(81517),o=i(39238),a=i(98089),c=i(69220),l=i(7412);const h=(0,c.om)("tooltip"),d=["bottom","top"],u=e=>{const{children:t,content:i,disabled:c,placement:u=d,qa:g,id:p,className:m,style:f,disablePortal:_,contentClassName:v,openDelay:C=1e3,closeDelay:E}=e,[b,S]=s.useState(null),y=(0,r.d)(b,{openDelay:C,closeDelay:E,preventTriggerOnFocus:!0}),w=s.Children.only(t),R=(0,l.Q)(w),L=(0,n.N)(S,R);return s.createElement(s.Fragment,null,s.cloneElement(w,{ref:L}),b?s.createElement(o.z,{id:p,role:"tooltip",className:h(null,m),style:f,open:y&&!c,placement:u,anchorRef:{current:b},disablePortal:_,disableEscapeKeyDown:!0,disableOutsideClick:!0,disableLayer:!0,qa:g},s.createElement("div",{className:h("content",v)},s.createElement(a.E,{variant:"body-short",color:"complementary"},i))):null)}},1226:(e,t,i)=>{"use strict";i.d(t,{g:()=>h});var s=i(91508),n=i(15092),r=i(32799),o=i(1245),a=i(94564),c=i(36677),l=i(83069);class h{static deleteRight(e,t,i,s){const r=[];let o=3!==e;for(let l=0,h=s.length;l=d.length+1)return!1;const u=d.charAt(h.column-2),g=s.get(u);if(!g)return!1;if((0,r.vG)(u)){if("never"===i)return!1}else if("never"===t)return!1;const p=d.charAt(h.column-1);let m=!1;for(const e of g)e.open===u&&e.close===p&&(m=!0);if(!m)return!1;if("auto"===e){let e=!1;for(let t=0,i=a.length;t1){const e=t.getLineContent(n.lineNumber),r=s.HG(e),a=-1===r?e.length+1:r+1;if(n.column<=a){const e=i.visibleColumnFromColumn(t,n),s=o.A.prevIndentTabStop(e,i.indentSize),r=i.columnFromVisibleColumn(t,n.lineNumber,s);return new c.Q(n.lineNumber,r,n.lineNumber,n.column)}}return c.Q.fromPositions(h.getPositionAfterDeleteLeft(n,t),n)}static getPositionAfterDeleteLeft(e,t){if(e.column>1){const i=s.Wd(e.column-1,t.getLineContent(e.lineNumber));return e.with(void 0,i+1)}if(e.lineNumber>1){const i=e.lineNumber-1;return new l.y(i,t.getLineMaxColumn(i))}return e}static cut(e,t,i){const s=[];let o=null;i.sort(((e,t)=>l.y.compare(e.getStartPosition(),t.getEndPosition())));for(let r=0,a=i.length;r1&&o?.endLineNumber!==e.lineNumber?(i=e.lineNumber-1,l=t.getLineMaxColumn(e.lineNumber-1),h=e.lineNumber,d=t.getLineMaxColumn(e.lineNumber)):(i=e.lineNumber,l=1,h=e.lineNumber,d=t.getLineMaxColumn(e.lineNumber));const u=new c.Q(i,l,h,d);o=u,u.isEmpty()?s[r]=null:s[r]=new n.iu(u,"")}else s[r]=null;else s[r]=new n.iu(a,"")}return new r.vY(0,s,{shouldPushStackElementBefore:!0,shouldPushStackElementAfter:!0})}}},1245:(e,t,i)=>{"use strict";i.d(t,{A:()=>n});var s=i(91508);class n{static _nextVisibleColumn(e,t,i){return 9===e?n.nextRenderTabStop(t,i):s.ne(e)||s.Ss(e)?t+2:t+1}static visibleColumnFromColumn(e,t,i){const n=Math.min(t-1,e.length),r=e.substring(0,n),o=new s.km(r);let a=0;for(;!o.eol();){const e=s.Z5(r,n,o.offset);o.nextGraphemeLength(),a=this._nextVisibleColumn(e,a,i)}return a}static columnFromVisibleColumn(e,t,i){if(t<=0)return 1;const n=e.length,r=new s.km(e);let o=0,a=1;for(;!r.eol();){const c=s.Z5(e,n,r.offset);r.nextGraphemeLength();const l=this._nextVisibleColumn(c,o,i),h=r.offset+1;if(l>=t){return l-t{!function(){"use strict";const t=i(59170);e.exports={encode:t.encode,decode:t.decode}}()},1592:(e,t,i)=>{"use strict";function s(e,t,i){return Math.min(Math.max(e,t),i)}i.d(t,{Uq:()=>n,mu:()=>r,qE:()=>s});class n{constructor(){this._n=1,this._val=0}update(e){return this._val=this._val+(e-this._val)/this._n,this._n+=1,this._val}get value(){return this._val}}class r{constructor(e){this._n=0,this._val=0,this._values=[],this._index=0,this._sum=0,this._values=new Array(e),this._values.fill(0,0,e)}update(e){const t=this._values[this._index];return this._values[this._index]=e,this._index=(this._index+1)%this._values.length,this._sum-=t,this._sum+=e,this._n{"use strict";i.d(t,{Fd:()=>h,Gv:()=>y,rC:()=>S});var s=i(25890),n=i(41234),r=i(631),o=i(78209),a=i(84001),c=i(78748),l=i(46359);const h={Configuration:"base.contributions.configuration"},d={properties:{},patternProperties:{}},u={properties:{},patternProperties:{}},g={properties:{},patternProperties:{}},p={properties:{},patternProperties:{}},m={properties:{},patternProperties:{}},f={properties:{},patternProperties:{}},_="vscode://schemas/settings/resourceLanguage",v=l.O.as(c.F.JSONContribution);const C="\\[([^\\]]+)\\]",E=new RegExp(C,"g"),b=`^(${C})+$`,S=new RegExp(b);function y(e){const t=[];if(S.test(e)){let i=E.exec(e);for(;i?.length;){const s=i[1].trim();s&&t.push(s),i=E.exec(e)}}return(0,s.dM)(t)}const w=new class{constructor(){this.registeredConfigurationDefaults=[],this.overrideIdentifiers=new Set,this._onDidSchemaChange=new n.vl,this._onDidUpdateConfiguration=new n.vl,this.configurationDefaultsOverrides=new Map,this.defaultLanguageConfigurationOverridesNode={id:"defaultOverrides",title:o.kg("defaultLanguageConfigurationOverrides.title","Default Language Configuration Overrides"),properties:{}},this.configurationContributors=[this.defaultLanguageConfigurationOverridesNode],this.resourceLanguageSettingsSchema={properties:{},patternProperties:{},additionalProperties:!0,allowTrailingCommas:!0,allowComments:!0},this.configurationProperties={},this.policyConfigurations=new Map,this.excludedConfigurationProperties={},v.registerSchema(_,this.resourceLanguageSettingsSchema),this.registerOverridePropertyPatternKey()}registerConfiguration(e,t=!0){this.registerConfigurations([e],t)}registerConfigurations(e,t=!0){const i=new Set;this.doRegisterConfigurations(e,t,i),v.registerSchema(_,this.resourceLanguageSettingsSchema),this._onDidSchemaChange.fire(),this._onDidUpdateConfiguration.fire({properties:i})}registerDefaultConfigurations(e){const t=new Set;this.doRegisterDefaultConfigurations(e,t),this._onDidSchemaChange.fire(),this._onDidUpdateConfiguration.fire({properties:t,defaultsOverrides:!0})}doRegisterDefaultConfigurations(e,t){this.registeredConfigurationDefaults.push(...e);const i=[];for(const{overrides:s,source:n}of e)for(const e in s){t.add(e);const r=this.configurationDefaultsOverrides.get(e)??this.configurationDefaultsOverrides.set(e,{configurationDefaultOverrides:[]}).get(e),o=s[e];if(r.configurationDefaultOverrides.push({value:o,source:n}),S.test(e)){const t=this.mergeDefaultConfigurationsForOverrideIdentifier(e,o,n,r.configurationDefaultOverrideValue);if(!t)continue;r.configurationDefaultOverrideValue=t,this.updateDefaultOverrideProperty(e,t,n),i.push(...y(e))}else{const t=this.mergeDefaultConfigurationsForConfigurationProperty(e,o,n,r.configurationDefaultOverrideValue);if(!t)continue;r.configurationDefaultOverrideValue=t;const i=this.configurationProperties[e];i&&(this.updatePropertyDefaultValue(e,i),this.updateSchema(e,i))}}this.doRegisterOverrideIdentifiers(i)}updateDefaultOverrideProperty(e,t,i){const s={type:"object",default:t.value,description:o.kg("defaultLanguageConfiguration.description","Configure settings to be overridden for the {0} language.",(0,a.Mo)(e)),$ref:_,defaultDefaultValue:t.value,source:i,defaultValueSource:i};this.configurationProperties[e]=s,this.defaultLanguageConfigurationOverridesNode.properties[e]=s}mergeDefaultConfigurationsForOverrideIdentifier(e,t,i,s){const n=s?.value||{},o=s?.source??new Map;if(o instanceof Map){for(const e of Object.keys(t)){const s=t[e];if(r.Gv(s)&&(r.b0(n[e])||r.Gv(n[e]))){if(n[e]={...n[e]??{},...s},i)for(const t in s)o.set(`${e}.${t}`,i)}else n[e]=s,i?o.set(e,i):o.delete(e)}return{value:n,source:o}}console.error("objectConfigurationSources is not a Map")}mergeDefaultConfigurationsForConfigurationProperty(e,t,i,s){const n=this.configurationProperties[e],o=s?.value??n?.defaultDefaultValue;let a=i;if(r.Gv(t)&&(void 0!==n&&"object"===n.type||void 0===n&&(r.b0(o)||r.Gv(o)))){if(a=s?.source??new Map,!(a instanceof Map))return void console.error("defaultValueSource is not a Map");for(const s in t)i&&a.set(`${e}.${s}`,i);t={...r.Gv(o)?o:{},...t}}return{value:t,source:a}}registerOverrideIdentifiers(e){this.doRegisterOverrideIdentifiers(e),this._onDidSchemaChange.fire()}doRegisterOverrideIdentifiers(e){for(const t of e)this.overrideIdentifiers.add(t);this.updateOverridePropertyPatternKey()}doRegisterConfigurations(e,t,i){e.forEach((e=>{this.validateAndRegisterProperties(e,t,e.extensionInfo,e.restrictedProperties,void 0,i),this.configurationContributors.push(e),this.registerJSONConfiguration(e)}))}validateAndRegisterProperties(e,t=!0,i,s,n=3,o){n=r.z(e.scope)?n:e.scope;const a=e.properties;if(a)for(const l in a){const e=a[l];t&&R(l,e)?delete a[l]:(e.source=i,e.defaultDefaultValue=a[l].default,this.updatePropertyDefaultValue(l,e),S.test(l)?e.scope=void 0:(e.scope=r.z(e.scope)?n:e.scope,e.restricted=r.z(e.restricted)?!!s?.includes(l):e.restricted),!a[l].hasOwnProperty("included")||a[l].included?(this.configurationProperties[l]=a[l],a[l].policy?.name&&this.policyConfigurations.set(a[l].policy.name,l),!a[l].deprecationMessage&&a[l].markdownDeprecationMessage&&(a[l].deprecationMessage=a[l].markdownDeprecationMessage),o.add(l)):(this.excludedConfigurationProperties[l]=a[l],delete a[l]))}const c=e.allOf;if(c)for(const r of c)this.validateAndRegisterProperties(r,t,i,s,n,o)}getConfigurationProperties(){return this.configurationProperties}getPolicyConfigurations(){return this.policyConfigurations}registerJSONConfiguration(e){const t=e=>{const i=e.properties;if(i)for(const t in i)this.updateSchema(t,i[t]);const s=e.allOf;s?.forEach(t)};t(e)}updateSchema(e,t){switch(d.properties[e]=t,t.scope){case 1:u.properties[e]=t;break;case 2:g.properties[e]=t;break;case 6:p.properties[e]=t;break;case 3:m.properties[e]=t;break;case 4:f.properties[e]=t;break;case 5:f.properties[e]=t,this.resourceLanguageSettingsSchema.properties[e]=t}}updateOverridePropertyPatternKey(){for(const e of this.overrideIdentifiers.values()){const t=`[${e}]`,i={type:"object",description:o.kg("overrideSettings.defaultDescription","Configure editor settings to be overridden for a language."),errorMessage:o.kg("overrideSettings.errorMessage","This setting does not support per-language configuration."),$ref:_};this.updatePropertyDefaultValue(t,i),d.properties[t]=i,u.properties[t]=i,g.properties[t]=i,p.properties[t]=i,m.properties[t]=i,f.properties[t]=i}}registerOverridePropertyPatternKey(){const e={type:"object",description:o.kg("overrideSettings.defaultDescription","Configure editor settings to be overridden for a language."),errorMessage:o.kg("overrideSettings.errorMessage","This setting does not support per-language configuration."),$ref:_};d.patternProperties[b]=e,u.patternProperties[b]=e,g.patternProperties[b]=e,p.patternProperties[b]=e,m.patternProperties[b]=e,f.patternProperties[b]=e,this._onDidSchemaChange.fire()}updatePropertyDefaultValue(e,t){const i=this.configurationDefaultsOverrides.get(e)?.configurationDefaultOverrideValue;let s,n;!i||t.disallowConfigurationDefault&&i.source||(s=i.value,n=i.source),r.b0(s)&&(s=t.defaultDefaultValue,n=void 0),r.b0(s)&&(s=function(e){switch(Array.isArray(e)?e[0]:e){case"boolean":return!1;case"integer":case"number":return 0;case"string":return"";case"array":return[];case"object":return{};default:return null}}(t.type)),t.default=s,t.defaultValueSource=n}};function R(e,t){return e.trim()?S.test(e)?o.kg("config.property.languageDefault","Cannot register '{0}'. This matches property pattern '\\\\[.*\\\\]$' for describing language specific editor settings. Use 'configurationDefaults' contribution.",e):void 0!==w.getConfigurationProperties()[e]?o.kg("config.property.duplicate","Cannot register '{0}'. This property is already registered.",e):t.policy?.name&&void 0!==w.getPolicyConfigurations().get(t.policy?.name)?o.kg("config.policy.duplicate","Cannot register '{0}'. The associated policy {1} is already registered with {2}.",e,t.policy?.name,w.getPolicyConfigurations().get(t.policy?.name)):null:o.kg("config.property.empty","Cannot register an empty property")}l.O.add(h.Configuration,w)},1956:(e,t,i)=>{"use strict";i.d(t,{A:()=>n});var s=i(59284);const n=e=>s.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),s.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M4.5 3h7A1.5 1.5 0 0 1 13 4.5v7a1.5 1.5 0 0 1-1.5 1.5h-7A1.5 1.5 0 0 1 3 11.5v-7A1.5 1.5 0 0 1 4.5 3m-3 1.5a3 3 0 0 1 3-3h7a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3h-7a3 3 0 0 1-3-3zm10.092 1.46a.75.75 0 0 0-1.184-.92L7.43 8.869l-1.4-1.4A.75.75 0 0 0 4.97 8.53l2 2a.75.75 0 0 0 1.122-.07z",clipRule:"evenodd"}))},2068:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"shell",extensions:[".sh",".bash"],aliases:["Shell","sh"],loader:()=>i.e(79842).then(i.bind(i,79842))})},2183:(e,t,i)=>{"use strict";var s=i(5662),n=i(98067),r=i(31450),o=i(83069),a=i(36677),c=i(75326),l=i(87289);class h{constructor(e,t,i){this.selection=e,this.targetPosition=t,this.copy=i,this.targetSelection=null}getEditOperations(e,t){const i=e.getValueInRange(this.selection);this.copy||t.addEditOperation(this.selection,null),t.addEditOperation(new a.Q(this.targetPosition.lineNumber,this.targetPosition.column,this.targetPosition.lineNumber,this.targetPosition.column),i),!this.selection.containsPosition(this.targetPosition)||this.copy&&(this.selection.getEndPosition().equals(this.targetPosition)||this.selection.getStartPosition().equals(this.targetPosition))?this.copy?this.targetSelection=new c.L(this.targetPosition.lineNumber,this.targetPosition.column,this.selection.endLineNumber-this.selection.startLineNumber+this.targetPosition.lineNumber,this.selection.startLineNumber===this.selection.endLineNumber?this.targetPosition.column+this.selection.endColumn-this.selection.startColumn:this.selection.endColumn):this.targetPosition.lineNumber>this.selection.endLineNumber?this.targetSelection=new c.L(this.targetPosition.lineNumber-this.selection.endLineNumber+this.selection.startLineNumber,this.targetPosition.column,this.targetPosition.lineNumber,this.selection.startLineNumber===this.selection.endLineNumber?this.targetPosition.column+this.selection.endColumn-this.selection.startColumn:this.selection.endColumn):this.targetPosition.lineNumberthis._onEditorMouseDown(e)))),this._register(this._editor.onMouseUp((e=>this._onEditorMouseUp(e)))),this._register(this._editor.onMouseDrag((e=>this._onEditorMouseDrag(e)))),this._register(this._editor.onMouseDrop((e=>this._onEditorMouseDrop(e)))),this._register(this._editor.onMouseDropCanceled((()=>this._onEditorMouseDropCanceled()))),this._register(this._editor.onKeyDown((e=>this.onEditorKeyDown(e)))),this._register(this._editor.onKeyUp((e=>this.onEditorKeyUp(e)))),this._register(this._editor.onDidBlurEditorWidget((()=>this.onEditorBlur()))),this._register(this._editor.onDidBlurEditorText((()=>this.onEditorBlur()))),this._mouseDown=!1,this._modifierPressed=!1,this._dragSelection=null}onEditorBlur(){this._removeDecoration(),this._dragSelection=null,this._mouseDown=!1,this._modifierPressed=!1}onEditorKeyDown(e){this._editor.getOption(35)&&!this._editor.getOption(22)&&(d(e)&&(this._modifierPressed=!0),this._mouseDown&&d(e)&&this._editor.updateOptions({mouseStyle:"copy"}))}onEditorKeyUp(e){this._editor.getOption(35)&&!this._editor.getOption(22)&&(d(e)&&(this._modifierPressed=!1),this._mouseDown&&e.keyCode===u.TRIGGER_KEY_VALUE&&this._editor.updateOptions({mouseStyle:"default"}))}_onEditorMouseDown(e){this._mouseDown=!0}_onEditorMouseUp(e){this._mouseDown=!1,this._editor.updateOptions({mouseStyle:"text"})}_onEditorMouseDrag(e){const t=e.target;if(null===this._dragSelection){const e=(this._editor.getSelections()||[]).filter((e=>t.position&&e.containsPosition(t.position)));if(1!==e.length)return;this._dragSelection=e[0]}d(e.event)?this._editor.updateOptions({mouseStyle:"copy"}):this._editor.updateOptions({mouseStyle:"default"}),t.position&&(this._dragSelection.containsPosition(t.position)?this._removeDecoration():this.showAt(t.position))}_onEditorMouseDropCanceled(){this._editor.updateOptions({mouseStyle:"text"}),this._removeDecoration(),this._dragSelection=null,this._mouseDown=!1}_onEditorMouseDrop(e){if(e.target&&(this._hitContent(e.target)||this._hitMargin(e.target))&&e.target.position){const t=new o.y(e.target.position.lineNumber,e.target.position.column);if(null===this._dragSelection){let i=null;if(e.event.shiftKey){const e=this._editor.getSelection();if(e){const{selectionStartLineNumber:s,selectionStartColumn:n}=e;i=[new c.L(s,n,t.lineNumber,t.column)]}}else i=(this._editor.getSelections()||[]).map((e=>e.containsPosition(t)?new c.L(t.lineNumber,t.column,t.lineNumber,t.column):e));this._editor.setSelections(i||[],"mouse",3)}else(!this._dragSelection.containsPosition(t)||(d(e.event)||this._modifierPressed)&&(this._dragSelection.getEndPosition().equals(t)||this._dragSelection.getStartPosition().equals(t)))&&(this._editor.pushUndoStop(),this._editor.executeCommand(u.ID,new h(this._dragSelection,t,d(e.event)||this._modifierPressed)),this._editor.pushUndoStop())}this._editor.updateOptions({mouseStyle:"text"}),this._removeDecoration(),this._dragSelection=null,this._mouseDown=!1}static{this._DECORATION_OPTIONS=l.kI.register({description:"dnd-target",className:"dnd-target"})}showAt(e){this._dndDecorationIds.set([{range:new a.Q(e.lineNumber,e.column,e.lineNumber,e.column),options:u._DECORATION_OPTIONS}]),this._editor.revealPosition(e,1)}_removeDecoration(){this._dndDecorationIds.clear()}_hitContent(e){return 6===e.type||7===e.type}_hitMargin(e){return 2===e.type||3===e.type||4===e.type}dispose(){this._removeDecoration(),this._dragSelection=null,this._mouseDown=!1,this._modifierPressed=!1,super.dispose()}}(0,r.HW)(u.ID,u,2)},2299:(e,t,i)=>{"use strict";i.d(t,{M:()=>n});var s=i(41234);const n=new class{constructor(){this._onDidChange=new s.vl,this.onDidChange=this._onDidChange.event,this._enabled=!0}get enabled(){return this._enabled}enable(){this._enabled=!0,this._onDidChange.fire()}disable(){this._enabled=!1,this._onDidChange.fire()}}},2539:e=>{e.exports=function(){function e(e,t){const i=e.$value;return"function"===typeof t.customNumberFormatter?t.customNumberFormatter(e.$value,e.$type):"yson"===t.format?i+"u":i}return e.isScalar=!0,e}},3254:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"java",extensions:[".java",".jav"],aliases:["Java","java"],mimetypes:["text/x-java-source","text/x-java"],loader:()=>i.e(99176).then(i.bind(i,99176))})},3730:(e,t,i)=>{"use strict";i.d(t,{CN:()=>u,EP:()=>l,P8:()=>d});var s=i(64383),n=i(5662),r=i(83069),o=i(36677),a=i(36456),c=i(79400);class l{constructor(e,t){this.range=e,this.direction=t}}class h{constructor(e,t,i){this.hint=e,this.anchor=t,this.provider=i,this._isResolved=!1}with(e){const t=new h(this.hint,e.anchor,this.provider);return t._isResolved=this._isResolved,t._currentResolve=this._currentResolve,t}async resolve(e){if("function"===typeof this.provider.resolveInlayHint){if(this._currentResolve){if(await this._currentResolve,e.isCancellationRequested)return;return this.resolve(e)}this._isResolved||(this._currentResolve=this._doResolve(e).finally((()=>this._currentResolve=void 0))),await this._currentResolve}}async _doResolve(e){try{const t=await Promise.resolve(this.provider.resolveInlayHint(this.hint,e));this.hint.tooltip=t?.tooltip??this.hint.tooltip,this.hint.label=t?.label??this.hint.label,this.hint.textEdits=t?.textEdits??this.hint.textEdits,this._isResolved=!0}catch(t){(0,s.M_)(t),this._isResolved=!1}}}class d{static{this._emptyInlayHintList=Object.freeze({dispose(){},hints:[]})}static async create(e,t,i,n){const r=[],o=e.ordered(t).reverse().map((e=>i.map((async i=>{try{const s=await e.provideInlayHints(t,i,n);(s?.hints.length||e.onDidChangeInlayHints)&&r.push([s??d._emptyInlayHintList,e])}catch(o){(0,s.M_)(o)}}))));if(await Promise.all(o.flat()),n.isCancellationRequested||t.isDisposed())throw new s.AL;return new d(i,r,t)}constructor(e,t,i){this._disposables=new n.Cm,this.ranges=e,this.provider=new Set;const s=[];for(const[n,r]of t){this._disposables.add(n),this.provider.add(r);for(const e of n.hints){const t=i.validatePosition(e.position);let n="before";const a=d._getRangeAtPosition(i,t);let c;a.getStartPosition().isBefore(t)?(c=o.Q.fromPositions(a.getStartPosition(),t),n="after"):(c=o.Q.fromPositions(t,a.getEndPosition()),n="before"),s.push(new h(e,new l(c,n),r))}}this.items=s.sort(((e,t)=>r.y.compare(e.hint.position,t.hint.position)))}dispose(){this._disposables.dispose()}static _getRangeAtPosition(e,t){const i=t.lineNumber,s=e.getWordAtPosition(t);if(s)return new o.Q(i,s.startColumn,i,s.endColumn);e.tokenization.tokenizeIfCheap(i);const n=e.tokenization.getLineTokens(i),r=t.column-1,a=n.findTokenIndexAtOffset(r);let c=n.getStartOffset(a),l=n.getEndOffset(a);return l-c===1&&(c===r&&a>1?(c=n.getStartOffset(a-1),l=n.getEndOffset(a-1)):l===r&&a{"use strict";i.d(t,{x:()=>r});var s=i(8597),n=i(91508);class r{constructor(e,t,i){this.options=t,this.styles=i,this.count=0,this.element=(0,s.BC)(e,(0,s.$)(".monaco-count-badge")),this.countFormat=this.options.countFormat||"{0}",this.titleFormat=this.options.titleFormat||"",this.setCount(this.options.count||0)}setCount(e){this.count=e,this.render()}setTitleFormat(e){this.titleFormat=e,this.render()}render(){this.element.textContent=(0,n.GP)(this.countFormat,this.count),this.element.title=(0,n.GP)(this.titleFormat,this.count),this.element.style.backgroundColor=this.styles.badgeBackground??"",this.element.style.color=this.styles.badgeForeground??"",this.styles.badgeBorder&&(this.element.style.border=`1px solid ${this.styles.badgeBorder}`)}}},4360:(e,t,i)=>{"use strict";i.d(t,{T:()=>Bt});var s=i(8597),n=i(46041),r=i(64383),o=i(41234),a=i(5662),c=i(31308),l=i(87958),h=i(31450),d=i(80301),u=i(55190),g=i(52555),p=i(80789),m=i(11799),f=i(31295),_=i(36921),v=i(25890),C=i(10350),E=i(25689),b=i(73157),S=i(92368),y=i(87908),w=i(86571),R=i(74444),L=i(83069),T=i(36677),x=i(87723),k=i(10154),A=i(87469),N=i(35600),I=i(92896),O=i(78209),D=i(87213),M=i(63591),P=i(61394),F=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},U=function(e,t){return function(i,s){t(i,s,e)}};const H=(0,P.pU)("diff-review-insert",C.W.add,(0,O.kg)("accessibleDiffViewerInsertIcon","Icon for 'Insert' in accessible diff viewer.")),B=(0,P.pU)("diff-review-remove",C.W.remove,(0,O.kg)("accessibleDiffViewerRemoveIcon","Icon for 'Remove' in accessible diff viewer.")),W=(0,P.pU)("diff-review-close",C.W.close,(0,O.kg)("accessibleDiffViewerCloseIcon","Icon for 'Close' in accessible diff viewer."));let V=class extends a.jG{static{this._ttPolicy=(0,p.H)("diffReview",{createHTML:e=>e})}constructor(e,t,i,s,n,r,o,a,l){super(),this._parentNode=e,this._visible=t,this._setVisible=i,this._canClose=s,this._width=n,this._height=r,this._diffs=o,this._models=a,this._instantiationService=l,this._state=(0,c.rm)(this,((e,t)=>{const i=this._visible.read(e);if(this._parentNode.style.visibility=i?"visible":"hidden",!i)return null;const s=t.add(this._instantiationService.createInstance(z,this._diffs,this._models,this._setVisible,this._canClose));return{model:s,view:t.add(this._instantiationService.createInstance(X,this._parentNode,s,this._width,this._height,this._models))}})).recomputeInitiallyAndOnChange(this._store)}next(){(0,c.Rn)((e=>{const t=this._visible.get();this._setVisible(!0,e),t&&this._state.get().model.nextGroup(e)}))}prev(){(0,c.Rn)((e=>{this._setVisible(!0,e),this._state.get().model.previousGroup(e)}))}close(){(0,c.Rn)((e=>{this._setVisible(!1,e)}))}};V=F([U(8,M._Y)],V);let z=class extends a.jG{constructor(e,t,i,s,n){super(),this._diffs=e,this._models=t,this._setVisible=i,this.canClose=s,this._accessibilitySignalService=n,this._groups=(0,c.FY)(this,[]),this._currentGroupIdx=(0,c.FY)(this,0),this._currentElementIdx=(0,c.FY)(this,0),this.groups=this._groups,this.currentGroup=this._currentGroupIdx.map(((e,t)=>this._groups.read(t)[e])),this.currentGroupIndex=this._currentGroupIdx,this.currentElement=this._currentElementIdx.map(((e,t)=>this.currentGroup.read(t)?.lines[e])),this._register((0,c.fm)((e=>{const t=this._diffs.read(e);if(!t)return void this._groups.set([],void 0);const i=function(e,t,i){const s=[];for(const n of(0,v.n)(e,((e,t)=>t.modified.startLineNumber-e.modified.endLineNumberExclusive<2*G))){const e=[];e.push(new Y);const r=new w.M(Math.max(1,n[0].original.startLineNumber-G),Math.min(n[n.length-1].original.endLineNumberExclusive+G,t+1)),o=new w.M(Math.max(1,n[0].modified.startLineNumber-G),Math.min(n[n.length-1].modified.endLineNumberExclusive+G,i+1));(0,v.pN)(n,((t,i)=>{const s=new w.M(t?t.original.endLineNumberExclusive:r.startLineNumber,i?i.original.startLineNumber:r.endLineNumberExclusive),n=new w.M(t?t.modified.endLineNumberExclusive:o.startLineNumber,i?i.modified.startLineNumber:o.endLineNumberExclusive);s.forEach((t=>{e.push(new Q(t,n.startLineNumber+(t-s.startLineNumber)))})),i&&(i.original.forEach((t=>{e.push(new q(i,t))})),i.modified.forEach((t=>{e.push(new $(i,t))})))}));const a=n[0].modified.join(n[n.length-1].modified),c=n[0].original.join(n[n.length-1].original);s.push(new K(new x.WL(a,c),e))}return s}(t,this._models.getOriginalModel().getLineCount(),this._models.getModifiedModel().getLineCount());(0,c.Rn)((e=>{const t=this._models.getModifiedPosition();if(t){const s=i.findIndex((e=>t?.lineNumber{const t=this.currentElement.read(e);t?.type===j.Deleted?this._accessibilitySignalService.playSignal(D.Rh.diffLineDeleted,{source:"accessibleDiffViewer.currentElementChanged"}):t?.type===j.Added&&this._accessibilitySignalService.playSignal(D.Rh.diffLineInserted,{source:"accessibleDiffViewer.currentElementChanged"})}))),this._register((0,c.fm)((e=>{const t=this.currentElement.read(e);if(t&&t.type!==j.Header){const e=t.modifiedLineNumber??t.diff.modified.startLineNumber;this._models.modifiedSetSelection(T.Q.fromPositions(new L.y(e,1)))}})))}_goToGroupDelta(e,t){const i=this.groups.get();!i||i.length<=1||(0,c.PO)(t,(t=>{this._currentGroupIdx.set(R.L.ofLength(i.length).clipCyclic(this._currentGroupIdx.get()+e),t),this._currentElementIdx.set(0,t)}))}nextGroup(e){this._goToGroupDelta(1,e)}previousGroup(e){this._goToGroupDelta(-1,e)}_goToLineDelta(e){const t=this.currentGroup.get();!t||t.lines.length<=1||(0,c.Rn)((i=>{this._currentElementIdx.set(R.L.ofLength(t.lines.length).clip(this._currentElementIdx.get()+e),i)}))}goToNextLine(){this._goToLineDelta(1)}goToPreviousLine(){this._goToLineDelta(-1)}goToLine(e){const t=this.currentGroup.get();if(!t)return;const i=t.lines.indexOf(e);-1!==i&&(0,c.Rn)((e=>{this._currentElementIdx.set(i,e)}))}revealCurrentElementInEditor(){if(!this.canClose.get())return;this._setVisible(!1,void 0);const e=this.currentElement.get();e&&(e.type===j.Deleted?this._models.originalReveal(T.Q.fromPositions(new L.y(e.originalLineNumber,1))):this._models.modifiedReveal(e.type!==j.Header?T.Q.fromPositions(new L.y(e.modifiedLineNumber,1)):void 0))}close(){this.canClose.get()&&(this._setVisible(!1,void 0),this._models.modifiedFocus())}};z=F([U(4,D.Nt)],z);const G=3;var j;!function(e){e[e.Header=0]="Header",e[e.Unchanged=1]="Unchanged",e[e.Deleted=2]="Deleted",e[e.Added=3]="Added"}(j||(j={}));class K{constructor(e,t){this.range=e,this.lines=t}}class Y{constructor(){this.type=j.Header}}class q{constructor(e,t){this.diff=e,this.originalLineNumber=t,this.type=j.Deleted,this.modifiedLineNumber=void 0}}class ${constructor(e,t){this.diff=e,this.modifiedLineNumber=t,this.type=j.Added,this.originalLineNumber=void 0}}class Q{constructor(e,t){this.originalLineNumber=e,this.modifiedLineNumber=t,this.type=j.Unchanged}}let X=class extends a.jG{constructor(e,t,i,n,r,o){super(),this._element=e,this._model=t,this._width=i,this._height=n,this._models=r,this._languageService=o,this.domNode=this._element,this.domNode.className="monaco-component diff-review monaco-editor-background";const l=document.createElement("div");l.className="diff-review-actions",this._actionBar=this._register(new m.E(l)),this._register((0,c.fm)((e=>{this._actionBar.clear(),this._model.canClose.read(e)&&this._actionBar.push(new _.rc("diffreview.close",(0,O.kg)("label.close","Close"),"close-diff-review "+E.L.asClassName(W),!0,(async()=>t.close())),{label:!1,icon:!0})}))),this._content=document.createElement("div"),this._content.className="diff-review-content",this._content.setAttribute("role","code"),this._scrollbar=this._register(new f.MU(this._content,{})),(0,s.Ln)(this.domNode,this._scrollbar.getDomNode(),l),this._register((0,c.fm)((e=>{this._height.read(e),this._width.read(e),this._scrollbar.scanDomNode()}))),this._register((0,a.s)((()=>{(0,s.Ln)(this.domNode)}))),this._register((0,S.AV)(this.domNode,{width:this._width,height:this._height})),this._register((0,S.AV)(this._content,{width:this._width,height:this._height})),this._register((0,c.yC)(((e,t)=>{this._model.currentGroup.read(e),this._render(t)}))),this._register((0,s.b2)(this.domNode,"keydown",(e=>{(e.equals(18)||e.equals(2066)||e.equals(530))&&(e.preventDefault(),this._model.goToNextLine()),(e.equals(16)||e.equals(2064)||e.equals(528))&&(e.preventDefault(),this._model.goToPreviousLine()),(e.equals(9)||e.equals(2057)||e.equals(521)||e.equals(1033))&&(e.preventDefault(),this._model.close()),(e.equals(10)||e.equals(3))&&(e.preventDefault(),this._model.revealCurrentElementInEditor())})))}_render(e){const t=this._models.getOriginalOptions(),i=this._models.getModifiedOptions(),n=document.createElement("div");n.className="diff-review-table",n.setAttribute("role","list"),n.setAttribute("aria-label",(0,O.kg)("ariaLabel","Accessible Diff Viewer. Use arrow up and down to navigate.")),(0,b.M)(n,i.get(50)),(0,s.Ln)(this._content,n);const r=this._models.getOriginalModel(),o=this._models.getModifiedModel();if(!r||!o)return;const a=r.getOptions(),l=o.getOptions(),h=i.get(67),d=this._model.currentGroup.get();for(const u of d?.lines||[]){if(!d)break;let g;if(u.type===j.Header){const e=document.createElement("div");e.className="diff-review-row",e.setAttribute("role","listitem");const t=d.range,i=this._model.currentGroupIndex.get(),s=this._model.groups.get().length,n=e=>0===e?(0,O.kg)("no_lines_changed","no lines changed"):1===e?(0,O.kg)("one_line_changed","1 line changed"):(0,O.kg)("more_lines_changed","{0} lines changed",e),r=n(t.original.length),o=n(t.modified.length);e.setAttribute("aria-label",(0,O.kg)({key:"header",comment:["This is the ARIA label for a git diff header.","A git diff header looks like this: @@ -154,12 +159,39 @@.","That encodes that at original line 154 (which is now line 159), 12 lines were removed/changed with 39 lines.","Variables 0 and 1 refer to the diff index out of total number of diffs.","Variables 2 and 4 will be numbers (a line number).",'Variables 3 and 5 will be "no lines changed", "1 line changed" or "X lines changed", localized separately.']},"Difference {0} of {1}: original line {2}, {3}, modified line {4}, {5}",i+1,s,t.original.startLineNumber,r,t.modified.startLineNumber,o));const a=document.createElement("div");a.className="diff-review-cell diff-review-summary",a.appendChild(document.createTextNode(`${i+1}/${s}: @@ -${t.original.startLineNumber},${t.original.length} +${t.modified.startLineNumber},${t.modified.length} @@`)),e.appendChild(a),g=e}else g=this._createRow(u,h,this._width.get(),t,r,a,i,o,l);n.appendChild(g);const p=(0,c.un)((e=>this._model.currentElement.read(e)===u));e.add((0,c.fm)((e=>{const t=p.read(e);g.tabIndex=t?0:-1,t&&g.focus()}))),e.add((0,s.ko)(g,"focus",(()=>{this._model.goToLine(u)})))}this._scrollbar.scanDomNode()}_createRow(e,t,i,s,n,r,o,a,c){const l=s.get(146),h=l.glyphMarginWidth+l.lineNumbersWidth,d=o.get(146),u=10+d.glyphMarginWidth+d.lineNumbersWidth;let g="diff-review-row",p="";let m=null;switch(e.type){case j.Added:g="diff-review-row line-insert",p=" char-insert",m=H;break;case j.Deleted:g="diff-review-row line-delete",p=" char-delete",m=B}const f=document.createElement("div");f.style.minWidth=i+"px",f.className=g,f.setAttribute("role","listitem"),f.ariaLevel="";const _=document.createElement("div");_.className="diff-review-cell",_.style.height=`${t}px`,f.appendChild(_);const v=document.createElement("span");v.style.width=h+"px",v.style.minWidth=h+"px",v.className="diff-review-line-number"+p,void 0!==e.originalLineNumber?v.appendChild(document.createTextNode(String(e.originalLineNumber))):v.innerText="\xa0",_.appendChild(v);const C=document.createElement("span");C.style.width=u+"px",C.style.minWidth=u+"px",C.style.paddingRight="10px",C.className="diff-review-line-number"+p,void 0!==e.modifiedLineNumber?C.appendChild(document.createTextNode(String(e.modifiedLineNumber))):C.innerText="\xa0",_.appendChild(C);const b=document.createElement("span");if(b.className="diff-review-spacer",m){const e=document.createElement("span");e.className=E.L.asClassName(m),e.innerText="\xa0\xa0",b.appendChild(e)}else b.innerText="\xa0\xa0";let S;if(_.appendChild(b),void 0!==e.modifiedLineNumber){let t=this._getLineHtml(a,o,c.tabSize,e.modifiedLineNumber,this._languageService.languageIdCodec);V._ttPolicy&&(t=V._ttPolicy.createHTML(t)),_.insertAdjacentHTML("beforeend",t),S=a.getLineContent(e.modifiedLineNumber)}else{let t=this._getLineHtml(n,s,r.tabSize,e.originalLineNumber,this._languageService.languageIdCodec);V._ttPolicy&&(t=V._ttPolicy.createHTML(t)),_.insertAdjacentHTML("beforeend",t),S=n.getLineContent(e.originalLineNumber)}0===S.length&&(S=(0,O.kg)("blankLine","blank"));let y="";switch(e.type){case j.Unchanged:y=e.originalLineNumber===e.modifiedLineNumber?(0,O.kg)({key:"unchangedLine",comment:["The placeholders are contents of the line and should not be translated."]},"{0} unchanged line {1}",S,e.originalLineNumber):(0,O.kg)("equalLine","{0} original line {1} modified line {2}",S,e.originalLineNumber,e.modifiedLineNumber);break;case j.Added:y=(0,O.kg)("insertLine","+ {0} modified line {1}",S,e.modifiedLineNumber);break;case j.Deleted:y=(0,O.kg)("deleteLine","- {0} original line {1}",S,e.originalLineNumber)}return f.setAttribute("aria-label",y),f}_getLineHtml(e,t,i,s,n){const r=e.getLineContent(s),o=t.get(50),a=A.f.createEmpty(r,n),c=I.qL.isBasicASCII(r,e.mightContainNonBasicASCII()),l=I.qL.containsRTL(r,c,e.mightContainRTL());return(0,N.Md)(new N.zL(o.isMonospace&&!t.get(33),o.canUseHalfwidthRightwardsArrow,r,!1,c,l,0,a,[],i,0,o.spaceWidth,o.middotWidth,o.wsmiddotWidth,t.get(118),t.get(100),t.get(95),t.get(51)!==y.Bc.OFF,null)).html}};X=F([U(5,k.L)],X);class Z{constructor(e){this.editors=e}getOriginalModel(){return this.editors.original.getModel()}getOriginalOptions(){return this.editors.original.getOptions()}originalReveal(e){this.editors.original.revealRange(e),this.editors.original.setSelection(e),this.editors.original.focus()}getModifiedModel(){return this.editors.modified.getModel()}getModifiedOptions(){return this.editors.modified.getOptions()}modifiedReveal(e){e&&(this.editors.modified.revealRange(e),this.editors.modified.setSelection(e)),this.editors.modified.focus()}modifiedSetSelection(e){this.editors.modified.setSelection(e)}modifiedFocus(){this.editors.modified.focus()}getModifiedPosition(){return this.editors.modified.getPosition()??void 0}}var J=i(90766),ee=i(631),te=i(10691),ie=i(18447),se=i(94746),ne=i(41127),re=i(26746),oe=i(94650),ae=i(84084),ce=i(82518),le=i(66782),he=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},de=function(e,t){return function(i,s){t(i,s,e)}};let ue=class extends a.jG{setActiveMovedText(e){this._activeMovedText.set(e,void 0)}constructor(e,t,i){super(),this.model=e,this._options=t,this._diffProviderFactoryService=i,this._isDiffUpToDate=(0,c.FY)(this,!1),this.isDiffUpToDate=this._isDiffUpToDate,this._diff=(0,c.FY)(this,void 0),this.diff=this._diff,this._unchangedRegions=(0,c.FY)(this,void 0),this.unchangedRegions=(0,c.un)(this,(e=>this._options.hideUnchangedRegions.read(e)?this._unchangedRegions.read(e)?.regions??[]:((0,c.Rn)((e=>{for(const t of this._unchangedRegions.get()?.regions||[])t.collapseAll(e)})),[]))),this.movedTextToCompare=(0,c.FY)(this,void 0),this._activeMovedText=(0,c.FY)(this,void 0),this._hoveredMovedText=(0,c.FY)(this,void 0),this.activeMovedText=(0,c.un)(this,(e=>this.movedTextToCompare.read(e)??this._hoveredMovedText.read(e)??this._activeMovedText.read(e))),this._cancellationTokenSource=new ie.Qi,this._diffProvider=(0,c.un)(this,(e=>{const t=this._diffProviderFactoryService.createDiffProvider({diffAlgorithm:this._options.diffAlgorithm.read(e)});return{diffProvider:t,onChangeSignal:(0,c.yQ)("onDidChange",t.onDidChange)}})),this._register((0,a.s)((()=>this._cancellationTokenSource.cancel())));const s=(0,c.Yd)("contentChangedSignal"),n=this._register(new J.uC((()=>s.trigger(void 0)),200));this._register((0,c.fm)((t=>{const i=this._unchangedRegions.read(t);if(!i||i.regions.some((e=>e.isDragged.read(t))))return;const s=i.originalDecorationIds.map((t=>e.original.getDecorationRange(t))).map((e=>e?w.M.fromRangeInclusive(e):void 0)),n=i.modifiedDecorationIds.map((t=>e.modified.getDecorationRange(t))).map((e=>e?w.M.fromRangeInclusive(e):void 0)),r=i.regions.map(((e,i)=>s[i]&&n[i]?new me(s[i].startLineNumber,n[i].startLineNumber,s[i].length,e.visibleLineCountTop.read(t),e.visibleLineCountBottom.read(t)):void 0)).filter(ee.O9),o=[];let a=!1;for(const e of(0,v.n)(r,((e,i)=>e.getHiddenModifiedRange(t).endLineNumberExclusive===i.getHiddenModifiedRange(t).startLineNumber)))if(e.length>1){a=!0;const t=e.reduce(((e,t)=>e+t.lineCount),0),i=new me(e[0].originalLineNumber,e[0].modifiedLineNumber,t,e[0].visibleLineCountTop.get(),e[e.length-1].visibleLineCountBottom.get());o.push(i)}else o.push(e[0]);if(a){const t=e.original.deltaDecorations(i.originalDecorationIds,o.map((e=>({range:e.originalUnchangedRange.toInclusiveRange(),options:{description:"unchanged"}})))),s=e.modified.deltaDecorations(i.modifiedDecorationIds,o.map((e=>({range:e.modifiedUnchangedRange.toInclusiveRange(),options:{description:"unchanged"}}))));(0,c.Rn)((e=>{this._unchangedRegions.set({regions:o,originalDecorationIds:t,modifiedDecorationIds:s},e)}))}})));const r=(t,i,s)=>{const n=me.fromDiffs(t.changes,e.original.getLineCount(),e.modified.getLineCount(),this._options.hideUnchangedRegionsMinimumLineCount.read(s),this._options.hideUnchangedRegionsContextLineCount.read(s));let r;const o=this._unchangedRegions.get();if(o){const t=o.originalDecorationIds.map((t=>e.original.getDecorationRange(t))).map((e=>e?w.M.fromRangeInclusive(e):void 0)),i=o.modifiedDecorationIds.map((t=>e.modified.getDecorationRange(t))).map((e=>e?w.M.fromRangeInclusive(e):void 0));let n=(0,S.EK)(o.regions.map(((e,s)=>{if(!t[s]||!i[s])return;const n=t[s].length;return new me(t[s].startLineNumber,i[s].startLineNumber,n,Math.min(e.visibleLineCountTop.get(),n),Math.min(e.visibleLineCountBottom.get(),n-e.visibleLineCountTop.get()))})).filter(ee.O9),((e,t)=>!t||e.modifiedLineNumber>=t.modifiedLineNumber+t.lineCount&&e.originalLineNumber>=t.originalLineNumber+t.lineCount)).map((e=>new x.WL(e.getHiddenOriginalRange(s),e.getHiddenModifiedRange(s))));n=x.WL.clip(n,w.M.ofLength(1,e.original.getLineCount()),w.M.ofLength(1,e.modified.getLineCount())),r=x.WL.inverse(n,e.original.getLineCount(),e.modified.getLineCount())}const a=[];if(r)for(const e of n){const t=r.filter((t=>t.original.intersectsStrict(e.originalUnchangedRange)&&t.modified.intersectsStrict(e.modifiedUnchangedRange)));a.push(...e.setVisibleRanges(t,i))}else a.push(...n);const c=e.original.deltaDecorations(o?.originalDecorationIds||[],a.map((e=>({range:e.originalUnchangedRange.toInclusiveRange(),options:{description:"unchanged"}})))),l=e.modified.deltaDecorations(o?.modifiedDecorationIds||[],a.map((e=>({range:e.modifiedUnchangedRange.toInclusiveRange(),options:{description:"unchanged"}}))));this._unchangedRegions.set({regions:a,originalDecorationIds:c,modifiedDecorationIds:l},i)};this._register(e.modified.onDidChangeContent((t=>{if(this._diff.get()){const i=oe.c.fromModelContentChanges(t.changes),s=_e(this._lastDiff,i,e.original,e.modified);s&&(this._lastDiff=s,(0,c.Rn)((e=>{this._diff.set(ge.fromDiffResult(this._lastDiff),e),r(s,e);const t=this.movedTextToCompare.get();this.movedTextToCompare.set(t?this._lastDiff.moves.find((e=>e.lineRangeMapping.modified.intersect(t.lineRangeMapping.modified))):void 0,e)})))}this._isDiffUpToDate.set(!1,void 0),n.schedule()}))),this._register(e.original.onDidChangeContent((t=>{if(this._diff.get()){const i=oe.c.fromModelContentChanges(t.changes),s=fe(this._lastDiff,i,e.original,e.modified);s&&(this._lastDiff=s,(0,c.Rn)((e=>{this._diff.set(ge.fromDiffResult(this._lastDiff),e),r(s,e);const t=this.movedTextToCompare.get();this.movedTextToCompare.set(t?this._lastDiff.moves.find((e=>e.lineRangeMapping.modified.intersect(t.lineRangeMapping.modified))):void 0,e)})))}this._isDiffUpToDate.set(!1,void 0),n.schedule()}))),this._register((0,c.yC)((async(t,i)=>{this._options.hideUnchangedRegionsMinimumLineCount.read(t),this._options.hideUnchangedRegionsContextLineCount.read(t),n.cancel(),s.read(t);const o=this._diffProvider.read(t);o.onChangeSignal.read(t),(0,ne.b)(re.D8,t),(0,ne.b)(ce.NC,t),this._isDiffUpToDate.set(!1,void 0);let a=[];i.add(e.original.onDidChangeContent((e=>{const t=oe.c.fromModelContentChanges(e.changes);a=(0,ae.M)(a,t)})));let l=[];i.add(e.modified.onDidChangeContent((e=>{const t=oe.c.fromModelContentChanges(e.changes);l=(0,ae.M)(l,t)})));let h=await o.diffProvider.computeDiff(e.original,e.modified,{ignoreTrimWhitespace:this._options.ignoreTrimWhitespace.read(t),maxComputationTimeMs:this._options.maxComputationTimeMs.read(t),computeMoves:this._options.showMoves.read(t)},this._cancellationTokenSource.token);var d,u,g;this._cancellationTokenSource.token.isCancellationRequested||(e.original.isDisposed()||e.modified.isDisposed()||(d=h,u=e.original,g=e.modified,h={changes:d.changes.map((e=>new x.wm(e.original,e.modified,e.innerChanges?e.innerChanges.map((e=>function(e,t,i){let s=e.originalRange,n=e.modifiedRange;return 1===s.startColumn&&1===n.startColumn&&(1!==s.endColumn||1!==n.endColumn)&&s.endColumn===t.getLineMaxColumn(s.endLineNumber)&&n.endColumn===i.getLineMaxColumn(n.endLineNumber)&&s.endLineNumber{r(h,e),this._lastDiff=h;const t=ge.fromDiffResult(h);this._diff.set(t,e),this._isDiffUpToDate.set(!0,e);const i=this.movedTextToCompare.get();this.movedTextToCompare.set(i?this._lastDiff.moves.find((e=>e.lineRangeMapping.modified.intersect(i.lineRangeMapping.modified))):void 0,e)}))))})))}ensureModifiedLineIsVisible(e,t,i){if(0===this.diff.get()?.mappings.length)return;const s=this._unchangedRegions.get()?.regions||[];for(const n of s)if(n.getHiddenModifiedRange(void 0).contains(e))return void n.showModifiedLine(e,t,i)}ensureOriginalLineIsVisible(e,t,i){if(0===this.diff.get()?.mappings.length)return;const s=this._unchangedRegions.get()?.regions||[];for(const n of s)if(n.getHiddenOriginalRange(void 0).contains(e))return void n.showOriginalLine(e,t,i)}async waitForDiff(){await(0,c.oJ)(this.isDiffUpToDate,(e=>e))}serializeState(){const e=this._unchangedRegions.get();return{collapsedRegions:e?.regions.map((e=>({range:e.getHiddenModifiedRange(void 0).serialize()})))}}restoreSerializedState(e){const t=e.collapsedRegions?.map((e=>w.M.deserialize(e.range))),i=this._unchangedRegions.get();i&&t&&(0,c.Rn)((e=>{for(const s of i.regions)for(const i of t)if(s.modifiedUnchangedRange.intersect(i)){s.setHiddenModifiedRange(i,e);break}}))}};ue=he([de(2,se.Hg)],ue);class ge{static fromDiffResult(e){return new ge(e.changes.map((e=>new pe(e))),e.moves||[],e.identical,e.quitEarly)}constructor(e,t,i,s){this.mappings=e,this.movedTexts=t,this.identical=i,this.quitEarly=s}}class pe{constructor(e){this.lineRangeMapping=e}}class me{static fromDiffs(e,t,i,s,n){const r=x.wm.inverse(e,t,i),o=[];for(const a of r){let e=a.original.startLineNumber,r=a.modified.startLineNumber,c=a.original.length;const l=1===e&&1===r,h=e+c===t+1&&r+c===i+1;(l||h)&&c>=n+s?(l&&!h&&(c-=n),h&&!l&&(e+=n,r+=n,c-=n),o.push(new me(e,r,c,0,0))):c>=2*n+s&&(e+=n,r+=n,c-=2*n,o.push(new me(e,r,c,0,0)))}return o}get originalUnchangedRange(){return w.M.ofLength(this.originalLineNumber,this.lineCount)}get modifiedUnchangedRange(){return w.M.ofLength(this.modifiedLineNumber,this.lineCount)}constructor(e,t,i,s,n){this.originalLineNumber=e,this.modifiedLineNumber=t,this.lineCount=i,this._visibleLineCountTop=(0,c.FY)(this,0),this.visibleLineCountTop=this._visibleLineCountTop,this._visibleLineCountBottom=(0,c.FY)(this,0),this.visibleLineCountBottom=this._visibleLineCountBottom,this._shouldHideControls=(0,c.un)(this,(e=>this.visibleLineCountTop.read(e)+this.visibleLineCountBottom.read(e)===this.lineCount&&!this.isDragged.read(e))),this.isDragged=(0,c.FY)(this,void 0);const r=Math.max(Math.min(s,this.lineCount),0),o=Math.max(Math.min(n,this.lineCount-s),0);(0,le.V7)(s===r),(0,le.V7)(n===o),this._visibleLineCountTop.set(r,void 0),this._visibleLineCountBottom.set(o,void 0)}setVisibleRanges(e,t){const i=[],s=new w.S(e.map((e=>e.modified))).subtractFrom(this.modifiedUnchangedRange);let n=this.originalLineNumber,r=this.modifiedLineNumber;const o=this.modifiedLineNumber+this.lineCount;if(0===s.ranges.length)this.showAll(t),i.push(this);else{let e=0;for(const a of s.ranges){const c=e===s.ranges.length-1;e++;const l=(c?o:a.endLineNumberExclusive)-r,h=new me(n,r,l,0,0);h.setHiddenModifiedRange(a,t),i.push(h),n=h.originalUnchangedRange.endLineNumberExclusive,r=h.modifiedUnchangedRange.endLineNumberExclusive}}return i}shouldHideControls(e){return this._shouldHideControls.read(e)}getHiddenOriginalRange(e){return w.M.ofLength(this.originalLineNumber+this._visibleLineCountTop.read(e),this.lineCount-this._visibleLineCountTop.read(e)-this._visibleLineCountBottom.read(e))}getHiddenModifiedRange(e){return w.M.ofLength(this.modifiedLineNumber+this._visibleLineCountTop.read(e),this.lineCount-this._visibleLineCountTop.read(e)-this._visibleLineCountBottom.read(e))}setHiddenModifiedRange(e,t){const i=e.startLineNumber-this.modifiedLineNumber,s=this.modifiedLineNumber+this.lineCount-e.endLineNumberExclusive;this.setState(i,s,t)}getMaxVisibleLineCountTop(){return this.lineCount-this._visibleLineCountBottom.get()}getMaxVisibleLineCountBottom(){return this.lineCount-this._visibleLineCountTop.get()}showMoreAbove(e=10,t){const i=this.getMaxVisibleLineCountTop();this._visibleLineCountTop.set(Math.min(this._visibleLineCountTop.get()+e,i),t)}showMoreBelow(e=10,t){const i=this.lineCount-this._visibleLineCountTop.get();this._visibleLineCountBottom.set(Math.min(this._visibleLineCountBottom.get()+e,i),t)}showAll(e){this._visibleLineCountBottom.set(this.lineCount-this._visibleLineCountTop.get(),e)}showModifiedLine(e,t,i){const s=e+1-(this.modifiedLineNumber+this._visibleLineCountTop.get()),n=this.modifiedLineNumber-this._visibleLineCountBottom.get()+this.lineCount-e;0===t&&s{this._contextMenuService.showContextMenu({domForShadowRoot:u?i.getDomNode()??void 0:void 0,getAnchor:()=>({x:e,y:t}),getActions:()=>{const e=[],t=n.modified.isEmpty;e.push(new _.rc("diff.clipboard.copyDeletedContent",t?n.original.length>1?(0,O.kg)("diff.clipboard.copyDeletedLinesContent.label","Copy deleted lines"):(0,O.kg)("diff.clipboard.copyDeletedLinesContent.single.label","Copy deleted line"):n.original.length>1?(0,O.kg)("diff.clipboard.copyChangedLinesContent.label","Copy changed lines"):(0,O.kg)("diff.clipboard.copyChangedLinesContent.single.label","Copy changed line"),void 0,!0,(async()=>{const e=this._originalTextModel.getValueInRange(n.original.toExclusiveRange());await this._clipboardService.writeText(e)}))),n.original.length>1&&e.push(new _.rc("diff.clipboard.copyDeletedLineContent",t?(0,O.kg)("diff.clipboard.copyDeletedLineContent.label","Copy deleted line ({0})",n.original.startLineNumber+d):(0,O.kg)("diff.clipboard.copyChangedLineContent.label","Copy changed line ({0})",n.original.startLineNumber+d),void 0,!0,(async()=>{let e=this._originalTextModel.getLineContent(n.original.startLineNumber+d);if(""===e){e=0===this._originalTextModel.getEndOfLineSequence()?"\n":"\r\n"}await this._clipboardService.writeText(e)})));return i.getOption(92)||e.push(new _.rc("diff.inline.revertChange",(0,O.kg)("diff.inline.revertChange.label","Revert this change"),void 0,!0,(async()=>{this._editor.revert(this._diff)}))),e},autoSelectFirstItem:!0})};this._register((0,s.b2)(this._diffActions,"mousedown",(e=>{if(!e.leftButton)return;const{top:t,height:i}=(0,s.BK)(this._diffActions),n=Math.floor(h/3);e.preventDefault(),g(e.posx,t+i+n)}))),this._register(i.onMouseMove((e=>{8!==e.target.type&&5!==e.target.type||e.target.detail.viewZoneId!==this._getViewZoneId()?this.visibility=!1:(d=this._updateLightBulbPosition(this._marginDomNode,e.event.browserEvent.y,h),this.visibility=!0)}))),this._register(i.onMouseDown((e=>{if(e.event.leftButton&&(8===e.target.type||5===e.target.type)){e.target.detail.viewZoneId===this._getViewZoneId()&&(e.event.preventDefault(),d=this._updateLightBulbPosition(this._marginDomNode,e.event.browserEvent.y,h),g(e.event.posx,e.event.posy+h))}})))}_updateLightBulbPosition(e,t,i){const{top:n}=(0,s.BK)(e),r=t-n,o=Math.floor(r/i),a=o*i;if(this._diffActions.style.top=`${a}px`,this._viewLineCounts){let e=0;for(let t=0;te});function ye(e,t,i,s){(0,b.M)(s,t.fontInfo);const n=i.length>0,r=new Ee.fe(1e4);let o=0,a=0;const c=[];for(let d=0;d');const c=t.getLineContent(),l=I.qL.isBasicASCII(c,n),h=I.qL.containsRTL(c,l,r),d=(0,N.UW)(new N.zL(o.fontInfo.isMonospace&&!o.disableMonospaceOptimizations,o.fontInfo.canUseHalfwidthRightwardsArrow,c,!1,l,h,0,t,i,o.tabSize,0,o.fontInfo.spaceWidth,o.fontInfo.middotWidth,o.fontInfo.wsmiddotWidth,o.stopRenderingLineAfter,o.renderWhitespace,o.renderControlCharacters,o.fontLigatures!==y.Bc.OFF,null),a);return a.appendString(""),d.characterMapping.getHorizontalOffset(d.characterMapping.length)}var Te=i(54770),xe=i(47508),ke=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},Ae=function(e,t){return function(i,s){t(i,s,e)}};let Ne=class extends a.jG{constructor(e,t,i,n,r,o,l,h,d,u){super(),this._targetWindow=e,this._editors=t,this._diffModel=i,this._options=n,this._diffEditorWidget=r,this._canIgnoreViewZoneUpdateEvent=o,this._origViewZonesToIgnore=l,this._modViewZonesToIgnore=h,this._clipboardService=d,this._contextMenuService=u,this._originalTopPadding=(0,c.FY)(this,0),this._originalScrollOffset=(0,c.FY)(this,0),this._originalScrollOffsetAnimated=(0,S.Nu)(this._targetWindow,this._originalScrollOffset,this._store),this._modifiedTopPadding=(0,c.FY)(this,0),this._modifiedScrollOffset=(0,c.FY)(this,0),this._modifiedScrollOffsetAnimated=(0,S.Nu)(this._targetWindow,this._modifiedScrollOffset,this._store);const g=(0,c.FY)("invalidateAlignmentsState",0),p=this._register(new J.uC((()=>{g.set(g.get()+1,void 0)}),0));this._register(this._editors.original.onDidChangeViewZones((e=>{this._canIgnoreViewZoneUpdateEvent()||p.schedule()}))),this._register(this._editors.modified.onDidChangeViewZones((e=>{this._canIgnoreViewZoneUpdateEvent()||p.schedule()}))),this._register(this._editors.original.onDidChangeConfiguration((e=>{(e.hasChanged(147)||e.hasChanged(67))&&p.schedule()}))),this._register(this._editors.modified.onDidChangeConfiguration((e=>{(e.hasChanged(147)||e.hasChanged(67))&&p.schedule()})));const m=this._diffModel.map((e=>e?(0,c.y0)(this,e.model.original.onDidChangeTokens,(()=>2===e.model.original.tokenization.backgroundTokenizationState)):void 0)).map(((e,t)=>e?.read(t))),f=(0,c.un)((e=>{const t=this._diffModel.read(e),i=t?.diff.read(e);if(!t||!i)return null;g.read(e);const s=this._options.renderSideBySide.read(e);return Ie(this._editors.original,this._editors.modified,i.mappings,this._origViewZonesToIgnore,this._modViewZonesToIgnore,s)})),_=(0,c.un)((e=>{const t=this._diffModel.read(e)?.movedTextToCompare.read(e);if(!t)return null;g.read(e);const i=t.changes.map((e=>new pe(e)));return Ie(this._editors.original,this._editors.modified,i,this._origViewZonesToIgnore,this._modViewZonesToIgnore,!0)}));function v(){const e=document.createElement("div");return e.className="diagonal-fill",e}const y=this._register(new a.Cm);this.viewZones=(0,c.rm)(this,((e,t)=>{y.clear();const i=f.read(e)||[],n=[],o=[],a=this._modifiedTopPadding.read(e);a>0&&o.push({afterLineNumber:0,domNode:document.createElement("div"),heightInPx:a,showInHiddenAreas:!0,suppressMouseDown:!0});const c=this._originalTopPadding.read(e);c>0&&n.push({afterLineNumber:0,domNode:document.createElement("div"),heightInPx:c,showInHiddenAreas:!0,suppressMouseDown:!0});const l=this._options.renderSideBySide.read(e),h=l?void 0:this._editors.modified._getViewModel()?.createLineBreaksComputer();if(h){const L=this._editors.original.getModel();for(const T of i)if(T.diff)for(let x=T.originalRange.startLineNumber;xL.getLineCount())return{orig:n,mod:o};h?.addRequest(L.getLineContent(x),null,null)}}const d=h?.finalize()??[];let u=0;const g=this._editors.modified.getOption(67),p=this._diffModel.read(e)?.movedTextToCompare.read(e),S=this._editors.original.getModel()?.mightContainNonBasicASCII()??!1,w=this._editors.original.getModel()?.mightContainRTL()??!1,R=Re.fromEditor(this._editors.modified);for(const k of i)if(!k.diff||l||this._options.useTrueInlineDiffRendering.read(e)&&De(k.diff)){const A=k.modifiedHeightInPx-k.originalHeightInPx;if(A>0){if(p?.lineRangeMapping.original.delta(-1).deltaLength(2).contains(k.originalRange.endLineNumberExclusive-1))continue;n.push({afterLineNumber:k.originalRange.endLineNumberExclusive-1,domNode:v(),heightInPx:A,showInHiddenAreas:!0,suppressMouseDown:!0})}else{if(p?.lineRangeMapping.modified.delta(-1).deltaLength(2).contains(k.modifiedRange.endLineNumberExclusive-1))continue;function N(){const e=document.createElement("div");return e.className="arrow-revert-change "+E.L.asClassName(C.W.arrowRight),t.add((0,s.ko)(e,"mousedown",(e=>e.stopPropagation()))),t.add((0,s.ko)(e,"click",(e=>{e.stopPropagation(),r.revert(k.diff)}))),(0,s.$)("div",{},e)}let O;k.diff&&k.diff.modified.isEmpty&&this._options.shouldRenderOldRevertArrows.read(e)&&(O=N()),o.push({afterLineNumber:k.modifiedRange.endLineNumberExclusive-1,domNode:v(),heightInPx:-A,marginDomNode:O,showInHiddenAreas:!0,suppressMouseDown:!0})}}else{if(!k.originalRange.isEmpty){m.read(e);const M=document.createElement("div");M.classList.add("view-lines","line-delete","monaco-mouse-cursor-text");const P=this._editors.original.getModel();if(k.originalRange.endLineNumberExclusive-1>P.getLineCount())return{orig:n,mod:o};const F=new we(k.originalRange.mapToLineArray((e=>P.tokenization.getLineTokens(e))),k.originalRange.mapToLineArray((e=>d[u++])),S,w),U=[];for(const V of k.diff.innerChanges||[])U.push(new I.kI(V.originalRange.delta(-(k.diff.original.startLineNumber-1)),te.Zb.className,0));const H=ye(F,R,U,M),B=document.createElement("div");if(B.className="inline-deleted-margin-view-zone",(0,b.M)(B,R.fontInfo),this._options.renderIndicators.read(e))for(let z=0;z(0,ee.eU)(W)),B,this._editors.modified,k.diff,this._diffEditorWidget,H.viewLineCounts,this._editors.original.getModel(),this._contextMenuService,this._clipboardService));for(let j=0;j1&&n.push({afterLineNumber:k.originalRange.startLineNumber+j,domNode:v(),heightInPx:(K-1)*g,showInHiddenAreas:!0,suppressMouseDown:!0})}o.push({afterLineNumber:k.modifiedRange.startLineNumber-1,domNode:M,heightInPx:H.heightInLines*g,minWidthInPx:H.minWidthInPx,marginDomNode:B,setZoneId(e){W=e},showInHiddenAreas:!0,suppressMouseDown:!0})}const D=document.createElement("div");D.className="gutter-delete",n.push({afterLineNumber:k.originalRange.endLineNumberExclusive-1,domNode:v(),heightInPx:k.modifiedHeightInPx,marginDomNode:D,showInHiddenAreas:!0,suppressMouseDown:!0})}for(const Y of _.read(e)??[]){if(!p?.lineRangeMapping.original.intersect(Y.originalRange)||!p?.lineRangeMapping.modified.intersect(Y.modifiedRange))continue;const q=Y.modifiedHeightInPx-Y.originalHeightInPx;q>0?n.push({afterLineNumber:Y.originalRange.endLineNumberExclusive-1,domNode:v(),heightInPx:q,showInHiddenAreas:!0,suppressMouseDown:!0}):o.push({afterLineNumber:Y.modifiedRange.endLineNumberExclusive-1,domNode:v(),heightInPx:-q,showInHiddenAreas:!0,suppressMouseDown:!0})}return{orig:n,mod:o}}));let w=!1;this._register(this._editors.original.onDidScrollChange((e=>{e.scrollLeftChanged&&!w&&(w=!0,this._editors.modified.setScrollLeft(e.scrollLeft),w=!1)}))),this._register(this._editors.modified.onDidScrollChange((e=>{e.scrollLeftChanged&&!w&&(w=!0,this._editors.original.setScrollLeft(e.scrollLeft),w=!1)}))),this._originalScrollTop=(0,c.y0)(this._editors.original.onDidScrollChange,(()=>this._editors.original.getScrollTop())),this._modifiedScrollTop=(0,c.y0)(this._editors.modified.onDidScrollChange,(()=>this._editors.modified.getScrollTop())),this._register((0,c.fm)((e=>{const t=this._originalScrollTop.read(e)-(this._originalScrollOffsetAnimated.get()-this._modifiedScrollOffsetAnimated.read(e))-(this._originalTopPadding.get()-this._modifiedTopPadding.read(e));t!==this._editors.modified.getScrollTop()&&this._editors.modified.setScrollTop(t,1)}))),this._register((0,c.fm)((e=>{const t=this._modifiedScrollTop.read(e)-(this._modifiedScrollOffsetAnimated.get()-this._originalScrollOffsetAnimated.read(e))-(this._modifiedTopPadding.get()-this._originalTopPadding.read(e));t!==this._editors.original.getScrollTop()&&this._editors.original.setScrollTop(t,1)}))),this._register((0,c.fm)((e=>{const t=this._diffModel.read(e)?.movedTextToCompare.read(e);let i=0;if(t){const e=this._editors.original.getTopForLineNumber(t.lineRangeMapping.original.startLineNumber,!0)-this._originalTopPadding.get();i=this._editors.modified.getTopForLineNumber(t.lineRangeMapping.modified.startLineNumber,!0)-this._modifiedTopPadding.get()-e}i>0?(this._modifiedTopPadding.set(0,void 0),this._originalTopPadding.set(i,void 0)):i<0?(this._modifiedTopPadding.set(-i,void 0),this._originalTopPadding.set(0,void 0)):setTimeout((()=>{this._modifiedTopPadding.set(0,void 0),this._originalTopPadding.set(0,void 0)}),400),this._editors.modified.hasTextFocus()?this._originalScrollOffset.set(this._modifiedScrollOffset.get()-i,void 0,!0):this._modifiedScrollOffset.set(this._originalScrollOffset.get()+i,void 0,!0)})))}};function Ie(e,t,i,s,n,r){const o=new v.j3(Oe(e,s)),a=new v.j3(Oe(t,n)),c=e.getOption(67),l=t.getOption(67),h=[];let d=0,u=0;function g(e,t){for(;;){let i=o.peek(),s=a.peek();if(i&&i.lineNumber>=e&&(i=void 0),s&&s.lineNumber>=t&&(s=void 0),!i&&!s)break;const n=i?i.lineNumber-d:Number.MAX_VALUE,r=s?s.lineNumber-u:Number.MAX_VALUE;nr?(a.dequeue(),i={lineNumber:s.lineNumber-u+d,heightInPx:0}):(o.dequeue(),a.dequeue()),h.push({originalRange:w.M.ofLength(i.lineNumber,1),modifiedRange:w.M.ofLength(s.lineNumber,1),originalHeightInPx:c+i.heightInPx,modifiedHeightInPx:l+s.heightInPx,diff:void 0})}}for(const p of i){const m=p.lineRangeMapping;g(m.original.startLineNumber,m.modified.startLineNumber);let f=!0,_=m.modified.startLineNumber,C=m.original.startLineNumber;function E(e,t,i=!1){if(et.lineNumbere+t.heightInPx),0)??0,d=a.takeWhile((e=>e.lineNumbere+t.heightInPx),0)??0;h.push({originalRange:s,modifiedRange:n,originalHeightInPx:s.length*c+r,modifiedHeightInPx:n.length*l+d,diff:p.lineRangeMapping}),C=e,_=t}if(r)for(const b of m.innerChanges||[]){b.originalRange.startColumn>1&&b.modifiedRange.startColumn>1&&E(b.originalRange.startLineNumber,b.modifiedRange.startLineNumber);const S=e.getModel(),y=b.originalRange.endLineNumber<=S.getLineCount()?S.getLineMaxColumn(b.originalRange.endLineNumber):Number.MAX_SAFE_INTEGER;b.originalRange.endColumn1&&s.push({lineNumber:a,heightInPx:o*(e-1)})}for(const a of e.getWhitespaces()){if(t.has(a.id))continue;const e=0===a.afterLineNumber?0:r.convertViewPositionToModelPosition(new L.y(a.afterLineNumber,1)).lineNumber;i.push({lineNumber:e,heightInPx:a.height})}return(0,S.Am)(i,s,(e=>e.lineNumber),((e,t)=>({lineNumber:e.lineNumber,heightInPx:e.heightInPx+t.heightInPx})))}function De(e){return!!e.innerChanges&&e.innerChanges.every((e=>Me(e.modifiedRange)&&Me(e.originalRange)||e.originalRange.equalsRange(new T.Q(1,1,1,1))))}function Me(e){return e.startLineNumber===e.endLineNumber}Ne=ke([Ae(8,Te.h),Ae(9,xe.Z)],Ne);class Pe extends a.jG{static{this.movedCodeBlockPadding=4}constructor(e,t,i,s,n){super(),this._rootElement=e,this._diffModel=t,this._originalEditorLayoutInfo=i,this._modifiedEditorLayoutInfo=s,this._editors=n,this._originalScrollTop=(0,c.y0)(this,this._editors.original.onDidScrollChange,(()=>this._editors.original.getScrollTop())),this._modifiedScrollTop=(0,c.y0)(this,this._editors.modified.onDidScrollChange,(()=>this._editors.modified.getScrollTop())),this._viewZonesChanged=(0,c.yQ)("onDidChangeViewZones",this._editors.modified.onDidChangeViewZones),this.width=(0,c.FY)(this,0),this._modifiedViewZonesChangedSignal=(0,c.yQ)("modified.onDidChangeViewZones",this._editors.modified.onDidChangeViewZones),this._originalViewZonesChangedSignal=(0,c.yQ)("original.onDidChangeViewZones",this._editors.original.onDidChangeViewZones),this._state=(0,c.rm)(this,((e,t)=>{this._element.replaceChildren();const i=this._diffModel.read(e),s=i?.diff.read(e)?.movedTexts;if(!s||0===s.length)return void this.width.set(0,void 0);this._viewZonesChanged.read(e);const n=this._originalEditorLayoutInfo.read(e),r=this._modifiedEditorLayoutInfo.read(e);if(!n||!r)return void this.width.set(0,void 0);this._modifiedViewZonesChangedSignal.read(e),this._originalViewZonesChangedSignal.read(e);const o=s.map((t=>{function i(e,t){return(t.getTopForLineNumber(e.startLineNumber,!0)+t.getTopForLineNumber(e.endLineNumberExclusive,!0))/2}const s=i(t.lineRangeMapping.original,this._editors.original),n=this._originalScrollTop.read(e),r=i(t.lineRangeMapping.modified,this._editors.modified),o=s-n,a=r-this._modifiedScrollTop.read(e),c=Math.min(s,r),l=Math.max(s,r);return{range:new R.L(c,l),from:o,to:a,fromWithoutScroll:s,toWithoutScroll:r,move:t}}));o.sort((0,v.nH)((0,v.VE)((e=>e.fromWithoutScroll>e.toWithoutScroll),v.TS),(0,v.VE)((e=>e.fromWithoutScroll>e.toWithoutScroll?e.fromWithoutScroll:-e.toWithoutScroll),v.U9)));const a=Fe.compute(o.map((e=>e.range))),l=n.verticalScrollbarWidth,h=10*(a.getTrackCount()-1)+20,d=l+h+(r.contentLeft-Pe.movedCodeBlockPadding);let u=0;for(const g of o){const e=l+10+10*a.getTrack(u),s=15,n=15,o=d,h=r.glyphMarginWidth+r.lineNumbersWidth,p=18,m=document.createElementNS("http://www.w3.org/2000/svg","rect");m.classList.add("arrow-rectangle"),m.setAttribute("x",""+(o-h)),m.setAttribute("y",""+(g.to-p/2)),m.setAttribute("width",`${h}`),m.setAttribute("height",`${p}`),this._element.appendChild(m);const f=document.createElementNS("http://www.w3.org/2000/svg","g"),_=document.createElementNS("http://www.w3.org/2000/svg","path");_.setAttribute("d",`M 0 ${g.from} L ${e} ${g.from} L ${e} ${g.to} L ${o-n} ${g.to}`),_.setAttribute("fill","none"),f.appendChild(_);const v=document.createElementNS("http://www.w3.org/2000/svg","polygon");v.classList.add("arrow"),t.add((0,c.fm)((e=>{_.classList.toggle("currentMove",g.move===i.activeMovedText.read(e)),v.classList.toggle("currentMove",g.move===i.activeMovedText.read(e))}))),v.setAttribute("points",`${o-n},${g.to-s/2} ${o},${g.to} ${o-n},${g.to+s/2}`),f.appendChild(v),this._element.appendChild(f),u++}this.width.set(h,void 0)})),this._element=document.createElementNS("http://www.w3.org/2000/svg","svg"),this._element.setAttribute("class","moved-blocks-lines"),this._rootElement.appendChild(this._element),this._register((0,a.s)((()=>this._element.remove()))),this._register((0,c.fm)((e=>{const t=this._originalEditorLayoutInfo.read(e),i=this._modifiedEditorLayoutInfo.read(e);t&&i&&(this._element.style.left=t.width-t.verticalScrollbarWidth+"px",this._element.style.height=`${t.height}px`,this._element.style.width=`${t.verticalScrollbarWidth+t.contentLeft-Pe.movedCodeBlockPadding+this.width.read(e)}px`)}))),this._register((0,c.OI)(this._state));const r=(0,c.un)((e=>{const t=this._diffModel.read(e),i=t?.diff.read(e);return i?i.movedTexts.map((e=>({move:e,original:new S.D1((0,c.lk)(e.lineRangeMapping.original.startLineNumber-1),18),modified:new S.D1((0,c.lk)(e.lineRangeMapping.modified.startLineNumber-1),18)}))):[]}));this._register((0,S.Vs)(this._editors.original,r.map((e=>e.map((e=>e.original)))))),this._register((0,S.Vs)(this._editors.modified,r.map((e=>e.map((e=>e.modified)))))),this._register((0,c.yC)(((e,t)=>{const i=r.read(e);for(const s of i)t.add(new Ue(this._editors.original,s.original,s.move,"original",this._diffModel.get())),t.add(new Ue(this._editors.modified,s.modified,s.move,"modified",this._diffModel.get()))})));const o=(0,c.yQ)("original.onDidFocusEditorWidget",(e=>this._editors.original.onDidFocusEditorWidget((()=>setTimeout((()=>e(void 0)),0))))),l=(0,c.yQ)("modified.onDidFocusEditorWidget",(e=>this._editors.modified.onDidFocusEditorWidget((()=>setTimeout((()=>e(void 0)),0)))));let h="modified";this._register((0,c.Y)({createEmptyChangeSummary:()=>{},handleChange:(e,t)=>(e.didChange(o)&&(h="original"),e.didChange(l)&&(h="modified"),!0)},(e=>{o.read(e),l.read(e);const t=this._diffModel.read(e);if(!t)return;const i=t.diff.read(e);let s;if(i&&"original"===h){const t=this._editors.originalCursor.read(e);t&&(s=i.movedTexts.find((e=>e.lineRangeMapping.original.contains(t.lineNumber))))}if(i&&"modified"===h){const t=this._editors.modifiedCursor.read(e);t&&(s=i.movedTexts.find((e=>e.lineRangeMapping.modified.contains(t.lineNumber))))}s!==t.movedTextToCompare.get()&&t.movedTextToCompare.set(void 0,void 0),t.setActiveMovedText(s)})))}}class Fe{static compute(e){const t=[],i=[];for(const s of e){let e=t.findIndex((e=>!e.intersectsStrict(s)));if(-1===e){const i=6;t.length>=i?e=(0,n.TM)(t,(0,v.VE)((e=>e.intersectWithRangeLength(s)),v.U9)):(e=t.length,t.push(new R.h))}t[e].addRange(s),i.push(e)}return new Fe(t.length,i)}constructor(e,t){this._trackCount=e,this.trackPerLineIdx=t}getTrack(e){return this.trackPerLineIdx[e]}getTrackCount(){return this._trackCount}}class Ue extends S.uN{constructor(e,t,i,n,r){const o=(0,s.h)("div.diff-hidden-lines-widget");super(e,t,o.root),this._editor=e,this._move=i,this._kind=n,this._diffModel=r,this._nodes=(0,s.h)("div.diff-moved-code-block",{style:{marginRight:"4px"}},[(0,s.h)("div.text-content@textContent"),(0,s.h)("div.action-bar@actionBar")]),o.root.appendChild(this._nodes.root);const a=(0,c.y0)(this._editor.onDidLayoutChange,(()=>this._editor.getLayoutInfo()));let l;this._register((0,S.AV)(this._nodes.root,{paddingRight:a.map((e=>e.verticalScrollbarWidth))})),l=i.changes.length>0?"original"===this._kind?(0,O.kg)("codeMovedToWithChanges","Code moved with changes to line {0}-{1}",this._move.lineRangeMapping.modified.startLineNumber,this._move.lineRangeMapping.modified.endLineNumberExclusive-1):(0,O.kg)("codeMovedFromWithChanges","Code moved with changes from line {0}-{1}",this._move.lineRangeMapping.original.startLineNumber,this._move.lineRangeMapping.original.endLineNumberExclusive-1):"original"===this._kind?(0,O.kg)("codeMovedTo","Code moved to line {0}-{1}",this._move.lineRangeMapping.modified.startLineNumber,this._move.lineRangeMapping.modified.endLineNumberExclusive-1):(0,O.kg)("codeMovedFrom","Code moved from line {0}-{1}",this._move.lineRangeMapping.original.startLineNumber,this._move.lineRangeMapping.original.endLineNumberExclusive-1);const h=this._register(new m.E(this._nodes.actionBar,{highlightToggledItems:!0})),d=new _.rc("",l,"",!1);h.push(d,{icon:!1,label:!0});const u=new _.rc("","Compare",E.L.asClassName(C.W.compareChanges),!0,(()=>{this._editor.focus(),this._diffModel.movedTextToCompare.set(this._diffModel.movedTextToCompare.get()===i?void 0:this._move,void 0)}));this._register((0,c.fm)((e=>{const t=this._diffModel.movedTextToCompare.read(e)===i;u.checked=t}))),h.push(u,{icon:!1,label:!0})}}class He extends a.jG{constructor(e,t,i,s){super(),this._editors=e,this._diffModel=t,this._options=i,this._decorations=(0,c.un)(this,(e=>{const t=this._diffModel.read(e),i=t?.diff.read(e);if(!i)return null;const s=this._diffModel.read(e).movedTextToCompare.read(e),n=this._options.renderIndicators.read(e),r=this._options.showEmptyDecorations.read(e),o=[],a=[];if(!s)for(const l of i.mappings)if(l.lineRangeMapping.original.isEmpty||o.push({range:l.lineRangeMapping.original.toInclusiveRange(),options:n?te.Ob:te.XT}),l.lineRangeMapping.modified.isEmpty||a.push({range:l.lineRangeMapping.modified.toInclusiveRange(),options:n?te.Kl:te.Zw}),l.lineRangeMapping.modified.isEmpty||l.lineRangeMapping.original.isEmpty)l.lineRangeMapping.original.isEmpty||o.push({range:l.lineRangeMapping.original.toInclusiveRange(),options:te.KL}),l.lineRangeMapping.modified.isEmpty||a.push({range:l.lineRangeMapping.modified.toInclusiveRange(),options:te.Ou});else{const i=this._options.useTrueInlineDiffRendering.read(e)&&De(l.lineRangeMapping);for(const e of l.lineRangeMapping.innerChanges||[])if(l.lineRangeMapping.original.contains(e.originalRange.startLineNumber)&&o.push({range:e.originalRange,options:e.originalRange.isEmpty()&&r?te.wp:te.Zb}),l.lineRangeMapping.modified.contains(e.modifiedRange.startLineNumber)&&a.push({range:e.modifiedRange,options:e.modifiedRange.isEmpty()&&r&&!i?te.GM:te.bk}),i){const i=t.model.original.getValueInRange(e.originalRange);a.push({range:e.modifiedRange,options:{description:"deleted-text",before:{content:i,inlineClassName:"inline-deleted-text"},zIndex:1e5,showIfCollapsed:!0}})}}if(s)for(const l of s.changes){const e=l.original.toInclusiveRange();e&&o.push({range:e,options:n?te.Ob:te.XT});const t=l.modified.toInclusiveRange();t&&a.push({range:t,options:n?te.Kl:te.Zw});for(const i of l.innerChanges||[])o.push({range:i.originalRange,options:te.Zb}),a.push({range:i.modifiedRange,options:te.bk})}const c=this._diffModel.read(e).activeMovedText.read(e);for(const l of i.movedTexts)o.push({range:l.lineRangeMapping.original.toInclusiveRange(),options:{description:"moved",blockClassName:"movedOriginal"+(l===c?" currentMove":""),blockPadding:[Pe.movedCodeBlockPadding,0,Pe.movedCodeBlockPadding,Pe.movedCodeBlockPadding]}}),a.push({range:l.lineRangeMapping.modified.toInclusiveRange(),options:{description:"moved",blockClassName:"movedModified"+(l===c?" currentMove":""),blockPadding:[4,0,4,4]}});return{originalDecorations:o,modifiedDecorations:a}})),this._register((0,S.pY)(this._editors.original,this._decorations.map((e=>e?.originalDecorations||[])))),this._register((0,S.pY)(this._editors.modified,this._decorations.map((e=>e?.modifiedDecorations||[]))))}}var Be=i(92403);class We{resetSash(){this._sashRatio.set(void 0,void 0)}constructor(e,t){this._options=e,this.dimensions=t,this.sashLeft=(0,l.dQ)(this,(e=>{const t=this._sashRatio.read(e)??this._options.splitViewDefaultRatio.read(e);return this._computeSashLeft(t,e)}),((e,t)=>{const i=this.dimensions.width.get();this._sashRatio.set(e/i,t)})),this._sashRatio=(0,c.FY)(this,void 0)}_computeSashLeft(e,t){const i=this.dimensions.width.read(t),s=Math.floor(this._options.splitViewDefaultRatio.read(t)*i),n=this._options.enableSplitViewResizing.read(t)?Math.floor(e*i):s,r=100;return i<=200?s:ni-r?i-r:n}}class Ve extends a.jG{constructor(e,t,i,s,n,r){super(),this._domNode=e,this._dimensions=t,this._enabled=i,this._boundarySashes=s,this.sashLeft=n,this._resetSash=r,this._sash=this._register(new Be.m(this._domNode,{getVerticalSashTop:e=>0,getVerticalSashLeft:e=>this.sashLeft.get(),getVerticalSashHeight:e=>this._dimensions.height.get()},{orientation:0})),this._startSashPosition=void 0,this._register(this._sash.onDidStart((()=>{this._startSashPosition=this.sashLeft.get()}))),this._register(this._sash.onDidChange((e=>{this.sashLeft.set(this._startSashPosition+(e.currentX-e.startX),void 0)}))),this._register(this._sash.onDidEnd((()=>this._sash.layout()))),this._register(this._sash.onDidReset((()=>this._resetSash()))),this._register((0,c.fm)((e=>{const t=this._boundarySashes.read(e);t&&(this._sash.orthogonalEndSash=t.bottom)}))),this._register((0,c.fm)((e=>{const t=this._enabled.read(e);this._sash.state=t?3:0,this.sashLeft.read(e),this._dimensions.height.read(e),this._sash.layout()})))}}class ze extends a.jG{constructor(e,t,i){super(),this._editor=e,this._domNode=t,this.itemProvider=i,this.scrollTop=(0,c.y0)(this,this._editor.onDidScrollChange,(e=>this._editor.getScrollTop())),this.isScrollTopZero=this.scrollTop.map((e=>0===e)),this.modelAttached=(0,c.y0)(this,this._editor.onDidChangeModel,(e=>this._editor.hasModel())),this.editorOnDidChangeViewZones=(0,c.yQ)("onDidChangeViewZones",this._editor.onDidChangeViewZones),this.editorOnDidContentSizeChange=(0,c.yQ)("onDidContentSizeChange",this._editor.onDidContentSizeChange),this.domNodeSizeChanged=(0,c.Yd)("domNodeSizeChanged"),this.views=new Map,this._domNode.className="gutter monaco-editor";const n=this._domNode.appendChild((0,s.h)("div.scroll-decoration",{role:"presentation",ariaHidden:"true",style:{width:"100%"}}).root),r=new ResizeObserver((()=>{(0,c.Rn)((e=>{this.domNodeSizeChanged.trigger(e)}))}));r.observe(this._domNode),this._register((0,a.s)((()=>r.disconnect()))),this._register((0,c.fm)((e=>{n.className=this.isScrollTopZero.read(e)?"":"scroll-decoration"}))),this._register((0,c.fm)((e=>this.render(e))))}dispose(){super.dispose(),(0,s.Ln)(this._domNode)}render(e){if(!this.modelAttached.read(e))return;this.domNodeSizeChanged.read(e),this.editorOnDidChangeViewZones.read(e),this.editorOnDidContentSizeChange.read(e);const t=this.scrollTop.read(e),i=this._editor.getVisibleRanges(),s=new Set(this.views.keys()),n=R.L.ofStartAndLength(0,this._domNode.clientHeight);if(!n.isEmpty)for(const r of i){const i=new w.M(r.startLineNumber,r.endLineNumber+1),o=this.itemProvider.getIntersectingGutterItems(i,e);(0,c.Rn)((e=>{for(const r of o){if(!r.range.intersect(i))continue;s.delete(r.id);let o=this.views.get(r.id);if(o)o.item.set(r,e);else{const e=document.createElement("div");this._domNode.appendChild(e);const t=(0,c.FY)("item",r),i=this.itemProvider.createView(t,e);o=new Ge(t,i,e),this.views.set(r.id,o)}const a=r.range.startLineNumber<=this._editor.getModel().getLineCount()?this._editor.getTopForLineNumber(r.range.startLineNumber,!0)-t:this._editor.getBottomForLineNumber(r.range.startLineNumber-1,!1)-t,l=(1===r.range.endLineNumberExclusive?Math.max(a,this._editor.getTopForLineNumber(r.range.startLineNumber,!1)-t):Math.max(a,this._editor.getBottomForLineNumber(r.range.endLineNumberExclusive-1,!0)-t))-a;o.domNode.style.top=`${a}px`,o.domNode.style.height=`${l}px`,o.gutterItemView.layout(R.L.ofStartAndLength(a,l),n)}}))}for(const r of s){const e=this.views.get(r);e.gutterItemView.dispose(),e.domNode.remove(),this.views.delete(r)}}}class Ge{constructor(e,t,i){this.item=e,this.gutterItemView=t,this.domNode=i}}var je=i(25791),Ke=i(75295),Ye=i(50973);class qe extends Ke.CO{constructor(e){super(),this._textModel=e}getValueOfRange(e){return this._textModel.getValueInRange(e)}get length(){const e=this._textModel.getLineCount(),t=this._textModel.getLineLength(e);return new Ye.W(e-1,t)}}var $e=i(65644),Qe=i(27195),Xe=i(32848),Ze=i(67220),Je=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},et=function(e,t){return function(i,s){t(i,s,e)}};const tt=[];let it=class extends a.jG{constructor(e,t,i,n,r,o,a,h,d){super(),this._diffModel=t,this._editors=i,this._options=n,this._sashLayout=r,this._boundarySashes=o,this._instantiationService=a,this._contextKeyService=h,this._menuService=d,this._menu=this._register(this._menuService.createMenu(Qe.D8.DiffEditorHunkToolbar,this._contextKeyService)),this._actions=(0,c.y0)(this,this._menu.onDidChange,(()=>this._menu.getActions())),this._hasActions=this._actions.map((e=>e.length>0)),this._showSash=(0,c.un)(this,(e=>this._options.renderSideBySide.read(e)&&this._hasActions.read(e))),this.width=(0,c.un)(this,(e=>this._hasActions.read(e)?35:0)),this.elements=(0,s.h)("div.gutter@gutter",{style:{position:"absolute",height:"100%",width:"35px"}},[]),this._currentDiff=(0,c.un)(this,(e=>{const t=this._diffModel.read(e);if(!t)return;const i=t.diff.read(e)?.mappings,s=this._editors.modifiedCursor.read(e);return s?i?.find((e=>e.lineRangeMapping.modified.contains(s.lineNumber))):void 0})),this._selectedDiffs=(0,c.un)(this,(e=>{const t=this._diffModel.read(e),i=t?.diff.read(e);if(!i)return tt;const s=this._editors.modifiedSelections.read(e);if(s.every((e=>e.isEmpty())))return tt;const n=new w.S(s.map((e=>w.M.fromRangeInclusive(e)))),r=i.mappings.filter((e=>e.lineRangeMapping.innerChanges&&n.intersects(e.lineRangeMapping.modified))).map((e=>({mapping:e,rangeMappings:e.lineRangeMapping.innerChanges.filter((e=>s.some((t=>T.Q.areIntersecting(e.modifiedRange,t)))))})));return 0===r.length||r.every((e=>0===e.rangeMappings.length))?tt:r})),this._register((0,S.$y)(e,this.elements.root)),this._register((0,s.ko)(this.elements.root,"click",(()=>{this._editors.modified.focus()}))),this._register((0,S.AV)(this.elements.root,{display:this._hasActions.map((e=>e?"block":"none"))})),(0,l.a0)(this,(t=>this._showSash.read(t)?new Ve(e,this._sashLayout.dimensions,this._options.enableSplitViewResizing,this._boundarySashes,(0,l.dQ)(this,(e=>this._sashLayout.sashLeft.read(e)-35),((e,t)=>this._sashLayout.sashLeft.set(e+35,t))),(()=>this._sashLayout.resetSash())):void 0)).recomputeInitiallyAndOnChange(this._store),this._register(new ze(this._editors.modified,this.elements.root,{getIntersectingGutterItems:(e,t)=>{const i=this._diffModel.read(t);if(!i)return[];const s=i.diff.read(t);if(!s)return[];const n=this._selectedDiffs.read(t);if(n.length>0){const e=x.wm.fromRangeMappings(n.flatMap((e=>e.rangeMappings)));return[new st(e,!0,Qe.D8.DiffEditorSelectionToolbar,void 0,i.model.original.uri,i.model.modified.uri)]}const r=this._currentDiff.read(t);return s.mappings.map((e=>new st(e.lineRangeMapping.withInnerChangesFromLineRanges(),e.lineRangeMapping===r?.lineRangeMapping,Qe.D8.DiffEditorHunkToolbar,void 0,i.model.original.uri,i.model.modified.uri)))},createView:(e,t)=>this._instantiationService.createInstance(nt,e,t,this)})),this._register((0,s.ko)(this.elements.gutter,s.Bx.MOUSE_WHEEL,(e=>{this._editors.modified.getOption(104).handleMouseWheel&&this._editors.modified.delegateScrollFromMouseWheelEvent(e)}),{passive:!1}))}computeStagedValue(e){const t=e.innerChanges??[],i=new qe(this._editors.modifiedModel.get()),s=new qe(this._editors.original.getModel()),n=new Ke.mF(t.map((e=>e.toTextEdit(i))));return n.apply(s)}layout(e){this.elements.gutter.style.left=e+"px"}};it=Je([et(6,M._Y),et(7,Xe.fN),et(8,Qe.ez)],it);class st{constructor(e,t,i,s,n,r){this.mapping=e,this.showAlways=t,this.menuId=i,this.rangeOverride=s,this.originalUri=n,this.modifiedUri=r}get id(){return this.mapping.modified.toString()}get range(){return this.rangeOverride??this.mapping.modified}}let nt=class extends a.jG{constructor(e,t,i,n){super(),this._item=e,this._elements=(0,s.h)("div.gutterItem",{style:{height:"20px",width:"34px"}},[(0,s.h)("div.background@background",{},[]),(0,s.h)("div.buttons@buttons",{},[])]),this._showAlways=this._item.map(this,(e=>e.showAlways)),this._menuId=this._item.map(this,(e=>e.menuId)),this._isSmall=(0,c.FY)(this,!1),this._lastItemRange=void 0,this._lastViewRange=void 0;const r=this._register(n.createInstance(Ze.fO,"element",!0,{position:{hoverPosition:1}}));this._register((0,S.rX)(t,this._elements.root)),this._register((0,c.fm)((e=>{const t=this._showAlways.read(e);this._elements.root.classList.toggle("noTransition",!0),this._elements.root.classList.toggle("showAlways",t),setTimeout((()=>{this._elements.root.classList.toggle("noTransition",!1)}),0)}))),this._register((0,c.yC)(((e,t)=>{this._elements.buttons.replaceChildren();const s=t.add(n.createInstance($e.m,this._elements.buttons,this._menuId.read(e),{orientation:1,hoverDelegate:r,toolbarOptions:{primaryGroup:e=>e.startsWith("primary")},overflowBehavior:{maxItems:this._isSmall.read(e)?1:3},hiddenItemStrategy:0,actionRunner:new je.I((()=>{const e=this._item.get(),t=e.mapping;return{mapping:t,originalWithModifiedChanges:i.computeStagedValue(t),originalUri:e.originalUri,modifiedUri:e.modifiedUri}})),menuOptions:{shouldForwardArgs:!0}}));t.add(s.onDidChangeMenuItems((()=>{this._lastItemRange&&this.layout(this._lastItemRange,this._lastViewRange)})))})))}layout(e,t){this._lastItemRange=e,this._lastViewRange=t;let i=this._elements.buttons.clientHeight;this._isSmall.set(1===this._item.get().mapping.original.startLineNumber&&e.length<30,void 0),i=this._elements.buttons.clientHeight;const s=e.length/2-i/2,n=i;let r=e.start+s;const o=R.L.tryCreate(n,t.endExclusive-n-i),a=R.L.tryCreate(e.start+n,e.endExclusive-i-n);a&&o&&a.start=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},gt=function(e,t){return function(i,s){t(i,s,e)}};let pt=class extends a.jG{static{rt=this}static{this.ONE_OVERVIEW_WIDTH=15}static{this.ENTIRE_DIFF_OVERVIEW_WIDTH=2*this.ONE_OVERVIEW_WIDTH}constructor(e,t,i,n,r,o,a){super(),this._editors=e,this._rootElement=t,this._diffModel=i,this._rootWidth=n,this._rootHeight=r,this._modifiedEditorLayoutInfo=o,this._themeService=a,this.width=rt.ENTIRE_DIFF_OVERVIEW_WIDTH;const l=(0,c.y0)(this._themeService.onDidColorThemeChange,(()=>this._themeService.getColorTheme())),h=(0,c.un)((e=>{const t=l.read(e);return{insertColor:t.getColor(ht.ld8)||(t.getColor(ht.Gj6)||ht.EY1).transparent(2),removeColor:t.getColor(ht.$BZ)||(t.getColor(ht.GNm)||ht.ZEf).transparent(2)}})),d=(0,at.Z)(document.createElement("div"));d.setClassName("diffViewport"),d.setPosition("absolute");const u=(0,s.h)("div.diffOverview",{style:{position:"absolute",top:"0px",width:rt.ENTIRE_DIFF_OVERVIEW_WIDTH+"px"}}).root;this._register((0,S.rX)(u,d.domNode)),this._register((0,s.b2)(u,s.Bx.POINTER_DOWN,(e=>{this._editors.modified.delegateVerticalScrollbarPointerDown(e)}))),this._register((0,s.ko)(u,s.Bx.MOUSE_WHEEL,(e=>{this._editors.modified.delegateScrollFromMouseWheelEvent(e)}),{passive:!1})),this._register((0,S.rX)(this._rootElement,u)),this._register((0,c.yC)(((e,t)=>{const i=this._diffModel.read(e),s=this._editors.original.createOverviewRuler("original diffOverviewRuler");s&&(t.add(s),t.add((0,S.rX)(u,s.getDomNode())));const n=this._editors.modified.createOverviewRuler("modified diffOverviewRuler");if(n&&(t.add(n),t.add((0,S.rX)(u,n.getDomNode()))),!s||!n)return;const r=(0,c.yQ)("viewZoneChanged",this._editors.original.onDidChangeViewZones),o=(0,c.yQ)("viewZoneChanged",this._editors.modified.onDidChangeViewZones),a=(0,c.yQ)("hiddenRangesChanged",this._editors.original.onDidChangeHiddenAreas),l=(0,c.yQ)("hiddenRangesChanged",this._editors.modified.onDidChangeHiddenAreas);t.add((0,c.fm)((e=>{r.read(e),o.read(e),a.read(e),l.read(e);const t=h.read(e),c=i?.diff.read(e)?.mappings;function d(e,t,i){const s=i._getViewModel();return s?e.filter((e=>e.length>0)).map((e=>{const i=s.coordinatesConverter.convertModelPositionToViewPosition(new L.y(e.startLineNumber,1)),n=s.coordinatesConverter.convertModelPositionToViewPosition(new L.y(e.endLineNumberExclusive,1)),r=n.lineNumber-i.lineNumber;return new lt.iE(i.lineNumber,n.lineNumber,r,t.toString())})):[]}const u=d((c||[]).map((e=>e.lineRangeMapping.original)),t.removeColor,this._editors.original),g=d((c||[]).map((e=>e.lineRangeMapping.modified)),t.insertColor,this._editors.modified);s?.setZones(u),n?.setZones(g)}))),t.add((0,c.fm)((e=>{const t=this._rootHeight.read(e),i=this._rootWidth.read(e),r=this._modifiedEditorLayoutInfo.read(e);if(r){const i=rt.ENTIRE_DIFF_OVERVIEW_WIDTH-2*rt.ONE_OVERVIEW_WIDTH;s.setLayout({top:0,height:t,right:i+rt.ONE_OVERVIEW_WIDTH,width:rt.ONE_OVERVIEW_WIDTH}),n.setLayout({top:0,height:t,right:0,width:rt.ONE_OVERVIEW_WIDTH});const o=this._editors.modifiedScrollTop.read(e),a=this._editors.modifiedScrollHeight.read(e),c=this._editors.modified.getOption(104),l=new ct.m(c.verticalHasArrows?c.arrowSize:0,c.verticalScrollbarSize,0,r.height,a,o);d.setTop(l.getSliderPosition()),d.setHeight(l.getSliderSize())}else d.setTop(0),d.setHeight(0);u.style.height=t+"px",u.style.left=i-rt.ENTIRE_DIFF_OVERVIEW_WIDTH+"px",d.setWidth(rt.ENTIRE_DIFF_OVERVIEW_WIDTH)})))})))}};pt=rt=ut([gt(6,dt.Gy)],pt);var mt=i(20370),ft=i(16223);const _t=[];class vt extends a.jG{constructor(e,t,i,s){super(),this._editors=e,this._diffModel=t,this._options=i,this._widget=s,this._selectedDiffs=(0,c.un)(this,(e=>{const t=this._diffModel.read(e),i=t?.diff.read(e);if(!i)return _t;const s=this._editors.modifiedSelections.read(e);if(s.every((e=>e.isEmpty())))return _t;const n=new w.S(s.map((e=>w.M.fromRangeInclusive(e)))),r=i.mappings.filter((e=>e.lineRangeMapping.innerChanges&&n.intersects(e.lineRangeMapping.modified))).map((e=>({mapping:e,rangeMappings:e.lineRangeMapping.innerChanges.filter((e=>s.some((t=>T.Q.areIntersecting(e.modifiedRange,t)))))})));return 0===r.length||r.every((e=>0===e.rangeMappings.length))?_t:r})),this._register((0,c.yC)(((e,t)=>{if(!this._options.shouldRenderOldRevertArrows.read(e))return;const i=this._diffModel.read(e),s=i?.diff.read(e);if(!i||!s)return;if(i.movedTextToCompare.read(e))return;const n=[],r=this._selectedDiffs.read(e),o=new Set(r.map((e=>e.mapping)));if(r.length>0){const i=this._editors.modifiedSelections.read(e),s=t.add(new Ct(i[i.length-1].positionLineNumber,this._widget,r.flatMap((e=>e.rangeMappings)),!0));this._editors.modified.addGlyphMarginWidget(s),n.push(s)}for(const a of s.mappings)if(!o.has(a)&&!a.lineRangeMapping.modified.isEmpty&&a.lineRangeMapping.innerChanges){const e=t.add(new Ct(a.lineRangeMapping.modified.startLineNumber,this._widget,a.lineRangeMapping,!1));this._editors.modified.addGlyphMarginWidget(e),n.push(e)}t.add((0,a.s)((()=>{for(const e of n)this._editors.modified.removeGlyphMarginWidget(e)})))})))}}class Ct extends a.jG{static{this.counter=0}getId(){return this._id}constructor(e,t,i,n){super(),this._lineNumber=e,this._widget=t,this._diffs=i,this._revertSelection=n,this._id="revertButton"+Ct.counter++,this._domNode=(0,s.h)("div.revertButton",{title:this._revertSelection?(0,O.kg)("revertSelectedChanges","Revert Selected Changes"):(0,O.kg)("revertChange","Revert Change")},[(0,mt.s)(C.W.arrowRight)]).root,this._register((0,s.ko)(this._domNode,s.Bx.MOUSE_DOWN,(e=>{2!==e.button&&(e.stopPropagation(),e.preventDefault())}))),this._register((0,s.ko)(this._domNode,s.Bx.MOUSE_UP,(e=>{e.stopPropagation(),e.preventDefault()}))),this._register((0,s.ko)(this._domNode,s.Bx.CLICK,(e=>{this._diffs instanceof x.WL?this._widget.revert(this._diffs):this._widget.revertRangeMappings(this._diffs),e.stopPropagation(),e.preventDefault()})))}getDomNode(){return this._domNode}getPosition(){return{lane:ft.ZS.Right,range:{startColumn:1,startLineNumber:this._lineNumber,endColumn:1,endLineNumber:this._lineNumber},zIndex:10001}}}var Et=i(71319),bt=i(23452),St=i(60002),yt=i(58345),wt=i(73823),Rt=i(38844),Lt=i(98031),Tt=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},xt=function(e,t){return function(i,s){t(i,s,e)}};let kt=class extends a.jG{get onDidContentSizeChange(){return this._onDidContentSizeChange.event}constructor(e,t,i,s,n,r,a){super(),this.originalEditorElement=e,this.modifiedEditorElement=t,this._options=i,this._argCodeEditorWidgetOptions=s,this._createInnerEditor=n,this._instantiationService=r,this._keybindingService=a,this.original=this._register(this._createLeftHandSideEditor(this._options.editorOptions.get(),this._argCodeEditorWidgetOptions.originalEditor||{})),this.modified=this._register(this._createRightHandSideEditor(this._options.editorOptions.get(),this._argCodeEditorWidgetOptions.modifiedEditor||{})),this._onDidContentSizeChange=this._register(new o.vl),this.modifiedScrollTop=(0,c.y0)(this,this.modified.onDidScrollChange,(()=>this.modified.getScrollTop())),this.modifiedScrollHeight=(0,c.y0)(this,this.modified.onDidScrollChange,(()=>this.modified.getScrollHeight())),this.modifiedObs=(0,Rt.Ud)(this.modified),this.originalObs=(0,Rt.Ud)(this.original),this.modifiedModel=this.modifiedObs.model,this.modifiedSelections=(0,c.y0)(this,this.modified.onDidChangeCursorSelection,(()=>this.modified.getSelections()??[])),this.modifiedCursor=(0,c.C)({owner:this,equalsFn:L.y.equals},(e=>this.modifiedSelections.read(e)[0]?.getPosition()??new L.y(1,1))),this.originalCursor=(0,c.y0)(this,this.original.onDidChangeCursorPosition,(()=>this.original.getPosition()??new L.y(1,1))),this._argCodeEditorWidgetOptions=null,this._register((0,c.Y)({createEmptyChangeSummary:()=>({}),handleChange:(e,t)=>(e.didChange(i.editorOptions)&&Object.assign(t,e.change.changedOptions),!0)},((e,t)=>{i.editorOptions.read(e),this._options.renderSideBySide.read(e),this.modified.updateOptions(this._adjustOptionsForRightHandSide(e,t)),this.original.updateOptions(this._adjustOptionsForLeftHandSide(e,t))})))}_createLeftHandSideEditor(e,t){const i=this._adjustOptionsForLeftHandSide(void 0,e),s=this._constructInnerEditor(this._instantiationService,this.originalEditorElement,i,t);return s.setContextValue("isInDiffLeftEditor",!0),s}_createRightHandSideEditor(e,t){const i=this._adjustOptionsForRightHandSide(void 0,e),s=this._constructInnerEditor(this._instantiationService,this.modifiedEditorElement,i,t);return s.setContextValue("isInDiffRightEditor",!0),s}_constructInnerEditor(e,t,i,s){const n=this._createInnerEditor(e,t,i,s);return this._register(n.onDidContentSizeChange((e=>{const t=this.original.getContentWidth()+this.modified.getContentWidth()+pt.ENTIRE_DIFF_OVERVIEW_WIDTH,i=Math.max(this.modified.getContentHeight(),this.original.getContentHeight());this._onDidContentSizeChange.fire({contentHeight:i,contentWidth:t,contentHeightChanged:e.contentHeightChanged,contentWidthChanged:e.contentWidthChanged})}))),n}_adjustOptionsForLeftHandSide(e,t){const i=this._adjustOptionsForSubEditor(t);return this._options.renderSideBySide.get()?(i.unicodeHighlight=this._options.editorOptions.get().unicodeHighlight||{},i.wordWrapOverride1=this._options.diffWordWrap.get()):(i.wordWrapOverride1="off",i.wordWrapOverride2="off",i.stickyScroll={enabled:!1},i.unicodeHighlight={nonBasicASCII:!1,ambiguousCharacters:!1,invisibleCharacters:!1}),i.glyphMargin=this._options.renderSideBySide.get(),t.originalAriaLabel&&(i.ariaLabel=t.originalAriaLabel),i.ariaLabel=this._updateAriaLabel(i.ariaLabel),i.readOnly=!this._options.originalEditable.get(),i.dropIntoEditor={enabled:!i.readOnly},i.extraEditorClassName="original-in-monaco-diff-editor",i}_adjustOptionsForRightHandSide(e,t){const i=this._adjustOptionsForSubEditor(t);return t.modifiedAriaLabel&&(i.ariaLabel=t.modifiedAriaLabel),i.ariaLabel=this._updateAriaLabel(i.ariaLabel),i.wordWrapOverride1=this._options.diffWordWrap.get(),i.revealHorizontalRightPadding=y.qB.revealHorizontalRightPadding.defaultValue+pt.ENTIRE_DIFF_OVERVIEW_WIDTH,i.scrollbar.verticalHasArrows=!1,i.extraEditorClassName="modified-in-monaco-diff-editor",i}_adjustOptionsForSubEditor(e){const t={...e,dimension:{height:0,width:0}};return t.inDiffEditor=!0,t.automaticLayout=!1,t.scrollbar={...t.scrollbar||{}},t.folding=!1,t.codeLens=this._options.diffCodeLens.get(),t.fixedOverflowWidgets=!0,t.minimap={...t.minimap||{}},t.minimap.enabled=!1,this._options.hideUnchangedRegions.get()?t.stickyScroll={enabled:!1}:t.stickyScroll=this._options.editorOptions.get().stickyScroll,t}_updateAriaLabel(e){e||(e="");const t=(0,O.kg)("diff-aria-navigation-tip"," use {0} to open the accessibility help.",this._keybindingService.lookupKeybinding("editor.action.accessibilityHelp")?.getAriaLabel());return this._options.accessibilityVerbose.get()?e+t:e?e.replaceAll(t,""):""}};kt=Tt([xt(5,M._Y),xt(6,Lt.b)],kt);class At extends a.jG{constructor(){super(...arguments),this._id=++At.idCounter,this._onDidDispose=this._register(new o.vl),this.onDidDispose=this._onDidDispose.event}static{this.idCounter=0}getId(){return this.getEditorType()+":v2:"+this._id}getVisibleColumnFromPosition(e){return this._targetEditor.getVisibleColumnFromPosition(e)}getPosition(){return this._targetEditor.getPosition()}setPosition(e,t="api"){this._targetEditor.setPosition(e,t)}revealLine(e,t=0){this._targetEditor.revealLine(e,t)}revealLineInCenter(e,t=0){this._targetEditor.revealLineInCenter(e,t)}revealLineInCenterIfOutsideViewport(e,t=0){this._targetEditor.revealLineInCenterIfOutsideViewport(e,t)}revealLineNearTop(e,t=0){this._targetEditor.revealLineNearTop(e,t)}revealPosition(e,t=0){this._targetEditor.revealPosition(e,t)}revealPositionInCenter(e,t=0){this._targetEditor.revealPositionInCenter(e,t)}revealPositionInCenterIfOutsideViewport(e,t=0){this._targetEditor.revealPositionInCenterIfOutsideViewport(e,t)}revealPositionNearTop(e,t=0){this._targetEditor.revealPositionNearTop(e,t)}getSelection(){return this._targetEditor.getSelection()}getSelections(){return this._targetEditor.getSelections()}setSelection(e,t="api"){this._targetEditor.setSelection(e,t)}setSelections(e,t="api"){this._targetEditor.setSelections(e,t)}revealLines(e,t,i=0){this._targetEditor.revealLines(e,t,i)}revealLinesInCenter(e,t,i=0){this._targetEditor.revealLinesInCenter(e,t,i)}revealLinesInCenterIfOutsideViewport(e,t,i=0){this._targetEditor.revealLinesInCenterIfOutsideViewport(e,t,i)}revealLinesNearTop(e,t,i=0){this._targetEditor.revealLinesNearTop(e,t,i)}revealRange(e,t=0,i=!1,s=!0){this._targetEditor.revealRange(e,t,i,s)}revealRangeInCenter(e,t=0){this._targetEditor.revealRangeInCenter(e,t)}revealRangeInCenterIfOutsideViewport(e,t=0){this._targetEditor.revealRangeInCenterIfOutsideViewport(e,t)}revealRangeNearTop(e,t=0){this._targetEditor.revealRangeNearTop(e,t)}revealRangeNearTopIfOutsideViewport(e,t=0){this._targetEditor.revealRangeNearTopIfOutsideViewport(e,t)}revealRangeAtTop(e,t=0){this._targetEditor.revealRangeAtTop(e,t)}getSupportedActions(){return this._targetEditor.getSupportedActions()}focus(){this._targetEditor.focus()}trigger(e,t,i){this._targetEditor.trigger(e,t,i)}createDecorationsCollection(e){return this._targetEditor.createDecorationsCollection(e)}changeDecorations(e){return this._targetEditor.changeDecorations(e)}}var Nt=i(13850),It=i(61059),Ot=i(253),Dt=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},Mt=function(e,t){return function(i,s){t(i,s,e)}};let Pt=class{get editorOptions(){return this._options}constructor(e,t){this._accessibilityService=t,this._diffEditorWidth=(0,c.FY)(this,0),this._screenReaderMode=(0,c.y0)(this,this._accessibilityService.onDidChangeScreenReaderOptimized,(()=>this._accessibilityService.isScreenReaderOptimized())),this.couldShowInlineViewBecauseOfSize=(0,c.un)(this,(e=>this._options.read(e).renderSideBySide&&this._diffEditorWidth.read(e)<=this._options.read(e).renderSideBySideInlineBreakpoint)),this.renderOverviewRuler=(0,c.un)(this,(e=>this._options.read(e).renderOverviewRuler)),this.renderSideBySide=(0,c.un)(this,(e=>(!this.compactMode.read(e)||!this.shouldRenderInlineViewInSmartMode.read(e))&&(this._options.read(e).renderSideBySide&&!(this._options.read(e).useInlineViewWhenSpaceIsLimited&&this.couldShowInlineViewBecauseOfSize.read(e)&&!this._screenReaderMode.read(e))))),this.readOnly=(0,c.un)(this,(e=>this._options.read(e).readOnly)),this.shouldRenderOldRevertArrows=(0,c.un)(this,(e=>!!this._options.read(e).renderMarginRevertIcon&&(!!this.renderSideBySide.read(e)&&(!this.readOnly.read(e)&&!this.shouldRenderGutterMenu.read(e))))),this.shouldRenderGutterMenu=(0,c.un)(this,(e=>this._options.read(e).renderGutterMenu)),this.renderIndicators=(0,c.un)(this,(e=>this._options.read(e).renderIndicators)),this.enableSplitViewResizing=(0,c.un)(this,(e=>this._options.read(e).enableSplitViewResizing)),this.splitViewDefaultRatio=(0,c.un)(this,(e=>this._options.read(e).splitViewDefaultRatio)),this.ignoreTrimWhitespace=(0,c.un)(this,(e=>this._options.read(e).ignoreTrimWhitespace)),this.maxComputationTimeMs=(0,c.un)(this,(e=>this._options.read(e).maxComputationTime)),this.showMoves=(0,c.un)(this,(e=>this._options.read(e).experimental.showMoves&&this.renderSideBySide.read(e))),this.isInEmbeddedEditor=(0,c.un)(this,(e=>this._options.read(e).isInEmbeddedEditor)),this.diffWordWrap=(0,c.un)(this,(e=>this._options.read(e).diffWordWrap)),this.originalEditable=(0,c.un)(this,(e=>this._options.read(e).originalEditable)),this.diffCodeLens=(0,c.un)(this,(e=>this._options.read(e).diffCodeLens)),this.accessibilityVerbose=(0,c.un)(this,(e=>this._options.read(e).accessibilityVerbose)),this.diffAlgorithm=(0,c.un)(this,(e=>this._options.read(e).diffAlgorithm)),this.showEmptyDecorations=(0,c.un)(this,(e=>this._options.read(e).experimental.showEmptyDecorations)),this.onlyShowAccessibleDiffViewer=(0,c.un)(this,(e=>this._options.read(e).onlyShowAccessibleDiffViewer)),this.compactMode=(0,c.un)(this,(e=>this._options.read(e).compactMode)),this.trueInlineDiffRenderingEnabled=(0,c.un)(this,(e=>this._options.read(e).experimental.useTrueInlineView)),this.useTrueInlineDiffRendering=(0,c.un)(this,(e=>!this.renderSideBySide.read(e)&&this.trueInlineDiffRenderingEnabled.read(e))),this.hideUnchangedRegions=(0,c.un)(this,(e=>this._options.read(e).hideUnchangedRegions.enabled)),this.hideUnchangedRegionsRevealLineCount=(0,c.un)(this,(e=>this._options.read(e).hideUnchangedRegions.revealLineCount)),this.hideUnchangedRegionsContextLineCount=(0,c.un)(this,(e=>this._options.read(e).hideUnchangedRegions.contextLineCount)),this.hideUnchangedRegionsMinimumLineCount=(0,c.un)(this,(e=>this._options.read(e).hideUnchangedRegions.minimumLineCount)),this._model=(0,c.FY)(this,void 0),this.shouldRenderInlineViewInSmartMode=this._model.map(this,(e=>(0,Nt.t)(this,(t=>{const i=e?.diff.read(t);return i?(s=i,n=this.trueInlineDiffRenderingEnabled.read(t),s.mappings.every((e=>0===e.lineRangeMapping.original.length||function(e){return 0===e.modified.length}(e.lineRangeMapping)||n&&De(e.lineRangeMapping)))):void 0;var s,n})))).flatten().map(this,(e=>!!e)),this.inlineViewHideOriginalLineNumbers=this.compactMode;const i={...e,...Ft(e,It.q)};this._options=(0,c.FY)(this,i)}updateOptions(e){const t=Ft(e,this._options.get()),i={...this._options.get(),...e,...t};this._options.set(i,void 0,{changedOptions:e})}setWidth(e){this._diffEditorWidth.set(e,void 0)}setModel(e){this._model.set(e,void 0)}};function Ft(e,t){return{enableSplitViewResizing:(0,y.zM)(e.enableSplitViewResizing,t.enableSplitViewResizing),splitViewDefaultRatio:(0,y.ls)(e.splitViewDefaultRatio,.5,.1,.9),renderSideBySide:(0,y.zM)(e.renderSideBySide,t.renderSideBySide),renderMarginRevertIcon:(0,y.zM)(e.renderMarginRevertIcon,t.renderMarginRevertIcon),maxComputationTime:(0,y.wA)(e.maxComputationTime,t.maxComputationTime,0,1073741824),maxFileSize:(0,y.wA)(e.maxFileSize,t.maxFileSize,0,1073741824),ignoreTrimWhitespace:(0,y.zM)(e.ignoreTrimWhitespace,t.ignoreTrimWhitespace),renderIndicators:(0,y.zM)(e.renderIndicators,t.renderIndicators),originalEditable:(0,y.zM)(e.originalEditable,t.originalEditable),diffCodeLens:(0,y.zM)(e.diffCodeLens,t.diffCodeLens),renderOverviewRuler:(0,y.zM)(e.renderOverviewRuler,t.renderOverviewRuler),diffWordWrap:(0,y.O4)(e.diffWordWrap,t.diffWordWrap,["off","on","inherit"]),diffAlgorithm:(0,y.O4)(e.diffAlgorithm,t.diffAlgorithm,["legacy","advanced"],{smart:"legacy",experimental:"advanced"}),accessibilityVerbose:(0,y.zM)(e.accessibilityVerbose,t.accessibilityVerbose),experimental:{showMoves:(0,y.zM)(e.experimental?.showMoves,t.experimental.showMoves),showEmptyDecorations:(0,y.zM)(e.experimental?.showEmptyDecorations,t.experimental.showEmptyDecorations),useTrueInlineView:(0,y.zM)(e.experimental?.useTrueInlineView,t.experimental.useTrueInlineView)},hideUnchangedRegions:{enabled:(0,y.zM)(e.hideUnchangedRegions?.enabled??e.experimental?.collapseUnchangedRegions,t.hideUnchangedRegions.enabled),contextLineCount:(0,y.wA)(e.hideUnchangedRegions?.contextLineCount,t.hideUnchangedRegions.contextLineCount,0,1073741824),minimumLineCount:(0,y.wA)(e.hideUnchangedRegions?.minimumLineCount,t.hideUnchangedRegions.minimumLineCount,0,1073741824),revealLineCount:(0,y.wA)(e.hideUnchangedRegions?.revealLineCount,t.hideUnchangedRegions.revealLineCount,0,1073741824)},isInEmbeddedEditor:(0,y.zM)(e.isInEmbeddedEditor,t.isInEmbeddedEditor),onlyShowAccessibleDiffViewer:(0,y.zM)(e.onlyShowAccessibleDiffViewer,t.onlyShowAccessibleDiffViewer),renderSideBySideInlineBreakpoint:(0,y.wA)(e.renderSideBySideInlineBreakpoint,t.renderSideBySideInlineBreakpoint,0,1073741824),useInlineViewWhenSpaceIsLimited:(0,y.zM)(e.useInlineViewWhenSpaceIsLimited,t.useInlineViewWhenSpaceIsLimited),renderGutterMenu:(0,y.zM)(e.renderGutterMenu,t.renderGutterMenu),compactMode:(0,y.zM)(e.compactMode,t.compactMode)}}Pt=Dt([Mt(1,Ot.j)],Pt);var Ut=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},Ht=function(e,t){return function(i,s){t(i,s,e)}};let Bt=class extends At{get onDidContentSizeChange(){return this._editors.onDidContentSizeChange}constructor(e,t,i,n,h,d,g,p){super(),this._domElement=e,this._parentContextKeyService=n,this._parentInstantiationService=h,this._accessibilitySignalService=g,this._editorProgressService=p,this.elements=(0,s.h)("div.monaco-diff-editor.side-by-side",{style:{position:"relative",height:"100%"}},[(0,s.h)("div.editor.original@original",{style:{position:"absolute",height:"100%"}}),(0,s.h)("div.editor.modified@modified",{style:{position:"absolute",height:"100%"}}),(0,s.h)("div.accessibleDiffViewer@accessibleDiffViewer",{style:{position:"absolute",height:"100%"}})]),this._diffModelSrc=this._register((0,c.X2)(this,void 0)),this._diffModel=(0,c.un)(this,(e=>this._diffModelSrc.read(e)?.object)),this.onDidChangeModel=o.Jh.fromObservableLight(this._diffModel),this._contextKeyService=this._register(this._parentContextKeyService.createScoped(this._domElement)),this._instantiationService=this._register(this._parentInstantiationService.createChild(new yt.a([Xe.fN,this._contextKeyService]))),this._boundarySashes=(0,c.FY)(this,void 0),this._accessibleDiffViewerShouldBeVisible=(0,c.FY)(this,!1),this._accessibleDiffViewerVisible=(0,c.un)(this,(e=>!!this._options.onlyShowAccessibleDiffViewer.read(e)||this._accessibleDiffViewerShouldBeVisible.read(e))),this._movedBlocksLinesPart=(0,c.FY)(this,void 0),this._layoutInfo=(0,c.un)(this,(e=>{const t=this._rootSizeObserver.width.read(e),i=this._rootSizeObserver.height.read(e);this._rootSizeObserver.automaticLayout?this.elements.root.style.height="100%":this.elements.root.style.height=i+"px";const s=this._sash.read(e),n=this._gutter.read(e),r=n?.width.read(e)??0,o=this._overviewRulerPart.read(e)?.width??0;let a,c,l,h,d;if(!!s){const i=s.sashLeft.read(e);a=0,c=i-r-(this._movedBlocksLinesPart.read(e)?.width.read(e)??0),d=i-r,l=i,h=t-l-o}else{d=0;a=r,c=this._options.inlineViewHideOriginalLineNumbers.read(e)?0:Math.max(5,this._editors.originalObs.layoutInfoDecorationsLeft.read(e)),l=r+c,h=t-l-o}return this.elements.original.style.left=a+"px",this.elements.original.style.width=c+"px",this._editors.original.layout({width:c,height:i},!0),n?.layout(d),this.elements.modified.style.left=l+"px",this.elements.modified.style.width=h+"px",this._editors.modified.layout({width:h,height:i},!0),{modifiedEditor:this._editors.modified.getLayoutInfo(),originalEditor:this._editors.original.getLayoutInfo()}})),this._diffValue=this._diffModel.map(((e,t)=>e?.diff.read(t))),this.onDidUpdateDiff=o.Jh.fromObservableLight(this._diffValue),d.willCreateDiffEditor(),this._contextKeyService.createKey("isInDiffEditor",!0),this._domElement.appendChild(this.elements.root),this._register((0,a.s)((()=>this.elements.root.remove()))),this._rootSizeObserver=this._register(new S.pN(this.elements.root,t.dimension)),this._rootSizeObserver.setAutomaticLayout(t.automaticLayout??!1),this._options=this._instantiationService.createInstance(Pt,t),this._register((0,c.fm)((e=>{this._options.setWidth(this._rootSizeObserver.width.read(e))}))),this._contextKeyService.createKey(St.R.isEmbeddedDiffEditor.key,!1),this._register((0,Et.w)(St.R.isEmbeddedDiffEditor,this._contextKeyService,(e=>this._options.isInEmbeddedEditor.read(e)))),this._register((0,Et.w)(St.R.comparingMovedCode,this._contextKeyService,(e=>!!this._diffModel.read(e)?.movedTextToCompare.read(e)))),this._register((0,Et.w)(St.R.diffEditorRenderSideBySideInlineBreakpointReached,this._contextKeyService,(e=>this._options.couldShowInlineViewBecauseOfSize.read(e)))),this._register((0,Et.w)(St.R.diffEditorInlineMode,this._contextKeyService,(e=>!this._options.renderSideBySide.read(e)))),this._register((0,Et.w)(St.R.hasChanges,this._contextKeyService,(e=>(this._diffModel.read(e)?.diff.read(e)?.mappings.length??0)>0))),this._editors=this._register(this._instantiationService.createInstance(kt,this.elements.original,this.elements.modified,this._options,i,((e,t,i,s)=>this._createInnerEditor(e,t,i,s)))),this._register((0,Et.w)(St.R.diffEditorOriginalWritable,this._contextKeyService,(e=>this._options.originalEditable.read(e)))),this._register((0,Et.w)(St.R.diffEditorModifiedWritable,this._contextKeyService,(e=>!this._options.readOnly.read(e)))),this._register((0,Et.w)(St.R.diffEditorOriginalUri,this._contextKeyService,(e=>this._diffModel.read(e)?.model.original.uri.toString()??""))),this._register((0,Et.w)(St.R.diffEditorModifiedUri,this._contextKeyService,(e=>this._diffModel.read(e)?.model.modified.uri.toString()??""))),this._overviewRulerPart=(0,l.a0)(this,(e=>this._options.renderOverviewRuler.read(e)?this._instantiationService.createInstance((0,ne.b)(pt,e),this._editors,this.elements.root,this._diffModel,this._rootSizeObserver.width,this._rootSizeObserver.height,this._layoutInfo.map((e=>e.modifiedEditor))):void 0)).recomputeInitiallyAndOnChange(this._store);const m={height:this._rootSizeObserver.height,width:this._rootSizeObserver.width.map(((e,t)=>e-(this._overviewRulerPart.read(t)?.width??0)))};this._sashLayout=new We(this._options,m),this._sash=(0,l.a0)(this,(e=>{const t=this._options.renderSideBySide.read(e);return this.elements.root.classList.toggle("side-by-side",t),t?new Ve(this.elements.root,m,this._options.enableSplitViewResizing,this._boundarySashes,this._sashLayout.sashLeft,(()=>this._sashLayout.resetSash())):void 0})).recomputeInitiallyAndOnChange(this._store);const f=(0,l.a0)(this,(e=>this._instantiationService.createInstance((0,ne.b)(ot.N,e),this._editors,this._diffModel,this._options))).recomputeInitiallyAndOnChange(this._store);(0,l.a0)(this,(e=>this._instantiationService.createInstance((0,ne.b)(He,e),this._editors,this._diffModel,this._options,this))).recomputeInitiallyAndOnChange(this._store);const _=new Set,v=new Set;let C=!1;const E=(0,l.a0)(this,(e=>this._instantiationService.createInstance((0,ne.b)(Ne,e),(0,s.zk)(this._domElement),this._editors,this._diffModel,this._options,this,(()=>C||f.get().isUpdatingHiddenAreas),_,v))).recomputeInitiallyAndOnChange(this._store),b=(0,c.un)(this,(e=>{const t=E.read(e).viewZones.read(e).orig,i=f.read(e).viewZones.read(e).origViewZones;return t.concat(i)})),y=(0,c.un)(this,(e=>{const t=E.read(e).viewZones.read(e).mod,i=f.read(e).viewZones.read(e).modViewZones;return t.concat(i)}));let w;this._register((0,S.Vs)(this._editors.original,b,(e=>{C=e}),_)),this._register((0,S.Vs)(this._editors.modified,y,(e=>{C=e,C?w=u.D.capture(this._editors.modified):(w?.restore(this._editors.modified),w=void 0)}),v)),this._accessibleDiffViewer=(0,l.a0)(this,(e=>this._instantiationService.createInstance((0,ne.b)(V,e),this.elements.accessibleDiffViewer,this._accessibleDiffViewerVisible,((e,t)=>this._accessibleDiffViewerShouldBeVisible.set(e,t)),this._options.onlyShowAccessibleDiffViewer.map((e=>!e)),this._rootSizeObserver.width,this._rootSizeObserver.height,this._diffModel.map(((e,t)=>e?.diff.read(t)?.mappings.map((e=>e.lineRangeMapping)))),new Z(this._editors)))).recomputeInitiallyAndOnChange(this._store);const R=this._accessibleDiffViewerVisible.map((e=>e?"hidden":"visible"));this._register((0,S.AV)(this.elements.modified,{visibility:R})),this._register((0,S.AV)(this.elements.original,{visibility:R})),this._createDiffEditorContributions(),d.addDiffEditor(this),this._gutter=(0,l.a0)(this,(e=>this._options.shouldRenderGutterMenu.read(e)?this._instantiationService.createInstance((0,ne.b)(it,e),this.elements.root,this._diffModel,this._editors,this._options,this._sashLayout,this._boundarySashes):void 0)),this._register((0,c.OI)(this._layoutInfo)),(0,l.a0)(this,(e=>new((0,ne.b)(Pe,e))(this.elements.root,this._diffModel,this._layoutInfo.map((e=>e.originalEditor)),this._layoutInfo.map((e=>e.modifiedEditor)),this._editors))).recomputeInitiallyAndOnChange(this._store,(e=>{this._movedBlocksLinesPart.set(e,void 0)})),this._register(o.Jh.runAndSubscribe(this._editors.modified.onDidChangeCursorPosition,(e=>this._handleCursorPositionChange(e,!0)))),this._register(o.Jh.runAndSubscribe(this._editors.original.onDidChangeCursorPosition,(e=>this._handleCursorPositionChange(e,!1))));const L=this._diffModel.map(this,((e,t)=>{if(e)return void 0===e.diff.read(t)&&!e.isDiffUpToDate.read(t)}));this._register((0,c.yC)(((e,t)=>{if(!0===L.read(e)){const e=this._editorProgressService.show(!0,1e3);t.add((0,a.s)((()=>e.done())))}}))),this._register((0,c.yC)(((e,t)=>{t.add(new((0,ne.b)(vt,e))(this._editors,this._diffModel,this._options,this))}))),this._register((0,c.yC)(((e,t)=>{const i=this._diffModel.read(e);if(i)for(const s of[i.model.original,i.model.modified])t.add(s.onWillDispose((e=>{(0,r.dz)(new r.D7("TextModel got disposed before DiffEditorWidget model got reset")),this.setModel(null)})))}))),this._register((0,c.fm)((e=>{this._options.setModel(this._diffModel.read(e))})))}_createInnerEditor(e,t,i,s){return e.createInstance(g.x,t,i,s)}_createDiffEditorContributions(){const e=h.dS.getDiffEditorContributions();for(const i of e)try{this._register(this._instantiationService.createInstance(i.ctor,this))}catch(t){(0,r.dz)(t)}}get _targetEditor(){return this._editors.modified}getEditorType(){return bt._.IDiffEditor}layout(e){this._rootSizeObserver.observe(e)}hasTextFocus(){return this._editors.original.hasTextFocus()||this._editors.modified.hasTextFocus()}saveViewState(){return{original:this._editors.original.saveViewState(),modified:this._editors.modified.saveViewState(),modelState:this._diffModel.get()?.serializeState()}}restoreViewState(e){if(e&&e.original&&e.modified){const t=e;this._editors.original.restoreViewState(t.original),this._editors.modified.restoreViewState(t.modified),t.modelState&&this._diffModel.get()?.restoreSerializedState(t.modelState)}}handleInitialized(){this._editors.original.handleInitialized(),this._editors.modified.handleInitialized()}createViewModel(e){return this._instantiationService.createInstance(ue,e,this._options)}getModel(){return this._diffModel.get()?.model??null}setModel(e){const t=e?"model"in e?S.O8.create(e).createNewRef(this):S.O8.create(this.createViewModel(e),this):null;this.setDiffModel(t)}setDiffModel(e,t){const i=this._diffModel.get();!e&&i&&this._accessibleDiffViewer.get().close(),this._diffModel.get()!==e?.object&&(0,c.PO)(t,(t=>{const i=e?.object;c.y0.batchEventsGlobally(t,(()=>{this._editors.original.setModel(i?i.model.original:null),this._editors.modified.setModel(i?i.model.modified:null)}));const s=this._diffModelSrc.get()?.createNewRef(this);this._diffModelSrc.set(e?.createNewRef(this),t),setTimeout((()=>{s?.dispose()}),0)}))}updateOptions(e){this._options.updateOptions(e)}getContainerDomNode(){return this._domElement}getOriginalEditor(){return this._editors.original}getModifiedEditor(){return this._editors.modified}getLineChanges(){const e=this._diffModel.get()?.diff.get();return e?e.mappings.map((e=>{const t=e.lineRangeMapping;let i,s,n,r,o=t.innerChanges;return t.original.isEmpty?(i=t.original.startLineNumber-1,s=0,o=void 0):(i=t.original.startLineNumber,s=t.original.endLineNumberExclusive-1),t.modified.isEmpty?(n=t.modified.startLineNumber-1,r=0,o=void 0):(n=t.modified.startLineNumber,r=t.modified.endLineNumberExclusive-1),{originalStartLineNumber:i,originalEndLineNumber:s,modifiedStartLineNumber:n,modifiedEndLineNumber:r,charChanges:o?.map((e=>({originalStartLineNumber:e.originalRange.startLineNumber,originalStartColumn:e.originalRange.startColumn,originalEndLineNumber:e.originalRange.endLineNumber,originalEndColumn:e.originalRange.endColumn,modifiedStartLineNumber:e.modifiedRange.startLineNumber,modifiedStartColumn:e.modifiedRange.startColumn,modifiedEndLineNumber:e.modifiedRange.endLineNumber,modifiedEndColumn:e.modifiedRange.endColumn})))}})):null}revert(e){const t=this._diffModel.get();t&&t.isDiffUpToDate.get()&&this._editors.modified.executeEdits("diffEditor",[{range:e.modified.toExclusiveRange(),text:t.model.original.getValueInRange(e.original.toExclusiveRange())}])}revertRangeMappings(e){const t=this._diffModel.get();if(!t||!t.isDiffUpToDate.get())return;const i=e.map((e=>({range:e.modifiedRange,text:t.model.original.getValueInRange(e.originalRange)})));this._editors.modified.executeEdits("diffEditor",i)}_goTo(e){this._editors.modified.setPosition(new L.y(e.lineRangeMapping.modified.startLineNumber,1)),this._editors.modified.revealRangeInCenter(e.lineRangeMapping.modified.toExclusiveRange())}goToDiff(e){const t=this._diffModel.get()?.diff.get()?.mappings;if(!t||0===t.length)return;const i=this._editors.modified.getPosition().lineNumber;let s;s="next"===e?t.find((e=>e.lineRangeMapping.modified.startLineNumber>i))??t[0]:(0,n.Uk)(t,(e=>e.lineRangeMapping.modified.startLineNumber{const t=e.diff.get()?.mappings;t&&0!==t.length&&this._goTo(t[0])}))}accessibleDiffViewerNext(){this._accessibleDiffViewer.get().next()}accessibleDiffViewerPrev(){this._accessibleDiffViewer.get().prev()}async waitForDiff(){const e=this._diffModel.get();e&&await e.waitForDiff()}mapToOtherSide(){const e=this._editors.modified.hasWidgetFocus(),t=e?this._editors.modified:this._editors.original,i=e?this._editors.original:this._editors.modified;let s;const n=t.getSelection();if(n){const t=this._diffModel.get()?.diff.get()?.mappings.map((t=>e?t.lineRangeMapping.flip():t.lineRangeMapping));if(t){const e=(0,S.Mu)(n.getStartPosition(),t),i=(0,S.Mu)(n.getEndPosition(),t);s=T.Q.plusRange(e,i)}}return{destination:i,destinationSelection:s}}switchSide(){const{destination:e,destinationSelection:t}=this.mapToOtherSide();e.focus(),t&&e.setSelection(t)}exitCompareMove(){const e=this._diffModel.get();e&&e.movedTextToCompare.set(void 0,void 0)}collapseAllUnchangedRegions(){const e=this._diffModel.get()?.unchangedRegions.get();e&&(0,c.Rn)((t=>{for(const i of e)i.collapseAll(t)}))}showAllUnchangedRegions(){const e=this._diffModel.get()?.unchangedRegions.get();e&&(0,c.Rn)((t=>{for(const i of e)i.showAll(t)}))}_handleCursorPositionChange(e,t){if(3===e?.reason){const i=this._diffModel.get()?.diff.get()?.mappings.find((i=>t?i.lineRangeMapping.modified.contains(e.position.lineNumber):i.lineRangeMapping.original.contains(e.position.lineNumber)));i?.lineRangeMapping.modified.isEmpty?this._accessibilitySignalService.playSignal(D.Rh.diffLineDeleted,{source:"diffEditor.cursorPositionChanged"}):i?.lineRangeMapping.original.isEmpty?this._accessibilitySignalService.playSignal(D.Rh.diffLineInserted,{source:"diffEditor.cursorPositionChanged"}):i&&this._accessibilitySignalService.playSignal(D.Rh.diffLineModified,{source:"diffEditor.cursorPositionChanged"})}}};Bt=Ut([Ht(3,Xe.fN),Ht(4,M._Y),Ht(5,d.T),Ht(6,D.Nt),Ht(7,wt.N8)],Bt)},4519:(e,t,i)=>{"use strict";var s=i(91090),n=i(5662),r=i(31450),o=i(60002),a=i(62083),c=i(56942),l=i(90766),h=i(64383),d=i(41234),u=i(60534),g=i(18447),p=i(631),m=i(79400),f=i(83069),_=i(18938),v=i(50091),C=i(32848);const E={Visible:new C.N1("parameterHintsVisible",!1),MultipleSignatures:new C.N1("parameterHintsMultipleSignatures",!1)};async function b(e,t,i,s,n){const r=e.ordered(t);for(const a of r)try{const e=await a.provideSignatureHelp(t,i,n,s);if(e)return e}catch(o){(0,h.M_)(o)}}var S;v.w.registerCommand("_executeSignatureHelpProvider",(async(e,...t)=>{const[i,s,n]=t;(0,p.j)(m.r.isUri(i)),(0,p.j)(f.y.isIPosition(s)),(0,p.j)("string"===typeof n||!n);const r=e.get(c.ILanguageFeaturesService),o=await e.get(_.ITextModelService).createModelReference(i);try{const e=await b(r.signatureHelpProvider,o.object.textEditorModel,f.y.lift(s),{triggerKind:a.WA.Invoke,isRetrigger:!1,triggerCharacter:n},g.XO.None);if(!e)return;return setTimeout((()=>e.dispose()),0),e.value}finally{o.dispose()}})),function(e){e.Default={type:0};e.Pending=class{constructor(e,t){this.request=e,this.previouslyActiveHints=t,this.type=2}};e.Active=class{constructor(e){this.hints=e,this.type=1}}}(S||(S={}));class y extends n.jG{static{this.DEFAULT_DELAY=120}constructor(e,t,i=y.DEFAULT_DELAY){super(),this._onChangedHints=this._register(new d.vl),this.onChangedHints=this._onChangedHints.event,this.triggerOnType=!1,this._state=S.Default,this._pendingTriggers=[],this._lastSignatureHelpResult=this._register(new n.HE),this.triggerChars=new u.y,this.retriggerChars=new u.y,this.triggerId=0,this.editor=e,this.providers=t,this.throttledDelayer=new l.ve(i),this._register(this.editor.onDidBlurEditorWidget((()=>this.cancel()))),this._register(this.editor.onDidChangeConfiguration((()=>this.onEditorConfigurationChange()))),this._register(this.editor.onDidChangeModel((e=>this.onModelChanged()))),this._register(this.editor.onDidChangeModelLanguage((e=>this.onModelChanged()))),this._register(this.editor.onDidChangeCursorSelection((e=>this.onCursorChange(e)))),this._register(this.editor.onDidChangeModelContent((e=>this.onModelContentChange()))),this._register(this.providers.onDidChange(this.onModelChanged,this)),this._register(this.editor.onDidType((e=>this.onDidType(e)))),this.onEditorConfigurationChange(),this.onModelChanged()}get state(){return this._state}set state(e){2===this._state.type&&this._state.request.cancel(),this._state=e}cancel(e=!1){this.state=S.Default,this.throttledDelayer.cancel(),e||this._onChangedHints.fire(void 0)}trigger(e,t){const i=this.editor.getModel();if(!i||!this.providers.has(i))return;const s=++this.triggerId;this._pendingTriggers.push(e),this.throttledDelayer.trigger((()=>this.doTrigger(s)),t).catch(h.dz)}next(){if(1!==this.state.type)return;const e=this.state.hints.signatures.length,t=this.state.hints.activeSignature,i=t%e===e-1,s=this.editor.getOption(86).cycle;!(e<2||i)||s?this.updateActiveSignature(i&&s?0:t+1):this.cancel()}previous(){if(1!==this.state.type)return;const e=this.state.hints.signatures.length,t=this.state.hints.activeSignature,i=0===t,s=this.editor.getOption(86).cycle;!(e<2||i)||s?this.updateActiveSignature(i&&s?e-1:t-1):this.cancel()}updateActiveSignature(e){1===this.state.type&&(this.state=new S.Active({...this.state.hints,activeSignature:e}),this._onChangedHints.fire(this.state.hints))}async doTrigger(e){const t=1===this.state.type||2===this.state.type,i=this.getLastActiveHints();if(this.cancel(!0),0===this._pendingTriggers.length)return!1;const s=this._pendingTriggers.reduce(w);this._pendingTriggers=[];const n={triggerKind:s.triggerKind,triggerCharacter:s.triggerCharacter,isRetrigger:t,activeSignatureHelp:i};if(!this.editor.hasModel())return!1;const r=this.editor.getModel(),o=this.editor.getPosition();this.state=new S.Pending((0,l.SS)((e=>b(this.providers,r,o,n,e))),i);try{const t=await this.state.request;return e!==this.triggerId?(t?.dispose(),!1):t&&t.value.signatures&&0!==t.value.signatures.length?(this.state=new S.Active(t.value),this._lastSignatureHelpResult.value=t,this._onChangedHints.fire(this.state.hints),!0):(t?.dispose(),this._lastSignatureHelpResult.clear(),this.cancel(),!1)}catch(a){return e===this.triggerId&&(this.state=S.Default),(0,h.dz)(a),!1}}getLastActiveHints(){switch(this.state.type){case 1:return this.state.hints;case 2:return this.state.previouslyActiveHints;default:return}}get isTriggered(){return 1===this.state.type||2===this.state.type||this.throttledDelayer.isTriggered()}onModelChanged(){this.cancel(),this.triggerChars.clear(),this.retriggerChars.clear();const e=this.editor.getModel();if(e)for(const t of this.providers.ordered(e)){for(const e of t.signatureHelpTriggerCharacters||[])if(e.length){const t=e.charCodeAt(0);this.triggerChars.add(t),this.retriggerChars.add(t)}for(const e of t.signatureHelpRetriggerCharacters||[])e.length&&this.retriggerChars.add(e.charCodeAt(0))}}onDidType(e){if(!this.triggerOnType)return;const t=e.length-1,i=e.charCodeAt(t);(this.triggerChars.has(i)||this.isTriggered&&this.retriggerChars.has(i))&&this.trigger({triggerKind:a.WA.TriggerCharacter,triggerCharacter:e.charAt(t)})}onCursorChange(e){"mouse"===e.source?this.cancel():this.isTriggered&&this.trigger({triggerKind:a.WA.ContentChange})}onModelContentChange(){this.isTriggered&&this.trigger({triggerKind:a.WA.ContentChange})}onEditorConfigurationChange(){this.triggerOnType=this.editor.getOption(86).enabled,this.triggerOnType||this.cancel()}dispose(){this.cancel(!0),super.dispose()}}function w(e,t){switch(t.triggerKind){case a.WA.Invoke:return t;case a.WA.ContentChange:return e;case a.WA.TriggerCharacter:default:return t}}var R,L=i(78209),T=i(63591),x=i(8597),k=i(11007),A=i(31295),N=i(10350),I=i(91508),O=i(87908),D=i(10154),M=i(20492),P=i(49099),F=i(66261),U=i(61394),H=i(25689),B=i(78381),W=i(90651),V=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},z=function(e,t){return function(i,s){t(i,s,e)}};const G=x.$,j=(0,U.pU)("parameter-hints-next",N.W.chevronDown,L.kg("parameterHintsNextIcon","Icon for show next parameter hint.")),K=(0,U.pU)("parameter-hints-previous",N.W.chevronUp,L.kg("parameterHintsPreviousIcon","Icon for show previous parameter hint."));let Y=class extends n.jG{static{R=this}static{this.ID="editor.widget.parameterHintsWidget"}constructor(e,t,i,s,r,o){super(),this.editor=e,this.model=t,this.telemetryService=o,this.renderDisposeables=this._register(new n.Cm),this.visible=!1,this.announcedLabel=null,this.allowEditorOverflow=!0,this.markdownRenderer=this._register(new M.T({editor:e},r,s)),this.keyVisible=E.Visible.bindTo(i),this.keyMultipleSignatures=E.MultipleSignatures.bindTo(i)}createParameterHintDOMNodes(){const e=G(".editor-widget.parameter-hints-widget"),t=x.BC(e,G(".phwrapper"));t.tabIndex=-1;const i=x.BC(t,G(".controls")),s=x.BC(i,G(".button"+H.L.asCSSSelector(K))),n=x.BC(i,G(".overloads")),r=x.BC(i,G(".button"+H.L.asCSSSelector(j)));this._register(x.ko(s,"click",(e=>{x.fs.stop(e),this.previous()}))),this._register(x.ko(r,"click",(e=>{x.fs.stop(e),this.next()})));const o=G(".body"),a=new A.MU(o,{alwaysConsumeMouseWheel:!0});this._register(a),t.appendChild(a.getDomNode());const c=x.BC(o,G(".signature")),l=x.BC(o,G(".docs"));e.style.userSelect="text",this.domNodes={element:e,signature:c,overloads:n,docs:l,scrollbar:a},this.editor.addContentWidget(this),this.hide(),this._register(this.editor.onDidChangeCursorSelection((e=>{this.visible&&this.editor.layoutContentWidget(this)})));const h=()=>{if(!this.domNodes)return;const e=this.editor.getOption(50),t=this.domNodes.element;t.style.fontSize=`${e.fontSize}px`,t.style.lineHeight=""+e.lineHeight/e.fontSize,t.style.setProperty("--vscode-parameterHintsWidget-editorFontFamily",e.fontFamily),t.style.setProperty("--vscode-parameterHintsWidget-editorFontFamilyDefault",O.jU.fontFamily)};h(),this._register(d.Jh.chain(this.editor.onDidChangeConfiguration.bind(this.editor),(e=>e.filter((e=>e.hasChanged(50)))))(h)),this._register(this.editor.onDidLayoutChange((e=>this.updateMaxHeight()))),this.updateMaxHeight()}show(){this.visible||(this.domNodes||this.createParameterHintDOMNodes(),this.keyVisible.set(!0),this.visible=!0,setTimeout((()=>{this.domNodes?.element.classList.add("visible")}),100),this.editor.layoutContentWidget(this))}hide(){this.renderDisposeables.clear(),this.visible&&(this.keyVisible.reset(),this.visible=!1,this.announcedLabel=null,this.domNodes?.element.classList.remove("visible"),this.editor.layoutContentWidget(this))}getPosition(){return this.visible?{position:this.editor.getPosition(),preference:[1,2]}:null}render(e){if(this.renderDisposeables.clear(),!this.domNodes)return;const t=e.signatures.length>1;this.domNodes.element.classList.toggle("multiple",t),this.keyMultipleSignatures.set(t),this.domNodes.signature.innerText="",this.domNodes.docs.innerText="";const i=e.signatures[e.activeSignature];if(!i)return;const s=x.BC(this.domNodes.signature,G(".code")),n=i.parameters.length>0,r=i.activeParameter??e.activeParameter;if(n)this.renderParameters(s,i,r);else{x.BC(s,G("span")).textContent=i.label}const o=i.parameters[r];if(o?.documentation){const e=G("span.documentation");if("string"===typeof o.documentation)e.textContent=o.documentation;else{const t=this.renderMarkdownDocs(o.documentation);e.appendChild(t.element)}x.BC(this.domNodes.docs,G("p",{},e))}if(void 0===i.documentation);else if("string"===typeof i.documentation)x.BC(this.domNodes.docs,G("p",{},i.documentation));else{const e=this.renderMarkdownDocs(i.documentation);x.BC(this.domNodes.docs,e.element)}const a=this.hasDocs(i,o);if(this.domNodes.signature.classList.toggle("has-docs",a),this.domNodes.docs.classList.toggle("empty",!a),this.domNodes.overloads.textContent=String(e.activeSignature+1).padStart(e.signatures.length.toString().length,"0")+"/"+e.signatures.length,o){let e="";const t=i.parameters[r];e=Array.isArray(t.label)?i.label.substring(t.label[0],t.label[1]):t.label,t.documentation&&(e+="string"===typeof t.documentation?`, ${t.documentation}`:`, ${t.documentation.value}`),i.documentation&&(e+="string"===typeof i.documentation?`, ${i.documentation}`:`, ${i.documentation.value}`),this.announcedLabel!==e&&(k.xE(L.kg("hint","{0}, hint",e)),this.announcedLabel=e)}this.editor.layoutContentWidget(this),this.domNodes.scrollbar.scanDomNode()}renderMarkdownDocs(e){const t=new B.W,i=this.renderDisposeables.add(this.markdownRenderer.render(e,{asyncRenderCallback:()=>{this.domNodes?.scrollbar.scanDomNode()}}));i.element.classList.add("markdown-docs");const s=t.elapsed();return s>300&&this.telemetryService.publicLog2("parameterHints.parseMarkdown",{renderDuration:s}),i}hasDocs(e,t){return!!(t&&"string"===typeof t.documentation&&(0,p.eU)(t.documentation).length>0)||(!!(t&&"object"===typeof t.documentation&&(0,p.eU)(t.documentation).value.length>0)||(!!(e.documentation&&"string"===typeof e.documentation&&(0,p.eU)(e.documentation).length>0)||!!(e.documentation&&"object"===typeof e.documentation&&(0,p.eU)(e.documentation.value).length>0)))}renderParameters(e,t,i){const[s,n]=this.getParameterLabelOffsets(t,i),r=document.createElement("span");r.textContent=t.label.substring(0,s);const o=document.createElement("span");o.textContent=t.label.substring(s,n),o.className="parameter active";const a=document.createElement("span");a.textContent=t.label.substring(n),x.BC(e,r,o,a)}getParameterLabelOffsets(e,t){const i=e.parameters[t];if(i){if(Array.isArray(i.label))return i.label;if(i.label.length){const t=new RegExp(`(\\W|^)${(0,I.bm)(i.label)}(?=\\W|$)`,"g");t.test(e.label);const s=t.lastIndex-i.label.length;return s>=0?[s,t.lastIndex]:[0,0]}return[0,0]}return[0,0]}next(){this.editor.focus(),this.model.next()}previous(){this.editor.focus(),this.model.previous()}getDomNode(){return this.domNodes||this.createParameterHintDOMNodes(),this.domNodes.element}getId(){return R.ID}updateMaxHeight(){if(!this.domNodes)return;const e=`${Math.max(this.editor.getLayoutInfo().height/4,250)}px`;this.domNodes.element.style.maxHeight=e;const t=this.domNodes.element.getElementsByClassName("phwrapper");t.length&&(t[0].style.maxHeight=e)}};Y=R=V([z(2,C.fN),z(3,P.C),z(4,D.L),z(5,W.k)],Y),(0,F.x1A)("editorHoverWidget.highlightForeground",F.QI5,L.kg("editorHoverWidgetHighlightForeground","Foreground color of the active item in the parameter hint."));var q,$=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},Q=function(e,t){return function(i,s){t(i,s,e)}};let X=class extends n.jG{static{q=this}static{this.ID="editor.controller.parameterHints"}static get(e){return e.getContribution(q.ID)}constructor(e,t,i){super(),this.editor=e,this.model=this._register(new y(e,i.signatureHelpProvider)),this._register(this.model.onChangedHints((e=>{e?(this.widget.value.show(),this.widget.value.render(e)):this.widget.rawValue?.hide()}))),this.widget=new s.d((()=>this._register(t.createInstance(Y,this.editor,this.model))))}cancel(){this.model.cancel()}previous(){this.widget.rawValue?.previous()}next(){this.widget.rawValue?.next()}trigger(e){this.model.trigger(e,0)}};X=q=$([Q(1,T._Y),Q(2,c.ILanguageFeaturesService)],X);class Z extends r.ks{constructor(){super({id:"editor.action.triggerParameterHints",label:L.kg("parameterHints.trigger.label","Trigger Parameter Hints"),alias:"Trigger Parameter Hints",precondition:o.R.hasSignatureHelpProvider,kbOpts:{kbExpr:o.R.editorTextFocus,primary:3082,weight:100}})}run(e,t){const i=X.get(t);i?.trigger({triggerKind:a.WA.Invoke})}}(0,r.HW)(X.ID,X,2),(0,r.Fl)(Z);const J=r.DX.bindToContribution(X.get);(0,r.E_)(new J({id:"closeParameterHints",precondition:E.Visible,handler:e=>e.cancel(),kbOpts:{weight:175,kbExpr:o.R.focus,primary:9,secondary:[1033]}})),(0,r.E_)(new J({id:"showPrevParameterHint",precondition:C.M$.and(E.Visible,E.MultipleSignatures),handler:e=>e.previous(),kbOpts:{weight:175,kbExpr:o.R.focus,primary:16,secondary:[528],mac:{primary:16,secondary:[528,302]}}})),(0,r.E_)(new J({id:"showNextParameterHint",precondition:C.M$.and(E.Visible,E.MultipleSignatures),handler:e=>e.next(),kbOpts:{weight:175,kbExpr:o.R.focus,primary:18,secondary:[530],mac:{primary:18,secondary:[530,300]}}}))},4836:(e,t,i)=>{"use strict";var s=i(31450),n=i(94371),r=i(8995),o=i(91508),a=i(60002),c=i(55130),l=i(78209),h=i(32848),d=i(61407),u=i(71933),g=i(59473);function p(e){return h.M$.regex(g.D_.keys()[0],new RegExp("(\\s|^)"+(0,o.bm)(e.value)+"\\b"))}const m={type:"object",defaultSnippets:[{body:{kind:""}}],properties:{kind:{type:"string",description:l.kg("args.schema.kind","Kind of the code action to run.")},apply:{type:"string",description:l.kg("args.schema.apply","Controls when the returned actions are applied."),default:"ifSingle",enum:["first","ifSingle","never"],enumDescriptions:[l.kg("args.schema.apply.first","Always apply the first returned code action."),l.kg("args.schema.apply.ifSingle","Apply the first returned code action if it is the only one."),l.kg("args.schema.apply.never","Do not apply the returned code actions.")]},preferred:{type:"boolean",default:!1,description:l.kg("args.schema.preferred","Controls if only preferred code actions should be returned.")}}};function f(e,t,i,s,n=d.fo.Default){if(e.hasModel()){const r=u.C.get(e);r?.manualTriggerAtCurrentPosition(t,n,i,s)}}class _ extends s.ks{constructor(){super({id:c.pQ,label:l.kg("quickfix.trigger.label","Quick Fix..."),alias:"Quick Fix...",precondition:h.M$.and(a.R.writable,a.R.hasCodeActionsProvider),kbOpts:{kbExpr:a.R.textInputFocus,primary:2137,weight:100}})}run(e,t){return f(t,l.kg("editor.action.quickFix.noneMessage","No code actions available"),void 0,void 0,d.fo.QuickFix)}}class v extends s.DX{constructor(){super({id:c.k_,precondition:h.M$.and(a.R.writable,a.R.hasCodeActionsProvider),metadata:{description:"Trigger a code action",args:[{name:"args",schema:m}]}})}runEditorCommand(e,t,i){const s=d.QA.fromUser(i,{kind:r.k.Empty,apply:"ifSingle"});return f(t,"string"===typeof i?.kind?s.preferred?l.kg("editor.action.codeAction.noneMessage.preferred.kind","No preferred code actions for '{0}' available",i.kind):l.kg("editor.action.codeAction.noneMessage.kind","No code actions for '{0}' available",i.kind):s.preferred?l.kg("editor.action.codeAction.noneMessage.preferred","No preferred code actions available"):l.kg("editor.action.codeAction.noneMessage","No code actions available"),{include:s.kind,includeSourceActions:!0,onlyIncludePreferredActions:s.preferred},s.apply)}}class C extends s.ks{constructor(){super({id:c.Xj,label:l.kg("refactor.label","Refactor..."),alias:"Refactor...",precondition:h.M$.and(a.R.writable,a.R.hasCodeActionsProvider),kbOpts:{kbExpr:a.R.textInputFocus,primary:3120,mac:{primary:1328},weight:100},contextMenuOpts:{group:"1_modification",order:2,when:h.M$.and(a.R.writable,p(d.gB.Refactor))},metadata:{description:"Refactor...",args:[{name:"args",schema:m}]}})}run(e,t,i){const s=d.QA.fromUser(i,{kind:d.gB.Refactor,apply:"never"});return f(t,"string"===typeof i?.kind?s.preferred?l.kg("editor.action.refactor.noneMessage.preferred.kind","No preferred refactorings for '{0}' available",i.kind):l.kg("editor.action.refactor.noneMessage.kind","No refactorings for '{0}' available",i.kind):s.preferred?l.kg("editor.action.refactor.noneMessage.preferred","No preferred refactorings available"):l.kg("editor.action.refactor.noneMessage","No refactorings available"),{include:d.gB.Refactor.contains(s.kind)?s.kind:r.k.None,onlyIncludePreferredActions:s.preferred},s.apply,d.fo.Refactor)}}class E extends s.ks{constructor(){super({id:c.C9,label:l.kg("source.label","Source Action..."),alias:"Source Action...",precondition:h.M$.and(a.R.writable,a.R.hasCodeActionsProvider),contextMenuOpts:{group:"1_modification",order:2.1,when:h.M$.and(a.R.writable,p(d.gB.Source))},metadata:{description:"Source Action...",args:[{name:"args",schema:m}]}})}run(e,t,i){const s=d.QA.fromUser(i,{kind:d.gB.Source,apply:"never"});return f(t,"string"===typeof i?.kind?s.preferred?l.kg("editor.action.source.noneMessage.preferred.kind","No preferred source actions for '{0}' available",i.kind):l.kg("editor.action.source.noneMessage.kind","No source actions for '{0}' available",i.kind):s.preferred?l.kg("editor.action.source.noneMessage.preferred","No preferred source actions available"):l.kg("editor.action.source.noneMessage","No source actions available"),{include:d.gB.Source.contains(s.kind)?s.kind:r.k.None,includeSourceActions:!0,onlyIncludePreferredActions:s.preferred},s.apply,d.fo.SourceAction)}}class b extends s.ks{constructor(){super({id:c.Uy,label:l.kg("organizeImports.label","Organize Imports"),alias:"Organize Imports",precondition:h.M$.and(a.R.writable,p(d.gB.SourceOrganizeImports)),kbOpts:{kbExpr:a.R.textInputFocus,primary:1581,weight:100}})}run(e,t){return f(t,l.kg("editor.action.organize.noneMessage","No organize imports action available"),{include:d.gB.SourceOrganizeImports,includeSourceActions:!0},"ifSingle",d.fo.OrganizeImports)}}class S extends s.ks{constructor(){super({id:c.Rw,label:l.kg("fixAll.label","Fix All"),alias:"Fix All",precondition:h.M$.and(a.R.writable,p(d.gB.SourceFixAll))})}run(e,t){return f(t,l.kg("fixAll.noneMessage","No fix all action available"),{include:d.gB.SourceFixAll,includeSourceActions:!0},"ifSingle",d.fo.FixAll)}}class y extends s.ks{constructor(){super({id:c.pR,label:l.kg("autoFix.label","Auto Fix..."),alias:"Auto Fix...",precondition:h.M$.and(a.R.writable,p(d.gB.QuickFix)),kbOpts:{kbExpr:a.R.textInputFocus,primary:1625,mac:{primary:2649},weight:100}})}run(e,t){return f(t,l.kg("editor.action.autoFix.noneMessage","No auto fixes available"),{include:d.gB.QuickFix,onlyIncludePreferredActions:!0},"ifSingle",d.fo.AutoFix)}}var w=i(96758),R=i(1646),L=i(46359);(0,s.HW)(u.C.ID,u.C,3),(0,s.HW)(w.E.ID,w.E,4),(0,s.Fl)(_),(0,s.Fl)(C),(0,s.Fl)(E),(0,s.Fl)(b),(0,s.Fl)(y),(0,s.Fl)(S),(0,s.E_)(new v),L.O.as(R.Fd.Configuration).registerConfiguration({...n.JJ,properties:{"editor.codeActionWidget.showHeaders":{type:"boolean",scope:5,description:l.kg("showCodeActionHeaders","Enable/disable showing group headers in the Code Action menu."),default:!0}}}),L.O.as(R.Fd.Configuration).registerConfiguration({...n.JJ,properties:{"editor.codeActionWidget.includeNearbyQuickFixes":{type:"boolean",scope:5,description:l.kg("includeNearbyQuickFixes","Enable/disable showing nearest Quick Fix within a line when not currently on a diagnostic."),default:!0}}}),L.O.as(R.Fd.Configuration).registerConfiguration({...n.JJ,properties:{"editor.codeActions.triggerOnFocusChange":{type:"boolean",scope:5,markdownDescription:l.kg("triggerOnFocusChange","Enable triggering {0} when {1} is set to {2}. Code Actions must be set to {3} to be triggered for window and focus changes.","`#editor.codeActionsOnSave#`","`#files.autoSave#`","`afterDelay`","`always`"),default:!1}}})},4853:(e,t,i)=>{"use strict";i.d(t,{cB:()=>l});var s=i(91508);class n{constructor(){this._value="",this._pos=0}reset(e){return this._value=e,this._pos=0,this}next(){return this._pos+=1,this}hasNext(){return this._pos=0;t--,this._valueLen--){const e=this._value.charCodeAt(t);if(!(47===e||this._splitOnBackslash&&92===e))break}return this.next()}hasNext(){return this._to!1,t=()=>!1){return new l(new a(e,t))}static forStrings(){return new l(new n)}static forConfigKeys(){return new l(new r)}constructor(e){this._iter=e}clear(){this._root=void 0}set(e,t){const i=this._iter.reset(e);let s;this._root||(this._root=new c,this._root.segment=i.value());const n=[];for(s=this._root;;){const e=i.cmp(s.segment);if(e>0)s.left||(s.left=new c,s.left.segment=i.value()),n.push([-1,s]),s=s.left;else if(e<0)s.right||(s.right=new c,s.right.segment=i.value()),n.push([1,s]),s=s.right;else{if(!i.hasNext())break;i.next(),s.mid||(s.mid=new c,s.mid.segment=i.value()),n.push([0,s]),s=s.mid}}const r=s.value;s.value=t,s.key=e;for(let o=n.length-1;o>=0;o--){const e=n[o][1];e.updateHeight();const t=e.balanceFactor();if(t<-1||t>1){const t=n[o][0],i=n[o+1][0];if(1===t&&1===i)n[o][1]=e.rotateLeft();else if(-1===t&&-1===i)n[o][1]=e.rotateRight();else if(1===t&&-1===i)e.right=n[o+1][1]=n[o+1][1].rotateRight(),n[o][1]=e.rotateLeft();else{if(-1!==t||1!==i)throw new Error;e.left=n[o+1][1]=n[o+1][1].rotateLeft(),n[o][1]=e.rotateRight()}if(o>0)switch(n[o-1][0]){case-1:n[o-1][1].left=n[o][1];break;case 1:n[o-1][1].right=n[o][1];break;case 0:n[o-1][1].mid=n[o][1]}else this._root=n[0][1]}}return r}get(e){return this._getNode(e)?.value}_getNode(e){const t=this._iter.reset(e);let i=this._root;for(;i;){const e=t.cmp(i.segment);if(e>0)i=i.left;else if(e<0)i=i.right;else{if(!t.hasNext())break;t.next(),i=i.mid}}return i}has(e){const t=this._getNode(e);return!(void 0===t?.value&&void 0===t?.mid)}delete(e){return this._delete(e,!1)}deleteSuperstr(e){return this._delete(e,!0)}_delete(e,t){const i=this._iter.reset(e),s=[];let n=this._root;for(;n;){const e=i.cmp(n.segment);if(e>0)s.push([-1,n]),n=n.left;else if(e<0)s.push([1,n]),n=n.right;else{if(!i.hasNext())break;i.next(),s.push([0,n]),n=n.mid}}if(n){if(t?(n.left=void 0,n.mid=void 0,n.right=void 0,n.height=1):(n.key=void 0,n.value=void 0),!n.mid&&!n.value)if(n.left&&n.right){const e=this._min(n.right);if(e.key){const{key:t,value:i,segment:s}=e;this._delete(e.key,!1),n.key=t,n.value=i,n.segment=s}}else{const e=n.left??n.right;if(s.length>0){const[t,i]=s[s.length-1];switch(t){case-1:i.left=e;break;case 0:i.mid=e;break;case 1:i.right=e}}else this._root=e}for(let e=s.length-1;e>=0;e--){const t=s[e][1];t.updateHeight();const i=t.balanceFactor();if(i>1?(t.right.balanceFactor()>=0||(t.right=t.right.rotateRight()),s[e][1]=t.rotateLeft()):i<-1&&(t.left.balanceFactor()<=0||(t.left=t.left.rotateLeft()),s[e][1]=t.rotateRight()),e>0)switch(s[e-1][0]){case-1:s[e-1][1].left=s[e][1];break;case 1:s[e-1][1].right=s[e][1];break;case 0:s[e-1][1].mid=s[e][1]}else this._root=s[0][1]}}}_min(e){for(;e.left;)e=e.left;return e}findSubstr(e){const t=this._iter.reset(e);let i,s=this._root;for(;s;){const e=t.cmp(s.segment);if(e>0)s=s.left;else if(e<0)s=s.right;else{if(!t.hasNext())break;t.next(),i=s.value||i,s=s.mid}}return s&&s.value||i}findSuperstr(e){return this._findSuperstrOrElement(e,!1)}_findSuperstrOrElement(e,t){const i=this._iter.reset(e);let s=this._root;for(;s;){const e=i.cmp(s.segment);if(e>0)s=s.left;else if(e<0)s=s.right;else{if(!i.hasNext())return s.mid?this._entries(s.mid):t?s.value:void 0;i.next(),s=s.mid}}}forEach(e){for(const[t,i]of this)e(i,t)}*[Symbol.iterator](){yield*this._entries(this._root)}_entries(e){const t=[];return this._dfsEntries(e,t),t[Symbol.iterator]()}_dfsEntries(e,t){e&&(e.left&&this._dfsEntries(e.left,t),e.value&&t.push([e.key,e.value]),e.mid&&this._dfsEntries(e.mid,t),e.right&&this._dfsEntries(e.right,t))}}},4983:(e,t,i)=>{"use strict";i.d(t,{u:()=>o});var s=i(5662),n=i(41234),r=i(8597);class o extends s.jG{constructor(e,t){super(),this._onDidChange=this._register(new n.vl),this.onDidChange=this._onDidChange.event,this._referenceDomElement=e,this._width=-1,this._height=-1,this._resizeObserver=null,this.measureReferenceDomElement(!1,t)}dispose(){this.stopObserving(),super.dispose()}getWidth(){return this._width}getHeight(){return this._height}startObserving(){if(!this._resizeObserver&&this._referenceDomElement){let e=null;const t=()=>{e?this.observe({width:e.width,height:e.height}):this.observe()};let i=!1,s=!1;const n=()=>{if(i&&!s)try{i=!1,s=!0,t()}finally{(0,r.PG)((0,r.zk)(this._referenceDomElement),(()=>{s=!1,n()}))}};this._resizeObserver=new ResizeObserver((t=>{e=t&&t[0]&&t[0].contentRect?{width:t[0].contentRect.width,height:t[0].contentRect.height}:null,i=!0,n()})),this._resizeObserver.observe(this._referenceDomElement)}}stopObserving(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null)}observe(e){this.measureReferenceDomElement(!0,e)}measureReferenceDomElement(e,t){let i=0,s=0;t?(i=t.width,s=t.height):this._referenceDomElement&&(i=this._referenceDomElement.clientWidth,s=this._referenceDomElement.clientHeight),i=Math.max(5,i),s=Math.max(5,s),this._width===i&&this._height===s||(this._width=i,this._height=s,e&&this._onDidChange.fire())}}},5239:(e,t,i)=>{"use strict";var s;i.d(t,{p:()=>s}),function(e){const t={total:0,min:Number.MAX_VALUE,max:0},i={...t},s={...t},n={...t};let r=0;const o={keydown:0,input:0,render:0};function a(){1===o.keydown&&(performance.mark("keydown/end"),o.keydown=2)}function c(){performance.mark("input/start"),o.input=1,d()}function l(){1===o.input&&(performance.mark("input/end"),o.input=2)}function h(){1===o.render&&(performance.mark("render/end"),o.render=2)}function d(){setTimeout(u)}function u(){2===o.keydown&&2===o.input&&2===o.render&&(performance.mark("inputlatency/end"),performance.measure("keydown","keydown/start","keydown/end"),performance.measure("input","input/start","input/end"),performance.measure("render","render/start","render/end"),performance.measure("inputlatency","inputlatency/start","inputlatency/end"),g("keydown",t),g("input",i),g("render",s),g("inputlatency",n),r++,performance.clearMarks("keydown/start"),performance.clearMarks("keydown/end"),performance.clearMarks("input/start"),performance.clearMarks("input/end"),performance.clearMarks("render/start"),performance.clearMarks("render/end"),performance.clearMarks("inputlatency/start"),performance.clearMarks("inputlatency/end"),performance.clearMeasures("keydown"),performance.clearMeasures("input"),performance.clearMeasures("render"),performance.clearMeasures("inputlatency"),o.keydown=0,o.input=0,o.render=0)}function g(e,t){const i=performance.getEntriesByName(e)[0].duration;t.total+=i,t.min=Math.min(t.min,i),t.max=Math.max(t.max,i)}function p(e){return{average:e.total/r,max:e.max,min:e.min}}function m(e){e.total=0,e.min=Number.MAX_VALUE,e.max=0}e.onKeyDown=function(){u(),performance.mark("inputlatency/start"),performance.mark("keydown/start"),o.keydown=1,queueMicrotask(a)},e.onBeforeInput=c,e.onInput=function(){0===o.input&&c(),queueMicrotask(l)},e.onKeyUp=function(){u()},e.onSelectionChange=function(){u()},e.onRenderStart=function(){2===o.keydown&&2===o.input&&0===o.render&&(performance.mark("render/start"),o.render=1,queueMicrotask(h),d())},e.getAndClearMeasurements=function(){if(0===r)return;const e={keydown:p(t),input:p(i),render:p(s),total:p(n),sampleCount:r};return m(t),m(i),m(s),m(n),r=0,e}}(s||(s={}))},5646:(e,t,i)=>{"use strict";i.d(t,{Z4:()=>k,EH:()=>x,XF:()=>A});var s=i(60413),n=i(42731),r=i(8597),o=i(25154),a=i(42904),c=i(56245),l=i(72962),h=i(68214),d=i(48196),u=i(93090),g=i(25890),p=i(41234),m=i(24939),f=i(5662),_=i(98067),v=i(78209);const C=r.$,E="selectOption.entry.template";class b{get templateId(){return E}renderTemplate(e){const t=Object.create(null);return t.root=e,t.text=r.BC(e,C(".option-text")),t.detail=r.BC(e,C(".option-detail")),t.decoratorRight=r.BC(e,C(".option-decorator-right")),t}renderElement(e,t,i){const s=i,n=e.text,r=e.detail,o=e.decoratorRight,a=e.isDisabled;s.text.textContent=n,s.detail.textContent=r||"",s.decoratorRight.innerText=o||"",a?s.root.classList.add("option-disabled"):s.root.classList.remove("option-disabled")}disposeTemplate(e){}}class S extends f.jG{static{this.DEFAULT_DROPDOWN_MINIMUM_BOTTOM_MARGIN=32}static{this.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN=2}static{this.DEFAULT_MINIMUM_VISIBLE_OPTIONS=3}constructor(e,t,i,s,n){super(),this.options=[],this._currentSelection=0,this._hasDetails=!1,this._skipLayout=!1,this._sticky=!1,this._isVisible=!1,this.styles=s,this.selectBoxOptions=n||Object.create(null),"number"!==typeof this.selectBoxOptions.minBottomMargin?this.selectBoxOptions.minBottomMargin=S.DEFAULT_DROPDOWN_MINIMUM_BOTTOM_MARGIN:this.selectBoxOptions.minBottomMargin<0&&(this.selectBoxOptions.minBottomMargin=0),this.selectElement=document.createElement("select"),this.selectElement.className="monaco-select-box monaco-select-box-dropdown-padding","string"===typeof this.selectBoxOptions.ariaLabel&&this.selectElement.setAttribute("aria-label",this.selectBoxOptions.ariaLabel),"string"===typeof this.selectBoxOptions.ariaDescription&&this.selectElement.setAttribute("aria-description",this.selectBoxOptions.ariaDescription),this._onDidSelect=new p.vl,this._register(this._onDidSelect),this.registerListeners(),this.constructSelectDropDown(i),this.selected=t||0,e&&this.setOptions(e,t),this.initStyleSheet()}setTitle(e){!this._hover&&e?this._hover=this._register((0,d.i)().setupManagedHover((0,a.nZ)("mouse"),this.selectElement,e)):this._hover&&this._hover.update(e)}getHeight(){return 22}getTemplateId(){return E}constructSelectDropDown(e){this.contextViewProvider=e,this.selectDropDownContainer=r.$(".monaco-select-box-dropdown-container"),this.selectDropDownContainer.classList.add("monaco-select-box-dropdown-padding"),this.selectionDetailsPane=r.BC(this.selectDropDownContainer,C(".select-box-details-pane"));const t=r.BC(this.selectDropDownContainer,C(".select-box-dropdown-container-width-control")),i=r.BC(t,C(".width-control-div"));this.widthControlElement=document.createElement("span"),this.widthControlElement.className="option-text-width-control",r.BC(i,this.widthControlElement),this._dropDownPosition=0,this.styleElement=r.li(this.selectDropDownContainer),this.selectDropDownContainer.setAttribute("draggable","true"),this._register(r.ko(this.selectDropDownContainer,r.Bx.DRAG_START,(e=>{r.fs.stop(e,!0)})))}registerListeners(){let e;this._register(r.b2(this.selectElement,"change",(e=>{this.selected=e.target.selectedIndex,this._onDidSelect.fire({index:e.target.selectedIndex,selected:e.target.value}),this.options[this.selected]&&this.options[this.selected].text&&this.setTitle(this.options[this.selected].text)}))),this._register(r.ko(this.selectElement,r.Bx.CLICK,(e=>{r.fs.stop(e),this._isVisible?this.hideSelectDropDown(!0):this.showSelectDropDown()}))),this._register(r.ko(this.selectElement,r.Bx.MOUSE_DOWN,(e=>{r.fs.stop(e)}))),this._register(r.ko(this.selectElement,"touchstart",(t=>{e=this._isVisible}))),this._register(r.ko(this.selectElement,"touchend",(t=>{r.fs.stop(t),e?this.hideSelectDropDown(!0):this.showSelectDropDown()}))),this._register(r.ko(this.selectElement,r.Bx.KEY_DOWN,(e=>{const t=new l.Z(e);let i=!1;_.zx?18!==t.keyCode&&16!==t.keyCode&&10!==t.keyCode&&3!==t.keyCode||(i=!0):(18===t.keyCode&&t.altKey||16===t.keyCode&&t.altKey||10===t.keyCode||3===t.keyCode)&&(i=!0),i&&(this.showSelectDropDown(),r.fs.stop(e,!0))})))}get onDidSelect(){return this._onDidSelect.event}setOptions(e,t){g.aI(this.options,e)||(this.options=e,this.selectElement.options.length=0,this._hasDetails=!1,this._cachedMaxDetailsHeight=void 0,this.options.forEach(((e,t)=>{this.selectElement.add(this.createOption(e.text,t,e.isDisabled)),"string"===typeof e.description&&(this._hasDetails=!0)}))),void 0!==t&&(this.select(t),this._currentSelection=this.selected)}setOptionsList(){this.selectList?.splice(0,this.selectList.length,this.options)}select(e){e>=0&&ethis.options.length-1?this.select(this.options.length-1):this.selected<0&&(this.selected=0),this.selectElement.selectedIndex=this.selected,this.options[this.selected]&&this.options[this.selected].text&&this.setTitle(this.options[this.selected].text)}focus(){this.selectElement&&(this.selectElement.tabIndex=0,this.selectElement.focus())}blur(){this.selectElement&&(this.selectElement.tabIndex=-1,this.selectElement.blur())}setFocusable(e){this.selectElement.tabIndex=e?0:-1}render(e){this.container=e,e.classList.add("select-container"),e.appendChild(this.selectElement),this.styleSelectElement()}initStyleSheet(){const e=[];this.styles.listFocusBackground&&e.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.focused { background-color: ${this.styles.listFocusBackground} !important; }`),this.styles.listFocusForeground&&e.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.focused { color: ${this.styles.listFocusForeground} !important; }`),this.styles.decoratorRightForeground&&e.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row:not(.focused) .option-decorator-right { color: ${this.styles.decoratorRightForeground}; }`),this.styles.selectBackground&&this.styles.selectBorder&&this.styles.selectBorder!==this.styles.selectBackground?(e.push(`.monaco-select-box-dropdown-container { border: 1px solid ${this.styles.selectBorder} } `),e.push(`.monaco-select-box-dropdown-container > .select-box-details-pane.border-top { border-top: 1px solid ${this.styles.selectBorder} } `),e.push(`.monaco-select-box-dropdown-container > .select-box-details-pane.border-bottom { border-bottom: 1px solid ${this.styles.selectBorder} } `)):this.styles.selectListBorder&&(e.push(`.monaco-select-box-dropdown-container > .select-box-details-pane.border-top { border-top: 1px solid ${this.styles.selectListBorder} } `),e.push(`.monaco-select-box-dropdown-container > .select-box-details-pane.border-bottom { border-bottom: 1px solid ${this.styles.selectListBorder} } `)),this.styles.listHoverForeground&&e.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row:not(.option-disabled):not(.focused):hover { color: ${this.styles.listHoverForeground} !important; }`),this.styles.listHoverBackground&&e.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row:not(.option-disabled):not(.focused):hover { background-color: ${this.styles.listHoverBackground} !important; }`),this.styles.listFocusOutline&&e.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.focused { outline: 1.6px dotted ${this.styles.listFocusOutline} !important; outline-offset: -1.6px !important; }`),this.styles.listHoverOutline&&e.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row:not(.option-disabled):not(.focused):hover { outline: 1.6px dashed ${this.styles.listHoverOutline} !important; outline-offset: -1.6px !important; }`),e.push(".monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.option-disabled.focused { background-color: transparent !important; color: inherit !important; outline: none !important; }"),e.push(".monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.option-disabled:hover { background-color: transparent !important; color: inherit !important; outline: none !important; }"),this.styleElement.textContent=e.join("\n")}styleSelectElement(){const e=this.styles.selectBackground??"",t=this.styles.selectForeground??"",i=this.styles.selectBorder??"";this.selectElement.style.backgroundColor=e,this.selectElement.style.color=t,this.selectElement.style.borderColor=i}styleList(){const e=this.styles.selectBackground??"",t=r.gI(this.styles.selectListBackground,e);this.selectDropDownListContainer.style.backgroundColor=t,this.selectionDetailsPane.style.backgroundColor=t;const i=this.styles.focusBorder??"";this.selectDropDownContainer.style.outlineColor=i,this.selectDropDownContainer.style.outlineOffset="-1px",this.selectList.style(this.styles)}createOption(e,t,i){const s=document.createElement("option");return s.value=e,s.text=e,s.disabled=!!i,s}showSelectDropDown(){this.selectionDetailsPane.innerText="",this.contextViewProvider&&!this._isVisible&&(this.createSelectList(this.selectDropDownContainer),this.setOptionsList(),this.contextViewProvider.showContextView({getAnchor:()=>this.selectElement,render:e=>this.renderSelectDropDown(e,!0),layout:()=>{this.layoutSelectDropDown()},onHide:()=>{this.selectDropDownContainer.classList.remove("visible"),this.selectElement.classList.remove("synthetic-focus")},anchorPosition:this._dropDownPosition},this.selectBoxOptions.optionsAsChildren?this.container:void 0),this._isVisible=!0,this.hideSelectDropDown(!1),this.contextViewProvider.showContextView({getAnchor:()=>this.selectElement,render:e=>this.renderSelectDropDown(e),layout:()=>this.layoutSelectDropDown(),onHide:()=>{this.selectDropDownContainer.classList.remove("visible"),this.selectElement.classList.remove("synthetic-focus")},anchorPosition:this._dropDownPosition},this.selectBoxOptions.optionsAsChildren?this.container:void 0),this._currentSelection=this.selected,this._isVisible=!0,this.selectElement.setAttribute("aria-expanded","true"))}hideSelectDropDown(e){this.contextViewProvider&&this._isVisible&&(this._isVisible=!1,this.selectElement.setAttribute("aria-expanded","false"),e&&this.selectElement.focus(),this.contextViewProvider.hideContextView())}renderSelectDropDown(e,t){return e.appendChild(this.selectDropDownContainer),this.layoutSelectDropDown(t),{dispose:()=>{this.selectDropDownContainer.remove()}}}measureMaxDetailsHeight(){let e=0;return this.options.forEach(((t,i)=>{this.updateDetail(i),this.selectionDetailsPane.offsetHeight>e&&(e=this.selectionDetailsPane.offsetHeight)})),e}layoutSelectDropDown(e){if(this._skipLayout)return!1;if(this.selectList){this.selectDropDownContainer.classList.add("visible");const t=r.zk(this.selectElement),i=r.BK(this.selectElement),s=r.zk(this.selectElement).getComputedStyle(this.selectElement),n=parseFloat(s.getPropertyValue("--dropdown-padding-top"))+parseFloat(s.getPropertyValue("--dropdown-padding-bottom")),o=t.innerHeight-i.top-i.height-(this.selectBoxOptions.minBottomMargin||0),a=i.top-S.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN,c=this.selectElement.offsetWidth,l=this.setWidthControlElement(this.widthControlElement),h=Math.max(l,Math.round(c)).toString()+"px";this.selectDropDownContainer.style.width=h,this.selectList.getHTMLElement().style.height="",this.selectList.layout();let d=this.selectList.contentHeight;this._hasDetails&&void 0===this._cachedMaxDetailsHeight&&(this._cachedMaxDetailsHeight=this.measureMaxDetailsHeight());const u=this._hasDetails?this._cachedMaxDetailsHeight:0,g=d+n+u,p=Math.floor((o-n-u)/this.getHeight()),m=Math.floor((a-n-u)/this.getHeight());if(e)return!(i.top+i.height>t.innerHeight-22||i.topp&&this.options.length>p?(this._dropDownPosition=1,this.selectDropDownListContainer.remove(),this.selectionDetailsPane.remove(),this.selectDropDownContainer.appendChild(this.selectionDetailsPane),this.selectDropDownContainer.appendChild(this.selectDropDownListContainer),this.selectionDetailsPane.classList.remove("border-top"),this.selectionDetailsPane.classList.add("border-bottom")):(this._dropDownPosition=0,this.selectDropDownListContainer.remove(),this.selectionDetailsPane.remove(),this.selectDropDownContainer.appendChild(this.selectDropDownListContainer),this.selectDropDownContainer.appendChild(this.selectionDetailsPane),this.selectionDetailsPane.classList.remove("border-bottom"),this.selectionDetailsPane.classList.add("border-top")),!0);if(i.top+i.height>t.innerHeight-22||i.topo&&(d=p*this.getHeight())}else g>a&&(d=m*this.getHeight());return this.selectList.layout(d),this.selectList.domFocus(),this.selectList.length>0&&(this.selectList.setFocus([this.selected||0]),this.selectList.reveal(this.selectList.getFocus()[0]||0)),this._hasDetails?(this.selectList.getHTMLElement().style.height=d+n+"px",this.selectDropDownContainer.style.height=""):this.selectDropDownContainer.style.height=d+n+"px",this.updateDetail(this.selected),this.selectDropDownContainer.style.width=h,this.selectDropDownListContainer.setAttribute("tabindex","0"),this.selectElement.classList.add("synthetic-focus"),this.selectDropDownContainer.classList.add("synthetic-focus"),!0}return!1}setWidthControlElement(e){let t=0;if(e){let i=0,s=0;this.options.forEach(((e,t)=>{const n=e.detail?e.detail.length:0,r=e.decoratorRight?e.decoratorRight.length:0,o=e.text.length+n+r;o>s&&(i=t,s=o)})),e.textContent=this.options[i].text+(this.options[i].decoratorRight?this.options[i].decoratorRight+" ":""),t=r.Tr(e)}return t}createSelectList(e){if(this.selectList)return;this.selectDropDownListContainer=r.BC(e,C(".select-box-dropdown-list-container")),this.listRenderer=new b,this.selectList=this._register(new u.B8("SelectBoxCustom",this.selectDropDownListContainer,this,[this.listRenderer],{useShadows:!1,verticalScrollMode:3,keyboardSupport:!1,mouseSupport:!1,accessibilityProvider:{getAriaLabel:e=>{let t=e.text;return e.detail&&(t+=`. ${e.detail}`),e.decoratorRight&&(t+=`. ${e.decoratorRight}`),e.description&&(t+=`. ${e.description}`),t},getWidgetAriaLabel:()=>(0,v.kg)({key:"selectBox",comment:["Behave like native select dropdown element."]},"Select Box"),getRole:()=>_.zx?"":"option",getWidgetRole:()=>"listbox"}})),this.selectBoxOptions.ariaLabel&&(this.selectList.ariaLabel=this.selectBoxOptions.ariaLabel);const t=this._register(new c.f(this.selectDropDownListContainer,"keydown")),i=p.Jh.chain(t.event,(e=>e.filter((()=>this.selectList.length>0)).map((e=>new l.Z(e)))));this._register(p.Jh.chain(i,(e=>e.filter((e=>3===e.keyCode))))(this.onEnter,this)),this._register(p.Jh.chain(i,(e=>e.filter((e=>2===e.keyCode))))(this.onEnter,this)),this._register(p.Jh.chain(i,(e=>e.filter((e=>9===e.keyCode))))(this.onEscape,this)),this._register(p.Jh.chain(i,(e=>e.filter((e=>16===e.keyCode))))(this.onUpArrow,this)),this._register(p.Jh.chain(i,(e=>e.filter((e=>18===e.keyCode))))(this.onDownArrow,this)),this._register(p.Jh.chain(i,(e=>e.filter((e=>12===e.keyCode))))(this.onPageDown,this)),this._register(p.Jh.chain(i,(e=>e.filter((e=>11===e.keyCode))))(this.onPageUp,this)),this._register(p.Jh.chain(i,(e=>e.filter((e=>14===e.keyCode))))(this.onHome,this)),this._register(p.Jh.chain(i,(e=>e.filter((e=>13===e.keyCode))))(this.onEnd,this)),this._register(p.Jh.chain(i,(e=>e.filter((e=>e.keyCode>=21&&e.keyCode<=56||e.keyCode>=85&&e.keyCode<=113))))(this.onCharacter,this)),this._register(r.ko(this.selectList.getHTMLElement(),r.Bx.POINTER_UP,(e=>this.onPointerUp(e)))),this._register(this.selectList.onMouseOver((e=>"undefined"!==typeof e.index&&this.selectList.setFocus([e.index])))),this._register(this.selectList.onDidChangeFocus((e=>this.onListFocus(e)))),this._register(r.ko(this.selectDropDownContainer,r.Bx.FOCUS_OUT,(e=>{this._isVisible&&!r.QX(e.relatedTarget,this.selectDropDownContainer)&&this.onListBlur()}))),this.selectList.getHTMLElement().setAttribute("aria-label",this.selectBoxOptions.ariaLabel||""),this.selectList.getHTMLElement().setAttribute("aria-expanded","true"),this.styleList()}onPointerUp(e){if(!this.selectList.length)return;r.fs.stop(e);const t=e.target;if(!t)return;if(t.classList.contains("slider"))return;const i=t.closest(".monaco-list-row");if(!i)return;const s=Number(i.getAttribute("data-index")),n=i.classList.contains("option-disabled");s>=0&&s{for(let t=0;tthis.selected+2)this.selected+=2;else{if(t)return;this.selected++}this.select(this.selected),this.selectList.setFocus([this.selected]),this.selectList.reveal(this.selectList.getFocus()[0])}}onUpArrow(e){if(this.selected>0){r.fs.stop(e,!0);this.options[this.selected-1].isDisabled&&this.selected>1?this.selected-=2:this.selected--,this.select(this.selected),this.selectList.setFocus([this.selected]),this.selectList.reveal(this.selectList.getFocus()[0])}}onPageUp(e){r.fs.stop(e),this.selectList.focusPreviousPage(),setTimeout((()=>{this.selected=this.selectList.getFocus()[0],this.options[this.selected].isDisabled&&this.selected{this.selected=this.selectList.getFocus()[0],this.options[this.selected].isDisabled&&this.selected>0&&(this.selected--,this.selectList.setFocus([this.selected])),this.selectList.reveal(this.selected),this.select(this.selected)}),1)}onHome(e){r.fs.stop(e),this.options.length<2||(this.selected=0,this.options[this.selected].isDisabled&&this.selected>1&&this.selected++,this.selectList.setFocus([this.selected]),this.selectList.reveal(this.selected),this.select(this.selected))}onEnd(e){r.fs.stop(e),this.options.length<2||(this.selected=this.options.length-1,this.options[this.selected].isDisabled&&this.selected>1&&this.selected--,this.selectList.setFocus([this.selected]),this.selectList.reveal(this.selected),this.select(this.selected))}onCharacter(e){const t=m.YM.toString(e.keyCode);let i=-1;for(let s=0;s{this._register(r.ko(this.selectElement,e,(e=>{this.selectElement.focus()})))})),this._register(r.b2(this.selectElement,"click",(e=>{r.fs.stop(e,!0)}))),this._register(r.b2(this.selectElement,"change",(e=>{this.selectElement.title=e.target.value,this._onDidSelect.fire({index:e.target.selectedIndex,selected:e.target.value})}))),this._register(r.b2(this.selectElement,"keydown",(e=>{let t=!1;_.zx?18!==e.keyCode&&16!==e.keyCode&&10!==e.keyCode||(t=!0):(18===e.keyCode&&e.altKey||10===e.keyCode||3===e.keyCode)&&(t=!0),t&&e.stopPropagation()})))}get onDidSelect(){return this._onDidSelect.event}setOptions(e,t){this.options&&g.aI(this.options,e)||(this.options=e,this.selectElement.options.length=0,this.options.forEach(((e,t)=>{this.selectElement.add(this.createOption(e.text,t,e.isDisabled))}))),void 0!==t&&this.select(t)}select(e){0===this.options.length?this.selected=0:e>=0&&ethis.options.length-1?this.select(this.options.length-1):this.selected<0&&(this.selected=0),this.selectElement.selectedIndex=this.selected,this.selected{this.element&&this.handleActionChangeEvent(e)})))}handleActionChangeEvent(e){void 0!==e.enabled&&this.updateEnabled(),void 0!==e.checked&&this.updateChecked(),void 0!==e.class&&this.updateClass(),void 0!==e.label&&(this.updateLabel(),this.updateTooltip()),void 0!==e.tooltip&&this.updateTooltip()}get actionRunner(){return this._actionRunner||(this._actionRunner=this._register(new L.LN)),this._actionRunner}set actionRunner(e){this._actionRunner=e}isEnabled(){return this._action.enabled}setActionContext(e){this._context=e}render(e){const t=this.element=e;this._register(o.q.addTarget(e));const i=this.options&&this.options.draggable;i&&(e.draggable=!0,s.gm&&this._register((0,r.ko)(e,r.Bx.DRAG_START,(e=>e.dataTransfer?.setData(n.t.TEXT,this._action.label))))),this._register((0,r.ko)(t,o.B.Tap,(e=>this.onClick(e,!0)))),this._register((0,r.ko)(t,r.Bx.MOUSE_DOWN,(e=>{i||r.fs.stop(e,!0),this._action.enabled&&0===e.button&&t.classList.add("active")}))),_.zx&&this._register((0,r.ko)(t,r.Bx.CONTEXT_MENU,(e=>{0===e.button&&!0===e.ctrlKey&&this.onClick(e)}))),this._register((0,r.ko)(t,r.Bx.CLICK,(e=>{r.fs.stop(e,!0),this.options&&this.options.isMenu||this.onClick(e)}))),this._register((0,r.ko)(t,r.Bx.DBLCLICK,(e=>{r.fs.stop(e,!0)}))),[r.Bx.MOUSE_UP,r.Bx.MOUSE_OUT].forEach((e=>{this._register((0,r.ko)(t,e,(e=>{r.fs.stop(e),t.classList.remove("active")})))}))}onClick(e,t=!1){r.fs.stop(e,!0);const i=T.z(this._context)?this.options?.useEventAsContext?e:{preserveFocus:t}:this._context;this.actionRunner.run(this._action,i)}focus(){this.element&&(this.element.tabIndex=0,this.element.focus(),this.element.classList.add("focused"))}blur(){this.element&&(this.element.blur(),this.element.tabIndex=-1,this.element.classList.remove("focused"))}setFocusable(e){this.element&&(this.element.tabIndex=e?0:-1)}get trapsArrowNavigation(){return!1}updateEnabled(){}updateLabel(){}getClass(){return this.action.class}getTooltip(){return this.action.tooltip}updateTooltip(){if(!this.element)return;const e=this.getTooltip()??"";if(this.updateAriaLabel(),this.options.hoverDelegate?.showNativeHover)this.element.title=e;else if(this.customHover||""===e)this.customHover&&this.customHover.update(e);else{const t=this.options.hoverDelegate??(0,a.nZ)("element");this.customHover=this._store.add((0,d.i)().setupManagedHover(t,this.element,e))}}updateAriaLabel(){if(this.element){const e=this.getTooltip()??"";this.element.setAttribute("aria-label",e)}}updateClass(){}updateChecked(){}dispose(){this.element&&(this.element.remove(),this.element=void 0),this._context=void 0,super.dispose()}}class k extends x{constructor(e,t,i){super(e,t,i),this.options=i,this.options.icon=void 0!==i.icon&&i.icon,this.options.label=void 0===i.label||i.label,this.cssClass=""}render(e){super.render(e),T.j(this.element);const t=document.createElement("a");if(t.classList.add("action-label"),t.setAttribute("role",this.getDefaultAriaRole()),this.label=t,this.element.appendChild(t),this.options.label&&this.options.keybinding){const e=document.createElement("span");e.classList.add("keybinding"),e.textContent=this.options.keybinding,this.element.appendChild(e)}this.updateClass(),this.updateLabel(),this.updateTooltip(),this.updateEnabled(),this.updateChecked()}getDefaultAriaRole(){return this._action.id===L.wv.ID?"presentation":this.options.isMenu?"menuitem":this.options.isTabList?"tab":"button"}focus(){this.label&&(this.label.tabIndex=0,this.label.focus())}blur(){this.label&&(this.label.tabIndex=-1)}setFocusable(e){this.label&&(this.label.tabIndex=e?0:-1)}updateLabel(){this.options.label&&this.label&&(this.label.textContent=this.action.label)}getTooltip(){let e=null;return this.action.tooltip?e=this.action.tooltip:!this.options.label&&this.action.label&&this.options.icon&&(e=this.action.label,this.options.keybinding&&(e=v.kg({key:"titleLabel",comment:["action title","action keybinding"]},"{0} ({1})",e,this.options.keybinding))),e??void 0}updateClass(){this.cssClass&&this.label&&this.label.classList.remove(...this.cssClass.split(" ")),this.options.icon?(this.cssClass=this.getClass(),this.label&&(this.label.classList.add("codicon"),this.cssClass&&this.label.classList.add(...this.cssClass.split(" "))),this.updateEnabled()):this.label?.classList.remove("codicon")}updateEnabled(){this.action.enabled?(this.label&&(this.label.removeAttribute("aria-disabled"),this.label.classList.remove("disabled")),this.element?.classList.remove("disabled")):(this.label&&(this.label.setAttribute("aria-disabled","true"),this.label.classList.add("disabled")),this.element?.classList.add("disabled"))}updateAriaLabel(){if(this.label){const e=this.getTooltip()??"";this.label.setAttribute("aria-label",e)}}updateChecked(){this.label&&(void 0!==this.action.checked?(this.label.classList.toggle("checked",this.action.checked),this.options.isTabList?this.label.setAttribute("aria-selected",this.action.checked?"true":"false"):(this.label.setAttribute("aria-checked",this.action.checked?"true":"false"),this.label.setAttribute("role","checkbox"))):(this.label.classList.remove("checked"),this.label.removeAttribute(this.options.isTabList?"aria-selected":"aria-checked"),this.label.setAttribute("role",this.getDefaultAriaRole())))}}class A extends x{constructor(e,t,i,s,n,r,o){super(e,t),this.selectBox=new R(i,s,n,r,o),this.selectBox.setFocusable(!1),this._register(this.selectBox),this.registerListeners()}select(e){this.selectBox.select(e)}registerListeners(){this._register(this.selectBox.onDidSelect((e=>this.runAction(e.selected,e.index))))}runAction(e,t){this.actionRunner.run(this._action,this.getActionContext(e,t))}getActionContext(e,t){return e}setFocusable(e){this.selectBox.setFocusable(e)}focus(){this.selectBox?.focus()}blur(){this.selectBox?.blur()}render(e){this.selectBox.render(e)}}},5662:(e,t,i)=>{"use strict";i.d(t,{$w:()=>C,AS:()=>d,Ay:()=>o,BO:()=>v,Cm:()=>p,HE:()=>f,VD:()=>a,Xm:()=>h,jG:()=>m,lC:()=>l,mp:()=>_,qE:()=>u,s:()=>g});var s=i(6921),n=i(42522);let r=null;function o(e){return r?.trackDisposable(e),e}function a(e){r?.markAsDisposed(e)}function c(e,t){r?.setParent(e,t)}function l(e){return r?.markAsSingleton(e),e}function h(e){return"object"===typeof e&&null!==e&&"function"===typeof e.dispose&&0===e.dispose.length}function d(e){if(n.f.is(e)){const i=[];for(const s of e)if(s)try{s.dispose()}catch(t){i.push(t)}if(1===i.length)throw i[0];if(i.length>1)throw new AggregateError(i,"Encountered errors while disposing of store");return Array.isArray(e)?[]:e}if(e)return e.dispose(),e}function u(...e){const t=g((()=>d(e)));return function(e,t){if(r)for(const i of e)r.setParent(i,t)}(e,t),t}function g(e){const t=o({dispose:(0,s.P)((()=>{a(t),e()}))});return t}class p{static{this.DISABLE_DISPOSED_WARNING=!1}constructor(){this._toDispose=new Set,this._isDisposed=!1,o(this)}dispose(){this._isDisposed||(a(this),this._isDisposed=!0,this.clear())}get isDisposed(){return this._isDisposed}clear(){if(0!==this._toDispose.size)try{d(this._toDispose)}finally{this._toDispose.clear()}}add(e){if(!e)return e;if(e===this)throw new Error("Cannot register a disposable on itself!");return c(e,this),this._isDisposed?p.DISABLE_DISPOSED_WARNING||console.warn(new Error("Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!").stack):this._toDispose.add(e),e}deleteAndLeak(e){e&&this._toDispose.has(e)&&(this._toDispose.delete(e),c(e,null))}}class m{static{this.None=Object.freeze({dispose(){}})}constructor(){this._store=new p,o(this),c(this._store,this)}dispose(){a(this),this._store.dispose()}_register(e){if(e===this)throw new Error("Cannot register a disposable on itself!");return this._store.add(e)}}class f{constructor(){this._isDisposed=!1,o(this)}get value(){return this._isDisposed?void 0:this._value}set value(e){this._isDisposed||e===this._value||(this._value?.dispose(),e&&c(e,this),this._value=e)}clear(){this.value=void 0}dispose(){this._isDisposed=!0,a(this),this._value?.dispose(),this._value=void 0}}class _{constructor(e){this._disposable=e,this._counter=1}acquire(){return this._counter++,this}release(){return 0===--this._counter&&this._disposable.dispose(),this}}class v{constructor(e){this.object=e}dispose(){}}class C{constructor(){this._store=new Map,this._isDisposed=!1,o(this)}dispose(){a(this),this._isDisposed=!0,this.clearAndDisposeAll()}clearAndDisposeAll(){if(this._store.size)try{d(this._store.values())}finally{this._store.clear()}}get(e){return this._store.get(e)}set(e,t,i=!1){this._isDisposed&&console.warn(new Error("Trying to add a disposable to a DisposableMap that has already been disposed of. The added object will be leaked!").stack),i||this._store.get(e)?.dispose(),this._store.set(e,t)}deleteAndDispose(e){this._store.get(e)?.dispose(),this._store.delete(e)}[Symbol.iterator](){return this._store[Symbol.iterator]()}}},5744:(e,t,i)=>{"use strict";i.d(t,{A:()=>n});var s=i(59284);const n=e=>s.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),s.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14m3.1-8.55a.75.75 0 1 0-1.2-.9L7.419 8.858 6.03 7.47a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.13-.08z",clipRule:"evenodd"}))},6156:(e,t,i)=>{"use strict";i.d(t,{F:()=>O});var s=i(59284),n=i(81240),r=i(84476),o=i(80604),a=i(99991),c=i(63365),l=i(46423),h=i(87184);const d=s.createContext(null),u=()=>{const e=s.useContext(d);if(!e)throw new Error('Alert: `useAlertContext` hook is used out of "AlertContext"');return e},g=e=>{const{view:t}=u();return s.createElement(r.$,Object.assign({view:"filled"===t?"normal-contrast":void 0},e))};var p=i(69220);const m=(0,p.om)("alert"),f=({layout:e,view:t,children:i})=>s.createElement(d.Provider,{value:{layout:e,view:t}},i);var _=i(18677),v=i(10800),C=i(45720),E=i(43937),b=i(5744),S=i(70825),y=i(71153),w=i(94420);const R=e=>s.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),s.createElement("path",{fill:"currentColor",d:"m14.61 6.914-7.632 8.08a1.614 1.614 0 0 1-2.69-1.66L5.5 10H2.677A1.677 1.677 0 0 1 1.12 7.7l2.323-5.807A2.22 2.22 0 0 1 5.5.5h4c.968 0 1.637.967 1.298 1.873L10 4.5h3.569a1.431 1.431 0 0 1 1.04 2.414"}));var L=i(27612);const T={danger:{filled:_.A,outlined:v.A},info:{filled:C.A,outlined:E.A},success:{filled:b.A,outlined:S.A},warning:{filled:y.A,outlined:w.A},utility:{filled:R,outlined:L.A},normal:null};var x=i(98089);var k=i(72837);const A=JSON.parse('{"label_close":"Close"}'),N=JSON.parse('{"label_close":"\u0417\u0430\u043a\u0440\u044b\u0442\u044c"}'),I=(0,k.N)({en:A,ru:N},"Alert"),O=e=>{const{theme:t="normal",view:i="filled",layout:d="vertical",message:u,className:g,corners:p,style:_,onClose:v,align:C,qa:E}=e;return s.createElement(f,{layout:d,view:i},s.createElement(o.Z,{style:_,className:m({corners:p},(0,l.Y)({py:4,px:5},g)),theme:t,view:i,qa:E},s.createElement(h.s,{gap:"3",alignItems:C},"undefined"===typeof e.icon?s.createElement(O.Icon,{theme:t,view:i}):e.icon,s.createElement(h.s,{direction:"vertical"===d?"column":"row",gap:"5",grow:!0},s.createElement(h.s,{gap:"2",grow:!0,className:m("text-content")},s.createElement(h.s,{direction:"column",gap:"1",grow:!0,justifyContent:C},"string"===typeof e.title?s.createElement(O.Title,{text:e.title}):e.title,u)),Array.isArray(e.actions)?s.createElement(O.Actions,{items:e.actions}):e.actions),v&&s.createElement(r.$,{view:"flat",className:m("close-btn"),onClick:v,extraProps:{"aria-label":I("label_close")}},s.createElement(a.I,{data:n.A,size:18,className:(0,c.$)({color:"secondary"})})))))};O.Icon=({className:e,theme:t,view:i="filled",size:n=18})=>{const r=T[t];if(!r)return null;let o;return"success"===t?o="positive":"normal"!==t&&(o=t),s.createElement("div",{className:m("icon",(0,c.$)({color:o},e))},s.createElement(a.I,{data:r[i],size:n}))},O.Title=({text:e,className:t})=>s.createElement(x.E,{variant:"subheader-2",className:m("title",t)},e),O.Actions=({items:e,children:t,className:i})=>{const{layout:n}=u();return s.createElement(h.s,{className:m("actions",{minContent:"horizontal"===n},i),direction:"row",gap:"3",wrap:!0,alignItems:"horizontal"===n?"center":"flex-start"},(null===e||void 0===e?void 0:e.map((({handler:e,text:t},i)=>s.createElement(g,{key:i,onClick:e},t))))||t)},O.Action=g},6170:(e,t,i)=>{"use strict";i.d(t,{B:()=>l});var s=i(59284),n=i(73633),r=i(84375),o=i(99991);const a=(0,i(98192).om)("help-popover"),c=16;function l(e){var t;return s.createElement(r.A,Object.assign({},e,{className:a(null,e.className)}),s.createElement("button",Object.assign({ref:e.buttonRef,type:"button"},e.buttonProps,{className:a("button",null===(t=e.buttonProps)||void 0===t?void 0:t.className)}),s.createElement(o.I,{data:n.A,size:c})))}},6376:(e,t,i)=>{"use strict";i.r(t),i.d(t,{MonacoDiffEditor:()=>l,default:()=>g,monaco:()=>s});var s=i(80781),n=i(59284);function r(e){return/^\d+$/.test(e)?"".concat(e,"px"):e}function o(){}var a=function(){return a=Object.assign||function(e){for(var t,i=1,s=arguments.length;i{"use strict";var s,n=i(46359),r=i(71597),o=i(51861),a=i(78209),c=i(5662),l=i(98031),h=i(51467),d=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},u=function(e,t){return function(i,s){t(i,s,e)}};let g=class{static{s=this}static{this.PREFIX="?"}constructor(e,t){this.quickInputService=e,this.keybindingService=t,this.registry=n.O.as(r.Fd.Quickaccess)}provide(e){const t=new c.Cm;return t.add(e.onDidAccept((()=>{const[t]=e.selectedItems;t&&this.quickInputService.quickAccess.show(t.prefix,{preserveValue:!0})}))),t.add(e.onDidChangeValue((e=>{const t=this.registry.getQuickAccessProvider(e.substr(s.PREFIX.length));t&&t.prefix&&t.prefix!==s.PREFIX&&this.quickInputService.quickAccess.show(t.prefix,{preserveValue:!0})}))),e.items=this.getQuickAccessProviders().filter((e=>e.prefix!==s.PREFIX)),t}getQuickAccessProviders(){return this.registry.getQuickAccessProviders().sort(((e,t)=>e.prefix.localeCompare(t.prefix))).flatMap((e=>this.createPicks(e)))}createPicks(e){return e.helpEntries.map((t=>{const i=t.prefix||e.prefix,s=i||"\u2026";return{prefix:i,label:s,keybinding:t.commandId?this.keybindingService.lookupKeybinding(t.commandId):void 0,ariaLabel:(0,a.kg)("helpPickAriaLabel","{0}, {1}",s,t.description),description:t.description}}))}};g=s=d([u(0,h.GK),u(1,l.b)],g),n.O.as(r.Fd.Quickaccess).registerQuickAccessProvider({ctor:g,prefix:"",helpEntries:[{description:o.oq.helpQuickAccessActionLabel}]})},6438:(e,t,i)=>{"use strict";var s=i(31450),n=i(15092),r=i(94564),o=i(36677),a=i(60002),c=i(78209);class l extends s.ks{constructor(){super({id:"editor.action.transposeLetters",label:c.kg("transposeLetters.label","Transpose Letters"),alias:"Transpose Letters",precondition:a.R.writable,kbOpts:{kbExpr:a.R.textInputFocus,primary:0,mac:{primary:306},weight:100}})}run(e,t){if(!t.hasModel())return;const i=t.getModel(),s=[],a=t.getSelections();for(const c of a){if(!c.isEmpty())continue;const e=c.startLineNumber,t=c.startColumn,a=i.getLineMaxColumn(e);if(1===e&&(1===t||2===t&&2===a))continue;const l=t===a?c.getPosition():r.I.rightPosition(i,c.getPosition().lineNumber,c.getPosition().column),h=r.I.leftPosition(i,l),d=r.I.leftPosition(i,h),u=i.getValueInRange(o.Q.fromPositions(d,h)),g=i.getValueInRange(o.Q.fromPositions(h,l)),p=o.Q.fromPositions(d,l);s.push(new n.iu(p,g+u))}s.length>0&&(t.pushUndoStop(),t.executeCommands(this.id,s),t.pushUndoStop())}}(0,s.Fl)(l)},6921:(e,t,i)=>{"use strict";function s(e,t){const i=this;let s,n=!1;return function(){if(n)return s;if(n=!0,t)try{s=e.apply(i,arguments)}finally{t()}else s=e.apply(i,arguments);return s}}i.d(t,{P:()=>s})},7085:(e,t,i)=>{"use strict";i.d(t,{k:()=>n});var s=i(36677);class n{static insert(e,t){return{range:new s.Q(e.lineNumber,e.column,e.lineNumber,e.column),text:t,forceMoveMarkers:!0}}static delete(e){return{range:e,text:null}}static replace(e,t){return{range:e,text:t}}static replaceMove(e,t){return{range:e,text:t,forceMoveMarkers:!0}}}},7142:(e,t,i)=>{"use strict";i.d(t,{U:()=>l});var s=i(90766),n=i(18447),r=i(64383),o=i(31450),a=i(56942);class c{constructor(e,t,i){this.provider=e,this.hover=t,this.ordinal=i}}function l(e,t,i,n,o=!1){const a=e.ordered(t,o).map(((e,s)=>async function(e,t,i,s,n){const o=await Promise.resolve(e.provideHover(i,s,n)).catch(r.M_);if(o&&function(e){const t="undefined"!==typeof e.range,i="undefined"!==typeof e.contents&&e.contents&&e.contents.length>0;return t&&i}(o))return new c(e,o,t)}(e,s,t,i,n)));return s.AE.fromPromises(a).coalesce()}function h(e,t,i,s,n=!1){return l(e,t,i,s,n).map((e=>e.hover)).toPromise()}(0,o.ke)("_executeHoverProvider",((e,t,i)=>h(e.get(a.ILanguageFeaturesService).hoverProvider,t,i,n.XO.None))),(0,o.ke)("_executeHoverProvider_recursive",((e,t,i)=>h(e.get(a.ILanguageFeaturesService).hoverProvider,t,i,n.XO.None,!0)))},7252:(e,t,i)=>{var s,n=n||{version:"5.4.2"};if(t.fabric=n,"undefined"!==typeof document&&"undefined"!==typeof window)document instanceof("undefined"!==typeof HTMLDocument?HTMLDocument:Document)?n.document=document:n.document=document.implementation.createHTMLDocument(""),n.window=window;else{var r=new(i(66574).JSDOM)(decodeURIComponent("%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E"),{features:{FetchExternalResources:["img"]},resources:"usable"}).window;n.document=r.document,n.jsdomImplForWrapper=i(2748).implForWrapper,n.nodeCanvas=i(52246).Canvas,n.window=r,DOMParser=n.window.DOMParser}function o(e,t){var i=e.canvas,s=t.targetCanvas,n=s.getContext("2d");n.translate(0,s.height),n.scale(1,-1);var r=i.height-s.height;n.drawImage(i,0,r,s.width,s.height,0,0,s.width,s.height)}function a(e,t){var i=t.targetCanvas.getContext("2d"),s=t.destinationWidth,n=t.destinationHeight,r=s*n*4,o=new Uint8Array(this.imageBuffer,0,r),a=new Uint8ClampedArray(this.imageBuffer,0,r);e.readPixels(0,0,s,n,e.RGBA,e.UNSIGNED_BYTE,o);var c=new ImageData(a,s,n);i.putImageData(c,0,0)}n.isTouchSupported="ontouchstart"in n.window||"ontouchstart"in n.document||n.window&&n.window.navigator&&n.window.navigator.maxTouchPoints>0,n.isLikelyNode="undefined"!==typeof Buffer&&"undefined"===typeof window,n.SHARED_ATTRIBUTES=["display","transform","fill","fill-opacity","fill-rule","opacity","stroke","stroke-dasharray","stroke-linecap","stroke-dashoffset","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","id","paint-order","vector-effect","instantiated_by_use","clip-path"],n.DPI=96,n.reNum="(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:[eE][-+]?\\d+)?)",n.commaWsp="(?:\\s+,?\\s*|,\\s*)",n.rePathCommand=/([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:[eE][-+]?\d+)?)/gi,n.reNonWord=/[ \n\.,;!\?\-]/,n.fontPaths={},n.iMatrix=[1,0,0,1,0,0],n.svgNS="http://www.w3.org/2000/svg",n.perfLimitSizeTotal=2097152,n.maxCacheSideLimit=4096,n.minCacheSideLimit=256,n.charWidthsCache={},n.textureSize=2048,n.disableStyleCopyPaste=!1,n.enableGLFiltering=!0,n.devicePixelRatio=n.window.devicePixelRatio||n.window.webkitDevicePixelRatio||n.window.mozDevicePixelRatio||1,n.browserShadowBlurConstant=1,n.arcToSegmentsCache={},n.boundsOfCurveCache={},n.cachesBoundsOfCurve=!0,n.forceGLPutImageData=!1,n.initFilterBackend=function(){return n.enableGLFiltering&&n.isWebglSupported&&n.isWebglSupported(n.textureSize)?(console.log("max texture size: "+n.maxTextureSize),new n.WebglFilterBackend({tileSize:n.textureSize})):n.Canvas2dFilterBackend?new n.Canvas2dFilterBackend:void 0},"undefined"!==typeof document&&"undefined"!==typeof window&&(window.fabric=n),function(){function e(e,t){if(this.__eventListeners[e]){var i=this.__eventListeners[e];t?i[i.indexOf(t)]=!1:n.util.array.fill(i,!1)}}function t(e,t){var i=function(){t.apply(this,arguments),this.off(e,i)}.bind(this);this.on(e,i)}n.Observable={fire:function(e,t){if(!this.__eventListeners)return this;var i=this.__eventListeners[e];if(!i)return this;for(var s=0,n=i.length;s-1||!!t&&this._objects.some((function(t){return"function"===typeof t.contains&&t.contains(e,!0)}))},complexity:function(){return this._objects.reduce((function(e,t){return e+=t.complexity?t.complexity():0}),0)}},n.CommonMethods={_setOptions:function(e){for(var t in e)this.set(t,e[t])},_initGradient:function(e,t){!e||!e.colorStops||e instanceof n.Gradient||this.set(t,new n.Gradient(e))},_initPattern:function(e,t,i){!e||!e.source||e instanceof n.Pattern?i&&i():this.set(t,new n.Pattern(e,i))},_setObject:function(e){for(var t in e)this._set(t,e[t])},set:function(e,t){return"object"===typeof e?this._setObject(e):this._set(e,t),this},_set:function(e,t){this[e]=t},toggle:function(e){var t=this.get(e);return"boolean"===typeof t&&this.set(e,!t),this},get:function(e){return this[e]}},function(e){var t=Math.sqrt,i=Math.atan2,s=Math.pow,r=Math.PI/180,o=Math.PI/2;n.util={cos:function(e){if(0===e)return 1;switch(e<0&&(e=-e),e/o){case 1:case 3:return 0;case 2:return-1}return Math.cos(e)},sin:function(e){if(0===e)return 0;var t=1;switch(e<0&&(t=-1),e/o){case 1:return t;case 2:return 0;case 3:return-t}return Math.sin(e)},removeFromArray:function(e,t){var i=e.indexOf(t);return-1!==i&&e.splice(i,1),e},getRandomInt:function(e,t){return Math.floor(Math.random()*(t-e+1))+e},degreesToRadians:function(e){return e*r},radiansToDegrees:function(e){return e/r},rotatePoint:function(e,t,i){var s=new n.Point(e.x-t.x,e.y-t.y),r=n.util.rotateVector(s,i);return new n.Point(r.x,r.y).addEquals(t)},rotateVector:function(e,t){var i=n.util.sin(t),s=n.util.cos(t);return{x:e.x*s-e.y*i,y:e.x*i+e.y*s}},createVector:function(e,t){return new n.Point(t.x-e.x,t.y-e.y)},calcAngleBetweenVectors:function(e,t){return Math.acos((e.x*t.x+e.y*t.y)/(Math.hypot(e.x,e.y)*Math.hypot(t.x,t.y)))},getHatVector:function(e){return new n.Point(e.x,e.y).multiply(1/Math.hypot(e.x,e.y))},getBisector:function(e,t,i){var s=n.util.createVector(e,t),r=n.util.createVector(e,i),o=n.util.calcAngleBetweenVectors(s,r),a=o*(0===n.util.calcAngleBetweenVectors(n.util.rotateVector(s,o),r)?1:-1)/2;return{vector:n.util.getHatVector(n.util.rotateVector(s,a)),angle:o}},projectStrokeOnPoints:function(e,t,i){var s=[],r=t.strokeWidth/2,o=t.strokeUniform?new n.Point(1/t.scaleX,1/t.scaleY):new n.Point(1,1),a=function(e){var t=r/Math.hypot(e.x,e.y);return new n.Point(e.x*t*o.x,e.y*t*o.y)};return e.length<=1||e.forEach((function(c,l){var h,d,u=new n.Point(c.x,c.y);0===l?(d=e[l+1],h=i?a(n.util.createVector(d,u)).addEquals(u):e[e.length-1]):l===e.length-1?(h=e[l-1],d=i?a(n.util.createVector(h,u)).addEquals(u):e[0]):(h=e[l-1],d=e[l+1]);var g,p,m=n.util.getBisector(u,h,d),f=m.vector,_=m.angle;if("miter"===t.strokeLineJoin&&(g=-r/Math.sin(_/2),p=new n.Point(f.x*g*o.x,f.y*g*o.y),Math.hypot(p.x,p.y)/r<=t.strokeMiterLimit))return s.push(u.add(p)),void s.push(u.subtract(p));g=-r*Math.SQRT2,p=new n.Point(f.x*g*o.x,f.y*g*o.y),s.push(u.add(p)),s.push(u.subtract(p))})),s},transformPoint:function(e,t,i){return i?new n.Point(t[0]*e.x+t[2]*e.y,t[1]*e.x+t[3]*e.y):new n.Point(t[0]*e.x+t[2]*e.y+t[4],t[1]*e.x+t[3]*e.y+t[5])},makeBoundingBoxFromPoints:function(e,t){if(t)for(var i=0;i0&&(t>s?t-=s:t=0,i>s?i-=s:i=0);var n,r=!0,o=e.getImageData(t,i,2*s||1,2*s||1),a=o.data.length;for(n=3;n0)n.util.hasStyleChanged(r,l,!0)?o.push({start:s,end:s+1,style:l}):o[o.length-1].end++;r=l||{}}else s+=i[a].length;return o},stylesFromArray:function(e,t){if(!Array.isArray(e))return e;for(var i=t.split("\n"),s=-1,n=0,r={},o=0;o=n?r-n:2*Math.PI-(n-r)}function o(e,t,i){for(var o=i[1],a=i[2],c=i[3],l=i[4],h=i[5],d=function(e,t,i,o,a,c,l){var h=Math.PI,d=l*h/180,u=n.util.sin(d),g=n.util.cos(d),p=0,m=0,f=-g*e*.5-u*t*.5,_=-g*t*.5+u*e*.5,v=(i=Math.abs(i))*i,C=(o=Math.abs(o))*o,E=_*_,b=f*f,S=v*C-v*E-C*b,y=0;if(S<0){var w=Math.sqrt(1-S/(v*C));i*=w,o*=w}else y=(a===c?-1:1)*Math.sqrt(S/(v*E+C*b));var R=y*i*_/o,L=-y*o*f/i,T=g*R-u*L+.5*e,x=u*R+g*L+.5*t,k=r(1,0,(f-R)/i,(_-L)/o),A=r((f-R)/i,(_-L)/o,(-f-R)/i,(-_-L)/o);0===c&&A>0?A-=2*h:1===c&&A<0&&(A+=2*h);for(var N=Math.ceil(Math.abs(A/h*2)),I=[],O=A/N,D=8/3*Math.sin(O/4)*Math.sin(O/4)/Math.sin(O/2),M=k+O,P=0;P1e-4;)i=c(r),n=r,(s=a(l.x,l.y,i.x,i.y))+o>t?(r-=h,h/=2):(l=i,r+=h,o+=s);return i.angle=d(n),i}function p(e){for(var t,i,s,n,r=0,o=e.length,g=0,p=0,m=0,f=0,_=[],v=0;vy)for(var R=1,L=f.length;R2;for(t=t||0,h&&(c=e[2].xe[i-2].x?1:r.x===e[i-2].x?0:-1,l=r.y>e[i-2].y?1:r.y===e[i-2].y?0:-1),s.push(["L",r.x+c*t,r.y+l*t]),s},n.util.getPathSegmentsInfo=p,n.util.getBoundsOfCurve=function(t,i,s,r,o,a,c,l){var h;if(n.cachesBoundsOfCurve&&(h=e.call(arguments),n.boundsOfCurveCache[h]))return n.boundsOfCurveCache[h];var d,u,g,p,m,f,_,v,C=Math.sqrt,E=Math.min,b=Math.max,S=Math.abs,y=[],w=[[],[]];u=6*t-12*s+6*o,d=-3*t+9*s-9*o+3*c,g=3*s-3*t;for(var R=0;R<2;++R)if(R>0&&(u=6*i-12*r+6*a,d=-3*i+9*r-9*a+3*l,g=3*r-3*i),S(d)<1e-12){if(S(u)<1e-12)continue;0<(p=-g/u)&&p<1&&y.push(p)}else(_=u*u-4*g*d)<0||(0<(m=(-u+(v=C(_)))/(2*d))&&m<1&&y.push(m),0<(f=(-u-v)/(2*d))&&f<1&&y.push(f));for(var L,T,x,k=y.length,A=k;k--;)L=(x=1-(p=y[k]))*x*x*t+3*x*x*p*s+3*x*p*p*o+p*p*p*c,w[0][k]=L,T=x*x*x*i+3*x*x*p*r+3*x*p*p*a+p*p*p*l,w[1][k]=T;w[0][A]=t,w[1][A]=i,w[0][A+1]=c,w[1][A+1]=l;var N=[{x:E.apply(null,w[0]),y:E.apply(null,w[1])},{x:b.apply(null,w[0]),y:b.apply(null,w[1])}];return n.cachesBoundsOfCurve&&(n.boundsOfCurveCache[h]=N),N},n.util.getPointOnPath=function(e,t,i){i||(i=p(e));for(var s=0;t-i[s].length>0&&s=t}))}}}(),function(){function e(t,i,s){if(s)if(!n.isLikelyNode&&i instanceof Element)t=i;else if(i instanceof Array){t=[];for(var r=0,o=i.length;r57343)return e.charAt(t);if(55296<=i&&i<=56319){if(e.length<=t+1)throw"High surrogate without following low surrogate";var s=e.charCodeAt(t+1);if(56320>s||s>57343)throw"High surrogate without following low surrogate";return e.charAt(t)+e.charAt(t+1)}if(0===t)throw"Low surrogate without preceding high surrogate";var n=e.charCodeAt(t-1);if(55296>n||n>56319)throw"Low surrogate without preceding high surrogate";return!1}n.util.string={camelize:function(e){return e.replace(/-+(.)?/g,(function(e,t){return t?t.toUpperCase():""}))},capitalize:function(e,t){return e.charAt(0).toUpperCase()+(t?e.slice(1):e.slice(1).toLowerCase())},escapeXml:function(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")},graphemeSplit:function(t){var i,s=0,n=[];for(s=0;s-1?e.prototype[n]=function(e){return function(){var i=this.constructor.superclass;this.constructor.superclass=s;var n=t[e].apply(this,arguments);if(this.constructor.superclass=i,"initialize"!==e)return n}}(n):e.prototype[n]=t[n],i&&(t.toString!==Object.prototype.toString&&(e.prototype.toString=t.toString),t.valueOf!==Object.prototype.valueOf&&(e.prototype.valueOf=t.valueOf))};function r(){}function o(t){for(var i=null,s=this;s.constructor.superclass;){var n=s.constructor.superclass.prototype[t];if(s[t]!==n){i=n;break}s=s.constructor.superclass.prototype}return i?arguments.length>1?i.apply(this,e.call(arguments,1)):i.call(this):console.log("tried to callSuper "+t+", method not found in prototype chain",this)}n.util.createClass=function(){var i=null,n=e.call(arguments,0);function a(){this.initialize.apply(this,arguments)}"function"===typeof n[0]&&(i=n.shift()),a.superclass=i,a.subclasses=[],i&&(r.prototype=i.prototype,a.prototype=new r,i.subclasses.push(a));for(var c=0,l=n.length;c-1||"touch"===e.pointerType}}(),function(){var e=n.document.createElement("div"),t="string"===typeof e.style.opacity,i="string"===typeof e.style.filter,s=/alpha\s*\(\s*opacity\s*=\s*([^\)]+)\)/,r=function(e){return e};t?r=function(e,t){return e.style.opacity=t,e}:i&&(r=function(e,t){var i=e.style;return e.currentStyle&&!e.currentStyle.hasLayout&&(i.zoom=1),s.test(i.filter)?(t=t>=.9999?"":"alpha(opacity="+100*t+")",i.filter=i.filter.replace(s,t)):i.filter+=" alpha(opacity="+100*t+")",e}),n.util.setStyle=function(e,t){var i=e.style;if(!i)return e;if("string"===typeof t)return e.style.cssText+=";"+t,t.indexOf("opacity")>-1?r(e,t.match(/opacity:\s*(\d?\.?\d*)/)[1]):e;for(var s in t)if("opacity"===s)r(e,t[s]);else{var n="float"===s||"cssFloat"===s?"undefined"===typeof i.styleFloat?"cssFloat":"styleFloat":s;i.setProperty(n,t[s])}return e}}(),function(){var e=Array.prototype.slice;var t,i,s=function(t){return e.call(t,0)};try{t=s(n.document.childNodes)instanceof Array}catch(a){}function r(e,t){var i=n.document.createElement(e);for(var s in t)"class"===s?i.className=t[s]:"for"===s?i.htmlFor=t[s]:i.setAttribute(s,t[s]);return i}function o(e){for(var t=0,i=0,s=n.document.documentElement,r=n.document.body||{scrollLeft:0,scrollTop:0};e&&(e.parentNode||e.host)&&((e=e.parentNode||e.host)===n.document?(t=r.scrollLeft||s.scrollLeft||0,i=r.scrollTop||s.scrollTop||0):(t+=e.scrollLeft||0,i+=e.scrollTop||0),1!==e.nodeType||"fixed"!==e.style.position););return{left:t,top:i}}t||(s=function(e){for(var t=new Array(e.length),i=e.length;i--;)t[i]=e[i];return t}),i=n.document.defaultView&&n.document.defaultView.getComputedStyle?function(e,t){var i=n.document.defaultView.getComputedStyle(e,null);return i?i[t]:void 0}:function(e,t){var i=e.style[t];return!i&&e.currentStyle&&(i=e.currentStyle[t]),i},function(){var e=n.document.documentElement.style,t="userSelect"in e?"userSelect":"MozUserSelect"in e?"MozUserSelect":"WebkitUserSelect"in e?"WebkitUserSelect":"KhtmlUserSelect"in e?"KhtmlUserSelect":"";n.util.makeElementUnselectable=function(e){return"undefined"!==typeof e.onselectstart&&(e.onselectstart=n.util.falseFunction),t?e.style[t]="none":"string"===typeof e.unselectable&&(e.unselectable="on"),e},n.util.makeElementSelectable=function(e){return"undefined"!==typeof e.onselectstart&&(e.onselectstart=null),t?e.style[t]="":"string"===typeof e.unselectable&&(e.unselectable=""),e}}(),n.util.setImageSmoothing=function(e,t){e.imageSmoothingEnabled=e.imageSmoothingEnabled||e.webkitImageSmoothingEnabled||e.mozImageSmoothingEnabled||e.msImageSmoothingEnabled||e.oImageSmoothingEnabled,e.imageSmoothingEnabled=t},n.util.getById=function(e){return"string"===typeof e?n.document.getElementById(e):e},n.util.toArray=s,n.util.addClass=function(e,t){e&&-1===(" "+e.className+" ").indexOf(" "+t+" ")&&(e.className+=(e.className?" ":"")+t)},n.util.makeElement=r,n.util.wrapElement=function(e,t,i){return"string"===typeof t&&(t=r(t,i)),e.parentNode&&e.parentNode.replaceChild(t,e),t.appendChild(e),t},n.util.getScrollLeftTop=o,n.util.getElementOffset=function(e){var t,s,n=e&&e.ownerDocument,r={left:0,top:0},a={left:0,top:0},c={borderLeftWidth:"left",borderTopWidth:"top",paddingLeft:"left",paddingTop:"top"};if(!n)return a;for(var l in c)a[c[l]]+=parseInt(i(e,l),10)||0;return t=n.documentElement,"undefined"!==typeof e.getBoundingClientRect&&(r=e.getBoundingClientRect()),s=o(e),{left:r.left+s.left-(t.clientLeft||0)+a.left,top:r.top+s.top-(t.clientTop||0)+a.top}},n.util.getNodeCanvas=function(e){var t=n.jsdomImplForWrapper(e);return t._canvas||t._image},n.util.cleanUpJsdomNode=function(e){if(n.isLikelyNode){var t=n.jsdomImplForWrapper(e);t&&(t._image=null,t._canvas=null,t._currentSrc=null,t._attributes=null,t._classList=null)}}}(),function(){function e(){}n.util.request=function(t,i){i||(i={});var s=i.method?i.method.toUpperCase():"GET",r=i.onComplete||function(){},o=new n.window.XMLHttpRequest,a=i.body||i.parameters;return o.onreadystatechange=function(){4===o.readyState&&(r(o),o.onreadystatechange=e)},"GET"===s&&(a=null,"string"===typeof i.parameters&&(t=function(e,t){return e+(/\?/.test(e)?"&":"?")+t}(t,i.parameters))),o.open(s,t,!0),"POST"!==s&&"PUT"!==s||o.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),o.send(a),o}}(),n.log=console.log,n.warn=console.warn,function(){var e=n.util.object.extend,t=n.util.object.clone,i=[];function s(){return!1}function r(e,t,i,s){return-i*Math.cos(e/s*(Math.PI/2))+i+t}n.util.object.extend(i,{cancelAll:function(){var e=this.splice(0);return e.forEach((function(e){e.cancel()})),e},cancelByCanvas:function(e){if(!e)return[];var t=this.filter((function(t){return"object"===typeof t.target&&t.target.canvas===e}));return t.forEach((function(e){e.cancel()})),t},cancelByTarget:function(e){var t=this.findAnimationsByTarget(e);return t.forEach((function(e){e.cancel()})),t},findAnimationIndex:function(e){return this.indexOf(this.findAnimation(e))},findAnimation:function(e){return this.find((function(t){return t.cancel===e}))},findAnimationsByTarget:function(e){return e?this.filter((function(t){return t.target===e})):[]}});var o=n.window.requestAnimationFrame||n.window.webkitRequestAnimationFrame||n.window.mozRequestAnimationFrame||n.window.oRequestAnimationFrame||n.window.msRequestAnimationFrame||function(e){return n.window.setTimeout(e,1e3/60)},a=n.window.cancelAnimationFrame||n.window.clearTimeout;function c(){return o.apply(n.window,arguments)}n.util.animate=function(i){i||(i={});var o,a=!1,l=function(){var e=n.runningAnimations.indexOf(o);return e>-1&&n.runningAnimations.splice(e,1)[0]};return o=e(t(i),{cancel:function(){return a=!0,l()},currentValue:"startValue"in i?i.startValue:0,completionRate:0,durationRate:0}),n.runningAnimations.push(o),c((function(e){var t,n=e||+new Date,h=i.duration||500,d=n+h,u=i.onChange||s,g=i.abort||s,p=i.onComplete||s,m=i.easing||r,f="startValue"in i&&i.startValue.length>0,_="startValue"in i?i.startValue:0,v="endValue"in i?i.endValue:100,C=i.byValue||(f?_.map((function(e,t){return v[t]-_[t]})):v-_);i.onStart&&i.onStart(),function e(i){var s=(t=i||+new Date)>d?h:t-n,r=s/h,E=f?_.map((function(e,t){return m(s,_[t],C[t],h)})):m(s,_,C,h),b=f?Math.abs((E[0]-_[0])/C[0]):Math.abs((E-_)/C);if(o.currentValue=f?E.slice():E,o.completionRate=b,o.durationRate=r,!a){if(!g(E,b,r))return t>d?(o.currentValue=f?v.slice():v,o.completionRate=1,o.durationRate=1,u(f?v.slice():v,1,1),p(v,1,1),void l()):(u(E,b,r),void c(e));l()}}(n)})),o.cancel},n.util.requestAnimFrame=c,n.util.cancelAnimFrame=function(){return a.apply(n.window,arguments)},n.runningAnimations=i}(),function(){function e(e,t,i){var s="rgba("+parseInt(e[0]+i*(t[0]-e[0]),10)+","+parseInt(e[1]+i*(t[1]-e[1]),10)+","+parseInt(e[2]+i*(t[2]-e[2]),10);return s+=","+(e&&t?parseFloat(e[3]+i*(t[3]-e[3])):1),s+=")"}n.util.animateColor=function(t,i,s,r){var o=new n.Color(t).getSource(),a=new n.Color(i).getSource(),c=r.onComplete,l=r.onChange;return r=r||{},n.util.animate(n.util.object.extend(r,{duration:s||500,startValue:o,endValue:a,byValue:a,easing:function(t,i,s,n){return e(i,s,r.colorEasing?r.colorEasing(t,n):1-Math.cos(t/n*(Math.PI/2)))},onComplete:function(t,i,s){if(c)return c(e(a,a,0),i,s)},onChange:function(t,i,s){if(l){if(Array.isArray(t))return l(e(t,t,0),i,s);l(t,i,s)}}}))}}(),function(){function e(e,t,i,s){return e-1&&h>-1&&h-1)&&(i="stroke")}else{if("href"===e||"xlink:href"===e||"font"===e)return i;if("imageSmoothing"===e)return"optimizeQuality"===i;a=c?i.map(r):r(i,n)}}else i="";return!c&&isNaN(a)?i:a}function g(e){return new RegExp("^("+e.join("|")+")\\b","i")}function p(e,t){var i,s,n,r,o=[];for(n=0,r=t.length;n1;)c.shift(),l=t.util.multiplyTransformMatrices(l,c[0]);return l}}();var v=new RegExp("^\\s*("+t.reNum+"+)\\s*,?\\s*("+t.reNum+"+)\\s*,?\\s*("+t.reNum+"+)\\s*,?\\s*("+t.reNum+"+)\\s*$");function C(e){if(!t.svgViewBoxElementsRegEx.test(e.nodeName))return{};var i,s,n,o,a,c,l=e.getAttribute("viewBox"),h=1,d=1,u=e.getAttribute("width"),g=e.getAttribute("height"),p=e.getAttribute("x")||0,m=e.getAttribute("y")||0,f=e.getAttribute("preserveAspectRatio")||"",_=!l||!(l=l.match(v)),C=!u||!g||"100%"===u||"100%"===g,E=_&&C,b={},S="",y=0,w=0;if(b.width=0,b.height=0,b.toBeParsed=E,_&&(p||m)&&e.parentNode&&"#document"!==e.parentNode.nodeName&&(S=" translate("+r(p)+" "+r(m)+") ",a=(e.getAttribute("transform")||"")+S,e.setAttribute("transform",a),e.removeAttribute("x"),e.removeAttribute("y")),E)return b;if(_)return b.width=r(u),b.height=r(g),b;if(i=-parseFloat(l[1]),s=-parseFloat(l[2]),n=parseFloat(l[3]),o=parseFloat(l[4]),b.minX=i,b.minY=s,b.viewBoxWidth=n,b.viewBoxHeight=o,C?(b.width=n,b.height=o):(b.width=r(u),b.height=r(g),h=b.width/n,d=b.height/o),"none"!==(f=t.util.parsePreserveAspectRatioAttribute(f)).alignX&&("meet"===f.meetOrSlice&&(d=h=h>d?d:h),"slice"===f.meetOrSlice&&(d=h=h>d?h:d),y=b.width-n*h,w=b.height-o*h,"Mid"===f.alignX&&(y/=2),"Mid"===f.alignY&&(w/=2),"Min"===f.alignX&&(y=0),"Min"===f.alignY&&(w=0)),1===h&&1===d&&0===i&&0===s&&0===p&&0===m)return b;if((p||m)&&"#document"!==e.parentNode.nodeName&&(S=" translate("+r(p)+" "+r(m)+") "),a=S+" matrix("+h+" 0 0 "+d+" "+(i*h+y)+" "+(s*d+w)+") ","svg"===e.nodeName){for(c=e.ownerDocument.createElementNS(t.svgNS,"g");e.firstChild;)c.appendChild(e.firstChild);e.appendChild(c)}else(c=e).removeAttribute("x"),c.removeAttribute("y"),a=c.getAttribute("transform")+a;return c.setAttribute("transform",a),b}function E(e,t){var i="xlink:href",s=_(e,t.getAttribute(i).slice(1));if(s&&s.getAttribute(i)&&E(e,s),["gradientTransform","x1","x2","y1","y2","gradientUnits","cx","cy","r","fx","fy"].forEach((function(e){s&&!t.hasAttribute(e)&&s.hasAttribute(e)&&t.setAttribute(e,s.getAttribute(e))})),!t.children.length)for(var n=s.cloneNode(!0);n.firstChild;)t.appendChild(n.firstChild);t.removeAttribute(i)}t.parseSVGDocument=function(e,i,n,r){if(e){!function(e){for(var i=p(e,["use","svg:use"]),s=0;i.length&&se.x&&this.y>e.y},gte:function(e){return this.x>=e.x&&this.y>=e.y},lerp:function(e,t){return"undefined"===typeof t&&(t=.5),t=Math.max(Math.min(1,t),0),new i(this.x+(e.x-this.x)*t,this.y+(e.y-this.y)*t)},distanceFrom:function(e){var t=this.x-e.x,i=this.y-e.y;return Math.sqrt(t*t+i*i)},midPointFrom:function(e){return this.lerp(e)},min:function(e){return new i(Math.min(this.x,e.x),Math.min(this.y,e.y))},max:function(e){return new i(Math.max(this.x,e.x),Math.max(this.y,e.y))},toString:function(){return this.x+","+this.y},setXY:function(e,t){return this.x=e,this.y=t,this},setX:function(e){return this.x=e,this},setY:function(e){return this.y=e,this},setFromPoint:function(e){return this.x=e.x,this.y=e.y,this},swap:function(e){var t=this.x,i=this.y;this.x=e.x,this.y=e.y,e.x=t,e.y=i},clone:function(){return new i(this.x,this.y)}})}(t),function(e){"use strict";var t=e.fabric||(e.fabric={});function i(e){this.status=e,this.points=[]}t.Intersection?t.warn("fabric.Intersection is already defined"):(t.Intersection=i,t.Intersection.prototype={constructor:i,appendPoint:function(e){return this.points.push(e),this},appendPoints:function(e){return this.points=this.points.concat(e),this}},t.Intersection.intersectLineLine=function(e,s,n,r){var o,a=(r.x-n.x)*(e.y-n.y)-(r.y-n.y)*(e.x-n.x),c=(s.x-e.x)*(e.y-n.y)-(s.y-e.y)*(e.x-n.x),l=(r.y-n.y)*(s.x-e.x)-(r.x-n.x)*(s.y-e.y);if(0!==l){var h=a/l,d=c/l;0<=h&&h<=1&&0<=d&&d<=1?(o=new i("Intersection")).appendPoint(new t.Point(e.x+h*(s.x-e.x),e.y+h*(s.y-e.y))):o=new i}else o=new i(0===a||0===c?"Coincident":"Parallel");return o},t.Intersection.intersectLinePolygon=function(e,t,s){var n,r,o,a,c=new i,l=s.length;for(a=0;a0&&(c.status="Intersection"),c},t.Intersection.intersectPolygonPolygon=function(e,t){var s,n=new i,r=e.length;for(s=0;s0&&(n.status="Intersection"),n},t.Intersection.intersectPolygonRectangle=function(e,s,n){var r=s.min(n),o=s.max(n),a=new t.Point(o.x,r.y),c=new t.Point(r.x,o.y),l=i.intersectLinePolygon(r,a,e),h=i.intersectLinePolygon(a,o,e),d=i.intersectLinePolygon(o,c,e),u=i.intersectLinePolygon(c,r,e),g=new i;return g.appendPoints(l.points),g.appendPoints(h.points),g.appendPoints(d.points),g.appendPoints(u.points),g.points.length>0&&(g.status="Intersection"),g})}(t),function(e){"use strict";var t=e.fabric||(e.fabric={});function i(e){e?this._tryParsingColor(e):this.setSource([0,0,0,1])}function s(e,t,i){return i<0&&(i+=1),i>1&&(i-=1),i<1/6?e+6*(t-e)*i:i<.5?t:i<2/3?e+(t-e)*(2/3-i)*6:e}t.Color?t.warn("fabric.Color is already defined."):(t.Color=i,t.Color.prototype={_tryParsingColor:function(e){var t;e in i.colorNameMap&&(e=i.colorNameMap[e]),"transparent"===e&&(t=[255,255,255,0]),t||(t=i.sourceFromHex(e)),t||(t=i.sourceFromRgb(e)),t||(t=i.sourceFromHsl(e)),t||(t=[0,0,0,1]),t&&this.setSource(t)},_rgbToHsl:function(e,i,s){e/=255,i/=255,s/=255;var n,r,o,a=t.util.array.max([e,i,s]),c=t.util.array.min([e,i,s]);if(o=(a+c)/2,a===c)n=r=0;else{var l=a-c;switch(r=o>.5?l/(2-a-c):l/(a+c),a){case e:n=(i-s)/l+(i0)-(e<0)||+e};function g(e,t){var i=e.angle+d(Math.atan2(t.y,t.x))+360;return Math.round(i%360/45)}function p(e,i){var s=i.transform.target,n=s.canvas,r=t.util.object.clone(i);r.target=s,n&&n.fire("object:"+e,r),s.fire(e,i)}function m(e,t){var i=t.canvas,s=e[i.uniScaleKey];return i.uniformScaling&&!s||!i.uniformScaling&&s}function f(e){return e.originX===l&&e.originY===l}function _(e,t,i){var s=e.lockScalingX,n=e.lockScalingY;return!(!s||!n)||(!(t||!s&&!n||!i)||(!(!s||"x"!==t)||!(!n||"y"!==t)))}function v(e,t,i,s){return{e:e,transform:t,pointer:{x:i,y:s}}}function C(e){return function(t,i,s,n){var r=i.target,o=r.getCenterPoint(),a=r.translateToOriginPoint(o,i.originX,i.originY),c=e(t,i,s,n);return r.setPositionByOrigin(a,i.originX,i.originY),c}}function E(e,t){return function(i,s,n,r){var o=t(i,s,n,r);return o&&p(e,v(i,s,n,r)),o}}function b(e,i,s,n,r){var o=e.target,a=o.controls[e.corner],c=o.canvas.getZoom(),l=o.padding/c,h=o.toLocalPoint(new t.Point(n,r),i,s);return h.x>=l&&(h.x-=l),h.x<=-l&&(h.x+=l),h.y>=l&&(h.y-=l),h.y<=l&&(h.y+=l),h.x-=a.offsetX,h.y-=a.offsetY,h}function S(e){return e.flipX!==e.flipY}function y(e,t,i,s,n){if(0!==e[t]){var r=n/e._getTransformedDimensions()[s]*e[i];e.set(i,r)}}function w(e,t,i,s){var n,l=t.target,h=l._getTransformedDimensions(0,l.skewY),u=b(t,t.originX,t.originY,i,s),g=Math.abs(2*u.x)-h.x,p=l.skewX;g<2?n=0:(n=d(Math.atan2(g/l.scaleX,h.y/l.scaleY)),t.originX===r&&t.originY===c&&(n=-n),t.originX===a&&t.originY===o&&(n=-n),S(l)&&(n=-n));var m=p!==n;if(m){var f=l._getTransformedDimensions().y;l.set("skewX",n),y(l,"skewY","scaleY","y",f)}return m}function R(e,t,i,s){var n,l=t.target,h=l._getTransformedDimensions(l.skewX,0),u=b(t,t.originX,t.originY,i,s),g=Math.abs(2*u.y)-h.y,p=l.skewY;g<2?n=0:(n=d(Math.atan2(g/l.scaleY,h.x/l.scaleX)),t.originX===r&&t.originY===c&&(n=-n),t.originX===a&&t.originY===o&&(n=-n),S(l)&&(n=-n));var m=p!==n;if(m){var f=l._getTransformedDimensions().x;l.set("skewY",n),y(l,"skewX","scaleX","x",f)}return m}function L(e,t,i,s,n){n=n||{};var r,o,a,c,l,d,g=t.target,p=g.lockScalingX,v=g.lockScalingY,C=n.by,E=m(e,g),S=_(g,C,E),y=t.gestureScale;if(S)return!1;if(y)o=t.scaleX*y,a=t.scaleY*y;else{if(r=b(t,t.originX,t.originY,i,s),l="y"!==C?u(r.x):1,d="x"!==C?u(r.y):1,t.signX||(t.signX=l),t.signY||(t.signY=d),g.lockScalingFlip&&(t.signX!==l||t.signY!==d))return!1;if(c=g._getTransformedDimensions(),E&&!C){var w=Math.abs(r.x)+Math.abs(r.y),R=t.original,L=w/(Math.abs(c.x*R.scaleX/g.scaleX)+Math.abs(c.y*R.scaleY/g.scaleY));o=R.scaleX*L,a=R.scaleY*L}else o=Math.abs(r.x*g.scaleX/c.x),a=Math.abs(r.y*g.scaleY/c.y);f(t)&&(o*=2,a*=2),t.signX!==l&&"y"!==C&&(t.originX=h[t.originX],o*=-1,t.signX=l),t.signY!==d&&"x"!==C&&(t.originY=h[t.originY],a*=-1,t.signY=d)}var T=g.scaleX,x=g.scaleY;return C?("x"===C&&g.set("scaleX",o),"y"===C&&g.set("scaleY",a)):(!p&&g.set("scaleX",o),!v&&g.set("scaleY",a)),T!==g.scaleX||x!==g.scaleY}n.scaleCursorStyleHandler=function(e,t,s){var n=m(e,s),r="";if(0!==t.x&&0===t.y?r="x":0===t.x&&0!==t.y&&(r="y"),_(s,r,n))return"not-allowed";var o=g(s,t);return i[o]+"-resize"},n.skewCursorStyleHandler=function(e,t,i){var n="not-allowed";if(0!==t.x&&i.lockSkewingY)return n;if(0!==t.y&&i.lockSkewingX)return n;var r=g(i,t)%4;return s[r]+"-resize"},n.scaleSkewCursorStyleHandler=function(e,t,i){return e[i.canvas.altActionKey]?n.skewCursorStyleHandler(e,t,i):n.scaleCursorStyleHandler(e,t,i)},n.rotationWithSnapping=E("rotating",C((function(e,t,i,s){var n=t,r=n.target,o=r.translateToOriginPoint(r.getCenterPoint(),n.originX,n.originY);if(r.lockRotation)return!1;var a,c=Math.atan2(n.ey-o.y,n.ex-o.x),l=Math.atan2(s-o.y,i-o.x),h=d(l-c+n.theta);if(r.snapAngle>0){var u=r.snapAngle,g=r.snapThreshold||u,p=Math.ceil(h/u)*u,m=Math.floor(h/u)*u;Math.abs(h-m)0?r:a:(h>0&&(n=d===o?r:a),h<0&&(n=d===o?a:r),S(c)&&(n=n===r?a:r)),t.originX=n,E("skewing",C(w))(e,t,i,s))},n.skewHandlerY=function(e,t,i,s){var n,a=t.target,h=a.skewY,d=t.originX;return!a.lockSkewingY&&(0===h?n=b(t,l,l,i,s).y>0?o:c:(h>0&&(n=d===r?o:c),h<0&&(n=d===r?c:o),S(a)&&(n=n===o?c:o)),t.originY=n,E("skewing",C(R))(e,t,i,s))},n.dragHandler=function(e,t,i,s){var n=t.target,r=i-t.offsetX,o=s-t.offsetY,a=!n.get("lockMovementX")&&n.left!==r,c=!n.get("lockMovementY")&&n.top!==o;return a&&n.set("left",r),c&&n.set("top",o),(a||c)&&p("moving",v(e,t,i,s)),a||c},n.scaleOrSkewActionName=function(e,t,i){var s=e[i.canvas.altActionKey];return 0===t.x?s?"skewX":"scaleY":0===t.y?s?"skewY":"scaleX":void 0},n.rotationStyleHandler=function(e,t,i){return i.lockRotation?"not-allowed":t.cursorStyle},n.fireEvent=p,n.wrapWithFixedAnchor=C,n.wrapWithFireEvent=E,n.getLocalPoint=b,t.controlsUtils=n}(t),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.util.degreesToRadians,s=t.controlsUtils;s.renderCircleControl=function(e,t,i,s,n){s=s||{};var r,o=this.sizeX||s.cornerSize||n.cornerSize,a=this.sizeY||s.cornerSize||n.cornerSize,c="undefined"!==typeof s.transparentCorners?s.transparentCorners:n.transparentCorners,l=c?"stroke":"fill",h=!c&&(s.cornerStrokeColor||n.cornerStrokeColor),d=t,u=i;e.save(),e.fillStyle=s.cornerColor||n.cornerColor,e.strokeStyle=s.cornerStrokeColor||n.cornerStrokeColor,o>a?(r=o,e.scale(1,a/o),u=i*o/a):a>o?(r=a,e.scale(o/a,1),d=t*a/o):r=o,e.lineWidth=1,e.beginPath(),e.arc(d,u,r/2,0,2*Math.PI,!1),e[l](),h&&e.stroke(),e.restore()},s.renderSquareControl=function(e,t,s,n,r){n=n||{};var o=this.sizeX||n.cornerSize||r.cornerSize,a=this.sizeY||n.cornerSize||r.cornerSize,c="undefined"!==typeof n.transparentCorners?n.transparentCorners:r.transparentCorners,l=c?"stroke":"fill",h=!c&&(n.cornerStrokeColor||r.cornerStrokeColor),d=o/2,u=a/2;e.save(),e.fillStyle=n.cornerColor||r.cornerColor,e.strokeStyle=n.cornerStrokeColor||r.cornerStrokeColor,e.lineWidth=1,e.translate(t,s),e.rotate(i(r.angle)),e[l+"Rect"](-d,-u,o,a),h&&e.strokeRect(-d,-u,o,a),e.restore()}}(t),function(e){"use strict";var t=e.fabric||(e.fabric={});t.Control=function(e){for(var t in e)this[t]=e[t]},t.Control.prototype={visible:!0,actionName:"scale",angle:0,x:0,y:0,offsetX:0,offsetY:0,sizeX:null,sizeY:null,touchSizeX:null,touchSizeY:null,cursorStyle:"crosshair",withConnection:!1,actionHandler:function(){},mouseDownHandler:function(){},mouseUpHandler:function(){},getActionHandler:function(){return this.actionHandler},getMouseDownHandler:function(){return this.mouseDownHandler},getMouseUpHandler:function(){return this.mouseUpHandler},cursorStyleHandler:function(e,t){return t.cursorStyle},getActionName:function(e,t){return t.actionName},getVisibility:function(e,t){var i=e._controlsVisibility;return i&&"undefined"!==typeof i[t]?i[t]:this.visible},setVisibility:function(e){this.visible=e},positionHandler:function(e,i){return t.util.transformPoint({x:this.x*e.x+this.offsetX,y:this.y*e.y+this.offsetY},i)},calcCornerCoords:function(e,i,s,n,r){var o,a,c,l,h=r?this.touchSizeX:this.sizeX,d=r?this.touchSizeY:this.sizeY;if(h&&d&&h!==d){var u=Math.atan2(d,h),g=Math.sqrt(h*h+d*d)/2,p=u-t.util.degreesToRadians(e),m=Math.PI/2-u-t.util.degreesToRadians(e);o=g*t.util.cos(p),a=g*t.util.sin(p),c=g*t.util.cos(m),l=g*t.util.sin(m)}else{g=.7071067812*(h&&d?h:i);p=t.util.degreesToRadians(45-e);o=c=g*t.util.cos(p),a=l=g*t.util.sin(p)}return{tl:{x:s-l,y:n-c},tr:{x:s+o,y:n-a},bl:{x:s-o,y:n+a},br:{x:s+l,y:n+c}}},render:function(e,i,s,n,r){if("circle"===((n=n||{}).cornerStyle||r.cornerStyle))t.controlsUtils.renderCircleControl.call(this,e,i,s,n,r);else t.controlsUtils.renderSquareControl.call(this,e,i,s,n,r)}}}(t),function(){function e(e,t){var i,s,r,o,a=e.getAttribute("style"),c=e.getAttribute("offset")||0;if(c=(c=parseFloat(c)/(/%$/.test(c)?100:1))<0?0:c>1?1:c,a){var l=a.split(/\s*;\s*/);for(""===l[l.length-1]&&l.pop(),o=l.length;o--;){var h=l[o].split(/\s*:\s*/),d=h[0].trim(),u=h[1].trim();"stop-color"===d?i=u:"stop-opacity"===d&&(r=u)}}return i||(i=e.getAttribute("stop-color")||"rgb(0,0,0)"),r||(r=e.getAttribute("stop-opacity")),s=(i=new n.Color(i)).getAlpha(),r=isNaN(parseFloat(r))?1:parseFloat(r),r*=s*t,{offset:c,color:i.toRgb(),opacity:r}}var t=n.util.object.clone;n.Gradient=n.util.createClass({offsetX:0,offsetY:0,gradientTransform:null,gradientUnits:"pixels",type:"linear",initialize:function(e){e||(e={}),e.coords||(e.coords={});var t,i=this;Object.keys(e).forEach((function(t){i[t]=e[t]})),this.id?this.id+="_"+n.Object.__uid++:this.id=n.Object.__uid++,t={x1:e.coords.x1||0,y1:e.coords.y1||0,x2:e.coords.x2||0,y2:e.coords.y2||0},"radial"===this.type&&(t.r1=e.coords.r1||0,t.r2=e.coords.r2||0),this.coords=t,this.colorStops=e.colorStops.slice()},addColorStop:function(e){for(var t in e){var i=new n.Color(e[t]);this.colorStops.push({offset:parseFloat(t),color:i.toRgb(),opacity:i.getAlpha()})}return this},toObject:function(e){var t={type:this.type,coords:this.coords,colorStops:this.colorStops,offsetX:this.offsetX,offsetY:this.offsetY,gradientUnits:this.gradientUnits,gradientTransform:this.gradientTransform?this.gradientTransform.concat():this.gradientTransform};return n.util.populateWithProperties(this,t,e),t},toSVG:function(e,i){var s,r,o,a,c=t(this.coords,!0),l=(i=i||{},t(this.colorStops,!0)),h=c.r1>c.r2,d=this.gradientTransform?this.gradientTransform.concat():n.iMatrix.concat(),u=-this.offsetX,g=-this.offsetY,p=!!i.additionalTransform,m="pixels"===this.gradientUnits?"userSpaceOnUse":"objectBoundingBox";if(l.sort((function(e,t){return e.offset-t.offset})),"objectBoundingBox"===m?(u/=e.width,g/=e.height):(u+=e.width/2,g+=e.height/2),"path"===e.type&&"percentage"!==this.gradientUnits&&(u-=e.pathOffset.x,g-=e.pathOffset.y),d[4]-=u,d[5]-=g,a='id="SVGID_'+this.id+'" gradientUnits="'+m+'"',a+=' gradientTransform="'+(p?i.additionalTransform+" ":"")+n.util.matrixToSVG(d)+'" ',"linear"===this.type?o=["\n']:"radial"===this.type&&(o=["\n']),"radial"===this.type){if(h)for((l=l.concat()).reverse(),s=0,r=l.length;s0){var _=f/Math.max(c.r1,c.r2);for(s=0,r=l.length;s\n')}return o.push("linear"===this.type?"\n":"\n"),o.join("")},toLive:function(e){var t,i,s,r=n.util.object.clone(this.coords);if(this.type){for("linear"===this.type?t=e.createLinearGradient(r.x1,r.y1,r.x2,r.y2):"radial"===this.type&&(t=e.createRadialGradient(r.x1,r.y1,r.r1,r.x2,r.y2,r.r2)),i=0,s=this.colorStops.length;i1?1:o,isNaN(o)&&(o=1);var a,c,l,h,d=t.getElementsByTagName("stop"),u="userSpaceOnUse"===t.getAttribute("gradientUnits")?"pixels":"percentage",g=t.getAttribute("gradientTransform")||"",p=[],m=0,f=0;for("linearGradient"===t.nodeName||"LINEARGRADIENT"===t.nodeName?(a="linear",c=function(e){return{x1:e.getAttribute("x1")||0,y1:e.getAttribute("y1")||0,x2:e.getAttribute("x2")||"100%",y2:e.getAttribute("y2")||0}}(t)):(a="radial",c=function(e){return{x1:e.getAttribute("fx")||e.getAttribute("cx")||"50%",y1:e.getAttribute("fy")||e.getAttribute("cy")||"50%",r1:0,x2:e.getAttribute("cx")||"50%",y2:e.getAttribute("cy")||"50%",r2:e.getAttribute("r")||"50%"}}(t)),l=d.length;l--;)p.push(e(d[l],o));return h=n.parseTransformAttribute(g),function(e,t,i,s){var n,r;Object.keys(t).forEach((function(e){"Infinity"===(n=t[e])?r=1:"-Infinity"===n?r=0:(r=parseFloat(t[e],10),"string"===typeof n&&/^(\d+\.\d+)%|(\d+)%$/.test(n)&&(r*=.01,"pixels"===s&&("x1"!==e&&"x2"!==e&&"r2"!==e||(r*=i.viewBoxWidth||i.width),"y1"!==e&&"y2"!==e||(r*=i.viewBoxHeight||i.height)))),t[e]=r}))}(0,c,r,u),"pixels"===u&&(m=-i.left,f=-i.top),new n.Gradient({id:t.getAttribute("id"),type:a,coords:c,colorStops:p,gradientUnits:u,gradientTransform:h,offsetX:m,offsetY:f})}})}(),function(){"use strict";var e=n.util.toFixed;n.Pattern=n.util.createClass({repeat:"repeat",offsetX:0,offsetY:0,crossOrigin:"",patternTransform:null,initialize:function(e,t){if(e||(e={}),this.id=n.Object.__uid++,this.setOptions(e),!e.source||e.source&&"string"!==typeof e.source)t&&t(this);else{var i=this;this.source=n.util.createImage(),n.util.loadImage(e.source,(function(e,s){i.source=e,t&&t(i,s)}),null,this.crossOrigin)}},toObject:function(t){var i,s,r=n.Object.NUM_FRACTION_DIGITS;return"string"===typeof this.source.src?i=this.source.src:"object"===typeof this.source&&this.source.toDataURL&&(i=this.source.toDataURL()),s={type:"pattern",source:i,repeat:this.repeat,crossOrigin:this.crossOrigin,offsetX:e(this.offsetX,r),offsetY:e(this.offsetY,r),patternTransform:this.patternTransform?this.patternTransform.concat():null},n.util.populateWithProperties(this,s,t),s},toSVG:function(e){var t="function"===typeof this.source?this.source():this.source,i=t.width/e.width,s=t.height/e.height,n=this.offsetX/e.width,r=this.offsetY/e.height,o="";return"repeat-x"!==this.repeat&&"no-repeat"!==this.repeat||(s=1,r&&(s+=Math.abs(r))),"repeat-y"!==this.repeat&&"no-repeat"!==this.repeat||(i=1,n&&(i+=Math.abs(n))),t.src?o=t.src:t.toDataURL&&(o=t.toDataURL()),'\n\n\n'},setOptions:function(e){for(var t in e)this[t]=e[t]},toLive:function(e){var t=this.source;if(!t)return"";if("undefined"!==typeof t.src){if(!t.complete)return"";if(0===t.naturalWidth||0===t.naturalHeight)return""}return e.createPattern(t,this.repeat)}})}(),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.util.toFixed;t.Shadow?t.warn("fabric.Shadow is already defined."):(t.Shadow=t.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,nonScaling:!1,initialize:function(e){for(var i in"string"===typeof e&&(e=this._parseShadow(e)),e)this[i]=e[i];this.id=t.Object.__uid++},_parseShadow:function(e){var i=e.trim(),s=t.Shadow.reOffsetsAndBlur.exec(i)||[];return{color:(i.replace(t.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").trim(),offsetX:parseFloat(s[1],10)||0,offsetY:parseFloat(s[2],10)||0,blur:parseFloat(s[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(e){var s=40,n=40,r=t.Object.NUM_FRACTION_DIGITS,o=t.util.rotateVector({x:this.offsetX,y:this.offsetY},t.util.degreesToRadians(-e.angle)),a=new t.Color(this.color);return e.width&&e.height&&(s=100*i((Math.abs(o.x)+this.blur)/e.width,r)+20,n=100*i((Math.abs(o.y)+this.blur)/e.height,r)+20),e.flipX&&(o.x*=-1),e.flipY&&(o.y*=-1),'\n\t\n\t\n\t\n\t\n\t\n\t\t\n\t\t\n\t\n\n'},toObject:function(){if(this.includeDefaultValues)return{color:this.color,blur:this.blur,offsetX:this.offsetX,offsetY:this.offsetY,affectStroke:this.affectStroke,nonScaling:this.nonScaling};var e={},i=t.Shadow.prototype;return["color","blur","offsetX","offsetY","affectStroke","nonScaling"].forEach((function(t){this[t]!==i[t]&&(e[t]=this[t])}),this),e}}),t.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:\.\d*)?(?:px)?(?:\s?|$))?(-?\d+(?:\.\d*)?(?:px)?(?:\s?|$))?(\d+(?:\.\d*)?(?:px)?)?(?:\s?|$)(?:$|\s)/)}(t),function(){"use strict";if(n.StaticCanvas)n.warn("fabric.StaticCanvas is already defined.");else{var e=n.util.object.extend,t=n.util.getElementOffset,i=n.util.removeFromArray,s=n.util.toFixed,r=n.util.transformPoint,o=n.util.invertTransform,a=n.util.getNodeCanvas,c=n.util.createCanvasElement,l=new Error("Could not initialize `canvas` element");n.StaticCanvas=n.util.createClass(n.CommonMethods,{initialize:function(e,t){t||(t={}),this.renderAndResetBound=this.renderAndReset.bind(this),this.requestRenderAllBound=this.requestRenderAll.bind(this),this._initStatic(e,t)},backgroundColor:"",backgroundImage:null,overlayColor:"",overlayImage:null,includeDefaultValues:!0,stateful:!1,renderOnAddRemove:!0,controlsAboveOverlay:!1,allowTouchScrolling:!1,imageSmoothingEnabled:!0,viewportTransform:n.iMatrix.concat(),backgroundVpt:!0,overlayVpt:!0,enableRetinaScaling:!0,vptCoords:{},skipOffscreen:!0,clipPath:void 0,_initStatic:function(e,t){var i=this.requestRenderAllBound;this._objects=[],this._createLowerCanvas(e),this._initOptions(t),this.interactive||this._initRetinaScaling(),t.overlayImage&&this.setOverlayImage(t.overlayImage,i),t.backgroundImage&&this.setBackgroundImage(t.backgroundImage,i),t.backgroundColor&&this.setBackgroundColor(t.backgroundColor,i),t.overlayColor&&this.setOverlayColor(t.overlayColor,i),this.calcOffset()},_isRetinaScaling:function(){return n.devicePixelRatio>1&&this.enableRetinaScaling},getRetinaScaling:function(){return this._isRetinaScaling()?Math.max(1,n.devicePixelRatio):1},_initRetinaScaling:function(){if(this._isRetinaScaling()){var e=n.devicePixelRatio;this.__initRetinaScaling(e,this.lowerCanvasEl,this.contextContainer),this.upperCanvasEl&&this.__initRetinaScaling(e,this.upperCanvasEl,this.contextTop)}},__initRetinaScaling:function(e,t,i){t.setAttribute("width",this.width*e),t.setAttribute("height",this.height*e),i.scale(e,e)},calcOffset:function(){return this._offset=t(this.lowerCanvasEl),this},setOverlayImage:function(e,t,i){return this.__setBgOverlayImage("overlayImage",e,t,i)},setBackgroundImage:function(e,t,i){return this.__setBgOverlayImage("backgroundImage",e,t,i)},setOverlayColor:function(e,t){return this.__setBgOverlayColor("overlayColor",e,t)},setBackgroundColor:function(e,t){return this.__setBgOverlayColor("backgroundColor",e,t)},__setBgOverlayImage:function(e,t,i,s){return"string"===typeof t?n.util.loadImage(t,(function(t,r){if(t){var o=new n.Image(t,s);this[e]=o,o.canvas=this}i&&i(t,r)}),this,s&&s.crossOrigin):(s&&t.setOptions(s),this[e]=t,t&&(t.canvas=this),i&&i(t,!1)),this},__setBgOverlayColor:function(e,t,i){return this[e]=t,this._initGradient(t,e),this._initPattern(t,e,i),this},_createCanvasElement:function(){var e=c();if(!e)throw l;if(e.style||(e.style={}),"undefined"===typeof e.getContext)throw l;return e},_initOptions:function(e){var t=this.lowerCanvasEl;this._setOptions(e),this.width=this.width||parseInt(t.width,10)||0,this.height=this.height||parseInt(t.height,10)||0,this.lowerCanvasEl.style&&(t.width=this.width,t.height=this.height,t.style.width=this.width+"px",t.style.height=this.height+"px",this.viewportTransform=this.viewportTransform.slice())},_createLowerCanvas:function(e){e&&e.getContext?this.lowerCanvasEl=e:this.lowerCanvasEl=n.util.getById(e)||this._createCanvasElement(),n.util.addClass(this.lowerCanvasEl,"lower-canvas"),this._originalCanvasStyle=this.lowerCanvasEl.style,this.interactive&&this._applyCanvasStyle(this.lowerCanvasEl),this.contextContainer=this.lowerCanvasEl.getContext("2d")},getWidth:function(){return this.width},getHeight:function(){return this.height},setWidth:function(e,t){return this.setDimensions({width:e},t)},setHeight:function(e,t){return this.setDimensions({height:e},t)},setDimensions:function(e,t){var i;for(var s in t=t||{},e)i=e[s],t.cssOnly||(this._setBackstoreDimension(s,e[s]),i+="px",this.hasLostContext=!0),t.backstoreOnly||this._setCssDimension(s,i);return this._isCurrentlyDrawing&&this.freeDrawingBrush&&this.freeDrawingBrush._setBrushStyles(this.contextTop),this._initRetinaScaling(),this.calcOffset(),t.cssOnly||this.requestRenderAll(),this},_setBackstoreDimension:function(e,t){return this.lowerCanvasEl[e]=t,this.upperCanvasEl&&(this.upperCanvasEl[e]=t),this.cacheCanvasEl&&(this.cacheCanvasEl[e]=t),this[e]=t,this},_setCssDimension:function(e,t){return this.lowerCanvasEl.style[e]=t,this.upperCanvasEl&&(this.upperCanvasEl.style[e]=t),this.wrapperEl&&(this.wrapperEl.style[e]=t),this},getZoom:function(){return this.viewportTransform[0]},setViewportTransform:function(e){var t,i,s,n=this._activeObject,r=this.backgroundImage,o=this.overlayImage;for(this.viewportTransform=e,i=0,s=this._objects.length;i\n'),this._setSVGBgOverlayColor(i,"background"),this._setSVGBgOverlayImage(i,"backgroundImage",t),this._setSVGObjects(i,t),this.clipPath&&i.push("\n"),this._setSVGBgOverlayColor(i,"overlay"),this._setSVGBgOverlayImage(i,"overlayImage",t),i.push(""),i.join("")},_setSVGPreamble:function(e,t){t.suppressPreamble||e.push('\n','\n')},_setSVGHeader:function(e,t){var i,r=t.width||this.width,o=t.height||this.height,a='viewBox="0 0 '+this.width+" "+this.height+'" ',c=n.Object.NUM_FRACTION_DIGITS;t.viewBox?a='viewBox="'+t.viewBox.x+" "+t.viewBox.y+" "+t.viewBox.width+" "+t.viewBox.height+'" ':this.svgViewportTransformation&&(i=this.viewportTransform,a='viewBox="'+s(-i[4]/i[0],c)+" "+s(-i[5]/i[3],c)+" "+s(this.width/i[0],c)+" "+s(this.height/i[3],c)+'" '),e.push("\n',"Created with Fabric.js ",n.version,"\n","\n",this.createSVGFontFacesMarkup(),this.createSVGRefElementsMarkup(),this.createSVGClipPathMarkup(t),"\n")},createSVGClipPathMarkup:function(e){var t=this.clipPath;return t?(t.clipPathId="CLIPPATH_"+n.Object.__uid++,'\n'+this.clipPath.toClipPathSVG(e.reviver)+"\n"):""},createSVGRefElementsMarkup:function(){var e=this;return["background","overlay"].map((function(t){var i=e[t+"Color"];if(i&&i.toLive){var s=e[t+"Vpt"],r=e.viewportTransform,o={width:e.width/(s?r[0]:1),height:e.height/(s?r[3]:1)};return i.toSVG(o,{additionalTransform:s?n.util.matrixToSVG(r):""})}})).join("")},createSVGFontFacesMarkup:function(){var e,t,i,s,r,o,a,c,l="",h={},d=n.fontPaths,u=[];for(this._objects.forEach((function e(t){u.push(t),t._objects&&t._objects.forEach(e)})),a=0,c=u.length;a',"\n",l,"","\n"].join("")),l},_setSVGObjects:function(e,t){var i,s,n,r=this._objects;for(s=0,n=r.length;s\n")}else e.push('\n")},sendToBack:function(e){if(!e)return this;var t,s,n,r=this._activeObject;if(e===r&&"activeSelection"===e.type)for(t=(n=r._objects).length;t--;)s=n[t],i(this._objects,s),this._objects.unshift(s);else i(this._objects,e),this._objects.unshift(e);return this.renderOnAddRemove&&this.requestRenderAll(),this},bringToFront:function(e){if(!e)return this;var t,s,n,r=this._activeObject;if(e===r&&"activeSelection"===e.type)for(n=r._objects,t=0;t0+l&&(o=r-1,i(this._objects,n),this._objects.splice(o,0,n)),l++;else 0!==(r=this._objects.indexOf(e))&&(o=this._findNewLowerIndex(e,r,t),i(this._objects,e),this._objects.splice(o,0,e));return this.renderOnAddRemove&&this.requestRenderAll(),this},_findNewLowerIndex:function(e,t,i){var s,n;if(i)for(s=t,n=t-1;n>=0;--n){if(e.intersectsWithObject(this._objects[n])||e.isContainedWithinObject(this._objects[n])||this._objects[n].isContainedWithinObject(e)){s=n;break}}else s=t-1;return s},bringForward:function(e,t){if(!e)return this;var s,n,r,o,a,c=this._activeObject,l=0;if(e===c&&"activeSelection"===e.type)for(s=(a=c._objects).length;s--;)n=a[s],(r=this._objects.indexOf(n))"}}),e(n.StaticCanvas.prototype,n.Observable),e(n.StaticCanvas.prototype,n.Collection),e(n.StaticCanvas.prototype,n.DataURLExporter),e(n.StaticCanvas,{EMPTY_JSON:'{"objects": [], "background": "white"}',supports:function(e){var t=c();if(!t||!t.getContext)return null;var i=t.getContext("2d");return i&&"setLineDash"===e?"undefined"!==typeof i.setLineDash:null}}),n.StaticCanvas.prototype.toJSON=n.StaticCanvas.prototype.toObject,n.isLikelyNode&&(n.StaticCanvas.prototype.createPNGStream=function(){var e=a(this.lowerCanvasEl);return e&&e.createPNGStream()},n.StaticCanvas.prototype.createJPEGStream=function(e){var t=a(this.lowerCanvasEl);return t&&t.createJPEGStream(e)})}}(),n.BaseBrush=n.util.createClass({color:"rgb(0, 0, 0)",width:1,shadow:null,strokeLineCap:"round",strokeLineJoin:"round",strokeMiterLimit:10,strokeDashArray:null,limitedToCanvasSize:!1,_setBrushStyles:function(e){e.strokeStyle=this.color,e.lineWidth=this.width,e.lineCap=this.strokeLineCap,e.miterLimit=this.strokeMiterLimit,e.lineJoin=this.strokeLineJoin,e.setLineDash(this.strokeDashArray||[])},_saveAndTransform:function(e){var t=this.canvas.viewportTransform;e.save(),e.transform(t[0],t[1],t[2],t[3],t[4],t[5])},_setShadow:function(){if(this.shadow){var e=this.canvas,t=this.shadow,i=e.contextTop,s=e.getZoom();e&&e._isRetinaScaling()&&(s*=n.devicePixelRatio),i.shadowColor=t.color,i.shadowBlur=t.blur*s,i.shadowOffsetX=t.offsetX*s,i.shadowOffsetY=t.offsetY*s}},needsFullRender:function(){return new n.Color(this.color).getAlpha()<1||!!this.shadow},_resetShadow:function(){var e=this.canvas.contextTop;e.shadowColor="",e.shadowBlur=e.shadowOffsetX=e.shadowOffsetY=0},_isOutSideCanvas:function(e){return e.x<0||e.x>this.canvas.getWidth()||e.y<0||e.y>this.canvas.getHeight()}}),n.PencilBrush=n.util.createClass(n.BaseBrush,{decimate:.4,drawStraightLine:!1,straightLineKey:"shiftKey",initialize:function(e){this.canvas=e,this._points=[]},needsFullRender:function(){return this.callSuper("needsFullRender")||this._hasStraightLine},_drawSegment:function(e,t,i){var s=t.midPointFrom(i);return e.quadraticCurveTo(t.x,t.y,s.x,s.y),s},onMouseDown:function(e,t){this.canvas._isMainEvent(t.e)&&(this.drawStraightLine=t.e[this.straightLineKey],this._prepareForDrawing(e),this._captureDrawingPath(e),this._render())},onMouseMove:function(e,t){if(this.canvas._isMainEvent(t.e)&&(this.drawStraightLine=t.e[this.straightLineKey],(!0!==this.limitedToCanvasSize||!this._isOutSideCanvas(e))&&this._captureDrawingPath(e)&&this._points.length>1))if(this.needsFullRender())this.canvas.clearContext(this.canvas.contextTop),this._render();else{var i=this._points,s=i.length,n=this.canvas.contextTop;this._saveAndTransform(n),this.oldEnd&&(n.beginPath(),n.moveTo(this.oldEnd.x,this.oldEnd.y)),this.oldEnd=this._drawSegment(n,i[s-2],i[s-1],!0),n.stroke(),n.restore()}},onMouseUp:function(e){return!this.canvas._isMainEvent(e.e)||(this.drawStraightLine=!1,this.oldEnd=void 0,this._finalizeAndAddPath(),!1)},_prepareForDrawing:function(e){var t=new n.Point(e.x,e.y);this._reset(),this._addPoint(t),this.canvas.contextTop.moveTo(t.x,t.y)},_addPoint:function(e){return!(this._points.length>1&&e.eq(this._points[this._points.length-1]))&&(this.drawStraightLine&&this._points.length>1&&(this._hasStraightLine=!0,this._points.pop()),this._points.push(e),!0)},_reset:function(){this._points=[],this._setBrushStyles(this.canvas.contextTop),this._setShadow(),this._hasStraightLine=!1},_captureDrawingPath:function(e){var t=new n.Point(e.x,e.y);return this._addPoint(t)},_render:function(e){var t,i,s=this._points[0],r=this._points[1];if(e=e||this.canvas.contextTop,this._saveAndTransform(e),e.beginPath(),2===this._points.length&&s.x===r.x&&s.y===r.y){var o=this.width/1e3;s=new n.Point(s.x,s.y),r=new n.Point(r.x,r.y),s.x-=o,r.x+=o}for(e.moveTo(s.x,s.y),t=1,i=this._points.length;t=n&&(o=e[i],a.push(o));return a.push(e[r]),a},_finalizeAndAddPath:function(){this.canvas.contextTop.closePath(),this.decimate&&(this._points=this.decimatePoints(this._points,this.decimate));var e=this.convertPointsToSVGPath(this._points);if(this._isEmptySVGPath(e))this.canvas.requestRenderAll();else{var t=this.createPath(e);this.canvas.clearContext(this.canvas.contextTop),this.canvas.fire("before:path:created",{path:t}),this.canvas.add(t),this.canvas.requestRenderAll(),t.setCoords(),this._resetShadow(),this.canvas.fire("path:created",{path:t})}}}),n.CircleBrush=n.util.createClass(n.BaseBrush,{width:10,initialize:function(e){this.canvas=e,this.points=[]},drawDot:function(e){var t=this.addPoint(e),i=this.canvas.contextTop;this._saveAndTransform(i),this.dot(i,t),i.restore()},dot:function(e,t){e.fillStyle=t.fill,e.beginPath(),e.arc(t.x,t.y,t.radius,0,2*Math.PI,!1),e.closePath(),e.fill()},onMouseDown:function(e){this.points.length=0,this.canvas.clearContext(this.canvas.contextTop),this._setShadow(),this.drawDot(e)},_render:function(){var e,t,i=this.canvas.contextTop,s=this.points;for(this._saveAndTransform(i),e=0,t=s.length;e0&&!this.preserveObjectStacking){t=[],i=[];for(var n=0,r=this._objects.length;n1&&(this._activeObject._objects=i),t.push.apply(t,i)}else t=this._objects;return t},renderAll:function(){!this.contextTopDirty||this._groupSelector||this.isDrawingMode||(this.clearContext(this.contextTop),this.contextTopDirty=!1),this.hasLostContext&&(this.renderTopLayer(this.contextTop),this.hasLostContext=!1);var e=this.contextContainer;return this.renderCanvas(e,this._chooseObjectsToRender()),this},renderTopLayer:function(e){e.save(),this.isDrawingMode&&this._isCurrentlyDrawing&&(this.freeDrawingBrush&&this.freeDrawingBrush._render(),this.contextTopDirty=!0),this.selection&&this._groupSelector&&(this._drawSelection(e),this.contextTopDirty=!0),e.restore()},renderTop:function(){var e=this.contextTop;return this.clearContext(e),this.renderTopLayer(e),this.fire("after:render"),this},_normalizePointer:function(e,t){var i=e.calcTransformMatrix(),s=n.util.invertTransform(i),r=this.restorePointerVpt(t);return n.util.transformPoint(r,s)},isTargetTransparent:function(e,t,i){if(e.shouldCache()&&e._cacheCanvas&&e!==this._activeObject){var s=this._normalizePointer(e,{x:t,y:i}),r=Math.max(e.cacheTranslationX+s.x*e.zoomX,0),o=Math.max(e.cacheTranslationY+s.y*e.zoomY,0);return n.util.isTransparent(e._cacheContext,Math.round(r),Math.round(o),this.targetFindTolerance)}var a=this.contextCache,c=e.selectionBackgroundColor,l=this.viewportTransform;return e.selectionBackgroundColor="",this.clearContext(a),a.save(),a.transform(l[0],l[1],l[2],l[3],l[4],l[5]),e.render(a),a.restore(),e.selectionBackgroundColor=c,n.util.isTransparent(a,t,i,this.targetFindTolerance)},_isSelectionKeyPressed:function(e){return Array.isArray(this.selectionKey)?!!this.selectionKey.find((function(t){return!0===e[t]})):e[this.selectionKey]},_shouldClearSelection:function(e,t){var i=this.getActiveObjects(),s=this._activeObject;return!t||t&&s&&i.length>1&&-1===i.indexOf(t)&&s!==t&&!this._isSelectionKeyPressed(e)||t&&!t.evented||t&&!t.selectable&&s&&s!==t},_shouldCenterTransform:function(e,t,i){var s;if(e)return"scale"===t||"scaleX"===t||"scaleY"===t||"resizing"===t?s=this.centeredScaling||e.centeredScaling:"rotate"===t&&(s=this.centeredRotation||e.centeredRotation),s?!i:i},_getOriginFromCorner:function(e,t){var i={x:e.originX,y:e.originY};return"ml"===t||"tl"===t||"bl"===t?i.x="right":"mr"!==t&&"tr"!==t&&"br"!==t||(i.x="left"),"tl"===t||"mt"===t||"tr"===t?i.y="bottom":"bl"!==t&&"mb"!==t&&"br"!==t||(i.y="top"),i},_getActionFromCorner:function(e,t,i,s){if(!t||!e)return"drag";var n=s.controls[t];return n.getActionName(i,n,s)},_setupCurrentTransform:function(e,i,s){if(i){var r=this.getPointer(e),o=i.__corner,a=i.controls[o],c=s&&o?a.getActionHandler(e,i,a):n.controlsUtils.dragHandler,l=this._getActionFromCorner(s,o,e,i),h=this._getOriginFromCorner(i,o),d=e[this.centeredKey],u={target:i,action:l,actionHandler:c,corner:o,scaleX:i.scaleX,scaleY:i.scaleY,skewX:i.skewX,skewY:i.skewY,offsetX:r.x-i.left,offsetY:r.y-i.top,originX:h.x,originY:h.y,ex:r.x,ey:r.y,lastX:r.x,lastY:r.y,theta:t(i.angle),width:i.width*i.scaleX,shiftKey:e.shiftKey,altKey:d,original:n.util.saveObjectTransform(i)};this._shouldCenterTransform(i,l,d)&&(u.originX="center",u.originY="center"),u.original.originX=h.x,u.original.originY=h.y,this._currentTransform=u,this._beforeTransform(e)}},setCursor:function(e){this.upperCanvasEl.style.cursor=e},_drawSelection:function(e){var t=this._groupSelector,i=new n.Point(t.ex,t.ey),s=n.util.transformPoint(i,this.viewportTransform),r=new n.Point(t.ex+t.left,t.ey+t.top),o=n.util.transformPoint(r,this.viewportTransform),a=Math.min(s.x,o.x),c=Math.min(s.y,o.y),l=Math.max(s.x,o.x),h=Math.max(s.y,o.y),d=this.selectionLineWidth/2;this.selectionColor&&(e.fillStyle=this.selectionColor,e.fillRect(a,c,l-a,h-c)),this.selectionLineWidth&&this.selectionBorderColor&&(e.lineWidth=this.selectionLineWidth,e.strokeStyle=this.selectionBorderColor,a+=d,c+=d,l-=d,h-=d,n.Object.prototype._setLineDash.call(this,e,this.selectionDashArray),e.strokeRect(a,c,l-a,h-c))},findTarget:function(e,t){if(!this.skipTargetFind){var s,n,r=this.getPointer(e,!0),o=this._activeObject,a=this.getActiveObjects(),c=i(e),l=a.length>1&&!t||1===a.length;if(this.targets=[],l&&o._findTargetCorner(r,c))return o;if(a.length>1&&!t&&o===this._searchPossibleTargets([o],r))return o;if(1===a.length&&o===this._searchPossibleTargets([o],r)){if(!this.preserveObjectStacking)return o;s=o,n=this.targets,this.targets=[]}var h=this._searchPossibleTargets(this._objects,r);return e[this.altSelectionKey]&&h&&s&&h!==s&&(h=s,this.targets=n),h}},_checkTarget:function(e,t,i){if(t&&t.visible&&t.evented&&t.containsPoint(e)){if(!this.perPixelTargetFind&&!t.perPixelTargetFind||t.isEditing)return!0;if(!this.isTargetTransparent(t,i.x,i.y))return!0}},_searchPossibleTargets:function(e,t){for(var i,s,r=e.length;r--;){var o=e[r],a=o.group?this._normalizePointer(o.group,t):t;if(this._checkTarget(a,o,t)){(i=e[r]).subTargetCheck&&i instanceof n.Group&&(s=this._searchPossibleTargets(i._objects,t))&&this.targets.push(s);break}}return i},restorePointerVpt:function(e){return n.util.transformPoint(e,n.util.invertTransform(this.viewportTransform))},getPointer:function(t,i){if(this._absolutePointer&&!i)return this._absolutePointer;if(this._pointer&&i)return this._pointer;var s,n=e(t),r=this.upperCanvasEl,o=r.getBoundingClientRect(),a=o.width||0,c=o.height||0;a&&c||("top"in o&&"bottom"in o&&(c=Math.abs(o.top-o.bottom)),"right"in o&&"left"in o&&(a=Math.abs(o.right-o.left))),this.calcOffset(),n.x=n.x-this._offset.left,n.y=n.y-this._offset.top,i||(n=this.restorePointerVpt(n));var l=this.getRetinaScaling();return 1!==l&&(n.x/=l,n.y/=l),s=0===a||0===c?{width:1,height:1}:{width:r.width/a,height:r.height/c},{x:n.x*s.width,y:n.y*s.height}},_createUpperCanvas:function(){var e=this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/,""),t=this.lowerCanvasEl,i=this.upperCanvasEl;i?i.className="":(i=this._createCanvasElement(),this.upperCanvasEl=i),n.util.addClass(i,"upper-canvas "+e),this.wrapperEl.appendChild(i),this._copyCanvasStyle(t,i),this._applyCanvasStyle(i),this.contextTop=i.getContext("2d")},getTopContext:function(){return this.contextTop},_createCacheCanvas:function(){this.cacheCanvasEl=this._createCanvasElement(),this.cacheCanvasEl.setAttribute("width",this.width),this.cacheCanvasEl.setAttribute("height",this.height),this.contextCache=this.cacheCanvasEl.getContext("2d")},_initWrapperElement:function(){this.wrapperEl=n.util.wrapElement(this.lowerCanvasEl,"div",{class:this.containerClass}),n.util.setStyle(this.wrapperEl,{width:this.width+"px",height:this.height+"px",position:"relative"}),n.util.makeElementUnselectable(this.wrapperEl)},_applyCanvasStyle:function(e){var t=this.width||e.width,i=this.height||e.height;n.util.setStyle(e,{position:"absolute",width:t+"px",height:i+"px",left:0,top:0,"touch-action":this.allowTouchScrolling?"manipulation":"none","-ms-touch-action":this.allowTouchScrolling?"manipulation":"none"}),e.width=t,e.height=i,n.util.makeElementUnselectable(e)},_copyCanvasStyle:function(e,t){t.style.cssText=e.style.cssText},getSelectionContext:function(){return this.contextTop},getSelectionElement:function(){return this.upperCanvasEl},getActiveObject:function(){return this._activeObject},getActiveObjects:function(){var e=this._activeObject;return e?"activeSelection"===e.type&&e._objects?e._objects.slice(0):[e]:[]},_onObjectRemoved:function(e){e===this._activeObject&&(this.fire("before:selection:cleared",{target:e}),this._discardActiveObject(),this.fire("selection:cleared",{target:e}),e.fire("deselected")),e===this._hoveredTarget&&(this._hoveredTarget=null,this._hoveredTargets=[]),this.callSuper("_onObjectRemoved",e)},_fireSelectionEvents:function(e,t){var i=!1,s=this.getActiveObjects(),n=[],r=[];e.forEach((function(e){-1===s.indexOf(e)&&(i=!0,e.fire("deselected",{e:t,target:e}),r.push(e))})),s.forEach((function(s){-1===e.indexOf(s)&&(i=!0,s.fire("selected",{e:t,target:s}),n.push(s))})),e.length>0&&s.length>0?i&&this.fire("selection:updated",{e:t,selected:n,deselected:r}):s.length>0?this.fire("selection:created",{e:t,selected:n}):e.length>0&&this.fire("selection:cleared",{e:t,deselected:r})},setActiveObject:function(e,t){var i=this.getActiveObjects();return this._setActiveObject(e,t),this._fireSelectionEvents(i,t),this},_setActiveObject:function(e,t){return this._activeObject!==e&&(!!this._discardActiveObject(t,e)&&(!e.onSelect({e:t})&&(this._activeObject=e,!0)))},_discardActiveObject:function(e,t){var i=this._activeObject;if(i){if(i.onDeselect({e:e,object:t}))return!1;this._activeObject=null}return!0},discardActiveObject:function(e){var t=this.getActiveObjects(),i=this.getActiveObject();return t.length&&this.fire("before:selection:cleared",{target:i,e:e}),this._discardActiveObject(e),this._fireSelectionEvents(t,e),this},dispose:function(){var e=this.wrapperEl;return this.removeListeners(),e.removeChild(this.upperCanvasEl),e.removeChild(this.lowerCanvasEl),this.contextCache=null,this.contextTop=null,["upperCanvasEl","cacheCanvasEl"].forEach(function(e){n.util.cleanUpJsdomNode(this[e]),this[e]=void 0}.bind(this)),e.parentNode&&e.parentNode.replaceChild(this.lowerCanvasEl,this.wrapperEl),delete this.wrapperEl,n.StaticCanvas.prototype.dispose.call(this),this},clear:function(){return this.discardActiveObject(),this.clearContext(this.contextTop),this.callSuper("clear")},drawControls:function(e){var t=this._activeObject;t&&t._renderControls(e)},_toObject:function(e,t,i){var s=this._realizeGroupTransformOnObject(e),n=this.callSuper("_toObject",e,t,i);return this._unwindGroupTransformOnObject(e,s),n},_realizeGroupTransformOnObject:function(e){if(e.group&&"activeSelection"===e.group.type&&this._activeObject===e.group){var t={};return["angle","flipX","flipY","left","scaleX","scaleY","skewX","skewY","top"].forEach((function(i){t[i]=e[i]})),n.util.addTransformToObject(e,this._activeObject.calcOwnMatrix()),t}return null},_unwindGroupTransformOnObject:function(e,t){t&&e.set(t)},_setSVGObject:function(e,t,i){var s=this._realizeGroupTransformOnObject(t);this.callSuper("_setSVGObject",e,t,i),this._unwindGroupTransformOnObject(t,s)},setViewportTransform:function(e){this.renderOnAddRemove&&this._activeObject&&this._activeObject.isEditing&&this._activeObject.clearContextTop(),n.StaticCanvas.prototype.setViewportTransform.call(this,e)}}),n.StaticCanvas)"prototype"!==s&&(n.Canvas[s]=n.StaticCanvas[s])}(),function(){var e=n.util.addListener,t=n.util.removeListener,i={passive:!1};function s(e,t){return e.button&&e.button===t-1}n.util.object.extend(n.Canvas.prototype,{mainTouchId:null,_initEventListeners:function(){this.removeListeners(),this._bindEvents(),this.addOrRemove(e,"add")},_getEventPrefix:function(){return this.enablePointerEvents?"pointer":"mouse"},addOrRemove:function(e,t){var s=this.upperCanvasEl,r=this._getEventPrefix();e(n.window,"resize",this._onResize),e(s,r+"down",this._onMouseDown),e(s,r+"move",this._onMouseMove,i),e(s,r+"out",this._onMouseOut),e(s,r+"enter",this._onMouseEnter),e(s,"wheel",this._onMouseWheel),e(s,"contextmenu",this._onContextMenu),e(s,"dblclick",this._onDoubleClick),e(s,"dragover",this._onDragOver),e(s,"dragenter",this._onDragEnter),e(s,"dragleave",this._onDragLeave),e(s,"drop",this._onDrop),this.enablePointerEvents||e(s,"touchstart",this._onTouchStart,i),"undefined"!==typeof eventjs&&t in eventjs&&(eventjs[t](s,"gesture",this._onGesture),eventjs[t](s,"drag",this._onDrag),eventjs[t](s,"orientation",this._onOrientationChange),eventjs[t](s,"shake",this._onShake),eventjs[t](s,"longpress",this._onLongPress))},removeListeners:function(){this.addOrRemove(t,"remove");var e=this._getEventPrefix();t(n.document,e+"up",this._onMouseUp),t(n.document,"touchend",this._onTouchEnd,i),t(n.document,e+"move",this._onMouseMove,i),t(n.document,"touchmove",this._onMouseMove,i)},_bindEvents:function(){this.eventsBound||(this._onMouseDown=this._onMouseDown.bind(this),this._onTouchStart=this._onTouchStart.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseUp=this._onMouseUp.bind(this),this._onTouchEnd=this._onTouchEnd.bind(this),this._onResize=this._onResize.bind(this),this._onGesture=this._onGesture.bind(this),this._onDrag=this._onDrag.bind(this),this._onShake=this._onShake.bind(this),this._onLongPress=this._onLongPress.bind(this),this._onOrientationChange=this._onOrientationChange.bind(this),this._onMouseWheel=this._onMouseWheel.bind(this),this._onMouseOut=this._onMouseOut.bind(this),this._onMouseEnter=this._onMouseEnter.bind(this),this._onContextMenu=this._onContextMenu.bind(this),this._onDoubleClick=this._onDoubleClick.bind(this),this._onDragOver=this._onDragOver.bind(this),this._onDragEnter=this._simpleEventHandler.bind(this,"dragenter"),this._onDragLeave=this._simpleEventHandler.bind(this,"dragleave"),this._onDrop=this._onDrop.bind(this),this.eventsBound=!0)},_onGesture:function(e,t){this.__onTransformGesture&&this.__onTransformGesture(e,t)},_onDrag:function(e,t){this.__onDrag&&this.__onDrag(e,t)},_onMouseWheel:function(e){this.__onMouseWheel(e)},_onMouseOut:function(e){var t=this._hoveredTarget;this.fire("mouse:out",{target:t,e:e}),this._hoveredTarget=null,t&&t.fire("mouseout",{e:e});var i=this;this._hoveredTargets.forEach((function(t){i.fire("mouse:out",{target:t,e:e}),t&&t.fire("mouseout",{e:e})})),this._hoveredTargets=[]},_onMouseEnter:function(e){this._currentTransform||this.findTarget(e)||(this.fire("mouse:over",{target:null,e:e}),this._hoveredTarget=null,this._hoveredTargets=[])},_onOrientationChange:function(e,t){this.__onOrientationChange&&this.__onOrientationChange(e,t)},_onShake:function(e,t){this.__onShake&&this.__onShake(e,t)},_onLongPress:function(e,t){this.__onLongPress&&this.__onLongPress(e,t)},_onDragOver:function(e){e.preventDefault();var t=this._simpleEventHandler("dragover",e);this._fireEnterLeaveEvents(t,e)},_onDrop:function(e){return this._simpleEventHandler("drop:before",e),this._simpleEventHandler("drop",e)},_onContextMenu:function(e){return this.stopContextMenu&&(e.stopPropagation(),e.preventDefault()),!1},_onDoubleClick:function(e){this._cacheTransformEventData(e),this._handleEvent(e,"dblclick"),this._resetTransformEventData(e)},getPointerId:function(e){var t=e.changedTouches;return t?t[0]&&t[0].identifier:this.enablePointerEvents?e.pointerId:-1},_isMainEvent:function(e){return!0===e.isPrimary||!1!==e.isPrimary&&("touchend"===e.type&&0===e.touches.length||(!e.changedTouches||e.changedTouches[0].identifier===this.mainTouchId))},_onTouchStart:function(s){s.preventDefault(),null===this.mainTouchId&&(this.mainTouchId=this.getPointerId(s)),this.__onMouseDown(s),this._resetTransformEventData();var r=this.upperCanvasEl,o=this._getEventPrefix();e(n.document,"touchend",this._onTouchEnd,i),e(n.document,"touchmove",this._onMouseMove,i),t(r,o+"down",this._onMouseDown)},_onMouseDown:function(s){this.__onMouseDown(s),this._resetTransformEventData();var r=this.upperCanvasEl,o=this._getEventPrefix();t(r,o+"move",this._onMouseMove,i),e(n.document,o+"up",this._onMouseUp),e(n.document,o+"move",this._onMouseMove,i)},_onTouchEnd:function(s){if(!(s.touches.length>0)){this.__onMouseUp(s),this._resetTransformEventData(),this.mainTouchId=null;var r=this._getEventPrefix();t(n.document,"touchend",this._onTouchEnd,i),t(n.document,"touchmove",this._onMouseMove,i);var o=this;this._willAddMouseDown&&clearTimeout(this._willAddMouseDown),this._willAddMouseDown=setTimeout((function(){e(o.upperCanvasEl,r+"down",o._onMouseDown),o._willAddMouseDown=0}),400)}},_onMouseUp:function(s){this.__onMouseUp(s),this._resetTransformEventData();var r=this.upperCanvasEl,o=this._getEventPrefix();this._isMainEvent(s)&&(t(n.document,o+"up",this._onMouseUp),t(n.document,o+"move",this._onMouseMove,i),e(r,o+"move",this._onMouseMove,i))},_onMouseMove:function(e){!this.allowTouchScrolling&&e.preventDefault&&e.preventDefault(),this.__onMouseMove(e)},_onResize:function(){this.calcOffset()},_shouldRender:function(e){var t=this._activeObject;return!!(!!t!==!!e||t&&e&&t!==e)||(t&&t.isEditing,!1)},__onMouseUp:function(e){var t,i=this._currentTransform,r=this._groupSelector,o=!1,a=!r||0===r.left&&0===r.top;if(this._cacheTransformEventData(e),t=this._target,this._handleEvent(e,"up:before"),s(e,3))this.fireRightClick&&this._handleEvent(e,"up",3,a);else{if(s(e,2))return this.fireMiddleClick&&this._handleEvent(e,"up",2,a),void this._resetTransformEventData();if(this.isDrawingMode&&this._isCurrentlyDrawing)this._onMouseUpInDrawingMode(e);else if(this._isMainEvent(e)){if(i&&(this._finalizeCurrentTransform(e),o=i.actionPerformed),!a){var c=t===this._activeObject;this._maybeGroupObjects(e),o||(o=this._shouldRender(t)||!c&&t===this._activeObject)}var l,h;if(t){if(l=t._findTargetCorner(this.getPointer(e,!0),n.util.isTouchEvent(e)),t.selectable&&t!==this._activeObject&&"up"===t.activeOn)this.setActiveObject(t,e),o=!0;else{var d=t.controls[l],u=d&&d.getMouseUpHandler(e,t,d);u&&u(e,i,(h=this.getPointer(e)).x,h.y)}t.isMoving=!1}if(i&&(i.target!==t||i.corner!==l)){var g=i.target&&i.target.controls[i.corner],p=g&&g.getMouseUpHandler(e,t,d);h=h||this.getPointer(e),p&&p(e,i,h.x,h.y)}this._setCursorFromEvent(e,t),this._handleEvent(e,"up",1,a),this._groupSelector=null,this._currentTransform=null,t&&(t.__corner=0),o?this.requestRenderAll():a||this.renderTop()}}},_simpleEventHandler:function(e,t){var i=this.findTarget(t),s=this.targets,n={e:t,target:i,subTargets:s};if(this.fire(e,n),i&&i.fire(e,n),!s)return i;for(var r=0;r1&&(t=new n.ActiveSelection(i.reverse(),{canvas:this}),this.setActiveObject(t,e))},_collectObjects:function(i){for(var s,r=[],o=this._groupSelector.ex,a=this._groupSelector.ey,c=o+this._groupSelector.left,l=a+this._groupSelector.top,h=new n.Point(e(o,c),e(a,l)),d=new n.Point(t(o,c),t(a,l)),u=!this.selectionFullyContained,g=o===c&&a===l,p=this._objects.length;p--&&!((s=this._objects[p])&&s.selectable&&s.visible&&(u&&s.intersectsWithRect(h,d,!0)||s.isContainedWithinRect(h,d,!0)||u&&s.containsPoint(h,null,!0)||u&&s.containsPoint(d,null,!0))&&(r.push(s),g)););return r.length>1&&(r=r.filter((function(e){return!e.onSelect({e:i})}))),r},_maybeGroupObjects:function(e){this.selection&&this._groupSelector&&this._groupSelectedObjects(e),this.setCursor(this.defaultCursor),this._groupSelector=null}})}(),n.util.object.extend(n.StaticCanvas.prototype,{toDataURL:function(e){e||(e={});var t=e.format||"png",i=e.quality||1,s=(e.multiplier||1)*(e.enableRetinaScaling?this.getRetinaScaling():1),r=this.toCanvasElement(s,e);return n.util.toDataURL(r,t,i)},toCanvasElement:function(e,t){e=e||1;var i=((t=t||{}).width||this.width)*e,s=(t.height||this.height)*e,r=this.getZoom(),o=this.width,a=this.height,c=r*e,l=this.viewportTransform,h=(l[4]-(t.left||0))*e,d=(l[5]-(t.top||0))*e,u=this.interactive,g=[c,0,0,c,h,d],p=this.enableRetinaScaling,m=n.util.createCanvasElement(),f=this.contextTop;return m.width=i,m.height=s,this.contextTop=null,this.enableRetinaScaling=!1,this.interactive=!1,this.viewportTransform=g,this.width=i,this.height=s,this.calcViewportBoundaries(),this.renderCanvas(m.getContext("2d"),this._objects),this.viewportTransform=l,this.width=o,this.height=a,this.calcViewportBoundaries(),this.interactive=u,this.enableRetinaScaling=p,this.contextTop=f,m}}),n.util.object.extend(n.StaticCanvas.prototype,{loadFromJSON:function(e,t,i){if(e){var s="string"===typeof e?JSON.parse(e):n.util.object.clone(e),r=this,o=s.clipPath,a=this.renderOnAddRemove;return this.renderOnAddRemove=!1,delete s.clipPath,this._enlivenObjects(s.objects,(function(e){r.clear(),r._setBgOverlay(s,(function(){o?r._enlivenObjects([o],(function(i){r.clipPath=i[0],r.__setupCanvas.call(r,s,e,a,t)})):r.__setupCanvas.call(r,s,e,a,t)}))}),i),this}},__setupCanvas:function(e,t,i,s){var n=this;t.forEach((function(e,t){n.insertAt(e,t)})),this.renderOnAddRemove=i,delete e.objects,delete e.backgroundImage,delete e.overlayImage,delete e.background,delete e.overlay,this._setOptions(e),this.renderAll(),s&&s()},_setBgOverlay:function(e,t){var i={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(e.backgroundImage||e.overlayImage||e.background||e.overlay){var s=function(){i.backgroundImage&&i.overlayImage&&i.backgroundColor&&i.overlayColor&&t&&t()};this.__setBgOverlay("backgroundImage",e.backgroundImage,i,s),this.__setBgOverlay("overlayImage",e.overlayImage,i,s),this.__setBgOverlay("backgroundColor",e.background,i,s),this.__setBgOverlay("overlayColor",e.overlay,i,s)}else t&&t()},__setBgOverlay:function(e,t,i,s){var r=this;if(!t)return i[e]=!0,void(s&&s());"backgroundImage"===e||"overlayImage"===e?n.util.enlivenObjects([t],(function(t){r[e]=t[0],i[e]=!0,s&&s()})):this["set"+n.util.string.capitalize(e,!0)](t,(function(){i[e]=!0,s&&s()}))},_enlivenObjects:function(e,t,i){e&&0!==e.length?n.util.enlivenObjects(e,(function(e){t&&t(e)}),null,i):t&&t([])},_toDataURL:function(e,t){this.clone((function(i){t(i.toDataURL(e))}))},_toDataURLWithMultiplier:function(e,t,i){this.clone((function(s){i(s.toDataURLWithMultiplier(e,t))}))},clone:function(e,t){var i=JSON.stringify(this.toJSON(t));this.cloneWithoutData((function(t){t.loadFromJSON(i,(function(){e&&e(t)}))}))},cloneWithoutData:function(e){var t=n.util.createCanvasElement();t.width=this.width,t.height=this.height;var i=new n.Canvas(t);this.backgroundImage?(i.setBackgroundImage(this.backgroundImage.src,(function(){i.renderAll(),e&&e(i)})),i.backgroundImageOpacity=this.backgroundImageOpacity,i.backgroundImageStretch=this.backgroundImageStretch):e&&e(i)}}),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.util.object.extend,s=t.util.object.clone,n=t.util.toFixed,r=t.util.string.capitalize,o=t.util.degreesToRadians,a=!t.isLikelyNode;t.Object||(t.Object=t.util.createClass(t.CommonMethods,{type:"object",originX:"left",originY:"top",top:0,left:0,width:0,height:0,scaleX:1,scaleY:1,flipX:!1,flipY:!1,opacity:1,angle:0,skewX:0,skewY:0,cornerSize:13,touchCornerSize:24,transparentCorners:!0,hoverCursor:null,moveCursor:null,padding:0,borderColor:"rgb(178,204,255)",borderDashArray:null,cornerColor:"rgb(178,204,255)",cornerStrokeColor:null,cornerStyle:"rect",cornerDashArray:null,centeredScaling:!1,centeredRotation:!0,fill:"rgb(0,0,0)",fillRule:"nonzero",globalCompositeOperation:"source-over",backgroundColor:"",selectionBackgroundColor:"",stroke:null,strokeWidth:1,strokeDashArray:null,strokeDashOffset:0,strokeLineCap:"butt",strokeLineJoin:"miter",strokeMiterLimit:4,shadow:null,borderOpacityWhenMoving:.4,borderScaleFactor:1,minScaleLimit:0,selectable:!0,evented:!0,visible:!0,hasControls:!0,hasBorders:!0,perPixelTargetFind:!1,includeDefaultValues:!0,lockMovementX:!1,lockMovementY:!1,lockRotation:!1,lockScalingX:!1,lockScalingY:!1,lockSkewingX:!1,lockSkewingY:!1,lockScalingFlip:!1,excludeFromExport:!1,objectCaching:a,statefullCache:!1,noScaleCache:!0,strokeUniform:!1,dirty:!0,__corner:0,paintFirst:"fill",activeOn:"down",stateProperties:"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit angle opacity fill globalCompositeOperation shadow visible backgroundColor skewX skewY fillRule paintFirst clipPath strokeUniform".split(" "),cacheProperties:"fill stroke strokeWidth strokeDashArray width height paintFirst strokeUniform strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit backgroundColor clipPath".split(" "),colorProperties:"fill stroke backgroundColor".split(" "),clipPath:void 0,inverted:!1,absolutePositioned:!1,initialize:function(e){e&&this.setOptions(e)},_createCacheCanvas:function(){this._cacheProperties={},this._cacheCanvas=t.util.createCanvasElement(),this._cacheContext=this._cacheCanvas.getContext("2d"),this._updateCacheCanvas(),this.dirty=!0},_limitCacheSize:function(e){var i=t.perfLimitSizeTotal,s=e.width,n=e.height,r=t.maxCacheSideLimit,o=t.minCacheSideLimit;if(s<=r&&n<=r&&s*n<=i)return sh&&(e.zoomX/=s/h,e.width=h,e.capped=!0),n>d&&(e.zoomY/=n/d,e.height=d,e.capped=!0),e},_getCacheCanvasDimensions:function(){var e=this.getTotalObjectScaling(),t=this._getTransformedDimensions(0,0),i=t.x*e.scaleX/this.scaleX,s=t.y*e.scaleY/this.scaleY;return{width:Math.ceil(i+2),height:Math.ceil(s+2),zoomX:e.scaleX,zoomY:e.scaleY,x:i,y:s}},_updateCacheCanvas:function(){var e=this.canvas;if(this.noScaleCache&&e&&e._currentTransform){var t=e._currentTransform.target,i=e._currentTransform.action;if(this===t&&i.slice&&"scale"===i.slice(0,5))return!1}var s,n,r=this._cacheCanvas,o=this._limitCacheSize(this._getCacheCanvasDimensions()),a=o.width,c=o.height,l=o.zoomX,h=o.zoomY,d=a!==this.cacheWidth||c!==this.cacheHeight,u=this.zoomX!==l||this.zoomY!==h;return!(!d&&!u)&&(d?(r.width=a,r.height=c):(this._cacheContext.setTransform(1,0,0,1,0,0),this._cacheContext.clearRect(0,0,r.width,r.height)),s=o.x/2,n=o.y/2,this.cacheTranslationX=Math.round(r.width/2-s)+s,this.cacheTranslationY=Math.round(r.height/2-n)+n,this.cacheWidth=a,this.cacheHeight=c,this._cacheContext.translate(this.cacheTranslationX,this.cacheTranslationY),this._cacheContext.scale(l,h),this.zoomX=l,this.zoomY=h,!0)},setOptions:function(e){this._setOptions(e),this._initGradient(e.fill,"fill"),this._initGradient(e.stroke,"stroke"),this._initPattern(e.fill,"fill"),this._initPattern(e.stroke,"stroke")},transform:function(e){var t=this.group&&!this.group._transformDone||this.group&&this.canvas&&e===this.canvas.contextTop,i=this.calcTransformMatrix(!t);e.transform(i[0],i[1],i[2],i[3],i[4],i[5])},toObject:function(e){var i=t.Object.NUM_FRACTION_DIGITS,s={type:this.type,version:t.version,originX:this.originX,originY:this.originY,left:n(this.left,i),top:n(this.top,i),width:n(this.width,i),height:n(this.height,i),fill:this.fill&&this.fill.toObject?this.fill.toObject():this.fill,stroke:this.stroke&&this.stroke.toObject?this.stroke.toObject():this.stroke,strokeWidth:n(this.strokeWidth,i),strokeDashArray:this.strokeDashArray?this.strokeDashArray.concat():this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeDashOffset:this.strokeDashOffset,strokeLineJoin:this.strokeLineJoin,strokeUniform:this.strokeUniform,strokeMiterLimit:n(this.strokeMiterLimit,i),scaleX:n(this.scaleX,i),scaleY:n(this.scaleY,i),angle:n(this.angle,i),flipX:this.flipX,flipY:this.flipY,opacity:n(this.opacity,i),shadow:this.shadow&&this.shadow.toObject?this.shadow.toObject():this.shadow,visible:this.visible,backgroundColor:this.backgroundColor,fillRule:this.fillRule,paintFirst:this.paintFirst,globalCompositeOperation:this.globalCompositeOperation,skewX:n(this.skewX,i),skewY:n(this.skewY,i)};return this.clipPath&&!this.clipPath.excludeFromExport&&(s.clipPath=this.clipPath.toObject(e),s.clipPath.inverted=this.clipPath.inverted,s.clipPath.absolutePositioned=this.clipPath.absolutePositioned),t.util.populateWithProperties(this,s,e),this.includeDefaultValues||(s=this._removeDefaultValues(s)),s},toDatalessObject:function(e){return this.toObject(e)},_removeDefaultValues:function(e){var i=t.util.getKlass(e.type).prototype;return i.stateProperties.forEach((function(t){"left"!==t&&"top"!==t&&(e[t]===i[t]&&delete e[t],Array.isArray(e[t])&&Array.isArray(i[t])&&0===e[t].length&&0===i[t].length&&delete e[t])})),e},toString:function(){return"#"},getObjectScaling:function(){if(!this.group)return{scaleX:this.scaleX,scaleY:this.scaleY};var e=t.util.qrDecompose(this.calcTransformMatrix());return{scaleX:Math.abs(e.scaleX),scaleY:Math.abs(e.scaleY)}},getTotalObjectScaling:function(){var e=this.getObjectScaling(),t=e.scaleX,i=e.scaleY;if(this.canvas){var s=this.canvas.getZoom(),n=this.canvas.getRetinaScaling();t*=s*n,i*=s*n}return{scaleX:t,scaleY:i}},getObjectOpacity:function(){var e=this.opacity;return this.group&&(e*=this.group.getObjectOpacity()),e},_set:function(e,i){var s="scaleX"===e||"scaleY"===e,n=this[e]!==i,r=!1;return s&&(i=this._constrainScale(i)),"scaleX"===e&&i<0?(this.flipX=!this.flipX,i*=-1):"scaleY"===e&&i<0?(this.flipY=!this.flipY,i*=-1):"shadow"!==e||!i||i instanceof t.Shadow?"dirty"===e&&this.group&&this.group.set("dirty",i):i=new t.Shadow(i),this[e]=i,n&&(r=this.group&&this.group.isOnACache(),this.cacheProperties.indexOf(e)>-1?(this.dirty=!0,r&&this.group.set("dirty",!0)):r&&this.stateProperties.indexOf(e)>-1&&this.group.set("dirty",!0)),this},setOnGroup:function(){},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:t.iMatrix.concat()},isNotVisible:function(){return 0===this.opacity||!this.width&&!this.height&&0===this.strokeWidth||!this.visible},render:function(e){this.isNotVisible()||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(e.save(),this._setupCompositeOperation(e),this.drawSelectionBackground(e),this.transform(e),this._setOpacity(e),this._setShadow(e,this),this.shouldCache()?(this.renderCache(),this.drawCacheOnCanvas(e)):(this._removeCacheCanvas(),this.dirty=!1,this.drawObject(e),this.objectCaching&&this.statefullCache&&this.saveState({propertySet:"cacheProperties"})),e.restore())},renderCache:function(e){e=e||{},this._cacheCanvas&&this._cacheContext||this._createCacheCanvas(),this.isCacheDirty()&&(this.statefullCache&&this.saveState({propertySet:"cacheProperties"}),this.drawObject(this._cacheContext,e.forClipping),this.dirty=!1)},_removeCacheCanvas:function(){this._cacheCanvas=null,this._cacheContext=null,this.cacheWidth=0,this.cacheHeight=0},hasStroke:function(){return this.stroke&&"transparent"!==this.stroke&&0!==this.strokeWidth},hasFill:function(){return this.fill&&"transparent"!==this.fill},needsItsOwnCache:function(){return!("stroke"!==this.paintFirst||!this.hasFill()||!this.hasStroke()||"object"!==typeof this.shadow)||!!this.clipPath},shouldCache:function(){return this.ownCaching=this.needsItsOwnCache()||this.objectCaching&&(!this.group||!this.group.isOnACache()),this.ownCaching},willDrawShadow:function(){return!!this.shadow&&(0!==this.shadow.offsetX||0!==this.shadow.offsetY)},drawClipPathOnCache:function(e,i){if(e.save(),i.inverted?e.globalCompositeOperation="destination-out":e.globalCompositeOperation="destination-in",i.absolutePositioned){var s=t.util.invertTransform(this.calcTransformMatrix());e.transform(s[0],s[1],s[2],s[3],s[4],s[5])}i.transform(e),e.scale(1/i.zoomX,1/i.zoomY),e.drawImage(i._cacheCanvas,-i.cacheTranslationX,-i.cacheTranslationY),e.restore()},drawObject:function(e,t){var i=this.fill,s=this.stroke;t?(this.fill="black",this.stroke="",this._setClippingProperties(e)):this._renderBackground(e),this._render(e),this._drawClipPath(e,this.clipPath),this.fill=i,this.stroke=s},_drawClipPath:function(e,t){t&&(t.canvas=this.canvas,t.shouldCache(),t._transformDone=!0,t.renderCache({forClipping:!0}),this.drawClipPathOnCache(e,t))},drawCacheOnCanvas:function(e){e.scale(1/this.zoomX,1/this.zoomY),e.drawImage(this._cacheCanvas,-this.cacheTranslationX,-this.cacheTranslationY)},isCacheDirty:function(e){if(this.isNotVisible())return!1;if(this._cacheCanvas&&this._cacheContext&&!e&&this._updateCacheCanvas())return!0;if(this.dirty||this.clipPath&&this.clipPath.absolutePositioned||this.statefullCache&&this.hasStateChanged("cacheProperties")){if(this._cacheCanvas&&this._cacheContext&&!e){var t=this.cacheWidth/this.zoomX,i=this.cacheHeight/this.zoomY;this._cacheContext.clearRect(-t/2,-i/2,t,i)}return!0}return!1},_renderBackground:function(e){if(this.backgroundColor){var t=this._getNonTransformedDimensions();e.fillStyle=this.backgroundColor,e.fillRect(-t.x/2,-t.y/2,t.x,t.y),this._removeShadow(e)}},_setOpacity:function(e){this.group&&!this.group._transformDone?e.globalAlpha=this.getObjectOpacity():e.globalAlpha*=this.opacity},_setStrokeStyles:function(e,t){var i=t.stroke;i&&(e.lineWidth=t.strokeWidth,e.lineCap=t.strokeLineCap,e.lineDashOffset=t.strokeDashOffset,e.lineJoin=t.strokeLineJoin,e.miterLimit=t.strokeMiterLimit,i.toLive?"percentage"===i.gradientUnits||i.gradientTransform||i.patternTransform?this._applyPatternForTransformedGradient(e,i):(e.strokeStyle=i.toLive(e,this),this._applyPatternGradientTransform(e,i)):e.strokeStyle=t.stroke)},_setFillStyles:function(e,t){var i=t.fill;i&&(i.toLive?(e.fillStyle=i.toLive(e,this),this._applyPatternGradientTransform(e,t.fill)):e.fillStyle=i)},_setClippingProperties:function(e){e.globalAlpha=1,e.strokeStyle="transparent",e.fillStyle="#000000"},_setLineDash:function(e,t){t&&0!==t.length&&(1&t.length&&t.push.apply(t,t),e.setLineDash(t))},_renderControls:function(e,i){var s,n,r,a=this.getViewportTransform(),c=this.calcTransformMatrix();n="undefined"!==typeof(i=i||{}).hasBorders?i.hasBorders:this.hasBorders,r="undefined"!==typeof i.hasControls?i.hasControls:this.hasControls,c=t.util.multiplyTransformMatrices(a,c),s=t.util.qrDecompose(c),e.save(),e.translate(s.translateX,s.translateY),e.lineWidth=1*this.borderScaleFactor,this.group||(e.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1),this.flipX&&(s.angle-=180),e.rotate(o(this.group?s.angle:this.angle)),i.forActiveSelection||this.group?n&&this.drawBordersInGroup(e,s,i):n&&this.drawBorders(e,i),r&&this.drawControls(e,i),e.restore()},_setShadow:function(e){if(this.shadow){var i,s=this.shadow,n=this.canvas,r=n&&n.viewportTransform[0]||1,o=n&&n.viewportTransform[3]||1;i=s.nonScaling?{scaleX:1,scaleY:1}:this.getObjectScaling(),n&&n._isRetinaScaling()&&(r*=t.devicePixelRatio,o*=t.devicePixelRatio),e.shadowColor=s.color,e.shadowBlur=s.blur*t.browserShadowBlurConstant*(r+o)*(i.scaleX+i.scaleY)/4,e.shadowOffsetX=s.offsetX*r*i.scaleX,e.shadowOffsetY=s.offsetY*o*i.scaleY}},_removeShadow:function(e){this.shadow&&(e.shadowColor="",e.shadowBlur=e.shadowOffsetX=e.shadowOffsetY=0)},_applyPatternGradientTransform:function(e,t){if(!t||!t.toLive)return{offsetX:0,offsetY:0};var i=t.gradientTransform||t.patternTransform,s=-this.width/2+t.offsetX||0,n=-this.height/2+t.offsetY||0;return"percentage"===t.gradientUnits?e.transform(this.width,0,0,this.height,s,n):e.transform(1,0,0,1,s,n),i&&e.transform(i[0],i[1],i[2],i[3],i[4],i[5]),{offsetX:s,offsetY:n}},_renderPaintInOrder:function(e){"stroke"===this.paintFirst?(this._renderStroke(e),this._renderFill(e)):(this._renderFill(e),this._renderStroke(e))},_render:function(){},_renderFill:function(e){this.fill&&(e.save(),this._setFillStyles(e,this),"evenodd"===this.fillRule?e.fill("evenodd"):e.fill(),e.restore())},_renderStroke:function(e){if(this.stroke&&0!==this.strokeWidth){if(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(e),e.save(),this.strokeUniform&&this.group){var t=this.getObjectScaling();e.scale(1/t.scaleX,1/t.scaleY)}else this.strokeUniform&&e.scale(1/this.scaleX,1/this.scaleY);this._setLineDash(e,this.strokeDashArray),this._setStrokeStyles(e,this),e.stroke(),e.restore()}},_applyPatternForTransformedGradient:function(e,i){var s,n=this._limitCacheSize(this._getCacheCanvasDimensions()),r=t.util.createCanvasElement(),o=this.canvas.getRetinaScaling(),a=n.x/this.scaleX/o,c=n.y/this.scaleY/o;r.width=Math.ceil(a),r.height=Math.ceil(c),(s=r.getContext("2d")).beginPath(),s.moveTo(0,0),s.lineTo(a,0),s.lineTo(a,c),s.lineTo(0,c),s.closePath(),s.translate(a/2,c/2),s.scale(n.zoomX/this.scaleX/o,n.zoomY/this.scaleY/o),this._applyPatternGradientTransform(s,i),s.fillStyle=i.toLive(e),s.fill(),e.translate(-this.width/2-this.strokeWidth/2,-this.height/2-this.strokeWidth/2),e.scale(o*this.scaleX/n.zoomX,o*this.scaleY/n.zoomY),e.strokeStyle=s.createPattern(r,"no-repeat")},_findCenterFromElement:function(){return{x:this.left+this.width/2,y:this.top+this.height/2}},_assignTransformMatrixProps:function(){if(this.transformMatrix){var e=t.util.qrDecompose(this.transformMatrix);this.flipX=!1,this.flipY=!1,this.set("scaleX",e.scaleX),this.set("scaleY",e.scaleY),this.angle=e.angle,this.skewX=e.skewX,this.skewY=0}},_removeTransformMatrix:function(e){var i=this._findCenterFromElement();this.transformMatrix&&(this._assignTransformMatrixProps(),i=t.util.transformPoint(i,this.transformMatrix)),this.transformMatrix=null,e&&(this.scaleX*=e.scaleX,this.scaleY*=e.scaleY,this.cropX=e.cropX,this.cropY=e.cropY,i.x+=e.offsetLeft,i.y+=e.offsetTop,this.width=e.width,this.height=e.height),this.setPositionByOrigin(i,"center","center")},clone:function(e,i){var s=this.toObject(i);this.constructor.fromObject?this.constructor.fromObject(s,e):t.Object._fromObject("Object",s,e)},cloneAsImage:function(e,i){var s=this.toCanvasElement(i);return e&&e(new t.Image(s)),this},toCanvasElement:function(e){e||(e={});var i=t.util,s=i.saveObjectTransform(this),n=this.group,r=this.shadow,o=Math.abs,a=(e.multiplier||1)*(e.enableRetinaScaling?t.devicePixelRatio:1);delete this.group,e.withoutTransform&&i.resetObjectTransform(this),e.withoutShadow&&(this.shadow=null);var c,l,h,d,u=t.util.createCanvasElement(),g=this.getBoundingRect(!0,!0),p=this.shadow,m={x:0,y:0};p&&(l=p.blur,c=p.nonScaling?{scaleX:1,scaleY:1}:this.getObjectScaling(),m.x=2*Math.round(o(p.offsetX)+l)*o(c.scaleX),m.y=2*Math.round(o(p.offsetY)+l)*o(c.scaleY)),h=g.width+m.x,d=g.height+m.y,u.width=Math.ceil(h),u.height=Math.ceil(d);var f=new t.StaticCanvas(u,{enableRetinaScaling:!1,renderOnAddRemove:!1,skipOffscreen:!1});"jpeg"===e.format&&(f.backgroundColor="#fff"),this.setPositionByOrigin(new t.Point(f.width/2,f.height/2),"center","center");var _=this.canvas;f.add(this);var v=f.toCanvasElement(a||1,e);return this.shadow=r,this.set("canvas",_),n&&(this.group=n),this.set(s).setCoords(),f._objects=[],f.dispose(),f=null,v},toDataURL:function(e){return e||(e={}),t.util.toDataURL(this.toCanvasElement(e),e.format||"png",e.quality||1)},isType:function(e){return arguments.length>1?Array.from(arguments).includes(this.type):this.type===e},complexity:function(){return 1},toJSON:function(e){return this.toObject(e)},rotate:function(e){var t=("center"!==this.originX||"center"!==this.originY)&&this.centeredRotation;return t&&this._setOriginToCenter(),this.set("angle",e),t&&this._resetOrigin(),this},centerH:function(){return this.canvas&&this.canvas.centerObjectH(this),this},viewportCenterH:function(){return this.canvas&&this.canvas.viewportCenterObjectH(this),this},centerV:function(){return this.canvas&&this.canvas.centerObjectV(this),this},viewportCenterV:function(){return this.canvas&&this.canvas.viewportCenterObjectV(this),this},center:function(){return this.canvas&&this.canvas.centerObject(this),this},viewportCenter:function(){return this.canvas&&this.canvas.viewportCenterObject(this),this},getLocalPointer:function(e,i){i=i||this.canvas.getPointer(e);var s=new t.Point(i.x,i.y),n=this._getLeftTopCoords();return this.angle&&(s=t.util.rotatePoint(s,n,o(-this.angle))),{x:s.x-n.x,y:s.y-n.y}},_setupCompositeOperation:function(e){this.globalCompositeOperation&&(e.globalCompositeOperation=this.globalCompositeOperation)},dispose:function(){t.runningAnimations&&t.runningAnimations.cancelByTarget(this)}}),t.util.createAccessors&&t.util.createAccessors(t.Object),i(t.Object.prototype,t.Observable),t.Object.NUM_FRACTION_DIGITS=2,t.Object.ENLIVEN_PROPS=["clipPath"],t.Object._fromObject=function(e,i,n,r){var o=t[e];i=s(i,!0),t.util.enlivenPatterns([i.fill,i.stroke],(function(e){"undefined"!==typeof e[0]&&(i.fill=e[0]),"undefined"!==typeof e[1]&&(i.stroke=e[1]),t.util.enlivenObjectEnlivables(i,i,(function(){var e=r?new o(i[r],i):new o(i);n&&n(e)}))}))},t.Object.__uid=0)}(t),function(){var e=n.util.degreesToRadians,t={left:-.5,center:0,right:.5},i={top:-.5,center:0,bottom:.5};n.util.object.extend(n.Object.prototype,{translateToGivenOrigin:function(e,s,r,o,a){var c,l,h,d=e.x,u=e.y;return"string"===typeof s?s=t[s]:s-=.5,"string"===typeof o?o=t[o]:o-=.5,"string"===typeof r?r=i[r]:r-=.5,"string"===typeof a?a=i[a]:a-=.5,l=a-r,((c=o-s)||l)&&(h=this._getTransformedDimensions(),d=e.x+c*h.x,u=e.y+l*h.y),new n.Point(d,u)},translateToCenterPoint:function(t,i,s){var r=this.translateToGivenOrigin(t,i,s,"center","center");return this.angle?n.util.rotatePoint(r,t,e(this.angle)):r},translateToOriginPoint:function(t,i,s){var r=this.translateToGivenOrigin(t,"center","center",i,s);return this.angle?n.util.rotatePoint(r,t,e(this.angle)):r},getCenterPoint:function(){var e=new n.Point(this.left,this.top);return this.translateToCenterPoint(e,this.originX,this.originY)},getPointByOrigin:function(e,t){var i=this.getCenterPoint();return this.translateToOriginPoint(i,e,t)},toLocalPoint:function(t,i,s){var r,o,a=this.getCenterPoint();return r="undefined"!==typeof i&&"undefined"!==typeof s?this.translateToGivenOrigin(a,"center","center",i,s):new n.Point(this.left,this.top),o=new n.Point(t.x,t.y),this.angle&&(o=n.util.rotatePoint(o,a,-e(this.angle))),o.subtractEquals(r)},setPositionByOrigin:function(e,t,i){var s=this.translateToCenterPoint(e,t,i),n=this.translateToOriginPoint(s,this.originX,this.originY);this.set("left",n.x),this.set("top",n.y)},adjustPosition:function(i){var s,r,o=e(this.angle),a=this.getScaledWidth(),c=n.util.cos(o)*a,l=n.util.sin(o)*a;s="string"===typeof this.originX?t[this.originX]:this.originX-.5,r="string"===typeof i?t[i]:i-.5,this.left+=c*(r-s),this.top+=l*(r-s),this.setCoords(),this.originX=i},_setOriginToCenter:function(){this._originalOriginX=this.originX,this._originalOriginY=this.originY;var e=this.getCenterPoint();this.originX="center",this.originY="center",this.left=e.x,this.top=e.y},_resetOrigin:function(){var e=this.translateToOriginPoint(this.getCenterPoint(),this._originalOriginX,this._originalOriginY);this.originX=this._originalOriginX,this.originY=this._originalOriginY,this.left=e.x,this.top=e.y,this._originalOriginX=null,this._originalOriginY=null},_getLeftTopCoords:function(){return this.translateToOriginPoint(this.getCenterPoint(),"left","top")}})}(),function(){var e=n.util,t=e.degreesToRadians,i=e.multiplyTransformMatrices,s=e.transformPoint;e.object.extend(n.Object.prototype,{oCoords:null,aCoords:null,lineCoords:null,ownMatrixCache:null,matrixCache:null,controls:{},_getCoords:function(e,t){return t?e?this.calcACoords():this.calcLineCoords():(this.aCoords&&this.lineCoords||this.setCoords(!0),e?this.aCoords:this.lineCoords)},getCoords:function(e,t){return i=this._getCoords(e,t),[new n.Point(i.tl.x,i.tl.y),new n.Point(i.tr.x,i.tr.y),new n.Point(i.br.x,i.br.y),new n.Point(i.bl.x,i.bl.y)];var i},intersectsWithRect:function(e,t,i,s){var r=this.getCoords(i,s);return"Intersection"===n.Intersection.intersectPolygonRectangle(r,e,t).status},intersectsWithObject:function(e,t,i){return"Intersection"===n.Intersection.intersectPolygonPolygon(this.getCoords(t,i),e.getCoords(t,i)).status||e.isContainedWithinObject(this,t,i)||this.isContainedWithinObject(e,t,i)},isContainedWithinObject:function(e,t,i){for(var s=this.getCoords(t,i),n=t?e.aCoords:e.lineCoords,r=0,o=e._getImageLines(n);r<4;r++)if(!e.containsPoint(s[r],o))return!1;return!0},isContainedWithinRect:function(e,t,i,s){var n=this.getBoundingRect(i,s);return n.left>=e.x&&n.left+n.width<=t.x&&n.top>=e.y&&n.top+n.height<=t.y},containsPoint:function(e,t,i,s){var n=this._getCoords(i,s),r=(t=t||this._getImageLines(n),this._findCrossPoints(e,t));return 0!==r&&r%2===1},isOnScreen:function(e){if(!this.canvas)return!1;var t=this.canvas.vptCoords.tl,i=this.canvas.vptCoords.br;return!!this.getCoords(!0,e).some((function(e){return e.x<=i.x&&e.x>=t.x&&e.y<=i.y&&e.y>=t.y}))||(!!this.intersectsWithRect(t,i,!0,e)||this._containsCenterOfCanvas(t,i,e))},_containsCenterOfCanvas:function(e,t,i){var s={x:(e.x+t.x)/2,y:(e.y+t.y)/2};return!!this.containsPoint(s,null,!0,i)},isPartiallyOnScreen:function(e){if(!this.canvas)return!1;var t=this.canvas.vptCoords.tl,i=this.canvas.vptCoords.br;return!!this.intersectsWithRect(t,i,!0,e)||this.getCoords(!0,e).every((function(e){return(e.x>=i.x||e.x<=t.x)&&(e.y>=i.y||e.y<=t.y)}))&&this._containsCenterOfCanvas(t,i,e)},_getImageLines:function(e){return{topline:{o:e.tl,d:e.tr},rightline:{o:e.tr,d:e.br},bottomline:{o:e.br,d:e.bl},leftline:{o:e.bl,d:e.tl}}},_findCrossPoints:function(e,t){var i,s,n,r=0;for(var o in t)if(!((n=t[o]).o.y=e.y&&n.d.y>=e.y)&&(n.o.x===n.d.x&&n.o.x>=e.x?s=n.o.x:(i=(n.d.y-n.o.y)/(n.d.x-n.o.x),s=-(e.y-0*e.x-(n.o.y-i*n.o.x))/(0-i)),s>=e.x&&(r+=1),2===r))break;return r},getBoundingRect:function(t,i){var s=this.getCoords(t,i);return e.makeBoundingBoxFromPoints(s)},getScaledWidth:function(){return this._getTransformedDimensions().x},getScaledHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(e){return Math.abs(e)\n')}},toSVG:function(e){return this._createBaseSVGMarkup(this._toSVG(e),{reviver:e})},toClipPathSVG:function(e){return"\t"+this._createBaseClipPathSVGMarkup(this._toSVG(e),{reviver:e})},_createBaseClipPathSVGMarkup:function(e,t){var i=(t=t||{}).reviver,s=t.additionalTransform||"",n=[this.getSvgTransform(!0,s),this.getSvgCommons()].join(""),r=e.indexOf("COMMON_PARTS");return e[r]=n,i?i(e.join("")):e.join("")},_createBaseSVGMarkup:function(e,t){var i,s,r=(t=t||{}).noStyle,o=t.reviver,a=r?"":'style="'+this.getSvgStyles()+'" ',c=t.withShadow?'style="'+this.getSvgFilter()+'" ':"",l=this.clipPath,h=this.strokeUniform?'vector-effect="non-scaling-stroke" ':"",d=l&&l.absolutePositioned,u=this.stroke,g=this.fill,p=this.shadow,m=[],f=e.indexOf("COMMON_PARTS"),_=t.additionalTransform;return l&&(l.clipPathId="CLIPPATH_"+n.Object.__uid++,s='\n'+l.toClipPathSVG(o)+"\n"),d&&m.push("\n"),m.push("\n"),i=[a,h,r?"":this.addPaintOrder()," ",_?'transform="'+_+'" ':""].join(""),e[f]=i,g&&g.toLive&&m.push(g.toSVG(this)),u&&u.toLive&&m.push(u.toSVG(this)),p&&m.push(p.toSVG(this)),l&&m.push(s),m.push(e.join("")),m.push("\n"),d&&m.push("\n"),o?o(m.join("")):m.join("")},addPaintOrder:function(){return"fill"!==this.paintFirst?' paint-order="'+this.paintFirst+'" ':""}})}(),function(){var e=n.util.object.extend,t="stateProperties";function i(t,i,s){var n={};s.forEach((function(e){n[e]=t[e]})),e(t[i],n,!0)}function s(e,t,i){if(e===t)return!0;if(Array.isArray(e)){if(!Array.isArray(t)||e.length!==t.length)return!1;for(var n=0,r=e.length;n=0;c--)if(n=a[c],this.isControlVisible(n)&&(s=this._getImageLines(t?this.oCoords[n].touchCorner:this.oCoords[n].corner),0!==(i=this._findCrossPoints({x:r,y:o},s))&&i%2===1))return this.__corner=n,n;return!1},forEachControl:function(e){for(var t in this.controls)e(this.controls[t],t,this)},_setCornerCoords:function(){var e=this.oCoords;for(var t in e){var i=this.controls[t];e[t].corner=i.calcCornerCoords(this.angle,this.cornerSize,e[t].x,e[t].y,!1),e[t].touchCorner=i.calcCornerCoords(this.angle,this.touchCornerSize,e[t].x,e[t].y,!0)}},drawSelectionBackground:function(t){if(!this.selectionBackgroundColor||this.canvas&&!this.canvas.interactive||this.canvas&&this.canvas._activeObject!==this)return this;t.save();var i=this.getCenterPoint(),s=this._calculateCurrentDimensions(),n=this.canvas.viewportTransform;return t.translate(i.x,i.y),t.scale(1/n[0],1/n[3]),t.rotate(e(this.angle)),t.fillStyle=this.selectionBackgroundColor,t.fillRect(-s.x/2,-s.y/2,s.x,s.y),t.restore(),this},drawBorders:function(e,t){t=t||{};var i=this._calculateCurrentDimensions(),s=this.borderScaleFactor,n=i.x+s,r=i.y+s,o="undefined"!==typeof t.hasControls?t.hasControls:this.hasControls,a=!1;return e.save(),e.strokeStyle=t.borderColor||this.borderColor,this._setLineDash(e,t.borderDashArray||this.borderDashArray),e.strokeRect(-n/2,-r/2,n,r),o&&(e.beginPath(),this.forEachControl((function(t,i,s){t.withConnection&&t.getVisibility(s,i)&&(a=!0,e.moveTo(t.x*n,t.y*r),e.lineTo(t.x*n+t.offsetX,t.y*r+t.offsetY))})),a&&e.stroke()),e.restore(),this},drawBordersInGroup:function(e,t,i){i=i||{};var s=n.util.sizeAfterTransform(this.width,this.height,t),r=this.strokeWidth,o=this.strokeUniform,a=this.borderScaleFactor,c=s.x+r*(o?this.canvas.getZoom():t.scaleX)+a,l=s.y+r*(o?this.canvas.getZoom():t.scaleY)+a;return e.save(),this._setLineDash(e,i.borderDashArray||this.borderDashArray),e.strokeStyle=i.borderColor||this.borderColor,e.strokeRect(-c/2,-l/2,c,l),e.restore(),this},drawControls:function(e,t){t=t||{},e.save();var i,s,r=1;return this.canvas&&(r=this.canvas.getRetinaScaling()),e.setTransform(r,0,0,r,0,0),e.strokeStyle=e.fillStyle=t.cornerColor||this.cornerColor,this.transparentCorners||(e.strokeStyle=t.cornerStrokeColor||this.cornerStrokeColor),this._setLineDash(e,t.cornerDashArray||this.cornerDashArray),this.setCoords(),this.group&&(i=this.group.calcTransformMatrix()),this.forEachControl((function(r,o,a){s=a.oCoords[o],r.getVisibility(a,o)&&(i&&(s=n.util.transformPoint(s,i)),r.render(e,s.x,s.y,t,a))})),e.restore(),this},isControlVisible:function(e){return this.controls[e]&&this.controls[e].getVisibility(this,e)},setControlVisible:function(e,t){return this._controlsVisibility||(this._controlsVisibility={}),this._controlsVisibility[e]=t,this},setControlsVisibility:function(e){for(var t in e||(e={}),e)this.setControlVisible(t,e[t]);return this},onDeselect:function(){},onSelect:function(){}})}(),n.util.object.extend(n.StaticCanvas.prototype,{FX_DURATION:500,fxCenterObjectH:function(e,t){var i=function(){},s=(t=t||{}).onComplete||i,r=t.onChange||i,o=this;return n.util.animate({target:this,startValue:e.left,endValue:this.getCenterPoint().x,duration:this.FX_DURATION,onChange:function(t){e.set("left",t),o.requestRenderAll(),r()},onComplete:function(){e.setCoords(),s()}})},fxCenterObjectV:function(e,t){var i=function(){},s=(t=t||{}).onComplete||i,r=t.onChange||i,o=this;return n.util.animate({target:this,startValue:e.top,endValue:this.getCenterPoint().y,duration:this.FX_DURATION,onChange:function(t){e.set("top",t),o.requestRenderAll(),r()},onComplete:function(){e.setCoords(),s()}})},fxRemove:function(e,t){var i=function(){},s=(t=t||{}).onComplete||i,r=t.onChange||i,o=this;return n.util.animate({target:this,startValue:e.opacity,endValue:0,duration:this.FX_DURATION,onChange:function(t){e.set("opacity",t),o.requestRenderAll(),r()},onComplete:function(){o.remove(e),s()}})}}),n.util.object.extend(n.Object.prototype,{animate:function(){if(arguments[0]&&"object"===typeof arguments[0]){var e,t,i=[],s=[];for(e in arguments[0])i.push(e);for(var n=0,r=i.length;n-1||r&&o.colorProperties.indexOf(r[1])>-1,c=r?this.get(r[0])[r[1]]:this.get(e);"from"in i||(i.from=c),a||(t=~t.indexOf("=")?c+parseFloat(t.replace("=","")):parseFloat(t));var l={target:this,startValue:i.from,endValue:t,byValue:i.by,easing:i.easing,duration:i.duration,abort:i.abort&&function(e,t,s){return i.abort.call(o,e,t,s)},onChange:function(t,n,a){r?o[r[0]][r[1]]=t:o.set(e,t),s||i.onChange&&i.onChange(t,n,a)},onComplete:function(e,t,n){s||(o.setCoords(),i.onComplete&&i.onComplete(e,t,n))}};return a?n.util.animateColor(l.startValue,l.endValue,l.duration,l):n.util.animate(l)}}),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.util.object.extend,s=t.util.object.clone,n={x1:1,x2:1,y1:1,y2:1};function r(e,t){var i=e.origin,s=e.axis1,n=e.axis2,r=e.dimension,o=t.nearest,a=t.center,c=t.farthest;return function(){switch(this.get(i)){case o:return Math.min(this.get(s),this.get(n));case a:return Math.min(this.get(s),this.get(n))+.5*this.get(r);case c:return Math.max(this.get(s),this.get(n))}}}t.Line?t.warn("fabric.Line is already defined"):(t.Line=t.util.createClass(t.Object,{type:"line",x1:0,y1:0,x2:0,y2:0,cacheProperties:t.Object.prototype.cacheProperties.concat("x1","x2","y1","y2"),initialize:function(e,t){e||(e=[0,0,0,0]),this.callSuper("initialize",t),this.set("x1",e[0]),this.set("y1",e[1]),this.set("x2",e[2]),this.set("y2",e[3]),this._setWidthHeight(t)},_setWidthHeight:function(e){e||(e={}),this.width=Math.abs(this.x2-this.x1),this.height=Math.abs(this.y2-this.y1),this.left="left"in e?e.left:this._getLeftToOriginX(),this.top="top"in e?e.top:this._getTopToOriginY()},_set:function(e,t){return this.callSuper("_set",e,t),"undefined"!==typeof n[e]&&this._setWidthHeight(),this},_getLeftToOriginX:r({origin:"originX",axis1:"x1",axis2:"x2",dimension:"width"},{nearest:"left",center:"center",farthest:"right"}),_getTopToOriginY:r({origin:"originY",axis1:"y1",axis2:"y2",dimension:"height"},{nearest:"top",center:"center",farthest:"bottom"}),_render:function(e){e.beginPath();var t=this.calcLinePoints();e.moveTo(t.x1,t.y1),e.lineTo(t.x2,t.y2),e.lineWidth=this.strokeWidth;var i=e.strokeStyle;e.strokeStyle=this.stroke||e.fillStyle,this.stroke&&this._renderStroke(e),e.strokeStyle=i},_findCenterFromElement:function(){return{x:(this.x1+this.x2)/2,y:(this.y1+this.y2)/2}},toObject:function(e){return i(this.callSuper("toObject",e),this.calcLinePoints())},_getNonTransformedDimensions:function(){var e=this.callSuper("_getNonTransformedDimensions");return"butt"===this.strokeLineCap&&(0===this.width&&(e.y-=this.strokeWidth),0===this.height&&(e.x-=this.strokeWidth)),e},calcLinePoints:function(){var e=this.x1<=this.x2?-1:1,t=this.y1<=this.y2?-1:1,i=e*this.width*.5,s=t*this.height*.5;return{x1:i,x2:e*this.width*-.5,y1:s,y2:t*this.height*-.5}},_toSVG:function(){var e=this.calcLinePoints();return["\n']}}),t.Line.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat("x1 y1 x2 y2".split(" ")),t.Line.fromElement=function(e,s,n){n=n||{};var r=t.parseAttributes(e,t.Line.ATTRIBUTE_NAMES),o=[r.x1||0,r.y1||0,r.x2||0,r.y2||0];s(new t.Line(o,i(r,n)))},t.Line.fromObject=function(e,i){var n=s(e,!0);n.points=[e.x1,e.y1,e.x2,e.y2],t.Object._fromObject("Line",n,(function(e){delete e.points,i&&i(e)}),"points")})}(t),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.util.degreesToRadians;t.Circle?t.warn("fabric.Circle is already defined."):(t.Circle=t.util.createClass(t.Object,{type:"circle",radius:0,startAngle:0,endAngle:360,cacheProperties:t.Object.prototype.cacheProperties.concat("radius","startAngle","endAngle"),_set:function(e,t){return this.callSuper("_set",e,t),"radius"===e&&this.setRadius(t),this},toObject:function(e){return this.callSuper("toObject",["radius","startAngle","endAngle"].concat(e))},_toSVG:function(){var e,s=(this.endAngle-this.startAngle)%360;if(0===s)e=["\n'];else{var n=i(this.startAngle),r=i(this.endAngle),o=this.radius;e=['180?"1":"0")+" 1"," "+t.util.cos(r)*o+" "+t.util.sin(r)*o,'" ',"COMMON_PARTS"," />\n"]}return e},_render:function(e){e.beginPath(),e.arc(0,0,this.radius,i(this.startAngle),i(this.endAngle),!1),this._renderPaintInOrder(e)},getRadiusX:function(){return this.get("radius")*this.get("scaleX")},getRadiusY:function(){return this.get("radius")*this.get("scaleY")},setRadius:function(e){return this.radius=e,this.set("width",2*e).set("height",2*e)}}),t.Circle.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat("cx cy r".split(" ")),t.Circle.fromElement=function(e,i){var s,n=t.parseAttributes(e,t.Circle.ATTRIBUTE_NAMES);if(!("radius"in(s=n)&&s.radius>=0))throw new Error("value of `r` attribute is required and can not be negative");n.left=(n.left||0)-n.radius,n.top=(n.top||0)-n.radius,i(new t.Circle(n))},t.Circle.fromObject=function(e,i){t.Object._fromObject("Circle",e,i)})}(t),function(e){"use strict";var t=e.fabric||(e.fabric={});t.Triangle?t.warn("fabric.Triangle is already defined"):(t.Triangle=t.util.createClass(t.Object,{type:"triangle",width:100,height:100,_render:function(e){var t=this.width/2,i=this.height/2;e.beginPath(),e.moveTo(-t,i),e.lineTo(0,-i),e.lineTo(t,i),e.closePath(),this._renderPaintInOrder(e)},_toSVG:function(){var e=this.width/2,t=this.height/2;return["']}}),t.Triangle.fromObject=function(e,i){return t.Object._fromObject("Triangle",e,i)})}(t),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=2*Math.PI;t.Ellipse?t.warn("fabric.Ellipse is already defined."):(t.Ellipse=t.util.createClass(t.Object,{type:"ellipse",rx:0,ry:0,cacheProperties:t.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(e){this.callSuper("initialize",e),this.set("rx",e&&e.rx||0),this.set("ry",e&&e.ry||0)},_set:function(e,t){switch(this.callSuper("_set",e,t),e){case"rx":this.rx=t,this.set("width",2*t);break;case"ry":this.ry=t,this.set("height",2*t)}return this},getRx:function(){return this.get("rx")*this.get("scaleX")},getRy:function(){return this.get("ry")*this.get("scaleY")},toObject:function(e){return this.callSuper("toObject",["rx","ry"].concat(e))},_toSVG:function(){return["\n']},_render:function(e){e.beginPath(),e.save(),e.transform(1,0,0,this.ry/this.rx,0,0),e.arc(0,0,this.rx,0,i,!1),e.restore(),this._renderPaintInOrder(e)}}),t.Ellipse.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat("cx cy rx ry".split(" ")),t.Ellipse.fromElement=function(e,i){var s=t.parseAttributes(e,t.Ellipse.ATTRIBUTE_NAMES);s.left=(s.left||0)-s.rx,s.top=(s.top||0)-s.ry,i(new t.Ellipse(s))},t.Ellipse.fromObject=function(e,i){t.Object._fromObject("Ellipse",e,i)})}(t),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.util.object.extend;t.Rect?t.warn("fabric.Rect is already defined"):(t.Rect=t.util.createClass(t.Object,{stateProperties:t.Object.prototype.stateProperties.concat("rx","ry"),type:"rect",rx:0,ry:0,cacheProperties:t.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(e){this.callSuper("initialize",e),this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(e){var t=this.rx?Math.min(this.rx,this.width/2):0,i=this.ry?Math.min(this.ry,this.height/2):0,s=this.width,n=this.height,r=-this.width/2,o=-this.height/2,a=0!==t||0!==i,c=.4477152502;e.beginPath(),e.moveTo(r+t,o),e.lineTo(r+s-t,o),a&&e.bezierCurveTo(r+s-c*t,o,r+s,o+c*i,r+s,o+i),e.lineTo(r+s,o+n-i),a&&e.bezierCurveTo(r+s,o+n-c*i,r+s-c*t,o+n,r+s-t,o+n),e.lineTo(r+t,o+n),a&&e.bezierCurveTo(r+c*t,o+n,r,o+n-c*i,r,o+n-i),e.lineTo(r,o+i),a&&e.bezierCurveTo(r,o+c*i,r+c*t,o,r+t,o),e.closePath(),this._renderPaintInOrder(e)},toObject:function(e){return this.callSuper("toObject",["rx","ry"].concat(e))},_toSVG:function(){return["\n']}}),t.Rect.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat("x y rx ry width height".split(" ")),t.Rect.fromElement=function(e,s,n){if(!e)return s(null);n=n||{};var r=t.parseAttributes(e,t.Rect.ATTRIBUTE_NAMES);r.left=r.left||0,r.top=r.top||0,r.height=r.height||0,r.width=r.width||0;var o=new t.Rect(i(n?t.util.object.clone(n):{},r));o.visible=o.visible&&o.width>0&&o.height>0,s(o)},t.Rect.fromObject=function(e,i){return t.Object._fromObject("Rect",e,i)})}(t),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.util.object.extend,s=t.util.array.min,n=t.util.array.max,r=t.util.toFixed,o=t.util.projectStrokeOnPoints;t.Polyline?t.warn("fabric.Polyline is already defined"):(t.Polyline=t.util.createClass(t.Object,{type:"polyline",points:null,exactBoundingBox:!1,cacheProperties:t.Object.prototype.cacheProperties.concat("points"),initialize:function(e,t){t=t||{},this.points=e||[],this.callSuper("initialize",t),this._setPositionDimensions(t)},_projectStrokeOnPoints:function(){return o(this.points,this,!0)},_setPositionDimensions:function(e){var t,i=this._calcDimensions(e),s=this.exactBoundingBox?this.strokeWidth:0;this.width=i.width-s,this.height=i.height-s,e.fromSVG||(t=this.translateToGivenOrigin({x:i.left-this.strokeWidth/2+s/2,y:i.top-this.strokeWidth/2+s/2},"left","top",this.originX,this.originY)),"undefined"===typeof e.left&&(this.left=e.fromSVG?i.left:t.x),"undefined"===typeof e.top&&(this.top=e.fromSVG?i.top:t.y),this.pathOffset={x:i.left+this.width/2+s/2,y:i.top+this.height/2+s/2}},_calcDimensions:function(){var e=this.exactBoundingBox?this._projectStrokeOnPoints():this.points,t=s(e,"x")||0,i=s(e,"y")||0;return{left:t,top:i,width:(n(e,"x")||0)-t,height:(n(e,"y")||0)-i}},toObject:function(e){return i(this.callSuper("toObject",e),{points:this.points.concat()})},_toSVG:function(){for(var e=[],i=this.pathOffset.x,s=this.pathOffset.y,n=t.Object.NUM_FRACTION_DIGITS,o=0,a=this.points.length;o\n']},commonRender:function(e){var t,i=this.points.length,s=this.pathOffset.x,n=this.pathOffset.y;if(!i||isNaN(this.points[i-1].y))return!1;e.beginPath(),e.moveTo(this.points[0].x-s,this.points[0].y-n);for(var r=0;r"},toObject:function(e){return n(this.callSuper("toObject",e),{path:this.path.map((function(e){return e.slice()}))})},toDatalessObject:function(e){var t=this.toObject(["sourcePath"].concat(e));return t.sourcePath&&delete t.path,t},_toSVG:function(){return["\n"]},_getOffsetTransform:function(){var e=t.Object.NUM_FRACTION_DIGITS;return" translate("+o(-this.pathOffset.x,e)+", "+o(-this.pathOffset.y,e)+")"},toClipPathSVG:function(e){var t=this._getOffsetTransform();return"\t"+this._createBaseClipPathSVGMarkup(this._toSVG(),{reviver:e,additionalTransform:t})},toSVG:function(e){var t=this._getOffsetTransform();return this._createBaseSVGMarkup(this._toSVG(),{reviver:e,additionalTransform:t})},complexity:function(){return this.path.length},_calcDimensions:function(){for(var e,n,r=[],o=[],a=0,c=0,l=0,h=0,d=0,u=this.path.length;d"},addWithUpdate:function(e){var i=!!this.group;return this._restoreObjectsState(),t.util.resetObjectTransform(this),e&&(i&&t.util.removeTransformFromObject(e,this.group.calcTransformMatrix()),this._objects.push(e),e.group=this,e._set("canvas",this.canvas)),this._calcBounds(),this._updateObjectsCoords(),this.dirty=!0,i?this.group.addWithUpdate():this.setCoords(),this},removeWithUpdate:function(e){return this._restoreObjectsState(),t.util.resetObjectTransform(this),this.remove(e),this._calcBounds(),this._updateObjectsCoords(),this.setCoords(),this.dirty=!0,this},_onObjectAdded:function(e){this.dirty=!0,e.group=this,e._set("canvas",this.canvas)},_onObjectRemoved:function(e){this.dirty=!0,delete e.group},_set:function(e,i){var s=this._objects.length;if(this.useSetOnGroup)for(;s--;)this._objects[s].setOnGroup(e,i);if("canvas"===e)for(;s--;)this._objects[s]._set(e,i);t.Object.prototype._set.call(this,e,i)},toObject:function(e){var i=this.includeDefaultValues,s=this._objects.filter((function(e){return!e.excludeFromExport})).map((function(t){var s=t.includeDefaultValues;t.includeDefaultValues=i;var n=t.toObject(e);return t.includeDefaultValues=s,n})),n=t.Object.prototype.toObject.call(this,e);return n.objects=s,n},toDatalessObject:function(e){var i,s=this.sourcePath;if(s)i=s;else{var n=this.includeDefaultValues;i=this._objects.map((function(t){var i=t.includeDefaultValues;t.includeDefaultValues=n;var s=t.toDatalessObject(e);return t.includeDefaultValues=i,s}))}var r=t.Object.prototype.toDatalessObject.call(this,e);return r.objects=i,r},render:function(e){this._transformDone=!0,this.callSuper("render",e),this._transformDone=!1},shouldCache:function(){var e=t.Object.prototype.shouldCache.call(this);if(e)for(var i=0,s=this._objects.length;i\n"],i=0,s=this._objects.length;i\n"),t},getSvgStyles:function(){var e="undefined"!==typeof this.opacity&&1!==this.opacity?"opacity: "+this.opacity+";":"",t=this.visible?"":" visibility: hidden;";return[e,this.getSvgFilter(),t].join("")},toClipPathSVG:function(e){for(var t=[],i=0,s=this._objects.length;i"},shouldCache:function(){return!1},isOnACache:function(){return!1},_renderControls:function(e,t,i){e.save(),e.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,"undefined"===typeof(i=i||{}).hasControls&&(i.hasControls=!1),i.forActiveSelection=!0;for(var s=0,n=this._objects.length;s\n','\t\n',"\n"),a=' clip-path="url(#imageCrop_'+l+')" '}if(this.imageSmoothing||(c='" image-rendering="optimizeSpeed'),i.push("\t\n"),this.stroke||this.strokeDashArray){var h=this.fill;this.fill=null,e=["\t\n'],this.fill=h}return t="fill"!==this.paintFirst?t.concat(e,i):t.concat(i,e)},getSrc:function(e){var t=e?this._element:this._originalElement;return t?t.toDataURL?t.toDataURL():this.srcFromAttribute?t.getAttribute("src"):t.src:this.src||""},setSrc:function(e,t,i){return n.util.loadImage(e,(function(e,s){this.setElement(e,i),this._setWidthHeight(),t&&t(this,s)}),this,i&&i.crossOrigin),this},toString:function(){return'#'},applyResizeFilters:function(){var e=this.resizeFilter,t=this.minimumScaleTrigger,i=this.getTotalObjectScaling(),s=i.scaleX,r=i.scaleY,o=this._filteredEl||this._originalElement;if(this.group&&this.set("dirty",!0),!e||s>t&&r>t)return this._element=o,this._filterScalingX=1,this._filterScalingY=1,this._lastScaleX=s,void(this._lastScaleY=r);n.filterBackend||(n.filterBackend=n.initFilterBackend());var a=n.util.createCanvasElement(),c=this._filteredEl?this.cacheKey+"_filtered":this.cacheKey,l=o.width,h=o.height;a.width=l,a.height=h,this._element=a,this._lastScaleX=e.scaleX=s,this._lastScaleY=e.scaleY=r,n.filterBackend.applyFilters([e],o,l,h,this._element,c),this._filterScalingX=a.width/this._originalElement.width,this._filterScalingY=a.height/this._originalElement.height},applyFilters:function(e){if(e=(e=e||this.filters||[]).filter((function(e){return e&&!e.isNeutralState()})),this.set("dirty",!0),this.removeTexture(this.cacheKey+"_filtered"),0===e.length)return this._element=this._originalElement,this._filteredEl=null,this._filterScalingX=1,this._filterScalingY=1,this;var t=this._originalElement,i=t.naturalWidth||t.width,s=t.naturalHeight||t.height;if(this._element===this._originalElement){var r=n.util.createCanvasElement();r.width=i,r.height=s,this._element=r,this._filteredEl=r}else this._element=this._filteredEl,this._filteredEl.getContext("2d").clearRect(0,0,i,s),this._lastScaleX=1,this._lastScaleY=1;return n.filterBackend||(n.filterBackend=n.initFilterBackend()),n.filterBackend.applyFilters(e,this._originalElement,i,s,this._element,this.cacheKey),this._originalElement.width===this._element.width&&this._originalElement.height===this._element.height||(this._filterScalingX=this._element.width/this._originalElement.width,this._filterScalingY=this._element.height/this._originalElement.height),this},_render:function(e){n.util.setImageSmoothing(e,this.imageSmoothing),!0!==this.isMoving&&this.resizeFilter&&this._needsResize()&&this.applyResizeFilters(),this._stroke(e),this._renderPaintInOrder(e)},drawCacheOnCanvas:function(e){n.util.setImageSmoothing(e,this.imageSmoothing),n.Object.prototype.drawCacheOnCanvas.call(this,e)},shouldCache:function(){return this.needsItsOwnCache()},_renderFill:function(e){var t=this._element;if(t){var i=this._filterScalingX,s=this._filterScalingY,n=this.width,r=this.height,o=Math.min,a=Math.max,c=a(this.cropX,0),l=a(this.cropY,0),h=t.naturalWidth||t.width,d=t.naturalHeight||t.height,u=c*i,g=l*s,p=o(n*i,h-u),m=o(r*s,d-g),f=-n/2,_=-r/2,v=o(n,h/i-c),C=o(r,d/s-l);t&&e.drawImage(t,u,g,p,m,f,_,v,C)}},_needsResize:function(){var e=this.getTotalObjectScaling();return e.scaleX!==this._lastScaleX||e.scaleY!==this._lastScaleY},_resetWidthHeight:function(){this.set(this.getOriginalSize())},_initElement:function(e,t){this.setElement(n.util.getById(e),t),n.util.addClass(this.getElement(),n.Image.CSS_CANVAS)},_initConfig:function(e){e||(e={}),this.setOptions(e),this._setWidthHeight(e)},_initFilters:function(e,t){e&&e.length?n.util.enlivenObjects(e,(function(e){t&&t(e)}),"fabric.Image.filters"):t&&t()},_setWidthHeight:function(e){e||(e={});var t=this.getElement();this.width=e.width||t.naturalWidth||t.width||0,this.height=e.height||t.naturalHeight||t.height||0},parsePreserveAspectRatioAttribute:function(){var e,t=n.util.parsePreserveAspectRatioAttribute(this.preserveAspectRatio||""),i=this._element.width,s=this._element.height,r=1,o=1,a=0,c=0,l=0,h=0,d=this.width,u=this.height,g={width:d,height:u};return!t||"none"===t.alignX&&"none"===t.alignY?(r=d/i,o=u/s):("meet"===t.meetOrSlice&&(e=(d-i*(r=o=n.util.findScaleToFit(this._element,g)))/2,"Min"===t.alignX&&(a=-e),"Max"===t.alignX&&(a=e),e=(u-s*o)/2,"Min"===t.alignY&&(c=-e),"Max"===t.alignY&&(c=e)),"slice"===t.meetOrSlice&&(e=i-d/(r=o=n.util.findScaleToCover(this._element,g)),"Mid"===t.alignX&&(l=e/2),"Max"===t.alignX&&(l=e),e=s-u/o,"Mid"===t.alignY&&(h=e/2),"Max"===t.alignY&&(h=e),i=d/r,s=u/o)),{width:i,height:s,scaleX:r,scaleY:o,offsetLeft:a,offsetTop:c,cropX:l,cropY:h}}}),n.Image.CSS_CANVAS="canvas-img",n.Image.prototype.getSvgSrc=n.Image.prototype.getSrc,n.Image.fromObject=function(e,t){var i=n.util.object.clone(e);n.util.loadImage(i.src,(function(e,s){s?t&&t(null,!0):n.Image.prototype._initFilters.call(i,i.filters,(function(s){i.filters=s||[],n.Image.prototype._initFilters.call(i,[i.resizeFilter],(function(s){i.resizeFilter=s[0],n.util.enlivenObjectEnlivables(i,i,(function(){var s=new n.Image(e,i);t(s,!1)}))}))}))}),null,i.crossOrigin)},n.Image.fromURL=function(e,t,i){n.util.loadImage(e,(function(e,s){t&&t(new n.Image(e,i),s)}),null,i&&i.crossOrigin)},n.Image.ATTRIBUTE_NAMES=n.SHARED_ATTRIBUTES.concat("x y width height preserveAspectRatio xlink:href crossOrigin image-rendering".split(" ")),n.Image.fromElement=function(e,i,s){var r=n.parseAttributes(e,n.Image.ATTRIBUTE_NAMES);n.Image.fromURL(r["xlink:href"],i,t(s?n.util.object.clone(s):{},r))})}(t),n.util.object.extend(n.Object.prototype,{_getAngleValueForStraighten:function(){var e=this.angle%360;return e>0?90*Math.round((e-1)/90):90*Math.round(e/90)},straighten:function(){return this.rotate(this._getAngleValueForStraighten())},fxStraighten:function(e){var t=function(){},i=(e=e||{}).onComplete||t,s=e.onChange||t,r=this;return n.util.animate({target:this,startValue:this.get("angle"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(e){r.rotate(e),s()},onComplete:function(){r.setCoords(),i()}})}}),n.util.object.extend(n.StaticCanvas.prototype,{straightenObject:function(e){return e.straighten(),this.requestRenderAll(),this},fxStraightenObject:function(e){return e.fxStraighten({onChange:this.requestRenderAllBound})}}),function(){"use strict";function e(e,t){var i="precision "+t+" float;\nvoid main(){}",s=e.createShader(e.FRAGMENT_SHADER);return e.shaderSource(s,i),e.compileShader(s),!!e.getShaderParameter(s,e.COMPILE_STATUS)}function t(e){e&&e.tileSize&&(this.tileSize=e.tileSize),this.setupGLContext(this.tileSize,this.tileSize),this.captureGPUInfo()}n.isWebglSupported=function(t){if(n.isLikelyNode)return!1;t=t||n.WebglFilterBackend.prototype.tileSize;var i=document.createElement("canvas"),s=i.getContext("webgl")||i.getContext("experimental-webgl"),r=!1;if(s){n.maxTextureSize=s.getParameter(s.MAX_TEXTURE_SIZE),r=n.maxTextureSize>=t;for(var o=["highp","mediump","lowp"],a=0;a<3;a++)if(e(s,o[a])){n.webGlPrecision=o[a];break}}return this.isSupported=r,r},n.WebglFilterBackend=t,t.prototype={tileSize:2048,resources:{},setupGLContext:function(e,t){this.dispose(),this.createWebGLCanvas(e,t),this.aPosition=new Float32Array([0,0,0,1,1,0,1,1]),this.chooseFastestCopyGLTo2DMethod(e,t)},chooseFastestCopyGLTo2DMethod:function(e,t){var i,s="undefined"!==typeof window.performance;try{new ImageData(1,1),i=!0}catch(p){i=!1}var r="undefined"!==typeof ArrayBuffer,c="undefined"!==typeof Uint8ClampedArray;if(s&&i&&r&&c){var l=n.util.createCanvasElement(),h=new ArrayBuffer(e*t*4);if(n.forceGLPutImageData)return this.imageBuffer=h,void(this.copyGLTo2D=a);var d,u,g={imageBuffer:h,destinationWidth:e,destinationHeight:t,targetCanvas:l};l.width=e,l.height=t,d=window.performance.now(),o.call(g,this.gl,g),u=window.performance.now()-d,d=window.performance.now(),a.call(g,this.gl,g),u>window.performance.now()-d?(this.imageBuffer=h,this.copyGLTo2D=a):this.copyGLTo2D=o}},createWebGLCanvas:function(e,t){var i=n.util.createCanvasElement();i.width=e,i.height=t;var s={alpha:!0,premultipliedAlpha:!1,depth:!1,stencil:!1,antialias:!1},r=i.getContext("webgl",s);r||(r=i.getContext("experimental-webgl",s)),r&&(r.clearColor(0,0,0,0),this.canvas=i,this.gl=r)},applyFilters:function(e,t,i,s,n,r){var o,a=this.gl;r&&(o=this.getCachedTexture(r,t));var c={originalWidth:t.width||t.originalWidth,originalHeight:t.height||t.originalHeight,sourceWidth:i,sourceHeight:s,destinationWidth:i,destinationHeight:s,context:a,sourceTexture:this.createTexture(a,i,s,!o&&t),targetTexture:this.createTexture(a,i,s),originalTexture:o||this.createTexture(a,i,s,!o&&t),passes:e.length,webgl:!0,aPosition:this.aPosition,programCache:this.programCache,pass:0,filterBackend:this,targetCanvas:n},l=a.createFramebuffer();return a.bindFramebuffer(a.FRAMEBUFFER,l),e.forEach((function(e){e&&e.applyTo(c)})),function(e){var t=e.targetCanvas,i=t.width,s=t.height,n=e.destinationWidth,r=e.destinationHeight;i===n&&s===r||(t.width=n,t.height=r)}(c),this.copyGLTo2D(a,c),a.bindTexture(a.TEXTURE_2D,null),a.deleteTexture(c.sourceTexture),a.deleteTexture(c.targetTexture),a.deleteFramebuffer(l),n.getContext("2d").setTransform(1,0,0,1,0,0),c},dispose:function(){this.canvas&&(this.canvas=null,this.gl=null),this.clearWebGLCaches()},clearWebGLCaches:function(){this.programCache={},this.textureCache={}},createTexture:function(e,t,i,s,n){var r=e.createTexture();return e.bindTexture(e.TEXTURE_2D,r),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,n||e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,n||e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),s?e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,s):e.texImage2D(e.TEXTURE_2D,0,e.RGBA,t,i,0,e.RGBA,e.UNSIGNED_BYTE,null),r},getCachedTexture:function(e,t){if(this.textureCache[e])return this.textureCache[e];var i=this.createTexture(this.gl,t.width,t.height,t);return this.textureCache[e]=i,i},evictCachesForKey:function(e){this.textureCache[e]&&(this.gl.deleteTexture(this.textureCache[e]),delete this.textureCache[e])},copyGLTo2D:o,captureGPUInfo:function(){if(this.gpuInfo)return this.gpuInfo;var e=this.gl,t={renderer:"",vendor:""};if(!e)return t;var i=e.getExtension("WEBGL_debug_renderer_info");if(i){var s=e.getParameter(i.UNMASKED_RENDERER_WEBGL),n=e.getParameter(i.UNMASKED_VENDOR_WEBGL);s&&(t.renderer=s.toLowerCase()),n&&(t.vendor=n.toLowerCase())}return this.gpuInfo=t,t}}}(),function(){"use strict";var e=function(){};function t(){}n.Canvas2dFilterBackend=t,t.prototype={evictCachesForKey:e,dispose:e,clearWebGLCaches:e,resources:{},applyFilters:function(e,t,i,s,n){var r=n.getContext("2d");r.drawImage(t,0,0,i,s);var o={sourceWidth:i,sourceHeight:s,imageData:r.getImageData(0,0,i,s),originalEl:t,originalImageData:r.getImageData(0,0,i,s),canvasEl:n,ctx:r,filterBackend:this};return e.forEach((function(e){e.applyTo(o)})),o.imageData.width===i&&o.imageData.height===s||(n.width=o.imageData.width,n.height=o.imageData.height),r.putImageData(o.imageData,0,0),o}}}(),n.Image=n.Image||{},n.Image.filters=n.Image.filters||{},n.Image.filters.BaseFilter=n.util.createClass({type:"BaseFilter",vertexSource:"attribute vec2 aPosition;\nvarying vec2 vTexCoord;\nvoid main() {\nvTexCoord = aPosition;\ngl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);\n}",fragmentSource:"precision highp float;\nvarying vec2 vTexCoord;\nuniform sampler2D uTexture;\nvoid main() {\ngl_FragColor = texture2D(uTexture, vTexCoord);\n}",initialize:function(e){e&&this.setOptions(e)},setOptions:function(e){for(var t in e)this[t]=e[t]},createProgram:function(e,t,i){t=t||this.fragmentSource,i=i||this.vertexSource,"highp"!==n.webGlPrecision&&(t=t.replace(/precision highp float/g,"precision "+n.webGlPrecision+" float"));var s=e.createShader(e.VERTEX_SHADER);if(e.shaderSource(s,i),e.compileShader(s),!e.getShaderParameter(s,e.COMPILE_STATUS))throw new Error("Vertex shader compile error for "+this.type+": "+e.getShaderInfoLog(s));var r=e.createShader(e.FRAGMENT_SHADER);if(e.shaderSource(r,t),e.compileShader(r),!e.getShaderParameter(r,e.COMPILE_STATUS))throw new Error("Fragment shader compile error for "+this.type+": "+e.getShaderInfoLog(r));var o=e.createProgram();if(e.attachShader(o,s),e.attachShader(o,r),e.linkProgram(o),!e.getProgramParameter(o,e.LINK_STATUS))throw new Error('Shader link error for "${this.type}" '+e.getProgramInfoLog(o));var a=this.getAttributeLocations(e,o),c=this.getUniformLocations(e,o)||{};return c.uStepW=e.getUniformLocation(o,"uStepW"),c.uStepH=e.getUniformLocation(o,"uStepH"),{program:o,attributeLocations:a,uniformLocations:c}},getAttributeLocations:function(e,t){return{aPosition:e.getAttribLocation(t,"aPosition")}},getUniformLocations:function(){return{}},sendAttributeData:function(e,t,i){var s=t.aPosition,n=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,n),e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,0,0),e.bufferData(e.ARRAY_BUFFER,i,e.STATIC_DRAW)},_setupFrameBuffer:function(e){var t,i,s=e.context;e.passes>1?(t=e.destinationWidth,i=e.destinationHeight,e.sourceWidth===t&&e.sourceHeight===i||(s.deleteTexture(e.targetTexture),e.targetTexture=e.filterBackend.createTexture(s,t,i)),s.framebufferTexture2D(s.FRAMEBUFFER,s.COLOR_ATTACHMENT0,s.TEXTURE_2D,e.targetTexture,0)):(s.bindFramebuffer(s.FRAMEBUFFER,null),s.finish())},_swapTextures:function(e){e.passes--,e.pass++;var t=e.targetTexture;e.targetTexture=e.sourceTexture,e.sourceTexture=t},isNeutralState:function(){var e=this.mainParameter,t=n.Image.filters[this.type].prototype;if(e){if(Array.isArray(t[e])){for(var i=t[e].length;i--;)if(this[e][i]!==t[e][i])return!1;return!0}return t[e]===this[e]}return!1},applyTo:function(e){e.webgl?(this._setupFrameBuffer(e),this.applyToWebGL(e),this._swapTextures(e)):this.applyTo2d(e)},retrieveShader:function(e){return e.programCache.hasOwnProperty(this.type)||(e.programCache[this.type]=this.createProgram(e.context)),e.programCache[this.type]},applyToWebGL:function(e){var t=e.context,i=this.retrieveShader(e);0===e.pass&&e.originalTexture?t.bindTexture(t.TEXTURE_2D,e.originalTexture):t.bindTexture(t.TEXTURE_2D,e.sourceTexture),t.useProgram(i.program),this.sendAttributeData(t,i.attributeLocations,e.aPosition),t.uniform1f(i.uniformLocations.uStepW,1/e.sourceWidth),t.uniform1f(i.uniformLocations.uStepH,1/e.sourceHeight),this.sendUniformData(t,i.uniformLocations),t.viewport(0,0,e.destinationWidth,e.destinationHeight),t.drawArrays(t.TRIANGLE_STRIP,0,4)},bindAdditionalTexture:function(e,t,i){e.activeTexture(i),e.bindTexture(e.TEXTURE_2D,t),e.activeTexture(e.TEXTURE0)},unbindAdditionalTexture:function(e,t){e.activeTexture(t),e.bindTexture(e.TEXTURE_2D,null),e.activeTexture(e.TEXTURE0)},getMainParameter:function(){return this[this.mainParameter]},setMainParameter:function(e){this[this.mainParameter]=e},sendUniformData:function(){},createHelpLayer:function(e){if(!e.helpLayer){var t=document.createElement("canvas");t.width=e.sourceWidth,t.height=e.sourceHeight,e.helpLayer=t}},toObject:function(){var e={type:this.type},t=this.mainParameter;return t&&(e[t]=this[t]),e},toJSON:function(){return this.toObject()}}),n.Image.filters.BaseFilter.fromObject=function(e,t){var i=new n.Image.filters[e.type](e);return t&&t(i),i},function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.Image.filters,s=t.util.createClass;i.ColorMatrix=s(i.BaseFilter,{type:"ColorMatrix",fragmentSource:"precision highp float;\nuniform sampler2D uTexture;\nvarying vec2 vTexCoord;\nuniform mat4 uColorMatrix;\nuniform vec4 uConstants;\nvoid main() {\nvec4 color = texture2D(uTexture, vTexCoord);\ncolor *= uColorMatrix;\ncolor += uConstants;\ngl_FragColor = color;\n}",matrix:[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0],mainParameter:"matrix",colorsOnly:!0,initialize:function(e){this.callSuper("initialize",e),this.matrix=this.matrix.slice(0)},applyTo2d:function(e){var t,i,s,n,r,o=e.imageData.data,a=o.length,c=this.matrix,l=this.colorsOnly;for(r=0;r=E||o<0||o>=C||(c=4*(a*C+o),l=f[g*_+u],t+=m[c]*l,i+=m[c+1]*l,s+=m[c+2]*l,y||(n+=m[c+3]*l));S[r]=t,S[r+1]=i,S[r+2]=s,S[r+3]=y?m[r+3]:n}e.imageData=b},getUniformLocations:function(e,t){return{uMatrix:e.getUniformLocation(t,"uMatrix"),uOpaque:e.getUniformLocation(t,"uOpaque"),uHalfSize:e.getUniformLocation(t,"uHalfSize"),uSize:e.getUniformLocation(t,"uSize")}},sendUniformData:function(e,t){e.uniform1fv(t.uMatrix,this.matrix)},toObject:function(){return i(this.callSuper("toObject"),{opaque:this.opaque,matrix:this.matrix})}}),t.Image.filters.Convolute.fromObject=t.Image.filters.BaseFilter.fromObject}(t),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.Image.filters,s=t.util.createClass;i.Grayscale=s(i.BaseFilter,{type:"Grayscale",fragmentSource:{average:"precision highp float;\nuniform sampler2D uTexture;\nvarying vec2 vTexCoord;\nvoid main() {\nvec4 color = texture2D(uTexture, vTexCoord);\nfloat average = (color.r + color.b + color.g) / 3.0;\ngl_FragColor = vec4(average, average, average, color.a);\n}",lightness:"precision highp float;\nuniform sampler2D uTexture;\nuniform int uMode;\nvarying vec2 vTexCoord;\nvoid main() {\nvec4 col = texture2D(uTexture, vTexCoord);\nfloat average = (max(max(col.r, col.g),col.b) + min(min(col.r, col.g),col.b)) / 2.0;\ngl_FragColor = vec4(average, average, average, col.a);\n}",luminosity:"precision highp float;\nuniform sampler2D uTexture;\nuniform int uMode;\nvarying vec2 vTexCoord;\nvoid main() {\nvec4 col = texture2D(uTexture, vTexCoord);\nfloat average = 0.21 * col.r + 0.72 * col.g + 0.07 * col.b;\ngl_FragColor = vec4(average, average, average, col.a);\n}"},mode:"average",mainParameter:"mode",applyTo2d:function(e){var t,i,s=e.imageData.data,n=s.length,r=this.mode;for(t=0;tl[0]&&n>l[1]&&r>l[2]&&s 0.0) {\n"+this.fragmentSource[e]+"}\n}"},retrieveShader:function(e){var t,i=this.type+"_"+this.mode;return e.programCache.hasOwnProperty(i)||(t=this.buildSource(this.mode),e.programCache[i]=this.createProgram(e.context,t)),e.programCache[i]},applyTo2d:function(e){var i,s,n,r,o,a,c,l=e.imageData.data,h=l.length,d=1-this.alpha;i=(c=new t.Color(this.color).getSource())[0]*this.alpha,s=c[1]*this.alpha,n=c[2]*this.alpha;for(var u=0;u=e||t<=-e)return 0;if(t<1.1920929e-7&&t>-1.1920929e-7)return 1;var i=(t*=Math.PI)/e;return a(t)/t*a(i)/i}},applyTo2d:function(e){var t=e.imageData,i=this.scaleX,s=this.scaleY;this.rcpScaleX=1/i,this.rcpScaleY=1/s;var n,r=t.width,a=t.height,c=o(r*i),l=o(a*s);"sliceHack"===this.resizeType?n=this.sliceByTwo(e,r,a,c,l):"hermite"===this.resizeType?n=this.hermiteFastResize(e,r,a,c,l):"bilinear"===this.resizeType?n=this.bilinearFiltering(e,r,a,c,l):"lanczos"===this.resizeType&&(n=this.lanczosResize(e,r,a,c,l)),e.imageData=n},sliceByTwo:function(e,i,n,r,o){var a,c,l=e.imageData,h=.5,d=!1,u=!1,g=i*h,p=n*h,m=t.filterBackend.resources,f=0,_=0,v=i,C=0;for(m.sliceByTwo||(m.sliceByTwo=document.createElement("canvas")),((a=m.sliceByTwo).width<1.5*i||a.height=t)){I=s(1e3*r(w-b.x)),E[I]||(E[I]={});for(var D=S.y-C;D<=S.y+C;D++)D<0||D>=o||(O=s(1e3*r(D-b.y)),E[I][O]||(E[I][O]=g(n(i(I*f,2)+i(O*_,2))/1e3)),(R=E[I][O])>0&&(T+=R,x+=R*h[L=4*(D*t+w)],k+=R*h[L+1],A+=R*h[L+2],N+=R*h[L+3]))}u[L=4*(y*a+c)]=x/T,u[L+1]=k/T,u[L+2]=A/T,u[L+3]=N/T}return++c1&&O<-1||(C=2*O*O*O-3*O*O+1)>0&&(R+=C*g[(I=4*(N+T*t))+3],b+=C,g[I+3]<255&&(C=C*g[I+3]/250),S+=C*g[I],y+=C*g[I+1],w+=C*g[I+2],E+=C)}m[v]=S/E,m[v+1]=y/E,m[v+2]=w/E,m[v+3]=R/b}return p},toObject:function(){return{type:this.type,scaleX:this.scaleX,scaleY:this.scaleY,resizeType:this.resizeType,lanczosLobes:this.lanczosLobes}}}),t.Image.filters.Resize.fromObject=t.Image.filters.BaseFilter.fromObject}(t),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.Image.filters,s=t.util.createClass;i.Contrast=s(i.BaseFilter,{type:"Contrast",fragmentSource:"precision highp float;\nuniform sampler2D uTexture;\nuniform float uContrast;\nvarying vec2 vTexCoord;\nvoid main() {\nvec4 color = texture2D(uTexture, vTexCoord);\nfloat contrastF = 1.015 * (uContrast + 1.0) / (1.0 * (1.015 - uContrast));\ncolor.rgb = contrastF * (color.rgb - 0.5) + 0.5;\ngl_FragColor = color;\n}",contrast:0,mainParameter:"contrast",applyTo2d:function(e){if(0!==this.contrast){var t,i=e.imageData.data,s=i.length,n=Math.floor(255*this.contrast),r=259*(n+255)/(255*(259-n));for(t=0;t1&&(t=1/this.aspectRatio):this.aspectRatio<1&&(t=this.aspectRatio),e=t*this.blur*.12,this.horizontal?i[0]=e:i[1]=e,i}}),i.Blur.fromObject=t.Image.filters.BaseFilter.fromObject}(t),function(e){"use strict";var t=e.fabric||(e.fabric={}),i=t.Image.filters,s=t.util.createClass;i.Gamma=s(i.BaseFilter,{type:"Gamma",fragmentSource:"precision highp float;\nuniform sampler2D uTexture;\nuniform vec3 uGamma;\nvarying vec2 vTexCoord;\nvoid main() {\nvec4 color = texture2D(uTexture, vTexCoord);\nvec3 correction = (1.0 / uGamma);\ncolor.r = pow(color.r, correction.r);\ncolor.g = pow(color.g, correction.g);\ncolor.b = pow(color.b, correction.b);\ngl_FragColor = color;\ngl_FragColor.rgb *= color.a;\n}",gamma:[1,1,1],mainParameter:"gamma",initialize:function(e){this.gamma=[1,1,1],i.BaseFilter.prototype.initialize.call(this,e)},applyTo2d:function(e){var t,i=e.imageData.data,s=this.gamma,n=i.length,r=1/s[0],o=1/s[1],a=1/s[2];for(this.rVals||(this.rVals=new Uint8Array(256),this.gVals=new Uint8Array(256),this.bVals=new Uint8Array(256)),t=0,n=256;t'},_getCacheCanvasDimensions:function(){var e=this.callSuper("_getCacheCanvasDimensions"),t=this.fontSize;return e.width+=t*e.zoomX,e.height+=t*e.zoomY,e},_render:function(e){var t=this.path;t&&!t.isNotVisible()&&t._render(e),this._setTextStyles(e),this._renderTextLinesBackground(e),this._renderTextDecoration(e,"underline"),this._renderText(e),this._renderTextDecoration(e,"overline"),this._renderTextDecoration(e,"linethrough")},_renderText:function(e){"stroke"===this.paintFirst?(this._renderTextStroke(e),this._renderTextFill(e)):(this._renderTextFill(e),this._renderTextStroke(e))},_setTextStyles:function(e,t,i){if(e.textBaseline="alphabetical",this.path)switch(this.pathAlign){case"center":e.textBaseline="middle";break;case"ascender":e.textBaseline="top";break;case"descender":e.textBaseline="bottom"}e.font=this._getFontDeclaration(t,i)},calcTextWidth:function(){for(var e=this.getLineWidth(0),t=1,i=this._textLines.length;te&&(e=s)}return e},_renderTextLine:function(e,t,i,s,n,r){this._renderChars(e,t,i,s,n,r)},_renderTextLinesBackground:function(e){if(this.textBackgroundColor||this.styleHas("textBackgroundColor")){for(var t,i,s,n,r,o,a,c=e.fillStyle,l=this._getLeftOffset(),h=this._getTopOffset(),d=0,u=0,g=this.path,p=0,m=this._textLines.length;p=0:ia?d%=a:d<0&&(d+=a),this._setGraphemeOnPath(d,r,o),d+=r.kernedWidth}return{width:c,numOfSpaces:0}},_setGraphemeOnPath:function(e,i,s){var n=e+i.kernedWidth/2,r=this.path,o=t.util.getPointOnPath(r.path,n,r.segmentsInfo);i.renderLeft=o.x-s.x,i.renderTop=o.y-s.y,i.angle=o.angle+("right"===this.pathSide?Math.PI:0)},_getGraphemeBox:function(e,t,i,s,n){var r,o=this.getCompleteStyleDeclaration(t,i),a=s?this.getCompleteStyleDeclaration(t,i-1):{},c=this._measureChar(e,o,s,a),l=c.kernedWidth,h=c.width;0!==this.charSpacing&&(h+=r=this._getWidthOfCharSpacing(),l+=r);var d={width:h,left:0,height:o.fontSize,kernedWidth:l,deltaY:o.deltaY};if(i>0&&!n){var u=this.__charBounds[t][i-1];d.left=u.left+u.width+c.kernedWidth-c.width}return d},getHeightOfLine:function(e){if(this.__lineHeights[e])return this.__lineHeights[e];for(var t=this._textLines[e],i=this.getHeightOfChar(e,0),s=1,n=t.length;s0){var T=v+r+d;"rtl"===this.direction&&(T=this.width-T-u),l&&_&&(e.fillStyle=_,e.fillRect(T,h+S*s+o,u,this.fontSize/15)),d=g.left,u=g.width,l=p,_=f,s=n,o=a}else u+=g.kernedWidth;T=v+r+d;"rtl"===this.direction&&(T=this.width-T-u),e.fillStyle=f,p&&f&&e.fillRect(T,h+S*s+o,u-b,this.fontSize/15),C+=i}else C+=i;e.restore()}},_getFontDeclaration:function(e,i){var s=e||this,n=this.fontFamily,r=t.Text.genericFonts.indexOf(n.toLowerCase())>-1,o=void 0===n||n.indexOf("'")>-1||n.indexOf(",")>-1||n.indexOf('"')>-1||r?s.fontFamily:'"'+s.fontFamily+'"';return[t.isLikelyNode?s.fontWeight:s.fontStyle,t.isLikelyNode?s.fontStyle:s.fontWeight,i?this.CACHE_FONT_SIZE+"px":s.fontSize+"px",o].join(" ")},render:function(e){this.visible&&(this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(this._shouldClearDimensionCache()&&this.initDimensions(),this.callSuper("render",e)))},_splitTextIntoLines:function(e){for(var i=e.split(this._reNewline),s=new Array(i.length),n=["\n"],r=[],o=0;o-1&&(e.underline=!0),e.textDecoration.indexOf("line-through")>-1&&(e.linethrough=!0),e.textDecoration.indexOf("overline")>-1&&(e.overline=!0),delete e.textDecoration)}n.IText=n.util.createClass(n.Text,n.Observable,{type:"i-text",selectionStart:0,selectionEnd:0,selectionColor:"rgba(17,119,255,0.3)",isEditing:!1,editable:!0,editingBorderColor:"rgba(102,153,255,0.25)",cursorWidth:2,cursorColor:"",cursorDelay:1e3,cursorDuration:600,caching:!0,hiddenTextareaContainer:null,_reSpace:/\s|\n/,_currentCursorOpacity:0,_selectionDirection:null,_abortCursorAnimation:!1,__widthOfSpace:[],inCompositionMode:!1,initialize:function(e,t){this.callSuper("initialize",e,t),this.initBehavior()},setSelectionStart:function(e){e=Math.max(e,0),this._updateAndFire("selectionStart",e)},setSelectionEnd:function(e){e=Math.min(e,this.text.length),this._updateAndFire("selectionEnd",e)},_updateAndFire:function(e,t){this[e]!==t&&(this._fireSelectionChanged(),this[e]=t),this._updateTextarea()},_fireSelectionChanged:function(){this.fire("selection:changed"),this.canvas&&this.canvas.fire("text:selection:changed",{target:this})},initDimensions:function(){this.isEditing&&this.initDelayedCursor(),this.clearContextTop(),this.callSuper("initDimensions")},render:function(e){this.clearContextTop(),this.callSuper("render",e),this.cursorOffsetCache={},this.renderCursorOrSelection()},_render:function(e){this.callSuper("_render",e)},clearContextTop:function(e){if(this.isEditing&&this.canvas&&this.canvas.contextTop){var t=this.canvas.contextTop,i=this.canvas.viewportTransform;t.save(),t.transform(i[0],i[1],i[2],i[3],i[4],i[5]),this.transform(t),this._clearTextArea(t),e||t.restore()}},renderCursorOrSelection:function(){if(this.isEditing&&this.canvas&&this.canvas.contextTop){var e=this._getCursorBoundaries(),t=this.canvas.contextTop;this.clearContextTop(!0),this.selectionStart===this.selectionEnd?this.renderCursor(e,t):this.renderSelection(e,t),t.restore()}},_clearTextArea:function(e){var t=this.width+4,i=this.height+4;e.clearRect(-t/2,-i/2,t,i)},_getCursorBoundaries:function(e){"undefined"===typeof e&&(e=this.selectionStart);var t=this._getLeftOffset(),i=this._getTopOffset(),s=this._getCursorBoundariesOffsets(e);return{left:t,top:i,leftOffset:s.left,topOffset:s.top}},_getCursorBoundariesOffsets:function(e){if(this.cursorOffsetCache&&"top"in this.cursorOffsetCache)return this.cursorOffsetCache;var t,i,s,n,r=0,o=0,a=this.get2DCursorLocation(e);s=a.charIndex,i=a.lineIndex;for(var c=0;c0?o:0)},"rtl"===this.direction&&(n.left*=-1),this.cursorOffsetCache=n,this.cursorOffsetCache},renderCursor:function(e,t){var i=this.get2DCursorLocation(),s=i.lineIndex,n=i.charIndex>0?i.charIndex-1:0,r=this.getValueOfPropertyAt(s,n,"fontSize"),o=this.scaleX*this.canvas.getZoom(),a=this.cursorWidth/o,c=e.topOffset,l=this.getValueOfPropertyAt(s,n,"deltaY");c+=(1-this._fontSizeFraction)*this.getHeightOfLine(s)/this.lineHeight-r*(1-this._fontSizeFraction),this.inCompositionMode&&this.renderSelection(e,t),t.fillStyle=this.cursorColor||this.getValueOfPropertyAt(s,n,"fill"),t.globalAlpha=this.__isMousedown?1:this._currentCursorOpacity,t.fillRect(e.left+e.leftOffset-a/2,c+e.top+l,a,r)},renderSelection:function(e,t){for(var i=this.inCompositionMode?this.hiddenTextarea.selectionStart:this.selectionStart,s=this.inCompositionMode?this.hiddenTextarea.selectionEnd:this.selectionEnd,n=-1!==this.textAlign.indexOf("justify"),r=this.get2DCursorLocation(i),o=this.get2DCursorLocation(s),a=r.lineIndex,c=o.lineIndex,l=r.charIndex<0?0:r.charIndex,h=o.charIndex<0?0:o.charIndex,d=a;d<=c;d++){var u,g=this._getLineLeftOffset(d)||0,p=this.getHeightOfLine(d),m=0,f=0;if(d===a&&(m=this.__charBounds[a][l].left),d>=a&&d1)&&(p/=this.lineHeight);var v=e.left+g+m,C=f-m,E=p,b=0;this.inCompositionMode?(t.fillStyle=this.compositionColor||"black",E=1,b=p):t.fillStyle=this.selectionColor,"rtl"===this.direction&&(v=this.width-v-C),t.fillRect(v,e.top+e.topOffset+b,C,E),e.topOffset+=u}},getCurrentCharFontSize:function(){var e=this._getCurrentCharIndex();return this.getValueOfPropertyAt(e.l,e.c,"fontSize")},getCurrentCharColor:function(){var e=this._getCurrentCharIndex();return this.getValueOfPropertyAt(e.l,e.c,"fill")},_getCurrentCharIndex:function(){var e=this.get2DCursorLocation(this.selectionStart,!0),t=e.charIndex>0?e.charIndex-1:0;return{l:e.lineIndex,c:t}}}),n.IText.fromObject=function(t,i){var s=n.util.stylesFromArray(t.styles,t.text),r=Object.assign({},t,{styles:s});if(delete r.path,e(r),r.styles)for(var o in r.styles)for(var a in r.styles[o])e(r.styles[o][a]);n.Object._fromObject("IText",r,(function(e){t.path?n.Object._fromObject("Path",t.path,(function(t){e.set("path",t),i(e)}),"path"):i(e)}),"text")}}(),function(){var e=n.util.object.clone;n.util.object.extend(n.IText.prototype,{initBehavior:function(){this.initAddedHandler(),this.initRemovedHandler(),this.initCursorSelectionHandlers(),this.initDoubleClickSimulation(),this.mouseMoveHandler=this.mouseMoveHandler.bind(this)},onDeselect:function(){this.isEditing&&this.exitEditing(),this.selected=!1},initAddedHandler:function(){var e=this;this.on("added",(function(){var t=e.canvas;t&&(t._hasITextHandlers||(t._hasITextHandlers=!0,e._initCanvasHandlers(t)),t._iTextInstances=t._iTextInstances||[],t._iTextInstances.push(e))}))},initRemovedHandler:function(){var e=this;this.on("removed",(function(){var t=e.canvas;t&&(t._iTextInstances=t._iTextInstances||[],n.util.removeFromArray(t._iTextInstances,e),0===t._iTextInstances.length&&(t._hasITextHandlers=!1,e._removeCanvasHandlers(t)))}))},_initCanvasHandlers:function(e){e._mouseUpITextHandler=function(){e._iTextInstances&&e._iTextInstances.forEach((function(e){e.__isMousedown=!1}))},e.on("mouse:up",e._mouseUpITextHandler)},_removeCanvasHandlers:function(e){e.off("mouse:up",e._mouseUpITextHandler)},_tick:function(){this._currentTickState=this._animateCursor(this,1,this.cursorDuration,"_onTickComplete")},_animateCursor:function(e,t,i,s){var n;return n={isAborted:!1,abort:function(){this.isAborted=!0}},e.animate("_currentCursorOpacity",t,{duration:i,onComplete:function(){n.isAborted||e[s]()},onChange:function(){e.canvas&&e.selectionStart===e.selectionEnd&&e.renderCursorOrSelection()},abort:function(){return n.isAborted}}),n},_onTickComplete:function(){var e=this;this._cursorTimeout1&&clearTimeout(this._cursorTimeout1),this._cursorTimeout1=setTimeout((function(){e._currentTickCompleteState=e._animateCursor(e,0,this.cursorDuration/2,"_tick")}),100)},initDelayedCursor:function(e){var t=this,i=e?0:this.cursorDelay;this.abortCursorAnimation(),this._currentCursorOpacity=1,this._cursorTimeout2=setTimeout((function(){t._tick()}),i)},abortCursorAnimation:function(){var e=this._currentTickState||this._currentTickCompleteState,t=this.canvas;this._currentTickState&&this._currentTickState.abort(),this._currentTickCompleteState&&this._currentTickCompleteState.abort(),clearTimeout(this._cursorTimeout1),clearTimeout(this._cursorTimeout2),this._currentCursorOpacity=0,e&&t&&t.clearContext(t.contextTop||t.contextContainer)},selectAll:function(){return this.selectionStart=0,this.selectionEnd=this._text.length,this._fireSelectionChanged(),this._updateTextarea(),this},getSelectedText:function(){return this._text.slice(this.selectionStart,this.selectionEnd).join("")},findWordBoundaryLeft:function(e){var t=0,i=e-1;if(this._reSpace.test(this._text[i]))for(;this._reSpace.test(this._text[i]);)t++,i--;for(;/\S/.test(this._text[i])&&i>-1;)t++,i--;return e-t},findWordBoundaryRight:function(e){var t=0,i=e;if(this._reSpace.test(this._text[i]))for(;this._reSpace.test(this._text[i]);)t++,i++;for(;/\S/.test(this._text[i])&&i-1;)t++,i--;return e-t},findLineBoundaryRight:function(e){for(var t=0,i=e;!/\n/.test(this._text[i])&&i0&&sthis.__selectionStartOnMouseDown?(this.selectionStart=this.__selectionStartOnMouseDown,this.selectionEnd=t):(this.selectionStart=t,this.selectionEnd=this.__selectionStartOnMouseDown),this.selectionStart===i&&this.selectionEnd===s||(this.restartCursorIfNeeded(),this._fireSelectionChanged(),this._updateTextarea(),this.renderCursorOrSelection()))}},_setEditingProps:function(){this.hoverCursor="text",this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor="text"),this.borderColor=this.editingBorderColor,this.hasControls=this.selectable=!1,this.lockMovementX=this.lockMovementY=!0},fromStringToGraphemeSelection:function(e,t,i){var s=i.slice(0,e),r=n.util.string.graphemeSplit(s).length;if(e===t)return{selectionStart:r,selectionEnd:r};var o=i.slice(e,t);return{selectionStart:r,selectionEnd:r+n.util.string.graphemeSplit(o).length}},fromGraphemeToStringSelection:function(e,t,i){var s=i.slice(0,e).join("").length;return e===t?{selectionStart:s,selectionEnd:s}:{selectionStart:s,selectionEnd:s+i.slice(e,t).join("").length}},_updateTextarea:function(){if(this.cursorOffsetCache={},this.hiddenTextarea){if(!this.inCompositionMode){var e=this.fromGraphemeToStringSelection(this.selectionStart,this.selectionEnd,this._text);this.hiddenTextarea.selectionStart=e.selectionStart,this.hiddenTextarea.selectionEnd=e.selectionEnd}this.updateTextareaPosition()}},updateFromTextArea:function(){if(this.hiddenTextarea){this.cursorOffsetCache={},this.text=this.hiddenTextarea.value,this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords());var e=this.fromStringToGraphemeSelection(this.hiddenTextarea.selectionStart,this.hiddenTextarea.selectionEnd,this.hiddenTextarea.value);this.selectionEnd=this.selectionStart=e.selectionEnd,this.inCompositionMode||(this.selectionStart=e.selectionStart),this.updateTextareaPosition()}},updateTextareaPosition:function(){if(this.selectionStart===this.selectionEnd){var e=this._calcTextareaPosition();this.hiddenTextarea.style.left=e.left,this.hiddenTextarea.style.top=e.top}},_calcTextareaPosition:function(){if(!this.canvas)return{x:1,y:1};var e=this.inCompositionMode?this.compositionStart:this.selectionStart,t=this._getCursorBoundaries(e),i=this.get2DCursorLocation(e),s=i.lineIndex,r=i.charIndex,o=this.getValueOfPropertyAt(s,r,"fontSize")*this.lineHeight,a=t.leftOffset,c=this.calcTransformMatrix(),l={x:t.left+a,y:t.top+t.topOffset+o},h=this.canvas.getRetinaScaling(),d=this.canvas.upperCanvasEl,u=d.width/h,g=d.height/h,p=u-o,m=g-o,f=d.clientWidth/u,_=d.clientHeight/g;return l=n.util.transformPoint(l,c),(l=n.util.transformPoint(l,this.canvas.viewportTransform)).x*=f,l.y*=_,l.x<0&&(l.x=0),l.x>p&&(l.x=p),l.y<0&&(l.y=0),l.y>m&&(l.y=m),l.x+=this.canvas._offset.left,l.y+=this.canvas._offset.top,{left:l.x+"px",top:l.y+"px",fontSize:o+"px",charHeight:o}},_saveEditingProps:function(){this._savedProps={hasControls:this.hasControls,borderColor:this.borderColor,lockMovementX:this.lockMovementX,lockMovementY:this.lockMovementY,hoverCursor:this.hoverCursor,selectable:this.selectable,defaultCursor:this.canvas&&this.canvas.defaultCursor,moveCursor:this.canvas&&this.canvas.moveCursor}},_restoreEditingProps:function(){this._savedProps&&(this.hoverCursor=this._savedProps.hoverCursor,this.hasControls=this._savedProps.hasControls,this.borderColor=this._savedProps.borderColor,this.selectable=this._savedProps.selectable,this.lockMovementX=this._savedProps.lockMovementX,this.lockMovementY=this._savedProps.lockMovementY,this.canvas&&(this.canvas.defaultCursor=this._savedProps.defaultCursor,this.canvas.moveCursor=this._savedProps.moveCursor))},exitEditing:function(){var e=this._textBeforeEdit!==this.text,t=this.hiddenTextarea;return this.selected=!1,this.isEditing=!1,this.selectionEnd=this.selectionStart,t&&(t.blur&&t.blur(),t.parentNode&&t.parentNode.removeChild(t)),this.hiddenTextarea=null,this.abortCursorAnimation(),this._restoreEditingProps(),this._currentCursorOpacity=0,this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords()),this.fire("editing:exited"),e&&this.fire("modified"),this.canvas&&(this.canvas.off("mouse:move",this.mouseMoveHandler),this.canvas.fire("text:editing:exited",{target:this}),e&&this.canvas.fire("object:modified",{target:this})),this},_removeExtraneousStyles:function(){for(var e in this.styles)this._textLines[e]||delete this.styles[e]},removeStyleFromTo:function(e,t){var i,s,n=this.get2DCursorLocation(e,!0),r=this.get2DCursorLocation(t,!0),o=n.lineIndex,a=n.charIndex,c=r.lineIndex,l=r.charIndex;if(o!==c){if(this.styles[o])for(i=a;i=l&&(s[h-u]=s[d],delete s[d])}},shiftLineStyles:function(t,i){var s=e(this.styles);for(var n in this.styles){var r=parseInt(n,10);r>t&&(this.styles[r+i]=s[r],s[r-i]||delete this.styles[r])}},restartCursorIfNeeded:function(){this._currentTickState&&!this._currentTickState.isAborted&&this._currentTickCompleteState&&!this._currentTickCompleteState.isAborted||this.initDelayedCursor()},insertNewlineStyleObject:function(t,i,s,n){var r,o={},a=!1,c=this._unwrappedTextLines[t].length,l=c===i;for(var h in s||(s=1),this.shiftLineStyles(t,s),this.styles[t]&&(r=this.styles[t][0===i?i:i-1]),this.styles[t]){var d=parseInt(h,10);d>=i&&(a=!0,o[d-i]=this.styles[t][h],l&&0===i||delete this.styles[t][h])}var u=!1;for(a&&!l&&(this.styles[t+s]=o,u=!0),(u||c>i)&&s--;s>0;)n&&n[s-1]?this.styles[t+s]={0:e(n[s-1])}:r?this.styles[t+s]={0:e(r)}:delete this.styles[t+s],s--;this._forceClearCache=!0},insertCharStyleObject:function(t,i,s,n){this.styles||(this.styles={});var r=this.styles[t],o=r?e(r):{};for(var a in s||(s=1),o){var c=parseInt(a,10);c>=i&&(r[c+s]=o[c],o[c-s]||delete r[c])}if(this._forceClearCache=!0,n)for(;s--;)Object.keys(n[s]).length&&(this.styles[t]||(this.styles[t]={}),this.styles[t][i+s]=e(n[s]));else if(r)for(var l=r[i?i-1:1];l&&s--;)this.styles[t][i+s]=e(l)},insertNewStyleBlock:function(e,t,i){for(var s=this.get2DCursorLocation(t,!0),n=[0],r=0,o=0;o0&&(this.insertCharStyleObject(s.lineIndex,s.charIndex,n[0],i),i=i&&i.slice(n[0]+1)),r&&this.insertNewlineStyleObject(s.lineIndex,s.charIndex+n[0],r);for(o=1;o0?this.insertCharStyleObject(s.lineIndex+o,0,n[o],i):i&&this.styles[s.lineIndex+o]&&i[0]&&(this.styles[s.lineIndex+o][0]=i[0]),i=i&&i.slice(n[o]+1);n[o]>0&&this.insertCharStyleObject(s.lineIndex+o,0,n[o],i)},setSelectionStartEndWithShift:function(e,t,i){i<=e?(t===e?this._selectionDirection="left":"right"===this._selectionDirection&&(this._selectionDirection="left",this.selectionEnd=e),this.selectionStart=i):i>e&&ie?this.selectionStart=e:this.selectionStart<0&&(this.selectionStart=0),this.selectionEnd>e?this.selectionEnd=e:this.selectionEnd<0&&(this.selectionEnd=0)}})}(),n.util.object.extend(n.IText.prototype,{initDoubleClickSimulation:function(){this.__lastClickTime=+new Date,this.__lastLastClickTime=+new Date,this.__lastPointer={},this.on("mousedown",this.onMouseDown)},onMouseDown:function(e){if(this.canvas){this.__newClickTime=+new Date;var t=e.pointer;this.isTripleClick(t)&&(this.fire("tripleclick",e),this._stopEvent(e.e)),this.__lastLastClickTime=this.__lastClickTime,this.__lastClickTime=this.__newClickTime,this.__lastPointer=t,this.__lastIsEditing=this.isEditing,this.__lastSelected=this.selected}},isTripleClick:function(e){return this.__newClickTime-this.__lastClickTime<500&&this.__lastClickTime-this.__lastLastClickTime<500&&this.__lastPointer.x===e.x&&this.__lastPointer.y===e.y},_stopEvent:function(e){e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation()},initCursorSelectionHandlers:function(){this.initMousedownHandler(),this.initMouseupHandler(),this.initClicks()},doubleClickHandler:function(e){this.isEditing&&this.selectWord(this.getSelectionStartFromPointer(e.e))},tripleClickHandler:function(e){this.isEditing&&this.selectLine(this.getSelectionStartFromPointer(e.e))},initClicks:function(){this.on("mousedblclick",this.doubleClickHandler),this.on("tripleclick",this.tripleClickHandler)},_mouseDownHandler:function(e){!this.canvas||!this.editable||e.e.button&&1!==e.e.button||(this.__isMousedown=!0,this.selected&&(this.inCompositionMode=!1,this.setCursorByClick(e.e)),this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.selectionStart===this.selectionEnd&&this.abortCursorAnimation(),this.renderCursorOrSelection()))},_mouseDownHandlerBefore:function(e){!this.canvas||!this.editable||e.e.button&&1!==e.e.button||(this.selected=this===this.canvas._activeObject)},initMousedownHandler:function(){this.on("mousedown",this._mouseDownHandler),this.on("mousedown:before",this._mouseDownHandlerBefore)},initMouseupHandler:function(){this.on("mouseup",this.mouseUpHandler)},mouseUpHandler:function(e){if(this.__isMousedown=!1,!(!this.editable||this.group||e.transform&&e.transform.actionPerformed||e.e.button&&1!==e.e.button)){if(this.canvas){var t=this.canvas._activeObject;if(t&&t!==this)return}this.__lastSelected&&!this.__corner?(this.selected=!1,this.__lastSelected=!1,this.enterEditing(e.e),this.selectionStart===this.selectionEnd?this.initDelayedCursor(!0):this.renderCursorOrSelection()):this.selected=!0}},setCursorByClick:function(e){var t=this.getSelectionStartFromPointer(e),i=this.selectionStart,s=this.selectionEnd;e.shiftKey?this.setSelectionStartEndWithShift(i,s,t):(this.selectionStart=t,this.selectionEnd=t),this.isEditing&&(this._fireSelectionChanged(),this._updateTextarea())},getSelectionStartFromPointer:function(e){for(var t,i=this.getLocalPointer(e),s=0,n=0,r=0,o=0,a=0,c=0,l=this._textLines.length;c0&&(o+=this._textLines[c-1].length+this.missingNewlineOffset(c-1));n=this._getLineLeftOffset(a)*this.scaleX,t=this._textLines[a],"rtl"===this.direction&&(i.x=this.width*this.scaleX-i.x+n);for(var h=0,d=t.length;hr||o<0?0:1);return this.flipX&&(a=n-a),a>this._text.length&&(a=this._text.length),a}}),n.util.object.extend(n.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=n.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off"),this.hiddenTextarea.setAttribute("autocorrect","off"),this.hiddenTextarea.setAttribute("autocomplete","off"),this.hiddenTextarea.setAttribute("spellcheck","false"),this.hiddenTextarea.setAttribute("data-fabric-hiddentextarea",""),this.hiddenTextarea.setAttribute("wrap","off");var e=this._calcTextareaPosition();this.hiddenTextarea.style.cssText="position: absolute; top: "+e.top+"; left: "+e.left+"; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; padding-top: "+e.fontSize+";",this.hiddenTextareaContainer?this.hiddenTextareaContainer.appendChild(this.hiddenTextarea):n.document.body.appendChild(this.hiddenTextarea),n.util.addListener(this.hiddenTextarea,"keydown",this.onKeyDown.bind(this)),n.util.addListener(this.hiddenTextarea,"keyup",this.onKeyUp.bind(this)),n.util.addListener(this.hiddenTextarea,"input",this.onInput.bind(this)),n.util.addListener(this.hiddenTextarea,"copy",this.copy.bind(this)),n.util.addListener(this.hiddenTextarea,"cut",this.copy.bind(this)),n.util.addListener(this.hiddenTextarea,"paste",this.paste.bind(this)),n.util.addListener(this.hiddenTextarea,"compositionstart",this.onCompositionStart.bind(this)),n.util.addListener(this.hiddenTextarea,"compositionupdate",this.onCompositionUpdate.bind(this)),n.util.addListener(this.hiddenTextarea,"compositionend",this.onCompositionEnd.bind(this)),!this._clickHandlerInitialized&&this.canvas&&(n.util.addListener(this.canvas.upperCanvasEl,"click",this.onClick.bind(this)),this._clickHandlerInitialized=!0)},keysMap:{9:"exitEditing",27:"exitEditing",33:"moveCursorUp",34:"moveCursorDown",35:"moveCursorRight",36:"moveCursorLeft",37:"moveCursorLeft",38:"moveCursorUp",39:"moveCursorRight",40:"moveCursorDown"},keysMapRtl:{9:"exitEditing",27:"exitEditing",33:"moveCursorUp",34:"moveCursorDown",35:"moveCursorLeft",36:"moveCursorRight",37:"moveCursorRight",38:"moveCursorUp",39:"moveCursorLeft",40:"moveCursorDown"},ctrlKeysMapUp:{67:"copy",88:"cut"},ctrlKeysMapDown:{65:"selectAll"},onClick:function(){this.hiddenTextarea&&this.hiddenTextarea.focus()},onKeyDown:function(e){if(this.isEditing){var t="rtl"===this.direction?this.keysMapRtl:this.keysMap;if(e.keyCode in t)this[t[e.keyCode]](e);else{if(!(e.keyCode in this.ctrlKeysMapDown)||!e.ctrlKey&&!e.metaKey)return;this[this.ctrlKeysMapDown[e.keyCode]](e)}e.stopImmediatePropagation(),e.preventDefault(),e.keyCode>=33&&e.keyCode<=40?(this.inCompositionMode=!1,this.clearContextTop(),this.renderCursorOrSelection()):this.canvas&&this.canvas.requestRenderAll()}},onKeyUp:function(e){!this.isEditing||this._copyDone||this.inCompositionMode?this._copyDone=!1:e.keyCode in this.ctrlKeysMapUp&&(e.ctrlKey||e.metaKey)&&(this[this.ctrlKeysMapUp[e.keyCode]](e),e.stopImmediatePropagation(),e.preventDefault(),this.canvas&&this.canvas.requestRenderAll())},onInput:function(e){var t=this.fromPaste;if(this.fromPaste=!1,e&&e.stopPropagation(),this.isEditing){var i,s,r,o,a,c=this._splitTextIntoLines(this.hiddenTextarea.value).graphemeText,l=this._text.length,h=c.length,d=h-l,u=this.selectionStart,g=this.selectionEnd,p=u!==g;if(""===this.hiddenTextarea.value)return this.styles={},this.updateFromTextArea(),this.fire("changed"),void(this.canvas&&(this.canvas.fire("text:changed",{target:this}),this.canvas.requestRenderAll()));var m=this.fromStringToGraphemeSelection(this.hiddenTextarea.selectionStart,this.hiddenTextarea.selectionEnd,this.hiddenTextarea.value),f=u>m.selectionStart;p?(i=this._text.slice(u,g),d+=g-u):h0&&(s+=(i=this.__charBounds[e][t-1]).left+i.width),s},getDownCursorOffset:function(e,t){var i=this._getSelectionForOffset(e,t),s=this.get2DCursorLocation(i),n=s.lineIndex;if(n===this._textLines.length-1||e.metaKey||34===e.keyCode)return this._text.length-i;var r=s.charIndex,o=this._getWidthBeforeCursor(n,r),a=this._getIndexOnLine(n+1,o);return this._textLines[n].slice(r).length+a+1+this.missingNewlineOffset(n)},_getSelectionForOffset:function(e,t){return e.shiftKey&&this.selectionStart!==this.selectionEnd&&t?this.selectionEnd:this.selectionStart},getUpCursorOffset:function(e,t){var i=this._getSelectionForOffset(e,t),s=this.get2DCursorLocation(i),n=s.lineIndex;if(0===n||e.metaKey||33===e.keyCode)return-i;var r=s.charIndex,o=this._getWidthBeforeCursor(n,r),a=this._getIndexOnLine(n-1,o),c=this._textLines[n].slice(0,r),l=this.missingNewlineOffset(n-1);return-this._textLines[n-1].length+a-c.length+(1-l)},_getIndexOnLine:function(e,t){for(var i,s,n=this._textLines[e],r=this._getLineLeftOffset(e),o=0,a=0,c=n.length;at){s=!0;var l=r-i,h=r,d=Math.abs(l-t);o=Math.abs(h-t)=this._text.length&&this.selectionEnd>=this._text.length||this._moveCursorUpOrDown("Down",e)},moveCursorUp:function(e){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorUpOrDown("Up",e)},_moveCursorUpOrDown:function(e,t){var i=this["get"+e+"CursorOffset"](t,"right"===this._selectionDirection);t.shiftKey?this.moveCursorWithShift(i):this.moveCursorWithoutShift(i),0!==i&&(this.setSelectionInBoundaries(),this.abortCursorAnimation(),this._currentCursorOpacity=1,this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorWithShift:function(e){var t="left"===this._selectionDirection?this.selectionStart+e:this.selectionEnd+e;return this.setSelectionStartEndWithShift(this.selectionStart,this.selectionEnd,t),0!==e},moveCursorWithoutShift:function(e){return e<0?(this.selectionStart+=e,this.selectionEnd=this.selectionStart):(this.selectionEnd+=e,this.selectionStart=this.selectionEnd),0!==e},moveCursorLeft:function(e){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorLeftOrRight("Left",e)},_move:function(e,t,i){var s;if(e.altKey)s=this["findWordBoundary"+i](this[t]);else{if(!e.metaKey&&35!==e.keyCode&&36!==e.keyCode)return this[t]+="Left"===i?-1:1,!0;s=this["findLineBoundary"+i](this[t])}if("undefined"!==typeof s&&this[t]!==s)return this[t]=s,!0},_moveLeft:function(e,t){return this._move(e,t,"Left")},_moveRight:function(e,t){return this._move(e,t,"Right")},moveCursorLeftWithoutShift:function(e){var t=!0;return this._selectionDirection="left",this.selectionEnd===this.selectionStart&&0!==this.selectionStart&&(t=this._moveLeft(e,"selectionStart")),this.selectionEnd=this.selectionStart,t},moveCursorLeftWithShift:function(e){return"right"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveLeft(e,"selectionEnd"):0!==this.selectionStart?(this._selectionDirection="left",this._moveLeft(e,"selectionStart")):void 0},moveCursorRight:function(e){this.selectionStart>=this._text.length&&this.selectionEnd>=this._text.length||this._moveCursorLeftOrRight("Right",e)},_moveCursorLeftOrRight:function(e,t){var i="moveCursor"+e+"With";this._currentCursorOpacity=1,t.shiftKey?i+="Shift":i+="outShift",this[i](t)&&(this.abortCursorAnimation(),this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorRightWithShift:function(e){return"left"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveRight(e,"selectionStart"):this.selectionEnd!==this._text.length?(this._selectionDirection="right",this._moveRight(e,"selectionEnd")):void 0},moveCursorRightWithoutShift:function(e){var t=!0;return this._selectionDirection="right",this.selectionStart===this.selectionEnd?(t=this._moveRight(e,"selectionStart"),this.selectionEnd=this.selectionStart):this.selectionStart=this.selectionEnd,t},removeChars:function(e,t){"undefined"===typeof t&&(t=e+1),this.removeStyleFromTo(e,t),this._text.splice(e,t-e),this.text=this._text.join(""),this.set("dirty",!0),this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords()),this._removeExtraneousStyles()},insertChars:function(e,t,i,s){"undefined"===typeof s&&(s=i),s>i&&this.removeStyleFromTo(i,s);var r=n.util.string.graphemeSplit(e);this.insertNewStyleBlock(r,i,t),this._text=[].concat(this._text.slice(0,i),r,this._text.slice(s)),this.text=this._text.join(""),this.set("dirty",!0),this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords()),this._removeExtraneousStyles()}}),function(){var e=n.util.toFixed,t=n.util.radiansToDegrees,i=n.util.calcRotateMatrix,s=n.util.transformPoint,r=/ +/g;n.util.object.extend(n.Text.prototype,{_toSVG:function(){var e=this._getSVGLeftTopOffsets(),t=this._getSVGTextAndBg(e.textTop,e.textLeft);return this._wrapSVGTextAndBg(t)},toSVG:function(e){var t=this._createBaseSVGMarkup(this._toSVG(),{reviver:e,noStyle:!0,withShadow:!0}),i=this.path;return i?t+i._createBaseSVGMarkup(i._toSVG(),{reviver:e,withShadow:!0}):t},_getSVGLeftTopOffsets:function(){return{textLeft:-this.width/2,textTop:-this.height/2,lineTop:this.getHeightOfLine(0)}},_wrapSVGTextAndBg:function(e){var t=this.getSvgTextDecoration(this);return[e.textBgRects.join(""),'\t\t",e.textSpans.join(""),"\n"]},_getSVGTextAndBg:function(e,t){var i,s=[],n=[],r=e;this._setSVGBg(n);for(var o=0,a=this._textLines.length;o",n.util.string.escapeXml(o),""].join("")},_setSVGTextLineText:function(e,t,i,s){var r,o,a,c,l,h=this.getHeightOfLine(t),d=-1!==this.textAlign.indexOf("justify"),u="",g=0,p=this._textLines[t];s+=h*(1-this._fontSizeFraction)/this.lineHeight;for(var m=0,f=p.length-1;m<=f;m++)l=m===f||this.charSpacing||this.path,u+=p[m],a=this.__charBounds[t][m],0===g?(i+=a.kernedWidth-a.width,g+=a.width):g+=a.kernedWidth,d&&!l&&this._reSpaceAndTab.test(p[m])&&(l=!0),l||(r=r||this.getCompleteStyleDeclaration(t,m),o=this.getCompleteStyleDeclaration(t,m+1),l=n.util.hasStyleChanged(r,o,!0)),l&&(c=this._getStyleDeclaration(t,m)||{},e.push(this._createTextCharSpan(u,c,i,s,a)),u="",r=o,i+=g,g=0)},_pushTextBgRect:function(t,i,s,r,o,a){var c=n.Object.NUM_FRACTION_DIGITS;t.push("\t\t\n')},_setSVGTextLineBg:function(e,t,i,s){for(var n,r,o=this._textLines[t],a=this.getHeightOfLine(t)/this.lineHeight,c=0,l=0,h=this.getValueOfPropertyAt(t,0,"textBackgroundColor"),d=0,u=o.length;dthis.width&&this._set("width",this.dynamicMinWidth),-1!==this.textAlign.indexOf("justify")&&this.enlargeSpaces(),this.height=this.calcTextHeight(),this.saveState({propertySet:"_dimensionAffectingProps"}))},_generateStyleMap:function(e){for(var t=0,i=0,s=0,n={},r=0;r0?(i=0,s++,t++):!this.splitByGrapheme&&this._reSpaceAndTab.test(e.graphemeText[s])&&r>0&&(i++,s++),n[r]={line:t,offset:i},s+=e.graphemeLines[r].length,i+=e.graphemeLines[r].length;return n},styleHas:function(e,i){if(this._styleMap&&!this.isWrapping){var s=this._styleMap[i];s&&(i=s.line)}return t.Text.prototype.styleHas.call(this,e,i)},isEmptyStyles:function(e){if(!this.styles)return!0;var t,i,s=0,n=!1,r=this._styleMap[e],o=this._styleMap[e+1];for(var a in r&&(e=r.line,s=r.offset),o&&(n=o.line===e,t=o.offset),i="undefined"===typeof e?this.styles:{line:this.styles[e]})for(var c in i[a])if(c>=s&&(!n||cs&&!f?(a.push(c),c=[],r=g,f=!0):r+=_,f||o||c.push(u),c=c.concat(h),p=o?0:this._measureWord([u],i,d),d++,f=!1,g>m&&(m=g);return v&&a.push(c),m+n>this.dynamicMinWidth&&(this.dynamicMinWidth=m-_+n),a},isEndOfWrapping:function(e){return!this._styleMap[e+1]||this._styleMap[e+1].line!==this._styleMap[e].line},missingNewlineOffset:function(e,t){return this.splitByGrapheme&&!t?this.isEndOfWrapping(e)?1:0:1},_splitTextIntoLines:function(e){for(var i=t.Text.prototype._splitTextIntoLines.call(this,e),s=this._wrapText(i.lines,this.width),n=new Array(s.length),r=0;r{"use strict";var s;i.d(t,{p:()=>s}),function(e){e[e.FILE=0]="FILE",e[e.FOLDER=1]="FOLDER",e[e.ROOT_FOLDER=2]="ROOT_FOLDER"}(s||(s={}))},7936:(e,t,i)=>{"use strict";i.d(t,{Y:()=>p});var s,n=i(91508),r=i(1245),o=i(36677),a=i(75326),c=i(63346),l=i(17469),h=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},d=function(e,t){return function(i,s){t(i,s,e)}};const u=Object.create(null);function g(e,t){if(t<=0)return"";u[e]||(u[e]=["",e]);const i=u[e];for(let s=i.length;s<=t;s++)i[s]=i[s-1]+e;return i[t]}let p=s=class{static unshiftIndent(e,t,i,s,n){const o=r.A.visibleColumnFromColumn(e,t,i);if(n){const e=g(" ",s);return g(e,r.A.prevIndentTabStop(o,s)/s)}return g("\t",r.A.prevRenderTabStop(o,i)/i)}static shiftIndent(e,t,i,s,n){const o=r.A.visibleColumnFromColumn(e,t,i);if(n){const e=g(" ",s);return g(e,r.A.nextIndentTabStop(o,s)/s)}return g("\t",r.A.nextRenderTabStop(o,i)/i)}constructor(e,t,i){this._languageConfigurationService=i,this._opts=t,this._selection=e,this._selectionId=null,this._useLastEditRangeForCursorEndPosition=!1,this._selectionStartColumnStaysPut=!1}_addEditOperation(e,t,i){this._useLastEditRangeForCursorEndPosition?e.addTrackedEditOperation(t,i):e.addEditOperation(t,i)}getEditOperations(e,t){const i=this._selection.startLineNumber;let a=this._selection.endLineNumber;1===this._selection.endColumn&&i!==a&&(a-=1);const{tabSize:l,indentSize:h,insertSpaces:d}=this._opts,u=i===a;if(this._opts.useTabStops){this._selection.isEmpty()&&/^\s*$/.test(e.getLineContent(i))&&(this._useLastEditRangeForCursorEndPosition=!0);let g=0,p=0;for(let m=i;m<=a;m++,g=p){p=0;const a=e.getLineContent(m);let f,_=n.HG(a);if((!this._opts.isUnshift||0!==a.length&&0!==_)&&(u||this._opts.isUnshift||0!==a.length)){if(-1===_&&(_=a.length),m>1){if(r.A.visibleColumnFromColumn(a,_+1,l)%h!==0&&e.tokenization.isCheapToTokenize(m-1)){const t=(0,c.h)(this._opts.autoIndent,e,new o.Q(m-1,e.getLineMaxColumn(m-1),m-1,e.getLineMaxColumn(m-1)),this._languageConfigurationService);if(t){if(p=g,t.appendText)for(let e=0,i=t.appendText.length;e{"use strict";i.d(t,{$:()=>Ue,BC:()=>Ie,BK:()=>j,Be:()=>F,Bx:()=>we,CE:()=>ze,Cl:()=>ee,Di:()=>Qe,Ej:()=>G,Er:()=>Se,Fv:()=>L,H4:()=>$,Hs:()=>Oe,Ij:()=>D,Iv:()=>w,L9:()=>H,Ln:()=>De,Mc:()=>et,OK:()=>Q,Oq:()=>M,PG:()=>P,Pl:()=>Ne,Q2:()=>b,QX:()=>X,TT:()=>$e,Tf:()=>je,Tr:()=>Y,U2:()=>_e,U3:()=>O,WU:()=>Be,Wt:()=>fe,X7:()=>se,XD:()=>Z,Xc:()=>I,ZF:()=>S,a:()=>re,a4:()=>qe,b2:()=>N,bo:()=>He,bq:()=>ie,cL:()=>z,fg:()=>V,fs:()=>Le,fz:()=>oe,gI:()=>Ye,h:()=>Je,i0:()=>Ge,jD:()=>We,jG:()=>te,jh:()=>ce,ko:()=>k,kx:()=>ye,li:()=>he,mU:()=>K,nR:()=>ne,nY:()=>Ee,pN:()=>Xe,q3:()=>R,sb:()=>Ce,sd:()=>Re,tG:()=>B,vT:()=>Ve,w5:()=>Ae,w_:()=>T,wk:()=>xe,xZ:()=>be,y6:()=>q,yt:()=>Ke,zK:()=>Te,zk:()=>_});var s=i(60413),n=i(55089),r=i(72962),o=i(47358),a=i(90766),c=i(64383),l=i(41234),h=i(83750),d=i(5662),u=i(36456),g=i(98067),p=i(85600),m=i(25893);const{registerWindow:f,getWindow:_,getDocument:v,getWindows:C,getWindowsCount:E,getWindowId:b,getWindowById:S,hasWindow:y,onDidRegisterWindow:w,onWillUnregisterWindow:R,onDidUnregisterWindow:L}=function(){const e=new Map;(0,m.y)(m.G,1);const t={window:m.G,disposables:new d.Cm};e.set(m.G.vscodeWindowId,t);const i=new l.vl,s=new l.vl,n=new l.vl;return{onDidRegisterWindow:i.event,onWillUnregisterWindow:n.event,onDidUnregisterWindow:s.event,registerWindow(t){if(e.has(t.vscodeWindowId))return d.jG.None;const r=new d.Cm,o={window:t,disposables:r.add(new d.Cm)};return e.set(t.vscodeWindowId,o),r.add((0,d.s)((()=>{e.delete(t.vscodeWindowId),s.fire(t)}))),r.add(k(t,we.BEFORE_UNLOAD,(()=>{n.fire(t)}))),i.fire(o),r},getWindows:()=>e.values(),getWindowsCount:()=>e.size,getWindowId:e=>e.vscodeWindowId,hasWindow:t=>e.has(t),getWindowById:function(i,s){return("number"===typeof i?e.get(i):void 0)??(s?t:void 0)},getWindow(e){const t=e;if(t?.ownerDocument?.defaultView)return t.ownerDocument.defaultView.window;const i=e;return i?.view?i.view.window:m.G},getDocument:e=>_(e).document}}();function T(e){for(;e.firstChild;)e.firstChild.remove()}class x{constructor(e,t,i,s){this._node=e,this._type=t,this._handler=i,this._options=s||!1,this._node.addEventListener(this._type,this._handler,this._options)}dispose(){this._handler&&(this._node.removeEventListener(this._type,this._handler,this._options),this._node=null,this._handler=null)}}function k(e,t,i,s){return new x(e,t,i,s)}function A(e,t){return function(i){return t(new o.P(e,i))}}const N=function(e,t,i,s){let n=i;return"click"===t||"mousedown"===t||"contextmenu"===t?n=A(_(e),i):"keydown"!==t&&"keypress"!==t&&"keyup"!==t||(n=function(e){return function(t){return e(new r.Z(t))}}(i)),k(e,t,n,s)},I=function(e,t,i){return function(e,t,i){return k(e,g.un&&n.e.pointerEvents?we.POINTER_DOWN:we.MOUSE_DOWN,t,i)}(e,A(_(e),t),i)};function O(e,t,i){return(0,a.b7)(e,t,i)}class D extends a.A0{constructor(e,t){super(e,t)}}let M,P;class F extends a.vb{constructor(e){super(),this.defaultTarget=e&&_(e)}cancelAndSet(e,t,i){return super.cancelAndSet(e,t,i??this.defaultTarget)}}class U{constructor(e,t=0){this._runner=e,this.priority=t,this._canceled=!1}dispose(){this._canceled=!0}execute(){if(!this._canceled)try{this._runner()}catch(e){(0,c.dz)(e)}}static sort(e,t){return t.priority-e.priority}}function H(e){return _(e).getComputedStyle(e,null)}function B(e,t){const i=_(e),s=i.document;if(e!==s.body)return new V(e.clientWidth,e.clientHeight);if(g.un&&i?.visualViewport)return new V(i.visualViewport.width,i.visualViewport.height);if(i?.innerWidth&&i.innerHeight)return new V(i.innerWidth,i.innerHeight);if(s.body&&s.body.clientWidth&&s.body.clientHeight)return new V(s.body.clientWidth,s.body.clientHeight);if(s.documentElement&&s.documentElement.clientWidth&&s.documentElement.clientHeight)return new V(s.documentElement.clientWidth,s.documentElement.clientHeight);if(t)return B(t);throw new Error("Unable to figure out browser width and height")}!function(){const e=new Map,t=new Map,i=new Map,s=new Map;P=(n,r,o=0)=>{const a=b(n),c=new U(r,o);let l=e.get(a);return l||(l=[],e.set(a,l)),l.push(c),i.get(a)||(i.set(a,!0),n.requestAnimationFrame((()=>(n=>{i.set(n,!1);const r=e.get(n)??[];for(t.set(n,r),e.set(n,[]),s.set(n,!0);r.length>0;)r.sort(U.sort),r.shift().execute();s.set(n,!1)})(a)))),c},M=(e,i,n)=>{const r=b(e);if(s.get(r)){const e=new U(i,n);let s=t.get(r);return s||(s=[],t.set(r,s)),s.push(e),e}return P(e,i,n)}}();class W{static convertToPixels(e,t){return parseFloat(t)||0}static getDimension(e,t,i){const s=H(e),n=s?s.getPropertyValue(t):"0";return W.convertToPixels(e,n)}static getBorderLeftWidth(e){return W.getDimension(e,"border-left-width","borderLeftWidth")}static getBorderRightWidth(e){return W.getDimension(e,"border-right-width","borderRightWidth")}static getBorderTopWidth(e){return W.getDimension(e,"border-top-width","borderTopWidth")}static getBorderBottomWidth(e){return W.getDimension(e,"border-bottom-width","borderBottomWidth")}static getPaddingLeft(e){return W.getDimension(e,"padding-left","paddingLeft")}static getPaddingRight(e){return W.getDimension(e,"padding-right","paddingRight")}static getPaddingTop(e){return W.getDimension(e,"padding-top","paddingTop")}static getPaddingBottom(e){return W.getDimension(e,"padding-bottom","paddingBottom")}static getMarginLeft(e){return W.getDimension(e,"margin-left","marginLeft")}static getMarginTop(e){return W.getDimension(e,"margin-top","marginTop")}static getMarginRight(e){return W.getDimension(e,"margin-right","marginRight")}static getMarginBottom(e){return W.getDimension(e,"margin-bottom","marginBottom")}}class V{static{this.None=new V(0,0)}constructor(e,t){this.width=e,this.height=t}with(e=this.width,t=this.height){return e!==this.width||t!==this.height?new V(e,t):this}static is(e){return"object"===typeof e&&"number"===typeof e.height&&"number"===typeof e.width}static lift(e){return e instanceof V?e:new V(e.width,e.height)}static equals(e,t){return e===t||!(!e||!t)&&(e.width===t.width&&e.height===t.height)}}function z(e){let t=e.offsetParent,i=e.offsetTop,s=e.offsetLeft;for(;null!==(e=e.parentNode)&&e!==e.ownerDocument.body&&e!==e.ownerDocument.documentElement;){i-=e.scrollTop;const n=J(e)?null:H(e);n&&(s-="rtl"!==n.direction?e.scrollLeft:-e.scrollLeft),e===t&&(s+=W.getBorderLeftWidth(e),i+=W.getBorderTopWidth(e),i+=e.offsetTop,s+=e.offsetLeft,t=e.offsetParent)}return{left:s,top:i}}function G(e,t,i){"number"===typeof t&&(e.style.width=`${t}px`),"number"===typeof i&&(e.style.height=`${i}px`)}function j(e){const t=e.getBoundingClientRect(),i=_(e);return{left:t.left+i.scrollX,top:t.top+i.scrollY,width:t.width,height:t.height}}function K(e){let t=e,i=1;do{const e=H(t).zoom;null!==e&&void 0!==e&&"1"!==e&&(i*=e),t=t.parentElement}while(null!==t&&t!==t.ownerDocument.documentElement);return i}function Y(e){const t=W.getMarginLeft(e)+W.getMarginRight(e);return e.offsetWidth+t}function q(e){const t=W.getBorderLeftWidth(e)+W.getBorderRightWidth(e),i=W.getPaddingLeft(e)+W.getPaddingRight(e);return e.offsetWidth-t-i}function $(e){const t=W.getBorderTopWidth(e)+W.getBorderBottomWidth(e),i=W.getPaddingTop(e)+W.getPaddingBottom(e);return e.offsetHeight-t-i}function Q(e){const t=W.getMarginTop(e)+W.getMarginBottom(e);return e.offsetHeight+t}function X(e,t){return Boolean(t?.contains(e))}function Z(e,t,i){return!!function(e,t,i){for(;e&&e.nodeType===e.ELEMENT_NODE;){if(e.classList.contains(t))return e;if(i)if("string"===typeof i){if(e.classList.contains(i))return null}else if(e===i)return null;e=e.parentNode}return null}(e,t,i)}function J(e){return e&&!!e.host&&!!e.mode}function ee(e){return!!te(e)}function te(e){for(;e.parentNode;){if(e===e.ownerDocument?.body)return null;e=e.parentNode}return J(e)?e:null}function ie(){let e=re().activeElement;for(;e?.shadowRoot;)e=e.shadowRoot.activeElement;return e}function se(e){return ie()===e}function ne(e){return X(ie(),e)}function re(){if(E()<=1)return m.G.document;return Array.from(C()).map((({window:e})=>e.document)).find((e=>e.hasFocus()))??m.G.document}function oe(){const e=re();return e.defaultView?.window??m.G}const ae=new Map;function ce(){return new le}class le{constructor(){this._currentCssStyle="",this._styleSheet=void 0}setStyle(e){e!==this._currentCssStyle&&(this._currentCssStyle=e,this._styleSheet?this._styleSheet.innerText=e:this._styleSheet=he(m.G.document.head,(t=>t.innerText=e)))}dispose(){this._styleSheet&&(this._styleSheet.remove(),this._styleSheet=void 0)}}function he(e=m.G.document.head,t,i){const s=document.createElement("style");if(s.type="text/css",s.media="screen",t?.(s),e.appendChild(s),i&&i.add((0,d.s)((()=>s.remove()))),e===m.G.document.head){const e=new Set;ae.set(s,e);for(const{window:t,disposables:n}of C()){if(t===m.G)continue;const r=n.add(de(s,e,t));i?.add(r)}}return s}function de(e,t,i){const s=new d.Cm,n=e.cloneNode(!0);i.document.head.appendChild(n),s.add((0,d.s)((()=>n.remove())));for(const r of me(e))n.sheet?.insertRule(r.cssText,n.sheet?.cssRules.length);return s.add(ue.observe(e,s,{childList:!0})((()=>{n.textContent=e.textContent}))),t.add(n),s.add((0,d.s)((()=>t.delete(n)))),s}const ue=new class{constructor(){this.mutationObservers=new Map}observe(e,t,i){let s=this.mutationObservers.get(e);s||(s=new Map,this.mutationObservers.set(e,s));const n=(0,p.tW)(i);let r=s.get(n);if(r)r.users+=1;else{const o=new l.vl,a=new MutationObserver((e=>o.fire(e)));a.observe(e,i);const c=r={users:1,observer:a,onDidMutate:o.event};t.add((0,d.s)((()=>{c.users-=1,0===c.users&&(o.dispose(),a.disconnect(),s?.delete(n),0===s?.size&&this.mutationObservers.delete(e))}))),s.set(n,r)}return r.onDidMutate}};let ge=null;function pe(){return ge||(ge=he()),ge}function me(e){return e?.sheet?.rules?e.sheet.rules:e?.sheet?.cssRules?e.sheet.cssRules:[]}function fe(e,t,i=pe()){if(i&&t){i.sheet?.insertRule(`${e} {${t}}`,0);for(const s of ae.get(i)??[])fe(e,t,s)}}function _e(e,t=pe()){if(!t)return;const i=me(t),s=[];for(let n=0;n=0;n--)t.sheet?.deleteRule(s[n]);for(const n of ae.get(t)??[])_e(e,n)}function ve(e){return"string"===typeof e.selectorText}function Ce(e){return e instanceof HTMLElement||e instanceof _(e).HTMLElement}function Ee(e){return e instanceof HTMLAnchorElement||e instanceof _(e).HTMLAnchorElement}function be(e){return e instanceof SVGElement||e instanceof _(e).SVGElement}function Se(e){return e instanceof MouseEvent||e instanceof _(e).MouseEvent}function ye(e){return e instanceof KeyboardEvent||e instanceof _(e).KeyboardEvent}const we={CLICK:"click",AUXCLICK:"auxclick",DBLCLICK:"dblclick",MOUSE_UP:"mouseup",MOUSE_DOWN:"mousedown",MOUSE_OVER:"mouseover",MOUSE_MOVE:"mousemove",MOUSE_OUT:"mouseout",MOUSE_ENTER:"mouseenter",MOUSE_LEAVE:"mouseleave",MOUSE_WHEEL:"wheel",POINTER_UP:"pointerup",POINTER_DOWN:"pointerdown",POINTER_MOVE:"pointermove",POINTER_LEAVE:"pointerleave",CONTEXT_MENU:"contextmenu",WHEEL:"wheel",KEY_DOWN:"keydown",KEY_PRESS:"keypress",KEY_UP:"keyup",LOAD:"load",BEFORE_UNLOAD:"beforeunload",UNLOAD:"unload",PAGE_SHOW:"pageshow",PAGE_HIDE:"pagehide",PASTE:"paste",ABORT:"abort",ERROR:"error",RESIZE:"resize",SCROLL:"scroll",FULLSCREEN_CHANGE:"fullscreenchange",WK_FULLSCREEN_CHANGE:"webkitfullscreenchange",SELECT:"select",CHANGE:"change",SUBMIT:"submit",RESET:"reset",FOCUS:"focus",FOCUS_IN:"focusin",FOCUS_OUT:"focusout",BLUR:"blur",INPUT:"input",STORAGE:"storage",DRAG_START:"dragstart",DRAG:"drag",DRAG_ENTER:"dragenter",DRAG_LEAVE:"dragleave",DRAG_OVER:"dragover",DROP:"drop",DRAG_END:"dragend",ANIMATION_START:s.Tc?"webkitAnimationStart":"animationstart",ANIMATION_END:s.Tc?"webkitAnimationEnd":"animationend",ANIMATION_ITERATION:s.Tc?"webkitAnimationIteration":"animationiteration"};function Re(e){const t=e;return!(!t||"function"!==typeof t.preventDefault||"function"!==typeof t.stopPropagation)}const Le={stop:(e,t)=>(e.preventDefault(),t&&e.stopPropagation(),e)};function Te(e){const t=[];for(let i=0;e&&e.nodeType===e.ELEMENT_NODE;i++)t[i]=e.scrollTop,e=e.parentNode;return t}function xe(e,t){for(let i=0;e&&e.nodeType===e.ELEMENT_NODE;i++)e.scrollTop!==t[i]&&(e.scrollTop=t[i]),e=e.parentNode}class ke extends d.jG{static hasFocusWithin(e){if(Ce(e)){const t=te(e);return X(t?t.activeElement:e.ownerDocument.activeElement,e)}{const t=e;return X(t.document.activeElement,t.document)}}constructor(e){super(),this._onDidFocus=this._register(new l.vl),this.onDidFocus=this._onDidFocus.event,this._onDidBlur=this._register(new l.vl),this.onDidBlur=this._onDidBlur.event;let t=ke.hasFocusWithin(e),i=!1;const s=()=>{i=!1,t||(t=!0,this._onDidFocus.fire())},n=()=>{t&&(i=!0,(Ce(e)?_(e):e).setTimeout((()=>{i&&(i=!1,t=!1,this._onDidBlur.fire())}),0))};this._refreshStateHandler=()=>{ke.hasFocusWithin(e)!==t&&(t?n():s())},this._register(k(e,we.FOCUS,s,!0)),this._register(k(e,we.BLUR,n,!0)),Ce(e)&&(this._register(k(e,we.FOCUS_IN,(()=>this._refreshStateHandler()))),this._register(k(e,we.FOCUS_OUT,(()=>this._refreshStateHandler()))))}}function Ae(e){return new ke(e)}function Ne(e,t){return e.after(t),t}function Ie(e,...t){if(e.append(...t),1===t.length&&"string"!==typeof t[0])return t[0]}function Oe(e,t){return e.insertBefore(t,e.firstChild),t}function De(e,...t){e.innerText="",Ie(e,...t)}const Me=/([\w\-]+)?(#([\w\-]+))?((\.([\w\-]+))*)/;var Pe;function Fe(e,t,i,...s){const n=Me.exec(t);if(!n)throw new Error("Bad use of emmet");const r=n[1]||"div";let o;return o=e!==Pe.HTML?document.createElementNS(e,r):document.createElement(r),n[3]&&(o.id=n[3]),n[4]&&(o.className=n[4].replace(/\./g," ").trim()),i&&Object.entries(i).forEach((([e,t])=>{"undefined"!==typeof t&&(/^on\w+$/.test(e)?o[e]=t:"selected"===e?t&&o.setAttribute(e,"true"):o.setAttribute(e,t))})),o.append(...s),o}function Ue(e,t,...i){return Fe(Pe.HTML,e,t,...i)}function He(e,...t){e?Be(...t):We(...t)}function Be(...e){for(const t of e)t.style.display="",t.removeAttribute("aria-hidden")}function We(...e){for(const t of e)t.style.display="none",t.setAttribute("aria-hidden","true")}function Ve(e,t){const i=e.devicePixelRatio*t;return Math.max(1,Math.floor(i))/e.devicePixelRatio}function ze(e){m.G.open(e,"_blank","noopener")}function Ge(e,t){const i=()=>{t(),s=P(e,i)};let s=P(e,i);return(0,d.s)((()=>s.dispose()))}function je(e){return e?`url('${u.zl.uriToBrowserUri(e).toString(!0).replace(/'/g,"%27")}')`:"url('')"}function Ke(e){return`'${e.replace(/'/g,"%27")}'`}function Ye(e,t){if(void 0!==e){const i=e.match(/^\s*var\((.+)\)$/);if(i){const e=i[1].split(",",2);return 2===e.length&&(t=Ye(e[1].trim(),t)),`var(${e[0]}, ${t})`}return e}return t}function qe(e,t=!1){const i=document.createElement("a");return h.$w("afterSanitizeAttributes",(s=>{for(const n of["href","src"])if(s.hasAttribute(n)){const r=s.getAttribute(n);if("href"===n&&r.startsWith("#"))continue;if(i.href=r,!e.includes(i.protocol.replace(/:$/,""))){if(t&&"src"===n&&i.href.startsWith("data:"))continue;s.removeAttribute(n)}}})),(0,d.s)((()=>{h.SV("afterSanitizeAttributes")}))}!function(e){e.HTML="http://www.w3.org/1999/xhtml",e.SVG="http://www.w3.org/2000/svg"}(Pe||(Pe={})),Ue.SVG=function(e,t,...i){return Fe(Pe.SVG,e,t,...i)},u.Ez.setPreferredWebSchema(/^https:/.test(m.G.location.href)?"https":"http");const $e=Object.freeze(["a","abbr","b","bdo","blockquote","br","caption","cite","code","col","colgroup","dd","del","details","dfn","div","dl","dt","em","figcaption","figure","h1","h2","h3","h4","h5","h6","hr","i","img","input","ins","kbd","label","li","mark","ol","p","pre","q","rp","rt","ruby","samp","small","small","source","span","strike","strong","sub","summary","sup","table","tbody","td","tfoot","th","thead","time","tr","tt","u","ul","var","video","wbr"]);Object.freeze({ALLOWED_TAGS:["a","button","blockquote","code","div","h1","h2","h3","h4","h5","h6","hr","input","label","li","p","pre","select","small","span","strong","textarea","ul","ol"],ALLOWED_ATTR:["href","data-href","data-command","target","title","name","src","alt","class","id","role","tabindex","style","data-code","width","height","align","x-dispatch","required","checked","placeholder","type","start"],RETURN_DOM:!1,RETURN_DOM_FRAGMENT:!1,RETURN_TRUSTED_TYPE:!0});class Qe extends l.vl{constructor(){super(),this._subscriptions=new d.Cm,this._keyStatus={altKey:!1,shiftKey:!1,ctrlKey:!1,metaKey:!1},this._subscriptions.add(l.Jh.runAndSubscribe(w,(({window:e,disposables:t})=>this.registerListeners(e,t)),{window:m.G,disposables:this._subscriptions}))}registerListeners(e,t){t.add(k(e,"keydown",(e=>{if(e.defaultPrevented)return;const t=new r.Z(e);if(6!==t.keyCode||!e.repeat){if(e.altKey&&!this._keyStatus.altKey)this._keyStatus.lastKeyPressed="alt";else if(e.ctrlKey&&!this._keyStatus.ctrlKey)this._keyStatus.lastKeyPressed="ctrl";else if(e.metaKey&&!this._keyStatus.metaKey)this._keyStatus.lastKeyPressed="meta";else if(e.shiftKey&&!this._keyStatus.shiftKey)this._keyStatus.lastKeyPressed="shift";else{if(6===t.keyCode)return;this._keyStatus.lastKeyPressed=void 0}this._keyStatus.altKey=e.altKey,this._keyStatus.ctrlKey=e.ctrlKey,this._keyStatus.metaKey=e.metaKey,this._keyStatus.shiftKey=e.shiftKey,this._keyStatus.lastKeyPressed&&(this._keyStatus.event=e,this.fire(this._keyStatus))}}),!0)),t.add(k(e,"keyup",(e=>{e.defaultPrevented||(!e.altKey&&this._keyStatus.altKey?this._keyStatus.lastKeyReleased="alt":!e.ctrlKey&&this._keyStatus.ctrlKey?this._keyStatus.lastKeyReleased="ctrl":!e.metaKey&&this._keyStatus.metaKey?this._keyStatus.lastKeyReleased="meta":!e.shiftKey&&this._keyStatus.shiftKey?this._keyStatus.lastKeyReleased="shift":this._keyStatus.lastKeyReleased=void 0,this._keyStatus.lastKeyPressed!==this._keyStatus.lastKeyReleased&&(this._keyStatus.lastKeyPressed=void 0),this._keyStatus.altKey=e.altKey,this._keyStatus.ctrlKey=e.ctrlKey,this._keyStatus.metaKey=e.metaKey,this._keyStatus.shiftKey=e.shiftKey,this._keyStatus.lastKeyReleased&&(this._keyStatus.event=e,this.fire(this._keyStatus)))}),!0)),t.add(k(e.document.body,"mousedown",(()=>{this._keyStatus.lastKeyPressed=void 0}),!0)),t.add(k(e.document.body,"mouseup",(()=>{this._keyStatus.lastKeyPressed=void 0}),!0)),t.add(k(e.document.body,"mousemove",(e=>{e.buttons&&(this._keyStatus.lastKeyPressed=void 0)}),!0)),t.add(k(e,"blur",(()=>{this.resetKeyStatus()})))}get keyStatus(){return this._keyStatus}resetKeyStatus(){this.doResetKeyStatus(),this.fire(this._keyStatus)}doResetKeyStatus(){this._keyStatus={altKey:!1,shiftKey:!1,ctrlKey:!1,metaKey:!1}}static getInstance(){return Qe.instance||(Qe.instance=new Qe),Qe.instance}dispose(){super.dispose(),this._subscriptions.dispose()}}class Xe extends d.jG{constructor(e,t){super(),this.element=e,this.callbacks=t,this.counter=0,this.dragStartTime=0,this.registerListeners()}registerListeners(){this.callbacks.onDragStart&&this._register(k(this.element,we.DRAG_START,(e=>{this.callbacks.onDragStart?.(e)}))),this.callbacks.onDrag&&this._register(k(this.element,we.DRAG,(e=>{this.callbacks.onDrag?.(e)}))),this._register(k(this.element,we.DRAG_ENTER,(e=>{this.counter++,this.dragStartTime=e.timeStamp,this.callbacks.onDragEnter?.(e)}))),this._register(k(this.element,we.DRAG_OVER,(e=>{e.preventDefault(),this.callbacks.onDragOver?.(e,e.timeStamp-this.dragStartTime)}))),this._register(k(this.element,we.DRAG_LEAVE,(e=>{this.counter--,0===this.counter&&(this.dragStartTime=0,this.callbacks.onDragLeave?.(e))}))),this._register(k(this.element,we.DRAG_END,(e=>{this.counter=0,this.dragStartTime=0,this.callbacks.onDragEnd?.(e)}))),this._register(k(this.element,we.DROP,(e=>{this.counter=0,this.dragStartTime=0,this.callbacks.onDrop?.(e)})))}}const Ze=/(?[\w\-]+)?(?:#(?[\w\-]+))?(?(?:\.(?:[\w\-]+))*)(?:@(?(?:[\w\_])+))?/;function Je(e,...t){let i,s;Array.isArray(t[0])?(i={},s=t[0]):(i=t[0]||{},s=t[1]);const n=Ze.exec(e);if(!n||!n.groups)throw new Error("Bad use of h");const r=n.groups.tag||"div",o=document.createElement(r);n.groups.id&&(o.id=n.groups.id);const a=[];if(n.groups.class)for(const l of n.groups.class.split("."))""!==l&&a.push(l);if(void 0!==i.className)for(const l of i.className.split("."))""!==l&&a.push(l);a.length>0&&(o.className=a.join(" "));const c={};if(n.groups.name&&(c[n.groups.name]=o),s)for(const l of s)Ce(l)?o.appendChild(l):"string"===typeof l?o.append(l):"root"in l&&(Object.assign(c,l),o.appendChild(l.root));for(const[l,h]of Object.entries(i))if("className"!==l)if("style"===l)for(const[e,t]of Object.entries(h))o.style.setProperty(tt(e),"number"===typeof t?t+"px":""+t);else"tabIndex"===l?o.tabIndex=h:o.setAttribute(tt(l),h.toString());return c.root=o,c}function et(e,...t){let i,s;Array.isArray(t[0])?(i={},s=t[0]):(i=t[0]||{},s=t[1]);const n=Ze.exec(e);if(!n||!n.groups)throw new Error("Bad use of h");const r=n.groups.tag||"div",o=document.createElementNS("http://www.w3.org/2000/svg",r);n.groups.id&&(o.id=n.groups.id);const a=[];if(n.groups.class)for(const l of n.groups.class.split("."))""!==l&&a.push(l);if(void 0!==i.className)for(const l of i.className.split("."))""!==l&&a.push(l);a.length>0&&(o.className=a.join(" "));const c={};if(n.groups.name&&(c[n.groups.name]=o),s)for(const l of s)Ce(l)?o.appendChild(l):"string"===typeof l?o.append(l):"root"in l&&(Object.assign(c,l),o.appendChild(l.root));for(const[l,h]of Object.entries(i))if("className"!==l)if("style"===l)for(const[e,t]of Object.entries(h))o.style.setProperty(tt(e),"number"===typeof t?t+"px":""+t);else"tabIndex"===l?o.tabIndex=h:o.setAttribute(tt(l),h.toString());return c.root=o,c}function tt(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}},8603:(e,t,i)=>{e.exports=function(e){const t=i(94297),s=i(83823)(e);return function(e,i,n){let r="";const o=e.$value,a=o.length;return t.drawFullView(a,i)?(r+=t.OBJECT_START+t.getIndent(i,n),r+=s(o,i,n),r+=t.getIndent(i,n-1)+t.OBJECT_END):t.drawCompactView(a,i)?(r+=t.OBJECT_START,r+=s(o,i,n-1),r+=t.OBJECT_END):r+=t.OBJECT_START+t.OBJECT_END,r}}},8868:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"msdax",extensions:[".dax",".msdax"],aliases:["DAX","MSDAX"],loader:()=>i.e(2994).then(i.bind(i,2994))})},8964:(e,t,i)=>{"use strict";i.d(t,{R:()=>a,J:()=>o});var s=i(1448);const n=JSON.parse('{"common":{"tooltip-sum":"Sum","tooltip-rest":"Rest"},"chartkit":{"error":"Error","legend-series-hide":"Hide all lines","legend-series-show":"Show all lines","tooltip-point-format-size":"Size","tooltip-sum":"Sum","tooltip-rest":"Rest","error-incorrect-key-value-intro":"Incorrect notation of an object passed to","error-incorrect-key":", object keys must be convertible to integer","error-incorrect-value":", object values must be a string or a function which returns a string"},"chartkit-table":{"message-no-data":"No data","paginator-rows":"Rows"},"chartkit-ymap-legend":{"label-more":"Show more {{count}}","label-hide":"Hide","label-heatmap":"Heatmap"},"error":{"label_no-data":"No data","label_unknown-plugin":"Unknown plugin type \\"{{type}}\\"","label_unknown-error":"Unknown error","label_invalid-axis-category-data-point":"It seems you are trying to use inappropriate data type for \\"{{key}}\\" value in series \\"{{seriesName}}\\" for axis with type \\"category\\". Strings and numbers are allowed.","label_invalid-axis-datetime-data-point":"It seems you are trying to use inappropriate data type for \\"{{key}}\\" value in series \\"{{seriesName}}\\" for axis with type \\"datetime\\". Only numbers are allowed.","label_invalid-axis-linear-data-point":"It seems you are trying to use inappropriate data type for \\"{{key}}\\" value in series \\"{{seriesName}}\\" for axis with type \\"linear\\". Numbers and nulls are allowed.","label_invalid-pie-data-value":"It seems you are trying to use inappropriate data type for \\"value\\" value. Only numbers are allowed.","label_invalid-series-type":"It seems you haven\'t defined \\"series.type\\" property, or defined it incorrectly. Available values: [{{types}}].","label_invalid-series-property":"It seems you are trying to use inappropriate value for \\"{{key}}\\", or defined it incorrectly. Available values: [{{values}}].","label_invalid-treemap-redundant-value":"It seems you are trying to set \\"value\\" for container node. Check node with this properties: { id: \\"{{id}}\\", name: \\"{{name}}\\" }","label_invalid-treemap-missing-value":"It seems you are trying to use node without \\"value\\". Check node with this properties: { id: \\"{{id}}\\", name: \\"{{name}}\\" }","label_invalid-y-axis-index":"It seems you are trying to use inappropriate index for Y axis: \\"{{index}}\\""},"highcharts":{"reset-zoom-title":"Reset zoom","decimal-point":".","thousands-sep":" ","Mon":"Mon","Tue":"Tue","Wed":"Wed","Thu":"Thu","Fri":"Fri","Sat":"Sat","Sun":"Sun","Jan":"Jan","January":"January","Feb":"Feb","February":"February","Mar":"Mar","March":"March","Apr":"Apr","April":"April","May":"May","Jun":"Jun","June":"June","Jul":"Jul","July":"July","Aug":"Aug","August":"August","Sep":"Sep","September":"September","Oct":"Oct","October":"October","Nov":"Nov","November":"November","Dec":"Dec","December":"December"}}'),r=JSON.parse('{"common":{"tooltip-sum":"\u0421\u0443\u043c\u043c\u0430","tooltip-rest":"\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435"},"chartkit":{"error":"\u041e\u0448\u0438\u0431\u043a\u0430","legend-series-hide":"\u0421\u043a\u0440\u044b\u0442\u044c \u0432\u0441\u0435 \u043b\u0438\u043d\u0438\u0438","legend-series-show":"\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0441\u0435 \u043b\u0438\u043d\u0438\u0438","loading":"\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430","tooltip-point-format-size":"\u0420\u0430\u0437\u043c\u0435\u0440","tooltip-sum":"\u0421\u0443\u043c\u043c\u0430","tooltip-rest":"\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435","error-incorrect-key-value-intro":"\u041d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u0430\u043a \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432","error-incorrect-key":", \u043a\u043b\u044e\u0447\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c\u044b \u0432 \u0446\u0435\u043b\u043e\u0435 \u0447\u0438\u0441\u043b\u043e","error-incorrect-value":", \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u0438\u0431\u043e \u0441\u0442\u0440\u043e\u043a\u0430, \u043b\u0438\u0431\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0443"},"chartkit-table":{"message-no-data":"\u041d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445","paginator-rows":"\u0421\u0442\u0440\u043e\u043a\u0438"},"chartkit-ymap-legend":{"label-more":"\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0435\u0449\u0451 {{count}}","label-hide":"\u0421\u0432\u0435\u0440\u043d\u0443\u0442\u044c","label-heatmap":"\u0422\u0435\u043f\u043b\u043e\u0432\u0430\u044f \u043a\u0430\u0440\u0442\u0430"},"error":{"label_no-data":"\u041d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445","label_unknown-plugin":"\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439 \u0442\u0438\u043f \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \\"{{type}}\\"","label_unknown-error":"\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430","label_invalid-axis-category-data-point":"\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \\"{{key}}\\" \u0432 \u0441\u0435\u0440\u0438\u0438 \\"{{seriesName}}\\" \u0434\u043b\u044f \u043e\u0441\u0438 \u0441 \u0442\u0438\u043f\u043e\u043c \\"category\\". \u0414\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u043e\u043a \u0438 \u0447\u0438\u0441\u0435\u043b.","label_invalid-axis-datetime-data-point":"\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \\"{{key}}\\" \u0432 \u0441\u0435\u0440\u0438\u0438 \\"{{seriesName}}\\" \u0434\u043b\u044f \u043e\u0441\u0438 \u0441 \u0442\u0438\u043f\u043e\u043c \\"datetime\\". \u0414\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0447\u0438\u0441\u0435\u043b.","label_invalid-axis-linear-data-point":"\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \\"{{key}}\\" \u0432 \u0441\u0435\u0440\u0438\u0438 \\"{{seriesName}}\\" \u0434\u043b\u044f \u043e\u0441\u0438 \u0441 \u0442\u0438\u043f\u043e\u043c \\"linear\\". \u0414\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0447\u0438\u0441\u0435\u043b \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 null.","label_invalid-pie-data-value":"\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \\"value\\". \u0414\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0447\u0438\u0441\u0435\u043b.","label_invalid-series-type":"\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u0432\u044b \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \\"series.type\\" \u0438\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0432\u0435\u0440\u043d\u043e. \u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f: [{{types}}].","label_invalid-series-property":"\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \\"{{key}}\\", \u0438\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0432\u0435\u0440\u043d\u043e. \u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f: [{{values}}].","label_invalid-treemap-redundant-value":"\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \\"value\\" \u0434\u043b\u044f \u0443\u0437\u043b\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0433\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0443\u0437\u0435\u043b \u0441 \u044d\u0442\u0438\u043c\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438: { id: \\"{{id}}\\", name: \\"{{name}}\\" }","label_invalid-treemap-missing-value":"\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0437\u0435\u043b \u0431\u0435\u0437 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \\"value\\". \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0443\u0437\u0435\u043b \u0441 \u044d\u0442\u0438\u043c\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438: { id: \\"{{id}}\\", name: \\"{{name}}\\" }","label_invalid-y-axis-index":"\u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441 \u0434\u043b\u044f \u043e\u0441\u0438 Y: \\"{{index}}\\""},"highcharts":{"reset-zoom-title":"\u0421\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0435","decimal-point":",","thousands-sep":" ","Mon":"\u041f\u043d","Tue":"\u0412\u0442","Wed":"\u0421\u0440","Thu":"\u0427\u0442","Fri":"\u041f\u0442","Sat":"\u0421\u0431","Sun":"\u0412\u0441","Jan":"\u042f\u043d\u0432","January":"\u042f\u043d\u0432\u0430\u0440\u044c","Feb":"\u0424\u0435\u0432","February":"\u0424\u0435\u0432\u0440\u0430\u043b\u044c","Mar":"\u041c\u0430\u0440","March":"\u041c\u0430\u0440\u0442","Apr":"\u0410\u043f\u0440","April":"\u0410\u043f\u0440\u0435\u043b\u044c","May":"\u041c\u0430\u0439","Jun":"\u0418\u044e\u043d","June":"\u0418\u044e\u043d\u044c","Jul":"\u0418\u044e\u043b","July":"\u0418\u044e\u043b\u044c","Aug":"\u0410\u0432\u0433","August":"\u0410\u0432\u0433\u0443\u0441\u0442","Sep":"\u0421\u0435\u043d","September":"\u0421\u0435\u043d\u0442\u044f\u0431\u0440\u044c","Oct":"\u041e\u043a\u0442","October":"\u041e\u043a\u0442\u044f\u0431\u0440\u044c","Nov":"\u041d\u043e\u044f","November":"\u041d\u043e\u044f\u0431\u0440\u044c","Dec":"\u0414\u0435\u043a","December":"\u0414\u0435\u043a\u0430\u0431\u0440\u044c"}}'),o=new s.TH;o.registerKeysets("en",n),o.registerKeysets("ru",r);const a=o.i18n.bind(o)},8995:(e,t,i)=>{"use strict";i.d(t,{k:()=>s});class s{static{this.sep="."}static{this.None=new s("@@none@@")}static{this.Empty=new s("")}constructor(e){this.value=e}equals(e){return this.value===e.value}contains(e){return this.equals(e)||""===this.value||e.value.startsWith(this.value+s.sep)}intersects(e){return this.contains(e)||e.contains(this)}append(...e){return new s((this.value?[this.value,...e]:e).join(s.sep))}}},9208:(e,t,i)=>{e.exports=i(8603)},9270:(e,t,i)=>{"use strict";i.d(t,{L:()=>h});var s=i(8597),n=i(52776),r=i(5662),o=i(98031),a=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},c=function(e,t){return function(i,s){t(i,s,e)}};const l=s.$;let h=class extends r.jG{get hasContent(){return this._hasContent}constructor(e){super(),this._keybindingService=e,this.actions=[],this._hasContent=!1,this.hoverElement=l("div.hover-row.status-bar"),this.hoverElement.tabIndex=0,this.actionsElement=s.BC(this.hoverElement,l("div.actions"))}addAction(e){const t=this._keybindingService.lookupKeybinding(e.commandId),i=t?t.getLabel():null;this._hasContent=!0;const s=this._register(n.jQ.render(this.actionsElement,e,i));return this.actions.push(s),s}append(e){const t=s.BC(this.actionsElement,e);return this._hasContent=!0,t}};h=a([c(0,o.b)],h)},9711:(e,t,i)=>{"use strict";i.d(t,{CS:()=>p,pc:()=>_,LP:()=>m});var s,n,r=i(41234),o=i(5662),a=i(631),c=i(90766),l=i(908);!function(e){e[e.STORAGE_DOES_NOT_EXIST=0]="STORAGE_DOES_NOT_EXIST",e[e.STORAGE_IN_MEMORY=1]="STORAGE_IN_MEMORY"}(s||(s={})),function(e){e[e.None=0]="None",e[e.Initialized=1]="Initialized",e[e.Closed=2]="Closed"}(n||(n={}));class h extends o.jG{static{this.DEFAULT_FLUSH_DELAY=100}constructor(e,t=Object.create(null)){super(),this.database=e,this.options=t,this._onDidChangeStorage=this._register(new r.fV),this.onDidChangeStorage=this._onDidChangeStorage.event,this.state=n.None,this.cache=new Map,this.flushDelayer=this._register(new c.Th(h.DEFAULT_FLUSH_DELAY)),this.pendingDeletes=new Set,this.pendingInserts=new Map,this.whenFlushedCallbacks=[],this.registerListeners()}registerListeners(){this._register(this.database.onDidChangeItemsExternal((e=>this.onDidChangeItemsExternal(e))))}onDidChangeItemsExternal(e){this._onDidChangeStorage.pause();try{e.changed?.forEach(((e,t)=>this.acceptExternal(t,e))),e.deleted?.forEach((e=>this.acceptExternal(e,void 0)))}finally{this._onDidChangeStorage.resume()}}acceptExternal(e,t){if(this.state===n.Closed)return;let i=!1;if((0,a.z)(t))i=this.cache.delete(e);else{this.cache.get(e)!==t&&(this.cache.set(e,t),i=!0)}i&&this._onDidChangeStorage.fire({key:e,external:!0})}get(e,t){const i=this.cache.get(e);return(0,a.z)(i)?t:i}getBoolean(e,t){const i=this.get(e);return(0,a.z)(i)?t:"true"===i}getNumber(e,t){const i=this.get(e);return(0,a.z)(i)?t:parseInt(i,10)}async set(e,t,i=!1){if(this.state===n.Closed)return;if((0,a.z)(t))return this.delete(e,i);const s=(0,a.Gv)(t)||Array.isArray(t)?(0,l.As)(t):String(t);return this.cache.get(e)!==s?(this.cache.set(e,s),this.pendingInserts.set(e,s),this.pendingDeletes.delete(e),this._onDidChangeStorage.fire({key:e,external:i}),this.doFlush()):void 0}async delete(e,t=!1){if(this.state===n.Closed)return;return this.cache.delete(e)?(this.pendingDeletes.has(e)||this.pendingDeletes.add(e),this.pendingInserts.delete(e),this._onDidChangeStorage.fire({key:e,external:t}),this.doFlush()):void 0}get hasPending(){return this.pendingInserts.size>0||this.pendingDeletes.size>0}async flushPending(){if(!this.hasPending)return;const e={insert:this.pendingInserts,delete:this.pendingDeletes};return this.pendingDeletes=new Set,this.pendingInserts=new Map,this.database.updateItems(e).finally((()=>{if(!this.hasPending)for(;this.whenFlushedCallbacks.length;)this.whenFlushedCallbacks.pop()?.()}))}async doFlush(e){return this.options.hint===s.STORAGE_IN_MEMORY?this.flushPending():this.flushDelayer.trigger((()=>this.flushPending()),e)}}class d{constructor(){this.onDidChangeItemsExternal=r.Jh.None,this.items=new Map}async updateItems(e){e.insert?.forEach(((e,t)=>this.items.set(t,e))),e.delete?.forEach((e=>this.items.delete(e)))}}var u=i(63591);const g="__$__targetStorageMarker",p=(0,u.u1)("storageService");var m;!function(e){e[e.NONE=0]="NONE",e[e.SHUTDOWN=1]="SHUTDOWN"}(m||(m={}));class f extends o.jG{static{this.DEFAULT_FLUSH_INTERVAL=6e4}constructor(e={flushInterval:f.DEFAULT_FLUSH_INTERVAL}){super(),this.options=e,this._onDidChangeValue=this._register(new r.fV),this._onDidChangeTarget=this._register(new r.fV),this._onWillSaveState=this._register(new r.vl),this.onWillSaveState=this._onWillSaveState.event,this._workspaceKeyTargets=void 0,this._profileKeyTargets=void 0,this._applicationKeyTargets=void 0}onDidChangeValue(e,t,i){return r.Jh.filter(this._onDidChangeValue.event,(i=>i.scope===e&&(void 0===t||i.key===t)),i)}emitDidChangeValue(e,t){const{key:i,external:s}=t;if(i===g){switch(e){case-1:this._applicationKeyTargets=void 0;break;case 0:this._profileKeyTargets=void 0;break;case 1:this._workspaceKeyTargets=void 0}this._onDidChangeTarget.fire({scope:e})}else this._onDidChangeValue.fire({scope:e,key:i,target:this.getKeyTargets(e)[i],external:s})}get(e,t,i){return this.getStorage(t)?.get(e,i)}getBoolean(e,t,i){return this.getStorage(t)?.getBoolean(e,i)}getNumber(e,t,i){return this.getStorage(t)?.getNumber(e,i)}store(e,t,i,s,n=!1){(0,a.z)(t)?this.remove(e,i,n):this.withPausedEmitters((()=>{this.updateKeyTarget(e,i,s),this.getStorage(i)?.set(e,t,n)}))}remove(e,t,i=!1){this.withPausedEmitters((()=>{this.updateKeyTarget(e,t,void 0),this.getStorage(t)?.delete(e,i)}))}withPausedEmitters(e){this._onDidChangeValue.pause(),this._onDidChangeTarget.pause();try{e()}finally{this._onDidChangeValue.resume(),this._onDidChangeTarget.resume()}}updateKeyTarget(e,t,i,s=!1){const n=this.getKeyTargets(t);"number"===typeof i?n[e]!==i&&(n[e]=i,this.getStorage(t)?.set(g,JSON.stringify(n),s)):"number"===typeof n[e]&&(delete n[e],this.getStorage(t)?.set(g,JSON.stringify(n),s))}get workspaceKeyTargets(){return this._workspaceKeyTargets||(this._workspaceKeyTargets=this.loadKeyTargets(1)),this._workspaceKeyTargets}get profileKeyTargets(){return this._profileKeyTargets||(this._profileKeyTargets=this.loadKeyTargets(0)),this._profileKeyTargets}get applicationKeyTargets(){return this._applicationKeyTargets||(this._applicationKeyTargets=this.loadKeyTargets(-1)),this._applicationKeyTargets}getKeyTargets(e){switch(e){case-1:return this.applicationKeyTargets;case 0:return this.profileKeyTargets;default:return this.workspaceKeyTargets}}loadKeyTargets(e){const t=this.getStorage(e);return t?function(e){const t=e.get(g);if(t)try{return JSON.parse(t)}catch(i){}return Object.create(null)}(t):Object.create(null)}}class _ extends f{constructor(){super(),this.applicationStorage=this._register(new h(new d,{hint:s.STORAGE_IN_MEMORY})),this.profileStorage=this._register(new h(new d,{hint:s.STORAGE_IN_MEMORY})),this.workspaceStorage=this._register(new h(new d,{hint:s.STORAGE_IN_MEMORY})),this._register(this.workspaceStorage.onDidChangeStorage((e=>this.emitDidChangeValue(1,e)))),this._register(this.profileStorage.onDidChangeStorage((e=>this.emitDidChangeValue(0,e)))),this._register(this.applicationStorage.onDidChangeStorage((e=>this.emitDidChangeValue(-1,e))))}getStorage(e){switch(e){case-1:return this.applicationStorage;case 0:return this.profileStorage;default:return this.workspaceStorage}}}},9772:(e,t,i)=>{"use strict";i.d(t,{mn:()=>S,nM:()=>b});var s,n=i(90766),r=i(47661),o=i(64383),a=i(41234),c=i(5662),l=i(78381),h=i(91508),d=i(37734),u=i(31450),g=i(36677),p=i(87289),m=i(32500),f=i(56942),_=i(68310),v=i(84001),C=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},E=function(e,t){return function(i,s){t(i,s,e)}};const b=Object.create({});let S=class extends c.jG{static{s=this}static{this.ID="editor.contrib.colorDetector"}static{this.RECOMPUTE_TIME=1e3}constructor(e,t,i,n){super(),this._editor=e,this._configurationService=t,this._languageFeaturesService=i,this._localToDispose=this._register(new c.Cm),this._decorationsIds=[],this._colorDatas=new Map,this._colorDecoratorIds=this._editor.createDecorationsCollection(),this._ruleFactory=new d.Qn(this._editor),this._decoratorLimitReporter=new y,this._colorDecorationClassRefs=this._register(new c.Cm),this._debounceInformation=n.for(i.colorProvider,"Document Colors",{min:s.RECOMPUTE_TIME}),this._register(e.onDidChangeModel((()=>{this._isColorDecoratorsEnabled=this.isEnabled(),this.updateColors()}))),this._register(e.onDidChangeModelLanguage((()=>this.updateColors()))),this._register(i.colorProvider.onDidChange((()=>this.updateColors()))),this._register(e.onDidChangeConfiguration((e=>{const t=this._isColorDecoratorsEnabled;this._isColorDecoratorsEnabled=this.isEnabled(),this._isDefaultColorDecoratorsEnabled=this._editor.getOption(148);const i=t!==this._isColorDecoratorsEnabled||e.hasChanged(21),s=e.hasChanged(148);(i||s)&&(this._isColorDecoratorsEnabled?this.updateColors():this.removeAllDecorations())}))),this._timeoutTimer=null,this._computePromise=null,this._isColorDecoratorsEnabled=this.isEnabled(),this._isDefaultColorDecoratorsEnabled=this._editor.getOption(148),this.updateColors()}isEnabled(){const e=this._editor.getModel();if(!e)return!1;const t=e.getLanguageId(),i=this._configurationService.getValue(t);if(i&&"object"===typeof i){const e=i.colorDecorators;if(e&&void 0!==e.enable&&!e.enable)return e.enable}return this._editor.getOption(20)}static get(e){return e.getContribution(this.ID)}dispose(){this.stop(),this.removeAllDecorations(),super.dispose()}updateColors(){if(this.stop(),!this._isColorDecoratorsEnabled)return;const e=this._editor.getModel();e&&this._languageFeaturesService.colorProvider.has(e)&&(this._localToDispose.add(this._editor.onDidChangeModelContent((()=>{this._timeoutTimer||(this._timeoutTimer=new n.pc,this._timeoutTimer.cancelAndSet((()=>{this._timeoutTimer=null,this.beginCompute()}),this._debounceInformation.get(e)))}))),this.beginCompute())}async beginCompute(){this._computePromise=(0,n.SS)((async e=>{const t=this._editor.getModel();if(!t)return[];const i=new l.W(!1),s=await(0,_.j)(this._languageFeaturesService.colorProvider,t,e,this._isDefaultColorDecoratorsEnabled);return this._debounceInformation.update(t,i.elapsed()),s}));try{const e=await this._computePromise;this.updateDecorations(e),this.updateColorDecorators(e),this._computePromise=null}catch(e){(0,o.dz)(e)}}stop(){this._timeoutTimer&&(this._timeoutTimer.cancel(),this._timeoutTimer=null),this._computePromise&&(this._computePromise.cancel(),this._computePromise=null),this._localToDispose.clear()}updateDecorations(e){const t=e.map((e=>({range:{startLineNumber:e.colorInfo.range.startLineNumber,startColumn:e.colorInfo.range.startColumn,endLineNumber:e.colorInfo.range.endLineNumber,endColumn:e.colorInfo.range.endColumn},options:p.kI.EMPTY})));this._editor.changeDecorations((i=>{this._decorationsIds=i.deltaDecorations(this._decorationsIds,t),this._colorDatas=new Map,this._decorationsIds.forEach(((t,i)=>this._colorDatas.set(t,e[i])))}))}updateColorDecorators(e){this._colorDecorationClassRefs.clear();const t=[],i=this._editor.getOption(21);for(let n=0;nthis._colorDatas.has(e.id)));return 0===i.length?null:this._colorDatas.get(i[0].id)}isColorDecoration(e){return this._colorDecoratorIds.has(e)}};S=s=C([E(1,v.pG),E(2,f.ILanguageFeaturesService),E(3,m.ILanguageFeatureDebounceService)],S);class y{constructor(){this._onDidChange=new a.vl,this._computed=0,this._limited=!1}update(e,t){e===this._computed&&t===this._limited||(this._computed=e,this._limited=t,this._onDidChange.fire())}}(0,u.HW)(S.ID,S,1)},9948:(e,t,i)=>{"use strict";i.d(t,{I:()=>f});var s=i(8597),n=i(90766),r=i(10350),o=i(5662),a=i(91508),c=i(25689),l=i(36677),h=i(87289),d=i(63591),u=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},g=function(e,t){return function(i,s){t(i,s,e)}};const p=h.kI.register({description:"inline-progress-widget",stickiness:1,showIfCollapsed:!0,after:{content:a.S8,inlineClassName:"inline-editor-progress-decoration",inlineClassNameAffectsLetterSpacing:!0}});class m extends o.jG{static{this.baseId="editor.widget.inlineProgressWidget"}constructor(e,t,i,s,n){super(),this.typeId=e,this.editor=t,this.range=i,this.delegate=n,this.allowEditorOverflow=!1,this.suppressMouseDown=!0,this.create(s),this.editor.addContentWidget(this),this.editor.layoutContentWidget(this)}create(e){this.domNode=s.$(".inline-progress-widget"),this.domNode.role="button",this.domNode.title=e;const t=s.$("span.icon");this.domNode.append(t),t.classList.add(...c.L.asClassNameArray(r.W.loading),"codicon-modifier-spin");const i=()=>{const e=this.editor.getOption(67);this.domNode.style.height=`${e}px`,this.domNode.style.width=`${Math.ceil(.8*e)}px`};i(),this._register(this.editor.onDidChangeConfiguration((e=>{(e.hasChanged(52)||e.hasChanged(67))&&i()}))),this._register(s.ko(this.domNode,s.Bx.CLICK,(e=>{this.delegate.cancel()})))}getId(){return m.baseId+"."+this.typeId}getDomNode(){return this.domNode}getPosition(){return{position:{lineNumber:this.range.startLineNumber,column:this.range.startColumn},preference:[0]}}dispose(){super.dispose(),this.editor.removeContentWidget(this)}}let f=class extends o.jG{constructor(e,t,i){super(),this.id=e,this._editor=t,this._instantiationService=i,this._showDelay=500,this._showPromise=this._register(new o.HE),this._currentWidget=this._register(new o.HE),this._operationIdPool=0,this._currentDecorations=t.createDecorationsCollection()}dispose(){super.dispose(),this._currentDecorations.clear()}async showWhile(e,t,i,s,r){const o=this._operationIdPool++;this._currentOperation=o,this.clear(),this._showPromise.value=(0,n.EQ)((()=>{const i=l.Q.fromPositions(e);this._currentDecorations.set([{range:i,options:p}]).length>0&&(this._currentWidget.value=this._instantiationService.createInstance(m,this.id,this._editor,i,t,s))}),r??this._showDelay);try{return await i}finally{this._currentOperation===o&&(this.clear(),this._currentOperation=void 0)}}clear(){this._showPromise.clear(),this._currentDecorations.clear(),this._currentWidget.clear()}};f=u([g(2,d._Y)],f)},10072:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"swift",aliases:["Swift","swift"],extensions:[".swift"],mimetypes:["text/swift"],loader:()=>i.e(11278).then(i.bind(i,11278))})},10146:(e,t,i)=>{"use strict";i.d(t,{Go:()=>n,PI:()=>a,V0:()=>d,aI:()=>h,co:()=>l,kT:()=>u,ol:()=>r});var s=i(631);function n(e){if(!e||"object"!==typeof e)return e;if(e instanceof RegExp)return e;const t=Array.isArray(e)?[]:{};return Object.entries(e).forEach((([e,i])=>{t[e]=i&&"object"===typeof i?n(i):i})),t}function r(e){if(!e||"object"!==typeof e)return e;const t=[e];for(;t.length>0;){const e=t.shift();Object.freeze(e);for(const i in e)if(o.call(e,i)){const n=e[i];"object"!==typeof n||Object.isFrozen(n)||(0,s.iu)(n)||t.push(n)}}return e}const o=Object.prototype.hasOwnProperty;function a(e,t){return c(e,t,new Set)}function c(e,t,i){if((0,s.z)(e))return e;const n=t(e);if("undefined"!==typeof n)return n;if(Array.isArray(e)){const s=[];for(const n of e)s.push(c(n,t,i));return s}if((0,s.Gv)(e)){if(i.has(e))throw new Error("Cannot clone recursive data-structure");i.add(e);const s={};for(const n in e)o.call(e,n)&&(s[n]=c(e[n],t,i));return i.delete(e),s}return e}function l(e,t,i=!0){return(0,s.Gv)(e)?((0,s.Gv)(t)&&Object.keys(t).forEach((n=>{n in e?i&&((0,s.Gv)(e[n])&&(0,s.Gv)(t[n])?l(e[n],t[n],i):e[n]=t[n]):e[n]=t[n]})),e):t}function h(e,t){if(e===t)return!0;if(null===e||void 0===e||null===t||void 0===t)return!1;if(typeof e!==typeof t)return!1;if("object"!==typeof e)return!1;if(Array.isArray(e)!==Array.isArray(t))return!1;let i,s;if(Array.isArray(e)){if(e.length!==t.length)return!1;for(i=0;ifunction(){const i=Array.prototype.slice.call(arguments,0);return t(e,i)},s={};for(const n of e)s[n]=i(n);return s}},10154:(e,t,i)=>{"use strict";i.d(t,{L:()=>s});const s=(0,i(63591).u1)("languageService")},10350:(e,t,i)=>{"use strict";i.d(t,{W:()=>n});var s=i(18956);const n={...{add:(0,s.k)("add",6e4),plus:(0,s.k)("plus",6e4),gistNew:(0,s.k)("gist-new",6e4),repoCreate:(0,s.k)("repo-create",6e4),lightbulb:(0,s.k)("lightbulb",60001),lightBulb:(0,s.k)("light-bulb",60001),repo:(0,s.k)("repo",60002),repoDelete:(0,s.k)("repo-delete",60002),gistFork:(0,s.k)("gist-fork",60003),repoForked:(0,s.k)("repo-forked",60003),gitPullRequest:(0,s.k)("git-pull-request",60004),gitPullRequestAbandoned:(0,s.k)("git-pull-request-abandoned",60004),recordKeys:(0,s.k)("record-keys",60005),keyboard:(0,s.k)("keyboard",60005),tag:(0,s.k)("tag",60006),gitPullRequestLabel:(0,s.k)("git-pull-request-label",60006),tagAdd:(0,s.k)("tag-add",60006),tagRemove:(0,s.k)("tag-remove",60006),person:(0,s.k)("person",60007),personFollow:(0,s.k)("person-follow",60007),personOutline:(0,s.k)("person-outline",60007),personFilled:(0,s.k)("person-filled",60007),gitBranch:(0,s.k)("git-branch",60008),gitBranchCreate:(0,s.k)("git-branch-create",60008),gitBranchDelete:(0,s.k)("git-branch-delete",60008),sourceControl:(0,s.k)("source-control",60008),mirror:(0,s.k)("mirror",60009),mirrorPublic:(0,s.k)("mirror-public",60009),star:(0,s.k)("star",60010),starAdd:(0,s.k)("star-add",60010),starDelete:(0,s.k)("star-delete",60010),starEmpty:(0,s.k)("star-empty",60010),comment:(0,s.k)("comment",60011),commentAdd:(0,s.k)("comment-add",60011),alert:(0,s.k)("alert",60012),warning:(0,s.k)("warning",60012),search:(0,s.k)("search",60013),searchSave:(0,s.k)("search-save",60013),logOut:(0,s.k)("log-out",60014),signOut:(0,s.k)("sign-out",60014),logIn:(0,s.k)("log-in",60015),signIn:(0,s.k)("sign-in",60015),eye:(0,s.k)("eye",60016),eyeUnwatch:(0,s.k)("eye-unwatch",60016),eyeWatch:(0,s.k)("eye-watch",60016),circleFilled:(0,s.k)("circle-filled",60017),primitiveDot:(0,s.k)("primitive-dot",60017),closeDirty:(0,s.k)("close-dirty",60017),debugBreakpoint:(0,s.k)("debug-breakpoint",60017),debugBreakpointDisabled:(0,s.k)("debug-breakpoint-disabled",60017),debugHint:(0,s.k)("debug-hint",60017),terminalDecorationSuccess:(0,s.k)("terminal-decoration-success",60017),primitiveSquare:(0,s.k)("primitive-square",60018),edit:(0,s.k)("edit",60019),pencil:(0,s.k)("pencil",60019),info:(0,s.k)("info",60020),issueOpened:(0,s.k)("issue-opened",60020),gistPrivate:(0,s.k)("gist-private",60021),gitForkPrivate:(0,s.k)("git-fork-private",60021),lock:(0,s.k)("lock",60021),mirrorPrivate:(0,s.k)("mirror-private",60021),close:(0,s.k)("close",60022),removeClose:(0,s.k)("remove-close",60022),x:(0,s.k)("x",60022),repoSync:(0,s.k)("repo-sync",60023),sync:(0,s.k)("sync",60023),clone:(0,s.k)("clone",60024),desktopDownload:(0,s.k)("desktop-download",60024),beaker:(0,s.k)("beaker",60025),microscope:(0,s.k)("microscope",60025),vm:(0,s.k)("vm",60026),deviceDesktop:(0,s.k)("device-desktop",60026),file:(0,s.k)("file",60027),fileText:(0,s.k)("file-text",60027),more:(0,s.k)("more",60028),ellipsis:(0,s.k)("ellipsis",60028),kebabHorizontal:(0,s.k)("kebab-horizontal",60028),mailReply:(0,s.k)("mail-reply",60029),reply:(0,s.k)("reply",60029),organization:(0,s.k)("organization",60030),organizationFilled:(0,s.k)("organization-filled",60030),organizationOutline:(0,s.k)("organization-outline",60030),newFile:(0,s.k)("new-file",60031),fileAdd:(0,s.k)("file-add",60031),newFolder:(0,s.k)("new-folder",60032),fileDirectoryCreate:(0,s.k)("file-directory-create",60032),trash:(0,s.k)("trash",60033),trashcan:(0,s.k)("trashcan",60033),history:(0,s.k)("history",60034),clock:(0,s.k)("clock",60034),folder:(0,s.k)("folder",60035),fileDirectory:(0,s.k)("file-directory",60035),symbolFolder:(0,s.k)("symbol-folder",60035),logoGithub:(0,s.k)("logo-github",60036),markGithub:(0,s.k)("mark-github",60036),github:(0,s.k)("github",60036),terminal:(0,s.k)("terminal",60037),console:(0,s.k)("console",60037),repl:(0,s.k)("repl",60037),zap:(0,s.k)("zap",60038),symbolEvent:(0,s.k)("symbol-event",60038),error:(0,s.k)("error",60039),stop:(0,s.k)("stop",60039),variable:(0,s.k)("variable",60040),symbolVariable:(0,s.k)("symbol-variable",60040),array:(0,s.k)("array",60042),symbolArray:(0,s.k)("symbol-array",60042),symbolModule:(0,s.k)("symbol-module",60043),symbolPackage:(0,s.k)("symbol-package",60043),symbolNamespace:(0,s.k)("symbol-namespace",60043),symbolObject:(0,s.k)("symbol-object",60043),symbolMethod:(0,s.k)("symbol-method",60044),symbolFunction:(0,s.k)("symbol-function",60044),symbolConstructor:(0,s.k)("symbol-constructor",60044),symbolBoolean:(0,s.k)("symbol-boolean",60047),symbolNull:(0,s.k)("symbol-null",60047),symbolNumeric:(0,s.k)("symbol-numeric",60048),symbolNumber:(0,s.k)("symbol-number",60048),symbolStructure:(0,s.k)("symbol-structure",60049),symbolStruct:(0,s.k)("symbol-struct",60049),symbolParameter:(0,s.k)("symbol-parameter",60050),symbolTypeParameter:(0,s.k)("symbol-type-parameter",60050),symbolKey:(0,s.k)("symbol-key",60051),symbolText:(0,s.k)("symbol-text",60051),symbolReference:(0,s.k)("symbol-reference",60052),goToFile:(0,s.k)("go-to-file",60052),symbolEnum:(0,s.k)("symbol-enum",60053),symbolValue:(0,s.k)("symbol-value",60053),symbolRuler:(0,s.k)("symbol-ruler",60054),symbolUnit:(0,s.k)("symbol-unit",60054),activateBreakpoints:(0,s.k)("activate-breakpoints",60055),archive:(0,s.k)("archive",60056),arrowBoth:(0,s.k)("arrow-both",60057),arrowDown:(0,s.k)("arrow-down",60058),arrowLeft:(0,s.k)("arrow-left",60059),arrowRight:(0,s.k)("arrow-right",60060),arrowSmallDown:(0,s.k)("arrow-small-down",60061),arrowSmallLeft:(0,s.k)("arrow-small-left",60062),arrowSmallRight:(0,s.k)("arrow-small-right",60063),arrowSmallUp:(0,s.k)("arrow-small-up",60064),arrowUp:(0,s.k)("arrow-up",60065),bell:(0,s.k)("bell",60066),bold:(0,s.k)("bold",60067),book:(0,s.k)("book",60068),bookmark:(0,s.k)("bookmark",60069),debugBreakpointConditionalUnverified:(0,s.k)("debug-breakpoint-conditional-unverified",60070),debugBreakpointConditional:(0,s.k)("debug-breakpoint-conditional",60071),debugBreakpointConditionalDisabled:(0,s.k)("debug-breakpoint-conditional-disabled",60071),debugBreakpointDataUnverified:(0,s.k)("debug-breakpoint-data-unverified",60072),debugBreakpointData:(0,s.k)("debug-breakpoint-data",60073),debugBreakpointDataDisabled:(0,s.k)("debug-breakpoint-data-disabled",60073),debugBreakpointLogUnverified:(0,s.k)("debug-breakpoint-log-unverified",60074),debugBreakpointLog:(0,s.k)("debug-breakpoint-log",60075),debugBreakpointLogDisabled:(0,s.k)("debug-breakpoint-log-disabled",60075),briefcase:(0,s.k)("briefcase",60076),broadcast:(0,s.k)("broadcast",60077),browser:(0,s.k)("browser",60078),bug:(0,s.k)("bug",60079),calendar:(0,s.k)("calendar",60080),caseSensitive:(0,s.k)("case-sensitive",60081),check:(0,s.k)("check",60082),checklist:(0,s.k)("checklist",60083),chevronDown:(0,s.k)("chevron-down",60084),chevronLeft:(0,s.k)("chevron-left",60085),chevronRight:(0,s.k)("chevron-right",60086),chevronUp:(0,s.k)("chevron-up",60087),chromeClose:(0,s.k)("chrome-close",60088),chromeMaximize:(0,s.k)("chrome-maximize",60089),chromeMinimize:(0,s.k)("chrome-minimize",60090),chromeRestore:(0,s.k)("chrome-restore",60091),circleOutline:(0,s.k)("circle-outline",60092),circle:(0,s.k)("circle",60092),debugBreakpointUnverified:(0,s.k)("debug-breakpoint-unverified",60092),terminalDecorationIncomplete:(0,s.k)("terminal-decoration-incomplete",60092),circleSlash:(0,s.k)("circle-slash",60093),circuitBoard:(0,s.k)("circuit-board",60094),clearAll:(0,s.k)("clear-all",60095),clippy:(0,s.k)("clippy",60096),closeAll:(0,s.k)("close-all",60097),cloudDownload:(0,s.k)("cloud-download",60098),cloudUpload:(0,s.k)("cloud-upload",60099),code:(0,s.k)("code",60100),collapseAll:(0,s.k)("collapse-all",60101),colorMode:(0,s.k)("color-mode",60102),commentDiscussion:(0,s.k)("comment-discussion",60103),creditCard:(0,s.k)("credit-card",60105),dash:(0,s.k)("dash",60108),dashboard:(0,s.k)("dashboard",60109),database:(0,s.k)("database",60110),debugContinue:(0,s.k)("debug-continue",60111),debugDisconnect:(0,s.k)("debug-disconnect",60112),debugPause:(0,s.k)("debug-pause",60113),debugRestart:(0,s.k)("debug-restart",60114),debugStart:(0,s.k)("debug-start",60115),debugStepInto:(0,s.k)("debug-step-into",60116),debugStepOut:(0,s.k)("debug-step-out",60117),debugStepOver:(0,s.k)("debug-step-over",60118),debugStop:(0,s.k)("debug-stop",60119),debug:(0,s.k)("debug",60120),deviceCameraVideo:(0,s.k)("device-camera-video",60121),deviceCamera:(0,s.k)("device-camera",60122),deviceMobile:(0,s.k)("device-mobile",60123),diffAdded:(0,s.k)("diff-added",60124),diffIgnored:(0,s.k)("diff-ignored",60125),diffModified:(0,s.k)("diff-modified",60126),diffRemoved:(0,s.k)("diff-removed",60127),diffRenamed:(0,s.k)("diff-renamed",60128),diff:(0,s.k)("diff",60129),diffSidebyside:(0,s.k)("diff-sidebyside",60129),discard:(0,s.k)("discard",60130),editorLayout:(0,s.k)("editor-layout",60131),emptyWindow:(0,s.k)("empty-window",60132),exclude:(0,s.k)("exclude",60133),extensions:(0,s.k)("extensions",60134),eyeClosed:(0,s.k)("eye-closed",60135),fileBinary:(0,s.k)("file-binary",60136),fileCode:(0,s.k)("file-code",60137),fileMedia:(0,s.k)("file-media",60138),filePdf:(0,s.k)("file-pdf",60139),fileSubmodule:(0,s.k)("file-submodule",60140),fileSymlinkDirectory:(0,s.k)("file-symlink-directory",60141),fileSymlinkFile:(0,s.k)("file-symlink-file",60142),fileZip:(0,s.k)("file-zip",60143),files:(0,s.k)("files",60144),filter:(0,s.k)("filter",60145),flame:(0,s.k)("flame",60146),foldDown:(0,s.k)("fold-down",60147),foldUp:(0,s.k)("fold-up",60148),fold:(0,s.k)("fold",60149),folderActive:(0,s.k)("folder-active",60150),folderOpened:(0,s.k)("folder-opened",60151),gear:(0,s.k)("gear",60152),gift:(0,s.k)("gift",60153),gistSecret:(0,s.k)("gist-secret",60154),gist:(0,s.k)("gist",60155),gitCommit:(0,s.k)("git-commit",60156),gitCompare:(0,s.k)("git-compare",60157),compareChanges:(0,s.k)("compare-changes",60157),gitMerge:(0,s.k)("git-merge",60158),githubAction:(0,s.k)("github-action",60159),githubAlt:(0,s.k)("github-alt",60160),globe:(0,s.k)("globe",60161),grabber:(0,s.k)("grabber",60162),graph:(0,s.k)("graph",60163),gripper:(0,s.k)("gripper",60164),heart:(0,s.k)("heart",60165),home:(0,s.k)("home",60166),horizontalRule:(0,s.k)("horizontal-rule",60167),hubot:(0,s.k)("hubot",60168),inbox:(0,s.k)("inbox",60169),issueReopened:(0,s.k)("issue-reopened",60171),issues:(0,s.k)("issues",60172),italic:(0,s.k)("italic",60173),jersey:(0,s.k)("jersey",60174),json:(0,s.k)("json",60175),kebabVertical:(0,s.k)("kebab-vertical",60176),key:(0,s.k)("key",60177),law:(0,s.k)("law",60178),lightbulbAutofix:(0,s.k)("lightbulb-autofix",60179),linkExternal:(0,s.k)("link-external",60180),link:(0,s.k)("link",60181),listOrdered:(0,s.k)("list-ordered",60182),listUnordered:(0,s.k)("list-unordered",60183),liveShare:(0,s.k)("live-share",60184),loading:(0,s.k)("loading",60185),location:(0,s.k)("location",60186),mailRead:(0,s.k)("mail-read",60187),mail:(0,s.k)("mail",60188),markdown:(0,s.k)("markdown",60189),megaphone:(0,s.k)("megaphone",60190),mention:(0,s.k)("mention",60191),milestone:(0,s.k)("milestone",60192),gitPullRequestMilestone:(0,s.k)("git-pull-request-milestone",60192),mortarBoard:(0,s.k)("mortar-board",60193),move:(0,s.k)("move",60194),multipleWindows:(0,s.k)("multiple-windows",60195),mute:(0,s.k)("mute",60196),noNewline:(0,s.k)("no-newline",60197),note:(0,s.k)("note",60198),octoface:(0,s.k)("octoface",60199),openPreview:(0,s.k)("open-preview",60200),package:(0,s.k)("package",60201),paintcan:(0,s.k)("paintcan",60202),pin:(0,s.k)("pin",60203),play:(0,s.k)("play",60204),run:(0,s.k)("run",60204),plug:(0,s.k)("plug",60205),preserveCase:(0,s.k)("preserve-case",60206),preview:(0,s.k)("preview",60207),project:(0,s.k)("project",60208),pulse:(0,s.k)("pulse",60209),question:(0,s.k)("question",60210),quote:(0,s.k)("quote",60211),radioTower:(0,s.k)("radio-tower",60212),reactions:(0,s.k)("reactions",60213),references:(0,s.k)("references",60214),refresh:(0,s.k)("refresh",60215),regex:(0,s.k)("regex",60216),remoteExplorer:(0,s.k)("remote-explorer",60217),remote:(0,s.k)("remote",60218),remove:(0,s.k)("remove",60219),replaceAll:(0,s.k)("replace-all",60220),replace:(0,s.k)("replace",60221),repoClone:(0,s.k)("repo-clone",60222),repoForcePush:(0,s.k)("repo-force-push",60223),repoPull:(0,s.k)("repo-pull",60224),repoPush:(0,s.k)("repo-push",60225),report:(0,s.k)("report",60226),requestChanges:(0,s.k)("request-changes",60227),rocket:(0,s.k)("rocket",60228),rootFolderOpened:(0,s.k)("root-folder-opened",60229),rootFolder:(0,s.k)("root-folder",60230),rss:(0,s.k)("rss",60231),ruby:(0,s.k)("ruby",60232),saveAll:(0,s.k)("save-all",60233),saveAs:(0,s.k)("save-as",60234),save:(0,s.k)("save",60235),screenFull:(0,s.k)("screen-full",60236),screenNormal:(0,s.k)("screen-normal",60237),searchStop:(0,s.k)("search-stop",60238),server:(0,s.k)("server",60240),settingsGear:(0,s.k)("settings-gear",60241),settings:(0,s.k)("settings",60242),shield:(0,s.k)("shield",60243),smiley:(0,s.k)("smiley",60244),sortPrecedence:(0,s.k)("sort-precedence",60245),splitHorizontal:(0,s.k)("split-horizontal",60246),splitVertical:(0,s.k)("split-vertical",60247),squirrel:(0,s.k)("squirrel",60248),starFull:(0,s.k)("star-full",60249),starHalf:(0,s.k)("star-half",60250),symbolClass:(0,s.k)("symbol-class",60251),symbolColor:(0,s.k)("symbol-color",60252),symbolConstant:(0,s.k)("symbol-constant",60253),symbolEnumMember:(0,s.k)("symbol-enum-member",60254),symbolField:(0,s.k)("symbol-field",60255),symbolFile:(0,s.k)("symbol-file",60256),symbolInterface:(0,s.k)("symbol-interface",60257),symbolKeyword:(0,s.k)("symbol-keyword",60258),symbolMisc:(0,s.k)("symbol-misc",60259),symbolOperator:(0,s.k)("symbol-operator",60260),symbolProperty:(0,s.k)("symbol-property",60261),wrench:(0,s.k)("wrench",60261),wrenchSubaction:(0,s.k)("wrench-subaction",60261),symbolSnippet:(0,s.k)("symbol-snippet",60262),tasklist:(0,s.k)("tasklist",60263),telescope:(0,s.k)("telescope",60264),textSize:(0,s.k)("text-size",60265),threeBars:(0,s.k)("three-bars",60266),thumbsdown:(0,s.k)("thumbsdown",60267),thumbsup:(0,s.k)("thumbsup",60268),tools:(0,s.k)("tools",60269),triangleDown:(0,s.k)("triangle-down",60270),triangleLeft:(0,s.k)("triangle-left",60271),triangleRight:(0,s.k)("triangle-right",60272),triangleUp:(0,s.k)("triangle-up",60273),twitter:(0,s.k)("twitter",60274),unfold:(0,s.k)("unfold",60275),unlock:(0,s.k)("unlock",60276),unmute:(0,s.k)("unmute",60277),unverified:(0,s.k)("unverified",60278),verified:(0,s.k)("verified",60279),versions:(0,s.k)("versions",60280),vmActive:(0,s.k)("vm-active",60281),vmOutline:(0,s.k)("vm-outline",60282),vmRunning:(0,s.k)("vm-running",60283),watch:(0,s.k)("watch",60284),whitespace:(0,s.k)("whitespace",60285),wholeWord:(0,s.k)("whole-word",60286),window:(0,s.k)("window",60287),wordWrap:(0,s.k)("word-wrap",60288),zoomIn:(0,s.k)("zoom-in",60289),zoomOut:(0,s.k)("zoom-out",60290),listFilter:(0,s.k)("list-filter",60291),listFlat:(0,s.k)("list-flat",60292),listSelection:(0,s.k)("list-selection",60293),selection:(0,s.k)("selection",60293),listTree:(0,s.k)("list-tree",60294),debugBreakpointFunctionUnverified:(0,s.k)("debug-breakpoint-function-unverified",60295),debugBreakpointFunction:(0,s.k)("debug-breakpoint-function",60296),debugBreakpointFunctionDisabled:(0,s.k)("debug-breakpoint-function-disabled",60296),debugStackframeActive:(0,s.k)("debug-stackframe-active",60297),circleSmallFilled:(0,s.k)("circle-small-filled",60298),debugStackframeDot:(0,s.k)("debug-stackframe-dot",60298),terminalDecorationMark:(0,s.k)("terminal-decoration-mark",60298),debugStackframe:(0,s.k)("debug-stackframe",60299),debugStackframeFocused:(0,s.k)("debug-stackframe-focused",60299),debugBreakpointUnsupported:(0,s.k)("debug-breakpoint-unsupported",60300),symbolString:(0,s.k)("symbol-string",60301),debugReverseContinue:(0,s.k)("debug-reverse-continue",60302),debugStepBack:(0,s.k)("debug-step-back",60303),debugRestartFrame:(0,s.k)("debug-restart-frame",60304),debugAlt:(0,s.k)("debug-alt",60305),callIncoming:(0,s.k)("call-incoming",60306),callOutgoing:(0,s.k)("call-outgoing",60307),menu:(0,s.k)("menu",60308),expandAll:(0,s.k)("expand-all",60309),feedback:(0,s.k)("feedback",60310),gitPullRequestReviewer:(0,s.k)("git-pull-request-reviewer",60310),groupByRefType:(0,s.k)("group-by-ref-type",60311),ungroupByRefType:(0,s.k)("ungroup-by-ref-type",60312),account:(0,s.k)("account",60313),gitPullRequestAssignee:(0,s.k)("git-pull-request-assignee",60313),bellDot:(0,s.k)("bell-dot",60314),debugConsole:(0,s.k)("debug-console",60315),library:(0,s.k)("library",60316),output:(0,s.k)("output",60317),runAll:(0,s.k)("run-all",60318),syncIgnored:(0,s.k)("sync-ignored",60319),pinned:(0,s.k)("pinned",60320),githubInverted:(0,s.k)("github-inverted",60321),serverProcess:(0,s.k)("server-process",60322),serverEnvironment:(0,s.k)("server-environment",60323),pass:(0,s.k)("pass",60324),issueClosed:(0,s.k)("issue-closed",60324),stopCircle:(0,s.k)("stop-circle",60325),playCircle:(0,s.k)("play-circle",60326),record:(0,s.k)("record",60327),debugAltSmall:(0,s.k)("debug-alt-small",60328),vmConnect:(0,s.k)("vm-connect",60329),cloud:(0,s.k)("cloud",60330),merge:(0,s.k)("merge",60331),export:(0,s.k)("export",60332),graphLeft:(0,s.k)("graph-left",60333),magnet:(0,s.k)("magnet",60334),notebook:(0,s.k)("notebook",60335),redo:(0,s.k)("redo",60336),checkAll:(0,s.k)("check-all",60337),pinnedDirty:(0,s.k)("pinned-dirty",60338),passFilled:(0,s.k)("pass-filled",60339),circleLargeFilled:(0,s.k)("circle-large-filled",60340),circleLarge:(0,s.k)("circle-large",60341),circleLargeOutline:(0,s.k)("circle-large-outline",60341),combine:(0,s.k)("combine",60342),gather:(0,s.k)("gather",60342),table:(0,s.k)("table",60343),variableGroup:(0,s.k)("variable-group",60344),typeHierarchy:(0,s.k)("type-hierarchy",60345),typeHierarchySub:(0,s.k)("type-hierarchy-sub",60346),typeHierarchySuper:(0,s.k)("type-hierarchy-super",60347),gitPullRequestCreate:(0,s.k)("git-pull-request-create",60348),runAbove:(0,s.k)("run-above",60349),runBelow:(0,s.k)("run-below",60350),notebookTemplate:(0,s.k)("notebook-template",60351),debugRerun:(0,s.k)("debug-rerun",60352),workspaceTrusted:(0,s.k)("workspace-trusted",60353),workspaceUntrusted:(0,s.k)("workspace-untrusted",60354),workspaceUnknown:(0,s.k)("workspace-unknown",60355),terminalCmd:(0,s.k)("terminal-cmd",60356),terminalDebian:(0,s.k)("terminal-debian",60357),terminalLinux:(0,s.k)("terminal-linux",60358),terminalPowershell:(0,s.k)("terminal-powershell",60359),terminalTmux:(0,s.k)("terminal-tmux",60360),terminalUbuntu:(0,s.k)("terminal-ubuntu",60361),terminalBash:(0,s.k)("terminal-bash",60362),arrowSwap:(0,s.k)("arrow-swap",60363),copy:(0,s.k)("copy",60364),personAdd:(0,s.k)("person-add",60365),filterFilled:(0,s.k)("filter-filled",60366),wand:(0,s.k)("wand",60367),debugLineByLine:(0,s.k)("debug-line-by-line",60368),inspect:(0,s.k)("inspect",60369),layers:(0,s.k)("layers",60370),layersDot:(0,s.k)("layers-dot",60371),layersActive:(0,s.k)("layers-active",60372),compass:(0,s.k)("compass",60373),compassDot:(0,s.k)("compass-dot",60374),compassActive:(0,s.k)("compass-active",60375),azure:(0,s.k)("azure",60376),issueDraft:(0,s.k)("issue-draft",60377),gitPullRequestClosed:(0,s.k)("git-pull-request-closed",60378),gitPullRequestDraft:(0,s.k)("git-pull-request-draft",60379),debugAll:(0,s.k)("debug-all",60380),debugCoverage:(0,s.k)("debug-coverage",60381),runErrors:(0,s.k)("run-errors",60382),folderLibrary:(0,s.k)("folder-library",60383),debugContinueSmall:(0,s.k)("debug-continue-small",60384),beakerStop:(0,s.k)("beaker-stop",60385),graphLine:(0,s.k)("graph-line",60386),graphScatter:(0,s.k)("graph-scatter",60387),pieChart:(0,s.k)("pie-chart",60388),bracket:(0,s.k)("bracket",60175),bracketDot:(0,s.k)("bracket-dot",60389),bracketError:(0,s.k)("bracket-error",60390),lockSmall:(0,s.k)("lock-small",60391),azureDevops:(0,s.k)("azure-devops",60392),verifiedFilled:(0,s.k)("verified-filled",60393),newline:(0,s.k)("newline",60394),layout:(0,s.k)("layout",60395),layoutActivitybarLeft:(0,s.k)("layout-activitybar-left",60396),layoutActivitybarRight:(0,s.k)("layout-activitybar-right",60397),layoutPanelLeft:(0,s.k)("layout-panel-left",60398),layoutPanelCenter:(0,s.k)("layout-panel-center",60399),layoutPanelJustify:(0,s.k)("layout-panel-justify",60400),layoutPanelRight:(0,s.k)("layout-panel-right",60401),layoutPanel:(0,s.k)("layout-panel",60402),layoutSidebarLeft:(0,s.k)("layout-sidebar-left",60403),layoutSidebarRight:(0,s.k)("layout-sidebar-right",60404),layoutStatusbar:(0,s.k)("layout-statusbar",60405),layoutMenubar:(0,s.k)("layout-menubar",60406),layoutCentered:(0,s.k)("layout-centered",60407),target:(0,s.k)("target",60408),indent:(0,s.k)("indent",60409),recordSmall:(0,s.k)("record-small",60410),errorSmall:(0,s.k)("error-small",60411),terminalDecorationError:(0,s.k)("terminal-decoration-error",60411),arrowCircleDown:(0,s.k)("arrow-circle-down",60412),arrowCircleLeft:(0,s.k)("arrow-circle-left",60413),arrowCircleRight:(0,s.k)("arrow-circle-right",60414),arrowCircleUp:(0,s.k)("arrow-circle-up",60415),layoutSidebarRightOff:(0,s.k)("layout-sidebar-right-off",60416),layoutPanelOff:(0,s.k)("layout-panel-off",60417),layoutSidebarLeftOff:(0,s.k)("layout-sidebar-left-off",60418),blank:(0,s.k)("blank",60419),heartFilled:(0,s.k)("heart-filled",60420),map:(0,s.k)("map",60421),mapHorizontal:(0,s.k)("map-horizontal",60421),foldHorizontal:(0,s.k)("fold-horizontal",60421),mapFilled:(0,s.k)("map-filled",60422),mapHorizontalFilled:(0,s.k)("map-horizontal-filled",60422),foldHorizontalFilled:(0,s.k)("fold-horizontal-filled",60422),circleSmall:(0,s.k)("circle-small",60423),bellSlash:(0,s.k)("bell-slash",60424),bellSlashDot:(0,s.k)("bell-slash-dot",60425),commentUnresolved:(0,s.k)("comment-unresolved",60426),gitPullRequestGoToChanges:(0,s.k)("git-pull-request-go-to-changes",60427),gitPullRequestNewChanges:(0,s.k)("git-pull-request-new-changes",60428),searchFuzzy:(0,s.k)("search-fuzzy",60429),commentDraft:(0,s.k)("comment-draft",60430),send:(0,s.k)("send",60431),sparkle:(0,s.k)("sparkle",60432),insert:(0,s.k)("insert",60433),mic:(0,s.k)("mic",60434),thumbsdownFilled:(0,s.k)("thumbsdown-filled",60435),thumbsupFilled:(0,s.k)("thumbsup-filled",60436),coffee:(0,s.k)("coffee",60437),snake:(0,s.k)("snake",60438),game:(0,s.k)("game",60439),vr:(0,s.k)("vr",60440),chip:(0,s.k)("chip",60441),piano:(0,s.k)("piano",60442),music:(0,s.k)("music",60443),micFilled:(0,s.k)("mic-filled",60444),repoFetch:(0,s.k)("repo-fetch",60445),copilot:(0,s.k)("copilot",60446),lightbulbSparkle:(0,s.k)("lightbulb-sparkle",60447),robot:(0,s.k)("robot",60448),sparkleFilled:(0,s.k)("sparkle-filled",60449),diffSingle:(0,s.k)("diff-single",60450),diffMultiple:(0,s.k)("diff-multiple",60451),surroundWith:(0,s.k)("surround-with",60452),share:(0,s.k)("share",60453),gitStash:(0,s.k)("git-stash",60454),gitStashApply:(0,s.k)("git-stash-apply",60455),gitStashPop:(0,s.k)("git-stash-pop",60456),vscode:(0,s.k)("vscode",60457),vscodeInsiders:(0,s.k)("vscode-insiders",60458),codeOss:(0,s.k)("code-oss",60459),runCoverage:(0,s.k)("run-coverage",60460),runAllCoverage:(0,s.k)("run-all-coverage",60461),coverage:(0,s.k)("coverage",60462),githubProject:(0,s.k)("github-project",60463),mapVertical:(0,s.k)("map-vertical",60464),foldVertical:(0,s.k)("fold-vertical",60464),mapVerticalFilled:(0,s.k)("map-vertical-filled",60465),foldVerticalFilled:(0,s.k)("fold-vertical-filled",60465),goToSearch:(0,s.k)("go-to-search",60466),percentage:(0,s.k)("percentage",60467),sortPercentage:(0,s.k)("sort-percentage",60467),attach:(0,s.k)("attach",60468)},...{dialogError:(0,s.k)("dialog-error","error"),dialogWarning:(0,s.k)("dialog-warning","warning"),dialogInfo:(0,s.k)("dialog-info","info"),dialogClose:(0,s.k)("dialog-close","close"),treeItemExpanded:(0,s.k)("tree-item-expanded","chevron-down"),treeFilterOnTypeOn:(0,s.k)("tree-filter-on-type-on","list-filter"),treeFilterOnTypeOff:(0,s.k)("tree-filter-on-type-off","list-selection"),treeFilterClear:(0,s.k)("tree-filter-clear","close"),treeItemLoading:(0,s.k)("tree-item-loading","loading"),menuSelection:(0,s.k)("menu-selection","check"),menuSubmenu:(0,s.k)("menu-submenu","chevron-right"),menuBarMore:(0,s.k)("menubar-more","more"),scrollbarButtonLeft:(0,s.k)("scrollbar-button-left","triangle-left"),scrollbarButtonRight:(0,s.k)("scrollbar-button-right","triangle-right"),scrollbarButtonUp:(0,s.k)("scrollbar-button-up","triangle-up"),scrollbarButtonDown:(0,s.k)("scrollbar-button-down","triangle-down"),toolBarMore:(0,s.k)("toolbar-more","more"),quickInputBack:(0,s.k)("quick-input-back","arrow-left"),dropDownButton:(0,s.k)("drop-down-button",60084),symbolCustomColor:(0,s.k)("symbol-customcolor",60252),exportIcon:(0,s.k)("export",60332),workspaceUnspecified:(0,s.k)("workspace-unspecified",60355),newLine:(0,s.k)("newline",60394),thumbsDownFilled:(0,s.k)("thumbsdown-filled",60435),thumbsUpFilled:(0,s.k)("thumbsup-filled",60436),gitFetch:(0,s.k)("git-fetch",60445),lightbulbSparkleAutofix:(0,s.k)("lightbulb-sparkle-autofix",60447),debugBreakpointPending:(0,s.k)("debug-breakpoint-pending",60377)}}},10411:(e,t,i)=>{e.exports=function(e){const t=i(83823)(e);return function(e,i,s){const n=e.$value;return t(n,i,s-1)}}},10424:(e,t,i)=>{"use strict";i.d(t,{aQ:()=>I,nr:()=>O,Sx:()=>B,po:()=>N,tj:()=>A});var s=i(8597),n=i(60413),r=i(47661),o=i(41234),a=i(62083),c=i(25982);class l{constructor(e,t,i,s,n){this._parsedThemeRuleBrand=void 0,this.token=e,this.index=t,this.fontStyle=i,this.foreground=s,this.background=n}}const h=/^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/;class d{constructor(){this._lastColorId=0,this._id2color=[],this._color2id=new Map}getId(e){if(null===e)return 0;const t=e.match(h);if(!t)throw new Error("Illegal value for token color: "+e);e=t[1].toUpperCase();let i=this._color2id.get(e);return i||(i=++this._lastColorId,this._color2id.set(e,i),this._id2color[i]=r.Q1.fromHex("#"+e),i)}getColorMap(){return this._id2color.slice(0)}}class u{static createFromRawTokenTheme(e,t){return this.createFromParsedTokenTheme(function(e){if(!e||!Array.isArray(e))return[];const t=[];let i=0;for(let s=0,n=e.length;s{const i=function(e,t){return et?1:0}(e.token,t.token);return 0!==i?i:e.index-t.index}));let i=0,s="000000",n="ffffff";for(;e.length>=1&&""===e[0].token;){const t=e.shift();-1!==t.fontStyle&&(i=t.fontStyle),null!==t.foreground&&(s=t.foreground),null!==t.background&&(n=t.background)}const r=new d;for(const h of t)r.getId(h);const o=r.getId(s),a=r.getId(n),c=new p(i,o,a),l=new m(c);for(let h=0,d=e.length;h>>0,this._cache.set(t,i)}return(i|e)>>>0}}const g=/\b(comment|string|regex|regexp)\b/;class p{constructor(e,t,i){this._themeTrieElementRuleBrand=void 0,this._fontStyle=e,this._foreground=t,this._background=i,this.metadata=(this._fontStyle<<11|this._foreground<<15|this._background<<24)>>>0}clone(){return new p(this._fontStyle,this._foreground,this._background)}acceptOverwrite(e,t,i){-1!==e&&(this._fontStyle=e),0!==t&&(this._foreground=t),0!==i&&(this._background=i),this.metadata=(this._fontStyle<<11|this._foreground<<15|this._background<<24)>>>0}}class m{constructor(e){this._themeTrieElementBrand=void 0,this._mainRule=e,this._children=new Map}match(e){if(""===e)return this._mainRule;const t=e.indexOf(".");let i,s;-1===t?(i=e,s=""):(i=e.substring(0,t),s=e.substring(t+1));const n=this._children.get(i);return"undefined"!==typeof n?n.match(s):this._mainRule}insert(e,t,i,s){if(""===e)return void this._mainRule.acceptOverwrite(t,i,s);const n=e.indexOf(".");let r,o;-1===n?(r=e,o=""):(r=e.substring(0,n),o=e.substring(n+1));let a=this._children.get(r);"undefined"===typeof a&&(a=new m(this._mainRule.clone()),this._children.set(r,a)),a.insert(o,t,i,s)}}var f=i(87119),_=i(66261);const v={base:"vs",inherit:!1,rules:[{token:"",foreground:"000000",background:"fffffe"},{token:"invalid",foreground:"cd3131"},{token:"emphasis",fontStyle:"italic"},{token:"strong",fontStyle:"bold"},{token:"variable",foreground:"001188"},{token:"variable.predefined",foreground:"4864AA"},{token:"constant",foreground:"dd0000"},{token:"comment",foreground:"008000"},{token:"number",foreground:"098658"},{token:"number.hex",foreground:"3030c0"},{token:"regexp",foreground:"800000"},{token:"annotation",foreground:"808080"},{token:"type",foreground:"008080"},{token:"delimiter",foreground:"000000"},{token:"delimiter.html",foreground:"383838"},{token:"delimiter.xml",foreground:"0000FF"},{token:"tag",foreground:"800000"},{token:"tag.id.pug",foreground:"4F76AC"},{token:"tag.class.pug",foreground:"4F76AC"},{token:"meta.scss",foreground:"800000"},{token:"metatag",foreground:"e00000"},{token:"metatag.content.html",foreground:"FF0000"},{token:"metatag.html",foreground:"808080"},{token:"metatag.xml",foreground:"808080"},{token:"metatag.php",fontStyle:"bold"},{token:"key",foreground:"863B00"},{token:"string.key.json",foreground:"A31515"},{token:"string.value.json",foreground:"0451A5"},{token:"attribute.name",foreground:"FF0000"},{token:"attribute.value",foreground:"0451A5"},{token:"attribute.value.number",foreground:"098658"},{token:"attribute.value.unit",foreground:"098658"},{token:"attribute.value.html",foreground:"0000FF"},{token:"attribute.value.xml",foreground:"0000FF"},{token:"string",foreground:"A31515"},{token:"string.html",foreground:"0000FF"},{token:"string.sql",foreground:"FF0000"},{token:"string.yaml",foreground:"0451A5"},{token:"keyword",foreground:"0000FF"},{token:"keyword.json",foreground:"0451A5"},{token:"keyword.flow",foreground:"AF00DB"},{token:"keyword.flow.scss",foreground:"0000FF"},{token:"operator.scss",foreground:"666666"},{token:"operator.sql",foreground:"778899"},{token:"operator.swift",foreground:"666666"},{token:"predefined.sql",foreground:"C700C7"}],colors:{[_.YtV]:"#FFFFFE",[_.By2]:"#000000",[_.tan]:"#E5EBF1",[f.vV]:"#D3D3D3",[f.H0]:"#939393",[_.QwA]:"#ADD6FF4D"}},C={base:"vs-dark",inherit:!1,rules:[{token:"",foreground:"D4D4D4",background:"1E1E1E"},{token:"invalid",foreground:"f44747"},{token:"emphasis",fontStyle:"italic"},{token:"strong",fontStyle:"bold"},{token:"variable",foreground:"74B0DF"},{token:"variable.predefined",foreground:"4864AA"},{token:"variable.parameter",foreground:"9CDCFE"},{token:"constant",foreground:"569CD6"},{token:"comment",foreground:"608B4E"},{token:"number",foreground:"B5CEA8"},{token:"number.hex",foreground:"5BB498"},{token:"regexp",foreground:"B46695"},{token:"annotation",foreground:"cc6666"},{token:"type",foreground:"3DC9B0"},{token:"delimiter",foreground:"DCDCDC"},{token:"delimiter.html",foreground:"808080"},{token:"delimiter.xml",foreground:"808080"},{token:"tag",foreground:"569CD6"},{token:"tag.id.pug",foreground:"4F76AC"},{token:"tag.class.pug",foreground:"4F76AC"},{token:"meta.scss",foreground:"A79873"},{token:"meta.tag",foreground:"CE9178"},{token:"metatag",foreground:"DD6A6F"},{token:"metatag.content.html",foreground:"9CDCFE"},{token:"metatag.html",foreground:"569CD6"},{token:"metatag.xml",foreground:"569CD6"},{token:"metatag.php",fontStyle:"bold"},{token:"key",foreground:"9CDCFE"},{token:"string.key.json",foreground:"9CDCFE"},{token:"string.value.json",foreground:"CE9178"},{token:"attribute.name",foreground:"9CDCFE"},{token:"attribute.value",foreground:"CE9178"},{token:"attribute.value.number.css",foreground:"B5CEA8"},{token:"attribute.value.unit.css",foreground:"B5CEA8"},{token:"attribute.value.hex.css",foreground:"D4D4D4"},{token:"string",foreground:"CE9178"},{token:"string.sql",foreground:"FF0000"},{token:"keyword",foreground:"569CD6"},{token:"keyword.flow",foreground:"C586C0"},{token:"keyword.json",foreground:"CE9178"},{token:"keyword.flow.scss",foreground:"569CD6"},{token:"operator.scss",foreground:"909090"},{token:"operator.sql",foreground:"778899"},{token:"operator.swift",foreground:"909090"},{token:"predefined.sql",foreground:"FF00FF"}],colors:{[_.YtV]:"#1E1E1E",[_.By2]:"#D4D4D4",[_.tan]:"#3A3D41",[f.vV]:"#404040",[f.H0]:"#707070",[_.QwA]:"#ADD6FF26"}},E={base:"hc-black",inherit:!1,rules:[{token:"",foreground:"FFFFFF",background:"000000"},{token:"invalid",foreground:"f44747"},{token:"emphasis",fontStyle:"italic"},{token:"strong",fontStyle:"bold"},{token:"variable",foreground:"1AEBFF"},{token:"variable.parameter",foreground:"9CDCFE"},{token:"constant",foreground:"569CD6"},{token:"comment",foreground:"608B4E"},{token:"number",foreground:"FFFFFF"},{token:"regexp",foreground:"C0C0C0"},{token:"annotation",foreground:"569CD6"},{token:"type",foreground:"3DC9B0"},{token:"delimiter",foreground:"FFFF00"},{token:"delimiter.html",foreground:"FFFF00"},{token:"tag",foreground:"569CD6"},{token:"tag.id.pug",foreground:"4F76AC"},{token:"tag.class.pug",foreground:"4F76AC"},{token:"meta",foreground:"D4D4D4"},{token:"meta.tag",foreground:"CE9178"},{token:"metatag",foreground:"569CD6"},{token:"metatag.content.html",foreground:"1AEBFF"},{token:"metatag.html",foreground:"569CD6"},{token:"metatag.xml",foreground:"569CD6"},{token:"metatag.php",fontStyle:"bold"},{token:"key",foreground:"9CDCFE"},{token:"string.key",foreground:"9CDCFE"},{token:"string.value",foreground:"CE9178"},{token:"attribute.name",foreground:"569CD6"},{token:"attribute.value",foreground:"3FF23F"},{token:"string",foreground:"CE9178"},{token:"string.sql",foreground:"FF0000"},{token:"keyword",foreground:"569CD6"},{token:"keyword.flow",foreground:"C586C0"},{token:"operator.sql",foreground:"778899"},{token:"operator.swift",foreground:"909090"},{token:"predefined.sql",foreground:"FF00FF"}],colors:{[_.YtV]:"#000000",[_.By2]:"#FFFFFF",[f.vV]:"#FFFFFF",[f.H0]:"#FFFFFF"}},b={base:"hc-light",inherit:!1,rules:[{token:"",foreground:"292929",background:"FFFFFF"},{token:"invalid",foreground:"B5200D"},{token:"emphasis",fontStyle:"italic"},{token:"strong",fontStyle:"bold"},{token:"variable",foreground:"264F70"},{token:"variable.predefined",foreground:"4864AA"},{token:"constant",foreground:"dd0000"},{token:"comment",foreground:"008000"},{token:"number",foreground:"098658"},{token:"number.hex",foreground:"3030c0"},{token:"regexp",foreground:"800000"},{token:"annotation",foreground:"808080"},{token:"type",foreground:"008080"},{token:"delimiter",foreground:"000000"},{token:"delimiter.html",foreground:"383838"},{token:"tag",foreground:"800000"},{token:"tag.id.pug",foreground:"4F76AC"},{token:"tag.class.pug",foreground:"4F76AC"},{token:"meta.scss",foreground:"800000"},{token:"metatag",foreground:"e00000"},{token:"metatag.content.html",foreground:"B5200D"},{token:"metatag.html",foreground:"808080"},{token:"metatag.xml",foreground:"808080"},{token:"metatag.php",fontStyle:"bold"},{token:"key",foreground:"863B00"},{token:"string.key.json",foreground:"A31515"},{token:"string.value.json",foreground:"0451A5"},{token:"attribute.name",foreground:"264F78"},{token:"attribute.value",foreground:"0451A5"},{token:"string",foreground:"A31515"},{token:"string.sql",foreground:"B5200D"},{token:"keyword",foreground:"0000FF"},{token:"keyword.flow",foreground:"AF00DB"},{token:"operator.sql",foreground:"778899"},{token:"operator.swift",foreground:"666666"},{token:"predefined.sql",foreground:"C700C7"}],colors:{[_.YtV]:"#FFFFFF",[_.By2]:"#292929",[f.vV]:"#292929",[f.H0]:"#292929"}};var S=i(46359),y=i(47612),w=i(5662),R=i(86723),L=i(25689),T=i(61394);class x{getIcon(e){const t=(0,T.HT)();let i=e.defaults;for(;L.L.isThemeIcon(i);){const e=t.getIcon(i.id);if(!e)return;i=e.defaults}return i}}var k=i(25893);const A="vs",N="vs-dark",I="hc-black",O="hc-light",D=S.O.as(_.FdG.ColorContribution),M=S.O.as(y.Fd.ThemingContribution);class P{constructor(e,t){this.semanticHighlighting=!1,this.themeData=t;const i=t.base;e.length>0?(F(e)?this.id=e:this.id=i+" "+e,this.themeName=e):(this.id=i,this.themeName=i),this.colors=null,this.defaultColors=Object.create(null),this._tokenTheme=null}get base(){return this.themeData.base}notifyBaseUpdated(){this.themeData.inherit&&(this.colors=null,this._tokenTheme=null)}getColors(){if(!this.colors){const e=new Map;for(const t in this.themeData.colors)e.set(t,r.Q1.fromHex(this.themeData.colors[t]));if(this.themeData.inherit){const t=U(this.themeData.base);for(const i in t.colors)e.has(i)||e.set(i,r.Q1.fromHex(t.colors[i]))}this.colors=e}return this.colors}getColor(e,t){const i=this.getColors().get(e);return i||(!1!==t?this.getDefault(e):void 0)}getDefault(e){let t=this.defaultColors[e];return t||(t=D.resolveDefaultColor(e,this),this.defaultColors[e]=t,t)}defines(e){return this.getColors().has(e)}get type(){switch(this.base){case A:return R.zM.LIGHT;case I:return R.zM.HIGH_CONTRAST_DARK;case O:return R.zM.HIGH_CONTRAST_LIGHT;default:return R.zM.DARK}}get tokenTheme(){if(!this._tokenTheme){let e=[],t=[];if(this.themeData.inherit){const i=U(this.themeData.base);e=i.rules,i.encodedTokensColors&&(t=i.encodedTokensColors)}const i=this.themeData.colors["editor.foreground"],s=this.themeData.colors["editor.background"];if(i||s){const t={token:""};i&&(t.foreground=i),s&&(t.background=s),e.push(t)}e=e.concat(this.themeData.rules),this.themeData.encodedTokensColors&&(t=this.themeData.encodedTokensColors),this._tokenTheme=u.createFromRawTokenTheme(e,t)}return this._tokenTheme}getTokenStyleMetadata(e,t,i){const s=this.tokenTheme._match([e].concat(t).join(".")).metadata,n=c.x.getForeground(s),r=c.x.getFontStyle(s);return{foreground:n,italic:Boolean(1&r),bold:Boolean(2&r),underline:Boolean(4&r),strikethrough:Boolean(8&r)}}}function F(e){return e===A||e===N||e===I||e===O}function U(e){switch(e){case A:return v;case N:return C;case I:return E;case O:return b}}function H(e){const t=U(e);return new P(e,t)}class B extends w.jG{constructor(){super(),this._onColorThemeChange=this._register(new o.vl),this.onDidColorThemeChange=this._onColorThemeChange.event,this._onProductIconThemeChange=this._register(new o.vl),this.onDidProductIconThemeChange=this._onProductIconThemeChange.event,this._environment=Object.create(null),this._builtInProductIconTheme=new x,this._autoDetectHighContrast=!0,this._knownThemes=new Map,this._knownThemes.set(A,H(A)),this._knownThemes.set(N,H(N)),this._knownThemes.set(I,H(I)),this._knownThemes.set(O,H(O));const e=this._register(function(e){const t=new w.Cm,i=t.add(new o.vl),n=(0,T.HT)();return t.add(n.onDidChange((()=>i.fire()))),e&&t.add(e.onDidProductIconThemeChange((()=>i.fire()))),{dispose:()=>t.dispose(),onDidChange:i.event,getCSS(){const t=e?e.getProductIconTheme():new x,i={},r=[],o=[];for(const e of n.getIcons()){const n=t.getIcon(e);if(!n)continue;const a=n.font,c=`--vscode-icon-${e.id}-font-family`,l=`--vscode-icon-${e.id}-content`;a?(i[a.id]=a.definition,o.push(`${c}: ${(0,s.yt)(a.id)};`,`${l}: '${n.fontCharacter}';`),r.push(`.codicon-${e.id}:before { content: '${n.fontCharacter}'; font-family: ${(0,s.yt)(a.id)}; }`)):(o.push(`${l}: '${n.fontCharacter}'; ${c}: 'codicon';`),r.push(`.codicon-${e.id}:before { content: '${n.fontCharacter}'; }`))}for(const e in i){const t=i[e],n=t.weight?`font-weight: ${t.weight};`:"",o=t.style?`font-style: ${t.style};`:"",a=t.src.map((e=>`${(0,s.Tf)(e.location)} format('${e.format}')`)).join(", ");r.push(`@font-face { src: ${a}; font-family: ${(0,s.yt)(e)};${n}${o} font-display: block; }`)}return r.push(`:root { ${o.join(" ")} }`),r.join("\n")}}}(this));this._codiconCSS=e.getCSS(),this._themeCSS="",this._allCSS=`${this._codiconCSS}\n${this._themeCSS}`,this._globalStyleElement=null,this._styleElements=[],this._colorMapOverride=null,this.setTheme(A),this._onOSSchemeChanged(),this._register(e.onDidChange((()=>{this._codiconCSS=e.getCSS(),this._updateCSS()}))),(0,n.Dy)(k.G,"(forced-colors: active)",(()=>{this._onOSSchemeChanged()}))}registerEditorContainer(e){return s.Cl(e)?this._registerShadowDomContainer(e):this._registerRegularEditorContainer()}_registerRegularEditorContainer(){return this._globalStyleElement||(this._globalStyleElement=s.li(void 0,(e=>{e.className="monaco-colors",e.textContent=this._allCSS})),this._styleElements.push(this._globalStyleElement)),w.jG.None}_registerShadowDomContainer(e){const t=s.li(e,(e=>{e.className="monaco-colors",e.textContent=this._allCSS}));return this._styleElements.push(t),{dispose:()=>{for(let e=0;e{t.base===e&&t.notifyBaseUpdated()})),this._theme.themeName===e&&this.setTheme(e)}getColorTheme(){return this._theme}setColorMapOverride(e){this._colorMapOverride=e,this._updateThemeOrColorMap()}setTheme(e){let t;t=this._knownThemes.has(e)?this._knownThemes.get(e):this._knownThemes.get(A),this._updateActualTheme(t)}_updateActualTheme(e){e&&this._theme!==e&&(this._theme=e,this._updateThemeOrColorMap())}_onOSSchemeChanged(){if(this._autoDetectHighContrast){const e=k.G.matchMedia("(forced-colors: active)").matches;if(e!==(0,R.Bb)(this._theme.type)){let t;t=(0,R.HD)(this._theme.type)?e?I:N:e?O:A,this._updateActualTheme(this._knownThemes.get(t))}}}setAutoDetectHighContrast(e){this._autoDetectHighContrast=e,this._onOSSchemeChanged()}_updateThemeOrColorMap(){const e=[],t={},i={addRule:i=>{t[i]||(e.push(i),t[i]=!0)}};M.getThemingParticipants().forEach((e=>e(this._theme,i,this._environment)));const s=[];for(const r of D.getColors()){const e=this._theme.getColor(r.id,!0);e&&s.push(`${(0,_.Bbc)(r.id)}: ${e.toString()};`)}i.addRule(`.monaco-editor, .monaco-diff-editor, .monaco-component { ${s.join("\n")} }`);const n=this._colorMapOverride||this._theme.tokenTheme.getColorMap();i.addRule(function(e){const t=[];for(let i=1,s=e.length;ie.textContent=this._allCSS))}getFileIconTheme(){return{hasFileIcons:!1,hasFolderIcons:!1,hidesExplorerArrows:!1}}getProductIconTheme(){return this._builtInProductIconTheme}}},10602:(e,t,i)=>{e.exports=i(2539)},10617:(e,t,i)=>{"use strict";var s=i(25890),n=i(18447),r=i(64383),o=i(31450),a=i(83069),c=i(36677),l=i(75326),h=i(60002),d=i(39286),u=i(91508);class g{constructor(e=!0){this.selectSubwords=e}provideSelectionRanges(e,t){const i=[];for(const s of t){const t=[];i.push(t),this.selectSubwords&&this._addInWordRanges(t,e,s),this._addWordRanges(t,e,s),this._addWhitespaceLine(t,e,s),t.push({range:e.getFullModelRange()})}return i}_addInWordRanges(e,t,i){const s=t.getWordAtPosition(i);if(!s)return;const{word:n,startColumn:r}=s,o=i.column-r;let a=o,l=o,h=0;for(;a>=0;a--){const e=n.charCodeAt(a);if(a!==o&&(95===e||45===e))break;if((0,u.Lv)(e)&&(0,u.Wv)(h))break;h=e}for(a+=1;l0&&0===t.getLineFirstNonWhitespaceColumn(i.lineNumber)&&0===t.getLineLastNonWhitespaceColumn(i.lineNumber)&&e.push({range:new c.Q(i.lineNumber,1,i.lineNumber,t.getLineMaxColumn(i.lineNumber))})}}var p,m=i(78209),f=i(27195),_=i(50091),v=i(56942),C=i(18938),E=i(631),b=i(79400),S=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},y=function(e,t){return function(i,s){t(i,s,e)}};class w{constructor(e,t){this.index=e,this.ranges=t}mov(e){const t=this.index+(e?1:-1);if(t<0||t>=this.ranges.length)return this;const i=new w(t,this.ranges);return i.ranges[t].equalsRange(this.ranges[this.index])?i.mov(e):i}}let R=class{static{p=this}static{this.ID="editor.contrib.smartSelectController"}static get(e){return e.getContribution(p.ID)}constructor(e,t){this._editor=e,this._languageFeaturesService=t,this._ignoreSelection=!1}dispose(){this._selectionListener?.dispose()}async run(e){if(!this._editor.hasModel())return;const t=this._editor.getSelections(),i=this._editor.getModel();if(this._state||await T(this._languageFeaturesService.selectionRangeProvider,i,t.map((e=>e.getPosition())),this._editor.getOption(114),n.XO.None).then((e=>{if(s.EI(e)&&e.length===t.length&&this._editor.hasModel()&&s.aI(this._editor.getSelections(),t,((e,t)=>e.equalsSelection(t)))){for(let i=0;ie.containsPosition(t[i].getStartPosition())&&e.containsPosition(t[i].getEndPosition()))),e[i].unshift(t[i]);this._state=e.map((e=>new w(0,e))),this._selectionListener?.dispose(),this._selectionListener=this._editor.onDidChangeCursorPosition((()=>{this._ignoreSelection||(this._selectionListener?.dispose(),this._state=void 0)}))}})),!this._state)return;this._state=this._state.map((t=>t.mov(e)));const r=this._state.map((e=>l.L.fromPositions(e.ranges[e.index].getStartPosition(),e.ranges[e.index].getEndPosition())));this._ignoreSelection=!0;try{this._editor.setSelections(r)}finally{this._ignoreSelection=!1}}};R=p=S([y(1,v.ILanguageFeaturesService)],R);class L extends o.ks{constructor(e,t){super(t),this._forward=e}async run(e,t){const i=R.get(t);i&&await i.run(this._forward)}}_.w.registerCommandAlias("editor.action.smartSelect.grow","editor.action.smartSelect.expand");async function T(e,t,i,n,o){const l=e.all(t).concat(new g(n.selectSubwords));1===l.length&&l.unshift(new d.n);const h=[],u=[];for(const a of l)h.push(Promise.resolve(a.provideSelectionRanges(t,i,o)).then((e=>{if(s.EI(e)&&e.length===i.length)for(let t=0;t{if(0===e.length)return[];e.sort(((e,t)=>a.y.isBefore(e.getStartPosition(),t.getStartPosition())?1:a.y.isBefore(t.getStartPosition(),e.getStartPosition())||a.y.isBefore(e.getEndPosition(),t.getEndPosition())?-1:a.y.isBefore(t.getEndPosition(),e.getEndPosition())?1:0));const i=[];let s;for(const t of e)(!s||c.Q.containsRange(t,s)&&!c.Q.equalsRange(t,s))&&(i.push(t),s=t);if(!n.selectLeadingAndTrailingWhitespace)return i;const r=[i[0]];for(let n=1;n{"use strict";i.d(t,{GM:()=>_,KL:()=>C,Kl:()=>d,Ob:()=>u,Ou:()=>f,XT:()=>p,Zb:()=>v,Zw:()=>g,bk:()=>m,dv:()=>h,wp:()=>E});var s=i(10350),n=i(25689),r=i(87289),o=i(78209),a=i(66261),c=i(61394);(0,a.x1A)("diffEditor.move.border","#8b8b8b9c",(0,o.kg)("diffEditor.move.border","The border color for text that got moved in the diff editor.")),(0,a.x1A)("diffEditor.moveActive.border","#FFA500",(0,o.kg)("diffEditor.moveActive.border","The active border color for text that got moved in the diff editor.")),(0,a.x1A)("diffEditor.unchangedRegionShadow",{dark:"#000000",light:"#737373BF",hcDark:"#000000",hcLight:"#737373BF"},(0,o.kg)("diffEditor.unchangedRegionShadow","The color of the shadow around unchanged region widgets."));const l=(0,c.pU)("diff-insert",s.W.add,(0,o.kg)("diffInsertIcon","Line decoration for inserts in the diff editor.")),h=(0,c.pU)("diff-remove",s.W.remove,(0,o.kg)("diffRemoveIcon","Line decoration for removals in the diff editor.")),d=r.kI.register({className:"line-insert",description:"line-insert",isWholeLine:!0,linesDecorationsClassName:"insert-sign "+n.L.asClassName(l),marginClassName:"gutter-insert"}),u=r.kI.register({className:"line-delete",description:"line-delete",isWholeLine:!0,linesDecorationsClassName:"delete-sign "+n.L.asClassName(h),marginClassName:"gutter-delete"}),g=r.kI.register({className:"line-insert",description:"line-insert",isWholeLine:!0,marginClassName:"gutter-insert"}),p=r.kI.register({className:"line-delete",description:"line-delete",isWholeLine:!0,marginClassName:"gutter-delete"}),m=r.kI.register({className:"char-insert",description:"char-insert",shouldFillLineOnLineBreak:!0}),f=r.kI.register({className:"char-insert",description:"char-insert",isWholeLine:!0}),_=r.kI.register({className:"char-insert diff-range-empty",description:"char-insert diff-range-empty"}),v=r.kI.register({className:"char-delete",description:"char-delete",shouldFillLineOnLineBreak:!0}),C=r.kI.register({className:"char-delete",description:"char-delete",isWholeLine:!0}),E=r.kI.register({className:"char-delete diff-range-empty",description:"char-delete diff-range-empty"})},10713:()=>{},10800:(e,t,i)=>{"use strict";i.d(t,{A:()=>n});var s=i(59284);const n=e=>s.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),s.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M13.5 8a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0M15 8A7 7 0 1 1 1 8a7 7 0 0 1 14 0M6.53 5.47a.75.75 0 0 0-1.06 1.06L6.94 8 5.47 9.47a.75.75 0 1 0 1.06 1.06L8 9.06l1.47 1.47a.75.75 0 1 0 1.06-1.06L9.06 8l1.47-1.47a.75.75 0 1 0-1.06-1.06L8 6.94z",clipRule:"evenodd"}))},10846:(e,t,i)=>{"use strict";var s=i(18447),n=i(26690),r=i(42522),o=i(5662),a=i(80301),c=i(36677),l=i(72466),h=i(56942),d=i(51173),u=i(48116),g=i(88415),p=i(96299),m=i(14055),f=i(54770),_=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},v=function(e,t){return function(i,s){t(i,s,e)}};class C{constructor(e,t,i,s,n,r){this.range=e,this.insertText=t,this.filterText=i,this.additionalTextEdits=s,this.command=n,this.completion=r}}let E=class extends o.mp{constructor(e,t,i,s,n,r){super(n.disposable),this.model=e,this.line=t,this.word=i,this.completionModel=s,this._suggestMemoryService=r}canBeReused(e,t,i){return this.model===e&&this.line===t&&this.word.word.length>0&&this.word.startColumn===i.startColumn&&this.word.endColumn=0&&h.resolve(s.XO.None)}return e}};E=_([v(5,g.GS)],E);let b=class extends o.jG{constructor(e,t,i,s){super(),this._languageFeatureService=e,this._clipboardService=t,this._suggestMemoryService=i,this._editorService=s,this._store.add(e.inlineCompletionsProvider.register("*",this))}async provideInlineCompletions(e,t,i,s){if(i.selectedSuggestionInfo)return;let n;for(const c of this._editorService.listCodeEditors())if(c.getModel()===e){n=c;break}if(!n)return;const r=n.getOption(90);if(u.r3.isAllOff(r))return;e.tokenization.tokenizeIfCheap(t.lineNumber);const o=e.tokenization.getLineTokens(t.lineNumber),a=o.getStandardTokenType(o.findTokenIndexAtOffset(Math.max(t.column-1-1,0)));if("inline"!==u.r3.valueFor(r,a))return;let l,h,g=e.getWordAtPosition(t);if(g?.word||(l=this._getTriggerCharacterInfo(e,t)),!g?.word&&!l)return;if(g||(g=e.getWordUntilPosition(t)),g.endColumn!==t.column)return;const f=e.getValueInRange(new c.Q(t.lineNumber,1,t.lineNumber,t.column));if(!l&&this._lastResult?.canBeReused(e,t.lineNumber,g)){const e=new d.O(f,t.column-this._lastResult.word.endColumn);this._lastResult.completionModel.lineContext=e,this._lastResult.acquire(),h=this._lastResult}else{const i=await(0,u.aR)(this._languageFeatureService.completionProvider,e,t,new u.l1(void 0,p.Y.createSuggestFilter(n).itemKind,l?.providers),l&&{triggerKind:1,triggerCharacter:l.ch},s);let r;i.needsClipboard&&(r=await this._clipboardService.readText());const o=new d.C(i.items,t.column,new d.O(f,0),m.S.None,n.getOption(119),n.getOption(113),{boostFullMatch:!1,firstMatchCanBeWeak:!1},r);h=new E(e,t.lineNumber,g,o,i,this._suggestMemoryService)}return this._lastResult=h,h}handleItemDidShow(e,t){t.completion.resolve(s.XO.None)}freeInlineCompletions(e){e.release()}_getTriggerCharacterInfo(e,t){const i=e.getValueInRange(c.Q.fromPositions({lineNumber:t.lineNumber,column:t.column-1},t)),s=new Set;for(const n of this._languageFeatureService.completionProvider.all(e))n.triggerCharacters?.includes(i)&&s.add(n);if(0!==s.size)return{providers:s,ch:i}}};b=_([v(0,h.ILanguageFeaturesService),v(1,f.h),v(2,g.GS),v(3,a.T)],b),(0,l.x)(b)},10920:(e,t,i)=>{"use strict";i.r(t),i.d(t,{IEditorWorkerService:()=>s});const s=(0,i(63591).u1)("editorWorkerService")},11007:(e,t,i)=>{"use strict";i.d(t,{xE:()=>d,vr:()=>h,h5:()=>u});var s=i(8597);const n=2e4;let r,o,a,c,l;function h(e){r=document.createElement("div"),r.className="monaco-aria-container";const t=()=>{const e=document.createElement("div");return e.className="monaco-alert",e.setAttribute("role","alert"),e.setAttribute("aria-atomic","true"),r.appendChild(e),e};o=t(),a=t();const i=()=>{const e=document.createElement("div");return e.className="monaco-status",e.setAttribute("aria-live","polite"),e.setAttribute("aria-atomic","true"),r.appendChild(e),e};c=i(),l=i(),e.appendChild(r)}function d(e){r&&(o.textContent!==e?(s.w_(a),g(o,e)):(s.w_(o),g(a,e)))}function u(e){r&&(c.textContent!==e?(s.w_(l),g(c,e)):(s.w_(c),g(l,e)))}function g(e,t){s.w_(e),t.length>n&&(t=t.substr(0,n)),e.textContent=t,e.style.visibility="hidden",e.style.visibility="visible"}},11272:(e,t,i)=>{"use strict";var s,n,r=i(80781),o=Object.defineProperty,a=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,l=Object.prototype.hasOwnProperty,h=(e,t,i,s)=>{if(t&&"object"===typeof t||"function"===typeof t)for(let n of c(t))l.call(e,n)||n===i||o(e,n,{get:()=>t[n],enumerable:!(s=a(t,n))||s.enumerable});return e},d={};h(d,s=r,"default"),n&&h(n,s,"default");var u=class{constructor(e,t,i){this._onDidChange=new d.Emitter,this._languageId=e,this.setOptions(t),this.setModeConfiguration(i)}get onDidChange(){return this._onDidChange.event}get languageId(){return this._languageId}get modeConfiguration(){return this._modeConfiguration}get diagnosticsOptions(){return this.options}get options(){return this._options}setOptions(e){this._options=e||Object.create(null),this._onDidChange.fire(this)}setDiagnosticsOptions(e){this.setOptions(e)}setModeConfiguration(e){this._modeConfiguration=e||Object.create(null),this._onDidChange.fire(this)}},g={validate:!0,lint:{compatibleVendorPrefixes:"ignore",vendorPrefix:"warning",duplicateProperties:"warning",emptyRules:"warning",importStatement:"ignore",boxModel:"ignore",universalSelector:"ignore",zeroUnits:"ignore",fontFaceProperties:"warning",hexColorLength:"error",argumentsInColorFunction:"error",unknownProperties:"warning",ieHack:"ignore",unknownVendorSpecificProperties:"ignore",propertyIgnoredDueToDisplay:"warning",important:"ignore",float:"ignore",idSelector:"ignore"},data:{useDefaultDataProvider:!0},format:{newlineBetweenSelectors:!0,newlineBetweenRules:!0,spaceAroundSelectorSeparator:!1,braceStyle:"collapse",maxPreserveNewLines:void 0,preserveNewLines:!0}},p={completionItems:!0,hovers:!0,documentSymbols:!0,definitions:!0,references:!0,documentHighlights:!0,rename:!0,colors:!0,foldingRanges:!0,diagnostics:!0,selectionRanges:!0,documentFormattingEdits:!0,documentRangeFormattingEdits:!0},m=new u("css",g,p),f=new u("scss",g,p),_=new u("less",g,p);function v(){return i.e(70225).then(i.bind(i,70225))}d.languages.css={cssDefaults:m,lessDefaults:_,scssDefaults:f},d.languages.onLanguage("less",(()=>{v().then((e=>e.setupMode(_)))})),d.languages.onLanguage("scss",(()=>{v().then((e=>e.setupMode(f)))})),d.languages.onLanguage("css",(()=>{v().then((e=>e.setupMode(m)))}))},11799:(e,t,i)=>{"use strict";i.d(t,{E:()=>d});var s=i(8597),n=i(72962),r=i(5646),o=i(42904),a=i(36921),c=i(41234),l=i(5662),h=i(631);i(62469);class d extends l.jG{constructor(e,t={}){let i,h;switch(super(),this._actionRunnerDisposables=this._register(new l.Cm),this.viewItemDisposables=this._register(new l.$w),this.triggerKeyDown=!1,this.focusable=!0,this._onDidBlur=this._register(new c.vl),this.onDidBlur=this._onDidBlur.event,this._onDidCancel=this._register(new c.vl({onWillAddFirstListener:()=>this.cancelHasListener=!0})),this.onDidCancel=this._onDidCancel.event,this.cancelHasListener=!1,this._onDidRun=this._register(new c.vl),this.onDidRun=this._onDidRun.event,this._onWillRun=this._register(new c.vl),this.onWillRun=this._onWillRun.event,this.options=t,this._context=t.context??null,this._orientation=this.options.orientation??0,this._triggerKeys={keyDown:this.options.triggerKeys?.keyDown??!1,keys:this.options.triggerKeys?.keys??[3,10]},this._hoverDelegate=t.hoverDelegate??this._register((0,o.bW)()),this.options.actionRunner?this._actionRunner=this.options.actionRunner:(this._actionRunner=new a.LN,this._actionRunnerDisposables.add(this._actionRunner)),this._actionRunnerDisposables.add(this._actionRunner.onDidRun((e=>this._onDidRun.fire(e)))),this._actionRunnerDisposables.add(this._actionRunner.onWillRun((e=>this._onWillRun.fire(e)))),this.viewItems=[],this.focusedItem=void 0,this.domNode=document.createElement("div"),this.domNode.className="monaco-action-bar",this._orientation){case 0:i=[15],h=[17];break;case 1:i=[16],h=[18],this.domNode.className+=" vertical"}this._register(s.ko(this.domNode,s.Bx.KEY_DOWN,(e=>{const t=new n.Z(e);let s=!0;const o="number"===typeof this.focusedItem?this.viewItems[this.focusedItem]:void 0;i&&(t.equals(i[0])||t.equals(i[1]))?s=this.focusPrevious():h&&(t.equals(h[0])||t.equals(h[1]))?s=this.focusNext():t.equals(9)&&this.cancelHasListener?this._onDidCancel.fire():t.equals(14)?s=this.focusFirst():t.equals(13)?s=this.focusLast():t.equals(2)&&o instanceof r.EH&&o.trapsArrowNavigation?s=this.focusNext(void 0,!0):this.isTriggerKeyEvent(t)?this._triggerKeys.keyDown?this.doTrigger(t):this.triggerKeyDown=!0:s=!1,s&&(t.preventDefault(),t.stopPropagation())}))),this._register(s.ko(this.domNode,s.Bx.KEY_UP,(e=>{const t=new n.Z(e);this.isTriggerKeyEvent(t)?(!this._triggerKeys.keyDown&&this.triggerKeyDown&&(this.triggerKeyDown=!1,this.doTrigger(t)),t.preventDefault(),t.stopPropagation()):(t.equals(2)||t.equals(1026)||t.equals(16)||t.equals(18)||t.equals(15)||t.equals(17))&&this.updateFocusedItem()}))),this.focusTracker=this._register(s.w5(this.domNode)),this._register(this.focusTracker.onDidBlur((()=>{s.bq()!==this.domNode&&s.QX(s.bq(),this.domNode)||(this._onDidBlur.fire(),this.previouslyFocusedItem=this.focusedItem,this.focusedItem=void 0,this.triggerKeyDown=!1)}))),this._register(this.focusTracker.onDidFocus((()=>this.updateFocusedItem()))),this.actionsList=document.createElement("ul"),this.actionsList.className="actions-container",this.options.highlightToggledItems&&this.actionsList.classList.add("highlight-toggled"),this.actionsList.setAttribute("role",this.options.ariaRole||"toolbar"),this.options.ariaLabel&&this.actionsList.setAttribute("aria-label",this.options.ariaLabel),this.domNode.appendChild(this.actionsList),e.appendChild(this.domNode)}refreshRole(){this.length()>=1?this.actionsList.setAttribute("role",this.options.ariaRole||"toolbar"):this.actionsList.setAttribute("role","presentation")}setFocusable(e){if(this.focusable=e,this.focusable){const e=this.viewItems.find((e=>e instanceof r.EH&&e.isEnabled()));e instanceof r.EH&&e.setFocusable(!0)}else this.viewItems.forEach((e=>{e instanceof r.EH&&e.setFocusable(!1)}))}isTriggerKeyEvent(e){let t=!1;return this._triggerKeys.keys.forEach((i=>{t=t||e.equals(i)})),t}updateFocusedItem(){for(let e=0;et.setActionContext(e)))}get actionRunner(){return this._actionRunner}set actionRunner(e){this._actionRunner=e,this._actionRunnerDisposables.clear(),this._actionRunnerDisposables.add(this._actionRunner.onDidRun((e=>this._onDidRun.fire(e)))),this._actionRunnerDisposables.add(this._actionRunner.onWillRun((e=>this._onWillRun.fire(e)))),this.viewItems.forEach((t=>t.actionRunner=e))}getContainer(){return this.domNode}getAction(e){if("number"===typeof e)return this.viewItems[e]?.action;if(s.sb(e)){for(;e.parentElement!==this.actionsList;){if(!e.parentElement)return;e=e.parentElement}for(let t=0;t{const i=document.createElement("li");let o;i.className="action-item",i.setAttribute("role","presentation");const a={hoverDelegate:this._hoverDelegate,...t,isTabList:"tablist"===this.options.ariaRole};this.options.actionViewItemProvider&&(o=this.options.actionViewItemProvider(e,a)),o||(o=new r.Z4(this.context,e,a)),this.options.allowContextMenu||this.viewItemDisposables.set(o,s.ko(i,s.Bx.CONTEXT_MENU,(e=>{s.fs.stop(e,!0)}))),o.actionRunner=this._actionRunner,o.setActionContext(this.context),o.render(i),this.focusable&&o instanceof r.EH&&0===this.viewItems.length&&o.setFocusable(!0),null===n||n<0||n>=this.actionsList.children.length?(this.actionsList.appendChild(i),this.viewItems.push(o)):(this.actionsList.insertBefore(i,this.actionsList.children[n]),this.viewItems.splice(n,0,o),n++)})),"number"===typeof this.focusedItem&&this.focus(this.focusedItem),this.refreshRole()}clear(){this.isEmpty()||(this.viewItems=(0,l.AS)(this.viewItems),this.viewItemDisposables.clearAndDisposeAll(),s.w_(this.actionsList),this.refreshRole())}length(){return this.viewItems.length}isEmpty(){return 0===this.viewItems.length}focus(e){let t,i=!1;if(void 0===e?i=!0:"number"===typeof e?t=e:"boolean"===typeof e&&(i=e),i&&"undefined"===typeof this.focusedItem){const e=this.viewItems.findIndex((e=>e.isEnabled()));this.focusedItem=-1===e?void 0:e,this.updateFocus(void 0,void 0,!0)}else void 0!==t&&(this.focusedItem=t),this.updateFocus(void 0,void 0,!0)}focusFirst(){return this.focusedItem=this.length()-1,this.focusNext(!0)}focusLast(){return this.focusedItem=0,this.focusPrevious(!0)}focusNext(e,t){if("undefined"===typeof this.focusedItem)this.focusedItem=this.viewItems.length-1;else if(this.viewItems.length<=1)return!1;const i=this.focusedItem;let s;do{if(!e&&this.options.preventLoopNavigation&&this.focusedItem+1>=this.viewItems.length)return this.focusedItem=i,!1;this.focusedItem=(this.focusedItem+1)%this.viewItems.length,s=this.viewItems[this.focusedItem]}while(this.focusedItem!==i&&(this.options.focusOnlyEnabledItems&&!s.isEnabled()||s.action.id===a.wv.ID));return this.updateFocus(void 0,void 0,t),!0}focusPrevious(e){if("undefined"===typeof this.focusedItem)this.focusedItem=0;else if(this.viewItems.length<=1)return!1;const t=this.focusedItem;let i;do{if(this.focusedItem=this.focusedItem-1,this.focusedItem<0){if(!e&&this.options.preventLoopNavigation)return this.focusedItem=t,!1;this.focusedItem=this.viewItems.length-1}i=this.viewItems[this.focusedItem]}while(this.focusedItem!==t&&(this.options.focusOnlyEnabledItems&&!i.isEnabled()||i.action.id===a.wv.ID));return this.updateFocus(!0),!0}updateFocus(e,t,i=!1){"undefined"===typeof this.focusedItem&&this.actionsList.focus({preventScroll:t}),void 0!==this.previouslyFocusedItem&&this.previouslyFocusedItem!==this.focusedItem&&this.viewItems[this.previouslyFocusedItem]?.blur();const s=void 0!==this.focusedItem?this.viewItems[this.focusedItem]:void 0;if(s){let n=!0;h.Tn(s.focus)||(n=!1),this.options.focusOnlyEnabledItems&&h.Tn(s.isEnabled)&&!s.isEnabled()&&(n=!1),s.action.id===a.wv.ID&&(n=!1),n?(i||this.previouslyFocusedItem!==this.focusedItem)&&(s.focus(e),this.previouslyFocusedItem=this.focusedItem):(this.actionsList.focus({preventScroll:t}),this.previouslyFocusedItem=void 0),n&&s.showHover?.()}}doTrigger(e){if("undefined"===typeof this.focusedItem)return;const t=this.viewItems[this.focusedItem];if(t instanceof r.EH){const i=null===t._context||void 0===t._context?e:t._context;this.run(t._action,i)}}async run(e,t){await this._actionRunner.run(e,t)}dispose(){this._context=void 0,this.viewItems=(0,l.AS)(this.viewItems),this.getContainer().remove(),super.dispose()}}},12143:(e,t,i)=>{"use strict";i.d(t,{w:()=>c});var s=i(90766),n=i(64383),r=i(41234),o=i(5662);class a{constructor(e,t,i){this.value=e,this.isComplete=t,this.hasLoadingMessage=i}}class c extends o.jG{constructor(e,t){super(),this._editor=e,this._computer=t,this._onResult=this._register(new r.vl),this.onResult=this._onResult.event,this._firstWaitScheduler=this._register(new s.uC((()=>this._triggerAsyncComputation()),0)),this._secondWaitScheduler=this._register(new s.uC((()=>this._triggerSyncComputation()),0)),this._loadingMessageScheduler=this._register(new s.uC((()=>this._triggerLoadingMessage()),0)),this._state=0,this._asyncIterable=null,this._asyncIterableDone=!1,this._result=[]}dispose(){this._asyncIterable&&(this._asyncIterable.cancel(),this._asyncIterable=null),super.dispose()}get _hoverTime(){return this._editor.getOption(60).delay}get _firstWaitTime(){return this._hoverTime/2}get _secondWaitTime(){return this._hoverTime-this._firstWaitTime}get _loadingMessageTime(){return 3*this._hoverTime}_setState(e,t=!0){this._state=e,t&&this._fireResult()}_triggerAsyncComputation(){this._setState(2),this._secondWaitScheduler.schedule(this._secondWaitTime),this._computer.computeAsync?(this._asyncIterableDone=!1,this._asyncIterable=(0,s.bI)((e=>this._computer.computeAsync(e))),(async()=>{try{for await(const e of this._asyncIterable)e&&(this._result.push(e),this._fireResult());this._asyncIterableDone=!0,3!==this._state&&4!==this._state||this._setState(0)}catch(e){(0,n.dz)(e)}})()):this._asyncIterableDone=!0}_triggerSyncComputation(){this._computer.computeSync&&(this._result=this._result.concat(this._computer.computeSync())),this._setState(this._asyncIterableDone?0:3)}_triggerLoadingMessage(){3===this._state&&this._setState(4)}_fireResult(){if(1===this._state||2===this._state)return;const e=0===this._state,t=4===this._state;this._onResult.fire(new a(this._result.slice(0),e,t))}start(e){if(0===e)0===this._state&&(this._setState(1),this._firstWaitScheduler.schedule(this._firstWaitTime),this._loadingMessageScheduler.schedule(this._loadingMessageTime));else switch(this._state){case 0:this._triggerAsyncComputation(),this._secondWaitScheduler.cancel(),this._triggerSyncComputation();break;case 2:this._secondWaitScheduler.cancel(),this._triggerSyncComputation()}}cancel(){this._firstWaitScheduler.cancel(),this._secondWaitScheduler.cancel(),this._loadingMessageScheduler.cancel(),this._asyncIterable&&(this._asyncIterable.cancel(),this._asyncIterable=null),this._result=[],this._setState(0,!1)}}},12296:(e,t,i)=>{"use strict";function s(e,t){const i=e.getCount(),s=e.findTokenIndexAtOffset(t),r=e.getLanguageId(s);let o=s;for(;o+10&&e.getLanguageId(a-1)===r;)a--;return new n(e,r,a,o+1,e.getStartOffset(a),e.getEndOffset(o))}i.d(t,{BQ:()=>s,Yo:()=>r});class n{constructor(e,t,i,s,n,r){this._scopedLineTokensBrand=void 0,this._actual=e,this.languageId=t,this._firstTokenIndex=i,this._lastTokenIndex=s,this.firstCharOffset=n,this._lastCharOffset=r,this.languageIdCodec=e.languageIdCodec}getLineContent(){return this._actual.getLineContent().substring(this.firstCharOffset,this._lastCharOffset)}getLineLength(){return this._lastCharOffset-this.firstCharOffset}getActualLineContentBefore(e){return this._actual.getLineContent().substring(0,this.firstCharOffset+e)}getTokenCount(){return this._lastTokenIndex-this._firstTokenIndex}findTokenIndexAtOffset(e){return this._actual.findTokenIndexAtOffset(e+this.firstCharOffset)-this._firstTokenIndex}getStandardTokenType(e){return this._actual.getStandardTokenType(e+this._firstTokenIndex)}toIViewLineTokens(){return this._actual.sliceAndInflate(this.firstCharOffset,this._lastCharOffset,0)}}function r(e){return 0!==(3&e)}},12437:(e,t,i)=>{"use strict";i.d(t,{o:()=>h});var s=i(6921),n=i(5662),r=i(34326),o=i(16223),a=i(87119),c=i(47612),l=i(11007);class h{constructor(e){this.options=e,this.rangeHighlightDecorationId=void 0}provide(e,t,i){const s=new n.Cm;e.canAcceptInBackground=!!this.options?.canAcceptInBackground,e.matchOnLabel=e.matchOnDescription=e.matchOnDetail=e.sortByLabel=!1;const r=s.add(new n.HE);return r.value=this.doProvide(e,t,i),s.add(this.onDidActiveTextEditorControlChange((()=>{r.value=void 0,r.value=this.doProvide(e,t)}))),s}doProvide(e,t,i){const o=new n.Cm,a=this.activeTextEditorControl;if(a&&this.canProvideWithTextEditor(a)){const c={editor:a},l=(0,r.jA)(a);if(l){let e=a.saveViewState()??void 0;o.add(l.onDidChangeCursorPosition((()=>{e=a.saveViewState()??void 0}))),c.restoreViewState=()=>{e&&a===this.activeTextEditorControl&&a.restoreViewState(e)},o.add((0,s.P)(t.onCancellationRequested)((()=>c.restoreViewState?.())))}o.add((0,n.s)((()=>this.clearDecorations(a)))),o.add(this.provideWithTextEditor(c,e,t,i))}else o.add(this.provideWithoutTextEditor(e,t));return o}canProvideWithTextEditor(e){return!0}gotoLocation({editor:e},t){e.setSelection(t.range,"code.jump"),e.revealRangeInCenter(t.range,0),t.preserveFocus||e.focus();const i=e.getModel();i&&"getLineContent"in i&&(0,l.h5)(`${i.getLineContent(t.range.startLineNumber)}`)}getModel(e){return(0,r.Np)(e)?e.getModel()?.modified:e.getModel()}addDecorations(e,t){e.changeDecorations((e=>{const i=[];this.rangeHighlightDecorationId&&(i.push(this.rangeHighlightDecorationId.overviewRulerDecorationId),i.push(this.rangeHighlightDecorationId.rangeHighlightId),this.rangeHighlightDecorationId=void 0);const s=[{range:t,options:{description:"quick-access-range-highlight",className:"rangeHighlight",isWholeLine:!0}},{range:t,options:{description:"quick-access-range-highlight-overview",overviewRuler:{color:(0,c.Yf)(a.vp),position:o.A5.Full}}}],[n,r]=e.deltaDecorations(i,s);this.rangeHighlightDecorationId={rangeHighlightId:n,overviewRulerDecorationId:r}}))}clearDecorations(e){const t=this.rangeHighlightDecorationId;t&&(e.changeDecorations((e=>{e.deltaDecorations([t.overviewRulerDecorationId,t.rangeHighlightId],[])})),this.rangeHighlightDecorationId=void 0)}}},12529:(e,t,i)=>{var s=i(43238),n=i(32112);e.exports=function(e,t){return t.length<2?e:s(e,n(t,0,-1))}},13850:(e,t,i)=>{"use strict";i.d(t,{OI:()=>v,Rl:()=>b,Yd:()=>f,ZX:()=>E,eP:()=>u,lk:()=>l,t:()=>y,y0:()=>d,yQ:()=>p});i(41234);var s=i(5662),n=i(49154),r=i(22311),o=i(87958),a=i(94958),c=i(51241);function l(e){return new h(e)}class h extends n.zV{constructor(e){super(),this.value=e}get debugName(){return this.toString()}get(){return this.value}addObserver(e){}removeObserver(e){}toString(){return`Const: ${this.value}`}}function d(...e){let t,i,s;return 3===e.length?[t,i,s]=e:[i,s]=e,new g(new r.nA(t,void 0,s),i,s,(()=>g.globalTransaction),c.nx)}function u(e,t,i){return new g(new r.nA(e.owner,e.debugName,e.debugReferenceFn??i),t,i,(()=>g.globalTransaction),e.equalsFn??c.nx)}class g extends n.ZK{constructor(e,t,i,s,r){super(),this._debugNameData=e,this.event=t,this._getValue=i,this._getTransaction=s,this._equalityComparator=r,this.hasValue=!1,this.handleEvent=e=>{const t=this._getValue(e),i=this.value,s=!this.hasValue||!this._equalityComparator(i,t);let r=!1;s&&(this.value=t,this.hasValue&&(r=!0,(0,n.PO)(this._getTransaction(),(e=>{(0,a.tZ)()?.handleFromEventObservableTriggered(this,{oldValue:i,newValue:t,change:void 0,didChange:s,hadValue:this.hasValue});for(const t of this.observers)e.updateObserver(t,this),t.handleChange(this,void 0)}),(()=>{const e=this.getDebugName();return"Event fired"+(e?`: ${e}`:"")}))),this.hasValue=!0),r||(0,a.tZ)()?.handleFromEventObservableTriggered(this,{oldValue:i,newValue:t,change:void 0,didChange:s,hadValue:this.hasValue})}}getDebugName(){return this._debugNameData.getDebugName(this)}get debugName(){const e=this.getDebugName();return"From Event"+(e?`: ${e}`:"")}onFirstObserverAdded(){this.subscription=this.event(this.handleEvent)}onLastObserverRemoved(){this.subscription.dispose(),this.subscription=void 0,this.hasValue=!1,this.value=void 0}get(){if(this.subscription)return this.hasValue||this.handleEvent(void 0),this.value;return this._getValue(void 0)}}function p(e,t){return new m(e,t)}!function(e){e.Observer=g,e.batchEventsGlobally=function(e,t){let i=!1;void 0===g.globalTransaction&&(g.globalTransaction=e,i=!0);try{t()}finally{i&&(g.globalTransaction=void 0)}}}(d||(d={}));class m extends n.ZK{constructor(e,t){super(),this.debugName=e,this.event=t,this.handleEvent=()=>{(0,n.Rn)((e=>{for(const t of this.observers)e.updateObserver(t,this),t.handleChange(this,void 0)}),(()=>this.debugName))}}onFirstObserverAdded(){this.subscription=this.event(this.handleEvent)}onLastObserverRemoved(){this.subscription.dispose(),this.subscription=void 0}get(){}}function f(e){return"string"===typeof e?new _(e):new _(void 0,e)}class _ extends n.ZK{get debugName(){return new r.nA(this._owner,this._debugName,void 0).getDebugName(this)??"Observable Signal"}toString(){return this.debugName}constructor(e,t){super(),this._debugName=e,this._owner=t}trigger(e,t){if(e)for(const i of this.observers)e.updateObserver(i,this),i.handleChange(this,t);else(0,n.Rn)((e=>{this.trigger(e,t)}),(()=>`Trigger signal ${this.debugName}`))}get(){}}function v(e,t){const i=new C(!0,t);return e.addObserver(i),t?t(e.get()):e.reportChanges(),(0,s.s)((()=>{e.removeObserver(i)}))}(0,n.FB)((function(e){const t=new C(!1,void 0);return e.addObserver(t),(0,s.s)((()=>{e.removeObserver(t)}))})),(0,n.Bm)(v);class C{constructor(e,t){this._forceRecompute=e,this._handleValue=t,this._counter=0}beginUpdate(e){this._counter++}endUpdate(e){this._counter--,0===this._counter&&this._forceRecompute&&(this._handleValue?this._handleValue(e.get()):e.reportChanges())}handlePossibleChange(e){}handleChange(e,t){}}function E(e,t){let i;return(0,o.C)({owner:e,debugReferenceFn:t},(e=>(i=t(e,i),i)))}function b(e,t,i,s){let n=new S(i,s);return(0,o.C)({debugReferenceFn:i,owner:e,onLastObserverRemoved:()=>{n.dispose(),n=new S(i)}},(e=>(n.setItems(t.read(e)),n.getItems())))}class S{constructor(e,t){this._map=e,this._keySelector=t,this._cache=new Map,this._items=[]}dispose(){this._cache.forEach((e=>e.store.dispose())),this._cache.clear()}setItems(e){const t=[],i=new Set(this._cache.keys());for(const n of e){const e=this._keySelector?this._keySelector(n):n;let r=this._cache.get(e);if(r)i.delete(e);else{const t=new s.Cm;r={out:this._map(n,t),store:t},this._cache.set(e,r)}t.push(r.out)}for(const s of i){this._cache.get(s).store.dispose(),this._cache.delete(s)}this._items=t}getItems(){return this._items}}function y(e,t){return E(e,((e,i)=>i??t(e)))}},13864:(e,t,i)=>{"use strict";i.d(t,{P:()=>C,v:()=>E});var s=i(16223),n=i(87289),r=i(62083),o=i(78209),a=i(66261),c=i(47612);const l=(0,a.x1A)("editor.wordHighlightBackground",{dark:"#575757B8",light:"#57575740",hcDark:null,hcLight:null},o.kg("wordHighlight","Background color of a symbol during read-access, like reading a variable. The color must not be opaque so as not to hide underlying decorations."),!0);(0,a.x1A)("editor.wordHighlightStrongBackground",{dark:"#004972B8",light:"#0e639c40",hcDark:null,hcLight:null},o.kg("wordHighlightStrong","Background color of a symbol during write-access, like writing to a variable. The color must not be opaque so as not to hide underlying decorations."),!0),(0,a.x1A)("editor.wordHighlightTextBackground",l,o.kg("wordHighlightText","Background color of a textual occurrence for a symbol. The color must not be opaque so as not to hide underlying decorations."),!0);const h=(0,a.x1A)("editor.wordHighlightBorder",{light:null,dark:null,hcDark:a.buw,hcLight:a.buw},o.kg("wordHighlightBorder","Border color of a symbol during read-access, like reading a variable."));(0,a.x1A)("editor.wordHighlightStrongBorder",{light:null,dark:null,hcDark:a.buw,hcLight:a.buw},o.kg("wordHighlightStrongBorder","Border color of a symbol during write-access, like writing to a variable.")),(0,a.x1A)("editor.wordHighlightTextBorder",h,o.kg("wordHighlightTextBorder","Border color of a textual occurrence for a symbol."));const d=(0,a.x1A)("editorOverviewRuler.wordHighlightForeground","#A0A0A0CC",o.kg("overviewRulerWordHighlightForeground","Overview ruler marker color for symbol highlights. The color must not be opaque so as not to hide underlying decorations."),!0),u=(0,a.x1A)("editorOverviewRuler.wordHighlightStrongForeground","#C0A0C0CC",o.kg("overviewRulerWordHighlightStrongForeground","Overview ruler marker color for write-access symbol highlights. The color must not be opaque so as not to hide underlying decorations."),!0),g=(0,a.x1A)("editorOverviewRuler.wordHighlightTextForeground",a.z5H,o.kg("overviewRulerWordHighlightTextForeground","Overview ruler marker color of a textual occurrence for a symbol. The color must not be opaque so as not to hide underlying decorations."),!0),p=n.kI.register({description:"word-highlight-strong",stickiness:1,className:"wordHighlightStrong",overviewRuler:{color:(0,c.Yf)(u),position:s.A5.Center},minimap:{color:(0,c.Yf)(a.Xp1),position:1}}),m=n.kI.register({description:"word-highlight-text",stickiness:1,className:"wordHighlightText",overviewRuler:{color:(0,c.Yf)(g),position:s.A5.Center},minimap:{color:(0,c.Yf)(a.Xp1),position:1}}),f=n.kI.register({description:"selection-highlight-overview",stickiness:1,className:"selectionHighlight",overviewRuler:{color:(0,c.Yf)(a.z5H),position:s.A5.Center},minimap:{color:(0,c.Yf)(a.Xp1),position:1}}),_=n.kI.register({description:"selection-highlight",stickiness:1,className:"selectionHighlight"}),v=n.kI.register({description:"word-highlight",stickiness:1,className:"wordHighlight",overviewRuler:{color:(0,c.Yf)(d),position:s.A5.Center},minimap:{color:(0,c.Yf)(a.Xp1),position:1}});function C(e){return e===r.Kb.Write?p:e===r.Kb.Text?m:v}function E(e){return e?_:f}(0,c.zy)(((e,t)=>{const i=e.getColor(a.QwA);i&&t.addRule(`.monaco-editor .selectionHighlight { background-color: ${i.transparent(.5)}; }`)}))},14055:(e,t,i)=>{"use strict";i.d(t,{S:()=>o});var s=i(25890),n=i(36677),r=i(39286);class o{static{this.None=new class extends o{distance(){return 0}}}static async create(e,t){if(!t.getOption(119).localityBonus)return o.None;if(!t.hasModel())return o.None;const i=t.getModel(),a=t.getPosition();if(!e.canComputeWordRanges(i.uri))return o.None;const[c]=await(new r.n).provideSelectionRanges(i,[a]);if(0===c.length)return o.None;const l=await e.computeWordRanges(i.uri,c[0].range);if(!l)return o.None;const h=i.getWordUntilPosition(a);return delete l[h.word],new class extends o{distance(e,i){if(!a.equals(t.getPosition()))return 0;if(17===i.kind)return 2<<20;const r="string"===typeof i.label?i.label:i.label.label,o=l[r];if((0,s.Ct)(o))return 2<<20;const h=(0,s.El)(o,n.Q.fromPositions(e),n.Q.compareRangesUsingStarts),d=h>=0?o[h]:o[Math.max(0,~h-1)];let u=c.length;for(const t of c){if(!n.Q.containsRange(t.range,d))break;u-=1}return u}}}}},14614:(e,t,i)=>{"use strict";var s=i(90766),n=i(18447),r=i(64383),o=i(16980),a=i(5662),c=i(36456),l=i(98067),h=i(89403),d=i(78381),u=i(79400),g=i(31450),p=i(87289),m=i(32500),f=i(56942),_=i(37927),v=i(25890),C=i(631),E=i(36677),b=i(23750),S=i(50091);class y{constructor(e,t){this._link=e,this._provider=t}toJSON(){return{range:this.range,url:this.url,tooltip:this.tooltip}}get range(){return this._link.range}get url(){return this._link.url}get tooltip(){return this._link.tooltip}async resolve(e){return this._link.url?this._link.url:"function"===typeof this._provider.resolveLink?Promise.resolve(this._provider.resolveLink(this._link,e)).then((t=>(this._link=t||this._link,this._link.url?this.resolve(e):Promise.reject(new Error("missing"))))):Promise.reject(new Error("missing"))}}class w{constructor(e){this._disposables=new a.Cm;let t=[];for(const[i,s]of e){const e=i.links.map((e=>new y(e,s)));t=w._union(t,e),(0,a.Xm)(i)&&this._disposables.add(i)}this.links=t}dispose(){this._disposables.dispose(),this.links.length=0}static _union(e,t){const i=[];let s,n,r,o;for(s=0,r=0,n=e.length,o=t.length;sPromise.resolve(e.provideLinks(t,i)).then((t=>{t&&(s[n]=[t,e])}),r.M_)));return Promise.all(n).then((()=>{const e=new w((0,v.Yc)(s));return i.isCancellationRequested?(e.dispose(),new w([])):e}))}S.w.registerCommand("_executeLinkProvider",(async(e,...t)=>{let[i,s]=t;(0,C.j)(i instanceof u.r),"number"!==typeof s&&(s=0);const{linkProvider:r}=e.get(f.ILanguageFeaturesService),o=e.get(b.IModelService).getModel(i);if(!o)return[];const a=await R(r,o,n.XO.None);if(!a)return[];for(let l=0;l=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},N=function(e,t){return function(i,s){t(i,s,e)}};let I=class extends a.jG{static{L=this}static{this.ID="editor.linkDetector"}static get(e){return e.getContribution(L.ID)}constructor(e,t,i,n,r){super(),this.editor=e,this.openerService=t,this.notificationService=i,this.languageFeaturesService=n,this.providers=this.languageFeaturesService.linkProvider,this.debounceInformation=r.for(this.providers,"Links",{min:1e3,max:4e3}),this.computeLinks=this._register(new s.uC((()=>this.computeLinksNow()),1e3)),this.computePromise=null,this.activeLinksList=null,this.currentOccurrences={},this.activeLinkDecorationId=null;const o=this._register(new _.gi(e));this._register(o.onMouseMoveOrRelevantKeyDown((([e,t])=>{this._onEditorMouseMove(e,t)}))),this._register(o.onExecute((e=>{this.onEditorMouseUp(e)}))),this._register(o.onCancel((e=>{this.cleanUpActiveLinkDecoration()}))),this._register(e.onDidChangeConfiguration((e=>{e.hasChanged(71)&&(this.updateDecorations([]),this.stop(),this.computeLinks.schedule(0))}))),this._register(e.onDidChangeModelContent((e=>{this.editor.hasModel()&&this.computeLinks.schedule(this.debounceInformation.get(this.editor.getModel()))}))),this._register(e.onDidChangeModel((e=>{this.currentOccurrences={},this.activeLinkDecorationId=null,this.stop(),this.computeLinks.schedule(0)}))),this._register(e.onDidChangeModelLanguage((e=>{this.stop(),this.computeLinks.schedule(0)}))),this._register(this.providers.onDidChange((e=>{this.stop(),this.computeLinks.schedule(0)}))),this.computeLinks.schedule(0)}async computeLinksNow(){if(!this.editor.hasModel()||!this.editor.getOption(71))return;const e=this.editor.getModel();if(!e.isTooLargeForSyncing()&&this.providers.has(e)){this.activeLinksList&&(this.activeLinksList.dispose(),this.activeLinksList=null),this.computePromise=(0,s.SS)((t=>R(this.providers,e,t)));try{const t=new d.W(!1);if(this.activeLinksList=await this.computePromise,this.debounceInformation.update(e,t.elapsed()),e.isDisposed())return;this.updateDecorations(this.activeLinksList.links)}catch(t){(0,r.dz)(t)}finally{this.computePromise=null}}}updateDecorations(e){const t="altKey"===this.editor.getOption(78),i=[],s=Object.keys(this.currentOccurrences);for(const r of s){const e=this.currentOccurrences[r];i.push(e.decorationId)}const n=[];if(e)for(const r of e)n.push(M.decoration(r,t));this.editor.changeDecorations((t=>{const s=t.deltaDecorations(i,n);this.currentOccurrences={},this.activeLinkDecorationId=null;for(let i=0,n=s.length;i{t.activate(e,i),this.activeLinkDecorationId=t.decorationId}))}else this.cleanUpActiveLinkDecoration()}cleanUpActiveLinkDecoration(){const e="altKey"===this.editor.getOption(78);if(this.activeLinkDecorationId){const t=this.currentOccurrences[this.activeLinkDecorationId];t&&this.editor.changeDecorations((i=>{t.deactivate(i,e)})),this.activeLinkDecorationId=null}}onEditorMouseUp(e){if(!this.isEnabled(e))return;const t=this.getLinkOccurrence(e.target.position);t&&this.openLinkOccurrence(t,e.hasSideBySideModifier,!0)}openLinkOccurrence(e,t,i=!1){if(!this.openerService)return;const{link:s}=e;s.resolve(n.XO.None).then((e=>{if("string"===typeof e&&this.editor.hasModel()){const t=this.editor.getModel().uri;if(t.scheme===c.ny.file&&e.startsWith(`${c.ny.file}:`)){const i=u.r.parse(e);if(i.scheme===c.ny.file){const s=h.su(i);let n=null;s.startsWith("/./")||s.startsWith("\\.\\")?n=`.${s.substr(1)}`:(s.startsWith("//./")||s.startsWith("\\\\.\\"))&&(n=`.${s.substr(2)}`),n&&(e=h.uJ(t,n))}}}return this.openerService.open(e,{openToSide:t,fromUserGesture:i,allowContributedOpeners:!0,allowCommands:!0,fromWorkspace:!0})}),(e=>{const t=e instanceof Error?e.message:e;"invalid"===t?this.notificationService.warn(T.kg("invalid.url","Failed to open this link because it is not well-formed: {0}",s.url.toString())):"missing"===t?this.notificationService.warn(T.kg("missing.url","Failed to open this link because its target is missing.")):(0,r.dz)(e)}))}getLinkOccurrence(e){if(!this.editor.hasModel()||!e)return null;const t=this.editor.getModel().getDecorationsInRange({startLineNumber:e.lineNumber,startColumn:e.column,endLineNumber:e.lineNumber,endColumn:e.column},0,!0);for(const i of t){const e=this.currentOccurrences[i.id];if(e)return e}return null}isEnabled(e,t){return Boolean(6===e.target.type&&(e.hasTriggerModifier||t&&t.keyCodeIsTriggerKey))}stop(){this.computeLinks.cancel(),this.activeLinksList&&(this.activeLinksList?.dispose(),this.activeLinksList=null),this.computePromise&&(this.computePromise.cancel(),this.computePromise=null)}dispose(){super.dispose(),this.stop()}};I=L=A([N(1,k.C),N(2,x.Ot),N(3,f.ILanguageFeaturesService),N(4,m.ILanguageFeatureDebounceService)],I);const O=p.kI.register({description:"detected-link",stickiness:1,collapseOnReplaceEdit:!0,inlineClassName:"detected-link"}),D=p.kI.register({description:"detected-link-active",stickiness:1,collapseOnReplaceEdit:!0,inlineClassName:"detected-link-active"});class M{static decoration(e,t){return{range:e.range,options:M._getOptions(e,t,!1)}}static _getOptions(e,t,i){const s={...i?D:O};return s.hoverMessage=function(e,t){const i=e.url&&/^command:/i.test(e.url.toString()),s=e.tooltip?e.tooltip:i?T.kg("links.navigate.executeCmd","Execute command"):T.kg("links.navigate.follow","Follow link"),n=t?l.zx?T.kg("links.navigate.kb.meta.mac","cmd + click"):T.kg("links.navigate.kb.meta","ctrl + click"):l.zx?T.kg("links.navigate.kb.alt.mac","option + click"):T.kg("links.navigate.kb.alt","alt + click");if(e.url){let t="";if(/^command:/i.test(e.url.toString())){const i=e.url.toString().match(/^command:([^?#]+)/);if(i){const e=i[1];t=T.kg("tooltip.explanation","Execute command {0}",e)}}return new o.Bc("",!0).appendLink(e.url.toString(!0).replace(/ /g,"%20"),s,t).appendMarkdown(` (${n})`)}return(new o.Bc).appendText(`${s} (${n})`)}(e,t),s}constructor(e,t){this.link=e,this.decorationId=t}activate(e,t){e.changeDecorationOptions(this.decorationId,M._getOptions(this.link,t,!0))}deactivate(e,t){e.changeDecorationOptions(this.decorationId,M._getOptions(this.link,t,!1))}}class P extends g.ks{constructor(){super({id:"editor.action.openLink",label:T.kg("label","Open Link"),alias:"Open Link",precondition:void 0})}run(e,t){const i=I.get(t);if(!i)return;if(!t.hasModel())return;const s=t.getSelections();for(const n of s){const e=i.getLinkOccurrence(n.getEndPosition());e&&i.openLinkOccurrence(e,!1)}}}(0,g.HW)(I.ID,I,1),(0,g.Fl)(P)},14718:(e,t,i)=>{"use strict";i.d(t,{N:()=>o,v:()=>r});var s=i(84040);const n=[];function r(e,t,i){t instanceof s.d||(t=new s.d(t,[],Boolean(i))),n.push([e,t])}function o(){return n}},14720:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"scheme",extensions:[".scm",".ss",".sch",".rkt"],aliases:["scheme","Scheme"],loader:()=>i.e(67574).then(i.bind(i,67574))})},14853:e=>{e.exports=function(){function e(e){return String(e.$value)}return e.isScalar=!0,e}},15040:(e,t,i)=>{"use strict";var s=i(31450),n=i(28291),r=i(60002),o=i(78209);class a extends s.ks{constructor(){super({id:"expandLineSelection",label:o.kg("expandLineSelection","Expand Line Selection"),alias:"Expand Line Selection",precondition:void 0,kbOpts:{weight:0,kbExpr:r.R.textInputFocus,primary:2090}})}run(e,t,i){if(i=i||{},!t.hasModel())return;const s=t._getViewModel();s.model.pushStackElement(),s.setCursorStates(i.source,3,n.c.expandLineSelection(s,s.getCursorStates())),s.revealAllCursors(i.source,!0)}}(0,s.Fl)(a)},15092:(e,t,i)=>{"use strict";i.d(t,{iP:()=>a,iu:()=>n,q2:()=>o,tA:()=>r,ui:()=>c});var s=i(75326);class n{constructor(e,t,i=!1){this._range=e,this._text=t,this.insertsAutoWhitespace=i}getEditOperations(e,t){t.addTrackedEditOperation(this._range,this._text)}computeCursorState(e,t){const i=t.getInverseEditOperations()[0].range;return s.L.fromPositions(i.getEndPosition())}}class r{constructor(e,t){this._range=e,this._text=t}getEditOperations(e,t){t.addTrackedEditOperation(this._range,this._text)}computeCursorState(e,t){const i=t.getInverseEditOperations()[0].range;return s.L.fromRange(i,0)}}class o{constructor(e,t,i=!1){this._range=e,this._text=t,this.insertsAutoWhitespace=i}getEditOperations(e,t){t.addTrackedEditOperation(this._range,this._text)}computeCursorState(e,t){const i=t.getInverseEditOperations()[0].range;return s.L.fromPositions(i.getStartPosition())}}class a{constructor(e,t,i,s,n=!1){this._range=e,this._text=t,this._columnDeltaOffset=s,this._lineNumberDeltaOffset=i,this.insertsAutoWhitespace=n}getEditOperations(e,t){t.addTrackedEditOperation(this._range,this._text)}computeCursorState(e,t){const i=t.getInverseEditOperations()[0].range;return s.L.fromPositions(i.getEndPosition().delta(this._lineNumberDeltaOffset,this._columnDeltaOffset))}}class c{constructor(e,t,i,s=!1){this._range=e,this._text=t,this._initialSelection=i,this._forceMoveMarkers=s,this._selectionId=null}getEditOperations(e,t){t.addTrackedEditOperation(this._range,this._text,this._forceMoveMarkers),this._selectionId=t.trackSelection(this._initialSelection)}computeCursorState(e,t){return t.getTrackedSelection(this._selectionId)}}},15482:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"aes",extensions:[".aes"],aliases:["aes","sophia","Sophia"],loader:()=>i.e(65988).then(i.bind(i,65988))})},15600:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"csharp",extensions:[".cs",".csx",".cake"],aliases:["C#","csharp"],loader:()=>i.e(52518).then(i.bind(i,52518))})},16122:(e,t,i)=>{"use strict";i.d(t,{u:()=>l});var s=i(23971);const n=(e,t,i)=>{if(e&&"reportValidity"in e){const n=(0,s.Jt)(i,t);e.setCustomValidity(n&&n.message||""),e.reportValidity()}},r=(e,t)=>{for(const i in t.fields){const s=t.fields[i];s&&s.ref&&"reportValidity"in s.ref?n(s.ref,i,e):s.refs&&s.refs.forEach((t=>n(t,i,e)))}},o=(e,t)=>{t.shouldUseNativeValidation&&r(e,t);const i={};for(const n in e){const r=(0,s.Jt)(t.fields,n),o=Object.assign(e[n]||{},{ref:r&&r.ref});if(a(t.names||Object.keys(e),n)){const e=Object.assign({},(0,s.Jt)(i,n));(0,s.hZ)(e,"root",o),(0,s.hZ)(i,n,e)}else(0,s.hZ)(i,n,o)}return i},a=(e,t)=>e.some((e=>e.startsWith(t+".")));var c=function(e,t){for(var i={};e.length;){var n=e[0],r=n.code,o=n.message,a=n.path.join(".");if(!i[a])if("unionErrors"in n){var c=n.unionErrors[0].errors[0];i[a]={message:c.message,type:c.code}}else i[a]={message:o,type:r};if("unionErrors"in n&&n.unionErrors.forEach((function(t){return t.errors.forEach((function(t){return e.push(t)}))})),t){var l=i[a].types,h=l&&l[n.code];i[a]=(0,s.Gb)(a,t,i,r,h?[].concat(h,n.message):n.message)}e.shift()}return i},l=function(e,t,i){return void 0===i&&(i={}),function(s,n,a){try{return Promise.resolve(function(n,o){try{var c=Promise.resolve(e["sync"===i.mode?"parse":"parseAsync"](s,t)).then((function(e){return a.shouldUseNativeValidation&&r({},a),{errors:{},values:i.raw?s:e}}))}catch(l){return o(l)}return c&&c.then?c.then(void 0,o):c}(0,(function(e){if(function(e){return Array.isArray(null==e?void 0:e.errors)}(e))return{values:{},errors:o(c(e.errors,!a.shouldUseNativeValidation&&"all"===a.criteriaMode),a)};throw e})))}catch(l){return Promise.reject(l)}}}},16223:(e,t,i)=>{"use strict";i.d(t,{A5:()=>s,Dg:()=>c,F4:()=>u,L5:()=>d,VW:()=>r,Wo:()=>h,X2:()=>a,ZS:()=>n,nk:()=>l,vd:()=>g});var s,n,r,o=i(10146);!function(e){e[e.Left=1]="Left",e[e.Center=2]="Center",e[e.Right=4]="Right",e[e.Full=7]="Full"}(s||(s={})),function(e){e[e.Left=1]="Left",e[e.Center=2]="Center",e[e.Right=3]="Right"}(n||(n={})),function(e){e[e.Both=0]="Both",e[e.Right=1]="Right",e[e.Left=2]="Left",e[e.None=3]="None"}(r||(r={}));class a{get originalIndentSize(){return this._indentSizeIsTabSize?"tabSize":this.indentSize}constructor(e){this._textModelResolvedOptionsBrand=void 0,this.tabSize=Math.max(1,0|e.tabSize),"tabSize"===e.indentSize?(this.indentSize=this.tabSize,this._indentSizeIsTabSize=!0):(this.indentSize=Math.max(1,0|e.indentSize),this._indentSizeIsTabSize=!1),this.insertSpaces=Boolean(e.insertSpaces),this.defaultEOL=0|e.defaultEOL,this.trimAutoWhitespace=Boolean(e.trimAutoWhitespace),this.bracketPairColorizationOptions=e.bracketPairColorizationOptions}equals(e){return this.tabSize===e.tabSize&&this._indentSizeIsTabSize===e._indentSizeIsTabSize&&this.indentSize===e.indentSize&&this.insertSpaces===e.insertSpaces&&this.defaultEOL===e.defaultEOL&&this.trimAutoWhitespace===e.trimAutoWhitespace&&(0,o.aI)(this.bracketPairColorizationOptions,e.bracketPairColorizationOptions)}createChangeEvent(e){return{tabSize:this.tabSize!==e.tabSize,indentSize:this.indentSize!==e.indentSize,insertSpaces:this.insertSpaces!==e.insertSpaces,trimAutoWhitespace:this.trimAutoWhitespace!==e.trimAutoWhitespace}}}class c{constructor(e,t){this._findMatchBrand=void 0,this.range=e,this.matches=t}}function l(e){return e&&"function"===typeof e.read}class h{constructor(e,t,i,s,n,r){this.identifier=e,this.range=t,this.text=i,this.forceMoveMarkers=s,this.isAutoWhitespaceEdit=n,this._isTracked=r}}class d{constructor(e,t,i){this.regex=e,this.wordSeparators=t,this.simpleSearch=i}}class u{constructor(e,t,i){this.reverseEdits=e,this.changes=t,this.trimAutoWhitespaceLineNumbers=i}}function g(e){return!e.isTooLargeForSyncing()&&!e.isForSimpleWidget}},16363:(e,t,i)=>{"use strict";i.r(t),i.d(t,{DefaultModelSHA1Computer:()=>R,ModelService:()=>w});var s,n=i(41234),r=i(5662),o=i(98067),a=i(87289),c=i(24329),l=i(83941),h=i(90360),d=i(84001),u=i(47579),g=i(85600),p=i(26656),m=i(36456),f=i(10146),_=i(63591),v=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},C=function(e,t){return function(i,s){t(i,s,e)}};function E(e){return e.toString()}class b{constructor(e,t,i){this.model=e,this._modelEventListeners=new r.Cm,this.model=e,this._modelEventListeners.add(e.onWillDispose((()=>t(e)))),this._modelEventListeners.add(e.onDidChangeLanguage((t=>i(e,t))))}dispose(){this._modelEventListeners.dispose()}}const S=o.j9||o.zx?1:2;class y{constructor(e,t,i,s,n,r,o,a){this.uri=e,this.initialUndoRedoSnapshot=t,this.time=i,this.sharesUndoRedoStack=s,this.heapSize=n,this.sha1=r,this.versionId=o,this.alternativeVersionId=a}}let w=class extends r.jG{static{s=this}static{this.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK=20971520}constructor(e,t,i,s){super(),this._configurationService=e,this._resourcePropertiesService=t,this._undoRedoService=i,this._instantiationService=s,this._onModelAdded=this._register(new n.vl),this.onModelAdded=this._onModelAdded.event,this._onModelRemoved=this._register(new n.vl),this.onModelRemoved=this._onModelRemoved.event,this._onModelModeChanged=this._register(new n.vl),this.onModelLanguageChanged=this._onModelModeChanged.event,this._modelCreationOptionsByLanguageAndResource=Object.create(null),this._models={},this._disposedModels=new Map,this._disposedModelsHeapSize=0,this._register(this._configurationService.onDidChangeConfiguration((e=>this._updateModelOptions(e)))),this._updateModelOptions(void 0)}static _readModelOptions(e,t){let i=c.R.tabSize;if(e.editor&&"undefined"!==typeof e.editor.tabSize){const t=parseInt(e.editor.tabSize,10);isNaN(t)||(i=t),i<1&&(i=1)}let s="tabSize";if(e.editor&&"undefined"!==typeof e.editor.indentSize&&"tabSize"!==e.editor.indentSize){const t=parseInt(e.editor.indentSize,10);isNaN(t)||(s=Math.max(t,1))}let n=c.R.insertSpaces;e.editor&&"undefined"!==typeof e.editor.insertSpaces&&(n="false"!==e.editor.insertSpaces&&Boolean(e.editor.insertSpaces));let r=S;const o=e.eol;"\r\n"===o?r=2:"\n"===o&&(r=1);let a=c.R.trimAutoWhitespace;e.editor&&"undefined"!==typeof e.editor.trimAutoWhitespace&&(a="false"!==e.editor.trimAutoWhitespace&&Boolean(e.editor.trimAutoWhitespace));let l=c.R.detectIndentation;e.editor&&"undefined"!==typeof e.editor.detectIndentation&&(l="false"!==e.editor.detectIndentation&&Boolean(e.editor.detectIndentation));let h=c.R.largeFileOptimizations;e.editor&&"undefined"!==typeof e.editor.largeFileOptimizations&&(h="false"!==e.editor.largeFileOptimizations&&Boolean(e.editor.largeFileOptimizations));let d=c.R.bracketPairColorizationOptions;return e.editor?.bracketPairColorization&&"object"===typeof e.editor.bracketPairColorization&&(d={enabled:!!e.editor.bracketPairColorization.enabled,independentColorPoolPerBracketType:!!e.editor.bracketPairColorization.independentColorPoolPerBracketType}),{isForSimpleWidget:t,tabSize:i,indentSize:s,insertSpaces:n,detectIndentation:l,defaultEOL:r,trimAutoWhitespace:a,largeFileOptimizations:h,bracketPairColorizationOptions:d}}_getEOL(e,t){if(e)return this._resourcePropertiesService.getEOL(e,t);const i=this._configurationService.getValue("files.eol",{overrideIdentifier:t});return i&&"string"===typeof i&&"auto"!==i?i:3===o.OS||2===o.OS?"\n":"\r\n"}_shouldRestoreUndoStack(){const e=this._configurationService.getValue("files.restoreUndoStack");return"boolean"!==typeof e||e}getCreationOptions(e,t,i){const n="string"===typeof e?e:e.languageId;let r=this._modelCreationOptionsByLanguageAndResource[n+t];if(!r){const e=this._configurationService.getValue("editor",{overrideIdentifier:n,resource:t}),o=this._getEOL(t,n);r=s._readModelOptions({editor:e,eol:o},i),this._modelCreationOptionsByLanguageAndResource[n+t]=r}return r}_updateModelOptions(e){const t=this._modelCreationOptionsByLanguageAndResource;this._modelCreationOptionsByLanguageAndResource=Object.create(null);const i=Object.keys(this._models);for(let n=0,r=i.length;ne){const t=[];for(this._disposedModels.forEach((e=>{e.sharesUndoRedoStack||t.push(e)})),t.sort(((e,t)=>e.time-t.time));t.length>0&&this._disposedModelsHeapSize>e;){const e=t.shift();this._removeDisposedModel(e.uri),null!==e.initialUndoRedoSnapshot&&this._undoRedoService.restoreSnapshot(e.initialUndoRedoSnapshot)}}}_createModelData(e,t,i,s){const n=this.getCreationOptions(t,i,s),r=this._instantiationService.createInstance(a.Bz,e,t,n,i);if(i&&this._disposedModels.has(E(i))){const e=this._removeDisposedModel(i),t=this._undoRedoService.getElements(i),s=this._getSHA1Computer(),n=!!s.canComputeSHA1(r)&&s.computeSHA1(r)===e.sha1;if(n||e.sharesUndoRedoStack){for(const e of t.past)(0,p.Th)(e)&&e.matchesResource(i)&&e.setModel(r);for(const e of t.future)(0,p.Th)(e)&&e.matchesResource(i)&&e.setModel(r);this._undoRedoService.setElementsValidFlag(i,!0,(e=>(0,p.Th)(e)&&e.matchesResource(i))),n&&(r._overwriteVersionId(e.versionId),r._overwriteAlternativeVersionId(e.alternativeVersionId),r._overwriteInitialUndoRedoSnapshot(e.initialUndoRedoSnapshot))}else null!==e.initialUndoRedoSnapshot&&this._undoRedoService.restoreSnapshot(e.initialUndoRedoSnapshot)}const o=E(r.uri);if(this._models[o])throw new Error("ModelService: Cannot add model because it already exists!");const c=new b(r,(e=>this._onWillDispose(e)),((e,t)=>this._onDidChangeLanguage(e,t)));return this._models[o]=c,c}createModel(e,t,i,s=!1){let n;return n=t?this._createModelData(e,t,i,s):this._createModelData(e,l.vH,i,s),this._onModelAdded.fire(n.model),n.model}getModels(){const e=[],t=Object.keys(this._models);for(let i=0,s=t.length;i0||t.future.length>0){for(const i of t.past)(0,p.Th)(i)&&i.matchesResource(e.uri)&&(r=!0,o+=i.heapSize(e.uri),i.setModel(e.uri));for(const i of t.future)(0,p.Th)(i)&&i.matchesResource(e.uri)&&(r=!0,o+=i.heapSize(e.uri),i.setModel(e.uri))}}const a=s.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK,c=this._getSHA1Computer();if(r)if(n||!(o>a)&&c.canComputeSHA1(e))this._ensureDisposedModelsHeapSize(a-o),this._undoRedoService.setElementsValidFlag(e.uri,!1,(t=>(0,p.Th)(t)&&t.matchesResource(e.uri))),this._insertDisposedModel(new y(e.uri,i.model.getInitialUndoRedoSnapshot(),Date.now(),n,o,c.computeSHA1(e),e.getVersionId(),e.getAlternativeVersionId()));else{const e=i.model.getInitialUndoRedoSnapshot();null!==e&&this._undoRedoService.restoreSnapshot(e)}else if(!n){const e=i.model.getInitialUndoRedoSnapshot();null!==e&&this._undoRedoService.restoreSnapshot(e)}delete this._models[t],i.dispose(),delete this._modelCreationOptionsByLanguageAndResource[e.getLanguageId()+e.uri],this._onModelRemoved.fire(e)}_onDidChangeLanguage(e,t){const i=t.oldLanguage,n=e.getLanguageId(),r=this.getCreationOptions(i,e.uri,e.isForSimpleWidget),o=this.getCreationOptions(n,e.uri,e.isForSimpleWidget);s._setModelOptionsForModel(e,o,r),this._onModelModeChanged.fire({model:e,oldLanguageId:i})}_getSHA1Computer(){return new R}};w=s=v([C(0,d.pG),C(1,h.ITextResourcePropertiesService),C(2,u.$D),C(3,_._Y)],w);class R{static{this.MAX_MODEL_SIZE=10485760}canComputeSHA1(e){return e.getValueLength()<=R.MAX_MODEL_SIZE}computeSHA1(e){const t=new g.v7,i=e.createSnapshot();let s;for(;s=i.read();)t.update(s);return t.digest()}}},16545:(e,t,i)=>{"use strict";i.r(t),i.d(t,{BaseEditorSimpleWorker:()=>Y,EditorSimpleWorker:()=>q,create:()=>$});var s=i(83993),n=i(36677),r=i(60534);class o{constructor(e,t,i){const s=new Uint8Array(e*t);for(let n=0,r=e*t;nt&&(t=r),s>i&&(i=s),o>i&&(i=o)}t++,i++;const s=new o(i,t,0);for(let n=0,r=e.length;n=this._maxCharCode?0:this._states.get(e,t)}}let c=null;let l=null;class h{static _createLink(e,t,i,s,n){let r=n-1;do{const i=t.charCodeAt(r);if(2!==e.get(i))break;r--}while(r>s);if(s>0){const e=t.charCodeAt(s-1),i=t.charCodeAt(r);(40===e&&41===i||91===e&&93===i||123===e&&125===i)&&r--}return{range:{startLineNumber:i,startColumn:s+1,endLineNumber:i,endColumn:r+2},url:t.substring(s,r+1)}}static computeLinks(e,t=function(){return null===c&&(c=new a([[1,104,2],[1,72,2],[1,102,6],[1,70,6],[2,116,3],[2,84,3],[3,116,4],[3,84,4],[4,112,5],[4,80,5],[5,115,9],[5,83,9],[5,58,10],[6,105,7],[6,73,7],[7,108,8],[7,76,8],[8,101,9],[8,69,9],[9,58,10],[10,47,11],[11,47,12]])),c}()){const i=function(){if(null===l){l=new r.V(0);const e=" \t<>'\"\u3001\u3002\uff61\uff64\uff0c\uff0e\uff1a\uff1b\u2018\u3008\u300c\u300e\u3014\uff08\uff3b\uff5b\uff62\uff63\uff5d\uff3d\uff09\u3015\u300f\u300d\u3009\u2019\uff40\uff5e\u2026";for(let i=0;i=0?(s+=i?1:-1,s<0?s=e.length-1:s%=e.length,e[s]):null}}var u=i(73848),g=i(80718),p=i(78381),m=i(74855),f=i(41845),_=i(87723),v=i(91508),C=i(66782),E=i(86571);class b{computeDiff(e,t,i){const s=new T(e,t,{maxComputationTime:i.maxComputationTimeMs,shouldIgnoreTrimWhitespace:i.ignoreTrimWhitespace,shouldComputeCharChanges:!0,shouldMakePrettyDiff:!0,shouldPostProcessCharChanges:!0}).computeDiff(),r=[];let o=null;for(const a of s.changes){let e,t;e=0===a.originalEndLineNumber?new E.M(a.originalStartLineNumber+1,a.originalStartLineNumber+1):new E.M(a.originalStartLineNumber,a.originalEndLineNumber+1),t=0===a.modifiedEndLineNumber?new E.M(a.modifiedStartLineNumber+1,a.modifiedStartLineNumber+1):new E.M(a.modifiedStartLineNumber,a.modifiedEndLineNumber+1);let i=new _.wm(e,t,a.charChanges?.map((e=>new _.q6(new n.Q(e.originalStartLineNumber,e.originalStartColumn,e.originalEndLineNumber,e.originalEndColumn),new n.Q(e.modifiedStartLineNumber,e.modifiedStartColumn,e.modifiedEndLineNumber,e.modifiedEndColumn)))));o&&(o.modified.endLineNumberExclusive!==i.modified.startLineNumber&&o.original.endLineNumberExclusive!==i.original.startLineNumber||(i=new _.wm(o.original.join(i.original),o.modified.join(i.modified),o.innerChanges&&i.innerChanges?o.innerChanges.concat(i.innerChanges):void 0),r.pop())),r.push(i),o=i}return(0,C.Ft)((()=>(0,C.Xo)(r,((e,t)=>t.original.startLineNumber-e.original.endLineNumberExclusive===t.modified.startLineNumber-e.modified.endLineNumberExclusive&&e.original.endLineNumberExclusive(10===e?"\\n":String.fromCharCode(e))+`-(${this._lineNumbers[t]},${this._columns[t]})`)).join(", ")+"]"}_assertIndex(e,t){if(e<0||e>=t.length)throw new Error("Illegal index")}getElements(){return this._charCodes}getStartLineNumber(e){return e>0&&e===this._lineNumbers.length?this.getEndLineNumber(e-1):(this._assertIndex(e,this._lineNumbers),this._lineNumbers[e])}getEndLineNumber(e){return-1===e?this.getStartLineNumber(e+1):(this._assertIndex(e,this._lineNumbers),10===this._charCodes[e]?this._lineNumbers[e]+1:this._lineNumbers[e])}getStartColumn(e){return e>0&&e===this._columns.length?this.getEndColumn(e-1):(this._assertIndex(e,this._columns),this._columns[e])}getEndColumn(e){return-1===e?this.getStartColumn(e+1):(this._assertIndex(e,this._columns),10===this._charCodes[e]?1:this._columns[e]+1)}}class R{constructor(e,t,i,s,n,r,o,a){this.originalStartLineNumber=e,this.originalStartColumn=t,this.originalEndLineNumber=i,this.originalEndColumn=s,this.modifiedStartLineNumber=n,this.modifiedStartColumn=r,this.modifiedEndLineNumber=o,this.modifiedEndColumn=a}static createFromDiffChange(e,t,i){const s=t.getStartLineNumber(e.originalStart),n=t.getStartColumn(e.originalStart),r=t.getEndLineNumber(e.originalStart+e.originalLength-1),o=t.getEndColumn(e.originalStart+e.originalLength-1),a=i.getStartLineNumber(e.modifiedStart),c=i.getStartColumn(e.modifiedStart),l=i.getEndLineNumber(e.modifiedStart+e.modifiedLength-1),h=i.getEndColumn(e.modifiedStart+e.modifiedLength-1);return new R(s,n,r,o,a,c,l,h)}}class L{constructor(e,t,i,s,n){this.originalStartLineNumber=e,this.originalEndLineNumber=t,this.modifiedStartLineNumber=i,this.modifiedEndLineNumber=s,this.charChanges=n}static createFromDiffResult(e,t,i,s,n,r,o){let a,c,l,h,d;if(0===t.originalLength?(a=i.getStartLineNumber(t.originalStart)-1,c=0):(a=i.getStartLineNumber(t.originalStart),c=i.getEndLineNumber(t.originalStart+t.originalLength-1)),0===t.modifiedLength?(l=s.getStartLineNumber(t.modifiedStart)-1,h=0):(l=s.getStartLineNumber(t.modifiedStart),h=s.getEndLineNumber(t.modifiedStart+t.modifiedLength-1)),r&&t.originalLength>0&&t.originalLength<20&&t.modifiedLength>0&&t.modifiedLength<20&&n()){const r=i.createCharSequence(e,t.originalStart,t.originalStart+t.originalLength-1),a=s.createCharSequence(e,t.modifiedStart,t.modifiedStart+t.modifiedLength-1);if(r.getElements().length>0&&a.getElements().length>0){let e=S(r,a,n,!0).changes;o&&(e=function(e){if(e.length<=1)return e;const t=[e[0]];let i=t[0];for(let s=1,n=e.length;s1&&o>1;){if(e.charCodeAt(i-2)!==t.charCodeAt(o-2))break;i--,o--}(i>1||o>1)&&this._pushTrimWhitespaceCharChange(s,n+1,1,i,r+1,1,o)}{let i=k(e,1),o=k(t,1);const a=e.length+1,c=t.length+1;for(;i!0;const t=Date.now();return()=>Date.now()-tnew b,O=()=>new N.D8;var D=i(10146),M=i(36456),P=i(47661);function F(e){const t=[];for(const i of e){const e=Number(i);(e||0===e&&""!==i.replace(/\s/g,""))&&t.push(e)}return t}function U(e,t,i,s){return{red:e/255,blue:i/255,green:t/255,alpha:s}}function H(e,t){const i=t.index,s=t[0].length;if(!i)return;const n=e.positionAt(i);return{startLineNumber:n.lineNumber,startColumn:n.column,endLineNumber:n.lineNumber,endColumn:n.column+s}}function B(e,t){if(!e)return;const i=P.Q1.Format.CSS.parseHex(t);return i?{range:e,color:U(i.rgba.r,i.rgba.g,i.rgba.b,i.rgba.a)}:void 0}function W(e,t,i){if(!e||1!==t.length)return;const s=F(t[0].values());return{range:e,color:U(s[0],s[1],s[2],i?s[3]:1)}}function V(e,t,i){if(!e||1!==t.length)return;const s=F(t[0].values()),n=new P.Q1(new P.hB(s[0],s[1]/100,s[2]/100,i?s[3]:1));return{range:e,color:U(n.rgba.r,n.rgba.g,n.rgba.b,n.rgba.a)}}function z(e,t){return"string"===typeof e?[...e.matchAll(t)]:e.findMatches(t)}function G(e){return e&&"function"===typeof e.getValue&&"function"===typeof e.positionAt?function(e){const t=[],i=z(e,/\b(rgb|rgba|hsl|hsla)(\([0-9\s,.\%]*\))|(#)([A-Fa-f0-9]{3})\b|(#)([A-Fa-f0-9]{4})\b|(#)([A-Fa-f0-9]{6})\b|(#)([A-Fa-f0-9]{8})\b/gm);if(i.length>0)for(const s of i){const i=s.filter((e=>void 0!==e)),n=i[1],r=i[2];if(!r)continue;let o;if("rgb"===n){const t=/^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*\)$/gm;o=W(H(e,s),z(r,t),!1)}else if("rgba"===n){const t=/^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*\)$/gm;o=W(H(e,s),z(r,t),!0)}else if("hsl"===n){const t=/^\(\s*(36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])\s*,\s*(100|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(100|\d{1,2}[.]\d*|\d{1,2})%\s*\)$/gm;o=V(H(e,s),z(r,t),!1)}else if("hsla"===n){const t=/^\(\s*(36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])\s*,\s*(100|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(100|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*\)$/gm;o=V(H(e,s),z(r,t),!0)}else"#"===n&&(o=B(H(e,s),n+r));o&&t.push(o)}return t}(e):[]}var j=i(56691),K=i(47443);class Y{constructor(){this._workerTextModelSyncServer=new K.WorkerTextModelSyncServer}dispose(){}_getModel(e){return this._workerTextModelSyncServer.getModel(e)}_getModels(){return this._workerTextModelSyncServer.getModels()}$acceptNewModel(e){this._workerTextModelSyncServer.$acceptNewModel(e)}$acceptModelChanged(e,t){this._workerTextModelSyncServer.$acceptModelChanged(e,t)}$acceptRemovedModel(e){this._workerTextModelSyncServer.$acceptRemovedModel(e)}async $computeUnicodeHighlights(e,t,i){const s=this._getModel(e);return s?m.UnicodeTextModelHighlighter.computeUnicodeHighlights(s,t,i):{ranges:[],hasMore:!1,ambiguousCharacterCount:0,invisibleCharacterCount:0,nonBasicAsciiCharacterCount:0}}async $findSectionHeaders(e,t){const i=this._getModel(e);return i?(0,j.findSectionHeaders)(i,t):[]}async $computeDiff(e,t,i,s){const n=this._getModel(e),r=this._getModel(t);if(!n||!r)return null;return q.computeDiff(n,r,i,s)}static computeDiff(e,t,i,s){const n="advanced"===s?O():I(),r=e.getLinesContent(),o=t.getLinesContent(),a=n.computeDiff(r,o,i);function c(e){return e.map((e=>[e.original.startLineNumber,e.original.endLineNumberExclusive,e.modified.startLineNumber,e.modified.endLineNumberExclusive,e.innerChanges?.map((e=>[e.originalRange.startLineNumber,e.originalRange.startColumn,e.originalRange.endLineNumber,e.originalRange.endColumn,e.modifiedRange.startLineNumber,e.modifiedRange.startColumn,e.modifiedRange.endLineNumber,e.modifiedRange.endColumn]))]))}return{identical:!(a.changes.length>0)&&this._modelsAreIdentical(e,t),quitEarly:a.hitTimeout,changes:c(a.changes),moves:a.moves.map((e=>[e.lineRangeMapping.original.startLineNumber,e.lineRangeMapping.original.endLineNumberExclusive,e.lineRangeMapping.modified.startLineNumber,e.lineRangeMapping.modified.endLineNumberExclusive,c(e.changes)]))}}static _modelsAreIdentical(e,t){const i=e.getLineCount();if(i!==t.getLineCount())return!1;for(let s=1;s<=i;s++){if(e.getLineContent(s)!==t.getLineContent(s))return!1}return!0}static{this._diffLimit=1e5}async $computeMoreMinimalEdits(e,t,i){const r=this._getModel(e);if(!r)return t;const o=[];let a;t=t.slice(0).sort(((e,t)=>{if(e.range&&t.range)return n.Q.compareRangesUsingStarts(e.range,t.range);return(e.range?0:1)-(t.range?0:1)}));let c=0;for(let s=1;sq._diffLimit){o.push({range:l,text:h});continue}const t=(0,s.F1)(e,h,i),c=r.offsetAt(n.Q.lift(l).getStartPosition());for(const i of t){const e=r.positionAt(c+i.originalStart),t=r.positionAt(c+i.originalStart+i.originalLength),s={text:h.substr(i.modifiedStart,i.modifiedLength),range:{startLineNumber:e.lineNumber,startColumn:e.column,endLineNumber:t.lineNumber,endColumn:t.column}};r.getValueInRange(s.range)!==s.text&&o.push(s)}}return"number"===typeof a&&o.push({eol:a,text:"",range:{startLineNumber:0,startColumn:0,endLineNumber:0,endColumn:0}}),o}async $computeLinks(e){const t=this._getModel(e);return t?function(e){return e&&"function"===typeof e.getLineCount&&"function"===typeof e.getLineContent?h.computeLinks(e):[]}(t):null}async $computeDefaultDocumentColors(e){const t=this._getModel(e);return t?G(t):null}static{this._suggestionsLimit=1e4}async $textualSuggest(e,t,i,s){const n=new p.W,r=new RegExp(i,s),o=new Set;e:for(const a of e){const e=this._getModel(a);if(e)for(const i of e.words(r))if(i!==t&&isNaN(Number(i))&&(o.add(i),o.size>q._suggestionsLimit))break e}return{words:Array.from(o),duration:n.elapsed()}}async $computeWordRanges(e,t,i,s){const n=this._getModel(e);if(!n)return Object.create(null);const r=new RegExp(i,s),o=Object.create(null);for(let a=t.startLineNumber;athis._host.$fhr(e,t))),getMirrorModels:()=>this._getModels()};return this._foreignModuleFactory?(this._foreignModule=this._foreignModuleFactory(n,t),Promise.resolve((0,D.V0)(this._foreignModule))):new Promise(((s,r)=>{const o=e=>{this._foreignModule=e.create(n,t),s((0,D.V0)(this._foreignModule))};{const t=M.zl.asBrowserUri(`${e}.js`).toString(!0);i(9204)(`${t}`).then(o).catch(r)}}))}$fmr(e,t){if(!this._foreignModule||"function"!==typeof this._foreignModule[e])return Promise.reject(new Error("Missing requestHandler or method: "+e));try{return Promise.resolve(this._foreignModule[e].apply(this._foreignModule,t))}catch(i){return Promise.reject(i)}}}function $(e){return new q(g.EditorWorkerHost.getChannel(e),null)}"function"===typeof importScripts&&(globalThis.monaco=(0,u.createMonacoBaseAPI)())},16963:(e,t,i)=>{"use strict";i.d(t,{A:()=>o});var s,n=i(59284);function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t{"use strict";i.d(t,{Bc:()=>c,VS:()=>h,_W:()=>g,it:()=>l,nI:()=>p,nK:()=>d,oO:()=>u});var s=i(64383),n=i(37882),r=i(89403),o=i(91508),a=i(79400);class c{constructor(e="",t=!1){if(this.value=e,"string"!==typeof this.value)throw(0,s.Qg)("value");"boolean"===typeof t?(this.isTrusted=t,this.supportThemeIcons=!1,this.supportHtml=!1):(this.isTrusted=t.isTrusted??void 0,this.supportThemeIcons=t.supportThemeIcons??!1,this.supportHtml=t.supportHtml??!1)}appendText(e,t=0){var i;return this.value+=(i=this.supportThemeIcons?(0,n.m2)(e):e,i.replace(/[\\`*_{}[\]()#+\-!~]/g,"\\$&")).replace(/([ \t]+)/g,((e,t)=>" ".repeat(t.length))).replace(/\>/gm,"\\>").replace(/\n/g,1===t?"\\\n":"\n\n"),this}appendMarkdown(e){return this.value+=e,this}appendCodeblock(e,t){return this.value+=`\n${function(e,t){const i=e.match(/^`+/gm)?.reduce(((e,t)=>e.length>t.length?e:t)).length??0,s=i>=3?i+1:3;return[`${"`".repeat(s)}${t}`,e,`${"`".repeat(s)}`].join("\n")}(t,e)}\n`,this}appendLink(e,t,i){return this.value+="[",this.value+=this._escape(t,"]"),this.value+="](",this.value+=this._escape(String(e),")"),i&&(this.value+=` "${this._escape(this._escape(i,'"'),")")}"`),this.value+=")",this}_escape(e,t){const i=new RegExp((0,o.bm)(t),"g");return e.replace(i,((t,i)=>"\\"!==e.charAt(i-1)?`\\${t}`:t))}}function l(e){return h(e)?!e.value:!Array.isArray(e)||e.every(l)}function h(e){return e instanceof c||!(!e||"object"!==typeof e)&&("string"===typeof e.value&&("boolean"===typeof e.isTrusted||"object"===typeof e.isTrusted||void 0===e.isTrusted)&&("boolean"===typeof e.supportThemeIcons||void 0===e.supportThemeIcons))}function d(e,t){return e===t||!(!e||!t)&&(e.value===t.value&&e.isTrusted===t.isTrusted&&e.supportThemeIcons===t.supportThemeIcons&&e.supportHtml===t.supportHtml&&(e.baseUri===t.baseUri||!!e.baseUri&&!!t.baseUri&&(0,r.n4)(a.r.from(e.baseUri),a.r.from(t.baseUri))))}function u(e){return e.replace(/"/g,""")}function g(e){return e?e.replace(/\\([\\`*_{}[\]()#+\-.!~])/g,"$1"):e}function p(e){const t=[],i=e.split("|").map((e=>e.trim()));e=i[0];const s=i[1];if(s){const e=/height=(\d+)/.exec(s),i=/width=(\d+)/.exec(s),n=e?e[1]:"",r=i?i[1]:"",o=isFinite(parseInt(r)),a=isFinite(parseInt(n));o&&t.push(`width="${r}"`),a&&t.push(`height="${n}"`)}return{href:e,dimensions:t}}},17184:e=>{e.exports=function(){function e(e,t){return"yson"===t.format?"#":e.$value}return e.isScalar=!0,e}},17390:(e,t,i)=>{"use strict";i.d(t,{x:()=>c});var s=i(8597),n=i(72962),r=i(47358),o=i(25154),a=i(5662);class c extends a.jG{onclick(e,t){this._register(s.ko(e,s.Bx.CLICK,(i=>t(new r.P(s.zk(e),i)))))}onmousedown(e,t){this._register(s.ko(e,s.Bx.MOUSE_DOWN,(i=>t(new r.P(s.zk(e),i)))))}onmouseover(e,t){this._register(s.ko(e,s.Bx.MOUSE_OVER,(i=>t(new r.P(s.zk(e),i)))))}onmouseleave(e,t){this._register(s.ko(e,s.Bx.MOUSE_LEAVE,(i=>t(new r.P(s.zk(e),i)))))}onkeydown(e,t){this._register(s.ko(e,s.Bx.KEY_DOWN,(e=>t(new n.Z(e)))))}onkeyup(e,t){this._register(s.ko(e,s.Bx.KEY_UP,(e=>t(new n.Z(e)))))}oninput(e,t){this._register(s.ko(e,s.Bx.INPUT,t))}onblur(e,t){this._register(s.ko(e,s.Bx.BLUR,t))}onfocus(e,t){this._register(s.ko(e,s.Bx.FOCUS,t))}ignoreGesture(e){return o.q.ignoreTarget(e)}}},17469:(e,t,i)=>{"use strict";i.d(t,{JZ:()=>N,Cw:()=>M});var s=i(41234),n=i(5662),r=i(91508),o=i(26486),a=i(38566);class c{static{this.DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_QUOTES=";:.,=}])> \n\t"}static{this.DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_BRACKETS="'\"`;:.,=}])> \n\t"}constructor(e){if(e.autoClosingPairs?this._autoClosingPairs=e.autoClosingPairs.map((e=>new a.i3(e))):e.brackets?this._autoClosingPairs=e.brackets.map((e=>new a.i3({open:e[0],close:e[1]}))):this._autoClosingPairs=[],e.__electricCharacterSupport&&e.__electricCharacterSupport.docComment){const t=e.__electricCharacterSupport.docComment;this._autoClosingPairs.push(new a.i3({open:t.open,close:t.close||""}))}this._autoCloseBeforeForQuotes="string"===typeof e.autoCloseBefore?e.autoCloseBefore:c.DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_QUOTES,this._autoCloseBeforeForBrackets="string"===typeof e.autoCloseBefore?e.autoCloseBefore:c.DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_BRACKETS,this._surroundingPairs=e.surroundingPairs||this._autoClosingPairs}getAutoClosingPairs(){return this._autoClosingPairs}getAutoCloseBeforeSet(e){return e?this._autoCloseBeforeForQuotes:this._autoCloseBeforeForBrackets}getSurroundingPairs(){return this._surroundingPairs}}var l=i(25890),h=i(12296),d=i(56772);class u{constructor(e){this._richEditBrackets=e}getElectricCharacters(){const e=[];if(this._richEditBrackets)for(const t of this._richEditBrackets.brackets)for(const i of t.close){const t=i.charAt(i.length-1);e.push(t)}return(0,l.dM)(e)}onElectricCharacter(e,t,i){if(!this._richEditBrackets||0===this._richEditBrackets.brackets.length)return null;const s=t.findTokenIndexAtOffset(i-1);if((0,h.Yo)(t.getStandardTokenType(s)))return null;const n=this._richEditBrackets.reversedRegex,r=t.getLineContent().substring(0,i-1)+e,o=d.Fu.findPrevBracketInRange(n,1,r,0,r.length);if(!o)return null;const a=r.substring(o.startColumn-1,o.endColumn-1).toLowerCase();if(this._richEditBrackets.textIsOpenBracket[a])return null;const c=t.getActualLineContentBefore(o.startColumn-1);return/^\s*$/.test(c)?{matchOpenBracket:a}:null}}function g(e){return e.global&&(e.lastIndex=0),!0}class p{constructor(e){this._indentationRules=e}shouldIncrease(e){return!!(this._indentationRules&&this._indentationRules.increaseIndentPattern&&g(this._indentationRules.increaseIndentPattern)&&this._indentationRules.increaseIndentPattern.test(e))}shouldDecrease(e){return!!(this._indentationRules&&this._indentationRules.decreaseIndentPattern&&g(this._indentationRules.decreaseIndentPattern)&&this._indentationRules.decreaseIndentPattern.test(e))}shouldIndentNextLine(e){return!!(this._indentationRules&&this._indentationRules.indentNextLinePattern&&g(this._indentationRules.indentNextLinePattern)&&this._indentationRules.indentNextLinePattern.test(e))}shouldIgnore(e){return!!(this._indentationRules&&this._indentationRules.unIndentedLinePattern&&g(this._indentationRules.unIndentedLinePattern)&&this._indentationRules.unIndentedLinePattern.test(e))}getIndentMetadata(e){let t=0;return this.shouldIncrease(e)&&(t+=1),this.shouldDecrease(e)&&(t+=2),this.shouldIndentNextLine(e)&&(t+=4),this.shouldIgnore(e)&&(t+=8),t}}var m=i(64383);class f{constructor(e){(e=e||{}).brackets=e.brackets||[["(",")"],["{","}"],["[","]"]],this._brackets=[],e.brackets.forEach((e=>{const t=f._createOpenBracketRegExp(e[0]),i=f._createCloseBracketRegExp(e[1]);t&&i&&this._brackets.push({open:e[0],openRegExp:t,close:e[1],closeRegExp:i})})),this._regExpRules=e.onEnterRules||[]}onEnter(e,t,i,s){if(e>=3)for(let n=0,r=this._regExpRules.length;n!e.reg||(e.reg.lastIndex=0,e.reg.test(e.text)))))return e.action}if(e>=2&&i.length>0&&s.length>0)for(let n=0,r=this._brackets.length;n=2&&i.length>0)for(let n=0,r=this._brackets.length;n{const t=new Set;return{info:new L(this,e,t),closing:t}})),n=new S.VV((e=>{const t=new Set,i=new Set;return{info:new T(this,e,t,i),opening:t,openingColorized:i}}));for(const[o,a]of i){const e=s.get(o),t=n.get(a);e.closing.add(t.info),t.opening.add(e.info)}const r=t.colorizedBracketPairs?w(t.colorizedBracketPairs):i.filter((e=>!("<"===e[0]&&">"===e[1])));for(const[o,a]of r){const e=s.get(o),t=n.get(a);e.closing.add(t.info),t.openingColorized.add(e.info),t.opening.add(e.info)}this._openingBrackets=new Map([...s.cachedValues].map((([e,t])=>[e,t.info]))),this._closingBrackets=new Map([...n.cachedValues].map((([e,t])=>[e,t.info])))}get openingBrackets(){return[...this._openingBrackets.values()]}get closingBrackets(){return[...this._closingBrackets.values()]}getOpeningBracketInfo(e){return this._openingBrackets.get(e)}getClosingBracketInfo(e){return this._closingBrackets.get(e)}getBracketInfo(e){return this.getOpeningBracketInfo(e)||this.getClosingBracketInfo(e)}getBracketRegExp(e){const t=Array.from([...this._openingBrackets.keys(),...this._closingBrackets.keys()]);return(0,d.xb)(t,e)}}function w(e){return e.filter((([e,t])=>""!==e&&""!==t))}class R{constructor(e,t){this.config=e,this.bracketText=t}get languageId(){return this.config.languageId}}class L extends R{constructor(e,t,i){super(e,t),this.openedBrackets=i,this.isOpeningBracket=!0}}class T extends R{constructor(e,t,i,s){super(e,t),this.openingBrackets=i,this.openingColorizedBrackets=s,this.isOpeningBracket=!1}closes(e){return e.config===this.config&&this.openingBrackets.has(e)}closesColorized(e){return e.config===this.config&&this.openingColorizedBrackets.has(e)}getOpeningBrackets(){return[...this.openingBrackets]}}var x=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},k=function(e,t){return function(i,s){t(i,s,e)}};class A{constructor(e){this.languageId=e}affects(e){return!this.languageId||this.languageId===e}}const N=(0,_.u1)("languageConfigurationService");let I=class extends n.jG{constructor(e,t){super(),this.configurationService=e,this.languageService=t,this._registry=this._register(new B),this.onDidChangeEmitter=this._register(new s.vl),this.onDidChange=this.onDidChangeEmitter.event,this.configurations=new Map;const i=new Set(Object.values(O));this._register(this.configurationService.onDidChangeConfiguration((e=>{const t=e.change.keys.some((e=>i.has(e))),s=e.change.overrides.filter((([e,t])=>t.some((e=>i.has(e))))).map((([e])=>e));if(t)this.configurations.clear(),this.onDidChangeEmitter.fire(new A(void 0));else for(const i of s)this.languageService.isRegisteredLanguageId(i)&&(this.configurations.delete(i),this.onDidChangeEmitter.fire(new A(i)))}))),this._register(this._registry.onDidChange((e=>{this.configurations.delete(e.languageId),this.onDidChangeEmitter.fire(new A(e.languageId))})))}register(e,t,i){return this._registry.register(e,t,i)}getLanguageConfiguration(e){let t=this.configurations.get(e);return t||(t=function(e,t,i,s){let n=t.getLanguageConfiguration(e);if(!n){if(!s.isRegisteredLanguageId(e))return new W(e,{});n=new W(e,{})}const r=function(e,t){const i=t.getValue(O.brackets,{overrideIdentifier:e}),s=t.getValue(O.colorizedBracketPairs,{overrideIdentifier:e});return{brackets:D(i),colorizedBracketPairs:D(s)}}(n.languageId,i),o=F([n.underlyingConfig,r]);return new W(n.languageId,o)}(e,this._registry,this.configurationService,this.languageService),this.configurations.set(e,t)),t}};I=x([k(0,v.pG),k(1,C.L)],I);const O={brackets:"editor.language.brackets",colorizedBracketPairs:"editor.language.colorizedBracketPairs"};function D(e){if(Array.isArray(e))return e.map((e=>{if(Array.isArray(e)&&2===e.length)return[e[0],e[1]]})).filter((e=>!!e))}function M(e,t,i){const s=e.getLineContent(t);let n=r.UU(s);return n.length>i-1&&(n=n.substring(0,i-1)),n}class P{constructor(e){this.languageId=e,this._resolved=null,this._entries=[],this._order=0,this._resolved=null}register(e,t){const i=new U(e,t,++this._order);return this._entries.push(i),this._resolved=null,(0,n.s)((()=>{for(let e=0;ee.configuration))))}}function F(e){let t={comments:void 0,brackets:void 0,wordPattern:void 0,indentationRules:void 0,onEnterRules:void 0,autoClosingPairs:void 0,surroundingPairs:void 0,autoCloseBefore:void 0,folding:void 0,colorizedBracketPairs:void 0,__electricCharacterSupport:void 0};for(const i of e)t={comments:i.comments||t.comments,brackets:i.brackets||t.brackets,wordPattern:i.wordPattern||t.wordPattern,indentationRules:i.indentationRules||t.indentationRules,onEnterRules:i.onEnterRules||t.onEnterRules,autoClosingPairs:i.autoClosingPairs||t.autoClosingPairs,surroundingPairs:i.surroundingPairs||t.surroundingPairs,autoCloseBefore:i.autoCloseBefore||t.autoCloseBefore,folding:i.folding||t.folding,colorizedBracketPairs:i.colorizedBracketPairs||t.colorizedBracketPairs,__electricCharacterSupport:i.__electricCharacterSupport||t.__electricCharacterSupport};return t}class U{constructor(e,t,i){this.configuration=e,this.priority=t,this.order=i}static cmp(e,t){return e.priority===t.priority?e.order-t.order:e.priority-t.priority}}class H{constructor(e){this.languageId=e}}class B extends n.jG{constructor(){super(),this._entries=new Map,this._onDidChange=this._register(new s.vl),this.onDidChange=this._onDidChange.event,this._register(this.register(b.vH,{brackets:[["(",")"],["[","]"],["{","}"]],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"<",close:">"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"`",close:"`"}],colorizedBracketPairs:[],folding:{offSide:!0}},0))}register(e,t,i=0){let s=this._entries.get(e);s||(s=new P(e),this._entries.set(e,s));const r=s.register(t,i);return this._onDidChange.fire(new H(e)),(0,n.s)((()=>{r.dispose(),this._onDidChange.fire(new H(e))}))}getLanguageConfiguration(e){const t=this._entries.get(e);return t?.getResolvedConfiguration()||null}}class W{constructor(e,t){this.languageId=e,this.underlyingConfig=t,this._brackets=null,this._electricCharacter=null,this._onEnterSupport=this.underlyingConfig.brackets||this.underlyingConfig.indentationRules||this.underlyingConfig.onEnterRules?new f(this.underlyingConfig):null,this.comments=W._handleComments(this.underlyingConfig),this.characterPair=new c(this.underlyingConfig),this.wordDefinition=this.underlyingConfig.wordPattern||o.Ld,this.indentationRules=this.underlyingConfig.indentationRules,this.underlyingConfig.indentationRules?this.indentRulesSupport=new p(this.underlyingConfig.indentationRules):this.indentRulesSupport=null,this.foldingRules=this.underlyingConfig.folding||{},this.bracketsNew=new y(e,this.underlyingConfig)}getWordDefinition(){return(0,o.Io)(this.wordDefinition)}get brackets(){return!this._brackets&&this.underlyingConfig.brackets&&(this._brackets=new d.az(this.languageId,this.underlyingConfig.brackets)),this._brackets}get electricCharacter(){return this._electricCharacter||(this._electricCharacter=new u(this.brackets)),this._electricCharacter}onEnter(e,t,i,s){return this._onEnterSupport?this._onEnterSupport.onEnter(e,t,i,s):null}getAutoClosingPairs(){return new a.GB(this.characterPair.getAutoClosingPairs())}getAutoCloseBeforeSet(e){return this.characterPair.getAutoCloseBeforeSet(e)}getSurroundingPairs(){return this.characterPair.getSurroundingPairs()}static _handleComments(e){const t=e.comments;if(!t)return null;const i={};if(t.lineComment&&(i.lineCommentToken=t.lineComment),t.blockComment){const[e,s]=t.blockComment;i.blockCommentStartToken=e,i.blockCommentEndToken=s}return i}}(0,E.v)(N,I,1)},17799:(e,t,i)=>{"use strict";i.d(t,{VX:()=>a,Vq:()=>c,Y:()=>h,gf:()=>o,jt:()=>u});var s=i(25890),n=i(42522),r=i(58255);function o(e){return{asString:async()=>e,asFile:()=>{},value:"string"===typeof e?e:void 0}}function a(e,t,i){const s={id:(0,r.b)(),name:e,uri:t,data:i};return{asString:async()=>"",asFile:()=>s,value:void 0}}class c{constructor(){this._entries=new Map}get size(){let e=0;for(const t of this._entries)e++;return e}has(e){return this._entries.has(this.toKey(e))}matches(e){const t=[...this._entries.keys()];return n.f.some(this,(([e,t])=>t.asFile()))&&t.push("files"),d(l(e),t)}get(e){return this._entries.get(this.toKey(e))?.[0]}append(e,t){const i=this._entries.get(e);i?i.push(t):this._entries.set(this.toKey(e),[t])}replace(e,t){this._entries.set(this.toKey(e),[t])}delete(e){this._entries.delete(this.toKey(e))}*[Symbol.iterator](){for(const[e,t]of this._entries)for(const i of t)yield[e,i]}toKey(e){return l(e)}}function l(e){return e.toLowerCase()}function h(e,t){return d(l(e),t.map(l))}function d(e,t){if("*/*"===e)return t.length>0;if(t.includes(e))return!0;const i=e.match(/^([a-z]+)\/([a-z]+|\*)$/i);if(!i)return!1;const[s,n,r]=i;return"*"===r&&t.some((e=>e.startsWith(n+"/")))}const u=Object.freeze({create:e=>(0,s.dM)(e.map((e=>e.toString()))).join("\r\n"),split:e=>e.split("\r\n"),parse:e=>u.split(e).filter((e=>!e.startsWith("#")))})},17890:(e,t,i)=>{"use strict";i.r(t),i.d(t,{LanguageService:()=>h});var s=i(41234),n=i(5662),r=i(69259),o=i(25890),a=i(62083),c=i(83941),l=i(31308);class h extends n.jG{static{this.instanceCount=0}constructor(e=!1){super(),this._onDidRequestBasicLanguageFeatures=this._register(new s.vl),this.onDidRequestBasicLanguageFeatures=this._onDidRequestBasicLanguageFeatures.event,this._onDidRequestRichLanguageFeatures=this._register(new s.vl),this.onDidRequestRichLanguageFeatures=this._onDidRequestRichLanguageFeatures.event,this._onDidChange=this._register(new s.vl({leakWarningThreshold:200})),this.onDidChange=this._onDidChange.event,this._requestedBasicLanguages=new Set,this._requestedRichLanguages=new Set,h.instanceCount++,this._registry=this._register(new r.LanguagesRegistry(!0,e)),this.languageIdCodec=this._registry.languageIdCodec,this._register(this._registry.onDidChange((()=>this._onDidChange.fire())))}dispose(){h.instanceCount--,super.dispose()}isRegisteredLanguageId(e){return this._registry.isRegisteredLanguageId(e)}getLanguageIdByLanguageName(e){return this._registry.getLanguageIdByLanguageName(e)}getLanguageIdByMimeType(e){return this._registry.getLanguageIdByMimeType(e)}guessLanguageIdByFilepathOrFirstLine(e,t){const i=this._registry.guessLanguageIdByFilepathOrFirstLine(e,t);return(0,o.Fy)(i,null)}createById(e){return new d(this.onDidChange,(()=>this._createAndGetLanguageIdentifier(e)))}createByFilepathOrFirstLine(e,t){return new d(this.onDidChange,(()=>{const i=this.guessLanguageIdByFilepathOrFirstLine(e,t);return this._createAndGetLanguageIdentifier(i)}))}_createAndGetLanguageIdentifier(e){return e&&this.isRegisteredLanguageId(e)||(e=c.vH),e}requestBasicLanguageFeatures(e){this._requestedBasicLanguages.has(e)||(this._requestedBasicLanguages.add(e),this._onDidRequestBasicLanguageFeatures.fire(e))}requestRichLanguageFeatures(e){this._requestedRichLanguages.has(e)||(this._requestedRichLanguages.add(e),this.requestBasicLanguageFeatures(e),a.dG.getOrCreate(e),this._onDidRequestRichLanguageFeatures.fire(e))}}class d{constructor(e,t){this._value=(0,l.y0)(this,e,(()=>t())),this.onDidChange=s.Jh.fromObservable(this._value)}get languageId(){return this._value.get()}}},18278:(e,t,i)=>{"use strict";var s=i(90766),n=i(5662),r=i(31450),o=i(17469),a=i(87289),c=i(10920),l=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},h=function(e,t){return function(i,s){t(i,s,e)}};let d=class extends n.jG{static{this.ID="editor.sectionHeaderDetector"}constructor(e,t,i){super(),this.editor=e,this.languageConfigurationService=t,this.editorWorkerService=i,this.decorations=this.editor.createDecorationsCollection(),this.options=this.createOptions(e.getOption(73)),this.computePromise=null,this.currentOccurrences={},this._register(e.onDidChangeModel((t=>{this.currentOccurrences={},this.options=this.createOptions(e.getOption(73)),this.stop(),this.computeSectionHeaders.schedule(0)}))),this._register(e.onDidChangeModelLanguage((t=>{this.currentOccurrences={},this.options=this.createOptions(e.getOption(73)),this.stop(),this.computeSectionHeaders.schedule(0)}))),this._register(t.onDidChange((t=>{const i=this.editor.getModel()?.getLanguageId();i&&t.affects(i)&&(this.currentOccurrences={},this.options=this.createOptions(e.getOption(73)),this.stop(),this.computeSectionHeaders.schedule(0))}))),this._register(e.onDidChangeConfiguration((t=>{this.options&&!t.hasChanged(73)||(this.options=this.createOptions(e.getOption(73)),this.updateDecorations([]),this.stop(),this.computeSectionHeaders.schedule(0))}))),this._register(this.editor.onDidChangeModelContent((e=>{this.computeSectionHeaders.schedule()}))),this._register(e.onDidChangeModelTokens((e=>{this.computeSectionHeaders.isScheduled()||this.computeSectionHeaders.schedule(1e3)}))),this.computeSectionHeaders=this._register(new s.uC((()=>{this.findSectionHeaders()}),250)),this.computeSectionHeaders.schedule(0)}createOptions(e){if(!e||!this.editor.hasModel())return;const t=this.editor.getModel().getLanguageId();if(!t)return;const i=this.languageConfigurationService.getLanguageConfiguration(t).comments,s=this.languageConfigurationService.getLanguageConfiguration(t).foldingRules;return i||s?.markers?{foldingRules:s,findMarkSectionHeaders:e.showMarkSectionHeaders,findRegionSectionHeaders:e.showRegionSectionHeaders}:void 0}findSectionHeaders(){if(!this.editor.hasModel()||!this.options?.findMarkSectionHeaders&&!this.options?.findRegionSectionHeaders)return;const e=this.editor.getModel();if(e.isDisposed()||e.isTooLargeForSyncing())return;const t=e.getVersionId();this.editorWorkerService.findSectionHeaders(e.uri,this.options).then((i=>{e.isDisposed()||e.getVersionId()!==t||this.updateDecorations(i)}))}updateDecorations(e){const t=this.editor.getModel();t&&(e=e.filter((e=>{if(!e.shouldBeInComments)return!0;const i=t.validateRange(e.range),s=t.tokenization.getLineTokens(i.startLineNumber),n=s.findTokenIndexAtOffset(i.startColumn-1),r=s.getStandardTokenType(n);return s.getLanguageId(n)===t.getLanguageId()&&1===r})));const i=Object.values(this.currentOccurrences).map((e=>e.decorationId)),s=e.map((e=>function(e){return{range:e.range,options:a.kI.createDynamic({description:"section-header",stickiness:3,collapseOnReplaceEdit:!0,minimap:{color:void 0,position:1,sectionHeaderStyle:e.hasSeparatorLine?2:1,sectionHeaderText:e.text}})}}(e)));this.editor.changeDecorations((t=>{const n=t.deltaDecorations(i,s);this.currentOccurrences={};for(let i=0,s=n.length;i{"use strict";i.d(t,{Qi:()=>a,XO:()=>r,bs:()=>c});var s=i(41234);const n=Object.freeze((function(e,t){const i=setTimeout(e.bind(t),0);return{dispose(){clearTimeout(i)}}}));var r;!function(e){e.isCancellationToken=function(t){return t===e.None||t===e.Cancelled||(t instanceof o||!(!t||"object"!==typeof t)&&("boolean"===typeof t.isCancellationRequested&&"function"===typeof t.onCancellationRequested))},e.None=Object.freeze({isCancellationRequested:!1,onCancellationRequested:s.Jh.None}),e.Cancelled=Object.freeze({isCancellationRequested:!0,onCancellationRequested:n})}(r||(r={}));class o{constructor(){this._isCancelled=!1,this._emitter=null}cancel(){this._isCancelled||(this._isCancelled=!0,this._emitter&&(this._emitter.fire(void 0),this.dispose()))}get isCancellationRequested(){return this._isCancelled}get onCancellationRequested(){return this._isCancelled?n:(this._emitter||(this._emitter=new s.vl),this._emitter.event)}dispose(){this._emitter&&(this._emitter.dispose(),this._emitter=null)}}class a{constructor(e){this._token=void 0,this._parentListener=void 0,this._parentListener=e&&e.onCancellationRequested(this.cancel,this)}get token(){return this._token||(this._token=new o),this._token}cancel(){this._token?this._token instanceof o&&this._token.cancel():this._token=r.Cancelled}dispose(e=!1){e&&this.cancel(),this._parentListener?.dispose(),this._token?this._token instanceof o&&this._token.dispose():this._token=r.None}}function c(e){const t=new a;return e.add({dispose(){t.cancel()}}),t.token}},18544:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"objective-c",extensions:[".m"],aliases:["Objective-C"],loader:()=>i.e(97638).then(i.bind(i,97638))})},18801:(e,t,i)=>{"use strict";i.d(t,{$b:()=>a,Cr:()=>h,Dk:()=>d,rr:()=>o});var s=i(41234),n=i(5662),r=i(32848);const o=(0,i(63591).u1)("logService");var a;!function(e){e[e.Off=0]="Off",e[e.Trace=1]="Trace",e[e.Debug=2]="Debug",e[e.Info=3]="Info",e[e.Warning=4]="Warning",e[e.Error=5]="Error"}(a||(a={}));const c=a.Info;class l extends n.jG{constructor(){super(...arguments),this.level=c,this._onDidChangeLogLevel=this._register(new s.vl),this.onDidChangeLogLevel=this._onDidChangeLogLevel.event}setLevel(e){this.level!==e&&(this.level=e,this._onDidChangeLogLevel.fire(this.level))}getLevel(){return this.level}checkLogLevel(e){return this.level!==a.Off&&this.level<=e}}class h extends l{constructor(e=c,t=!0){super(),this.useColors=t,this.setLevel(e)}trace(e,...t){this.checkLogLevel(a.Trace)&&(this.useColors?console.log("%cTRACE","color: #888",e,...t):console.log(e,...t))}debug(e,...t){this.checkLogLevel(a.Debug)&&(this.useColors?console.log("%cDEBUG","background: #eee; color: #888",e,...t):console.log(e,...t))}info(e,...t){this.checkLogLevel(a.Info)&&(this.useColors?console.log("%c INFO","color: #33f",e,...t):console.log(e,...t))}warn(e,...t){this.checkLogLevel(a.Warning)&&(this.useColors?console.log("%c WARN","color: #993",e,...t):console.log(e,...t))}error(e,...t){this.checkLogLevel(a.Error)&&(this.useColors?console.log("%c ERR","color: #f33",e,...t):console.error(e,...t))}}class d extends l{constructor(e){super(),this.loggers=e,e.length&&this.setLevel(e[0].getLevel())}setLevel(e){for(const t of this.loggers)t.setLevel(e);super.setLevel(e)}trace(e,...t){for(const i of this.loggers)i.trace(e,...t)}debug(e,...t){for(const i of this.loggers)i.debug(e,...t)}info(e,...t){for(const i of this.loggers)i.info(e,...t)}warn(e,...t){for(const i of this.loggers)i.warn(e,...t)}error(e,...t){for(const i of this.loggers)i.error(e,...t)}dispose(){for(const e of this.loggers)e.dispose();super.dispose()}}new r.N1("logLevel",function(e){switch(e){case a.Trace:return"trace";case a.Debug:return"debug";case a.Info:return"info";case a.Warning:return"warn";case a.Error:return"error";case a.Off:return"off"}}(a.Info))},18864:(e,t,i)=>{"use strict";i.d(t,{d:()=>E});var s,n=i(8597),r=i(5646),o=i(36921),a=i(5662),c=i(98067),l=i(31450),h=i(60002),d=i(78209),u=i(27195),g=i(32848),p=i(47508),m=i(98031),f=i(84001),_=i(37227),v=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},C=function(e,t){return function(i,s){t(i,s,e)}};let E=class{static{s=this}static{this.ID="editor.contrib.contextmenu"}static get(e){return e.getContribution(s.ID)}constructor(e,t,i,s,r,o,c,l){this._contextMenuService=t,this._contextViewService=i,this._contextKeyService=s,this._keybindingService=r,this._menuService=o,this._configurationService=c,this._workspaceContextService=l,this._toDispose=new a.Cm,this._contextMenuIsBeingShownCount=0,this._editor=e,this._toDispose.add(this._editor.onContextMenu((e=>this._onContextMenu(e)))),this._toDispose.add(this._editor.onMouseWheel((e=>{if(this._contextMenuIsBeingShownCount>0){const t=this._contextViewService.getContextViewElement(),i=e.srcElement;i.shadowRoot&&n.jG(t)===i.shadowRoot||this._contextViewService.hideContextView()}}))),this._toDispose.add(this._editor.onKeyDown((e=>{this._editor.getOption(24)&&58===e.keyCode&&(e.preventDefault(),e.stopPropagation(),this.showContextMenu())})))}_onContextMenu(e){if(!this._editor.hasModel())return;if(!this._editor.getOption(24))return this._editor.focus(),void(e.target.position&&!this._editor.getSelection().containsPosition(e.target.position)&&this._editor.setPosition(e.target.position));if(12===e.target.type)return;if(6===e.target.type&&e.target.detail.injectedText)return;if(e.event.preventDefault(),e.event.stopPropagation(),11===e.target.type)return this._showScrollbarContextMenu(e.event);if(6!==e.target.type&&7!==e.target.type&&1!==e.target.type)return;if(this._editor.focus(),e.target.position){let t=!1;for(const i of this._editor.getSelections())if(i.containsPosition(e.target.position)){t=!0;break}t||this._editor.setPosition(e.target.position)}let t=null;1!==e.target.type&&(t=e.event),this.showContextMenu(t)}showContextMenu(e){if(!this._editor.getOption(24))return;if(!this._editor.hasModel())return;const t=this._getMenuActions(this._editor.getModel(),this._editor.contextMenuId);t.length>0&&this._doShowContextMenu(t,e)}_getMenuActions(e,t){const i=[],s=this._menuService.getMenuActions(t,this._contextKeyService,{arg:e.uri});for(const n of s){const[,t]=n;let s=0;for(const n of t)if(n instanceof u.nI){const t=this._getMenuActions(e,n.item.submenu);t.length>0&&(i.push(new o.YH(n.id,n.label,t)),s++)}else i.push(n),s++;s&&i.push(new o.wv)}return i.length&&i.pop(),i}_doShowContextMenu(e,t=null){if(!this._editor.hasModel())return;const i=this._editor.getOption(60);this._editor.updateOptions({hover:{enabled:!1}});let s=t;if(!s){this._editor.revealPosition(this._editor.getPosition(),1),this._editor.render();const e=this._editor.getScrolledVisiblePosition(this._editor.getPosition()),t=n.BK(this._editor.getDomNode()),i=t.left+e.left,r=t.top+e.top+e.height;s={x:i,y:r}}const o=this._editor.getOption(128)&&!c.un;this._contextMenuIsBeingShownCount++,this._contextMenuService.showContextMenu({domForShadowRoot:o?this._editor.getOverflowWidgetsDomNode()??this._editor.getDomNode():void 0,getAnchor:()=>s,getActions:()=>e,getActionViewItem:e=>{const t=this._keybindingFor(e);if(t)return new r.Z4(e,e,{label:!0,keybinding:t.getLabel(),isMenu:!0});const i=e;return"function"===typeof i.getActionViewItem?i.getActionViewItem():new r.Z4(e,e,{icon:!0,label:!0,isMenu:!0})},getKeyBinding:e=>this._keybindingFor(e),onHide:e=>{this._contextMenuIsBeingShownCount--,this._editor.updateOptions({hover:i})}})}_showScrollbarContextMenu(e){if(!this._editor.hasModel())return;if((0,_.ct)(this._workspaceContextService.getWorkspace()))return;const t=this._editor.getOption(73);let i=0;const s=e=>({id:"menu-action-"+ ++i,label:e.label,tooltip:"",class:void 0,enabled:"undefined"===typeof e.enabled||e.enabled,checked:e.checked,run:e.run}),n=(e,t,n,r,a)=>{if(!t)return s({label:e,enabled:t,run:()=>{}});const c=e=>()=>{this._configurationService.updateValue(n,e)},l=[];for(const i of a)l.push(s({label:i.label,checked:r===i.value,run:c(i.value)}));return((e,t)=>new o.YH("menu-action-"+ ++i,e,t,void 0))(e,l)},r=[];r.push(s({label:d.kg("context.minimap.minimap","Minimap"),checked:t.enabled,run:()=>{this._configurationService.updateValue("editor.minimap.enabled",!t.enabled)}})),r.push(new o.wv),r.push(s({label:d.kg("context.minimap.renderCharacters","Render Characters"),enabled:t.enabled,checked:t.renderCharacters,run:()=>{this._configurationService.updateValue("editor.minimap.renderCharacters",!t.renderCharacters)}})),r.push(n(d.kg("context.minimap.size","Vertical size"),t.enabled,"editor.minimap.size",t.size,[{label:d.kg("context.minimap.size.proportional","Proportional"),value:"proportional"},{label:d.kg("context.minimap.size.fill","Fill"),value:"fill"},{label:d.kg("context.minimap.size.fit","Fit"),value:"fit"}])),r.push(n(d.kg("context.minimap.slider","Slider"),t.enabled,"editor.minimap.showSlider",t.showSlider,[{label:d.kg("context.minimap.slider.mouseover","Mouse Over"),value:"mouseover"},{label:d.kg("context.minimap.slider.always","Always"),value:"always"}]));const a=this._editor.getOption(128)&&!c.un;this._contextMenuIsBeingShownCount++,this._contextMenuService.showContextMenu({domForShadowRoot:a?this._editor.getDomNode():void 0,getAnchor:()=>e,getActions:()=>r,onHide:e=>{this._contextMenuIsBeingShownCount--,this._editor.focus()}})}_keybindingFor(e){return this._keybindingService.lookupKeybinding(e.id)}dispose(){this._contextMenuIsBeingShownCount>0&&this._contextViewService.hideContextView(),this._toDispose.dispose()}};E=s=v([C(1,p.Z),C(2,p.l),C(3,g.fN),C(4,m.b),C(5,u.ez),C(6,f.pG),C(7,_.VR)],E);class b extends l.ks{constructor(){super({id:"editor.action.showContextMenu",label:d.kg("action.showContextMenu.label","Show Editor Context Menu"),alias:"Show Editor Context Menu",precondition:void 0,kbOpts:{kbExpr:h.R.textInputFocus,primary:1092,weight:100}})}run(e,t){E.get(t)?.showContextMenu()}}(0,l.HW)(E.ID,E,2),(0,l.Fl)(b)},18938:(e,t,i)=>{"use strict";i.r(t),i.d(t,{ITextModelService:()=>s});const s=(0,i(63591).u1)("textModelService")},18956:(e,t,i)=>{"use strict";i.d(t,{J:()=>o,k:()=>r});var s=i(631);const n=Object.create(null);function r(e,t){if((0,s.Kg)(t)){const i=n[t];if(void 0===i)throw new Error(`${e} references an unknown codicon: ${t}`);t=i}return n[e]=t,{id:e}}function o(){return n}},19070:(e,t,i)=>{"use strict";i.d(t,{Dk:()=>h,IN:()=>u,RE:()=>p,XS:()=>m,cv:()=>o,ho:()=>l,ir:()=>r,m$:()=>d,mk:()=>c,oJ:()=>a,t8:()=>g});var s=i(66261),n=i(47661);const r={keybindingLabelBackground:(0,s.GuP)(s.HDX),keybindingLabelForeground:(0,s.GuP)(s.eUu),keybindingLabelBorder:(0,s.GuP)(s.zUX),keybindingLabelBottomBorder:(0,s.GuP)(s.Qfh),keybindingLabelShadow:(0,s.GuP)(s.f9l)},o={buttonForeground:(0,s.GuP)(s.G_h),buttonSeparator:(0,s.GuP)(s.Q1$),buttonBackground:(0,s.GuP)(s.XJc),buttonHoverBackground:(0,s.GuP)(s.T9h),buttonSecondaryForeground:(0,s.GuP)(s.Inn),buttonSecondaryBackground:(0,s.GuP)(s.xOA),buttonSecondaryHoverBackground:(0,s.GuP)(s.nZG),buttonBorder:(0,s.GuP)(s.raQ)},a={progressBarBackground:(0,s.GuP)(s.BTi)},c={inputActiveOptionBorder:(0,s.GuP)(s.uNK),inputActiveOptionForeground:(0,s.GuP)(s.$$0),inputActiveOptionBackground:(0,s.GuP)(s.c1f)},l=((0,s.GuP)(s.jOE),(0,s.GuP)(s.Ukx),(0,s.GuP)(s.Ips),(0,s.GuP)(s.kPT),(0,s.GuP)(s.xWN),(0,s.GuP)(s.ZBU),(0,s.GuP)(s.jr9),(0,s.GuP)(s.OcU),(0,s.GuP)(s.C5U),(0,s.GuP)(s.t0B),(0,s.GuP)(s.CgL),(0,s.GuP)(s.FiB),(0,s.GuP)(s.f9l),(0,s.GuP)(s.b1q),(0,s.GuP)(s.tYX),(0,s.GuP)(s.JPj),(0,s.GuP)(s.bNw),(0,s.GuP)(s.vwp),{inputBackground:(0,s.GuP)(s.L4c),inputForeground:(0,s.GuP)(s.cws),inputBorder:(0,s.GuP)(s.Zgs),inputValidationInfoBorder:(0,s.GuP)(s.YSW),inputValidationInfoBackground:(0,s.GuP)(s.I$A),inputValidationInfoForeground:(0,s.GuP)(s.L9Z),inputValidationWarningBorder:(0,s.GuP)(s.C1n),inputValidationWarningBackground:(0,s.GuP)(s.ULt),inputValidationWarningForeground:(0,s.GuP)(s.T5N),inputValidationErrorBorder:(0,s.GuP)(s.eYZ),inputValidationErrorBackground:(0,s.GuP)(s._$n),inputValidationErrorForeground:(0,s.GuP)(s.h9z)}),h={listFilterWidgetBackground:(0,s.GuP)(s.pnl),listFilterWidgetOutline:(0,s.GuP)(s.fiM),listFilterWidgetNoMatchesOutline:(0,s.GuP)(s.P9Z),listFilterWidgetShadow:(0,s.GuP)(s.H8q),inputBoxStyles:l,toggleStyles:c},d={badgeBackground:(0,s.GuP)(s.WMx),badgeForeground:(0,s.GuP)(s.zRE),badgeBorder:(0,s.GuP)(s.b1q)},u=((0,s.GuP)(s.vV$),(0,s.GuP)(s.mc0),(0,s.GuP)(s.etE),(0,s.GuP)(s.etE),(0,s.GuP)(s.sAS),{listBackground:void 0,listInactiveFocusForeground:void 0,listFocusBackground:(0,s.GuP)(s.VFX),listFocusForeground:(0,s.GuP)(s.efJ),listFocusOutline:(0,s.GuP)(s.p7Y),listActiveSelectionBackground:(0,s.GuP)(s.Rjz),listActiveSelectionForeground:(0,s.GuP)(s.GVV),listActiveSelectionIconForeground:(0,s.GuP)(s.fED),listFocusAndSelectionOutline:(0,s.GuP)(s.gtq),listFocusAndSelectionBackground:(0,s.GuP)(s.Rjz),listFocusAndSelectionForeground:(0,s.GuP)(s.GVV),listInactiveSelectionBackground:(0,s.GuP)(s.uNx),listInactiveSelectionIconForeground:(0,s.GuP)(s.C9U),listInactiveSelectionForeground:(0,s.GuP)(s.f4y),listInactiveFocusBackground:(0,s.GuP)(s.CQ3),listInactiveFocusOutline:(0,s.GuP)(s.ijf),listHoverBackground:(0,s.GuP)(s.lO1),listHoverForeground:(0,s.GuP)(s.QRv),listDropOverBackground:(0,s.GuP)(s.Yoe),listDropBetweenBackground:(0,s.GuP)(s.yIp),listSelectionOutline:(0,s.GuP)(s.buw),listHoverOutline:(0,s.GuP)(s.buw),treeIndentGuidesStroke:(0,s.GuP)(s.U4U),treeInactiveIndentGuidesStroke:(0,s.GuP)(s.pft),treeStickyScrollBackground:void 0,treeStickyScrollBorder:void 0,treeStickyScrollShadow:(0,s.GuP)(s.bXl),tableColumnsBorder:(0,s.GuP)(s.k5u),tableOddRowsBackgroundColor:(0,s.GuP)(s.sbQ)});function g(e){return function(e,t){const i={...t};for(const n in e){const t=e[n];i[n]=void 0!==t?(0,s.GuP)(t):void 0}return i}(e,u)}const p={selectBackground:(0,s.GuP)(s.rvE),selectListBackground:(0,s.GuP)(s.lWP),selectForeground:(0,s.GuP)(s.yqq),decoratorRightForeground:(0,s.GuP)(s.NBf),selectBorder:(0,s.GuP)(s.HcB),focusBorder:(0,s.GuP)(s.tAP),listFocusBackground:(0,s.GuP)(s.AlL),listInactiveSelectionIconForeground:(0,s.GuP)(s.c7i),listFocusForeground:(0,s.GuP)(s.nH),listFocusOutline:(0,s.HP_)(s.buw,n.Q1.transparent.toString()),listHoverBackground:(0,s.GuP)(s.lO1),listHoverForeground:(0,s.GuP)(s.QRv),listHoverOutline:(0,s.GuP)(s.buw),selectListBorder:(0,s.GuP)(s.sIe),listBackground:void 0,listActiveSelectionBackground:void 0,listActiveSelectionForeground:void 0,listActiveSelectionIconForeground:void 0,listFocusAndSelectionBackground:void 0,listDropOverBackground:void 0,listDropBetweenBackground:void 0,listInactiveSelectionBackground:void 0,listInactiveSelectionForeground:void 0,listInactiveFocusBackground:void 0,listInactiveFocusOutline:void 0,listSelectionOutline:void 0,listFocusAndSelectionForeground:void 0,listFocusAndSelectionOutline:void 0,listInactiveFocusForeground:void 0,tableColumnsBorder:void 0,tableOddRowsBackgroundColor:void 0,treeIndentGuidesStroke:void 0,treeInactiveIndentGuidesStroke:void 0,treeStickyScrollBackground:void 0,treeStickyScrollBorder:void 0,treeStickyScrollShadow:void 0},m={shadowColor:(0,s.GuP)(s.f9l),borderColor:(0,s.GuP)(s.g$2),foregroundColor:(0,s.GuP)(s.dd_),backgroundColor:(0,s.GuP)(s.c6Y),selectionForegroundColor:(0,s.GuP)(s.pmr),selectionBackgroundColor:(0,s.GuP)(s.Ux$),selectionBorderColor:(0,s.GuP)(s.SNb),separatorColor:(0,s.GuP)(s.D7X),scrollbarShadow:(0,s.GuP)(s.bXl),scrollbarSliderBackground:(0,s.GuP)(s.gnV),scrollbarSliderHoverBackground:(0,s.GuP)(s.cI_),scrollbarSliderActiveBackground:(0,s.GuP)(s.mhZ)}},19131:(e,t,i)=>{"use strict";i.d(t,{C7:()=>o,MS:()=>_,QB:()=>p,Qx:()=>S,VL:()=>b,Vh:()=>c,Vp:()=>a,eu:()=>u,l4:()=>d,o0:()=>E,pW:()=>m,qe:()=>h,rR:()=>y,sS:()=>g,vr:()=>C,wP:()=>f,zG:()=>v});var s=i(91508),n=i(36677),r=i(50973);function o(e,t,i,s){return e!==i?h(i-e,s):h(0,s-t)}const a=0;function c(e){return 0===e}const l=2**26;function h(e,t){return e*l+t}function d(e){const t=e,i=Math.floor(t/l),s=t-i*l;return new r.W(i,s)}function u(e){return Math.floor(e/l)}function g(e){return e}function p(e,t){let i=e+t;return t>=l&&(i-=e%l),i}function m(e,t){return e.reduce(((e,i)=>p(e,t(i))),a)}function f(e,t){return e===t}function _(e,t){const i=e,s=t;if(s-i<=0)return a;const n=Math.floor(i/l),r=Math.floor(s/l),o=s-r*l;if(n===r){return h(0,o-(i-n*l))}return h(r-n,o)}function v(e,t){return e=t}function b(e){return h(e.lineNumber-1,e.column-1)}function S(e,t){const i=e,s=Math.floor(i/l),r=i-s*l,o=t,a=Math.floor(o/l),c=o-a*l;return new n.Q(s+1,r+1,a+1,c+1)}function y(e){const t=(0,s.uz)(e);return h(t.length-1,t[t.length-1].length)}},19436:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"less",extensions:[".less"],aliases:["Less","less"],mimetypes:["text/x-less","text/less"],loader:()=>i.e(33338).then(i.bind(i,33338))})},19466:(e,t,i)=>{"use strict";i.d(t,{DO:()=>q,w0:()=>x,KP:()=>s,RD:()=>O,vD:()=>I});var s,n=i(8597),r=(i(56245),i(72962)),o=(i(11799),i(88443),i(91581)),a=i(66700),c=i(93090),l=i(35315),h=i(37472),d=i(84565),u=(i(36921),i(25890)),g=i(90766),p=i(10350),m=i(25689),f=i(74320),_=i(41234),v=i(26690),C=i(5662),E=i(1592),b=i(631),S=i(78209),y=(i(42904),i(31308)),w=i(11007);class R extends a.ur{constructor(e){super(e.elements.map((e=>e.element))),this.data=e}}function L(e){return e instanceof a.ur?new R(e):e}class T{constructor(e,t){this.modelProvider=e,this.dnd=t,this.autoExpandDisposable=C.jG.None,this.disposables=new C.Cm}getDragURI(e){return this.dnd.getDragURI(e.element)}getDragLabel(e,t){if(this.dnd.getDragLabel)return this.dnd.getDragLabel(e.map((e=>e.element)),t)}onDragStart(e,t){this.dnd.onDragStart?.(L(e),t)}onDragOver(e,t,i,s,n,r=!0){const o=this.dnd.onDragOver(L(e),t&&t.element,i,s,n),a=this.autoExpandNode!==t;if(a&&(this.autoExpandDisposable.dispose(),this.autoExpandNode=t),"undefined"===typeof t)return o;if(a&&"boolean"!==typeof o&&o.autoExpand&&(this.autoExpandDisposable=(0,g.EQ)((()=>{const e=this.modelProvider(),i=e.getNodeLocation(t);e.isCollapsed(i)&&e.setCollapsed(i,!1),this.autoExpandNode=void 0}),500,this.disposables)),"boolean"===typeof o||!o.accept||"undefined"===typeof o.bubble||o.feedback){if(!r){return{accept:"boolean"===typeof o?o:o.accept,effect:"boolean"===typeof o?void 0:o.effect,feedback:[i]}}return o}if(1===o.bubble){const i=this.modelProvider(),r=i.getNodeLocation(t),o=i.getParentNodeLocation(r),a=i.getNode(o),c=o&&i.getListIndex(o);return this.onDragOver(e,a,c,s,n,!1)}const c=this.modelProvider(),l=c.getNodeLocation(t),h=c.getListIndex(l),d=c.getListRenderCount(l);return{...o,feedback:(0,u.y1)(h,h+d)}}drop(e,t,i,s,n){this.autoExpandDisposable.dispose(),this.autoExpandNode=void 0,this.dnd.drop(L(e),t&&t.element,i,s,n)}onDragEnd(e){this.dnd.onDragEnd?.(e)}dispose(){this.disposables.dispose(),this.dnd.dispose()}}class x{constructor(e){this.delegate=e}getHeight(e){return this.delegate.getHeight(e.element)}getTemplateId(e){return this.delegate.getTemplateId(e.element)}hasDynamicHeight(e){return!!this.delegate.hasDynamicHeight&&this.delegate.hasDynamicHeight(e.element)}setDynamicHeight(e,t){this.delegate.setDynamicHeight?.(e.element,t)}}!function(e){e.None="none",e.OnHover="onHover",e.Always="always"}(s||(s={}));class k{get elements(){return this._elements}constructor(e,t=[]){this._elements=t,this.disposables=new C.Cm,this.onDidChange=_.Jh.forEach(e,(e=>this._elements=e),this.disposables)}dispose(){this.disposables.dispose()}}class A{static{this.DefaultIndent=8}constructor(e,t,i,s,n,r={}){this.renderer=e,this.modelProvider=t,this.activeNodes=s,this.renderedIndentGuides=n,this.renderedElements=new Map,this.renderedNodes=new Map,this.indent=A.DefaultIndent,this.hideTwistiesOfChildlessElements=!1,this.shouldRenderIndentGuides=!1,this.activeIndentNodes=new Set,this.indentGuidesDisposable=C.jG.None,this.disposables=new C.Cm,this.templateId=e.templateId,this.updateOptions(r),_.Jh.map(i,(e=>e.node))(this.onDidChangeNodeTwistieState,this,this.disposables),e.onDidChangeTwistieState?.(this.onDidChangeTwistieState,this,this.disposables)}updateOptions(e={}){if("undefined"!==typeof e.indent){const t=(0,E.qE)(e.indent,0,40);if(t!==this.indent){this.indent=t;for(const[e,t]of this.renderedNodes)this.renderTreeElement(e,t)}}if("undefined"!==typeof e.renderIndentGuides){const t=e.renderIndentGuides!==s.None;if(t!==this.shouldRenderIndentGuides){this.shouldRenderIndentGuides=t;for(const[e,t]of this.renderedNodes)this._renderIndentGuides(e,t);if(this.indentGuidesDisposable.dispose(),t){const e=new C.Cm;this.activeNodes.onDidChange(this._onDidChangeActiveNodes,this,e),this.indentGuidesDisposable=e,this._onDidChangeActiveNodes(this.activeNodes.elements)}}}"undefined"!==typeof e.hideTwistiesOfChildlessElements&&(this.hideTwistiesOfChildlessElements=e.hideTwistiesOfChildlessElements)}renderTemplate(e){const t=(0,n.BC)(e,(0,n.$)(".monaco-tl-row")),i=(0,n.BC)(t,(0,n.$)(".monaco-tl-indent")),s=(0,n.BC)(t,(0,n.$)(".monaco-tl-twistie")),r=(0,n.BC)(t,(0,n.$)(".monaco-tl-contents")),o=this.renderer.renderTemplate(r);return{container:e,indent:i,twistie:s,indentGuidesDisposable:C.jG.None,templateData:o}}renderElement(e,t,i,s){this.renderedNodes.set(e,i),this.renderedElements.set(e.element,e),this.renderTreeElement(e,i),this.renderer.renderElement(e,t,i.templateData,s)}disposeElement(e,t,i,s){i.indentGuidesDisposable.dispose(),this.renderer.disposeElement?.(e,t,i.templateData,s),"number"===typeof s&&(this.renderedNodes.delete(e),this.renderedElements.delete(e.element))}disposeTemplate(e){this.renderer.disposeTemplate(e.templateData)}onDidChangeTwistieState(e){const t=this.renderedElements.get(e);t&&this.onDidChangeNodeTwistieState(t)}onDidChangeNodeTwistieState(e){const t=this.renderedNodes.get(e);t&&(this._onDidChangeActiveNodes(this.activeNodes.elements),this.renderTreeElement(e,t))}renderTreeElement(e,t){const i=A.DefaultIndent+(e.depth-1)*this.indent;t.twistie.style.paddingLeft=`${i}px`,t.indent.style.width=i+this.indent-16+"px",e.collapsible?t.container.setAttribute("aria-expanded",String(!e.collapsed)):t.container.removeAttribute("aria-expanded"),t.twistie.classList.remove(...m.L.asClassNameArray(p.W.treeItemExpanded));let s=!1;this.renderer.renderTwistie&&(s=this.renderer.renderTwistie(e.element,t.twistie)),e.collapsible&&(!this.hideTwistiesOfChildlessElements||e.visibleChildrenCount>0)?(s||t.twistie.classList.add(...m.L.asClassNameArray(p.W.treeItemExpanded)),t.twistie.classList.add("collapsible"),t.twistie.classList.toggle("collapsed",e.collapsed)):t.twistie.classList.remove("collapsible","collapsed"),this._renderIndentGuides(e,t)}_renderIndentGuides(e,t){if((0,n.w_)(t.indent),t.indentGuidesDisposable.dispose(),!this.shouldRenderIndentGuides)return;const i=new C.Cm,s=this.modelProvider();for(;;){const r=s.getNodeLocation(e),o=s.getParentNodeLocation(r);if(!o)break;const a=s.getNode(o),c=(0,n.$)(".indent-guide",{style:`width: ${this.indent}px`});this.activeIndentNodes.has(a)&&c.classList.add("active"),0===t.indent.childElementCount?t.indent.appendChild(c):t.indent.insertBefore(c,t.indent.firstElementChild),this.renderedIndentGuides.add(a,c),i.add((0,C.s)((()=>this.renderedIndentGuides.delete(a,c)))),e=a}t.indentGuidesDisposable=i}_onDidChangeActiveNodes(e){if(!this.shouldRenderIndentGuides)return;const t=new Set,i=this.modelProvider();e.forEach((e=>{const s=i.getNodeLocation(e);try{const n=i.getParentNodeLocation(s);e.collapsible&&e.children.length>0&&!e.collapsed?t.add(e):n&&t.add(i.getNode(n))}catch{}})),this.activeIndentNodes.forEach((e=>{t.has(e)||this.renderedIndentGuides.forEach(e,(e=>e.classList.remove("active")))})),t.forEach((e=>{this.activeIndentNodes.has(e)||this.renderedIndentGuides.forEach(e,(e=>e.classList.add("active")))})),this.activeIndentNodes=t}dispose(){this.renderedNodes.clear(),this.renderedElements.clear(),this.indentGuidesDisposable.dispose(),(0,C.AS)(this.disposables)}}class N{get totalCount(){return this._totalCount}get matchCount(){return this._matchCount}constructor(e,t,i){this.tree=e,this.keyboardNavigationLabelProvider=t,this._filter=i,this._totalCount=0,this._matchCount=0,this._pattern="",this._lowercasePattern="",this.disposables=new C.Cm,e.onWillRefilter(this.reset,this,this.disposables)}filter(e,t){let i=1;if(this._filter){const s=this._filter.filter(e,t);if(i="boolean"===typeof s?s?1:0:(0,h.iZ)(s)?(0,h.Mn)(s.visibility):s,0===i)return!1}if(this._totalCount++,!this._pattern)return this._matchCount++,{data:v.ne.Default,visibility:i};const s=this.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(e),n=Array.isArray(s)?s:[s];for(const r of n){const e=r&&r.toString();if("undefined"===typeof e)return{data:v.ne.Default,visibility:i};let t;if(this.tree.findMatchType===O.Contiguous){const i=e.toLowerCase().indexOf(this._lowercasePattern);if(i>-1){t=[Number.MAX_SAFE_INTEGER,0];for(let e=this._lowercasePattern.length;e>0;e--)t.push(i+e-1)}}else t=(0,v.dt)(this._pattern,this._lowercasePattern,0,e,e.toLowerCase(),0,{firstMatchCanBeWeak:!0,boostFullMatch:!0});if(t)return this._matchCount++,1===n.length?{data:t,visibility:i}:{data:{label:e,score:t},visibility:i}}return this.tree.findMode===I.Filter?"number"===typeof this.tree.options.defaultFindVisibility?this.tree.options.defaultFindVisibility:this.tree.options.defaultFindVisibility?this.tree.options.defaultFindVisibility(e):2:{data:v.ne.Default,visibility:i}}reset(){this._totalCount=0,this._matchCount=0}dispose(){(0,C.AS)(this.disposables)}}l.l;l.l;o.x8,l.F;var I,O;!function(e){e[e.Highlight=0]="Highlight",e[e.Filter=1]="Filter"}(I||(I={})),function(e){e[e.Fuzzy=0]="Fuzzy",e[e.Contiguous=1]="Contiguous"}(O||(O={}));C.jG;class D{get pattern(){return this._pattern}get mode(){return this._mode}set mode(e){e!==this._mode&&(this._mode=e,this.widget&&(this.widget.mode=this._mode),this.tree.refilter(),this.render(),this._onDidChangeMode.fire(e))}get matchType(){return this._matchType}set matchType(e){e!==this._matchType&&(this._matchType=e,this.widget&&(this.widget.matchType=this._matchType),this.tree.refilter(),this.render(),this._onDidChangeMatchType.fire(e))}constructor(e,t,i,s,n,r={}){this.tree=e,this.view=i,this.filter=s,this.contextViewProvider=n,this.options=r,this._pattern="",this.width=0,this._onDidChangeMode=new _.vl,this.onDidChangeMode=this._onDidChangeMode.event,this._onDidChangeMatchType=new _.vl,this.onDidChangeMatchType=this._onDidChangeMatchType.event,this._onDidChangePattern=new _.vl,this._onDidChangeOpenState=new _.vl,this.onDidChangeOpenState=this._onDidChangeOpenState.event,this.enabledDisposables=new C.Cm,this.disposables=new C.Cm,this._mode=e.options.defaultFindMode??I.Highlight,this._matchType=e.options.defaultFindMatchType??O.Fuzzy,t.onDidSplice(this.onDidSpliceModel,this,this.disposables)}updateOptions(e={}){void 0!==e.defaultFindMode&&(this.mode=e.defaultFindMode),void 0!==e.defaultFindMatchType&&(this.matchType=e.defaultFindMatchType)}onDidSpliceModel(){this.widget&&0!==this.pattern.length&&(this.tree.refilter(),this.render())}render(){const e=this.filter.totalCount>0&&0===this.filter.matchCount;this.pattern&&e?((0,w.xE)((0,S.kg)("replFindNoResults","No results")),this.tree.options.showNotFoundMessage??1?this.widget?.showMessage({type:2,content:(0,S.kg)("not found","No elements found.")}):this.widget?.showMessage({type:2})):(this.widget?.clearMessage(),this.pattern&&(0,w.xE)((0,S.kg)("replFindResults","{0} results",this.filter.matchCount)))}shouldAllowFocus(e){return!this.widget||!this.pattern||(this.filter.totalCount>0&&this.filter.matchCount<=1||!v.ne.isDefault(e.filterData))}layout(e){this.width=e,this.widget?.layout(e)}dispose(){this._history=void 0,this._onDidChangePattern.dispose(),this.enabledDisposables.dispose(),this.disposables.dispose()}}function M(e,t){return e.position===t.position&&P(e,t)}function P(e,t){return e.node.element===t.node.element&&e.startIndex===t.startIndex&&e.height===t.height&&e.endIndex===t.endIndex}class F{constructor(e=[]){this.stickyNodes=e}get count(){return this.stickyNodes.length}equal(e){return(0,u.aI)(this.stickyNodes,e.stickyNodes,M)}lastNodePartiallyVisible(){if(0===this.count)return!1;const e=this.stickyNodes[this.count-1];if(1===this.count)return 0!==e.position;const t=this.stickyNodes[this.count-2];return t.position+t.height!==e.position}animationStateChanged(e){if(!(0,u.aI)(this.stickyNodes,e.stickyNodes,P))return!1;if(0===this.count)return!1;const t=this.stickyNodes[this.count-1],i=e.stickyNodes[e.count-1];return t.position!==i.position}}class U{constrainStickyScrollNodes(e,t,i){for(let s=0;si||s>=t)return e.slice(0,s)}return e}}class H extends C.jG{constructor(e,t,i,s,n,r={}){super(),this.tree=e,this.model=t,this.view=i,this.treeDelegate=n,this.maxWidgetViewRatio=.4;const o=this.validateStickySettings(r);this.stickyScrollMaxItemCount=o.stickyScrollMaxItemCount,this.stickyScrollDelegate=r.stickyScrollDelegate??new U,this._widget=this._register(new B(i.getScrollableElement(),i,e,s,n,r.accessibilityProvider)),this.onDidChangeHasFocus=this._widget.onDidChangeHasFocus,this.onContextMenu=this._widget.onContextMenu,this._register(i.onDidScroll((()=>this.update()))),this._register(i.onDidChangeContentHeight((()=>this.update()))),this._register(e.onDidChangeCollapseState((()=>this.update()))),this.update()}get height(){return this._widget.height}getNodeAtHeight(e){let t;if(t=0===e?this.view.firstVisibleIndex:this.view.indexAt(e+this.view.scrollTop),!(t<0||t>=this.view.length))return this.view.element(t)}update(){const e=this.getNodeAtHeight(0);if(!e||0===this.tree.scrollTop)return void this._widget.setState(void 0);const t=this.findStickyState(e);this._widget.setState(t)}findStickyState(e){const t=[];let i=e,s=0,n=this.getNextStickyNode(i,void 0,s);for(;n&&(t.push(n),s+=n.height,!(t.length<=this.stickyScrollMaxItemCount)||(i=this.getNextVisibleNode(n),i));)n=this.getNextStickyNode(i,n.node,s);const r=this.constrainStickyNodes(t);return r.length?new F(r):void 0}getNextVisibleNode(e){return this.getNodeAtHeight(e.position+e.height)}getNextStickyNode(e,t,i){const s=this.getAncestorUnderPrevious(e,t);if(s){if(s===e){if(!this.nodeIsUncollapsedParent(e))return;if(this.nodeTopAlignsWithStickyNodesBottom(e,i))return}return this.createStickyScrollNode(s,i)}}nodeTopAlignsWithStickyNodesBottom(e,t){const i=this.getNodeIndex(e),s=this.view.getElementTop(i),n=t;return this.view.scrollTop===s-n}createStickyScrollNode(e,t){const i=this.treeDelegate.getHeight(e),{startIndex:s,endIndex:n}=this.getNodeRange(e);return{node:e,position:this.calculateStickyNodePosition(n,t,i),height:i,startIndex:s,endIndex:n}}getAncestorUnderPrevious(e,t=void 0){let i=e,s=this.getParentNode(i);for(;s;){if(s===t)return i;i=s,s=this.getParentNode(i)}if(void 0===t)return i}calculateStickyNodePosition(e,t,i){let s=this.view.getRelativeTop(e);if(null===s&&this.view.firstVisibleIndex===e&&e+1o&&t<=o?o-i:t}constrainStickyNodes(e){if(0===e.length)return[];const t=this.view.renderHeight*this.maxWidgetViewRatio,i=e[e.length-1];if(e.length<=this.stickyScrollMaxItemCount&&i.position+i.height<=t)return e;const s=this.stickyScrollDelegate.constrainStickyScrollNodes(e,this.stickyScrollMaxItemCount,t);if(!s.length)return[];const n=s[s.length-1];if(s.length>this.stickyScrollMaxItemCount||n.position+n.height>t)throw new Error("stickyScrollDelegate violates constraints");return s}getParentNode(e){const t=this.model.getNodeLocation(e),i=this.model.getParentNodeLocation(t);return i?this.model.getNode(i):void 0}nodeIsUncollapsedParent(e){const t=this.model.getNodeLocation(e);return this.model.getListRenderCount(t)>1}getNodeIndex(e){const t=this.model.getNodeLocation(e);return this.model.getListIndex(t)}getNodeRange(e){const t=this.model.getNodeLocation(e),i=this.model.getListIndex(t);if(i<0)throw new Error("Node not found in tree");return{startIndex:i,endIndex:i+this.model.getListRenderCount(t)-1}}nodePositionTopBelowWidget(e){const t=[];let i=this.getParentNode(e);for(;i;)t.push(i),i=this.getParentNode(i);let s=0;for(let n=0;n0,i=!!e&&e.count>0;if(!t&&!i||t&&i&&this._previousState.equal(e))return;if(t!==i&&this.setVisible(i),!i)return this._previousState=void 0,this._previousElements=[],void this._previousStateDisposables.clear();const s=e.stickyNodes[e.count-1];if(this._previousState&&e.animationStateChanged(this._previousState))this._previousElements[this._previousState.count-1].style.top=`${s.position}px`;else{this._previousStateDisposables.clear();const t=Array(e.count);for(let i=e.count-1;i>=0;i--){const s=e.stickyNodes[i],{element:n,disposable:r}=this.createElement(s,i,e.count);t[i]=n,this._rootDomNode.appendChild(n),this._previousStateDisposables.add(r)}this.stickyScrollFocus.updateElements(t,e),this._previousElements=t}this._previousState=e,this._rootDomNode.style.height=`${s.position+s.height}px`}createElement(e,t,i){const s=e.startIndex,n=document.createElement("div");n.style.top=`${e.position}px`,!1!==this.tree.options.setRowHeight&&(n.style.height=`${e.height}px`),!1!==this.tree.options.setRowLineHeight&&(n.style.lineHeight=`${e.height}px`),n.classList.add("monaco-tree-sticky-row"),n.classList.add("monaco-list-row"),n.setAttribute("data-index",`${s}`),n.setAttribute("data-parity",s%2===0?"even":"odd"),n.setAttribute("id",this.view.getElementID(s));const r=this.setAccessibilityAttributes(n,e.node.element,t,i),o=this.treeDelegate.getTemplateId(e.node),a=this.treeRenderers.find((e=>e.templateId===o));if(!a)throw new Error(`No renderer found for template id ${o}`);let c=e.node;c===this.tree.getNode(this.tree.getNodeLocation(e.node))&&(c=new Proxy(e.node,{}));const l=a.renderTemplate(n);a.renderElement(c,e.startIndex,l,e.height);const h=(0,C.s)((()=>{r.dispose(),a.disposeElement(c,e.startIndex,l,e.height),a.disposeTemplate(l),n.remove()}));return{element:n,disposable:h}}setAccessibilityAttributes(e,t,i,s){if(!this.accessibilityProvider)return C.jG.None;this.accessibilityProvider.getSetSize&&e.setAttribute("aria-setsize",String(this.accessibilityProvider.getSetSize(t,i,s))),this.accessibilityProvider.getPosInSet&&e.setAttribute("aria-posinset",String(this.accessibilityProvider.getPosInSet(t,i))),this.accessibilityProvider.getRole&&e.setAttribute("role",this.accessibilityProvider.getRole(t)??"treeitem");const n=this.accessibilityProvider.getAriaLabel(t),r=n&&"string"!==typeof n?n:(0,y.lk)(n),o=(0,y.fm)((t=>{const i=t.readObservable(r);i?e.setAttribute("aria-label",i):e.removeAttribute("aria-label")}));"string"===typeof n||n&&e.setAttribute("aria-label",n.get());const a=this.accessibilityProvider.getAriaLevel&&this.accessibilityProvider.getAriaLevel(t);return"number"===typeof a&&e.setAttribute("aria-level",`${a}`),e.setAttribute("aria-selected",String(!1)),o}setVisible(e){this._rootDomNode.classList.toggle("empty",!e),e||this.stickyScrollFocus.updateElements([],void 0)}domFocus(){this.stickyScrollFocus.domFocus()}focusedLast(){return this.stickyScrollFocus.focusedLast()}dispose(){this.stickyScrollFocus.dispose(),this._previousStateDisposables.dispose(),this._rootDomNode.remove()}}class W extends C.jG{get domHasFocus(){return this._domHasFocus}set domHasFocus(e){e!==this._domHasFocus&&(this._onDidChangeHasFocus.fire(e),this._domHasFocus=e)}constructor(e,t){super(),this.container=e,this.view=t,this.focusedIndex=-1,this.elements=[],this._onDidChangeHasFocus=new _.vl,this.onDidChangeHasFocus=this._onDidChangeHasFocus.event,this._onContextMenu=new _.vl,this.onContextMenu=this._onContextMenu.event,this._domHasFocus=!1,this._register((0,n.ko)(this.container,"focus",(()=>this.onFocus()))),this._register((0,n.ko)(this.container,"blur",(()=>this.onBlur()))),this._register(this.view.onDidFocus((()=>this.toggleStickyScrollFocused(!1)))),this._register(this.view.onKeyDown((e=>this.onKeyDown(e)))),this._register(this.view.onMouseDown((e=>this.onMouseDown(e)))),this._register(this.view.onContextMenu((e=>this.handleContextMenu(e))))}handleContextMenu(e){const t=e.browserEvent.target;if(!(0,c.Es)(t)&&!(0,c.xu)(t))return void(this.focusedLast()&&this.view.domFocus());if(!(0,n.kx)(e.browserEvent)){if(!this.state)throw new Error("Context menu should not be triggered when state is undefined");const t=this.state.stickyNodes.findIndex((t=>t.node.element===e.element?.element));if(-1===t)throw new Error("Context menu should not be triggered when element is not in sticky scroll widget");return this.container.focus(),void this.setFocus(t)}if(!this.state||this.focusedIndex<0)throw new Error("Context menu key should not be triggered when focus is not in sticky scroll widget");const i=this.state.stickyNodes[this.focusedIndex].node.element,s=this.elements[this.focusedIndex];this._onContextMenu.fire({element:i,anchor:s,browserEvent:e.browserEvent,isStickyScroll:!0})}onKeyDown(e){if(this.domHasFocus&&this.state)if("ArrowUp"===e.key)this.setFocusedElement(Math.max(0,this.focusedIndex-1)),e.preventDefault(),e.stopPropagation();else if("ArrowDown"===e.key||"ArrowRight"===e.key){if(this.focusedIndex>=this.state.count-1){const e=this.state.stickyNodes[this.state.count-1].startIndex+1;this.view.domFocus(),this.view.setFocus([e]),this.scrollNodeUnderWidget(e,this.state)}else this.setFocusedElement(this.focusedIndex+1);e.preventDefault(),e.stopPropagation()}}onMouseDown(e){const t=e.browserEvent.target;((0,c.Es)(t)||(0,c.xu)(t))&&(e.browserEvent.preventDefault(),e.browserEvent.stopPropagation())}updateElements(e,t){if(t&&0===t.count)throw new Error("Sticky scroll state must be undefined when there are no sticky nodes");if(t&&t.count!==e.length)throw new Error("Sticky scroll focus received illigel state");const i=this.focusedIndex;if(this.removeFocus(),this.elements=e,this.state=t,t){const e=(0,E.qE)(i,0,t.count-1);this.setFocus(e)}else this.domHasFocus&&this.view.domFocus();this.container.tabIndex=t?0:-1}setFocusedElement(e){const t=this.state;if(!t)throw new Error("Cannot set focus when state is undefined");if(this.setFocus(e),!(e1?t.stickyNodes[t.count-2]:void 0,n=this.view.getElementTop(e),r=s?s.position+s.height+i.height:i.height;this.view.scrollTop=n-r}domFocus(){if(!this.state)throw new Error("Cannot focus when state is undefined");this.container.focus()}focusedLast(){return!!this.state&&this.view.getHTMLElement().classList.contains("sticky-scroll-focused")}removeFocus(){-1!==this.focusedIndex&&(this.toggleElementFocus(this.elements[this.focusedIndex],!1),this.focusedIndex=-1)}setFocus(e){if(0>e)throw new Error("addFocus() can not remove focus");if(!this.state&&e>=0)throw new Error("Cannot set focus index when state is undefined");if(this.state&&e>=this.state.count)throw new Error("Cannot set focus index to an index that does not exist");const t=this.focusedIndex;t>=0&&this.toggleElementFocus(this.elements[t],!1),e>=0&&this.toggleElementFocus(this.elements[e],!0),this.focusedIndex=e}toggleElementFocus(e,t){this.toggleElementActiveFocus(e,t&&this.domHasFocus),this.toggleElementPassiveFocus(e,t)}toggleCurrentElementActiveFocus(e){-1!==this.focusedIndex&&this.toggleElementActiveFocus(this.elements[this.focusedIndex],e)}toggleElementActiveFocus(e,t){e.classList.toggle("focused",t)}toggleElementPassiveFocus(e,t){e.classList.toggle("passive-focused",t)}toggleStickyScrollFocused(e){this.view.getHTMLElement().classList.toggle("sticky-scroll-focused",e)}onFocus(){if(!this.state||0===this.elements.length)throw new Error("Cannot focus when state is undefined or elements are empty");this.domHasFocus=!0,this.toggleStickyScrollFocused(!0),this.toggleCurrentElementActiveFocus(!0),-1===this.focusedIndex&&this.setFocus(0)}onBlur(){this.domHasFocus=!1,this.toggleCurrentElementActiveFocus(!1)}dispose(){this.toggleStickyScrollFocused(!1),this._onDidChangeHasFocus.fire(!1),super.dispose()}}function V(e){let t=d.Lx.Unknown;return(0,n.XD)(e.browserEvent.target,"monaco-tl-twistie","monaco-tl-row")?t=d.Lx.Twistie:(0,n.XD)(e.browserEvent.target,"monaco-tl-contents","monaco-tl-row")?t=d.Lx.Element:(0,n.XD)(e.browserEvent.target,"monaco-tree-type-filter","monaco-list")&&(t=d.Lx.Filter),{browserEvent:e.browserEvent,element:e.element?e.element.element:null,target:t}}function z(e){const t=(0,c.Es)(e.browserEvent.target);return{element:e.element?e.element.element:null,browserEvent:e.browserEvent,anchor:e.anchor,isStickyScroll:t}}function G(e,t){t(e),e.children.forEach((e=>G(e,t)))}class j{get nodeSet(){return this._nodeSet||(this._nodeSet=this.createNodeSet()),this._nodeSet}constructor(e,t){this.getFirstViewElementWithTrait=e,this.identityProvider=t,this.nodes=[],this._onDidChange=new _.vl,this.onDidChange=this._onDidChange.event}set(e,t){!t?.__forceEvent&&(0,u.aI)(this.nodes,e)||this._set(e,!1,t)}_set(e,t,i){if(this.nodes=[...e],this.elements=void 0,this._nodeSet=void 0,!t){const e=this;this._onDidChange.fire({get elements(){return e.get()},browserEvent:i})}}get(){return this.elements||(this.elements=this.nodes.map((e=>e.element))),[...this.elements]}getNodes(){return this.nodes}has(e){return this.nodeSet.has(e)}onDidModelSplice({insertedNodes:e,deletedNodes:t}){if(!this.identityProvider){const e=this.createNodeSet(),i=t=>e.delete(t);return t.forEach((e=>G(e,i))),void this.set([...e.values()])}const i=new Set,s=e=>i.add(this.identityProvider.getId(e.element).toString());t.forEach((e=>G(e,s)));const n=new Map,r=e=>n.set(this.identityProvider.getId(e.element).toString(),e);e.forEach((e=>G(e,r)));const o=[];for(const a of this.nodes){const e=this.identityProvider.getId(a.element).toString();if(i.has(e)){const t=n.get(e);t&&t.visible&&o.push(t)}else o.push(a)}if(this.nodes.length>0&&0===o.length){const e=this.getFirstViewElementWithTrait();e&&o.push(e)}this._set(o,!0)}createNodeSet(){const e=new Set;for(const t of this.nodes)e.add(t);return e}}class K extends c.MH{constructor(e,t,i){super(e),this.tree=t,this.stickyScrollProvider=i}onViewPointer(e){if((0,c.Bm)(e.browserEvent.target)||(0,c.B6)(e.browserEvent.target)||(0,c.bm)(e.browserEvent.target))return;if(e.browserEvent.isHandledByList)return;const t=e.element;if(!t)return super.onViewPointer(e);if(this.isSelectionRangeChangeEvent(e)||this.isSelectionSingleChangeEvent(e))return super.onViewPointer(e);const i=e.browserEvent.target,s=i.classList.contains("monaco-tl-twistie")||i.classList.contains("monaco-icon-label")&&i.classList.contains("folder-icon")&&e.browserEvent.offsetX<16,n=(0,c.xu)(e.browserEvent.target);let r=!1;if(r=!!n||("function"===typeof this.tree.expandOnlyOnTwistieClick?this.tree.expandOnlyOnTwistieClick(t.element):!!this.tree.expandOnlyOnTwistieClick),n)this.handleStickyScrollMouseEvent(e,t);else{if(r&&!s&&2!==e.browserEvent.detail)return super.onViewPointer(e);if(!this.tree.expandOnDoubleClick&&2===e.browserEvent.detail)return super.onViewPointer(e)}if(t.collapsible&&(!n||s)){const i=this.tree.getNodeLocation(t),n=e.browserEvent.altKey;if(this.tree.setFocus([i]),this.tree.toggleCollapsed(i,n),s)return void(e.browserEvent.isHandledByList=!0)}n||super.onViewPointer(e)}handleStickyScrollMouseEvent(e,t){if((0,c.b$)(e.browserEvent.target)||(0,c.W0)(e.browserEvent.target))return;const i=this.stickyScrollProvider();if(!i)throw new Error("Sticky scroll controller not found");const s=this.list.indexOf(t),n=this.list.getElementTop(s),r=i.nodePositionTopBelowWidget(t);this.tree.scrollTop=n-r,this.list.domFocus(),this.list.setFocus([s]),this.list.setSelection([s])}onDoubleClick(e){!e.browserEvent.target.classList.contains("monaco-tl-twistie")&&this.tree.expandOnDoubleClick&&(e.browserEvent.isHandledByList||super.onDoubleClick(e))}onMouseDown(e){const t=e.browserEvent.target;(0,c.Es)(t)||(0,c.xu)(t)||super.onMouseDown(e)}onContextMenu(e){const t=e.browserEvent.target;(0,c.Es)(t)||(0,c.xu)(t)||super.onContextMenu(e)}}class Y extends c.B8{constructor(e,t,i,s,n,r,o,a){super(e,t,i,s,a),this.focusTrait=n,this.selectionTrait=r,this.anchorTrait=o}createMouseController(e){return new K(this,e.tree,e.stickyScrollProvider)}splice(e,t,i=[]){if(super.splice(e,t,i),0===i.length)return;const s=[],n=[];let r;i.forEach(((t,i)=>{this.focusTrait.has(t)&&s.push(e+i),this.selectionTrait.has(t)&&n.push(e+i),this.anchorTrait.has(t)&&(r=e+i)})),s.length>0&&super.setFocus((0,u.dM)([...super.getFocus(),...s])),n.length>0&&super.setSelection((0,u.dM)([...super.getSelection(),...n])),"number"===typeof r&&super.setAnchor(r)}setFocus(e,t,i=!1){super.setFocus(e,t),i||this.focusTrait.set(e.map((e=>this.element(e))),t)}setSelection(e,t,i=!1){super.setSelection(e,t),i||this.selectionTrait.set(e.map((e=>this.element(e))),t)}setAnchor(e,t=!1){super.setAnchor(e),t||("undefined"===typeof e?this.anchorTrait.set([]):this.anchorTrait.set([this.element(e)]))}}class q{get onDidScroll(){return this.view.onDidScroll}get onDidChangeFocus(){return this.eventBufferer.wrapEvent(this.focus.onDidChange)}get onDidChangeSelection(){return this.eventBufferer.wrapEvent(this.selection.onDidChange)}get onMouseDblClick(){return _.Jh.filter(_.Jh.map(this.view.onMouseDblClick,V),(e=>e.target!==d.Lx.Filter))}get onMouseOver(){return _.Jh.map(this.view.onMouseOver,V)}get onMouseOut(){return _.Jh.map(this.view.onMouseOut,V)}get onContextMenu(){return _.Jh.any(_.Jh.filter(_.Jh.map(this.view.onContextMenu,z),(e=>!e.isStickyScroll)),this.stickyScrollController?.onContextMenu??_.Jh.None)}get onPointer(){return _.Jh.map(this.view.onPointer,V)}get onKeyDown(){return this.view.onKeyDown}get onDidFocus(){return this.view.onDidFocus}get onDidChangeModel(){return _.Jh.signal(this.model.onDidSplice)}get onDidChangeCollapseState(){return this.model.onDidChangeCollapseState}get findMode(){return this.findController?.mode??I.Highlight}set findMode(e){this.findController&&(this.findController.mode=e)}get findMatchType(){return this.findController?.matchType??O.Fuzzy}set findMatchType(e){this.findController&&(this.findController.matchType=e)}get expandOnDoubleClick(){return"undefined"===typeof this._options.expandOnDoubleClick||this._options.expandOnDoubleClick}get expandOnlyOnTwistieClick(){return"undefined"===typeof this._options.expandOnlyOnTwistieClick||this._options.expandOnlyOnTwistieClick}get onDidDispose(){return this.view.onDidDispose}constructor(e,t,i,o,a={}){this._user=e,this._options=a,this.eventBufferer=new _.at,this.onDidChangeFindOpenState=_.Jh.None,this.onDidChangeStickyScrollFocused=_.Jh.None,this.disposables=new C.Cm,this._onWillRefilter=new _.vl,this.onWillRefilter=this._onWillRefilter.event,this._onDidUpdateOptions=new _.vl,this.treeDelegate=new x(i);const l=new _.Wj,h=new _.Wj,d=this.disposables.add(new k(h.event)),u=new f.db;this.renderers=o.map((e=>new A(e,(()=>this.model),l.event,d,u,a)));for(const s of this.renderers)this.disposables.add(s);let p;var m,v;a.keyboardNavigationLabelProvider&&(p=new N(this,a.keyboardNavigationLabelProvider,a.filter),a={...a,filter:p},this.disposables.add(p)),this.focus=new j((()=>this.view.getFocusedElements()[0]),a.identityProvider),this.selection=new j((()=>this.view.getSelectedElements()[0]),a.identityProvider),this.anchor=new j((()=>this.view.getAnchorElement()),a.identityProvider),this.view=new Y(e,t,this.treeDelegate,this.renderers,this.focus,this.selection,this.anchor,{...(m=()=>this.model,v=a,v&&{...v,identityProvider:v.identityProvider&&{getId:e=>v.identityProvider.getId(e.element)},dnd:v.dnd&&new T(m,v.dnd),multipleSelectionController:v.multipleSelectionController&&{isSelectionSingleChangeEvent:e=>v.multipleSelectionController.isSelectionSingleChangeEvent({...e,element:e.element}),isSelectionRangeChangeEvent:e=>v.multipleSelectionController.isSelectionRangeChangeEvent({...e,element:e.element})},accessibilityProvider:v.accessibilityProvider&&{...v.accessibilityProvider,getSetSize(e){const t=m(),i=t.getNodeLocation(e),s=t.getParentNodeLocation(i);return t.getNode(s).visibleChildrenCount},getPosInSet:e=>e.visibleChildIndex+1,isChecked:v.accessibilityProvider&&v.accessibilityProvider.isChecked?e=>v.accessibilityProvider.isChecked(e.element):void 0,getRole:v.accessibilityProvider&&v.accessibilityProvider.getRole?e=>v.accessibilityProvider.getRole(e.element):()=>"treeitem",getAriaLabel:e=>v.accessibilityProvider.getAriaLabel(e.element),getWidgetAriaLabel:()=>v.accessibilityProvider.getWidgetAriaLabel(),getWidgetRole:v.accessibilityProvider&&v.accessibilityProvider.getWidgetRole?()=>v.accessibilityProvider.getWidgetRole():()=>"tree",getAriaLevel:v.accessibilityProvider&&v.accessibilityProvider.getAriaLevel?e=>v.accessibilityProvider.getAriaLevel(e.element):e=>e.depth,getActiveDescendantId:v.accessibilityProvider.getActiveDescendantId&&(e=>v.accessibilityProvider.getActiveDescendantId(e.element))},keyboardNavigationLabelProvider:v.keyboardNavigationLabelProvider&&{...v.keyboardNavigationLabelProvider,getKeyboardNavigationLabel:e=>v.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(e.element)}}),tree:this,stickyScrollProvider:()=>this.stickyScrollController}),this.model=this.createModel(e,this.view,a),l.input=this.model.onDidChangeCollapseState;const E=_.Jh.forEach(this.model.onDidSplice,(e=>{this.eventBufferer.bufferEvents((()=>{this.focus.onDidModelSplice(e),this.selection.onDidModelSplice(e)}))}),this.disposables);E((()=>null),null,this.disposables);const b=this.disposables.add(new _.vl),S=this.disposables.add(new g.ve(0));if(this.disposables.add(_.Jh.any(E,this.focus.onDidChange,this.selection.onDidChange)((()=>{S.trigger((()=>{const e=new Set;for(const t of this.focus.getNodes())e.add(t);for(const t of this.selection.getNodes())e.add(t);b.fire([...e.values()])}))}))),h.input=b.event,!1!==a.keyboardSupport){const e=_.Jh.chain(this.view.onKeyDown,(e=>e.filter((e=>!(0,c.B6)(e.target))).map((e=>new r.Z(e)))));_.Jh.chain(e,(e=>e.filter((e=>15===e.keyCode))))(this.onLeftArrow,this,this.disposables),_.Jh.chain(e,(e=>e.filter((e=>17===e.keyCode))))(this.onRightArrow,this,this.disposables),_.Jh.chain(e,(e=>e.filter((e=>10===e.keyCode))))(this.onSpace,this,this.disposables)}if((a.findWidgetEnabled??1)&&a.keyboardNavigationLabelProvider&&a.contextViewProvider){const e=this.options.findWidgetStyles?{styles:this.options.findWidgetStyles}:void 0;this.findController=new D(this,this.model,this.view,p,a.contextViewProvider,e),this.focusNavigationFilter=e=>this.findController.shouldAllowFocus(e),this.onDidChangeFindOpenState=this.findController.onDidChangeOpenState,this.disposables.add(this.findController),this.onDidChangeFindMode=this.findController.onDidChangeMode,this.onDidChangeFindMatchType=this.findController.onDidChangeMatchType}else this.onDidChangeFindMode=_.Jh.None,this.onDidChangeFindMatchType=_.Jh.None;a.enableStickyScroll&&(this.stickyScrollController=new H(this,this.model,this.view,this.renderers,this.treeDelegate,a),this.onDidChangeStickyScrollFocused=this.stickyScrollController.onDidChangeHasFocus),this.styleElement=(0,n.li)(this.view.getHTMLElement()),this.getHTMLElement().classList.toggle("always",this._options.renderIndentGuides===s.Always)}updateOptions(e={}){this._options={...this._options,...e};for(const t of this.renderers)t.updateOptions(e);this.view.updateOptions(this._options),this.findController?.updateOptions(e),this.updateStickyScroll(e),this._onDidUpdateOptions.fire(this._options),this.getHTMLElement().classList.toggle("always",this._options.renderIndentGuides===s.Always)}get options(){return this._options}updateStickyScroll(e){!this.stickyScrollController&&this._options.enableStickyScroll?(this.stickyScrollController=new H(this,this.model,this.view,this.renderers,this.treeDelegate,this._options),this.onDidChangeStickyScrollFocused=this.stickyScrollController.onDidChangeHasFocus):this.stickyScrollController&&!this._options.enableStickyScroll&&(this.onDidChangeStickyScrollFocused=_.Jh.None,this.stickyScrollController.dispose(),this.stickyScrollController=void 0),this.stickyScrollController?.updateOptions(e)}getHTMLElement(){return this.view.getHTMLElement()}get scrollTop(){return this.view.scrollTop}set scrollTop(e){this.view.scrollTop=e}get scrollHeight(){return this.view.scrollHeight}get renderHeight(){return this.view.renderHeight}get ariaLabel(){return this.view.ariaLabel}set ariaLabel(e){this.view.ariaLabel=e}domFocus(){this.stickyScrollController?.focusedLast()?this.stickyScrollController.domFocus():this.view.domFocus()}layout(e,t){this.view.layout(e,t),(0,b.Et)(t)&&this.findController?.layout(t)}style(e){const t=`.${this.view.domId}`,i=[];e.treeIndentGuidesStroke&&(i.push(`.monaco-list${t}:hover .monaco-tl-indent > .indent-guide, .monaco-list${t}.always .monaco-tl-indent > .indent-guide { border-color: ${e.treeInactiveIndentGuidesStroke}; }`),i.push(`.monaco-list${t} .monaco-tl-indent > .indent-guide.active { border-color: ${e.treeIndentGuidesStroke}; }`));const s=e.treeStickyScrollBackground??e.listBackground;s&&(i.push(`.monaco-list${t} .monaco-scrollable-element .monaco-tree-sticky-container { background-color: ${s}; }`),i.push(`.monaco-list${t} .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-row { background-color: ${s}; }`)),e.treeStickyScrollBorder&&i.push(`.monaco-list${t} .monaco-scrollable-element .monaco-tree-sticky-container { border-bottom: 1px solid ${e.treeStickyScrollBorder}; }`),e.treeStickyScrollShadow&&i.push(`.monaco-list${t} .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-container-shadow { box-shadow: ${e.treeStickyScrollShadow} 0 6px 6px -6px inset; height: 3px; }`),e.listFocusForeground&&(i.push(`.monaco-list${t}.sticky-scroll-focused .monaco-scrollable-element .monaco-tree-sticky-container:focus .monaco-list-row.focused { color: ${e.listFocusForeground}; }`),i.push(`.monaco-list${t}:not(.sticky-scroll-focused) .monaco-scrollable-element .monaco-tree-sticky-container .monaco-list-row.focused { color: inherit; }`));const r=(0,n.gI)(e.listFocusAndSelectionOutline,(0,n.gI)(e.listSelectionOutline,e.listFocusOutline??""));r&&(i.push(`.monaco-list${t}.sticky-scroll-focused .monaco-scrollable-element .monaco-tree-sticky-container:focus .monaco-list-row.focused.selected { outline: 1px solid ${r}; outline-offset: -1px;}`),i.push(`.monaco-list${t}:not(.sticky-scroll-focused) .monaco-scrollable-element .monaco-tree-sticky-container .monaco-list-row.focused.selected { outline: inherit;}`)),e.listFocusOutline&&(i.push(`.monaco-list${t}.sticky-scroll-focused .monaco-scrollable-element .monaco-tree-sticky-container:focus .monaco-list-row.focused { outline: 1px solid ${e.listFocusOutline}; outline-offset: -1px; }`),i.push(`.monaco-list${t}:not(.sticky-scroll-focused) .monaco-scrollable-element .monaco-tree-sticky-container .monaco-list-row.focused { outline: inherit; }`),i.push(`.monaco-workbench.context-menu-visible .monaco-list${t}.last-focused.sticky-scroll-focused .monaco-scrollable-element .monaco-tree-sticky-container .monaco-list-row.passive-focused { outline: 1px solid ${e.listFocusOutline}; outline-offset: -1px; }`),i.push(`.monaco-workbench.context-menu-visible .monaco-list${t}.last-focused.sticky-scroll-focused .monaco-list-rows .monaco-list-row.focused { outline: inherit; }`),i.push(`.monaco-workbench.context-menu-visible .monaco-list${t}.last-focused:not(.sticky-scroll-focused) .monaco-tree-sticky-container .monaco-list-rows .monaco-list-row.focused { outline: inherit; }`)),this.styleElement.textContent=i.join("\n"),this.view.style(e)}getParentElement(e){const t=this.model.getParentNodeLocation(e);return this.model.getNode(t).element}getFirstElementChild(e){return this.model.getFirstElementChild(e)}getNode(e){return this.model.getNode(e)}getNodeLocation(e){return this.model.getNodeLocation(e)}collapse(e,t=!1){return this.model.setCollapsed(e,!0,t)}expand(e,t=!1){return this.model.setCollapsed(e,!1,t)}toggleCollapsed(e,t=!1){return this.model.setCollapsed(e,void 0,t)}isCollapsible(e){return this.model.isCollapsible(e)}setCollapsible(e,t){return this.model.setCollapsible(e,t)}isCollapsed(e){return this.model.isCollapsed(e)}refilter(){this._onWillRefilter.fire(void 0),this.model.refilter()}setSelection(e,t){this.eventBufferer.bufferEvents((()=>{const i=e.map((e=>this.model.getNode(e)));this.selection.set(i,t);const s=e.map((e=>this.model.getListIndex(e))).filter((e=>e>-1));this.view.setSelection(s,t,!0)}))}getSelection(){return this.selection.get()}setFocus(e,t){this.eventBufferer.bufferEvents((()=>{const i=e.map((e=>this.model.getNode(e)));this.focus.set(i,t);const s=e.map((e=>this.model.getListIndex(e))).filter((e=>e>-1));this.view.setFocus(s,t,!0)}))}focusNext(e=1,t=!1,i,s=((0,n.kx)(i)&&i.altKey?void 0:this.focusNavigationFilter)){this.view.focusNext(e,t,i,s)}focusPrevious(e=1,t=!1,i,s=((0,n.kx)(i)&&i.altKey?void 0:this.focusNavigationFilter)){this.view.focusPrevious(e,t,i,s)}focusNextPage(e,t=((0,n.kx)(e)&&e.altKey?void 0:this.focusNavigationFilter)){return this.view.focusNextPage(e,t)}focusPreviousPage(e,t=((0,n.kx)(e)&&e.altKey?void 0:this.focusNavigationFilter)){return this.view.focusPreviousPage(e,t,(()=>this.stickyScrollController?.height??0))}focusLast(e,t=((0,n.kx)(e)&&e.altKey?void 0:this.focusNavigationFilter)){this.view.focusLast(e,t)}focusFirst(e,t=((0,n.kx)(e)&&e.altKey?void 0:this.focusNavigationFilter)){this.view.focusFirst(e,t)}getFocus(){return this.focus.get()}reveal(e,t){this.model.expandTo(e);const i=this.model.getListIndex(e);if(-1!==i)if(this.stickyScrollController){const s=this.stickyScrollController.nodePositionTopBelowWidget(this.getNode(e));this.view.reveal(i,t,s)}else this.view.reveal(i,t)}onLeftArrow(e){e.preventDefault(),e.stopPropagation();const t=this.view.getFocusedElements();if(0===t.length)return;const i=t[0],s=this.model.getNodeLocation(i);if(!this.model.setCollapsed(s,!0)){const e=this.model.getParentNodeLocation(s);if(!e)return;const t=this.model.getListIndex(e);this.view.reveal(t),this.view.setFocus([t])}}onRightArrow(e){e.preventDefault(),e.stopPropagation();const t=this.view.getFocusedElements();if(0===t.length)return;const i=t[0],s=this.model.getNodeLocation(i);if(!this.model.setCollapsed(s,!1)){if(!i.children.some((e=>e.visible)))return;const[e]=this.view.getFocus(),t=e+1;this.view.reveal(t),this.view.setFocus([t])}}onSpace(e){e.preventDefault(),e.stopPropagation();const t=this.view.getFocusedElements();if(0===t.length)return;const i=t[0],s=this.model.getNodeLocation(i),n=e.browserEvent.altKey;this.model.setCollapsed(s,void 0,n)}dispose(){(0,C.AS)(this.disposables),this.stickyScrollController?.dispose(),this.view.dispose()}}},19531:(e,t,i)=>{"use strict";i.d(t,{iE:()=>n,rW:()=>r});class s{constructor(e,t,i){this._colorZoneBrand=void 0,this.from=0|e,this.to=0|t,this.colorId=0|i}static compare(e,t){return e.colorId===t.colorId?e.from===t.from?e.to-t.to:e.from-t.from:e.colorId-t.colorId}}class n{constructor(e,t,i,s){this._overviewRulerZoneBrand=void 0,this.startLineNumber=e,this.endLineNumber=t,this.heightInLines=i,this.color=s,this._colorZone=null}static compare(e,t){return e.color===t.color?e.startLineNumber===t.startLineNumber?e.heightInLines===t.heightInLines?e.endLineNumber-t.endLineNumber:e.heightInLines-t.heightInLines:e.startLineNumber-t.startLineNumber:e.colori&&(g=i-p);const m=c.color;let f=this._color2Id[m];f||(f=++this._lastAssignedId,this._color2Id[m]=f,this._id2Color[f]=m);const _=new s(g-p,g+p,f);c.setColorZone(_),o.push(_)}return this._colorZonesInvalid=!1,o.sort(s.compare),o}}},19562:(e,t,i)=>{"use strict";i.d(t,{T:()=>g});var s=i(40579),n=i(94650),r=i(32956),o=i(19131);function a(e,t=!1){if(0===e.length)return null;if(1===e.length)return e[0];let i=e.length;for(;i>3;){const n=i>>1;for(let r=0;r=3?e[2]:null,t)}function c(e,t){return Math.abs(e.listHeight-t.listHeight)}function l(e,t){return e.listHeight===t.listHeight?s.Xw.create23(e,t,null,!1):e.listHeight>t.listHeight?function(e,t){let i=e=e.toMutable();const n=[];let r;for(;;){if(t.listHeight===i.listHeight){r=t;break}if(4!==i.kind)throw new Error("unexpected");n.push(i),i=i.makeLastElementMutable()}for(let o=n.length-1;o>=0;o--){const e=n[o];r?e.childrenLength>=3?r=s.Xw.create23(e.unappendChild(),r,null,!1):(e.appendChildOfSameHeight(r),r=void 0):e.handleChildrenChanged()}return r?s.Xw.create23(e,r,null,!1):e}(e,t):function(e,t){let i=e=e.toMutable();const n=[];for(;t.listHeight!==i.listHeight;){if(4!==i.kind)throw new Error("unexpected");n.push(i),i=i.makeFirstElementMutable()}let r=t;for(let o=n.length-1;o>=0;o--){const e=n[o];r?e.childrenLength>=3?r=s.Xw.create23(r,e.unprependChild(),null,!1):(e.prependChildOfSameHeight(r),r=void 0):e.handleChildrenChanged()}return r?s.Xw.create23(r,e,null,!1):e}(t,e)}class h{constructor(e){this.lastOffset=o.Vp,this.nextNodes=[e],this.offsets=[o.Vp],this.idxs=[]}readLongestNodeAt(e,t){if((0,o.zG)(e,this.lastOffset))throw new Error("Invalid offset");for(this.lastOffset=e;;){const i=u(this.nextNodes);if(!i)return;const s=u(this.offsets);if((0,o.zG)(e,s))return;if((0,o.zG)(s,e))if((0,o.QB)(s,i.length)<=e)this.nextNodeAfterCurrent();else{const e=d(i);-1!==e?(this.nextNodes.push(i.getChild(e)),this.offsets.push(s),this.idxs.push(e)):this.nextNodeAfterCurrent()}else{if(t(i))return this.nextNodeAfterCurrent(),i;{const e=d(i);if(-1===e)return void this.nextNodeAfterCurrent();this.nextNodes.push(i.getChild(e)),this.offsets.push(s),this.idxs.push(e)}}}}nextNodeAfterCurrent(){for(;;){const e=u(this.offsets),t=u(this.nextNodes);if(this.nextNodes.pop(),this.offsets.pop(),0===this.idxs.length)break;const i=u(this.nextNodes),s=d(i,this.idxs[this.idxs.length-1]);if(-1!==s){this.nextNodes.push(i.getChild(s)),this.offsets.push((0,o.QB)(e,t.length)),this.idxs[this.idxs.length-1]=s;break}this.idxs.pop()}}}function d(e,t=-1){for(;;){if(++t>=e.childrenLength)return-1;if(e.getChild(t))return t}}function u(e){return e.length>0?e[e.length-1]:void 0}function g(e,t,i,s){return new p(e,t,i,s).parseDocument()}class p{constructor(e,t,i,s){if(this.tokenizer=e,this.createImmutableLists=s,this._itemsConstructed=0,this._itemsFromCache=0,i&&s)throw new Error("Not supported");this.oldNodeReader=i?new h(i):void 0,this.positionMapper=new n.W(t)}parseDocument(){this._itemsConstructed=0,this._itemsFromCache=0;let e=this.parseList(r.gV.getEmpty(),0);return e||(e=s.Xw.getEmpty()),e}parseList(e,t){const i=[];for(;;){let s=this.tryReadChildFromCache(e);if(!s){const i=this.tokenizer.peek();if(!i||2===i.kind&&i.bracketIds.intersects(e))break;s=this.parseChild(e,t+1)}4===s.kind&&0===s.childrenLength||i.push(s)}const s=this.oldNodeReader?function(e){if(0===e.length)return null;if(1===e.length)return e[0];let t=0;function i(){if(t>=e.length)return null;const i=t,s=e[i].listHeight;for(t++;t=2?a(0===i&&t===e.length?e:e.slice(i,t),!1):e[i]}let s=i(),n=i();if(!n)return s;for(let r=i();r;r=i())c(s,n)<=c(n,r)?(s=l(s,n),n=r):n=l(n,r);return l(s,n)}(i):a(i,this.createImmutableLists);return s}tryReadChildFromCache(e){if(this.oldNodeReader){const t=this.positionMapper.getDistanceToNextChange(this.tokenizer.offset);if(null===t||!(0,o.Vh)(t)){const i=this.oldNodeReader.readLongestNodeAt(this.positionMapper.getOffsetBeforeChange(this.tokenizer.offset),(i=>{if(null!==t&&!(0,o.zG)(i.length,t))return!1;return i.canBeReused(e)}));if(i)return this._itemsFromCache++,this.tokenizer.skip(i.length),i}}}parseChild(e,t){this._itemsConstructed++;const i=this.tokenizer.read();switch(i.kind){case 2:return new s.Gc(i.bracketIds,i.length);case 0:return i.astNode;case 1:{if(t>300)return new s.yF(i.length);const n=e.merge(i.bracketIds),r=this.parseList(n,t+1),o=this.tokenizer.peek();return o&&2===o.kind&&(o.bracketId===i.bracketId||o.bracketIds.intersects(i.bracketIds))?(this.tokenizer.read(),s.Nn.create(i.astNode,r,o.astNode)):s.Nn.create(i.astNode,r,null)}default:throw new Error("unexpected")}}}},19856:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"hcl",extensions:[".tf",".tfvars",".hcl"],aliases:["Terraform","tf","HCL","hcl"],loader:()=>i.e(13638).then(i.bind(i,13638))})},20370:(e,t,i)=>{"use strict";i.d(t,{n:()=>o,s:()=>a});var s=i(8597),n=i(25689);const r=new RegExp(`(\\\\)?\\$\\((${n.L.iconNameExpression}(?:${n.L.iconModifierExpression})?)\\)`,"g");function o(e){const t=new Array;let i,s=0,n=0;for(;null!==(i=r.exec(e));){n=i.index||0,s{"use strict";i.d(t,{T:()=>f,i:()=>_});var s,n=i(68214),r=i(80789),o=i(64383),a=i(41234),c=i(5662),l=i(73157),h=i(10154),d=i(83941),u=i(58314),g=i(49099),p=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},m=function(e,t){return function(i,s){t(i,s,e)}};let f=class{static{s=this}static{this._ttpTokenizer=(0,r.H)("tokenizeToString",{createHTML:e=>e})}constructor(e,t,i){this._options=e,this._languageService=t,this._openerService=i,this._onDidRenderAsync=new a.vl,this.onDidRenderAsync=this._onDidRenderAsync.event}dispose(){this._onDidRenderAsync.dispose()}render(e,t,i){if(!e){return{element:document.createElement("span"),dispose:()=>{}}}const s=new c.Cm,r=s.add((0,n.Gc)(e,{...this._getRenderOptions(e,s),...t},i));return r.element.classList.add("rendered-markdown"),{element:r.element,dispose:()=>s.dispose()}}_getRenderOptions(e,t){return{codeBlockRenderer:async(e,t)=>{let i;e?i=this._languageService.getLanguageIdByLanguageName(e):this._options.editor&&(i=this._options.editor.getModel()?.getLanguageId()),i||(i=d.vH);const n=await(0,u.Yj)(this._languageService,t,i),r=document.createElement("span");if(r.innerHTML=s._ttpTokenizer?.createHTML(n)??n,this._options.editor){const e=this._options.editor.getOption(50);(0,l.M)(r,e)}else this._options.codeBlockFontFamily&&(r.style.fontFamily=this._options.codeBlockFontFamily);return void 0!==this._options.codeBlockFontSize&&(r.style.fontSize=this._options.codeBlockFontSize),r},asyncRenderCallback:()=>this._onDidRenderAsync.fire(),actionHandler:{callback:t=>_(this._openerService,t,e.isTrusted),disposables:t}}}};async function _(e,t,i){try{return await e.open(t,{fromUserGesture:!0,allowContributedOpeners:!0,allowCommands:v(i)})}catch(s){return(0,o.dz)(s),!1}}function v(e){return!0===e||!(!e||!Array.isArray(e.enabledCommands))&&e.enabledCommands}f=s=p([m(1,h.L),m(2,g.C)],f)},20761:(e,t,i)=>{"use strict";i.d(t,{_:()=>n});var s=i(5662);class n extends s.jG{constructor(){super(...arguments),this._isDisposed=!1}dispose(){super.dispose(),this._isDisposed=!0}assertNotDisposed(){if(this._isDisposed)throw new Error("TextModelPart is disposed!")}}},20788:(e,t,i)=>{"use strict";i.d(t,{$H:()=>r,Lh:()=>o,r3:()=>n});var s=i(62083);const n=new class{clone(){return this}equals(e){return this===e}};function r(e,t){return new s.$M([new s.ou(0,"",e)],t)}function o(e,t){const i=new Uint32Array(2);return i[0]=0,i[1]=(32768|e|2<<24)>>>0,new s.rY(i,null===t?n:t)}},20897:e=>{e.exports=function(){function e(e){const t=1e3*Number(e.$value),i=new Date(t),s=i.getFullYear();return s<=0&&i.setFullYear(s-1),isNaN(i.valueOf())?"Invalid datetime":i.toISOString().replace(/\.\d{3}Z$/,"Z")}return e.isScalar=!0,e}},20940:(e,t,i)=>{"use strict";i.d(t,{Yk:()=>C});var s=i(66782),n=i(90766),r=i(18447),o=i(74320),a=i(64383),c=i(83069),l=i(36677),h=i(93630),d=i(19131),u=i(19562),g=i(32956),p=i(51934);class m{constructor(e){this.lines=e,this.tokenization={getLineTokens:e=>this.lines[e-1]}}getLineCount(){return this.lines.length}getLineLength(e){return this.lines[e-1].getLineContent().length}}var f=i(75295),_=i(73401),v=i(29319);async function C(e,t,i,s,h=r.XO.None,d){const u=t instanceof c.y?function(e,t){const i=t.getWordAtPosition(e),s=t.getLineMaxColumn(e.lineNumber);return i?new l.Q(e.lineNumber,i.startColumn,e.lineNumber,s):l.Q.fromPositions(e,e.with(void 0,s))}(t,i):t,g=e.all(i),p=new o.db;for(const n of g)n.groupId&&p.add(n.groupId,n);function m(e){if(!e.yieldsToGroupIds)return[];const t=[];for(const i of e.yieldsToGroupIds||[]){const e=p.get(i);for(const i of e)t.push(i)}return t}const f=new Map,_=new Set;function v(e,t){if(t=[...t,e],_.has(e))return t;_.add(e);try{const i=m(e);for(const e of i){const i=v(e,t);if(i)return i}}finally{_.delete(e)}}function C(e){const r=f.get(e);if(r)return r;const o=v(e,[]);o&&(0,a.M_)(new Error(`Inline completions: cyclic yield-to dependency detected. Path: ${o.map((e=>e.toString?e.toString():""+e)).join(" -> ")}`));const l=new n.Zv;return f.set(e,l.p),(async()=>{if(!o){const t=m(e);for(const e of t){const t=await C(e);if(t&&t.items.length>0)return}}try{if(t instanceof c.y){return await e.provideInlineCompletions(i,t,s,h)}return await(e.provideInlineEdits?.(i,t,s,h))}catch(n){return void(0,a.M_)(n)}})().then((e=>l.complete(e)),(e=>l.error(e))),l.p}const y=await Promise.all(g.map((async e=>({provider:e,completions:await C(e)})))),w=new Map,R=[];for(const n of y){const e=n.completions;if(!e)continue;const t=new b(e,n.provider);R.push(t);for(const s of e.items){const e=S.from(s,t,u,i,d);w.set(e.hash(),e)}}return new E(Array.from(w.values()),new Set(w.keys()),R)}class E{constructor(e,t,i){this.completions=e,this.hashs=t,this.providerResults=i}has(e){return this.hashs.has(e.hash())}dispose(){for(const e of this.providerResults)e.removeRef()}}class b{constructor(e,t){this.inlineCompletions=e,this.provider=t,this.refCount=1}addRef(){this.refCount++}removeRef(){this.refCount--,0===this.refCount&&this.provider.freeInlineCompletions(this.inlineCompletions)}}class S{static from(e,t,i,n,r){let o,a,c=e.range?l.Q.lift(e.range):i;if("string"===typeof e.insertText){if(o=e.insertText,r&&e.completeBracketPairs){o=y(o,c.getStartPosition(),n,r);const t=o.length-e.insertText.length;0!==t&&(c=new l.Q(c.startLineNumber,c.startColumn,c.endLineNumber,c.endColumn+t))}a=void 0}else if("snippet"in e.insertText){const t=e.insertText.snippet.length;if(r&&e.completeBracketPairs){e.insertText.snippet=y(e.insertText.snippet,c.getStartPosition(),n,r);const i=e.insertText.snippet.length-t;0!==i&&(c=new l.Q(c.startLineNumber,c.startColumn,c.endLineNumber,c.endColumn+i))}const i=(new v.fr).parse(e.insertText.snippet);1===i.children.length&&i.children[0]instanceof v.EY?(o=i.children[0].value,a=void 0):(o=i.toString(),a={snippet:e.insertText.snippet,range:c})}else(0,s.xb)(e.insertText);return new S(o,e.command,c,o,a,e.additionalTextEdits||(0,_.zk)(),e,t)}constructor(e,t,i,s,n,r,o,a){this.filterText=e,this.command=t,this.range=i,this.insertText=s,this.snippetInfo=n,this.additionalTextEdits=r,this.sourceInlineCompletion=o,this.source=a,s=(e=e.replace(/\r\n|\r/g,"\n")).replace(/\r\n|\r/g,"\n")}withRange(e){return new S(this.filterText,this.command,e,this.insertText,this.snippetInfo,this.additionalTextEdits,this.sourceInlineCompletion,this.source)}hash(){return JSON.stringify({insertText:this.insertText,range:this.range.toString()})}toSingleTextEdit(){return new f.WR(this.range,this.insertText)}}function y(e,t,i,s){const n=i.getLineContent(t.lineNumber).substring(0,t.column-1)+e,r=i.tokenization.tokenizeLineWithEdit(t,n.length-(t.column-1),e),o=r?.sliceAndInflate(t.column-1,n.length,0);if(!o)return e;const a=function(e,t){const i=new g.Mg,s=new h.Z(i,(e=>t.getLanguageConfiguration(e))),n=new p.tk(new m([e]),s),r=(0,u.T)(n,[],void 0,!0);let o="";const a=e.getLineContent();return function e(t,i){if(2===t.kind)if(e(t.openingBracket,i),i=(0,d.QB)(i,t.openingBracket.length),t.child&&(e(t.child,i),i=(0,d.QB)(i,t.child.length)),t.closingBracket)e(t.closingBracket,i),i=(0,d.QB)(i,t.closingBracket.length);else{const e=s.getSingleLanguageBracketTokens(t.openingBracket.languageId).findClosingTokenText(t.openingBracket.bracketIds);o+=e}else if(3===t.kind);else if(0===t.kind||1===t.kind)o+=a.substring((0,d.sS)(i),(0,d.sS)((0,d.QB)(i,t.length)));else if(4===t.kind)for(const s of t.children)e(s,i),i=(0,d.QB)(i,s.length)}(r,d.Vp),o}(o,s);return a}},20961:(e,t,i)=>{"use strict";var s=i(10350),n=i(8597),r=i(31450),o=i(80301),a=i(4360),c=i(60002),l=i(78209),h=i(27195),d=i(84001),u=i(32848);i(10691);class g extends h.L{constructor(){super({id:"diffEditor.toggleCollapseUnchangedRegions",title:(0,l.aS)("toggleCollapseUnchangedRegions","Toggle Collapse Unchanged Regions"),icon:s.W.map,toggled:u.M$.has("config.diffEditor.hideUnchangedRegions.enabled"),precondition:u.M$.has("isInDiffEditor"),menu:{when:u.M$.has("isInDiffEditor"),id:h.D8.EditorTitle,order:22,group:"navigation"}})}run(e,...t){const i=e.get(d.pG),s=!i.getValue("diffEditor.hideUnchangedRegions.enabled");i.updateValue("diffEditor.hideUnchangedRegions.enabled",s)}}class p extends h.L{constructor(){super({id:"diffEditor.toggleShowMovedCodeBlocks",title:(0,l.aS)("toggleShowMovedCodeBlocks","Toggle Show Moved Code Blocks"),precondition:u.M$.has("isInDiffEditor")})}run(e,...t){const i=e.get(d.pG),s=!i.getValue("diffEditor.experimental.showMoves");i.updateValue("diffEditor.experimental.showMoves",s)}}class m extends h.L{constructor(){super({id:"diffEditor.toggleUseInlineViewWhenSpaceIsLimited",title:(0,l.aS)("toggleUseInlineViewWhenSpaceIsLimited","Toggle Use Inline View When Space Is Limited"),precondition:u.M$.has("isInDiffEditor")})}run(e,...t){const i=e.get(d.pG),s=!i.getValue("diffEditor.useInlineViewWhenSpaceIsLimited");i.updateValue("diffEditor.useInlineViewWhenSpaceIsLimited",s)}}const f=(0,l.aS)("diffEditor","Diff Editor");class _ extends r.qO{constructor(){super({id:"diffEditor.switchSide",title:(0,l.aS)("switchSide","Switch Side"),icon:s.W.arrowSwap,precondition:u.M$.has("isInDiffEditor"),f1:!0,category:f})}runEditorCommand(e,t,i){const s=R(e);if(s instanceof a.T){if(i&&i.dryRun)return{destinationSelection:s.mapToOtherSide().destinationSelection};s.switchSide()}}}class v extends r.qO{constructor(){super({id:"diffEditor.exitCompareMove",title:(0,l.aS)("exitCompareMove","Exit Compare Move"),icon:s.W.close,precondition:c.R.comparingMovedCode,f1:!1,category:f,keybinding:{weight:1e4,primary:9}})}runEditorCommand(e,t,...i){const s=R(e);s instanceof a.T&&s.exitCompareMove()}}class C extends r.qO{constructor(){super({id:"diffEditor.collapseAllUnchangedRegions",title:(0,l.aS)("collapseAllUnchangedRegions","Collapse All Unchanged Regions"),icon:s.W.fold,precondition:u.M$.has("isInDiffEditor"),f1:!0,category:f})}runEditorCommand(e,t,...i){const s=R(e);s instanceof a.T&&s.collapseAllUnchangedRegions()}}class E extends r.qO{constructor(){super({id:"diffEditor.showAllUnchangedRegions",title:(0,l.aS)("showAllUnchangedRegions","Show All Unchanged Regions"),icon:s.W.unfold,precondition:u.M$.has("isInDiffEditor"),f1:!0,category:f})}runEditorCommand(e,t,...i){const s=R(e);s instanceof a.T&&s.showAllUnchangedRegions()}}class b extends h.L{constructor(){super({id:"diffEditor.revert",title:(0,l.aS)("revert","Revert"),f1:!1,category:f})}run(e,t){const i=function(e,t,i){const s=e.get(o.T);return s.listDiffEditors().find((e=>{const s=e.getModifiedEditor(),n=e.getOriginalEditor();return s&&s.getModel()?.uri.toString()===i.toString()&&n&&n.getModel()?.uri.toString()===t.toString()}))||null}(e,t.originalUri,t.modifiedUri);i instanceof a.T&&i.revertRangeMappings(t.mapping.innerChanges??[])}}const S=(0,l.aS)("accessibleDiffViewer","Accessible Diff Viewer");class y extends h.L{static{this.id="editor.action.accessibleDiffViewer.next"}constructor(){super({id:y.id,title:(0,l.aS)("editor.action.accessibleDiffViewer.next","Go to Next Difference"),category:S,precondition:u.M$.has("isInDiffEditor"),keybinding:{primary:65,weight:100},f1:!0})}run(e){const t=R(e);t?.accessibleDiffViewerNext()}}class w extends h.L{static{this.id="editor.action.accessibleDiffViewer.prev"}constructor(){super({id:w.id,title:(0,l.aS)("editor.action.accessibleDiffViewer.prev","Go to Previous Difference"),category:S,precondition:u.M$.has("isInDiffEditor"),keybinding:{primary:1089,weight:100},f1:!0})}run(e){const t=R(e);t?.accessibleDiffViewerPrev()}}function R(e){const t=e.get(o.T).listDiffEditors(),i=(0,n.bq)();if(i)for(const s of t){if(L(s.getContainerDomNode(),i))return s}return null}function L(e,t){let i=t;for(;i;){if(i===e)return!0;i=i.parentElement}return!1}var T=i(50091);(0,h.ug)(g),(0,h.ug)(p),(0,h.ug)(m),h.ZG.appendMenuItem(h.D8.EditorTitle,{command:{id:(new m).desc.id,title:(0,l.kg)("useInlineViewWhenSpaceIsLimited","Use Inline View When Space Is Limited"),toggled:u.M$.has("config.diffEditor.useInlineViewWhenSpaceIsLimited"),precondition:u.M$.has("isInDiffEditor")},order:11,group:"1_diff",when:u.M$.and(c.R.diffEditorRenderSideBySideInlineBreakpointReached,u.M$.has("isInDiffEditor"))}),h.ZG.appendMenuItem(h.D8.EditorTitle,{command:{id:(new p).desc.id,title:(0,l.kg)("showMoves","Show Moved Code Blocks"),icon:s.W.move,toggled:u.f1.create("config.diffEditor.experimental.showMoves",!0),precondition:u.M$.has("isInDiffEditor")},order:10,group:"1_diff",when:u.M$.has("isInDiffEditor")}),(0,h.ug)(b);for(const x of[{icon:s.W.arrowRight,key:c.R.diffEditorInlineMode.toNegated()},{icon:s.W.discard,key:c.R.diffEditorInlineMode}])h.ZG.appendMenuItem(h.D8.DiffEditorHunkToolbar,{command:{id:(new b).desc.id,title:(0,l.kg)("revertHunk","Revert Block"),icon:x.icon},when:u.M$.and(c.R.diffEditorModifiedWritable,x.key),order:5,group:"primary"}),h.ZG.appendMenuItem(h.D8.DiffEditorSelectionToolbar,{command:{id:(new b).desc.id,title:(0,l.kg)("revertSelection","Revert Selection"),icon:x.icon},when:u.M$.and(c.R.diffEditorModifiedWritable,x.key),order:5,group:"primary"});(0,h.ug)(_),(0,h.ug)(v),(0,h.ug)(C),(0,h.ug)(E),h.ZG.appendMenuItem(h.D8.EditorTitle,{command:{id:y.id,title:(0,l.kg)("Open Accessible Diff Viewer","Open Accessible Diff Viewer"),precondition:u.M$.has("isInDiffEditor")},order:10,group:"2_diff",when:u.M$.and(c.R.accessibleDiffViewerVisible.negate(),u.M$.has("isInDiffEditor"))}),T.w.registerCommandAlias("editor.action.diffReview.next",y.id),(0,h.ug)(y),T.w.registerCommandAlias("editor.action.diffReview.prev",w.id),(0,h.ug)(w)},21152:(e,t,i)=>{e.exports=function(e){const t=i(94297),s=i(76319)(e);return function(e,i,n){let r="";const o=e.$value,a=o.length;return t.drawFullView(a,i)?(r+="("+t.getIndent(i,n),r+=s(o,i,n),r+=t.getIndent(i,n-1)+")"):t.drawCompactView(a,i)?(r+="(",r+=s(o,i,n),r+=")"):r+="()",r}}},21377:(e,t,i)=>{e.exports=i(64066)},21478:(e,t,i)=>{"use strict";i.d(t,{M:()=>H,z:()=>F});var s,n=i(8597),r=i(25890),o=i(90766),a=i(18447),c=i(64383),l=i(5662),h=i(74320),d=i(631),u=i(79400),g=i(37734),p=i(55190),m=i(87908),f=i(7085),_=i(36677),v=i(62083),C=i(16223),E=i(87289),b=i(32500),S=i(56942),y=i(18938),w=i(37927),R=i(3730),L=i(60952),T=i(50091),x=i(14718),k=i(63591),A=i(58591),N=i(66261),I=i(47612),O=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},D=function(e,t){return function(i,s){t(i,s,e)}};class M{constructor(){this._entries=new h.qK(50)}get(e){const t=M._key(e);return this._entries.get(t)}set(e,t){const i=M._key(e);this._entries.set(i,t)}static _key(e){return`${e.uri.toString()}/${e.getVersionId()}`}}const P=(0,k.u1)("IInlayHintsCache");(0,x.v)(P,M,1);class F{constructor(e,t){this.item=e,this.index=t}get part(){const e=this.item.hint.label;return"string"===typeof e?{label:e}:e[this.index]}}class U{constructor(e,t){this.part=e,this.hasTriggerModifier=t}}let H=class{static{s=this}static{this.ID="editor.contrib.InlayHints"}static{this._MAX_DECORATORS=1500}static{this._MAX_LABEL_LEN=43}static get(e){return e.getContribution(s.ID)??void 0}constructor(e,t,i,s,n,r,o){this._editor=e,this._languageFeaturesService=t,this._inlayHintsCache=s,this._commandService=n,this._notificationService=r,this._instaService=o,this._disposables=new l.Cm,this._sessionDisposables=new l.Cm,this._decorationsMetadata=new Map,this._ruleFactory=new g.Qn(this._editor),this._activeRenderMode=0,this._debounceInfo=i.for(t.inlayHintsProvider,"InlayHint",{min:25}),this._disposables.add(t.inlayHintsProvider.onDidChange((()=>this._update()))),this._disposables.add(e.onDidChangeModel((()=>this._update()))),this._disposables.add(e.onDidChangeModelLanguage((()=>this._update()))),this._disposables.add(e.onDidChangeConfiguration((e=>{e.hasChanged(142)&&this._update()}))),this._update()}dispose(){this._sessionDisposables.dispose(),this._removeAllDecorations(),this._disposables.dispose()}_update(){this._sessionDisposables.clear(),this._removeAllDecorations();const e=this._editor.getOption(142);if("off"===e.enabled)return;const t=this._editor.getModel();if(!t||!this._languageFeaturesService.inlayHintsProvider.has(t))return;if("on"===e.enabled)this._activeRenderMode=0;else{let t,i;"onUnlessPressed"===e.enabled?(t=0,i=1):(t=1,i=0),this._activeRenderMode=t,this._sessionDisposables.add(n.Di.getInstance().event((e=>{if(!this._editor.hasModel())return;const s=e.altKey&&e.ctrlKey&&!e.shiftKey&&!e.metaKey?i:t;if(s!==this._activeRenderMode){this._activeRenderMode=s;const e=this._editor.getModel(),t=this._copyInlayHintsWithCurrentAnchor(e);this._updateHintsDecorators([e.getFullModelRange()],t),h.schedule(0)}})))}const i=this._inlayHintsCache.get(t);let s;i&&this._updateHintsDecorators([t.getFullModelRange()],i),this._sessionDisposables.add((0,l.s)((()=>{t.isDisposed()||this._cacheHintsForFastRestore(t)})));const r=new Set,h=new o.uC((async()=>{const e=Date.now();s?.dispose(!0),s=new a.Qi;const i=t.onWillDispose((()=>s?.cancel()));try{const i=s.token,n=await R.P8.create(this._languageFeaturesService.inlayHintsProvider,t,this._getHintsRanges(),i);if(h.delay=this._debounceInfo.update(t,Date.now()-e),i.isCancellationRequested)return void n.dispose();for(const e of n.provider)"function"!==typeof e.onDidChangeInlayHints||r.has(e)||(r.add(e),this._sessionDisposables.add(e.onDidChangeInlayHints((()=>{h.isScheduled()||h.schedule()}))));this._sessionDisposables.add(n),this._updateHintsDecorators(n.ranges,n.items),this._cacheHintsForFastRestore(t)}catch(n){(0,c.dz)(n)}finally{s.dispose(),i.dispose()}}),this._debounceInfo.get(t));this._sessionDisposables.add(h),this._sessionDisposables.add((0,l.s)((()=>s?.dispose(!0)))),h.schedule(0),this._sessionDisposables.add(this._editor.onDidScrollChange((e=>{!e.scrollTopChanged&&h.isScheduled()||h.schedule()}))),this._sessionDisposables.add(this._editor.onDidChangeModelContent((e=>{s?.cancel();const t=Math.max(h.delay,1250);h.schedule(t)}))),this._sessionDisposables.add(this._installDblClickGesture((()=>h.schedule(0)))),this._sessionDisposables.add(this._installLinkGesture()),this._sessionDisposables.add(this._installContextMenu())}_installLinkGesture(){const e=new l.Cm,t=e.add(new w.gi(this._editor)),i=new l.Cm;return e.add(i),e.add(t.onMouseMoveOrRelevantKeyDown((e=>{const[t]=e,s=this._getInlayHintLabelPart(t),n=this._editor.getModel();if(!s||!n)return void i.clear();const r=new a.Qi;i.add((0,l.s)((()=>r.dispose(!0)))),s.item.resolve(r.token),this._activeInlayHintPart=s.part.command||s.part.location?new U(s,t.hasTriggerModifier):void 0;const o=n.validatePosition(s.item.hint.position).lineNumber,c=new _.Q(o,1,o,n.getLineMaxColumn(o)),h=this._getInlineHintsForRange(c);this._updateHintsDecorators([c],h),i.add((0,l.s)((()=>{this._activeInlayHintPart=void 0,this._updateHintsDecorators([c],h)})))}))),e.add(t.onCancel((()=>i.clear()))),e.add(t.onExecute((async e=>{const t=this._getInlayHintLabelPart(e);if(t){const i=t.part;i.location?this._instaService.invokeFunction(L.U,e,this._editor,i.location):v.uB.is(i.command)&&await this._invokeCommand(i.command,t.item)}}))),e}_getInlineHintsForRange(e){const t=new Set;for(const i of this._decorationsMetadata.values())e.containsRange(i.item.anchor.range)&&t.add(i.item);return Array.from(t)}_installDblClickGesture(e){return this._editor.onMouseUp((async t=>{if(2!==t.event.detail)return;const i=this._getInlayHintLabelPart(t);if(i&&(t.event.preventDefault(),await i.item.resolve(a.XO.None),(0,r.EI)(i.item.hint.textEdits))){const t=i.item.hint.textEdits.map((e=>f.k.replace(_.Q.lift(e.range),e.text)));this._editor.executeEdits("inlayHint.default",t),e()}}))}_installContextMenu(){return this._editor.onContextMenu((async e=>{if(!(0,n.sb)(e.event.target))return;const t=this._getInlayHintLabelPart(e);t&&await this._instaService.invokeFunction(L.h,this._editor,e.event.target,t)}))}_getInlayHintLabelPart(e){if(6!==e.target.type)return;const t=e.target.detail.injectedText?.options;return t instanceof E.Ho&&t?.attachedData instanceof F?t.attachedData:void 0}async _invokeCommand(e,t){try{await this._commandService.executeCommand(e.id,...e.arguments??[])}catch(i){this._notificationService.notify({severity:A.AI.Error,source:t.provider.displayName,message:i})}}_cacheHintsForFastRestore(e){const t=this._copyInlayHintsWithCurrentAnchor(e);this._inlayHintsCache.set(e,t)}_copyInlayHintsWithCurrentAnchor(e){const t=new Map;for(const[i,s]of this._decorationsMetadata){if(t.has(s.item))continue;const n=e.getDecorationRange(i);if(n){const e=new R.EP(n,s.item.anchor.direction),i=s.item.with({anchor:e});t.set(s.item,i)}}return Array.from(t.values())}_getHintsRanges(){const e=this._editor.getModel(),t=this._editor.getVisibleRangesPlusViewportAboveBelow(),i=[];for(const s of t.sort(_.Q.compareRangesUsingStarts)){const t=e.validateRange(new _.Q(s.startLineNumber-30,s.startColumn,s.endLineNumber+30,s.endColumn));0!==i.length&&_.Q.areIntersectingOrTouching(i[i.length-1],t)?i[i.length-1]=_.Q.plusRange(i[i.length-1],t):i.push(t)}return i}_updateHintsDecorators(e,t){const i=[],n=(e,t,s,n,r)=>{const o={content:s,inlineClassNameAffectsLetterSpacing:!0,inlineClassName:t.className,cursorStops:n,attachedData:r};i.push({item:e,classNameRef:t,decoration:{range:e.anchor.range,options:{description:"InlayHint",showIfCollapsed:e.anchor.range.isEmpty(),collapseOnReplaceEdit:!e.anchor.range.isEmpty(),stickiness:0,[e.anchor.direction]:0===this._activeRenderMode?o:void 0}}})},o=(e,t)=>{const i=this._ruleFactory.createClassNameRef({width:(a/3|0)+"px",display:"inline-block"});n(e,i,"\u200a",t?C.VW.Right:C.VW.None)},{fontSize:a,fontFamily:c,padding:l,isUniform:h}=this._getLayoutInfo(),d="--code-editorInlayHintsFontFamily";this._editor.getContainerDomNode().style.setProperty(d,c);let u={line:0,totalLen:0};for(const p of t){if(u.line!==p.anchor.range.startLineNumber&&(u={line:p.anchor.range.startLineNumber,totalLen:0}),u.totalLen>s._MAX_LABEL_LEN)continue;p.hint.paddingLeft&&o(p,!1);const e="string"===typeof p.hint.label?[{label:p.hint.label}]:p.hint.label;for(let t=0;t0&&(f=f.slice(0,-v)+"\u2026",_=!0),n(p,this._ruleFactory.createClassNameRef(g),B(f),c&&!p.hint.paddingRight?C.VW.Right:C.VW.None,new F(p,t)),_)break}if(p.hint.paddingRight&&o(p,!0),i.length>s._MAX_DECORATORS)break}const g=[];for(const[s,r]of this._decorationsMetadata){const t=this._editor.getModel()?.getDecorationRange(s);t&&e.some((e=>e.containsRange(t)))&&(g.push(s),r.classNameRef.dispose(),this._decorationsMetadata.delete(s))}const f=p.D.capture(this._editor);this._editor.changeDecorations((e=>{const t=e.deltaDecorations(g,i.map((e=>e.decoration)));for(let s=0;si)&&(n=i);const r=e.fontFamily||s;return{fontSize:n,fontFamily:r,padding:t,isUniform:!t&&r===s&&n===i}}_removeAllDecorations(){this._editor.removeDecorations(Array.from(this._decorationsMetadata.keys()));for(const e of this._decorationsMetadata.values())e.classNameRef.dispose();this._decorationsMetadata.clear()}};function B(e){return e.replace(/[ \t]/g,"\xa0")}H=s=O([D(1,S.ILanguageFeaturesService),D(2,b.ILanguageFeatureDebounceService),D(3,P),D(4,T.d),D(5,A.Ot),D(6,k._Y)],H),T.w.registerCommand("_executeInlayHintProvider",(async(e,...t)=>{const[i,s]=t;(0,d.j)(u.r.isUri(i)),(0,d.j)(_.Q.isIRange(s));const{inlayHintsProvider:n}=e.get(S.ILanguageFeaturesService),r=await e.get(y.ITextModelService).createModelReference(i);try{const e=await R.P8.create(n,r.object.textEditorModel,[_.Q.lift(s)],a.XO.None),t=e.items.map((e=>e.hint));return setTimeout((()=>e.dispose()),0),t}finally{r.dispose()}}))},21852:(e,t,i)=>{"use strict";i.d(t,{s:()=>g});var s=i(8597),n=i(37479),r=i(5662),o=i(10146),a=i(92719),c=i(42904),l=i(48196),h=i(631),d=i(37882);class u{constructor(e){this._element=e}get element(){return this._element}set textContent(e){this.disposed||e===this._textContent||(this._textContent=e,this._element.textContent=e)}set classNames(e){this.disposed||(0,o.aI)(e,this._classNames)||(this._classNames=e,this._element.classList.value="",this._element.classList.add(...e))}set empty(e){this.disposed||e===this._empty||(this._empty=e,this._element.style.marginLeft=e?"0":"")}dispose(){this.disposed=!0}}class g extends r.jG{constructor(e,t){super(),this.customHovers=new Map,this.creationOptions=t,this.domNode=this._register(new u(s.BC(e,s.$(".monaco-icon-label")))),this.labelContainer=s.BC(this.domNode.element,s.$(".monaco-icon-label-container")),this.nameContainer=s.BC(this.labelContainer,s.$("span.monaco-icon-name-container")),this.nameNode=t?.supportHighlights||t?.supportIcons?this._register(new m(this.nameContainer,!!t.supportIcons)):new p(this.nameContainer),this.hoverDelegate=t?.hoverDelegate??(0,c.nZ)("mouse")}get element(){return this.domNode.element}setLabel(e,t,i){const r=["monaco-icon-label"],o=["monaco-icon-label-container"];let a="";i&&(i.extraClasses&&r.push(...i.extraClasses),i.italic&&r.push("italic"),i.strikethrough&&r.push("strikethrough"),i.disabledCommand&&o.push("disabled"),i.title&&("string"===typeof i.title?a+=i.title:a+=e));const c=this.domNode.element.querySelector(".monaco-icon-label-iconpath");if(i?.iconPath){let e;c&&s.sb(c)?e=c:(e=s.$(".monaco-icon-label-iconpath"),this.domNode.element.prepend(e)),e.style.backgroundImage=s.Tf(i?.iconPath)}else c&&c.remove();if(this.domNode.classNames=r,this.domNode.element.setAttribute("aria-label",a),this.labelContainer.classList.value="",this.labelContainer.classList.add(...o),this.setupHover(i?.descriptionTitle?this.labelContainer:this.element,i?.title),this.nameNode.setLabel(e,i),t||this.descriptionNode){const e=this.getOrCreateDescriptionNode();e instanceof n._?(e.set(t||"",i?i.descriptionMatches:void 0,void 0,i?.labelEscapeNewLines),this.setupHover(e.element,i?.descriptionTitle)):(e.textContent=t&&i?.labelEscapeNewLines?n._.escapeNewLines(t,[]):t||"",this.setupHover(e.element,i?.descriptionTitle||""),e.empty=!t)}if(i?.suffix||this.suffixNode){this.getOrCreateSuffixNode().textContent=i?.suffix??""}}setupHover(e,t){const i=this.customHovers.get(e);if(i&&(i.dispose(),this.customHovers.delete(e)),t)if(this.hoverDelegate.showNativeHover){function s(e,t){(0,h.Kg)(t)?e.title=(0,d.pS)(t):t?.markdownNotSupportedFallback?e.title=t.markdownNotSupportedFallback:e.removeAttribute("title")}s(e,t)}else{const n=(0,l.i)().setupManagedHover(this.hoverDelegate,e,t);n&&this.customHovers.set(e,n)}else e.removeAttribute("title")}dispose(){super.dispose();for(const e of this.customHovers.values())e.dispose();this.customHovers.clear()}getOrCreateSuffixNode(){if(!this.suffixNode){const e=this._register(new u(s.Pl(this.nameContainer,s.$("span.monaco-icon-suffix-container"))));this.suffixNode=this._register(new u(s.BC(e.element,s.$("span.label-suffix"))))}return this.suffixNode}getOrCreateDescriptionNode(){if(!this.descriptionNode){const e=this._register(new u(s.BC(this.labelContainer,s.$("span.monaco-icon-description-container"))));this.creationOptions?.supportDescriptionHighlights?this.descriptionNode=this._register(new n._(s.BC(e.element,s.$("span.label-description")),{supportIcons:!!this.creationOptions.supportIcons})):this.descriptionNode=this._register(new u(s.BC(e.element,s.$("span.label-description"))))}return this.descriptionNode}}class p{constructor(e){this.container=e,this.label=void 0,this.singleLabel=void 0}setLabel(e,t){if(this.label!==e||!(0,o.aI)(this.options,t))if(this.label=e,this.options=t,"string"===typeof e)this.singleLabel||(this.container.innerText="",this.container.classList.remove("multiple"),this.singleLabel=s.BC(this.container,s.$("a.label-name",{id:t?.domId}))),this.singleLabel.textContent=e;else{this.container.innerText="",this.container.classList.add("multiple"),this.singleLabel=void 0;for(let i=0;i{const n={start:s,end:s+e.length},r=i.map((e=>a.Q.intersect(n,e))).filter((e=>!a.Q.isEmpty(e))).map((({start:e,end:t})=>({start:e-s,end:t-s})));return s=n.end+t.length,r}))}(e,i,t?.matches);for(let o=0;o{"use strict";i.d(t,{nA:()=>s,qQ:()=>c});class s{constructor(e,t,i){this.owner=e,this.debugNameSource=t,this.referenceFn=i}getDebugName(e){return function(e,t){const i=r.get(e);if(i)return i;const s=function(e,t){const i=r.get(e);if(i)return i;const s=t.owner?function(e){const t=a.get(e);if(t)return t;const i=function(e){const t=e.constructor;if(t)return t.name;return"Object"}(e);let s=o.get(i)??0;s++,o.set(i,s);const n=1===s?i:`${i}#${s}`;return a.set(e,n),n}(t.owner)+".":"";let n;const l=t.debugNameSource;if(void 0!==l){if("function"!==typeof l)return s+l;if(n=l(),void 0!==n)return s+n}const h=t.referenceFn;if(void 0!==h&&(n=c(h),void 0!==n))return s+n;if(void 0!==t.owner){const i=function(e,t){for(const i in e)if(e[i]===t)return i;return}(t.owner,e);if(void 0!==i)return s+i}return}(e,t);if(s){let t=n.get(s)??0;t++,n.set(s,t);const i=1===t?s:`${s}#${t}`;return r.set(e,i),i}return}(e,this)}}const n=new Map,r=new WeakMap;const o=new Map,a=new WeakMap;function c(e){const t=e.toString(),i=/\/\*\*\s*@description\s*([^*]*)\*\//.exec(t),s=i?i[1]:void 0;return s?.trim()}},22362:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"vb",extensions:[".vb"],aliases:["Visual Basic","vb"],loader:()=>i.e(59748).then(i.bind(i,59748))})},22890:(e,t,i)=>{"use strict";var s=i(31450),n=i(24520),r=i(51861),o=i(86723),a=i(10424);class c extends s.ks{constructor(){super({id:"editor.action.toggleHighContrast",label:r.E6.toggleHighContrast,alias:"Toggle High Contrast Theme",precondition:void 0}),this._originalThemeName=null}run(e,t){const i=e.get(n.L),s=i.getColorTheme();(0,o.Bb)(s.type)?(i.setTheme(this._originalThemeName||((0,o.HD)(s.type)?a.po:a.tj)),this._originalThemeName=null):(i.setTheme((0,o.HD)(s.type)?a.aQ:a.nr),this._originalThemeName=s.themeName)}}(0,s.Fl)(c)},23034:(e,t,i)=>{"use strict";i.d(t,{Ix:()=>u,bc:()=>h,nV:()=>d});var s=i(42904),n=i(35315),r=i(10350),o=i(78209);const a=o.kg("caseDescription","Match Case"),c=o.kg("wordsDescription","Match Whole Word"),l=o.kg("regexDescription","Use Regular Expression");class h extends n.l{constructor(e){super({icon:r.W.caseSensitive,title:a+e.appendTitle,isChecked:e.isChecked,hoverDelegate:e.hoverDelegate??(0,s.nZ)("element"),inputActiveOptionBorder:e.inputActiveOptionBorder,inputActiveOptionForeground:e.inputActiveOptionForeground,inputActiveOptionBackground:e.inputActiveOptionBackground})}}class d extends n.l{constructor(e){super({icon:r.W.wholeWord,title:c+e.appendTitle,isChecked:e.isChecked,hoverDelegate:e.hoverDelegate??(0,s.nZ)("element"),inputActiveOptionBorder:e.inputActiveOptionBorder,inputActiveOptionForeground:e.inputActiveOptionForeground,inputActiveOptionBackground:e.inputActiveOptionBackground})}}class u extends n.l{constructor(e){super({icon:r.W.regex,title:l+e.appendTitle,isChecked:e.isChecked,hoverDelegate:e.hoverDelegate??(0,s.nZ)("element"),inputActiveOptionBorder:e.inputActiveOptionBorder,inputActiveOptionForeground:e.inputActiveOptionForeground,inputActiveOptionBackground:e.inputActiveOptionBackground})}}},23157:(e,t,i)=>{e.exports=function(e){const t=i(94297),s=i(83823)(e);return function(e,i,n){let r="";const o=e.$value,a=o.length;return t.drawFullView(a,i)?(r+="("+t.getIndent(i,n),r+=s(o,i,n),r+=t.getIndent(i,n-1)+")"):t.drawCompactView(a,i)?(r+="(",r+=s(o,i,n-1),r+=")"):r+="()",r}}},23195:(e,t,i)=>{"use strict";i.d(t,{l:()=>n});var s=i(61850);const n="yql";(0,s.KV)({id:n,extensions:[],loader:()=>i.e(19507).then(i.bind(i,19507)).then((e=>({conf:e.conf,language:e.getLanguage()})))})},23304:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"azcli",extensions:[".azcli"],aliases:["Azure CLI","azcli"],loader:()=>i.e(73534).then(i.bind(i,73534))})},23452:(e,t,i)=>{"use strict";i.d(t,{_:()=>s});const s={ICodeEditor:"vs.editor.ICodeEditor",IDiffEditor:"vs.editor.IDiffEditor"}},23646:(e,t,i)=>{"use strict";i.d(t,{X:()=>le});var s,n=i(90766),r=i(64383),o=i(24939),a=i(5662),c=i(80301),l=i(83069),h=i(36677),d=i(84226),u=i(78209),g=i(50091),p=i(84001),m=i(32848),f=i(63591),_=i(59261),v=i(36584),C=i(58591),E=i(9711),b=i(79614),S=i(8597),y=i(35151),w=i(47661),R=i(41234),L=i(36456),T=i(89403),x=i(29163),k=i(87289),A=i(83941),N=i(18938),I=i(3828),O=i(37479),D=i(21852),M=i(26690),P=i(98031),F=i(67841),U=i(19070),H=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},B=function(e,t){return function(i,s){t(i,s,e)}};let W=class{constructor(e){this._resolverService=e}hasChildren(e){return e instanceof b.y4||e instanceof b.$L}getChildren(e){if(e instanceof b.y4)return e.groups;if(e instanceof b.$L)return e.resolve(this._resolverService).then((e=>e.children));throw new Error("bad tree")}};W=H([B(0,N.ITextModelService)],W);class V{getHeight(){return 23}getTemplateId(e){return e instanceof b.$L?K.id:q.id}}let z=class{constructor(e){this._keybindingService=e}getKeyboardNavigationLabel(e){if(e instanceof b.yc){const t=e.parent.getPreview(e)?.preview(e.range);if(t)return t.value}return(0,T.P8)(e.uri)}};z=H([B(0,P.b)],z);class G{getId(e){return e instanceof b.yc?e.id:e.uri}}let j=class extends a.jG{constructor(e,t){super(),this._labelService=t;const i=document.createElement("div");i.classList.add("reference-file"),this.file=this._register(new D.s(i,{supportHighlights:!0})),this.badge=new I.x(S.BC(i,S.$(".count")),{},U.m$),e.appendChild(i)}set(e,t){const i=(0,T.pD)(e.uri);this.file.setLabel(this._labelService.getUriBasenameLabel(e.uri),this._labelService.getUriLabel(i,{relative:!0}),{title:this._labelService.getUriLabel(e.uri),matches:t});const s=e.children.length;this.badge.setCount(s),s>1?this.badge.setTitleFormat((0,u.kg)("referencesCount","{0} references",s)):this.badge.setTitleFormat((0,u.kg)("referenceCount","{0} reference",s))}};j=H([B(1,F.L)],j);let K=class{static{s=this}static{this.id="FileReferencesRenderer"}constructor(e){this._instantiationService=e,this.templateId=s.id}renderTemplate(e){return this._instantiationService.createInstance(j,e)}renderElement(e,t,i){i.set(e.element,(0,M.WJ)(e.filterData))}disposeTemplate(e){e.dispose()}};K=s=H([B(0,f._Y)],K);class Y extends a.jG{constructor(e){super(),this.label=this._register(new O._(e))}set(e,t){const i=e.parent.getPreview(e)?.preview(e.range);if(i&&i.value){const{value:e,highlight:s}=i;t&&!M.ne.isDefault(t)?(this.label.element.classList.toggle("referenceMatch",!1),this.label.set(e,(0,M.WJ)(t))):(this.label.element.classList.toggle("referenceMatch",!0),this.label.set(e,[s]))}else this.label.set(`${(0,T.P8)(e.uri)}:${e.range.startLineNumber+1}:${e.range.startColumn+1}`)}}class q{constructor(){this.templateId=q.id}static{this.id="OneReferenceRenderer"}renderTemplate(e){return new Y(e)}renderElement(e,t,i){i.set(e.element,e.filterData)}disposeTemplate(e){e.dispose()}}class ${getWidgetAriaLabel(){return(0,u.kg)("treeAriaLabel","References")}getAriaLabel(e){return e.ariaMessage}}var Q=i(47612),X=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},Z=function(e,t){return function(i,s){t(i,s,e)}};class J{static{this.DecorationOptions=k.kI.register({description:"reference-decoration",stickiness:1,className:"reference-decoration"})}constructor(e,t){this._editor=e,this._model=t,this._decorations=new Map,this._decorationIgnoreSet=new Set,this._callOnDispose=new a.Cm,this._callOnModelChange=new a.Cm,this._callOnDispose.add(this._editor.onDidChangeModel((()=>this._onModelChanged()))),this._onModelChanged()}dispose(){this._callOnModelChange.dispose(),this._callOnDispose.dispose(),this.removeDecorations()}_onModelChanged(){this._callOnModelChange.clear();const e=this._editor.getModel();if(e)for(const t of this._model.references)if(t.uri.toString()===e.uri.toString())return void this._addDecorations(t.parent)}_addDecorations(e){if(!this._editor.hasModel())return;this._callOnModelChange.add(this._editor.getModel().onDidChangeDecorations((()=>this._onDecorationChanged())));const t=[],i=[];for(let s=0,n=e.children.length;s{const n=s.deltaDecorations([],t);for(let t=0;t{e.equals(9)&&(this._keybindingService.dispatchEvent(e,e.target),e.stopPropagation())}),!0)),this._tree=this._instantiationService.createInstance(te,"ReferencesWidget",this._treeContainer,new V,[this._instantiationService.createInstance(K),this._instantiationService.createInstance(q)],this._instantiationService.createInstance(W),t),this._splitView.addView({onDidChange:R.Jh.None,element:this._previewContainer,minimumSize:200,maximumSize:Number.MAX_VALUE,layout:e=>{this._preview.layout({height:this._dim.height,width:e})}},y.X.Distribute),this._splitView.addView({onDidChange:R.Jh.None,element:this._treeContainer,minimumSize:100,maximumSize:Number.MAX_VALUE,layout:e=>{this._treeContainer.style.height=`${this._dim.height}px`,this._treeContainer.style.width=`${e}px`,this._tree.layout(this._dim.height,e)}},y.X.Distribute),this._disposables.add(this._splitView.onDidSashChange((()=>{this._dim.width&&(this.layoutData.ratio=this._splitView.getViewSize(0)/this._dim.width)}),void 0));const i=(e,t)=>{e instanceof b.yc&&("show"===t&&this._revealReference(e,!1),this._onDidSelectReference.fire({element:e,kind:t,source:"tree"}))};this._disposables.add(this._tree.onDidOpen((e=>{e.sideBySide?i(e.element,"side"):e.editorOptions.pinned?i(e.element,"goto"):i(e.element,"show")}))),S.jD(this._treeContainer)}_onWidth(e){this._dim&&this._doLayoutBody(this._dim.height,e)}_doLayoutBody(e,t){super._doLayoutBody(e,t),this._dim=new S.fg(t,e),this.layoutData.heightInLines=this._viewZone?this._viewZone.heightInLines:this.layoutData.heightInLines,this._splitView.layout(t),this._splitView.resizeView(0,t*this.layoutData.ratio)}setSelection(e){return this._revealReference(e,!0).then((()=>{this._model&&(this._tree.setSelection([e]),this._tree.setFocus([e]))}))}setModel(e){return this._disposeOnNewModel.clear(),this._model=e,this._model?this._onNewModel():Promise.resolve()}_onNewModel(){return this._model?this._model.isEmpty?(this.setTitle(""),this._messageContainer.innerText=u.kg("noResults","No results"),S.WU(this._messageContainer),Promise.resolve(void 0)):(S.jD(this._messageContainer),this._decorationsManager=new J(this._preview,this._model),this._disposeOnNewModel.add(this._decorationsManager),this._disposeOnNewModel.add(this._model.onDidChangeReferenceRange((e=>this._tree.rerender(e)))),this._disposeOnNewModel.add(this._preview.onMouseDown((e=>{const{event:t,target:i}=e;if(2!==t.detail)return;const s=this._getFocusedReference();s&&this._onDidSelectReference.fire({element:{uri:s.uri,range:i.range},kind:t.ctrlKey||t.metaKey||t.altKey?"side":"open",source:"editor"})}))),this.container.classList.add("results-loaded"),S.WU(this._treeContainer),S.WU(this._previewContainer),this._splitView.layout(this._dim.width),this.focusOnReferenceTree(),this._tree.setInput(1===this._model.groups.length?this._model.groups[0]:this._model)):Promise.resolve(void 0)}_getFocusedReference(){const[e]=this._tree.getFocus();return e instanceof b.yc?e:e instanceof b.$L&&e.children.length>0?e.children[0]:void 0}async revealReference(e){await this._revealReference(e,!1),this._onDidSelectReference.fire({element:e,kind:"goto",source:"tree"})}async _revealReference(e,t){if(this._revealedReference===e)return;this._revealedReference=e,e.uri.scheme!==L.ny.inMemory?this.setTitle((0,T.Pi)(e.uri),this._uriLabel.getUriLabel((0,T.pD)(e.uri))):this.setTitle(u.kg("peekView.alternateTitle","References"));const i=this._textModelResolverService.createModelReference(e.uri);this._tree.getInput()===e.parent||(t&&this._tree.reveal(e.parent),await this._tree.expand(e.parent)),this._tree.reveal(e);const s=await i;if(!this._model)return void s.dispose();(0,a.AS)(this._previewModelReference);const n=s.object;if(n){const t=this._preview.getModel()===n.textEditorModel?0:1,i=h.Q.lift(e.range).collapseToStart();this._previewModelReference=s,this._preview.setModel(n.textEditorModel),this._preview.setSelection(i),this._preview.revealRangeInCenter(i,t)}else this._preview.setModel(this._previewNotAvailableMessage),s.dispose()}};ie=X([Z(3,Q.Gy),Z(4,N.ITextModelService),Z(5,f._Y),Z(6,d.zn),Z(7,F.L),Z(8,P.b)],ie);var se,ne=i(60002),re=i(28290),oe=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},ae=function(e,t){return function(i,s){t(i,s,e)}};const ce=new m.N1("referenceSearchVisible",!1,u.kg("referenceSearchVisible","Whether reference peek is visible, like 'Peek References' or 'Peek Definition'"));let le=class{static{se=this}static{this.ID="editor.contrib.referencesController"}static get(e){return e.getContribution(se.ID)}constructor(e,t,i,s,n,r,o,c){this._defaultTreeKeyboardSupport=e,this._editor=t,this._editorService=s,this._notificationService=n,this._instantiationService=r,this._storageService=o,this._configurationService=c,this._disposables=new a.Cm,this._requestIdPool=0,this._ignoreModelChangeEvent=!1,this._referenceSearchVisible=ce.bindTo(i)}dispose(){this._referenceSearchVisible.reset(),this._disposables.dispose(),this._widget?.dispose(),this._model?.dispose(),this._widget=void 0,this._model=void 0}toggleWidget(e,t,i){let s;if(this._widget&&(s=this._widget.position),this.closeWidget(),s&&e.containsPosition(s))return;this._peekMode=i,this._referenceSearchVisible.set(!0),this._disposables.add(this._editor.onDidChangeModelLanguage((()=>{this.closeWidget()}))),this._disposables.add(this._editor.onDidChangeModel((()=>{this._ignoreModelChangeEvent||this.closeWidget()})));const n="peekViewLayout",r=ee.fromJSON(this._storageService.get(n,0,"{}"));this._widget=this._instantiationService.createInstance(ie,this._editor,this._defaultTreeKeyboardSupport,r),this._widget.setTitle(u.kg("labelLoading","Loading...")),this._widget.show(e),this._disposables.add(this._widget.onDidClose((()=>{t.cancel(),this._widget?(this._storageService.store(n,JSON.stringify(this._widget.layoutData),0,1),this._widget.isClosing||this.closeWidget(),this._widget=void 0):this.closeWidget()}))),this._disposables.add(this._widget.onDidSelectReference((e=>{const{element:t,kind:s}=e;if(t)switch(s){case"open":"editor"===e.source&&this._configurationService.getValue("editor.stablePeek")||this.openReference(t,!1,!1);break;case"side":this.openReference(t,!0,!1);break;case"goto":i?this._gotoReference(t,!0):this.openReference(t,!1,!0)}})));const o=++this._requestIdPool;t.then((t=>{if(o===this._requestIdPool&&this._widget)return this._model?.dispose(),this._model=t,this._widget.setModel(this._model).then((()=>{if(this._widget&&this._model&&this._editor.hasModel()){this._model.isEmpty?this._widget.setMetaTitle(""):this._widget.setMetaTitle(u.kg("metaTitle.N","{0} ({1})",this._model.title,this._model.references.length));const t=this._editor.getModel().uri,i=new l.y(e.startLineNumber,e.startColumn),s=this._model.nearestReference(t,i);if(s)return this._widget.setSelection(s).then((()=>{this._widget&&"editor"===this._editor.getOption(87)&&this._widget.focusOnPreviewEditor()}))}}));t.dispose()}),(e=>{this._notificationService.error(e)}))}changeFocusBetweenPreviewAndReferences(){this._widget&&(this._widget.isPreviewEditorFocused()?this._widget.focusOnReferenceTree():this._widget.focusOnPreviewEditor())}async goToNextOrPreviousReference(e){if(!this._editor.hasModel()||!this._model||!this._widget)return;const t=this._widget.position;if(!t)return;const i=this._model.nearestReference(this._editor.getModel().uri,t);if(!i)return;const s=this._model.nextOrPreviousReference(i,e),n=this._editor.hasTextFocus(),r=this._widget.isPreviewEditorFocused();await this._widget.setSelection(s),await this._gotoReference(s,!1),n?this._editor.focus():this._widget&&r&&this._widget.focusOnPreviewEditor()}async revealReference(e){this._editor.hasModel()&&this._model&&this._widget&&await this._widget.revealReference(e)}closeWidget(e=!0){this._widget?.dispose(),this._model?.dispose(),this._referenceSearchVisible.reset(),this._disposables.clear(),this._widget=void 0,this._model=void 0,e&&this._editor.focus(),this._requestIdPool+=1}_gotoReference(e,t){this._widget?.hide(),this._ignoreModelChangeEvent=!0;const i=h.Q.lift(e.range).collapseToStart();return this._editorService.openCodeEditor({resource:e.uri,options:{selection:i,selectionSource:"code.jump",pinned:t}},this._editor).then((e=>{if(this._ignoreModelChangeEvent=!1,e&&this._widget)if(this._editor===e)this._widget.show(i),this._widget.focusOnReferenceTree();else{const t=se.get(e),s=this._model.clone();this.closeWidget(),e.focus(),t?.toggleWidget(i,(0,n.SS)((e=>Promise.resolve(s))),this._peekMode??!1)}else this.closeWidget()}),(e=>{this._ignoreModelChangeEvent=!1,(0,r.dz)(e)}))}openReference(e,t,i){t||this.closeWidget();const{uri:s,range:n}=e;this._editorService.openCodeEditor({resource:s,options:{selection:n,selectionSource:"code.jump",pinned:i}},this._editor,t)}};function he(e,t){const i=(0,d.RL)(e);if(!i)return;const s=le.get(i);s&&t(s)}le=se=oe([ae(2,m.fN),ae(3,c.T),ae(4,C.Ot),ae(5,f._Y),ae(6,E.CS),ae(7,p.pG)],le),_.f.registerCommandAndKeybindingRule({id:"togglePeekWidgetFocus",weight:100,primary:(0,o.m5)(2089,60),when:m.M$.or(ce,d.x2.inPeekEditor),handler(e){he(e,(e=>{e.changeFocusBetweenPreviewAndReferences()}))}}),_.f.registerCommandAndKeybindingRule({id:"goToNextReference",weight:90,primary:62,secondary:[70],when:m.M$.or(ce,d.x2.inPeekEditor),handler(e){he(e,(e=>{e.goToNextOrPreviousReference(!0)}))}}),_.f.registerCommandAndKeybindingRule({id:"goToPreviousReference",weight:90,primary:1086,secondary:[1094],when:m.M$.or(ce,d.x2.inPeekEditor),handler(e){he(e,(e=>{e.goToNextOrPreviousReference(!1)}))}}),g.w.registerCommandAlias("goToNextReferenceFromEmbeddedEditor","goToNextReference"),g.w.registerCommandAlias("goToPreviousReferenceFromEmbeddedEditor","goToPreviousReference"),g.w.registerCommandAlias("closeReferenceSearchEditor","closeReferenceSearch"),g.w.registerCommand("closeReferenceSearch",(e=>he(e,(e=>e.closeWidget())))),_.f.registerKeybindingRule({id:"closeReferenceSearch",weight:-1,primary:9,secondary:[1033],when:m.M$.and(d.x2.inPeekEditor,m.M$.not("config.editor.stablePeek"))}),_.f.registerKeybindingRule({id:"closeReferenceSearch",weight:250,primary:9,secondary:[1033],when:m.M$.and(ce,m.M$.not("config.editor.stablePeek"),m.M$.or(ne.R.editorTextFocus,re.J7.negate()))}),_.f.registerCommandAndKeybindingRule({id:"revealReference",weight:200,primary:3,mac:{primary:3,secondary:[2066]},when:m.M$.and(ce,v.YD,v.Nf.negate(),v.cH.negate()),handler(e){const t=e.get(v.PE),i=t.lastFocusedList?.getFocus();Array.isArray(i)&&i[0]instanceof b.yc&&he(e,(e=>e.revealReference(i[0])))}}),_.f.registerCommandAndKeybindingRule({id:"openReferenceToSide",weight:100,primary:2051,mac:{primary:259},when:m.M$.and(ce,v.YD,v.Nf.negate(),v.cH.negate()),handler(e){const t=e.get(v.PE),i=t.lastFocusedList?.getFocus();Array.isArray(i)&&i[0]instanceof b.yc&&he(e,(e=>e.openReference(i[0],!0,!0)))}}),g.w.registerCommand("openReference",(e=>{const t=e.get(v.PE),i=t.lastFocusedList?.getFocus();Array.isArray(i)&&i[0]instanceof b.yc&&he(e,(e=>e.openReference(i[0],!1,!0)))}))},23750:(e,t,i)=>{"use strict";i.r(t),i.d(t,{IModelService:()=>s});const s=(0,i(63591).u1)("modelService")},23812:(e,t,i)=>{"use strict";i.d(t,{k:()=>ai});var s=i(60712),n=i(59284),r=i(46819),o=i(85736),a=i(51301);const c="g-date-",l=(0,i(82435).withNaming)({n:c,e:"__",m:"_"});function h({name:e,value:t,onReset:i,form:r,disabled:o,toStringValue:a}){const c=function({initialValue:e,onReset:t}){const[i,s]=n.useState(null),r=n.useRef(e);n.useEffect((()=>{if(!i||!t)return;const e=()=>{t(r.current)};return i.addEventListener("reset",e),()=>{i.removeEventListener("reset",e)}}),[i,t]);const o=n.useCallback((e=>{var t;s(null!==(t=null===e||void 0===e?void 0:e.form)&&void 0!==t?t:null)}),[]);return o}({initialValue:t,onReset:i});if(!e)return null;const l=a?a(t):`${null!==t&&void 0!==t?t:""}`;return(0,s.jsx)("input",{ref:c,type:"hidden",name:e,value:l,disabled:o,form:r})}const d=e=>n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),n.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M5.25 5.497a.75.75 0 0 1-.75-.75V4A1.5 1.5 0 0 0 3 5.5v1h10v-1A1.5 1.5 0 0 0 11.5 4v.75a.75.75 0 0 1-1.5 0V4H6v.747a.75.75 0 0 1-.75.75M10 2.5H6v-.752a.75.75 0 1 0-1.5 0V2.5a3 3 0 0 0-3 3v6a3 3 0 0 0 3 3h7a3 3 0 0 0 3-3v-6a3 3 0 0 0-3-3v-.75a.75.75 0 0 0-1.5 0zM3 8v3.5A1.5 1.5 0 0 0 4.5 13h7a1.5 1.5 0 0 0 1.5-1.5V8z",clipRule:"evenodd"}));var u=i(28664),g=i(84476),p=i(99991);function m(e){switch(e){case"xl":return"l";case"l":return"m";case"s":return"xs";default:return"s"}}var f=i(14750),_=i(72837);const v=JSON.parse('{"Last 5 minutes":"Last 5 minutes","Last 15 minutes":"Last 15 minutes","Last 30 minutes":"Last 30 minutes","Last hour":"Last hour","Last 3 hours":"Last 3 hours","Last 6 hours":"Last 6 hours","Last 12 hours":"Last 12 hours","Last day":"Last day","Last 3 days":"Last 3 days","Last week":"Last week","Last month":"Last month","Last 3 months":"Last 3 months","Last 6 months":"Last 6 months","Last year":"Last year","Last 3 years":"Last 3 years","Today":"Today","Yesterday":"Yesterday","Day before yesterday":"Day before yesterday","This week":"This week","This month":"This month","This year":"This year","From start of day":"From start of day","From start of week":"From start of week","From start of month":"From start of month","From start of year":"From start of year","Previous month":"Previous month","Last second":"Last second","Last minute":"Last minute","Last {count} second":["Last {{count}} second","Last {{count}} seconds","Last {{count}} seconds"],"Last {count} minute":["Last {{count}} minute","Last {{count}} minutes","Last {{count}} minutes"],"Last {count} hour":["Last {{count}} hour","Last {{count}} hours","Last {{count}} hours"],"Last {count} day":["Last {{count}} day","Last {{count}} days","Last {{count}} days"],"Last {count} week":["Last {{count}} week","Last {{count}} weeks","Last {{count}} weeks"],"Last {count} month":["Last {{count}} month","Last {{count}} months","Last {{count}} months"],"Last {count} year":["Last {{count}} year","Last {{count}} years","Last {{count}} years"],"Main":"Main","Other":"Other","Range":"Range","From":"From","To":"To"}'),C=JSON.parse('{"Last 5 minutes":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 5 \u043c\u0438\u043d\u0443\u0442","Last 15 minutes":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 15 \u043c\u0438\u043d\u0443\u0442","Last 30 minutes":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 30 \u043c\u0438\u043d\u0443\u0442","Last hour":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0447\u0430\u0441","Last 3 hours":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 3 \u0447\u0430\u0441\u0430","Last 6 hours":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 6 \u0447\u0430\u0441\u043e\u0432","Last 12 hours":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 12 \u0447\u0430\u0441\u043e\u0432","Last day":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0434\u0435\u043d\u044c","Last 3 days":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 3 \u0434\u043d\u044f","Last week":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u043d\u0435\u0434\u0435\u043b\u044f","Last month":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043c\u0435\u0441\u044f\u0446","Last 3 months":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 3 \u043c\u0435\u0441\u044f\u0446\u0430","Last 6 months":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 6 \u043c\u0435\u0441\u044f\u0446\u0435\u0432","Last year":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0433\u043e\u0434","Last 3 years":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 3 \u0433\u043e\u0434\u0430","Today":"\u0421\u0435\u0433\u043e\u0434\u043d\u044f","Yesterday":"\u0412\u0447\u0435\u0440\u0430","Day before yesterday":"\u041f\u043e\u0437\u0430\u0432\u0447\u0435\u0440\u0430","This week":"\u042d\u0442\u0430 \u043d\u0435\u0434\u0435\u043b\u044f","This month":"\u042d\u0442\u043e\u0442 \u043c\u0435\u0441\u044f\u0446","This year":"\u042d\u0442\u043e\u0442 \u0433\u043e\u0434","From start of day":"\u0421 \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043d\u044f","From start of week":"\u0421 \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u0434\u0435\u043b\u0438","From start of month":"\u0421 \u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u0435\u0441\u044f\u0446\u0430","From start of year":"\u0421 \u043d\u0430\u0447\u0430\u043b\u0430 \u0433\u043e\u0434\u0430","Previous month":"\u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u043c\u0435\u0441\u044f\u0446","Last second":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0441\u0435\u043a\u0443\u043d\u0434\u0430","Last minute":"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u043c\u0438\u043d\u0443\u0442\u0430","Last {count} second":["\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f {{count}} \u0441\u0435\u043a\u0443\u043d\u0434\u0430","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u0441\u0435\u043a\u0443\u043d\u0434\u044b","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u0441\u0435\u043a\u0443\u043d\u0434"],"Last {count} minute":["\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f {{count}} \u043c\u0438\u043d\u0443\u0442\u0430","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u043c\u0438\u043d\u0443\u0442\u044b","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u043c\u0438\u043d\u0443\u0442"],"Last {count} hour":["\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 {{count}} \u0447\u0430\u0441","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u0447\u0430\u0441\u0430","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u0447\u0430\u0441\u043e\u0432"],"Last {count} day":["\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 {{count}} \u0434\u0435\u043d\u044c","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u0434\u043d\u044f","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u0434\u043d\u0435\u0439"],"Last {count} week":["\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f {{count}} \u043d\u0435\u0434\u0435\u043b\u044f","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u043d\u0435\u0434\u0435\u043b\u0438","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u043d\u0435\u0434\u0435\u043b\u044c"],"Last {count} month":["\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 {{count}} \u043c\u0435\u0441\u044f\u0446","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u043c\u0435\u0441\u044f\u0446\u0430","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u043c\u0435\u0441\u044f\u0446\u0435\u0432"],"Last {count} year":["\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 {{count}} \u0433\u043e\u0434","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u0433\u043e\u0434\u0430","\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 {{count}} \u043b\u0435\u0442"],"Main":"\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435","Other":"\u0414\u0440\u0443\u0433\u0438\u0435","Range":"\u041f\u0435\u0440\u0438\u043e\u0434","From":"\u041e\u0442","To":"\u0414\u043e"}'),E=(0,_.N)({en:v,ru:C},`${c}relative-range-date-picker-presets`),b=[{from:"now-1d",to:"now",get title(){return E("Last day")}},{from:"now-3d",to:"now",get title(){return E("Last 3 days")}},{from:"now-1w",to:"now",get title(){return E("Last week")}},{from:"now-1M",to:"now",get title(){return E("Last month")}},{from:"now-3M",to:"now",get title(){return E("Last 3 months")}},{from:"now-6M",to:"now",get title(){return E("Last 6 months")}},{from:"now-1y",to:"now",get title(){return E("Last year")}},{from:"now-3y",to:"now",get title(){return E("Last 3 years")}}],S=[{from:"now-5m",to:"now",get title(){return E("Last 5 minutes")}},{from:"now-15m",to:"now",get title(){return E("Last 15 minutes")}},{from:"now-30m",to:"now",get title(){return E("Last 30 minutes")}},{from:"now-1h",to:"now",get title(){return E("Last hour")}},{from:"now-3h",to:"now",get title(){return E("Last 3 hours")}},{from:"now-6h",to:"now",get title(){return E("Last 6 hours")}},{from:"now-12h",to:"now",get title(){return E("Last 12 hours")}}],y=[{from:"now/d",to:"now/d",get title(){return E("Today")}},{from:"now-1d/d",to:"now-1d/d",get title(){return E("Yesterday")}},{from:"now-2d/d",to:"now-2d/d",get title(){return E("Day before yesterday")}},{from:"now/w",to:"now/w",get title(){return E("This week")}},{from:"now/M",to:"now/M",get title(){return E("This month")}},{from:"now/y",to:"now/y",get title(){return E("This year")}},{from:"now/d",to:"now",get title(){return E("From start of day")}},{from:"now/w",to:"now",get title(){return E("From start of week")}},{from:"now/M",to:"now",get title(){return E("From start of month")}},{from:"now/y",to:"now",get title(){return E("From start of year")}}],w=S.concat(b,y),R=/^now-(\d+)([smhdwMy])$/,L={s:"Last second",m:"Last minute",h:"Last hour",d:"Last day",w:"Last week",M:"Last month",y:"Last year"},T={s:"Last {count} second",m:"Last {count} minute",h:"Last {count} hour",d:"Last {count} day",w:"Last {count} week",M:"Last {count} month",y:"Last {count} year"};function x(e,t){return e.filter((e=>{const i=(0,f.bQ)(e.from),s=(0,f.bQ)(e.to,{roundUp:!0});return!(!i||!s)&&(!s.isBefore(i)&&(!t||!i.isBefore(t)))}))}function k(e){const t=e.toLowerCase();return"default"===t||"system"===t?t:function(e){return"default"===e||"system"===e?(0,f.KQ)({timeZone:e}).timeZone():e}(e)}function A(e){return`UTC ${(0,f.KQ)({timeZone:e}).format("Z")}`}function N({value:e,timeZone:t,alwaysShowAsAbsolute:i,format:s="L",presets:n}){var r,o,a,c,l,h;if(!e)return"";const d="default"===t?"":` (${A(t)})`;let u="";e.start&&(u="relative"!==e.start.type||i?null!==(o=null===(r=(0,f.bQ)(e.start.value,{timeZone:t}))||void 0===r?void 0:r.format(s))&&void 0!==o?o:"":e.start.value);let g="";if(e.end&&(g="relative"!==e.end.type||i?null!==(c=null===(a=(0,f.bQ)(e.end.value,{timeZone:t,roundUp:!0}))||void 0===a?void 0:a.format(s))&&void 0!==c?c:"":e.end.value),!i&&"relative"===(null===(l=e.start)||void 0===l?void 0:l.type)&&"relative"===(null===(h=e.end)||void 0===h?void 0:h.type))return`${function(e,t,i=w){const s=e.replace(/\s+/g,""),n=t.replace(/\s+/g,"");for(const r of i)if(r.from===s&&r.to===n)return r.title;if("now"===t){const e=R.exec(s);if(e){const[,t,i]=e;if(["s","m","h","d","w","M","y"].includes(i)){const e=1===Number(t)?L[i]:T[i];return E(e,{count:t})}}}return s+" \u2014 "+n}(e.start.value,e.end.value,n)}`;return`${u} \u2014 ${g}${d}`}const I=JSON.parse('{"Range date picker":"Range date picker"}'),O=JSON.parse('{"Range date picker":"\u0412\u044b\u0431\u043e\u0440 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0430 \u0434\u0430\u0442"}'),D=(0,_.N)({en:I,ru:O},`${c}relative-range-date-picker-control`),M=l("relative-range-date-picker-control"),P=n.forwardRef((({props:e,state:t,open:i,isMobile:r,onClick:o,onKeyDown:a,onFocus:c,onClickCalendar:l,onUpdate:h},f)=>{var _;const{alwaysShowAsAbsolute:v,presetTabs:C,getRangeTitle:E}=e,b=e.format||"L",S=n.useMemo((()=>"function"===typeof E?E(t.value,t.timeZone):N({value:t.value,timeZone:t.timeZone,alwaysShowAsAbsolute:v,format:b,presets:null===C||void 0===C?void 0:C.flatMap((({presets:e})=>e))})),[v,b,E,C,t.timeZone,t.value]),y=e.validationState||(t.isInvalid?"invalid":void 0),w=null!==(_=e.errorMessage)&&void 0!==_?_:t.errors.join("\n"),R={id:e.id,role:"combobox","aria-haspopup":"dialog","aria-expanded":i,"aria-label":e["aria-label"],"aria-labelledby":e["aria-labelledby"],"aria-describedby":e["aria-describedby"],"aria-details":e["aria-details"],disabled:e.disabled,readOnly:e.readOnly,onClick:l,onKeyDown:a};return e.renderControl?e.renderControl({ref:f,value:t.value,title:S,validationState:y,errorMessage:w,open:i,triggerProps:R}):(0,s.jsxs)(n.Fragment,{children:[(0,s.jsx)(u.k,{id:e.id,autoFocus:e.autoFocus,controlRef:f,value:S,placeholder:e.placeholder,onUpdate:h,controlProps:Object.assign(Object.assign({className:M("input",{mobile:r})},R),{disabled:r,onClick:o}),onKeyDown:a,onFocus:c,validationState:y,errorMessage:w,errorPlacement:e.errorPlacement,pin:e.pin,size:e.size,label:e.label,hasClear:e.hasClear,disabled:e.disabled,endContent:(0,s.jsx)(g.$,{view:"flat-secondary",size:m(e.size),disabled:e.disabled,extraProps:{"aria-haspopup":"dialog","aria-expanded":i,"aria-label":D("Range date picker")},onClick:l,children:(0,s.jsx)(p.I,{data:d})})}),r?(0,s.jsx)("button",{className:M("mobile-trigger",{"has-clear":Boolean(e.hasClear&&t.value),"has-errors":t.isInvalid&&"inside"===e.errorPlacement,size:e.size}),onClick:o}):null]})}));P.displayName="Control";var F=i(12640),U=i(39238);const H=e=>n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),n.createElement("g",{clipPath:"url(#a)"},n.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M4.312 4.29a.764.764 0 0 1 1.103-.62.75.75 0 1 0 .67-1.34 2.264 2.264 0 0 0-3.268 1.836L2.706 5.5H1.75a.75.75 0 0 0 0 1.5h.83l-.392 4.71a.764.764 0 0 1-1.103.62.75.75 0 0 0-.67 1.34 2.264 2.264 0 0 0 3.268-1.836L4.086 7H5.25a.75.75 0 1 0 0-1.5H4.21zm6.014 2.23a.75.75 0 0 0-1.152.96l.85 1.02-.85 1.02a.75.75 0 0 0 1.152.96L11 9.672l.674.808a.75.75 0 0 0 1.152-.96l-.85-1.02.85-1.02a.75.75 0 0 0-1.152-.96L11 7.328zM8.02 4.55a.75.75 0 0 1 .43.969l-.145.378a7.25 7.25 0 0 0 0 5.205l.145.378a.75.75 0 0 1-1.4.539l-.145-.378a8.75 8.75 0 0 1 0-6.282l.145-.378a.75.75 0 0 1 .97-.431m5.961 0a.75.75 0 0 1 .97.43l.145.379a8.75 8.75 0 0 1 0 6.282l-.146.378a.75.75 0 1 1-1.4-.538l.146-.379a7.25 7.25 0 0 0 0-5.205l-.146-.378a.75.75 0 0 1 .431-.97",clipRule:"evenodd"})),n.createElement("defs",null,n.createElement("clipPath",{id:"a"},n.createElement("path",{fill:"currentColor",d:"M0 0h16v16H0z"})))),B=e=>n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),n.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M13.5 8a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0M15 8A7 7 0 1 1 1 8a7 7 0 0 1 14 0M8.75 4.5a.75.75 0 0 0-1.5 0V8a.75.75 0 0 0 .3.6l2 1.5a.75.75 0 1 0 .9-1.2l-1.7-1.275z",clipRule:"evenodd"}));var W=i(32084),V=i(9187),z=i(38602),G=i(33705);function j({placeholderValue:e,timeZone:t}){return null!==e&&void 0!==e?e:(0,f.KQ)({timeZone:t}).set("hour",0).set("minute",0).set("second",0)}function K(e,t,i){return t&&e.isBefore(t)?t:i&&i.isBefore(e)?i:e}function Y(e,t){return e.set("hours",t.hour()).set("minutes",t.minute()).set("seconds",t.second())}function q(e,t,i){return(0,f.KQ)({input:e,timeZone:i}).format(t)}function $(e,t){const i=n.useRef(null),s=t.isCellFocused(e);n.useEffect((()=>{var e;s&&(null===(e=i.current)||void 0===e||e.focus({preventScroll:!0}))}),[s]);const r=t.focusedDate.isSame(e,t.mode)?0:-1,o=t.isCellDisabled(e),a=t.isSelected(e),c="highlightedRange"in t&&t.highlightedRange,l=Boolean(c&&a),h=a&&c&&e.isSame(c.start,t.mode),d=a&&c&&e.isSame(c.end,t.mode),u="days"===t.mode&&!t.focusedDate.isSame(e,"month"),g=t.isCellUnavailable(e),p=!o&&!g,m=t.isCurrent(e),f=t.isWeekend(e),_=function(e,t){switch(t.mode){case"days":return`${q(e,"dddd",t.timeZone)}, ${q(e,"LL",t.timeZone)}`;case"months":return`${q(e,"MMMM YYYY",t.timeZone)}`;case"quarters":return`${q(e,"[Q]Q YYYY",t.timeZone)}`;case"years":return`${q(e,"YYYY",t.timeZone)}`;default:return""}}(e,t),v={role:"gridcell","aria-selected":a?"true":void 0,"aria-disabled":o?"true":void 0},C={ref:i,role:"button",tabIndex:o?void 0:r,"aria-disabled":p?void 0:"true","aria-label":_,onClick:p?()=>{t.setFocusedDate(e),t.selectDate(e)}:void 0,onPointerEnter(){if("highlightDate"in t&&p)if(u){const i=e.isBefore(t.focusedDate)?t.focusedDate.startOf("month"):t.focusedDate.endOf("month").startOf("date");t.highlightDate(i)}else t.highlightDate(e)}};let E=q(e,"D",t.timeZone);return"months"===t.mode?E=q(e,"MMM",t.timeZone):"quarters"===t.mode?E=q(e,"[Q]Q",t.timeZone):"years"===t.mode&&(E=q(e,"YYYY",t.timeZone)),{cellProps:v,buttonProps:C,formattedDate:E,isDisabled:o,isSelected:a,isRangeSelection:l,isSelectionStart:h,isSelectionEnd:d,isOutsideCurrentRange:u,isUnavailable:g,isCurrent:m,isWeekend:f}}const Q=JSON.parse('{"Previous":"Previous","Next":"Next","Switch to months view":"Switch to months view","Switch to quarters view":"Switch to quarters view","Switch to years view":"Switch to years view"}'),X=JSON.parse('{"Previous":"\u041d\u0430\u0437\u0430\u0434","Next":"\u0412\u043f\u0435\u0440\u0451\u0434","Switch to months view":"\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u043f\u043e \u043c\u0435\u0441\u044f\u0446\u0430\u043c","Switch to quarters view":"\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u043f\u043e \u043a\u0432\u0430\u0440\u0442\u0430\u043b\u0430\u043c","Switch to years view":"\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u043f\u043e \u0433\u043e\u0434\u0430\u043c"}'),Z=(0,_.N)({en:Q,ru:X},`${c}calendar`),J="yc-button_disabled g-button_disabled";function ee(e,t){const i=t.indexOf(e)+1;if(i===t.length)return;return{days:"",months:Z("Switch to months view"),quarters:Z("Switch to quarters view"),years:Z("Switch to years view")}[t[i]]}const te=["days","months","quarters","years"],ie=l("calendar"),se=n.forwardRef((function(e,t){const{state:i}=e,{calendarProps:r,modeButtonProps:o,nextButtonProps:c,previousButtonProps:l}=function(e,t){const i="years"===t.mode||"quarters"===t.mode?`${t.startDate.year()} \u2014 ${t.endDate.year()}`:q(t.focusedDate,"days"===t.mode?"MMMM YYYY":"YYYY",t.timeZone),{focusWithinProps:s}=(0,a.R)({onFocusWithin:e.onFocus,onBlurWithin:e.onBlur}),r=Object.assign({role:"group",id:e.id,"aria-label":[e["aria-label"],i].filter(Boolean).join(", "),"aria-labelledby":e["aria-labelledby"]||void 0,"aria-describedby":e["aria-describedby"]||void 0,"aria-details":e["aria-details"]||void 0,"aria-disabled":t.disabled||void 0},s),o=t.availableModes.indexOf(t.mode),c=o+1===t.availableModes.length,l=o+2===t.availableModes.length,h=t.disabled||c,d={disabled:t.disabled,className:h?J:void 0,onClick:h?void 0:()=>{t.zoomOut(),l&&t.setFocused(!0)},extraProps:{"aria-disabled":h?"true":void 0,"aria-description":ee(t.mode,t.availableModes),"aria-live":"polite"},children:i},u=n.useRef(!1),g=t.disabled||t.isPreviousPageInvalid();n.useLayoutEffect((()=>{g&&u.current&&(u.current=!1,t.setFocused(!0))}));const p={disabled:t.disabled,className:g?J:void 0,onClick:g?void 0:()=>{t.focusPreviousPage()},onFocus:g?void 0:()=>{u.current=!0},onBlur:g?void 0:()=>{u.current=!1},extraProps:{"aria-label":Z("Previous"),"aria-disabled":g?"true":void 0}},m=n.useRef(!1),f=t.disabled||t.isNextPageInvalid();return n.useLayoutEffect((()=>{f&&m.current&&(m.current=!1,t.setFocused(!0))})),{calendarProps:r,modeButtonProps:d,nextButtonProps:{disabled:t.disabled,className:f?J:void 0,onClick:f?void 0:()=>{t.focusNextPage()},onFocus:f?void 0:()=>{m.current=!0},onBlur:f?void 0:()=>{m.current=!1},extraProps:{"aria-label":Z("Next"),"aria-disabled":g?"true":void 0}},previousButtonProps:p}}(e,i);return n.useImperativeHandle(t,(()=>({focus(){i.setFocused(!0)}}))),(0,s.jsxs)("div",Object.assign({},r,{className:ie({size:e.size}),children:[(0,s.jsxs)("div",{className:ie("header"),children:[(0,s.jsx)(g.$,Object.assign({},o,{view:"flat",size:e.size,children:i.availableModes.indexOf(i.mode)+1===i.availableModes.length?(0,s.jsx)("span",{className:ie("mode-label",ie("years-label")),children:o.children},"label"):[(0,s.jsx)("span",{className:ie("mode-label"),children:o.children},"label"),(0,s.jsx)(g.$.Icon,{children:(0,s.jsx)(G.I,{direction:"bottom"})},"icon")]})),(0,s.jsxs)("div",{className:ie("controls"),children:[(0,s.jsx)(g.$,Object.assign({},l,{view:"flat",size:e.size,children:(0,s.jsx)(g.$.Icon,{children:(0,s.jsx)(V.A,{className:ie("control-icon")})})})),(0,s.jsx)(g.$,Object.assign({},c,{view:"flat",size:e.size,children:(0,s.jsx)(g.$.Icon,{children:(0,s.jsx)(z.A,{className:ie("control-icon")})})}))]})]}),(0,s.jsx)(ne,{state:i})]}))}));function ne({state:e}){const[t,i]=n.useState((()=>Object.assign(Object.assign({},e),{isFocused:!1}))),r=e.mode!==t.mode,o=!e.startDate.isSame(t.startDate,"days");let c;r?c=te.indexOf(t.mode)>te.indexOf(e.mode)?"zoom-out":"zoom-in":o&&(c=e.startDate.isBefore(t.startDate)?"forward":"backward");const{gridProps:l}=function(e){const{focusWithinProps:t}=(0,a.R)({onFocusWithinChange:t=>{e.setFocused(t)}});return{gridProps:Object.assign(Object.assign({role:"grid","aria-label":"years"===e.mode||"quarters"===e.mode?`${e.startDate.year()} \u2014 ${e.endDate.year()}`:q(e.focusedDate,"days"===e.mode?"MMMM YYYY":"YYYY",e.timeZone),"aria-disabled":e.disabled?"true":void 0,"aria-readonly":e.readOnly?"true":void 0},t),{onKeyDown:t=>{"ArrowRight"===t.key?(t.preventDefault(),e.focusNextCell()):"ArrowLeft"===t.key?(t.preventDefault(),e.focusPreviousCell()):"ArrowDown"===t.key?(t.preventDefault(),e.focusNextRow()):"ArrowUp"===t.key?(t.preventDefault(),e.focusPreviousRow()):"PageDown"===t.key?(t.preventDefault(),e.focusNextPage(t.shiftKey)):"PageUp"===t.key?(t.preventDefault(),e.focusPreviousPage(t.shiftKey)):"End"===t.key?(t.preventDefault(),e.focusSectionEnd()):"Home"===t.key?(t.preventDefault(),e.focusSectionStart()):"Minus"===t.code?(t.preventDefault(),e.zoomOut()):"Equal"===t.code?(t.preventDefault(),e.zoomIn()):"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),e.selectDate(e.focusedDate))}})}}(e);return(0,s.jsxs)("div",Object.assign({className:ie("grid")},l,{children:[c&&(0,s.jsx)(re,{className:ie("previous-state"),state:t,animation:c}),(0,s.jsx)(re,{className:ie("current-state"),state:e,animation:c,onAnimationEnd:()=>{i(Object.assign(Object.assign({},e),{isFocused:!1}))}},"current")]}))}function re({className:e,state:t,animation:i,onAnimationEnd:n}){return(0,s.jsxs)("div",{className:ie("content",{animation:i},e),onAnimationEnd:n,role:"presentation",children:["days"===t.mode&&(0,s.jsx)(oe,{state:t}),(0,s.jsx)(ae,{state:t})]})}function oe({state:e}){const t=function(e){const t=[],i=(0,f.KQ)({timeZone:e.timeZone}).startOf("week");for(let s=0;s<7;s++){const e=i.add({days:s});t.push(e)}return t}(e);return(0,s.jsx)("div",{className:ie("grid-row"),role:"row",children:t.map((t=>(0,s.jsx)("div",{className:ie("weekday",{weekend:e.isWeekend(t)}),role:"columnheader","aria-label":q(t,"dddd",e.timeZone),children:q(t,"dd",e.timeZone)},t.day())))})}function ae({state:e}){const t="days"===e.mode?6:4,i="days"===e.mode?7:3+("quarters"===e.mode?1:0),n=function(e){const t=[],i=(0,f.KQ)({input:e.startDate,timeZone:e.timeZone});if("days"===e.mode){const e=i.startOf("week");for(let i=0;i<42;i++)t.push(e.add({days:i}))}else if("quarters"===e.mode)for(let s=0;s<16;s++)t.push(i.add(s,"quarters"));else for(let s=0;s<12;s++)t.push(i.add({[e.mode]:s}));return t}(e);return(0,s.jsx)("div",{className:ie("grid-rowgroup",{mode:e.mode}),role:"rowgroup",children:[...new Array(t).keys()].map((t=>(0,s.jsxs)("div",{className:ie("grid-row"),role:"row",children:["quarters"===e.mode?(0,s.jsx)("span",{role:"rowheader",className:ie("grid-rowgroup-header"),children:q(n[t*i],"YYYY",e.timeZone)}):null,n.slice(t*i,(t+1)*i).map((t=>(0,s.jsx)(ce,{date:t,state:e},t.unix())))]},t)))})}function ce({date:e,state:t}){const{cellProps:i,buttonProps:n,formattedDate:r,isDisabled:o,isSelected:a,isRangeSelection:c,isSelectionStart:l,isSelectionEnd:h,isOutsideCurrentRange:d,isUnavailable:u,isCurrent:g,isWeekend:p}=$(e,t);return(0,s.jsx)("div",Object.assign({},i,{children:(0,s.jsx)("div",Object.assign({},n,{className:ie("button",{disabled:o,selected:a,"range-selection":c,"selection-start":l,"selection-end":h,"out-of-boundary":d,unavailable:u,current:g,weekend:p}),children:r}))}))}function le(e){const t=e?e.timeZone():"default",[i,s]=n.useState(t);e&&t!==i&&s(t);return e?t:i}const he={days:!0,months:!0,quarters:!1,years:!0};function de(e,t){if("days"===t)return e.startOf("month");if("months"===t)return e.startOf("year");if("quarters"===t){const t=4*Math.floor(e.year()/4);return e.startOf("year").set("year",t)}const i=12*Math.floor(e.year()/12);return e.startOf("year").set("year",i)}function ue(e,t){if("days"===t)return e.endOf("month").startOf("day");if("months"===t)return e.endOf("year").startOf("month");const i=de(e,t);return"quarters"===t?i.add(15,"quarters"):i.add({[t]:11})}function ge(e,t,i,s="days"){return!K(e,t,i).isSame(e,s)}const pe=n.forwardRef((function(e,t){const i=function(e){var t,i,s;const{disabled:r,readOnly:a,modes:c=he}=e,[l,h]=(0,o.P)(e.value,null!==(t=e.defaultValue)&&void 0!==t?t:null,e.onUpdate),d=te.filter((e=>c[e])),u=d[0]||"days",[g,p]=(0,o.P)(e.mode,null!==(i=e.defaultMode)&&void 0!==i?i:u,e.onUpdateMode),m=g&&d.includes(g)?g:u,_=le(e.value||e.defaultValue||e.focusedValue||e.defaultFocusedValue),v=e.timeZone||_,C=n.useMemo((()=>e.minValue?e.minValue.timeZone(v):void 0),[v,e.minValue]),E=n.useMemo((()=>e.maxValue?e.maxValue.timeZone(v):void 0),[v,e.maxValue]),b=n.useMemo((()=>e.focusedValue?K(e.focusedValue.timeZone(v),C,E):e.focusedValue),[e.focusedValue,C,E,v]),S=n.useMemo((()=>{var t;return K((null===(t=e.defaultFocusedValue?e.defaultFocusedValue:l)||void 0===t?void 0:t.timeZone(v))||j({timeZone:v}).startOf(u),C,E)}),[E,C,e.defaultFocusedValue,v,l,u]),[y,w]=(0,o.P)(b,S,(t=>{var i;null===(i=e.onFocusUpdate)||void 0===i||i.call(e,t.timeZone(_))})),R=null!==(s=null===y||void 0===y?void 0:y.timeZone(v))&&void 0!==s?s:K(j({timeZone:v}),C,E);function L(e){w(K(e.startOf(m),C,E))}ge(R,C,E)&&w(K(R,C,E));const[T,x]=n.useState(e.autoFocus||!1),k=de(R,m),A=ue(R,m);return{disabled:r,readOnly:a,value:l,setValue(e){if(!r&&!a){let t=K(e,C,E);if(this.isCellUnavailable(t))return;l&&(t=Y(t,l.timeZone(v))),h(t.timeZone(_))}},timeZone:v,selectDate(e,t=!1){r||(a||!t&&this.mode!==u?this.zoomIn():(this.setValue(e.startOf(u)),t&&m!==u&&p(u)))},minValue:C,maxValue:E,focusedDate:R,startDate:k,endDate:A,setFocusedDate(e){L(e),x(!0)},focusNextCell(){L(R.add(1,this.mode))},focusPreviousCell(){L(R.subtract(1,this.mode))},focusNextRow(){"days"===this.mode?L(R.add(1,"week")):"quarters"===this.mode?L(R.add(1,"years")):L(R.add(3,this.mode))},focusPreviousRow(){"days"===this.mode?L(R.subtract(1,"week")):"quarters"===this.mode?L(R.subtract(1,"years")):L(R.subtract(3,this.mode))},focusNextPage(e){"days"===this.mode?L(R.add({months:e?12:1})):"quarters"===this.mode?L(R.add(4,"years")):L(R.add(12,this.mode))},focusPreviousPage(e){"days"===this.mode?L(R.subtract({months:e?12:1})):"quarters"===this.mode?L(R.subtract(4,"years")):L(R.subtract(12,this.mode))},focusSectionStart(){L(de(R,this.mode))},focusSectionEnd(){L(ue(R,this.mode))},zoomIn(){const e=d[d.indexOf(this.mode)-1];e&&this.setMode(e)},zoomOut(){const e=d[d.indexOf(this.mode)+1];e&&this.setMode(e)},selectFocusedDate(){this.selectDate(R,!0)},isFocused:T,setFocused:x,isInvalid(e){return ge(e,this.minValue,this.maxValue,this.mode)},isPreviousPageInvalid(){const e=this.startDate.subtract(1,"day");return this.isInvalid(e)},isNextPageInvalid(){const e=this.endDate.endOf(this.mode).add(1,"day");return this.isInvalid(e)},isSelected(e){return Boolean(l&&e.isSame(l.timeZone(v),m)&&!this.isCellDisabled(e))},isCellUnavailable(t){return this.mode===u&&Boolean(e.isDateUnavailable&&e.isDateUnavailable(t))},isCellFocused(e){return this.isFocused&&R&&e.isSame(R,m)},isCellDisabled(e){return this.disabled||this.isInvalid(e)},isWeekend(t){return"days"===this.mode&&("function"===typeof e.isWeekend?e.isWeekend(t):function(e){return[0,6].includes(e.day())}(t))},isCurrent(e){return(0,f.KQ)({timeZone:v}).isSame(e,this.mode)},mode:m,setMode:p,availableModes:d}}(e);return(0,s.jsx)(se,Object.assign({ref:t},e,{state:i}))}));var me=i(27145);const fe=JSON.parse('{"year_placeholder":"Y","month_placeholder":"M","weekday_placeholder":"E","day_placeholder":"D","hour_placeholder":"h","minute_placeholder":"m","second_placeholder":"s","dayPeriod_placeholder":"aa"}'),_e=JSON.parse('{"year_placeholder":"\u0413","month_placeholder":"\u041c","weekday_placeholder":"\u0414\u041d","day_placeholder":"\u0414","hour_placeholder":"\u0447","minute_placeholder":"\u043c","second_placeholder":"\u0441","dayPeriod_placeholder":"(\u0434|\u043f)\u043f"}'),ve=(0,_.N)({en:fe,ru:_e},`${c}date-field`),Ce={year:!0,month:!0,day:!0,hour:!0,minute:!0,second:!0,dayPeriod:!0,weekday:!0},Ee={start:"[",end:"]"},be={YY:"year",YYYY:"year",M:"month",MM:"month",MMM:{sectionType:"month",contentType:"letter"},MMMM:{sectionType:"month",contentType:"letter"},D:"day",DD:"day",Do:"day",d:"weekday",dd:{sectionType:"weekday",contentType:"letter"},ddd:{sectionType:"weekday",contentType:"letter"},dddd:{sectionType:"weekday",contentType:"letter"},A:{sectionType:"dayPeriod",contentType:"letter"},a:{sectionType:"dayPeriod",contentType:"letter"},H:"hour",HH:"hour",h:"hour",hh:"hour",m:"minute",mm:"minute",s:"second",ss:"second",z:{sectionType:"timeZoneName",contentType:"letter"},zzz:{sectionType:"timeZoneName",contentType:"letter"},Z:{sectionType:"timeZoneName",contentType:"letter"},ZZ:{sectionType:"timeZoneName",contentType:"letter"}};function Se(e){return 4===(0,f.KQ)().format(e).length}function ye(e,t){const{type:i,format:s}=e;switch(i){case"year":{const e=Se(s);return{minValue:e?1:0,maxValue:e?9999:99}}case"month":return{minValue:0,maxValue:11};case"weekday":return{minValue:0,maxValue:6};case"day":return{minValue:1,maxValue:t?t.daysInMonth():31};case"hour":if(function(e){return"15"!==(0,f.KQ)().set("hour",15).format(e)}(s)){const e=t.hour()>=12;return{minValue:e?12:0,maxValue:e?23:11}}return{minValue:0,maxValue:23};case"minute":case"second":return{minValue:0,maxValue:59}}return{}}function we(e,t){const i=e.type;switch(i){case"year":return Se(e.format)?t.year():Number(t.format(e.format));case"month":case"hour":case"minute":case"second":return t[i]();case"day":return t.date();case"weekday":return t.day();case"dayPeriod":return t.hour()>=12?12:0}}const Re={weekday:"day",day:"date",dayPeriod:"hour"};function Le(e){if("literal"===e||"timeZoneName"===e||"unknown"===e)throw new Error(`${e} section does not have duration unit.`);return e in Re?Re[e]:e}function Te(e,t){switch(e.type){case"year":return ve("year_placeholder").repeat((0,f.KQ)().format(t).length);case"month":return ve("month_placeholder").repeat("letter"===e.contentType?4:2);case"day":return ve("day_placeholder").repeat(2);case"weekday":return ve("weekday_placeholder").repeat("letter"===e.contentType?4:2);case"hour":return ve("hour_placeholder").repeat(2);case"minute":return ve("minute_placeholder").repeat(2);case"second":return ve("second_placeholder").repeat(2);case"dayPeriod":return ve("dayPeriod_placeholder");default:return t}}function xe(e){const t=[],i=(0,f.cS)(e);let s="",n=!1,r=!1;for(let o=0;o1;case"day":return(0,f.KQ)().startOf("month").format(i).length>1;case"weekday":return(0,f.KQ)().startOf("week").format(i).length>1;case"hour":return(0,f.KQ)().set("hour",1).format(i).length>1;case"minute":return(0,f.KQ)().set("minute",1).format(i).length>1;case"second":return(0,f.KQ)().set("second",1).format(i).length>1;default:throw new Error("Invalid section type")}}(i.contentType,i.type,t);e.push(Object.assign(Object.assign({},i),{format:t,placeholder:Te(i,t),options:Ne(i,t),hasLeadingZeros:s}))}function Ae(e,t){t&&e.push({type:"literal",contentType:"letter",format:t,placeholder:t,hasLeadingZeros:!1})}function Ne(e,t){switch(e.type){case"month":{const i="letter"===e.contentType?t:"MMMM";let s=(0,f.KQ)().startOf("year");const n=[];for(let e=0;e<12;e++)n.push(s.format(i).toLocaleUpperCase()),s=s.add(1,"months");return n}case"dayPeriod":{const e=(0,f.KQ)().hour(0),i=e.hour(12);return[e.format(t).toLocaleUpperCase(),i.format(t).toLocaleUpperCase()]}case"weekday":{const i="letter"===e.contentType?t:"dddd";let s=(0,f.KQ)().day(0);const n=[];for(let e=0;e<7;e++)n.push(s.format(i).toLocaleUpperCase()),s=s.add(1,"day");return n}}}function Ie(e,t,i){let s=1;const n=[];let r=-1;for(let o=0;ot[e]))}function Ue(e,t){const i=n.useRef(null),[,s]=n.useState({});function r(t){e.setSelectedSections(t),s({})}function o(){var t,n;e.focusSectionInPosition(null!==(n=null===(t=i.current)||void 0===t?void 0:t.selectionStart)&&void 0!==n?n:0),s({})}n.useLayoutEffect((()=>{const t=i.current;if(!t)return;if(null===e.selectedSectionIndexes)return void(t.scrollLeft&&(t.scrollLeft=0));const s=e.sections[e.selectedSectionIndexes.startIndex],n=e.sections[e.selectedSectionIndexes.endIndex];if(s&&n){const e=s.start,i=n.end;e===t.selectionStart&&i===t.selectionEnd||t.setSelectionRange(e,i)}}));const a=n.useMemo((()=>{if(!e.selectedSectionIndexes)return"text";const t=e.sections[e.selectedSectionIndexes.startIndex];return t&&"letter"!==t.contentType?"tel":"text"}),[e.selectedSectionIndexes,e.sections]);return{inputProps:{value:e.text,view:t.view,size:t.size,disabled:e.disabled,hasClear:!e.readOnly&&!e.isEmpty&&t.hasClear,placeholder:t.placeholder,id:t.id,label:t.label,startContent:t.startContent,endContent:t.endContent,pin:t.pin,autoFocus:t.autoFocus,controlRef:i,autoComplete:"off",type:"text",validationState:e.validationState,errorMessage:t.errorMessage,errorPlacement:t.errorPlacement,onUpdate(t){t||e.clearAll()},onFocus(s){var n;if(null===(n=t.onFocus)||void 0===n||n.call(t,s),null!==e.selectedSectionIndexes)return;const a=s.target,c=!i.current;setTimeout((()=>{a&&a===i.current&&(c?e.focusSectionInPosition(0):a.value.length&&Number(a.selectionEnd)-Number(a.selectionStart)===a.value.length?r("all"):o())}))},onBlur(e){var i;null===(i=t.onBlur)||void 0===i||i.call(t,e),r(-1)},onKeyDown(i){var s;null===(s=t.onKeyDown)||void 0===s||s.call(t,i),"ArrowLeft"===i.key?(i.preventDefault(),e.focusPreviousSection()):"ArrowRight"===i.key?(i.preventDefault(),e.focusNextSection()):"Home"===i.key?(i.preventDefault(),e.decrementToMin()):"End"===i.key?(i.preventDefault(),e.incrementToMax()):"ArrowUp"!==i.key||i.altKey?"ArrowDown"!==i.key||i.altKey?"PageUp"===i.key?(i.preventDefault(),e.incrementPage()):"PageDown"===i.key?(i.preventDefault(),e.decrementPage()):"Backspace"===i.key||"Delete"===i.key?(i.preventDefault(),e.clearSection()):"a"===i.key&&(i.ctrlKey||i.metaKey)&&(i.preventDefault(),r("all")):(i.preventDefault(),e.decrement()):(i.preventDefault(),e.increment())},onKeyUp:t.onKeyUp,controlProps:{"aria-label":t["aria-label"]||void 0,"aria-labelledby":t["aria-labelledby"]||void 0,"aria-describedby":t["aria-describedby"]||void 0,"aria-details":t["aria-details"]||void 0,"aria-disabled":e.disabled||void 0,readOnly:e.readOnly,inputMode:a,onClick(){o()},onMouseUp(e){e.preventDefault()},onBeforeInput(t){t.preventDefault();const i=t.data;void 0!==i&&null!==i&&e.onInput(i)},onPaste(t){if(t.preventDefault(),e.readOnly)return;const i=t.clipboardData.getData("text").replace(/[\u2066\u2067\u2068\u2069]/g,"");if(e.selectedSectionIndexes&&e.selectedSectionIndexes.startIndex===e.selectedSectionIndexes.endIndex){const t=e.sections[e.selectedSectionIndexes.startIndex],s=/^\d+$/.test(i),n=/^[a-zA-Z]+$/.test(i);if(Boolean(t&&("digit"===t.contentType&&s||"letter"===t.contentType&&n)))return void e.onInput(i);if(s||n)return}e.setValueFromString(i)}}}}}const He={year:5,month:2,weekday:3,day:7,hour:2,minute:15,second:15};function Be(e){var t,i;const[s,r]=(0,o.P)(e.value,null!==(t=e.defaultValue)&&void 0!==t?t:null,e.onUpdate),a=le(e.value||e.defaultValue||e.placeholderValue),c=e.timeZone||a,l=e=>{r(e?e.timeZone(a):e)},[h,d]=n.useState((()=>j({placeholderValue:e.placeholderValue,timeZone:c}))),u=e.format||"L",g=function(e){const t=e,[i,s]=n.useState((()=>xe(t))),[r,o]=n.useState(t);return t!==r&&(o(t),s(xe(t))),i}(u),p=n.useMemo((()=>g.filter((e=>Ce[e.type])).reduce(((e,t)=>Object.assign(Object.assign({},e),{[t.type]:!0})),{})),[g]),m=n.useState((()=>s?Object.assign({},p):{}));let _=m[0];const v=m[1];s&&!Fe(p,_)&&v(Object.assign({},p)),!s&&Object.keys(p).length>0&&Fe(p,_)&&Object.keys(_).length===Object.keys(p).length&&(_={},v(_),d(j({placeholderValue:e.placeholderValue,timeZone:c})));const C=s&&s.isValid()&&Fe(p,_)?s.timeZone(c):h.timeZone(c),E=function(e,t,i){const[s,r]=n.useState((()=>({value:t,sections:e,validSegments:i,editableSections:Ie(e,t,i)})));e===s.sections&&i===s.validSegments&&t.isSame(s.value)&&t.timeZone()===s.value.timeZone()||r({value:t,sections:e,validSegments:i,editableSections:Ie(e,t,i)});return s}(g,C,_),[b,S]=n.useState(-1),y=n.useMemo((()=>{if(-1===b)return null;if("all"===b)return{startIndex:0,endIndex:E.editableSections.length-1};if("number"===typeof b)return{startIndex:b,endIndex:b};if("string"===typeof b){const e=E.editableSections.findIndex((e=>e.type===b));return{startIndex:e,endIndex:e}}return b}),[b,E.editableSections]);function w(t){e.disabled||e.readOnly||(Fe(p,_)?s&&t.isSame(s)||l(t):(s&&l(null),d(t)))}function R(e){_[e]=!0,_.day&&_.month&&_.year&&p.weekday&&(_.weekday=!0),_.hour&&p.dayPeriod&&(_.dayPeriod=!0),v(Object.assign({},_))}const L=e.validationState||(function(e,t,i){return!!e&&(!(!t||!e.isBefore(t))||!(!i||!i.isBefore(e)))}(s,e.minValue,e.maxValue)?"invalid":void 0)||(s&&(null===(i=e.isDateUnavailable)||void 0===i?void 0:i.call(e,s))?"invalid":void 0);return function(e){const{value:t,validationState:i,displayValue:s,editableSections:r,selectedSectionIndexes:o,selectedSections:a,isEmpty:c,flushAllValidSections:l,flushValidSection:h,setSelectedSections:d,setValue:u,setDate:g,adjustSection:p,setSection:m,getSectionValue:f,setSectionValue:_,createPlaceholder:v,setValueFromString:C}=e,E=n.useRef(""),{hasDate:b,hasTime:S}=n.useMemo((()=>{let e=!1,t=!1;for(const i of r)t||(t=["hour","minute","second"].includes(i.type)),e||(e=["day","month","year"].includes(i.type));return{hasTime:t,hasDate:e}}),[r]);return{value:t,isEmpty:c,displayValue:s,setValue:u,setDate:g,text:(y=r,"\u2066"+y.map((e=>e.textValue)).join("")+"\u2069"),readOnly:e.readOnly,disabled:e.disabled,sections:r,hasDate:b,hasTime:S,selectedSectionIndexes:o,validationState:i,setSelectedSections(e){E.current="",d(e)},focusSectionInPosition(e){const t=this.sections.findIndex((t=>t.end>=e)),i=-1===t?0:t,s=this.sections[i];s&&this.setSelectedSections(Ce[s.type]?i:s.nextEditableSection)},focusNextSection(){var e,t;const i="all"===a?0:a,s=null!==(t=null===(e=this.sections[i])||void 0===e?void 0:e.nextEditableSection)&&void 0!==t?t:-1;-1!==s&&this.setSelectedSections(s)},focusPreviousSection(){var e,t;const i="all"===a?0:a,s=null!==(t=null===(e=this.sections[i])||void 0===e?void 0:e.previousEditableSection)&&void 0!==t?t:-1;-1!==s&&this.setSelectedSections(s)},focusFirstSection(){var e,t;const i=null!==(t=null===(e=this.sections[0])||void 0===e?void 0:e.previousEditableSection)&&void 0!==t?t:-1;-1!==i&&d(i)},focusLastSection(){var e,t;const i=null!==(t=null===(e=this.sections[this.sections.length-1])||void 0===e?void 0:e.nextEditableSection)&&void 0!==t?t:-1;-1!==i&&this.setSelectedSections(i)},increment(){if(this.readOnly||this.disabled)return;E.current="";const e=Me(this.sections,a);-1!==e&&p(e,1)},decrement(){if(this.readOnly||this.disabled)return;E.current="";const e=Me(this.sections,a);-1!==e&&p(e,-1)},incrementPage(){if(this.readOnly||this.disabled)return;E.current="";const e=Me(this.sections,a);-1!==e&&p(e,He[this.sections[e].type]||1)},decrementPage(){if(this.readOnly||this.disabled)return;E.current="";const e=Me(this.sections,a);-1!==e&&p(e,-(He[this.sections[e].type]||1))},incrementToMax(){if(this.readOnly||this.disabled)return;E.current="";const e=Me(this.sections,a);if(-1!==e){const t=this.sections[e];"number"===typeof t.maxValue&&m(e,t.maxValue)}},decrementToMin(){if(this.readOnly||this.disabled)return;E.current="";const e=Me(this.sections,a);if(-1!==e){const t=this.sections[e];"number"===typeof t.minValue&&m(e,t.minValue)}},clearSection(){if(this.readOnly||this.disabled)return;if(E.current="","all"===a)return void this.clearAll();const t=Me(this.sections,a);if(-1===t)return;h(t);const i=this.sections[t],s=j({placeholderValue:e.placeholderValue,timeZone:e.timeZone}).timeZone(e.timeZone),n=f(t);let r=n;if("dayPeriod"===i.type){const e=n.hour()>=12,t=s.hour()>=12;e&&!t?r=n.set("hour",n.hour()-12):!e&&t&&(r=n.set("hour",n.hour()+12))}else{const e=Le(i.type);r=n.set(e,s[e]())}_(t,r)},clearAll(){if(this.readOnly||this.disabled)return;E.current="",l(),null!==t&&g(null);const e=v();u(e)},onInput(e){if(this.readOnly||this.disabled)return;const t=Me(this.sections,a);if(-1===t)return;const i=this.sections[t];let s=E.current+e;const n=n=>{var r,o,a;let c="month"===i.type?n-1:n;const l=0===i.minValue;if("hour"!==i.type||12!==i.minValue&&11!==i.maxValue){if(c>(null!==(r=i.maxValue)&&void 0!==r?r:0)&&(c=Number(e)-("month"===i.type?1:0),s=e,c>(null!==(o=i.maxValue)&&void 0!==o?o:0)))return void(E.current="")}else n>12&&(c=Number(e)),12===i.minValue&&c>1&&(c+=12);const h=c>0||0===c&&l;h&&m(t,c),Number(n+"0")>(null!==(a=i.maxValue)&&void 0!==a?a:0)||s.length>=String(i.maxValue).length?(E.current="",h&&this.focusNextSection()):E.current=s},r=n=>{var r;const o=null!==(r=i.options)&&void 0!==r?r:[];let a=n.toLocaleUpperCase(),c=o.filter((e=>e.startsWith(a)));if(0===c.length&&(n!==e&&(a=e.toLocaleUpperCase(),c=o.filter((e=>e.startsWith(a)))),0===c.length))return void(E.current="");const l=c[0],h=o.indexOf(l);"dayPeriod"===i.type?m(t,1===h?12:0):m(t,h),c.length>1?E.current=s:(E.current="",this.focusNextSection())};switch(i.type){case"day":case"hour":case"minute":case"second":case"year":if(!Number.isInteger(Number(s)))return;n(Number(s));break;case"dayPeriod":r(s);break;case"weekday":case"month":Number.isInteger(Number(s))?n(Number(s)):r(s)}},setValueFromString:e=>(E.current="",C(e))};var y}({value:s,displayValue:C,placeholderValue:e.placeholderValue,timeZone:c,validationState:L,editableSections:E.editableSections,readOnly:e.readOnly,disabled:e.disabled,selectedSectionIndexes:y,selectedSections:b,isEmpty:0===Object.keys(_).length,flushAllValidSections:function(){_={},v({})},flushValidSection:function(e){const t=E.editableSections[e];t&&delete _[t.type],v(Object.assign({},_))},setSelectedSections:S,setValue:w,setDate:l,adjustSection:function(e,t){const i=E.editableSections[e];i&&(_[i.type]?w(function(e,t,i){var s;let n=null!==(s=e.value)&&void 0!==s?s:0;if("dayPeriod"===e.type)n=t.hour()+(t.hour()>=12?-12:12);else{n+=i;const t=e.minValue,s=e.maxValue;if("number"===typeof t&&"number"===typeof s){const e=s-t+1;n=(n-t+e)%e+t}}"year"!==e.type||Se(e.format)||(n=(0,f.KQ)({input:`${n}`.padStart(2,"0"),format:e.format}).year());const r=Le(e.type);return t.set(r,n)}(i,C,t)):(R(i.type),Object.keys(_).length>=Object.keys(p).length&&w(C)))},setSection:function(e,t){const i=E.editableSections[e];i&&(R(i.type),w(function(e,t,i){const s=e.type;switch(s){case"year":return t.set("year",Se(e.format)?i:(0,f.KQ)({input:`${i}`.padStart(2,"0"),format:e.format}).year());case"day":case"weekday":case"month":return t.set(Le(s),i);case"dayPeriod":{const e=t.hour(),s=e>=12;return i>=12===s?t:t.set("hour",s?e-12:e+12)}case"hour":{let s=i;if(12===e.minValue||11===e.maxValue){const e=t.hour()>=12;e||12!==s||(s=0),e&&s<12&&(s+=12)}return t.set("hour",s)}case"minute":case"second":return t.set(s,i)}return t}(i,C,t)))},getSectionValue:function(e){return C},setSectionValue:function(e,t){w(t)},createPlaceholder:function(){return j({placeholderValue:e.placeholderValue,timeZone:c}).timeZone(c)},setValueFromString:function(e){const t=function(e,t,i){let s=Pe({input:e,format:t,timeZone:i});s.isValid()&&i&&!function(e){return/z$/i.test(e)||/[+-]\d\d:\d\d$/.test(e)}(e)&&(s=Y(s,Pe({input:e,format:t})));return s}(e,u,c);return!!t.isValid()&&(l(t),!0)}})}const We=l("date-field");function Ve(e){var{className:t}=e,i=(0,me.Tt)(e,["className"]);const r=Be(i),{inputProps:o}=Ue(r,i),[c,l]=n.useState(!1),{focusWithinProps:d}=(0,a.R)({onFocusWithinChange(e){l(e)}});return(0,s.jsxs)("div",Object.assign({className:We(null,t),style:i.style},d,{children:[(0,s.jsx)(u.k,Object.assign({},o,{value:r.isEmpty&&!c&&i.placeholder?"":o.value})),(0,s.jsx)(h,{name:i.name,value:r.value,toStringValue:e=>{var t;return null!==(t=null===e||void 0===e?void 0:e.toISOString())&&void 0!==t?t:""},onReset:e=>{r.setDate(e)},disabled:r.disabled,form:i.form})]}))}const ze=l("mobile-calendar");function Ge({props:e,state:t}){var i,n;let r="date";return t.hasTime&&t.hasDate?r="datetime-local":t.hasTime&&(r="time"),(0,s.jsx)("input",{className:ze(),disabled:e.disabled,type:r,value:Ke(t.dateFieldState.value,r),id:e.id,min:Ke(null===(i=e.minValue)||void 0===i?void 0:i.timeZone(t.timeZone),r),max:Ke(null===(n=e.maxValue)||void 0===n?void 0:n.timeZone(t.timeZone),r),tabIndex:-1,onChange:i=>{var s,n;if(e.readOnly)return;const o=i.target.value;if(o){const i=(0,f.KQ)({input:o,format:je(r),timeZone:"system"}).timeZone(t.timeZone,!0);let a=t.hasDate?i:j({placeholderValue:null===(s=e.placeholderValue)||void 0===s?void 0:s.timeZone(t.timeZone),timeZone:t.timeZone});a=t.hasTime?Y(a,i):t.value?Y(a,t.value.timeZone(t.timeZone)):Y(a,j({placeholderValue:null===(n=e.placeholderValue)||void 0===n?void 0:n.timeZone(t.timeZone),timeZone:t.timeZone})),t.setValue(a)}else t.setValue(null)}})}function je(e){switch(e){case"time":return"HH:mm";case"datetime-local":return"YYYY-MM-DDTHH:mm";default:return"YYYY-MM-DD"}}function Ke(e,t){if(!e)return"";const i=je(t);return e.format(i)}const Ye=l("stub-button");function qe({size:e,icon:t}){return(0,s.jsx)("span",{className:Ye({size:e}),children:(0,s.jsx)("span",{className:Ye("icon"),children:(0,s.jsx)(p.I,{data:t})})})}function $e(...e){const t=Object.assign({},e[0]);for(let i=1;i=65&&e.charCodeAt(2)<=90?t[e]=Qe(i,n):t[e]="className"===e&&"string"===typeof i&&"string"===typeof n?i+" "+n:"controlProps"===e&&"object"===typeof i&&"object"===typeof n?$e(i,n):void 0===n?i:n}}return t}function Qe(...e){return(...t)=>{for(const i of e)"function"===typeof i&&i(...t)}}const Xe=JSON.parse('{"Calendar":"Calendar","Formula input mode":"Formula input mode"}'),Ze=JSON.parse('{"Calendar":"\u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c","Formula input mode":"\u0420\u0435\u0436\u0438\u043c \u0432\u0432\u043e\u0434\u0430 \u0444\u043e\u0440\u043c\u0443\u043b\u044b"}'),Je=(0,_.N)({en:Xe,ru:Ze},`${c}relative-date-picker`);function et(e,t){var{onFocus:i,onBlur:s}=t,r=(0,me.Tt)(t,["onFocus","onBlur"]);const{mode:c,setMode:l,datePickerState:h,relativeDateState:d}=e,[u,g]=n.useState("relative"===c?d.lastCorrectDate:h.dateFieldState.displayValue),[p,f]=n.useState(d.lastCorrectDate);p!==d.lastCorrectDate&&(f(d.lastCorrectDate),g(d.lastCorrectDate));const[_,v]=n.useState(h.dateFieldState.displayValue);h.dateFieldState.displayValue.isSame(_,"day")||(v(h.dateFieldState.displayValue),g(h.dateFieldState.displayValue));const{focusWithinProps:C}=(0,a.R)({onFocusWithin:i,onBlurWithin:s,onFocusWithinChange(t){t||e.setActive(!1)}}),[E,b]=(0,o.P)(void 0,!1,r.onOpenChange);!e.isActive&&E&&b(!1);const S={onFocus:()=>{e.isActive||(e.setActive(!0),b(!0))},errorMessage:r.errorMessage,errorPlacement:r.errorPlacement,controlProps:{onClick:()=>{e.disabled||E||(e.setActive(!0),b(!0))},role:"combobox","aria-expanded":E}},{inputProps:y}=Ue(h.dateFieldState,Object.assign(Object.assign({},r),{value:void 0,defaultValue:void 0,onUpdate:void 0})),{inputProps:w}=function(e,t){const[i,s]=n.useState(e.lastCorrectDate),[r,o]=n.useState(e.lastCorrectDate);return i!==e.lastCorrectDate&&(s(e.lastCorrectDate),o(e.lastCorrectDate)),{inputProps:{size:t.size,autoFocus:t.autoFocus,value:e.text,onUpdate:e.setText,disabled:e.disabled,hasClear:t.hasClear,validationState:e.validationState,errorMessage:t.errorMessage,errorPlacement:t.errorPlacement,label:t.label,id:t.id,startContent:t.startContent,endContent:t.endContent,pin:t.pin,view:t.view,placeholder:t.placeholder,onKeyDown:t.onKeyDown,onKeyUp:t.onKeyUp,onBlur:t.onBlur,onFocus:t.onFocus,controlProps:{"aria-label":t["aria-label"]||void 0,"aria-labelledby":t["aria-labelledby"]||void 0,"aria-describedby":t["aria-describedby"]||void 0,"aria-details":t["aria-details"]||void 0,"aria-disabled":e.disabled||void 0,readOnly:e.readOnly}},calendarProps:{size:"s"===t.size?"m":t.size,readOnly:!0,value:e.parsedDate,focusedValue:r,onFocusUpdate:o},timeInputProps:{size:t.size,readOnly:!0,value:e.lastCorrectDate,format:"LTS"}}}(d,Object.assign(Object.assign({},r),{value:void 0,defaultValue:void 0,onUpdate:void 0}));let R=r.validationState;R||(R="relative"===c?d.validationState:h.dateFieldState.validationState);const L=n.useRef(null),T=(0,W.N)(L,"relative"===c?w.controlRef:y.controlRef),x=n.useRef(null);function k(){setTimeout((()=>{var e;null===(e=x.current)||void 0===e||e.focus()}))}function A(){setTimeout((()=>{var e;null===(e=L.current)||void 0===e||e.focus({preventScroll:!0})}))}const N=n.useRef(null);return{groupProps:Object.assign(Object.assign({ref:N,tabIndex:-1,role:"group"},C),{onKeyDown:e=>{!e.altKey||"ArrowDown"!==e.key&&"ArrowUp"!==e.key||(e.preventDefault(),e.stopPropagation(),b(!0),k())}}),fieldProps:$e(S,"relative"===c?w:y,"absolute"===c&&h.dateFieldState.isEmpty&&!e.isActive&&r.placeholder?{value:""}:void 0,{controlRef:T,validationState:R}),modeSwitcherProps:{size:m(r.size),disabled:e.readOnly||e.disabled,view:"flat-secondary",style:{zIndex:2,marginInlineEnd:2},selected:"relative"===c,extraProps:{"aria-label":Je("Formula input mode")},onClick:()=>{if(l("relative"===c?"absolute":"relative"),"relative"===c){const e=h.value;e&&g(e)}else d.parsedDate&&g(d.parsedDate);A()}},calendarButtonProps:{size:m(r.size),disabled:e.disabled,extraProps:{"aria-label":Je("Calendar"),"aria-haspopup":"dialog","aria-expanded":E},view:"flat-secondary",onClick:()=>{e.setActive(!0),b(!E),E||k()}},popupProps:{open:E,onEscapeKeyDown:()=>{b(!1),A()},onOutsideClick:e=>{var t;e.target&&!(null===(t=N.current)||void 0===t?void 0:t.contains(e.target))&&b(!1)},onTransitionExited:()=>{g("relative"===c?d.lastCorrectDate:h.dateFieldState.displayValue)}},calendarProps:{ref:x,size:"s"===r.size?"m":r.size,readOnly:r.readOnly,value:e.selectedDate,onUpdate:t=>{h.setDateValue(t),e.datePickerState.hasTime||(b(!1),A())},focusedValue:u,onFocusUpdate:g,minValue:r.minValue,maxValue:r.maxValue},timeInputProps:{value:h.timeValue,onUpdate:h.setTimeValue,format:h.timeFormat,readOnly:e.readOnly,disabled:e.disabled,timeZone:r.timeZone,hasClear:r.hasClear,size:r.size}}}const tt=function({getPlaceholderTime:e,mergeDateTime:t,setTimezone:i,getDateTime:s,useDateFieldState:r}){return function(a){var c,l;const{disabled:h,readOnly:d}=a,[u,g]=(0,o.P)(a.open,null!==(c=a.defaultOpen)&&void 0!==c&&c,a.onOpenChange),p=g,[m,f]=(0,o.P)(a.value,null!==(l=a.defaultValue)&&void 0!==l?l:null,a.onUpdate),[_,v]=n.useState(null),[C,E]=n.useState(null),b=le(s(a.value)||s(a.defaultValue)||a.placeholderValue),S=a.timeZone||b;let y=_,w=C;const R=a.format||"L",L=(e,s)=>{h||d||(f(i(t(e,s),b)),v(null),E(null))},T=r(Object.assign(Object.assign({},a),{value:m,onUpdate(e){e?L(e,e):f(null)},disabled:h,readOnly:d,validationState:a.validationState,minValue:a.minValue,maxValue:a.maxValue,isDateUnavailable:a.isDateUnavailable,format:R,placeholderValue:a.placeholderValue,timeZone:S})),x=n.useMemo((()=>{if(!T.hasTime)return;const e=[],t=T.sections.find((e=>"hour"===e.type));t&&e.push(t.format);const i=T.sections.find((e=>"minute"===e.type));i&&e.push(i.format);const s=T.sections.find((e=>"second"===e.type));s&&e.push(s.format);const n=T.sections.find((e=>"dayPeriod"===e.type));return e.join(":")+(n?` ${n.format}`:"")}),[T.hasTime,T.sections]);m&&(y=i(m,S),T.hasTime&&(w=i(m,S)));return T.hasTime&&!w&&(w=T.displayValue),{value:m,setValue(e){a.readOnly||a.disabled||f(e?i(e,b):null)},dateValue:y,timeValue:w,setDateValue:e=>{if(h||d)return;const t=!T.hasTime;T.hasTime?w||t?L(e,w||e):v(e):L(e,e),t&&p(!1,"ValueSelected")},setTimeValue:t=>{if(h||d)return;const i=null!==t&&void 0!==t?t:e(a.placeholderValue,S);y?L(y,i):E(i)},disabled:h,readOnly:d,format:R,hasDate:T.hasDate,hasTime:T.hasTime,timeFormat:x,timeZone:S,isOpen:u,setOpen(t,i){!t&&!m&&y&&T.hasTime&&L(y,w||e(a.placeholderValue,a.timeZone)),p(t,i)},dateFieldState:T}}}({getPlaceholderTime:function(e,t){return j({placeholderValue:e,timeZone:t})},mergeDateTime:Y,setTimezone:(e,t)=>e.timeZone(t),getDateTime:function(e){if(e)return"start"in e&&"end"in e?e.start:e},useDateFieldState:Be});function it(e){var t;const[i,s]=(0,o.P)(e.value,null!==(t=e.defaultValue)&&void 0!==t?t:null,e.onUpdate),[r,a]=n.useState("relative"===(null===i||void 0===i?void 0:i.type)?"relative":"absolute"),[c,l]=n.useState(i);i!==c&&(l(i),i&&i.type!==r&&a(i.type));const[h,d]=n.useState("absolute"===(null===i||void 0===i?void 0:i.type)?i.value:null);"absolute"===(null===i||void 0===i?void 0:i.type)&&i.value!==h&&d(i.value);const u=tt({value:h,onUpdate:e=>{d(e),"absolute"===(null===i||void 0===i?void 0:i.type)&&(null===e||void 0===e?void 0:e.isSame(i.value))||s(e?{type:"absolute",value:e}:null)},format:e.format,placeholderValue:e.placeholderValue,timeZone:e.timeZone,disabled:e.disabled,readOnly:e.readOnly,minValue:e.minValue,maxValue:e.maxValue}),[g,p]=n.useState("relative"===(null===i||void 0===i?void 0:i.type)?i.value:null);"relative"===(null===i||void 0===i?void 0:i.type)&&i.value!==g&&p(i.value);const m=function(e){var t;const[i,s]=(0,o.P)(e.value,null!==(t=e.defaultValue)&&void 0!==t?t:null,e.onUpdate),[r,a]=n.useState(null!==i&&void 0!==i?i:"");i&&i!==r&&a(i);const c=n.useMemo((()=>{var t;return i&&null!==(t=(0,f.bQ)(i,{timeZone:e.timeZone,roundUp:e.roundUp}))&&void 0!==t?t:null}),[i,e.timeZone,e.roundUp]),[l,h]=n.useState(c);c&&c!==l&&h(c);const d=e.validationState||r&&!c?"invalid":void 0;return{value:i,setValue(t){e.disabled||e.readOnly||s(t)},text:r,setText:t=>{if(!e.disabled&&!e.readOnly)if(a(t),(0,f.eP)(t)){const e=(0,f.bQ)(t);e&&e.isValid()?s(t):s(null)}else s(null)},parsedDate:c,lastCorrectDate:l,validationState:d,disabled:e.disabled,readOnly:e.readOnly}}({value:g,onUpdate:e=>{p(e),"relative"===(null===i||void 0===i?void 0:i.type)&&e===i.value||s(e?{type:"relative",value:e}:null)},disabled:e.disabled,readOnly:e.readOnly,timeZone:u.timeZone,roundUp:e.roundUp});i||("absolute"===r&&h?d(null):"relative"===r&&g&&p(null));const _="relative"===r?m.parsedDate:u.dateFieldState.displayValue,[v,C]=n.useState(!1);return{value:i,setValue(t){e.readOnly||e.disabled||s(t)},disabled:e.disabled,readOnly:e.readOnly,mode:r,setMode(t){e.readOnly||e.disabled||t===r||(a(t),"relative"===t?(!i&&g||i)&&s(g?{type:"relative",value:g}:null):(!i&&h||i)&&s(h?{type:"absolute",value:h}:null))},datePickerState:u,relativeDateState:m,selectedDate:_,isActive:v,setActive:C}}const st=l("relative-date-picker");function nt(e){var t;const i=it(e),{groupProps:o,fieldProps:a,modeSwitcherProps:c,calendarButtonProps:l,popupProps:m,calendarProps:f,timeInputProps:_}=et(i,e),v=n.useRef(null),C=(0,W.N)(v,o.ref),E=(0,r.I)(),b=i.datePickerState.hasTime&&!i.datePickerState.hasDate;return(0,s.jsxs)("div",Object.assign({},o,{ref:C,className:st(null,e.className),children:[E&&"absolute"===i.mode&&(0,s.jsx)(Ge,{state:i.datePickerState,props:{id:e.id,disabled:e.disabled,readOnly:e.readOnly,placeholderValue:e.placeholderValue,timeZone:e.timeZone}}),(0,s.jsx)(u.k,Object.assign({},a,{controlProps:Object.assign(Object.assign({},a.controlProps),{disabled:E&&"absolute"===i.mode,className:st("input",{mobile:E&&"absolute"===i.mode})}),hasClear:e.hasClear&&!(E&&"absolute"===i.mode),startContent:(0,s.jsx)(g.$,Object.assign({},c,{children:(0,s.jsx)(p.I,{data:H})})),endContent:(0,s.jsxs)(n.Fragment,{children:[!E&&!b&&(0,s.jsx)(g.$,Object.assign({},l,{children:(0,s.jsx)(p.I,{data:d})})),!E&&b&&(0,s.jsx)(qe,{size:l.size,icon:B}),E&&"absolute"===i.mode&&(0,s.jsx)(qe,{size:l.size,icon:b?B:d})]})})),(0,s.jsx)(h,{name:e.name,value:null===(t=i.value)||void 0===t?void 0:t.type,disabled:i.disabled,form:e.form}),(0,s.jsx)(h,{name:e.name,value:i.value,toStringValue:e=>function(e){if(!e)return"";if("relative"===e.type)return e.value;return e.value.toISOString()}(e),onReset:e=>{i.setValue(e)},disabled:i.disabled,form:e.form}),!E&&!b&&(0,s.jsx)(U.z,Object.assign({},m,{anchorRef:v,children:(0,s.jsxs)("div",{className:st("popup-content"),children:["function"===typeof e.children?e.children(f):(0,s.jsx)(pe,Object.assign({},f)),i.datePickerState.hasTime&&(0,s.jsx)("div",{className:st("time-field-wrapper"),children:(0,s.jsx)(Ve,Object.assign({},_))})]})}))]}))}var rt=i(23871),ot=i(40091),at=i(73633),ct=i(87924),lt=i.n(ct),ht=i(81824),dt=i.n(ht),ut=i(61199),gt=i.n(ut),pt=i(69220),mt=i(27629);const ft=JSON.parse('{"label_empty":"No data","label-actions":"Actions","label-row-select":"Select"}'),_t=JSON.parse('{"label_empty":"\u041d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445","label-actions":"\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f","label-row-select":"\u0412\u044b\u0431\u0440\u0430\u0442\u044c"}'),vt=(0,_.N)({en:ft,ru:_t},"Table");function Ct(e){(0,mt.m)(`[Table] Physical values (left, right) of "${e}" property are deprecated. Use logical values (start, end) instead.`)}function Et(e,t){return"left"===e?(Ct(t),"start"):"right"===e?(Ct(t),"end"):e}const bt=(0,pt.om)("table");class St extends n.Component{constructor(){super(...arguments),this.state={activeScrollElement:"scrollContainer",columnsStyles:Array.from(this.props.columns,(()=>({}))),columnHeaderRefs:Array.from(this.props.columns,(()=>n.createRef()))},this.tableRef=n.createRef(),this.scrollContainerRef=n.createRef(),this.horizontalScrollBarRef=n.createRef(),this.horizontalScrollBarInnerRef=n.createRef(),this.renderRow=(e,t)=>{const{columns:i,isRowDisabled:s,onRowClick:r,onRowMouseEnter:o,onRowMouseLeave:a,onRowMouseDown:c,getRowClassNames:l,verticalAlign:h,edgePadding:d,wordWrap:u,getRowDescriptor:g}=this.props,{columnsStyles:p}=this.state,m=null===g||void 0===g?void 0:g(e,t),f=(null===m||void 0===m?void 0:m.disabled)||(null===s||void 0===s?void 0:s(e,t))||!1,_=(null===m||void 0===m?void 0:m.classNames)||(null===l||void 0===l?void 0:l(e,t))||[],v=Boolean(!f&&r);return n.createElement("tr",{key:St.getRowId(this.props,e,t),onClick:!f&&r?r.bind(null,e,t):void 0,onMouseEnter:!f&&o?o.bind(null,e,t):void 0,onMouseLeave:!f&&a?a.bind(null,e,t):void 0,onMouseDown:!f&&c?c.bind(null,e,t):void 0,className:bt("row",{disabled:f,interactive:v,"vertical-align":h},_.join(" "))},i.map(((i,s)=>{const{id:r,align:o,primary:a,className:c,sticky:l}=i,h=St.getBodyCellContent(i,e,t),g=Et(o,"column.align"),m=Et(l,"column.sticky");return n.createElement("td",{key:r,style:p[s],className:bt("cell",{align:g,primary:a,sticky:m,"edge-padding":d,"word-wrap":u},c)},h)})))},this.handleScrollContainerMouseenter=()=>{this.setState({activeScrollElement:"scrollContainer"})},this.handleScrollContainerScroll=()=>{"scrollContainer"===this.state.activeScrollElement&&this.horizontalScrollBarRef.current&&this.scrollContainerRef.current&&(this.horizontalScrollBarRef.current.scrollLeft=this.scrollContainerRef.current.scrollLeft)},this.handleHorizontalScrollBarMouseenter=()=>{this.setState({activeScrollElement:"scrollBar"})},this.handleHorizontalScrollBarScroll=()=>{"scrollBar"===this.state.activeScrollElement&&this.horizontalScrollBarRef.current&&this.scrollContainerRef.current&&(this.scrollContainerRef.current.scrollLeft=this.horizontalScrollBarRef.current.scrollLeft)}}static getRowId(e,t,i){const{data:s,getRowId:n,getRowDescriptor:r}=e,o=null!==i&&void 0!==i?i:s.indexOf(t),a=null===r||void 0===r?void 0:r(t,o);return void 0!==(null===a||void 0===a?void 0:a.id)?a.id:"function"===typeof n?n(t,o):String(n&&n in t?t[n]:o)}static getHeadCellContent(e){const{id:t,name:i}=e;let s;return s="function"===typeof i?i():"string"===typeof i?i:t,s}static getBodyCellContent(e,t,i){const{id:s,template:n,placeholder:r}=e;let o,a;return o="function"===typeof r?r(t,i):null!==r&&void 0!==r?r:"\u2014","function"===typeof n?a=n(t,i):"string"===typeof n?a=lt()(t,n):dt()(t,s)&&(a=lt()(t,s)),[void 0,null,""].includes(a)&&o?o:a}static getDerivedStateFromProps(e,t){return e.columns.length===t.columnHeaderRefs.length?null:{columnHeaderRefs:Array.from(e.columns,(()=>n.createRef()))}}componentDidMount(){this.props.stickyHorizontalScroll&&(this.tableResizeObserver=new ResizeObserver((e=>{var t;const{contentRect:i}=e[0];null===(t=this.horizontalScrollBarInnerRef.current)||void 0===t||t.style.setProperty("width",`${i.width}px`)})),this.tableRef.current&&this.tableResizeObserver.observe(this.tableRef.current),this.scrollContainerRef.current&&(this.scrollContainerRef.current.addEventListener("scroll",this.handleScrollContainerScroll),this.scrollContainerRef.current.addEventListener("mouseenter",this.handleScrollContainerMouseenter)),this.horizontalScrollBarRef.current&&(this.horizontalScrollBarRef.current.addEventListener("scroll",this.handleHorizontalScrollBarScroll),this.horizontalScrollBarRef.current.addEventListener("mouseenter",this.handleHorizontalScrollBarMouseenter))),this.columnsResizeObserver=new ResizeObserver((e=>{window.requestAnimationFrame((()=>{Array.isArray(e)&&e.length&&this.updateColumnStyles()}))})),this.tableRef.current&&this.columnsResizeObserver.observe(this.tableRef.current),this.updateColumnStyles()}componentDidUpdate(e){this.props.columns!==e.columns&&this.updateColumnStyles()}componentWillUnmount(){this.props.stickyHorizontalScroll&&(this.tableResizeObserver&&this.tableResizeObserver.disconnect(),this.scrollContainerRef.current&&(this.scrollContainerRef.current.removeEventListener("scroll",this.handleScrollContainerScroll),this.scrollContainerRef.current.removeEventListener("mouseenter",this.handleScrollContainerMouseenter)),this.horizontalScrollBarRef.current&&(this.horizontalScrollBarRef.current.removeEventListener("scroll",this.handleHorizontalScrollBarScroll),this.horizontalScrollBarRef.current.removeEventListener("mouseenter",this.handleHorizontalScrollBarMouseenter))),this.columnsResizeObserver&&this.columnsResizeObserver.disconnect()}render(){const{columns:e,stickyHorizontalScroll:t,className:i,qa:s}=this.props,r=e.some((({primary:e})=>e));return n.createElement("div",{className:bt({"with-primary":r,"with-sticky-scroll":t},i),"data-qa":s},t?n.createElement(n.Fragment,null,n.createElement("div",{ref:this.scrollContainerRef,className:bt("scroll-container")},this.renderTable()),this.renderHorizontalScrollBar()):this.renderTable())}renderHead(){const{columns:e,edgePadding:t,wordWrap:i}=this.props,{columnsStyles:s}=this.state;return n.createElement("thead",{className:bt("head")},n.createElement("tr",{className:bt("row")},e.map(((e,r)=>{const{id:o,align:a,primary:c,sticky:l,className:h}=e,d=Et(a,"column.align"),u=Et(l,"column.sticky"),g=St.getHeadCellContent(e);return n.createElement("th",{key:o,ref:this.state.columnHeaderRefs[r],style:s[r],className:bt("cell",{align:d,primary:c,sticky:u,"edge-padding":t,"word-wrap":i},h)},g)}))))}renderBody(){const{data:e}=this.props;return n.createElement("tbody",{className:bt("body")},e.length>0?e.map(this.renderRow):this.renderEmptyRow())}renderTable(){const{width:e="auto"}=this.props;return n.createElement("table",{ref:this.tableRef,className:bt("table",{width:e})},this.renderHead(),this.renderBody())}renderEmptyRow(){const{columns:e,emptyMessage:t}=this.props;return n.createElement("tr",{className:bt("row",{empty:!0})},n.createElement("td",{className:bt("cell"),colSpan:e.length},t||vt("label_empty")))}renderHorizontalScrollBar(){const{stickyHorizontalScroll:e,stickyHorizontalScrollBreakpoint:t=0}=this.props;return n.createElement("div",{ref:this.horizontalScrollBarRef,className:bt("horizontal-scroll-bar",{"sticky-horizontal-scroll":e}),style:{bottom:`${t}px`},"data-qa":"sticky-horizontal-scroll-breakpoint-qa"},n.createElement("div",{ref:this.horizontalScrollBarInnerRef,className:bt("horizontal-scroll-bar-inner")}))}updateColumnStyles(){this.setState((e=>{const t=e.columnHeaderRefs.map((e=>null===e.current?void 0:e.current.getBoundingClientRect().width));return{columnsStyles:this.props.columns.map(((e,i)=>this.getColumnStyles(i,t)))}}))}getColumnStyles(e,t){const{columns:i}=this.props,s=i[e],n={};if("string"===typeof s.width)return{maxWidth:0,width:s.width};if("undefined"!==typeof s.width&&(n.width=s.width),!s.sticky)return n;const r="left"===s.sticky||"start"===s.sticky?t.slice(0,e):t.slice(e+1);return n["left"===s.sticky||"start"===s.sticky?"insetInlineStart":"insetInlineEnd"]=r.reduce(((e,t)=>gt()(t)?e+t:e),0),n}}St.defaultProps={edgePadding:!0};var yt=i(84375);const wt=l("relative-range-date-picker-presets-doc"),Rt=[{id:"title",name:()=>E("Range")},{id:"from",name:()=>E("From")},{id:"to",name:()=>E("To")}],Lt=[{get title(){return E("Last 5 minutes")},from:"now - 5m",to:"now"},{get title(){return E("From start of day")},from:"now/d",to:"now"},{get title(){return E("This week")},from:"now/w",to:"now/w"},{get title(){return E("From start of week")},from:"now/w",to:"now"},{get title(){return E("Previous month")},from:"now - 1M/M",to:"now - 1M/M"}];function Tt({size:e,docs:t}){return(0,s.jsx)(St,{columns:Rt,data:t,className:wt("table",{size:e})})}function xt({className:e,size:t,docs:i}){return(0,s.jsx)(yt.A,{className:wt(null,e),tooltipContentClassName:wt("content"),hasArrow:!1,content:(0,s.jsx)(Tt,{size:t,docs:i}),children:(0,s.jsx)(g.$,{className:wt("button"),view:"flat-secondary",size:m(t),children:(0,s.jsx)(p.I,{data:at.A})})})}function kt({className:e,size:t,docs:i}){const[r,o]=n.useState(!1);return(0,s.jsxs)("div",{className:wt(null,e),children:[(0,s.jsx)(g.$,{className:wt("button"),view:"flat-secondary",size:"l",onClick:()=>{o(!0)},children:(0,s.jsx)(p.I,{data:at.A})}),(0,s.jsx)(F.c,{visible:r,onClose:()=>o(!1),children:(0,s.jsx)(Tt,{size:t,docs:i})})]})}function At({className:e,size:t,docs:i=Lt}){const n=(0,r.I)();return Array.isArray(i)&&0!==i.length?n?(0,s.jsx)(kt,{className:e,size:t,docs:i}):(0,s.jsx)(xt,{className:e,size:t,docs:i}):null}const Nt=l("relative-range-date-picker-presets");function It({className:e,size:t="m",minValue:i,withTime:r,onChoosePreset:o,presetTabs:a,docs:c}){var l,h;const d=n.useMemo((()=>function(e,{minValue:t}={}){return e.reduce(((e,i)=>{const s=x(i.presets,t);return s.length&&e.push(Object.assign(Object.assign({},i),{presets:s})),e}),[])}(null!==a&&void 0!==a?a:function({withTime:e,minValue:t}){const i=[],s={id:"main",title:E("Main"),presets:[]},n=b;e&&n.unshift(...S),s.presets=x(n,t),s.presets.length>0&&i.push(s);const r={id:"other",title:E("Other"),presets:x(y,t)};return r.presets.length>0&&i.push(r),i}({withTime:r}),{minValue:i})),[r,i,a]),[u,g]=n.useState(null===(l=d[0])||void 0===l?void 0:l.id);if(0===d.length)return null;const p=null!==(h=d.find((e=>e.id===u)))&&void 0!==h?h:d[0];return p?(p.id!==u&&g(p.id),(0,s.jsxs)("div",{className:Nt({size:t},e),children:[(0,s.jsxs)("div",{className:Nt("tabs"),children:[(0,s.jsx)(rt.t,{activeTab:u,onSelectTab:g,items:d,size:"s"===t?"m":t}),(0,s.jsx)(At,{className:Nt("doc"),size:t,docs:c})]}),(0,s.jsx)("div",{className:Nt("content"),children:(0,s.jsx)(Dt,{presets:p.presets,onChoosePreset:o,size:t})})]})):null}const Ot={s:28,m:28,l:32,xl:36};function Dt({presets:e,onChoosePreset:t,size:i="m"}){const r=n.useRef(null);return n.useEffect((()=>{var e,t;const i=r.current,s=null===(t=null===(e=r.current)||void 0===e?void 0:e.refContainer.current)||void 0===t?void 0:t.node;if(i&&s)try{s.setAttribute("tabindex","0"),s.setAttribute("class",Nt("list-container"));const e=()=>{null===i.getActiveItem()&&i.activateItem(0,!0)};return s.addEventListener("focus",e),()=>{s.removeEventListener("focus",e)}}catch(n){}}),[]),(0,s.jsx)(ot.B,{ref:r,className:Nt("list"),itemClassName:Nt("item"),items:e,filterable:!1,virtualized:!1,renderItem:e=>e.title,itemHeight:Ot[i],onItemClick:e=>{t(e.from,e.to)}})}var Mt=i(24555),Pt=i(98089);const Ft=JSON.parse('{"default":"Default","system":"Browser time"}'),Ut=JSON.parse('{"default":"\u0414\u0435\u0444\u043e\u043b\u0442\u043d\u0430\u044f","system":"\u0411\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f"}'),Ht=(0,_.N)({en:Ft,ru:Ut},`${c}relative-range-date-picker-zones`),Bt={},Wt=(0,f.Pn)().reduce(((e,t)=>{const[i]=t.split("/");if(i){let s=Bt[i];s||(s={label:i,options:[]},Bt[i]=s,e.push(s)),s.options.push({value:t})}return e}),[]);Wt.unshift({value:"UTC"}),Wt.unshift({value:"system",get content(){return Ht("system")}}),Wt.unshift({value:"default",get content(){return Ht("default")}});const Vt=l("relative-range-date-picker-zones");function zt(e){const t=k(e.value),i=e.isMobile?"xl":e.size;return(0,s.jsx)(Mt.l,{disabled:e.disabled,value:[t],options:Wt,size:i,onUpdate:t=>{const i=t[0];i&&e.onUpdate(i)},width:"max",renderControl:n=>{const r="system"===t||"default"===t?Ht(t):t;return(0,s.jsxs)(g.$,{onClick:n.onClick,ref:n.ref,view:"flat-secondary",width:"max",pin:"clear-clear",size:i,disabled:e.disabled,extraProps:{"aria-haspopup":"listbox","aria-expanded":n.open,onKeyDown:n.onKeyDown},className:Vt("control"),children:[`${r} (${A(t)})`,(0,s.jsx)(p.I,{className:Vt("control-icon"),data:z.A,size:e.isMobile?20:16})]})},renderOption:({value:e,content:t})=>{const i=null!==t&&void 0!==t?t:e;return(0,s.jsxs)("span",{className:Vt("item"),children:[(0,s.jsxs)("span",{className:Vt("item-title"),title:e,children:[i,"\xa0"]}),(0,s.jsx)(Pt.E,{color:"secondary",children:A(e)})]})},filterable:!0})}const Gt=JSON.parse('{"Value is incorrect.":"Value is incorrect.","Value is required.":"Value is required.","\\"From\\" can\'t be after \\"To\\".":"\\"From\\" can\'t be after \\"To\\".","From":"From","To":"To","Apply":"Apply"}'),jt=JSON.parse('{"Value is incorrect.":"\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e.","Value is required.":"Value is required.","\\"From\\" can\'t be after \\"To\\".":"\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \xab\u041e\u0442\xbb \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u0447\u0435\u043c \xab\u0414\u043e\xbb.","From":"\u041e\u0442","To":"\u0414o","Apply":"\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c"}'),Kt=(0,_.N)({en:Gt,ru:jt},`${c}relative-range-date-picker-dialog`),Yt=JSON.parse('{"Value must be {minValue} or later.":"{{value}} must be {{minValue}} or later.","Value must be {maxValue} or earlier.":"{{value}} must be {{maxValue}} or earlier.","Selected date unavailable.":"Selected date unavailable.","Value is required.":"{{value}} is required."}'),qt=JSON.parse('{"Value must be {minValue} or later.":"{value} \u0434\u043e\u043b\u0436\u043d\u043e \u0440\u043e\u0432\u043d\u044f\u0442\u044c\u0441\u044f {minValue} \u0438\u043b\u0438 \u0431\u044b\u0442\u044c \u043f\u043e\u0437\u0436\u0435.","Value must be {maxValue} or earlier.":"{value} \u0434\u043e\u043b\u0436\u043d\u043e \u0440\u043e\u0432\u043d\u044f\u0442\u044c\u0441\u044f {maxValue} \u0438\u043b\u0438 \u0431\u044b\u0442\u044c \u0440\u0430\u043d\u044c\u0448\u0435.","Selected date unavailable.":"\u0412\u044b\u0431\u0440\u0430\u043d\u043d\u0430\u044f \u0434\u0430\u0442\u0430 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430.","Value is required.":"{value} \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e."}'),$t=(0,_.N)({en:Yt,ru:qt},`${c}validation`);function Qt(e,t,i,s,n,r="Value"){const o=e&&i&&i.isBefore(e),a=e&&t&&e.isBefore(t),c=e&&(null===s||void 0===s?void 0:s(e))||!1,l=o||a||c,h=[];return l&&(a&&t&&h.push($t("Value must be {minValue} or later.",{minValue:t.timeZone(n).format(),value:r})),o&&i&&h.push($t("Value must be {maxValue} or earlier.",{maxValue:i.timeZone(n).format(),value:r})),c&&h.push($t("Selected date unavailable."))),{isInvalid:l,errors:h}}function Xt(e,t,i={}){var s;if(!e&&!t)return null;const{isInvalid:n}=Zt(e,t,i.allowNullableValues,i.minValue,i.maxValue,i.isDateUnavailable,null!==(s=i.timeZone)&&void 0!==s?s:"default");return n?null:{start:e,end:t}}function Zt(e,t,i,s,n,r,o){if(!e&&!t)return{isInvalid:!1};const a=e?(0,f.bQ)(e.value,{timeZone:o}):null,c=t?(0,f.bQ)(t.value,{timeZone:o,roundUp:!0}):null,l=Qt(a,s,n,r,o);a||i||(l.isInvalid=!0,l.errors.push(Kt("Value is required.")));const h=Qt(c,s,n,r,o);return c||i||(h.isInvalid=!0,h.errors.push(Kt("Value is required."))),a&&c&&c.isBefore(a)&&(l.isInvalid=!0,l.errors.push(Kt('"From" can\'t be after "To".'))),{isInvalid:l.isInvalid||h.isInvalid,startValidationResult:l,endValidationResult:h}}const Jt=l("relative-range-date-picker-dialog");function ei({props:e,state:t,open:i,onClose:n,focusInput:r,isMobile:o,anchorRef:a,className:c}){return o?(0,s.jsx)(F.c,{visible:i,onClose:n,contentClassName:Jt("content",{mobile:!0,size:"xl"},c),children:(0,s.jsx)(ti,Object.assign({},e,{size:"xl",state:t,onApply:n}))}):(0,s.jsx)(U.z,{open:i,onEscapeKeyDown:()=>{n(),r()},onClose:n,role:"dialog",anchorRef:a,contentClassName:Jt("content",{size:e.size},c),autoFocus:!0,focusTrap:!0,children:(0,s.jsx)(ti,Object.assign({},e,{state:t,onApply:n}))})}function ti(e){var t,i,r,o,a,c,l;const h=function(e,t){var i,s,r,o;const{withApplyButton:a,allowNullableValues:c}=t,[l,h]=n.useState(null!==(s=null===(i=e.value)||void 0===i?void 0:i.start)&&void 0!==s?s:null),[d,u]=n.useState(null!==(o=null===(r=e.value)||void 0===r?void 0:r.end)&&void 0!==o?o:null),[g,p]=n.useState(e.timeZone),m=a?g:e.timeZone,f=n.useMemo((()=>Zt(l,d,c,t.minValue,t.maxValue,t.isDateUnavailable,m)),[c,d,t.isDateUnavailable,t.maxValue,t.minValue,l,m]);return{start:l,end:d,timeZone:m,setStart:function(i){h(i),a||e.setValue(Xt(i,d,Object.assign(Object.assign({},t),{timeZone:m})),m)},setEnd:function(i){u(i),a||e.setValue(Xt(l,i,Object.assign(Object.assign({},t),{timeZone:m})),m)},setRange:function(i,s){h(i),u(s),a||e.setValue(Xt(i,s,Object.assign(Object.assign({},t),{timeZone:m})),m)},setTimeZone:function(i){p(i),a||e.setValue(Xt(l,d,Object.assign(Object.assign({},t),{timeZone:i})),i)},applyValue:function(){e.setValue(Xt(l,d,Object.assign(Object.assign({},t),{timeZone:m})),m)},isInvalid:f.isInvalid,startValidation:f.startValidationResult,endValidation:f.endValidationResult}}(e.state,e),d=(null===(t=e.placeholderValue)||void 0===t?void 0:t.timeZone(e.state.timeZone))||(0,f.KQ)({timeZone:e.state.timeZone}),u={timeZone:e.state.timeZone,format:e.format,minValue:e.minValue,maxValue:e.maxValue,hasClear:e.allowNullableValues,readOnly:e.readOnly,size:e.size,errorPlacement:"inside"};return(0,s.jsxs)("div",{children:[(0,s.jsxs)("div",{className:Jt("pickers"),children:[(0,s.jsx)(nt,Object.assign({},u,{validationState:(null===(i=h.startValidation)||void 0===i?void 0:i.isInvalid)?"invalid":void 0,errorMessage:(null===(o=null===(r=h.startValidation)||void 0===r?void 0:r.errors)||void 0===o?void 0:o.join("\n"))||Kt("Value is incorrect."),placeholderValue:d.startOf("day"),label:Kt("From"),value:h.start,onUpdate:h.setStart})),(0,s.jsx)(nt,Object.assign({},u,{validationState:(null===(a=h.endValidation)||void 0===a?void 0:a.isInvalid)?"invalid":void 0,errorMessage:(null===(l=null===(c=h.endValidation)||void 0===c?void 0:c.errors)||void 0===l?void 0:l.join("\n"))||Kt("Value is incorrect."),placeholderValue:d.endOf("day"),label:Kt("To"),value:h.end,onUpdate:h.setEnd,roundUp:!0}))]}),e.withApplyButton&&!e.readOnly?(0,s.jsx)(g.$,{disabled:h.isInvalid,size:e.size,onClick:()=>{h.applyValue(),e.onApply()},className:Jt("apply"),width:"max",children:Kt("Apply")}):null,e.withPresets&&!e.readOnly?(0,s.jsx)(It,{size:e.size,presetTabs:e.presetTabs,onChoosePreset:(t,i)=>{h.setRange({type:"relative",value:t},{type:"relative",value:i}),e.withApplyButton||e.onApply()},minValue:e.minValue,docs:e.docs,className:Jt("presets")}):null,e.withZonesList?(0,s.jsx)("div",{className:Jt("zone"),children:(0,s.jsx)(zt,{value:h.timeZone,onUpdate:h.setTimeZone,disabled:e.readOnly,size:e.size})}):null]})}const ii=JSON.parse('{"\\"From\\"":"\\"From\\"","\\"From\\" is required.":"\\"From\\" is required.","\\"To\\"":"\\"To\\"","\\"To\\" is required.":"\\"To\\" is required.","\\"From\\" can\'t be after \\"To\\".":"\\"From\\" can\'t be after \\"To\\".","to":"to"}'),si=JSON.parse('{"\\"From\\"":"\xab\u041e\u0442\xbb","\\"From\\" is required.":"\xab\u041e\u0442\xbb \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e.","\\"To\\"":"\xab\u0414\u043e\xbb","\\"To\\" is required.":"\xab\u0414\u043e\xbb \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e.","\\"From\\" can\'t be after \\"To\\".":"\xab\u041e\u0442\xbb \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u0447\u0435\u043c \xab\u0414\u043e\xbb.","to":"\u0434\u043e"}'),ni=(0,_.N)({en:ii,ru:si},`${c}relative-range-date-picker`);function ri(e){var t,i;const[s,r]=(0,o.P)(e.value,null!==(t=e.defaultValue)&&void 0!==t?t:null),[a,c]=(0,o.P)(e.timeZone,null!==(i=e.defaultTimeZone)&&void 0!==i?i:"default",e.onUpdateTimeZone),l=n.useMemo((()=>function(e,t,i,s,n,r){if(!e)return{isInvalid:!1,errors:[]};const o=e.start?(0,f.bQ)(e.start.value,{timeZone:r}):null,a=e.end?(0,f.bQ)(e.end.value,{timeZone:r,roundUp:!0}):null,c=Qt(o,i,s,n,r,ni('"From"'));o||t||(c.isInvalid=!0,c.errors.push(ni('"From" is required.')));const l=Qt(a,i,s,n,r,ni('"To"'));a||t||(l.isInvalid=!0,l.errors.push(ni('"To" is required.')));o&&a&&a.isBefore(o)&&(c.isInvalid=!0,c.errors.push(ni('"From" can\'t be after "To".')));return{isInvalid:c.isInvalid||l.isInvalid,errors:c.errors.concat(l.errors)}}(s,e.allowNullableValues,e.minValue,e.maxValue,e.isDateUnavailable,a)),[s,e.allowNullableValues,e.isDateUnavailable,e.maxValue,e.minValue,a]);return Object.assign({value:s,timeZone:a,setValue(t,i){var n;r(t),c(i),(s!==t||s&&a!==i)&&(null===(n=e.onUpdate)||void 0===n||n.call(e,t,i))}},l)}const oi=l("relative-range-date-picker");function ai(e){const t=ri(e),i=(0,r.I)(),c=n.useRef(null),l=n.useRef(null),[d,u]=n.useState(!1),[g,p]=(0,o.P)(void 0,!1,e.onOpenChange),{focusWithinProps:m}=(0,a.R)({isDisabled:e.disabled,onFocusWithin:t=>{var i;d||null===(i=e.onFocus)||void 0===i||i.call(e,t)},onBlurWithin:t=>{var i;g||(u(!1),null===(i=e.onBlur)||void 0===i||i.call(e,t))}});return(0,s.jsxs)("div",Object.assign({ref:c},m,{className:oi(null,e.className),style:e.style,children:[(0,s.jsx)(P,{props:e,state:t,open:g,isMobile:i,ref:l,onClick:()=>{e.disabled||g||(u(!0),p(!0))},onKeyDown:t=>{e.disabled||!t.altKey||"ArrowDown"!==t.key&&"ArrowUp"!==t.key||(t.preventDefault(),p(!0))},onClickCalendar:()=>{u(!0),p(!g)},onFocus:()=>{d||(u(!0),p(!0))},onUpdate:i=>{e.readOnly||i||t.setValue(null,"default")}}),(0,s.jsx)(h,{name:e.name,form:e.form,value:t.value,toStringValue:e=>{var t,i;return null!==(i=null===(t=null===e||void 0===e?void 0:e.start)||void 0===t?void 0:t.type)&&void 0!==i?i:""},disabled:e.disabled}),(0,s.jsx)(h,{name:e.name,form:e.form,value:t.value,toStringValue:e=>{var t;return ci(null!==(t=null===e||void 0===e?void 0:e.start)&&void 0!==t?t:null)},disabled:e.disabled}),(0,s.jsx)(h,{name:e.name,form:e.form,value:t.value,toStringValue:e=>{var t,i;return null!==(i=null===(t=null===e||void 0===e?void 0:e.end)||void 0===t?void 0:t.type)&&void 0!==i?i:""},disabled:e.disabled}),(0,s.jsx)(h,{name:e.name,form:e.form,value:t.value,toStringValue:e=>{var t;return ci(null!==(t=null===e||void 0===e?void 0:e.end)&&void 0!==t?t:null)},disabled:e.disabled}),(0,s.jsx)(h,{name:e.name,form:e.form,onReset:e=>{t.setValue(e.value,e.timeZone)},value:{value:t.value,timeZone:t.timeZone},toStringValue:e=>e.timeZone,disabled:e.disabled}),(0,s.jsx)(ei,{state:t,props:e,open:g,onClose:()=>{p(!1)},focusInput:()=>{setTimeout((()=>{var e;null===(e=l.current)||void 0===e||e.focus({preventScroll:!0})}))},anchorRef:c,isMobile:i,className:e.popupClassName})]}))}function ci(e){return e?"relative"===e.type?e.value:e.value.toISOString():""}},23934:(e,t,i)=>{"use strict";var s=i(61850),n=i(92727);const r="clickhouse";(0,s.KV)({id:r,extensions:[],loader:()=>i.e(66397).then(i.bind(i,66397)).then((e=>({conf:e.conf,language:e.language,completions:e.completionLists})))});const o=new s.IK(r,s.bC,s.RQ);n.eo[r]=o;(0,s.KV)({id:"s-expression",extensions:[],loader:()=>i.e(5475).then(i.bind(i,5475))}),n.EN.defineTheme("vs",{base:"vs",inherit:!0,rules:[{token:"string.tablepath",foreground:"338186"},{token:"constant.yql",foreground:"608b4e"},{token:"keyword.type",foreground:"4d932d"},{token:"string.sql",foreground:"a31515"},{token:"support.function",foreground:"7a3e9d"},{token:"constant.other.color",foreground:"7a3e9d"},{token:"comment",foreground:"969896"}],colors:{"editor.lineHighlightBackground":"#EFEFEF"}}),n.EN.defineTheme("vs-dark",{base:"vs-dark",inherit:!0,rules:[{token:"string.tablepath",foreground:"338186"},{token:"constant.yql",foreground:"608b4e"},{token:"storage.type",foreground:"6A8759"},{token:"string.sql",foreground:"ce9178"},{token:"support.function",foreground:"9e7bb0"},{token:"constant.other.color",foreground:"9e7bb0"},{token:"comment",foreground:"969896"}],colors:{"editor.lineHighlightBackground":"#282A2E"}});i(23195);(0,s.KV)({id:"yql_ansi",extensions:[],loader:()=>i.e(19507).then(i.bind(i,19507)).then((e=>({conf:e.conf,language:e.getLanguage({ansi:!0})})))});i(43733)},23971:(e,t,i)=>{"use strict";i.d(t,{Gb:()=>V,Jt:()=>f,hZ:()=>E,mN:()=>Ae,xI:()=>W});var s=i(59284),n=e=>"checkbox"===e.type,r=e=>e instanceof Date,o=e=>null==e;const a=e=>"object"===typeof e;var c=e=>!o(e)&&!Array.isArray(e)&&a(e)&&!r(e),l=e=>c(e)&&e.target?n(e.target)?e.target.checked:e.target.value:e,h=(e,t)=>e.has((e=>e.substring(0,e.search(/\.\d+(\.|$)/))||e)(t)),d=e=>{const t=e.constructor&&e.constructor.prototype;return c(t)&&t.hasOwnProperty("isPrototypeOf")},u="undefined"!==typeof window&&"undefined"!==typeof window.HTMLElement&&"undefined"!==typeof document;function g(e){let t;const i=Array.isArray(e),s="undefined"!==typeof FileList&&e instanceof FileList;if(e instanceof Date)t=new Date(e);else if(e instanceof Set)t=new Set(e);else{if(u&&(e instanceof Blob||s)||!i&&!c(e))return e;if(t=i?[]:{},i||d(e))for(const i in e)e.hasOwnProperty(i)&&(t[i]=g(e[i]));else t=e}return t}var p=e=>Array.isArray(e)?e.filter(Boolean):[],m=e=>void 0===e,f=(e,t,i)=>{if(!t||!c(e))return i;const s=p(t.split(/[,[\].]+?/)).reduce(((e,t)=>o(e)?e:e[t]),e);return m(s)||s===e?m(e[t])?i:e[t]:s},_=e=>"boolean"===typeof e,v=e=>/^\w*$/.test(e),C=e=>p(e.replace(/["|']|\]/g,"").split(/\.|\[/)),E=(e,t,i)=>{let s=-1;const n=v(t)?[t]:C(t),r=n.length,o=r-1;for(;++ss.useContext(A);var I=(e,t,i,s=!0)=>{const n={defaultValues:t._defaultValues};for(const r in e)Object.defineProperty(n,r,{get:()=>{const n=r;return t._proxyFormState[n]!==S.all&&(t._proxyFormState[n]=!s||S.all),i&&(i[n]=!0),e[n]}});return n},O=e=>c(e)&&!Object.keys(e).length,D=(e,t,i,s)=>{i(e);const{name:n,...r}=e;return O(r)||Object.keys(r).length>=Object.keys(t).length||Object.keys(r).find((e=>t[e]===(!s||S.all)))},M=e=>Array.isArray(e)?e:[e],P=(e,t,i)=>!e||!t||e===t||M(e).some((e=>e&&(i?e===t:e.startsWith(t)||t.startsWith(e))));function F(e){const t=s.useRef(e);t.current=e,s.useEffect((()=>{const i=!e.disabled&&t.current.subject&&t.current.subject.subscribe({next:t.current.next});return()=>{i&&i.unsubscribe()}}),[e.disabled])}var U=e=>"string"===typeof e,H=(e,t,i,s,n)=>U(e)?(s&&t.watch.add(e),f(i,e,n)):Array.isArray(e)?e.map((e=>(s&&t.watch.add(e),f(i,e)))):(s&&(t.watchAll=!0),i);function B(e){const t=N(),{name:i,disabled:n,control:r=t.control,shouldUnregister:o}=e,a=h(r._names.array,i),c=function(e){const t=N(),{control:i=t.control,name:n,defaultValue:r,disabled:o,exact:a}=e||{},c=s.useRef(n);c.current=n,F({disabled:o,subject:i._subjects.values,next:e=>{P(c.current,e.name,a)&&h(g(H(c.current,i._names,e.values||i._formValues,!1,r)))}});const[l,h]=s.useState(i._getWatch(n,r));return s.useEffect((()=>i._removeUnmounted())),l}({control:r,name:i,defaultValue:f(r._formValues,i,f(r._defaultValues,i,e.defaultValue)),exact:!0}),d=function(e){const t=N(),{control:i=t.control,disabled:n,name:r,exact:o}=e||{},[a,c]=s.useState(i._formState),l=s.useRef(!0),h=s.useRef({isDirty:!1,isLoading:!1,dirtyFields:!1,touchedFields:!1,validatingFields:!1,isValidating:!1,isValid:!1,errors:!1}),d=s.useRef(r);return d.current=r,F({disabled:n,next:e=>l.current&&P(d.current,e.name,o)&&D(e,h.current,i._updateFormState)&&c({...i._formState,...e}),subject:i._subjects.state}),s.useEffect((()=>(l.current=!0,h.current.isValid&&i._updateValid(!0),()=>{l.current=!1})),[i]),s.useMemo((()=>I(a,i,h.current,!1)),[a,i])}({control:r,name:i,exact:!0}),u=s.useRef(r.register(i,{...e.rules,value:c,..._(e.disabled)?{disabled:e.disabled}:{}})),p=s.useMemo((()=>Object.defineProperties({},{invalid:{enumerable:!0,get:()=>!!f(d.errors,i)},isDirty:{enumerable:!0,get:()=>!!f(d.dirtyFields,i)},isTouched:{enumerable:!0,get:()=>!!f(d.touchedFields,i)},isValidating:{enumerable:!0,get:()=>!!f(d.validatingFields,i)},error:{enumerable:!0,get:()=>f(d.errors,i)}})),[d,i]),v=s.useMemo((()=>({name:i,value:c,..._(n)||d.disabled?{disabled:d.disabled||n}:{},onChange:e=>u.current.onChange({target:{value:l(e),name:i},type:b.CHANGE}),onBlur:()=>u.current.onBlur({target:{value:f(r._formValues,i),name:i},type:b.BLUR}),ref:e=>{const t=f(r._fields,i);t&&e&&(t._f.ref={focus:()=>e.focus(),select:()=>e.select(),setCustomValidity:t=>e.setCustomValidity(t),reportValidity:()=>e.reportValidity()})}})),[i,r._formValues,n,d.disabled,c,r._fields]);return s.useEffect((()=>{const e=r._options.shouldUnregister||o,t=(e,t)=>{const i=f(r._fields,e);i&&i._f&&(i._f.mount=t)};if(t(i,!0),e){const e=g(f(r._options.defaultValues,i));E(r._defaultValues,i,e),m(f(r._formValues,i))&&E(r._formValues,i,e)}return!a&&r.register(i),()=>{(a?e&&!r._state.action:e)?r.unregister(i):t(i,!1)}}),[i,r,a,o]),s.useEffect((()=>{r._updateDisabledField({disabled:n,fields:r._fields,name:i})}),[n,i,r]),s.useMemo((()=>({field:v,formState:d,fieldState:p})),[v,d,p])}const W=e=>e.render(B(e));var V=(e,t,i,s,n)=>t?{...i[e],types:{...i[e]&&i[e].types?i[e].types:{},[s]:n||!0}}:{},z=e=>({isOnSubmit:!e||e===S.onSubmit,isOnBlur:e===S.onBlur,isOnChange:e===S.onChange,isOnAll:e===S.all,isOnTouch:e===S.onTouched}),G=(e,t,i)=>!i&&(t.watchAll||t.watch.has(e)||[...t.watch].some((t=>e.startsWith(t)&&/^\.\w+/.test(e.slice(t.length)))));const j=(e,t,i,s)=>{for(const n of i||Object.keys(e)){const i=f(e,n);if(i){const{_f:e,...r}=i;if(e){if(e.refs&&e.refs[0]&&t(e.refs[0],n)&&!s)return!0;if(e.ref&&t(e.ref,e.name)&&!s)return!0;if(j(r,t))break}else if(c(r)&&j(r,t))break}}};var K=(e,t,i)=>{const s=M(f(e,i));return E(s,"root",t[i]),E(e,i,s),e},Y=e=>"file"===e.type,q=e=>"function"===typeof e,$=e=>{if(!u)return!1;const t=e?e.ownerDocument:0;return e instanceof(t&&t.defaultView?t.defaultView.HTMLElement:HTMLElement)},Q=e=>U(e),X=e=>"radio"===e.type,Z=e=>e instanceof RegExp;const J={value:!1,isValid:!1},ee={value:!0,isValid:!0};var te=e=>{if(Array.isArray(e)){if(e.length>1){const t=e.filter((e=>e&&e.checked&&!e.disabled)).map((e=>e.value));return{value:t,isValid:!!t.length}}return e[0].checked&&!e[0].disabled?e[0].attributes&&!m(e[0].attributes.value)?m(e[0].value)||""===e[0].value?ee:{value:e[0].value,isValid:!0}:ee:J}return J};const ie={isValid:!1,value:null};var se=e=>Array.isArray(e)?e.reduce(((e,t)=>t&&t.checked&&!t.disabled?{isValid:!0,value:t.value}:e),ie):ie;function ne(e,t,i="validate"){if(Q(e)||Array.isArray(e)&&e.every(Q)||_(e)&&!e)return{type:i,message:Q(e)?e:"",ref:t}}var re=e=>c(e)&&!Z(e)?e:{value:e,message:""},oe=async(e,t,i,s,r,a)=>{const{ref:l,refs:h,required:d,maxLength:u,minLength:g,min:p,max:v,pattern:C,validate:E,name:b,valueAsNumber:S,mount:A}=e._f,N=f(i,b);if(!A||t.has(b))return{};const I=h?h[0]:l,D=e=>{r&&I.reportValidity&&(I.setCustomValidity(_(e)?"":e||""),I.reportValidity())},M={},P=X(l),F=n(l),H=P||F,B=(S||Y(l))&&m(l.value)&&m(N)||$(l)&&""===l.value||""===N||Array.isArray(N)&&!N.length,W=V.bind(null,b,s,M),z=(e,t,i,s=R,n=L)=>{const r=e?t:i;M[b]={type:e?s:n,message:r,ref:l,...W(e?s:n,r)}};if(a?!Array.isArray(N)||!N.length:d&&(!H&&(B||o(N))||_(N)&&!N||F&&!te(h).isValid||P&&!se(h).isValid)){const{value:e,message:t}=Q(d)?{value:!!d,message:d}:re(d);if(e&&(M[b]={type:x,message:t,ref:I,...W(x,t)},!s))return D(t),M}if(!B&&(!o(p)||!o(v))){let e,t;const i=re(v),n=re(p);if(o(N)||isNaN(N)){const s=l.valueAsDate||new Date(N),r=e=>new Date((new Date).toDateString()+" "+e),o="time"==l.type,a="week"==l.type;U(i.value)&&N&&(e=o?r(N)>r(i.value):a?N>i.value:s>new Date(i.value)),U(n.value)&&N&&(t=o?r(N)i.value),o(n.value)||(t=s+e.value,n=!o(t.value)&&N.length<+t.value;if((i||n)&&(z(i,e.message,t.message),!s))return D(M[b].message),M}if(C&&!B&&U(N)){const{value:e,message:t}=re(C);if(Z(e)&&!N.match(e)&&(M[b]={type:T,message:t,ref:l,...W(T,t)},!s))return D(t),M}if(E)if(q(E)){const e=ne(await E(N,i),I);if(e&&(M[b]={...e,...W(k,e.message)},!s))return D(e.message),M}else if(c(E)){let e={};for(const t in E){if(!O(e)&&!s)break;const n=ne(await E[t](N,i),I,t);n&&(e={...n,...W(t,n.message)},D(n.message),s&&(M[b]=e))}if(!O(e)&&(M[b]={ref:I,...e},!s))return M}return D(!0),M};function ae(e,t){const i=Array.isArray(t)?t:v(t)?[t]:C(t),s=1===i.length?e:function(e,t){const i=t.slice(0,-1).length;let s=0;for(;s{let e=[];return{get observers(){return e},next:t=>{for(const i of e)i.next&&i.next(t)},subscribe:t=>(e.push(t),{unsubscribe:()=>{e=e.filter((e=>e!==t))}}),unsubscribe:()=>{e=[]}}},le=e=>o(e)||!a(e);function he(e,t){if(le(e)||le(t))return e===t;if(r(e)&&r(t))return e.getTime()===t.getTime();const i=Object.keys(e),s=Object.keys(t);if(i.length!==s.length)return!1;for(const n of i){const i=e[n];if(!s.includes(n))return!1;if("ref"!==n){const e=t[n];if(r(i)&&r(e)||c(i)&&c(e)||Array.isArray(i)&&Array.isArray(e)?!he(i,e):i!==e)return!1}}return!0}var de=e=>"select-multiple"===e.type,ue=e=>X(e)||n(e),ge=e=>$(e)&&e.isConnected,pe=e=>{for(const t in e)if(q(e[t]))return!0;return!1};function me(e,t={}){const i=Array.isArray(e);if(c(e)||i)for(const s in e)Array.isArray(e[s])||c(e[s])&&!pe(e[s])?(t[s]=Array.isArray(e[s])?[]:{},me(e[s],t[s])):o(e[s])||(t[s]=!0);return t}function fe(e,t,i){const s=Array.isArray(e);if(c(e)||s)for(const n in e)Array.isArray(e[n])||c(e[n])&&!pe(e[n])?m(t)||le(i[n])?i[n]=Array.isArray(e[n])?me(e[n],[]):{...me(e[n])}:fe(e[n],o(t)?{}:t[n],i[n]):i[n]=!he(e[n],t[n]);return i}var _e=(e,t)=>fe(e,t,me(t)),ve=(e,{valueAsNumber:t,valueAsDate:i,setValueAs:s})=>m(e)?e:t?""===e?NaN:e?+e:e:i&&U(e)?new Date(e):s?s(e):e;function Ce(e){const t=e.ref;return Y(t)?t.files:X(t)?se(e.refs).value:de(t)?[...t.selectedOptions].map((({value:e})=>e)):n(t)?te(e.refs).value:ve(m(t.value)?e.ref.value:t.value,e)}var Ee=(e,t,i,s)=>{const n={};for(const r of e){const e=f(t,r);e&&E(n,r,e._f)}return{criteriaMode:i,names:[...e],fields:n,shouldUseNativeValidation:s}},be=e=>m(e)?e:Z(e)?e.source:c(e)?Z(e.value)?e.value.source:e.value:e;const Se="AsyncFunction";var ye=e=>!!e&&!!e.validate&&!!(q(e.validate)&&e.validate.constructor.name===Se||c(e.validate)&&Object.values(e.validate).find((e=>e.constructor.name===Se))),we=e=>e.mount&&(e.required||e.min||e.max||e.maxLength||e.minLength||e.pattern||e.validate);function Re(e,t,i){const s=f(e,i);if(s||v(i))return{error:s,name:i};const n=i.split(".");for(;n.length;){const s=n.join("."),r=f(t,s),o=f(e,s);if(r&&!Array.isArray(r)&&i!==s)return{name:i};if(o&&o.type)return{name:s,error:o};n.pop()}return{name:i}}var Le=(e,t,i,s,n)=>!n.isOnAll&&(!i&&n.isOnTouch?!(t||e):(i?s.isOnBlur:n.isOnBlur)?!e:!(i?s.isOnChange:n.isOnChange)||e),Te=(e,t)=>!p(f(e,t)).length&&ae(e,t);const xe={mode:S.onSubmit,reValidateMode:S.onChange,shouldFocusError:!0};function ke(e={}){let t,i={...xe,...e},s={submitCount:0,isDirty:!1,isLoading:q(i.defaultValues),isValidating:!1,isSubmitted:!1,isSubmitting:!1,isSubmitSuccessful:!1,isValid:!1,touchedFields:{},dirtyFields:{},validatingFields:{},errors:i.errors||{},disabled:i.disabled||!1},a={},d=(c(i.defaultValues)||c(i.values))&&g(i.defaultValues||i.values)||{},v=i.shouldUnregister?{}:g(d),C={action:!1,mount:!1,watch:!1},y={mount:new Set,disabled:new Set,unMount:new Set,array:new Set,watch:new Set},w=0;const R={isDirty:!1,dirtyFields:!1,validatingFields:!1,touchedFields:!1,isValidating:!1,isValid:!1,errors:!1},L={values:ce(),array:ce(),state:ce()},T=z(i.mode),x=z(i.reValidateMode),k=i.criteriaMode===S.all,A=async e=>{if(!i.disabled&&(R.isValid||e)){const e=i.resolver?O((await F()).errors):await B(a,!0);e!==s.isValid&&L.state.next({isValid:e})}},N=(e,t)=>{i.disabled||!R.isValidating&&!R.validatingFields||((e||Array.from(y.mount)).forEach((e=>{e&&(t?E(s.validatingFields,e,t):ae(s.validatingFields,e))})),L.state.next({validatingFields:s.validatingFields,isValidating:!O(s.validatingFields)}))},I=(e,t,i,s)=>{const n=f(a,e);if(n){const r=f(v,e,m(i)?f(d,e):i);m(r)||s&&s.defaultChecked||t?E(v,e,t?r:Ce(n._f)):Q(e,r),C.mount&&A()}},D=(e,t,n,r,o)=>{let c=!1,l=!1;const h={name:e};if(!i.disabled){const i=!!(f(a,e)&&f(a,e)._f&&f(a,e)._f.disabled);if(!n||r){R.isDirty&&(l=s.isDirty,s.isDirty=h.isDirty=W(),c=l!==h.isDirty);const n=i||he(f(d,e),t);l=!(i||!f(s.dirtyFields,e)),n||i?ae(s.dirtyFields,e):E(s.dirtyFields,e,!0),h.dirtyFields=s.dirtyFields,c=c||R.dirtyFields&&l!==!n}if(n){const t=f(s.touchedFields,e);t||(E(s.touchedFields,e,n),h.touchedFields=s.touchedFields,c=c||R.touchedFields&&t!==n)}c&&o&&L.state.next(h)}return c?h:{}},P=(e,n,r,o)=>{const a=f(s.errors,e),c=R.isValid&&_(n)&&s.isValid!==n;var l;if(i.delayError&&r?(l=()=>((e,t)=>{E(s.errors,e,t),L.state.next({errors:s.errors})})(e,r),t=e=>{clearTimeout(w),w=setTimeout(l,e)},t(i.delayError)):(clearTimeout(w),t=null,r?E(s.errors,e,r):ae(s.errors,e)),(r?!he(a,r):a)||!O(o)||c){const t={...o,...c&&_(n)?{isValid:n}:{},errors:s.errors,name:e};s={...s,...t},L.state.next(t)}},F=async e=>{N(e,!0);const t=await i.resolver(v,i.context,Ee(e||y.mount,a,i.criteriaMode,i.shouldUseNativeValidation));return N(e),t},B=async(e,t,n={valid:!0})=>{for(const r in e){const o=e[r];if(o){const{_f:e,...a}=o;if(e){const a=y.array.has(e.name),c=o._f&&ye(o._f);c&&R.validatingFields&&N([r],!0);const l=await oe(o,y.disabled,v,k,i.shouldUseNativeValidation&&!t,a);if(c&&R.validatingFields&&N([r]),l[e.name]&&(n.valid=!1,t))break;!t&&(f(l,e.name)?a?K(s.errors,l,e.name):E(s.errors,e.name,l[e.name]):ae(s.errors,e.name))}!O(a)&&await B(a,t,n)}}return n.valid},W=(e,t)=>!i.disabled&&(e&&t&&E(v,e,t),!he(ie(),d)),V=(e,t,i)=>H(e,y,{...C.mount?v:m(t)?d:U(e)?{[e]:t}:t},i,t),Q=(e,t,i={})=>{const s=f(a,e);let r=t;if(s){const i=s._f;i&&(!i.disabled&&E(v,e,ve(t,i)),r=$(i.ref)&&o(t)?"":t,de(i.ref)?[...i.ref.options].forEach((e=>e.selected=r.includes(e.value))):i.refs?n(i.ref)?i.refs.length>1?i.refs.forEach((e=>(!e.defaultChecked||!e.disabled)&&(e.checked=Array.isArray(r)?!!r.find((t=>t===e.value)):r===e.value))):i.refs[0]&&(i.refs[0].checked=!!r):i.refs.forEach((e=>e.checked=e.value===r)):Y(i.ref)?i.ref.value="":(i.ref.value=r,i.ref.type||L.values.next({name:e,values:{...v}})))}(i.shouldDirty||i.shouldTouch)&&D(e,r,i.shouldTouch,i.shouldDirty,!0),i.shouldValidate&&te(e)},X=(e,t,i)=>{for(const s in t){const n=t[s],o=`${e}.${s}`,l=f(a,o);(y.array.has(e)||c(n)||l&&!l._f)&&!r(n)?X(o,n,i):Q(o,n,i)}},Z=(e,t,i={})=>{const n=f(a,e),r=y.array.has(e),c=g(t);E(v,e,c),r?(L.array.next({name:e,values:{...v}}),(R.isDirty||R.dirtyFields)&&i.shouldDirty&&L.state.next({name:e,dirtyFields:_e(d,v),isDirty:W(e,c)})):!n||n._f||o(c)?Q(e,c,i):X(e,c,i),G(e,y)&&L.state.next({...s}),L.values.next({name:C.mount?e:void 0,values:{...v}})},J=async e=>{C.mount=!0;const n=e.target;let o=n.name,c=!0;const h=f(a,o),d=e=>{c=Number.isNaN(e)||r(e)&&isNaN(e.getTime())||he(e,f(v,o,e))};if(h){let r,u;const g=n.type?Ce(h._f):l(e),p=e.type===b.BLUR||e.type===b.FOCUS_OUT,m=!we(h._f)&&!i.resolver&&!f(s.errors,o)&&!h._f.deps||Le(p,f(s.touchedFields,o),s.isSubmitted,x,T),_=G(o,y,p);E(v,o,g),p?(h._f.onBlur&&h._f.onBlur(e),t&&t(0)):h._f.onChange&&h._f.onChange(e);const C=D(o,g,p,!1),S=!O(C)||_;if(!p&&L.values.next({name:o,type:e.type,values:{...v}}),m)return R.isValid&&("onBlur"===i.mode&&p?A():p||A()),S&&L.state.next({name:o,..._?{}:C});if(!p&&_&&L.state.next({...s}),i.resolver){const{errors:e}=await F([o]);if(d(g),c){const t=Re(s.errors,a,o),i=Re(e,a,t.name||o);r=i.error,o=i.name,u=O(e)}}else N([o],!0),r=(await oe(h,y.disabled,v,k,i.shouldUseNativeValidation))[o],N([o]),d(g),c&&(r?u=!1:R.isValid&&(u=await B(a,!0)));c&&(h._f.deps&&te(h._f.deps),P(o,u,r,C))}},ee=(e,t)=>{if(f(s.errors,t)&&e.focus)return e.focus(),1},te=async(e,t={})=>{let n,r;const o=M(e);if(i.resolver){const t=await(async e=>{const{errors:t}=await F(e);if(e)for(const i of e){const e=f(t,i);e?E(s.errors,i,e):ae(s.errors,i)}else s.errors=t;return t})(m(e)?e:o);n=O(t),r=e?!o.some((e=>f(t,e))):n}else e?(r=(await Promise.all(o.map((async e=>{const t=f(a,e);return await B(t&&t._f?{[e]:t}:t)})))).every(Boolean),(r||s.isValid)&&A()):r=n=await B(a);return L.state.next({...!U(e)||R.isValid&&n!==s.isValid?{}:{name:e},...i.resolver||!e?{isValid:n}:{},errors:s.errors}),t.shouldFocus&&!r&&j(a,ee,e?o:y.mount),r},ie=e=>{const t={...C.mount?v:d};return m(e)?t:U(e)?f(t,e):e.map((e=>f(t,e)))},se=(e,t)=>({invalid:!!f((t||s).errors,e),isDirty:!!f((t||s).dirtyFields,e),error:f((t||s).errors,e),isValidating:!!f(s.validatingFields,e),isTouched:!!f((t||s).touchedFields,e)}),ne=(e,t,i)=>{const n=(f(a,e,{_f:{}})._f||{}).ref,r=f(s.errors,e)||{},{ref:o,message:c,type:l,...h}=r;E(s.errors,e,{...h,...t,ref:n}),L.state.next({name:e,errors:s.errors,isValid:!1}),i&&i.shouldFocus&&n&&n.focus&&n.focus()},re=(e,t={})=>{for(const n of e?M(e):y.mount)y.mount.delete(n),y.array.delete(n),t.keepValue||(ae(a,n),ae(v,n)),!t.keepError&&ae(s.errors,n),!t.keepDirty&&ae(s.dirtyFields,n),!t.keepTouched&&ae(s.touchedFields,n),!t.keepIsValidating&&ae(s.validatingFields,n),!i.shouldUnregister&&!t.keepDefaultValue&&ae(d,n);L.values.next({values:{...v}}),L.state.next({...s,...t.keepDirty?{isDirty:W()}:{}}),!t.keepIsValid&&A()},le=({disabled:e,name:t,field:i,fields:s})=>{(_(e)&&C.mount||e||y.disabled.has(t))&&(e?y.disabled.add(t):y.disabled.delete(t),D(t,Ce(i?i._f:f(s,t)._f),!1,!1,!0))},pe=(e,t={})=>{let s=f(a,e);const n=_(t.disabled)||_(i.disabled);return E(a,e,{...s||{},_f:{...s&&s._f?s._f:{ref:{name:e}},name:e,mount:!0,...t}}),y.mount.add(e),s?le({field:s,disabled:_(t.disabled)?t.disabled:i.disabled,name:e}):I(e,!0,t.value),{...n?{disabled:t.disabled||i.disabled}:{},...i.progressive?{required:!!t.required,min:be(t.min),max:be(t.max),minLength:be(t.minLength),maxLength:be(t.maxLength),pattern:be(t.pattern)}:{},name:e,onChange:J,onBlur:J,ref:n=>{if(n){pe(e,t),s=f(a,e);const i=m(n.value)&&n.querySelectorAll&&n.querySelectorAll("input,select,textarea")[0]||n,r=ue(i),o=s._f.refs||[];if(r?o.find((e=>e===i)):i===s._f.ref)return;E(a,e,{_f:{...s._f,...r?{refs:[...o.filter(ge),i,...Array.isArray(f(d,e))?[{}]:[]],ref:{type:i.type,name:e}}:{ref:i}}}),I(e,!1,void 0,i)}else s=f(a,e,{}),s._f&&(s._f.mount=!1),(i.shouldUnregister||t.shouldUnregister)&&(!h(y.array,e)||!C.action)&&y.unMount.add(e)}}},me=()=>i.shouldFocusError&&j(a,ee,y.mount),fe=(e,t)=>async n=>{let r;n&&(n.preventDefault&&n.preventDefault(),n.persist&&n.persist());let o=g(v);if(y.disabled.size)for(const e of y.disabled)E(o,e,void 0);if(L.state.next({isSubmitting:!0}),i.resolver){const{errors:e,values:t}=await F();s.errors=e,o=t}else await B(a);if(ae(s.errors,"root"),O(s.errors)){L.state.next({errors:{}});try{await e(o,n)}catch(c){r=c}}else t&&await t({...s.errors},n),me(),setTimeout(me);if(L.state.next({isSubmitted:!0,isSubmitting:!1,isSubmitSuccessful:O(s.errors)&&!r,submitCount:s.submitCount+1,errors:s.errors}),r)throw r},Se=(e,t={})=>{const n=e?g(e):d,r=g(n),o=O(e),c=o?d:r;if(t.keepDefaultValues||(d=n),!t.keepValues){if(t.keepDirtyValues){const e=new Set([...y.mount,...Object.keys(_e(d,v))]);for(const t of Array.from(e))f(s.dirtyFields,t)?E(c,t,f(v,t)):Z(t,f(c,t))}else{if(u&&m(e))for(const e of y.mount){const t=f(a,e);if(t&&t._f){const e=Array.isArray(t._f.refs)?t._f.refs[0]:t._f.ref;if($(e)){const t=e.closest("form");if(t){t.reset();break}}}}a={}}v=i.shouldUnregister?t.keepDefaultValues?g(d):{}:g(c),L.array.next({values:{...c}}),L.values.next({values:{...c}})}y={mount:t.keepDirtyValues?y.mount:new Set,unMount:new Set,array:new Set,disabled:new Set,watch:new Set,watchAll:!1,focus:""},C.mount=!R.isValid||!!t.keepIsValid||!!t.keepDirtyValues,C.watch=!!i.shouldUnregister,L.state.next({submitCount:t.keepSubmitCount?s.submitCount:0,isDirty:!o&&(t.keepDirty?s.isDirty:!(!t.keepDefaultValues||he(e,d))),isSubmitted:!!t.keepIsSubmitted&&s.isSubmitted,dirtyFields:o?{}:t.keepDirtyValues?t.keepDefaultValues&&v?_e(d,v):s.dirtyFields:t.keepDefaultValues&&e?_e(d,e):t.keepDirty?s.dirtyFields:{},touchedFields:t.keepTouched?s.touchedFields:{},errors:t.keepErrors?s.errors:{},isSubmitSuccessful:!!t.keepIsSubmitSuccessful&&s.isSubmitSuccessful,isSubmitting:!1})},ke=(e,t)=>Se(q(e)?e(v):e,t);return{control:{register:pe,unregister:re,getFieldState:se,handleSubmit:fe,setError:ne,_executeSchema:F,_getWatch:V,_getDirty:W,_updateValid:A,_removeUnmounted:()=>{for(const e of y.unMount){const t=f(a,e);t&&(t._f.refs?t._f.refs.every((e=>!ge(e))):!ge(t._f.ref))&&re(e)}y.unMount=new Set},_updateFieldArray:(e,t=[],n,r,o=!0,c=!0)=>{if(r&&n&&!i.disabled){if(C.action=!0,c&&Array.isArray(f(a,e))){const t=n(f(a,e),r.argA,r.argB);o&&E(a,e,t)}if(c&&Array.isArray(f(s.errors,e))){const t=n(f(s.errors,e),r.argA,r.argB);o&&E(s.errors,e,t),Te(s.errors,e)}if(R.touchedFields&&c&&Array.isArray(f(s.touchedFields,e))){const t=n(f(s.touchedFields,e),r.argA,r.argB);o&&E(s.touchedFields,e,t)}R.dirtyFields&&(s.dirtyFields=_e(d,v)),L.state.next({name:e,isDirty:W(e,t),dirtyFields:s.dirtyFields,errors:s.errors,isValid:s.isValid})}else E(v,e,t)},_updateDisabledField:le,_getFieldArray:e=>p(f(C.mount?v:d,e,i.shouldUnregister?f(d,e,[]):[])),_reset:Se,_resetDefaultValues:()=>q(i.defaultValues)&&i.defaultValues().then((e=>{ke(e,i.resetOptions),L.state.next({isLoading:!1})})),_updateFormState:e=>{s={...s,...e}},_disableForm:e=>{_(e)&&(L.state.next({disabled:e}),j(a,((t,i)=>{const s=f(a,i);s&&(t.disabled=s._f.disabled||e,Array.isArray(s._f.refs)&&s._f.refs.forEach((t=>{t.disabled=s._f.disabled||e})))}),0,!1))},_subjects:L,_proxyFormState:R,_setErrors:e=>{s.errors=e,L.state.next({errors:s.errors,isValid:!1})},get _fields(){return a},get _formValues(){return v},get _state(){return C},set _state(e){C=e},get _defaultValues(){return d},get _names(){return y},set _names(e){y=e},get _formState(){return s},set _formState(e){s=e},get _options(){return i},set _options(e){i={...i,...e}}},trigger:te,register:pe,handleSubmit:fe,watch:(e,t)=>q(e)?L.values.subscribe({next:i=>e(V(void 0,t),i)}):V(e,t,!0),setValue:Z,getValues:ie,reset:ke,resetField:(e,t={})=>{f(a,e)&&(m(t.defaultValue)?Z(e,g(f(d,e))):(Z(e,t.defaultValue),E(d,e,g(t.defaultValue))),t.keepTouched||ae(s.touchedFields,e),t.keepDirty||(ae(s.dirtyFields,e),s.isDirty=t.defaultValue?W(e,g(f(d,e))):W()),t.keepError||(ae(s.errors,e),R.isValid&&A()),L.state.next({...s}))},clearErrors:e=>{e&&M(e).forEach((e=>ae(s.errors,e))),L.state.next({errors:e?s.errors:{}})},unregister:re,setError:ne,setFocus:(e,t={})=>{const i=f(a,e),s=i&&i._f;if(s){const e=s.refs?s.refs[0]:s.ref;e.focus&&(e.focus(),t.shouldSelect&&q(e.select)&&e.select())}},getFieldState:se}}function Ae(e={}){const t=s.useRef(void 0),i=s.useRef(void 0),[n,r]=s.useState({isDirty:!1,isValidating:!1,isLoading:q(e.defaultValues),isSubmitted:!1,isSubmitting:!1,isSubmitSuccessful:!1,isValid:!1,submitCount:0,dirtyFields:{},touchedFields:{},validatingFields:{},errors:e.errors||{},disabled:e.disabled||!1,defaultValues:q(e.defaultValues)?void 0:e.defaultValues});t.current||(t.current={...ke(e),formState:n});const o=t.current.control;return o._options=e,F({subject:o._subjects.state,next:e=>{D(e,o._proxyFormState,o._updateFormState,!0)&&r({...o._formState})}}),s.useEffect((()=>o._disableForm(e.disabled)),[o,e.disabled]),s.useEffect((()=>{if(o._proxyFormState.isDirty){const e=o._getDirty();e!==n.isDirty&&o._subjects.state.next({isDirty:e})}}),[o,n.isDirty]),s.useEffect((()=>{e.values&&!he(e.values,i.current)?(o._reset(e.values,o._options.resetOptions),i.current=e.values,r((e=>({...e})))):o._resetDefaultValues()}),[e.values,o]),s.useEffect((()=>{e.errors&&o._setErrors(e.errors)}),[e.errors,o]),s.useEffect((()=>{o._state.mount||(o._updateValid(),o._state.mount=!0),o._state.watch&&(o._state.watch=!1,o._subjects.state.next({...o._formState})),o._removeUnmounted()})),s.useEffect((()=>{e.shouldUnregister&&o._subjects.values.next({values:o._getWatch()})}),[e.shouldUnregister,o]),t.current.formState=I(n,o),t.current}},24152:(e,t,i)=>{"use strict";i.d(t,{IF:()=>C});var s,n,r=i(80781),o=Object.defineProperty,a=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,l=Object.prototype.hasOwnProperty,h=(e,t,i,s)=>{if(t&&"object"===typeof t||"function"===typeof t)for(let n of c(t))l.call(e,n)||n===i||o(e,n,{get:()=>t[n],enumerable:!(s=a(t,n))||s.enumerable});return e},d={};h(d,s=r,"default"),n&&h(n,s,"default");var u=(e=>(e[e.None=0]="None",e[e.CommonJS=1]="CommonJS",e[e.AMD=2]="AMD",e[e.UMD=3]="UMD",e[e.System=4]="System",e[e.ES2015=5]="ES2015",e[e.ESNext=99]="ESNext",e))(u||{}),g=(e=>(e[e.None=0]="None",e[e.Preserve=1]="Preserve",e[e.React=2]="React",e[e.ReactNative=3]="ReactNative",e[e.ReactJSX=4]="ReactJSX",e[e.ReactJSXDev=5]="ReactJSXDev",e))(g||{}),p=(e=>(e[e.CarriageReturnLineFeed=0]="CarriageReturnLineFeed",e[e.LineFeed=1]="LineFeed",e))(p||{}),m=(e=>(e[e.ES3=0]="ES3",e[e.ES5=1]="ES5",e[e.ES2015=2]="ES2015",e[e.ES2016=3]="ES2016",e[e.ES2017=4]="ES2017",e[e.ES2018=5]="ES2018",e[e.ES2019=6]="ES2019",e[e.ES2020=7]="ES2020",e[e.ESNext=99]="ESNext",e[e.JSON=100]="JSON",e[e.Latest=99]="Latest",e))(m||{}),f=(e=>(e[e.Classic=1]="Classic",e[e.NodeJs=2]="NodeJs",e))(f||{}),_=class{constructor(e,t,i,s,n){this._onDidChange=new d.Emitter,this._onDidExtraLibsChange=new d.Emitter,this._extraLibs=Object.create(null),this._removedExtraLibs=Object.create(null),this._eagerModelSync=!1,this.setCompilerOptions(e),this.setDiagnosticsOptions(t),this.setWorkerOptions(i),this.setInlayHintsOptions(s),this.setModeConfiguration(n),this._onDidExtraLibsChangeTimeout=-1}get onDidChange(){return this._onDidChange.event}get onDidExtraLibsChange(){return this._onDidExtraLibsChange.event}get modeConfiguration(){return this._modeConfiguration}get workerOptions(){return this._workerOptions}get inlayHintsOptions(){return this._inlayHintsOptions}getExtraLibs(){return this._extraLibs}addExtraLib(e,t){let i;if(i="undefined"===typeof t?`ts:extralib-${Math.random().toString(36).substring(2,15)}`:t,this._extraLibs[i]&&this._extraLibs[i].content===e)return{dispose:()=>{}};let s=1;return this._removedExtraLibs[i]&&(s=this._removedExtraLibs[i]+1),this._extraLibs[i]&&(s=this._extraLibs[i].version+1),this._extraLibs[i]={content:e,version:s},this._fireOnDidExtraLibsChangeSoon(),{dispose:()=>{let e=this._extraLibs[i];e&&e.version===s&&(delete this._extraLibs[i],this._removedExtraLibs[i]=s,this._fireOnDidExtraLibsChangeSoon())}}}setExtraLibs(e){for(const t in this._extraLibs)this._removedExtraLibs[t]=this._extraLibs[t].version;if(this._extraLibs=Object.create(null),e&&e.length>0)for(const t of e){const e=t.filePath||`ts:extralib-${Math.random().toString(36).substring(2,15)}`,i=t.content;let s=1;this._removedExtraLibs[e]&&(s=this._removedExtraLibs[e]+1),this._extraLibs[e]={content:i,version:s}}this._fireOnDidExtraLibsChangeSoon()}_fireOnDidExtraLibsChangeSoon(){-1===this._onDidExtraLibsChangeTimeout&&(this._onDidExtraLibsChangeTimeout=window.setTimeout((()=>{this._onDidExtraLibsChangeTimeout=-1,this._onDidExtraLibsChange.fire(void 0)}),0))}getCompilerOptions(){return this._compilerOptions}setCompilerOptions(e){this._compilerOptions=e||Object.create(null),this._onDidChange.fire(void 0)}getDiagnosticsOptions(){return this._diagnosticsOptions}setDiagnosticsOptions(e){this._diagnosticsOptions=e||Object.create(null),this._onDidChange.fire(void 0)}setWorkerOptions(e){this._workerOptions=e||Object.create(null),this._onDidChange.fire(void 0)}setInlayHintsOptions(e){this._inlayHintsOptions=e||Object.create(null),this._onDidChange.fire(void 0)}setMaximumWorkerIdleTime(e){}setEagerModelSync(e){this._eagerModelSync=e}getEagerModelSync(){return this._eagerModelSync}setModeConfiguration(e){this._modeConfiguration=e||Object.create(null),this._onDidChange.fire(void 0)}},v={completionItems:!0,hovers:!0,documentSymbols:!0,definitions:!0,references:!0,documentHighlights:!0,rename:!0,diagnostics:!0,documentRangeFormattingEdits:!0,signatureHelp:!0,onTypeFormattingEdits:!0,codeActions:!0,inlayHints:!0},C=new _({allowNonTsExtensions:!0,target:99},{noSemanticValidation:!1,noSyntaxValidation:!1,onlyVisible:!1},{},{},v),E=new _({allowNonTsExtensions:!0,allowJs:!0,target:99},{noSemanticValidation:!0,noSyntaxValidation:!1,onlyVisible:!1},{},{},v);function b(){return i.e(78979).then(i.bind(i,78979))}d.languages.typescript={ModuleKind:u,JsxEmit:g,NewLineKind:p,ScriptTarget:m,ModuleResolutionKind:f,typescriptVersion:"5.4.5",typescriptDefaults:C,javascriptDefaults:E,getTypeScriptWorker:()=>b().then((e=>e.getTypeScriptWorker())),getJavaScriptWorker:()=>b().then((e=>e.getJavaScriptWorker()))},d.languages.onLanguage("typescript",(()=>b().then((e=>e.setupTypeScript(C))))),d.languages.onLanguage("javascript",(()=>b().then((e=>e.setupJavaScript(E)))))},24329:(e,t,i)=>{"use strict";i.d(t,{R:()=>s});const s={tabSize:4,indentSize:4,insertSpaces:!0,detectIndentation:!0,trimAutoWhitespace:!0,largeFileOptimizations:!0,bracketPairColorizationOptions:{enabled:!0,independentColorPoolPerBracketType:!1}}},24410:(e,t,i)=>{var s=i(20011);e.exports=function(e){return s(e)?void 0:e}},24520:(e,t,i)=>{"use strict";i.d(t,{L:()=>s});const s=(0,i(63591).u1)("themeService")},24853:(e,t,i)=>{"use strict";i.d(t,{A:()=>o});var s,n=i(59284);function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t{"use strict";i.d(t,{Fo:()=>u,YM:()=>p,m5:()=>m,uw:()=>a});class s{constructor(){this._keyCodeToStr=[],this._strToKeyCode=Object.create(null)}define(e,t){this._keyCodeToStr[e]=t,this._strToKeyCode[t.toLowerCase()]=e}keyCodeToStr(e){return this._keyCodeToStr[e]}strToKeyCode(e){return this._strToKeyCode[e.toLowerCase()]||0}}const n=new s,r=new s,o=new s,a=new Array(230),c={},l=[],h=Object.create(null),d=Object.create(null),u=[],g=[];for(let f=0;f<=193;f++)u[f]=-1;for(let f=0;f<=132;f++)g[f]=-1;var p;function m(e,t){return(e|(65535&t)<<16>>>0)>>>0}!function(){const e="",t=[[1,0,"None",0,"unknown",0,"VK_UNKNOWN",e,e],[1,1,"Hyper",0,e,0,e,e,e],[1,2,"Super",0,e,0,e,e,e],[1,3,"Fn",0,e,0,e,e,e],[1,4,"FnLock",0,e,0,e,e,e],[1,5,"Suspend",0,e,0,e,e,e],[1,6,"Resume",0,e,0,e,e,e],[1,7,"Turbo",0,e,0,e,e,e],[1,8,"Sleep",0,e,0,"VK_SLEEP",e,e],[1,9,"WakeUp",0,e,0,e,e,e],[0,10,"KeyA",31,"A",65,"VK_A",e,e],[0,11,"KeyB",32,"B",66,"VK_B",e,e],[0,12,"KeyC",33,"C",67,"VK_C",e,e],[0,13,"KeyD",34,"D",68,"VK_D",e,e],[0,14,"KeyE",35,"E",69,"VK_E",e,e],[0,15,"KeyF",36,"F",70,"VK_F",e,e],[0,16,"KeyG",37,"G",71,"VK_G",e,e],[0,17,"KeyH",38,"H",72,"VK_H",e,e],[0,18,"KeyI",39,"I",73,"VK_I",e,e],[0,19,"KeyJ",40,"J",74,"VK_J",e,e],[0,20,"KeyK",41,"K",75,"VK_K",e,e],[0,21,"KeyL",42,"L",76,"VK_L",e,e],[0,22,"KeyM",43,"M",77,"VK_M",e,e],[0,23,"KeyN",44,"N",78,"VK_N",e,e],[0,24,"KeyO",45,"O",79,"VK_O",e,e],[0,25,"KeyP",46,"P",80,"VK_P",e,e],[0,26,"KeyQ",47,"Q",81,"VK_Q",e,e],[0,27,"KeyR",48,"R",82,"VK_R",e,e],[0,28,"KeyS",49,"S",83,"VK_S",e,e],[0,29,"KeyT",50,"T",84,"VK_T",e,e],[0,30,"KeyU",51,"U",85,"VK_U",e,e],[0,31,"KeyV",52,"V",86,"VK_V",e,e],[0,32,"KeyW",53,"W",87,"VK_W",e,e],[0,33,"KeyX",54,"X",88,"VK_X",e,e],[0,34,"KeyY",55,"Y",89,"VK_Y",e,e],[0,35,"KeyZ",56,"Z",90,"VK_Z",e,e],[0,36,"Digit1",22,"1",49,"VK_1",e,e],[0,37,"Digit2",23,"2",50,"VK_2",e,e],[0,38,"Digit3",24,"3",51,"VK_3",e,e],[0,39,"Digit4",25,"4",52,"VK_4",e,e],[0,40,"Digit5",26,"5",53,"VK_5",e,e],[0,41,"Digit6",27,"6",54,"VK_6",e,e],[0,42,"Digit7",28,"7",55,"VK_7",e,e],[0,43,"Digit8",29,"8",56,"VK_8",e,e],[0,44,"Digit9",30,"9",57,"VK_9",e,e],[0,45,"Digit0",21,"0",48,"VK_0",e,e],[1,46,"Enter",3,"Enter",13,"VK_RETURN",e,e],[1,47,"Escape",9,"Escape",27,"VK_ESCAPE",e,e],[1,48,"Backspace",1,"Backspace",8,"VK_BACK",e,e],[1,49,"Tab",2,"Tab",9,"VK_TAB",e,e],[1,50,"Space",10,"Space",32,"VK_SPACE",e,e],[0,51,"Minus",88,"-",189,"VK_OEM_MINUS","-","OEM_MINUS"],[0,52,"Equal",86,"=",187,"VK_OEM_PLUS","=","OEM_PLUS"],[0,53,"BracketLeft",92,"[",219,"VK_OEM_4","[","OEM_4"],[0,54,"BracketRight",94,"]",221,"VK_OEM_6","]","OEM_6"],[0,55,"Backslash",93,"\\",220,"VK_OEM_5","\\","OEM_5"],[0,56,"IntlHash",0,e,0,e,e,e],[0,57,"Semicolon",85,";",186,"VK_OEM_1",";","OEM_1"],[0,58,"Quote",95,"'",222,"VK_OEM_7","'","OEM_7"],[0,59,"Backquote",91,"`",192,"VK_OEM_3","`","OEM_3"],[0,60,"Comma",87,",",188,"VK_OEM_COMMA",",","OEM_COMMA"],[0,61,"Period",89,".",190,"VK_OEM_PERIOD",".","OEM_PERIOD"],[0,62,"Slash",90,"/",191,"VK_OEM_2","/","OEM_2"],[1,63,"CapsLock",8,"CapsLock",20,"VK_CAPITAL",e,e],[1,64,"F1",59,"F1",112,"VK_F1",e,e],[1,65,"F2",60,"F2",113,"VK_F2",e,e],[1,66,"F3",61,"F3",114,"VK_F3",e,e],[1,67,"F4",62,"F4",115,"VK_F4",e,e],[1,68,"F5",63,"F5",116,"VK_F5",e,e],[1,69,"F6",64,"F6",117,"VK_F6",e,e],[1,70,"F7",65,"F7",118,"VK_F7",e,e],[1,71,"F8",66,"F8",119,"VK_F8",e,e],[1,72,"F9",67,"F9",120,"VK_F9",e,e],[1,73,"F10",68,"F10",121,"VK_F10",e,e],[1,74,"F11",69,"F11",122,"VK_F11",e,e],[1,75,"F12",70,"F12",123,"VK_F12",e,e],[1,76,"PrintScreen",0,e,0,e,e,e],[1,77,"ScrollLock",84,"ScrollLock",145,"VK_SCROLL",e,e],[1,78,"Pause",7,"PauseBreak",19,"VK_PAUSE",e,e],[1,79,"Insert",19,"Insert",45,"VK_INSERT",e,e],[1,80,"Home",14,"Home",36,"VK_HOME",e,e],[1,81,"PageUp",11,"PageUp",33,"VK_PRIOR",e,e],[1,82,"Delete",20,"Delete",46,"VK_DELETE",e,e],[1,83,"End",13,"End",35,"VK_END",e,e],[1,84,"PageDown",12,"PageDown",34,"VK_NEXT",e,e],[1,85,"ArrowRight",17,"RightArrow",39,"VK_RIGHT","Right",e],[1,86,"ArrowLeft",15,"LeftArrow",37,"VK_LEFT","Left",e],[1,87,"ArrowDown",18,"DownArrow",40,"VK_DOWN","Down",e],[1,88,"ArrowUp",16,"UpArrow",38,"VK_UP","Up",e],[1,89,"NumLock",83,"NumLock",144,"VK_NUMLOCK",e,e],[1,90,"NumpadDivide",113,"NumPad_Divide",111,"VK_DIVIDE",e,e],[1,91,"NumpadMultiply",108,"NumPad_Multiply",106,"VK_MULTIPLY",e,e],[1,92,"NumpadSubtract",111,"NumPad_Subtract",109,"VK_SUBTRACT",e,e],[1,93,"NumpadAdd",109,"NumPad_Add",107,"VK_ADD",e,e],[1,94,"NumpadEnter",3,e,0,e,e,e],[1,95,"Numpad1",99,"NumPad1",97,"VK_NUMPAD1",e,e],[1,96,"Numpad2",100,"NumPad2",98,"VK_NUMPAD2",e,e],[1,97,"Numpad3",101,"NumPad3",99,"VK_NUMPAD3",e,e],[1,98,"Numpad4",102,"NumPad4",100,"VK_NUMPAD4",e,e],[1,99,"Numpad5",103,"NumPad5",101,"VK_NUMPAD5",e,e],[1,100,"Numpad6",104,"NumPad6",102,"VK_NUMPAD6",e,e],[1,101,"Numpad7",105,"NumPad7",103,"VK_NUMPAD7",e,e],[1,102,"Numpad8",106,"NumPad8",104,"VK_NUMPAD8",e,e],[1,103,"Numpad9",107,"NumPad9",105,"VK_NUMPAD9",e,e],[1,104,"Numpad0",98,"NumPad0",96,"VK_NUMPAD0",e,e],[1,105,"NumpadDecimal",112,"NumPad_Decimal",110,"VK_DECIMAL",e,e],[0,106,"IntlBackslash",97,"OEM_102",226,"VK_OEM_102",e,e],[1,107,"ContextMenu",58,"ContextMenu",93,e,e,e],[1,108,"Power",0,e,0,e,e,e],[1,109,"NumpadEqual",0,e,0,e,e,e],[1,110,"F13",71,"F13",124,"VK_F13",e,e],[1,111,"F14",72,"F14",125,"VK_F14",e,e],[1,112,"F15",73,"F15",126,"VK_F15",e,e],[1,113,"F16",74,"F16",127,"VK_F16",e,e],[1,114,"F17",75,"F17",128,"VK_F17",e,e],[1,115,"F18",76,"F18",129,"VK_F18",e,e],[1,116,"F19",77,"F19",130,"VK_F19",e,e],[1,117,"F20",78,"F20",131,"VK_F20",e,e],[1,118,"F21",79,"F21",132,"VK_F21",e,e],[1,119,"F22",80,"F22",133,"VK_F22",e,e],[1,120,"F23",81,"F23",134,"VK_F23",e,e],[1,121,"F24",82,"F24",135,"VK_F24",e,e],[1,122,"Open",0,e,0,e,e,e],[1,123,"Help",0,e,0,e,e,e],[1,124,"Select",0,e,0,e,e,e],[1,125,"Again",0,e,0,e,e,e],[1,126,"Undo",0,e,0,e,e,e],[1,127,"Cut",0,e,0,e,e,e],[1,128,"Copy",0,e,0,e,e,e],[1,129,"Paste",0,e,0,e,e,e],[1,130,"Find",0,e,0,e,e,e],[1,131,"AudioVolumeMute",117,"AudioVolumeMute",173,"VK_VOLUME_MUTE",e,e],[1,132,"AudioVolumeUp",118,"AudioVolumeUp",175,"VK_VOLUME_UP",e,e],[1,133,"AudioVolumeDown",119,"AudioVolumeDown",174,"VK_VOLUME_DOWN",e,e],[1,134,"NumpadComma",110,"NumPad_Separator",108,"VK_SEPARATOR",e,e],[0,135,"IntlRo",115,"ABNT_C1",193,"VK_ABNT_C1",e,e],[1,136,"KanaMode",0,e,0,e,e,e],[0,137,"IntlYen",0,e,0,e,e,e],[1,138,"Convert",0,e,0,e,e,e],[1,139,"NonConvert",0,e,0,e,e,e],[1,140,"Lang1",0,e,0,e,e,e],[1,141,"Lang2",0,e,0,e,e,e],[1,142,"Lang3",0,e,0,e,e,e],[1,143,"Lang4",0,e,0,e,e,e],[1,144,"Lang5",0,e,0,e,e,e],[1,145,"Abort",0,e,0,e,e,e],[1,146,"Props",0,e,0,e,e,e],[1,147,"NumpadParenLeft",0,e,0,e,e,e],[1,148,"NumpadParenRight",0,e,0,e,e,e],[1,149,"NumpadBackspace",0,e,0,e,e,e],[1,150,"NumpadMemoryStore",0,e,0,e,e,e],[1,151,"NumpadMemoryRecall",0,e,0,e,e,e],[1,152,"NumpadMemoryClear",0,e,0,e,e,e],[1,153,"NumpadMemoryAdd",0,e,0,e,e,e],[1,154,"NumpadMemorySubtract",0,e,0,e,e,e],[1,155,"NumpadClear",131,"Clear",12,"VK_CLEAR",e,e],[1,156,"NumpadClearEntry",0,e,0,e,e,e],[1,0,e,5,"Ctrl",17,"VK_CONTROL",e,e],[1,0,e,4,"Shift",16,"VK_SHIFT",e,e],[1,0,e,6,"Alt",18,"VK_MENU",e,e],[1,0,e,57,"Meta",91,"VK_COMMAND",e,e],[1,157,"ControlLeft",5,e,0,"VK_LCONTROL",e,e],[1,158,"ShiftLeft",4,e,0,"VK_LSHIFT",e,e],[1,159,"AltLeft",6,e,0,"VK_LMENU",e,e],[1,160,"MetaLeft",57,e,0,"VK_LWIN",e,e],[1,161,"ControlRight",5,e,0,"VK_RCONTROL",e,e],[1,162,"ShiftRight",4,e,0,"VK_RSHIFT",e,e],[1,163,"AltRight",6,e,0,"VK_RMENU",e,e],[1,164,"MetaRight",57,e,0,"VK_RWIN",e,e],[1,165,"BrightnessUp",0,e,0,e,e,e],[1,166,"BrightnessDown",0,e,0,e,e,e],[1,167,"MediaPlay",0,e,0,e,e,e],[1,168,"MediaRecord",0,e,0,e,e,e],[1,169,"MediaFastForward",0,e,0,e,e,e],[1,170,"MediaRewind",0,e,0,e,e,e],[1,171,"MediaTrackNext",124,"MediaTrackNext",176,"VK_MEDIA_NEXT_TRACK",e,e],[1,172,"MediaTrackPrevious",125,"MediaTrackPrevious",177,"VK_MEDIA_PREV_TRACK",e,e],[1,173,"MediaStop",126,"MediaStop",178,"VK_MEDIA_STOP",e,e],[1,174,"Eject",0,e,0,e,e,e],[1,175,"MediaPlayPause",127,"MediaPlayPause",179,"VK_MEDIA_PLAY_PAUSE",e,e],[1,176,"MediaSelect",128,"LaunchMediaPlayer",181,"VK_MEDIA_LAUNCH_MEDIA_SELECT",e,e],[1,177,"LaunchMail",129,"LaunchMail",180,"VK_MEDIA_LAUNCH_MAIL",e,e],[1,178,"LaunchApp2",130,"LaunchApp2",183,"VK_MEDIA_LAUNCH_APP2",e,e],[1,179,"LaunchApp1",0,e,0,"VK_MEDIA_LAUNCH_APP1",e,e],[1,180,"SelectTask",0,e,0,e,e,e],[1,181,"LaunchScreenSaver",0,e,0,e,e,e],[1,182,"BrowserSearch",120,"BrowserSearch",170,"VK_BROWSER_SEARCH",e,e],[1,183,"BrowserHome",121,"BrowserHome",172,"VK_BROWSER_HOME",e,e],[1,184,"BrowserBack",122,"BrowserBack",166,"VK_BROWSER_BACK",e,e],[1,185,"BrowserForward",123,"BrowserForward",167,"VK_BROWSER_FORWARD",e,e],[1,186,"BrowserStop",0,e,0,"VK_BROWSER_STOP",e,e],[1,187,"BrowserRefresh",0,e,0,"VK_BROWSER_REFRESH",e,e],[1,188,"BrowserFavorites",0,e,0,"VK_BROWSER_FAVORITES",e,e],[1,189,"ZoomToggle",0,e,0,e,e,e],[1,190,"MailReply",0,e,0,e,e,e],[1,191,"MailForward",0,e,0,e,e,e],[1,192,"MailSend",0,e,0,e,e,e],[1,0,e,114,"KeyInComposition",229,e,e,e],[1,0,e,116,"ABNT_C2",194,"VK_ABNT_C2",e,e],[1,0,e,96,"OEM_8",223,"VK_OEM_8",e,e],[1,0,e,0,e,0,"VK_KANA",e,e],[1,0,e,0,e,0,"VK_HANGUL",e,e],[1,0,e,0,e,0,"VK_JUNJA",e,e],[1,0,e,0,e,0,"VK_FINAL",e,e],[1,0,e,0,e,0,"VK_HANJA",e,e],[1,0,e,0,e,0,"VK_KANJI",e,e],[1,0,e,0,e,0,"VK_CONVERT",e,e],[1,0,e,0,e,0,"VK_NONCONVERT",e,e],[1,0,e,0,e,0,"VK_ACCEPT",e,e],[1,0,e,0,e,0,"VK_MODECHANGE",e,e],[1,0,e,0,e,0,"VK_SELECT",e,e],[1,0,e,0,e,0,"VK_PRINT",e,e],[1,0,e,0,e,0,"VK_EXECUTE",e,e],[1,0,e,0,e,0,"VK_SNAPSHOT",e,e],[1,0,e,0,e,0,"VK_HELP",e,e],[1,0,e,0,e,0,"VK_APPS",e,e],[1,0,e,0,e,0,"VK_PROCESSKEY",e,e],[1,0,e,0,e,0,"VK_PACKET",e,e],[1,0,e,0,e,0,"VK_DBE_SBCSCHAR",e,e],[1,0,e,0,e,0,"VK_DBE_DBCSCHAR",e,e],[1,0,e,0,e,0,"VK_ATTN",e,e],[1,0,e,0,e,0,"VK_CRSEL",e,e],[1,0,e,0,e,0,"VK_EXSEL",e,e],[1,0,e,0,e,0,"VK_EREOF",e,e],[1,0,e,0,e,0,"VK_PLAY",e,e],[1,0,e,0,e,0,"VK_ZOOM",e,e],[1,0,e,0,e,0,"VK_NONAME",e,e],[1,0,e,0,e,0,"VK_PA1",e,e],[1,0,e,0,e,0,"VK_OEM_CLEAR",e,e]],i=[],s=[];for(const p of t){const[e,t,m,f,_,v,C,E,b]=p;if(s[t]||(s[t]=!0,l[t]=m,h[m]=t,d[m.toLowerCase()]=t,e&&(u[t]=f,0!==f&&3!==f&&5!==f&&4!==f&&6!==f&&57!==f&&(g[f]=t))),!i[f]){if(i[f]=!0,!_)throw new Error(`String representation missing for key code ${f} around scan code ${m}`);n.define(f,_),r.define(f,E||_),o.define(f,b||E||_)}v&&(a[v]=f),C&&(c[C]=f)}g[3]=46}(),function(e){e.toString=function(e){return n.keyCodeToStr(e)},e.fromString=function(e){return n.strToKeyCode(e)},e.toUserSettingsUS=function(e){return r.keyCodeToStr(e)},e.toUserSettingsGeneral=function(e){return o.keyCodeToStr(e)},e.fromUserSettings=function(e){return r.strToKeyCode(e)||o.strToKeyCode(e)},e.toElectronAccelerator=function(e){if(e>=98&&e<=113)return null;switch(e){case 16:return"Up";case 18:return"Down";case 15:return"Left";case 17:return"Right"}return n.keyCodeToStr(e)}}(p||(p={}))},25064:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"pascaligo",extensions:[".ligo"],aliases:["Pascaligo","ligo"],loader:()=>i.e(57118).then(i.bind(i,57118))})},25154:(e,t,i)=>{"use strict";i.d(t,{B:()=>s,q:()=>u});var s,n=i(8597),r=i(25893),o=i(25890),a=i(58694),c=i(41234),l=i(5662),h=i(58925),d=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o};!function(e){e.Tap="-monaco-gesturetap",e.Change="-monaco-gesturechange",e.Start="-monaco-gesturestart",e.End="-monaco-gesturesend",e.Contextmenu="-monaco-gesturecontextmenu"}(s||(s={}));class u extends l.jG{static{this.SCROLL_FRICTION=-.005}static{this.HOLD_DELAY=700}static{this.CLEAR_TAP_COUNT_TIME=400}constructor(){super(),this.dispatched=!1,this.targets=new h.w,this.ignoreTargets=new h.w,this.activeTouches={},this.handle=null,this._lastSetTapCountTime=0,this._register(c.Jh.runAndSubscribe(n.Iv,(({window:e,disposables:t})=>{t.add(n.ko(e.document,"touchstart",(e=>this.onTouchStart(e)),{passive:!1})),t.add(n.ko(e.document,"touchend",(t=>this.onTouchEnd(e,t)))),t.add(n.ko(e.document,"touchmove",(e=>this.onTouchMove(e)),{passive:!1}))}),{window:r.G,disposables:this._store}))}static addTarget(e){if(!u.isTouchDevice())return l.jG.None;u.INSTANCE||(u.INSTANCE=(0,l.lC)(new u));const t=u.INSTANCE.targets.push(e);return(0,l.s)(t)}static ignoreTarget(e){if(!u.isTouchDevice())return l.jG.None;u.INSTANCE||(u.INSTANCE=(0,l.lC)(new u));const t=u.INSTANCE.ignoreTargets.push(e);return(0,l.s)(t)}static isTouchDevice(){return"ontouchstart"in r.G||navigator.maxTouchPoints>0}dispose(){this.handle&&(this.handle.dispose(),this.handle=null),super.dispose()}onTouchStart(e){const t=Date.now();this.handle&&(this.handle.dispose(),this.handle=null);for(let i=0,n=e.targetTouches.length;i=u.HOLD_DELAY&&Math.abs(c.initialPageX-o.RT(c.rollingPageX))<30&&Math.abs(c.initialPageY-o.RT(c.rollingPageY))<30){const e=this.newGestureEvent(s.Contextmenu,c.initialTarget);e.pageX=o.RT(c.rollingPageX),e.pageY=o.RT(c.rollingPageY),this.dispatchEvent(e)}else if(1===n){const t=o.RT(c.rollingPageX),s=o.RT(c.rollingPageY),n=o.RT(c.rollingTimestamps)-c.rollingTimestamps[0],r=t-c.rollingPageX[0],a=s-c.rollingPageY[0],l=[...this.targets].filter((e=>c.initialTarget instanceof Node&&e.contains(c.initialTarget)));this.inertia(e,l,i,Math.abs(r)/n,r>0?1:-1,t,Math.abs(a)/n,a>0?1:-1,s)}this.dispatchEvent(this.newGestureEvent(s.End,c.initialTarget)),delete this.activeTouches[a.identifier]}this.dispatched&&(t.preventDefault(),t.stopPropagation(),this.dispatched=!1)}newGestureEvent(e,t){const i=document.createEvent("CustomEvent");return i.initEvent(e,!1,!0),i.initialTarget=t,i.tapCount=0,i}dispatchEvent(e){if(e.type===s.Tap){const t=(new Date).getTime();let i=0;i=t-this._lastSetTapCountTime>u.CLEAR_TAP_COUNT_TIME?1:2,this._lastSetTapCountTime=t,e.tapCount=i}else e.type!==s.Change&&e.type!==s.Contextmenu||(this._lastSetTapCountTime=0);if(e.initialTarget instanceof Node){for(const i of this.ignoreTargets)if(i.contains(e.initialTarget))return;const t=[];for(const i of this.targets)if(i.contains(e.initialTarget)){let s=0,n=e.initialTarget;for(;n&&n!==i;)s++,n=n.parentElement;t.push([s,i])}t.sort(((e,t)=>e[0]-t[0]));for(const[i,s]of t)s.dispatchEvent(e),this.dispatched=!0}}inertia(e,t,i,r,o,a,c,l,h){this.handle=n.PG(e,(()=>{const n=Date.now(),d=n-i;let g=0,p=0,m=!0;r+=u.SCROLL_FRICTION*d,c+=u.SCROLL_FRICTION*d,r>0&&(m=!1,g=o*r*d),c>0&&(m=!1,p=l*c*d);const f=this.newGestureEvent(s.Change);f.translationX=g,f.translationY=p,t.forEach((e=>e.dispatchEvent(f))),m||this.inertia(e,t,n,r,o,a+g,c,l,h+p)}))}onTouchMove(e){const t=Date.now();for(let i=0,n=e.changedTouches.length;i3&&(r.rollingPageX.shift(),r.rollingPageY.shift(),r.rollingTimestamps.shift()),r.rollingPageX.push(n.pageX),r.rollingPageY.push(n.pageY),r.rollingTimestamps.push(t)}this.dispatched&&(e.preventDefault(),e.stopPropagation(),this.dispatched=!1)}}d([a.B],u,"isTouchDevice",null)},25521:(e,t,i)=>{"use strict";i.d(t,{Bs:()=>a,d:()=>n});var s=i(91508);class n{constructor(e,t,i,s){this.startColumn=e,this.endColumn=t,this.className=i,this.type=s,this._lineDecorationBrand=void 0}static _equals(e,t){return e.startColumn===t.startColumn&&e.endColumn===t.endColumn&&e.className===t.className&&e.type===t.type}static equalsArr(e,t){const i=e.length;if(i!==t.length)return!1;for(let s=0;s=r||(a[c++]=new n(Math.max(1,l.startColumn-s+1),Math.min(o+1,l.endColumn-s+1),l.className,l.type));return a}static filter(e,t,i,s){if(0===e.length)return[];const r=[];let o=0;for(let a=0,c=e.length;at)continue;if(l.isEmpty()&&(0===c.type||3===c.type))continue;const h=l.startLineNumber===t?l.startColumn:i,d=l.endLineNumber===t?l.endColumn:s;r[o++]=new n(h,d,c.inlineClassName,c.type)}return r}static _typeCompare(e,t){const i=[2,0,1,3];return i[e]-i[t]}static compare(e,t){if(e.startColumn!==t.startColumn)return e.startColumn-t.startColumn;if(e.endColumn!==t.endColumn)return e.endColumn-t.endColumn;const i=n._typeCompare(e.type,t.type);return 0!==i?i:e.className!==t.className?e.className0&&this.stopOffsets[0]0&&t=e){this.stopOffsets.splice(s,0,e),this.classNames.splice(s,0,t),this.metadata.splice(s,0,i);break}this.count++}}class a{static normalize(e,t){if(0===t.length)return[];const i=[],n=new o;let r=0;for(let o=0,a=t.length;o1){const t=e.charCodeAt(c-2);s.pc(t)&&c--}if(l>1){const t=e.charCodeAt(l-2);s.pc(t)&&l--}const u=c-1,g=l-2;r=n.consumeLowerThan(u,r,i),0===n.count&&(r=u),n.insert(g,h,d)}return n.consumeLowerThan(1073741824,r,i),i}}},25533:(e,t,i)=>{"use strict";i.d(t,{YagrPlugin:()=>s});const s={type:"yagr",renderer:i(59284).lazy((()=>Promise.all([i.e(81836),i.e(48593)]).then(i.bind(i,81836))))}},25689:(e,t,i)=>{"use strict";i.d(t,{L:()=>n});var s,n,r=i(10350);!function(e){e.isThemeColor=function(e){return e&&"object"===typeof e&&"string"===typeof e.id}}(s||(s={})),function(e){e.iconNameSegment="[A-Za-z0-9]+",e.iconNameExpression="[A-Za-z0-9-]+",e.iconModifierExpression="~[A-Za-z]+",e.iconNameCharacter="[A-Za-z0-9~-]";const t=new RegExp(`^(${e.iconNameExpression})(${e.iconModifierExpression})?$`);function i(e){const s=t.exec(e.id);if(!s)return i(r.W.error);const[,n,o]=s,a=["codicon","codicon-"+n];return o&&a.push("codicon-modifier-"+o.substring(1)),a}e.asClassNameArray=i,e.asClassName=function(e){return i(e).join(" ")},e.asCSSSelector=function(e){return"."+i(e).join(".")},e.isThemeIcon=function(e){return e&&"object"===typeof e&&"string"===typeof e.id&&("undefined"===typeof e.color||s.isThemeColor(e.color))};const n=new RegExp(`^\\$\\((${e.iconNameExpression}(?:${e.iconModifierExpression})?)\\)$`);e.fromString=function(e){const t=n.exec(e);if(!t)return;const[,i]=t;return{id:i}},e.fromId=function(e){return{id:e}},e.modify=function(e,t){let i=e.id;const s=i.lastIndexOf("~");return-1!==s&&(i=i.substring(0,s)),t&&(i=`${i}~${t}`),{id:i}},e.getModifier=function(e){const t=e.id.lastIndexOf("~");if(-1!==t)return e.id.substring(t+1)},e.isEqual=function(e,t){return e.id===t.id&&e.color?.id===t.color?.id}}(n||(n={}))},25783:(e,t,i)=>{e.exports=function(){const e=i(94297),t=[{length:4,reverse:!0},{length:2,reverse:!0},{length:2,reverse:!0},{length:2,reverse:!1},{length:6,reverse:!1}];function s(i){let s=0;const n=[],r=i.$binary?atob(i.$value):i.$value;return t.forEach((function(t){const i=r.substr(s,t.length).split(e.EMPTY_STRING).map((function(t){return e.toPaddedHex(t.charCodeAt(0),2)}));s+=t.length,t.reverse&&i.reverse(),n.push(i.join(e.EMPTY_STRING))})),n.join("-")}return s.isScalar=!0,s}},25791:(e,t,i)=>{"use strict";i.d(t,{I:()=>n});var s=i(36921);class n extends s.LN{constructor(e){super(),this._getContext=e}runAction(e,t){const i=this._getContext();return super.runAction(e,i)}}},25890:(e,t,i)=>{"use strict";function s(e,t=0){return e[e.length-(1+t)]}function n(e){if(0===e.length)throw new Error("Invalid tail call");return[e.slice(0,e.length-1),e[e.length-1]]}function r(e,t,i=(e,t)=>e===t){if(e===t)return!0;if(!e||!t)return!1;if(e.length!==t.length)return!1;for(let s=0,n=e.length;s0))return e;s=e-1}}return-(i+1)}(e.length,(s=>i(e[s],t)))}function c(e,t,i){if((e|=0)>=t.length)throw new TypeError("invalid index");const s=t[Math.floor(t.length*Math.random())],n=[],r=[],o=[];for(const a of t){const e=i(a,s);e<0?n.push(a):e>0?r.push(a):o.push(a)}return e!!e))}function p(e){let t=0;for(let i=0;i0}function _(e,t=e=>e){const i=new Set;return e.filter((e=>{const s=t(e);return!i.has(s)&&(i.add(s),!0)}))}function v(e,t){return e.length>0?e[0]:t}function C(e,t){let i="number"===typeof t?e:0;"number"===typeof t?i=e:(i=0,t=e);const s=[];if(i<=t)for(let n=i;nt;n--)s.push(n);return s}function E(e,t,i){const s=e.slice(0,t),n=e.slice(t);return s.concat(i,n)}function b(e,t){const i=e.indexOf(t);i>-1&&(e.splice(i,1),e.unshift(t))}function S(e,t){const i=e.indexOf(t);i>-1&&(e.splice(i,1),e.push(t))}function y(e,t){for(const i of t)e.push(i)}function w(e){return Array.isArray(e)?e:[e]}function R(e,t,i,s){const n=L(e,t);let r=e.splice(n,i);return void 0===r&&(r=[]),function(e,t,i){const s=L(e,t),n=e.length,r=i.length;e.length=n+r;for(let o=n-1;o>=s;o--)e[o+r]=e[o];for(let o=0;ot(e(i),e(s))}function k(...e){return(t,i)=>{for(const s of e){const e=s(t,i);if(!T.isNeitherLessOrGreaterThan(e))return e}return T.neitherLessOrGreaterThan}}i.d(t,{$z:()=>l,Ct:()=>m,E4:()=>y,EI:()=>f,El:()=>a,Fy:()=>v,Hw:()=>I,RT:()=>s,SK:()=>p,SO:()=>c,TS:()=>N,U9:()=>A,UH:()=>o,V4:()=>R,VE:()=>x,Yc:()=>g,_A:()=>b,_j:()=>w,aI:()=>r,bS:()=>n,c1:()=>D,dM:()=>_,j3:()=>O,kj:()=>u,n:()=>h,nH:()=>k,nK:()=>E,pN:()=>d,r7:()=>S,t9:()=>M,y1:()=>C}),function(e){e.isLessThan=function(e){return e<0},e.isLessThanOrEqual=function(e){return e<=0},e.isGreaterThan=function(e){return e>0},e.isNeitherLessOrGreaterThan=function(e){return 0===e},e.greaterThan=1,e.lessThan=-1,e.neitherLessOrGreaterThan=0}(T||(T={}));const A=(e,t)=>e-t,N=(e,t)=>A(e?1:0,t?1:0);function I(e){return(t,i)=>-e(t,i)}class O{constructor(e){this.items=e,this.firstIdx=0,this.lastIdx=this.items.length-1}get length(){return this.lastIdx-this.firstIdx+1}takeWhile(e){let t=this.firstIdx;for(;t=0&&e(this.items[t]);)t--;const i=t===this.lastIdx?null:this.items.slice(t+1,this.lastIdx+1);return this.lastIdx=t,i}peek(){if(0!==this.length)return this.items[this.firstIdx]}dequeue(){const e=this.items[this.firstIdx];return this.firstIdx++,e}takeCount(e){const t=this.items.slice(this.firstIdx,this.firstIdx+e);return this.firstIdx+=e,t}}class D{static{this.empty=new D((e=>{}))}constructor(e){this.iterate=e}toArray(){const e=[];return this.iterate((t=>(e.push(t),!0))),e}filter(e){return new D((t=>this.iterate((i=>!e(i)||t(i)))))}map(e){return new D((t=>this.iterate((i=>t(e(i))))))}findLast(e){let t;return this.iterate((i=>(e(i)&&(t=i),!0))),t}findLastMaxBy(e){let t,i=!0;return this.iterate((s=>((i||T.isGreaterThan(e(s,t)))&&(i=!1,t=s),!0))),t}}class M{constructor(e){this._indexMap=e}static createSortPermutation(e,t){const i=Array.from(e.keys()).sort(((i,s)=>t(e[i],e[s])));return new M(i)}apply(e){return e.map(((t,i)=>e[this._indexMap[i]]))}inverse(){const e=this._indexMap.slice();for(let t=0;t{"use strict";function s(e,t){const i=e;"number"!==typeof i.vscodeWindowId&&Object.defineProperty(i,"vscodeWindowId",{get:()=>t})}i.d(t,{G:()=>n,y:()=>s});const n=window},25922:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"go",extensions:[".go"],aliases:["Go"],loader:()=>i.e(27148).then(i.bind(i,27148))})},25982:(e,t,i)=>{"use strict";i.d(t,{x:()=>s});class s{static getLanguageId(e){return(255&e)>>>0}static getTokenType(e){return(768&e)>>>8}static containsBalancedBrackets(e){return 0!==(1024&e)}static getFontStyle(e){return(30720&e)>>>11}static getForeground(e){return(16744448&e)>>>15}static getBackground(e){return(4278190080&e)>>>24}static getClassNameFromMetadata(e){let t="mtk"+this.getForeground(e);const i=this.getFontStyle(e);return 1&i&&(t+=" mtki"),2&i&&(t+=" mtkb"),4&i&&(t+=" mtku"),8&i&&(t+=" mtks"),t}static getInlineStyleFromMetadata(e,t){const i=this.getForeground(e),s=this.getFontStyle(e);let n=`color: ${t[i]};`;1&s&&(n+="font-style: italic;"),2&s&&(n+="font-weight: bold;");let r="";return 4&s&&(r+=" underline"),8&s&&(r+=" line-through"),r&&(n+=`text-decoration:${r};`),n}static getPresentationFromMetadata(e){const t=this.getForeground(e),i=this.getFontStyle(e);return{foreground:t,italic:Boolean(1&i),bold:Boolean(2&i),underline:Boolean(4&i),strikethrough:Boolean(8&i)}}}},26195:(e,t,i)=>{"use strict";i.d(t,{A:()=>o});var s,n=i(59284);function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t{e.exports=function(e,t,i){return e===e&&(void 0!==i&&(e=e<=i?e:i),void 0!==t&&(e=e>=t?e:t)),e}},26486:(e,t,i)=>{"use strict";i.d(t,{Io:()=>a,J3:()=>r,Ld:()=>o,Th:()=>l});var s=i(42522),n=i(58925);const r="`~!@#$%^&*()-=+[{]}\\|;:'\",.<>/?";const o=function(e=""){let t="(-?\\d*\\.\\d\\w*)|([^";for(const i of r)e.indexOf(i)>=0||(t+="\\"+i);return t+="\\s]+)",new RegExp(t,"g")}();function a(e){let t=o;if(e&&e instanceof RegExp)if(e.global)t=e;else{let i="g";e.ignoreCase&&(i+="i"),e.multiline&&(i+="m"),e.unicode&&(i+="u"),t=new RegExp(e.source,i)}return t.lastIndex=0,t}const c=new n.w;function l(e,t,i,n,r){if(t=a(t),r||(r=s.f.first(c)),i.length>r.maxLen){let s=e-r.maxLen/2;return s<0?s=0:n+=s,l(e,t,i=i.substring(s,e+r.maxLen/2),n,r)}const o=Date.now(),d=e-1-n;let u=-1,g=null;for(let s=1;!(Date.now()-o>=r.timeBudget);s++){const e=d-r.windowSize*s;t.lastIndex=Math.max(0,e);const n=h(t,i,d,u);if(!n&&g)break;if(g=n,e<=0)break;u=e}if(g){const e={word:g[0],startColumn:n+1+g.index,endColumn:n+1+g.index+g[0].length};return t.lastIndex=0,e}return null}function h(e,t,i,s){let n;for(;n=e.exec(t);){const t=n.index||0;if(t<=i&&e.lastIndex>=i)return n;if(s>0&&t>s)return null}return null}c.unshift({maxLen:1e3,windowSize:15,timeBudget:150})},26656:(e,t,i)=>{"use strict";i.d(t,{Th:()=>m,z8:()=>f});var s=i(78209),n=i(64383),r=i(75326),o=i(79400),a=i(64829),c=i(81674),l=i(89403);function h(e){return e.toString()}class d{static create(e,t){const i=e.getAlternativeVersionId(),s=p(e);return new d(i,i,s,s,t,t,[])}constructor(e,t,i,s,n,r,o){this.beforeVersionId=e,this.afterVersionId=t,this.beforeEOL=i,this.afterEOL=s,this.beforeCursorState=n,this.afterCursorState=r,this.changes=o}append(e,t,i,s,n){t.length>0&&(this.changes=(0,a.x)(this.changes,t)),this.afterEOL=i,this.afterVersionId=s,this.afterCursorState=n}static _writeSelectionsSize(e){return 4+16*(e?e.length:0)}static _writeSelections(e,t,i){if(c.Sw(e,t?t.length:0,i),i+=4,t)for(const s of t)c.Sw(e,s.selectionStartLineNumber,i),i+=4,c.Sw(e,s.selectionStartColumn,i),i+=4,c.Sw(e,s.positionLineNumber,i),i+=4,c.Sw(e,s.positionColumn,i),i+=4;return i}static _readSelections(e,t,i){const s=c.bb(e,t);t+=4;for(let n=0;ne.toString())).join(", ")}matchesResource(e){return(o.r.isUri(this.model)?this.model:this.model.uri).toString()===e.toString()}setModel(e){this.model=e}canAppend(e){return this.model===e&&this._data instanceof d}append(e,t,i,s,n){this._data instanceof d&&this._data.append(e,t,i,s,n)}close(){this._data instanceof d&&(this._data=this._data.serialize())}open(){this._data instanceof d||(this._data=d.deserialize(this._data))}undo(){if(o.r.isUri(this.model))throw new Error("Invalid SingleModelEditStackElement");this._data instanceof d&&(this._data=this._data.serialize());const e=d.deserialize(this._data);this.model._applyUndo(e.changes,e.beforeEOL,e.beforeVersionId,e.beforeCursorState)}redo(){if(o.r.isUri(this.model))throw new Error("Invalid SingleModelEditStackElement");this._data instanceof d&&(this._data=this._data.serialize());const e=d.deserialize(this._data);this.model._applyRedo(e.changes,e.afterEOL,e.afterVersionId,e.afterCursorState)}heapSize(){return this._data instanceof d&&(this._data=this._data.serialize()),this._data.byteLength+168}}class g{get resources(){return this._editStackElementsArr.map((e=>e.resource))}constructor(e,t,i){this.label=e,this.code=t,this.type=1,this._isOpen=!0,this._editStackElementsArr=i.slice(0),this._editStackElementsMap=new Map;for(const s of this._editStackElementsArr){const e=h(s.resource);this._editStackElementsMap.set(e,s)}this._delegate=null}prepareUndoRedo(){if(this._delegate)return this._delegate.prepareUndoRedo(this)}matchesResource(e){const t=h(e);return this._editStackElementsMap.has(t)}setModel(e){const t=h(o.r.isUri(e)?e:e.uri);this._editStackElementsMap.has(t)&&this._editStackElementsMap.get(t).setModel(e)}canAppend(e){if(!this._isOpen)return!1;const t=h(e.uri);if(this._editStackElementsMap.has(t)){return this._editStackElementsMap.get(t).canAppend(e)}return!1}append(e,t,i,s,n){const r=h(e.uri);this._editStackElementsMap.get(r).append(e,t,i,s,n)}close(){this._isOpen=!1}open(){}undo(){this._isOpen=!1;for(const e of this._editStackElementsArr)e.undo()}redo(){for(const e of this._editStackElementsArr)e.redo()}heapSize(e){const t=h(e);if(this._editStackElementsMap.has(t)){return this._editStackElementsMap.get(t).heapSize()}return 0}split(){return this._editStackElementsArr}toString(){const e=[];for(const t of this._editStackElementsArr)e.push(`${(0,l.P8)(t.resource)}: ${t}`);return`{${e.join(", ")}}`}}function p(e){return"\n"===e.getEOL()?0:1}function m(e){return!!e&&(e instanceof u||e instanceof g)}class f{constructor(e,t){this._model=e,this._undoRedoService=t}pushStackElement(){const e=this._undoRedoService.getLastElement(this._model.uri);m(e)&&e.close()}popStackElement(){const e=this._undoRedoService.getLastElement(this._model.uri);m(e)&&e.open()}clear(){this._undoRedoService.removeElements(this._model.uri)}_getOrCreateEditStackElement(e,t){const i=this._undoRedoService.getLastElement(this._model.uri);if(m(i)&&i.canAppend(this._model))return i;const n=new u(s.kg("edit","Typing"),"undoredo.textBufferEdit",this._model,e);return this._undoRedoService.pushElement(n,t),n}pushEOL(e){const t=this._getOrCreateEditStackElement(null,void 0);this._model.setEOL(e),t.append(this._model,[],p(this._model),this._model.getAlternativeVersionId(),null)}pushEditOperation(e,t,i,s){const n=this._getOrCreateEditStackElement(e,s),r=this._model.applyEdits(t,!0),o=f._computeCursorState(i,r),a=r.map(((e,t)=>({index:t,textChange:e.textChange})));return a.sort(((e,t)=>e.textChange.oldPosition===t.textChange.oldPosition?e.index-t.index:e.textChange.oldPosition-t.textChange.oldPosition)),n.append(this._model,a.map((e=>e.textChange)),p(this._model),this._model.getAlternativeVersionId(),o),o}static _computeCursorState(e,t){try{return e?e(t):null}catch(i){return(0,n.dz)(i),null}}}},26685:(e,t,i)=>{"use strict";i.d(t,{AO:()=>w,Dr:()=>R,Hs:()=>k,K4:()=>C,Ls:()=>y,UN:()=>T,YA:()=>L,dU:()=>_,ey:()=>B,h0:()=>x,is:()=>b,kr:()=>S,oi:()=>E,sx:()=>v});var s=i(64383),n=i(91508),r=i(15092),o=i(7936),a=i(71964),c=i(32799),l=i(81782),h=i(36677),d=i(83069),u=i(38566),g=i(17469),p=i(12296),m=i(82365),f=i(63346);class _{static getEdits(e,t,i,s,n){if(!n&&this._isAutoIndentType(e,t,i)){const n=[];for(const o of i){const i=this._findActualIndentationForSelection(e,t,o,s);if(null===i)return;n.push({selection:o,indentation:i})}const r=E.getAutoClosingPairClose(e,t,i,s,!1);return this._getIndentationAndAutoClosingPairEdits(e,t,n,s,r)}}static _isAutoIndentType(e,t,i){if(e.autoIndent<4)return!1;for(let s=0,n=i.length;sU(e,t),unshiftIndent:t=>H(e,t)},e.languageConfigurationService);if(null===n)return null;const r=(0,g.Cw)(t,i.startLineNumber,i.startColumn);return n===e.normalizeIndentation(r)?null:n}static _getIndentationAndAutoClosingPairEdits(e,t,i,s,n){const r=i.map((({selection:i,indentation:r})=>{if(null!==n){const o=this._getEditFromIndentationAndSelection(e,t,r,i,s,!1);return new N(o,i,s,n)}{const n=this._getEditFromIndentationAndSelection(e,t,r,i,s,!0);return F(n.range,n.text,!1)}}));return new c.vY(4,r,{shouldPushStackElementBefore:!0,shouldPushStackElementAfter:!1})}static _getEditFromIndentationAndSelection(e,t,i,s,n,r=!0){const o=s.startLineNumber,a=t.getLineFirstNonWhitespaceColumn(o);let c=e.normalizeIndentation(i);if(0!==a){c+=t.getLineContent(o).substring(a-1,s.startColumn-1)}c+=r?n:"";return{range:new h.Q(o,1,s.endLineNumber,s.endColumn),text:c}}}class v{static getEdits(e,t,i,s,n,r){if(P(t,i,s,n,r))return this._runAutoClosingOvertype(e,s,r)}static _runAutoClosingOvertype(e,t,i){const s=[];for(let n=0,o=t.length;nnew r.iu(new h.Q(e.positionLineNumber,e.positionColumn,e.positionLineNumber,e.positionColumn+1),"",!1)));return new c.vY(4,e,{shouldPushStackElementBefore:!0,shouldPushStackElementAfter:!1})}}}class E{static getEdits(e,t,i,s,n,r){if(!r){const r=this.getAutoClosingPairClose(e,t,i,s,n);if(null!==r)return this._runAutoClosingOpenCharType(i,s,n,r)}}static _runAutoClosingOpenCharType(e,t,i,s){const n=[];for(let r=0,o=e.length;r{const t=e.getPosition();return n?{lineNumber:t.lineNumber,beforeColumn:t.column-s.length,afterColumn:t.column}:{lineNumber:t.lineNumber,beforeColumn:t.column,afterColumn:t.column}})),o=this._findAutoClosingPairOpen(e,t,r.map((e=>new d.y(e.lineNumber,e.beforeColumn))),s);if(!o)return null;let a,h;if((0,c.vG)(s))a=e.autoClosingQuotes,h=e.shouldAutoCloseBefore.quote;else{!!e.blockCommentStartToken&&o.open.includes(e.blockCommentStartToken)?(a=e.autoClosingComments,h=e.shouldAutoCloseBefore.comment):(a=e.autoClosingBrackets,h=e.shouldAutoCloseBefore.bracket)}if("never"===a)return null;const u=this._findContainedAutoClosingPair(e,o),g=u?u.close:"";let m=!0;for(const c of r){const{lineNumber:i,beforeColumn:n,afterColumn:r}=c,d=t.getLineContent(i),u=d.substring(0,n-1),f=d.substring(r-1);if(f.startsWith(g)||(m=!1),f.length>0){const t=f.charAt(0);if(!this._isBeforeClosingBrace(e,f)&&!h(t))return null}if(1===o.open.length&&("'"===s||'"'===s)&&"always"!==a){const t=(0,l.i)(e.wordSeparators,[]);if(u.length>0){const e=u.charCodeAt(u.length-1);if(0===t.get(e))return null}}if(!t.tokenization.isCheapToTokenize(i))return null;t.tokenization.forceTokenization(i);const _=t.tokenization.getLineTokens(i),v=(0,p.BQ)(_,n-1);if(!o.shouldAutoClose(v,n-v.firstCharOffset))return null;const C=o.findNeutralCharacter();if(C){const e=t.tokenization.getTokenTypeIfInsertingCharacter(i,n,C);if(!o.isOK(e))return null}}return m?o.close.substring(0,o.close.length-g.length):o.close}static _findContainedAutoClosingPair(e,t){if(t.open.length<=1)return null;const i=t.close.charAt(t.close.length-1),s=e.autoClosingPairs.autoClosingPairsCloseByEnd.get(i)||[];let n=null;for(const r of s)r.open!==t.open&&t.open.includes(r.open)&&t.close.endsWith(r.close)&&(!n||r.open.length>n.open.length)&&(n=r);return n}static _findAutoClosingPairOpen(e,t,i,s){const n=e.autoClosingPairs.autoClosingPairsOpenByEnd.get(s);if(!n)return null;let r=null;for(const o of n)if(null===r||o.open.length>r.open.length){let e=!0;for(const n of i){if(t.getValueInRange(new h.Q(n.lineNumber,n.column-o.open.length+1,n.lineNumber,n.column))+s!==o.open){e=!1;break}}e&&(r=o)}return r}static _isBeforeClosingBrace(e,t){const i=t.charAt(0),s=e.autoClosingPairs.autoClosingPairsOpenByStart.get(i)||[],n=e.autoClosingPairs.autoClosingPairsCloseByStart.get(i)||[],r=s.some((e=>t.startsWith(e.open))),o=n.some((e=>t.startsWith(e.close)));return!r&&o}}class b{static getEdits(e,t,i,s,n){if(!n&&this._isSurroundSelectionType(e,t,i,s))return this._runSurroundSelectionType(e,i,s)}static _runSurroundSelectionType(e,t,i){const s=[];for(let n=0,r=t.length;n=4){const o=(0,m.MU)(e.autoIndent,t,s,{unshiftIndent:t=>H(e,t),shiftIndent:t=>U(e,t),normalizeIndentation:t=>e.normalizeIndentation(t)},e.languageConfigurationService);if(o){let a=e.visibleColumnFromColumn(t,s.getEndPosition());const c=s.endColumn,l=t.getLineContent(s.endLineNumber),h=n.HG(l);if(s=h>=0?s.setEndPosition(s.endLineNumber,Math.max(s.endColumn,h+1)):s.setEndPosition(s.endLineNumber,t.getLineMaxColumn(s.endLineNumber)),i)return new r.q2(s,"\n"+e.normalizeIndentation(o.afterEnter),!0);{let t=0;return c<=h+1&&(e.insertSpaces||(a=Math.ceil(a/e.indentSize)),t=Math.min(a+1-e.normalizeIndentation(o.afterEnter).length-1,0)),new r.iP(s,"\n"+e.normalizeIndentation(o.afterEnter),0,t,!0)}}}return F(s,"\n"+e.normalizeIndentation(c),i)}static lineInsertBefore(e,t,i){if(null===t||null===i)return[];const s=[];for(let n=0,o=i.length;nthis._compositionType(i,e,n,r,o,a)));return new c.vY(4,l,{shouldPushStackElementBefore:O(e,4),shouldPushStackElementAfter:!1})}static _compositionType(e,t,i,s,n,o){if(!t.isEmpty())return null;const a=t.getPosition(),c=Math.max(1,a.column-s),l=Math.min(e.getLineMaxColumn(a.lineNumber),a.column+n),d=new h.Q(a.lineNumber,c,a.lineNumber,l);return e.getValueInRange(d)===i&&0===o?null:new r.iP(d,i,0,o)}}class T{static getEdits(e,t,i){const s=[];for(let o=0,a=t.length;o1){let s;for(s=i-1;s>=1;s--){const e=t.getLineContent(s);if(n.lT(e)>=0)break}if(s<1)return null;const o=t.getLineMaxColumn(s),a=(0,f.h)(e.autoIndent,t,new h.Q(s,o,s,o),e.languageConfigurationService);a&&(r=a.indentation+a.appendText)}return s&&(s===u.l.Indent&&(r=U(e,r)),s===u.l.Outdent&&(r=H(e,r)),r=e.normalizeIndentation(r)),r||null}static _replaceJumpToNextIndent(e,t,i,s){let n="";const o=i.getStartPosition();if(e.insertSpaces){const i=e.visibleColumnFromColumn(t,o),s=e.indentSize,r=s-i%s;for(let e=0;e2?l.charCodeAt(a.column-2):0)&&h)return!1;if("auto"===e.autoClosingOvertype){let e=!1;for(let t=0,i=s.length;t{"use strict";i.d(t,{ne:()=>ie,Nd:()=>se,Jo:()=>W,WJ:()=>V,dt:()=>ne,uU:()=>oe,Tt:()=>f,yr:()=>H,O:()=>B,WP:()=>p,dE:()=>_,J1:()=>O,or:()=>g});var s=i(74320);function n(e){const t=function(e){if(r=0,a(e,c,4352),r>0)return o.subarray(0,r);if(a(e,l,4449),r>0)return o.subarray(0,r);if(a(e,h,4520),r>0)return o.subarray(0,r);if(a(e,d,12593),r)return o.subarray(0,r);if(e>=44032&&e<=55203){const t=e-44032,i=t%588,s=Math.floor(t/588),n=Math.floor(i/28),u=i%28-1;if(s=0&&(u0)return o.subarray(0,r)}return}(e);if(t&&t.length>0)return new Uint32Array(t)}let r=0;const o=new Uint32Array(10);function a(e,t,i){e>=i&&e>8&&(o[r++]=e>>8&255);e>>16&&(o[r++]=e>>16&255)}(t[e-i])}const c=new Uint8Array([114,82,115,101,69,102,97,113,81,116,84,100,119,87,99,122,120,118,103]),l=new Uint16Array([107,111,105,79,106,112,117,80,104,27496,28520,27752,121,110,27246,28782,27758,98,109,27757,108]),h=new Uint16Array([114,82,29810,115,30579,26483,101,102,29286,24934,29030,29798,30822,30310,26470,97,113,29809,116,84,100,119,99,122,120,118,103]),d=new Uint16Array([114,82,29810,115,30579,26483,101,69,102,29286,24934,29030,29798,30822,30310,26470,97,113,81,29809,116,84,100,119,87,99,122,120,118,103,107,111,105,79,106,112,117,80,104,27496,28520,27752,121,110,27246,28782,27758,98,109,27757,108]);var u=i(91508);function g(...e){return function(t,i){for(let s=0,n=e.length;s0?[{start:0,end:t.length}]:[]:null}function f(e,t){const i=t.toLowerCase().indexOf(e.toLowerCase());return-1===i?null:[{start:i,end:i+e.length}]}function _(e,t){return v(e.toLowerCase(),t.toLowerCase(),0,0)}function v(e,t,i,s){if(i===e.length)return[];if(s===t.length)return null;if(e[i]===t[s]){let n=null;return(n=v(e,t,i+1,s+1))?k({start:s,end:s+1},n):null}return v(e,t,i,s+1)}function C(e){return 97<=e&&e<=122}function E(e){return 65<=e&&e<=90}function b(e){return 48<=e&&e<=57}function S(e){return 32===e||9===e||10===e||13===e}const y=new Set;function w(e){return S(e)||y.has(e)}function R(e,t){return e===t||w(e)&&w(t)}"()[]{}<>`'\"-/;:,.?!".split("").forEach((e=>y.add(e.charCodeAt(0))));const L=new Map;function T(e){if(L.has(e))return L.get(e);let t;const i=n(e);return i&&(t=i),L.set(e,t),t}function x(e){return C(e)||E(e)||b(e)}function k(e,t){return 0===t.length?t=[e]:e.end===t[0].start?t[0].start=e.start:t.unshift(e),t}function A(e,t){for(let i=t;i0&&!x(e.charCodeAt(i-1)))return i}return e.length}function N(e,t,i,s){if(i===e.length)return[];if(s===t.length)return null;if(e[i]!==t[s].toLowerCase())return null;{let n=null,r=s+1;for(n=N(e,t,i+1,s+1);!n&&(r=A(t,r))60&&(t=t.substring(0,60));const i=function(e){let t=0,i=0,s=0,n=0,r=0;for(let o=0;o.2&&t<.8&&s>.6&&n<.2}(i)){if(!function(e){const{upperPercent:t,lowerPercent:i}=e;return 0===i&&t>.6}(i))return null;t=t.toLowerCase()}let s=null,n=0;for(e=e.toLowerCase();n0&&w(e.charCodeAt(i-1)))return i;return e.length}const P=g(p,I,f),F=g(p,I,_),U=new s.qK(1e4);function H(e,t,i=!1){if("string"!==typeof e||"string"!==typeof t)return null;let s=U.get(e);s||(s=new RegExp(u.Bm(e),"i"),U.set(e,s));const n=s.exec(t);return n?[{start:n.index,end:n.index+n[0].length}]:i?F(e,t):P(e,t)}function B(e,t){const i=ne(e,e.toLowerCase(),0,t,t.toLowerCase(),0,{firstMatchCanBeWeak:!0,boostFullMatch:!0});return i?V(i):null}function W(e,t,i,s,n,r){const o=Math.min(13,e.length);for(;i1;s--){const n=e[s]+i,r=t[t.length-1];r&&r.end===n?r.end=n+1:t.push({start:n,end:n+1})}return t}const z=128;function G(){const e=[],t=[];for(let i=0;i<=z;i++)t[i]=0;for(let i=0;i<=z;i++)e.push(t.slice(0));return e}function j(e){const t=[];for(let i=0;i<=e;i++)t[i]=0;return t}const K=j(2*z),Y=j(2*z),q=G(),$=G(),Q=G(),X=!1;function Z(e,t,i,s,n){function r(e,t,i=" "){for(;e.lengthr(e,3))).join("|")}\n`;for(let a=0;a<=i;a++)o+=0===a?" |":`${t[a-1]}|`,o+=e[a].slice(0,n+1).map((e=>r(e.toString(),3))).join("|")+"\n";return o}function J(e,t){if(t<0||t>=e.length)return!1;const i=e.codePointAt(t);switch(i){case 95:case 45:case 46:case 32:case 47:case 92:case 39:case 34:case 58:case 36:case 60:case 62:case 40:case 41:case 91:case 93:case 123:case 125:return!0;case void 0:return!1;default:return!!u.Ss(i)}}function ee(e,t){if(t<0||t>=e.length)return!1;switch(e.charCodeAt(t)){case 32:case 9:return!0;default:return!1}}function te(e,t,i){return t[e]!==i[e]}var ie;!function(e){e.Default=[-100,0],e.isDefault=function(e){return!e||2===e.length&&-100===e[0]&&0===e[1]}}(ie||(ie={}));class se{static{this.default={boostFullMatch:!0,firstMatchCanBeWeak:!1}}constructor(e,t){this.firstMatchCanBeWeak=e,this.boostFullMatch=t}}function ne(e,t,i,s,n,r,o=se.default){const a=e.length>z?z:e.length,c=s.length>z?z:s.length;if(i>=a||r>=c||a-i>c-r)return;if(!function(e,t,i,s,n,r,o=!1){for(;t=i&&a>=s;)n[o]===r[a]&&(Y[o]=a,o--),a--}(a,c,i,r,t,n);let l=1,h=1,d=i,u=r;const g=[!1];for(l=1,d=i;do,v=_?$[l][h-1]+(q[l][h-1]>0?-5:0):0,C=u>o+1&&q[l][h-1]>0,E=C?$[l][h-2]+(q[l][h-2]>0?-5:0):0;if(C&&(!_||E>=v)&&(!m||E>=f))$[l][h]=E,Q[l][h]=3,q[l][h]=0;else if(_&&(!m||v>=f))$[l][h]=v,Q[l][h]=2,q[l][h]=0;else{if(!m)throw new Error("not possible");$[l][h]=f,Q[l][h]=1,q[l][h]=q[l-1][h-1]+1}}}if(X&&function(e,t,i,s){e=e.substr(t),i=i.substr(s),console.log(Z($,e,e.length,i,i.length)),console.log(Z(Q,e,e.length,i,i.length)),console.log(Z(q,e,e.length,i,i.length))}(e,i,s,r),!g[0]&&!o.firstMatchCanBeWeak)return;l--,h--;const p=[$[l][h],r];let m=0,f=0;for(;l>=1;){let e=h;do{const t=Q[l][e];if(3===t)e-=2;else{if(2!==t)break;e-=1}}while(e>=1);m>1&&t[i+l-1]===n[r+h-1]&&!te(e+r-1,s,n)&&m+1>q[l][e]&&(e=h),e===h?m++:m=1,f||(f=e),l--,h=e-1,p.push(h)}c-r===a&&o.boostFullMatch&&(p[0]+=2);const _=f-a;return p[0]-=_,p}function re(e,t,i,s,n,r,o,a,c,l,h){if(t[i]!==r[o])return Number.MIN_SAFE_INTEGER;let d=1,u=!1;return o===i-s?d=e[i]===n[o]?7:5:!te(o,n,r)||0!==o&&te(o-1,n,r)?!J(r,o)||0!==o&&J(r,o-1)?(J(r,o-1)||ee(r,o-1))&&(d=5,u=!0):d=5:(d=e[i]===n[o]?7:5,u=!0),d>1&&i===s&&(h[0]=!0),u||(u=te(o,n,r)||J(r,o-1)||ee(r,o-1)),i===s?o>c&&(d-=u?3:5):d+=l?u?2:0:u?0:1,o+1===a&&(d-=u?3:5),d}function oe(e,t,i,s,n,r,o){return function(e,t,i,s,n,r,o,a){let c=ne(e,t,i,s,n,r,a);if(c&&!o)return c;if(e.length>=3){const t=Math.min(7,e.length-1);for(let o=i+1;oc[0])&&(c=e))}}}return c}(e,t,i,s,n,r,!0,o)}function ae(e,t){if(t+1>=e.length)return;const i=e[t],s=e[t+1];return i!==s?e.slice(0,t)+s+i+e.slice(t+2):void 0}},26746:(e,t,i)=>{"use strict";i.d(t,{D8:()=>I});var s=i(25890),n=i(66782),r=i(86571),o=i(74444),a=i(36677),c=i(68938);class l{constructor(e,t){this.width=e,this.height=t,this.array=[],this.array=new Array(e*t)}get(e,t){return this.array[e+t*this.width]}set(e,t,i){this.array[e+t*this.width]=i}}function h(e){return 32===e||9===e}class d{static{this.chrKeys=new Map}static getKey(e){let t=this.chrKeys.get(e);return void 0===t&&(t=this.chrKeys.size,this.chrKeys.set(e,t)),t}constructor(e,t,i){this.range=e,this.lines=t,this.source=i,this.histogram=[];let s=0;for(let n=e.startLineNumber-1;n0&&l>0&&3===r.get(o-1,l-1)&&(u+=a.get(o-1,l-1)),u+=s?s(o,l):1):u=-1;const g=Math.max(h,d,u);if(g===u){const e=o>0&&l>0?a.get(o-1,l-1):0;a.set(o,l,e+1),r.set(o,l,3)}else g===h?(a.set(o,l,0),r.set(o,l,1)):g===d&&(a.set(o,l,0),r.set(o,l,2));n.set(o,l,g)}const h=[];let d=e.length,u=t.length;function g(e,t){e+1===d&&t+1===u||h.push(new c.$8(new o.L(e+1,d),new o.L(t+1,u))),d=e,u=t}let p=e.length-1,m=t.length-1;for(;p>=0&&m>=0;)3===r.get(p,m)?(g(p,m),p--,m--):1===r.get(p,m)?p--:m--;return g(-1,-1),h.reverse(),new c.SL(h,!1)}}class g{compute(e,t,i=c.uY.instance){if(0===e.length||0===t.length)return c.SL.trivial(e,t);const s=e,n=t;function r(e,t){for(;es.length||u>n.length)continue;const g=r(c,u);l.set(d,g);const m=c===o?h.get(d+1):h.get(d-1);if(h.set(d,g!==c?new p(m,c,u,g-c):m),l.get(d)===s.length&&l.get(d)-d===n.length)break e}}let u=h.get(d);const g=[];let _=s.length,v=n.length;for(;;){const e=u?u.x+u.length:0,t=u?u.y+u.length:0;if(e===_&&t===v||g.push(new c.$8(new o.L(e,_),new o.L(t,v))),!u)break;_=u.x,v=u.y,u=u.prev}return g.reverse(),new c.SL(g,!1)}}class p{constructor(e,t,i,s){this.prev=e,this.x=t,this.y=i,this.length=s}}class m{constructor(){this.positiveArr=new Int32Array(10),this.negativeArr=new Int32Array(10)}get(e){return e<0?(e=-e-1,this.negativeArr[e]):this.positiveArr[e]}set(e,t){if(e<0){if((e=-e-1)>=this.negativeArr.length){const e=this.negativeArr;this.negativeArr=new Int32Array(2*e.length),this.negativeArr.set(e)}this.negativeArr[e]=t}else{if(e>=this.positiveArr.length){const e=this.positiveArr;this.positiveArr=new Int32Array(2*e.length),this.positiveArr.set(e)}this.positiveArr[e]=t}}}class f{constructor(){this.positiveArr=[],this.negativeArr=[]}get(e){return e<0?(e=-e-1,this.negativeArr[e]):this.positiveArr[e]}set(e,t){e<0?(e=-e-1,this.negativeArr[e]=t):this.positiveArr[e]=t}}var _=i(87723),v=i(46041),C=i(74320),E=i(83069);class b{constructor(e,t,i){this.lines=e,this.range=t,this.considerWhitespaceChanges=i,this.elements=[],this.firstElementOffsetByLineIdx=[],this.lineStartOffsets=[],this.trimmedWsLengthsByLineIdx=[],this.firstElementOffsetByLineIdx.push(0);for(let s=this.range.startLineNumber;s<=this.range.endLineNumber;s++){let t=e[s-1],n=0;s===this.range.startLineNumber&&this.range.startColumn>1&&(n=this.range.startColumn-1,t=t.substring(n)),this.lineStartOffsets.push(n);let r=0;if(!i){const e=t.trimStart();r=t.length-e.length,t=e.trimEnd()}this.trimmedWsLengthsByLineIdx.push(r);const o=s===this.range.endLineNumber?Math.min(this.range.endColumn-1-n-r,t.length):t.length;for(let e=0;eString.fromCharCode(e))).join("")}getElement(e){return this.elements[e]}get length(){return this.elements.length}getBoundaryScore(e){const t=R(e>0?this.elements[e-1]:-1),i=R(et<=e)),s=e-this.firstElementOffsetByLineIdx[i];return new E.y(this.range.startLineNumber+i,1+this.lineStartOffsets[i]+s+(0===s&&"left"===t?0:this.trimmedWsLengthsByLineIdx[i]))}translateRange(e){const t=this.translateOffset(e.start,"right"),i=this.translateOffset(e.endExclusive,"left");return i.isBefore(t)?a.Q.fromPositions(i,i):a.Q.fromPositions(t,i)}findWordContaining(e){if(e<0||e>=this.elements.length)return;if(!S(this.elements[e]))return;let t=e;for(;t>0&&S(this.elements[t-1]);)t--;let i=e;for(;it<=e.start))??0,i=(0,v.XP)(this.firstElementOffsetByLineIdx,(t=>e.endExclusive<=t))??this.elements.length;return new o.L(t,i)}}function S(e){return e>=97&&e<=122||e>=65&&e<=90||e>=48&&e<=57}const y={0:0,1:0,2:0,3:10,4:2,5:30,6:3,7:10,8:10};function w(e){return y[e]}function R(e){return 10===e?8:13===e?7:h(e)?6:e>=97&&e<=122?0:e>=65&&e<=90?1:e>=48&&e<=57?2:-1===e?3:44===e||59===e?5:4}function L(e,t,i,n,o,a){let{moves:c,excludedChanges:l}=function(e,t,i,s){const n=[],r=e.filter((e=>e.modified.isEmpty&&e.original.length>=3)).map((e=>new d(e.original,t,e))),o=new Set(e.filter((e=>e.original.isEmpty&&e.modified.length>=3)).map((e=>new d(e.modified,i,e)))),a=new Set;for(const c of r){let e,t=-1;for(const i of o){const s=c.computeSimilarity(i);s>t&&(t=s,e=i)}if(t>.9&&e&&(o.delete(e),n.push(new _.WL(c.range,e.range)),a.add(c.source),a.add(e.source)),!s.isValid())return{moves:n,excludedChanges:a}}return{moves:n,excludedChanges:a}}(e,t,i,a);if(!a.isValid())return[];const h=function(e,t,i,n,o,a){const c=[],l=new C.db;for(const s of e)for(let e=s.original.startLineNumber;ee.modified.startLineNumber),s.U9));for(const s of e){let e=[];for(let t=s.modified.startLineNumber;t{for(const s of e)if(s.originalLineRange.endLineNumberExclusive+1===t.endLineNumberExclusive&&s.modifiedLineRange.endLineNumberExclusive+1===n.endLineNumberExclusive)return s.originalLineRange=new r.M(s.originalLineRange.startLineNumber,t.endLineNumberExclusive),s.modifiedLineRange=new r.M(s.modifiedLineRange.startLineNumber,n.endLineNumberExclusive),void o.push(s);const i={modifiedLineRange:n,originalLineRange:t};h.push(i),o.push(i)})),e=o}if(!a.isValid())return[]}h.sort((0,s.Hw)((0,s.VE)((e=>e.modifiedLineRange.length),s.U9)));const d=new r.S,u=new r.S;for(const s of h){const e=s.modifiedLineRange.startLineNumber-s.originalLineRange.startLineNumber,t=d.subtractFrom(s.modifiedLineRange),i=u.subtractFrom(s.originalLineRange).getWithDelta(e),n=t.getIntersection(i);for(const s of n.ranges){if(s.length<3)continue;const t=s,i=s.delta(-e);c.push(new _.WL(i,t)),d.addRange(t),u.addRange(i)}}c.sort((0,s.VE)((e=>e.original.startLineNumber),s.U9));const g=new v.vJ(e);for(let s=0;se.original.startLineNumber<=t.original.startLineNumber)),l=(0,v.lx)(e,(e=>e.modified.startLineNumber<=t.modified.startLineNumber)),h=Math.max(t.original.startLineNumber-i.original.startLineNumber,t.modified.startLineNumber-l.modified.startLineNumber),p=g.findLastMonotonous((e=>e.original.startLineNumbere.modified.startLineNumbern.length||i>o.length)break;if(d.contains(i)||u.contains(e))break;if(!T(n[e-1],o[i-1],a))break}for(C>0&&(u.addRange(new r.M(t.original.startLineNumber-C,t.original.startLineNumber)),d.addRange(new r.M(t.modified.startLineNumber-C,t.modified.startLineNumber))),E=0;En.length||i>o.length)break;if(d.contains(i)||u.contains(e))break;if(!T(n[e-1],o[i-1],a))break}E>0&&(u.addRange(new r.M(t.original.endLineNumberExclusive,t.original.endLineNumberExclusive+E)),d.addRange(new r.M(t.modified.endLineNumberExclusive,t.modified.endLineNumberExclusive+E))),(C>0||E>0)&&(c[s]=new _.WL(new r.M(t.original.startLineNumber-C,t.original.endLineNumberExclusive+E),new r.M(t.modified.startLineNumber-C,t.modified.endLineNumberExclusive+E)))}return c}(e.filter((e=>!l.has(e))),n,o,t,i,a);return(0,s.E4)(c,h),c=function(e){if(0===e.length)return e;e.sort((0,s.VE)((e=>e.original.startLineNumber),s.U9));const t=[e[0]];for(let i=1;i=0&&o>=0&&r+o<=2?t[t.length-1]=s.join(n):t.push(n)}return t}(c),c=c.filter((e=>{const i=e.original.toOffsetRange().slice(t).map((e=>e.trim()));return i.join("\n").length>=15&&function(e,t){let i=0;for(const s of e)t(s)&&i++;return i}(i,(e=>e.length>=2))>=2})),c=function(e,t){const i=new v.vJ(e);return t=t.filter((t=>(i.findLastMonotonous((e=>e.original.startLineNumbere.modified.startLineNumber300&&t.length>300)return!1;const s=(new g).compute(new b([e],new a.Q(1,1,1,e.length),!1),new b([t],new a.Q(1,1,1,t.length),!1),i);let n=0;const r=c.$8.invert(s.diffs,e.length);for(const a of r)a.seq1Range.forEach((t=>{h(e.charCodeAt(t))||n++}));const o=function(t){let i=0;for(let s=0;st.length?e:t);return n/o>.6&&o>10}var x=i(82518);class k{constructor(e,t){this.trimmedHash=e,this.lines=t}getElement(e){return this.trimmedHash[e]}get length(){return this.trimmedHash.length}getBoundaryScore(e){return 1e3-((0===e?0:A(this.lines[e-1]))+(e===this.lines.length?0:A(this.lines[e])))}getText(e){return this.lines.slice(e.start,e.endExclusive).join("\n")}isStronglyEqual(e,t){return this.lines[e]===this.lines[t]}}function A(e){let t=0;for(;te===t)))return new N.p([],[],!1);if(1===e.length&&0===e[0].length||1===t.length&&0===t[0].length)return new N.p([new _.wm(new r.M(1,e.length+1),new r.M(1,t.length+1),[new _.q6(new a.Q(1,1,e.length,e[e.length-1].length+1),new a.Q(1,1,t.length,t[t.length-1].length+1))])],[],!1);const l=0===i.maxComputationTimeMs?c.uY.instance:new c.aY(i.maxComputationTimeMs),h=!i.ignoreTrimWhitespace,d=new Map;function u(e){let t=d.get(e);return void 0===t&&(t=d.size,d.set(e,t)),t}const g=e.map((e=>u(e.trim()))),p=t.map((e=>u(e.trim()))),m=new k(g,e),f=new k(p,t),v=(()=>m.length+f.length<1700?this.dynamicProgrammingDiffing.compute(m,f,l,((i,s)=>e[i]===t[s]?0===t[s].length?.1:1+Math.log(1+t[s].length):.99)):this.myersDiffingAlgorithm.compute(m,f,l))();let C=v.diffs,E=v.hitTimeout;C=(0,x.NC)(m,f,C),C=(0,x.X5)(m,f,C);const b=[],S=i=>{if(h)for(let s=0;ss.seq1Range.start-y===s.seq2Range.start-w));S(s.seq1Range.start-y),y=s.seq1Range.endExclusive,w=s.seq2Range.endExclusive;const i=this.refineDiff(e,t,s,l,h);i.hitTimeout&&(E=!0);for(const e of i.mappings)b.push(e)}S(e.length-y);const R=O(b,e,t);let L=[];return i.computeMoves&&(L=this.computeMoves(R,e,t,g,p,l,h)),(0,n.Ft)((()=>{function i(e,t){if(e.lineNumber<1||e.lineNumber>t.length)return!1;const i=t[e.lineNumber-1];return!(e.column<1||e.column>i.length+1)}function s(e,t){return!(e.startLineNumber<1||e.startLineNumber>t.length+1)&&!(e.endLineNumberExclusive<1||e.endLineNumberExclusive>t.length+1)}for(const n of R){if(!n.innerChanges)return!1;for(const s of n.innerChanges){if(!(i(s.modifiedRange.getStartPosition(),t)&&i(s.modifiedRange.getEndPosition(),t)&&i(s.originalRange.getStartPosition(),e)&&i(s.originalRange.getEndPosition(),e)))return!1}if(!s(n.modified,t)||!s(n.original,e))return!1}return!0})),new N.p(R,L,E)}computeMoves(e,t,i,s,n,r,o){return L(e,t,i,s,n,r).map((e=>{const s=O(this.refineDiff(t,i,new c.$8(e.original.toOffsetRange(),e.modified.toOffsetRange()),r,o).mappings,t,i,!0);return new N.t(e,s)}))}refineDiff(e,t,i,s,n){var o;const a=(o=i,new _.WL(new r.M(o.seq1Range.start+1,o.seq1Range.endExclusive+1),new r.M(o.seq2Range.start+1,o.seq2Range.endExclusive+1))).toRangeMapping2(e,t),c=new b(e,a.originalRange,n),l=new b(t,a.modifiedRange,n),h=c.length+l.length<500?this.dynamicProgrammingDiffing.compute(c,l,s):this.myersDiffingAlgorithm.compute(c,l,s),d=!1;let u=h.diffs;u=(0,x.NC)(c,l,u),u=(0,x.Lk)(c,l,u),u=(0,x.sq)(c,l,u),u=(0,x.Rl)(c,l,u);const g=u.map((e=>new _.q6(c.translateRange(e.seq1Range),l.translateRange(e.seq2Range))));return{mappings:g,hitTimeout:h.hitTimeout}}}function O(e,t,i,o=!1){const a=[];for(const n of(0,s.n)(e.map((e=>function(e,t,i){let s=0,n=0;1===e.modifiedRange.endColumn&&1===e.originalRange.endColumn&&e.originalRange.startLineNumber+s<=e.originalRange.endLineNumber&&e.modifiedRange.startLineNumber+s<=e.modifiedRange.endLineNumber&&(n=-1);e.modifiedRange.startColumn-1>=i[e.modifiedRange.startLineNumber-1].length&&e.originalRange.startColumn-1>=t[e.originalRange.startLineNumber-1].length&&e.originalRange.startLineNumber<=e.originalRange.endLineNumber+n&&e.modifiedRange.startLineNumber<=e.modifiedRange.endLineNumber+n&&(s=1);const o=new r.M(e.originalRange.startLineNumber+s,e.originalRange.endLineNumber+1+n),a=new r.M(e.modifiedRange.startLineNumber+s,e.modifiedRange.endLineNumber+1+n);return new _.wm(o,a,[e])}(e,t,i))),((e,t)=>e.original.overlapOrTouch(t.original)||e.modified.overlapOrTouch(t.modified)))){const e=n[0],t=n[n.length-1];a.push(new _.wm(e.original.join(t.original),e.modified.join(t.modified),n.map((e=>e.innerChanges[0]))))}return(0,n.Ft)((()=>{if(!o&&a.length>0){if(a[0].modified.startLineNumber!==a[0].original.startLineNumber)return!1;if(i.length-a[a.length-1].modified.endLineNumberExclusive!==t.length-a[a.length-1].original.endLineNumberExclusive)return!1}return(0,n.Xo)(a,((e,t)=>t.original.startLineNumber-e.original.endLineNumberExclusive===t.modified.startLineNumber-e.modified.endLineNumberExclusive&&e.original.endLineNumberExclusive{"use strict";i.r(t),i.d(t,{SemanticTokensStylingService:()=>u});var s=i(5662),n=i(10154),r=i(47612),o=i(18801),a=i(45538),c=i(74243),l=i(14718),h=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},d=function(e,t){return function(i,s){t(i,s,e)}};let u=class extends s.jG{constructor(e,t,i){super(),this._themeService=e,this._logService=t,this._languageService=i,this._caches=new WeakMap,this._register(this._themeService.onDidColorThemeChange((()=>{this._caches=new WeakMap})))}getStyling(e){return this._caches.has(e)||this._caches.set(e,new a.SemanticTokensProviderStyling(e.getLegend(),this._themeService,this._languageService,this._logService)),this._caches.get(e)}};u=h([d(0,r.Gy),d(1,o.rr),d(2,n.L)],u),(0,l.v)(c.ISemanticTokensStylingService,u,1)},27020:(e,t,i)=>{"use strict";var s=i(34918);(0,s.K)({id:"c",extensions:[".c",".h"],aliases:["C","c"],loader:()=>i.e(62042).then(i.bind(i,62042))}),(0,s.K)({id:"cpp",extensions:[".cpp",".cc",".cxx",".hpp",".hh",".hxx"],aliases:["C++","Cpp","cpp"],loader:()=>i.e(62042).then(i.bind(i,62042))})},27195:(e,t,i)=>{"use strict";i.d(t,{D8:()=>_,L:()=>y,Xe:()=>S,ZG:()=>E,ez:()=>v,i1:()=>f,is:()=>m,nI:()=>b,ug:()=>w});var s,n=i(36921),r=i(25689),o=i(41234),a=i(5662),c=i(58925),l=i(50091),h=i(32848),d=i(63591),u=i(59261),g=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},p=function(e,t){return function(i,s){t(i,s,e)}};function m(e){return void 0!==e.command}function f(e){return void 0!==e.submenu}class _{static{this._instances=new Map}static{this.CommandPalette=new _("CommandPalette")}static{this.DebugBreakpointsContext=new _("DebugBreakpointsContext")}static{this.DebugCallStackContext=new _("DebugCallStackContext")}static{this.DebugConsoleContext=new _("DebugConsoleContext")}static{this.DebugVariablesContext=new _("DebugVariablesContext")}static{this.NotebookVariablesContext=new _("NotebookVariablesContext")}static{this.DebugHoverContext=new _("DebugHoverContext")}static{this.DebugWatchContext=new _("DebugWatchContext")}static{this.DebugToolBar=new _("DebugToolBar")}static{this.DebugToolBarStop=new _("DebugToolBarStop")}static{this.DebugCallStackToolbar=new _("DebugCallStackToolbar")}static{this.DebugCreateConfiguration=new _("DebugCreateConfiguration")}static{this.EditorContext=new _("EditorContext")}static{this.SimpleEditorContext=new _("SimpleEditorContext")}static{this.EditorContent=new _("EditorContent")}static{this.EditorLineNumberContext=new _("EditorLineNumberContext")}static{this.EditorContextCopy=new _("EditorContextCopy")}static{this.EditorContextPeek=new _("EditorContextPeek")}static{this.EditorContextShare=new _("EditorContextShare")}static{this.EditorTitle=new _("EditorTitle")}static{this.EditorTitleRun=new _("EditorTitleRun")}static{this.EditorTitleContext=new _("EditorTitleContext")}static{this.EditorTitleContextShare=new _("EditorTitleContextShare")}static{this.EmptyEditorGroup=new _("EmptyEditorGroup")}static{this.EmptyEditorGroupContext=new _("EmptyEditorGroupContext")}static{this.EditorTabsBarContext=new _("EditorTabsBarContext")}static{this.EditorTabsBarShowTabsSubmenu=new _("EditorTabsBarShowTabsSubmenu")}static{this.EditorTabsBarShowTabsZenModeSubmenu=new _("EditorTabsBarShowTabsZenModeSubmenu")}static{this.EditorActionsPositionSubmenu=new _("EditorActionsPositionSubmenu")}static{this.ExplorerContext=new _("ExplorerContext")}static{this.ExplorerContextShare=new _("ExplorerContextShare")}static{this.ExtensionContext=new _("ExtensionContext")}static{this.GlobalActivity=new _("GlobalActivity")}static{this.CommandCenter=new _("CommandCenter")}static{this.CommandCenterCenter=new _("CommandCenterCenter")}static{this.LayoutControlMenuSubmenu=new _("LayoutControlMenuSubmenu")}static{this.LayoutControlMenu=new _("LayoutControlMenu")}static{this.MenubarMainMenu=new _("MenubarMainMenu")}static{this.MenubarAppearanceMenu=new _("MenubarAppearanceMenu")}static{this.MenubarDebugMenu=new _("MenubarDebugMenu")}static{this.MenubarEditMenu=new _("MenubarEditMenu")}static{this.MenubarCopy=new _("MenubarCopy")}static{this.MenubarFileMenu=new _("MenubarFileMenu")}static{this.MenubarGoMenu=new _("MenubarGoMenu")}static{this.MenubarHelpMenu=new _("MenubarHelpMenu")}static{this.MenubarLayoutMenu=new _("MenubarLayoutMenu")}static{this.MenubarNewBreakpointMenu=new _("MenubarNewBreakpointMenu")}static{this.PanelAlignmentMenu=new _("PanelAlignmentMenu")}static{this.PanelPositionMenu=new _("PanelPositionMenu")}static{this.ActivityBarPositionMenu=new _("ActivityBarPositionMenu")}static{this.MenubarPreferencesMenu=new _("MenubarPreferencesMenu")}static{this.MenubarRecentMenu=new _("MenubarRecentMenu")}static{this.MenubarSelectionMenu=new _("MenubarSelectionMenu")}static{this.MenubarShare=new _("MenubarShare")}static{this.MenubarSwitchEditorMenu=new _("MenubarSwitchEditorMenu")}static{this.MenubarSwitchGroupMenu=new _("MenubarSwitchGroupMenu")}static{this.MenubarTerminalMenu=new _("MenubarTerminalMenu")}static{this.MenubarViewMenu=new _("MenubarViewMenu")}static{this.MenubarHomeMenu=new _("MenubarHomeMenu")}static{this.OpenEditorsContext=new _("OpenEditorsContext")}static{this.OpenEditorsContextShare=new _("OpenEditorsContextShare")}static{this.ProblemsPanelContext=new _("ProblemsPanelContext")}static{this.SCMInputBox=new _("SCMInputBox")}static{this.SCMChangesSeparator=new _("SCMChangesSeparator")}static{this.SCMChangesContext=new _("SCMChangesContext")}static{this.SCMIncomingChanges=new _("SCMIncomingChanges")}static{this.SCMIncomingChangesContext=new _("SCMIncomingChangesContext")}static{this.SCMIncomingChangesSetting=new _("SCMIncomingChangesSetting")}static{this.SCMOutgoingChanges=new _("SCMOutgoingChanges")}static{this.SCMOutgoingChangesContext=new _("SCMOutgoingChangesContext")}static{this.SCMOutgoingChangesSetting=new _("SCMOutgoingChangesSetting")}static{this.SCMIncomingChangesAllChangesContext=new _("SCMIncomingChangesAllChangesContext")}static{this.SCMIncomingChangesHistoryItemContext=new _("SCMIncomingChangesHistoryItemContext")}static{this.SCMOutgoingChangesAllChangesContext=new _("SCMOutgoingChangesAllChangesContext")}static{this.SCMOutgoingChangesHistoryItemContext=new _("SCMOutgoingChangesHistoryItemContext")}static{this.SCMChangeContext=new _("SCMChangeContext")}static{this.SCMResourceContext=new _("SCMResourceContext")}static{this.SCMResourceContextShare=new _("SCMResourceContextShare")}static{this.SCMResourceFolderContext=new _("SCMResourceFolderContext")}static{this.SCMResourceGroupContext=new _("SCMResourceGroupContext")}static{this.SCMSourceControl=new _("SCMSourceControl")}static{this.SCMSourceControlInline=new _("SCMSourceControlInline")}static{this.SCMSourceControlTitle=new _("SCMSourceControlTitle")}static{this.SCMHistoryTitle=new _("SCMHistoryTitle")}static{this.SCMTitle=new _("SCMTitle")}static{this.SearchContext=new _("SearchContext")}static{this.SearchActionMenu=new _("SearchActionContext")}static{this.StatusBarWindowIndicatorMenu=new _("StatusBarWindowIndicatorMenu")}static{this.StatusBarRemoteIndicatorMenu=new _("StatusBarRemoteIndicatorMenu")}static{this.StickyScrollContext=new _("StickyScrollContext")}static{this.TestItem=new _("TestItem")}static{this.TestItemGutter=new _("TestItemGutter")}static{this.TestProfilesContext=new _("TestProfilesContext")}static{this.TestMessageContext=new _("TestMessageContext")}static{this.TestMessageContent=new _("TestMessageContent")}static{this.TestPeekElement=new _("TestPeekElement")}static{this.TestPeekTitle=new _("TestPeekTitle")}static{this.TestCallStack=new _("TestCallStack")}static{this.TouchBarContext=new _("TouchBarContext")}static{this.TitleBarContext=new _("TitleBarContext")}static{this.TitleBarTitleContext=new _("TitleBarTitleContext")}static{this.TunnelContext=new _("TunnelContext")}static{this.TunnelPrivacy=new _("TunnelPrivacy")}static{this.TunnelProtocol=new _("TunnelProtocol")}static{this.TunnelPortInline=new _("TunnelInline")}static{this.TunnelTitle=new _("TunnelTitle")}static{this.TunnelLocalAddressInline=new _("TunnelLocalAddressInline")}static{this.TunnelOriginInline=new _("TunnelOriginInline")}static{this.ViewItemContext=new _("ViewItemContext")}static{this.ViewContainerTitle=new _("ViewContainerTitle")}static{this.ViewContainerTitleContext=new _("ViewContainerTitleContext")}static{this.ViewTitle=new _("ViewTitle")}static{this.ViewTitleContext=new _("ViewTitleContext")}static{this.CommentEditorActions=new _("CommentEditorActions")}static{this.CommentThreadTitle=new _("CommentThreadTitle")}static{this.CommentThreadActions=new _("CommentThreadActions")}static{this.CommentThreadAdditionalActions=new _("CommentThreadAdditionalActions")}static{this.CommentThreadTitleContext=new _("CommentThreadTitleContext")}static{this.CommentThreadCommentContext=new _("CommentThreadCommentContext")}static{this.CommentTitle=new _("CommentTitle")}static{this.CommentActions=new _("CommentActions")}static{this.CommentsViewThreadActions=new _("CommentsViewThreadActions")}static{this.InteractiveToolbar=new _("InteractiveToolbar")}static{this.InteractiveCellTitle=new _("InteractiveCellTitle")}static{this.InteractiveCellDelete=new _("InteractiveCellDelete")}static{this.InteractiveCellExecute=new _("InteractiveCellExecute")}static{this.InteractiveInputExecute=new _("InteractiveInputExecute")}static{this.InteractiveInputConfig=new _("InteractiveInputConfig")}static{this.ReplInputExecute=new _("ReplInputExecute")}static{this.IssueReporter=new _("IssueReporter")}static{this.NotebookToolbar=new _("NotebookToolbar")}static{this.NotebookStickyScrollContext=new _("NotebookStickyScrollContext")}static{this.NotebookCellTitle=new _("NotebookCellTitle")}static{this.NotebookCellDelete=new _("NotebookCellDelete")}static{this.NotebookCellInsert=new _("NotebookCellInsert")}static{this.NotebookCellBetween=new _("NotebookCellBetween")}static{this.NotebookCellListTop=new _("NotebookCellTop")}static{this.NotebookCellExecute=new _("NotebookCellExecute")}static{this.NotebookCellExecuteGoTo=new _("NotebookCellExecuteGoTo")}static{this.NotebookCellExecutePrimary=new _("NotebookCellExecutePrimary")}static{this.NotebookDiffCellInputTitle=new _("NotebookDiffCellInputTitle")}static{this.NotebookDiffCellMetadataTitle=new _("NotebookDiffCellMetadataTitle")}static{this.NotebookDiffCellOutputsTitle=new _("NotebookDiffCellOutputsTitle")}static{this.NotebookOutputToolbar=new _("NotebookOutputToolbar")}static{this.NotebookOutlineFilter=new _("NotebookOutlineFilter")}static{this.NotebookOutlineActionMenu=new _("NotebookOutlineActionMenu")}static{this.NotebookEditorLayoutConfigure=new _("NotebookEditorLayoutConfigure")}static{this.NotebookKernelSource=new _("NotebookKernelSource")}static{this.BulkEditTitle=new _("BulkEditTitle")}static{this.BulkEditContext=new _("BulkEditContext")}static{this.TimelineItemContext=new _("TimelineItemContext")}static{this.TimelineTitle=new _("TimelineTitle")}static{this.TimelineTitleContext=new _("TimelineTitleContext")}static{this.TimelineFilterSubMenu=new _("TimelineFilterSubMenu")}static{this.AccountsContext=new _("AccountsContext")}static{this.SidebarTitle=new _("SidebarTitle")}static{this.PanelTitle=new _("PanelTitle")}static{this.AuxiliaryBarTitle=new _("AuxiliaryBarTitle")}static{this.AuxiliaryBarHeader=new _("AuxiliaryBarHeader")}static{this.TerminalInstanceContext=new _("TerminalInstanceContext")}static{this.TerminalEditorInstanceContext=new _("TerminalEditorInstanceContext")}static{this.TerminalNewDropdownContext=new _("TerminalNewDropdownContext")}static{this.TerminalTabContext=new _("TerminalTabContext")}static{this.TerminalTabEmptyAreaContext=new _("TerminalTabEmptyAreaContext")}static{this.TerminalStickyScrollContext=new _("TerminalStickyScrollContext")}static{this.WebviewContext=new _("WebviewContext")}static{this.InlineCompletionsActions=new _("InlineCompletionsActions")}static{this.InlineEditsActions=new _("InlineEditsActions")}static{this.InlineEditActions=new _("InlineEditActions")}static{this.NewFile=new _("NewFile")}static{this.MergeInput1Toolbar=new _("MergeToolbar1Toolbar")}static{this.MergeInput2Toolbar=new _("MergeToolbar2Toolbar")}static{this.MergeBaseToolbar=new _("MergeBaseToolbar")}static{this.MergeInputResultToolbar=new _("MergeToolbarResultToolbar")}static{this.InlineSuggestionToolbar=new _("InlineSuggestionToolbar")}static{this.InlineEditToolbar=new _("InlineEditToolbar")}static{this.ChatContext=new _("ChatContext")}static{this.ChatCodeBlock=new _("ChatCodeblock")}static{this.ChatCompareBlock=new _("ChatCompareBlock")}static{this.ChatMessageTitle=new _("ChatMessageTitle")}static{this.ChatExecute=new _("ChatExecute")}static{this.ChatExecuteSecondary=new _("ChatExecuteSecondary")}static{this.ChatInputSide=new _("ChatInputSide")}static{this.AccessibleView=new _("AccessibleView")}static{this.MultiDiffEditorFileToolbar=new _("MultiDiffEditorFileToolbar")}static{this.DiffEditorHunkToolbar=new _("DiffEditorHunkToolbar")}static{this.DiffEditorSelectionToolbar=new _("DiffEditorSelectionToolbar")}constructor(e){if(_._instances.has(e))throw new TypeError(`MenuId with identifier '${e}' already exists. Use MenuId.for(ident) or a unique identifier`);_._instances.set(e,this),this.id=e}}const v=(0,d.u1)("menuService");class C{static{this._all=new Map}static for(e){let t=this._all.get(e);return t||(t=new C(e),this._all.set(e,t)),t}static merge(e){const t=new Set;for(const i of e)i instanceof C&&t.add(i.id);return t}constructor(e){this.id=e,this.has=t=>t===e}}const E=new class{constructor(){this._commands=new Map,this._menuItems=new Map,this._onDidChangeMenu=new o.QT({merge:C.merge}),this.onDidChangeMenu=this._onDidChangeMenu.event}addCommand(e){return this._commands.set(e.id,e),this._onDidChangeMenu.fire(C.for(_.CommandPalette)),(0,a.s)((()=>{this._commands.delete(e.id)&&this._onDidChangeMenu.fire(C.for(_.CommandPalette))}))}getCommand(e){return this._commands.get(e)}getCommands(){const e=new Map;return this._commands.forEach(((t,i)=>e.set(i,t))),e}appendMenuItem(e,t){let i=this._menuItems.get(e);i||(i=new c.w,this._menuItems.set(e,i));const s=i.push(t);return this._onDidChangeMenu.fire(C.for(e)),(0,a.s)((()=>{s(),this._onDidChangeMenu.fire(C.for(e))}))}appendMenuItems(e){const t=new a.Cm;for(const{id:i,item:s}of e)t.add(this.appendMenuItem(i,s));return t}getMenuItems(e){let t;return t=this._menuItems.has(e)?[...this._menuItems.get(e)]:[],e===_.CommandPalette&&this._appendImplicitItems(t),t}_appendImplicitItems(e){const t=new Set;for(const i of e)m(i)&&(t.add(i.command.id),i.alt&&t.add(i.alt.id));this._commands.forEach(((i,s)=>{t.has(s)||e.push({command:i})}))}};class b extends n.YH{constructor(e,t,i){super(`submenuitem.${e.submenu.id}`,"string"===typeof e.title?e.title:e.title.value,i,"submenu"),this.item=e,this.hideActions=t}}let S=s=class{static label(e,t){return t?.renderShortTitle&&e.shortTitle?"string"===typeof e.shortTitle?e.shortTitle:e.shortTitle.value:"string"===typeof e.title?e.title:e.title.value}constructor(e,t,i,n,o,a,c){let l;if(this.hideActions=n,this.menuKeybinding=o,this._commandService=c,this.id=e.id,this.label=s.label(e,i),this.tooltip=("string"===typeof e.tooltip?e.tooltip:e.tooltip?.value)??"",this.enabled=!e.precondition||a.contextMatchesRules(e.precondition),this.checked=void 0,e.toggled){const t=e.toggled.condition?e.toggled:{condition:e.toggled};this.checked=a.contextMatchesRules(t.condition),this.checked&&t.tooltip&&(this.tooltip="string"===typeof t.tooltip?t.tooltip:t.tooltip.value),this.checked&&r.L.isThemeIcon(t.icon)&&(l=t.icon),this.checked&&t.title&&(this.label="string"===typeof t.title?t.title:t.title.value)}l||(l=r.L.isThemeIcon(e.icon)?e.icon:void 0),this.item=e,this.alt=t?new s(t,void 0,i,n,void 0,a,c):void 0,this._options=i,this.class=l&&r.L.asClassName(l)}run(...e){let t=[];return this._options?.arg&&(t=[...t,this._options.arg]),this._options?.shouldForwardArgs&&(t=[...t,...e]),this._commandService.executeCommand(this.id,...t)}};S=s=g([p(5,h.fN),p(6,l.d)],S);class y{constructor(e){this.desc=e}}function w(e){const t=[],i=new e,{f1:s,menu:n,keybinding:r,...o}=i.desc;if(l.w.getCommand(o.id))throw new Error(`Cannot register two commands with the same id: ${o.id}`);if(t.push(l.w.registerCommand({id:o.id,handler:(e,...t)=>i.run(e,...t),metadata:o.metadata})),Array.isArray(n))for(const a of n)t.push(E.appendMenuItem(a.id,{command:{...o,precondition:null===a.precondition?void 0:o.precondition},...a}));else n&&t.push(E.appendMenuItem(n.id,{command:{...o,precondition:null===n.precondition?void 0:o.precondition},...n}));if(s&&(t.push(E.appendMenuItem(_.CommandPalette,{command:o,when:o.precondition})),t.push(E.addCommand(o))),Array.isArray(r))for(const a of r)t.push(u.f.registerKeybindingRule({...a,id:o.id,when:o.precondition?h.M$.and(o.precondition,a.when):a.when}));else r&&t.push(u.f.registerKeybindingRule({...r,id:o.id,when:o.precondition?h.M$.and(o.precondition,r.when):r.when}));return{dispose(){(0,a.AS)(t)}}}},27414:(e,t,i)=>{"use strict";i.d(t,{N:()=>r,c2:()=>o});var s=i(25890),n=i(85152);class r{constructor(e){this.values=e,this.prefixSum=new Uint32Array(e.length),this.prefixSumValidIndex=new Int32Array(1),this.prefixSumValidIndex[0]=-1}insertValues(e,t){e=(0,n.j)(e);const i=this.values,s=this.prefixSum,r=t.length;return 0!==r&&(this.values=new Uint32Array(i.length+r),this.values.set(i.subarray(0,e),0),this.values.set(i.subarray(e),e+r),this.values.set(t,e),e-1=0&&this.prefixSum.set(s.subarray(0,this.prefixSumValidIndex[0]+1)),!0)}setValue(e,t){return e=(0,n.j)(e),t=(0,n.j)(t),this.values[e]!==t&&(this.values[e]=t,e-1=i.length)return!1;const r=i.length-e;return t>=r&&(t=r),0!==t&&(this.values=new Uint32Array(i.length-t),this.values.set(i.subarray(0,e),0),this.values.set(i.subarray(e+t),e),this.prefixSum=new Uint32Array(this.values.length),e-1=0&&this.prefixSum.set(s.subarray(0,this.prefixSumValidIndex[0]+1)),!0)}getTotalSum(){return 0===this.values.length?0:this._getPrefixSum(this.values.length-1)}getPrefixSum(e){return e<0?0:(e=(0,n.j)(e),this._getPrefixSum(e))}_getPrefixSum(e){if(e<=this.prefixSumValidIndex[0])return this.prefixSum[e];let t=this.prefixSumValidIndex[0]+1;0===t&&(this.prefixSum[0]=this.values[0],t++),e>=this.values.length&&(e=this.values.length-1);for(let i=t;i<=e;i++)this.prefixSum[i]=this.prefixSum[i-1]+this.values[i];return this.prefixSumValidIndex[0]=Math.max(this.prefixSumValidIndex[0],e),this.prefixSum[e]}getIndexOf(e){e=Math.floor(e),this.getTotalSum();let t=0,i=this.values.length-1,s=0,n=0,r=0;for(;t<=i;)if(s=t+(i-t)/2|0,n=this.prefixSum[s],r=n-this.values[s],e=n))break;t=s+1}return new a(s,e-r)}}class o{constructor(e){this._values=e,this._isValid=!1,this._validEndIndex=-1,this._prefixSum=[],this._indexBySum=[]}getTotalSum(){return this._ensureValid(),this._indexBySum.length}getPrefixSum(e){return this._ensureValid(),0===e?0:this._prefixSum[e-1]}getIndexOf(e){this._ensureValid();const t=this._indexBySum[e],i=t>0?this._prefixSum[t-1]:0;return new a(t,e-i)}removeValues(e,t){this._values.splice(e,t),this._invalidate(e)}insertValues(e,t){this._values=(0,s.nK)(this._values,e,t),this._invalidate(e)}_invalidate(e){this._isValid=!1,this._validEndIndex=Math.min(this._validEndIndex,e-1)}_ensureValid(){if(!this._isValid){for(let e=this._validEndIndex+1,t=this._values.length;e0?this._prefixSum[e-1]:0;this._prefixSum[e]=i+t;for(let s=0;s{"use strict";i.d(t,{S5:()=>n,n:()=>o,yk:()=>r});var s=i(8597);function n(e,t={}){const i=o(t);return i.textContent=e,i}function r(e,t={}){const i=o(t);return c(i,function(e,t){const i={type:1,children:[]};let s=0,n=i;const r=[],o=new a(e);for(;!o.eos();){let e=o.next();const i="\\"===e&&0!==h(o.peek(),t);if(i&&(e=o.next()),!i&&l(e,t)&&e===o.peek()){o.advance(),2===n.type&&(n=r.pop());const i=h(e,t);if(n.type===i||5===n.type&&6===i)n=r.pop();else{const e={type:i,children:[]};5===i&&(e.index=s,s++),n.children.push(e),r.push(n),n=e}}else if("\n"===e)2===n.type&&(n=r.pop()),n.children.push({type:8});else if(2!==n.type){const t={type:2,content:e};n.children.push(t),r.push(n),n=t}else n.content+=e}2===n.type&&(n=r.pop());r.length;return i}(e,!!t.renderCodeSegments),t.actionHandler,t.renderCodeSegments),i}function o(e){const t=e.inline?"span":"div",i=document.createElement(t);return e.className&&(i.className=e.className),i}class a{constructor(e){this.source=e,this.index=0}eos(){return this.index>=this.source.length}next(){const e=this.peek();return this.advance(),e}peek(){return this.source[this.index]}advance(){this.index++}}function c(e,t,i,n){let r;if(2===t.type)r=document.createTextNode(t.content||"");else if(3===t.type)r=document.createElement("b");else if(4===t.type)r=document.createElement("i");else if(7===t.type&&n)r=document.createElement("code");else if(5===t.type&&i){const e=document.createElement("a");i.disposables.add(s.b2(e,"click",(e=>{i.callback(String(t.index),e)}))),r=e}else 8===t.type?r=document.createElement("br"):1===t.type&&(r=e);r&&e!==r&&e.appendChild(r),r&&Array.isArray(t.children)&&t.children.forEach((e=>{c(r,e,i,n)}))}function l(e,t){return 0!==h(e,t)}function h(e,t){switch(e){case"*":return 3;case"_":return 4;case"[":return 5;case"]":return 6;case"`":return t?7:0;default:return 0}}},27734:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"scss",extensions:[".scss"],aliases:["Sass","sass","scss"],mimetypes:["text/x-scss","text/scss"],loader:()=>i.e(3048).then(i.bind(i,3048))})},27760:(e,t,i)=>{"use strict";i.d(t,{V:()=>a,WR:()=>l,no:()=>o});var s=i(91508),n=i(12296),r=i(87469);class o{constructor(e,t,i){this._indentRulesSupport=t,this._indentationLineProcessor=new c(e,i)}shouldIncrease(e,t){const i=this._indentationLineProcessor.getProcessedLine(e,t);return this._indentRulesSupport.shouldIncrease(i)}shouldDecrease(e,t){const i=this._indentationLineProcessor.getProcessedLine(e,t);return this._indentRulesSupport.shouldDecrease(i)}shouldIgnore(e,t){const i=this._indentationLineProcessor.getProcessedLine(e,t);return this._indentRulesSupport.shouldIgnore(i)}shouldIndentNextLine(e,t){const i=this._indentationLineProcessor.getProcessedLine(e,t);return this._indentRulesSupport.shouldIndentNextLine(i)}}class a{constructor(e,t){this.model=e,this.indentationLineProcessor=new c(e,t)}getProcessedTokenContextAroundRange(e){return{beforeRangeProcessedTokens:this._getProcessedTokensBeforeRange(e),afterRangeProcessedTokens:this._getProcessedTokensAfterRange(e),previousLineProcessedTokens:this._getProcessedPreviousLineTokens(e)}}_getProcessedTokensBeforeRange(e){this.model.tokenization.forceTokenization(e.startLineNumber);const t=this.model.tokenization.getLineTokens(e.startLineNumber),i=(0,n.BQ)(t,e.startColumn-1);let s;if(l(this.model,e.getStartPosition())){const n=e.startColumn-1-i.firstCharOffset,r=i.firstCharOffset,o=r+n;s=t.sliceAndInflate(r,o,0)}else{const i=e.startColumn-1;s=t.sliceAndInflate(0,i,0)}return this.indentationLineProcessor.getProcessedTokens(s)}_getProcessedTokensAfterRange(e){const t=e.isEmpty()?e.getStartPosition():e.getEndPosition();this.model.tokenization.forceTokenization(t.lineNumber);const i=this.model.tokenization.getLineTokens(t.lineNumber),s=(0,n.BQ)(i,t.column-1),r=t.column-1-s.firstCharOffset,o=s.firstCharOffset+r,a=s.firstCharOffset+s.getLineLength(),c=i.sliceAndInflate(o,a,0);return this.indentationLineProcessor.getProcessedTokens(c)}_getProcessedPreviousLineTokens(e){this.model.tokenization.forceTokenization(e.startLineNumber);const t=this.model.tokenization.getLineTokens(e.startLineNumber),i=(0,n.BQ)(t,e.startColumn-1),s=r.f.createEmpty("",i.languageIdCodec),o=e.startLineNumber-1;if(0===o)return s;if(!(0===i.firstCharOffset))return s;const a=(e=>{this.model.tokenization.forceTokenization(e);const t=this.model.tokenization.getLineTokens(e),i=this.model.getLineMaxColumn(e)-1;return(0,n.BQ)(t,i)})(o);if(!(i.languageId===a.languageId))return s;const c=a.toIViewLineTokens();return this.indentationLineProcessor.getProcessedTokens(c)}}class c{constructor(e,t){this.model=e,this.languageConfigurationService=t}getProcessedLine(e,t){this.model.tokenization.forceTokenization?.(e);const i=this.model.tokenization.getLineTokens(e);let n=this.getProcessedTokens(i).getLineContent();return void 0!==t&&(n=((e,t)=>{const i=s.UU(e);return t+e.substring(i.length)})(n,t)),n}getProcessedTokens(e){const t=e.getLanguageId(0),i=this.languageConfigurationService.getLanguageConfiguration(t).bracketsNew.getBracketRegExp({global:!0}),s=[];e.forEach((t=>{const n=e.getStandardTokenType(t);let r=e.getTokenText(t);(e=>2===e||3===e||1===e)(n)&&(r=r.replace(i,""));const o=e.getMetadata(t);s.push({text:r,metadata:o})}));return r.f.createFromTextAndMetadata(s,e.languageIdCodec)}}function l(e,t){e.tokenization.forceTokenization(t.lineNumber);const i=e.tokenization.getLineTokens(t.lineNumber),s=(0,n.BQ)(i,t.column-1),r=0===s.firstCharOffset,o=i.getLanguageId(0)===s.languageId;return!r&&!o}},27769:e=>{e.exports=function(){return"Unipika Pika!"}},28211:(e,t,i)=>{"use strict";i(97791),i(93409);var s=i(90766),n=i(18447),r=i(10350),o=i(25689),a=i(26690),c=i(74027),l=i(98067),h=i(91508);const d=[void 0,[]];function u(e,t,i=0,s=0){const n=t;return n.values&&n.values.length>1?function(e,t,i,s){let n=0;const r=[];for(const o of t){const[t,a]=g(e,o,i,s);if("number"!==typeof t)return d;n+=t,r.push(...a)}return[n,p(r)]}(e,n.values,i,s):g(e,t,i,s)}function g(e,t,i,s){const n=(0,a.dt)(t.original,t.originalLowercase,i,e,e.toLowerCase(),s,{firstMatchCanBeWeak:!0,boostFullMatch:!0});return n?[n[0],(0,a.WJ)(n)]:d}Object.freeze({score:0});function p(e){const t=e.sort(((e,t)=>e.start-t.start)),i=[];let s;for(const n of t)s&&m(s,n)?(s.start=Math.min(s.start,n.start),s.end=Math.max(s.end,n.end)):(s=n,i.push(n));return i}function m(e,t){return!(e.end=0,o=f(e);let a;const l=e.split(" ");if(l.length>1)for(const c of l){const e=f(c),{pathNormalized:t,normalized:i,normalizedLowercase:s}=v(c);i&&(a||(a=[]),a.push({original:c,originalLowercase:c.toLowerCase(),pathNormalized:t,normalized:i,normalizedLowercase:s,expectContiguousMatch:e}))}return{original:e,originalLowercase:t,pathNormalized:i,normalized:s,normalizedLowercase:n,values:a,containsPathSeparator:r,expectContiguousMatch:o}}function v(e){let t;t=l.uF?e.replace(/\//g,c.Vn):e.replace(/\\/g,c.Vn);const i=(0,h.wB)(t).replace(/\s|"/g,"");return{pathNormalized:t,normalized:i,normalizedLowercase:i.toLowerCase()}}function C(e){return Array.isArray(e)?_(e.map((e=>e.original)).join(" ")):_(e.original)}var E,b=i(5662),S=i(36677),y=i(62083),w=i(29999),R=i(12437),L=i(78209),T=i(56942),x=i(46041),k=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},A=function(e,t){return function(i,s){t(i,s,e)}};let N=class extends R.o{static{E=this}static{this.PREFIX="@"}static{this.SCOPE_PREFIX=":"}static{this.PREFIX_BY_CATEGORY=`${this.PREFIX}${this.SCOPE_PREFIX}`}constructor(e,t,i=Object.create(null)){super(i),this._languageFeaturesService=e,this._outlineModelService=t,this.options=i,this.options.canAcceptInBackground=!0}provideWithoutTextEditor(e){return this.provideLabelPick(e,(0,L.kg)("cannotRunGotoSymbolWithoutEditor","To go to a symbol, first open a text editor with symbol information.")),b.jG.None}provideWithTextEditor(e,t,i,s){const n=e.editor,r=this.getModel(n);return r?this._languageFeaturesService.documentSymbolProvider.has(r)?this.doProvideWithEditorSymbols(e,r,t,i,s):this.doProvideWithoutEditorSymbols(e,r,t,i):b.jG.None}doProvideWithoutEditorSymbols(e,t,i,s){const n=new b.Cm;return this.provideLabelPick(i,(0,L.kg)("cannotRunGotoSymbolWithoutSymbolProvider","The active text editor does not provide symbol information.")),(async()=>{await this.waitForLanguageSymbolRegistry(t,n)&&!s.isCancellationRequested&&n.add(this.doProvideWithEditorSymbols(e,t,i,s))})(),n}provideLabelPick(e,t){e.items=[{label:t,index:0,kind:14}],e.ariaLabel=t}async waitForLanguageSymbolRegistry(e,t){if(this._languageFeaturesService.documentSymbolProvider.has(e))return!0;const i=new s.Zv,n=t.add(this._languageFeaturesService.documentSymbolProvider.onDidChange((()=>{this._languageFeaturesService.documentSymbolProvider.has(e)&&(n.dispose(),i.complete(!0))})));return t.add((0,b.s)((()=>i.complete(!1)))),i.p}doProvideWithEditorSymbols(e,t,i,s,r){const o=e.editor,a=new b.Cm;a.add(i.onDidAccept((t=>{const[s]=i.selectedItems;s&&s.range&&(this.gotoLocation(e,{range:s.range.selection,keyMods:i.keyMods,preserveFocus:t.inBackground}),r?.handleAccept?.(s),t.inBackground||i.hide())}))),a.add(i.onDidTriggerItemButton((({item:t})=>{t&&t.range&&(this.gotoLocation(e,{range:t.range.selection,keyMods:i.keyMods,forceSideBySide:!0}),i.hide())})));const c=this.getDocumentSymbols(t,s);let l;const h=async e=>{l?.dispose(!0),i.busy=!1,l=new n.Qi(s),i.busy=!0;try{const n=_(i.value.substr(E.PREFIX.length).trim()),r=await this.doGetSymbolPicks(c,n,void 0,l.token,t);if(s.isCancellationRequested)return;if(r.length>0){if(i.items=r,e&&0===n.original.length){const t=(0,x.Uk)(r,(t=>Boolean("separator"!==t.type&&t.range&&S.Q.containsPosition(t.range.decoration,e))));t&&(i.activeItems=[t])}}else n.original.length>0?this.provideLabelPick(i,(0,L.kg)("noMatchingSymbolResults","No matching editor symbols")):this.provideLabelPick(i,(0,L.kg)("noSymbolResults","No editor symbols"))}finally{s.isCancellationRequested||(i.busy=!1)}};return a.add(i.onDidChangeValue((()=>h(void 0)))),h(o.getSelection()?.getPosition()),a.add(i.onDidChangeActive((()=>{const[e]=i.activeItems;e&&e.range&&(o.revealRangeInCenter(e.range.selection,0),this.addDecorations(o,e.range.decoration))}))),a}async doGetSymbolPicks(e,t,i,s,n){const a=await e;if(s.isCancellationRequested)return[];const c=0===t.original.indexOf(E.SCOPE_PREFIX),l=c?1:0;let d,g,p;t.values&&t.values.length>1?(d=C(t.values[0]),g=C(t.values.slice(1))):d=t;const m=this.options?.openSideBySideDirection?.();m&&(p=[{iconClass:"right"===m?o.L.asClassName(r.W.splitHorizontal):o.L.asClassName(r.W.splitVertical),tooltip:"right"===m?(0,L.kg)("openToSide","Open to the Side"):(0,L.kg)("openToBottom","Open to the Bottom")}]);const f=[];for(let b=0;bl){let F=!1;if(d!==t&&([k,A]=u(T,{...t,values:void 0},l,x),"number"===typeof k&&(F=!0)),"number"!==typeof k&&([k,A]=u(T,d,l,x),"number"!==typeof k))continue;if(!F&&g){if(M&&g.original.length>0&&([N,D]=u(M,g)),"number"!==typeof N)continue;"number"===typeof k&&(k+=N)}}const P=w.tags&&w.tags.indexOf(1)>=0;f.push({index:b,kind:w.kind,score:k,label:T,ariaLabel:(0,y.PK)(w.name,w.kind),description:M,highlights:P?void 0:{label:A,description:D},range:{selection:S.Q.collapseToStart(w.selectionRange),decoration:w.range},uri:n.uri,symbolName:R,strikethrough:P,buttons:p})}const _=f.sort(((e,t)=>c?this.compareByKindAndScore(e,t):this.compareByScore(e,t)));let v=[];if(c){let U,H,B=0;function W(){H&&"number"===typeof U&&B>0&&(H.label=(0,h.GP)(O[U]||I,B))}for(const V of _)U!==V.kind?(W(),U=V.kind,B=1,H={type:"separator"},v.push(H)):B++,v.push(V);W()}else _.length>0&&(v=[{label:(0,L.kg)("symbols","symbols ({0})",f.length),type:"separator"},..._]);return v}compareByScore(e,t){if("number"!==typeof e.score&&"number"===typeof t.score)return 1;if("number"===typeof e.score&&"number"!==typeof t.score)return-1;if("number"===typeof e.score&&"number"===typeof t.score){if(e.score>t.score)return-1;if(e.scoret.index?1:0}compareByKindAndScore(e,t){const i=O[e.kind]||I,s=O[t.kind]||I,n=i.localeCompare(s);return 0===n?this.compareByScore(e,t):n}async getDocumentSymbols(e,t){const i=await this._outlineModelService.getOrCreate(e,t);return t.isCancellationRequested?[]:i.asListOfDocumentSymbols()}};N=E=k([A(0,T.ILanguageFeaturesService),A(1,w.gW)],N);const I=(0,L.kg)("property","properties ({0})"),O={5:(0,L.kg)("method","methods ({0})"),11:(0,L.kg)("function","functions ({0})"),8:(0,L.kg)("_constructor","constructors ({0})"),12:(0,L.kg)("variable","variables ({0})"),4:(0,L.kg)("class","classes ({0})"),22:(0,L.kg)("struct","structs ({0})"),23:(0,L.kg)("event","events ({0})"),24:(0,L.kg)("operator","operators ({0})"),10:(0,L.kg)("interface","interfaces ({0})"),2:(0,L.kg)("namespace","namespaces ({0})"),3:(0,L.kg)("package","packages ({0})"),25:(0,L.kg)("typeParameter","type parameters ({0})"),1:(0,L.kg)("modules","modules ({0})"),6:(0,L.kg)("property","properties ({0})"),9:(0,L.kg)("enum","enumerations ({0})"),21:(0,L.kg)("enumMember","enumeration members ({0})"),14:(0,L.kg)("string","strings ({0})"),0:(0,L.kg)("file","files ({0})"),17:(0,L.kg)("array","arrays ({0})"),15:(0,L.kg)("number","numbers ({0})"),16:(0,L.kg)("boolean","booleans ({0})"),18:(0,L.kg)("object","objects ({0})"),19:(0,L.kg)("key","keys ({0})"),7:(0,L.kg)("field","fields ({0})"),13:(0,L.kg)("constant","constants ({0})")};var D=i(46359),M=i(71597),P=i(80301),F=i(51861),U=i(41234),H=i(31450),B=i(60002),W=i(51467),V=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},z=function(e,t){return function(i,s){t(i,s,e)}};let G=class extends N{constructor(e,t,i){super(t,i),this.editorService=e,this.onDidActiveTextEditorControlChange=U.Jh.None}get activeTextEditorControl(){return this.editorService.getFocusedCodeEditor()??void 0}};G=V([z(0,P.T),z(1,T.ILanguageFeaturesService),z(2,w.gW)],G);class j extends H.ks{static{this.ID="editor.action.quickOutline"}constructor(){super({id:j.ID,label:F.n9.quickOutlineActionLabel,alias:"Go to Symbol...",precondition:B.R.hasDocumentSymbolProvider,kbOpts:{kbExpr:B.R.focus,primary:3117,weight:100},contextMenuOpts:{group:"navigation",order:3}})}run(e){e.get(W.GK).quickAccess.show(N.PREFIX,{itemActivation:W.C1.NONE})}}(0,H.Fl)(j),D.O.as(M.Fd.Quickaccess).registerQuickAccessProvider({ctor:G,prefix:N.PREFIX,helpEntries:[{description:F.n9.quickOutlineActionLabel,prefix:N.PREFIX,commandId:j.ID},{description:F.n9.quickOutlineByCategoryActionLabel,prefix:N.PREFIX_BY_CATEGORY}]})},28290:(e,t,i)=>{"use strict";i.d(t,{J7:()=>l,W0:()=>a,aV:()=>c,nd:()=>o});var s=i(98067),n=i(78209),r=i(32848);new r.N1("isMac",s.zx,(0,n.kg)("isMac","Whether the operating system is macOS")),new r.N1("isLinux",s.j9,(0,n.kg)("isLinux","Whether the operating system is Linux"));const o=new r.N1("isWindows",s.uF,(0,n.kg)("isWindows","Whether the operating system is Windows")),a=new r.N1("isWeb",s.HZ,(0,n.kg)("isWeb","Whether the platform is a web browser")),c=(new r.N1("isMacNative",s.zx&&!s.HZ,(0,n.kg)("isMacNative","Whether the operating system is macOS on a non-browser platform")),new r.N1("isIOS",s.un,(0,n.kg)("isIOS","Whether the operating system is iOS")),new r.N1("isMobile",s.Fr,(0,n.kg)("isMobile","Whether the platform is a mobile web browser")),new r.N1("isDevelopment",!1,!0),new r.N1("productQualityType","",(0,n.kg)("productQualityType","Quality type of VS Code")),"inputFocus"),l=new r.N1(c,!1,(0,n.kg)("inputFocus","Whether keyboard focus is inside an input box"))},28291:(e,t,i)=>{"use strict";i.d(t,{S:()=>s,c:()=>h});var s,n=i(631),r=i(32799),o=i(94564),a=i(97681),c=i(83069),l=i(36677);class h{static addCursorDown(e,t,i){const s=[];let n=0;for(let a=0,c=t.length;at&&(i=t,s=e.model.getLineMaxColumn(i)),r.MF.fromModelState(new r.mG(new l.Q(o.lineNumber,1,i,s),2,0,new c.y(i,s),0))}const h=t.modelState.selectionStart.getStartPosition().lineNumber;if(o.lineNumberh){const i=e.getLineCount();let s=a.lineNumber+1,n=1;return s>i&&(s=i,n=e.getLineMaxColumn(s)),r.MF.fromViewState(t.viewState.move(!0,s,n,0))}{const e=t.modelState.selectionStart.getEndPosition();return r.MF.fromModelState(t.modelState.move(!0,e.lineNumber,e.column,0))}}static word(e,t,i,s){const n=e.model.validatePosition(s);return r.MF.fromModelState(a.z.word(e.cursorConfig,e.model,t.modelState,i,n))}static cancelSelection(e,t){if(!t.modelState.hasSelection())return new r.MF(t.modelState,t.viewState);const i=t.viewState.position.lineNumber,s=t.viewState.position.column;return r.MF.fromViewState(new r.mG(new l.Q(i,s,i,s),0,0,new c.y(i,s),0))}static moveTo(e,t,i,s,n){if(i){if(1===t.modelState.selectionStartKind)return this.word(e,t,i,s);if(2===t.modelState.selectionStartKind)return this.line(e,t,i,s,n)}const o=e.model.validatePosition(s),a=n?e.coordinatesConverter.validateViewPosition(new c.y(n.lineNumber,n.column),o):e.coordinatesConverter.convertModelPositionToViewPosition(o);return r.MF.fromViewState(t.viewState.move(i,a.lineNumber,a.column,0))}static simpleMove(e,t,i,s,n,a){switch(i){case 0:return 4===a?this._moveHalfLineLeft(e,t,s):this._moveLeft(e,t,s,n);case 1:return 4===a?this._moveHalfLineRight(e,t,s):this._moveRight(e,t,s,n);case 2:return 2===a?this._moveUpByViewLines(e,t,s,n):this._moveUpByModelLines(e,t,s,n);case 3:return 2===a?this._moveDownByViewLines(e,t,s,n):this._moveDownByModelLines(e,t,s,n);case 4:return 2===a?t.map((t=>r.MF.fromViewState(o.I.moveToPrevBlankLine(e.cursorConfig,e,t.viewState,s)))):t.map((t=>r.MF.fromModelState(o.I.moveToPrevBlankLine(e.cursorConfig,e.model,t.modelState,s))));case 5:return 2===a?t.map((t=>r.MF.fromViewState(o.I.moveToNextBlankLine(e.cursorConfig,e,t.viewState,s)))):t.map((t=>r.MF.fromModelState(o.I.moveToNextBlankLine(e.cursorConfig,e.model,t.modelState,s))));case 6:return this._moveToViewMinColumn(e,t,s);case 7:return this._moveToViewFirstNonWhitespaceColumn(e,t,s);case 8:return this._moveToViewCenterColumn(e,t,s);case 9:return this._moveToViewMaxColumn(e,t,s);case 10:return this._moveToViewLastNonWhitespaceColumn(e,t,s);default:return null}}static viewportMove(e,t,i,s,n){const r=e.getCompletelyVisibleViewRange(),o=e.coordinatesConverter.convertViewRangeToModelRange(r);switch(i){case 11:{const i=this._firstLineNumberInRange(e.model,o,n),r=e.model.getLineFirstNonWhitespaceColumn(i);return[this._moveToModelPosition(e,t[0],s,i,r)]}case 13:{const i=this._lastLineNumberInRange(e.model,o,n),r=e.model.getLineFirstNonWhitespaceColumn(i);return[this._moveToModelPosition(e,t[0],s,i,r)]}case 12:{const i=Math.round((o.startLineNumber+o.endLineNumber)/2),n=e.model.getLineFirstNonWhitespaceColumn(i);return[this._moveToModelPosition(e,t[0],s,i,n)]}case 14:{const i=[];for(let n=0,o=t.length;ni.endLineNumber-1?i.endLineNumber-1:nr.MF.fromViewState(o.I.moveLeft(e.cursorConfig,e,t.viewState,i,s))))}static _moveHalfLineLeft(e,t,i){const s=[];for(let n=0,a=t.length;nr.MF.fromViewState(o.I.moveRight(e.cursorConfig,e,t.viewState,i,s))))}static _moveHalfLineRight(e,t,i){const s=[];for(let n=0,a=t.length;n{"use strict";(0,i(34918).K)({id:"scala",extensions:[".scala",".sc",".sbt"],aliases:["Scala","scala","SBT","Sbt","sbt","Dotty","dotty"],mimetypes:["text/x-scala-source","text/x-scala","text/x-sbt","text/x-dotty"],loader:()=>i.e(56358).then(i.bind(i,56358))})},28433:(e,t,i)=>{"use strict";i.d(t,{T:()=>p});var s=i(8597),n=i(94106),r=i(41234),o=i(5662),a=i(73157);class c{constructor(e,t){this.chr=e,this.type=t,this.width=0}fulfill(e){this.width=e}}class l{constructor(e,t){this._bareFontInfo=e,this._requests=t,this._container=null,this._testElements=null}read(e){this._createDomElements(),e.document.body.appendChild(this._container),this._readFromDomElements(),this._container?.remove(),this._container=null,this._testElements=null}_createDomElements(){const e=document.createElement("div");e.style.position="absolute",e.style.top="-50000px",e.style.width="50000px";const t=document.createElement("div");(0,a.M)(t,this._bareFontInfo),e.appendChild(t);const i=document.createElement("div");(0,a.M)(i,this._bareFontInfo),i.style.fontWeight="bold",e.appendChild(i);const s=document.createElement("div");(0,a.M)(s,this._bareFontInfo),s.style.fontStyle="italic",e.appendChild(s);const n=[];for(const r of this._requests){let e;0===r.type&&(e=t),2===r.type&&(e=i),1===r.type&&(e=s),e.appendChild(document.createElement("br"));const o=document.createElement("span");l._render(o,r),e.appendChild(o),n.push(o)}this._container=e,this._testElements=n}static _render(e,t){if(" "===t.chr){let t="\xa0";for(let e=0;e<8;e++)t+=t;e.innerText=t}else{let i=t.chr;for(let e=0;e<8;e++)i+=i;e.textContent=i}}_readFromDomElements(){for(let e=0,t=this._requests.length;e{this._evictUntrustedReadingsTimeout=-1,this._evictUntrustedReadings(e)}),5e3))}_evictUntrustedReadings(e){const t=this._ensureCache(e),i=t.getValues();let s=!1;for(const n of i)n.isTrusted||(s=!0,t.remove(n));s&&this._onDidChange.fire()}readFontInfo(e,t){const i=this._ensureCache(e);if(!i.has(t)){let i=this._actualReadFontInfo(e,t);(i.typicalHalfwidthCharacterWidth<=2||i.typicalFullwidthCharacterWidth<=2||i.spaceWidth<=2||i.maxDigitWidth<=2)&&(i=new d.YJ({pixelRatio:n.c.getInstance(e).value,fontFamily:i.fontFamily,fontWeight:i.fontWeight,fontSize:i.fontSize,fontFeatureSettings:i.fontFeatureSettings,fontVariationSettings:i.fontVariationSettings,lineHeight:i.lineHeight,letterSpacing:i.letterSpacing,isMonospace:i.isMonospace,typicalHalfwidthCharacterWidth:Math.max(i.typicalHalfwidthCharacterWidth,5),typicalFullwidthCharacterWidth:Math.max(i.typicalFullwidthCharacterWidth,5),canUseHalfwidthRightwardsArrow:i.canUseHalfwidthRightwardsArrow,spaceWidth:Math.max(i.spaceWidth,5),middotWidth:Math.max(i.middotWidth,5),wsmiddotWidth:Math.max(i.wsmiddotWidth,5),maxDigitWidth:Math.max(i.maxDigitWidth,5)},!1)),this._writeToCache(e,t,i)}return i.get(t)}_createRequest(e,t,i,s){const n=new c(e,t);return i.push(n),s?.push(n),n}_actualReadFontInfo(e,t){const i=[],s=[],r=this._createRequest("n",0,i,s),o=this._createRequest("\uff4d",0,i,null),a=this._createRequest(" ",0,i,s),c=this._createRequest("0",0,i,s),u=this._createRequest("1",0,i,s),g=this._createRequest("2",0,i,s),p=this._createRequest("3",0,i,s),m=this._createRequest("4",0,i,s),f=this._createRequest("5",0,i,s),_=this._createRequest("6",0,i,s),v=this._createRequest("7",0,i,s),C=this._createRequest("8",0,i,s),E=this._createRequest("9",0,i,s),b=this._createRequest("\u2192",0,i,s),S=this._createRequest("\uffeb",0,i,null),y=this._createRequest("\xb7",0,i,s),w=this._createRequest(String.fromCharCode(11825),0,i,null),R="|/-_ilm%";for(let n=0,l=8;n.001){T=!1;break}}let k=!0;return T&&S.width!==x&&(k=!1),S.width>b.width&&(k=!1),new d.YJ({pixelRatio:n.c.getInstance(e).value,fontFamily:t.fontFamily,fontWeight:t.fontWeight,fontSize:t.fontSize,fontFeatureSettings:t.fontFeatureSettings,fontVariationSettings:t.fontVariationSettings,lineHeight:t.lineHeight,letterSpacing:t.letterSpacing,isMonospace:T,typicalHalfwidthCharacterWidth:r.width,typicalFullwidthCharacterWidth:o.width,canUseHalfwidthRightwardsArrow:k,spaceWidth:a.width,middotWidth:y.width,wsmiddotWidth:w.width,maxDigitWidth:L},!0)}}class g{constructor(){this._keys=Object.create(null),this._values=Object.create(null)}has(e){const t=e.getId();return!!this._values[t]}get(e){const t=e.getId();return this._values[t]}put(e,t){const i=e.getId();this._keys[i]=e,this._values[i]=t}remove(e){const t=e.getId();delete this._keys[t],delete this._values[t]}getValues(){return Object.keys(this._keys).map((e=>this._values[e]))}}const p=new u},28449:(e,t,i)=>{"use strict";var s=i(90766),n=i(64383),r=i(50868),o=i(31450),a=i(36677),c=i(75326),l=i(60002),h=i(87289),d=i(10920),u=i(78209);class g{constructor(e,t,i){this._editRange=e,this._originalSelection=t,this._text=i}getEditOperations(e,t){t.addTrackedEditOperation(this._editRange,this._text)}computeCursorState(e,t){const i=t.getInverseEditOperations()[0].range;return this._originalSelection.isEmpty()?new c.L(i.endLineNumber,Math.min(this._originalSelection.positionColumn,i.endColumn),i.endLineNumber,Math.min(this._originalSelection.positionColumn,i.endColumn)):new c.L(i.endLineNumber,i.endColumn-this._text.length,i.endLineNumber,i.endColumn)}}var p,m=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},f=function(e,t){return function(i,s){t(i,s,e)}};let _=class{static{p=this}static{this.ID="editor.contrib.inPlaceReplaceController"}static get(e){return e.getContribution(p.ID)}static{this.DECORATION=h.kI.register({description:"in-place-replace",className:"valueSetReplacement"})}constructor(e,t){this.editor=e,this.editorWorkerService=t,this.decorations=this.editor.createDecorationsCollection()}dispose(){}run(e,t){this.currentRequest?.cancel();const i=this.editor.getSelection(),o=this.editor.getModel();if(!o||!i)return;let l=i;if(l.startLineNumber!==l.endLineNumber)return;const h=new r.$t(this.editor,5),d=o.uri;return this.editorWorkerService.canNavigateValueSet(d)?(this.currentRequest=(0,s.SS)((e=>this.editorWorkerService.navigateValueSet(d,l,t))),this.currentRequest.then((t=>{if(!t||!t.range||!t.value)return;if(!h.validate(this.editor))return;const i=a.Q.lift(t.range);let r=t.range;const o=t.value.length-(l.endColumn-l.startColumn);r={startLineNumber:r.startLineNumber,startColumn:r.startColumn,endLineNumber:r.endLineNumber,endColumn:r.startColumn+t.value.length},o>1&&(l=new c.L(l.startLineNumber,l.startColumn,l.endLineNumber,l.endColumn+o-1));const d=new g(i,l,t.value);this.editor.pushUndoStop(),this.editor.executeCommand(e,d),this.editor.pushUndoStop(),this.decorations.set([{range:r,options:p.DECORATION}]),this.decorationRemover?.cancel(),this.decorationRemover=(0,s.wR)(350),this.decorationRemover.then((()=>this.decorations.clear())).catch(n.dz)})).catch(n.dz)):Promise.resolve(void 0)}};_=p=m([f(1,d.IEditorWorkerService)],_);class v extends o.ks{constructor(){super({id:"editor.action.inPlaceReplace.up",label:u.kg("InPlaceReplaceAction.previous.label","Replace with Previous Value"),alias:"Replace with Previous Value",precondition:l.R.writable,kbOpts:{kbExpr:l.R.editorTextFocus,primary:3159,weight:100}})}run(e,t){const i=_.get(t);return i?i.run(this.id,!1):Promise.resolve(void 0)}}class C extends o.ks{constructor(){super({id:"editor.action.inPlaceReplace.down",label:u.kg("InPlaceReplaceAction.next.label","Replace with Next Value"),alias:"Replace with Next Value",precondition:l.R.writable,kbOpts:{kbExpr:l.R.editorTextFocus,primary:3161,weight:100}})}run(e,t){const i=_.get(t);return i?i.run(this.id,!0):Promise.resolve(void 0)}}(0,o.HW)(_.ID,_,4),(0,o.Fl)(v),(0,o.Fl)(C)},28712:(e,t,i)=>{"use strict";i.d(t,{BJ:()=>P,WE:()=>U});var s=i(90766),n=i(18447),r=i(47661),o=i(5662),a=i(36677),c=i(68310),l=i(9772),h=i(41234);class d{get color(){return this._color}set color(e){this._color.equals(e)||(this._color=e,this._onDidChangeColor.fire(e))}get presentation(){return this.colorPresentations[this.presentationIndex]}get colorPresentations(){return this._colorPresentations}set colorPresentations(e){this._colorPresentations=e,this.presentationIndex>e.length-1&&(this.presentationIndex=0),this._onDidChangePresentation.fire(this.presentation)}constructor(e,t,i){this.presentationIndex=i,this._onColorFlushed=new h.vl,this.onColorFlushed=this._onColorFlushed.event,this._onDidChangeColor=new h.vl,this.onDidChangeColor=this._onDidChangeColor.event,this._onDidChangePresentation=new h.vl,this.onDidChangePresentation=this._onDidChangePresentation.event,this.originalColor=e,this._color=e,this._colorPresentations=t}selectNextColorPresentation(){this.presentationIndex=(this.presentationIndex+1)%this.colorPresentations.length,this.flushColor(),this._onDidChangePresentation.fire(this.presentation)}guessColorPresentation(e,t){let i=-1;for(let s=0;s{this.backgroundColor=e.getColor(C.WfR)||r.Q1.white}))),this._register(g.ko(this._pickedColorNode,g.Bx.CLICK,(()=>this.model.selectNextColorPresentation()))),this._register(g.ko(this._originalColorNode,g.Bx.CLICK,(()=>{this.model.color=this.model.originalColor,this.model.flushColor()}))),this._register(t.onDidChangeColor(this.onDidChangeColor,this)),this._register(t.onDidChangePresentation(this.onDidChangePresentation,this)),this._pickedColorNode.style.backgroundColor=r.Q1.Format.CSS.format(t.color)||"",this._pickedColorNode.classList.toggle("light",t.color.rgba.a<.5?this.backgroundColor.isLighter():t.color.isLighter()),this.onDidChangeColor(this.model.color),this.showingStandaloneColorPicker&&(this._domNode.classList.add("standalone-colorpicker"),this._closeButton=this._register(new y(this._domNode)))}get closeButton(){return this._closeButton}get pickedColorNode(){return this._pickedColorNode}get originalColorNode(){return this._originalColorNode}onDidChangeColor(e){this._pickedColorNode.style.backgroundColor=r.Q1.Format.CSS.format(e)||"",this._pickedColorNode.classList.toggle("light",e.rgba.a<.5?this.backgroundColor.isLighter():e.isLighter()),this.onDidChangePresentation()}onDidChangePresentation(){this._pickedColorPresentation.textContent=this.model.presentation?this.model.presentation.label:""}}class y extends o.jG{constructor(e){super(),this._onClicked=this._register(new h.vl),this.onClicked=this._onClicked.event,this._button=document.createElement("div"),this._button.classList.add("close-button"),g.BC(e,this._button);const t=document.createElement("div");t.classList.add("close-button-inner-div"),g.BC(this._button,t);g.BC(t,b(".button"+_.L.asCSSSelector((0,E.pU)("color-picker-close",f.W.close,(0,v.kg)("closeIcon","Icon to close the color picker"))))).classList.add("close-icon"),this._register(g.ko(this._button,g.Bx.CLICK,(()=>{this._onClicked.fire()})))}}class w extends o.jG{constructor(e,t,i,s=!1){super(),this.model=t,this.pixelRatio=i,this._insertButton=null,this._domNode=b(".colorpicker-body"),g.BC(e,this._domNode),this._saturationBox=new R(this._domNode,this.model,this.pixelRatio),this._register(this._saturationBox),this._register(this._saturationBox.onDidChange(this.onDidSaturationValueChange,this)),this._register(this._saturationBox.onColorFlushed(this.flushColor,this)),this._opacityStrip=new T(this._domNode,this.model,s),this._register(this._opacityStrip),this._register(this._opacityStrip.onDidChange(this.onDidOpacityChange,this)),this._register(this._opacityStrip.onColorFlushed(this.flushColor,this)),this._hueStrip=new x(this._domNode,this.model,s),this._register(this._hueStrip),this._register(this._hueStrip.onDidChange(this.onDidHueChange,this)),this._register(this._hueStrip.onColorFlushed(this.flushColor,this)),s&&(this._insertButton=this._register(new k(this._domNode)),this._domNode.classList.add("standalone-colorpicker"))}flushColor(){this.model.flushColor()}onDidSaturationValueChange({s:e,v:t}){const i=this.model.color.hsva;this.model.color=new r.Q1(new r.$J(i.h,e,t,i.a))}onDidOpacityChange(e){const t=this.model.color.hsva;this.model.color=new r.Q1(new r.$J(t.h,t.s,t.v,e))}onDidHueChange(e){const t=this.model.color.hsva,i=360*(1-e);this.model.color=new r.Q1(new r.$J(360===i?0:i,t.s,t.v,t.a))}get domNode(){return this._domNode}get saturationBox(){return this._saturationBox}get enterButton(){return this._insertButton}layout(){this._saturationBox.layout(),this._opacityStrip.layout(),this._hueStrip.layout()}}class R extends o.jG{constructor(e,t,i){super(),this.model=t,this.pixelRatio=i,this._onDidChange=new h.vl,this.onDidChange=this._onDidChange.event,this._onColorFlushed=new h.vl,this.onColorFlushed=this._onColorFlushed.event,this._domNode=b(".saturation-wrap"),g.BC(e,this._domNode),this._canvas=document.createElement("canvas"),this._canvas.className="saturation-box",g.BC(this._domNode,this._canvas),this.selection=b(".saturation-selection"),g.BC(this._domNode,this.selection),this.layout(),this._register(g.ko(this._domNode,g.Bx.POINTER_DOWN,(e=>this.onPointerDown(e)))),this._register(this.model.onDidChangeColor(this.onDidChangeColor,this)),this.monitor=null}get domNode(){return this._domNode}onPointerDown(e){if(!e.target||!(e.target instanceof Element))return;this.monitor=this._register(new p._);const t=g.BK(this._domNode);e.target!==this.selection&&this.onDidChangePosition(e.offsetX,e.offsetY),this.monitor.startMonitoring(e.target,e.pointerId,e.buttons,(e=>this.onDidChangePosition(e.pageX-t.left,e.pageY-t.top)),(()=>null));const i=g.ko(e.target.ownerDocument,g.Bx.POINTER_UP,(()=>{this._onColorFlushed.fire(),i.dispose(),this.monitor&&(this.monitor.stopMonitoring(!0),this.monitor=null)}),!0)}onDidChangePosition(e,t){const i=Math.max(0,Math.min(1,e/this.width)),s=Math.max(0,Math.min(1,1-t/this.height));this.paintSelection(i,s),this._onDidChange.fire({s:i,v:s})}layout(){this.width=this._domNode.offsetWidth,this.height=this._domNode.offsetHeight,this._canvas.width=this.width*this.pixelRatio,this._canvas.height=this.height*this.pixelRatio,this.paint();const e=this.model.color.hsva;this.paintSelection(e.s,e.v)}paint(){const e=this.model.color.hsva,t=new r.Q1(new r.$J(e.h,1,1,1)),i=this._canvas.getContext("2d"),s=i.createLinearGradient(0,0,this._canvas.width,0);s.addColorStop(0,"rgba(255, 255, 255, 1)"),s.addColorStop(.5,"rgba(255, 255, 255, 0.5)"),s.addColorStop(1,"rgba(255, 255, 255, 0)");const n=i.createLinearGradient(0,0,0,this._canvas.height);n.addColorStop(0,"rgba(0, 0, 0, 0)"),n.addColorStop(1,"rgba(0, 0, 0, 1)"),i.rect(0,0,this._canvas.width,this._canvas.height),i.fillStyle=r.Q1.Format.CSS.format(t),i.fill(),i.fillStyle=s,i.fill(),i.fillStyle=n,i.fill()}paintSelection(e,t){this.selection.style.left=e*this.width+"px",this.selection.style.top=this.height-t*this.height+"px"}onDidChangeColor(e){if(this.monitor&&this.monitor.isMonitoring())return;this.paint();const t=e.hsva;this.paintSelection(t.s,t.v)}}class L extends o.jG{constructor(e,t,i=!1){super(),this.model=t,this._onDidChange=new h.vl,this.onDidChange=this._onDidChange.event,this._onColorFlushed=new h.vl,this.onColorFlushed=this._onColorFlushed.event,i?(this.domNode=g.BC(e,b(".standalone-strip")),this.overlay=g.BC(this.domNode,b(".standalone-overlay"))):(this.domNode=g.BC(e,b(".strip")),this.overlay=g.BC(this.domNode,b(".overlay"))),this.slider=g.BC(this.domNode,b(".slider")),this.slider.style.top="0px",this._register(g.ko(this.domNode,g.Bx.POINTER_DOWN,(e=>this.onPointerDown(e)))),this._register(t.onDidChangeColor(this.onDidChangeColor,this)),this.layout()}layout(){this.height=this.domNode.offsetHeight-this.slider.offsetHeight;const e=this.getValue(this.model.color);this.updateSliderPosition(e)}onDidChangeColor(e){const t=this.getValue(e);this.updateSliderPosition(t)}onPointerDown(e){if(!e.target||!(e.target instanceof Element))return;const t=this._register(new p._),i=g.BK(this.domNode);this.domNode.classList.add("grabbing"),e.target!==this.slider&&this.onDidChangeTop(e.offsetY),t.startMonitoring(e.target,e.pointerId,e.buttons,(e=>this.onDidChangeTop(e.pageY-i.top)),(()=>null));const s=g.ko(e.target.ownerDocument,g.Bx.POINTER_UP,(()=>{this._onColorFlushed.fire(),s.dispose(),t.stopMonitoring(!0),this.domNode.classList.remove("grabbing")}),!0)}onDidChangeTop(e){const t=Math.max(0,Math.min(1,1-e/this.height));this.updateSliderPosition(t),this._onDidChange.fire(t)}updateSliderPosition(e){this.slider.style.top=(1-e)*this.height+"px"}}class T extends L{constructor(e,t,i=!1){super(e,t,i),this.domNode.classList.add("opacity-strip"),this.onDidChangeColor(this.model.color)}onDidChangeColor(e){super.onDidChangeColor(e);const{r:t,g:i,b:s}=e.rgba,n=new r.Q1(new r.bU(t,i,s,1)),o=new r.Q1(new r.bU(t,i,s,0));this.overlay.style.background=`linear-gradient(to bottom, ${n} 0%, ${o} 100%)`}getValue(e){return e.hsva.a}}class x extends L{constructor(e,t,i=!1){super(e,t,i),this.domNode.classList.add("hue-strip")}getValue(e){return 1-e.hsva.h/360}}class k extends o.jG{constructor(e){super(),this._onClicked=this._register(new h.vl),this.onClicked=this._onClicked.event,this._button=g.BC(e,document.createElement("button")),this._button.classList.add("insert-button"),this._button.textContent="Insert",this._register(g.ko(this._button,g.Bx.CLICK,(()=>{this._onClicked.fire()})))}get button(){return this._button}}class A extends m.x{constructor(e,t,i,s,n=!1){super(),this.model=t,this.pixelRatio=i,this._register(u.c.getInstance(g.zk(e)).onDidChange((()=>this.layout()))),this._domNode=b(".colorpicker-widget"),e.appendChild(this._domNode),this.header=this._register(new S(this._domNode,this.model,s,n)),this.body=this._register(new w(this._domNode,this.model,this.pixelRatio,n))}layout(){this.body.layout()}get domNode(){return this._domNode}}var N=i(57039),I=i(47612),O=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},D=function(e,t){return function(i,s){t(i,s,e)}};class M{constructor(e,t,i,s){this.owner=e,this.range=t,this.model=i,this.provider=s,this.forceShowAtRange=!0}isValidForHoverAnchor(e){return 1===e.type&&this.range.startColumn<=e.range.startColumn&&this.range.endColumn>=e.range.endColumn}}let P=class{constructor(e,t){this._editor=e,this._themeService=t,this.hoverOrdinal=2}computeSync(e,t){return[]}computeAsync(e,t,i){return s.AE.fromPromise(this._computeAsync(e,t,i))}async _computeAsync(e,t,i){if(!this._editor.hasModel())return[];const s=l.mn.get(this._editor);if(!s)return[];for(const n of t){if(!s.isColorDecoration(n))continue;const e=s.getColorData(n.range.getStartPosition());if(e){return[await H(this,this._editor.getModel(),e.colorInfo,e.provider)]}}return[]}renderHoverParts(e,t){const i=B(this,this._editor,this._themeService,t,e);if(!i)return new N.Ke([]);this._colorPicker=i.colorPicker;const s={hoverPart:i.hoverPart,hoverElement:this._colorPicker.domNode,dispose(){i.disposables.dispose()}};return new N.Ke([s])}handleResize(){this._colorPicker?.layout()}isColorPickerVisible(){return!!this._colorPicker}};P=O([D(1,I.Gy)],P);class F{constructor(e,t,i,s){this.owner=e,this.range=t,this.model=i,this.provider=s}}let U=class{constructor(e,t){this._editor=e,this._themeService=t,this._color=null}async createColorHover(e,t,i){if(!this._editor.hasModel())return null;if(!l.mn.get(this._editor))return null;const s=await(0,c.j)(i,this._editor.getModel(),n.XO.None);let r=null,o=null;for(const n of s){const t=n.colorInfo;a.Q.containsRange(t.range,e.range)&&(r=t,o=n.provider)}const h=r??e,d=o??t,u=!!r;return{colorHover:await H(this,this._editor.getModel(),h,d),foundInEditor:u}}async updateEditorModel(e){if(!this._editor.hasModel())return;const t=e.model;let i=new a.Q(e.range.startLineNumber,e.range.startColumn,e.range.endLineNumber,e.range.endColumn);this._color&&(await V(this._editor.getModel(),t,this._color,i,e),i=W(this._editor,i,t))}renderHoverParts(e,t){return B(this,this._editor,this._themeService,t,e)}set color(e){this._color=e}get color(){return this._color}};async function H(e,t,i,s){const o=t.getValueInRange(i.range),{red:l,green:h,blue:u,alpha:g}=i.color,p=new r.bU(Math.round(255*l),Math.round(255*h),Math.round(255*u),g),m=new r.Q1(p),f=await(0,c.R)(t,i,s,n.XO.None),_=new d(m,[],0);return _.colorPresentations=f||[],_.guessColorPresentation(m,o),e instanceof P?new M(e,a.Q.lift(i.range),_,s):new F(e,a.Q.lift(i.range),_,s)}function B(e,t,i,s,n){if(0===s.length||!t.hasModel())return;if(n.setMinimumDimensions){const e=t.getOption(67)+8;n.setMinimumDimensions(new g.fg(302,e))}const r=new o.Cm,c=s[0],l=t.getModel(),h=c.model,d=r.add(new A(n.fragment,h,t.getOption(144),i,e instanceof U));let u=!1,p=new a.Q(c.range.startLineNumber,c.range.startColumn,c.range.endLineNumber,c.range.endColumn);if(e instanceof U){const t=c.model.color;e.color=t,V(l,h,t,p,c),r.add(h.onColorFlushed((t=>{e.color=t})))}else r.add(h.onColorFlushed((async e=>{await V(l,h,e,p,c),u=!0,p=W(t,p,h)})));return r.add(h.onDidChangeColor((e=>{V(l,h,e,p,c)}))),r.add(t.onDidChangeModelContent((e=>{u?u=!1:(n.hide(),t.focus())}))),{hoverPart:c,colorPicker:d,disposables:r}}function W(e,t,i){const s=[],n=i.presentation.textEdit??{range:t,text:i.presentation.label,forceMoveMarkers:!1};s.push(n),i.presentation.additionalTextEdits&&s.push(...i.presentation.additionalTextEdits);const r=a.Q.lift(n.range),o=e.getModel()._setTrackedRange(null,r,3);return e.executeEdits("colorpicker",s),e.pushUndoStop(),e.getModel()._getTrackedRange(o)??r}async function V(e,t,i,s,r){const o=await(0,c.R)(e,{range:s,color:{red:i.rgba.r/255,green:i.rgba.g/255,blue:i.rgba.b/255,alpha:i.rgba.a}},r.provider,n.XO.None);t.colorPresentations=o||[]}U=O([D(1,I.Gy)],U)},29100:(e,t,i)=>{"use strict";i.r(t),i.d(t,{ITreeViewsDnDService:()=>o});var s=i(14718),n=i(63591),r=i(36723);const o=(0,n.u1)("treeViewsDndService");(0,s.v)(o,r.TreeViewsDnDService,1)},29163:(e,t,i)=>{"use strict";i.d(t,{t:()=>f});var s=i(10146),n=i(80301),r=i(52555),o=i(17469),a=i(56942),c=i(253),l=i(50091),h=i(32848),d=i(63591),u=i(58591),g=i(47612),p=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},m=function(e,t){return function(i,s){t(i,s,e)}};let f=class extends r.x{constructor(e,t,i,s,n,r,o,a,c,l,h,d,u){super(e,{...s.getRawOptions(),overflowWidgetsDomNode:s.getOverflowWidgetsDomNode()},i,n,r,o,a,c,l,h,d,u),this._parentEditor=s,this._overwriteOptions=t,super.updateOptions(this._overwriteOptions),this._register(s.onDidChangeConfiguration((e=>this._onParentConfigurationChanged(e))))}getParentEditor(){return this._parentEditor}_onParentConfigurationChanged(e){super.updateOptions(this._parentEditor.getRawOptions()),super.updateOptions(this._overwriteOptions)}updateOptions(e){s.co(this._overwriteOptions,e,!0),super.updateOptions(this._overwriteOptions)}};f=p([m(4,d._Y),m(5,n.T),m(6,l.d),m(7,h.fN),m(8,g.Gy),m(9,u.Ot),m(10,c.j),m(11,o.JZ),m(12,a.ILanguageFeaturesService)],f)},29319:(e,t,i)=>{"use strict";i.d(t,{EY:()=>r,GR:()=>c,Or:()=>a,fr:()=>p,mQ:()=>g});class s{constructor(){this.value="",this.pos=0}static{this._table={36:0,58:1,44:2,123:3,125:4,92:5,47:6,124:7,43:11,45:12,63:13}}static isDigitCharacter(e){return e>=48&&e<=57}static isVariableCharacter(e){return 95===e||e>=97&&e<=122||e>=65&&e<=90}text(e){this.value=e,this.pos=0}tokenText(e){return this.value.substr(e.pos,e.len)}next(){if(this.pos>=this.value.length)return{type:14,pos:this.pos,len:0};const e=this.pos;let t,i=0,n=this.value.charCodeAt(e);if(t=s._table[n],"number"===typeof t)return this.pos+=1,{type:t,pos:e,len:1};if(s.isDigitCharacter(n)){t=8;do{i+=1,n=this.value.charCodeAt(e+i)}while(s.isDigitCharacter(n));return this.pos+=i,{type:t,pos:e,len:i}}if(s.isVariableCharacter(n)){t=9;do{n=this.value.charCodeAt(e+ ++i)}while(s.isVariableCharacter(n)||s.isDigitCharacter(n));return this.pos+=i,{type:t,pos:e,len:i}}t=10;do{i+=1,n=this.value.charCodeAt(e+i)}while(!isNaN(n)&&"undefined"===typeof s._table[n]&&!s.isDigitCharacter(n)&&!s.isVariableCharacter(n));return this.pos+=i,{type:t,pos:e,len:i}}}class n{constructor(){this._children=[]}appendChild(e){return e instanceof r&&this._children[this._children.length-1]instanceof r?this._children[this._children.length-1].value+=e.value:(e.parent=this,this._children.push(e)),this}replace(e,t){const{parent:i}=e,s=i.children.indexOf(e),n=i.children.slice(0);n.splice(s,1,...t),i._children=n,function e(t,i){for(const s of t)s.parent=i,e(s.children,s)}(t,i)}get children(){return this._children}get rightMostDescendant(){return this._children.length>0?this._children[this._children.length-1].rightMostDescendant:this}get snippet(){let e=this;for(;;){if(!e)return;if(e instanceof g)return e;e=e.parent}}toString(){return this.children.reduce(((e,t)=>e+t.toString()),"")}len(){return 0}}class r extends n{constructor(e){super(),this.value=e}toString(){return this.value}len(){return this.value.length}clone(){return new r(this.value)}}class o extends n{}class a extends o{static compareByIndex(e,t){return e.index===t.index?0:e.isFinalTabstop?1:t.isFinalTabstop||e.indext.index?1:0}constructor(e){super(),this.index=e}get isFinalTabstop(){return 0===this.index}get choice(){return 1===this._children.length&&this._children[0]instanceof c?this._children[0]:void 0}clone(){const e=new a(this.index);return this.transform&&(e.transform=this.transform.clone()),e._children=this.children.map((e=>e.clone())),e}}class c extends n{constructor(){super(...arguments),this.options=[]}appendChild(e){return e instanceof r&&(e.parent=this,this.options.push(e)),this}toString(){return this.options[0].value}len(){return this.options[0].len()}clone(){const e=new c;return this.options.forEach(e.appendChild,e),e}}class l extends n{constructor(){super(...arguments),this.regexp=new RegExp("")}resolve(e){const t=this;let i=!1,s=e.replace(this.regexp,(function(){return i=!0,t._replace(Array.prototype.slice.call(arguments,0,-2))}));return!i&&this._children.some((e=>e instanceof h&&Boolean(e.elseValue)))&&(s=this._replace([])),s}_replace(e){let t="";for(const i of this._children)if(i instanceof h){let s=e[i.index]||"";s=i.resolve(s),t+=s}else t+=i.toString();return t}toString(){return""}clone(){const e=new l;return e.regexp=new RegExp(this.regexp.source,(this.regexp.ignoreCase?"i":"")+(this.regexp.global?"g":"")),e._children=this.children.map((e=>e.clone())),e}}class h extends n{constructor(e,t,i,s){super(),this.index=e,this.shorthandName=t,this.ifValue=i,this.elseValue=s}resolve(e){return"upcase"===this.shorthandName?e?e.toLocaleUpperCase():"":"downcase"===this.shorthandName?e?e.toLocaleLowerCase():"":"capitalize"===this.shorthandName?e?e[0].toLocaleUpperCase()+e.substr(1):"":"pascalcase"===this.shorthandName?e?this._toPascalCase(e):"":"camelcase"===this.shorthandName?e?this._toCamelCase(e):"":Boolean(e)&&"string"===typeof this.ifValue?this.ifValue:Boolean(e)||"string"!==typeof this.elseValue?e||"":this.elseValue}_toPascalCase(e){const t=e.match(/[a-z0-9]+/gi);return t?t.map((e=>e.charAt(0).toUpperCase()+e.substr(1))).join(""):e}_toCamelCase(e){const t=e.match(/[a-z0-9]+/gi);return t?t.map(((e,t)=>0===t?e.charAt(0).toLowerCase()+e.substr(1):e.charAt(0).toUpperCase()+e.substr(1))).join(""):e}clone(){return new h(this.index,this.shorthandName,this.ifValue,this.elseValue)}}class d extends o{constructor(e){super(),this.name=e}resolve(e){let t=e.resolve(this);return this.transform&&(t=this.transform.resolve(t||"")),void 0!==t&&(this._children=[new r(t)],!0)}clone(){const e=new d(this.name);return this.transform&&(e.transform=this.transform.clone()),e._children=this.children.map((e=>e.clone())),e}}function u(e,t){const i=[...e];for(;i.length>0;){const e=i.shift();if(!t(e))break;i.unshift(...e.children)}}class g extends n{get placeholderInfo(){if(!this._placeholders){const e=[];let t;this.walk((function(i){return i instanceof a&&(e.push(i),t=!t||t.indexs===e?(i=!0,!1):(t+=s.len(),!0))),i?t:-1}fullLen(e){let t=0;return u([e],(e=>(t+=e.len(),!0))),t}enclosingPlaceholders(e){const t=[];let{parent:i}=e;for(;i;)i instanceof a&&t.push(i),i=i.parent;return t}resolveVariables(e){return this.walk((t=>(t instanceof d&&t.resolve(e)&&(this._placeholders=void 0),!0))),this}appendChild(e){return this._placeholders=void 0,super.appendChild(e)}replace(e,t){return this._placeholders=void 0,super.replace(e,t)}clone(){const e=new g;return this._children=this.children.map((e=>e.clone())),e}walk(e){u(this.children,e)}}class p{constructor(){this._scanner=new s,this._token={type:14,pos:0,len:0}}static escape(e){return e.replace(/\$|}|\\/g,"\\$&")}static guessNeedsClipboard(e){return/\${?CLIPBOARD/.test(e)}parse(e,t,i){const s=new g;return this.parseFragment(e,s),this.ensureFinalTabstop(s,i??!1,t??!1),s}parseFragment(e,t){const i=t.children.length;for(this._scanner.text(e),this._token=this._scanner.next();this._parse(t););const s=new Map,n=[];t.walk((e=>(e instanceof a&&(e.isFinalTabstop?s.set(0,void 0):!s.has(e.index)&&e.children.length>0?s.set(e.index,e.children):n.push(e)),!0)));const r=(e,i)=>{const n=s.get(e.index);if(!n)return;const o=new a(e.index);o.transform=e.transform;for(const t of n){const e=t.clone();o.appendChild(e),e instanceof a&&s.has(e.index)&&!i.has(e.index)&&(i.add(e.index),r(e,i),i.delete(e.index))}t.replace(e,[o])},o=new Set;for(const a of n)r(a,o);return t.children.slice(i)}ensureFinalTabstop(e,t,i){if(t||i&&e.placeholders.length>0){e.placeholders.find((e=>0===e.index))||e.appendChild(new a(0))}}_accept(e,t){if(void 0===e||this._token.type===e){const e=!t||this._scanner.tokenText(this._token);return this._token=this._scanner.next(),e}return!1}_backTo(e){return this._scanner.pos=e.pos+e.len,this._token=e,!1}_until(e){const t=this._token;for(;this._token.type!==e;){if(14===this._token.type)return!1;if(5===this._token.type){const e=this._scanner.next();if(0!==e.type&&4!==e.type&&5!==e.type)return!1}this._token=this._scanner.next()}const i=this._scanner.value.substring(t.pos,this._token.pos).replace(/\\(\$|}|\\)/g,"$1");return this._token=this._scanner.next(),i}_parse(e){return this._parseEscaped(e)||this._parseTabstopOrVariableName(e)||this._parseComplexPlaceholder(e)||this._parseComplexVariable(e)||this._parseAnything(e)}_parseEscaped(e){let t;return!!(t=this._accept(5,!0))&&(t=this._accept(0,!0)||this._accept(4,!0)||this._accept(5,!0)||t,e.appendChild(new r(t)),!0)}_parseTabstopOrVariableName(e){let t;const i=this._token;return this._accept(0)&&(t=this._accept(9,!0)||this._accept(8,!0))?(e.appendChild(/^\d+$/.test(t)?new a(Number(t)):new d(t)),!0):this._backTo(i)}_parseComplexPlaceholder(e){let t;const i=this._token;if(!(this._accept(0)&&this._accept(3)&&(t=this._accept(8,!0))))return this._backTo(i);const s=new a(Number(t));if(this._accept(1))for(;;){if(this._accept(4))return e.appendChild(s),!0;if(!this._parse(s))return e.appendChild(new r("${"+t+":")),s.children.forEach(e.appendChild,e),!0}else{if(!(s.index>0&&this._accept(7)))return this._accept(6)?this._parseTransform(s)?(e.appendChild(s),!0):(this._backTo(i),!1):this._accept(4)?(e.appendChild(s),!0):this._backTo(i);{const t=new c;for(;;){if(this._parseChoiceElement(t)){if(this._accept(2))continue;if(this._accept(7)&&(s.appendChild(t),this._accept(4)))return e.appendChild(s),!0}return this._backTo(i),!1}}}}_parseChoiceElement(e){const t=this._token,i=[];for(;2!==this._token.type&&7!==this._token.type;){let e;if(e=(e=this._accept(5,!0))?this._accept(2,!0)||this._accept(7,!0)||this._accept(5,!0)||e:this._accept(void 0,!0),!e)return this._backTo(t),!1;i.push(e)}return 0===i.length?(this._backTo(t),!1):(e.appendChild(new r(i.join(""))),!0)}_parseComplexVariable(e){let t;const i=this._token;if(!(this._accept(0)&&this._accept(3)&&(t=this._accept(9,!0))))return this._backTo(i);const s=new d(t);if(!this._accept(1))return this._accept(6)?this._parseTransform(s)?(e.appendChild(s),!0):(this._backTo(i),!1):this._accept(4)?(e.appendChild(s),!0):this._backTo(i);for(;;){if(this._accept(4))return e.appendChild(s),!0;if(!this._parse(s))return e.appendChild(new r("${"+t+":")),s.children.forEach(e.appendChild,e),!0}}_parseTransform(e){const t=new l;let i="",s="";for(;!this._accept(6);){let e;if(e=this._accept(5,!0))e=this._accept(6,!0)||e,i+=e;else{if(14===this._token.type)return!1;i+=this._accept(void 0,!0)}}for(;!this._accept(6);){let e;if(e=this._accept(5,!0))e=this._accept(5,!0)||this._accept(6,!0)||e,t.appendChild(new r(e));else if(!this._parseFormatString(t)&&!this._parseAnything(t))return!1}for(;!this._accept(4);){if(14===this._token.type)return!1;s+=this._accept(void 0,!0)}try{t.regexp=new RegExp(i,s)}catch(n){return!1}return e.transform=t,!0}_parseFormatString(e){const t=this._token;if(!this._accept(0))return!1;let i=!1;this._accept(3)&&(i=!0);const s=this._accept(8,!0);if(!s)return this._backTo(t),!1;if(!i)return e.appendChild(new h(Number(s))),!0;if(this._accept(4))return e.appendChild(new h(Number(s))),!0;if(!this._accept(1))return this._backTo(t),!1;if(this._accept(6)){const i=this._accept(9,!0);return i&&this._accept(4)?(e.appendChild(new h(Number(s),i)),!0):(this._backTo(t),!1)}if(this._accept(11)){const t=this._until(4);if(t)return e.appendChild(new h(Number(s),void 0,t,void 0)),!0}else if(this._accept(12)){const t=this._until(4);if(t)return e.appendChild(new h(Number(s),void 0,void 0,t)),!0}else if(this._accept(13)){const t=this._until(1);if(t){const i=this._until(4);if(i)return e.appendChild(new h(Number(s),void 0,t,i)),!0}}else{const t=this._until(4);if(t)return e.appendChild(new h(Number(s),void 0,void 0,t)),!0}return this._backTo(t),!1}_parseAnything(e){return 14!==this._token.type&&(e.appendChild(new r(this._scanner.tokenText(this._token))),this._accept(void 0),!0)}}},29611:(e,t,i)=>{"use strict";i.d(t,{f:()=>s});class s{constructor(e,t,i,s,n,r,o){this.id=e,this.label=t,this.alias=i,this.metadata=s,this._precondition=n,this._run=r,this._contextKeyService=o}isSupported(){return this._contextKeyService.contextMatchesRules(this._precondition)}run(e){return this.isSupported()?this._run(e):Promise.resolve(void 0)}}},29818:e=>{e.exports=function(){function e(e){return e.$value}return e.isScalar=!0,e}},29999:(e,t,i)=>{"use strict";i.d(t,{LC:()=>C,e0:()=>E,gW:()=>S,i9:()=>b});var s=i(25890),n=i(18447),r=i(64383),o=i(42522),a=i(74320),c=i(83069),l=i(36677),h=i(32500),d=i(63591),u=i(14718),g=i(23750),p=i(5662),m=i(56942),f=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},_=function(e,t){return function(i,s){t(i,s,e)}};class v{remove(){this.parent?.children.delete(this.id)}static findId(e,t){let i;"string"===typeof e?i=`${t.id}/${e}`:(i=`${t.id}/${e.name}`,void 0!==t.children.get(i)&&(i=`${t.id}/${e.name}_${e.range.startLineNumber}_${e.range.startColumn}`));let s=i;for(let n=0;void 0!==t.children.get(s);n++)s=`${i}_${n}`;return s}static empty(e){return 0===e.children.size}}class C extends v{constructor(e,t,i){super(),this.id=e,this.parent=t,this.symbol=i,this.children=new Map}}class E extends v{constructor(e,t,i,s){super(),this.id=e,this.parent=t,this.label=i,this.order=s,this.children=new Map}}class b extends v{static create(e,t,i){const o=new n.Qi(i),a=new b(t.uri),c=e.ordered(t),l=c.map(((e,i)=>{const s=v.findId(`provider_${i}`,a),n=new E(s,a,e.displayName??"Unknown Outline Provider",i);return Promise.resolve(e.provideDocumentSymbols(t,o.token)).then((e=>{for(const t of e||[])b._makeOutlineElement(t,n);return n}),(e=>((0,r.M_)(e),n))).then((e=>{v.empty(e)?e.remove():a._groups.set(s,e)}))})),h=e.onDidChange((()=>{const i=e.ordered(t);(0,s.aI)(i,c)||o.cancel()}));return Promise.all(l).then((()=>o.token.isCancellationRequested&&!i.isCancellationRequested?b.create(e,t,i):a._compact())).finally((()=>{o.dispose(),h.dispose(),o.dispose()}))}static _makeOutlineElement(e,t){const i=v.findId(e,t),s=new C(i,t,e);if(e.children)for(const n of e.children)b._makeOutlineElement(n,s);t.children.set(s.id,s)}constructor(e){super(),this.uri=e,this.id="root",this.parent=void 0,this._groups=new Map,this.children=new Map,this.id="root",this.parent=void 0}_compact(){let e=0;for(const[t,i]of this._groups)0===i.children.size?this._groups.delete(t):e+=1;if(1!==e)this.children=this._groups;else{const e=o.f.first(this._groups.values());for(const[,t]of e.children)t.parent=this,this.children.set(t.id,t)}return this}getTopLevelSymbols(){const e=[];for(const t of this.children.values())t instanceof C?e.push(t.symbol):e.push(...o.f.map(t.children.values(),(e=>e.symbol)));return e.sort(((e,t)=>l.Q.compareRangesUsingStarts(e.range,t.range)))}asListOfDocumentSymbols(){const e=this.getTopLevelSymbols(),t=[];return b._flattenDocumentSymbols(t,e,""),t.sort(((e,t)=>c.y.compare(l.Q.getStartPosition(e.range),l.Q.getStartPosition(t.range))||c.y.compare(l.Q.getEndPosition(t.range),l.Q.getEndPosition(e.range))))}static _flattenDocumentSymbols(e,t,i){for(const s of t)e.push({kind:s.kind,tags:s.tags,name:s.name,detail:s.detail,containerName:s.containerName||i,range:s.range,selectionRange:s.selectionRange,children:void 0}),s.children&&b._flattenDocumentSymbols(e,s.children,s.name)}}const S=(0,d.u1)("IOutlineModelService");let y=class{constructor(e,t,i){this._languageFeaturesService=e,this._disposables=new p.Cm,this._cache=new a.qK(10,.7),this._debounceInformation=t.for(e.documentSymbolProvider,"DocumentSymbols",{min:350}),this._disposables.add(i.onModelRemoved((e=>{this._cache.delete(e.id)})))}dispose(){this._disposables.dispose()}async getOrCreate(e,t){const i=this._languageFeaturesService.documentSymbolProvider,r=i.ordered(e);let o=this._cache.get(e.id);if(!o||o.versionId!==e.getVersionId()||!(0,s.aI)(o.provider,r)){const t=new n.Qi;o={versionId:e.getVersionId(),provider:r,promiseCnt:0,source:t,promise:b.create(i,e,t.token),model:void 0},this._cache.set(e.id,o);const s=Date.now();o.promise.then((t=>{o.model=t,this._debounceInformation.update(e,Date.now()-s)})).catch((t=>{this._cache.delete(e.id)}))}if(o.model)return o.model;o.promiseCnt+=1;const a=t.onCancellationRequested((()=>{0===--o.promiseCnt&&(o.source.cancel(),this._cache.delete(e.id))}));try{return await o.promise}finally{a.dispose()}}};y=f([_(0,m.ILanguageFeaturesService),_(1,h.ILanguageFeatureDebounceService),_(2,g.IModelService)],y),(0,u.v)(S,y,1)},30076:(e,t,i)=>{"use strict";i.d(t,{O:()=>r,e:()=>n});var s=i(59911);function n(){return s._K&&!!s._K.VSCODE_DEV}function r(e){if(n()){const t=function(){o||(o=new Set);const e=globalThis;e.$hotReload_applyNewExports||(e.$hotReload_applyNewExports=e=>{const t={config:{mode:void 0},...e},i=[];for(const s of o){const e=s(t);e&&i.push(e)}if(i.length>0)return e=>{let t=!1;for(const s of i)s(e)&&(t=!0);return t}});return o}();return t.add(e),{dispose(){t.delete(e)}}}return{dispose(){}}}let o;n()&&r((({oldExports:e,newSrc:t,config:i})=>{if("patch-prototype"===i.mode)return t=>{for(const i in t){const s=t[i];if(console.log(`[hot-reload] Patching prototype methods of '${i}'`,{exportedItem:s}),"function"===typeof s&&s.prototype){const n=e[i];if(n){for(const e of Object.getOwnPropertyNames(s.prototype)){const t=Object.getOwnPropertyDescriptor(s.prototype,e),r=Object.getOwnPropertyDescriptor(n.prototype,e);t?.value?.toString()!==r?.value?.toString()&&console.log(`[hot-reload] Patching prototype method '${i}.${e}'`),Object.defineProperty(n.prototype,e,t)}t[i]=n}}}return!0}}))},30707:(e,t,i)=>{"use strict";i.r(t),i.d(t,{MarkerDecorationsService:()=>_});var s=i(75147),n=i(5662),r=i(16223),o=i(47612),a=i(87119),c=i(23750),l=i(36677),h=i(36456),d=i(41234),u=i(66261),g=i(74320),p=i(48495),m=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},f=function(e,t){return function(i,s){t(i,s,e)}};let _=class extends n.jG{constructor(e,t){super(),this._markerService=t,this._onDidChangeMarker=this._register(new d.vl),this._markerDecorations=new g.fT,e.getModels().forEach((e=>this._onModelAdded(e))),this._register(e.onModelAdded(this._onModelAdded,this)),this._register(e.onModelRemoved(this._onModelRemoved,this)),this._register(this._markerService.onMarkerChanged(this._handleMarkerChange,this))}dispose(){super.dispose(),this._markerDecorations.forEach((e=>e.dispose())),this._markerDecorations.clear()}getMarker(e,t){const i=this._markerDecorations.get(e);return i&&i.getMarker(t)||null}_handleMarkerChange(e){e.forEach((e=>{const t=this._markerDecorations.get(e);t&&this._updateDecorations(t)}))}_onModelAdded(e){const t=new v(e);this._markerDecorations.set(e.uri,t),this._updateDecorations(t)}_onModelRemoved(e){const t=this._markerDecorations.get(e.uri);t&&(t.dispose(),this._markerDecorations.delete(e.uri)),e.uri.scheme!==h.ny.inMemory&&e.uri.scheme!==h.ny.internal&&e.uri.scheme!==h.ny.vscode||this._markerService?.read({resource:e.uri}).map((e=>e.owner)).forEach((t=>this._markerService.remove(t,[e.uri])))}_updateDecorations(e){const t=this._markerService.read({resource:e.model.uri,take:500});e.update(t)&&this._onDidChangeMarker.fire(e.model)}};_=m([f(0,c.IModelService),f(1,s.DR)],_);class v extends n.jG{constructor(e){super(),this.model=e,this._map=new g.cO,this._register((0,n.s)((()=>{this.model.deltaDecorations([...this._map.values()],[]),this._map.clear()})))}update(e){const{added:t,removed:i}=(0,p.Z)(new Set(this._map.keys()),new Set(e));if(0===t.length&&0===i.length)return!1;const s=i.map((e=>this._map.get(e))),n=t.map((e=>({range:this._createDecorationRange(this.model,e),options:this._createDecorationOption(e)}))),r=this.model.deltaDecorations(s,n);for(const o of i)this._map.delete(o);for(let o=0;o=t)return i;const s=e.getWordAtPosition(i.getStartPosition());s&&(i=new l.Q(i.startLineNumber,s.startColumn,i.endLineNumber,s.endColumn))}else if(t.endColumn===Number.MAX_VALUE&&1===t.startColumn&&i.startLineNumber===i.endLineNumber){const s=e.getLineFirstNonWhitespaceColumn(t.startLineNumber);s=0}}},30936:(e,t,i)=>{"use strict";i.d(t,{O:()=>C});var s,n=i(5662),r=i(631),o=i(31450),a=i(83069),c=i(60002),l=i(17469),h=i(56942),d=i(48116),u=i(78209),g=i(32848),p=i(18801),m=i(38280),f=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},_=function(e,t){return function(i,s){t(i,s,e)}};const v={overwriteBefore:0,overwriteAfter:0,undoStopBefore:!0,undoStopAfter:!0,adjustWhitespace:!0,clipboardText:void 0,overtypingCapturer:void 0};let C=class{static{s=this}static{this.ID="snippetController2"}static get(e){return e.getContribution(s.ID)}static{this.InSnippetMode=new g.N1("inSnippetMode",!1,(0,u.kg)("inSnippetMode","Whether the editor in current in snippet mode"))}static{this.HasNextTabstop=new g.N1("hasNextTabstop",!1,(0,u.kg)("hasNextTabstop","Whether there is a next tab stop when in snippet mode"))}static{this.HasPrevTabstop=new g.N1("hasPrevTabstop",!1,(0,u.kg)("hasPrevTabstop","Whether there is a previous tab stop when in snippet mode"))}constructor(e,t,i,r,o){this._editor=e,this._logService=t,this._languageFeaturesService=i,this._languageConfigurationService=o,this._snippetListener=new n.Cm,this._modelVersionId=-1,this._inSnippet=s.InSnippetMode.bindTo(r),this._hasNextTabstop=s.HasNextTabstop.bindTo(r),this._hasPrevTabstop=s.HasPrevTabstop.bindTo(r)}dispose(){this._inSnippet.reset(),this._hasPrevTabstop.reset(),this._hasNextTabstop.reset(),this._session?.dispose(),this._snippetListener.dispose()}insert(e,t){try{this._doInsert(e,"undefined"===typeof t?v:{...v,...t})}catch(i){this.cancel(),this._logService.error(i),this._logService.error("snippet_error"),this._logService.error("insert_template=",e),this._logService.error("existing_template=",this._session?this._session._logInfo():"")}}_doInsert(e,t){if(this._editor.hasModel()){if(this._snippetListener.clear(),t.undoStopBefore&&this._editor.getModel().pushStackElement(),this._session&&"string"!==typeof e&&this.cancel(),this._session?((0,r.j)("string"===typeof e),this._session.merge(e,t)):(this._modelVersionId=this._editor.getModel().getAlternativeVersionId(),this._session=new m.O(this._editor,e,t,this._languageConfigurationService),this._session.insert()),t.undoStopAfter&&this._editor.getModel().pushStackElement(),this._session?.hasChoice){const e={_debugDisplayName:"snippetChoiceCompletions",provideCompletionItems:(e,t)=>{if(!this._session||e!==this._editor.getModel()||!a.y.equals(this._editor.getPosition(),t))return;const{activeChoice:i}=this._session;if(!i||0===i.choice.options.length)return;const s=e.getValueInRange(i.range),n=Boolean(i.choice.options.find((e=>e.value===s))),r=[];for(let o=0;o{i?.dispose(),s=!1},r=()=>{s||(i=this._languageFeaturesService.completionProvider.register({language:t.getLanguageId(),pattern:t.uri.fsPath,scheme:t.uri.scheme,exclusive:!0},e),this._snippetListener.add(i),s=!0)};this._choiceCompletions={provider:e,enable:r,disable:n}}this._updateState(),this._snippetListener.add(this._editor.onDidChangeModelContent((e=>e.isFlush&&this.cancel()))),this._snippetListener.add(this._editor.onDidChangeModel((()=>this.cancel()))),this._snippetListener.add(this._editor.onDidChangeCursorSelection((()=>this._updateState())))}}_updateState(){if(this._session&&this._editor.hasModel()){if(this._modelVersionId===this._editor.getModel().getAlternativeVersionId())return this.cancel();if(!this._session.hasPlaceholder)return this.cancel();if(this._session.isAtLastPlaceholder||!this._session.isSelectionWithinPlaceholders())return this._editor.getModel().pushStackElement(),this.cancel();this._inSnippet.set(!0),this._hasPrevTabstop.set(!this._session.isAtFirstPlaceholder),this._hasNextTabstop.set(!this._session.isAtLastPlaceholder),this._handleChoice()}}_handleChoice(){if(!this._session||!this._editor.hasModel())return void(this._currentChoice=void 0);const{activeChoice:e}=this._session;if(!e||!this._choiceCompletions)return this._choiceCompletions?.disable(),void(this._currentChoice=void 0);this._currentChoice!==e.choice&&(this._currentChoice=e.choice,this._choiceCompletions.enable(),queueMicrotask((()=>{(0,d.p3)(this._editor,this._choiceCompletions.provider)})))}finish(){for(;this._inSnippet.get();)this.next()}cancel(e=!1){this._inSnippet.reset(),this._hasPrevTabstop.reset(),this._hasNextTabstop.reset(),this._snippetListener.clear(),this._currentChoice=void 0,this._session?.dispose(),this._session=void 0,this._modelVersionId=-1,e&&this._editor.setSelections([this._editor.getSelection()])}prev(){this._session?.prev(),this._updateState()}next(){this._session?.next(),this._updateState()}isInSnippet(){return Boolean(this._inSnippet.get())}};C=s=f([_(1,p.rr),_(2,h.ILanguageFeaturesService),_(3,g.fN),_(4,l.JZ)],C),(0,o.HW)(C.ID,C,4);const E=o.DX.bindToContribution(C.get);(0,o.E_)(new E({id:"jumpToNextSnippetPlaceholder",precondition:g.M$.and(C.InSnippetMode,C.HasNextTabstop),handler:e=>e.next(),kbOpts:{weight:130,kbExpr:c.R.textInputFocus,primary:2}})),(0,o.E_)(new E({id:"jumpToPrevSnippetPlaceholder",precondition:g.M$.and(C.InSnippetMode,C.HasPrevTabstop),handler:e=>e.prev(),kbOpts:{weight:130,kbExpr:c.R.textInputFocus,primary:1026}})),(0,o.E_)(new E({id:"leaveSnippet",precondition:C.InSnippetMode,handler:e=>e.cancel(!0),kbOpts:{weight:130,kbExpr:c.R.textInputFocus,primary:9,secondary:[1033]}})),(0,o.E_)(new E({id:"acceptSnippet",precondition:C.InSnippetMode,handler:e=>e.finish()}))},31295:(e,t,i)=>{"use strict";i.d(t,{MU:()=>x,QC:()=>w,Se:()=>L,oO:()=>T});var s=i(60413),n=i(8597),r=i(55275),o=i(47358),a=i(34072),c=i(17390),l=i(90766),h=i(25689);const d=11;class u extends c.x{constructor(e){super(),this._onActivate=e.onActivate,this.bgDomNode=document.createElement("div"),this.bgDomNode.className="arrow-background",this.bgDomNode.style.position="absolute",this.bgDomNode.style.width=e.bgWidth+"px",this.bgDomNode.style.height=e.bgHeight+"px","undefined"!==typeof e.top&&(this.bgDomNode.style.top="0px"),"undefined"!==typeof e.left&&(this.bgDomNode.style.left="0px"),"undefined"!==typeof e.bottom&&(this.bgDomNode.style.bottom="0px"),"undefined"!==typeof e.right&&(this.bgDomNode.style.right="0px"),this.domNode=document.createElement("div"),this.domNode.className=e.className,this.domNode.classList.add(...h.L.asClassNameArray(e.icon)),this.domNode.style.position="absolute",this.domNode.style.width="11px",this.domNode.style.height="11px","undefined"!==typeof e.top&&(this.domNode.style.top=e.top+"px"),"undefined"!==typeof e.left&&(this.domNode.style.left=e.left+"px"),"undefined"!==typeof e.bottom&&(this.domNode.style.bottom=e.bottom+"px"),"undefined"!==typeof e.right&&(this.domNode.style.right=e.right+"px"),this._pointerMoveMonitor=this._register(new a._),this._register(n.b2(this.bgDomNode,n.Bx.POINTER_DOWN,(e=>this._arrowPointerDown(e)))),this._register(n.b2(this.domNode,n.Bx.POINTER_DOWN,(e=>this._arrowPointerDown(e)))),this._pointerdownRepeatTimer=this._register(new n.Be),this._pointerdownScheduleRepeatTimer=this._register(new l.pc)}_arrowPointerDown(e){if(!e.target||!(e.target instanceof Element))return;this._onActivate(),this._pointerdownRepeatTimer.cancel(),this._pointerdownScheduleRepeatTimer.cancelAndSet((()=>{this._pointerdownRepeatTimer.cancelAndSet((()=>this._onActivate()),1e3/24,n.zk(e))}),200),this._pointerMoveMonitor.startMonitoring(e.target,e.pointerId,e.buttons,(e=>{}),(()=>{this._pointerdownRepeatTimer.cancel(),this._pointerdownScheduleRepeatTimer.cancel()})),e.preventDefault()}}var g=i(5662);class p extends g.jG{constructor(e,t,i){super(),this._visibility=e,this._visibleClassName=t,this._invisibleClassName=i,this._domNode=null,this._isVisible=!1,this._isNeeded=!1,this._rawShouldBeVisible=!1,this._shouldBeVisible=!1,this._revealTimer=this._register(new l.pc)}setVisibility(e){this._visibility!==e&&(this._visibility=e,this._updateShouldBeVisible())}setShouldBeVisible(e){this._rawShouldBeVisible=e,this._updateShouldBeVisible()}_applyVisibilitySetting(){return 2!==this._visibility&&(3===this._visibility||this._rawShouldBeVisible)}_updateShouldBeVisible(){const e=this._applyVisibilitySetting();this._shouldBeVisible!==e&&(this._shouldBeVisible=e,this.ensureVisibility())}setIsNeeded(e){this._isNeeded!==e&&(this._isNeeded=e,this.ensureVisibility())}setDomNode(e){this._domNode=e,this._domNode.setClassName(this._invisibleClassName),this.setShouldBeVisible(!1)}ensureVisibility(){this._isNeeded?this._shouldBeVisible?this._reveal():this._hide(!0):this._hide(!1)}_reveal(){this._isVisible||(this._isVisible=!0,this._revealTimer.setIfNotSet((()=>{this._domNode?.setClassName(this._visibleClassName)}),0))}_hide(e){this._revealTimer.cancel(),this._isVisible&&(this._isVisible=!1,this._domNode?.setClassName(this._invisibleClassName+(e?" fade":"")))}}var m=i(98067);class f extends c.x{constructor(e){super(),this._lazyRender=e.lazyRender,this._host=e.host,this._scrollable=e.scrollable,this._scrollByPage=e.scrollByPage,this._scrollbarState=e.scrollbarState,this._visibilityController=this._register(new p(e.visibility,"visible scrollbar "+e.extraScrollbarClassName,"invisible scrollbar "+e.extraScrollbarClassName)),this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded()),this._pointerMoveMonitor=this._register(new a._),this._shouldRender=!0,this.domNode=(0,r.Z)(document.createElement("div")),this.domNode.setAttribute("role","presentation"),this.domNode.setAttribute("aria-hidden","true"),this._visibilityController.setDomNode(this.domNode),this.domNode.setPosition("absolute"),this._register(n.ko(this.domNode.domNode,n.Bx.POINTER_DOWN,(e=>this._domNodePointerDown(e))))}_createArrow(e){const t=this._register(new u(e));this.domNode.domNode.appendChild(t.bgDomNode),this.domNode.domNode.appendChild(t.domNode)}_createSlider(e,t,i,s){this.slider=(0,r.Z)(document.createElement("div")),this.slider.setClassName("slider"),this.slider.setPosition("absolute"),this.slider.setTop(e),this.slider.setLeft(t),"number"===typeof i&&this.slider.setWidth(i),"number"===typeof s&&this.slider.setHeight(s),this.slider.setLayerHinting(!0),this.slider.setContain("strict"),this.domNode.domNode.appendChild(this.slider.domNode),this._register(n.ko(this.slider.domNode,n.Bx.POINTER_DOWN,(e=>{0===e.button&&(e.preventDefault(),this._sliderPointerDown(e))}))),this.onclick(this.slider.domNode,(e=>{e.leftButton&&e.stopPropagation()}))}_onElementSize(e){return this._scrollbarState.setVisibleSize(e)&&(this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded()),this._shouldRender=!0,this._lazyRender||this.render()),this._shouldRender}_onElementScrollSize(e){return this._scrollbarState.setScrollSize(e)&&(this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded()),this._shouldRender=!0,this._lazyRender||this.render()),this._shouldRender}_onElementScrollPosition(e){return this._scrollbarState.setScrollPosition(e)&&(this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded()),this._shouldRender=!0,this._lazyRender||this.render()),this._shouldRender}beginReveal(){this._visibilityController.setShouldBeVisible(!0)}beginHide(){this._visibilityController.setShouldBeVisible(!1)}render(){this._shouldRender&&(this._shouldRender=!1,this._renderDomNode(this._scrollbarState.getRectangleLargeSize(),this._scrollbarState.getRectangleSmallSize()),this._updateSlider(this._scrollbarState.getSliderSize(),this._scrollbarState.getArrowSize()+this._scrollbarState.getSliderPosition()))}_domNodePointerDown(e){e.target===this.domNode.domNode&&this._onPointerDown(e)}delegatePointerDown(e){const t=this.domNode.domNode.getClientRects()[0].top,i=t+this._scrollbarState.getSliderPosition(),s=t+this._scrollbarState.getSliderPosition()+this._scrollbarState.getSliderSize(),n=this._sliderPointerPosition(e);i<=n&&n<=s?0===e.button&&(e.preventDefault(),this._sliderPointerDown(e)):this._onPointerDown(e)}_onPointerDown(e){let t,i;if(e.target===this.domNode.domNode&&"number"===typeof e.offsetX&&"number"===typeof e.offsetY)t=e.offsetX,i=e.offsetY;else{const s=n.BK(this.domNode.domNode);t=e.pageX-s.left,i=e.pageY-s.top}const s=this._pointerDownRelativePosition(t,i);this._setDesiredScrollPositionNow(this._scrollByPage?this._scrollbarState.getDesiredScrollPositionFromOffsetPaged(s):this._scrollbarState.getDesiredScrollPositionFromOffset(s)),0===e.button&&(e.preventDefault(),this._sliderPointerDown(e))}_sliderPointerDown(e){if(!e.target||!(e.target instanceof Element))return;const t=this._sliderPointerPosition(e),i=this._sliderOrthogonalPointerPosition(e),s=this._scrollbarState.clone();this.slider.toggleClassName("active",!0),this._pointerMoveMonitor.startMonitoring(e.target,e.pointerId,e.buttons,(e=>{const n=this._sliderOrthogonalPointerPosition(e),r=Math.abs(n-i);if(m.uF&&r>140)return void this._setDesiredScrollPositionNow(s.getScrollPosition());const o=this._sliderPointerPosition(e)-t;this._setDesiredScrollPositionNow(s.getDesiredScrollPositionFromDelta(o))}),(()=>{this.slider.toggleClassName("active",!1),this._host.onDragEnd()})),this._host.onDragStart()}_setDesiredScrollPositionNow(e){const t={};this.writeScrollPosition(t,e),this._scrollable.setScrollPositionNow(t)}updateScrollbarSize(e){this._updateScrollbarSize(e),this._scrollbarState.setScrollbarSize(e),this._shouldRender=!0,this._lazyRender||this.render()}isNeeded(){return this._scrollbarState.isNeeded()}}var _=i(74850),v=i(10350);class C extends f{constructor(e,t,i){const s=e.getScrollDimensions(),n=e.getCurrentScrollPosition();if(super({lazyRender:t.lazyRender,host:i,scrollbarState:new _.m(t.horizontalHasArrows?t.arrowSize:0,2===t.horizontal?0:t.horizontalScrollbarSize,2===t.vertical?0:t.verticalScrollbarSize,s.width,s.scrollWidth,n.scrollLeft),visibility:t.horizontal,extraScrollbarClassName:"horizontal",scrollable:e,scrollByPage:t.scrollByPage}),t.horizontalHasArrows){const e=(t.arrowSize-d)/2,i=(t.horizontalScrollbarSize-d)/2;this._createArrow({className:"scra",icon:v.W.scrollbarButtonLeft,top:i,left:e,bottom:void 0,right:void 0,bgWidth:t.arrowSize,bgHeight:t.horizontalScrollbarSize,onActivate:()=>this._host.onMouseWheel(new o.$(null,1,0))}),this._createArrow({className:"scra",icon:v.W.scrollbarButtonRight,top:i,left:void 0,bottom:void 0,right:e,bgWidth:t.arrowSize,bgHeight:t.horizontalScrollbarSize,onActivate:()=>this._host.onMouseWheel(new o.$(null,-1,0))})}this._createSlider(Math.floor((t.horizontalScrollbarSize-t.horizontalSliderSize)/2),0,void 0,t.horizontalSliderSize)}_updateSlider(e,t){this.slider.setWidth(e),this.slider.setLeft(t)}_renderDomNode(e,t){this.domNode.setWidth(e),this.domNode.setHeight(t),this.domNode.setLeft(0),this.domNode.setBottom(0)}onDidScroll(e){return this._shouldRender=this._onElementScrollSize(e.scrollWidth)||this._shouldRender,this._shouldRender=this._onElementScrollPosition(e.scrollLeft)||this._shouldRender,this._shouldRender=this._onElementSize(e.width)||this._shouldRender,this._shouldRender}_pointerDownRelativePosition(e,t){return e}_sliderPointerPosition(e){return e.pageX}_sliderOrthogonalPointerPosition(e){return e.pageY}_updateScrollbarSize(e){this.slider.setHeight(e)}writeScrollPosition(e,t){e.scrollLeft=t}updateOptions(e){this.updateScrollbarSize(2===e.horizontal?0:e.horizontalScrollbarSize),this._scrollbarState.setOppositeScrollbarSize(2===e.vertical?0:e.verticalScrollbarSize),this._visibilityController.setVisibility(e.horizontal),this._scrollByPage=e.scrollByPage}}class E extends f{constructor(e,t,i){const s=e.getScrollDimensions(),n=e.getCurrentScrollPosition();if(super({lazyRender:t.lazyRender,host:i,scrollbarState:new _.m(t.verticalHasArrows?t.arrowSize:0,2===t.vertical?0:t.verticalScrollbarSize,0,s.height,s.scrollHeight,n.scrollTop),visibility:t.vertical,extraScrollbarClassName:"vertical",scrollable:e,scrollByPage:t.scrollByPage}),t.verticalHasArrows){const e=(t.arrowSize-d)/2,i=(t.verticalScrollbarSize-d)/2;this._createArrow({className:"scra",icon:v.W.scrollbarButtonUp,top:e,left:i,bottom:void 0,right:void 0,bgWidth:t.verticalScrollbarSize,bgHeight:t.arrowSize,onActivate:()=>this._host.onMouseWheel(new o.$(null,0,1))}),this._createArrow({className:"scra",icon:v.W.scrollbarButtonDown,top:void 0,left:i,bottom:e,right:void 0,bgWidth:t.verticalScrollbarSize,bgHeight:t.arrowSize,onActivate:()=>this._host.onMouseWheel(new o.$(null,0,-1))})}this._createSlider(0,Math.floor((t.verticalScrollbarSize-t.verticalSliderSize)/2),t.verticalSliderSize,void 0)}_updateSlider(e,t){this.slider.setHeight(e),this.slider.setTop(t)}_renderDomNode(e,t){this.domNode.setWidth(t),this.domNode.setHeight(e),this.domNode.setRight(0),this.domNode.setTop(0)}onDidScroll(e){return this._shouldRender=this._onElementScrollSize(e.scrollHeight)||this._shouldRender,this._shouldRender=this._onElementScrollPosition(e.scrollTop)||this._shouldRender,this._shouldRender=this._onElementSize(e.height)||this._shouldRender,this._shouldRender}_pointerDownRelativePosition(e,t){return t}_sliderPointerPosition(e){return e.pageY}_sliderOrthogonalPointerPosition(e){return e.pageX}_updateScrollbarSize(e){this.slider.setWidth(e)}writeScrollPosition(e,t){e.scrollTop=t}updateOptions(e){this.updateScrollbarSize(2===e.vertical?0:e.verticalScrollbarSize),this._scrollbarState.setOppositeScrollbarSize(0),this._visibilityController.setVisibility(e.vertical),this._scrollByPage=e.scrollByPage}}var b=i(41234),S=i(49353);class y{constructor(e,t,i){this.timestamp=e,this.deltaX=t,this.deltaY=i,this.score=0}}class w{static{this.INSTANCE=new w}constructor(){this._capacity=5,this._memory=[],this._front=-1,this._rear=-1}isPhysicalMouseWheel(){if(-1===this._front&&-1===this._rear)return!1;let e=1,t=0,i=1,s=this._rear;for(;;){const n=s===this._front?e:Math.pow(2,-i);if(e-=n,t+=this._memory[s].score*n,s===this._front)break;s=(this._capacity+s-1)%this._capacity,i++}return t<=.5}acceptStandardWheelEvent(e){if(s.H8){const t=n.zk(e.browserEvent),i=(0,s.pR)(t);this.accept(Date.now(),e.deltaX*i,e.deltaY*i)}else this.accept(Date.now(),e.deltaX,e.deltaY)}accept(e,t,i){let s=null;const n=new y(e,t,i);-1===this._front&&-1===this._rear?(this._memory[0]=n,this._front=0,this._rear=0):(s=this._memory[this._rear],this._rear=(this._rear+1)%this._capacity,this._rear===this._front&&(this._front=(this._front+1)%this._capacity),this._memory[this._rear]=n),n.score=this._computeScore(n,s)}_computeScore(e,t){if(Math.abs(e.deltaX)>0&&Math.abs(e.deltaY)>0)return 1;let i=.5;if(this._isAlmostInt(e.deltaX)&&this._isAlmostInt(e.deltaY)||(i+=.25),t){const s=Math.abs(e.deltaX),n=Math.abs(e.deltaY),r=Math.abs(t.deltaX),o=Math.abs(t.deltaY),a=Math.max(Math.min(s,r),1),c=Math.max(Math.min(n,o),1),l=Math.max(s,r),h=Math.max(n,o);l%a===0&&h%c===0&&(i-=.5)}return Math.min(Math.max(i,0),1)}_isAlmostInt(e){return Math.abs(Math.round(e)-e)<.01}}class R extends c.x{get options(){return this._options}constructor(e,t,i){super(),this._onScroll=this._register(new b.vl),this.onScroll=this._onScroll.event,this._onWillScroll=this._register(new b.vl),e.style.overflow="hidden",this._options=function(e){const t={lazyRender:"undefined"!==typeof e.lazyRender&&e.lazyRender,className:"undefined"!==typeof e.className?e.className:"",useShadows:"undefined"===typeof e.useShadows||e.useShadows,handleMouseWheel:"undefined"===typeof e.handleMouseWheel||e.handleMouseWheel,flipAxes:"undefined"!==typeof e.flipAxes&&e.flipAxes,consumeMouseWheelIfScrollbarIsNeeded:"undefined"!==typeof e.consumeMouseWheelIfScrollbarIsNeeded&&e.consumeMouseWheelIfScrollbarIsNeeded,alwaysConsumeMouseWheel:"undefined"!==typeof e.alwaysConsumeMouseWheel&&e.alwaysConsumeMouseWheel,scrollYToX:"undefined"!==typeof e.scrollYToX&&e.scrollYToX,mouseWheelScrollSensitivity:"undefined"!==typeof e.mouseWheelScrollSensitivity?e.mouseWheelScrollSensitivity:1,fastScrollSensitivity:"undefined"!==typeof e.fastScrollSensitivity?e.fastScrollSensitivity:5,scrollPredominantAxis:"undefined"===typeof e.scrollPredominantAxis||e.scrollPredominantAxis,mouseWheelSmoothScroll:"undefined"===typeof e.mouseWheelSmoothScroll||e.mouseWheelSmoothScroll,arrowSize:"undefined"!==typeof e.arrowSize?e.arrowSize:11,listenOnDomNode:"undefined"!==typeof e.listenOnDomNode?e.listenOnDomNode:null,horizontal:"undefined"!==typeof e.horizontal?e.horizontal:1,horizontalScrollbarSize:"undefined"!==typeof e.horizontalScrollbarSize?e.horizontalScrollbarSize:10,horizontalSliderSize:"undefined"!==typeof e.horizontalSliderSize?e.horizontalSliderSize:0,horizontalHasArrows:"undefined"!==typeof e.horizontalHasArrows&&e.horizontalHasArrows,vertical:"undefined"!==typeof e.vertical?e.vertical:1,verticalScrollbarSize:"undefined"!==typeof e.verticalScrollbarSize?e.verticalScrollbarSize:10,verticalHasArrows:"undefined"!==typeof e.verticalHasArrows&&e.verticalHasArrows,verticalSliderSize:"undefined"!==typeof e.verticalSliderSize?e.verticalSliderSize:0,scrollByPage:"undefined"!==typeof e.scrollByPage&&e.scrollByPage};t.horizontalSliderSize="undefined"!==typeof e.horizontalSliderSize?e.horizontalSliderSize:t.horizontalScrollbarSize,t.verticalSliderSize="undefined"!==typeof e.verticalSliderSize?e.verticalSliderSize:t.verticalScrollbarSize,m.zx&&(t.className+=" mac");return t}(t),this._scrollable=i,this._register(this._scrollable.onScroll((e=>{this._onWillScroll.fire(e),this._onDidScroll(e),this._onScroll.fire(e)})));const s={onMouseWheel:e=>this._onMouseWheel(e),onDragStart:()=>this._onDragStart(),onDragEnd:()=>this._onDragEnd()};this._verticalScrollbar=this._register(new E(this._scrollable,this._options,s)),this._horizontalScrollbar=this._register(new C(this._scrollable,this._options,s)),this._domNode=document.createElement("div"),this._domNode.className="monaco-scrollable-element "+this._options.className,this._domNode.setAttribute("role","presentation"),this._domNode.style.position="relative",this._domNode.style.overflow="hidden",this._domNode.appendChild(e),this._domNode.appendChild(this._horizontalScrollbar.domNode.domNode),this._domNode.appendChild(this._verticalScrollbar.domNode.domNode),this._options.useShadows?(this._leftShadowDomNode=(0,r.Z)(document.createElement("div")),this._leftShadowDomNode.setClassName("shadow"),this._domNode.appendChild(this._leftShadowDomNode.domNode),this._topShadowDomNode=(0,r.Z)(document.createElement("div")),this._topShadowDomNode.setClassName("shadow"),this._domNode.appendChild(this._topShadowDomNode.domNode),this._topLeftShadowDomNode=(0,r.Z)(document.createElement("div")),this._topLeftShadowDomNode.setClassName("shadow"),this._domNode.appendChild(this._topLeftShadowDomNode.domNode)):(this._leftShadowDomNode=null,this._topShadowDomNode=null,this._topLeftShadowDomNode=null),this._listenOnDomNode=this._options.listenOnDomNode||this._domNode,this._mouseWheelToDispose=[],this._setListeningToMouseWheel(this._options.handleMouseWheel),this.onmouseover(this._listenOnDomNode,(e=>this._onMouseOver(e))),this.onmouseleave(this._listenOnDomNode,(e=>this._onMouseLeave(e))),this._hideTimeout=this._register(new l.pc),this._isDragging=!1,this._mouseIsOver=!1,this._shouldRender=!0,this._revealOnScroll=!0}dispose(){this._mouseWheelToDispose=(0,g.AS)(this._mouseWheelToDispose),super.dispose()}getDomNode(){return this._domNode}getOverviewRulerLayoutInfo(){return{parent:this._domNode,insertBefore:this._verticalScrollbar.domNode.domNode}}delegateVerticalScrollbarPointerDown(e){this._verticalScrollbar.delegatePointerDown(e)}getScrollDimensions(){return this._scrollable.getScrollDimensions()}setScrollDimensions(e){this._scrollable.setScrollDimensions(e,!1)}updateClassName(e){this._options.className=e,m.zx&&(this._options.className+=" mac"),this._domNode.className="monaco-scrollable-element "+this._options.className}updateOptions(e){"undefined"!==typeof e.handleMouseWheel&&(this._options.handleMouseWheel=e.handleMouseWheel,this._setListeningToMouseWheel(this._options.handleMouseWheel)),"undefined"!==typeof e.mouseWheelScrollSensitivity&&(this._options.mouseWheelScrollSensitivity=e.mouseWheelScrollSensitivity),"undefined"!==typeof e.fastScrollSensitivity&&(this._options.fastScrollSensitivity=e.fastScrollSensitivity),"undefined"!==typeof e.scrollPredominantAxis&&(this._options.scrollPredominantAxis=e.scrollPredominantAxis),"undefined"!==typeof e.horizontal&&(this._options.horizontal=e.horizontal),"undefined"!==typeof e.vertical&&(this._options.vertical=e.vertical),"undefined"!==typeof e.horizontalScrollbarSize&&(this._options.horizontalScrollbarSize=e.horizontalScrollbarSize),"undefined"!==typeof e.verticalScrollbarSize&&(this._options.verticalScrollbarSize=e.verticalScrollbarSize),"undefined"!==typeof e.scrollByPage&&(this._options.scrollByPage=e.scrollByPage),this._horizontalScrollbar.updateOptions(this._options),this._verticalScrollbar.updateOptions(this._options),this._options.lazyRender||this._render()}delegateScrollFromMouseWheelEvent(e){this._onMouseWheel(new o.$(e))}_setListeningToMouseWheel(e){if(this._mouseWheelToDispose.length>0!==e&&(this._mouseWheelToDispose=(0,g.AS)(this._mouseWheelToDispose),e)){const e=e=>{this._onMouseWheel(new o.$(e))};this._mouseWheelToDispose.push(n.ko(this._listenOnDomNode,n.Bx.MOUSE_WHEEL,e,{passive:!1}))}}_onMouseWheel(e){if(e.browserEvent?.defaultPrevented)return;const t=w.INSTANCE;t.acceptStandardWheelEvent(e);let i=!1;if(e.deltaY||e.deltaX){let s=e.deltaY*this._options.mouseWheelScrollSensitivity,n=e.deltaX*this._options.mouseWheelScrollSensitivity;this._options.scrollPredominantAxis&&(this._options.scrollYToX&&n+s===0?n=s=0:Math.abs(s)>=Math.abs(n)?n=0:s=0),this._options.flipAxes&&([s,n]=[n,s]);const r=!m.zx&&e.browserEvent&&e.browserEvent.shiftKey;!this._options.scrollYToX&&!r||n||(n=s,s=0),e.browserEvent&&e.browserEvent.altKey&&(n*=this._options.fastScrollSensitivity,s*=this._options.fastScrollSensitivity);const o=this._scrollable.getFutureScrollPosition();let a={};if(s){const e=50*s,t=o.scrollTop-(e<0?Math.floor(e):Math.ceil(e));this._verticalScrollbar.writeScrollPosition(a,t)}if(n){const e=50*n,t=o.scrollLeft-(e<0?Math.floor(e):Math.ceil(e));this._horizontalScrollbar.writeScrollPosition(a,t)}if(a=this._scrollable.validateScrollPosition(a),o.scrollLeft!==a.scrollLeft||o.scrollTop!==a.scrollTop){this._options.mouseWheelSmoothScroll&&t.isPhysicalMouseWheel()?this._scrollable.setScrollPositionSmooth(a):this._scrollable.setScrollPositionNow(a),i=!0}}let s=i;!s&&this._options.alwaysConsumeMouseWheel&&(s=!0),!s&&this._options.consumeMouseWheelIfScrollbarIsNeeded&&(this._verticalScrollbar.isNeeded()||this._horizontalScrollbar.isNeeded())&&(s=!0),s&&(e.preventDefault(),e.stopPropagation())}_onDidScroll(e){this._shouldRender=this._horizontalScrollbar.onDidScroll(e)||this._shouldRender,this._shouldRender=this._verticalScrollbar.onDidScroll(e)||this._shouldRender,this._options.useShadows&&(this._shouldRender=!0),this._revealOnScroll&&this._reveal(),this._options.lazyRender||this._render()}renderNow(){if(!this._options.lazyRender)throw new Error("Please use `lazyRender` together with `renderNow`!");this._render()}_render(){if(this._shouldRender&&(this._shouldRender=!1,this._horizontalScrollbar.render(),this._verticalScrollbar.render(),this._options.useShadows)){const e=this._scrollable.getCurrentScrollPosition(),t=e.scrollTop>0,i=e.scrollLeft>0,s=i?" left":"",n=t?" top":"",r=i||t?" top-left-corner":"";this._leftShadowDomNode.setClassName(`shadow${s}`),this._topShadowDomNode.setClassName(`shadow${n}`),this._topLeftShadowDomNode.setClassName(`shadow${r}${n}${s}`)}}_onDragStart(){this._isDragging=!0,this._reveal()}_onDragEnd(){this._isDragging=!1,this._hide()}_onMouseLeave(e){this._mouseIsOver=!1,this._hide()}_onMouseOver(e){this._mouseIsOver=!0,this._reveal()}_reveal(){this._verticalScrollbar.beginReveal(),this._horizontalScrollbar.beginReveal(),this._scheduleHide()}_hide(){this._mouseIsOver||this._isDragging||(this._verticalScrollbar.beginHide(),this._horizontalScrollbar.beginHide())}_scheduleHide(){this._mouseIsOver||this._isDragging||this._hideTimeout.cancelAndSet((()=>this._hide()),500)}}class L extends R{constructor(e,t){(t=t||{}).mouseWheelSmoothScroll=!1;const i=new S.yE({forceIntegerValues:!0,smoothScrollDuration:0,scheduleAtNextAnimationFrame:t=>n.PG(n.zk(e),t)});super(e,t,i),this._register(i)}setScrollPosition(e){this._scrollable.setScrollPositionNow(e)}}class T extends R{constructor(e,t,i){super(e,t,i)}setScrollPosition(e){e.reuseAnimation?this._scrollable.setScrollPositionSmooth(e,e.reuseAnimation):this._scrollable.setScrollPositionNow(e)}getScrollPosition(){return this._scrollable.getCurrentScrollPosition()}}class x extends R{constructor(e,t){(t=t||{}).mouseWheelSmoothScroll=!1;const i=new S.yE({forceIntegerValues:!1,smoothScrollDuration:0,scheduleAtNextAnimationFrame:t=>n.PG(n.zk(e),t)});super(e,t,i),this._register(i),this._element=e,this._register(this.onScroll((e=>{e.scrollTopChanged&&(this._element.scrollTop=e.scrollTop),e.scrollLeftChanged&&(this._element.scrollLeft=e.scrollLeft)}))),this.scanDomNode()}setScrollPosition(e){this._scrollable.setScrollPositionNow(e)}getScrollPosition(){return this._scrollable.getCurrentScrollPosition()}scanDomNode(){this.setScrollDimensions({width:this._element.clientWidth,scrollWidth:this._element.scrollWidth,height:this._element.clientHeight,scrollHeight:this._element.scrollHeight}),this.setScrollPosition({scrollLeft:this._element.scrollLeft,scrollTop:this._element.scrollTop})}}},31308:(e,t,i)=>{"use strict";i.d(t,{BK:()=>_,fm:()=>l,Y:()=>d,zL:()=>h,yC:()=>g,ht:()=>u,lk:()=>m.lk,un:()=>n.un,nb:()=>n.nb,ZX:()=>m.ZX,C:()=>n.C,rm:()=>n.rm,X2:()=>s.X2,y0:()=>m.y0,Yd:()=>m.Yd,yQ:()=>m.yQ,FY:()=>s.FY,Zh:()=>S,OI:()=>m.OI,PO:()=>s.PO,Rn:()=>s.Rn,oJ:()=>C});var s=i(49154),n=i(87958),r=i(66782),o=i(5662),a=i(22311),c=i(94958);function l(e){return new p(new a.nA(void 0,void 0,e),e,void 0,void 0)}function h(e,t){return new p(new a.nA(e.owner,e.debugName,e.debugReferenceFn??t),t,void 0,void 0)}function d(e,t){return new p(new a.nA(e.owner,e.debugName,e.debugReferenceFn??t),t,e.createEmptyChangeSummary,e.handleChange)}function u(e,t){const i=new o.Cm,s=d({owner:e.owner,debugName:e.debugName,debugReferenceFn:e.debugReferenceFn??t,createEmptyChangeSummary:e.createEmptyChangeSummary,handleChange:e.handleChange},((e,s)=>{i.clear(),t(e,s,i)}));return(0,o.s)((()=>{s.dispose(),i.dispose()}))}function g(e){const t=new o.Cm,i=h({owner:void 0,debugName:void 0,debugReferenceFn:e},(i=>{t.clear(),e(i,t)}));return(0,o.s)((()=>{i.dispose(),t.dispose()}))}class p{get debugName(){return this._debugNameData.getDebugName(this)??"(anonymous)"}constructor(e,t,i,s){this._debugNameData=e,this._runFn=t,this.createChangeSummary=i,this._handleChange=s,this.state=2,this.updateCount=0,this.disposed=!1,this.dependencies=new Set,this.dependenciesToBeRemoved=new Set,this.changeSummary=this.createChangeSummary?.(),(0,c.tZ)()?.handleAutorunCreated(this),this._runIfNeeded(),(0,o.Ay)(this)}dispose(){this.disposed=!0;for(const e of this.dependencies)e.removeObserver(this);this.dependencies.clear(),(0,o.VD)(this)}_runIfNeeded(){if(3===this.state)return;const e=this.dependenciesToBeRemoved;this.dependenciesToBeRemoved=this.dependencies,this.dependencies=e,this.state=3;const t=this.disposed;try{if(!t){(0,c.tZ)()?.handleAutorunTriggered(this);const e=this.changeSummary;this.changeSummary=this.createChangeSummary?.(),this._runFn(this,e)}}finally{t||(0,c.tZ)()?.handleAutorunFinished(this);for(const e of this.dependenciesToBeRemoved)e.removeObserver(this);this.dependenciesToBeRemoved.clear()}}toString(){return`Autorun<${this.debugName}>`}beginUpdate(){3===this.state&&(this.state=1),this.updateCount++}endUpdate(){if(1===this.updateCount)do{if(1===this.state){this.state=3;for(const e of this.dependencies)if(e.reportChanges(),2===this.state)break}this._runIfNeeded()}while(3!==this.state);this.updateCount--,(0,r.Ft)((()=>this.updateCount>=0))}handlePossibleChange(e){3===this.state&&this.dependencies.has(e)&&!this.dependenciesToBeRemoved.has(e)&&(this.state=1)}handleChange(e,t){if(this.dependencies.has(e)&&!this.dependenciesToBeRemoved.has(e)){(!this._handleChange||this._handleChange({changedObservable:e,change:t,didChange:t=>t===e},this.changeSummary))&&(this.state=2)}}readObservable(e){if(this.disposed)return e.get();e.addObserver(this);const t=e.get();return this.dependencies.add(e),this.dependenciesToBeRemoved.delete(e),t}}!function(e){e.Observer=p}(l||(l={}));var m=i(13850),f=i(64383);class _{static fromFn(e){return new _(e())}constructor(e){this._value=(0,s.FY)(this,void 0),this.promiseResult=this._value,this.promise=e.then((e=>((0,s.Rn)((t=>{this._value.set(new v(e,void 0),t)})),e)),(e=>{throw(0,s.Rn)((t=>{this._value.set(new v(void 0,e),t)})),e}))}}class v{constructor(e,t){this.data=e,this.error=t}}function C(e,t,i,s){return t||(t=e=>null!==e&&void 0!==e),new Promise(((n,r)=>{let o=!0,a=!1;const c=e.map((e=>({isFinished:t(e),error:!!i&&i(e),state:e}))),h=l((e=>{const{isFinished:t,error:i,state:s}=c.read(e);(t||i)&&(o?a=!0:h.dispose(),i?r(!0===i?s:i):n(s))}));if(s){const e=s.onCancellationRequested((()=>{h.dispose(),e.dispose(),r(new f.AL)}));if(s.isCancellationRequested)return h.dispose(),e.dispose(),void r(new f.AL)}o=!1,a&&h.dispose()}))}var E=i(51241);class b extends s.ZK{get debugName(){return this._debugNameData.getDebugName(this)??"LazyObservableValue"}constructor(e,t,i){super(),this._debugNameData=e,this._equalityComparator=i,this._isUpToDate=!0,this._deltas=[],this._updateCounter=0,this._value=t}get(){return this._update(),this._value}_update(){if(!this._isUpToDate)if(this._isUpToDate=!0,this._deltas.length>0){for(const e of this.observers)for(const t of this._deltas)e.handleChange(this,t);this._deltas.length=0}else for(const e of this.observers)e.handleChange(this,void 0)}_beginUpdate(){if(this._updateCounter++,1===this._updateCounter)for(const e of this.observers)e.beginUpdate(this)}_endUpdate(){if(this._updateCounter--,0===this._updateCounter){this._update();const e=[...this.observers];for(const t of e)t.endUpdate(this)}}addObserver(e){const t=!this.observers.has(e)&&this._updateCounter>0;super.addObserver(e),t&&e.beginUpdate(this)}removeObserver(e){const t=this.observers.has(e)&&this._updateCounter>0;super.removeObserver(e),t&&e.endUpdate(this)}set(e,t,i){if(void 0===i&&this._equalityComparator(this._value,e))return;let n;t||(t=n=new s.XL((()=>{}),(()=>`Setting ${this.debugName}`)));try{if(this._isUpToDate=!1,this._setValue(e),void 0!==i&&this._deltas.push(i),t.updateObserver({beginUpdate:()=>this._beginUpdate(),endUpdate:()=>this._endUpdate(),handleChange:(e,t)=>{},handlePossibleChange:e=>{}},this),this._updateCounter>1)for(const e of this.observers)e.handlePossibleChange(this)}finally{n&&n.finish()}}toString(){return`${this.debugName}: ${this._value}`}_setValue(e){this._value=e}}function S(e,t){return e.lazy?new b(new a.nA(e.owner,e.debugName,void 0),t,e.equalsFn??E.nx):new s.Lj(new a.nA(e.owner,e.debugName,void 0),t,e.equalsFn??E.nx)}},31396:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"mysql",extensions:[],aliases:["MySQL","mysql"],loader:()=>i.e(16210).then(i.bind(i,93829))})},31450:(e,t,i)=>{"use strict";i.d(t,{DX:()=>y,E_:()=>x,Fl:()=>k,HW:()=>I,PF:()=>R,aU:()=>M,dS:()=>s,fE:()=>b,gW:()=>A,ih:()=>P,ke:()=>T,ks:()=>w,qO:()=>L,tc:()=>F,uB:()=>E,xX:()=>N});var s,n=i(78209),r=i(79400),o=i(80301),a=i(83069),c=i(23750),l=i(18938),h=i(27195),d=i(50091),u=i(32848),g=i(63591),p=i(59261),m=i(46359),f=i(90651),_=i(631),v=i(18801),C=i(8597);class E{constructor(e){this.id=e.id,this.precondition=e.precondition,this._kbOpts=e.kbOpts,this._menuOpts=e.menuOpts,this.metadata=e.metadata}register(){if(Array.isArray(this._menuOpts)?this._menuOpts.forEach(this._registerMenuItem,this):this._menuOpts&&this._registerMenuItem(this._menuOpts),this._kbOpts){const e=Array.isArray(this._kbOpts)?this._kbOpts:[this._kbOpts];for(const t of e){let e=t.kbExpr;this.precondition&&(e=e?u.M$.and(e,this.precondition):this.precondition);const i={id:this.id,weight:t.weight,args:t.args,when:e,primary:t.primary,secondary:t.secondary,win:t.win,linux:t.linux,mac:t.mac};p.f.registerKeybindingRule(i)}}d.w.registerCommand({id:this.id,handler:(e,t)=>this.runCommand(e,t),metadata:this.metadata})}_registerMenuItem(e){h.ZG.appendMenuItem(e.menuId,{group:e.group,command:{id:this.id,title:e.title,icon:e.icon,precondition:this.precondition},when:e.when,order:e.order})}}class b extends E{constructor(){super(...arguments),this._implementations=[]}addImplementation(e,t,i,s){return this._implementations.push({priority:e,name:t,implementation:i,when:s}),this._implementations.sort(((e,t)=>t.priority-e.priority)),{dispose:()=>{for(let e=0;e{if(e.get(u.fN).contextMatchesRules(i??void 0))return s(e,r,t)}))}runCommand(e,t){return y.runEditorCommand(e,t,this.precondition,((e,t,i)=>this.runEditorCommand(e,t,i)))}}class w extends y{static convertOptions(e){let t;function i(t){return t.menuId||(t.menuId=h.D8.EditorContext),t.title||(t.title=e.label),t.when=u.M$.and(e.precondition,t.when),t}return t=Array.isArray(e.menuOpts)?e.menuOpts:e.menuOpts?[e.menuOpts]:[],Array.isArray(e.contextMenuOpts)?t.push(...e.contextMenuOpts.map(i)):e.contextMenuOpts&&t.push(i(e.contextMenuOpts)),e.menuOpts=t,e}constructor(e){super(w.convertOptions(e)),this.label=e.label,this.alias=e.alias}runEditorCommand(e,t,i){return this.reportTelemetry(e,t),this.run(e,t,i||{})}reportTelemetry(e,t){e.get(f.k).publicLog2("editorActionInvoked",{name:this.label,id:this.id})}}class R extends w{constructor(){super(...arguments),this._implementations=[]}addImplementation(e,t){return this._implementations.push([e,t]),this._implementations.sort(((e,t)=>t[0]-e[0])),{dispose:()=>{for(let e=0;e{const i=e.get(u.fN),n=e.get(v.rr);if(i.contextMatchesRules(this.desc.precondition??void 0))return this.runEditorCommand(e,s,...t);n.debug("[EditorAction2] NOT running command because its precondition is FALSE",this.desc.id,this.desc.precondition?.serialize())}))}}function T(e,t){d.w.registerCommand(e,(function(e,...i){const s=e.get(g._Y),[n,o]=i;(0,_.j)(r.r.isUri(n)),(0,_.j)(a.y.isIPosition(o));const h=e.get(c.IModelService).getModel(n);if(h){const e=a.y.lift(o);return s.invokeFunction(t,h,e,...i.slice(2))}return e.get(l.ITextModelService).createModelReference(n).then((e=>new Promise(((n,r)=>{try{n(s.invokeFunction(t,e.object.textEditorModel,a.y.lift(o),i.slice(2)))}catch(c){r(c)}})).finally((()=>{e.dispose()}))))}))}function x(e){return O.INSTANCE.registerEditorCommand(e),e}function k(e){const t=new e;return O.INSTANCE.registerEditorAction(t),t}function A(e){return O.INSTANCE.registerEditorAction(e),e}function N(e){O.INSTANCE.registerEditorAction(e)}function I(e,t,i){O.INSTANCE.registerEditorContribution(e,t,i)}!function(e){e.getEditorCommand=function(e){return O.INSTANCE.getEditorCommand(e)},e.getEditorActions=function(){return O.INSTANCE.getEditorActions()},e.getEditorContributions=function(){return O.INSTANCE.getEditorContributions()},e.getSomeEditorContributions=function(e){return O.INSTANCE.getEditorContributions().filter((t=>e.indexOf(t.id)>=0))},e.getDiffEditorContributions=function(){return O.INSTANCE.getDiffEditorContributions()}}(s||(s={}));class O{static{this.INSTANCE=new O}constructor(){this.editorContributions=[],this.diffEditorContributions=[],this.editorActions=[],this.editorCommands=Object.create(null)}registerEditorContribution(e,t,i){this.editorContributions.push({id:e,ctor:t,instantiation:i})}getEditorContributions(){return this.editorContributions.slice(0)}getDiffEditorContributions(){return this.diffEditorContributions.slice(0)}registerEditorAction(e){e.register(),this.editorActions.push(e)}getEditorActions(){return this.editorActions}registerEditorCommand(e){e.register(),this.editorCommands[e.id]=e}getEditorCommand(e){return this.editorCommands[e]||null}}function D(e){return e.register(),e}m.O.add("editor.contributions",O.INSTANCE);const M=D(new b({id:"undo",precondition:void 0,kbOpts:{weight:0,primary:2104},menuOpts:[{menuId:h.D8.MenubarEditMenu,group:"1_do",title:n.kg({key:"miUndo",comment:["&& denotes a mnemonic"]},"&&Undo"),order:1},{menuId:h.D8.CommandPalette,group:"",title:n.kg("undo","Undo"),order:1}]}));D(new S(M,{id:"default:undo",precondition:void 0}));const P=D(new b({id:"redo",precondition:void 0,kbOpts:{weight:0,primary:2103,secondary:[3128],mac:{primary:3128}},menuOpts:[{menuId:h.D8.MenubarEditMenu,group:"1_do",title:n.kg({key:"miRedo",comment:["&& denotes a mnemonic"]},"&&Redo"),order:2},{menuId:h.D8.CommandPalette,group:"",title:n.kg("redo","Redo"),order:1}]}));D(new S(P,{id:"default:redo",precondition:void 0}));const F=D(new b({id:"editor.action.selectAll",precondition:void 0,kbOpts:{weight:0,kbExpr:null,primary:2079},menuOpts:[{menuId:h.D8.MenubarSelectionMenu,group:"1_basic",title:n.kg({key:"miSelectAll",comment:["&& denotes a mnemonic"]},"&&Select All"),order:1},{menuId:h.D8.CommandPalette,group:"",title:n.kg("selectAll","Select All"),order:1}]}))},31474:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"dockerfile",extensions:[".dockerfile"],filenames:["Dockerfile"],aliases:["Dockerfile"],loader:()=>i.e(46012).then(i.bind(i,46012))})},31659:(e,t,i)=>{"use strict";var s=i(5662),n=i(31450),r=i(36677),o=i(9772),a=i(28712),c=i(77011),l=i(57039);class h extends s.jG{static{this.ID="editor.contrib.colorContribution"}constructor(e){super(),this._editor=e,this._register(e.onMouseDown((e=>this.onMouseDown(e))))}dispose(){super.dispose()}onMouseDown(e){const t=this._editor.getOption(149);if("click"!==t&&"clickAndHover"!==t)return;const i=e.target;if(6!==i.type)return;if(!i.detail.injectedText)return;if(i.detail.injectedText.options.attachedData!==o.nM)return;if(!i.range)return;const s=this._editor.getContribution(c.A.ID);if(s&&!s.isColorPickerVisible){const e=new r.Q(i.range.startLineNumber,i.range.startColumn+1,i.range.endLineNumber,i.range.endColumn+1);s.showContentHover(e,1,0,!1,!0)}}}(0,n.HW)(h.ID,h,2),l.B2.register(a.BJ)},31819:(e,t,i)=>{"use strict";i.d(t,{A:()=>n});var s=i(59284);const n=e=>s.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",width:16,height:16,fill:"none",viewBox:"0 0 16 16"},e),s.createElement("path",{fill:"currentColor",fillRule:"evenodd",d:"M4.5 3A1.5 1.5 0 0 0 3 4.5v1.75a.75.75 0 0 1-1.5 0V4.5a3 3 0 0 1 3-3h1.75a.75.75 0 0 1 0 1.5zM9 2.25a.75.75 0 0 1 .75-.75h1.75a3 3 0 0 1 3 3v1.75a.75.75 0 0 1-1.5 0V4.5A1.5 1.5 0 0 0 11.5 3H9.75A.75.75 0 0 1 9 2.25M2.25 9a.75.75 0 0 1 .75.75v1.75A1.5 1.5 0 0 0 4.5 13h1.75a.75.75 0 0 1 0 1.5H4.5a3 3 0 0 1-3-3V9.75A.75.75 0 0 1 2.25 9m11.5 0a.75.75 0 0 1 .75.75v1.75a3 3 0 0 1-3 3H9.75a.75.75 0 0 1 0-1.5h1.75a1.5 1.5 0 0 0 1.5-1.5V9.75a.75.75 0 0 1 .75-.75",clipRule:"evenodd"}))},32371:(e,t,i)=>{"use strict";i.d(t,{BB:()=>u,WG:()=>v,aw:()=>f,br:()=>m,nZ:()=>E,yS:()=>g});var s=i(18447),n=i(64383),r=i(79400),o=i(23750),a=i(50091),c=i(631),l=i(98232),h=i(36677),d=i(56942);function u(e){return e&&!!e.data}function g(e){return e&&Array.isArray(e.edits)}class p{constructor(e,t,i){this.provider=e,this.tokens=t,this.error=i}}function m(e,t){return e.has(t)}async function f(e,t,i,s,n){const r=function(e,t){const i=e.orderedGroups(t);return i.length>0?i[0]:[]}(e,t),o=await Promise.all(r.map((async e=>{let r,o=null;try{r=await e.provideDocumentSemanticTokens(t,e===i?s:null,n)}catch(a){o=a,r=null}return r&&(u(r)||g(r))||(r=null),new p(e,r,o)})));for(const a of o){if(a.error)throw a.error;if(a.tokens)return a}return o.length>0?o[0]:null}class _{constructor(e,t){this.provider=e,this.tokens=t}}function v(e,t){return e.has(t)}function C(e,t){const i=e.orderedGroups(t);return i.length>0?i[0]:[]}async function E(e,t,i,s){const r=C(e,t),o=await Promise.all(r.map((async e=>{let r;try{r=await e.provideDocumentRangeSemanticTokens(t,i,s)}catch(o){(0,n.M_)(o),r=null}return r&&u(r)||(r=null),new _(e,r)})));for(const n of o)if(n.tokens)return n;return o.length>0?o[0]:null}a.w.registerCommand("_provideDocumentSemanticTokensLegend",(async(e,...t)=>{const[i]=t;(0,c.j)(i instanceof r.r);const s=e.get(o.IModelService).getModel(i);if(!s)return;const{documentSemanticTokensProvider:n}=e.get(d.ILanguageFeaturesService),l=function(e,t){const i=e.orderedGroups(t);return i.length>0?i[0]:null}(n,s);return l?l[0].getLegend():e.get(a.d).executeCommand("_provideDocumentRangeSemanticTokensLegend",i)})),a.w.registerCommand("_provideDocumentSemanticTokens",(async(e,...t)=>{const[i]=t;(0,c.j)(i instanceof r.r);const n=e.get(o.IModelService).getModel(i);if(!n)return;const{documentSemanticTokensProvider:h}=e.get(d.ILanguageFeaturesService);if(!m(h,n))return e.get(a.d).executeCommand("_provideDocumentRangeSemanticTokens",i,n.getFullModelRange());const g=await f(h,n,null,null,s.XO.None);if(!g)return;const{provider:p,tokens:_}=g;if(!_||!u(_))return;const v=(0,l.encodeSemanticTokensDto)({id:0,type:"full",data:_.data});return _.resultId&&p.releaseDocumentSemanticTokens(_.resultId),v})),a.w.registerCommand("_provideDocumentRangeSemanticTokensLegend",(async(e,...t)=>{const[i,n]=t;(0,c.j)(i instanceof r.r);const a=e.get(o.IModelService).getModel(i);if(!a)return;const{documentRangeSemanticTokensProvider:l}=e.get(d.ILanguageFeaturesService),u=C(l,a);if(0===u.length)return;if(1===u.length)return u[0].getLegend();if(!n||!h.Q.isIRange(n))return console.warn("provideDocumentRangeSemanticTokensLegend might be out-of-sync with provideDocumentRangeSemanticTokens unless a range argument is passed in"),u[0].getLegend();const g=await E(l,a,h.Q.lift(n),s.XO.None);return g?g.provider.getLegend():void 0})),a.w.registerCommand("_provideDocumentRangeSemanticTokens",(async(e,...t)=>{const[i,n]=t;(0,c.j)(i instanceof r.r),(0,c.j)(h.Q.isIRange(n));const a=e.get(o.IModelService).getModel(i);if(!a)return;const{documentRangeSemanticTokensProvider:u}=e.get(d.ILanguageFeaturesService),g=await E(u,a,h.Q.lift(n),s.XO.None);return g&&g.tokens?(0,l.encodeSemanticTokensDto)({id:0,type:"full",data:g.tokens.data}):void 0}))},32398:(e,t,i)=>{"use strict";i.d(t,{GN:()=>c,UB:()=>a,a6:()=>l,wc:()=>h});var s=i(83069),n=i(36677),r=i(92896),o=i(87908);class a{constructor(e,t,i,s,n){this.editorId=e,this.model=t,this.configuration=i,this._linesCollection=s,this._coordinatesConverter=n,this._decorationsCache=Object.create(null),this._cachedModelDecorationsResolver=null,this._cachedModelDecorationsResolverViewRange=null}_clearCachedModelDecorationsResolver(){this._cachedModelDecorationsResolver=null,this._cachedModelDecorationsResolverViewRange=null}dispose(){this._decorationsCache=Object.create(null),this._clearCachedModelDecorationsResolver()}reset(){this._decorationsCache=Object.create(null),this._clearCachedModelDecorationsResolver()}onModelDecorationsChanged(){this._decorationsCache=Object.create(null),this._clearCachedModelDecorationsResolver()}onLineMappingChanged(){this._decorationsCache=Object.create(null),this._clearCachedModelDecorationsResolver()}_getOrCreateViewModelDecoration(e){const t=e.id;let i=this._decorationsCache[t];if(!i){const o=e.range,a=e.options;let c;if(a.isWholeLine){const e=this._coordinatesConverter.convertModelPositionToViewPosition(new s.y(o.startLineNumber,1),0,!1,!0),t=this._coordinatesConverter.convertModelPositionToViewPosition(new s.y(o.endLineNumber,this.model.getLineMaxColumn(o.endLineNumber)),1);c=new n.Q(e.lineNumber,e.column,t.lineNumber,t.column)}else c=this._coordinatesConverter.convertModelRangeToViewRange(o,1);i=new r.vo(c,a),this._decorationsCache[t]=i}return i}getMinimapDecorationsInRange(e){return this._getDecorationsInRange(e,!0,!1).decorations}getDecorationsViewportData(e){let t=null!==this._cachedModelDecorationsResolver;return t=t&&e.equalsRange(this._cachedModelDecorationsResolverViewRange),t||(this._cachedModelDecorationsResolver=this._getDecorationsInRange(e,!1,!1),this._cachedModelDecorationsResolverViewRange=e),this._cachedModelDecorationsResolver}getInlineDecorationsOnLine(e,t=!1,i=!1){const s=new n.Q(e,this._linesCollection.getViewLineMinColumn(e),e,this._linesCollection.getViewLineMaxColumn(e));return this._getDecorationsInRange(s,t,i).inlineDecorations[0]}_getDecorationsInRange(e,t,i){const s=this._linesCollection.getDecorationsInRange(e,this.editorId,(0,o.$C)(this.configuration.options),t,i),a=e.startLineNumber,l=e.endLineNumber,h=[];let d=0;const u=[];for(let n=a;n<=l;n++)u[n-a]=[];for(let o=0,g=s.length;o1===e))}function h(e,t){return d(e,t.range,(e=>2===e))}function d(e,t,i){for(let s=t.startLineNumber;s<=t.endLineNumber;s++){const n=e.tokenization.getLineTokens(s),r=s===t.startLineNumber,o=s===t.endLineNumber;let a=r?n.findTokenIndexAtOffset(t.startColumn-1):0;for(;at.endColumn-1)break}if(!i(n.getStandardTokenType(a)))return!1;a++}}return!0}},32500:(e,t,i)=>{"use strict";i.r(t),i.d(t,{ILanguageFeatureDebounceService:()=>g,LanguageFeatureDebounceService:()=>_});var s=i(85600),n=i(74320),r=i(1592),o=i(97035),a=i(14718),c=i(63591),l=i(18801),h=i(36456),d=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},u=function(e,t){return function(i,s){t(i,s,e)}};const g=(0,c.u1)("ILanguageFeatureDebounceService");var p;!function(e){const t=new WeakMap;let i=0;e.of=function(e){let s=t.get(e);return void 0===s&&(s=++i,t.set(e,s)),s}}(p||(p={}));class m{constructor(e){this._default=e}get(e){return this._default}update(e,t){return this._default}default(){return this._default}}class f{constructor(e,t,i,s,r,o){this._logService=e,this._name=t,this._registry=i,this._default=s,this._min=r,this._max=o,this._cache=new n.qK(50,.7)}_key(e){return e.id+this._registry.all(e).reduce(((e,t)=>(0,s.sN)(p.of(t),e)),0)}get(e){const t=this._key(e),i=this._cache.get(t);return i?(0,r.qE)(i.value,this._min,this._max):this.default()}update(e,t){const i=this._key(e);let s=this._cache.get(i);s||(s=new r.mu(6),this._cache.set(i,s));const n=(0,r.qE)(s.update(t),this._min,this._max);return(0,h.v$)(e.uri,"output")||this._logService.trace(`[DEBOUNCE: ${this._name}] for ${e.uri.toString()} is ${n}ms`),n}_overall(){const e=new r.Uq;for(const[,t]of this._cache)e.update(t.value);return e.value}default(){const e=0|this._overall()||this._default;return(0,r.qE)(e,this._min,this._max)}}let _=class{constructor(e,t){this._logService=e,this._data=new Map,this._isDev=t.isExtensionDevelopment||!t.isBuilt}for(e,t,i){const s=i?.min??50,n=i?.max??s**2,r=i?.key??void 0,o=`${p.of(e)},${s}${r?","+r:""}`;let a=this._data.get(o);return a||(this._isDev?(this._logService.debug(`[DEBOUNCE: ${t}] is disabled in developed mode`),a=new m(1.5*s)):a=new f(this._logService,t,e,0|this._overallAverage()||1.5*s,s,n),this._data.set(o,a)),a}_overallAverage(){const e=new r.Uq;for(const t of this._data.values())e.update(t.default());return e.value}};_=d([u(0,l.rr),u(1,o.k)],_),(0,a.v)(g,_,1)},32516:(e,t,i)=>{"use strict";var s=i(5662),n=i(31450),r=i(60002),o=i(78209);class a{constructor(e){this.selections=e}equals(e){const t=this.selections.length;if(t!==e.selections.length)return!1;for(let i=0;i{this._undoStack=[],this._redoStack=[]}))),this._register(e.onDidChangeModelContent((e=>{this._undoStack=[],this._redoStack=[]}))),this._register(e.onDidChangeCursorSelection((t=>{if(this._isCursorUndoRedo)return;if(!t.oldSelections)return;if(t.oldModelVersionId!==t.modelVersionId)return;const i=new a(t.oldSelections);this._undoStack.length>0&&this._undoStack[this._undoStack.length-1].cursorState.equals(i)||(this._undoStack.push(new c(i,e.getScrollTop(),e.getScrollLeft())),this._redoStack=[],this._undoStack.length>50&&this._undoStack.shift())})))}cursorUndo(){this._editor.hasModel()&&0!==this._undoStack.length&&(this._redoStack.push(new c(new a(this._editor.getSelections()),this._editor.getScrollTop(),this._editor.getScrollLeft())),this._applyState(this._undoStack.pop()))}cursorRedo(){this._editor.hasModel()&&0!==this._redoStack.length&&(this._undoStack.push(new c(new a(this._editor.getSelections()),this._editor.getScrollTop(),this._editor.getScrollLeft())),this._applyState(this._redoStack.pop()))}_applyState(e){this._isCursorUndoRedo=!0,this._editor.setSelections(e.cursorState.selections),this._editor.setScrollPosition({scrollTop:e.scrollTop,scrollLeft:e.scrollLeft}),this._isCursorUndoRedo=!1}}class h extends n.ks{constructor(){super({id:"cursorUndo",label:o.kg("cursor.undo","Cursor Undo"),alias:"Cursor Undo",precondition:void 0,kbOpts:{kbExpr:r.R.textInputFocus,primary:2099,weight:100}})}run(e,t,i){l.get(t)?.cursorUndo()}}class d extends n.ks{constructor(){super({id:"cursorRedo",label:o.kg("cursor.redo","Cursor Redo"),alias:"Cursor Redo",precondition:void 0})}run(e,t,i){l.get(t)?.cursorRedo()}}(0,n.HW)(l.ID,l,0),(0,n.Fl)(h),(0,n.Fl)(d)},32624:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"pgsql",extensions:[],aliases:["PostgreSQL","postgres","pg","postgre"],loader:()=>i.e(84582).then(i.bind(i,84582))})},32799:(e,t,i)=>{"use strict";i.d(t,{MF:()=>g,d$:()=>u,mG:()=>f,vG:()=>v,vY:()=>_});var s=i(83069),n=i(36677),r=i(75326),o=i(12296),a=i(1245),c=i(93895);const l=()=>!0,h=()=>!1,d=e=>" "===e||"\t"===e;class u{static shouldRecreate(e){return e.hasChanged(146)||e.hasChanged(132)||e.hasChanged(37)||e.hasChanged(77)||e.hasChanged(79)||e.hasChanged(80)||e.hasChanged(6)||e.hasChanged(7)||e.hasChanged(11)||e.hasChanged(9)||e.hasChanged(10)||e.hasChanged(14)||e.hasChanged(129)||e.hasChanged(50)||e.hasChanged(92)||e.hasChanged(131)}constructor(e,t,i,s){this.languageConfigurationService=s,this._cursorMoveConfigurationBrand=void 0,this._languageId=e;const n=i.options,r=n.get(146),o=n.get(50);this.readOnly=n.get(92),this.tabSize=t.tabSize,this.indentSize=t.indentSize,this.insertSpaces=t.insertSpaces,this.stickyTabStops=n.get(117),this.lineHeight=o.lineHeight,this.typicalHalfwidthCharacterWidth=o.typicalHalfwidthCharacterWidth,this.pageSize=Math.max(1,Math.floor(r.height/this.lineHeight)-2),this.useTabStops=n.get(129),this.wordSeparators=n.get(132),this.emptySelectionClipboard=n.get(37),this.copyWithSyntaxHighlighting=n.get(25),this.multiCursorMergeOverlapping=n.get(77),this.multiCursorPaste=n.get(79),this.multiCursorLimit=n.get(80),this.autoClosingBrackets=n.get(6),this.autoClosingComments=n.get(7),this.autoClosingQuotes=n.get(11),this.autoClosingDelete=n.get(9),this.autoClosingOvertype=n.get(10),this.autoSurround=n.get(14),this.autoIndent=n.get(12),this.wordSegmenterLocales=n.get(131),this.surroundingPairs={},this._electricChars=null,this.shouldAutoCloseBefore={quote:this._getShouldAutoClose(e,this.autoClosingQuotes,!0),comment:this._getShouldAutoClose(e,this.autoClosingComments,!1),bracket:this._getShouldAutoClose(e,this.autoClosingBrackets,!1)},this.autoClosingPairs=this.languageConfigurationService.getLanguageConfiguration(e).getAutoClosingPairs();const a=this.languageConfigurationService.getLanguageConfiguration(e).getSurroundingPairs();if(a)for(const l of a)this.surroundingPairs[l.open]=l.close;const c=this.languageConfigurationService.getLanguageConfiguration(e).comments;this.blockCommentStartToken=c?.blockCommentStartToken??null}get electricChars(){if(!this._electricChars){this._electricChars={};const e=this.languageConfigurationService.getLanguageConfiguration(this._languageId).electricCharacter?.getElectricCharacters();if(e)for(const t of e)this._electricChars[t]=!0}return this._electricChars}onElectricCharacter(e,t,i){const s=(0,o.BQ)(t,i-1),n=this.languageConfigurationService.getLanguageConfiguration(s.languageId).electricCharacter;return n?n.onElectricCharacter(e,s,i-s.firstCharOffset):null}normalizeIndentation(e){return(0,c.P)(e,this.indentSize,this.insertSpaces)}_getShouldAutoClose(e,t,i){switch(t){case"beforeWhitespace":return d;case"languageDefined":return this._getLanguageDefinedShouldAutoClose(e,i);case"always":return l;case"never":return h}}_getLanguageDefinedShouldAutoClose(e,t){const i=this.languageConfigurationService.getLanguageConfiguration(e).getAutoCloseBeforeSet(t);return e=>-1!==i.indexOf(e)}visibleColumnFromColumn(e,t){return a.A.visibleColumnFromColumn(e.getLineContent(t.lineNumber),t.column,this.tabSize)}columnFromVisibleColumn(e,t,i){const s=a.A.columnFromVisibleColumn(e.getLineContent(t),i,this.tabSize),n=e.getLineMinColumn(t);if(sr?r:s}}class g{static fromModelState(e){return new p(e)}static fromViewState(e){return new m(e)}static fromModelSelection(e){const t=r.L.liftSelection(e),i=new f(n.Q.fromPositions(t.getSelectionStart()),0,0,t.getPosition(),0);return g.fromModelState(i)}static fromModelSelections(e){const t=[];for(let i=0,s=e.length;i{"use strict";i.d(t,{f1:()=>A,M$:()=>w,fN:()=>K,N1:()=>j,jQ:()=>R,M0:()=>$});var s=i(98067),n=i(91508),r=i(64383),o=i(78209);function a(...e){switch(e.length){case 1:return(0,o.kg)("contextkey.scanner.hint.didYouMean1","Did you mean {0}?",e[0]);case 2:return(0,o.kg)("contextkey.scanner.hint.didYouMean2","Did you mean {0} or {1}?",e[0],e[1]);case 3:return(0,o.kg)("contextkey.scanner.hint.didYouMean3","Did you mean {0}, {1} or {2}?",e[0],e[1],e[2]);default:return}}const c=(0,o.kg)("contextkey.scanner.hint.didYouForgetToOpenOrCloseQuote","Did you forget to open or close the quote?"),l=(0,o.kg)("contextkey.scanner.hint.didYouForgetToEscapeSlash","Did you forget to escape the '/' (slash) character? Put two backslashes before it to escape, e.g., '\\\\/'.");class h{constructor(){this._input="",this._start=0,this._current=0,this._tokens=[],this._errors=[],this.stringRe=/[a-zA-Z0-9_<>\-\./\\:\*\?\+\[\]\^,#@;"%\$\p{L}-]+/uy}static getLexeme(e){switch(e.type){case 0:return"(";case 1:return")";case 2:return"!";case 3:return e.isTripleEq?"===":"==";case 4:return e.isTripleEq?"!==":"!=";case 5:return"<";case 6:return"<=";case 7:case 8:return">=";case 9:return"=~";case 10:case 17:case 18:case 19:return e.lexeme;case 11:return"true";case 12:return"false";case 13:return"in";case 14:return"not";case 15:return"&&";case 16:return"||";case 20:return"EOF";default:throw(0,r.iH)(`unhandled token type: ${JSON.stringify(e)}; have you forgotten to add a case?`)}}static{this._regexFlags=new Set(["i","g","s","m","y","u"].map((e=>e.charCodeAt(0))))}static{this._keywords=new Map([["not",14],["in",13],["false",12],["true",11]])}reset(e){return this._input=e,this._start=0,this._current=0,this._tokens=[],this._errors=[],this}scan(){for(;!this._isAtEnd();){this._start=this._current;switch(this._advance()){case 40:this._addToken(0);break;case 41:this._addToken(1);break;case 33:if(this._match(61)){const e=this._match(61);this._tokens.push({type:4,offset:this._start,isTripleEq:e})}else this._addToken(2);break;case 39:this._quotedString();break;case 47:this._regex();break;case 61:if(this._match(61)){const e=this._match(61);this._tokens.push({type:3,offset:this._start,isTripleEq:e})}else this._match(126)?this._addToken(9):this._error(a("==","=~"));break;case 60:this._addToken(this._match(61)?6:5);break;case 62:this._addToken(this._match(61)?8:7);break;case 38:this._match(38)?this._addToken(15):this._error(a("&&"));break;case 124:this._match(124)?this._addToken(16):this._error(a("||"));break;case 32:case 13:case 9:case 10:case 160:break;default:this._string()}}return this._start=this._current,this._addToken(20),Array.from(this._tokens)}_match(e){return!this._isAtEnd()&&(this._input.charCodeAt(this._current)===e&&(this._current++,!0))}_advance(){return this._input.charCodeAt(this._current++)}_peek(){return this._isAtEnd()?0:this._input.charCodeAt(this._current)}_addToken(e){this._tokens.push({type:e,offset:this._start})}_error(e){const t=this._start,i=this._input.substring(this._start,this._current),s={type:19,offset:this._start,lexeme:i};this._errors.push({offset:t,lexeme:i,additionalInfo:e}),this._tokens.push(s)}_string(){this.stringRe.lastIndex=this._start;const e=this.stringRe.exec(this._input);if(e){this._current=this._start+e[0].length;const t=this._input.substring(this._start,this._current),i=h._keywords.get(t);i?this._addToken(i):this._tokens.push({type:17,lexeme:t,offset:this._start})}}_quotedString(){for(;39!==this._peek()&&!this._isAtEnd();)this._advance();this._isAtEnd()?this._error(c):(this._advance(),this._tokens.push({type:18,lexeme:this._input.substring(this._start+1,this._current-1),offset:this._start+1}))}_regex(){let e=this._current,t=!1,i=!1;for(;;){if(e>=this._input.length)return this._current=e,void this._error(l);const s=this._input.charCodeAt(e);if(t)t=!1;else{if(47===s&&!i){e++;break}91===s?i=!0:92===s?t=!0:93===s&&(i=!1)}e++}for(;e=this._input.length}}var d=i(63591);const u=new Map;u.set("false",!1),u.set("true",!0),u.set("isMac",s.zx),u.set("isLinux",s.j9),u.set("isWindows",s.uF),u.set("isWeb",s.HZ),u.set("isMacNative",s.zx&&!s.HZ),u.set("isEdge",s.UP),u.set("isFirefox",s.gm),u.set("isChrome",s.H8),u.set("isSafari",s.nr);const g=Object.prototype.hasOwnProperty,p={regexParsingWithErrorRecovery:!0},m=(0,o.kg)("contextkey.parser.error.emptyString","Empty context key expression"),f=(0,o.kg)("contextkey.parser.error.emptyString.hint","Did you forget to write an expression? You can also put 'false' or 'true' to always evaluate to false or true, respectively."),_=(0,o.kg)("contextkey.parser.error.noInAfterNot","'in' after 'not'."),v=(0,o.kg)("contextkey.parser.error.closingParenthesis","closing parenthesis ')'"),C=(0,o.kg)("contextkey.parser.error.unexpectedToken","Unexpected token"),E=(0,o.kg)("contextkey.parser.error.unexpectedToken.hint","Did you forget to put && or || before the token?"),b=(0,o.kg)("contextkey.parser.error.unexpectedEOF","Unexpected end of expression"),S=(0,o.kg)("contextkey.parser.error.unexpectedEOF.hint","Did you forget to put a context key?");class y{static{this._parseError=new Error}constructor(e=p){this._config=e,this._scanner=new h,this._tokens=[],this._current=0,this._parsingErrors=[],this._flagsGYRe=/g|y/g}parse(e){if(""!==e){this._tokens=this._scanner.reset(e).scan(),this._current=0,this._parsingErrors=[];try{const e=this._expr();if(!this._isAtEnd()){const e=this._peek(),t=17===e.type?E:void 0;throw this._parsingErrors.push({message:C,offset:e.offset,lexeme:h.getLexeme(e),additionalInfo:t}),y._parseError}return e}catch(t){if(t!==y._parseError)throw t;return}}else this._parsingErrors.push({message:m,offset:0,lexeme:"",additionalInfo:f})}_expr(){return this._or()}_or(){const e=[this._and()];for(;this._matchOne(16);){const t=this._and();e.push(t)}return 1===e.length?e[0]:w.or(...e)}_and(){const e=[this._term()];for(;this._matchOne(15);){const t=this._term();e.push(t)}return 1===e.length?e[0]:w.and(...e)}_term(){if(this._matchOne(2)){const e=this._peek();switch(e.type){case 11:return this._advance(),T.INSTANCE;case 12:return this._advance(),x.INSTANCE;case 0:{this._advance();const e=this._expr();return this._consume(1,v),e?.negate()}case 17:return this._advance(),D.create(e.lexeme);default:throw this._errExpectedButGot("KEY | true | false | '(' expression ')'",e)}}return this._primary()}_primary(){const e=this._peek();switch(e.type){case 11:return this._advance(),w.true();case 12:return this._advance(),w.false();case 0:{this._advance();const e=this._expr();return this._consume(1,v),e}case 17:{const s=e.lexeme;if(this._advance(),this._matchOne(9)){const e=this._peek();if(!this._config.regexParsingWithErrorRecovery){if(this._advance(),10!==e.type)throw this._errExpectedButGot("REGEX",e);const i=e.lexeme,n=i.lastIndexOf("/"),r=n===i.length-1?void 0:this._removeFlagsGY(i.substring(n+1));let o;try{o=new RegExp(i.substring(1,n),r)}catch(t){throw this._errExpectedButGot("REGEX",e)}return B.create(s,o)}switch(e.type){case 10:case 19:{const i=[e.lexeme];this._advance();let n=this._peek(),r=0;for(let t=0;t=0){const o=t.slice(s+1,n),a="i"===t[n+1]?"i":"";try{r=new RegExp(o,a)}catch(i){throw this._errExpectedButGot("REGEX",e)}}}if(null===r)throw this._errExpectedButGot("REGEX",e);return B.create(s,r)}default:throw this._errExpectedButGot("REGEX",this._peek())}}if(this._matchOne(14)){this._consume(13,_);const e=this._value();return w.notIn(s,e)}switch(this._peek().type){case 3:{this._advance();const e=this._value();if(18===this._previous().type)return w.equals(s,e);switch(e){case"true":return w.has(s);case"false":return w.not(s);default:return w.equals(s,e)}}case 4:{this._advance();const e=this._value();if(18===this._previous().type)return w.notEquals(s,e);switch(e){case"true":return w.not(s);case"false":return w.has(s);default:return w.notEquals(s,e)}}case 5:return this._advance(),U.create(s,this._value());case 6:return this._advance(),H.create(s,this._value());case 7:return this._advance(),P.create(s,this._value());case 8:return this._advance(),F.create(s,this._value());case 13:return this._advance(),w.in(s,this._value());default:return w.has(s)}}case 20:throw this._parsingErrors.push({message:b,offset:e.offset,lexeme:"",additionalInfo:S}),y._parseError;default:throw this._errExpectedButGot("true | false | KEY \n\t| KEY '=~' REGEX \n\t| KEY ('==' | '!=' | '<' | '<=' | '>' | '>=' | 'in' | 'not' 'in') value",this._peek())}}_value(){const e=this._peek();switch(e.type){case 17:case 18:return this._advance(),e.lexeme;case 11:return this._advance(),"true";case 12:return this._advance(),"false";case 13:return this._advance(),"in";default:return""}}_removeFlagsGY(e){return e.replaceAll(this._flagsGYRe,"")}_previous(){return this._tokens[this._current-1]}_matchOne(e){return!!this._check(e)&&(this._advance(),!0)}_advance(){return this._isAtEnd()||this._current++,this._previous()}_consume(e,t){if(this._check(e))return this._advance();throw this._errExpectedButGot(t,this._peek())}_errExpectedButGot(e,t,i){const s=(0,o.kg)("contextkey.parser.error.expectedButGot","Expected: {0}\nReceived: '{1}'.",e,h.getLexeme(t)),n=t.offset,r=h.getLexeme(t);return this._parsingErrors.push({message:s,offset:n,lexeme:r,additionalInfo:i}),y._parseError}_check(e){return this._peek().type===e}_peek(){return this._tokens[this._current]}_isAtEnd(){return 20===this._peek().type}}class w{static false(){return T.INSTANCE}static true(){return x.INSTANCE}static has(e){return k.create(e)}static equals(e,t){return A.create(e,t)}static notEquals(e,t){return O.create(e,t)}static regex(e,t){return B.create(e,t)}static in(e,t){return N.create(e,t)}static notIn(e,t){return I.create(e,t)}static not(e){return D.create(e)}static and(...e){return z.create(e,null,!0)}static or(...e){return G.create(e,null,!0)}static{this._parser=new y({regexParsingWithErrorRecovery:!1})}static deserialize(e){if(void 0===e||null===e)return;return this._parser.parse(e)}}function R(e,t){const i=e?e.substituteConstants():void 0,s=t?t.substituteConstants():void 0;return!i&&!s||!(!i||!s)&&i.equals(s)}function L(e,t){return e.cmp(t)}class T{static{this.INSTANCE=new T}constructor(){this.type=0}cmp(e){return this.type-e.type}equals(e){return e.type===this.type}substituteConstants(){return this}evaluate(e){return!1}serialize(){return"false"}keys(){return[]}negate(){return x.INSTANCE}}class x{static{this.INSTANCE=new x}constructor(){this.type=1}cmp(e){return this.type-e.type}equals(e){return e.type===this.type}substituteConstants(){return this}evaluate(e){return!0}serialize(){return"true"}keys(){return[]}negate(){return T.INSTANCE}}class k{static create(e,t=null){const i=u.get(e);return"boolean"===typeof i?i?x.INSTANCE:T.INSTANCE:new k(e,t)}constructor(e,t){this.key=e,this.negated=t,this.type=2}cmp(e){return e.type!==this.type?this.type-e.type:Y(this.key,e.key)}equals(e){return e.type===this.type&&this.key===e.key}substituteConstants(){const e=u.get(this.key);return"boolean"===typeof e?e?x.INSTANCE:T.INSTANCE:this}evaluate(e){return!!e.getValue(this.key)}serialize(){return this.key}keys(){return[this.key]}negate(){return this.negated||(this.negated=D.create(this.key,this)),this.negated}}class A{static create(e,t,i=null){if("boolean"===typeof t)return t?k.create(e,i):D.create(e,i);const s=u.get(e);if("boolean"===typeof s){return t===(s?"true":"false")?x.INSTANCE:T.INSTANCE}return new A(e,t,i)}constructor(e,t,i){this.key=e,this.value=t,this.negated=i,this.type=4}cmp(e){return e.type!==this.type?this.type-e.type:q(this.key,this.value,e.key,e.value)}equals(e){return e.type===this.type&&(this.key===e.key&&this.value===e.value)}substituteConstants(){const e=u.get(this.key);if("boolean"===typeof e){const t=e?"true":"false";return this.value===t?x.INSTANCE:T.INSTANCE}return this}evaluate(e){return e.getValue(this.key)==this.value}serialize(){return`${this.key} == '${this.value}'`}keys(){return[this.key]}negate(){return this.negated||(this.negated=O.create(this.key,this.value,this)),this.negated}}class N{static create(e,t){return new N(e,t)}constructor(e,t){this.key=e,this.valueKey=t,this.type=10,this.negated=null}cmp(e){return e.type!==this.type?this.type-e.type:q(this.key,this.valueKey,e.key,e.valueKey)}equals(e){return e.type===this.type&&(this.key===e.key&&this.valueKey===e.valueKey)}substituteConstants(){return this}evaluate(e){const t=e.getValue(this.valueKey),i=e.getValue(this.key);return Array.isArray(t)?t.includes(i):"string"===typeof i&&"object"===typeof t&&null!==t&&g.call(t,i)}serialize(){return`${this.key} in '${this.valueKey}'`}keys(){return[this.key,this.valueKey]}negate(){return this.negated||(this.negated=I.create(this.key,this.valueKey)),this.negated}}class I{static create(e,t){return new I(e,t)}constructor(e,t){this.key=e,this.valueKey=t,this.type=11,this._negated=N.create(e,t)}cmp(e){return e.type!==this.type?this.type-e.type:this._negated.cmp(e._negated)}equals(e){return e.type===this.type&&this._negated.equals(e._negated)}substituteConstants(){return this}evaluate(e){return!this._negated.evaluate(e)}serialize(){return`${this.key} not in '${this.valueKey}'`}keys(){return this._negated.keys()}negate(){return this._negated}}class O{static create(e,t,i=null){if("boolean"===typeof t)return t?D.create(e,i):k.create(e,i);const s=u.get(e);if("boolean"===typeof s){return t===(s?"true":"false")?T.INSTANCE:x.INSTANCE}return new O(e,t,i)}constructor(e,t,i){this.key=e,this.value=t,this.negated=i,this.type=5}cmp(e){return e.type!==this.type?this.type-e.type:q(this.key,this.value,e.key,e.value)}equals(e){return e.type===this.type&&(this.key===e.key&&this.value===e.value)}substituteConstants(){const e=u.get(this.key);if("boolean"===typeof e){const t=e?"true":"false";return this.value===t?T.INSTANCE:x.INSTANCE}return this}evaluate(e){return e.getValue(this.key)!=this.value}serialize(){return`${this.key} != '${this.value}'`}keys(){return[this.key]}negate(){return this.negated||(this.negated=A.create(this.key,this.value,this)),this.negated}}class D{static create(e,t=null){const i=u.get(e);return"boolean"===typeof i?i?T.INSTANCE:x.INSTANCE:new D(e,t)}constructor(e,t){this.key=e,this.negated=t,this.type=3}cmp(e){return e.type!==this.type?this.type-e.type:Y(this.key,e.key)}equals(e){return e.type===this.type&&this.key===e.key}substituteConstants(){const e=u.get(this.key);return"boolean"===typeof e?e?T.INSTANCE:x.INSTANCE:this}evaluate(e){return!e.getValue(this.key)}serialize(){return`!${this.key}`}keys(){return[this.key]}negate(){return this.negated||(this.negated=k.create(this.key,this)),this.negated}}function M(e,t){if("string"===typeof e){const t=parseFloat(e);isNaN(t)||(e=t)}return"string"===typeof e||"number"===typeof e?t(e):T.INSTANCE}class P{static create(e,t,i=null){return M(t,(t=>new P(e,t,i)))}constructor(e,t,i){this.key=e,this.value=t,this.negated=i,this.type=12}cmp(e){return e.type!==this.type?this.type-e.type:q(this.key,this.value,e.key,e.value)}equals(e){return e.type===this.type&&(this.key===e.key&&this.value===e.value)}substituteConstants(){return this}evaluate(e){return"string"!==typeof this.value&&parseFloat(e.getValue(this.key))>this.value}serialize(){return`${this.key} > ${this.value}`}keys(){return[this.key]}negate(){return this.negated||(this.negated=H.create(this.key,this.value,this)),this.negated}}class F{static create(e,t,i=null){return M(t,(t=>new F(e,t,i)))}constructor(e,t,i){this.key=e,this.value=t,this.negated=i,this.type=13}cmp(e){return e.type!==this.type?this.type-e.type:q(this.key,this.value,e.key,e.value)}equals(e){return e.type===this.type&&(this.key===e.key&&this.value===e.value)}substituteConstants(){return this}evaluate(e){return"string"!==typeof this.value&&parseFloat(e.getValue(this.key))>=this.value}serialize(){return`${this.key} >= ${this.value}`}keys(){return[this.key]}negate(){return this.negated||(this.negated=U.create(this.key,this.value,this)),this.negated}}class U{static create(e,t,i=null){return M(t,(t=>new U(e,t,i)))}constructor(e,t,i){this.key=e,this.value=t,this.negated=i,this.type=14}cmp(e){return e.type!==this.type?this.type-e.type:q(this.key,this.value,e.key,e.value)}equals(e){return e.type===this.type&&(this.key===e.key&&this.value===e.value)}substituteConstants(){return this}evaluate(e){return"string"!==typeof this.value&&parseFloat(e.getValue(this.key))new H(e,t,i)))}constructor(e,t,i){this.key=e,this.value=t,this.negated=i,this.type=15}cmp(e){return e.type!==this.type?this.type-e.type:q(this.key,this.value,e.key,e.value)}equals(e){return e.type===this.type&&(this.key===e.key&&this.value===e.value)}substituteConstants(){return this}evaluate(e){return"string"!==typeof this.value&&parseFloat(e.getValue(this.key))<=this.value}serialize(){return`${this.key} <= ${this.value}`}keys(){return[this.key]}negate(){return this.negated||(this.negated=P.create(this.key,this.value,this)),this.negated}}class B{static create(e,t){return new B(e,t)}constructor(e,t){this.key=e,this.regexp=t,this.type=7,this.negated=null}cmp(e){if(e.type!==this.type)return this.type-e.type;if(this.keye.key)return 1;const t=this.regexp?this.regexp.source:"",i=e.regexp?e.regexp.source:"";return ti?1:0}equals(e){if(e.type===this.type){const t=this.regexp?this.regexp.source:"",i=e.regexp?e.regexp.source:"";return this.key===e.key&&t===i}return!1}substituteConstants(){return this}evaluate(e){const t=e.getValue(this.key);return!!this.regexp&&this.regexp.test(t)}serialize(){const e=this.regexp?`/${this.regexp.source}/${this.regexp.flags}`:"/invalid/";return`${this.key} =~ ${e}`}keys(){return[this.key]}negate(){return this.negated||(this.negated=W.create(this)),this.negated}}class W{static create(e){return new W(e)}constructor(e){this._actual=e,this.type=8}cmp(e){return e.type!==this.type?this.type-e.type:this._actual.cmp(e._actual)}equals(e){return e.type===this.type&&this._actual.equals(e._actual)}substituteConstants(){return this}evaluate(e){return!this._actual.evaluate(e)}serialize(){return`!(${this._actual.serialize()})`}keys(){return this._actual.keys()}negate(){return this._actual}}function V(e){let t=null;for(let i=0,s=e.length;ie.expr.length)return 1;for(let t=0,i=this.expr.length;t1;){const e=s[s.length-1];if(9!==e.type)break;s.pop();const t=s.pop(),n=0===s.length,r=G.create(e.expr.map((e=>z.create([e,t],null,i))),null,n);r&&(s.push(r),s.sort(L))}if(1===s.length)return s[0];if(i){for(let e=0;ee.serialize())).join(" && ")}keys(){const e=[];for(const t of this.expr)e.push(...t.keys());return e}negate(){if(!this.negated){const e=[];for(const t of this.expr)e.push(t.negate());this.negated=G.create(e,this,!0)}return this.negated}}class G{static create(e,t,i){return G._normalizeArr(e,t,i)}constructor(e,t){this.expr=e,this.negated=t,this.type=9}cmp(e){if(e.type!==this.type)return this.type-e.type;if(this.expr.lengthe.expr.length)return 1;for(let t=0,i=this.expr.length;te.serialize())).join(" || ")}keys(){const e=[];for(const t of this.expr)e.push(...t.keys());return e}negate(){if(!this.negated){const e=[];for(const t of this.expr)e.push(t.negate());for(;e.length>1;){const t=e.shift(),i=e.shift(),s=[];for(const e of X(t))for(const t of X(i))s.push(z.create([e,t],null,!1));e.unshift(G.create(s,null,!1))}this.negated=G.create(e,this,!0)}return this.negated}}class j extends k{static{this._info=[]}static all(){return j._info.values()}constructor(e,t,i){super(e,null),this._defaultValue=t,"object"===typeof i?j._info.push({...i,key:e}):!0!==i&&j._info.push({key:e,description:i,type:null!==t&&void 0!==t?typeof t:void 0})}bindTo(e){return e.createKey(this.key,this._defaultValue)}getValue(e){return e.getContextKeyValue(this.key)}toNegated(){return this.negate()}isEqualTo(e){return A.create(this.key,e)}}const K=(0,d.u1)("contextKeyService");function Y(e,t){return et?1:0}function q(e,t,i,s){return ei?1:ts?1:0}function $(e,t){if(0===e.type||1===t.type)return!0;if(9===e.type)return 9===t.type&&Q(e.expr,t.expr);if(9===t.type){for(const i of t.expr)if($(e,i))return!0;return!1}if(6===e.type){if(6===t.type)return Q(t.expr,e.expr);for(const i of e.expr)if($(i,t))return!0;return!1}return e.equals(t)}function Q(e,t){let i=0,s=0;for(;i{"use strict";i.d(t,{FD:()=>r,Mg:()=>o,gV:()=>n});const s=[];class n{static{this.cache=new Array(129)}static create(e,t){if(e<=128&&0===t.length){let i=n.cache[e];return i||(i=new n(e,t),n.cache[e]=i),i}return new n(e,t)}static{this.empty=n.create(0,s)}static getEmpty(){return this.empty}constructor(e,t){this.items=e,this.additionalItems=t}add(e,t){const i=t.getKey(e);let s=i>>5;if(0===s){const e=1<e};class o{constructor(){this.items=new Map}getKey(e){let t=this.items.get(e);return void 0===t&&(t=this.items.size,this.items.set(e,t)),t}}},33157:(e,t,i)=>{var s=i(33609),n=i(89807);e.exports=function(e,t,i,r){var o=e.length;for((i=s(i))<0&&(i=-i>o?0:o+i),(r=void 0===r||r>o?o:s(r))<0&&(r+=o),r=i>r?0:n(r);i{"use strict";(0,i(34918).K)({id:"rust",extensions:[".rs",".rlib"],aliases:["Rust","rust"],loader:()=>i.e(3648).then(i.bind(i,3648))})},34072:(e,t,i)=>{"use strict";i.d(t,{_:()=>r});var s=i(8597),n=i(5662);class r{constructor(){this._hooks=new n.Cm,this._pointerMoveCallback=null,this._onStopCallback=null}dispose(){this.stopMonitoring(!1),this._hooks.dispose()}stopMonitoring(e,t){if(!this.isMonitoring())return;this._hooks.clear(),this._pointerMoveCallback=null;const i=this._onStopCallback;this._onStopCallback=null,e&&i&&i(t)}isMonitoring(){return!!this._pointerMoveCallback}startMonitoring(e,t,i,r,o){this.isMonitoring()&&this.stopMonitoring(!1),this._pointerMoveCallback=r,this._onStopCallback=o;let a=e;try{e.setPointerCapture(t),this._hooks.add((0,n.s)((()=>{try{e.releasePointerCapture(t)}catch(i){}})))}catch(c){a=s.zk(e)}this._hooks.add(s.ko(a,s.Bx.POINTER_MOVE,(e=>{e.buttons===i?(e.preventDefault(),this._pointerMoveCallback(e)):this.stopMonitoring(!0)}))),this._hooks.add(s.ko(a,s.Bx.POINTER_UP,(e=>this.stopMonitoring(!0))))}}},34132:e=>{!function(){function t(e){return"yql."+e}function i(e,i){const s=t(i.toLowerCase());switch(i){case"String":case"Uuid":if(Array.isArray(e))return{$binary:!0,$type:s,$value:e[0]}}return{$type:s,$value:e}}function s(e,t){let s;return s="StructType"===t[0]?i(t[1][e][0],"String"):i(e,"Int32"),s.$key=!0,s}function n(e){const i={};return e.$value.forEach((function(e){const s=e[0],n=e[1];if(s.$type!==t("string"))throw new Error("unipika: try to convert struct with no-string keys to object");i[s.$value]=n.$value})),i}function r(e={}){return Object.prototype.hasOwnProperty.call(e,"src")&&"string"===typeof e.src?e.src:"string"===typeof e.$value?e.$value:void 0}function o(e,o,a){function c(e){return o.maxListSize>0&&Array.isArray(e)&&e.length>o.maxListSize?e.slice(0,o.maxListSize):e}function l(e,t){return t&&(e.$incomplete=!0),e}function h(e){if(o.maxStringSize>0&&e.$value){if(!e.$binary&&!e.$tag&&e.$value.length>o.maxStringSize)return e.$original_value=e.$value,e.$value=e.$value.substr(0,o.maxStringSize),l(e,!0);if(e.$binary&&!e.$tag&&.75*e.$value.length>o.maxStringSize)return e.$original_value=e.$value,e.$value=function(e,t){const i=Math.min(Math.floor(t/3),Math.ceil(e.length/4)),s=4*i,n=Math.min(t-3*i,e.length-s),r=e.substr(0,s);return 1==n?r+e.substr(s,2)+"==":2==n?r+e.substr(s,3)+"=":r}(e.$value,o.maxStringSize),l(e,!0)}return e}return function e(d,u){const g=u[0],p=u[1];let m,f,_;switch(o.treatValAsData&&d&&Object.hasOwnProperty.call(d,"val")&&(m=d.inc,f=d.b64,d=d.val),m?_=d:(_=c(d),m=_!==d),a.incomplete=a.incomplete||m,g){case"OptionalType":{const t=Array.isArray(d)&&d.length,i=t?e(d[0],p):e(null,["VoidType"]);return t&&(i.$optional=(i.$optional||0)+1),i}case"TaggedType":return function(e,i,s,o,a){let c,l=o(s,i);switch(e){case"url":if("StructType"===i[0]){if(c=n(l),!Object.prototype.hasOwnProperty.call(c,"href")||"string"!==typeof c.href)return l;l={$type:"tag_value",$value:c}}break;case"videourl":case"audiourl":case"imageurl":{if("StructType"===i[0]){c=n(l);const e=r(c);if(!e||!a(e))return l;l={$type:"tag_value",$value:c}}const e=r(l);if(e&&!a(e))return l;break}case"image/svg":case"image/svg+xml":case"image/jpeg":case"image/png":case"image/gif":case"image/webp":case"video/mp4":case"video/webm":if("StructType"===i[0]){if(c=n(l),!r(c))return l;l={$type:"tag_value",$value:c}}}return{$type:t("tagged"),$tag:e,$value:l}}(u[1],u[2],d,e,o.validateSrcUrl);case"ListType":return l({$type:t("list"),$value:_.map((function(t){return e(t,u[1])}))},m);case"StreamType":return l({$type:t("stream"),$value:_.map((function(t){return e(t,u[1])}))},m);case"TupleType":return l({$type:t("tuple"),$value:_.map((function(t,i){return e(t,p[i])}))},m);case"DictType":return"VoidType"===u[2][0]?l({$type:t("set"),$value:_.map((function(t){return e(t[0],u[1])}))},m):l({$type:t("dict"),$value:_.map((function(t){return[e(t[0],u[1]),e(t[1],u[2])]}))},m);case"StructType":{const s=d.map((function(t,s){const n=p[s],r=e(t,n[1]);if(o.omitStructNull&&null===r.$value)return null;const a=i(n[0],"String");return a.$key=!0,[a,r]})).filter(Boolean);return _=c(s),l({$type:t("struct"),$value:_},_!==s)}case"VariantType":{const i=function(e){const t=e[0];return e[1].map((function(e){return"StructType"===t?e[1]:e}))}(p);return function(e){return e.every((function(e){return"VoidType"===e[0]}))}(i)?{$type:t("enum"),$value:s(d[0],p).$value}:{$type:t("variant"),$value:[[s(d[0],p),e(d[1],i[d[0]])]]}}case"VoidType":case"NullType":return{$type:t("null"),$value:null};case"EmptyListType":return{$type:t("list"),$value:[]};case"EmptyDictType":return{$type:t("dict"),$value:[]};case"DataType":switch(p){case"String":case"Utf8":{const e=i(d,p);return f&&(e.$binary=!0),m?l(e,!0):h(e)}case"JsonDocument":return{$type:"yql.json",$value:d};case"Yson":{const e=i(d,p);return m?l(e,!0):e}default:return i(d,p)}case"PgType":{const e=u[2];return function(e,t,i){return{$type:"yql.pg."+t.toLowerCase(),$value:e,$category:i}}(d,p,e)}}}(...e)}e.exports=function(e,t,i){const s=function(e){const t=e||{},i=e&&e.validateSrcUrl?e.validateSrcUrl:()=>!1;return t.validateSrcUrl=i,t}(t);return o(e,s,i||{})}}()},34175:(e,t,i)=>{"use strict";i.d(t,{z0:()=>mt});var s=i(90766),n=i(5662),r=i(91508),o=i(31450),a=i(87119),c=i(60002),l=i(16223),h=i(46041),d=i(15092),u=i(83069),g=i(36677),p=i(75326),m=i(43264),f=i(87289),_=i(66261),v=i(47612);class C{constructor(e){this._editor=e,this._decorations=[],this._overviewRulerApproximateDecorations=[],this._findScopeDecorationIds=[],this._rangeHighlightDecorationId=null,this._highlightedDecorationId=null,this._startPosition=this._editor.getPosition()}dispose(){this._editor.removeDecorations(this._allDecorations()),this._decorations=[],this._overviewRulerApproximateDecorations=[],this._findScopeDecorationIds=[],this._rangeHighlightDecorationId=null,this._highlightedDecorationId=null}reset(){this._decorations=[],this._overviewRulerApproximateDecorations=[],this._findScopeDecorationIds=[],this._rangeHighlightDecorationId=null,this._highlightedDecorationId=null}getCount(){return this._decorations.length}getFindScope(){return this._findScopeDecorationIds[0]?this._editor.getModel().getDecorationRange(this._findScopeDecorationIds[0]):null}getFindScopes(){if(this._findScopeDecorationIds.length){const e=this._findScopeDecorationIds.map((e=>this._editor.getModel().getDecorationRange(e))).filter((e=>!!e));if(e.length)return e}return null}getStartPosition(){return this._startPosition}setStartPosition(e){this._startPosition=e,this.setCurrentFindMatch(null)}_getDecorationIndex(e){const t=this._decorations.indexOf(e);return t>=0?t+1:1}getDecorationRangeAt(e){const t=e{if(null!==this._highlightedDecorationId&&(e.changeDecorationOptions(this._highlightedDecorationId,C._FIND_MATCH_DECORATION),this._highlightedDecorationId=null),null!==t&&(this._highlightedDecorationId=t,e.changeDecorationOptions(this._highlightedDecorationId,C._CURRENT_FIND_MATCH_DECORATION)),null!==this._rangeHighlightDecorationId&&(e.removeDecoration(this._rangeHighlightDecorationId),this._rangeHighlightDecorationId=null),null!==t){let i=this._editor.getModel().getDecorationRange(t);if(i.startLineNumber!==i.endLineNumber&&1===i.endColumn){const e=i.endLineNumber-1,t=this._editor.getModel().getLineMaxColumn(e);i=new g.Q(i.startLineNumber,i.startColumn,e,t)}this._rangeHighlightDecorationId=e.addDecoration(i,C._RANGE_HIGHLIGHT_DECORATION)}})),i}set(e,t){this._editor.changeDecorations((i=>{let s=C._FIND_MATCH_DECORATION;const n=[];if(e.length>1e3){s=C._FIND_MATCH_NO_OVERVIEW_DECORATION;const t=this._editor.getModel().getLineCount(),i=this._editor.getLayoutInfo().height/t,r=Math.max(2,Math.ceil(3/i));let o=e[0].range.startLineNumber,a=e[0].range.endLineNumber;for(let s=1,c=e.length;s=t.startLineNumber?t.endLineNumber>a&&(a=t.endLineNumber):(n.push({range:new g.Q(o,1,a,1),options:C._FIND_MATCH_ONLY_OVERVIEW_DECORATION}),o=t.startLineNumber,a=t.endLineNumber)}n.push({range:new g.Q(o,1,a,1),options:C._FIND_MATCH_ONLY_OVERVIEW_DECORATION})}const r=new Array(e.length);for(let t=0,o=e.length;ti.removeDecoration(e))),this._findScopeDecorationIds=[]),t?.length&&(this._findScopeDecorationIds=t.map((e=>i.addDecoration(e,C._FIND_SCOPE_DECORATION))))}))}matchBeforePosition(e){if(0===this._decorations.length)return null;for(let t=this._decorations.length-1;t>=0;t--){const i=this._decorations[t],s=this._editor.getModel().getDecorationRange(i);if(s&&!(s.endLineNumber>e.lineNumber)){if(s.endLineNumbere.column))return s}}return this._editor.getModel().getDecorationRange(this._decorations[this._decorations.length-1])}matchAfterPosition(e){if(0===this._decorations.length)return null;for(let t=0,i=this._decorations.length;te.lineNumber)return s;if(!(s.startColumn0){const e=[];for(let t=0;tg.Q.compareRangesUsingStarts(e.range,t.range)));const i=[];let s=e[0];for(let t=1;t0?t[0].toUpperCase()+t.substr(1):e[0][0].toUpperCase()!==e[0][0]&&t.length>0?t[0].toLowerCase()+t.substr(1):t}return t}function S(e,t,i){return-1!==e[0].indexOf(i)&&-1!==t.indexOf(i)&&e[0].split(i).length===t.split(i).length}function y(e,t,i){const s=t.split(i),n=e[0].split(i);let r="";return s.forEach(((e,t)=>{r+=b([n[t]],e)+i})),r.slice(0,-1)}class w{constructor(e){this.staticValue=e,this.kind=0}}class R{constructor(e){this.pieces=e,this.kind=1}}class L{static fromStaticValue(e){return new L([T.staticValue(e)])}get hasReplacementPatterns(){return 1===this._state.kind}constructor(e){e&&0!==e.length?1===e.length&&null!==e[0].staticValue?this._state=new w(e[0].staticValue):this._state=new R(e):this._state=new w("")}buildReplaceString(e,t){if(0===this._state.kind)return t?b(e,this._state.staticValue):this._state.staticValue;let i="";for(let s=0,n=this._state.pieces.length;s0){const e=[],i=t.caseOps.length;let s=0;for(let r=0,o=n.length;r=i){e.push(n.slice(r));break}switch(t.caseOps[s]){case"U":e.push(n[r].toUpperCase());break;case"u":e.push(n[r].toUpperCase()),s++;break;case"L":e.push(n[r].toLowerCase());break;case"l":e.push(n[r].toLowerCase()),s++;break;default:e.push(n[r])}}n=e.join("")}i+=n}return i}static _substitute(e,t){if(null===t)return"";if(0===e)return t[0];let i="";for(;e>0;){if(e{if(this._editor.hasModel())return this.research(!1)}),100),this._toDispose.add(this._updateDecorationsScheduler),this._toDispose.add(this._editor.onDidChangeCursorPosition((e=>{3!==e.reason&&5!==e.reason&&6!==e.reason||this._decorations.setStartPosition(this._editor.getPosition())}))),this._ignoreModelContentChanged=!1,this._toDispose.add(this._editor.onDidChangeModelContent((e=>{this._ignoreModelContentChanged||(e.isFlush&&this._decorations.reset(),this._decorations.setStartPosition(this._editor.getPosition()),this._updateDecorationsScheduler.schedule())}))),this._toDispose.add(this._state.onFindReplaceStateChange((e=>this._onStateChanged(e)))),this.research(!1,this._state.searchScope)}dispose(){this._isDisposed=!0,(0,n.AS)(this._startSearchingTimer),this._toDispose.dispose()}_onStateChanged(e){if(!this._isDisposed&&this._editor.hasModel()&&(e.searchString||e.isReplaceRevealed||e.isRegex||e.wholeWord||e.matchCase||e.searchScope)){this._editor.getModel().isTooLargeForSyncing()?(this._startSearchingTimer.cancel(),this._startSearchingTimer.setIfNotSet((()=>{e.searchScope?this.research(e.moveCursor,this._state.searchScope):this.research(e.moveCursor)}),240)):e.searchScope?this.research(e.moveCursor,this._state.searchScope):this.research(e.moveCursor)}}static _getSearchRange(e,t){return t||e.getFullModelRange()}research(e,t){let i=null;"undefined"!==typeof t?null!==t&&(i=Array.isArray(t)?t:[t]):i=this._decorations.getFindScopes(),null!==i&&(i=i.map((e=>{if(e.startLineNumber!==e.endLineNumber){let t=e.endLineNumber;return 1===e.endColumn&&(t-=1),new g.Q(e.startLineNumber,1,t,this._editor.getModel().getLineMaxColumn(t))}return e})));const s=this._findMatches(i,!1,ie);this._decorations.set(s,i);const n=this._editor.getSelection();let r=this._decorations.getCurrentMatchesPosition(n);if(0===r&&s.length>0){const e=(0,h.hw)(s.map((e=>e.range)),(e=>g.Q.compareRangesUsingStarts(e,n)>=0));r=e>0?e-1+1:r}this._state.changeMatchInfo(r,this._decorations.getCount(),void 0),e&&this._editor.getOption(41).cursorMoveOnType&&this._moveToNextMatch(this._decorations.getStartPosition())}_hasMatches(){return this._state.matchesCount>0}_cannotFind(){if(!this._hasMatches()){const e=this._decorations.getFindScope();return e&&this._editor.revealRangeInCenterIfOutsideViewport(e,0),!0}return!1}_setCurrentFindMatch(e){const t=this._decorations.setCurrentFindMatch(e);this._state.changeMatchInfo(t,this._decorations.getCount(),e),this._editor.setSelection(e),this._editor.revealRangeInCenterIfOutsideViewport(e,0)}_prevSearchPosition(e){const t=this._state.isRegex&&(this._state.searchString.indexOf("^")>=0||this._state.searchString.indexOf("$")>=0);let{lineNumber:i,column:s}=e;const n=this._editor.getModel();return t||1===s?(1===i?i=n.getLineCount():i--,s=n.getLineMaxColumn(i)):s--,new u.y(i,s)}_moveToPrevMatch(e,t=!1){if(!this._state.canNavigateBack()){const t=this._decorations.matchAfterPosition(e);return void(t&&this._setCurrentFindMatch(t))}if(this._decorations.getCount()=0||this._state.searchString.indexOf("$")>=0);let{lineNumber:i,column:s}=e;const n=this._editor.getModel();return t||s===n.getLineMaxColumn(i)?(i===n.getLineCount()?i=1:i++,s=1):s++,new u.y(i,s)}_moveToNextMatch(e){if(!this._state.canNavigateForward()){const t=this._decorations.matchBeforePosition(e);return void(t&&this._setCurrentFindMatch(t))}if(this._decorations.getCount()=n)break;const r=e.charCodeAt(s);if(36===r){i.emitUnchanged(s-1),i.emitStatic("$",s+1);continue}if(48===r||38===r){i.emitUnchanged(s-1),i.emitMatchIndex(0,s+1,t),t.length=0;continue}if(49<=r&&r<=57){let o=r-48;if(s+1=n)break;const r=e.charCodeAt(s);switch(r){case 92:i.emitUnchanged(s-1),i.emitStatic("\\",s+1);break;case 110:i.emitUnchanged(s-1),i.emitStatic("\n",s+1);break;case 116:i.emitUnchanged(s-1),i.emitStatic("\t",s+1);break;case 117:case 85:case 108:case 76:i.emitUnchanged(s-1),i.emitStatic("",s+1),t.push(String.fromCharCode(r))}}}return i.finalize()}(this._state.replaceString):L.fromStaticValue(this._state.replaceString)}replace(){if(!this._hasMatches())return;const e=this._getReplacePattern(),t=this._editor.getSelection(),i=this._getNextMatch(t.getStartPosition(),!0,!1);if(i)if(t.equalsRange(i.range)){const s=e.buildReplaceString(i.matches,this._state.preserveCase),n=new d.iu(t,s);this._executeEditorCommand("replace",n),this._decorations.setStartPosition(new u.y(t.startLineNumber,t.startColumn+s.length)),this.research(!0)}else this._decorations.setStartPosition(this._editor.getPosition()),this._setCurrentFindMatch(i.range)}_findMatches(e,t,i){const s=(e||[null]).map((e=>se._getSearchRange(this._editor.getModel(),e)));return this._editor.getModel().findMatches(this._state.searchString,s,this._state.isRegex,this._state.matchCase,this._state.wholeWord?this._editor.getOption(132):null,t,i)}replaceAll(){if(!this._hasMatches())return;const e=this._decorations.getFindScopes();null===e&&this._state.matchesCount>=ie?this._largeReplaceAll():this._regularReplaceAll(e),this.research(!1)}_largeReplaceAll(){const e=new m.lt(this._state.searchString,this._state.isRegex,this._state.matchCase,this._state.wholeWord?this._editor.getOption(132):null).parseSearchRequest();if(!e)return;let t=e.regex;if(!t.multiline){let e="mu";t.ignoreCase&&(e+="i"),t.global&&(e+="g"),t=new RegExp(t.source,e)}const i=this._editor.getModel(),s=i.getValue(1),n=i.getFullModelRange(),r=this._getReplacePattern();let o;const a=this._state.preserveCase;o=r.hasReplacementPatterns||a?s.replace(t,(function(){return r.buildReplaceString(arguments,a)})):s.replace(t,r.buildReplaceString(null,a));const c=new d.ui(n,o,this._editor.getSelection());this._executeEditorCommand("replaceAll",c)}_regularReplaceAll(e){const t=this._getReplacePattern(),i=this._findMatches(e,t.hasReplacementPatterns||this._state.preserveCase,1073741824),s=[];for(let r=0,o=i.length;re.range)),s);this._executeEditorCommand("replaceAll",n)}selectAllMatches(){if(!this._hasMatches())return;const e=this._decorations.getFindScopes();let t=this._findMatches(e,!1,1073741824).map((e=>new p.L(e.range.startLineNumber,e.range.startColumn,e.range.endLineNumber,e.range.endColumn)));const i=this._editor.getSelection();for(let s=0,n=t.length;sthis._hide()),2e3)),this._isVisible=!1,this._editor=e,this._state=t,this._keybindingService=i,this._domNode=document.createElement("div"),this._domNode.className="findOptionsWidget",this._domNode.style.display="none",this._domNode.style.top="10px",this._domNode.style.zIndex="12",this._domNode.setAttribute("role","presentation"),this._domNode.setAttribute("aria-hidden","true");const n={inputActiveOptionBorder:(0,_.GuP)(_.uNK),inputActiveOptionForeground:(0,_.GuP)(_.$$0),inputActiveOptionBackground:(0,_.GuP)(_.c1f)},r=this._register((0,ae.bW)());this.caseSensitive=this._register(new re.bc({appendTitle:this._keybindingLabelFor(q),isChecked:this._state.matchCase,hoverDelegate:r,...n})),this._domNode.appendChild(this.caseSensitive.domNode),this._register(this.caseSensitive.onChange((()=>{this._state.change({matchCase:this.caseSensitive.checked},!1)}))),this.wholeWords=this._register(new re.nV({appendTitle:this._keybindingLabelFor($),isChecked:this._state.wholeWord,hoverDelegate:r,...n})),this._domNode.appendChild(this.wholeWords.domNode),this._register(this.wholeWords.onChange((()=>{this._state.change({wholeWord:this.wholeWords.checked},!1)}))),this.regex=this._register(new re.Ix({appendTitle:this._keybindingLabelFor(Q),isChecked:this._state.isRegex,hoverDelegate:r,...n})),this._domNode.appendChild(this.regex.domNode),this._register(this.regex.onChange((()=>{this._state.change({isRegex:this.regex.checked},!1)}))),this._editor.addOverlayWidget(this),this._register(this._state.onFindReplaceStateChange((e=>{let t=!1;e.isRegex&&(this.regex.checked=this._state.isRegex,t=!0),e.wholeWord&&(this.wholeWords.checked=this._state.wholeWord,t=!0),e.matchCase&&(this.caseSensitive.checked=this._state.matchCase,t=!0),!this._state.isRevealed&&t&&this._revealTemporarily()}))),this._register(ne.ko(this._domNode,ne.Bx.MOUSE_LEAVE,(e=>this._onMouseLeave()))),this._register(ne.ko(this._domNode,"mouseover",(e=>this._onMouseOver())))}_keybindingLabelFor(e){const t=this._keybindingService.lookupKeybinding(e);return t?` (${t.getLabel()})`:""}dispose(){this._editor.removeOverlayWidget(this),super.dispose()}getId(){return ce.ID}getDomNode(){return this._domNode}getPosition(){return{preference:0}}highlightFindOptions(){this._revealTemporarily()}_revealTemporarily(){this._show(),this._hideSoon.schedule()}_onMouseLeave(){this._hideSoon.schedule()}_onMouseOver(){this._hideSoon.cancel()}_show(){this._isVisible||(this._isVisible=!0,this._domNode.style.display="block")}_hide(){this._isVisible&&(this._isVisible=!1,this._domNode.style.display="none")}}var le=i(41234);function he(e,t){return 1===e||2!==e&&t}class de extends n.jG{get searchString(){return this._searchString}get replaceString(){return this._replaceString}get isRevealed(){return this._isRevealed}get isReplaceRevealed(){return this._isReplaceRevealed}get isRegex(){return he(this._isRegexOverride,this._isRegex)}get wholeWord(){return he(this._wholeWordOverride,this._wholeWord)}get matchCase(){return he(this._matchCaseOverride,this._matchCase)}get preserveCase(){return he(this._preserveCaseOverride,this._preserveCase)}get actualIsRegex(){return this._isRegex}get actualWholeWord(){return this._wholeWord}get actualMatchCase(){return this._matchCase}get actualPreserveCase(){return this._preserveCase}get searchScope(){return this._searchScope}get matchesPosition(){return this._matchesPosition}get matchesCount(){return this._matchesCount}get currentMatch(){return this._currentMatch}constructor(){super(),this._onFindReplaceStateChange=this._register(new le.vl),this.onFindReplaceStateChange=this._onFindReplaceStateChange.event,this._searchString="",this._replaceString="",this._isRevealed=!1,this._isReplaceRevealed=!1,this._isRegex=!1,this._isRegexOverride=0,this._wholeWord=!1,this._wholeWordOverride=0,this._matchCase=!1,this._matchCaseOverride=0,this._preserveCase=!1,this._preserveCaseOverride=0,this._searchScope=null,this._matchesPosition=0,this._matchesCount=0,this._currentMatch=null,this._loop=!0,this._isSearching=!1,this._filters=null}changeMatchInfo(e,t,i){const s={moveCursor:!1,updateHistory:!1,searchString:!1,replaceString:!1,isRevealed:!1,isReplaceRevealed:!1,isRegex:!1,wholeWord:!1,matchCase:!1,preserveCase:!1,searchScope:!1,matchesPosition:!1,matchesCount:!1,currentMatch:!1,loop:!1,isSearching:!1,filters:!1};let n=!1;0===t&&(e=0),e>t&&(e=t),this._matchesPosition!==e&&(this._matchesPosition=e,s.matchesPosition=!0,n=!0),this._matchesCount!==t&&(this._matchesCount=t,s.matchesCount=!0,n=!0),"undefined"!==typeof i&&(g.Q.equalsRange(this._currentMatch,i)||(this._currentMatch=i,s.currentMatch=!0,n=!0)),n&&this._onFindReplaceStateChange.fire(s)}change(e,t,i=!0){const s={moveCursor:t,updateHistory:i,searchString:!1,replaceString:!1,isRevealed:!1,isReplaceRevealed:!1,isRegex:!1,wholeWord:!1,matchCase:!1,preserveCase:!1,searchScope:!1,matchesPosition:!1,matchesCount:!1,currentMatch:!1,loop:!1,isSearching:!1,filters:!1};let n=!1;const r=this.isRegex,o=this.wholeWord,a=this.matchCase,c=this.preserveCase;"undefined"!==typeof e.searchString&&this._searchString!==e.searchString&&(this._searchString=e.searchString,s.searchString=!0,n=!0),"undefined"!==typeof e.replaceString&&this._replaceString!==e.replaceString&&(this._replaceString=e.replaceString,s.replaceString=!0,n=!0),"undefined"!==typeof e.isRevealed&&this._isRevealed!==e.isRevealed&&(this._isRevealed=e.isRevealed,s.isRevealed=!0,n=!0),"undefined"!==typeof e.isReplaceRevealed&&this._isReplaceRevealed!==e.isReplaceRevealed&&(this._isReplaceRevealed=e.isReplaceRevealed,s.isReplaceRevealed=!0,n=!0),"undefined"!==typeof e.isRegex&&(this._isRegex=e.isRegex),"undefined"!==typeof e.wholeWord&&(this._wholeWord=e.wholeWord),"undefined"!==typeof e.matchCase&&(this._matchCase=e.matchCase),"undefined"!==typeof e.preserveCase&&(this._preserveCase=e.preserveCase),"undefined"!==typeof e.searchScope&&(e.searchScope?.every((e=>this._searchScope?.some((t=>!g.Q.equalsRange(t,e)))))||(this._searchScope=e.searchScope,s.searchScope=!0,n=!0)),"undefined"!==typeof e.loop&&this._loop!==e.loop&&(this._loop=e.loop,s.loop=!0,n=!0),"undefined"!==typeof e.isSearching&&this._isSearching!==e.isSearching&&(this._isSearching=e.isSearching,s.isSearching=!0,n=!0),"undefined"!==typeof e.filters&&(this._filters?this._filters.update(e.filters):this._filters=e.filters,s.filters=!0,n=!0),this._isRegexOverride="undefined"!==typeof e.isRegexOverride?e.isRegexOverride:0,this._wholeWordOverride="undefined"!==typeof e.wholeWordOverride?e.wholeWordOverride:0,this._matchCaseOverride="undefined"!==typeof e.matchCaseOverride?e.matchCaseOverride:0,this._preserveCaseOverride="undefined"!==typeof e.preserveCaseOverride?e.preserveCaseOverride:0,r!==this.isRegex&&(n=!0,s.isRegex=!0),o!==this.wholeWord&&(n=!0,s.wholeWord=!0),a!==this.matchCase&&(n=!0,s.matchCase=!0),c!==this.preserveCase&&(n=!0,s.preserveCase=!0),n&&this._onFindReplaceStateChange.fire(s)}canNavigateBack(){return this.canNavigateInLoop()||1!==this.matchesPosition}canNavigateForward(){return this.canNavigateInLoop()||this.matchesPosition=ie}}var ue=i(11007),ge=i(35315),pe=i(92403),me=i(10350),fe=i(64383),_e=i(98067),ve=i(78209),Ce=i(89100);function Ee(e){return"Up"===e.lookupKeybinding("history.showPrevious")?.getElectronAccelerator()&&"Down"===e.lookupKeybinding("history.showNext")?.getElectronAccelerator()}var be=i(61394),Se=i(25689),ye=i(86723),we=i(631),Re=i(19070);const Le=(0,be.pU)("find-collapsed",me.W.chevronRight,ve.kg("findCollapsedIcon","Icon to indicate that the editor find widget is collapsed.")),Te=(0,be.pU)("find-expanded",me.W.chevronDown,ve.kg("findExpandedIcon","Icon to indicate that the editor find widget is expanded.")),xe=(0,be.pU)("find-selection",me.W.selection,ve.kg("findSelectionIcon","Icon for 'Find in Selection' in the editor find widget.")),ke=(0,be.pU)("find-replace",me.W.replace,ve.kg("findReplaceIcon","Icon for 'Replace' in the editor find widget.")),Ae=(0,be.pU)("find-replace-all",me.W.replaceAll,ve.kg("findReplaceAllIcon","Icon for 'Replace All' in the editor find widget.")),Ne=(0,be.pU)("find-previous-match",me.W.arrowUp,ve.kg("findPreviousMatchIcon","Icon for 'Find Previous' in the editor find widget.")),Ie=(0,be.pU)("find-next-match",me.W.arrowDown,ve.kg("findNextMatchIcon","Icon for 'Find Next' in the editor find widget.")),Oe=ve.kg("label.findDialog","Find / Replace"),De=ve.kg("label.find","Find"),Me=ve.kg("placeholder.find","Find"),Pe=ve.kg("label.previousMatchButton","Previous Match"),Fe=ve.kg("label.nextMatchButton","Next Match"),Ue=ve.kg("label.toggleSelectionFind","Find in Selection"),He=ve.kg("label.closeButton","Close"),Be=ve.kg("label.replace","Replace"),We=ve.kg("placeholder.replace","Replace"),Ve=ve.kg("label.replaceButton","Replace"),ze=ve.kg("label.replaceAllButton","Replace All"),Ge=ve.kg("label.toggleReplaceButton","Toggle Replace"),je=ve.kg("title.matchesCountLimit","Only the first {0} results are highlighted, but all find operations work on the entire text.",ie),Ke=ve.kg("label.matchesLocation","{0} of {1}"),Ye=ve.kg("label.noResults","No results"),qe=419;let $e=69;const Qe="ctrlEnterReplaceAll.windows.donotask",Xe=_e.zx?256:2048;class Ze{constructor(e){this.afterLineNumber=e,this.heightInPx=33,this.suppressMouseDown=!1,this.domNode=document.createElement("div"),this.domNode.className="dock-find-viewzone"}}function Je(e,t,i){const s=!!t.match(/\n/);i&&s&&i.selectionStart>0&&e.stopPropagation()}function et(e,t,i){const s=!!t.match(/\n/);i&&s&&i.selectionEndthis._updateHistoryDelayer.cancel()))),this._register(this._state.onFindReplaceStateChange((e=>this._onStateChanged(e)))),this._buildDomNode(),this._updateButtons(),this._tryUpdateWidgetWidth(),this._findInput.inputBox.layout(),this._register(this._codeEditor.onDidChangeConfiguration((e=>{if(e.hasChanged(92)&&(this._codeEditor.getOption(92)&&this._state.change({isReplaceRevealed:!1},!1),this._updateButtons()),e.hasChanged(146)&&this._tryUpdateWidgetWidth(),e.hasChanged(2)&&this.updateAccessibilitySupport(),e.hasChanged(41)){const e=this._codeEditor.getOption(41).loop;this._state.change({loop:e},!1);const t=this._codeEditor.getOption(41).addExtraSpaceOnTop;t&&!this._viewZone&&(this._viewZone=new Ze(0),this._showViewZone()),!t&&this._viewZone&&this._removeViewZone()}}))),this.updateAccessibilitySupport(),this._register(this._codeEditor.onDidChangeCursorSelection((()=>{this._isVisible&&this._updateToggleSelectionFindButton()}))),this._register(this._codeEditor.onDidFocusEditorWidget((async()=>{if(this._isVisible){const e=await this._controller.getGlobalBufferTerm();e&&e!==this._state.searchString&&(this._state.change({searchString:e},!1),this._findInput.select())}}))),this._findInputFocused=N.bindTo(a),this._findFocusTracker=this._register(ne.w5(this._findInput.inputBox.inputElement)),this._register(this._findFocusTracker.onDidFocus((()=>{this._findInputFocused.set(!0),this._updateSearchScope()}))),this._register(this._findFocusTracker.onDidBlur((()=>{this._findInputFocused.set(!1)}))),this._replaceInputFocused=I.bindTo(a),this._replaceFocusTracker=this._register(ne.w5(this._replaceInput.inputBox.inputElement)),this._register(this._replaceFocusTracker.onDidFocus((()=>{this._replaceInputFocused.set(!0),this._updateSearchScope()}))),this._register(this._replaceFocusTracker.onDidBlur((()=>{this._replaceInputFocused.set(!1)}))),this._codeEditor.addOverlayWidget(this),this._codeEditor.getOption(41).addExtraSpaceOnTop&&(this._viewZone=new Ze(0)),this._register(this._codeEditor.onDidChangeModel((()=>{this._isVisible&&(this._viewZoneId=void 0)}))),this._register(this._codeEditor.onDidScrollChange((e=>{e.scrollTopChanged?this._layoutViewZone():setTimeout((()=>{this._layoutViewZone()}),0)})))}getId(){return tt.ID}getDomNode(){return this._domNode}getPosition(){return this._isVisible?{preference:0}:null}_onStateChanged(e){if(e.searchString){try{this._ignoreChangeEvent=!0,this._findInput.setValue(this._state.searchString)}finally{this._ignoreChangeEvent=!1}this._updateButtons()}if(e.replaceString&&(this._replaceInput.inputBox.value=this._state.replaceString),e.isRevealed&&(this._state.isRevealed?this._reveal():this._hide(!0)),e.isReplaceRevealed&&(this._state.isReplaceRevealed?this._codeEditor.getOption(92)||this._isReplaceVisible||(this._isReplaceVisible=!0,this._replaceInput.width=ne.Tr(this._findInput.domNode),this._updateButtons(),this._replaceInput.inputBox.layout()):this._isReplaceVisible&&(this._isReplaceVisible=!1,this._updateButtons())),(e.isRevealed||e.isReplaceRevealed)&&(this._state.isRevealed||this._state.isReplaceRevealed)&&this._tryUpdateHeight()&&this._showViewZone(),e.isRegex&&this._findInput.setRegex(this._state.isRegex),e.wholeWord&&this._findInput.setWholeWords(this._state.wholeWord),e.matchCase&&this._findInput.setCaseSensitive(this._state.matchCase),e.preserveCase&&this._replaceInput.setPreserveCase(this._state.preserveCase),e.searchScope&&(this._state.searchScope?this._toggleSelectionFind.checked=!0:this._toggleSelectionFind.checked=!1,this._updateToggleSelectionFindButton()),e.searchString||e.matchesCount||e.matchesPosition){const e=this._state.searchString.length>0&&0===this._state.matchesCount;this._domNode.classList.toggle("no-results",e),this._updateMatchesCount(),this._updateButtons()}(e.searchString||e.currentMatch)&&this._layoutViewZone(),e.updateHistory&&this._delayedUpdateHistory(),e.loop&&this._updateButtons()}_delayedUpdateHistory(){this._updateHistoryDelayer.trigger(this._updateHistory.bind(this)).then(void 0,fe.dz)}_updateHistory(){this._state.searchString&&this._findInput.inputBox.addToHistory(),this._state.replaceString&&this._replaceInput.inputBox.addToHistory()}_updateMatchesCount(){let e;if(this._matchesCount.style.minWidth=$e+"px",this._state.matchesCount>=ie?this._matchesCount.title=je:this._matchesCount.title="",this._matchesCount.firstChild?.remove(),this._state.matchesCount>0){let t=String(this._state.matchesCount);this._state.matchesCount>=ie&&(t+="+");let i=String(this._state.matchesPosition);"0"===i&&(i="?"),e=r.GP(Ke,i,t)}else e=Ye;this._matchesCount.appendChild(document.createTextNode(e)),(0,ue.xE)(this._getAriaLabel(e,this._state.currentMatch,this._state.searchString)),$e=Math.max($e,this._matchesCount.clientWidth)}_getAriaLabel(e,t,i){if(e===Ye)return""===i?ve.kg("ariaSearchNoResultEmpty","{0} found",e):ve.kg("ariaSearchNoResult","{0} found for '{1}'",e,i);if(t){const s=ve.kg("ariaSearchNoResultWithLineNum","{0} found for '{1}', at {2}",e,i,t.startLineNumber+":"+t.startColumn),n=this._codeEditor.getModel();if(n&&t.startLineNumber<=n.getLineCount()&&t.startLineNumber>=1){return`${n.getLineContent(t.startLineNumber)}, ${s}`}return s}return ve.kg("ariaSearchNoResultWithLineNumNoCurrentMatch","{0} found for '{1}'",e,i)}_updateToggleSelectionFindButton(){const e=this._codeEditor.getSelection(),t=!!e&&(e.startLineNumber!==e.endLineNumber||e.startColumn!==e.endColumn),i=this._toggleSelectionFind.checked;this._isVisible&&(i||t)?this._toggleSelectionFind.enable():this._toggleSelectionFind.disable()}_updateButtons(){this._findInput.setEnabled(this._isVisible),this._replaceInput.setEnabled(this._isVisible&&this._isReplaceVisible),this._updateToggleSelectionFindButton(),this._closeBtn.setEnabled(this._isVisible);const e=this._state.searchString.length>0,t=!!this._state.matchesCount;this._prevBtn.setEnabled(this._isVisible&&e&&t&&this._state.canNavigateBack()),this._nextBtn.setEnabled(this._isVisible&&e&&t&&this._state.canNavigateForward()),this._replaceBtn.setEnabled(this._isVisible&&this._isReplaceVisible&&e),this._replaceAllBtn.setEnabled(this._isVisible&&this._isReplaceVisible&&e),this._domNode.classList.toggle("replaceToggled",this._isReplaceVisible),this._toggleReplaceBtn.setExpanded(this._isReplaceVisible);const i=!this._codeEditor.getOption(92);this._toggleReplaceBtn.setEnabled(this._isVisible&&i)}_reveal(){if(this._revealTimeouts.forEach((e=>{clearTimeout(e)})),this._revealTimeouts=[],!this._isVisible){this._isVisible=!0;const e=this._codeEditor.getSelection();switch(this._codeEditor.getOption(41).autoFindInSelection){case"always":this._toggleSelectionFind.checked=!0;break;case"never":this._toggleSelectionFind.checked=!1;break;case"multiline":{const t=!!e&&e.startLineNumber!==e.endLineNumber;this._toggleSelectionFind.checked=t;break}}this._tryUpdateWidgetWidth(),this._updateButtons(),this._revealTimeouts.push(setTimeout((()=>{this._domNode.classList.add("visible"),this._domNode.setAttribute("aria-hidden","false")}),0)),this._revealTimeouts.push(setTimeout((()=>{this._findInput.validate()}),200)),this._codeEditor.layoutOverlayWidget(this);let t=!0;if(this._codeEditor.getOption(41).seedSearchStringFromSelection&&e){const i=this._codeEditor.getDomNode();if(i){const s=ne.BK(i),n=this._codeEditor.getScrolledVisiblePosition(e.getStartPosition()),r=s.left+(n?n.left:0),o=n?n.top:0;if(this._viewZone&&oe.startLineNumber&&(t=!1);const i=ne.cL(this._domNode).left;r>i&&(t=!1);const n=this._codeEditor.getScrolledVisiblePosition(e.getEndPosition());s.left+(n?n.left:0)>i&&(t=!1)}}}this._showViewZone(t)}}_hide(e){this._revealTimeouts.forEach((e=>{clearTimeout(e)})),this._revealTimeouts=[],this._isVisible&&(this._isVisible=!1,this._updateButtons(),this._domNode.classList.remove("visible"),this._domNode.setAttribute("aria-hidden","true"),this._findInput.clearMessage(),e&&this._codeEditor.focus(),this._codeEditor.layoutOverlayWidget(this),this._removeViewZone())}_layoutViewZone(e){if(!this._codeEditor.getOption(41).addExtraSpaceOnTop)return void this._removeViewZone();if(!this._isVisible)return;const t=this._viewZone;void 0===this._viewZoneId&&t&&this._codeEditor.changeViewZones((i=>{t.heightInPx=this._getHeight(),this._viewZoneId=i.addZone(t),this._codeEditor.setScrollTop(e||this._codeEditor.getScrollTop()+t.heightInPx)}))}_showViewZone(e=!0){if(!this._isVisible)return;if(!this._codeEditor.getOption(41).addExtraSpaceOnTop)return;void 0===this._viewZone&&(this._viewZone=new Ze(0));const t=this._viewZone;this._codeEditor.changeViewZones((i=>{if(void 0!==this._viewZoneId){const s=this._getHeight();if(s===t.heightInPx)return;const n=s-t.heightInPx;return t.heightInPx=s,i.layoutZone(this._viewZoneId),void(e&&this._codeEditor.setScrollTop(this._codeEditor.getScrollTop()+n))}{let s=this._getHeight();if(s-=this._codeEditor.getOption(84).top,s<=0)return;t.heightInPx=s,this._viewZoneId=i.addZone(t),e&&this._codeEditor.setScrollTop(this._codeEditor.getScrollTop()+s)}}))}_removeViewZone(){this._codeEditor.changeViewZones((e=>{void 0!==this._viewZoneId&&(e.removeZone(this._viewZoneId),this._viewZoneId=void 0,this._viewZone&&(this._codeEditor.setScrollTop(this._codeEditor.getScrollTop()-this._viewZone.heightInPx),this._viewZone=void 0))}))}_tryUpdateWidgetWidth(){if(!this._isVisible)return;if(!this._domNode.isConnected)return;const e=this._codeEditor.getLayoutInfo();if(e.contentWidth<=0)return void this._domNode.classList.add("hiddenEditor");this._domNode.classList.contains("hiddenEditor")&&this._domNode.classList.remove("hiddenEditor");const t=e.width,i=e.minimap.minimapWidth;let s=!1,n=!1,r=!1;if(this._resized){if(ne.Tr(this._domNode)>qe)return this._domNode.style.maxWidth=t-28-i-15+"px",void(this._replaceInput.width=ne.Tr(this._findInput.domNode))}if(447+i>=t&&(n=!0),447+i-$e>=t&&(r=!0),447+i-$e>=t+50&&(s=!0),this._domNode.classList.toggle("collapsed-find-widget",s),this._domNode.classList.toggle("narrow-find-widget",r),this._domNode.classList.toggle("reduced-find-widget",n),r||s||(this._domNode.style.maxWidth=t-28-i-15+"px"),this._findInput.layout({collapsedFindWidget:s,narrowFindWidget:r,reducedFindWidget:n}),this._resized){const e=this._findInput.inputBox.element.clientWidth;e>0&&(this._replaceInput.width=e)}else this._isReplaceVisible&&(this._replaceInput.width=ne.Tr(this._findInput.domNode))}_getHeight(){let e=0;return e+=4,e+=this._findInput.inputBox.height+2,this._isReplaceVisible&&(e+=4,e+=this._replaceInput.inputBox.height+2),e+=4,e}_tryUpdateHeight(){const e=this._getHeight();return(null===this._cachedHeight||this._cachedHeight!==e)&&(this._cachedHeight=e,this._domNode.style.height=`${e}px`,!0)}focusFindInput(){this._findInput.select(),this._findInput.focus()}focusReplaceInput(){this._replaceInput.select(),this._replaceInput.focus()}highlightFindOptions(){this._findInput.highlightFindOptions()}_updateSearchScope(){if(this._codeEditor.hasModel()&&this._toggleSelectionFind.checked){const e=this._codeEditor.getSelections();e.map((e=>{1===e.endColumn&&e.endLineNumber>e.startLineNumber&&(e=e.setEndPosition(e.endLineNumber-1,this._codeEditor.getModel().getLineMaxColumn(e.endLineNumber-1)));const t=this._state.currentMatch;return e.startLineNumber===e.endLineNumber||g.Q.equalsRange(e,t)?null:e})).filter((e=>!!e)),e.length&&this._state.change({searchScope:e},!0)}}_onFindInputMouseDown(e){e.middleButton&&e.stopPropagation()}_onFindInputKeyDown(e){return e.equals(3|Xe)?(this._keybindingService.dispatchEvent(e,e.target)||this._findInput.inputBox.insertAtCursor("\n"),void e.preventDefault()):e.equals(2)?(this._isReplaceVisible?this._replaceInput.focus():this._findInput.focusOnCaseSensitive(),void e.preventDefault()):e.equals(2066)?(this._codeEditor.focus(),void e.preventDefault()):e.equals(16)?Je(e,this._findInput.getValue(),this._findInput.domNode.querySelector("textarea")):e.equals(18)?et(e,this._findInput.getValue(),this._findInput.domNode.querySelector("textarea")):void 0}_onReplaceInputKeyDown(e){return e.equals(3|Xe)?(this._keybindingService.dispatchEvent(e,e.target)||(_e.uF&&_e.ib&&!this._ctrlEnterReplaceAllWarningPrompted&&(this._notificationService.info(ve.kg("ctrlEnter.keybindingChanged","Ctrl+Enter now inserts line break instead of replacing all. You can modify the keybinding for editor.action.replaceAll to override this behavior.")),this._ctrlEnterReplaceAllWarningPrompted=!0,this._storageService.store(Qe,!0,0,0)),this._replaceInput.inputBox.insertAtCursor("\n")),void e.preventDefault()):e.equals(2)?(this._findInput.focusOnCaseSensitive(),void e.preventDefault()):e.equals(1026)?(this._findInput.focus(),void e.preventDefault()):e.equals(2066)?(this._codeEditor.focus(),void e.preventDefault()):e.equals(16)?Je(e,this._replaceInput.inputBox.value,this._replaceInput.inputBox.element.querySelector("textarea")):e.equals(18)?et(e,this._replaceInput.inputBox.value,this._replaceInput.inputBox.element.querySelector("textarea")):void 0}getVerticalSashLeft(e){return 0}_keybindingLabelFor(e){const t=this._keybindingService.lookupKeybinding(e);return t?` (${t.getLabel()})`:""}_buildDomNode(){const e=!0,t=!0;this._findInput=this._register(new Ce.pG(null,this._contextViewProvider,{width:221,label:De,placeholder:Me,appendCaseSensitiveLabel:this._keybindingLabelFor(q),appendWholeWordsLabel:this._keybindingLabelFor($),appendRegexLabel:this._keybindingLabelFor(Q),validation:e=>{if(0===e.length||!this._findInput.getRegex())return null;try{return new RegExp(e,"gu"),null}catch(t){return{content:t.message}}},flexibleHeight:e,flexibleWidth:t,flexibleMaxHeight:118,showCommonFindToggles:!0,showHistoryHint:()=>Ee(this._keybindingService),inputBoxStyles:Re.ho,toggleStyles:Re.mk},this._contextKeyService)),this._findInput.setRegex(!!this._state.isRegex),this._findInput.setCaseSensitive(!!this._state.matchCase),this._findInput.setWholeWords(!!this._state.wholeWord),this._register(this._findInput.onKeyDown((e=>this._onFindInputKeyDown(e)))),this._register(this._findInput.inputBox.onDidChange((()=>{this._ignoreChangeEvent||this._state.change({searchString:this._findInput.getValue()},!0)}))),this._register(this._findInput.onDidOptionChange((()=>{this._state.change({isRegex:this._findInput.getRegex(),wholeWord:this._findInput.getWholeWords(),matchCase:this._findInput.getCaseSensitive()},!0)}))),this._register(this._findInput.onCaseSensitiveKeyDown((e=>{e.equals(1026)&&this._isReplaceVisible&&(this._replaceInput.focus(),e.preventDefault())}))),this._register(this._findInput.onRegexKeyDown((e=>{e.equals(2)&&this._isReplaceVisible&&(this._replaceInput.focusOnPreserve(),e.preventDefault())}))),this._register(this._findInput.inputBox.onDidHeightChange((e=>{this._tryUpdateHeight()&&this._showViewZone()}))),_e.j9&&this._register(this._findInput.onMouseDown((e=>this._onFindInputMouseDown(e)))),this._matchesCount=document.createElement("div"),this._matchesCount.className="matchesCount",this._updateMatchesCount();const i=this._register((0,ae.bW)());this._prevBtn=this._register(new it({label:Pe+this._keybindingLabelFor(V),icon:Ne,hoverDelegate:i,onTrigger:()=>{(0,we.eU)(this._codeEditor.getAction(V)).run().then(void 0,fe.dz)}},this._hoverService)),this._nextBtn=this._register(new it({label:Fe+this._keybindingLabelFor(W),icon:Ie,hoverDelegate:i,onTrigger:()=>{(0,we.eU)(this._codeEditor.getAction(W)).run().then(void 0,fe.dz)}},this._hoverService));const s=document.createElement("div");s.className="find-part",s.appendChild(this._findInput.domNode);const n=document.createElement("div");n.className="find-actions",s.appendChild(n),n.appendChild(this._matchesCount),n.appendChild(this._prevBtn.domNode),n.appendChild(this._nextBtn.domNode),this._toggleSelectionFind=this._register(new ge.l({icon:xe,title:Ue+this._keybindingLabelFor(X),isChecked:!1,hoverDelegate:i,inputActiveOptionBackground:(0,_.GuP)(_.c1f),inputActiveOptionBorder:(0,_.GuP)(_.uNK),inputActiveOptionForeground:(0,_.GuP)(_.$$0)})),this._register(this._toggleSelectionFind.onChange((()=>{if(this._toggleSelectionFind.checked){if(this._codeEditor.hasModel()){let e=this._codeEditor.getSelections();e=e.map((e=>(1===e.endColumn&&e.endLineNumber>e.startLineNumber&&(e=e.setEndPosition(e.endLineNumber-1,this._codeEditor.getModel().getLineMaxColumn(e.endLineNumber-1))),e.isEmpty()?null:e))).filter((e=>!!e)),e.length&&this._state.change({searchScope:e},!0)}}else this._state.change({searchScope:null},!0)}))),n.appendChild(this._toggleSelectionFind.domNode),this._closeBtn=this._register(new it({label:He+this._keybindingLabelFor(Y),icon:be.$_,hoverDelegate:i,onTrigger:()=>{this._state.change({isRevealed:!1,searchScope:null},!1)},onKeyDown:e=>{e.equals(2)&&this._isReplaceVisible&&(this._replaceBtn.isEnabled()?this._replaceBtn.focus():this._codeEditor.focus(),e.preventDefault())}},this._hoverService)),this._replaceInput=this._register(new Ce._Q(null,void 0,{label:Be,placeholder:We,appendPreserveCaseLabel:this._keybindingLabelFor(Z),history:[],flexibleHeight:e,flexibleWidth:t,flexibleMaxHeight:118,showHistoryHint:()=>Ee(this._keybindingService),inputBoxStyles:Re.ho,toggleStyles:Re.mk},this._contextKeyService,!0)),this._replaceInput.setPreserveCase(!!this._state.preserveCase),this._register(this._replaceInput.onKeyDown((e=>this._onReplaceInputKeyDown(e)))),this._register(this._replaceInput.inputBox.onDidChange((()=>{this._state.change({replaceString:this._replaceInput.inputBox.value},!1)}))),this._register(this._replaceInput.inputBox.onDidHeightChange((e=>{this._isReplaceVisible&&this._tryUpdateHeight()&&this._showViewZone()}))),this._register(this._replaceInput.onDidOptionChange((()=>{this._state.change({preserveCase:this._replaceInput.getPreserveCase()},!0)}))),this._register(this._replaceInput.onPreserveCaseKeyDown((e=>{e.equals(2)&&(this._prevBtn.isEnabled()?this._prevBtn.focus():this._nextBtn.isEnabled()?this._nextBtn.focus():this._toggleSelectionFind.enabled?this._toggleSelectionFind.focus():this._closeBtn.isEnabled()&&this._closeBtn.focus(),e.preventDefault())})));const r=this._register((0,ae.bW)());this._replaceBtn=this._register(new it({label:Ve+this._keybindingLabelFor(J),icon:ke,hoverDelegate:r,onTrigger:()=>{this._controller.replace()},onKeyDown:e=>{e.equals(1026)&&(this._closeBtn.focus(),e.preventDefault())}},this._hoverService)),this._replaceAllBtn=this._register(new it({label:ze+this._keybindingLabelFor(ee),icon:Ae,hoverDelegate:r,onTrigger:()=>{this._controller.replaceAll()}},this._hoverService));const o=document.createElement("div");o.className="replace-part",o.appendChild(this._replaceInput.domNode);const a=document.createElement("div");a.className="replace-actions",o.appendChild(a),a.appendChild(this._replaceBtn.domNode),a.appendChild(this._replaceAllBtn.domNode),this._toggleReplaceBtn=this._register(new it({label:Ge,className:"codicon toggle left",onTrigger:()=>{this._state.change({isReplaceRevealed:!this._isReplaceVisible},!1),this._isReplaceVisible&&(this._replaceInput.width=ne.Tr(this._findInput.domNode),this._replaceInput.inputBox.layout()),this._showViewZone()}},this._hoverService)),this._toggleReplaceBtn.setExpanded(this._isReplaceVisible),this._domNode=document.createElement("div"),this._domNode.className="editor-widget find-widget",this._domNode.setAttribute("aria-hidden","true"),this._domNode.ariaLabel=Oe,this._domNode.role="dialog",this._domNode.style.width="419px",this._domNode.appendChild(this._toggleReplaceBtn.domNode),this._domNode.appendChild(s),this._domNode.appendChild(this._closeBtn.domNode),this._domNode.appendChild(o),this._resizeSash=this._register(new pe.m(this._domNode,this,{orientation:0,size:2})),this._resized=!1;let c=qe;this._register(this._resizeSash.onDidStart((()=>{c=ne.Tr(this._domNode)}))),this._register(this._resizeSash.onDidChange((e=>{this._resized=!0;const t=c+e.startX-e.currentX;if(t(parseFloat(ne.L9(this._domNode).maxWidth)||0)||(this._domNode.style.width=`${t}px`,this._isReplaceVisible&&(this._replaceInput.width=ne.Tr(this._findInput.domNode)),this._findInput.inputBox.layout(),this._tryUpdateHeight())}))),this._register(this._resizeSash.onDidReset((()=>{const e=ne.Tr(this._domNode);if(e{this._opts.onTrigger(),e.preventDefault()})),this.onkeydown(this._domNode,(e=>{if(e.equals(10)||e.equals(3))return this._opts.onTrigger(),void e.preventDefault();this._opts.onKeyDown?.(e)}))}get domNode(){return this._domNode}isEnabled(){return this._domNode.tabIndex>=0}focus(){this._domNode.focus()}setEnabled(e){this._domNode.classList.toggle("disabled",!e),this._domNode.setAttribute("aria-disabled",String(!e)),this._domNode.tabIndex=e?0:-1}setExpanded(e){this._domNode.setAttribute("aria-expanded",String(!!e)),e?(this._domNode.classList.remove(...Se.L.asClassNameArray(Le)),this._domNode.classList.add(...Se.L.asClassNameArray(Te))):(this._domNode.classList.remove(...Se.L.asClassNameArray(Te)),this._domNode.classList.add(...Se.L.asClassNameArray(Le)))}}(0,v.zy)(((e,t)=>{const i=e.getColor(_.ECk);i&&t.addRule(`.monaco-editor .findMatch { border: 1px ${(0,ye.Bb)(e.type)?"dotted":"solid"} ${i}; box-sizing: border-box; }`);const s=e.getColor(_.S5J);s&&t.addRule(`.monaco-editor .findScope { border: 1px ${(0,ye.Bb)(e.type)?"dashed":"solid"} ${s}; }`);const n=e.getColor(_.b1q);n&&t.addRule(`.monaco-editor .find-widget { border: 1px solid ${n}; }`);const r=e.getColor(_.f3U);r&&t.addRule(`.monaco-editor .findMatchInline { color: ${r}; }`);const o=e.getColor(_.p8Y);o&&t.addRule(`.monaco-editor .currentFindMatchInline { color: ${o}; }`)}));var st,nt=i(27195),rt=i(54770),ot=i(47508),at=i(98031),ct=i(58591),lt=i(51467),ht=i(9711),dt=i(67220),ut=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},gt=function(e,t){return function(i,s){t(i,s,e)}};function pt(e,t="single",i=!1){if(!e.hasModel())return null;const s=e.getSelection();if("single"===t&&s.startLineNumber===s.endLineNumber||"multiple"===t)if(s.isEmpty()){const t=e.getConfiguredWordAtPosition(s.getStartPosition());if(t&&!1===i)return t.word}else if(e.getModel().getValueLengthInRange(s)<524288)return e.getModel().getValueInRange(s);return null}let mt=class extends n.jG{static{st=this}static{this.ID="editor.contrib.findController"}get editor(){return this._editor}static get(e){return e.getContribution(st.ID)}constructor(e,t,i,n,r,o){super(),this._editor=e,this._findWidgetVisible=A.bindTo(t),this._contextKeyService=t,this._storageService=i,this._clipboardService=n,this._notificationService=r,this._hoverService=o,this._updateHistoryDelayer=new s.ve(500),this._state=this._register(new de),this.loadQueryState(),this._register(this._state.onFindReplaceStateChange((e=>this._onStateChanged(e)))),this._model=null,this._register(this._editor.onDidChangeModel((()=>{const e=this._editor.getModel()&&this._state.isRevealed;this.disposeModel(),this._state.change({searchScope:null,matchCase:this._storageService.getBoolean("editor.matchCase",1,!1),wholeWord:this._storageService.getBoolean("editor.wholeWord",1,!1),isRegex:this._storageService.getBoolean("editor.isRegex",1,!1),preserveCase:this._storageService.getBoolean("editor.preserveCase",1,!1)},!1),e&&this._start({forceRevealReplace:!1,seedSearchStringFromSelection:"none",seedSearchStringFromNonEmptySelection:!1,seedSearchStringFromGlobalClipboard:!1,shouldFocus:0,shouldAnimate:!1,updateSearchScope:!1,loop:this._editor.getOption(41).loop})})))}dispose(){this.disposeModel(),super.dispose()}disposeModel(){this._model&&(this._model.dispose(),this._model=null)}_onStateChanged(e){this.saveQueryState(e),e.isRevealed&&(this._state.isRevealed?this._findWidgetVisible.set(!0):(this._findWidgetVisible.reset(),this.disposeModel())),e.searchString&&this.setGlobalBufferTerm(this._state.searchString)}saveQueryState(e){e.isRegex&&this._storageService.store("editor.isRegex",this._state.actualIsRegex,1,1),e.wholeWord&&this._storageService.store("editor.wholeWord",this._state.actualWholeWord,1,1),e.matchCase&&this._storageService.store("editor.matchCase",this._state.actualMatchCase,1,1),e.preserveCase&&this._storageService.store("editor.preserveCase",this._state.actualPreserveCase,1,1)}loadQueryState(){this._state.change({matchCase:this._storageService.getBoolean("editor.matchCase",1,this._state.matchCase),wholeWord:this._storageService.getBoolean("editor.wholeWord",1,this._state.wholeWord),isRegex:this._storageService.getBoolean("editor.isRegex",1,this._state.isRegex),preserveCase:this._storageService.getBoolean("editor.preserveCase",1,this._state.preserveCase)},!1)}isFindInputFocused(){return!!N.getValue(this._contextKeyService)}getState(){return this._state}closeFindWidget(){this._state.change({isRevealed:!1,searchScope:null},!1),this._editor.focus()}toggleCaseSensitive(){this._state.change({matchCase:!this._state.matchCase},!1),this._state.isRevealed||this.highlightFindOptions()}toggleWholeWords(){this._state.change({wholeWord:!this._state.wholeWord},!1),this._state.isRevealed||this.highlightFindOptions()}toggleRegex(){this._state.change({isRegex:!this._state.isRegex},!1),this._state.isRevealed||this.highlightFindOptions()}togglePreserveCase(){this._state.change({preserveCase:!this._state.preserveCase},!1),this._state.isRevealed||this.highlightFindOptions()}toggleSearchScope(){if(this._state.searchScope)this._state.change({searchScope:null},!0);else if(this._editor.hasModel()){let e=this._editor.getSelections();e=e.map((e=>(1===e.endColumn&&e.endLineNumber>e.startLineNumber&&(e=e.setEndPosition(e.endLineNumber-1,this._editor.getModel().getLineMaxColumn(e.endLineNumber-1))),e.isEmpty()?null:e))).filter((e=>!!e)),e.length&&this._state.change({searchScope:e},!0)}}setSearchString(e){this._state.isRegex&&(e=r.bm(e)),this._state.change({searchString:e},!1)}highlightFindOptions(e=!1){}async _start(e,t){if(this.disposeModel(),!this._editor.hasModel())return;const i={...t,isRevealed:!0};if("single"===e.seedSearchStringFromSelection){const t=pt(this._editor,e.seedSearchStringFromSelection,e.seedSearchStringFromNonEmptySelection);t&&(this._state.isRegex?i.searchString=r.bm(t):i.searchString=t)}else if("multiple"===e.seedSearchStringFromSelection&&!e.updateSearchScope){const t=pt(this._editor,e.seedSearchStringFromSelection);t&&(i.searchString=t)}if(!i.searchString&&e.seedSearchStringFromGlobalClipboard){const e=await this.getGlobalBufferTerm();if(!this._editor.hasModel())return;e&&(i.searchString=e)}if(e.forceRevealReplace||i.isReplaceRevealed?i.isReplaceRevealed=!0:this._findWidgetVisible.get()||(i.isReplaceRevealed=!1),e.updateSearchScope){const e=this._editor.getSelections();e.some((e=>!e.isEmpty()))&&(i.searchScope=e)}i.loop=e.loop,this._state.change(i,!1),this._model||(this._model=new se(this._editor,this._state))}start(e,t){return this._start(e,t)}moveToNextMatch(){return!!this._model&&(this._model.moveToNextMatch(),!0)}moveToPrevMatch(){return!!this._model&&(this._model.moveToPrevMatch(),!0)}goToMatch(e){return!!this._model&&(this._model.moveToMatch(e),!0)}replace(){return!!this._model&&(this._model.replace(),!0)}replaceAll(){return!!this._model&&(this._editor.getModel()?.isTooLargeForHeapOperation()?(this._notificationService.warn(ve.kg("too.large.for.replaceall","The file is too large to perform a replace all operation.")),!1):(this._model.replaceAll(),!0))}selectAllMatches(){return!!this._model&&(this._model.selectAllMatches(),this._editor.focus(),!0)}async getGlobalBufferTerm(){return this._editor.getOption(41).globalFindClipboard&&this._editor.hasModel()&&!this._editor.getModel().isTooLargeForSyncing()?this._clipboardService.readFindText():""}setGlobalBufferTerm(e){this._editor.getOption(41).globalFindClipboard&&this._editor.hasModel()&&!this._editor.getModel().isTooLargeForSyncing()&&this._clipboardService.writeFindText(e)}};mt=st=ut([gt(1,k.fN),gt(2,ht.CS),gt(3,rt.h),gt(4,ct.Ot),gt(5,dt.TN)],mt);let ft=class extends mt{constructor(e,t,i,s,n,r,o,a,c){super(e,i,o,a,r,c),this._contextViewService=t,this._keybindingService=s,this._themeService=n,this._widget=null,this._findOptionsWidget=null}async _start(e,t){this._widget||this._createFindWidget();const i=this._editor.getSelection();let s=!1;switch(this._editor.getOption(41).autoFindInSelection){case"always":s=!0;break;case"never":s=!1;break;case"multiline":s=!!i&&i.startLineNumber!==i.endLineNumber;break}e.updateSearchScope=e.updateSearchScope||s,await super._start(e,t),this._widget&&(2===e.shouldFocus?this._widget.focusReplaceInput():1===e.shouldFocus&&this._widget.focusFindInput())}highlightFindOptions(e=!1){this._widget||this._createFindWidget(),this._state.isRevealed&&!e?this._widget.highlightFindOptions():this._findOptionsWidget.highlightFindOptions()}_createFindWidget(){this._widget=this._register(new tt(this._editor,this,this._state,this._contextViewService,this._keybindingService,this._contextKeyService,this._themeService,this._storageService,this._notificationService,this._hoverService)),this._findOptionsWidget=this._register(new ce(this._editor,this._state,this._keybindingService))}};ft=ut([gt(1,ot.l),gt(2,k.fN),gt(3,at.b),gt(4,v.Gy),gt(5,ct.Ot),gt(6,ht.CS),gt(7,rt.h),gt(8,dt.TN)],ft);(0,o.gW)(new o.PF({id:U,label:ve.kg("startFindAction","Find"),alias:"Find",precondition:k.M$.or(c.R.focus,k.M$.has("editorIsOpen")),kbOpts:{kbExpr:null,primary:2084,weight:100},menuOpts:{menuId:nt.D8.MenubarEditMenu,group:"3_find",title:ve.kg({key:"miFind",comment:["&& denotes a mnemonic"]},"&&Find"),order:1}})).addImplementation(0,((e,t,i)=>{const s=mt.get(t);return!!s&&s.start({forceRevealReplace:!1,seedSearchStringFromSelection:"never"!==t.getOption(41).seedSearchStringFromSelection?"single":"none",seedSearchStringFromNonEmptySelection:"selection"===t.getOption(41).seedSearchStringFromSelection,seedSearchStringFromGlobalClipboard:t.getOption(41).globalFindClipboard,shouldFocus:1,shouldAnimate:!0,updateSearchScope:!1,loop:t.getOption(41).loop})}));const _t={description:"Open a new In-Editor Find Widget.",args:[{name:"Open a new In-Editor Find Widget args",schema:{properties:{searchString:{type:"string"},replaceString:{type:"string"},isRegex:{type:"boolean"},matchWholeWord:{type:"boolean"},isCaseSensitive:{type:"boolean"},preserveCase:{type:"boolean"},findInSelection:{type:"boolean"}}}}]};class vt extends o.ks{constructor(){super({id:B,label:ve.kg("startFindWithArgsAction","Find With Arguments"),alias:"Find With Arguments",precondition:void 0,kbOpts:{kbExpr:null,primary:0,weight:100},metadata:_t})}async run(e,t,i){const s=mt.get(t);if(s){const e=i?{searchString:i.searchString,replaceString:i.replaceString,isReplaceRevealed:void 0!==i.replaceString,isRegex:i.isRegex,wholeWord:i.matchWholeWord,matchCase:i.isCaseSensitive,preserveCase:i.preserveCase}:{};await s.start({forceRevealReplace:!1,seedSearchStringFromSelection:0===s.getState().searchString.length&&"never"!==t.getOption(41).seedSearchStringFromSelection?"single":"none",seedSearchStringFromNonEmptySelection:"selection"===t.getOption(41).seedSearchStringFromSelection,seedSearchStringFromGlobalClipboard:!0,shouldFocus:1,shouldAnimate:!0,updateSearchScope:i?.findInSelection||!1,loop:t.getOption(41).loop},e),s.setGlobalBufferTerm(s.getState().searchString)}}}class Ct extends o.ks{constructor(){super({id:H,label:ve.kg("startFindWithSelectionAction","Find With Selection"),alias:"Find With Selection",precondition:void 0,kbOpts:{kbExpr:null,primary:0,mac:{primary:2083},weight:100}})}async run(e,t){const i=mt.get(t);i&&(await i.start({forceRevealReplace:!1,seedSearchStringFromSelection:"multiple",seedSearchStringFromNonEmptySelection:!1,seedSearchStringFromGlobalClipboard:!1,shouldFocus:0,shouldAnimate:!0,updateSearchScope:!1,loop:t.getOption(41).loop}),i.setGlobalBufferTerm(i.getState().searchString))}}class Et extends o.ks{async run(e,t){const i=mt.get(t);i&&!this._run(i)&&(await i.start({forceRevealReplace:!1,seedSearchStringFromSelection:0===i.getState().searchString.length&&"never"!==t.getOption(41).seedSearchStringFromSelection?"single":"none",seedSearchStringFromNonEmptySelection:"selection"===t.getOption(41).seedSearchStringFromSelection,seedSearchStringFromGlobalClipboard:!0,shouldFocus:0,shouldAnimate:!0,updateSearchScope:!1,loop:t.getOption(41).loop}),this._run(i))}}class bt extends o.ks{constructor(){super({id:z,label:ve.kg("findMatchAction.goToMatch","Go to Match..."),alias:"Go to Match...",precondition:A}),this._highlightDecorations=[]}run(e,t,i){const s=mt.get(t);if(!s)return;const r=s.getState().matchesCount;if(r<1){return void e.get(ct.Ot).notify({severity:ct.AI.Warning,message:ve.kg("findMatchAction.noResults","No matches. Try searching for something else.")})}const o=e.get(lt.GK),a=new n.Cm,c=a.add(o.createInputBox());c.placeholder=ve.kg("findMatchAction.inputPlaceHolder","Type a number to go to a specific match (between 1 and {0})",r);const l=e=>{const t=parseInt(e);if(isNaN(t))return;const i=s.getState().matchesCount;return t>0&&t<=i?t-1:t<0&&t>=-i?i+t:void 0},h=e=>{const i=l(e);if("number"===typeof i){c.validationMessage=void 0,s.goToMatch(i);const e=s.getState().currentMatch;e&&this.addDecorations(t,e)}else c.validationMessage=ve.kg("findMatchAction.inputValidationMessage","Please type a number between 1 and {0}",s.getState().matchesCount),this.clearDecorations(t)};a.add(c.onDidChangeValue((e=>{h(e)}))),a.add(c.onDidAccept((()=>{const e=l(c.value);"number"===typeof e?(s.goToMatch(e),c.hide()):c.validationMessage=ve.kg("findMatchAction.inputValidationMessage","Please type a number between 1 and {0}",s.getState().matchesCount)}))),a.add(c.onDidHide((()=>{this.clearDecorations(t),a.dispose()}))),c.show()}clearDecorations(e){e.changeDecorations((e=>{this._highlightDecorations=e.deltaDecorations(this._highlightDecorations,[])}))}addDecorations(e,t){e.changeDecorations((e=>{this._highlightDecorations=e.deltaDecorations(this._highlightDecorations,[{range:t,options:{description:"find-match-quick-access-range-highlight",className:"rangeHighlight",isWholeLine:!0}},{range:t,options:{description:"find-match-quick-access-range-highlight-overview",overviewRuler:{color:(0,v.Yf)(a.vp),position:l.A5.Full}}}])}))}}class St extends o.ks{async run(e,t){const i=mt.get(t);if(!i)return;const s=pt(t,"single",!1);s&&i.setSearchString(s),this._run(i)||(await i.start({forceRevealReplace:!1,seedSearchStringFromSelection:"none",seedSearchStringFromNonEmptySelection:!1,seedSearchStringFromGlobalClipboard:!1,shouldFocus:0,shouldAnimate:!0,updateSearchScope:!1,loop:t.getOption(41).loop}),this._run(i))}}(0,o.gW)(new o.PF({id:K,label:ve.kg("startReplace","Replace"),alias:"Replace",precondition:k.M$.or(c.R.focus,k.M$.has("editorIsOpen")),kbOpts:{kbExpr:null,primary:2086,mac:{primary:2596},weight:100},menuOpts:{menuId:nt.D8.MenubarEditMenu,group:"3_find",title:ve.kg({key:"miReplace",comment:["&& denotes a mnemonic"]},"&&Replace"),order:2}})).addImplementation(0,((e,t,i)=>{if(!t.hasModel()||t.getOption(92))return!1;const s=mt.get(t);if(!s)return!1;const n=t.getSelection(),r=s.isFindInputFocused(),o=!n.isEmpty()&&n.startLineNumber===n.endLineNumber&&"never"!==t.getOption(41).seedSearchStringFromSelection&&!r,a=r||o?2:1;return s.start({forceRevealReplace:!0,seedSearchStringFromSelection:o?"single":"none",seedSearchStringFromNonEmptySelection:"selection"===t.getOption(41).seedSearchStringFromSelection,seedSearchStringFromGlobalClipboard:"never"!==t.getOption(41).seedSearchStringFromSelection,shouldFocus:a,shouldAnimate:!0,updateSearchScope:!1,loop:t.getOption(41).loop})})),(0,o.HW)(mt.ID,ft,0),(0,o.Fl)(vt),(0,o.Fl)(Ct),(0,o.Fl)(class extends Et{constructor(){super({id:W,label:ve.kg("findNextMatchAction","Find Next"),alias:"Find Next",precondition:void 0,kbOpts:[{kbExpr:c.R.focus,primary:61,mac:{primary:2085,secondary:[61]},weight:100},{kbExpr:k.M$.and(c.R.focus,N),primary:3,weight:100}]})}_run(e){return!!e.moveToNextMatch()&&(e.editor.pushUndoStop(),!0)}}),(0,o.Fl)(class extends Et{constructor(){super({id:V,label:ve.kg("findPreviousMatchAction","Find Previous"),alias:"Find Previous",precondition:void 0,kbOpts:[{kbExpr:c.R.focus,primary:1085,mac:{primary:3109,secondary:[1085]},weight:100},{kbExpr:k.M$.and(c.R.focus,N),primary:1027,weight:100}]})}_run(e){return e.moveToPrevMatch()}}),(0,o.Fl)(bt),(0,o.Fl)(class extends St{constructor(){super({id:G,label:ve.kg("nextSelectionMatchFindAction","Find Next Selection"),alias:"Find Next Selection",precondition:void 0,kbOpts:{kbExpr:c.R.focus,primary:2109,weight:100}})}_run(e){return e.moveToNextMatch()}}),(0,o.Fl)(class extends St{constructor(){super({id:j,label:ve.kg("previousSelectionMatchFindAction","Find Previous Selection"),alias:"Find Previous Selection",precondition:void 0,kbOpts:{kbExpr:c.R.focus,primary:3133,weight:100}})}_run(e){return e.moveToPrevMatch()}});const yt=o.DX.bindToContribution(mt.get);(0,o.E_)(new yt({id:Y,precondition:A,handler:e=>e.closeFindWidget(),kbOpts:{weight:105,kbExpr:k.M$.and(c.R.focus,k.M$.not("isComposing")),primary:9,secondary:[1033]}})),(0,o.E_)(new yt({id:q,precondition:void 0,handler:e=>e.toggleCaseSensitive(),kbOpts:{weight:105,kbExpr:c.R.focus,primary:O.primary,mac:O.mac,win:O.win,linux:O.linux}})),(0,o.E_)(new yt({id:$,precondition:void 0,handler:e=>e.toggleWholeWords(),kbOpts:{weight:105,kbExpr:c.R.focus,primary:D.primary,mac:D.mac,win:D.win,linux:D.linux}})),(0,o.E_)(new yt({id:Q,precondition:void 0,handler:e=>e.toggleRegex(),kbOpts:{weight:105,kbExpr:c.R.focus,primary:M.primary,mac:M.mac,win:M.win,linux:M.linux}})),(0,o.E_)(new yt({id:X,precondition:void 0,handler:e=>e.toggleSearchScope(),kbOpts:{weight:105,kbExpr:c.R.focus,primary:P.primary,mac:P.mac,win:P.win,linux:P.linux}})),(0,o.E_)(new yt({id:Z,precondition:void 0,handler:e=>e.togglePreserveCase(),kbOpts:{weight:105,kbExpr:c.R.focus,primary:F.primary,mac:F.mac,win:F.win,linux:F.linux}})),(0,o.E_)(new yt({id:J,precondition:A,handler:e=>e.replace(),kbOpts:{weight:105,kbExpr:c.R.focus,primary:3094}})),(0,o.E_)(new yt({id:J,precondition:A,handler:e=>e.replace(),kbOpts:{weight:105,kbExpr:k.M$.and(c.R.focus,I),primary:3}})),(0,o.E_)(new yt({id:ee,precondition:A,handler:e=>e.replaceAll(),kbOpts:{weight:105,kbExpr:c.R.focus,primary:2563}})),(0,o.E_)(new yt({id:ee,precondition:A,handler:e=>e.replaceAll(),kbOpts:{weight:105,kbExpr:k.M$.and(c.R.focus,I),primary:void 0,mac:{primary:2051}}})),(0,o.E_)(new yt({id:te,precondition:A,handler:e=>e.selectAllMatches(),kbOpts:{weight:105,kbExpr:c.R.focus,primary:515}}))},34309:(e,t,i)=>{"use strict";i.d(t,{N:()=>y});var s,n=i(8597),r=i(20370),o=i(10350),a=i(16980),c=i(5662),l=i(31308),h=i(87958),d=i(25689),u=i(631),g=i(38844),p=i(92368),m=i(86571),f=i(83069),_=i(36677),v=i(62083),C=i(78209),E=i(63591),b=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},S=function(e,t){return function(i,s){t(i,s,e)}};let y=class extends c.jG{static{s=this}static{this._breadcrumbsSourceFactory=(0,l.FY)(s,(()=>({dispose(){},getBreadcrumbItems:(e,t)=>[]})))}static setBreadcrumbsSourceFactory(e){this._breadcrumbsSourceFactory.set(e,void 0)}get isUpdatingHiddenAreas(){return this._isUpdatingHiddenAreas}constructor(e,t,i,n){super(),this._editors=e,this._diffModel=t,this._options=i,this._instantiationService=n,this._modifiedOutlineSource=(0,h.a0)(this,(e=>{const t=this._editors.modifiedModel.read(e),i=s._breadcrumbsSourceFactory.read(e);return t&&i?i(t,this._instantiationService):void 0})),this._isUpdatingHiddenAreas=!1,this._register(this._editors.original.onDidChangeCursorPosition((e=>{if(1===e.reason)return;const t=this._diffModel.get();(0,l.Rn)((e=>{for(const i of this._editors.original.getSelections()||[])t?.ensureOriginalLineIsVisible(i.getStartPosition().lineNumber,0,e),t?.ensureOriginalLineIsVisible(i.getEndPosition().lineNumber,0,e)}))}))),this._register(this._editors.modified.onDidChangeCursorPosition((e=>{if(1===e.reason)return;const t=this._diffModel.get();(0,l.Rn)((e=>{for(const i of this._editors.modified.getSelections()||[])t?.ensureModifiedLineIsVisible(i.getStartPosition().lineNumber,0,e),t?.ensureModifiedLineIsVisible(i.getEndPosition().lineNumber,0,e)}))})));const r=this._diffModel.map(((e,t)=>{const i=e?.unchangedRegions.read(t)??[];return 1===i.length&&1===i[0].modifiedLineNumber&&i[0].lineCount===this._editors.modifiedModel.read(t)?.getLineCount()?[]:i}));this.viewZones=(0,l.rm)(this,((e,t)=>{const i=this._modifiedOutlineSource.read(e);if(!i)return{origViewZones:[],modViewZones:[]};const s=[],n=[],o=this._options.renderSideBySide.read(e),a=this._options.compactMode.read(e),c=r.read(e);for(let r=0;rh.getHiddenOriginalRange(e).startLineNumber-1)),i=new p.D1(e,12);s.push(i),t.add(new w(this._editors.original,i,h,!o))}{const e=(0,l.un)(this,(e=>h.getHiddenModifiedRange(e).startLineNumber-1)),i=new p.D1(e,12);n.push(i),t.add(new w(this._editors.modified,i,h))}}else{{const e=(0,l.un)(this,(e=>h.getHiddenOriginalRange(e).startLineNumber-1)),n=new p.D1(e,24);s.push(n),t.add(new R(this._editors.original,n,h,h.originalUnchangedRange,!o,i,(e=>this._diffModel.get().ensureModifiedLineIsVisible(e,2,void 0)),this._options))}{const e=(0,l.un)(this,(e=>h.getHiddenModifiedRange(e).startLineNumber-1)),s=new p.D1(e,24);n.push(s),t.add(new R(this._editors.modified,s,h,h.modifiedUnchangedRange,!1,i,(e=>this._diffModel.get().ensureModifiedLineIsVisible(e,2,void 0)),this._options))}}}return{origViewZones:s,modViewZones:n}}));const c={description:"unchanged lines",className:"diff-unchanged-lines",isWholeLine:!0},g={description:"Fold Unchanged",glyphMarginHoverMessage:new a.Bc(void 0,{isTrusted:!0,supportThemeIcons:!0}).appendMarkdown((0,C.kg)("foldUnchanged","Fold Unchanged Region")),glyphMarginClassName:"fold-unchanged "+d.L.asClassName(o.W.fold),zIndex:10001};this._register((0,p.pY)(this._editors.original,(0,l.un)(this,(e=>{const t=r.read(e),i=t.map((e=>({range:e.originalUnchangedRange.toInclusiveRange(),options:c})));for(const s of t)s.shouldHideControls(e)&&i.push({range:_.Q.fromPositions(new f.y(s.originalLineNumber,1)),options:g});return i})))),this._register((0,p.pY)(this._editors.modified,(0,l.un)(this,(e=>{const t=r.read(e),i=t.map((e=>({range:e.modifiedUnchangedRange.toInclusiveRange(),options:c})));for(const s of t)s.shouldHideControls(e)&&i.push({range:m.M.ofLength(s.modifiedLineNumber,1).toInclusiveRange(),options:g});return i})))),this._register((0,l.fm)((e=>{const t=r.read(e);this._isUpdatingHiddenAreas=!0;try{this._editors.original.setHiddenAreas(t.map((t=>t.getHiddenOriginalRange(e).toInclusiveRange())).filter(u.O9)),this._editors.modified.setHiddenAreas(t.map((t=>t.getHiddenModifiedRange(e).toInclusiveRange())).filter(u.O9))}finally{this._isUpdatingHiddenAreas=!1}}))),this._register(this._editors.modified.onMouseUp((e=>{if(!e.event.rightButton&&e.target.position&&e.target.element?.className.includes("fold-unchanged")){const t=e.target.position.lineNumber,i=this._diffModel.get();if(!i)return;const s=i.unchangedRegions.get().find((e=>e.modifiedUnchangedRange.includes(t)));if(!s)return;s.collapseAll(void 0),e.event.stopPropagation(),e.event.preventDefault()}}))),this._register(this._editors.original.onMouseUp((e=>{if(!e.event.rightButton&&e.target.position&&e.target.element?.className.includes("fold-unchanged")){const t=e.target.position.lineNumber,i=this._diffModel.get();if(!i)return;const s=i.unchangedRegions.get().find((e=>e.originalUnchangedRange.includes(t)));if(!s)return;s.collapseAll(void 0),e.event.stopPropagation(),e.event.preventDefault()}})))}};y=s=b([S(3,E._Y)],y);class w extends p.uN{constructor(e,t,i,s=!1){const r=(0,n.h)("div.diff-hidden-lines-widget");super(e,t,r.root),this._unchangedRegion=i,this._hide=s,this._nodes=(0,n.h)("div.diff-hidden-lines-compact",[(0,n.h)("div.line-left",[]),(0,n.h)("div.text@text",[]),(0,n.h)("div.line-right",[])]),r.root.appendChild(this._nodes.root),this._hide&&this._nodes.root.replaceChildren(),this._register((0,l.fm)((e=>{if(!this._hide){const t=this._unchangedRegion.getHiddenModifiedRange(e).length,i=(0,C.kg)("hiddenLines","{0} hidden lines",t);this._nodes.text.innerText=i}})))}}class R extends p.uN{constructor(e,t,i,s,a,c,h,d){const u=(0,n.h)("div.diff-hidden-lines-widget");super(e,t,u.root),this._editor=e,this._unchangedRegion=i,this._unchangedRegionRange=s,this._hide=a,this._modifiedOutlineSource=c,this._revealModifiedHiddenLine=h,this._options=d,this._nodes=(0,n.h)("div.diff-hidden-lines",[(0,n.h)("div.top@top",{title:(0,C.kg)("diff.hiddenLines.top","Click or drag to show more above")}),(0,n.h)("div.center@content",{style:{display:"flex"}},[(0,n.h)("div@first",{style:{display:"flex",justifyContent:"center",alignItems:"center",flexShrink:"0"}},[(0,n.$)("a",{title:(0,C.kg)("showUnchangedRegion","Show Unchanged Region"),role:"button",onclick:()=>{this._unchangedRegion.showAll(void 0)}},...(0,r.n)("$(unfold)"))]),(0,n.h)("div@others",{style:{display:"flex",justifyContent:"center",alignItems:"center"}})]),(0,n.h)("div.bottom@bottom",{title:(0,C.kg)("diff.bottom","Click or drag to show more below"),role:"button"})]),u.root.appendChild(this._nodes.root),this._hide?(0,n.Ln)(this._nodes.first):this._register((0,p.AV)(this._nodes.first,{width:(0,g.Ud)(this._editor).layoutInfoContentLeft})),this._register((0,l.fm)((e=>{const t=this._unchangedRegion.visibleLineCountTop.read(e)+this._unchangedRegion.visibleLineCountBottom.read(e)===this._unchangedRegion.lineCount;this._nodes.bottom.classList.toggle("canMoveTop",!t),this._nodes.bottom.classList.toggle("canMoveBottom",this._unchangedRegion.visibleLineCountBottom.read(e)>0),this._nodes.top.classList.toggle("canMoveTop",this._unchangedRegion.visibleLineCountTop.read(e)>0),this._nodes.top.classList.toggle("canMoveBottom",!t);const i=this._unchangedRegion.isDragged.read(e),s=this._editor.getDomNode();s&&(s.classList.toggle("draggingUnchangedRegion",!!i),"top"===i?(s.classList.toggle("canMoveTop",this._unchangedRegion.visibleLineCountTop.read(e)>0),s.classList.toggle("canMoveBottom",!t)):"bottom"===i?(s.classList.toggle("canMoveTop",!t),s.classList.toggle("canMoveBottom",this._unchangedRegion.visibleLineCountBottom.read(e)>0)):(s.classList.toggle("canMoveTop",!1),s.classList.toggle("canMoveBottom",!1)))})));const m=this._editor;this._register((0,n.ko)(this._nodes.top,"mousedown",(e=>{if(0!==e.button)return;this._nodes.top.classList.toggle("dragging",!0),this._nodes.root.classList.toggle("dragging",!0),e.preventDefault();const t=e.clientY;let i=!1;const s=this._unchangedRegion.visibleLineCountTop.get();this._unchangedRegion.isDragged.set("top",void 0);const r=(0,n.zk)(this._nodes.top),o=(0,n.ko)(r,"mousemove",(e=>{const n=e.clientY-t;i=i||Math.abs(n)>2;const r=Math.round(n/m.getOption(67)),o=Math.max(0,Math.min(s+r,this._unchangedRegion.getMaxVisibleLineCountTop()));this._unchangedRegion.visibleLineCountTop.set(o,void 0)})),a=(0,n.ko)(r,"mouseup",(e=>{i||this._unchangedRegion.showMoreAbove(this._options.hideUnchangedRegionsRevealLineCount.get(),void 0),this._nodes.top.classList.toggle("dragging",!1),this._nodes.root.classList.toggle("dragging",!1),this._unchangedRegion.isDragged.set(void 0,void 0),o.dispose(),a.dispose()}))}))),this._register((0,n.ko)(this._nodes.bottom,"mousedown",(e=>{if(0!==e.button)return;this._nodes.bottom.classList.toggle("dragging",!0),this._nodes.root.classList.toggle("dragging",!0),e.preventDefault();const t=e.clientY;let i=!1;const s=this._unchangedRegion.visibleLineCountBottom.get();this._unchangedRegion.isDragged.set("bottom",void 0);const r=(0,n.zk)(this._nodes.bottom),o=(0,n.ko)(r,"mousemove",(e=>{const n=e.clientY-t;i=i||Math.abs(n)>2;const r=Math.round(n/m.getOption(67)),o=Math.max(0,Math.min(s-r,this._unchangedRegion.getMaxVisibleLineCountBottom())),a=this._unchangedRegionRange.endLineNumberExclusive>m.getModel().getLineCount()?m.getContentHeight():m.getTopForLineNumber(this._unchangedRegionRange.endLineNumberExclusive);this._unchangedRegion.visibleLineCountBottom.set(o,void 0);const c=this._unchangedRegionRange.endLineNumberExclusive>m.getModel().getLineCount()?m.getContentHeight():m.getTopForLineNumber(this._unchangedRegionRange.endLineNumberExclusive);m.setScrollTop(m.getScrollTop()+(c-a))})),a=(0,n.ko)(r,"mouseup",(e=>{if(this._unchangedRegion.isDragged.set(void 0,void 0),!i){const e=m.getTopForLineNumber(this._unchangedRegionRange.endLineNumberExclusive);this._unchangedRegion.showMoreBelow(this._options.hideUnchangedRegionsRevealLineCount.get(),void 0);const t=m.getTopForLineNumber(this._unchangedRegionRange.endLineNumberExclusive);m.setScrollTop(m.getScrollTop()+(t-e))}this._nodes.bottom.classList.toggle("dragging",!1),this._nodes.root.classList.toggle("dragging",!1),o.dispose(),a.dispose()}))}))),this._register((0,l.fm)((e=>{const t=[];if(!this._hide){const s=i.getHiddenModifiedRange(e).length,a=(0,C.kg)("hiddenLines","{0} hidden lines",s),c=(0,n.$)("span",{title:(0,C.kg)("diff.hiddenLines.expandAll","Double click to unfold")},a);c.addEventListener("dblclick",(e=>{0===e.button&&(e.preventDefault(),this._unchangedRegion.showAll(void 0))})),t.push(c);const l=this._unchangedRegion.getHiddenModifiedRange(e),h=this._modifiedOutlineSource.getBreadcrumbItems(l,e);if(h.length>0){t.push((0,n.$)("span",void 0,"\xa0\xa0|\xa0\xa0"));for(let e=0;e{this._revealModifiedHiddenLine(i.startLineNumber)}}}}(0,n.Ln)(this._nodes.others,...t)})))}}},34326:(e,t,i)=>{"use strict";i.d(t,{Np:()=>r,jA:()=>o,z9:()=>n});var s=i(23452);function n(e){return!(!e||"function"!==typeof e.getEditorType)&&e.getEditorType()===s._.ICodeEditor}function r(e){return!(!e||"function"!==typeof e.getEditorType)&&e.getEditorType()===s._.IDiffEditor}function o(e){return n(e)?e:r(e)?e.getModifiedEditor():function(e){return!!e&&"object"===typeof e&&"function"===typeof e.onDidChangeActiveEditor}(e)&&n(e.activeCodeEditor)?e.activeCodeEditor:null}},34408:(e,t,i)=>{var s=i(73917),n=i(39069),r=i(72633);e.exports=function(e){return r(n(e,void 0,s),e+"")}},34420:(e,t,i)=>{!function(){"use strict";const t=i(85858),s="$value",n={string:null,number:null,boolean:null,null:null,object:null,array:null};function r(e){switch(e){case"array":return"list";case"object":return"map";default:return e}}function o(e){const i=t(e);if(!Object.prototype.hasOwnProperty.call(n,i))throw new Error('unipika: invalid input - node type "'+i+'" is not supported.');return{$type:r(i),$value:e}}function a(e,t){return e[s]=function(e,t){return Object.keys(e).map((function(i){const s=o(i);return"$attributes"===i||"$value"===i||"$incomplete"===i||"$type"===i?s.$special_key=!0:s.$key=!0,[s,c(e[i],t)]}))}(e[s],t),e}const c=function(e,t){let i;return(e=o(e))&&(i=e.$type,"map"===i?e=a(e,t):"list"===i&&(e=function(e,t){return e[s]=e[s].map((function(e){return c(e,t)})),e}(e,t))),e};e.exports=c}()},34529:(e,t,i)=>{e.exports=function(e){const t=i(94297),s=i(76319)(e);return function(e,i,n){let r="";const o=e.$value,a=o.length;return t.drawFullView(a,i)?(r+=t.ARRAY_START+t.getIndent(i,n),r+=s(o,i,n),r+=t.getIndent(i,n-1)+t.ARRAY_END):t.drawCompactView(a,i)?(r+=t.ARRAY_START,r+=s(o,i,n-1),r+=t.ARRAY_END):r+=t.ARRAY_START+t.ARRAY_END,r}}},34671:(e,t,i)=>{"use strict";i.d(t,{A:()=>o});var s,n=i(59284);function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t{"use strict";i.d(t,{K:()=>m});var s,n,r=i(80781),o=Object.defineProperty,a=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,l=Object.prototype.hasOwnProperty,h=(e,t,i,s)=>{if(t&&"object"===typeof t||"function"===typeof t)for(let n of c(t))l.call(e,n)||n===i||o(e,n,{get:()=>t[n],enumerable:!(s=a(t,n))||s.enumerable});return e},d={};h(d,s=r,"default"),n&&h(n,s,"default");var u={},g={},p=class e{static getOrCreate(t){return g[t]||(g[t]=new e(t)),g[t]}constructor(e){this._languageId=e,this._loadingTriggered=!1,this._lazyLoadPromise=new Promise(((e,t)=>{this._lazyLoadPromiseResolve=e,this._lazyLoadPromiseReject=t}))}load(){return this._loadingTriggered||(this._loadingTriggered=!0,u[this._languageId].loader().then((e=>this._lazyLoadPromiseResolve(e)),(e=>this._lazyLoadPromiseReject(e)))),this._lazyLoadPromise}};function m(e){const t=e.id;u[t]=e,d.languages.register(e);const i=p.getOrCreate(t);d.languages.registerTokensProviderFactory(t,{create:async()=>(await i.load()).language}),d.languages.onLanguageEncountered(t,(async()=>{const e=await i.load();d.languages.setLanguageConfiguration(t,e.conf)}))}},35015:(e,t,i)=>{"use strict";var s,n,r,o,a,c,l,h,d,u,g,p,m,f,_,v,C,E,b,S,y,w,R,L,T,x,k,A,N,I,O,D,M,P,F,U,H,B,W,V,z,G,j,K,Y,q;i.d(t,{A5:()=>O,Ah:()=>D,DD:()=>w,DO:()=>P,Gn:()=>s,H_:()=>G,Ic:()=>M,Io:()=>o,Kb:()=>u,M$:()=>v,OV:()=>A,QP:()=>a,Qj:()=>l,R3:()=>T,SB:()=>B,U7:()=>j,VW:()=>E,VX:()=>x,WA:()=>V,WU:()=>f,XR:()=>H,YT:()=>N,ZS:()=>_,_E:()=>r,cj:()=>R,dE:()=>I,d_:()=>L,e0:()=>g,h5:()=>h,hS:()=>k,hW:()=>F,jT:()=>W,kK:()=>Y,kf:()=>m,l:()=>C,m9:()=>K,of:()=>d,ok:()=>n,ov:()=>U,p2:()=>p,qw:()=>S,r4:()=>b,sm:()=>y,t7:()=>c,tJ:()=>q,v0:()=>z}),function(e){e[e.Unknown=0]="Unknown",e[e.Disabled=1]="Disabled",e[e.Enabled=2]="Enabled"}(s||(s={})),function(e){e[e.Invoke=1]="Invoke",e[e.Auto=2]="Auto"}(n||(n={})),function(e){e[e.None=0]="None",e[e.KeepWhitespace=1]="KeepWhitespace",e[e.InsertAsSnippet=4]="InsertAsSnippet"}(r||(r={})),function(e){e[e.Method=0]="Method",e[e.Function=1]="Function",e[e.Constructor=2]="Constructor",e[e.Field=3]="Field",e[e.Variable=4]="Variable",e[e.Class=5]="Class",e[e.Struct=6]="Struct",e[e.Interface=7]="Interface",e[e.Module=8]="Module",e[e.Property=9]="Property",e[e.Event=10]="Event",e[e.Operator=11]="Operator",e[e.Unit=12]="Unit",e[e.Value=13]="Value",e[e.Constant=14]="Constant",e[e.Enum=15]="Enum",e[e.EnumMember=16]="EnumMember",e[e.Keyword=17]="Keyword",e[e.Text=18]="Text",e[e.Color=19]="Color",e[e.File=20]="File",e[e.Reference=21]="Reference",e[e.Customcolor=22]="Customcolor",e[e.Folder=23]="Folder",e[e.TypeParameter=24]="TypeParameter",e[e.User=25]="User",e[e.Issue=26]="Issue",e[e.Snippet=27]="Snippet"}(o||(o={})),function(e){e[e.Deprecated=1]="Deprecated"}(a||(a={})),function(e){e[e.Invoke=0]="Invoke",e[e.TriggerCharacter=1]="TriggerCharacter",e[e.TriggerForIncompleteCompletions=2]="TriggerForIncompleteCompletions"}(c||(c={})),function(e){e[e.EXACT=0]="EXACT",e[e.ABOVE=1]="ABOVE",e[e.BELOW=2]="BELOW"}(l||(l={})),function(e){e[e.NotSet=0]="NotSet",e[e.ContentFlush=1]="ContentFlush",e[e.RecoverFromMarkers=2]="RecoverFromMarkers",e[e.Explicit=3]="Explicit",e[e.Paste=4]="Paste",e[e.Undo=5]="Undo",e[e.Redo=6]="Redo"}(h||(h={})),function(e){e[e.LF=1]="LF",e[e.CRLF=2]="CRLF"}(d||(d={})),function(e){e[e.Text=0]="Text",e[e.Read=1]="Read",e[e.Write=2]="Write"}(u||(u={})),function(e){e[e.None=0]="None",e[e.Keep=1]="Keep",e[e.Brackets=2]="Brackets",e[e.Advanced=3]="Advanced",e[e.Full=4]="Full"}(g||(g={})),function(e){e[e.acceptSuggestionOnCommitCharacter=0]="acceptSuggestionOnCommitCharacter",e[e.acceptSuggestionOnEnter=1]="acceptSuggestionOnEnter",e[e.accessibilitySupport=2]="accessibilitySupport",e[e.accessibilityPageSize=3]="accessibilityPageSize",e[e.ariaLabel=4]="ariaLabel",e[e.ariaRequired=5]="ariaRequired",e[e.autoClosingBrackets=6]="autoClosingBrackets",e[e.autoClosingComments=7]="autoClosingComments",e[e.screenReaderAnnounceInlineSuggestion=8]="screenReaderAnnounceInlineSuggestion",e[e.autoClosingDelete=9]="autoClosingDelete",e[e.autoClosingOvertype=10]="autoClosingOvertype",e[e.autoClosingQuotes=11]="autoClosingQuotes",e[e.autoIndent=12]="autoIndent",e[e.automaticLayout=13]="automaticLayout",e[e.autoSurround=14]="autoSurround",e[e.bracketPairColorization=15]="bracketPairColorization",e[e.guides=16]="guides",e[e.codeLens=17]="codeLens",e[e.codeLensFontFamily=18]="codeLensFontFamily",e[e.codeLensFontSize=19]="codeLensFontSize",e[e.colorDecorators=20]="colorDecorators",e[e.colorDecoratorsLimit=21]="colorDecoratorsLimit",e[e.columnSelection=22]="columnSelection",e[e.comments=23]="comments",e[e.contextmenu=24]="contextmenu",e[e.copyWithSyntaxHighlighting=25]="copyWithSyntaxHighlighting",e[e.cursorBlinking=26]="cursorBlinking",e[e.cursorSmoothCaretAnimation=27]="cursorSmoothCaretAnimation",e[e.cursorStyle=28]="cursorStyle",e[e.cursorSurroundingLines=29]="cursorSurroundingLines",e[e.cursorSurroundingLinesStyle=30]="cursorSurroundingLinesStyle",e[e.cursorWidth=31]="cursorWidth",e[e.disableLayerHinting=32]="disableLayerHinting",e[e.disableMonospaceOptimizations=33]="disableMonospaceOptimizations",e[e.domReadOnly=34]="domReadOnly",e[e.dragAndDrop=35]="dragAndDrop",e[e.dropIntoEditor=36]="dropIntoEditor",e[e.emptySelectionClipboard=37]="emptySelectionClipboard",e[e.experimentalWhitespaceRendering=38]="experimentalWhitespaceRendering",e[e.extraEditorClassName=39]="extraEditorClassName",e[e.fastScrollSensitivity=40]="fastScrollSensitivity",e[e.find=41]="find",e[e.fixedOverflowWidgets=42]="fixedOverflowWidgets",e[e.folding=43]="folding",e[e.foldingStrategy=44]="foldingStrategy",e[e.foldingHighlight=45]="foldingHighlight",e[e.foldingImportsByDefault=46]="foldingImportsByDefault",e[e.foldingMaximumRegions=47]="foldingMaximumRegions",e[e.unfoldOnClickAfterEndOfLine=48]="unfoldOnClickAfterEndOfLine",e[e.fontFamily=49]="fontFamily",e[e.fontInfo=50]="fontInfo",e[e.fontLigatures=51]="fontLigatures",e[e.fontSize=52]="fontSize",e[e.fontWeight=53]="fontWeight",e[e.fontVariations=54]="fontVariations",e[e.formatOnPaste=55]="formatOnPaste",e[e.formatOnType=56]="formatOnType",e[e.glyphMargin=57]="glyphMargin",e[e.gotoLocation=58]="gotoLocation",e[e.hideCursorInOverviewRuler=59]="hideCursorInOverviewRuler",e[e.hover=60]="hover",e[e.inDiffEditor=61]="inDiffEditor",e[e.inlineSuggest=62]="inlineSuggest",e[e.inlineEdit=63]="inlineEdit",e[e.letterSpacing=64]="letterSpacing",e[e.lightbulb=65]="lightbulb",e[e.lineDecorationsWidth=66]="lineDecorationsWidth",e[e.lineHeight=67]="lineHeight",e[e.lineNumbers=68]="lineNumbers",e[e.lineNumbersMinChars=69]="lineNumbersMinChars",e[e.linkedEditing=70]="linkedEditing",e[e.links=71]="links",e[e.matchBrackets=72]="matchBrackets",e[e.minimap=73]="minimap",e[e.mouseStyle=74]="mouseStyle",e[e.mouseWheelScrollSensitivity=75]="mouseWheelScrollSensitivity",e[e.mouseWheelZoom=76]="mouseWheelZoom",e[e.multiCursorMergeOverlapping=77]="multiCursorMergeOverlapping",e[e.multiCursorModifier=78]="multiCursorModifier",e[e.multiCursorPaste=79]="multiCursorPaste",e[e.multiCursorLimit=80]="multiCursorLimit",e[e.occurrencesHighlight=81]="occurrencesHighlight",e[e.overviewRulerBorder=82]="overviewRulerBorder",e[e.overviewRulerLanes=83]="overviewRulerLanes",e[e.padding=84]="padding",e[e.pasteAs=85]="pasteAs",e[e.parameterHints=86]="parameterHints",e[e.peekWidgetDefaultFocus=87]="peekWidgetDefaultFocus",e[e.placeholder=88]="placeholder",e[e.definitionLinkOpensInPeek=89]="definitionLinkOpensInPeek",e[e.quickSuggestions=90]="quickSuggestions",e[e.quickSuggestionsDelay=91]="quickSuggestionsDelay",e[e.readOnly=92]="readOnly",e[e.readOnlyMessage=93]="readOnlyMessage",e[e.renameOnType=94]="renameOnType",e[e.renderControlCharacters=95]="renderControlCharacters",e[e.renderFinalNewline=96]="renderFinalNewline",e[e.renderLineHighlight=97]="renderLineHighlight",e[e.renderLineHighlightOnlyWhenFocus=98]="renderLineHighlightOnlyWhenFocus",e[e.renderValidationDecorations=99]="renderValidationDecorations",e[e.renderWhitespace=100]="renderWhitespace",e[e.revealHorizontalRightPadding=101]="revealHorizontalRightPadding",e[e.roundedSelection=102]="roundedSelection",e[e.rulers=103]="rulers",e[e.scrollbar=104]="scrollbar",e[e.scrollBeyondLastColumn=105]="scrollBeyondLastColumn",e[e.scrollBeyondLastLine=106]="scrollBeyondLastLine",e[e.scrollPredominantAxis=107]="scrollPredominantAxis",e[e.selectionClipboard=108]="selectionClipboard",e[e.selectionHighlight=109]="selectionHighlight",e[e.selectOnLineNumbers=110]="selectOnLineNumbers",e[e.showFoldingControls=111]="showFoldingControls",e[e.showUnused=112]="showUnused",e[e.snippetSuggestions=113]="snippetSuggestions",e[e.smartSelect=114]="smartSelect",e[e.smoothScrolling=115]="smoothScrolling",e[e.stickyScroll=116]="stickyScroll",e[e.stickyTabStops=117]="stickyTabStops",e[e.stopRenderingLineAfter=118]="stopRenderingLineAfter",e[e.suggest=119]="suggest",e[e.suggestFontSize=120]="suggestFontSize",e[e.suggestLineHeight=121]="suggestLineHeight",e[e.suggestOnTriggerCharacters=122]="suggestOnTriggerCharacters",e[e.suggestSelection=123]="suggestSelection",e[e.tabCompletion=124]="tabCompletion",e[e.tabIndex=125]="tabIndex",e[e.unicodeHighlighting=126]="unicodeHighlighting",e[e.unusualLineTerminators=127]="unusualLineTerminators",e[e.useShadowDOM=128]="useShadowDOM",e[e.useTabStops=129]="useTabStops",e[e.wordBreak=130]="wordBreak",e[e.wordSegmenterLocales=131]="wordSegmenterLocales",e[e.wordSeparators=132]="wordSeparators",e[e.wordWrap=133]="wordWrap",e[e.wordWrapBreakAfterCharacters=134]="wordWrapBreakAfterCharacters",e[e.wordWrapBreakBeforeCharacters=135]="wordWrapBreakBeforeCharacters",e[e.wordWrapColumn=136]="wordWrapColumn",e[e.wordWrapOverride1=137]="wordWrapOverride1",e[e.wordWrapOverride2=138]="wordWrapOverride2",e[e.wrappingIndent=139]="wrappingIndent",e[e.wrappingStrategy=140]="wrappingStrategy",e[e.showDeprecated=141]="showDeprecated",e[e.inlayHints=142]="inlayHints",e[e.editorClassName=143]="editorClassName",e[e.pixelRatio=144]="pixelRatio",e[e.tabFocusMode=145]="tabFocusMode",e[e.layoutInfo=146]="layoutInfo",e[e.wrappingInfo=147]="wrappingInfo",e[e.defaultColorDecorators=148]="defaultColorDecorators",e[e.colorDecoratorsActivatedOn=149]="colorDecoratorsActivatedOn",e[e.inlineCompletionsAccessibilityVerbose=150]="inlineCompletionsAccessibilityVerbose"}(p||(p={})),function(e){e[e.TextDefined=0]="TextDefined",e[e.LF=1]="LF",e[e.CRLF=2]="CRLF"}(m||(m={})),function(e){e[e.LF=0]="LF",e[e.CRLF=1]="CRLF"}(f||(f={})),function(e){e[e.Left=1]="Left",e[e.Center=2]="Center",e[e.Right=3]="Right"}(_||(_={})),function(e){e[e.Increase=0]="Increase",e[e.Decrease=1]="Decrease"}(v||(v={})),function(e){e[e.None=0]="None",e[e.Indent=1]="Indent",e[e.IndentOutdent=2]="IndentOutdent",e[e.Outdent=3]="Outdent"}(C||(C={})),function(e){e[e.Both=0]="Both",e[e.Right=1]="Right",e[e.Left=2]="Left",e[e.None=3]="None"}(E||(E={})),function(e){e[e.Type=1]="Type",e[e.Parameter=2]="Parameter"}(b||(b={})),function(e){e[e.Automatic=0]="Automatic",e[e.Explicit=1]="Explicit"}(S||(S={})),function(e){e[e.Invoke=0]="Invoke",e[e.Automatic=1]="Automatic"}(y||(y={})),function(e){e[e.DependsOnKbLayout=-1]="DependsOnKbLayout",e[e.Unknown=0]="Unknown",e[e.Backspace=1]="Backspace",e[e.Tab=2]="Tab",e[e.Enter=3]="Enter",e[e.Shift=4]="Shift",e[e.Ctrl=5]="Ctrl",e[e.Alt=6]="Alt",e[e.PauseBreak=7]="PauseBreak",e[e.CapsLock=8]="CapsLock",e[e.Escape=9]="Escape",e[e.Space=10]="Space",e[e.PageUp=11]="PageUp",e[e.PageDown=12]="PageDown",e[e.End=13]="End",e[e.Home=14]="Home",e[e.LeftArrow=15]="LeftArrow",e[e.UpArrow=16]="UpArrow",e[e.RightArrow=17]="RightArrow",e[e.DownArrow=18]="DownArrow",e[e.Insert=19]="Insert",e[e.Delete=20]="Delete",e[e.Digit0=21]="Digit0",e[e.Digit1=22]="Digit1",e[e.Digit2=23]="Digit2",e[e.Digit3=24]="Digit3",e[e.Digit4=25]="Digit4",e[e.Digit5=26]="Digit5",e[e.Digit6=27]="Digit6",e[e.Digit7=28]="Digit7",e[e.Digit8=29]="Digit8",e[e.Digit9=30]="Digit9",e[e.KeyA=31]="KeyA",e[e.KeyB=32]="KeyB",e[e.KeyC=33]="KeyC",e[e.KeyD=34]="KeyD",e[e.KeyE=35]="KeyE",e[e.KeyF=36]="KeyF",e[e.KeyG=37]="KeyG",e[e.KeyH=38]="KeyH",e[e.KeyI=39]="KeyI",e[e.KeyJ=40]="KeyJ",e[e.KeyK=41]="KeyK",e[e.KeyL=42]="KeyL",e[e.KeyM=43]="KeyM",e[e.KeyN=44]="KeyN",e[e.KeyO=45]="KeyO",e[e.KeyP=46]="KeyP",e[e.KeyQ=47]="KeyQ",e[e.KeyR=48]="KeyR",e[e.KeyS=49]="KeyS",e[e.KeyT=50]="KeyT",e[e.KeyU=51]="KeyU",e[e.KeyV=52]="KeyV",e[e.KeyW=53]="KeyW",e[e.KeyX=54]="KeyX",e[e.KeyY=55]="KeyY",e[e.KeyZ=56]="KeyZ",e[e.Meta=57]="Meta",e[e.ContextMenu=58]="ContextMenu",e[e.F1=59]="F1",e[e.F2=60]="F2",e[e.F3=61]="F3",e[e.F4=62]="F4",e[e.F5=63]="F5",e[e.F6=64]="F6",e[e.F7=65]="F7",e[e.F8=66]="F8",e[e.F9=67]="F9",e[e.F10=68]="F10",e[e.F11=69]="F11",e[e.F12=70]="F12",e[e.F13=71]="F13",e[e.F14=72]="F14",e[e.F15=73]="F15",e[e.F16=74]="F16",e[e.F17=75]="F17",e[e.F18=76]="F18",e[e.F19=77]="F19",e[e.F20=78]="F20",e[e.F21=79]="F21",e[e.F22=80]="F22",e[e.F23=81]="F23",e[e.F24=82]="F24",e[e.NumLock=83]="NumLock",e[e.ScrollLock=84]="ScrollLock",e[e.Semicolon=85]="Semicolon",e[e.Equal=86]="Equal",e[e.Comma=87]="Comma",e[e.Minus=88]="Minus",e[e.Period=89]="Period",e[e.Slash=90]="Slash",e[e.Backquote=91]="Backquote",e[e.BracketLeft=92]="BracketLeft",e[e.Backslash=93]="Backslash",e[e.BracketRight=94]="BracketRight",e[e.Quote=95]="Quote",e[e.OEM_8=96]="OEM_8",e[e.IntlBackslash=97]="IntlBackslash",e[e.Numpad0=98]="Numpad0",e[e.Numpad1=99]="Numpad1",e[e.Numpad2=100]="Numpad2",e[e.Numpad3=101]="Numpad3",e[e.Numpad4=102]="Numpad4",e[e.Numpad5=103]="Numpad5",e[e.Numpad6=104]="Numpad6",e[e.Numpad7=105]="Numpad7",e[e.Numpad8=106]="Numpad8",e[e.Numpad9=107]="Numpad9",e[e.NumpadMultiply=108]="NumpadMultiply",e[e.NumpadAdd=109]="NumpadAdd",e[e.NUMPAD_SEPARATOR=110]="NUMPAD_SEPARATOR",e[e.NumpadSubtract=111]="NumpadSubtract",e[e.NumpadDecimal=112]="NumpadDecimal",e[e.NumpadDivide=113]="NumpadDivide",e[e.KEY_IN_COMPOSITION=114]="KEY_IN_COMPOSITION",e[e.ABNT_C1=115]="ABNT_C1",e[e.ABNT_C2=116]="ABNT_C2",e[e.AudioVolumeMute=117]="AudioVolumeMute",e[e.AudioVolumeUp=118]="AudioVolumeUp",e[e.AudioVolumeDown=119]="AudioVolumeDown",e[e.BrowserSearch=120]="BrowserSearch",e[e.BrowserHome=121]="BrowserHome",e[e.BrowserBack=122]="BrowserBack",e[e.BrowserForward=123]="BrowserForward",e[e.MediaTrackNext=124]="MediaTrackNext",e[e.MediaTrackPrevious=125]="MediaTrackPrevious",e[e.MediaStop=126]="MediaStop",e[e.MediaPlayPause=127]="MediaPlayPause",e[e.LaunchMediaPlayer=128]="LaunchMediaPlayer",e[e.LaunchMail=129]="LaunchMail",e[e.LaunchApp2=130]="LaunchApp2",e[e.Clear=131]="Clear",e[e.MAX_VALUE=132]="MAX_VALUE"}(w||(w={})),function(e){e[e.Hint=1]="Hint",e[e.Info=2]="Info",e[e.Warning=4]="Warning",e[e.Error=8]="Error"}(R||(R={})),function(e){e[e.Unnecessary=1]="Unnecessary",e[e.Deprecated=2]="Deprecated"}(L||(L={})),function(e){e[e.Inline=1]="Inline",e[e.Gutter=2]="Gutter"}(T||(T={})),function(e){e[e.Normal=1]="Normal",e[e.Underlined=2]="Underlined"}(x||(x={})),function(e){e[e.UNKNOWN=0]="UNKNOWN",e[e.TEXTAREA=1]="TEXTAREA",e[e.GUTTER_GLYPH_MARGIN=2]="GUTTER_GLYPH_MARGIN",e[e.GUTTER_LINE_NUMBERS=3]="GUTTER_LINE_NUMBERS",e[e.GUTTER_LINE_DECORATIONS=4]="GUTTER_LINE_DECORATIONS",e[e.GUTTER_VIEW_ZONE=5]="GUTTER_VIEW_ZONE",e[e.CONTENT_TEXT=6]="CONTENT_TEXT",e[e.CONTENT_EMPTY=7]="CONTENT_EMPTY",e[e.CONTENT_VIEW_ZONE=8]="CONTENT_VIEW_ZONE",e[e.CONTENT_WIDGET=9]="CONTENT_WIDGET",e[e.OVERVIEW_RULER=10]="OVERVIEW_RULER",e[e.SCROLLBAR=11]="SCROLLBAR",e[e.OVERLAY_WIDGET=12]="OVERLAY_WIDGET",e[e.OUTSIDE_EDITOR=13]="OUTSIDE_EDITOR"}(k||(k={})),function(e){e[e.AIGenerated=1]="AIGenerated"}(A||(A={})),function(e){e[e.Invoke=0]="Invoke",e[e.Automatic=1]="Automatic"}(N||(N={})),function(e){e[e.TOP_RIGHT_CORNER=0]="TOP_RIGHT_CORNER",e[e.BOTTOM_RIGHT_CORNER=1]="BOTTOM_RIGHT_CORNER",e[e.TOP_CENTER=2]="TOP_CENTER"}(I||(I={})),function(e){e[e.Left=1]="Left",e[e.Center=2]="Center",e[e.Right=4]="Right",e[e.Full=7]="Full"}(O||(O={})),function(e){e[e.Word=0]="Word",e[e.Line=1]="Line",e[e.Suggest=2]="Suggest"}(D||(D={})),function(e){e[e.Left=0]="Left",e[e.Right=1]="Right",e[e.None=2]="None",e[e.LeftOfInjectedText=3]="LeftOfInjectedText",e[e.RightOfInjectedText=4]="RightOfInjectedText"}(M||(M={})),function(e){e[e.Off=0]="Off",e[e.On=1]="On",e[e.Relative=2]="Relative",e[e.Interval=3]="Interval",e[e.Custom=4]="Custom"}(P||(P={})),function(e){e[e.None=0]="None",e[e.Text=1]="Text",e[e.Blocks=2]="Blocks"}(F||(F={})),function(e){e[e.Smooth=0]="Smooth",e[e.Immediate=1]="Immediate"}(U||(U={})),function(e){e[e.Auto=1]="Auto",e[e.Hidden=2]="Hidden",e[e.Visible=3]="Visible"}(H||(H={})),function(e){e[e.LTR=0]="LTR",e[e.RTL=1]="RTL"}(B||(B={})),function(e){e.Off="off",e.OnCode="onCode",e.On="on"}(W||(W={})),function(e){e[e.Invoke=1]="Invoke",e[e.TriggerCharacter=2]="TriggerCharacter",e[e.ContentChange=3]="ContentChange"}(V||(V={})),function(e){e[e.File=0]="File",e[e.Module=1]="Module",e[e.Namespace=2]="Namespace",e[e.Package=3]="Package",e[e.Class=4]="Class",e[e.Method=5]="Method",e[e.Property=6]="Property",e[e.Field=7]="Field",e[e.Constructor=8]="Constructor",e[e.Enum=9]="Enum",e[e.Interface=10]="Interface",e[e.Function=11]="Function",e[e.Variable=12]="Variable",e[e.Constant=13]="Constant",e[e.String=14]="String",e[e.Number=15]="Number",e[e.Boolean=16]="Boolean",e[e.Array=17]="Array",e[e.Object=18]="Object",e[e.Key=19]="Key",e[e.Null=20]="Null",e[e.EnumMember=21]="EnumMember",e[e.Struct=22]="Struct",e[e.Event=23]="Event",e[e.Operator=24]="Operator",e[e.TypeParameter=25]="TypeParameter"}(z||(z={})),function(e){e[e.Deprecated=1]="Deprecated"}(G||(G={})),function(e){e[e.Hidden=0]="Hidden",e[e.Blink=1]="Blink",e[e.Smooth=2]="Smooth",e[e.Phase=3]="Phase",e[e.Expand=4]="Expand",e[e.Solid=5]="Solid"}(j||(j={})),function(e){e[e.Line=1]="Line",e[e.Block=2]="Block",e[e.Underline=3]="Underline",e[e.LineThin=4]="LineThin",e[e.BlockOutline=5]="BlockOutline",e[e.UnderlineThin=6]="UnderlineThin"}(K||(K={})),function(e){e[e.AlwaysGrowsWhenTypingAtEdges=0]="AlwaysGrowsWhenTypingAtEdges",e[e.NeverGrowsWhenTypingAtEdges=1]="NeverGrowsWhenTypingAtEdges",e[e.GrowsOnlyWhenTypingBefore=2]="GrowsOnlyWhenTypingBefore",e[e.GrowsOnlyWhenTypingAfter=3]="GrowsOnlyWhenTypingAfter"}(Y||(Y={})),function(e){e[e.None=0]="None",e[e.Same=1]="Same",e[e.Indent=2]="Indent",e[e.DeepIndent=3]="DeepIndent"}(q||(q={}))},35151:(e,t,i)=>{"use strict";i.d(t,{X:()=>C,U:()=>E});var s=i(8597),n=i(56245),r=i(92403),o=i(31295),a=i(25890),c=i(47661),l=i(41234),h=i(5662),d=i(1592),u=i(49353),g=i(631);const p={separatorBorder:c.Q1.transparent};class m{set size(e){this._size=e}get size(){return this._size}get visible(){return"undefined"===typeof this._cachedVisibleSize}setVisible(e,t){if(e!==this.visible){e?(this.size=(0,d.qE)(this._cachedVisibleSize,this.viewMinimumSize,this.viewMaximumSize),this._cachedVisibleSize=void 0):(this._cachedVisibleSize="number"===typeof t?t:this.size,this.size=0),this.container.classList.toggle("visible",e);try{this.view.setVisible?.(e)}catch(i){console.error("Splitview: Failed to set visible view"),console.error(i)}}}get minimumSize(){return this.visible?this.view.minimumSize:0}get viewMinimumSize(){return this.view.minimumSize}get maximumSize(){return this.visible?this.view.maximumSize:0}get viewMaximumSize(){return this.view.maximumSize}get priority(){return this.view.priority}get proportionalLayout(){return this.view.proportionalLayout??!0}get snap(){return!!this.view.snap}set enabled(e){this.container.style.pointerEvents=e?"":"none"}constructor(e,t,i,s){this.container=e,this.view=t,this.disposable=s,this._cachedVisibleSize=void 0,"number"===typeof i?(this._size=i,this._cachedVisibleSize=void 0,e.classList.add("visible")):(this._size=0,this._cachedVisibleSize=i.cachedVisibleSize)}layout(e,t){this.layoutContainer(e);try{this.view.layout(this.size,e,t)}catch(i){console.error("Splitview: Failed to layout view"),console.error(i)}}dispose(){this.disposable.dispose()}}class f extends m{layoutContainer(e){this.container.style.top=`${e}px`,this.container.style.height=`${this.size}px`}}class _ extends m{layoutContainer(e){this.container.style.left=`${e}px`,this.container.style.width=`${this.size}px`}}var v,C;!function(e){e[e.Idle=0]="Idle",e[e.Busy=1]="Busy"}(v||(v={})),function(e){e.Distribute={type:"distribute"},e.Split=function(e){return{type:"split",index:e}},e.Auto=function(e){return{type:"auto",index:e}},e.Invisible=function(e){return{type:"invisible",cachedVisibleSize:e}}}(C||(C={}));class E extends h.jG{get orthogonalStartSash(){return this._orthogonalStartSash}get orthogonalEndSash(){return this._orthogonalEndSash}get startSnappingEnabled(){return this._startSnappingEnabled}get endSnappingEnabled(){return this._endSnappingEnabled}set orthogonalStartSash(e){for(const t of this.sashItems)t.sash.orthogonalStartSash=e;this._orthogonalStartSash=e}set orthogonalEndSash(e){for(const t of this.sashItems)t.sash.orthogonalEndSash=e;this._orthogonalEndSash=e}set startSnappingEnabled(e){this._startSnappingEnabled!==e&&(this._startSnappingEnabled=e,this.updateSashEnablement())}set endSnappingEnabled(e){this._endSnappingEnabled!==e&&(this._endSnappingEnabled=e,this.updateSashEnablement())}constructor(e,t={}){super(),this.size=0,this._contentSize=0,this.proportions=void 0,this.viewItems=[],this.sashItems=[],this.state=v.Idle,this._onDidSashChange=this._register(new l.vl),this._onDidSashReset=this._register(new l.vl),this._startSnappingEnabled=!0,this._endSnappingEnabled=!0,this.onDidSashChange=this._onDidSashChange.event,this.onDidSashReset=this._onDidSashReset.event,this.orientation=t.orientation??0,this.inverseAltBehavior=t.inverseAltBehavior??!1,this.proportionalLayout=t.proportionalLayout??!0,this.getSashOrthogonalSize=t.getSashOrthogonalSize,this.el=document.createElement("div"),this.el.classList.add("monaco-split-view2"),this.el.classList.add(0===this.orientation?"vertical":"horizontal"),e.appendChild(this.el),this.sashContainer=(0,s.BC)(this.el,(0,s.$)(".sash-container")),this.viewContainer=(0,s.$)(".split-view-container"),this.scrollable=this._register(new u.yE({forceIntegerValues:!0,smoothScrollDuration:125,scheduleAtNextAnimationFrame:e=>(0,s.PG)((0,s.zk)(this.el),e)})),this.scrollableElement=this._register(new o.oO(this.viewContainer,{vertical:0===this.orientation?t.scrollbarVisibility??1:2,horizontal:1===this.orientation?t.scrollbarVisibility??1:2},this.scrollable));const i=this._register(new n.f(this.viewContainer,"scroll")).event;this._register(i((e=>{const t=this.scrollableElement.getScrollPosition(),i=Math.abs(this.viewContainer.scrollLeft-t.scrollLeft)<=1?void 0:this.viewContainer.scrollLeft,s=Math.abs(this.viewContainer.scrollTop-t.scrollTop)<=1?void 0:this.viewContainer.scrollTop;void 0===i&&void 0===s||this.scrollableElement.setScrollPosition({scrollLeft:i,scrollTop:s})}))),this.onDidScroll=this.scrollableElement.onScroll,this._register(this.onDidScroll((e=>{e.scrollTopChanged&&(this.viewContainer.scrollTop=e.scrollTop),e.scrollLeftChanged&&(this.viewContainer.scrollLeft=e.scrollLeft)}))),(0,s.BC)(this.el,this.scrollableElement.getDomNode()),this.style(t.styles||p),t.descriptor&&(this.size=t.descriptor.size,t.descriptor.views.forEach(((e,t)=>{const i=g.b0(e.visible)||e.visible?e.size:{type:"invisible",cachedVisibleSize:e.size},s=e.view;this.doAddView(s,i,t,!0)})),this._contentSize=this.viewItems.reduce(((e,t)=>e+t.size),0),this.saveProportions())}style(e){e.separatorBorder.isTransparent()?(this.el.classList.remove("separator-border"),this.el.style.removeProperty("--separator-border")):(this.el.classList.add("separator-border"),this.el.style.setProperty("--separator-border",e.separatorBorder.toString()))}addView(e,t,i=this.viewItems.length,s){this.doAddView(e,t,i,s)}layout(e,t){const i=Math.max(this.size,this._contentSize);if(this.size=e,this.layoutContext=t,this.proportions){let t=0;for(let i=0;i0&&(s.size=(0,d.qE)(Math.round(n*e/t),s.minimumSize,s.maximumSize))}}else{const t=(0,a.y1)(this.viewItems.length),s=t.filter((e=>1===this.viewItems[e].priority)),n=t.filter((e=>2===this.viewItems[e].priority));this.resize(this.viewItems.length-1,e-i,void 0,s,n)}this.distributeEmptySpace(),this.layoutViews()}saveProportions(){this.proportionalLayout&&this._contentSize>0&&(this.proportions=this.viewItems.map((e=>e.proportionalLayout&&e.visible?e.size/this._contentSize:void 0)))}onSashStart({sash:e,start:t,alt:i}){for(const s of this.viewItems)s.enabled=!1;const n=this.sashItems.findIndex((t=>t.sash===e)),r=(0,h.qE)((0,s.ko)(this.el.ownerDocument.body,"keydown",(e=>o(this.sashDragState.current,e.altKey))),(0,s.ko)(this.el.ownerDocument.body,"keyup",(()=>o(this.sashDragState.current,!1)))),o=(e,t)=>{const i=this.viewItems.map((e=>e.size));let s,o,c=Number.NEGATIVE_INFINITY,l=Number.POSITIVE_INFINITY;if(this.inverseAltBehavior&&(t=!t),t){if(n===this.sashItems.length-1){const e=this.viewItems[n];c=(e.minimumSize-e.size)/2,l=(e.maximumSize-e.size)/2}else{const e=this.viewItems[n+1];c=(e.size-e.maximumSize)/2,l=(e.size-e.minimumSize)/2}}if(!t){const e=(0,a.y1)(n,-1),t=(0,a.y1)(n+1,this.viewItems.length),r=e.reduce(((e,t)=>e+(this.viewItems[t].minimumSize-i[t])),0),c=e.reduce(((e,t)=>e+(this.viewItems[t].viewMaximumSize-i[t])),0),l=0===t.length?Number.POSITIVE_INFINITY:t.reduce(((e,t)=>e+(i[t]-this.viewItems[t].minimumSize)),0),h=0===t.length?Number.NEGATIVE_INFINITY:t.reduce(((e,t)=>e+(i[t]-this.viewItems[t].viewMaximumSize)),0),d=Math.max(r,h),u=Math.min(l,c),g=this.findFirstSnapIndex(e),p=this.findFirstSnapIndex(t);if("number"===typeof g){const e=this.viewItems[g],t=Math.floor(e.viewMinimumSize/2);s={index:g,limitDelta:e.visible?d-t:d+t,size:e.size}}if("number"===typeof p){const e=this.viewItems[p],t=Math.floor(e.viewMinimumSize/2);o={index:p,limitDelta:e.visible?u+t:u-t,size:e.size}}}this.sashDragState={start:e,current:e,index:n,sizes:i,minDelta:c,maxDelta:l,alt:t,snapBefore:s,snapAfter:o,disposable:r}};o(t,i)}onSashChange({current:e}){const{index:t,start:i,sizes:s,alt:n,minDelta:r,maxDelta:o,snapBefore:a,snapAfter:c}=this.sashDragState;this.sashDragState.current=e;const l=e-i,h=this.resize(t,l,s,void 0,void 0,r,o,a,c);if(n){const e=t===this.sashItems.length-1,i=this.viewItems.map((e=>e.size)),s=e?t:t+1,n=this.viewItems[s],r=n.size-n.maximumSize,o=n.size-n.minimumSize,a=e?t-1:t+1;this.resize(a,-h,i,void 0,void 0,r,o)}this.distributeEmptySpace(),this.layoutViews()}onSashEnd(e){this._onDidSashChange.fire(e),this.sashDragState.disposable.dispose(),this.saveProportions();for(const t of this.viewItems)t.enabled=!0}onViewChange(e,t){const i=this.viewItems.indexOf(e);i<0||i>=this.viewItems.length||(t="number"===typeof t?t:e.size,t=(0,d.qE)(t,e.minimumSize,e.maximumSize),this.inverseAltBehavior&&i>0?(this.resize(i-1,Math.floor((e.size-t)/2)),this.distributeEmptySpace(),this.layoutViews()):(e.size=t,this.relayout([i],void 0)))}resizeView(e,t){if(!(e<0||e>=this.viewItems.length)){if(this.state!==v.Idle)throw new Error("Cant modify splitview");this.state=v.Busy;try{const i=(0,a.y1)(this.viewItems.length).filter((t=>t!==e)),s=[...i.filter((e=>1===this.viewItems[e].priority)),e],n=i.filter((e=>2===this.viewItems[e].priority)),r=this.viewItems[e];t=Math.round(t),t=(0,d.qE)(t,r.minimumSize,Math.min(r.maximumSize,this.size)),r.size=t,this.relayout(s,n)}finally{this.state=v.Idle}}}distributeViewSizes(){const e=[];let t=0;for(const o of this.viewItems)o.maximumSize-o.minimumSize>0&&(e.push(o),t+=o.size);const i=Math.floor(t/e.length);for(const o of e)o.size=(0,d.qE)(i,o.minimumSize,o.maximumSize);const s=(0,a.y1)(this.viewItems.length),n=s.filter((e=>1===this.viewItems[e].priority)),r=s.filter((e=>2===this.viewItems[e].priority));this.relayout(n,r)}getViewSize(e){return e<0||e>=this.viewItems.length?-1:this.viewItems[e].size}doAddView(e,t,i=this.viewItems.length,n){if(this.state!==v.Idle)throw new Error("Cant modify splitview");this.state=v.Busy;try{const o=(0,s.$)(".split-view-view");i===this.viewItems.length?this.viewContainer.appendChild(o):this.viewContainer.insertBefore(o,this.viewContainer.children.item(i));const c=e.onDidChange((e=>this.onViewChange(p,e))),d=(0,h.s)((()=>o.remove())),u=(0,h.qE)(c,d);let g;"number"===typeof t?g=t:("auto"===t.type&&(t=this.areViewsDistributed()?{type:"distribute"}:{type:"split",index:t.index}),g="split"===t.type?this.getViewSize(t.index)/2:"invisible"===t.type?{cachedVisibleSize:t.cachedVisibleSize}:e.minimumSize);const p=0===this.orientation?new f(o,e,g,u):new _(o,e,g,u);if(this.viewItems.splice(i,0,p),this.viewItems.length>1){const e={orthogonalStartSash:this.orthogonalStartSash,orthogonalEndSash:this.orthogonalEndSash},t=0===this.orientation?new r.m(this.sashContainer,{getHorizontalSashTop:e=>this.getSashPosition(e),getHorizontalSashWidth:this.getSashOrthogonalSize},{...e,orientation:1}):new r.m(this.sashContainer,{getVerticalSashLeft:e=>this.getSashPosition(e),getVerticalSashHeight:this.getSashOrthogonalSize},{...e,orientation:0}),s=0===this.orientation?e=>({sash:t,start:e.startY,current:e.currentY,alt:e.altKey}):e=>({sash:t,start:e.startX,current:e.currentX,alt:e.altKey}),n=l.Jh.map(t.onDidStart,s)(this.onSashStart,this),o=l.Jh.map(t.onDidChange,s)(this.onSashChange,this),c=l.Jh.map(t.onDidEnd,(()=>this.sashItems.findIndex((e=>e.sash===t)))),d=c(this.onSashEnd,this),u=t.onDidReset((()=>{const e=this.sashItems.findIndex((e=>e.sash===t)),i=(0,a.y1)(e,-1),s=(0,a.y1)(e+1,this.viewItems.length),n=this.findFirstSnapIndex(i),r=this.findFirstSnapIndex(s);("number"!==typeof n||this.viewItems[n].visible)&&("number"!==typeof r||this.viewItems[r].visible)&&this._onDidSashReset.fire(e)})),g=(0,h.qE)(n,o,d,u,t),p={sash:t,disposable:g};this.sashItems.splice(i-1,0,p)}let m;o.appendChild(e.element),"number"!==typeof t&&"split"===t.type&&(m=[t.index]),n||this.relayout([i],m),n||"number"===typeof t||"distribute"!==t.type||this.distributeViewSizes()}finally{this.state=v.Idle}}relayout(e,t){const i=this.viewItems.reduce(((e,t)=>e+t.size),0);this.resize(this.viewItems.length-1,this.size-i,void 0,e,t),this.distributeEmptySpace(),this.layoutViews(),this.saveProportions()}resize(e,t,i=this.viewItems.map((e=>e.size)),s,n,r=Number.NEGATIVE_INFINITY,o=Number.POSITIVE_INFINITY,c,l){if(e<0||e>=this.viewItems.length)return 0;const h=(0,a.y1)(e,-1),u=(0,a.y1)(e+1,this.viewItems.length);if(n)for(const d of n)(0,a._A)(h,d),(0,a._A)(u,d);if(s)for(const d of s)(0,a.r7)(h,d),(0,a.r7)(u,d);const g=h.map((e=>this.viewItems[e])),p=h.map((e=>i[e])),m=u.map((e=>this.viewItems[e])),f=u.map((e=>i[e])),_=h.reduce(((e,t)=>e+(this.viewItems[t].minimumSize-i[t])),0),v=h.reduce(((e,t)=>e+(this.viewItems[t].maximumSize-i[t])),0),C=0===u.length?Number.POSITIVE_INFINITY:u.reduce(((e,t)=>e+(i[t]-this.viewItems[t].minimumSize)),0),E=0===u.length?Number.NEGATIVE_INFINITY:u.reduce(((e,t)=>e+(i[t]-this.viewItems[t].maximumSize)),0),b=Math.max(_,E,r),S=Math.min(C,v,o);let y=!1;if(c){const e=this.viewItems[c.index],i=t>=c.limitDelta;y=i!==e.visible,e.setVisible(i,c.size)}if(!y&&l){const e=this.viewItems[l.index],i=te+t.size),0);let i=this.size-t;const s=(0,a.y1)(this.viewItems.length-1,-1),n=s.filter((e=>1===this.viewItems[e].priority)),r=s.filter((e=>2===this.viewItems[e].priority));for(const o of r)(0,a._A)(s,o);for(const o of n)(0,a.r7)(s,o);"number"===typeof e&&(0,a.r7)(s,e);for(let o=0;0!==i&&oe+t.size),0);let e=0;for(const t of this.viewItems)t.layout(e,this.layoutContext),e+=t.size;this.sashItems.forEach((e=>e.sash.layout())),this.updateSashEnablement(),this.updateScrollableElement()}updateScrollableElement(){0===this.orientation?this.scrollableElement.setScrollDimensions({height:this.size,scrollHeight:this._contentSize}):this.scrollableElement.setScrollDimensions({width:this.size,scrollWidth:this._contentSize})}updateSashEnablement(){let e=!1;const t=this.viewItems.map((t=>e=t.size-t.minimumSize>0||e));e=!1;const i=this.viewItems.map((t=>e=t.maximumSize-t.size>0||e)),s=[...this.viewItems].reverse();e=!1;const n=s.map((t=>e=t.size-t.minimumSize>0||e)).reverse();e=!1;const r=s.map((t=>e=t.maximumSize-t.size>0||e)).reverse();let o=0;for(let c=0;c0||this.startSnappingEnabled)?e.state=1:d&&t[c]&&(o0)return;if(!e.visible&&e.snap)return t}}areViewsDistributed(){let e,t;for(const i of this.viewItems)if(e=void 0===e?i.size:Math.min(e,i.size),t=void 0===t?i.size:Math.max(t,i.size),t-e>2)return!1;return!0}dispose(){this.sashDragState?.disposable.dispose(),(0,h.AS)(this.viewItems),this.viewItems=[],this.sashItems.forEach((e=>e.disposable.dispose())),this.sashItems=[],super.dispose()}}},35315:(e,t,i)=>{"use strict";i.d(t,{l:()=>l,F:()=>c});var s=i(17390),n=i(25689),r=i(41234),o=i(42904),a=i(48196);const c={inputActiveOptionBorder:"#007ACC00",inputActiveOptionForeground:"#FFFFFF",inputActiveOptionBackground:"#0E639C50"};class l extends s.x{constructor(e){super(),this._onChange=this._register(new r.vl),this.onChange=this._onChange.event,this._onKeyDown=this._register(new r.vl),this.onKeyDown=this._onKeyDown.event,this._opts=e,this._checked=this._opts.isChecked;const t=["monaco-custom-toggle"];this._opts.icon&&(this._icon=this._opts.icon,t.push(...n.L.asClassNameArray(this._icon))),this._opts.actionClassName&&t.push(...this._opts.actionClassName.split(" ")),this._checked&&t.push("checked"),this.domNode=document.createElement("div"),this._hover=this._register((0,a.i)().setupManagedHover(e.hoverDelegate??(0,o.nZ)("mouse"),this.domNode,this._opts.title)),this.domNode.classList.add(...t),this._opts.notFocusable||(this.domNode.tabIndex=0),this.domNode.setAttribute("role","checkbox"),this.domNode.setAttribute("aria-checked",String(this._checked)),this.domNode.setAttribute("aria-label",this._opts.title),this.applyStyles(),this.onclick(this.domNode,(e=>{this.enabled&&(this.checked=!this._checked,this._onChange.fire(!1),e.preventDefault())})),this._register(this.ignoreGesture(this.domNode)),this.onkeydown(this.domNode,(e=>{if(10===e.keyCode||3===e.keyCode)return this.checked=!this._checked,this._onChange.fire(!0),e.preventDefault(),void e.stopPropagation();this._onKeyDown.fire(e)}))}get enabled(){return"true"!==this.domNode.getAttribute("aria-disabled")}focus(){this.domNode.focus()}get checked(){return this._checked}set checked(e){this._checked=e,this.domNode.setAttribute("aria-checked",String(this._checked)),this.domNode.classList.toggle("checked",this._checked),this.applyStyles()}width(){return 22}applyStyles(){this.domNode&&(this.domNode.style.borderColor=this._checked&&this._opts.inputActiveOptionBorder||"",this.domNode.style.color=this._checked&&this._opts.inputActiveOptionForeground||"inherit",this.domNode.style.backgroundColor=this._checked&&this._opts.inputActiveOptionBackground||"")}enable(){this.domNode.setAttribute("aria-disabled",String(!1))}disable(){this.domNode.setAttribute("aria-disabled",String(!0))}}},35600:(e,t,i)=>{"use strict";i.d(t,{wZ:()=>h,MT:()=>c,zL:()=>l,UW:()=>g,Md:()=>m});var s=i(78209),n=i(91508),r=i(99020),o=i(25521);class a{constructor(e,t,i,s){this.endIndex=e,this.type=t,this.metadata=i,this.containsRTL=s,this._linePartBrand=void 0}isWhitespace(){return!!(1&this.metadata)}isPseudoAfter(){return!!(4&this.metadata)}}class c{constructor(e,t){this.startOffset=e,this.endOffset=t}equals(e){return this.startOffset===e.startOffset&&this.endOffset===e.endOffset}}class l{constructor(e,t,i,s,n,r,a,c,l,h,d,u,g,p,m,f,_,v,C){this.useMonospaceOptimizations=e,this.canUseHalfwidthRightwardsArrow=t,this.lineContent=i,this.continuesWithWrappedLine=s,this.isBasicASCII=n,this.containsRTL=r,this.fauxIndentLength=a,this.lineTokens=c,this.lineDecorations=l.sort(o.d.compare),this.tabSize=h,this.startVisibleColumn=d,this.spaceWidth=u,this.stopRenderingLineAfter=m,this.renderWhitespace="all"===f?4:"boundary"===f?1:"selection"===f?2:"trailing"===f?3:0,this.renderControlCharacters=_,this.fontLigatures=v,this.selectionsOnLine=C&&C.sort(((e,t)=>e.startOffset>>16}static getCharIndex(e){return(65535&e)>>>0}constructor(e,t){this.length=e,this._data=new Uint32Array(this.length),this._horizontalOffset=new Uint32Array(this.length)}setColumnInfo(e,t,i,s){const n=(t<<16|i)>>>0;this._data[e-1]=n,this._horizontalOffset[e-1]=s}getHorizontalOffset(e){return 0===this._horizontalOffset.length?0:this._horizontalOffset[e-1]}charOffsetToPartData(e){return 0===this.length?0:e<0?this._data[0]:e>=this.length?this._data[this.length-1]:this._data[e]}getDomPosition(e){const t=this.charOffsetToPartData(e-1),i=d.getPartIndex(t),s=d.getCharIndex(t);return new h(i,s)}getColumn(e,t){return this.partDataToCharOffset(e.partIndex,t,e.charIndex)+1}partDataToCharOffset(e,t,i){if(0===this.length)return 0;const s=(e<<16|i)>>>0;let n=0,r=this.length-1;for(;n+1>>1,t=this._data[e];if(t===s)return e;t>s?r=e:n=e}if(n===r)return n;const o=this._data[n],a=this._data[r];if(o===s)return n;if(a===s)return r;const c=d.getPartIndex(o),l=d.getCharIndex(o);let h;h=c!==d.getPartIndex(a)?t:d.getCharIndex(a);return i-l<=h-i?n:r}}class u{constructor(e,t,i){this._renderLineOutputBrand=void 0,this.characterMapping=e,this.containsRTL=t,this.containsForeignElements=i}}function g(e,t){if(0===e.lineContent.length){if(e.lineDecorations.length>0){t.appendString("");let i=0,s=0,n=0;for(const o of e.lineDecorations)1!==o.type&&2!==o.type||(t.appendString(''),1===o.type&&(n|=1,i++),2===o.type&&(n|=2,s++));t.appendString("");const r=new d(1,i+s);return r.setColumnInfo(1,i,0,0),new u(r,!1,n)}return t.appendString(""),new u(new d(0,0),!1,0)}return function(e,t){const i=e.fontIsMonospace,r=e.canUseHalfwidthRightwardsArrow,o=e.containsForeignElements,a=e.lineContent,c=e.len,l=e.isOverflowing,h=e.overflowingCharCount,g=e.parts,p=e.fauxIndentLength,m=e.tabSize,f=e.startVisibleColumn,C=e.containsRTL,E=e.spaceWidth,b=e.renderSpaceCharCode,S=e.renderWhitespace,y=e.renderControlCharacters,w=new d(c+1,g.length);let R=!1,L=0,T=f,x=0,k=0,A=0;C?t.appendString(''):t.appendString("");for(let s=0,d=g.length;s=p&&(i+=s)}}for(f&&(t.appendString(' style="width:'),t.appendString(String(E*e)),t.appendString('px"')),t.appendASCIICharCode(62);L1?t.appendCharCode(8594):t.appendCharCode(65515);for(let e=2;e<=i;e++)t.appendCharCode(160)}else e=2,i=1,t.appendCharCode(b),t.appendCharCode(8204);x+=e,k+=i,L>=p&&(T+=i)}}else for(t.appendASCIICharCode(62);L=p&&(T+=r)}C?A++:A=0,L>=c&&!R&&e.isPseudoAfter()&&(R=!0,w.setColumnInfo(L+1,s,x,k)),t.appendString("")}R||w.setColumnInfo(c+1,g.length-1,x,k);l&&(t.appendString(''),t.appendString(s.kg("showMore","Show more ({0})",function(e){if(e<1024)return s.kg("overflow.chars","{0} chars",e);if(e<1048576)return`${(e/1024).toFixed(1)} KB`;return`${(e/1024/1024).toFixed(1)} MB`}(h))),t.appendString(""));return t.appendString(""),new u(w,C,o)}(function(e){const t=e.lineContent;let i,s,r;-1!==e.stopRenderingLineAfter&&e.stopRenderingLineAfter0&&(o[c++]=new a(s,"",0,!1));let l=s;for(let h=0,d=i.getCount();h=r){const i=!!t&&n.E_(e.substring(l,r));o[c++]=new a(r,u,0,i);break}const g=!!t&&n.E_(e.substring(l,d));o[c++]=new a(d,u,0,g),l=d}return o}(t,e.containsRTL,e.lineTokens,e.fauxIndentLength,r);e.renderControlCharacters&&!e.isBasicASCII&&(c=function(e,t){const i=[];let s=new a(0,"",0,!1),n=0;for(const r of t){const t=r.endIndex;for(;ns.endIndex&&(s=new a(n,r.type,r.metadata,r.containsRTL),i.push(s)),s=new a(n+1,"mtkcontrol",r.metadata,!1),i.push(s))}n>s.endIndex&&(s=new a(t,r.type,r.metadata,r.containsRTL),i.push(s))}return i}(t,c));(4===e.renderWhitespace||1===e.renderWhitespace||2===e.renderWhitespace&&e.selectionsOnLine||3===e.renderWhitespace&&!e.continuesWithWrappedLine)&&(c=function(e,t,i,s){const r=e.continuesWithWrappedLine,o=e.fauxIndentLength,c=e.tabSize,l=e.startVisibleColumn,h=e.useMonospaceOptimizations,d=e.selectionsOnLine,u=1===e.renderWhitespace,g=3===e.renderWhitespace,p=e.renderSpaceWidth!==e.spaceWidth,m=[];let f=0,_=0,v=s[_].type,C=s[_].containsRTL,E=s[_].endIndex;const b=s.length;let S,y=!1,w=n.HG(t);-1===w?(y=!0,w=i,S=i):S=n.lT(t);let R=!1,L=0,T=d&&d[L],x=l%c;for(let A=o;A=T.endOffset&&(L++,T=d&&d[L]),AS)r=!0;else if(9===e)r=!0;else if(32===e)if(u)if(R)r=!0;else{const e=A+1A),r&&g&&(r=y||A>S),r&&C&&A>=w&&A<=S&&(r=!1),R){if(!r||!h&&x>=c){if(p){for(let e=(f>0?m[f-1].endIndex:o)+1;e<=A;e++)m[f++]=new a(e,"mtkw",1,!1)}else m[f++]=new a(A,"mtkw",1,!1);x%=c}}else(A===E||r&&A>o)&&(m[f++]=new a(A,v,0,C),x%=c);for(9===e?x=c:n.ne(e)?x+=2:x++,R=r;A===E&&(_++,_0?t.charCodeAt(i-1):0,s=i>1?t.charCodeAt(i-2):0;32===e&&32!==s&&9!==s||(k=!0)}else k=!0;if(k)if(p){for(let e=(f>0?m[f-1].endIndex:o)+1;e<=i;e++)m[f++]=new a(e,"mtkw",1,!1)}else m[f++]=new a(i,"mtkw",1,!1);else m[f++]=new a(i,v,0,C);return m}(e,t,r,c));let l=0;if(e.lineDecorations.length>0){for(let t=0,i=e.lineDecorations.length;td&&(d=e.startOffset,l[h++]=new a(d,s,u,g)),!(e.endOffset+1<=t)){d=t,l[h++]=new a(d,s+" "+e.className,u|e.metadata,g);break}d=e.endOffset+1,l[h++]=new a(d,s+" "+e.className,u|e.metadata,g),c++}t>d&&(d=t,l[h++]=new a(d,s,u,g))}const u=i[i.length-1].endIndex;if(c=50&&(n[r++]=new a(h+1,t,o,l),d=h+1,h=-1);d!==c&&(n[r++]=new a(c,t,o,l))}else n[r++]=i;s=c}else for(let o=0,c=t.length;o50){const t=e.type,o=e.metadata,l=e.containsRTL,h=Math.ceil(c/50);for(let e=1;e=8234&&e<=8238||e>=8294&&e<=8297||e>=8206&&e<=8207||1564===e)}function v(e){return e.toString(16).toUpperCase().padStart(4,"0")}},35762:(e,t,i)=>{e.exports=function(e){const t=i(94297),s=i(76319)(e);function n(e,i,n){let r="";const o=e.$value,a=o.length;return t.drawFullView(a,i)?(r+="{"+t.getIndent(i,n),r+=s(o,i,n),r+=t.getIndent(i,n-1)+"}"):t.drawCompactView(a,i)?(r+="{",r+=s(o,i,n),r+="}"):r+="{}",r}return n.isScalar=!0,n}},35817:(e,t,i)=>{"use strict";i.d(t,{s:()=>n});var s=i(1245);class n{static whitespaceVisibleColumn(e,t,i){const n=e.length;let r=0,o=-1,a=-1;for(let c=0;c{"use strict";(0,i(34918).K)({id:"st",extensions:[".st",".iecst",".iecplc",".lc3lib",".TcPOU",".TcDUT",".TcGVL",".TcIO"],aliases:["StructuredText","scl","stl"],loader:()=>i.e(43702).then(i.bind(i,43702))})},36317:e=>{e.exports=function(){function e(e){return e.$value}return e.isScalar=!0,e}},36456:(e,t,i)=>{"use strict";i.d(t,{Ez:()=>d,SJ:()=>p,fV:()=>h,ny:()=>s,v$:()=>l,zl:()=>g});var s,n=i(64383),r=i(98067),o=i(91508),a=i(79400),c=i(74027);function l(e,t){return a.r.isUri(e)?(0,o.Q_)(e.scheme,t):(0,o.ns)(e,t+":")}function h(e,...t){return t.some((t=>l(e,t)))}!function(e){e.inMemory="inmemory",e.vscode="vscode",e.internal="private",e.walkThrough="walkThrough",e.walkThroughSnippet="walkThroughSnippet",e.http="http",e.https="https",e.file="file",e.mailto="mailto",e.untitled="untitled",e.data="data",e.command="command",e.vscodeRemote="vscode-remote",e.vscodeRemoteResource="vscode-remote-resource",e.vscodeManagedRemoteResource="vscode-managed-remote-resource",e.vscodeUserData="vscode-userdata",e.vscodeCustomEditor="vscode-custom-editor",e.vscodeNotebookCell="vscode-notebook-cell",e.vscodeNotebookCellMetadata="vscode-notebook-cell-metadata",e.vscodeNotebookCellMetadataDiff="vscode-notebook-cell-metadata-diff",e.vscodeNotebookCellOutput="vscode-notebook-cell-output",e.vscodeNotebookCellOutputDiff="vscode-notebook-cell-output-diff",e.vscodeNotebookMetadata="vscode-notebook-metadata",e.vscodeInteractiveInput="vscode-interactive-input",e.vscodeSettings="vscode-settings",e.vscodeWorkspaceTrust="vscode-workspace-trust",e.vscodeTerminal="vscode-terminal",e.vscodeChatCodeBlock="vscode-chat-code-block",e.vscodeChatCodeCompareBlock="vscode-chat-code-compare-block",e.vscodeChatSesssion="vscode-chat-editor",e.webviewPanel="webview-panel",e.vscodeWebview="vscode-webview",e.extension="extension",e.vscodeFileResource="vscode-file",e.tmp="tmp",e.vsls="vsls",e.vscodeSourceControl="vscode-scm",e.commentsInput="comment",e.codeSetting="code-setting",e.outputChannel="output"}(s||(s={}));const d=new class{constructor(){this._hosts=Object.create(null),this._ports=Object.create(null),this._connectionTokens=Object.create(null),this._preferredWebSchema="http",this._delegate=null,this._serverRootPath="/"}setPreferredWebSchema(e){this._preferredWebSchema=e}get _remoteResourcesPath(){return c.SA.join(this._serverRootPath,s.vscodeRemoteResource)}rewrite(e){if(this._delegate)try{return this._delegate(e)}catch(h){return n.dz(h),e}const t=e.authority;let i=this._hosts[t];i&&-1!==i.indexOf(":")&&-1===i.indexOf("[")&&(i=`[${i}]`);const o=this._ports[t],c=this._connectionTokens[t];let l=`path=${encodeURIComponent(e.path)}`;return"string"===typeof c&&(l+=`&tkn=${encodeURIComponent(c)}`),a.r.from({scheme:r.HZ?this._preferredWebSchema:s.vscodeRemoteResource,authority:`${i}:${o}`,path:this._remoteResourcesPath,query:l})}};class u{static{this.FALLBACK_AUTHORITY="vscode-app"}asBrowserUri(e){const t=this.toUri(e);return this.uriToBrowserUri(t)}uriToBrowserUri(e){return e.scheme===s.vscodeRemote?d.rewrite(e):e.scheme!==s.file||!r.ib&&r.lg!==`${s.vscodeFileResource}://${u.FALLBACK_AUTHORITY}`?e:e.with({scheme:s.vscodeFileResource,authority:e.authority||u.FALLBACK_AUTHORITY,query:null,fragment:null})}toUri(e,t){if(a.r.isUri(e))return e;if(globalThis._VSCODE_FILE_ROOT){const t=globalThis._VSCODE_FILE_ROOT;if(/^\w[\w\d+.-]*:\/\//.test(t))return a.r.joinPath(a.r.parse(t,!0),e);const i=c.fj(t,e);return a.r.file(i)}return a.r.parse(t.toUrl(e))}}const g=new u;var p;!function(e){const t=new Map([["1",{"Cross-Origin-Opener-Policy":"same-origin"}],["2",{"Cross-Origin-Embedder-Policy":"require-corp"}],["3",{"Cross-Origin-Opener-Policy":"same-origin","Cross-Origin-Embedder-Policy":"require-corp"}]]);e.CoopAndCoep=Object.freeze(t.get("3"));const i="vscode-coi";e.getHeadersFromQuery=function(e){let s;"string"===typeof e?s=new URL(e).searchParams:e instanceof URL?s=e.searchParams:a.r.isUri(e)&&(s=new URL(e.toString(!0)).searchParams);const n=s?.get(i);if(n)return t.get(n)},e.addSearchParam=function(e,t,s){if(!globalThis.crossOriginIsolated)return;const n=t&&s?"3":s?"2":"1";e instanceof URLSearchParams?e.set(i,n):e[i]=n}}(p||(p={}))},36584:(e,t,i)=>{"use strict";i.d(t,{PE:()=>Ce,aG:()=>Ee,er:()=>ft,YD:()=>Re,zL:()=>gt,Nf:()=>Ne,cH:()=>Oe});var s=i(8597),n=i(25890),r=i(18447),o=i(41234),a=i(5662),c=(i(48215),i(93090));class l{get templateId(){return this.renderer.templateId}constructor(e,t){this.renderer=e,this.modelProvider=t}renderTemplate(e){return{data:this.renderer.renderTemplate(e),disposable:a.jG.None}}renderElement(e,t,i,s){if(i.disposable?.dispose(),!i.data)return;const n=this.modelProvider();if(n.isResolved(e))return this.renderer.renderElement(n.get(e),e,i.data,s);const o=new r.Qi,a=n.resolve(e,o.token);i.disposable={dispose:()=>o.cancel()},this.renderer.renderPlaceholder(e,i.data),a.then((t=>this.renderer.renderElement(t,e,i.data,s)))}disposeTemplate(e){e.disposable&&(e.disposable.dispose(),e.disposable=void 0),e.data&&(this.renderer.disposeTemplate(e.data),e.data=void 0)}}class h{constructor(e,t){this.modelProvider=e,this.accessibilityProvider=t}getWidgetAriaLabel(){return this.accessibilityProvider.getWidgetAriaLabel()}getAriaLabel(e){const t=this.modelProvider();return t.isResolved(e)?this.accessibilityProvider.getAriaLabel(t.get(e)):null}}class d{constructor(e,t,i,s,n={}){const r=()=>this.model,o=s.map((e=>new l(e,r)));this.list=new c.B8(e,t,i,o,function(e,t){return{...t,accessibilityProvider:t.accessibilityProvider&&new h(e,t.accessibilityProvider)}}(r,n))}updateOptions(e){this.list.updateOptions(e)}getHTMLElement(){return this.list.getHTMLElement()}get onDidFocus(){return this.list.onDidFocus}get widget(){return this.list}get onDidDispose(){return this.list.onDidDispose}get onMouseDblClick(){return o.Jh.map(this.list.onMouseDblClick,(({element:e,index:t,browserEvent:i})=>({element:void 0===e?void 0:this._model.get(e),index:t,browserEvent:i})))}get onPointer(){return o.Jh.map(this.list.onPointer,(({element:e,index:t,browserEvent:i})=>({element:void 0===e?void 0:this._model.get(e),index:t,browserEvent:i})))}get onDidChangeSelection(){return o.Jh.map(this.list.onDidChangeSelection,(({elements:e,indexes:t,browserEvent:i})=>({elements:e.map((e=>this._model.get(e))),indexes:t,browserEvent:i})))}get model(){return this._model}set model(e){this._model=e,this.list.splice(0,this.list.length,(0,n.y1)(e.length))}getFocus(){return this.list.getFocus()}getSelection(){return this.list.getSelection()}getSelectedElements(){return this.getSelection().map((e=>this.model.get(e)))}style(e){this.list.style(e)}dispose(){this.list.dispose()}}var u=i(48196),g=i(42904),p=i(35151);class m{static{this.TemplateId="row"}constructor(e,t,i){this.columns=e,this.getColumnSize=i,this.templateId=m.TemplateId,this.renderedTemplates=new Set;const s=new Map(t.map((e=>[e.templateId,e])));this.renderers=[];for(const n of e){const e=s.get(n.templateId);if(!e)throw new Error(`Table cell renderer for template id ${n.templateId} not found.`);this.renderers.push(e)}}renderTemplate(e){const t=(0,s.BC)(e,(0,s.$)(".monaco-table-tr")),i=[],n=[];for(let o=0;othis.disposables.add(new f(e,t)))),d={size:h.reduce(((e,t)=>e+t.column.weight),0),views:h.map((e=>({size:e.column.weight,view:e})))};this.splitview=this.disposables.add(new p.U(this.domNode,{orientation:1,scrollbarVisibility:2,getSashOrthogonalSize:()=>this.cachedHeight,descriptor:d})),this.splitview.el.style.height=`${i.headerRowHeight}px`,this.splitview.el.style.lineHeight=`${i.headerRowHeight}px`;const u=new m(n,r,(e=>this.splitview.getViewSize(e)));var g;this.list=this.disposables.add(new c.B8(e,this.domNode,(g=i,{getHeight:e=>g.getHeight(e),getTemplateId:()=>m.TemplateId}),[u],l)),o.Jh.any(...h.map((e=>e.onDidLayout)))((([e,t])=>u.layoutColumn(e,t)),null,this.disposables),this.splitview.onDidSashReset((e=>{const t=n.reduce(((e,t)=>e+t.weight),0),i=n[e].weight/t*this.cachedWidth;this.splitview.resizeView(e,i)}),null,this.disposables),this.styleElement=(0,s.li)(this.domNode),this.style(c.bG)}updateOptions(e){this.list.updateOptions(e)}splice(e,t,i=[]){this.list.splice(e,t,i)}getHTMLElement(){return this.domNode}style(e){const t=[];t.push(`.monaco-table.${this.domId} > .monaco-split-view2 .monaco-sash.vertical::before {\n\t\t\ttop: ${this.virtualDelegate.headerRowHeight+1}px;\n\t\t\theight: calc(100% - ${this.virtualDelegate.headerRowHeight}px);\n\t\t}`),this.styleElement.textContent=t.join("\n"),this.list.style(e)}getSelectedElements(){return this.list.getSelectedElements()}getSelection(){return this.list.getSelection()}getFocus(){return this.list.getFocus()}dispose(){this.disposables.dispose()}}var v=i(19466),C=i(66700),E=i(37472),b=i(84565),S=i(42522);class y{constructor(e,t,i={}){this.user=e,this.rootRef=null,this.nodes=new Map,this.nodesByIdentity=new Map,this.model=new E.G6(e,t,null,i),this.onDidSplice=this.model.onDidSplice,this.onDidChangeCollapseState=this.model.onDidChangeCollapseState,this.onDidChangeRenderNodeCount=this.model.onDidChangeRenderNodeCount,i.sorter&&(this.sorter={compare:(e,t)=>i.sorter.compare(e.element,t.element)}),this.identityProvider=i.identityProvider}setChildren(e,t=S.f.empty(),i={}){const s=this.getElementLocation(e);this._setChildren(s,this.preserveCollapseState(t),i)}_setChildren(e,t=S.f.empty(),i){const s=new Set,n=new Set;this.model.splice([...e,0],Number.MAX_VALUE,t,{...i,onDidCreateNode:e=>{if(null===e.element)return;const t=e;if(s.add(t.element),this.nodes.set(t.element,t),this.identityProvider){const e=this.identityProvider.getId(t.element).toString();n.add(e),this.nodesByIdentity.set(e,t)}i.onDidCreateNode?.(t)},onDidDeleteNode:e=>{if(null===e.element)return;const t=e;if(s.has(t.element)||this.nodes.delete(t.element),this.identityProvider){const e=this.identityProvider.getId(t.element).toString();n.has(e)||this.nodesByIdentity.delete(e)}i.onDidDeleteNode?.(t)}})}preserveCollapseState(e=S.f.empty()){return this.sorter&&(e=[...e].sort(this.sorter.compare.bind(this.sorter))),S.f.map(e,(e=>{let t=this.nodes.get(e.element);if(!t&&this.identityProvider){const i=this.identityProvider.getId(e.element).toString();t=this.nodesByIdentity.get(i)}if(!t){let t;return t="undefined"===typeof e.collapsed?void 0:e.collapsed===b.Yo.Collapsed||e.collapsed===b.Yo.PreserveOrCollapsed||e.collapsed!==b.Yo.Expanded&&e.collapsed!==b.Yo.PreserveOrExpanded&&Boolean(e.collapsed),{...e,children:this.preserveCollapseState(e.children),collapsed:t}}const i="boolean"===typeof e.collapsible?e.collapsible:t.collapsible;let s;return s="undefined"===typeof e.collapsed||e.collapsed===b.Yo.PreserveOrCollapsed||e.collapsed===b.Yo.PreserveOrExpanded?t.collapsed:e.collapsed===b.Yo.Collapsed||e.collapsed!==b.Yo.Expanded&&Boolean(e.collapsed),{...e,collapsible:i,collapsed:s,children:this.preserveCollapseState(e.children)}}))}rerender(e){const t=this.getElementLocation(e);this.model.rerender(t)}getFirstElementChild(e=null){const t=this.getElementLocation(e);return this.model.getFirstElementChild(t)}has(e){return this.nodes.has(e)}getListIndex(e){const t=this.getElementLocation(e);return this.model.getListIndex(t)}getListRenderCount(e){const t=this.getElementLocation(e);return this.model.getListRenderCount(t)}isCollapsible(e){const t=this.getElementLocation(e);return this.model.isCollapsible(t)}setCollapsible(e,t){const i=this.getElementLocation(e);return this.model.setCollapsible(i,t)}isCollapsed(e){const t=this.getElementLocation(e);return this.model.isCollapsed(t)}setCollapsed(e,t,i){const s=this.getElementLocation(e);return this.model.setCollapsed(s,t,i)}expandTo(e){const t=this.getElementLocation(e);this.model.expandTo(t)}refilter(){this.model.refilter()}getNode(e=null){if(null===e)return this.model.getNode(this.model.rootRef);const t=this.nodes.get(e);if(!t)throw new b.jh(this.user,`Tree element not found: ${e}`);return t}getNodeLocation(e){return e.element}getParentNodeLocation(e){if(null===e)throw new b.jh(this.user,"Invalid getParentNodeLocation call");const t=this.nodes.get(e);if(!t)throw new b.jh(this.user,`Tree element not found: ${e}`);const i=this.model.getNodeLocation(t),s=this.model.getParentNodeLocation(i);return this.model.getNode(s).element}getElementLocation(e){if(null===e)return[];const t=this.nodes.get(e);if(!t)throw new b.jh(this.user,`Tree element not found: ${e}`);return this.model.getNodeLocation(t)}}function w(e){return{element:{elements:[e.element],incompressible:e.incompressible||!1},children:S.f.map(S.f.from(e.children),w),collapsible:e.collapsible,collapsed:e.collapsed}}function R(e){const t=[e.element],i=e.incompressible||!1;let s,n;for(;[n,s]=S.f.consume(S.f.from(e.children),2),1===n.length&&!n[0].incompressible;)e=n[0],t.push(e.element);return{element:{elements:t,incompressible:i},children:S.f.map(S.f.concat(n,s),R),collapsible:e.collapsible,collapsed:e.collapsed}}function L(e,t=0){let i;return i=tL(e,0))),0===t&&e.element.incompressible?{element:e.element.elements[t],children:i,incompressible:!0,collapsible:e.collapsible,collapsed:e.collapsed}:{element:e.element.elements[t],children:i,collapsible:e.collapsible,collapsed:e.collapsed}}function T(e){return L(e,0)}function x(e,t,i){return e.element===t?{...e,children:i}:{...e,children:S.f.map(S.f.from(e.children),(e=>x(e,t,i)))}}class k{get onDidSplice(){return this.model.onDidSplice}get onDidChangeCollapseState(){return this.model.onDidChangeCollapseState}get onDidChangeRenderNodeCount(){return this.model.onDidChangeRenderNodeCount}constructor(e,t,i={}){this.user=e,this.rootRef=null,this.nodes=new Map,this.model=new y(e,t,i),this.enabled="undefined"===typeof i.compressionEnabled||i.compressionEnabled,this.identityProvider=i.identityProvider}setChildren(e,t=S.f.empty(),i){const s=i.diffIdentityProvider&&(r=i.diffIdentityProvider,{getId:e=>e.elements.map((e=>r.getId(e).toString())).join("\0")});var r;if(null===e){const e=S.f.map(t,this.enabled?R:w);return void this._setChildren(null,e,{diffIdentityProvider:s,diffDepth:1/0})}const o=this.nodes.get(e);if(!o)throw new b.jh(this.user,"Unknown compressed tree node");const a=this.model.getNode(o),c=this.model.getParentNodeLocation(o),l=this.model.getNode(c),h=x(T(a),e,t),d=(this.enabled?R:w)(h),u=i.diffIdentityProvider?(e,t)=>i.diffIdentityProvider.getId(e)===i.diffIdentityProvider.getId(t):void 0;if((0,n.aI)(d.element.elements,a.element.elements,u))return void this._setChildren(o,d.children||S.f.empty(),{diffIdentityProvider:s,diffDepth:1});const g=l.children.map((e=>e===a?d:e));this._setChildren(l.element,g,{diffIdentityProvider:s,diffDepth:a.depth-l.depth})}isCompressionEnabled(){return this.enabled}setCompressionEnabled(e){if(e===this.enabled)return;this.enabled=e;const t=this.model.getNode().children,i=S.f.map(t,T),s=S.f.map(i,e?R:w);this._setChildren(null,s,{diffIdentityProvider:this.identityProvider,diffDepth:1/0})}_setChildren(e,t,i){const s=new Set;this.model.setChildren(e,t,{...i,onDidCreateNode:e=>{for(const t of e.element.elements)s.add(t),this.nodes.set(t,e.element)},onDidDeleteNode:e=>{for(const t of e.element.elements)s.has(t)||this.nodes.delete(t)}})}has(e){return this.nodes.has(e)}getListIndex(e){const t=this.getCompressedNode(e);return this.model.getListIndex(t)}getListRenderCount(e){const t=this.getCompressedNode(e);return this.model.getListRenderCount(t)}getNode(e){if("undefined"===typeof e)return this.model.getNode();const t=this.getCompressedNode(e);return this.model.getNode(t)}getNodeLocation(e){const t=this.model.getNodeLocation(e);return null===t?null:t.elements[t.elements.length-1]}getParentNodeLocation(e){const t=this.getCompressedNode(e),i=this.model.getParentNodeLocation(t);return null===i?null:i.elements[i.elements.length-1]}getFirstElementChild(e){const t=this.getCompressedNode(e);return this.model.getFirstElementChild(t)}isCollapsible(e){const t=this.getCompressedNode(e);return this.model.isCollapsible(t)}setCollapsible(e,t){const i=this.getCompressedNode(e);return this.model.setCollapsible(i,t)}isCollapsed(e){const t=this.getCompressedNode(e);return this.model.isCollapsed(t)}setCollapsed(e,t,i){const s=this.getCompressedNode(e);return this.model.setCollapsed(s,t,i)}expandTo(e){const t=this.getCompressedNode(e);this.model.expandTo(t)}rerender(e){const t=this.getCompressedNode(e);this.model.rerender(t)}refilter(){this.model.refilter()}getCompressedNode(e){if(null===e)return null;const t=this.nodes.get(e);if(!t)throw new b.jh(this.user,`Tree element not found: ${e}`);return t}}const A=e=>e[e.length-1];class N{get element(){return null===this.node.element?null:this.unwrapper(this.node.element)}get children(){return this.node.children.map((e=>new N(this.unwrapper,e)))}get depth(){return this.node.depth}get visibleChildrenCount(){return this.node.visibleChildrenCount}get visibleChildIndex(){return this.node.visibleChildIndex}get collapsible(){return this.node.collapsible}get collapsed(){return this.node.collapsed}get visible(){return this.node.visible}get filterData(){return this.node.filterData}constructor(e,t){this.unwrapper=e,this.node=t}}class I{get onDidSplice(){return o.Jh.map(this.model.onDidSplice,(({insertedNodes:e,deletedNodes:t})=>({insertedNodes:e.map((e=>this.nodeMapper.map(e))),deletedNodes:t.map((e=>this.nodeMapper.map(e)))})))}get onDidChangeCollapseState(){return o.Jh.map(this.model.onDidChangeCollapseState,(({node:e,deep:t})=>({node:this.nodeMapper.map(e),deep:t})))}get onDidChangeRenderNodeCount(){return o.Jh.map(this.model.onDidChangeRenderNodeCount,(e=>this.nodeMapper.map(e)))}constructor(e,t,i={}){this.rootRef=null,this.elementMapper=i.elementMapper||A;const s=e=>this.elementMapper(e.elements);this.nodeMapper=new b.y2((e=>new N(s,e))),this.model=new k(e,function(e,t){return{splice(i,s,n){t.splice(i,s,n.map((t=>e.map(t))))},updateElementHeight(e,i){t.updateElementHeight(e,i)}}}(this.nodeMapper,t),function(e,t){return{...t,identityProvider:t.identityProvider&&{getId:i=>t.identityProvider.getId(e(i))},sorter:t.sorter&&{compare:(e,i)=>t.sorter.compare(e.elements[0],i.elements[0])},filter:t.filter&&{filter:(i,s)=>t.filter.filter(e(i),s)}}}(s,i))}setChildren(e,t=S.f.empty(),i={}){this.model.setChildren(e,t,i)}isCompressionEnabled(){return this.model.isCompressionEnabled()}setCompressionEnabled(e){this.model.setCompressionEnabled(e)}has(e){return this.model.has(e)}getListIndex(e){return this.model.getListIndex(e)}getListRenderCount(e){return this.model.getListRenderCount(e)}getNode(e){return this.nodeMapper.map(this.model.getNode(e))}getNodeLocation(e){return e.element}getParentNodeLocation(e){return this.model.getParentNodeLocation(e)}getFirstElementChild(e){const t=this.model.getFirstElementChild(e);return null===t||"undefined"===typeof t?t:this.elementMapper(t.elements)}isCollapsible(e){return this.model.isCollapsible(e)}setCollapsible(e,t){return this.model.setCollapsible(e,t)}isCollapsed(e){return this.model.isCollapsed(e)}setCollapsed(e,t,i){return this.model.setCollapsed(e,t,i)}expandTo(e){return this.model.expandTo(e)}rerender(e){return this.model.rerender(e)}refilter(){return this.model.refilter()}getCompressedTreeNode(e=null){return this.model.getNode(e)}}var O=i(58694),D=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o};class M extends v.DO{get onDidChangeCollapseState(){return this.model.onDidChangeCollapseState}constructor(e,t,i,s,n={}){super(e,t,i,s,n),this.user=e}setChildren(e,t=S.f.empty(),i){this.model.setChildren(e,t,i)}rerender(e){void 0!==e?this.model.rerender(e):this.view.rerender()}hasElement(e){return this.model.has(e)}createModel(e,t,i){return new y(e,t,i)}}class P{get compressedTreeNodeProvider(){return this._compressedTreeNodeProvider()}constructor(e,t,i){this._compressedTreeNodeProvider=e,this.stickyScrollDelegate=t,this.renderer=i,this.templateId=i.templateId,i.onDidChangeTwistieState&&(this.onDidChangeTwistieState=i.onDidChangeTwistieState)}renderTemplate(e){return{compressedTreeNode:void 0,data:this.renderer.renderTemplate(e)}}renderElement(e,t,i,s){let n=this.stickyScrollDelegate.getCompressedNode(e);n||(n=this.compressedTreeNodeProvider.getCompressedTreeNode(e.element)),1===n.element.elements.length?(i.compressedTreeNode=void 0,this.renderer.renderElement(e,t,i.data,s)):(i.compressedTreeNode=n,this.renderer.renderCompressedElements(n,t,i.data,s))}disposeElement(e,t,i,s){i.compressedTreeNode?this.renderer.disposeCompressedElements?.(i.compressedTreeNode,t,i.data,s):this.renderer.disposeElement?.(e,t,i.data,s)}disposeTemplate(e){this.renderer.disposeTemplate(e.data)}renderTwistie(e,t){return!!this.renderer.renderTwistie&&this.renderer.renderTwistie(e,t)}}D([O.B],P.prototype,"compressedTreeNodeProvider",null);class F{constructor(e){this.modelProvider=e,this.compressedStickyNodes=new Map}getCompressedNode(e){return this.compressedStickyNodes.get(e)}constrainStickyScrollNodes(e,t,i){if(this.compressedStickyNodes.clear(),0===e.length)return[];for(let s=0;si||s>=t-1&&tthis,o=new F((()=>this.model));super(e,t,i,s.map((e=>new P(r,o,e))),{...U(r,n),stickyScrollDelegate:o})}setChildren(e,t=S.f.empty(),i){this.model.setChildren(e,t,i)}createModel(e,t,i){return new I(e,t,i)}updateOptions(e={}){super.updateOptions(e),"undefined"!==typeof e.compressionEnabled&&this.model.setCompressionEnabled(e.compressionEnabled)}getCompressedTreeNode(e=null){return this.model.getCompressedTreeNode(e)}}var B=i(90766),W=i(10350),V=i(25689),z=i(64383),G=i(631);function j(e){return{...e,children:[],refreshPromise:void 0,stale:!0,slow:!1,forceExpanded:!1}}function K(e,t){return!!t.parent&&(t.parent===e||K(e,t.parent))}class Y{get element(){return this.node.element.element}get children(){return this.node.children.map((e=>new Y(e)))}get depth(){return this.node.depth}get visibleChildrenCount(){return this.node.visibleChildrenCount}get visibleChildIndex(){return this.node.visibleChildIndex}get collapsible(){return this.node.collapsible}get collapsed(){return this.node.collapsed}get visible(){return this.node.visible}get filterData(){return this.node.filterData}constructor(e){this.node=e}}class q{constructor(e,t,i){this.renderer=e,this.nodeMapper=t,this.onDidChangeTwistieState=i,this.renderedNodes=new Map,this.templateId=e.templateId}renderTemplate(e){return{templateData:this.renderer.renderTemplate(e)}}renderElement(e,t,i,s){this.renderer.renderElement(this.nodeMapper.map(e),t,i.templateData,s)}renderTwistie(e,t){return e.slow?(t.classList.add(...V.L.asClassNameArray(W.W.treeItemLoading)),!0):(t.classList.remove(...V.L.asClassNameArray(W.W.treeItemLoading)),!1)}disposeElement(e,t,i,s){this.renderer.disposeElement?.(this.nodeMapper.map(e),t,i.templateData,s)}disposeTemplate(e){this.renderer.disposeTemplate(e.templateData)}dispose(){this.renderedNodes.clear()}}function $(e){return{browserEvent:e.browserEvent,elements:e.elements.map((e=>e.element))}}function Q(e){return{browserEvent:e.browserEvent,element:e.element&&e.element.element,target:e.target}}class X extends C.ur{constructor(e){super(e.elements.map((e=>e.element))),this.data=e}}function Z(e){return e instanceof C.ur?new X(e):e}class J{constructor(e){this.dnd=e}getDragURI(e){return this.dnd.getDragURI(e.element)}getDragLabel(e,t){if(this.dnd.getDragLabel)return this.dnd.getDragLabel(e.map((e=>e.element)),t)}onDragStart(e,t){this.dnd.onDragStart?.(Z(e),t)}onDragOver(e,t,i,s,n,r=!0){return this.dnd.onDragOver(Z(e),t&&t.element,i,s,n)}drop(e,t,i,s,n){this.dnd.drop(Z(e),t&&t.element,i,s,n)}onDragEnd(e){this.dnd.onDragEnd?.(e)}dispose(){this.dnd.dispose()}}function ee(e){return e&&{...e,collapseByDefault:!0,identityProvider:e.identityProvider&&{getId:t=>e.identityProvider.getId(t.element)},dnd:e.dnd&&new J(e.dnd),multipleSelectionController:e.multipleSelectionController&&{isSelectionSingleChangeEvent:t=>e.multipleSelectionController.isSelectionSingleChangeEvent({...t,element:t.element}),isSelectionRangeChangeEvent:t=>e.multipleSelectionController.isSelectionRangeChangeEvent({...t,element:t.element})},accessibilityProvider:e.accessibilityProvider&&{...e.accessibilityProvider,getPosInSet:void 0,getSetSize:void 0,getRole:e.accessibilityProvider.getRole?t=>e.accessibilityProvider.getRole(t.element):()=>"treeitem",isChecked:e.accessibilityProvider.isChecked?t=>!!e.accessibilityProvider?.isChecked(t.element):void 0,getAriaLabel:t=>e.accessibilityProvider.getAriaLabel(t.element),getWidgetAriaLabel:()=>e.accessibilityProvider.getWidgetAriaLabel(),getWidgetRole:e.accessibilityProvider.getWidgetRole?()=>e.accessibilityProvider.getWidgetRole():()=>"tree",getAriaLevel:e.accessibilityProvider.getAriaLevel&&(t=>e.accessibilityProvider.getAriaLevel(t.element)),getActiveDescendantId:e.accessibilityProvider.getActiveDescendantId&&(t=>e.accessibilityProvider.getActiveDescendantId(t.element))},filter:e.filter&&{filter:(t,i)=>e.filter.filter(t.element,i)},keyboardNavigationLabelProvider:e.keyboardNavigationLabelProvider&&{...e.keyboardNavigationLabelProvider,getKeyboardNavigationLabel:t=>e.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(t.element)},sorter:void 0,expandOnlyOnTwistieClick:"undefined"===typeof e.expandOnlyOnTwistieClick?void 0:"function"!==typeof e.expandOnlyOnTwistieClick?e.expandOnlyOnTwistieClick:t=>e.expandOnlyOnTwistieClick(t.element),defaultFindVisibility:t=>t.hasChildren&&t.stale?1:"number"===typeof e.defaultFindVisibility?e.defaultFindVisibility:"undefined"===typeof e.defaultFindVisibility?2:e.defaultFindVisibility(t.element)}}function te(e,t){t(e),e.children.forEach((e=>te(e,t)))}class ie{get onDidScroll(){return this.tree.onDidScroll}get onDidChangeFocus(){return o.Jh.map(this.tree.onDidChangeFocus,$)}get onDidChangeSelection(){return o.Jh.map(this.tree.onDidChangeSelection,$)}get onMouseDblClick(){return o.Jh.map(this.tree.onMouseDblClick,Q)}get onPointer(){return o.Jh.map(this.tree.onPointer,Q)}get onDidFocus(){return this.tree.onDidFocus}get onDidChangeModel(){return this.tree.onDidChangeModel}get onDidChangeCollapseState(){return this.tree.onDidChangeCollapseState}get onDidChangeFindOpenState(){return this.tree.onDidChangeFindOpenState}get onDidChangeStickyScrollFocused(){return this.tree.onDidChangeStickyScrollFocused}get onDidDispose(){return this.tree.onDidDispose}constructor(e,t,i,s,n,r={}){this.user=e,this.dataSource=n,this.nodes=new Map,this.subTreeRefreshPromises=new Map,this.refreshPromises=new Map,this._onDidRender=new o.vl,this._onDidChangeNodeSlowState=new o.vl,this.nodeMapper=new b.y2((e=>new Y(e))),this.disposables=new a.Cm,this.identityProvider=r.identityProvider,this.autoExpandSingleChildren="undefined"!==typeof r.autoExpandSingleChildren&&r.autoExpandSingleChildren,this.sorter=r.sorter,this.getDefaultCollapseState=e=>r.collapseByDefault?r.collapseByDefault(e)?b.Yo.PreserveOrCollapsed:b.Yo.PreserveOrExpanded:void 0,this.tree=this.createTree(e,t,i,s,r),this.onDidChangeFindMode=this.tree.onDidChangeFindMode,this.onDidChangeFindMatchType=this.tree.onDidChangeFindMatchType,this.root=j({element:void 0,parent:null,hasChildren:!0,defaultCollapseState:void 0}),this.identityProvider&&(this.root={...this.root,id:null}),this.nodes.set(null,this.root),this.tree.onDidChangeCollapseState(this._onDidChangeCollapseState,this,this.disposables)}createTree(e,t,i,s,n){const r=new v.w0(i),o=s.map((e=>new q(e,this.nodeMapper,this._onDidChangeNodeSlowState.event))),a=ee(n)||{};return new M(e,t,r,o,a)}updateOptions(e={}){this.tree.updateOptions(e)}getHTMLElement(){return this.tree.getHTMLElement()}get scrollTop(){return this.tree.scrollTop}set scrollTop(e){this.tree.scrollTop=e}get scrollHeight(){return this.tree.scrollHeight}get renderHeight(){return this.tree.renderHeight}domFocus(){this.tree.domFocus()}layout(e,t){this.tree.layout(e,t)}style(e){this.tree.style(e)}getInput(){return this.root.element}async setInput(e,t){this.refreshPromises.forEach((e=>e.cancel())),this.refreshPromises.clear(),this.root.element=e;const i=t&&{viewState:t,focus:[],selection:[]};await this._updateChildren(e,!0,!1,i),i&&(this.tree.setFocus(i.focus),this.tree.setSelection(i.selection)),t&&"number"===typeof t.scrollTop&&(this.scrollTop=t.scrollTop)}async _updateChildren(e=this.root.element,t=!0,i=!1,s,n){if("undefined"===typeof this.root.element)throw new b.jh(this.user,"Tree input not set");this.root.refreshPromise&&(await this.root.refreshPromise,await o.Jh.toPromise(this._onDidRender.event));const r=this.getDataNode(e);if(await this.refreshAndRenderNode(r,t,s,n),i)try{this.tree.rerender(r)}catch{}}rerender(e){if(void 0===e||e===this.root.element)return void this.tree.rerender();const t=this.getDataNode(e);this.tree.rerender(t)}getNode(e=this.root.element){const t=this.getDataNode(e),i=this.tree.getNode(t===this.root?null:t);return this.nodeMapper.map(i)}collapse(e,t=!1){const i=this.getDataNode(e);return this.tree.collapse(i===this.root?null:i,t)}async expand(e,t=!1){if("undefined"===typeof this.root.element)throw new b.jh(this.user,"Tree input not set");this.root.refreshPromise&&(await this.root.refreshPromise,await o.Jh.toPromise(this._onDidRender.event));const i=this.getDataNode(e);if(this.tree.hasElement(i)&&!this.tree.isCollapsible(i))return!1;if(i.refreshPromise&&(await this.root.refreshPromise,await o.Jh.toPromise(this._onDidRender.event)),i!==this.root&&!i.refreshPromise&&!this.tree.isCollapsed(i))return!1;const s=this.tree.expand(i===this.root?null:i,t);return i.refreshPromise&&(await this.root.refreshPromise,await o.Jh.toPromise(this._onDidRender.event)),s}setSelection(e,t){const i=e.map((e=>this.getDataNode(e)));this.tree.setSelection(i,t)}getSelection(){return this.tree.getSelection().map((e=>e.element))}setFocus(e,t){const i=e.map((e=>this.getDataNode(e)));this.tree.setFocus(i,t)}getFocus(){return this.tree.getFocus().map((e=>e.element))}reveal(e,t){this.tree.reveal(this.getDataNode(e),t)}getParentElement(e){const t=this.tree.getParentElement(this.getDataNode(e));return t&&t.element}getFirstElementChild(e=this.root.element){const t=this.getDataNode(e),i=this.tree.getFirstElementChild(t===this.root?null:t);return i&&i.element}getDataNode(e){const t=this.nodes.get(e===this.root.element?null:e);if(!t)throw new b.jh(this.user,`Data tree node not found: ${e}`);return t}async refreshAndRenderNode(e,t,i,s){await this.refreshNode(e,t,i),this.disposables.isDisposed||this.render(e,i,s)}async refreshNode(e,t,i){let s;if(this.subTreeRefreshPromises.forEach(((n,r)=>{!s&&function(e,t){return e===t||K(e,t)||K(t,e)}(r,e)&&(s=n.then((()=>this.refreshNode(e,t,i))))})),s)return s;if(e!==this.root){if(this.tree.getNode(e).collapsed)return e.hasChildren=!!this.dataSource.hasChildren(e.element),e.stale=!0,void this.setChildren(e,[],t,i)}return this.doRefreshSubTree(e,t,i)}async doRefreshSubTree(e,t,i){let s;e.refreshPromise=new Promise((e=>s=e)),this.subTreeRefreshPromises.set(e,e.refreshPromise),e.refreshPromise.finally((()=>{e.refreshPromise=void 0,this.subTreeRefreshPromises.delete(e)}));try{const s=await this.doRefreshNode(e,t,i);e.stale=!1,await B.HC.settled(s.map((e=>this.doRefreshSubTree(e,t,i))))}finally{s()}}async doRefreshNode(e,t,i){let s;if(e.hasChildren=!!this.dataSource.hasChildren(e.element),e.hasChildren){const t=this.doGetChildren(e);if((0,G.xZ)(t))s=Promise.resolve(t);else{const i=(0,B.wR)(800);i.then((()=>{e.slow=!0,this._onDidChangeNodeSlowState.fire(e)}),(e=>null)),s=t.finally((()=>i.cancel()))}}else s=Promise.resolve(S.f.empty());try{const n=await s;return this.setChildren(e,n,t,i)}catch(n){if(e!==this.root&&this.tree.hasElement(e)&&this.tree.collapse(e),(0,z.MB)(n))return[];throw n}finally{e.slow&&(e.slow=!1,this._onDidChangeNodeSlowState.fire(e))}}doGetChildren(e){let t=this.refreshPromises.get(e);if(t)return t;const i=this.dataSource.getChildren(e.element);return(0,G.xZ)(i)?this.processChildren(i):(t=(0,B.SS)((async()=>this.processChildren(await i))),this.refreshPromises.set(e,t),t.finally((()=>{this.refreshPromises.delete(e)})))}_onDidChangeCollapseState({node:e,deep:t}){null!==e.element&&!e.collapsed&&e.element.stale&&(t?this.collapse(e.element.element):this.refreshAndRenderNode(e.element,!1).catch(z.dz))}setChildren(e,t,i,s){const n=[...t];if(0===e.children.length&&0===n.length)return[];const r=new Map,o=new Map;for(const l of e.children)r.set(l.element,l),this.identityProvider&&o.set(l.id,{node:l,collapsed:this.tree.hasElement(l)&&this.tree.isCollapsed(l)});const a=[],c=n.map((t=>{const n=!!this.dataSource.hasChildren(t);if(!this.identityProvider){const i=j({element:t,parent:e,hasChildren:n,defaultCollapseState:this.getDefaultCollapseState(t)});return n&&i.defaultCollapseState===b.Yo.PreserveOrExpanded&&a.push(i),i}const c=this.identityProvider.getId(t).toString(),l=o.get(c);if(l){const e=l.node;return r.delete(e.element),this.nodes.delete(e.element),this.nodes.set(t,e),e.element=t,e.hasChildren=n,i?l.collapsed?(e.children.forEach((e=>te(e,(e=>this.nodes.delete(e.element))))),e.children.splice(0,e.children.length),e.stale=!0):a.push(e):n&&!l.collapsed&&a.push(e),e}const h=j({element:t,parent:e,id:c,hasChildren:n,defaultCollapseState:this.getDefaultCollapseState(t)});return s&&s.viewState.focus&&s.viewState.focus.indexOf(c)>-1&&s.focus.push(h),s&&s.viewState.selection&&s.viewState.selection.indexOf(c)>-1&&s.selection.push(h),(s&&s.viewState.expanded&&s.viewState.expanded.indexOf(c)>-1||n&&h.defaultCollapseState===b.Yo.PreserveOrExpanded)&&a.push(h),h}));for(const l of r.values())te(l,(e=>this.nodes.delete(e.element)));for(const l of c)this.nodes.set(l.element,l);return e.children.splice(0,e.children.length,...c),e!==this.root&&this.autoExpandSingleChildren&&1===c.length&&0===a.length&&(c[0].forceExpanded=!0,a.push(c[0])),a}render(e,t,i){const s=e.children.map((e=>this.asTreeElement(e,t))),n=i&&{...i,diffIdentityProvider:i.diffIdentityProvider&&{getId:e=>i.diffIdentityProvider.getId(e.element)}};this.tree.setChildren(e===this.root?null:e,s,n),e!==this.root&&this.tree.setCollapsible(e,e.hasChildren),this._onDidRender.fire()}asTreeElement(e,t){if(e.stale)return{element:e,collapsible:e.hasChildren,collapsed:!0};let i;return t&&t.viewState.expanded&&e.id&&t.viewState.expanded.indexOf(e.id)>-1?i=!1:e.forceExpanded?(i=!1,e.forceExpanded=!1):i=e.defaultCollapseState,{element:e,children:e.hasChildren?S.f.map(e.children,(e=>this.asTreeElement(e,t))):[],collapsible:e.hasChildren,collapsed:i}}processChildren(e){return this.sorter&&(e=[...e].sort(this.sorter.compare.bind(this.sorter))),e}dispose(){this.disposables.dispose(),this.tree.dispose()}}class se{get element(){return{elements:this.node.element.elements.map((e=>e.element)),incompressible:this.node.element.incompressible}}get children(){return this.node.children.map((e=>new se(e)))}get depth(){return this.node.depth}get visibleChildrenCount(){return this.node.visibleChildrenCount}get visibleChildIndex(){return this.node.visibleChildIndex}get collapsible(){return this.node.collapsible}get collapsed(){return this.node.collapsed}get visible(){return this.node.visible}get filterData(){return this.node.filterData}constructor(e){this.node=e}}class ne{constructor(e,t,i,s){this.renderer=e,this.nodeMapper=t,this.compressibleNodeMapperProvider=i,this.onDidChangeTwistieState=s,this.renderedNodes=new Map,this.disposables=[],this.templateId=e.templateId}renderTemplate(e){return{templateData:this.renderer.renderTemplate(e)}}renderElement(e,t,i,s){this.renderer.renderElement(this.nodeMapper.map(e),t,i.templateData,s)}renderCompressedElements(e,t,i,s){this.renderer.renderCompressedElements(this.compressibleNodeMapperProvider().map(e),t,i.templateData,s)}renderTwistie(e,t){return e.slow?(t.classList.add(...V.L.asClassNameArray(W.W.treeItemLoading)),!0):(t.classList.remove(...V.L.asClassNameArray(W.W.treeItemLoading)),!1)}disposeElement(e,t,i,s){this.renderer.disposeElement?.(this.nodeMapper.map(e),t,i.templateData,s)}disposeCompressedElements(e,t,i,s){this.renderer.disposeCompressedElements?.(this.compressibleNodeMapperProvider().map(e),t,i.templateData,s)}disposeTemplate(e){this.renderer.disposeTemplate(e.templateData)}dispose(){this.renderedNodes.clear(),this.disposables=(0,a.AS)(this.disposables)}}class re extends ie{constructor(e,t,i,s,n,r,o={}){super(e,t,i,n,r,o),this.compressionDelegate=s,this.compressibleNodeMapper=new b.y2((e=>new se(e))),this.filter=o.filter}createTree(e,t,i,s,n){const r=new v.w0(i),o=s.map((e=>new ne(e,this.nodeMapper,(()=>this.compressibleNodeMapper),this._onDidChangeNodeSlowState.event))),a=function(e){const t=e&&ee(e);return t&&{...t,keyboardNavigationLabelProvider:t.keyboardNavigationLabelProvider&&{...t.keyboardNavigationLabelProvider,getCompressedNodeKeyboardNavigationLabel:t=>e.keyboardNavigationLabelProvider.getCompressedNodeKeyboardNavigationLabel(t.map((e=>e.element)))}}}(n)||{};return new H(e,t,r,o,a)}asTreeElement(e,t){return{incompressible:this.compressionDelegate.isIncompressible(e.element),...super.asTreeElement(e,t)}}updateOptions(e={}){this.tree.updateOptions(e)}render(e,t,i){if(!this.identityProvider)return super.render(e,t);const s=e=>this.identityProvider.getId(e).toString(),n=e=>{const t=new Set;for(const i of e){const e=this.tree.getCompressedTreeNode(i===this.root?null:i);if(e.element)for(const i of e.element.elements)t.add(s(i.element))}return t},r=n(this.tree.getSelection()),o=n(this.tree.getFocus());super.render(e,t,i);const a=this.getSelection();let c=!1;const l=this.getFocus();let h=!1;const d=e=>{const t=e.element;if(t)for(let i=0;i{const t=this.filter.filter(e,1),i="boolean"===typeof(s=t)?s?1:0:(0,E.iZ)(s)?(0,E.Mn)(s.visibility):(0,E.Mn)(s);var s;if(2===i)throw new Error("Recursive tree visibility not supported in async data compressed trees");return 1===i}))),super.processChildren(e)}}class oe extends v.DO{constructor(e,t,i,s,n,r={}){super(e,t,i,s,r),this.user=e,this.dataSource=n,this.identityProvider=r.identityProvider}createModel(e,t,i){return new y(e,t,i)}}var ae=i(78209),ce=i(84001),le=i(1646),he=i(32848),de=i(28290),ue=i(47508),ge=i(63591),pe=i(98031),me=i(46359),fe=i(19070),_e=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},ve=function(e,t){return function(i,s){t(i,s,e)}};const Ce=(0,ge.u1)("listService");class Ee{get lastFocusedList(){return this._lastFocusedWidget}constructor(){this.disposables=new a.Cm,this.lists=[],this._lastFocusedWidget=void 0,this._hasCreatedStyleController=!1}setLastFocusedList(e){e!==this._lastFocusedWidget&&(this._lastFocusedWidget?.getHTMLElement().classList.remove("last-focused"),this._lastFocusedWidget=e,this._lastFocusedWidget?.getHTMLElement().classList.add("last-focused"))}register(e,t){if(!this._hasCreatedStyleController){this._hasCreatedStyleController=!0;new c.hb((0,s.li)(),"").style(fe.IN)}if(this.lists.some((t=>t.widget===e)))throw new Error("Cannot register the same widget multiple times");const i={widget:e,extraContextKeys:t};return this.lists.push(i),(0,s.X7)(e.getHTMLElement())&&this.setLastFocusedList(e),(0,a.qE)(e.onDidFocus((()=>this.setLastFocusedList(e))),(0,a.s)((()=>this.lists.splice(this.lists.indexOf(i),1))),e.onDidDispose((()=>{this.lists=this.lists.filter((e=>e!==i)),this._lastFocusedWidget===e&&this.setLastFocusedList(void 0)})))}dispose(){this.disposables.dispose()}}const be=new he.N1("listScrollAtBoundary","none"),Se=(he.M$.or(be.isEqualTo("top"),be.isEqualTo("both")),he.M$.or(be.isEqualTo("bottom"),be.isEqualTo("both")),new he.N1("listFocus",!0)),ye=new he.N1("treestickyScrollFocused",!1),we=new he.N1("listSupportsMultiselect",!0),Re=he.M$.and(Se,he.M$.not(de.aV),ye.negate()),Le=new he.N1("listHasSelectionOrFocus",!1),Te=new he.N1("listDoubleSelection",!1),xe=new he.N1("listMultiSelection",!1),ke=new he.N1("listSelectionNavigation",!1),Ae=new he.N1("listSupportsFind",!0),Ne=new he.N1("treeElementCanCollapse",!1),Ie=new he.N1("treeElementHasParent",!1),Oe=new he.N1("treeElementCanExpand",!1),De=new he.N1("treeElementHasChild",!1),Me=new he.N1("treeFindOpen",!1),Pe="listTypeNavigationMode",Fe="listAutomaticKeyboardNavigation";function Ue(e,t){const i=e.createScoped(t.getHTMLElement());return Se.bindTo(i),i}function He(e,t){const i=be.bindTo(e),s=()=>{const e=0===t.scrollTop,s=t.scrollHeight-t.renderHeight-t.scrollTop<1;e&&s?i.set("both"):e?i.set("top"):s?i.set("bottom"):i.set("none")};return s(),t.onDidScroll(s)}const Be="workbench.list.multiSelectModifier",We="workbench.list.openMode",Ve="workbench.list.horizontalScrolling",ze="workbench.list.defaultFindMode",Ge="workbench.list.typeNavigationMode",je="workbench.list.keyboardNavigation",Ke="workbench.list.scrollByPage",Ye="workbench.list.defaultFindMatchType",qe="workbench.tree.indent",$e="workbench.tree.renderIndentGuides",Qe="workbench.list.smoothScrolling",Xe="workbench.list.mouseWheelScrollSensitivity",Ze="workbench.list.fastScrollSensitivity",Je="workbench.tree.expandMode",et="workbench.tree.enableStickyScroll",tt="workbench.tree.stickyScrollMaxItemCount";function it(e){return"alt"===e.getValue(Be)}class st extends a.jG{constructor(e){super(),this.configurationService=e,this.useAltAsMultipleSelectionModifier=it(e),this.registerListeners()}registerListeners(){this._register(this.configurationService.onDidChangeConfiguration((e=>{e.affectsConfiguration(Be)&&(this.useAltAsMultipleSelectionModifier=it(this.configurationService))})))}isSelectionSingleChangeEvent(e){return this.useAltAsMultipleSelectionModifier?e.browserEvent.altKey:(0,c.tX)(e)}isSelectionRangeChangeEvent(e){return(0,c.mh)(e)}}function nt(e,t){const i=e.get(ce.pG),s=e.get(pe.b),n=new a.Cm;return[{...t,keyboardNavigationDelegate:{mightProducePrintableCharacter:e=>s.mightProducePrintableCharacter(e)},smoothScrolling:Boolean(i.getValue(Qe)),mouseWheelScrollSensitivity:i.getValue(Xe),fastScrollSensitivity:i.getValue(Ze),multipleSelectionController:t.multipleSelectionController??n.add(new st(i)),keyboardNavigationEventFilter:ut(s),scrollByPage:Boolean(i.getValue(Ke))},n]}let rt=class extends c.B8{constructor(e,t,i,s,n,r,o,a,c){const l="undefined"!==typeof n.horizontalScrolling?n.horizontalScrolling:Boolean(a.getValue(Ve)),[h,d]=c.invokeFunction(nt,n);super(e,t,i,s,{keyboardSupport:!1,...h,horizontalScrolling:l}),this.disposables.add(d),this.contextKeyService=Ue(r,this),this.disposables.add(He(this.contextKeyService,this)),this.listSupportsMultiSelect=we.bindTo(this.contextKeyService),this.listSupportsMultiSelect.set(!1!==n.multipleSelectionSupport);ke.bindTo(this.contextKeyService).set(Boolean(n.selectionNavigation)),this.listHasSelectionOrFocus=Le.bindTo(this.contextKeyService),this.listDoubleSelection=Te.bindTo(this.contextKeyService),this.listMultiSelection=xe.bindTo(this.contextKeyService),this.horizontalScrolling=n.horizontalScrolling,this._useAltAsMultipleSelectionModifier=it(a),this.disposables.add(this.contextKeyService),this.disposables.add(o.register(this)),this.updateStyles(n.overrideStyles),this.disposables.add(this.onDidChangeSelection((()=>{const e=this.getSelection(),t=this.getFocus();this.contextKeyService.bufferChangeEvents((()=>{this.listHasSelectionOrFocus.set(e.length>0||t.length>0),this.listMultiSelection.set(e.length>1),this.listDoubleSelection.set(2===e.length)}))}))),this.disposables.add(this.onDidChangeFocus((()=>{const e=this.getSelection(),t=this.getFocus();this.listHasSelectionOrFocus.set(e.length>0||t.length>0)}))),this.disposables.add(a.onDidChangeConfiguration((e=>{e.affectsConfiguration(Be)&&(this._useAltAsMultipleSelectionModifier=it(a));let t={};if(e.affectsConfiguration(Ve)&&void 0===this.horizontalScrolling){const e=Boolean(a.getValue(Ve));t={...t,horizontalScrolling:e}}if(e.affectsConfiguration(Ke)){const e=Boolean(a.getValue(Ke));t={...t,scrollByPage:e}}if(e.affectsConfiguration(Qe)){const e=Boolean(a.getValue(Qe));t={...t,smoothScrolling:e}}if(e.affectsConfiguration(Xe)){const e=a.getValue(Xe);t={...t,mouseWheelScrollSensitivity:e}}if(e.affectsConfiguration(Ze)){const e=a.getValue(Ze);t={...t,fastScrollSensitivity:e}}Object.keys(t).length>0&&this.updateOptions(t)}))),this.navigator=new lt(this,{configurationService:a,...n}),this.disposables.add(this.navigator)}updateOptions(e){super.updateOptions(e),void 0!==e.overrideStyles&&this.updateStyles(e.overrideStyles),void 0!==e.multipleSelectionSupport&&this.listSupportsMultiSelect.set(!!e.multipleSelectionSupport)}updateStyles(e){this.style(e?(0,fe.t8)(e):fe.IN)}};rt=_e([ve(5,he.fN),ve(6,Ce),ve(7,ce.pG),ve(8,ge._Y)],rt);let ot=class extends d{constructor(e,t,i,s,n,r,o,c,l){const h="undefined"!==typeof n.horizontalScrolling?n.horizontalScrolling:Boolean(c.getValue(Ve)),[d,u]=l.invokeFunction(nt,n);super(e,t,i,s,{keyboardSupport:!1,...d,horizontalScrolling:h}),this.disposables=new a.Cm,this.disposables.add(u),this.contextKeyService=Ue(r,this),this.disposables.add(He(this.contextKeyService,this.widget)),this.horizontalScrolling=n.horizontalScrolling,this.listSupportsMultiSelect=we.bindTo(this.contextKeyService),this.listSupportsMultiSelect.set(!1!==n.multipleSelectionSupport);ke.bindTo(this.contextKeyService).set(Boolean(n.selectionNavigation)),this._useAltAsMultipleSelectionModifier=it(c),this.disposables.add(this.contextKeyService),this.disposables.add(o.register(this)),this.updateStyles(n.overrideStyles),this.disposables.add(c.onDidChangeConfiguration((e=>{e.affectsConfiguration(Be)&&(this._useAltAsMultipleSelectionModifier=it(c));let t={};if(e.affectsConfiguration(Ve)&&void 0===this.horizontalScrolling){const e=Boolean(c.getValue(Ve));t={...t,horizontalScrolling:e}}if(e.affectsConfiguration(Ke)){const e=Boolean(c.getValue(Ke));t={...t,scrollByPage:e}}if(e.affectsConfiguration(Qe)){const e=Boolean(c.getValue(Qe));t={...t,smoothScrolling:e}}if(e.affectsConfiguration(Xe)){const e=c.getValue(Xe);t={...t,mouseWheelScrollSensitivity:e}}if(e.affectsConfiguration(Ze)){const e=c.getValue(Ze);t={...t,fastScrollSensitivity:e}}Object.keys(t).length>0&&this.updateOptions(t)}))),this.navigator=new lt(this,{configurationService:c,...n}),this.disposables.add(this.navigator)}updateOptions(e){super.updateOptions(e),void 0!==e.overrideStyles&&this.updateStyles(e.overrideStyles),void 0!==e.multipleSelectionSupport&&this.listSupportsMultiSelect.set(!!e.multipleSelectionSupport)}updateStyles(e){this.style(e?(0,fe.t8)(e):fe.IN)}dispose(){this.disposables.dispose(),super.dispose()}};ot=_e([ve(5,he.fN),ve(6,Ce),ve(7,ce.pG),ve(8,ge._Y)],ot);let at=class extends _{constructor(e,t,i,s,n,r,o,a,c,l){const h="undefined"!==typeof r.horizontalScrolling?r.horizontalScrolling:Boolean(c.getValue(Ve)),[d,u]=l.invokeFunction(nt,r);super(e,t,i,s,n,{keyboardSupport:!1,...d,horizontalScrolling:h}),this.disposables.add(u),this.contextKeyService=Ue(o,this),this.disposables.add(He(this.contextKeyService,this)),this.listSupportsMultiSelect=we.bindTo(this.contextKeyService),this.listSupportsMultiSelect.set(!1!==r.multipleSelectionSupport);ke.bindTo(this.contextKeyService).set(Boolean(r.selectionNavigation)),this.listHasSelectionOrFocus=Le.bindTo(this.contextKeyService),this.listDoubleSelection=Te.bindTo(this.contextKeyService),this.listMultiSelection=xe.bindTo(this.contextKeyService),this.horizontalScrolling=r.horizontalScrolling,this._useAltAsMultipleSelectionModifier=it(c),this.disposables.add(this.contextKeyService),this.disposables.add(a.register(this)),this.updateStyles(r.overrideStyles),this.disposables.add(this.onDidChangeSelection((()=>{const e=this.getSelection(),t=this.getFocus();this.contextKeyService.bufferChangeEvents((()=>{this.listHasSelectionOrFocus.set(e.length>0||t.length>0),this.listMultiSelection.set(e.length>1),this.listDoubleSelection.set(2===e.length)}))}))),this.disposables.add(this.onDidChangeFocus((()=>{const e=this.getSelection(),t=this.getFocus();this.listHasSelectionOrFocus.set(e.length>0||t.length>0)}))),this.disposables.add(c.onDidChangeConfiguration((e=>{e.affectsConfiguration(Be)&&(this._useAltAsMultipleSelectionModifier=it(c));let t={};if(e.affectsConfiguration(Ve)&&void 0===this.horizontalScrolling){const e=Boolean(c.getValue(Ve));t={...t,horizontalScrolling:e}}if(e.affectsConfiguration(Ke)){const e=Boolean(c.getValue(Ke));t={...t,scrollByPage:e}}if(e.affectsConfiguration(Qe)){const e=Boolean(c.getValue(Qe));t={...t,smoothScrolling:e}}if(e.affectsConfiguration(Xe)){const e=c.getValue(Xe);t={...t,mouseWheelScrollSensitivity:e}}if(e.affectsConfiguration(Ze)){const e=c.getValue(Ze);t={...t,fastScrollSensitivity:e}}Object.keys(t).length>0&&this.updateOptions(t)}))),this.navigator=new ht(this,{configurationService:c,...r}),this.disposables.add(this.navigator)}updateOptions(e){super.updateOptions(e),void 0!==e.overrideStyles&&this.updateStyles(e.overrideStyles),void 0!==e.multipleSelectionSupport&&this.listSupportsMultiSelect.set(!!e.multipleSelectionSupport)}updateStyles(e){this.style(e?(0,fe.t8)(e):fe.IN)}dispose(){this.disposables.dispose(),super.dispose()}};at=_e([ve(6,he.fN),ve(7,Ce),ve(8,ce.pG),ve(9,ge._Y)],at);class ct extends a.jG{constructor(e,t){super(),this.widget=e,this._onDidOpen=this._register(new o.vl),this.onDidOpen=this._onDidOpen.event,this._register(o.Jh.filter(this.widget.onDidChangeSelection,(e=>(0,s.kx)(e.browserEvent)))((e=>this.onSelectionFromKeyboard(e)))),this._register(this.widget.onPointer((e=>this.onPointer(e.element,e.browserEvent)))),this._register(this.widget.onMouseDblClick((e=>this.onMouseDblClick(e.element,e.browserEvent)))),"boolean"!==typeof t?.openOnSingleClick&&t?.configurationService?(this.openOnSingleClick="doubleClick"!==t?.configurationService.getValue(We),this._register(t?.configurationService.onDidChangeConfiguration((e=>{e.affectsConfiguration(We)&&(this.openOnSingleClick="doubleClick"!==t?.configurationService.getValue(We))})))):this.openOnSingleClick=t?.openOnSingleClick??!0}onSelectionFromKeyboard(e){if(1!==e.elements.length)return;const t=e.browserEvent,i="boolean"!==typeof t.preserveFocus||t.preserveFocus,s="boolean"===typeof t.pinned?t.pinned:!i;this._open(this.getSelectedElement(),i,s,!1,e.browserEvent)}onPointer(e,t){if(!this.openOnSingleClick)return;if(2===t.detail)return;const i=1===t.button,s=t.ctrlKey||t.metaKey||t.altKey;this._open(e,!0,i,s,t)}onMouseDblClick(e,t){if(!t)return;const i=t.target;if(i.classList.contains("monaco-tl-twistie")||i.classList.contains("monaco-icon-label")&&i.classList.contains("folder-icon")&&t.offsetX<16)return;const s=t.ctrlKey||t.metaKey||t.altKey;this._open(e,!1,!0,s,t)}_open(e,t,i,s,n){e&&this._onDidOpen.fire({editorOptions:{preserveFocus:t,pinned:i,revealIfVisible:!0},sideBySide:s,element:e,browserEvent:n})}}class lt extends ct{constructor(e,t){super(e,t),this.widget=e}getSelectedElement(){return this.widget.getSelectedElements()[0]}}class ht extends ct{constructor(e,t){super(e,t)}getSelectedElement(){return this.widget.getSelectedElements()[0]}}class dt extends ct{constructor(e,t){super(e,t)}getSelectedElement(){return this.widget.getSelection()[0]??void 0}}function ut(e){let t=!1;return i=>{if(i.toKeyCodeChord().isModifierKey())return!1;if(t)return t=!1,!1;const s=e.softDispatch(i,i.target);return 1===s.kind?(t=!0,!1):(t=!1,0===s.kind)}}let gt=class extends M{constructor(e,t,i,s,n,r,o,a,c){const{options:l,getTypeNavigationMode:h,disposable:d}=r.invokeFunction(Et,n);super(e,t,i,s,l),this.disposables.add(d),this.internals=new bt(this,n,h,n.overrideStyles,o,a,c),this.disposables.add(this.internals)}updateOptions(e){super.updateOptions(e),this.internals.updateOptions(e)}};gt=_e([ve(5,ge._Y),ve(6,he.fN),ve(7,Ce),ve(8,ce.pG)],gt);let pt=class extends H{constructor(e,t,i,s,n,r,o,a,c){const{options:l,getTypeNavigationMode:h,disposable:d}=r.invokeFunction(Et,n);super(e,t,i,s,l),this.disposables.add(d),this.internals=new bt(this,n,h,n.overrideStyles,o,a,c),this.disposables.add(this.internals)}updateOptions(e={}){super.updateOptions(e),e.overrideStyles&&this.internals.updateStyleOverrides(e.overrideStyles),this.internals.updateOptions(e)}};pt=_e([ve(5,ge._Y),ve(6,he.fN),ve(7,Ce),ve(8,ce.pG)],pt);let mt=class extends oe{constructor(e,t,i,s,n,r,o,a,c,l){const{options:h,getTypeNavigationMode:d,disposable:u}=o.invokeFunction(Et,r);super(e,t,i,s,n,h),this.disposables.add(u),this.internals=new bt(this,r,d,r.overrideStyles,a,c,l),this.disposables.add(this.internals)}updateOptions(e={}){super.updateOptions(e),void 0!==e.overrideStyles&&this.internals.updateStyleOverrides(e.overrideStyles),this.internals.updateOptions(e)}};mt=_e([ve(6,ge._Y),ve(7,he.fN),ve(8,Ce),ve(9,ce.pG)],mt);let ft=class extends ie{get onDidOpen(){return this.internals.onDidOpen}constructor(e,t,i,s,n,r,o,a,c,l){const{options:h,getTypeNavigationMode:d,disposable:u}=o.invokeFunction(Et,r);super(e,t,i,s,n,h),this.disposables.add(u),this.internals=new bt(this,r,d,r.overrideStyles,a,c,l),this.disposables.add(this.internals)}updateOptions(e={}){super.updateOptions(e),e.overrideStyles&&this.internals.updateStyleOverrides(e.overrideStyles),this.internals.updateOptions(e)}};ft=_e([ve(6,ge._Y),ve(7,he.fN),ve(8,Ce),ve(9,ce.pG)],ft);let _t=class extends re{constructor(e,t,i,s,n,r,o,a,c,l,h){const{options:d,getTypeNavigationMode:u,disposable:g}=a.invokeFunction(Et,o);super(e,t,i,s,n,r,d),this.disposables.add(g),this.internals=new bt(this,o,u,o.overrideStyles,c,l,h),this.disposables.add(this.internals)}updateOptions(e){super.updateOptions(e),this.internals.updateOptions(e)}};function vt(e){const t=e.getValue(ze);if("highlight"===t)return v.vD.Highlight;if("filter"===t)return v.vD.Filter;const i=e.getValue(je);return"simple"===i||"highlight"===i?v.vD.Highlight:"filter"===i?v.vD.Filter:void 0}function Ct(e){const t=e.getValue(Ye);return"fuzzy"===t?v.RD.Fuzzy:"contiguous"===t?v.RD.Contiguous:void 0}function Et(e,t){const i=e.get(ce.pG),s=e.get(ue.l),n=e.get(he.fN),r=e.get(ge._Y),o=void 0!==t.horizontalScrolling?t.horizontalScrolling:Boolean(i.getValue(Ve)),[a,l]=r.invokeFunction(nt,t),h=t.paddingBottom,d=void 0!==t.renderIndentGuides?t.renderIndentGuides:i.getValue($e);return{getTypeNavigationMode:()=>{const e=n.getContextKeyValue(Pe);if("automatic"===e)return c._C.Automatic;if("trigger"===e)return c._C.Trigger;if(!1===n.getContextKeyValue(Fe))return c._C.Trigger;const t=i.getValue(Ge);return"automatic"===t?c._C.Automatic:"trigger"===t?c._C.Trigger:void 0},disposable:l,options:{keyboardSupport:!1,...a,indent:"number"===typeof i.getValue(qe)?i.getValue(qe):void 0,renderIndentGuides:d,smoothScrolling:Boolean(i.getValue(Qe)),defaultFindMode:vt(i),defaultFindMatchType:Ct(i),horizontalScrolling:o,scrollByPage:Boolean(i.getValue(Ke)),paddingBottom:h,hideTwistiesOfChildlessElements:t.hideTwistiesOfChildlessElements,expandOnlyOnTwistieClick:t.expandOnlyOnTwistieClick??"doubleClick"===i.getValue(Je),contextViewProvider:s,findWidgetStyles:fe.Dk,enableStickyScroll:Boolean(i.getValue(et)),stickyScrollMaxItemCount:Number(i.getValue(tt))}}}_t=_e([ve(7,ge._Y),ve(8,he.fN),ve(9,Ce),ve(10,ce.pG)],_t);let bt=class{get onDidOpen(){return this.navigator.onDidOpen}constructor(e,t,i,s,n,r,o){this.tree=e,this.disposables=[],this.contextKeyService=Ue(n,e),this.disposables.push(He(this.contextKeyService,e)),this.listSupportsMultiSelect=we.bindTo(this.contextKeyService),this.listSupportsMultiSelect.set(!1!==t.multipleSelectionSupport);ke.bindTo(this.contextKeyService).set(Boolean(t.selectionNavigation)),this.listSupportFindWidget=Ae.bindTo(this.contextKeyService),this.listSupportFindWidget.set(t.findWidgetEnabled??!0),this.hasSelectionOrFocus=Le.bindTo(this.contextKeyService),this.hasDoubleSelection=Te.bindTo(this.contextKeyService),this.hasMultiSelection=xe.bindTo(this.contextKeyService),this.treeElementCanCollapse=Ne.bindTo(this.contextKeyService),this.treeElementHasParent=Ie.bindTo(this.contextKeyService),this.treeElementCanExpand=Oe.bindTo(this.contextKeyService),this.treeElementHasChild=De.bindTo(this.contextKeyService),this.treeFindOpen=Me.bindTo(this.contextKeyService),this.treeStickyScrollFocused=ye.bindTo(this.contextKeyService),this._useAltAsMultipleSelectionModifier=it(o),this.updateStyleOverrides(s);const a=()=>{const t=e.getFocus()[0];if(!t)return;const i=e.getNode(t);this.treeElementCanCollapse.set(i.collapsible&&!i.collapsed),this.treeElementHasParent.set(!!e.getParentElement(t)),this.treeElementCanExpand.set(i.collapsible&&i.collapsed),this.treeElementHasChild.set(!!e.getFirstElementChild(t))},c=new Set;c.add(Pe),c.add(Fe),this.disposables.push(this.contextKeyService,r.register(e),e.onDidChangeSelection((()=>{const t=e.getSelection(),i=e.getFocus();this.contextKeyService.bufferChangeEvents((()=>{this.hasSelectionOrFocus.set(t.length>0||i.length>0),this.hasMultiSelection.set(t.length>1),this.hasDoubleSelection.set(2===t.length)}))})),e.onDidChangeFocus((()=>{const t=e.getSelection(),i=e.getFocus();this.hasSelectionOrFocus.set(t.length>0||i.length>0),a()})),e.onDidChangeCollapseState(a),e.onDidChangeModel(a),e.onDidChangeFindOpenState((e=>this.treeFindOpen.set(e))),e.onDidChangeStickyScrollFocused((e=>this.treeStickyScrollFocused.set(e))),o.onDidChangeConfiguration((s=>{let n={};if(s.affectsConfiguration(Be)&&(this._useAltAsMultipleSelectionModifier=it(o)),s.affectsConfiguration(qe)){const e=o.getValue(qe);n={...n,indent:e}}if(s.affectsConfiguration($e)&&void 0===t.renderIndentGuides){const e=o.getValue($e);n={...n,renderIndentGuides:e}}if(s.affectsConfiguration(Qe)){const e=Boolean(o.getValue(Qe));n={...n,smoothScrolling:e}}if(s.affectsConfiguration(ze)||s.affectsConfiguration(je)){const e=vt(o);n={...n,defaultFindMode:e}}if(s.affectsConfiguration(Ge)||s.affectsConfiguration(je)){const e=i();n={...n,typeNavigationMode:e}}if(s.affectsConfiguration(Ye)){const e=Ct(o);n={...n,defaultFindMatchType:e}}if(s.affectsConfiguration(Ve)&&void 0===t.horizontalScrolling){const e=Boolean(o.getValue(Ve));n={...n,horizontalScrolling:e}}if(s.affectsConfiguration(Ke)){const e=Boolean(o.getValue(Ke));n={...n,scrollByPage:e}}if(s.affectsConfiguration(Je)&&void 0===t.expandOnlyOnTwistieClick&&(n={...n,expandOnlyOnTwistieClick:"doubleClick"===o.getValue(Je)}),s.affectsConfiguration(et)){const e=o.getValue(et);n={...n,enableStickyScroll:e}}if(s.affectsConfiguration(tt)){const e=Math.max(1,o.getValue(tt));n={...n,stickyScrollMaxItemCount:e}}if(s.affectsConfiguration(Xe)){const e=o.getValue(Xe);n={...n,mouseWheelScrollSensitivity:e}}if(s.affectsConfiguration(Ze)){const e=o.getValue(Ze);n={...n,fastScrollSensitivity:e}}Object.keys(n).length>0&&e.updateOptions(n)})),this.contextKeyService.onDidChangeContext((t=>{t.affectsSome(c)&&e.updateOptions({typeNavigationMode:i()})}))),this.navigator=new dt(e,{configurationService:o,...t}),this.disposables.push(this.navigator)}updateOptions(e){void 0!==e.multipleSelectionSupport&&this.listSupportsMultiSelect.set(!!e.multipleSelectionSupport)}updateStyleOverrides(e){this.tree.style(e?(0,fe.t8)(e):fe.IN)}dispose(){this.disposables=(0,a.AS)(this.disposables)}};bt=_e([ve(4,he.fN),ve(5,Ce),ve(6,ce.pG)],bt);me.O.as(le.Fd.Configuration).registerConfiguration({id:"workbench",order:7,title:(0,ae.kg)("workbenchConfigurationTitle","Workbench"),type:"object",properties:{[Be]:{type:"string",enum:["ctrlCmd","alt"],markdownEnumDescriptions:[(0,ae.kg)("multiSelectModifier.ctrlCmd","Maps to `Control` on Windows and Linux and to `Command` on macOS."),(0,ae.kg)("multiSelectModifier.alt","Maps to `Alt` on Windows and Linux and to `Option` on macOS.")],default:"ctrlCmd",description:(0,ae.kg)({key:"multiSelectModifier",comment:["- `ctrlCmd` refers to a value the setting can take and should not be localized.","- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized."]},"The modifier to be used to add an item in trees and lists to a multi-selection with the mouse (for example in the explorer, open editors and scm view). The 'Open to Side' mouse gestures - if supported - will adapt such that they do not conflict with the multiselect modifier.")},[We]:{type:"string",enum:["singleClick","doubleClick"],default:"singleClick",description:(0,ae.kg)({key:"openModeModifier",comment:["`singleClick` and `doubleClick` refers to a value the setting can take and should not be localized."]},"Controls how to open items in trees and lists using the mouse (if supported). Note that some trees and lists might choose to ignore this setting if it is not applicable.")},[Ve]:{type:"boolean",default:!1,description:(0,ae.kg)("horizontalScrolling setting","Controls whether lists and trees support horizontal scrolling in the workbench. Warning: turning on this setting has a performance implication.")},[Ke]:{type:"boolean",default:!1,description:(0,ae.kg)("list.scrollByPage","Controls whether clicks in the scrollbar scroll page by page.")},[qe]:{type:"number",default:8,minimum:4,maximum:40,description:(0,ae.kg)("tree indent setting","Controls tree indentation in pixels.")},[$e]:{type:"string",enum:["none","onHover","always"],default:"onHover",description:(0,ae.kg)("render tree indent guides","Controls whether the tree should render indent guides.")},[Qe]:{type:"boolean",default:!1,description:(0,ae.kg)("list smoothScrolling setting","Controls whether lists and trees have smooth scrolling.")},[Xe]:{type:"number",default:1,markdownDescription:(0,ae.kg)("Mouse Wheel Scroll Sensitivity","A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.")},[Ze]:{type:"number",default:5,markdownDescription:(0,ae.kg)("Fast Scroll Sensitivity","Scrolling speed multiplier when pressing `Alt`.")},[ze]:{type:"string",enum:["highlight","filter"],enumDescriptions:[(0,ae.kg)("defaultFindModeSettingKey.highlight","Highlight elements when searching. Further up and down navigation will traverse only the highlighted elements."),(0,ae.kg)("defaultFindModeSettingKey.filter","Filter elements when searching.")],default:"highlight",description:(0,ae.kg)("defaultFindModeSettingKey","Controls the default find mode for lists and trees in the workbench.")},[je]:{type:"string",enum:["simple","highlight","filter"],enumDescriptions:[(0,ae.kg)("keyboardNavigationSettingKey.simple","Simple keyboard navigation focuses elements which match the keyboard input. Matching is done only on prefixes."),(0,ae.kg)("keyboardNavigationSettingKey.highlight","Highlight keyboard navigation highlights elements which match the keyboard input. Further up and down navigation will traverse only the highlighted elements."),(0,ae.kg)("keyboardNavigationSettingKey.filter","Filter keyboard navigation will filter out and hide all the elements which do not match the keyboard input.")],default:"highlight",description:(0,ae.kg)("keyboardNavigationSettingKey","Controls the keyboard navigation style for lists and trees in the workbench. Can be simple, highlight and filter."),deprecated:!0,deprecationMessage:(0,ae.kg)("keyboardNavigationSettingKeyDeprecated","Please use 'workbench.list.defaultFindMode' and\t'workbench.list.typeNavigationMode' instead.")},[Ye]:{type:"string",enum:["fuzzy","contiguous"],enumDescriptions:[(0,ae.kg)("defaultFindMatchTypeSettingKey.fuzzy","Use fuzzy matching when searching."),(0,ae.kg)("defaultFindMatchTypeSettingKey.contiguous","Use contiguous matching when searching.")],default:"fuzzy",description:(0,ae.kg)("defaultFindMatchTypeSettingKey","Controls the type of matching used when searching lists and trees in the workbench.")},[Je]:{type:"string",enum:["singleClick","doubleClick"],default:"singleClick",description:(0,ae.kg)("expand mode","Controls how tree folders are expanded when clicking the folder names. Note that some trees and lists might choose to ignore this setting if it is not applicable.")},[et]:{type:"boolean",default:!0,description:(0,ae.kg)("sticky scroll","Controls whether sticky scrolling is enabled in trees.")},[tt]:{type:"number",minimum:1,default:7,markdownDescription:(0,ae.kg)("sticky scroll maximum items","Controls the number of sticky elements displayed in the tree when {0} is enabled.","`#workbench.tree.enableStickyScroll#`")},[Ge]:{type:"string",enum:["automatic","trigger"],default:"automatic",markdownDescription:(0,ae.kg)("typeNavigationMode2","Controls how type navigation works in lists and trees in the workbench. When set to `trigger`, type navigation begins once the `list.triggerTypeNavigation` command is run.")}}})},36677:(e,t,i)=>{"use strict";i.d(t,{Q:()=>n});var s=i(83069);class n{constructor(e,t,i,s){e>i||e===i&&t>s?(this.startLineNumber=i,this.startColumn=s,this.endLineNumber=e,this.endColumn=t):(this.startLineNumber=e,this.startColumn=t,this.endLineNumber=i,this.endColumn=s)}isEmpty(){return n.isEmpty(this)}static isEmpty(e){return e.startLineNumber===e.endLineNumber&&e.startColumn===e.endColumn}containsPosition(e){return n.containsPosition(this,e)}static containsPosition(e,t){return!(t.lineNumbere.endLineNumber)&&(!(t.lineNumber===e.startLineNumber&&t.columne.endColumn))}static strictContainsPosition(e,t){return!(t.lineNumbere.endLineNumber)&&(!(t.lineNumber===e.startLineNumber&&t.column<=e.startColumn)&&!(t.lineNumber===e.endLineNumber&&t.column>=e.endColumn))}containsRange(e){return n.containsRange(this,e)}static containsRange(e,t){return!(t.startLineNumbere.endLineNumber||t.endLineNumber>e.endLineNumber)&&(!(t.startLineNumber===e.startLineNumber&&t.startColumne.endColumn)))}strictContainsRange(e){return n.strictContainsRange(this,e)}static strictContainsRange(e,t){return!(t.startLineNumbere.endLineNumber||t.endLineNumber>e.endLineNumber)&&(!(t.startLineNumber===e.startLineNumber&&t.startColumn<=e.startColumn)&&!(t.endLineNumber===e.endLineNumber&&t.endColumn>=e.endColumn)))}plusRange(e){return n.plusRange(this,e)}static plusRange(e,t){let i,s,r,o;return t.startLineNumbere.endLineNumber?(r=t.endLineNumber,o=t.endColumn):t.endLineNumber===e.endLineNumber?(r=t.endLineNumber,o=Math.max(t.endColumn,e.endColumn)):(r=e.endLineNumber,o=e.endColumn),new n(i,s,r,o)}intersectRanges(e){return n.intersectRanges(this,e)}static intersectRanges(e,t){let i=e.startLineNumber,s=e.startColumn,r=e.endLineNumber,o=e.endColumn;const a=t.startLineNumber,c=t.startColumn,l=t.endLineNumber,h=t.endColumn;return il?(r=l,o=h):r===l&&(o=Math.min(o,h)),i>r||i===r&&s>o?null:new n(i,s,r,o)}equalsRange(e){return n.equalsRange(this,e)}static equalsRange(e,t){return!e&&!t||!!e&&!!t&&e.startLineNumber===t.startLineNumber&&e.startColumn===t.startColumn&&e.endLineNumber===t.endLineNumber&&e.endColumn===t.endColumn}getEndPosition(){return n.getEndPosition(this)}static getEndPosition(e){return new s.y(e.endLineNumber,e.endColumn)}getStartPosition(){return n.getStartPosition(this)}static getStartPosition(e){return new s.y(e.startLineNumber,e.startColumn)}toString(){return"["+this.startLineNumber+","+this.startColumn+" -> "+this.endLineNumber+","+this.endColumn+"]"}setEndPosition(e,t){return new n(this.startLineNumber,this.startColumn,e,t)}setStartPosition(e,t){return new n(e,t,this.endLineNumber,this.endColumn)}collapseToStart(){return n.collapseToStart(this)}static collapseToStart(e){return new n(e.startLineNumber,e.startColumn,e.startLineNumber,e.startColumn)}collapseToEnd(){return n.collapseToEnd(this)}static collapseToEnd(e){return new n(e.endLineNumber,e.endColumn,e.endLineNumber,e.endColumn)}delta(e){return new n(this.startLineNumber+e,this.startColumn,this.endLineNumber+e,this.endColumn)}static fromPositions(e,t=e){return new n(e.lineNumber,e.column,t.lineNumber,t.column)}static lift(e){return e?new n(e.startLineNumber,e.startColumn,e.endLineNumber,e.endColumn):null}static isIRange(e){return e&&"number"===typeof e.startLineNumber&&"number"===typeof e.startColumn&&"number"===typeof e.endLineNumber&&"number"===typeof e.endColumn}static areIntersectingOrTouching(e,t){return!(e.endLineNumbere.startLineNumber}toJSON(){return this}}},36723:(e,t,i)=>{"use strict";i.r(t),i.d(t,{DraggedTreeItemsIdentifier:()=>n,TreeViewsDnDService:()=>s});class s{constructor(){this._dragOperations=new Map}removeDragOperationTransfer(e){if(e&&this._dragOperations.has(e)){const t=this._dragOperations.get(e);return this._dragOperations.delete(e),t}}}class n{constructor(e){this.identifier=e}}},36921:(e,t,i)=>{"use strict";i.d(t,{HJ:()=>h,LN:()=>a,YH:()=>l,ih:()=>d,rc:()=>o,wv:()=>c});var s=i(41234),n=i(5662),r=i(78209);class o extends n.jG{constructor(e,t="",i="",n=!0,r){super(),this._onDidChange=this._register(new s.vl),this.onDidChange=this._onDidChange.event,this._enabled=!0,this._id=e,this._label=t,this._cssClass=i,this._enabled=n,this._actionCallback=r}get id(){return this._id}get label(){return this._label}set label(e){this._setLabel(e)}_setLabel(e){this._label!==e&&(this._label=e,this._onDidChange.fire({label:e}))}get tooltip(){return this._tooltip||""}set tooltip(e){this._setTooltip(e)}_setTooltip(e){this._tooltip!==e&&(this._tooltip=e,this._onDidChange.fire({tooltip:e}))}get class(){return this._cssClass}set class(e){this._setClass(e)}_setClass(e){this._cssClass!==e&&(this._cssClass=e,this._onDidChange.fire({class:e}))}get enabled(){return this._enabled}set enabled(e){this._setEnabled(e)}_setEnabled(e){this._enabled!==e&&(this._enabled=e,this._onDidChange.fire({enabled:e}))}get checked(){return this._checked}set checked(e){this._setChecked(e)}_setChecked(e){this._checked!==e&&(this._checked=e,this._onDidChange.fire({checked:e}))}async run(e,t){this._actionCallback&&await this._actionCallback(e)}}class a extends n.jG{constructor(){super(...arguments),this._onWillRun=this._register(new s.vl),this.onWillRun=this._onWillRun.event,this._onDidRun=this._register(new s.vl),this.onDidRun=this._onDidRun.event}async run(e,t){if(!e.enabled)return;let i;this._onWillRun.fire({action:e});try{await this.runAction(e,t)}catch(s){i=s}this._onDidRun.fire({action:e,error:i})}async runAction(e,t){await e.run(t)}}class c{constructor(){this.id=c.ID,this.label="",this.tooltip="",this.class="separator",this.enabled=!1,this.checked=!1}static join(...e){let t=[];for(const i of e)i.length&&(t=t.length?[...t,new c,...i]:i);return t}static{this.ID="vs.actions.separator"}async run(){}}class l{get actions(){return this._actions}constructor(e,t,i,s){this.tooltip="",this.enabled=!0,this.checked=void 0,this.id=e,this.label=t,this.class=s,this._actions=i}async run(){}}class h extends o{static{this.ID="vs.actions.empty"}constructor(){super(h.ID,r.kg("submenu.empty","(empty)"),void 0,!1)}}function d(e){return{id:e.id,label:e.label,tooltip:e.tooltip??e.label,class:e.class,enabled:e.enabled??!0,checked:e.checked,run:async(...t)=>e.run(...t)}}},36998:(e,t,i)=>{"use strict";i.d(t,{c:()=>o});var s=i(7085),n=i(36677),r=i(55190);class o{static _handleEolEdits(e,t){let i;const s=[];for(const n of t)"number"===typeof n.eol&&(i=n.eol),n.range&&"string"===typeof n.text&&s.push(n);return"number"===typeof i&&e.hasModel()&&e.getModel().pushEOL(i),s}static _isFullModelReplaceEdit(e,t){if(!e.hasModel())return!1;const i=e.getModel(),s=i.validateRange(t.range);return i.getFullModelRange().equalsRange(s)}static execute(e,t,i){i&&e.pushUndoStop();const a=r.D.capture(e),c=o._handleEolEdits(e,t);1===c.length&&o._isFullModelReplaceEdit(e,c[0])?e.executeEdits("formatEditsCommand",c.map((e=>s.k.replace(n.Q.lift(e.range),e.text)))):e.executeEdits("formatEditsCommand",c.map((e=>s.k.replaceMove(n.Q.lift(e.range),e.text)))),i&&e.pushUndoStop(),a.restoreRelativeVerticalPositionOfCursor(e)}}},36999:(e,t,i)=>{"use strict";i.d(t,{Yh:()=>k,QM:()=>w});var s=i(78209),n=i(60413),r=i(631),o=i(11007),a=i(31450),c=i(80301),l=i(32799),h=i(83069),d=i(36677);class u{static columnSelect(e,t,i,s,n,r){const o=Math.abs(n-i)+1,a=i>n,c=s>r,u=sr)continue;if(_s)continue;if(f0&&s--,u.columnSelect(e,t,i.fromViewLineNumber,i.fromViewVisualColumn,i.toViewLineNumber,s)}static columnSelectRight(e,t,i){let s=0;const n=Math.min(i.fromViewLineNumber,i.toViewLineNumber),r=Math.max(i.fromViewLineNumber,i.toViewLineNumber);for(let a=n;a<=r;a++){const i=t.getLineMaxColumn(a),n=e.visibleColumnFromColumn(t,new h.y(a,i));s=Math.max(s,n)}let o=i.toViewVisualColumn;return o{const i=e.get(c.T).getFocusedCodeEditor();return!(!i||!i.hasTextFocus())&&this._runEditorCommand(e,i,t)})),e.addImplementation(1e3,"generic-dom-input-textarea",((e,t)=>{const i=(0,C.bq)();return!!(i&&["input","textarea"].indexOf(i.tagName.toLowerCase())>=0)&&(this.runDOMCommand(i),!0)})),e.addImplementation(0,"generic-dom",((e,t)=>{const i=e.get(c.T).getActiveCodeEditor();return!!i&&(i.focus(),this._runEditorCommand(e,i,t))}))}_runEditorCommand(e,t,i){const s=this.runEditorCommand(e,t,i);return s||!0}}!function(e){class t extends b{constructor(e){super(e),this._inSelectionMode=e.inSelectionMode}runCoreEditorCommand(e,t){if(!t.position)return;e.model.pushStackElement();e.setCursorStates(t.source,3,[p.c.moveTo(e,e.getPrimaryCursorState(),this._inSelectionMode,t.position,t.viewPosition)])&&2!==t.revealType&&e.revealAllCursors(t.source,!0,!0)}}e.MoveTo=(0,a.E_)(new t({id:"_moveTo",inSelectionMode:!1,precondition:void 0})),e.MoveToSelect=(0,a.E_)(new t({id:"_moveToSelect",inSelectionMode:!0,precondition:void 0}));class i extends b{runCoreEditorCommand(e,t){e.model.pushStackElement();const i=this._getColumnSelectResult(e,e.getPrimaryCursorState(),e.getCursorColumnSelectData(),t);null!==i&&(e.setCursorStates(t.source,3,i.viewStates.map((e=>l.MF.fromViewState(e)))),e.setCursorColumnSelectData({isReal:!0,fromViewLineNumber:i.fromLineNumber,fromViewVisualColumn:i.fromVisualColumn,toViewLineNumber:i.toLineNumber,toViewVisualColumn:i.toVisualColumn}),i.reversed?e.revealTopMostCursor(t.source):e.revealBottomMostCursor(t.source))}}e.ColumnSelect=(0,a.E_)(new class extends i{constructor(){super({id:"columnSelect",precondition:void 0})}_getColumnSelectResult(e,t,i,s){if("undefined"===typeof s.position||"undefined"===typeof s.viewPosition||"undefined"===typeof s.mouseColumn)return null;const n=e.model.validatePosition(s.position),r=e.coordinatesConverter.validateViewPosition(new h.y(s.viewPosition.lineNumber,s.viewPosition.column),n),o=s.doColumnSelect?i.fromViewLineNumber:r.lineNumber,a=s.doColumnSelect?i.fromViewVisualColumn:s.mouseColumn-1;return u.columnSelect(e.cursorConfig,e,o,a,r.lineNumber,s.mouseColumn-1)}}),e.CursorColumnSelectLeft=(0,a.E_)(new class extends i{constructor(){super({id:"cursorColumnSelectLeft",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:3599,linux:{primary:0}}})}_getColumnSelectResult(e,t,i,s){return u.columnSelectLeft(e.cursorConfig,e,i)}}),e.CursorColumnSelectRight=(0,a.E_)(new class extends i{constructor(){super({id:"cursorColumnSelectRight",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:3601,linux:{primary:0}}})}_getColumnSelectResult(e,t,i,s){return u.columnSelectRight(e.cursorConfig,e,i)}});class r extends i{constructor(e){super(e),this._isPaged=e.isPaged}_getColumnSelectResult(e,t,i,s){return u.columnSelectUp(e.cursorConfig,e,i,this._isPaged)}}e.CursorColumnSelectUp=(0,a.E_)(new r({isPaged:!1,id:"cursorColumnSelectUp",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:3600,linux:{primary:0}}})),e.CursorColumnSelectPageUp=(0,a.E_)(new r({isPaged:!0,id:"cursorColumnSelectPageUp",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:3595,linux:{primary:0}}}));class c extends i{constructor(e){super(e),this._isPaged=e.isPaged}_getColumnSelectResult(e,t,i,s){return u.columnSelectDown(e.cursorConfig,e,i,this._isPaged)}}e.CursorColumnSelectDown=(0,a.E_)(new c({isPaged:!1,id:"cursorColumnSelectDown",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:3602,linux:{primary:0}}})),e.CursorColumnSelectPageDown=(0,a.E_)(new c({isPaged:!0,id:"cursorColumnSelectPageDown",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:3596,linux:{primary:0}}}));class g extends b{constructor(){super({id:"cursorMove",precondition:void 0,metadata:p.S.metadata})}runCoreEditorCommand(e,t){const i=p.S.parse(t);i&&this._runCursorMove(e,t.source,i)}_runCursorMove(e,t,i){e.model.pushStackElement(),e.setCursorStates(t,3,g._move(e,e.getCursorStates(),i)),e.revealAllCursors(t,!0)}static _move(e,t,i){const s=i.select,n=i.value;switch(i.direction){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9:case 10:return p.c.simpleMove(e,t,i.direction,s,n,i.unit);case 11:case 13:case 12:case 14:return p.c.viewportMove(e,t,i.direction,s,n);default:return null}}}e.CursorMoveImpl=g,e.CursorMove=(0,a.E_)(new g);class m extends b{constructor(e){super(e),this._staticArgs=e.args}runCoreEditorCommand(e,t){let i=this._staticArgs;-1===this._staticArgs.value&&(i={direction:this._staticArgs.direction,unit:this._staticArgs.unit,select:this._staticArgs.select,value:t.pageSize||e.cursorConfig.pageSize}),e.model.pushStackElement(),e.setCursorStates(t.source,3,p.c.simpleMove(e,e.getCursorStates(),i.direction,i.select,i.value,i.unit)),e.revealAllCursors(t.source,!0)}}e.CursorLeft=(0,a.E_)(new m({args:{direction:0,unit:0,select:!1,value:1},id:"cursorLeft",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:15,mac:{primary:15,secondary:[288]}}})),e.CursorLeftSelect=(0,a.E_)(new m({args:{direction:0,unit:0,select:!0,value:1},id:"cursorLeftSelect",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:1039}})),e.CursorRight=(0,a.E_)(new m({args:{direction:1,unit:0,select:!1,value:1},id:"cursorRight",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:17,mac:{primary:17,secondary:[292]}}})),e.CursorRightSelect=(0,a.E_)(new m({args:{direction:1,unit:0,select:!0,value:1},id:"cursorRightSelect",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:1041}})),e.CursorUp=(0,a.E_)(new m({args:{direction:2,unit:2,select:!1,value:1},id:"cursorUp",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:16,mac:{primary:16,secondary:[302]}}})),e.CursorUpSelect=(0,a.E_)(new m({args:{direction:2,unit:2,select:!0,value:1},id:"cursorUpSelect",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:1040,secondary:[3088],mac:{primary:1040},linux:{primary:1040}}})),e.CursorPageUp=(0,a.E_)(new m({args:{direction:2,unit:2,select:!1,value:-1},id:"cursorPageUp",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:11}})),e.CursorPageUpSelect=(0,a.E_)(new m({args:{direction:2,unit:2,select:!0,value:-1},id:"cursorPageUpSelect",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:1035}})),e.CursorDown=(0,a.E_)(new m({args:{direction:3,unit:2,select:!1,value:1},id:"cursorDown",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:18,mac:{primary:18,secondary:[300]}}})),e.CursorDownSelect=(0,a.E_)(new m({args:{direction:3,unit:2,select:!0,value:1},id:"cursorDownSelect",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:1042,secondary:[3090],mac:{primary:1042},linux:{primary:1042}}})),e.CursorPageDown=(0,a.E_)(new m({args:{direction:3,unit:2,select:!1,value:-1},id:"cursorPageDown",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:12}})),e.CursorPageDownSelect=(0,a.E_)(new m({args:{direction:3,unit:2,select:!0,value:-1},id:"cursorPageDownSelect",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:1036}})),e.CreateCursor=(0,a.E_)(new class extends b{constructor(){super({id:"createCursor",precondition:void 0})}runCoreEditorCommand(e,t){if(!t.position)return;let i;i=t.wholeLine?p.c.line(e,e.getPrimaryCursorState(),!1,t.position,t.viewPosition):p.c.moveTo(e,e.getPrimaryCursorState(),!1,t.position,t.viewPosition);const s=e.getCursorStates();if(s.length>1){const n=i.modelState?i.modelState.position:null,r=i.viewState?i.viewState.position:null;for(let i=0,o=s.length;ir&&(n=r);const o=new d.Q(n,1,n,e.model.getLineMaxColumn(n));let a=0;if(i.at)switch(i.at){case y.RawAtArgument.Top:a=3;break;case y.RawAtArgument.Center:a=1;break;case y.RawAtArgument.Bottom:a=4}const c=e.coordinatesConverter.convertModelRangeToViewRange(o);e.revealRange(t.source,!1,c,a,0)}}),e.SelectAll=new class extends R{constructor(){super(a.tc)}runDOMCommand(e){n.gm&&(e.focus(),e.select()),e.ownerDocument.execCommand("selectAll")}runEditorCommand(e,t,i){const s=t._getViewModel();s&&this.runCoreEditorCommand(s,i)}runCoreEditorCommand(e,t){e.model.pushStackElement(),e.setCursorStates("keyboard",3,[p.c.selectAll(e,e.getPrimaryCursorState())])}},e.SetSelection=(0,a.E_)(new class extends b{constructor(){super({id:"setSelection",precondition:void 0})}runCoreEditorCommand(e,t){t.selection&&(e.model.pushStackElement(),e.setCursorStates(t.source,3,[l.MF.fromModelSelection(t.selection)]))}})}(w||(w={}));const L=_.M$.and(f.R.textInputFocus,f.R.columnSelection);function T(e,t){v.f.registerKeybindingRule({id:e,primary:t,when:L,weight:1})}function x(e){return e.register(),e}var k;T(w.CursorColumnSelectLeft.id,1039),T(w.CursorColumnSelectRight.id,1041),T(w.CursorColumnSelectUp.id,1040),T(w.CursorColumnSelectPageUp.id,1035),T(w.CursorColumnSelectDown.id,1042),T(w.CursorColumnSelectPageDown.id,1036),function(e){class t extends a.DX{runEditorCommand(e,t,i){const s=t._getViewModel();s&&this.runCoreEditingCommand(t,s,i||{})}}e.CoreEditingCommand=t,e.LineBreakInsert=(0,a.E_)(new class extends t{constructor(){super({id:"lineBreakInsert",precondition:f.R.writable,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:0,mac:{primary:301}}})}runCoreEditingCommand(e,t,i){e.pushUndoStop(),e.executeCommands(this.id,E.AO.lineBreakInsert(t.cursorConfig,t.model,t.getCursorStates().map((e=>e.modelState.selection))))}}),e.Outdent=(0,a.E_)(new class extends t{constructor(){super({id:"outdent",precondition:f.R.writable,kbOpts:{weight:0,kbExpr:_.M$.and(f.R.editorTextFocus,f.R.tabDoesNotMoveFocus),primary:1026}})}runCoreEditingCommand(e,t,i){e.pushUndoStop(),e.executeCommands(this.id,m.T.outdent(t.cursorConfig,t.model,t.getCursorStates().map((e=>e.modelState.selection)))),e.pushUndoStop()}}),e.Tab=(0,a.E_)(new class extends t{constructor(){super({id:"tab",precondition:f.R.writable,kbOpts:{weight:0,kbExpr:_.M$.and(f.R.editorTextFocus,f.R.tabDoesNotMoveFocus),primary:2}})}runCoreEditingCommand(e,t,i){e.pushUndoStop(),e.executeCommands(this.id,m.T.tab(t.cursorConfig,t.model,t.getCursorStates().map((e=>e.modelState.selection)))),e.pushUndoStop()}}),e.DeleteLeft=(0,a.E_)(new class extends t{constructor(){super({id:"deleteLeft",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:1,secondary:[1025],mac:{primary:1,secondary:[1025,294,257]}}})}runCoreEditingCommand(e,t,i){const[s,n]=g.g.deleteLeft(t.getPrevEditOperationType(),t.cursorConfig,t.model,t.getCursorStates().map((e=>e.modelState.selection)),t.getCursorAutoClosedCharacters());s&&e.pushUndoStop(),e.executeCommands(this.id,n),t.setPrevEditOperationType(2)}}),e.DeleteRight=(0,a.E_)(new class extends t{constructor(){super({id:"deleteRight",precondition:void 0,kbOpts:{weight:0,kbExpr:f.R.textInputFocus,primary:20,mac:{primary:20,secondary:[290,276]}}})}runCoreEditingCommand(e,t,i){const[s,n]=g.g.deleteRight(t.getPrevEditOperationType(),t.cursorConfig,t.model,t.getCursorStates().map((e=>e.modelState.selection)));s&&e.pushUndoStop(),e.executeCommands(this.id,n),t.setPrevEditOperationType(3)}}),e.Undo=new class extends R{constructor(){super(a.aU)}runDOMCommand(e){e.ownerDocument.execCommand("undo")}runEditorCommand(e,t,i){if(t.hasModel()&&!0!==t.getOption(92))return t.getModel().undo()}},e.Redo=new class extends R{constructor(){super(a.ih)}runDOMCommand(e){e.ownerDocument.execCommand("redo")}runEditorCommand(e,t,i){if(t.hasModel()&&!0!==t.getOption(92))return t.getModel().redo()}}}(k||(k={}));class A extends a.uB{constructor(e,t,i){super({id:e,precondition:void 0,metadata:i}),this._handlerId=t}runCommand(e,t){const i=e.get(c.T).getFocusedCodeEditor();i&&i.trigger("keyboard",this._handlerId,t)}}function N(e,t){x(new A("default:"+e,e)),x(new A(e,e,t))}N("type",{description:"Type",args:[{name:"args",schema:{type:"object",required:["text"],properties:{text:{type:"string"}}}}]}),N("replacePreviousChar"),N("compositionType"),N("compositionStart"),N("compositionEnd"),N("paste"),N("cut")},37035:(e,t,i)=>{e.exports=i(96409)},37227:(e,t,i)=>{"use strict";i.d(t,{A7:()=>c,Q_:()=>d,VR:()=>o,cn:()=>p,ct:()=>m,jB:()=>a,kF:()=>g,mX:()=>u});var s=i(78209),n=i(74027),r=(i(4853),i(79400));const o=(0,i(63591).u1)("contextService");function a(e){const t=e;return"string"===typeof t?.id&&r.r.isUri(t.uri)}function c(e){const t=e;return"string"===typeof t?.id&&!a(e)&&!function(e){const t=e;return"string"===typeof t?.id&&r.r.isUri(t.configPath)}(e)}const l={id:"ext-dev"},h={id:"empty-window"};function d(e,t){if("string"===typeof e||"undefined"===typeof e)return"string"===typeof e?{id:(0,n.P8)(e)}:t?l:h;const i=e;return i.configuration?{id:i.id,configPath:i.configuration}:1===i.folders.length?{id:i.id,uri:i.folders[0].uri}:{id:i.id}}class u{constructor(e,t){this.raw=t,this.uri=e.uri,this.index=e.index,this.name=e.name}toJSON(){return{uri:this.uri,name:this.name,index:this.index}}}const g="code-workspace",p=((0,s.kg)("codeWorkspace","Code Workspace"),"4064f6ec-cb38-4ad0-af64-ee6467e63c82");function m(e){return e.id===p}},37301:(e,t,i)=>{e.exports=function(){const e=i(94297),t=[{name:"microsecond",divisor:1e6},{name:"second",divisor:60},{name:"minute",divisor:60},{name:"hour",divisor:24},{name:"day"}];function s(i){const s=Number(i.$value)<0?"-":"";let n=Math.abs(i.$value);if(0===n)return"0";return s+t.map((function(e){let t=n;return e.divisor?(t=n%e.divisor,n=Math.floor(n/e.divisor)):(t=n,n=0),[t,e.name]})).reverse().filter((function(e){return e[0]>0})).map((function(t){const i=t[0],s=i>1?"s":"";return i+e.NON_BREAKING_WHITESPACE+t[1]+s})).join(e.WHITESPACE)}return s.isScalar=!0,s}},37403:(e,t,i)=>{!function(){"use strict";const t=i(94297),s=i(1019),n=i(34132),r=i(34420),o="json";function a(e){return String(e.$value)}const c={};function l(e,i,s){const n=e.$type?.startsWith("yql.pg")?"yql.pg":e.$type,r=Object.prototype.hasOwnProperty.call(c,n)?c[n]:a,o=r(e,i,s),l=r.isScalar?t.wrapScalar(e,i,o):t.wrapComplex(e,i,o);return t.wrapOptional(e,i,l)}function h(e,t,i){return l({$type:"string",$special_key:!0,$value:e,$decoded_value:e},t,i)}function d(e,i,s){let n="";const r=e.$attributes,a=r.length;return t.drawFullView(a,i)?(n+=t.getAttributesStart(i)+t.getIndent(i,s),n+=p(r,i,s),n+=t.getIndent(i,s-1)+t.getAttributesEnd(i)+t.getIndent(i,s-1)):t.drawCompactView(a,i)?(n+=t.getAttributesStart(i),n+=p(r,i,s-1),n+=t.getAttributesEnd(i)+(i.format===o?t.getIndent(i,s-1):"")):n+=t.getAttributesStart(i)+t.getAttributesEnd(i),n}function u(e){return Object.prototype.hasOwnProperty.call(e,"$attributes")&&e.$attributes.length>0}const g=function(e,i,s){s=s||1;let n="";return i.format===o?u(e)?(n+=t.OBJECT_START+t.getIndent(i,s),n+=h("$attributes",i,s)+t.getKeyValueSeparator(i),n+=d(e,i,s+1),n+=h("$value",i,s)+t.getKeyValueSeparator(i),n+=l(e,i,s+1),n+=t.getIndent(i,s-1)+t.OBJECT_END):n+=l(e,i,s):"yson"===i.format&&(u(e)&&(n+=d(e,i,s)),n+=l(e,i,s)),n},p=i(83823)(g);function m(e,i,s){return"undefined"===typeof e?t.EMPTY_STRING:(s=s||function(e){return e},(i=i||{}).format=t.parseSetting(i,"format",o),i.decodeUTF8=t.parseSetting(i,"decodeUTF8",!0),i.showDecoded=t.parseSetting(i,"showDecoded",!0),i.asHTML=t.parseSetting(i,"asHTML",!0),i.indent=t.parseSetting(i,"indent",4),i.break=t.parseSetting(i,"break",!0),i.compact=t.parseSetting(i,"compact",!1),i.binaryAsHex=t.parseSetting(i,"binaryAsHex",!0),i.escapeWhitespace=t.parseSetting(i,"escapeWhitespace",!0),i.highlightControlCharacter=t.parseSetting(i,"highlightControlCharacter",!1),i.escapeYQLStrings=t.parseSetting(i,"escapeYQLStrings",!0),i.nonBreakingIndent=t.parseSetting(i,"nonBreakingIndent",!0),i.treatValAsData=t.parseSetting(i,"treatValAsData",!1),i.validateSrcUrl=t.parseSetting(i,"validateSrcUrl",(()=>!1)),i.normalizeUrl=t.parseSetting(i,"normalizeUrl",(e=>encodeURI(e))),g(s(e,i),i))}c.list=i(34529)(g),c.map=i(8603)(g),c.string=i(88608)(g),c.number=i(94484)(g),c.int64=i(64066)(g),c.uint64=i(2539)(g),c.double=i(66668)(g),c.boolean=i(50629)(g),c.null=i(17184)(g),c.tagged=i(57233)(g),c["yql.list"]=i(56976)(g),c["yql.stream"]=i(89896)(g),c["yql.tuple"]=i(21152)(g),c["yql.struct"]=i(23157)(g),c["yql.dict"]=i(9208)(g),c["yql.string"]=i(96409)(g),c["yql.utf8"]=i(37035)(g),c["yql.int64"]=i(38785)(g),c["yql.int8"]=c["yql.int64"],c["yql.int16"]=c["yql.int64"],c["yql.int32"]=c["yql.int64"],c["yql.uint64"]=i(10602)(g),c["yql.uint8"]=c["yql.uint64"],c["yql.uint16"]=c["yql.uint64"],c["yql.uint32"]=c["yql.uint64"],c["yql.double"]=i(21377)(g),c["yql.float"]=c["yql.double"],c["yql.decimal"]=i(46133)(g),c["yql.bool"]=i(43932)(g),c["yql.date"]=i(84316)(g),c["yql.date32"]=c["yql.date"],c["yql.datetime"]=i(20897)(g),c["yql.datetime64"]=c["yql.datetime"],c["yql.timestamp"]=i(75162)(g),c["yql.timestamp64"]=c["yql.timestamp"],c["yql.tzdate"]=i(29818)(g),c["yql.tzdate32"]=i(29818)(g),c["yql.tzdatetime"]=i(93599)(g),c["yql.tzdatetime64"]=i(93599)(g),c["yql.tztimestamp"]=i(79928)(g),c["yql.tztimestamp64"]=i(79928)(g),c["yql.interval"]=i(37301)(g),c["yql.interval64"]=c["yql.interval"],c["yql.uuid"]=i(25783)(g),c["yql.null"]=i(80449)(g),c["yql.variant"]=i(10411)(g),c["yql.enum"]=i(36317)(g),c["yql.set"]=i(35762)(g),c["yql.json"]=i(92778)(g),c["yql.yson"]=i(41893)(g),c["yql.tagged"]=i(74688)(g),c["yql.pg"]=i(14853)(g),e.exports={format:m,formatFromYSON:function(e,t){return m(e,t,s)},formatFromYQL:function(e,t){return m(e,t,n)},formatRaw:function(e,t){return(t=t||{}).format="json",t.showDecoded=!1,t.compact=!1,t.escapeWhitespace=!0,m(e,t,r)},formatAttributes:d,formatKey:h,formatValue:l}}()},37472:(e,t,i)=>{"use strict";i.d(t,{G6:()=>g,Mn:()=>d,iZ:()=>h});var s=i(84565),n=i(25890),r=i(90766),o=i(44759),a=i(83993),c=i(41234),l=i(42522);function h(e){return"object"===typeof e&&"visibility"in e&&"data"in e}function d(e){switch(e){case!0:return 1;case!1:return 0;default:return e}}function u(e){return"boolean"===typeof e.collapsible}class g{constructor(e,t,i,s={}){this.user=e,this.list=t,this.rootRef=[],this.eventBufferer=new c.at,this._onDidChangeCollapseState=new c.vl,this.onDidChangeCollapseState=this.eventBufferer.wrapEvent(this._onDidChangeCollapseState.event),this._onDidChangeRenderNodeCount=new c.vl,this.onDidChangeRenderNodeCount=this.eventBufferer.wrapEvent(this._onDidChangeRenderNodeCount.event),this._onDidSplice=new c.vl,this.onDidSplice=this._onDidSplice.event,this.refilterDelayer=new r.ve(o.h),this.collapseByDefault="undefined"!==typeof s.collapseByDefault&&s.collapseByDefault,this.allowNonCollapsibleParents=s.allowNonCollapsibleParents??!1,this.filter=s.filter,this.autoExpandSingleChildren="undefined"!==typeof s.autoExpandSingleChildren&&s.autoExpandSingleChildren,this.root={parent:void 0,element:i,children:[],depth:0,visibleChildrenCount:0,visibleChildIndex:-1,collapsible:!1,collapsed:!1,renderNodeCount:0,visibility:1,visible:!0,filterData:void 0}}splice(e,t,i=l.f.empty(),n={}){if(0===e.length)throw new s.jh(this.user,"Invalid tree location");n.diffIdentityProvider?this.spliceSmart(n.diffIdentityProvider,e,t,i,n):this.spliceSimple(e,t,i,n)}spliceSmart(e,t,i,s=l.f.empty(),n,r=n.diffDepth??0){const{parentNode:o}=this.getParentNodeWithListIndex(t);if(!o.lastDiffIds)return this.spliceSimple(t,i,s,n);const c=[...s],h=t[t.length-1],d=new a.uP({getElements:()=>o.lastDiffIds},{getElements:()=>[...o.children.slice(0,h),...c,...o.children.slice(h+i)].map((t=>e.getId(t.element).toString()))}).ComputeDiff(!1);if(d.quitEarly)return o.lastDiffIds=void 0,this.spliceSimple(t,i,c,n);const u=t.slice(0,-1),g=(t,i,s)=>{if(r>0)for(let o=0;ot.originalStart-e.originalStart)))g(p,m,p-(a.originalStart+a.originalLength)),p=a.originalStart,m=a.modifiedStart-h,this.spliceSimple([...u,p],a.originalLength,l.f.slice(c,m,m+a.modifiedLength),n);g(p,m,p)}spliceSimple(e,t,i=l.f.empty(),{onDidCreateNode:s,onDidDeleteNode:r,diffIdentityProvider:o}){const{parentNode:a,listIndex:c,revealed:h,visible:d}=this.getParentNodeWithListIndex(e),u=[],g=l.f.map(i,(e=>this.createTreeNode(e,a,a.visible?1:0,h,u,s))),p=e[e.length-1];let m=0;for(let n=p;n>=0&&no.getId(e.element).toString()))):a.lastDiffIds=a.children.map((e=>o.getId(e.element).toString())):a.lastDiffIds=void 0;let E=0;for(const n of C)n.visible&&E++;if(0!==E)for(let n=p+f.length;ne+(t.visible?t.renderNodeCount:0)),0);this._updateAncestorsRenderNodeCount(a,v-e),this.list.splice(c,e,u)}if(C.length>0&&r){const e=t=>{r(t),t.children.forEach(e)};C.forEach(e)}this._onDidSplice.fire({insertedNodes:f,deletedNodes:C});let b=a;for(;b;){if(2===b.visibility){this.refilterDelayer.trigger((()=>this.refilter()));break}b=b.parent}}rerender(e){if(0===e.length)throw new s.jh(this.user,"Invalid tree location");const{node:t,listIndex:i,revealed:n}=this.getTreeNodeWithListIndex(e);t.visible&&n&&this.list.splice(i,1,[t])}has(e){return this.hasTreeNode(e)}getListIndex(e){const{listIndex:t,visible:i,revealed:s}=this.getTreeNodeWithListIndex(e);return i&&s?t:-1}getListRenderCount(e){return this.getTreeNode(e).renderNodeCount}isCollapsible(e){return this.getTreeNode(e).collapsible}setCollapsible(e,t){const i=this.getTreeNode(e);"undefined"===typeof t&&(t=!i.collapsible);const s={collapsible:t};return this.eventBufferer.bufferEvents((()=>this._setCollapseState(e,s)))}isCollapsed(e){return this.getTreeNode(e).collapsed}setCollapsed(e,t,i){const s=this.getTreeNode(e);"undefined"===typeof t&&(t=!s.collapsed);const n={collapsed:t,recursive:i||!1};return this.eventBufferer.bufferEvents((()=>this._setCollapseState(e,n)))}_setCollapseState(e,t){const{node:i,listIndex:s,revealed:n}=this.getTreeNodeWithListIndex(e),r=this._setListNodeCollapseState(i,s,n,t);if(i!==this.root&&this.autoExpandSingleChildren&&r&&!u(t)&&i.collapsible&&!i.collapsed&&!t.recursive){let s=-1;for(let e=0;e-1){s=-1;break}s=e}}s>-1&&this._setCollapseState([...e,s],t)}return r}_setListNodeCollapseState(e,t,i,s){const n=this._setNodeCollapseState(e,s,!1);if(!i||!e.visible||!n)return n;const r=e.renderNodeCount,o=this.updateNodeAfterCollapseChange(e),a=r-(-1===t?0:1);return this.list.splice(t+1,a,o.slice(1)),n}_setNodeCollapseState(e,t,i){let s;if(e===this.root?s=!1:(u(t)?(s=e.collapsible!==t.collapsible,e.collapsible=t.collapsible):e.collapsible?(s=e.collapsed!==t.collapsed,e.collapsed=t.collapsed):s=!1,s&&this._onDidChangeCollapseState.fire({node:e,deep:i})),!u(t)&&t.recursive)for(const n of e.children)s=this._setNodeCollapseState(n,t,!0)||s;return s}expandTo(e){this.eventBufferer.bufferEvents((()=>{let t=this.getTreeNode(e);for(;t.parent;)t=t.parent,e=e.slice(0,e.length-1),t.collapsed&&this._setCollapseState(e,{collapsed:!1,recursive:!1})}))}refilter(){const e=this.root.renderNodeCount,t=this.updateNodeAfterFilterChange(this.root);this.list.splice(0,e,t),this.refilterDelayer.cancel()}createTreeNode(e,t,i,s,n,r){const o={parent:t,element:e.element,children:[],depth:t.depth+1,visibleChildrenCount:0,visibleChildIndex:-1,collapsible:"boolean"===typeof e.collapsible?e.collapsible:"undefined"!==typeof e.collapsed,collapsed:"undefined"===typeof e.collapsed?this.collapseByDefault:e.collapsed,renderNodeCount:1,visibility:1,visible:!0,filterData:void 0},a=this._filterNode(o,i);o.visibility=a,s&&n.push(o);const c=e.children||l.f.empty(),h=s&&0!==a&&!o.collapsed;let d=0,u=1;for(const l of c){const e=this.createTreeNode(l,o,a,h,n,r);o.children.push(e),u+=e.renderNodeCount,e.visible&&(e.visibleChildIndex=d++)}return this.allowNonCollapsibleParents||(o.collapsible=o.collapsible||o.children.length>0),o.visibleChildrenCount=d,o.visible=2===a?d>0:1===a,o.visible?o.collapsed||(o.renderNodeCount=u):(o.renderNodeCount=0,s&&n.pop()),r?.(o),o}updateNodeAfterCollapseChange(e){const t=e.renderNodeCount,i=[];return this._updateNodeAfterCollapseChange(e,i),this._updateAncestorsRenderNodeCount(e.parent,i.length-t),i}_updateNodeAfterCollapseChange(e,t){if(!1===e.visible)return 0;if(t.push(e),e.renderNodeCount=1,!e.collapsed)for(const i of e.children)e.renderNodeCount+=this._updateNodeAfterCollapseChange(i,t);return this._onDidChangeRenderNodeCount.fire(e),e.renderNodeCount}updateNodeAfterFilterChange(e){const t=e.renderNodeCount,i=[];return this._updateNodeAfterFilterChange(e,e.visible?1:0,i),this._updateAncestorsRenderNodeCount(e.parent,i.length-t),i}_updateNodeAfterFilterChange(e,t,i,s=!0){let n;if(e!==this.root){if(n=this._filterNode(e,t),0===n)return e.visible=!1,e.renderNodeCount=0,!1;s&&i.push(e)}const r=i.length;e.renderNodeCount=e===this.root?0:1;let o=!1;if(e.collapsed&&0===n)e.visibleChildrenCount=0;else{let t=0;for(const r of e.children)o=this._updateNodeAfterFilterChange(r,n,i,s&&!e.collapsed)||o,r.visible&&(r.visibleChildIndex=t++);e.visibleChildrenCount=t}return e!==this.root&&(e.visible=2===n?o:1===n,e.visibility=n),e.visible?e.collapsed||(e.renderNodeCount+=i.length-r):(e.renderNodeCount=0,s&&i.pop()),this._onDidChangeRenderNodeCount.fire(e),e.visible}_updateAncestorsRenderNodeCount(e,t){if(0!==t)for(;e;)e.renderNodeCount+=t,this._onDidChangeRenderNodeCount.fire(e),e=e.parent}_filterNode(e,t){const i=this.filter?this.filter.filter(e.element,t):1;return"boolean"===typeof i?(e.filterData=void 0,i?1:0):h(i)?(e.filterData=i.data,d(i.visibility)):(e.filterData=void 0,d(i))}hasTreeNode(e,t=this.root){if(!e||0===e.length)return!0;const[i,...s]=e;return!(i<0||i>t.children.length)&&this.hasTreeNode(s,t.children[i])}getTreeNode(e,t=this.root){if(!e||0===e.length)return t;const[i,...n]=e;if(i<0||i>t.children.length)throw new s.jh(this.user,"Invalid tree location");return this.getTreeNode(n,t.children[i])}getTreeNodeWithListIndex(e){if(0===e.length)return{node:this.root,listIndex:-1,revealed:!0,visible:!1};const{parentNode:t,listIndex:i,revealed:n,visible:r}=this.getParentNodeWithListIndex(e),o=e[e.length-1];if(o<0||o>t.children.length)throw new s.jh(this.user,"Invalid tree location");const a=t.children[o];return{node:a,listIndex:i,revealed:n,visible:r&&a.visible}}getParentNodeWithListIndex(e,t=this.root,i=0,n=!0,r=!0){const[o,...a]=e;if(o<0||o>t.children.length)throw new s.jh(this.user,"Invalid tree location");for(let s=0;s{"use strict";i.d(t,{_:()=>l});var s=i(8597),n=i(48196),r=i(42904),o=i(20370),a=i(5662),c=i(10146);class l extends a.jG{constructor(e,t){super(),this.options=t,this.text="",this.title="",this.highlights=[],this.didEverRender=!1,this.supportIcons=t?.supportIcons??!1,this.domNode=s.BC(e,s.$("span.monaco-highlighted-label"))}get element(){return this.domNode}set(e,t=[],i="",s){e||(e=""),s&&(e=l.escapeNewLines(e,t)),this.didEverRender&&this.text===e&&this.title===i&&c.aI(this.highlights,t)||(this.text=e,this.title=i,this.highlights=t,this.render())}render(){const e=[];let t=0;for(const i of this.highlights){if(i.end===i.start)continue;if(t{s="\r\n"===e?-1:0,n+=i;for(const i of t)i.end<=n||(i.start>=n&&(i.start+=s),i.end>=n&&(i.end+=s));return i+=s,"\u23ce"}))}}},37550:(e,t,i)=>{"use strict";i.r(t),i.d(t,{IMarkerDecorationsService:()=>s});const s=(0,i(63591).u1)("markerDecorationsService")},37734:(e,t,i)=>{"use strict";i.d(t,{$z:()=>f,BA:()=>v,DW:()=>_,Hh:()=>h,Qn:()=>C,dO:()=>m,i_:()=>p,nz:()=>l,wt:()=>g});var s=i(8597),n=i(34072),r=i(47358),o=i(90766),a=i(5662),c=i(66261);class l{constructor(e,t){this.x=e,this.y=t,this._pageCoordinatesBrand=void 0}toClientCoordinates(e){return new h(this.x-e.scrollX,this.y-e.scrollY)}}class h{constructor(e,t){this.clientX=e,this.clientY=t,this._clientCoordinatesBrand=void 0}toPageCoordinates(e){return new l(this.clientX+e.scrollX,this.clientY+e.scrollY)}}class d{constructor(e,t,i,s){this.x=e,this.y=t,this.width=i,this.height=s,this._editorPagePositionBrand=void 0}}class u{constructor(e,t){this.x=e,this.y=t,this._positionRelativeToEditorBrand=void 0}}function g(e){const t=s.BK(e);return new d(t.left,t.top,t.width,t.height)}function p(e,t,i){const s=t.width/e.offsetWidth,n=t.height/e.offsetHeight,r=(i.x-t.x)/s,o=(i.y-t.y)/n;return new u(r,o)}class m extends r.P{constructor(e,t,i){super(s.zk(i),e),this._editorMouseEventBrand=void 0,this.isFromPointerCapture=t,this.pos=new l(this.posx,this.posy),this.editorPos=g(i),this.relativePos=p(i,this.editorPos,this.pos)}}class f{constructor(e){this._editorViewDomNode=e}_create(e){return new m(e,!1,this._editorViewDomNode)}onContextMenu(e,t){return s.ko(e,"contextmenu",(e=>{t(this._create(e))}))}onMouseUp(e,t){return s.ko(e,"mouseup",(e=>{t(this._create(e))}))}onMouseDown(e,t){return s.ko(e,s.Bx.MOUSE_DOWN,(e=>{t(this._create(e))}))}onPointerDown(e,t){return s.ko(e,s.Bx.POINTER_DOWN,(e=>{t(this._create(e),e.pointerId)}))}onMouseLeave(e,t){return s.ko(e,s.Bx.MOUSE_LEAVE,(e=>{t(this._create(e))}))}onMouseMove(e,t){return s.ko(e,"mousemove",(e=>t(this._create(e))))}}class _{constructor(e){this._editorViewDomNode=e}_create(e){return new m(e,!1,this._editorViewDomNode)}onPointerUp(e,t){return s.ko(e,"pointerup",(e=>{t(this._create(e))}))}onPointerDown(e,t){return s.ko(e,s.Bx.POINTER_DOWN,(e=>{t(this._create(e),e.pointerId)}))}onPointerLeave(e,t){return s.ko(e,s.Bx.POINTER_LEAVE,(e=>{t(this._create(e))}))}onPointerMove(e,t){return s.ko(e,"pointermove",(e=>t(this._create(e))))}}class v extends a.jG{constructor(e){super(),this._editorViewDomNode=e,this._globalPointerMoveMonitor=this._register(new n._),this._keydownListener=null}startMonitoring(e,t,i,n,r){this._keydownListener=s.b2(e.ownerDocument,"keydown",(e=>{e.toKeyCodeChord().isModifierKey()||this._globalPointerMoveMonitor.stopMonitoring(!0,e.browserEvent)}),!0),this._globalPointerMoveMonitor.startMonitoring(e,t,i,(e=>{n(new m(e,!0,this._editorViewDomNode))}),(e=>{this._keydownListener.dispose(),r(e)}))}stopMonitoring(){this._globalPointerMoveMonitor.stopMonitoring(!0)}}class C{static{this._idPool=0}constructor(e){this._editor=e,this._instanceId=++C._idPool,this._counter=0,this._rules=new Map,this._garbageCollectionScheduler=new o.uC((()=>this.garbageCollect()),1e3)}createClassNameRef(e){const t=this.getOrCreateRule(e);return t.increaseRefCount(),{className:t.className,dispose:()=>{t.decreaseRefCount(),this._garbageCollectionScheduler.schedule()}}}getOrCreateRule(e){const t=this.computeUniqueKey(e);let i=this._rules.get(t);if(!i){const n=this._counter++;i=new E(t,`dyn-rule-${this._instanceId}-${n}`,s.Cl(this._editor.getContainerDomNode())?this._editor.getContainerDomNode():void 0,e),this._rules.set(t,i)}return i}computeUniqueKey(e){return JSON.stringify(e)}garbageCollect(){for(const e of this._rules.values())e.hasReferences()||(this._rules.delete(e.key),e.dispose())}}class E{constructor(e,t,i,n){this.key=e,this.className=t,this.properties=n,this._referenceCount=0,this._styleElementDisposables=new a.Cm,this._styleElement=s.li(i,void 0,this._styleElementDisposables),this._styleElement.textContent=this.getCssText(this.className,this.properties)}getCssText(e,t){let i=`.${e} {`;for(const s in t){const e=t[s];let n;n="object"===typeof e?(0,c.GuP)(e.id):e;i+=`\n\t${b(s)}: ${n};`}return i+="\n}",i}dispose(){this._styleElementDisposables.dispose(),this._styleElement=void 0}increaseRefCount(){this._referenceCount++}decreaseRefCount(){this._referenceCount--}hasReferences(){return this._referenceCount>0}}function b(e){return e.replace(/(^[A-Z])/,(([e])=>e.toLowerCase())).replace(/([A-Z])/g,(([e])=>`-${e.toLowerCase()}`))}},37882:(e,t,i)=>{"use strict";i.d(t,{R$:()=>p,_k:()=>f,m2:()=>l,pS:()=>g,pz:()=>_,sA:()=>d});var s=i(26690),n=i(91508),r=i(25689);const o="$(",a=new RegExp(`\\$\\(${r.L.iconNameExpression}(?:${r.L.iconModifierExpression})?\\)`,"g"),c=new RegExp(`(\\\\)?${a.source}`,"g");function l(e){return e.replace(c,((e,t)=>t?e:`\\${e}`))}const h=new RegExp(`\\\\${a.source}`,"g");function d(e){return e.replace(h,(e=>`\\${e}`))}const u=new RegExp(`(\\s)?(\\\\)?${a.source}(\\s)?`,"g");function g(e){return-1===e.indexOf(o)?e:e.replace(u,((e,t,i,s)=>i?e:t||s||""))}function p(e){return e?e.replace(/\$\((.*?)\)/g,((e,t)=>` ${t} `)).trim():""}const m=new RegExp(`\\$\\(${r.L.iconNameCharacter}+\\)`,"g");function f(e){m.lastIndex=0;let t="";const i=[];let s=0;for(;;){const n=m.lastIndex,r=m.exec(e),o=e.substring(n,r?.index);if(o.length>0){t+=o;for(let e=0;e{"use strict";i.d(t,{gi:()=>d});var s=i(41234),n=i(5662),r=i(98067);function o(e,t){return!!e[t]}class a{constructor(e,t){this.target=e.target,this.isLeftClick=e.event.leftButton,this.isMiddleClick=e.event.middleButton,this.isRightClick=e.event.rightButton,this.hasTriggerModifier=o(e.event,t.triggerModifier),this.hasSideBySideModifier=o(e.event,t.triggerSideBySideModifier),this.isNoneOrSingleMouseDown=e.event.detail<=1}}class c{constructor(e,t){this.keyCodeIsTriggerKey=e.keyCode===t.triggerKey,this.keyCodeIsSideBySideKey=e.keyCode===t.triggerSideBySideKey,this.hasTriggerModifier=o(e,t.triggerModifier)}}class l{constructor(e,t,i,s){this.triggerKey=e,this.triggerModifier=t,this.triggerSideBySideKey=i,this.triggerSideBySideModifier=s}equals(e){return this.triggerKey===e.triggerKey&&this.triggerModifier===e.triggerModifier&&this.triggerSideBySideKey===e.triggerSideBySideKey&&this.triggerSideBySideModifier===e.triggerSideBySideModifier}}function h(e){return"altKey"===e?r.zx?new l(57,"metaKey",6,"altKey"):new l(5,"ctrlKey",6,"altKey"):r.zx?new l(6,"altKey",57,"metaKey"):new l(6,"altKey",5,"ctrlKey")}class d extends n.jG{constructor(e,t){super(),this._onMouseMoveOrRelevantKeyDown=this._register(new s.vl),this.onMouseMoveOrRelevantKeyDown=this._onMouseMoveOrRelevantKeyDown.event,this._onExecute=this._register(new s.vl),this.onExecute=this._onExecute.event,this._onCancel=this._register(new s.vl),this.onCancel=this._onCancel.event,this._editor=e,this._extractLineNumberFromMouseEvent=t?.extractLineNumberFromMouseEvent??(e=>e.target.position?e.target.position.lineNumber:0),this._opts=h(this._editor.getOption(78)),this._lastMouseMoveEvent=null,this._hasTriggerKeyOnMouseDown=!1,this._lineNumberOnMouseDown=0,this._register(this._editor.onDidChangeConfiguration((e=>{if(e.hasChanged(78)){const e=h(this._editor.getOption(78));if(this._opts.equals(e))return;this._opts=e,this._lastMouseMoveEvent=null,this._hasTriggerKeyOnMouseDown=!1,this._lineNumberOnMouseDown=0,this._onCancel.fire()}}))),this._register(this._editor.onMouseMove((e=>this._onEditorMouseMove(new a(e,this._opts))))),this._register(this._editor.onMouseDown((e=>this._onEditorMouseDown(new a(e,this._opts))))),this._register(this._editor.onMouseUp((e=>this._onEditorMouseUp(new a(e,this._opts))))),this._register(this._editor.onKeyDown((e=>this._onEditorKeyDown(new c(e,this._opts))))),this._register(this._editor.onKeyUp((e=>this._onEditorKeyUp(new c(e,this._opts))))),this._register(this._editor.onMouseDrag((()=>this._resetHandler()))),this._register(this._editor.onDidChangeCursorSelection((e=>this._onDidChangeCursorSelection(e)))),this._register(this._editor.onDidChangeModel((e=>this._resetHandler()))),this._register(this._editor.onDidChangeModelContent((()=>this._resetHandler()))),this._register(this._editor.onDidScrollChange((e=>{(e.scrollTopChanged||e.scrollLeftChanged)&&this._resetHandler()})))}_onDidChangeCursorSelection(e){e.selection&&e.selection.startColumn!==e.selection.endColumn&&this._resetHandler()}_onEditorMouseMove(e){this._lastMouseMoveEvent=e,this._onMouseMoveOrRelevantKeyDown.fire([e,null])}_onEditorMouseDown(e){this._hasTriggerKeyOnMouseDown=e.hasTriggerModifier,this._lineNumberOnMouseDown=this._extractLineNumberFromMouseEvent(e)}_onEditorMouseUp(e){const t=this._extractLineNumberFromMouseEvent(e);this._hasTriggerKeyOnMouseDown&&this._lineNumberOnMouseDown&&this._lineNumberOnMouseDown===t&&this._onExecute.fire(e)}_onEditorKeyDown(e){this._lastMouseMoveEvent&&(e.keyCodeIsTriggerKey||e.keyCodeIsSideBySideKey&&e.hasTriggerModifier)?this._onMouseMoveOrRelevantKeyDown.fire([this._lastMouseMoveEvent,e]):e.hasTriggerModifier&&this._onCancel.fire()}_onEditorKeyUp(e){e.keyCodeIsTriggerKey&&this._onCancel.fire()}_resetHandler(){this._lastMouseMoveEvent=null,this._hasTriggerKeyOnMouseDown=!1,this._onCancel.fire()}}},37954:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"fsharp",extensions:[".fs",".fsi",".ml",".mli",".fsx",".fsscript"],aliases:["F#","FSharp","fsharp"],loader:()=>i.e(47692).then(i.bind(i,47692))})},38280:(e,t,i)=>{"use strict";i.d(t,{O:()=>P});var s=i(25890),n=i(5662),r=i(91508),o=i(7085),a=i(36677),c=i(75326),l=i(17469),h=i(87289),d=i(67841),u=i(37227),g=i(29319),p=i(79326),m=i(98067);function f(e,t=m.uF){return(0,p.No)(e,t)?e.charAt(0).toUpperCase()+e.slice(1):e}Object.create(null);var _=i(74027),v=i(89403),C=i(58255),E=i(78209),b=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},S=function(e,t){return function(i,s){t(i,s,e)}};Object.freeze({CURRENT_YEAR:!0,CURRENT_YEAR_SHORT:!0,CURRENT_MONTH:!0,CURRENT_DATE:!0,CURRENT_HOUR:!0,CURRENT_MINUTE:!0,CURRENT_SECOND:!0,CURRENT_DAY_NAME:!0,CURRENT_DAY_NAME_SHORT:!0,CURRENT_MONTH_NAME:!0,CURRENT_MONTH_NAME_SHORT:!0,CURRENT_SECONDS_UNIX:!0,CURRENT_TIMEZONE_OFFSET:!0,SELECTION:!0,CLIPBOARD:!0,TM_SELECTED_TEXT:!0,TM_CURRENT_LINE:!0,TM_CURRENT_WORD:!0,TM_LINE_INDEX:!0,TM_LINE_NUMBER:!0,TM_FILENAME:!0,TM_FILENAME_BASE:!0,TM_DIRECTORY:!0,TM_FILEPATH:!0,CURSOR_INDEX:!0,CURSOR_NUMBER:!0,RELATIVE_FILEPATH:!0,BLOCK_COMMENT_START:!0,BLOCK_COMMENT_END:!0,LINE_COMMENT:!0,WORKSPACE_NAME:!0,WORKSPACE_FOLDER:!0,RANDOM:!0,RANDOM_HEX:!0,UUID:!0});class y{constructor(e){this._delegates=e}resolve(e){for(const t of this._delegates){const i=t.resolve(e);if(void 0!==i)return i}}}class w{constructor(e,t,i,s){this._model=e,this._selection=t,this._selectionIdx=i,this._overtypingCapturer=s}resolve(e){const{name:t}=e;if("SELECTION"===t||"TM_SELECTED_TEXT"===t){let t=this._model.getValueInRange(this._selection)||void 0,i=this._selection.startLineNumber!==this._selection.endLineNumber;if(!t&&this._overtypingCapturer){const e=this._overtypingCapturer.getLastOvertypedInfo(this._selectionIdx);e&&(t=e.value,i=e.multiline)}if(t&&i&&e.snippet){const i=this._model.getLineContent(this._selection.startLineNumber),s=(0,r.UU)(i,0,this._selection.startColumn-1);let n=s;e.snippet.walk((t=>t!==e&&(t instanceof g.EY&&(n=(0,r.UU)((0,r.uz)(t.value).pop())),!0)));const o=(0,r.Qp)(n,s);t=t.replace(/(\r\n|\r|\n)(.*)/g,((e,t,i)=>`${t}${n.substr(o)}${i}`))}return t}if("TM_CURRENT_LINE"===t)return this._model.getLineContent(this._selection.positionLineNumber);if("TM_CURRENT_WORD"===t){const e=this._model.getWordAtPosition({lineNumber:this._selection.positionLineNumber,column:this._selection.positionColumn});return e&&e.word||void 0}return"TM_LINE_INDEX"===t?String(this._selection.positionLineNumber-1):"TM_LINE_NUMBER"===t?String(this._selection.positionLineNumber):"CURSOR_INDEX"===t?String(this._selectionIdx):"CURSOR_NUMBER"===t?String(this._selectionIdx+1):void 0}}class R{constructor(e,t){this._labelService=e,this._model=t}resolve(e){const{name:t}=e;if("TM_FILENAME"===t)return _.P8(this._model.uri.fsPath);if("TM_FILENAME_BASE"===t){const e=_.P8(this._model.uri.fsPath),t=e.lastIndexOf(".");return t<=0?e:e.slice(0,t)}return"TM_DIRECTORY"===t?"."===_.pD(this._model.uri.fsPath)?"":this._labelService.getUriLabel((0,v.pD)(this._model.uri)):"TM_FILEPATH"===t?this._labelService.getUriLabel(this._model.uri):"RELATIVE_FILEPATH"===t?this._labelService.getUriLabel(this._model.uri,{relative:!0,noPrefix:!0}):void 0}}class L{constructor(e,t,i,s){this._readClipboardText=e,this._selectionIdx=t,this._selectionCount=i,this._spread=s}resolve(e){if("CLIPBOARD"!==e.name)return;const t=this._readClipboardText();if(t){if(this._spread){const e=t.split(/\r\n|\n|\r/).filter((e=>!(0,r.AV)(e)));if(e.length===this._selectionCount)return e[this._selectionIdx]}return t}}}let T=class{constructor(e,t,i){this._model=e,this._selection=t,this._languageConfigurationService=i}resolve(e){const{name:t}=e,i=this._model.getLanguageIdAtPosition(this._selection.selectionStartLineNumber,this._selection.selectionStartColumn),s=this._languageConfigurationService.getLanguageConfiguration(i).comments;if(s)return"LINE_COMMENT"===t?s.lineCommentToken||void 0:"BLOCK_COMMENT_START"===t?s.blockCommentStartToken||void 0:"BLOCK_COMMENT_END"===t&&s.blockCommentEndToken||void 0}};T=b([S(2,l.JZ)],T);class x{constructor(){this._date=new Date}static{this.dayNames=[E.kg("Sunday","Sunday"),E.kg("Monday","Monday"),E.kg("Tuesday","Tuesday"),E.kg("Wednesday","Wednesday"),E.kg("Thursday","Thursday"),E.kg("Friday","Friday"),E.kg("Saturday","Saturday")]}static{this.dayNamesShort=[E.kg("SundayShort","Sun"),E.kg("MondayShort","Mon"),E.kg("TuesdayShort","Tue"),E.kg("WednesdayShort","Wed"),E.kg("ThursdayShort","Thu"),E.kg("FridayShort","Fri"),E.kg("SaturdayShort","Sat")]}static{this.monthNames=[E.kg("January","January"),E.kg("February","February"),E.kg("March","March"),E.kg("April","April"),E.kg("May","May"),E.kg("June","June"),E.kg("July","July"),E.kg("August","August"),E.kg("September","September"),E.kg("October","October"),E.kg("November","November"),E.kg("December","December")]}static{this.monthNamesShort=[E.kg("JanuaryShort","Jan"),E.kg("FebruaryShort","Feb"),E.kg("MarchShort","Mar"),E.kg("AprilShort","Apr"),E.kg("MayShort","May"),E.kg("JuneShort","Jun"),E.kg("JulyShort","Jul"),E.kg("AugustShort","Aug"),E.kg("SeptemberShort","Sep"),E.kg("OctoberShort","Oct"),E.kg("NovemberShort","Nov"),E.kg("DecemberShort","Dec")]}resolve(e){const{name:t}=e;if("CURRENT_YEAR"===t)return String(this._date.getFullYear());if("CURRENT_YEAR_SHORT"===t)return String(this._date.getFullYear()).slice(-2);if("CURRENT_MONTH"===t)return String(this._date.getMonth().valueOf()+1).padStart(2,"0");if("CURRENT_DATE"===t)return String(this._date.getDate().valueOf()).padStart(2,"0");if("CURRENT_HOUR"===t)return String(this._date.getHours().valueOf()).padStart(2,"0");if("CURRENT_MINUTE"===t)return String(this._date.getMinutes().valueOf()).padStart(2,"0");if("CURRENT_SECOND"===t)return String(this._date.getSeconds().valueOf()).padStart(2,"0");if("CURRENT_DAY_NAME"===t)return x.dayNames[this._date.getDay()];if("CURRENT_DAY_NAME_SHORT"===t)return x.dayNamesShort[this._date.getDay()];if("CURRENT_MONTH_NAME"===t)return x.monthNames[this._date.getMonth()];if("CURRENT_MONTH_NAME_SHORT"===t)return x.monthNamesShort[this._date.getMonth()];if("CURRENT_SECONDS_UNIX"===t)return String(Math.floor(this._date.getTime()/1e3));if("CURRENT_TIMEZONE_OFFSET"===t){const e=this._date.getTimezoneOffset(),t=e>0?"-":"+",i=Math.trunc(Math.abs(e/60)),s=i<10?"0"+i:i,n=Math.abs(e)-60*i;return t+s+":"+(n<10?"0"+n:n)}}}class k{constructor(e){this._workspaceService=e}resolve(e){if(!this._workspaceService)return;const t=(0,u.Q_)(this._workspaceService.getWorkspace());return(0,u.A7)(t)?void 0:"WORKSPACE_NAME"===e.name?this._resolveWorkspaceName(t):"WORKSPACE_FOLDER"===e.name?this._resoveWorkspacePath(t):void 0}_resolveWorkspaceName(e){if((0,u.jB)(e))return _.P8(e.uri.path);let t=_.P8(e.configPath.path);return t.endsWith(u.kF)&&(t=t.substr(0,t.length-u.kF.length-1)),t}_resoveWorkspacePath(e){if((0,u.jB)(e))return f(e.uri.fsPath);const t=_.P8(e.configPath.path);let i=e.configPath.fsPath;return i.endsWith(t)&&(i=i.substr(0,i.length-t.length-1)),i?f(i):"/"}}class A{resolve(e){const{name:t}=e;return"RANDOM"===t?Math.random().toString().slice(-6):"RANDOM_HEX"===t?Math.random().toString(16).slice(-6):"UUID"===t?(0,C.b)():void 0}}var N,I=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},O=function(e,t){return function(i,s){t(i,s,e)}};class D{static{this._decor={active:h.kI.register({description:"snippet-placeholder-1",stickiness:0,className:"snippet-placeholder"}),inactive:h.kI.register({description:"snippet-placeholder-2",stickiness:1,className:"snippet-placeholder"}),activeFinal:h.kI.register({description:"snippet-placeholder-3",stickiness:1,className:"finish-snippet-placeholder"}),inactiveFinal:h.kI.register({description:"snippet-placeholder-4",stickiness:1,className:"finish-snippet-placeholder"})}}constructor(e,t,i){this._editor=e,this._snippet=t,this._snippetLineLeadingWhitespace=i,this._offset=-1,this._nestingLevel=1,this._placeholderGroups=(0,s.$z)(t.placeholders,g.Or.compareByIndex),this._placeholderGroupsIdx=-1}initialize(e){this._offset=e.newPosition}dispose(){this._placeholderDecorations&&this._editor.removeDecorations([...this._placeholderDecorations.values()]),this._placeholderGroups.length=0}_initDecorations(){if(-1===this._offset)throw new Error("Snippet not initialized!");if(this._placeholderDecorations)return;this._placeholderDecorations=new Map;const e=this._editor.getModel();this._editor.changeDecorations((t=>{for(const i of this._snippet.placeholders){const s=this._snippet.offset(i),n=this._snippet.fullLen(i),r=a.Q.fromPositions(e.getPositionAt(this._offset+s),e.getPositionAt(this._offset+s+n)),o=i.isFinalTabstop?D._decor.inactiveFinal:D._decor.inactive,c=t.addDecoration(r,o);this._placeholderDecorations.set(i,c)}}))}move(e){if(!this._editor.hasModel())return[];if(this._initDecorations(),this._placeholderGroupsIdx>=0){const e=[];for(const t of this._placeholderGroups[this._placeholderGroupsIdx])if(t.transform){const i=this._placeholderDecorations.get(t),s=this._editor.getModel().getDecorationRange(i),n=this._editor.getModel().getValueInRange(s),r=t.transform.resolve(n).split(/\r\n|\r|\n/);for(let e=1;e0&&this._editor.executeEdits("snippet.placeholderTransform",e)}let t=!1;!0===e&&this._placeholderGroupsIdx0&&(this._placeholderGroupsIdx-=1,t=!0);const i=this._editor.getModel().changeDecorations((e=>{const i=new Set,s=[];for(const n of this._placeholderGroups[this._placeholderGroupsIdx]){const r=this._placeholderDecorations.get(n),o=this._editor.getModel().getDecorationRange(r);s.push(new c.L(o.startLineNumber,o.startColumn,o.endLineNumber,o.endColumn)),t=t&&this._hasPlaceholderBeenCollapsed(n),e.changeDecorationOptions(r,n.isFinalTabstop?D._decor.activeFinal:D._decor.active),i.add(n);for(const t of this._snippet.enclosingPlaceholders(n)){const s=this._placeholderDecorations.get(t);e.changeDecorationOptions(s,t.isFinalTabstop?D._decor.activeFinal:D._decor.active),i.add(t)}}for(const[t,n]of this._placeholderDecorations)i.has(t)||e.changeDecorationOptions(n,t.isFinalTabstop?D._decor.inactiveFinal:D._decor.inactive);return s}));return t?this.move(e):i??[]}_hasPlaceholderBeenCollapsed(e){let t=e;for(;t;){if(t instanceof g.Or){const e=this._placeholderDecorations.get(t);if(this._editor.getModel().getDecorationRange(e).isEmpty()&&t.toString().length>0)return!0}t=t.parent}return!1}get isAtFirstPlaceholder(){return this._placeholderGroupsIdx<=0||0===this._placeholderGroups.length}get isAtLastPlaceholder(){return this._placeholderGroupsIdx===this._placeholderGroups.length-1}get hasPlaceholder(){return this._snippet.placeholders.length>0}get isTrivialSnippet(){if(0===this._snippet.placeholders.length)return!0;if(1===this._snippet.placeholders.length){const[e]=this._snippet.placeholders;if(e.isFinalTabstop&&this._snippet.rightMostDescendant===e)return!0}return!1}computePossibleSelections(){const e=new Map;for(const t of this._placeholderGroups){let i;for(const s of t){if(s.isFinalTabstop)break;i||(i=[],e.set(s.index,i));const t=this._placeholderDecorations.get(s),n=this._editor.getModel().getDecorationRange(t);if(!n){e.delete(s.index);break}i.push(n)}}return e}get activeChoice(){if(!this._placeholderDecorations)return;const e=this._placeholderGroups[this._placeholderGroupsIdx][0];if(!e?.choice)return;const t=this._placeholderDecorations.get(e);if(!t)return;const i=this._editor.getModel().getDecorationRange(t);return i?{range:i,choice:e.choice}:void 0}get hasChoice(){let e=!1;return this._snippet.walk((t=>(e=t instanceof g.GR,!e))),e}merge(e){const t=this._editor.getModel();this._nestingLevel*=10,this._editor.changeDecorations((i=>{for(const s of this._placeholderGroups[this._placeholderGroupsIdx]){const n=e.shift();console.assert(-1!==n._offset),console.assert(!n._placeholderDecorations);const r=n._snippet.placeholderInfo.last.index;for(const e of n._snippet.placeholderInfo.all)e.isFinalTabstop?e.index=s.index+(r+1)/this._nestingLevel:e.index=s.index+e.index/this._nestingLevel;this._snippet.replace(s,n._snippet.children);const o=this._placeholderDecorations.get(s);i.removeDecoration(o),this._placeholderDecorations.delete(s);for(const e of n._snippet.placeholders){const s=n._snippet.offset(e),r=n._snippet.fullLen(e),o=a.Q.fromPositions(t.getPositionAt(n._offset+s),t.getPositionAt(n._offset+s+r)),c=i.addDecoration(o,D._decor.inactive);this._placeholderDecorations.set(e,c)}}this._placeholderGroups=(0,s.$z)(this._snippet.placeholders,g.Or.compareByIndex)}))}}const M={overwriteBefore:0,overwriteAfter:0,adjustWhitespace:!0,clipboardText:void 0,overtypingCapturer:void 0};let P=N=class{static adjustWhitespace(e,t,i,s,n){const o=e.getLineContent(t.lineNumber),a=(0,r.UU)(o,0,t.column-1);let c;return s.walk((t=>{if(!(t instanceof g.EY)||t.parent instanceof g.GR)return!0;if(n&&!n.has(t))return!0;const r=t.value.split(/\r\n|\r|\n/);if(i){const i=s.offset(t);if(0===i)r[0]=e.normalizeIndentation(r[0]);else{c=c??s.toString();const t=c.charCodeAt(i-1);10!==t&&13!==t||(r[0]=e.normalizeIndentation(a+r[0]))}for(let t=1;te.get(u.VR))),v=e.invokeWithinContext((e=>new R(e.get(d.L),f))),C=()=>c,E=f.getValueInRange(N.adjustSelection(f,e.getSelection(),i,0)),b=f.getValueInRange(N.adjustSelection(f,e.getSelection(),0,s)),S=f.getLineFirstNonWhitespaceColumn(e.getSelection().positionLineNumber),I=e.getSelections().map(((e,t)=>({selection:e,idx:t}))).sort(((e,t)=>a.Q.compareRangesUsingStarts(e.selection,t.selection)));for(const{selection:a,idx:d}of I){let c=N.adjustSelection(f,a,i,0),u=N.adjustSelection(f,a,0,s);E!==f.getValueInRange(c)&&(c=a),b!==f.getValueInRange(u)&&(u=a);const R=a.setStartPosition(c.startLineNumber,c.startColumn).setEndPosition(u.endLineNumber,u.endColumn),O=(new g.fr).parse(t,!0,n),M=R.getStartPosition(),P=N.adjustWhitespace(f,M,r||d>0&&S!==f.getLineFirstNonWhitespaceColumn(a.positionLineNumber),O);O.resolveVariables(new y([v,new L(C,d,I.length,"spread"===e.getOption(79)),new w(f,a,d,l),new T(f,a,h),new x,new k(_),new A])),p[d]=o.k.replace(R,O.toString()),p[d].identifier={major:d,minor:0},p[d]._isTracked=!0,m[d]=new D(e,O,P)}return{edits:p,snippets:m}}static createEditsAndSnippetsFromEdits(e,t,i,s,n,r,c){if(!e.hasModel()||0===t.length)return{edits:[],snippets:[]};const l=[],h=e.getModel(),p=new g.fr,m=new g.mQ,f=new y([e.invokeWithinContext((e=>new R(e.get(d.L),h))),new L((()=>n),0,e.getSelections().length,"spread"===e.getOption(79)),new w(h,e.getSelection(),0,r),new T(h,e.getSelection(),c),new x,new k(e.invokeWithinContext((e=>e.get(u.VR)))),new A]);t=t.sort(((e,t)=>a.Q.compareRangesUsingStarts(e.range,t.range)));let _=0;for(let d=0;d0){const i=t[d-1].range,s=a.Q.fromPositions(i.getEndPosition(),e.getStartPosition()),n=new g.EY(h.getValueInRange(s));m.appendChild(n),_+=n.value.length}const s=p.parseFragment(i,m);N.adjustWhitespace(h,e.getStartPosition(),!0,m,new Set(s)),m.resolveVariables(f);const n=m.toString(),r=n.slice(_);_=n.length;const c=o.k.replace(e,r);c.identifier={major:d,minor:0},c._isTracked=!0,l.push(c)}return p.ensureFinalTabstop(m,i,!0),{edits:l,snippets:[new D(e,m,"")]}}constructor(e,t,i=M,s){this._editor=e,this._template=t,this._options=i,this._languageConfigurationService=s,this._templateMerges=[],this._snippets=[]}dispose(){(0,n.AS)(this._snippets)}_logInfo(){return`template="${this._template}", merged_templates="${this._templateMerges.join(" -> ")}"`}insert(){if(!this._editor.hasModel())return;const{edits:e,snippets:t}="string"===typeof this._template?N.createEditsAndSnippetsFromSelections(this._editor,this._template,this._options.overwriteBefore,this._options.overwriteAfter,!1,this._options.adjustWhitespace,this._options.clipboardText,this._options.overtypingCapturer,this._languageConfigurationService):N.createEditsAndSnippetsFromEdits(this._editor,this._template,!1,this._options.adjustWhitespace,this._options.clipboardText,this._options.overtypingCapturer,this._languageConfigurationService);this._snippets=t,this._editor.executeEdits("snippet",e,(e=>{const i=e.filter((e=>!!e.identifier));for(let s=0;sc.L.fromPositions(e.range.getEndPosition())))})),this._editor.revealRange(this._editor.getSelections()[0])}merge(e,t=M){if(!this._editor.hasModel())return;this._templateMerges.push([this._snippets[0]._nestingLevel,this._snippets[0]._placeholderGroupsIdx,e]);const{edits:i,snippets:s}=N.createEditsAndSnippetsFromSelections(this._editor,e,t.overwriteBefore,t.overwriteAfter,!0,t.adjustWhitespace,t.clipboardText,t.overtypingCapturer,this._languageConfigurationService);this._editor.executeEdits("snippet",i,(e=>{const t=e.filter((e=>!!e.identifier));for(let n=0;nc.L.fromPositions(e.range.getEndPosition())))}))}next(){const e=this._move(!0);this._editor.setSelections(e),this._editor.revealPositionInCenterIfOutsideViewport(e[0].getPosition())}prev(){const e=this._move(!1);this._editor.setSelections(e),this._editor.revealPositionInCenterIfOutsideViewport(e[0].getPosition())}_move(e){const t=[];for(const i of this._snippets){const s=i.move(e);t.push(...s)}return t}get isAtFirstPlaceholder(){return this._snippets[0].isAtFirstPlaceholder}get isAtLastPlaceholder(){return this._snippets[0].isAtLastPlaceholder}get hasPlaceholder(){return this._snippets[0].hasPlaceholder}get hasChoice(){return this._snippets[0].hasChoice}get activeChoice(){return this._snippets[0].activeChoice}isSelectionWithinPlaceholders(){if(!this.hasPlaceholder)return!1;const e=this._editor.getSelections();if(e.length{e.push(...s.get(t))}))}e.sort(a.Q.compareRangesUsingStarts);for(const[i,s]of t)if(s.length===e.length){s.sort(a.Q.compareRangesUsingStarts);for(let n=0;n0}};P=N=I([O(3,l.JZ)],P)},38320:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"markdown",extensions:[".md",".markdown",".mdown",".mkdn",".mkd",".mdwn",".mdtxt",".mdtext"],aliases:["Markdown","markdown"],loader:()=>i.e(73478).then(i.bind(i,73478))})},38566:(e,t,i)=>{"use strict";var s;i.d(t,{GB:()=>r,i3:()=>n,l:()=>s}),function(e){e[e.None=0]="None",e[e.Indent=1]="Indent",e[e.IndentOutdent=2]="IndentOutdent",e[e.Outdent=3]="Outdent"}(s||(s={}));class n{constructor(e){if(this._neutralCharacter=null,this._neutralCharacterSearched=!1,this.open=e.open,this.close=e.close,this._inString=!0,this._inComment=!0,this._inRegEx=!0,Array.isArray(e.notIn))for(let t=0,i=e.notIn.length;t{"use strict";i.d(t,{Jk:()=>v,R7:()=>b});var s=i(31450),n=i(15092),r=i(87908),o=i(32799),a=i(97681),c=i(81782),l=i(83069),h=i(36677),d=i(75326),u=i(60002),g=i(17469),p=i(78209),m=i(253),f=i(32848),_=i(28290);class v extends s.DX{constructor(e){super(e),this._inSelectionMode=e.inSelectionMode,this._wordNavigationType=e.wordNavigationType}runEditorCommand(e,t,i){if(!t.hasModel())return;const s=(0,c.i)(t.getOption(132),t.getOption(131)),n=t.getModel(),r=t.getSelections(),a=r.length>1,h=r.map((e=>{const t=new l.y(e.positionLineNumber,e.positionColumn),i=this._move(s,n,t,this._wordNavigationType,a);return this._moveTo(e,i,this._inSelectionMode)}));if(n.pushStackElement(),t._getViewModel().setCursorStates("moveWordCommand",3,h.map((e=>o.MF.fromModelSelection(e)))),1===h.length){const e=new l.y(h[0].positionLineNumber,h[0].positionColumn);t.revealPosition(e,0)}}_moveTo(e,t,i){return i?new d.L(e.selectionStartLineNumber,e.selectionStartColumn,t.lineNumber,t.column):new d.L(t.lineNumber,t.column,t.lineNumber,t.column)}}class C extends v{_move(e,t,i,s,n){return a.z.moveWordLeft(e,t,i,s,n)}}class E extends v{_move(e,t,i,s,n){return a.z.moveWordRight(e,t,i,s)}}class b extends s.DX{constructor(e){super(e),this._whitespaceHeuristics=e.whitespaceHeuristics,this._wordNavigationType=e.wordNavigationType}runEditorCommand(e,t,i){const s=e.get(g.JZ);if(!t.hasModel())return;const r=(0,c.i)(t.getOption(132),t.getOption(131)),o=t.getModel(),a=t.getSelections(),l=t.getOption(6),h=t.getOption(11),d=s.getLanguageConfiguration(o.getLanguageId()).getAutoClosingPairs(),u=t._getViewModel(),p=a.map((e=>{const i=this._delete({wordSeparators:r,model:o,selection:e,whitespaceHeuristics:this._whitespaceHeuristics,autoClosingDelete:t.getOption(9),autoClosingBrackets:l,autoClosingQuotes:h,autoClosingPairs:d,autoClosedCharacters:u.getCursorAutoClosedCharacters()},this._wordNavigationType);return new n.iu(i,"")}));t.pushUndoStop(),t.executeCommands(this.id,p),t.pushUndoStop()}}class S extends b{_delete(e,t){const i=a.z.deleteWordLeft(e,t);return i||new h.Q(1,1,1,1)}}class y extends b{_delete(e,t){const i=a.z.deleteWordRight(e,t);if(i)return i;const s=e.model.getLineCount(),n=e.model.getLineMaxColumn(s);return new h.Q(s,n,s,n)}}class w extends s.ks{constructor(){super({id:"deleteInsideWord",precondition:u.R.writable,label:p.kg("deleteInsideWord","Delete Word"),alias:"Delete Word"})}run(e,t,i){if(!t.hasModel())return;const s=(0,c.i)(t.getOption(132),t.getOption(131)),r=t.getModel(),o=t.getSelections().map((e=>{const t=a.z.deleteInsideWord(s,r,e);return new n.iu(t,"")}));t.pushUndoStop(),t.executeCommands(this.id,o),t.pushUndoStop()}}(0,s.E_)(new class extends C{constructor(){super({inSelectionMode:!1,wordNavigationType:0,id:"cursorWordStartLeft",precondition:void 0})}}),(0,s.E_)(new class extends C{constructor(){super({inSelectionMode:!1,wordNavigationType:2,id:"cursorWordEndLeft",precondition:void 0})}}),(0,s.E_)(new class extends C{constructor(){super({inSelectionMode:!1,wordNavigationType:1,id:"cursorWordLeft",precondition:void 0,kbOpts:{kbExpr:f.M$.and(u.R.textInputFocus,f.M$.and(m.f,_.nd)?.negate()),primary:2063,mac:{primary:527},weight:100}})}}),(0,s.E_)(new class extends C{constructor(){super({inSelectionMode:!0,wordNavigationType:0,id:"cursorWordStartLeftSelect",precondition:void 0})}}),(0,s.E_)(new class extends C{constructor(){super({inSelectionMode:!0,wordNavigationType:2,id:"cursorWordEndLeftSelect",precondition:void 0})}}),(0,s.E_)(new class extends C{constructor(){super({inSelectionMode:!0,wordNavigationType:1,id:"cursorWordLeftSelect",precondition:void 0,kbOpts:{kbExpr:f.M$.and(u.R.textInputFocus,f.M$.and(m.f,_.nd)?.negate()),primary:3087,mac:{primary:1551},weight:100}})}}),(0,s.E_)(new class extends E{constructor(){super({inSelectionMode:!1,wordNavigationType:0,id:"cursorWordStartRight",precondition:void 0})}}),(0,s.E_)(new class extends E{constructor(){super({inSelectionMode:!1,wordNavigationType:2,id:"cursorWordEndRight",precondition:void 0,kbOpts:{kbExpr:f.M$.and(u.R.textInputFocus,f.M$.and(m.f,_.nd)?.negate()),primary:2065,mac:{primary:529},weight:100}})}}),(0,s.E_)(new class extends E{constructor(){super({inSelectionMode:!1,wordNavigationType:2,id:"cursorWordRight",precondition:void 0})}}),(0,s.E_)(new class extends E{constructor(){super({inSelectionMode:!0,wordNavigationType:0,id:"cursorWordStartRightSelect",precondition:void 0})}}),(0,s.E_)(new class extends E{constructor(){super({inSelectionMode:!0,wordNavigationType:2,id:"cursorWordEndRightSelect",precondition:void 0,kbOpts:{kbExpr:f.M$.and(u.R.textInputFocus,f.M$.and(m.f,_.nd)?.negate()),primary:3089,mac:{primary:1553},weight:100}})}}),(0,s.E_)(new class extends E{constructor(){super({inSelectionMode:!0,wordNavigationType:2,id:"cursorWordRightSelect",precondition:void 0})}}),(0,s.E_)(new class extends C{constructor(){super({inSelectionMode:!1,wordNavigationType:3,id:"cursorWordAccessibilityLeft",precondition:void 0})}_move(e,t,i,s,n){return super._move((0,c.i)(r.qB.wordSeparators.defaultValue,e.intlSegmenterLocales),t,i,s,n)}}),(0,s.E_)(new class extends C{constructor(){super({inSelectionMode:!0,wordNavigationType:3,id:"cursorWordAccessibilityLeftSelect",precondition:void 0})}_move(e,t,i,s,n){return super._move((0,c.i)(r.qB.wordSeparators.defaultValue,e.intlSegmenterLocales),t,i,s,n)}}),(0,s.E_)(new class extends E{constructor(){super({inSelectionMode:!1,wordNavigationType:3,id:"cursorWordAccessibilityRight",precondition:void 0})}_move(e,t,i,s,n){return super._move((0,c.i)(r.qB.wordSeparators.defaultValue,e.intlSegmenterLocales),t,i,s,n)}}),(0,s.E_)(new class extends E{constructor(){super({inSelectionMode:!0,wordNavigationType:3,id:"cursorWordAccessibilityRightSelect",precondition:void 0})}_move(e,t,i,s,n){return super._move((0,c.i)(r.qB.wordSeparators.defaultValue,e.intlSegmenterLocales),t,i,s,n)}}),(0,s.E_)(new class extends S{constructor(){super({whitespaceHeuristics:!1,wordNavigationType:0,id:"deleteWordStartLeft",precondition:u.R.writable})}}),(0,s.E_)(new class extends S{constructor(){super({whitespaceHeuristics:!1,wordNavigationType:2,id:"deleteWordEndLeft",precondition:u.R.writable})}}),(0,s.E_)(new class extends S{constructor(){super({whitespaceHeuristics:!0,wordNavigationType:0,id:"deleteWordLeft",precondition:u.R.writable,kbOpts:{kbExpr:u.R.textInputFocus,primary:2049,mac:{primary:513},weight:100}})}}),(0,s.E_)(new class extends y{constructor(){super({whitespaceHeuristics:!1,wordNavigationType:0,id:"deleteWordStartRight",precondition:u.R.writable})}}),(0,s.E_)(new class extends y{constructor(){super({whitespaceHeuristics:!1,wordNavigationType:2,id:"deleteWordEndRight",precondition:u.R.writable})}}),(0,s.E_)(new class extends y{constructor(){super({whitespaceHeuristics:!0,wordNavigationType:2,id:"deleteWordRight",precondition:u.R.writable,kbOpts:{kbExpr:u.R.textInputFocus,primary:2068,mac:{primary:532},weight:100}})}}),(0,s.Fl)(w)},38785:(e,t,i)=>{e.exports=i(64066)},38844:(e,t,i)=>{"use strict";i.d(t,{Qg:()=>u,Ud:()=>l,jD:()=>d});var s=i(51241),n=i(5662),r=i(31308),o=i(49154),a=i(87958),c=i(75326);function l(e){return h.get(e)}class h extends n.jG{static{this._map=new Map}static get(e){let t=h._map.get(e);if(!t){t=new h(e),h._map.set(e,t);const i=e.onDidDispose((()=>{const t=h._map.get(e);t&&(h._map.delete(e),t.dispose(),i.dispose())}))}return t}_beginUpdate(){this._updateCounter++,1===this._updateCounter&&(this._currentTransaction=new o.XL((()=>{})))}_endUpdate(){if(this._updateCounter--,0===this._updateCounter){const e=this._currentTransaction;this._currentTransaction=void 0,e.finish()}}constructor(e){super(),this.editor=e,this._updateCounter=0,this._currentTransaction=void 0,this._model=(0,r.FY)(this,this.editor.getModel()),this.model=this._model,this.isReadonly=(0,r.y0)(this,this.editor.onDidChangeConfiguration,(()=>this.editor.getOption(92))),this._versionId=(0,r.Zh)({owner:this,lazy:!0},this.editor.getModel()?.getVersionId()??null),this.versionId=this._versionId,this._selections=(0,r.Zh)({owner:this,equalsFn:(0,s.KC)((0,s.S3)(c.L.selectionsEqual)),lazy:!0},this.editor.getSelections()??null),this.selections=this._selections,this.isFocused=(0,r.y0)(this,(e=>{const t=this.editor.onDidFocusEditorWidget(e),i=this.editor.onDidBlurEditorWidget(e);return{dispose(){t.dispose(),i.dispose()}}}),(()=>this.editor.hasWidgetFocus())),this.value=(0,a.dQ)(this,(e=>(this.versionId.read(e),this.model.read(e)?.getValue()??"")),((e,t)=>{const i=this.model.get();null!==i&&e!==i.getValue()&&i.setValue(e)})),this.valueIsEmpty=(0,r.un)(this,(e=>(this.versionId.read(e),0===this.editor.getModel()?.getValueLength()))),this.cursorSelection=(0,r.C)({owner:this,equalsFn:(0,s.KC)(c.L.selectionsEqual)},(e=>this.selections.read(e)?.[0]??null)),this.onDidType=(0,r.Yd)(this),this.scrollTop=(0,r.y0)(this.editor.onDidScrollChange,(()=>this.editor.getScrollTop())),this.scrollLeft=(0,r.y0)(this.editor.onDidScrollChange,(()=>this.editor.getScrollLeft())),this.layoutInfo=(0,r.y0)(this.editor.onDidLayoutChange,(()=>this.editor.getLayoutInfo())),this.layoutInfoContentLeft=this.layoutInfo.map((e=>e.contentLeft)),this.layoutInfoDecorationsLeft=this.layoutInfo.map((e=>e.decorationsLeft)),this.contentWidth=(0,r.y0)(this.editor.onDidContentSizeChange,(()=>this.editor.getContentWidth())),this._overlayWidgetCounter=0,this._register(this.editor.onBeginUpdate((()=>this._beginUpdate()))),this._register(this.editor.onEndUpdate((()=>this._endUpdate()))),this._register(this.editor.onDidChangeModel((()=>{this._beginUpdate();try{this._model.set(this.editor.getModel(),this._currentTransaction),this._forceUpdate()}finally{this._endUpdate()}}))),this._register(this.editor.onDidType((e=>{this._beginUpdate();try{this._forceUpdate(),this.onDidType.trigger(this._currentTransaction,e)}finally{this._endUpdate()}}))),this._register(this.editor.onDidChangeModelContent((e=>{this._beginUpdate();try{this._versionId.set(this.editor.getModel()?.getVersionId()??null,this._currentTransaction,e),this._forceUpdate()}finally{this._endUpdate()}}))),this._register(this.editor.onDidChangeCursorSelection((e=>{this._beginUpdate();try{this._selections.set(this.editor.getSelections(),this._currentTransaction,e),this._forceUpdate()}finally{this._endUpdate()}})))}forceUpdate(e){this._beginUpdate();try{if(this._forceUpdate(),!e)return;return e(this._currentTransaction)}finally{this._endUpdate()}}_forceUpdate(){this._beginUpdate();try{this._model.set(this.editor.getModel(),this._currentTransaction),this._versionId.set(this.editor.getModel()?.getVersionId()??null,this._currentTransaction,void 0),this._selections.set(this.editor.getSelections(),this._currentTransaction,void 0)}finally{this._endUpdate()}}getOption(e){return(0,r.y0)(this,(t=>this.editor.onDidChangeConfiguration((i=>{i.hasChanged(e)&&t(void 0)}))),(()=>this.editor.getOption(e)))}setDecorations(e){const t=new n.Cm,i=this.editor.createDecorationsCollection();return t.add((0,r.zL)({owner:this,debugName:()=>`Apply decorations from ${e.debugName}`},(t=>{const s=e.read(t);i.set(s)}))),t.add({dispose:()=>{i.clear()}}),t}createOverlayWidget(e){const t="observableOverlayWidget"+this._overlayWidgetCounter++,i={getDomNode:()=>e.domNode,getPosition:()=>e.position.get(),getId:()=>t,allowEditorOverflow:e.allowEditorOverflow,getMinContentWidthInPx:()=>e.minContentWidthInPx.get()};this.editor.addOverlayWidget(i);const s=(0,r.fm)((t=>{e.position.read(t),e.minContentWidthInPx.read(t),this.editor.layoutOverlayWidget(i)}));return(0,n.s)((()=>{s.dispose(),this.editor.removeOverlayWidget(i)}))}}function d(e,t){return(0,r.ht)({createEmptyChangeSummary:()=>({deltas:[],didChange:!1}),handleChange:(t,i)=>{if(t.didChange(e)){const e=t.change;void 0!==e&&i.deltas.push(e),i.didChange=!0}return!0}},((i,s)=>{const n=e.read(i);s.didChange&&t(n,s.deltas)}))}function u(e,t){const i=new n.Cm,s=d(e,((e,s)=>{i.clear(),t(e,s,i)}));return{dispose(){s.dispose(),i.dispose()}}}},39286:(e,t,i)=>{"use strict";i.d(t,{n:()=>o});var s=i(58925),n=i(83069),r=i(36677);class o{async provideSelectionRanges(e,t){const i=[];for(const s of t){const t=[];i.push(t);const n=new Map;await new Promise((t=>o._bracketsRightYield(t,0,e,s,n))),await new Promise((i=>o._bracketsLeftYield(i,0,e,s,n,t)))}return i}static{this._maxDuration=30}static{this._maxRounds=2}static _bracketsRightYield(e,t,i,n,r){const a=new Map,c=Date.now();for(;;){if(t>=o._maxRounds){e();break}if(!n){e();break}const l=i.bracketPairs.findNextBracket(n);if(!l){e();break}if(Date.now()-c>o._maxDuration){setTimeout((()=>o._bracketsRightYield(e,t+1,i,n,r)));break}if(l.bracketInfo.isOpeningBracket){const e=l.bracketInfo.bracketText,t=a.has(e)?a.get(e):0;a.set(e,t+1)}else{const e=l.bracketInfo.getOpeningBrackets()[0].bracketText;let t=a.has(e)?a.get(e):0;if(t-=1,a.set(e,Math.max(0,t)),t<0){let t=r.get(e);t||(t=new s.w,r.set(e,t)),t.push(l.range)}}n=l.range.getEndPosition()}}static _bracketsLeftYield(e,t,i,s,n,a){const c=new Map,l=Date.now();for(;;){if(t>=o._maxRounds&&0===n.size){e();break}if(!s){e();break}const h=i.bracketPairs.findPrevBracket(s);if(!h){e();break}if(Date.now()-l>o._maxDuration){setTimeout((()=>o._bracketsLeftYield(e,t+1,i,s,n,a)));break}if(h.bracketInfo.isOpeningBracket){const e=h.bracketInfo.bracketText;let t=c.has(e)?c.get(e):0;if(t-=1,c.set(e,Math.max(0,t)),t<0){const t=n.get(e);if(t){const s=t.shift();0===t.size&&n.delete(e);const c=r.Q.fromPositions(h.range.getEndPosition(),s.getStartPosition()),l=r.Q.fromPositions(h.range.getStartPosition(),s.getEndPosition());a.push({range:c}),a.push({range:l}),o._addBracketLeading(i,l,a)}}}else{const e=h.bracketInfo.getOpeningBrackets()[0].bracketText,t=c.has(e)?c.get(e):0;c.set(e,t+1)}s=h.range.getStartPosition()}}static _addBracketLeading(e,t,i){if(t.startLineNumber===t.endLineNumber)return;const s=t.startLineNumber,o=e.getLineFirstNonWhitespaceColumn(s);0!==o&&o!==t.startColumn&&(i.push({range:r.Q.fromPositions(new n.y(s,o),t.getEndPosition())}),i.push({range:r.Q.fromPositions(new n.y(s,1),t.getEndPosition())}));const a=s-1;if(a>0){const s=e.getLineFirstNonWhitespaceColumn(a);s===t.startColumn&&s!==e.getLineLastNonWhitespaceColumn(a)&&(i.push({range:r.Q.fromPositions(new n.y(a,s),t.getEndPosition())}),i.push({range:r.Q.fromPositions(new n.y(a,1),t.getEndPosition())}))}}}},39439:(e,t,i)=>{var s=i(33157),n=i(90552);e.exports=function(e,t,i,r){var o=null==e?0:e.length;return o?(i&&"number"!=typeof i&&n(e,t,i)&&(i=0,r=o),s(e,t,i,r)):[]}},39866:(e,t,i)=>{"use strict";(0,i(34918).K)({id:"python",extensions:[".py",".rpy",".pyw",".cpy",".gyp",".gypi"],aliases:["Python","py"],firstLine:"^#!/.*\\bpython[0-9.-]*\\b",loader:()=>i.e(22372).then(i.bind(i,22372))})},40014:(e,t,i)=>{"use strict";i.d(t,{Ay:()=>C});var s=i(27145),n=i(59284),r=i(8964),o=i(66643),a=i(42392);const c=()=>`ck.${((e,t)=>{let i="";for(let s=e;s>0;--s)i+=t[Math.floor(Math.random()*t.length)];return i})(10,"0123456789abcdefghijklmnopqrstuvwxyz")}`,l=n.memo;var h=i(82435);const d=(0,h.withNaming)({e:"__",m:"_"}),u=(0,h.withNaming)({n:"chartkit-",e:"__",m:"_"});class g extends n.Component{constructor(){super(...arguments),this.state={error:void 0},this.resetError=()=>{this.state.error&&this.setState({error:void 0})}}static getDerivedStateFromError(e){return{error:e}}componentDidCatch(){var e,t;const{error:i}=this.state;i&&(null===(t=(e=this.props).onError)||void 0===t||t.call(e,{error:i}))}componentDidUpdate(e){if(e.data!==this.props.data){const{error:e}=this.state;e&&"code"in e&&e.code===a.iY.NO_DATA&&this.resetError()}}render(){const{error:e}=this.state;if(e){const t=function(e){const t="code"in e&&e.code;return(e.message||t||(0,r.R)("error","label_unknown-error")).toString()}(e);return this.props.renderError?this.props.renderError({error:e,message:t,resetError:this.resetError}):n.createElement("div",null,t)}return this.props.children}}var p=i(74417);const m=u("loader"),f=e=>{var{renderPluginLoader:t}=e,i=(0,s.Tt)(e,["renderPluginLoader"]);const r=null===t||void 0===t?void 0:t();return"undefined"!==typeof r?r:n.createElement("div",{className:m()},n.createElement(p.a,Object.assign({},i)))},_=d("chartkit"),v=e=>{const t=n.useRef(),{instanceRef:i,id:l,type:h,isMobile:d,renderPluginLoader:u}=e,g=(0,s.Tt)(e,["instanceRef","id","type","isMobile","renderPluginLoader"]),p=n.useMemo((()=>c()),[]),m=l||p,v=o.W.get("lang"),C=o.W.get("plugins").find((e=>e.type===h));if(!C)throw new a.R({code:a.iY.UNKNOWN_PLUGIN,message:(0,r.R)("error","label_unknown-plugin",{type:h})});const E=C.renderer;return n.useImperativeHandle(i,(()=>({reflow(e){var i;(null===(i=t.current)||void 0===i?void 0:i.reflow)&&t.current.reflow(e)}})),[]),n.createElement(n.Suspense,{fallback:n.createElement(f,{renderPluginLoader:u})},n.createElement("div",{className:_({mobile:d},"chartkit-theme_common")},n.createElement(E,Object.assign({ref:t,id:m,lang:v},g))))},C=l(n.forwardRef((function(e,t){return n.createElement(g,{onError:e.onError,data:e.data,renderError:e.renderError},n.createElement(v,Object.assign({instanceRef:t},e)))})))},40142:(e,t,i)=>{"use strict";var s=i(24939),n=i(31450),r=i(36677),o=i(60002),a=i(17469),c=i(7085),l=i(83069),h=i(75326);class d{constructor(e,t,i){this.languageConfigurationService=i,this._selection=e,this._insertSpace=t,this._usedEndToken=null}static _haystackHasNeedleAtOffset(e,t,i){if(i<0)return!1;const s=t.length;if(i+s>e.length)return!1;for(let n=0;n=65&&s<=90&&s+32===r)&&!(r>=65&&r<=90&&r+32===s)))return!1}return!0}_createOperationsForBlockComment(e,t,i,s,n,o){const a=e.startLineNumber,c=e.startColumn,l=e.endLineNumber,h=e.endColumn,u=n.getLineContent(a),g=n.getLineContent(l);let p,m=u.lastIndexOf(t,c-1+t.length),f=g.indexOf(i,h-1-i.length);if(-1!==m&&-1!==f)if(a===l){u.substring(m+t.length,f).indexOf(i)>=0&&(m=-1,f=-1)}else{const e=u.substring(m+t.length),s=g.substring(0,f);(e.indexOf(i)>=0||s.indexOf(i)>=0)&&(m=-1,f=-1)}-1!==m&&-1!==f?(s&&m+t.length0&&32===g.charCodeAt(f-1)&&(i=" "+i,f-=1),p=d._createRemoveBlockCommentOperations(new r.Q(a,m+t.length+1,l,f+1),t,i)):(p=d._createAddBlockCommentOperations(e,t,i,this._insertSpace),this._usedEndToken=1===p.length?i:null);for(const r of p)o.addTrackedEditOperation(r.range,r.text)}static _createRemoveBlockCommentOperations(e,t,i){const s=[];return r.Q.isEmpty(e)?s.push(c.k.delete(new r.Q(e.startLineNumber,e.startColumn-t.length,e.endLineNumber,e.endColumn+i.length))):(s.push(c.k.delete(new r.Q(e.startLineNumber,e.startColumn-t.length,e.startLineNumber,e.startColumn))),s.push(c.k.delete(new r.Q(e.endLineNumber,e.endColumn,e.endLineNumber,e.endColumn+i.length)))),s}static _createAddBlockCommentOperations(e,t,i,s){const n=[];return r.Q.isEmpty(e)?n.push(c.k.replace(new r.Q(e.startLineNumber,e.startColumn,e.endLineNumber,e.endColumn),t+" "+i)):(n.push(c.k.insert(new l.y(e.startLineNumber,e.startColumn),t+(s?" ":""))),n.push(c.k.insert(new l.y(e.endLineNumber,e.endColumn),(s?" ":"")+i))),n}getEditOperations(e,t){const i=this._selection.startLineNumber,s=this._selection.startColumn;e.tokenization.tokenizeIfCheap(i);const n=e.getLanguageIdAtPosition(i,s),r=this.languageConfigurationService.getLanguageConfiguration(n).comments;r&&r.blockCommentStartToken&&r.blockCommentEndToken&&this._createOperationsForBlockComment(this._selection,r.blockCommentStartToken,r.blockCommentEndToken,this._insertSpace,e,t)}computeCursorState(e,t){const i=t.getInverseEditOperations();if(2===i.length){const e=i[0],t=i[1];return new h.L(e.range.endLineNumber,e.range.endColumn,t.range.startLineNumber,t.range.startColumn)}{const e=i[0].range,t=this._usedEndToken?-this._usedEndToken.length-1:0;return new h.L(e.endLineNumber,e.endColumn+t,e.endLineNumber,e.endColumn+t)}}}var u=i(91508);class g{constructor(e,t,i,s,n,r,o){this.languageConfigurationService=e,this._selection=t,this._indentSize=i,this._type=s,this._insertSpace=n,this._selectionId=null,this._deltaColumn=0,this._moveEndPositionDown=!1,this._ignoreEmptyLines=r,this._ignoreFirstLine=o||!1}static _gatherPreflightCommentStrings(e,t,i,s){e.tokenization.tokenizeIfCheap(t);const n=e.getLanguageIdAtPosition(t,1),r=s.getLanguageConfiguration(n).comments,o=r?r.lineCommentToken:null;if(!o)return null;const a=[];for(let c=0,l=i-t+1;co?n-1:n}}}var p=i(78209),m=i(27195);class f extends n.ks{constructor(e,t){super(t),this._type=e}run(e,t){const i=e.get(a.JZ);if(!t.hasModel())return;const s=[],n=t.getModel().getOptions(),o=t.getOption(23),c=t.getSelections().map(((e,t)=>({selection:e,index:t,ignoreFirstLine:!1})));c.sort(((e,t)=>r.Q.compareRangesUsingStarts(e.selection,t.selection)));let l=c[0];for(let r=1;r{"use strict";(0,i(34918).K)({id:"lexon",extensions:[".lex"],aliases:["Lexon"],loader:()=>i.e(99010).then(i.bind(i,99010))})},40579:(e,t,i)=>{"use strict";i.d(t,{Gc:()=>v,Nn:()=>c,Xw:()=>l,rh:()=>_,yF:()=>f});var s=i(64383),n=i(1245),r=i(19131),o=i(32956);class a{get length(){return this._length}constructor(e){this._length=e}}class c extends a{static create(e,t,i){let s=e.length;return t&&(s=(0,r.QB)(s,t.length)),i&&(s=(0,r.QB)(s,i.length)),new c(s,e,t,i,t?t.missingOpeningBracketIds:o.gV.getEmpty())}get kind(){return 2}get listHeight(){return 0}get childrenLength(){return 3}getChild(e){switch(e){case 0:return this.openingBracket;case 1:return this.child;case 2:return this.closingBracket}throw new Error("Invalid child index")}get children(){const e=[];return e.push(this.openingBracket),this.child&&e.push(this.child),this.closingBracket&&e.push(this.closingBracket),e}constructor(e,t,i,s,n){super(e),this.openingBracket=t,this.child=i,this.closingBracket=s,this.missingOpeningBracketIds=n}canBeReused(e){return null!==this.closingBracket&&!e.intersects(this.missingOpeningBracketIds)}deepClone(){return new c(this.length,this.openingBracket.deepClone(),this.child&&this.child.deepClone(),this.closingBracket&&this.closingBracket.deepClone(),this.missingOpeningBracketIds)}computeMinIndentation(e,t){return this.child?this.child.computeMinIndentation((0,r.QB)(e,this.openingBracket.length),t):Number.MAX_SAFE_INTEGER}}class l extends a{static create23(e,t,i,s=!1){let n=e.length,o=e.missingOpeningBracketIds;if(e.listHeight!==t.listHeight)throw new Error("Invalid list heights");if(n=(0,r.QB)(n,t.length),o=o.merge(t.missingOpeningBracketIds),i){if(e.listHeight!==i.listHeight)throw new Error("Invalid list heights");n=(0,r.QB)(n,i.length),o=o.merge(i.missingOpeningBracketIds)}return s?new d(n,e.listHeight+1,e,t,i,o):new h(n,e.listHeight+1,e,t,i,o)}static getEmpty(){return new g(r.Vp,0,[],o.gV.getEmpty())}get kind(){return 4}get missingOpeningBracketIds(){return this._missingOpeningBracketIds}constructor(e,t,i){super(e),this.listHeight=t,this._missingOpeningBracketIds=i,this.cachedMinIndentation=-1}throwIfImmutable(){}makeLastElementMutable(){this.throwIfImmutable();const e=this.childrenLength;if(0===e)return;const t=this.getChild(e-1),i=4===t.kind?t.toMutable():t;return t!==i&&this.setChild(e-1,i),i}makeFirstElementMutable(){this.throwIfImmutable();if(0===this.childrenLength)return;const e=this.getChild(0),t=4===e.kind?e.toMutable():e;return e!==t&&this.setChild(0,t),t}canBeReused(e){if(e.intersects(this.missingOpeningBracketIds))return!1;if(0===this.childrenLength)return!1;let t=this;for(;4===t.kind;){const e=t.childrenLength;if(0===e)throw new s.D7;t=t.getChild(e-1)}return t.canBeReused(e)}handleChildrenChanged(){this.throwIfImmutable();const e=this.childrenLength;let t=this.getChild(0).length,i=this.getChild(0).missingOpeningBracketIds;for(let s=1;s{"use strict";var s=i(31450),n=i(10350),r=i(31308),o=i(49154),a=i(29163),c=i(60002),l=i(78209),h=i(32848);const d=new h.N1("inlineEditsVisible",!1,(0,l.kg)("inlineEditsVisible","Whether an inline edit is visible")),u=new h.N1("inlineEditsIsPinned",!1,(0,l.kg)("isPinned","Whether an inline edit is visible"));var g=i(5662),p=i(87958),m=i(38844),f=i(41127),_=i(75326),v=i(32500),C=i(56942),E=i(90766),b=i(18447),S=i(51241),y=i(64383),w=i(79400),R=i(94746),L=i(86571),T=i(62083),x=i(23750),k=i(20940),A=i(8597),N=i(49435),I=i(10691),O=i(92368),D=i(83941),M=i(87289),P=i(18864),F=i(1098),U=i(90870),H=i(63591),B=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},W=function(e,t){return function(i,s){t(i,s,e)}};class V{constructor(e,t,i){this.range=e,this.newLines=t,this.changes=i}}let z=class extends g.jG{constructor(e,t,i,n){super(),this._editor=e,this._edit=t,this._userPrompt=i,this._instantiationService=n,this._editorObs=(0,m.Ud)(this._editor),this._elements=(0,A.h)("div.inline-edits-widget",{style:{position:"absolute",overflow:"visible",top:"0px",left:"0px"}},[(0,A.h)("div@editorContainer",{style:{position:"absolute",top:"0px",left:"0px",width:"500px",height:"500px"}},[(0,A.h)("div.toolbar@toolbar",{style:{position:"absolute",top:"-25px",left:"0px"}}),(0,A.h)("div.promptEditor@promptEditor",{style:{position:"absolute",top:"-25px",left:"80px",width:"300px",height:"22px"}}),(0,A.h)("div.preview@editor",{style:{position:"absolute",top:"0px",left:"0px"}})]),(0,A.Mc)("svg",{style:{overflow:"visible",pointerEvents:"none"}},[(0,A.Mc)("defs",[(0,A.Mc)("linearGradient",{id:"Gradient2",x1:"0",y1:"0",x2:"1",y2:"0"},[(0,A.Mc)("stop",{offset:"0%",class:"gradient-stop"}),(0,A.Mc)("stop",{offset:"100%",class:"gradient-stop"})])]),(0,A.Mc)("path@path",{d:"",fill:"url(#Gradient2)"})])]),this._previewTextModel=this._register(this._instantiationService.createInstance(M.Bz,"",D.vH,M.Bz.DEFAULT_CREATION_OPTIONS,null)),this._setText=(0,r.un)((e=>{const t=this._edit.read(e);t&&this._previewTextModel.setValue(t.newLines.join("\n"))})).recomputeInitiallyAndOnChange(this._store),this._promptTextModel=this._register(this._instantiationService.createInstance(M.Bz,"",D.vH,M.Bz.DEFAULT_CREATION_OPTIONS,null)),this._promptEditor=this._register(this._instantiationService.createInstance(a.t,this._elements.promptEditor,{glyphMargin:!1,lineNumbers:"off",minimap:{enabled:!1},guides:{indentation:!1,bracketPairs:!1,bracketPairsHorizontal:!1,highlightActiveIndentation:!1},folding:!1,selectOnLineNumbers:!1,selectionHighlight:!1,columnSelection:!1,overviewRulerBorder:!1,overviewRulerLanes:0,lineDecorationsWidth:0,lineNumbersMinChars:0,placeholder:"Describe the change you want...",fontFamily:N.z},{contributions:s.dS.getSomeEditorContributions([U.D.ID,F.X.ID,P.d.ID]),isSimpleWidget:!0},this._editor)),this._previewEditor=this._register(this._instantiationService.createInstance(a.t,this._elements.editor,{glyphMargin:!1,lineNumbers:"off",minimap:{enabled:!1},guides:{indentation:!1,bracketPairs:!1,bracketPairsHorizontal:!1,highlightActiveIndentation:!1},folding:!1,selectOnLineNumbers:!1,selectionHighlight:!1,columnSelection:!1,overviewRulerBorder:!1,overviewRulerLanes:0,lineDecorationsWidth:0,lineNumbersMinChars:0},{contributions:[]},this._editor)),this._previewEditorObs=(0,m.Ud)(this._previewEditor),this._decorations=(0,r.un)(this,(e=>{this._setText.read(e);const t=this._edit.read(e)?.changes;if(!t)return[];const i=[],s=[];if(1===t.length&&t[0].innerChanges[0].modifiedRange.equalsRange(this._previewTextModel.getFullModelRange()))return[];for(const n of t)if(n.original.isEmpty||i.push({range:n.original.toInclusiveRange(),options:I.Ob}),n.modified.isEmpty||s.push({range:n.modified.toInclusiveRange(),options:I.Kl}),n.modified.isEmpty||n.original.isEmpty)n.original.isEmpty||i.push({range:n.original.toInclusiveRange(),options:I.KL}),n.modified.isEmpty||s.push({range:n.modified.toInclusiveRange(),options:I.Ou});else for(const e of n.innerChanges||[])n.original.contains(e.originalRange.startLineNumber)&&i.push({range:e.originalRange,options:e.originalRange.isEmpty()?I.wp:I.Zb}),n.modified.contains(e.modifiedRange.startLineNumber)&&s.push({range:e.modifiedRange,options:e.modifiedRange.isEmpty()?I.GM:I.bk});return s})),this._layout1=(0,r.un)(this,(e=>{const t=this._editor.getModel(),i=this._edit.read(e);if(!i)return null;const s=i.range;let n=0;for(let r=s.startLineNumber;r{const t=this._edit.read(e);if(!t)return null;const i=t.range,s=this._editorObs.scrollLeft.read(e),n=this._layout1.read(e).left+20-s,r=this._editor.getTopForLineNumber(i.startLineNumber)-this._editorObs.scrollTop.read(e),o=this._editor.getTopForLineNumber(i.endLineNumberExclusive)-this._editorObs.scrollTop.read(e),a=new G(n,r),c=new G(n,o),l=o-r,h=this._editor.getOption(67)*t.newLines.length,d=l-h;return{topCode:a,bottomCode:c,codeHeight:l,topEdit:new G(n+50,r+d/2),bottomEdit:new G(n+50,o-d/2),editHeight:h}}));const o=(0,r.un)(this,(e=>void 0!==this._edit.read(e)||void 0!==this._userPrompt.read(e)));var c,l,h;this._register((0,O.AV)(this._elements.root,{display:(0,r.un)(this,(e=>o.read(e)?"block":"none"))})),this._register((0,O.rX)(this._editor.getDomNode(),this._elements.root)),this._register((0,m.Ud)(e).createOverlayWidget({domNode:this._elements.root,position:(0,r.lk)(null),allowEditorOverflow:!1,minContentWidthInPx:(0,r.un)((e=>{const t=this._layout1.read(e)?.left;if(void 0===t)return 0;return t+this._previewEditorObs.contentWidth.read(e)}))})),this._previewEditor.setModel(this._previewTextModel),this._register(this._previewEditorObs.setDecorations(this._decorations)),this._register((0,r.fm)((e=>{const t=this._layout.read(e);if(!t)return;const{topCode:i,bottomCode:s,topEdit:n,bottomEdit:r,editHeight:o}=t,a=(new j).moveTo(i).lineTo(i.deltaX(10)).curveTo(i.deltaX(50),n.deltaX(-40),n.deltaX(-0)).lineTo(n).lineTo(r).lineTo(r.deltaX(-0)).curveTo(r.deltaX(-40),s.deltaX(50),s.deltaX(10)).lineTo(s).build();this._elements.path.setAttribute("d",a),this._elements.editorContainer.style.top=`${n.y}px`,this._elements.editorContainer.style.left=`${n.x}px`,this._elements.editorContainer.style.height=`${o}px`;const c=this._previewEditorObs.contentWidth.read(e);this._previewEditor.layout({height:o,width:c})}))),this._promptEditor.setModel(this._promptTextModel),this._promptEditor.layout(),this._register(function(e,t){const i=new g.Cm;return i.add((0,r.fm)((i=>{const s=e.read(i);t.set(s,void 0)}))),i.add((0,r.fm)((i=>{const s=t.read(i);e.set(s,void 0)}))),i}((c=this._userPrompt,l=e=>e??"",h=e=>e,(0,p.dQ)(void 0,(e=>l(c.read(e))),((e,t)=>c.set(h(e),t)))),(0,m.Ud)(this._promptEditor).value)),this._register((0,r.fm)((e=>{const t=(0,m.Ud)(this._promptEditor).isFocused.read(e);this._elements.root.classList.toggle("focused",t)})))}};z=B([W(3,H._Y)],z);class G{constructor(e,t){this.x=e,this.y=t}deltaX(e){return new G(this.x+e,this.y)}}class j{constructor(){this._data=""}moveTo(e){return this._data+=`M ${e.x} ${e.y} `,this}lineTo(e){return this._data+=`L ${e.x} ${e.y} `,this}curveTo(e,t,i){return this._data+=`C ${e.x} ${e.y} ${t.x} ${t.y} ${i.x} ${i.y} `,this}build(){return this._data}}var K,Y=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},q=function(e,t){return function(i,s){t(i,s,e)}};let $=class extends g.jG{static{K=this}static{this._modelId=0}static _createUniqueUri(){return w.r.from({scheme:"inline-edits",path:(new Date).toString()+String(K._modelId++)})}constructor(e,t,i,s,n,o,a){super(),this.textModel=e,this._textModelVersionId=t,this._selection=i,this._debounceValue=s,this.languageFeaturesService=n,this._diffProviderFactoryService=o,this._modelService=a,this._forceUpdateExplicitlySignal=(0,r.Yd)(this),this._selectedInlineCompletionId=(0,r.FY)(this,void 0),this._isActive=(0,r.FY)(this,!1),this._originalModel=(0,p.a0)((()=>this._modelService.createModel("",null,K._createUniqueUri()))).keepObserved(this._store),this._modifiedModel=(0,p.a0)((()=>this._modelService.createModel("",null,K._createUniqueUri()))).keepObserved(this._store),this._pinnedRange=new X(this.textModel,this._textModelVersionId),this.isPinned=this._pinnedRange.range.map((e=>!!e)),this.userPrompt=(0,r.FY)(this,void 0),this.inlineEdit=(0,r.un)(this,(e=>this._inlineEdit.read(e)?.promiseResult.read(e)?.data)),this._inlineEdit=(0,r.un)(this,(e=>{const t=this.selectedInlineEdit.read(e);if(!t)return;const i=t.inlineCompletion.range;if(""===t.inlineCompletion.insertText.trim())return;let s=t.inlineCompletion.insertText.split(/\r\n|\r|\n/);function n(e){const t=e[0].match(/^\s*/)?.[0]??"";return e.map((e=>e.replace(new RegExp("^"+t),"")))}s=n(s);let o=this.textModel.getValueInRange(i).split(/\r\n|\r|\n/);o=n(o),this._originalModel.get().setValue(o.join("\n")),this._modifiedModel.get().setValue(s.join("\n"));const a=this._diffProviderFactoryService.createDiffProvider({diffAlgorithm:"advanced"});return r.BK.fromFn((async()=>{const e=await a.computeDiff(this._originalModel.get(),this._modifiedModel.get(),{computeMoves:!1,ignoreTrimWhitespace:!1,maxComputationTimeMs:1e3},b.XO.None);if(!e.identical)return new V(L.M.fromRangeInclusive(i),n(s),e.changes)}))})),this._fetchStore=this._register(new g.Cm),this._inlineEditsFetchResult=(0,r.X2)(this,void 0),this._inlineEdits=(0,r.C)({owner:this,equalsFn:S.dB},(e=>this._inlineEditsFetchResult.read(e)?.completions.map((e=>new Q(e)))??[])),this._fetchInlineEditsPromise=(0,r.nb)({owner:this,createEmptyChangeSummary:()=>({inlineCompletionTriggerKind:T.qw.Automatic}),handleChange:(e,t)=>(e.didChange(this._forceUpdateExplicitlySignal)&&(t.inlineCompletionTriggerKind=T.qw.Explicit),!0)},(async(e,t)=>{this._fetchStore.clear(),this._forceUpdateExplicitlySignal.read(e),this._textModelVersionId.read(e);const i=this._pinnedRange.range.read(e)??(s=this._selection.read(e),(e=>e.isEmpty()?void 0:e)(s));var s;if(!i)return this._inlineEditsFetchResult.set(void 0,void 0),void this.userPrompt.set(void 0,void 0);const n={triggerKind:t.inlineCompletionTriggerKind,selectedSuggestionInfo:void 0,userPrompt:this.userPrompt.read(e)},r=(0,b.bs)(this._fetchStore);await(0,E.wR)(200,r);const o=await(0,k.Yk)(this.languageFeaturesService.inlineCompletionsProvider,i,this.textModel,n,r);r.isCancellationRequested||this._inlineEditsFetchResult.set(o,void 0)})),this._filteredInlineEditItems=(0,r.C)({owner:this,equalsFn:(0,S.S3)()},(e=>this._inlineEdits.read(e))),this.selectedInlineCompletionIndex=(0,r.un)(this,(e=>{const t=this._selectedInlineCompletionId.read(e),i=this._filteredInlineEditItems.read(e),s=void 0===this._selectedInlineCompletionId?-1:i.findIndex((e=>e.semanticId===t));return-1===s?(this._selectedInlineCompletionId.set(void 0,void 0),0):s})),this.selectedInlineEdit=(0,r.un)(this,(e=>this._filteredInlineEditItems.read(e)[this.selectedInlineCompletionIndex.read(e)])),this._register((0,r.OI)(this._fetchInlineEditsPromise))}async triggerExplicitly(e){(0,r.PO)(e,(e=>{this._isActive.set(!0,e),this._forceUpdateExplicitlySignal.trigger(e)})),await this._fetchInlineEditsPromise.get()}stop(e){(0,r.PO)(e,(e=>{this.userPrompt.set(void 0,e),this._isActive.set(!1,e),this._inlineEditsFetchResult.set(void 0,e),this._pinnedRange.setRange(void 0,e)}))}async _deltaSelectedInlineCompletionIndex(e){await this.triggerExplicitly();const t=this._filteredInlineEditItems.get()||[];if(t.length>0){const i=(this.selectedInlineCompletionIndex.get()+e+t.length)%t.length;this._selectedInlineCompletionId.set(t[i].semanticId,void 0)}else this._selectedInlineCompletionId.set(void 0,void 0)}async next(){await this._deltaSelectedInlineCompletionIndex(1)}async previous(){await this._deltaSelectedInlineCompletionIndex(-1)}async accept(e){if(e.getModel()!==this.textModel)throw new y.D7;const t=this.selectedInlineEdit.get();t&&(e.pushUndoStop(),e.executeEdits("inlineSuggestion.accept",[t.inlineCompletion.toSingleTextEdit().toSingleEditOperation()]),this.stop())}};$=K=Y([q(4,C.ILanguageFeaturesService),q(5,R.Hg),q(6,x.IModelService)],$);class Q{constructor(e){this.inlineCompletion=e,this.semanticId=this.inlineCompletion.hash()}}class X extends g.jG{constructor(e,t){super(),this._textModel=e,this._versionId=t,this._decorations=(0,r.FY)(this,[]),this.range=(0,r.un)(this,(e=>{this._versionId.read(e);const t=this._decorations.read(e)[0];return t?this._textModel.getDecorationRange(t)??null:null})),this._register((0,g.s)((()=>{this._textModel.deltaDecorations(this._decorations.get(),[])})))}setRange(e,t){this._decorations.set(this._textModel.deltaDecorations(this._decorations.get(),e?[{range:e,options:{description:"trackedRange"}}]:[]),t)}}var Z,J=i(84001),ee=i(71319),te=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},ie=function(e,t){return function(i,s){t(i,s,e)}};let se=class extends g.jG{static{Z=this}static{this.ID="editor.contrib.inlineEditsController"}static get(e){return e.getContribution(Z.ID)}constructor(e,t,i,s,n,o){super(),this.editor=e,this._instantiationService=t,this._contextKeyService=i,this._debounceService=s,this._languageFeaturesService=n,this._configurationService=o,this._enabled=(0,ee.V)("editor.inlineEdits.enabled",!1,this._configurationService),this._editorObs=(0,m.Ud)(this.editor),this._selection=(0,r.un)(this,(e=>this._editorObs.cursorSelection.read(e)??new _.L(1,1,1,1))),this._debounceValue=this._debounceService.for(this._languageFeaturesService.inlineCompletionsProvider,"InlineEditsDebounce",{min:50,max:50}),this.model=(0,p.a0)(this,(e=>{if(!this._enabled.read(e))return;if(this._editorObs.isReadonly.read(e))return;const t=this._editorObs.model.read(e);if(!t)return;return this._instantiationService.createInstance((0,f.b)($,e),t,this._editorObs.versionId,this._selection,this._debounceValue)})),this._hadInlineEdit=(0,r.ZX)(this,((e,t)=>t||void 0!==this.model.read(e)?.inlineEdit.read(e))),this._widget=(0,p.a0)(this,(e=>{var t;if(this._hadInlineEdit.read(e))return this._instantiationService.createInstance((0,f.b)(z,e),this.editor,this.model.map(((e,t)=>e?.inlineEdit.read(t))),(t=e=>this.model.read(e)?.userPrompt??(0,r.FY)("empty",""),(0,p.dQ)(void 0,(e=>t(e).read(e)),((e,i)=>{t(void 0).set(e,i)}))))})),this._register((0,ee.w)(d,this._contextKeyService,(e=>!!this.model.read(e)?.inlineEdit.read(e)))),this._register((0,ee.w)(u,this._contextKeyService,(e=>!!this.model.read(e)?.isPinned.read(e)))),this.model.recomputeInitiallyAndOnChange(this._store),this._widget.recomputeInitiallyAndOnChange(this._store)}};se=Z=te([ie(1,H._Y),ie(2,h.fN),ie(3,v.ILanguageFeatureDebounceService),ie(4,C.ILanguageFeaturesService),ie(5,J.pG)],se);var ne=i(27195);function re(e){return{label:e.value,alias:e.original}}class oe extends s.ks{static{this.ID="editor.action.inlineEdits.showNext"}constructor(){super({id:oe.ID,...re(l.aS("action.inlineEdits.showNext","Show Next Inline Edit")),precondition:h.M$.and(c.R.writable,d),kbOpts:{weight:100,primary:606}})}async run(e,t){const i=se.get(t);i?.model.get()?.next()}}class ae extends s.ks{static{this.ID="editor.action.inlineEdits.showPrevious"}constructor(){super({id:ae.ID,...re(l.aS("action.inlineEdits.showPrevious","Show Previous Inline Edit")),precondition:h.M$.and(c.R.writable,d),kbOpts:{weight:100,primary:604}})}async run(e,t){const i=se.get(t);i?.model.get()?.previous()}}class ce extends s.ks{constructor(){super({id:"editor.action.inlineEdits.trigger",...re(l.aS("action.inlineEdits.trigger","Trigger Inline Edit")),precondition:c.R.writable})}async run(e,t){const i=se.get(t);await(0,o.fL)((async e=>{await(i?.model.get()?.triggerExplicitly(e))}))}}class le extends s.ks{constructor(){super({id:"editor.action.inlineEdits.accept",...re(l.aS("action.inlineEdits.accept","Accept Inline Edit")),precondition:d,menuOpts:{menuId:ne.D8.InlineEditsActions,title:l.kg("inlineEditsActions","Accept Inline Edit"),group:"primary",order:1,icon:n.W.check},kbOpts:{primary:2058,weight:2e4,kbExpr:d}})}async run(e,t){t instanceof a.t&&(t=t.getParentEditor());const i=se.get(t);i&&(i.model.get()?.accept(i.editor),i.editor.focus())}}class he extends s.ks{static{this.ID="editor.action.inlineEdits.hide"}constructor(){super({id:he.ID,...re(l.aS("action.inlineEdits.hide","Hide Inline Edit")),precondition:d,kbOpts:{weight:100,primary:9}})}async run(e,t){const i=se.get(t);(0,r.Rn)((e=>{i?.model.get()?.stop(e)}))}}(0,s.HW)(se.ID,se,3),(0,s.Fl)(ce),(0,s.Fl)(oe),(0,s.Fl)(ae),(0,s.Fl)(le),(0,s.Fl)(he)},40800:(e,t,i)=>{"use strict";var s=i(25890),n=i(31308),r=i(34309),o=i(92368),a=i(56942),c=i(29999),l=i(5662),h=i(41234),d=function(e,t,i,s){var n,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(o=(r<3?n(o):r>3?n(t,i,o):n(t,i))||o);return r>3&&o&&Object.defineProperty(t,i,o),o},u=function(e,t){return function(i,s){t(i,s,e)}};let g=class extends l.jG{constructor(e,t,i){super(),this._textModel=e,this._languageFeaturesService=t,this._outlineModelService=i,this._currentModel=(0,n.FY)(this,void 0);const s=(0,n.yQ)("documentSymbolProvider.onDidChange",this._languageFeaturesService.documentSymbolProvider.onDidChange),r=(0,n.yQ)("_textModel.onDidChangeContent",h.Jh.debounce((e=>this._textModel.onDidChangeContent(e)),(()=>{}),100));this._register((0,n.yC)((async(e,t)=>{s.read(e),r.read(e);const i=t.add(new o.MZ),n=await this._outlineModelService.getOrCreate(this._textModel,i.token);t.isDisposed||this._currentModel.set(n,void 0)})))}getBreadcrumbItems(e,t){const i=this._currentModel.read(t);if(!i)return[];const n=i.asListOfDocumentSymbols().filter((t=>e.contains(t.range.startLineNumber)&&!e.contains(t.range.endLineNumber)));return n.sort((0,s.Hw)((0,s.VE)((e=>e.range.endLineNumber-e.range.startLineNumber),s.U9))),n.map((e=>({name:e.name,kind:e.kind,startLineNumber:e.range.startLineNumber})))}};g=d([u(1,a.ILanguageFeaturesService),u(2,c.gW)],g),r.N.setBreadcrumbsSourceFactory(((e,t)=>t.createInstance(g,e)))},41127:(e,t,i)=>{"use strict";i.d(t,{b:()=>r});var s=i(30076),n=i(31308);function r(e,t){return function(e,t){if((0,s.e)()){(0,n.yQ)("reload",(t=>(0,s.O)((({oldExports:i})=>{if([...Object.values(i)].some((t=>e.includes(t))))return e=>(t(void 0),!0)})))).read(t)}}([e],t),e}},41234:(e,t,i)=>{"use strict";i.d(t,{Jh:()=>c,QT:()=>b,Qy:()=>_,Wj:()=>w,_B:()=>S,at:()=>y,fV:()=>C,uI:()=>E,vl:()=>f});var s=i(64383),n=i(6921),r=i(5662),o=i(58925),a=i(78381);var c;!function(e){function t(e){false}function i(e){return(t,i=null,s)=>{let n,r=!1;return n=e((e=>{if(!r)return n?n.dispose():r=!0,t.call(i,e)}),null,s),r&&n.dispose(),n}}function s(e,t,i){return o(((i,s=null,n)=>e((e=>i.call(s,t(e))),null,n)),i)}function n(e,t,i){return o(((i,s=null,n)=>e((e=>t(e)&&i.call(s,e)),null,n)),i)}function o(e,i){let s;const n={onWillAddFirstListener(){s=e(r.fire,r)},onDidRemoveLastListener(){s?.dispose()}};i||t();const r=new f(n);return i?.add(r),r.event}function a(e,i,s=100,n=!1,r=!1,o,a){let c,l,h,d,u=0;const g={leakWarningThreshold:o,onWillAddFirstListener(){c=e((e=>{u++,l=i(l,e),n&&!h&&(p.fire(l),l=void 0),d=()=>{const e=l;l=void 0,h=void 0,(!n||u>1)&&p.fire(e),u=0},"number"===typeof s?(clearTimeout(h),h=setTimeout(d,s)):void 0===h&&(h=0,queueMicrotask(d))}))},onWillRemoveListener(){r&&u>0&&d?.()},onDidRemoveLastListener(){d=void 0,c.dispose()}};a||t();const p=new f(g);return a?.add(p),p.event}e.None=()=>r.jG.None,e.defer=function(e,t){return a(e,(()=>{}),0,void 0,!0,void 0,t)},e.once=i,e.onceIf=function(t,i){return e.once(e.filter(t,i))},e.map=s,e.forEach=function(e,t,i){return o(((i,s=null,n)=>e((e=>{t(e),i.call(s,e)}),null,n)),i)},e.filter=n,e.signal=function(e){return e},e.any=function(...e){return(t,i=null,s)=>function(e,t){t instanceof Array?t.push(e):t&&t.add(e);return e}((0,r.qE)(...e.map((e=>e((e=>t.call(i,e)))))),s)},e.reduce=function(e,t,i,n){let r=i;return s(e,(e=>(r=t(r,e),r)),n)},e.debounce=a,e.accumulate=function(t,i=0,s){return e.debounce(t,((e,t)=>e?(e.push(t),e):[t]),i,void 0,!0,void 0,s)},e.latch=function(e,t=(e,t)=>e===t,i){let s,r=!0;return n(e,(e=>{const i=r||!t(e,s);return r=!1,s=e,i}),i)},e.split=function(t,i,s){return[e.filter(t,i,s),e.filter(t,(e=>!i(e)),s)]},e.buffer=function(e,t=!1,i=[],s){let n=i.slice(),r=e((e=>{n?n.push(e):a.fire(e)}));s&&s.add(r);const o=()=>{n?.forEach((e=>a.fire(e))),n=null},a=new f({onWillAddFirstListener(){r||(r=e((e=>a.fire(e))),s&&s.add(r))},onDidAddFirstListener(){n&&(t?setTimeout(o):o())},onDidRemoveLastListener(){r&&r.dispose(),r=null}});return s&&s.add(a),a.event},e.chain=function(e,t){return(i,s,n)=>{const r=t(new l);return e((function(e){const t=r.evaluate(e);t!==c&&i.call(s,t)}),void 0,n)}};const c=Symbol("HaltChainable");class l{constructor(){this.steps=[]}map(e){return this.steps.push(e),this}forEach(e){return this.steps.push((t=>(e(t),t))),this}filter(e){return this.steps.push((t=>e(t)?t:c)),this}reduce(e,t){let i=t;return this.steps.push((t=>(i=e(i,t),i))),this}latch(e=(e,t)=>e===t){let t,i=!0;return this.steps.push((s=>{const n=i||!e(s,t);return i=!1,t=s,n?s:c})),this}evaluate(e){for(const t of this.steps)if((e=t(e))===c)break;return e}}e.fromNodeEventEmitter=function(e,t,i=e=>e){const s=(...e)=>n.fire(i(...e)),n=new f({onWillAddFirstListener:()=>e.on(t,s),onDidRemoveLastListener:()=>e.removeListener(t,s)});return n.event},e.fromDOMEventEmitter=function(e,t,i=e=>e){const s=(...e)=>n.fire(i(...e)),n=new f({onWillAddFirstListener:()=>e.addEventListener(t,s),onDidRemoveLastListener:()=>e.removeEventListener(t,s)});return n.event},e.toPromise=function(e){return new Promise((t=>i(e)(t)))},e.fromPromise=function(e){const t=new f;return e.then((e=>{t.fire(e)}),(()=>{t.fire(void 0)})).finally((()=>{t.dispose()})),t.event},e.forward=function(e,t){return e((e=>t.fire(e)))},e.runAndSubscribe=function(e,t,i){return t(i),e((e=>t(e)))};class h{constructor(e,i){this._observable=e,this._counter=0,this._hasChanged=!1;const s={onWillAddFirstListener:()=>{e.addObserver(this),this._observable.reportChanges()},onDidRemoveLastListener:()=>{e.removeObserver(this)}};i||t(),this.emitter=new f(s),i&&i.add(this.emitter)}beginUpdate(e){this._counter++}handlePossibleChange(e){}handleChange(e,t){this._hasChanged=!0}endUpdate(e){this._counter--,0===this._counter&&(this._observable.reportChanges(),this._hasChanged&&(this._hasChanged=!1,this.emitter.fire(this._observable.get())))}}e.fromObservable=function(e,t){return new h(e,t).emitter.event},e.fromObservableLight=function(e){return(t,i,s)=>{let n=0,o=!1;const a={beginUpdate(){n++},endUpdate(){n--,0===n&&(e.reportChanges(),o&&(o=!1,t.call(i)))},handlePossibleChange(){},handleChange(){o=!0}};e.addObserver(a),e.reportChanges();const c={dispose(){e.removeObserver(a)}};return s instanceof r.Cm?s.add(c):Array.isArray(s)&&s.push(c),c}}}(c||(c={}));class l{static{this.all=new Set}static{this._idPool=0}constructor(e){this.listenerCount=0,this.invocationCount=0,this.elapsedOverall=0,this.durations=[],this.name=`${e}_${l._idPool++}`,l.all.add(this)}start(e){this._stopWatch=new a.W,this.listenerCount=e}stop(){if(this._stopWatch){const e=this._stopWatch.elapsed();this.durations.push(e),this.elapsedOverall+=e,this.invocationCount+=1,this._stopWatch=void 0}}}class h{static{this._idPool=1}constructor(e,t,i=(h._idPool++).toString(16).padStart(3,"0")){this._errorHandler=e,this.threshold=t,this.name=i,this._warnCountdown=0}dispose(){this._stacks?.clear()}check(e,t){const i=this.threshold;if(i<=0||t{const t=this._stacks.get(e.value)||0;this._stacks.set(e.value,t-1)}}getMostFrequentStack(){if(!this._stacks)return;let e,t=0;for(const[i,s]of this._stacks)(!e||t{if(this._leakageMon&&this._size>this._leakageMon.threshold**2){const e=`[${this._leakageMon.name}] REFUSES to accept new listeners because it exceeded its threshold by far (${this._size} vs ${this._leakageMon.threshold})`;console.warn(e);const t=this._leakageMon.getMostFrequentStack()??["UNKNOWN stack",-1],i=new g(`${e}. HINT: Stack shows most frequent listener (${t[1]}-times)`,t[0]);return(this._options?.onListenerError||s.dz)(i),r.jG.None}if(this._disposed)return r.jG.None;t&&(e=e.bind(t));const n=new p(e);let o;this._leakageMon&&this._size>=Math.ceil(.2*this._leakageMon.threshold)&&(n.stack=d.create(),o=this._leakageMon.check(n.stack,this._size+1)),this._listeners?this._listeners instanceof p?(this._deliveryQueue??=new v,this._listeners=[this._listeners,n]):this._listeners.push(n):(this._options?.onWillAddFirstListener?.(this),this._listeners=n,this._options?.onDidAddFirstListener?.(this)),this._size++;const a=(0,r.s)((()=>{m?.unregister(a),o?.(),this._removeListener(n)}));if(i instanceof r.Cm?i.add(a):Array.isArray(i)&&i.push(a),m){const e=(new Error).stack.split("\n").slice(2,3).join("\n").trim(),t=/(file:|vscode-file:\/\/vscode-app)?(\/[^:]*:\d+:\d+)/.exec(e);m.register(a,t?.[2]??e,a)}return a},this._event}_removeListener(e){if(this._options?.onWillRemoveListener?.(this),!this._listeners)return;if(1===this._size)return this._listeners=void 0,this._options?.onDidRemoveLastListener?.(this),void(this._size=0);const t=this._listeners,i=t.indexOf(e);if(-1===i)throw console.log("disposed?",this._disposed),console.log("size?",this._size),console.log("arr?",JSON.stringify(this._listeners)),new Error("Attempted to dispose unknown listener");this._size--,t[i]=void 0;const s=this._deliveryQueue.current===this;if(2*this._size<=t.length){let e=0;for(let i=0;i0}}const _=()=>new v;class v{constructor(){this.i=-1,this.end=0}enqueue(e,t,i){this.i=0,this.end=i,this.current=e,this.value=t}reset(){this.i=this.end,this.current=void 0,this.value=void 0}}class C extends f{constructor(e){super(e),this._isPaused=0,this._eventQueue=new o.w,this._mergeFn=e?.merge}pause(){this._isPaused++}resume(){if(0!==this._isPaused&&0===--this._isPaused)if(this._mergeFn){if(this._eventQueue.size>0){const e=Array.from(this._eventQueue);this._eventQueue.clear(),super.fire(this._mergeFn(e))}}else for(;!this._isPaused&&0!==this._eventQueue.size;)super.fire(this._eventQueue.shift())}fire(e){this._size&&(0!==this._isPaused?this._eventQueue.push(e):super.fire(e))}}class E extends C{constructor(e){super(e),this._delay=e.delay??100}fire(e){this._handle||(this.pause(),this._handle=setTimeout((()=>{this._handle=void 0,this.resume()}),this._delay)),super.fire(e)}}class b extends f{constructor(e){super(e),this._queuedEvents=[],this._mergeFn=e?.merge}fire(e){this.hasListeners()&&(this._queuedEvents.push(e),1===this._queuedEvents.length&&queueMicrotask((()=>{this._mergeFn?super.fire(this._mergeFn(this._queuedEvents)):this._queuedEvents.forEach((e=>super.fire(e))),this._queuedEvents=[]})))}}class S{constructor(){this.hasListeners=!1,this.events=[],this.emitter=new f({onWillAddFirstListener:()=>this.onFirstListenerAdd(),onDidRemoveLastListener:()=>this.onLastListenerRemove()})}get event(){return this.emitter.event}add(e){const t={event:e,listener:null};this.events.push(t),this.hasListeners&&this.hook(t);return(0,r.s)((0,n.P)((()=>{this.hasListeners&&this.unhook(t);const e=this.events.indexOf(t);this.events.splice(e,1)})))}onFirstListenerAdd(){this.hasListeners=!0,this.events.forEach((e=>this.hook(e)))}onLastListenerRemove(){this.hasListeners=!1,this.events.forEach((e=>this.unhook(e)))}hook(e){e.listener=e.event((e=>this.emitter.fire(e)))}unhook(e){e.listener?.dispose(),e.listener=null}dispose(){this.emitter.dispose();for(const e of this.events)e.listener?.dispose();this.events=[]}}class y{constructor(){this.data=[]}wrapEvent(e,t,i){return(s,n,r)=>e((e=>{const r=this.data[this.data.length-1];if(!t)return void(r?r.buffers.push((()=>s.call(n,e))):s.call(n,e));const o=r;o?(o.items??=[],o.items.push(e),0===o.buffers.length&&r.buffers.push((()=>{o.reducedResult??=i?o.items.reduce(t,i):o.items.reduce(t),s.call(n,o.reducedResult)}))):s.call(n,t(i,e))}),void 0,r)}bufferEvents(e){const t={buffers:new Array};this.data.push(t);const i=e();return this.data.pop(),t.buffers.forEach((e=>e())),i}}class w{constructor(){this.listening=!1,this.inputEvent=c.None,this.inputEventListener=r.jG.None,this.emitter=new f({onDidAddFirstListener:()=>{this.listening=!0,this.inputEventListener=this.inputEvent(this.emitter.fire,this.emitter)},onDidRemoveLastListener:()=>{this.listening=!1,this.inputEventListener.dispose()}}),this.event=this.emitter.event}set input(e){this.inputEvent=e,this.listening&&(this.inputEventListener.dispose(),this.inputEventListener=e(this.emitter.fire,this.emitter))}dispose(){this.inputEventListener.dispose(),this.emitter.dispose()}}},41614:(e,t,i)=>{"use strict";i.d(t,{parseYqlQuery:()=>Au,kh:()=>ku});var s,n,r,o,a=Object.defineProperty,c=(e,t)=>a(e,"name",{value:t,configurable:!0});(n=s||(s={})).EOF=-1,n.UNKNOWN_SOURCE_NAME="",(o=r||(r={})).INVALID_TYPE=0,o.EPSILON=-2,o.MIN_USER_TOKEN_TYPE=1,o.EOF=s.EOF,o.DEFAULT_CHANNEL=0,o.HIDDEN_CHANNEL=1,o.MIN_USER_CHANNEL_VALUE=2;var l=c((e=>{const t=e;return void 0!==t.tokenSource&&void 0!==t.channel}),"isToken"),h=class{static{c(this,"BitSet")}data;constructor(e){this.data=e?new Uint32Array(e.map((e=>e>>>0))):new Uint32Array(1)}[Symbol.iterator](){const e=this.data.length;let t=0,i=this.data[t];const s=this.data;return{[Symbol.iterator](){return this},next:c((()=>{for(;t>>5]&=~(1<>>5;return!(t>=this.data.length)&&0!==(this.data[t]&1<=e)return t}set(e){if(e<0)throw new RangeError("index cannot be negative");this.resize(e),this.data[e>>>5]|=1<>>5;if(t<=this.data.length)return;const i=new Uint32Array(t);i.set(this.data),i.fill(0,this.data.length),this.data=i}bitCount(e){return e=(e=(858993459&(e-=e>>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135,e+=e>>8,63&(e+=e>>16)}},d=class e{static{c(this,"MurmurHash")}static defaultSeed=701;constructor(){}static initialize(t=e.defaultSeed){return t}static updateFromComparable(e,t){return this.update(e,t?.hashCode()??0)}static update(e,t){return t=(t=Math.imul(t,3432918353))<<15|t>>>17,e=(e^=t=Math.imul(t,461845907))<<13|e>>>19,e=Math.imul(e,5)+3864292196}static finish(e,t){return e^=4*t,e^=e>>>16,e=Math.imul(e,2246822507),e^=e>>>13,e=Math.imul(e,3266489909),e^=e>>>16}static hashCode(t,i){return e.finish(e.update(i??e.defaultSeed,t),1)}},u=class e{static{c(this,"ObjectEqualityComparator")}static instance=new e;hashCode(e){return null==e?0:e.hashCode()}equals(e,t){return null==e?null==t:e.equals(t)}},g=class e{static{c(this,"DefaultEqualityComparator")}static instance=new e;hashCode(e){return null==e?0:u.instance.hashCode(e)}equals(e,t){return null==e?null==t:"string"===typeof e||"number"===typeof e?e===t:u.instance.equals(e,t)}},p=class e{static{c(this,"HashSet")}static defaultLoadFactor=.75;static initialCapacity=16;comparator;buckets;threshold;itemCount=0;constructor(t,i=e.initialCapacity){if(t instanceof e){this.comparator=t.comparator,this.buckets=t.buckets.slice(0);for(let e=0;ethis.threshold&&this.expand();const t=this.getBucket(e);let i=this.buckets[t];if(!i)return i=[e],this.buckets[t]=i,++this.itemCount,e;for(const s of i)if(this.comparator.equals(s,e))return s;return i.push(e),++this.itemCount,e}get(e){if(null==e)return e;const t=this.getBucket(e),i=this.buckets[t];if(i)for(const s of i)if(this.comparator.equals(s,e))return s}remove(e){if(null==e)return!1;const t=this.getBucket(e),i=this.buckets[t];if(!i)return!1;for(let s=0;se.INTERVAL_POOL_MAX_VALUE?new e(t,i):(e.cache[t]||(e.cache[t]=new e(t,t)),e.cache[t])}equals(e){return this.start===e.start&&this.stop===e.stop}hashCode(){return this.cachedHashCode}startsBeforeDisjoint(e){return this.start=e.start}startsAfter(e){return this.start>e.start}startsAfterDisjoint(e){return this.start>e.stop}startsAfterNonDisjoint(e){return this.start>e.start&&this.start<=e.stop}disjoint(e){return this.startsBeforeDisjoint(e)||this.startsAfterDisjoint(e)}adjacent(e){return this.start===e.stop+1||this.stop===e.start-1}properlyContains(e){return e.start>=this.start&&e.stop<=this.stop}union(t){return e.of(Math.min(this.start,t.start),Math.max(this.stop,t.stop))}intersection(t){return e.of(Math.max(this.start,t.start),Math.min(this.stop,t.stop))}differenceNotProperlyContained(t){let i=null;return t.startsBeforeNonDisjoint(this)?i=e.of(Math.max(this.start,t.stop+1),this.stop):t.startsAfterNonDisjoint(this)&&(i=e.of(this.start,t.start-1)),i}toString(){return`${this.start}..${this.stop}`}get length(){return this.stop0){const t=n.codePointAt(0);if(39===t){s[e]=null;continue}if(t>=65&&t<=90){i[e]=null;continue}}i[e]=null,s[e]=null}}return new e(i,s,t)}getMaxTokenType(){return this.maxTokenType}getLiteralName(e){return e>=0&&e=0&&e=0&&ethis.addInterval(e)),this),this}complementWithVocabulary(t){const i=new e;return t?0===t.length?i:(i.addSet(t),i.subtract(this)):i}complement(t,i){const s=new e;return s.addInterval(new m(t,i)),s.subtract(this)}or(t){const i=new e;return i.addSet(this),t.forEach((e=>i.addSet(e))),i}and(t){if(0===t.length)return new e;const i=this.intervals,s=t.intervals;let n;const r=i.length,o=s.length;let a=0,c=0;for(;ae.stop){s++;continue}let o,a;r.start>e.start&&(o=new m(e.start,r.start-1)),r.stope))return!0;i=s-1}}return!1}removeRange(e){if(this.cachedHashCode=void 0,e.start===e.stop)this.removeOne(e.start);else if(null!==this.intervals){let t=0;for(const i of this.intervals){if(e.stop<=i.start)return;if(e.start>i.start&&e.stop=i.stop?(this.intervals.splice(t,1),t-=1):e.start1&&(t+="{");for(let i=0;i":t+=e?"'"+String.fromCodePoint(n)+"'":n:t+=e?"'"+String.fromCodePoint(n)+"'..'"+String.fromCodePoint(o)+"'":n+".."+o,i1&&(t+="}"),t}toStringWithVocabulary(e){if(0===this.intervals.length)return"{}";let t="";this.length>1&&(t+="{");for(let i=0;i":t+=this.elementName(e,n);else for(let i=n;i<=o;++i)i>n&&(t+=", "),t+=this.elementName(e,i);i1&&(t+="}"),t}toStringWithRuleNames(e){if(0===this.intervals.length)return"{}";let t="";this.length>1&&(t+="{");const i=f.fromTokenNames(e);for(let s=0;s":t+=this.elementName(i,n);else for(let s=n;s<=o;++s)s>n&&(t+=", "),t+=this.elementName(i,s);s1&&(t+="}"),t}toArray(){const e=[];for(const t of this.intervals)for(let i=t.start;i<=t.stop;i++)e.push(i);return e}get length(){let e=0;for(const t of this.intervals)e+=t.length;return e}elementName(e,t){return t===r.EOF?"":t===r.EPSILON?"":e.getDisplayName(t)}},v=c((e=>null===e?"null":e),"valueToString"),C=c((e=>Array.isArray(e)?"["+e.map(v).join(", ")+"]":"null"),"arrayToString"),E=c(((e,t)=>{if(e===t)return!0;if(e.length!==t.length)return!1;for(let i=0;i{if(e===t)return!0;if(e.length!==t.length)return!1;for(let i=0;i(e=e.replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r"),t&&(e=e.replace(/ /g,"\xb7")),e)),"escapeWhitespace"),y=class e{static{c(this,"SemanticContext")}cachedHashCode;static andContext(t,i){if(null===t||t===e.NONE)return i;if(null===i||i===e.NONE)return t;const s=new w(t,i);return 1===s.operands.length?s.operands[0]:s}static orContext(t,i){if(null===t)return i;if(null===i)return t;if(t===e.NONE||i===e.NONE)return e.NONE;const s=new R(t,i);return 1===s.operands.length?s.operands[0]:s}static filterPrecedencePredicates(t){const i=[];for(const s of t)s instanceof e.PrecedencePredicate&&i.push(s);return i}evalPrecedence(e,t){return this}},w=class e extends y{static{c(this,"AND")}operands;constructor(t,i){super();const s=new p;t instanceof e?t.operands.forEach((e=>{s.add(e)})):s.add(t),i instanceof e?i.operands.forEach((e=>{s.add(e)})):s.add(i);const n=y.filterPrecedencePredicates(s);if(n.length>0){let e=null;n.forEach((t=>{(null===e||t.precedence{n=null===n?e:y.andContext(n,e)})),n}toString(){const e=this.operands.map((e=>e.toString()));return(e.length>3?e.slice(3):e).join("&&")}},R=class e extends y{static{c(this,"OR")}operands;constructor(t,i){super();const s=new p;t instanceof e?t.operands.forEach((e=>{s.add(e)})):s.add(t),i instanceof e?i.operands.forEach((e=>{s.add(e)})):s.add(i);const n=y.filterPrecedencePredicates(s);if(n.length>0){const e=n.sort(((e,t)=>e.compareTo(t))),t=e[e.length-1];s.add(t)}this.operands=s.toArray()}equals(t){return this===t||t instanceof e&&E(this.operands,t.operands)}hashCode(){if(void 0===this.cachedHashCode){let e=d.initialize();for(const t of this.operands)e=d.updateFromComparable(e,t);e=d.update(e,3383313031),this.cachedHashCode=d.finish(e,this.operands.length+1)}return this.cachedHashCode}evaluate(e,t){for(const i of this.operands)if(i.evaluate(e,t))return!0;return!1}evalPrecedence(e,t){let i=!1;const s=[];for(const r of this.operands){const n=r.evalPrecedence(e,t);if(i||=n!==r,n===y.NONE)return y.NONE;null!==n&&s.push(n)}if(!i)return this;if(0===s.length)return null;let n=null;return s.forEach((e=>{n=null===n?e:y.orContext(n,e)})),n}toString(){const e=this.operands.map((e=>e.toString()));return(e.length>3?e.slice(3):e).join("||")}};(e=>{class t extends e{static{c(this,"Predicate")}ruleIndex;predIndex;isCtxDependent;constructor(e,t,i){super(),this.ruleIndex=e??-1,this.predIndex=t??-1,this.isCtxDependent=i??!1}evaluate(e,t){const i=this.isCtxDependent?t:null;return e.sempred(i,this.ruleIndex,this.predIndex)}hashCode(){if(void 0===this.cachedHashCode){let e=d.initialize();e=d.update(e,this.ruleIndex),e=d.update(e,this.predIndex),e=d.update(e,this.isCtxDependent?1:0),e=d.finish(e,3),this.cachedHashCode=e}return this.cachedHashCode}equals(e){return this===e||this.ruleIndex===e.ruleIndex&&this.predIndex===e.predIndex&&this.isCtxDependent===e.isCtxDependent}toString(){return"{"+this.ruleIndex+":"+this.predIndex+"}?"}}e.Predicate=t;class i extends e{static{c(this,"PrecedencePredicate")}precedence;constructor(e){super(),this.precedence=e??0}evaluate(e,t){return e.precpred(t,this.precedence)}evalPrecedence(t,i){return t.precpred(i??null,this.precedence)?e.NONE:null}compareTo(e){return this.precedence-e.precedence}hashCode(){return 31+this.precedence}equals(e){return this===e||this.precedence===e.precedence}toString(){return"{"+this.precedence+">=prec}?"}}e.PrecedencePredicate=i,e.NONE=new t})(y||(y={}));var L,T=class e{static{c(this,"ATNConfig")}state;alt;reachesIntoOuterContext=!1;precedenceFilterSuppressed=!1;get semanticContext(){return this.#e}cachedHashCode;#t=null;#e;constructor(e,t,i,s){this.state=t,this.alt=e.alt,this.context=i,this.#e=s??y.NONE,this.reachesIntoOuterContext=e.reachesIntoOuterContext,void 0!==e.precedenceFilterSuppressed&&(this.precedenceFilterSuppressed=e.precedenceFilterSuppressed)}static duplicate(t,i){return new e(t,t.state,t.context,i??t.semanticContext)}static createWithContext(t,i,s,n){return new e({alt:i},t,s,n)}static createWithConfig(t,i,s){return new e(i,t,s??i.context,i.semanticContext)}static createWithSemanticContext(t,i,s){return new e(i,t??i.state,i.context,s)}hashCode(){if(void 0===this.cachedHashCode){let e=d.initialize(7);e=d.update(e,this.state.stateNumber),e=d.update(e,this.alt),e=d.updateFromComparable(e,this.#t),e=d.updateFromComparable(e,this.semanticContext),e=d.finish(e,4),this.cachedHashCode=e}return this.cachedHashCode}get context(){return this.#t}set context(e){this.#t=e,this.cachedHashCode=void 0}equals(e){return this===e||this.state.stateNumber===e.state.stateNumber&&this.alt===e.alt&&(null===this.context?null===e.context:this.context.equals(e.context))&&this.semanticContext.equals(e.semanticContext)&&this.precedenceFilterSuppressed===e.precedenceFilterSuppressed}toString(e,t=!0){let i="";return t&&(i=","+this.alt),"("+this.state+i+(null!==this.context?",["+this.context.toString()+"]":"")+(this.semanticContext!==y.NONE?","+this.semanticContext.toString():"")+(this.reachesIntoOuterContext?",up="+this.reachesIntoOuterContext:"")+")"}},x=class e{static{c(this,"ATNState")}static INVALID_STATE_NUMBER=-1;static INVALID_TYPE=0;static BASIC=1;static RULE_START=2;static BLOCK_START=3;static PLUS_BLOCK_START=4;static STAR_BLOCK_START=5;static TOKEN_START=6;static RULE_STOP=7;static BLOCK_END=8;static STAR_LOOP_BACK=9;static STAR_LOOP_ENTRY=10;static PLUS_LOOP_BACK=11;static LOOP_END=12;static stateType=e.INVALID_STATE_NUMBER;stateNumber=0;ruleIndex=0;epsilonOnlyTransitions=!1;nextTokenWithinRule;transitions=[];hashCode(){return this.stateNumber}equals(e){return this.stateNumber===e.stateNumber}toString(){return`${this.stateNumber}`}addTransitionAtIndex(e,t){0===this.transitions.length?this.epsilonOnlyTransitions=t.isEpsilon:this.epsilonOnlyTransitions!==t.isEpsilon&&(this.epsilonOnlyTransitions=!1),this.transitions.splice(e,1,t)}addTransition(e){0===this.transitions.length?this.epsilonOnlyTransitions=e.isEpsilon:this.epsilonOnlyTransitions!==e.isEpsilon&&(this.epsilonOnlyTransitions=!1),this.transitions.push(e)}setTransition(e,t){this.transitions.splice(e,1,t)}removeTransition(e){return this.transitions.splice(e,1)[0]}},k=class e{static{c(this,"PredictionContext")}static EMPTY_RETURN_STATE=2147483647;static traceATNSimulator=!1;cachedHashCode;constructor(e){this.cachedHashCode=e}static calculateEmptyHashCode(){let e=d.initialize(31);return e=d.finish(e,0),e}static calculateHashCodeSingle(e,t){let i=d.initialize(31);return i=d.updateFromComparable(i,e),i=d.update(i,t),i=d.finish(i,2),i}static calculateHashCodeList(e,t){let i=d.initialize(31);for(const s of e)i=d.updateFromComparable(i,s);for(const s of t)i=d.update(i,s);return i=d.finish(i,2*e.length),i}isEmpty(){return!1}hasEmptyPath(){return this.getReturnState(this.length-1)===e.EMPTY_RETURN_STATE}hashCode(){return this.cachedHashCode}toString(e){return""}},A=class e extends k{static{c(this,"SingletonPredictionContext")}parent;returnState;constructor(e,t){super(e?k.calculateHashCodeSingle(e,t):k.calculateEmptyHashCode()),this.parent=e??null,this.returnState=t}getParent(e){return this.parent}getReturnState(e){return this.returnState}equals(t){return this===t||t instanceof e&&(this.hashCode()===t.hashCode()&&(this.returnState===t.returnState&&(null==this.parent?null==t.parent:this.parent.equals(t.parent))))}toString(){const e=null===this.parent?"":this.parent.toString();return 0===e.length?this.returnState===k.EMPTY_RETURN_STATE?"$":""+this.returnState:this.returnState+" "+e}get length(){return 1}},N=class e extends A{static{c(this,"EmptyPredictionContext")}static instance=new e;constructor(){super(void 0,k.EMPTY_RETURN_STATE)}isEmpty(){return!0}getParent(){return null}getReturnState(){return this.returnState}equals(e){return this===e}toString(){return"$"}},I=class{static{c(this,"Transition")}static INVALID=0;static EPSILON=1;static RANGE=2;static RULE=3;static PREDICATE=4;static ATOM=5;static ACTION=6;static SET=7;static NOT_SET=8;static WILDCARD=9;static PRECEDENCE=10;target;constructor(e){this.target=e}get isEpsilon(){return!1}get label(){return null}toString(){return""}},O=class extends I{static{c(this,"SetTransition")}set;constructor(e,t){super(e),this.set=t||_.of(r.INVALID_TYPE,r.INVALID_TYPE)}get transitionType(){return I.SET}get label(){return this.set}matches(e,t,i){return this.set.contains(e)}toString(){return this.set.toString()}},D=class extends O{static{c(this,"NotSetTransition")}get transitionType(){return I.NOT_SET}matches(e,t,i){return e>=t&&e<=i&&!super.matches(e,t,i)}toString(){return"~"+super.toString()}},M=class{static{c(this,"MapKeyEqualityComparator")}keyComparator;constructor(e){this.keyComparator=e}hashCode(e){return this.keyComparator.hashCode(e.key)}equals(e,t){return this.keyComparator.equals(e.key,t.key)}},P=class e{static{c(this,"HashMap")}backingStore;constructor(t){t instanceof e?this.backingStore=new p(t.backingStore):(t=t??g.instance,this.backingStore=new p(new M(t)))}clear(){this.backingStore.clear()}containsKey(e){return this.backingStore.contains({key:e})}get(e){const t=this.backingStore.get({key:e});if(t)return t.value}get isEmpty(){return this.backingStore.isEmpty}set(e,t){const i=this.backingStore.get({key:e,value:t});let s;return i?(s=i.value,i.value=t):this.backingStore.add({key:e,value:t}),s}setIfAbsent(e,t){const i=this.backingStore.get({key:e,value:t});let s;return i?s=i.value:this.backingStore.add({key:e,value:t}),s}keys(){return this.backingStore.toArray().map((e=>e.key))}values(){return this.backingStore.toArray().map((e=>e.value))}get size(){return this.backingStore.size}hashCode(){return this.backingStore.hashCode()}equals(e){return this.backingStore.equals(e.backingStore)}},F=class{static{c(this,"TerminalNode")}parent=null;symbol;constructor(e){this.symbol=e}getChild(e){return null}getSymbol(){return this.symbol}getPayload(){return this.symbol}getSourceInterval(){if(null===this.symbol)return m.INVALID_INTERVAL;const e=this.symbol.tokenIndex;return new m(e,e)}getChildCount(){return 0}accept(e){return e.visitTerminal(this)}getText(){return this.symbol?.text??""}toString(){return this.symbol?.type===r.EOF?"":this.symbol?.text??""}toStringTree(){return this.toString()}},U=class extends F{static{c(this,"ErrorNode")}accept(e){return e.visitErrorNode(this)}},H=class e{static{c(this,"CommonToken")}static EMPTY_SOURCE=[null,null];source;tokenIndex;start;stop;type;line;column;channel;#i;constructor(e){this.type=e.type,this.source=e.source,this.tokenIndex=e.tokenIndex??-1,this.line=e.line??0,this.column=e.column??-1,this.channel=e.channel??r.DEFAULT_CHANNEL,this.start=e.start??0,this.stop=e.stop??0,this.#i=e.text,void 0===e.line&&null!==e.source[0]&&(this.line=e.source[0].line),void 0===e.column&&null!==e.source[0]&&(this.column=e.source[0].column)}static fromToken(t){const i=[t.tokenSource,t.inputStream];return new e({type:t.type,line:t.line,tokenIndex:t.tokenIndex,column:t.column,channel:t.channel,start:t.start,stop:t.stop,text:t.text,source:i})}static fromType(t,i){return new e({type:t,text:i,source:e.EMPTY_SOURCE})}static fromSource(t,i,s,n,r){return new e({type:i,channel:s,start:n,stop:r,source:t})}get tokenSource(){return this.source[0]}get inputStream(){return this.source[1]}set inputStream(e){this.source[1]=e}clone(){return new e({source:this.source,type:this.type,channel:this.channel,start:this.start,stop:this.stop,tokenIndex:this.tokenIndex,line:this.line,column:this.column,text:this.#i})}toString(e){let t="";this.channel>0&&(t=",channel="+this.channel);let i=this.text;i?(i=i.replace(/\n/g,"\\n"),i=i.replace(/\r/g,"\\r"),i=i.replace(/\t/g,"\\t")):i="";let s=String(this.type);return e&&(s=e.vocabulary.getDisplayName(this.type)??""),"[@"+this.tokenIndex+","+this.start+":"+this.stop+"='"+i+"',<"+s+">"+t+","+this.line+":"+this.column+"]"}get text(){if(void 0!==this.#i)return this.#i;const e=this.inputStream;if(!e)return;const t=e.size;return this.start"}set text(e){this.#i=e}setText(e){this.#i=e}setType(e){this.type=e}setLine(e){this.line=e}setCharPositionInLine(e){this.column=e}setChannel(e){this.channel=e}setTokenIndex(e){this.tokenIndex=e}},B=class e{static{c(this,"Trees")}static toStringTree(t,i,s){i=i??null,s&&(i=s.ruleNames);let n=e.getNodeText(t,i);n=S(n,!1);const r=t.getChildCount();if(0===r)return n;let o="("+n+" ";r>0&&(n=e.toStringTree(t.getChild(0),i),o=o.concat(n));for(let a=1;a=e.start.tokenIndex&&(null===e.stop||i<=e.stop.tokenIndex)?e:null}static stripChildrenOutOfRange(e,t,i,s){if(null!==e)for(let n=0;ns)&&this.isAncestorOf(o,t)){const t=H.fromType(r.INVALID_TYPE,"...");e.children[n]=new F(t)}}}static doFindAllNodes(t,i,s,n){s&&t instanceof F?t.symbol?.type===i&&n.push(t):!s&&t instanceof W&&t.ruleIndex===i&&n.push(t);for(let r=0;r{e instanceof U&&(this.children.push(e),e.parent=this)}))}enterRule(e){}exitRule(e){}addChild(e){return this.children.push(e),e}removeLastChild(){this.children.pop()}addTokenNode(e){const t=new F(e);return this.children.push(t),t.parent=this,t}addErrorNode(e){return e.parent=this,this.children.push(e),e}getChild(e,t){if(e<0||e>=this.children.length)return null;if(!t)return this.children[e];for(const i of this.children)if(i instanceof t){if(0===e)return i;e-=1}return null}getToken(e,t){if(t<0||t>=this.children.length)return null;for(const i of this.children)if("symbol"in i&&i.symbol?.type===e){if(0===t)return i;t-=1}return null}getTokens(e){const t=[];for(const i of this.children)"symbol"in i&&i.symbol?.type===e&&t.push(i);return t}getRuleContext(e,t){return this.getChild(e,t)}getRuleContexts(e){const t=[];for(const i of this.children)i instanceof e&&t.push(i);return t}getChildCount(){return this.children.length}getSourceInterval(){return null===this.start?m.INVALID_INTERVAL:null===this.stop||this.stop.tokenIndexe.getText())).join("")}getAltNumber(){return Z.INVALID_ALT_NUMBER}setAltNumber(e){}accept(e){return e.visitChildren(this)}toStringTree(...e){return e.length<2?B.toStringTree(this,null,e[0]):B.toStringTree(this,e[0],e[1])}toString(e,t){e=e??null,t=t??null;let i=this,s="[";for(;null!==i&&i!==t;){if(null===e)i.isEmpty()||(s+=i.invokingState);else{const t=i.ruleIndex;s+=t>=0&&tt===k.EMPTY_RETURN_STATE&&null===e?N.instance:new A(e,t)),"createSingletonPredictionContext"),G=c(((e,t)=>{if(t||(t=W.empty),!t.parent||t===W.empty)return N.instance;const i=G(e,t.parent),s=e.states[t.invokingState].transitions[0];return z(i,s.followState.stateNumber)}),"predictionContextFromRuleContext"),j=c(((e,t,i)=>{if(e.isEmpty())return e;let s=i.get(e);if(s)return s;if(s=t.get(e),s)return i.set(e,s),s;let n,r=!1,o=[];for(let a=0;a{if(e===t||e.equals(t))return e;if(e instanceof A&&t instanceof A)return $(e,t,i,s);if(i){if(e instanceof N)return e;if(t instanceof N)return t}return e instanceof A&&(e=new V([e.parent],[e.returnState])),t instanceof A&&(t=new V([t.parent],[t.returnState])),Y(e,t,i,s)}),"merge"),Y=c(((e,t,i,s)=>{if(s){let i=s.get(e,t);if(i)return i;if(i=s.get(t,e),i)return i}let n=0,r=0,o=0,a=new Array(e.returnStates.length+t.returnStates.length).fill(0),c=new Array(e.returnStates.length+t.returnStates.length).fill(null);for(;n a"),e):l.equals(t)?(null!==s&&s.set(e,t,t),t):(q(c),null!==s&&s.set(e,t,l),k.traceATNSimulator&&console.log("mergeArrays a="+e+",b="+t+" -> "+l),l)}),"mergeArrays"),q=c((e=>{const t=new P(u.instance);for(const i of e)i&&(t.containsKey(i)||t.set(i,i));for(let i=0;i{if(null!==s){let i=s.get(e,t);if(null!==i)return i;if(i=s.get(t,e),null!==i)return i}const n=Q(e,t,i);if(null!==n)return null!==s&&s.set(e,t,n),n;if(e.returnState===t.returnState){const n=K(e.parent,t.parent,i,s);if(n===e.parent)return e;if(n===t.parent)return t;const r=z(n,e.returnState);return null!==s&&s.set(e,t,r),r}{let i=null;if((e===t||null!==e.parent&&e.parent.equals(t.parent))&&(i=e.parent),null!==i){const n=[e.returnState,t.returnState];e.returnState>t.returnState&&(n[0]=t.returnState,n[1]=e.returnState);const r=new V([i,i],n);return null!==s&&s.set(e,t,r),r}const n=[e.returnState,t.returnState];let r=[e.parent,t.parent];e.returnState>t.returnState&&(n[0]=t.returnState,n[1]=e.returnState,r=[t.parent,e.parent]);const o=new V(r,n);return null!==s&&s.set(e,t,o),o}}),"mergeSingletons"),Q=c(((e,t,i)=>{if(i){if(e===N.instance||t===N.instance)return N.instance}else{if(e===N.instance&&t===N.instance)return N.instance;if(e===N.instance){const e=[t.returnState,k.EMPTY_RETURN_STATE],i=[t.parent,null];return new V(i,e)}if(t===N.instance){const t=[e.returnState,k.EMPTY_RETURN_STATE],i=[e.parent,null];return new V(i,t)}}return null}),"mergeRoot"),X=class e{constructor(e){this.atn=e}static{c(this,"LL1Analyzer")}static hitPredicate=r.INVALID_TYPE;getDecisionLookahead(t){if(!t)return;const i=t.transitions.length,s=new Array(i);for(let n=0;n0&&!i.contains(e.hitPredicate)&&(s[n]=i)}return s}look(e,t,i){const s=new _,n=i?G(this.atn,i):null;return this.doLook(e,t,n,s,new p,new h,!0,!0),s}doLook(t,i,s,n,o,a,c,l){const h=T.createWithContext(t,0,s);if(!o.get(h)){if(o.add(h),t===i){if(!s)return void n.addOne(r.EPSILON);if(s.isEmpty()&&l)return void n.addOne(r.EOF)}if(t.constructor.stateType===x.RULE_STOP){if(!s)return void n.addOne(r.EPSILON);if(s.isEmpty()&&l)return void n.addOne(r.EOF);if(s!==N.instance){const e=a.get(t.ruleIndex);try{a.clear(t.ruleIndex);for(let e=0;e=this.states.length)throw new Error("Invalid state number.");const i=this.states[e];let s=this.nextTokens(i);if(!s.contains(r.EPSILON))return s;let n=t;const o=new _;for(o.addSet(s),o.removeOne(r.EPSILON);null!==n&&n.invokingState>=0&&s.contains(r.EPSILON);){const e=this.states[n.invokingState].transitions[0];s=this.nextTokens(e.followState),o.addSet(s),o.removeOne(r.EPSILON),n=n.parent}return s.contains(r.EPSILON)&&o.addOne(r.EOF),o}},J=class e{static{c(this,"KeyTypeEqualityComparer")}static instance=new e;hashCode(e){let t=7;return t=31*t+e.state.stateNumber,t=31*t+e.alt,t=31*t+e.semanticContext.hashCode(),t}equals(e,t){return e===t||e.state.stateNumber===t.state.stateNumber&&e.alt===t.alt&&e.semanticContext.equals(t.semanticContext)}},ee=class{static{c(this,"ATNConfigSet")}configLookup=new p(J.instance);configs=[];uniqueAlt=0;hasSemanticContext=!1;dipsIntoOuterContext=!1;fullCtx=!1;readOnly=!1;conflictingAlts=null;firstStopState;#s=-1;constructor(e){if(void 0!==e)if("boolean"===typeof e)this.fullCtx=e??!0;else{const t=e;this.addAll(t.configs),this.uniqueAlt=t.uniqueAlt,this.conflictingAlts=t.conflictingAlts,this.hasSemanticContext=t.hasSemanticContext,this.dipsIntoOuterContext=t.dipsIntoOuterContext}}[Symbol.iterator](){return this.configs[Symbol.iterator]()}add(e,t=null){if(this.readOnly)throw new Error("This set is readonly");this.firstStopState||e.state.constructor.stateType!==x.RULE_STOP||(this.firstStopState=e),this.hasSemanticContext||=e.semanticContext!==y.NONE,this.dipsIntoOuterContext||=e.reachesIntoOuterContext;const i=this.configLookup.getOrAdd(e);if(i===e)return this.#s=-1,void this.configs.push(e);const s=!this.fullCtx,n=K(i.context,e.context,s,t);i.reachesIntoOuterContext||=e.reachesIntoOuterContext,i.precedenceFilterSuppressed||=e.precedenceFilterSuppressed,i.context=n}get elements(){return this.configs}getAlts(){const e=new h;for(const t of this.configs)e.set(t.alt);return e}getPredicates(){const e=[];for(const t of this.configs)t.semanticContext!==y.NONE&&e.push(t.semanticContext);return e}getStates(){const e=new p;for(const t of this.configs)e.add(t.state);return e}optimizeConfigs(e){if(this.readOnly)throw new Error("This set is readonly");if(0!==this.configLookup.size)for(const t of this.configs)t.context=e.getCachedContext(t.context)}addAll(e){for(const t of e)this.add(t);return!1}equals(e){return this===e||!(this.fullCtx!==e.fullCtx||this.uniqueAlt!==e.uniqueAlt||this.conflictingAlts!==e.conflictingAlts||this.hasSemanticContext!==e.hasSemanticContext||this.dipsIntoOuterContext!==e.dipsIntoOuterContext||!E(this.configs,e.configs))}hashCode(){return-1===this.#s&&(this.#s=this.computeHashCode()),this.#s}get length(){return this.configs.length}isEmpty(){return 0===this.configs.length}contains(e){if(null===this.configLookup)throw new Error("This method is not implemented for readonly sets.");return this.configLookup.contains(e)}containsFast(e){if(null===this.configLookup)throw new Error("This method is not implemented for readonly sets.");return this.configLookup.contains(e)}clear(){if(this.readOnly)throw new Error("This set is readonly");this.configs=[],this.#s=-1,this.configLookup=new p(J.instance)}setReadonly(e){this.readOnly=e,e&&(this.configLookup=null)}toString(){return C(this.configs)+(this.hasSemanticContext?",hasSemanticContext="+this.hasSemanticContext:"")+(this.uniqueAlt!==Z.INVALID_ALT_NUMBER?",uniqueAlt="+this.uniqueAlt:"")+(null!==this.conflictingAlts?",conflictingAlts="+this.conflictingAlts:"")+(this.dipsIntoOuterContext?",dipsIntoOuterContext":"")}computeHashCode(){let e=d.initialize();return this.configs.forEach((t=>{e=d.update(e,t.hashCode())})),e=d.finish(e,this.configs.length),e}},te=class extends x{static{c(this,"BasicState")}static stateType=x.BASIC},ie=class extends x{static{c(this,"DecisionState")}decision=-1;nonGreedy=!1},se=class extends ie{static{c(this,"BlockStartState")}endState},ne=class extends x{static{c(this,"BlockEndState")}static stateType=x.BLOCK_END;startState},re=class extends x{static{c(this,"LoopEndState")}static stateType=x.LOOP_END;loopBackState},oe=class extends x{static{c(this,"RuleStartState")}static stateType=x.RULE_START;stopState;isLeftRecursiveRule=!1},ae=class extends x{static{c(this,"RuleStopState")}static stateType=x.RULE_STOP},ce=class extends ie{static{c(this,"TokensStartState")}static stateType=x.TOKEN_START},le=class extends ie{static{c(this,"PlusLoopbackState")}static stateType=x.PLUS_LOOP_BACK},he=class extends x{static{c(this,"StarLoopbackState")}static stateType=x.STAR_LOOP_BACK},de=class extends ie{static{c(this,"StarLoopEntryState")}static stateType=x.STAR_LOOP_ENTRY;loopBackState;precedenceRuleDecision=!1},ue=class extends se{static{c(this,"PlusBlockStartState")}static stateType=x.PLUS_BLOCK_START;loopBackState},ge=class extends se{static{c(this,"StarBlockStartState")}static stateType=x.STAR_BLOCK_START},pe=class extends se{static{c(this,"BasicBlockStartState")}static stateType=x.BLOCK_START},me=class extends I{static{c(this,"AtomTransition")}labelValue;#n;constructor(e,t){super(e),this.labelValue=t,this.#n=_.of(t,t)}get label(){return this.#n}get transitionType(){return I.ATOM}matches(e){return this.labelValue===e}toString(){return this.labelValue.toString()}},fe=class extends I{static{c(this,"RuleTransition")}ruleIndex;precedence;followState;constructor(e,t,i,s){super(e),this.ruleIndex=t,this.precedence=i,this.followState=s}get isEpsilon(){return!0}get transitionType(){return I.RULE}matches(e,t,i){return!1}},_e=class extends I{static{c(this,"RangeTransition")}start;stop;#n=new _;constructor(e,t,i){super(e),this.start=t,this.stop=i,this.#n.addRange(t,i)}get label(){return this.#n}get transitionType(){return I.RANGE}matches(e,t,i){return e>=this.start&&e<=this.stop}toString(){return"'"+String.fromCharCode(this.start)+"'..'"+String.fromCharCode(this.stop)+"'"}},ve=class extends I{static{c(this,"ActionTransition")}ruleIndex;actionIndex;isCtxDependent;constructor(e,t,i,s){super(e),this.ruleIndex=t,this.actionIndex=i??-1,this.isCtxDependent=s??!1}get isEpsilon(){return!0}get transitionType(){return I.ACTION}matches(e,t,i){return!1}toString(){return"action_"+this.ruleIndex+":"+this.actionIndex}},Ce=class extends I{static{c(this,"EpsilonTransition")}#r;constructor(e,t=-1){super(e),this.#r=t}get outermostPrecedenceReturn(){return this.#r}get isEpsilon(){return!0}get transitionType(){return I.EPSILON}matches(){return!1}toString(){return"epsilon"}},Ee=class extends I{static{c(this,"WildcardTransition")}get transitionType(){return I.WILDCARD}matches(e,t,i){return e>=t&&e<=i}toString(){return"."}},be=class extends I{static{c(this,"AbstractPredicateTransition")}constructor(e){super(e)}},Se=class extends be{static{c(this,"PredicateTransition")}ruleIndex;predIndex;isCtxDependent;constructor(e,t,i,s){super(e),this.ruleIndex=t,this.predIndex=i,this.isCtxDependent=s}get isEpsilon(){return!0}matches(e,t,i){return!1}get transitionType(){return I.PREDICATE}getPredicate(){return new y.Predicate(this.ruleIndex,this.predIndex,this.isCtxDependent)}toString(){return"pred_"+this.ruleIndex+":"+this.predIndex}},ye=class extends be{static{c(this,"PrecedencePredicateTransition")}precedence;constructor(e,t){super(e),this.precedence=t}get isEpsilon(){return!0}matches(e,t,i){return!1}getPredicate(){return new y.PrecedencePredicate(this.precedence)}get transitionType(){return I.PRECEDENCE}toString(){return this.precedence+" >= _p"}},we=0,Re=1,Le=2,Te=3,xe=4,ke=5,Ae=6,Ne=7,Ie=class e{static{c(this,"LexerSkipAction")}static instance=new e;actionType;isPositionDependent=!1;constructor(){this.actionType=Ae}equals(e){return e===this}hashCode(){return Ae}execute(e){e.skip()}toString(){return"skip"}},Oe=class e{static{c(this,"LexerChannelAction")}channel;actionType;isPositionDependent=!1;cachedHashCode;constructor(e){this.actionType=we,this.channel=e}execute(e){e.channel=this.channel}hashCode(){if(void 0===this.cachedHashCode){let e=d.initialize();e=d.update(e,this.actionType),e=d.update(e,this.channel),this.cachedHashCode=d.finish(e,2)}return this.cachedHashCode}equals(t){return this===t||t instanceof e&&this.channel===t.channel}toString(){return"channel("+this.channel+")"}},De=class e{static{c(this,"LexerCustomAction")}ruleIndex;actionIndex;actionType;isPositionDependent=!0;cachedHashCode;constructor(e,t){this.actionType=Re,this.ruleIndex=e,this.actionIndex=t}execute(e){e.action(null,this.ruleIndex,this.actionIndex)}hashCode(){if(void 0===this.cachedHashCode){let e=d.initialize();e=d.update(e,this.actionType),e=d.update(e,this.ruleIndex),e=d.update(e,this.actionIndex),this.cachedHashCode=d.finish(e,3)}return this.cachedHashCode}equals(t){return this===t||t instanceof e&&(this.ruleIndex===t.ruleIndex&&this.actionIndex===t.actionIndex)}},Me=class e{static{c(this,"LexerMoreAction")}static instance=new e;actionType;isPositionDependent=!1;constructor(){this.actionType=Te}equals(e){return e===this}hashCode(){return Te}execute(e){e.more()}toString(){return"more"}},Pe=class e{static{c(this,"LexerTypeAction")}type;actionType;isPositionDependent=!1;cachedHashCode;constructor(e){this.actionType=Ne,this.type=e}execute(e){e.type=this.type}hashCode(){if(void 0===this.cachedHashCode){let e=d.initialize();e=d.update(e,this.actionType),e=d.update(e,this.type),this.cachedHashCode=d.finish(e,2)}return this.cachedHashCode}equals(t){return this===t||t instanceof e&&this.type===t.type}toString(){return"type("+this.type+")"}},Fe=class e{static{c(this,"LexerPushModeAction")}mode;actionType;isPositionDependent=!1;cachedHashCode;constructor(e){this.actionType=ke,this.mode=e}execute(e){e.pushMode(this.mode)}hashCode(){if(void 0===this.cachedHashCode){let e=d.initialize();e=d.update(e,this.actionType),e=d.update(e,this.mode),this.cachedHashCode=d.finish(e,2)}return this.cachedHashCode}equals(t){return this===t||t instanceof e&&this.mode===t.mode}toString(){return"pushMode("+this.mode+")"}},Ue=class e{static{c(this,"LexerPopModeAction")}static instance=new e;actionType;isPositionDependent=!1;constructor(){this.actionType=xe}equals(e){return e===this}hashCode(){return xe}execute(e){e.popMode()}toString(){return"popMode"}},He=class e{static{c(this,"LexerModeAction")}mode;actionType;isPositionDependent=!1;cachedHashCode;constructor(e){this.actionType=Le,this.mode=e}execute(e){e.mode=this.mode}hashCode(){if(void 0===this.cachedHashCode){let e=d.initialize();e=d.update(e,this.actionType),e=d.update(e,this.mode),this.cachedHashCode=d.finish(e,2)}return this.cachedHashCode}equals(t){return this===t||t instanceof e&&this.mode===t.mode}toString(){return"mode("+this.mode+")"}},Be=class e{static{c(this,"ATNDeserializer")}static SERIALIZED_VERSION=4;static stateTypeMapper=new Map([[x.INVALID_TYPE,void 0],[x.BASIC,te],[x.RULE_START,oe],[x.BLOCK_START,pe],[x.PLUS_BLOCK_START,ue],[x.STAR_BLOCK_START,ge],[x.TOKEN_START,ce],[x.RULE_STOP,ae],[x.BLOCK_END,ne],[x.STAR_LOOP_BACK,he],[x.STAR_LOOP_ENTRY,de],[x.PLUS_LOOP_BACK,le],[x.LOOP_END,re]]);static lexerActionFactoryMapper=new Map([[we,e=>new Oe(e)],[Re,(e,t)=>new De(e,t)],[Le,e=>new He(e)],[Te,()=>Me.instance],[xe,()=>Ue.instance],[ke,e=>new Fe(e)],[Ae,()=>Ie.instance],[Ne,e=>new Pe(e)]]);data=[];pos=0;deserializationOptions;actionFactories;constructor(e){e||(e={readOnly:!1,verifyATN:!0,generateRuleBypassTransitions:!1}),this.deserializationOptions=e}deserialize(e){this.data=e,this.checkVersion();const t=this.readATN();this.readStates(t),this.readRules(t),this.readModes(t);const i=[];return this.readSets(t,i),this.readEdges(t,i),this.readDecisions(t),this.readLexerActions(t),this.markPrecedenceDecisions(t),this.verifyATN(t),this.deserializationOptions.generateRuleBypassTransitions&&t.grammarType===Z.PARSER&&(this.generateRuleBypassTransitions(t),this.verifyATN(t)),t}checkVersion(){const t=this.data[this.pos++];if(t!==e.SERIALIZED_VERSION)throw new Error("Could not deserialize ATN with version "+t+" (expected "+e.SERIALIZED_VERSION+").")}readATN(){const e=this.data[this.pos++],t=this.data[this.pos++];return new Z(e,t)}readStates(e){let t,i;const s=[],n=[],r=this.data[this.pos++];for(let c=0;c0;){const e=c.removeTransition(c.transitions.length-1);n.addTransition(e)}e.ruleToStartState[t].addTransition(new Ce(n)),a&&r.addTransition(new Ce(a));const l=new te;e.addState(l),l.addTransition(new me(r,e.ruleToTokenType[t])),n.addTransition(new Ce(l))}stateIsEndStateFor(e,t){if(e.ruleIndex!==t)return null;if(!(e instanceof de))return null;const i=e.transitions[e.transitions.length-1].target;return i instanceof re&&i.epsilonOnlyTransitions&&i.transitions[0].target instanceof ae?e:null}markPrecedenceDecisions(e){for(const t of e.states)if(t instanceof de&&e.ruleToStartState[t.ruleIndex].isLeftRecursiveRule){const e=t.transitions[t.transitions.length-1].target;e instanceof re&&e.epsilonOnlyTransitions&&e.transitions[0].target instanceof ae&&(t.precedenceRuleDecision=!0)}}verifyATN(e){if(this.deserializationOptions.verifyATN)for(const t of e.states)if(null!==t)if(this.checkCondition(t.epsilonOnlyTransitions||t.transitions.length<=1),t instanceof ue)this.checkCondition(null!==t.loopBackState);else if(t instanceof de)if(this.checkCondition(null!==t.loopBackState),this.checkCondition(2===t.transitions.length),t.transitions[0].target instanceof ge)this.checkCondition(t.transitions[1].target instanceof re),this.checkCondition(!t.nonGreedy);else{if(!(t.transitions[0].target instanceof re))throw new Error("IllegalState");this.checkCondition(t.transitions[1].target instanceof ge),this.checkCondition(t.nonGreedy)}else t instanceof he?(this.checkCondition(1===t.transitions.length),this.checkCondition(t.transitions[0].target instanceof de)):t instanceof re?this.checkCondition(null!==t.loopBackState):t instanceof oe?this.checkCondition(null!==t.stopState):t instanceof se?this.checkCondition(null!==t.endState):t instanceof ne?this.checkCondition(null!==t.startState):t instanceof ie?this.checkCondition(t.transitions.length<=1||t.decision>=0):this.checkCondition(t.transitions.length<=1||t instanceof ae)}checkCondition(e,t){if(!e)throw void 0!==t&&null!==t||(t="IllegalState"),t}edgeFactory(e,t,i,s,n,o,a){const c=e.states[i];switch(t){case I.EPSILON:return new Ce(c);case I.RANGE:return new _e(c,0!==o?r.EOF:s,n);case I.RULE:return new fe(e.states[s],n,o,c);case I.PREDICATE:return new Se(c,s,n,0!==o);case I.PRECEDENCE:return new ye(c,s);case I.ATOM:return new me(c,0!==o?r.EOF:s);case I.ACTION:return new ve(c,s,n,0!==o);case I.SET:return new O(c,a[s]);case I.NOT_SET:return new D(c,a[s]);case I.WILDCARD:return new Ee(c);default:throw new Error("The specified transition type: "+t+" is not valid.")}}stateFactory(t,i){const s=e.stateTypeMapper.get(t);if(!s)throw new Error("The specified state type "+t+" is not valid.");const n=new s;return n.ruleIndex=i,n}lexerActionFactory(t,i,s){const n=e.lexerActionFactoryMapper.get(t);if(!n)throw new Error("The specified lexer action type "+t+" is not valid.");return n(i,s)}},We=class e extends P{static{c(this,"OrderedHashMap")}#o=[];clear(){super.clear(),this.#o=[]}get(e){return super.get(e)}set(e,t){const i=super.set(e,t);return void 0===i&&this.#o.push(e),i}setIfAbsent(e,t){const i=super.setIfAbsent(e,t);return void 0===i&&this.#o.push(e),i}values(){return{[Symbol.iterator]:()=>{let e=0;return{next:c((()=>e0)for(const t of this.atn.modeToStartState)this.data.push(t.stateNumber)}addRuleStatesAndLexerTokenTypes(){const e=this.atn.ruleToStartState.length;this.data.push(e);for(let t=0;t",this.predicates?e+=C(this.predicates):e+=this.prediction),e.toString()}}),ze=class{static{c(this,"ATNSimulator")}static ERROR=Ve.fromState(2147483647);atn;sharedContextCache;constructor(e,t){return this.atn=e,this.sharedContextCache=t,this}getCachedContext(e){if(!this.sharedContextCache)return e;const t=new P(u.instance);return j(e,this.sharedContextCache,t)}},Ge=(class e{static{c(this,"CodePointTransitions")}static createWithCodePoint(t,i){return e.createWithCodePointRange(t,i,i)}static createWithCodePointRange(e,t,i){return t===i?new me(e,t):new _e(e,t,i)}},class{static{c(this,"DecisionInfo")}decision=0;invocations=0;timeInPrediction=0;sllTotalLook=0;sllMinLook=0;sllMaxLook=0;sllMaxLookEvent;llTotalLook=0;llMinLook=0;llMaxLook=0;llMaxLookEvent;contextSensitivities;errors;ambiguities;predicateEvals;sllATNTransitions=0;sllDFATransitions=0;llFallback=0;llATNTransitions=0;llDFATransitions=0;constructor(e){this.decision=e,this.contextSensitivities=[],this.errors=[],this.ambiguities=[],this.predicateEvals=[]}toString(){return"{decision="+this.decision+", contextSensitivities="+this.contextSensitivities.length+", errors="+this.errors.length+", ambiguities="+this.ambiguities.length+", sllLookahead="+this.sllTotalLook+", sllATNTransitions="+this.sllATNTransitions+", sllDFATransitions="+this.sllDFATransitions+", llFallback="+this.llFallback+", llLookahead="+this.llTotalLook+", llATNTransitions="+this.llATNTransitions+"}"}}),je=class e extends T{static{c(this,"LexerATNConfig")}lexerActionExecutor;passedThroughNonGreedyDecision;constructor(t,i,s,n){return super(t,i,s??t.context,s?y.NONE:t.semanticContext),this.lexerActionExecutor=s?n:t.lexerActionExecutor??null,this.passedThroughNonGreedyDecision=e.checkNonGreedyDecision(t,this.state),this}static createWithExecutor(t,i,s){return new e(t,i,t.context,s)}static createWithConfig(t,i,s){return new e(i,t,s??null,i.lexerActionExecutor)}static createWithContext(t,i,s){return new e({alt:i},t,s,null)}static checkNonGreedyDecision(e,t){return e.passedThroughNonGreedyDecision||"nonGreedy"in t&&t.nonGreedy}hashCode(){if(void 0===this.cachedHashCode){let e=d.initialize(7);e=d.update(e,this.state.stateNumber),e=d.update(e,this.alt),e=d.updateFromComparable(e,this.context),e=d.updateFromComparable(e,this.semanticContext),e=d.update(e,this.passedThroughNonGreedyDecision?1:0),e=d.updateFromComparable(e,this.lexerActionExecutor),e=d.finish(e,6),this.cachedHashCode=e}return this.cachedHashCode}equals(e){return this===e||this.passedThroughNonGreedyDecision===e.passedThroughNonGreedyDecision&&(this.lexerActionExecutor&&e.lexerActionExecutor?this.lexerActionExecutor.equals(e.lexerActionExecutor):!e.lexerActionExecutor)&&super.equals(e)}},Ke=class{static{c(this,"BaseErrorListener")}syntaxError(e,t,i,s,n,r){}reportAmbiguity(e,t,i,s,n,r,o){}reportAttemptingFullContext(e,t,i,s,n,r){}reportContextSensitivity(e,t,i,s,n,r){}},Ye=class e extends Ke{static{c(this,"ConsoleErrorListener")}static instance=new e;syntaxError(e,t,i,s,n,r){console.error("line "+i+":"+s+" "+n)}},qe=class extends Ke{constructor(e){return super(),this.delegates=e,this}static{c(this,"ProxyErrorListener")}syntaxError(e,t,i,s,n,r){this.delegates.forEach((o=>{o.syntaxError(e,t,i,s,n,r)}))}reportAmbiguity(e,t,i,s,n,r,o){this.delegates.forEach((a=>{a.reportAmbiguity(e,t,i,s,n,r,o)}))}reportAttemptingFullContext(e,t,i,s,n,r){this.delegates.forEach((o=>{o.reportAttemptingFullContext(e,t,i,s,n,r)}))}reportContextSensitivity(e,t,i,s,n,r){this.delegates.forEach((o=>{o.reportContextSensitivity(e,t,i,s,n,r)}))}},$e=class e{static{c(this,"Recognizer")}static EOF=-1;static tokenTypeMapCache=new Map;static ruleIndexMapCache=new Map;interpreter;listeners=[Ye.instance];stateNumber=-1;checkVersion(e){const t="4.13.1";t!==e&&console.error("ANTLR runtime and generated code versions disagree: "+t+"!="+e)}addErrorListener(e){this.listeners.push(e)}removeErrorListeners(){this.listeners=[]}removeErrorListener(e){for(let t=0;ti.set(e,t))),e.ruleIndexMapCache.set(t,i)),i}getTokenType(e){const t=this.getTokenTypeMap().get(e);return t||r.INVALID_TYPE}getErrorHeader(e){const t=e.offendingToken?.line,i=e.offendingToken?.column;return"line "+t+":"+i}get errorListenerDispatch(){return new qe(this.listeners)}sempred(e,t,i){return!0}precpred(e,t){return!0}action(e,t,i){}get atn(){return this.interpreter.atn}get state(){return this.stateNumber}set state(e){this.stateNumber=e}getParseInfo(){}},Qe=class e{static{c(this,"CommonTokenFactory")}static DEFAULT=new e;copyText=!1;constructor(e){this.copyText=e??!1}create(e,t,i,s,n,r,o,a){const c=H.fromSource(e,t,s,n,r);return c.line=o,c.column=a,i?c.text=i:this.copyText&&null!==e[1]&&(c.text=e[1].getTextFromRange(n,r)),c}},Xe=class e extends Error{static{c(this,"RecognitionException")}ctx;offendingToken=null;offendingState=-1;recognizer;input;constructor(t){super(t.message),Error.captureStackTrace&&Error.captureStackTrace(this,e),this.message=t.message,this.recognizer=t.recognizer,this.input=t.input,this.ctx=t.ctx,null!==this.recognizer&&(this.offendingState=this.recognizer.state)}getExpectedTokens(){return null!==this.recognizer&&null!==this.ctx?this.recognizer.atn.getExpectedTokens(this.offendingState,this.ctx):null}toString(){return this.message}},Ze=class extends Xe{static{c(this,"LexerNoViableAltException")}startIndex;deadEndConfigs;constructor(e,t,i,s){super({message:"",recognizer:e,input:t,ctx:null}),this.startIndex=i,this.deadEndConfigs=s}toString(){let e="";return this.input&&this.startIndex>=0&&this.startIndex